[
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: Bug Report\ndescription: Create a bug report.\ntitle: \"[Bug]: \"\nassignees: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Before you ask a question, check Google for a solution, [the dlib FAQ](http://dlib.net/faq.html), or consult the dlib documentation.  Every single function in dlib is documented in detail.  If you obviously haven't read the documentation your issue will be closed.\n  - type: dropdown\n    id: platform\n    attributes:\n      label: What Operating System(s) are you seeing this problem on?\n      description: Select all that apply\n      multiple: true\n      options:\n        - Linux (x86-64)\n        - Linux (aarch64)\n        - macOS (Intel)\n        - macOS (Apple Silicon)\n        - Windows\n        - Other (plase, specify in the Steps to Reproduce)\n    validations:\n      required: true\n  - type: input\n    id: version\n    attributes:\n      label: dlib version\n      description: \"The commit hash, tag name, or package version\"\n      placeholder: \"19.24\"\n    validations:\n      required: true\n  - type: input\n    id: python\n    attributes:\n      label: Python version\n      description: \"The version of Python you are using\"\n      placeholder: \"3.8\"\n    validations:\n      required: false\n  - type: input\n    id: compiler\n    attributes:\n      label: Compiler\n      description: \"The compiler and version you used to build dlib from source\"\n      placeholder: \"e.g.: GCC 9, MSVC 19, clang 10\"\n    validations:\n      required: true\n  - type: textarea\n    id: expected\n    attributes:\n      label: Expected Behavior\n      description: |\n        A clear and concise description of what you expected to happen\n  - type: textarea\n    id: current\n    attributes:\n      label: Current Behavior\n      description: A clear and concise description of what the bug is\n      placeholder: |\n        Tell us what happened.  Expain in detail the current behavior.\n    validations:\n      required: true\n  - type: textarea\n    id: reproduce\n    validations:\n      required: true    \n    attributes:\n      label: Steps to Reproduce\n      description: Steps to reproduce the behavior\n      placeholder: |\n        Please include as much information as possible that can help to reproduce and\n        understand the issue.  Including a minimal example that reproduces the bug is very useful.\n\n  - type: textarea\n    id: other\n    attributes:\n      label: Anything else?\n      description: |\n        Add any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n- name: 💬 Discussions\n  url: https://github.com/davisking/dlib/discussions\n  about: Please start usage discussions here\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature.yml",
    "content": "name: Feature Request\ndescription: Suggest an idea for dlib\nlabels: type:enhancement\nassignees: []\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        It is OK to suggest interesting improvements to dlib, even if you are not volunteering to implement them.\n        **However, the issue tracker is not a code writing service, do not ask for someone to write code for you**.\n        E.g. Do not ask for feature improvements to the example programs.\n        **If there is some feature improvement you want in an example program then it's up to you to write it**.\n  - type: textarea\n    id: description\n    attributes:\n      label: Main idea\n      description: Describe what you want to add or improve\n    validations:\n      required: true\n  - type: textarea\n    id: other\n    attributes:\n      label: Anything else?\n      description: Add any other context about the suggestion here.\n"
  },
  {
    "path": ".github/workflows/build_cpp.yml",
    "content": "name: C++\n\non:\n  push:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_cpp.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n  pull_request:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_cpp.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n\ndefaults:\n  run:\n    shell: bash\n    working-directory: dlib/test\n\njobs:\n  ubuntu-22-04-gcc-default-cmake-3-17-ffmpeg5:\n    runs-on: 'ubuntu-22.04'\n    steps:\n    - uses: actions/checkout@v2\n\n    - name: Install dependencies\n      run: |\n        sudo apt update\n        sudo apt install libwebp-dev make yasm\n        \n    - name: Cache cmake 3.17.0\n      uses: actions/cache@v3\n      id: cache-cmake-download\n      with:\n        # cache this folder:\n        path: ~/cmake-3.17.0-Linux-x86_64\n        key: cmake-3.17.0_try3\n        \n    - run: |\n        # Get the minimum version of cmake dlib supports\n        wget https://cmake.org/files/v3.17/cmake-3.17.0-Linux-x86_64.tar.gz\n        tar -xf cmake-3.17.0-Linux-x86_64.tar.gz -C ~\n      if: steps.cache-cmake-download.outputs.cache-hit != 'true'\n\n    - name: Cache FFmpeg 5\n      uses: actions/cache@v3\n      id: cache-ffmpeg5\n      with:\n        path: /home/runner/ffmpeg-n5.1.3_installation\n        key: ffmpeg-n5.1.3_try4\n        \n    - name: Build FFmpeg 5\n      if: steps.cache-ffmpeg5.outputs.cache-hit != 'true'\n      run: |\n        wget https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n5.1.3.tar.gz\n        tar -xf n5.1.3.tar.gz\n        cd FFmpeg-n5.1.3\n        ./configure --prefix=/home/runner/ffmpeg-n5.1.3_installation --disable-doc --disable-programs\n        make -j4\n        make install\n        cd ..\n        \n    - name: Configure\n      run: |\n        mkdir build\n        cd build\n        ~/cmake-3.17.0-Linux-x86_64/bin/cmake -DCMAKE_PREFIX_PATH=/home/runner/ffmpeg-n5.1.3_installation .. \n    \n    - name: Build just tests\n      run: |\n        cd build\n        make -j4 dtest\n        \n    - name: Test\n      run: build/dtest --runall -q\n      \n    - name: Build examples, etc\n      run: |\n        cd build\n        make -j2\n\n  ubuntu-latest-gcc-11-blas:\n    runs-on: 'ubuntu-latest'\n    steps:\n    - uses: actions/checkout@v2\n    - name: Install dependencies\n      run: |\n        sudo apt update\n        sudo apt install libwebp-dev libavformat-dev libavcodec-dev libavdevice-dev libavfilter-dev libswresample-dev libswscale-dev libavutil-dev \n        sudo apt install libopenblas-dev liblapack-dev\n    - name: Install gcc 11\n      run: |\n        sudo apt install gcc-11 g++-11\n        sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11\n    - name: Configure\n      run: cmake ${{ github.workspace }}/dlib/test -B build\n    - name: Build just tests\n      run: cmake --build build --config Release --target dtest --parallel 4\n    - name: Test\n      run: build/dtest --runall -q\n    - name: Build examples, etc\n      run: cmake --build build --config Release --parallel 2\n\n    # Test the BLAS bindings\n    - name: Configure BLAS binding tests\n      run: cmake ${{ github.workspace }}/dlib/test/blas_bindings -B build_blas_bindings\n    - name: Build blas binding tests\n      run: cmake --build build_blas_bindings --config Debug --parallel 4\n    - name: Test BLAS bindings\n      run: build_blas_bindings/dtest --runall -q\n\n  ubuntu-latest-clang-default-avx:\n    runs-on: 'ubuntu-latest'\n    steps:\n    - uses: actions/checkout@v2\n    - name: Install dependencies\n      run: |\n        sudo apt update\n        sudo apt install libwebp-dev libavformat-dev libavcodec-dev libavdevice-dev libavfilter-dev libswresample-dev libswscale-dev libavutil-dev \n    - name: Configure\n      run: |\n        export CC=/usr/bin/clang\n        export CXX=/usr/bin/clang++\n        cmake ${{ github.workspace }}/dlib/test -B build -DUSE_AVX_INSTRUCTIONS=1\n    - name: Build just tests\n      run: cmake --build build --config Release --target dtest --parallel 4\n    - name: Test\n      run: build/dtest --runall -q\n    - name: Build examples, etc\n      run: cmake --build build --config Release --parallel 2\n\n  ubuntu-22-04-ffmpeg701:\n    runs-on: 'ubuntu-22.04'\n    steps:\n    - uses: actions/checkout@v2\n\n    - name: Install dependencies\n      run: |\n        sudo apt update\n        sudo apt install make yasm \n\n    - name: Cache FFmpeg 7\n      uses: actions/cache@v3\n      id: cache-ffmpeg7\n      with:\n        path: /home/runner/ffmpeg-n7.0.1_installation\n        key: ffmpeg-n7.0.1_try2\n        \n    - name: Build FFmpeg 7\n      if: steps.cache-ffmpeg7.outputs.cache-hit != 'true'\n      run: |\n        wget https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.0.1.tar.gz\n        tar -xf n7.0.1.tar.gz\n        cd FFmpeg-n7.0.1\n        ./configure --prefix=/home/runner/ffmpeg-n7.0.1_installation --disable-doc --disable-programs\n        make -j4\n        make install\n        cd ..\n        \n    - name: Configure\n      run: cmake . -B build -DCMAKE_PREFIX_PATH=/home/runner/ffmpeg-n7.0.1_installation\n    - name: Build ffmpeg example\n      run: cmake --build build --config Release --target ffmpeg_video_muxing_ex --parallel 4\n\n  ubuntu-22-04-ffmpeg711:\n    runs-on: 'ubuntu-22.04'\n    steps:\n    - uses: actions/checkout@v2\n\n    - name: Install dependencies\n      run: |\n        sudo apt update\n        sudo apt install make yasm \n\n    - name: Cache FFmpeg 7\n      uses: actions/cache@v3\n      id: cache-ffmpeg7\n      with:\n        path: /home/runner/ffmpeg-n7.1.1_installation\n        key: ffmpeg-n7.1.1_try1\n        \n    - name: Build FFmpeg 7\n      if: steps.cache-ffmpeg7.outputs.cache-hit != 'true'\n      run: |\n        wget https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.1.1.tar.gz\n        tar -xf n7.1.1.tar.gz\n        cd FFmpeg-n7.1.1\n        ./configure --prefix=/home/runner/ffmpeg-n7.1.1_installation --disable-doc --disable-programs\n        make -j4\n        make install\n        cd ..\n        \n    - name: Configure\n      run: cmake . -B build -DCMAKE_PREFIX_PATH=/home/runner/ffmpeg-n7.1.1_installation\n    - name: Build ffmpeg example\n      run: cmake --build build --config Release --target ffmpeg_video_muxing_ex --parallel 4\n      \n  windows-latest:\n    runs-on: 'windows-latest'\n    steps:\n    - uses: actions/checkout@v2\n    - name: Configure\n      run: |\n        # don't use CMake 3.25.0 https://gitlab.kitware.com/cmake/cmake/-/issues/23975\n        pip3 install cmake==3.24.0\n        cmake . -B build\n    - name: Build just tests\n      run: cmake --build build --config Release --target dtest --parallel 4\n    - name: Test\n      run: build/Release/dtest.exe --runall -q\n    - name: Build ancillary tools\n      run: cmake --build build --config Release --target imglab htmlify dtoc --parallel 4\n\n  # Disable this because macos targets aren't working on github actions right now.\n  #macos-latest:\n  #  runs-on: 'macos-latest'\n  #  steps:\n  #  - uses: actions/checkout@v2\n  #  - name: Configure\n  #    # MacOS machines often come with low quality BLAS libraries installed, so don't use those.\n  #    run: cmake ${{ github.workspace }}/dlib/test -B build -DDLIB_USE_BLAS=0 -DDLIB_USE_LAPACK=0\n  #  - name: Build just tests\n  #    run: cmake --build build --config Release --target dtest --parallel 4\n  #  - name: Test\n  #    run: build/dtest --runall --no_test_timer -q\n  #  - name: Build examples, etc\n  #    run: cmake --build build --config Release --parallel 2\n"
  },
  {
    "path": ".github/workflows/build_matlab.yml",
    "content": "name: Matlab\n\non:\n  push:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_matlab.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n  pull_request:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_matlab.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n\ndefaults:\n  run:\n    shell: bash\n    working-directory: dlib/matlab\n\n\njobs:\n  mex-wrapper:\n    runs-on: 'ubuntu-22.04'\n    steps:\n    - uses: actions/checkout@v2\n    - name: Setup MATLAB\n      uses: matlab-actions/setup-matlab@v1\n    - name: Compile mex wrappers \n      run: |\n        pwd\n        mkdir build\n        cd build\n        cmake ..\n        cmake --build . --config Release --target install --parallel 4\n    - name: Run example script\n      uses: matlab-actions/run-command@v1\n      with:\n        command: cd dlib/matlab; example\n\n\n"
  },
  {
    "path": ".github/workflows/build_python.yml",
    "content": "name: Python\n\non:\n  push:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_python.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n    - \"**py\"\n  pull_request:\n    branches:\n    - master\n    paths:\n    - \".github/workflows/build_python.yml\"\n    - \"**.cpp\"\n    - \"**.h\"\n    - \"**.c\"\n    - \"**.cu\"\n    - \"**.cmake\"\n    - \"**CMakeLists.txt\"\n    - \"**py\"\n\ndefaults:\n  run:\n    shell: bash\n\njobs:\n  Windows:\n    runs-on: 'windows-latest'\n    steps:\n    - uses: actions/checkout@v3\n    - uses: actions/setup-python@v4\n    - name: Install python deps\n      run: |\n        pip install pytest numpy\n        # don't use CMake 3.25.0 https://gitlab.kitware.com/cmake/cmake/-/issues/23975\n        pip3 install cmake==3.24.0\n    - name: Build\n      run: |\n        pip3 install cmake==3.24.0\n        pip3 install .\n    - name: Test\n      run: python -m pytest --ignore docs --ignore dlib\n\n  Ubuntu:\n    runs-on: 'ubuntu-latest'\n    steps:\n    - uses: actions/checkout@v3\n    - uses: actions/setup-python@v4\n    - name: Install python deps\n      run: pip install pytest numpy\n    - name: Build\n      run: |\n        pip install .\n    - name: Test\n      run: python -m pytest --ignore docs --ignore dlib\n\n# Disabled for now since something is going sideways with python packages on github actions\n# MacOS:\n#   runs-on: 'macos-latest'\n#   steps:\n#   - uses: actions/checkout@v3\n#   - uses: actions/setup-python@v4\n#   - name: Install python deps\n#     run: pip3 install pytest numpy\n#   - name: Build\n#     run: |\n#       pip install .\n#   - name: Test\n#     run: python3 -m pytest --ignore docs --ignore dlib\n\n"
  },
  {
    "path": ".gitignore",
    "content": "**/.idea\n*~\n*.swp\n*.o\n*.so\n*.pyc\nbuild\nbuild2\ndist\n*.egg-info/\ndocs/release/\ndocs/docs/web/\ndocs/docs/chm/\ndocs/docs/cache/\ndocs/docs/git-logs.xml\ndocs/docs/python/classes.txt\ndocs/docs/python/functions.txt\ndocs/docs/python/constants.txt\n**/.vscode\n**/venv\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.17.0)\n\nproject(dlib_project)\n\n\n\n#############################################################################\n#                                                                           #\n#  READ examples/CMakeLists.txt TO SEE HOW TO USE DLIB FROM C++ WITH CMAKE  #\n#                                                                           #\n#############################################################################\n\n\n\n\n\nget_directory_property(has_parent PARENT_DIRECTORY)\nif(NOT has_parent)\n   # When you call add_subdirectory(dlib) from a parent CMake project dlib's\n   # CMake scripts will assume you want to statically compile dlib into\n   # whatever you are building rather than create a standalone copy of dlib.\n   # This means CMake will build dlib as a static library, disable dlib's\n   # install targets so they don't clutter your project, and adjust a few other\n   # minor things that are convenient when statically building dlib as part of\n   # your own projects.\n   #\n   # On the other hand, if there is no parent CMake project or if\n   # DLIB_IN_PROJECT_BUILD is set to false, CMake will compile dlib as a normal\n   # standalone library (either shared or static, based on the state of CMake's\n   # BUILD_SHARED_LIBS flag), and include the usual install targets so you can\n   # install dlib on your computer via `make install`.  Since the only reason\n   # to build this CMakeLists.txt (the one you are reading right now) by itself\n   # is if you want to install dlib, we indicate as such by setting\n   # DLIB_IN_PROJECT_BUILD to false.\n   set(DLIB_IN_PROJECT_BUILD false)\nendif()\nadd_subdirectory(dlib)\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE."
  },
  {
    "path": "MANIFEST.in",
    "content": "#\n# MANIFEST.in\n#\n# Manifest template for creating the dlib source distribution.\n\ninclude MANIFEST.in\ninclude setup.py\ninclude README.md\n\n# sources\nrecursive-include dlib **\nrecursive-include python_examples *.txt *.py \nrecursive-include tools/python **\n\nprune tools/python/build*\nprune dlib/cmake_utils/*/build*\nprune dlib/test\n\nglobal-exclude *.pyc\n"
  },
  {
    "path": "README.md",
    "content": "# dlib C++ library  [![GitHub Actions C++ Status](https://github.com/davisking/dlib/actions/workflows/build_cpp.yml/badge.svg)](https://github.com/davisking/dlib/actions/workflows/build_cpp.yml) [![GitHub Actions Python Status](https://github.com/davisking/dlib/actions/workflows/build_python.yml/badge.svg)](https://github.com/davisking/dlib/actions/workflows/build_python.yml)\n\nDlib is a modern C++ toolkit containing machine learning algorithms and tools for creating complex software in C++ to solve real world problems. See [http://dlib.net](http://dlib.net) for the main project documentation and API reference.\n\n\n\n## Compiling dlib C++ example programs\n\nGo into the examples folder and type:\n\n```bash\nmkdir build; cd build; cmake .. ; cmake --build .\n```\n\nThat will build all the examples.\nIf you have a CPU that supports AVX instructions then turn them on like this:\n\n```bash\nmkdir build; cd build; cmake .. -DUSE_AVX_INSTRUCTIONS=1; cmake --build .\n```\n\nDoing so will make some things run faster.\n\nFinally, Visual Studio users should usually do everything in 64bit mode.  By default Visual Studio is 32bit, both in its outputs and its own execution, so you have to explicitly tell it to use 64bits.  Since it's not the 1990s anymore you probably want to use 64bits.  Do that with a cmake invocation like this:\n```bash\ncmake .. -G \"Visual Studio 14 2015 Win64\" -T host=x64\n```\n\n## Compiling your own C++ programs that use dlib\n\nThe examples folder has a [CMake tutorial](https://github.com/davisking/dlib/blob/master/examples/CMakeLists.txt) that tells you what to do.  There are also additional instructions on the [dlib web site](http://dlib.net/compile.html).\n\nAlternatively, if you are using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager you can download and install dlib with CMake integration in a single command:\n```bash\nvcpkg install dlib\n```\n\n## Compiling dlib Python API\n\nEither fetch the latest stable release of dlib from PyPi and install that:\n```bash\npip install dlib\n```\nOr fetch the very latest version from github and install that:\n```bash\ngit clone https://github.com/davisking/dlib.git\ncd dlib\npip install .\n```\n\nIt's possible to change build settings by passing parameters to `setup.py` or `DLIB_*` environment variables.\nFor example, setting the environment variable `DLIB_NO_GUI_SUPPORT` to `ON` will add the cmake option\n`-DDLIB_NO_GUI_SUPPORT=ON`.\n\n\n## Running the unit test suite\n\nType the following to compile and run the dlib unit test suite:\n\n```bash\ncd dlib/test\nmkdir build\ncd build\ncmake ..\ncmake --build . --config Release\n./dtest --runall\n```\n\nNote that on windows your compiler might put the test executable in a subfolder called `Release`. If that's the case then you have to go to that folder before running the test.\n\nThis library is licensed under the Boost Software License, which can be found in [dlib/LICENSE.txt](https://github.com/davisking/dlib/blob/master/dlib/LICENSE.txt).  The long and short of the license is that you can use dlib however you like, even in closed source commercial software.\n\n## dlib sponsors\n\nThis research is based in part upon work supported by the Office of the Director of National Intelligence (ODNI), Intelligence Advanced Research Projects Activity (IARPA) under contract number 2014-14071600010. The views and conclusions contained herein are those of the authors and should not be interpreted as necessarily representing the official policies or endorsements, either expressed or implied, of ODNI, IARPA, or the U.S. Government.\n"
  },
  {
    "path": "dlib/CMakeLists.txt",
    "content": "#\n# This is a CMake makefile.  You can find the cmake utility and\n# information about it at http://www.cmake.org\n#\n\n\ncmake_minimum_required(VERSION 3.17.0)\n\nset(CMAKE_DISABLE_SOURCE_CHANGES ON)\nset(CMAKE_DISABLE_IN_SOURCE_BUILD ON)\n\nif(POLICY CMP0077)\n   cmake_policy(SET CMP0077 NEW)\nendif()\n\nproject(dlib LANGUAGES C CXX)\n\nset(CPACK_PACKAGE_NAME \"dlib\")\nset(CPACK_PACKAGE_VERSION_MAJOR \"20\")\nset(CPACK_PACKAGE_VERSION_MINOR \"0\")\nset(CPACK_PACKAGE_VERSION_PATCH \"99\")\nset(VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH})\n# Only print these messages once, even if dlib is added multiple times via add_subdirectory()\nif (NOT TARGET dlib)\n   message(STATUS \"Using CMake version: ${CMAKE_VERSION}\")\n   message(STATUS \"Compiling dlib version: ${VERSION}\")\nendif()\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake_utils)\n\ninclude(cmake_utils/set_compiler_specific_options.cmake)\n\n\n# Adhere to GNU filesystem layout conventions\ninclude(GNUInstallDirs)\n\nif (POLICY CMP0075)\n   cmake_policy(SET CMP0075 NEW)\nendif()\n\n# default to a Release build (except if CMAKE_BUILD_TYPE is set)\ninclude(cmake_utils/release_build_by_default)\n\n# Set DLIB_VERSION in the including CMake file so they can use it to do whatever they want. \nget_directory_property(has_parent PARENT_DIRECTORY)\nif(has_parent)\n   set(DLIB_VERSION ${VERSION} PARENT_SCOPE)\n   if (NOT DEFINED DLIB_IN_PROJECT_BUILD)\n      set(DLIB_IN_PROJECT_BUILD true)\n   endif()\nendif()\n\n\nif (COMMAND pybind11_add_module AND MSVC)\n   # True when building a python extension module using Visual Studio.  We care\n   # about this because a huge number of windows users have broken systems, and\n   # in particular, they have broken or incompatibly installed copies of things\n   # like libjpeg or libpng.  So if we detect we are in this mode we will never\n   # ever link to those libraries.  Instead, we link to the copy included with\n   # dlib.\n   set (BUILDING_PYTHON_IN_MSVC true)\nelse()\n   set (BUILDING_PYTHON_IN_MSVC false)\nendif()\n\nif (DLIB_IN_PROJECT_BUILD)\n\n   # Check if we are being built as part of a pybind11 module. \n   if (COMMAND pybind11_add_module)\n      set(CMAKE_POSITION_INDEPENDENT_CODE True)\n      if (CMAKE_COMPILER_IS_GNUCXX)\n         # Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set\n         # -fPIC for GCC but sometimes it still doesn't get set, so make sure it\n         # does.\n         add_definitions(\"-fPIC\")\n      endif()\n      # Make DLIB_ASSERT statements not abort the python interpreter, but just return an error.\n      list(APPEND active_preprocessor_switches \"-DDLIB_NO_ABORT_ON_2ND_FATAL_ERROR\")\n   endif()\n\n   # DLIB_IN_PROJECT_BUILD==true means you are using dlib by invoking\n   # add_subdirectory(dlib) in the parent project. In this case, we always want\n   # to build dlib as a static library so the parent project doesn't need to\n   # deal with some random dlib shared library file.  It is much better to\n   # statically compile dlib into the parent project.  So the following bit of\n   # CMake ensures that happens.  However, we have to take care to compile dlib\n   # with position independent code if appropriate (i.e. if the parent project\n   # is a shared library).\n   if (BUILD_SHARED_LIBS)\n      if (CMAKE_COMPILER_IS_GNUCXX)\n         # Just setting CMAKE_POSITION_INDEPENDENT_CODE should be enough to set\n         # -fPIC for GCC but sometimes it still doesn't get set, so make sure it\n         # does.\n         add_definitions(\"-fPIC\")\n      endif()\n      set(CMAKE_POSITION_INDEPENDENT_CODE true)\n   endif()\n\n   # Tell cmake to build dlib as a static library\n   set(BUILD_SHARED_LIBS false)\n\nelseif(BUILD_SHARED_LIBS)\n   if (MSVC)\n      message(FATAL_ERROR \"Building dlib as a standalone dll is not supported when using Visual Studio.  You are highly encouraged to use static linking instead.  See https://github.com/davisking/dlib/issues/1483 for a discussion.\") \n   endif()\nendif()\n\nmacro (enable_preprocessor_switch option_name)\n   list(APPEND active_preprocessor_switches \"-D${option_name}\")\nendmacro()\n\nmacro (disable_preprocessor_switch option_name)\n   if (active_preprocessor_switches)\n      list(REMOVE_ITEM active_preprocessor_switches \"-D${option_name}\")\n   endif()\nendmacro()\n\nmacro (toggle_preprocessor_switch option_name)\n   if (${option_name})\n      enable_preprocessor_switch(${option_name})\n   else()\n      disable_preprocessor_switch(${option_name})\n   endif()\nendmacro()\n\n\n\n# Suppress superfluous randlib warnings about libdlib.a having no symbols on MacOSX.\nif (CMAKE_C_COMPILER_ID STREQUAL \"AppleClang\")\n   set(CMAKE_C_ARCHIVE_CREATE   \"<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>\")\n   set(CMAKE_C_ARCHIVE_FINISH   \"<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>\")\nendif()\nif (CMAKE_CXX_COMPILER_ID STREQUAL \"AppleClang\")\n   set(CMAKE_CXX_ARCHIVE_CREATE \"<CMAKE_AR> Scr <TARGET> <LINK_FLAGS> <OBJECTS>\")\n   set(CMAKE_CXX_ARCHIVE_FINISH \"<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>\")\nendif()\n\n# Don't try to call add_library(dlib) and setup dlib's stuff if it has already\n# been done by some other part of the current cmake project.  We do this\n# because it avoids getting warnings/errors about cmake policy CMP0002.  This\n# happens when a project tries to call add_subdirectory() on dlib more than\n# once.  This most often happens when the top level of a project depends on two\n# or more other things which both depend on dlib. \nif (NOT TARGET dlib)\n\n   set (DLIB_ISO_CPP_ONLY_STR \n      \"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)\" )\n   set (DLIB_NO_GUI_SUPPORT_STR \n      \"Enable this if you don't want to compile any of the dlib GUI code\" )\n   set (DLIB_ENABLE_STACK_TRACE_STR \n      \"Enable this if you want to turn on the DLIB_STACK_TRACE macros\" )\n   set (DLIB_USE_BLAS_STR\n      \"Disable this if you don't want to use a BLAS library\" )\n   set (DLIB_USE_LAPACK_STR\n      \"Disable this if you don't want to use a LAPACK library\" )\n   set (DLIB_USE_CUDA_STR\n      \"Disable this if you don't want to use NVIDIA CUDA\" )\n   set (DLIB_USE_CUDA_COMPUTE_CAPABILITIES_STR\n      \"Set this to a comma-separated list of CUDA compute capabilities\" )\n   set (DLIB_USE_MKL_SEQUENTIAL_STR\n      \"Enable this if you have MKL installed and want to use the sequential version instead of the multi-core version.\" )\n   set (DLIB_USE_MKL_WITH_TBB_STR\n      \"Enable this if you have MKL installed and want to use the tbb version instead of the openmp version.\" )\n   set (DLIB_PNG_SUPPORT_STR\n      \"Disable this if you don't want to link against libpng\" )\n   set (DLIB_GIF_SUPPORT_STR\n      \"Disable this if you don't want to link against libgif\" )\n   set (DLIB_JPEG_SUPPORT_STR\n      \"Disable this if you don't want to link against libjpeg\" )\n   set (DLIB_WEBP_SUPPORT_STR\n      \"Disable this if you don't want to link against libwebp\" )\n   set (DLIB_JXL_SUPPORT_STR\n      \"Disable this if you don't want to link against libjxl\" )\n   set (DLIB_LINK_WITH_SQLITE3_STR\n      \"Disable this if you don't want to link against sqlite3\" )\n   #set (DLIB_USE_FFTW_STR \"Disable this if you don't want to link against fftw\" )\n   set (DLIB_USE_MKL_FFT_STR\n      \"Disable this is you don't want to use the MKL DFTI FFT implementation\" )\n   set (DLIB_ENABLE_ASSERTS_STR\n      \"Enable this if you want to turn on the DLIB_ASSERT macro\" )\n   set (DLIB_USE_FFMPEG_STR\n      \"Disable this if you don't want to use the FFMPEG library\" )\n\n   option(DLIB_ENABLE_ASSERTS ${DLIB_ENABLE_ASSERTS_STR} OFF)\n   option(DLIB_ISO_CPP_ONLY ${DLIB_ISO_CPP_ONLY_STR} OFF)\n   toggle_preprocessor_switch(DLIB_ISO_CPP_ONLY)\n   option(DLIB_NO_GUI_SUPPORT ${DLIB_NO_GUI_SUPPORT_STR} OFF)\n   toggle_preprocessor_switch(DLIB_NO_GUI_SUPPORT)\n   option(DLIB_ENABLE_STACK_TRACE ${DLIB_ENABLE_STACK_TRACE_STR} OFF)\n   toggle_preprocessor_switch(DLIB_ENABLE_STACK_TRACE)\n   option(DLIB_USE_MKL_SEQUENTIAL ${DLIB_USE_MKL_SEQUENTIAL_STR} OFF)\n   option(DLIB_USE_MKL_WITH_TBB ${DLIB_USE_MKL_WITH_TBB_STR} OFF)\n\n   if(DLIB_ENABLE_ASSERTS)\n      # Set these variables so they are set in the config.h.in file when dlib\n      # is installed.\n      set (DLIB_DISABLE_ASSERTS false)\n      set (ENABLE_ASSERTS true) \n      enable_preprocessor_switch(ENABLE_ASSERTS)\n      disable_preprocessor_switch(DLIB_DISABLE_ASSERTS)\n   else()\n      # Set these variables so they are set in the config.h.in file when dlib\n      # is installed.\n      set (DLIB_DISABLE_ASSERTS true)\n      set (ENABLE_ASSERTS false) \n      disable_preprocessor_switch(ENABLE_ASSERTS)\n      # Never force the asserts off when doing an in project build.  The only\n      # time this matters is when using visual studio.  The visual studio IDE\n      # has a drop down that lets the user select either release or debug\n      # builds.  The DLIB_ASSERT macro is setup to enable/disable automatically\n      # based on this drop down (via preprocessor magic).  However, if\n      # DLIB_DISABLE_ASSERTS is defined it permanently disables asserts no\n      # matter what, which would defeat the visual studio drop down.  So here\n      # we make a point to not do that kind of severe disabling when in a\n      # project build.  It should also be pointed out that DLIB_DISABLE_ASSERTS\n      # is only needed when building and installing dlib as a separately\n      # installed library.  It doesn't matter when doing an in project build. \n      if (NOT DLIB_IN_PROJECT_BUILD)\n         enable_preprocessor_switch(DLIB_DISABLE_ASSERTS)\n      endif()\n   endif()\n\n   if (DLIB_ISO_CPP_ONLY)\n      option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} OFF)\n      option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} OFF)\n      option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} OFF)\n      option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} OFF)\n      option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} OFF)\n      option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} OFF)\n      option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} OFF)\n      option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} OFF)\n      option(DLIB_JXL_SUPPORT ${DLIB_JXL_SUPPORT_STR} OFF)\n      #option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} OFF)\n      option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} OFF)\n      option(DLIB_USE_FFMPEG ${DLIB_USE_FFMPEG_STR} OFF)\n   else()\n      option(DLIB_JPEG_SUPPORT ${DLIB_JPEG_SUPPORT_STR} ON)\n      option(DLIB_LINK_WITH_SQLITE3 ${DLIB_LINK_WITH_SQLITE3_STR} ON)\n      option(DLIB_USE_BLAS ${DLIB_USE_BLAS_STR} ON)\n      option(DLIB_USE_LAPACK ${DLIB_USE_LAPACK_STR} ON)\n      option(DLIB_USE_CUDA ${DLIB_USE_CUDA_STR} ON)\n      option(DLIB_PNG_SUPPORT ${DLIB_PNG_SUPPORT_STR} ON)\n      option(DLIB_GIF_SUPPORT ${DLIB_GIF_SUPPORT_STR} ON)\n      option(DLIB_WEBP_SUPPORT ${DLIB_WEBP_SUPPORT_STR} ON)\n      option(DLIB_JXL_SUPPORT ${DLIB_JXL_SUPPORT_STR} ON)\n      #option(DLIB_USE_FFTW ${DLIB_USE_FFTW_STR} ON)\n      option(DLIB_USE_MKL_FFT ${DLIB_USE_MKL_FFT_STR} ON)\n      option(DLIB_USE_FFMPEG ${DLIB_USE_FFMPEG_STR} ON)\n   endif()\n   toggle_preprocessor_switch(DLIB_JPEG_SUPPORT)\n   toggle_preprocessor_switch(DLIB_USE_BLAS)\n   toggle_preprocessor_switch(DLIB_USE_LAPACK)\n   toggle_preprocessor_switch(DLIB_USE_CUDA)\n   toggle_preprocessor_switch(DLIB_PNG_SUPPORT) \n   toggle_preprocessor_switch(DLIB_GIF_SUPPORT) \n   toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)\n   toggle_preprocessor_switch(DLIB_JXL_SUPPORT) \n   #toggle_preprocessor_switch(DLIB_USE_FFTW)\n   toggle_preprocessor_switch(DLIB_USE_MKL_FFT)\n   toggle_preprocessor_switch(DLIB_USE_FFMPEG)\n\n\n   set(source_files\n      base64/base64_kernel_1.cpp\n      bigint/bigint_kernel_1.cpp\n      bigint/bigint_kernel_2.cpp\n      bit_stream/bit_stream_kernel_1.cpp\n      entropy_decoder/entropy_decoder_kernel_1.cpp\n      entropy_decoder/entropy_decoder_kernel_2.cpp\n      entropy_encoder/entropy_encoder_kernel_1.cpp\n      entropy_encoder/entropy_encoder_kernel_2.cpp\n      md5/md5_kernel_1.cpp\n      tokenizer/tokenizer_kernel_1.cpp\n      unicode/unicode.cpp\n      test_for_odr_violations.cpp\n      fft/fft.cpp\n      )\n\n   set(dlib_needed_public_libraries)\n   set(dlib_needed_public_includes)\n   set(dlib_needed_public_cflags)\n   set(dlib_needed_public_ldflags)\n   set(dlib_needed_private_libraries)\n   set(dlib_needed_private_includes)\n\n   if (DLIB_ISO_CPP_ONLY)\n      add_library(dlib ${source_files} )\n   else()\n\n      set(source_files ${source_files}\n         sockets/sockets_kernel_1.cpp\n         bsp/bsp.cpp\n         dir_nav/dir_nav_kernel_1.cpp\n         dir_nav/dir_nav_kernel_2.cpp\n         dir_nav/dir_nav_extensions.cpp\n         gui_widgets/fonts.cpp\n         linker/linker_kernel_1.cpp\n         logger/extra_logger_headers.cpp\n         logger/logger_kernel_1.cpp\n         logger/logger_config_file.cpp\n         misc_api/misc_api_kernel_1.cpp\n         misc_api/misc_api_kernel_2.cpp\n         sockets/sockets_extensions.cpp\n         sockets/sockets_kernel_2.cpp\n         sockstreambuf/sockstreambuf.cpp\n         sockstreambuf/sockstreambuf_unbuffered.cpp\n         server/server_kernel.cpp\n         server/server_iostream.cpp\n         server/server_http.cpp\n         threads/multithreaded_object_extension.cpp\n         threads/threaded_object_extension.cpp\n         threads/threads_kernel_1.cpp\n         threads/threads_kernel_2.cpp\n         threads/threads_kernel_shared.cpp\n         threads/thread_pool_extension.cpp\n         threads/async.cpp\n         timer/timer.cpp\n         stack_trace.cpp\n         cuda/cpu_dlib.cpp\n         cuda/tensor_tools.cpp\n         data_io/image_dataset_metadata.cpp\n         data_io/mnist.cpp\n         data_io/cifar.cpp\n         global_optimization/global_function_search.cpp\n         filtering/kalman_filter.cpp\n         svm/auto.cpp\n         )\n\n      if(UNIX)\n         set(CMAKE_THREAD_PREFER_PTHREAD ON)\n         find_package(Threads REQUIRED)\n         list (APPEND dlib_needed_private_libraries ${CMAKE_THREAD_LIBS_INIT})\n      endif()\n\n      # we want to link to the right stuff depending on our platform.  \n      if (WIN32 AND NOT CYGWIN) ###############################################################################\n         if (DLIB_NO_GUI_SUPPORT)\n            list (APPEND dlib_needed_private_libraries ws2_32 winmm)\n         else()\n            list (APPEND dlib_needed_private_libraries ws2_32 winmm comctl32 gdi32 imm32)\n         endif()\n      elseif(APPLE) ############################################################################\n         set(CMAKE_MACOSX_RPATH 1)\n         if (NOT DLIB_NO_GUI_SUPPORT)\n            find_package(X11 QUIET)\n            if (X11_FOUND)\n               # If both X11 and anaconda are installed, it's possible for the\n               # anaconda path to appear before /opt/X11, so we remove anaconda.\n               foreach (ITR ${X11_INCLUDE_DIR})\n                  if (\"${ITR}\" MATCHES \"(.*)(Ana|ana|mini)conda(.*)\")\n                     list (REMOVE_ITEM X11_INCLUDE_DIR ${ITR})\n                  endif ()\n               endforeach(ITR)\n               list (APPEND dlib_needed_public_includes ${X11_INCLUDE_DIR})\n               list (APPEND dlib_needed_public_libraries ${X11_LIBRARIES})\n            else()\n               find_library(xlib X11)\n               # Make sure X11 is in the include path.  Note that we look for\n               # Xlocale.h rather than Xlib.h because it avoids finding a partial\n               # copy of the X11 headers on systems with anaconda installed.\n               find_path(xlib_path Xlocale.h\n                  PATHS \n                  /Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include\n                  /opt/local/include\n                  PATH_SUFFIXES X11\n                  )\n               if (xlib AND xlib_path)\n                  get_filename_component(x11_path ${xlib_path} PATH CACHE)\n                  list (APPEND dlib_needed_public_includes ${x11_path})\n                  list (APPEND dlib_needed_public_libraries ${xlib})\n                  set(X11_FOUND 1)\n               endif()\n            endif()\n            if (NOT X11_FOUND)\n               message(\" *****************************************************************************\")\n               message(\" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***\")\n               message(\" *** Make sure XQuartz is installed if you want GUI support.               ***\")\n               message(\" *** You can download XQuartz from: https://www.xquartz.org/               ***\")\n               message(\" *****************************************************************************\")\n               set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE )\n               enable_preprocessor_switch(DLIB_NO_GUI_SUPPORT)\n            endif()\n         endif()\n\n         mark_as_advanced(xlib xlib_path x11_path)\n      else () ##################################################################################\n         # link to the socket library if it exists.  this is something you need on solaris\n         find_library(socketlib socket)\n         if (socketlib)\n            list (APPEND dlib_needed_private_libraries ${socketlib})\n         endif ()\n\n         if (NOT DLIB_NO_GUI_SUPPORT)\n            include(FindX11)\n            if (X11_FOUND)\n               list (APPEND dlib_needed_private_includes ${X11_INCLUDE_DIR})\n               list (APPEND dlib_needed_private_libraries ${X11_LIBRARIES})\n            else()\n               message(\" *****************************************************************************\")\n               message(\" *** DLIB GUI SUPPORT DISABLED BECAUSE X11 DEVELOPMENT LIBRARIES NOT FOUND ***\")\n               message(\" *** Make sure libx11-dev is installed if you want GUI support.            ***\")\n               message(\" *** On Ubuntu run: sudo apt-get install libx11-dev                        ***\")\n               message(\" *****************************************************************************\")\n               set(DLIB_NO_GUI_SUPPORT ON CACHE STRING ${DLIB_NO_GUI_SUPPORT_STR} FORCE )\n               enable_preprocessor_switch(DLIB_NO_GUI_SUPPORT)\n            endif()\n         endif()\n\n         mark_as_advanced(nsllib socketlib)\n      endif () ##################################################################################\n\n      if (NOT DLIB_NO_GUI_SUPPORT)\n         set(source_files ${source_files}\n            gui_widgets/widgets.cpp\n            gui_widgets/drawable.cpp\n            gui_widgets/canvas_drawing.cpp\n            gui_widgets/style.cpp\n            gui_widgets/base_widgets.cpp\n            gui_core/gui_core_kernel_1.cpp\n            gui_core/gui_core_kernel_2.cpp\n            )\n      endif()\n\n      INCLUDE (CheckFunctionExists)\n\n      if (DLIB_GIF_SUPPORT)\n         find_package(GIF QUIET)\n         if (GIF_FOUND)\n            list (APPEND dlib_needed_public_includes ${GIF_INCLUDE_DIR})\n            list (APPEND dlib_needed_public_libraries ${GIF_LIBRARY})\n         else()\n            set(DLIB_GIF_SUPPORT OFF CACHE STRING ${DLIB_GIF_SUPPORT_STR} FORCE )\n            toggle_preprocessor_switch(DLIB_GIF_SUPPORT)\n         endif()\n      endif()\n\n      if (DLIB_PNG_SUPPORT)\n         include(cmake_utils/find_libpng.cmake)\n         if (PNG_FOUND)\n            list (APPEND dlib_needed_private_includes ${PNG_INCLUDE_DIR})\n            list (APPEND dlib_needed_private_libraries ${PNG_LIBRARIES})\n         else()\n            # If we can't find libpng then statically compile it in.\n            include_directories(external/libpng external/zlib)\n            set(source_files ${source_files}\n               external/libpng/arm/arm_init.c\n               external/libpng/arm/filter_neon_intrinsics.c\n               external/libpng/arm/palette_neon_intrinsics.c\n               external/libpng/png.c\n               external/libpng/pngerror.c\n               external/libpng/pngget.c\n               external/libpng/pngmem.c\n               external/libpng/pngpread.c\n               external/libpng/pngread.c\n               external/libpng/pngrio.c\n               external/libpng/pngrtran.c\n               external/libpng/pngrutil.c\n               external/libpng/pngset.c\n               external/libpng/pngtrans.c\n               external/libpng/pngwio.c\n               external/libpng/pngwrite.c\n               external/libpng/pngwtran.c\n               external/libpng/pngwutil.c\n               external/zlib/adler32.c\n               external/zlib/compress.c\n               external/zlib/crc32.c\n               external/zlib/deflate.c\n               external/zlib/gzclose.c\n               external/zlib/gzlib.c\n               external/zlib/gzread.c\n               external/zlib/gzwrite.c\n               external/zlib/infback.c\n               external/zlib/inffast.c\n               external/zlib/inflate.c\n               external/zlib/inftrees.c\n               external/zlib/trees.c\n               external/zlib/uncompr.c\n               external/zlib/zutil.c\n               )\n\n            include(cmake_utils/check_if_neon_available.cmake)\n            if (ARM_NEON_IS_AVAILABLE)\n               message (STATUS \"NEON instructions will be used for libpng.\")\n               enable_language(ASM)\n               set(source_files ${source_files}\n                  external/libpng/arm/arm_init.c\n                  external/libpng/arm/filter_neon_intrinsics.c\n                  external/libpng/arm/filter_neon.S\n                  )\n               set_source_files_properties(external/libpng/arm/filter_neon.S PROPERTIES COMPILE_FLAGS \"${CMAKE_ASM_FLAGS} ${CMAKE_CXX_FLAGS} -x assembler-with-cpp\")\n            endif()\n         endif()\n         set(source_files ${source_files}\n            image_loader/png_loader.cpp\n            image_saver/save_png.cpp\n            )\n      endif()\n\n      if (DLIB_JPEG_SUPPORT)\n         include(cmake_utils/find_libjpeg.cmake)\n         if (JPEG_FOUND)\n            list (APPEND dlib_needed_private_includes ${JPEG_INCLUDE_DIR})\n            list (APPEND dlib_needed_private_libraries ${JPEG_LIBRARY})\n         else()\n            # If we can't find libjpeg then statically compile it in.\n            add_definitions(-DDLIB_JPEG_STATIC)\n            set(source_files ${source_files}\n              external/libjpeg/jaricom.c\n              external/libjpeg/jcapimin.c\n              external/libjpeg/jcapistd.c\n              external/libjpeg/jcarith.c\n              external/libjpeg/jccoefct.c\n              external/libjpeg/jccolor.c\n              external/libjpeg/jcdctmgr.c\n              external/libjpeg/jchuff.c\n              external/libjpeg/jcinit.c\n              external/libjpeg/jcmainct.c\n              external/libjpeg/jcmarker.c\n              external/libjpeg/jcmaster.c\n              external/libjpeg/jcomapi.c\n              external/libjpeg/jcparam.c\n              external/libjpeg/jcprepct.c\n              external/libjpeg/jcsample.c\n              external/libjpeg/jdapimin.c\n              external/libjpeg/jdapistd.c\n              external/libjpeg/jdarith.c\n              external/libjpeg/jdatadst.c\n              external/libjpeg/jdatasrc.c\n              external/libjpeg/jdcoefct.c\n              external/libjpeg/jdcolor.c\n              external/libjpeg/jddctmgr.c\n              external/libjpeg/jdhuff.c\n              external/libjpeg/jdinput.c\n              external/libjpeg/jdmainct.c\n              external/libjpeg/jdmarker.c\n              external/libjpeg/jdmaster.c\n              external/libjpeg/jdmerge.c\n              external/libjpeg/jdpostct.c\n              external/libjpeg/jdsample.c\n              external/libjpeg/jerror.c\n              external/libjpeg/jfdctflt.c\n              external/libjpeg/jfdctfst.c\n              external/libjpeg/jfdctint.c\n              external/libjpeg/jidctflt.c\n              external/libjpeg/jidctfst.c\n              external/libjpeg/jidctint.c\n              external/libjpeg/jmemmgr.c\n              external/libjpeg/jmemnobs.c\n              external/libjpeg/jquant1.c\n              external/libjpeg/jquant2.c\n              external/libjpeg/jutils.c\n               )\n         endif()\n         set(source_files ${source_files}\n            image_loader/jpeg_loader.cpp\n            image_saver/save_jpeg.cpp\n            )\n      endif()\n      if (DLIB_WEBP_SUPPORT)\n         include(cmake_utils/find_libwebp.cmake)\n         if (WEBP_FOUND)\n            list (APPEND dlib_needed_private_includes ${WEBP_INCLUDE_DIR})\n            list (APPEND dlib_needed_private_libraries ${WEBP_LIBRARY})\n            set(source_files ${source_files}\n               image_loader/webp_loader.cpp\n               image_saver/save_webp.cpp\n               )\n         else()\n             set(DLIB_WEBP_SUPPORT OFF CACHE BOOL ${DLIB_WEBP_SUPPORT_STR} FORCE )\n             toggle_preprocessor_switch(DLIB_WEBP_SUPPORT)\n         endif()\n      endif()\n      if (DLIB_JXL_SUPPORT)\n         include(cmake_utils/find_libjxl.cmake)\n         if (JXL_FOUND)\n            list (APPEND dlib_needed_private_includes ${JXL_INCLUDE_DIRS})\n            list (APPEND dlib_needed_private_libraries ${JXL_LIBRARIES})\n            list (APPEND dlib_needed_public_cflags ${JXL_CFLAGS})\n            list (APPEND dlib_needed_public_ldflags ${JXL_LDFLAGS})\n            set(source_files ${source_files}\n               image_loader/jxl_loader.cpp\n               image_saver/save_jxl.cpp\n               )\n            enable_preprocessor_switch(DLIB_JXL_SUPPORT)\n         else()\n            set(DLIB_JXL_SUPPORT OFF CACHE BOOL ${DLIB_JXL_SUPPORT_STR} FORCE)\n            disable_preprocessor_switch(DLIB_JXL_SUPPORT)\n         endif()\n      endif()\n\n\n      if (DLIB_USE_BLAS OR DLIB_USE_LAPACK OR DLIB_USE_MKL_FFT)\n         if (DLIB_USE_MKL_WITH_TBB AND DLIB_USE_MKL_SEQUENTIAL)\n            set(DLIB_USE_MKL_SEQUENTIAL OFF CACHE STRING ${DLIB_USE_MKL_SEQUENTIAL_STR} FORCE )\n            toggle_preprocessor_switch(DLIB_USE_MKL_SEQUENTIAL)\n            message(STATUS \"Disabling DLIB_USE_MKL_SEQUENTIAL. It cannot be used simultaneously with DLIB_USE_MKL_WITH_TBB.\")\n         endif()\n\n\n         # Try to find BLAS, LAPACK and MKL\n         include(cmake_utils/find_blas.cmake)\n\n         if (DLIB_USE_BLAS)\n            if (blas_found)\n               list (APPEND dlib_needed_public_libraries ${blas_libraries})\n            else()\n               set(DLIB_USE_BLAS OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE )\n               toggle_preprocessor_switch(DLIB_USE_BLAS)\n            endif()\n         endif()\n\n         if (DLIB_USE_LAPACK)\n            if (lapack_found)\n               list (APPEND dlib_needed_public_libraries ${lapack_libraries})\n               if (lapack_with_underscore)\n                  set(LAPACK_FORCE_UNDERSCORE 1)\n                  enable_preprocessor_switch(LAPACK_FORCE_UNDERSCORE)\n               elseif (lapack_without_underscore)\n                  set(LAPACK_FORCE_NOUNDERSCORE 1)\n                  enable_preprocessor_switch(LAPACK_FORCE_NOUNDERSCORE)\n               endif ()\n            else()\n               set(DLIB_USE_LAPACK OFF CACHE STRING ${DLIB_USE_LAPACK_STR} FORCE )\n               toggle_preprocessor_switch(DLIB_USE_LAPACK)\n            endif()\n         endif()\n\n         if (DLIB_USE_MKL_FFT)\n            if (found_intel_mkl AND found_intel_mkl_headers)\n               list (APPEND dlib_needed_public_includes ${mkl_include_dir})\n               list (APPEND dlib_needed_public_libraries ${mkl_libraries})\n            else()\n               set(DLIB_USE_MKL_FFT OFF CACHE STRING ${DLIB_USE_MKL_FFT_STR} FORCE )\n               toggle_preprocessor_switch(DLIB_USE_MKL_FFT)\n            endif()\n         endif()\n      endif()\n\n\n      if (DLIB_USE_CUDA)\n         find_package(CUDAToolkit)\n      \n         if (CUDAToolkit_FOUND AND CUDAToolkit_NVCC_EXECUTABLE)\n            set(CMAKE_CUDA_COMPILER ${CUDAToolkit_NVCC_EXECUTABLE})\n\n            # Set USER_DID_NOT_SPECIFY_WHAT_CUDA_ARCH_TO_USE before calling\n            # enable_language(CUDA) because enable_language() sets\n            # CMAKE_CUDA_ARCHITECTURES to a default that isn't especially\n            # helpful for most users in newer cmake versions.  E.g. it picks\n            # the oldest supported arch the cuda toolkit you have can build for\n            # which is often so old your GPU can't actually run the resulting\n            # kernels.\n            set(USER_DID_NOT_SPECIFY_WHAT_CUDA_ARCH_TO_USE FALSE)\n            if (NOT DEFINED CMAKE_CUDA_ARCHITECTURES AND (NOT DEFINED ENV{CUDAARCHS} OR \"$ENV{CUDAARCHS}\" STREQUAL \"\"))\n               set(USER_DID_NOT_SPECIFY_WHAT_CUDA_ARCH_TO_USE TRUE)\n            endif()\n\n            enable_language(CUDA)\n\n            # If the user didn't say what cuda arch they want to use try to pick something reasonable\n            if(USER_DID_NOT_SPECIFY_WHAT_CUDA_ARCH_TO_USE)\n               if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)\n                  # Auto-detect host GPU(s); safest default on modern CMake.\n                  set(CMAKE_CUDA_ARCHITECTURES native)  # requires CMake ≥ 3.24\n               else()\n                  # Fallback by nvcc version to avoid asking for archs it doesn't know yet\n                  if (CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 11)\n                     # CUDA 10.x and older\n                     set(CMAKE_CUDA_ARCHITECTURES 52;60;61;70;75)\n                  elseif (CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 12)\n                     # CUDA 11.x\n                     set(CMAKE_CUDA_ARCHITECTURES 60;61;70;75;80;86)\n                  else()\n                     # CUDA 12.x+\n                     # (Keep this conservative; add 89/90 only on toolkits that support them.)\n                     set(CMAKE_CUDA_ARCHITECTURES 70;75;80;86;89;90)\n                  endif()\n               endif()\n            endif()\n\n            find_package(CUDNN)\n\n            if(CUDNN_FOUND)\n               set(source_files ${source_files} \n                  cuda/cuda_dlib.cu \n                  cuda/cudnn_dlibapi.cpp\n                  cuda/cublas_dlibapi.cpp\n                  cuda/cusolver_dlibapi.cu\n                  cuda/curand_dlibapi.cpp\n                  cuda/cuda_data_ptr.cpp\n                  cuda/gpu_data.cpp\n                  )\n               list (APPEND dlib_needed_private_libraries CUDA::cublas)\n               list (APPEND dlib_needed_private_libraries ${CUDNN_LIBRARY_PATH})\n               list (APPEND dlib_needed_private_libraries CUDA::curand)\n               list (APPEND dlib_needed_private_libraries CUDA::cusolver)\n               list (APPEND dlib_needed_private_libraries CUDA::cudart)\n               if(openmp_libraries)\n                  list (APPEND dlib_needed_private_libraries ${openmp_libraries})\n               endif()\n\n               include_directories(${CUDAToolkit_INCLUDE_DIRS} ${CUDNN_INCLUDE_PATH})\n               message(STATUS \"Enabling CUDA support for dlib.  DLIB WILL USE CUDA using cuda arch ${CMAKE_CUDA_ARCHITECTURES}.  If you don't want to use that arch set the CUDAARCHS env var or CMAKE_CUDA_ARCHITECTURES cmake variable.\")\n            else()\n                set(DLIB_USE_CUDA OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE )\n               toggle_preprocessor_switch(DLIB_USE_CUDA)\n               message(STATUS \"DID NOT FIND CUDNN\")\n               message(STATUS \"Disabling CUDA support for dlib.  DLIB WILL NOT USE CUDA\")\n               endif()\n         else()\n            set(DLIB_USE_CUDA OFF CACHE STRING ${DLIB_USE_BLAS_STR} FORCE )\n            toggle_preprocessor_switch(DLIB_USE_CUDA)\n            if (NOT CUDA_FOUND)\n               message(STATUS \"DID NOT FIND CUDA\")\n            endif()\n            message(STATUS \"Disabling CUDA support for dlib.  DLIB WILL NOT USE CUDA\")\n         endif()\n      endif()\n\n\n      if (DLIB_LINK_WITH_SQLITE3)\n         find_library(sqlite sqlite3)\n         # make sure sqlite3.h is in the include path\n         find_path(sqlite_path sqlite3.h)\n         if (sqlite AND sqlite_path)\n            list (APPEND dlib_needed_public_includes ${sqlite_path})\n            list (APPEND dlib_needed_public_libraries ${sqlite} )\n         else()\n            set(DLIB_LINK_WITH_SQLITE3 OFF CACHE STRING ${DLIB_LINK_WITH_SQLITE3_STR} FORCE )\n         endif()\n         mark_as_advanced(sqlite sqlite_path)\n      endif()\n\n\n\n      if (DLIB_USE_FFTW)\n         find_library(fftw fftw3)\n         # make sure fftw3.h is in the include path\n         find_path(fftw_path fftw3.h)\n         if (fftw AND fftw_path)\n           list (APPEND dlib_needed_private_includes ${fftw_path})\n           list (APPEND dlib_needed_private_libraries ${fftw})\n         else()\n            set(DLIB_USE_FFTW OFF CACHE STRING ${DLIB_USE_FFTW_STR} FORCE )\n            toggle_preprocessor_switch(DLIB_USE_FFTW)\n         endif()\n         mark_as_advanced(fftw fftw_path)\n      endif()\n\n      if (DLIB_USE_FFMPEG)\n         include(cmake_utils/find_ffmpeg.cmake)\n         if (FFMPEG_FOUND)\n            list (APPEND dlib_needed_public_includes ${FFMPEG_INCLUDE_DIRS})\n            list (APPEND dlib_needed_public_libraries ${FFMPEG_LINK_LIBRARIES})\n            list (APPEND dlib_needed_public_cflags ${FFMPEG_CFLAGS})\n            list (APPEND dlib_needed_public_ldflags ${FFMPEG_LDFLAGS})\n            enable_preprocessor_switch(DLIB_USE_FFMPEG)\n         else()\n            set(DLIB_USE_FFMPEG OFF CACHE BOOL ${DLIB_USE_FFMPEG_STR} FORCE )\n            disable_preprocessor_switch(DLIB_USE_FFMPEG)\n         endif()\n      endif()\n\n      add_library(dlib ${source_files})\n\n\n   endif ()  ##### end of if NOT DLIB_ISO_CPP_ONLY ##########################################################\n\n\n   target_include_directories(dlib\n      INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>\n      INTERFACE $<INSTALL_INTERFACE:include>\n      PUBLIC ${dlib_needed_public_includes}\n      PRIVATE ${dlib_needed_private_includes}\n      )\n   target_link_libraries(dlib PUBLIC ${dlib_needed_public_libraries} ${dlib_needed_public_ldflags})\n   target_link_libraries(dlib PRIVATE ${dlib_needed_private_libraries})\n   target_compile_options(dlib PUBLIC ${dlib_needed_public_cflags})\n   if (DLIB_IN_PROJECT_BUILD)\n      target_compile_options(dlib PUBLIC ${active_preprocessor_switches})\n   else()\n      # These are private in this case because they will be controlled by the\n      # contents of dlib/config.h once it's installed. But for in project\n      # builds, there is no real config.h so they are public in the above case.\n      target_compile_options(dlib PRIVATE ${active_preprocessor_switches})\n      # Do this so that dlib/config.h won't set DLIB_NOT_CONFIGURED. This will then allow\n      # the code in dlib/threads_kernel_shared.cpp to emit a linker error for users who\n      # don't use the configured config.h file generated by cmake.\n      target_compile_options(dlib PRIVATE -DDLIB__CMAKE_GENERATED_A_CONFIG_H_FILE)\n\n      # Do this so that dlib/config.h can record the version of dlib it's configured with\n      # and ultimately issue a linker error to people who try to use a binary dlib that is\n      # the wrong version.\n      set(DLIB_CHECK_FOR_VERSION_MISMATCH \n         DLIB_VERSION_MISMATCH_CHECK__EXPECTED_VERSION_${CPACK_PACKAGE_VERSION_MAJOR}_${CPACK_PACKAGE_VERSION_MINOR}_${CPACK_PACKAGE_VERSION_PATCH})\n      target_compile_options(dlib PRIVATE \"-DDLIB_CHECK_FOR_VERSION_MISMATCH=${DLIB_CHECK_FOR_VERSION_MISMATCH}\")\n   endif()\n\n\n   # Allow the unit tests to ask us to compile the all/source.cpp file just to make sure it compiles.\n   if (DLIB_TEST_COMPILE_ALL_SOURCE_CPP)\n      add_library(dlib_all_source_cpp STATIC all/source.cpp) \n      target_link_libraries(dlib_all_source_cpp dlib)\n      target_compile_options(dlib_all_source_cpp PUBLIC ${active_preprocessor_switches})\n      target_compile_features(dlib_all_source_cpp PUBLIC cxx_std_14)\n   endif()\n\n   target_compile_features(dlib PUBLIC cxx_std_14)\n   if((MSVC AND CMAKE_VERSION VERSION_LESS 3.11))\n      target_compile_options(dlib PUBLIC ${active_compile_opts})\n      target_compile_options(dlib PRIVATE ${active_compile_opts_private})\n   else()\n      target_compile_options(dlib PUBLIC $<$<COMPILE_LANGUAGE:CXX>:${active_compile_opts}>)\n      target_compile_options(dlib PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${active_compile_opts_private}>)\n   endif()\n\n   # Install the library\n   if (NOT DLIB_IN_PROJECT_BUILD)\n      string (REPLACE \";\" \" \" pkg_config_dlib_needed_libraries \"${dlib_needed_public_libraries}\")\n      # Make the -I include options for pkg-config\n      foreach (ITR ${dlib_needed_public_includes})\n         set (pkg_config_dlib_needed_includes \"${pkg_config_dlib_needed_includes} -I${ITR}\")\n      endforeach()\n      set_target_properties(dlib PROPERTIES\n         VERSION ${VERSION})\n      install(TARGETS dlib\n         EXPORT dlib \n         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # Windows considers .dll to be runtime artifacts\n         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}\n         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})\n\n      install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib\n         FILES_MATCHING \n            PATTERN \"*.h\" \n            PATTERN \"*.cmake\"\n            PATTERN \"*_tutorial.txt\"\n            PATTERN \"cassert\"\n            PATTERN \"cstring\"\n            PATTERN \"fstream\"\n            PATTERN \"iomanip\"\n            PATTERN \"iosfwd\"\n            PATTERN \"iostream\"\n            PATTERN \"istream\"\n            PATTERN \"locale\"\n            PATTERN \"ostream\"\n            PATTERN \"sstream\"\n            REGEX \"${CMAKE_CURRENT_BINARY_DIR}\" EXCLUDE)\n\n\n      configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)\n      # overwrite config.h with the configured one\n      install(FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib)\n\n      configure_file(${PROJECT_SOURCE_DIR}/revision.h.in ${CMAKE_CURRENT_BINARY_DIR}/revision.h)\n      install(FILES ${CMAKE_CURRENT_BINARY_DIR}/revision.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dlib)\n\n      ## Config.cmake generation and installation\n\n      set(ConfigPackageLocation \"${CMAKE_INSTALL_LIBDIR}/cmake/dlib\")\n      install(EXPORT dlib\n         NAMESPACE dlib::\n         DESTINATION ${ConfigPackageLocation})\n\n      configure_file(cmake_utils/dlibConfig.cmake.in \"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake\" @ONLY)\n\n      include(CMakePackageConfigHelpers)\n      write_basic_package_version_file(\n         \"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake\"\n         VERSION ${VERSION}\n         COMPATIBILITY AnyNewerVersion\n         )\n\n      install(FILES \n         \"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfig.cmake\" \n         \"${CMAKE_CURRENT_BINARY_DIR}/config/dlibConfigVersion.cmake\" \n         DESTINATION ${ConfigPackageLocation})\n\n      ## dlib-1.pc generation and installation\n\n      configure_file(\"cmake_utils/dlib.pc.in\" \"dlib-1.pc\" @ONLY)\n      install(FILES \"${CMAKE_CURRENT_BINARY_DIR}/dlib-1.pc\"\n         DESTINATION \"${CMAKE_INSTALL_LIBDIR}/pkgconfig\")\n\n      # Add a cpack \"package\" target. This will create an archive containing\n      # the built library file, the header files, and cmake and pkgconfig\n      # configuration files.\n      include(CPack)\n\n   endif()\n\nendif()\n\nif (MSVC)\n   # Give the output library files names that are unique functions of the\n   # visual studio mode that compiled them.  We do this so that people who\n   # compile dlib and then copy the .lib files around (which they shouldn't be\n   # doing in the first place!) will hopefully be slightly less confused by\n   # what happens since, at the very least, the filenames will indicate what\n   # visual studio runtime they go with.\n   math(EXPR numbits ${CMAKE_SIZEOF_VOID_P}*8)\n   set_target_properties(dlib PROPERTIES DEBUG_POSTFIX \"${VERSION}_debug_${numbits}bit_msvc${MSVC_VERSION}\")\n   set_target_properties(dlib PROPERTIES RELEASE_POSTFIX \"${VERSION}_release_${numbits}bit_msvc${MSVC_VERSION}\")\n   set_target_properties(dlib PROPERTIES MINSIZEREL_POSTFIX \"${VERSION}_minsizerel_${numbits}bit_msvc${MSVC_VERSION}\")\n   set_target_properties(dlib PROPERTIES RELWITHDEBINFO_POSTFIX \"${VERSION}_relwithdebinfo_${numbits}bit_msvc${MSVC_VERSION}\")\nendif()\n\n# Check if we are being built as part of a pybind11 module. \nif (COMMAND pybind11_add_module)\n   # Don't export unnecessary symbols.\n   set_target_properties(dlib PROPERTIES CXX_VISIBILITY_PRESET \"hidden\")\n   set_target_properties(dlib PROPERTIES CUDA_VISIBILITY_PRESET \"hidden\")\nendif()\n\nif (WIN32 AND mkl_iomp_dll)\n   # If we are using the Intel MKL on windows then try and copy the iomp dll\n   # file to the output folder.  We do this since a very large number of\n   # windows users don't understand that they need to add the Intel MKL's\n   # folders to their PATH to use the Intel MKL.  They then complain on the\n   # dlib forums.  Copying the Intel MKL dlls to the output directory removes\n   # the need to add the Intel MKL to the PATH.\n   if (CMAKE_LIBRARY_OUTPUT_DIRECTORY)\n      add_custom_command(TARGET dlib POST_BUILD\n         # In some newer versions of windows/visual studio the output Config folder doesn't\n         # exist at first, so you can't copy to it unless you make it yourself.  So make\n         # sure the target folder exists first.\n         COMMAND ${CMAKE_COMMAND} -E make_directory \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/\"\n         COMMAND ${CMAKE_COMMAND} -E copy \"${mkl_iomp_dll}\" \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/\"\n         )\n   else()\n      add_custom_command(TARGET dlib POST_BUILD\n         # In some newer versions of windows/visual studio the output Config folder doesn't\n         # exist at first, so you can't copy to it unless you make it yourself.  So make\n         # sure the target folder exists first.\n         COMMAND ${CMAKE_COMMAND} -E make_directory \"${CMAKE_BINARY_DIR}/$<CONFIG>/\"\n         COMMAND ${CMAKE_COMMAND} -E copy \"${mkl_iomp_dll}\" \"${CMAKE_BINARY_DIR}/$<CONFIG>/\"\n         )\n   endif()\nendif()\n\nadd_library(dlib::dlib ALIAS dlib)\n"
  },
  {
    "path": "dlib/LICENSE.txt",
    "content": "Boost Software License - Version 1.0 - August 17th, 2003\n\nPermission is hereby granted, free of charge, to any person or organization\nobtaining a copy of the software and accompanying documentation covered by\nthis license (the \"Software\") to use, reproduce, display, distribute,\nexecute, and transmit the Software, and to prepare derivative works of the\nSoftware, and to permit third-parties to whom the Software is furnished to\ndo so, all subject to the following:\n\nThe copyright notices in the Software and this entire statement, including\nthe above license grant, this restriction and the following disclaimer,\nmust be included in all copies of the Software, in whole or in part, and\nall derivative works of the Software, unless such copies or derivative\nworks are solely in the form of machine-executable object code generated by\na source language processor.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\nSHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\nFOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE."
  },
  {
    "path": "dlib/algs.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_ALGs_\n#define DLIB_ALGs_\n\n// this file contains miscellaneous stuff                      \n\n// Give people who forget the -std=c++14 option a reminder\n#if (defined(__GNUC__) && ((__GNUC__ >= 5 && __GNUC_MINOR__ >= 0) || (__GNUC__ > 5))) || \\\n    (defined(__clang__) && ((__clang_major__ >= 3 && __clang_minor__ >= 4) || (__clang_major__ >= 3)))\n    #if __cplusplus < 201402L\n        #error \"Dlib requires C++14 support.  Give your compiler the -std=c++14 option to enable it.\"\n    #endif\n#endif\n\n#if defined __NVCC__\n    // Disable the \"statement is unreachable\" message since it will go off on code that is\n    // actually reachable but just happens to not be reachable sometimes during certain\n    // template instantiations.\n    #ifdef __NVCC_DIAG_PRAGMA_SUPPORT__\n    #pragma nv_diag_suppress code_is_unreachable\n    #else\n    #pragma diag_suppress code_is_unreachable\n    #endif\n#endif\n\n\n#ifdef _MSC_VER\n\n#if  _MSC_VER < 1900\n#error \"dlib versions newer than v19.1 use C++11 and therefore require Visual Studio 2015 or newer.\"\n#endif\n\n// Disable the following warnings for Visual Studio\n\n// this is to disable the \"'this' : used in base member initializer list\"\n// warning you get from some of the GUI objects since all the objects\n// require that their parent class be passed into their constructor. \n// In this case though it is totally safe so it is ok to disable this warning.\n#pragma warning(disable : 4355)\n\n// This is a warning you get sometimes when Visual Studio performs a Koenig Lookup. \n// This is a bug in visual studio.  It is a totally legitimate thing to \n// expect from a compiler. \n#pragma warning(disable : 4675)\n\n// This is a warning you get from visual studio 2005 about things in the standard C++\n// library being \"deprecated.\"  I checked the C++ standard and it doesn't say jack \n// about any of them (I checked the searchable PDF).   So this warning is total Bunk.\n#pragma warning(disable : 4996)\n\n// This is a warning you get from visual studio 2003:\n//    warning C4345: behavior change: an object of POD type constructed with an initializer \n//    of the form () will be default-initialized.\n// I love it when this compiler gives warnings about bugs in previous versions of itself. \n#pragma warning(disable : 4345)\n\n\n// Disable warnings about conversion from size_t to unsigned long and long.\n#pragma warning(disable : 4267)\n\n// Disable warnings about conversion from double to float  \n#pragma warning(disable : 4244)\n#pragma warning(disable : 4305)\n\n// Disable \"warning C4180: qualifier applied to function type has no meaning; ignored\".\n// This warning happens often in generic code that works with functions and isn't useful.\n#pragma warning(disable : 4180)\n\n// Disable \"warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)\"\n#pragma warning(disable : 4290)\n\n\n// DNN module uses template-based network declaration that leads to very long\n// type names. Visual Studio will produce Warning C4503 in such cases. https://msdn.microsoft.com/en-us/library/074af4b6.aspx says\n// that correct binaries are still produced even when this warning happens, but linker errors from visual studio, if they occur could be confusing.\n#pragma warning( disable: 4503 )\n\n\n#endif\n\n#ifdef __BORLANDC__\n// Disable the following warnings for the Borland Compilers\n//\n// These warnings just say that the compiler is refusing to inline functions with\n// loops or try blocks in them.  \n//\n#pragma option -w-8027\n#pragma option -w-8026 \n#endif\n\n#include <string>       // for the exceptions\n\n#ifdef __CYGWIN__\nnamespace std\n{\n   typedef std::basic_string<wchar_t> wstring;\n}\n#endif\n\n#include \"platform.h\"\n#include \"windows_magic.h\"\n\n\n#include <algorithm>    // for std::swap\n#include <new>          // for std::bad_alloc\n#include <cstdlib>\n#include <stddef.h>\n#include <limits>\n#include <cmath> // for std::isfinite for is_finite()\n#include \"assert.h\"\n#include \"error.h\"\n#include \"noncopyable.h\"\n#include \"enable_if.h\"\n#include \"uintn.h\"\n#include \"numeric_constants.h\"\n#include \"memory_manager_stateless/memory_manager_stateless_kernel_1.h\" // for the default memory manager\n#include \"type_traits.h\"\n\n// ----------------------------------------------------------------------------------------\n/*!A _dT !*/\n\ntemplate <typename charT>\ninline charT _dTcast (const char a, const wchar_t b);\ntemplate <>\ninline char _dTcast<char> (const char a, const wchar_t ) { return a; }\ntemplate <>\ninline wchar_t _dTcast<wchar_t> (const char , const wchar_t b) { return b; }\n\ntemplate <typename charT>\ninline const charT* _dTcast ( const char* a, const wchar_t* b);\ntemplate <>\ninline const char* _dTcast<char> ( const char* a, const wchar_t* ) { return a; }\ntemplate <>\ninline const wchar_t* _dTcast<wchar_t> ( const char* , const wchar_t* b) { return b; }\n\n\n#define _dT(charT,str) _dTcast<charT>(str,L##str) \n/*!\n    requires\n        - charT == char or wchar_t\n        - str == a string or character literal\n    ensures\n        - returns the literal in the form of a charT type literal.\n!*/\n\n// ----------------------------------------------------------------------------------------\n\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A default_memory_manager\n\n        This memory manager just calls new and delete directly.  \n\n    !*/\n    typedef memory_manager_stateless_kernel_1<char> default_memory_manager;\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A swap !*/\n    // make swap available in the dlib namespace\n    using std::swap;\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        Here is where I define my return codes.  It is \n        important that they all be < 0.\n    !*/\n\n    enum general_return_codes\n    {\n        TIMEOUT     = -1,\n        WOULDBLOCK  = -2,\n        OTHER_ERROR = -3,\n        SHUTDOWN    = -4,\n        PORTINUSE   = -5\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long square_root (\n        unsigned long value\n    )\n    /*!\n        requires\n            - value <= 2^32 - 1\n        ensures\n            - returns the square root of value.  if the square root is not an\n              integer then it will be rounded up to the nearest integer.\n    !*/\n    {\n        unsigned long x;\n\n        // set the initial guess for what the root is depending on \n        // how big value is\n        if (value < 3)\n            return value;\n        else if (value < 4096) // 12\n            x = 45;\n        else if (value < 65536) // 16\n            x = 179;\n        else if (value < 1048576) // 20\n            x = 717;\n        else if (value < 16777216) // 24\n            x = 2867;\n        else if (value < 268435456) // 28\n            x = 11469;\n        else   // 32\n            x = 45875;\n\n\n\n        // find the root\n        x = (x + value/x)>>1;\n        x = (x + value/x)>>1;\n        x = (x + value/x)>>1;\n        x = (x + value/x)>>1;\n\n\n\n        if (x*x < value)\n            return x+1;\n        else\n            return x;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >    \n    void median (\n        T& one,\n        T& two,\n        T& three\n    );\n    /*!\n        requires\n            - T implements operator< \n            - T is swappable by a global swap()\n        ensures\n            - #one is the median \n            - #one, #two, and #three is some permutation of one, two, and three.  \n    !*/\n    \n    \n    template <\n        typename T\n        >\n    void median (\n        T& one,\n        T& two,\n        T& three\n    )    \n    {    \n        using std::swap;\n        using dlib::swap;\n\n        if ( one < two )\n        {\n            // one < two\n            if ( two < three )\n            {\n                // one < two < three : two\n                swap(one,two);\n                \n            }\n            else\n            {\n                // one < two >= three\n                if ( one < three)\n                {\n                    // three\n                    swap(three,one);\n                }\n            }\n            \n        }\n        else\n        {\n            // one >= two\n            if ( three < one )\n            {\n                // three <= one >= two\n                if ( three < two )\n                {\n                    // two\n                    swap(two,one);\n                }\n                else\n                {\n                    // three\n                    swap(three,one);\n                }\n            }\n        }        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace relational_operators\n    {\n        template <\n            typename A,\n            typename B\n            >\n        constexpr bool operator> (\n            const A& a,\n            const B& b\n        ) { return b < a; }\n\n    // ---------------------------------\n\n        template <\n            typename A,\n            typename B\n            >\n        constexpr bool operator!= (\n            const A& a,\n            const B& b\n        ) { return !(a == b); }\n\n    // ---------------------------------\n\n        template <\n            typename A,\n            typename B\n            >\n        constexpr bool operator<= (\n            const A& a,\n            const B& b\n        ) { return !(b < a); }\n\n    // ---------------------------------\n\n        template <\n            typename A,\n            typename B\n            >\n        constexpr bool operator>= (\n            const A& a,\n            const B& b\n        ) { return !(a < b); }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void exchange (\n        T& a,\n        T& b\n    )\n    /*!\n        This function does the exact same thing that global swap does and it does it by\n        just calling swap.  But a lot of compilers have problems doing a Koenig Lookup\n        and the fact that this has a different name (global swap has the same name as\n        the member functions called swap) makes them compile right.\n\n        So this is a workaround but not too ugly of one.  But hopefully I can get\n        rid of this in a few years.  So this function is already deprecated. \n\n        This also means you should NOT use this function in your own code unless\n        you have to support an old buggy compiler that benefits from this hack.\n    !*/\n    {\n        using std::swap;\n        using dlib::swap;\n        swap(a,b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct general_ {};\n    struct special_ : general_ {};\n    template<typename> struct int_ { typedef int type; };\n\n// ----------------------------------------------------------------------------------------\n\n\n    /*!A is_same_object \n\n        This is a templated function which checks if both of its arguments are actually\n        references to the same object.  It returns true if they are and false otherwise.\n\n    !*/\n\n    // handle the case where T and U are unrelated types.\n    template < typename T, typename U >\n    std::enable_if_t<!std::is_convertible<T*, U*>::value && !std::is_convertible<U*,T*>::value, bool>\n    is_same_object (\n        const T& a, \n        const U& b\n    ) \n    { \n        return ((void*)&a == (void*)&b); \n    }\n\n    // handle the case where T and U are related types because their pointers can be\n    // implicitly converted into one or the other.  E.g. a derived class and its base class. \n    // Or where both T and U are just the same type.  This way we make sure that if there is a\n    // valid way to convert between these two pointer types then we will take that route rather\n    // than the void* approach used otherwise.\n    template < typename T, typename U >\n    std::enable_if_t<std::is_convertible<T*, U*>::value || std::is_convertible<U*,T*>::value, bool>\n    is_same_object (\n        const T& a, \n        const U& b\n    ) \n    { \n        return (&a == &b); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class copy_functor\n    {\n    public:\n        void operator() (\n            const T& source, \n            T& destination\n        ) const\n        {\n            destination = source;\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A static_switch\n\n        To use this template you give it some number of boolean expressions and it\n        tells you which one of them is true.   If more than one of them is true then\n        it causes a compile time error.\n\n        for example:\n            static_switch<1 + 1 == 2, 4 - 1 == 4>::value == 1  // because the first expression is true\n            static_switch<1 + 1 == 3, 4 == 4>::value == 2      // because the second expression is true\n            static_switch<1 + 1 == 3, 4 == 5>::value == 0      // 0 here because none of them are true \n            static_switch<1 + 1 == 2, 4 == 4>::value == compiler error  // because more than one expression is true \n    !*/\n\n    template < bool v1 = 0, bool v2 = 0, bool v3 = 0, bool v4 = 0, bool v5 = 0,\n               bool v6 = 0, bool v7 = 0, bool v8 = 0, bool v9 = 0, bool v10 = 0, \n               bool v11 = 0, bool v12 = 0, bool v13 = 0, bool v14 = 0, bool v15 = 0 >\n    struct static_switch; \n\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 0; };\n    template <> struct static_switch<1,0,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 1; };\n    template <> struct static_switch<0,1,0,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 2; };\n    template <> struct static_switch<0,0,1,0,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 3; };\n    template <> struct static_switch<0,0,0,1,0,0,0,0,0,0,0,0,0,0,0> { const static int value = 4; };\n    template <> struct static_switch<0,0,0,0,1,0,0,0,0,0,0,0,0,0,0> { const static int value = 5; };\n    template <> struct static_switch<0,0,0,0,0,1,0,0,0,0,0,0,0,0,0> { const static int value = 6; };\n    template <> struct static_switch<0,0,0,0,0,0,1,0,0,0,0,0,0,0,0> { const static int value = 7; };\n    template <> struct static_switch<0,0,0,0,0,0,0,1,0,0,0,0,0,0,0> { const static int value = 8; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,1,0,0,0,0,0,0> { const static int value = 9; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,1,0,0,0,0,0> { const static int value = 10; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,1,0,0,0,0> { const static int value = 11; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,1,0,0,0> { const static int value = 12; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,1,0,0> { const static int value = 13; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,1,0> { const static int value = 14; };\n    template <> struct static_switch<0,0,0,0,0,0,0,0,0,0,0,0,0,0,1> { const static int value = 15; };\n\n// ----------------------------------------------------------------------------------------\n    \n    template <typename T>\n    std::enable_if_t<std::is_floating_point<T>::value, bool> is_finite(T value)\n    /*!\n        requires\n            - value must be some kind of scalar type such as int or double\n        ensures\n            - returns true if value is a finite value (e.g. not infinity or NaN) and false\n              otherwise.\n    !*/\n    {\n        return std::isfinite(value);\n    }\n    \n    template <typename T>\n    std::enable_if_t<std::is_integral<T>::value, bool> is_finite(T value)\n    {\n        return std::isfinite((double)value);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A promote \n        \n        This is a template that takes one of the built in scalar types and gives you another\n        scalar type that should be big enough to hold sums of values from the original scalar \n        type.  The new scalar type will also always be signed.\n\n        For example, promote<uint16>::type == int32\n    !*/\n\n    template <typename T, size_t s = sizeof(T)> struct promote;\n    template <typename T> struct promote<T,1> { typedef int32 type; };\n    template <typename T> struct promote<T,2> { typedef int32 type; };\n    template <typename T> struct promote<T,4> { typedef int64 type; };\n    template <typename T> struct promote<T,8> { typedef int64 type; };\n\n    template <> struct promote<float,sizeof(float)>             { typedef double type; };\n    template <> struct promote<double,sizeof(double)>           { typedef double type; };\n    template <> struct promote<long double,sizeof(long double)> { typedef long double type; };\n\n// ----------------------------------------------------------------------------------------\n    \n    /*!A assign_zero_if_built_in_scalar_type\n\n        This function assigns its argument the value of 0 if it is a built in scalar\n        type according to the is_built_in_scalar_type<> template.  If it isn't a\n        built in scalar type then it does nothing.\n    !*/\n\n    template <typename T> inline typename disable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T&){}\n    template <typename T> inline typename enable_if<is_built_in_scalar_type<T>,void>::type assign_zero_if_built_in_scalar_type (T& a){a=0;}\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    T put_in_range (\n        const T& a, \n        const T& b, \n        const T& val\n    )\n    /*!\n        requires\n            - T is a type that looks like double, float, int, or so forth\n        ensures\n            - if (val is within the range [a,b]) then\n                - returns val\n            - else \n                - returns the end of the range [a,b] that is closest to val\n    !*/\n    {\n        if (a < b)\n        {\n            if (val < a)\n                return a;\n            else if (val > b)\n                return b;\n        }\n        else\n        {\n            if (val < b)\n                return b;\n            else if (val > a)\n                return a;\n        }\n\n        return val;\n    }\n\n    // overload for double \n    inline double put_in_range(const double& a, const double& b, const double& val)\n    { return put_in_range<double>(a,b,val); }\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A tabs \n\n        This is a template to compute the absolute value a number at compile time.\n\n        For example,\n            abs<-4>::value == 4\n            abs<4>::value == 4\n    !*/\n\n    template <long x, typename enabled=void>\n    struct tabs { const static long value = x; };\n    template <long x>\n    struct tabs<x,typename enable_if_c<(x < 0)>::type> { const static long value = -x; };\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A tmax\n\n        This is a template to compute the max of two values at compile time\n\n        For example,\n            abs<4,7>::value == 7\n    !*/\n\n    template <long x, long y, typename enabled=void>\n    struct tmax { const static long value = x; };\n    template <long x, long y>\n    struct tmax<x,y,typename enable_if_c<(y > x)>::type> { const static long value = y; };\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A tmin \n\n        This is a template to compute the min of two values at compile time\n\n        For example,\n            abs<4,7>::value == 4\n    !*/\n\n    template <long x, long y, typename enabled=void>\n    struct tmin { const static long value = x; };\n    template <long x, long y>\n    struct tmin<x,y,typename enable_if_c<(y < x)>::type> { const static long value = y; };\n\n// ----------------------------------------------------------------------------------------\n\n#define DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(testname, returnT, funct_name, args)                        \\\n    struct _two_bytes_##testname { char a[2]; };                                                       \\\n    template < typename T, returnT (T::*funct)args >                                                   \\\n    struct _helper_##testname { typedef char type; };                                                  \\\n    template <typename T>                                                                              \\\n    static char _has_##testname##_helper( typename _helper_##testname<T,&T::funct_name >::type ) { return 0;} \\\n    template <typename T>                                                                              \\\n    static _two_bytes_##testname _has_##testname##_helper(int) { return _two_bytes_##testname();}             \\\n    template <typename T> struct _##testname##workaroundbug {                                          \\\n                const static unsigned long U = sizeof(_has_##testname##_helper<T>('a')); };            \\\n    template <typename T, unsigned long U = _##testname##workaroundbug<T>::U >                         \\\n    struct testname      { static const bool value = false; };                                         \\\n    template <typename T>                                                                              \\\n    struct testname<T,1> { static const bool value = true; };\n    /*!A DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST\n\n        The DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST() macro is used to define traits templates\n        that tell you if a class has a certain member function.  For example, to make a\n        test to see if a class has a public method with the signature void print(int) you\n        would say:\n            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, (int))\n\n        Then you can check if a class, T, has this method by looking at the boolean value:\n            has_print<T>::value \n        which will be true if the member function is in the T class.\n\n        Note that you can test for member functions taking no arguments by simply passing\n        in empty () like so:\n            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ())\n        This would test for a member of the form:\n            void print().\n\n        To test for const member functions you would use a statement such as this:\n            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, print, ()const)\n        This would test for a member of the form: \n            void print() const.\n\n        To test for const templated member functions you would use a statement such as this:\n            DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(has_print, void, template print<int>, ())\n        This would test for a member of the form: \n            template <typename T> void print().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T> class funct_wrap0\n    {\n    public:\n        funct_wrap0(T (&f_)()):f(f_){}\n        T operator()() const { return f(); }\n    private:\n        T (&f)();\n    };\n    template <typename T, typename A0> class funct_wrap1\n    {\n    public:\n        funct_wrap1(T (&f_)(A0)):f(f_){}\n        T operator()(A0 a0) const { return f(a0); }\n    private:\n        T (&f)(A0);\n    };\n    template <typename T, typename A0, typename A1> class funct_wrap2\n    {\n    public:\n        funct_wrap2(T (&f_)(A0,A1)):f(f_){}\n        T operator()(A0 a0, A1 a1) const { return f(a0,a1); }\n    private:\n        T (&f)(A0,A1);\n    };\n    template <typename T, typename A0, typename A1, typename A2> class funct_wrap3\n    {\n    public:\n        funct_wrap3(T (&f_)(A0,A1,A2)):f(f_){}\n        T operator()(A0 a0, A1 a1, A2 a2) const { return f(a0,a1,a2); }\n    private:\n        T (&f)(A0,A1,A2);\n    };\n    template <typename T, typename A0, typename A1, typename A2, typename A3> class funct_wrap4\n    {\n    public:\n        funct_wrap4(T (&f_)(A0,A1,A2,A3)):f(f_){}\n        T operator()(A0 a0, A1 a1, A2 a2, A3 a3) const { return f(a0,a1,a2,a3); }\n    private:\n        T (&f)(A0,A1,A2,A3);\n    };\n    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4> class funct_wrap5\n    {\n    public:\n        funct_wrap5(T (&f_)(A0,A1,A2,A3,A4)):f(f_){}\n        T operator()(A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) const { return f(a0,a1,a2,a3,a4); }\n    private:\n        T (&f)(A0,A1,A2,A3,A4);\n    };\n\n    /*!A wrap_function \n        \n        This is a template that allows you to turn a global function into a \n        function object.  The reason for this template's existence is so you can\n        do stuff like this:\n            \n            template <typename T>\n            void call_funct(const T& funct)\n            {  cout << funct(); }\n\n            std::string test() { return \"asdfasf\"; }\n\n            int main()\n            {\n                call_funct(wrap_function(test));\n            }\n\n        The above code doesn't work right on some compilers if you don't\n        use wrap_function.  \n    !*/\n\n    template <typename T>\n    funct_wrap0<T> wrap_function(T (&f)()) { return funct_wrap0<T>(f); }\n    template <typename T, typename A0>\n    funct_wrap1<T,A0> wrap_function(T (&f)(A0)) { return funct_wrap1<T,A0>(f); }\n    template <typename T, typename A0, typename A1>\n    funct_wrap2<T,A0,A1> wrap_function(T (&f)(A0, A1)) { return funct_wrap2<T,A0,A1>(f); }\n    template <typename T, typename A0, typename A1, typename A2>\n    funct_wrap3<T,A0,A1,A2> wrap_function(T (&f)(A0, A1, A2)) { return funct_wrap3<T,A0,A1,A2>(f); }\n    template <typename T, typename A0, typename A1, typename A2, typename A3>\n    funct_wrap4<T,A0,A1,A2,A3> wrap_function(T (&f)(A0, A1, A2, A3)) { return funct_wrap4<T,A0,A1,A2,A3>(f); }\n    template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4>\n    funct_wrap5<T,A0,A1,A2,A3,A4> wrap_function(T (&f)(A0, A1, A2, A3, A4)) { return funct_wrap5<T,A0,A1,A2,A3,A4>(f); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <unsigned long bSIZE>\n    class stack_based_memory_block : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple container for a block of memory\n                of bSIZE bytes.  This memory block is located on the stack\n                and properly aligned to hold any kind of object.\n        !*/\n    public:\n        static const unsigned long size = bSIZE;\n\n        stack_based_memory_block(): data(mem.data) {}\n\n        void* get () { return data; }\n        /*!\n            ensures\n                - returns a pointer to the block of memory contained in this object\n        !*/\n\n        const void* get () const { return data; }\n        /*!\n            ensures\n                - returns a pointer to the block of memory contained in this object\n        !*/\n\n    private:\n\n        // You obviously can't have a block of memory that has zero bytes in it.\n        COMPILE_TIME_ASSERT(bSIZE > 0);\n        \n        union mem_block\n        {\n            // All of this garbage is to make sure this union is properly aligned \n            // (a union is always aligned such that everything in it would be properly\n            // aligned.  So the assumption here is that one of these objects has \n            // a large enough alignment requirement to satisfy any object this\n            // block of memory might be cast into).\n            void* void_ptr;\n            int integer;\n            struct {\n                void (stack_based_memory_block::*callback)();\n                stack_based_memory_block* o; \n            } stuff;\n            long double more_stuff;\n\n            uint64 var1;\n            uint32 var2;\n            double var3;\n\n            char data[size]; \n        } mem;\n\n        // The reason for having this variable is that doing it this way avoids\n        // warnings from gcc about violations of strict-aliasing rules.\n        void* const data; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename F\n        >\n    auto max_scoring_element(\n        const T& container,\n        F score_func\n    ) -> decltype(std::make_pair(*container.begin(), 0.0))\n    /*!\n        requires\n            - container has .begin() and .end(), allowing it to be enumerated.\n            - score_func() is a function that takes an element of the container and returns a double.\n        ensures\n            - This function finds the element of container that has the largest score,\n              according to score_func(), and returns a std::pair containing that maximal\n              element along with the score.\n            - If the container is empty then make_pair(a default initialized object, -infinity) is returned.\n    !*/\n    {\n        double best_score = -std::numeric_limits<double>::infinity();\n        auto best_i = container.begin();\n        for (auto i = container.begin(); i != container.end(); ++i)\n        {\n            auto score = score_func(*i);\n            if (score > best_score)\n            {\n                best_score = score;\n                best_i = i;\n            }\n        }\n\n        using item_type = typename std::remove_reference<decltype(*best_i)>::type;\n\n        if (best_i == container.end())\n            return std::make_pair(item_type(), best_score);\n        else\n            return std::make_pair(*best_i, best_score);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename F\n        >\n    auto min_scoring_element(\n        const T& container, \n        F score_func\n    ) -> decltype(std::make_pair(*container.begin(), 0.0))\n    /*!\n        requires\n            - container has .begin() and .end(), allowing it to be enumerated.\n            - score_func() is a function that takes an element of the container and returns a double.\n        ensures\n            - This function finds the element of container that has the smallest score,\n              according to score_func(), and returns a std::pair containing that minimal\n              element along with the score.\n            - If the container is empty then make_pair(a default initialized object, infinity) is returned.\n    !*/\n    {\n        double best_score = std::numeric_limits<double>::infinity();\n        auto best_i = container.begin();\n        for (auto i = container.begin(); i != container.end(); ++i)\n        {\n            auto score = score_func(*i);\n            if (score < best_score)\n            {\n                best_score = score;\n                best_i = i;\n            }\n        }\n\n        using item_type = typename std::remove_reference<decltype(*best_i)>::type;\n\n        if (best_i == container.end())\n            return std::make_pair(item_type(), best_score);\n        else\n            return std::make_pair(*best_i, best_score);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n        template <class Tuple, class F, std::size_t... I>\n        constexpr void for_each_impl(Tuple&& t, F&& f, std::index_sequence<I...>)\n        {\n#ifdef __cpp_fold_expressions\n            (std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))),...);\n#else\n            (void)std::initializer_list<int>{(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))),0)...};\n#endif\n        }\n    }\n\n    template <class Tuple, class F>\n    constexpr void for_each_in_tuple(Tuple&& t, F&& f)\n    {\n        detail::for_each_impl(std::forward<Tuple>(t), std::forward<F>(f),\n                              std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_ALGs_\n\n"
  },
  {
    "path": "dlib/all/source.cpp",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ALL_SOURCe_\n#define DLIB_ALL_SOURCe_\n\n#if defined(DLIB_ALGs_) || defined(DLIB_PLATFORm_)\n#include \"../dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n// ISO C++ code\n#include \"../base64/base64_kernel_1.cpp\"\n#include \"../bigint/bigint_kernel_1.cpp\"\n#include \"../bigint/bigint_kernel_2.cpp\"\n#include \"../bit_stream/bit_stream_kernel_1.cpp\"\n#include \"../entropy_decoder/entropy_decoder_kernel_1.cpp\"\n#include \"../entropy_decoder/entropy_decoder_kernel_2.cpp\"\n#include \"../entropy_encoder/entropy_encoder_kernel_1.cpp\"\n#include \"../entropy_encoder/entropy_encoder_kernel_2.cpp\"\n#include \"../md5/md5_kernel_1.cpp\"\n#include \"../tokenizer/tokenizer_kernel_1.cpp\"\n#include \"../unicode/unicode.cpp\"\n#include \"../test_for_odr_violations.cpp\"\n\n\n\n\n#ifndef DLIB_ISO_CPP_ONLY\n// Code that depends on OS specific APIs\n\n// include this first so that it can disable the older version\n// of the winsock API when compiled in windows.\n#include \"../sockets/sockets_kernel_1.cpp\"\n#include \"../bsp/bsp.cpp\"\n\n#include \"../dir_nav/dir_nav_kernel_1.cpp\"\n#include \"../dir_nav/dir_nav_kernel_2.cpp\"\n#include \"../dir_nav/dir_nav_extensions.cpp\"\n#include \"../fft/fft.cpp\"\n#include \"../linker/linker_kernel_1.cpp\"\n#include \"../logger/extra_logger_headers.cpp\"\n#include \"../logger/logger_kernel_1.cpp\"\n#include \"../logger/logger_config_file.cpp\"\n#include \"../misc_api/misc_api_kernel_1.cpp\"\n#include \"../misc_api/misc_api_kernel_2.cpp\"\n#include \"../sockets/sockets_extensions.cpp\"\n#include \"../sockets/sockets_kernel_2.cpp\"\n#include \"../sockstreambuf/sockstreambuf.cpp\"\n#include \"../sockstreambuf/sockstreambuf_unbuffered.cpp\"\n#include \"../server/server_kernel.cpp\"\n#include \"../server/server_iostream.cpp\"\n#include \"../server/server_http.cpp\"\n#include \"../threads/multithreaded_object_extension.cpp\"\n#include \"../threads/threaded_object_extension.cpp\"\n#include \"../threads/threads_kernel_1.cpp\"\n#include \"../threads/threads_kernel_2.cpp\"\n#include \"../threads/threads_kernel_shared.cpp\"\n#include \"../threads/thread_pool_extension.cpp\"\n#include \"../threads/async.cpp\"\n#include \"../timer/timer.cpp\"\n#include \"../stack_trace.cpp\"\n\n#ifdef DLIB_PNG_SUPPORT\n#include \"../image_loader/png_loader.cpp\"\n#include \"../image_saver/save_png.cpp\"\n#endif\n\n#ifdef DLIB_JPEG_SUPPORT\n#include \"../image_loader/jpeg_loader.cpp\"\n#include \"../image_saver/save_jpeg.cpp\"\n#endif\n\n#include \"../gui_widgets/fonts.cpp\"\n\n#ifndef DLIB_NO_GUI_SUPPORT\n#include \"../gui_widgets/widgets.cpp\"\n#include \"../gui_widgets/drawable.cpp\"\n#include \"../gui_widgets/canvas_drawing.cpp\"\n#include \"../gui_widgets/style.cpp\"\n#include \"../gui_widgets/base_widgets.cpp\"\n#include \"../gui_core/gui_core_kernel_1.cpp\"\n#include \"../gui_core/gui_core_kernel_2.cpp\"\n#endif // DLIB_NO_GUI_SUPPORT\n\n#include \"../cuda/cpu_dlib.cpp\"\n#include \"../cuda/tensor_tools.cpp\"\n#include \"../data_io/image_dataset_metadata.cpp\"\n#include \"../data_io/mnist.cpp\"\n#include \"../data_io/cifar.cpp\"\n#include \"../svm/auto.cpp\"\n#include \"../global_optimization/global_function_search.cpp\"\n#include \"../filtering/kalman_filter.cpp\"\n\n#endif // DLIB_ISO_CPP_ONLY\n\n\n\n\n\n#define DLIB_ALL_SOURCE_END\n\n#endif // DLIB_ALL_SOURCe_\n\n"
  },
  {
    "path": "dlib/any/any.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_AnY_H_\n#define DLIB_AnY_H_\n\n#include \"any_abstract.h\"\n#include <memory>\n#include \"storage.h\"\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    class any\n    {\n    public:\n        any()                               = default;\n        any(const any& other)               = default;\n        any& operator=(const any& other)    = default;\n        any(any&& other)                    = default;\n        any& operator=(any&& other)         = default;\n\n        template<\n            typename T,\n            std::enable_if_t<!std::is_same<std::decay_t<T>, any>::value, bool> = true\n        >\n        any(T&& item)\n        : storage{std::forward<T>(item)}\n        {\n        }\n\n        template<\n            typename T,\n            typename T_ = std::decay_t<T>,\n            std::enable_if_t<!std::is_same<T_, any>::value, bool> = true\n        >\n        any& operator=(T&& item)\n        {\n            if (contains<T_>())\n                storage.unsafe_get<T_>() = std::forward<T>(item);\n            else\n                *this = any{std::forward<T>(item)};\n            return *this;\n        }\n\n        bool is_empty() const { return storage.is_empty(); }\n        void clear()          { storage.clear(); }\n        void swap (any& item) { std::swap(*this, item); }\n\n        template<typename T>      bool contains() const { return storage.contains<T>();}\n        template <typename T>       T& cast_to()        { return storage.cast_to<T>(); }\n        template <typename T> const T& cast_to() const  { return storage.cast_to<T>(); }\n        template <typename T>       T& get()            { return storage.get<T>(); }\n\n    private:\n        te::storage_heap storage;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T> T& any_cast(any& a) { return a.cast_to<T>(); }\n    template <typename T> const T& any_cast(const any& a) { return a.cast_to<T>(); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // DLIB_AnY_H_\n\n\n\n"
  },
  {
    "path": "dlib/any/any_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_AnY_ABSTRACT_H_\n#ifdef DLIB_AnY_ABSTRACT_H_\n\n#include <typeinfo>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class bad_any_cast : public std::bad_cast \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is the exception class used by the any object.\n                It is used to indicate when someone attempts to cast an any\n                object into a type which isn't contained in the any object.\n        !*/\n\n    public:\n          virtual const char* what() const noexcept { return \"bad_any_cast\"; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class any\n    {\n        /*!\n            INITIAL VALUE\n                - is_empty() == true\n                - for all T: contains<T>() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is basically a type-safe version of a void*.  In particular,\n                it is a container which can contain only one object but the object may\n                be of any type.  \n\n                It is somewhat like the type_safe_union except you don't have to declare \n                the set of possible content types beforehand.  So in some sense this is \n                like a less type-strict version of the type_safe_union.\n        !*/\n\n    public:\n\n        any(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        any (\n            const any& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that *this and item will contain independent copies of the\n                  contents of item.  That is, this function performs a deep\n                  copy and therefore does not result in *this containing\n                  any kind of reference to item.\n        !*/\n\n        any_function (\n            any_function&& item\n        );\n        /*!\n            ensures\n                - #item.is_empty() == true\n                - moves item into *this.\n        !*/\n\n        template < typename T >\n        any (\n            const T& item\n        );\n        /*!\n            ensures\n                - #contains<T>() == true\n                - #cast_to<T>() == item\n                  (i.e. a copy of item will be stored in *this)\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - #*this will have its default value.  I.e. #is_empty() == true\n        !*/\n\n        template <typename T>\n        bool contains (\n        ) const;\n        /*!\n            ensures\n                - if (this object currently contains an object of type T) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_empty(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains any kind of object) then\n                    - returns false \n                - else\n                    - returns true \n        !*/\n\n        template <typename T>\n        T& cast_to(\n        );\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a non-const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        const T& cast_to(\n        ) const;\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        T& get(\n        );\n        /*!\n            ensures\n                - #is_empty() == false\n                - #contains<T>() == true\n                - if (contains<T>() == true)\n                    - returns a non-const reference to the object contained in *this.\n                - else\n                    - Constructs an object of type T inside *this\n                    - Any previous object stored in this any object is destructed and its\n                      state is lost.\n                    - returns a non-const reference to the newly created T object.\n        !*/\n\n        any& operator= (\n            const any& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that *this and item will contain independent copies of the\n                  contents of item.  That is, this function performs a deep\n                  copy and therefore does not result in *this containing\n                  any kind of reference to item.\n        !*/\n\n        void swap (\n            any& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n                - does not invalidate pointers or references to the object contained \n                  inside *this or item.  Moreover, a pointer or reference to the object in \n                  *this will now refer to the contents of #item and vice versa.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        > \n    T& any_cast(\n        any& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        > \n    const T& any_cast(\n        const any& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_AnY_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/any/any_decision_function.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_AnY_DECISION_FUNCTION_Hh_\n#define DLIB_AnY_DECISION_FUNCTION_Hh_\n\n#include \"any_decision_function_abstract.h\"\n#include \"any_function.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <class sample_type, class result_type = double>\n    using any_decision_function = any_function<result_type(const sample_type&)>;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // DLIB_AnY_DECISION_FUNCTION_Hh_\n"
  },
  {
    "path": "dlib/any/any_decision_function_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_\n#ifdef DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_\n\n#include \"any_function_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <class sample_type, class result_type = double>\n    using any_decision_function = any_function<result_type(const sample_type&)>;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_AnY_DECISION_FUNCTION_ABSTRACT_H_\n\n\n\n"
  },
  {
    "path": "dlib/any/any_function.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_AnY_FUNCTION_Hh_\n#define DLIB_AnY_FUNCTION_Hh_\n\n#include \"../assert.h\"\n#include \"../functional.h\"\n#include \"any.h\"\n#include \"any_function_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        class Storage, \n        class F\n    > \n    class any_function_basic;\n\n    template <\n        class Storage,\n        class R, \n        class... Args\n    > \n    class any_function_basic<Storage, R(Args...)> \n    {\n    private:\n        template<class F>\n        using is_valid = std::enable_if_t<!std::is_same<std::decay_t<F>, any_function_basic>::value &&\n                                          dlib::is_invocable_r<R, F, Args...>::value,\n                                          bool>;\n\n        template<typename Func>\n        static auto make_invoker()\n        {\n            return [](void* self, Args... args) -> R {\n                return dlib::invoke(*reinterpret_cast<std::add_pointer_t<Func>>(self),\n                                    std::forward<Args>(args)...);\n            };\n        }\n\n        Storage str;\n        R (*func)(void*, Args...) = nullptr;\n\n    public:\n\n        using result_type = R;\n        \n        constexpr any_function_basic(std::nullptr_t) noexcept {}\n        constexpr any_function_basic()                                              = default;\n        constexpr any_function_basic(const any_function_basic& other)               = default;\n        constexpr any_function_basic& operator=(const any_function_basic& other)    = default;\n\n        constexpr any_function_basic(any_function_basic&& other) \n        :   str{std::move(other.str)}, \n            func{std::exchange(other.func, nullptr)} \n        {\n        }\n\n        constexpr any_function_basic& operator=(any_function_basic&& other)\n        {\n            if (this != &other)\n            {\n                str     = std::move(other.str);\n                func    = std::exchange(other.func, nullptr);\n            }\n\n            return *this;\n        }\n\n        template<class F, is_valid<F> = true>\n        any_function_basic(\n            F&& f\n        ) : str{std::forward<F>(f)},\n            func{make_invoker<F&&>()}\n        {\n        }\n\n        template<class F, is_valid<F> = true>\n        any_function_basic(\n            F* f\n        ) : str{f},\n            func{make_invoker<F*>()}\n        {\n        }\n\n        R operator()(Args... args) const {\n            return func(const_cast<void*>(str.get_ptr()), std::forward<Args>(args)...);\n        }\n\n        void clear()                            { str.clear(); }\n        void swap (any_function_basic& item)    { std::swap(*this, item); }\n        bool is_empty()          const noexcept { return str.is_empty() || func == nullptr; }\n        bool is_set()            const noexcept { return !is_empty(); }\n        explicit operator bool() const noexcept { return is_set(); }\n\n        template <typename T>     bool contains() const { return str.template contains<T>();}\n        template <typename T>       T& cast_to()        { return str.template cast_to<T>(); }\n        template <typename T> const T& cast_to() const  { return str.template cast_to<T>(); }\n        template <typename T>       T& get()            { return str.template get<T>(); }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <class T, class Storage, class F> \n    T& any_cast(any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }\n\n    template <class T, class Storage, class F> \n    const T& any_cast(const any_function_basic<Storage, F>& a) { return a.template cast_to<T>(); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <class F> \n    using any_function = any_function_basic<te::storage_sbo<16>, F>;\n\n    template <class F> \n    using any_function_view = any_function_basic<te::storage_view, F>;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_AnY_FUNCTION_Hh_\n\n"
  },
  {
    "path": "dlib/any/any_function_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_AnY_FUNCTION_ABSTRACT_H_\n#ifdef DLIB_AnY_FUNCTION_ABSTRACT_H_\n\n#include \"any_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        class Storage, \n        typename function_type\n        >\n    class any_function_basic\n    {\n        /*!\n            REQUIREMENTS ON Storage\n                This must be one of the storage types from dlib/any/storage.hh\n                E.g. storage_heap, storage_stack, etc.\n\n                It determines the method by which any_function_basic holds onto the function it uses.\n\n            REQUIREMENTS ON function_type\n                This type should be a function signature.  Some examples are:\n                    void (int,int)  // a function returning nothing and taking two ints\n                    void ()         // a function returning nothing and taking no arguments\n                    char (double&)  // a function returning a char and taking a reference to a double\n\n                The number of arguments in the function must be no greater than 10.\n\n            INITIAL VALUE\n                - is_empty() == true\n                - for all T: contains<T>() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a version of dlib::any that is restricted to containing \n                elements which are some kind of function object with an operator() which\n                matches the function signature defined by function_type.\n\n\n                Here is an example:\n                    #include <iostream>\n                    #include <string>\n                    #include \"dlib/any.h\"\n                    void print_message(string str) { cout << str << endl; }\n\n                    int main()\n                    {\n                        dlib::any_function<void(string)> f;\n                        f = print_message;\n                        f(\"hello world\"); // calls print_message(\"hello world\")\n                    }\n\n                Note that any_function_basic objects can be used to store general function \n                objects (i.e. defined by a class with an overloaded operator()) in\n                addition to regular global functions.  \n        !*/\n\n    public:\n\n        // This is the type of object returned by function_type functions.\n        typedef result_type_for_function_type result_type;\n\n        any_function_basic(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        any_function_basic (\n            const any_function_basic& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that *this and item will contain independent copies of the\n                  contents of item.  That is, this function performs a deep\n                  copy and therefore does not result in *this containing\n                  any kind of reference to item.\n        !*/\n\n        any_function_basic (\n            any_function_basic&& item\n        );\n        /*!\n            ensures\n                - moves item into *this.\n                - The exact move semantics are determined by which Storage type is used.  E.g. \n                  storage_heap will result in #item.is_empty()==true but storage_view would result\n                  in #item.is_empty() == false\n        !*/\n\n        template < typename Funct >\n        any_function_basic (\n            Funct&& funct \n        );\n        /*!\n            ensures\n                - #contains<T>() == true\n                - #cast_to<T>() == item\n                  (i.e. calling operator() will invoke funct())\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - #*this will have its default value.  I.e. #is_empty() == true\n        !*/\n\n        template <typename T>\n        bool contains (\n        ) const;\n        /*!\n            ensures\n                - if (this object currently contains an object of type T) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_empty(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains any kind of object) then\n                    - returns false \n                - else\n                    - returns true \n        !*/\n\n        bool is_set (\n        ) const;\n        /*!\n            ensures\n                - returns !is_empty()\n        !*/\n\n        explicit operator bool(\n        ) const;\n        /*!\n            ensures\n                - returns is_set()\n        !*/\n\n        result_type operator(Args... args) (\n        ) const;\n        /*!\n            requires\n                - is_empty() == false\n                - the signature defined by function_type takes no arguments\n            ensures\n                - Let F denote the function object contained within *this.  Then\n                  this function performs:\n                    return F(std::forward<Args>(args)...)\n        !*/\n\n        template <typename T>\n        T& cast_to(\n        );\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a non-const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        const T& cast_to(\n        ) const;\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        T& get(\n        );\n        /*!\n            ensures\n                - #is_empty() == false\n                - #contains<T>() == true\n                - if (contains<T>() == true)\n                    - returns a non-const reference to the object contained in *this.\n                - else\n                    - Constructs an object of type T inside *this\n                    - Any previous object stored in this any_function_basic object is destructed and its\n                      state is lost.\n                    - returns a non-const reference to the newly created T object.\n        !*/\n\n        any_function_basic& operator= (\n            const any_function_basic& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that the type of copy is determined by the Storage template argument.  E.g.\n                  storage_sbo will result in a deep copy, while storage_view would result in *this\n                  and item referring to the same underlying function.\n        !*/\n\n        void swap (\n            any_function_basic& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename function_type\n        > \n    T& any_cast(\n        any_function_basic<function_type>& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename function_type\n        > \n    const T& any_cast(\n        const any_function_basic<function_type>& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A any_function\n\n        A version of any_function_basic (defined above) that owns the function it contains.  Uses\n        the small buffer optimization to make working with small lambdas faster.\n    !*/\n    template <class F> \n    using any_function = any_function_basic<te::storage_sbo<16>, F>;\n\n    /*!A any_function_view\n\n        A version of any_function_basic (defined above) that *DOES NOT* own the function it\n        contains.  It merely holds a pointer to the function given to its constructor. \n    !*/\n    template <class F> \n    using any_function_view = any_function_basic<te::storage_view, F>;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_AnY_FUNCTION_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/any/any_trainer.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_AnY_TRAINER_H_\n#define DLIB_AnY_TRAINER_H_\n\n#include \"any.h\"\n#include \"any_decision_function.h\"\n#include \"any_trainer_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type_,\n        typename scalar_type_ = double\n    >\n    class any_trainer\n    {\n    public:\n        using sample_type = sample_type_;\n        using scalar_type = scalar_type_;\n        using mem_manager_type = default_memory_manager;\n        using trained_function_type = any_decision_function<sample_type, scalar_type>;\n\n        any_trainer()                                       = default;\n        any_trainer(const any_trainer& other)               = default;\n        any_trainer& operator=(const any_trainer& other)    = default;\n        any_trainer(any_trainer&& other)                    = default;\n        any_trainer& operator=(any_trainer&& other)         = default;\n\n        template <\n            class T,\n            class T_ = std::decay_t<T>,\n            std::enable_if_t<!std::is_same<T_,any_trainer>::value, bool> = true\n        >\n        any_trainer (\n            T&& item\n        ) : storage{std::forward<T>(item)},\n            train_func{[](\n                const void* ptr,\n                const std::vector<sample_type>& samples,\n                const std::vector<scalar_type>& labels\n            ) -> trained_function_type {\n                const T_& f = *reinterpret_cast<const T_*>(ptr);\n                return f.train(samples, labels);\n            }}\n        {\n        }\n\n        template <\n            class T,\n            class T_ = std::decay_t<T>,\n            std::enable_if_t<!std::is_same<T_,any_trainer>::value, bool> = true\n        >\n        any_trainer& operator= (\n            T&& item\n        )\n        {\n            if (contains<T_>())\n                storage.unsafe_get<T_>() = std::forward<T>(item);\n            else\n                *this = std::move(any_trainer{std::forward<T>(item)});\n            return *this;\n        }\n\n        trained_function_type train (\n            const std::vector<sample_type>& samples,\n            const std::vector<scalar_type>& labels\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_empty() == false,\n                \"\\t trained_function_type any_trainer::train()\"\n                << \"\\n\\t You can't call train() on an empty any_trainer\"\n                << \"\\n\\t this: \" << this\n                );\n\n            return train_func(storage.get_ptr(), samples, labels);\n        }\n\n        bool is_empty() const { return storage.is_empty(); }\n        void clear()          { storage.clear(); }\n        void swap (any_trainer& item) { std::swap(*this, item); }\n\n        template <typename T>     bool contains() const { return storage.contains<T>();}\n        template <typename T>       T& cast_to()        { return storage.cast_to<T>(); }\n        template <typename T> const T& cast_to() const  { return storage.cast_to<T>(); }\n        template <typename T>       T& get()            { return storage.get<T>(); }\n\n    private:\n        te::storage_heap storage;\n        trained_function_type (*train_func) (\n            const void* self,\n            const std::vector<sample_type>& samples,\n            const std::vector<scalar_type>& labels\n        ) = nullptr;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename V> \n    T& any_cast(any_trainer<U,V>& a) { return a.template cast_to<T>(); }\n\n    template <typename T, typename U, typename V> \n    const T& any_cast(const any_trainer<U,V>& a) { return a.template cast_to<T>(); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // DLIB_AnY_TRAINER_H_\n\n\n\n\n"
  },
  {
    "path": "dlib/any/any_trainer_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_AnY_TRAINER_ABSTRACT_H_\n#ifdef DLIB_AnY_TRAINER_ABSTRACT_H_\n\n#include \"any_abstract.h\"\n#include \"../algs.h\"\n#include \"any_decision_function_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type_,\n        typename scalar_type_ = double\n        >\n    class any_trainer\n    {\n        /*!\n            INITIAL VALUE\n                - is_empty() == true\n                - for all T: contains<T>() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a version of dlib::any that is restricted to containing \n                elements which are some kind of object with a .train() method compatible \n                with the following signature: \n\n                    decision_function train(\n                        const std::vector<sample_type>& samples,\n                        const std::vector<scalar_type>& labels\n                    ) const\n\n                    Where decision_function is a type capable of being stored in an\n                    any_decision_function<sample_type,scalar_type> object.\n\n                any_trainer is intended to be used to contain objects such as the svm_nu_trainer\n                and other similar types which represent supervised machine learning algorithms.   \n                It allows you to write code which contains and processes these trainer objects \n                without needing to know the specific types of trainer objects used.\n        !*/\n\n    public:\n\n        typedef sample_type_ sample_type;\n        typedef scalar_type_ scalar_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef any_decision_function<sample_type, scalar_type> trained_function_type;\n\n        any_trainer(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        any_trainer (\n            const any_trainer& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that *this and item will contain independent copies of the\n                  contents of item.  That is, this function performs a deep\n                  copy and therefore does not result in *this containing\n                  any kind of reference to item.\n        !*/\n\n        any_trainer (\n            any_trainer&& item\n        );\n        /*!\n            ensures\n                - #item.is_empty() == true\n                - moves item into *this.\n        !*/\n\n        template < typename T >\n        any_trainer (\n            const T& item\n        );\n        /*!\n            ensures\n                - #contains<T>() == true\n                - #cast_to<T>() == item\n                  (i.e. a copy of item will be stored in *this)\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - #*this will have its default value.  I.e. #is_empty() == true\n        !*/\n\n        template <typename T>\n        bool contains (\n        ) const;\n        /*!\n            ensures\n                - if (this object currently contains an object of type T) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_empty(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains any kind of object) then\n                    - returns false \n                - else\n                    - returns true\n        !*/\n\n        trained_function_type train (\n            const std::vector<sample_type>& samples,\n            const std::vector<scalar_type>& labels\n        ) const\n        /*!\n            requires\n                - is_empty() == false\n            ensures\n                - Let TRAINER denote the object contained within *this.  Then\n                  this function performs:\n                    return TRAINER.train(samples, labels)\n        !*/\n\n        template <typename T>\n        T& cast_to(\n        );\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a non-const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        const T& cast_to(\n        ) const;\n        /*!\n            ensures\n                - if (contains<T>() == true) then\n                    - returns a const reference to the object contained within *this\n                - else\n                    - throws bad_any_cast\n        !*/\n\n        template <typename T>\n        T& get(\n        );\n        /*!\n            ensures\n                - #is_empty() == false\n                - #contains<T>() == true\n                - if (contains<T>() == true)\n                    - returns a non-const reference to the object contained in *this.\n                - else\n                    - Constructs an object of type T inside *this\n                    - Any previous object stored in this any_trainer object is destructed and its\n                      state is lost.\n                    - returns a non-const reference to the newly created T object.\n        !*/\n\n        any_trainer& operator= (\n            const any_trainer& item\n        );\n        /*!\n            ensures\n                - copies the state of item into *this.  \n                - Note that *this and item will contain independent copies of the\n                  contents of item.  That is, this function performs a deep\n                  copy and therefore does not result in *this containing\n                  any kind of reference to item.\n        !*/\n\n        void swap (\n            any_trainer& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type,\n        typename scalar_type\n        >\n    inline void swap (\n        any_trainer<sample_type,scalar_type>& a,\n        any_trainer<sample_type,scalar_type>& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename sample_type,\n        typename scalar_type\n        > \n    T& any_cast(\n        any_trainer<sample_type,scalar_type>& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename sample_type,\n        typename scalar_type\n        > \n    const T& any_cast(\n        const any_trainer<sample_type,scalar_type>& a\n    ) { return a.cast_to<T>(); }\n    /*!\n        ensures\n            - returns a.cast_to<T>()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_AnY_TRAINER_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/any/storage.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_TYPE_ERASURE_H_\n#define DLIB_TYPE_ERASURE_H_\n\n#include <type_traits>\n#include <utility>\n#include <typeindex>\n#include <new>\n#include <memory>\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------------------\n\n    class bad_any_cast : public std::bad_cast \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is the exception class used by the storage objects.\n                It is used to indicate when someone attempts to cast a storage\n                object into a type which isn't contained in the object.\n        !*/\n        \n    public:\n          virtual const char * what() const noexcept\n          {\n              return \"bad_any_cast\";\n          }\n    };\n    \n// -----------------------------------------------------------------------------------------------------\n\n    namespace te\n    {\n\n        /*!\n            This is used as a SFINAE tool to prevent a function taking a universal reference from\n            binding to some undesired type.  For example:\n                template <\n                    typename T,\n                    T_is_not_this_type<SomeExcludedType, T> = true\n                    >\n                void foo(T&&);\n            prevents foo() from binding to an object of type SomeExcludedType.\n        !*/\n        template<class Storage, class T>\n        using T_is_not_this_type = std::enable_if_t<!std::is_same<std::decay_t<T>, Storage>::value, bool>;\n\n// -----------------------------------------------------------------------------------------------------\n\n        template<class Storage>\n        class storage_base\n        {       \n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class defines functionality common to all type erasure storage objects\n                    (defined below in this file).  These objects are essentially type-safe versions of\n                    a void*.  In particular, they are containers which can contain only one object\n                    but the object may be of any type.  \n\n                    Each storage object implements a different way of storing the underlying object.\n                    E.g. on the heap or stack or some other more specialized method.\n            !*/\n\n        public:\n\n            bool is_empty() const\n            /*!\n                ensures\n                    - if (this object contains any kind of object) then\n                        - returns false \n                    - else\n                        - returns true\n            !*/\n            {\n                const Storage& me = *static_cast<const Storage*>(this);\n                return me.get_ptr() == nullptr;\n            }\n\n            template<typename T>\n            bool contains() const\n            /*!\n                ensures\n                    - if (this object currently contains an object of type T) then\n                        - returns true\n                    - else\n                        - returns false\n            !*/\n            {\n                const Storage& me = *static_cast<const Storage*>(this);\n                return !is_empty() && me.type_id() == std::type_index{typeid(T)};\n            }\n\n            template<typename T>\n            T& unsafe_get() \n            /*!\n                requires\n                    - contains<T>() == true\n                ensures\n                    - returns a reference to the object contained within *this.\n            !*/\n            {\n                DLIB_ASSERT(contains<T>());\n                Storage& me = *static_cast<Storage*>(this);\n                return *reinterpret_cast<T*>(me.get_ptr()); \n            }\n\n            template<typename T>\n            const T& unsafe_get() const \n            /*!\n                requires\n                    - contains<T>() == true\n                ensures\n                    - returns a const reference to the object contained within *this.\n            !*/\n            {\n                DLIB_ASSERT(contains<T>());\n                const Storage& me = *static_cast<const Storage*>(this);\n                return *reinterpret_cast<const T*>(me.get_ptr()); \n            }\n            \n            template <typename T>\n            T& get(\n            ) \n            /*!\n                ensures\n                    - #is_empty() == false\n                    - #contains<T>() == true\n                    - if (contains<T>() == true)\n                        - returns a non-const reference to the object contained in *this.\n                    - else\n                        - Constructs an object of type T inside *this\n                        - Any previous object stored in this any object is destructed and its\n                          state is lost.\n                        - returns a non-const reference to the newly created T object.\n            !*/\n            {\n                Storage& me = *static_cast<Storage*>(this);\n\n                if (!contains<T>())\n                    me = T{};\n                return unsafe_get<T>();\n            }\n\n            template <typename T>\n            T& cast_to(\n            ) \n            /*!\n                ensures\n                    - if (contains<T>() == true) then\n                        - returns a non-const reference to the object contained within *this\n                    - else\n                        - throws bad_any_cast\n            !*/\n            {\n                if (!contains<T>())\n                    throw bad_any_cast{};\n                return unsafe_get<T>();\n            }\n\n            template <typename T>\n            const T& cast_to(\n            ) const\n            /*!\n                ensures\n                    - if (contains<T>() == true) then\n                        - returns a const reference to the object contained within *this\n                    - else\n                        - throws bad_any_cast\n            !*/\n            {\n                if (!contains<T>())\n                    throw bad_any_cast{};\n                return unsafe_get<T>();\n            }\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n        class storage_heap : public storage_base<storage_heap>\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a storage type that uses type erasure to erase any type.\n\n                    This particular storage type uses heap allocation only.\n            !*/\n\n            storage_heap() = default;\n            /*!\n                ensures\n                    - #is_empty() == true\n                    - for all T: #contains<T>() == false\n            !*/\n\n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_heap, T> = true\n            >\n            storage_heap(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)\n            /*!\n                ensures\n                    - copies or moves the incoming object (depending on the forwarding reference)\n                    - #is_empty() == false \n                    - #contains<std::decay_t<T>>() == true\n                    - #unsafe_get<T>() will yield the provided t.\n            !*/\n            :   ptr{new T_{std::forward<T>(t)}},\n                del{[](void *self) { \n                    delete reinterpret_cast<T_*>(self); \n                }},\n                copy{[](const void *self) -> void * {\n                    return new T_{*reinterpret_cast<const T_*>(self)};\n                }},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n            }\n\n            storage_heap(const storage_heap& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor.\n            !*/\n            :   ptr{other.ptr ? other.copy(other.ptr) : nullptr},\n                del{other.del},\n                copy{other.copy},\n                type_id_{other.type_id_}\n            {\n            }\n\n            storage_heap& operator=(const storage_heap& other)\n            /*!\n                ensures\n                    - if is_empty() == false then\n                       - destructs the object contained in this class.\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor.\n            !*/\n            {\n                if (this != &other) \n                    *this = storage_heap{other};\n                return *this;\n            }\n\n            storage_heap(storage_heap&& other) noexcept\n            /*!\n                ensures\n                    - The state of other is moved into *this.\n                    - #other.is_empty() == true\n            !*/\n            :   ptr{std::exchange(other.ptr, nullptr)},\n                del{std::exchange(other.del, nullptr)},\n                copy{std::exchange(other.copy, nullptr)},\n                type_id_{std::exchange(other.type_id_, nullptr)}\n            {\n            }\n\n            storage_heap& operator=(storage_heap&& other) noexcept\n            /*!\n                ensures\n                    - The state of other is moved into *this.\n                    - #other.is_empty() == true\n                    - returns *this\n            !*/\n            {\n                if (this != &other) \n                {\n                    clear();\n                    ptr     = std::exchange(other.ptr, nullptr);\n                    del     = std::exchange(other.del, nullptr);\n                    copy    = std::exchange(other.copy, nullptr);\n                    type_id_ = std::exchange(other.type_id_, nullptr);\n                }\n                return *this;\n            }\n\n            ~storage_heap()\n            /*!\n                ensures\n                    - destructs the object contained in *this if one exists. \n            !*/\n            {\n                if (ptr)\n                    del(ptr);\n            }\n\n            void clear()\n            /*!\n                ensures\n                    - #is_empty() == true\n            !*/\n            {\n                storage_heap{std::move(*this)};\n            }\n\n            void* get_ptr()       \n            /*!\n                ensures\n                    - returns a pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            const void* get_ptr() const \n            /*!\n                ensures\n                    - returns a const pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            std::type_index type_id() const\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - returns the std::type_index of the type contained within this object.\n                      I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.\n            !*/\n            {\n                DLIB_ASSERT(!this->is_empty());\n                return type_id_();\n            }\n\n        private:\n            void* ptr                     = nullptr;\n            void  (*del)(void*)           = nullptr;\n            void* (*copy)(const void*)    = nullptr;\n            std::type_index (*type_id_)()  = nullptr;\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n        template <std::size_t Size, std::size_t Alignment = 8>\n        class storage_stack : public storage_base<storage_stack<Size, Alignment>>\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a storage type that uses type erasure to erase any type.\n\n                    This particular storage type uses stack allocation using a template size and alignment.\n                    Therefore, only objects whose size and alignment fits the template parameters can be\n                    erased and absorbed into this object.  Attempting to store a type not\n                    representable on the stack with those settings will result in a build error.\n\n                    This object will be capable of storing any type with an alignment requirement\n                    that is a divisor of Alignment.\n            !*/\n\n        public:\n            storage_stack() = default;\n            /*!\n                ensures\n                    - #is_empty() == true\n                    - for all T: #contains<T>() == false\n            !*/\n\n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_stack, T> = true\n            >\n            storage_stack(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)\n            /*!\n                ensures\n                    - copies or moves the incoming object (depending on the forwarding reference)\n                    - #is_empty() == false \n                    - #contains<std::decay_t<T>>() == true\n            !*/\n            :   del{[](storage_stack& self) {\n                    reinterpret_cast<T_*>(&self.data)->~T_();\n                    self.del        = nullptr;\n                    self.copy       = nullptr;\n                    self.move       = nullptr;\n                    self.type_id_   = nullptr;\n                }},\n                copy{[](const storage_stack& src, storage_stack& dst) {\n                    new (&dst.data) T_{*reinterpret_cast<const T_*>(&src.data)};\n                    dst.del     = src.del;\n                    dst.copy    = src.copy;\n                    dst.move    = src.move;\n                    dst.type_id_ = src.type_id_;\n                }},\n                move{[](storage_stack& src, storage_stack& dst) {\n                    new (&dst.data) T_{std::move(*reinterpret_cast<T_*>(&src.data))};\n                    dst.del     = src.del;\n                    dst.copy    = src.copy;\n                    dst.move    = src.move;\n                    dst.type_id_ = src.type_id_;\n                }},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n                static_assert(sizeof(T_) <= Size, \"insufficient size\");\n                static_assert(Alignment % alignof(T_) == 0, \"bad alignment\");\n                new (&data) T_{std::forward<T>(t)};\n            }\n\n            storage_stack(const storage_stack& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor.\n            !*/\n            {\n                if (other.copy)\n                    other.copy(other, *this);\n            }\n\n            storage_stack& operator=(const storage_stack& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if is_empty() == false then\n                       - destructs the object contained in this class.\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor\n            !*/\n            {\n                if (this != &other) \n                {\n                    clear();\n                    if (other.copy)\n                        other.copy(other, *this);\n                }\n                return *this;\n            }\n\n            storage_stack(storage_stack&& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is moved using erased type's moved constructor\n            !*/\n            {\n                if (other.move)\n                    other.move(other, *this);\n            }\n\n            storage_stack& operator=(storage_stack&& other)\n            /*!\n                ensures\n                    - if is_empty() == false then\n                       - destructs the object contained in this class.\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is moved using erased type's moved constructor.\n                          This does not make other empty.  It will still contain a moved from object\n                          of the underlying type in whatever that object's moved from state is.\n                        - #other.is_empty() == false\n            !*/\n            {\n                if (this != &other) \n                {\n                    clear();\n                    if (other.move)\n                        other.move(other, *this);\n                }\n                return *this;\n            }\n\n            ~storage_stack()\n            /*!\n                ensures\n                    - destructs the object contained in *this if one exists. \n            !*/\n            {\n                clear();\n            }\n\n            void clear()\n            /*!\n                ensures\n                    - #is_empty() == true\n            !*/\n            {\n                if (del)\n                    del(*this);\n            }\n\n            void* get_ptr()       \n            /*!\n                ensures\n                    - returns a pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return del ? (void*)&data : nullptr;\n            }\n\n            const void* get_ptr() const \n            /*!\n                ensures\n                    - returns a const pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return del ? (const void*)&data : nullptr;\n            }\n\n            std::type_index type_id() const\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - returns the std::type_index of the type contained within this object.\n                      I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.\n            !*/\n            {\n                DLIB_ASSERT(!this->is_empty());\n                return type_id_();\n            }\n\n        private:\n            alignas(Alignment) unsigned char data[Size];\n            void (*del)(storage_stack&)                         = nullptr;\n            void (*copy)(const storage_stack&, storage_stack&)  = nullptr;\n            void (*move)(storage_stack&, storage_stack&)        = nullptr;\n            std::type_index (*type_id_)()                        = nullptr;\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n        template <std::size_t Size, std::size_t Alignment = 8>\n        class storage_sbo : public storage_base<storage_sbo<Size, Alignment>>\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a storage type that uses type erasure to erase any type.\n\n                    This particular storage type uses small buffer optimization (SBO), i.e. optional\n                    stack allocation if the erased type has sizeof <= Size and alignment\n                    requirements no greater than the given Alignment template value.  If not it\n                    allocates the object on the heap.\n            !*/\n\n        public:\n            // type_fits<T>::value tells us if our SBO can hold T.\n            template<typename T>\n            struct type_fits : std::integral_constant<bool, sizeof(T) <= Size && Alignment % alignof(T) == 0>{};\n\n            storage_sbo() = default;\n            /*!\n                ensures\n                    - #is_empty() == true\n                    - for all T: #contains<T>() == false\n            !*/\n\n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_sbo, T> = true,\n                std::enable_if_t<type_fits<T_>::value, bool> = true\n            >\n            storage_sbo(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)\n            /*!\n                ensures\n                    - copies or moves the incoming object (depending on the forwarding reference)\n                    - #is_empty() == false \n                    - #contains<std::decay_t<T>>() == true\n                    - stack allocation is used\n            !*/\n            :   ptr{new (&data) T_{std::forward<T>(t)}},\n                del{[](storage_sbo& self) {\n                    reinterpret_cast<T_*>(&self.data)->~T_();\n                    self.ptr        = nullptr;\n                    self.del        = nullptr;\n                    self.copy       = nullptr;\n                    self.move       = nullptr;\n                    self.type_id_    = nullptr;\n                }},\n                copy{[](const storage_sbo& src, storage_sbo& dst) {\n                    dst.ptr     = new (&dst.data) T_{*reinterpret_cast<const T_*>(src.ptr)};\n                    dst.del     = src.del;\n                    dst.copy    = src.copy;\n                    dst.move    = src.move;\n                    dst.type_id_ = src.type_id_;\n                }},\n                move{[](storage_sbo& src, storage_sbo& dst) {\n                    dst.ptr     = new (&dst.data) T_{std::move(*reinterpret_cast<T_*>(src.ptr))};\n                    dst.del     = src.del;\n                    dst.copy    = src.copy;\n                    dst.move    = src.move;\n                    dst.type_id_ = src.type_id_;\n                }},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n            }\n\n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_sbo, T> = true,\n                std::enable_if_t<!type_fits<T_>::value, bool> = true\n            >\n            storage_sbo(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)\n            /*!\n                ensures\n                    - copies or moves the incoming object (depending on the forwarding reference)\n                    - #is_empty() == false\n                    - #contains<std::decay_t<T>>() == true\n                    - heap allocation is used\n            !*/\n            :   ptr{new T_{std::forward<T>(t)}},\n                del{[](storage_sbo& self) {\n                    delete reinterpret_cast<T_*>(self.ptr);\n                    self.ptr        = nullptr;\n                    self.del        = nullptr;\n                    self.copy       = nullptr;\n                    self.move       = nullptr;\n                    self.type_id_    = nullptr;\n                }},\n                copy{[](const storage_sbo& src, storage_sbo& dst) {\n                    dst.ptr     = new T_{*reinterpret_cast<const T_*>(src.ptr)};\n                    dst.del     = src.del;\n                    dst.copy    = src.copy;\n                    dst.move    = src.move;\n                    dst.type_id_ = src.type_id_;\n                }},\n                move{[](storage_sbo& src, storage_sbo& dst) {\n                    dst.ptr     = std::exchange(src.ptr,     nullptr);\n                    dst.del     = std::exchange(src.del,     nullptr);\n                    dst.copy    = std::exchange(src.copy,    nullptr);\n                    dst.move    = std::exchange(src.move,    nullptr);\n                    dst.type_id_ = std::exchange(src.type_id_, nullptr);\n                }},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n            }\n\n            storage_sbo(const storage_sbo& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor\n            !*/\n            {\n                if (other.copy)\n                    other.copy(other, *this);\n            }\n\n            storage_sbo& operator=(const storage_sbo& other)\n            /*!\n                ensures\n                    - if is_empty() == false then\n                       - destructs the object contained in this class.\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - underlying object of other is copied using erased type's copy constructor\n            !*/\n            {\n                if (this != &other) \n                {\n                    clear();\n                    if (other.copy)\n                        other.copy(other, *this);\n                }\n                return *this;\n            }\n\n            storage_sbo(storage_sbo&& other)\n            /*!\n                ensures\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - if underlying object of other is allocated on stack then\n                            - underlying object of other is moved using erased type's moved constructor.\n                              This does not make other empty.  It will still contain a moved from\n                              object of the underlying type in whatever that object's moved from\n                              state is.\n                            - #other.is_empty() == false\n                        - else\n                            - storage heap pointer is moved.\n                            - #other.is_empty() == true \n            !*/\n            {\n                if (other.move)\n                    other.move(other, *this);\n            }\n\n            storage_sbo& operator=(storage_sbo&& other)\n            /*!\n                ensures\n                    - underlying object is destructed if is_empty() == false\n                    - #is_empty() == other.is_empty()\n                    - if other.is_empty() == false then\n                        - if underlying object of other is allocated on stack then\n                            - underlying object of other is moved using erased type's moved constructor.\n                              This does not make other empty.  It will still contain a moved from\n                              object of the underlying type in whatever that object's moved from\n                              state is.\n                            - #other.is_empty() == false\n                        - else\n                            - storage heap pointer is moved.\n                            - #other.is_empty() == true \n            !*/\n            {\n                if (this != &other) \n                {\n                    clear();\n                    if (other.move)\n                        other.move(other, *this);\n                }\n                return *this;\n            }\n\n            ~storage_sbo()\n            /*!\n                ensures\n                    - destructs the object contained in *this if one exists. \n            !*/\n            {\n                clear();\n            }\n\n            void clear()\n            /*!\n                ensures\n                    - #is_empty() == true\n            !*/\n            {\n                if (ptr)\n                    del(*this);\n            }\n\n            void* get_ptr()       \n            /*!\n                ensures\n                    - returns a pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            const void* get_ptr() const \n            /*!\n                ensures\n                    - returns a const pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            std::type_index type_id() const\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - returns the std::type_index of the type contained within this object.\n                      I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.\n            !*/\n            {\n                DLIB_ASSERT(!this->is_empty());\n                return type_id_();\n            }\n\n        private:\n            alignas(Alignment) unsigned char data[Size];\n            void* ptr                                       = nullptr;\n            void (*del)(storage_sbo&)                       = nullptr;\n            void (*copy)(const storage_sbo&, storage_sbo&)  = nullptr;\n            void (*move)(storage_sbo&, storage_sbo&)        = nullptr;\n            std::type_index (*type_id_)()                    = nullptr;\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n        class storage_shared : public storage_base<storage_shared>\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a storage type that uses type erasure to erase any type.\n\n                    This particular storage type uses std::shared_ptr<void> to store and erase\n                    incoming objects. Therefore, it uses heap allocation and reference counting.\n                    Moreover, it has the same copying and move semantics as std::shared_ptr.  I.e.\n                    it results in the underlying object being held by reference rather than by\n                    value.\n            !*/\n\n        public:\n            storage_shared() = default;\n            /*!\n                ensures\n                    - #is_empty() == true\n                    - for all T: #contains<T>() == false\n            !*/\n\n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_shared, T> = true\n            >\n            storage_shared(T &&t) noexcept(std::is_nothrow_constructible<T_,T&&>::value)\n            /*!\n                ensures\n                    - copies or moves the incoming object (depending on the forwarding reference)\n                    - #is_empty() == true\n                    - #contains<std::decay_t<T>>() == true\n            !*/\n            :   ptr{std::make_shared<T_>(std::forward<T>(t))},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n            }\n\n            // This object has the same copy/move semantics as a std::shared_ptr<void>\n            storage_shared(const storage_shared& other)             = default;\n            storage_shared& operator=(const storage_shared& other)  = default;\n            storage_shared(storage_shared&& other) noexcept = default;\n            storage_shared& operator=(storage_shared&& other) noexcept = default;\n\n            void clear() \n            /*!\n                ensures\n                    - #is_empty() == true\n            !*/\n            { \n                ptr     = nullptr;\n                type_id_ = nullptr;\n            }\n\n            void* get_ptr()       \n            /*!\n                ensures\n                    - returns a pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr.get();\n            }\n\n            const void* get_ptr() const \n            /*!\n                ensures\n                    - returns a const pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr.get();\n            }\n\n            std::type_index type_id() const\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - returns the std::type_index of the type contained within this object.\n                      I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.\n            !*/\n            {\n                DLIB_ASSERT(!this->is_empty());\n                return type_id_();\n            }\n\n        private:\n            std::shared_ptr<void> ptr    = nullptr;\n            std::type_index (*type_id_)() = nullptr;\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n        class storage_view : public storage_base<storage_view>\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a storage type that uses type erasure to erase any type.\n\n                    This particular storage type is a view type, similar to std::string_view or\n                    std::span.  So underlying objects are only ever referenced, not copied, moved or\n                    destructed.  That is, instances of this object take no ownership of the objects\n                    they contain.  So they are only valid as long as the contained object exists.\n                    So storage_view merely holds a pointer to the underlying object.\n            !*/\n\n        public:\n            storage_view() = default;\n            /*!\n                ensures\n                    - #is_empty() == true\n                    - for all T: #contains<T>() == false\n            !*/\n            \n            template <\n                class T,\n                class T_ = std::decay_t<T>,\n                T_is_not_this_type<storage_view, T> = true\n            >\n            storage_view(T &&t) noexcept\n            /*!\n                ensures\n                    - #get_ptr() == &t\n                    - #is_empty() == false \n                    - #contains<std::decay_t<T>>() == true\n            !*/\n            :   ptr{&t},\n                type_id_{[] {\n                    return std::type_index{typeid(T_)};\n                }}\n            {\n            }\n            \n            // This object has the same copy/move semantics as a void*.\n            storage_view(const storage_view& other)             = default;\n            storage_view& operator=(const storage_view& other)  = default;\n            storage_view(storage_view&& other) noexcept = default;\n            storage_view& operator=(storage_view&& other) noexcept = default;\n\n            void clear() \n            /*!\n                ensures\n                    - #is_empty() == true\n            !*/\n            { \n                ptr     = nullptr;\n                type_id_ = nullptr;\n            }\n\n            void* get_ptr()       \n            /*!\n                ensures\n                    - returns a pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            const void* get_ptr() const \n            /*!\n                ensures\n                    - returns a const pointer to the underlying object or nullptr if is_empty()\n            !*/\n            {\n                return ptr;\n            }\n\n            std::type_index type_id() const\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - returns the std::type_index of the type contained within this object.\n                      I.e. if this object contains the type T then this returns std::type_index{typeid(T)}.\n            !*/\n            {\n                DLIB_ASSERT(!this->is_empty());\n                return type_id_();\n            }\n\n        private:\n            void* ptr = nullptr;\n            std::type_index (*type_id_)() = nullptr;\n        };\n\n// -----------------------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif //DLIB_TYPE_ERASURE_H_\n"
  },
  {
    "path": "dlib/any.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_AnY_\n#define DLIB_AnY_\n\n#include \"any/any.h\"\n#include \"any/any_trainer.h\"\n#include \"any/any_decision_function.h\"\n#include \"any/any_function.h\"\n\n#endif // DLIB_AnY_\n\n\n"
  },
  {
    "path": "dlib/array/array_kernel.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY_KERNEl_2_\n#define DLIB_ARRAY_KERNEl_2_\n\n#include \"array_kernel_abstract.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../sort.h\"\n#include \"../is_kind.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager \n        >\n    class array : public enumerable<T>\n    {\n\n        /*!\n            INITIAL VALUE\n                - array_size == 0    \n                - max_array_size == 0\n                - array_elements == 0\n                - pos == 0\n                - last_pos == 0\n                - _at_start == true\n\n            CONVENTION\n                - array_size == size() \n                - max_array_size == max_size() \n                - if (max_array_size > 0)\n                    - array_elements == pointer to max_array_size elements of type T\n                - else\n                    - array_elements == 0\n\n                - if (array_size > 0) \n                    - last_pos == array_elements + array_size - 1\n                - else\n                    - last_pos == 0\n\n\n                - at_start() == _at_start \n                - current_element_valid() == pos != 0\n                - if (current_element_valid()) then\n                    - *pos == element()\n        !*/\n\n    public:\n\n        // These typedefs are here for backwards compatibility with old versions of dlib.\n        typedef array kernel_1a;\n        typedef array kernel_1a_c;\n        typedef array kernel_2a;\n        typedef array kernel_2a_c;\n        typedef array sort_1a;\n        typedef array sort_1a_c;\n        typedef array sort_1b;\n        typedef array sort_1b_c;\n        typedef array sort_2a;\n        typedef array sort_2a_c;\n        typedef array sort_2b;\n        typedef array sort_2b_c;\n        typedef array expand_1a;\n        typedef array expand_1a_c;\n        typedef array expand_1b;\n        typedef array expand_1b_c;\n        typedef array expand_1c;\n        typedef array expand_1c_c;\n        typedef array expand_1d;\n        typedef array expand_1d_c;\n\n\n\n\n        typedef T type;\n        typedef T value_type;\n        typedef mem_manager mem_manager_type;\n\n        array (\n        ) :\n            array_size(0),\n            max_array_size(0),\n            array_elements(0),\n            pos(0),\n            last_pos(0),\n            _at_start(true)\n        {}\n\n        array(const array&) = delete;\n        array& operator=(array&) = delete; \n\n        array(\n            array&& item\n        ) : array()\n        {\n            swap(item);\n        }\n\n        array& operator=(\n            array&& item\n        )\n        {\n            swap(item);\n            return *this;\n        }\n\n        explicit array (\n            size_t new_size\n        ) :\n            array_size(0),\n            max_array_size(0),\n            array_elements(0),\n            pos(0),\n            last_pos(0),\n            _at_start(true)\n        {\n            resize(new_size);\n        }\n\n        ~array (\n        ); \n\n        void clear (\n        );\n\n        inline const T& operator[] (\n            size_t pos\n        ) const;\n\n        inline T& operator[] (\n            size_t pos\n        );\n\n        void set_size (\n            size_t size\n        );\n\n        inline size_t max_size(\n        ) const;\n\n        void set_max_size(\n            size_t max\n        );\n\n        void swap (\n            array& item\n        );\n\n        // functions from the enumerable interface\n        inline size_t size (\n        ) const;\n\n        inline bool at_start (\n        ) const;\n\n        inline void reset (\n        ) const;\n\n        bool current_element_valid (\n        ) const;\n\n        inline const T& element (\n        ) const;\n\n        inline T& element (\n        );\n\n        bool move_next (\n        ) const;\n\n        void sort (\n        );\n\n        void resize (\n            size_t new_size\n        );\n\n        const T& back (\n        ) const;\n\n        T& back (\n        );\n\n        void pop_back (\n        );\n\n        void pop_back (\n            T& item\n        );\n\n        void push_back (\n            T& item\n        );\n\n        void push_back (\n            T&& item\n        );\n\n        typedef T* iterator;\n        typedef const T* const_iterator;\n        iterator                begin()                         { return array_elements; }\n        const_iterator          begin() const                   { return array_elements; }\n        iterator                end()                           { return array_elements+array_size; }\n        const_iterator          end() const                     { return array_elements+array_size; }\n\n    private:\n\n        typename mem_manager::template rebind<T>::other pool;\n\n        // data members\n        size_t array_size;\n        size_t max_array_size;\n        T* array_elements;\n\n        mutable T* pos;\n        T* last_pos;\n        mutable bool _at_start;\n\n    };\n\n    template <\n        typename T,\n        typename mem_manager \n        >\n    inline void swap (\n        array<T,mem_manager>& a, \n        array<T,mem_manager>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void serialize (\n        const array<T,mem_manager>& item,  \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.max_size(),out);\n            serialize(item.size(),out);\n\n            for (size_t i = 0; i < item.size(); ++i)\n                serialize(item[i],out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array\"); \n        }\n    }\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        array<T,mem_manager>& item,  \n        std::istream& in\n    )\n    {\n        try\n        {\n            size_t max_size, size;\n            deserialize(max_size,in);\n            deserialize(size,in);\n            item.set_max_size(max_size);\n            item.set_size(size);\n            for (size_t i = 0; i < size; ++i)\n                deserialize(item[i],in);\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    array<T,mem_manager>::\n    ~array (\n    )\n    {\n        if (array_elements)\n        {\n            pool.deallocate_array(array_elements);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    clear (\n    )\n    {\n        reset();\n        last_pos = 0;\n        array_size = 0;\n        if (array_elements)\n        {\n            pool.deallocate_array(array_elements);\n        }\n        array_elements = 0;\n        max_array_size = 0;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& array<T,mem_manager>::\n    operator[] (\n        size_t pos\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( pos < this->size() , \n            \"\\tconst T& array::operator[]\"\n            << \"\\n\\tpos must < size()\" \n            << \"\\n\\tpos: \" << pos \n            << \"\\n\\tsize(): \" << this->size()\n            << \"\\n\\tthis: \" << this\n            );\n\n        return array_elements[pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& array<T,mem_manager>::\n    operator[] (\n        size_t pos\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( pos < this->size() , \n            \"\\tT& array::operator[]\"\n            << \"\\n\\tpos must be < size()\" \n            << \"\\n\\tpos: \" << pos \n            << \"\\n\\tsize(): \" << this->size()\n            << \"\\n\\tthis: \" << this\n            );\n\n        return array_elements[pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    set_size (\n        size_t size\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( size <= this->max_size() ),\n            \"\\tvoid array::set_size\"\n            << \"\\n\\tsize must be <= max_size()\"\n            << \"\\n\\tsize: \" << size \n            << \"\\n\\tmax size: \" << this->max_size()\n            << \"\\n\\tthis: \" << this\n            );\n\n        reset();\n        array_size = size;\n        if (size > 0)\n            last_pos = array_elements + size - 1;\n        else\n            last_pos = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    size_t array<T,mem_manager>::\n    size (\n    ) const\n    {\n        return array_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    set_max_size(\n        size_t max\n    )\n    {\n        reset();\n        array_size = 0;\n        last_pos = 0;\n        if (max != 0)\n        {\n            // if new max size is different\n            if (max != max_array_size)\n            {\n                if (array_elements)\n                {\n                    pool.deallocate_array(array_elements);\n                }\n                // try to get more memroy\n                try { array_elements = pool.allocate_array(max); }\n                catch (...) { array_elements = 0;  max_array_size = 0; throw; }\n                max_array_size = max;\n            }\n\n        }\n        // if the array is being made to be zero\n        else\n        {\n            if (array_elements)\n                pool.deallocate_array(array_elements);\n            max_array_size = 0;\n            array_elements = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    size_t array<T,mem_manager>::\n    max_size (\n    ) const\n    {\n        return max_array_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    swap (\n        array<T,mem_manager>& item\n    )\n    {\n        auto             array_size_temp        = item.array_size;\n        auto             max_array_size_temp    = item.max_array_size;\n        T*               array_elements_temp    = item.array_elements;\n\n        item.array_size         = array_size;\n        item.max_array_size     = max_array_size;\n        item.array_elements     = array_elements;\n\n        array_size        = array_size_temp;\n        max_array_size    = max_array_size_temp;\n        array_elements    = array_elements_temp;\n\n        exchange(_at_start,item._at_start);\n        exchange(pos,item.pos);\n        exchange(last_pos,item.last_pos);\n        pool.swap(item.pool);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//           enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool array<T,mem_manager>::\n    at_start (\n    ) const\n    {\n        return _at_start;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    reset (\n    ) const\n    {\n        _at_start = true;\n        pos = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool array<T,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return pos != 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& array<T,mem_manager>::\n    element (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(this->current_element_valid(),\n            \"\\tconst T& array::element()\"\n            << \"\\n\\tThe current element must be valid if you are to access it.\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        return *pos;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& array<T,mem_manager>::\n    element (\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(this->current_element_valid(),\n            \"\\tT& array::element()\"\n            << \"\\n\\tThe current element must be valid if you are to access it.\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        return *pos;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool array<T,mem_manager>::\n    move_next (\n    ) const\n    {\n        if (!_at_start)\n        {\n            if (pos < last_pos)\n            {\n                ++pos;\n                return true;\n            }\n            else\n            {\n                pos = 0;\n                return false;\n            }\n        }\n        else\n        {\n            _at_start = false;\n            if (array_size > 0)\n            {\n                pos = array_elements;\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Yet more functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    sort (\n    )\n    {\n        if (this->size() > 1)\n        {\n            // call the quick sort function for arrays that is in algs.h\n            dlib::qsort_array(*this,0,this->size()-1);\n        }\n        this->reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    resize (\n        size_t new_size\n    )\n    {\n        if (this->max_size() < new_size)\n        {\n            array temp;\n            temp.set_max_size(new_size);\n            temp.set_size(new_size);\n            for (size_t i = 0; i < this->size(); ++i)\n            {\n                exchange((*this)[i],temp[i]);\n            }\n            temp.swap(*this);\n        }\n        else\n        {\n            this->set_size(new_size);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& array<T,mem_manager>::\n    back (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( this->size() > 0 , \n                      \"\\tT& array::back()\"\n                      << \"\\n\\tsize() must be bigger than 0\" \n                      << \"\\n\\tsize(): \" << this->size()\n                      << \"\\n\\tthis:   \" << this\n        );\n\n        return (*this)[this->size()-1];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& array<T,mem_manager>::\n    back (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( this->size() > 0 , \n                      \"\\tconst T& array::back()\"\n                      << \"\\n\\tsize() must be bigger than 0\" \n                      << \"\\n\\tsize(): \" << this->size()\n                      << \"\\n\\tthis:   \" << this\n        );\n\n        return (*this)[this->size()-1];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    pop_back (\n        T& item\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( this->size() > 0 , \n                      \"\\tvoid array::pop_back()\"\n                      << \"\\n\\tsize() must be bigger than 0\" \n                      << \"\\n\\tsize(): \" << this->size()\n                      << \"\\n\\tthis:   \" << this\n        );\n\n        exchange(item,(*this)[this->size()-1]);\n        this->set_size(this->size()-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    pop_back (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( this->size() > 0 , \n                      \"\\tvoid array::pop_back()\"\n                      << \"\\n\\tsize() must be bigger than 0\" \n                      << \"\\n\\tsize(): \" << this->size()\n                      << \"\\n\\tthis:   \" << this\n        );\n\n        this->set_size(this->size()-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    push_back (\n        T& item\n    ) \n    {\n        if (this->max_size() == this->size())\n        {\n            // double the size of the array\n            array temp;\n            temp.set_max_size(this->size()*2 + 1);\n            temp.set_size(this->size()+1);\n            for (size_t i = 0; i < this->size(); ++i)\n            {\n                exchange((*this)[i],temp[i]);\n            }\n            exchange(item,temp[temp.size()-1]);\n            temp.swap(*this);\n        }\n        else\n        {\n            this->set_size(this->size()+1);\n            exchange(item,(*this)[this->size()-1]);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array<T,mem_manager>::\n    push_back (\n        T&& item\n    ) { push_back(item); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename MM>\n    struct is_array <array<T,MM> >  \n    {\n        const static bool value = true;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ARRAY_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/array/array_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ARRAY_KERNEl_ABSTRACT_\n#ifdef DLIB_ARRAY_KERNEl_ABSTRACT_\n\n#include \"../interfaces/enumerable.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager \n        >\n    class array : public enumerable<T>\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must have a default constructor.\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                front(), back(), swap(), max_size(), set_size(), and operator[] \n                functions do not invalidate pointers or references to internal data.\n                All other functions have no such guarantee.\n\n            INITIAL VALUE\n                size() == 0    \n                max_size() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the elements of the array in the\n                order (*this)[0], (*this)[1], (*this)[2], ...\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an ordered 1-dimensional array of items, \n                each item is associated with an integer value.  The items are \n                numbered from 0 though size() - 1 and the operator[] functions \n                run in constant time.  \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n        !*/\n        \n        public:\n\n            typedef T type;\n            typedef T value_type;\n            typedef mem_manager mem_manager_type;\n\n            array (\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            explicit array (\n                size_t new_size\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                    - #size() == new_size\n                    - #max_size() == new_size\n                    - All elements of the array will have initial values for their type.\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            ~array (\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            array(\n                array&& item\n            );\n            /*!\n                ensures\n                    - move constructs *this from item.  Therefore, the state of item is\n                      moved into *this and #item has a valid but unspecified state.\n            !*/\n\n            array& operator=(\n                array&& item\n            );\n            /*!\n                ensures\n                    - move assigns *this from item.  Therefore, the state of item is\n                      moved into *this and #item has a valid but unspecified state.\n                    - returns a reference to #*this\n            !*/\n\n            void clear (\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if this exception is thrown then the array object is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            const T& operator[] (\n                size_t pos\n            ) const;\n            /*!\n                requires\n                    - pos < size()\n                ensures\n                    - returns a const reference to the element at position pos\n            !*/\n            \n            T& operator[] (\n                size_t pos\n            );\n            /*!\n                requires\n                    - pos < size()\n                ensures\n                    - returns a non-const reference to the element at position pos\n            !*/\n\n            void set_size (\n                size_t size\n            );\n            /*!\n                requires\n                    - size <= max_size()\n                ensures\n                    - #size() == size\n                    - any element with index between 0 and size - 1 which was in the \n                      array before the call to set_size() retains its value and index.\n                      All other elements have undetermined (but valid for their type) \n                      values.  (e.g. this object might buffer old T objects and reuse \n                      them without reinitializing them between calls to set_size())\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        may throw this exception if there is not enough memory and \n                        if it does throw then the call to set_size() has no effect    \n            !*/\n\n            size_t max_size(\n            ) const;\n            /*!\n                ensures\n                    - returns the maximum size of *this\n            !*/\n\n            void set_max_size(\n                size_t max\n            );\n            /*!\n                ensures\n                    - #max_size() == max\n                    - #size() == 0\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        may throw this exception if there is not enough \n                        memory and if it does throw then max_size() == 0    \n            !*/\n\n            void swap (\n                array<T>& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n            \n            void sort (\n            );\n            /*!\n                requires\n                    - T must be a type with that is comparable via operator<\n                ensures\n                    - for all elements in #*this the ith element is <= the i+1 element\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        data may be lost if sort() throws\n            !*/\n\n            void resize (\n                size_t new_size\n            );\n            /*!\n                ensures\n                    - #size() == new_size\n                    - #max_size() == max(new_size,max_size())\n                    - for all i < size() && i < new_size:\n                        - #(*this)[i] == (*this)[i]\n                          (i.e. All the original elements of *this which were at index\n                          values less than new_size are unmodified.)\n                    - for all valid i >= size():\n                        - #(*this)[i] has an undefined value\n                          (i.e. any new elements of the array have an undefined value)\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                       If an exception is thrown then it has no effect on *this.\n            !*/\n\n            \n            const T& back (\n            ) const;\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - returns a const reference to (*this)[size()-1]\n            !*/\n\n            T& back (\n            );\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - returns a non-const reference to (*this)[size()-1]\n            !*/\n\n            void pop_back (\n                T& item\n            );\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - #size() == size() - 1\n                    - swaps (*this)[size()-1] into item\n                    - All elements with an index less than size()-1 are \n                      unmodified by this operation.\n            !*/\n\n            void pop_back (\n            );\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - #size() == size() - 1\n                    - All elements with an index less than size()-1 are \n                      unmodified by this operation.\n            !*/\n\n            void push_back (\n                T& item\n            );\n            /*!\n                ensures\n                    - #size() == size()+1\n                    - swaps item into (*this)[#size()-1] \n                    - #back() == item\n                    - #item has some undefined value (whatever happens to \n                      get swapped out of the array)\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                       If an exception is thrown then it has no effect on *this.\n            !*/\n\n            void push_back (T&& item) { push_back(item); }\n            /*!\n                enable push_back from rvalues \n            !*/\n\n            typedef T* iterator;\n            typedef const T* const_iterator;\n\n            iterator begin(\n            );\n            /*!\n                ensures\n                    - returns an iterator that points to the first element in this array or\n                      end() if the array is empty.\n            !*/\n\n            const_iterator begin(\n            ) const;\n            /*!\n                ensures\n                    - returns a const iterator that points to the first element in this\n                      array or end() if the array is empty.\n            !*/\n\n            iterator end(\n            );\n            /*!\n                ensures\n                    - returns an iterator that points to one past the end of the array.\n            !*/\n\n            const_iterator end(\n            ) const;\n            /*!\n                ensures\n                    - returns a const iterator that points to one past the end of the\n                      array.\n            !*/\n\n        private:\n\n            // restricted functions\n            array(array<T>&);        // copy constructor\n            array<T>& operator=(array<T>&);    // assignment operator        \n\n    };\n\n    template <\n        typename T\n        >\n    inline void swap (\n        array<T>& a, \n        array<T>& b \n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T\n        >\n    void serialize (\n        const array<T>& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        typename T \n        >\n    void deserialize (\n        array<T>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n}\n\n#endif // DLIB_ARRAY_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/array/array_tools.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY_tOOLS_H_\n#define DLIB_ARRAY_tOOLS_H_\n\n#include \"../assert.h\"\n#include \"array_tools_abstract.h\"\n\nnamespace dlib\n{\n    template <typename T>\n    void split_array (\n        T& a,\n        T& b,\n        double frac\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 <= frac && frac <= 1,\n            \"\\t void split_array()\"\n            << \"\\n\\t frac must be between 0 and 1.\"\n            << \"\\n\\t frac: \" << frac\n            );\n\n        const unsigned long asize = static_cast<unsigned long>(a.size()*frac);\n        const unsigned long bsize = a.size()-asize;\n\n        b.resize(bsize);\n        for (unsigned long i = 0; i < b.size(); ++i)\n        {\n            swap(b[i], a[i+asize]);\n        }\n        a.resize(asize);\n    }\n}\n\n#endif // DLIB_ARRAY_tOOLS_H_\n\n"
  },
  {
    "path": "dlib/array/array_tools_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ARRAY_tOOLS_ABSTRACT_H_\n#ifdef DLIB_ARRAY_tOOLS_ABSTRACT_H_\n\n#include \"array_kernel_abstract.h\"\n\nnamespace dlib\n{\n    template <typename T>\n    void split_array (\n        T& a,\n        T& b,\n        double frac\n    );\n    /*!\n        requires\n            - 0 <= frac <= 1\n            - T must be an array type such as dlib::array or std::vector\n        ensures\n            - This function takes the elements of a and splits them into two groups.  The\n              first group remains in a and the second group is put into b.  The ordering of\n              elements in a is preserved.  In particular, concatenating #a with #b will\n              reproduce the original contents of a.\n            - The elements in a are moved around using global swap().  So they must be\n              swappable, but do not need to be copyable.\n            - #a.size() == floor(a.size()*frac)\n            - #b.size() == a.size()-#a.size()\n    !*/\n}\n\n#endif // DLIB_ARRAY_tOOLS_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/array.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAy_\n#define DLIB_ARRAy_\n\n#include \"array/array_kernel.h\"\n#include \"array/array_tools.h\"\n\n#endif // DLIB_ARRAy_\n\n"
  },
  {
    "path": "dlib/array2d/array2d_generic_image.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY2D_GENERIC_iMAGE_Hh_\n#define DLIB_ARRAY2D_GENERIC_iMAGE_Hh_\n\n#include \"array2d_kernel.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    template <typename T, typename mm>\n    struct image_traits<array2d<T,mm> >\n    {\n        typedef T pixel_type;\n    };\n    template <typename T, typename mm>\n    struct image_traits<const array2d<T,mm> >\n    {\n        typedef T pixel_type;\n    };\n\n    template <typename T, typename mm>\n    inline long num_rows( const array2d<T,mm>& img) { return img.nr(); }\n    template <typename T, typename mm>\n    inline long num_columns( const array2d<T,mm>& img) { return img.nc(); }\n\n    template <typename T, typename mm>\n    inline void set_image_size(\n        array2d<T,mm>& img,\n        long rows,\n        long cols \n    ) { img.set_size(rows,cols); }\n\n    template <typename T, typename mm>\n    inline void* image_data(\n        array2d<T,mm>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T, typename mm>\n    inline const void* image_data(\n        const array2d<T,mm>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T, typename mm>\n    inline size_t width_step(\n        const array2d<T,mm>& img\n    ) \n    { \n        return img.width_step(); \n    }\n\n}\n\n#endif // DLIB_ARRAY2D_GENERIC_iMAGE_Hh_\n\n"
  },
  {
    "path": "dlib/array2d/array2d_kernel.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY2D_KERNEl_1_\n#define DLIB_ARRAY2D_KERNEl_1_\n\n#include \"array2d_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../serialize.h\"\n#include \"../geometry/rectangle.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class array2d : public enumerable<T>\n    {\n\n        /*!\n            INITIAL VALUE\n                - nc_ == 0 \n                - nr_ == 0 \n                - data == 0 \n                - at_start_ == true\n                - cur == 0\n                - last == 0\n\n            CONVENTION\n                - nc_ == nc() \n                - nr_ == nc() \n                - if (data != 0) then\n                    - last == a pointer to the last element in the data array\n                    - data == pointer to an array of nc_*nr_ T objects \n                - else\n                    - nc_ == 0\n                    - nr_ == 0\n                    - data == 0\n                    - last == 0\n\n\n                - nr_ * nc_ == size()\n                - if (cur == 0) then\n                    - current_element_valid() == false\n                - else \n                    - current_element_valid() == true\n                    - *cur == element()\n\n                - at_start_ == at_start()      \n        !*/\n\n\n        class row_helper;\n    public:\n\n        // These typedefs are here for backwards compatibility with older versions of dlib.\n        typedef array2d kernel_1a;\n        typedef array2d kernel_1a_c;\n         \n        typedef T type;\n        typedef mem_manager mem_manager_type;\n        typedef T*          iterator;       \n        typedef const T*    const_iterator; \n\n\n        // -----------------------------------\n\n        class row \n        {\n            /*!\n                CONVENTION\n                    - nc_ == nc()\n                    - for all x < nc_:\n                        - (*this)[x] == data[x]\n            !*/\n\n            friend class array2d<T,mem_manager>;\n            friend class row_helper;\n\n        public:\n            long nc (\n            ) const { return nc_; }\n\n            const T& operator[] (\n                long column\n            ) const \n            { \n                // make sure requires clause is not broken\n                DLIB_ASSERT(column < nc() && column >= 0,\n                    \"\\tconst T& array2d::operator[](long column) const\"\n                    << \"\\n\\tThe column index given must be less than the number of columns.\"\n                    << \"\\n\\tthis:    \" << this\n                    << \"\\n\\tcolumn:  \" << column \n                    << \"\\n\\tnc(): \" << nc()\n                );\n\n                return data[column]; \n            }\n\n            T& operator[] (\n                long column\n            ) \n            { \n                // make sure requires clause is not broken\n                DLIB_ASSERT(column < nc() && column >= 0,\n                    \"\\tT& array2d::operator[](long column)\"\n                    << \"\\n\\tThe column index given must be less than the number of columns.\"\n                    << \"\\n\\tthis:    \" << this\n                    << \"\\n\\tcolumn:  \" << column \n                    << \"\\n\\tnc(): \" << nc()\n                );\n\n                return data[column]; \n            }\n\n        private:\n\n            row(T* data_, long cols) : data(data_), nc_(cols) {}\n            row(row&& r) = default;\n            row& operator=(row&& r) = default;\n\n            T* data = nullptr;\n            long nc_ = 0;\n\n\n            // restricted functions\n            row(const row&) = delete;\n            row& operator=(const row&) = delete;\n        };\n\n        // -----------------------------------\n\n        array2d (\n        ) : \n            data(0),\n            nc_(0),\n            nr_(0),\n            cur(0),\n            last(0),\n            at_start_(true)\n        {\n        }\n\n        array2d(\n            long rows,\n            long cols\n        ) : \n            data(0),\n            nc_(0),\n            nr_(0),\n            cur(0),\n            last(0),\n            at_start_(true)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT((cols >= 0 && rows >= 0),\n                        \"\\t array2d::array2d(long rows, long cols)\"\n                        << \"\\n\\t The array2d can't have negative rows or columns.\"\n                        << \"\\n\\t this: \" << this\n                        << \"\\n\\t cols: \" << cols \n                        << \"\\n\\t rows: \" << rows \n            );\n\n            set_size(rows,cols);\n        }\n\n        array2d(const array2d&) = delete;        // copy constructor\n        array2d& operator=(const array2d&) = delete;    // assignment operator\n\n#ifdef DLIB_HAS_RVALUE_REFERENCES\n        array2d(array2d&& item) : array2d()\n        {\n            swap(item);\n        }\n\n        array2d& operator= (\n            array2d&& rhs\n        )\n        {\n            swap(rhs);\n            return *this;\n        }\n#endif\n\n        virtual ~array2d (\n        ) { clear(); }\n\n        long nc (\n        ) const { return nc_; }\n\n        long nr (\n        ) const { return nr_; }\n\n        row operator[] (\n            long row_\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(row_ < nr() && row_ >= 0,\n                \"\\trow array2d::operator[](long row_)\"\n                << \"\\n\\tThe row index given must be less than the number of rows.\"\n                << \"\\n\\tthis:     \" << this\n                << \"\\n\\trow_:      \" << row_ \n                << \"\\n\\tnr(): \" << nr()\n                );\n\n            return row(data+row_*nc_, nc_);\n        }\n\n        const row operator[] (\n            long row_\n        ) const \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(row_ < nr() && row_ >= 0,\n                \"\\tconst row array2d::operator[](long row_) const\"\n                << \"\\n\\tThe row index given must be less than the number of rows.\"\n                << \"\\n\\tthis:     \" << this\n                << \"\\n\\trow_:      \" << row_ \n                << \"\\n\\tnr(): \" << nr()\n            );\n\n            return row(data+row_*nc_, nc_);\n        }\n\n        void swap (\n            array2d& item\n        )\n        {\n            exchange(data,item.data);\n            exchange(nr_,item.nr_);\n            exchange(nc_,item.nc_);\n            exchange(at_start_,item.at_start_);\n            exchange(cur,item.cur);\n            exchange(last,item.last);\n            pool.swap(item.pool);\n        }\n\n        void clear (\n        )\n        {\n            if (data != 0)\n            {\n                pool.deallocate_array(data);\n                nc_ = 0;\n                nr_ = 0;\n                data = 0;\n                at_start_ = true;\n                cur = 0;\n                last = 0;\n            }\n        }\n\n        void set_size (\n            long rows,\n            long cols\n        );\n\n        bool at_start (\n        ) const { return at_start_; }\n\n        void reset (\n        ) const { at_start_ = true; cur = 0; }\n\n        bool current_element_valid (\n        ) const { return (cur != 0); }\n\n        const T& element (\n        ) const \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                \"\\tconst T& array2d::element()()\"\n                << \"\\n\\tYou can only call element() when you are at a valid one.\"\n                << \"\\n\\tthis:    \" << this\n            );\n\n            return *cur; \n        }\n\n        T& element (\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                         \"\\tT& array2d::element()()\"\n                         << \"\\n\\tYou can only call element() when you are at a valid one.\"\n                         << \"\\n\\tthis:    \" << this\n            );\n\n            return *cur; \n        }\n\n        bool move_next (\n        ) const\n        {\n            if (cur != 0)\n            {\n                if (cur != last)\n                {\n                    ++cur;\n                    return true;\n                }\n                cur = 0;\n                return false;\n            }\n            else if (at_start_)\n            {\n                cur = data;\n                at_start_ = false;\n                return (data != 0);\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        size_t size (\n        ) const { return static_cast<size_t>(nc_) * static_cast<size_t>(nr_); }\n\n        size_t width_step (\n        ) const\n        {\n            return nc_*sizeof(T);\n        }\n\n        iterator begin() \n        {\n            return data;\n        }\n\n        iterator end()\n        {\n            return data+size();\n        }\n\n        const_iterator begin()  const\n        {\n            return data;\n        }\n\n        const_iterator end() const\n        {\n            return data+size();\n        }\n\n\n    private:\n\n\n        T* data;\n        long nc_;\n        long nr_;\n\n        typename mem_manager::template rebind<T>::other pool;\n        mutable T* cur;\n        T* last;\n        mutable bool at_start_;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        array2d<T,mem_manager>& a, \n        array2d<T,mem_manager>& b \n    ) { a.swap(b); }   \n\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<T,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            item.reset();\n            while (item.move_next())\n                serialize(item.element(),out);\n            item.reset();\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<T,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n            item.set_size(nr,nc);\n\n            while (item.move_next())\n                deserialize(item.element(),in); \n            item.reset();\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void array2d<T,mem_manager>::\n    set_size (\n        long rows,\n        long cols\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT((cols >= 0 && rows >= 0) ,\n               \"\\tvoid array2d::set_size(long rows, long cols)\"\n               << \"\\n\\tThe array2d can't have negative rows or columns.\"\n               << \"\\n\\tthis: \" << this\n               << \"\\n\\tcols: \" << cols \n               << \"\\n\\trows: \" << rows \n        );\n\n        // set the enumerator back at the start\n        at_start_ = true;\n        cur = 0;\n\n        // don't do anything if we are already the right size.\n        if (nc_ == cols && nr_ == rows)\n        {\n            return;\n        }\n\n        nc_ = cols;\n        nr_ = rows;\n\n        // free any existing memory\n        if (data != 0)\n        {\n            pool.deallocate_array(data);\n            data = 0;\n        }\n\n        // now setup this object to have the new size\n        try\n        {\n            if (nr_ > 0)\n            {\n                data = pool.allocate_array(nr_*nc_);\n                last = data + nr_*nc_ - 1;\n            }\n        }\n        catch (...)\n        {\n            if (data)\n                pool.deallocate_array(data);\n\n            data = 0;\n            nc_ = 0;\n            nr_ = 0;\n            last = 0;\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename MM>\n    struct is_array2d <array2d<T,MM> >  \n    {\n        const static bool value = true;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ARRAY2D_KERNEl_1_ \n\n"
  },
  {
    "path": "dlib/array2d/array2d_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ARRAY2D_KERNEl_ABSTRACT_\n#ifdef DLIB_ARRAY2D_KERNEl_ABSTRACT_\n\n#include \"../interfaces/enumerable.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include \"../geometry/rectangle_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager \n        >\n    class array2d : public enumerable<T>\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must have a default constructor.\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                No member functions in this object will invalidate pointers\n                or references to internal data except for the set_size()\n                and clear() member functions.\n\n            INITIAL VALUE\n                nr() == 0\n                nc() == 0\n                \n            ENUMERATION ORDER\n                The enumerator will iterate over the elements of the array starting\n                with row 0 and then proceeding to row 1 and so on.  Each row will be\n                fully enumerated before proceeding on to the next row and the elements\n                in a row will be enumerated beginning with the 0th column, then the 1st \n                column and so on.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a 2-Dimensional array of objects of \n                type T. \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n\n\n                Finally, note that this object stores its data contiguously and in \n                row major order.  Moreover, there is no padding at the end of each row.\n                This means that its width_step() value is always equal to sizeof(type)*nc().  \n        !*/\n\n\n    public:\n\n        // ----------------------------------------\n\n        typedef T type;\n        typedef mem_manager mem_manager_type;\n        typedef T*          iterator;       \n        typedef const T*    const_iterator; \n         \n        // ----------------------------------------\n\n        class row \n        {\n            /*!\n                POINTERS AND REFERENCES TO INTERNAL DATA\n                    No member functions in this object will invalidate pointers\n                    or references to internal data.\n\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a row of Ts in an array2d object.\n            !*/\n        public:\n            long nc (\n            ) const;\n            /*!\n                ensures\n                    - returns the number of columns in this row\n            !*/\n\n            const T& operator[] (\n                long column\n            ) const;\n            /*!\n                requires\n                    - 0 <= column < nc()\n                ensures\n                    - returns a const reference to the T in the given column \n            !*/\n\n            T& operator[] (\n                long column\n            );\n            /*!\n                requires\n                    - 0 <= column < nc()\n                ensures\n                    - returns a non-const reference to the T in the given column \n            !*/\n\n        private:\n            // restricted functions\n            row();\n            row& operator=(row&);\n        };\n\n        // ----------------------------------------\n\n        array2d (\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc \n        !*/\n\n        array2d(const array2d&) = delete;        // copy constructor\n        array2d& operator=(const array2d&) = delete;    // assignment operator\n\n        array2d(\n            array2d&& item\n        );\n        /*!\n            ensures\n                - Moves the state of item into *this.\n                - #item is in a valid but unspecified state.\n        !*/\n\n        array2d (\n            long rows,\n            long cols \n        );\n        /*!\n            requires\n                - rows >= 0 && cols >= 0\n            ensures\n                - #nc() == cols\n                - #nr() == rows\n                - #at_start() == true\n                - all elements in this array have initial values for their type\n            throws\n                - std::bad_alloc \n        !*/\n\n        virtual ~array2d (\n        ); \n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n        \n        void clear (\n        );\n        /*!\n            ensures\n                - #*this has an initial value for its type\n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of elements there are in a row.  i.e. returns\n                  the number of columns in *this\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in *this\n        !*/\n\n        void set_size (\n            long rows,\n            long cols\n        );\n        /*!\n            requires\n                - rows >= 0 && cols >= 0\n            ensures\n                - #nc() == cols\n                - #nr() == rows\n                - #at_start() == true\n                - if (the call to set_size() doesn't change the dimensions of this array) then\n                    - all elements in this array retain their values from before this function was called\n                - else\n                    - all elements in this array have initial values for their type\n            throws\n                - std::bad_alloc \n                    If this exception is thrown then #*this will have an initial\n                    value for its type.\n        !*/\n\n        row operator[] (\n            long row_index\n        );\n        /*!\n            requires\n                - 0 <= row_index < nr()\n            ensures\n                - returns a non-const row of nc() elements that represents the \n                  given row_index'th row in *this.\n        !*/\n\n        const row operator[] (\n            long row_index\n        ) const;\n        /*!\n            requires\n                - 0 <= row_index < nr()\n            ensures\n                - returns a const row of nc() elements that represents the \n                  given row_index'th row in *this.\n        !*/\n\n        void swap (\n            array2d& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n        array2d& operator= (\n            array2d&& rhs\n        );\n        /*!\n            ensures\n                - Moves the state of item into *this.\n                - #item is in a valid but unspecified state.\n                - returns #*this\n        !*/\n\n        size_t width_step (\n        ) const;\n        /*!\n            ensures\n                - returns the size of one row of the image, in bytes.  \n                  More precisely, return a number N such that:\n                  (char*)&item[0][0] + N == (char*)&item[1][0].\n                - for dlib::array2d objects, the returned value\n                  is always equal to sizeof(type)*nc().  However,\n                  other objects which implement dlib::array2d style\n                  interfaces might have padding at the ends of their\n                  rows and therefore might return larger numbers.\n                  An example of such an object is the dlib::cv_image.\n        !*/\n\n        iterator begin(\n        );\n        /*!\n            ensures\n                - returns a random access iterator pointing to the first element in this\n                  object.\n                - The iterator will iterate over the elements of the object in row major\n                  order.\n        !*/\n\n        iterator end(\n        );\n        /*!\n            ensures\n                - returns a random access iterator pointing to one past the end of the last\n                  element in this object.\n        !*/\n\n        const_iterator begin(\n        ) const;\n        /*!\n            ensures\n                - returns a random access iterator pointing to the first element in this\n                  object.\n                - The iterator will iterate over the elements of the object in row major\n                  order.\n        !*/\n\n        const_iterator end(\n        ) const;\n        /*!\n            ensures\n                - returns a random access iterator pointing to one past the end of the last\n                  element in this object.\n        !*/\n\n    };\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        array2d<T,mem_manager>& a, \n        array2d<T,mem_manager>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<T,mem_manager>& item, \n        std::ostream& out \n    );   \n    /*!\n        Provides serialization support.  Note that the serialization formats used by the\n        dlib::matrix and dlib::array2d objects are compatible.  That means you can load the\n        serialized data from one into another and it will work properly.\n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<T,mem_manager>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n}\n\n#endif // DLIB_ARRAY2D_KERNEl_ABSTRACT_ \n\n"
  },
  {
    "path": "dlib/array2d/serialize_pixel_overloads.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_\n#define DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_\n\n#include \"array2d_kernel.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*\n        This file contains overloads of the serialize functions for array2d object\n        for the case where they contain simple 8bit POD pixel types.  In these\n        cases we can perform a much faster serialization by writing data in chunks\n        instead of one pixel at a time (this avoids a lot of function call overhead\n        inside the iostreams).\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<rgb_pixel,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);\n            \n            if (item.size() != 0)\n                out.write((char*)&item[0][0], sizeof(rgb_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<rgb_pixel,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            COMPILE_TIME_ASSERT(sizeof(rgb_pixel) == 3);\n\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n            item.set_size(nr,nc);\n\n            if (item.size() != 0)\n                in.read((char*)&item[0][0], sizeof(rgb_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<bgr_pixel,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);\n\n            if (item.size() != 0)\n                out.write((char*)&item[0][0], sizeof(bgr_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<bgr_pixel,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            COMPILE_TIME_ASSERT(sizeof(bgr_pixel) == 3);\n\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n\n            item.set_size(nr,nc);\n\n            if (item.size() != 0)\n                in.read((char*)&item[0][0], sizeof(bgr_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<hsi_pixel,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);\n\n            if (item.size() != 0)\n                out.write((char*)&item[0][0], sizeof(hsi_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<hsi_pixel,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            COMPILE_TIME_ASSERT(sizeof(hsi_pixel) == 3);\n\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n\n            item.set_size(nr,nc);\n\n            if (item.size() != 0)\n                in.read((char*)&item[0][0], sizeof(hsi_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<rgb_alpha_pixel,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);\n\n            if (item.size() != 0)\n                out.write((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<rgb_alpha_pixel,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            COMPILE_TIME_ASSERT(sizeof(rgb_alpha_pixel) == 4);\n\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n\n            item.set_size(nr,nc);\n\n            if (item.size() != 0)\n                in.read((char*)&item[0][0], sizeof(rgb_alpha_pixel)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mem_manager\n        >\n    void serialize (\n        const array2d<unsigned char,mem_manager>& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n\n            if (item.size() != 0)\n                out.write((char*)&item[0][0], sizeof(unsigned char)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type array2d\"); \n        }\n    }\n\n    template <\n        typename mem_manager\n        >\n    void deserialize (\n        array2d<unsigned char,mem_manager>& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            long nr, nc;\n            deserialize(nr,in);\n            deserialize(nc,in);\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n            else\n            {\n                std::swap(nr,nc);\n            }\n\n\n            item.set_size(nr,nc);\n\n            if (item.size() != 0)\n                in.read((char*)&item[0][0], sizeof(unsigned char)*item.size());\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type array2d\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ARRAY2D_SERIALIZE_PIXEL_OvERLOADS_Hh_\n\n"
  },
  {
    "path": "dlib/array2d.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARRAY2d_ \n#define DLIB_ARRAY2d_\n\n\n#include \"array2d/array2d_kernel.h\"\n#include \"array2d/serialize_pixel_overloads.h\"\n#include \"array2d/array2d_generic_image.h\"\n\n#endif // DLIB_ARRAY2d_\n\n"
  },
  {
    "path": "dlib/assert.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ASSERt_\n#define DLIB_ASSERt_\n\n#include \"config.h\"\n#include <sstream>\n#include <iosfwd>\n#include \"error.h\"\n\n// -----------------------------\n\n// Use some stuff from boost here\n//  (C) Copyright John Maddock 2001 - 2003.\n//  (C) Copyright Darin Adler 2001.\n//  (C) Copyright Peter Dimov 2001.\n//  (C) Copyright Bill Kempf 2002.\n//  (C) Copyright Jens Maurer 2002.\n//  (C) Copyright David Abrahams 2002 - 2003.\n//  (C) Copyright Gennaro Prota 2003.\n//  (C) Copyright Eric Friedman 2003.\n// License: Boost Software License   See LICENSE.txt for the full license.\n// \n#ifndef DLIB_BOOST_JOIN\n#define DLIB_BOOST_JOIN( X, Y ) DLIB_BOOST_DO_JOIN( X, Y )\n#define DLIB_BOOST_DO_JOIN( X, Y ) DLIB_BOOST_DO_JOIN2(X,Y)\n#define DLIB_BOOST_DO_JOIN2( X, Y ) X##Y\n#endif\n\n// figure out if the compiler has rvalue references. \n#if defined(__clang__) \n#   if __has_feature(cxx_rvalue_references)\n#       define DLIB_HAS_RVALUE_REFERENCES\n#   endif\n#   if __has_feature(cxx_generalized_initializers)\n#       define DLIB_HAS_INITIALIZER_LISTS\n#   endif\n#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) \n#   define DLIB_HAS_RVALUE_REFERENCES\n#   define DLIB_HAS_INITIALIZER_LISTS\n#elif defined(_MSC_VER) && _MSC_VER >= 1800\n#   define DLIB_HAS_INITIALIZER_LISTS\n#   define DLIB_HAS_RVALUE_REFERENCES\n#elif defined(_MSC_VER) && _MSC_VER >= 1600\n#   define DLIB_HAS_RVALUE_REFERENCES\n#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X)\n#   define DLIB_HAS_RVALUE_REFERENCES\n#   define DLIB_HAS_INITIALIZER_LISTS\n#endif\n\n#if defined(__APPLE__) && defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)\n // Apple has not updated libstdc++ in some time and anything under 4.02 does not have <initializer_list> for sure.\n#   undef DLIB_HAS_INITIALIZER_LISTS\n#endif\n\n// figure out if the compiler has static_assert. \n#if defined(__clang__) \n#   if __has_feature(cxx_static_assert)\n#       define DLIB_HAS_STATIC_ASSERT\n#   endif\n#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) \n#   define DLIB_HAS_STATIC_ASSERT\n#elif defined(_MSC_VER) && _MSC_VER >= 1600\n#   define DLIB_HAS_STATIC_ASSERT\n#elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X)\n#   define DLIB_HAS_STATIC_ASSERT\n#endif\n\n\n// -----------------------------\n\nnamespace dlib\n{\n    template <bool value> struct compile_time_assert;\n    template <> struct compile_time_assert<true> { enum {value=1};  };\n\n    template <typename T, typename U> struct assert_are_same_type;\n    template <typename T> struct assert_are_same_type<T,T> {enum{value=1};};\n    template <typename T, typename U> struct assert_are_not_same_type {enum{value=1}; };\n    template <typename T> struct assert_are_not_same_type<T,T> {};\n\n    template <typename T, typename U> struct assert_types_match {enum{value=0};};\n    template <typename T> struct assert_types_match<T,T> {enum{value=1};};\n}\n\n\n// gcc 4.8 will warn about unused typedefs.  But we use typedefs in some of the compile\n// time assert macros so we need to make it not complain about them \"not being used\".\n#ifdef __GNUC__\n#define DLIB_NO_WARN_UNUSED __attribute__ ((unused))\n#else\n#define DLIB_NO_WARN_UNUSED \n#endif\n\n// Use the newer static_assert if it's available since it produces much more readable error\n// messages.\n#ifdef DLIB_HAS_STATIC_ASSERT\n    #define COMPILE_TIME_ASSERT(expression) static_assert(expression, \"Failed assertion\")\n    #define ASSERT_ARE_SAME_TYPE(type1, type2) static_assert(::dlib::assert_types_match<type1,type2>::value, \"These types should be the same but aren't.\")\n    #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match<type1,type2>::value, \"These types should NOT be the same.\")\n#else\n    #define COMPILE_TIME_ASSERT(expression) \\\n        DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] \n\n    #define ASSERT_ARE_SAME_TYPE(type1, type2) \\\n        DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type<type1,type2>::value] \n\n    #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \\\n        DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type<type1,type2>::value] \n#endif\n\n// -----------------------------\n\n#if defined DLIB_DISABLE_ASSERTS\n    // if DLIB_DISABLE_ASSERTS is on then never enable DLIB_ASSERT no matter what.\n    #undef ENABLE_ASSERTS\n#endif\n\n#if !defined(DLIB_DISABLE_ASSERTS) && ( defined DEBUG || defined _DEBUG)\n    // make sure ENABLE_ASSERTS is defined if we are indeed using them.\n    #ifndef ENABLE_ASSERTS\n        #define ENABLE_ASSERTS\n    #endif\n#endif\n\n// -----------------------------\n\n#ifdef __GNUC__\n// There is a bug in version 4.4.5 of GCC on Ubuntu which causes GCC to segfault\n// when __PRETTY_FUNCTION__ is used within certain templated functions.  So just\n// don't use it with this version of GCC.\n#  if !(__GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 5)\n#    define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__\n#  else\n#    define DLIB_FUNCTION_NAME \"unknown function\" \n#  endif\n#elif defined(_MSC_VER)\n#define DLIB_FUNCTION_NAME __FUNCSIG__\n#else\n#define DLIB_FUNCTION_NAME \"unknown function\" \n#endif\n\n#define DLIBM_CASSERT(_exp,_message)                                              \\\n    {if ( !(_exp) )                                                         \\\n    {                                                                       \\\n        dlib_assert_breakpoint();                                           \\\n        std::ostringstream dlib_o_out;                                       \\\n        dlib_o_out << \"\\n\\nError detected at line \" << __LINE__ << \".\\n\";    \\\n        dlib_o_out << \"Error detected in file \" << __FILE__ << \".\\n\";      \\\n        dlib_o_out << \"Error detected in function \" << DLIB_FUNCTION_NAME << \".\\n\\n\";      \\\n        dlib_o_out << \"Failing expression was \" << #_exp << \".\\n\";           \\\n        dlib_o_out << std::boolalpha << _message << \"\\n\";                    \\\n        throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str());      \\\n    }}                                                                      \n\n// This macro is not needed if you have a real C++ compiler.  It's here to work around bugs in Visual Studio's preprocessor.  \n#define DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(x) x\n// Make it so the 2nd argument of DLIB_CASSERT is optional.  That is, you can call it like\n// DLIB_CASSERT(exp) or DLIB_CASSERT(exp,message).\n#define DLIBM_CASSERT_1_ARGS(exp)              DLIBM_CASSERT(exp,\"\")\n#define DLIBM_CASSERT_2_ARGS(exp,message)      DLIBM_CASSERT(exp,message)\n#define DLIBM_GET_3TH_ARG(arg1, arg2, arg3, ...) arg3\n#define DLIBM_CASSERT_CHOOSER(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_GET_3TH_ARG(__VA_ARGS__,  DLIBM_CASSERT_2_ARGS, DLIBM_CASSERT_1_ARGS, DLIB_CASSERT_NEVER_USED))\n#define DLIB_CASSERT(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_CASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__))\n\n\n#ifdef ENABLE_ASSERTS \n    #define DLIB_ASSERT(...) DLIB_CASSERT(__VA_ARGS__)\n    #define DLIB_IF_ASSERT(exp) exp\n#else\n    #define DLIB_ASSERT(...) {}\n    #define DLIB_IF_ASSERT(exp) \n#endif\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A DLIB_ASSERT_HAS_STANDARD_LAYOUT \n    \n        This macro is meant to cause a compiler error if a type doesn't have a simple\n        memory layout (like a C struct). In particular, types with simple layouts are\n        ones which can be copied via memcpy().\n        \n        \n        This was called a POD type in C++03 and in C++0x we are looking to check if \n        it is a \"standard layout type\".  Once we can use C++0x we can change this macro \n        to something that uses the std::is_standard_layout type_traits class.  \n        See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs\n    !*/\n    // Use the fact that in C++03 you can't put non-PODs into a union.\n#define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type)   \\\n    union  DLIB_BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; };  \\\n    DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(DLIB_BOOST_JOIN(DAHSL_,__LINE__))]; \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n// breakpoints\nextern \"C\"\n{\n    inline void dlib_assert_breakpoint(\n    ) {}\n    /*!\n        ensures\n            - this function does nothing \n              It exists just so you can put breakpoints on it in a debugging tool.\n              It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to\n              throw an exception.\n    !*/\n}\n\n// -----------------------------\n\n#include \"stack_trace.h\"\n\n#endif // DLIB_ASSERt_\n\n"
  },
  {
    "path": "dlib/base64/base64_kernel_1.cpp",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BASE64_KERNEL_1_CPp_\n#define DLIB_BASE64_KERNEL_1_CPp_\n\n#include \"base64_kernel_1.h\"\n#include <iostream>\n#include <sstream>\n#include <climits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    base64::line_ending_type base64::\n    line_ending (\n    ) const\n    {\n        return eol_style;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base64::\n    set_line_ending (\n        line_ending_type eol_style_\n    )\n    {\n        eol_style = eol_style_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base64::\n    base64 (\n    ) : \n        encode_table(0),\n        decode_table(0),\n        bad_value(100),\n        eol_style(LF)\n    {\n        try\n        {\n            encode_table = new char[64];\n            decode_table = new unsigned char[UCHAR_MAX];\n        }\n        catch (...)\n        {\n            if (encode_table) delete [] encode_table;\n            if (decode_table) delete [] decode_table;\n            throw;\n        }\n\n        // now set up the tables with the right stuff\n        encode_table[0] = 'A';\n        encode_table[17] = 'R';\n        encode_table[34] = 'i';\n        encode_table[51] = 'z';\n\n        encode_table[1] = 'B';\n        encode_table[18] = 'S';\n        encode_table[35] = 'j';\n        encode_table[52] = '0';\n\n        encode_table[2] = 'C';\n        encode_table[19] = 'T';\n        encode_table[36] = 'k';\n        encode_table[53] = '1';\n\n        encode_table[3] = 'D';\n        encode_table[20] = 'U';\n        encode_table[37] = 'l';\n        encode_table[54] = '2';\n\n        encode_table[4] = 'E';\n        encode_table[21] = 'V';\n        encode_table[38] = 'm';\n        encode_table[55] = '3';\n\n        encode_table[5] = 'F';\n        encode_table[22] = 'W';\n        encode_table[39] = 'n';\n        encode_table[56] = '4';\n\n        encode_table[6] = 'G';\n        encode_table[23] = 'X';\n        encode_table[40] = 'o';\n        encode_table[57] = '5';\n\n        encode_table[7] = 'H';\n        encode_table[24] = 'Y';\n        encode_table[41] = 'p';\n        encode_table[58] = '6';\n\n        encode_table[8] = 'I';\n        encode_table[25] = 'Z';\n        encode_table[42] = 'q';\n        encode_table[59] = '7';\n\n        encode_table[9] = 'J';\n        encode_table[26] = 'a';\n        encode_table[43] = 'r';\n        encode_table[60] = '8';\n\n        encode_table[10] = 'K';\n        encode_table[27] = 'b';\n        encode_table[44] = 's';\n        encode_table[61] = '9';\n\n        encode_table[11] = 'L';\n        encode_table[28] = 'c';\n        encode_table[45] = 't';\n        encode_table[62] = '+';\n\n        encode_table[12] = 'M';\n        encode_table[29] = 'd';\n        encode_table[46] = 'u';\n        encode_table[63] = '/';\n\n        encode_table[13] = 'N';\n        encode_table[30] = 'e';\n        encode_table[47] = 'v';\n\n        encode_table[14] = 'O';\n        encode_table[31] = 'f';\n        encode_table[48] = 'w';\n\n        encode_table[15] = 'P';\n        encode_table[32] = 'g';\n        encode_table[49] = 'x';\n\n        encode_table[16] = 'Q';\n        encode_table[33] = 'h';\n        encode_table[50] = 'y';\n\n\n\n        // we can now fill out the decode_table by using the encode_table\n        for (int i = 0; i < UCHAR_MAX; ++i)\n        {\n            decode_table[i] = bad_value;\n        }\n        for (unsigned char i = 0; i < 64; ++i)\n        {\n            decode_table[(unsigned char)encode_table[i]] = i;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base64::\n    ~base64 (\n    )\n    {\n        delete [] encode_table;\n        delete [] decode_table;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base64::\n    encode (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n        using namespace std;\n        streambuf& in = *in_.rdbuf();\n        streambuf& out = *out_.rdbuf();\n\n        unsigned char inbuf[3];\n        unsigned char outbuf[4];\n        streamsize status = in.sgetn(reinterpret_cast<char*>(&inbuf),3);\n\n        unsigned char c1, c2, c3, c4, c5, c6;\n\n        int counter = 19;\n\n        // while we haven't hit the end of the input stream\n        while (status != 0)\n        {\n            if (counter == 0)\n            {\n                counter = 19;\n                // write a newline\n                char ch;\n                switch (eol_style)\n                {\n                    case CR:\n                        ch = '\\r';\n                        if (out.sputn(&ch,1)!=1)\n                            throw std::ios_base::failure(\"error occurred in the base64 object\");\n                        break;\n                    case LF:\n                        ch = '\\n';\n                        if (out.sputn(&ch,1)!=1)\n                            throw std::ios_base::failure(\"error occurred in the base64 object\");\n                        break;\n                    case CRLF:\n                        ch = '\\r';\n                        if (out.sputn(&ch,1)!=1)\n                            throw std::ios_base::failure(\"error occurred in the base64 object\");\n                        ch = '\\n';\n                        if (out.sputn(&ch,1)!=1)\n                            throw std::ios_base::failure(\"error occurred in the base64 object\");\n                        break;\n                    default:\n                        DLIB_CASSERT(false,\"this should never happen\");\n                }\n            }\n            --counter;\n\n            if (status == 3)\n            {\n                // encode the bytes in inbuf to base64 and write them to the output stream\n                c1 = inbuf[0]&0xfc;\n                c2 = inbuf[0]&0x03;\n                c3 = inbuf[1]&0xf0;\n                c4 = inbuf[1]&0x0f;\n                c5 = inbuf[2]&0xc0;\n                c6 = inbuf[2]&0x3f;\n\n                outbuf[0] = c1>>2;\n                outbuf[1] = (c2<<4)|(c3>>4);\n                outbuf[2] = (c4<<2)|(c5>>6);\n                outbuf[3] = c6;\n\n\n                outbuf[0] = encode_table[outbuf[0]];\n                outbuf[1] = encode_table[outbuf[1]];\n                outbuf[2] = encode_table[outbuf[2]];\n                outbuf[3] = encode_table[outbuf[3]];\n\n                // write the encoded bytes to the output stream\n                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)\n                {\n                    throw std::ios_base::failure(\"error occurred in the base64 object\");\n                }\n\n                // get 3 more input bytes\n                status = in.sgetn(reinterpret_cast<char*>(&inbuf),3);\n                continue;\n            }\n            else if (status == 2)\n            {\n                // we are at the end of the input stream and need to add some padding\n\n                // encode the bytes in inbuf to base64 and write them to the output stream\n                c1 = inbuf[0]&0xfc;\n                c2 = inbuf[0]&0x03;\n                c3 = inbuf[1]&0xf0;\n                c4 = inbuf[1]&0x0f;\n                c5 = 0;\n\n                outbuf[0] = c1>>2;\n                outbuf[1] = (c2<<4)|(c3>>4);\n                outbuf[2] = (c4<<2)|(c5>>6);\n                outbuf[3] = '=';\n\n                outbuf[0] = encode_table[outbuf[0]];\n                outbuf[1] = encode_table[outbuf[1]];\n                outbuf[2] = encode_table[outbuf[2]];\n\n                // write the encoded bytes to the output stream\n                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)\n                {\n                    throw std::ios_base::failure(\"error occurred in the base64 object\");\n                }\n\n\n                break;\n            }\n            else // in this case status must be 1 \n            {\n                // we are at the end of the input stream and need to add some padding\n\n                // encode the bytes in inbuf to base64 and write them to the output stream\n                c1 = inbuf[0]&0xfc;\n                c2 = inbuf[0]&0x03;\n                c3 = 0;\n\n                outbuf[0] = c1>>2;\n                outbuf[1] = (c2<<4)|(c3>>4);\n                outbuf[2] = '=';\n                outbuf[3] = '=';\n\n                outbuf[0] = encode_table[outbuf[0]];\n                outbuf[1] = encode_table[outbuf[1]];\n\n\n                // write the encoded bytes to the output stream\n                if (out.sputn(reinterpret_cast<char*>(&outbuf),4)!=4)\n                {\n                    throw std::ios_base::failure(\"error occurred in the base64 object\");\n                }\n\n                break;\n            }\n        } // while (status != 0)\n        \n\n        // make sure the stream buffer flushes to its I/O channel\n        out.pubsync();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base64::\n    decode (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n        using namespace std;\n        streambuf& in = *in_.rdbuf();\n        streambuf& out = *out_.rdbuf();\n\n        unsigned char inbuf[4];\n        unsigned char outbuf[3];\n        int inbuf_pos = 0;\n        streamsize status = in.sgetn(reinterpret_cast<char*>(inbuf),1);\n\n        // only count this character if it isn't some kind of filler\n        if (status == 1 && decode_table[inbuf[0]] != bad_value )\n            ++inbuf_pos;\n\n        unsigned char c1, c2, c3, c4, c5, c6;\n        streamsize outsize;\n\n        // while we haven't hit the end of the input stream\n        while (status != 0)\n        {\n            // if we have 4 valid characters\n            if (inbuf_pos == 4)\n            {\n                inbuf_pos = 0;\n\n                // this might be the end of the encoded data so we need to figure out if \n                // there was any padding applied.\n                outsize = 3;\n                if (inbuf[3] == '=')\n                {\n                    if (inbuf[2] == '=')\n                        outsize = 1;\n                    else\n                        outsize = 2;\n                }\n\n                // decode the incoming characters\n                inbuf[0] = decode_table[inbuf[0]];\n                inbuf[1] = decode_table[inbuf[1]];\n                inbuf[2] = decode_table[inbuf[2]];\n                inbuf[3] = decode_table[inbuf[3]];\n\n\n                // now pack these guys into bytes rather than 6 bit chunks\n                c1 = inbuf[0]<<2;\n                c2 = inbuf[1]>>4;\n                c3 = inbuf[1]<<4;\n                c4 = inbuf[2]>>2;\n                c5 = inbuf[2]<<6;\n                c6 = inbuf[3];\n\n                outbuf[0] = c1|c2;\n                outbuf[1] = c3|c4;\n                outbuf[2] = c5|c6;\n\n\n                // write the encoded bytes to the output stream\n                if (out.sputn(reinterpret_cast<char*>(&outbuf),outsize)!=outsize)\n                {\n                    throw std::ios_base::failure(\"error occurred in the base64 object\");\n                }\n            }\n\n            // get more input characters \n            status = in.sgetn(reinterpret_cast<char*>(inbuf + inbuf_pos),1);\n            // only count this character if it isn't some kind of filler \n            if ((decode_table[inbuf[inbuf_pos]] != bad_value || inbuf[inbuf_pos] == '=') && \n                status != 0)\n                ++inbuf_pos;\n        } // while (status != 0)\n        \n        if (inbuf_pos != 0)\n        {\n            ostringstream sout;\n            sout << inbuf_pos << \" extra characters were found at the end of the encoded data.\"\n                << \"  This may indicate that the data stream has been truncated.\";\n            // this happens if we hit EOF in the middle of decoding a 24bit block.\n            throw decode_error(sout.str());\n        }\n\n        // make sure the stream buffer flushes to its I/O channel\n        out.pubsync();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BASE64_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/base64/base64_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BASE64_KERNEl_1_\n#define DLIB_BASE64_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"base64_kernel_abstract.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class base64 \n    {\n        /*!\n            INITIAL VALUE\n                - bad_value == 100\n                - encode_table == a pointer to an array of 64 chars\n                - where x is a 6 bit value the following is true:\n                    - encode_table[x] == the base64 encoding of x\n                - decode_table == a pointer to an array of UCHAR_MAX chars\n                - where x is any char value:\n                    - if (x is a valid character in the base64 coding scheme) then\n                        - decode_table[x] == the 6 bit value that x encodes\n                    - else\n                        - decode_table[x] == bad_value \n\n            CONVENTION\n                - The state of this object never changes so just refer to its\n                  initial value.\n                  \n\n        !*/\n\n    public:\n        // this is here for backwards compatibility with older versions of dlib.\n        typedef base64 kernel_1a;\n\n        class decode_error : public dlib::error { public:\n        decode_error( const std::string& e) : error(e) {}};\n\n        base64 (\n        );\n\n        virtual ~base64 (\n        );\n\n        enum line_ending_type\n        {\n            CR,  // i.e. \"\\r\"\n            LF,  // i.e. \"\\n\"\n            CRLF // i.e. \"\\r\\n\"\n        };\n\n        line_ending_type line_ending (\n        ) const;\n\n        void set_line_ending (\n            line_ending_type eol_style_\n        );\n\n        void encode (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n        void decode (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n    private:\n\n        char* encode_table;\n        unsigned char* decode_table;\n        const unsigned char bad_value;\n        line_ending_type eol_style;\n\n        // restricted functions\n        base64(base64&);        // copy constructor\n        base64& operator=(base64&);    // assignment operator\n\n    };   \n   \n}\n\n#ifdef NO_MAKEFILE\n#include \"base64_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_BASE64_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/base64/base64_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BASE64_KERNEl_ABSTRACT_\n#ifdef DLIB_BASE64_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class base64 \n    {\n        /*!\n            INITIAL VALUE\n                - line_ending() == LF\n\n            WHAT THIS OBJECT REPRESENTS\n                This object consists of the two functions encode and decode.\n                These functions allow you to encode and decode data to and from\n                the Base64 Content-Transfer-Encoding defined in section 6.8 of\n                rfc2045.\n        !*/\n\n    public:\n\n        class decode_error : public dlib::error {};\n\n        base64 (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~base64 (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        enum line_ending_type\n        {\n            CR,  // i.e. \"\\r\"\n            LF,  // i.e. \"\\n\"\n            CRLF // i.e. \"\\r\\n\"\n        };\n\n        line_ending_type line_ending (\n        ) const;\n        /*!\n            ensures\n                - returns the type of end of line bytes the encoder\n                  will use when encoding data to base64 blocks.  Note that\n                  the ostream object you use might apply some sort of transform\n                  to line endings as well.  For example, C++ ofstream objects\n                  usually convert '\\n' into whatever a normal newline is for\n                  your platform unless you open a file in binary mode.  But\n                  aside from file streams the ostream objects usually don't\n                  modify the data you pass to them.\n        !*/\n\n        void set_line_ending (\n            line_ending_type eol_style\n        );\n        /*!\n            ensures\n                - #line_ending() == eol_style\n        !*/\n\n        void encode (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - reads all data from in (until EOF is reached) and encodes it\n                  and writes it to out\n            throws\n                - std::ios_base::failure\n                    if there was a problem writing to out then this exception will \n                    be thrown.                      \n                - any other exception\n                    this exception may be thrown if there is any other problem                    \n        !*/\n\n        void decode (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - reads data from in (until EOF is reached), decodes it,\n                  and writes it to out. \n            throws\n                - std::ios_base::failure\n                    if there was a problem writing to out then this exception will \n                    be thrown.           \n                - decode_error\n                    if an error was detected in the encoded data that prevented\n                    it from being correctly decoded then this exception is \n                    thrown.  \n                - any other exception\n                    this exception may be thrown if there is any other problem                    \n        !*/\n\n    private:\n\n        // restricted functions\n        base64(base64&);        // copy constructor\n        base64& operator=(base64&);    // assignment operator\n\n    };   \n   \n}\n\n#endif // DLIB_BASE64_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/base64.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BASe64_\n#define DLIB_BASe64_\n\n#include \"base64/base64_kernel_1.h\"\n\n#endif // DLIB_BASe64_\n\n"
  },
  {
    "path": "dlib/bayes_utils/bayes_utils.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BAYES_UTILs_\n#define DLIB_BAYES_UTILs_\n\n#include \"bayes_utils_abstract.h\"\n\n#include <algorithm>\n#include <ctime>\n#include <memory>\n#include <vector>\n\n#include \"../string.h\"\n#include \"../map.h\"\n#include \"../matrix.h\"\n#include \"../rand.h\"\n#include \"../array.h\"\n#include \"../set.h\"\n#include \"../algs.h\"\n#include \"../noncopyable.h\"\n#include \"../graph.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class assignment \n    {\n    public:\n\n        assignment()\n        {\n        }\n\n        assignment(\n            const assignment& a\n        )\n        {\n            a.reset();\n            while (a.move_next())\n            {\n                unsigned long idx = a.element().key();\n                unsigned long value = a.element().value();\n                vals.add(idx,value);\n            }\n        }\n\n        assignment& operator = (\n            const assignment& rhs\n        )\n        {\n            if (this == &rhs)\n                return *this;\n\n            assignment(rhs).swap(*this);\n            return *this;\n        }\n\n        void clear()\n        {\n            vals.clear();\n        }\n\n        bool operator < (\n            const assignment& item\n        ) const \n        {  \n            if (size() < item.size())\n                return true;\n            else if (size() > item.size())\n                return false;\n\n            reset();\n            item.reset();\n            while (move_next())\n            {\n                item.move_next();\n                if (element().key() < item.element().key())\n                    return true;\n                else if (element().key() > item.element().key())\n                    return false;\n                else if (element().value() < item.element().value())\n                    return true;\n                else if (element().value() > item.element().value())\n                    return false;\n            }\n\n            return false;\n        }\n\n        bool has_index (\n            unsigned long idx\n        ) const\n        {\n            return vals.is_in_domain(idx);\n        }\n\n        void add (\n            unsigned long idx,\n            unsigned long value = 0\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( has_index(idx) == false ,\n                         \"\\tvoid assignment::add(idx)\"\n                         << \"\\n\\tYou can't add the same index to an assignment object more than once\"\n                         << \"\\n\\tidx:  \" << idx \n                         << \"\\n\\tthis: \" << this\n            );\n\n            vals.add(idx, value);\n        }\n\n        unsigned long& operator[] (\n            const long idx\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( has_index(idx) == true ,\n                         \"\\tunsigned long assignment::operator[](idx)\"\n                         << \"\\n\\tYou can't access an index value if it isn't already in the object\"\n                         << \"\\n\\tidx:  \" << idx \n                         << \"\\n\\tthis: \" << this\n            );\n\n            return vals[idx];\n        }\n\n        const unsigned long& operator[] (\n            const long idx\n        ) const\n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( has_index(idx) == true ,\n                         \"\\tunsigned long assignment::operator[](idx)\"\n                         << \"\\n\\tYou can't access an index value if it isn't already in the object\"\n                         << \"\\n\\tidx:  \" << idx \n                         << \"\\n\\tthis: \" << this\n            );\n\n            return vals[idx];\n        }\n\n        void swap (\n            assignment& item\n        )\n        {\n            vals.swap(item.vals);\n        }\n\n        void remove (\n            unsigned long idx\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( has_index(idx) == true ,\n                         \"\\tunsigned long assignment::remove(idx)\"\n                         << \"\\n\\tYou can't remove an index value if it isn't already in the object\"\n                         << \"\\n\\tidx:  \" << idx \n                         << \"\\n\\tthis: \" << this\n            );\n\n            vals.destroy(idx);\n        }\n\n        unsigned long size() const { return vals.size(); }\n\n        void reset() const { vals.reset(); }\n\n        bool move_next() const { return vals.move_next(); }\n\n        map_pair<unsigned long, unsigned long>& element() \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                        \"\\tmap_pair<unsigned long,unsigned long>& assignment::element()\"\n                        << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                        << \"\\n\\tthis: \" << this\n            );\n            return vals.element(); \n        }\n\n        const map_pair<unsigned long, unsigned long>& element() const \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                        \"\\tconst map_pair<unsigned long,unsigned long>& assignment::element() const\"\n                        << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                        << \"\\n\\tthis: \" << this\n            );\n\n            return vals.element(); \n        }\n\n        bool at_start() const { return vals.at_start(); }\n\n        bool current_element_valid() const { return vals.current_element_valid(); }\n\n        friend inline void serialize (\n            const assignment& item,\n            std::ostream& out \n        )   \n        {\n            serialize(item.vals, out);\n        }\n\n        friend inline void deserialize (\n            assignment& item,\n            std::istream& in\n        )\n        {\n            deserialize(item.vals, in);\n        }\n\n    private:\n        mutable dlib::map<unsigned long, unsigned long>::kernel_1b_c vals;\n    };\n\n    inline std::ostream& operator << (\n        std::ostream& out,\n        const assignment& a\n    )\n    {\n        a.reset();\n        out << \"(\";\n        if (a.move_next())\n            out << a.element().key() << \":\" << a.element().value();\n\n        while (a.move_next())\n        {\n            out << \", \" << a.element().key() << \":\" << a.element().value();\n        }\n\n        out << \")\";\n        return out;\n    }\n\n\n    inline void swap (\n        assignment& a,\n        assignment& b\n    )\n    {\n        a.swap(b);\n    }\n\n\n// ------------------------------------------------------------------------\n\n    class joint_probability_table \n    {\n        /*!\n            INITIAL VALUE\n                - table.size() == 0\n\n            CONVENTION\n                - size() == table.size()\n                - probability(a) == table[a]\n        !*/\n    public:\n\n        joint_probability_table (\n            const joint_probability_table& t\n        )\n        {\n            t.reset();\n            while (t.move_next())\n            {\n                assignment a = t.element().key();\n                double p = t.element().value();\n                set_probability(a,p);\n            }\n        }\n\n        joint_probability_table() {}\n\n        joint_probability_table& operator= (\n            const joint_probability_table& rhs\n        )\n        {\n            if (this == &rhs)\n                return *this;\n            joint_probability_table(rhs).swap(*this);\n            return *this;\n        }\n\n        void set_probability (\n            const assignment& a,\n            double p\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(0.0 <= p && p <= 1.0,\n                        \"\\tvoid& joint_probability_table::set_probability(a,p)\"\n                        << \"\\n\\tyou have given an invalid probability value\"\n                        << \"\\n\\tp:    \" << p \n                        << \"\\n\\ta:    \" << a \n                        << \"\\n\\tthis: \" << this\n            );\n\n            if (table.is_in_domain(a))\n            {\n                table[a] = p;\n            }\n            else\n            {\n                assignment temp(a);\n                table.add(temp,p);\n            }\n        }\n\n        bool has_entry_for (\n            const assignment& a\n        ) const\n        {\n            return table.is_in_domain(a);\n        }\n\n        void add_probability (\n            const assignment& a,\n            double p\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(0.0 <= p && p <= 1.0,\n                        \"\\tvoid& joint_probability_table::add_probability(a,p)\"\n                        << \"\\n\\tyou have given an invalid probability value\"\n                        << \"\\n\\tp:    \" << p \n                        << \"\\n\\ta:    \" << a \n                        << \"\\n\\tthis: \" << this\n            );\n\n            if (table.is_in_domain(a))\n            {\n                table[a] += p;\n                if (table[a] > 1.0)\n                    table[a] = 1.0;\n            }\n            else\n            {\n                assignment temp(a);\n                table.add(temp,p);\n            }\n        }\n\n        double probability (\n            const assignment& a\n        ) const\n        {\n            return table[a];\n        }\n\n        void clear()\n        {\n            table.clear();\n        }\n\n        size_t size () const { return table.size(); }\n        bool move_next() const { return table.move_next(); }\n        void reset() const { table.reset(); }\n        map_pair<assignment,double>& element() \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                        \"\\tmap_pair<assignment,double>& joint_probability_table::element()\"\n                        << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                        << \"\\n\\tthis: \" << this\n            );\n\n            return table.element(); \n        }\n\n        const map_pair<assignment,double>& element() const \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid() == true,\n                        \"\\tconst map_pair<assignment,double>& joint_probability_table::element() const\"\n                        << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                        << \"\\n\\tthis: \" << this\n            );\n\n            return table.element(); \n        }\n\n        bool at_start() const { return table.at_start(); }\n\n        bool current_element_valid() const { return table.current_element_valid(); }\n\n\n        template <typename T>\n        void marginalize (\n            const T& vars,\n            joint_probability_table& out\n        ) const\n        {\n            out.clear();\n            double p;\n            reset();\n            while (move_next())\n            {\n                assignment a;\n                const assignment& asrc = element().key();\n                p = element().value();\n\n                asrc.reset();\n                while (asrc.move_next())\n                {\n                    if (vars.is_member(asrc.element().key()))\n                        a.add(asrc.element().key(), asrc.element().value());\n                }\n\n                out.add_probability(a,p);\n            }\n        }\n\n        void marginalize (\n            const unsigned long var,\n            joint_probability_table& out\n        ) const\n        {\n            out.clear();\n            double p;\n            reset();\n            while (move_next())\n            {\n                assignment a;\n                const assignment& asrc = element().key();\n                p = element().value();\n\n                asrc.reset();\n                while (asrc.move_next())\n                {\n                    if (var == asrc.element().key())\n                        a.add(asrc.element().key(), asrc.element().value());\n                }\n\n                out.add_probability(a,p);\n            }\n        }\n\n        void normalize (\n        )\n        {\n            double sum = 0;\n\n            reset();\n            while (move_next())\n                sum += element().value();\n\n            reset();\n            while (move_next())\n                element().value() /= sum;\n        }\n\n        void swap (\n            joint_probability_table& item\n        )\n        {\n            table.swap(item.table);\n        }\n\n        friend inline void serialize (\n            const joint_probability_table& item,\n            std::ostream& out \n        )   \n        {\n            serialize(item.table, out);\n        }\n\n        friend inline void deserialize (\n            joint_probability_table& item,\n            std::istream& in\n        )\n        {\n            deserialize(item.table, in);\n        }\n\n    private:\n\n        dlib::map<assignment, double >::kernel_1b_c table;\n    };\n\n    inline void swap (\n        joint_probability_table& a,\n        joint_probability_table& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    class conditional_probability_table : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                - table.size() == 0\n\n            CONVENTION\n                - if (table.is_in_domain(ps) && value < num_vals && table[ps](value) >= 0) then\n                    - has_entry_for(value,ps) == true\n                    - probability(value,ps) == table[ps](value)\n                - else\n                    - has_entry_for(value,ps) == false \n\n                - num_values() == num_vals\n        !*/\n    public:\n\n        conditional_probability_table()\n        {\n            clear();\n        }\n\n        void set_num_values (\n            unsigned long num\n        )\n        {\n            num_vals = num;\n            table.clear();\n        }\n\n        bool has_entry_for (\n            unsigned long value,\n            const assignment& ps\n        ) const\n        {\n            if (table.is_in_domain(ps) && value < num_vals && table[ps](value) >= 0)\n                return true;\n            else\n                return false;\n        }\n\n        unsigned long num_values (\n        ) const { return num_vals; }\n\n        void set_probability (\n            unsigned long value,\n            const assignment& ps,\n            double p\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( value < num_values() && 0.0 <= p && p <= 1.0 ,\n                         \"\\tvoid conditional_probability_table::set_probability()\"\n                         << \"\\n\\tinvalid arguments to set_probability\"\n                         << \"\\n\\tvalue: \" << value \n                         << \"\\n\\tnum_values(): \" << num_values()\n                         << \"\\n\\tp:     \" << p \n                         << \"\\n\\tps:    \" << ps \n                         << \"\\n\\tthis:  \" << this\n            );\n\n            if (table.is_in_domain(ps))\n            {\n                table[ps](value) = p;\n            }\n            else\n            {\n                matrix<double,1> dist(num_vals);\n                set_all_elements(dist,-1);\n                dist(value) = p;\n                assignment temp(ps);\n                table.add(temp,dist);\n            }\n        }\n\n        double probability(\n            unsigned long value,\n            const assignment& ps \n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( value < num_values() && has_entry_for(value,ps) ,\n                         \"\\tvoid conditional_probability_table::probability()\"\n                         << \"\\n\\tinvalid arguments to probability\"\n                         << \"\\n\\tvalue:        \" << value \n                         << \"\\n\\tnum_values(): \" << num_values() \n                         << \"\\n\\tps:           \" << ps \n                         << \"\\n\\tthis:         \" << this\n            );\n\n            return table[ps](value);\n        }\n\n        void clear()\n        {\n            table.clear();\n            num_vals = 0;\n        }\n\n        void empty_table ()\n        {\n            table.clear();\n        }\n\n        void swap (\n            conditional_probability_table& item \n        ) \n        { \n            exchange(num_vals, item.num_vals);\n            table.swap(item.table);\n        }\n\n        friend inline void serialize (\n            const conditional_probability_table& item,\n            std::ostream& out \n        )   \n        {\n            serialize(item.table, out);\n            serialize(item.num_vals, out);\n        }\n\n        friend inline void deserialize (\n            conditional_probability_table& item,\n            std::istream& in\n        )\n        {\n            deserialize(item.table, in);\n            deserialize(item.num_vals, in);\n        }\n\n    private:\n        dlib::map<assignment, matrix<double,1> >::kernel_1b_c table;\n        unsigned long num_vals;\n    };\n\n    inline void swap (\n        conditional_probability_table& a,\n        conditional_probability_table& b\n    ) { a.swap(b); }\n\n// ------------------------------------------------------------------------\n\n    class bayes_node : noncopyable\n    {\n    public:\n        bayes_node ()\n        {\n            is_instantiated = false;\n            value_ = 0;\n        }\n\n        unsigned long value (\n        ) const { return value_;}\n\n        void set_value (\n            unsigned long new_value\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( new_value < table().num_values(),\n                         \"\\tvoid bayes_node::set_value(new_value)\"\n                         << \"\\n\\tnew_value must be less than the number of possible values for this node\"\n                         << \"\\n\\tnew_value:            \" << new_value \n                         << \"\\n\\ttable().num_values(): \" << table().num_values() \n                         << \"\\n\\tthis:                 \" << this\n            );\n\n            value_ = new_value;\n        }\n\n        conditional_probability_table& table (\n        ) { return table_; }\n\n        const conditional_probability_table& table (\n        ) const { return table_; }\n\n        bool is_evidence (\n        ) const { return is_instantiated; }\n\n        void set_as_nonevidence (\n        ) { is_instantiated = false; }\n\n        void set_as_evidence (\n        ) { is_instantiated = true; }\n\n        void swap (\n            bayes_node& item \n        ) \n        { \n            exchange(value_, item.value_);\n            exchange(is_instantiated, item.is_instantiated);\n            table_.swap(item.table_);\n        }\n\n        friend inline void serialize (\n            const bayes_node& item,\n            std::ostream& out \n        )   \n        {\n            serialize(item.value_, out);\n            serialize(item.is_instantiated, out);\n            serialize(item.table_, out);\n        }\n\n        friend inline void deserialize (\n            bayes_node& item,\n            std::istream& in\n        )\n        {\n            deserialize(item.value_, in);\n            deserialize(item.is_instantiated, in);\n            deserialize(item.table_, in);\n        }\n\n    private:\n\n        unsigned long value_; \n        bool is_instantiated;\n        conditional_probability_table table_;\n    };\n\n    inline void swap (\n        bayes_node& a,\n        bayes_node& b\n    ) { a.swap(b); }\n\n// ------------------------------------------------------------------------\n\n    namespace bayes_node_utils\n    {\n\n        template <typename T>\n        unsigned long node_num_values (\n            const T& bn,\n            unsigned long n\n        )  \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tvoid bayes_node_utils::node_num_values(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            return bn.node(n).data.table().num_values(); \n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        void set_node_value (\n            T& bn,\n            unsigned long n,\n            unsigned long val\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes() && val < node_num_values(bn,n),\n                         \"\\tvoid bayes_node_utils::set_node_value(bn, n, val)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tval:                   \" << val \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n                         << \"\\n\\tnode_num_values(bn,n): \" << node_num_values(bn,n) \n            );\n\n            bn.node(n).data.set_value(val); \n        }\n\n    // ----------------------------------------------------------------------------------------\n        template <typename T>\n        unsigned long node_value (\n            const T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tunsigned long bayes_node_utils::node_value(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            return bn.node(n).data.value();\n        }\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool node_is_evidence (\n            const T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tbool bayes_node_utils::node_is_evidence(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            return bn.node(n).data.is_evidence();\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        void set_node_as_evidence (\n            T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tvoid bayes_node_utils::set_node_as_evidence(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            bn.node(n).data.set_as_evidence(); \n        }\n\n    // ----------------------------------------------------------------------------------------\n        template <typename T>\n        void set_node_as_nonevidence (\n            T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tvoid bayes_node_utils::set_node_as_nonevidence(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            bn.node(n).data.set_as_nonevidence(); \n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        void set_node_num_values (\n            T& bn,\n            unsigned long n,\n            unsigned long num\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tvoid bayes_node_utils::set_node_num_values(bn, n, num)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            bn.node(n).data.table().set_num_values(num); \n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        double node_probability (\n            const T& bn,\n            unsigned long n,\n            unsigned long value,\n            const assignment& parents \n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes() && value < node_num_values(bn,n),\n                         \"\\tdouble bayes_node_utils::node_probability(bn, n, value, parents)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tvalue:                 \" << value \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n                         << \"\\n\\tnode_num_values(bn,n): \" << node_num_values(bn,n) \n            );\n\n            DLIB_ASSERT( parents.size() == bn.node(n).number_of_parents(),\n                         \"\\tdouble bayes_node_utils::node_probability(bn, n, value, parents)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                             \" << n \n                         << \"\\n\\tparents.size():                \" << parents.size()\n                         << \"\\n\\tb.node(n).number_of_parents(): \" << bn.node(n).number_of_parents()\n            );\n\n#ifdef ENABLE_ASSERTS\n            parents.reset();\n            while (parents.move_next())\n            {\n                const unsigned long x = parents.element().key();\n                DLIB_ASSERT( bn.has_edge(x, n),\n                             \"\\tdouble bayes_node_utils::node_probability(bn, n, value, parents)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn: \" << n \n                             << \"\\n\\tx: \" << x \n                );\n                DLIB_ASSERT( parents[x] < node_num_values(bn,x),\n                             \"\\tdouble bayes_node_utils::node_probability(bn, n, value, parents)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn:                     \" << n \n                             << \"\\n\\tx:                     \" << x \n                             << \"\\n\\tparents[x]:            \" << parents[x] \n                             << \"\\n\\tnode_num_values(bn,x): \" << node_num_values(bn,x) \n                );\n            }\n#endif\n\n            return bn.node(n).data.table().probability(value, parents);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        void set_node_probability (\n            T& bn,\n            unsigned long n,\n            unsigned long value,\n            const assignment& parents,\n            double p\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes() && value < node_num_values(bn,n),\n                         \"\\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tp:                     \" << p \n                         << \"\\n\\tvalue:                 \" << value \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n                         << \"\\n\\tnode_num_values(bn,n): \" << node_num_values(bn,n) \n            );\n\n            DLIB_ASSERT( parents.size() == bn.node(n).number_of_parents(),\n                         \"\\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                             \" << n \n                         << \"\\n\\tp:                             \" << p \n                         << \"\\n\\tparents.size():                \" << parents.size()\n                         << \"\\n\\tbn.node(n).number_of_parents(): \" << bn.node(n).number_of_parents()\n            );\n\n            DLIB_ASSERT( 0.0 <= p && p <= 1.0,\n                         \"\\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn: \" << n \n                         << \"\\n\\tp: \" << p \n            );\n\n#ifdef ENABLE_ASSERTS\n            parents.reset();\n            while (parents.move_next())\n            {\n                const unsigned long x = parents.element().key();\n                DLIB_ASSERT( bn.has_edge(x, n),\n                             \"\\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn: \" << n \n                             << \"\\n\\tx: \" << x \n                );\n                DLIB_ASSERT( parents[x] < node_num_values(bn,x),\n                             \"\\tvoid bayes_node_utils::set_node_probability(bn, n, value, parents, p)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn:                     \" << n \n                             << \"\\n\\tx:                     \" << x \n                             << \"\\n\\tparents[x]:            \" << parents[x] \n                             << \"\\n\\tnode_num_values(bn,x): \" << node_num_values(bn,x) \n                );\n            }\n#endif\n\n            bn.node(n).data.table().set_probability(value,parents,p);\n        }\n\n// ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        const assignment node_first_parent_assignment (\n            const T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tconst assignment bayes_node_utils::node_first_parent_assignment(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n            );\n\n            assignment a;\n            const unsigned long num_parents = bn.node(n).number_of_parents();\n            for (unsigned long i = 0; i < num_parents; ++i)\n            {\n                a.add(bn.node(n).parent(i).index(), 0);\n            }\n            return a;\n        }\n\n// ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool node_next_parent_assignment (\n            const T& bn,\n            unsigned long n,\n            assignment& a\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n            );\n\n            DLIB_ASSERT( a.size() == bn.node(n).number_of_parents(),\n                         \"\\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                             \" << n \n                         << \"\\n\\ta.size():                      \" << a.size()\n                         << \"\\n\\tbn.node(n).number_of_parents(): \" << bn.node(n).number_of_parents()\n            );\n\n#ifdef ENABLE_ASSERTS\n            a.reset();\n            while (a.move_next())\n            {\n                const unsigned long x = a.element().key();\n                DLIB_ASSERT( bn.has_edge(x, n),\n                             \"\\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn: \" << n \n                             << \"\\n\\tx: \" << x \n                );\n                DLIB_ASSERT( a[x] < node_num_values(bn,x),\n                             \"\\tbool bayes_node_utils::node_next_parent_assignment(bn, n, a)\"\n                             << \"\\n\\tInvalid arguments to this function\"\n                             << \"\\n\\tn:                     \" << n \n                             << \"\\n\\tx:                     \" << x \n                             << \"\\n\\ta[x]:                  \" << a[x] \n                             << \"\\n\\tnode_num_values(bn,x): \" << node_num_values(bn,x) \n                );\n            }\n#endif\n\n            // basically this loop just adds 1 to the assignment but performs\n            // carries if necessary\n            for (unsigned long p = 0; p < a.size(); ++p)\n            {\n                const unsigned long pindex = bn.node(n).parent(p).index();\n                a[pindex] += 1;\n\n                // if we need to perform a carry\n                if (a[pindex] >= node_num_values(bn,pindex))\n                {\n                    a[pindex] = 0;\n                }\n                else\n                {\n                    // no carry necessary so we are done\n                    return true;\n                }\n            }\n\n            // we got through the entire loop which means a carry propagated all the way out\n            // so there must not be any more valid assignments left\n            return false;\n        }\n\n// ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool node_cpt_filled_out (\n            const T& bn,\n            unsigned long n\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT( n < bn.number_of_nodes(),\n                         \"\\tbool bayes_node_utils::node_cpt_filled_out(bn, n)\"\n                         << \"\\n\\tInvalid arguments to this function\"\n                         << \"\\n\\tn:                     \" << n \n                         << \"\\n\\tbn.number_of_nodes():  \" << bn.number_of_nodes() \n            );\n\n            const unsigned long num_values = node_num_values(bn,n);\n\n\n            const conditional_probability_table& table = bn.node(n).data.table();\n\n            // now loop over all the possible parent assignments for this node\n            assignment a(node_first_parent_assignment(bn,n));\n            do\n            {\n                double sum = 0;\n                // make sure that this assignment has an entry for all the values this node can take one\n                for (unsigned long value = 0; value < num_values; ++value)\n                {\n                    if (table.has_entry_for(value,a) == false)\n                        return false;\n                    else\n                        sum += table.probability(value,a);\n                }\n\n                // check if the sum of probabilities equals 1 as it should\n                if (std::abs(sum-1.0) > 1e-5)\n                    return false;\n            } while (node_next_parent_assignment(bn,n,a));\n\n            return true;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class bayesian_network_gibbs_sampler : noncopyable\n    {\n    public:\n\n        bayesian_network_gibbs_sampler ()\n        {\n            rnd.set_seed(cast_to_string(std::time(0)));\n        }\n\n\n        template <\n            typename T\n            >\n        void sample_graph (\n            T& bn\n        )\n        {\n            using namespace bayes_node_utils;\n            for (unsigned long n = 0; n < bn.number_of_nodes(); ++n)\n            {\n                if (node_is_evidence(bn, n))\n                    continue;\n\n                samples.set_size(node_num_values(bn,n)); \n                // obtain the probability distribution for this node\n                for (long i = 0; i < samples.nc(); ++i)\n                {\n                    set_node_value(bn, n, i);\n                    samples(i) = node_probability(bn, n);\n\n                    for (unsigned long j = 0; j < bn.node(n).number_of_children(); ++j)\n                        samples(i) *= node_probability(bn, bn.node(n).child(j).index());\n                }\n\n                //normalize samples\n                samples /= sum(samples);\n\n\n                // select a random point in the probability distribution\n                double prob = rnd.get_random_double();\n\n                // now find the point in the distribution this probability corresponds to\n                long j;\n                for (j = 0; j < samples.nc()-1; ++j)\n                {\n                    if (prob <= samples(j))\n                        break;\n                    else\n                        prob -= samples(j);\n                }\n\n                set_node_value(bn, n, j);\n            }\n        }\n\n\n    private:\n\n        template <\n            typename T\n            >\n        double node_probability (\n            const T& bn,\n            unsigned long n \n        ) \n        /*!\n            requires\n                - n < bn.number_of_nodes()\n            ensures\n                - computes the probability of node n having its current value given\n                  the current values of its parents in the network bn\n        !*/\n        {\n            v.clear();\n            for (unsigned long i = 0; i < bn.node(n).number_of_parents(); ++i)\n            {\n                v.add(bn.node(n).parent(i).index(), bn.node(n).parent(i).data.value());\n            }\n            return bn.node(n).data.table().probability(bn.node(n).data.value(), v);\n        }\n\n        assignment v;\n\n        dlib::rand rnd;\n        matrix<double,1> samples; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace bayesian_network_join_tree_helpers\n    {\n        class bnjt\n        {\n            /*!\n                this object is the base class used in this pimpl idiom\n            !*/\n        public:\n            virtual ~bnjt() {}\n\n            virtual const matrix<double,1> probability(\n                unsigned long idx\n            )  const = 0;\n        };\n\n        template <typename T, typename U>\n        class bnjt_impl : public bnjt\n        {\n            /*!\n                This object is the implementation in the pimpl idiom\n            !*/\n\n        public:\n\n            bnjt_impl (\n                const T& bn,\n                const U& join_tree\n            )\n            {\n                create_bayesian_network_join_tree(bn, join_tree, join_tree_values);\n\n                cliques.resize(bn.number_of_nodes());\n\n                // figure out which cliques contain each node\n                for (unsigned long i = 0; i < cliques.size(); ++i)\n                {\n                    // find the smallest clique that contains node with index i\n                    unsigned long smallest_clique = 0;\n                    unsigned long size = std::numeric_limits<unsigned long>::max();\n\n                    for (unsigned long n = 0; n < join_tree.number_of_nodes(); ++n)\n                    {\n                        if (join_tree.node(n).data.is_member(i) && join_tree.node(n).data.size() < size)\n                        {\n                            size = join_tree.node(n).data.size();\n                            smallest_clique = n;\n                        }\n                    }\n\n                    cliques[i] = smallest_clique;\n                }\n            }\n\n            virtual const matrix<double,1> probability(\n                unsigned long idx\n            ) const \n            {\n                join_tree_values.node(cliques[idx]).data.marginalize(idx, table);\n                table.normalize();\n                var.clear();\n                var.add(idx);\n                dist.set_size(table.size());\n\n                // read the probabilities out of the table and into the row matrix\n                for (unsigned long i = 0; i < table.size(); ++i)\n                {\n                    var[idx] = i;\n                    dist(i) = table.probability(var); \n                }\n\n                return dist;\n            }\n\n        private:\n\n            graph< joint_probability_table, joint_probability_table >::kernel_1a_c join_tree_values;\n            array<unsigned long> cliques;\n            mutable joint_probability_table table;\n            mutable assignment var;\n            mutable matrix<double,1> dist;\n           \n\n        // ----------------------------------------------------------------------------------------\n\n            template <typename set_type, typename node_type>\n            bool set_contains_all_parents_of_node (\n                const set_type& set,\n                const node_type& node\n            )\n            {\n                for (unsigned long i = 0; i < node.number_of_parents(); ++i)\n                {\n                    if (set.is_member(node.parent(i).index()) == false)\n                        return false;\n                }\n                return true;\n            }\n\n        // ----------------------------------------------------------------------------------------\n\n            template <\n                typename V\n                >\n            void pass_join_tree_message (\n                const U& join_tree,\n                V& bn_join_tree ,\n                unsigned long from,\n                unsigned long to\n            )\n            {\n                using namespace bayes_node_utils;\n                const typename U::edge_type& e = edge(join_tree, from, to);\n                typename V::edge_type& old_s = edge(bn_join_tree, from, to);\n\n                typedef typename V::edge_type joint_prob_table;\n\n                joint_prob_table new_s;\n                bn_join_tree.node(from).data.marginalize(e, new_s);\n\n                joint_probability_table temp(new_s);\n                // divide new_s by old_s and store the result in temp.\n                // if old_s is empty then that is the same as if it was all 1s\n                // so we don't have to do this if that is the case.\n                if (old_s.size() > 0)\n                {\n                    temp.reset();\n                    old_s.reset();\n                    while (temp.move_next())\n                    {\n                        old_s.move_next();\n                        if (old_s.element().value() != 0)\n                            temp.element().value()  /= old_s.element().value();\n                    }\n                }\n\n                // now multiply temp by d and store the results in d\n                joint_probability_table& d = bn_join_tree.node(to).data;\n                d.reset();\n                while (d.move_next())\n                {\n                    assignment a; \n                    const assignment& asrc = d.element().key();\n                    asrc.reset();\n                    while (asrc.move_next())\n                    {\n                        if (e.is_member(asrc.element().key()))\n                            a.add(asrc.element().key(), asrc.element().value());\n                    }\n\n                    d.element().value() *= temp.probability(a);\n\n                }\n\n                // store new_s in old_s\n                new_s.swap(old_s);\n\n            }\n\n        // ----------------------------------------------------------------------------------------\n\n            template <\n                typename V\n                >\n            void create_bayesian_network_join_tree (\n                const T& bn,\n                const U& join_tree,\n                V& bn_join_tree \n            )\n            /*!\n                requires\n                    - bn is a proper bayesian network\n                    - join_tree is the join tree for that bayesian network\n                ensures\n                    - bn_join_tree == the output of the join tree algorithm for bayesian network inference.  \n                      So each node in this graph contains a joint_probability_table for the clique\n                      in the corresponding node in the join_tree graph.\n            !*/\n            {\n                using namespace bayes_node_utils;\n                bn_join_tree.clear();\n                copy_graph_structure(join_tree, bn_join_tree);\n\n                // we need to keep track of which node is \"in\" each clique for the purposes of \n                // initializing the tables in each clique.  So this vector will be used to do that\n                // and a value of join_tree.number_of_nodes() means that the node with \n                // that index is unassigned.\n                std::vector<unsigned long> node_assigned_to(bn.number_of_nodes(),join_tree.number_of_nodes());\n\n                // populate evidence with all the evidence node indices and their values\n                dlib::map<unsigned long, unsigned long>::kernel_1b_c evidence;\n                for (unsigned long i = 0; i < bn.number_of_nodes(); ++i)\n                {\n                    if (node_is_evidence(bn, i))\n                    {\n                        unsigned long idx = i;\n                        unsigned long value = node_value(bn, i);\n                        evidence.add(idx,value);\n                    }\n                }\n\n\n                // initialize the bn join tree\n                for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)\n                {\n                    bool contains_evidence = false;\n                    std::vector<unsigned long> indices;\n                    assignment value;\n\n                    // loop over all the nodes in this clique in the join tree.  In this loop \n                    // we are making an assignment with all the values of the nodes it represents set to 0\n                    join_tree.node(i).data.reset();\n                    while (join_tree.node(i).data.move_next())\n                    {\n                        const unsigned long idx = join_tree.node(i).data.element();\n                        indices.push_back(idx);\n                        value.add(idx);\n\n                        if (evidence.is_in_domain(join_tree.node(i).data.element()))\n                            contains_evidence = true;\n                    }\n\n                    // now loop over all possible combinations of values that the nodes this \n                    // clique in the join tree can take on.  We do this by counting by one through all\n                    // legal values\n                    bool more_assignments = true;\n                    while (more_assignments)\n                    {\n                        bn_join_tree.node(i).data.set_probability(value,1);\n\n                        // account for any evidence\n                        if (contains_evidence)\n                        {\n                            // loop over all the nodes in this cluster\n                            for (unsigned long j = 0; j < indices.size(); ++j)\n                            {\n                                // if the current node is an evidence node\n                                if (evidence.is_in_domain(indices[j]))\n                                {\n                                    const unsigned long idx = indices[j];\n                                    const unsigned long evidence_value = evidence[idx];\n                                    if (value[idx] != evidence_value)\n                                        bn_join_tree.node(i).data.set_probability(value , 0);\n                                }\n                            }\n                        }\n\n\n                        // now check if any of the nodes in this cluster also have their parents in this cluster\n                        join_tree.node(i).data.reset();\n                        while (join_tree.node(i).data.move_next())\n                        {\n                            const unsigned long idx = join_tree.node(i).data.element();\n                            // if this clique contains all the parents of this node and also hasn't\n                            // been assigned to another clique\n                            if (set_contains_all_parents_of_node(join_tree.node(i).data,  bn.node(idx)) && \n                                (i == node_assigned_to[idx] || node_assigned_to[idx] == join_tree.number_of_nodes()) )\n                            {\n                                // note that this node is now assigned to this clique \n                                node_assigned_to[idx] = i;\n                                // node idx has all its parents in the cluster\n                                assignment parent_values;\n                                for (unsigned long j = 0; j < bn.node(idx).number_of_parents(); ++j)\n                                {\n                                    const unsigned long pidx = bn.node(idx).parent(j).index();\n                                    parent_values.add(pidx, value[pidx]);\n                                }\n\n                                double temp = bn_join_tree.node(i).data.probability(value);\n                                bn_join_tree.node(i).data.set_probability(value, temp * node_probability(bn, idx, value[idx], parent_values));\n\n                            }\n                        }\n\n\n                        // now advance the value variable to its next possible state if there is one\n                        more_assignments = false;\n                        value.reset();\n                        while (value.move_next())\n                        {\n                            value.element().value() += 1;\n                            // if overflow\n                            if (value.element().value() == node_num_values(bn, value.element().key()))\n                            {\n                                value.element().value() = 0;\n                            }\n                            else\n                            {\n                                more_assignments = true;\n                                break;\n                            }\n                        }\n\n                    } // end while (more_assignments) \n                } \n\n\n\n\n                // the tree is now initialized.  Now all we need to do is perform the propagation and\n                // we are done\n                dlib::array<dlib::set<unsigned long>::compare_1b_c> remaining_msg_to_send;\n                dlib::array<dlib::set<unsigned long>::compare_1b_c> remaining_msg_to_receive;\n                remaining_msg_to_receive.resize(join_tree.number_of_nodes());\n                remaining_msg_to_send.resize(join_tree.number_of_nodes());\n                for (unsigned long i = 0; i < remaining_msg_to_receive.size(); ++i)\n                {\n                    for (unsigned long j = 0; j < join_tree.node(i).number_of_neighbors(); ++j)\n                    {\n                        const unsigned long idx = join_tree.node(i).neighbor(j).index();\n                        unsigned long temp;\n                        temp = idx; remaining_msg_to_receive[i].add(temp);\n                        temp = idx; remaining_msg_to_send[i].add(temp);\n                    }\n                }\n\n                // now remaining_msg_to_receive[i] contains all the nodes that node i hasn't yet received\n                // a message from.\n                // we will consider node 0 to be the root node.\n\n\n                bool message_sent = true;\n                while (message_sent)\n                {\n                    message_sent = false;\n                    for (unsigned long i = 1; i < remaining_msg_to_send.size(); ++i)\n                    {\n                        // if node i hasn't sent any messages but has received all but one then send a message to the one\n                        // node who hasn't sent i a message\n                        if (remaining_msg_to_send[i].size() == join_tree.node(i).number_of_neighbors() && remaining_msg_to_receive[i].size() == 1)\n                        {\n                            unsigned long to;\n                            // get the last remaining thing from this set\n                            remaining_msg_to_receive[i].remove_any(to);\n\n                            // send the message\n                            pass_join_tree_message(join_tree, bn_join_tree, i, to);\n\n                            // record that we sent this message\n                            remaining_msg_to_send[i].destroy(to);\n                            remaining_msg_to_receive[to].destroy(i);\n\n                            // put to back in since we still need to receive it\n                            remaining_msg_to_receive[i].add(to);\n                            message_sent = true;\n                        }\n                        else if (remaining_msg_to_receive[i].size() == 0 && remaining_msg_to_send[i].size() > 0)\n                        {\n                            unsigned long to;\n                            remaining_msg_to_send[i].remove_any(to);\n                            remaining_msg_to_receive[to].destroy(i);\n                            pass_join_tree_message(join_tree, bn_join_tree, i, to);\n                            message_sent = true;\n                        }\n                    }\n\n                    if (remaining_msg_to_receive[0].size() == 0)\n                    {\n                        // send a message to all of the root nodes neighbors unless we have already sent out he messages\n                        while (remaining_msg_to_send[0].size() > 0)\n                        {\n                            unsigned long to;\n                            remaining_msg_to_send[0].remove_any(to);\n                            remaining_msg_to_receive[to].destroy(0);\n                            pass_join_tree_message(join_tree, bn_join_tree, 0, to);\n                            message_sent = true;\n                        }\n                    }\n\n\n                }\n\n            }\n\n        };\n    }\n\n    class bayesian_network_join_tree : noncopyable\n    {\n        /*!\n            use the pimpl idiom to push the template arguments from the class level to the\n            constructor level\n        !*/\n\n    public:\n\n        template <\n            typename T,\n            typename U\n            >\n        bayesian_network_join_tree (\n            const T& bn,\n            const U& join_tree\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( bn.number_of_nodes() > 0 ,\n                        \"\\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)\"\n                        << \"\\n\\tYou have given an invalid bayesian network\"\n                        << \"\\n\\tthis:              \" << this\n                    );\n\n            DLIB_ASSERT( is_join_tree(bn, join_tree) == true ,\n                        \"\\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)\"\n                        << \"\\n\\tYou have given an invalid join tree for the supplied bayesian network\"\n                        << \"\\n\\tthis:              \" << this\n                    );\n            DLIB_ASSERT( graph_contains_length_one_cycle(bn) == false,\n                        \"\\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)\"\n                        << \"\\n\\tYou have given an invalid bayesian network\"\n                        << \"\\n\\tthis:              \" << this\n                    );\n            DLIB_ASSERT( graph_is_connected(bn) == true,\n                        \"\\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)\"\n                        << \"\\n\\tYou have given an invalid bayesian network\"\n                        << \"\\n\\tthis:              \" << this\n                    );\n\n#ifdef ENABLE_ASSERTS\n            for (unsigned long i = 0; i < bn.number_of_nodes(); ++i)\n            {\n                DLIB_ASSERT(bayes_node_utils::node_cpt_filled_out(bn,i) == true,\n                        \"\\tbayesian_network_join_tree::bayesian_network_join_tree(bn,join_tree)\"\n                        << \"\\n\\tYou have given an invalid bayesian network. \"\n                        << \"\\n\\tYou must finish filling out the conditional_probability_table of node \" << i\n                        << \"\\n\\tthis:              \" << this\n                    );\n            }\n#endif\n\n            impl.reset(new bayesian_network_join_tree_helpers::bnjt_impl<T,U>(bn, join_tree));\n            num_nodes = bn.number_of_nodes();\n        }\n\n        const matrix<double,1> probability(\n            unsigned long idx\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( idx < number_of_nodes() ,\n                        \"\\tconst matrix<double,1> bayesian_network_join_tree::probability(idx)\"\n                        << \"\\n\\tYou have specified an invalid node index\"\n                        << \"\\n\\tidx:               \" << idx \n                        << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                        << \"\\n\\tthis:              \" << this\n                    );\n\n            return impl->probability(idx);\n        }\n\n        unsigned long number_of_nodes (\n        ) const { return num_nodes; }\n\n        void swap (\n            bayesian_network_join_tree& item\n        )\n        {\n            exchange(num_nodes, item.num_nodes);\n            impl.swap(item.impl);\n        }\n\n    private:\n\n        std::unique_ptr<bayesian_network_join_tree_helpers::bnjt> impl;\n        unsigned long num_nodes;\n\n    };\n\n    inline void swap (\n        bayesian_network_join_tree& a,\n        bayesian_network_join_tree& b\n    ) { a.swap(b); }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_BAYES_UTILs_\n\n"
  },
  {
    "path": "dlib/bayes_utils/bayes_utils_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BAYES_UTILs_ABSTRACT_\n#ifdef DLIB_BAYES_UTILs_ABSTRACT_\n\n#include \"../algs.h\"\n#include \"../noncopyable.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../serialize.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class assignment : public enumerable<map_pair<unsigned long, unsigned long> >\n    {\n        /*!\n            INITIAL VALUE\n                - size() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the entries in the assignment in \n                ascending order according to index values.  (i.e. the elements are \n                enumerated in sorted order according to the value of their keys)\n\n            WHAT THIS OBJECT REPRESENTS\n                This object models an assignment of random variables to particular values.\n                It is used with the joint_probability_table and conditional_probability_table\n                objects to represent assignments of various random variables to actual values.\n\n                So for example, if you had a joint_probability_table that represented the\n                following table:\n                    P(A = 0, B = 0) = 0.2\n                    P(A = 0, B = 1) = 0.3\n                    P(A = 1, B = 0) = 0.1\n                    P(A = 1, B = 1) = 0.4\n\n                    Also lets define an enum so we have concrete index numbers for A and B\n                    enum { A = 0, B = 1};\n\n                Then you could query the value of P(A=1, B=0) as follows:\n                    assignment a;\n                    a.set(A, 1);\n                    a.set(B, 0);\n                    // and now it is the case that:\n                    table.probability(a) == 0.1 \n                    a[A] == 1\n                    a[B] == 0\n\n\n                Also note that when enumerating the elements of an assignment object\n                the key() refers to the index and the value() refers to the value at that\n                index. For example: \n\n                // assume a is an assignment object\n                a.reset();\n                while (a.move_next())\n                {\n                    // in this loop it is always the case that:\n                    // a[a.element().key()] == a.element().value()\n                }\n        !*/\n\n    public:\n\n        assignment(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        assignment(\n            const assignment& a\n        );\n        /*!\n            ensures\n                - #*this is a copy of a\n        !*/\n\n        assignment& operator = (\n            const assignment& rhs\n        );\n        /*!\n            ensures\n                - #*this is a copy of rhs\n                - returns *this\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - this object has been returned to its initial value\n        !*/\n\n        bool operator < (\n            const assignment& item\n        ) const;\n        /*!\n            ensures\n                - The exact functioning of this operator is undefined.  The only guarantee\n                  is that it establishes a total ordering on all possible assignment objects.\n                  In other words, this operator makes it so that you can use assignment\n                  objects in the associative containers but otherwise isn't of any \n                  particular use.\n        !*/\n\n        bool has_index (\n            unsigned long idx\n        ) const;\n        /*!\n            ensures\n                - if (this assignment object has an entry for index idx) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void add (\n            unsigned long idx,\n            unsigned long value = 0\n        );\n        /*!\n            requires\n                - has_index(idx) == false\n            ensures\n                - #has_index(idx) == true \n                - #(*this)[idx] == value \n        !*/\n\n        void remove (\n            unsigned long idx\n        );\n        /*!\n            requires\n                - has_index(idx) == true \n            ensures\n                - #has_index(idx) == false \n        !*/\n\n        unsigned long& operator[] (\n            const long idx\n        );\n        /*!\n            requires\n                - has_index(idx) == true\n            ensures\n                - returns a reference to the value associated with index idx\n        !*/\n\n        const unsigned long& operator[] (\n            const long idx\n        ) const;\n        /*!\n            requires\n                - has_index(idx) == true\n            ensures\n                - returns a const reference to the value associated with index idx\n        !*/\n\n        void swap (\n            assignment& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n    inline void swap (\n        assignment& a,\n        assignment& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n    std::ostream& operator << (\n        std::ostream& out,\n        const assignment& a\n    );\n    /*!\n        ensures\n            - writes a to the given output stream in the following format:\n              (index1:value1, index2:value2, ..., indexN:valueN)\n    !*/\n\n    void serialize (\n        const assignment& item,\n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        assignment& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ------------------------------------------------------------------------\n\n    class joint_probability_table : public enumerable<map_pair<assignment, double> >\n    {\n        /*!\n            INITIAL VALUE\n                - size() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the entries in the probability table \n                in no particular order but they will all be visited.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object models a joint probability table.  That is, it models\n                the function p(X).  So this object models the probability of a particular\n                set of variables (referred to as X).\n        !*/\n\n    public:\n\n        joint_probability_table(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        joint_probability_table (\n            const joint_probability_table& t\n        );\n        /*!\n            ensures\n                - this object is a copy of t\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - this object has its initial value\n        !*/\n\n        joint_probability_table& operator= (\n            const joint_probability_table& rhs\n        );\n        /*!\n            ensures\n                - this object is a copy of rhs\n                - returns a reference to *this\n        !*/\n\n        bool has_entry_for (\n            const assignment& a\n        ) const;\n        /*!\n            ensures\n                - if (this joint_probability_table has an entry for p(X = a)) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void set_probability (\n            const assignment& a,\n            double p\n        );\n        /*!\n            requires\n                - 0 <= p <= 1\n            ensures\n                - if (has_entry_for(a) == false) then\n                    - #size() == size() + 1\n                - #probability(a) == p\n                - #has_entry_for(a) == true\n        !*/\n\n        void add_probability (\n            const assignment& a,\n            double p\n        );\n        /*!\n            requires\n                - 0 <= p <= 1\n            ensures\n                - if (has_entry_for(a) == false) then\n                    - #size() == size() + 1\n                    - #probability(a) == p\n                - else\n                    - #probability(a) == min(probability(a) + p, 1.0)\n                      (i.e. does a saturating add)\n                - #has_entry_for(a) == true\n        !*/\n\n        const double probability (\n            const assignment& a\n        ) const;\n        /*!\n            ensures\n                - returns the probability p(X == a)\n        !*/\n\n        template <\n            typename T\n            >\n        void marginalize (\n            const T& vars,\n            joint_probability_table& output_table\n        ) const;\n        /*!\n            requires\n                - T is an implementation of set/set_kernel_abstract.h\n            ensures\n                - marginalizes *this by summing over all variables not in vars.  The\n                  result is stored in output_table.  \n        !*/\n\n        void marginalize (\n            const unsigned long var,\n            joint_probability_table& output_table\n        ) const;\n        /*!\n            ensures\n                - is identical to calling the above marginalize() function with a set\n                  that contains only var.  Or in other words, performs a marginalization\n                  with just one variable var.  So that output_table will contain a table giving\n                  the marginal probability of var all by itself.\n        !*/\n\n        void normalize (\n        );\n        /*!\n            ensures\n                - let sum == the sum of all the probabilities in this table\n                - after normalize() has finished it will be the case that the sum of all\n                  the entries in this table is 1.0.  This is accomplished by dividing all\n                  the entries by the sum described above.\n        !*/\n\n        void swap (\n            joint_probability_table& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n    inline void swap (\n        joint_probability_table& a,\n        joint_probability_table& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n    void serialize (\n        const joint_probability_table& item,\n        std::ostream& out \n    );   \n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        joint_probability_table& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class conditional_probability_table : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                - num_values() == 0\n                - has_value_for(x, y) == false for all values of x and y\n\n            WHAT THIS OBJECT REPRESENTS\n                This object models a conditional probability table.  That is, it models\n                the function p( X | parents).  So this object models the conditional \n                probability of a particular variable (referred to as X) given another set \n                of variables (referred to as parents).  \n        !*/\n\n    public:\n\n        conditional_probability_table(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - this object has its initial value\n        !*/\n\n        void empty_table (\n        );\n        /*!\n            ensures\n                - for all possible v and p:\n                    - #has_entry_for(v,p) == false\n                  (i.e. this function clears out the table when you call it but doesn't \n                  change the value of num_values())\n        !*/\n\n        void set_num_values (\n            unsigned long num\n        );\n        /*!\n            ensures\n                - #num_values() == num\n                - for all possible v and p:\n                    - #has_entry_for(v,p) == false\n                  (i.e. this function clears out the table when you call it)\n        !*/\n\n        unsigned long num_values (\n        ) const; \n        /*!\n            ensures\n                - This object models the probability table p(X | parents).  This\n                  function returns the number of values X can take on.\n        !*/\n\n        bool has_entry_for (\n            unsigned long value,\n            const assignment& ps\n        ) const;\n        /*!\n            ensures\n                - if (this conditional_probability_table has an entry for p(X = value, parents = ps)) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void set_probability (\n            unsigned long value,\n            const assignment& ps,\n            double p\n        );\n        /*!\n            requires\n                - value < num_values()\n                - 0 <= p <= 1\n            ensures\n                - #probability(ps, value) == p\n                - #has_entry_for(value, ps) == true\n        !*/\n\n        double probability(\n            unsigned long value,\n            const assignment& ps\n        ) const;\n        /*!\n            requires\n                - value < num_values()\n                - has_entry_for(value, ps) == true\n            ensures\n                - returns the probability p( X = value | parents = ps). \n        !*/\n\n        void swap (\n            conditional_probability_table& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n    };\n\n    inline void swap (\n        conditional_probability_table& a,\n        conditional_probability_table& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n    void serialize (\n        const conditional_probability_table& item,\n        std::ostream& out \n    );   \n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        conditional_probability_table& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ------------------------------------------------------------------------\n// ------------------------------------------------------------------------\n// ------------------------------------------------------------------------\n\n    class bayes_node : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                - is_evidence() == false\n                - value() == 0\n                - table().num_values() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a node in a bayesian network.  It is\n                intended to be used inside the dlib::directed_graph object to\n                represent bayesian networks.\n        !*/\n\n    public:\n        bayes_node (\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        unsigned long value (\n        ) const;\n        /*!\n            ensures\n                - returns the current value of this node\n        !*/\n\n        void set_value (\n            unsigned long new_value\n        );\n        /*!\n            requires\n                - new_value < table().num_values()\n            ensures\n                - #value() == new_value\n        !*/\n\n        conditional_probability_table& table (\n        );\n        /*!\n            ensures\n                - returns a reference to the conditional_probability_table associated with this node\n        !*/\n\n        const conditional_probability_table& table (\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the conditional_probability_table associated with this \n                  node.\n        !*/\n\n        bool is_evidence (\n        ) const;\n        /*!\n            ensures\n                - if (this is an evidence node) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void set_as_nonevidence (\n        );\n        /*!\n            ensures\n                - #is_evidence() == false\n        !*/\n\n        void set_as_evidence (\n        );\n        /*!\n            ensures\n                - #is_evidence() == true \n        !*/\n\n        void swap (\n            bayes_node& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n    inline void swap (\n        bayes_node& a,\n        bayes_node& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n    void serialize (\n        const bayes_node& item,\n        std::ostream& out \n    );   \n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        bayes_node& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    /*\n        The following group of functions are convenience functions for manipulating \n        bayes_node objects while they are inside a directed_graph.   These functions\n        also have additional requires clauses that, in debug mode, will protect you\n        from attempts to manipulate a bayesian network in an inappropriate way.\n    */\n\n    namespace bayes_node_utils\n    {\n\n        template <\n            typename T\n            >\n        void set_node_value (\n            T& bn,\n            unsigned long n,\n            unsigned long val\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n                - val < node_num_values(bn, n)\n            ensures\n                - #bn.node(n).data.value() = val\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        unsigned long node_value (\n            const T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - returns bn.node(n).data.value()\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        bool node_is_evidence (\n            const T& bn,\n            unsigned long n\n        ); \n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - returns bn.node(n).data.is_evidence()\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        void set_node_as_evidence (\n            T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - executes: bn.node(n).data.set_as_evidence()\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        void set_node_as_nonevidence (\n            T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - executes: bn.node(n).data.set_as_nonevidence()\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        void set_node_num_values (\n            T& bn,\n            unsigned long n,\n            unsigned long num\n        ); \n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - #bn.node(n).data.table().num_values() == num\n                  (i.e. sets the number of different values this node can take)\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        unsigned long node_num_values (\n            const T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - returns bn.node(n).data.table().num_values() \n                  (i.e. returns the number of different values this node can take)\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        const double node_probability (\n            const T& bn,\n            unsigned long n,\n            unsigned long value,\n            const assignment& parents \n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n                - value < node_num_values(bn,n)\n                - parents.size() == bn.node(n).number_of_parents()\n                - if (parents.has_index(x)) then\n                    - bn.has_edge(x, n)\n                    - parents[x] < node_num_values(bn,x)\n            ensures\n                - returns bn.node(n).data.table().probability(value, parents)\n                  (i.e. returns the probability of node n having the given value when\n                  its parents have the given assignment)\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        const double set_node_probability (\n            const T& bn,\n            unsigned long n,\n            unsigned long value,\n            const assignment& parents,\n            double p\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n                - value < node_num_values(bn,n)\n                - 0 <= p <= 1\n                - parents.size() == bn.node(n).number_of_parents()\n                - if (parents.has_index(x)) then\n                    - bn.has_edge(x, n)\n                    - parents[x] < node_num_values(bn,x)\n            ensures\n                - #bn.node(n).data.table().probability(value, parents) == p\n                  (i.e. sets the probability of node n having the given value when\n                  its parents have the given assignment to the probability p)\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        const assignment node_first_parent_assignment (\n            const T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - returns an assignment A such that:\n                    - A.size() == bn.node(n).number_of_parents()\n                    - if (P is a parent of bn.node(n)) then\n                        - A.has_index(P)\n                        - A[P] == 0\n                    - I.e. this function returns an assignment that contains all\n                      the parents of the given node.  Also, all the values of each\n                      parent in the assignment is set to zero.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool node_next_parent_assignment (\n            const T& bn,\n            unsigned long n,\n            assignment& A\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n                - A.size() == bn.node(n).number_of_parents()\n                - if (A.has_index(x)) then\n                    - bn.has_edge(x, n)\n                    - A[x] < node_num_values(bn,x)\n            ensures\n                - The behavior of this function is defined by the following code:\n                  assignment a(node_first_parent_assignment(bn,n);\n                  do {\n                    // this loop loops over all possible parent assignments\n                    // of the node bn.node(n).  Each time through the loop variable a\n                    // will be the next assignment.\n                  } while (node_next_parent_assignment(bn,n,a))\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool node_cpt_filled_out (\n            const T& bn,\n            unsigned long n\n        );\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n                - n < bn.number_of_nodes()\n            ensures\n                - if (the conditional_probability_table bn.node(n).data.table() is\n                  fully filled out for this node) then\n                    - returns true\n                    - This means that each parent assignment for the given node\n                      along with all possible values of this node shows up in the\n                      table.\n                    - It also means that all the probabilities conditioned on the\n                      same parent assignment sum to 1.0\n                - else\n                    - returns false\n        !*/\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class bayesian_network_gibbs_sampler : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                This object has no state\n\n            WHAT THIS OBJECT REPRESENTS\n                This object performs Markov Chain Monte Carlo sampling of a bayesian\n                network using the Gibbs sampling technique. \n\n                Note that this object is limited to only bayesian networks that \n                don't contain deterministic nodes.  That is, incorrect results may\n                be computed if this object is used when the bayesian network contains \n                any nodes that have a probability of 1 in their conditional probability\n                tables for any event.  So don't use this object for networks with \n                deterministic nodes.\n        !*/\n    public:\n\n        bayesian_network_gibbs_sampler (\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename T\n            >\n        void sample_graph (\n            T& bn\n        )\n        /*!\n            requires\n                - T is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - T::type == bayes_node\n            ensures\n                - modifies randomly (via the Gibbs sampling technique) samples all the nodes\n                  in the network and updates their values with the newly sampled values\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class bayesian_network_join_tree : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an implementation of the join tree algorithm\n                for inference in bayesian networks.  It doesn't have any mutable state.\n                To you use you just give it a directed_graph that contains a bayesian \n                network and a graph object that contains that networks corresponding\n                join tree.  Then you may query this object to determine the probabilities\n                of any variables in the original bayesian network.\n        !*/\n\n    public:\n\n        template <\n            typename bn_type,\n            typename join_tree_type \n            >\n        bayesian_network_join_tree (\n            const bn_type& bn,\n            const join_tree_type& join_tree\n        );\n        /*!\n            requires\n                - bn_type is an implementation of directed_graph/directed_graph_kernel_abstract.h\n                - bn_type::type == bayes_node\n                - join_tree_type is an implementation of graph/graph_kernel_abstract.h\n                - join_tree_type::type is an implementation of set/set_compare_abstract.h and\n                  this set type contains unsigned long objects. \n                - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and\n                  this set type contains unsigned long objects. \n                - is_join_tree(bn, join_tree) == true\n                - bn == a valid bayesian network with all its conditional probability tables\n                  filled out\n                - for all valid n:\n                    - node_cpt_filled_out(bn,n) == true\n                - graph_contains_length_one_cycle(bn) == false\n                - graph_is_connected(bn) == true\n                - bn.number_of_nodes() > 0\n            ensures\n                - this object is properly initialized\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the bayesian network that this\n                  object was instantiated from.\n        !*/\n\n        const matrix<double,1> probability(\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns the probability distribution for the node with index idx that was in the bayesian \n                  network that *this was instantiated from.  Let D represent this distribution, then:\n                    - D.nc() == the number of values the node idx ranges over\n                    - D.nr() == 1 \n                    - D(i) == the probability of node idx taking on the value i \n        !*/\n\n        void swap (\n            bayesian_network_join_tree& item\n        );\n        /*!\n            ensures\n                - swaps *this with item\n        !*/\n\n    };\n\n    inline void swap (\n        bayesian_network_join_tree& a,\n        bayesian_network_join_tree& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BAYES_UTILs_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/bayes_utils.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BAYES_UTILs_H_\n#define DLIB_BAYES_UTILs_H_ \n\n#include \"bayes_utils/bayes_utils.h\"\n\n#endif // DLIB_BAYES_UTILs_H_ \n\n\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINT_KERNEL_1_CPp_\n#define DLIB_BIGINT_KERNEL_1_CPp_\n#include \"bigint_kernel_1.h\"\n\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member/friend function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1::\n    bigint_kernel_1 (\n    ) :\n        slack(25),\n        data(new data_record(slack))\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1::\n    bigint_kernel_1 (\n        uint32 value\n    ) :\n        slack(25),\n        data(new data_record(slack))\n    {\n        *(data->number) = static_cast<uint16>(value&0xFFFF);\n        *(data->number+1) = static_cast<uint16>((value>>16)&0xFFFF);\n        if (*(data->number+1) != 0)\n            data->digits_used = 2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1::\n    bigint_kernel_1 (\n        const bigint_kernel_1& item\n    ) :\n        slack(25),\n        data(item.data)\n    {\n        data->references += 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1::\n    ~bigint_kernel_1 (\n    )\n    {\n        if (data->references == 1)\n        {\n            delete data;\n        }\n        else\n        {\n            data->references -= 1;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator+ (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    std::max(rhs.data->digits_used,data->digits_used) + slack\n                    );\n        long_add(data,rhs.data,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator+= (\n        const bigint_kernel_1& rhs\n    )\n    {\n        // if there are other references to our data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);\n            data->references -= 1;   \n            long_add(data,rhs.data,temp);\n            data = temp;\n        }\n        // if data is not big enough for the result\n        else if (data->size <= std::max(data->digits_used,rhs.data->digits_used))\n        {\n            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);\n            long_add(data,rhs.data,temp);\n            delete data;\n            data = temp;\n        }\n        // there is enough size and no references\n        else\n        {\n            long_add(data,rhs.data,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator- (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    data->digits_used + slack\n                    );\n        long_sub(data,rhs.data,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator-= (\n        const bigint_kernel_1& rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            long_sub(data,rhs.data,temp);\n            data = temp;\n        }\n        else\n        {\n            long_sub(data,rhs.data,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator* (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    data->digits_used + rhs.data->digits_used + slack\n                    );\n        long_mul(data,rhs.data,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator*= (\n        const bigint_kernel_1& rhs\n    )\n    {\n        // create a data_record to store the result of the multiplication in\n        data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack);        \n        long_mul(data,rhs.data,temp);\n\n        // if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        else\n        {\n            delete data;\n        }\n        data = temp;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator/ (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);           \n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n        delete remainder;\n    \n\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator/= (\n        const bigint_kernel_1& rhs\n    )\n    {\n\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }    \n\n        long_div(data,rhs.data,temp,remainder);\n\n        // check if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        // if there are no references to data then it must be deleted\n        else\n        {\n            delete data;\n        }\n        data = temp;\n        delete remainder;\n\n        \n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator% (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n        delete temp;\n        return bigint_kernel_1(remainder,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator%= (\n        const bigint_kernel_1& rhs\n    )\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n\n        // check if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        // if there are no references to data then it must be deleted\n        else\n        {\n            delete data;\n        }\n        data = remainder;\n        delete temp;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_1::\n    operator < (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        return is_less_than(data,rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_1::\n    operator == (\n        const bigint_kernel_1& rhs\n    ) const\n    {\n        return is_equal_to(data,rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator= (\n        const bigint_kernel_1& rhs\n    )\n    {\n        if (this == &rhs)\n            return *this;\n\n        // if we have the only reference to our data then delete it\n        if (data->references == 1)\n        {\n            delete data;\n            data = rhs.data;\n            data->references += 1;\n        }\n        else\n        {\n            data->references -= 1;\n            data = rhs.data;\n            data->references += 1;\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& operator<< (\n        std::ostream& out_,\n        const bigint_kernel_1& rhs\n    )\n    {\n        std::ostream out(out_.rdbuf());\n\n        typedef bigint_kernel_1 bigint;\n        \n        bigint::data_record* temp = new bigint::data_record(*rhs.data,0);\n\n\n\n        // get a char array big enough to hold the number in ascii format\n        char* str;\n        try {\n            str = new char[(rhs.data->digits_used)*5+10];\n        } catch (...) { delete temp; throw; }\n\n        char* str_start = str;\n        str += (rhs.data->digits_used)*5+9;\n        *str = 0; --str;\n\n\n        uint16 remainder;\n        rhs.short_div(temp,10000,temp,remainder);\n\n        // pull the digits out of remainder\n        char a = remainder % 10 + '0';\n        remainder /= 10;\n        char b = remainder % 10 + '0';\n        remainder /= 10;\n        char c = remainder % 10 + '0';\n        remainder /= 10;\n        char d = remainder % 10 + '0';\n        remainder /= 10;\n\n\n        *str = a; --str;\n        *str = b; --str;\n        *str = c; --str;\n        *str = d; --str;\n\n\n        // keep looping until temp represents zero\n        while (temp->digits_used != 1 || *(temp->number) != 0)\n        {            \n            rhs.short_div(temp,10000,temp,remainder);\n\n            // pull the digits out of remainder\n            char a = remainder % 10 + '0';\n            remainder /= 10;\n            char b = remainder % 10 + '0';\n            remainder /= 10;\n            char c = remainder % 10 + '0';\n            remainder /= 10;\n            char d = remainder % 10 + '0';\n            remainder /= 10;\n\n            *str = a; --str;\n            *str = b; --str;\n            *str = c; --str;\n            *str = d; --str;              \n        }\n\n        // throw away and extra leading zeros\n        ++str;\n        if (*str == '0')\n            ++str;\n        if (*str == '0')\n            ++str;\n        if (*str == '0')\n            ++str;\n\n\n        \n\n        out << str;\n        delete [] str_start;\n        delete temp;\n        return out_;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::istream& operator>> (\n        std::istream& in_,\n        bigint_kernel_1& rhs\n    )\n    {\n        std::istream in(in_.rdbuf());\n\n        // ignore any leading whitespaces\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\n')\n        {\n            in.get();\n        }\n\n        // if the first digit is not an integer then this is an error\n        if ( !(in.peek() >= '0' && in.peek() <= '9'))\n        {\n            in_.clear(std::ios::failbit);\n            return in_;\n        }\n\n        int num_read;\n        bigint_kernel_1 temp;\n        do\n        {\n\n            // try to get 4 chars from in\n            num_read = 1;\n            char a = 0;\n            char b = 0; \n            char c = 0;\n            char d = 0;\n\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                a = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                b = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                c = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                d = in.get();\n            }\n            \n            // merge the for digits into an uint16\n            uint16 num = 0;\n            if (a != 0)\n            {\n                num = a - '0';\n            }\n            if (b != 0)\n            {\n                num *= 10;\n                num += b - '0';\n            }\n            if (c != 0)\n            {\n                num *= 10;\n                num += c - '0';\n            }\n            if (d != 0)\n            {\n                num *= 10;\n                num += d - '0';\n            }\n\n\n            if (num_read != 1)\n            {\n                // shift the digits in temp left by the number of new digits we just read\n                temp *= num_read;\n                // add in new digits\n                temp += num;\n            }\n\n        } while (num_read == 10000);\n\n\n        rhs = temp;\n        return in_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator+ (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (rhs.data->digits_used+rhs.slack);\n\n        rhs.short_add(rhs.data,lhs,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator+ (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_add(lhs.data,rhs,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator+= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;    \n            short_add(data,rhs,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data then do so\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            short_add(data,rhs,temp);\n            delete data;\n            data = temp;\n        }\n        // or if there is plenty of space and no references\n        else\n        {\n            short_add(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator- (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        *(temp->number) = lhs - *(rhs.data->number);\n\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator- (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_sub(lhs.data,rhs,temp);\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator-= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_sub(data,rhs,temp);\n            data = temp;\n        }\n        else\n        {\n            short_sub(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator* (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (rhs.data->digits_used+rhs.slack);\n\n        rhs.short_mul(rhs.data,lhs,temp);\n        return bigint_kernel_1(temp,0);        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator* (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_mul(lhs.data,rhs,temp);\n        return bigint_kernel_1(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator*= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_mul(data,rhs,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            short_mul(data,rhs,temp);\n            delete data;\n            data = temp;\n        }\n        else\n        {\n            short_mul(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator/ (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        // if rhs might not be bigger than lhs\n        if (rhs.data->digits_used == 1)\n        {\n            *(temp->number) = lhs/ *(rhs.data->number);\n        }\n        \n        return bigint_kernel_1(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator/ (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        uint16 remainder;\n        lhs.short_div(lhs.data,rhs,temp,remainder);\n        return bigint_kernel_1(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator/= (\n        uint16 rhs\n    )\n    {\n        uint16 remainder;\n        // if there are other references to this data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_div(data,rhs,temp,remainder);    \n            data = temp;\n        }\n        else\n        {\n            short_div(data,rhs,data,remainder);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator% (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        // temp is zero by default\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        if (rhs.data->digits_used == 1)\n        {\n            // if rhs is just an uint16 inside then perform the modulus\n            *(temp->number) = lhs % *(rhs.data->number);\n        }\n        else\n        {\n            // if rhs is bigger than lhs then the answer is lhs\n            *(temp->number) = lhs;\n        }\n        \n        return bigint_kernel_1(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 operator% (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_1 bigint;\n        bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack);\n\n        uint16 remainder;\n\n        lhs.short_div(lhs.data,rhs,temp,remainder);\n        temp->digits_used = 1;\n        *(temp->number) = remainder;\n        return bigint_kernel_1(temp,0);          \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator%= (\n        uint16 rhs\n    )\n    {\n        uint16 remainder;\n        // if there are other references to this data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_div(data,rhs,temp,remainder);\n            data = temp;\n        }\n        else\n        {\n            short_div(data,rhs,data,remainder);\n        }\n\n        data->digits_used = 1;\n        *(data->number) = remainder;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator < (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator < (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator == (\n        const bigint_kernel_1& lhs,\n        uint16 rhs\n    )\n    {\n        return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator == (\n        uint16 lhs,\n        const bigint_kernel_1& rhs\n    )\n    {\n        return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator= (\n        uint16 rhs\n    )\n    {\n        // check if there are other references to our data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n            try {\n                data = new data_record(slack);\n            } catch (...) { data->references += 1; throw; }\n        }\n        else\n        {\n            data->digits_used = 1;\n        }\n        \n        *(data->number) = rhs;\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator++ (\n    )\n    {\n        // if there are other references to this data then make a copy of it\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            increment(data,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data then do so\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            increment(data,temp);\n            delete data;\n            data = temp;\n        }\n        else\n        {\n            increment(data,data);\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator++ (\n        int\n    )\n    {\n        data_record* temp; // this is the copy of temp we will return in the end\n         \n        data_record* temp2 = new data_record(data->digits_used+slack);\n        increment(data,temp2);\n        \n        temp = data;\n        data = temp2;\n\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_1& bigint_kernel_1::\n    operator-- (\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            decrement(data,temp);\n            data = temp;\n        }\n        else\n        {\n            decrement(data,data);\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_1 bigint_kernel_1::\n    operator-- (\n        int\n    )\n    {\n        data_record* temp; // this is the copy of temp we will return in the end\n         \n        data_record* temp2 = new data_record(data->digits_used+slack);\n        decrement(data,temp2);\n        \n        temp = data;\n        data = temp2;\n\n        return bigint_kernel_1(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    short_add (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        // put value into the carry part of temp\n        uint32 temp = value;\n        temp <<= 16;\n\n        \n        const uint16* number = data->number;\n        const uint16* end = number + data->digits_used; // one past the end of number\n        uint16* r = result->number;\n\n        while (number != end)\n        {\n            // add *number and the current carry\n            temp = *number + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number;\n            ++r;\n        }\n\n        // if there is a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = data->digits_used + 1;\n            // store the carry in the most significant digit of the result\n            *r = static_cast<uint16>(temp>>16); \n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    short_sub (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        \n\n        const uint16* number = data->number;\n        const uint16* end = number + data->digits_used - 1;\n        uint16* r = result->number;\n\n        uint32 temp = *number - value;\n\n        // put the low word of temp into *data \n        *r = static_cast<uint16>(temp & 0xFFFF);\n\n        \n        while (number != end)\n        {\n            ++number;\n            ++r;\n\n            // subtract the carry from *number \n            temp = *number - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n        }\n\n        // if we lost a digit in the subtraction\n        if (*r == 0)\n        {\n            if (data->digits_used == 1)\n                result->digits_used = 1;\n            else\n                result->digits_used = data->digits_used - 1;\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    short_mul (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        \n        uint32 temp = 0;\n\n\n        const uint16* number = data->number;        \n        uint16* r = result->number;\n        const uint16* end = r + data->digits_used;\n\n\n\n        while ( r != end)\n        {\n\n            // multiply *data and value and add in the carry\n            temp = *number*(uint32)value + (temp>>16);\n\n            // put the low word of temp into *data\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number;\n            ++r;\n        }\n\n        // if there is a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = data->digits_used + 1;\n            // put the final carry into the most significant digit of the result\n            *r = static_cast<uint16>(temp>>16);\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    short_div (\n        const data_record* data,        \n        uint16 value,   \n        data_record* result,\n        uint16& rem\n    ) const\n    {\n        \n        uint16 remainder = 0;\n        uint32 temp;\n\n        \n\n        const uint16* number = data->number + data->digits_used - 1;\n        const uint16* end = number - data->digits_used;\n        uint16* r = result->number + data->digits_used - 1;\n\n\n        // if we are losing a digit in this division\n        if (*number < value)\n        {\n            if (data->digits_used == 1)\n                result->digits_used = 1;\n            else\n                result->digits_used = data->digits_used - 1;\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n        // perform the actual division\n        while (number != end)\n        {\n           \n            temp = *number + (((uint32)remainder)<<16);\n\n            *r = static_cast<uint16>(temp/value);\n            remainder = static_cast<uint16>(temp%value);\n\n            --number;\n            --r;\n        }\n\n        rem = remainder;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    long_add (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n        // put value into the carry part of temp\n        uint32 temp=0;        \n\n        uint16* min_num;  // the number with the least digits used\n        uint16* max_num;  // the number with the most digits used\n        uint16* min_end;  // one past the end of min_num\n        uint16* max_end;  // one past the end of max_num\n        uint16* r = result->number;\n\n        uint32 max_digits_used;\n        if (lhs->digits_used < rhs->digits_used)\n        {\n            max_digits_used = rhs->digits_used;\n            min_num = lhs->number;\n            max_num = rhs->number;\n            min_end = min_num + lhs->digits_used;\n            max_end = max_num + rhs->digits_used;\n        }\n        else\n        {\n            max_digits_used = lhs->digits_used;\n            min_num = rhs->number;\n            max_num = lhs->number;\n            min_end = min_num + rhs->digits_used;\n            max_end = max_num + lhs->digits_used;\n        }\n\n        \n\n\n        while (min_num != min_end)\n        {\n            // add *min_num, *max_num and the current carry\n            temp = *min_num + *max_num + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++min_num;\n            ++max_num;\n            ++r;\n        }\n\n\n        while (max_num != max_end)\n        {\n            // add *max_num and the current carry\n            temp = *max_num + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++max_num;\n            ++r;\n        }        \n\n        // check if there was a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = max_digits_used + 1;\n            // put the carry into the most significant digit in the result\n            *r = static_cast<uint16>(temp>>16);\n        }\n        else\n        {\n            result->digits_used = max_digits_used;\n        }\n\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    long_sub (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n\n\n        const uint16* number1 = lhs->number;\n        const uint16* number2 = rhs->number;\n        const uint16* end = number2 + rhs->digits_used;\n        uint16* r = result->number;\n\n\n\n        uint32 temp =0;\n\n        \n        while (number2 != end)\n        {\n\n            // subtract *number2 from *number1 and then subtract any carry\n            temp = *number1 - *number2 - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number1;\n            ++number2;\n            ++r;\n        }\n\n        end = lhs->number + lhs->digits_used;\n        while (number1 != end)\n        {\n\n            // subtract the carry from *number1 \n            temp = *number1 - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number1;\n            ++r;\n        }\n\n        result->digits_used = lhs->digits_used;\n        // adjust the number of digits used appropriately \n        --r;\n        while (*r == 0 && result->digits_used > 1)\n        {\n            --r;\n            --result->digits_used;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    long_div (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result,\n        data_record* remainder\n    ) const\n    {\n        // zero result\n        result->digits_used = 1;\n        *(result->number) = 0;\n\n        uint16* a;\n        uint16* b;\n        uint16* end;\n\n        // copy lhs into remainder\n        remainder->digits_used = lhs->digits_used;\n        a = remainder->number;\n        end = a + remainder->digits_used;\n        b = lhs->number;\n        while (a != end)\n        {\n            *a = *b;\n            ++a;\n            ++b;\n        }\n\n\n        // if rhs is bigger than lhs then result == 0 and remainder == lhs\n        // so then we can quit right now\n        if (is_less_than(lhs,rhs))\n        {\n            return;            \n        }\n\n\n        // make a temporary number\n        data_record temp(lhs->digits_used + slack);\n\n\n        // shift rhs left until it is one shift away from being larger than lhs and\n        // put the number of left shifts necessary into shifts\n        uint32 shifts; \n        shifts = (lhs->digits_used - rhs->digits_used) * 16;\n\n        shift_left(rhs,&temp,shifts);\n\n\n        // while (lhs > temp)\n        while (is_less_than(&temp,lhs))\n        {\n            shift_left(&temp,&temp,1);\n            ++shifts;\n        }\n        // make sure lhs isn't smaller than temp\n        while (is_less_than(lhs,&temp))\n        {\n            shift_right(&temp,&temp);\n            --shifts;\n        }\n\n        \n        \n        // we want to execute the loop shifts +1 times\n        ++shifts;\n        while (shifts != 0)\n        {\n            shift_left(result,result,1);\n            // if (temp <= remainder)\n            if (!is_less_than(remainder,&temp))\n            {\n                long_sub(remainder,&temp,remainder);\n                \n                // increment result\n                uint16* r = result->number;\n                uint16* end = r + result->digits_used;\n                while (true)\n                {\n                    ++(*r);\n                    // if there was no carry then we are done\n                    if (*r != 0)\n                        break;\n\n                    ++r;\n\n                    // if we hit the end of r and there is still a carry then\n                    // the next digit of r is 1 and there is one more digit used\n                    if (r == end)\n                    {\n                        *r = 1;\n                        ++(result->digits_used);\n                        break;\n                    }\n                }\n            }\n            shift_right(&temp,&temp);\n            --shifts;\n        }\n        \n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    long_mul (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n        // make result be zero\n        result->digits_used = 1;\n        *(result->number) = 0;\n        \n\n        const data_record* aa;\n        const data_record* bb;\n\n        if (lhs->digits_used < rhs->digits_used)\n        {\n            // make copies of lhs and rhs and give them an appropriate amount of\n            // extra memory so there won't be any overflows\n            aa = lhs;\n            bb = rhs;\n        }\n        else\n        {\n            // make copies of lhs and rhs and give them an appropriate amount of\n            // extra memory so there won't be any overflows\n            aa = rhs;\n            bb = lhs;\n        }\n        // this is where we actually copy lhs and rhs\n        data_record b(*bb,aa->digits_used+slack); // the larger(approximately) of lhs and rhs\n\n\n        uint32 shift_value = 0;\n        uint16* anum = aa->number;\n        uint16* end = anum + aa->digits_used;\n        while (anum != end )\n        {\n            uint16 bit = 0x0001;\n \n            for (int i = 0; i < 16; ++i)\n            {\n                // if the specified bit of a is 1\n                if ((*anum & bit) != 0)\n                {\n                    shift_left(&b,&b,shift_value);\n                    shift_value = 0;\n                    long_add(&b,result,result);\n                }\n                ++shift_value;\n                bit <<= 1;\n            }\n\n            ++anum;                        \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    shift_left (\n        const data_record* data,\n        data_record* result,\n        uint32 shift_amount\n    ) const\n    {\n        uint32 offset = shift_amount/16;\n        shift_amount &= 0xf;  // same as shift_amount %= 16;\n\n        uint16* r = result->number + data->digits_used + offset; // result\n        uint16* end = data->number;\n        uint16* s = end + data->digits_used; // source\n        const uint32 temp = 16 - shift_amount;\n\n        *r = (*(--s) >> temp);\n        // set the number of digits used in the result\n        // if the upper bits from *s were zero then don't count this first word\n        if (*r == 0)\n        {\n            result->digits_used = data->digits_used + offset;\n        }\n        else\n        {\n            result->digits_used = data->digits_used + offset + 1;\n        }\n        --r;\n\n        while (s != end)\n        {\n            *r = ((*s << shift_amount) | ( *(s-1) >> temp));\n            --r;\n            --s;\n        }\n        *r = *s << shift_amount;\n\n        // now zero the rest of the result\n        end = result->number;\n        while (r != end)\n            *(--r) = 0;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    shift_right (\n        const data_record* data,\n        data_record* result\n    ) const\n    {\n\n            uint16* r = result->number; // result\n            uint16* s = data->number; // source\n            uint16* end = s + data->digits_used - 1;\n\n            while (s != end)\n            {\n                *r = (*s >> 1) | (*(s+1) << 15);\n                ++r;\n                ++s;\n            }\n            *r = *s >> 1;\n\n\n            // calculate the new number for digits_used\n            if (*r == 0)\n            {\n                if (data->digits_used != 1)\n                    result->digits_used = data->digits_used - 1;\n                else\n                    result->digits_used = 1;\n            }\n            else\n            {\n                result->digits_used = data->digits_used;\n            }\n  \n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_1::\n    is_less_than (\n        const data_record* lhs,\n        const data_record* rhs\n    ) const\n    {\n        uint32 lhs_digits_used = lhs->digits_used;\n        uint32 rhs_digits_used = rhs->digits_used;\n\n        // if lhs is definitely less than rhs\n        if (lhs_digits_used < rhs_digits_used )\n            return true;\n        // if lhs is definitely greater than rhs\n        else if (lhs_digits_used > rhs_digits_used)\n            return false;\n        else \n        {\n            uint16* end = lhs->number;\n            uint16* l = end         + lhs_digits_used;\n            uint16* r = rhs->number + rhs_digits_used;\n            \n            while (l != end)\n            {\n                --l;\n                --r;\n                if (*l < *r)\n                    return true;\n                else if (*l > *r)\n                    return false;\n            }\n\n            // at this point we know that they are equal\n            return false;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_1::\n    is_equal_to (\n        const data_record* lhs,\n        const data_record* rhs\n    ) const\n    {\n        // if lhs and rhs are definitely not equal\n        if (lhs->digits_used != rhs->digits_used )\n        {\n            return false;\n        }\n        else \n        {            \n            uint16* l = lhs->number;\n            uint16* r = rhs->number;\n            uint16* end = l + lhs->digits_used;\n            \n            while (l != end)\n            {\n                if (*l != *r)\n                    return false;\n                ++l;\n                ++r;\n            }\n\n            // at this point we know that they are equal\n            return true;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    increment (\n        const data_record* source,\n        data_record* dest\n    ) const\n    {\n        uint16* s = source->number;\n        uint16* d = dest->number;\n        uint16* end = s + source->digits_used;\n        while (true)\n        {\n            *d = *s + 1;\n\n            // if there was no carry then break out of the loop\n            if (*d != 0)\n            {\n                dest->digits_used = source->digits_used;\n\n                // copy the rest of the digits over to d\n                ++d; ++s;\n                while (s != end)\n                {\n                    *d = *s;\n                    ++d;\n                    ++s;\n                }\n\n                break;\n            }\n            \n\n            ++s;            \n\n            // if we have hit the end of s and there was a carry up to this point\n            // then just make the next digit 1 and add one to the digits used\n            if (s == end)\n            {\n                ++d;\n                dest->digits_used = source->digits_used + 1;\n                *d = 1;\n                break;\n            }\n\n            ++d;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_1::\n    decrement (\n        const data_record* source,\n        data_record* dest\n    ) const\n    {\n        uint16* s = source->number;\n        uint16* d = dest->number;\n        uint16* end = s + source->digits_used;\n        while (true)\n        {\n            *d = *s - 1;\n\n            // if there was no carry then break out of the loop\n            if (*d != 0xFFFF)\n            {\n                // if we lost a digit in the subtraction \n                if (*d == 0 && s+1 == end)\n                {\n                    if (source->digits_used == 1)\n                        dest->digits_used = 1;\n                    else\n                        dest->digits_used = source->digits_used - 1;\n                }\n                else\n                {\n                    dest->digits_used = source->digits_used;\n                }\n                break;\n            }\n            else\n            {\n                ++d;\n                ++s;\n            }\n\n        }\n\n        // copy the rest of the digits over to d\n        ++d;\n        ++s;\n        while (s != end)\n        {\n            *d = *s;\n            ++d;\n            ++s;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_BIGINT_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINT_KERNEl_1_\n#define DLIB_BIGINT_KERNEl_1_\n\n#include \"bigint_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../uintn.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n    \n\n    class bigint_kernel_1 \n    {\n        /*!\n            INITIAL VALUE\n                slack               == 25\n                data->number[0]     == 0 \n                data->size          == slack \n                data->references    == 1 \n                data->digits_used   == 1\n                \n\n            CONVENTION\n                slack  == the number of extra digits placed into the number when it is \n                    created.  the slack value should never be less than 1\n\n                data->number == pointer to an array of data->size uint16s.\n                    data represents a string of base 65535 numbers with data[0] being\n                    the least significant bit and data[data->digits_used-1] being the most \n                    significant\n\n\n                NOTE: In the comments I will consider a word to be a 16 bit value\n\n\n                data->digits_used == the number of significant digits in the number.\n                    data->digits_used tells us the number of used elements in the \n                    data->number array so everything beyond data->number[data->digits_used-1] \n                    is undefined\n\n                data->references == the number of bigint_kernel_1 objects which refer\n                    to this data_record\n\n\n\n        !*/\n\n\n        struct data_record\n        {\n\n\n            explicit data_record(\n                uint32 size_\n            ) : \n                size(size_),\n                number(new uint16[size_]),\n                references(1),\n                digits_used(1)\n            {*number = 0;}\n            /*!\n                ensures\n                    - initializes *this to represent zero\n            !*/\n\n            data_record(\n                const data_record& item,\n                uint32 additional_size\n            ) :\n                size(item.digits_used + additional_size),\n                number(new uint16[size]),\n                references(1),\n                digits_used(item.digits_used)\n            {\n                uint16* source = item.number;\n                uint16* dest = number;\n                uint16* end = source + digits_used;\n                while (source != end)\n                {\n                    *dest = *source;\n                    ++dest;\n                    ++source;\n                }\n            }\n            /*!\n                ensures\n                    - *this is a copy of item except with \n                      size == item.digits_used + additional_size\n            !*/\n\n            ~data_record(\n            )\n            {\n                delete [] number;\n            }\n\n\n            const uint32 size;\n            uint16* number;\n            uint32 references;            \n            uint32 digits_used;\n\n        private:\n            // no copy constructor\n            data_record ( data_record&);\n        };\n\n\n\n        // note that the second parameter is just there \n        // to resolve the ambiguity between this constructor and \n        // bigint_kernel_1(uint32)\n        explicit bigint_kernel_1 (\n            data_record* data_, int\n        ): slack(25),data(data_) {}\n        /*!\n            ensures\n                - *this is initialized with data_ as its data member\n        !*/\n\n\n    public:\n\n        bigint_kernel_1 (\n        );\n\n        bigint_kernel_1 (\n            uint32 value\n        );\n\n        bigint_kernel_1 (\n            const bigint_kernel_1& item\n        );\n\n        virtual ~bigint_kernel_1 (\n        );\n\n        const bigint_kernel_1 operator+ (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator+= (\n            const bigint_kernel_1& rhs\n        );\n\n        const bigint_kernel_1 operator- (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator-= (\n            const bigint_kernel_1& rhs\n        );\n\n        const bigint_kernel_1 operator* (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator*= (\n            const bigint_kernel_1& rhs\n        );\n\n        const bigint_kernel_1 operator/ (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator/= (\n            const bigint_kernel_1& rhs\n        );\n\n        const bigint_kernel_1 operator% (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator%= (\n            const bigint_kernel_1& rhs\n        );\n\n        bool operator < (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bool operator == (\n            const bigint_kernel_1& rhs\n        ) const;\n\n        bigint_kernel_1& operator= (\n            const bigint_kernel_1& rhs\n        );\n\n        friend std::ostream& operator<< (\n            std::ostream& out,\n            const bigint_kernel_1& rhs\n        );\n\n        friend std::istream& operator>> (\n            std::istream& in,\n            bigint_kernel_1& rhs\n        );\n\n        bigint_kernel_1& operator++ (\n        );\n\n        const bigint_kernel_1 operator++ (\n            int\n        );\n\n        bigint_kernel_1& operator-- (\n        );\n\n        const bigint_kernel_1 operator-- (\n            int\n        );\n\n        friend const bigint_kernel_1 operator+ (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend const bigint_kernel_1 operator+ (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_1& operator+= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_1 operator- (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend const bigint_kernel_1 operator- (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_1& operator-= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_1 operator* (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend const bigint_kernel_1 operator* (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_1& operator*= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_1 operator/ (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend const bigint_kernel_1 operator/ (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_1& operator/= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_1 operator% (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend const bigint_kernel_1 operator% (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_1& operator%= (\n            uint16 rhs\n        );\n\n        friend bool operator < (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        friend bool operator < (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        friend bool operator == (\n            const bigint_kernel_1& lhs,\n            uint16 rhs\n        );\n\n        friend bool operator == (\n            uint16 lhs,\n            const bigint_kernel_1& rhs\n        );\n\n        bigint_kernel_1& operator= (\n            uint16 rhs\n        );\n\n\n        void swap (\n            bigint_kernel_1& item\n        ) { data_record* temp = data; data = item.data; item.data = temp; }\n\n\n    private:\n\n        void long_add (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= max(lhs->digits_used,rhs->digits_used) + 1\n            ensures\n                - result == lhs + rhs\n        !*/\n\n        void long_sub (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - lhs >= rhs \n                - result->size >= lhs->digits_used\n            ensures\n                - result == lhs - rhs\n        !*/\n\n        void long_div (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result,\n            data_record* remainder\n        ) const;\n        /*!\n            requires \n                - rhs != 0 \n                - result->size >= lhs->digits_used \n                - remainder->size >= lhs->digits_used \n                - each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)\n            ensures\n                - result == lhs / rhs\n                - remainder == lhs % rhs\n        !*/\n\n        void long_mul (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= lhs->digits_used + rhs->digits_used \n                - result != lhs \n                - result != rhs\n            ensures\n                - result == lhs * rhs\n        !*/\n\n        void short_add (\n            const data_record* data,\n            uint16 value,\n            data_record* result            \n        ) const;\n        /*!\n            requires\n                - result->size >= data->size + 1\n            ensures\n                - result == data + value\n        !*/\n\n        void short_sub (\n            const data_record* data,\n            uint16 value,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - data >= value \n                - result->size >= data->digits_used\n            ensures\n                - result == data - value\n        !*/\n\n        void short_mul (\n            const data_record* data,\n            uint16 value,\n            data_record* result            \n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used + 1\n            ensures\n                - result == data * value\n        !*/\n\n        void short_div (\n            const data_record* data,            \n            uint16 value,\n            data_record* result,\n            uint16& remainder\n        ) const;\n        /*!\n            requires\n                - value != 0 \n                - result->size >= data->digits_used\n            ensures\n                - result = data*value \n                - remainder = data%value\n        !*/\n\n        void shift_left (\n            const data_record* data,\n            data_record* result,\n            uint32 shift_amount\n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used + shift_amount/8 + 1\n            ensures\n                - result == data << shift_amount\n        !*/\n\n        void shift_right (\n            const data_record* data,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used \n            ensures\n                - result == data >> 1\n        !*/\n\n        bool is_less_than (\n            const data_record* lhs,\n            const data_record* rhs\n        ) const;\n        /*! \n            ensures\n                - returns true if lhs < rhs \n                - returns false otherwise\n        !*/ \n\n        bool is_equal_to (\n            const data_record* lhs,\n            const data_record* rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if lhs == rhs \n                - returns false otherwise\n        !*/\n\n        void increment (\n            const data_record* source,\n            data_record* dest\n        ) const;\n        /*!\n            requires\n                - dest->size >= source->digits_used + 1\n            ensures\n                - dest = source + 1\n        !*/\n\n        void decrement (\n            const data_record* source,\n            data_record* dest\n        ) const;\n        /*!\n            requires\n                source != 0\n            ensuers\n                dest = source - 1\n        !*/\n\n        // member data\n        const uint32 slack;\n        data_record* data;     \n        \n        \n\n    };\n\n    inline void swap (\n        bigint_kernel_1& a,\n        bigint_kernel_1& b\n    ) { a.swap(b); }\n\n    inline void serialize (\n        const bigint_kernel_1& item, \n        std::ostream& out\n    )\n    { \n        std::ios::fmtflags oldflags = out.flags();  \n        out << item << ' '; \n        out.flags(oldflags); \n        if (!out) throw serialization_error(\"Error serializing object of type bigint_kernel_c\"); \n    }   \n\n    inline void deserialize (\n        bigint_kernel_1& item, \n        std::istream& in\n    ) \n    { \n        std::ios::fmtflags oldflags = in.flags();  \n        in >> item;\n        in.flags(oldflags); \n        if (in.get() != ' ')\n        {\n            item = 0;\n            throw serialization_error(\"Error deserializing object of type bigint_kernel_c\"); \n        }\n    }   \n\n    inline bool operator>  (const bigint_kernel_1& a, const bigint_kernel_1& b) { return b < a; } \n    inline bool operator!= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a == b); }\n    inline bool operator<= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(b < a); }\n    inline bool operator>= (const bigint_kernel_1& a, const bigint_kernel_1& b) { return !(a < b); }\n}\n\n#ifdef NO_MAKEFILE\n#include \"bigint_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_BIGINT_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_2.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINT_KERNEL_2_CPp_\n#define DLIB_BIGINT_KERNEL_2_CPp_\n#include \"bigint_kernel_2.h\"\n\n#include <iostream>\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member/friend function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2::\n    bigint_kernel_2 (\n    ) :\n        slack(25),\n        data(new data_record(slack))\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2::\n    bigint_kernel_2 (\n        uint32 value\n    ) :\n        slack(25),\n        data(new data_record(slack))\n    {\n        *(data->number) = static_cast<uint16>(value&0xFFFF);\n        *(data->number+1) = static_cast<uint16>((value>>16)&0xFFFF);\n        if (*(data->number+1) != 0)\n            data->digits_used = 2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2::\n    bigint_kernel_2 (\n        const bigint_kernel_2& item\n    ) :\n        slack(25),\n        data(item.data)\n    {\n        data->references += 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2::\n    ~bigint_kernel_2 (\n    )\n    {\n        if (data->references == 1)\n        {\n            delete data;\n        }\n        else\n        {\n            data->references -= 1;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator+ (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    std::max(rhs.data->digits_used,data->digits_used) + slack\n                    );\n        long_add(data,rhs.data,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator+= (\n        const bigint_kernel_2& rhs\n    )\n    {\n        // if there are other references to our data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);\n            data->references -= 1;   \n            long_add(data,rhs.data,temp);\n            data = temp;\n        }\n        // if data is not big enough for the result\n        else if (data->size <= std::max(data->digits_used,rhs.data->digits_used))\n        {\n            data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack);\n            long_add(data,rhs.data,temp);\n            delete data;\n            data = temp;\n        }\n        // there is enough size and no references\n        else\n        {\n            long_add(data,rhs.data,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator- (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    data->digits_used + slack\n                    );\n        long_sub(data,rhs.data,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator-= (\n        const bigint_kernel_2& rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            long_sub(data,rhs.data,temp);\n            data = temp;\n        }\n        else\n        {\n            long_sub(data,rhs.data,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator* (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        data_record* temp = new data_record (\n                    data->digits_used + rhs.data->digits_used + slack\n                    );\n        long_mul(data,rhs.data,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator*= (\n        const bigint_kernel_2& rhs\n    )\n    {\n        // create a data_record to store the result of the multiplication in\n        data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack);        \n        long_mul(data,rhs.data,temp);\n\n        // if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        else\n        {\n            delete data;\n        }\n        data = temp;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator/ (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);           \n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n        delete remainder;\n    \n\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator/= (\n        const bigint_kernel_2& rhs\n    )\n    {\n\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }    \n\n        long_div(data,rhs.data,temp,remainder);\n\n        // check if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        // if there are no references to data then it must be deleted\n        else\n        {\n            delete data;\n        }\n        data = temp;\n        delete remainder;\n\n        \n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator% (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n        delete temp;\n        return bigint_kernel_2(remainder,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator%= (\n        const bigint_kernel_2& rhs\n    )\n    {\n        data_record* temp = new data_record(data->digits_used+slack);\n        data_record* remainder;\n        try {\n            remainder = new data_record(data->digits_used+slack);\n        } catch (...) { delete temp; throw; }\n\n        long_div(data,rhs.data,temp,remainder);\n\n        // check if there are other references to data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n        }\n        // if there are no references to data then it must be deleted\n        else\n        {\n            delete data;\n        }\n        data = remainder;\n        delete temp;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_2::\n    operator < (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        return is_less_than(data,rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_2::\n    operator == (\n        const bigint_kernel_2& rhs\n    ) const\n    {\n        return is_equal_to(data,rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator= (\n        const bigint_kernel_2& rhs\n    )\n    {\n        if (this == &rhs)\n            return *this;\n\n        // if we have the only reference to our data then delete it\n        if (data->references == 1)\n        {\n            delete data;\n            data = rhs.data;\n            data->references += 1;\n        }\n        else\n        {\n            data->references -= 1;\n            data = rhs.data;\n            data->references += 1;\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& operator<< (\n        std::ostream& out_,\n        const bigint_kernel_2& rhs\n    )\n    {\n        std::ostream out(out_.rdbuf());\n\n        typedef bigint_kernel_2 bigint;\n        \n        bigint::data_record* temp = new bigint::data_record(*rhs.data,0);\n\n\n\n        // get a char array big enough to hold the number in ascii format\n        char* str;\n        try {\n            str = new char[(rhs.data->digits_used)*5+10];\n        } catch (...) { delete temp; throw; }\n\n        char* str_start = str;\n        str += (rhs.data->digits_used)*5+9;\n        *str = 0; --str;\n\n\n        uint16 remainder;\n        rhs.short_div(temp,10000,temp,remainder);\n\n        // pull the digits out of remainder\n        char a = remainder % 10 + '0';\n        remainder /= 10;\n        char b = remainder % 10 + '0';\n        remainder /= 10;\n        char c = remainder % 10 + '0';\n        remainder /= 10;\n        char d = remainder % 10 + '0';\n        remainder /= 10;\n\n\n        *str = a; --str;\n        *str = b; --str;\n        *str = c; --str;\n        *str = d; --str;\n\n\n        // keep looping until temp represents zero\n        while (temp->digits_used != 1 || *(temp->number) != 0)\n        {            \n            rhs.short_div(temp,10000,temp,remainder);\n\n            // pull the digits out of remainder\n            char a = remainder % 10 + '0';\n            remainder /= 10;\n            char b = remainder % 10 + '0';\n            remainder /= 10;\n            char c = remainder % 10 + '0';\n            remainder /= 10;\n            char d = remainder % 10 + '0';\n            remainder /= 10;\n\n            *str = a; --str;\n            *str = b; --str;\n            *str = c; --str;\n            *str = d; --str;              \n        }\n\n        // throw away and extra leading zeros\n        ++str;\n        if (*str == '0')\n            ++str;\n        if (*str == '0')\n            ++str;\n        if (*str == '0')\n            ++str;\n\n\n        \n\n        out << str;\n        delete [] str_start;\n        delete temp;\n        return out_;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::istream& operator>> (\n        std::istream& in_,\n        bigint_kernel_2& rhs\n    )\n    {\n        std::istream in(in_.rdbuf());\n\n        // ignore any leading whitespaces\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\n')\n        {\n            in.get();\n        }\n\n        // if the first digit is not an integer then this is an error\n        if ( !(in.peek() >= '0' && in.peek() <= '9'))\n        {\n            in_.clear(std::ios::failbit);\n            return in_;\n        }\n\n        int num_read;\n        bigint_kernel_2 temp;\n        do\n        {\n\n            // try to get 4 chars from in\n            num_read = 1;\n            char a = 0;\n            char b = 0; \n            char c = 0;\n            char d = 0;\n\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                a = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                b = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                c = in.get();\n            }\n            if (in.peek() >= '0' && in.peek() <= '9')\n            {\n                num_read *= 10;\n                d = in.get();\n            }\n            \n            // merge the for digits into an uint16\n            uint16 num = 0;\n            if (a != 0)\n            {\n                num = a - '0';\n            }\n            if (b != 0)\n            {\n                num *= 10;\n                num += b - '0';\n            }\n            if (c != 0)\n            {\n                num *= 10;\n                num += c - '0';\n            }\n            if (d != 0)\n            {\n                num *= 10;\n                num += d - '0';\n            }\n\n\n            if (num_read != 1)\n            {\n                // shift the digits in temp left by the number of new digits we just read\n                temp *= num_read;\n                // add in new digits\n                temp += num;\n            }\n\n        } while (num_read == 10000);\n\n\n        rhs = temp;\n        return in_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator+ (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (rhs.data->digits_used+rhs.slack);\n\n        rhs.short_add(rhs.data,lhs,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator+ (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_add(lhs.data,rhs,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator+= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;    \n            short_add(data,rhs,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data then do so\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            short_add(data,rhs,temp);\n            delete data;\n            data = temp;\n        }\n        // or if there is plenty of space and no references\n        else\n        {\n            short_add(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator- (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        *(temp->number) = lhs - *(rhs.data->number);\n\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator- (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_sub(lhs.data,rhs,temp);\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator-= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_sub(data,rhs,temp);\n            data = temp;\n        }\n        else\n        {\n            short_sub(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator* (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (rhs.data->digits_used+rhs.slack);\n\n        rhs.short_mul(rhs.data,lhs,temp);\n        return bigint_kernel_2(temp,0);        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator* (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        lhs.short_mul(lhs.data,rhs,temp);\n        return bigint_kernel_2(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator*= (\n        uint16 rhs\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_mul(data,rhs,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            short_mul(data,rhs,temp);\n            delete data;\n            data = temp;\n        }\n        else\n        {\n            short_mul(data,rhs,data);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator/ (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        // if rhs might not be bigger than lhs\n        if (rhs.data->digits_used == 1)\n        {\n            *(temp->number) = lhs/ *(rhs.data->number);\n        }\n        \n        return bigint_kernel_2(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator/ (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record\n                (lhs.data->digits_used+lhs.slack);\n\n        uint16 remainder;\n        lhs.short_div(lhs.data,rhs,temp,remainder);\n        return bigint_kernel_2(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator/= (\n        uint16 rhs\n    )\n    {\n        uint16 remainder;\n        // if there are other references to this data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_div(data,rhs,temp,remainder);    \n            data = temp;\n        }\n        else\n        {\n            short_div(data,rhs,data,remainder);\n        }\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator% (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        // temp is zero by default\n        bigint::data_record* temp = new bigint::data_record(rhs.slack);\n\n        if (rhs.data->digits_used == 1)\n        {\n            // if rhs is just an uint16 inside then perform the modulus\n            *(temp->number) = lhs % *(rhs.data->number);\n        }\n        else\n        {\n            // if rhs is bigger than lhs then the answer is lhs\n            *(temp->number) = lhs;\n        }\n        \n        return bigint_kernel_2(temp,0);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 operator% (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        typedef bigint_kernel_2 bigint;\n        bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack);\n\n        uint16 remainder;\n\n        lhs.short_div(lhs.data,rhs,temp,remainder);\n        temp->digits_used = 1;\n        *(temp->number) = remainder;\n        return bigint_kernel_2(temp,0);          \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator%= (\n        uint16 rhs\n    )\n    {\n        uint16 remainder;\n        // if there are other references to this data\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            short_div(data,rhs,temp,remainder);\n            data = temp;\n        }\n        else\n        {\n            short_div(data,rhs,data,remainder);\n        }\n\n        data->digits_used = 1;\n        *(data->number) = remainder;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator < (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator < (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator == (\n        const bigint_kernel_2& lhs,\n        uint16 rhs\n    )\n    {\n        return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool operator == (\n        uint16 lhs,\n        const bigint_kernel_2& rhs\n    )\n    {\n        return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator= (\n        uint16 rhs\n    )\n    {\n        // check if there are other references to our data\n        if (data->references != 1)\n        {\n            data->references -= 1;\n            try {\n                data = new data_record(slack);\n            } catch (...) { data->references += 1; throw; }\n        }\n        else\n        {\n            data->digits_used = 1;\n        }\n        \n        *(data->number) = rhs;\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator++ (\n    )\n    {\n        // if there are other references to this data then make a copy of it\n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            increment(data,temp);\n            data = temp;\n        }\n        // or if we need to enlarge data then do so\n        else if (data->digits_used == data->size)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            increment(data,temp);\n            delete data;\n            data = temp;\n        }\n        else\n        {\n            increment(data,data);\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator++ (\n        int\n    )\n    {\n        data_record* temp; // this is the copy of temp we will return in the end\n         \n        data_record* temp2 = new data_record(data->digits_used+slack);\n        increment(data,temp2);\n        \n        temp = data;\n        data = temp2;\n\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bigint_kernel_2& bigint_kernel_2::\n    operator-- (\n    )\n    {\n        // if there are other references to this data \n        if (data->references != 1)\n        {\n            data_record* temp = new data_record(data->digits_used+slack);\n            data->references -= 1;\n            decrement(data,temp);\n            data = temp;\n        }\n        else\n        {\n            decrement(data,data);\n        }\n\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const bigint_kernel_2 bigint_kernel_2::\n    operator-- (\n        int\n    )\n    {\n        data_record* temp; // this is the copy of temp we will return in the end\n         \n        data_record* temp2 = new data_record(data->digits_used+slack);\n        decrement(data,temp2);\n        \n        temp = data;\n        data = temp2;\n\n        return bigint_kernel_2(temp,0);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    short_add (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        // put value into the carry part of temp\n        uint32 temp = value;\n        temp <<= 16;\n\n        \n        const uint16* number = data->number;\n        const uint16* end = number + data->digits_used; // one past the end of number\n        uint16* r = result->number;\n\n        while (number != end)\n        {\n            // add *number and the current carry\n            temp = *number + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number;\n            ++r;\n        }\n\n        // if there is a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = data->digits_used + 1;\n            // store the carry in the most significant digit of the result\n            *r = static_cast<uint16>(temp>>16); \n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    short_sub (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        \n\n        const uint16* number = data->number;\n        const uint16* end = number + data->digits_used - 1;\n        uint16* r = result->number;\n\n        uint32 temp = *number - value;\n\n        // put the low word of temp into *data \n        *r = static_cast<uint16>(temp & 0xFFFF);\n\n        \n        while (number != end)\n        {\n            ++number;\n            ++r;\n\n            // subtract the carry from *number \n            temp = *number - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n        }\n\n        // if we lost a digit in the subtraction\n        if (*r == 0)\n        {\n            if (data->digits_used == 1)\n                result->digits_used = 1;\n            else\n                result->digits_used = data->digits_used - 1;\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    short_mul (\n        const data_record* data,        \n        uint16 value,\n        data_record* result\n    ) const\n    {\n        \n        uint32 temp = 0;\n\n\n        const uint16* number = data->number;        \n        uint16* r = result->number;\n        const uint16* end = r + data->digits_used;\n\n\n\n        while ( r != end)\n        {\n\n            // multiply *data and value and add in the carry\n            temp = *number*(uint32)value + (temp>>16);\n\n            // put the low word of temp into *data\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number;\n            ++r;\n        }\n\n        // if there is a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = data->digits_used + 1;\n            // put the final carry into the most significant digit of the result\n            *r = static_cast<uint16>(temp>>16);\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    short_div (\n        const data_record* data,        \n        uint16 value,   \n        data_record* result,\n        uint16& rem\n    ) const\n    {\n        \n        uint16 remainder = 0;\n        uint32 temp;\n\n        \n\n        const uint16* number = data->number + data->digits_used - 1;\n        const uint16* end = number - data->digits_used;\n        uint16* r = result->number + data->digits_used - 1;\n\n\n        // if we are losing a digit in this division\n        if (*number < value)\n        {\n            if (data->digits_used == 1)\n                result->digits_used = 1;\n            else\n                result->digits_used = data->digits_used - 1;\n        }\n        else\n        {\n            result->digits_used = data->digits_used;\n        }\n\n\n        // perform the actual division\n        while (number != end)\n        {\n           \n            temp = *number + (((uint32)remainder)<<16);\n\n            *r = static_cast<uint16>(temp/value);\n            remainder = static_cast<uint16>(temp%value);\n\n            --number;\n            --r;\n        }\n\n        rem = remainder;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    long_add (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n        // put value into the carry part of temp\n        uint32 temp=0;        \n\n        uint16* min_num;  // the number with the least digits used\n        uint16* max_num;  // the number with the most digits used\n        uint16* min_end;  // one past the end of min_num\n        uint16* max_end;  // one past the end of max_num\n        uint16* r = result->number;\n\n        uint32 max_digits_used;\n        if (lhs->digits_used < rhs->digits_used)\n        {\n            max_digits_used = rhs->digits_used;\n            min_num = lhs->number;\n            max_num = rhs->number;\n            min_end = min_num + lhs->digits_used;\n            max_end = max_num + rhs->digits_used;\n        }\n        else\n        {\n            max_digits_used = lhs->digits_used;\n            min_num = rhs->number;\n            max_num = lhs->number;\n            min_end = min_num + rhs->digits_used;\n            max_end = max_num + lhs->digits_used;\n        }\n\n        \n\n\n        while (min_num != min_end)\n        {\n            // add *min_num, *max_num and the current carry\n            temp = *min_num + *max_num + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++min_num;\n            ++max_num;\n            ++r;\n        }\n\n\n        while (max_num != max_end)\n        {\n            // add *max_num and the current carry\n            temp = *max_num + (temp>>16);\n            // put the low word of temp into *r\n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++max_num;\n            ++r;\n        }        \n\n        // check if there was a final carry\n        if ((temp>>16) != 0)\n        {\n            result->digits_used = max_digits_used + 1;\n            // put the carry into the most significant digit in the result\n            *r = static_cast<uint16>(temp>>16);\n        }\n        else\n        {\n            result->digits_used = max_digits_used;\n        }\n\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    long_sub (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n\n\n        const uint16* number1 = lhs->number;\n        const uint16* number2 = rhs->number;\n        const uint16* end = number2 + rhs->digits_used;\n        uint16* r = result->number;\n\n\n\n        uint32 temp =0;\n\n        \n        while (number2 != end)\n        {\n\n            // subtract *number2 from *number1 and then subtract any carry\n            temp = *number1 - *number2 - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number1;\n            ++number2;\n            ++r;\n        }\n\n        end = lhs->number + lhs->digits_used;\n        while (number1 != end)\n        {\n\n            // subtract the carry from *number1 \n            temp = *number1 - (temp>>31);\n\n            // put the low word of temp into *r \n            *r = static_cast<uint16>(temp & 0xFFFF);\n\n            ++number1;\n            ++r;\n        }\n\n        result->digits_used = lhs->digits_used;\n        // adjust the number of digits used appropriately \n        --r;\n        while (*r == 0 && result->digits_used > 1)\n        {\n            --r;\n            --result->digits_used;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    long_div (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result,\n        data_record* remainder\n    ) const\n    {\n        // zero result\n        result->digits_used = 1;\n        *(result->number) = 0;\n\n        uint16* a;\n        uint16* b;\n        uint16* end;\n\n        // copy lhs into remainder\n        remainder->digits_used = lhs->digits_used;\n        a = remainder->number;\n        end = a + remainder->digits_used;\n        b = lhs->number;\n        while (a != end)\n        {\n            *a = *b;\n            ++a;\n            ++b;\n        }\n\n\n        // if rhs is bigger than lhs then result == 0 and remainder == lhs\n        // so then we can quit right now\n        if (is_less_than(lhs,rhs))\n        {\n            return;            \n        }\n\n\n        // make a temporary number\n        data_record temp(lhs->digits_used + slack);\n\n\n        // shift rhs left until it is one shift away from being larger than lhs and\n        // put the number of left shifts necessary into shifts\n        uint32 shifts; \n        shifts = (lhs->digits_used - rhs->digits_used) * 16;\n\n        shift_left(rhs,&temp,shifts);\n\n\n        // while (lhs > temp)\n        while (is_less_than(&temp,lhs))\n        {\n            shift_left(&temp,&temp,1);\n            ++shifts;\n        }\n        // make sure lhs isn't smaller than temp\n        while (is_less_than(lhs,&temp))\n        {\n            shift_right(&temp,&temp);\n            --shifts;\n        }\n\n        \n        \n        // we want to execute the loop shifts +1 times\n        ++shifts;\n        while (shifts != 0)\n        {\n            shift_left(result,result,1);\n            // if (temp <= remainder)\n            if (!is_less_than(remainder,&temp))\n            {\n                long_sub(remainder,&temp,remainder);\n                \n                // increment result\n                uint16* r = result->number;\n                uint16* end = r + result->digits_used;\n                while (true)\n                {\n                    ++(*r);\n                    // if there was no carry then we are done\n                    if (*r != 0)\n                        break;\n\n                    ++r;\n\n                    // if we hit the end of r and there is still a carry then\n                    // the next digit of r is 1 and there is one more digit used\n                    if (r == end)\n                    {\n                        *r = 1;\n                        ++(result->digits_used);\n                        break;\n                    }\n                }\n            }\n            shift_right(&temp,&temp);\n            --shifts;\n        }\n        \n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    long_mul (\n        const data_record* lhs,\n        const data_record* rhs,\n        data_record* result\n    ) const\n    {\n        // if one of the numbers is small then use this simple but O(n^2) algorithm\n        if (std::min(lhs->digits_used, rhs->digits_used) < 10)\n        {\n            // make result be zero\n            result->digits_used = 1;\n            *(result->number) = 0;\n\n\n            const data_record* aa;\n            const data_record* bb;\n\n            if (lhs->digits_used < rhs->digits_used)\n            {\n                // make copies of lhs and rhs and give them an appropriate amount of\n                // extra memory so there won't be any overflows\n                aa = lhs;\n                bb = rhs;\n            }\n            else\n            {\n                // make copies of lhs and rhs and give them an appropriate amount of\n                // extra memory so there won't be any overflows\n                aa = rhs;\n                bb = lhs;\n            }\n\n            // copy the larger(approximately) of lhs and rhs into b\n            data_record b(*bb,aa->digits_used+slack); \n\n\n            uint32 shift_value = 0;\n            uint16* anum = aa->number;\n            uint16* end = anum + aa->digits_used;\n            while (anum != end )\n            {\n                uint16 bit = 0x0001;\n\n                for (int i = 0; i < 16; ++i)\n                {\n                    // if the specified bit of a is 1\n                    if ((*anum & bit) != 0)\n                    {\n                        shift_left(&b,&b,shift_value);\n                        shift_value = 0;\n                        long_add(&b,result,result);\n                    }\n                    ++shift_value;\n                    bit <<= 1;\n                }\n\n                ++anum;                        \n            }\n        }\n        else  // else if both lhs and rhs are large then use the more complex \n              // O(n*logn) algorithm\n        {\n            uint32 size = 1;\n            // make size a power of 2\n            while (size < (lhs->digits_used + rhs->digits_used)*2)  \n            {\n                size *= 2;\n            }\n\n            // allocate some temporary space so we can do the FFT\n            ct* a = new ct[size];\n            ct* b; try {b = new ct[size]; } catch (...) { delete [] a; throw; }\n\n            // load lhs into the a array.  We are breaking the input number into \n            // 8bit chunks for the purpose of using this fft algorithm.  The reason \n            // for this is so that we have smaller numbers coming out of the final \n            // ifft.  This helps avoid overflow.\n            for (uint32 i = 0; i < lhs->digits_used; ++i)\n            {\n                a[i*2] = ct((t)(lhs->number[i]&0xFF),0);\n                a[i*2+1] = ct((t)(lhs->number[i]>>8),0);\n            }\n            for (uint32 i = lhs->digits_used*2; i < size; ++i)\n            {\n                a[i] = 0;\n            }\n\n            // load rhs into the b array\n            for (uint32 i = 0; i < rhs->digits_used; ++i)\n            {\n                b[i*2] = ct((t)(rhs->number[i]&0xFF),0);\n                b[i*2+1] = ct((t)(rhs->number[i]>>8),0);\n            }\n            for (uint32 i = rhs->digits_used*2; i < size; ++i)\n            {\n                b[i] = 0;\n            }\n\n            // perform the forward fft of a and b\n            fft(a,size);\n            fft(b,size);\n\n            const double l = 1.0/size;\n\n            // do the pointwise multiply of a and b and also apply the scale\n            // factor in this loop too.\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                a[i] = l*a[i]*b[i];\n            }\n\n            // Now compute the inverse fft of the pointwise multiplication of a and b.  \n            // This is basically the result.  We just have to take care of any carries \n            // that should happen.\n            ifft(a,size);\n\n            // loop over the result and propagate any carries that need to take place.  \n            // We will also be moving the resulting numbers into result->number at \n            // the same time.\n            uint64 carry = 0;\n            result->digits_used = 0;\n            int zeros = 0;\n            const uint32 len = lhs->digits_used + rhs->digits_used;\n            for (unsigned long i = 0; i < len; ++i)\n            {\n                uint64 num1 = static_cast<uint64>(std::round(a[i*2].real()));\n                num1 += carry;\n                carry = 0;\n                if (num1 > 255)\n                {\n                    carry = num1 >> 8;\n                    num1 = (num1&0xFF);\n                }\n\n                uint64 num2 = static_cast<uint64>(std::round(a[i*2+1].real()));\n                num2 += carry;\n                carry = 0;\n                if (num2 > 255)\n                {\n                    carry = num2 >> 8;\n                    num2 = (num2&0xFF);\n                }\n\n                // put the new number into its final place\n                num1 = (num2<<8) | num1;\n                result->number[i] = static_cast<uint16>(num1);\n\n                // keep track of the number of leading zeros\n                if (num1 == 0)\n                    ++zeros;\n                else\n                    zeros = 0;\n                ++(result->digits_used);\n            }\n\n            // adjust digits_used so that it reflects the actual number\n            // of non-zero digits in our representation.\n            result->digits_used -= zeros;\n\n            // if the result was zero then adjust the result accordingly\n            if (result->digits_used == 0)\n            {\n                // make result be zero\n                result->digits_used = 1;\n                *(result->number) = 0;\n            }\n\n            // free all the temporary buffers\n            delete [] a;\n            delete [] b;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    shift_left (\n        const data_record* data,\n        data_record* result,\n        uint32 shift_amount\n    ) const\n    {\n        uint32 offset = shift_amount/16;\n        shift_amount &= 0xf;  // same as shift_amount %= 16;\n\n        uint16* r = result->number + data->digits_used + offset; // result\n        uint16* end = data->number;\n        uint16* s = end + data->digits_used; // source\n        const uint32 temp = 16 - shift_amount;\n\n        *r = (*(--s) >> temp);\n        // set the number of digits used in the result\n        // if the upper bits from *s were zero then don't count this first word\n        if (*r == 0)\n        {\n            result->digits_used = data->digits_used + offset;\n        }\n        else\n        {\n            result->digits_used = data->digits_used + offset + 1;\n        }\n        --r;\n\n        while (s != end)\n        {\n            *r = ((*s << shift_amount) | ( *(s-1) >> temp));\n            --r;\n            --s;\n        }\n        *r = *s << shift_amount;\n\n        // now zero the rest of the result\n        end = result->number;\n        while (r != end)\n            *(--r) = 0;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    shift_right (\n        const data_record* data,\n        data_record* result\n    ) const\n    {\n\n            uint16* r = result->number; // result\n            uint16* s = data->number; // source\n            uint16* end = s + data->digits_used - 1;\n\n            while (s != end)\n            {\n                *r = (*s >> 1) | (*(s+1) << 15);\n                ++r;\n                ++s;\n            }\n            *r = *s >> 1;\n\n\n            // calculate the new number for digits_used\n            if (*r == 0)\n            {\n                if (data->digits_used != 1)\n                    result->digits_used = data->digits_used - 1;\n                else\n                    result->digits_used = 1;\n            }\n            else\n            {\n                result->digits_used = data->digits_used;\n            }\n  \n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_2::\n    is_less_than (\n        const data_record* lhs,\n        const data_record* rhs\n    ) const\n    {\n        uint32 lhs_digits_used = lhs->digits_used;\n        uint32 rhs_digits_used = rhs->digits_used;\n\n        // if lhs is definitely less than rhs\n        if (lhs_digits_used < rhs_digits_used )\n            return true;\n        // if lhs is definitely greater than rhs\n        else if (lhs_digits_used > rhs_digits_used)\n            return false;\n        else \n        {\n            uint16* end = lhs->number;\n            uint16* l = end         + lhs_digits_used;\n            uint16* r = rhs->number + rhs_digits_used;\n            \n            while (l != end)\n            {\n                --l;\n                --r;\n                if (*l < *r)\n                    return true;\n                else if (*l > *r)\n                    return false;\n            }\n\n            // at this point we know that they are equal\n            return false;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bigint_kernel_2::\n    is_equal_to (\n        const data_record* lhs,\n        const data_record* rhs\n    ) const\n    {\n        // if lhs and rhs are definitely not equal\n        if (lhs->digits_used != rhs->digits_used )\n        {\n            return false;\n        }\n        else \n        {            \n            uint16* l = lhs->number;\n            uint16* r = rhs->number;\n            uint16* end = l + lhs->digits_used;\n            \n            while (l != end)\n            {\n                if (*l != *r)\n                    return false;\n                ++l;\n                ++r;\n            }\n\n            // at this point we know that they are equal\n            return true;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    increment (\n        const data_record* source,\n        data_record* dest\n    ) const\n    {\n        uint16* s = source->number;\n        uint16* d = dest->number;\n        uint16* end = s + source->digits_used;\n        while (true)\n        {\n            *d = *s + 1;\n\n            // if there was no carry then break out of the loop\n            if (*d != 0)\n            {\n                dest->digits_used = source->digits_used;\n\n                // copy the rest of the digits over to d\n                ++d; ++s;\n                while (s != end)\n                {\n                    *d = *s;\n                    ++d;\n                    ++s;\n                }\n\n                break;\n            }\n            \n\n            ++s;            \n\n            // if we have hit the end of s and there was a carry up to this point\n            // then just make the next digit 1 and add one to the digits used\n            if (s == end)\n            {\n                ++d;\n                dest->digits_used = source->digits_used + 1;\n                *d = 1;\n                break;\n            }\n\n            ++d;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    decrement (\n        const data_record* source,\n        data_record* dest\n    ) const\n    {\n        uint16* s = source->number;\n        uint16* d = dest->number;\n        uint16* end = s + source->digits_used;\n        while (true)\n        {\n            *d = *s - 1;\n\n            // if there was no carry then break out of the loop\n            if (*d != 0xFFFF)\n            {\n                // if we lost a digit in the subtraction \n                if (*d == 0 && s+1 == end)\n                {\n                    if (source->digits_used == 1)\n                        dest->digits_used = 1;\n                    else\n                        dest->digits_used = source->digits_used - 1;\n                }\n                else\n                {\n                    dest->digits_used = source->digits_used;\n                }\n                break;\n            }\n            else\n            {\n                ++d;\n                ++s;\n            }\n\n        }\n\n        // copy the rest of the digits over to d\n        ++d;\n        ++s;\n        while (s != end)\n        {\n            *d = *s;\n            ++d;\n            ++s;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    fft (\n        ct* data, \n        unsigned long len\n    ) const \n    {\n        const t pi2 = -2.0*3.1415926535897932384626433832795028841971693993751;\n\n        const unsigned long half = len/2;\n\n        std::vector<ct> twiddle_factors;\n        twiddle_factors.resize(half);\n\n        // compute the complex root of unity w\n        const t temp = pi2/len;\n        ct w = ct(std::cos(temp),std::sin(temp));\n\n        ct w_pow = 1;\n\n        // compute the twiddle factors\n        for (std::vector<ct>::size_type j = 0; j < twiddle_factors.size(); ++j)\n        {\n            twiddle_factors[j] = w_pow; \n            w_pow *= w;\n        }\n\n        ct a, b;\n\n        // now compute the decimation in frequency.  This first\n        // outer loop loops log2(len) number of times\n        unsigned long skip = 1;\n        for (unsigned long step = half; step != 0; step >>= 1)\n        {\n            // do blocks of butterflies in this loop\n            for (unsigned long j = 0; j < len; j += step*2)\n            {\n                // do step butterflies\n                for (unsigned long k = 0; k < step; ++k)\n                {\n                    const unsigned long a_idx = j+k;\n                    const unsigned long b_idx = j+k+step;\n                    a = data[a_idx] + data[b_idx];\n                    b = (data[a_idx] - data[b_idx])*twiddle_factors[k*skip];\n                    data[a_idx] = a;\n                    data[b_idx] = b;\n                }\n            }\n            skip *= 2;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bigint_kernel_2::\n    ifft(\n        ct* data, \n        unsigned long len\n    ) const \n    {\n        const t pi2 = 2.0*3.1415926535897932384626433832795028841971693993751;\n\n        const unsigned long half = len/2;\n\n        std::vector<ct> twiddle_factors;\n        twiddle_factors.resize(half);\n\n        // compute the complex root of unity w\n        const t temp = pi2/len;\n        ct w = ct(std::cos(temp),std::sin(temp));\n\n        ct w_pow = 1;\n\n        // compute the twiddle factors\n        for (std::vector<ct>::size_type j = 0; j < twiddle_factors.size(); ++j)\n        {\n            twiddle_factors[j] = w_pow; \n            w_pow *= w;\n        }\n\n        ct a, b;\n\n        // now compute the inverse decimation in frequency.  This first\n        // outer loop loops log2(len) number of times\n        unsigned long skip = half;\n        for (unsigned long step = 1; step <= half; step <<= 1)\n        {\n            // do blocks of butterflies in this loop\n            for (unsigned long j = 0; j < len; j += step*2)\n            {\n                // do step butterflies\n                for (unsigned long k = 0; k < step; ++k)\n                {\n                    const unsigned long a_idx = j+k;\n                    const unsigned long b_idx = j+k+step;\n                    data[b_idx] *= twiddle_factors[k*skip];\n                    a = data[a_idx] + data[b_idx];\n                    b = data[a_idx] - data[b_idx];\n                    data[a_idx] = a;\n                    data[b_idx] = b;\n                }\n            }\n            skip /= 2;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_BIGINT_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINT_KERNEl_2_\n#define DLIB_BIGINT_KERNEl_2_\n\n#include \"bigint_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../uintn.h\"\n#include <iosfwd>\n#include <cmath>\n#include <complex>\n#include <vector>\n\nnamespace dlib\n{\n    \n    class bigint_kernel_2 \n    {\n        /*!\n            INITIAL VALUE\n                slack               == 25\n                data->number[0]     == 0 \n                data->size          == slack \n                data->references    == 1 \n                data->digits_used   == 1\n                \n\n            CONVENTION\n                slack  == the number of extra digits placed into the number when it is \n                    created.  the slack value should never be less than 1\n\n                data->number == pointer to an array of data->size uint16s.\n                    data represents a string of base 65535 numbers with data[0] being\n                    the least significant bit and data[data->digits_used-1] being the most \n                    significant\n\n\n                NOTE: In the comments I will consider a word to be a 16 bit value\n\n\n                data->digits_used == the number of significant digits in the number.\n                    data->digits_used tells us the number of used elements in the \n                    data->number array so everything beyond data->number[data->digits_used-1] \n                    is undefined\n\n                data->references == the number of bigint_kernel_2 objects which refer\n                    to this data_record\n        !*/\n\n\n        struct data_record\n        {\n\n\n            explicit data_record(\n                uint32 size_\n            ) : \n                size(size_),\n                number(new uint16[size_]),\n                references(1),\n                digits_used(1)\n            {*number = 0;}\n            /*!\n                ensures\n                    - initializes *this to represent zero\n            !*/\n\n            data_record(\n                const data_record& item,\n                uint32 additional_size\n            ) :\n                size(item.digits_used + additional_size),\n                number(new uint16[size]),\n                references(1),\n                digits_used(item.digits_used)\n            {\n                uint16* source = item.number;\n                uint16* dest = number;\n                uint16* end = source + digits_used;\n                while (source != end)\n                {\n                    *dest = *source;\n                    ++dest;\n                    ++source;\n                }\n            }\n            /*!\n                ensures\n                    - *this is a copy of item except with \n                      size == item.digits_used + additional_size\n            !*/\n\n            ~data_record(\n            )\n            {\n                delete [] number;\n            }\n\n\n            const uint32 size;\n            uint16* number;\n            uint32 references;            \n            uint32 digits_used;\n\n        private:\n            // no copy constructor\n            data_record ( data_record&);\n        };\n\n\n        // note that the second parameter is just there \n        // to resolve the ambiguity between this constructor and \n        // bigint_kernel_2(uint32)\n        explicit bigint_kernel_2 (\n            data_record* data_, int\n        ): slack(25),data(data_) {}\n        /*!\n            ensures\n                - *this is initialized with data_ as its data member\n        !*/\n\n    public:\n\n        bigint_kernel_2 (\n        );\n\n        bigint_kernel_2 (\n            uint32 value\n        );\n\n        bigint_kernel_2 (\n            const bigint_kernel_2& item\n        );\n\n        virtual ~bigint_kernel_2 (\n        );\n\n        const bigint_kernel_2 operator+ (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator+= (\n            const bigint_kernel_2& rhs\n        );\n\n        const bigint_kernel_2 operator- (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator-= (\n            const bigint_kernel_2& rhs\n        );\n\n        const bigint_kernel_2 operator* (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator*= (\n            const bigint_kernel_2& rhs\n        );\n\n        const bigint_kernel_2 operator/ (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator/= (\n            const bigint_kernel_2& rhs\n        );\n\n        const bigint_kernel_2 operator% (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator%= (\n            const bigint_kernel_2& rhs\n        );\n\n        bool operator < (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bool operator == (\n            const bigint_kernel_2& rhs\n        ) const;\n\n        bigint_kernel_2& operator= (\n            const bigint_kernel_2& rhs\n        );\n\n        friend std::ostream& operator<< (\n            std::ostream& out,\n            const bigint_kernel_2& rhs\n        );\n\n        friend std::istream& operator>> (\n            std::istream& in,\n            bigint_kernel_2& rhs\n        );\n\n        bigint_kernel_2& operator++ (\n        );\n\n        const bigint_kernel_2 operator++ (\n            int\n        );\n\n        bigint_kernel_2& operator-- (\n        );\n\n        const bigint_kernel_2 operator-- (\n            int\n        );\n\n        friend const bigint_kernel_2 operator+ (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend const bigint_kernel_2 operator+ (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_2& operator+= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_2 operator- (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend const bigint_kernel_2 operator- (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_2& operator-= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_2 operator* (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend const bigint_kernel_2 operator* (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_2& operator*= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_2 operator/ (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend const bigint_kernel_2 operator/ (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_2& operator/= (\n            uint16 rhs\n        );\n\n        friend const bigint_kernel_2 operator% (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend const bigint_kernel_2 operator% (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_2& operator%= (\n            uint16 rhs\n        );\n\n        friend bool operator < (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        friend bool operator < (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        friend bool operator == (\n            const bigint_kernel_2& lhs,\n            uint16 rhs\n        );\n\n        friend bool operator == (\n            uint16 lhs,\n            const bigint_kernel_2& rhs\n        );\n\n        bigint_kernel_2& operator= (\n            uint16 rhs\n        );\n\n\n        void swap (\n            bigint_kernel_2& item\n        ) { data_record* temp = data; data = item.data; item.data = temp; }\n\n\n    private:\n\n        typedef double t;\n        typedef std::complex<t> ct;\n\n        void fft(\n            ct* data, \n            unsigned long len\n        ) const;\n        /*!\n            requires\n                - len == x^n for some integer n (i.e. len is a power of 2)\n                - len > 0\n            ensures\n                - #data == the FT decimation in frequency of data\n        !*/\n\n        void ifft(\n            ct* data, \n            unsigned long len\n        ) const;\n        /*!\n            requires\n                - len == x^n for some integer n (i.e. len is a power of 2)\n                - len > 0\n            ensures\n                - #data == the inverse decimation in frequency of data. \n                  (i.e. the inverse of what fft(data,len,-1) does to data)\n        !*/\n\n        void long_add (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= max(lhs->digits_used,rhs->digits_used) + 1\n            ensures\n                - result == lhs + rhs\n        !*/\n\n        void long_sub (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - lhs >= rhs \n                - result->size >= lhs->digits_used\n            ensures\n                - result == lhs - rhs\n        !*/\n\n        void long_div (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result,\n            data_record* remainder\n        ) const;\n        /*!\n            requires \n                - rhs != 0 \n                - result->size >= lhs->digits_used \n                - remainder->size >= lhs->digits_used \n                - each parameter is unique (i.e. lhs != result, lhs != remainder, etc.)\n            ensures\n                - result == lhs / rhs\n                - remainder == lhs % rhs\n        !*/\n\n        void long_mul (\n            const data_record* lhs,\n            const data_record* rhs,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= lhs->digits_used + rhs->digits_used \n                - result != lhs \n                - result != rhs\n            ensures\n                - result == lhs * rhs\n        !*/\n\n        void short_add (\n            const data_record* data,\n            uint16 value,\n            data_record* result            \n        ) const;\n        /*!\n            requires\n                - result->size >= data->size + 1\n            ensures\n                - result == data + value\n        !*/\n\n        void short_sub (\n            const data_record* data,\n            uint16 value,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - data >= value \n                - result->size >= data->digits_used\n            ensures\n                - result == data - value\n        !*/\n\n        void short_mul (\n            const data_record* data,\n            uint16 value,\n            data_record* result            \n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used + 1\n            ensures\n                - result == data * value\n        !*/\n\n        void short_div (\n            const data_record* data,            \n            uint16 value,\n            data_record* result,\n            uint16& remainder\n        ) const;\n        /*!\n            requires\n                - value != 0 \n                - result->size >= data->digits_used\n            ensures\n                - result = data*value \n                - remainder = data%value\n        !*/\n\n        void shift_left (\n            const data_record* data,\n            data_record* result,\n            uint32 shift_amount\n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used + shift_amount/8 + 1\n            ensures\n                - result == data << shift_amount\n        !*/\n\n        void shift_right (\n            const data_record* data,\n            data_record* result\n        ) const;\n        /*!\n            requires\n                - result->size >= data->digits_used \n            ensures\n                - result == data >> 1\n        !*/\n\n        bool is_less_than (\n            const data_record* lhs,\n            const data_record* rhs\n        ) const;\n        /*! \n            ensures\n                - returns true if lhs < rhs \n                - returns false otherwise\n        !*/ \n\n        bool is_equal_to (\n            const data_record* lhs,\n            const data_record* rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if lhs == rhs \n                - returns false otherwise\n        !*/\n\n        void increment (\n            const data_record* source,\n            data_record* dest\n        ) const;\n        /*!\n            requires\n                - dest->size >= source->digits_used + 1\n            ensures\n                - dest = source + 1\n        !*/\n\n        void decrement (\n            const data_record* source,\n            data_record* dest\n        ) const;\n        /*!\n            requires\n                source != 0\n            ensuers\n                dest = source - 1\n        !*/\n\n        // member data\n        const uint32 slack;\n        data_record* data;     \n        \n        \n\n    };\n\n    inline void swap (\n        bigint_kernel_2& a,\n        bigint_kernel_2& b\n    ) { a.swap(b); }\n\n    inline void serialize (\n        const bigint_kernel_2& item, \n        std::ostream& out\n    )\n    { \n        std::ios::fmtflags oldflags = out.flags();  \n        out << item << ' '; \n        out.flags(oldflags); \n        if (!out) throw serialization_error(\"Error serializing object of type bigint_kernel_c\"); \n    }   \n\n    inline void deserialize (\n        bigint_kernel_2& item, \n        std::istream& in\n    ) \n    { \n        std::ios::fmtflags oldflags = in.flags();  \n        in >> item;\n        in.flags(oldflags); \n        if (in.get() != ' ')\n        {\n            item = 0;\n            throw serialization_error(\"Error deserializing object of type bigint_kernel_c\"); \n        }\n    }   \n\n    inline bool operator>  (const bigint_kernel_2& a, const bigint_kernel_2& b) { return b < a; } \n    inline bool operator!= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a == b); }\n    inline bool operator<= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(b < a); }\n    inline bool operator>= (const bigint_kernel_2& a, const bigint_kernel_2& b) { return !(a < b); }\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"bigint_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_BIGINT_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BIGINT_KERNEl_ABSTRACT_\n#ifdef DLIB_BIGINT_KERNEl_ABSTRACT_\n\n#include <iosfwd>\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class bigint \n    {\n        /*!\n            INITIAL VALUE\n                *this == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an arbitrary precision unsigned integer\n\n                the following operators are supported:\n                operator +\n                operator +=\n                operator -\n                operator -=\n                operator *\n                operator *=\n                operator /\n                operator /=\n                operator %\n                operator %=\n                operator ==\n                operator <\n                operator =\n                operator << (for writing to ostreams)\n                operator >> (for reading from istreams)\n                operator++       // pre increment\n                operator++(int)  // post increment\n                operator--       // pre decrement\n                operator--(int)  // post decrement\n\n\n                the other comparison operators(>, !=, <=, and >=) are \n                available and come from the templates in dlib::relational_operators\n\n            THREAD SAFETY\n                bigint may be reference counted so it is very unthread safe.\n                use with care in a multithreaded program\n\n        !*/\n\n    public:\n\n        bigint (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n                    if this is thrown the bigint will be unusable but \n                    will not leak memory\n        !*/\n\n        bigint (\n            uint32 value\n        );\n        /*!\n            requires\n                - value <= (2^32)-1\n            ensures\n                - #*this is properly initialized\n                - #*this == value\n            throws\n                - std::bad_alloc\n                    if this is thrown the bigint will be unusable but \n                    will not leak memory\n        !*/\n\n        bigint (\n            const bigint& item\n        );\n        /*!\n            ensures\n                - #*this is properly initialized \n                - #*this == value\n            throws\n                - std::bad_alloc\n                    if this is thrown the bigint will be unusable but \n                    will not leak memory\n        !*/\n\n        virtual ~bigint (\n        );\n        /*!\n            ensures\n                - all resources associated with #*this have been released\n        !*/\n\n        const bigint operator+ (\n            const bigint& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of adding rhs to *this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator+= (\n            const bigint& rhs\n        );\n        /*!\n            ensures\n                - #*this == *this + rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect                                        \n        !*/\n\n        const bigint operator- (\n            const bigint& rhs\n        ) const;\n        /*!\n            requires\n                - *this >= rhs\n            ensures\n                - returns the result of subtracting rhs from *this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator-= (\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - *this >= rhs            \n            ensures\n                - #*this == *this - rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        const bigint operator* (\n            const bigint& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of multiplying *this and rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator*= (\n            const bigint& rhs\n        );\n        /*!\n            ensures\n                - #*this == *this * rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        const bigint operator/ (\n            const bigint& rhs\n        ) const;\n        /*!\n            requires\n                - rhs != 0\n            ensures\n                - returns the result of dividing *this by rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator/= (\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - rhs != 0\n            ensures\n                - #*this == *this / rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        const bigint operator% (\n            const bigint& rhs\n        ) const;\n        /*!\n            requires\n                - rhs != 0\n            ensures\n                - returns the result of *this mod rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator%= (\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - rhs != 0\n            ensures\n                - #*this == *this % rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bool operator < (\n            const bigint& rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if *this is less than rhs \n                - returns false otherwise\n        !*/\n\n        bool operator == (\n            const bigint& rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if *this and rhs represent the same number \n                - returns false otherwise\n        !*/\n\n        bigint& operator= (\n            const bigint& rhs\n        );\n        /*!\n            ensures\n                - #*this == rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n\n        friend std::ostream& operator<< (\n            std::ostream& out,\n            const bigint& rhs\n        );\n        /*!\n            ensures\n                - the number in *this has been written to #out as a base ten number\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect (nothing\n                    is written to out)\n        !*/\n\n        friend std::istream& operator>> (\n            std::istream& in,\n            bigint& rhs\n        );\n        /*!\n            ensures\n                - reads a number from in and puts it into #*this \n                - if (there is no positive base ten number on the input stream ) then \n                    - #in.fail() == true\n            throws\n                - std::bad_alloc\n                    if this function throws the value in rhs is undefined and some\n                    characters may have been read from in.  rhs is still usable though,\n                    its value is just unknown.\n        !*/\n\n\n        bigint& operator++ (\n        );\n        /*!\n            ensures\n                - #*this == *this + 1 \n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        const bigint operator++ (\n            int\n        );\n        /*!\n            ensures\n                - #*this == *this + 1\n                - returns *this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator-- (\n        );\n        /*! \n            requires\n                - *this != 0\n            ensures\n                - #*this == *this - 1\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        const bigint operator-- (\n            int\n        );\n        /*!\n            requires\n                - *this != 0\n            ensures\n                - #*this == *this - 1\n                - returns *this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        void swap (\n            bigint& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n\n        // ------------------------------------------------------------------\n        // ----    The following functions are identical to the above   -----\n        // ----  but take uint16 as one of their arguments. They  ---\n        // ----  exist only to allow for a more efficient implementation  ---\n        // ------------------------------------------------------------------\n\n\n        friend const bigint operator+ (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - lhs <= 65535\n            ensures\n                - returns the result of adding rhs to lhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator+ (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - returns the result of adding rhs to lhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator+= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - #*this == *this + rhs                \n                - returns #this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator- (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - lhs >= rhs \n                - lhs <= 65535\n            ensures\n                - returns the result of subtracting rhs from lhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator- (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - lhs >= rhs \n                - rhs <= 65535\n            ensures\n                - returns the result of subtracting rhs from lhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator-= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - *this >= rhs \n                - rhs <= 65535\n            ensures\n                - #*this == *this - rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator* (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - lhs <= 65535\n            ensures\n                - returns the result of multiplying lhs and rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator* (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - returns the result of multiplying lhs and rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator*= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - #*this == *this * rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator/ (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - lhs <= 65535\n            ensures\n                - returns the result of dividing lhs by rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator/ (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - rhs <= 65535\n            ensures\n                - returns the result of dividing lhs by rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator/= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - rhs <= 65535\n            ensures\n                - #*this == *this / rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator% (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - lhs <= 65535\n            ensures\n                - returns the result of lhs mod rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        friend const bigint operator% (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - rhs <= 65535\n            ensures\n                - returns the result of lhs mod rhs\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n        bigint& operator%= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs != 0 \n                - rhs <= 65535\n            ensures\n                - #*this == *this % rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n\n        friend bool operator < (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - lhs <= 65535\n            ensures\n                - returns true if lhs is less than rhs \n                - returns false otherwise\n        !*/\n\n        friend bool operator < (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - returns true if lhs is less than rhs \n                - returns false otherwise\n        !*/\n\n        friend bool operator == (\n            const bigint& lhs,\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - returns true if lhs and rhs represent the same number \n                - returns false otherwise\n        !*/\n\n        friend bool operator == (\n            uint16 lhs,\n            const bigint& rhs\n        );\n        /*!\n            requires\n                - lhs <= 65535\n            ensures\n                - returns true if lhs and rhs represent the same number \n                - returns false otherwise\n        !*/\n\n        bigint& operator= (\n            uint16 rhs\n        );\n        /*!\n            requires\n                - rhs <= 65535\n            ensures\n                - #*this == rhs\n                - returns #*this\n            throws\n                - std::bad_alloc\n                    if this function throws then it has no effect\n        !*/\n\n    };   \n   \n    inline void swap (\n        bigint& a, \n        bigint& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    void serialize (\n        const bigint& item, \n        std::istream& in\n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        bigint& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n    inline bool operator>  (const bigint& a, const bigint& b) { return b < a; } \n    inline bool operator!= (const bigint& a, const bigint& b) { return !(a == b); }\n    inline bool operator<= (const bigint& a, const bigint& b) { return !(b < a); }\n    inline bool operator>= (const bigint& a, const bigint& b) { return !(a < b); }\n}\n\n#endif // DLIB_BIGINT_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/bigint/bigint_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINT_KERNEl_C_\n#define DLIB_BIGINT_KERNEl_C_\n\n#include \"bigint_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    class bigint_kernel_c \n    {\n        bigint_base data;\n\n        explicit bigint_kernel_c (\n            const bigint_base& item\n        ) : data(item) {}\n\n    public:\n\n\n        bigint_kernel_c (\n        );\n\n        bigint_kernel_c (\n            uint32 value\n        );\n\n        bigint_kernel_c (\n            const bigint_kernel_c<bigint_base>& item\n        );\n\n        ~bigint_kernel_c (\n        );\n\n        const bigint_kernel_c<bigint_base> operator+ (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bigint_kernel_c<bigint_base>& operator+= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        const bigint_kernel_c<bigint_base> operator- (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n        bigint_kernel_c<bigint_base>& operator-= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        const bigint_kernel_c<bigint_base> operator* (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bigint_kernel_c<bigint_base>& operator*= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        const bigint_kernel_c<bigint_base> operator/ (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bigint_kernel_c<bigint_base>& operator/= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        const bigint_kernel_c<bigint_base> operator% (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bigint_kernel_c<bigint_base>& operator%= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        bool operator < (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bool operator == (\n            const bigint_kernel_c<bigint_base>& rhs\n        ) const;\n\n        bigint_kernel_c<bigint_base>& operator= (\n            const bigint_kernel_c<bigint_base>& rhs\n        );\n\n        template <typename T>\n        friend std::ostream& operator<< (\n            std::ostream& out,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend std::istream& operator>>  (\n            std::istream& in,\n            bigint_kernel_c<T>& rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator++ (\n        );\n\n        const bigint_kernel_c<bigint_base> operator++ (\n            int\n        );\n\n        bigint_kernel_c<bigint_base>& operator-- (\n        );\n\n        const bigint_kernel_c<bigint_base> operator-- (\n            int\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator+  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator+  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator+= (\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator-  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator-  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator-= (\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator*  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator*  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator*= (\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator/  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator/  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator/= (\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator%  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend const bigint_kernel_c<T> operator%  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator%= (\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend bool operator <  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        template <typename T>\n        friend bool operator <  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend bool operator ==  (\n            const bigint_kernel_c<T>& lhs,\n            uint16 rhs\n        );\n\n        template <typename T>\n        friend bool operator ==  (\n            uint16 lhs,\n            const bigint_kernel_c<T>& rhs\n        );\n\n        bigint_kernel_c<bigint_base>& operator= (\n            uint16 rhs\n        );\n\n\n        void swap (\n            bigint_kernel_c<bigint_base>& item\n        ) { data.swap(item.data); }\n\n    };\n\n    template <\n        typename bigint_base\n        >\n    void swap (\n        bigint_kernel_c<bigint_base>& a,\n        bigint_kernel_c<bigint_base>& b\n    ) { a.swap(b); }\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    inline void serialize (\n        const bigint_kernel_c<bigint_base>& item, \n        std::ostream& out\n    )\n    { \n        std::ios::fmtflags oldflags = out.flags();  \n        out << item << ' '; \n        out.flags(oldflags); \n        if (!out) throw serialization_error(\"Error serializing object of type bigint_kernel_c\"); \n    }   \n\n    template <\n        typename bigint_base\n        >\n    inline void deserialize (\n        bigint_kernel_c<bigint_base>& item, \n        std::istream& in\n    ) \n    { \n        std::ios::fmtflags oldflags = in.flags();  \n        in >> item;\n        in.flags(oldflags); \n        if (in.get() != ' ') \n        {\n            item = 0;\n            throw serialization_error(\"Error deserializing object of type bigint_kernel_c\"); \n        }\n    }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>::\n    bigint_kernel_c (\n    )\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>::\n    bigint_kernel_c (\n        uint32 value\n    ) : \n        data(value)\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( value <= 0xFFFFFFFF ,\n            \"\\tbigint::bigint(uint16)\"\n            << \"\\n\\t value must be <= (2^32)-1\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\tvalue:   \" << value\n            );        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>::\n    bigint_kernel_c (\n        const bigint_kernel_c<bigint_base>& item\n    ) :\n        data(item.data)\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>::\n    ~bigint_kernel_c (\n    )\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator+ (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        return bigint_kernel_c<bigint_base>(data + rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator+= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        data += rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator- (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(*this < rhs),\n            \"\\tconst bigint bigint::operator-(const bigint&)\"\n            << \"\\n\\t *this should not be less than rhs\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t*this: \" << *this \n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(data-rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator-= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(*this < rhs),\n            \"\\tbigint& bigint::operator-=(const bigint&)\"\n            << \"\\n\\t *this should not be less than rhs\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t*this: \" << *this \n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        data -= rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator* (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        return bigint_kernel_c<bigint_base>(data * rhs.data );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator*= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        data *= rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator/ (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        //make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0),\n            \"\\tconst bigint bigint::operator/(const bigint&)\"\n            << \"\\n\\t can't divide by zero\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(data/rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator/= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0),\n            \"\\tbigint& bigint::operator/=(const bigint&)\"\n            << \"\\n\\t can't divide by zero\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        data /= rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator% (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0),\n            \"\\tconst bigint bigint::operator%(const bigint&)\"\n            << \"\\n\\t can't divide by zero\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(data%rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator%= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0),\n            \"\\tbigint& bigint::operator%=(const bigint&)\"\n            << \"\\n\\t can't divide by zero\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        data %= rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool bigint_kernel_c<bigint_base>::\n    operator < (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        return data < rhs.data;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool bigint_kernel_c<bigint_base>::\n    operator == (\n        const bigint_kernel_c<bigint_base>& rhs\n    ) const\n    {\n        return data == rhs.data;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator= (\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        data = rhs.data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    std::ostream& operator<< (\n        std::ostream& out,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        out << rhs.data;\n        return out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    std::istream& operator>> (\n        std::istream& in,\n        bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        in >> rhs.data;\n        return in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator++ (\n    )\n    {\n        ++data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator++ (\n        int\n    )\n    {\n        return bigint_kernel_c<bigint_base>(data++);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator-- (\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(*this == 0),\n            \"\\tbigint& bigint::operator--()\"\n            << \"\\n\\t *this to subtract from *this it must not be zero to begin with\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        --data;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::\n    operator-- (\n        int\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(*this == 0),\n            \"\\tconst bigint bigint::operator--(int)\"\n            << \"\\n\\t *this to subtract from *this it must not be zero to begin with\"\n            << \"\\n\\tthis:  \" << this\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(data--);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator+ (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( lhs <= 65535,\n            \"\\tconst bigint operator+(uint16, const bigint&)\"\n            << \"\\n\\t lhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return bigint_kernel_c<bigint_base>(static_cast<uint16>(lhs)+rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator+ (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tconst bigint operator+(const bigint&, uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return bigint_kernel_c<bigint_base>(lhs.data+static_cast<uint16>(rhs));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator+= (\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tbigint& bigint::operator+=(uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t*this: \" << *this \n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        data += rhs;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator- (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(static_cast<uint16>(lhs) < rhs) && lhs <= 65535,\n            \"\\tconst bigint operator-(uint16,const bigint&)\"\n            << \"\\n\\t lhs must be greater than or equal to rhs and lhs <= 65535\"\n            << \"\\n\\tlhs:   \" << lhs\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(static_cast<uint16>(lhs)-rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator- (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(lhs < static_cast<uint16>(rhs)) && rhs <= 65535,\n            \"\\tconst bigint operator-(const bigint&,uint16)\"\n            << \"\\n\\t lhs must be greater than or equal to rhs and rhs <= 65535\"\n            << \"\\n\\tlhs:   \" << lhs\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(lhs.data-static_cast<uint16>(rhs));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator-= (\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(*this < static_cast<uint16>(rhs)) && rhs <= 65535,\n            \"\\tbigint& bigint::operator-=(uint16)\"\n            << \"\\n\\t *this must not be less than rhs and rhs <= 65535\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t*this: \" << *this\n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        data -= static_cast<uint16>(rhs);\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator* (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( lhs <= 65535,\n            \"\\tconst bigint operator*(uint16, const bigint&)\"\n            << \"\\n\\t lhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return bigint_kernel_c<bigint_base>(lhs*rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator* (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tconst bigint operator*(const bigint&, uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return bigint_kernel_c<bigint_base>(lhs.data*rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator*= (\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\t bigint bigint::operator*=(uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t*this: \" << *this \n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        data *= static_cast<uint16>(rhs);\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator/ (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && lhs <= 65535,\n            \"\\tconst bigint operator/(uint16,const bigint&)\"\n            << \"\\n\\t you can't divide by zero and lhs <= 65535\"\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(lhs/rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator/ (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,\n            \"\\tconst bigint operator/(const bigint&,uint16)\"\n            << \"\\n\\t you can't divide by zero and rhs <= 65535\"\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(lhs.data/static_cast<uint16>(rhs));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator/= (\n        uint16 rhs\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && static_cast<uint32>(rhs) <= 65535,\n            \"\\tbigint& bigint::operator/=(uint16)\"\n            << \"\\n\\t you can't divide by zero and rhs must be <= 65535\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        data /= rhs;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator% (\n        uint16 lhs,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && static_cast<uint32>(lhs) <= 65535,\n            \"\\tconst bigint operator%(uint16,const bigint&)\"\n            << \"\\n\\t you can't divide by zero and lhs must be <= 65535\"\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(lhs%rhs.data);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    const bigint_kernel_c<bigint_base> operator% (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,\n            \"\\tconst bigint operator%(const bigint&,uint16)\"\n            << \"\\n\\t you can't divide by zero and rhs must be <= 65535\"\n            << \"\\n\\t&lhs:  \" << &lhs\n            << \"\\n\\t&rhs:  \" << &rhs\n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        return bigint_kernel_c<bigint_base>(lhs.data%static_cast<uint16>(rhs));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator%= (\n        uint16 r\n    )\n    {\n\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,\n            \"\\tbigint& bigint::operator%=(uint16)\"\n            << \"\\n\\t you can't divide by zero and rhs must be <= 65535\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\trhs:   \" << rhs\n            );\n\n        // call the real function\n        data %= rhs;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool operator < (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( lhs <= 65535,\n            \"\\tbool operator<(uint16, const bigint&)\"\n            << \"\\n\\t lhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return static_cast<uint16>(lhs) < rhs.data;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool operator < (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tbool operator<(const bigint&, uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return lhs.data < static_cast<uint16>(rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool operator == (\n        const bigint_kernel_c<bigint_base>& lhs,\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tbool operator==(const bigint&, uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return lhs.data == static_cast<uint16>(rhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bool operator == (\n        uint16 l,\n        const bigint_kernel_c<bigint_base>& rhs\n    )\n    {\n        uint32 lhs = l;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( lhs <= 65535,\n            \"\\tbool operator==(uint16, const bigint&)\"\n            << \"\\n\\t lhs must be <= 65535\"\n            << \"\\n\\trhs:   \" << rhs\n            << \"\\n\\tlhs:   \" << lhs\n            );\n\n        return static_cast<uint16>(lhs) == rhs.data;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bigint_base\n        >\n    bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::\n    operator= (\n        uint16 r\n    )\n    {\n        uint32 rhs = r;\n        // make sure requires clause is not broken\n        DLIB_CASSERT( rhs <= 65535,\n            \"\\tbigint bigint::operator=(uint16)\"\n            << \"\\n\\t rhs must be <= 65535\"\n            << \"\\n\\t*this:  \" << *this\n            << \"\\n\\tthis:   \" << this\n            << \"\\n\\tlhs:    \" << rhs\n            );\n\n        data = static_cast<uint16>(rhs);\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template < typename bigint_base >\n    inline bool operator>  (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return b < a; } \n    template < typename bigint_base >\n    inline bool operator!= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(a == b); }\n    template < typename bigint_base >\n    inline bool operator<= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(b < a); }\n    template < typename bigint_base >\n    inline bool operator>= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(a < b); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BIGINT_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/bigint.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIGINt_\n#define DLIB_BIGINt_\n\n#include \"bigint/bigint_kernel_1.h\"\n#include \"bigint/bigint_kernel_2.h\"\n#include \"bigint/bigint_kernel_c.h\"\n\n\n\n\nnamespace dlib\n{\n\n\n    class bigint\n    {\n        bigint() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     bigint_kernel_1\n                    kernel_1a;\n        typedef     bigint_kernel_c<kernel_1a>\n                    kernel_1a_c;\n          \n        // kernel_2a        \n        typedef     bigint_kernel_2\n                    kernel_2a;\n        typedef     bigint_kernel_c<kernel_2a>\n                    kernel_2a_c;\n          \n\n    };\n}\n\n#endif // DLIB_BIGINt_\n\n"
  },
  {
    "path": "dlib/binary_search_tree/binary_search_tree_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_1_\n#define DLIB_BINARY_SEARCH_TREE_KERNEl_1_\n\n#include \"binary_search_tree_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include <cstdlib>\n#include <functional>\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare = std::less<domain>\n        >\n    class binary_search_tree_kernel_1 : public enumerable<map_pair<domain,range> >,\n                                        public asc_pair_remover<domain,range,compare>\n    {\n\n        /*!\n            INITIAL VALUE\n                tree_size == 0\n                tree_root == 0\n                tree_height == 0\n                at_start_ == true\n                current_element == 0\n                stack == array of 50 node pointers\n                stack_pos == 0\n\n\n            CONVENTION\n                tree_size   == size()\n                tree_height == height()\n\n                stack[stack_pos-1] == pop()\n\n                current_element_valid() == (current_element != 0)\n                if (current_element_valid()) then\n                    element() == current_element->d and current_element->r\n                at_start_ == at_start()\n                if (current_element != 0 && current_element != tree_root) then\n                    stack[stack_pos-1] == the parent of the node pointed to by current_element\n\n                if (tree_size != 0)\n                    tree_root == pointer to the root node of the binary search tree\n                else\n                    tree_root == 0\n\n\n                for all nodes:\n                {\n                    left points to the left subtree or 0 if there is no left subtree and\n                    right points to the right subtree or 0 if there is no right subtree and\n                    all elements in a left subtree are <= the root and\n                    all elements in a right subtree are >= the root and\n                    d is the item in the domain of *this contained in the node\n                    r is the item in the range of *this contained in the node\n                    balance:\n                        balance == 0 if both subtrees have the same height\n                        balance == -1 if the left subtree has a height that is greater \n                                   than the height of the right subtree by 1\n                        balance == 1 if the right subtree has a height that is greater \n                                   than the height of the left subtree by 1\n                    for all trees:\n                        the height of the left and right subtrees differ by at most one\n                }\n\n        !*/\n    \n        class node\n        {\n        public:\n            node* left;\n            node* right;\n            domain d;\n            range r;\n            signed char balance;\n        };\n\n        class mpair : public map_pair<domain,range>\n        {\n        public:\n            const domain* d;\n            range* r;\n\n            const domain& key( \n            ) const { return *d; }\n\n            const range& value(\n            ) const { return *r; }\n\n            range& value(\n            ) { return *r; }\n        };\n\n   \n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            binary_search_tree_kernel_1(\n            ) :\n                tree_size(0),\n                tree_root(0),\n                current_element(0),\n                tree_height(0),\n                at_start_(true),\n                stack_pos(0),\n                stack(ppool.allocate_array(50))\n            {\n            }\n\n            virtual ~binary_search_tree_kernel_1(\n            ); \n    \n            inline void clear(\n            );\n\n            inline short height (\n            ) const;\n\n            inline unsigned long count (\n                const domain& item\n            ) const;\n\n            inline void add (\n                domain& d,\n                range& r\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& item\n            );\n\n            inline const range* operator[] (\n                const domain& item\n            ) const;\n\n            inline range* operator[] (\n                const domain& item\n            );\n\n            inline void swap (\n                binary_search_tree_kernel_1& item\n            );\n\n            // function from the asc_pair_remover interface\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            const map_pair<domain,range>& element (\n            ) const;\n\n            map_pair<domain,range>& element (\n            );\n\n            bool move_next (\n            ) const;\n\n            void remove_last_in_order (\n                domain& d,\n                range& r\n            );\n\n            void remove_current_element (\n                domain& d,\n                range& r\n            );\n\n            void position_enumerator (\n                const domain& d\n            ) const;\n\n        private:\n\n\n            inline void rotate_left (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == 2 \n                    - t->right->balance == 0 or 1 \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - #t is still a binary search tree \n                    - #t->balance is between 1 and -1 \n                    - #t now has a height smaller by 1 if #t->balance == 0\n            !*/\n\n            inline void rotate_right (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == -2 \n                    - t->left->balance == 0 or -1 \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - #t is still a binary search tree \n                    - #t->balance is between 1 and -1 \n                    - #t now has a height smaller by 1 if #t->balance == 0\n\n            !*/\n\n            inline void double_rotate_right (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == -2 \n                    - t->left->balance == 1 \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - #t is still a binary search tree \n                    - #t now has a balance of 0 \n                    - #t now has a height smaller by 1             \n            !*/\n\n            inline void double_rotate_left (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == 2 \n                    - t->right->balance == -1 \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - #t is still a binary search tree \n                    - #t now has a balance of 0 \n                    - #t now has a height smaller by 1\n            !*/\n\n            bool remove_biggest_element_in_tree (\n                node*& t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t != 0  (i.e. there must be something in the tree to remove) \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - the biggest node in t has been removed \n                    - the biggest node domain element in t has been put into #d \n                    - the biggest node range element in t has been put into #r\n                    - #t is still a binary search tree \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            bool remove_least_element_in_tree (\n                node*& t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t != 0  (i.e. there must be something in the tree to remove) \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - the least node in t has been removed \n                    - the least node domain element in t has been put into #d \n                    - the least node range element in t has been put into #r\n                    - #t is still a binary search tree \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            bool add_to_tree (\n                node*& t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - the mapping (d --> r) has been added to #t \n                    - #d and #r have initial values for their types\n                    - #t is still a binary search tree \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has grown by one\n            !*/\n\n            bool remove_from_tree (\n                node*& t,\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n            /*!\n                requires\n                    - return_reference(t,d) != 0\n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - #d_copy is equivalent to d                                    \n                    - an element in t equivalent to d has been removed and swapped \n                      into #d_copy and its associated range object has been \n                      swapped into #r\n                    - #t is still a binary search tree                                     \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            bool remove_from_tree (\n                node*& t,\n                const domain& item\n            );\n            /*!\n                requires\n                    - return_reference(t,item) != 0\n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - an element in t equivalent to item has been removed                      \n                    - #t is still a binary search tree                                     \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            const range* return_reference (\n                const node* t,\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - if (there is a domain element equivalent to d in t) then\n                        - returns a pointer to the element in the range equivalent to d\n                    - else\n                        - returns 0\n            !*/\n\n            range* return_reference (\n                node* t,\n                const domain& d\n            );\n            /*!\n                ensures\n                    - if (there is a domain element equivalent to d in t) then\n                        - returns a pointer to the element in the range equivalent to d\n                    - else\n                        - returns 0\n            !*/\n\n\n            inline bool keep_node_balanced (\n                node*& t\n            );\n            /*!\n                requires\n                    - t != 0 \n                    - t == reference to the pointer in t's parent node that points to t\n                ensures\n                    - if (t->balance is < 1 or > 1) then \n                        - keep_node_balanced() will ensure that #t->balance == 0, -1, or 1\n                    - #t is still a binary search tree\n                    - returns true if it made the tree one height shorter \n                    - returns false if it didn't change the height\n            !*/\n\n\n            unsigned long get_count (\n                const domain& item,\n                node* tree_root\n            ) const;\n            /*!\n                requires\n                    - tree_root == the root of a binary search tree or 0\n                ensures\n                    - if (tree_root == 0) then\n                        - returns 0\n                    - else\n                        - returns the number of elements in tree_root that are \n                          equivalent to item\n            !*/\n\n\n            void delete_tree (\n                node* t\n            );\n            /*!\n                requires\n                    - t != 0\n                ensures\n                    - deallocates the node pointed to by t and all of t's left and right children\n            !*/\n\n\n            void push (\n                node* n\n            ) const { stack[stack_pos] = n; ++stack_pos; }\n            /*!\n                ensures\n                    - pushes n onto the stack\n            !*/\n            \n\n            node* pop (\n            ) const { --stack_pos; return stack[stack_pos]; }\n            /*!\n                ensures\n                    - pops the top of the stack and returns it\n            !*/\n\n\n\n            bool fix_stack (\n                node* t,\n                unsigned char depth = 0\n            );\n            /*!\n                requires\n                    - current_element != 0\n                    - depth == 0\n                    - t == tree_root\n                ensures\n                    - makes the stack contain the correct set of parent pointers.\n                      also adjusts stack_pos so it is correct.\n                    - #t is still a binary search tree                                     \n            !*/\n\n            bool remove_current_element_from_tree (\n                node*& t,\n                domain& d,\n                range& r,\n                unsigned long cur_stack_pos = 1\n            ); \n            /*!\n                requires\n                    - t == tree_root\n                    - cur_stack_pos == 1\n                    - current_element != 0\n                ensures\n                    - removes the data in the node given by current_element and swaps it into \n                      #d and #r.  \n                    - #t is still a binary search tree                                     \n                    - the enumerator is advances on to the next element but its stack is \n                      potentially corrupted.  so you must call fix_stack(tree_root) to fix\n                      it.\n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n\n            // data members\n\n            mutable mpair p;\n            unsigned long tree_size;            \n            node* tree_root;\n            mutable node* current_element;            \n            typename mem_manager::template rebind<node>::other pool;\n            typename mem_manager::template rebind<node*>::other ppool;\n            short tree_height;\n            mutable bool at_start_;\n            mutable unsigned char stack_pos;\n            mutable node** stack;\n            compare comp; \n\n            // restricted functions\n            binary_search_tree_kernel_1(binary_search_tree_kernel_1&);        \n            binary_search_tree_kernel_1& operator=(binary_search_tree_kernel_1&); \n\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    inline void swap (\n        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& a, \n        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& b \n    ) { a.swap(b); }\n\n\n\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void deserialize (\n        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type binary_search_tree_kernel_1\"); \n        }\n    }\n\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    ~binary_search_tree_kernel_1 (\n    )\n    {\n        ppool.deallocate_array(stack);\n        if (tree_size != 0)\n        {\n            delete_tree(tree_root);\n        }        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    clear (\n    )\n    {\n        if (tree_size > 0)\n        {\n            delete_tree(tree_root);\n            tree_root = 0;\n            tree_size = 0;\n            tree_height = 0;\n        }\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    size_t binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    size (\n    ) const\n    {\n        return tree_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    short binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    height (\n    ) const\n    {\n        return tree_height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    unsigned long binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    count (\n        const domain& item\n    ) const\n    {\n        return get_count(item,tree_root);        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    add (\n        domain& d,\n        range& r\n    ) \n    {\n        tree_height += add_to_tree(tree_root,d,r);\n        ++tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    ) \n    {\n        tree_height -= remove_from_tree(tree_root,d,d_copy,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    destroy (\n        const domain& item\n    ) \n    {\n        tree_height -= remove_from_tree(tree_root,item);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_any (\n        domain& d,\n        range& r\n    ) \n    {\n        tree_height -= remove_least_element_in_tree(tree_root,d,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    operator[] (\n        const domain& item\n    ) \n    {\n        return return_reference(tree_root,item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    const range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    operator[] (\n        const domain& item\n    ) const\n    {\n        return return_reference(tree_root,item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    swap (\n        binary_search_tree_kernel_1<domain,range,mem_manager,compare>& item\n    ) \n    {\n        pool.swap(item.pool);\n        ppool.swap(item.ppool);\n        exchange(p,item.p);\n        exchange(stack,item.stack);\n        exchange(stack_pos,item.stack_pos);\n        exchange(comp,item.comp);\n        \n\n        node* tree_root_temp            = item.tree_root;\n        unsigned long tree_size_temp    = item.tree_size;\n        short tree_height_temp          = item.tree_height;\n        node* current_element_temp      = item.current_element;\n        bool at_start_temp              = item.at_start_;\n\n        item.tree_root   = tree_root;\n        item.tree_size   = tree_size;\n        item.tree_height = tree_height;\n        item.current_element = current_element;\n        item.at_start_   = at_start_;\n\n        tree_root   = tree_root_temp;\n        tree_size   = tree_size_temp;\n        tree_height = tree_height_temp;\n        current_element = current_element_temp;\n        at_start_   = at_start_temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_last_in_order (\n        domain& d,\n        range& r\n    )\n    {\n        tree_height -= remove_biggest_element_in_tree(tree_root,d,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_current_element (\n        domain& d,\n        range& r\n    )\n    {\n        tree_height -= remove_current_element_from_tree(tree_root,d,r);\n        --tree_size;\n\n        // fix the enumerator stack if we need to\n        if (current_element)\n            fix_stack(tree_root);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    position_enumerator (\n        const domain& d\n    ) const\n    {\n        // clear the enumerator state and make sure the stack is empty\n        reset();\n        at_start_ = false;\n        node* t = tree_root;\n        bool went_left = false;\n        while (t != 0)\n        {\n            if ( comp(d , t->d) )\n            {\n                push(t);\n                // if item is on the left then look in left\n                t = t->left;\n                went_left = true;\n            }\n            else if (comp(t->d , d))\n            {\n                push(t);\n                // if item is on the right then look in right\n                t = t->right;\n                went_left = false;\n            }\n            else\n            {\n                current_element = t;\n                return;\n            }\n        }\n\n        // if we didn't find any matches but there might be something after the\n        // d in this tree.\n        if (stack_pos > 0)\n        {\n            current_element = pop();\n            // if we went left from this node then this node is the next\n            // biggest.\n            if (went_left)\n            {\n                return;\n            }\n            else\n            {\n                move_next();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n        stack_pos = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    const map_pair<domain,range>& binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    element (\n    ) const\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    map_pair<domain,range>& binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    element (\n    )\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    move_next (\n    ) const\n    {\n        // if we haven't started iterating yet\n        if (at_start_)\n        {\n            at_start_ = false;\n            if (tree_size == 0)\n            {\n                return false;\n            }\n            else\n            {                    \n                // find the first element in the tree\n                current_element = tree_root;\n                node* temp = current_element->left;\n                while (temp != 0)\n                {\n                    push(current_element);\n                    current_element = temp;\n                    temp = current_element->left;\n                }\n                return true;\n            }\n        }\n        else\n        {\n            if (current_element == 0)\n            {\n                return false;\n            }\n            else\n            {\n                node* temp;\n                bool went_up;  // true if we went up the tree from a child node to parent\n                bool from_left = false; // true if we went up and were coming from a left child node\n                // find the next element in the tree\n                if (current_element->right != 0)\n                {\n                    // go right and down    \n                    temp = current_element;\n                    push(current_element);\n                    current_element = temp->right;\n                    went_up = false;\n                }\n                else\n                {\n                    // go up to the parent if we can\n                    if (current_element == tree_root)\n                    {\n                        // in this case we have iterated over all the element of the tree\n                        current_element = 0;\n                        return false;\n                    }\n                    went_up = true;\n                    node* parent = pop();\n\n\n                    from_left = (parent->left == current_element);\n                    // go up to parent\n                    current_element = parent;\n                }\n\n\n                while (true)\n                {\n                    if (went_up)\n                    {\n                        if (from_left)\n                        {\n                            // in this case we have found the next node\n                            break;\n                        }\n                        else\n                        {\n                            if (current_element == tree_root)\n                            {\n                                // in this case we have iterated over all the elements\n                                // in the tree\n                                current_element = 0;\n                                return false;\n                            }\n                            // we should go up\n                            node* parent = pop();\n                            from_left = (parent->left == current_element);                            \n                            current_element = parent;\n                        }\n                    }\n                    else\n                    {\n                        // we just went down to a child node\n                        if (current_element->left != 0)\n                        {\n                            // go left\n                            went_up = false;\n                            temp = current_element;\n                            push(current_element);\n                            current_element = temp->left;\n                        }\n                        else\n                        {\n                            // if there is no left child then we have found the next node\n                            break;\n                        }\n                    }\n                }\n\n                return true;               \n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    delete_tree (\n        node* t\n    ) \n    {\n        if (t->left != 0)\n            delete_tree(t->left);\n        if (t->right != 0)\n            delete_tree(t->right);\n        pool.deallocate(t);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    rotate_left (\n        node*& t\n    ) \n    {\n\n        // set the new balance numbers\n        if (t->right->balance == 1)\n        {\n            t->balance = 0;\n            t->right->balance = 0;\n        }\n        else\n        {\n            t->balance = 1;\n            t->right->balance = -1;            \n        }\n\n        // perform the rotation\n        node* temp = t->right;\n        t->right = temp->left;\n        temp->left = t;\n        t = temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    rotate_right (\n        node*& t\n    ) \n    {\n        // set the new balance numbers\n        if (t->left->balance == -1)\n        {\n            t->balance = 0;\n            t->left->balance = 0;\n        }\n        else\n        {\n            t->balance = -1;\n            t->left->balance = 1;            \n        }\n\n        // preform the rotation\n        node* temp = t->left;\n        t->left = temp->right;\n        temp->right = t;\n        t = temp;    \n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    double_rotate_right (\n        node*& t\n    )\n    {\n\n        node* temp = t;\n        t = t->left->right;\n        \n        temp->left->right = t->left;\n        t->left = temp->left;\n\n        temp->left = t->right;\n        t->right = temp;\n\n        if (t->balance < 0)\n        {  \n            t->left->balance = 0;\n            t->right->balance = 1;\n        }\n        else if (t->balance > 0)\n        {\n            t->left->balance = -1;\n            t->right->balance = 0;\n        }\n        else \n        {\n            t->left->balance = 0;\n            t->right->balance = 0;\n        }\n        t->balance = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    double_rotate_left (\n        node*& t\n    )\n    {\n        node* temp = t;\n        t = t->right->left;\n        \n        temp->right->left = t->right;\n        t->right = temp->right;\n\n        temp->right = t->left;\n        t->left = temp;\n\n        if (t->balance < 0)\n        {  \n            t->left->balance = 0;\n            t->right->balance = 1;\n        }\n        else if (t->balance > 0)\n        {\n            t->left->balance = -1;\n            t->right->balance = 0;\n        }\n        else \n        {\n            t->left->balance = 0;\n            t->right->balance = 0;\n        }\n\n        t->balance = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_biggest_element_in_tree (\n        node*& t,\n        domain& d,\n        range& r\n    ) \n    {\n        // make a reference to the current node so we don't have to dereference a \n        // pointer a bunch of times\n        node& tree = *t;\n\n        // if the right tree is an empty tree\n        if ( tree.right == 0)\n        {\n            // swap nodes domain and range elements into d and r\n            exchange(d,tree.d);\n            exchange(r,tree.r);\n\n            // plug hole left by removing this node\n            t = tree.left;\n\n            // delete the node that was just removed\n            pool.deallocate(&tree);    \n\n            // return that the height of this part of the tree has decreased\n            return true;\n        }\n        else\n        {\n\n            // keep going right\n\n            // if remove made the tree one height shorter\n            if ( remove_biggest_element_in_tree(tree.right,d,r) ) \n            {\n                // if this caused the current tree to strink then report that\n                if ( tree.balance == 1)\n                {\n                    --tree.balance;\n                    return true;\n                }\n                else\n                {\n                    --tree.balance;\n                    return keep_node_balanced(t);\n                }                \n            }\n\n            return false;            \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_least_element_in_tree (\n        node*& t,\n        domain& d,\n        range& r\n    ) \n    {\n        // make a reference to the current node so we don't have to dereference a \n        // pointer a bunch of times\n        node& tree = *t;\n\n        // if the left tree is an empty tree\n        if ( tree.left == 0)\n        {\n            // swap nodes domain and range elements into d and r\n            exchange(d,tree.d);\n            exchange(r,tree.r);\n\n            // plug hole left by removing this node\n            t = tree.right;\n\n            // delete the node that was just removed\n            pool.deallocate(&tree);    \n\n            // return that the height of this part of the tree has decreased\n            return true;\n        }\n        else\n        {\n\n            // keep going left\n\n            // if remove made the tree one height shorter\n            if ( remove_least_element_in_tree(tree.left,d,r) ) \n            {\n                // if this caused the current tree to strink then report that\n                if ( tree.balance == -1)\n                {\n                    ++tree.balance;\n                    return true;\n                }\n                else\n                {\n                    ++tree.balance;\n                    return keep_node_balanced(t);\n                }                \n            }\n\n            return false;            \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    add_to_tree (\n        node*& t,\n        domain& d,\n        range& r\n    ) \n    {\n\n        // if found place to add\n        if (t == 0)\n        {\n            // create a node to add new item into\n            t = pool.allocate(); \n\n            // make a reference to the current node so we don't have to dereference a \n            // pointer a bunch of times\n            node& tree = *t;\n\n\n            // set left and right pointers to NULL to indicate that there are no \n            // left or right subtrees\n            tree.left = 0;\n            tree.right = 0;\n            tree.balance = 0;\n\n            // put d and r into t\n            exchange(tree.d,d);\n            exchange(tree.r,r);\n\n            // indicate that the height of this tree has increased\n            return true;\n        }\n        else  // keep looking for a place to add the new item\n        {\n            // make a reference to the current node so we don't have to dereference \n            // a pointer a bunch of times\n            node& tree = *t;\n            signed char old_balance = tree.balance;\n\n            // add the new item to whatever subtree it should go into\n            if (comp( d , tree.d) )\n                tree.balance -= add_to_tree(tree.left,d,r);\n            else\n                tree.balance += add_to_tree(tree.right,d,r);\n\n\n            // if the tree was balanced to start with\n            if (old_balance == 0)\n            {\n                // if its not balanced anymore then it grew in height\n                if (tree.balance != 0)\n                    return true;\n                else\n                    return false;\n            }\n            else\n            {\n                // if the tree is now balanced then it didn't grow\n                if (tree.balance == 0)\n                {\n                    return false;\n                }\n                else\n                {\n                    // if the tree needs to be balanced\n                    if (tree.balance != old_balance)\n                    {\n                        return !keep_node_balanced(t);\n                    }\n                    // if there has been no change in the heights\n                    else\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    fix_stack (\n        node* t,\n        unsigned char depth \n    ) \n    {\n        // if we found the node we were looking for\n        if (t == current_element)\n        {\n            stack_pos = depth;\n            return true;\n        }\n        else if (t == 0)\n        {\n            return false;\n        }\n\n        if (!( comp(t->d , current_element->d)))\n        {\n            // go left\n            if (fix_stack(t->left,depth+1))\n            {\n                stack[depth] = t;\n                return true;\n            }            \n        }\n        if (!(comp(current_element->d , t->d)))\n        {\n            // go right\n            if (fix_stack(t->right,depth+1))\n            {\n                stack[depth] = t;\n                return true;\n            }            \n        }\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_current_element_from_tree (\n        node*& t,\n        domain& d,\n        range& r,\n        unsigned long cur_stack_pos \n    ) \n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n\n        // if we found the node we were looking for\n        if (t == current_element)\n        {\n\n            // swap nodes domain and range elements into d_copy and r\n            exchange(d,tree.d);\n            exchange(r,tree.r);\n\n            // if there is no left node\n            if (tree.left == 0)\n            {\n                // move the enumerator on to the next element before we mess with the \n                // tree\n                move_next();\n\n                // plug hole left by removing this node and free memory\n                t = tree.right;  // plug hole with right subtree\n                \n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height has changed\n                return true;\n            }\n            // if there is no right node\n            else if (tree.right == 0)\n            {\n                // move the enumerator on to the next element before we mess with the \n                // tree\n                move_next();\n\n                // plug hole left by removing this node and free memory\n                t = tree.left;  // plug hole with left subtree\n\n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height of this tree has changed\n                return true;\n            }\n            // if there are both a left and right sub node\n            else\n            {\n\n                // in this case the next current element is going to get swapped back\n                // into this t node.\n                current_element = t;\n\n                // get an element that can replace the one being removed and do this \n                // if it made the right subtree shrink by one\n                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))\n                {\n                    // adjust the tree height\n                    --tree.balance;\n\n                    // if the height of the current tree has dropped by one\n                    if (tree.balance == 0)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return keep_node_balanced(t);\n                    }\n                }\n                // else this remove did not effect the height of this tree\n                else\n                {\n                    return false;\n                }\n\n            }\n\n        }\n        else if (  (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.left) || \n                    tree.left == current_element )\n        {\n            // go left\n            if (tree.balance == -1)\n            {\n                int balance = tree.balance;\n                balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance += remove_current_element_from_tree(tree.left,d,r,cur_stack_pos+1);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n        }\n        else if (  (cur_stack_pos < stack_pos && stack[cur_stack_pos] == tree.right) || \n                    tree.right == current_element )\n        {\n            // go right\n            if (tree.balance == 1)\n            {\n                int balance = tree.balance;\n                balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance -= remove_current_element_from_tree(tree.right,d,r,cur_stack_pos+1);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n        }\n        \n        // this return should never happen but do it anyway to suppress compiler warnings\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_from_tree (\n        node*& t,\n        const domain& d,\n        domain& d_copy,\n        range& r\n    ) \n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n\n        // if item is on the left\n        if (comp(d , tree.d))\n        {\n            // if the left side of the tree has the greatest height\n            if (tree.balance == -1)\n            {\n                int balance = tree.balance;\n                balance += remove_from_tree(tree.left,d,d_copy,r);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance += remove_from_tree(tree.left,d,d_copy,r);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n             \n        }\n        // if item is on the right\n        else if (comp(tree.d , d))\n        {\n\n            // if the right side of the tree has the greatest height\n            if (tree.balance == 1)\n            {\n                int balance = tree.balance;\n                balance -= remove_from_tree(tree.right,d,d_copy,r);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance -= remove_from_tree(tree.right,d,d_copy,r);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n        }\n        // if item is found\n        else \n        {\n\n            // swap nodes domain and range elements into d_copy and r\n            exchange(d_copy,tree.d);\n            exchange(r,tree.r);\n\n            // if there is no left node\n            if (tree.left == 0)\n            {\n\n                // plug hole left by removing this node and free memory\n                t = tree.right;  // plug hole with right subtree\n                \n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height has changed\n                return true;\n            }\n            // if there is no right node\n            else if (tree.right == 0)\n            {\n\n                // plug hole left by removing this node and free memory\n                t = tree.left;  // plug hole with left subtree\n\n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height of this tree has changed\n                return true;\n            }\n            // if there are both a left and right sub node\n            else\n            {\n\n                // get an element that can replace the one being removed and do this \n                // if it made the right subtree shrink by one\n                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))\n                {\n                    // adjust the tree height\n                    --tree.balance;\n\n                    // if the height of the current tree has dropped by one\n                    if (tree.balance == 0)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return keep_node_balanced(t);\n                    }\n                }\n                // else this remove did not effect the height of this tree\n                else\n                {\n                    return false;\n                }\n\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    remove_from_tree (\n        node*& t,\n        const domain& d\n    ) \n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n\n        // if item is on the left\n        if (comp(d , tree.d))\n        {\n            // if the left side of the tree has the greatest height\n            if (tree.balance == -1)\n            {\n                int balance = tree.balance;\n                balance += remove_from_tree(tree.left,d);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance += remove_from_tree(tree.left,d);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n             \n        }\n        // if item is on the right\n        else if (comp(tree.d , d))\n        {\n\n            // if the right side of the tree has the greatest height\n            if (tree.balance == 1)\n            {\n                int balance = tree.balance;\n                balance -= remove_from_tree(tree.right,d);\n                tree.balance = balance;\n                return !tree.balance;\n            }\n            else\n            {\n                int balance = tree.balance;\n                balance -= remove_from_tree(tree.right,d);\n                tree.balance = balance;\n                return keep_node_balanced(t);\n            }\n        }\n        // if item is found\n        else \n        {\n\n            // if there is no left node\n            if (tree.left == 0)\n            {\n\n                // plug hole left by removing this node and free memory\n                t = tree.right;  // plug hole with right subtree\n                \n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height has changed\n                return true;\n            }\n            // if there is no right node\n            else if (tree.right == 0)\n            {\n\n                // plug hole left by removing this node and free memory\n                t = tree.left;  // plug hole with left subtree\n\n                // delete old node\n                pool.deallocate(&tree);  \n\n                // indicate that the height of this tree has changed\n                return true;\n            }\n            // if there are both a left and right sub node\n            else\n            {\n\n                // get an element that can replace the one being removed and do this \n                // if it made the right subtree shrink by one\n                if (remove_least_element_in_tree(tree.right,tree.d,tree.r))\n                {\n                    // adjust the tree height\n                    --tree.balance;\n\n                    // if the height of the current tree has dropped by one\n                    if (tree.balance == 0)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return keep_node_balanced(t);\n                    }\n                }\n                // else this remove did not effect the height of this tree\n                else\n                {\n                    return false;\n                }\n\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    return_reference (\n        node* t,\n        const domain& d\n    ) \n    {\n        while (t != 0)\n        {\n\n            if ( comp(d , t->d ))\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // if it's found then return a reference to it\n                return &(t->r);\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    const range* binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    return_reference (\n        const node* t,\n        const domain& d\n    ) const\n    {\n        while (t != 0)\n        {\n\n            if ( comp(d , t->d) )\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // if it's found then return a reference to it\n                return &(t->r);\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    bool binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    keep_node_balanced (\n        node*& t\n    )\n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n \n        // if tree does not need to be balanced then return false\n        if (tree.balance == 0)\n            return false;\n\n\n        // if tree needs to be rotated left\n        if (tree.balance == 2)\n        {\n            if (tree.right->balance >= 0)\n                rotate_left(t);\n            else\n                double_rotate_left(t);\n        }\n        // else if the tree needs to be rotated right\n        else if (tree.balance == -2)\n        {\n            if (tree.left->balance <= 0)\n                rotate_right(t);\n            else\n                double_rotate_right(t);\n        }\n   \n\n        if (t->balance == 0)\n            return true;\n        else\n            return false; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    unsigned long binary_search_tree_kernel_1<domain,range,mem_manager,compare>::\n    get_count (\n        const domain& d,\n        node* tree_root\n    ) const\n    {\n        if (tree_root != 0)\n        {\n            if (comp(d , tree_root->d))\n            {\n                // go left\n                return get_count(d,tree_root->left);                \n            }\n            else if (comp(tree_root->d , d))\n            {\n                // go right\n                return get_count(d,tree_root->right);\n            }\n            else\n            {\n                // go left and right to look for more matches\n                return   get_count(d,tree_root->left) \n                       + get_count(d,tree_root->right) \n                       + 1;\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/binary_search_tree/binary_search_tree_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_2_\n#define DLIB_BINARY_SEARCH_TREE_KERNEl_2_\n\n#include \"binary_search_tree_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include <functional>\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare = std::less<domain>\n        >\n    class binary_search_tree_kernel_2 : public enumerable<map_pair<domain,range> >,\n                                        public asc_pair_remover<domain,range,compare>\n    {\n\n        /*!\n            INITIAL VALUE\n                NIL == pointer to a node that represents a leaf\n                tree_size == 0\n                tree_root == NIL     \n                at_start == true\n                current_element == 0\n\n\n            CONVENTION\n                current_element_valid() == (current_element != 0)\n                if (current_element_valid()) then\n                    element() == current_element->d and current_element->r\n                at_start_ == at_start()\n\n\n                tree_size   == size()\n\n                NIL == pointer to a node that represents a leaf\n\n                if (tree_size != 0)\n                    tree_root == pointer to the root node of the binary search tree\n                else\n                    tree_root == NIL\n\n                tree_root->color == black                    \n                Every leaf is black and all leafs are the NIL node.\n                The number of black nodes in any path from the root to a leaf is the \n                same. \n\n                for all nodes:\n                {\n                    - left points to the left subtree or NIL if there is no left subtree  \n                    - right points to the right subtree or NIL if there is no right \n                      subtree                                                             \n                    - parent points to the parent node or NIL if the node is the root     \n                    - ordering of nodes is determined by comparing each node's d member  \n                    - all elements in a left subtree are <= the node                      \n                    - all elements in a right subtree are >= the node                     \n                    - color == red or black                                               \n                    - if (color == red)                                                   \n                        - the node's children are black\n                }\n\n        !*/\n    \n        class node\n        {\n        public:            \n            node* left;\n            node* right;\n            node* parent;\n            domain d;\n            range r;\n            char color;\n        };\n\n        class mpair : public map_pair<domain,range>\n        {\n        public:\n            const domain* d;\n            range* r;\n\n            const domain& key( \n            ) const { return *d; }\n\n            const range& value(\n            ) const { return *r; }\n\n            range& value(\n            ) { return *r; }\n        };\n        \n     \n        const static char red = 0;\n        const static char black = 1;\n\n\n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            binary_search_tree_kernel_2(\n            ) :\n                NIL(pool.allocate()),\n                tree_size(0),\n                tree_root(NIL),\n                current_element(0),\n                at_start_(true)\n            {\n                NIL->color = black;\n                NIL->left = 0;\n                NIL->right = 0;\n                NIL->parent = 0;\n            }\n\n            virtual ~binary_search_tree_kernel_2(\n            ); \n    \n            inline void clear(\n            );\n\n            inline short height (\n            ) const;\n\n            inline unsigned long count (\n                const domain& d\n            ) const;\n\n            inline void add (\n                domain& d,\n                range& r\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            inline const range* operator[] (\n                const domain& item\n            ) const;\n\n            inline range* operator[] (\n                const domain& item\n            );\n\n            inline void swap (\n                binary_search_tree_kernel_2& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            const map_pair<domain,range>& element (\n            ) const;\n\n            map_pair<domain,range>& element (\n            );\n\n            bool move_next (\n            ) const;\n\n            void remove_last_in_order (\n                domain& d,\n                range& r\n            );\n\n            void remove_current_element (\n                domain& d,\n                range& r\n            );\n\n            void position_enumerator (\n                const domain& d\n            ) const;\n\n        private:\n\n            inline void rotate_left (\n                node* t\n            );\n            /*!\n                requires\n                    - t != NIL \n                    - t->right != NIL\n                ensures\n                    - performs a left rotation around t and its right child\n            !*/\n\n            inline void rotate_right (\n                node* t\n            );\n            /*!\n                requires\n                    - t != NIL \n                    - t->left != NIL\n                ensures\n                    - performs a right rotation around t and its left child\n            !*/\n\n            inline void double_rotate_right (\n                node* t\n            );\n            /*!\n                requires\n                    - t != NIL \n                    - t->left != NIL \n                    - t->left->right != NIL \n                    - double_rotate_right() is only called in fix_after_add()\n                ensures\n                    - performs a left rotation around t->left \n                    - then performs a right rotation around t\n            !*/\n\n            inline void double_rotate_left (\n                node* t\n            );\n            /*!\n                requires\n                    - t != NIL \n                    - t->right != NIL \n                    - t->right->left != NIL \n                    - double_rotate_left() is only called in fix_after_add()\n                ensures\n                    - performs a right rotation around t->right \n                    - then performs a left rotation around t\n            !*/\n\n            void remove_biggest_element_in_tree (\n                node* t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t != NIL  (i.e. there must be something in the tree to remove)\n                ensures\n                    - the biggest node in t has been removed \n                    - the biggest node element in t has been put into #d and #r \n                    - #t is still a binary search tree \n            !*/\n\n            bool remove_least_element_in_tree (\n                node* t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t != NIL  (i.e. there must be something in the tree to remove)\n                ensures\n                    - the least node in t has been removed \n                    - the least node element in t has been put into #d and #r \n                    - #t is still a binary search tree \n                    - if (the node that was removed was the one pointed to by current_element) then\n                        - returns true\n                    - else\n                        - returns false\n            !*/\n\n            void add_to_tree (\n                node* t,\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - t != NIL\n                ensures\n                    - d and r are now in #t\n                    - there is a mapping from d to r in #t\n                    - #d and #r have initial values for their types\n                    - #t is still a binary search tree \n            !*/\n\n            void remove_from_tree (\n                node* t,\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n            /*!\n                requires\n                    - return_reference(t,d) != 0\n                ensures\n                    - #d_copy is equivalent to d                                     \n                    - the first element in t equivalent to d that is encountered when searching down the tree\n                      from t has been removed and swapped into #d_copy.  Also, the associated range element \n                      has been removed and swapped into #r.\n                    - if (the node that got removed wasn't current_element) then\n                        - adjusts the current_element pointer if the data in the node that it points to gets moved.\n                    - else\n                        - the value of current_element is now invalid\n                    - #t is still a binary search tree \n            !*/\n\n            void remove_from_tree (\n                node* t,\n                const domain& d\n            );\n            /*!\n                requires\n                    - return_reference(t,d) != 0\n                ensures                                  \n                    - an element in t equivalent to d has been removed                \n                    - #t is still a binary search tree \n            !*/\n\n            const range* return_reference (\n                const node* t,\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - if (there is a domain element equivalent to d in t) then\n                        - returns a pointer to the element in the range equivalent to d\n                    - else\n                        - returns 0\n            !*/\n\n            range* return_reference (\n                node* t,\n                const domain& d\n            );\n            /*!\n                ensures\n                    - if (there is a domain element equivalent to d in t) then\n                        - returns a pointer to the element in the range equivalent to d\n                    - else\n                        - returns 0\n            !*/\n\n            void fix_after_add (\n                node* t\n            );\n            /*!\n                requires\n                    - t == pointer to the node just added\n                    - t->color == red \n                    - t->parent != NIL (t must not be the root)\n                    - fix_after_add() is only called after a new node has been added\n                      to t\n                ensures\n                    - fixes any deviations from the CONVENTION caused by adding a node\n            !*/\n\n            void fix_after_remove (\n                node* t\n            );\n            /*!\n                requires\n                    - t == pointer to the only child of the node that was spliced out \n                    - fix_after_remove() is only called after a node has been removed\n                      from t\n                    - the color of the spliced out node was black\n                ensures\n                    - fixes any deviations from the CONVENTION causes by removing a node\n            !*/            \n\n\n            short tree_height (\n                node* t\n            ) const;\n            /*!\n                ensures\n                    - returns the number of nodes in the longest path from the root of the \n                      tree to a leaf\n            !*/\n\n            void delete_tree (\n                node* t\n            );\n            /*!\n                requires\n                    - t == root of binary search tree\n                    - t != NIL\n                ensures\n                    - deletes all nodes in t except for NIL\n            !*/\n\n            unsigned long get_count (\n                const domain& item,\n                node* tree_root\n            ) const;\n            /*!\n                requires\n                    - tree_root == the root of a binary search tree or NIL\n                ensures\n                    - if (tree_root == NIL) then\n                        - returns 0\n                    - else\n                        - returns the number of elements in tree_root that are \n                          equivalent to item\n            !*/\n\n\n\n            // data members\n            typename mem_manager::template rebind<node>::other pool;\n            node* NIL;\n            unsigned long tree_size;\n            node* tree_root;\n            mutable node* current_element;\n            mutable bool at_start_;\n            mutable mpair p;\n            compare comp;\n\n            \n\n            // restricted functions\n            binary_search_tree_kernel_2(binary_search_tree_kernel_2&);        \n            binary_search_tree_kernel_2& operator=(binary_search_tree_kernel_2&);\n\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    inline void swap (\n        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& a, \n        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& b \n    ) { a.swap(b); }\n\n\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >   \n    void deserialize (\n        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type binary_search_tree_kernel_2\"); \n        }\n    }\n\n\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    ~binary_search_tree_kernel_2 (\n    )\n    {     \n        if (tree_root != NIL)\n            delete_tree(tree_root);\n        pool.deallocate(NIL);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    clear (\n    )\n    {\n        if (tree_size > 0)\n        {\n            delete_tree(tree_root);\n            tree_root = NIL;\n            tree_size = 0;\n        }\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    size_t binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    size (\n    ) const\n    {\n        return tree_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    short binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    height (\n    ) const\n    {\n        return tree_height(tree_root);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    unsigned long binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    count (\n        const domain& item\n    ) const\n    {\n        return get_count(item,tree_root);        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    add (\n        domain& d,\n        range& r\n    ) \n    {\n        if (tree_size == 0)\n        {\n            tree_root = pool.allocate();\n            tree_root->color = black;\n            tree_root->left = NIL;\n            tree_root->right = NIL;\n            tree_root->parent = NIL;\n            exchange(tree_root->d,d);\n            exchange(tree_root->r,r);\n        }\n        else \n        {\n            add_to_tree(tree_root,d,r);\n        }\n        ++tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    ) \n    {\n        remove_from_tree(tree_root,d,d_copy,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    destroy (\n        const domain& item\n    ) \n    {\n        remove_from_tree(tree_root,item);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_any (\n        domain& d,\n        range& r\n    ) \n    {\n        remove_least_element_in_tree(tree_root,d,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    operator[] (\n        const domain& d\n    ) \n    {\n        return return_reference(tree_root,d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    const range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    operator[] (\n        const domain& d\n    ) const\n    {\n        return return_reference(tree_root,d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    swap (\n        binary_search_tree_kernel_2<domain,range,mem_manager,compare>& item\n    ) \n    {\n        pool.swap(item.pool);\n        \n        exchange(p,item.p);\n        exchange(comp,item.comp);\n\n        node* tree_root_temp            = item.tree_root;\n        unsigned long tree_size_temp    = item.tree_size;\n        node* const NIL_temp            = item.NIL;\n        node* current_element_temp      = item.current_element;\n        bool at_start_temp              = item.at_start_;\n        \n        item.tree_root                  = tree_root;\n        item.tree_size                  = tree_size;\n        item.NIL                        = NIL;\n        item.current_element            = current_element;\n        item.at_start_                  = at_start_;\n        \n        tree_root                       = tree_root_temp;\n        tree_size                       = tree_size_temp;\n        NIL                             = NIL_temp;\n        current_element                 = current_element_temp;\n        at_start_                       = at_start_temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_last_in_order (\n        domain& d,\n        range& r\n    )\n    {\n        remove_biggest_element_in_tree(tree_root,d,r);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_current_element (\n        domain& d,\n        range& r\n    )\n    {\n        node* t = current_element;\n        move_next();\n        remove_from_tree(t,t->d,d,r);\n        --tree_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    position_enumerator (\n        const domain& d\n    ) const\n    {\n        // clear the enumerator state and make sure the stack is empty\n        reset();\n        at_start_ = false;\n        node* t = tree_root;\n        node* parent = NIL;\n        bool went_left = false;\n        while (t != NIL)\n        {\n            if ( comp(d , t->d ))\n            {\n                // if item is on the left then look in left\n                parent = t;\n                t = t->left;\n                went_left = true;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                parent = t;\n                t = t->right;\n                went_left = false;\n            }\n            else\n            {\n                current_element = t;\n                return;\n            }\n        }\n\n        // if we didn't find any matches but there might be something after the\n        // d in this tree.\n        if (parent != NIL)\n        {\n            current_element = parent;\n            // if we went left from this node then this node is the next\n            // biggest.\n            if (went_left)\n            {\n                return;\n            }\n            else\n            {\n                move_next();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    const map_pair<domain,range>& binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    element (\n    ) const\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    map_pair<domain,range>& binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    element (\n    )\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    move_next (\n    ) const\n    {\n        // if we haven't started iterating yet\n        if (at_start_)\n        {\n            at_start_ = false;\n            if (tree_size == 0)\n            {\n                return false;\n            }\n            else\n            {\n                // find the first element in the tree\n                current_element = tree_root;\n                node* temp = current_element->left;\n                while (temp != NIL)\n                {\n                    current_element = temp;\n                    temp = current_element->left;\n                }\n                return true;\n            }\n        }\n        else\n        {\n            if (current_element == 0)\n            {\n                return false;\n            }\n            else\n            {\n                bool went_up;  // true if we went up the tree from a child node to parent\n                bool from_left = false; // true if we went up and were coming from a left child node\n                // find the next element in the tree\n                if (current_element->right != NIL)\n                {\n                    // go right and down                    \n                    current_element = current_element->right;\n                    went_up = false;\n                }\n                else\n                {\n                    went_up = true;\n                    node* parent = current_element->parent;\n                    if (parent == NIL)\n                    {\n                        // in this case we have iterated over all the element of the tree\n                        current_element = 0;\n                        return false;\n                    }\n\n                    from_left = (parent->left == current_element);\n                    // go up to parent\n                    current_element = parent;\n                }\n\n\n                while (true)\n                {\n                    if (went_up)\n                    {\n                        if (from_left)\n                        {\n                            // in this case we have found the next node\n                            break;\n                        }\n                        else\n                        {\n                            // we should go up\n                            node* parent = current_element->parent;\n                            from_left = (parent->left == current_element);                            \n                            current_element = parent;\n                            if (current_element == NIL)\n                            {\n                                // in this case we have iterated over all the elements\n                                // in the tree\n                                current_element = 0;\n                                return false;\n                            }\n                        }\n                    }\n                    else\n                    {\n                        // we just went down to a child node\n                        if (current_element->left != NIL)\n                        {\n                            // go left\n                            went_up = false;\n                            current_element = current_element->left;\n                        }\n                        else\n                        {\n                            // if there is no left child then we have found the next node\n                            break;\n                        }\n                    }\n                }\n\n                return true;               \n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    delete_tree (\n        node* t\n    )  \n    {\n        if (t->left != NIL)\n            delete_tree(t->left);\n        if (t->right != NIL)\n            delete_tree(t->right);\n        pool.deallocate(t);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    rotate_left (\n        node* t\n    ) \n    {\n\n        // perform the rotation\n        node* temp = t->right;\n        t->right = temp->left;\n        if (temp->left != NIL)\n            temp->left->parent = t;\n        temp->left = t;\n        temp->parent = t->parent;\n\n\n        if (t == tree_root)\n            tree_root = temp;\n        else \n        {\n            // if t was on the left\n            if (t->parent->left == t)\n                t->parent->left = temp;\n            else\n                t->parent->right = temp;\n        }\n\n        t->parent = temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    rotate_right (\n        node* t\n    ) \n    {\n        // perform the rotation\n        node* temp = t->left;\n        t->left = temp->right;\n        if (temp->right != NIL)\n            temp->right->parent = t;\n        temp->right = t;\n        temp->parent = t->parent;\n\n        if (t == tree_root)\n            tree_root = temp;\n        else \n        {\n            // if t is a left child\n            if (t->parent->left == t)\n                t->parent->left = temp;\n            else\n                t->parent->right = temp;\n        }\n\n        t->parent = temp;\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    double_rotate_right (\n        node* t\n    )\n    {\n\n        // preform the rotation\n        node& temp = *(t->left->right);\n        t->left = temp.right;\n        temp.right->parent = t;\n        temp.left->parent = temp.parent;\n        temp.parent->right = temp.left;\n        temp.parent->parent = &temp;\n        temp.right = t;\n        temp.left = temp.parent;\n        temp.parent = t->parent;  \n\n\n        if (tree_root == t)\n            tree_root = &temp;\n        else\n        {\n            // t is a left child\n            if (t->parent->left == t)\n                t->parent->left = &temp;\n            else\n                t->parent->right = &temp;\n        }\n        t->parent = &temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    double_rotate_left (\n        node* t\n    )\n    {\n\n\n        // preform the rotation\n        node& temp = *(t->right->left);\n        t->right = temp.left;\n        temp.left->parent = t;\n        temp.right->parent = temp.parent;\n        temp.parent->left = temp.right;\n        temp.parent->parent = &temp;\n        temp.left = t;\n        temp.right = temp.parent;\n        temp.parent = t->parent;  \n\n\n        if (tree_root == t)\n            tree_root = &temp;\n        else\n        {\n            // t is a left child\n            if (t->parent->left == t)\n                t->parent->left = &temp;\n            else\n                t->parent->right = &temp;\n        }\n        t->parent = &temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_biggest_element_in_tree (\n        node* t,\n        domain& d,\n        range& r\n    ) \n    {\n\n        node* next = t->right;\n        node* child;  // the child node of the one we will slice out\n\n        if (next == NIL)\n        {\n            // need to determine if t is a right or left child\n            if (t->parent->right == t)\n                child = t->parent->right = t->left;\n            else\n                child = t->parent->left = t->left;\n\n            // update tree_root if necessary\n            if (t == tree_root)\n                tree_root = child;\n        }\n        else\n        {\n            // find the least node\n            do \n            {\n                t = next;\n                next = next->right;\n            } while (next != NIL);\n            // t is a right child\n            child = t->parent->right = t->left;\n\n        }\n        \n        // swap the item from this node into d and r\n        exchange(d,t->d);\n        exchange(r,t->r);\n\n        // plug hole right by removing this node\n        child->parent = t->parent;\n\n        // keep the red-black properties true\n        if (t->color == black)\n            fix_after_remove(child);\n\n        // free the memory for this removed node\n        pool.deallocate(t);        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_least_element_in_tree (\n        node* t,\n        domain& d,\n        range& r\n    ) \n    {\n\n        node* next = t->left;\n        node* child;  // the child node of the one we will slice out\n\n        if (next == NIL)\n        {\n            // need to determine if t is a left or right child\n            if (t->parent->left == t)\n                child = t->parent->left = t->right;\n            else\n                child = t->parent->right = t->right;\n\n            // update tree_root if necessary\n            if (t == tree_root)\n                tree_root = child;\n        }\n        else\n        {\n            // find the least node\n            do \n            {\n                t = next;\n                next = next->left;\n            } while (next != NIL);\n            // t is a left child\n            child = t->parent->left = t->right;\n\n        }\n        \n        // swap the item from this node into d and r\n        exchange(d,t->d);\n        exchange(r,t->r);\n\n        // plug hole left by removing this node\n        child->parent = t->parent;\n\n        // keep the red-black properties true\n        if (t->color == black)\n            fix_after_remove(child);\n\n        bool rvalue = (t == current_element);\n        // free the memory for this removed node\n        pool.deallocate(t);        \n        return rvalue;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    add_to_tree (\n        node* t,\n        domain& d,\n        range& r\n    ) \n    {\n        // parent of the current node\n        node* parent;\n\n        // find a place to add node\n        while (true)\n        {\n            parent = t;\n            // if item should be put on the left then go left\n            if (comp(d , t->d))\n            {\n                t = t->left;\n                if (t == NIL)\n                {\n                    t = parent->left = pool.allocate();\n                    break;\n                }\n            }\n            // if item should be put on the right then go right\n            else\n            {\n                t = t->right;\n                if (t == NIL)\n                {\n                    t = parent->right = pool.allocate();\n                    break;\n                }\n            }\n        }\n\n        // t is now the node where we will add item and\n        // parent is the parent of t\n\n        t->parent = parent;\n        t->left = NIL;\n        t->right = NIL;\n        t->color = red;\n        exchange(t->d,d);\n        exchange(t->r,r);\n\n\n        // keep the red-black properties true\n        fix_after_add(t);\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_from_tree (\n        node* t,\n        const domain& d,\n        domain& d_copy,\n        range& r\n    ) \n    {\n        while (true)\n        {\n            if ( comp(d , t->d) )\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // found the node we want to remove\n\n                // swap out the item into d_copy and r\n                exchange(d_copy,t->d);\n                exchange(r,t->r);\n\n                if (t->left == NIL)\n                {\n                    // if there is no left subtree\n\n                    node* parent = t->parent;\n                    \n                    // plug hole with right subtree\n\n\n                    // if t is on the left\n                    if (parent->left == t)\n                        parent->left = t->right;  \n                    else\n                        parent->right = t->right;\n                    t->right->parent = parent;\n\n                    // update tree_root if necessary\n                    if (t == tree_root)\n                        tree_root = t->right;\n\n                    if (t->color == black)\n                        fix_after_remove(t->right);\n\n                    // delete old node\n                    pool.deallocate(t);  \n                }\n                else if (t->right == NIL)\n                {\n                    // if there is no right subtree\n\n                    node* parent = t->parent;\n                    \n                    // plug hole with left subtree\n                    if (parent->left == t)\n                        parent->left = t->left;  \n                    else\n                        parent->right = t->left;\n                    t->left->parent = parent;\n\n                    // update tree_root if necessary\n                    if (t == tree_root)\n                        tree_root = t->left;\n\n                    if (t->color == black)\n                        fix_after_remove(t->left);\n\n                    // delete old node\n                    pool.deallocate(t);\n                }\n                else\n                {\n                    // if there is both a left and right subtree\n                    // get an element to fill this node now that its been swapped into \n                    // item_copy\n                    if (remove_least_element_in_tree(t->right,t->d,t->r))\n                    {\n                        // the node removed was the one pointed to by current_element so we\n                        // need to update it so that it points to the right spot.\n                        current_element = t;\n                    }\n                }\n\n                // quit loop\n                break;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    remove_from_tree (\n        node* t,\n        const domain& d\n    ) \n    {\n        while (true)\n        {\n            if ( comp(d , t->d) )\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // found the node we want to remove\n\n\n                if (t->left == NIL)\n                {\n                    // if there is no left subtree\n\n                    node* parent = t->parent;\n                    \n                    // plug hole with right subtree\n\n\n                    if (parent->left == t)\n                        parent->left = t->right;  \n                    else\n                        parent->right = t->right;\n                    t->right->parent = parent;\n\n                    // update tree_root if necessary\n                    if (t == tree_root)\n                        tree_root = t->right;\n\n                    if (t->color == black)\n                        fix_after_remove(t->right);\n\n                    // delete old node\n                    pool.deallocate(t);  \n                }\n                else if (t->right == NIL)\n                {\n                    // if there is no right subtree\n\n                    node* parent = t->parent;\n                    \n                    // plug hole with left subtree\n                    if (parent->left == t)\n                        parent->left = t->left;  \n                    else\n                        parent->right = t->left;\n                    t->left->parent = parent;\n\n                    // update tree_root if necessary\n                    if (t == tree_root)\n                        tree_root = t->left;\n\n                    if (t->color == black)\n                        fix_after_remove(t->left);\n\n                    // delete old node\n                    pool.deallocate(t);\n                }\n                else\n                {\n                    // if there is both a left and right subtree\n                    // get an element to fill this node now that its been swapped into \n                    // item_copy\n                    remove_least_element_in_tree(t->right,t->d,t->r);\n\n                }\n\n                // quit loop\n                break;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    return_reference (\n        node* t,\n        const domain& d\n    ) \n    {\n        while (t != NIL)\n        {\n            if ( comp(d , t->d ))\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // if it's found then return a reference to it\n                return &(t->r);\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    const range* binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    return_reference (\n        const node* t,\n        const domain& d\n    ) const\n    {\n        while (t != NIL)\n        {\n            if ( comp(d , t->d) )\n            {\n                // if item is on the left then look in left\n                t = t->left;\n            }\n            else if (comp(t->d , d))\n            {\n                // if item is on the right then look in right\n                t = t->right;\n            }\n            else\n            {\n                // if it's found then return a reference to it\n                return &(t->r);\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    fix_after_add (\n        node* t\n    )\n    {\n\n        while (t->parent->color == red)\n        {\n            node& grandparent = *(t->parent->parent);\n\n            // if both t's parent and its sibling are red \n            if (grandparent.left->color == grandparent.right->color)\n            {\n                grandparent.color = red;\n                grandparent.left->color = black;\n                grandparent.right->color = black;\n                t = &grandparent;\n            }\n            else\n            {\n                // if t is a left child\n                if (t == t->parent->left)\n                {\n                    // if t's parent is a left child\n                    if (t->parent == grandparent.left)\n                    {\n                        grandparent.color = red;\n                        grandparent.left->color = black;\n                        rotate_right(&grandparent);\n                    }\n                    // if t's parent is a right child\n                    else\n                    {\n                        t->color = black;\n                        grandparent.color = red;\n                        double_rotate_left(&grandparent);\n                    }\n                }\n                // if t is a right child\n                else\n                {\n                    // if t's parent is a left child\n                    if (t->parent == grandparent.left)\n                    {\n                        t->color = black;\n                        grandparent.color = red;                        \n                        double_rotate_right(&grandparent);\n                    }\n                    // if t's parent is a right child\n                    else\n                    {\n                        grandparent.color = red;\n                        grandparent.right->color = black;\n                        rotate_left(&grandparent);\n                    }\n                }\n                break;\n            }\n        }\n        tree_root->color = black;\n    }       \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    fix_after_remove (\n        node* t\n    )\n    {\n\n        while (t != tree_root && t->color == black)\n        {\n            if (t->parent->left == t)\n            {\n                node* sibling = t->parent->right;\n                if (sibling->color == red)\n                {\n                    sibling->color = black;\n                    t->parent->color = red;\n                    rotate_left(t->parent);\n                    sibling = t->parent->right;\n                }\n\n                if (sibling->left->color == black && sibling->right->color == black)\n                {\n                    sibling->color = red;\n                    t = t->parent;\n                }\n                else\n                {\n                    if (sibling->right->color == black)\n                    {\n                        sibling->left->color = black;\n                        sibling->color = red;\n                        rotate_right(sibling);\n                        sibling = t->parent->right;\n                    }\n\n                    sibling->color = t->parent->color;\n                    t->parent->color = black;\n                    sibling->right->color = black;\n                    rotate_left(t->parent);\n                    t = tree_root;\n\n                }\n\n\n            }\n            else\n            {\n\n                node* sibling = t->parent->left;\n                if (sibling->color == red)\n                {\n                    sibling->color = black;\n                    t->parent->color = red;\n                    rotate_right(t->parent);\n                    sibling = t->parent->left;\n                }\n\n                if (sibling->left->color == black && sibling->right->color == black)\n                {\n                    sibling->color = red;\n                    t = t->parent;\n                }\n                else\n                {\n                    if (sibling->left->color == black)\n                    {\n                        sibling->right->color = black;\n                        sibling->color = red;\n                        rotate_left(sibling);\n                        sibling = t->parent->left;\n                    }\n\n                    sibling->color = t->parent->color;\n                    t->parent->color = black;\n                    sibling->left->color = black;\n                    rotate_right(t->parent);\n                    t = tree_root;\n\n                }\n\n\n            }\n\n        }\n        t->color = black;\n    \n    }         \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    short binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    tree_height (\n        node* t\n    ) const\n    {\n        if (t == NIL)\n            return 0;\n\n        short height1 = tree_height(t->left);\n        short height2 = tree_height(t->right);        \n        if (height1 > height2)\n            return height1 + 1;\n        else\n            return height2 + 1;\n    }       \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    unsigned long binary_search_tree_kernel_2<domain,range,mem_manager,compare>::\n    get_count (\n        const domain& d,\n        node* tree_root\n    ) const\n    {\n        if (tree_root != NIL)\n        {\n            if (comp(d , tree_root->d))\n            {\n                // go left\n                return get_count(d,tree_root->left);                \n            }\n            else if (comp(tree_root->d , d))\n            {\n                // go right\n                return get_count(d,tree_root->right);\n            }\n            else\n            {\n                // go left and right to look for more matches\n                return   get_count(d,tree_root->left) \n                       + get_count(d,tree_root->right) \n                       + 1;\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/binary_search_tree/binary_search_tree_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_\n#ifdef DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_\n\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include <functional>\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class binary_search_tree : public enumerable<map_pair<domain,range> >, \n                               public asc_pair_remover<domain,range,compare>\n    {\n\n        /*!\n            REQUIREMENTS ON domain\n                domain must be comparable by compare where compare is a functor compatible with std::less and\n                domain is swappable by a global swap() and             \n                domain must have a default constructor\n\n            REQUIREMENTS ON range\n                range is swappable by a global swap() and\n                range must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap(), count(), height(),  and operator[] functions \n                do not invalidate pointers or references to internal data.\n\n                position_enumerator() invalidates pointers or references to \n                data returned by element() and only by element() (i.e. pointers and\n                references returned by operator[] are still valid).\n\n                All other functions have no such guarantees.\n\n            INITIAL VALUE\n                size() == 0\n                height() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the domain (and each associated\n                range element) elements in ascending order according to the compare functor.  \n                (i.e. the elements are enumerated in sorted order)              \n\n            WHAT THIS OBJECT REPRESENTS\n                this object represents a data dictionary that is built on top of some \n                kind of binary search tree.  It maps objects of type domain to objects\n                of type range.  \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n                    \n                NOTE:\n                    definition of equivalent:\n                    a is equivalent to b if\n                    a < b == false and\n                    b < a == false\n        !*/\n\n\n    public:\n\n        typedef domain domain_type;\n        typedef range range_type;\n        typedef compare compare_type;\n        typedef mem_manager mem_manager_type;\n\n        binary_search_tree(\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc or any exception thrown by domain's or range's \n                  constructor.\n        !*/\n\n        virtual ~binary_search_tree(\n        ); \n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc or any exception thrown by domain's or range's \n                  constructor.\n                    if this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        short height (\n        ) const;\n        /*!\n            ensures\n                - returns the number of elements in the longest path from the root \n                  of the tree to a leaf\n        !*/\n\n        unsigned long count (\n            const domain& d\n        ) const;\n        /*!\n            ensures\n                - returns the number of elements in the domain of *this that are \n                  equivalent to d\n        !*/ \n\n        void add (\n            domain& d,\n            range& r\n        );\n        /*!\n            requires    \n                - &d != &r (i.e. d and r cannot be the same variable)\n            ensures             \n                - adds a mapping between d and r to *this\n                - if (count(d) == 0) then\n                    - #*(*this)[d] == r\n                - else\n                    - #(*this)[d] != 0\n                - #d and #r have initial values for their types\n                - #count(d) == count(d) + 1\n                - #at_start() == true\n                - #size() == size() + 1\n            throws  \n                - std::bad_alloc or any exception thrown by domain's or range's \n                  constructor.\n                    if add() throws then it has no effect\n        !*/\n\n        void remove (\n            const domain& d,\n            domain& d_copy,\n            range& r\n        );\n        /*!\n            requires\n                - (*this)[d] != 0 \n                - &d != &r (i.e. d and r cannot be the same variable) \n                - &d != &d_copy (i.e. d and d_copy cannot be the same variable) \n                - &r != &d_copy (i.e. r and d_copy cannot be the same variable) \n            ensures\n                - some element in the domain of *this that is equivalent to d has\n                  been removed and swapped into #d_copy.  Additionally, its \n                  associated range element has been removed and swapped into #r.\n                - #count(d) == count(d) - 1\n                - #size() == size() - 1\n                - #at_start() == true  \n        !*/\n\n        void destroy (\n            const domain& d\n        );\n        /*!\n            requires\n                - (*this)[d] != 0 \n            ensures\n                - an element in the domain of *this equivalent to d has been removed.  \n                  The element in the range of *this associated with d has also been \n                  removed.\n                - #count(d) == count(d) - 1\n                - #size() == size() - 1\n                - #at_start() == true  \n        !*/\n\n        void remove_last_in_order (\n            domain& d,\n            range& r\n        );\n        /*!\n            requires\n                - size() > 0\n            ensures\n                - the last/biggest (according to the compare functor) element in the domain of *this has\n                  been removed and swapped into #d.  The element in the range of *this\n                  associated with #d has also been removed and swapped into #r.\n                - #count(#d) == count(#d) - 1\n                - #size() == size() - 1\n                - #at_start() == true\n        !*/\n\n        void remove_current_element (\n            domain& d,\n            range& r\n        );\n        /*!\n            requires\n                - current_element_valid() == true\n            ensures\n                - the current element given by element() has been removed and swapped into d and r.\n                - #d == element().key()\n                - #r == element().value()\n                - #count(#d) == count(#d) - 1\n                - #size() == size() - 1\n                - moves the enumerator to the next element.  If element() was the last \n                  element in enumeration order then #current_element_valid() == false \n                  and #at_start() == false.\n        !*/\n\n        void position_enumerator (\n            const domain& d\n        ) const;\n        /*!\n            ensures\n                - #at_start() == false\n                - if (count(d) > 0) then\n                    - #element().key() == d\n                - else if (there are any items in the domain of *this that are bigger than \n                  d according to the compare functor) then\n                    - #element().key() == the smallest item in the domain of *this that is\n                      bigger than d according to the compare functor.\n                - else\n                    - #current_element_valid() == false\n        !*/\n\n        const range* operator[] (\n            const domain& d\n        ) const;\n        /*!\n            ensures\n                - if (there is an element in the domain equivalent to d) then\n                    - returns a pointer to an element in the range of *this that\n                      is associated with an element in the domain of *this \n                      equivalent to d.\n                - else\n                    - returns 0\n        !*/\n\n        range* operator[] (\n            const domain& d\n        );\n        /*!\n            ensures\n                - if (there is an element in the domain equivalent to d) then\n                    - returns a pointer to an element in the range of *this that\n                      is associated with an element in the domain of *this \n                      equivalent to d.\n                - else\n                    - returns 0\n        !*/\n\n        void swap (\n            binary_search_tree& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    private:\n\n        // restricted functions\n        binary_search_tree(binary_search_tree&);      \n        binary_search_tree& operator=(binary_search_tree&);\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        binary_search_tree<domain,range,mem_manager,compare>& a, \n        binary_search_tree<domain,range,mem_manager,compare>& b \n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        binary_search_tree<domain,range,mem_manager,compare>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/binary_search_tree/binary_search_tree_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BINARY_SEARCH_TREE_KERNEl_C_\n#define DLIB_BINARY_SEARCH_TREE_KERNEl_C_\n\n#include \"../interfaces/map_pair.h\"\n#include \"binary_search_tree_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib \n{\n\n    template <\n        typename bst_base\n        >\n    class binary_search_tree_kernel_c : public bst_base\n    {\n        typedef typename bst_base::domain_type domain;\n        typedef typename bst_base::range_type range;\n\n        public:\n\n            binary_search_tree_kernel_c () {}\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            void add (\n                domain& d,\n                range& r\n            );\n\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            const map_pair<domain, range>& element(\n            ) const\n            {\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tconst map_pair<domain,range>& binary_search_tree::element() const\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                );\n\n                return bst_base::element();\n            }\n\n            map_pair<domain, range>& element(\n            )\n            {\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tmap_pair<domain,range>& binary_search_tree::element()\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                );\n\n                return bst_base::element();\n            }\n\n            void remove_last_in_order (\n                domain& d,\n                range& r\n            );\n\n            void remove_current_element (\n                domain& d,\n                range& r\n            );\n\n\n    };\n\n\n    template <\n        typename bst_base\n        >\n    inline void swap (\n        binary_search_tree_kernel_c<bst_base>& a, \n        binary_search_tree_kernel_c<bst_base>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    add (\n        domain& d,\n        range& r\n    )\n    {\n        DLIB_CASSERT( static_cast<const void*>(&d) != static_cast<void*>(&r),\n            \"\\tvoid binary_search_tree::add\"\n            << \"\\n\\tyou can't call add() and give the same object to both parameters.\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&d:         \" << &d\n            << \"\\n\\t&r:         \" << &r\n            << \"\\n\\tsize():     \" << this->size()\n            );\n\n        bst_base::add(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    destroy (\n        const domain& d\n    )\n    {\n        DLIB_CASSERT(this->operator[](d) != 0,\n            \"\\tvoid binary_search_tree::destroy\"\n            << \"\\n\\tthe element must be in the tree for it to be removed\"\n            << \"\\n\\tthis:    \" << this\n            << \"\\n\\t&d:      \" << &d \n            );\n\n        bst_base::destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        DLIB_CASSERT(this->operator[](d) != 0 &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&\n                (static_cast<const void*>(&r) != static_cast<void*>(&d_copy)),\n            \"\\tvoid binary_search_tree::remove\"\n            << \"\\n\\tthe element must be in the tree for it to be removed\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&d:         \" << &d \n            << \"\\n\\t&d_copy:    \" << &d_copy\n            << \"\\n\\t&r:         \" << &r\n            );\n\n        bst_base::remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    remove_any(\n        domain& d,\n        range& r\n    )\n    {\n        DLIB_CASSERT(this->size() != 0 && \n            (static_cast<const void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid binary_search_tree::remove_any\"\n            << \"\\n\\ttree must not be empty if something is going to be removed\"\n            << \"\\n\\tthis: \" << this\n            << \"\\n\\t&d:   \" << &d\n            << \"\\n\\t&r:   \" << &r\n            );\n\n        bst_base::remove_any(d,r);\n    }\n \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    remove_last_in_order (\n        domain& d,\n        range& r\n    )\n    {\n        DLIB_CASSERT(this->size() > 0, \n            \"\\tvoid binary_search_tree::remove_last_in_order()\"\n            << \"\\n\\tyou can't remove an element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        bst_base::remove_last_in_order(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bst_base\n        >\n    void binary_search_tree_kernel_c<bst_base>::\n    remove_current_element (\n        domain& d,\n        range& r\n    ) \n    {\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tvoid binary_search_tree::remove_current_element()\"\n            << \"\\n\\tyou can't remove the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        bst_base::remove_current_element(d,r);\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BINARY_SEARCH_TREE_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/binary_search_tree.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BINARY_SEARCH_TREe_\n#define DLIB_BINARY_SEARCH_TREe_\n\n\n#include \"binary_search_tree/binary_search_tree_kernel_1.h\"\n#include \"binary_search_tree/binary_search_tree_kernel_2.h\"\n#include \"binary_search_tree/binary_search_tree_kernel_c.h\"\n\n\n#include \"algs.h\"\n#include <functional>\n\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class binary_search_tree\n    {\n        binary_search_tree() {}\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     binary_search_tree_kernel_1<domain,range,mem_manager,compare>    \n                    kernel_1a;\n        typedef     binary_search_tree_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n\n        // kernel_2a        \n        typedef     binary_search_tree_kernel_2<domain,range,mem_manager,compare>    \n                    kernel_2a;\n        typedef     binary_search_tree_kernel_c<kernel_2a>\n                    kernel_2a_c;\n\n    };\n}\n\n#endif // DLIB_BINARY_SEARCH_TREe_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAM_KERNEL_1_CPp_\n#define DLIB_BIT_STREAM_KERNEL_1_CPp_\n\n\n#include \"bit_stream_kernel_1.h\"\n#include \"../algs.h\"\n\n#include <iostream>\n\nnamespace dlib\n{\n\n    inline void swap (\n        bit_stream_kernel_1& a, \n        bit_stream_kernel_1& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    clear (\n    )\n    {\n        if (write_mode)\n        {\n            write_mode = false;\n\n            // flush output buffer\n            if (buffer_size > 0)\n            {\n                buffer <<= 8 - buffer_size;\n                osp->write(reinterpret_cast<char*>(&buffer),1);\n            }\n        }\n        else\n            read_mode = false;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    set_input_stream (\n        std::istream& is\n    )\n    {\n        isp = &is;\n        read_mode = true;\n\n        buffer_size = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    set_output_stream (\n        std::ostream& os\n    )\n    {\n        osp = &os;\n        write_mode = true;\n\n        buffer_size = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    close (\n    )\n    {\n        if (write_mode)\n        {\n            write_mode = false;\n\n            // flush output buffer\n            if (buffer_size > 0)\n            {\n                buffer <<= 8 - buffer_size;\n                osp->write(reinterpret_cast<char*>(&buffer),1);\n            }\n        }\n        else\n            read_mode = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bit_stream_kernel_1::\n    is_in_write_mode (\n    ) const\n    {\n        return write_mode;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bit_stream_kernel_1::\n    is_in_read_mode (\n    ) const\n    {\n        return read_mode;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    write (\n        int bit\n    )\n    {\n        // flush buffer if necessary\n        if (buffer_size == 8)\n        {\n            buffer <<= 8 - buffer_size;\n            if (osp->rdbuf()->sputn(reinterpret_cast<char*>(&buffer),1) == 0)\n            {\n                throw std::ios_base::failure(\"error occurred in the bit_stream object\");\n            }\n\n            buffer_size = 0;\n        }\n\n        ++buffer_size;\n        buffer <<= 1;\n        buffer += static_cast<unsigned char>(bit);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bit_stream_kernel_1::\n    read (\n        int& bit\n    )\n    {\n        // get new byte if necessary\n        if (buffer_size == 0)\n        {\n            if (isp->rdbuf()->sgetn(reinterpret_cast<char*>(&buffer), 1) == 0)\n            {\n                // if we didn't read anything then return false\n                return false;\n            }\n\n            buffer_size = 8;\n        }\n\n        // put the most significant bit from buffer into bit\n        bit = static_cast<int>(buffer >> 7);\n\n        // shift out the bit that was just read\n        buffer <<= 1;\n        --buffer_size;\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bit_stream_kernel_1::\n    swap (\n        bit_stream_kernel_1& item\n    )\n    {\n\n        std::istream*   isp_temp            = item.isp;\n        std::ostream*   osp_temp            = item.osp;\n        bool            write_mode_temp     = item.write_mode;\n        bool            read_mode_temp      = item.read_mode;\n        unsigned char   buffer_temp         = item.buffer;\n        unsigned short  buffer_size_temp    = item.buffer_size;\n\n        item.isp            = isp;\n        item.osp            = osp;\n        item.write_mode     = write_mode;\n        item.read_mode      = read_mode;\n        item.buffer         = buffer;\n        item.buffer_size    = buffer_size;\n\n\n        isp             = isp_temp;\n        osp             = osp_temp;\n        write_mode      = write_mode_temp;\n        read_mode       = read_mode_temp;\n        buffer          = buffer_temp;\n        buffer_size     = buffer_size_temp;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_BIT_STREAM_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAM_KERNEl_1_\n#define DLIB_BIT_STREAM_KERNEl_1_\n\n#include \"bit_stream_kernel_abstract.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class bit_stream_kernel_1\n    {\n\n        /*!\n            INITIAL VALUE\n                write_mode          == false\n                read_mode           == false    \n\n            CONVENTION\n                write_mode          == is_in_write_mode()\n                read_mode           == is_in_read_mode()\n\n                if (write_mode)\n                {\n                    osp             == pointer to an ostream object\n                    buffer          == the low order bits of buffer are the bits to be \n                                       written\n                    buffer_size     == the number of low order bits in buffer that are \n                                       bits that should be written\n                    the lowest order bit is the last bit entered by the user\n                }\n\n                if (read_mode)\n                {\n                    isp             == pointer to an istream object\n                    buffer          == the high order bits of buffer are the bits \n                                       waiting to be read by the user\n                    buffer_size     == the number of high order bits in buffer that \n                                       are bits that are waiting to be read\n                    the highest order bit is the next bit to give to the user\n                }\n        !*/\n\n\n    public:\n\n        bit_stream_kernel_1 (\n        ) :\n            write_mode(false),\n            read_mode(false)\n        {}\n\n        virtual ~bit_stream_kernel_1 (\n        )\n        {}\n\n        void clear (\n        );\n\n        void set_input_stream (\n            std::istream& is\n        );\n\n        void set_output_stream (\n            std::ostream& os\n        );\n\n        void close (\n        );\n\n        inline bool is_in_write_mode (\n        ) const;\n\n        inline bool is_in_read_mode (\n        ) const;\n\n        inline void write (\n            int bit\n        );\n\n        bool read (\n            int& bit\n        );\n\n        void swap (\n            bit_stream_kernel_1& item\n        );\n\n        private:\n\n            // member data\n            std::istream* isp;\n            std::ostream* osp;\n            bool write_mode;\n            bool read_mode;\n            unsigned char buffer;\n            unsigned short buffer_size;\n            \n            // restricted functions\n            bit_stream_kernel_1(bit_stream_kernel_1&);        // copy constructor\n            bit_stream_kernel_1& operator=(bit_stream_kernel_1&);  // assignment operator\n\n    };\n\n    inline void swap (\n        bit_stream_kernel_1& a, \n        bit_stream_kernel_1& b\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"bit_stream_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_BIT_STREAM_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BIT_STREAM_KERNEl_ABSTRACT_\n#ifdef DLIB_BIT_STREAM_KERNEl_ABSTRACT_\n\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class bit_stream\n    {\n\n        /*!\n            INITIAL VALUE\n                is_in_write_mode()  == false\n                is_in_read_mode()   == false\n\n            WHAT THIS OBJECT REPRESENTS\n                this object is a middle man between a user and the iostream classes.\n                it allows single bits to be read/written easily to/from \n                the iostream classes  \n\n            BUFFERING:\n                This object will only read/write single bytes at a time from/to the \n                iostream objects. Any buffered bits still in the bit_stream object \n                when it is closed or destructed are lost if it is in read mode.  If \n                it is in write mode then any remaining bits are guaranteed to be \n                written to the output stream by the time it is closed or destructed.\n        !*/\n\n\n    public:\n\n        bit_stream (\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~bit_stream (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n\n        void set_input_stream (\n            std::istream& is\n        );\n        /*!\n            requires\n                - is_in_write_mode() == false                 \n                - is_in_read_mode() == false                  \n                - is is ready to give input\n            ensures \n                - #is_in_write_mode() == false                 \n                - #is_in_read_mode() == true                   \n                - #*this will now be reading from is\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_output_stream (\n            std::ostream& os\n        );\n        /*!\n            requires\n                - is_in_write_mode() == false         \n                - is_in_read_mode() == false          \n                - os is ready to take output\n            ensures \n                - #is_in_write_mode() == true          \n                - #is_in_read_mode() == false          \n                - #*this will now write to os\n            throws\n                - std::bad_alloc\n        !*/\n        \n\n\n        void close (\n        );\n        /*!\n            requires\n                - is_in_write_mode() == true || is_in_read_mode() == true\n            ensures\n                - #is_in_write_mode() == false \n                - #is_in_read_mode()  == false \n        !*/\n\n        bool is_in_write_mode (\n        ) const;\n        /*!\n            ensures\n                - returns true if *this is associated with an output stream object\n                - returns false otherwise\n        !*/\n\n        bool is_in_read_mode (\n        ) const;\n        /*!\n            ensures\n                - returns true if *this is associated with an input stream object\n                - returns false otherwise\n        !*/\n\n        void write (\n            int bit\n        );\n        /*!\n            requires\n                - is_in_write_mode() == true \n                - bit == 0 || bit == 1\n            ensures\n                - bit will be written to the ostream object associated with *this\n            throws\n                - std::ios_base::failure\n                    if (there was a problem writing to the output stream) then\n                    this exception will be thrown.  #*this will be unusable until\n                    clear() is called and succeeds\n                - any other exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        bool read (\n            int& bit\n        );\n        /*!\n            requires\n                - is_in_read_mode() == true \n            ensures\n                - the next bit has been read and placed into #bit \n                - returns true if the read was successful, else false \n                  (ex. false if EOF has been reached)\n            throws\n                - any exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void swap (\n            bit_stream& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n        private:\n\n            // restricted functions\n            bit_stream(bit_stream&);        // copy constructor\n            bit_stream& operator=(bit_stream&);    // assignment operator\n\n    };\n\n    inline void swap (\n        bit_stream& a, \n        bit_stream& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_BIT_STREAM_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAM_KERNEl_C_\n#define DLIB_BIT_STREAM_KERNEl_C_\n\n#include \"bit_stream_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    template <\n        typename bit_stream_base // implements bit_stream/bit_stream_kernel_abstract.h\n        >\n    class bit_stream_kernel_c : public bit_stream_base\n    {\n    public:\n\n\n        void set_input_stream (\n            std::istream& is\n        );\n\n        void set_output_stream (\n            std::ostream& os\n        );\n\n        void close (\n        );\n\n        void write (\n            int bit\n        );\n\n        bool read (\n            int& bit\n        );\n\n    };\n\n    template <\n        typename bit_stream_base\n        >\n    inline void swap (\n        bit_stream_kernel_c<bit_stream_base>& a, \n        bit_stream_kernel_c<bit_stream_base>& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_kernel_c<bit_stream_base>:: \n    set_input_stream (\n        std::istream& is\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ), \n            \"\\tvoid bit_stream::set_intput_stream\"\n            << \"\\n\\tbit_stream must not be in write or read mode\" \n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        bit_stream_base::set_input_stream(is);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_kernel_c<bit_stream_base>:: \n    set_output_stream (\n        std::ostream& os\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_write_mode() == false ) && ( this->is_in_read_mode() == false ), \n            \"\\tvoid bit_stream::set_output_stream\"\n            << \"\\n\\tbit_stream must not be in write or read mode\" \n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        bit_stream_base::set_output_stream(os);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_kernel_c<bit_stream_base>:: \n    close (\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_write_mode() == true ) || ( this->is_in_read_mode() == true ), \n            \"\\tvoid bit_stream::close\"\n            << \"\\n\\tyou can't close a bit_stream that isn't open\" \n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        bit_stream_base::close();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_kernel_c<bit_stream_base>:: \n    write (\n        int bit\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_write_mode() == true ) && ( bit == 0 || bit == 1 ), \n            \"\\tvoid bit_stream::write\"\n            << \"\\n\\tthe bit stream bust be in write mode and bit must be either 1 or 0\" \n            << \"\\n\\tis_in_write_mode() == \" << this->is_in_write_mode()\n            << \"\\n\\tbit == \" << bit\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        bit_stream_base::write(bit);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    bool bit_stream_kernel_c<bit_stream_base>:: \n    read (\n        int& bit\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_read_mode() == true ), \n            \"\\tbool bit_stream::read\"\n            << \"\\n\\tyou can't read from a bit_stream that isn't in read mode\" \n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return bit_stream_base::read(bit);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BIT_STREAM_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_multi_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAM_MULTi_1_\n#define DLIB_BIT_STREAM_MULTi_1_\n\n#include \"bit_stream_multi_abstract.h\"\n\nnamespace dlib\n{\n    template <\n        typename bit_stream_base\n        >\n    class bit_stream_multi_1 : public bit_stream_base\n    {\n\n    public:\n\n        void multi_write (\n            unsigned long data,\n            int num_to_write\n        );\n\n        int multi_read (\n            unsigned long& data,\n            int num_to_read\n        );\n\n    };\n\n    template <\n        typename bit_stream_base\n        >\n    inline void swap (\n        bit_stream_multi_1<bit_stream_base>& a, \n        bit_stream_multi_1<bit_stream_base>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_multi_1<bit_stream_base>:: \n    multi_write (\n        unsigned long data,\n        int num_to_write\n    )\n    {\n        // move the first bit into the most significant position\n        data <<= 32 - num_to_write;\n\n        for (int i = 0; i < num_to_write; ++i)\n        {\n            // write the first bit from data\n            this->write(static_cast<char>(data >> 31));\n\n            // shift the next bit into position\n            data <<= 1;\n\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    int bit_stream_multi_1<bit_stream_base>:: \n    multi_read (\n        unsigned long& data,\n        int num_to_read\n    )\n    {\n        int bit, i;\n        data = 0;\n        for (i = 0; i < num_to_read; ++i)\n        {\n\n            // get a bit\n            if (this->read(bit) == false)\n                break;\n\n            // shift data to make room for this new bit\n            data <<= 1;\n\n            // put bit into the least significant position in data\n            data += static_cast<unsigned long>(bit);\n\n        }\n\n        return i;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BIT_STREAM_MULTi_1_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_multi_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BIT_STREAM_MULTi_ABSTRACT_\n#ifdef DLIB_BIT_STREAM_MULTi_ABSTRACT_\n\n#include \"bit_stream_kernel_abstract.h\"\n\nnamespace dlib\n{\n    template <\n        typename bit_stream_base  \n        >\n    class bit_stream_multi : public bit_stream_base\n    {\n\n        /*!\n            REQUIREMENTS ON BIT_STREAM_BASE\n                it is an implementation of bit_stream/bit_stream_kernel_abstract.h\n\n      \n            WHAT THIS EXTENSION DOES FOR BIT_STREAM\n                this gives a bit_stream object the ability to read/write multible bits \n                at a time\n        !*/\n\n\n        public:\n\n        void multi_write (\n            unsigned long data,\n            int num_to_write\n        );\n        /*!\n            requires\n                - is_in_write_mode() == true \n                - 0 <= num_to_write <= 32\n            ensures\n                - num_to_write low order bits from data will be written to the ostream \n                - object associated with *this\n                  example: if data is 10010 then the bits will be written in the \n                  order 1,0,0,1,0\n        !*/\n\n\n        int multi_read (\n            unsigned long& data,\n            int num_to_read\n        );\n        /*!\n            requires\n                - is_in_read_mode() == true \n                - 0 <= num_to_read <= 32\n            ensures\n                - tries to read num_to_read bits into the low order end of #data       \n                  example:  if the incoming bits were 10010 then data would end \n                  up with 10010 as its low order bits\n                - all of the bits in #data not filled in by multi_read() are zero             \n                - returns the number of bits actually read into #data\n        !*/\n\n    };\n\n    template <\n        typename bit_stream_base\n        >\n    inline void swap (\n        bit_stream_multi<bit_stream_base>& a, \n        bit_stream_multi<bit_stream_base>& b \n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_BIT_STREAM_MULTi_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/bit_stream/bit_stream_multi_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAM_MULTi_C_\n#define DLIB_BIT_STREAM_MULTi_C_\n\n#include \"bit_stream_multi_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n    template <\n        typename bit_stream_base // implements bit_stream/bit_stream_multi_abstract.h\n        >\n    class bit_stream_multi_c : public bit_stream_base\n    {\n    public:\n\n        void multi_write (\n            unsigned long data,\n            int num_to_write\n        );\n\n        int multi_read (\n            unsigned long& data,\n            int num_to_read\n        );\n\n    };\n\n    template <\n        typename bit_stream_base\n        >\n    inline void swap (\n        bit_stream_multi_c<bit_stream_base>& a, \n        bit_stream_multi_c<bit_stream_base>& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    void bit_stream_multi_c<bit_stream_base>:: \n    multi_write (\n        unsigned long data,\n        int num_to_write\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->is_in_write_mode() == true) && (num_to_write >= 0 && num_to_write <=32), \n            \"\\tvoid bit_stream::write\"\n            << \"\\n\\tthe bit stream bust be in write mode and\"\n            << \"\\n\\tnum_to_write must be between 0 and 32 inclusive\" \n            << \"\\n\\tnum_to_write == \" << num_to_write\n            << \"\\n\\tis_in_write_mode() == \" << this->is_in_write_mode()\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        bit_stream_base::multi_write(data,num_to_write);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename bit_stream_base\n        >\n    int bit_stream_multi_c<bit_stream_base>:: \n    multi_read (\n        unsigned long& data,\n        int num_to_read\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( this->is_in_read_mode() == true && ( num_to_read >= 0 && num_to_read <=32 ) ), \n            \"\\tvoid bit_stream::read\"\n            << \"\\n\\tyou can't read from a bit_stream that isn't in read mode and\" \n            << \"\\n\\tnum_to_read must be between 0 and 32 inclusive\"\n            << \"\\n\\tnum_to_read == \" << num_to_read\n            << \"\\n\\tis_in_read_mode() == \" << this->is_in_read_mode()\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return bit_stream_base::multi_read(data,num_to_read);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BIT_STREAM_MULTi_C_\n\n"
  },
  {
    "path": "dlib/bit_stream.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BIT_STREAm_\n#define DLIB_BIT_STREAm_\n\n#include \"bit_stream/bit_stream_kernel_1.h\"\n#include \"bit_stream/bit_stream_kernel_c.h\"\n\n#include \"bit_stream/bit_stream_multi_1.h\"\n#include \"bit_stream/bit_stream_multi_c.h\"\n\nnamespace dlib\n{\n\n\n    class bit_stream\n    {\n        bit_stream() {}\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     bit_stream_kernel_1    \n                    kernel_1a;\n        typedef     bit_stream_kernel_c<kernel_1a >\n                    kernel_1a_c;\n\n        //---------- extensions ------------\n\n        \n        // multi_1 extend kernel_1a\n        typedef     bit_stream_multi_1<kernel_1a>\n                    multi_1a;\n        typedef     bit_stream_multi_c<bit_stream_multi_1<kernel_1a_c> >\n                    multi_1a_c;\n\n    };\n}\n\n#endif // DLIB_BIT_STREAm_\n\n"
  },
  {
    "path": "dlib/bits/c++config.h",
    "content": "#include \"../dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/bound_function_pointer/bound_function_pointer_kernel_1.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_\n#define DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"../member_function_pointer.h\"\n#include \"bound_function_pointer_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace bfp1_helpers\n    {\n        template <typename T> struct strip { typedef T type; };\n        template <typename T> struct strip<T&> { typedef T type; };\n\n    // ------------------------------------------------------------------------------------\n\n        class bound_function_helper_base_base\n        {\n        public:\n            virtual ~bound_function_helper_base_base(){}\n            virtual void call() const = 0;\n            virtual bool is_set() const = 0;\n            virtual void clone(void* ptr) const = 0;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T1, typename T2, typename T3, typename T4>\n        class bound_function_helper_base : public bound_function_helper_base_base\n        {\n        public:\n            bound_function_helper_base():arg1(0), arg2(0), arg3(0), arg4(0) {}\n\n            typename strip<T1>::type* arg1;\n            typename strip<T2>::type* arg2;\n            typename strip<T3>::type* arg3;\n            typename strip<T4>::type* arg4;\n\n\n            member_function_pointer<T1,T2,T3,T4> mfp;\n        };\n\n    // ----------------\n\n        template <typename F, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void>\n        class bound_function_helper : public bound_function_helper_base<T1,T2,T3,T4>\n        {\n        public:\n            void call() const\n            {\n                (*fp)(*this->arg1, *this->arg2, *this->arg3, *this->arg4);\n            }\n\n            typename strip<F>::type* fp;\n        };\n\n        template <typename T1, typename T2, typename T3, typename T4>\n        class bound_function_helper<void,T1,T2,T3,T4> : public bound_function_helper_base<T1,T2,T3,T4>\n        {\n        public:\n            void call() const\n            {\n                if (this->mfp)    this->mfp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);\n                else if (fp) fp(*this->arg1, *this->arg2, *this->arg3, *this->arg4);\n            }\n\n            void (*fp)(T1, T2, T3, T4);\n        };\n\n    // ----------------\n\n        template <typename F>\n        class bound_function_helper<F,void,void,void,void> : public bound_function_helper_base<void,void,void,void>\n        {\n        public:\n            void call() const\n            {\n                (*fp)();\n            }\n\n            typename strip<F>::type* fp;\n        };\n\n        template <>\n        class bound_function_helper<void,void,void,void,void> : public bound_function_helper_base<void,void,void,void>\n        {\n        public:\n            void call() const\n            {\n                if (this->mfp)    this->mfp();\n                else if (fp) fp();\n            }\n\n            void (*fp)();\n        };\n\n    // ----------------\n\n        template <typename F, typename T1>\n        class bound_function_helper<F,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>\n        {\n        public:\n            void call() const\n            {\n                (*fp)(*this->arg1);\n            }\n\n            typename strip<F>::type* fp;\n        };\n\n        template <typename T1>\n        class bound_function_helper<void,T1,void,void,void> : public bound_function_helper_base<T1,void,void,void>\n        {\n        public:\n            void call() const\n            {\n                if (this->mfp)    this->mfp(*this->arg1);\n                else if (fp) fp(*this->arg1);\n            }\n\n            void (*fp)(T1);\n        };\n\n    // ----------------\n\n        template <typename F, typename T1, typename T2>\n        class bound_function_helper<F,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>\n        {\n        public:\n            void call() const\n            {\n                (*fp)(*this->arg1, *this->arg2);\n            }\n\n            typename strip<F>::type* fp;\n        };\n\n        template <typename T1, typename T2>\n        class bound_function_helper<void,T1,T2,void,void> : public bound_function_helper_base<T1,T2,void,void>\n        {\n        public:\n            void call() const\n            {\n                if (this->mfp)    this->mfp(*this->arg1, *this->arg2);\n                else if (fp) fp(*this->arg1, *this->arg2);\n            }\n\n            void (*fp)(T1, T2);\n        };\n\n    // ----------------\n\n        template <typename F, typename T1, typename T2, typename T3>\n        class bound_function_helper<F,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>\n        {\n        public:\n            void call() const\n            {\n                (*fp)(*this->arg1, *this->arg2, *this->arg3);\n            }\n\n            typename strip<F>::type* fp;\n        };\n\n        template <typename T1, typename T2, typename T3>\n        class bound_function_helper<void,T1,T2,T3,void> : public bound_function_helper_base<T1,T2,T3,void>\n        {\n        public:\n\n            void call() const\n            {\n                if (this->mfp)    this->mfp(*this->arg1, *this->arg2, *this->arg3);\n                else if (fp) fp(*this->arg1, *this->arg2, *this->arg3);\n            }\n\n            void (*fp)(T1, T2, T3);\n        };\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        class bound_function_helper_T : public T\n        {\n        public:\n            bound_function_helper_T(){ this->fp = 0;}\n\n            bool is_set() const\n            {\n                return this->fp != 0 || this->mfp.is_set();\n            }\n\n            template <unsigned long mem_size>\n            void safe_clone(stack_based_memory_block<mem_size>& buf)\n            {\n                // This is here just to validate the assumption that our block of memory we have made\n                // in bf_memory is the right size to store the data for this object.  If you\n                // get a compiler error on this line then email me :)\n                COMPILE_TIME_ASSERT(sizeof(bound_function_helper_T) <= mem_size);\n                clone(buf.get());\n            }\n\n            void clone   (void* ptr) const  \n            { \n                bound_function_helper_T* p = new(ptr) bound_function_helper_T(); \n                p->arg1 = this->arg1;\n                p->arg2 = this->arg2;\n                p->arg3 = this->arg3;\n                p->arg4 = this->arg4;\n                p->fp = this->fp;\n                p->mfp = this->mfp;\n            }\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class bound_function_pointer\n    {\n        typedef bfp1_helpers::bound_function_helper_T<bfp1_helpers::bound_function_helper<void,int> > bf_null_type;\n\n    public:\n\n        // These typedefs are here for backwards compatibility with previous versions of\n        // dlib.\n        typedef bound_function_pointer kernel_1a;\n        typedef bound_function_pointer kernel_1a_c;\n\n\n        bound_function_pointer (\n        ) { bf_null_type().safe_clone(bf_memory); }\n\n        bound_function_pointer ( \n            const bound_function_pointer& item\n        ) { item.bf()->clone(bf_memory.get()); }\n\n        ~bound_function_pointer()\n        { destroy_bf_memory(); }\n\n        bound_function_pointer& operator= (\n            const bound_function_pointer& item\n        ) { bound_function_pointer(item).swap(*this); return *this; }\n\n        void clear (\n        ) { bound_function_pointer().swap(*this); }\n\n        bool is_set (\n        ) const\n        {\n            return bf()->is_set();\n        }\n\n        void swap (\n            bound_function_pointer& item\n        )\n        {\n            // make a temp copy of item\n            bound_function_pointer temp(item);\n\n            // destory the stuff in item\n            item.destroy_bf_memory();\n            // copy *this into item\n            bf()->clone(item.bf_memory.get());\n\n            // destory the stuff in this \n            destroy_bf_memory();\n            // copy temp into *this\n            temp.bf()->clone(bf_memory.get());\n        }\n\n        void operator() (\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_set() == true ,\n                \"\\tvoid bound_function_pointer::operator()\"\n                << \"\\n\\tYou must call set() before you can use this function\"\n                << \"\\n\\tthis: \" << this\n            );\n\n            bf()->call();\n        }\n\n    private:\n        struct dummy{ void nonnull() {}};\n        typedef void (dummy::*safe_bool)();\n\n    public:\n        operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; }\n        bool operator!() const { return !is_set(); }\n\n    // -------------------------------------------\n    //      set function object overloads\n    // -------------------------------------------\n\n        template <typename F>\n        void set (\n            F& function_object\n        )\n        {\n            COMPILE_TIME_ASSERT(std::is_function<F>::value == false);\n            COMPILE_TIME_ASSERT(std::is_pointer<F>::value == false);\n            \n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<F> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.fp = &function_object;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename F, typename A1 >\n        void set (\n            F& function_object,\n            A1& arg1\n        )\n        {\n            COMPILE_TIME_ASSERT(std::is_function<F>::value == false);\n            COMPILE_TIME_ASSERT(std::is_pointer<F>::value == false);\n            \n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<F,A1> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.fp = &function_object;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename F, typename A1, typename A2 >\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2\n        )\n        {\n            COMPILE_TIME_ASSERT(std::is_function<F>::value == false);\n            COMPILE_TIME_ASSERT(std::is_pointer<F>::value == false);\n            \n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<F,A1,A2> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.fp = &function_object;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename F, typename A1, typename A2, typename A3 >\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        )\n        {\n            COMPILE_TIME_ASSERT(std::is_function<F>::value == false);\n            COMPILE_TIME_ASSERT(std::is_pointer<F>::value == false);\n            \n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.fp = &function_object;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename F, typename A1, typename A2, typename A3, typename A4>\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        )\n        {\n            COMPILE_TIME_ASSERT(std::is_function<F>::value == false);\n            COMPILE_TIME_ASSERT(std::is_pointer<F>::value == false);\n            \n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<F,A1,A2,A3,A4> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.arg4 = &arg4;\n            temp.fp = &function_object;\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // -------------------------------------------\n    //      set mfp overloads\n    // -------------------------------------------\n\n        template <typename T>\n        void set (\n            T& object,\n            void (T::*funct)()\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T >\n        void set (\n            const T& object,\n            void (T::*funct)()const\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // -------------------------------------------\n\n        template <typename T, typename T1, typename A1 >\n        void set (\n            T& object,\n            void (T::*funct)(T1),\n            A1& arg1\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T, typename T1, typename A1 >\n        void set (\n            const T& object,\n            void (T::*funct)(T1)const,\n            A1& arg1\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // ----------------\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2>\n        void set (\n            T& object,\n            void (T::*funct)(T1, T2),\n            A1& arg1,\n            A2& arg2\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2>\n        void set (\n            const T& object,\n            void (T::*funct)(T1, T2)const,\n            A1& arg1,\n            A2& arg2\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // ----------------\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3>\n        void set (\n            T& object,\n            void (T::*funct)(T1, T2, T3),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3>\n        void set (\n            const T& object,\n            void (T::*funct)(T1, T2, T3)const,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // ----------------\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3,\n        typename T4, typename A4>\n        void set (\n            T& object,\n            void (T::*funct)(T1, T2, T3, T4),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.arg4 = &arg4;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T, typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3,\n        typename T4, typename A4>\n        void set (\n            const T& object,\n            void (T::*funct)(T1, T2, T3, T4)const,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.arg4 = &arg4;\n            temp.mfp.set(object,funct);\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // -------------------------------------------\n    //      set fp overloads\n    // -------------------------------------------\n\n        void set (\n            void (*funct)()\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.fp = funct;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T1, typename A1>\n        void set (\n            void (*funct)(T1),\n            A1& arg1\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.fp = funct;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T1, typename A1,\n        typename T2, typename A2>\n        void set (\n            void (*funct)(T1, T2),\n            A1& arg1,\n            A2& arg2\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.fp = funct;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3>\n        void set (\n            void (*funct)(T1, T2, T3),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.fp = funct;\n\n            temp.safe_clone(bf_memory);\n        }\n\n        template <typename T1, typename A1,\n        typename T2, typename A2,\n        typename T3, typename A3,\n        typename T4, typename A4>\n        void set (\n            void (*funct)(T1, T2, T3, T4),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        )\n        {\n            using namespace bfp1_helpers;\n            destroy_bf_memory();\n            typedef bound_function_helper_T<bound_function_helper<void,T1,T2,T3,T4> > bf_helper_type;\n\n            bf_helper_type temp;\n            temp.arg1 = &arg1;\n            temp.arg2 = &arg2;\n            temp.arg3 = &arg3;\n            temp.arg4 = &arg4;\n            temp.fp = funct;\n\n            temp.safe_clone(bf_memory);\n        }\n\n    // -------------------------------------------\n\n    private:\n\n        stack_based_memory_block<sizeof(bf_null_type)> bf_memory;\n\n        void destroy_bf_memory (\n        )\n        {\n            // Honestly, this probably doesn't even do anything but I'm putting\n            // it here just for good measure.\n            bf()->~bound_function_helper_base_base();\n        }\n\n        bfp1_helpers::bound_function_helper_base_base*       bf ()       \n        { return static_cast<bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }\n\n        const bfp1_helpers::bound_function_helper_base_base* bf () const \n        { return static_cast<const bfp1_helpers::bound_function_helper_base_base*>(bf_memory.get()); }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        bound_function_pointer& a,\n        bound_function_pointer& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/bound_function_pointer/bound_function_pointer_kernel_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_\n#ifdef DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class bound_function_pointer\n    {\n        /*!\n            INITIAL VALUE\n                is_set() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a function with all its arguments bound to \n                specific objects.  For example:\n\n                    void test(int& var) { var = var+1; }\n\n                    bound_function_pointer funct;\n\n                    int a = 4; \n                    funct.set(test,a); // bind the variable a to the first argument of the test() function \n\n                    // at this point a == 4\n                    funct();\n                    // after funct() is called a == 5\n        !*/\n\n    public:\n\n        bound_function_pointer (  \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n        !*/\n\n        bound_function_pointer(\n            const bound_function_pointer& item\n        );\n        /*!\n            ensures\n                - *this == item\n        !*/\n\n        ~bound_function_pointer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        bound_function_pointer& operator=(\n            const bound_function_pointer& item\n        );\n        /*!\n            ensures\n                - *this == item\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n        !*/\n\n        bool is_set (\n        ) const;\n        /*!\n            ensures\n                - if (this->set() has been called) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        operator some_undefined_pointer_type (\n        ) const;\n        /*!\n            ensures\n                - if (is_set()) then\n                    - returns a non 0 value\n                - else\n                    - returns a 0 value\n        !*/\n\n        bool operator! (\n        ) const;\n        /*!\n            ensures\n                - returns !is_set()\n        !*/\n\n        void operator () (\n        ) const;\n        /*!\n            requires\n                - is_set() == true\n            ensures\n                - calls the bound function on the object(s) specified by the last \n                  call to this->set()\n            throws\n                - any exception thrown by the function specified by\n                  the previous call to this->set().\n                    If any of these exceptions are thrown then the call to this \n                    function will have no effect on *this.                  \n        !*/\n\n        void swap (\n            bound_function_pointer& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n        // ----------------------\n\n        template <typename F>\n        void set (\n            F& function_object\n        );\n        /*!\n            requires\n                - function_object() is a valid expression \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call function_object()\n                  (This seems pointless but it is a useful base case)\n        !*/\n\n        template < typename T>\n        void set (\n            T& object,\n            void (T::*funct)()\n        );\n        /*!\n            requires\n                - funct == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)()\n        !*/\n\n        template < typename T>\n        void set (\n            const T& object,\n            void (T::*funct)()const\n        );\n        /*!\n            requires\n                - funct == a valid bound function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)()\n        !*/\n\n        void set (\n            void (*funct)()\n        );\n        /*!\n            requires\n                - funct == a valid function pointer \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call funct()\n        !*/\n\n        // ----------------------\n\n        template <typename F, typename A1 >\n        void set (\n            F& function_object,\n            A1& arg1\n        );\n        /*!\n            requires\n                - function_object(arg1) is a valid expression \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call function_object(arg1)\n        !*/\n\n        template < typename T, typename T1, typename A1 >\n        void set (\n            T& object,\n            void (T::*funct)(T1),\n            A1& arg1\n        );\n        /*!\n            requires\n                - funct == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1)\n        !*/\n\n        template < typename T, typename T1, typename A1 >\n        void set (\n            const T& object,\n            void (T::*funct)(T1)const,\n            A1& arg1\n        );\n        /*!\n            requires\n                - funct == a valid bound function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1)\n        !*/\n\n        template <typename T1, typename A1>\n        void set (\n            void (*funct)(T1),\n            A1& arg1\n        );\n        /*!\n            requires\n                - funct == a valid function pointer \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call funct(arg1)\n        !*/\n\n        // ----------------------\n        template <typename F, typename A1, typename A2 >\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2\n        );\n        /*!\n            requires\n                - function_object(arg1,arg2) is a valid expression \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call function_object(arg1,arg2)\n        !*/\n\n        template < typename T, typename T1, typename A1,\n                               typename T2, typename A2>\n        void set (\n            T& object,\n            void (T::*funct)(T1,T2),\n            A1& arg1,\n            A2& arg2\n        );\n        /*!\n            requires\n                - funct == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2)\n        !*/\n\n        template < typename T, typename T1, typename A1, \n                               typename T2, typename A2>\n        void set (\n            const T& object,\n            void (T::*funct)(T1,T2)const,\n            A1& arg1,\n            A2& arg2\n        );\n        /*!\n            requires\n                - funct == a valid bound function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2)\n        !*/\n\n        template <typename T1, typename A1,\n                  typename T2, typename A2>\n        void set (\n            void (*funct)(T1,T2),\n            A1& arg1,\n            A2& arg2\n        );\n        /*!\n            requires\n                - funct == a valid function pointer \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call funct(arg1,arg2)\n        !*/\n\n        // ----------------------\n\n        template <typename F, typename A1, typename A2, typename A3 >\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        );\n        /*!\n            requires\n                - function_object(arg1,arg2,arg3) is a valid expression \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call function_object(arg1,arg2,arg3)\n        !*/\n\n        template < typename T, typename T1, typename A1,\n                               typename T2, typename A2,\n                               typename T3, typename A3>\n        void set (\n            T& object,\n            void (T::*funct)(T1,T2,T3),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        );\n        /*!\n            requires\n                - funct == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)\n        !*/\n\n        template < typename T, typename T1, typename A1,\n                               typename T2, typename A2,\n                               typename T3, typename A3>\n        void set (\n            const T& object,\n            void (T::*funct)(T1,T2,T3)const,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        );\n        /*!\n            requires\n                - funct == a valid bound function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3)\n        !*/\n\n        template <typename T1, typename A1,\n                  typename T2, typename A2,\n                  typename T3, typename A3>\n        void set (\n            void (*funct)(T1,T2,T3),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3\n        );\n        /*!\n            requires\n                - funct == a valid function pointer \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call funct(arg1,arg2,arg3)\n        !*/\n\n        // ----------------------\n\n        template <typename F, typename A1, typename A2, typename A3, typename A4>\n        void set (\n            F& function_object,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        );\n        /*!\n            requires\n                - function_object(arg1,arg2,arg3,arg4) is a valid expression \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call function_object(arg1,arg2,arg3,arg4)\n        !*/\n\n        template < typename T, typename T1, typename A1,\n                               typename T2, typename A2,\n                               typename T3, typename A3,\n                               typename T4, typename A4>\n        void set (\n            T& object,\n            void (T::*funct)(T1,T2,T3,T4),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        );\n        /*!\n            requires\n                - funct == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)\n        !*/\n\n        template < typename T, typename T1, typename A1,\n                               typename T2, typename A2,\n                               typename T3, typename A3,\n                               typename T4, typename A4>\n        void set (\n            const T& object,\n            void (T::*funct)(T1,T2,T3,T4)const,\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        );\n        /*!\n            requires\n                - funct == a valid bound function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*funct)(arg1,arg2,arg3,arg4)\n        !*/\n\n        template <typename T1, typename A1,\n                  typename T2, typename A2,\n                  typename T3, typename A3,\n                  typename T4, typename A4>\n        void set (\n            void (*funct)(T1,T2,T3,T4),\n            A1& arg1,\n            A2& arg2,\n            A3& arg3,\n            A4& arg4\n        );\n        /*!\n            requires\n                - funct == a valid function pointer \n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call funct(arg1,arg2,arg3,arg4)\n        !*/\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        bound_function_pointer& a,\n        bound_function_pointer& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOUND_FUNCTION_POINTER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/bound_function_pointer.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BOUND_FUNCTION_POINTEr_\n#define DLIB_BOUND_FUNCTION_POINTEr_\n\n#include \"bound_function_pointer/bound_function_pointer_kernel_1.h\"\n\n#endif // DLIB_BOUND_FUNCTION_POINTEr_ \n\n\n"
  },
  {
    "path": "dlib/bridge/bridge.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BRIDGe_Hh_\n#define DLIB_BRIDGe_Hh_\n\n#include <iostream>\n#include <memory>\n#include <string>\n\n#include \"bridge_abstract.h\"\n#include \"../pipe.h\"\n#include \"../threads.h\"\n#include \"../serialize.h\"\n#include \"../sockets.h\"\n#include \"../sockstreambuf.h\"\n#include \"../logger.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------- \n\n    struct connect_to_ip_and_port\n    {\n        connect_to_ip_and_port (\n            const std::string& ip_,\n            unsigned short port_\n        ): ip(ip_), port(port_)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_ip_address(ip) && port != 0,\n                \"\\t connect_to_ip_and_port()\"\n                << \"\\n\\t Invalid inputs were given to this function\"\n                << \"\\n\\t ip:   \" << ip \n                << \"\\n\\t port: \" << port\n                << \"\\n\\t this: \" << this\n                );\n        }\n\n    private:\n        friend class bridge;\n        const std::string ip;\n        const unsigned short port;\n    };\n\n    inline connect_to_ip_and_port connect_to (\n        const network_address& addr\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(addr.port != 0,\n            \"\\t connect_to_ip_and_port()\"\n            << \"\\n\\t The TCP port to connect to can't be 0.\"\n            << \"\\n\\t addr.port: \" << addr.port\n            );\n\n        if (is_ip_address(addr.host_address))\n        {\n            return connect_to_ip_and_port(addr.host_address, addr.port);\n        }\n        else\n        {\n            std::string ip;\n            if(hostname_to_ip(addr.host_address,ip))\n                throw socket_error(ERESOLVE,\"unable to resolve '\" + addr.host_address + \"' in connect_to()\");\n\n            return connect_to_ip_and_port(ip, addr.port);\n        }\n    }\n\n    struct listen_on_port\n    {\n        listen_on_port(\n            unsigned short port_\n        ) : port(port_) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( port != 0,\n                \"\\t listen_on_port()\"\n                << \"\\n\\t Invalid inputs were given to this function\"\n                << \"\\n\\t port: \" << port\n                << \"\\n\\t this: \" << this\n                );\n        }\n\n    private:\n        friend class bridge;\n        const unsigned short port;\n    };\n\n    template <typename pipe_type>\n    struct bridge_transmit_decoration\n    {\n        bridge_transmit_decoration ( \n            pipe_type& p_\n        ) : p(p_) {}\n\n    private:\n        friend class bridge;\n        pipe_type& p;\n    };\n\n    template <typename pipe_type>\n    bridge_transmit_decoration<pipe_type> transmit ( pipe_type& p) { return bridge_transmit_decoration<pipe_type>(p); }\n\n    template <typename pipe_type>\n    struct bridge_receive_decoration\n    {\n        bridge_receive_decoration ( \n            pipe_type& p_\n        ) : p(p_) {}\n\n    private:\n        friend class bridge;\n        pipe_type& p;\n    };\n\n    template <typename pipe_type>\n    bridge_receive_decoration<pipe_type> receive ( pipe_type& p) { return bridge_receive_decoration<pipe_type>(p); }\n\n// ----------------------------------------------------------------------------------------\n\n    struct bridge_status\n    {\n        bridge_status() : is_connected(false), foreign_port(0){}\n\n        bool is_connected;\n        unsigned short foreign_port;\n        std::string foreign_ip;\n    };\n\n    inline void serialize ( const bridge_status& , std::ostream& )\n    {\n        throw serialization_error(\"It is illegal to serialize bridge_status objects.\");\n    }\n\n    inline void deserialize ( bridge_status& , std::istream& )\n    {\n        throw serialization_error(\"It is illegal to serialize bridge_status objects.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl_brns\n    {\n        class impl_bridge_base\n        {\n        public:\n\n            virtual ~impl_bridge_base() {}\n\n            virtual bridge_status get_bridge_status (\n            ) const = 0;\n        };\n\n        template <\n            typename transmit_pipe_type,\n            typename receive_pipe_type\n            >\n        class impl_bridge : public impl_bridge_base, private noncopyable, private multithreaded_object\n        {\n            /*!\n                CONVENTION\n                    - if (list) then\n                        - this object is supposed to be listening on the list object for incoming\n                          connections when not connected.\n                    - else\n                        - this object is supposed to be attempting to connect to ip:port when\n                          not connected.\n\n                    - get_bridge_status() == current_bs\n            !*/\n        public:\n\n            impl_bridge (\n                unsigned short listen_port,\n                transmit_pipe_type* transmit_pipe_,\n                receive_pipe_type* receive_pipe_\n            ) :\n                s(m),\n                receive_thread_active(false),\n                transmit_thread_active(false),\n                port(0),\n                transmit_pipe(transmit_pipe_),\n                receive_pipe(receive_pipe_),\n                dlog(\"dlib.bridge\"),\n                keepalive_code(0),\n                message_code(1)\n            {\n                int status = create_listener(list, listen_port);\n                if (status == PORTINUSE)\n                {\n                    std::ostringstream sout;\n                    sout << \"Error, the port \" << listen_port << \" is already in use.\";\n                    throw socket_error(EPORT_IN_USE, sout.str());\n                }\n                else if (status == OTHER_ERROR)\n                {\n                    throw socket_error(\"Unable to create listening socket for an unknown reason.\");\n                }\n\n                register_thread(*this, &impl_bridge::transmit_thread);\n                register_thread(*this, &impl_bridge::receive_thread);\n                register_thread(*this, &impl_bridge::connect_thread);\n\n                start();\n            }\n\n            impl_bridge (\n                const std::string ip_,\n                unsigned short port_,\n                transmit_pipe_type* transmit_pipe_,\n                receive_pipe_type* receive_pipe_\n            ) :\n                s(m),\n                receive_thread_active(false),\n                transmit_thread_active(false),\n                port(port_),\n                ip(ip_),\n                transmit_pipe(transmit_pipe_),\n                receive_pipe(receive_pipe_),\n                dlog(\"dlib.bridge\"),\n                keepalive_code(0),\n                message_code(1)\n            {\n                register_thread(*this, &impl_bridge::transmit_thread);\n                register_thread(*this, &impl_bridge::receive_thread);\n                register_thread(*this, &impl_bridge::connect_thread);\n\n                start();\n            }\n\n            ~impl_bridge()\n            {\n                // tell the threads to terminate\n                stop();\n\n                // save current pipe enabled status so we can restore it to however\n                // it was before this destructor ran.\n                bool transmit_enabled = true;\n                bool receive_enabled = true;\n\n                // make any calls blocked on a pipe return immediately.\n                if (transmit_pipe)\n                {\n                    transmit_enabled = transmit_pipe->is_dequeue_enabled();\n                    transmit_pipe->disable_dequeue();\n                }\n                if (receive_pipe)\n                {\n                    receive_enabled = receive_pipe->is_enqueue_enabled();\n                    receive_pipe->disable_enqueue();\n                }\n\n                {\n                    auto_mutex lock(m);\n                    s.broadcast();\n                    // Shutdown the connection if we have one.  This will cause\n                    // all blocked I/O calls to return an error.\n                    if (con)\n                        con->shutdown();\n                }\n\n                // wait for all the threads to terminate.\n                wait();\n\n                if (transmit_pipe && transmit_enabled)\n                    transmit_pipe->enable_dequeue();\n                if (receive_pipe && receive_enabled)\n                    receive_pipe->enable_enqueue();\n            }\n\n            bridge_status get_bridge_status (\n            ) const\n            {\n                auto_mutex lock(current_bs_mutex);\n                return current_bs;\n            }\n\n        private:\n\n\n            template <typename pipe_type>\n            std::enable_if_t<std::is_convertible<bridge_status, typename pipe_type::type>::value>  enqueue_bridge_status (\n                pipe_type* p,\n                const bridge_status& status\n            )\n            {\n                if (p)\n                {\n                    typename pipe_type::type temp(status);\n                    p->enqueue(temp);\n                }\n            }\n\n            template <typename pipe_type>\n            std::enable_if_t<!std::is_convertible<bridge_status, typename pipe_type::type>::value>  enqueue_bridge_status (\n                pipe_type* ,\n                const bridge_status& \n            )\n            {\n            }\n\n            void connect_thread (\n            )\n            {\n                while (!should_stop())\n                {\n                    auto_mutex lock(m);\n                    int status = OTHER_ERROR;\n                    if (list)\n                    {\n                        do\n                        {\n                            status = list->accept(con, 1000);\n                        } while (status == TIMEOUT && !should_stop());\n                    }\n                    else\n                    {\n                        status = create_connection(con, port, ip);\n                    }\n                    \n                    if (should_stop())\n                        break;\n\n                    if (status != 0)\n                    {\n                        // The last connection attempt failed.  So pause for a little bit before making another attempt.\n                        s.wait_or_timeout(2000);\n                        continue;\n                    }\n\n                    dlog << LINFO << \"Established new connection to \" << con->get_foreign_ip() << \":\" << con->get_foreign_port() << \".\";\n\n                    bridge_status temp_bs;\n                    {   auto_mutex lock(current_bs_mutex);\n                        current_bs.is_connected = true;\n                        current_bs.foreign_port = con->get_foreign_port();\n                        current_bs.foreign_ip = con->get_foreign_ip();\n                        temp_bs = current_bs;\n                    }\n                    enqueue_bridge_status(receive_pipe, temp_bs);\n\n\n                    receive_thread_active = true;\n                    transmit_thread_active = true;\n\n                    s.broadcast();\n\n                    // Wait for the transmit and receive threads to end before we continue.\n                    // This way we don't invalidate the con pointer while it is in use.\n                    while (receive_thread_active || transmit_thread_active)\n                        s.wait();\n\n\n                    dlog << LINFO << \"Closed connection to \" << con->get_foreign_ip() << \":\" << con->get_foreign_port() << \".\";\n                    {   auto_mutex lock(current_bs_mutex);\n                        current_bs.is_connected = false;\n                        current_bs.foreign_port = con->get_foreign_port();\n                        current_bs.foreign_ip = con->get_foreign_ip();\n                        temp_bs = current_bs;\n                    }\n                    enqueue_bridge_status(receive_pipe, temp_bs);\n                }\n\n            }\n\n\n            void receive_thread (\n            )\n            {\n                while (true)\n                {\n                    // wait until we have a connection\n                    {   auto_mutex lock(m);\n                        while (!receive_thread_active && !should_stop())\n                        {\n                            s.wait();\n                        }\n\n                        if (should_stop())\n                            break;\n                    }\n\n\n\n                    try\n                    {\n                        if (receive_pipe)\n                        {\n                            sockstreambuf buf(con);\n                            std::istream in(&buf);\n                            typename receive_pipe_type::type item;\n                            // This isn't necessary but doing it avoids a warning about\n                            // item being uninitialized sometimes.\n                            assign_zero_if_built_in_scalar_type(item);\n\n                            while (in.peek() != EOF)\n                            {\n                                unsigned char code;\n                                in.read((char*)&code, sizeof(code));\n                                if (code == message_code)\n                                {\n                                    deserialize(item, in);\n                                    receive_pipe->enqueue(item);\n                                }\n                            }\n                        }\n                        else\n                        {\n                            // Since we don't have a receive pipe to put messages into we will\n                            // just read the bytes from the connection and ignore them.\n                            char buf[1000];\n                            while (con->read(buf, sizeof(buf)) > 0) ;\n                        }\n                    }\n                    catch (std::bad_alloc& )\n                    {\n                        dlog << LERROR << \"std::bad_alloc thrown while deserializing message from \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port();\n                    }\n                    catch (dlib::serialization_error& e)\n                    {\n                        dlog << LERROR << \"dlib::serialization_error thrown while deserializing message from \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port() \n                            << \".\\nThe exception error message is: \\n\" << e.what();\n                    }\n                    catch (std::exception& e)\n                    {\n                        dlog << LERROR << \"std::exception thrown while deserializing message from \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port() \n                            << \".\\nThe exception error message is: \\n\" << e.what();\n                    }\n\n\n\n\n                    con->shutdown();\n                    auto_mutex lock(m);\n                    receive_thread_active = false;\n                    s.broadcast();\n                }\n\n                auto_mutex lock(m);\n                receive_thread_active = false;\n                s.broadcast();\n            }\n\n            void transmit_thread (\n            )\n            {\n                while (true)\n                {\n                    // wait until we have a connection\n                    {   auto_mutex lock(m);\n                        while (!transmit_thread_active && !should_stop())\n                        {\n                            s.wait();\n                        }\n\n                        if (should_stop())\n                            break;\n                    }\n\n\n\n                    try\n                    {\n                        sockstreambuf buf(con);\n                        std::ostream out(&buf);\n                        typename transmit_pipe_type::type item;\n                        // This isn't necessary but doing it avoids a warning about\n                        // item being uninitialized sometimes.\n                        assign_zero_if_built_in_scalar_type(item);\n\n\n                        while (out)\n                        {\n                            bool dequeue_timed_out = false;\n                            if (transmit_pipe )\n                            {\n                                if (transmit_pipe->dequeue_or_timeout(item,1000))\n                                {\n                                    out.write((char*)&message_code, sizeof(message_code));\n                                    serialize(item, out);\n                                    if (transmit_pipe->size() == 0)\n                                        out.flush();\n\n                                    continue;\n                                }\n\n                                dequeue_timed_out = (transmit_pipe->is_enabled() && transmit_pipe->is_dequeue_enabled());\n                            }\n\n                            // Pause for about a second.  Note that we use a wait_or_timeout() call rather \n                            // than sleep() here because we want to wake up immediately if this object is \n                            // being destructed rather than hang for a second.\n                            if (!dequeue_timed_out)\n                            {\n                                auto_mutex lock(m);\n                                if (should_stop())\n                                    break;\n\n                                s.wait_or_timeout(1000);\n                            }\n                            // Just send the keepalive byte periodically so we can\n                            // tell if the connection is alive. \n                            out.write((char*)&keepalive_code, sizeof(keepalive_code));\n                            out.flush();\n                        }\n                    }\n                    catch (std::bad_alloc& )\n                    {\n                        dlog << LERROR << \"std::bad_alloc thrown while serializing message to \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port();\n                    }\n                    catch (dlib::serialization_error& e)\n                    {\n                        dlog << LERROR << \"dlib::serialization_error thrown while serializing message to \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port() \n                            << \".\\nThe exception error message is: \\n\" << e.what();\n                    }\n                    catch (std::exception& e)\n                    {\n                        dlog << LERROR << \"std::exception thrown while serializing message to \" \n                            << con->get_foreign_ip() << \":\" << con->get_foreign_port() \n                            << \".\\nThe exception error message is: \\n\" << e.what();\n                    }\n\n\n\n\n                    con->shutdown();\n                    auto_mutex lock(m);\n                    transmit_thread_active = false;\n                    s.broadcast();\n                }\n\n                auto_mutex lock(m);\n                transmit_thread_active = false;\n                s.broadcast();\n            }\n\n            mutex m;\n            signaler s;\n            bool receive_thread_active;\n            bool transmit_thread_active;\n            std::unique_ptr<connection> con;\n            std::unique_ptr<listener> list;\n            const unsigned short port;\n            const std::string ip;\n            transmit_pipe_type* const transmit_pipe;\n            receive_pipe_type* const receive_pipe;\n            logger dlog;\n            const unsigned char keepalive_code;\n            const unsigned char message_code;\n\n            mutex current_bs_mutex;\n            bridge_status current_bs;\n        };\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    class bridge : noncopyable\n    {\n    public:\n\n        bridge () {}\n\n        template < typename T, typename U, typename V >\n        bridge (\n            T network_parameters,\n            U pipe1,\n            V pipe2 \n        ) { reconfigure(network_parameters,pipe1,pipe2); }\n\n        template < typename T, typename U>\n        bridge (\n            T network_parameters,\n            U pipe \n        ) { reconfigure(network_parameters,pipe); }\n\n\n        void clear (\n        )\n        {\n            pimpl.reset();\n        }\n\n        template < typename T, typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe,\n            bridge_receive_decoration<R> receive_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }\n\n        template < typename T, typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe,\n            bridge_transmit_decoration<T> transmit_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }\n\n        template < typename T >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,T>(network_parameters.port, &transmit_pipe.p, 0)); }\n\n        template < typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<R,R>(network_parameters.port, 0, &receive_pipe.p)); }\n\n\n\n\n        template < typename T, typename R >\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe,\n            bridge_receive_decoration<R> receive_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }\n\n        template < typename T, typename R >\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe,\n            bridge_transmit_decoration<T> transmit_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,R>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, &receive_pipe.p)); }\n\n        template < typename R >\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<R,R>(network_parameters.ip, network_parameters.port, 0, &receive_pipe.p)); }\n\n        template < typename T >\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe\n        ) { pimpl.reset(); pimpl.reset(new impl_brns::impl_bridge<T,T>(network_parameters.ip, network_parameters.port, &transmit_pipe.p, 0)); }\n\n\n        bridge_status get_bridge_status (\n        ) const\n        {\n            if (pimpl)\n                return pimpl->get_bridge_status();\n            else\n                return bridge_status();\n        }\n\n    private:\n\n        std::unique_ptr<impl_brns::impl_bridge_base> pimpl;\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n}\n\n#endif // DLIB_BRIDGe_Hh_\n\n"
  },
  {
    "path": "dlib/bridge/bridge_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BRIDGe_ABSTRACT_\n#ifdef DLIB_BRIDGe_ABSTRACT_\n\n#include <string>\n#include \"../pipe/pipe_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------- \n\n    struct connect_to_ip_and_port\n    {\n        connect_to_ip_and_port (\n            const std::string& ip,\n            unsigned short port\n        );\n        /*!\n            requires\n                - is_ip_address(ip) == true\n                - port != 0\n            ensures\n                - this object will represent a request to make a TCP connection\n                  to the given IP address and port number.\n        !*/\n    };\n\n    connect_to_ip_and_port connect_to (\n        const network_address& addr\n    );\n    /*!\n        requires\n            - addr.port != 0\n        ensures\n            - converts the given network_address object into a connect_to_ip_and_port\n              object.\n    !*/\n\n    struct listen_on_port\n    {\n        listen_on_port(\n            unsigned short port\n        );\n        /*!\n            requires\n                - port != 0\n            ensures\n                - this object will represent a request to listen on the given\n                  port number for incoming TCP connections.\n        !*/\n    };\n\n    template <\n        typename pipe_type\n        >\n    bridge_transmit_decoration<pipe_type> transmit ( \n        pipe_type& p\n    ); \n    /*!\n        requires\n            - pipe_type is some kind of dlib::pipe object\n            - the objects in the pipe must be serializable\n        ensures\n            - Adds a type decoration to the given pipe, marking it as a transmit pipe, and \n              then returns it.  \n    !*/\n\n    template <\n        typename pipe_type\n        >\n    bridge_receive_decoration<pipe_type> receive ( \n        pipe_type& p\n    );\n    /*!\n        requires\n            - pipe_type is some kind of dlib::pipe object\n            - the objects in the pipe must be serializable\n        ensures\n            - Adds a type decoration to the given pipe, marking it as a receive pipe, and \n              then returns it.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct bridge_status\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This simple struct represents the state of a bridge object.  A\n                bridge is either connected or not.  If it is connected then it\n                is connected to a foreign host with an IP address and port number\n                as indicated by this object.\n        !*/\n        \n        bridge_status(\n        ); \n        /*!\n            ensures\n                - #is_connected == false\n                - #foreign_port == 0\n                - #foreign_ip == \"\"\n        !*/\n\n        bool is_connected;\n        unsigned short foreign_port;\n        std::string foreign_ip;\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n    class bridge : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for bridging a dlib::pipe object between\n                two network connected applications.  \n\n\n                Note also that this object contains a dlib::logger object\n                which will log various events taking place inside a bridge.\n                If you want to see these log messages then enable the logger\n                named \"dlib.bridge\".\n\n            \n            BRIDGE PROTOCOL DETAILS\n                The bridge object creates a single TCP connection between\n                two applications.  Whenever it sends an object from a pipe\n                over a TCP connection it sends a byte with the value 1 followed \n                immediately by the serialized copy of the object from the pipe. \n                The serialization is performed by calling the global serialize()\n                function.  \n\n                Additionally, a bridge object will periodically send bytes with\n                a value of 0 to ensure the TCP connection remains alive.  These\n                are just read and ignored.  \n        !*/\n\n    public:\n\n        bridge (\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n                - #get_bridge_status().is_connected == false\n        !*/\n\n        template <typename T, typename U, typename V>\n        bridge (\n            T network_parameters,\n            U pipe1,\n            V pipe2 \n        ); \n        /*!\n            requires\n                - T is of type connect_to_ip_and_port or listen_on_port\n                - U and V are of type bridge_transmit_decoration or bridge_receive_decoration,\n                  however, U and V must be of different types (i.e. one is a receive type and \n                  another a transmit type).\n            ensures\n                - this object is properly initialized\n                - performs: reconfigure(network_parameters, pipe1, pipe2)\n                  (i.e. using this constructor is identical to using the default constructor \n                  and then calling reconfigure())\n        !*/\n\n        template <typename T, typename U>\n        bridge (\n            T network_parameters,\n            U pipe \n        ); \n        /*!\n            requires\n                - T is of type connect_to_ip_and_port or listen_on_port\n                - U is of type bridge_transmit_decoration or bridge_receive_decoration.\n            ensures\n                - this object is properly initialized\n                - performs: reconfigure(network_parameters, pipe)\n                  (i.e. using this constructor is identical to using the default constructor \n                  and then calling reconfigure())\n        !*/\n\n        ~bridge (\n        );\n        /*!\n            ensures\n                - blocks until all resources associated with this object have been destroyed.\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - returns this object to its default constructed state.  That is, it will\n                  be inactive, neither maintaining a connection nor attempting to acquire one.\n                - Any active connections or listening sockets will be closed.\n        !*/\n\n        bridge_status get_bridge_status (\n        ) const;\n        /*!\n            ensures\n                - returns the current status of this bridge object. In particular, returns \n                  an object BS such that:\n                    - BS.is_connected == true if and only if the bridge has an active TCP \n                      connection to another computer.\n                    - if (BS.is_connected) then\n                        - BS.foreign_ip == the IP address of the remote host we are connected to.\n                        - BS.foreign_port == the port number on the remote host we are connected to.\n                    - else if (the bridge has previously been connected to a remote host but hasn't been \n                               reconfigured or cleared since) then\n                        - BS.foreign_ip == the IP address of the remote host we were connected to.\n                        - BS.foreign_port == the port number on the remote host we were connected to.\n                    - else\n                        - BS.foreign_ip == \"\"\n                        - BS.foreign_port == 0\n        !*/\n\n\n\n        template < typename T, typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe,\n            bridge_receive_decoration<R> receive_pipe\n        ); \n        /*!\n            ensures\n                - This object will begin listening on the port specified by network_parameters\n                  for incoming TCP connections.  Any previous bridge state is cleared out.\n                - Onces a connection is established we will:\n                    - Stop accepting new connections.\n                    - Begin dequeuing objects from the transmit pipe and serializing them over \n                      the TCP connection.\n                    - Begin deserializing objects from the TCP connection and enqueueing them \n                      onto the receive pipe.\n                - if (the current TCP connection is lost) then \n                    - This object goes back to listening for a new connection.\n                - if (the receive pipe can contain bridge_status objects) then\n                    - Whenever the bridge's status changes the updated bridge_status will be\n                      enqueued onto the receive pipe unless the change was a TCP disconnect \n                      resulting from a user calling reconfigure(), clear(), or destructing this \n                      bridge.  The status contents are defined by get_bridge_status().\n            throws\n                - socket_error\n                  This exception is thrown if we are unable to open the listening socket.\n        !*/\n        template < typename T, typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe,\n            bridge_transmit_decoration<T> transmit_pipe\n        ); \n        /*!\n            ensures\n                - performs reconfigure(network_parameters, transmit_pipe, receive_pipe)\n        !*/\n        template < typename T >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe\n        );\n        /*!\n            ensures\n                - This function is identical to the above two reconfigure() functions \n                  except that there is no receive pipe.\n        !*/\n        template < typename R >\n        void reconfigure (\n            listen_on_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe\n        );\n        /*!\n            ensures\n                - This function is identical to the above three reconfigure() functions \n                  except that there is no transmit pipe.\n        !*/\n\n\n\n        template <typename T, typename R>\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe,\n            bridge_receive_decoration<R> receive_pipe\n        ); \n        /*!\n            ensures\n                - This object will begin making TCP connection attempts to the IP address and port \n                  specified by network_parameters.  Any previous bridge state is cleared out.\n                - Onces a connection is established we will:\n                    - Stop attempting new connections.\n                    - Begin dequeuing objects from the transmit pipe and serializing them over \n                      the TCP connection.\n                    - Begin deserializing objects from the TCP connection and enqueueing them \n                      onto the receive pipe.\n                - if (the current TCP connection is lost) then \n                    - This object goes back to attempting to make a TCP connection with the\n                      IP address and port specified by network_parameters.\n                - if (the receive pipe can contain bridge_status objects) then\n                    - Whenever the bridge's status changes the updated bridge_status will be\n                      enqueued onto the receive pipe unless the change was a TCP disconnect \n                      resulting from a user calling reconfigure(), clear(), or destructing this \n                      bridge.  The status contents are defined by get_bridge_status().\n        !*/\n        template <typename T, typename R>\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe,\n            bridge_transmit_decoration<T> transmit_pipe\n        ); \n        /*!\n            ensures\n                - performs reconfigure(network_parameters, transmit_pipe, receive_pipe)\n        !*/\n        template <typename T>\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_transmit_decoration<T> transmit_pipe\n        );\n        /*!\n            ensures\n                - This function is identical to the above two reconfigure() functions \n                  except that there is no receive pipe.\n        !*/\n        template <typename R>\n        void reconfigure (\n            connect_to_ip_and_port network_parameters,\n            bridge_receive_decoration<R> receive_pipe\n        );\n        /*!\n            ensures\n                - This function is identical to the above three reconfigure() functions \n                  except that there is no transmit pipe.\n        !*/\n\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n}\n\n#endif // DLIB_BRIDGe_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/bridge.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n\n#ifndef DLIB_BRIdGE_\n#define DLIB_BRIdGE_ \n\n\n#include \"bridge/bridge.h\"\n\n#endif // DLIB_BRIdGE_ \n\n\n"
  },
  {
    "path": "dlib/bsp/bsp.cpp",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BSP_CPph_\n#define DLIB_BSP_CPph_\n\n#include \"bsp.h\"\n#include <memory>\n#include <stack>\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n    namespace impl1\n    {\n\n        void connect_all (\n            map_id_to_con& cons,\n            const std::vector<network_address>& hosts,\n            unsigned long node_id\n        )\n        {\n            cons.clear();\n            for (unsigned long i = 0; i < hosts.size(); ++i)\n            {\n                std::unique_ptr<bsp_con> con(new bsp_con(hosts[i]));\n                dlib::serialize(node_id, con->stream); // tell the other end our node_id\n                unsigned long id = i+1;\n                cons.add(id, con);\n            }\n        }\n\n        void connect_all_hostinfo (\n            map_id_to_con& cons,\n            const std::vector<hostinfo>& hosts,\n            unsigned long node_id,\n            std::string& error_string \n        )\n        {\n            cons.clear();\n            for (unsigned long i = 0; i < hosts.size(); ++i)\n            {\n                try\n                {\n                    std::unique_ptr<bsp_con> con(new bsp_con(hosts[i].addr));\n                    dlib::serialize(node_id, con->stream); // tell the other end our node_id\n                    con->stream.flush();\n                    unsigned long id = hosts[i].node_id;\n                    cons.add(id, con);\n                }\n                catch (std::exception&)\n                {\n                    std::ostringstream sout;\n                    sout << \"Could not connect to \" << hosts[i].addr;\n                    error_string = sout.str();\n                    break;\n                }\n            }\n        }\n\n\n        void send_out_connection_orders (\n            map_id_to_con& cons,\n            const std::vector<network_address>& hosts\n        )\n        {\n            // tell everyone their node ids\n            cons.reset();\n            while (cons.move_next())\n            {\n                dlib::serialize(cons.element().key(), cons.element().value()->stream);\n            }\n\n            // now tell them who to connect to\n            std::vector<hostinfo> targets; \n            for (unsigned long i = 0; i < hosts.size(); ++i)\n            {\n                hostinfo info(hosts[i], i+1);\n\n                dlib::serialize(targets, cons[info.node_id]->stream);\n                targets.push_back(info);\n\n                // let the other host know how many incoming connections to expect\n                const unsigned long num = hosts.size()-targets.size();\n                dlib::serialize(num, cons[info.node_id]->stream);\n                cons[info.node_id]->stream.flush();\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl2\n    {\n        // These control bytes are sent before each message between nodes.  Note that many\n        // of these are only sent between the control node (node 0) and the other nodes.\n        // This is because the controller node is responsible for handling the\n        // synchronization that needs to happen when all nodes block on calls to\n        // receive_data()\n        // at the same time.\n\n        // denotes a normal content message.\n        const static char MESSAGE_HEADER            = 0; \n\n        // sent to the controller node when someone receives a message via receive_data().\n        const static char GOT_MESSAGE               = 1; \n\n        // sent to the controller node when someone sends a message via send().\n        const static char SENT_MESSAGE              = 2; \n\n        // sent to the controller node when someone enters a call to receive_data()\n        const static char IN_WAITING_STATE          = 3; \n\n        // broadcast when a node terminates itself. \n        const static char NODE_TERMINATE            = 5; \n\n        // broadcast by the controller node when it determines that all nodes are blocked\n        // on calls to receive_data() and there aren't any messages in flight.  This is also\n        // what makes us go to the next epoch.\n        const static char SEE_ALL_IN_WAITING_STATE  = 6; \n\n        // This isn't ever transmitted between nodes.  It is used internally to indicate\n        // that an error occurred.\n        const static char READ_ERROR                = 7;\n\n    // ------------------------------------------------------------------------------------\n\n        void read_thread (\n            impl1::bsp_con* con,\n            unsigned long node_id,\n            unsigned long sender_id,\n            impl1::thread_safe_message_queue& msg_buffer\n        )\n        {\n            try\n            {\n                while(true)\n                {\n                    impl1::msg_data msg;\n                    deserialize(msg.msg_type, con->stream);\n                    msg.sender_id = sender_id;\n\n                    if (msg.msg_type == MESSAGE_HEADER)\n                    {\n                        msg.data.reset(new std::vector<char>);\n                        deserialize(msg.epoch, con->stream);\n                        deserialize(*msg.data, con->stream);\n                    }\n\n                    msg_buffer.push_and_consume(msg);\n\n                    if (msg.msg_type == NODE_TERMINATE)\n                        break;\n                }\n            }\n            catch (std::exception& e)\n            {\n                impl1::msg_data msg;\n                msg.data.reset(new std::vector<char>);\n                vectorstream sout(*msg.data);\n                sout << \"An exception was thrown while attempting to receive a message from processing node \" << sender_id << \".\\n\";\n                sout << \"  Sending processing node address:   \" << con->con->get_foreign_ip() << \":\" << con->con->get_foreign_port() << std::endl;\n                sout << \"  Receiving processing node address: \" << con->con->get_local_ip() << \":\" << con->con->get_local_port() << std::endl;\n                sout << \"  Receiving processing node id:      \" << node_id << std::endl;\n                sout << \"  Error message in the exception:    \" << e.what() << std::endl;\n\n                msg.sender_id = sender_id;\n                msg.msg_type = READ_ERROR;\n\n                msg_buffer.push_and_consume(msg);\n            }\n            catch (...)\n            {\n                impl1::msg_data msg;\n                msg.data.reset(new std::vector<char>);\n                vectorstream sout(*msg.data);\n                sout << \"An exception was thrown while attempting to receive a message from processing node \" << sender_id << \".\\n\";\n                sout << \"  Sending processing node address:   \" << con->con->get_foreign_ip() << \":\" << con->con->get_foreign_port() << std::endl;\n                sout << \"  Receiving processing node address: \" << con->con->get_local_ip() << \":\" << con->con->get_local_port() << std::endl;\n                sout << \"  Receiving processing node id:      \" << node_id << std::endl;\n\n                msg.sender_id = sender_id;\n                msg.msg_type = READ_ERROR;\n\n                msg_buffer.push_and_consume(msg);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                          IMPLEMENTATION OF bsp_context OBJECT MEMBERS\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void bsp_context::\n    close_all_connections_gracefully(\n    )\n    {\n        if (node_id() != 0)\n        {\n            _cons.reset();\n            while (_cons.move_next())\n            {\n                // tell the other end that we are intentionally dropping the connection\n                serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream);\n                _cons.element().value()->stream.flush();\n            }\n        }\n\n        impl1::msg_data msg;\n        // now wait for all the other nodes to terminate\n        while (num_terminated_nodes < _cons.size() )\n        {\n            if (node_id() == 0 && num_waiting_nodes + num_terminated_nodes == _cons.size() && outstanding_messages == 0)\n            {\n                num_waiting_nodes = 0;\n                broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE);\n                ++current_epoch;\n            }\n\n            if (!msg_buffer.pop(msg))\n                throw dlib::socket_error(\"Error reading from msg_buffer in dlib::bsp_context.\");\n\n            if (msg.msg_type == impl2::NODE_TERMINATE)\n            {\n                ++num_terminated_nodes;\n                _cons[msg.sender_id]->terminated = true;\n            }\n            else if (msg.msg_type == impl2::READ_ERROR)\n            {\n                throw dlib::socket_error(msg.data_to_string());\n            }\n            else if (msg.msg_type == impl2::MESSAGE_HEADER)\n            {\n                throw dlib::socket_error(\"A BSP node received a message after it has terminated.\");\n            }\n            else if (msg.msg_type == impl2::GOT_MESSAGE)\n            {\n                --num_waiting_nodes;\n                --outstanding_messages;\n            }\n            else if (msg.msg_type == impl2::SENT_MESSAGE)\n            {\n                ++outstanding_messages;\n            }\n            else if (msg.msg_type == impl2::IN_WAITING_STATE)\n            {\n                ++num_waiting_nodes;\n            }\n        }\n\n        if (node_id() == 0)\n        {\n            _cons.reset();\n            while (_cons.move_next())\n            {\n                // tell the other end that we are intentionally dropping the connection\n                serialize(impl2::NODE_TERMINATE,_cons.element().value()->stream);\n                _cons.element().value()->stream.flush();\n            }\n\n            if (outstanding_messages != 0)\n            {\n                std::ostringstream sout;\n                sout << \"A BSP job was allowed to terminate before all sent messages have been received.\\n\";\n                sout << \"There are at least \" << outstanding_messages << \" messages still in flight.   Make sure all sent messages\\n\";\n                sout << \"have a corresponding call to receive().\";\n                throw dlib::socket_error(sout.str());\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bsp_context::\n    ~bsp_context()\n    {\n        _cons.reset();\n        while (_cons.move_next())\n        {\n            _cons.element().value()->con->shutdown();\n        }\n\n        msg_buffer.disable();\n\n        // this will wait for all the threads to terminate\n        threads.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bsp_context::\n    bsp_context(\n        unsigned long node_id_,\n        impl1::map_id_to_con& cons_\n    ) :\n        outstanding_messages(0),\n        num_waiting_nodes(0),\n        num_terminated_nodes(0),\n        current_epoch(1),\n        _cons(cons_),\n        _node_id(node_id_)\n    {\n        // spawn a bunch of read threads, one for each connection\n        _cons.reset();\n        while (_cons.move_next())\n        {\n            std::unique_ptr<thread_function> ptr(new thread_function(&impl2::read_thread,\n                                                                _cons.element().value().get(),\n                                                                _node_id,\n                                                                _cons.element().key(),\n                                                                ref(msg_buffer)));\n            threads.push_back(ptr);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bsp_context::\n    receive_data (\n        std::shared_ptr<std::vector<char> >& item,\n        unsigned long& sending_node_id\n    ) \n    {\n        notify_control_node(impl2::IN_WAITING_STATE);\n\n        while (true)\n        {\n            // If there aren't any nodes left to give us messages then return right now.\n            // We need to check the msg_buffer size to make sure there aren't any\n            // unprocessed message there.  Recall that this can happen because status\n            // messages always jump to the front of the message buffer.  So we might have\n            // learned about the node terminations before processing their messages for us.\n            if (num_terminated_nodes == _cons.size() && msg_buffer.size() == 0)\n            {\n                return false;\n            }\n\n            // if all running nodes are currently blocking forever on receive_data()\n            if (node_id() == 0 && outstanding_messages == 0 && num_terminated_nodes + num_waiting_nodes == _cons.size())\n            {\n                num_waiting_nodes = 0;\n                broadcast_byte(impl2::SEE_ALL_IN_WAITING_STATE);\n\n                // Note that the reason we have this epoch counter is so we can tell if a\n                // sent message is from before or after one of these \"all nodes waiting\"\n                // synchronization events.  If we didn't have the epoch count we would have\n                // a race condition where one node gets the SEE_ALL_IN_WAITING_STATE\n                // message before others and then sends out a message to another node\n                // before that node got the SEE_ALL_IN_WAITING_STATE message.  Then that\n                // node would think the normal message came before SEE_ALL_IN_WAITING_STATE\n                // which would be bad.\n                ++current_epoch;\n                return false;\n            }\n\n            impl1::msg_data data;\n            if (!msg_buffer.pop(data, current_epoch))\n                throw dlib::socket_error(\"Error reading from msg_buffer in dlib::bsp_context.\");\n\n\n            switch(data.msg_type)\n            {\n                case impl2::MESSAGE_HEADER: {\n                    item = data.data;\n                    sending_node_id = data.sender_id;\n                    notify_control_node(impl2::GOT_MESSAGE);\n                    return true;\n                } break;\n\n                case impl2::IN_WAITING_STATE: {\n                    ++num_waiting_nodes;\n                } break;\n\n                case impl2::GOT_MESSAGE: {\n                    --outstanding_messages;\n                    --num_waiting_nodes;\n                } break;\n\n                case impl2::SENT_MESSAGE: {\n                    ++outstanding_messages;\n                } break;\n\n                case impl2::NODE_TERMINATE: {\n                    ++num_terminated_nodes;\n                    _cons[data.sender_id]->terminated = true;\n                } break;\n\n                case impl2::SEE_ALL_IN_WAITING_STATE: {\n                    ++current_epoch;\n                    return false;\n                } break;\n\n                case impl2::READ_ERROR: {\n                    throw dlib::socket_error(data.data_to_string());\n                } break;\n\n                default: {\n                    throw dlib::socket_error(\"Unknown message received by dlib::bsp_context\");\n                } break;\n            } // end switch()\n        } // end while (true)\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bsp_context::\n    notify_control_node (\n        char val\n    )\n    {\n        if (node_id() == 0)\n        {\n            using namespace impl2;\n            switch(val)\n            {\n                case SENT_MESSAGE: {\n                    ++outstanding_messages;\n                } break;\n\n                case GOT_MESSAGE: {\n                    --outstanding_messages;\n                } break;\n\n                case IN_WAITING_STATE: {\n                    // nothing to do in this case\n                } break;\n\n                default:\n                    DLIB_CASSERT(false,\"This should never happen\");\n            }\n        }\n        else\n        {\n            serialize(val, _cons[0]->stream);\n            _cons[0]->stream.flush();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bsp_context::\n    broadcast_byte (\n        char val\n    )\n    {\n        for (unsigned long i = 0; i < number_of_nodes(); ++i)\n        {\n            // don't send to yourself or to terminated nodes\n            if (i == node_id() || _cons[i]->terminated)\n                continue;\n\n            serialize(val, _cons[i]->stream);\n            _cons[i]->stream.flush();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bsp_context::\n    send_data(\n        const std::vector<char>& item,\n        unsigned long target_node_id\n    ) \n    {\n        using namespace impl2;\n        if (_cons[target_node_id]->terminated)\n            throw socket_error(\"Attempt to send a message to a node that has terminated.\");\n\n        serialize(MESSAGE_HEADER, _cons[target_node_id]->stream);\n        serialize(current_epoch, _cons[target_node_id]->stream);\n        serialize(item, _cons[target_node_id]->stream);\n        _cons[target_node_id]->stream.flush();\n\n        notify_control_node(SENT_MESSAGE);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BSP_CPph_\n\n"
  },
  {
    "path": "dlib/bsp/bsp.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BsP_Hh_\n#define DLIB_BsP_Hh_\n\n#include \"bsp_abstract.h\"\n\n#include <memory>\n#include <queue>\n#include <vector>\n\n#include \"../sockets.h\"\n#include \"../array.h\"\n#include \"../sockstreambuf.h\"\n#include \"../string.h\"\n#include \"../serialize.h\"\n#include \"../map.h\"\n#include \"../ref.h\"\n#include \"../vectorstream.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl1\n    {\n        inline void null_notify(\n            unsigned short\n        ) {}\n\n        struct bsp_con\n        {\n            bsp_con(\n                const network_address& dest\n            ) : \n                con(connect(dest)),\n                buf(con),\n                stream(&buf),\n                terminated(false)\n            {\n                con->disable_nagle();\n            }\n\n            bsp_con(\n               std::unique_ptr<connection>& conptr \n            ) : \n                buf(conptr),\n                stream(&buf),\n                terminated(false)\n            {\n                // make sure we own the connection\n                conptr.swap(con);\n\n                con->disable_nagle();\n            }\n\n            std::unique_ptr<connection> con;\n            sockstreambuf buf;\n            std::iostream stream;\n            bool terminated;\n        };\n\n        typedef dlib::map<unsigned long, std::unique_ptr<bsp_con> >::kernel_1a_c map_id_to_con;\n\n        void connect_all (\n            map_id_to_con& cons,\n            const std::vector<network_address>& hosts,\n            unsigned long node_id\n        );\n        /*!\n            ensures\n                - creates connections to all the given hosts and stores them into cons\n        !*/\n\n        void send_out_connection_orders (\n            map_id_to_con& cons,\n            const std::vector<network_address>& hosts\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        struct hostinfo\n        {\n            hostinfo() {}\n            hostinfo (\n                const network_address& addr_,\n                unsigned long node_id_\n            ) : \n                addr(addr_),\n                node_id(node_id_)\n            {\n            }\n\n            network_address addr;\n            unsigned long node_id;\n        };\n\n        inline void serialize (\n            const hostinfo& item,\n            std::ostream& out\n        )\n        {\n            dlib::serialize(item.addr, out);\n            dlib::serialize(item.node_id, out);\n        }\n\n        inline void deserialize (\n            hostinfo& item,\n            std::istream& in\n        )\n        {\n            dlib::deserialize(item.addr, in);\n            dlib::deserialize(item.node_id, in);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void connect_all_hostinfo (\n            map_id_to_con& cons,\n            const std::vector<hostinfo>& hosts,\n            unsigned long node_id,\n            std::string& error_string \n        );\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename port_notify_function_type\n        >\n        void listen_and_connect_all(\n            unsigned long& node_id,\n            map_id_to_con& cons,\n            unsigned short port,\n            port_notify_function_type port_notify_function\n        )\n        {\n            cons.clear();\n            std::unique_ptr<listener> list;\n            const int status = create_listener(list, port);\n            if (status == PORTINUSE)\n            {\n                throw socket_error(\"Unable to create listening port \" + cast_to_string(port) +\n                                   \".  The port is already in use\");\n            }\n            else if (status != 0)\n            {\n                throw socket_error(\"Unable to create listening port \" + cast_to_string(port) );\n            }\n\n            port_notify_function(list->get_listening_port());\n\n            std::unique_ptr<connection> con;\n            if (list->accept(con))\n            {\n                throw socket_error(\"Error occurred while accepting new connection\");\n            }\n\n            std::unique_ptr<bsp_con> temp(new bsp_con(con));\n\n            unsigned long remote_node_id;\n            dlib::deserialize(remote_node_id, temp->stream);\n            dlib::deserialize(node_id, temp->stream);\n            std::vector<hostinfo> targets; \n            dlib::deserialize(targets, temp->stream);\n            unsigned long num_incoming_connections;\n            dlib::deserialize(num_incoming_connections, temp->stream);\n\n            cons.add(remote_node_id,temp);\n\n            // make a thread that will connect to all the targets\n            map_id_to_con cons2;\n            std::string error_string;\n            thread_function thread(connect_all_hostinfo, dlib::ref(cons2), dlib::ref(targets), node_id, dlib::ref(error_string));\n            if (error_string.size() != 0)\n                throw socket_error(error_string);\n\n            // accept any incoming connections\n            for (unsigned long i = 0; i < num_incoming_connections; ++i)\n            {\n                // If it takes more than 10 seconds for the other nodes to connect to us\n                // then something has gone horribly wrong and it almost certainly will\n                // never connect at all.  So just give up if that happens.\n                const unsigned long timeout_milliseconds = 10000;\n                if (list->accept(con, timeout_milliseconds))\n                {\n                    throw socket_error(\"Error occurred while accepting new connection\");\n                }\n\n                temp.reset(new bsp_con(con));\n\n                dlib::deserialize(remote_node_id, temp->stream);\n                cons.add(remote_node_id,temp);\n            }\n\n\n            // put all the connections created by the thread into cons\n            thread.wait();\n            while (cons2.size() > 0)\n            {\n                unsigned long id;\n                std::unique_ptr<bsp_con> temp;\n                cons2.remove_any(id,temp);\n                cons.add(id,temp);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        struct msg_data\n        {\n            std::shared_ptr<std::vector<char> > data;\n            unsigned long sender_id;\n            char msg_type;\n            dlib::uint64 epoch;\n\n            msg_data() : sender_id(0xFFFFFFFF), msg_type(-1), epoch(0) {}\n\n            std::string data_to_string() const\n            {\n                if (data && data->size() != 0)\n                    return std::string(&(*data)[0], data->size());\n                else\n                    return \"\";\n            }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        class thread_safe_message_queue : noncopyable\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a simple message queue for msg_data objects.  Note that it\n                    has the special property that, while messages will generally leave\n                    the queue in the order they are inserted, any message with a smaller\n                    epoch value will always be popped out first.  But for all messages\n                    with equal epoch values the queue functions as a normal FIFO queue.\n            !*/\n        private:\n            struct msg_wrap\n            {\n                msg_wrap(\n                    const msg_data& data_,\n                    const dlib::uint64& sequence_number_\n                ) : data(data_), sequence_number(sequence_number_) {}\n\n                msg_wrap() : sequence_number(0){}\n\n                msg_data data;\n                dlib::uint64 sequence_number;\n\n                // Make it so that when msg_wrap objects are in a std::priority_queue,\n                // messages with a smaller epoch number always come first.  Then, within an\n                // epoch, messages are ordered by their sequence number (so smaller first\n                // there as well).\n                bool operator<(const msg_wrap& item) const\n                {\n                    if (data.epoch < item.data.epoch)\n                    {\n                        return false;\n                    }\n                    else if (data.epoch > item.data.epoch)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        if (sequence_number < item.sequence_number)\n                            return false;\n                        else\n                            return true;\n                    }\n                }\n            };\n\n        public:\n            thread_safe_message_queue() : sig(class_mutex),disabled(false),next_seq_num(1) {}\n\n            ~thread_safe_message_queue()\n            {\n                disable();\n            }\n\n            void disable()\n            {\n                auto_mutex lock(class_mutex);\n                disabled = true;\n                sig.broadcast();\n            }\n\n            unsigned long size() const \n            { \n                auto_mutex lock(class_mutex);\n                return data.size(); \n            }\n\n            void push_and_consume( msg_data& item)\n            {\n                auto_mutex lock(class_mutex);\n                data.push(msg_wrap(item, next_seq_num++));\n                // do this here so that we don't have to worry about different threads touching the shared_ptr.\n                item.data.reset(); \n                sig.signal();\n            }\n\n            bool pop ( \n                msg_data& item\n            )\n            /*!\n                ensures\n                    - if (this function returns true) then\n                        - #item == the next thing from the queue\n                    - else\n                        - this object is disabled\n            !*/\n            {\n                auto_mutex lock(class_mutex);\n                while (data.size() == 0 && !disabled)\n                    sig.wait();\n\n                if (disabled)\n                    return false;\n\n                item = data.top().data;\n                data.pop();\n\n                return true;\n            }\n\n            bool pop ( \n                msg_data& item,\n                const dlib::uint64& max_epoch\n            )\n            /*!\n                ensures\n                    - if (this function returns true) then\n                        - #item == the next thing from the queue that has an epoch <= max_epoch\n                    - else\n                        - this object is disabled\n            !*/\n            {\n                auto_mutex lock(class_mutex);\n                while ((data.size() == 0 || data.top().data.epoch > max_epoch) && !disabled)\n                    sig.wait();\n\n                if (disabled)\n                    return false;\n\n                item = data.top().data;\n                data.pop();\n\n                return true;\n            }\n\n        private:\n            std::priority_queue<msg_wrap> data;\n            dlib::mutex class_mutex;\n            dlib::signaler sig;\n            bool disabled;\n            dlib::uint64 next_seq_num;\n        };\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class bsp_context : noncopyable\n    {\n\n    public:\n\n        template <typename T>\n        void send(\n            const T& item,\n            unsigned long target_node_id\n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(target_node_id < number_of_nodes() &&\n                        target_node_id != node_id(),\n                \"\\t void bsp_context::send()\"\n                << \"\\n\\t Invalid arguments were given to this function.\"\n                << \"\\n\\t target_node_id:    \" << target_node_id\n                << \"\\n\\t node_id():         \" << node_id()\n                << \"\\n\\t number_of_nodes(): \" << number_of_nodes()\n                << \"\\n\\t this: \" << this\n                );\n\n            std::vector<char> buf;\n            vectorstream sout(buf);\n            serialize(item, sout);\n            send_data(buf, target_node_id);\n        }\n\n        template <typename T>\n        void broadcast (\n            const T& item\n        ) \n        {\n            std::vector<char> buf;\n            vectorstream sout(buf);\n            serialize(item, sout);\n            for (unsigned long i = 0; i < number_of_nodes(); ++i)\n            {\n                // Don't send to yourself.\n                if (i == node_id())\n                    continue;\n\n                send_data(buf, i);\n            }\n        }\n\n        unsigned long node_id (\n        ) const { return _node_id; }\n\n        unsigned long number_of_nodes (\n        ) const { return _cons.size()+1; }\n\n        void receive (\n        )\n        {\n            unsigned long id;\n            std::shared_ptr<std::vector<char> > temp;\n            if (receive_data(temp,id))\n                throw dlib::socket_error(\"Call to bsp_context::receive() got an unexpected message.\");\n        }\n\n        template <typename T>\n        void receive (\n            T& item\n        ) \n        {\n            if(!try_receive(item))\n                throw dlib::socket_error(\"bsp_context::receive(): no messages to receive, all nodes currently blocked.\");\n        }\n\n        template <typename T>\n        bool try_receive (\n            T& item\n        ) \n        {\n            unsigned long sending_node_id;\n            return try_receive(item, sending_node_id);\n        }\n\n        template <typename T>\n        void receive (\n            T& item,\n            unsigned long& sending_node_id\n        ) \n        {\n            if(!try_receive(item, sending_node_id))\n                throw dlib::socket_error(\"bsp_context::receive(): no messages to receive, all nodes currently blocked.\");\n        }\n\n        template <typename T>\n        bool try_receive (\n            T& item,\n            unsigned long& sending_node_id\n        ) \n        {\n            std::shared_ptr<std::vector<char> > temp;\n            if (receive_data(temp, sending_node_id))\n            {\n                vectorstream sin(*temp);\n                deserialize(item, sin);\n                if (sin.peek() != EOF)\n                    throw serialization_error(\"deserialize() did not consume all bytes produced by serialize().  \"\n                                              \"This probably means you are calling a receive method with a different type \"\n                                              \"of object than the one which was sent.\");\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n        ~bsp_context();\n\n    private:\n\n        bsp_context();\n\n        bsp_context(\n            unsigned long node_id_,\n            impl1::map_id_to_con& cons_\n        );\n\n        void close_all_connections_gracefully();\n        /*!\n            ensures\n                - closes all the connections to other nodes and lets them know that\n                  we are terminating normally rather than as the result of some kind\n                  of error.\n        !*/\n\n        bool receive_data (\n            std::shared_ptr<std::vector<char> >& item,\n            unsigned long& sending_node_id\n        );\n\n\n        void notify_control_node (\n            char val\n        );\n\n        void broadcast_byte (\n            char val\n        );\n\n        void send_data(\n            const std::vector<char>& item,\n            unsigned long target_node_id\n        );\n        /*!\n            requires\n                - target_node_id < number_of_nodes()\n                - target_node_id != node_id()\n            ensures\n                - sends a copy of item to the node with the given id.\n        !*/\n\n\n\n\n        unsigned long outstanding_messages;\n        unsigned long num_waiting_nodes;\n        unsigned long num_terminated_nodes;\n        dlib::uint64 current_epoch;\n\n        impl1::thread_safe_message_queue msg_buffer;\n\n        impl1::map_id_to_con& _cons;\n        const unsigned long _node_id;\n        array<std::unique_ptr<thread_function> > threads;\n\n    // -----------------------------------\n\n        template <\n            typename funct_type\n            >\n        friend void bsp_connect (\n            const std::vector<network_address>& hosts,\n            funct_type funct\n        );\n\n        template <\n            typename funct_type,\n            typename ARG1\n            >\n        friend void bsp_connect (\n            const std::vector<network_address>& hosts,\n            funct_type funct,\n            ARG1 arg1\n        );\n\n        template <\n            typename funct_type,\n            typename ARG1,\n            typename ARG2\n            >\n        friend void bsp_connect (\n            const std::vector<network_address>& hosts,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2\n        );\n\n        template <\n            typename funct_type,\n            typename ARG1,\n            typename ARG2,\n            typename ARG3\n            >\n        friend void bsp_connect (\n            const std::vector<network_address>& hosts,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2,\n            ARG3 arg3\n        );\n\n        template <\n            typename funct_type,\n            typename ARG1,\n            typename ARG2,\n            typename ARG3,\n            typename ARG4\n            >\n        friend void bsp_connect (\n            const std::vector<network_address>& hosts,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2,\n            ARG3 arg3,\n            ARG4 arg4\n        );\n\n    // -----------------------------------\n\n        template <\n            typename port_notify_function_type,\n            typename funct_type\n            >\n        friend void bsp_listen_dynamic_port (\n            unsigned short listening_port,\n            port_notify_function_type port_notify_function,\n            funct_type funct\n        );\n\n        template <\n            typename port_notify_function_type,\n            typename funct_type,\n            typename ARG1\n            >\n        friend void bsp_listen_dynamic_port (\n            unsigned short listening_port,\n            port_notify_function_type port_notify_function,\n            funct_type funct,\n            ARG1 arg1\n        );\n\n        template <\n            typename port_notify_function_type,\n            typename funct_type,\n            typename ARG1,\n            typename ARG2\n            >\n        friend void bsp_listen_dynamic_port (\n            unsigned short listening_port,\n            port_notify_function_type port_notify_function,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2\n        );\n\n        template <\n            typename port_notify_function_type,\n            typename funct_type,\n            typename ARG1,\n            typename ARG2,\n            typename ARG3\n            >\n        friend void bsp_listen_dynamic_port (\n            unsigned short listening_port,\n            port_notify_function_type port_notify_function,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2,\n            ARG3 arg3\n        );\n\n        template <\n            typename port_notify_function_type,\n            typename funct_type,\n            typename ARG1,\n            typename ARG2,\n            typename ARG3,\n            typename ARG4\n            >\n        friend void bsp_listen_dynamic_port (\n            unsigned short listening_port,\n            port_notify_function_type port_notify_function,\n            funct_type funct,\n            ARG1 arg1,\n            ARG2 arg2,\n            ARG3 arg3,\n            ARG4 arg4\n        );\n\n    // -----------------------------------\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct\n    )\n    {\n        impl1::map_id_to_con cons;\n        const unsigned long node_id = 0;\n        connect_all(cons, hosts, node_id);\n        send_out_connection_orders(cons, hosts);\n        bsp_context obj(node_id, cons);\n        funct(obj);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1\n    )\n    {\n        impl1::map_id_to_con cons;\n        const unsigned long node_id = 0;\n        connect_all(cons, hosts, node_id);\n        send_out_connection_orders(cons, hosts);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    )\n    {\n        impl1::map_id_to_con cons;\n        const unsigned long node_id = 0;\n        connect_all(cons, hosts, node_id);\n        send_out_connection_orders(cons, hosts);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    )\n    {\n        impl1::map_id_to_con cons;\n        const unsigned long node_id = 0;\n        connect_all(cons, hosts, node_id);\n        send_out_connection_orders(cons, hosts);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2,arg3);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    )\n    {\n        impl1::map_id_to_con cons;\n        const unsigned long node_id = 0;\n        connect_all(cons, hosts, node_id);\n        send_out_connection_orders(cons, hosts);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2,arg3,arg4);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(listening_port != 0,\n            \"\\t void bsp_listen()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            );\n\n        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(listening_port != 0,\n            \"\\t void bsp_listen()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            );\n\n        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(listening_port != 0,\n            \"\\t void bsp_listen()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            );\n\n        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(listening_port != 0,\n            \"\\t void bsp_listen()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            );\n\n        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2, arg3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(listening_port != 0,\n            \"\\t void bsp_listen()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            );\n\n        bsp_listen_dynamic_port(listening_port, impl1::null_notify, funct, arg1, arg2, arg3, arg4);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct\n    )\n    {\n        impl1::map_id_to_con cons;\n        unsigned long node_id;\n        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);\n        bsp_context obj(node_id, cons);\n        funct(obj);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1\n    )\n    {\n        impl1::map_id_to_con cons;\n        unsigned long node_id;\n        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    )\n    {\n        impl1::map_id_to_con cons;\n        unsigned long node_id;\n        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    )\n    {\n        impl1::map_id_to_con cons;\n        unsigned long node_id;\n        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2,arg3);\n        obj.close_all_connections_gracefully();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    )\n    {\n        impl1::map_id_to_con cons;\n        unsigned long node_id;\n        listen_and_connect_all(node_id, cons, listening_port, port_notify_function);\n        bsp_context obj(node_id, cons);\n        funct(obj,arg1,arg2,arg3,arg4);\n        obj.close_all_connections_gracefully();\n    }\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"bsp.cpp\"\n#endif\n\n#endif // DLIB_BsP_Hh_\n\n"
  },
  {
    "path": "dlib/bsp/bsp_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BsP_ABSTRACT_Hh_\n#ifdef DLIB_BsP_ABSTRACT_Hh_\n\n#include \"../noncopyable.h\"\n#include \"../sockets/sockets_extensions_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class bsp_context : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool used to implement algorithms using the Bulk Synchronous\n                Parallel (BSP) computing model.  A BSP algorithm is composed of a number of\n                processing nodes, each executing in parallel.  The general flow of\n                execution in each processing node is the following:\n                    1. Do work locally on some data.\n                    2. Send some messages to other nodes.\n                    3. Receive messages from other nodes.\n                    4. Go to step 1 or terminate if complete.\n\n                To do this, each processing node needs an API used to send and receive\n                messages.  This API is implemented by the bsp_connect object which provides\n                these services to a BSP node.  \n\n                Note that BSP processing nodes are spawned using the bsp_connect() and\n                bsp_listen() routines defined at the bottom of this file.  For example, to\n                start a BSP algorithm consisting of N processing nodes, you would make N-1\n                calls to bsp_listen() and one call to bsp_connect().  The call to\n                bsp_connect() then initiates the computation on all nodes.\n\n                Finally, note that there is no explicit barrier synchronization function\n                you call at the end of step 3.  Instead, you can simply call a method such\n                as try_receive() until it returns false.  That is, the bsp_context's\n                receive methods incorporate a barrier synchronization that happens once all\n                the BSP nodes are blocked on receive calls and there are no more messages\n                in flight. \n\n\n            THREAD SAFETY\n                This object is not thread-safe.  In particular, you should only ever have\n                one thread that works with an instance of this object.  This means that,\n                for example, you should not spawn sub-threads from within a BSP processing\n                node and have them invoke methods on this object.  Instead, you should only\n                invoke this object's methods from within the BSP processing node's main\n                thread (i.e. the thread that executes the user supplied function funct()).\n        !*/\n\n    public:\n\n        template <typename T>\n        void send(\n            const T& item,\n            unsigned long target_node_id\n        );\n        /*!\n            requires\n                - item is serializable \n                - target_node_id < number_of_nodes()\n                - target_node_id != node_id()\n            ensures\n                - sends a copy of item to the node with the given id.\n            throws\n                - dlib::socket_error:\n                    This exception is thrown if there is an error which prevents us from\n                    delivering the message to the given node.  One way this might happen is\n                    if the target node has already terminated its execution or has lost\n                    network connectivity. \n        !*/\n\n        template <typename T>\n        void broadcast (\n            const T& item\n        );\n        /*!\n            ensures\n                - item is serializable\n                - sends a copy of item to all other processing nodes.   \n            throws\n                - dlib::socket_error\n                    This exception is thrown if there is an error which prevents us from\n                    delivering a message to one of the other nodes.  This might happen, for\n                    example, if one of the nodes has terminated its execution or has lost\n                    network connectivity.\n        !*/\n\n        unsigned long node_id (\n        ) const; \n        /*!\n            ensures\n                - Returns the id of the current processing node.  That is, \n                  returns a number N such that:\n                    - N < number_of_nodes()\n                    - N == the node id of the processing node that called node_id().  This\n                      is a number that uniquely identifies the processing node.\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const; \n        /*!\n            ensures\n                - returns the number of processing nodes participating in the BSP\n                  computation.\n        !*/\n\n        template <typename T>\n        bool try_receive (\n            T& item\n        );\n        /*!\n            requires\n                - item is serializable\n            ensures\n                - if (this function returns true) then\n                    - #item == the next message which was sent to the calling processing\n                      node.\n                - else\n                    - The following must have been true for this function to return false:\n                        - All other nodes were blocked on calls to receive(),\n                          try_receive(), or have terminated.\n                        - There were not any messages in flight between any nodes.  \n                        - That is, if all the nodes had continued to block on receive\n                          methods then they all would have blocked forever.  Therefore,\n                          this function only returns false once there are no more messages\n                          to process by any node and there is no possibility of more being\n                          generated until control is returned to the callers of receive\n                          methods. \n                    - When one BSP node's receive method returns because of the above\n                      conditions then all of them will also return.  That is, it is NOT the\n                      case that just a subset of BSP nodes unblock.  Moreover, they all\n                      unblock at the same time.  \n            throws\n                - dlib::socket_error:\n                    This exception is thrown if some error occurs which prevents us from\n                    communicating with other processing nodes.\n                - dlib::serialization_error or any exception thrown by the global\n                  deserialize(T) routine:\n                    This is thrown if there is a problem in deserialize().  This might\n                    happen if the message sent doesn't match the type T expected by\n                    try_receive().\n        !*/\n\n        template <typename T>\n        void receive (\n            T& item\n        );\n        /*!\n            requires\n                - item is serializable\n            ensures\n                - #item == the next message which was sent to the calling processing\n                  node.\n                - This function is just a wrapper around try_receive() that throws an\n                  exception if a message is not received (i.e. if try_receive() returns\n                  false).\n            throws\n                - dlib::socket_error:\n                    This exception is thrown if some error occurs which prevents us from\n                    communicating with other processing nodes or if there was not a message\n                    to receive.\n                - dlib::serialization_error or any exception thrown by the global\n                  deserialize(T) routine:\n                    This is thrown if there is a problem in deserialize().  This might\n                    happen if the message sent doesn't match the type T expected by\n                    receive().\n        !*/\n\n        template <typename T>\n        bool try_receive (\n            T& item,\n            unsigned long& sending_node_id\n        ); \n        /*!\n            requires\n                - item is serializable\n            ensures\n                - if (this function returns true) then\n                    - #item == the next message which was sent to the calling processing\n                      node.\n                    - #sending_node_id == the node id of the node that sent this message.\n                    - #sending_node_id < number_of_nodes()\n                - else\n                    - The following must have been true for this function to return false:\n                        - All other nodes were blocked on calls to receive(),\n                          try_receive(), or have terminated.\n                        - There were not any messages in flight between any nodes.  \n                        - That is, if all the nodes had continued to block on receive\n                          methods then they all would have blocked forever.  Therefore,\n                          this function only returns false once there are no more messages\n                          to process by any node and there is no possibility of more being\n                          generated until control is returned to the callers of receive\n                          methods. \n                    - When one BSP node's receive method returns because of the above\n                      conditions then all of them will also return.  That is, it is NOT the\n                      case that just a subset of BSP nodes unblock.  Moreover, they all\n                      unblock at the same time.  \n            throws\n                - dlib::socket_error:\n                    This exception is thrown if some error occurs which prevents us from\n                    communicating with other processing nodes.\n                - dlib::serialization_error or any exception thrown by the global\n                  deserialize(T) routine:\n                    This is thrown if there is a problem in deserialize().  This might\n                    happen if the message sent doesn't match the type T expected by\n                    try_receive().\n        !*/\n\n        template <typename T>\n        void receive (\n            T& item,\n            unsigned long& sending_node_id\n        ); \n        /*!\n            requires\n                - item is serializable\n            ensures\n                - #item == the next message which was sent to the calling processing node.\n                - #sending_node_id == the node id of the node that sent this message.\n                - #sending_node_id < number_of_nodes()\n                - This function is just a wrapper around try_receive() that throws an\n                  exception if a message is not received (i.e. if try_receive() returns\n                  false).\n            throws\n                - dlib::socket_error:\n                    This exception is thrown if some error occurs which prevents us from\n                    communicating with other processing nodes or if there was not a message\n                    to receive.\n                - dlib::serialization_error or any exception thrown by the global\n                  deserialize(T) routine:\n                    This is thrown if there is a problem in deserialize().  This might\n                    happen if the message sent doesn't match the type T expected by\n                    receive().\n        !*/\n\n        void receive (\n        );\n        /*!\n            ensures\n                - Waits for the following to all be true:\n                    - All other nodes were blocked on calls to receive(), try_receive(), or\n                      have terminated.\n                    - There are not any messages in flight between any nodes.  \n                    - That is, if all the nodes had continued to block on receive methods\n                      then they all would have blocked forever.  Therefore, this function\n                      only returns once there are no more messages to process by any node\n                      and there is no possibility of more being generated until control is\n                      returned to the callers of receive methods. \n                - When one BSP node's receive method returns because of the above\n                  conditions then all of them will also return.  That is, it is NOT the\n                  case that just a subset of BSP nodes unblock.  Moreover, they all unblock\n                  at the same time.  \n            throws\n                - dlib::socket_error:\n                    This exception is thrown if some error occurs which prevents us from\n                    communicating with other processing nodes or if a message is received\n                    before this function would otherwise return.\n\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.\n            - The processing node with a node ID of 0 will run locally on the machine\n              calling bsp_connect().  In particular, this node will execute funct(CONTEXT),\n              which is expected to carry out this node's portion of the BSP computation.\n            - The other processing nodes are executed on the hosts indicated by the input\n              argument.  In particular, this function interprets hosts as a list addresses\n              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()\n              routines.  \n            - This call to bsp_connect() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.\n            - The processing node with a node ID of 0 will run locally on the machine\n              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1),\n              which is expected to carry out this node's portion of the BSP computation.\n            - The other processing nodes are executed on the hosts indicated by the input\n              argument.  In particular, this function interprets hosts as a list addresses\n              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()\n              routines.  \n            - This call to bsp_connect() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.\n            - The processing node with a node ID of 0 will run locally on the machine\n              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2),\n              which is expected to carry out this node's portion of the BSP computation.\n            - The other processing nodes are executed on the hosts indicated by the input\n              argument.  In particular, this function interprets hosts as a list addresses\n              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()\n              routines.  \n            - This call to bsp_connect() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.\n            - The processing node with a node ID of 0 will run locally on the machine\n              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3),\n              which is expected to carry out this node's portion of the BSP computation.\n            - The other processing nodes are executed on the hosts indicated by the input\n              argument.  In particular, this function interprets hosts as a list addresses\n              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()\n              routines.  \n            - This call to bsp_connect() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_connect (\n        const std::vector<network_address>& hosts,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function spawns a BSP job consisting of hosts.size()+1 processing nodes.\n            - The processing node with a node ID of 0 will run locally on the machine\n              calling bsp_connect().  In particular, this node will execute funct(CONTEXT,arg1,arg2,arg3,arg4),\n              which is expected to carry out this node's portion of the BSP computation.\n            - The other processing nodes are executed on the hosts indicated by the input\n              argument.  In particular, this function interprets hosts as a list addresses\n              identifying machines running the bsp_listen() or bsp_listen_dynamic_port()\n              routines.  \n            - This call to bsp_connect() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct\n    );\n    /*!\n        requires\n            - listening_port != 0\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT) will be executed and it will\n              then be able to participate in the BSP computation as one of the processing\n              nodes.  \n            - This function will listen on TCP port listening_port for a connection from\n              bsp_connect().  Once the connection is established, it will close the\n              listening port so it is free for use by other applications.  The connection\n              and BSP computation will continue uninterrupted.\n            - This call to bsp_listen() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1\n    );\n    /*!\n        requires\n            - listening_port != 0\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1) will be executed and it will\n              then be able to participate in the BSP computation as one of the processing\n              nodes.  \n            - This function will listen on TCP port listening_port for a connection from\n              bsp_connect().  Once the connection is established, it will close the\n              listening port so it is free for use by other applications.  The connection\n              and BSP computation will continue uninterrupted.\n            - This call to bsp_listen() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    );\n    /*!\n        requires\n            - listening_port != 0\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2) will be executed and\n              it will then be able to participate in the BSP computation as one of the\n              processing nodes.  \n            - This function will listen on TCP port listening_port for a connection from\n              bsp_connect().  Once the connection is established, it will close the\n              listening port so it is free for use by other applications.  The connection\n              and BSP computation will continue uninterrupted.\n            - This call to bsp_listen() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    );\n    /*!\n        requires\n            - listening_port != 0\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be\n              executed and it will then be able to participate in the BSP computation as\n              one of the processing nodes.  \n            - This function will listen on TCP port listening_port for a connection from\n              bsp_connect().  Once the connection is established, it will close the\n              listening port so it is free for use by other applications.  The connection\n              and BSP computation will continue uninterrupted.\n            - This call to bsp_listen() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_listen (\n        unsigned short listening_port,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    );\n    /*!\n        requires\n            - listening_port != 0\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression \n                  (i.e. funct must be a function or function object)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be\n              executed and it will then be able to participate in the BSP computation as\n              one of the processing nodes.  \n            - This function will listen on TCP port listening_port for a connection from\n              bsp_connect().  Once the connection is established, it will close the\n              listening port so it is free for use by other applications.  The connection\n              and BSP computation will continue uninterrupted.\n            - This call to bsp_listen() blocks until the BSP computation has completed on\n              all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT) must be a valid expression \n                  (i.e. funct must be a function or function object)\n            - port_notify_function((unsigned short) 1234) must be a valid expression\n              (i.e. port_notify_function() must be a function or function object taking an \n              unsigned short)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT) will be executed and it will\n              then be able to participate in the BSP computation as one of the processing\n              nodes.  \n            - if (listening_port != 0) then\n                - This function will listen on TCP port listening_port for a connection\n                  from bsp_connect().  \n            - else\n                - An available TCP port number is automatically selected and this function\n                  will listen on it for a connection from bsp_connect(). \n            - Once a listening port is opened, port_notify_function() is called with the\n              port number used.  This provides a mechanism to find out what listening port\n              has been used if it is automatically selected.  It also allows you to find\n              out when the routine has begun listening for an incoming connection from\n              bsp_connect().\n            - Once a connection is established, we will close the listening port so it is\n              free for use by other applications.  The connection and BSP computation will\n              continue uninterrupted.\n            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has\n              completed on all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1) must be a valid expression \n                  (i.e. funct must be a function or function object)\n            - port_notify_function((unsigned short) 1234) must be a valid expression\n              (i.e. port_notify_function() must be a function or function object taking an \n              unsigned short)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1) will be executed and it\n              will then be able to participate in the BSP computation as one of the\n              processing nodes.  \n            - if (listening_port != 0) then\n                - This function will listen on TCP port listening_port for a connection\n                  from bsp_connect().  \n            - else\n                - An available TCP port number is automatically selected and this function\n                  will listen on it for a connection from bsp_connect(). \n            - Once a listening port is opened, port_notify_function() is called with the\n              port number used.  This provides a mechanism to find out what listening port\n              has been used if it is automatically selected.  It also allows you to find\n              out when the routine has begun listening for an incoming connection from\n              bsp_connect().\n            - Once a connection is established, we will close the listening port so it is\n              free for use by other applications.  The connection and BSP computation will\n              continue uninterrupted.\n            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has\n              completed on all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2) must be a valid expression \n                  (i.e. funct must be a function or function object)\n            - port_notify_function((unsigned short) 1234) must be a valid expression\n              (i.e. port_notify_function() must be a function or function object taking an \n              unsigned short)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2) will be executed and\n              it will then be able to participate in the BSP computation as one of the\n              processing nodes.  \n            - if (listening_port != 0) then\n                - This function will listen on TCP port listening_port for a connection\n                  from bsp_connect().  \n            - else\n                - An available TCP port number is automatically selected and this function\n                  will listen on it for a connection from bsp_connect(). \n            - Once a listening port is opened, port_notify_function() is called with the\n              port number used.  This provides a mechanism to find out what listening port\n              has been used if it is automatically selected.  It also allows you to find\n              out when the routine has begun listening for an incoming connection from\n              bsp_connect().\n            - Once a connection is established, we will close the listening port so it is\n              free for use by other applications.  The connection and BSP computation will\n              continue uninterrupted.\n            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has\n              completed on all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3) must be a valid expression \n                  (i.e. funct must be a function or function object)\n            - port_notify_function((unsigned short) 1234) must be a valid expression\n              (i.e. port_notify_function() must be a function or function object taking an \n              unsigned short)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2,arg3) will be\n              executed and it will then be able to participate in the BSP computation as\n              one of the processing nodes.  \n            - if (listening_port != 0) then\n                - This function will listen on TCP port listening_port for a connection\n                  from bsp_connect().  \n            - else\n                - An available TCP port number is automatically selected and this function\n                  will listen on it for a connection from bsp_connect(). \n            - Once a listening port is opened, port_notify_function() is called with the\n              port number used.  This provides a mechanism to find out what listening port\n              has been used if it is automatically selected.  It also allows you to find\n              out when the routine has begun listening for an incoming connection from\n              bsp_connect().\n            - Once a connection is established, we will close the listening port so it is\n              free for use by other applications.  The connection and BSP computation will\n              continue uninterrupted.\n            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has\n              completed on all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename port_notify_function_type,\n        typename funct_type,\n        typename ARG1,\n        typename ARG2,\n        typename ARG3,\n        typename ARG4\n        >\n    void bsp_listen_dynamic_port (\n        unsigned short listening_port,\n        port_notify_function_type port_notify_function,\n        funct_type funct,\n        ARG1 arg1,\n        ARG2 arg2,\n        ARG3 arg3,\n        ARG4 arg4\n    );\n    /*!\n        requires\n            - let CONTEXT be an instance of a bsp_context object.  Then:\n                - funct(CONTEXT,arg1,arg2,arg3,arg4) must be a valid expression \n                  (i.e. funct must be a function or function object)\n            - port_notify_function((unsigned short) 1234) must be a valid expression\n              (i.e. port_notify_function() must be a function or function object taking an \n              unsigned short)\n        ensures\n            - This function listens for a connection from the bsp_connect() routine.  Once\n              this connection is established, funct(CONTEXT,arg1,arg2,arg3,arg4) will be\n              executed and it will then be able to participate in the BSP computation as\n              one of the processing nodes.  \n            - if (listening_port != 0) then\n                - This function will listen on TCP port listening_port for a connection\n                  from bsp_connect().  \n            - else\n                - An available TCP port number is automatically selected and this function\n                  will listen on it for a connection from bsp_connect(). \n            - Once a listening port is opened, port_notify_function() is called with the\n              port number used.  This provides a mechanism to find out what listening port\n              has been used if it is automatically selected.  It also allows you to find\n              out when the routine has begun listening for an incoming connection from\n              bsp_connect().\n            - Once a connection is established, we will close the listening port so it is\n              free for use by other applications.  The connection and BSP computation will\n              continue uninterrupted.\n            - This call to bsp_listen_dynamic_port() blocks until the BSP computation has\n              completed on all processing nodes.\n        throws\n            - dlib::socket_error\n                This exception is thrown if there is an error which prevents the BSP\n                job from executing.  \n            - Any exception thrown by funct() will be propagated out of this call to\n              bsp_connect().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BsP_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/bsp.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BSPh_\n#define DLIB_BSPh_ \n\n\n#include \"bsp/bsp.h\"\n\n#endif // DLIB_BSPh_ \n\n\n\n"
  },
  {
    "path": "dlib/byte_orderer/byte_orderer_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BYTE_ORDEREr_KERNEL_1_ \n#define DLIB_BYTE_ORDEREr_KERNEL_1_ \n\n#include \"byte_orderer_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    class byte_orderer \n    {\n        /*!\n            INITIAL VALUE\n                - if (this machine is little endian) then\n                    - little_endian == true\n                - else\n                    - little_endian == false\n\n            CONVENTION\n                - host_is_big_endian() == !little_endian\n                - host_is_little_endian() == little_endian\n\n                - if (this machine is little endian) then\n                    - little_endian == true\n                - else\n                    - little_endian == false\n\n\n        !*/\n\n\n    public:\n\n        // this is here for backwards compatibility with older versions of dlib.\n        typedef byte_orderer kernel_1a;\n\n        byte_orderer (        \n        )\n        {\n            // This will probably never be false but if it is then it means chars are not 8bits\n            // on this system.  Which is a problem for this object.\n            COMPILE_TIME_ASSERT(sizeof(short) >= 2);\n\n            unsigned long temp = 1;\n            unsigned char* ptr = reinterpret_cast<unsigned char*>(&temp);\n            if (*ptr == 1)\n                little_endian = true;\n            else\n                little_endian = false;\n        }\n\n        virtual ~byte_orderer (\n        ){}\n\n        bool host_is_big_endian (\n        ) const { return !little_endian; }\n\n        bool host_is_little_endian (\n        ) const { return little_endian; }\n\n        template <\n            typename T\n            >\n        inline void host_to_network (\n            T& item\n        ) const\n        { if (little_endian) flip(item); }\n\n        template <\n            typename T\n            >\n        inline void network_to_host (\n            T& item\n        ) const { if (little_endian) flip(item); }\n\n        template <\n            typename T\n            >\n        void host_to_big (\n            T& item\n        ) const { if (little_endian) flip(item); }\n\n        template <\n            typename T\n            >\n        void big_to_host (\n            T& item\n        ) const { if (little_endian) flip(item); }\n\n        template <\n            typename T\n            >\n        void host_to_little (\n            T& item\n        ) const { if (!little_endian) flip(item); }\n\n        template <\n            typename T\n            >\n        void little_to_host (\n            T& item\n        ) const { if (!little_endian) flip(item); }\n\n\n    private:\n\n        template <\n            typename T,\n            size_t size\n            >\n        inline void flip (\n            T (&array)[size]\n        ) const\n        /*!\n            ensures\n                - flips the bytes in every element of this array\n        !*/\n        {\n            for (size_t i = 0; i < size; ++i)\n            {\n                flip(array[i]);\n            }\n        }\n\n        template <\n            typename T\n            >\n        inline void flip (\n            T& item\n        ) const\n        /*!\n            ensures\n                - reverses the byte ordering in item\n        !*/\n        {\n            DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);\n\n            T value;\n\n            // If you are getting this as an error then you are probably using\n            // this object wrong.  If you think you aren't then send me (Davis) an\n            // email and I'll either set you straight or change/remove this check so\n            // your stuff works :)\n            COMPILE_TIME_ASSERT(sizeof(T) <= sizeof(long double));\n\n            // If you are getting a compile error on this line then it means T is\n            // a pointer type.  It doesn't make any sense to byte swap pointers\n            // since they have no meaning outside the context of their own process.\n            // So you probably just forgot to dereference that pointer before passing\n            // it to this function  :)\n            COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);\n\n\n            const size_t size = sizeof(T);\n            unsigned char* const ptr = reinterpret_cast<unsigned char*>(&item);\n            unsigned char* const ptr_temp = reinterpret_cast<unsigned char*>(&value);\n            for (size_t i = 0; i < size; ++i)\n                ptr_temp[size-i-1] = ptr[i];\n\n            item = value;\n        }\n\n        bool little_endian;\n    };    \n\n    // make flip not do anything at all for chars\n    template <> inline void byte_orderer::flip<char> ( char& ) const {} \n    template <> inline void byte_orderer::flip<unsigned char> ( unsigned char& ) const {} \n    template <> inline void byte_orderer::flip<signed char> ( signed char& ) const {} \n}\n\n#endif // DLIB_BYTE_ORDEREr_KERNEL_1_ \n\n"
  },
  {
    "path": "dlib/byte_orderer/byte_orderer_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BYTE_ORDEREr_ABSTRACT_ \n#ifdef DLIB_BYTE_ORDEREr_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    class byte_orderer \n    {\n        /*!\n            INITIAL VALUE\n                This object has no state.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object simply provides a mechanism to convert data from a\n                host machine's own byte ordering to big or little endian and to \n                also do the reverse.\n\n                It also provides a pair of functions to convert to/from network byte\n                order where network byte order is big endian byte order.  This pair of\n                functions does the exact same thing as the host_to_big() and big_to_host()\n                functions and is provided simply so that client code can use the most \n                self documenting name appropriate.\n\n                Also note that this object is capable of correctly flipping the contents \n                of arrays when the arrays are declared on the stack.  e.g.  You can  \n                say things like:\n                int array[10]; \n                bo.host_to_network(array);\n        !*/\n\n    public:\n\n        byte_orderer (        \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~byte_orderer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        bool host_is_big_endian (\n        ) const;\n        /*!\n            ensures\n                - if (the host computer is a big endian machine) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool host_is_little_endian (\n        ) const;\n        /*!\n            ensures\n                - if (the host computer is a little endian machine) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        template <\n            typename T\n            >\n        void host_to_network (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from host byte order \n                  to network byte order.\n        !*/\n\n        template <\n            typename T\n            >\n        void network_to_host (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from network byte order\n                  to host byte order.\n        !*/\n\n        template <\n            typename T\n            >\n        void host_to_big (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from host byte order \n                  to big endian byte order.\n        !*/\n\n        template <\n            typename T\n            >\n        void big_to_host (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from big endian byte order\n                  to host byte order.\n        !*/\n\n        template <\n            typename T\n            >\n        void host_to_little (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from host byte order \n                  to little endian byte order.\n        !*/\n\n        template <\n            typename T\n            >\n        void little_to_host (\n            T& item\n        ) const;\n        /*!\n            ensures\n                - #item == the value of item converted from little endian byte order\n                  to host byte order.\n        !*/\n\n    };    \n}\n\n#endif // DLIB_BYTE_ORDEREr_ABSTRACT_ \n\n"
  },
  {
    "path": "dlib/byte_orderer.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BYTE_ORDEREr_ \n#define DLIB_BYTE_ORDEREr_ \n\n\n#include \"byte_orderer/byte_orderer_kernel_1.h\"\n\n#endif // DLIB_BYTE_ORDEREr_ \n\n"
  },
  {
    "path": "dlib/cassert",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/clustering/bottom_up_cluster.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BOTTOM_uP_CLUSTER_Hh_\n#define DLIB_BOTTOM_uP_CLUSTER_Hh_\n\n#include <queue>\n#include <map>\n\n#include \"bottom_up_cluster_abstract.h\"\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../disjoint_subsets.h\"\n#include \"../graph_utils.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace buc_impl\n    {\n        inline void merge_sets (\n            matrix<double>& dists,\n            unsigned long dest,\n            unsigned long src\n        )\n        {\n            for (long r = 0; r < dists.nr(); ++r)\n                dists(dest,r) = dists(r,dest) = std::max(dists(r,dest), dists(r,src));\n        }\n\n        struct compare_dist\n        {\n            bool operator() (\n                const sample_pair& a,\n                const sample_pair& b\n            ) const\n            {\n                return a.distance() > b.distance();\n            }\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    unsigned long bottom_up_cluster (\n        const matrix_exp<EXP>& dists_,\n        std::vector<unsigned long>& labels,\n        unsigned long min_num_clusters,\n        double max_dist = std::numeric_limits<double>::infinity()\n    )\n    {\n        matrix<double> dists = matrix_cast<double>(dists_);\n        // make sure requires clause is not broken\n        DLIB_CASSERT(dists.nr() == dists.nc() && min_num_clusters > 0, \n            \"\\t unsigned long bottom_up_cluster()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t dists.nr(): \" << dists.nr() \n            << \"\\n\\t dists.nc(): \" << dists.nc() \n            << \"\\n\\t min_num_clusters: \" << min_num_clusters \n            );\n\n        using namespace buc_impl;\n\n        labels.resize(dists.nr());\n        disjoint_subsets sets;\n        sets.set_size(dists.nr());\n        if (labels.size() == 0)\n            return 0;\n\n        // push all the edges in the graph into a priority queue so the best edges to merge\n        // come first.\n        std::priority_queue<sample_pair, std::vector<sample_pair>, compare_dist> que;\n        for (long r = 0; r < dists.nr(); ++r)\n            for (long c = r+1; c < dists.nc(); ++c)\n                que.push(sample_pair(r,c,dists(r,c)));\n\n        // Now start merging nodes.\n        for (unsigned long iter = min_num_clusters; iter < sets.size(); ++iter)\n        {\n            // find the next best thing to merge.\n            double best_dist = que.top().distance();\n            unsigned long a = sets.find_set(que.top().index1());\n            unsigned long b = sets.find_set(que.top().index2());\n            que.pop();\n            // we have been merging and modifying the distances, so make sure this distance\n            // is still valid and these guys haven't been merged already.\n            while(a == b || best_dist < dists(a,b))\n            {\n                // Haven't merged it yet, so put it back in with updated distance for\n                // reconsideration later.\n                if (a != b)\n                    que.push(sample_pair(a, b, dists(a, b)));\n\n                best_dist = que.top().distance();\n                a = sets.find_set(que.top().index1());\n                b = sets.find_set(que.top().index2());\n                que.pop();\n            }\n\n\n            // now merge these sets if the best distance is small enough\n            if (best_dist > max_dist)\n                break;\n            unsigned long news = sets.merge_sets(a,b);\n            unsigned long olds = (news==a)?b:a;\n            merge_sets(dists, news, olds);\n        }\n\n        // figure out which cluster each element is in.  Also make sure the labels are\n        // contiguous.\n        std::map<unsigned long, unsigned long> relabel;\n        for (unsigned long r = 0; r < labels.size(); ++r)\n        {\n            unsigned long l = sets.find_set(r);\n            // relabel to make contiguous\n            if (relabel.count(l) == 0)\n            {\n                unsigned long next = relabel.size();\n                relabel[l] = next;\n            }\n            labels[r] = relabel[l];\n        }\n\n\n        return relabel.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct snl_range\n    {\n        snl_range() = default;\n        snl_range(double val) : lower(val), upper(val) {}\n        snl_range(double l, double u) : lower(l), upper(u) { DLIB_ASSERT(lower <= upper)}\n\n        double lower = 0;\n        double upper = 0;\n\n        double width() const { return upper-lower; }\n        bool operator<(const snl_range& item) const { return lower < item.lower; }\n    };\n\n    inline snl_range merge(const snl_range& a, const snl_range& b)\n    {\n        return snl_range(std::min(a.lower, b.lower), std::max(a.upper, b.upper));\n    }\n\n    inline double distance (const snl_range& a, const snl_range& b)\n    {\n        return std::max(a.lower,b.lower) - std::min(a.upper,b.upper);\n    }\n\n    inline std::ostream& operator<< (std::ostream& out, const snl_range& item )\n    {\n        out << \"[\"<<item.lower<<\",\"<<item.upper<<\"]\";\n        return out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<snl_range> segment_number_line (\n        const std::vector<double>& x,\n        const double max_range_width\n    )\n    {\n        DLIB_CASSERT(max_range_width >= 0);\n\n        // create initial ranges, one for each value in x.  So initially, all the ranges have\n        // width of 0.\n        std::vector<snl_range> ranges;\n        for (auto v : x)\n            ranges.push_back(v);\n        std::sort(ranges.begin(), ranges.end());\n\n        std::vector<snl_range> greedy_final_ranges;\n        if (ranges.size() == 0)\n            return greedy_final_ranges;\n        // We will try two different clustering strategies.  One that does a simple greedy left\n        // to right sweep and another that does a bottom up agglomerative clustering.  This\n        // first loop runs the greedy left to right sweep.  Then at the end of this routine we\n        // will return the results that produced the tightest clustering.\n        greedy_final_ranges.push_back(ranges[0]);\n        for (size_t i = 1; i < ranges.size(); ++i)\n        {\n            auto m = merge(greedy_final_ranges.back(), ranges[i]);\n            if (m.width() <= max_range_width)\n                greedy_final_ranges.back() = m;\n            else\n                greedy_final_ranges.push_back(ranges[i]);\n        }\n\n\n        // Here we do the bottom up clustering.  So compute the edges connecting our ranges.\n        // We will simply say there are edges between ranges if and only if they are\n        // immediately adjacent on the number line.\n        std::vector<sample_pair> edges;\n        for (size_t i = 1; i < ranges.size(); ++i)\n            edges.push_back(sample_pair(i-1,i, distance(ranges[i-1],ranges[i])));\n        std::sort(edges.begin(), edges.end(), order_by_distance<sample_pair>);\n\n        disjoint_subsets sets;\n        sets.set_size(ranges.size());\n\n        // Now start merging nodes.\n        for (auto edge : edges)\n        {\n            // find the next best thing to merge.\n            unsigned long a = sets.find_set(edge.index1());\n            unsigned long b = sets.find_set(edge.index2());\n\n            // merge it if it doesn't result in an interval that's too big.\n            auto m = merge(ranges[a], ranges[b]);\n            if (m.width() <= max_range_width)\n            {\n                unsigned long news = sets.merge_sets(a,b);\n                ranges[news] = m;\n            }\n        }\n\n        // Now create a list of the final ranges.  We will do this by keeping track of which\n        // range we already added to final_ranges.\n        std::vector<snl_range> final_ranges;\n        std::vector<bool> already_output(ranges.size(), false);\n        for (unsigned long i = 0; i < sets.size(); ++i)\n        {\n            auto s = sets.find_set(i);\n            if (!already_output[s])\n            {\n                final_ranges.push_back(ranges[s]);\n                already_output[s] = true;\n            }\n        }\n\n        // only use the greedy clusters if they found a clustering with fewer clusters.\n        // Otherwise, the bottom up clustering probably produced a more sensible clustering.\n        if (final_ranges.size() <= greedy_final_ranges.size())\n            return final_ranges;\n        else\n            return greedy_final_ranges;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOTTOM_uP_CLUSTER_Hh_\n\n"
  },
  {
    "path": "dlib/clustering/bottom_up_cluster_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_\n#ifdef DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    unsigned long bottom_up_cluster (\n        const matrix_exp<EXP>& dists,\n        std::vector<unsigned long>& labels,\n        unsigned long min_num_clusters,\n        double max_dist = std::numeric_limits<double>::infinity()\n    );\n    /*!\n        requires\n            - dists.nr() == dists.nc()\n            - min_num_clusters > 0\n            - dists == trans(dists)\n              (l.e. dists should be symmetric)\n        ensures\n            - Runs a bottom up agglomerative clustering algorithm.   \n            - Interprets dists as a matrix that gives the distances between dists.nr()\n              items.  In particular, we take dists(i,j) to be the distance between the ith\n              and jth element of some set.  This function clusters the elements of this set\n              into at least min_num_clusters (or dists.nr() if there aren't enough\n              elements).  Additionally, within each cluster, the maximum pairwise distance\n              between any two cluster elements is <= max_dist.\n            - returns the number of clusters found.\n            - #labels.size() == dists.nr()\n            - for all valid i:\n                - #labels[i] == the cluster ID of the node with index i (i.e. the node\n                  corresponding to the distances dists(i,*)).  \n                - 0 <= #labels[i] < the number of clusters found\n                  (i.e. cluster IDs are assigned contiguously and start at 0) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct snl_range\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an interval on the real number line.  It is used\n                to store the outputs of the segment_number_line() routine defined below.\n        !*/\n\n        snl_range(\n        );\n        /*!\n            ensures\n                - #lower == 0\n                - #upper == 0\n        !*/\n\n        snl_range(\n            double val\n        );\n        /*!\n            ensures\n                - #lower == val \n                - #upper == val \n        !*/\n\n        snl_range(\n            double l, \n            double u\n        );\n        /*!\n            requires\n                - l <= u\n            ensures\n                - #lower == l \n                - #upper == u \n        !*/\n\n        double lower;\n        double upper;\n\n        double width(\n        ) const { return upper-lower; }\n        /*!\n            ensures\n                - returns the width of this interval on the number line.\n        !*/\n\n        bool operator<(const snl_range& item) const { return lower < item.lower; }\n        /*!\n            ensures\n                - provides a total ordering of snl_range objects assuming they are\n                  non-overlapping.\n        !*/\n    };\n\n    std::ostream& operator<< (std::ostream& out, const snl_range& item );\n    /*!\n        ensures\n            - prints item to out in the form [lower,upper].\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<snl_range> segment_number_line (\n        const std::vector<double>& x,\n        const double max_range_width\n    );\n    /*!\n        requires\n            - max_range_width >= 0\n        ensures\n            - Finds a clustering of the values in x and returns the ranges that define the\n              clustering.  This routine uses a combination of bottom up clustering and a\n              simple greedy scan to try and find the most compact set of ranges that\n              contain all the values in x.  \n            - This routine has approximately linear runtime.\n            - Every value in x will be contained inside one of the returned snl_range\n              objects;\n            - All returned snl_range object's will have a width() <= max_range_width and\n              will also be non-overlapping.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOTTOM_uP_CLUSTER_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/clustering/chinese_whispers.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CHINESE_WHISPErS_Hh_\n#define DLIB_CHINESE_WHISPErS_Hh_\n\n#include \"chinese_whispers_abstract.h\"\n#include <vector>\n#include \"../rand.h\"\n#include \"../graph_utils/edge_list_graphs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long chinese_whispers (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations,\n        dlib::rand& rnd\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_ordered_by_index(edges),\n                    \"\\t unsigned long chinese_whispers()\"\n                    << \"\\n\\t Invalid inputs were given to this function\"\n        );\n\n        labels.clear();\n        if (edges.size() == 0)\n            return 0;\n\n        std::vector<std::pair<unsigned long, unsigned long> > neighbors;\n        find_neighbor_ranges(edges, neighbors);\n\n        // Initialize the labels, each node gets a different label.\n        labels.resize(neighbors.size());\n        for (unsigned long i = 0; i < labels.size(); ++i)\n            labels[i] = i;\n\n\n        for (unsigned long iter = 0; iter < neighbors.size()*num_iterations; ++iter)\n        {\n            // Pick a random node.\n            const unsigned long idx = rnd.get_random_64bit_number()%neighbors.size();\n\n            // Count how many times each label happens amongst our neighbors.\n            std::map<unsigned long, double> labels_to_counts;\n            const unsigned long end = neighbors[idx].second;\n            for (unsigned long i = neighbors[idx].first; i != end; ++i)\n            {\n                labels_to_counts[labels[edges[i].index2()]] += edges[i].distance();\n            }\n\n            // find the most common label\n            std::map<unsigned long, double>::iterator i;\n            double best_score = -std::numeric_limits<double>::infinity();\n            unsigned long best_label = labels[idx];\n            for (i = labels_to_counts.begin(); i != labels_to_counts.end(); ++i)\n            {\n                if (i->second > best_score)\n                {\n                    best_score = i->second;\n                    best_label = i->first;\n                }\n            }\n\n            labels[idx] = best_label;\n        }\n\n\n        // Remap the labels into a contiguous range.  First we find the\n        // mapping.\n        std::map<unsigned long,unsigned long> label_remap;\n        for (unsigned long i = 0; i < labels.size(); ++i)\n        {\n            const unsigned long next_id = label_remap.size();\n            if (label_remap.count(labels[i]) == 0)\n                label_remap[labels[i]] = next_id;\n        }\n        // now apply the mapping to all the labels.\n        for (unsigned long i = 0; i < labels.size(); ++i)\n        {\n            labels[i] = label_remap[labels[i]];\n        }\n\n        return label_remap.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long chinese_whispers (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations,\n        dlib::rand& rnd\n    )\n    {\n        std::vector<ordered_sample_pair> oedges;\n        convert_unordered_to_ordered(edges, oedges);\n        std::sort(oedges.begin(), oedges.end(), &order_by_index<ordered_sample_pair>);\n\n        return chinese_whispers(oedges, labels, num_iterations, rnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long chinese_whispers (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations = 100\n    )\n    {\n        dlib::rand rnd;\n        return chinese_whispers(edges, labels, num_iterations, rnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long chinese_whispers (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations = 100\n    )\n    {\n        dlib::rand rnd;\n        return chinese_whispers(edges, labels, num_iterations, rnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CHINESE_WHISPErS_Hh_\n\n"
  },
  {
    "path": "dlib/clustering/chinese_whispers_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_\n#ifdef DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../rand.h\"\n#include \"../graph_utils/ordered_sample_pair_abstract.h\"\n#include \"../graph_utils/sample_pair_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long chinese_whispers (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations,\n        dlib::rand& rnd\n    );\n    /*!\n        requires\n            - is_ordered_by_index(edges) == true\n        ensures\n            - This function implements the graph clustering algorithm described in the\n              paper: Chinese Whispers - an Efficient Graph Clustering Algorithm and its\n              Application to Natural Language Processing Problems by Chris Biemann.\n            - Interprets edges as a directed graph.  That is, it contains the edges on the\n              said graph and the ordered_sample_pair::distance() values define the edge\n              weights (larger values indicating a stronger edge connection between the\n              nodes).  If an edge has a distance() value of infinity then it is considered\n              a \"must link\" edge.\n            - returns the number of clusters found.\n            - #labels.size() == max_index_plus_one(edges)\n            - for all valid i:\n                - #labels[i] == the cluster ID of the node with index i in the graph.  \n                - 0 <= #labels[i] < the number of clusters found\n                  (i.e. cluster IDs are assigned contiguously and start at 0) \n            - Duplicate edges are interpreted as if there had been just one edge with a\n              distance value equal to the sum of all the duplicate edge's distance values.\n            - The algorithm performs exactly num_iterations passes over the graph before\n              terminating.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long chinese_whispers (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations,\n        dlib::rand& rnd\n    );\n    /*!\n        ensures\n            - This function is identical to the above chinese_whispers() routine except\n              that it operates on a vector of sample_pair objects instead of\n              ordered_sample_pairs.  Therefore, this is simply a convenience routine.  In\n              particular, it is implemented by transforming the given edges into\n              ordered_sample_pairs and then calling the chinese_whispers() routine defined\n              above.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long chinese_whispers (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations = 100\n    );\n    /*!\n        requires\n            - is_ordered_by_index(edges) == true\n        ensures\n            - performs: return chinese_whispers(edges, labels, num_iterations, rnd)\n              where rnd is a default initialized dlib::rand object.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long chinese_whispers (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const unsigned long num_iterations = 100\n    );\n    /*!\n        ensures\n            - performs: return chinese_whispers(edges, labels, num_iterations, rnd)\n              where rnd is a default initialized dlib::rand object.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CHINESE_WHISPErS_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/clustering/modularity_clustering.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MODULARITY_ClUSTERING__H__\n#define DLIB_MODULARITY_ClUSTERING__H__\n\n#include \"modularity_clustering_abstract.h\"\n#include \"../sparse_vector.h\"\n#include \"../graph_utils/edge_list_graphs.h\"\n#include \"../matrix.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline double newman_cluster_split (\n            dlib::rand& rnd,\n            const std::vector<ordered_sample_pair>& edges,\n            const matrix<double,0,1>& node_degrees, // k from the Newman paper\n            const matrix<double,0,1>& Bdiag,        // diag(B) from the Newman paper\n            const double& edge_sum,                 // m from the Newman paper\n            matrix<double,0,1>& labels,\n            const double eps,\n            const unsigned long max_iterations\n        )\n        /*!\n            requires\n                - node_degrees.size() == max_index_plus_one(edges)\n                - Bdiag.size() == max_index_plus_one(edges)\n                - edges must be sorted according to order_by_index()\n            ensures\n                - This routine splits a graph into two subgraphs using the Newman \n                  clustering method.  \n                - returns the modularity obtained when the graph is split according\n                  to the contents of #labels. \n                - #labels.size() == node_degrees.size()\n                - for all valid i: #labels(i) == -1 or +1\n                - if (this function returns 0) then\n                    - all the labels are equal, i.e. the graph is not split.\n        !*/\n        {\n            // Scale epsilon so that it is relative to the expected value of an element of a\n            // unit vector of length node_degrees.size().\n            const double power_iter_eps = eps * std::sqrt(1.0/node_degrees.size());\n\n            // Make a random unit vector and put in labels.\n            labels.set_size(node_degrees.size());\n            for (long i = 0; i < labels.size(); ++i)\n                labels(i) = rnd.get_random_gaussian();\n            labels /= length(labels);\n\n            matrix<double,0,1> Bv, Bv_unit;\n\n            // Do the power iteration for a while.\n            double eig = -1;\n            double offset = 0;\n            while (eig < 0)\n            {\n\n                // any number larger than power_iter_eps\n                double iteration_change = power_iter_eps*2+1; \n                for (unsigned long i = 0; i < max_iterations && iteration_change > power_iter_eps; ++i) \n                {\n                    sparse_matrix_vector_multiply(edges, labels, Bv);\n                    Bv -= dot(node_degrees, labels)/(2*edge_sum) * node_degrees;\n\n                    if (offset != 0)\n                    {\n                        Bv -= offset*labels;\n                    }\n\n\n                    const double len = length(Bv);\n                    if (len != 0)\n                    {\n                        Bv_unit = Bv/len;\n                        iteration_change = max(abs(labels-Bv_unit));\n                        labels.swap(Bv_unit);\n                    }\n                    else\n                    {\n                        // Had a bad time, pick another random vector and try it with the\n                        // power iteration.\n                        for (long i = 0; i < labels.size(); ++i)\n                            labels(i) = rnd.get_random_gaussian();\n                    }\n                }\n\n                eig = dot(Bv,labels);\n                // we will repeat this loop if the largest eigenvalue is negative\n                offset = eig;\n            }\n\n\n            for (long i = 0; i < labels.size(); ++i)\n            {\n                if (labels(i) > 0)\n                    labels(i) = 1;\n                else\n                    labels(i) = -1;\n            }\n\n\n            // compute B*labels, store result in Bv.\n            sparse_matrix_vector_multiply(edges, labels, Bv);\n            Bv -= dot(node_degrees, labels)/(2*edge_sum) * node_degrees;\n\n            // Do some label refinement.  In this step we swap labels if it\n            // improves the modularity score.\n            bool flipped_label = true;\n            while(flipped_label)\n            {\n                flipped_label = false;\n                unsigned long idx = 0;\n                for (long i = 0; i < labels.size(); ++i)\n                {\n                    const double val = -2*labels(i);\n                    const double increase = 4*Bdiag(i) + 2*val*Bv(i);\n\n                    // if there is an increase in modularity for swapping this label\n                    if (increase > 0)\n                    {\n                        labels(i) *= -1;\n                        while (idx < edges.size() && edges[idx].index1() == (unsigned long)i)\n                        {\n                            const long j = edges[idx].index2();\n                            Bv(j) += val*edges[idx].distance();\n                            ++idx;\n                        }\n\n                        Bv -= (val*node_degrees(i)/(2*edge_sum))*node_degrees;\n\n                        flipped_label = true;\n                    }\n                    else\n                    {\n                        while (idx < edges.size() && edges[idx].index1() == (unsigned long)i)\n                        {\n                            ++idx;\n                        }\n                    }\n                }\n            }\n\n\n            const double modularity = dot(Bv, labels)/(4*edge_sum);\n\n            return modularity;\n        }\n\n    // -------------------------------------------------------------------------------------\n\n        inline unsigned long newman_cluster_helper (\n            dlib::rand& rnd,\n            const std::vector<ordered_sample_pair>& edges,\n            const matrix<double,0,1>& node_degrees, // k from the Newman paper\n            const matrix<double,0,1>& Bdiag,        // diag(B) from the Newman paper\n            const double& edge_sum,                 // m from the Newman paper\n            std::vector<unsigned long>& labels,\n            double modularity_threshold,\n            const double eps,\n            const unsigned long max_iterations\n        )\n        /*!\n            ensures\n                - returns the number of clusters the data was split into\n        !*/\n        {\n            matrix<double,0,1> l;\n            const double modularity = newman_cluster_split(rnd,edges,node_degrees,Bdiag,edge_sum,l,eps,max_iterations);\n\n\n            // We need to collapse the node index values down to contiguous values.  So\n            // we use the following two vectors to contain the mappings from input index\n            // values to their corresponding index values in each split.\n            std::vector<unsigned long> left_idx_map(node_degrees.size());\n            std::vector<unsigned long> right_idx_map(node_degrees.size());\n\n            // figure out how many nodes went into each side of the split.\n            unsigned long num_left_split = 0;\n            unsigned long num_right_split = 0;\n            for (long i = 0; i < l.size(); ++i)\n            {\n                if (l(i) > 0)\n                {\n                    left_idx_map[i] = num_left_split;\n                    ++num_left_split;\n                }\n                else\n                {\n                    right_idx_map[i] = num_right_split;\n                    ++num_right_split;\n                }\n            }\n\n            // do a recursive split if it will improve the modularity.\n            if (modularity > modularity_threshold && num_left_split > 0 && num_right_split > 0)\n            {\n\n                // split the node_degrees and Bdiag matrices into left and right split parts\n                matrix<double,0,1> left_node_degrees(num_left_split);\n                matrix<double,0,1> right_node_degrees(num_right_split);\n                matrix<double,0,1> left_Bdiag(num_left_split);\n                matrix<double,0,1> right_Bdiag(num_right_split);\n                for (long i = 0; i < l.size(); ++i)\n                {\n                    if (l(i) > 0)\n                    {\n                        left_node_degrees(left_idx_map[i]) = node_degrees(i);\n                        left_Bdiag(left_idx_map[i]) = Bdiag(i);\n                    }\n                    else\n                    {\n                        right_node_degrees(right_idx_map[i]) = node_degrees(i);\n                        right_Bdiag(right_idx_map[i]) = Bdiag(i);\n                    }\n                }\n\n\n                // put the edges from one side of the split into split_edges\n                std::vector<ordered_sample_pair> split_edges;\n                modularity_threshold = 0;\n                for (unsigned long k = 0; k < edges.size(); ++k)\n                {\n                    const unsigned long i = edges[k].index1();\n                    const unsigned long j = edges[k].index2();\n                    const double d = edges[k].distance();\n                    if (l(i) > 0 && l(j) > 0)\n                    {\n                        split_edges.push_back(ordered_sample_pair(left_idx_map[i], left_idx_map[j], d));\n                        modularity_threshold += d;\n                    }\n                }\n                modularity_threshold -= sum(left_node_degrees*sum(left_node_degrees))/(2*edge_sum);\n                modularity_threshold /= 4*edge_sum;\n\n                unsigned long num_left_clusters;\n                std::vector<unsigned long> left_labels;\n                num_left_clusters = newman_cluster_helper(rnd,split_edges,left_node_degrees,left_Bdiag,\n                                                          edge_sum,left_labels,modularity_threshold,\n                                                          eps, max_iterations);\n\n                // now load the other side into split_edges and cluster it as well\n                split_edges.clear();\n                modularity_threshold = 0;\n                for (unsigned long k = 0; k < edges.size(); ++k)\n                {\n                    const unsigned long i = edges[k].index1();\n                    const unsigned long j = edges[k].index2();\n                    const double d = edges[k].distance();\n                    if (l(i) < 0 && l(j) < 0)\n                    {\n                        split_edges.push_back(ordered_sample_pair(right_idx_map[i], right_idx_map[j], d));\n                        modularity_threshold += d;\n                    }\n                }\n                modularity_threshold -= sum(right_node_degrees*sum(right_node_degrees))/(2*edge_sum);\n                modularity_threshold /= 4*edge_sum;\n\n                unsigned long num_right_clusters;\n                std::vector<unsigned long> right_labels;\n                num_right_clusters = newman_cluster_helper(rnd,split_edges,right_node_degrees,right_Bdiag,\n                                                           edge_sum,right_labels,modularity_threshold,\n                                                           eps, max_iterations);\n\n                // Now merge the labels from the two splits.\n                labels.resize(node_degrees.size());\n                for (unsigned long i = 0; i < labels.size(); ++i)\n                {\n                    // if this node was in the left split\n                    if (l(i) > 0)\n                    {\n                        labels[i] = left_labels[left_idx_map[i]];\n                    }\n                    else // if this node was in the right split\n                    {\n                        labels[i] = right_labels[right_idx_map[i]] + num_left_clusters;\n                    }\n                }\n\n\n                return num_left_clusters + num_right_clusters;\n            }\n            else\n            {\n                labels.assign(node_degrees.size(),0);\n                return 1;\n            }\n\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long newman_cluster (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const double eps = 1e-4,\n        const unsigned long max_iterations = 2000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_ordered_by_index(edges),\n                    \"\\t unsigned long newman_cluster()\"\n                    << \"\\n\\t Invalid inputs were given to this function\"\n        );\n\n        labels.clear();\n        if (edges.size() == 0)\n            return 0;\n\n        const unsigned long num_nodes = max_index_plus_one(edges);\n\n        // compute the node_degrees vector, edge_sum value, and diag(B).\n        matrix<double,0,1> node_degrees(num_nodes);\n        matrix<double,0,1> Bdiag(num_nodes);\n        Bdiag = 0;\n        double edge_sum = 0;\n        node_degrees = 0;\n        for (unsigned long i = 0; i < edges.size(); ++i)\n        {\n            node_degrees(edges[i].index1()) += edges[i].distance();\n            edge_sum += edges[i].distance();\n            if (edges[i].index1() == edges[i].index2())\n                Bdiag(edges[i].index1()) += edges[i].distance();\n        }\n        edge_sum /= 2;\n        Bdiag -= squared(node_degrees)/(2*edge_sum);\n\n\n        dlib::rand rnd;\n        return impl::newman_cluster_helper(rnd,edges,node_degrees,Bdiag,edge_sum,labels,0,eps,max_iterations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long newman_cluster (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const double eps = 1e-4,\n        const unsigned long max_iterations = 2000\n    )\n    {\n        std::vector<ordered_sample_pair> oedges;\n        convert_unordered_to_ordered(edges, oedges);\n        std::sort(oedges.begin(), oedges.end(), &order_by_index<ordered_sample_pair>);\n\n        return newman_cluster(oedges, labels, eps, max_iterations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline std::vector<unsigned long> remap_labels (\n            const std::vector<unsigned long>& labels,\n            unsigned long& num_labels\n        )\n        /*!\n            ensures\n                - This function takes labels and produces a mapping which maps elements of\n                  labels into the most compact range in [0, max] as possible.  In particular,\n                  there won't be any unused integers in the mapped range.\n                - #num_labels == the number of distinct values in labels.\n                - returns a vector V such that:\n                    - V.size() == labels.size()\n                    - max(mat(V))+1 == num_labels.\n                    - for all valid i,j:\n                        - if (labels[i] == labels[j]) then\n                            - V[i] == V[j]\n                        - else\n                            - V[i] != V[j]\n        !*/\n        {\n            std::map<unsigned long, unsigned long> temp;\n            for (unsigned long i = 0; i < labels.size(); ++i)\n            {\n                if (temp.count(labels[i]) == 0)\n                {\n                    const unsigned long next = temp.size();\n                    temp[labels[i]] = next;\n                }\n            }\n\n            num_labels = temp.size();\n\n            std::vector<unsigned long> result(labels.size());\n            for (unsigned long i = 0; i < labels.size(); ++i)\n            {\n                result[i] = temp[labels[i]];\n            }\n            return result;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double modularity (\n        const std::vector<sample_pair>& edges,\n        const std::vector<unsigned long>& labels\n    )\n    {\n        const unsigned long num_nodes = max_index_plus_one(edges);\n        // make sure requires clause is not broken\n        DLIB_ASSERT(labels.size() == num_nodes,\n                    \"\\t double modularity()\"\n                    << \"\\n\\t Invalid inputs were given to this function\"\n        );\n\n        unsigned long num_labels;\n        const std::vector<unsigned long>& labels_ = dlib::impl::remap_labels(labels,num_labels);\n\n        std::vector<double> cluster_sums(num_labels,0);\n        std::vector<double> k(num_nodes,0);\n\n        double Q = 0;\n        double m = 0;\n        for (unsigned long i = 0; i < edges.size(); ++i)\n        {\n            const unsigned long n1 = edges[i].index1();\n            const unsigned long n2 = edges[i].index2();\n            k[n1] += edges[i].distance();\n            if (n1 != n2)\n                k[n2] += edges[i].distance();\n\n            if (n1 != n2)\n                m += edges[i].distance();\n            else\n                m += edges[i].distance()/2;\n\n            if (labels_[n1] == labels_[n2])\n            {\n                if (n1 != n2)\n                    Q += 2*edges[i].distance();\n                else\n                    Q += edges[i].distance();\n            }\n        }\n\n        if (m == 0)\n            return 0;\n\n        for (unsigned long i = 0; i < labels_.size(); ++i)\n        {\n            cluster_sums[labels_[i]] += k[i];\n        }\n\n        for (unsigned long i = 0; i < labels_.size(); ++i)\n        {\n            Q -= k[i]*cluster_sums[labels_[i]]/(2*m);\n        }\n\n        return 1.0/(2*m)*Q;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double modularity (\n        const std::vector<ordered_sample_pair>& edges,\n        const std::vector<unsigned long>& labels\n    )\n    {\n        const unsigned long num_nodes = max_index_plus_one(edges);\n        // make sure requires clause is not broken\n        DLIB_ASSERT(labels.size() == num_nodes,\n                    \"\\t double modularity()\"\n                    << \"\\n\\t Invalid inputs were given to this function\"\n        );\n\n\n        unsigned long num_labels;\n        const std::vector<unsigned long>& labels_ = dlib::impl::remap_labels(labels,num_labels);\n\n        std::vector<double> cluster_sums(num_labels,0);\n        std::vector<double> k(num_nodes,0);\n\n        double Q = 0;\n        double m = 0;\n        for (unsigned long i = 0; i < edges.size(); ++i)\n        {\n            const unsigned long n1 = edges[i].index1();\n            const unsigned long n2 = edges[i].index2();\n            k[n1] += edges[i].distance();\n            m += edges[i].distance();\n            if (labels_[n1] == labels_[n2])\n            {\n                Q += edges[i].distance();\n            }\n        }\n\n        if (m == 0)\n            return 0;\n\n        for (unsigned long i = 0; i < labels_.size(); ++i)\n        {\n            cluster_sums[labels_[i]] += k[i];\n        }\n\n        for (unsigned long i = 0; i < labels_.size(); ++i)\n        {\n            Q -= k[i]*cluster_sums[labels_[i]]/m;\n        }\n\n        return 1.0/m*Q;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MODULARITY_ClUSTERING__H__\n\n"
  },
  {
    "path": "dlib/clustering/modularity_clustering_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_\n#ifdef DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../graph_utils/ordered_sample_pair_abstract.h\"\n#include \"../graph_utils/sample_pair_abstract.h\"\n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------\n\n    double modularity (\n        const std::vector<sample_pair>& edges,\n        const std::vector<unsigned long>& labels\n    );\n    /*!\n        requires\n            - labels.size() == max_index_plus_one(edges)\n            - for all valid i:\n                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()\n        ensures\n            - Interprets edges as an undirected graph.  That is, it contains the edges on\n              the said graph and the sample_pair::distance() values define the edge weights\n              (larger values indicating a stronger edge connection between the nodes).\n            - This function returns the modularity value obtained when the given input\n              graph is broken into subgraphs according to the contents of labels.  In\n              particular, we say that two nodes with indices i and j are in the same\n              subgraph or community if and only if labels[i] == labels[j].\n            - Duplicate edges are interpreted as if there had been just one edge with a\n              distance value equal to the sum of all the duplicate edge's distance values.\n            - See the paper Modularity and community structure in networks by M. E. J. Newman\n              for a detailed definition.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    double modularity (\n        const std::vector<ordered_sample_pair>& edges,\n        const std::vector<unsigned long>& labels\n    );\n    /*!\n        requires\n            - labels.size() == max_index_plus_one(edges)\n            - for all valid i:\n                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()\n        ensures\n            - Interprets edges as a directed graph.  That is, it contains the edges on the\n              said graph and the ordered_sample_pair::distance() values define the edge\n              weights (larger values indicating a stronger edge connection between the\n              nodes).  Note that, generally, modularity is only really defined for\n              undirected graphs.  Therefore, the \"directed graph\" given to this function\n              should have symmetric edges between all nodes.  The reason this function is\n              provided at all is because sometimes a vector of ordered_sample_pair objects\n              is a useful representation of an undirected graph.\n            - This function returns the modularity value obtained when the given input\n              graph is broken into subgraphs according to the contents of labels.  In\n              particular, we say that two nodes with indices i and j are in the same\n              subgraph or community if and only if labels[i] == labels[j].\n            - Duplicate edges are interpreted as if there had been just one edge with a\n              distance value equal to the sum of all the duplicate edge's distance values.\n            - See the paper Modularity and community structure in networks by M. E. J. Newman\n              for a detailed definition.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long newman_cluster (\n        const std::vector<ordered_sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const double eps = 1e-4,\n        const unsigned long max_iterations = 2000\n    );\n    /*!\n        requires\n            - is_ordered_by_index(edges) == true\n            - for all valid i:\n                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()\n        ensures\n            - This function performs the clustering algorithm described in the paper\n              Modularity and community structure in networks by M. E. J. Newman.  \n            - This function interprets edges as a graph and attempts to find the labeling\n              that maximizes modularity(edges, #labels).   \n            - returns the number of clusters found.\n            - #labels.size() == max_index_plus_one(edges)\n            - for all valid i:\n                - #labels[i] == the cluster ID of the node with index i in the graph.  \n                - 0 <= #labels[i] < the number of clusters found\n                  (i.e. cluster IDs are assigned contiguously and start at 0) \n            - The main computation of the algorithm is involved in finding an eigenvector\n              of a certain matrix.  To do this, we use the power iteration.  In particular,\n              each time we try to find an eigenvector we will let the power iteration loop\n              at most max_iterations times or until it reaches an accuracy of eps.\n              Whichever comes first.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long newman_cluster (\n        const std::vector<sample_pair>& edges,\n        std::vector<unsigned long>& labels,\n        const double eps = 1e-4,\n        const unsigned long max_iterations = 2000\n    );\n    /*!\n        requires\n            - for all valid i:\n                - 0 <= edges[i].distance() < std::numeric_limits<double>::infinity()\n        ensures\n            - This function is identical to the above newman_cluster() routine except that\n              it operates on a vector of sample_pair objects instead of\n              ordered_sample_pairs.  Therefore, this is simply a convenience routine.  In\n              particular, it is implemented by transforming the given edges into\n              ordered_sample_pairs and then calling the newman_cluster() routine defined\n              above.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MODULARITY_ClUSTERING_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/clustering/spectral_cluster.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SPECTRAL_CLUSTEr_H_\n#define DLIB_SPECTRAL_CLUSTEr_H_\n\n#include \"spectral_cluster_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include \"../svm/kkmeans.h\"\n\nnamespace dlib\n{\n    template <\n        typename kernel_type,\n        typename vector_type\n        >\n    std::vector<unsigned long> spectral_cluster (\n        const kernel_type& k,\n        const vector_type& samples,\n        const unsigned long num_clusters\n    )\n    {\n        DLIB_CASSERT(num_clusters > 0, \n            \"\\t std::vector<unsigned long> spectral_cluster(k,samples,num_clusters)\"\n            << \"\\n\\t num_clusters can't be 0.\"\n            );\n\n        if (num_clusters == 1)\n        {\n            // nothing to do, just assign everything to the 0 cluster.\n            return std::vector<unsigned long>(samples.size(), 0);\n        }\n\n        // compute the similarity matrix.\n        matrix<double> K(samples.size(), samples.size());\n        for (long r = 0; r < K.nr(); ++r)\n            for (long c = r+1; c < K.nc(); ++c)\n                K(r,c) = K(c,r) = (double)k(samples[r], samples[c]);\n        for (long r = 0; r < K.nr(); ++r)\n            K(r,r) = 0;\n\n        matrix<double,0,1> D(K.nr());\n        for (long r = 0; r < K.nr(); ++r)\n            D(r) = sum(rowm(K,r));\n        D = sqrt(reciprocal(D));\n        K = diagm(D)*K*diagm(D); \n        matrix<double> u,w,v;\n        // Use the normal SVD routine unless the matrix is really big, then use the fast\n        // approximate version.\n        if (K.nr() < 1000)\n            svd3(K,u,w,v);\n        else\n            svd_fast(K,u,w,v, num_clusters+100, 5);\n        // Pick out the eigenvectors associated with the largest eigenvalues.\n        rsort_columns(v,w);\n        v = colm(v, range(0,num_clusters-1));\n        // Now build the normalized spectral vectors, one for each input vector.\n        std::vector<matrix<double,0,1> > spec_samps, centers;\n        for (long r = 0; r < v.nr(); ++r)\n        {\n            spec_samps.push_back(trans(rowm(v,r)));\n            const double len = length(spec_samps.back());\n            if (len != 0)\n                spec_samps.back() /= len;\n        }\n        // Finally do the K-means clustering\n        pick_initial_centers(num_clusters, centers, spec_samps);\n        find_clusters_using_kmeans(spec_samps, centers);\n        // And then compute the cluster assignments based on the output of K-means.\n        std::vector<unsigned long> assignments;\n        for (unsigned long i = 0; i < spec_samps.size(); ++i)\n            assignments.push_back(nearest_center(centers, spec_samps[i]));\n\n        return assignments;\n    }\n\n}\n\n#endif // DLIB_SPECTRAL_CLUSTEr_H_\n\n"
  },
  {
    "path": "dlib/clustering/spectral_cluster_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_\n#ifdef DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_\n\n#include <vector>\n\nnamespace dlib\n{\n    template <\n        typename kernel_type,\n        typename vector_type\n        >\n    std::vector<unsigned long> spectral_cluster (\n        const kernel_type& k,\n        const vector_type& samples,\n        const unsigned long num_clusters\n    );\n    /*!\n        requires\n            - samples must be something with an interface compatible with std::vector.\n            - The following expression must evaluate to a double or float:\n                k(samples[i], samples[j])\n            - num_clusters > 0\n        ensures\n            - Performs the spectral clustering algorithm described in the paper: \n              On spectral clustering: Analysis and an algorithm by Ng, Jordan, and Weiss.\n              and returns the results.\n            - This function clusters the input data samples into num_clusters clusters and\n              returns a vector that indicates which cluster each sample falls into.  In\n              particular, we return an array A such that:\n                - A.size() == samples.size()\n                - A[i] == the cluster assignment of samples[i].\n                - for all valid i: 0 <= A[i] < num_clusters \n            - The \"similarity\" of samples[i] with samples[j] is given by\n              k(samples[i],samples[j]).  This means that k() should output a number >= 0\n              and the number should be larger for samples that are more similar.\n    !*/\n}\n\n#endif // DLIB_SPECTRAL_CLUSTEr_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/clustering.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CLuSTERING_\n#define DLIB_CLuSTERING_\n\n#include \"clustering/modularity_clustering.h\"\n#include \"clustering/chinese_whispers.h\"\n#include \"clustering/spectral_cluster.h\"\n#include \"clustering/bottom_up_cluster.h\"\n#include \"svm/kkmeans.h\"\n\n#endif // DLIB_CLuSTERING_\n\n"
  },
  {
    "path": "dlib/cmake",
    "content": "\ncmake_minimum_required(VERSION 3.8.0)\n\nadd_subdirectory(${CMAKE_CURRENT_LIST_DIR} dlib_build)\n\n"
  },
  {
    "path": "dlib/cmake_utils/FindCUDNN.cmake",
    "content": "# Find the CUDNN libraries\n#\n# The following variables are optionally searched for defaults\n#  CUDNN_ROOT: Base directory where CUDNN is found\n#  CUDNN_INCLUDE_DIR: Directory where CUDNN header is searched for\n#  CUDNN_LIBRARY: Directory where CUDNN library is searched for\n#  CUDNN_STATIC: Are we looking for a static library? (default: no)\n#\n# The following are set after configuration is done:\n#  CUDNN_FOUND\n#  CUDNN_INCLUDE_PATH\n#  CUDNN_LIBRARY_PATH\n#\n\ninclude(FindPackageHandleStandardArgs)\n\nset(CUDNN_ROOT $ENV{CUDNN_ROOT_DIR} CACHE PATH \"Folder containing NVIDIA cuDNN\")\nif (DEFINED $ENV{CUDNN_ROOT_DIR})\n  message(WARNING \"CUDNN_ROOT_DIR is deprecated. Please set CUDNN_ROOT instead.\")\nendif()\nlist(APPEND CUDNN_ROOT $ENV{CUDNN_ROOT_DIR} ${CUDA_TOOLKIT_ROOT_DIR})\n\n# Compatible layer for CMake <3.12. CUDNN_ROOT will be accounted in for searching paths and libraries for CMake >=3.12.\nlist(APPEND CMAKE_PREFIX_PATH ${CUDNN_ROOT})\n\nset(CUDNN_INCLUDE_DIR $ENV{CUDNN_INCLUDE_DIR} CACHE PATH \"Folder containing NVIDIA cuDNN header files\")\n\nset(CUDA_VERSION \"${CUDAToolkit_VERSION_MAJOR}.${CUDAToolkit_VERSION_MINOR}\")\n\nfind_path(CUDNN_INCLUDE_PATH cudnn.h\n  HINTS ${CUDNN_INCLUDE_DIR} ENV CUDNN_INCLUDE_DIR  ENV CUDNN_HOME\n  PATHS /usr/local /usr/local/cuda \"C:/Program Files/NVIDIA/CUDNN/*/include/${CUDA_VERSION}\" \"C:/Program Files/NVIDIA/CUDNN/*/include/*\" ENV CPATH\n  PATH_SUFFIXES cuda/include cuda include)\n\noption(CUDNN_STATIC \"Look for static CUDNN\" OFF)\nif (CUDNN_STATIC)\n  set(CUDNN_LIBNAME \"libcudnn_static.a\")\nelse()\n  set(CUDNN_LIBNAME \"cudnn\")\nendif()\n\nset(CUDNN_LIBRARY $ENV{CUDNN_LIBRARY} CACHE PATH \"Path to the cudnn library file (e.g., libcudnn.so)\")\nif (CUDNN_LIBRARY MATCHES \".*cudnn_static.a\" AND NOT CUDNN_STATIC)\n  message(WARNING \"CUDNN_LIBRARY points to a static library (${CUDNN_LIBRARY}) but CUDNN_STATIC is OFF.\")\nendif()\n\nfind_library(CUDNN_LIBRARY_PATH ${CUDNN_LIBNAME}\n  PATHS ${CUDNN_LIBRARY} /usr/local /usr/local/cuda  \"C:/Program Files/NVIDIA/CUDNN/*/lib/${CUDA_VERSION}/x64\" \"C:/Program Files/NVIDIA/CUDNN/*/lib/${CUDA_VERSION}\" \"C:/Program Files/NVIDIA/CUDNN/*/lib/*\" ENV LD_LIBRARY_PATH\n  PATH_SUFFIXES lib lib64 cuda/lib cuda/lib64 lib/x64)\n\nfind_package_handle_standard_args(CUDNN DEFAULT_MSG CUDNN_LIBRARY_PATH CUDNN_INCLUDE_PATH)\n\nif(CUDNN_FOUND)\n  # Get cuDNN version\n  if(EXISTS ${CUDNN_INCLUDE_PATH}/cudnn_version.h)\n    file(READ ${CUDNN_INCLUDE_PATH}/cudnn_version.h CUDNN_HEADER_CONTENTS)\n  else()\n    file(READ ${CUDNN_INCLUDE_PATH}/cudnn.h CUDNN_HEADER_CONTENTS)\n  endif()\n  string(REGEX MATCH \"define CUDNN_MAJOR * +([0-9]+)\"\n               CUDNN_VERSION_MAJOR \"${CUDNN_HEADER_CONTENTS}\")\n  string(REGEX REPLACE \"define CUDNN_MAJOR * +([0-9]+)\" \"\\\\1\"\n               CUDNN_VERSION_MAJOR \"${CUDNN_VERSION_MAJOR}\")\n  string(REGEX MATCH \"define CUDNN_MINOR * +([0-9]+)\"\n               CUDNN_VERSION_MINOR \"${CUDNN_HEADER_CONTENTS}\")\n  string(REGEX REPLACE \"define CUDNN_MINOR * +([0-9]+)\" \"\\\\1\"\n               CUDNN_VERSION_MINOR \"${CUDNN_VERSION_MINOR}\")\n  string(REGEX MATCH \"define CUDNN_PATCHLEVEL * +([0-9]+)\"\n               CUDNN_VERSION_PATCH \"${CUDNN_HEADER_CONTENTS}\")\n  string(REGEX REPLACE \"define CUDNN_PATCHLEVEL * +([0-9]+)\" \"\\\\1\"\n               CUDNN_VERSION_PATCH \"${CUDNN_VERSION_PATCH}\")\n  # Assemble cuDNN version\n  if(NOT CUDNN_VERSION_MAJOR)\n    set(CUDNN_VERSION \"?\")\n  else()\n    set(CUDNN_VERSION\n        \"${CUDNN_VERSION_MAJOR}.${CUDNN_VERSION_MINOR}.${CUDNN_VERSION_PATCH}\")\n  endif()\nendif()\n\nmark_as_advanced(CUDNN_ROOT CUDNN_INCLUDE_DIR CUDNN_LIBRARY CUDNN_VERSION)\n"
  },
  {
    "path": "dlib/cmake_utils/check_if_avx_instructions_executable_on_host.cmake",
    "content": "# This script checks if your compiler and host processor can generate and then run programs with AVX instructions.\n\ncmake_minimum_required(VERSION 3.10.0)\n\n# Don't rerun this script if its already been executed.\nif (DEFINED AVX_IS_AVAILABLE_ON_HOST)\n   return()\nendif()\n\n# Set to false unless we find out otherwise in the code below.\nset(AVX_IS_AVAILABLE_ON_HOST 0)\n\ntry_compile(test_for_avx_worked ${PROJECT_BINARY_DIR}/avx_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_avx \n\tavx_test)\n\nif(test_for_avx_worked)\n\tmessage (STATUS \"AVX instructions can be executed by the host processor.\")\n\tset(AVX_IS_AVAILABLE_ON_HOST 1)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/check_if_neon_available.cmake",
    "content": "# This script checks if __ARM_NEON__ is defined for your compiler\n\ncmake_minimum_required(VERSION 3.10.0)\n\n# Don't rerun this script if its already been executed.\nif (DEFINED ARM_NEON_IS_AVAILABLE)\n   return()\nendif()\n\n# Set to false unless we find out otherwise in the code below.\nset(ARM_NEON_IS_AVAILABLE 0)\n\n# test if __ARM_NEON__ is defined\ntry_compile(test_for_neon_worked ${PROJECT_BINARY_DIR}/neon_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_neon \n   neon_test)\n\nif(test_for_neon_worked)\n   message (STATUS \"__ARM_NEON__ defined.\")\n   set(ARM_NEON_IS_AVAILABLE 1)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/check_if_sse4_instructions_executable_on_host.cmake",
    "content": "# This script checks if your compiler and host processor can generate and then run programs with SSE4 instructions.\n\ncmake_minimum_required(VERSION 3.10.0)\n\n# Don't rerun this script if its already been executed.\nif (DEFINED SSE4_IS_AVAILABLE_ON_HOST)\n   return()\nendif()\n\n# Set to false unless we find out otherwise in the code below.\nset(SSE4_IS_AVAILABLE_ON_HOST 0)\n\ntry_compile(test_for_sse4_worked ${PROJECT_BINARY_DIR}/sse4_test_build ${CMAKE_CURRENT_LIST_DIR}/test_for_sse4\n\tsse4_test)\n\nif(test_for_sse4_worked)\n\tmessage (STATUS \"SSE4 instructions can be executed by the host processor.\")\n\tset(SSE4_IS_AVAILABLE_ON_HOST 1)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/dlib.pc.in",
    "content": "libdir=@CMAKE_INSTALL_FULL_LIBDIR@\nincludedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@\n\nName: @PROJECT_NAME@\nDescription: Numerical and networking C++ library\nVersion: @VERSION@\nLibs: -L${libdir} -ldlib @pkg_config_dlib_needed_libraries@\nCflags: -I${includedir} @pkg_config_dlib_needed_includes@\n"
  },
  {
    "path": "dlib/cmake_utils/dlibConfig.cmake.in",
    "content": "# ===================================================================================\n#  The dlib CMake configuration file\n#\n#             ** File generated automatically, do not modify **\n#\n#  Usage from an external project:\n#    In your CMakeLists.txt, add these lines:\n#\n#    find_package(dlib REQUIRED)\n#    target_link_libraries(MY_TARGET_NAME dlib::dlib)\n#\n# ===================================================================================\n\n\n\n \n# Our library dependencies (contains definitions for IMPORTED targets)\nif(NOT TARGET dlib-shared AND NOT dlib_BINARY_DIR)\n   # Compute paths\n   get_filename_component(dlib_CMAKE_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n   include(\"${dlib_CMAKE_DIR}/dlib.cmake\")\n   # Check if Threads::Threads target is required and find it if necessary\n   get_target_property(dlib_deps_threads_check dlib::dlib INTERFACE_LINK_LIBRARIES)\n   list(FIND dlib_deps_threads_check \"Threads::Threads\" dlib_deps_threads_idx)\n   if (${dlib_deps_threads_idx} GREATER -1)\n      if (NOT TARGET Threads)\n         find_package(Threads REQUIRED)\n      endif()\n   endif()\n   unset(dlib_deps_threads_idx)\n   unset(dlib_deps_threads_check)\nendif()\n\nset(dlib_LIBRARIES dlib::dlib)\nset(dlib_LIBS      dlib::dlib)\nset(dlib_INCLUDE_DIRS \"@CMAKE_INSTALL_FULL_INCLUDEDIR@\" \"@dlib_needed_includes@\")\n\nif (@DLIB_USE_CUDA@)\n   find_package(CUDAToolkit)\nendif()\n\nmark_as_advanced(dlib_LIBRARIES)\nmark_as_advanced(dlib_LIBS)\nmark_as_advanced(dlib_INCLUDE_DIRS)\n\n# Mark these variables above as deprecated.\nfunction(__deprecated_var var access)\n   if(access STREQUAL \"READ_ACCESS\")\n      message(WARNING \"The variable '${var}' is deprecated!  Instead, simply use target_link_libraries(your_app dlib::dlib).  See http://dlib.net/examples/CMakeLists.txt.html for an example.\")\n   endif()\nendfunction()\nvariable_watch(dlib_LIBRARIES __deprecated_var)\nvariable_watch(dlib_LIBS __deprecated_var)\nvariable_watch(dlib_INCLUDE_DIRS __deprecated_var)\n\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/find_blas.cmake",
    "content": "#\n# This is a CMake makefile.  You can find the cmake utility and\n# information about it at http://www.cmake.org\n#\n#\n# This cmake file tries to find installed BLAS and LAPACK libraries.  \n# It looks for an installed copy of the Intel MKL library first and then\n# attempts to find some other BLAS and LAPACK libraries if you don't have \n# the Intel MKL.\n#\n#  blas_found               - True if BLAS is available\n#  lapack_found             - True if LAPACK is available\n#  found_intel_mkl          - True if the Intel MKL library is available\n#  found_intel_mkl_headers  - True if Intel MKL headers are available\n#  blas_libraries           - link against these to use BLAS library \n#  lapack_libraries         - link against these to use LAPACK library \n#  mkl_libraries            - link against these to use the MKL library\n#  mkl_include_dir          - add to the include path to use the MKL library\n#  openmp_libraries         - Set to Intel's OpenMP library if and only if we\n#                             find the MKL.\n\n# setting this makes CMake allow normal looking if else statements\nSET(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)\n\nSET(blas_found 0)\nSET(lapack_found 0)\nSET(found_intel_mkl 0)\nSET(found_intel_mkl_headers 0)\nSET(lapack_with_underscore 0)\nSET(lapack_without_underscore 0)\n\nmessage(STATUS \"Searching for BLAS and LAPACK\")\nINCLUDE(CheckFunctionExists)\n\nif (UNIX OR MINGW)\n   message(STATUS \"Searching for BLAS and LAPACK\")\n\n   if (BUILDING_MATLAB_MEX_FILE)\n      # # This commented out stuff would link directly to MATLAB's built in\n      # BLAS and LAPACK. But it's better to not link to anything and do a\n      #find_library(MATLAB_BLAS_LIBRARY mwblas  PATHS ${MATLAB_LIB_FOLDERS} )\n      #find_library(MATLAB_LAPACK_LIBRARY mwlapack  PATHS ${MATLAB_LIB_FOLDERS} )\n      #if (MATLAB_BLAS_LIBRARY AND MATLAB_LAPACK_LIBRARY)\n      #    add_subdirectory(external/cblas)\n      #    set(blas_libraries  ${MATLAB_BLAS_LIBRARY} cblas  )\n      #    set(lapack_libraries  ${MATLAB_LAPACK_LIBRARY} )\n      #    set(blas_found 1)\n      #    set(lapack_found 1)\n      #    message(STATUS \"Found MATLAB's BLAS and LAPACK libraries\")\n      #endif()\n\n      # We need cblas since MATLAB doesn't provide cblas symbols.\n      add_subdirectory(external/cblas)\n      set(blas_libraries  cblas  )\n      set(blas_found 1)\n      set(lapack_found 1)\n      message(STATUS \"Will link with MATLAB's BLAS and LAPACK at runtime (hopefully!)\")\n\n\n      ## Don't try to link to anything other than MATLAB's own internal blas\n      ## and lapack libraries because doing so generally upsets MATLAB.  So\n      ## we just end here no matter what.\n      return()\n   endif()\n\n   \n   # First, search for libraries via pkg-config, which is the cleanest path\n   find_package(PkgConfig)\n   pkg_check_modules(BLAS_REFERENCE cblas)\n   pkg_check_modules(LAPACK_REFERENCE lapack)\n   # Make sure the cblas found by pkgconfig actually has cblas symbols.\n   SET(CMAKE_REQUIRED_LIBRARIES \"${BLAS_REFERENCE_LDFLAGS}\")   \n   CHECK_FUNCTION_EXISTS(cblas_ddot PKGCFG_HAVE_CBLAS)\n   if (BLAS_REFERENCE_FOUND AND LAPACK_REFERENCE_FOUND AND PKGCFG_HAVE_CBLAS)\n      set(blas_libraries \"${BLAS_REFERENCE_LDFLAGS}\")\n      set(lapack_libraries \"${LAPACK_REFERENCE_LDFLAGS}\")\n      set(blas_found 1)\n      set(lapack_found 1)\n      set(REQUIRES_LIBS \"${REQUIRES_LIBS} cblas lapack\")\n      message(STATUS \"Found BLAS and LAPACK via pkg-config\")\n      return()\n   endif()\n   \n   include(CheckTypeSize)\n   check_type_size( \"void*\" SIZE_OF_VOID_PTR)\n\n   if (SIZE_OF_VOID_PTR EQUAL 8)\n      set( mkl_search_path\n         /opt/intel/oneapi/mkl/latest/lib/intel64\n         /opt/intel/mkl/*/lib/em64t\n         /opt/intel/mkl/lib/intel64\n         /opt/intel/lib/intel64\n         /opt/intel/mkl/lib\n         /opt/intel/tbb/*/lib/em64t/gcc4.7\n         /opt/intel/tbb/lib/intel64/gcc4.7\n         /opt/intel/tbb/lib/gcc4.7\n         )\n\n      find_library(mkl_intel mkl_intel_lp64 ${mkl_search_path})\n      mark_as_advanced(mkl_intel)\n   else()\n      set( mkl_search_path\n         /opt/intel/oneapi/mkl/latest/lib/ia32\n         /opt/intel/mkl/*/lib/32\n         /opt/intel/mkl/lib/ia32\n         /opt/intel/lib/ia32\n         /opt/intel/tbb/*/lib/32/gcc4.7\n         /opt/intel/tbb/lib/ia32/gcc4.7\n         )\n\n      find_library(mkl_intel mkl_intel ${mkl_search_path})\n      mark_as_advanced(mkl_intel)\n   endif()\n\n   include(CheckLibraryExists)\n\n   # Get mkl_include_dir\n   set(mkl_include_search_path\n      /opt/intel/oneapi/mkl/latest/include\n      /opt/intel/mkl/include\n      /opt/intel/include\n      )\n   find_path(mkl_include_dir mkl_version.h ${mkl_include_search_path})\n   mark_as_advanced(mkl_include_dir)\n\n   if(NOT DLIB_USE_MKL_SEQUENTIAL AND NOT DLIB_USE_MKL_WITH_TBB)\n      # Search for the needed libraries from the MKL.  We will try to link against the mkl_rt\n      # file first since this way avoids linking bugs in some cases.\n      find_library(mkl_rt mkl_rt ${mkl_search_path})\n      find_library(openmp_libraries iomp5 ${mkl_search_path}) \n      mark_as_advanced(mkl_rt  openmp_libraries)\n      # if we found the MKL \n      if (mkl_rt)\n         set(mkl_libraries  ${mkl_rt} )\n         set(blas_libraries  ${mkl_rt} )\n         set(lapack_libraries  ${mkl_rt} )\n         set(blas_found 1)\n         set(lapack_found 1)\n         set(found_intel_mkl 1)\n         message(STATUS \"Found Intel MKL BLAS/LAPACK library\")\n      endif()\n   endif()\n   \n\n   if (NOT found_intel_mkl)\n      # Search for the needed libraries from the MKL.  This time try looking for a different\n      # set of MKL files and try to link against those.\n      find_library(mkl_core mkl_core ${mkl_search_path})\n      set(mkl_libs ${mkl_intel} ${mkl_core})\n      mark_as_advanced(mkl_libs mkl_intel mkl_core)\n\n      if (DLIB_USE_MKL_WITH_TBB)\n         find_library(mkl_tbb_thread mkl_tbb_thread ${mkl_search_path})\n         find_library(mkl_tbb tbb ${mkl_search_path})\n         mark_as_advanced(mkl_tbb_thread mkl_tbb)\n         list(APPEND mkl_libs ${mkl_tbb_thread} ${mkl_tbb})\n      elseif (DLIB_USE_MKL_SEQUENTIAL)\n         find_library(mkl_sequential mkl_sequential ${mkl_search_path})\n         mark_as_advanced(mkl_sequential)\n         list(APPEND mkl_libs ${mkl_sequential})\n      else()\n         find_library(mkl_thread mkl_intel_thread ${mkl_search_path})\n         find_library(mkl_iomp iomp5 ${mkl_search_path})\n         find_library(mkl_pthread pthread ${mkl_search_path})\n         mark_as_advanced(mkl_thread mkl_iomp mkl_pthread)\n         list(APPEND mkl_libs ${mkl_thread} ${mkl_iomp} ${mkl_pthread})\n      endif()\n   \n      # If we found the MKL \n      if (mkl_intel AND mkl_core AND ((mkl_tbb_thread AND mkl_tbb) OR (mkl_thread AND mkl_iomp AND mkl_pthread) OR mkl_sequential))\n         set(mkl_libraries ${mkl_libs})\n         set(blas_libraries ${mkl_libs})\n         set(lapack_libraries ${mkl_libs})\n         set(blas_found 1)\n         set(lapack_found 1)\n         set(found_intel_mkl 1)\n         message(STATUS \"Found Intel MKL BLAS/LAPACK library\")\n      endif()\n   endif()\n\n   if (found_intel_mkl AND mkl_include_dir)\n      set(found_intel_mkl_headers 1)\n   endif()\n\n   # try to find some other LAPACK libraries if we didn't find the MKL\n   set(extra_paths\n      /usr/lib64\n      /usr/lib64/atlas-sse3\n      /usr/lib64/atlas-sse2\n      /usr/lib64/atlas\n      /usr/lib\n      /usr/lib/atlas-sse3\n      /usr/lib/atlas-sse2\n      /usr/lib/atlas\n      /usr/lib/openblas-base\n      /opt/OpenBLAS/lib\n      $ENV{OPENBLAS_HOME}/lib\n      )\n\n   if (NOT blas_found)\n      find_library(cblas_lib NAMES openblasp openblas PATHS ${extra_paths})\n      if (cblas_lib)\n         set(blas_libraries ${cblas_lib})\n         set(blas_found 1)\n         message(STATUS \"Found OpenBLAS library\")\n         set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})\n         # If you compiled OpenBLAS with LAPACK in it then it should have the\n         # sgetrf_single function in it.  So if we find that function in\n         # OpenBLAS then just use OpenBLAS's LAPACK. \n         CHECK_FUNCTION_EXISTS(sgetrf_single OPENBLAS_HAS_LAPACK)\n         if (OPENBLAS_HAS_LAPACK)\n            message(STATUS \"Using OpenBLAS's built in LAPACK\")\n            # set(lapack_libraries gfortran) \n            set(lapack_found 1)\n         endif()\n      endif()\n      mark_as_advanced( cblas_lib)\n   endif()\n\n\n   if (NOT lapack_found)\n      find_library(lapack_lib NAMES lapack lapack-3 PATHS ${extra_paths})\n      if (lapack_lib)\n         set(lapack_libraries ${lapack_lib})\n         set(lapack_found 1)\n         message(STATUS \"Found LAPACK library\")\n      endif()\n      mark_as_advanced( lapack_lib)\n   endif()\n\n\n   # try to find some other BLAS libraries if we didn't find the MKL\n\n   if (NOT blas_found)\n      find_library(atlas_lib atlas PATHS ${extra_paths})\n      find_library(cblas_lib cblas PATHS ${extra_paths})\n      if (atlas_lib AND cblas_lib)\n         set(blas_libraries ${atlas_lib} ${cblas_lib})\n         set(blas_found 1)\n         message(STATUS \"Found ATLAS BLAS library\")\n      endif()\n      mark_as_advanced( atlas_lib cblas_lib)\n   endif()\n\n   # CentOS 7 atlas\n   if (NOT blas_found)\n      find_library(tatlas_lib tatlas PATHS ${extra_paths})\n      find_library(satlas_lib satlas PATHS ${extra_paths})\n      if (tatlas_lib AND satlas_lib )\n         set(blas_libraries ${tatlas_lib} ${satlas_lib})\n         set(blas_found 1)\n         message(STATUS \"Found ATLAS BLAS library\")\n      endif()\n      mark_as_advanced( tatlas_lib satlas_lib)\n   endif()\n\n\n   if (NOT blas_found)\n      find_library(cblas_lib cblas PATHS ${extra_paths})\n      if (cblas_lib)\n         set(blas_libraries ${cblas_lib})\n         set(blas_found 1)\n         message(STATUS \"Found CBLAS library\")\n      endif()\n      mark_as_advanced( cblas_lib)\n   endif()\n\n\n   if (NOT blas_found)\n      find_library(generic_blas blas PATHS ${extra_paths})\n      if (generic_blas)\n         set(blas_libraries ${generic_blas})\n         set(blas_found 1)\n         message(STATUS \"Found BLAS library\")\n      endif()\n      mark_as_advanced( generic_blas)\n   endif()\n\n\n\n\n   # Make sure we really found a CBLAS library.  That is, it needs to expose\n   # the proper cblas link symbols.  So here we test if one of them is present\n   # and assume everything is good if it is. Note that we don't do this check if\n   # we found the Intel MKL since for some reason CHECK_FUNCTION_EXISTS doesn't work\n   # with it.  But it's fine since the MKL should always have cblas.\n   if (blas_found AND NOT found_intel_mkl)\n      set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})\n      CHECK_FUNCTION_EXISTS(cblas_ddot FOUND_BLAS_HAS_CBLAS)\n      if (NOT FOUND_BLAS_HAS_CBLAS)\n         message(STATUS \"BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK\")\n         set(blas_found 0)\n         set(lapack_found 0)\n      endif()\n   endif()\n\n\n\nelseif(WIN32 AND NOT MINGW)\n   message(STATUS \"Searching for BLAS and LAPACK\")\n\n   include(CheckTypeSize)\n   check_type_size( \"void*\" SIZE_OF_VOID_PTR)\n   if (SIZE_OF_VOID_PTR EQUAL 8)\n      set( mkl_search_path\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/intel64\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/tbb/lib/intel64/vc14\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/intel64\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/intel64\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/tbb/lib/intel64/vc14\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/tbb/lib/intel64/vc_mt\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/intel64\" \n         \"C:/Program Files (x86)/Intel/Composer XE/mkl/lib/intel64\"\n         \"C:/Program Files (x86)/Intel/Composer XE/tbb/lib/intel64/vc14\"\n         \"C:/Program Files (x86)/Intel/Composer XE/compiler/lib/intel64\"\n         \"C:/Program Files/Intel/Composer XE/mkl/lib/intel64\"\n         \"C:/Program Files/Intel/Composer XE/tbb/lib/intel64/vc14\"\n         \"C:/Program Files/Intel/Composer XE/compiler/lib/intel64\"\n         \"C:/Program Files (x86)/Intel/oneAPI/mkl/*/lib\"\n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/lib\"\n         \"C:/Program Files (x86)/Intel/oneAPI/mkl/*/lib/intel64\"\n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/windows/compiler/lib/intel64_win\"\n         )\n      set (mkl_redist_path\n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/bin\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/redist/intel64/compiler\" \n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/windows/redist/intel64_win/compiler\"\n         )\n      find_library(mkl_intel  mkl_intel_lp64 ${mkl_search_path})\n   else()\n      set( mkl_search_path\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/lib/ia32\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/tbb/lib/ia32/vc14\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/lib/ia32\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/lib/ia32\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/tbb/lib/ia32/vc14\" \n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/tbb/lib/ia32/vc_mt\"\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/lib/ia32\"\n         \"C:/Program Files (x86)/Intel/Composer XE/mkl/lib/ia32\"\n         \"C:/Program Files (x86)/Intel/Composer XE/tbb/lib/ia32/vc14\"\n         \"C:/Program Files (x86)/Intel/Composer XE/compiler/lib/ia32\"\n         \"C:/Program Files/Intel/Composer XE/mkl/lib/ia32\"\n         \"C:/Program Files/Intel/Composer XE/tbb/lib/ia32/vc14\"\n         \"C:/Program Files/Intel/Composer XE/compiler/lib/ia32\"\n         \"C:/Program Files (x86)/Intel/oneAPI/mkl/*/lib/ia32\"\n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/windows/compiler/lib/ia32_win\"\n\n         )\n      set (mkl_redist_path\n         \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/redist/ia32/compiler\"\n         \"C:/Program Files (x86)/Intel/oneAPI/compiler/*/windows/redist/ia32_win/compiler\"\n         )\n      find_library(mkl_intel  mkl_intel_c ${mkl_search_path})\n   endif()\n\n\n   # Get mkl_include_dir\n   set(mkl_include_search_path\n      \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/mkl/include\"\n      \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries_*/windows/compiler/include\"\n      \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/mkl/include\"\n      \"C:/Program Files (x86)/IntelSWTools/compilers_and_libraries/windows/compiler/include\"\n      \"C:/Program Files (x86)/Intel/Composer XE/mkl/include\"\n      \"C:/Program Files (x86)/Intel/Composer XE/compiler/include\"\n      \"C:/Program Files/Intel/Composer XE/mkl/include\"\n      \"C:/Program Files/Intel/Composer XE/compiler/include\"\n      \"C:/Program Files (x86)/Intel/oneAPI/mkl/*/include\"\n      )\n   find_path(mkl_include_dir mkl_version.h ${mkl_include_search_path})\n   mark_as_advanced(mkl_include_dir)\n\n   # Search for the needed libraries from the MKL.  \n   find_library(mkl_core mkl_core ${mkl_search_path})\n   set(mkl_libs ${mkl_intel} ${mkl_core})\n   mark_as_advanced(mkl_libs mkl_intel mkl_core)\n   if (DLIB_USE_MKL_WITH_TBB)\n      find_library(mkl_tbb_thread mkl_tbb_thread ${mkl_search_path})\n      find_library(mkl_tbb tbb ${mkl_search_path})\n      mark_as_advanced(mkl_tbb_thread mkl_tbb)\n      list(APPEND mkl_libs ${mkl_tbb_thread} ${mkl_tbb})\n   elseif (DLIB_USE_MKL_SEQUENTIAL)\n      find_library(mkl_sequential mkl_sequential ${mkl_search_path})\n      mark_as_advanced(mkl_sequential)\n      list(APPEND mkl_libs ${mkl_sequential})\n   else()\n     find_library(mkl_thread mkl_intel_thread ${mkl_search_path})\n     mark_as_advanced(mkl_thread)\n     if (mkl_thread)\n        find_library(mkl_iomp libiomp5md ${mkl_search_path})\n        mark_as_advanced(mkl_iomp)\n        list(APPEND mkl_libs ${mkl_thread} ${mkl_iomp})\n\n        # See if we can find the dll that goes with this, so we can copy it to\n        # the output folder, since a very large number of windows users don't\n        # understand that they need to add the Intel MKL's folders to their\n        # PATH to use the Intel MKL.  They then complain on the dlib forums.\n        # Copying the Intel MKL dlls to the output directory removes the need\n        # to add the Intel MKL to the PATH.\n        find_file(mkl_iomp_dll \"libiomp5md.dll\" ${mkl_redist_path})\n        if (mkl_iomp_dll)\n            message(STATUS \"FOUND libiomp5md.dll: ${mkl_iomp_dll}\")\n        endif()\n     endif()\n   endif()\n\n   # If we found the MKL \n   if (mkl_intel AND mkl_core AND ((mkl_tbb_thread AND mkl_tbb) OR mkl_sequential OR (mkl_thread AND mkl_iomp)))\n      set(blas_libraries ${mkl_libs})\n      set(lapack_libraries ${mkl_libs})\n      set(blas_found 1)\n      set(lapack_found 1)\n      set(found_intel_mkl 1)\n      message(STATUS \"Found Intel MKL BLAS/LAPACK library\")\n\n      # Make sure the version of the Intel MKL we found is compatible with\n      # the compiler we are using.  One way to do this check is to see if we can\n      # link to it right now.\n      set(CMAKE_REQUIRED_LIBRARIES ${blas_libraries})\n      CHECK_FUNCTION_EXISTS(cblas_ddot MKL_HAS_CBLAS)\n      if (NOT MKL_HAS_CBLAS)\n         message(\"BLAS library does not have cblas symbols, so dlib will not use BLAS or LAPACK\")\n         set(blas_found 0)\n         set(lapack_found 0)\n      endif()\n   endif()\n\n   if (found_intel_mkl AND mkl_include_dir)\n      set(found_intel_mkl_headers 1)\n   endif()\n\nendif()\n\n\n# When all else fails use CMake's built in functions to find BLAS and LAPACK\nif (NOT blas_found)\n   find_package(BLAS QUIET)\n   if (${BLAS_FOUND})\n      set(blas_libraries ${BLAS_LIBRARIES})      \n      set(blas_found 1)\n      if (NOT lapack_found)\n         find_package(LAPACK QUIET)\n         if (${LAPACK_FOUND})\n            set(lapack_libraries ${LAPACK_LIBRARIES})\n            set(lapack_found 1)\n         endif()\n      endif()\n   endif()\nendif()\n\n\n# If using lapack, determine whether to mangle functions\nif (lapack_found)\n   include(CheckFortranFunctionExists)\n   set(CMAKE_REQUIRED_LIBRARIES ${lapack_libraries})\n\n   check_function_exists(\"sgesv\" LAPACK_FOUND_C_UNMANGLED)\n   check_function_exists(\"sgesv_\" LAPACK_FOUND_C_MANGLED)\n   if (CMAKE_Fortran_COMPILER_LOADED)\n      check_fortran_function_exists(\"sgesv\" LAPACK_FOUND_FORTRAN_UNMANGLED)\n      check_fortran_function_exists(\"sgesv_\" LAPACK_FOUND_FORTRAN_MANGLED)\n   endif ()\n   if (LAPACK_FOUND_C_MANGLED OR LAPACK_FOUND_FORTRAN_MANGLED)\n      set(lapack_with_underscore 1)\n   elseif (LAPACK_FOUND_C_UNMANGLED OR LAPACK_FOUND_FORTRAN_UNMANGLED)\n      set(lapack_without_underscore 1)\n   endif ()\nendif()\n\n\nif (UNIX OR MINGW)\n   if (NOT blas_found)\n      message(\" *****************************************************************************\")\n      message(\" *** No BLAS library found so using dlib's built in BLAS.  However, if you ***\")\n      message(\" *** install an optimized BLAS such as OpenBLAS or the Intel MKL your code ***\")\n      message(\" *** will run faster.  On Ubuntu you can install OpenBLAS by executing:    ***\")\n      message(\" ***    sudo apt-get install libopenblas-dev liblapack-dev                 ***\")\n      message(\" *** Or you can easily install OpenBLAS from source by downloading the     ***\")\n      message(\" *** source tar file from http://www.openblas.net, extracting it, and      ***\")\n      message(\" *** running:                                                              ***\")\n      message(\" ***    make; sudo make install                                            ***\")\n      message(\" *****************************************************************************\")\n   endif()\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/find_ffmpeg.cmake",
    "content": "cmake_minimum_required(VERSION 3.10.0)\n\nmessage(STATUS \"Searching for FFMPEG/LIBAV\")\nfind_package(PkgConfig)\nif (PkgConfig_FOUND)\n    pkg_check_modules(FFMPEG IMPORTED_TARGET\n        libavdevice\n        libavfilter\n        libavformat\n        libavcodec\n        libswresample\n        libswscale\n        libavutil\n    )\n    if (FFMPEG_FOUND)\n        message(STATUS \"Found FFMPEG/LIBAV via pkg-config in `${FFMPEG_LIBRARY_DIRS}`\")\n    else()\n        message(\" *****************************************************************************\")\n        message(\" *** No FFMPEG/LIBAV libraries found.                                      ***\")\n        message(\" *** On Ubuntu you can install them by executing                           ***\")\n        message(\" ***    sudo apt install libavdevice-dev libavfilter-dev libavformat-dev   ***\")\n        message(\" ***    sudo apt install libavcodec-dev libswresample-dev libswscale-dev   ***\")\n        message(\" ***    sudo apt install libavutil-dev                                     ***\")\n        message(\" *****************************************************************************\")\n    endif()\nelse()\n    message(STATUS \"PkgConfig could not be found, FFMPEG won't be available\")\n    set(FFMPEG_FOUND 0)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/find_libjpeg.cmake",
    "content": "#This script just runs CMake's built in JPEG finding tool.  But it also checks that the\n#copy of libjpeg that cmake finds actually builds and links.\n\ncmake_minimum_required(VERSION 3.10.0)\n\nif (BUILDING_PYTHON_IN_MSVC)\n   # Never use any system copy of libjpeg when building python in visual studio\n   set(JPEG_FOUND 0)\n   return()\nendif()\n\n# Don't rerun this script if its already been executed.\nif (DEFINED JPEG_FOUND)\n   return()\nendif()\n\nfind_package(JPEG QUIET)\n\nif(JPEG_FOUND)\n   set(JPEG_TEST_CMAKE_FLAGS \n      \"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}\"\n      \"-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}\"\n      \"-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}\")\n\n   try_compile(test_for_libjpeg_worked \n      ${PROJECT_BINARY_DIR}/test_for_libjpeg_build  \n      ${CMAKE_CURRENT_LIST_DIR}/test_for_libjpeg\n      test_if_libjpeg_is_broken\n      CMAKE_FLAGS \"${JPEG_TEST_CMAKE_FLAGS}\")\n\n   message (STATUS \"Found system copy of libjpeg: ${JPEG_LIBRARY}\")\n   if(NOT test_for_libjpeg_worked)\n      set(JPEG_FOUND 0)\n      message (STATUS \"System copy of libjpeg is broken or too old.  Will build our own libjpeg and use that instead.\")\n   endif()\nendif()\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/find_libjxl.cmake",
    "content": "#=============================================================================\n# Find JPEG XL library\n#=============================================================================\n# Find the native JPEG XL headers and libraries.\n#\n#  JXL_INCLUDE_DIRS - where to find jxl/decode_cxx.h, etc.\n#  JXL_LIBRARIES    - List of libraries when using jxl.\n#  JXL_FOUND        - True if jxl is found.\n#=============================================================================\n\n# Look for the header file.\n\nmessage(STATUS \"Searching for JPEG XL\")\nfind_package(PkgConfig)\nif (PkgConfig_FOUND)\n    pkg_check_modules(JXL IMPORTED_TARGET libjxl libjxl_cms libjxl_threads)\n    if (JXL_FOUND)\n        message(STATUS \"Found libjxl via pkg-config in `${JXL_LIBRARY_DIRS}`\")\n    else()\n        message(\" *****************************************************************************\")\n        message(\" *** No JPEG XL libraries found.                                           ***\")\n        message(\" *** On Ubuntu 23.04 and newer you can install them by executing           ***\")\n        message(\" ***    sudo apt install libjxl-dev                                        ***\")\n        message(\" ***                                                                       ***\")\n        message(\" *** Otherwise, you can find precompiled packages here:                    ***\")\n        message(\" ***    https://github.com/libjxl/libjxl/releases                          ***\")\n        message(\" *****************************************************************************\")\n    endif()\nelse()\n    message(STATUS \"PkgConfig could not be found, JPEG XL support won't be available\")\n    set(JXL_FOUND 0)\nendif()\n\nif(JXL_FOUND)\n    set(JXL_TEST_CMAKE_FLAGS\n      \"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}\"\n      \"-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}\"\n      \"-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}\")\n\n    try_compile(test_for_libjxl_worked\n        ${PROJECT_BINARY_DIR}/test_for_libjxl_build\n        ${CMAKE_CURRENT_LIST_DIR}/test_for_libjxl\n        test_if_libjxl_is_broken\n        CMAKE_FLAGS \"${JXL_TEST_CMAKE_FLAGS}\")\n\n    if(NOT test_for_libjxl_worked)\n        set(JXL_FOUND 0)\n        message (STATUS \"System copy of libjxl is either too old or broken.  Will disable JPEG XL support.\")\n    endif()\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/find_libpng.cmake",
    "content": "#This script just runs CMake's built in PNG finding tool.  But it also checks that the\n#copy of libpng that cmake finds actually builds and links.\n\ncmake_minimum_required(VERSION 3.10.0)\n\nif (BUILDING_PYTHON_IN_MSVC)\n   # Never use any system copy of libpng when building python in visual studio\n   set(PNG_FOUND 0)\n   return()\nendif()\n\n# Don't rerun this script if its already been executed.\nif (DEFINED PNG_FOUND)\n   return()\nendif()\n\nfind_package(PNG QUIET)\n\nif(PNG_FOUND)\n   set(PNG_TEST_CMAKE_FLAGS \n      \"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}\"\n      \"-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}\"\n      \"-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}\")\n\n   try_compile(test_for_libpng_worked \n      ${PROJECT_BINARY_DIR}/test_for_libpng_build  \n      ${CMAKE_CURRENT_LIST_DIR}/test_for_libpng\n      test_if_libpng_is_broken\n      CMAKE_FLAGS \"${PNG_TEST_CMAKE_FLAGS}\")\n\n   message (STATUS \"Found system copy of libpng: ${PNG_LIBRARIES}\")\n   if(NOT test_for_libpng_worked)\n      set(PNG_FOUND 0)\n      message (STATUS \"System copy of libpng is broken.  Will build our own libpng and use that instead.\")\n   endif()\nendif()\n\n"
  },
  {
    "path": "dlib/cmake_utils/find_libwebp.cmake",
    "content": "#=============================================================================\n# Find WebP library\n# From OpenCV\n#=============================================================================\n# Find the native WebP headers and libraries.\n#\n#  WEBP_INCLUDE_DIRS - where to find webp/decode.h, etc.\n#  WEBP_LIBRARIES    - List of libraries when using webp.\n#  WEBP_FOUND        - True if webp is found.\n#=============================================================================\n\n# Look for the header file.\n\nunset(WEBP_FOUND)\n\nfind_path(WEBP_INCLUDE_DIR NAMES webp/decode.h)\n\nif(NOT WEBP_INCLUDE_DIR)\n    unset(WEBP_FOUND)\nelse()\n    mark_as_advanced(WEBP_INCLUDE_DIR)\n\n    # Look for the library.\n    find_library(WEBP_LIBRARY NAMES webp)\n    mark_as_advanced(WEBP_LIBRARY)\n\n    # handle the QUIETLY and REQUIRED arguments and set WEBP_FOUND to TRUE if\n    # all listed variables are TRUE\n    include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)\n    find_package_handle_standard_args(WebP DEFAULT_MSG WEBP_LIBRARY WEBP_INCLUDE_DIR)\n\n    set(WEBP_LIBRARIES ${WEBP_LIBRARY})\n    set(WEBP_INCLUDE_DIRS ${WEBP_INCLUDE_DIR})\nendif()\n\nif(WEBP_FOUND)\n    set(WEBP_TEST_CMAKE_FLAGS\n      \"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}\"\n      \"-DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}\"\n      \"-DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}\")\n\n    try_compile(test_for_libwebp_worked\n        ${PROJECT_BINARY_DIR}/test_for_libwebp_build\n        ${CMAKE_CURRENT_LIST_DIR}/test_for_libwebp\n        test_if_libwebp_is_broken\n        CMAKE_FLAGS \"${WEBP_TEST_CMAKE_FLAGS}\")\n\n    if(NOT test_for_libwebp_worked)\n        set(WEBP_FOUND 0)\n        message (STATUS \"System copy of libwebp is either too old or broken.  Will disable WebP support.\")\n    endif()\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/release_build_by_default",
    "content": "\n#set default build type to Release\nif(NOT CMAKE_BUILD_TYPE)\n   set(CMAKE_BUILD_TYPE \"Release\" CACHE STRING\n      \"Choose the type of build, options are: Debug Release\n      RelWithDebInfo MinSizeRel.\" FORCE)\nendif()\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/set_compiler_specific_options.cmake",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\n\n\n# Check if we are being built as part of a pybind11 module. \nif (COMMAND pybind11_add_module)\n   # For python users, enable SSE4 and AVX if they have these instructions.\n   include(${CMAKE_CURRENT_LIST_DIR}/check_if_sse4_instructions_executable_on_host.cmake)\n   if (SSE4_IS_AVAILABLE_ON_HOST)\n      set(USE_SSE4_INSTRUCTIONS ON CACHE BOOL \"Compile your program with SSE4 instructions\")\n   endif()\n   include(${CMAKE_CURRENT_LIST_DIR}/check_if_avx_instructions_executable_on_host.cmake)\n   if (AVX_IS_AVAILABLE_ON_HOST)\n      set(USE_AVX_INSTRUCTIONS ON CACHE BOOL \"Compile your program with AVX instructions\")\n   endif()\n   include(${CMAKE_CURRENT_LIST_DIR}/check_if_neon_available.cmake)\n   if (ARM_NEON_IS_AVAILABLE)\n      set(USE_NEON_INSTRUCTIONS ON CACHE BOOL \"Compile your program with ARM-NEON instructions\")\n   endif()\nendif()\n\n\n\n\nset(gcc_like_compilers GNU Clang  Intel)\nset(intel_archs x86_64 i386 i686 AMD64 amd64 x86)\n\n\n# Setup some options to allow a user to enable SSE and AVX instruction use.  \nif ((\";${gcc_like_compilers};\" MATCHES \";${CMAKE_CXX_COMPILER_ID};\")  AND\n   (\";${intel_archs};\"        MATCHES \";${CMAKE_SYSTEM_PROCESSOR};\") AND NOT USE_AUTO_VECTOR)\n   option(USE_SSE2_INSTRUCTIONS \"Compile your program with SSE2 instructions\" OFF)\n   option(USE_SSE4_INSTRUCTIONS \"Compile your program with SSE4 instructions\" OFF)\n   option(USE_AVX_INSTRUCTIONS  \"Compile your program with AVX instructions\"  OFF)\n   if(USE_AVX_INSTRUCTIONS)\n      list(APPEND active_compile_opts -mavx)\n      message(STATUS \"Enabling AVX instructions\")\n   elseif (USE_SSE4_INSTRUCTIONS)\n      list(APPEND active_compile_opts -msse4)\n      message(STATUS \"Enabling SSE4 instructions\")\n   elseif(USE_SSE2_INSTRUCTIONS)\n      list(APPEND active_compile_opts -msse2)\n      message(STATUS \"Enabling SSE2 instructions\")\n   endif()\nelseif (MSVC OR \"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\") # else if using Visual Studio \n   # Use SSE2 by default when using Visual Studio.\n   option(USE_SSE2_INSTRUCTIONS \"Compile your program with SSE2 instructions\" ON)\n   option(USE_SSE4_INSTRUCTIONS \"Compile your program with SSE4 instructions\" OFF)\n   option(USE_AVX_INSTRUCTIONS  \"Compile your program with AVX instructions\"  OFF)\n\n   include(CheckTypeSize)\n   check_type_size( \"void*\" SIZE_OF_VOID_PTR)\n   if(USE_AVX_INSTRUCTIONS)\n      list(APPEND active_compile_opts /arch:AVX)\n      message(STATUS \"Enabling AVX instructions\")\n   elseif (USE_SSE4_INSTRUCTIONS)\n      # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes.\n      # So only give it when we are doing a 32 bit build.\n      if (SIZE_OF_VOID_PTR EQUAL 4)\n         list(APPEND active_compile_opts /arch:SSE2)\n      endif()\n      message(STATUS \"Enabling SSE4 instructions\")\n      list(APPEND active_preprocessor_switches \"-DDLIB_HAVE_SSE2\")\n      list(APPEND active_preprocessor_switches \"-DDLIB_HAVE_SSE3\")\n      list(APPEND active_preprocessor_switches \"-DDLIB_HAVE_SSE41\")\n   elseif(USE_SSE2_INSTRUCTIONS)\n      # Visual studio doesn't have an /arch:SSE2 flag when building in 64 bit modes.\n      # So only give it when we are doing a 32 bit build.\n      if (SIZE_OF_VOID_PTR EQUAL 4)\n         list(APPEND active_compile_opts /arch:SSE2)\n      endif()\n      message(STATUS \"Enabling SSE2 instructions\")\n      list(APPEND active_preprocessor_switches \"-DDLIB_HAVE_SSE2\")\n   endif()\n\nelseif((\";${gcc_like_compilers};\" MATCHES \";${CMAKE_CXX_COMPILER_ID};\")  AND\n        (\"${CMAKE_SYSTEM_PROCESSOR}\" MATCHES \"^arm\"))\n   option(USE_NEON_INSTRUCTIONS \"Compile your program with ARM-NEON instructions\" OFF)\n   if(USE_NEON_INSTRUCTIONS)\n      list(APPEND active_compile_opts -mfpu=neon)\n      message(STATUS \"Enabling ARM-NEON instructions\")\n   endif()\nendif()\n\n\n\n\nif (CMAKE_COMPILER_IS_GNUCXX)\n   # By default, g++ won't warn or error if you forget to return a value in a\n   # function which requires you to do so.  This option makes it give a warning\n   # for doing this.\n   list(APPEND active_compile_opts \"-Wreturn-type\")\nendif()\n\nif (\"Clang\" MATCHES ${CMAKE_CXX_COMPILER_ID} AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0.0)\n   # Clang 6 had a default template recursion depth of 256. This was changed to 1024 in Clang 7.\n   # It must be increased on Clang 6 and below to ensure that the dnn examples don't error out.\n   list(APPEND active_compile_opts \"-ftemplate-depth=500\")\nendif()\n\nif (MSVC)\n   # By default Visual Studio does not support .obj files with more than 65k sections.\n   # However, code generated by file_to_code_ex and code using DNN module can have\n   # them.  So this flag enables > 65k sections, but produces .obj files\n   # that will not be readable by VS 2005.\n   list(APPEND active_compile_opts \"/bigobj\")\n\n   # Build dlib with all cores.  Don't propagate the setting to client programs\n   # though since they might compile large translation units that use too much\n   # RAM.\n   list(APPEND active_compile_opts_private \"/MP\")\n\n   if(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.3) \n      # Clang can compile all Dlib's code at Windows platform. Tested with Clang 5\n      list(APPEND active_compile_opts -Xclang)\n      list(APPEND active_compile_opts -fcxx-exceptions)\n   endif()\nendif()\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/tell_visual_studio_to_use_static_runtime.cmake",
    "content": "\n# Including this cmake script into your cmake project will cause visual studio\n# to build your project against the static C runtime.\n\ncmake_minimum_required(VERSION 3.10.0)\n\nif (MSVC OR \"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\")\n   option (DLIB_FORCE_MSVC_STATIC_RUNTIME \"use static runtime\" ON)\n   if (DLIB_FORCE_MSVC_STATIC_RUNTIME)\n      foreach(flag_var\n         CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE\n         CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)\n         if(${flag_var} MATCHES \"/MD\")\n            string(REGEX REPLACE \"/MD\" \"/MT\" ${flag_var} \"${${flag_var}}\")\n         endif()\n      endforeach(flag_var)\n   endif ()\nendif()\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_avx/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(avx_test)\n\nset(USE_AVX_INSTRUCTIONS ON CACHE BOOL \"Use AVX instructions\")\n\n# Pull this in since it sets the AVX compile options by putting that kind of stuff into the active_compile_opts list.\ninclude(../set_compiler_specific_options.cmake)\n\n\ntry_run(run_result compile_result ${PROJECT_BINARY_DIR}/avx_test_try_run_build ${CMAKE_CURRENT_LIST_DIR}/avx_test.cpp\n   COMPILE_DEFINITIONS ${active_compile_opts})\n\nmessage(STATUS \"run_result = ${run_result}\")\nmessage(STATUS \"compile_result = ${compile_result}\")\n\nif (\"${run_result}\" EQUAL 0 AND compile_result)\n   message(STATUS \"Ran AVX test program successfully, you have AVX available.\")\nelse()\n   message(STATUS \"Unable to run AVX test program, you don't seem to have AVX instructions available.\")\n   # make this build fail so that calling try_compile statements will error in this case.\n   add_library(make_this_build_fail ${CMAKE_CURRENT_LIST_DIR}/this_file_doesnt_compile.cpp)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_avx/avx_test.cpp",
    "content": "\n#include <immintrin.h> \n\nint main()\n{\n    __m256 x;\n    x = _mm256_set1_ps(1.23);\n    x = _mm256_add_ps(x,x);\n    return 0;\n}\n\n// ------------------------------------------------------------------------------------\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_avx/this_file_doesnt_compile.cpp",
    "content": "\n#error \"This file doesn't compile!\"\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libjpeg/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(test_if_libjpeg_is_broken)\n\nfind_package(JPEG)\n\ninclude_directories(${JPEG_INCLUDE_DIR})\nadd_executable(libjpeg_test libjpeg_test.cpp)\ntarget_link_libraries(libjpeg_test ${JPEG_LIBRARY})\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libjpeg/libjpeg_test.cpp",
    "content": "// Copyright (C) 2019  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#include <setjmp.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <jpeglib.h>\n#include <iostream>\n\nstruct jpeg_loader_error_mgr \n{\n    jpeg_error_mgr pub;    \n    jmp_buf setjmp_buffer;  \n};\n\nvoid jpeg_loader_error_exit (j_common_ptr cinfo)\n{\n    jpeg_loader_error_mgr* myerr = (jpeg_loader_error_mgr*) cinfo->err;\n\n    longjmp(myerr->setjmp_buffer, 1);\n}\n\n// This code doesn't really make a lot of sense.  It's just calling all the libjpeg functions to make\n// sure they can be compiled and linked.  \nint main() \n{\n    std::cerr << \"This program is just for build system testing.  Don't actually run it.\" << std::endl;\n    abort();\n\n    FILE *fp = fopen(\"whatever.jpg\", \"rb\" );\n\n    jpeg_decompress_struct cinfo;\n    jpeg_loader_error_mgr jerr;\n\n    cinfo.err = jpeg_std_error(&jerr.pub);\n\n    jerr.pub.error_exit = jpeg_loader_error_exit;\n\n    setjmp(jerr.setjmp_buffer);\n\n    jpeg_create_decompress(&cinfo);\n\n    jpeg_stdio_src(&cinfo, fp);\n    if (false) {\n        unsigned char imgbuffer[1234];\n        jpeg_mem_src(&cinfo, imgbuffer, sizeof(imgbuffer));\n    }\n\n    jpeg_read_header(&cinfo, TRUE);\n\n    jpeg_start_decompress(&cinfo);\n\n    unsigned long height_ = cinfo.output_height;\n    unsigned long width_ = cinfo.output_width;\n    unsigned long output_components_ = cinfo.output_components;\n\n    unsigned char* rows[123];\n\n    while (cinfo.output_scanline < cinfo.output_height)\n    {\n        jpeg_read_scanlines(&cinfo, &rows[cinfo.output_scanline], 100);\n    }\n\n    jpeg_finish_decompress(&cinfo);\n    jpeg_destroy_decompress(&cinfo);\n\n    fclose( fp );\n}\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libjxl/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(test_if_libjxl_is_broken)\n\ninclude_directories(${JXL_INCLUDE_DIR})\nadd_executable(libjxl_test libjxl_test.cpp)\ntarget_link_libraries(libjxl_test ${JXL_LIBRARY})\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libjxl/libjxl_test.cpp",
    "content": "// Copyright (C) 2023 Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#include <jxl/encode_cxx.h>\n#include <jxl/decode_cxx.h>\n#include <jxl/resizable_parallel_runner_cxx.h>\n#include <iostream>\n#include <memory>\n\n// This code doesn't really make a lot of sense.  It's just calling all the libjpeg functions to make\n// sure they can be compiled and linked.\n\nint main()\n{\n    std::cerr << \"This program is just for build system testing.  Don't actually run it.\" << std::endl;\n    std::abort();\n    auto enc = JxlEncoderMake(nullptr);\n    auto dec = JxlDecoderMake(nullptr);\n    auto runner = JxlResizableParallelRunnerMake(nullptr);\n}\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libpng/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(test_if_libpng_is_broken)\n\nfind_package(PNG)\n\ninclude_directories(${PNG_INCLUDE_DIR})\nadd_executable(libpng_test libpng_test.cpp)\ntarget_link_libraries(libpng_test ${PNG_LIBRARIES})\n\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libpng/libpng_test.cpp",
    "content": "// Copyright (C) 2019  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#include <png.h>\n#include <setjmp.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <iostream>\n\nvoid png_loader_user_error_fn_silent(png_structp  png_struct, png_const_charp ) \n{\n    longjmp(png_jmpbuf(png_struct),1);\n}\nvoid png_loader_user_warning_fn_silent(png_structp , png_const_charp ) \n{\n}\n\n// This code doesn't really make a lot of sense.  It's just calling all the libpng functions to make\n// sure they can be compiled and linked.  \nint main() \n{\n    std::cerr << \"This program is just for build system testing.  Don't actually run it.\" << std::endl;\n    abort();\n\n    png_bytep* row_pointers_;\n    png_structp png_ptr_;\n    png_infop info_ptr_;\n    png_infop end_info_;\n\n    FILE *fp = fopen( \"whatever.png\", \"rb\" );\n    png_byte sig[8];\n    fread( sig, 1, 8, fp );\n    png_sig_cmp( sig, 0, 8 );\n    png_ptr_ = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent );\n\n    png_get_header_ver(NULL);\n    info_ptr_ = png_create_info_struct( png_ptr_ );\n    end_info_ = png_create_info_struct( png_ptr_ );\n    setjmp(png_jmpbuf(png_ptr_));\n    png_set_palette_to_rgb(png_ptr_);\n    png_init_io( png_ptr_, fp );\n    png_set_sig_bytes( png_ptr_, 8 );\n    // flags force one byte per channel output\n    int png_transforms = PNG_TRANSFORM_PACKING;\n    png_read_png( png_ptr_, info_ptr_, png_transforms, NULL );\n    png_get_image_height( png_ptr_, info_ptr_ );\n    png_get_image_width( png_ptr_, info_ptr_ );\n    png_get_bit_depth( png_ptr_, info_ptr_ );\n    png_get_color_type( png_ptr_,  info_ptr_ );\n\n    png_get_rows( png_ptr_, info_ptr_ );\n\n    fclose(fp);\n    png_destroy_read_struct(&png_ptr_, &info_ptr_, &end_info_);\n}\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libwebp/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(test_if_libwebp_is_broken)\n\ninclude_directories(${WEBP_INCLUDE_DIR})\nadd_executable(libwebp_test libwebp_test.cpp)\ntarget_link_libraries(libwebp_test ${WEBP_LIBRARY})\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_libwebp/libwebp_test.cpp",
    "content": "// Copyright (C) 2019  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#include <webp/encode.h>\n#include <webp/decode.h>\n#include <iostream>\n\n// This code doesn't really make a lot of sense.  It's just calling all the libjpeg functions to make\n// sure they can be compiled and linked.\nint main()\n{\n    std::cerr << \"This program is just for build system testing.  Don't actually run it.\" << std::endl;\n    std::abort();\n\n    uint8_t* data;\n    size_t output_size = 0;\n    int width, height, stride;\n    float quality;\n    output_size = WebPEncodeRGB(data, width, height, stride, quality, &data);\n    WebPDecodeRGBInto(data, output_size, data, output_size, stride);\n    WebPFree(data);\n}\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_neon/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(neon_test)\n\nadd_library(neon_test STATIC neon_test.cpp )\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_neon/neon_test.cpp",
    "content": "#ifdef __ARM_NEON__\n#else\n#error \"No NEON\"\n#endif\nint main(){}\n\n\n// ------------------------------------------------------------------------------------\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_sse4/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject(sse4_test)\n\nset(USE_SSE4_INSTRUCTIONS ON CACHE BOOL \"Use SSE4 instructions\")\n\n# Pull this in since it sets the SSE4 compile options by putting that kind of stuff into the active_compile_opts list.\ninclude(../set_compiler_specific_options.cmake)\n\n\ntry_run(run_result compile_result ${PROJECT_BINARY_DIR}/sse4_test_try_run_build ${CMAKE_CURRENT_LIST_DIR}/sse4_test.cpp\n   COMPILE_DEFINITIONS ${active_compile_opts})\n\nmessage(STATUS \"run_result = ${run_result}\")\nmessage(STATUS \"compile_result = ${compile_result}\")\n\nif (\"${run_result}\" EQUAL 0 AND compile_result)\n   message(STATUS \"Ran SSE4 test program successfully, you have SSE4 available.\")\nelse()\n   message(STATUS \"Unable to run SSE4 test program, you don't seem to have SSE4 instructions available.\")\n   # make this build fail so that calling try_compile statements will error in this case.\n   add_library(make_this_build_fail ${CMAKE_CURRENT_LIST_DIR}/this_file_doesnt_compile.cpp)\nendif()\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_sse4/sse4_test.cpp",
    "content": "\n#include <xmmintrin.h>\n#include <emmintrin.h>\n#include <mmintrin.h>\n#include <pmmintrin.h> // SSE3\n#include <tmmintrin.h>\n#include <smmintrin.h> // SSE4\n\nint main()\n{\n    __m128 x;\n    x = _mm_set1_ps(1.23);\n    x = _mm_ceil_ps(x);\n    return 0;\n}\n\n// ------------------------------------------------------------------------------------\n\n"
  },
  {
    "path": "dlib/cmake_utils/test_for_sse4/this_file_doesnt_compile.cpp",
    "content": "\n#error \"This file doesn't compile!\"\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_check_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_CHECk_1_\n#define DLIB_CMD_LINE_PARSER_CHECk_1_ \n\n#include \"cmd_line_parser_kernel_abstract.h\"\n#include <sstream>\n#include <string>\n#include \"../string.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n    template <\n        typename clp_base\n        >\n    class cmd_line_parser_check_1 : public clp_base\n    {\n\n        /*!\n            This extension doesn't add any state.\n\n        !*/\n\n\n    public:\n        typedef typename clp_base::char_type char_type;\n        typedef typename clp_base::string_type string_type;\n\n    // ------------------------------------------------------------------------------------\n\n        class cmd_line_check_error : public dlib::error \n        {\n            friend class cmd_line_parser_check_1;\n\n            cmd_line_check_error(\n                error_type t,\n                const string_type& opt_,\n                const string_type& arg_ \n            ) :\n                dlib::error(t),\n                opt(opt_),\n                opt2(),\n                arg(arg_),\n                required_opts()\n            { set_info_string(); }\n\n            cmd_line_check_error(\n                error_type t,\n                const string_type& opt_,\n                const string_type& opt2_,\n                int  // this is just to make this constructor different from the one above\n            ) :\n                dlib::error(t),\n                opt(opt_),\n                opt2(opt2_),\n                arg(),\n                required_opts()\n            { set_info_string(); }\n\n            cmd_line_check_error (\n                error_type t,\n                const string_type& opt_,\n                const std::vector<string_type>& vect\n            ) :\n                dlib::error(t),\n                opt(opt_),\n                opt2(),\n                arg(),\n                required_opts(vect)\n            { set_info_string(); }\n\n            cmd_line_check_error(\n                error_type t,\n                const string_type& opt_\n            ) :\n                dlib::error(t),\n                opt(opt_),\n                opt2(),\n                arg(),\n                required_opts()\n            { set_info_string(); }\n\n            ~cmd_line_check_error() noexcept {}\n\n            void set_info_string (\n            )\n            {\n                std::ostringstream sout;\n                switch (type)\n                {\n                    case EINVALID_OPTION_ARG:\n                        sout << \"Command line error: '\" << narrow(arg) << \"' is not a valid argument to \" \n                             << \"the '\" << narrow(opt) << \"' option.\";\n                        break;\n                    case EMISSING_REQUIRED_OPTION:\n                        if (required_opts.size() == 1)\n                        {\n                            sout << \"Command line error: The '\" << narrow(opt) << \"' option requires the presence of \"\n                                 << \"the '\" << required_opts[0] << \"' option.\";\n                        }\n                        else\n                        {\n                            sout << \"Command line error: The '\" << narrow(opt) << \"' option requires the presence of \"\n                                 << \"one of the following options: \";\n                            for (unsigned long i = 0; i < required_opts.size(); ++i)\n                            {\n                                if (i == required_opts.size()-2)\n                                    sout << \"'\" << required_opts[i] << \"' or \";\n                                else if (i == required_opts.size()-1)\n                                    sout << \"'\" << required_opts[i] << \"'.\";\n                                else\n                                    sout << \"'\" << required_opts[i] << \"', \";\n                            }\n                        }\n                        break;\n                    case EINCOMPATIBLE_OPTIONS:\n                        sout << \"Command line error: The '\" << narrow(opt) << \"' and '\" << narrow(opt2) \n                            << \"' options cannot be given together on the command line.\";\n                        break;\n                    case EMULTIPLE_OCCURANCES:\n                        sout << \"Command line error: The '\" << narrow(opt) << \"' option can only \"\n                             << \"be given on the command line once.\";\n                        break;\n                    default:\n                        sout << \"Command line error.\";\n                        break;\n                }\n                const_cast<std::string&>(info) = wrap_string(sout.str(),0,0);\n            }\n\n        public:\n            const string_type opt;\n            const string_type opt2;\n            const string_type arg; \n            const std::vector<string_type> required_opts; \n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        void check_option_arg_type (\n            const string_type& option_name\n        ) const;\n\n        template <\n            typename T\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T& first,\n            const T& last\n        ) const;\n\n        template <\n            typename T,\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T (&arg_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const char_type* (&arg_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_incompatible_options (\n            const char_type* (&option_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_one_time_options (\n            const char_type* (&option_set)[length]\n        ) const;\n\n        void check_incompatible_options (\n            const string_type& option_name1,\n            const string_type& option_name2\n        ) const;\n\n        void check_sub_option (\n            const string_type& parent_option,\n            const string_type& sub_option\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const string_type& parent_option,\n            const char_type* (&sub_option_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[length],\n            const string_type& sub_option\n        ) const;\n\n        template <\n            size_t parent_length,\n            size_t sub_length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[parent_length],\n            const char_type* (&sub_option_set)[sub_length]\n        ) const;\n    };\n\n    template <\n        typename clp_base\n        >\n    inline void swap (\n        cmd_line_parser_check_1<clp_base>& a, \n        cmd_line_parser_check_1<clp_base>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template <typename T>\n    void cmd_line_parser_check_1<clp_base>::\n    check_option_arg_type (\n        const string_type& option_name\n    ) const\n    {\n        try\n        {\n            const typename clp_base::option_type& opt = this->option(option_name);\n            const unsigned long number_of_arguments = opt.number_of_arguments();\n            const unsigned long count = opt.count();\n            for (unsigned long i = 0; i < number_of_arguments; ++i)\n            {\n                for (unsigned long j = 0; j < count; ++j)\n                {\n                    string_cast<T>(opt.argument(i,j));\n                }\n            }\n        }\n        catch (string_cast_error& e)\n        {\n            throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template <typename T>\n    void cmd_line_parser_check_1<clp_base>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const T& first,\n        const T& last\n    ) const\n    {\n        try\n        {\n            const typename clp_base::option_type& opt = this->option(option_name);\n            const unsigned long number_of_arguments = opt.number_of_arguments();\n            const unsigned long count = opt.count();\n            for (unsigned long i = 0; i < number_of_arguments; ++i)\n            {\n                for (unsigned long j = 0; j < count; ++j)\n                {\n                    T temp(string_cast<T>(opt.argument(i,j)));\n                    if (temp < first || last < temp)\n                    {\n                        throw cmd_line_check_error(\n                            EINVALID_OPTION_ARG,\n                            option_name,\n                            opt.argument(i,j)\n                        );\n                    }\n                }\n            }\n        }\n        catch (string_cast_error& e)\n        {\n            throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base> \n    template < typename T, size_t length >\n    void cmd_line_parser_check_1<clp_base>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const T (&arg_set)[length]\n    ) const\n    {\n        try\n        {\n            const typename clp_base::option_type& opt = this->option(option_name);\n            const unsigned long number_of_arguments = opt.number_of_arguments();\n            const unsigned long count = opt.count();\n            for (unsigned long i = 0; i < number_of_arguments; ++i)\n            {\n                for (unsigned long j = 0; j < count; ++j)\n                {\n                    T temp(string_cast<T>(opt.argument(i,j)));\n                    size_t k = 0;\n                    for (; k < length; ++k)\n                    {\n                        if (arg_set[k] == temp)\n                            break;\n                    }\n                    if (k == length)\n                    {\n                        throw cmd_line_check_error(\n                            EINVALID_OPTION_ARG,\n                            option_name,\n                            opt.argument(i,j)\n                        );\n                    }\n                }\n            }\n        }\n        catch (string_cast_error& e)\n        {\n            throw cmd_line_check_error(EINVALID_OPTION_ARG,option_name,e.info);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t length >\n    void cmd_line_parser_check_1<clp_base>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const char_type* (&arg_set)[length]\n    ) const\n    {\n        const typename clp_base::option_type& opt = this->option(option_name);\n        const unsigned long number_of_arguments = opt.number_of_arguments();\n        const unsigned long count = opt.count();\n        for (unsigned long i = 0; i < number_of_arguments; ++i)\n        {\n            for (unsigned long j = 0; j < count; ++j)\n            {\n                size_t k = 0;\n                for (; k < length; ++k)\n                {\n                    if (arg_set[k] == opt.argument(i,j))\n                        break;\n                }\n                if (k == length)\n                {\n                    throw cmd_line_check_error(\n                        EINVALID_OPTION_ARG,\n                        option_name,\n                        opt.argument(i,j)\n                    );\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t length >\n    void cmd_line_parser_check_1<clp_base>::\n    check_incompatible_options (\n        const char_type* (&option_set)[length]\n    ) const\n    {\n        for (size_t i = 0; i < length; ++i)\n        {\n            for (size_t j = i+1; j < length; ++j)\n            {\n                if (this->option(option_set[i]).count() > 0 &&\n                    this->option(option_set[j]).count() > 0 )\n                {\n                    throw cmd_line_check_error(\n                        EINCOMPATIBLE_OPTIONS,\n                        option_set[i],\n                        option_set[j],\n                        0 // this argument has no meaning and is only here to make this\n                        // call different from the other constructor\n                    );\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    void cmd_line_parser_check_1<clp_base>::\n    check_incompatible_options (\n        const string_type& option_name1,\n        const string_type& option_name2\n    ) const\n    {\n        if (this->option(option_name1).count() > 0 &&\n            this->option(option_name2).count() > 0 )\n        {\n            throw cmd_line_check_error(\n                EINCOMPATIBLE_OPTIONS,\n                option_name1,\n                option_name2,\n                0 // this argument has no meaning and is only here to make this\n                // call different from the other constructor\n            );\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    void cmd_line_parser_check_1<clp_base>::\n    check_sub_option (\n        const string_type& parent_option,\n        const string_type& sub_option\n    ) const\n    {\n        if (this->option(parent_option).count() == 0)\n        {\n            if (this->option(sub_option).count() != 0)\n            {\n                std::vector<string_type> vect;\n                vect.resize(1);\n                vect[0] = parent_option;\n                throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t length >\n    void cmd_line_parser_check_1<clp_base>::\n    check_sub_options (\n        const string_type& parent_option,\n        const char_type* (&sub_option_set)[length]\n    ) const\n    {\n        if (this->option(parent_option).count() == 0)\n        {\n            size_t i = 0;\n            for (; i < length; ++i)\n            {\n                if (this->option(sub_option_set[i]).count() > 0)\n                    break;\n            }\n            if (i != length)\n            {\n                std::vector<string_type> vect;\n                vect.resize(1);\n                vect[0] = parent_option;\n                throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t length > \n    void cmd_line_parser_check_1<clp_base>::\n    check_sub_options (\n        const char_type* (&parent_option_set)[length],\n        const string_type& sub_option\n    ) const\n    {\n        // first check if the sub_option is present\n        if (this->option(sub_option).count() > 0)\n        {\n            // now check if any of the parents are present\n            bool parents_present = false;\n            for (size_t i = 0; i < length; ++i)\n            {\n                if (this->option(parent_option_set[i]).count() > 0)\n                {\n                    parents_present = true;\n                    break;\n                }\n            }\n\n            if (!parents_present)\n            {\n                std::vector<string_type> vect(parent_option_set, parent_option_set+length);\n                throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option, vect);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t parent_length, size_t sub_length > \n    void cmd_line_parser_check_1<clp_base>::\n    check_sub_options (\n        const char_type* (&parent_option_set)[parent_length],\n        const char_type* (&sub_option_set)[sub_length]\n    ) const\n    {\n        // first check if any of the parent options are present\n        bool parents_present = false;\n        for (size_t i = 0; i < parent_length; ++i)\n        {\n            if (this->option(parent_option_set[i]).count() > 0)\n            {\n                parents_present = true;\n                break;\n            }\n        }\n\n        if (!parents_present)\n        {\n            // none of these sub options should be present\n            size_t i = 0;\n            for (; i < sub_length; ++i)\n            {\n                if (this->option(sub_option_set[i]).count() > 0)\n                    break;\n            }\n            if (i != sub_length)\n            {\n                std::vector<string_type> vect(parent_option_set, parent_option_set+parent_length);\n                throw cmd_line_check_error( EMISSING_REQUIRED_OPTION, sub_option_set[i], vect);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_base>\n    template < size_t length >\n    void cmd_line_parser_check_1<clp_base>::\n    check_one_time_options (\n        const char_type* (&option_set)[length]\n    ) const\n    {\n        size_t i = 0;\n        for (; i < length; ++i)\n        {\n            if (this->option(option_set[i]).count() > 1)\n                break;\n        }\n        if (i != length)\n        {\n            throw cmd_line_check_error(\n                EMULTIPLE_OCCURANCES,\n                option_set[i] \n            );\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_CHECk_1_ \n\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_check_c.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_CHECk_C_\n#define DLIB_CMD_LINE_PARSER_CHECk_C_\n\n#include \"cmd_line_parser_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <string>\n#include \"../interfaces/cmd_line_parser_option.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename clp_check\n        >\n    class cmd_line_parser_check_c : public clp_check\n    {\n        public:\n\n        typedef typename clp_check::char_type char_type;\n        typedef typename clp_check::string_type string_type;\n\n        template <\n            typename T\n            >\n        void check_option_arg_type (\n            const string_type& option_name\n        ) const;\n\n        template <\n            typename T\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T& first,\n            const T& last\n        ) const;\n\n        template <\n            typename T,\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T (&arg_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const char_type* (&arg_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_incompatible_options (\n            const char_type* (&option_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_one_time_options (\n            const char_type* (&option_set)[length]\n        ) const;\n\n        void check_incompatible_options (\n            const string_type& option_name1,\n            const string_type& option_name2\n        ) const;\n\n        void check_sub_option (\n            const string_type& parent_option,\n            const string_type& sub_option\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const string_type& parent_option,\n            const char_type* (&sub_option_set)[length]\n        ) const;\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[length],\n            const string_type& sub_option\n        ) const;\n\n        template <\n            size_t parent_length,\n            size_t sub_length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[parent_length],\n            const char_type* (&sub_option_set)[sub_length]\n        ) const;\n    };\n\n\n    template <\n        typename clp_check\n        >\n    inline void swap (\n        cmd_line_parser_check_c<clp_check>& a, \n        cmd_line_parser_check_c<clp_check>& b \n    ) { a.swap(b); } \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template <typename T>\n    void cmd_line_parser_check_c<clp_check>::\n    check_option_arg_type (\n        const string_type& option_name\n    ) const\n    {\n        COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name),\n               \"\\tvoid cmd_line_parser_check::check_option_arg_type()\"\n            << \"\\n\\tYou must have already parsed the command line and option_name must be valid.\"\n            << \"\\n\\tthis:                           \" << this\n            << \"\\n\\toption_is_defined(option_name): \" << ((this->option_is_defined(option_name))?\"true\":\"false\")\n            << \"\\n\\tparsed_line():                  \" << ((this->parsed_line())?\"true\":\"false\")\n            << \"\\n\\toption_name:                    \" << option_name \n            );\n\n        clp_check::template check_option_arg_type<T>(option_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template <typename T>\n    void cmd_line_parser_check_c<clp_check>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const T& first,\n        const T& last\n    ) const\n    {\n        COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name) &&\n                 first <= last,\n               \"\\tvoid cmd_line_parser_check::check_option_arg_range()\"\n            << \"\\n\\tSee the requires clause for this function.\"\n            << \"\\n\\tthis:                           \" << this\n            << \"\\n\\toption_is_defined(option_name): \" << ((this->option_is_defined(option_name))?\"true\":\"false\")\n            << \"\\n\\tparsed_line():                  \" << ((this->parsed_line())?\"true\":\"false\")\n            << \"\\n\\toption_name:                    \" << option_name \n            << \"\\n\\tfirst:                          \" << first \n            << \"\\n\\tlast:                           \" << last \n            );\n\n        clp_check::check_option_arg_range(option_name,first,last);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check> \n    template < typename T, size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const T (&arg_set)[length]\n    ) const\n    {\n        COMPILE_TIME_ASSERT(is_pointer_type<T>::value == false);\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name), \n               \"\\tvoid cmd_line_parser_check::check_option_arg_range()\"\n            << \"\\n\\tSee the requires clause for this function.\"\n            << \"\\n\\tthis:                           \" << this\n            << \"\\n\\toption_is_defined(option_name): \" << ((this->option_is_defined(option_name))?\"true\":\"false\")\n            << \"\\n\\tparsed_line():                  \" << ((this->parsed_line())?\"true\":\"false\")\n            << \"\\n\\toption_name:                    \" << option_name \n            );\n\n        clp_check::check_option_arg_range(option_name,arg_set);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_option_arg_range (\n        const string_type& option_name,\n        const char_type* (&arg_set)[length]\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name), \n               \"\\tvoid cmd_line_parser_check::check_option_arg_range()\"\n            << \"\\n\\tSee the requires clause for this function.\"\n            << \"\\n\\tthis:                           \" << this\n            << \"\\n\\toption_is_defined(option_name): \" << ((this->option_is_defined(option_name))?\"true\":\"false\")\n            << \"\\n\\tparsed_line():                  \" << ((this->parsed_line())?\"true\":\"false\")\n            << \"\\n\\toption_name:                    \" << option_name \n            );\n\n        clp_check::check_option_arg_range(option_name,arg_set);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_incompatible_options (\n        const char_type* (&option_set)[length]\n    ) const\n    {\n        // make sure requires clause is not broken\n        for (size_t i = 0; i < length; ++i)\n        {\n            DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_incompatible_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                             \" << this\n                     << \"\\n\\toption_is_defined(option_set[i]): \" << ((this->option_is_defined(option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tparsed_line():                    \" << ((this->parsed_line())?\"true\":\"false\")\n                     << \"\\n\\toption_set[i]:                    \" << option_set[i] \n                     << \"\\n\\ti:                                \" << static_cast<unsigned long>(i) \n            );\n\n        }\n        clp_check::check_incompatible_options(option_set);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    void cmd_line_parser_check_c<clp_check>::\n    check_incompatible_options (\n        const string_type& option_name1,\n        const string_type& option_name2\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_name1) &&\n                 this->option_is_defined(option_name2), \n               \"\\tvoid cmd_line_parser_check::check_incompatible_options()\"\n            << \"\\n\\tSee the requires clause for this function.\"\n            << \"\\n\\tthis:                            \" << this\n            << \"\\n\\toption_is_defined(option_name1): \" << ((this->option_is_defined(option_name1))?\"true\":\"false\")\n            << \"\\n\\toption_is_defined(option_name2): \" << ((this->option_is_defined(option_name2))?\"true\":\"false\")\n            << \"\\n\\tparsed_line():                   \" << ((this->parsed_line())?\"true\":\"false\")\n            << \"\\n\\toption_name1:                    \" << option_name1 \n            << \"\\n\\toption_name2:                    \" << option_name2 \n            );\n\n        clp_check::check_incompatible_options(option_name1,option_name2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    void cmd_line_parser_check_c<clp_check>::\n    check_sub_option (\n        const string_type& parent_option,\n        const string_type& sub_option\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(parent_option) &&\n                      this->option_is_defined(sub_option), \n                 \"\\tvoid cmd_line_parser_check::check_sub_option()\"\n                 << \"\\n\\tSee the requires clause for this function.\"\n                 << \"\\n\\tthis:                             \" << this\n                 << \"\\n\\tparsed_line():                    \" << this->parsed_line()\n                 << \"\\n\\toption_is_defined(parent_option): \" << this->option_is_defined(parent_option)\n                 << \"\\n\\toption_is_defined(sub_option):    \" << this->option_is_defined(sub_option)\n                 << \"\\n\\tparent_option:                    \" << parent_option \n                 << \"\\n\\tsub_option:                       \" << sub_option \n        );\n        clp_check::check_sub_option(parent_option,sub_option);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_sub_options (\n        const string_type& parent_option,\n        const char_type* (&sub_option_set)[length]\n    ) const\n    {\n        // make sure requires clause is not broken\n        for (size_t i = 0; i < length; ++i)\n        {\n            DLIB_CASSERT( this->option_is_defined(sub_option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                                 \" << this\n                     << \"\\n\\toption_is_defined(sub_option_set[i]): \" \n                         << ((this->option_is_defined(sub_option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tsub_option_set[i]:                    \" << sub_option_set[i] \n                     << \"\\n\\ti:                                    \" << static_cast<unsigned long>(i) \n            );\n\n        }\n\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(parent_option), \n                 \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                 << \"\\n\\tSee the requires clause for this function.\"\n                 << \"\\n\\tthis:                             \" << this\n                 << \"\\n\\toption_is_defined(parent_option): \" << ((this->option_is_defined(parent_option))?\"true\":\"false\")\n                 << \"\\n\\tparsed_line():                    \" << ((this->parsed_line())?\"true\":\"false\")\n                 << \"\\n\\tparent_option:                    \" << parent_option \n        );\n        clp_check::check_sub_options(parent_option,sub_option_set);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_sub_options (\n        const char_type* (&parent_option_set)[length],\n        const string_type& sub_option\n    ) const\n    {\n        // make sure requires clause is not broken\n        for (size_t i = 0; i < length; ++i)\n        {\n            DLIB_CASSERT( this->option_is_defined(parent_option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                                    \" << this\n                     << \"\\n\\toption_is_defined(parent_option_set[i]): \" \n                         << ((this->option_is_defined(parent_option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tparent_option_set[i]:                    \" << parent_option_set[i] \n                     << \"\\n\\ti:                                       \" << static_cast<unsigned long>(i) \n            );\n\n        }\n\n        DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(sub_option), \n                 \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                 << \"\\n\\tSee the requires clause for this function.\"\n                 << \"\\n\\tthis:                          \" << this\n                 << \"\\n\\toption_is_defined(sub_option): \" << ((this->option_is_defined(sub_option))?\"true\":\"false\")\n                 << \"\\n\\tparsed_line():                 \" << ((this->parsed_line())?\"true\":\"false\")\n                 << \"\\n\\tsub_option:                    \" << sub_option \n        );\n        clp_check::check_sub_options(parent_option_set,sub_option);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t parent_length, size_t sub_length > \n    void cmd_line_parser_check_c<clp_check>::\n    check_sub_options (\n        const char_type* (&parent_option_set)[parent_length],\n        const char_type* (&sub_option_set)[sub_length]\n    ) const\n    {\n        // make sure requires clause is not broken\n        for (size_t i = 0; i < sub_length; ++i)\n        {\n            DLIB_CASSERT( this->option_is_defined(sub_option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                                 \" << this\n                     << \"\\n\\toption_is_defined(sub_option_set[i]): \" \n                         << ((this->option_is_defined(sub_option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tsub_option_set[i]:                    \" << sub_option_set[i] \n                     << \"\\n\\ti:                                    \" << static_cast<unsigned long>(i) \n            );\n        }\n\n        for (size_t i = 0; i < parent_length; ++i)\n        {\n            DLIB_CASSERT( this->option_is_defined(parent_option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_parent_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                                    \" << this\n                     << \"\\n\\toption_is_defined(parent_option_set[i]): \" \n                         << ((this->option_is_defined(parent_option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tparent_option_set[i]:                    \" << parent_option_set[i] \n                     << \"\\n\\ti:                                       \" << static_cast<unsigned long>(i)\n            );\n        }\n\n\n\n        DLIB_CASSERT( this->parsed_line() == true , \n                 \"\\tvoid cmd_line_parser_check::check_sub_options()\"\n                 << \"\\n\\tYou must have parsed the command line before you call this function.\"\n                 << \"\\n\\tthis:                             \" << this\n                 << \"\\n\\tparsed_line():                    \" << ((this->parsed_line())?\"true\":\"false\")\n        );\n\n        clp_check::check_sub_options(parent_option_set,sub_option_set);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename clp_check>\n    template < size_t length >\n    void cmd_line_parser_check_c<clp_check>::\n    check_one_time_options (\n        const char_type* (&option_set)[length]\n    ) const\n    {\n        // make sure requires clause is not broken\n        for (size_t i = 0; i < length; ++i)\n        {\n            DLIB_CASSERT( this->parsed_line() == true && this->option_is_defined(option_set[i]), \n                     \"\\tvoid cmd_line_parser_check::check_one_time_options()\"\n                     << \"\\n\\tSee the requires clause for this function.\"\n                     << \"\\n\\tthis:                             \" << this\n                     << \"\\n\\toption_is_defined(option_set[i]): \" << ((this->option_is_defined(option_set[i]))?\"true\":\"false\")\n                     << \"\\n\\tparsed_line():                    \" << ((this->parsed_line())?\"true\":\"false\")\n                     << \"\\n\\toption_set[i]:                    \" << option_set[i] \n                     << \"\\n\\ti:                                \" << static_cast<unsigned long>(i)\n            );\n\n        }\n        clp_check::check_one_time_options(option_set);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_CHECk_C_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_KERNEl_1_\n#define DLIB_CMD_LINE_PARSER_KERNEl_1_\n\n#include \"cmd_line_parser_kernel_abstract.h\"\n#include \"../algs.h\"\n#include <string>\n#include <sstream>\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/cmd_line_parser_option.h\"\n#include \"../assert.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    class cmd_line_parser_kernel_1 : public enumerable<cmd_line_parser_option<charT> >\n    {\n        /*!\n            REQUIREMENTS ON map\n                is an implementation of map/map_kernel_abstract.h \n                is instantiated to map items of type std::basic_string<charT> to void*     \n\n            REQUIREMENTS ON sequence\n                is an implementation of sequence/sequence_kernel_abstract.h and\n                is instantiated with std::basic_string<charT>\n\n            REQUIREMENTS ON sequence2\n                is an implementation of sequence/sequence_kernel_abstract.h and\n                is instantiated with std::basic_string<charT>*\n\n            INITIAL VALUE\n                options.size()   == 0\n                argv.size()      == 0\n                have_parsed_line == false\n\n            CONVENTION\n                have_parsed_line           == parsed_line()\n                argv[index]                == operator[](index)\n                argv.size()                == number_of_arguments()\n                *((option_t*)options[name])  == option(name)\n                options.is_in_domain(name) == option_is_defined(name)\n        !*/\n\n\n\n\n    public:\n\n        typedef charT char_type;\n        typedef std::basic_string<charT> string_type;\n        typedef cmd_line_parser_option<charT> option_type;\n\n        // exception class\n        class cmd_line_parse_error : public dlib::error \n        { \n            void set_info_string (\n            )\n            {\n                std::ostringstream sout;\n                switch (type)\n                {\n                    case EINVALID_OPTION:\n                        sout << \"Command line error: '\" << narrow(item) << \"' is not a valid option.\";\n                        break;\n                    case ETOO_FEW_ARGS:\n                        if (num > 1)\n                        {\n                            sout << \"Command line error: The '\" << narrow(item) << \"' option requires \" << num \n                                << \" arguments.\"; \n                        }\n                        else\n                        {\n                            sout << \"Command line error: The '\" << narrow(item) << \"' option requires \" << num \n                                << \" argument.\"; \n                        }\n                        break;\n                    case ETOO_MANY_ARGS:\n                        sout << \"Command line error: The '\" << narrow(item) << \"' option does not take any arguments.\\n\";\n                        break;\n                    default:\n                        sout << \"Command line error.\";\n                        break;\n                }\n                const_cast<std::string&>(info) = wrap_string(sout.str(),0,0);\n            }\n\n        public: \n            cmd_line_parse_error(\n                error_type t,\n                const std::basic_string<charT>& _item\n            ) :\n                dlib::error(t),\n                item(_item),\n                num(0)\n            { set_info_string();}\n\n            cmd_line_parse_error(\n                error_type t,\n                const std::basic_string<charT>& _item,\n                unsigned long _num\n            ) :\n                dlib::error(t),\n                item(_item),\n                num(_num)\n            { set_info_string();}\n\n            cmd_line_parse_error(\n            ) :\n                dlib::error(),\n                item(),\n                num(0)\n            { set_info_string();}\n\n            ~cmd_line_parse_error() noexcept {}\n\n            const std::basic_string<charT> item;\n            const unsigned long num;\n        };\n\n\n    private:\n\n        class option_t : public cmd_line_parser_option<charT>\n        {\n            /*!\n                INITIAL VALUE\n                    options.size()      == 0\n\n                CONVENTION\n                    name_                == name()\n                    description_         == description()\n                    number_of_arguments_ == number_of_arguments()\n                    options[N][arg]      == argument(arg,N)\n                    num_present          == count()                    \n            !*/\n\n            friend class cmd_line_parser_kernel_1<charT,map,sequence,sequence2>;\n\n        public:\n\n            const std::basic_string<charT>& name (\n            ) const { return name_; }\n\n            const std::basic_string<charT>& group_name (\n            ) const { return group_name_; }\n\n            const std::basic_string<charT>& description (\n            ) const { return description_; }\n\n            unsigned long number_of_arguments( \n            ) const { return number_of_arguments_; }\n\n            unsigned long count (\n            ) const { return num_present; }\n\n            const std::basic_string<charT>& argument (\n                unsigned long arg,\n                unsigned long N\n            ) const\n            {  \n                // make sure requires clause is not broken\n                DLIB_CASSERT( N < count() && arg < number_of_arguments(),\n                    \"\\tconst string_type& cmd_line_parser_option::argument(unsigned long,unsigned long)\"\n                    << \"\\n\\tInvalid arguments were given to this function.\"\n                    << \"\\n\\tthis:                  \" << this\n                    << \"\\n\\tN:                     \" << N\n                    << \"\\n\\targ:                   \" << arg \n                    << \"\\n\\tname():                \" << narrow(name())\n                    << \"\\n\\tcount():               \" << count()\n                    << \"\\n\\tnumber_of_arguments(): \" << number_of_arguments()\n                    );\n\n                return options[N][arg]; \n            }\n\n        protected:\n\n            option_t (\n            ) : \n                num_present(0)\n            {}\n\n            ~option_t()\n            {\n                clear();\n            }\n\n        private:\n\n            void clear()\n            /*!\n                ensures\n                    - #count() == 0\n                    - clears everything out of options and frees memory\n            !*/\n            {\n                for (unsigned long i = 0; i < options.size(); ++i)\n                {\n                    delete [] options[i];\n                }\n                options.clear();\n                num_present = 0;\n            }\n\n            // data members\n            std::basic_string<charT> name_;\n            std::basic_string<charT> group_name_;\n            std::basic_string<charT> description_;\n            sequence2 options;\n            unsigned long number_of_arguments_;\n            unsigned long num_present;\n\n\n\n            // restricted functions\n            option_t(option_t&);        // copy constructor\n            option_t& operator=(option_t&);    // assignment operator\n        };\n\n    // --------------------------\n\n    public:\n\n        cmd_line_parser_kernel_1 (\n        );\n\n        virtual ~cmd_line_parser_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        void parse (\n            int argc,\n            const charT** argv\n        );\n\n        void parse (\n            int argc,\n            charT** argv\n        )\n        {\n            parse(argc, const_cast<const charT**>(argv));\n        }\n\n        bool parsed_line(\n        ) const;\n\n        bool option_is_defined (\n            const string_type& name\n        ) const;\n\n        void add_option (\n            const string_type& name,\n            const string_type& description,\n            unsigned long number_of_arguments = 0\n        );\n\n        void set_group_name (\n            const string_type& group_name\n        );\n\n        string_type get_group_name (\n        ) const { return group_name; }\n\n        const cmd_line_parser_option<charT>& option (\n            const string_type& name\n        ) const;\n\n        unsigned long number_of_arguments( \n        ) const;\n\n        const string_type& operator[] (\n            unsigned long index\n        ) const;\n\n        void swap (\n            cmd_line_parser_kernel_1& item\n        );\n\n        // functions from the enumerable interface\n        bool at_start (\n        ) const { return options.at_start(); }\n\n        void reset (\n        ) const { options.reset(); }\n\n        bool current_element_valid (\n        ) const { return options.current_element_valid(); }\n\n        const cmd_line_parser_option<charT>& element (\n        ) const { return *static_cast<cmd_line_parser_option<charT>*>(options.element().value()); }\n\n        cmd_line_parser_option<charT>& element (\n        ) { return *static_cast<cmd_line_parser_option<charT>*>(options.element().value()); }\n\n        bool move_next (\n        ) const { return options.move_next(); }\n\n        size_t size (\n        ) const { return options.size(); }\n\n    private:\n\n        // data members\n        map options;\n        sequence argv;\n        bool have_parsed_line;\n        string_type group_name;\n\n        // restricted functions\n        cmd_line_parser_kernel_1(cmd_line_parser_kernel_1&);        // copy constructor\n        cmd_line_parser_kernel_1& operator=(cmd_line_parser_kernel_1&);    // assignment operator\n\n    };   \n   \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    inline void swap (\n        cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& a, \n        cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    cmd_line_parser_kernel_1 (\n    ) :\n        have_parsed_line(false)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    ~cmd_line_parser_kernel_1 (\n    ) \n    {\n        // delete all option_t objects in options\n        options.reset();\n        while (options.move_next())\n        {\n            delete static_cast<option_t*>(options.element().value());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    clear(\n    )\n    {\n        have_parsed_line = false;\n        argv.clear();\n\n\n        // delete all option_t objects in options\n        options.reset();\n        while (options.move_next())\n        {\n            delete static_cast<option_t*>(options.element().value());\n        }\n        options.clear();\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    parse (\n        int argc_,\n        const charT** argv\n    )\n    {\n        // make sure there aren't any arguments hanging around from the last time\n        // parse was called\n        this->argv.clear();\n\n        // make sure that the options have been cleared of any arguments since\n        // the last time parse() was called\n        if (have_parsed_line)\n        {\n            options.reset();\n            while (options.move_next())\n            {\n                static_cast<option_t*>(options.element().value())->clear();                \n            }\n            options.reset();\n        }\n\n        // this tells us if we have seen -- on the command line all by itself\n        // or not.  \n        bool escape = false;\n\n        const unsigned long argc = static_cast<unsigned long>(argc_);\n        try \n        {     \n\n            for (unsigned long i = 1; i < argc; ++i)\n            {            \n                if (argv[i][0] == _dT(charT,'-') && !escape)\n                {\n                    // we are looking at the start of an option                \n\n                    // --------------------------------------------------------------------\n                    if (argv[i][1] == _dT(charT,'-'))\n                    {\n                        // we are looking at the start of a \"long named\" option\n                        string_type temp = &argv[i][2];\n                        string_type first_argument;\n                        typename string_type::size_type pos = temp.find_first_of(_dT(charT,'='));\n                        // This variable will be 1 if there is an argument supplied via the = sign\n                        // and 0 otherwise.\n                        unsigned long extra_argument = 0;\n                        if (pos != string_type::npos)\n                        {\n                            // there should be an extra argument\n                            extra_argument = 1;\n                            first_argument = temp.substr(pos+1);\n                            temp = temp.substr(0,pos);\n                        }\n\n                        // make sure this name is defined\n                        if (!options.is_in_domain(temp))\n                        {\n                            // the long name is not a valid option                            \n                            if (argv[i][2] == _dT(charT,'\\0'))\n                            {\n                                // there was nothing after the -- on the command line\n                                escape = true;\n                                continue;\n                            }\n                            else\n                            {\n                                // there was something after the command line but it \n                                // wasn't a valid option\n                                throw cmd_line_parse_error(EINVALID_OPTION,temp);\n                            }                            \n                        }\n                        \n\n                        option_t* o = static_cast<option_t*>(options[temp]);\n\n                        // check the number of arguments after this option and make sure\n                        // it is correct\n                        if (argc + extra_argument <= o->number_of_arguments() + i) \n                        {\n                            // there are too few arguments\n                            throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments());    \n                        }\n                        if (extra_argument && first_argument.size() == 0 ) \n                        {\n                            // if there would be exactly the right number of arguments if \n                            // the first_argument wasn't empty\n                            if (argc == o->number_of_arguments() + i)\n                                throw cmd_line_parse_error(ETOO_FEW_ARGS,temp,o->number_of_arguments());    \n                            else\n                            {\n                                // in this case we just ignore the trailing = and parse everything\n                                // the same.\n                                extra_argument = 0;\n                            }\n                        }\n                        // you can't force an option that doesn't have any arguments to take\n                        // one by using the --option=arg syntax\n                        if (extra_argument == 1 && o->number_of_arguments() == 0)\n                        {\n                            throw cmd_line_parse_error(ETOO_MANY_ARGS,temp);\n                        }\n                        \n\n\n\n\n\n                        // at this point we know that the option is ok and we should\n                        // populate its options object\n                        if (o->number_of_arguments() > 0)\n                        {\n\n                            string_type* stemp = new string_type[o->number_of_arguments()];\n                            unsigned long j = 0;\n\n                            // add the argument after the = sign if one is present\n                            if (extra_argument)\n                            {\n                                stemp[0] = first_argument;\n                                ++j;\n                            }\n\n                            for (; j < o->number_of_arguments(); ++j)\n                            {                            \n                                stemp[j] = argv[i+j+1-extra_argument];\n                            }\n                            o->options.add(o->options.size(),stemp);\n                        }\n                        o->num_present += 1;\n\n\n                        // adjust the value of i to account for the arguments to \n                        // this option\n                        i += o->number_of_arguments() - extra_argument;\n                    }\n                    // --------------------------------------------------------------------\n                    else\n                    {\n                        // we are looking at the start of a list of a single char options\n\n                        // make sure there is something in this string other than -\n                        if (argv[i][1] == _dT(charT,'\\0'))\n                        {\n                            throw cmd_line_parse_error();                            \n                        }\n\n                        string_type temp = &argv[i][1];\n                        const typename string_type::size_type num = temp.size();\n                        for (unsigned long k = 0; k < num; ++k)\n                        {\n                            string_type name;\n                            // Doing this instead of name = temp[k] seems to avoid a bug in g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2\n                            // which results in name[0] having the wrong value.\n                            name.resize(1);\n                            name[0] = temp[k];\n\n\n                            // make sure this name is defined\n                            if (!options.is_in_domain(name))\n                            {\n                                // the name is not a valid option\n                                throw cmd_line_parse_error(EINVALID_OPTION,name);\n                            }\n\n                            option_t* o = static_cast<option_t*>(options[name]);\n\n                            // if there are chars immediately following this option\n                            int delta = 0;\n                            if (num != k+1)\n                            {\n                                delta = 1;\n                            }\n\n                            // check the number of arguments after this option and make sure\n                            // it is correct                            \n                            if (argc + delta <= o->number_of_arguments() + i)\n                            {\n                                // there are too few arguments\n                                std::ostringstream sout;\n                                throw cmd_line_parse_error(ETOO_FEW_ARGS,name,o->number_of_arguments());    \n                            }\n\n                            \n                            o->num_present += 1;\n\n                            // at this point we know that the option is ok and we should\n                            // populate its options object\n                            if (o->number_of_arguments() > 0)\n                            {\n                                string_type* stemp = new string_type[o->number_of_arguments()];\n                                if (delta == 1)\n                                {\n                                    temp = &argv[i][2+k];\n                                    k = (unsigned long)num;  // this ensures that the argument to this \n                                              // option isn't going to be treated as a \n                                              // list of options\n                                    \n                                    stemp[0] = temp;\n                                }\n                                for (unsigned long j = 0; j < o->number_of_arguments()-delta; ++j)\n                                {\n                                    stemp[j+delta] = argv[i+j+1];\n                                }\n                                o->options.add(o->options.size(),stemp);\n\n                                // adjust the value of i to account for the arguments to \n                                // this option\n                                i += o->number_of_arguments()-delta;\n                            }\n                        } // for (unsigned long k = 0; k < num; ++k)\n                    }\n                    // --------------------------------------------------------------------\n\n                }\n                else\n                {\n                    // this is just a normal argument\n                    string_type temp = argv[i];\n                    this->argv.add(this->argv.size(),temp);             \n                }\n\n            }\n            have_parsed_line = true;\n\n        }\n        catch (...)\n        {\n            have_parsed_line = false;\n\n            // clear all the option objects\n            options.reset();\n            while (options.move_next())\n            {\n                static_cast<option_t*>(options.element().value())->clear();                \n            }\n            options.reset();\n\n            throw;            \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    bool cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    parsed_line(\n    ) const\n    {\n        return have_parsed_line;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    bool cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    option_is_defined (\n        const string_type& name\n    ) const\n    {\n        return options.is_in_domain(name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    set_group_name (\n        const string_type& group_name_\n    )\n    {\n        group_name = group_name_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    add_option (\n        const string_type& name,\n        const string_type& description,\n        unsigned long number_of_arguments\n    )\n    {\n        option_t* temp = new option_t;\n        try\n        { \n            temp->name_ = name;\n            temp->group_name_ = group_name;\n            temp->description_ = description;\n            temp->number_of_arguments_ = number_of_arguments;\n            void* t = temp;\n            string_type n(name);\n            options.add(n,t); \n        }catch (...) { delete temp; throw;}\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    const cmd_line_parser_option<charT>& cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    option (\n        const string_type& name\n    ) const\n    {\n        return *static_cast<cmd_line_parser_option<charT>*>(options[name]);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    unsigned long cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    number_of_arguments( \n    ) const\n    {\n        return argv.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    const std::basic_string<charT>& cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    operator[] (\n        unsigned long index\n    ) const\n    {\n        return argv[index];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT,\n        typename map,\n        typename sequence,\n        typename sequence2\n        >\n    void cmd_line_parser_kernel_1<charT,map,sequence,sequence2>::\n    swap (\n        cmd_line_parser_kernel_1<charT,map,sequence,sequence2>& item\n    )\n    {\n        options.swap(item.options);\n        argv.swap(item.argv);\n        exchange(have_parsed_line,item.have_parsed_line);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_\n#ifdef DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <string>\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/cmd_line_parser_option.h\"\n#include <vector>\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename charT\n        >\n    class cmd_line_parser : public enumerable<cmd_line_parser_option<charT> >\n    {\n        /*!\n            REQUIREMENTS ON charT\n                Must be an integral type suitable for storing characters.  (e.g. char\n                or wchar_t)\n\n            INITIAL VALUE\n                - parsed_line() == false\n                - option_is_defined(x) == false, for all values of x\n                - get_group_name() == \"\"\n\n            ENUMERATION ORDER   \n                The enumerator will enumerate over all the options defined in *this \n                in alphabetical order according to the name of the option.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                parsed_line(), option_is_defined(), option(), number_of_arguments(),\n                operator[](), and swap() functions do not invalidate pointers or \n                references to internal data.  All other functions have no such guarantee.\n\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a command line parser. \n                The command lines must match the following BNF.  \n\n                command_line     ::= <program_name> { <options> | <arg> } [ -- {<word>} ]\n                program_name     ::= <word>\n                arg              ::= any <word> that does not start with - \n                option_arg       ::= <sword> \n                option_name      ::= <char>                \n                long_option_name ::= <char> {<char> | - }\n                options          ::= <bword> - <option_name> {<option_name>}  {<option_arg>}  |\n                                     <bword> -- <long_option_name> [=<option_arg>] {<bword> <option_arg>}\n                char             ::= any character other than - or =\n                word             ::= any string from argv where argv is the second \n                                     parameter to main() \n                sword            ::= any suffix of a string from argv where argv is the \n                                     second parameter to main() \n                bword            ::= This is an empty string which denotes the beginning of a \n                                     <word>.\n\n\n                Options with arguments:\n                    An option with N arguments will consider the next N swords to be\n                    its arguments. \n\n                    so for example, if we have an option o that expects 2 arguments \n                    then the following are a few legal examples:\n\n                        program -o arg1 arg2 general_argument\n                        program -oarg1 arg2 general_argument\n\n                    arg1 and arg2 are associated with the option o and general_argument\n                    is not.\n\n                Arguments not associated with an option:\n                    An argument that is not associated with an option is considered a\n                    general command line argument and is indexed by operator[] defined\n                    by the cmd_line_parser object.  Additionally, if the string\n                    \"--\" appears in the command line all by itself then all words\n                    following it are considered to be general command line arguments.\n\n\n                    Consider the following two examples involving a command line and \n                    a cmd_line_parser object called parser.\n\n                    Example 1:\n                        command line: program general_arg1 -o arg1 arg2 general_arg2\n                        Then the following is true (assuming the o option is defined\n                        and takes 2 arguments).\n\n                        parser[0] == \"general_arg1\"\n                        parser[1] == \"general_arg2\"\n                        parser.number_of_arguments() == 2\n                        parser.option(\"o\").argument(0) == \"arg1\"\n                        parser.option(\"o\").argument(1) == \"arg2\"\n                        parser.option(\"o\").count() == 1\n\n                    Example 2:\n                        command line: program general_arg1 -- -o arg1 arg2 general_arg2\n                        Then the following is true (the -- causes everything following \n                        it to be treated as a general argument).\n                        \n                        parser[0] == \"general_arg1\"\n                        parser[1] == \"-o\"\n                        parser[2] == \"arg1\"\n                        parser[3] == \"arg2\"\n                        parser[4] == \"general_arg2\"\n                        parser.number_of_arguments() == 5\n                        parser.option(\"o\").count() == 0\n        !*/\n\n    public:\n\n        typedef charT char_type;\n        typedef std::basic_string<charT> string_type;\n        typedef cmd_line_parser_option<charT> option_type;\n\n        // exception class\n        class cmd_line_parse_error : public dlib::error \n        {\n            /*!\n                GENERAL\n                    This exception is thrown if there is an error detected in a \n                    command line while it is being parsed.  You can consult this \n                    object's type and item members to determine the nature of the \n                    error. (note that the type member is inherited from dlib::error).\n\n                INTERPRETING THIS EXCEPTION\n                    - if (type == EINVALID_OPTION) then\n                        - There was an undefined option on the command line\n                        - item == The invalid option that was on the command line\n                    - if (type == ETOO_FEW_ARGS) then\n                        - An option was given on the command line but it was not\n                          supplied with the required number of arguments.\n                        - item == The name of this option.\n                        - num == The number of arguments expected by this option.\n                    - if (type == ETOO_MANY_ARGS) then\n                        - An option was given on the command line such as --option=arg\n                          but this option doesn't take any arguments.\n                        - item == The name of this option.\n            !*/\n        public:\n            const std::basic_string<charT> item;\n            const unsigned long num;\n        };\n\n    // --------------------------\n\n        cmd_line_parser (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~cmd_line_parser (\n        );\n        /*!\n            ensures\n                 - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void parse (\n            int argc,\n            const charT** argv\n        );\n        /*!\n            requires                \n                - argv == an array of strings that was obtained from the second argument \n                          of the function main().\n                          (i.e. argv[0] should be the <program> token, argv[1] should be\n                          an <options> or <arg> token, etc.)\n                - argc == the number of strings in argv\n            ensures\n                - parses the command line given by argc and argv \n                - #parsed_line() == true\n                - #at_start() == true\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable until clear()\n                    is called successfully\n                - cmd_line_parse_error\n                    This exception is thrown if there is an error parsing the command line.\n                    If this exception is thrown then #parsed_line() == false and all \n                    options will have their count() set to 0 but otherwise there will \n                    be no effect (i.e. all registered options will remain registered).\n        !*/\n\n        void parse (\n            int argc,\n            charT** argv\n        );\n        /*!\n            This just calls this->parse(argc,argv) and performs the necessary const_cast\n            on argv.\n        !*/\n\n        bool parsed_line(\n        ) const;\n        /*!\n            ensures\n                - returns true if parse() has been called successfully \n                - returns false otherwise\n        !*/\n\n        bool option_is_defined (\n            const string_type& name\n        ) const;\n        /*!\n            ensures\n                - returns true if the option has been added to the parser object \n                  by calling add_option(name). \n                - returns false otherwise\n        !*/\n\n        void add_option (\n            const string_type& name,\n            const string_type& description,\n            unsigned long number_of_arguments = 0\n        );\n        /*!\n            requires\n                - parsed_line() == false \n                - option_is_defined(name) == false \n                - name does not contain any ' ', '\\t', '\\n', or '=' characters\n                - name[0] != '-'\n                - name.size() > 0\n            ensures\n                - #option_is_defined(name) == true \n                - #at_start() == true\n                - #option(name).count() == 0\n                - #option(name).description() == description \n                - #option(name).number_of_arguments() == number_of_arguments\n                - #option(name).group_name() == get_group_name()\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then the add_option() function has no \n                    effect\n        !*/\n\n        const option_type& option (\n            const string_type& name\n        ) const;\n        /*! \n            requires\n                - option_is_defined(name) == true\n            ensures\n                - returns the option specified by name\n        !*/ \n\n        unsigned long number_of_arguments( \n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n            ensures\n                - returns the number of arguments present in the command line.\n                  This count does not include options or their arguments.  Only \n                  arguments unrelated to any option are counted.\n        !*/\n\n        const string_type& operator[] (\n            unsigned long N\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - N < number_of_arguments()\n            ensures\n                - returns the Nth command line argument\n        !*/\n\n        void swap (\n            cmd_line_parser& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n        void print_options (\n            std::basic_ostream<char_type>& out\n        ) const;\n        /*!\n            ensures\n                - prints all the command line options to out.\n                - #at_start() == true\n            throws                \n                - any exception.\n                    if an exception is thrown then #at_start() == true but otherwise  \n                    it will have no effect on the state of #*this.\n        !*/\n\n        void print_options (\n        ) const;\n        /*!\n            ensures\n                - prints all the command line options to cout.\n                - #at_start() == true\n            throws                \n                - any exception.\n                    if an exception is thrown then #at_start() == true but otherwise  \n                    it will have no effect on the state of #*this.\n        !*/\n\n        string_type get_group_name (\n        ) const;\n        /*!\n            ensures\n                - returns the current group name.  This is the group new options will be\n                  added into when added via add_option().  \n                - The group name of an option is used by print_options().  In particular,\n                  it groups all options with the same group name together and displays them\n                  under a title containing the text of the group name.  This allows you to\n                  group similar options together in the output of print_options().\n                - A group name of \"\" (i.e. the empty string) means that no group name is\n                  set.\n        !*/\n\n        void set_group_name (\n            const string_type& group_name\n        );\n        /*!\n            ensures\n                - #get_group_name() == group_name\n        !*/\n\n    // -------------------------------------------------------------\n    //                    Input Validation Tools\n    // -------------------------------------------------------------\n\n        class cmd_line_check_error : public dlib::error \n        {\n            /*!\n                This is the exception thrown by the check_*() routines if they find a\n                command line error.  The interpretation of the member variables is defined\n                below in each check_*() routine.\n            !*/\n\n        public:\n            const string_type opt;\n            const string_type opt2;\n            const string_type arg; \n            const std::vector<string_type> required_opts; \n        };\n\n        template <\n            typename T\n            >\n        void check_option_arg_type (\n            const string_type& option_name\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(option_name) == true\n                - T is not a pointer type\n            ensures\n                - all the arguments for the given option are convertible\n                  by string_cast<T>() to an object of type T.\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied. \n                    The exception's members will be set as follows:\n                        - type == EINVALID_OPTION_ARG\n                        - opt == option_name\n                        - arg == the text of the offending argument\n        !*/\n\n        template <\n            typename T\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T& first,\n            const T& last\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(option_name) == true\n                - first <= last\n                - T is not a pointer type\n            ensures\n                - all the arguments for the given option are convertible\n                  by string_cast<T>() to an object of type T and the resulting value is\n                  in the range first to last inclusive.\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EINVALID_OPTION_ARG\n                        - opt == option_name\n                        - arg == the text of the offending argument\n        !*/\n\n        template <\n            typename T,\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const T (&arg_set)[length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(option_name) == true\n                - T is not a pointer type\n            ensures\n                - for each argument to the given option:\n                    - this argument is convertible by string_cast<T>() to an object of\n                      type T and the resulting value is equal to some element in the\n                      arg_set array.\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EINVALID_OPTION_ARG\n                        - opt == option_name\n                        - arg == the text of the offending argument\n        !*/\n\n        template <\n            size_t length\n            >\n        void check_option_arg_range (\n            const string_type& option_name,\n            const char_type* (&arg_set)[length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(option_name) == true\n            ensures\n                - for each argument to the given option:\n                    - there is a string in the arg_set array that is equal to this argument.\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EINVALID_OPTION_ARG\n                        - opt == option_name\n                        - arg == the text of the offending argument\n        !*/\n\n        template <\n            size_t length\n            >\n        void check_one_time_options (\n            const char_type* (&option_set)[length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - for all valid i:\n                    - option_is_defined(option_set[i]) == true\n            ensures\n                - all the options in the option_set array occur at most once on the\n                  command line.\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EMULTIPLE_OCCURANCES \n                        - opt == the option that occurred more than once on the command line. \n        !*/\n\n        void check_incompatible_options (\n            const string_type& option_name1,\n            const string_type& option_name2\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(option_name1) == true\n                - option_is_defined(option_name2) == true\n            ensures\n                - option(option_name1).count() == 0 || option(option_name2).count() == 0\n                  (i.e. at most, only one of the options is currently present)\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EINCOMPATIBLE_OPTIONS \n                        - opt == option_name1 \n                        - opt2 == option_name2 \n        !*/\n\n        template <\n            size_t length\n            >\n        void check_incompatible_options (\n            const char_type* (&option_set)[length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - for all valid i:\n                    - option_is_defined(option_set[i]) == true\n            ensures\n                - At most only one of the options in the array option_set has a count()\n                  greater than 0.  (i.e. at most, only one of the options is currently present)\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EINCOMPATIBLE_OPTIONS \n                        - opt == One of the incompatible options found.\n                        - opt2 == The next incompatible option found.\n        !*/\n\n        void check_sub_option (\n            const string_type& parent_option,\n            const string_type& sub_option\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(parent_option) == true\n                - option_is_defined(sub_option) == true\n            ensures\n                - if (option(parent_option).count() == 0) then\n                    - option(sub_option).count() == 0\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EMISSING_REQUIRED_OPTION \n                        - opt == sub_option. \n                        - required_opts == a vector that contains only parent_option. \n        !*/\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[length],\n            const string_type& sub_option\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(sub_option) == true\n                - for all valid i:\n                    - option_is_defined(parent_option_set[i] == true\n            ensures\n                - if (option(sub_option).count() > 0) then\n                    - At least one of the options in the array parent_option_set has a count()\n                      greater than 0. (i.e. at least one of the options in parent_option_set\n                      is currently present)\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EMISSING_REQUIRED_OPTION \n                        - opt == the first option from the sub_option that is present. \n                        - required_opts == a vector containing everything from parent_option_set.\n        !*/\n\n        template <\n            size_t length\n            >\n        void check_sub_options (\n            const string_type& parent_option,\n            const char_type* (&sub_option_set)[length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - option_is_defined(parent_option) == true\n                - for all valid i:\n                    - option_is_defined(sub_option_set[i]) == true\n            ensures\n                - if (option(parent_option).count() == 0) then\n                    - for all valid i:\n                        - option(sub_option_set[i]).count() == 0\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EMISSING_REQUIRED_OPTION \n                        - opt == the first option from the sub_option_set that is present.\n                        - required_opts == a vector that contains only parent_option. \n        !*/\n\n        template <\n            size_t parent_length,\n            size_t sub_length\n            >\n        void check_sub_options (\n            const char_type* (&parent_option_set)[parent_length],\n            const char_type* (&sub_option_set)[sub_length]\n        ) const;\n        /*!\n            requires\n                - parsed_line() == true\n                - for all valid i:\n                    - option_is_defined(parent_option_set[i] == true\n                - for all valid j:\n                    - option_is_defined(sub_option_set[j]) == true\n            ensures\n                - for all valid j:\n                    - if (option(sub_option_set[j]).count() > 0) then\n                        - At least one of the options in the array parent_option_set has a count()\n                          greater than 0. (i.e. at least one of the options in parent_option_set\n                          is currently present)\n            throws\n                - std::bad_alloc\n                - cmd_line_check_error\n                    This exception is thrown if the ensures clause could not be satisfied.\n                    The exception's members will be set as follows:\n                        - type == EMISSING_REQUIRED_OPTION \n                        - opt == the first option from the sub_option_set that is present. \n                        - required_opts == a vector containing everything from parent_option_set.\n        !*/\n\n\n    private:\n\n        // restricted functions\n        cmd_line_parser(cmd_line_parser&);        // copy constructor\n        cmd_line_parser& operator=(cmd_line_parser&);    // assignment operator\n\n    };   \n\n// -----------------------------------------------------------------------------------------\n\n    typedef cmd_line_parser<char>    command_line_parser;\n    typedef cmd_line_parser<wchar_t> wcommand_line_parser;\n   \n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename charT\n        >\n    inline void swap (\n        cmd_line_parser<charT>& a, \n        cmd_line_parser<charT>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_KERNEl_C_\n#define DLIB_CMD_LINE_PARSER_KERNEl_C_\n\n#include \"cmd_line_parser_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <string>\n#include \"../interfaces/cmd_line_parser_option.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename clp_base\n        >\n    class cmd_line_parser_kernel_c : public clp_base\n    {\n    public:\n\n        typedef typename clp_base::char_type char_type;\n        typedef typename clp_base::string_type string_type;\n        typedef typename clp_base::option_type option_type;\n\n        void add_option (\n            const string_type& name,\n            const string_type& description,\n            unsigned long number_of_arguments = 0\n        );\n\n        const option_type& option (\n            const string_type& name\n        ) const;\n\n        unsigned long number_of_arguments( \n        ) const;\n\n        const option_type& element (\n        ) const;\n\n        option_type& element (\n        );\n\n        const string_type& operator[] (\n            unsigned long N\n        ) const;\n\n    };\n\n\n    template <\n        typename clp_base\n        >\n    inline void swap (\n        cmd_line_parser_kernel_c<clp_base>& a, \n        cmd_line_parser_kernel_c<clp_base>& b \n    ) { a.swap(b); } \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    const typename clp_base::string_type& cmd_line_parser_kernel_c<clp_base>::\n    operator[] (\n        unsigned long N\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true && N < number_of_arguments(),\n                 \"\\tvoid cmd_line_parser::operator[](unsigned long N)\"\n                 << \"\\n\\tYou must specify a valid index N and the parser must have run already.\"\n                 << \"\\n\\tthis:                      \" << this\n                 << \"\\n\\tN:                         \" << N\n                 << \"\\n\\tparsed_line():             \" << this->parsed_line()\n                 << \"\\n\\tnumber_of_arguments():     \" << number_of_arguments()\n        );\n\n        return clp_base::operator[](N);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    void cmd_line_parser_kernel_c<clp_base>::\n    add_option (\n        const string_type& name,\n        const string_type& description,\n        unsigned long number_of_arguments\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == false &&\n                 name.size() > 0 &&\n                 this->option_is_defined(name) == false &&\n                 name.find_first_of(_dT(char_type,\" \\t\\n=\")) == string_type::npos &&\n                 name[0] != '-',\n                 \"\\tvoid cmd_line_parser::add_option(const string_type&,const string_type&,unsigned long)\"\n                 << \"\\n\\tsee the requires clause of add_option()\"\n                 << \"\\n\\tthis:                   \" << this\n                 << \"\\n\\tname.size():            \" << static_cast<unsigned long>(name.size())\n                 << \"\\n\\tname:                  \\\"\" << narrow(name) << \"\\\"\"\n                 << \"\\n\\tparsed_line():          \" << (this->parsed_line()? \"true\" : \"false\")\n                 << \"\\n\\tis_option_defined(\\\"\" << narrow(name) << \"\\\"): \" << (this->option_is_defined(name)? \"true\" : \"false\")\n        );\n\n        clp_base::add_option(name,description,number_of_arguments);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::\n    option (\n        const string_type& name\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->option_is_defined(name) == true,\n                 \"\\toption cmd_line_parser::option(const string_type&)\"\n                 << \"\\n\\tto get an option it must be defined by a call to add_option()\"\n                 << \"\\n\\tthis:   \" << this\n                 << \"\\n\\tname:  \\\"\" << narrow(name) << \"\\\"\"\n        );\n\n        return clp_base::option(name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    unsigned long cmd_line_parser_kernel_c<clp_base>::\n    number_of_arguments( \n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->parsed_line() == true ,\n                 \"\\tunsigned long cmd_line_parser::number_of_arguments()\"\n                 << \"\\n\\tyou must parse the command line before you can find out how many arguments it has\"\n                 << \"\\n\\tthis:            \" << this\n        );\n\n        return clp_base::number_of_arguments();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    const typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::\n    element (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n                \"\\tconst cmd_line_parser_option& cmd_line_parser::element()\"\n                << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        return clp_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    typename clp_base::option_type& cmd_line_parser_kernel_c<clp_base>::\n    element (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n                \"\\tcmd_line_parser_option& cmd_line_parser::element()\"\n                << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        return clp_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/cmd_line_parser_print_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_PRINt_1_\n#define DLIB_CMD_LINE_PARSER_PRINt_1_\n\n#include \"cmd_line_parser_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../string.h\"\n#include <iostream>\n#include <string>\n#include <sstream>\n#include <map>\n#include <memory>\n\nnamespace dlib\n{\n\n    template <\n        typename clp_base \n        >\n    class cmd_line_parser_print_1 : public clp_base\n    {\n\n        public:\n\n            void print_options (\n                std::basic_ostream<typename clp_base::char_type>& out\n            ) const;\n\n            void print_options (\n            ) const\n            {\n                print_options(std::cout);\n            }\n\n    };\n\n    template <\n        typename clp_base\n        >\n    inline void swap (\n        cmd_line_parser_print_1<clp_base>& a, \n        cmd_line_parser_print_1<clp_base>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename clp_base\n        >\n    void cmd_line_parser_print_1<clp_base>::\n    print_options (\n        std::basic_ostream<typename clp_base::char_type>& out\n    ) const\n    {\n        typedef typename clp_base::char_type ct;\n        typedef std::basic_string<ct> string;\n        typedef typename string::size_type size_type;\n\n        typedef std::basic_ostringstream<ct> ostringstream;\n\n        try\n        {\n\n\n            size_type max_len = 0; \n            this->reset();\n\n            // this loop here is just the bottom loop but without the print statements.\n            // I'm doing this to figure out what len should be.\n            while (this->move_next())\n            {\n                size_type len = 0; \n                len += 3;\n                if (this->element().name().size() > 1)\n                {\n                    ++len;\n                }\n                len += this->element().name().size();\n\n                if (this->element().number_of_arguments() == 1)\n                {\n                    len += 6;\n                }\n                else\n                {\n                    for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i)\n                    {\n                        len += 7;\n                        if (i+1 > 9)\n                            ++len;\n                    }\n                }\n\n                len += 3;\n                if (len < 33)\n                    max_len = std::max(max_len,len);\n            }\n\n\n            // Make a separate ostringstream for each option group.  We are going to write\n            // the output for each group to a separate ostringstream so that we can keep\n            // them grouped together in the final output.\n            std::map<string,std::shared_ptr<ostringstream> > groups;\n            this->reset();\n            while(this->move_next())\n            {\n                if (!groups[this->element().group_name()])\n                    groups[this->element().group_name()].reset(new ostringstream);\n            }\n\n\n\n\n            this->reset();\n\n            while (this->move_next())\n            {\n                ostringstream& sout = *groups[this->element().group_name()];\n\n                size_type len = 0; \n                sout << _dT(ct,\"\\n  -\");\n                len += 3;\n                if (this->element().name().size() > 1)\n                {\n                    sout << _dT(ct,\"-\");\n                    ++len;\n                }\n                sout << this->element().name();\n                len += this->element().name().size();\n\n                if (this->element().number_of_arguments() == 1)\n                {\n                    sout << _dT(ct,\" <arg>\");\n                    len += 6;\n                }\n                else\n                {\n                    for (unsigned long i = 0; i < this->element().number_of_arguments(); ++i)\n                    {\n                        sout << _dT(ct,\" <arg\") << i+1 << _dT(ct,\">\");\n                        len += 7;\n                        if (i+1 > 9)\n                            ++len;\n                    }\n                }\n\n                sout << _dT(ct,\"   \");\n                len += 3;\n\n                while (len < max_len)\n                {\n                    ++len;\n                    sout << _dT(ct,\" \");\n                }\n\n                const unsigned long ml = static_cast<unsigned long>(max_len);\n                // now print the description but make it wrap around nicely if it \n                // is to long to fit on one line.\n                if (len <= max_len)\n                    sout << wrap_string(this->element().description(),0,ml);\n                else\n                    sout << _dT(ct,\"\\n\") << wrap_string(this->element().description(),ml,ml);\n            }\n\n            // Only print out a generic Options: group name if there is an unnamed option\n            // present.\n            if (groups.count(string()) == 1)\n                out << _dT(ct,\"Options:\");\n\n            // Now print everything out\n            typename std::map<string,std::shared_ptr<ostringstream> >::iterator i;\n            for (i = groups.begin(); i != groups.end(); ++i)\n            {\n                // print the group name if we have one\n                if (i->first.size() != 0)\n                {\n                    if (i != groups.begin())\n                        out << _dT(ct,\"\\n\\n\");\n                    out << i->first << _dT(ct,\":\");\n                }\n\n                // print the options in the group\n                out << i->second->str();\n            }\n            out << _dT(ct,\"\\n\\n\");\n            this->reset();\n        }\n        catch (...)\n        {\n            this->reset();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_PRINt_1_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/get_option.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GET_OPTiON_Hh_\n#define DLIB_GET_OPTiON_Hh_\n\n#include \"get_option_abstract.h\"\n#include \"../string.h\"\n#include \"../is_kind.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class option_parse_error : public error\n    {\n    public:\n        option_parse_error(const std::string& option_string, const std::string& str):\n            error(EOPTION_PARSE,\"Error parsing argument for option '\" + option_string + \"', offending string is '\" + str + \"'.\") {}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename config_reader_type, typename T>\n    T impl_config_reader_get_option (\n        const config_reader_type& cr,\n        const std::string& option_name,\n        const std::string& full_option_name,\n        T default_value\n    )\n    {\n        std::string::size_type pos = option_name.find_first_of(\".\");\n        if (pos == std::string::npos)\n        {\n            if (cr.is_key_defined(option_name))\n            {\n                try{ return string_cast<T>(cr[option_name]); }\n                catch (string_cast_error&) { throw option_parse_error(full_option_name, cr[option_name]); }\n            }\n        }\n        else\n        {\n            std::string block_name = option_name.substr(0,pos);\n            if (cr.is_block_defined(block_name))\n            {\n                return impl_config_reader_get_option(cr.block(block_name), \n                                                     option_name.substr(pos+1),\n                                                     full_option_name,\n                                                     default_value);\n            }\n        }\n\n        return default_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename cr_type, typename T>\n    typename enable_if<is_config_reader<cr_type>,T>::type get_option (\n        const cr_type& cr,\n        const std::string& option_name,\n        T default_value\n    )\n    {\n        return impl_config_reader_get_option(cr, option_name, option_name, default_value);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename parser_type, typename T>\n    typename disable_if<is_config_reader<parser_type>,T>::type get_option (\n        const parser_type& parser,\n        const std::string& option_name,\n        T default_value\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&\n                     parser.option(option_name).number_of_arguments() == 1,\n            \"\\t T get_option()\"\n            << \"\\n\\t option_name: \" << option_name\n            << \"\\n\\t parser.option_is_defined(option_name):            \" << parser.option_is_defined(option_name)\n            << \"\\n\\t parser.option(option_name).number_of_arguments(): \" << parser.option(option_name).number_of_arguments()\n            );\n\n        if (parser.option(option_name))\n        {\n            try\n            {\n                default_value = string_cast<T>(parser.option(option_name).argument()); \n            }\n            catch (string_cast_error&) \n            { \n                throw option_parse_error(option_name, parser.option(option_name).argument()); \n            }\n        }\n        return default_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename parser_type, typename cr_type, typename T>\n    typename disable_if<is_config_reader<parser_type>,T>::type get_option (\n        const parser_type& parser,\n        const cr_type& cr,\n        const std::string& option_name,\n        T default_value\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&\n                     parser.option(option_name).number_of_arguments() == 1,\n            \"\\t T get_option()\"\n            << \"\\n\\t option_name: \" << option_name\n            << \"\\n\\t parser.option_is_defined(option_name):            \" << parser.option_is_defined(option_name)\n            << \"\\n\\t parser.option(option_name).number_of_arguments(): \" << parser.option(option_name).number_of_arguments()\n            );\n\n        if (parser.option(option_name))\n            return get_option(parser, option_name, default_value); \n        else\n            return get_option(cr, option_name, default_value);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename parser_type, typename cr_type, typename T>\n    typename disable_if<is_config_reader<parser_type>,T>::type get_option (\n        const cr_type& cr,\n        const parser_type& parser,\n        const std::string& option_name,\n        T default_value\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( parser.option_is_defined(option_name) == true &&\n                     parser.option(option_name).number_of_arguments() == 1,\n            \"\\t T get_option()\"\n            << \"\\n\\t option_name: \" << option_name\n            << \"\\n\\t parser.option_is_defined(option_name):            \" << parser.option_is_defined(option_name)\n            << \"\\n\\t parser.option(option_name).number_of_arguments(): \" << parser.option(option_name).number_of_arguments()\n            );\n\n        if (parser.option(option_name))\n            return get_option(parser, option_name, default_value); \n        else\n            return get_option(cr, option_name, default_value);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline std::string get_option (\n        const T& cr,\n        const std::string& option_name,\n        const char* default_value\n    )\n    {\n        return get_option(cr, option_name, std::string(default_value));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline std::string get_option (\n        const T& parser,\n        const U& cr,\n        const std::string& option_name,\n        const char* default_value\n    )\n    {\n        return get_option(parser, cr, option_name, std::string(default_value));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GET_OPTiON_Hh_\n\n"
  },
  {
    "path": "dlib/cmd_line_parser/get_option_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GET_OPTiON_ABSTRACT_Hh_\n#ifdef DLIB_GET_OPTiON_ABSTRACT_Hh_\n\n#inclue <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class option_parse_error : public error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown by the get_option() functions.  It is\n                thrown when the option string given by a command line parser or\n                config reader can't be converted into the type T.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_type, \n        typename T\n        >\n    T get_option (\n        const config_reader_type& cr,\n        const std::string& option_name,\n        T default_value\n    );\n    /*!\n        requires\n            - T is a type which can be read from an input stream\n            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h\n        ensures\n            - option_name is used to index into the given config_reader.  \n            - if (cr contains an entry corresponding to option_name) then\n                - converts the string value in cr corresponding to option_name into\n                  an object of type T and returns it.\n            - else\n                - returns default_value\n            - The scheme for indexing into cr based on option_name is best\n              understood by looking at a few examples:\n                - an option name of \"name\" corresponds to cr[\"name\"]\n                - an option name of \"block1.name\" corresponds to cr.block(\"block1\")[\"name\"]\n                - an option name of \"block1.block2.name\" corresponds to cr.block(\"block1\").block(\"block2\")[\"name\"]\n        throws\n            - option_parse_error\n              This exception is thrown if we attempt but fail to convert the string value\n              in cr into an object of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename command_line_parser_type,\n        typename T\n        >\n    T get_option (\n        const command_line_parser_type& parser,\n        const std::string& option_name,\n        T default_value\n    );\n    /*!\n        requires\n            - parser.option_is_defined(option_name) == true\n            - parser.option(option_name).number_of_arguments() == 1   \n            - T is a type which can be read from an input stream\n            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h\n        ensures\n            - if (parser.option(option_name)) then \n                - converts parser.option(option_name).argument() into an object\n                  of type T and returns it.  That is, the string argument to this\n                  command line option is converted into a T and returned.\n            - else\n                - returns default_value\n        throws\n            - option_parse_error\n              This exception is thrown if we attempt but fail to convert the string\n              argument into an object of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename command_line_parser_type, \n        typename config_reader_type, \n        typename T\n        >\n    T get_option (\n        const command_line_parser_type& parser,\n        const config_reader_type& cr,\n        const std::string& option_name,\n        T default_value\n    );\n    /*!\n        requires\n            - parser.option_is_defined(option_name) == true\n            - parser.option(option_name).number_of_arguments() == 1   \n            - T is a type which can be read from an input stream\n            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h\n            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h\n        ensures\n            - if (parser.option(option_name)) then \n                - returns get_option(parser, option_name, default_value)\n            - else\n                - returns get_option(cr, option_name, default_value)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename command_line_parser_type, \n        typename config_reader_type, \n        typename T\n        >\n    T get_option (\n        const config_reader_type& cr,\n        const command_line_parser_type& parser,\n        const std::string& option_name,\n        T default_value\n    );\n    /*!\n        requires\n            - parser.option_is_defined(option_name) == true\n            - parser.option(option_name).number_of_arguments() == 1   \n            - T is a type which can be read from an input stream\n            - command_line_parser_type == an implementation of cmd_line_parser/cmd_line_parser_kernel_abstract.h\n            - config_reader_type == an implementation of config_reader/config_reader_kernel_abstract.h\n        ensures\n            - if (parser.option(option_name)) then \n                - returns get_option(parser, option_name, default_value)\n            - else\n                - returns get_option(cr, option_name, default_value)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GET_OPTiON_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/cmd_line_parser.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSEr_\n#define DLIB_CMD_LINE_PARSEr_\n\n#include \"cmd_line_parser/cmd_line_parser_kernel_1.h\"\n#include \"cmd_line_parser/cmd_line_parser_kernel_c.h\"\n#include \"cmd_line_parser/cmd_line_parser_print_1.h\"\n#include \"cmd_line_parser/cmd_line_parser_check_1.h\"\n#include \"cmd_line_parser/cmd_line_parser_check_c.h\"\n#include <string>\n#include \"cmd_line_parser/get_option.h\"\n\n#include \"map.h\"\n#include \"sequence.h\"\n\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT\n        >\n    class impl_cmd_line_parser\n    {\n        /*!\n            This class is basically just a big templated typedef for building \n            a complete command line parser type out of all the parts it needs.\n        !*/\n\n        impl_cmd_line_parser() {}\n\n        typedef typename sequence<std::basic_string<charT> >::kernel_2a sequence_2a;\n        typedef typename sequence<std::basic_string<charT>*>::kernel_2a psequence_2a;\n        typedef typename map<std::basic_string<charT>,void*>::kernel_1a map_1a_string;\n\n    public:\n        \n        typedef cmd_line_parser_kernel_1<charT,map_1a_string,sequence_2a,psequence_2a> kernel_1a;\n        typedef cmd_line_parser_kernel_c<kernel_1a> kernel_1a_c;\n        typedef cmd_line_parser_print_1<kernel_1a_c> print_1a_c;\n        typedef cmd_line_parser_check_c<cmd_line_parser_check_1<print_1a_c> > check_1a_c;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT\n        >\n    class cmd_line_parser : public impl_cmd_line_parser<charT>::check_1a_c\n    {\n    public:\n\n        // These typedefs are here for backwards compatibility with previous versions of dlib.\n        typedef cmd_line_parser kernel_1a;\n        typedef cmd_line_parser kernel_1a_c;\n        typedef cmd_line_parser print_1a;\n        typedef cmd_line_parser print_1a_c;\n        typedef cmd_line_parser check_1a;\n        typedef cmd_line_parser check_1a_c;\n    };\n\n    template <\n        typename charT \n        >\n    inline void swap (\n        cmd_line_parser<charT>& a, \n        cmd_line_parser<charT>& b \n    ) { a.swap(b); } \n\n// ----------------------------------------------------------------------------------------\n\n    typedef cmd_line_parser<char> command_line_parser;\n    typedef cmd_line_parser<wchar_t> wcommand_line_parser;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSEr_\n\n"
  },
  {
    "path": "dlib/compress_stream/compress_stream_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_COMPRESS_STREAM_KERNEl_1_\n#define DLIB_COMPRESS_STREAM_KERNEl_1_\n\n#include \"../algs.h\"\n#include <iostream>\n#include <streambuf>\n#include <cstdio>\n#include \"compress_stream_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename fce,\n        typename fcd,\n        typename crc32\n        >\n    class compress_stream_kernel_1\n    {\n        /*!\n            REQUIREMENTS ON fce\n                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h\n                the alphabet_size of fce must be 257.\n                fce and fcd share the same kernel number.\n\n            REQUIREMENTS ON fcd\n                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h\n                the alphabet_size of fcd must be 257.\n                fce and fcd share the same kernel number.\n\n            REQUIREMENTS ON crc32\n                is an implementation of crc32/crc32_kernel_abstract.h\n\n\n\n            INITIAL VALUE\n                this object has no state\n\n            CONVENTION\n                this object has no state\n        !*/\n\n        const static unsigned long eof_symbol = 256;\n\n    public:\n\n        class decompression_error : public dlib::error \n        { \n            public: \n                decompression_error(\n                    const char* i\n                ) :\n                    dlib::error(std::string(i))\n                {}\n\n                decompression_error(\n                    const std::string& i\n                ) :\n                    dlib::error(i)\n                {}\n        };\n\n\n        compress_stream_kernel_1 (\n        )\n        {}\n\n        ~compress_stream_kernel_1 (\n        )\n        {}\n\n        void compress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n        void decompress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n    private:\n\n        // restricted functions\n        compress_stream_kernel_1(compress_stream_kernel_1&);        // copy constructor\n        compress_stream_kernel_1& operator=(compress_stream_kernel_1&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename fce,\n        typename fcd,\n        typename crc32\n        >\n    void compress_stream_kernel_1<fce,fcd,crc32>::\n    compress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n        std::streambuf::int_type temp;\n\n        std::streambuf& in = *in_.rdbuf();\n\n        typename fce::entropy_encoder_type coder;\n        coder.set_stream(out_);\n\n        fce model(coder);\n\n        crc32 crc;\n\n        unsigned long count = 0;\n\n        while (true)\n        {\n            // write out a known value every 20000 symbols\n            if (count == 20000)\n            {\n                count = 0;\n                coder.encode(1500,1501,8000);\n            }\n            ++count;\n\n            // get the next character\n            temp = in.sbumpc();\n\n            // if we have hit EOF then encode the marker symbol\n            if (temp != EOF)  \n            {\n                // encode the symbol\n                model.encode(static_cast<unsigned long>(temp));\n                crc.add(static_cast<unsigned char>(temp));\n                continue;\n            }\n            else\n            {\n                model.encode(eof_symbol);\n\n                // now write the checksum\n                unsigned long checksum = crc.get_checksum();\n                unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);\n                unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);\n                unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);\n                unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);\n\n                model.encode(byte1);\n                model.encode(byte2);\n                model.encode(byte3);\n                model.encode(byte4);\n\n                break;\n            }\n        }      \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename fce,\n        typename fcd,\n        typename crc32\n        >\n    void compress_stream_kernel_1<fce,fcd,crc32>::\n    decompress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n\n        std::streambuf& out = *out_.rdbuf();\n\n        typename fcd::entropy_decoder_type coder;\n        coder.set_stream(in_);\n\n        fcd model(coder);\n\n        unsigned long symbol;\n        unsigned long count = 0;\n\n        crc32 crc;\n\n        // decode until we hit the marker symbol\n        while (true)\n        {\n            // make sure this is the value we expect\n            if (count == 20000)\n            {\n                if (coder.get_target(8000) != 1500)\n                {\n                    throw decompression_error(\"Error detected in compressed data stream.\");\n                }\n                count = 0;\n                coder.decode(1500,1501);\n            }\n            ++count;\n\n            // decode the next symbol\n            model.decode(symbol);\n            if (symbol != eof_symbol)\n            {\n                crc.add(static_cast<unsigned char>(symbol));\n                // write this symbol to out\n                if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))\n                {\n                    throw std::ios::failure(\"error occurred in compress_stream_kernel_1::decompress\");\n                }\n                continue;\n            }\n            else\n            {\n                // we read eof from the encoded data.  now we just have to check the checksum and we are done.\n                unsigned char byte1;\n                unsigned char byte2;\n                unsigned char byte3;\n                unsigned char byte4;\n\n                model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);\n                model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);\n                model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);\n                model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);\n\n                unsigned long checksum = byte1;\n                checksum <<= 8;\n                checksum |= byte2;\n                checksum <<= 8;\n                checksum |= byte3;\n                checksum <<= 8;\n                checksum |= byte4;\n\n                if (checksum != crc.get_checksum())\n                    throw decompression_error(\"Error detected in compressed data stream.\");\n\n                break;\n            }\n        } // while (true)\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_COMPRESS_STREAM_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/compress_stream/compress_stream_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_COMPRESS_STREAM_KERNEl_2_\n#define DLIB_COMPRESS_STREAM_KERNEl_2_\n\n#include \"../algs.h\"\n#include <iostream>\n#include <streambuf>\n#include \"compress_stream_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename fce,\n        typename fcd,\n        typename lz77_buffer,\n        typename sliding_buffer,\n        typename fce_length,\n        typename fcd_length,\n        typename fce_index,\n        typename fcd_index,\n        typename crc32\n        >\n    class compress_stream_kernel_2\n    {\n        /*!\n            REQUIREMENTS ON fce\n                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h\n                the alphabet_size of fce must be 257.\n                fce and fcd share the same kernel number.\n\n            REQUIREMENTS ON fcd\n                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h\n                the alphabet_size of fcd must be 257.\n                fce and fcd share the same kernel number.\n\n            REQUIREMENTS ON lz77_buffer\n                is an implementation of lz77_buffer/lz77_buffer_kernel_abstract.h\n\n            REQUIREMENTS ON sliding_buffer\n                is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h\n                is instantiated with T = unsigned char\n\n            REQUIREMENTS ON fce_length\n                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h\n                the alphabet_size of fce must be 513.  This will be used to encode the length of lz77 matches.\n                fce_length and fcd share the same kernel number.\n\n            REQUIREMENTS ON fcd_length\n                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h\n                the alphabet_size of fcd must be 513.  This will be used to decode the length of lz77 matches.\n                fce_length and fcd share the same kernel number.\n\n            REQUIREMENTS ON fce_index\n                is an implementation of entropy_encoder_model/entropy_encoder_model_kernel_abstract.h\n                the alphabet_size of fce must be 32257.  This will be used to encode the index of lz77 matches.\n                fce_index and fcd share the same kernel number.\n\n            REQUIREMENTS ON fcd_index\n                is an implementation of entropy_decoder_model/entropy_decoder_model_kernel_abstract.h\n                the alphabet_size of fcd must be 32257.  This will be used to decode the index of lz77 matches.\n                fce_index and fcd share the same kernel number.\n\n            REQUIREMENTS ON crc32\n                is an implementation of crc32/crc32_kernel_abstract.h\n\n            INITIAL VALUE\n                this object has no state\n\n            CONVENTION\n                this object has no state\n        !*/\n\n        const static unsigned long eof_symbol = 256;\n\n    public:\n\n        class decompression_error : public dlib::error \n        { \n            public: \n                decompression_error(\n                    const char* i\n                ) :\n                    dlib::error(std::string(i))\n                {}\n\n                decompression_error(\n                    const std::string& i\n                ) :\n                    dlib::error(i)\n                {}\n        };\n\n\n        compress_stream_kernel_2 (\n        )\n        {}\n\n        ~compress_stream_kernel_2 (\n        )\n        {}\n\n        void compress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n        void decompress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n    private:\n\n        // restricted functions\n        compress_stream_kernel_2(compress_stream_kernel_2&);        // copy constructor\n        compress_stream_kernel_2& operator=(compress_stream_kernel_2&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename fce,\n        typename fcd,\n        typename lz77_buffer,\n        typename sliding_buffer,\n        typename fce_length,\n        typename fcd_length,\n        typename fce_index,\n        typename fcd_index,\n        typename crc32\n        >\n    void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::\n    compress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n        std::streambuf::int_type temp;\n\n        std::streambuf& in = *in_.rdbuf();\n\n        typename fce::entropy_encoder_type coder;\n        coder.set_stream(out_);\n\n        fce model(coder);\n        fce_length model_length(coder);\n        fce_index model_index(coder);\n\n        const unsigned long LOOKAHEAD_LIMIT = 512; \n        lz77_buffer buffer(15,LOOKAHEAD_LIMIT);\n        \n        crc32 crc;\n      \n\n        unsigned long count = 0;\n\n        unsigned long lz77_count = 1;  // number of times we used lz77 to encode\n        unsigned long ppm_count = 1;   // number of times we used ppm to encode\n\n\n        while (true)\n        {\n            // write out a known value every 20000 symbols\n            if (count == 20000)\n            {\n                count = 0;\n                coder.encode(150,151,400);\n            }\n            ++count;\n\n            // try to fill the lookahead buffer\n            if (buffer.get_lookahead_buffer_size() < buffer.get_lookahead_buffer_limit())\n            {\n                temp = in.sbumpc();\n                while (temp != EOF)\n                {\n                    crc.add(static_cast<unsigned char>(temp));\n                    buffer.add(static_cast<unsigned char>(temp));\n                    if (buffer.get_lookahead_buffer_size() == buffer.get_lookahead_buffer_limit())\n                        break;\n                    temp = in.sbumpc();\n                }\n            }\n\n            // compute the sum of ppm_count and lz77_count but make sure\n            // it is less than 65536\n            unsigned long sum = ppm_count + lz77_count;\n            if (sum >= 65536)\n            {\n                ppm_count >>= 1;                    \n                lz77_count >>= 1;\n                ppm_count |= 1;\n                lz77_count |= 1;\n                sum = ppm_count+lz77_count;                    \n            }\n\n            // if there are still more symbols in the lookahead buffer to encode\n            if (buffer.get_lookahead_buffer_size() > 0)  \n            {\n                unsigned long match_index, match_length;\n                buffer.find_match(match_index,match_length,6);\n                if (match_length != 0)\n                {\n                  \n                    // signal the decoder that we are using lz77\n                    coder.encode(0,lz77_count,sum);\n                    ++lz77_count;\n                    \n                    // encode the index and length pair\n                    model_index.encode(match_index);                   \n                    model_length.encode(match_length);                   \n\n                }\n                else\n                {\n\n                    // signal the decoder that we are using ppm \n                    coder.encode(lz77_count,sum,sum);\n                    ++ppm_count;\n\n                    // encode the symbol using the ppm model\n                    model.encode(buffer.lookahead_buffer(0));\n                    buffer.shift_buffers(1);                    \n                }\n            }\n            else\n            {\n                // signal the decoder that we are using ppm \n                coder.encode(lz77_count,sum,sum);\n                \n\n                model.encode(eof_symbol);\n                // now write the checksum\n                unsigned long checksum = crc.get_checksum();\n                unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);\n                unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);\n                unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);\n                unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);\n\n                model.encode(byte1);\n                model.encode(byte2);\n                model.encode(byte3);\n                model.encode(byte4);\n\n                break;      \n            }\n        } // while (true)        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename fce,\n        typename fcd,\n        typename lz77_buffer,\n        typename sliding_buffer,\n        typename fce_length,\n        typename fcd_length,\n        typename fce_index,\n        typename fcd_index,\n        typename crc32\n        >\n    void compress_stream_kernel_2<fce,fcd,lz77_buffer,sliding_buffer,fce_length,fcd_length,fce_index,fcd_index,crc32>::\n    decompress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n\n        std::streambuf& out = *out_.rdbuf();\n\n        typename fcd::entropy_decoder_type coder;\n        coder.set_stream(in_);\n\n        fcd model(coder);\n        fcd_length model_length(coder);\n        fcd_index model_index(coder);\n\n        unsigned long symbol;\n        unsigned long count = 0;\n\n        sliding_buffer buffer;\n        buffer.set_size(15);\n\n        // Initialize the buffer to all zeros.  There is no algorithmic reason to\n        // do this.  But doing so avoids a warning from valgrind so that is why\n        // I'm doing this.\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n              buffer[i] = 0;\n\n        crc32 crc;\n        \n        unsigned long lz77_count = 1;  // number of times we used lz77 to encode\n        unsigned long ppm_count = 1;   // number of times we used ppm to encode\n        bool next_block_lz77;\n\n\n        // decode until we hit the marker symbol\n        while (true)\n        {\n            // make sure this is the value we expect\n            if (count == 20000)\n            {\n                if (coder.get_target(400) != 150)\n                {\n                    throw decompression_error(\"Error detected in compressed data stream.\");\n                }\n                count = 0;\n                coder.decode(150,151);\n            }\n            ++count;\n\n\n            // compute the sum of ppm_count and lz77_count but make sure\n            // it is less than 65536\n            unsigned long sum = ppm_count + lz77_count;\n            if (sum >= 65536)\n            {\n                ppm_count >>= 1;                    \n                lz77_count >>= 1;\n                ppm_count |= 1;\n                lz77_count |= 1;\n                sum = ppm_count+lz77_count;                    \n            }\n\n            // check if we are decoding a lz77 or ppm block\n            if (coder.get_target(sum) < lz77_count)\n            {\n                coder.decode(0,lz77_count);\n                next_block_lz77 = true;\n                ++lz77_count;\n            }\n            else\n            {\n                coder.decode(lz77_count,sum);\n                next_block_lz77 = false;\n                ++ppm_count;\n            }\n\n\n            if (next_block_lz77)\n            {\n                \n                unsigned long match_length, match_index;\n                // decode the match index\n                model_index.decode(match_index);\n\n                // decode the match length\n                model_length.decode(match_length);\n\n                \n                match_index += match_length;\n                buffer.rotate_left(match_length);\n                for (unsigned long i = 0; i < match_length; ++i)\n                {\n                    unsigned char ch = buffer[match_index-i];\n                    buffer[match_length-i-1] = ch;\n\n                    crc.add(ch);\n                    // write this ch to out\n                    if (out.sputc(static_cast<char>(ch)) != static_cast<int>(ch))\n                    {\n                        throw std::ios::failure(\"error occurred in compress_stream_kernel_2::decompress\");\n                    }\n                }\n                \n            }\n            else\n            {\n\n                // decode the next symbol\n                model.decode(symbol);\n                if (symbol != eof_symbol)\n                {\n                    buffer.rotate_left(1);\n                    buffer[0] = static_cast<unsigned char>(symbol);\n                    \n\n                    crc.add(static_cast<unsigned char>(symbol));\n                    // write this symbol to out\n                    if (out.sputc(static_cast<char>(symbol)) != static_cast<int>(symbol))\n                    {\n                        throw std::ios::failure(\"error occurred in compress_stream_kernel_2::decompress\");\n                    }\n                }\n                else\n                {\n                    // this was the eof marker symbol so we are done.  now check the checksum\n\n                    // now get the checksum and make sure it matches\n                    unsigned char byte1;\n                    unsigned char byte2;\n                    unsigned char byte3;\n                    unsigned char byte4;\n\n                    model.decode(symbol); byte1 = static_cast<unsigned char>(symbol);\n                    model.decode(symbol); byte2 = static_cast<unsigned char>(symbol);\n                    model.decode(symbol); byte3 = static_cast<unsigned char>(symbol);\n                    model.decode(symbol); byte4 = static_cast<unsigned char>(symbol);\n\n                    unsigned long checksum = byte1;\n                    checksum <<= 8;\n                    checksum |= byte2;\n                    checksum <<= 8;\n                    checksum |= byte3;\n                    checksum <<= 8;\n                    checksum |= byte4;\n\n                    if (checksum != crc.get_checksum())\n                        throw decompression_error(\"Error detected in compressed data stream.\");\n\n                    break;\n                }\n            }\n\n        } // while (true)\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_COMPRESS_STREAM_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/compress_stream/compress_stream_kernel_3.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_COMPRESS_STREAM_KERNEl_3_\n#define DLIB_COMPRESS_STREAM_KERNEl_3_\n\n#include \"../algs.h\"\n#include \"compress_stream_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename lzp_buf,\n        typename crc32,\n        unsigned long buffer_size\n        >\n    class compress_stream_kernel_3\n    {\n        /*!\n            REQUIREMENTS ON lzp_buf\n                is an implementation of lzp_buffer/lzp_buffer_kernel_abstract.h\n\n            REQUIREMENTS ON buffer_size\n                10 < buffer_size < 32\n\n            REQUIREMENTS ON crc32\n                is an implementation of crc32/crc32_kernel_abstract.h\n\n\n            INITIAL VALUE\n                this object has no state\n\n            CONVENTION\n                this object has no state\n\n\n                This implementation uses the lzp_buffer and writes out matches\n                in a byte aligned format.\n\n        !*/\n\n\n    public:\n\n        class decompression_error : public dlib::error \n        { \n            public: \n                decompression_error(\n                    const char* i\n                ) :\n                    dlib::error(std::string(i))\n                {}\n\n                decompression_error(\n                    const std::string& i\n                ) :\n                    dlib::error(i)\n                {}\n        };\n\n\n        compress_stream_kernel_3 (\n        )\n        {\n            COMPILE_TIME_ASSERT(10 < buffer_size && buffer_size < 32);\n        }\n\n        ~compress_stream_kernel_3 (\n        )\n        {}\n\n        void compress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n        void decompress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n\n\n\n    private:\n\n        inline void write (\n            unsigned char symbol\n        ) const\n        { \n            if (out->sputn(reinterpret_cast<char*>(&symbol),1)==0)\n                throw std::ios_base::failure(\"error writing to output stream in compress_stream_kernel_3\");        \n        }\n\n        inline void decode (\n            unsigned char& symbol,\n            unsigned char& flag\n        ) const\n        { \n            if (count == 0)\n            {\n                if (((size_t)in->sgetn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))\n                    throw decompression_error(\"Error detected in compressed data stream.\");\n                count = 8;\n            }\n            --count;\n            symbol = buffer[8-count];\n            flag = buffer[0] >> 7; \n            buffer[0] <<= 1;\n        }\n\n        inline void encode (\n            unsigned char symbol,\n            unsigned char flag\n        ) const\n        /*!\n            requires\n                - 0 <= flag <= 1\n            ensures\n                - writes symbol with the given one bit flag\n        !*/\n        { \n            // add this symbol and flag to the buffer            \n            ++count;\n            buffer[0] <<= 1;\n            buffer[count] = symbol;\n            buffer[0] |= flag;\n\n            if (count == 8)\n            {\n                if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))\n                    throw std::ios_base::failure(\"error writing to output stream in compress_stream_kernel_3\");        \n                count = 0;\n                buffer[0] = 0;\n            }\n        }\n\n        void clear (\n        ) const\n        /*!\n            ensures\n                - resets the buffers\n        !*/\n        {\n            count = 0;\n        }\n\n        void flush (\n        ) const\n        /*!\n            ensures\n                - flushes any data in the buffers to out\n        !*/\n        {\n            if (count != 0)\n            {\n                buffer[0] <<= (8-count);\n                if (((size_t)out->sputn(reinterpret_cast<char*>(buffer),sizeof(buffer)))!=sizeof(buffer))\n                    throw std::ios_base::failure(\"error writing to output stream in compress_stream_kernel_3\");        \n            }\n        }\n\n        mutable unsigned int count;\n        // count tells us how many bytes are buffered in buffer and how many flag\n        // bit are currently in buffer[0]\n        mutable unsigned char buffer[9];  \n        // buffer[0] holds the flag bits to be writen.\n        // the rest of the buffer holds the bytes to be writen.\n\n        mutable std::streambuf* in;\n        mutable std::streambuf* out;\n\n        // restricted functions\n        compress_stream_kernel_3(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&);        // copy constructor\n        compress_stream_kernel_3<lzp_buf,crc32,buffer_size>& operator=(compress_stream_kernel_3<lzp_buf,crc32,buffer_size>&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lzp_buf,\n        typename crc32,\n        unsigned long buffer_size\n        >\n    void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::\n    compress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    {\n        in = in_.rdbuf();\n        out = out_.rdbuf();\n        clear();\n\n        crc32 crc;\n     \n        lzp_buf buffer(buffer_size);\n\n        std::streambuf::int_type temp = in->sbumpc();\n        unsigned long index;\n        unsigned char symbol;\n        unsigned char length;\n\n        while (temp != EOF)\n        {\n            symbol = static_cast<unsigned char>(temp);\n            if (buffer.predict_match(index))\n            {\n                if (buffer[index] == symbol)\n                {\n                    // this is a match so we must find out how long it is\n                    length = 1;\n                                        \n                    buffer.add(symbol);\n                    crc.add(symbol);\n\n                    temp = in->sbumpc();\n                    while (length < 255)\n                    {\n                        if (temp == EOF)\n                        {                          \n                            break;\n                        }\n                        else if (static_cast<unsigned long>(length) >= index)\n                        {\n                            break;\n                        }\n                        else if (static_cast<unsigned char>(temp) == buffer[index])\n                        {\n                            ++length;\n                            buffer.add(static_cast<unsigned char>(temp));\n                            crc.add(static_cast<unsigned char>(temp));\n                            temp = in->sbumpc();\n                        }\n                        else\n                        {\n                            break;\n                        }\n                    }                        \n\n                    encode(length,1);\n                }\n                else\n                {\n                    // this is also not a match\n                    encode(symbol,0);\n                    buffer.add(symbol);\n                    crc.add(symbol);\n\n                    // get the next symbol\n                    temp = in->sbumpc();\n                }\n            }\n            else\n            {\n                // there wasn't a match so just write this symbol\n                encode(symbol,0);\n                buffer.add(symbol);\n                crc.add(symbol);\n\n                // get the next symbol\n                temp = in->sbumpc();\n            }\n        }\n\n        // use a match of zero length to indicate EOF\n        encode(0,1);\n\n        // now write the checksum\n        unsigned long checksum = crc.get_checksum();\n        unsigned char byte1 = static_cast<unsigned char>((checksum>>24)&0xFF);\n        unsigned char byte2 = static_cast<unsigned char>((checksum>>16)&0xFF);\n        unsigned char byte3 = static_cast<unsigned char>((checksum>>8)&0xFF);\n        unsigned char byte4 = static_cast<unsigned char>((checksum)&0xFF);\n\n        encode(byte1,0);\n        encode(byte2,0);\n        encode(byte3,0);\n        encode(byte4,0);\n\n        flush();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lzp_buf,\n        typename crc32,\n        unsigned long buffer_size\n        >\n    void compress_stream_kernel_3<lzp_buf,crc32,buffer_size>::\n    decompress (\n        std::istream& in_,\n        std::ostream& out_\n    ) const\n    { \n        in = in_.rdbuf();\n        out = out_.rdbuf();\n        clear();\n     \n        crc32 crc;\n\n        lzp_buf buffer(buffer_size);\n\n\n        unsigned long index = 0;\n        unsigned char symbol;\n        unsigned char length;\n        unsigned char flag;\n\n        decode(symbol,flag);\n        while (flag == 0 || symbol != 0)\n        {\n            buffer.predict_match(index);\n\n            if (flag == 1)\n            {\n                length = symbol;\n                do \n                {\n                    --length;\n                    symbol = buffer[index];\n                    write(symbol);\n                    buffer.add(symbol);   \n                    crc.add(symbol);                    \n                } while (length != 0);\n            }\n            else\n            {\n                // this is just a literal\n                write(symbol);\n                buffer.add(symbol);\n                crc.add(symbol);\n            }\n            decode(symbol,flag);\n        }\n\n\n        // now get the checksum and make sure it matches\n        unsigned char byte1;\n        unsigned char byte2;\n        unsigned char byte3;\n        unsigned char byte4;\n\n        decode(byte1,flag);\n        if (flag != 0)\n            throw decompression_error(\"Error detected in compressed data stream.\");\n        decode(byte2,flag);\n        if (flag != 0)\n            throw decompression_error(\"Error detected in compressed data stream.\");\n        decode(byte3,flag);\n        if (flag != 0)\n            throw decompression_error(\"Error detected in compressed data stream.\");\n        decode(byte4,flag);\n        if (flag != 0)\n            throw decompression_error(\"Error detected in compressed data stream.\");\n\n        unsigned long checksum = byte1;\n        checksum <<= 8;\n        checksum |= byte2;\n        checksum <<= 8;\n        checksum |= byte3;\n        checksum <<= 8;\n        checksum |= byte4;\n\n        if (checksum != crc.get_checksum())\n            throw decompression_error(\"Error detected in compressed data stream.\");\n \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_COMPRESS_STREAM_KERNEl_3_\n\n"
  },
  {
    "path": "dlib/compress_stream/compress_stream_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_\n#ifdef DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class compress_stream \n    {\n        /*!\n            INITIAL VALUE\n                This object does not have any state associated with it.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object consists of the two functions compress and decompress.\n                These functions allow you to compress and decompress data.\n        !*/\n\n    public:\n\n        class decompression_error : public dlib::error {};\n\n        compress_stream (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~compress_stream (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n\n        void compress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - reads all data from in (until EOF is reached) and compresses it\n                  and writes it to out\n            throws\n                - std::ios_base::failure\n                    if there was a problem writing to out then this exception will \n                    be thrown.                      \n                - any other exception\n                    this exception may be thrown if there is any other problem                    \n        !*/\n\n\n        void decompress (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - reads data from in, decompresses it and writes it to out.  note that\n                  it stops reading data from in when it encounters the end of the \n                  compressed data, not when it encounters EOF. \n            throws\n                - std::ios_base::failure\n                    if there was a problem writing to out then this exception will \n                    be thrown.           \n                - decompression_error\n                    if an error was detected in the compressed data that prevented\n                    it from being correctly decompressed then this exception is \n                    thrown.  \n                - any other exception\n                    this exception may be thrown if there is any other problem                    \n        !*/\n\n\n    private:\n\n        // restricted functions\n        compress_stream(compress_stream&);        // copy constructor\n        compress_stream& operator=(compress_stream&);    // assignment operator\n\n    };   \n   \n}\n\n#endif // DLIB_COMPRESS_STREAM_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/compress_stream.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_COMPRESS_STREAm_\n#define DLIB_COMPRESS_STREAm_\n\n#include \"compress_stream/compress_stream_kernel_1.h\"\n#include \"compress_stream/compress_stream_kernel_2.h\"\n#include \"compress_stream/compress_stream_kernel_3.h\"\n\n#include \"conditioning_class.h\"\n#include \"entropy_encoder.h\"\n#include \"entropy_decoder.h\"\n\n#include \"entropy_encoder_model.h\"\n#include \"entropy_decoder_model.h\"\n#include \"lz77_buffer.h\"\n#include \"sliding_buffer.h\"\n#include \"lzp_buffer.h\"\n#include \"crc32.h\"\n\n\nnamespace dlib\n{\n\n    class compress_stream\n    {\n        compress_stream() {}\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_1b fce1;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_1b fcd1;\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2b fce2;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2b fcd2;\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_3b fce3;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_3b fcd3;\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4a fce4a;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4a fcd4a;\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_4b fce4b;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_4b fcd4b;\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5a fce5a;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5a fcd5a;\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5b fce5b;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5b fcd5b;\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_5c fce5c;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_5c fcd5c;\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_6a fce6;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_6a fcd6;\n\n\n        typedef entropy_encoder_model<257,entropy_encoder::kernel_2a>::kernel_2d fce2d;\n        typedef entropy_decoder_model<257,entropy_decoder::kernel_2a>::kernel_2d fcd2d;\n\n        typedef sliding_buffer<unsigned char>::kernel_1a sliding_buffer1;\n        typedef lz77_buffer::kernel_2a lz77_buffer2a;\n\n\n        typedef lzp_buffer::kernel_1a lzp_buf_1;\n        typedef lzp_buffer::kernel_2a lzp_buf_2;\n\n\n        typedef entropy_encoder_model<513,entropy_encoder::kernel_2a>::kernel_1b fce_length;\n        typedef entropy_decoder_model<513,entropy_decoder::kernel_2a>::kernel_1b fcd_length;\n\n        typedef entropy_encoder_model<65534,entropy_encoder::kernel_2a>::kernel_1b fce_length_2;\n        typedef entropy_decoder_model<65534,entropy_decoder::kernel_2a>::kernel_1b fcd_length_2;\n\n\n        typedef entropy_encoder_model<32257,entropy_encoder::kernel_2a>::kernel_1b fce_index;\n        typedef entropy_decoder_model<32257,entropy_decoder::kernel_2a>::kernel_1b fcd_index;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef      compress_stream_kernel_1 <fce1,fcd1,crc32::kernel_1a>\n                     kernel_1a;\n   \n        // kernel_1b        \n        typedef      compress_stream_kernel_1 <fce2,fcd2,crc32::kernel_1a>\n                     kernel_1b;\n\n        // kernel_1c        \n        typedef      compress_stream_kernel_1 <fce3,fcd3,crc32::kernel_1a>\n                     kernel_1c;\n\n        // kernel_1da        \n        typedef      compress_stream_kernel_1 <fce4a,fcd4a,crc32::kernel_1a>\n                     kernel_1da;\n\n        // kernel_1ea        \n        typedef      compress_stream_kernel_1 <fce5a,fcd5a,crc32::kernel_1a>\n                     kernel_1ea;\n\n        // kernel_1db        \n        typedef      compress_stream_kernel_1 <fce4b,fcd4b,crc32::kernel_1a>\n                     kernel_1db;\n\n        // kernel_1eb        \n        typedef      compress_stream_kernel_1 <fce5b,fcd5b,crc32::kernel_1a>\n                     kernel_1eb;\n\n        // kernel_1ec        \n        typedef      compress_stream_kernel_1 <fce5c,fcd5c,crc32::kernel_1a>\n                     kernel_1ec;\n\n\n\n\n        // kernel_2a        \n        typedef      compress_stream_kernel_2 <fce2,fcd2,lz77_buffer2a,sliding_buffer1,fce_length,fcd_length,fce_index,fcd_index,crc32::kernel_1a>\n                     kernel_2a;\n\n\n\n\n        // kernel_3a        \n        typedef      compress_stream_kernel_3 <lzp_buf_1,crc32::kernel_1a,16>\n                     kernel_3a;\n        // kernel_3b        \n        typedef      compress_stream_kernel_3 <lzp_buf_2,crc32::kernel_1a,16>\n                     kernel_3b;\n   \n\n    };\n}\n\n#endif // DLIB_COMPRESS_STREAm_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASS_KERNEl_1_\n#define DLIB_CONDITIONING_CLASS_KERNEl_1_\n\n#include \"conditioning_class_kernel_abstract.h\"\n#include \"../assert.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size\n        >\n    class conditioning_class_kernel_1 \n    {\n        /*!\n            INITIAL VALUE\n                total == 1\n                counts == pointer to an array of alphabet_size unsigned shorts\n                for all i except i == alphabet_size-1: counts[i] == 0\n                counts[alphabet_size-1] == 1\n\n            CONVENTION\n                counts == pointer to an array of alphabet_size unsigned shorts\n                get_total() == total\n                get_count(symbol) == counts[symbol]\n\n                LOW_COUNT(symbol) == sum of counts[0] though counts[symbol-1]\n                                     or 0 if symbol == 0\n\n                get_memory_usage() == global_state.memory_usage\n        !*/\n\n    public:\n\n        class global_state_type\n        {\n        public:\n            global_state_type () : memory_usage(0) {}\n        private:\n            unsigned long memory_usage;\n\n            friend class conditioning_class_kernel_1<alphabet_size>;\n        };\n\n        conditioning_class_kernel_1 (\n            global_state_type& global_state_\n        );\n\n        ~conditioning_class_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n\n        unsigned long get_total (\n        ) const;\n        \n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n\n        unsigned long get_memory_usage (\n        ) const;\n\n        global_state_type& get_global_state (\n        );\n\n        static unsigned long get_alphabet_size (\n        );\n\n\n    private:\n\n        // restricted functions\n        conditioning_class_kernel_1(conditioning_class_kernel_1<alphabet_size>&);        // copy constructor\n        conditioning_class_kernel_1& operator=(conditioning_class_kernel_1<alphabet_size>&);    // assignment operator\n\n        // data members\n        unsigned short total;\n        unsigned short* counts;\n        global_state_type& global_state;\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_1<alphabet_size>::\n    conditioning_class_kernel_1 (\n        global_state_type& global_state_\n    ) :\n        total(1),\n        counts(new unsigned short[alphabet_size]),\n        global_state(global_state_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );\n\n        unsigned short* start = counts;\n        unsigned short* end = counts+alphabet_size-1;\n        while (start != end)\n        {\n            *start = 0;\n            ++start;\n        }\n        *start = 1;\n\n        // update memory usage\n        global_state.memory_usage += sizeof(unsigned short)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_1<alphabet_size>::\n    ~conditioning_class_kernel_1 (\n    )\n    {\n        delete [] counts;\n        // update memory usage\n        global_state.memory_usage -= sizeof(unsigned short)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_1<alphabet_size>::\n    clear(\n    )\n    {\n        total = 1;\n        unsigned short* start = counts;\n        unsigned short* end = counts+alphabet_size-1;\n        while (start != end)\n        {\n            *start = 0;\n            ++start;\n        }\n        *start = 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_1<alphabet_size>::\n    get_memory_usage(\n    ) const\n    {\n        return global_state.memory_usage;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    typename conditioning_class_kernel_1<alphabet_size>::global_state_type& conditioning_class_kernel_1<alphabet_size>::\n    get_global_state(\n    )\n    {\n        return global_state;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    bool conditioning_class_kernel_1<alphabet_size>::\n    increment_count (\n        unsigned long symbol,\n        unsigned short amount\n    )\n    {        \n        // if we are going over a total of 65535 then scale down all counts by 2\n        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)\n        {\n            total = 0;\n            unsigned short* start = counts;\n            unsigned short* end = counts+alphabet_size;\n            while (start != end)\n            {\n                *start >>= 1;\n                total += *start;\n                ++start;\n            }    \n            // make sure it is at least one\n            if (counts[alphabet_size-1]==0)\n            {\n                ++total;\n                counts[alphabet_size-1] = 1;\n            }\n        }\n        counts[symbol] += amount;\n        total += amount;\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_1<alphabet_size>::\n    get_count (\n        unsigned long symbol\n    ) const\n    {\n        return counts[symbol];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_1<alphabet_size>::\n    get_alphabet_size (        \n    ) \n    {\n        return alphabet_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_1<alphabet_size>::\n    get_total (\n    ) const\n    {\n        return total;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_1<alphabet_size>::\n    get_range (\n        unsigned long symbol,\n        unsigned long& low_count,\n        unsigned long& high_count,\n        unsigned long& total_count\n    ) const\n    {\n        if (counts[symbol] == 0)\n            return 0;\n\n        total_count = total;\n        \n        const unsigned short* start = counts;\n        const unsigned short* end = counts+symbol;\n        unsigned short high_count_temp = *start;\n        while (start != end)\n        {\n            ++start;\n            high_count_temp += *start;            \n        }  \n        low_count = high_count_temp - *start;\n        high_count = high_count_temp;\n        return *start;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_1<alphabet_size>::\n    get_symbol (\n        unsigned long target,\n        unsigned long& symbol,            \n        unsigned long& low_count,\n        unsigned long& high_count\n    ) const\n    {\n        unsigned long high_count_temp = *counts;\n        const unsigned short* start = counts;        \n        while (target >= high_count_temp)\n        {\n            ++start;\n            high_count_temp += *start;            \n        } \n\n        low_count = high_count_temp - *start;\n        high_count = high_count_temp;\n        symbol = static_cast<unsigned long>(start-counts);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASS_KERNEl_2_\n#define DLIB_CONDITIONING_CLASS_KERNEl_2_\n\n#include \"conditioning_class_kernel_abstract.h\"\n#include \"../assert.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size\n        >\n    class conditioning_class_kernel_2 \n    {\n        /*!\n            INITIAL VALUE\n                total == 1\n                symbols == pointer to array of alphabet_size data structs\n                for all i except i == alphabet_size-1: symbols[i].count == 0\n                                                       symbols[i].left_count == 0\n\n                symbols[alphabet_size-1].count == 1\n                symbols[alpahbet_size-1].left_count == 0\n\n            CONVENTION\n                symbols == pointer to array of alphabet_size data structs\n                get_total() == total\n                get_count(symbol) == symbols[symbol].count\n\n                symbols is organized as a tree with symbols[0] as the root.\n\n                the left subchild of symbols[i] is symbols[i*2+1] and\n                the right subchild is symbols[i*2+2].\n                the partent of symbols[i] == symbols[(i-1)/2]\n\n                symbols[i].left_count == the sum of the counts of all the\n                                         symbols to the left of symbols[i]\n\n                get_memory_usage() == global_state.memory_usage                                         \n        !*/\n\n    public:\n\n        class global_state_type\n        {\n        public:\n            global_state_type () : memory_usage(0) {}\n        private:\n            unsigned long memory_usage;\n\n            friend class conditioning_class_kernel_2<alphabet_size>;\n        };\n\n        conditioning_class_kernel_2 (\n            global_state_type& global_state_\n        );\n\n        ~conditioning_class_kernel_2 (\n        );\n\n        void clear(\n        );\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n\n        inline unsigned long get_total (\n        ) const;\n        \n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n\n        unsigned long get_memory_usage (\n        ) const;\n\n        global_state_type& get_global_state (\n        );\n\n        static unsigned long get_alphabet_size (\n        );\n\n    private:\n\n        // restricted functions\n        conditioning_class_kernel_2(conditioning_class_kernel_2<alphabet_size>&);        // copy constructor\n        conditioning_class_kernel_2& operator=(conditioning_class_kernel_2<alphabet_size>&);    // assignment operator\n\n        // data members\n        unsigned short total;\n        struct data\n        {\n            unsigned short count;\n            unsigned short left_count;\n        };\n\n        data* symbols;\n        global_state_type& global_state;\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_2<alphabet_size>::\n    conditioning_class_kernel_2 (\n        global_state_type& global_state_\n    ) :\n        total(1),\n        symbols(new data[alphabet_size]),\n        global_state(global_state_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );\n\n        data* start = symbols;\n        data* end = symbols + alphabet_size-1;\n        \n        while (start != end)\n        {            \n            start->count = 0;            \n            start->left_count = 0;\n            ++start;\n        }\n\n        start->count = 1;\n        start->left_count = 0;\n\n\n        // update the left_counts for the symbol alphabet_size-1\n        unsigned short temp;\n        unsigned long symbol = alphabet_size-1;\n        while (symbol != 0)\n        {\n            // temp will be 1 if symbol is odd, 0 if it is even\n            temp = static_cast<unsigned short>(symbol&0x1);\n\n            // set symbol to its parent\n            symbol = (symbol-1)>>1;\n            \n            // note that all left subchidren are odd and also that \n            // if symbol was a left subchild then we want to increment\n            // its parents left_count \n            if (temp)\n                ++symbols[symbol].left_count;\n        }\n\n        global_state.memory_usage += sizeof(data)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_2<alphabet_size>::\n    ~conditioning_class_kernel_2 (\n    )\n    {\n        delete [] symbols;\n        global_state.memory_usage -= sizeof(data)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_2<alphabet_size>::\n    clear(\n    )\n    {\n        data* start = symbols;\n        data* end = symbols + alphabet_size-1;\n        \n        total = 1;\n\n        while (start != end)\n        {            \n            start->count = 0;            \n            start->left_count = 0;\n            ++start;\n        }\n\n        start->count = 1;\n        start->left_count = 0;\n\n        // update the left_counts \n        unsigned short temp;\n        unsigned long symbol = alphabet_size-1;\n        while (symbol != 0)\n        {\n            // temp will be 1 if symbol is odd, 0 if it is even\n            temp = static_cast<unsigned short>(symbol&0x1);\n\n            // set symbol to its parent\n            symbol = (symbol-1)>>1;\n            \n            // note that all left subchidren are odd and also that \n            // if symbol was a left subchild then we want to increment\n            // its parents left_count \n            symbols[symbol].left_count += temp;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_2<alphabet_size>::\n    get_memory_usage(\n    ) const\n    {\n        return global_state.memory_usage;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    typename conditioning_class_kernel_2<alphabet_size>::global_state_type& conditioning_class_kernel_2<alphabet_size>::\n    get_global_state(\n    )\n    {\n        return global_state;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    bool conditioning_class_kernel_2<alphabet_size>::\n    increment_count (\n        unsigned long symbol,\n        unsigned short amount\n    )\n    {        \n        // if we need to renormalize then do so\n        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)\n        {\n            unsigned long s;\n            unsigned short temp;\n            for (unsigned short i = 0; i < alphabet_size-1; ++i)\n            {\n                s = i;\n\n                // divide the count for this symbol by 2                \n                symbols[i].count >>= 1;\n                \n                symbols[i].left_count = 0;\n\n                // bubble this change up though the tree                \n                while (s != 0)\n                {\n                    // temp will be 1 if symbol is odd, 0 if it is even\n                    temp = static_cast<unsigned short>(s&0x1);\n\n                    // set s to its parent\n                    s = (s-1)>>1;\n                    \n                    // note that all left subchidren are odd and also that \n                    // if s was a left subchild then we want to increment\n                    // its parents left_count \n                    if (temp)\n                        symbols[s].left_count += symbols[i].count;\n                }   \n            }\n\n            // update symbols alphabet_size-1\n            {\n                s = alphabet_size-1;\n\n                // divide alphabet_size-1 symbol by 2 if it's > 1\n                if (symbols[alphabet_size-1].count > 1)\n                    symbols[alphabet_size-1].count >>= 1;\n                \n                // bubble this change up though the tree                \n                while (s != 0)\n                {\n                    // temp will be 1 if symbol is odd, 0 if it is even\n                    temp = static_cast<unsigned short>(s&0x1);\n\n                    // set s to its parent\n                    s = (s-1)>>1;\n                    \n                    // note that all left subchidren are odd and also that \n                    // if s was a left subchild then we want to increment\n                    // its parents left_count \n                    if (temp)\n                        symbols[s].left_count += symbols[alphabet_size-1].count;\n                }   \n            }        \n            \n\n\n\n\n\n            // calculate the new total\n            total = 0;\n            unsigned long m = 0;\n            while (m < alphabet_size)\n            {\n                total += symbols[m].count + symbols[m].left_count;\n                m = (m<<1) + 2;        \n            }\n            \n        }\n\n        \n\n\n        // increment the count for the specified symbol      \n        symbols[symbol].count += amount;;\n        total += amount;\n\n        \n        unsigned short temp;\n        while (symbol != 0)\n        {\n            // temp will be 1 if symbol is odd, 0 if it is even\n            temp = static_cast<unsigned short>(symbol&0x1);\n\n            // set symbol to its parent\n            symbol = (symbol-1)>>1;\n            \n            // note that all left subchidren are odd and also that \n            // if symbol was a left subchild then we want to increment\n            // its parents left_count \n            if (temp)\n                symbols[symbol].left_count += amount;\n        }\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_2<alphabet_size>::\n    get_count (\n        unsigned long symbol\n    ) const\n    {\n        return symbols[symbol].count;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_2<alphabet_size>::\n    get_alphabet_size (        \n    ) \n    {\n        return alphabet_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_2<alphabet_size>::\n    get_total (\n    ) const\n    {\n        return total;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_2<alphabet_size>::\n    get_range (\n        unsigned long symbol,\n        unsigned long& low_count,\n        unsigned long& high_count,\n        unsigned long& total_count\n    ) const\n    {\n        if (symbols[symbol].count == 0)\n            return 0;\n\n        unsigned long current = symbol;\n        total_count = total;\n        unsigned long high_count_temp = 0;\n        bool came_from_right = true;\n        while (true)\n        {                        \n            if (came_from_right)\n            {\n                high_count_temp += symbols[current].count + symbols[current].left_count;\n            }\n\n            // note that if current is even then it is a right child\n            came_from_right = !(current&0x1);\n\n            if (current == 0)\n                break;\n\n            // set current to its parent\n            current = (current-1)>>1 ;\n        }\n\n\n        low_count = high_count_temp - symbols[symbol].count;\n        high_count = high_count_temp;\n\n        return symbols[symbol].count;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_2<alphabet_size>::\n    get_symbol (\n        unsigned long target,\n        unsigned long& symbol,            \n        unsigned long& low_count,\n        unsigned long& high_count\n    ) const\n    {\n        unsigned long current = 0;\n        unsigned long low_count_temp = 0;\n        \n        while (true)\n        {\n            if (static_cast<unsigned short>(target) < symbols[current].left_count)\n            {\n                // we should go left\n                current = (current<<1) + 1;\n            }\n            else \n            {\n                target -= symbols[current].left_count;\n                low_count_temp += symbols[current].left_count;\n                if (static_cast<unsigned short>(target) < symbols[current].count)\n                {\n                    // we have found our target\n                    symbol = current;\n                    high_count = low_count_temp + symbols[current].count;\n                    low_count = low_count_temp;\n                    break;\n                }\n                else\n                {   \n                    // go right\n                    target -= symbols[current].count;\n                    low_count_temp += symbols[current].count;\n                    current = (current<<1) + 2;\n                }\n            }\n\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_3.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASS_KERNEl_3_\n#define DLIB_CONDITIONING_CLASS_KERNEl_3_\n\n#include \"conditioning_class_kernel_abstract.h\"\n#include \"../assert.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size\n        >\n    class conditioning_class_kernel_3 \n    {\n        /*!\n            INITIAL VALUE\n                total == 1\n                counts == pointer to an array of alphabet_size data structs                \n                for all i except i == 0: counts[i].count == 0\n                counts[0].count == 1\n                counts[0].symbol == alphabet_size-1\n                for all i except i == alphabet_size-1:  counts[i].present == false\n                counts[alphabet_size-1].present == true\n\n            CONVENTION\n                counts == pointer to an array of alphabet_size data structs\n                get_total() == total\n                get_count(symbol) == counts[x].count where \n                                     counts[x].symbol == symbol\n\n\n                LOW_COUNT(symbol) == sum of counts[0].count though counts[x-1].count\n                                     where counts[x].symbol == symbol\n                                     if (counts[0].symbol == symbol) LOW_COUNT(symbol)==0\n\n\n                if (counts[i].count == 0) then\n                    counts[i].symbol == undefined value\n\n                if (symbol has a nonzero count) then\n                    counts[symbol].present == true\n\n                get_memory_usage() == global_state.memory_usage\n        !*/\n\n    public:\n\n        class global_state_type\n        {\n        public:\n            global_state_type () : memory_usage(0) {}\n        private:\n            unsigned long memory_usage;\n\n            friend class conditioning_class_kernel_3<alphabet_size>;\n        };\n\n        conditioning_class_kernel_3 (\n            global_state_type& global_state_\n        );\n\n        ~conditioning_class_kernel_3 (\n        );\n\n        void clear(\n        );\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n\n        unsigned long get_total (\n        ) const;\n        \n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n\n        unsigned long get_memory_usage (\n        ) const;\n\n        global_state_type& get_global_state (\n        );\n\n        static unsigned long get_alphabet_size (\n        );\n\n    private:\n\n        // restricted functions\n        conditioning_class_kernel_3(conditioning_class_kernel_3<alphabet_size>&);        // copy constructor\n        conditioning_class_kernel_3& operator=(conditioning_class_kernel_3<alphabet_size>&);    // assignment operator\n\n        struct data\n        {\n            unsigned short count;\n            unsigned short symbol;\n            bool present;\n        };\n\n        // data members\n        unsigned short total;\n        data* counts;\n        global_state_type& global_state;\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_3<alphabet_size>::\n    conditioning_class_kernel_3 (\n        global_state_type& global_state_\n    ) :\n        total(1),\n        counts(new data[alphabet_size]),\n        global_state(global_state_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );\n\n        data* start = counts;\n        data* end = counts+alphabet_size;\n        start->count = 1;\n        start->symbol = alphabet_size-1;\n        start->present = false;\n        ++start;\n        while (start != end)\n        {\n            start->count = 0;\n            start->present = false;\n            ++start;\n        }        \n        counts[alphabet_size-1].present = true;\n\n        // update memory usage\n        global_state.memory_usage += sizeof(data)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_3);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    conditioning_class_kernel_3<alphabet_size>::\n    ~conditioning_class_kernel_3 (\n    )\n    {\n        delete [] counts;\n        // update memory usage\n        global_state.memory_usage -= sizeof(data)*alphabet_size + \n                                     sizeof(conditioning_class_kernel_3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_3<alphabet_size>::\n    clear(\n    )\n    {\n        total = 1;\n        data* start = counts;\n        data* end = counts+alphabet_size;\n        start->count = 1;\n        start->symbol = alphabet_size-1;\n        start->present = false;\n        ++start;\n        while (start != end)\n        {\n            start->count = 0;\n            start->present = false;\n            ++start;\n        }        \n        counts[alphabet_size-1].present = true; \n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    typename conditioning_class_kernel_3<alphabet_size>::global_state_type& conditioning_class_kernel_3<alphabet_size>::\n    get_global_state(\n    )\n    {\n        return global_state;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_3<alphabet_size>::\n    get_memory_usage(\n    ) const\n    {\n        return global_state.memory_usage;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    bool conditioning_class_kernel_3<alphabet_size>::\n    increment_count (\n        unsigned long symbol,\n        unsigned short amount\n    )\n    {        \n        // if we are going over a total of 65535 then scale down all counts by 2\n        if (static_cast<unsigned long>(total)+static_cast<unsigned long>(amount) >= 65536)\n        {\n            total = 0;\n            data* start = counts;\n            data* end = counts+alphabet_size;\n            \n            while (start != end)\n            {\n                if (start->count == 1)\n                {\n                    if (start->symbol == alphabet_size-1)\n                    {\n                        // this symbol must never be zero so we will leave its count at 1\n                        ++total;\n                    }\n                    else\n                    {\n                        start->count = 0;\n                        counts[start->symbol].present = false;\n                    }\n                }\n                else\n                {\n                    start->count >>= 1;\n                    total += start->count;\n                }\n \n                ++start;\n            }  \n        }\n\n\n        data* start = counts;   \n        data* swap_spot = counts;\n\n        if (counts[symbol].present)\n        {\n            while (true)\n            {                \n                if (start->symbol == symbol && start->count!=0)\n                {                \n                    unsigned short temp = start->count + amount;\n\n                    start->symbol = swap_spot->symbol;\n                    start->count = swap_spot->count;\n\n                    swap_spot->symbol = static_cast<unsigned short>(symbol);                \n                    swap_spot->count  = temp;\n                    break;\n                }\n                \n                if ( (start->count) < (swap_spot->count))\n                {\n                    swap_spot = start;\n                }\n\n\n                ++start;\n            }\n        }\n        else\n        {\n            counts[symbol].present = true;\n            while (true)\n            {\n                if (start->count == 0)\n                {\n                    start->symbol = swap_spot->symbol;\n                    start->count = swap_spot->count;\n                    \n                    swap_spot->symbol = static_cast<unsigned short>(symbol);                \n                    swap_spot->count  = amount;\n                    break;\n                }\n                    \n                if ((start->count) < (swap_spot->count))\n                {\n                    swap_spot = start;\n                }\n\n                ++start;\n            }\n        }\n        \n        total += amount;\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_3<alphabet_size>::\n    get_count (\n        unsigned long symbol\n    ) const\n    {\n        if (counts[symbol].present == false)\n            return 0;\n\n        data* start = counts;        \n        while (start->symbol != symbol)\n        {\n            ++start;\n        }\n        return start->count;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_3<alphabet_size>::\n    get_alphabet_size (        \n    ) \n    {\n        return alphabet_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_3<alphabet_size>::\n    get_total (\n    ) const\n    {\n        return total;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    unsigned long conditioning_class_kernel_3<alphabet_size>::\n    get_range (\n        unsigned long symbol,\n        unsigned long& low_count,\n        unsigned long& high_count,\n        unsigned long& total_count\n    ) const\n    {\n        if (counts[symbol].present == false)\n            return 0;\n\n        total_count = total;\n        unsigned long low_count_temp = 0;\n        data* start = counts;        \n        while (start->symbol != symbol)\n        {\n            low_count_temp += start->count;\n            ++start;\n        } \n\n        low_count = low_count_temp;\n        high_count = low_count_temp + start->count;\n        return start->count;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size\n        >\n    void conditioning_class_kernel_3<alphabet_size>::\n    get_symbol (\n        unsigned long target,\n        unsigned long& symbol,            \n        unsigned long& low_count,\n        unsigned long& high_count\n    ) const\n    {\n        unsigned long high_count_temp = counts->count;\n        const data* start = counts;        \n        while (target >= high_count_temp)\n        {\n            ++start;\n            high_count_temp += start->count;\n        } \n\n        low_count = high_count_temp - start->count;\n        high_count = high_count_temp;\n        symbol = static_cast<unsigned long>(start->symbol);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_3_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_4.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASS_KERNEl_4_\n#define DLIB_CONDITIONING_CLASS_KERNEl_4_\n\n#include \"conditioning_class_kernel_abstract.h\"\n#include \"../assert.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    class conditioning_class_kernel_4 \n    {\n        /*!\n            REQUIREMENTS ON pool_size\n                pool_size > 0\n                this will be the number of nodes contained in our memory pool\n\n            REQUIREMENTS ON mem_manager\n                mem_manager is an implementation of memory_manager/memory_manager_kernel_abstract.h\n\n            INITIAL VALUE\n                total == 1\n                escapes == 1\n                next == 0\n                \n            CONVENTION                \n                get_total() == total\n                get_count(alphabet_size-1) == escapes\n\n                if (next != 0) then\n                    next == pointer to the start of a linked list and the linked list\n                            is terminated by a node with a next pointer of 0.\n\n                get_count(symbol) == node::count for the node where node::symbol==symbol \n                                     or 0 if no such node currently exists.\n\n                if (there is a node for the symbol) then\n                    LOW_COUNT(symbol) == the sum of all node's counts in the linked list\n                    up to but not including the node for the symbol.\n\n                get_memory_usage() == global_state.memory_usage\n        !*/\n\n\n        struct node\n        {\n            unsigned short symbol;\n            unsigned short count;\n            node* next;\n        };\n\n    public:\n\n        class global_state_type\n        {\n        public:\n            global_state_type (\n            ) : \n                memory_usage(pool_size*sizeof(node)+sizeof(global_state_type))\n                {}\n        private:\n            unsigned long memory_usage;\n\n            typename mem_manager::template rebind<node>::other pool;\n\n            friend class conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>;\n        };\n\n        conditioning_class_kernel_4 (\n            global_state_type& global_state_\n        );\n\n        ~conditioning_class_kernel_4 (\n        );\n\n        void clear(\n        );\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n\n        inline unsigned long get_total (\n        ) const;\n        \n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n\n        unsigned long get_memory_usage (\n        ) const;\n\n        global_state_type& get_global_state (\n        );\n\n        static unsigned long get_alphabet_size (\n        );\n\n\n    private:\n\n        void half_counts (\n        );\n        /*!\n            ensures\n                - divides all counts by 2 but ensures that escapes is always at least 1\n        !*/\n\n        // restricted functions\n        conditioning_class_kernel_4(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&);        // copy constructor\n        conditioning_class_kernel_4& operator=(conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>&);    // assignment operator\n\n        // data members\n        unsigned short total;\n        unsigned short escapes;\n        node* next;\n        global_state_type& global_state;\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    conditioning_class_kernel_4 (\n        global_state_type& global_state_\n    ) :\n        total(1),\n        escapes(1),\n        next(0),\n        global_state(global_state_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65536 );\n\n        // update memory usage\n        global_state.memory_usage += sizeof(conditioning_class_kernel_4);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    ~conditioning_class_kernel_4 (\n    )\n    {\n        clear();\n        // update memory usage\n        global_state.memory_usage -= sizeof(conditioning_class_kernel_4);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    clear(\n    )\n    {\n        total = 1;\n        escapes = 1;\n        while (next)\n        {\n            node* temp = next;\n            next = next->next;\n            global_state.pool.deallocate(temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_memory_usage(\n    ) const\n    {\n        return global_state.memory_usage;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    typename conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::global_state_type& conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_global_state(\n    )\n    {\n        return global_state;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    bool conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    increment_count (\n        unsigned long symbol,\n        unsigned short amount\n    )\n    {        \n        if (symbol == alphabet_size-1)\n        {\n            // make sure we won't cause any overflow\n            if (total >= 65536 - amount )                        \n                half_counts();\n\n            escapes += amount;\n            total += amount;\n            return true;\n        }\n\n        \n        // find the symbol and increment it or add a new node to the list\n        if (next)\n        {\n            node* temp = next;\n            node* previous = 0;\n            while (true)\n            {\n                if (temp->symbol == static_cast<unsigned short>(symbol))\n                {\n                    // make sure we won't cause any overflow\n                    if (total >= 65536 - amount )                        \n                        half_counts();\n                    \n                    // we have found the symbol\n                    total += amount;\n                    temp->count += amount;\n\n                    // if this node now has a count greater than its parent node\n                    if (previous && temp->count > previous->count)\n                    {\n                        // swap the nodes so that the nodes will be in semi-sorted order\n                        swap(temp->count,previous->count);\n                        swap(temp->symbol,previous->symbol);\n                    }\n                    return true;\n                }\n                else if (temp->next == 0)\n                {\n                    // we did not find the symbol so try to add it to the list\n                    if (global_state.pool.get_number_of_allocations() < pool_size)\n                    {\n                        // make sure we won't cause any overflow\n                        if (total >= 65536 - amount )                        \n                            half_counts();\n\n                        node* t = global_state.pool.allocate();\n                        t->next = 0;\n                        t->symbol = static_cast<unsigned short>(symbol);\n                        t->count = amount;\n                        temp->next = t;\n                        total += amount;\n                        return true;\n                    }\n                    else\n                    {\n                        // no memory left\n                        return false;\n                    }\n                }\n                else if (temp->count == 0)\n                {\n                    // remove nodes that have a zero count\n                    if (previous)\n                    {\n                        previous->next = temp->next;\n                        node* t = temp;\n                        temp = temp->next;\n                        global_state.pool.deallocate(t);\n                    }\n                    else\n                    {\n                        next = temp->next;\n                        node* t = temp;\n                        temp = temp->next;\n                        global_state.pool.deallocate(t);\n                    }\n                }\n                else\n                {\n                    previous = temp;\n                    temp = temp->next;\n                }\n            } // while (true)\n        }\n        // if there aren't any nodes in the list yet then do this instead\n        else\n        {\n            if (global_state.pool.get_number_of_allocations() < pool_size)\n            {\n                // make sure we won't cause any overflow\n                if (total >= 65536 - amount )                        \n                    half_counts();\n\n                next = global_state.pool.allocate();\n                next->next = 0;\n                next->symbol = static_cast<unsigned short>(symbol);\n                next->count = amount;\n                total += amount;\n                return true;\n            }\n            else\n            {\n                // no memory left\n                return false;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_count (\n        unsigned long symbol\n    ) const\n    {\n        if (symbol == alphabet_size-1)\n        { \n            return escapes;\n        }\n        else\n        {\n            node* temp = next;\n            while (temp)\n            {\n                if (temp->symbol == symbol)\n                    return temp->count;\n                temp = temp->next;\n            }\n            return 0;\n        }        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_alphabet_size (        \n    ) \n    {\n        return alphabet_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_total (\n    ) const\n    {\n        return total;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    unsigned long conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_range (\n        unsigned long symbol,\n        unsigned long& low_count,\n        unsigned long& high_count,\n        unsigned long& total_count\n    ) const\n    {   \n        if (symbol != alphabet_size-1)\n        {\n            node* temp = next;\n            unsigned long low = 0;\n            while (temp)\n            {\n                if (temp->symbol == static_cast<unsigned short>(symbol))\n                {\n                    high_count = temp->count + low;\n                    low_count = low;                \n                    total_count = total;\n                    return temp->count;\n                }\n                low += temp->count;\n                temp = temp->next;\n            }\n            return 0;\n        }\n        else\n        {\n            total_count = total;\n            high_count = total;\n            low_count = total-escapes;\n            return escapes;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    get_symbol (\n        unsigned long target,\n        unsigned long& symbol,            \n        unsigned long& low_count,\n        unsigned long& high_count\n    ) const\n    {\n        node* temp = next;\n        unsigned long high = 0;\n        while (true)\n        {\n            if (temp != 0)\n            {\n                high += temp->count;\n                if (target < high)\n                {\n                    symbol = temp->symbol;\n                    high_count = high;\n                    low_count = high - temp->count;\n                    return;\n                }\n                temp = temp->next;\n            }\n            else\n            {\n                // this must be the escape symbol\n                symbol = alphabet_size-1;\n                low_count = total-escapes;\n                high_count = total;\n                return;\n            }            \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n\n    template <\n        unsigned long alphabet_size,\n        unsigned long pool_size,\n        typename mem_manager\n        >\n    void conditioning_class_kernel_4<alphabet_size,pool_size,mem_manager>::\n    half_counts (\n    ) \n    {\n        total = 0;\n        if (escapes > 1)\n            escapes >>= 1;\n\n        //divide all counts by 2\n        node* temp = next;\n        while (temp)\n        {\n            temp->count >>= 1;\n            total += temp->count;\n            temp = temp->next;\n        }\n        total += escapes;\n    }\n\n// ----------------------------------------------------------------------------------------\n \n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_4_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_\n#ifdef DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size\n        >\n    class conditioning_class \n    {\n        /*!\n            REQUIREMENTS ON alphabet_size\n                1 < alphabet_size < 65536\n\n            INITIAL VALUE\n                get_total() == 1\n                get_count(X) == 0 : for all valid values of X except alphabet_size-1\n                get_count(alphabet_size-1) == 1\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a conditioning class used for arithmetic style\n                compression.  It maintains the cumulative counts which are needed\n                by the entropy_coder and entropy_decoder objects.\n\n                At any moment a conditioning_class object represents a set of \n                alphabet_size symbols.  Each symbol is associated with an integer \n                called its count.  \n\n                All symbols start out with a count of zero except for alphabet_size-1.\n                This last symbol will always have a count of at least one.  It is\n                intended to be used as an escape into a lower context when coding\n                and so it must never have a zero probability or the decoder won't\n                be able to identify the escape symbol.\n\n            NOTATION:\n                Let MAP(i) be a function which maps integers to symbols.  MAP(i) is\n                one to one and onto.  Its domain is 1 to alphabet_size inclusive.\n               \n                Let RMAP(s) be the inverse of MAP(i).  \n                 ( i.e.  RMAP(MAP(i)) == i  and  MAP(RMAP(s)) == s  )\n\n                Let COUNT(i) give the count for the symbol MAP(i).  \n                 ( i.e.  COUNT(i) == get_count(MAP(i)) )\n              \n\n                Let LOW_COUNT(s) == the sum of COUNT(x) for x == 1 to x == RMAP(s)-1\n                  (note that the sum of COUNT(x) for x == 1 to x == 0 is 0)\n                Let HIGH_COUNT(s) == LOW_COUNT(s) + get_count(s)    \n\n\n\n                Basically what this is saying is just that you shoudln't assume you know\n                what order the symbols are placed in when calculating the cumulative\n                sums.  The specific mapping provided by the MAP() function is unspecified.  \n\n            THREAD SAFETY\n                This object can be used safely in a multithreaded program as long as the \n                global state is not shared between conditioning classes which run on \n                different threads.  \n\n            GLOBAL_STATE_TYPE\n                The global_state_type obejct allows instances of the conditioning_class\n                object to share any kind of global state the implementer desires. \n                However, the global_state_type object exists primarily to facilitate the \n                sharing of a memory pool between many instances of a conditioning_class \n                object.  But note that it is not required that there be any kind of \n                memory pool at all, it is just a possibility.\n        !*/\n\n    public:\n\n        class global_state_type \n        {\n            global_state_type (\n            );\n            /*!\n                ensures\n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n            !*/\n\n            // my contents are implementation specific.               \n        };\n\n        conditioning_class (\n            global_state_type& global_state\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n                - &#get_global_state() == &global_state\n            throws\n                - std::bad_alloc\n        !*/\n\n        ~conditioning_class (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n        !*/\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n        /*!\n            requires\n                - 0 <= symbol < alphabet_size\n                - 0 < amount < 32768\n            ensures\n                - if (sufficient memory is available to complete this operation) then\n                    - returns true\n                    - if (get_total()+amount < 65536) then \n                        - #get_count(symbol) == get_count(symbol) + amount\n                    - else\n                        - #get_count(symbol) == get_count(symbol)/2 + amount\n                        - if (get_count(alphabet_size-1) == 1) then\n                            - #get_count(alphabet_size-1) == 1\n                        - else\n                            - #get_count(alphabet_size-1) == get_count(alphabet_size-1)/2\n                        - for all X where (X != symbol)&&(X != alpahbet_size-1): \n                          #get_count(X) == get_count(X)/2  \n                - else\n                    - returns false\n        !*/\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n        /*!\n            requires \n                - 0 <= symbol < alphabet_size\n            ensures\n                - returns the count for the specified symbol\n        !*/\n\n        unsigned long get_total (\n        ) const;\n        /*!\n            ensures\n                - returns the sum of get_count(X) for all valid values of X\n                  (i.e. returns the sum of the counts for all the symbols)\n        !*/\n\n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n        /*!\n            requires\n                - 0 <= symbol < alphabet_size\n            ensures                \n                - returns get_count(symbol)\n                - if (get_count(symbol) != 0) then\n                    - #total_count == get_total()\n                    - #low_count   == LOW_COUNT(symbol)\n                    - #high_count  == HIGH_COUNT(symbol)\n                    - #low_count < #high_count <= #total_count                \n        !*/\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n        /*!\n            requires\n                - 0 <= target < get_total()\n            ensures\n                - LOW_COUNT(#symbol) <= target < HIGH_COUNT(#symbol)\n                - #low_count   == LOW_COUNT(#symbol)\n                - #high_count  == HIGH_COUNT(#symbol)\n                - #low_count < #high_count <= get_total()\n        !*/\n\n        global_state_type& get_global_state (\n        );\n        /*! \n            ensures\n                - returns a reference to the global state used by *this\n        !*/\n\n        unsigned long get_memory_usage (\n        ) const;\n        /*!\n            ensures \n                - returns the number of bytes of memory allocated by all conditioning_class\n                  objects that share the global state given by get_global_state()\n        !*/\n\n        static unsigned long get_alphabet_size (\n        );\n        /*!\n            ensures\n                - returns alphabet_size\n        !*/\n\n    private:\n\n        // restricted functions\n        conditioning_class(conditioning_class<alphabet_size>&);        // copy constructor\n        conditioning_class<alphabet_size>& operator=(conditioning_class<alphabet_size>&);    // assignment operator\n\n    };   \n\n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/conditioning_class/conditioning_class_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASS_KERNEl_C_\n#define DLIB_CONDITIONING_CLASS_KERNEl_C_\n\n#include \"conditioning_class_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename cc_base\n        >\n    class conditioning_class_kernel_c : public cc_base\n    {\n        const unsigned long alphabet_size;\n\n    public:\n\n        conditioning_class_kernel_c (\n            typename cc_base::global_state_type& global_state\n            ) : cc_base(global_state),alphabet_size(cc_base::get_alphabet_size()) {}\n\n        bool increment_count (\n            unsigned long symbol,\n            unsigned short amount = 1\n        );\n\n        unsigned long get_count (\n            unsigned long symbol\n        ) const;\n\n        unsigned long get_range (\n            unsigned long symbol,\n            unsigned long& low_count,\n            unsigned long& high_count,\n            unsigned long& total_count\n        ) const;\n\n        void get_symbol (\n            unsigned long target,\n            unsigned long& symbol,            \n            unsigned long& low_count,\n            unsigned long& high_count\n        ) const;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename cc_base\n        >\n    bool conditioning_class_kernel_c<cc_base>::\n    increment_count (\n        unsigned long symbol,\n        unsigned short amount\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(symbol < alphabet_size &&\n                0 < amount && amount < 32768,\n                \"\\tvoid conditioning_class::increment_count()\"\n                << \"\\n\\tthe symbol must be in the range 0 to alphabet_size-1. and\"\n                << \"\\n\\tamount must be in the range 1 to 32767\"\n                << \"\\n\\talphabet_size: \" << alphabet_size\n                << \"\\n\\tsymbol:        \" << symbol\n                << \"\\n\\tamount:        \" << amount\n                << \"\\n\\tthis:          \" << this\n        );\n\n        // call the real function\n        return cc_base::increment_count(symbol,amount);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename cc_base\n        >\n    unsigned long conditioning_class_kernel_c<cc_base>::\n    get_count (\n        unsigned long symbol\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(symbol < alphabet_size,\n                \"\\tvoid conditioning_class::get_count()\"\n                << \"\\n\\tthe symbol must be in the range 0 to alphabet_size-1\"\n                << \"\\n\\talphabet_size: \" << alphabet_size\n                << \"\\n\\tsymbol:        \" << symbol\n                << \"\\n\\tthis:          \" << this\n        );\n\n        // call the real function\n        return cc_base::get_count(symbol);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename cc_base\n        >\n    unsigned long conditioning_class_kernel_c<cc_base>::\n    get_range (\n        unsigned long symbol,\n        unsigned long& low_count,\n        unsigned long& high_count,\n        unsigned long& total_count\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(symbol < alphabet_size,\n                \"\\tvoid conditioning_class::get_range()\"\n                << \"\\n\\tthe symbol must be in the range 0 to alphabet_size-1\"\n                << \"\\n\\talphabet_size: \" << alphabet_size\n                << \"\\n\\tsymbol:        \" << symbol\n                << \"\\n\\tthis:          \" << this\n        );\n\n        // call the real function\n        return cc_base::get_range(symbol,low_count,high_count,total_count);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename cc_base\n        >\n    void conditioning_class_kernel_c<cc_base>::\n    get_symbol (\n        unsigned long target,\n        unsigned long& symbol,            \n        unsigned long& low_count,\n        unsigned long& high_count\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( target < this->get_total(),\n                 \"\\tvoid conditioning_class::get_symbol()\"\n                 << \"\\n\\tthe target must be in the range 0 to get_total()-1\"\n                 << \"\\n\\tget_total(): \" << this->get_total()\n                 << \"\\n\\ttarget:       \" << target\n                 << \"\\n\\tthis:         \" << this\n        );\n\n        // call the real function\n        cc_base::get_symbol(target,symbol,low_count,high_count);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONDITIONING_CLASS_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/conditioning_class.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONDITIONING_CLASs_\n#define DLIB_CONDITIONING_CLASs_\n\n#include \"conditioning_class/conditioning_class_kernel_1.h\"\n#include \"conditioning_class/conditioning_class_kernel_2.h\"\n#include \"conditioning_class/conditioning_class_kernel_3.h\"\n#include \"conditioning_class/conditioning_class_kernel_4.h\"\n#include \"conditioning_class/conditioning_class_kernel_c.h\"\n\n\n#include \"memory_manager.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size\n        >\n    class conditioning_class\n    {\n        conditioning_class() {}\n\n        typedef memory_manager<char>::kernel_2b mm;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef      conditioning_class_kernel_1<alphabet_size>\n                     kernel_1a;\n        typedef      conditioning_class_kernel_c<kernel_1a>\n                     kernel_1a_c;\n\n        // kernel_2a        \n        typedef      conditioning_class_kernel_2<alphabet_size>\n                     kernel_2a;\n        typedef      conditioning_class_kernel_c<kernel_2a>\n                     kernel_2a_c;\n          \n        // kernel_3a        \n        typedef      conditioning_class_kernel_3<alphabet_size>\n                     kernel_3a;\n        typedef      conditioning_class_kernel_c<kernel_3a>\n                     kernel_3a_c;\n          \n\n        // -------- kernel_4 ---------\n\n        // kernel_4a        \n        typedef      conditioning_class_kernel_4<alphabet_size,10000,mm>\n                     kernel_4a;\n        typedef      conditioning_class_kernel_c<kernel_4a>\n                     kernel_4a_c;\n\n        // kernel_4b        \n        typedef      conditioning_class_kernel_4<alphabet_size,100000,mm>\n                     kernel_4b;\n        typedef      conditioning_class_kernel_c<kernel_4b>\n                     kernel_4b_c;\n\n        // kernel_4c        \n        typedef      conditioning_class_kernel_4<alphabet_size,1000000,mm>\n                     kernel_4c;\n        typedef      conditioning_class_kernel_c<kernel_4c>\n                     kernel_4c_c;\n\n        // kernel_4d        \n        typedef      conditioning_class_kernel_4<alphabet_size,10000000,mm>\n                     kernel_4d;\n        typedef      conditioning_class_kernel_c<kernel_4d>\n                     kernel_4d_c;\n\n    };\n}\n\n#endif // DLIB_CONDITIONING_CLASS_\n\n"
  },
  {
    "path": "dlib/config.h",
    "content": "\n\n// If you are compiling dlib as a shared library and installing it somewhere on your system\n// then it is important that any programs that use dlib agree on the state of the\n// DLIB_ASSERT statements (i.e. they are either always on or always off).  Therefore,\n// uncomment one of the following lines to force all DLIB_ASSERTs to either always on or\n// always off.  If you don't define one of these two macros then DLIB_ASSERT will toggle\n// automatically depending on the state of certain other macros, which is not what you want\n// when creating a shared library.\n//#define ENABLE_ASSERTS       // asserts always enabled \n//#define DLIB_DISABLE_ASSERTS // asserts always disabled \n\n//#define DLIB_ISO_CPP_ONLY\n//#define DLIB_NO_GUI_SUPPORT\n//#define DLIB_ENABLE_STACK_TRACE\n\n// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA, \n// and a BLAS and LAPACK library.  To do this you need to uncomment the following #defines.\n// #define DLIB_JPEG_SUPPORT\n// #define DLIB_PNG_SUPPORT\n// #define DLIB_GIF_SUPPORT\n// #define DLIB_USE_FFTW\n// #define DLIB_USE_BLAS\n// #define DLIB_USE_LAPACK\n// #define DLIB_USE_CUDA\n\n\n// Define this so the code in dlib/test_for_odr_violations.h can detect ODR violations\n// related to users doing bad things with config.h\n#define DLIB_NOT_CONFIGURED\n\n"
  },
  {
    "path": "dlib/config.h.in",
    "content": "\n\n// If you are compiling dlib as a shared library and installing it somewhere on your system\n// then it is important that any programs that use dlib agree on the state of the\n// DLIB_ASSERT statements (i.e. they are either always on or always off).  Therefore,\n// uncomment one of the following lines to force all DLIB_ASSERTs to either always on or\n// always off.  If you don't define one of these two macros then DLIB_ASSERT will toggle\n// automatically depending on the state of certain other macros, which is not what you want\n// when creating a shared library.\n#cmakedefine ENABLE_ASSERTS       // asserts always enabled \n#cmakedefine DLIB_DISABLE_ASSERTS // asserts always disabled \n\n#cmakedefine DLIB_ISO_CPP_ONLY\n#cmakedefine DLIB_NO_GUI_SUPPORT\n#cmakedefine DLIB_ENABLE_STACK_TRACE\n\n#cmakedefine LAPACK_FORCE_UNDERSCORE\n#cmakedefine LAPACK_FORCE_NOUNDERSCORE\n\n// You should also consider telling dlib to link against libjpeg, libpng, libgif, fftw, CUDA, \n// and a BLAS and LAPACK library.  To do this you need to uncomment the following #defines.\n#cmakedefine DLIB_JPEG_SUPPORT\n#cmakedefine DLIB_PNG_SUPPORT\n#cmakedefine DLIB_GIF_SUPPORT\n#cmakedefine DLIB_WEBP_SUPPORT\n#cmakedefine DLIB_JXL_SUPPORT\n#cmakedefine DLIB_USE_FFTW\n#cmakedefine DLIB_USE_BLAS\n#cmakedefine DLIB_USE_LAPACK\n#cmakedefine DLIB_USE_CUDA\n#cmakedefine DLIB_USE_MKL_FFT\n#cmakedefine DLIB_USE_FFMPEG\n\n// This variable allows dlib/test_for_odr_violations.h to catch people who mistakenly use\n// headers from one version of dlib with a compiled dlib binary from a different dlib version.\n#cmakedefine DLIB_CHECK_FOR_VERSION_MISMATCH @DLIB_CHECK_FOR_VERSION_MISMATCH@\n\n"
  },
  {
    "path": "dlib/config_reader/config_reader_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONFIG_READER_KERNEl_1_\n#define DLIB_CONFIG_READER_KERNEl_1_\n\n#include \"config_reader_kernel_abstract.h\"\n#include <string>\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include \"../algs.h\"\n#include \"../stl_checked/std_vector_c.h\"\n\n#ifndef DLIB_ISO_CPP_ONLY\n#include \"config_reader_thread_safe_1.h\"\n#endif\n\nnamespace dlib\n{\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    class config_reader_kernel_1 \n    {\n\n        /*!                \n            REQUIREMENTS ON map_string_string\n                is an implementation of map/map_kernel_abstract.h that maps std::string to std::string\n\n            REQUIREMENTS ON map_string_void \n                is an implementation of map/map_kernel_abstract.h that maps std::string to void*\n\n            REQUIREMENTS ON tokenizer\n                is an implementation of tokenizer/tokenizer_kernel_abstract.h \n\n            CONVENTION\n                key_table.is_in_domain(x) == is_key_defined(x)\n                block_table.is_in_domain(x) == is_block_defined(x)\n\n                key_table[x] == operator[](x)\n                block_table[x] == (void*)&block(x)\n        !*/\n        \n    public:\n\n        // These two typedefs are defined for backwards compatibility with older versions of dlib.\n        typedef config_reader_kernel_1 kernel_1a;\n#ifndef DLIB_ISO_CPP_ONLY\n        typedef config_reader_thread_safe_1<\n            config_reader_kernel_1,\n            map_string_void \n            > thread_safe_1a;\n#endif // DLIB_ISO_CPP_ONLY\n\n\n        config_reader_kernel_1();\n\n        class config_reader_error : public dlib::error \n        {\n            friend class config_reader_kernel_1;\n            config_reader_error(\n                unsigned long ln, \n                bool r = false\n            ) : \n                dlib::error(ECONFIG_READER),\n                line_number(ln), \n                redefinition(r)\n            {\n                std::ostringstream sout;\n                sout << \"Error in config_reader while parsing at line number \" << line_number << \".\";\n                if (redefinition)\n                    sout << \"\\nThe identifier on this line has already been defined in this scope.\";\n                const_cast<std::string&>(info) = sout.str();\n            }\n        public:\n            const unsigned long line_number;\n            const bool redefinition;\n        };\n\n        class file_not_found : public dlib::error \n        {\n            friend class config_reader_kernel_1;\n            file_not_found(\n                const std::string& file_name_\n            ) : \n                dlib::error(ECONFIG_READER, \"Error in config_reader, unable to open file \" + file_name_),\n                file_name(file_name_)\n            {}\n\n            ~file_not_found() noexcept {}\n\n        public:\n            const std::string file_name;\n        };\n\n        class config_reader_access_error : public dlib::error\n        {\n        public:\n            config_reader_access_error(\n                const std::string& block_name_,\n                const std::string& key_name_\n            ) : \n                dlib::error(ECONFIG_READER),\n                block_name(block_name_), \n                key_name(key_name_)\n            {\n                std::ostringstream sout;\n                sout << \"Error in config_reader.\\n\";\n                if (block_name.size() > 0)\n                    sout << \"   A block with the name '\" << block_name << \"' was expected but not found.\";\n                else if (key_name.size() > 0)\n                    sout << \"   A key with the name '\" << key_name << \"' was expected but not found.\";\n\n                const_cast<std::string&>(info) = sout.str();\n            }\n\n            ~config_reader_access_error() noexcept {}\n            const std::string block_name;\n            const std::string key_name;\n        };\n\n        config_reader_kernel_1(\n            const std::string& config_file \n        );\n\n        config_reader_kernel_1(\n            std::istream& in\n        );\n\n        virtual ~config_reader_kernel_1(\n        ); \n\n        void clear (\n        );\n\n        void load_from (\n            std::istream& in\n        );\n\n        void load_from (\n            const std::string& config_file\n        );\n\n        bool is_key_defined (\n            const std::string& key\n        ) const;\n\n        bool is_block_defined (\n            const std::string& name\n        ) const;\n\n        typedef config_reader_kernel_1 this_type;\n        const this_type& block (\n            const std::string& name\n        ) const;\n\n        const std::string& operator[] (\n            const std::string& key\n        ) const;\n\n        template <\n            typename queue_of_strings\n            >\n        void get_keys (\n            queue_of_strings& keys\n        ) const;\n\n        template <\n            typename alloc \n            >\n        void get_keys (\n            std::vector<std::string,alloc>& keys\n        ) const;\n\n        template <\n            typename alloc \n            >\n        void get_keys (\n            std_vector_c<std::string,alloc>& keys\n        ) const;\n\n        template <\n            typename queue_of_strings\n            >\n        void get_blocks (\n            queue_of_strings& blocks\n        ) const;\n\n        template <\n            typename alloc \n            >\n        void get_blocks (\n            std::vector<std::string,alloc>& blocks\n        ) const;\n\n        template <\n            typename alloc \n            >\n        void get_blocks (\n            std_vector_c<std::string,alloc>& blocks\n        ) const;\n\n    private:\n\n        static void parse_config_file (\n            config_reader_kernel_1& cr,\n            tokenizer& tok,\n            unsigned long& line_number,\n            const bool top_of_recursion = true\n        );\n        /*!\n            requires\n                - line_number == 1\n                - cr == *this\n                - top_of_recursion == true\n            ensures\n                - parses the data coming from tok and puts it into cr.\n            throws\n                - config_reader_error\n        !*/\n\n        map_string_string key_table;\n        map_string_void block_table;\n\n        // restricted functions\n        config_reader_kernel_1(config_reader_kernel_1&);     \n        config_reader_kernel_1& operator=(config_reader_kernel_1&);\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    config_reader_kernel_1(\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    clear(\n    )\n    {\n        // free all our blocks\n        block_table.reset();\n        while (block_table.move_next())\n        {\n            delete static_cast<config_reader_kernel_1*>(block_table.element().value());\n        }\n        block_table.clear();\n        key_table.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    load_from(\n        std::istream& in\n    )\n    {\n        clear();\n\n        tokenizer tok;\n        tok.set_stream(in);\n        tok.set_identifier_token(\n            tok.lowercase_letters() + tok.uppercase_letters(),\n            tok.lowercase_letters() + tok.uppercase_letters() + tok.numbers() + \"_-.\"\n        );\n\n        unsigned long line_number = 1;\n        try\n        {\n            parse_config_file(*this,tok,line_number);\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    load_from(\n        const std::string& config_file\n    )\n    {\n        clear();\n        std::ifstream fin(config_file.c_str());\n        if (!fin)\n            throw file_not_found(config_file);\n\n        load_from(fin);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    config_reader_kernel_1(\n        std::istream& in\n    )\n    {\n        load_from(in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    config_reader_kernel_1(\n        const std::string& config_file\n    )\n    {\n        load_from(config_file);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    parse_config_file(\n        config_reader_kernel_1<map_string_string,map_string_void,tokenizer>& cr,\n        tokenizer& tok,\n        unsigned long& line_number,\n        const bool top_of_recursion\n    )\n    {\n        int type;\n        std::string token;\n        bool in_comment = false;\n        bool seen_identifier = false;\n        std::string identifier;\n        while (true)\n        {\n            tok.get_token(type,token);\n            // ignore white space\n            if (type == tokenizer::WHITE_SPACE)\n                continue;\n\n            // basically ignore end of lines\n            if (type == tokenizer::END_OF_LINE)\n            {\n                ++line_number;\n                in_comment = false;\n                continue;\n            }\n\n            // we are in a comment still so ignore this\n            if (in_comment)\n                continue;\n\n            // if this is the start of a comment\n            if (type == tokenizer::CHAR && token[0] == '#')\n            {\n                in_comment = true;\n                continue;\n            }\n\n            // if this is the case then we have just finished parsing a block so we should\n            // quit this function\n            if ( (type == tokenizer::CHAR && token[0] == '}' && !top_of_recursion) ||\n                 (type == tokenizer::END_OF_FILE && top_of_recursion) )\n            {\n                break;\n            }\n\n            if (seen_identifier)\n            {\n                seen_identifier = false;\n                // the next character should be either a '=' or a '{'\n                if (type != tokenizer::CHAR || (token[0] != '=' && token[0] != '{'))\n                    throw config_reader_error(line_number);\n                \n                if (token[0] == '=')\n                {\n                    // we should parse the value out now\n                    // first discard any white space\n                    if (tok.peek_type() == tokenizer::WHITE_SPACE)\n                        tok.get_token(type,token);\n\n                    std::string value;\n                    type = tok.peek_type();\n                    token = tok.peek_token();\n                    while (true)\n                    {\n                        if (type == tokenizer::END_OF_FILE || type == tokenizer::END_OF_LINE)\n                            break;\n\n                        if (type == tokenizer::CHAR && token[0] == '\\\\')\n                        {\n                            tok.get_token(type,token);\n                            if (tok.peek_type() == tokenizer::CHAR && \n                                tok.peek_token()[0] == '#')\n                            {\n                                tok.get_token(type,token);\n                                value += '#';\n                            }\n                            else if (tok.peek_type() == tokenizer::CHAR && \n                                tok.peek_token()[0] == '}')\n                            {\n                                tok.get_token(type,token);\n                                value += '}';\n                            }\n                            else\n                            {\n                                value += '\\\\';\n                            }\n                        }\n                        else if (type == tokenizer::CHAR && \n                                 (token[0] == '#' || token[0] == '}'))\n                        {\n                            break;\n                        }\n                        else\n                        {\n                            value += token;\n                            tok.get_token(type,token);\n                        }\n                        type = tok.peek_type();\n                        token = tok.peek_token();\n                    } // while(true)\n\n                    // strip of any tailing white space from value\n                    std::string::size_type pos = value.find_last_not_of(\" \\t\\r\\n\");\n                    if (pos == std::string::npos)\n                        value.clear();\n                    else\n                        value.erase(pos+1);\n\n                    // make sure this key isn't already in the key_table\n                    if (cr.key_table.is_in_domain(identifier))\n                        throw config_reader_error(line_number,true);\n\n                    // add this key/value pair to the key_table\n                    cr.key_table.add(identifier,value);\n\n                }\n                else  // when token[0] == '{'\n                {\n                    // make sure this identifier isn't already in the block_table\n                    if (cr.block_table.is_in_domain(identifier))\n                        throw config_reader_error(line_number,true);\n\n                    config_reader_kernel_1* new_cr = new config_reader_kernel_1;\n                    void* vtemp = new_cr;\n                    try { cr.block_table.add(identifier,vtemp); }\n                    catch (...) { delete new_cr; throw; }\n\n                    // now parse this block \n                    parse_config_file(*new_cr,tok,line_number,false);\n                }\n            }\n            else\n            {\n                // the next thing should be an identifier but if it isn't this is an error\n                if (type != tokenizer::IDENTIFIER)\n                    throw config_reader_error(line_number);\n\n                seen_identifier = true;\n                identifier = token;\n            }\n        } // while (true) \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    ~config_reader_kernel_1(\n    ) \n    {\n        clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    is_key_defined (\n        const std::string& key\n    ) const\n    {\n        return key_table.is_in_domain(key);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    bool config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    is_block_defined (\n        const std::string& name\n    ) const\n    {\n        return block_table.is_in_domain(name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename mss,\n        typename msv,\n        typename tokenizer\n        >\n    const config_reader_kernel_1<mss,msv,tokenizer>& config_reader_kernel_1<mss,msv,tokenizer>::\n    block (\n        const std::string& name\n    ) const\n    {\n        if (is_block_defined(name) == false)\n        {\n            throw config_reader_access_error(name,\"\");\n        }\n\n        return *static_cast<config_reader_kernel_1*>(block_table[name]);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    const std::string& config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    operator[] (\n        const std::string& key\n    ) const\n    {\n        if (is_key_defined(key) == false)\n        {\n            throw config_reader_access_error(\"\",key);\n        }\n\n        return key_table[key];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename queue_of_strings\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_keys (\n        queue_of_strings& keys\n    ) const\n    {\n        keys.clear();\n        key_table.reset();\n        std::string temp;\n        while (key_table.move_next())\n        {\n            temp = key_table.element().key();\n            keys.enqueue(temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename alloc \n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_keys (\n        std::vector<std::string,alloc>& keys\n    ) const\n    {\n        keys.clear();\n        key_table.reset();\n        while (key_table.move_next())\n        {\n            keys.push_back(key_table.element().key());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename alloc \n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_keys (\n        std_vector_c<std::string,alloc>& keys\n    ) const\n    {\n        keys.clear();\n        key_table.reset();\n        while (key_table.move_next())\n        {\n            keys.push_back(key_table.element().key());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename queue_of_strings\n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_blocks (\n        queue_of_strings& blocks\n    ) const\n    {\n        blocks.clear();\n        block_table.reset();\n        std::string temp;\n        while (block_table.move_next())\n        {\n            temp = block_table.element().key();\n            blocks.enqueue(temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename alloc \n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_blocks (\n        std::vector<std::string,alloc>& blocks\n    ) const\n    {\n        blocks.clear();\n        block_table.reset();\n        while (block_table.move_next())\n        {\n            blocks.push_back(block_table.element().key());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_string_string,\n        typename map_string_void,\n        typename tokenizer\n        >\n    template <\n        typename alloc \n        >\n    void config_reader_kernel_1<map_string_string,map_string_void,tokenizer>::\n    get_blocks (\n        std_vector_c<std::string,alloc>& blocks\n    ) const\n    {\n        blocks.clear();\n        block_table.reset();\n        while (block_table.move_next())\n        {\n            blocks.push_back(block_table.element().key());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONFIG_READER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/config_reader/config_reader_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CONFIG_READER_KERNEl_ABSTRACT_\n#ifdef DLIB_CONFIG_READER_KERNEl_ABSTRACT_\n\n#include <string>\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    class config_reader \n    {\n\n        /*!                \n            INITIAL VALUE\n                - there aren't any keys defined for this object\n                - there aren't any blocks defined for this object\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                The destructor, clear(), and load_from() invalidate pointers\n                and references to internal data.  All other functions are guaranteed\n                to NOT invalidate pointers or references to internal data.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents something which is intended to be used to read\n                text configuration files that are defined by the following EBNF (with\n                config_file as the starting symbol):\n            \n                config_file    = block;\n                block          = { key_value_pair | sub_block };\n                key_value_pair = key_name, \"=\", value;\n                sub_block      = block_name, \"{\", block, \"}\";\n\n                key_name       = identifier;\n                block_name     = identifier;\n                value          = matches any string of text that ends with a newline character, # or }.  \n                                 note that the trailing newline, # or } is not part of the value though.\n                identifier     = Any string that matches the following regular expression:\n                                 [a-zA-Z][a-zA-Z0-9_-\\.]*\n                                 i.e. Any string that starts with a letter and then is continued\n                                 with any number of letters, numbers, _ . or - characters.\n\n                Whitespace and comments are ignored.  A comment is text that starts with # (but not \\#\n                since the \\ escapes the # so that you can have a # symbol in a value if you want) and \n                ends in a new line.  You can also escape a } (e.g. \"\\}\") if you want to have one in a \n                value.\n\n                Note that in a value the leading and trailing white spaces are stripped off but any \n                white space inside the value is preserved.\n\n                Also note that all key_names and block_names within a block syntax group must be unique \n                but don't have to be globally unique.  I.e. different blocks can reuse names. \n\n                EXAMPLE CONFIG FILES:\n\n                    Example 1:\n                        #comment.  This line is ignored because it starts with #\n\n                        #here we have key1 which will have the value of \"my value\"\n                        key1 = my value \n\n                        another_key=  another value  # this is another key called \"another_key\" with\n                                                     # a value of \"another value\"\n\n                        # this key's value is the empty string.  I.e. \"\"\n                        key2=\n\n                    Example 2:\n                        #this example illustrates the use of blocks\n                        some_key = blah blah\n\n                        # now here is a block\n                        our_block\n                        {\n                            # here we can define some keys and values that are local to this block.\n                            a_key = something\n                            foo = bar\n                            some_key = more stuff  # note that it is ok to name our key this even though\n                                                   # there is a key called some_key above.  This is because\n                                                   # we are doing so inside a different block\n                        }\n\n                        another_block { foo = bar2 }  # this block has only one key and is all on a single line\n        !*/\n    \n    public:\n\n        // exception classes\n        class config_reader_error : public dlib::error \n        {\n            /*!\n                GENERAL\n                    This exception is thrown if there is an error while parsing the\n                    config file.  The type member of this exception will be set\n                    to ECONFIG_READER.\n\n                INTERPRETING THIS EXCEPTION\n                    - line_number == the line number the parser was at when the \n                      error occurred.\n                    - if (redefinition) then\n                        - The key or block name on line line_number has already\n                          been defined in this scope which is an error.\n                    - else\n                        - Some other general syntax error was detected\n            !*/\n        public:\n            const unsigned long line_number;\n            const bool redefinition;\n        };\n\n        class file_not_found : public dlib::error \n        {\n            /*!\n                GENERAL\n                    This exception is thrown if the config file can't be opened for\n                    some reason.  The type member of this exception will be set\n                    to ECONFIG_READER.\n\n                INTERPRETING THIS EXCEPTION\n                    - file_name == the name of the config file which we failed to open\n            !*/\n        public:\n            const std::string file_name;\n        };\n\n\n        class config_reader_access_error : public dlib::error\n        {\n            /*!\n                GENERAL\n                    This exception is thrown if you try to access a key or\n                    block that doesn't exist inside a config reader.  The type \n                    member of this exception will be set to ECONFIG_READER.\n            !*/\n        public:\n            config_reader_access_error(\n                const std::string& block_name_,\n                const std::string& key_name_\n            );\n            /*!\n                ensures\n                    - #block_name == block_name_\n                    - #key_name == key_name_\n            !*/\n\n            const std::string block_name;\n            const std::string key_name;\n        };\n\n    // --------------------------\n\n        config_reader(\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n                - This object will not have any keys or blocks defined in it.  \n            throws\n                - std::bad_alloc\n                - config_reader_error\n        !*/\n\n        config_reader(\n            std::istream& in\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n                - reads the config file to parse from the given input stream,\n                  parses it and loads this object up with all the sub blocks and\n                  key/value pairs it finds.\n                - before the load is performed, the previous state of the config file\n                  reader is erased.  So after the load the config file reader will contain\n                  only information from the given config file.\n                - This object will represent the top most block of the config file.\n            throws\n                - std::bad_alloc\n                - config_reader_error\n        !*/\n\n        config_reader(\n            const std::string& config_file \n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n                - parses the config file named by the config_file string.  Specifically, \n                  parses it and loads this object up with all the sub blocks and\n                  key/value pairs it finds in the file.\n                - before the load is performed, the previous state of the config file\n                  reader is erased.  So after the load the config file reader will contain\n                  only information from the given config file.\n                - This object will represent the top most block of the config file.\n            throws\n                - std::bad_alloc\n                - config_reader_error\n                - file_not_found\n        !*/\n\n        virtual ~config_reader(\n        ); \n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc \n                    If this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void load_from (\n            std::istream& in\n        );\n        /*!\n            ensures \n                - reads the config file to parse from the given input stream,\n                  parses it and loads this object up with all the sub blocks and\n                  key/value pairs it finds.\n                - before the load is performed, the previous state of the config file\n                  reader is erased.  So after the load the config file reader will contain\n                  only information from the given config file.\n                - *this will represent the top most block of the config file contained\n                  in the input stream in.\n            throws\n                - std::bad_alloc \n                    If this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n                - config_reader_error\n                    If this exception is thrown then this object will\n                    revert to its initial value.\n        !*/\n\n        void load_from (\n            const std::string& config_file\n        );\n        /*!\n            ensures \n                - parses the config file named by the config_file string.  Specifically, \n                  parses it and loads this object up with all the sub blocks and\n                  key/value pairs it finds in the file.  \n                - before the load is performed, the previous state of the config file\n                  reader is erased.  So after the load the config file reader will contain\n                  only information from the given config file.\n                - This object will represent the top most block of the config file.\n            throws\n                - std::bad_alloc \n                    If this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n                - config_reader_error\n                    If this exception is thrown then this object will\n                    revert to its initial value.\n                - file_not_found\n                    If this exception is thrown then this object will\n                    revert to its initial value.\n        !*/\n\n        bool is_key_defined (\n            const std::string& key_name\n        ) const;\n        /*!\n            ensures\n                - if (there is a key with the given name defined within this config_reader's block) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_block_defined (\n            const std::string& block_name\n        ) const;\n        /*!\n            ensures\n                - if (there is a sub block with the given name defined within this config_reader's block) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        typedef config_reader this_type;\n        const this_type& block (\n            const std::string& block_name\n        ) const;\n        /*!\n            ensures\n                - if (is_block_defined(block_name) == true) then\n                    - returns a const reference to the config_reader that represents the given named sub block\n                - else\n                    - throws config_reader_access_error\n            throws\n                - config_reader_access_error\n                    if this exception is thrown then its block_name field will be set to the\n                    given block_name string.\n        !*/\n\n        const std::string& operator[] (\n            const std::string& key_name\n        ) const;\n        /*!\n            ensures\n                - if (is_key_defined(key_name) == true) then\n                    - returns a const reference to the value string associated with the given key in \n                      this config_reader's block.\n                - else\n                    - throws config_reader_access_error\n            throws\n                - config_reader_access_error\n                    if this exception is thrown then its key_name field will be set to the\n                    given key_name string.\n        !*/\n\n        template <\n            typename queue_of_strings\n            >\n        void get_keys (\n            queue_of_strings& keys\n        ) const;\n        /*!\n            requires\n                - queue_of_strings is an implementation of queue/queue_kernel_abstract.h \n                  with T set to std::string, or std::vector<std::string>, or \n                  dlib::std_vector_c<std::string>\n            ensures \n                - #keys == a collection containing all the keys defined in this config_reader's block.\n                  (i.e. for all strings str in keys it is the case that is_key_defined(str) == true)\n        !*/\n\n        template <\n            typename queue_of_strings\n            >\n        void get_blocks (\n            queue_of_strings& blocks\n        ) const;\n        /*!\n            requires\n                - queue_of_strings is an implementation of queue/queue_kernel_abstract.h \n                  with T set to std::string, or std::vector<std::string>, or \n                  dlib::std_vector_c<std::string>\n            ensures \n                - #blocks == a collection containing the names of all the blocks defined in this \n                  config_reader's block.\n                  (i.e. for all strings str in blocks it is the case that is_block_defined(str) == true)\n        !*/\n\n    private:\n\n        // restricted functions\n        config_reader(config_reader&);        // copy constructor\n        config_reader& operator=(config_reader&);    // assignment operator\n\n    };\n\n}\n\n#endif // DLIB_CONFIG_READER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/config_reader/config_reader_thread_safe_1.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONFIG_READER_THREAD_SAFe_\n#define DLIB_CONFIG_READER_THREAD_SAFe_\n\n#include \"config_reader_kernel_abstract.h\"\n#include <string>\n#include <iostream>\n#include <sstream>\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../threads.h\"\n#include \"config_reader_thread_safe_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    class config_reader_thread_safe_1 \n    {\n\n        /*!                \n            CONVENTION\n                - get_mutex() == *m\n                - *cr == the config reader being extended\n                - block_table[x] == (void*)&block(x)\n                - block_table.size() == the number of blocks in *cr\n                - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)\n                - if (own_pointers) then\n                    - this object owns the m and cr pointers and should delete them when destructed \n        !*/\n        \n    public:\n\n        config_reader_thread_safe_1 (\n            const config_reader_base* base,\n            rmutex* m_\n        );\n\n        config_reader_thread_safe_1();\n\n        typedef typename config_reader_base::config_reader_error config_reader_error;\n        typedef typename config_reader_base::config_reader_access_error config_reader_access_error;\n\n        config_reader_thread_safe_1(\n            std::istream& in\n        );\n\n        config_reader_thread_safe_1(\n            const std::string& config_file \n        );\n\n        virtual ~config_reader_thread_safe_1(\n        ); \n\n        void clear (\n        );\n\n        void load_from (\n            std::istream& in\n        );\n\n        void load_from (\n            const std::string& config_file \n        );\n\n        bool is_key_defined (\n            const std::string& key\n        ) const;\n\n        bool is_block_defined (\n            const std::string& name\n        ) const;\n\n        typedef config_reader_thread_safe_1 this_type;\n        const this_type& block (\n            const std::string& name\n        ) const;\n\n        const std::string& operator[] (\n            const std::string& key\n        ) const;\n\n        template <\n            typename queue_of_strings\n            >\n        void get_keys (\n            queue_of_strings& keys\n        ) const;\n\n        template <\n            typename queue_of_strings\n            >\n        void get_blocks (\n            queue_of_strings& blocks\n        ) const;\n\n        inline const rmutex& get_mutex (\n        ) const;\n\n    private:\n\n        void fill_block_table (\n        );\n        /*!\n            ensures\n                - block_table.size() == the number of blocks in cr \n                - block_table[key] == a config_reader_thread_safe_1 that contains &cr.block(key)\n        !*/\n\n        rmutex* m;\n        config_reader_base* cr;\n        map_string_void block_table;\n        const bool own_pointers;\n\n        // restricted functions\n        config_reader_thread_safe_1(config_reader_thread_safe_1&);     \n        config_reader_thread_safe_1& operator=(config_reader_thread_safe_1&);\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    config_reader_thread_safe_1(\n        const config_reader_base* base,\n        rmutex* m_\n    ) :\n        m(m_),\n        cr(const_cast<config_reader_base*>(base)),\n        own_pointers(false)\n    {\n        fill_block_table();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    config_reader_thread_safe_1(\n    ) :\n        m(0),\n        cr(0),\n        own_pointers(true)\n    {\n        try\n        {\n            m = new rmutex;\n            cr = new config_reader_base;\n        }\n        catch (...)\n        {\n            if (m) delete m;\n            if (cr) delete cr;\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    clear(\n    )\n    {\n        auto_mutex M(*m);\n        cr->clear();\n        fill_block_table();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    load_from(\n        std::istream& in\n    )\n    {\n        auto_mutex M(*m);\n        cr->load_from(in);\n        fill_block_table();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    load_from(\n        const std::string& config_file\n    )\n    {\n        auto_mutex M(*m);\n        cr->load_from(config_file);\n        fill_block_table();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    config_reader_thread_safe_1(\n        std::istream& in\n    ) :\n        m(0),\n        cr(0),\n        own_pointers(true)\n    {\n        try\n        {\n            m = new rmutex;\n            cr = new config_reader_base(in);\n            fill_block_table();\n        }\n        catch (...)\n        {\n            if (m) delete m;\n            if (cr) delete cr;\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    config_reader_thread_safe_1(\n        const std::string& config_file\n    ) :\n        m(0),\n        cr(0),\n        own_pointers(true)\n    {\n        try\n        {\n            m = new rmutex;\n            cr = new config_reader_base(config_file);\n            fill_block_table();\n        }\n        catch (...)\n        {\n            if (m) delete m;\n            if (cr) delete cr;\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    ~config_reader_thread_safe_1(\n    ) \n    {\n        if (own_pointers)\n        {\n            delete m;\n            delete cr;\n        }\n\n        // clear out the block table\n        block_table.reset();\n        while (block_table.move_next())\n        {\n            delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());\n        }\n        block_table.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    bool config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    is_key_defined (\n        const std::string& key\n    ) const\n    {\n        auto_mutex M(*m);\n        return cr->is_key_defined(key);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    bool config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    is_block_defined (\n        const std::string& name\n    ) const\n    {\n        auto_mutex M(*m);\n        return cr->is_block_defined(name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    const config_reader_thread_safe_1<config_reader_base,map_string_void>& config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    block (\n        const std::string& name\n    ) const\n    {\n        auto_mutex M(*m);\n        if (block_table.is_in_domain(name) == false)\n        {\n            throw config_reader_access_error(name,\"\");\n        }\n\n        return *static_cast<config_reader_thread_safe_1*>(block_table[name]);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    const std::string& config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    operator[] (\n        const std::string& key\n    ) const\n    {\n        auto_mutex M(*m);\n        return (*cr)[key];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    template <\n        typename queue_of_strings\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    get_keys (\n        queue_of_strings& keys\n    ) const\n    {\n        auto_mutex M(*m);\n        cr->get_keys(keys);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    template <\n        typename queue_of_strings\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    get_blocks (\n        queue_of_strings& blocks\n    ) const\n    {\n        auto_mutex M(*m);\n        cr->get_blocks(blocks);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    const rmutex& config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    get_mutex (\n    ) const\n    {\n        return *m;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//      private member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename config_reader_base,\n        typename map_string_void\n        >\n    void config_reader_thread_safe_1<config_reader_base,map_string_void>::\n    fill_block_table (\n    ) \n    {\n        // first empty out the block table\n        block_table.reset();\n        while (block_table.move_next())\n        {\n            delete static_cast<config_reader_thread_safe_1*>(block_table.element().value());\n        }\n        block_table.clear();\n\n        std::vector<std::string> blocks;\n        cr->get_blocks(blocks);\n\n        // now fill the block table up to match what is in cr\n        for (unsigned long i = 0; i < blocks.size(); ++i)\n        {\n            config_reader_thread_safe_1* block = new config_reader_thread_safe_1(&cr->block(blocks[i]),m);\n            void* temp = block;\n            block_table.add(blocks[i],temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONFIG_READER_THREAD_SAFe_\n\n\n"
  },
  {
    "path": "dlib/config_reader/config_reader_thread_safe_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_\n#ifdef DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_\n\n#include <string>\n#include <iosfwd>\n#include \"config_reader_kernel_abstract.h\"\n#include \"../threads/threads_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    class config_reader_thread_safe \n    {\n\n        /*!                \n            WHAT THIS EXTENSION DOES FOR config_reader \n                This object extends a normal config_reader by simply wrapping all \n                its member functions inside mutex locks to make it safe to use\n                in a threaded program.  \n\n                So this object provides an interface identical to the one defined\n                in the config_reader/config_reader_kernel_abstract.h file except that\n                the rmutex returned by get_mutex() is always locked when this \n                object's member functions are called.\n        !*/\n    \n    public:\n\n        const rmutex& get_mutex (\n        ) const;\n        /*!\n            ensures\n                - returns the rmutex used to make this object thread safe.  i.e. returns\n                  the rmutex that is locked when this object's functions are called.\n        !*/\n\n    };\n\n}\n\n#endif // DLIB_CONFIG_READER_THREAD_SAFe_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/config_reader.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONFIG_READEr_\n#define DLIB_CONFIG_READEr_\n\n#include \"config_reader/config_reader_kernel_1.h\"\n#include \"map.h\"\n#include \"tokenizer.h\"\n#include \"cmd_line_parser/get_option.h\"\n\n#include \"algs.h\"\n#include \"is_kind.h\"\n\n\nnamespace dlib\n{\n\n    typedef config_reader_kernel_1<\n        map<std::string,std::string>::kernel_1b,\n        map<std::string,void*>::kernel_1b,\n        tokenizer::kernel_1a\n        > config_reader;\n\n    template <> struct is_config_reader<config_reader> { const static bool value = true; };\n\n#ifndef DLIB_ISO_CPP_ONLY\n    typedef config_reader_thread_safe_1<\n        config_reader,\n        map<std::string,void*>::kernel_1b\n        > config_reader_thread_safe;\n\n    template <> struct is_config_reader<config_reader_thread_safe> { const static bool value = true; };\n#endif // DLIB_ISO_CPP_ONLY\n\n\n}\n\n#endif // DLIB_CONFIG_READEr_\n\n"
  },
  {
    "path": "dlib/console_progress_indicator.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_\n#define DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_\n\n#include <cmath>\n#include <chrono>\n#include <limits>\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class console_progress_indicator\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for reporting how long a task will take\n                to complete.  \n\n                For example, consider the following bit of code:\n\n                    console_progress_indicator pbar(100)\n                    for (int i = 1; i <= 100; ++i)\n                    {\n                        pbar.print_status(i);\n                        long_running_operation();\n                    }\n\n                The above code will print a message to the console each iteration\n                which shows the current progress and how much time is remaining until\n                the loop terminates.\n        !*/\n\n    public:\n\n        inline explicit console_progress_indicator (\n            double target_value \n        ); \n        /*!\n            ensures\n                - #target() == target_value\n        !*/\n\n        inline void reset (\n            double target_value\n        );\n        /*!\n            ensures\n                - #target() == target_value\n                - performs the equivalent of:\n                    *this = console_progress_indicator(target_value)\n                    (i.e. resets this object with a new target value)\n\n        !*/\n\n        inline double target (\n        ) const;\n        /*!\n            ensures\n                - This object attempts to measure how much time is\n                  left until we reach a certain targeted value.  This\n                  function returns that targeted value.\n        !*/\n\n        inline bool print_status (\n            double cur,\n            bool always_print = false,\n            std::ostream& out = std::clog\n        );\n        /*!\n            ensures\n                - print_status() assumes it is called with values which are linearly\n                  approaching target().  It will display the current progress and attempt\n                  to predict how much time is remaining until cur becomes equal to target().\n                - prints a status message to out which indicates how much more time is\n                  left until cur is equal to target()\n                - if (always_print) then\n                    - This function prints to the screen each time it is called.\n                - else\n                    - This function throttles the printing so that at most 1 message is\n                      printed each second.  Note that it won't print anything to the screen\n                      until about one second has elapsed.  This means that the first call\n                      to print_status() never prints to the screen.\n                - This function returns true if it prints to the screen and false\n                  otherwise.\n        !*/\n\n        inline void finish (\n            std::ostream& out = std::cout\n        ) const;\n        /*!\n            ensures\n                - This object prints the completed progress and the elapsed time to out.\n                  It is meant to be called after the loop we are tracking the progress of.\n        !*/\n\n    private:\n\n        double target_val;\n        std::chrono::time_point<std::chrono::steady_clock> start_time;\n        double first_val;\n        double seen_first_val;\n        std::chrono::time_point<std::chrono::steady_clock> last_time;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                               IMPLEMENTATION DETAILS\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    console_progress_indicator::\n    console_progress_indicator (\n        double target_value \n    ) :\n        target_val(target_value),\n        start_time(std::chrono::steady_clock::now()),\n        first_val(0),\n        seen_first_val(false),\n        last_time(std::chrono::steady_clock::now())\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool console_progress_indicator::\n    print_status (\n        double cur,\n        bool always_print,\n        std::ostream& out\n    )\n    {\n        const auto cur_time = std::chrono::steady_clock::now();\n\n        // if this is the first time print_status has been called\n        // then collect some information and exit.  We will print status\n        // on the next call.\n        if (!seen_first_val)\n        {\n            start_time = cur_time;\n            last_time = cur_time;\n            first_val = cur;\n            seen_first_val = true;\n            return false;\n        }\n\n        if ((cur_time - last_time) >= std::chrono::seconds(1) || always_print)\n        {\n            last_time = cur_time;\n            const auto delta_t = cur_time - start_time;\n            double delta_val = std::abs(cur - first_val);\n\n            // don't do anything if cur is equal to first_val\n            if (delta_val < std::numeric_limits<double>::epsilon())\n                return false;\n\n            const auto rem_time = delta_t / delta_val * std::abs(target_val - cur);\n\n            const auto oldflags = out.flags();\n            out.setf(std::ios::fixed,std::ios::floatfield);\n            std::streamsize ss;\n\n            // adapt the precision based on whether the target val is an integer\n            if (std::trunc(target_val) == target_val)\n                ss = out.precision(0);\n            else\n                ss = out.precision(2);\n\n            out << \"Progress: \" << cur << \"/\" << target_val;\n            ss = out.precision(2);\n            out << \" (\" << cur / target_val * 100. << \"%). \";\n\n            const auto hours = std::chrono::duration_cast<std::chrono::hours>(rem_time);\n            const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(rem_time) - hours;\n            const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(rem_time) - hours - minutes;\n            out << \"Time remaining: \";\n            if (rem_time >= std::chrono::hours(1))\n                out << hours.count() << \"h \";\n            if (rem_time >= std::chrono::minutes(1))\n                out << minutes.count() << \"min \";\n            out << seconds.count() << \"s.                \\r\" << std::flush;\n\n            // restore previous output flags and precision settings\n            out.flags(oldflags);\n            out.precision(ss);\n\n            return true;\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double console_progress_indicator::\n    target (\n    ) const\n    {\n        return target_val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void console_progress_indicator::\n    reset (\n        double target_value\n    ) \n    {\n        *this = console_progress_indicator(target_value);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void console_progress_indicator::\n    finish (\n        std::ostream& out\n    ) const\n    {\n        const auto oldflags = out.flags();\n        out.setf(std::ios::fixed,std::ios::floatfield);\n        std::streamsize ss;\n\n        // adapt the precision based on whether the target val is an integer\n        if (std::trunc(target_val) == target_val)\n            ss = out.precision(0);\n        else\n            ss = out.precision(2);\n\n        out << \"Progress: \" << target_val << \"/\" << target_val;\n        out << \" (100.00%). \";\n        const auto delta_t = std::chrono::steady_clock::now() - start_time;\n        const auto hours = std::chrono::duration_cast<std::chrono::hours>(delta_t);\n        const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(delta_t) - hours;\n        const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(delta_t) - hours - minutes;\n        out << \"Time elapsed: \";\n        if (delta_t >= std::chrono::hours(1))\n            out << hours.count() << \"h \";\n        if (delta_t >= std::chrono::minutes(1))\n            out << minutes.count() << \"min \";\n        out << seconds.count() << \"s.                \" << std::endl;\n\n        // restore previous output flags and precision settings\n        out.flags(oldflags);\n        out.precision(ss);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CONSOLE_PROGRESS_INDiCATOR_Hh_\n\n"
  },
  {
    "path": "dlib/constexpr_if.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IF_CONSTEXPR_H\n#define DLIB_IF_CONSTEXPR_H\n\n#include \"overloaded.h\"\n#include \"type_traits.h\"\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n        const auto _ = [](auto&& arg) -> decltype(auto) { return std::forward<decltype(arg)>(arg); };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template<bool... v>\n    constexpr auto bools(std::integral_constant<bool, v>...)\n    /*!\n        ensures\n            - returns a type list of compile time booleans.\n    !*/\n    {\n        return types_<std::integral_constant<bool,v>...>{};\n    }\n\n    using true_t  = types_<std::true_type>;\n    using false_t = types_<std::false_type>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename... T,\n        typename... Cases\n    >\n    constexpr decltype(auto) switch_(\n        types_<T...> /*meta_obj*/,\n        Cases&&...   cases\n    )\n    /*!\n        requires\n            - meta_obj combines a set of initial types. These are used as compile-time initial conditions.\n            - cases is a set of overload-able conditional branches.\n            - at least one of the cases is callable given meta_obj.\n            - each case statement has signature auto(types_<>..., auto _) where _ is an identity function\n              with identical behaviour to std::identity. This is used to make each generic lambda artificially\n              dependent on the function body. This allows semantic analysis of the lambdas to be performed AFTER\n              the correct lambda is chosen depending on meta_obj. This is the crucial bit that makes switch_() behave\n              in a similar way to \"if constexpr()\" in C++17. Make sure to use _ on one of the objects in the lambdas.\n        ensures\n            - calls the correct conditional branch.\n            - the correct conditional branch is selected at compile-time.\n            - Note, each branch can return different types, and the return type of the switch_() function\n              is that of the compile-time selected branch.\n\n            Here is an example:\n\n            template<typename T>\n            auto perform_correct_action(T& obj)\n            {\n                return switch_(\n                    types_<T>{},\n                    [&](types_<A>, auto _) {\n                        return _(obj).set_something_specific_to_A_and_return_something();\n                    },\n                    [&](types_<B>, auto _) {\n                        return _(obj).set_something_specific_to_B_and_return_something();\n                    },\n                    [&](auto...) {\n                        // Default case statement. Do something sensible.\n                        return false;\n                    }\n                );\n            }\n\n            Here is another example:\n\n            template<typename T>\n            auto transfer_state(T& a, T& b)\n            {\n                return switch_(\n                    bools(std::is_move_constructible<T>{}, std::is_copy_constructible<T>{}),\n                    [&](true_t, auto, auto _) {\n                        // T is both move-constructible. Copy semantics can be anything\n                        a = std::move(_(b));\n                        return move_tag{}; // Just for fun, we return different types in each branch.\n                    },\n                    [&](auto, true_t, auto _) {\n                        // T is copy-constructible, Move semantics can be anything. Though in this case,\n                        // if it had been move-constructible, the first branch would have been selected.\n                        // So in this case, it is not move-constructible.\n                        a = _(b);\n                        return copy_tag{};\n                    },\n                    [&](auto...) {\n                        // Default case statement\n                        return dont_care_tag{};\n                    }\n                );\n            }\n      !*/\n    {\n        return overloaded(std::forward<Cases>(cases)...)(types_<T>{}..., detail::_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif //DLIB_IF_CONSTEXPR_H\n"
  },
  {
    "path": "dlib/control/approximate_linear_models.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_APPROXIMATE_LINEAR_MODELS_Hh_\n#define DLIB_APPROXIMATE_LINEAR_MODELS_Hh_\n\n#include \"approximate_linear_models_abstract.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    struct process_sample\n    {\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n        process_sample(){}\n\n        process_sample(\n            const state_type& s,\n            const action_type& a,\n            const state_type& n,\n            const double& r\n        ) : state(s), action(a), next_state(n), reward(r) {}\n\n        state_type  state;\n        action_type action;\n        state_type  next_state;\n        double reward;\n    };\n\n    template < typename feature_extractor >\n    void serialize (const process_sample<feature_extractor>& item, std::ostream& out)\n    {\n        serialize(item.state, out);\n        serialize(item.action, out);\n        serialize(item.next_state, out);\n        serialize(item.reward, out);\n    }\n\n    template < typename feature_extractor >\n    void deserialize (process_sample<feature_extractor>& item, std::istream& in)\n    {\n        deserialize(item.state, in);\n        deserialize(item.action, in);\n        deserialize(item.next_state, in);\n        deserialize(item.reward, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class policy\n    {\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n\n        policy (\n        )\n        {\n            w.set_size(fe.num_features());\n            w = 0;\n        }\n\n        policy (\n            const matrix<double,0,1>& weights_,\n            const feature_extractor& fe_\n        ) : w(weights_), fe(fe_) {}\n\n        action_type operator() (\n            const state_type& state\n        ) const\n        {\n            return fe.find_best_action(state,w);\n        }\n\n        const feature_extractor& get_feature_extractor (\n        ) const { return fe; }\n\n        const matrix<double,0,1>& get_weights (\n        ) const { return w; }\n\n\n    private:\n        matrix<double,0,1> w;\n        feature_extractor fe;\n    };\n\n    template < typename feature_extractor >\n    inline void serialize(const policy<feature_extractor>& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.get_feature_extractor(), out);\n        serialize(item.get_weights(), out);\n    }\n    template < typename feature_extractor >\n    inline void deserialize(policy<feature_extractor>& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::policy object.\");\n        feature_extractor fe;\n        matrix<double,0,1> w;\n        deserialize(fe, in);\n        deserialize(w, in);\n        item = policy<feature_extractor>(w,fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_APPROXIMATE_LINEAR_MODELS_Hh_\n\n"
  },
  {
    "path": "dlib/control/approximate_linear_models_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_\n#ifdef DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct example_feature_extractor \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines the interface a feature extractor must implement if it\n                is to be used with the process_sample and policy objects defined at the\n                bottom of this file.  Moreover, it is meant to represent the core part\n                of a model used in a reinforcement learning algorithm.\n                \n                In particular, this object models a Q(state,action) function where\n                    Q(state,action) == dot(w, PSI(state,action))\n                    where PSI(state,action) is a feature vector and w is a parameter\n                    vector.\n\n                Therefore, a feature extractor defines how the PSI(x,y) feature vector is\n                calculated.  It also defines the types used to represent the state and\n                action objects. \n\n\n            THREAD SAFETY\n                Instances of this object are required to be threadsafe, that is, it should\n                be safe for multiple threads to make concurrent calls to the member\n                functions of this object.\n        !*/\n\n        // The state and actions can be any types so long as you provide typedefs for them.\n        typedef T state_type;\n        typedef U action_type; \n        // We can also say that the last element in the weight vector w must be 1.  This\n        // can be useful for including a prior into your model.\n        const static bool force_last_weight_to_1 = false;\n\n        example_feature_extractor(\n        );\n        /*!\n            ensures\n                - this object is properly initialized.\n        !*/\n\n        unsigned long num_features(\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the PSI() feature vector.  \n        !*/\n\n        action_type find_best_action (\n            const state_type& state,\n            const matrix<double,0,1>& w\n        ) const;\n        /*!\n            ensures\n                - returns the action A that maximizes Q(state,A) = dot(w,PSI(state,A)).\n                  That is, this function finds the best action to take in the given state\n                  when our model is parameterized by the given weight vector w.\n        !*/\n\n        void get_features (\n            const state_type& state,\n            const action_type& action,\n            matrix<double,0,1>& feats\n        ) const;\n        /*!\n            ensures\n                - #feats.size() == num_features()\n                - #feats == PSI(state,action)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    struct process_sample\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor\n                feature_extractor should implement the example_feature_extractor interface\n                defined at the top of this file.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object holds a training sample for a reinforcement learning algorithm.\n                In particular, it should be a sample from some process where the process\n                was in state this->state, then took this->action action which resulted in\n                receiving this->reward and ending up in the state this->next_state.\n        !*/\n\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n        process_sample(){}\n\n        process_sample(\n            const state_type& s,\n            const action_type& a,\n            const state_type& n,\n            const double& r\n        ) : state(s), action(a), next_state(n), reward(r) {}\n\n        state_type  state;\n        action_type action;\n        state_type  next_state;\n        double reward;\n    };\n\n    template < typename feature_extractor >\n    void serialize (const process_sample<feature_extractor>& item, std::ostream& out);\n    template < typename feature_extractor >\n    void deserialize (process_sample<feature_extractor>& item, std::istream& in);\n    /*!\n        provides serialization support.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class policy\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor\n                feature_extractor should implement the example_feature_extractor interface\n                defined at the top of this file.\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a policy based on the supplied feature_extractor model.  In\n                particular, it maps from feature_extractor::state_type to the best action\n                to take in that state.\n        !*/\n\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n\n        policy (\n        );\n        /*!\n            ensures\n                - #get_feature_extractor() == feature_extractor() \n                  (i.e. it will have its default value)\n                - #get_weights().size() == #get_feature_extractor().num_features()\n                - #get_weights() == 0\n        !*/\n\n        policy (\n            const matrix<double,0,1>& weights,\n            const feature_extractor& fe\n        ); \n        /*!\n            requires\n                - fe.num_features() == weights.size()\n            ensures\n                - #get_feature_extractor() == fe\n                - #get_weights() == weights\n        !*/\n\n        action_type operator() (\n            const state_type& state\n        ) const;\n        /*!\n            ensures\n                - returns get_feature_extractor().find_best_action(state,w);\n        !*/\n\n        const feature_extractor& get_feature_extractor (\n        ) const; \n        /*!\n            ensures\n                - returns the feature extractor used by this object\n        !*/\n\n        const matrix<double,0,1>& get_weights (\n        ) const; \n        /*!\n            ensures\n                - returns the parameter vector (w) associated with this object.  The length\n                  of the vector is get_feature_extractor().num_features().  \n        !*/\n\n    };\n\n    template < typename feature_extractor >\n    void serialize(const policy<feature_extractor>& item, std::ostream& out);\n    template < typename feature_extractor >\n    void deserialize(policy<feature_extractor>& item, std::istream& in);\n    /*!\n        provides serialization support.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n\n#endif // DLIB_APPROXIMATE_LINEAR_MODELS_ABSTRACT_Hh_\n \n"
  },
  {
    "path": "dlib/control/lspi.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LSPI_Hh_\n#define DLIB_LSPI_Hh_\n\n#include \"lspi_abstract.h\"\n#include \"approximate_linear_models.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class lspi\n    {\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n        explicit lspi(\n            const feature_extractor& fe_\n        ) : fe(fe_)\n        {\n            init();\n        }\n\n        lspi(\n        )\n        {\n            init();\n        }\n\n        double get_discount (\n        ) const { return discount; }\n\n        void set_discount (\n            double value\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(0 < value && value <= 1,\n                \"\\t void lspi::set_discount(value)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t value: \" << value \n                );\n            discount = value;\n        }\n\n        const feature_extractor& get_feature_extractor (\n        ) const { return fe; }\n\n        void be_verbose (\n        )\n        {\n            verbose = true;\n        }\n\n        void be_quiet (\n        )\n        {\n            verbose = false;\n        }\n\n        void set_epsilon (\n            double eps_\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(eps_ > 0,\n                \"\\t void lspi::set_epsilon(eps_)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t eps_: \" << eps_ \n                );\n            eps = eps_;\n        }\n\n        double get_epsilon (\n        ) const\n        { \n            return eps;\n        }\n\n        void set_lambda (\n            double lambda_ \n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(lambda_ >= 0,\n                \"\\t void lspi::set_lambda(lambda_)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t lambda_: \" << lambda_ \n                );\n            lambda = lambda_;\n        }\n\n        double get_lambda (\n        ) const \n        { \n            return lambda; \n        }\n\n        void set_max_iterations (\n            unsigned long max_iter\n        ) { max_iterations = max_iter; }\n\n        unsigned long get_max_iterations (\n        ) { return max_iterations; }\n\n        template <typename vector_type>\n        policy<feature_extractor> train (\n            const vector_type& samples\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(samples.size() > 0,\n                \"\\t policy lspi::train(samples)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                );\n\n            matrix<double,0,1> w(fe.num_features());\n            w = 0;\n            matrix<double,0,1> prev_w, b, f1, f2;\n\n            matrix<double> A;\n\n            double change; \n            unsigned long iter = 0;\n            do\n            {\n                A = identity_matrix<double>(fe.num_features())*lambda;\n                b = 0;\n                for (unsigned long i = 0; i < samples.size(); ++i)\n                {\n                    fe.get_features(samples[i].state, samples[i].action, f1);\n                    fe.get_features(samples[i].next_state, \n                                    fe.find_best_action(samples[i].next_state,w), \n                                    f2);\n                    A += f1*trans(f1 - discount*f2);\n                    b += f1*samples[i].reward;\n                }\n\n                prev_w = w;\n                if (feature_extractor::force_last_weight_to_1)\n                    w = join_cols(pinv(colm(A,range(0,A.nc()-2)))*(b-colm(A,A.nc()-1)),mat(1.0));\n                else\n                    w = pinv(A)*b;\n\n                change = length(w-prev_w);\n                ++iter;\n\n                if (verbose)\n                    std::cout << \"iteration: \" << iter << \"\\tchange: \" << change << std::endl;\n\n            } while(change > eps && iter < max_iterations);\n\n            return policy<feature_extractor>(w,fe);\n        }\n\n\n    private:\n\n        void init()\n        {\n            lambda = 0.01;\n            discount = 0.8;\n            eps = 0.01;\n            verbose = false;\n            max_iterations = 100;\n        }\n\n        double lambda;\n        double discount;\n        double eps;\n        bool verbose;\n        unsigned long max_iterations;\n        feature_extractor fe;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LSPI_Hh_\n\n"
  },
  {
    "path": "dlib/control/lspi_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LSPI_ABSTRACT_Hh_\n#ifdef DLIB_LSPI_ABSTRACT_Hh_\n\n#include \"approximate_linear_models_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class lspi\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor\n                feature_extractor should implement the example_feature_extractor interface\n                defined at the top of dlib/control/approximate_linear_models_abstract.h\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is an implementation of the reinforcement learning algorithm\n                described in the following paper:\n                    Lagoudakis, Michail G., and Ronald Parr. \"Least-squares policy\n                    iteration.\" The Journal of Machine Learning Research 4 (2003):\n                    1107-1149.\n                \n                This means that it takes a bunch of training data in the form of\n                process_samples and outputs a policy that hopefully performs well when run\n                on the process that generated those samples.\n        !*/\n\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::state_type state_type;\n        typedef typename feature_extractor::action_type action_type;\n\n        explicit lspi(\n            const feature_extractor& fe_\n        ); \n        /*!\n            ensures\n                - #get_feature_extractor() == fe_\n                - #get_lambda() == 0.01\n                - #get_discount == 0.8\n                - #get_epsilon() == 0.01\n                - is not verbose\n                - #get_max_iterations() == 100\n        !*/\n\n        lspi(\n        );\n        /*!\n            ensures\n                - #get_feature_extractor() == feature_extractor() \n                  (i.e. it will have its default value)\n                - #get_lambda() == 0.01\n                - #get_discount == 0.8\n                - #get_epsilon() == 0.01\n                - is not verbose\n                - #get_max_iterations() == 100\n        !*/\n\n        double get_discount (\n        ) const;\n        /*!\n            ensures\n                - returns the discount applied to the sum of rewards in the Bellman\n                  equation.\n        !*/\n\n        void set_discount (\n            double value\n        );\n        /*!\n            requires\n                - 0 < value <= 1\n            ensures\n                - #get_discount() == value\n        !*/\n\n        const feature_extractor& get_feature_extractor (\n        ) const;\n        /*!\n            ensures\n                - returns the feature extractor used by this object\n        !*/\n\n        void be_verbose (\n        );\n        /*!\n            ensures\n                - This object will print status messages to standard out so that a \n                  user can observe the progress of the algorithm.\n        !*/\n\n        void be_quiet (\n        );\n        /*!\n            ensures\n                - this object will not print anything to standard out\n        !*/\n\n        void set_epsilon (\n            double eps\n        );\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_epsilon() == eps\n        !*/\n\n        double get_epsilon (\n        ) const;\n        /*!\n            ensures\n                - returns the error epsilon that determines when training should stop.\n                  Smaller values may result in a more accurate solution but take longer to\n                  train.  \n        !*/\n\n        void set_lambda (\n            double lambda_ \n        ); \n        /*!\n            requires\n                - lambda >= 0\n            ensures\n                - #get_lambda() == lambda \n        !*/\n\n        double get_lambda (\n        ) const;\n        /*!\n            ensures\n                - returns the regularization parameter.  It is the parameter that \n                  determines the trade off between trying to fit the training data \n                  exactly or allowing more errors but hopefully improving the \n                  generalization ability of the resulting function.  Smaller values \n                  encourage exact fitting while larger values of lambda may encourage \n                  better generalization. \n        !*/\n\n        void set_max_iterations (\n            unsigned long max_iter\n        ); \n        /*!\n            ensures\n                - #get_max_iterations() == max_iter\n        !*/\n\n        unsigned long get_max_iterations (\n        ); \n        /*!\n            ensures\n                - returns the maximum number of iterations the SVM optimizer is allowed to\n                  run before it is required to stop and return a result.\n        !*/\n\n        template <\n            typename vector_type\n            >\n        policy<feature_extractor> train (\n            const vector_type& samples\n        ) const;\n        /*!\n            requires\n                - samples.size() > 0\n                - samples is something with an interface that looks like \n                  std::vector<process_sample<feature_extractor>>.  That is, it should\n                  be some kind of array of process_sample objects.\n            ensures\n                - Trains a policy based on the given data and returns the results.  The\n                  idea is to find a policy that will obtain the largest possible reward\n                  when run on the process that generated the samples.  In particular, \n                  if the returned policy is P then:\n                    - P(S) == the best action to take when in state S.\n                    - if (feature_extractor::force_last_weight_to_1) then\n                        - The last element of P.get_weights() is 1. \n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LSPI_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/control/mpc.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MPC_Hh_\n#define DLIB_MPC_Hh_\n\n#include \"mpc_abstract.h\"\n#include \"../matrix.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n    template <\n        long S_,\n        long I_,\n        unsigned long horizon_\n        >\n    class mpc\n    {\n\n    public:\n\n        const static long S = S_;\n        const static long I = I_;\n        const static unsigned long horizon = horizon_;\n\n        mpc(\n        ) \n        {\n            A = 0;\n            B = 0;\n            C = 0;\n            Q = 0;\n            R = 0;\n            lower = 0;\n            upper = 0;\n\n            max_iterations = 0;\n            eps = 0.01;\n            for (unsigned long i = 0; i < horizon; ++i)\n            {\n                target[i].set_size(A.nr());\n                target[i] = 0;\n\n                controls[i].set_size(B.nc());\n                controls[i] = 0;\n            }\n            lambda = 0;\n        }\n\n        mpc (\n            const matrix<double,S,S>& A_,\n            const matrix<double,S,I>& B_,\n            const matrix<double,S,1>& C_,\n            const matrix<double,S,1>& Q_,\n            const matrix<double,I,1>& R_,\n            const matrix<double,I,1>& lower_,\n            const matrix<double,I,1>& upper_\n        ) : A(A_), B(B_), C(C_), Q(Q_), R(R_), lower(lower_), upper(upper_)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(A.nr() > 0 && B.nc() > 0,\n                \"\\t mpc::mpc()\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t A.nr(): \" <<  A.nr()\n                << \"\\n\\t B.nc(): \" <<  B.nc()\n                );\n\n            DLIB_ASSERT(A.nr() == A.nc() && \n                        A.nr() == B.nr() && \n                        A.nr() == C.nr() && \n                        A.nr() == Q.nr(),\n                \"\\t mpc::mpc()\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t A.nr(): \" <<  A.nr()\n                << \"\\n\\t A.nc(): \" <<  A.nc()\n                << \"\\n\\t B.nr(): \" <<  B.nr()\n                << \"\\n\\t C.nr(): \" <<  C.nr()\n                << \"\\n\\t Q.nr(): \" <<  Q.nr()\n                );\n            DLIB_ASSERT(\n                        B.nc() == R.nr() && \n                        B.nc() == lower.nr() && \n                        B.nc() == upper.nr() ,\n                \"\\t mpc::mpc()\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t B.nr(): \" <<  B.nr()\n                << \"\\n\\t B.nc(): \" <<  B.nc()\n                << \"\\n\\t lower.nr(): \" <<  lower.nr()\n                << \"\\n\\t upper.nr(): \" <<  upper.nr()\n                );\n            DLIB_ASSERT(min(Q) >= 0 &&\n                        min(R) >  0 &&\n                        min(upper-lower) >= 0,\n                \"\\t mpc::mpc()\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t min(Q): \" << min(Q) \n                << \"\\n\\t min(R): \" << min(R) \n                << \"\\n\\t min(upper-lower): \" << min(upper-lower) \n                );\n\n\n            max_iterations = 10000;\n            eps = 0.01;\n            for (unsigned long i = 0; i < horizon; ++i)\n            {\n                target[i].set_size(A.nr());\n                target[i] = 0;\n\n                controls[i].set_size(B.nc());\n                controls[i] = 0;\n            }\n\n            // Bound the maximum eigenvalue of the hessian by computing the trace of the\n            // hessian matrix. \n            lambda = sum(R)*horizon;\n            matrix<double,S,S> temp = diagm(Q);\n            for (unsigned long c = 0; c < horizon; ++c)\n            {\n                lambda += trace(trans(B)*temp*B);\n                Q_diag[horizon-c-1] = diag(trans(B)*temp*B);\n                temp = trans(A)*temp*A + diagm(Q);\n            }\n\n        }\n\n        const matrix<double,S,S>& get_A (\n        ) const { return A; }\n        const matrix<double,S,I>& get_B (\n        ) const { return B; }\n        const matrix<double,S,1>& get_C (\n        ) const { return C; }\n        const matrix<double,S,1>& get_Q (\n        ) const { return Q; }\n        const matrix<double,I,1>& get_R (\n        ) const { return R; }\n        const matrix<double,I,1>& get_lower_constraints (\n        ) const { return lower; }\n        const matrix<double,I,1>& get_upper_constraints (\n        ) const { return upper; }\n\n        void set_target (\n            const matrix<double,S,1>& val,\n            const unsigned long time\n        )\n        {\n            DLIB_ASSERT(time < horizon,\n                \"\\t void mpc::set_target(eps_)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t time: \" << time \n                << \"\\n\\t horizon: \" << horizon \n                );\n\n            target[time] = val;\n        }\n\n        void set_target (\n            const matrix<double,S,1>& val\n        )\n        {\n            for (unsigned long i = 0; i < horizon; ++i)\n                target[i] = val;\n        }\n\n        void set_last_target (\n            const matrix<double,S,1>& val\n        )\n        {\n            set_target(val, horizon-1);\n        }\n\n        const matrix<double,S,1>& get_target (\n            const unsigned long time\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(time < horizon,\n                \"\\t matrix mpc::get_target(eps_)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t time: \" << time \n                << \"\\n\\t horizon: \" << horizon \n                );\n\n            return target[time];\n        }\n\n        double get_target_error_threshold (\n        ) const \n        {\n            return target_error_threshold;\n        }\n\n        void set_target_error_threshold (\n            const double thresh \n        )\n        {\n            target_error_threshold = thresh;\n        }\n\n        unsigned long get_max_iterations (\n        ) const { return max_iterations; }\n\n        void set_max_iterations (\n            unsigned long max_iter\n        ) \n        {\n            max_iterations = max_iter;\n        }\n\n        void set_epsilon (\n            double eps_\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(eps_ > 0,\n                \"\\t void mpc::set_epsilon(eps_)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t eps_: \" << eps_ \n                );\n            eps = eps_;\n        }\n\n        double get_epsilon (\n        ) const\n        { \n            return eps;\n        }\n\n        matrix<double,I,1> operator() (\n            const matrix<double,S,1>& current_state\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(min(R) > 0 && A.nr() == current_state.size(),\n                \"\\t matrix mpc::operator(current_state)\"\n                << \"\\n\\t invalid inputs were given to this function\"\n                << \"\\n\\t min(R): \" << min(R) \n                << \"\\n\\t A.nr(): \" << A.nr() \n                << \"\\n\\t current_state.size(): \" << current_state.size() \n                );\n\n            // Shift the inputs over by one time step so we can use them to warm start the\n            // optimizer.\n            for (unsigned long i = 1; i < horizon; ++i)\n                controls[i-1] = controls[i];\n\n            solve_linear_mpc(current_state);\n\n            for (unsigned long i = 1; i < horizon; ++i)\n                target[i-1] = target[i];\n\n            return controls[0];\n        }\n\n    private:\n\n\n        // These temporary variables here just to avoid reallocating them on each call to\n        // operator().\n        matrix<double,S,1> M[horizon];\n        matrix<double,I,1> MM[horizon];\n        matrix<double,I,1> df[horizon]; \n        matrix<double,I,1> v[horizon]; \n        matrix<double,I,1> v_old[horizon]; \n\n        void solve_linear_mpc (\n            const matrix<double,S,1>& initial_state\n        )\n        {\n            // make it so MM == trans(K)*Q*(M-target)\n            M[0] = A*initial_state + C;\n            for (unsigned long i = 1; i < horizon; ++i)\n                M[i] = A*M[i-1] + C;\n            double min_error_seen = std::numeric_limits<double>::infinity();\n            for (unsigned long i = 0; i < horizon; ++i) {\n                M[i] = diagm(Q)*(M[i]-target[i]);\n                if (target_error_threshold >= 0) {\n                    const double current_error = dot(M[i]-target[i], M[i]);\n                    min_error_seen = std::min(current_error, min_error_seen);\n                    // Once our trajectory gets us within target_error_threshold of the target at any time\n                    // then we essentially stop caring about what happens at times after that.  This\n                    // gives us a \"just hit the target, I don't care what happens after the hit\" model.\n                    if (min_error_seen < target_error_threshold) \n                    {\n                        // Make it so all future errors now appear to be 0.  E.g. it is as if target[i]\n                        // was equal to the state the current control sequence generates at time i.\n                        M[i] = 0;\n                    }\n                }\n            }\n            for (long i = (long)horizon-2; i >= 0; --i)\n                M[i] += trans(A)*M[i+1];\n            for (unsigned long i = 0; i < horizon; ++i)\n                MM[i] = trans(B)*M[i];\n\n\n\n            unsigned long iter = 0;\n            for (; iter < max_iterations; ++iter)\n            {\n                // compute current gradient and put it into df.\n                // df == H*controls + MM;\n                M[0] = B*controls[0];\n                for (unsigned long i = 1; i < horizon; ++i)\n                    M[i] = A*M[i-1] + B*controls[i];\n                for (unsigned long i = 0; i < horizon; ++i)\n                    M[i] = diagm(Q)*M[i];\n                for (long i = (long)horizon-2; i >= 0; --i)\n                    M[i] += trans(A)*M[i+1];\n                for (unsigned long i = 0; i < horizon; ++i)\n                    df[i] = MM[i] + trans(B)*M[i] + diagm(R)*controls[i];\n\n\n\n                // Check the stopping condition, which is the magnitude of the largest element\n                // of the gradient.\n                double max_df = 0;\n                unsigned long max_t = 0;\n                long max_v = 0;\n                for (unsigned long i = 0; i < horizon; ++i)\n                {\n                    for (long j = 0; j < controls[i].size(); ++j)\n                    {\n                        // if this variable isn't an active constraint then we care about it's\n                        // derivative.\n                        if (!((controls[i](j) <= lower(j) && df[i](j) > 0) || \n                              (controls[i](j) >= upper(j) && df[i](j) < 0)))\n                        {\n                            if (std::abs(df[i](j)) > max_df)\n                            {\n                                max_df = std::abs(df[i](j));\n                                max_t = i;\n                                max_v = j;\n                            }\n                        }\n                    }\n                }\n                if (max_df < eps)\n                    break;\n\n\n\n                // We will start out by doing a little bit of coordinate descent because it\n                // allows us to optimize individual variables exactly.  Since we are warm\n                // starting each iteration with a really good solution this helps speed\n                // things up a lot.\n                const unsigned long smo_iters = 50;\n                if (iter < smo_iters)\n                {\n                    if (Q_diag[max_t](max_v) == 0) continue;\n\n                    // Take the optimal step but just for one variable.\n                    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);\n                    controls[max_t](max_v) = put_in_range(lower(max_v), upper(max_v), controls[max_t](max_v));\n\n                    // If this is the last SMO iteration then don't forget to initialize v\n                    // for the gradient steps.\n                    if (iter+1 == smo_iters)\n                    {\n                        for (unsigned long i = 0; i < horizon; ++i)\n                            v[i] = controls[i];\n                    }\n                }\n                else\n                {\n                    // Take a projected gradient step.\n                    for (unsigned long i = 0; i < horizon; ++i)\n                    {\n                        v_old[i] = v[i];\n                        v[i] = dlib::clamp(controls[i] - 1.0/lambda * df[i], lower, upper);\n                        controls[i] = dlib::clamp(v[i] + (std::sqrt(lambda)-1)/(std::sqrt(lambda)+1)*(v[i]-v_old[i]), lower, upper);\n                    }\n                }\n            }\n        }\n\n        unsigned long max_iterations;\n        double eps;\n        double target_error_threshold = -1;\n\n        matrix<double,S,S> A;\n        matrix<double,S,I> B;\n        matrix<double,S,1> C;\n        matrix<double,S,1> Q;\n        matrix<double,I,1> R;\n        matrix<double,I,1> lower;\n        matrix<double,I,1> upper;\n        matrix<double,S,1> target[horizon]; \n\n        double lambda; // abound on the largest eigenvalue of the hessian matrix.\n        matrix<double,I,1> Q_diag[horizon]; \n        matrix<double,I,1> controls[horizon]; \n\n    };\n\n}\n\n#endif // DLIB_MPC_Hh_\n\n"
  },
  {
    "path": "dlib/control/mpc_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MPC_ABSTRACT_Hh_\n#ifdef DLIB_MPC_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    template <\n        long S_,\n        long I_,\n        unsigned long horizon_\n        >\n    class mpc\n    {\n        /*!\n            REQUIREMENTS ON horizon_\n                horizon_ > 0\n\n            REQUIREMENTS ON S_\n                S_ >= 0\n\n            REQUIREMENTS ON I_\n                I_ >= 0\n            \n            WHAT THIS OBJECT REPRESENTS\n                This object implements a linear model predictive controller.  To explain\n                what that means, suppose you have some process you want to control and the\n                process dynamics are described by the linear equation:\n                    x_{i+1} = A*x_i + B*u_i + C\n                That is, the next state the system goes into is a linear function of its\n                current state (x_i) and the current control (u_i) plus some constant bias\n                or disturbance.  \n                \n                A model predictive controller can find the control (u) you should apply to\n                drive the state (x) to some reference value, or alternatively to make the\n                state track some reference time-varying sequence.  It does this by\n                simulating the process for horizon_ time steps and selecting the control\n                that leads to the best performance over the next horizon_ steps.\n                \n                To be precise, each time you ask this object for a control, it solves the\n                following quadratic program:\n        \n                    min    sum_i trans(x_i-target_i)*Q*(x_i-target_i) + trans(u_i)*R*u_i \n                  x_i,u_i\n\n                    such that: x_0     == current_state \n                               x_{i+1} == A*x_i + B*u_i + C\n                               lower <= u_i <= upper\n                               0 <= i < horizon_\n\n                and reports u_0 as the control you should take given that you are currently\n                in current_state.  Q and R are user supplied matrices that define how we\n                penalize variations away from the target state as well as how much we want\n                to avoid generating large control signals.  \n                \n                Finally, the algorithm we use to solve this quadratic program is based\n                largely on the method described in:\n                  A Fast Gradient method for embedded linear predictive control (2011)\n                  by Markus Kogel and Rolf Findeisen\n        !*/\n\n    public:\n\n        const static long S = S_;\n        const static long I = I_;\n        const static unsigned long horizon = horizon_;\n\n        mpc(\n        );\n        /*!\n            ensures\n                - #get_max_iterations() == 0\n                - The A,B,C,Q,R,lower, and upper parameter matrices are filled with zeros.\n                  Therefore, to use this object you must initialize it via the constructor\n                  that supplies these parameters.\n                - #get_target_error_threshold() == -1\n        !*/\n\n        mpc (\n            const matrix<double,S,S>& A,\n            const matrix<double,S,I>& B,\n            const matrix<double,S,1>& C,\n            const matrix<double,S,1>& Q,\n            const matrix<double,I,1>& R,\n            const matrix<double,I,1>& lower,\n            const matrix<double,I,1>& upper\n        ); \n        /*!\n            requires\n                - A.nr() > 0\n                - B.nc() > 0\n                - A.nr() == A.nc() == B.nr() == C.nr() == Q.nr()\n                - B.nc() == R.nr() == lower.nr() == upper.nr()\n                - min(Q) >= 0\n                - min(R) > 0\n                - min(upper-lower) >= 0\n            ensures\n                - #get_A() == A\n                - #get_B() == B\n                - #get_C() == C\n                - #get_Q() == Q\n                - #get_R() == R\n                - #get_lower_constraints() == lower\n                - #get_upper_constraints() == upper \n                - for all valid i:\n                    - get_target(i) == a vector of all zeros\n                    - get_target(i).size() == A.nr()\n                - #get_max_iterations() == 10000 \n                - #get_epsilon() == 0.01\n                - #get_target_error_threshold() == -1\n        !*/\n\n        const matrix<double,S,S>& get_A (\n        ) const; \n        /*!\n            ensures\n                - returns the A matrix from the quadratic program defined above. \n        !*/\n\n        const matrix<double,S,I>& get_B (\n        ) const; \n        /*!\n            ensures\n                - returns the B matrix from the quadratic program defined above. \n        !*/\n\n        const matrix<double,S,1>& get_C (\n        ) const;\n        /*!\n            ensures\n                - returns the C matrix from the quadratic program defined above. \n        !*/\n\n        const matrix<double,S,1>& get_Q (\n        ) const;\n        /*!\n            ensures\n                - returns the diagonal of the Q matrix from the quadratic program defined\n                  above. \n        !*/\n\n        const matrix<double,I,1>& get_R (\n        ) const;\n        /*!\n            ensures\n                - returns the diagonal of the R matrix from the quadratic program defined\n                  above. \n        !*/\n\n        const matrix<double,I,1>& get_lower_constraints (\n        ) const;\n        /*!\n            ensures\n                - returns the lower matrix from the quadratic program defined above.  All\n                  controls generated by this object will have values no less than this\n                  lower bound.  That is, any control u will satisfy min(u-lower) >= 0.\n        !*/\n\n        const matrix<double,I,1>& get_upper_constraints (\n        ) const;\n        /*!\n            ensures\n                - returns the upper matrix from the quadratic program defined above.  All\n                  controls generated by this object will have values no larger than this\n                  upper bound.  That is, any control u will satisfy min(upper-u) >= 0.\n        !*/\n\n        const matrix<double,S,1>& get_target (\n            const unsigned long time\n        ) const;\n        /*!\n            requires\n                - time < horizon\n            ensures\n                - This object will try to find the control sequence that results in the\n                  process obtaining get_target(time) state at the indicated time.  Note\n                  that the next time instant after \"right now\" is time 0. \n        !*/\n\n        void set_target (\n            const matrix<double,S,1>& val,\n            const unsigned long time\n        );\n        /*!\n            requires\n                - time < horizon\n            ensures\n                - #get_target(time) == val\n        !*/\n\n        void set_target (\n            const matrix<double,S,1>& val\n        );\n        /*!\n            ensures\n                - for all valid t:\n                    - #get_target(t) == val\n        !*/\n\n        void set_last_target (\n            const matrix<double,S,1>& val\n        );\n        /*!\n            ensures\n                - performs: set_target(val, horizon-1)\n        !*/\n\n        double get_target_error_threshold (\n        ) const;\n        /*!\n            ensures\n                - The target error terms in the objective function with values less than\n                  get_target_error_threshold() are ignored.  That is, the\n                  trans(x_i-target_i)*Q*(x_i-target_i) terms with values less than this are dropped\n                  from the objective function.  Therefore, setting get_target_error_threshold() to a\n                  value >= 0 allows you to encode a control law that says \"find me the controls that\n                  make the target error less than or equal to this at some point, but I don't care\n                  what happens at times after that.\"\n        !*/\n\n        void set_target_error_threshold (\n            const double thresh \n        );\n        /*!\n            ensures\n                - #target_error_threshold() == thresh\n        !*/\n\n\n\n        unsigned long get_max_iterations (\n        ) const; \n        /*!\n            ensures\n                - When operator() is called it solves an optimization problem to\n                  get_epsilon() precision to determine the next control action.  In\n                  particular, we run the optimizer until the magnitude of each element of\n                  the gradient vector is less than get_epsilon() or until\n                  get_max_iterations() solver iterations have been executed.\n        !*/\n\n        void set_max_iterations (\n            unsigned long max_iter\n        );\n        /*!\n            ensures\n                - #get_max_iterations() == max_iter\n        !*/\n\n        void set_epsilon (\n            double eps\n        );\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_epsilon() == eps\n        !*/\n\n        double get_epsilon (\n        ) const;\n        /*!\n            ensures\n                - When operator() is called it solves an optimization problem to\n                  get_epsilon() precision to determine the next control action.  In\n                  particular, we run the optimizer until the magnitude of each element of\n                  the gradient vector is less than get_epsilon() or until\n                  get_max_iterations() solver iterations have been executed.  This means\n                  that smaller epsilon values will give more accurate outputs but may take\n                  longer to compute.\n        !*/\n\n        matrix<double,I,1> operator() (\n            const matrix<double,S,1>& current_state\n        );\n        /*!\n            requires\n                - min(R) > 0\n                - A.nr() == current_state.size()\n            ensures\n                - Solves the model predictive control problem defined by the arguments to\n                  this object's constructor, assuming that the starting state is given by\n                  current_state.  Then we return the control that should be taken in the\n                  current state that best optimizes the quadratic objective function\n                  defined above.\n                - We also shift over the target states so that you only need to update the\n                  last one (if you are using non-zero target states) via a call to\n                  set_last_target()).  In particular, for all valid t, it will be the case\n                  that:\n                    - #get_target(t) == get_target(t+1)\n                    - #get_target(horizon-1) == get_target(horizon-1)\n        !*/\n\n    };\n\n}\n\n#endif // DLIB_MPC_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/control.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CONTRoL_\n#define DLIB_CONTRoL_\n\n#include \"control/lspi.h\"\n#include \"control/mpc.h\"\n\n#endif // DLIB_CONTRoL_\n\n\n"
  },
  {
    "path": "dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_1_\n#define DLIB_CPP_PRETTY_PRINTER_KERNEl_1_\n\n#include <string>\n#include <iostream>\n#include <sstream>\n#include \"cpp_pretty_printer_kernel_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename stack,\n        typename tok\n        >\n    class cpp_pretty_printer_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON stack\n                must be an implementation of stack/stack_kernel_abstract.h and\n                stack::type == unsigned long\n\n            REQUIREMENTS ON tok\n                must be an implementation of tokenizer/tokenizer_kernel_abstract.h\n\n            INFO\n                This implementation applies a color scheme, turns include directives \n                such as #include \"file.h\" into links to file.h.html, and it also puts \n                HTML anchor points on function and class declarations.\n        !*/\n\n    public:\n\n        cpp_pretty_printer_kernel_1 (        \n        );\n\n        virtual ~cpp_pretty_printer_kernel_1 (\n        );\n\n        void print (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n\n        void print_and_number (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n\n    private:\n\n        const std::string htmlify (\n            const std::string& str\n        ) const;\n        /*!\n            ensures\n                - str == str but with any '<' replaced with '&lt;', any '>' replaced\n                  with '&gt;', and any '&' replaced with '&amp;'\n        !*/\n\n        // data members\n        mutable tok t;\n\n        void number (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - prints in to out and adds line numbers\n        !*/\n\n        // restricted functions\n        cpp_pretty_printer_kernel_1(const cpp_pretty_printer_kernel_1&);        // copy constructor\n        cpp_pretty_printer_kernel_1& operator=(const cpp_pretty_printer_kernel_1&);    // assignment operator\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    cpp_pretty_printer_kernel_1<stack,tok>::\n    cpp_pretty_printer_kernel_1 (        \n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    cpp_pretty_printer_kernel_1<stack,tok>::\n    ~cpp_pretty_printer_kernel_1 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_1<stack,tok>::\n    print (\n        std::istream& in,\n        std::ostream& out,\n        const std::string& title\n    ) const\n    {\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_1::print\");\n\n        t.set_stream(in);\n\n        out << \"<html><!-- \" \n            << \"Created using the cpp_pretty_printer from the dlib C++ library.  See http://dlib.net for updates.\" \n            << \" --><head><title>\" << title << \"</title></head><body bgcolor='white'><pre>\\n\";\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_1::print\");\n\n        unsigned long scope = 0; // counts the number of new scopes we have entered \n                        // since we were at a scope where functions can be declared\n\n        bool recently_seen_class_keyword = false;\n            // true if we have seen the keywords class, struct, or enum and\n            // we have not seen any identifiers or { characters\n\n        bool recently_seen_include = false;\n            // true if we have seen the #include keyword and have not seen double\n            // quoted text or >\n\n        bool recently_seen_new_scope = false;  \n            // true if we have seen the keywords class, namespace, or struct and\n            // we have not seen the characters {, ), or ; since then\n\n        bool recently_seen_paren = false;\n            // true if we have seen a ) and we have only seen white_space or comments since\n\n        bool in_initialization_list = false;\n            // true if we have seen a ) followed by any white space or comments and then\n            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we \n            // have not yet seen the character { or ;\n\n        bool recently_seen_preprocessor = false;\n            // true if we have seen the #pragma or #if or #define or #elif keywords and have \n            // not seen an end of line.\n\n        bool recently_seen_extern = false;\n            // true if we have seen the extern keyword and haven't seen a ; or { yet.\n\n        unsigned long paren_count = 0; \n            // this is the number of ( we have seen minus the number of ) we have\n            // seen.\n            \n\n        int type;\n        stack scopes; // a stack to hold old scopes\n        std::string token, temp;\n        t.get_token(type,token);\n        while (type != tok::END_OF_FILE)\n        {\n            switch (type)\n            {\n            case tok::IDENTIFIER: // ------------------------------------------\n                if ( recently_seen_class_keyword)\n                {\n                    // this might be a class name so check if there is a \n                    // ; or identifier or * or & coming up.\n                    type = t.peek_type();\n                    temp.clear();\n                    if (type == tok::WHITE_SPACE)\n                    {\n                        t.get_token(type,temp);\n                        if (temp.find_first_of(\"\\n\\r\") != std::string::npos)\n                            recently_seen_preprocessor = false;\n                    }\n                    if (t.peek_type() != tok::IDENTIFIER &&\n                        t.peek_token() != \"*\" && t.peek_token() != \"&\")\n                    {\n                        // this is the name of a class or struct in a class or\n                        // struct declaration.\n                        out << \"<b><a name='\" << token << \"'></a>\" << token << \"</b>\" << temp;\n                    }\n                    else\n                    {\n                        out << token << temp;\n                    }\n                }\n                else if ( !in_initialization_list &&\n                     !recently_seen_preprocessor )\n                {\n                    // this might be a function name so check if there is a \n                    // ( coming up.\n                    type = t.peek_type();\n                    temp.clear();\n                    if (type == tok::WHITE_SPACE)\n                    {\n                        t.get_token(type,temp);\n                        type = t.peek_type();\n                    }\n                    if (type == tok::OTHER && t.peek_token() == \"(\")\n                    {\n                        if (scope == 0 && paren_count == 0)\n                        {\n                            // this is a function definition or prototype\n                            out << \"<b><a name='\" << token << \"'></a>\" << token << \"</b>\" << temp;\n                        }\n                        else\n                        {\n                            // this is a function call (probably) \n                            out << \"<font color='#BB00BB'>\" << token << \"</font>\" << temp;\n                        }\n                    }\n                    else\n                    {\n                        out << token << temp;\n                    }\n                }\n                else\n                {\n                    out << token;\n                }\n                \n\n\n                recently_seen_class_keyword = false;\n                recently_seen_paren = false;\n                break;\n\n            case tok::KEYWORD: // ---------------------------------------------\n                if (scope == 0 && token == \"operator\")\n                {\n                    // Doing this is sort of weird since operator is really a keyword\n                    // but I just like how this looks.\n                    out << \"<b><a name='\" << token << \"'></a>\" << token << \"</b>\";\n                }\n                // this isn't a keyword if it is something like #include <new>\n                else if ( token == \"true\" || token == \"false\")\n                {\n                    // color 'true' and 'false' the same way we color numbers\n                    out << \"<font color='#979000'>\" << token << \"</font>\";\n                }\n                else if (!recently_seen_include) \n                {\n                    // This is a normal keyword\n                    if (token == \"char\" || token == \"unsigned\" || token == \"signed\" ||\n                        token == \"short\" || token == \"int\" || token == \"long\" || \n                        token == \"float\" || token == \"double\" || token == \"bool\" ||\n                        token == \"void\" || token == \"size_t\" || token == \"wchar_t\")\n                    {\n                        out << \"<font color='#0000FF'><u>\" << token << \"</u></font>\";\n                    }\n                    else\n                    {\n                        out << \"<font color='#0000FF'>\" << token << \"</font>\";\n                    }\n                }\n                else\n                {\n                    out << token;\n                }\n\n                if (token == \"#include\") \n                {\n                    recently_seen_include = true;\n                }\n                else if (token == \"class\")\n                {\n                    recently_seen_new_scope = true;\n                    recently_seen_class_keyword = true;\n                }\n                else if (token == \"namespace\")\n                {\n                    recently_seen_new_scope = true;\n                }\n                else if (token == \"enum\")\n                {\n                    recently_seen_class_keyword = true;\n                }\n                else if (token == \"struct\")\n                {\n                    recently_seen_new_scope = true;\n                    recently_seen_class_keyword = true;\n                }\n                else if (token == \"#pragma\" || token == \"#if\" || token == \"#define\" || token == \"#elif\")\n                {\n                    recently_seen_preprocessor = true;\n                }\n                else if (token == \"extern\")\n                {\n                    recently_seen_extern = true;\n                }\n                recently_seen_paren = false;\n                break;\n\n            case tok::COMMENT: // ---------------------------------------------\n                {\n                    // if this is a special anchor comment\n                    if (token.size() > 4 &&\n                        token[0] == '/' &&\n                        token[1] == '*' &&\n                        token[2] == '!' &&\n                        token[3] == 'A' &&\n                        token[4] == ' '\n                    )\n                    {\n                        temp = token;\n                        std::istringstream sin(token);\n                        sin >> temp;\n                        sin >> temp;\n                        sin.get();\n                        // if there was still more stuff in the token then we are ok.\n                        if (sin)\n                            out << \"<a name='\" << temp << \"'/>\";\n                    }\n                    out << \"<font color='#009900'>\" << htmlify(token) << \"</font>\";\n                }\n                break;\n\n            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------\n                {\n                    out << \"<font color='#FF0000'>\" << htmlify(token) << \"</font>\";\n                    recently_seen_paren = false;\n                }\n                break;\n\n            case tok::NUMBER: // -----------------------------------------\n                {\n                    out << \"<font color='#979000'>\" << token << \"</font>\";\n                    recently_seen_include = false;\n                }\n                break;\n\n            case tok::WHITE_SPACE: // -----------------------------------------\n                {\n                    out << token;\n                    if (token.find_first_of(\"\\n\\r\") != std::string::npos)\n                        recently_seen_preprocessor = false;\n                }\n                break;\n\n            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------\n                {\n                    if (recently_seen_include)\n                    {\n                        // this is the name of an included file\n                        recently_seen_include = false;\n                        out << \"<a style='text-decoration:none' href='\" << htmlify(token) << \".html'>\" << htmlify(token) << \"</a>\";                \n                    }\n                    else\n                    {\n                        // this is just a normal quoted string\n                        out << \"<font color='#CC0000'>\" << htmlify(token) << \"</font>\";\n                    }\n                    recently_seen_paren = false;\n                }\n                break;\n\n            case tok::OTHER: // -----------------------------------------------               \n                switch (token[0])\n                {\n                case '{':\n                    out << \"<b>{</b>\";  \n                    // if we are entering a new scope\n                    if (recently_seen_new_scope || recently_seen_extern)\n                    {\n                        recently_seen_new_scope = false;\n                        scopes.push(scope);\n                        scope = 0;\n                    }\n                    else\n                    {\n                        ++scope;\n                    }\n                    in_initialization_list = false;\n                    recently_seen_paren = false;\n                    recently_seen_class_keyword = false;\n                    recently_seen_extern = false;\n                    break;\n                case '}':\n                    out << \"<b>}</b>\";\n                    if (scope > 0)\n                    {\n                        --scope;\n                    }\n                    else if (scopes.size())\n                    {\n                        scopes.pop(scope);\n                    }\n                    recently_seen_paren = false;\n                    break;\n\n                case ':':\n                    out << ':';\n                    if (recently_seen_paren && scope == 0 && \n                        recently_seen_preprocessor == false)\n                    {\n                        in_initialization_list = true;\n                    }\n                    recently_seen_paren = false;\n                    break;\n\n                case ';': \n                    out << ';';\n                    recently_seen_new_scope = false;\n                    recently_seen_paren = false;\n                    recently_seen_extern = false;\n                    break;\n\n                case ')':\n                    out << \"<font face='Lucida Console'>)</font>\";\n                    recently_seen_paren = true;\n                    recently_seen_new_scope = false;\n                    --paren_count;\n                    break;\n\n                case '(':\n                    out << \"<font face='Lucida Console'>(</font>\";\n                    recently_seen_paren = false;\n                    ++paren_count;\n                    break;\n\n                case '>':\n                    recently_seen_include = false;\n                    out << \"<font color='#5555FF'>&gt;</font>\";\n                    recently_seen_paren = false;\n                    break;\n\n                case '<':\n                    out << \"<font color='#5555FF'>&lt;</font>\";\n                    recently_seen_paren = false;\n                    break;\n\n                case '&':\n                    out << \"<font color='#5555FF'>&amp;</font>\";\n                    recently_seen_paren = false;\n                    break;\n\n                case '=':\n                case '+':\n                case '-':\n                case '/':\n                case '*':\n                case '!':\n                case '|':\n                case '%':\n                    out << \"<font color='#5555FF'>\" << token << \"</font>\";\n                    recently_seen_paren = false;\n                    break;\n\n                default:\n                    out << token;\n                    recently_seen_paren = false;\n                    break;\n\n                } // switch (token[0])\n                break;\n\n            } // switch (type)\n\n            t.get_token(type,token);\n        } // while (type != tok::END_OF_FILE)\n\n\n        out << \"\\n</pre></body></html>\";\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_1::print\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_1<stack,tok>::\n    print_and_number (\n        std::istream& in,\n        std::ostream& out,\n        const std::string& title\n    ) const\n    {\n        std::ostringstream sout;\n        print(in,sout,title);\n        std::istringstream sin(sout.str());\n        number(sin,out);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_1<stack,tok>::\n    number (\n        std::istream& in,\n        std::ostream& out\n    ) const\n    {\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_1::number\");\n\n        std::string space = \"&nbsp;&nbsp;&nbsp;\";\n        std::ios::int_type ch;\n        unsigned long count = 1;\n        while ((ch=in.get()) != EOF)\n        {\n            if (ch != '\\n')\n            {\n                out << (char)ch;    \n            }\n            else\n            {\n                out << \"\\n<font color='555555'>\" << count << \" </font> \" + space;\n                ++count;\n                if (count == 10)\n                    space = \"&nbsp;&nbsp;\";\n                if (count == 100)\n                    space = \"&nbsp;\";\n                if (count == 1000)\n                    space = \"\";            \n            }\n        }\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_1::number\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    const std::string cpp_pretty_printer_kernel_1<stack,tok>::\n    htmlify (\n        const std::string& str\n    ) const\n    {\n        std::string::size_type i;\n        std::string temp;\n        for (i = 0; i < str.size(); ++i)\n        {\n            if (str[i] == '<')\n                temp += \"&lt;\";\n            else if (str[i] == '>')\n                temp += \"&gt;\";\n            else if (str[i] == '&')\n                temp += \"&amp;\";\n            else\n                temp += str[i];\n        }\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_2.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_PRETTY_PRINTER_KERNEl_2_\n#define DLIB_CPP_PRETTY_PRINTER_KERNEl_2_\n\n#include <string>\n#include <iostream>\n#include <sstream>\n#include \"cpp_pretty_printer_kernel_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename stack,\n        typename tok\n        >\n    class cpp_pretty_printer_kernel_2 \n    {\n        /*!\n            REQUIREMENTS ON stack\n                must be an implementation of stack/stack_kernel_abstract.h and\n                stack::type == unsigned long\n\n            REQUIREMENTS ON tok\n                must be an implementation of tokenizer/tokenizer_kernel_abstract.h\n\n            INFO\n                This implementation applies a black and white color scheme suitable \n                for printing on a black and white printer.  It also places the document \n                title prominently at the top of the pretty printed source file.\n        !*/\n\n    public:\n\n        cpp_pretty_printer_kernel_2 (        \n        );\n\n        virtual ~cpp_pretty_printer_kernel_2 (\n        );\n\n        void print (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n\n        void print_and_number (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n\n    private:\n\n        // data members\n        mutable tok t;\n\n        const std::string htmlify (\n            const std::string& str\n        ) const;\n        /*!\n            ensures\n                - str == str but with any '<' replaced with '&lt;', any '>' replaced\n                  with '&gt;', and any '&' replaced with '&amp;'\n        !*/\n\n        void number (\n            std::istream& in,\n            std::ostream& out\n        ) const;\n        /*!\n            ensures\n                - prints in to out and adds line numbers\n        !*/\n\n        // restricted functions\n        cpp_pretty_printer_kernel_2(const cpp_pretty_printer_kernel_2&);        // copy constructor\n        cpp_pretty_printer_kernel_2& operator=(const cpp_pretty_printer_kernel_2&);    // assignment operator\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    cpp_pretty_printer_kernel_2<stack,tok>::\n    cpp_pretty_printer_kernel_2 (        \n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    cpp_pretty_printer_kernel_2<stack,tok>::\n    ~cpp_pretty_printer_kernel_2 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_2<stack,tok>::\n    print (\n        std::istream& in,\n        std::ostream& out,\n        const std::string& title\n    ) const\n    {\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_2::print\");\n\n        t.set_stream(in);\n\n        out << \"<html><!-- \"\n            << \"Created using the cpp_pretty_printer from the dlib C++ library.  See http://dlib.net for updates.\" \n            << \" --><head>\"\n            << \"<title>\" << title << \"</title></head><body bgcolor='white'>\"\n            << \"<h1><center>\" << title << \"</center></h1><pre>\\n\"\n            << \"<font style='font-size:9pt' face='Lucida Console'>\\n\";\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_2::print\");\n\n        unsigned long scope = 0; // counts the number of new scopes we have entered \n                        // since we were at a scope where functions can be declared\n\n        bool recently_seen_class_keyword = false;\n            // true if we have seen the keywords class or struct and\n            // we have not seen any identifiers or { characters\n\n        bool recently_seen_include = false;\n            // true if we have seen the #include keyword and have not seen double\n            // quoted text or >\n\n        bool recently_seen_new_scope = false;  \n            // true if we have seen the keywords class, namespace, or struct and\n            // we have not seen the characters {, ), or ; since then\n\n        bool recently_seen_paren = false;\n            // true if we have seen a ) and we have only seen white_space or comments since\n\n        bool in_initialization_list = false;\n            // true if we have seen a ) followed by any white space or comments and then\n            // followed by a : (in scope==0 with recently_seen_preprocessor==false) and we \n            // have not yet seen the character { or ;\n\n        bool recently_seen_preprocessor = false;\n            // true if we have seen the #pragma or #if or #define or #elif keyword and \n            // have not seen an identifier.\n\n\n        bool recently_seen_extern = false;\n            // true if we have seen the extern keyword and haven't yet seen a \n            // { or ; character.\n\n        unsigned long paren_count = 0; \n            // this is the number of ( we have seen minus the number of ) we have\n            // seen.\n            \n\n        int type;\n        stack scopes; // a stack to hold old scopes\n        std::string token, temp;\n        t.get_token(type,token);\n        while (type != tok::END_OF_FILE)\n        {\n            switch (type)\n            {\n            case tok::IDENTIFIER: // ------------------------------------------\n                if ( recently_seen_class_keyword)\n                {\n                    // this might be a class name so check if there is a \n                    // ; or identifier or * or &amp; coming up.\n                    type = t.peek_type();\n                    temp.clear();\n                    if (type == tok::WHITE_SPACE)\n                    {\n                        t.get_token(type,temp);\n                        if (temp.find_first_of(\"\\n\\r\") != std::string::npos)\n                            recently_seen_preprocessor = false;\n                    }\n                    if (t.peek_token() != \";\" && t.peek_type() != tok::IDENTIFIER &&\n                        t.peek_token() != \"*\" && t.peek_token() != \"&amp;\")\n                    {\n                        // this is the name of a class or struct in a class or\n                        // struct declaration.\n                        out << \"<b><i>\" << token << \"</i></b>\" << temp;\n                    }\n                    else\n                    {\n                        out << token << temp;\n                    }\n                }\n                else if ( !in_initialization_list &&\n                     !recently_seen_preprocessor &&\n                     scope == 0 &&\n                     paren_count == 0)\n                {\n                    // this might be a function name so check if there is a \n                    // ( coming up.\n                    type = t.peek_type();\n                    temp.clear();\n                    if (type == tok::WHITE_SPACE)\n                    {\n                        t.get_token(type,temp);\n                        type = t.peek_type();\n                    }\n                    if (type == tok::OTHER && t.peek_token() == \"(\")\n                    {\n                        // this is a function definition or prototype\n                        out << \"<b><i>\" << token << \"</i></b>\" << temp;\n                    }\n                    else\n                    {\n                        out << token << temp;\n                    }\n                }\n                else\n                {\n                    out << token;\n                }\n                \n\n\n                recently_seen_class_keyword = false;\n                recently_seen_paren = false;\n                break;\n\n            case tok::KEYWORD: // ---------------------------------------------\n                if (scope == 0 && token == \"operator\")\n                {\n                    // Doing this is sort of weird since operator is really a keyword\n                    // but I just like how this looks.\n                    out << \"<b><i>\" << token << \"</i></b>\";\n                }\n                // this isn't a keyword if it is something like #include <new>\n                else if (!recently_seen_include) \n                {\n                    // This is a normal keyword\n                    out << \"<u><font face='Fixedsys'>\" << token << \"</font></u>\";\n                }\n                else\n                {\n                    out << token;\n                }\n\n                if (token == \"#include\") \n                {\n                    recently_seen_include = true;\n                }\n                else if (token == \"class\")\n                {\n                    recently_seen_new_scope = true;\n                    recently_seen_class_keyword = true;\n                }\n                else if (token == \"namespace\")\n                {\n                    recently_seen_new_scope = true;\n                }\n                else if (token == \"struct\")\n                {\n                    recently_seen_new_scope = true;\n                    recently_seen_class_keyword = true;\n                }\n                else if (token == \"#pragma\" || token == \"#define\" || token == \"#elif\" || token == \"#if\")\n                {\n                    recently_seen_preprocessor = true;\n                }\n                else if (token == \"extern\")\n                {\n                    recently_seen_extern = true;\n                }\n                recently_seen_paren = false;\n                break;\n\n            case tok::COMMENT: // ---------------------------------------------\n                {\n                    out << \"<font face='Courier New'>\" << htmlify(token) << \"</font>\";\n                }\n                break;\n\n            case tok::SINGLE_QUOTED_TEXT: // ----------------------------------\n                {\n                    out << htmlify(token);\n                    recently_seen_paren = false;\n                }\n                break;\n\n            case tok::WHITE_SPACE: // -----------------------------------------\n                {\n                    out << token;\n                    if (token.find_first_of(\"\\n\\r\") != std::string::npos)\n                        recently_seen_preprocessor = false;\n                }\n                break;\n\n            case tok::DOUBLE_QUOTED_TEXT: // ----------------------------------\n                {                    \n                    out << htmlify(token);\n                    recently_seen_paren = false;\n                    recently_seen_include = false;\n                }\n                break;\n\n            case tok::NUMBER:\n            case tok::OTHER: // -----------------------------------------------               \n                switch (token[0])\n                {\n                case '{':\n                    out << \"<b>{</b>\";  \n                    // if we are entering a new scope\n                    if (recently_seen_new_scope || recently_seen_extern)\n                    {\n                        recently_seen_new_scope = false;\n                        scopes.push(scope);\n                        scope = 0;\n                    }\n                    else\n                    {\n                        ++scope;\n                    }\n                    in_initialization_list = false;\n                    recently_seen_paren = false;\n                    recently_seen_class_keyword = false;\n                    recently_seen_extern = false;\n                    break;\n                case '}':\n                    out << \"<b>}</b>\";\n                    if (scope > 0)\n                    {\n                        --scope;\n                    }\n                    else if (scopes.size())\n                    {\n                        scopes.pop(scope);\n                    }\n                    recently_seen_paren = false;\n                    break;\n\n                case ':':\n                    out << ':';\n                    if (recently_seen_paren && scope == 0 &&\n                        recently_seen_preprocessor == false)\n                    {\n                        in_initialization_list = true;\n                    }\n                    recently_seen_paren = false;\n                    break;\n\n                case ';': \n                    out << ';';\n                    recently_seen_new_scope = false;\n                    recently_seen_paren = false;\n                    recently_seen_extern = false;\n                    break;\n\n                case ')':\n                    out << ')';\n                    recently_seen_paren = true;\n                    recently_seen_new_scope = false;\n                    --paren_count;\n                    break;\n\n                case '(':\n                    out << '(';\n                    recently_seen_paren = false;\n                    ++paren_count;\n                    break;\n\n                case '>':\n                    recently_seen_include = false;\n                    out << \"&gt;\";\n                    recently_seen_paren = true;\n                    break;\n\n                case '<':\n                    out << \"&lt;\";\n                    recently_seen_paren = true;\n                    break;\n\n                case '&':\n                    out << \"&amp;\";\n                    recently_seen_paren = true;\n                    break;\n\n                default:\n                    out << token;\n                    recently_seen_paren = false;\n                    if (token == \"&gt;\")\n                        recently_seen_include = false;\n                    break;\n\n                } // switch (token[0])\n                break;\n\n            } // switch (type)\n\n            t.get_token(type,token);\n        } // while (type != tok::END_OF_FILE)\n\n\n        out << \"</font></pre></body></html>\";\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_2::print\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_2<stack,tok>::\n    print_and_number (\n        std::istream& in,\n        std::ostream& out,\n        const std::string& title\n    ) const\n    {\n        std::ostringstream sout;\n        print(in,sout,title);\n        std::istringstream sin(sout.str());\n        number(sin,out);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    void cpp_pretty_printer_kernel_2<stack,tok>::\n    number (\n        std::istream& in,\n        std::ostream& out\n    ) const\n    {\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_2::number\");\n\n        std::string space = \"&nbsp;&nbsp;&nbsp;\";\n        std::ios::int_type ch;\n        unsigned long count = 1;\n        while ((ch=in.get()) != EOF)\n        {\n            if (ch != '\\n')\n            {\n                out << (char)ch;    \n            }\n            else\n            {\n                out << \"\\n<i><font face='Courier New'>\" << count << \" </font></i> \" + space;\n                ++count;\n                if (count == 10)\n                    space = \"&nbsp;&nbsp;\";\n                if (count == 100)\n                    space = \"&nbsp;\";\n                if (count == 1000)\n                    space = \"\";            \n            }\n        }\n        if (!out)\n            throw std::ios::failure(\"error occurred in cpp_pretty_printer_kernel_2::number\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stack,\n        typename tok\n        >\n    const std::string cpp_pretty_printer_kernel_2<stack,tok>::\n    htmlify (\n        const std::string& str\n    ) const\n    {\n        std::string::size_type i;\n        std::string temp;\n        for (i = 0; i < str.size(); ++i)\n        {\n            if (str[i] == '<')\n                temp += \"&lt;\";\n            else if (str[i] == '>')\n                temp += \"&gt;\";\n            else if (str[i] == '&')\n                temp += \"&amp;\";\n            else\n                temp += str[i];\n        }\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/cpp_pretty_printer/cpp_pretty_printer_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_\n#ifdef DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_\n\n#include <string>\n#include <ioswfd>\n\nnamespace dlib\n{\n\n    class cpp_pretty_printer \n    {\n        /*!\n            INITIAL VALUE\n                This object does not have any state associated with it.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an HTML pretty printer for C++ source code. \n\n        !*/\n\n    public:\n\n        cpp_pretty_printer (        \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~cpp_pretty_printer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        void print (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n        /*!\n            ensures\n                - treats data from in as C++ source code and pretty prints it in\n                  HTML and writes it to out.\n                - The title of the HTML document written to out will be title\n            throws\n                - std::ios_base::failure\n                    If there was a problem writing to out then this exception will \n                    be thrown.                      \n                - any other exception\n                    This exception may be thrown if there is any other problem. \n        !*/\n\n        void print_and_number (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& title\n        ) const;\n        /*!\n            ensures\n                - treats data from in as C++ source code and pretty prints it in\n                  HTML with line numbers and writes it to out.\n                - The title of the HTML document written to out will be title\n            throws\n                - std::ios_base::failure\n                    If there was a problem writing to out then this exception will \n                    be thrown.                      \n                - any other exception\n                    This exception may be thrown if there is any other problem. \n        !*/\n\n    private:\n\n        // restricted functions\n        cpp_pretty_printer(const cpp_pretty_printer&);        // copy constructor\n        cpp_pretty_printer& operator=(const cpp_pretty_printer&);    // assignment operator\n\n    };    \n\n}\n\n#endif // DLIB_CPP_PRETTY_PRINTER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/cpp_pretty_printer.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_PRETTY_PRINTEr_\n#define DLIB_CPP_PRETTY_PRINTEr_\n\n\n#include \"cpp_pretty_printer/cpp_pretty_printer_kernel_1.h\"\n#include \"cpp_pretty_printer/cpp_pretty_printer_kernel_2.h\"\n#include \"cpp_tokenizer.h\"\n#include \"stack.h\"\n\nnamespace dlib\n{\n\n    class cpp_pretty_printer\n    {\n        cpp_pretty_printer() {}\n\n\n        typedef stack<unsigned long>::kernel_1a stack;\n        typedef cpp_tokenizer::kernel_1a tok;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     cpp_pretty_printer_kernel_1<stack,tok>\n                    kernel_1a;\n\n        // kernel_2a        \n        typedef     cpp_pretty_printer_kernel_2<stack,tok>\n                    kernel_2a;\n\n    };\n}\n\n#endif // DLIB_CPP_PRETTY_PRINTEr_\n\n"
  },
  {
    "path": "dlib/cpp_tokenizer/cpp_tokenizer_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_TOKENIZER_KERNEl_1_\n#define DLIB_CPP_TOKENIZER_KERNEl_1_\n\n#include <string>\n#include <iostream>\n#include \"cpp_tokenizer_kernel_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    namespace cpp_tok_kernel_1_helper\n    {\n        struct token_text_pair\n        {\n            std::string token;\n            int type=0;\n        };        \n\n    }\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    class cpp_tokenizer_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON tok\n                tok must be an implementation of tokenizer/tokenizer_kernel_abstract.h\n\n            REQUIREMENTS ON queue\n                queue must be an implementation of queue/queue_kernel_abstract.h\n                and must have T==cpp_tok_kernel_1_helper::token_text_pair\n\n            REQUIREMENTS ON set\n                set must be an implemention of set/set_kernel_abstract.h or\n                hash_set/hash_set_kernel_abstract.h and must have T==std::string.\n\n            INITIAL VALUE\n                - keywords == a set of all the C++ keywords\n                - tokenizer.stream_is_set() == false\n                - buffer.size() == 0\n                - tokenizer.get_identifier_head() == \"$_\" + tokenizer.lowercase_letters() + \n                  tokenizer.uppercase_letters()\n                - tokenizer.get_identifier_body() == \"$_\" + tokenizer.lowercase_letters() + \n                  tokenizer.uppercase_letters() + tokenizer.numbers()\n                - have_peeked == false\n\n\n            CONVENTION                  \n                - tokenizer.stream_is_set() == stream_is_set()\n                - tokenizer.get_stream() == get_stream()\n                - keywords == a set of all the C++ keywords\n\n                - tokenizer.get_identifier_head() == \"$_\" + tokenizer.lowercase_letters() + \n                  tokenizer.uppercase_letters()\n                - tokenizer.get_identifier_body() == \"$_\" + tokenizer.lowercase_letters() + \n                  tokenizer.uppercase_letters() + tokenizer.numbers()\n\n                - buffer == a queue of tokens.  This is where we put tokens \n                  we gathered early due to looking ahead.\n\n\n                - if (have_peeked) then\n                    - next_token == the next token to be returned from get_token()\n                    - next_type == the type of token in peek_token\n      !*/\n\n        typedef cpp_tok_kernel_1_helper::token_text_pair token_text_pair;\n\n    public:\n\n        enum \n        {\n            END_OF_FILE,\n            KEYWORD,\n            COMMENT,\n            SINGLE_QUOTED_TEXT,\n            DOUBLE_QUOTED_TEXT,\n            IDENTIFIER,\n            OTHER,\n            NUMBER,\n            WHITE_SPACE\n        };\n\n        cpp_tokenizer_kernel_1 (        \n        );\n\n        virtual ~cpp_tokenizer_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        void set_stream (\n            std::istream& in\n        );\n\n        bool stream_is_set (\n        ) const;\n\n        std::istream& get_stream (\n        ) const;\n\n        void get_token (\n            int& type,\n            std::string& token\n        );\n\n        int peek_type (\n        ) const;\n\n        const std::string& peek_token (\n        ) const;\n\n        void swap (\n            cpp_tokenizer_kernel_1<tok,queue,set>& item\n        );\n\n    private:\n\n        void buffer_token(\n            int type,\n            const std::string& token\n        )\n        /*!\n            ensures\n                - stores the token and its type into buffer\n        !*/\n        {\n            token_text_pair temp;\n            temp.token = token;\n            temp.type = type;\n            buffer.enqueue(temp);\n        }\n\n        void buffer_token(\n            int type,\n            char token\n        )\n        /*!\n            ensures\n                - stores the token and its type into buffer\n        !*/\n        {\n            token_text_pair temp;\n            temp.token = token;\n            temp.type = type;\n            buffer.enqueue(temp);\n        }\n\n        // restricted functions\n        cpp_tokenizer_kernel_1(const cpp_tokenizer_kernel_1<tok,queue,set>&);        // copy constructor\n        cpp_tokenizer_kernel_1<tok,queue,set>& operator=(const cpp_tokenizer_kernel_1<tok,queue,set>&);    // assignment operator\n\n        // data members\n        set keywords;\n        queue buffer;\n        tok tokenizer;\n\n        mutable std::string next_token;\n        mutable int next_type;\n        mutable bool have_peeked;\n\n\n    };    \n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    inline void swap (\n        cpp_tokenizer_kernel_1<tok,queue,set>& a, \n        cpp_tokenizer_kernel_1<tok,queue,set>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    cpp_tokenizer_kernel_1<tok,queue,set>::\n    cpp_tokenizer_kernel_1(        \n    ) :\n        have_peeked(false)\n    {\n        // add C++ keywords to keywords\n        std::string temp;\n        temp = \"#include\";              keywords.add(temp);\n        temp = \"__asm\";                 keywords.add(temp);\n        temp = \"_asm\";                  keywords.add(temp);        \n        temp = \"if\";                    keywords.add(temp);\n        temp = \"int\";                   keywords.add(temp);\n        temp = \"else\";                  keywords.add(temp);\n        temp = \"template\";              keywords.add(temp);\n        temp = \"void\";                  keywords.add(temp);\n        temp = \"false\";                 keywords.add(temp);\n        temp = \"class\";                 keywords.add(temp);\n        temp = \"public\";                keywords.add(temp);\n        temp = \"while\";                 keywords.add(temp);\n        temp = \"bool\";                  keywords.add(temp);\n        temp = \"new\";                   keywords.add(temp);\n        temp = \"delete\";                keywords.add(temp);\n        temp = \"true\";                  keywords.add(temp);\n        temp = \"typedef\";               keywords.add(temp);\n        temp = \"const\";                 keywords.add(temp);\n        temp = \"virtual\";               keywords.add(temp);\n        temp = \"inline\";                keywords.add(temp);\n        temp = \"for\";                   keywords.add(temp);\n        temp = \"break\";                 keywords.add(temp);\n        temp = \"struct\";                keywords.add(temp);\n        temp = \"float\";                 keywords.add(temp);\n        temp = \"case\";                  keywords.add(temp);\n        temp = \"enum\";                  keywords.add(temp);\n        temp = \"this\";                  keywords.add(temp);\n        temp = \"typeid\";                keywords.add(temp);\n        temp = \"double\";                keywords.add(temp);\n        temp = \"char\";                  keywords.add(temp);\n        temp = \"typename\";              keywords.add(temp);\n        temp = \"signed\";                keywords.add(temp);\n        temp = \"friend\";                keywords.add(temp);\n        temp = \"wint_t\";                keywords.add(temp);\n        temp = \"default\";               keywords.add(temp);\n        temp = \"asm\";                   keywords.add(temp);\n        temp = \"reinterpret_cast\";      keywords.add(temp);\n        temp = \"#define\";               keywords.add(temp);\n        temp = \"do\";                    keywords.add(temp);\n        temp = \"continue\";              keywords.add(temp);\n        temp = \"auto\";                  keywords.add(temp);\n        temp = \"unsigned\";              keywords.add(temp);\n        temp = \"size_t\";                keywords.add(temp);\n        temp = \"#undef\";                keywords.add(temp);\n        temp = \"#pragma\";               keywords.add(temp);\n        temp = \"namespace\";             keywords.add(temp);\n        temp = \"private\";               keywords.add(temp);\n        temp = \"#endif\";                keywords.add(temp);\n        temp = \"catch\";                 keywords.add(temp);\n        temp = \"#else\";                 keywords.add(temp);\n        temp = \"register\";              keywords.add(temp);\n        temp = \"volatile\";              keywords.add(temp);\n        temp = \"const_cast\";            keywords.add(temp);\n        temp = \"#end\";                  keywords.add(temp);\n        temp = \"mutable\";               keywords.add(temp);\n        temp = \"static_cast\";           keywords.add(temp);\n        temp = \"wchar_t\";               keywords.add(temp);\n        temp = \"#if\";                   keywords.add(temp);\n        temp = \"protected\";             keywords.add(temp);\n        temp = \"throw\";                 keywords.add(temp);\n        temp = \"using\";                 keywords.add(temp);\n        temp = \"dynamic_cast\";          keywords.add(temp);\n        temp = \"#ifdef\";                keywords.add(temp);\n        temp = \"return\";                keywords.add(temp);\n        temp = \"short\";                 keywords.add(temp);\n        temp = \"#error\";                keywords.add(temp);\n        temp = \"#line\";                 keywords.add(temp);\n        temp = \"explicit\";              keywords.add(temp);\n        temp = \"union\";                 keywords.add(temp);\n        temp = \"#ifndef\";               keywords.add(temp);\n        temp = \"try\";                   keywords.add(temp);\n        temp = \"sizeof\";                keywords.add(temp);\n        temp = \"goto\";                  keywords.add(temp);\n        temp = \"long\";                  keywords.add(temp);\n        temp = \"#elif\";                 keywords.add(temp);\n        temp = \"static\";                keywords.add(temp);\n        temp = \"operator\";              keywords.add(temp);  \n        temp = \"switch\";                keywords.add(temp);\n        temp = \"extern\";                keywords.add(temp);\n\n\n        // set the tokenizer's IDENTIFIER token for C++ identifiers\n        tokenizer.set_identifier_token(\n            \"$_\" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),\n            \"$_\" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() + \n            tokenizer.numbers()\n            );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    cpp_tokenizer_kernel_1<tok,queue,set>::\n    ~cpp_tokenizer_kernel_1 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    void cpp_tokenizer_kernel_1<tok,queue,set>::\n    clear(\n    )\n    {\n        tokenizer.clear();\n        buffer.clear();\n        have_peeked = false;\n\n        // set the tokenizer's IDENTIFIER token for C++ identifiers\n        tokenizer.set_identifier_token(\n            \"$_\" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters(),\n            \"$_\" + tokenizer.lowercase_letters() + tokenizer.uppercase_letters() + \n            tokenizer.numbers()\n            );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    void cpp_tokenizer_kernel_1<tok,queue,set>::\n    set_stream (\n        std::istream& in\n    )\n    {\n        tokenizer.set_stream(in);\n        buffer.clear();\n        have_peeked = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    bool cpp_tokenizer_kernel_1<tok,queue,set>::\n    stream_is_set (\n    ) const\n    {\n        return tokenizer.stream_is_set();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    std::istream& cpp_tokenizer_kernel_1<tok,queue,set>::\n    get_stream (\n    ) const\n    {\n        return tokenizer.get_stream();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    void cpp_tokenizer_kernel_1<tok,queue,set>::\n    get_token (\n        int& type,\n        std::string& token\n    )\n    {\n        if (!have_peeked)\n        {\n\n            if (buffer.size() > 0)\n            {\n                // just return what is in the buffer\n                token_text_pair temp;\n                buffer.dequeue(temp);\n                type = temp.type;\n                token = temp.token;\n                return;\n            }\n\n            tokenizer.get_token(type,token);\n\n            switch (type)\n            {\n            case tok::END_OF_FILE:\n                {\n                    type = END_OF_FILE;\n                } break;\n\n            case tok::END_OF_LINE:\n            case tok::WHITE_SPACE:\n                {\n                    type = tokenizer.peek_type();\n                    if (type == tok::END_OF_LINE || type == tok::WHITE_SPACE)\n                    {\n                        std::string temp;\n                        do\n                        {\n                            tokenizer.get_token(type,temp);\n                            token += temp;\n                            type = tokenizer.peek_type();\n                        }while (type == tok::END_OF_LINE || type == tok::WHITE_SPACE);\n                    }\n                    type = WHITE_SPACE;\n\n                } break;\n\n            case tok::NUMBER:\n                {\n                    // this could be a hex number such as 0xa33.  we should check for this.\n                    if (tokenizer.peek_type() == tok::IDENTIFIER && token == \"0\" && \n                        (tokenizer.peek_token()[0] == 'x' || tokenizer.peek_token()[0] == 'X'))\n                    {\n                        // this is a hex number so accumulate all the numbers and identifiers that follow\n                        // because they have to be part of the number\n                        std::string temp;\n                        tokenizer.get_token(type,temp);\n                        token = \"0\" + temp; \n\n                        // get the rest of the hex number\n                        while (tokenizer.peek_type() == tok::IDENTIFIER ||\n                               tokenizer.peek_type() == tok::NUMBER\n                               )\n                        {\n                            tokenizer.get_token(type,temp);\n                            token += temp;\n                        }\n\n                    }\n                    // or this could be a floating point value or something with an 'e' or 'E' in it.\n                    else if ((tokenizer.peek_type() == tok::CHAR && tokenizer.peek_token()[0] == '.') ||\n                             (tokenizer.peek_type() == tok::IDENTIFIER && std::tolower(tokenizer.peek_token()[0]) == 'e'))\n                    {\n                        std::string temp;\n                        tokenizer.get_token(type,temp);\n                        token += temp;\n                        // now get the rest of the floating point value\n                        while (tokenizer.peek_type() == tok::IDENTIFIER ||\n                               tokenizer.peek_type() == tok::NUMBER\n                               )\n                        {\n                            tokenizer.get_token(type,temp);\n                            token += temp;\n                        }\n                    }\n                    type = NUMBER;\n\n                } break;\n\n            case tok::IDENTIFIER:\n                {\n                    if (keywords.is_member(token))\n                    {\n                        type = KEYWORD;\n                    }\n                    else\n                    {\n                        type = IDENTIFIER;\n                    }\n                } break;\n\n            case tok::CHAR:            \n                type = OTHER;\n                switch (token[0])\n                {\n                case '#':\n                    {\n                        // this might be a preprocessor keyword so we should check the\n                        // next token\n                        if (tokenizer.peek_type() == tok::IDENTIFIER && \n                            keywords.is_member('#'+tokenizer.peek_token()))\n                        {\n                            tokenizer.get_token(type,token);\n                            token = '#' + token;\n                            type = KEYWORD;\n                        }\n                        else\n                        {\n                            token = '#';\n                            type = OTHER;\n                        }\n                    }\n                    break;\n\n                case '\"':\n                    {\n                        std::string temp;                    \n                        tokenizer.get_token(type,token);\n                        while (type != tok::END_OF_FILE)\n                        {\n                            // if this is the end of the quoted string\n                            if (type == tok::CHAR && token[0] == '\"' &&\n                                (temp.size() == 0 || temp[temp.size()-1] != '\\\\' ||\n                                (temp.size() > 1 && temp[temp.size()-2] == '\\\\') ))\n                            {\n                                buffer_token(DOUBLE_QUOTED_TEXT,temp);                         \n                                buffer_token(OTHER,\"\\\"\");\n                                break;\n                            }\n                            else\n                            {\n                                temp += token;\n                            }\n                            tokenizer.get_token(type,token);\n                        }\n\n\n                        type = OTHER;\n                        token = '\"';\n                    } break;\n\n                case '\\'':\n                    {\n                        std::string temp;                    \n                        tokenizer.get_token(type,token);\n                        if (type == tok::CHAR && token[0] == '\\\\')\n                        {\n                            temp += '\\\\';\n                            tokenizer.get_token(type,token);\n                        }\n                        temp += token;\n                        buffer_token(SINGLE_QUOTED_TEXT,temp);\n\n                        // The next character should be a ' so take it out and put it in\n                        // the buffer.\n                        tokenizer.get_token(type,token);\n                        buffer_token(OTHER,token);\n\n                        type = OTHER;\n                        token = '\\'';\n                    } break;\n\n                case '/':\n                    {                \n                        // look ahead to see if this is the start of a comment\n                        if (tokenizer.peek_type() == tok::CHAR)\n                        {\n                            if (tokenizer.peek_token()[0] == '/')\n                            {\n                                tokenizer.get_token(type,token);\n                                // this is the start of a line comment\n                                token = \"//\";\n                                std::string temp;                    \n                                tokenizer.get_token(type,temp);\n                                while (type != tok::END_OF_FILE)\n                                {\n                                    // if this is the end of the comment\n                                    if (type == tok::END_OF_LINE && \n                                        token[token.size()-1] != '\\\\' )\n                                    {\n                                        token += '\\n';\n                                        break;\n                                    }\n                                    else\n                                    {\n                                        token += temp;\n                                    }\n                                    tokenizer.get_token(type,temp);\n                                }\n                                type = COMMENT;\n\n                            }\n                            else if (tokenizer.peek_token()[0] == '*')\n                            {\n                                tokenizer.get_token(type,token);\n                                // this is the start of a block comment\n                                token = \"/*\";\n                                std::string temp;                    \n                                tokenizer.get_token(type,temp);\n                                while (type != tok::END_OF_FILE)\n                                {\n                                    // if this is the end of the comment\n                                    if (type == tok::CHAR && temp[0] == '/' &&\n                                        token[token.size()-1] == '*')\n                                    {\n                                        token += '/';\n                                        break;\n                                    }\n                                    else\n                                    {\n                                        token += temp;\n                                    }\n                                    tokenizer.get_token(type,temp);\n                                }  \n                                type = COMMENT;                       \n                            }\n                        }\n                    } break;\n\n                default:\n                    break;\n                } // switch (token[0])\n            } // switch (type)\n        }\n        else\n        {\n            // if we get this far it means we have peeked so we should \n            // return the peek data.\n            type = next_type;\n            token = next_token;\n            have_peeked = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    int cpp_tokenizer_kernel_1<tok,queue,set>::\n    peek_type (\n    ) const\n    {\n        const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);\n        have_peeked = true;\n        return next_type;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    const std::string& cpp_tokenizer_kernel_1<tok,queue,set>::\n    peek_token (\n    ) const\n    {\n        const_cast<cpp_tokenizer_kernel_1<tok,queue,set>*>(this)->get_token(next_type,next_token);\n        have_peeked = true;\n        return next_token;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tok,\n        typename queue,\n        typename set\n        >\n    void cpp_tokenizer_kernel_1<tok,queue,set>::\n    swap (\n        cpp_tokenizer_kernel_1& item\n    )\n    {\n        tokenizer.swap(item.tokenizer);\n        buffer.swap(item.buffer);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CPP_TOKENIZER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/cpp_tokenizer/cpp_tokenizer_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_\n#ifdef DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_\n\n#include <string>\n#include <ioswfd>\n\nnamespace dlib\n{\n\n    class cpp_tokenizer \n    {\n        /*!\n            INITIAL VALUE\n                stream_is_set() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple tokenizer for C++ source code. \n\n            BUFFERING\n                This object is allowed to buffer data from the input stream.\n                Thus if you clear it or switch streams (via calling set_stream())\n                any buffered data will be lost.\n\n            TOKENS\n                When picking out tokens the cpp_tokenizer will always extract the \n                longest token it can.  For example, if faced with the string \n                \"AAA\" it will consider the three As to be a single IDENTIFIER \n                token not three smaller IDENTIFIER tokens.\n\n                Also note that no characters in the input stream are discarded.\n                They will all be returned in the text of some token.  \n                Additionally, each character will never be returned more than once.  \n                This means that if you concatenated all returned tokens it would exactly\n                reproduce the contents of the input stream.\n\n                The tokens are defined as follows:\n\n                END_OF_FILE\n                    This token represents the end of file.  It doesn't have any\n                    actual characters associated with it.\n\n                KEYWORD\n                    This token matches a C++ keyword.  (This includes the preprocessor\n                    directives).\n\n                COMMENT\n                    This token matches a C++ comment.\n\n                SINGLE_QUOTED_TEXT\n                    This token matches the text of any single quoted literal.\n                    For example, 'a' would be a match and the text of this token\n                    would be the single character a.\n\n                DOUBLE_QUOTED_TEXT  \n                    This token matches the text of any double quoted string.\n                    For example, \"C++\" would be a match and the text of this token\n                    would be the three character string C++.\n\n                WHITE_SPACE\n                    This is a multi character token.  It is defined as a sequence of\n                    one or more spaces, carrage returns, newlines, and tabs.  I.e. It \n                    is composed of characters from the following string \" \\r\\n\\t\".\n\n                IDENTIFIER\n                    This token matches any C++ identifier that isn't matched by any \n                    of the above tokens.   (A C++ identifier being a string matching\n                    the regular expression [_$a-zA-Z][_$a-zA-Z0-9]*).\n\n                NUMBER\n                    This token matches any C++ numerical constant.\n\n                OTHER\n                    This matches anything that isn't part of one of the above tokens. \n                    It is always a single character. \n        !*/\n\n    public:\n\n        enum \n        {\n            END_OF_FILE,\n            KEYWORD,\n            COMMENT,\n            SINGLE_QUOTED_TEXT,\n            DOUBLE_QUOTED_TEXT,\n            IDENTIFIER,\n            OTHER,\n            NUMBER,\n            WHITE_SPACE\n        };\n\n        cpp_tokenizer (        \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~cpp_tokenizer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n                    If this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds.\n        !*/\n\n        void set_stream (\n            std::istream& in\n        );\n        /*!\n            ensures\n                - #*this will read data from in and tokenize it\n                - #stream_is_set() == true\n                - #get_stream() == in\n        !*/\n\n        bool stream_is_set (\n        ) const;\n        /*!\n            ensures\n                - returns true if a stream has been associated with *this by calling\n                  set_stream()\n        !*/\n\n        std::istream& get_stream (\n        ) const;\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - returns a reference to the istream object that *this is reading \n                  from.\n        !*/\n\n        void get_token (\n            int& type,\n            std::string& token\n        );\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - #token == the next token from the input stream get_stream()\n                - #type == the type of the token in #token\n            throws\n                - bad_alloc\n                    If this exception is thrown then the call to this function will \n                    have no effect on *this but the values of #type and #token will be \n                    undefined.  Additionally, some characters may have been read\n                    from the stream get_stream() and lost.\n        !*/\n\n        int peek_type (\n        ) const;\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - returns the type of the token that will be returned from\n                  the next call to get_token()\n            throws\n                - bad_alloc\n                    If this exception is thrown then the call to this function will \n                    have no effect on *this.  However, some characters may have been \n                    read from the stream get_stream() and lost.\n        !*/\n\n        const std::string& peek_token (\n        ) const;\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - returns the text of the token that will be returned from\n                  the next call to get_token()\n            throws\n                - bad_alloc\n                    If this exception is thrown then the call to this function will \n                    have no effect on *this.  However, some characters may have been \n                    read from the stream get_stream() and lost.\n        !*/\n\n        void swap (\n            cpp_tokenizer& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    private:\n\n        // restricted functions\n        cpp_tokenizer(const cpp_tokenizer&);        // copy constructor\n        cpp_tokenizer& operator=(const cpp_tokenizer&);    // assignment operator\n\n    };    \n\n    inline void swap (\n        cpp_tokenizer& a, \n        cpp_tokenizer& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_CPP_TOKENIZER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/cpp_tokenizer/cpp_tokenizer_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_TOKENIZER_KERNEl_C_\n#define DLIB_CPP_TOKENIZER_KERNEl_C_\n\n#include \"cpp_tokenizer_kernel_abstract.h\"\n#include \"../assert.h\"\n#include <string>\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename tokenizer\n        >\n    class cpp_tokenizer_kernel_c : public tokenizer\n    {\n        \n        public:\n            std::istream& get_stream (\n            ) const;\n\n            void get_token (\n                int& type,\n                std::string& token\n            );\n\n            int peek_type (\n            ) const;\n\n            const std::string& peek_token (\n            ) const;\n\n    };\n\n    template <\n        typename tokenizer\n        >\n    inline void swap (\n        cpp_tokenizer_kernel_c<tokenizer>& a, \n        cpp_tokenizer_kernel_c<tokenizer>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tokenizer\n        >\n    std::istream& cpp_tokenizer_kernel_c<tokenizer>::\n    get_stream (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tstd::istream& cpp_tokenizer::get_stream()\"\n            << \"\\n\\tyou must set a stream for this object before you can get it\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return tokenizer::get_stream();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tokenizer\n        >\n    const std::string& cpp_tokenizer_kernel_c<tokenizer>::\n    peek_token (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tconst std::string& cpp_tokenizer::peek_token()\"\n            << \"\\n\\tyou must set a stream for this object before you can peek at what it contains\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return tokenizer::peek_token();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tokenizer\n        >\n    int cpp_tokenizer_kernel_c<tokenizer>::\n    peek_type (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tint cpp_tokenizer::peek_type()\"\n            << \"\\n\\tyou must set a stream for this object before you can peek at what it contains\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return tokenizer::peek_type();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename tokenizer\n        >\n    void cpp_tokenizer_kernel_c<tokenizer>::\n    get_token (\n        int& type,\n        std::string& token\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tvoid cpp_tokenizer::get_token()\"\n            << \"\\n\\tyou must set a stream for this object before you can get tokens from it.\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        tokenizer::get_token(type,token);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_TOKENIZER_KERNEl_C_\n\n\n"
  },
  {
    "path": "dlib/cpp_tokenizer.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CPP_TOKENIZEr_\n#define DLIB_CPP_TOKENIZEr_\n\n#include <string>\n#include \"cpp_tokenizer/cpp_tokenizer_kernel_1.h\"\n#include \"cpp_tokenizer/cpp_tokenizer_kernel_c.h\"\n#include \"tokenizer.h\"\n#include \"queue.h\"\n#include \"set.h\"\n\nnamespace dlib\n{\n\n    class cpp_tokenizer\n    {\n        cpp_tokenizer() {}\n\n\n        typedef set<std::string>::kernel_1a set;\n        typedef queue<cpp_tok_kernel_1_helper::token_text_pair>::kernel_2a queue;\n        typedef tokenizer::kernel_1a tok;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     cpp_tokenizer_kernel_1<tok,queue,set>\n                    kernel_1a;\n        typedef     cpp_tokenizer_kernel_c<kernel_1a>\n                    kernel_1a_c;\n          \n\n    };\n}\n\n#endif // DLIB_CPP_TOKENIZEr_\n\n"
  },
  {
    "path": "dlib/crc32/crc32_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CRC32_KERNEl_1_\n#define DLIB_CRC32_KERNEl_1_\n\n#include \"../algs.h\"\n#include <string>\n#include <vector>\n#include \"crc32_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    class crc32 \n    {\n        /*!\n            INITIAL VALUE\n                checksum == 0xFFFFFFFF\n\n            CONVENTION\n                get_checksum() == checksum ^ 0xFFFFFFFF\n        !*/\n\n    public:\n\n        // this is here for backwards compatibility with older versions of dlib.\n        typedef crc32 kernel_1a;\n\n        inline crc32 (\n        );\n\n        inline crc32 (\n            const std::string& item\n        );\n\n        inline crc32 (\n            const std::vector<char>& item\n        );\n\n        inline virtual ~crc32 (\n        );\n\n        inline void clear(\n        );\n\n        inline void add (\n            unsigned char item\n        );\n\n        inline void add (\n            const std::string& item\n        );\n\n        inline void add (\n            const std::vector<char>& item\n        );\n\n        inline operator unsigned long (\n        ) const { return get_checksum(); }\n\n        inline unsigned long get_checksum (\n        ) const;\n\n        inline void swap (\n            crc32& item\n        );\n\n    private:\n\n        unsigned long checksum;\n\n        inline unsigned long table (\n            unsigned int idx\n        ) const \n        {\n            /*\n            // This code generates the crc_table used below.\n            unsigned long crc_table[256];\n            for (unsigned long i = 0; i < 256; ++i)\n            {\n                unsigned long temp = i;\n                for (unsigned long j = 0; j < 8; ++j)\n                {\n                    if (temp&1)\n                        temp = (temp>>1)^0xedb88320;\n                    else\n                        temp >>= 1;\n                }\n                crc_table[i] = temp;\n                std::cout << std::hex << crc_table[i] << std::endl;\n            }\n            */\n\n            const static unsigned long crc_table[256] = {\n                0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n                0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n                0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n                0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n                0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n                0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n                0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n                0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n                0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n                0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,\n                0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n                0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n                0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n                0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n                0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n                0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n                0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683,\n                0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,\n                0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n                0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n                0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n                0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n                0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n                0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n                0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713,\n                0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,\n                0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n                0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n                0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n                0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n                0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n                0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n            };\n\n            return crc_table[idx];\n        }\n\n    };    \n\n    inline void swap (\n        crc32& a, \n        crc32& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    crc32::\n    crc32 (\n    )\n    {\n        checksum = 0xFFFFFFFF;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    crc32::\n    crc32 (        \n        const std::string& item\n    )\n    {\n        checksum = 0xFFFFFFFF;\n        add(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    crc32::\n    crc32 (        \n        const std::vector<char>& item\n    )\n    {\n        checksum = 0xFFFFFFFF;\n        add(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    crc32::\n    ~crc32 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void crc32::\n    clear(\n    )\n    {\n        checksum = 0xFFFFFFFF;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void crc32::\n    add (\n        unsigned char item\n    )\n    {\n        checksum = (checksum>>8) ^ table((checksum^item) & 0xFF);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void crc32::\n    add (\n        const std::string& item\n    )\n    {\n        for (std::string::size_type i = 0; i < item.size(); ++i)\n            checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void crc32::\n    add (\n        const std::vector<char>& item\n    )\n    {\n        for (unsigned long i = 0; i < item.size(); ++i)\n            checksum = (checksum>>8) ^ table((checksum^item[i]) & 0xFF);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long crc32::\n    get_checksum (\n    ) const\n    {\n        return checksum ^ 0xFFFFFFFF;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void crc32::\n    swap (\n        crc32& item\n    )\n    {\n        exchange(checksum,item.checksum);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CRC32_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/crc32/crc32_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CRC32_KERNEl_ABSTRACT_\n#ifdef DLIB_CRC32_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <string>\n#include <vector>\n\nnamespace dlib\n{\n\n    class crc32 \n    {\n        /*!\n            INITIAL VALUE\n                The current checksum covers zero bytes. \n                get_checksum() == 0x00000000\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the CRC32 algorithm for calculating\n                checksums.  \n        !*/\n\n    public:\n\n        crc32 (        \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n        !*/\n\n        crc32 (\n            const std::string& item\n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n                - calls this->add(item).\n                  (i.e. Using this constructor is the same as using the default \n                  constructor and then calling add() on item)\n        !*/\n\n        crc32 (        \n            const std::vector<char>& item\n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n                - calls this->add(item).\n                  (i.e. Using this constructor is the same as using the default \n                  constructor and then calling add() on item)\n        !*/\n\n        virtual ~crc32 (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n        !*/\n\n        void add (\n            unsigned char item\n        );\n        /*!\n            ensures\n                - #get_checksum() == The checksum of all items added to *this previously\n                  concatenated with item.\n        !*/\n\n        void add (\n            const std::string& item\n        );\n        /*!\n            ensures\n                - #get_checksum() == The checksum of all items added to *this previously\n                  concatenated with item.\n        !*/\n\n        void add (\n            const std::vector<char>& item\n        );\n        /*!\n            ensures\n                - #get_checksum() == The checksum of all items added to *this previously\n                  concatenated with item.\n        !*/\n\n        unsigned long get_checksum (\n        ) const;\n        /*!\n            ensures\n                - returns the current checksum\n        !*/\n\n        operator unsigned long (\n        ) const; \n        /*!\n            ensures\n                - returns get_checksum()\n        !*/\n\n        void swap (\n            crc32& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };    \n\n    void swap (\n        crc32& a, \n        crc32& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_CRC32_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/crc32.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CRc32_\n#define DLIB_CRc32_\n\n\n#include \"crc32/crc32_kernel_1.h\"\n\n#endif // DLIB_CRc32_\n\n"
  },
  {
    "path": "dlib/cstring",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/cuda/cpu_dlib.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CPU_cPP_\n#define DLIB_DNN_CPU_cPP_\n\n// This file contains CPU implementations of the GPU based functions in cuda_dlib.h\n\n#include \"cpu_dlib.h\"\n#include \"tensor_tools.h\"\n#include \"../image_transforms/interpolation.h\"\n#include \"../threads.h\"\n\nnamespace dlib\n{\n    namespace cpu \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        void multiply (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            DLIB_CASSERT(dest.k() == src1.k() && src1.k() == src2.k() &&\n                dest.nr() == src1.nr() && src1.nr() == src2.nr() &&\n                dest.nc() == src1.nc() && src1.nc() == src2.nc() );\n            const long MD = std::max(std::max(dest.num_samples(),src1.num_samples()),src2.num_samples());\n            DLIB_CASSERT((dest.num_samples()==1 || dest.num_samples()==MD) &&\n                (src1.num_samples()==1 || src1.num_samples()==MD) &&\n                (src2.num_samples()==1 || src2.num_samples()==MD) );\n\n            if (dest.size() == 0)\n                return;\n\n            const size_t max_size = std::max(std::max(dest.size(),src1.size()),src2.size());\n            const auto d = dest.host();\n            const auto s1 = src1.host();\n            const auto s2 = src2.host();\n            if (dest.size() == src1.size() && src1.size() == src2.size())\n            {\n                if (add_to)\n                {\n                    for (size_t i = 0; i < src1.size(); ++i)\n                        d[i] += s1[i]*s2[i];\n                }\n                else\n                {\n                    for (size_t i = 0; i < src1.size(); ++i)\n                        d[i] = s1[i]*s2[i];\n                }\n            }\n            else if (dest.num_samples() == 1)\n            {\n                if (!add_to)\n                {\n                    for (size_t i = 0; i < dest.size(); ++i)\n                        d[i] = 0;\n                }\n                for (size_t i = 0; i < max_size; ++i)\n                    d[i%dest.size()] += s1[i%src1.size()]*s2[i%src2.size()];\n            }\n            else\n            {\n                if (add_to)\n                {\n                    for (size_t i = 0; i < max_size; ++i)\n                        d[i] += s1[i%src1.size()]*s2[i%src2.size()];\n                }\n                else\n                {\n                    for (size_t i = 0; i < max_size; ++i)\n                        d[i] = s1[i%src1.size()]*s2[i%src2.size()];\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void multiply_conv (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            auto d = dest.host();\n            auto s1 = src1.host();\n            auto s2 = src2.host();\n            if (have_same_dimensions(dest,src1))\n            {\n                DLIB_CASSERT(src2.num_samples() == 1 && src2.nr() == 1 && src2.nc() == 1 && src2.k() == src1.k());\n\n                if (add_to)\n                {\n                    for (long n = 0; n < dest.num_samples(); ++n)\n                    {\n                        for (long k = 0; k < dest.k(); ++k)\n                        {\n                            for (long r = 0; r < dest.nr(); ++r)\n                            {\n                                for (long c = 0; c < dest.nc(); ++c)\n                                {\n                                    *d++ += (*s1++)*s2[k];\n                                }\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    for (long n = 0; n < dest.num_samples(); ++n)\n                    {\n                        for (long k = 0; k < dest.k(); ++k)\n                        {\n                            for (long r = 0; r < dest.nr(); ++r)\n                            {\n                                for (long c = 0; c < dest.nc(); ++c)\n                                {\n                                    *d++ = (*s1++)*s2[k];\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            else\n            {\n                DLIB_CASSERT(have_same_dimensions(src1,src2));\n                DLIB_CASSERT(dest.num_samples() == 1 && dest.nr() == 1 && dest.nc() == 1 && dest.k() == src1.k());\n\n                if (!add_to)\n                {\n                    for (long k = 0; k < src1.k(); ++k)\n                        d[k] = 0;\n                }\n\n                for (long n = 0; n < src1.num_samples(); ++n)\n                {\n                    for (long k = 0; k < src1.k(); ++k)\n                    {\n                        for (long r = 0; r < src1.nr(); ++r)\n                        {\n                            for (long c = 0; c < src1.nc(); ++c)\n                            {\n                                d[k] += (*s1++)*(*s2++);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void scale_channels (\n            bool add_to,\n            tensor& dest,\n            const tensor& src,\n            const tensor& scales\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src) && \n                         scales.num_samples() == src.num_samples() &&\n                         scales.k()           == src.k() &&\n                         scales.nr()          == 1 &&\n                         scales.nc()          == 1 );\n\n            if (dest.size() == 0)\n                return;\n\n            if (add_to)\n            {\n                auto d = dest.host();\n                auto s = src.host();\n                auto scal = scales.host();\n\n                for (long n = 0; n < src.num_samples(); ++n)\n                {\n                    for (long k = 0; k < src.k(); ++k)\n                    {\n                        const auto scale = scal[n*scales.k() + k];\n                        for (long r = 0; r < src.nr(); ++r)\n                        {\n                            for (long c = 0; c < src.nc(); ++c)\n                            {\n                                *d++ += (*s++) * scale;\n                            }\n                        }\n                    }\n                }\n\n\n            }\n            else\n            {\n                auto d = dest.host_write_only();\n                auto s = src.host();\n                auto scal = scales.host();\n\n                for (long n = 0; n < src.num_samples(); ++n)\n                {\n                    for (long k = 0; k < src.k(); ++k)\n                    {\n                        const auto scale = scal[n*scales.k() + k];\n                        for (long r = 0; r < src.nr(); ++r)\n                        {\n                            for (long c = 0; c < src.nc(); ++c)\n                            {\n                                *d++ = (*s++) * scale;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void add(\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(\n                  (have_same_dimensions(src, dest) ||\n                  (src.num_samples()==1 && src.k()==dest.k() && src.nr()==1 && src.nc()==1) ||\n                  (src.num_samples()==1 && src.k()==dest.k() && src.nr()==dest.nr() && src.nc()==dest.nc()) ||\n                  (src.num_samples()==1 && src.k()==1 && src.nr()==dest.nr() && src.nc()==dest.nc()) ||\n                  (src.num_samples()==dest.num_samples() && src.k()==1 && src.nr()==1 && src.nc()==1)) &&\n                  is_same_object(src,dest) == false , \n                    \"\\n\\t dest.num_samples(): \" << dest.num_samples()\n                    <<\"\\n\\t dest.k():           \" << dest.k()\n                    <<\"\\n\\t dest.nr():          \" << dest.nr()\n                    <<\"\\n\\t dest.nc():          \" << dest.nc()\n                    <<\"\\n\\t src.num_samples():  \" << src.num_samples()\n                    <<\"\\n\\t src.k():            \" << src.k()\n                    <<\"\\n\\t src.nr():           \" << src.nr()\n                    <<\"\\n\\t src.nc():           \" << src.nc()\n                    );\n\n\n            if (beta == 0 && alpha == 0)\n            {\n                dest = 0;\n                return;\n            }\n\n            auto d = dest.host();\n            auto s = src.host();\n            for (long n = 0; n < dest.num_samples(); ++n)\n            {\n                const auto sn = src.num_samples()==1 ? 0:n;\n                for (long k = 0; k < dest.k(); ++k)\n                {\n                    const auto sk = src.k()==1 ? 0:k;\n                    for (long r = 0; r < dest.nr(); ++r)\n                    {\n                        const auto sr = src.nr()==1 ? 0:r;\n                        for (long c = 0; c < dest.nc(); ++c)\n                        {\n                            const auto sc = src.nc()==1 ? 0:c;\n\n                            const auto s_idx = ((sn*src.k() + sk)*src.nr() + sr)*src.nc() + sc;\n                            *d = beta*(*d) + alpha*s[s_idx];\n                            ++d;\n                        }\n                    }\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void add (\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            auto d = dest.host();\n            auto s1 = src1.host();\n            auto s2 = src2.host();\n\n            // Do the simple and fast version if everything has the same dimensions\n            if (have_same_dimensions(dest, src1) &&\n                have_same_dimensions(dest, src2))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                    d[i] = s1[i] + s2[i];\n                return;\n            }\n\n            // Otherwise, do the more complex version with bounds checking.\n            for (long n = 0; n < dest.num_samples(); ++n)\n            {\n                for (long k = 0; k < dest.k(); ++k)\n                {\n                    for (long r = 0; r < dest.nr(); ++r)\n                    {\n                        for (long c = 0; c < dest.nc(); ++c)\n                        {\n                            float v1 = 0;\n                            float v2 = 0;\n\n                            // if this index is inside src1\n                            if (n < src1.num_samples() && \n                                k < src1.k() && \n                                r < src1.nr() && \n                                c < src1.nc() )\n                            {\n                                const auto s_idx = ((n*src1.k() + k)*src1.nr() + r)*src1.nc() + c;\n                                v1 = s1[s_idx];\n                            }\n\n                            // if this index is inside src2\n                            if (n < src2.num_samples() && \n                                k < src2.k() && \n                                r < src2.nr() && \n                                c < src2.nc() )\n                            {\n                                const auto s_idx = ((n*src2.k() + k)*src2.nr() + r)*src2.nc() + c;\n                                v2 = s2[s_idx];\n                            }\n\n                            *d = v1 + v2;\n                            ++d;\n                        }\n                    }\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void multiply_zero_padded (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            auto d = dest.host();\n            auto s1 = src1.host();\n            auto s2 = src2.host();\n\n            // Do the simple and fast version if everything has the same dimensions\n            if (have_same_dimensions(dest, src1) &&\n                have_same_dimensions(dest, src2))\n            {\n                if (add_to)\n                {\n                    for (size_t i = 0; i < dest.size(); ++i)\n                        d[i] += s1[i] * s2[i];\n                }\n                else\n                {\n                    for (size_t i = 0; i < dest.size(); ++i)\n                        d[i] = s1[i] * s2[i];\n                }\n                return;\n            }\n\n            // Otherwise, do the more complex version with bounds checking.\n            for (long n = 0; n < dest.num_samples(); ++n)\n            {\n                for (long k = 0; k < dest.k(); ++k)\n                {\n                    for (long r = 0; r < dest.nr(); ++r)\n                    {\n                        for (long c = 0; c < dest.nc(); ++c)\n                        {\n                            float v1 = 0;\n                            float v2 = 0;\n\n                            // if this index is inside src1\n                            if (n < src1.num_samples() && \n                                k < src1.k() && \n                                r < src1.nr() && \n                                c < src1.nc() )\n                            {\n                                const auto s_idx = ((n*src1.k() + k)*src1.nr() + r)*src1.nc() + c;\n                                v1 = s1[s_idx];\n                            }\n\n                            // if this index is inside src2\n                            if (n < src2.num_samples() && \n                                k < src2.k() && \n                                r < src2.nr() && \n                                c < src2.nc() )\n                            {\n                                const auto s_idx = ((n*src2.k() + k)*src2.nr() + r)*src2.nc() + c;\n                                v2 = s2[s_idx];\n                            }\n\n                            if (add_to)\n                                *d += v1 * v2;\n                            else\n                                *d = v1 * v2;\n                            ++d;\n                        }\n                    }\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void assign_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  grad.num_samples() == 1 &&\n                  gradient_input.k() == grad.k() &&\n                  gradient_input.nr() == grad.nr() &&\n                  gradient_input.nc() == grad.nc() &&\n                  gradient_input.size() > 0);\n\n            auto out = grad.host();\n            auto in = gradient_input.host();\n\n            for (size_t i = 0; i < grad.size(); ++i)\n                out[i] = *in++;\n\n            for (long j = 1; j < gradient_input.num_samples(); ++j)\n            {\n                for (size_t i = 0; i < grad.size(); ++i)\n                    out[i] += *in++;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void assign_conv_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  grad.num_samples() == 1 &&\n                  grad.k()  >= 1 &&\n                  grad.nr() == 1 &&\n                  grad.nc() == 1 &&\n                  gradient_input.k() == grad.k() &&\n                  gradient_input.size() > 0 && \n                  is_same_object(grad,gradient_input) == false\n                  );\n\n            auto g = grad.host();\n            auto gi = gradient_input.host();\n\n            for (long k = 0; k < gradient_input.k(); ++k)\n                g[k] = 0;\n\n            for (long n = 0; n < gradient_input.num_samples(); ++n)\n            {\n                for (long k = 0; k < gradient_input.k(); ++k)\n                {\n                    for (long r = 0; r < gradient_input.nr(); ++r)\n                    {\n                        for (long c = 0; c < gradient_input.nc(); ++c)\n                        {\n                            g[k] += (*gi++);\n                        }\n                    }\n                }\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A,\n            const float B\n        )\n        {\n            DLIB_CASSERT(dest.size()==src.size());\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n                d[i] = A*s[i] + B;\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B,\n            const float C\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            const auto d = dest.host();\n            const auto s1 = src1.host();\n            const auto s2 = src2.host();\n            for (size_t i = 0; i < src1.size(); ++i)\n                d[i] = A*s1[i] + B*s2[i] + C;\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C,\n            const float D\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            DLIB_CASSERT(dest.size()==src3.size());\n            const auto d = dest.host();\n            const auto s1 = src1.host();\n            const auto s2 = src2.host();\n            const auto s3 = src3.host();\n            for (size_t i = 0; i < src1.size(); ++i)\n                d[i] = A*s1[i] + B*s2[i] + C*s3[i] + D;\n        }\n\n        void affine_transform_range(\n            size_t begin,\n            size_t end,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            DLIB_CASSERT(dest.size()==src3.size());\n            DLIB_CASSERT(begin <= end && end <= dest.size());\n            const auto d = dest.host();\n            const auto s1 = src1.host();\n            const auto s2 = src2.host();\n            const auto s3 = src3.host();\n            for (size_t i = begin; i < end; ++i)\n                d[i] = A*s1[i] + B*s2[i] + C*s3[i];\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            DLIB_CASSERT(\n                  ((A.num_samples()==1 && B.num_samples()==1) ||\n                  (A.num_samples()==src.num_samples() && B.num_samples()==src.num_samples())) &&\n                  A.nr()==B.nr() && B.nr()==src.nr() &&\n                  A.nc()==B.nc() && B.nc()==src.nc() &&\n                  A.k() ==B.k()  && B.k()==src.k());\n\n            auto d = dest.host();\n            auto s = src.host();\n            const auto a = A.host();\n            const auto b = B.host();\n            if (A.num_samples() == 1)\n            {\n                const long num = src.size()/src.num_samples();\n                for (long i = 0; i < src.num_samples(); ++i)\n                {\n                    for (long j = 0; j < num; ++j)\n                    {\n                        *d = a[j]*(*s) + b[j];\n                        d++;\n                        s++;\n                    }\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                    d[i] = a[i]*s[i] + b[i];\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform_conv(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            DLIB_CASSERT(have_same_dimensions(A,B));\n            DLIB_CASSERT(A.num_samples() == 1 &&\n                         A.nr() == 1 &&\n                         A.nc() == 1 &&\n                         A.k() == src.k());\n\n            auto d = dest.host();\n            auto s = src.host();\n            const auto a = A.host();\n            const auto b = B.host();\n            for (long n = 0; n < dest.num_samples(); ++n)\n            {\n                for (long k = 0; k < dest.k(); ++k)\n                {\n                    for (long r = 0; r < dest.nr(); ++r)\n                    {\n                        for (long c = 0; c < dest.nc(); ++c)\n                        {\n                            *d++ = a[k]*(*s++) + b[k];\n                        }\n                    }\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void affine_transform(\n            const rectangle& rect,\n            tensor& dest, \n            const tensor& src1, \n            const tensor& src2, \n            const tensor& src3, \n            float A, \n            float B,\n            float C\n        )\n        {\n            DLIB_CASSERT(dest.size() == src1.size());\n            DLIB_CASSERT(dest.size() == src2.size());\n            DLIB_CASSERT(dest.size() == src3.size());\n            DLIB_CASSERT(dest.num_samples() == src1.num_samples());\n            DLIB_CASSERT(dest.num_samples() == src2.num_samples());\n            DLIB_CASSERT(dest.num_samples() == src3.num_samples());\n            DLIB_CASSERT(rectangle(0,0, dest.size()/dest.num_samples()-1, dest.num_samples()-1).contains(rect));\n\n\n            auto d = dest.host();\n            auto s1 = src1.host();\n            auto s2 = src2.host();\n            auto s3 = src3.host();\n\n            const auto nc = dest.size()/dest.num_samples();\n\n            for (long r = rect.top(); r <= rect.bottom(); ++r)\n            {\n                for (long c = rect.left(); c <= rect.right(); ++c)\n                {\n                    auto idx = r*nc + c;\n                    d[idx] = s1[idx]*A + s2[idx]*B + s3[idx]*C;\n                }\n            }\n\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void compute_adam_update (\n            size_t begin,\n            size_t end,\n            tensor& s,\n            tensor& m,\n            tensor& v,\n            const float t,\n            const float learning_rate,\n            const float weight_decay,\n            const float momentum1,\n            const float momentum2,\n            const tensor& params,\n            const tensor& params_grad\n        )\n        {\n            DLIB_CASSERT(s.size() == m.size() &&\n                         s.size() == v.size() &&\n                         s.size() == params.size() &&\n                         s.size() == params_grad.size());\n            DLIB_CASSERT(begin <= end && end <= params.size());\n            const float eps = 1e-8;\n            const float alpha = learning_rate*std::sqrt(1-std::pow(momentum2,t))/(1-std::pow(momentum1, t));\n\n            // The loop is equivalent to doing this:\n            //   m = momentum1*m + (1-momentum1)    *   (weight_decay*params + params_grad);\n            //   v = momentum2*v + (1-momentum2)*squared(weight_decay*params + params_grad);\n            //   s = -alpha*m/(sqrt(v) + eps);\n            auto pm = m.host();\n            auto pv = v.host();\n            auto ps = s.host_write_only();\n            auto pparams = params.host();\n            auto ppgrad = params_grad.host();\n            for (size_t i = begin; i < end; ++i)\n            {\n                float g = weight_decay*pparams[i] + ppgrad[i];\n                pm[i] = momentum1*pm[i] + (1-momentum1)*g;\n                pv[i] = momentum2*pv[i] + (1-momentum2)*g*g;\n                ps[i] = -alpha*pm[i]/(std::sqrt(pv[i]) + eps);\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void batch_normalize_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        )\n        {\n            DLIB_CASSERT(\n                gamma.num_samples() == 1 && \n                gamma.nr() == src.nr() &&\n                gamma.nc() == src.nc() &&\n                gamma.k()  == src.k() &&\n                have_same_dimensions(gamma, beta) &&\n                have_same_dimensions(gamma, running_means) &&\n                have_same_dimensions(gamma, running_variances) && \n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nrunning_means.num_samples(): \" << running_means.num_samples() << \n                \"\\nrunning_means.k():   \" << running_means.k() << \n                \"\\nrunning_means.nr():  \" << running_means.nr() << \n                \"\\nrunning_means.nc():  \" << running_means.nc() << \n                \"\\nrunning_variances.num_samples(): \" << running_variances.num_samples() << \n                \"\\nrunning_variances.k():   \" << running_variances.k() << \n                \"\\nrunning_variances.nr():  \" << running_variances.nr() << \n                \"\\nrunning_variances.nc():  \" << running_variances.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n            dest.copy_size(src);\n\n            auto d = dest.host();\n            auto s = src.host();\n            auto g = gamma.host();\n            auto b = beta.host();\n            auto m = running_means.host();\n            auto v = running_variances.host();\n\n            const long num = src.k()*src.nr()*src.nc();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < num; ++k)\n                {\n                    *d = g[k]*(*s - m[k])/std::sqrt(v[k]+eps) + b[k];\n                    ++d;\n                    ++s;\n                }\n            }\n        }\n\n        void batch_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        )\n        {\n            DLIB_CASSERT(0 <= averaging_factor && averaging_factor <= 1, \"averaging_factor: \" << averaging_factor);\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_means,means));\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_variances,invstds));\n            DLIB_CASSERT(\n                src.num_samples() > 1 &&\n                gamma.num_samples() == 1 && \n                beta.num_samples() == 1 && \n                gamma.nr() == beta.nr() && beta.nr() == src.nr() &&\n                gamma.nc() == beta.nc() && beta.nc() == src.nc() &&\n                gamma.k()  == beta.k()  && beta.k() == src.k() &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n\n            dest.copy_size(src);\n            means.set_size(1, src.k(), src.nr(), src.nc());\n            invstds.set_size(1, src.k(), src.nr(), src.nc());\n            running_means.set_size(1, src.k(), src.nr(), src.nc());\n            running_variances.set_size(1, src.k(), src.nr(), src.nc());\n\n            // first compute means and invstds\n            const auto p_invstds = invstds.host();\n            const auto p_means = means.host();\n            auto p_src = src.host();\n            const auto rvar = running_variances.host();\n            const long num = src.k()*src.nr()*src.nc();\n\n            // This scale makes the running variances unbiased.\n            const double scale = (src.num_samples())/(src.num_samples()-1.0);\n\n            // Apply Welford's algorithm to improve numerical stability\n            for (long i = 0; i < num; ++i)\n            {\n                double mean = 0.0;\n                double M2 = 0.0;\n\n                for (long n = 0; n < src.num_samples(); ++n)\n                {\n                    float val = p_src[n*num+i];\n                    const double delta1 = val - mean;\n                    mean += delta1 / (n + 1);\n                    const double delta2 = val - mean;\n                    M2 += delta1 * delta2;\n                }\n\n                p_means[i] = mean;\n\n                const auto actual_var = (src.num_samples() > 1) ? (M2 / src.num_samples()) : 0.0;\n\n                if (averaging_factor == 1)\n                    rvar[i] = scale*actual_var;\n                else\n                    rvar[i] = (1-averaging_factor)*rvar[i] + scale*averaging_factor*actual_var;\n\n                p_invstds[i] = 1.0f/std::sqrt(actual_var + eps);\n            }\n\n            auto p_dest = dest.host();\n            const auto p_gamma = gamma.host();   \n            const auto p_beta = beta.host();   \n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long i = 0; i < num; ++i)\n                {\n                    *p_dest = (*p_src - p_means[i])*p_invstds[i];\n                    *p_dest = (*p_dest)*p_gamma[i] + p_beta[i];\n                    ++p_src;\n                    ++p_dest;\n                }\n            }\n\n            // now keep track of the running means \n            if (averaging_factor != 1)\n                running_means = (1-averaging_factor)*mat(running_means) + averaging_factor*mat(means);\n            else\n                running_means = means;\n        }\n\n        void batch_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        )\n        {\n\n            const long num = src.k()*src.nr()*src.nc();\n            DLIB_CASSERT(src.num_samples() > 1);\n            DLIB_CASSERT(num == (long)means.size());\n            DLIB_CASSERT(num == (long)invstds.size());\n            DLIB_CASSERT(num == (long)gamma.size());\n            DLIB_CASSERT(num == (long)gamma_grad.size());\n            DLIB_CASSERT(num == (long)beta_grad.size());\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            beta_grad = 0;\n            gamma_grad = 0;\n            auto p_grad = gradient_input.host();\n            auto p_src = src.host();\n            const auto p_gamma = gamma.host();   \n            const auto p_gamma_grad = gamma_grad.host();   \n            const auto p_beta_grad = beta_grad.host();   \n            const auto p_invstds = invstds.host();\n            const auto p_means = means.host();\n\n            resizable_tensor dvars, dmeans;\n            dvars.copy_size(invstds);\n            dmeans.copy_size(means);\n            dvars = 0;\n            dmeans = 0;\n            const auto p_dvars = dvars.host();\n            const auto p_dmeans = dmeans.host();\n\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long i = 0; i < num; ++i)\n                {\n                    const float x_hat = (*p_src - p_means[i])*p_invstds[i];\n                    p_beta_grad[i] += *p_grad;\n                    p_gamma_grad[i] += (*p_grad)*x_hat;\n\n                    const float dx = *p_grad * p_gamma[i];\n\n                    p_dvars[i] += dx*(*p_src - p_means[i])*-0.5*std::pow(p_invstds[i], 3.0f);\n\n                    ++p_grad;\n                    ++p_src;\n                }\n            }\n\n            const float invnum = 1.0f/src.num_samples();\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long i = 0; i < num; ++i)\n                {\n                    const float dx = *p_grad * p_gamma[i];\n\n                    p_dmeans[i] += dx*-p_invstds[i] + p_dvars[i] * -2*(*p_src - p_means[i])*invnum;\n\n                    ++p_grad;\n                    ++p_src;\n                }\n            }\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            auto p_src_grad = src_grad.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long i = 0; i < num; ++i)\n                {\n                    const float dx = *p_grad * p_gamma[i];\n\n                    *p_src_grad += dx*p_invstds[i] + \n                        p_dvars[i] *2*(*p_src - p_means[i])*invnum + \n                        p_dmeans[i]*invnum;\n\n\n                    ++p_grad;\n                    ++p_src;\n                    ++p_src_grad;\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void batch_normalize_conv_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        )\n        {\n            DLIB_CASSERT(\n                gamma.num_samples() == 1 && \n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                gamma.k()  == src.k() &&\n                have_same_dimensions(gamma, beta) &&\n                have_same_dimensions(gamma, running_means) &&\n                have_same_dimensions(gamma, running_variances) &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nrunning_means.num_samples(): \" << running_means.num_samples() << \n                \"\\nrunning_means.k():   \" << running_means.k() << \n                \"\\nrunning_means.nr():  \" << running_means.nr() << \n                \"\\nrunning_means.nc():  \" << running_means.nc() << \n                \"\\nrunning_variances.num_samples(): \" << running_variances.num_samples() << \n                \"\\nrunning_variances.k():   \" << running_variances.k() << \n                \"\\nrunning_variances.nr():  \" << running_variances.nr() << \n                \"\\nrunning_variances.nc():  \" << running_variances.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n            dest.copy_size(src);\n\n            auto d = dest.host();\n            auto s = src.host();\n            auto g = gamma.host();\n            auto b = beta.host();\n            auto m = running_means.host();\n            auto v = running_variances.host();\n\n            const long num = src.nr()*src.nc();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    const float invstd = 1.0f/std::sqrt(v[k] + eps);\n                    for (long j = 0; j < num; ++j)\n                    {\n                        *d = g[k]*(*s - m[k])*invstd + b[k];\n                        ++d;\n                        ++s;\n                    }\n                }\n            }\n        }\n\n        void batch_normalize_conv (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        )\n        {\n            DLIB_CASSERT(0 <= averaging_factor && averaging_factor <= 1, \"averaging_factor: \" << averaging_factor);\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_means,means));\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_variances,invstds));\n            DLIB_CASSERT(\n                src.num_samples() > 1 &&\n                gamma.num_samples() == 1 && \n                beta.num_samples() == 1 && \n                gamma.nr() == 1 && \n                beta.nr() == 1 && \n                gamma.nc() == 1 && \n                beta.nc() == 1 && \n                gamma.k()  == beta.k()  && beta.k() == src.k() &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc()  <<\n                \"\\neps:  \" << eps \n            );\n\n            dest.copy_size(src);\n            means.set_size(1, src.k());\n            invstds.set_size(1, src.k());\n            running_means.set_size(1, src.k());\n            running_variances.set_size(1, src.k());\n\n            // first compute means and invstds\n            const auto p_invstds = invstds.host();\n            const auto p_means = means.host();\n            const auto p_gamma = gamma.host();   \n            const auto p_beta = beta.host();   \n            auto p_src = src.host();\n            auto rvar = running_variances.host();\n            const long num = src.nr()*src.nc();\n\n            // This scale makes the running variances unbiased.\n            const double scale = (src.num_samples()*num)/(src.num_samples()*num-1.0);\n\n            // Apply Welford's algorithm to improve numerical stability\n            for (long k = 0; k < src.k(); ++k)\n            {\n                double mean = 0.0;\n                double M2 = 0.0;\n                long count = 0;\n\n                for (long n = 0; n < src.num_samples(); ++n)\n                {\n                    long start_index = tensor_index(src, n, k, 0, 0);\n                    auto p = p_src + start_index;\n\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float val = *p;\n                        const double delta1 = val - mean;\n                        mean += delta1 / (count + 1);\n                        const double delta2 = val - mean;\n                        M2 += delta1 * delta2;\n                        ++count;\n                        ++p;\n                    }\n                }\n\n                const auto actual_var = (count > 1) ? (M2 / count) : 0.0;\n\n                if (averaging_factor == 1)\n                    rvar[k] = scale*actual_var;\n                else\n                    rvar[k] = (1-averaging_factor)*rvar[k] + scale*averaging_factor*actual_var;\n\n                p_means[k] = mean;\n                p_invstds[k] = 1.0f/std::sqrt(actual_var + eps);\n            }\n\n            auto p_dest = dest.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        *p_dest = (*p_src - p_means[k])*p_invstds[k];\n                        *p_dest = (*p_dest)*p_gamma[k] + p_beta[k];\n                        ++p_src;\n                        ++p_dest;\n                    }\n                }\n            }\n\n            // now keep track of the running means \n            if (averaging_factor != 1)\n                running_means = (1-averaging_factor)*mat(running_means) + averaging_factor*mat(means);\n            else\n                running_means = means;\n        }\n\n        void batch_normalize_conv_gradient(\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        )\n        {\n\n            const long num = src.nr()*src.nc();\n            DLIB_CASSERT(src.num_samples() > 1);\n            DLIB_CASSERT(src.k() == (long)means.size());\n            DLIB_CASSERT(src.k() == (long)invstds.size());\n            DLIB_CASSERT(src.k() == (long)gamma.size());\n            DLIB_CASSERT(src.k() == (long)gamma_grad.size());\n            DLIB_CASSERT(src.k() == (long)beta_grad.size());\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            beta_grad = 0;\n            gamma_grad = 0;\n\n            auto p_grad = gradient_input.host();\n            auto p_src = src.host();\n            const auto p_gamma = gamma.host();   \n            const auto p_gamma_grad = gamma_grad.host();   \n            const auto p_beta_grad = beta_grad.host();   \n            const auto p_invstds = invstds.host();\n            const auto p_means = means.host();\n\n            resizable_tensor dvars, dmeans;\n            dvars.copy_size(invstds);\n            dmeans.copy_size(means);\n            dvars = 0;\n            dmeans = 0;\n            const auto p_dvars = dvars.host();\n            const auto p_dmeans = dmeans.host();\n\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    const float invstd_pow = -0.5*std::pow(p_invstds[k], 3.0f);\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float x_hat = (*p_src - p_means[k])*p_invstds[k];\n                        p_beta_grad[k] += *p_grad;\n                        p_gamma_grad[k] += (*p_grad)*x_hat;\n\n                        const float dx = *p_grad * p_gamma[k];\n\n                        p_dvars[k] += dx*(*p_src - p_means[k])*invstd_pow;\n\n                        ++p_grad;\n                        ++p_src;\n                    }\n                }\n            }\n\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            const float invnum = 1.0f/(src.num_samples()*num);\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float dx = *p_grad * p_gamma[k];\n\n                        p_dmeans[k] += -dx*p_invstds[k] + p_dvars[k] * -2*(*p_src - p_means[k])*invnum;\n\n                        ++p_grad;\n                        ++p_src;\n                    }\n                }\n            }\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            auto p_src_grad = src_grad.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float dx = *p_grad * p_gamma[k];\n\n                        *p_src_grad += dx*p_invstds[k] + \n                            p_dvars[k]*2*(*p_src - p_means[k])*invnum + \n                            p_dmeans[k]*invnum;\n\n\n                        ++p_grad;\n                        ++p_src;\n                        ++p_src_grad;\n                    }\n                }\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void layer_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            const tensor& beta\n        )\n        {\n            DLIB_CASSERT(\n                have_same_dimensions(gamma, beta) &&\n                gamma.k() == src.k() &&\n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                eps > 0,\n                \"\\nsrc.k():    \" << src.k() <<\n                \"\\ngamma.k():  \" << gamma.k() <<\n                \"\\ngamma.nr(): \" << gamma.nr() <<\n                \"\\ngamma.nc(): \" << gamma.nc() <<\n                \"\\nbeta.k():   \" << beta.k() <<\n                \"\\nbeta.nr():  \" << beta.nr() <<\n                \"\\nbeta.nc():  \" << beta.nc() <<\n                \"\\neps:  \" << eps\n            );\n\n            dest.copy_size(src);\n            means.set_size(src.num_samples());\n            invstds.set_size(src.num_samples());\n\n            // first compute means and invstds\n            means = 0;\n            invstds = 0;\n            const float* p_src = src.host();\n            float* p_invstds = invstds.host();\n            float* p_means = means.host();\n            const long num = src.nr() * src.nc();\n            // compute means, and sum of squares\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        p_means[n] += *p_src;\n                        p_invstds[n] += (*p_src) * (*p_src);\n                        ++p_src;\n                    }\n                }\n            }\n            means /= src.k() * num;\n            invstds /= src.k () * num;\n            // copy data back to host\n            invstds.host();\n            means.host();\n\n            // compute variances\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                p_invstds[n] = 1.0f / std::sqrt(p_invstds[n] - p_means[n] * p_means[n] + eps);\n            }\n\n            p_src = src.host();\n            float* p_dest = dest.host();\n            const float* p_gamma = gamma.host();\n            const float* p_beta = beta.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        *p_dest = (*p_src - p_means[n]) * p_invstds[n];\n                        *p_dest = (*p_dest) * p_gamma[k] + p_beta[k];\n                        ++p_src;\n                        ++p_dest;\n                    }\n                }\n            }\n        }\n\n        void layer_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n        )\n        {\n            const long num = src.nr() * src.nc();\n            DLIB_CASSERT(src.num_samples() == means.size());\n            DLIB_CASSERT(src.num_samples() == invstds.size());\n            DLIB_CASSERT(have_same_dimensions(gamma, gamma_grad));\n            DLIB_CASSERT(have_same_dimensions(gamma_grad, beta_grad));\n            DLIB_CASSERT(gamma.k() == src.k());\n            DLIB_CASSERT(gamma.nr() == 1);\n            DLIB_CASSERT(gamma.nc() == 1);\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            beta_grad = 0;\n            gamma_grad = 0;\n\n            auto p_grad = gradient_input.host();\n            auto p_src = src.host();\n            const auto p_gamma = gamma.host();\n            const auto p_gamma_grad = gamma_grad.host();\n            const auto p_beta_grad = beta_grad.host();\n            const auto p_invstds = invstds.host();\n            const auto p_means = means.host();\n\n            dvars.copy_size(invstds);\n            dmeans.copy_size(means);\n            dvars = 0;\n            dmeans = 0;\n            const auto p_dvars = dvars.host();\n            const auto p_dmeans = dmeans.host();\n\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                const float invstd_pow = -0.5 * std::pow(p_invstds[n], 3.0f);\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float x_hat = (*p_src - p_means[n]) * p_invstds[n];\n                        p_beta_grad[k] += *p_grad;\n                        p_gamma_grad[k] += (*p_grad) * x_hat;\n\n                        const float dx = *p_grad * p_gamma[k];\n\n                        p_dvars[n] += dx * (*p_src - p_means[n]) * invstd_pow;\n\n                        ++p_grad;\n                        ++p_src;\n                    }\n                }\n            }\n\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            const float invnum = 1.0f / (src.k() * num);\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float dx = *p_grad * p_gamma[k];\n\n                        p_dmeans[n] += -dx * p_invstds[n] + p_dvars[n] * -2 * (*p_src - p_means[n]) * invnum;\n\n                        ++p_grad;\n                        ++p_src;\n                    }\n                }\n            }\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            auto p_src_grad = src_grad.host();\n            for (long n = 0; n < src.num_samples(); ++n)\n            {\n                for (long k = 0; k < src.k(); ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float dx = *p_grad * p_gamma[k];\n\n                        *p_src_grad += dx * p_invstds[n] +\n                            p_dvars[n] * 2 * (*p_src - p_means[n]) * invnum +\n                            p_dmeans[n] * invnum;\n\n                        ++p_grad;\n                        ++p_src;\n                        ++p_src_grad;\n                    }\n                }\n            }\n        }\n\n// -----------------------------------------------------------------------------------\n\n        void rms_normalize(\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& scale,\n            const tensor& src,\n            const tensor& gamma\n        )\n        {\n            DLIB_CASSERT(\n                gamma.k() == src.k() &&\n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                eps > 0,\n                \"\\nsrc.k():    \" << src.k() <<\n                \"\\ngamma.k():  \" << gamma.k() <<\n                \"\\ngamma.nr(): \" << gamma.nr() <<\n                \"\\ngamma.nc(): \" << gamma.nc() <<\n                \"\\neps:  \" << eps\n            );\n\n            const long ns = src.num_samples();\n            const long ks = src.k();\n            const long num = src.nr() * src.nc();\n\n            dest.copy_size(src);\n            scale.set_size(ns);\n\n            // Compute RMS values\n            scale = 0;\n            const float* p_src = src.host();\n            float* p_scale = scale.host();\n            for (long n = 0; n < ns; ++n)\n            {\n                for (long k = 0; k < ks; ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        p_scale[n] += (*p_src) * (*p_src);\n                        ++p_src;\n                    }\n                }\n                p_scale[n] = 1.0f / std::sqrt(p_scale[n] / (ks * num) + static_cast<float>(eps));\n            }\n            scale.host();\n\n            // Apply RMS normalization\n            p_src = src.host();\n            float* p_dest = dest.host();\n            const float* p_gamma = gamma.host();\n            for (long n = 0; n < ns; ++n)\n            {\n                for (long k = 0; k < ks; ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        *p_dest = (*p_src) * p_scale[n] * p_gamma[k];\n                        ++p_src;\n                        ++p_dest;\n                    }\n                }\n            }\n        }\n\n        void rms_normalize_gradient(\n            const tensor& gradient_input,\n            const tensor& scale,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            resizable_tensor& dscale\n        )\n        {\n            DLIB_CASSERT(src.num_samples() == scale.size());\n            DLIB_CASSERT(have_same_dimensions(gamma, gamma_grad));\n            DLIB_CASSERT(gamma.k() == src.k());\n            DLIB_CASSERT(gamma.nr() == 1);\n            DLIB_CASSERT(gamma.nc() == 1);\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n\n            const long ns = src.num_samples();\n            const long ks = src.k();\n            const long num = src.nr() * src.nc();\n\n            gamma_grad = 0;\n            dscale.copy_size(scale);\n            dscale = 0;\n\n            auto p_grad = gradient_input.host();\n            auto p_src = src.host();\n            const auto p_gamma = gamma.host();\n            const auto p_gamma_grad = gamma_grad.host();\n            const auto p_scale = scale.host();\n            auto p_dscale = dscale.host();\n\n            for (long n = 0; n < ns; ++n)\n            {\n                const float scale_pow = -0.5f * std::pow(p_scale[n], 3.0f);\n                for (long k = 0; k < ks; ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float x_hat = *p_src * p_scale[n];\n                        p_gamma_grad[k] += (*p_grad) * x_hat;\n\n                        const float dx = *p_grad * p_gamma[k];\n                        p_dscale[n] += dx * *p_src * scale_pow;\n\n                        ++p_grad;\n                        ++p_src;\n                    }\n                }\n            }\n\n            p_grad = gradient_input.host();\n            p_src = src.host();\n            auto p_src_grad = src_grad.host();\n            const float invnum = 1.0f / (ks * num);\n            for (long n = 0; n < ns; ++n)\n            {\n                for (long k = 0; k < ks; ++k)\n                {\n                    for (long i = 0; i < num; ++i)\n                    {\n                        const float dx = *p_grad * p_gamma[k];\n                        *p_src_grad += dx * p_scale[n] + p_dscale[n] * 2 * *p_src * invnum;\n\n                        ++p_grad;\n                        ++p_src;\n                        ++p_src_grad;\n                    }\n                }\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void threshold (\n            tensor& data,\n            float thresh\n        )\n        {\n            const auto d = data.host();\n            for (size_t i = 0; i < data.size(); ++i)\n                d[i] = d[i]>thresh ? 1:0;\n        }\n\n        void dot (\n            const tensor& a,\n            const tensor& b,\n            tensor& result,\n            size_t idx\n        )\n        {\n            DLIB_CASSERT(a.size() == b.size());\n            DLIB_CASSERT(idx < result.size());\n\n            const auto aa = a.host();\n            const auto bb = b.host();\n            auto r = result.host();\n            for (size_t i = 0; i < a.size(); ++i)\n                r[idx] += aa[i]*bb[i];\n        }\n\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n\n        namespace ttimpl\n        {\n            void softmax(\n                const long num_locations,\n                const long num_channels,\n                tensor& dest,\n                const tensor& src,\n                operation_mode mode = operation_mode::CHANNEL_WISE\n            )\n            {\n                DLIB_ASSERT(num_channels * num_locations == src.nr() * src.nc() * src.k());\n                DLIB_CASSERT(have_same_dimensions(dest, src));\n                const auto d = dest.host();\n                const auto s = src.host();\n\n                for (long n = 0; n < src.num_samples(); ++n)\n                {\n                    auto ss = s + num_locations * num_channels * n;\n                    auto dd = d + num_locations * num_channels * n;\n\n                    if (mode == operation_mode::CHANNEL_WISE)\n                    {\n                        for (long i = 0; i < num_locations; ++i)\n                        {\n                            float max_val = -std::numeric_limits<float>::infinity();\n                            for (long k = 0; k < num_channels; ++k)\n                                max_val = std::max(max_val, ss[k * num_locations]);\n\n                            float sum = 0.0f;\n                            for (long k = 0; k < num_channels; ++k)\n                            {\n                                dd[k * num_locations] = std::exp(ss[k * num_locations] - max_val);\n                                sum += dd[k * num_locations];\n                            }\n                            for (long k = 0; k < num_channels; ++k)\n                                dd[k * num_locations] /= sum;\n\n                            ++ss;\n                            ++dd;\n                        }\n                    }\n                    else if (mode == operation_mode::PLANE_WISE)\n                    {\n                        for (long k = 0; k < num_channels; ++k)\n                        {\n                            auto s_channel = ss + k * num_locations;\n                            auto d_channel = dd + k * num_locations;\n                            for (long r = 0; r < src.nr(); ++r)\n                            {\n                                float max_val = -std::numeric_limits<float>::infinity();\n                                for (long c = 0, idx = r * src.nc(); c < src.nc(); ++c, ++idx)\n                                    max_val = std::max(max_val, s_channel[idx]);\n\n                                if (max_val == -std::numeric_limits<float>::infinity())\n                                {\n                                    for (long c = 0, idx = r * src.nc(); c < src.nc(); ++c, ++idx)\n                                        d_channel[idx] = 0.0f;\n                                }\n                                else\n                                {\n                                    float sum = 0.0f;\n                                    for (long c = 0, idx = r * src.nc(); c < src.nc(); ++c, ++idx)\n                                    {\n                                        d_channel[idx] = std::exp(s_channel[idx] - max_val);\n                                        sum += d_channel[idx];\n                                    }\n                                    for (long c = 0, idx = r * src.nc(); c < src.nc(); ++c, ++idx)\n                                        d_channel[idx] /= sum;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            void softmax_gradient(\n                const long num_locations,\n                const long num_channels,\n                tensor& grad,\n                const tensor& dest,\n                const tensor& gradient_input,\n                operation_mode mode = operation_mode::CHANNEL_WISE\n            )\n            {\n                DLIB_ASSERT(num_channels * num_locations == grad.nr() * grad.nc() * grad.k());\n                DLIB_CASSERT(have_same_dimensions(grad, dest));\n                DLIB_CASSERT(have_same_dimensions(grad, gradient_input));\n\n                const auto d = dest.host();\n                const auto g = grad.host();\n                const auto in = gradient_input.host();\n                for (long n = 0; n < grad.num_samples(); ++n)\n                {\n                    const auto d2 = d + num_locations * num_channels * n;\n                    const auto g2 = g + num_locations * num_channels * n;\n                    const auto in2 = in + num_locations * num_channels * n;\n\n                    if (mode == operation_mode::CHANNEL_WISE)\n                    {\n                        for (long i = 0; i < num_locations; ++i)\n                        {\n                            const auto d3 = d2 + i;\n                            const auto g3 = g2 + i;\n                            const auto in3 = in2 + i;\n                            float sum = 0.0f;\n                            for (long k = 0; k < num_channels; ++k)\n                                sum += -d3[k * num_locations] * in3[k * num_locations];\n                            if (is_same_object(gradient_input, grad))\n                            {\n                                for (long k = 0; k < num_channels; ++k)\n                                    g3[k * num_locations] = d3[k * num_locations] * (sum + in3[k * num_locations]);\n                            }\n                            else\n                            {\n                                for (long k = 0; k < num_channels; ++k)\n                                    g3[k * num_locations] += d3[k * num_locations] * (sum + in3[k * num_locations]);\n                            }\n                        }\n                    }\n                    else if (mode == operation_mode::PLANE_WISE)\n                    {\n                        for (long k = 0; k < num_channels; ++k)\n                        {\n                            const auto d_channel = d2 + k * num_locations;\n                            const auto g_channel = g2 + k * num_locations;\n                            const auto in_channel = in2 + k * num_locations;\n                            for (long r = 0; r < grad.nr(); ++r)\n                            {\n                                float sum = 0.0f;\n                                for (long c = 0, idx = r * grad.nc(); c < grad.nc(); ++c, ++idx)\n                                    sum += -d_channel[idx] * in_channel[idx];\n                                if (is_same_object(gradient_input, grad))\n                                {\n                                    for (long c = 0, idx = r * grad.nc(); c < grad.nc(); ++c, ++idx)\n                                        g_channel[idx] = d_channel[idx] * (sum + in_channel[idx]);\n                                }\n                                else\n                                {\n                                    for (long c = 0, idx = r * grad.nc(); c < grad.nc(); ++c, ++idx)\n                                        g_channel[idx] += d_channel[idx] * (sum + in_channel[idx]);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void softmax(\n            tensor& dest,\n            const tensor& src,\n            operation_mode mode\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest, src));\n            DLIB_CASSERT(mode == operation_mode::CHANNEL_WISE || mode == operation_mode::PLANE_WISE, \"Invalid softmax mode\");\n            ttimpl::softmax(src.nr() * src.nc(), src.k(), dest, src, mode);\n        }\n\n        void softmax_gradient(\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            operation_mode mode\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(grad, dest));\n            DLIB_CASSERT(have_same_dimensions(grad, gradient_input));\n            ttimpl::softmax_gradient(grad.nr() * grad.nc(), grad.k(), grad, dest, gradient_input, mode);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax_all (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            ttimpl::softmax(1, src.nr()*src.nc()*src.k(), dest, src);\n        }\n\n        void softmax_all_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(grad,dest));\n            DLIB_CASSERT(have_same_dimensions(grad,gradient_input));\n            ttimpl::softmax_gradient(1, grad.nr()*grad.nc()*grad.k(), grad, dest, gradient_input);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void sigmoid (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n                d[i] = 1/(1+std::exp(-s[i]));\n        }\n\n        void sigmoid_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            const auto g = grad.host();\n            const auto d = dest.host();\n            const auto in = gradient_input.host();\n            if (is_same_object(gradient_input, grad))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                    g[i] = in[i]*d[i]*(1-d[i]);\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                    g[i] += in[i]*d[i]*(1-d[i]);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void mish (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            const auto d = dest.host_write_only();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n            {\n                const auto e = std::exp(s[i]);\n                const auto delta = 2*e + e*e + 2;\n                d[i] = s[i] - 2*s[i]/delta;\n            }\n        }\n\n        void mish_gradient(\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            const auto g = grad.host();\n            const auto s = src.host();\n            const auto in = gradient_input.host();\n\n            const auto calculate_gradient = [](float x)\n            {\n                if (x >= 8)\n                    return 1.f;\n                if (x <= -8)\n                    return 0.f;\n\n                const auto e = std::exp(x);\n                const auto delta = 2*e + e*e + 2;\n                const auto omega = 4*(x + 1) + 4*e*e + e*e*e + e*(4*x + 6);\n                return e*omega/(delta*delta);\n            };\n\n            if (is_same_object(gradient_input, grad))\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                    g[i] = in[i]*calculate_gradient(s[i]);\n            }\n            else\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                    g[i] += in[i]*calculate_gradient(s[i]);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void relu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            dest = lowerbound(mat(src), 0);\n        }\n\n        void relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            const float* gi = gradient_input.host();\n            const float* in = dest.host();\n            float* out = grad.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] = gi[i];\n                    else\n                        out[i] = 0;\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] += gi[i];\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void prelu (\n            tensor& dest,\n            const tensor& src,\n            const tensor& param\n        )\n        {\n            const float p = param.host()[0];\n            const float* s = src.host();\n            float* d = dest.host();\n            for (size_t i = 0; i < dest.size(); ++i)\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = p*s[i];\n            }\n        }\n\n        void prelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const tensor& param,\n            tensor& params_grad \n        )\n        {\n            DLIB_CASSERT(is_same_object(grad, gradient_input) == false);\n            const float p = param.host()[0];\n            const float* gi = gradient_input.host();\n            const float* s = src.host();\n            float* out = grad.host();\n            float pgrad = 0;\n            for (size_t i = 0; i < src.size(); ++i)\n            {\n                if (s[i] > 0)\n                {\n                    out[i] += gi[i];\n                }\n                else\n                {\n                    out[i] += p*gi[i];\n                    pgrad += gi[i]*s[i];\n                }\n            }\n            params_grad.host()[0] = pgrad;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void leaky_relu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        )\n        {\n            const float* s = src.host();\n            float* d = dest.host();\n            for (size_t i = 0; i < dest.size(); ++i)\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = alpha * s[i];\n            }\n        }\n\n        void leaky_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        )\n        {\n            const float* gi = gradient_input.host();\n            const float* in = dest.host();\n            float* out = grad.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] = gi[i];\n                    else\n                        out[i] = alpha * gi[i];\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] += gi[i];\n                    else\n                        out[i] += alpha * gi[i];\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void tanh (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n                d[i] = std::tanh(s[i]);\n        }\n\n        void tanh_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            const auto g = grad.host();\n            const auto d = dest.host();\n            const auto in = gradient_input.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                    g[i] = in[i]*(1-d[i]*d[i]);\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                    g[i] += in[i]*(1-d[i]*d[i]);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void clipped_relu (\n            tensor& dest,\n            const tensor& src,\n            const float ceiling\n        )\n        {\n            dest = upperbound(lowerbound(mat(src), 0), ceiling);\n        }\n\n        void clipped_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float ceiling\n        )\n        {\n            const auto out = grad.host();\n            const auto in = dest.host();\n            const auto gi = gradient_input.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0 && in[i] < ceiling)\n                        out[i] = gi[i];\n                    else\n                        out[i] = 0;\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0 && in[i] < ceiling)\n                        out[i] += gi[i];\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void elu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        )\n        {\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = alpha * (std::exp(s[i]) - 1.0f);\n            }\n        }\n\n        void elu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        )\n        {\n            const auto out = grad.host();\n            const auto in = dest.host();\n            const auto gi = gradient_input.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] = gi[i];\n                    else\n                        out[i] = (alpha + in[i]) * gi[i];\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] > 0)\n                        out[i] += gi[i];\n                    else\n                        out[i] += (alpha + in[i]) * gi[i];\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void gelu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n                d[i] = 0.5f*s[i]*(1.0f + std::erf(s[i]/sqrt_2));\n        }\n\n        void gelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            const float beta = 1.0f / std::sqrt(2.0f * pi);\n            const auto compute_gradient = [beta](float x)\n            {\n                const float cdf = 0.5f*(1.0f + std::erf(x/sqrt_2));\n                const float pdf = beta*std::exp(-0.5f*x*x);\n                return cdf + x * pdf;\n            };\n            const auto g = grad.host();\n            const auto s = src.host();\n            const auto in = gradient_input.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                    g[i] = in[i]*compute_gradient(s[i]);\n            }\n            else\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                    g[i] += in[i]*compute_gradient(s[i]);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void smelu (\n            tensor& dest,\n            const tensor& src,\n            const float beta\n        )\n        {\n            const float* s = src.host();\n            float* d = dest.host();\n            for (size_t i = 0; i < dest.size(); ++i)\n            {\n                if (s[i] >= beta)\n                    d[i] = s[i];\n                else if (s[i] <= -beta)\n                    d[i] = 0;\n                else\n                    d[i] = (s[i] + beta) * (s[i] + beta) / (4 * beta);\n            }\n        }\n\n        void smelu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float beta\n        )\n        {\n            const float* gi = gradient_input.host();\n            const float* in = dest.host();\n            float* out = grad.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] >= beta)\n                        out[i] = gi[i];\n                    else if (in[i] == 0)\n                        out[i] = 0;\n                    else\n                        out[i] = std::sqrt(beta * in[i]) / beta * gi[i];\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < dest.size(); ++i)\n                {\n                    if (in[i] >= beta)\n                        out[i] += gi[i];\n                    else if (in[i] == 0)\n                        continue;\n                    else\n                        out[i] += std::sqrt(beta * in[i]) / beta * gi[i];\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void silu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            const auto d = dest.host();\n            const auto s = src.host();\n            for (size_t i = 0; i < src.size(); ++i)\n                d[i] = s[i] * impl::sigmoid(s[i]);\n        }\n\n        void silu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            const auto g = grad.host();\n            const auto s = src.host();\n            const auto in = gradient_input.host();\n            if (is_same_object(grad, gradient_input))\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                {\n                    const auto sig_s = impl::sigmoid(s[i]);\n                    g[i] = in[i] * (sig_s * (1.0f + s[i] * (1.0f - sig_s)));\n                }\n            }\n            else\n            {\n                for (size_t i = 0; i < src.size(); ++i)\n                {\n                    const auto sig_s = impl::sigmoid(s[i]);\n                    g[i] += in[i] * (sig_s * (1.0f + s[i] * (1.0f - sig_s)));\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void resize_bilinear (\n            tensor& dest,\n            long long dest_row_stride,\n            long long dest_channel_stride,\n            const tensor& src,\n            long long src_row_stride,\n            long long src_channel_stride\n        )\n        {\n            DLIB_CASSERT(is_same_object(dest, src)==false);\n            DLIB_CASSERT(dest.num_samples() == src.num_samples());\n            DLIB_CASSERT(dest.k() == src.k());\n\n            if (dest.size() == 0 || src.size() == 0)\n                return;\n\n            const float* s = src.host();\n            float* d = dest.host();\n\n            parallel_for(0, dest.k()*dest.num_samples(), [&](long i)\n            {\n                auto simg = sub_image(s+i*src_channel_stride, src.nr(), src.nc(), src_row_stride);\n                auto dimg = sub_image(d+i*dest_channel_stride, dest.nr(), dest.nc(), dest_row_stride);\n\n                resize_image(simg, dimg);\n            });\n        }\n\n        void resize_bilinear_gradient (\n            tensor& grad,\n            long long grad_row_stride,\n            long long grad_channel_stride,\n            const tensor& gradient_input,\n            long long gradient_input_row_stride,\n            long long gradient_input_channel_stride\n        )\n        {\n            DLIB_CASSERT(is_same_object(grad, gradient_input)==false);\n            DLIB_CASSERT(gradient_input.num_samples() == grad.num_samples());\n            DLIB_CASSERT(gradient_input.k() == grad.k());\n\n            if (gradient_input.size() == 0 || grad.size() == 0)\n                return;\n\n            const float* gi = gradient_input.host();\n            float* g = grad.host();\n            const float x_scale = (grad.nc()-1)/(float)std::max<long>((gradient_input.nc()-1),1);\n            const float y_scale = (grad.nr()-1)/(float)std::max<long>((gradient_input.nr()-1),1);\n            for (long long samp = 0; samp < gradient_input.num_samples(); ++samp)\n            {\n                for (long long k = 0; k < gradient_input.k(); ++k)\n                {\n                    for (long long r = 0; r < gradient_input.nr(); ++r)\n                    {\n                        const float y = r*y_scale;\n                        const long long top    = static_cast<long long>(std::floor(y));\n                        const long long bottom = std::min(top+1, grad.nr()-1);\n                        const float tb_frac = y - top;\n                        for (long long c = 0; c < gradient_input.nc(); ++c)\n                        {\n                            const float x = c*x_scale;\n                            const long long left   = static_cast<long long>(std::floor(x));\n                            const long long right  = std::min(left+1, grad.nc()-1);\n                            const float lr_frac = x - left;\n\n                            const float tmp = gi[r*gradient_input_row_stride+c];\n\n                            g[top*grad_row_stride+left]     += tmp*(1-tb_frac)*(1-lr_frac);\n                            g[top*grad_row_stride+right]    += tmp*(1-tb_frac)*(lr_frac);\n                            g[bottom*grad_row_stride+left]  += tmp*(tb_frac)*(1-lr_frac);\n                            g[bottom*grad_row_stride+right] += tmp*(tb_frac)*(lr_frac);\n                        }\n                    }\n\n                    g += grad_channel_stride;\n                    gi += gradient_input_channel_stride;\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void reorg(\n            bool add_to,\n            tensor& dest,\n            const int row_stride,\n            const int col_stride,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(!is_same_object(dest, src), \"Destination and source must be distinct objects.\");\n            DLIB_CASSERT(src.nr() % row_stride == 0, \"The number of rows in src must be divisible by row_stride.\");\n            DLIB_CASSERT(src.nc() % col_stride == 0, \"The number of columns in src must be divisible by col_stride.\");\n            DLIB_CASSERT(dest.num_samples() == src.num_samples(), \"The number of samples must match.\");\n            DLIB_CASSERT(dest.k() == src.k() * row_stride * col_stride, \"The number of channels must match.\");\n            DLIB_CASSERT(dest.nr() == src.nr() / row_stride, \"The number of rows must match.\");\n            DLIB_CASSERT(dest.nc() == src.nc() / col_stride, \"The number of columns must match.\");\n\n            const float* s = src.host();\n            float* d = dest.host();\n\n            const size_t sk = src.k(), snr = src.nr(), snc = src.nc();\n            const size_t dk = dest.k(), dnr = dest.nr(), dnc = dest.nc(), dsize = dest.size();\n\n            dlib::parallel_for(0, dsize, [&](long i)\n            {\n                const size_t out_plane_size = dnr * dnc;\n                const size_t out_sample_size = dk * out_plane_size;\n\n                const size_t n = i / out_sample_size;\n                const size_t out_idx = i % out_sample_size;\n                const size_t out_k = out_idx / out_plane_size;\n                const size_t out_rc = out_idx % out_plane_size;\n                const size_t out_r = out_rc / dnc;\n                const size_t out_c = out_rc % dnc;\n\n                const size_t in_k = out_k % sk;\n                const size_t in_r = out_r * row_stride + (out_k / sk) / col_stride;\n                const size_t in_c = out_c * col_stride + (out_k / sk) % col_stride;\n\n                const size_t in_idx = ((n * sk + in_k) * snr + in_r) * snc + in_c;\n\n                if (add_to) d[i] += s[in_idx];\n                else d[i] = s[in_idx];\n            });\n        }\n\n        void reorg_gradient(\n            bool add_to,\n            tensor& grad,\n            const int row_stride,\n            const int col_stride,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(!is_same_object(grad, gradient_input), \"Grad and gradient_input must be distinct objects.\");\n            DLIB_CASSERT(grad.nr() % row_stride == 0, \"The number of rows in grad must be divisible by row_stride.\");\n            DLIB_CASSERT(grad.nc() % col_stride == 0, \"The number of columns in grad must be divisible by col_stride.\");\n            DLIB_CASSERT(grad.num_samples() == gradient_input.num_samples(), \"The number of samples in grad and gradient_input must match.\");\n            DLIB_CASSERT(grad.k() == gradient_input.k() / row_stride / col_stride, \"The number of channels in grad must be gradient_input.k() divided by row_stride and col_stride.\");\n            DLIB_CASSERT(grad.nr() == gradient_input.nr() * row_stride, \"The number of rows in grad must be gradient_input.nr() multiplied by row_stride.\");\n            DLIB_CASSERT(grad.nc() == gradient_input.nc() * col_stride, \"The number of columns in grad must be gradient_input.nc() multiplied by col_stride.\");\n\n            const float* gi = gradient_input.host();\n            float* g = grad.host();\n\n            parallel_for(0, gradient_input.num_samples(), [&](long n)\n            {\n                for (long k = 0; k < gradient_input.k(); ++k)\n                {\n                    for (long r = 0; r < gradient_input.nr(); ++r)\n                    {\n                        for (long c = 0; c < gradient_input.nc(); ++c)\n                        {\n                                const auto in_idx = tensor_index(gradient_input, n, k, r, c);\n                                const auto out_idx = tensor_index(grad,\n                                    n,\n                                    k % grad.k(),\n                                    r * row_stride + (k / grad.k()) / col_stride,\n                                    c * col_stride + (k / grad.k()) % col_stride);\n                                \n                                if (add_to) g[out_idx] += gi[in_idx];\n                                else g[out_idx] = gi[in_idx];\n                        }\n                    }\n                }\n            });\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void embeddings(\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& embs\n        )\n        {\n            DLIB_CASSERT(\n                src.nr() > 0 &&\n                embs.num_samples() > 0 &&\n                embs.k() > 0 &&\n                embs.nr() == 1 &&\n                embs.nc() == 1,\n                \"\\nsrc.num_samples(): \" << src.num_samples() <<\n                \"\\nsrc.k(): \" << src.k() <<\n                \"\\nsrc.nr(): \" << src.nr() <<\n                \"\\nsrc.nc(): \" << src.nc() <<\n                \"\\nembs.num_samples(): \" << embs.num_samples() <<\n                \"\\nembs.k(): \" << embs.k() <<\n                \"\\nembs.nr(): \" << embs.nr() <<\n                \"\\nembs.nc(): \" << embs.nc()\n            );\n\n            long ns = dest.num_samples(), nk = dest.k(), nr = dest.nr(), nc = dest.nc();\n            const float* src_data = src.host();\n            float* dest_data = dest.host();\n            const float* embs_data = embs.host();\n            for (long s = 0; s < ns; ++s)\n            {\n                for (long k = 0; k < nk; ++k)\n                {\n                    for (long r = 0; r < nr; ++r)\n                    {\n                        const unsigned long token_idx = static_cast<unsigned long>(src_data[tensor_index(src, s, k, r, 0)]);\n                        if (token_idx < embs.num_samples())\n                        {\n                            for (long c = 0; c < nc; ++c)\n                                dest_data[tensor_index(dest, s, k, r, c)] = embs_data[tensor_index(embs, token_idx, c, 0, 0)];\n                        }\n                        else\n                        {\n                            for (long c = 0; c < nc; ++c)\n                                dest_data[tensor_index(dest, s, k, r, c)] = 0;\n                        }\n                    }\n                }\n            }\n        }\n\n        void embeddings_gradient(\n            const tensor& prev,\n            const tensor& gradient_input,\n            tensor& grads,\n            const tensor& freqs,\n            float learning_rate,\n            bool scale\n        )\n        {\n            DLIB_CASSERT(\n                prev.nr() > 0 &&\n                gradient_input.num_samples() == prev.num_samples() &&\n                gradient_input.k() == prev.k() &&\n                gradient_input.nr() == prev.nr() &&\n                gradient_input.nc() == grads.k() &&\n                grads.num_samples() > 0 &&\n                grads.k() > 0 &&\n                grads.nr() == 1 &&\n                grads.nc() == 1,\n                \"\\ngradient_input.num_samples(): \" << gradient_input.num_samples() <<\n                \"\\ngradient_input.k(): \" << gradient_input.k() <<\n                \"\\ngradient_input.nr(): \" << gradient_input.nr() <<\n                \"\\ngradient_input.nc(): \" << gradient_input.nc() <<\n                \"\\nprev.num_samples(): \" << prev.num_samples() <<\n                \"\\nprev.k(): \" << prev.k() <<\n                \"\\nprev.nr(): \" << prev.nr() <<\n                \"\\nprev.nc(): \" << prev.nc() <<\n                \"\\ngrads.num_samples(): \" << grads.num_samples() <<\n                \"\\ngrads.k(): \" << grads.k() <<\n                \"\\ngrads.nr(): \" << grads.nr() <<\n                \"\\ngrads.nc(): \" << grads.nc()\n            );\n\n            const float* prev_data = prev.host();\n            const float* gradient_input_data = gradient_input.host();\n            const float* freqs_data = freqs.host();\n            float* grads_data = grads.host();\n            long ns = gradient_input.num_samples(), nk = gradient_input.k();\n            long nr = gradient_input.nr(), nc = gradient_input.nc();\n\n            std::vector<dlib::mutex> embedding_mutexes(grads.num_samples());\n            parallel_for(0, ns * nk, [&](long i)\n                {\n                    long s = i / nk;\n                    long k = i % nk;\n\n                    for (long r = 0; r < nr; ++r)\n                    {\n                        const unsigned long token_idx = static_cast<unsigned long>(prev_data[tensor_index(prev, s, k, r, 0)]);\n                        if (token_idx < grads.num_samples())\n                        {\n                            const float freg_token = freqs_data[token_idx];\n                            float freq_scale = 1.0f;\n\n                            if (scale && freg_token != 0.0f) freq_scale = std::min(0.15f, std::max(1.0f / freg_token, 1.0f));\n                            auto_mutex locker(embedding_mutexes[token_idx]);\n                            for (long c = 0; c < nc; ++c)\n                            {\n                                const float gradient = gradient_input_data[tensor_index(gradient_input, s, k, r, c)];\n                                grads_data[tensor_index(grads, token_idx, c, 0, 0)] -= (gradient * learning_rate * freq_scale);\n                            }\n                        }\n                    }\n                });\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        pooling::pooling (\n        ) : window_height(0),window_width(0),stride_y(0),stride_x(0),padding_y(0),padding_x(0),do_max_pooling(true)\n        {\n        }\n\n        void pooling::\n        clear(\n        )\n        {\n            window_height = 0;\n            window_width = 0;\n            stride_y = 0;\n            stride_x = 0;\n            padding_y = 0;\n            padding_x = 0;\n        }\n\n        void pooling::\n        setup_max_pooling(\n            int window_height_,\n            int window_width_,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_\n        )\n        {\n            DLIB_CASSERT(window_width_ > 0);\n            DLIB_CASSERT(window_height_ > 0);\n            DLIB_CASSERT(stride_y_ > 0);\n            DLIB_CASSERT(stride_x_ > 0);\n            DLIB_CASSERT(0 <= padding_y_ && padding_y_ < window_height_);\n            DLIB_CASSERT(0 <= padding_x_ && padding_x_ < window_width_);\n\n            window_height = window_height_;\n            window_width = window_width_;\n            stride_y = stride_y_;\n            stride_x = stride_x_;\n            padding_y = padding_y_;\n            padding_x = padding_x_;\n            do_max_pooling = true;\n        }\n\n        void pooling::\n        setup_avg_pooling(\n            int window_height_,\n            int window_width_,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_\n        )\n        {\n            DLIB_CASSERT(window_width_ > 0);\n            DLIB_CASSERT(window_height_ > 0);\n            DLIB_CASSERT(stride_y_ > 0);\n            DLIB_CASSERT(stride_x_ > 0);\n            DLIB_CASSERT(0 <= padding_y_ && padding_y_ < window_height_);\n            DLIB_CASSERT(0 <= padding_x_ && padding_x_ < window_width_);\n\n            window_height = window_height_;\n            window_width = window_width_;\n            stride_y = stride_y_;\n            stride_x = stride_x_;\n            padding_y = padding_y_;\n            padding_x = padding_x_;\n            do_max_pooling = false;\n        }\n\n        void pooling::\n        operator() (\n            resizable_tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(window_width > 0);\n            DLIB_CASSERT(window_height > 0);\n            DLIB_CASSERT(stride_y > 0);\n            DLIB_CASSERT(stride_x > 0);\n            DLIB_CASSERT(0 <= padding_y && padding_y < window_height);\n            DLIB_CASSERT(0 <= padding_x && padding_x < window_width);\n            DLIB_CASSERT(window_width  <= src.nc() + 2*padding_x,\n                \"Pooling windows must be small enough to fit into the padded image.\");\n            DLIB_CASSERT(window_height <= src.nr() + 2*padding_y,\n                \"Pooling windows must be small enough to fit into the padded image.\");\n\n            dest.set_size(\n                 src.num_samples(),\n                 src.k(),\n                 1+(src.nr()+2*padding_y-window_height)/stride_y,\n                 1+(src.nc()+2*padding_x-window_width)/stride_x\n                );\n\n            if (src.size() == 0)\n            {\n                dest = 0;\n                return;\n            }\n\n\n            auto d = dest.host();\n            const long x_offset = window_width/2 - padding_x;\n            const long y_offset = window_height/2 - padding_y;\n            if (does_max_pooling())\n            {\n                for (long n = 0; n < dest.num_samples(); ++n)\n                {\n                    for (long k = 0; k < dest.k(); ++k)\n                    {\n                        auto simg = image_plane(src,n,k);\n                        auto dimg = d + (n*dest.k() + k)*dest.nr()*dest.nc();\n\n                        for (long r = 0; r < dest.nr(); ++r)\n                        {\n                            for (long c = 0; c < dest.nc(); ++c)\n                            {\n                                auto win = centered_rect(c*stride_x+x_offset,\n                                    r*stride_y+y_offset,\n                                    window_width,\n                                    window_height);\n                                dimg[r*dest.nc() + c] = max(subm_clipped(simg,win));\n                            }\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (long n = 0; n < dest.num_samples(); ++n)\n                {\n                    for (long k = 0; k < dest.k(); ++k)\n                    {\n                        auto simg = image_plane(src,n,k);\n                        auto dimg = d + (n*dest.k() + k)*dest.nr()*dest.nc();\n\n                        for (long r = 0; r < dest.nr(); ++r)\n                        {\n                            for (long c = 0; c < dest.nc(); ++c)\n                            {\n                                auto win = centered_rect(c*stride_x+x_offset,\n                                    r*stride_y+y_offset,\n                                    window_width,\n                                    window_height);\n                                dimg[r*dest.nc() + c] = mean(subm_clipped(simg,win));\n                            }\n                        }\n                    }\n                }\n            }\n\n        }\n\n        void pooling::get_gradient(\n            const tensor& gradient_input, \n            const tensor& dest,\n            const tensor& src,\n            tensor& grad \n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(gradient_input,dest));\n            DLIB_CASSERT(have_same_dimensions(src,grad));\n\n\n            if (src.size() == 0)\n            {\n                return;\n            }\n\n\n            auto gi = gradient_input.host();\n            auto g = grad.host();\n            const long x_offset = window_width/2 - padding_x;\n            const long y_offset = window_height/2 - padding_y;\n            if (does_max_pooling())\n            {\n                for (long n = 0; n < dest.num_samples(); ++n)\n                {\n                    for (long k = 0; k < dest.k(); ++k)\n                    {\n                        auto simg = image_plane(src,n,k);\n                        auto gimg = g + (n*grad.k() + k)*grad.nr()*grad.nc();\n                        auto giimg = gi + (n*dest.k() + k)*dest.nr()*dest.nc();\n                        auto imgbox = get_rect(simg);\n\n                        for (long r = 0; r < dest.nr(); ++r)\n                        {\n                            for (long c = 0; c < dest.nc(); ++c)\n                            {\n                                auto win = centered_rect(c*stride_x+x_offset,\n                                    r*stride_y+y_offset,\n                                    window_width,\n                                    window_height).intersect(imgbox);\n                                auto p = max_point(subm(simg,win))+win.tl_corner();\n                                gimg[p.y()*grad.nc()+p.x()] += giimg[r*dest.nc()+c];\n                            }\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (long n = 0; n < dest.num_samples(); ++n)\n                {\n                    for (long k = 0; k < dest.k(); ++k)\n                    {\n                        auto simg = image_plane(src,n,k);\n                        auto gimg = g + (n*grad.k() + k)*grad.nr()*grad.nc();\n                        auto giimg = gi + (n*dest.k() + k)*dest.nr()*dest.nc();\n                        auto imgbox = get_rect(simg);\n\n                        for (long r = 0; r < dest.nr(); ++r)\n                        {\n                            for (long c = 0; c < dest.nc(); ++c)\n                            {\n                                auto win = centered_rect(c*stride_x+x_offset,\n                                    r*stride_y+y_offset,\n                                    window_width,\n                                    window_height).intersect(imgbox);\n                                const float delta = giimg[r*dest.nc()+c]/win.area();\n                                for (long y = win.top(); y <= win.bottom(); ++y)\n                                {\n                                    for (long x = win.left(); x <= win.right(); ++x)\n                                    {\n                                        gimg[y*grad.nc()+x] += delta;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        void img2col(\n            matrix<float>& output,\n            const tensor& data,\n            long n,\n            long filter_nr,\n            long filter_nc,\n            long stride_y,\n            long stride_x,\n            long padding_y,\n            long padding_x\n        )\n        {\n            const auto d = data.host() + data.k()*data.nr()*data.nc()*n;\n            const rectangle boundary = get_rect(data);\n\n            const long out_nr = 1+(data.nr()+2*padding_y-filter_nr)/stride_y;\n            const long out_nc = 1+(data.nc()+2*padding_x-filter_nc)/stride_x;\n\n            output.set_size(out_nr*out_nc, \n                            data.k()*filter_nr*filter_nc);\n            DLIB_CASSERT(output.size() != 0);\n            float* t = &output(0,0);\n\n            // now fill in the Toeplitz output matrix for the n-th sample in data.  \n            long cnt = 0;\n            const long max_r = data.nr() + padding_y-(filter_nr-1);\n            const long max_c = data.nc() + padding_x-(filter_nc-1);\n            for (long r = -padding_y; r < max_r; r+=stride_y)\n            {\n                for (long c = -padding_x; c < max_c; c+=stride_x)\n                {\n                    for (long k = 0; k < data.k(); ++k)\n                    {\n                        for (long y = 0; y < filter_nr; ++y)\n                        {\n                            for (long x = 0; x < filter_nc; ++x)\n                            {\n                                DLIB_ASSERT(cnt < output.size());\n                                long xx = c+x;\n                                long yy = r+y;\n                                if (boundary.contains(xx,yy))\n                                    *t = d[(k*data.nr() + yy)*data.nc() + xx];\n                                else\n                                    *t = 0;\n                                ++t;\n                                ++cnt;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        void col2img(\n            const matrix<float>& output,\n            tensor& data,\n            long n,\n            long filter_nr,\n            long filter_nc,\n            long stride_y,\n            long stride_x,\n            long padding_y,\n            long padding_x\n        )\n        {\n            const auto d = data.host() + data.k()*data.nr()*data.nc()*n;\n            const rectangle boundary = get_rect(data);\n\n            DLIB_CASSERT(output.size() != 0);\n            const float* t = &output(0,0);\n\n            // now fill in the Toeplitz output matrix for the n-th sample in data.  \n            const long max_r = data.nr() + padding_y-(filter_nr-1);\n            const long max_c = data.nc() + padding_x-(filter_nc-1);\n            for (long r = -padding_y; r < max_r; r+=stride_y)\n            {\n                for (long c = -padding_x; c < max_c; c+=stride_x)\n                {\n                    for (long k = 0; k < data.k(); ++k)\n                    {\n                        for (long y = 0; y < filter_nr; ++y)\n                        {\n                            for (long x = 0; x < filter_nc; ++x)\n                            {\n                                long xx = c+x;\n                                long yy = r+y;\n                                if (boundary.contains(xx,yy))\n                                    d[(k*data.nr() + yy)*data.nc() + xx] += *t;\n                                ++t;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters\n        )\n        {\n            DLIB_CASSERT(last_stride_y > 0 && last_stride_x > 0, \"You must call setup() before calling this function.\");\n            output.set_size(data.num_samples(),\n                            filters.num_samples(),\n                            1+(data.nr()+2*last_padding_y-filters.nr())/last_stride_y,\n                            1+(data.nc()+2*last_padding_x-filters.nc())/last_stride_x);\n            (*this)(add_to_output, static_cast<tensor&>(output),data,filters);\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters\n        )\n        {\n            DLIB_CASSERT(is_same_object(output,data) == false);\n            DLIB_CASSERT(is_same_object(output,filters) == false);\n            DLIB_CASSERT(filters.k() == data.k());\n            DLIB_CASSERT(last_stride_y > 0 && last_stride_x > 0, \"You must call setup() before calling this function.\");\n            DLIB_CASSERT(filters.nr() <= data.nr() + 2*last_padding_y,\n                \"Filter windows must be small enough to fit into the padded image.\");\n            DLIB_CASSERT(filters.nc() <= data.nc() + 2*last_padding_x,\n                \"Filter windows must be small enough to fit into the padded image.\");\n\n            DLIB_CASSERT(output.num_samples() == data.num_samples());\n            DLIB_CASSERT(output.k() == filters.num_samples());\n            DLIB_CASSERT(output.nr() == 1+(data.nr()+2*last_padding_y-filters.nr())/last_stride_y);\n            DLIB_CASSERT(output.nc() == 1+(data.nc()+2*last_padding_x-filters.nc())/last_stride_x);\n\n\n            matrix<float> temp;\n            for (long n = 0; n < data.num_samples(); ++n)\n            {\n                img2col(temp, data, n, filters.nr(), filters.nc(), last_stride_y, last_stride_x, last_padding_y, last_padding_x);\n\n                if (add_to_output)\n                    output.add_to_sample(n, mat(filters)*trans(temp));\n                else \n                    output.set_sample(n, mat(filters)*trans(temp));\n            }\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        )\n        {\n            DLIB_CASSERT(filters.num_samples() == biases.k());\n            (*this)(add_to_output, output,data,filters);\n            tt::add(1, output, 1, biases);\n            if (use_relu) tt::relu(output, output);\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        )\n        {\n            DLIB_CASSERT(filters.num_samples() == biases.k());\n            (*this)(add_to_output, output, data, filters);\n            tt::add(1, output, 1, biases);\n            if (use_relu) tt::relu(output, output);\n        }\n\n\n    // ------------------------------------------------------------------------------------\n\n        void tensor_conv::\n        get_gradient_for_data (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& filters,\n            tensor& data_gradient\n        )\n        {\n            matrix<float> temp;\n            if (!add_to_output)\n                data_gradient = 0;\n            for (long n = 0; n < gradient_input.num_samples(); ++n)\n            {\n                auto gi = mat(gradient_input.host()+gradient_input.k()*gradient_input.nr()*gradient_input.nc()*n,\n                              gradient_input.k(),\n                              gradient_input.nr()*gradient_input.nc());\n                                    \n\n                temp = trans(gi)*mat(filters);\n                col2img(temp, data_gradient, n, filters.nr(), filters.nc(), last_stride_y, last_stride_x, last_padding_y, last_padding_x);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void tensor_conv::\n        get_gradient_for_filters (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& data,\n            tensor& filters_gradient\n        )\n        {\n            matrix<float> temp;\n            for (long n = 0; n < gradient_input.num_samples(); ++n)\n            {\n                auto gi = mat(gradient_input.host()+gradient_input.k()*gradient_input.nr()*gradient_input.nc()*n,\n                              gradient_input.k(),\n                              gradient_input.nr()*gradient_input.nc());\n\n\n                img2col(temp, data, n, filters_gradient.nr(), filters_gradient.nc(), last_stride_y, last_stride_x, last_padding_y, last_padding_x);\n                if (n == 0)\n                {\n                    if (add_to_output)\n                        filters_gradient += gi*temp;\n                    else\n                        filters_gradient = gi*temp;\n                }\n                else\n                {\n                    filters_gradient += gi*temp;\n                }\n            }\n        }\n\n     // ------------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n        )\n        {\n            const size_t dest_sample_size = static_cast<size_t>(dest.nc() * dest.nr() * dest.k());\n            const size_t src_sample_size = static_cast<size_t>(src.nc() * src.nr() * src.k());\n\n            const size_t block_size = count_k * dest.nc() * dest.nr();\n\n            DLIB_CASSERT(dest.num_samples() == src.num_samples() &&\n                dest.nc() == src.nc() && dest.nr() == src.nr(), \"All sources should fit into dest tensor size\");\n            DLIB_CASSERT(dest.k() - dest_k_offset >= count_k, \"Not enough space in dest tensor\");\n            DLIB_CASSERT(src.k() - src_k_offset >= count_k, \"Not enough space in src tensor\");\n\n            float* dest_p = dest.host() + dest_k_offset * dest.nc() * dest.nr();\n            const float* src_p = src.host() + src_k_offset * src.nc() * src.nr();\n\n            for (long i = 0; i < src.num_samples(); ++i)\n            {\n                if (add_to)\n                {\n                    for (size_t j = 0; j < block_size; ++j)\n                        dest_p[j] += src_p[j];\n                }\n                else\n                {\n                    ::memcpy(dest_p, src_p, block_size * sizeof(float));\n                }\n\n                dest_p += dest_sample_size;\n                src_p  += src_sample_size;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dk, size_t dnr, size_t dnc,\n            const tensor& src,\n            size_t sk, size_t snr, size_t snc,\n            size_t k, size_t nr, size_t nc\n        )\n        {\n            size_t dest_stride_sample = static_cast<size_t>(dest.nc() * dest.nr() * dest.k());\n            size_t dest_stride_k      = static_cast<size_t>(dest.nc() * dest.nr());\n            size_t dest_stride_nr     = static_cast<size_t>(dest.nc());\n\n            size_t src_stride_sample = static_cast<size_t>(src.nc() * src.nr() * src.k());\n            size_t src_stride_k      = static_cast<size_t>(src.nc() * src.nr());\n            size_t src_stride_nr     = static_cast<size_t>(src.nc());\n\n            DLIB_CASSERT(dest.num_samples() == src.num_samples(), \"All sources should fit into dest tensor size\");\n            DLIB_CASSERT(dest.k() - dk >= k &&\n                dest.nr() - dnr >= nr &&\n                dest.nc() - dnc >= nc, \"Not enough space in dest tensor\");\n            DLIB_CASSERT(src.k() - sk >= k &&\n                src.nr() - snr >= nr &&\n                src.nc() - snc >= nc, \"Not enough space in src tensor\");\n\n            float* dest_p = dest.host() + dk * dest_stride_k \\\n                                        + dnr * dest_stride_nr \\\n                                        + dnc;\n\n            const float* src_p = src.host() + sk * src_stride_k \\\n                                            + snr * src_stride_nr \\\n                                            + snc;\n\n            for (long i = 0; i < src.num_samples(); ++i)\n            {\n                float* dest_channel_p = dest_p;\n                const float* src_channel_p = src_p;\n\n                for (long j = 0; j < k; ++j)\n                {\n                    float* dest_row_p = dest_channel_p;\n                    const float* src_row_p = src_channel_p;\n\n                    for (long r = 0; r < nr; ++r)\n                    {\n                        if (add_to)\n                        {\n                            for (size_t c = 0; c < nc; ++c)\n                                dest_row_p[c] += src_row_p[c];\n                        }\n                        else\n                        {\n                            ::memcpy(dest_row_p, src_row_p, nc * sizeof(float));\n                        }\n\n                        dest_row_p += dest_stride_nr;\n                        src_row_p += src_stride_nr;\n                    }\n\n                    dest_channel_p += dest_stride_k;\n                    src_channel_p += src_stride_k;\n                }\n\n                dest_p += dest_stride_sample;\n                src_p  += src_stride_sample;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void transpose(\n            bool add,\n            tensor& dest,\n            const tensor& src            \n        )\n        {\n            DLIB_CASSERT(dest.num_samples() == src.num_samples() &&\n                dest.k() == src.k() &&\n                dest.nr() == src.nc() &&\n                dest.nc() == src.nr(),\n                \"Incompatible tensor dimensions.\");\n\n            const float* src_data = src.host();\n            float* dest_data = dest.host();\n\n            const long num_samples = src.num_samples();\n            const long k_dim = src.k();\n            const long src_nr = src.nr();\n            const long src_nc = src.nc();\n            const long dest_nr = dest.nr();\n            const long dest_nc = dest.nc();\n\n            parallel_for(0, num_samples * k_dim, [&](long i) {\n                const long n = i / k_dim;\n                const long k = i % k_dim;\n                const long src_nk_offset = (n * src.k() + k) * src_nr;\n                const long dest_nk_offset = (n * dest.k() + k) * dest_nr;\n\n                for (long r = 0; r < src_nr; ++r) {\n                    for (long c = 0; c < src_nc; ++c) {\n                        const long src_idx = (src_nk_offset + r) * src_nc + c;\n                        const long dest_idx = (dest_nk_offset + c) * dest_nc + r;\n\n                        if (add) dest_data[dest_idx] += src_data[src_idx];\n                        else dest_data[dest_idx] = src_data[src_idx];\n                    }\n                }\n            });\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void compute_act_halt_probabilities(\n            resizable_tensor& halt_probs,\n            resizable_tensor& logits,\n            const tensor& input_data,\n            const tensor& halt_params,\n            long batch_size,\n            long seq_len,\n            long feature_dim\n        )\n        {\n            const float* in_ptr = input_data.host();\n            const float* W_halt = halt_params.host();\n            const float b_halt = halt_params.host()[feature_dim];\n            float* logits_ptr = logits.host();\n            float* halt_probs_ptr = halt_probs.host();\n\n            const long d_model = feature_dim / input_data.k();\n            const long num_channels = input_data.k();\n\n            for (long pos = 0; pos < batch_size * seq_len; ++pos) {\n                const long n = pos / seq_len;\n                const long s = pos % seq_len;\n\n                float logit = b_halt;\n\n                for (long c = 0; c < num_channels; ++c) {\n                    for (long d = 0; d < d_model; ++d) {\n                        const long in_idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                        const long weight_idx = c * d_model + d;\n                        logit += in_ptr[in_idx] * W_halt[weight_idx];\n                    }\n                }\n\n                logits_ptr[pos] = logit;\n\n                halt_probs_ptr[pos] = 1.0f / (1.0f + std::exp(-logit));\n            }\n        }\n\n        void update_act_state(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& halt_probs,\n            resizable_tensor& cumulative_halting,\n            resizable_tensor& remainders,\n            resizable_tensor& n_steps,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float halt_threshold,\n            long current_step\n        )\n        {\n            const float* in_ptr = input_data.host();\n            const float* p_halt = halt_probs.host();\n            float* out_ptr = output.host();\n            float* cum_halt = cumulative_halting.host();\n            float* remain = remainders.host();\n            float* steps = n_steps.host();\n            float* eff_weights = effective_weights.host();\n\n            for (long pos = 0; pos < batch_size * seq_len; ++pos) {\n                if (cum_halt[pos] < halt_threshold) {\n                    const long n = pos / seq_len;\n                    const long s = pos % seq_len;\n\n                    float p = p_halt[pos];\n                    float r = remain[pos];\n                    float effective = std::min(p * r, halt_threshold - cum_halt[pos]);\n\n                    cum_halt[pos] += effective;\n                    remain[pos] -= effective;\n                    steps[pos] = static_cast<float>(current_step + 1);\n                    eff_weights[pos] += effective;\n\n                    for (long c = 0; c < num_channels; ++c) {\n                        for (long d = 0; d < d_model; ++d) {\n                            const long idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                            out_ptr[idx] += effective * in_ptr[idx];\n                        }\n                    }\n                }\n            }\n        }\n\n        void finalize_act_output(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& remainders,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels\n        )\n        {\n            const float* in_ptr = input_data.host();\n            const float* remain = remainders.host();\n            float* out_ptr = output.host();\n            float* eff_weights = effective_weights.host();\n\n            for (long pos = 0; pos < batch_size * seq_len; ++pos) {\n                float r = remain[pos];\n                if (r > 1e-6f) {\n                    const long n = pos / seq_len;\n                    const long s = pos % seq_len;\n\n                    eff_weights[pos] += r;\n\n                    for (long c = 0; c < num_channels; ++c) {\n                        for (long d = 0; d < d_model; ++d) {\n                            const long idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                            out_ptr[idx] += r * in_ptr[idx];\n                        }\n                    }\n                }\n            }\n        }\n\n        void apply_act_depth_scaling(\n            tensor& gradients,\n            const tensor& n_steps,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float max_steps,\n            float scale_factor\n        )\n        {\n            const float* steps = n_steps.host();\n            float* grad_ptr = gradients.host();\n\n            for (long pos = 0; pos < batch_size * seq_len; ++pos)\n            {\n                const float scale = 1.0f + scale_factor * (steps[pos] / max_steps);\n                const long n = pos / seq_len;\n                const long s = pos % seq_len;\n\n                for (long c = 0; c < num_channels; ++c)\n                {\n                    for (long d = 0; d < d_model; ++d)\n                    {\n                        const long idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                        grad_ptr[idx] *= scale;\n                    }\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n    \n    } \n}\n\n\n#endif // DLIB_DNN_CPU_cPP_\n\n\n"
  },
  {
    "path": "dlib/cuda/cpu_dlib.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CPU_H_\n#define DLIB_DNN_CPU_H_\n\n// This file contains CPU implementations of the GPU based functions in cuda_dlib.h\n// and cudnn_dlibapi.h\n\n#include \"tensor.h\"\n#include \"../geometry/rectangle.h\"\n#include \"../dnn/utilities.h\"\n\nnamespace dlib\n{\n    namespace cpu \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        void multiply (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void multiply_conv (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void multiply_zero_padded (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void scale_channels (\n            bool add_to,\n            tensor& dest,\n            const tensor& src,\n            const tensor& scales\n        );\n\n        void add(\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& src\n        );\n\n        void assign_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        );\n\n        void add (\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void assign_conv_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A,\n            const float B\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B,\n            const float C\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C,\n            const float D\n        );\n\n        void affine_transform_range(\n            size_t begin,\n            size_t end,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform_conv(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            const rectangle& rect,\n            tensor& dest, \n            const tensor& src1, \n            const tensor& src2, \n            const tensor& src3, \n            float A, \n            float B,\n            float C\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void compute_adam_update (\n            size_t begin,\n            size_t end,\n            tensor& s,\n            tensor& m,\n            tensor& v,\n            const float t,\n            const float learning_rate,\n            const float weight_decay,\n            const float momentum1,\n            const float momentum2,\n            const tensor& params,\n            const tensor& params_grad\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void batch_normalize_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        );\n\n        void batch_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        );\n\n        void batch_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        );\n\n        void batch_normalize_conv_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        );\n\n        void batch_normalize_conv (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        );\n\n        void batch_normalize_conv_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void layer_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            const tensor& beta\n        );\n\n        void layer_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n        );\n\n   // -----------------------------------------------------------------------------------\n\n        void rms_normalize(\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& scale,\n            const tensor& src,\n            const tensor& gamma\n        );\n\n        void rms_normalize_gradient(\n            const tensor& gradient_input,\n            const tensor& scale,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            resizable_tensor& dscale\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void threshold (\n            tensor& data,\n            float thresh\n        );\n\n        void dot (\n            const tensor& a,\n            const tensor& b,\n            tensor& result,\n            size_t idx\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void softmax(\n            tensor& dest,\n            const tensor& src,\n            operation_mode mode = operation_mode::CHANNEL_WISE\n        );\n\n        void softmax_gradient(\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            operation_mode mode = operation_mode::CHANNEL_WISE\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax_all (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void softmax_all_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void sigmoid (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void sigmoid_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void mish (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void mish_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void relu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void prelu (\n            tensor& dest,\n            const tensor& src,\n            const tensor& param\n        );\n\n        void prelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const tensor& param,\n            tensor& params_grad \n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void leaky_relu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        );\n\n        void leaky_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void tanh (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void tanh_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void clipped_relu (\n            tensor& dest,\n            const tensor& src,\n            const float ceiling\n        );\n\n        void clipped_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float ceiling\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void elu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        );\n\n        void elu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void gelu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void gelu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void smelu (\n            tensor& dest,\n            const tensor& src,\n            const float beta\n        );\n\n        void smelu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float beta\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void silu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void silu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void resize_bilinear (\n            tensor& dest,\n            long long dest_row_stride,\n            long long dest_channel_stride,\n            const tensor& src,\n            long long src_row_stride,\n            long long src_channel_stride\n        );\n\n        void resize_bilinear_gradient (\n            tensor& grad,\n            long long grad_row_stride,\n            long long grad_channel_stride,\n            const tensor& gradient_input,\n            long long gradient_input_row_stride,\n            long long gradient_input_channel_stride\n        );\n\n        inline void resize_bilinear (\n            tensor& dest,\n            const tensor& src\n        ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); }\n\n        inline void resize_bilinear_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); }\n\n    // -----------------------------------------------------------------------------------\n\n        void reorg (\n            bool add_to,\n            tensor& dest,\n            const int row_stride,\n            const int col_stride,\n            const tensor& src\n        );\n\n        void reorg_gradient (\n            bool add_to,\n            tensor& grad,\n            const int row_stride,\n            const int col_stride,\n            const tensor& gradient_input\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void embeddings(\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& embs\n        );\n\n        void embeddings_gradient(\n            const tensor& prev,\n            const tensor& gradient_input,\n            tensor& grads,\n            const tensor& freqs,\n            float learning_rate,\n            bool scale\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void compute_act_halt_probabilities(\n            resizable_tensor& halt_probs,\n            resizable_tensor& logits,\n            const tensor& input_data,\n            const tensor& halt_params,\n            long batch_size,\n            long seq_len,\n            long feature_dim\n        );\n\n        void update_act_state(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& halt_probs,\n            resizable_tensor& cumulative_halting,\n            resizable_tensor& remainders,\n            resizable_tensor& n_steps,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float halt_threshold,\n            long current_step\n        );\n\n        void finalize_act_output(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& remainders,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels\n        );\n\n        void apply_act_depth_scaling(\n            tensor& gradients,\n            const tensor& n_steps,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float max_steps,\n            float scale_factor\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        class pooling\n        {\n        public:\n\n            pooling(const pooling&) = delete;\n            pooling& operator=(const pooling&) = delete;\n\n            pooling (\n            );\n\n            void clear(\n            );\n\n            void setup_max_pooling(\n                int window_height,\n                int window_width,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n            void setup_avg_pooling(\n                int window_height,\n                int window_width,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n            bool does_max_pooling(\n            ) const { return do_max_pooling; }\n\n            void operator() (\n                resizable_tensor& dest,\n                const tensor& src\n            );\n\n            void get_gradient(\n                const tensor& gradient_input, \n                const tensor& dest,\n                const tensor& src,\n                tensor& grad \n            );\n\n        private:\n            int window_height;\n            int window_width;\n            int stride_y;\n            int stride_x;\n            int padding_y;\n            int padding_x;\n            bool do_max_pooling;\n\n        };\n\n    // -----------------------------------------------------------------------------------\n\n        class tensor_conv\n        {\n        public:\n            tensor_conv(const tensor_conv&) = delete;\n            tensor_conv& operator=(const tensor_conv&) = delete;\n\n            tensor_conv() {}\n\n            void clear(\n            ) {}\n\n            void setup(\n                const tensor& data,    /* not used but required for interface */\n                const tensor& filters, /* not used but required for interface */\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            ) \n            {\n                (void)data;    /* silence compiler */\n                DLIB_CASSERT(stride_y > 0 && stride_x > 0);\n                DLIB_CASSERT(0 <= padding_y && padding_y < filters.nr());\n                DLIB_CASSERT(0 <= padding_x && padding_x < filters.nc());\n                last_stride_y = stride_y;\n                last_stride_x = stride_x;\n                last_padding_y = padding_y;\n                last_padding_x = padding_x;            \n            }\n\n             void operator() (\n                const bool add_to_output,\n                resizable_tensor& output,\n                const tensor& data,\n                const tensor& filters\n            );\n\n             void operator() (\n                const bool add_to_output,\n                tensor& output,\n                const tensor& data,\n                const tensor& filters\n            );\n\n            void operator() (\n                const bool add_to_output,\n                resizable_tensor& output,\n                const tensor& data,\n                const tensor& filters,\n                const tensor& biases,\n                bool use_relu\n            );\n\n            void operator() (\n                const bool add_to_output,\n                tensor& output,\n                const tensor& data,\n                const tensor& filters,\n                const tensor& biases,\n                bool use_relu\n            );\n\n            void get_gradient_for_data (\n                const bool add_to_output,\n                const tensor& gradient_input, \n                const tensor& filters,\n                tensor& data_gradient\n            );\n\n            void get_gradient_for_filters (\n                const bool add_to_output,\n                const tensor& gradient_input, \n                const tensor& data,\n                tensor& filters_gradient\n            );\n\n        private:\n\n            long last_stride_y = 0;\n            long last_stride_x = 0;\n            long last_padding_y = 0;\n            long last_padding_x = 0;\n        };\n\n    // -----------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dk, size_t dnr, size_t dnc,\n            const tensor& src,\n            size_t sk, size_t snr, size_t snc,\n            size_t k, size_t nr, size_t nc\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void transpose(\n            bool add_to,\n            tensor& dest,\n            const tensor& src\n        );\n\n    // -----------------------------------------------------------------------------------\n\n    class compute_loss_binary_log_per_pixel\n    {\n\n        /*! The point of this class is to compute the loss for loss_binary_log_per_pixel_\n            on the cpu to provide an analogous implementation of the cuda version\n        !*/\n    public:\n        compute_loss_binary_log_per_pixel(\n        )\n        {\n        }\n\n        template <\n            typename const_label_iterator\n            >\n        void operator()(\n            const_label_iterator truth,\n            const tensor& output_tensor,\n            tensor& grad,\n            double& loss\n        ) const\n        {\n            sigmoid(grad, output_tensor);\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0/(output_tensor.num_samples()*output_tensor.nr()*output_tensor.nc());\n            loss = 0;\n            float* const g = grad.host();\n            const float* const out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        const float y = truth->operator()(r, c);\n                        const size_t idx = tensor_index(output_tensor, i, 0, r, c);\n\n                        if (y > 0.f)\n                        {\n                            const float temp = log1pexp(-out_data[idx]);\n                            loss += y*scale*temp;\n                            g[idx] = y*scale*(g[idx]-1);\n                        }\n                        else if (y < 0.f)\n                        {\n                            const float temp = -(-out_data[idx]-log1pexp(-out_data[idx]));\n                            loss += -y*scale*temp;\n                            g[idx] = -y*scale*g[idx];\n                        }\n                        else\n                        {\n                            g[idx] = 0.f;\n                        }\n                    }\n                }\n            }\n        }\n    };\n\n    // -----------------------------------------------------------------------------------\n\n    class compute_loss_multiclass_log_per_pixel\n    {\n\n        /*! The point of this class is to compute the loss for loss_multiclass_log_per_pixel_\n            on the cpu to provide an analogous implementation of the cuda version\n        !*/\n    public:\n        compute_loss_multiclass_log_per_pixel(\n        )\n        {\n        }\n\n        template <\n            typename const_label_iterator\n            >\n        void operator()(\n            const_label_iterator truth,\n            const tensor& output_tensor,\n            tensor& grad,\n            double& loss\n        ) const\n        {\n            softmax(grad, output_tensor);\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc());\n            loss = 0;\n            float* const g = grad.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        const uint16_t y = truth->operator()(r, c);\n                        // The network must produce a number of outputs that is equal to the number\n                        // of labels when using this type of loss.\n                        DLIB_CASSERT(static_cast<long>(y) < output_tensor.k() || y == label_to_ignore,\n                                        \"y: \" << y << \", output_tensor.k(): \" << output_tensor.k());\n                        for (long k = 0; k < output_tensor.k(); ++k)\n                        {\n                            const size_t idx = tensor_index(output_tensor, i, k, r, c);\n                            if (k == y)\n                            {\n                                loss += scale*-safe_log(g[idx]);\n                                g[idx] = scale*(g[idx] - 1);\n                            }\n                            else if (y == label_to_ignore)\n                            {\n                                g[idx] = 0.f;\n                            }\n                            else\n                            {\n                                g[idx] = scale*g[idx];\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    private:\n        static const uint16_t label_to_ignore = std::numeric_limits<uint16_t>::max();\n    };\n\n    // -----------------------------------------------------------------------------------\n\n    class compute_loss_multiclass_log_per_pixel_weighted\n    {\n\n        /*! The point of this class is to compute the loss for loss_multiclass_log_per_pixel_weighted_\n            on the cpu to provide an analogous implementation of the cuda version\n        !*/\n    public:\n        compute_loss_multiclass_log_per_pixel_weighted(\n        )\n        {\n        }\n\n        template <\n            typename const_label_iterator\n            >\n        void operator()(\n            const_label_iterator truth,\n            const tensor& output_tensor,\n            tensor& grad,\n            double& loss\n        ) const\n        {\n            softmax(grad, output_tensor);\n            // The loss we output is the weighted average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc());\n            loss = 0;\n            float* const g = grad.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        const weighted_label<uint16_t>& weighted_label = truth->operator()(r, c);\n                        const uint16_t y = weighted_label.label;\n                        const float weight = weighted_label.weight;\n                        // The network must produce a number of outputs that is equal to the number\n                        // of labels when using this type of loss.\n                        DLIB_CASSERT(static_cast<long>(y) < output_tensor.k() || weight == 0.f,\n                                        \"y: \" << y << \", output_tensor.k(): \" << output_tensor.k());\n                        for (long k = 0; k < output_tensor.k(); ++k)\n                        {\n                            const size_t idx = tensor_index(output_tensor, i, k, r, c);\n                            if (k == y)\n                            {\n                                loss += weight*scale*-safe_log(g[idx]);\n                                g[idx] = weight*scale*(g[idx] - 1);\n                            }\n                            else\n                            {\n                                g[idx] = weight*scale*g[idx];\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n    };\n\n    // -----------------------------------------------------------------------------------\n\n    class compute_loss_mean_squared_per_channel_and_pixel\n    {\n        /*! The point of this class is to compute the loss for loss_mean_squared_per_channel_and_pixel_\n            on the cpu to provide an analogous implementation of the cuda version\n        !*/\n        public:\n\n            compute_loss_mean_squared_per_channel_and_pixel(\n            )\n            {\n            }\n\n        template <\n            typename const_label_iterator\n            >\n        void operator()(\n            const_label_iterator truth,\n            const tensor& output_tensor,\n            tensor& grad,\n            double& loss\n        ) const\n        {\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.k() * output_tensor.nr() * output_tensor.nc());\n            loss = 0;\n            float* const g = grad.host();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    for (long r = 0; r < output_tensor.nr(); ++r)\n                    {\n                        for (long c = 0; c < output_tensor.nc(); ++c)\n                        {\n                            const float y = (*truth)[k].operator()(r, c);\n                            const size_t idx = tensor_index(output_tensor, i, k, r, c);\n                            const float temp1 = y - out_data[idx];\n                            const float temp2 = scale*temp1;\n                            loss += temp2*temp1;\n                            g[idx] = -temp2;\n                        }\n                    }\n                }\n            }\n        }\n\n    };\n\n    // -----------------------------------------------------------------------------------\n\n    } \n}\n\n#ifdef NO_MAKEFILE\n#include \"cpu_dlib.cpp\"\n#endif\n\n#endif // DLIB_DNN_CPU_H_\n\n\n"
  },
  {
    "path": "dlib/cuda/cublas_dlibapi.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuBLAS_CPP_\n#define DLIB_DNN_CuBLAS_CPP_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"cublas_dlibapi.h\"\n#include \"cuda_utils.h\"\n\n#include <cublas_v2.h>\n#include <vector>\n\nstatic const char* cublas_get_error_string(cublasStatus_t s)\n{\n    switch(s)\n    {\n        case CUBLAS_STATUS_NOT_INITIALIZED: \n            return \"CUDA Runtime API initialization failed.\";\n        case CUBLAS_STATUS_ALLOC_FAILED: \n            return \"CUDA Resources could not be allocated.\";\n        default:\n            return \"A call to cuBLAS failed\";\n    }\n}\n\n// Check the return value of a call to the cuBLAS runtime for an error condition.\n#define CHECK_CUBLAS(call)                                                      \\\ndo{                                                                              \\\n    const cublasStatus_t error = call;                                         \\\n    if (error != CUBLAS_STATUS_SUCCESS)                                        \\\n    {                                                                          \\\n        std::ostringstream sout;                                               \\\n        sout << \"Error while calling \" << #call << \" in file \" << __FILE__ << \":\" << __LINE__ << \". \";\\\n        sout << \"code: \" << error << \", reason: \" << cublas_get_error_string(error);\\\n        throw dlib::cublas_error(sout.str());                            \\\n    }                                                                          \\\n}while(false)\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        class cublas_context\n        {\n        public:\n            // not copyable\n            cublas_context(const cublas_context&) = delete;\n            cublas_context& operator=(const cublas_context&) = delete;\n\n            cublas_context()\n            {\n                handles.resize(16);\n            }\n            ~cublas_context()\n            {\n                for (auto h : handles)\n                {\n                    if (h)\n                        cublasDestroy(h);\n                }\n            }\n\n            cublasHandle_t get_handle (\n            )  \n            { \n                int new_device_id;\n                CHECK_CUDA(cudaGetDevice(&new_device_id));\n                // make room for more devices if needed\n                if (new_device_id >= (long)handles.size())\n                    handles.resize(new_device_id+16);\n\n                // If we don't have a handle already for this device then make one\n                if (!handles[new_device_id])\n                    CHECK_CUBLAS(cublasCreate(&handles[new_device_id]));\n\n                // Finally, return the handle for the current device\n                return handles[new_device_id];\n            }\n\n        private:\n\n            std::vector<cublasHandle_t> handles;\n        };\n\n        static cublasHandle_t context()\n        {\n            thread_local cublas_context c;\n            return c.get_handle();\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        void gemm (\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& lhs,\n            bool trans_lhs,\n            const tensor& rhs,\n            bool trans_rhs,\n            operation_mode mode\n        )\n        {\n            if (mode == operation_mode::CHANNEL_WISE)\n            {\n                // Recall that BLAS uses column major order so to deal with that we flip the\n                // order of the lhs and rhs arguments.\n                const auto transa = trans_lhs ? CUBLAS_OP_T : CUBLAS_OP_N;\n                const auto transb = trans_rhs ? CUBLAS_OP_T : CUBLAS_OP_N;\n\n                const int dest_nr = dest.num_samples();\n                const int dest_nc = dest.size() / dest_nr;\n                const int lhs_nr = lhs.num_samples();\n                const int lhs_nc = lhs.size() / lhs_nr;\n                const int rhs_nr = rhs.num_samples();\n                const int rhs_nc = rhs.size() / rhs_nr;\n                if (trans_lhs && trans_rhs)\n                {\n                    DLIB_ASSERT(dest_nr == lhs_nc &&\n                        dest_nc == rhs_nr &&\n                        lhs_nr == rhs_nc)\n                }\n                else if (!trans_lhs && trans_rhs)\n                {\n                    DLIB_ASSERT(dest_nr == lhs_nr &&\n                        dest_nc == rhs_nr &&\n                        lhs_nc == rhs_nc)\n                }\n                else if (trans_lhs && !trans_rhs)\n                {\n                    DLIB_ASSERT(dest_nr == lhs_nc &&\n                        dest_nc == rhs_nc &&\n                        lhs_nr == rhs_nr)\n                }\n                else\n                {\n                    DLIB_ASSERT(dest_nr == lhs_nr &&\n                        dest_nc == rhs_nc &&\n                        lhs_nc == rhs_nr)\n                }\n\n                const int k = trans_rhs ? rhs_nc : rhs_nr;\n                CHECK_CUBLAS(cublasSgemm(context(),\n                    transb,\n                    transa,\n                    dest_nc, dest_nr, k,\n                    &alpha,\n                    rhs.device(), rhs_nc,\n                    lhs.device(), lhs_nc,\n                    &beta,\n                    dest.device(), dest_nc));\n            }\n            else if (mode == operation_mode::PLANE_WISE)\n            {\n                const auto transa = trans_lhs ? CUBLAS_OP_T : CUBLAS_OP_N;\n                const auto transb = trans_rhs ? CUBLAS_OP_T : CUBLAS_OP_N;\n\n                long num_samples = std::min({ lhs.num_samples(), rhs.num_samples(), dest.num_samples() });\n                long num_channels = std::min({ lhs.k(), rhs.k(), dest.k() });\n\n                auto is_matrix = [](const auto& tensor) {\n                    return ((tensor.num_samples() * tensor.k() == 1 && tensor.nr() * tensor.nc() > 1) ||\n                        (tensor.num_samples() * tensor.k() > 1 && tensor.nr() * tensor.nc() == 1));\n                };\n                const bool lhs_is_matrix = is_matrix(lhs), rhs_is_matrix = is_matrix(rhs), dest_is_matrix = is_matrix(dest);\n\n                if (lhs_is_matrix && rhs_is_matrix && dest_is_matrix) num_samples = num_channels = 1;\n\n                size_t lhs_rows = lhs.nr();\n                size_t lhs_cols = lhs.nc();\n                if (lhs_is_matrix && (lhs.num_samples() > 1 || lhs.k() > 1)) {\n                    lhs_rows = lhs.num_samples();\n                    lhs_cols = lhs.k();\n                }\n                size_t rhs_rows = rhs.nr();\n                size_t rhs_cols = rhs.nc();\n                if (rhs_is_matrix && (rhs.num_samples() > 1 || rhs.k() > 1)) {\n                    rhs_rows = rhs.num_samples();\n                    rhs_cols = rhs.k();\n                }\n                size_t dest_rows = dest.nr();\n                size_t dest_cols = dest.nc();\n                if (dest_is_matrix && (dest.num_samples() > 1 || dest.k() > 1)) {\n                    dest_rows = dest.num_samples();\n                    dest_cols = dest.k();\n                }\n\n                const size_t lhs_plane_size = lhs_rows * lhs_cols;\n                const size_t rhs_plane_size = rhs_rows * rhs_cols;\n                const size_t dest_plane_size = dest_rows * dest_cols;\n\n                for (long b = 0; b < num_samples; ++b)\n                {\n                    for (long c = 0; c < num_channels; ++c)\n                    {\n                        auto lhs_slice = lhs_is_matrix ? lhs.device() :\n                            lhs.device() + (b * num_channels + c) * lhs_plane_size;\n                        auto rhs_slice = rhs_is_matrix ? rhs.device() :\n                            rhs.device() + (b * num_channels + c) * rhs_plane_size;\n                        auto dest_slice = dest_is_matrix ? dest.device() :\n                            dest.device() + (b * num_channels + c) * dest_plane_size;\n                        const int k = trans_rhs ? rhs_cols : rhs_rows;\n\n                        CHECK_CUBLAS(cublasSgemm(\n                            context(), transb, transa, dest_cols, dest_rows, k,\n                            &alpha, rhs_slice, rhs_cols, lhs_slice, lhs_cols,\n                            &beta, dest_slice, dest_cols\n                        ));\n                    }\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuBLAS_CPP_\n\n\n\n"
  },
  {
    "path": "dlib/cuda/cublas_dlibapi.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuBLAS_H_\n#define DLIB_DNN_CuBLAS_H_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"tensor.h\"\n#include \"cuda_errors.h\"\n\nnamespace dlib\n{    \n    namespace cuda \n    {        \n\n    // -----------------------------------------------------------------------------------\n\n        void gemm (\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& lhs,\n            bool trans_lhs,\n            const tensor& rhs,\n            bool trans_rhs,\n            operation_mode mode = operation_mode::CHANNEL_WISE\n        );\n    /*!\n        requires\n            - The dimensions of lhs and rhs must be compatible for matrix multiplication.\n                The specific requirements depend on the mode:\n\n                For CHANNEL_WISE mode (default):\n                    - Let L == trans_lhs ? trans(mat(lhs)) : mat(lhs)\n                    - Let R == trans_rhs ? trans(mat(rhs)) : mat(rhs)\n                    - Let D == mat(dest)\n                    - D.nr() == L.nr() && D.nc() == R.nc()\n                        (i.e. dest must be preallocated and have the correct output dimensions)\n                    - L.nc() == R.nr()\n\n                For PLANE_WISE mode:\n                    - lhs.num_samples() == rhs.num_samples() && lhs.k() == rhs.k()\n                    - If !trans_lhs && !trans_rhs:\n                        lhs.nc() == rhs.nr()\n                        dest.nr() == lhs.nr() && dest.nc() == rhs.nc()\n                    - If trans_lhs && !trans_rhs:\n                        lhs.nr() == rhs.nr()\n                        dest.nr() == lhs.nc() && dest.nc() == rhs.nc()\n                    - If !trans_lhs && trans_rhs:\n                        lhs.nc() == rhs.nc()\n                        dest.nr() == lhs.nr() && dest.nc() == rhs.nr()\n                    - If trans_lhs && trans_rhs:\n                        lhs.nr() == rhs.nc()\n                        dest.nr() == lhs.nc() && dest.nc() == rhs.nr()\n\n        ensures\n            - Performs matrix multiplication based on the specified mode:\n\n                For CHANNEL_WISE mode:\n                    - performs: dest = alpha*L*R + beta*mat(dest)\n                        where L, R, and D are as defined above.\n\n                For PLANE_WISE mode:\n                    - Performs matrix multiplication for each corresponding 2D plane (nr x nc)\n                        in lhs and rhs across all samples and channels.\n                    - The operation is equivalent to performing the following for each sample\n                        and channel:\n                        dest[s][k] = alpha * (lhs[s][k] * rhs[s][k]) + beta * dest[s][k]\n                        where [s][k] represents the 2D plane for sample s and channel k.\n    !*/\n\n    // ------------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuBLAS_H_\n\n\n"
  },
  {
    "path": "dlib/cuda/cuda_data_ptr.cpp",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuDA_DATA_PTR_CPP_\n#define DLIB_DNN_CuDA_DATA_PTR_CPP_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"cuda_data_ptr.h\"\n#include \"cuda_utils.h\"\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // ----------------------------------------------------------------------------------------\n\n        weak_cuda_data_void_ptr::\n        weak_cuda_data_void_ptr(\n            const cuda_data_void_ptr& ptr\n        ) : num(ptr.num), pdata(ptr.pdata)\n        {\n\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        cuda_data_void_ptr weak_cuda_data_void_ptr::\n        lock() const \n        {\n            auto ptr = pdata.lock();\n            if (ptr)\n            {\n                cuda_data_void_ptr temp;\n                temp.pdata = ptr;\n                temp.num = num;\n                return temp;\n            }\n            else\n            {\n                return cuda_data_void_ptr();\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n\n        cuda_data_void_ptr::\n        cuda_data_void_ptr(\n            size_t n\n        ) : num(n)\n        {\n            if (n == 0)\n                return;\n\n            void* data = nullptr;\n\n            CHECK_CUDA(cudaMalloc(&data, n));\n            pdata.reset(data, [](void* ptr){\n                auto err = cudaFree(ptr);\n                if(err!=cudaSuccess)\n                std::cerr << \"cudaFree() failed. Reason: \" << cudaGetErrorString(err) << std::endl;\n            });\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            void* dest,\n            const cuda_data_void_ptr& src,\n            const size_t num\n        )\n        {\n            DLIB_ASSERT(num <= src.size());\n            if (src.size() != 0)\n            {\n                CHECK_CUDA(cudaMemcpy(dest, src.data(),  num, cudaMemcpyDefault));\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            void* dest,\n            const cuda_data_void_ptr& src\n        )\n        {\n            memcpy(dest, src, src.size());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            cuda_data_void_ptr dest, \n            const void* src,\n            const size_t num\n        )\n        {\n            DLIB_ASSERT(num <= dest.size());\n            if (dest.size() != 0)\n            {\n                CHECK_CUDA(cudaMemcpy(dest.data(), src, num, cudaMemcpyDefault));\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            cuda_data_void_ptr dest, \n            const void* src\n        )\n        {\n            memcpy(dest,src,dest.size());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        class cudnn_device_buffer\n        {\n        public:\n            // not copyable\n            cudnn_device_buffer(const cudnn_device_buffer&) = delete;\n            cudnn_device_buffer& operator=(const cudnn_device_buffer&) = delete;\n\n            cudnn_device_buffer()\n            {\n                buffers.resize(16);\n            }\n            ~cudnn_device_buffer()\n            {\n            }\n\n            cuda_data_void_ptr get (\n                size_t size\n            )\n            {\n                int new_device_id;\n                CHECK_CUDA(cudaGetDevice(&new_device_id));\n                // make room for more devices if needed\n                if (new_device_id >= (long)buffers.size())\n                    buffers.resize(new_device_id+16);\n\n                // If we don't have a buffer already for this device then make one, or if it's too\n                // small, make a bigger one.\n                cuda_data_void_ptr buff = buffers[new_device_id].lock();\n                if (!buff || buff.size() < size)\n                {\n                    buff = cuda_data_void_ptr(size);\n                    buffers[new_device_id] = buff;\n                }\n\n                // Finally, return the buffer for the current device\n                return buff;\n            }\n\n        private:\n\n            std::vector<weak_cuda_data_void_ptr> buffers;\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        cuda_data_void_ptr device_global_buffer(size_t size) \n        {\n            thread_local cudnn_device_buffer buffer;\n            return buffer.get(size);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuDA_DATA_PTR_CPP_\n\n\n"
  },
  {
    "path": "dlib/cuda/cuda_data_ptr.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuDA_DATA_PTR_H_\n#define DLIB_DNN_CuDA_DATA_PTR_H_\n\n#include \"../assert.h\"\n\n#ifdef DLIB_USE_CUDA\n\n#include <memory>\n#include <vector>\n#include <type_traits>\n\nnamespace dlib\n{\n    namespace cuda\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        class cuda_data_void_ptr;\n        class weak_cuda_data_void_ptr \n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is just like a std::weak_ptr version of cuda_data_void_ptr.  It allows you\n                    to hold a non-owning reference to a cuda_data_void_ptr.\n            !*/\n        public:\n            weak_cuda_data_void_ptr() = default;\n\n            weak_cuda_data_void_ptr(const cuda_data_void_ptr& ptr);\n\n            void reset() { pdata.reset(); num = 0; }\n\n            cuda_data_void_ptr lock() const;\n            /*!\n                ensures\n                    - if (the memory block referenced by this object hasn't been deleted) then\n                        - returns a cuda_data_void_ptr referencing that memory block\n                    - else\n                        - returns a default initialized cuda_data_void_ptr (i.e. an empty one).\n            !*/\n\n        private:\n            size_t num = 0;\n            std::weak_ptr<void> pdata;\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        class cuda_data_void_ptr\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a block of memory on a CUDA device.  \n            !*/\n        public:\n\n            cuda_data_void_ptr() = default;\n\n            cuda_data_void_ptr(size_t n); \n            /*!\n                ensures\n                    - This object will allocate a device memory buffer of n bytes.\n                    - #size() == n\n            !*/\n\n            void* data() { return pdata.get(); }\n            const void* data() const { return pdata.get(); }\n            operator void*() { return pdata.get(); }\n            operator const void*() const { return pdata.get(); }\n\n            void reset() { pdata.reset(); }\n\n            size_t size() const { return num; }\n            /*!\n                ensures\n                    - returns the length of this buffer, in bytes.\n            !*/\n\n            cuda_data_void_ptr operator+ (size_t offset) const \n            /*!\n                requires\n                    - offset < size()\n                ensures\n                    - returns a pointer that is offset by the given amount.\n            !*/\n            { \n                DLIB_CASSERT(offset < num);\n                cuda_data_void_ptr temp;\n                temp.num = num-offset;\n                temp.pdata = std::shared_ptr<void>(pdata, ((char*)pdata.get())+offset);\n                return temp;\n            }\n\n            void shrink(size_t new_size) \n            /*!\n                requires\n                    - new_size <= num\n                ensures\n                    - #size() == new_size\n                    - Doesn't actually deallocate anything, just changes the size() metadata to a\n                      smaller number and only for this instance of the pointer.\n            !*/\n            {\n                DLIB_CASSERT(new_size <= num);\n                num = new_size;\n            }\n\n        private:\n\n            friend class weak_cuda_data_void_ptr;\n            size_t num = 0;\n            std::shared_ptr<void> pdata;\n        };\n\n        inline cuda_data_void_ptr operator+(size_t offset, const cuda_data_void_ptr& rhs) { return rhs+offset; }\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            void* dest,\n            const cuda_data_void_ptr& src\n        );\n        /*!\n            requires\n                - dest == a pointer to at least src.size() bytes on the host machine.\n            ensures\n                - copies the GPU data from src into dest.\n                - This routine is equivalent to performing: memcpy(dest,src,src.size())\n        !*/\n\n        void memcpy(\n            void* dest,\n            const cuda_data_void_ptr& src,\n            const size_t num\n        );\n        /*!\n            requires\n                - dest == a pointer to at least num bytes on the host machine.\n                - num <= src.size()\n            ensures\n                - copies the GPU data from src into dest.  Copies only the first num bytes\n                  of src to dest.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        void memcpy(\n            cuda_data_void_ptr dest, \n            const void* src\n        );\n        /*!\n            requires\n                - dest == a pointer to at least src.size() bytes on the host machine.\n            ensures\n                - copies the host data from src to the GPU memory buffer dest.\n                - This routine is equivalent to performing: memcpy(dest,src,dest.size())\n        !*/\n\n        void memcpy(\n            cuda_data_void_ptr dest, \n            const void* src,\n            const size_t num\n        );\n        /*!\n            requires\n                - dest == a pointer to at least num bytes on the host machine.\n                - num <= dest.size()\n            ensures\n                - copies the host data from src to the GPU memory buffer dest.  Copies only\n                  the first num bytes of src to dest.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        class cuda_data_ptr\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a block of memory on a CUDA device.   It is just a type safe\n                    version of cuda_data_void_ptr.\n            !*/\n\n        public:\n\n            static_assert(std::is_standard_layout<T>::value, \"You can only create basic standard layout types on the GPU\");\n\n            cuda_data_ptr() = default;\n            cuda_data_ptr(size_t n) : num(n)\n            /*!\n                ensures\n                    - This object will allocate a device memory buffer of n T objects.\n                    - #size() == n\n            !*/\n            {\n                if (n == 0)\n                    return;\n\n                pdata = cuda_data_void_ptr(n*sizeof(T));\n            }\n\n            cuda_data_ptr(\n                const cuda_data_ptr<typename std::remove_const<T>::type> &other\n            ) : num(other.num), pdata(other.pdata) {}\n            /*!\n                ensures\n                    - *this is a copy of other.  This version of the copy constructor allows\n                      assigning non-const pointers to const ones.  For instance, converting from\n                      cuda_data_ptr<float> to cuda_data_ptr<const float>.\n            !*/\n\n            T* data() { return (T*)pdata.data(); }\n            const T* data() const { return (T*)pdata.data(); }\n\n            operator T*() { return (T*)pdata.data(); }\n            operator const T*() const { return (T*)pdata.data(); }\n\n            void reset() { pdata.reset(); }\n\n            size_t size() const { return num; }\n            /*!\n                ensures\n                    - returns the number of T instances pointed to by *this.\n            !*/\n\n            operator cuda_data_void_ptr() const \n            /*!\n                ensures\n                    - returns *this as a cuda_data_void_ptr.  Importantly, the returned size() will\n                      reflect the number of bytes referenced by *this.  To be clear, let P be the\n                      returned pointer.  Then:\n                        - P.get() == get()\n                        - P.size() == size() * sizeof(T)\n            !*/\n            { \n                cuda_data_void_ptr temp = pdata;\n                temp.shrink(size() * sizeof(T));\n                return temp;\n            }\n\n        private:\n            template <typename U>\n            friend cuda_data_ptr<U> static_pointer_cast(const cuda_data_void_ptr &ptr);\n            template <typename U>\n            friend cuda_data_ptr<U> static_pointer_cast(const cuda_data_void_ptr &ptr, size_t num);\n            template <typename U>\n            friend class cuda_data_ptr;\n\n            size_t num = 0;\n            cuda_data_void_ptr pdata;\n        };\n\n        template <typename T>\n        cuda_data_ptr<T> static_pointer_cast(const cuda_data_void_ptr &ptr) \n        {\n            DLIB_CASSERT(ptr.size() % sizeof(T) == 0, \n                \"Size of memory buffer in ptr doesn't match sizeof(T). \"\n                << \"\\nptr.size(): \"<< ptr.size() \n                << \"\\nsizeof(T): \"<< sizeof(T));\n            cuda_data_ptr<T> result;\n            result.pdata = ptr;\n            result.num = ptr.size() / sizeof(T);\n            return result;\n        }\n\n        template <typename T>\n        cuda_data_ptr<T> static_pointer_cast(const cuda_data_void_ptr &ptr, size_t num) \n        {\n            DLIB_CASSERT(num*sizeof(T) <= ptr.size(), \n                \"Size of memory buffer in ptr isn't big enough to represent this many T objects. \"\n                << \"\\nnum: \"<< num \n                << \"\\nnum*sizeof(T): \"<< num*sizeof(T)\n                << \"\\nsizeof(T): \"<< sizeof(T)\n                << \"\\nptr.size(): \"<< ptr.size());\n\n            cuda_data_ptr<T> result;\n            result.pdata = ptr;\n            result.num = num;\n            return result;\n        }\n\n        template <typename T>\n        void memcpy(std::vector<T>& dest, const cuda_data_ptr<T>& src)\n        {\n            dest.resize(src.size());\n            if (src.size() != 0)\n                memcpy(dest.data(), static_cast<cuda_data_void_ptr>(src));\n        }\n\n        template <typename T>\n        void memcpy(cuda_data_ptr<T>& dest, const std::vector<T>& src)\n        {\n            if (src.size() != dest.size())\n                dest = cuda_data_ptr<T>(src.size());\n\n            if (dest.size() != 0)\n                memcpy(static_cast<cuda_data_void_ptr>(dest), src.data());\n        }\n\n        template <typename T>\n        void memcpy(cuda_data_ptr<T>& dest, const T* src)\n        {\n            memcpy(static_cast<cuda_data_void_ptr>(dest), src);\n        }\n        template <typename T>\n        void memcpy(cuda_data_ptr<T>& dest, const T* src, size_t num)\n        {\n            DLIB_CASSERT(num <= dest.size());\n            memcpy(static_cast<cuda_data_void_ptr>(dest), src, num*sizeof(T));\n        }\n\n        template <typename T>\n        void memcpy(T* dest, const cuda_data_ptr<T>& src)\n        {\n            memcpy(dest, static_cast<cuda_data_void_ptr>(src));\n        }\n        template <typename T>\n        void memcpy(T* dest, const cuda_data_ptr<T>& src, size_t num)\n        {\n            DLIB_CASSERT(num <= src.size());\n            memcpy(dest, static_cast<cuda_data_void_ptr>(src), num*sizeof(T));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        cuda_data_void_ptr device_global_buffer(size_t size);\n        /*!\n            ensures\n                - Returns a pointer to a globally shared CUDA memory buffer on the\n                  currently selected CUDA device.  The buffer is also thread local.  So\n                  each host thread will get its own buffer.  You can use this global buffer\n                  as scratch space for CUDA computations that all take place on the default\n                  stream.  Using it in this way ensures that there aren't any race conditions\n                  involving the use of the buffer.\n                - The returned pointer will point to at least size bytes.  It may point to more.\n                - The global buffer is deallocated once all references to it are destructed.\n                  However, if device_global_buffer() is called before then with a size <= the last\n                  size requested, then the previously returned global buffer pointer is returned.\n                  This avoids triggering expensive CUDA reallocations.  So if you want to avoid\n                  these reallocations then hold a copy of the pointer returned by this function.\n                  However, as a general rule, client code should not hold the returned\n                  cuda_data_void_ptr for long durations, but instead should call\n                  device_global_buffer() whenever the buffer is needed, and overwrite the previously\n                  returned pointer with the new pointer.  Doing so ensures multiple buffers are not\n                  kept around in the event that multiple sized buffers are requested.  To explain\n                  this, consider this code, assumed to execute at program startup:\n                    auto ptr1 = device_global_buffer(1);\n                    auto ptr2 = device_global_buffer(2);\n                    auto ptr3 = device_global_buffer(3);\n                  since the sizes increased at each call 3 separate buffers were allocated.  First\n                  one of size 1, then of size 2, then of size 3.  If we then executed:\n                    ptr1 = device_global_buffer(1);\n                    ptr2 = device_global_buffer(2);\n                    ptr3 = device_global_buffer(3);\n                  all three of these pointers would now point to the same buffer, since the smaller\n                  requests can be satisfied by returning the size 3 buffer in each case.\n        !*/\n\n    // ----------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuDA_DATA_PTR_H_\n\n"
  },
  {
    "path": "dlib/cuda/cuda_dlib.cu",
    "content": "﻿// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#include \"cuda_utils.h\"\n#include \"cuda_dlib.h\"\n#include \"cudnn_dlibapi.h\"\n#include <math_constants.h>\n\n\nnamespace dlib \n{ \n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        void set_device (\n            int dev\n        )\n        {\n            CHECK_CUDA(cudaSetDevice(dev));\n        }\n\n        int get_device (\n        )\n        {\n            int dev = 0;\n            CHECK_CUDA(cudaGetDevice(&dev));\n            return dev;\n        }\n\n        std::string get_device_name (\n            int device\n        )\n        {\n            cudaDeviceProp props;\n            CHECK_CUDA(cudaGetDeviceProperties(&props, device));\n            return props.name;\n        }\n\n        void set_current_device_blocking_sync(\n        )\n        {\n            CHECK_CUDA(cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync));\n        }\n\n        int get_num_devices (\n        )\n        {\n            int num_devices;\n            CHECK_CUDA(cudaGetDeviceCount(&num_devices));\n            return num_devices;\n        }\n\n        bool can_access_peer (int device_id, int peer_device_id)\n        {\n            int can_access;\n            CHECK_CUDA(cudaDeviceCanAccessPeer(&can_access, device_id, peer_device_id));\n            return can_access != 0;\n        }\n        bool can_access_peer (const tensor& device, const tensor& peer_device)\n        {\n            return can_access_peer(device.device_id(), peer_device.device_id());\n        }\n\n        void device_synchronize (int dev) \n        { \n            raii_set_device set_dev(dev);\n            CHECK_CUDA(cudaDeviceSynchronize());\n        }\n        void device_synchronize (const tensor& dev) { device_synchronize(dev.device_id()); }\n\n        enable_peer_access::\n        enable_peer_access(\n            int device_id,\n            int peer_device_id\n        ) : call_disable(false), device_id(device_id), peer_device_id(peer_device_id)\n        {\n            raii_set_device set_dev(device_id);\n\n            auto err = cudaDeviceEnablePeerAccess(peer_device_id, 0);\n            if (err == cudaSuccess)\n            {\n                call_disable = true;\n            }\n            else if (err == cudaErrorPeerAccessAlreadyEnabled)\n            {\n                // call cudaGetLastError() to dispose of this error since we don't\n                // care.\n                auto err2 = cudaGetLastError();\n                if (err2 != cudaErrorPeerAccessAlreadyEnabled)\n                    CHECK_CUDA(err2);\n            }\n            else\n            {\n                CHECK_CUDA(err);\n            }\n        }\n\n\n        enable_peer_access::\n        ~enable_peer_access() noexcept(false)\n        {\n            if (call_disable)\n            {\n                raii_set_device set_dev(device_id);\n                CHECK_CUDA(cudaDeviceDisablePeerAccess(peer_device_id));\n            }\n        }\n\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _cuda_inverse_norms(float* invnorms, const float* data, size_t nr, size_t nc, const float eps)\n        {\n            // initialize invnorms before we begin.\n            for (auto i : grid_stride_range_y(0, nr))\n                for (auto j : grid_stride_range(0, 1))\n                    invnorms[i] = eps;\n            __syncthreads();\n\n            for (auto i : grid_stride_range_y(0, nr))\n            {\n                auto p = data + i*nc;\n                float temp = 0;\n                for (auto j : grid_stride_range(0, nc))\n                    temp += p[j]*p[j];\n\n                // and store the sum into invnorms[i]\n                warp_reduce_atomic_add(invnorms[i], temp);\n            }\n            __syncthreads();\n\n            for (auto i : grid_stride_range_y(0, nr))\n                for (auto j : grid_stride_range(0, 1))\n                    invnorms[i] = 1.0/std::sqrt(invnorms[i]);\n        }\n\n        void inverse_norms (\n            resizable_tensor& invnorms,\n            const tensor& data,\n            const double eps\n        )\n        {\n            invnorms.set_size(data.num_samples());\n            launch_kernel(_cuda_inverse_norms, max_jobs(data.size()/data.num_samples(), data.num_samples()),\n                invnorms.device(), data.device(), data.num_samples(), data.size()/data.num_samples(), eps);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_dot_prods(float* out, const float* lhs, const float* rhs, size_t nr, size_t nc)\n        {\n            // initialize out before we begin.\n            for (auto i : grid_stride_range_y(0, nr))\n                for (auto j : grid_stride_range(0, 1))\n                    out[i] = 0;\n            __syncthreads();\n\n            for (auto i : grid_stride_range_y(0, nr))\n            {\n                auto l = lhs + i*nc;\n                auto r = rhs + i*nc;\n                float temp = 0;\n                for (auto j : grid_stride_range(0, nc))\n                    temp += l[j]*r[j];\n\n                // and store the sum into out[i]\n                warp_reduce_atomic_add(out[i], temp);\n            }\n        }\n\n        __global__ void _cuda_dot_prods_add_to(float* out, const float* lhs, const float* rhs, size_t nr, size_t nc)\n        {\n            for (auto i : grid_stride_range_y(0, nr))\n            {\n                auto l = lhs + i*nc;\n                auto r = rhs + i*nc;\n                float temp = 0;\n                for (auto j : grid_stride_range(0, nc))\n                    temp += l[j]*r[j];\n\n                // and store the sum into out[i]\n                warp_reduce_atomic_add(out[i], temp);\n            }\n        }\n\n        void dot_prods (\n            resizable_tensor& out,\n            const tensor& lhs,\n            const tensor& rhs\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(lhs,rhs));\n\n            out.set_size(lhs.num_samples());\n            if (out.size() == 0)\n                return;\n\n            const auto nr = lhs.num_samples();\n            const auto nc = lhs.size()/lhs.num_samples();\n\n            launch_kernel(_cuda_dot_prods, max_jobs(nc,nr), out.device_write_only(), lhs.device(), rhs.device(), nr, nc);\n        }\n\n        void dot_prods (\n            bool add_to,\n            tensor& out,\n            const tensor& lhs,\n            const tensor& rhs\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(lhs,rhs));\n            DLIB_CASSERT(out.k() == 1 && out.nr() == 1 && out.nc() == 1);\n            DLIB_CASSERT(out.size() == lhs.num_samples());\n\n            const auto nr = lhs.num_samples();\n            const auto nc = lhs.size()/lhs.num_samples();\n\n            if (add_to)\n                launch_kernel(_cuda_dot_prods_add_to, max_jobs(nc,nr), out.device(), lhs.device(), rhs.device(), nr, nc);\n            else\n                launch_kernel(_cuda_dot_prods, max_jobs(nc,nr), out.device_write_only(), lhs.device(), rhs.device(), nr, nc);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_scale_columns(float* out, const float* m, const float* v, size_t nr, size_t nc)\n        {\n            for (auto j : grid_stride_range(0, nr*nc))\n            {\n                out[j] = m[j]*v[j%nc];\n            }\n        }\n\n        void scale_columns (\n            tensor& out,\n            const tensor& m,\n            const tensor& v\n        )\n        {\n            launch_kernel(_cuda_scale_columns, max_jobs(m.size()), out.device(), m.device(), v.device(), m.num_samples(), m.size()/m.num_samples());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_scale_rows(float* out, const float* m, const float* v, size_t nr, size_t nc)\n        {\n            for (auto j : grid_stride_range(0, nr*nc))\n            {\n                out[j] = m[j]*v[j/nc];\n            }\n        }\n\n        void scale_rows (\n            tensor& out,\n            const tensor& m,\n            const tensor& v\n        )\n        {\n            launch_kernel(_cuda_scale_rows, max_jobs(m.size()), out.device(), m.device(), v.device(), m.num_samples(), m.size()/m.num_samples());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_scale_rows2(float* out, const float* m1, const float* m2, const float* v1, const float* v2, size_t nr, size_t nc)\n        {\n            for (auto j : grid_stride_range(0, nr*nc))\n            {\n                out[j] = (m1[j] - m2[j]*v1[j/nc]) * v2[j/nc];\n            }\n        }\n\n        __global__ void _cuda_scale_rows2_beta(const float beta, float* out, const float* m1, const float* m2, const float* v1, const float* v2, size_t nr, size_t nc)\n        {\n            for (auto j : grid_stride_range(0, nr*nc))\n            {\n                out[j] = beta*out[j] + (m1[j] - m2[j]*v1[j/nc]) * v2[j/nc];\n            }\n        }\n\n        void scale_rows2 (\n            float beta, \n            tensor& out,\n            const tensor& m1,\n            const tensor& m2,\n            const tensor& v1,\n            const tensor& v2\n        )\n        {\n            if (beta == 0)\n            {\n                launch_kernel(_cuda_scale_rows2, max_jobs(m1.size()), out.device(),\n                    m1.device(), m2.device(), v1.device(), v2.device(), m1.num_samples(),\n                    m1.size()/m1.num_samples());\n            }\n            else\n            {\n                launch_kernel(_cuda_scale_rows2_beta, max_jobs(m1.size()), beta,\n                    out.device(), m1.device(), m2.device(), v1.device(), v2.device(),\n                    m1.num_samples(), m1.size()/m1.num_samples());\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_exp(float* dest, const float* src, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                dest[i] = ::exp(src[i]);\n        }\n\n        void exp (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_ASSERT(dest.size() == src.size());\n            launch_kernel(_cuda_exp, max_jobs(src.size()), dest.device(), src.device(), src.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_log(float* dest, const float* src, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                dest[i] = ::log(src[i]);\n        }\n\n        void log (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_ASSERT(dest.size() == src.size());\n            launch_kernel(_cuda_log, max_jobs(src.size()), dest.device(), src.device(), src.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_log10(float* dest, const float* src, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                dest[i] = ::log10(src[i]);\n        }\n\n        void log10 (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_ASSERT(dest.size() == src.size());\n            launch_kernel(_cuda_log10, max_jobs(src.size()), dest.device(), src.device(), src.size());\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _cuda_multiply1(float* d, const float* s1, const float* s2, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s1[i]*s2[i];\n            }\n        }\n        __global__ void _cuda_multiply2(float* d, const float* s1, const float* s2, \n                                       size_t n, size_t s1_n, size_t s2_n, size_t max_size)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = 0;\n                for (size_t j = i; j < max_size; j += n)\n                    d[i] += s1[j%s1_n]*s2[j%s2_n];\n            }\n        }\n\n        __global__ void _cuda_multiply3(float* d, const float* s1, const float* s2, \n                                       size_t n, size_t s1_n, size_t s2_n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s1[i%s1_n]*s2[i%s2_n];\n            }\n        }\n\n        __global__ void _cuda_multiply1_add_to(float* d, const float* s1, const float* s2, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] += s1[i]*s2[i];\n            }\n        }\n        __global__ void _cuda_multiply2_add_to(float* d, const float* s1, const float* s2, \n                                       size_t n, size_t s1_n, size_t s2_n, size_t max_size)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                for (size_t j = i; j < max_size; j += n)\n                    d[i] += s1[j%s1_n]*s2[j%s2_n];\n            }\n        }\n\n        __global__ void _cuda_multiply3_add_to(float* d, const float* s1, const float* s2, \n                                       size_t n, size_t s1_n, size_t s2_n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] += s1[i%s1_n]*s2[i%s2_n];\n            }\n        }\n\n        void multiply (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n\n            DLIB_CASSERT(dest.k() == src1.k() && src1.k() == src2.k() &&\n                dest.nr() == src1.nr() && src1.nr() == src2.nr() &&\n                dest.nc() == src1.nc() && src1.nc() == src2.nc() );\n            const long MD = std::max(std::max(dest.num_samples(),src1.num_samples()),src2.num_samples());\n            DLIB_CASSERT((dest.num_samples()==1 || dest.num_samples()==MD) &&\n                (src1.num_samples()==1 || src1.num_samples()==MD) &&\n                (src2.num_samples()==1 || src2.num_samples()==MD) );\n\n            if (dest.size() == 0)\n                return;\n\n            const size_t max_size = std::max(std::max(dest.size(),src1.size()),src2.size());\n            const auto d = dest.host();\n            const auto s1 = src1.host();\n            const auto s2 = src2.host();\n            if (dest.size() == src1.size() && src1.size() == src2.size())\n            {\n                if (add_to)\n                    launch_kernel(_cuda_multiply1_add_to,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), src1.size());\n                else\n                    launch_kernel(_cuda_multiply1,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), src1.size());\n            }\n            else if (dest.num_samples() == 1)\n            {\n                if (add_to)\n                    launch_kernel(_cuda_multiply2_add_to,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), \n                                                dest.size(), src1.size(), src2.size(), max_size);\n                else\n                    launch_kernel(_cuda_multiply2,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), \n                                                dest.size(), src1.size(), src2.size(), max_size);\n            }\n            else\n            {\n                if (add_to)\n                    launch_kernel(_cuda_multiply3_add_to,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), \n                                                dest.size(), src1.size(), src2.size());\n                else\n                    launch_kernel(_cuda_multiply3,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), \n                                                dest.size(), src1.size(), src2.size());\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_multiply_conv(float* d, const float* s1, size_t n, const float* s2, size_t bs, size_t ks)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                auto k = (i/bs)%ks;\n                d[i] = s1[i]*s2[k];\n            }\n        }\n\n        __global__ void _cuda_multiply_conv2(float* d, const float* s1, size_t n, const float* s2, size_t bs, size_t ks)\n        {\n            // zero initialize d before we begin.\n            for (auto i : grid_stride_range_y(0, ks))\n                for (auto j : grid_stride_range(0, 1))\n                    d[i] = 0;\n            __syncthreads();\n\n            // loop over all the image planes\n            for (auto i : grid_stride_range_y(0, n))\n            {\n                // sum all the elements in the i-th image plane\n                float temp = 0;\n                for (auto j : grid_stride_range(i*bs, (i+1)*bs))\n                    temp += s1[j]*s2[j];\n                auto k = i%ks;\n                // and store the sum into d[k]\n                warp_reduce_atomic_add(d[k], temp);\n            }\n        }\n\n        __global__ void _cuda_multiply_conv_add_to(float* d, const float* s1, size_t n, const float* s2, size_t bs, size_t ks)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                auto k = (i/bs)%ks;\n                d[i] += s1[i]*s2[k];\n            }\n        }\n\n        __global__ void _cuda_multiply_conv2_add_to(float* d, const float* s1, size_t n, const float* s2, size_t bs, size_t ks)\n        {\n            // loop over all the image planes\n            for (auto i : grid_stride_range_y(0, n))\n            {\n                // sum all the elements in the i-th image plane\n                float temp = 0;\n                for (auto j : grid_stride_range(i*bs, (i+1)*bs))\n                    temp += s1[j]*s2[j];\n                auto k = i%ks;\n                // and store the sum into d[k]\n                warp_reduce_atomic_add(d[k], temp);\n            }\n        }\n\n\n        void multiply_conv (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            if (have_same_dimensions(dest,src1))\n            {\n                DLIB_CASSERT(src2.num_samples() == 1 && src2.nr() == 1 && src2.nc() == 1 && src2.k() == src1.k());\n                if (dest.size() == 0)\n                    return;\n\n                if (add_to)\n                    launch_kernel(_cuda_multiply_conv_add_to,max_jobs(dest.size()),\n                        dest.device(), src1.device(), src1.size(), src2.device(), src1.nr()*src1.nc(), src1.k());\n                else\n                    launch_kernel(_cuda_multiply_conv,max_jobs(dest.size()),\n                        dest.device(), src1.device(), src1.size(), src2.device(), src1.nr()*src1.nc(), src1.k());\n            }\n            else\n            {\n                DLIB_CASSERT(have_same_dimensions(src1,src2));\n                DLIB_CASSERT(dest.num_samples() == 1 && dest.nr() == 1 && dest.nc() == 1 && dest.k() == src1.k());\n                if (dest.size() == 0)\n                    return;\n\n\n                const auto bs = src1.nr()*src1.nc();\n                const auto n = src1.num_samples()*src1.k();\n                if (add_to)\n                    launch_kernel(_cuda_multiply_conv2_add_to, max_jobs(bs,n),\n                        dest.device(), src1.device(), n, src2.device(), bs, src1.k());\n                else\n                    launch_kernel(_cuda_multiply_conv2, max_jobs(bs,n),\n                        dest.device(), src1.device(), n, src2.device(), bs, src1.k());\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_scale_channels_add_to(float* d, const float* src, size_t n, const float* scales, size_t bs)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                auto k = i/bs;\n                d[i] += src[i]*scales[k];\n            }\n        }\n\n        __global__ void _cuda_scale_channels(float* d, const float* src, size_t n, const float* scales, size_t bs)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                auto k = i/bs;\n                d[i] = src[i]*scales[k];\n            }\n        }\n\n        void scale_channels (\n            bool add_to,\n            tensor& dest,\n            const tensor& src,\n            const tensor& scales\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src) && \n                         scales.num_samples() == src.num_samples() &&\n                         scales.k()           == src.k() &&\n                         scales.nr()          == 1 &&\n                         scales.nc()          == 1 );\n\n            if (dest.size() == 0)\n                return;\n\n            if (add_to)\n                launch_kernel(_cuda_scale_channels_add_to,max_jobs(dest.size()),\n                    dest.device(), src.device(), src.size(), scales.device(), src.nr()*src.nc());\n            else\n                launch_kernel(_cuda_scale_channels,max_jobs(dest.size()),\n                    dest.device_write_only(), src.device(), src.size(), scales.device(), src.nr()*src.nc());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_mult1(float* d, const float* s1, const float* s2, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s1[i]*s2[i];\n            }\n        }\n\n        __global__ void _cuda_mult1_add_to(float* d, const float* s1, const float* s2, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] += s1[i]*s2[i];\n            }\n        }\n\n        __global__ void _cuda_mult2(float* d, const float* s1, const float* s2, \n                                   size_t dn, size_t dk, size_t dr, size_t dc,\n                                   size_t s1n, size_t s1k, size_t s1r, size_t s1c,\n                                   size_t s2n, size_t s2k, size_t s2r, size_t s2c)\n        {\n            for (auto i : grid_stride_range(0, dn*dk*dr*dc))\n            {\n                size_t n,k,r,c;\n                unpack_idx(i, dk,dr,dc, n,k,r,c);\n\n                float v1 = 0;\n                float v2 = 0;\n\n                if (n < s1n &&\n                    k < s1k &&\n                    r < s1r &&\n                    c < s1c )\n                {\n                    v1 = s1[pack_idx(s1k,s1r,s1c, n,k,r,c)];\n                }\n\n                if (n < s2n &&\n                    k < s2k &&\n                    r < s2r &&\n                    c < s2c )\n                {\n                    v2 = s2[pack_idx(s2k,s2r,s2c, n,k,r,c)];\n                }\n\n                d[i] = v1*v2;\n            }\n        }\n\n        __global__ void _cuda_mult2_add_to(float* d, const float* s1, const float* s2, \n                                   size_t dn, size_t dk, size_t dr, size_t dc,\n                                   size_t s1n, size_t s1k, size_t s1r, size_t s1c,\n                                   size_t s2n, size_t s2k, size_t s2r, size_t s2c)\n        {\n            for (auto i : grid_stride_range(0, dn*dk*dr*dc))\n            {\n                size_t n,k,r,c;\n                unpack_idx(i, dk,dr,dc, n,k,r,c);\n\n                float v1 = 0;\n                float v2 = 0;\n\n                if (n < s1n &&\n                    k < s1k &&\n                    r < s1r &&\n                    c < s1c )\n                {\n                    v1 = s1[pack_idx(s1k,s1r,s1c, n,k,r,c)];\n                }\n\n                if (n < s2n &&\n                    k < s2k &&\n                    r < s2r &&\n                    c < s2c )\n                {\n                    v2 = s2[pack_idx(s2k,s2r,s2c, n,k,r,c)];\n                }\n\n                d[i] += v1*v2;\n            }\n        }\n\n        void multiply_zero_padded (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            if (dest.size() == 0)\n                return;\n\n            // Do the simple and fast version if everything has the same dimensions\n            if (have_same_dimensions(dest, src1) &&\n                have_same_dimensions(dest, src2))\n            {\n                if (add_to)\n                    launch_kernel(_cuda_mult1_add_to,max_jobs(dest.size()), dest.device(), src1.device(), src2.device(), dest.size());\n                else\n                    launch_kernel(_cuda_mult1,max_jobs(dest.size()), dest.device(), src1.device(), src2.device(), dest.size());\n            }\n            else\n            {\n                if (add_to)\n                {\n                    // Otherwise, do the more complex version with bounds checking.\n                    launch_kernel(_cuda_mult2_add_to,max_jobs(dest.size()),\n                                dest.device(), src1.device(), src2.device(), \n                                dest.num_samples(), dest.k(), dest.nr(), dest.nc(),\n                                src1.num_samples(), src1.k(), src1.nr(), src1.nc(),\n                                src2.num_samples(), src2.k(), src2.nr(), src2.nc()\n                                );\n                }\n                else\n                {\n                    // Otherwise, do the more complex version with bounds checking.\n                    launch_kernel(_cuda_mult2,max_jobs(dest.size()),\n                                dest.device(), src1.device(), src2.device(), \n                                dest.num_samples(), dest.k(), dest.nr(), dest.nc(),\n                                src1.num_samples(), src1.k(), src1.nr(), src1.nc(),\n                                src2.num_samples(), src2.k(), src2.nr(), src2.nc()\n                                );\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_add1(float* d, const float* s1, const float* s2, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s1[i]+s2[i];\n            }\n        }\n\n        __global__ void _cuda_add2(float* d, const float* s1, const float* s2, \n                                   size_t dn, size_t dk, size_t dr, size_t dc,\n                                   size_t s1n, size_t s1k, size_t s1r, size_t s1c,\n                                   size_t s2n, size_t s2k, size_t s2r, size_t s2c)\n        {\n            for (auto i : grid_stride_range(0, dn*dk*dr*dc))\n            {\n                size_t n,k,r,c;\n                unpack_idx(i, dk,dr,dc, n,k,r,c);\n\n                float v1 = 0;\n                float v2 = 0;\n\n                if (n < s1n &&\n                    k < s1k &&\n                    r < s1r &&\n                    c < s1c )\n                {\n                    v1 = s1[pack_idx(s1k,s1r,s1c, n,k,r,c)];\n                }\n\n                if (n < s2n &&\n                    k < s2k &&\n                    r < s2r &&\n                    c < s2c )\n                {\n                    v2 = s2[pack_idx(s2k,s2r,s2c, n,k,r,c)];\n                }\n\n                d[i] = v1+v2;\n            }\n        }\n\n        void add (\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        )\n        {\n            if (dest.size() == 0)\n                return;\n\n            // Do the simple and fast version if everything has the same dimensions\n            if (have_same_dimensions(dest, src1) &&\n                have_same_dimensions(dest, src2))\n            {\n                launch_kernel(_cuda_add1,max_jobs(dest.size()), dest.device(), src1.device(), src2.device(), dest.size());\n            }\n            else\n            {\n                // Otherwise, do the more complex version with bounds checking.\n                launch_kernel(_cuda_add2,max_jobs(dest.size()),\n                            dest.device(), src1.device(), src2.device(), \n                            dest.num_samples(), dest.k(), dest.nr(), dest.nc(),\n                            src1.num_samples(), src1.k(), src1.nr(), src1.nc(),\n                            src2.num_samples(), src2.k(), src2.nr(), src2.nc()\n                            );\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform1(float* d, const float* s, size_t n, float A, float B)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A*s[i] + B;\n            }\n        }\n\n        __global__ void _cuda_affine_transform1_0(float* d, const float* s, size_t n, float A)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A*s[i];\n            }\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A,\n            const float B\n        )\n        {\n            DLIB_CASSERT(dest.size()==src.size());\n            if (B != 0)\n                launch_kernel(_cuda_affine_transform1,max_jobs(dest.size()),dest.device(), src.device(), src.size(), A, B);\n            else\n                launch_kernel(_cuda_affine_transform1_0,max_jobs(dest.size()),dest.device(), src.device(), src.size(), A);\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A\n        )\n        {\n            DLIB_CASSERT(dest.size()==src.size());\n            launch_kernel(_cuda_affine_transform1_0,max_jobs(dest.size()),dest.device(), src.device(), src.size(), A);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform_rect(\n            float* d, \n            const float* s1, \n            const float* s2, \n            const float* s3, \n            float A, \n            float B,\n            float C,\n            size_t start_idx,\n            size_t n, \n            size_t rect_nc,\n            size_t total_nc\n        )\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                size_t r = i/rect_nc;\n                size_t c = i%rect_nc;\n                size_t idx = r*total_nc + c + start_idx;\n                d[idx] = A*s1[idx] + B*s2[idx] + C*s3[idx];\n            }\n        }\n\n        void affine_transform(\n            const rectangle& rect,\n            tensor& dest, \n            const tensor& src1, \n            const tensor& src2, \n            const tensor& src3, \n            float A, \n            float B,\n            float C\n        )\n        {\n            DLIB_CASSERT(dest.size() == src1.size());\n            DLIB_CASSERT(dest.size() == src2.size());\n            DLIB_CASSERT(dest.size() == src3.size());\n            DLIB_CASSERT(dest.num_samples() == src1.num_samples());\n            DLIB_CASSERT(dest.num_samples() == src2.num_samples());\n            DLIB_CASSERT(dest.num_samples() == src3.num_samples());\n            DLIB_CASSERT(rectangle(0,0, dest.size()/dest.num_samples()-1, dest.num_samples()-1).contains(rect));\n            launch_kernel(_cuda_affine_transform_rect,max_jobs(rect.area()),\n                dest.device(), src1.device(), src2.device(), src3.device(), A, B, C,\n                rect.left() + rect.top()*(dest.size()/dest.num_samples()),\n                rect.area(),\n                rect.width(),\n                dest.size()/dest.num_samples());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform4(float* d, const float* s1, const float* s2, size_t n, float A, float B, float C)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A*s1[i] + B*s2[i] + C;\n            }\n        }\n\n        __global__ void _cuda_affine_transform4_0(float* d, const float* s1, const float* s2, size_t n, float A, float B)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A*s1[i] + B*s2[i];\n            }\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B,\n            const float C\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            if (C != 0)\n                launch_kernel(_cuda_affine_transform4,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), dest.size(), A, B, C);\n            else\n                launch_kernel(_cuda_affine_transform4_0,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), dest.size(), A, B);\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            launch_kernel(_cuda_affine_transform4_0,max_jobs(dest.size()),dest.device(), src1.device(), src2.device(), dest.size(), A, B);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_add_scaled(float* d, const float* s, size_t n, float scale)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] += scale*s[i]; \n            }\n        }\n\n        void add_scaled(\n            tensor& dest,\n            const float scale,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(dest.size()==src.size());\n            launch_kernel(_cuda_add_scaled,max_jobs(dest.size()),dest.device(), src.device(), dest.size(), scale);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_add_cv_to_all_columns(float beta, float* dest, float alpha, const float* src, size_t size, size_t stride)\n        {\n            for (auto i : grid_stride_range(0, size))\n            {\n                dest[i] = beta*dest[i] + alpha*src[i/stride];\n            }\n        }\n\n        __global__ void _cuda_add_cv_to_all_columns_no_beta(float* dest, float alpha, const float* src, size_t size, size_t stride)\n        {\n            for (auto i : grid_stride_range(0, size))\n            {\n                dest[i] = alpha*src[i/stride];\n            }\n        }\n\n        void add_cv_to_all_columns(\n            float beta, \n            tensor& dest, \n            float alpha, \n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(dest.num_samples() == src.num_samples() && src.num_samples() == src.size());\n            if (beta == 0)\n                launch_kernel(_cuda_add_cv_to_all_columns_no_beta, max_jobs(dest.size()), dest.device(), alpha, src.device(), dest.size(), dest.size()/dest.num_samples());\n            else\n                launch_kernel(_cuda_add_cv_to_all_columns, max_jobs(dest.size()), beta, dest.device(), alpha, src.device(), dest.size(), dest.size()/dest.num_samples());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform5(\n            float* d, const float* s1, const float* s2, const float* s3, size_t n, float A, float B, float C, float D\n        )\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A*s1[i] + B*s2[i] + C*s3[i] + D;\n            }\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C,\n            const float D\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            DLIB_CASSERT(dest.size()==src3.size());\n            launch_kernel(_cuda_affine_transform5,max_jobs(dest.size()),dest.device(), src1.device(),\n                src2.device(), src3.device(), dest.size(), A, B, C, D);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform_range(\n            float* d, const float* s1, const float* s2, const float* s3, size_t begin, size_t end, float A, float B, float C\n        )\n        {\n            for (auto i : grid_stride_range(begin, end))\n            {\n                d[i] = A*s1[i] + B*s2[i] + C*s3[i];\n            }\n        }\n\n\n        void affine_transform_range(\n            size_t begin,\n            size_t end,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C\n        )\n        {\n            DLIB_CASSERT(dest.size()==src1.size());\n            DLIB_CASSERT(dest.size()==src2.size());\n            DLIB_CASSERT(dest.size()==src3.size());\n            DLIB_CASSERT(begin <= end && end <= dest.size());\n            launch_kernel(_cuda_affine_transform_range,max_jobs(end-begin),\n                dest.device(), src1.device(),\n                src2.device(), src3.device(), begin, end, A, B, C);\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform2(float* d, const float* s, size_t n, const float* A, const float* B)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A[i]*s[i] + B[i];\n            }\n        }\n        __global__ void _cuda_affine_transform3(float* d, const float* s, size_t n, const float* A, const float* B, size_t bs)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = A[i%bs]*s[i] + B[i%bs];\n            }\n        }\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest, src));\n            DLIB_CASSERT(\n                  ((A.num_samples()==1 && B.num_samples()==1) ||\n                  (A.num_samples()==src.num_samples() && B.num_samples()==src.num_samples())));\n            DLIB_CASSERT(\n                  A.nr()==B.nr() && B.nr()==src.nr() &&\n                  A.nc()==B.nc() && B.nc()==src.nc() &&\n                  A.k() ==B.k()  && B.k()==src.k(),\n                  \"\\nA.nr(): \" << A.nr() << \"\\nB.nr(): \" << B.nr() << \"\\nsrc.nr(): \" << src.nr()\n                  <<\"\\nA.nc(): \" << A.nc() << \"\\nB.nc(): \" << B.nc() << \"\\nsrc.nc(): \" << src.nc()\n                  <<\"\\nA.k(): \" << A.k() << \"\\nB.k(): \" << B.k() << \"\\nsrc.k(): \" << src.k()\n                  );\n\n            if (A.num_samples() == 1)\n            {\n                launch_kernel(_cuda_affine_transform3,max_jobs(dest.size()),dest.device(), src.device(), src.size(), A.device(), B.device(), A.size());\n            }\n            else\n            {\n                launch_kernel(_cuda_affine_transform2,max_jobs(dest.size()),dest.device(), src.device(), src.size(), A.device(), B.device());\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_compute_adam_update(\n            size_t begin,\n            size_t end,\n            float* s,\n            float* m,\n            float* v,\n            const float alpha,\n            const float weight_decay,\n            const float momentum1,\n            const float momentum2,\n            const float* params,\n            const float* params_grad\n        )\n        {\n            const float eps = 1e-8;\n            // The loop is equivalent to doing this:\n            //   m = momentum1*m + (1-momentum1)    *   (weight_decay*params + params_grad);\n            //   v = momentum2*v + (1-momentum2)*squared(weight_decay*params + params_grad);\n            //   s = -alpha*m/(sqrt(v) + eps);\n            for (auto i : grid_stride_range(begin, end))\n            {\n                float g = (weight_decay*params[i] + params_grad[i]);\n                m[i] = momentum1*m[i] + (1-momentum1)*g;\n                v[i] = momentum2*v[i] + (1-momentum2)*g*g;\n                s[i] = -alpha*m[i]/(std::sqrt(v[i]) + eps);\n            }\n        }\n\n        void compute_adam_update (\n            size_t begin,\n            size_t end,\n            tensor& s,\n            tensor& m,\n            tensor& v,\n            const float t,\n            const float learning_rate,\n            const float weight_decay,\n            const float momentum1,\n            const float momentum2,\n            const tensor& params,\n            const tensor& params_grad\n        )\n        {\n            DLIB_CASSERT(s.size() == m.size() &&\n                         s.size() == v.size() &&\n                         s.size() == params.size() &&\n                         s.size() == params_grad.size());\n            DLIB_CASSERT(begin <= end && end <= params.size());\n            const float alpha = learning_rate*std::sqrt(1-std::pow(momentum2,t))/(1-std::pow(momentum1, t));\n\n            launch_kernel(_cuda_compute_adam_update,max_jobs(end-begin),\n                    begin, end, s.device(), m.device(), v.device(), alpha, weight_decay,\n                    momentum1, momentum2, params.device(), params_grad.device());\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _cuda_affine_transform_conv(float* d, const float* s, size_t n, const float* A, const float* B, size_t bs, size_t ks)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                auto k = (i/bs)%ks;\n                d[i] = A[k]*s[i] + B[k];\n            }\n        }\n\n        void affine_transform_conv(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest, src));\n            DLIB_CASSERT(have_same_dimensions(A, B));\n            DLIB_CASSERT(A.num_samples() == 1 && A.nr() == 1 && A.nc() == 1 && A.k() == src.k());\n\n            launch_kernel(_cuda_affine_transform_conv,max_jobs(dest.size()),\n                    dest.device(), src.device(), src.size(), A.device(), B.device(), src.nr()*src.nc(), src.k());\n        }\n\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _add_bias_gradient(float* out, const float* in, size_t n, size_t total_n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                out[i] = in[i];\n                for (size_t j = i+n; j < total_n; j+=n)\n                    out[i] += in[j];\n            }\n        }\n\n        void assign_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  grad.num_samples() == 1 &&\n                  gradient_input.k() == grad.k() &&\n                  gradient_input.nr() == grad.nr() &&\n                  gradient_input.nc() == grad.nc() &&\n                  gradient_input.size() > 0);\n\n            launch_kernel(_add_bias_gradient,max_jobs(grad.size()),grad.device(), gradient_input.device(), grad.size(), gradient_input.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _set_tensor(float* out, size_t n, const float val)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] = val;\n        }\n\n        void set_tensor (\n            tensor& t,\n            float value\n        )\n        {\n            launch_kernel(_set_tensor, max_jobs(t.size()), t.device(), t.size(), value);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _scale_tensor(float* out, size_t n, const float val)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] *= val;\n        }\n\n        void scale_tensor (\n            tensor& t,\n            float value\n        )\n        {\n            launch_kernel(_scale_tensor, max_jobs(t.size()), t.device(), t.size(), value);\n        }\n\n    // -----------------------------------------------------------------------------------\n    // -----------------------------------------------------------------------------------\n\n        __global__ void _cuda_threshold(float* d, size_t n, float thresh)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = d[i]>thresh ? 1:0;\n            }\n        }\n\n        void threshold (\n            tensor& data,\n            float thresh\n        )\n        {\n            launch_kernel(_cuda_threshold,max_jobs(data.size()),data.device(), data.size(), thresh);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_dot(const float* a, const float* b, size_t n, float* result)\n        {\n            // Parallel sum everything into local temp variables.\n            float temp = 0;\n            for(auto i : grid_stride_range(0, n))\n                temp += a[i]*b[i];\n\n            // Then do the warp reduce add thing to merge into one output value.\n            warp_reduce_atomic_add(*result, temp);\n        }\n\n\n        void dot (\n            const tensor& a,\n            const tensor& b,\n            tensor& result,\n            size_t idx\n        )\n        {\n            DLIB_CASSERT(a.size() == b.size());\n            DLIB_CASSERT(idx < result.size());\n\n            launch_kernel(_cuda_dot, max_jobs(a.size()), a.device(), b.device(), a.size(), result.device()+idx);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_prelu(const float* s, float* d, size_t n, const float* pp)\n        {\n            const float p = *pp;\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = p*s[i];\n            }\n        }\n\n        void prelu (\n            tensor& dest,\n            const tensor& src,\n            const tensor& param\n        )\n        {\n            launch_kernel(_cuda_prelu, max_jobs(dest.size()), \n                src.device(), dest.device(), src.size(), param.device());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_prelu_gradient(float* out, const float* s, const float* gi, size_t n, const float* pp, float* ppgrad)\n        {\n            const float p = *pp;\n            float pgrad = 0;\n            for(auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                {\n                    out[i] += gi[i];\n                }\n                else\n                {\n                    out[i] += p*gi[i];\n                    pgrad += gi[i]*s[i];\n                }\n            }\n\n            // Then do the warp reduce add thing to merge into one output value.\n            warp_reduce_atomic_add(*ppgrad, pgrad);\n        }\n\n        void prelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const tensor& param,\n            tensor& params_grad \n        )\n        {\n            params_grad = 0;\n            launch_kernel(_cuda_prelu_gradient, max_jobs(grad.size()), \n                grad.device(), src.device(), gradient_input.device(), grad.size(),\n                param.device(), params_grad.device());\n        }\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_leaky_relu(const float* s, float* d, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = alpha * s[i];\n            }\n        }\n\n        void leaky_relu(\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        )\n        {\n            launch_kernel(_cuda_leaky_relu, max_jobs(dest.size()),\n                src.device(), dest.device(), src.size(), alpha);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_leaky_relu_gradient_inplace(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    out[i] = gi[i];\n                else\n                    out[i] = alpha * gi[i];\n            }\n        }\n\n        __global__ void _cuda_leaky_relu_gradient(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    out[i] += gi[i];\n                else\n                    out[i] += alpha * gi[i];\n            }\n        }\n\n        void leaky_relu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const float alpha\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n            {\n                launch_kernel(_cuda_leaky_relu_gradient_inplace, max_jobs(grad.size()),\n                    out, src.device(), gi, grad.size(), alpha);\n            }\n            else\n            {\n                launch_kernel(_cuda_leaky_relu_gradient, max_jobs(grad.size()),\n                    out, src.device(), gi, grad.size(), alpha);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_mish(const float* s, float* d, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                const auto e = std::exp(s[i]);\n                const auto delta = 2*e + e*e + 2;\n                d[i] = s[i] - 2*s[i]/delta;\n            }\n        }\n\n        void mish (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            launch_kernel(_cuda_mish, max_jobs(dest.size()), src.device(), dest.device(), src.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __device__ float mish_compute_gradient(float x)\n        {\n            if (x >= 8)\n                return 1.f;\n            if (x <= -8)\n                return 0.f;\n\n            const auto e = std::exp(x);\n            const auto delta = 2*e + e*e + 2;\n            const auto omega = 4*(x + 1) + 4*e*e + e*e*e + e*(4*x + 6);\n            return e*omega/(delta*delta);\n        }\n\n        __global__ void _cuda_mish_gradient_inplace(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] = gi[i]*mish_compute_gradient(s[i]);\n        }\n\n        __global__ void _cuda_mish_gradient(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] += gi[i]*mish_compute_gradient(s[i]);\n        }\n\n        void mish_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n                launch_kernel(_cuda_mish_gradient_inplace, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n            else\n                launch_kernel(_cuda_mish_gradient, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_clipped_relu(const float* s, float* d, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] < 0)\n                    d[i] = 0;\n                else if (s[i] > alpha)\n                    d[i] = alpha;\n                else\n                    d[i] = s[i];\n            }\n        }\n\n        void clipped_relu (\n            tensor& dest,\n            const tensor &src,\n            const float alpha\n        )\n        {\n            launch_kernel(_cuda_clipped_relu, max_jobs(dest.size()),\n                src.device(), dest.device(), src.size(), alpha);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_clipped_relu_gradient_inplace(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0 && s[i] < alpha)\n                    out[i] = gi[i];\n                else\n                    out[i] = 0.f;\n            }\n        }\n\n        __global__ void _cuda_clipped_relu_gradient(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0 && s[i] < alpha)\n                    out[i] += gi[i];\n            }\n        }\n\n        void clipped_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n                launch_kernel(_cuda_clipped_relu_gradient_inplace, max_jobs(grad.size()), out, dest.device(), gi, grad.size(), alpha);\n            else\n                launch_kernel(_cuda_clipped_relu_gradient, max_jobs(grad.size()), out, dest.device(), gi, grad.size(), alpha);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_elu(const float* s, float* d, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    d[i] = s[i];\n                else\n                    d[i] = alpha * (std::exp(s[i]) - 1.0f);\n            }\n        }\n\n        void elu (\n            tensor& dest,\n            const tensor &src,\n            const float alpha\n        )\n        {\n            launch_kernel(_cuda_elu, max_jobs(dest.size()), src.device(), dest.device(), src.size(), alpha);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_elu_gradient_inplace(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    out[i] = gi[i];\n                else\n                    out[i] = (alpha + s[i]) * gi[i];\n            }\n        }\n\n        __global__ void _cuda_elu_gradient(float* out, const float* s, const float* gi, size_t n, const float alpha)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] > 0)\n                    out[i] += gi[i];\n                else\n                    out[i] += (alpha + s[i]) * gi[i];\n            }\n        }\n\n        void elu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n                launch_kernel(_cuda_elu_gradient_inplace, max_jobs(grad.size()), out, dest.device(), gi, grad.size(), alpha);\n            else\n                launch_kernel(_cuda_elu_gradient, max_jobs(grad.size()), out, dest.device(), gi, grad.size(), alpha);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_gelu(const float* s, float* d, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s[i] * normcdf(s[i]);\n            }\n        }\n\n        void gelu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            launch_kernel(_cuda_gelu, max_jobs(dest.size()), src.device(), dest.device(), src.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __device__ float gelu_compute_gradient(float x)\n        {\n                const float beta = 1.0f / CUDART_SQRT_2PI;\n                const float cdf = normcdf(x);\n                const float pdf = beta*std::exp(-0.5f*x*x);\n                return cdf + x * pdf;\n        }\n\n        __global__ void _cuda_gelu_gradient_inplace(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] = gi[i]*gelu_compute_gradient(s[i]);\n        }\n\n        __global__ void _cuda_gelu_gradient(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n                out[i] += gi[i]*gelu_compute_gradient(s[i]);\n        }\n\n        void gelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n                launch_kernel(_cuda_gelu_gradient_inplace, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n            else\n                launch_kernel(_cuda_gelu_gradient, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_smelu (const float* s, float* d, size_t n, const float beta)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] >= beta)\n                    d[i] = s[i];\n                else if (s[i] <= -beta)\n                    d[i] = 0;\n                else\n                    d[i] = (s[i] + beta) * (s[i] + beta) / (4 * beta);\n            }\n        }\n\n        void smelu (\n            tensor& dest,\n            const tensor& src,\n            const float beta\n        )\n        {\n            launch_kernel(_cuda_smelu, max_jobs(dest.size()), src.device(), dest.device(), src.size(), beta);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_smelu_gradient_inplace(float* out, const float* s, const float* gi, size_t n, const float beta)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] >= beta)\n                    out[i] = gi[i];\n                else if (s[i] == 0)\n                    out[i] = 0;\n                else\n                    out[i] = std::sqrt(beta * s[i]) / beta * gi[i];\n            }\n        }\n\n        __global__ void _cuda_smelu_gradient(float* out, const float* s, const float* gi, size_t n, const float beta)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                if (s[i] >= beta)\n                    out[i] += gi[i];\n                else if (s[i] == 0)\n                    continue;\n                else\n                    out[i] += std::sqrt(beta * s[i]) / beta * gi[i];\n            }\n        }\n\n        void smelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const float beta\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n            {\n                launch_kernel(_cuda_smelu_gradient_inplace, max_jobs(grad.size()),\n                    out, src.device(), gi, grad.size(), beta);\n            }\n            else\n            {\n                launch_kernel(_cuda_smelu_gradient, max_jobs(grad.size()),\n                    out, src.device(), gi, grad.size(), beta);\n            }\n        }\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_silu(const float* s, float* d, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                d[i] = s[i] / (1.0f + std::exp(-s[i]));\n            }\n        }\n\n        void silu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            launch_kernel(_cuda_silu, max_jobs(dest.size()), src.device(), dest.device(), src.size());\n        }\n\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_silu_gradient_inplace(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                const auto sig_s = 1.0f / (1.0f + std::exp(-s[i]));\n                out[i] = gi[i] * (sig_s * (1.0f + s[i] * (1.0f - sig_s)));\n            }\n        }\n\n        __global__ void _cuda_silu_gradient(float* out, const float* s, const float* gi, size_t n)\n        {\n            for (auto i : grid_stride_range(0, n))\n            {\n                const auto sig_s = 1.0f / (1.0f + std::exp(-s[i]));\n                out[i] += gi[i] * (sig_s * (1.0f + s[i] * (1.0f - sig_s)));\n            }\n        }\n\n        void silu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        )\n        {\n            float* out = grad.device();\n            const float* gi = gradient_input.device();\n            if (out == gi)\n                launch_kernel(_cuda_silu_gradient_inplace, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n            else\n                launch_kernel(_cuda_silu_gradient, max_jobs(grad.size()), out, src.device(), gi, grad.size());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_resize_bilinear(size_t dsize, size_t dchan_size, size_t dnc, float* d, \n                                              size_t schan_size, int snr, int snc, const float* s, \n                                              const float x_scale, const float y_scale)\n        {\n            for(auto i : grid_stride_range(0, dsize)) \n            {\n                const int idx = i%dchan_size;\n                const int channel = i/dchan_size;\n                const int sidx = channel*schan_size;\n                const int r = idx/dnc;\n                const int c = idx%dnc;\n\n                const float y = r*y_scale;\n                const int top    = static_cast<int>(::floorf(y));\n                const int bottom = ::min(top+1, snr-1);\n                const float tb_frac = y - top;\n\n                const float x = c*x_scale;\n                const int left   = static_cast<int>(::floorf(x));\n                const int right  = ::min(left+1, snc-1);\n                const float lr_frac = x - left;\n\n                float tl = s[sidx+top*snc+left];\n                float tr = s[sidx+top*snc+right];\n                float bl = s[sidx+bottom*snc+left];\n                float br = s[sidx+bottom*snc+right];\n\n                float temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) + \n                    tb_frac*((1-lr_frac)*bl + lr_frac*br);\n\n                d[i] = temp;\n            }\n        }\n\n        __global__ void _cuda_resize_bilinear_strided(size_t dsize, size_t dchan_size, size_t dnc, float* d, \n                                              size_t schan_size, int snr, int snc, const float* s, \n                                              const float x_scale, const float y_scale, \n                                              size_t dest_row_stride, size_t src_row_stride, size_t dest_chan_size_strided\n                                              )\n        {\n            for(auto i : grid_stride_range(0, dsize)) \n            {\n                const int idx = i%dchan_size;\n                const int channel = i/dchan_size;\n                const int sidx = channel*schan_size;\n                const int r = idx/dnc;\n                const int c = idx%dnc;\n                const int didx = channel*dest_chan_size_strided + r*dest_row_stride+c;\n\n                const float y = r*y_scale;\n                const int top    = static_cast<int>(::floorf(y));\n                const int bottom = ::min(top+1, snr-1);\n                const float tb_frac = y - top;\n\n                const float x = c*x_scale;\n                const int left   = static_cast<int>(::floorf(x));\n                const int right  = ::min(left+1, snc-1);\n                const float lr_frac = x - left;\n\n                float tl = s[sidx+top*src_row_stride+left];\n                float tr = s[sidx+top*src_row_stride+right];\n                float bl = s[sidx+bottom*src_row_stride+left];\n                float br = s[sidx+bottom*src_row_stride+right];\n\n                float temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) + \n                    tb_frac*((1-lr_frac)*bl + lr_frac*br);\n\n                d[didx] = temp;\n            }\n        }\n\n        void resize_bilinear (\n            tensor& dest,\n            long long dest_row_stride,\n            long long dest_channel_stride,\n            const tensor& src,\n            long long src_row_stride,\n            long long src_channel_stride\n        )\n        {\n            DLIB_CASSERT(is_same_object(dest, src)==false);\n            DLIB_CASSERT(dest.num_samples() == src.num_samples());\n            DLIB_CASSERT(dest.k() == src.k());\n\n            if (dest.size() == 0 || src.size() == 0)\n                return;\n\n            const float x_scale = (src.nc()-1)/(float)std::max<long>((dest.nc()-1),1);\n            const float y_scale = (src.nr()-1)/(float)std::max<long>((dest.nr()-1),1);\n\n            if (dest.nc() == dest_row_stride && dest.nr()*dest.nc()==dest_channel_stride &&\n                src.nc()  == src_row_stride  && src.nr()*src.nc()==src_channel_stride)\n            {\n                launch_kernel(_cuda_resize_bilinear, \n                        dest.size(), dest.nr()*dest.nc(), dest.nc(), dest.device(),\n                        src.nr()*src.nc(), src.nr(), src.nc(), src.device(),\n                        x_scale, y_scale);\n            }\n            else\n            {\n                launch_kernel(_cuda_resize_bilinear_strided, \n                        dest.size(), dest.nr()*dest.nc(), dest.nc(), dest.device(),\n                        src_channel_stride, src.nr(), src.nc(), src.device(),\n                        x_scale, y_scale, dest_row_stride, src_row_stride, dest_channel_stride);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_resize_bilinear_gradient(size_t dsize, size_t dchan_size, size_t dnc, const float* d, \n                                              size_t schan_size, int snr, int snc, float* s, \n                                              const float x_scale, const float y_scale)\n        {\n            for(auto i : grid_stride_range(0, dsize)) \n            {\n                const float tmp = d[i];\n\n                const int idx = i%dchan_size;\n                const int channel = i/dchan_size;\n                const int sidx = channel*schan_size;\n                const int r = idx/dnc;\n                const int c = idx%dnc;\n\n                const float y = r*y_scale;\n                const int top    = static_cast<int>(::floorf(y));\n                const int bottom = ::min(top+1, snr-1);\n                const float tb_frac = y - top;\n\n                const float x = c*x_scale;\n                const int left   = static_cast<int>(::floorf(x));\n                const int right  = ::min(left+1, snc-1);\n                const float lr_frac = x - left;\n\n\n                atomicAdd(s+sidx+top*snc+left,     tmp*(1-tb_frac)*(1-lr_frac));\n                atomicAdd(s+sidx+top*snc+right,    tmp*(1-tb_frac)*(lr_frac));\n                atomicAdd(s+sidx+bottom*snc+left,  tmp*(tb_frac)*(1-lr_frac));\n                atomicAdd(s+sidx+bottom*snc+right, tmp*(tb_frac)*(lr_frac));\n            }\n        }\n\n        __global__ void _cuda_resize_bilinear_gradient_strided(size_t dsize, size_t dchan_size, size_t dnc, const float* d, \n                                              size_t schan_size, int snr, int snc, float* s, \n                                              const float x_scale, const float y_scale,\n                                              size_t dest_row_stride, size_t src_row_stride, size_t dest_chan_size_strided\n                                              )\n        {\n            for(auto i : grid_stride_range(0, dsize)) \n            {\n\n                const int idx = i%dchan_size;\n                const int channel = i/dchan_size;\n                const int didx = channel*dest_chan_size_strided;\n                const int sidx = channel*schan_size;\n                const int r = idx/dnc;\n                const int c = idx%dnc;\n\n                const float tmp = d[didx + r*dest_row_stride+c];\n\n                const float y = r*y_scale;\n                const int top    = static_cast<int>(::floorf(y));\n                const int bottom = ::min(top+1, snr-1);\n                const float tb_frac = y - top;\n\n                const float x = c*x_scale;\n                const int left   = static_cast<int>(::floorf(x));\n                const int right  = ::min(left+1, snc-1);\n                const float lr_frac = x - left;\n\n\n                atomicAdd(s+sidx+top*src_row_stride+left,     tmp*(1-tb_frac)*(1-lr_frac));\n                atomicAdd(s+sidx+top*src_row_stride+right,    tmp*(1-tb_frac)*(lr_frac));\n                atomicAdd(s+sidx+bottom*src_row_stride+left,  tmp*(tb_frac)*(1-lr_frac));\n                atomicAdd(s+sidx+bottom*src_row_stride+right, tmp*(tb_frac)*(lr_frac));\n            }\n        }\n\n        void resize_bilinear_gradient (\n            tensor& grad,\n            long long grad_row_stride,\n            long long grad_channel_stride,\n            const tensor& gradient_input,\n            long long gradient_input_row_stride,\n            long long gradient_input_channel_stride\n        )\n        {\n            DLIB_CASSERT(is_same_object(grad, gradient_input)==false);\n            DLIB_CASSERT(gradient_input.num_samples() == grad.num_samples());\n            DLIB_CASSERT(gradient_input.k() == grad.k());\n\n            if (grad.size() == 0 || gradient_input.size() == 0)\n                return;\n\n            const float x_scale = (grad.nc()-1)/(float)std::max<long>((gradient_input.nc()-1),1);\n            const float y_scale = (grad.nr()-1)/(float)std::max<long>((gradient_input.nr()-1),1);\n\n            if (grad.nc() == grad_row_stride && grad.nr()*grad.nc()==grad_channel_stride &&\n                gradient_input.nc() == gradient_input_row_stride && gradient_input.nr()*gradient_input.nc()==gradient_input_channel_stride)\n            {\n                launch_kernel(_cuda_resize_bilinear_gradient, \n                        gradient_input.size(), gradient_input.nr()*gradient_input.nc(), gradient_input.nc(), gradient_input.device(),\n                        grad.nr()*grad.nc(), grad.nr(), grad.nc(), grad.device(),\n                        x_scale, y_scale);\n            }\n            else\n            {\n                launch_kernel(_cuda_resize_bilinear_gradient_strided, \n                        gradient_input.size(), gradient_input.nr()*gradient_input.nc(), gradient_input.nc(), gradient_input.device(),\n                        grad_channel_stride, grad.nr(), grad.nc(), grad.device(),\n                        x_scale, y_scale, gradient_input_row_stride, grad_row_stride, gradient_input_channel_stride);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_reorg(size_t dsize, size_t dk, size_t dnr, size_t dnc, float* d,\n                                    size_t sk, size_t snr, int snc, const float* s,\n                                    const size_t row_stride, const size_t col_stride, const bool add_to)\n        {\n            const auto out_plane_size = dnr * dnc;\n            const auto out_sample_size = dk * out_plane_size;\n            for (auto i : grid_stride_range(0, dsize))\n            {\n                const auto n = i / out_sample_size;\n                const auto out_idx = i % out_sample_size;\n                const auto out_k = out_idx / out_plane_size;\n                const auto out_rc = out_idx % out_plane_size;\n                const auto out_r = out_rc / dnc;\n                const auto out_c = out_rc % dnc;\n\n                const auto in_k = out_k % sk;\n                const auto in_r = out_r * row_stride + (out_k / sk) / col_stride;\n                const auto in_c = out_c * col_stride + (out_k / sk) % col_stride;\n\n                const auto in_idx = ((n * sk + in_k) * snr + in_r) * snc + in_c;\n                if (add_to) d[i] += s[in_idx];\n                else d[i] = s[in_idx];\n            }\n        }\n\n        __global__ void _cuda_reorg_gradient(size_t ssize, size_t dk, size_t dnr, size_t dnc, float* d,\n                                            size_t sk, size_t snr, int snc, const float* s, const size_t row_stride,\n                                            const size_t col_stride, const bool add_to\n        )\n        {\n            for(auto i : grid_stride_range(0, ssize))\n            {\n                const auto n = i / (sk * snr * snc);\n                const auto sample_idx = i % (sk * snr * snc);\n                const auto in_k = (sample_idx / (snr * snc)) % sk;\n                const auto in_r = (sample_idx / snc) % snr;\n                const auto in_c = sample_idx % snc;\n\n                const auto out_k = in_k % dk;\n                const auto out_r = in_r * row_stride + (in_k / dk) / col_stride;\n                const auto out_c = in_c * col_stride + (in_k / dk) % col_stride;\n                const auto out_idx = ((n * dk + out_k) * dnr + out_r) * dnc + out_c;\n\n                if (add_to) d[out_idx] += s[i];\n                else d[out_idx] = s[i];\n            }\n        }\n\n        void reorg(\n            bool add_to,\n            tensor& dest,\n            const int row_stride,\n            const int col_stride,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(!is_same_object(dest, src), \"Destination and source must be distinct objects.\");\n            DLIB_CASSERT(src.nr() % row_stride == 0, \"The number of rows in src must be divisible by row_stride.\");\n            DLIB_CASSERT(src.nc() % col_stride == 0, \"The number of columns in src must be divisible by col_stride.\");\n            DLIB_CASSERT(dest.num_samples() == src.num_samples(), \"The number of samples must match.\");\n            DLIB_CASSERT(dest.k() == src.k() * row_stride * col_stride, \"The number of channels must match.\");\n            DLIB_CASSERT(dest.nr() == src.nr() / row_stride, \"The number of rows must match.\");\n            DLIB_CASSERT(dest.nc() == src.nc() / col_stride, \"The number of columns must match.\");\n\n            launch_kernel(_cuda_reorg, dest.size(), dest.k(), dest.nr(), dest.nc(), dest.device(),\n                src.k(), src.nr(), src.nc(), src.device(), row_stride, col_stride, add_to);\n        }\n\n        void reorg_gradient(\n            bool add_to,\n            tensor& grad,\n            const int row_stride,\n            const int col_stride,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(!is_same_object(grad, gradient_input), \"Grad and gradient_input must be distinct objects.\");\n            DLIB_CASSERT(grad.nr() % row_stride == 0, \"The number of rows in grad must be divisible by row_stride.\");\n            DLIB_CASSERT(grad.nc() % col_stride == 0, \"The number of columns in grad must be divisible by col_stride.\");\n            DLIB_CASSERT(grad.num_samples() == gradient_input.num_samples(), \"The number of samples in grad and gradient_input must match.\");\n            DLIB_CASSERT(grad.k() == gradient_input.k() / row_stride / col_stride, \"The number of channels in grad must be gradient_input.k() divided by row_stride and col_stride.\");\n            DLIB_CASSERT(grad.nr() == gradient_input.nr() * row_stride, \"The number of rows in grad must be gradient_input.nr() multiplied by row_stride.\");\n            DLIB_CASSERT(grad.nc() == gradient_input.nc() * col_stride, \"The number of columns in grad must be gradient_input.nc() multiplied by col_stride.\");\n\n            launch_kernel(_cuda_reorg_gradient, gradient_input.size(), grad.k(), grad.nr(), grad.nc(), grad.device(),\n                gradient_input.k(), gradient_input.nr(), gradient_input.nc(), gradient_input.device(),\n                row_stride, col_stride, add_to);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_embeddings(size_t dsize, size_t dk, size_t dr, size_t dc,\n            float* d, const float* s, const float* e, size_t es\n        )\n        {\n            for (auto i : grid_stride_range(0, dsize))\n            {\n                const auto n = i / (dk * dr * dc);\n                const auto s_idx = i % (dk * dr * dc);\n                const auto k = (s_idx / (dr * dc)) % dk;\n                const auto r = (s_idx / dc) % dr;\n                const auto c = s_idx % dc;\n\n                const unsigned long t_idx = static_cast<unsigned long>(s[(n * dk + k) * dr + r]);\n\n                if (t_idx < es)\n                    d[i] = e[t_idx * dc + c];\n                else\n                    d[i] = 0.0f;\n            }\n        }\n\n        void embeddings(\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& embs\n        )\n        {\n            DLIB_CASSERT(\n                src.nr() > 0 &&\n                embs.num_samples() > 0 &&\n                embs.k() > 0 &&\n                embs.nr() == 1 &&\n                embs.nc() == 1,\n                \"\\nsrc.num_samples(): \" << src.num_samples() <<\n                \"\\nsrc.k(): \" << src.k() <<\n                \"\\nsrc.nr(): \" << src.nr() <<\n                \"\\nsrc.nc(): \" << src.nc() <<\n                \"\\nembs.num_samples(): \" << embs.num_samples() <<\n                \"\\nembs.k(): \" << embs.k() <<\n                \"\\nembs.nr(): \" << embs.nr() <<\n                \"\\nembs.nc(): \" << embs.nc()\n            );\n\n            const long dk = dest.k();\n            const long dr = dest.nr();\n            const long dc = dest.nc();\n\n            launch_kernel(_cuda_embeddings, dest.size(), dk, dr, dc,\n                dest.device(), src.device(), embs.device(), embs.num_samples());\n        }\n\n        __global__ void _cuda_embeddings_gradient(size_t ssize, size_t sk, size_t sr, size_t sc,\n            const float* o, const float* gi, float* g, const float* f, float lr, bool sl, size_t es\n        )\n        {\n            for (auto i : grid_stride_range(0, ssize))\n            {\n                const auto n = i / (sk * sr * sc);\n                const auto s_idx = i % (sk * sr * sc);\n                const auto k = (s_idx / (sr * sc)) % sk;\n                const auto r = (s_idx / sc) % sr;\n                const auto c = s_idx % sc;\n\n                const unsigned long t_idx = static_cast<unsigned long>(o[(n * sk + k) * sr + r]);\n                if (t_idx < es)\n                {\n                    const float f_t = f[t_idx];\n                    float f_s = 1.0f;                    \n\n                    if (sl && f_t != 0.0f) f_s = fminf(0.15f, fmaxf(1.0f / f_t, 1.0f));\n                    if (f_t > 1) atomicAdd(&g[t_idx * sc + c], -gi[i] * lr * f_s);\n                    else g[t_idx * sc + c] -= gi[i] * lr * f_s;\n                }\n            }\n        }\n\n        void embeddings_gradient(\n            const tensor& prev,\n            const tensor& gradient_input,\n            tensor& grads,\n            const tensor& freqs,\n            float learning_rate,\n            bool scale\n        )\n        {\n            DLIB_CASSERT(\n                prev.nr() > 0 &&\n                gradient_input.num_samples() == prev.num_samples() &&\n                gradient_input.k() == prev.k() &&\n                gradient_input.nr() == prev.nr() &&\n                gradient_input.nc() == grads.k() &&\n                grads.num_samples() > 0 &&\n                grads.k() > 0 &&\n                grads.nr() == 1 &&\n                grads.nc() == 1,\n                \"\\ngradient_input.num_samples(): \" << gradient_input.num_samples() <<\n                \"\\ngradient_input.k(): \" << gradient_input.k() <<\n                \"\\ngradient_input.nr(): \" << gradient_input.nr() <<\n                \"\\ngradient_input.nc(): \" << gradient_input.nc() <<\n                \"\\nprev.num_samples(): \" << prev.num_samples() <<\n                \"\\nprev.k(): \" << prev.k() <<\n                \"\\nprev.nr(): \" << prev.nr() <<\n                \"\\nprev.nc(): \" << prev.nc() <<\n                \"\\ngrads.num_samples(): \" << grads.num_samples() <<\n                \"\\ngrads.k(): \" << grads.k() <<\n                \"\\ngrads.nr(): \" << grads.nr() <<\n                \"\\ngrads.nc(): \" << grads.nc()\n            );\n            \n            const long sk = gradient_input.k();\n            const long sr = gradient_input.nr();\n            const long sc = gradient_input.nc();\n\n            launch_kernel(_cuda_embeddings_gradient, gradient_input.size(), sk, sr, sc,\n                prev.device(), gradient_input.device(), grads.device(), freqs.device(),\n                learning_rate, scale, grads.num_samples());\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_layer_normalize(\n            float* out,\n            const float* s,\n            float* m,\n            float* v,\n            const float* g,\n            const float* b,\n            float eps,\n            size_t ns,\n            size_t k,\n            size_t num\n        )\n        {\n           // compute means and sum of squares\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = s + n * k * num;\n                float means = 0;\n                float invstds = 0;\n                for (auto i : grid_stride_range(0, k * num))\n                {\n                    means += ps[i];\n                    invstds += ps[i] * ps[i];\n                }\n                warp_reduce_atomic_add(m[n], means / (k * num));\n                warp_reduce_atomic_add(v[n], invstds / (k * num));\n            }\n            __syncthreads();\n\n            // compute variances\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                for (auto i : grid_stride_range(0, 1))\n                {\n                    v[n] = 1.0f / std::sqrt(v[n] - m[n] * m[n] + eps);\n                }\n            }\n            __syncthreads();\n\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = s + n * k * num;\n                const auto pout = out + n * k * num;\n                for (auto i : grid_stride_range(0, k * num))\n                {\n                    pout[i] = (ps[i] - m[n]) * v[n];\n                    pout[i] = pout[i] * g[i / num] + b[i / num];\n                }\n            }\n        }\n\n        void layer_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            const tensor& beta\n        )\n        {\n            const long num = src.nr() * src.nc();\n            DLIB_CASSERT(\n                have_same_dimensions(gamma, beta) &&\n                gamma.k() == src.k() &&\n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                eps > 0,\n                \"\\nsrc.k():    \" << src.k() <<\n                \"\\ngamma.k():  \" << gamma.k() <<\n                \"\\ngamma.nr(): \" << gamma.nr() <<\n                \"\\ngamma.nc(): \" << gamma.nc() <<\n                \"\\nbeta.k():   \" << beta.k() <<\n                \"\\nbeta.nr():  \" << beta.nr() <<\n                \"\\nbeta.nc():  \" << beta.nc() <<\n                \"\\neps:  \" << eps\n            );\n\n            dest.copy_size(src);\n            means.set_size(src.num_samples());\n            invstds.set_size(src.num_samples());\n            means = 0;\n            invstds = 0;\n            launch_kernel(_cuda_layer_normalize, max_jobs(src.k() * num, src.num_samples()), dest.device(), src.device(),\n                          means.device(), invstds.device(), gamma.device(), beta.device(), eps, src.num_samples(), src.k(), num);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_layer_normalize_gradient(\n            float* out,\n            float* gg,\n            float* bg,\n            const float* s,\n            const float* gi,\n            const float* m,\n            const float* v,\n            const float* g,\n            float* dm,\n            float* dv,\n            float eps,\n            size_t ns,\n            size_t ks,\n            size_t num)\n        {\n            for (auto nk : grid_stride_range_y(0, ns * ks))\n            {\n                const auto n = nk / ks;\n                const auto k = nk % ks;\n                const auto ps = s + (n * ks + k) * num;\n                const auto pgi = gi + (n * ks + k) * num;\n                const float invstd_pow = -0.5 * std::pow(v[n], 3.0f);\n                float temp_bg = 0;\n                float temp_gg = 0;\n                float temp_dv = 0;\n                for (auto i : grid_stride_range(0, num))\n                {\n                    const float x_hat = (ps[i] - m[n]) * v[n];\n                    const float dx = pgi[i] * g[i / num];\n                    temp_bg += pgi[i];\n                    temp_gg += pgi[i] * x_hat;\n                    temp_dv += dx * (ps[i] - m[n]) * invstd_pow;\n                }\n                warp_reduce_atomic_add(bg[k], temp_bg);\n                warp_reduce_atomic_add(gg[k], temp_gg);\n                warp_reduce_atomic_add(dv[n], temp_dv);\n            }\n            __syncthreads();\n\n            const float invnum = 1.0f / (ks * num);\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = s + n * ks * num;\n                const auto pgi = gi + n * ks * num;\n                float temp_dm = 0;\n                for (auto i : grid_stride_range(0, ks * num))\n                {\n                    const float dx = pgi[i] * g[i / num];\n                    temp_dm += -dx * v[n] + dv[n] * -2 * (ps[i] - m[n]) * invnum;\n                }\n                warp_reduce_atomic_add(dm[n], temp_dm);\n            }\n            __syncthreads();\n\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = s + n * ks * num;\n                const auto pgi = gi + n * ks * num;\n                const auto pout = out + n * ks * num;\n                for (auto i : grid_stride_range(0, ks * num))\n                {\n                    const float dx = pgi[i] * g[i / num];\n                    pout[i] += dx * v[n] + dv[n] * 2 * (ps[i] - m[n]) * invnum + dm[n] * invnum;\n                }\n            }\n        }\n\n        void layer_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n        )\n        {\n            const long num = src.nr() * src.nc();\n            DLIB_CASSERT(src.num_samples() == means.size());\n            DLIB_CASSERT(src.num_samples() == invstds.size());\n            DLIB_CASSERT(have_same_dimensions(gamma, gamma_grad));\n            DLIB_CASSERT(have_same_dimensions(gamma_grad, beta_grad));\n            DLIB_CASSERT(gamma.k() == src.k());\n            DLIB_CASSERT(gamma.nr() == 1);\n            DLIB_CASSERT(gamma.nc() == 1);\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            beta_grad = 0;\n            gamma_grad = 0;\n            dvars.copy_size(invstds);\n            dmeans.copy_size(means);\n            dvars = 0;\n            dmeans = 0;\n            launch_kernel(_cuda_layer_normalize_gradient, max_jobs(src.k() * num, src.num_samples()),\n                          src_grad.device(), gamma_grad.device(), beta_grad.device(), src.device(),\n                          gradient_input.device(), means.device(), invstds.device(), gamma.device(),\n                          dmeans.device(), dvars.device(), eps, src.num_samples(), src.k(), num);\n        }\n\n   // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_rms_normalize(\n            float* dest,\n            float* scale,\n            const float* src,\n            const float* gamma,\n            float eps,\n            size_t ns,\n            size_t ks,\n            size_t num\n        )\n        {\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = src + n * ks * num;\n                float sum_squares = 0.0f;\n                for (auto i : grid_stride_range(0, ks * num))\n                {\n                    sum_squares += ps[i] * ps[i];\n                }\n                warp_reduce_atomic_add(scale[n], sum_squares / (ks * num));\n            }\n            __syncthreads();\n\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                for (auto i : grid_stride_range(0, 1))\n                {\n                    scale[n] = 1.0f / std::sqrt(scale[n] + eps);\n                }\n            }\n            __syncthreads();\n\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = src + n * ks * num;\n                const auto pd = dest + n * ks * num;\n                for (auto i : grid_stride_range(0, ks * num))\n                {\n                    pd[i] = ps[i] * scale[n] * gamma[i / num];\n                }\n            }\n        }\n\n        void rms_normalize(\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& scale,\n            const tensor& src,\n            const tensor& gamma\n        )\n        {            \n            DLIB_CASSERT(\n                gamma.k() == src.k() &&\n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                eps > 0,\n                \"\\nsrc.k():    \" << src.k() <<\n                \"\\ngamma.k():  \" << gamma.k() <<\n                \"\\ngamma.nr(): \" << gamma.nr() <<\n                \"\\ngamma.nc(): \" << gamma.nc() <<\n                \"\\neps:  \" << eps\n            );\n\n            const long ns = src.num_samples();\n            const long ks = src.k();\n            const long num = src.nr() * src.nc();\n\n            dest.copy_size(src);\n            scale.set_size(ns);\n            scale = 0;\n\n            launch_kernel(_cuda_rms_normalize, max_jobs(ks * num, ns),\n                dest.device(), scale.device(), src.device(), gamma.device(), eps, ns, ks, num);\n        }\n\n   // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_rms_normalize_gradient(\n            float* src_grad,\n            float* gamma_grad,\n            float* dscale,\n            const float* src,\n            const float* gradient_input,\n            const float* scale,\n            const float* gamma,\n            size_t ns, \n            size_t ks,  \n            size_t num \n        )\n        {\n            for (auto nk : grid_stride_range_y(0, ns * ks))\n            {\n                const auto n = nk / ks;\n                const auto k = nk % ks;\n                const auto ps = src + (n * ks + k) * num;\n                const auto pgi = gradient_input + (n * ks + k) * num;\n                const float scale_pow = -0.5f * std::pow(scale[n], 3.0f);\n                float temp_gg = 0.0f;\n                float temp_ds = 0.0f;\n                for (auto i : grid_stride_range(0, num))\n                {\n                    const float x_hat = ps[i] * scale[n];\n                    const float dx = pgi[i] * gamma[i / num];\n                    temp_gg += pgi[i] * x_hat;\n                    temp_ds += dx * ps[i] * scale_pow;\n                }\n                warp_reduce_atomic_add(gamma_grad[k], temp_gg);\n                warp_reduce_atomic_add(dscale[n], temp_ds);\n            }\n            __syncthreads();\n\n            const float invnum = 1.0f / (ks * num);\n            for (auto n : grid_stride_range_y(0, ns))\n            {\n                const auto ps = src + n * ks * num;\n                const auto pgi = gradient_input + n * ks * num;\n                const auto psg = src_grad + n * ks * num;\n                for (auto i : grid_stride_range(0, ks * num))\n                {\n                    const float dx = pgi[i] * gamma[i / num];\n                    psg[i] += dx * scale[n] + dscale[n] * 2 * ps[i] * invnum;\n                }\n            }\n        }\n\n        void rms_normalize_gradient(\n            const tensor& gradient_input,\n            const tensor& scale,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            resizable_tensor& dscale\n        )\n        {            \n            DLIB_CASSERT(src.num_samples() == scale.size());\n            DLIB_CASSERT(have_same_dimensions(gamma, gamma_grad));\n            DLIB_CASSERT(gamma.k() == src.k());\n            DLIB_CASSERT(gamma.nr() == 1);\n            DLIB_CASSERT(gamma.nc() == 1);\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n\n            const long ns = src.num_samples();\n            const long ks = src.k();\n            const long num = src.nr() * src.nc();\n\n            gamma_grad = 0;\n            dscale.copy_size(scale);\n            dscale = 0;\n\n            // Lancement du kernel CUDA\n            launch_kernel(_cuda_rms_normalize_gradient, max_jobs(ks * num, ns),\n                src_grad.device(), gamma_grad.device(), dscale.device(),\n                src.device(), gradient_input.device(), scale.device(), gamma.device(),\n                ns, ks, num);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_copy_tensor_add_to (float* dest, size_t size,  const float* src,  size_t dest_stride, size_t src_stride, size_t block_size)\n        {\n            for(auto i : grid_stride_range(0, size)) \n            {\n                size_t blk = i/block_size;\n                size_t j = i%block_size;\n                dest[blk*dest_stride + j] += src[blk*src_stride + j];\n            }\n        }\n\n        __global__ void _cuda_copy_tensor (float* dest, size_t size,  const float* src,  size_t dest_stride, size_t src_stride, size_t block_size)\n        {\n            for(auto i : grid_stride_range(0, size)) \n            {\n                size_t blk = i/block_size;\n                size_t j = i%block_size;\n                dest[blk*dest_stride + j] = src[blk*src_stride + j];\n            }\n        }\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n        )\n        {\n            const size_t dest_sample_size = static_cast<size_t>(dest.nc() * dest.nr() * dest.k());\n            const size_t src_sample_size = static_cast<size_t>(src.nc() * src.nr() * src.k());\n\n            const size_t block_size = count_k * dest.nc() * dest.nr();\n\n            DLIB_CASSERT(dest.num_samples() == src.num_samples() &&\n                         dest.nc() == src.nc() && dest.nr() == src.nr(), \"All sources should fit into dest tensor size\");\n            DLIB_CASSERT(dest.k() - dest_k_offset >= count_k, \"Not enough space in dest tensor\");\n            DLIB_CASSERT(src.k() - src_k_offset >= count_k, \"Not enough space in src tensor\");\n\n            float* dest_p = dest.device() + dest_k_offset * dest.nc() * dest.nr();\n            const float* src_p = src.device() + src_k_offset * src.nc() * src.nr();;\n\n            if (add_to)\n            {\n                launch_kernel(_cuda_copy_tensor_add_to, max_jobs(dest.size()), \n                              dest_p, block_size*dest.num_samples(),\n                              src_p, dest_sample_size, src_sample_size, block_size);\n            }\n            else\n            {\n                launch_kernel(_cuda_copy_tensor, max_jobs(dest.size()), \n                              dest_p, block_size*dest.num_samples(),\n                              src_p, dest_sample_size, src_sample_size, block_size);\n            }\n        }\n\n        __global__ void _cuda_copy_strided_tensor_add_to (float* dest, const float* src, \n                                                        size_t ns, size_t nk, size_t nr, size_t nc,\n                                                        size_t dk, size_t dr, size_t dc,\n                                                        size_t sk, size_t sr, size_t sc)\n        {\n            for(auto i : grid_stride_range(0, ns*nk*nr*nc)) \n            {\n                size_t n,k,r,c;\n                unpack_idx(i, nk,nr,nc, n,k,r,c);\n                dest[pack_idx(dk,dr,dc, n,k,r,c)] += src[pack_idx(sk,sr,sc, n,k,r,c)];\n            }\n        }\n\n        __global__ void _cuda_copy_strided_tensor (float* dest, const float* src,\n                                                   size_t ns, size_t nk, size_t nr, size_t nc,\n                                                   size_t dk, size_t dr, size_t dc,\n                                                   size_t sk, size_t sr, size_t sc)\n        {\n            for(auto i : grid_stride_range(0, ns*nk*nr*nc)) \n            {\n                size_t n,k,r,c;\n                unpack_idx(i, nk,nr,nc, n,k,r,c);\n                dest[pack_idx(dk,dr,dc, n,k,r,c)] = src[pack_idx(sk,sr,sc, n,k,r,c)];\n            }\n        }\n\n       void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dk, size_t dnr, size_t dnc,\n            const tensor& src,\n            size_t sk, size_t snr, size_t snc,\n            size_t k, size_t nr, size_t nc\n        )\n        {\n\n            DLIB_CASSERT(dest.num_samples() == src.num_samples(), \"All sources should fit into dest tensor size\");\n            DLIB_CASSERT(dest.k() - dk >= k &&\n                dest.nr() - dnr >= nr &&\n                dest.nc() - dnc >= nc, \"Not enough space in dest tensor\");\n            DLIB_CASSERT(src.k() - sk >= k &&\n                src.nr() - snr >= nr &&\n                src.nc() - snc >= nc, \"Not enough space in src tensor\");\n\n            float* dest_p = dest.device() + dk * static_cast<size_t>(dest.nc() * dest.nr()) \\\n                                          + dnr * static_cast<size_t>(dest.nc()) \\\n                                          + dnc;\n\n            const float* src_p = src.device() + sk * static_cast<size_t>(src.nc() * src.nr()) \\\n                                              + snr * static_cast<size_t>(src.nc()) \\\n                                              + snc;\n\n            if (add_to)\n            {\n                launch_kernel(_cuda_copy_strided_tensor_add_to, max_jobs(dest.size()), \n                              dest_p, src_p, dest.num_samples(),\n                              k, nr, nc,\n                              dest.k(), dest.nr(), dest.nc(),\n                              src.k(), src.nr(), src.nc());\n            }\n            else\n            {\n                launch_kernel(_cuda_copy_strided_tensor, max_jobs(dest.size()), \n                              dest_p, src_p, dest.num_samples(),\n                              k, nr, nc,\n                              dest.k(), dest.nr(), dest.nc(),\n                              src.k(), src.nr(), src.nc());\n            }\n        }\n\n\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_transpose(size_t dsize, size_t dk, size_t dnr, size_t dnc, float* d,\n            size_t sk, size_t snr, int snc, const float* s, const bool add_to)\n        {\n            const auto plane_size = dnr * dnc;\n            const auto sample_size = dk * plane_size;\n            for (auto i : grid_stride_range(0, dsize))\n            {\n                const auto n = i / sample_size;\n                const auto idx = i % plane_size;\n                const auto in_k = (i / plane_size) % dk;\n                const auto in_r = idx % dnc;\n                const auto in_c = idx / dnc;\n\n                const auto in_idx = ((n * sk + in_k) * snr + in_r) * snc + in_c;\n                if (add_to) d[i] += s[in_idx];\n                else d[i] = s[in_idx];\n            }\n        }\n\n        void transpose(\n            bool add_to,\n            tensor& dest,\n            const tensor& src            \n        )\n        {\n            DLIB_CASSERT(is_same_object(dest, src) == false);\n            DLIB_CASSERT(dest.num_samples() == src.num_samples() &&\n                dest.k() == src.k() &&\n                dest.nr() == src.nc() &&\n                dest.nc() == src.nr(),\n                \"Incompatible tensor dimensions.\");\n\n            launch_kernel(_cuda_transpose, max_jobs(dest.size()), dest.size(),\n                dest.k(), dest.nr(), dest.nc(), dest.device(),\n                src.k(), src.nr(), src.nc(), src.device(), add_to);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        // CUDA Kernels for ACT operations\n        __global__ void _cuda_compute_act_halt_probabilities(\n            float* halt_probs,\n            float* logits,\n            const float* input_data,\n            const float* W_halt,\n            float b_halt,\n            size_t batch_size,\n            size_t seq_len,\n            size_t d_model,\n            size_t num_channels,\n            size_t feature_dim\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n\n            for (auto pos : grid_stride_range_y(0, total_positions))\n                for (auto i : grid_stride_range(0, 1))\n                    logits[pos] = b_halt;\n            __syncthreads();\n\n            for (auto pos : grid_stride_range_y(0, total_positions))\n            {\n                const long n = pos / seq_len;\n                const long s = pos % seq_len;\n\n                float temp = 0;\n                for (auto feat_idx : grid_stride_range(0, feature_dim))\n                {\n                    const long c = feat_idx / d_model;\n                    const long d = feat_idx % d_model;\n\n                    const long in_idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                    temp += input_data[in_idx] * W_halt[feat_idx];\n                }\n\n                warp_reduce_atomic_add(logits[pos], temp);\n            }\n            __syncthreads();\n\n            for (auto pos : grid_stride_range(0, total_positions))\n            {\n                halt_probs[pos] = 1.0f / (1.0f + expf(-logits[pos]));\n            }\n        }\n\n        void compute_act_halt_probabilities(\n            resizable_tensor& halt_probs,\n            resizable_tensor& logits,\n            const tensor& input_data,\n            const tensor& halt_params,\n            long batch_size,\n            long seq_len,\n            long feature_dim\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n            const long d_model = feature_dim / input_data.k();\n            const long num_channels = input_data.k();\n\n            halt_probs.set_size(total_positions, 1, 1, 1);\n            logits.set_size(total_positions, 1, 1, 1);\n\n            launch_kernel(_cuda_compute_act_halt_probabilities,\n                max_jobs(feature_dim, total_positions),\n                halt_probs.device(),\n                logits.device(),\n                input_data.device(),\n                halt_params.device(),\n                halt_params.host()[feature_dim],\n                batch_size,\n                seq_len,\n                d_model,\n                num_channels,\n                feature_dim);\n        }\n\n        __global__ void _cuda_update_act_state(\n            float* output,\n            const float* input_data,\n            const float* halt_probs,\n            float* cumulative_halting,\n            float* remainders,\n            float* n_steps,\n            float* effective_weights,\n            size_t batch_size,\n            size_t seq_len,\n            size_t d_model,\n            size_t num_channels,\n            float halt_threshold,\n            long current_step\n        )\n        {\n            for (auto pos : grid_stride_range(0, batch_size * seq_len))\n            {\n                if (cumulative_halting[pos] < halt_threshold)\n                {\n                    const size_t n = pos / seq_len;\n                    const size_t s = pos % seq_len;\n\n                    float p = halt_probs[pos];\n                    float r = remainders[pos];\n                    float effective = fminf(p * r, halt_threshold - cumulative_halting[pos]);\n\n                    cumulative_halting[pos] += effective;\n                    remainders[pos] -= effective;\n                    n_steps[pos] = static_cast<float>(current_step + 1);\n                    effective_weights[pos] += effective;\n\n                    for (size_t c = 0; c < num_channels; ++c) {\n                        for (size_t d = 0; d < d_model; ++d) {\n                            const size_t idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                            output[idx] += effective * input_data[idx];\n                        }\n                    }\n                }\n            }\n        }\n\n        void update_act_state(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& halt_probs,\n            resizable_tensor& cumulative_halting,\n            resizable_tensor& remainders,\n            resizable_tensor& n_steps,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float halt_threshold,\n            long current_step\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n\n            launch_kernel(_cuda_update_act_state,\n                max_jobs(total_positions),\n                output.device(),\n                input_data.device(),\n                halt_probs.device(),\n                cumulative_halting.device(),\n                remainders.device(),\n                n_steps.device(),\n                effective_weights.device(),\n                batch_size,\n                seq_len,\n                d_model,\n                num_channels,\n                halt_threshold,\n                current_step);\n        }\n\n        __global__ void _cuda_finalize_act_output(\n            float* output,\n            const float* input_data,\n            const float* remainders,\n            float* effective_weights,\n            size_t batch_size,\n            size_t seq_len,\n            size_t d_model,\n            size_t num_channels\n        )\n        {\n            for (auto pos : grid_stride_range(0, batch_size * seq_len))\n            {\n                float r = remainders[pos];\n                if (r > 1e-6f) {\n                    const size_t n = pos / seq_len;\n                    const size_t s = pos % seq_len;\n\n                    effective_weights[pos] += r;\n\n                    for (size_t c = 0; c < num_channels; ++c) {\n                        for (size_t d = 0; d < d_model; ++d) {\n                            const size_t idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                            output[idx] += r * input_data[idx];\n                        }\n                    }\n                }\n            }\n        }\n\n        void finalize_act_output(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& remainders,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n\n            launch_kernel(_cuda_finalize_act_output,\n                max_jobs(total_positions),\n                output.device(),\n                input_data.device(),\n                remainders.device(),\n                effective_weights.device(),\n                batch_size,\n                seq_len,\n                d_model,\n                num_channels);\n        }\n\n        __global__ void _cuda_apply_act_depth_scaling(\n            float* gradients,\n            const float* n_steps,\n            size_t batch_size,\n            size_t seq_len,\n            size_t d_model,\n            size_t num_channels,\n            float max_steps,\n            float scale_factor\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n            const long feature_dim = num_channels * d_model;\n\n            for (auto pos : grid_stride_range_y(0, total_positions))\n            {\n                const long n = pos / seq_len;\n                const long s = pos % seq_len;\n                const float scale = 1.0f + scale_factor * (n_steps[pos] / max_steps);\n\n                for (auto feat_idx : grid_stride_range(0, feature_dim))\n                {\n                    const long c = feat_idx / d_model;\n                    const long d = feat_idx % d_model;\n                    const long idx = ((n * num_channels + c) * seq_len + s) * d_model + d;\n                    gradients[idx] *= scale;\n                }\n            }\n        }\n\n        void apply_act_depth_scaling(\n            tensor& gradients,\n            const tensor& n_steps,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float max_steps,\n            float scale_factor\n        )\n        {\n            const long total_positions = batch_size * seq_len;\n            const long feature_dim = num_channels * d_model;\n\n            launch_kernel(_cuda_apply_act_depth_scaling,\n                max_jobs(feature_dim, total_positions),\n                gradients.device(),\n                n_steps.device(),\n                batch_size,\n                seq_len,\n                d_model,\n                num_channels,\n                max_steps,\n                scale_factor);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n\n        __device__ float cuda_log1pexp(float x)\n        {\n            if (x <= -18)\n                return std::exp(x);\n            else if (-18 < x && x <= 9)\n                return std::log1pf(std::exp(x));\n            else if (9 < x && x <= 16)\n                return x + expf(-x);\n            else\n                return x;\n        }\n\n        __global__ void _cuda_compute_loss_binary_log_per_pixel(float* loss_out, float* g, const float* truth, const float* out_data, size_t n, const float scale)\n        {\n            float loss = 0;\n            for(auto i : grid_stride_range(0, n))\n            {\n                const float y = truth[i];\n\n                if (y > 0.f)\n                {\n                    const float temp = cuda_log1pexp(-out_data[i]);\n                    loss += y*temp;\n                    g[i] = y*scale*(g[i]-1);\n                }\n                else if (y < 0.f)\n                {\n                    const float temp = -(-out_data[i]-cuda_log1pexp(-out_data[i]));\n                    loss += -y*temp;\n                    g[i] = -y*scale*g[i];\n                }\n                else\n                {\n                    g[i] = 0.f;\n                }\n            }\n\n            warp_reduce_atomic_add(*loss_out, loss);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        __device__ float cuda_safe_log(float x, float epsilon = 1e-10)\n        {\n            // Prevent trying to calculate the logarithm of a very small number (let alone zero)\n            if (x >= epsilon)\n                return ::log(x);\n            else\n                return ::log(epsilon);\n        }\n\n        __global__ void _cuda_compute_loss_multiclass_log_per_pixel(float* loss_out, float* g, const uint16_t* truth, size_t n, size_t plane_size, size_t sample_size, size_t nk, uint16_t label_to_ignore, const float scale)\n        {\n            float loss = 0;\n            for(auto i : grid_stride_range(0, n))\n            {\n                const size_t k = (i/plane_size)%nk;\n                const size_t idx = (i%plane_size) + plane_size*(i/sample_size);\n\n                const size_t y = truth[idx];\n\n                if (k == y)\n                {\n                    loss -= cuda_safe_log(g[i]);\n                    g[i] = scale*(g[i] - 1);\n                }\n                else if (y == label_to_ignore)\n                {\n                    g[i] = 0.f;\n                }\n                else\n                {\n                    g[i] = scale*g[i];\n                }\n            }\n\n            warp_reduce_atomic_add(*loss_out, loss);\n        }\n\n        __global__ void _cuda_compute_loss_multiclass_log_per_pixel_weighted(float* loss_out, float* g, const uint16_t* truth, size_t n, size_t plane_size, size_t sample_size, size_t nk, const float* weights, const float scale)\n        {\n            float loss = 0;\n            for(auto i : grid_stride_range(0, n))\n            {\n                const size_t k = (i/plane_size)%nk;\n                const size_t idx = (i%plane_size) + plane_size*(i/sample_size);\n\n                const size_t y = truth[idx];\n                const float weight = weights[idx];\n\n                if (k == y)\n                {\n                    loss -= weight*cuda_safe_log(g[i]);\n                    g[i] = weight*scale*(g[i] - 1);\n                }\n                else\n                {\n                    g[i] = weight*scale*g[i];\n                }\n            }\n\n            warp_reduce_atomic_add(*loss_out, loss);\n        }\n    // ----------------------------------------------------------------------------------------\n\n        __global__ void _cuda_compute_loss_mean_squared_per_channel_and_pixel(float* loss_out, float* g, const float* truth, const float* out_data, size_t n, const float scale)\n        {\n            float loss = 0;\n            for (auto i : grid_stride_range(0, n))\n            {\n                const float y = truth[i];\n                const float temp = y - out_data[i];\n                loss += temp * temp;\n                g[i] = -temp * scale;\n            }\n            warp_reduce_atomic_add(*loss_out, loss);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void compute_loss_binary_log_per_pixel::\n        do_work(\n            cuda_data_ptr<float> loss_work_buffer,\n            cuda_data_ptr<const float> truth_buffer,\n            const tensor& subnetwork_output,\n            tensor& gradient,\n            double& loss\n        )\n        {\n            CHECK_CUDA(cudaMemset(loss_work_buffer, 0, sizeof(float)));\n            sigmoid(gradient, subnetwork_output);\n\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (subnetwork_output.num_samples() * subnetwork_output.nr() * subnetwork_output.nc());\n\n            launch_kernel(_cuda_compute_loss_binary_log_per_pixel, max_jobs(gradient.size()),\n                loss_work_buffer.data(), gradient.device(), truth_buffer.data(), subnetwork_output.device(), gradient.size(), scale);\n\n            float floss;\n            dlib::cuda::memcpy(&floss, loss_work_buffer);\n            loss = scale*floss;\n        }\n\n        void compute_loss_multiclass_log_per_pixel::\n        do_work(\n            cuda_data_ptr<float> loss_work_buffer,\n            cuda_data_ptr<const uint16_t> truth_buffer,\n            const tensor& subnetwork_output,\n            tensor& gradient,\n            double& loss\n        )\n        {\n            CHECK_CUDA(cudaMemset(loss_work_buffer, 0, sizeof(float)));\n            softmax(gradient, subnetwork_output);\n            static const uint16_t label_to_ignore = std::numeric_limits<uint16_t>::max();\n\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (subnetwork_output.num_samples() * subnetwork_output.nr() * subnetwork_output.nc());\n\n            launch_kernel(_cuda_compute_loss_multiclass_log_per_pixel, max_jobs(gradient.size()),\n                loss_work_buffer.data(), gradient.device(), truth_buffer.data(), gradient.size(), gradient.nr()*gradient.nc(), gradient.nr()*gradient.nc()*gradient.k(), gradient.k(), label_to_ignore, scale);\n\n            float floss;\n            dlib::cuda::memcpy(&floss, loss_work_buffer);\n            loss = scale*floss;\n        }\n\n        void compute_loss_multiclass_log_per_pixel_weighted::\n        do_work(\n            cuda_data_ptr<float> loss_work_buffer,\n            cuda_data_ptr<const uint16_t> truth_buffer,\n            cuda_data_ptr<const float> weights_buffer,\n            const tensor& subnetwork_output,\n            tensor& gradient,\n            double& loss\n        )\n        {\n            CHECK_CUDA(cudaMemset(loss_work_buffer, 0, sizeof(float)));\n            softmax(gradient, subnetwork_output);\n\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (subnetwork_output.num_samples() * subnetwork_output.nr() * subnetwork_output.nc());\n\n            launch_kernel(_cuda_compute_loss_multiclass_log_per_pixel_weighted, max_jobs(gradient.size()),\n                loss_work_buffer.data(), gradient.device(), truth_buffer.data(), gradient.size(), gradient.nr()*gradient.nc(), gradient.nr()*gradient.nc()*gradient.k(), gradient.k(), weights_buffer.data(), scale);\n\n            float floss;\n            dlib::cuda::memcpy(&floss, loss_work_buffer);\n            loss = scale*floss;\n        }\n\n        void compute_loss_mean_squared_per_channel_and_pixel::\n        do_work(\n            cuda_data_ptr<float> loss_work_buffer,\n            cuda_data_ptr<const float> truth_buffer,\n            const tensor& subnetwork_output,\n            tensor& gradient,\n            double& loss\n        )\n        {\n            CHECK_CUDA(cudaMemset(loss_work_buffer, 0, sizeof(float)));\n\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (subnetwork_output.num_samples() * subnetwork_output.k() * subnetwork_output.nr() * subnetwork_output.nc());\n\n            launch_kernel(_cuda_compute_loss_mean_squared_per_channel_and_pixel , max_jobs(gradient.size()),\n                loss_work_buffer.data(), gradient.device(), truth_buffer.data(), subnetwork_output.device(), gradient.size(), scale);\n\n            float floss;\n            dlib::cuda::memcpy(&floss, loss_work_buffer);\n            loss = scale*floss;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n    }\n}\n\n"
  },
  {
    "path": "dlib/cuda/cuda_dlib.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuDA_H_\n#define DLIB_DNN_CuDA_H_\n\n\n#include \"tensor.h\"\n#include \"../geometry/rectangle.h\"\n#include \"../dnn/utilities.h\"\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // ----------------------------------------------------------------------------------------\n\n        void set_device (\n            int dev\n        );\n\n        int get_device (\n        );\n\n        int get_num_devices (\n        );\n\n        std::string get_device_name (\n            int device\n        );\n\n        void set_current_device_blocking_sync(\n        );\n\n        bool can_access_peer (int device_id, int peer_device_id);\n        bool can_access_peer (const tensor& device, const tensor& peer_device);\n\n        void device_synchronize (int dev);\n        void device_synchronize (const tensor& dev);\n\n\n        class raii_set_device\n        {\n        public:\n            raii_set_device() = delete;\n            raii_set_device(const raii_set_device&) = delete;\n            raii_set_device& operator=(const raii_set_device&) = delete;\n\n            raii_set_device(int dev)\n            {\n                prev_dev = get_device();\n                set_device(dev);\n            }\n\n            raii_set_device(const tensor& dev)\n            {\n                prev_dev = get_device();\n                set_device(dev.device_id());\n            }\n\n            void operator() (int dev)\n            {\n                set_device(dev);\n            }\n\n            void operator() (const tensor& dev)\n            {\n                set_device(dev.device_id());\n            }\n\n            ~raii_set_device() noexcept(false)\n            {\n                set_device(prev_dev);\n            }\n\n        private:\n            int prev_dev;\n        };\n\n\n#ifdef DLIB_USE_CUDA\n\n        class enable_peer_access\n        {\n        public:\n\n            enable_peer_access() = delete;\n            enable_peer_access(const enable_peer_access&) = delete;\n            enable_peer_access& operator=(const enable_peer_access&) = delete;\n\n            enable_peer_access(\n                int device_id,\n                int peer_device_id\n            );\n\n            enable_peer_access(\n                const tensor& device,\n                const tensor& peer_device\n            ) : enable_peer_access(device.device_id(), peer_device.device_id())\n            {}\n\n            ~enable_peer_access() noexcept(false);\n\n        private:\n\n            bool call_disable;\n            int device_id;\n            int peer_device_id;\n        };\n\n    // -----------------------------------------------------------------------------------\n\n        void inverse_norms (\n            resizable_tensor& invnorms,\n            const tensor& data,\n            const double eps\n        );\n\n        void dot_prods (\n            resizable_tensor& out,\n            const tensor& lhs,\n            const tensor& rhs\n        );\n\n        void dot_prods (\n            bool add_to,\n            tensor& out,\n            const tensor& lhs,\n            const tensor& rhs\n        );\n\n        void scale_columns (\n            tensor& out,\n            const tensor& m,\n            const tensor& v\n        );\n\n        void scale_rows (\n            tensor& out,\n            const tensor& m,\n            const tensor& v\n        );\n\n        void scale_rows2 (\n            float beta, \n            tensor& out,\n            const tensor& m1,\n            const tensor& m2,\n            const tensor& v1,\n            const tensor& v2\n        );\n\n        void exp (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void log (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void log10 (\n            tensor& dest,\n            const tensor& src\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void set_tensor (\n            tensor& t,\n            float value\n        );\n\n        void scale_tensor (\n            tensor& t,\n            float value\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void multiply (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void multiply_conv (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void multiply_zero_padded (\n            bool add_to,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n        void scale_channels (\n            bool add_to,\n            tensor& dest,\n            const tensor& src,\n            const tensor& scales\n        );\n\n        void add (\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A,\n            const float B\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const float A\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B,\n            const float C\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const float A,\n            const float B\n        );\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C,\n            const float D\n        );\n\n        void affine_transform_range(\n            size_t begin,\n            size_t end,\n            tensor& dest,\n            const tensor& src1,\n            const tensor& src2,\n            const tensor& src3,\n            const float A,\n            const float B,\n            const float C\n        );\n\n        void affine_transform(\n            const rectangle& rect,\n            tensor& dest, \n            const tensor& src1, \n            const tensor& src2, \n            const tensor& src3, \n            float A, \n            float B,\n            float C\n        );\n\n        // Note that this function isn't in the tt:: namespace because add_scaled() is\n        // called by cuda::add() so we don't need a tt:: version of add_scaled().  \n        void add_scaled(\n            tensor& dest,\n            const float scale,\n            const tensor& src\n        );\n\n        void add_cv_to_all_columns(\n            float beta, \n            tensor& dest, \n            float alpha, \n            const tensor& src\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void affine_transform_conv(\n            tensor& dest,\n            const tensor& src,\n            const tensor& A,\n            const tensor& B\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void compute_adam_update (\n            size_t begin,\n            size_t end,\n            tensor& s,\n            tensor& m,\n            tensor& v,\n            const float t,\n            const float learning_rate,\n            const float weight_decay,\n            const float momentum1,\n            const float momentum2,\n            const tensor& params,\n            const tensor& params_grad\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void assign_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void layer_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            const tensor& beta\n        );\n\n        void layer_normalize_gradient (\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n        );\n\n   // -----------------------------------------------------------------------------------\n\n        void rms_normalize(\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& scale,\n            const tensor& src,\n            const tensor& gamma\n        );\n\n        void rms_normalize_gradient(\n            const tensor& gradient_input,\n            const tensor& scale,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            resizable_tensor& dscale\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void threshold (\n            tensor& data,\n            float thresh\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void dot (\n            const tensor& a,\n            const tensor& b,\n            tensor& result,\n            size_t idx\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void prelu (\n            tensor& dest,\n            const tensor& src,\n            const tensor& param\n        );\n\n        void prelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const tensor& param,\n            tensor& params_grad \n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void leaky_relu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        );\n\n        void leaky_relu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input,\n            const float alpha\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void mish (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void mish_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void clipped_relu (\n            tensor& dest,\n            const tensor& src,\n            const float coef\n        );\n\n        void clipped_relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float ceiling\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void elu (\n            tensor& dest,\n            const tensor& src,\n            const float alpha\n        );\n\n        void elu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float alpha\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void gelu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void gelu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void smelu (\n            tensor& dest,\n            const tensor& src,\n            const float beta\n        );\n\n        void smelu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            const float beta\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void silu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void silu_gradient (\n            tensor& grad,\n            const tensor& src,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void resize_bilinear (\n            tensor& dest,\n            long long dest_row_stride,\n            long long dest_channel_stride,\n            const tensor& src,\n            long long src_row_stride,\n            long long src_channel_stride\n        );\n\n        void resize_bilinear_gradient (\n            tensor& grad,\n            long long grad_row_stride,\n            long long grad_channel_stride,\n            const tensor& gradient_input,\n            long long gradient_input_row_stride,\n            long long gradient_input_channel_stride\n        );\n\n        inline void resize_bilinear (\n            tensor& dest,\n            const tensor& src\n        ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); }\n\n        inline void resize_bilinear_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); }\n\n    // ----------------------------------------------------------------------------------------\n\n        void reorg (\n            bool add_to,\n            tensor& dest,\n            const int row_stride,\n            const int col_stride,\n            const tensor& src\n        );\n\n        void reorg_gradient (\n            bool add_to,\n            tensor& grad,\n            const int row_stride,\n            const int col_stride,\n            const tensor& gradient_input\n        );\n\n    // -----------------------------------------------------------------------------------\n\n        void embeddings(\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& embs\n        );\n\n        void embeddings_gradient(\n            const tensor& prev,\n            const tensor& gradient_input,\n            tensor& grads,\n            const tensor& freqs,\n            float learning_rate,\n            bool scale\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dk, size_t dnr, size_t dnc,\n            const tensor& src,\n            size_t sk, size_t snr, size_t snc,\n            size_t k, size_t nr, size_t nc\n        );\n \n    // ----------------------------------------------------------------------------------------\n\n        void transpose(\n            bool add_to,\n            tensor& dest,\n            const tensor& src\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        void compute_act_halt_probabilities(\n            resizable_tensor& halt_probs,\n            resizable_tensor& logits,\n            const tensor& input_data,\n            const tensor& halt_params,\n            long batch_size,\n            long seq_len,\n            long feature_dim\n        );\n\n        void update_act_state(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& halt_probs,\n            resizable_tensor& cumulative_halting,\n            resizable_tensor& remainders,\n            resizable_tensor& n_steps,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float halt_threshold,\n            long current_step\n        );\n\n        void finalize_act_output(\n            resizable_tensor& output,\n            const tensor& input_data,\n            const tensor& remainders,\n            resizable_tensor& effective_weights,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels\n        );\n\n        void apply_act_depth_scaling(\n            tensor& gradients,\n            const tensor& n_steps,\n            long batch_size,\n            long seq_len,\n            long d_model,\n            long num_channels,\n            float max_steps,\n            float scale_factor\n        );\n\n    // ----------------------------------------------------------------------------------------\n\n        class compute_loss_binary_log_per_pixel\n        {\n            /*!\n                The point of this class is to compute the loss computed by\n                loss_binary_log_per_pixel_, but to do so with CUDA.\n            !*/\n        public:\n\n            compute_loss_binary_log_per_pixel(\n            )\n            {\n            }\n\n            template <\n                typename const_label_iterator\n                >\n            void operator() (\n                const_label_iterator truth,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            ) const\n            {\n                const auto image_size = subnetwork_output.nr()*subnetwork_output.nc();\n                const size_t bytes_per_plane = image_size*sizeof(float);\n                // Allocate a cuda buffer to store all the truth images and also one float\n                // for the scalar loss output.\n                buf = device_global_buffer(subnetwork_output.num_samples()*bytes_per_plane + sizeof(float));\n\n                cuda_data_ptr<float> loss_buf = static_pointer_cast<float>(buf, 1);\n                buf = buf+sizeof(float);\n\n                // copy the truth data into a cuda buffer.\n                for (long i = 0; i < subnetwork_output.num_samples(); ++i, ++truth)\n                {\n                    const matrix<float>& t = *truth;\n                    DLIB_ASSERT(t.nr() == subnetwork_output.nr());\n                    DLIB_ASSERT(t.nc() == subnetwork_output.nc());\n                    memcpy(buf + i*bytes_per_plane, &t(0,0), bytes_per_plane);\n                }\n\n                auto truth_buf = static_pointer_cast<const float>(buf, subnetwork_output.num_samples()*image_size);\n\n                do_work(loss_buf, truth_buf, subnetwork_output, gradient, loss);\n            }\n\n        private:\n\n            static void do_work(\n                cuda_data_ptr<float> loss_work_buffer,\n                cuda_data_ptr<const float> truth_buffer,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            );\n\n            mutable cuda_data_void_ptr buf;\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        class compute_loss_multiclass_log_per_pixel\n        {\n            /*!\n                The point of this class is to compute the loss computed by\n                loss_multiclass_log_per_pixel_, but to do so with CUDA.\n            !*/\n        public:\n\n            compute_loss_multiclass_log_per_pixel(\n            )\n            {\n            }\n\n            template <\n                typename const_label_iterator\n                >\n            void operator() (\n                const_label_iterator truth,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            ) const\n            {\n                const auto image_size = subnetwork_output.nr()*subnetwork_output.nc();\n                const size_t bytes_per_plane = image_size*sizeof(uint16_t);\n                // Allocate a cuda buffer to store all the truth images and also one float\n                // for the scalar loss output.\n                buf = device_global_buffer(subnetwork_output.num_samples()*bytes_per_plane + sizeof(float));\n\n                cuda_data_ptr<float> loss_buf = static_pointer_cast<float>(buf, 1);\n                buf = buf+sizeof(float);\n\n                // copy the truth data into a cuda buffer.\n                for (long i = 0; i < subnetwork_output.num_samples(); ++i, ++truth)\n                {\n                    const matrix<uint16_t>& t = *truth;\n                    DLIB_ASSERT(t.nr() == subnetwork_output.nr());\n                    DLIB_ASSERT(t.nc() == subnetwork_output.nc());\n                    memcpy(buf + i*bytes_per_plane, &t(0,0), bytes_per_plane);\n                }\n\n                auto truth_buf = static_pointer_cast<const uint16_t>(buf, subnetwork_output.num_samples()*image_size);\n\n                do_work(loss_buf, truth_buf, subnetwork_output, gradient, loss);\n            }\n\n        private:\n\n            static void do_work(\n                cuda_data_ptr<float> loss_work_buffer,\n                cuda_data_ptr<const uint16_t> truth_buffer,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            );\n            \n            mutable cuda_data_void_ptr buf;\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        class compute_loss_multiclass_log_per_pixel_weighted\n        {\n            /*!\n                The point of this class is to compute the loss computed by\n                loss_multiclass_log_per_pixel_weighted_, but to do so with CUDA.\n            !*/\n        public:\n\n            compute_loss_multiclass_log_per_pixel_weighted(\n            )\n            {\n            }\n\n            template <\n                typename const_label_iterator\n                >\n            void operator() (\n                const_label_iterator truth,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            ) const\n            {\n                const auto image_size = subnetwork_output.nr()*subnetwork_output.nc();\n                const size_t bytes_per_plane = image_size*sizeof(uint16_t);\n                const size_t weight_bytes_per_plane = image_size*sizeof(float);\n                matrix<uint16_t> labels(truth->nr(), truth->nc());\n                matrix<float> weights(truth->nr(), truth->nc());\n                // Allocate a cuda buffer to store all the truth images and also one float\n                // for the scalar loss output.\n                buf = device_global_buffer(subnetwork_output.num_samples()*(bytes_per_plane + weight_bytes_per_plane) + sizeof(float));\n\n                cuda_data_ptr<float> loss_buf = static_pointer_cast<float>(buf, 1);\n                buf = buf+sizeof(float);\n                const auto truth_offset = subnetwork_output.num_samples() * weight_bytes_per_plane;\n                // copy the truth data into a cuda buffer.\n                for (long i = 0; i < subnetwork_output.num_samples(); ++i, ++truth)\n                {\n                    const matrix<weighted_label<uint16_t>>& t = *truth;\n                    DLIB_ASSERT(t.nr() == subnetwork_output.nr());\n                    DLIB_ASSERT(t.nc() == subnetwork_output.nc());\n                    for (long r = 0; r < t.nr(); ++r)\n                    {\n                        for (long c = 0; c < t.nc(); ++c)\n                        {\n                            labels(r, c) = t(r, c).label;\n                            weights(r, c) = t(r, c).weight;\n                        }\n                    }\n                    memcpy(buf + truth_offset + i*bytes_per_plane, &labels(0,0), bytes_per_plane);\n                    memcpy(buf + i*weight_bytes_per_plane, &weights(0, 0), weight_bytes_per_plane);\n                }\n\n                auto weights_buf = static_pointer_cast<const float>(buf, subnetwork_output.num_samples()*image_size);\n                buf = buf+truth_offset;\n                auto truth_buf = static_pointer_cast<const uint16_t>(buf, subnetwork_output.num_samples()*image_size);\n\n                do_work(loss_buf, truth_buf, weights_buf, subnetwork_output, gradient, loss);\n            }\n\n        private:\n\n            static void do_work(\n                cuda_data_ptr<float> loss_work_buffer,\n                cuda_data_ptr<const uint16_t> truth_buffer,\n                cuda_data_ptr<const float> weights_buffer,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            );\n\n            mutable cuda_data_void_ptr buf;\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        class compute_loss_mean_squared_per_channel_and_pixel\n        {\n            /*!\n                The point of this class is to compute the loss computed by\n                loss_mean_squared_per_channel_and_pixel_, but to do so with CUDA.\n            !*/\n        public:\n\n            compute_loss_mean_squared_per_channel_and_pixel(\n            )\n            {\n            }\n\n            template <\n                typename const_label_iterator\n                >\n            void operator() (\n                const_label_iterator truth,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            ) const\n            {\n                const auto image_size = subnetwork_output.nr()*subnetwork_output.nc()*subnetwork_output.k();\n                const size_t bytes_per_image = image_size*sizeof(float);\n                // Allocate a cuda buffer to store all the truth images and also one float\n                // for the scalar loss output.\n                buf = device_global_buffer(subnetwork_output.num_samples()*bytes_per_image + sizeof(float));\n\n                cuda_data_ptr<float> loss_buf = static_pointer_cast<float>(buf, 1);\n                buf = buf+sizeof(float);\n\n                const size_t bytes_per_plane = subnetwork_output.nr()*subnetwork_output.nc()*sizeof(float);\n\n                // copy the truth data into a cuda buffer.\n                for (long i = 0; i < subnetwork_output.num_samples(); ++i, ++truth)\n                {\n                    const auto& t = *truth;\n                    DLIB_ASSERT(static_cast<long>(t.size()) == subnetwork_output.k());\n                    for (size_t j = 0; j < t.size(); ++j) {\n                        DLIB_ASSERT(t[j].nr() == subnetwork_output.nr());\n                        DLIB_ASSERT(t[j].nc() == subnetwork_output.nc());\n                        memcpy(buf + i*bytes_per_image + j*bytes_per_plane, &t[j](0,0), bytes_per_plane);\n                    }\n                }\n\n                auto truth_buf = static_pointer_cast<const float>(buf, subnetwork_output.num_samples()*image_size);\n\n                do_work(loss_buf, truth_buf, subnetwork_output, gradient, loss);\n            }\n\n        private:\n\n            static void do_work(\n                cuda_data_ptr<float> loss_work_buffer,\n                cuda_data_ptr<const float> truth_buffer,\n                const tensor& subnetwork_output,\n                tensor& gradient,\n                double& loss\n            );\n\n            mutable cuda_data_void_ptr buf;\n        };\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n#else // if DLIB_USE_CUDA NOT DEFINED\n\n        inline void set_device (\n            int id\n        )\n        {\n            DLIB_CASSERT(id == 0, \"dlib::cuda::set_device(id) called with an invalid device id.\");\n        }\n\n        inline int get_device (\n        ){ return 0; }\n\n        inline int get_num_devices (\n        ) { return 1; }\n\n        inline std::string get_device_name (\n            int device\n        ) \n        {\n            DLIB_CASSERT(device == 0, \"dlib::cuda::set_device(id) called with an invalid device id.\");\n            return \"CUDA_DISABLED\";\n        }\n\n        inline void set_current_device_blocking_sync(\n        ) {}\n\n\n        inline bool can_access_peer (int , int )\n        { return false; }\n        inline bool can_access_peer (const tensor& , const tensor& )\n        { return false; }\n\n        inline void device_synchronize (int ){}\n        inline void device_synchronize (const tensor& ){}\n\n        class enable_peer_access\n        {\n        public:\n            enable_peer_access() = delete;\n            enable_peer_access(const enable_peer_access&) = delete;\n            enable_peer_access& operator=(const enable_peer_access&) = delete;\n            enable_peer_access( int, int ){}\n            enable_peer_access( const tensor&, const tensor& ) {}\n        };\n\n#endif // DLIB_USE_CUDA\n\n    } \n}\n\n\n#endif // DLIB_DNN_CuDA_H_\n\n"
  },
  {
    "path": "dlib/cuda/cuda_errors.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CUDA_ERRORs_H_\n#define DLIB_CUDA_ERRORs_H_\n\n\n#include \"../error.h\"\n\nnamespace dlib\n{\n    struct cuda_error : public error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown if any calls to the NVIDIA CUDA runtime\n                returns an error.  \n        !*/\n\n        cuda_error(const std::string& message): error(message) {}\n    };\n\n\n    struct cudnn_error : public cuda_error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown if any calls to the NVIDIA cuDNN library\n                returns an error.  \n        !*/\n\n        cudnn_error(const std::string& message): cuda_error(message) {}\n    };\n\n    struct curand_error : public cuda_error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown if any calls to the NVIDIA cuRAND library\n                returns an error.  \n        !*/\n\n        curand_error(const std::string& message): cuda_error(message) {}\n    };\n\n    struct cublas_error : public cuda_error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown if any calls to the NVIDIA cuBLAS library\n                returns an error.  \n        !*/\n\n        cublas_error(const std::string& message): cuda_error(message) {}\n    };\n\n    struct cusolver_error : public cuda_error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown if any calls to the NVIDIA cuSolver library\n                returns an error.  \n        !*/\n\n        cusolver_error(const std::string& message): cuda_error(message) {}\n    };\n}\n\n\n#endif // DLIB_CUDA_ERRORs_H_\n\n"
  },
  {
    "path": "dlib/cuda/cuda_utils.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CUDA_UtILS_H_\n#define DLIB_CUDA_UtILS_H_\n\n#include \"../algs.h\"\n\n#ifndef DLIB_USE_CUDA\n#error \"This file shouldn't be #included unless DLIB_USE_CUDA is #defined\"\n#endif\n\n#include \"cuda_errors.h\"\n#include <cmath>\n\n#include <cuda_runtime.h>\n#include <sstream>\n#include <iostream>\n#include <memory>\n#include <vector>\n#include <type_traits>\n\n\n// Check the return value of a call to the CUDA runtime for an error condition.\n#define CHECK_CUDA(call)                                                       \\\ndo{                                                                              \\\n    const cudaError_t error = call;                                            \\\n    if (error != cudaSuccess)                                                  \\\n    {                                                                          \\\n        std::ostringstream sout;                                               \\\n        sout << \"Error while calling \" << #call << \" in file \" << __FILE__ << \":\" << __LINE__ << \". \";\\\n        sout << \"code: \" << cudaGetLastError() << \", reason: \" << cudaGetErrorString(error);\\\n        throw dlib::cuda_error(sout.str());                                          \\\n    }                                                                          \\\n}while(false)\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef __CUDACC__\n\nnamespace dlib\n{\n    namespace cuda\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        __inline__ __device__ size_t pack_idx (\n            size_t dim_size3,\n            size_t dim_size2,\n            size_t dim_size1,\n            size_t idx4,\n            size_t idx3,\n            size_t idx2,\n            size_t idx1\n        )\n        /*!\n            ensures\n                - Converts a 4D array index into a 1D index assuming row major layout.  To\n                  understand precisely what this function does, imagine we had an array\n                  declared like this:\n                    int ARRAY[anything][dim_size3][dim_size2][dim_size1];\n                  Then we could index it like this:\n                    ARRAY[idx4][idx3][idx2][idx1]\n                  or equivalently like this:\n                    ((int*)ARRAY)[pack_idx(dim_size3,dim_size2,dim_size1, idx4,idx3,idx2,idx1)]\n        !*/\n        {\n            return ((idx4*dim_size3 + idx3)*dim_size2 + idx2)*dim_size1 + idx1;\n        }\n\n        __inline__ __device__ void unpack_idx (\n            size_t idx,\n            size_t dim_size3,\n            size_t dim_size2,\n            size_t dim_size1,\n            size_t& idx4,\n            size_t& idx3,\n            size_t& idx2,\n            size_t& idx1\n        )\n        /*!\n            ensures\n                - This function computes the inverse of pack_idx().  Therefore, \n                  if PACKED == pack_idx(dim_size3,dim_size2,dim_size1, idx4,idx3,idx2,idx1)\n                  then unpack_idx(PACKED,dim_size3,dim_size2,dim_size1, IDX4,IDX3,IDX2,IDX1)\n                  results in:\n                    - IDX1 == idx1\n                    - IDX2 == idx2\n                    - IDX3 == idx3\n                    - IDX4 == idx4\n        !*/\n        {\n            idx1 = idx%dim_size1;\n\n            idx /= dim_size1;\n            idx2 = idx%dim_size2;\n\n            idx /= dim_size2;\n            idx3 = idx%dim_size3;\n\n            idx /= dim_size3;\n            idx4 = idx;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        // This function is from the article:\n        // http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/\n        __inline__ __device__ float warp_reduce_sum(float val) \n        {\n            for (int offset = warpSize/2; offset > 0; offset /= 2) \n#if CUDART_VERSION >= 9000\n                val += __shfl_down_sync(0xFFFFFFFF,val, offset);\n#else\n                val += __shfl_down(val, offset);\n#endif\n            return val;\n        }\n\n        __inline__ __device__ bool is_first_thread_in_warp()\n        {\n            return (threadIdx.x & (warpSize - 1)) == 0;\n        }\n\n        __inline__ __device__ void warp_reduce_atomic_add(\n            float& out, \n            float val\n        ) \n        /*!\n            ensures\n                - Atomically adds all the val variables in the current warp to out.\n                  See this page for an extended discussion: \n                  http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/\n        !*/\n        {\n            val = warp_reduce_sum(val);\n            if (is_first_thread_in_warp())\n                atomicAdd(&out, val);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        struct max_jobs\n        {\n            max_jobs(int x) : num_x(x) {}\n            max_jobs(int x, int y) : num_x(x), num_y(y) {}\n            int num_x;\n            int num_y = 1;\n        };\n\n        template <typename Kernel, typename... T>\n        void launch_kernel (\n            Kernel K,\n            T ...args\n        )\n        /*!\n            ensures\n                - launches the given kernel K(args...).  The point of this function is to\n                  automatically set the kernel launch parameters to something reasonable\n                  based on the properties of the kernel and the current GPU card.\n        !*/\n        {\n            int num_blocks, num_threads;\n            CHECK_CUDA(cudaOccupancyMaxPotentialBlockSize(&num_blocks,&num_threads,K));\n            K<<<num_blocks,num_threads>>>(args...);\n        }\n\n        template <typename Kernel, typename... T>\n        void launch_kernel (\n            Kernel K,\n            max_jobs m,\n            T ...args\n        )\n        /*!\n            ensures\n                - This function is just like launch_kernel(K,args...) except that you can\n                  additionally supply a max_jobs number that tells it how many possible\n                  total threads could be used.  This is useful when launching potentially\n                  small jobs that might not need the number of threads suggested by\n                  launch_kernel().  \n        !*/\n        {\n            if (m.num_x == 0 || m.num_y == 0)\n                return;\n            int num_blocks, num_threads;\n            CHECK_CUDA(cudaOccupancyMaxPotentialBlockSize(&num_blocks,&num_threads,K));\n            // Check if the job is really small and we don't really need to launch a kernel\n            // with this many blocks and threads.\n            if (num_blocks*num_threads > m.num_x*m.num_y)\n                num_blocks = (m.num_x*m.num_y+num_threads-1)/num_threads;\n\n            if (m.num_y == 1)\n            {\n                K<<<num_blocks,num_threads>>>(args...);\n            }\n            else\n            {\n                /*\n                    In general, the reason m.num_y!=1 (i.e. the reason you are in this\n                    code path) is because we are using nested grid-stride loops.  There are\n                    two important things to note about what we are doing here.  To\n                    illustrate them we will talk about this little CUDA code snippet:\n\n                        // initialize out before we begin.\n                        for (auto i : grid_stride_range_y(0, nr))\n                            for (auto j : grid_stride_range(0, 1))\n                                out[i] = 0;\n\n                        __syncthreads(); // synchronize threads in block\n\n                        // loop over some 2D thing and sum and store things into out.\n                        for (auto i : grid_stride_range_y(0, nr))\n                        {\n                            float temp = 0;\n                            for (auto j : grid_stride_range(0, nc))\n                                temp += whatever[i*nc+j];\n\n                            // store the sum into out[i]\n                            warp_reduce_atomic_add(out[i], temp);\n                        }\n                    \n                    First, we make sure the number of x threads is a multiple of 32 so that\n                    you can use warp_reduce_atomic_add() inside the y loop.  \n                    \n                    Second, we put the x block size to 1 so inter-block synchronization is\n                    easier.  For example, if the number of x blocks wasn't 1 the above code\n                    would have a race condition in it.  This is because the execution of\n                    out[i]=0 would be done by blocks with blockIdx.x==0, but then in the\n                    second set of loops, *all* the x blocks use out[i].  Since\n                    __syncthreads() doesn't do any synchronization between blocks some of\n                    the blocks might begin before the out[i]=0 statements finished and that\n                    would be super bad.\n                */\n                \n                // Try and make sure that the ratio of x to y threads is reasonable based\n                // on the respective size of our loops.\n                int x_threads = 32;\n                int y_threads = num_threads/32;\n                const int ratio = static_cast<int>(std::round(put_in_range(1, y_threads, m.num_x/(double)m.num_y)));\n                x_threads *= ratio;\n                y_threads /= ratio;\n\n                dim3 blocks(1,num_blocks);  \n                dim3 threads(x_threads,y_threads); \n                K<<<blocks,threads>>>(args...);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        class grid_stride_range\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a tool for making a for loop that loops over an entire block of\n                    memory inside a kernel, but doing so in a way that parallelizes\n                    appropriately across all the threads in a kernel launch.  For example,\n                    the following kernel would add the vector a to the vector b and store\n                    the output in out (assuming all vectors are of dimension n):\n                        __global__ void add_arrays(\n                            const float* a, \n                            const float* b, \n                            float* out, \n                            size_t n\n                        )\n                        {\n                            for (auto i : grid_stride_range(0, n))\n                            {\n                                out[i] = a[i]+b[i];\n                            }\n                        }\n            !*/\n\n        public:\n            __device__ grid_stride_range(\n                size_t ibegin_,\n                size_t iend_\n            ) : \n                ibegin(ibegin_),\n                iend(iend_)\n            {}\n\n            class iterator\n            {\n            public:\n                __device__ iterator() {}\n                __device__ iterator(size_t pos_) : pos(pos_) {}\n\n                __device__ size_t operator*() const\n                {\n                    return pos;\n                }\n\n                __device__ iterator& operator++()\n                {\n                    pos += gridDim.x * blockDim.x;\n                    return *this;\n                }\n\n                __device__ bool operator!=(const iterator& item) const\n                { return pos < item.pos; }\n\n            private:\n                size_t pos;\n            };\n\n            __device__ iterator begin() const\n            {\n                return iterator(ibegin+blockDim.x * blockIdx.x + threadIdx.x);\n            }\n            __device__ iterator end() const\n            {\n                return iterator(iend);\n            }\n        private:\n\n            size_t ibegin;\n            size_t iend;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        class grid_stride_range_y\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is just like grid_stride_range except that it looks at\n                    CUDA's y thread index (e.g. threadIdx.y) instead of the x index.\n                    Therefore, if you launch a cuda kernel with a statement like:\n                        dim3 blocks(1,10);\n                        dim3 threads(32,32);  // You need to have x and y not equal to 1 to get parallelism over both loops.\n                        add_arrays<<<blocks,threads>>>(a,b,out,nr,nc);\n                    You can perform a nested 2D parallel for loop rather than doing just a\n                    1D for loop.\n                   \n                    So the code in the kernel would look like this if you wanted to add two\n                    2D matrices:\n                        __global__ void add_arrays(\n                            const float* a, \n                            const float* b, \n                            float* out, \n                            size_t nr,\n                            size_t nc\n                        )\n                        {\n                            for (auto r : grid_stride_range_y(0, nr))\n                            {\n                                for (auto c : grid_stride_range(0, nc))\n                                {\n                                    auto i = r*nc+c;\n                                    out[i] = a[i]+b[i];\n                                }\n                            }\n                        }\n            !*/\n\n        public:\n            __device__ grid_stride_range_y(\n                size_t ibegin_,\n                size_t iend_\n            ) : \n                ibegin(ibegin_),\n                iend(iend_)\n            {}\n\n            class iterator\n            {\n            public:\n                __device__ iterator() {}\n                __device__ iterator(size_t pos_) : pos(pos_) {}\n\n                __device__ size_t operator*() const\n                {\n                    return pos;\n                }\n\n                __device__ iterator& operator++()\n                {\n                    pos += gridDim.y * blockDim.y;\n                    return *this;\n                }\n\n                __device__ bool operator!=(const iterator& item) const\n                { return pos < item.pos; }\n\n            private:\n                size_t pos;\n            };\n\n            __device__ iterator begin() const\n            {\n                return iterator(ibegin+blockDim.y * blockIdx.y + threadIdx.y);\n            }\n            __device__ iterator end() const\n            {\n                return iterator(iend);\n            }\n        private:\n\n            size_t ibegin;\n            size_t iend;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif // __CUDACC__\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_CUDA_UtILS_H_\n\n"
  },
  {
    "path": "dlib/cuda/cudnn_dlibapi.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuDNN_CPP_\n#define DLIB_DNN_CuDNN_CPP_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"cudnn_dlibapi.h\"\n#include \"tensor.h\"\n#include <cudnn.h>\n#include <tuple>\n#include <map>\n#include <iostream>\n#include <string>\n#include <vector>\n#include \"cuda_utils.h\"\n#include \"cpu_dlib.h\"\n#include \"cuda_dlib.h\"\n#include \"tensor_tools.h\"\n\nstatic const char* cudnn_get_error_string(cudnnStatus_t s)\n{\n    switch(s)\n    {\n        case CUDNN_STATUS_NOT_INITIALIZED: \n            return \"CUDA Runtime API initialization failed.\";\n        case CUDNN_STATUS_ALLOC_FAILED: \n            return \"CUDA Resources could not be allocated.\";\n        case CUDNN_STATUS_BAD_PARAM:\n            return \"CUDNN_STATUS_BAD_PARAM\";\n        case CUDNN_STATUS_EXECUTION_FAILED:\n            return \"CUDNN_STATUS_EXECUTION_FAILED\";\n        case CUDNN_STATUS_NOT_SUPPORTED:\n            return \"CUDNN_STATUS_NOT_SUPPORTED\";\n        case CUDNN_STATUS_ARCH_MISMATCH:\n            return \"CUDNN_STATUS_ARCH_MISMATCH: Your GPU is too old and not supported by cuDNN\";\n        default:\n            return \"A call to cuDNN failed\";\n    }\n}\n\n// Check the return value of a call to the cuDNN runtime for an error condition.\n#define CHECK_CUDNN(call)                                                      \\\ndo{                                                                              \\\n    const cudnnStatus_t error = call;                                         \\\n    if (error != CUDNN_STATUS_SUCCESS)                                        \\\n    {                                                                          \\\n        std::ostringstream sout;                                               \\\n        sout << \"Error while calling \" << #call << \" in file \" << __FILE__ << \":\" << __LINE__ << \". \";\\\n        sout << \"code: \" << error << \", reason: \" << cudnn_get_error_string(error);\\\n        throw dlib::cudnn_error(sout.str());                            \\\n    }                                                                          \\\n}while(false)\n\n\nnamespace dlib\n{\n\n    namespace cuda \n    {\n\n    // ------------------------------------------------------------------------------------\n\n        static cudnnTensorDescriptor_t descriptor(const tensor& t) \n        {\n            return (const cudnnTensorDescriptor_t)t.get_cudnn_tensor_descriptor().get_handle();\n        }\n        static cudnnTensorDescriptor_t descriptor(const tensor_descriptor& t) \n        {\n            return (const cudnnTensorDescriptor_t)t.get_handle();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        class cudnn_context\n        {\n        public:\n            // not copyable\n            cudnn_context(const cudnn_context&) = delete;\n            cudnn_context& operator=(const cudnn_context&) = delete;\n\n            cudnn_context()\n            {\n                handles.resize(16);\n            }\n            ~cudnn_context()\n            {\n                for (auto h : handles)\n                {\n                    if (h)\n                        cudnnDestroy(h);\n                }\n            }\n\n            cudnnHandle_t get_handle (\n            )  \n            { \n                int new_device_id;\n                CHECK_CUDA(cudaGetDevice(&new_device_id));\n                // make room for more devices if needed\n                if (new_device_id >= (long)handles.size())\n                    handles.resize(new_device_id+16);\n\n                // If we don't have a handle already for this device then make one\n                if (!handles[new_device_id])\n                    CHECK_CUDNN(cudnnCreate(&handles[new_device_id]));\n\n                // Finally, return the handle for the current device\n                return handles[new_device_id];\n            }\n\n        private:\n\n            std::vector<cudnnHandle_t> handles;\n        };\n\n        static cudnnHandle_t context()\n        {\n            thread_local cudnn_context c;\n            return c.get_handle();\n        }\n    // ------------------------------------------------------------------------------------\n\n        class cudnn_activation_descriptor\n        {\n        public:\n            // not copyable \n            cudnn_activation_descriptor(const cudnn_activation_descriptor&) = delete;\n            cudnn_activation_descriptor& operator=(const cudnn_activation_descriptor&) = delete;\n\n            cudnn_activation_descriptor(\n                cudnnActivationMode_t mode,\n                cudnnNanPropagation_t reluNanOpt,\n                double coef\n            )\n            {\n                CHECK_CUDNN(cudnnCreateActivationDescriptor(&handle));\n                CHECK_CUDNN(cudnnSetActivationDescriptor(handle, mode, reluNanOpt, coef));\n            }\n\n            ~cudnn_activation_descriptor()\n            {\n                cudnnDestroyActivationDescriptor(handle);\n            }\n\n            cudnnActivationDescriptor_t get_handle (\n            ) \n            { \n                return handle; \n            }\n        private:\n            cudnnActivationDescriptor_t handle;\n        };\n\n        static cudnnActivationDescriptor_t identity_activation_descriptor()\n        {\n            thread_local cudnn_activation_descriptor des(CUDNN_ACTIVATION_IDENTITY, CUDNN_PROPAGATE_NAN,0);\n            return des.get_handle();\n        }\n\n        static cudnnActivationDescriptor_t relu_activation_descriptor()\n        {\n            thread_local cudnn_activation_descriptor des(CUDNN_ACTIVATION_RELU, CUDNN_PROPAGATE_NAN,0);\n            return des.get_handle();\n        }\n\n        static cudnnActivationDescriptor_t sigmoid_activation_descriptor()\n        {\n            thread_local cudnn_activation_descriptor des(CUDNN_ACTIVATION_SIGMOID, CUDNN_PROPAGATE_NAN,0);\n            return des.get_handle();\n        }\n\n        static cudnnActivationDescriptor_t tanh_activation_descriptor()\n        {\n            thread_local cudnn_activation_descriptor des(CUDNN_ACTIVATION_TANH, CUDNN_PROPAGATE_NAN,0);\n            return des.get_handle();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        tensor_descriptor::\n        tensor_descriptor(\n        ) : handle(nullptr)\n        {\n        }\n\n        tensor_descriptor::\n        ~tensor_descriptor()\n        {\n            set_size(0,0,0,0);\n        }\n\n        void tensor_descriptor::\n        set_size(\n            int n, \n            int k,\n            int nr, \n            int nc \n        )\n        {\n            if (handle)\n            {\n                cudnnDestroyTensorDescriptor((cudnnTensorDescriptor_t)handle);\n                handle = nullptr;\n            }\n\n            if (n != 0 && nr != 0 && nc != 0 && k != 0)\n            {\n                cudnnTensorDescriptor_t h;\n                CHECK_CUDNN(cudnnCreateTensorDescriptor(&h));\n                handle = h;\n\n                CHECK_CUDNN(cudnnSetTensor4dDescriptor((cudnnTensorDescriptor_t)handle,\n                        CUDNN_TENSOR_NCHW,\n                        CUDNN_DATA_FLOAT,\n                        n,\n                        k,\n                        nr,\n                        nc));\n            }\n        }\n\n        void tensor_descriptor::\n        get_size (\n            int& n, \n            int& k,\n            int& nr,\n            int& nc\n        ) const\n        {\n            if (handle)\n            {\n                int nStride, cStride, hStride, wStride;\n                cudnnDataType_t datatype;\n                CHECK_CUDNN(cudnnGetTensor4dDescriptor((cudnnTensorDescriptor_t)handle,\n                        &datatype,\n                        &n,\n                        &k,\n                        &nr,\n                        &nc,\n                        &nStride,\n                        &cStride,\n                        &hStride,\n                        &wStride));\n            }\n            else\n            {\n                n = 0;\n                k = 0;\n                nr = 0;\n                nc = 0;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void add(\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(\n                  (have_same_dimensions(src, dest) ||\n                  (src.num_samples()==1 && src.k()==dest.k() && src.nr()==1 && src.nc()==1) ||\n                  (src.num_samples()==1 && src.k()==dest.k() && src.nr()==dest.nr() && src.nc()==dest.nc()) ||\n                  (src.num_samples()==1 && src.k()==1 && src.nr()==dest.nr() && src.nc()==dest.nc()) ||\n                  (src.num_samples()==dest.num_samples() && src.k()==1 && src.nr()==1 && src.nc()==1)) &&\n                  is_same_object(src,dest) == false , \n                    \"\\n\\t dest.num_samples(): \" << dest.num_samples()\n                    <<\"\\n\\t dest.k():           \" << dest.k()\n                    <<\"\\n\\t dest.nr():          \" << dest.nr()\n                    <<\"\\n\\t dest.nc():          \" << dest.nc()\n                    <<\"\\n\\t src.num_samples():  \" << src.num_samples()\n                    <<\"\\n\\t src.k():            \" << src.k()\n                    <<\"\\n\\t src.nr():           \" << src.nr()\n                    <<\"\\n\\t src.nc():           \" << src.nc()\n                    );\n\n            if (dest.size() == src.size() && beta == 1)\n            {\n                // Call the dlib function in this case since it's faster than the one that\n                // comes with cuDNN (at least as of cuDNN v4).\n                add_scaled(dest, alpha, src);\n                return;\n            }\n            else if (src.num_samples()==dest.num_samples() && src.k()==1 && src.nr()==1 && src.nc()==1)\n            {\n                add_cv_to_all_columns(beta, dest, alpha, src);\n                return;\n            }\n\n            CHECK_CUDNN(cudnnAddTensor(context(),\n                                    &alpha,\n                                    descriptor(src),\n                                    src.device(),\n                                    &beta,\n                                    descriptor(dest),\n                                    dest.device()));\n        }\n\n        void assign_conv_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  grad.num_samples() == 1 &&\n                  grad.k()  >= 1 &&\n                  grad.nr() == 1 &&\n                  grad.nc() == 1 &&\n                  gradient_input.k() == grad.k() &&\n                  gradient_input.size() > 0 &&\n                  is_same_object(grad,gradient_input) == false\n                  );\n\n            const float alpha = 1;\n            const float beta = 0;\n            CHECK_CUDNN(cudnnConvolutionBackwardBias(context(),\n                                               &alpha,\n                                               descriptor(gradient_input),\n                                               gradient_input.device(),\n                                               &beta,\n                                               descriptor(grad),\n                                               grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void batch_normalize_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        )\n        {\n            DLIB_CASSERT(\n                gamma.num_samples() == 1 && \n                gamma.nr() == src.nr() &&\n                gamma.nc() == src.nc() &&\n                gamma.k()  == src.k() &&\n                have_same_dimensions(gamma, beta) &&\n                have_same_dimensions(gamma, running_means) &&\n                have_same_dimensions(gamma, running_variances) && \n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nrunning_means.num_samples(): \" << running_means.num_samples() << \n                \"\\nrunning_means.k():   \" << running_means.k() << \n                \"\\nrunning_means.nr():  \" << running_means.nr() << \n                \"\\nrunning_means.nc():  \" << running_means.nc() << \n                \"\\nrunning_variances.num_samples(): \" << running_variances.num_samples() << \n                \"\\nrunning_variances.k():   \" << running_variances.k() << \n                \"\\nrunning_variances.nr():  \" << running_variances.nr() << \n                \"\\nrunning_variances.nc():  \" << running_variances.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n            const float in_scale = 1;\n            const float out_scale = 0;\n\n            dest.copy_size(src);\n\n            CHECK_CUDNN(cudnnBatchNormalizationForwardInference(\n                                context(),\n                                CUDNN_BATCHNORM_PER_ACTIVATION,\n                                &in_scale,\n                                &out_scale,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(dest),\n                                dest.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                beta.device(),\n                                running_means.device(),\n                                running_variances.device(),\n                                eps));\n        }\n\n        void batch_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        )\n        {\n            DLIB_CASSERT(0 <= averaging_factor && averaging_factor <= 1, \"averaging_factor: \" << averaging_factor);\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_means,means));\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_variances,invstds));\n            DLIB_CASSERT(\n                src.num_samples() > 1 &&\n                gamma.num_samples() == 1 && \n                beta.num_samples() == 1 && \n                gamma.nr() == beta.nr() && beta.nr() == src.nr() &&\n                gamma.nc() == beta.nc() && beta.nc() == src.nc() &&\n                gamma.k()  == beta.k()  && beta.k() == src.k() &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n\n            const float in_scale = 1;\n            const float out_scale = 0;\n\n            dest.copy_size(src);\n            means.set_size(1, src.k(), src.nr(), src.nc());\n            invstds.copy_size(means);\n            running_means.copy_size(means);\n            running_variances.copy_size(means);\n            // cuDNN requires that running_means and running_variances be initialized to\n            // some valid float values even if the averaging factor would have ignored\n            // them.  \n            if (averaging_factor == 1)\n            {\n                running_means = 0;\n                running_variances = 1;\n            }\n\n            CHECK_CUDNN(cudnnBatchNormalizationForwardTraining(\n                                context(),\n                                CUDNN_BATCHNORM_PER_ACTIVATION,\n                                &in_scale,\n                                &out_scale,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(dest),\n                                dest.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                beta.device(),\n                                averaging_factor,\n                                running_means.device(),\n                                running_variances.device(),\n                                eps,\n                                means.device(),\n                                invstds.device()));\n        }\n\n        void batch_normalize_gradient(\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        )\n        {\n            const long num = src.k()*src.nr()*src.nc();\n            DLIB_CASSERT(src.num_samples() > 1);\n            DLIB_CASSERT(num == (long)means.size());\n            DLIB_CASSERT(num == (long)invstds.size());\n            DLIB_CASSERT(num == (long)gamma.size());\n            DLIB_CASSERT(num == (long)gamma_grad.size());\n            DLIB_CASSERT(num == (long)beta_grad.size());\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            const float in_scale = 1;\n            const float out_scale = 1;\n            const float in_scale_params = 1;\n            const float out_scale_params = 0;\n\n            CHECK_CUDNN(cudnnBatchNormalizationBackward(\n                                context(),\n                                CUDNN_BATCHNORM_PER_ACTIVATION,\n                                &in_scale,\n                                &out_scale,\n                                &in_scale_params,\n                                &out_scale_params,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(gradient_input),\n                                gradient_input.device(),\n                                descriptor(src_grad),\n                                src_grad.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                gamma_grad.device(),\n                                beta_grad.device(),\n                                eps,\n                                means.device(),\n                                invstds.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void batch_normalize_conv_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        )\n        {\n            DLIB_CASSERT(\n                gamma.num_samples() == 1 && \n                gamma.nr() == 1 &&\n                gamma.nc() == 1 &&\n                gamma.k()  == src.k() &&\n                have_same_dimensions(gamma, beta) &&\n                have_same_dimensions(gamma, running_means) &&\n                have_same_dimensions(gamma, running_variances) &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nrunning_means.num_samples(): \" << running_means.num_samples() << \n                \"\\nrunning_means.k():   \" << running_means.k() << \n                \"\\nrunning_means.nr():  \" << running_means.nr() << \n                \"\\nrunning_means.nc():  \" << running_means.nc() << \n                \"\\nrunning_variances.num_samples(): \" << running_variances.num_samples() << \n                \"\\nrunning_variances.k():   \" << running_variances.k() << \n                \"\\nrunning_variances.nr():  \" << running_variances.nr() << \n                \"\\nrunning_variances.nc():  \" << running_variances.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n            const float in_scale = 1;\n            const float out_scale = 0;\n\n            dest.copy_size(src);\n\n            CHECK_CUDNN(cudnnBatchNormalizationForwardInference(\n                                context(),\n                                CUDNN_BATCHNORM_SPATIAL,\n                                &in_scale,\n                                &out_scale,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(dest),\n                                dest.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                beta.device(),\n                                running_means.device(),\n                                running_variances.device(),\n                                eps));\n        }\n\n        void batch_normalize_conv (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        )\n        {\n            DLIB_CASSERT(0 <= averaging_factor && averaging_factor <= 1, \"averaging_factor: \" << averaging_factor);\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_means,means));\n            DLIB_CASSERT(averaging_factor==1 || have_same_dimensions(running_variances,invstds));\n            DLIB_CASSERT(\n                src.num_samples() > 1 &&\n                gamma.num_samples() == 1 && \n                beta.num_samples() == 1 && \n                gamma.nr() == 1 && \n                beta.nr() == 1 && \n                gamma.nc() == 1 && \n                beta.nc() == 1 && \n                gamma.k()  == beta.k()  && beta.k() == src.k() &&\n                eps > 0, \n                \"\\ngamma.num_samples(): \" << gamma.num_samples() << \n                \"\\ngamma.k():  \" << gamma.k() << \n                \"\\ngamma.nr(): \" << gamma.nr() << \n                \"\\ngamma.nc(): \" << gamma.nc() << \n                \"\\nbeta.num_samples(): \" << beta.num_samples() << \n                \"\\nbeta.k():   \" << beta.k() << \n                \"\\nbeta.nr():  \" << beta.nr() << \n                \"\\nbeta.nc():  \" << beta.nc() << \n                \"\\nsrc.k():   \" << src.k() << \n                \"\\nsrc.nr():  \" << src.nr() << \n                \"\\nsrc.nc():  \" << src.nc() <<\n                \"\\neps:  \" << eps \n            );\n            const float in_scale = 1;\n            const float out_scale = 0;\n\n            dest.copy_size(src);\n            means.set_size(1, src.k());\n            invstds.copy_size(means);\n            running_means.copy_size(means);\n            running_variances.copy_size(means);\n            // cuDNN requires that running_means and running_variances be initialized to\n            // some valid float values even if the averaging factor would have ignored\n            // them.  \n            if (averaging_factor == 1)\n            {\n                running_means = 0;\n                running_variances = 1;\n            }\n\n            CHECK_CUDNN(cudnnBatchNormalizationForwardTraining(\n                                context(),\n                                CUDNN_BATCHNORM_SPATIAL,\n                                &in_scale,\n                                &out_scale,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(dest),\n                                dest.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                beta.device(),\n                                averaging_factor,\n                                running_means.device(),\n                                running_variances.device(),\n                                eps,\n                                means.device(),\n                                invstds.device()));\n        }\n\n        void batch_normalize_conv_gradient(\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        )\n        {\n            DLIB_CASSERT(src.k() == (long)means.size());\n            DLIB_CASSERT(src.k() == (long)invstds.size());\n            DLIB_CASSERT(src.k() == (long)gamma.size());\n            DLIB_CASSERT(src.k() == (long)gamma_grad.size());\n            DLIB_CASSERT(src.k() == (long)beta_grad.size());\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src));\n            DLIB_CASSERT(have_same_dimensions(gradient_input, src_grad));\n            DLIB_CASSERT(eps > 0);\n\n            const float in_scale = 1;\n            const float out_scale = 1;\n            const float in_scale_params = 1;\n            const float out_scale_params = 0;\n\n            CHECK_CUDNN(cudnnBatchNormalizationBackward(\n                                context(),\n                                CUDNN_BATCHNORM_SPATIAL,\n                                &in_scale,\n                                &out_scale,\n                                &in_scale_params,\n                                &out_scale_params,\n                                descriptor(src),\n                                src.device(),\n                                descriptor(gradient_input),\n                                gradient_input.device(),\n                                descriptor(src_grad),\n                                src_grad.device(),\n                                descriptor(gamma),\n                                gamma.device(),\n                                gamma_grad.device(),\n                                beta_grad.device(),\n                                eps,\n                                means.device(),\n                                invstds.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        tensor_conv::\n        tensor_conv(\n        ) : \n            filter_handle(nullptr),\n            conv_handle(nullptr),\n            forward_algo(0),\n            backward_data_algo(0),\n            backward_filters_algo(0)\n        {\n            clear();\n        }\n\n        void tensor_conv::\n        clear (\n        )\n        {\n            if (filter_handle) \n                cudnnDestroyFilterDescriptor((cudnnFilterDescriptor_t)filter_handle);\n            if (conv_handle) \n                cudnnDestroyConvolutionDescriptor((cudnnConvolutionDescriptor_t)conv_handle);\n            filter_handle = nullptr;\n            conv_handle = nullptr;\n            out_num_samples = 0;\n            out_k = 0;\n            out_nr = 0;\n            out_nc = 0;\n\n            stride_y = 0;\n            stride_x = 0;\n            padding_y = 0;\n            padding_x = 0;\n            data_num_samples = 0;\n            data_k = 0;\n            data_nr = 0;\n            data_nc = 0;\n            filters_num_samples = 0;\n            filters_k = 0;\n            filters_nr = 0;\n            filters_nc = 0;\n\n            forward_algo = 0;\n            backward_data_algo = 0;\n            backward_filters_algo = 0;\n\n            forward_workspace_size_in_bytes = 0;\n            backward_data_workspace_size_in_bytes = 0;\n            backward_filters_workspace_size_in_bytes = 0;\n\n            forward_workspace.reset();\n            backward_data_workspace.reset();\n            backward_filters_workspace.reset();\n        }\n\n        // Given an array of cudnn algorithm performance results, like\n        // cudnnConvolutionFwdAlgoPerf_t, pick the best one to use.\n        template <typename T>\n        decltype(std::declval<T>().algo) pick_best_algorithm(const std::vector<T> &perf_results) \n        {\n            DLIB_CASSERT(!perf_results.empty());\n            CHECK_CUDNN(perf_results[0].status);\n            if (dnn_prefer_fastest_algorithms())\n                return perf_results[0].algo;\n\n            // Otherwise we find the algorithm that has a good status and uses the least amount\n            // of memory.\n            size_t best_memory = std::numeric_limits<size_t>::max();\n            decltype(std::declval<T>().algo) best_alg;\n            for (auto&& perf : perf_results) \n            {\n                if (perf.status == CUDNN_STATUS_SUCCESS && perf.memory < best_memory) \n                {\n                    best_memory = perf.memory;\n                    best_alg = perf.algo;\n                }\n            }\n            return best_alg;\n        }\n\n        void tensor_conv::\n        select_best_algorithms (\n            const tensor& data,\n            const tensor_descriptor& dest_desc,\n            allow_cache_use allow_cache_use_\n        ) \n        {\n            // Calling the cuDNN \"find the best algorithm\" functions is really slow.  So we keep a\n            // cache that tells us what method was best for a particular configuration.\n            thread_local std::map<std::tuple<int,int,int,int,long,long>,\n                                  std::tuple<int,int,int>> config_to_algo_cache;\n\n            // If we have already found good algorithms for this setting then just pull them from\n            // the cache.\n            const auto cache_key = std::make_tuple(stride_y, stride_x, padding_y, padding_x, filters_nr, filters_nc);\n            const auto iter = config_to_algo_cache.find(cache_key);\n            if (iter != config_to_algo_cache.end() && allow_cache_use_ == allow_cache_use::yes)\n            {\n                std::tie(forward_algo, backward_data_algo, backward_filters_algo) = iter->second;\n                return;\n            }\n\n\n            // Pick which forward algorithm we will use and allocate the necessary\n            // workspace buffer.\n            cudnnConvolutionFwdAlgo_t forward_best_algo;\n#if CUDNN_MAJOR >= 8\n            {\n                int num_possible_algorithms = 0;\n                CHECK_CUDNN(cudnnGetConvolutionForwardAlgorithmMaxCount(context(), &num_possible_algorithms));\n                std::vector<cudnnConvolutionFwdAlgoPerf_t> perf_results(num_possible_algorithms);\n                int num_algorithms = 0;\n                CHECK_CUDNN(cudnnFindConvolutionForwardAlgorithm(\n                        context(), \n                        descriptor(data),\n                        (const cudnnFilterDescriptor_t)filter_handle,\n                        (const cudnnConvolutionDescriptor_t)conv_handle,\n                        descriptor(dest_desc),\n                        num_possible_algorithms,\n                        &num_algorithms,\n                        perf_results.data()));\n                perf_results.resize(num_algorithms);\n                forward_best_algo = pick_best_algorithm(perf_results);\n            }\n#else\n            CHECK_CUDNN(cudnnGetConvolutionForwardAlgorithm(\n                    context(), \n                    descriptor(data),\n                    (const cudnnFilterDescriptor_t)filter_handle,\n                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                    descriptor(dest_desc),\n                    dnn_prefer_fastest_algorithms()?CUDNN_CONVOLUTION_FWD_PREFER_FASTEST:CUDNN_CONVOLUTION_FWD_NO_WORKSPACE,\n                    std::numeric_limits<size_t>::max(),\n                    &forward_best_algo));\n#endif\n            forward_algo = forward_best_algo;\n\n\n\n            // Pick which backward data algorithm we will use and allocate the\n            // necessary workspace buffer.\n            cudnnConvolutionBwdDataAlgo_t backward_data_best_algo;\n#if CUDNN_MAJOR >= 8\n            {\n                int num_possible_algorithms = 0;\n                CHECK_CUDNN(cudnnGetConvolutionBackwardFilterAlgorithmMaxCount(context(), &num_possible_algorithms));\n                std::vector<cudnnConvolutionBwdDataAlgoPerf_t> perf_results(num_possible_algorithms);\n                int num_algorithms = 0;\n                CHECK_CUDNN(cudnnFindConvolutionBackwardDataAlgorithm(\n                        context(),\n                        (const cudnnFilterDescriptor_t)filter_handle,\n                        descriptor(dest_desc),\n                        (const cudnnConvolutionDescriptor_t)conv_handle,\n                        descriptor(data),\n                        num_possible_algorithms,\n                        &num_algorithms,\n                        perf_results.data()));\n                perf_results.resize(num_algorithms);\n                backward_data_best_algo = pick_best_algorithm(perf_results);\n            }\n#else\n            CHECK_CUDNN(cudnnGetConvolutionBackwardDataAlgorithm(\n                    context(),\n                    (const cudnnFilterDescriptor_t)filter_handle,\n                    descriptor(dest_desc),\n                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                    descriptor(data),\n                    dnn_prefer_fastest_algorithms()?CUDNN_CONVOLUTION_BWD_DATA_PREFER_FASTEST:CUDNN_CONVOLUTION_BWD_DATA_NO_WORKSPACE,\n                    std::numeric_limits<size_t>::max(),\n                    &backward_data_best_algo));\n#endif\n            backward_data_algo = backward_data_best_algo;\n\n\n\n\n            // Pick which backward filters algorithm we will use and allocate the\n            // necessary workspace buffer.\n            cudnnConvolutionBwdFilterAlgo_t backward_filters_best_algo;\n#if CUDNN_MAJOR >= 8\n            {\n                int num_possible_algorithms = 0;\n                CHECK_CUDNN(cudnnGetConvolutionBackwardFilterAlgorithmMaxCount(context(), &num_possible_algorithms));\n                std::vector<cudnnConvolutionBwdFilterAlgoPerf_t> perf_results(num_possible_algorithms);\n                int num_algorithms = 0;\n                CHECK_CUDNN(cudnnFindConvolutionBackwardFilterAlgorithm(\n                        context(),\n                        descriptor(data),\n                        descriptor(dest_desc),\n                        (const cudnnConvolutionDescriptor_t)conv_handle,\n                        (const cudnnFilterDescriptor_t)filter_handle,\n                        num_possible_algorithms,\n                        &num_algorithms,\n                        perf_results.data()));\n                perf_results.resize(num_algorithms);\n                backward_filters_best_algo = pick_best_algorithm(perf_results);\n            }\n#else\n            CHECK_CUDNN(cudnnGetConvolutionBackwardFilterAlgorithm(\n                    context(),\n                    descriptor(data),\n                    descriptor(dest_desc),\n                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                    (const cudnnFilterDescriptor_t)filter_handle,\n                    dnn_prefer_fastest_algorithms()?CUDNN_CONVOLUTION_BWD_FILTER_PREFER_FASTEST:CUDNN_CONVOLUTION_BWD_FILTER_NO_WORKSPACE,\n                    std::numeric_limits<size_t>::max(),\n                    &backward_filters_best_algo));\n#endif\n\n#if CUDNN_MAJOR < 7\n            // cuDNN 5.1 has a bug that causes\n            // cudnnGetConvolutionBackwardFilterAlgorithm() to pick the winograd\n            // algorithm even for cases where cuDNN doesn't support it, leading to\n            // incorrect outputs.  So here we check if we are in a case where winograd\n            // isn't supported and manually overrule\n            // cudnnGetConvolutionBackwardFilterAlgorithm() by picking a safe\n            // algorithm.\n            if (dnn_prefer_fastest_algorithms() && \n                !(stride_x == 1 && stride_y == 1 && ((filters_nr==3&&filters_nc==3) || (filters_nr==5&&filters_nc==5)))\n            )\n            {\n                backward_filters_best_algo = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_0;\n            }\n#endif\n            backward_filters_algo = backward_filters_best_algo;\n\n            // Save this algorithm selection in the cache\n            config_to_algo_cache[cache_key] = std::make_tuple(forward_algo, backward_data_algo, backward_filters_algo);\n        }\n\n        void tensor_conv::\n        update_convolution_data_workspace_sizes(\n            const tensor& data,\n            const tensor_descriptor& dest_desc\n        )\n        {\n            CHECK_CUDNN(cudnnGetConvolutionForwardWorkspaceSize(\n                context(),\n                descriptor(data),\n                (const cudnnFilterDescriptor_t)filter_handle,\n                (const cudnnConvolutionDescriptor_t)conv_handle,\n                descriptor(dest_desc),\n                (cudnnConvolutionFwdAlgo_t)forward_algo,\n                &forward_workspace_size_in_bytes));\n\n            CHECK_CUDNN(cudnnGetConvolutionBackwardDataWorkspaceSize(\n                context(),\n                (const cudnnFilterDescriptor_t)filter_handle,\n                descriptor(dest_desc),\n                (const cudnnConvolutionDescriptor_t)conv_handle,\n                descriptor(data),\n                (cudnnConvolutionBwdDataAlgo_t)backward_data_algo,\n                &backward_data_workspace_size_in_bytes));\n\n            CHECK_CUDNN(cudnnGetConvolutionBackwardFilterWorkspaceSize(\n                context(),\n                descriptor(data),\n                descriptor(dest_desc),\n                (const cudnnConvolutionDescriptor_t)conv_handle,\n                (const cudnnFilterDescriptor_t)filter_handle,\n                (cudnnConvolutionBwdFilterAlgo_t)backward_filters_algo,\n                &backward_filters_workspace_size_in_bytes));\n        }\n\n        void tensor_conv::\n        setup(\n            const tensor& data,\n            const tensor& filters,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_\n        ) \n        {\n            DLIB_CASSERT(data.k() == filters.k());\n\n            // if the last call to setup gave the same exact settings then don't do\n            // anything.\n            if (data_num_samples == data.num_samples() &&\n                data_k == data.k() &&\n                data_nr == data.nr() &&\n                data_nc == data.nc() &&\n                stride_y_ == stride_y && \n                stride_x_ == stride_x &&\n                padding_y_ == padding_y && \n                padding_x_ == padding_x &&\n                filters_num_samples == filters.num_samples() &&\n                filters_k == filters.k() &&\n                filters_nr == filters.nr() &&\n                filters_nc == filters.nc()\n            )\n            {\n                return;\n            }\n\n            clear();\n            try\n            {\n                stride_y = stride_y_;\n                stride_x = stride_x_;\n                padding_y = padding_y_;\n                padding_x = padding_x_;\n                data_num_samples = data.num_samples();\n                data_k = data.k();\n                data_nr = data.nr();\n                data_nc = data.nc();\n                filters_num_samples = filters.num_samples();\n                filters_k = filters.k();\n                filters_nr = filters.nr();\n                filters_nc = filters.nc();\n\n                CHECK_CUDNN(cudnnCreateFilterDescriptor((cudnnFilterDescriptor_t*)&filter_handle));\n                CHECK_CUDNN(cudnnSetFilter4dDescriptor((cudnnFilterDescriptor_t)filter_handle, \n                                                 CUDNN_DATA_FLOAT, \n                                                 CUDNN_TENSOR_NCHW,\n                                                 filters.num_samples(),\n                                                 filters.k(),\n                                                 filters.nr(),\n                                                 filters.nc()));\n\n                CHECK_CUDNN(cudnnCreateConvolutionDescriptor((cudnnConvolutionDescriptor_t*)&conv_handle));\n#if CUDNN_MAJOR >= 6\n                CHECK_CUDNN(cudnnSetConvolution2dDescriptor((cudnnConvolutionDescriptor_t)conv_handle,\n                        padding_y, // vertical padding\n                        padding_x, // horizontal padding\n                        stride_y,\n                        stride_x,\n                        1, 1, // must be 1,1\n                        CUDNN_CROSS_CORRELATION,\n                        CUDNN_DATA_FLOAT)); // could also be CUDNN_CONVOLUTION\n#else\n                CHECK_CUDNN(cudnnSetConvolution2dDescriptor((cudnnConvolutionDescriptor_t)conv_handle,\n                        padding_y, // vertical padding\n                        padding_x, // horizontal padding\n                        stride_y,\n                        stride_x,\n                        1, 1, // must be 1,1\n                        CUDNN_CROSS_CORRELATION)); // could also be CUDNN_CONVOLUTION\n#endif\n\n#if CUDNN_MAJOR >= 8\n                // On Ampere and later GPUs, CUDNN_DEFAULT_MATH permits TF32 Tensor Core\n                // operations which have reduced precision. Use CUDNN_FMA_MATH to force\n                // true FP32 computation for consistent numerical results.\n                CHECK_CUDNN(cudnnSetConvolutionMathType(\n                        (cudnnConvolutionDescriptor_t)conv_handle,\n                        CUDNN_FMA_MATH));\n#endif\n\n                CHECK_CUDNN(cudnnGetConvolution2dForwardOutputDim(\n                        (const cudnnConvolutionDescriptor_t)conv_handle,\n                        descriptor(data),\n                        (const cudnnFilterDescriptor_t)filter_handle,\n                        &out_num_samples,\n                        &out_k,\n                        &out_nr,\n                        &out_nc));\n\n                tensor_descriptor dest_desc;\n                dest_desc.set_size(out_num_samples,out_k,out_nr,out_nc);\n\n                try\n                {\n                    select_best_algorithms(data, dest_desc, allow_cache_use::yes);\n                    update_convolution_data_workspace_sizes(data, dest_desc);\n                }\n                catch (dlib::cudnn_error&)\n                {\n                    // Sometimes the values stored in `config_to_algo_cache` do not quite work -\n                    // so let's get a fresh estimate, instead of using a cached value.\n                    select_best_algorithms(data, dest_desc, allow_cache_use::no);\n                    update_convolution_data_workspace_sizes(data, dest_desc);\n                }\n            }\n            catch(...)\n            {\n                clear();\n                throw;\n            }\n        }\n\n        tensor_conv::\n        ~tensor_conv (\n        )\n        {\n            clear();\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters\n        )\n        {\n            DLIB_CASSERT(stride_y > 0 && stride_x > 0, \"You must call setup() before calling this function\");\n\n            output.set_size(out_num_samples, out_k, out_nr, out_nc);\n            (*this)(add_to_output, static_cast<tensor&>(output), data, filters);\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters\n        )\n        {\n            DLIB_CASSERT(is_same_object(output,data) == false);\n            DLIB_CASSERT(is_same_object(output,filters) == false);\n            DLIB_CASSERT(filters.k() == data.k());\n            DLIB_CASSERT(stride_y > 0 && stride_x > 0, \"You must call setup() before calling this function\");\n            DLIB_CASSERT(filters.nc() <= data.nc() + 2*padding_x,\n                \"Filter windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t filters.nc(): \" << filters.nc() \n                << \"\\n\\t data.nc():  \" << data.nc() \n                << \"\\n\\t padding_x: \" << padding_x \n                );\n            DLIB_CASSERT(filters.nr() <= data.nr() + 2*padding_y,\n                \"Filter windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t filters.nr(): \" << filters.nr() \n                << \"\\n\\t data.nr():  \" << data.nr() \n                << \"\\n\\t padding_y: \" << padding_y \n                );\n\n\n            DLIB_CASSERT(output.num_samples() == data.num_samples(),out_num_samples << \"  \" << data.num_samples());\n            DLIB_CASSERT(output.k() == filters.num_samples());\n            DLIB_CASSERT(output.nr() == 1+(data.nr()+2*padding_y-filters.nr())/stride_y);\n            DLIB_CASSERT(output.nc() == 1+(data.nc()+2*padding_x-filters.nc())/stride_x);\n\n\n\n            const float alpha = 1;\n            const float beta = add_to_output ? 1 : 0;\n\n            // Since cudnnConvolutionForward() is an asynchronous call, we need to hold a\n            // reference to the workspace buffer so we can be sure it isn't reallocated\n            // while the function is still executing on the device.  But each time we come\n            // here, we make sure to grab the latest workspace buffer so that, globally, we\n            // minimize the number of such buffers.\n            forward_workspace = device_global_buffer(forward_workspace_size_in_bytes);\n\n            CHECK_CUDNN(cudnnConvolutionForward(\n                    context(),\n                    &alpha,\n                    descriptor(data),\n                    data.device(),\n                    (const cudnnFilterDescriptor_t)filter_handle,\n                    filters.device(),\n                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                    (cudnnConvolutionFwdAlgo_t)forward_algo,\n                    forward_workspace,\n                    forward_workspace_size_in_bytes,\n                    &beta,\n                    descriptor(output),\n                    output.device()));\n\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        )\n        {\n            DLIB_CASSERT(stride_y > 0 && stride_x > 0, \"You must call setup() before calling this function\");\n\n            output.set_size(out_num_samples, out_k, out_nr, out_nc);\n            (*this)(add_to_output, static_cast<tensor&>(output), data, filters, biases, use_relu);\n        }\n\n        void tensor_conv::operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        )\n        {\n\n            // Function cudnnConvolutionBiasActivationForward should only be called with CUDNN_ACTIVATION_IDENTITY when\n            // the chosen forward algorithm is CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM, as cuDNN documentation explicitly says.\n            // In case the algorithm is different, perform the forward pass and bias addition separately.\n            // If use_relu is true, any algorithm can be used.\n            if (!use_relu && forward_algo != CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM)\n            {\n                (*this)(add_to_output, output, data, filters);\n\n                tt::add(1, output, 1, biases);\n\n                return;\n            }\n\n            DLIB_CASSERT(is_same_object(output,data) == false);\n            DLIB_CASSERT(is_same_object(output,filters) == false);\n            DLIB_CASSERT(filters.k() == data.k());\n            DLIB_CASSERT(stride_y > 0 && stride_x > 0, \"You must call setup() before calling this function\");\n            DLIB_CASSERT(filters.nc() <= data.nc() + 2*padding_x,\n                \"Filter windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t filters.nc(): \" << filters.nc()\n                << \"\\n\\t data.nc():  \" << data.nc()\n                << \"\\n\\t padding_x: \" << padding_x\n                );\n            DLIB_CASSERT(filters.nr() <= data.nr() + 2*padding_y,\n                \"Filter windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t filters.nr(): \" << filters.nr()\n                << \"\\n\\t data.nr():  \" << data.nr()\n                << \"\\n\\t padding_y: \" << padding_y\n                );\n\n\n            DLIB_CASSERT(output.num_samples() == data.num_samples(),out_num_samples << \"  \" << data.num_samples());\n            DLIB_CASSERT(output.k() == filters.num_samples());\n            DLIB_CASSERT(output.nr() == 1+(data.nr()+2*padding_y-filters.nr())/stride_y);\n            DLIB_CASSERT(output.nc() == 1+(data.nc()+2*padding_x-filters.nc())/stride_x);\n            DLIB_CASSERT(filters.num_samples() == biases.k());\n\n\n\n            const float alpha1 = 1;\n            const float alpha2 = add_to_output ? 1 : 0;\n\n            // Since cudnnConvolutionBiasActivationForward() is an asynchronous call,\n            // we need to hold a reference to the workspace buffer so we can be sure it\n            // isn't reallocated while the function is still executing on the device.\n            // But each time we come here, we make sure to grab the latest workspace\n            // buffer so that, globally, we minimize the number of such buffers.\n            forward_workspace = device_global_buffer(forward_workspace_size_in_bytes);\n\n            float* out = output.device();\n            const cudnnTensorDescriptor_t out_desc = descriptor(output);\n\n            CHECK_CUDNN(cudnnConvolutionBiasActivationForward(\n                    context(),\n                    &alpha1,\n                    descriptor(data),\n                    data.device(),\n                    (const cudnnFilterDescriptor_t)filter_handle,\n                    filters.device(),\n                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                    (cudnnConvolutionFwdAlgo_t)forward_algo,\n                    forward_workspace,\n                    forward_workspace_size_in_bytes,\n                    &alpha2,\n                    out_desc,\n                    out,\n                    descriptor(biases),\n                    biases.device(),\n                    use_relu ? relu_activation_descriptor() : identity_activation_descriptor(),\n                    out_desc,\n                    out));\n        }\n\n        void tensor_conv::get_gradient_for_data (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& filters,\n            tensor& data_gradient\n        )\n        {\n            const float alpha = 1;\n            const float beta = add_to_output ? 1 : 0;\n\n            // Since cudnnConvolutionBackwardData() is an asynchronous call, we need to hold a\n            // reference to the workspace buffer so we can be sure it isn't reallocated\n            // while the function is still executing on the device.  But each time we come\n            // here, we make sure to grab the latest workspace buffer so that, globally, we\n            // minimize the number of such buffers.\n            backward_data_workspace = device_global_buffer(backward_data_workspace_size_in_bytes);\n\n\n            CHECK_CUDNN(cudnnConvolutionBackwardData(context(),\n                                                  &alpha,\n                                                  (const cudnnFilterDescriptor_t)filter_handle,\n                                                  filters.device(),\n                                                  descriptor(gradient_input),\n                                                  gradient_input.device(),\n                                                  (const cudnnConvolutionDescriptor_t)conv_handle,\n                                                  (cudnnConvolutionBwdDataAlgo_t)backward_data_algo,\n                                                  backward_data_workspace,\n                                                  backward_data_workspace_size_in_bytes,\n                                                  &beta,\n                                                  descriptor(data_gradient),\n                                                  data_gradient.device()));\n        }\n\n        void tensor_conv::\n        get_gradient_for_filters (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& data,\n            tensor& filters_gradient\n        )\n        {\n            const float alpha = 1;\n            const float beta = add_to_output ? 1 : 0;\n\n            // Since cudnnConvolutionBackwardFilter() is an asynchronous call, we need to hold a\n            // reference to the workspace buffer so we can be sure it isn't reallocated\n            // while the function is still executing on the device.  But each time we come\n            // here, we make sure to grab the latest workspace buffer so that, globally, we\n            // minimize the number of such buffers.\n            backward_filters_workspace = device_global_buffer(backward_filters_workspace_size_in_bytes);\n\n            CHECK_CUDNN(cudnnConvolutionBackwardFilter(context(),\n                                                    &alpha,\n                                                    descriptor(data),\n                                                    data.device(),\n                                                    descriptor(gradient_input),\n                                                    gradient_input.device(),\n                                                    (const cudnnConvolutionDescriptor_t)conv_handle,\n                                                    (cudnnConvolutionBwdFilterAlgo_t)backward_filters_algo,\n                                                    backward_filters_workspace,\n                                                    backward_filters_workspace_size_in_bytes,\n                                                    &beta,\n                                                    (const cudnnFilterDescriptor_t)filter_handle,\n                                                    filters_gradient.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        pooling::pooling (\n        ) : handle(nullptr),window_height(0),window_width(0),stride_y(0),stride_x(0),padding_y(0), padding_x(0)\n        {\n        }\n\n        pooling::~pooling(\n        )\n        {\n            clear();\n        }\n\n        void pooling::\n        clear(\n        )\n        {\n            if (handle)\n                cudnnDestroyPoolingDescriptor((cudnnPoolingDescriptor_t)handle);\n            handle = nullptr;\n            window_height = 0;\n            window_width = 0;\n            stride_y = 0;\n            stride_x = 0;\n            padding_y = 0;\n            padding_x = 0;\n        }\n\n        void pooling::\n        setup_max_pooling(\n            int window_height_,\n            int window_width_,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_ \n        )\n        {\n            setup(window_height_, window_width_, stride_y_, stride_x_, padding_y_, padding_x_, CUDNN_POOLING_MAX);\n            do_max_pooling = true;\n        }\n\n        void pooling::\n        setup_avg_pooling(\n            int window_height_,\n            int window_width_,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_\n        )\n        {\n            setup(window_height_, window_width_, stride_y_, stride_x_, padding_y_, padding_x_, CUDNN_POOLING_AVERAGE_COUNT_EXCLUDE_PADDING);\n            do_max_pooling = false;\n        }\n\n        void pooling::\n        setup(\n            int window_height_,\n            int window_width_,\n            int stride_y_,\n            int stride_x_,\n            int padding_y_,\n            int padding_x_,\n            int pooling_mode\n        )\n        {\n            DLIB_CASSERT (window_height_ > 0 && window_width_ > 0 && \n                          stride_y_ > 0 && stride_x_ > 0 , \n                          \"window_height_: \" << window_height_ \n                          << \"\\t\\n window_width_: \" << window_width_ \n                          << \"\\t\\n stride_y_: \" << stride_y_ \n                          << \"\\t\\n stride_x_: \" << stride_x_ );\n            DLIB_CASSERT( 0 <= padding_y_ && padding_y_ < window_height_ && \n                          0 <= padding_x_ && padding_x_ < window_width_,\n                          \"window_height_: \" << window_height_ \n                          << \"\\t\\n window_width_: \" << window_width_ \n                          << \"\\t\\n padding_y_: \" << padding_y_ \n                          << \"\\t\\n padding_x_: \" << padding_x_ );\n\n            if (window_height == window_height_ &&\n                window_width  == window_width_ &&\n                stride_y == stride_y_ &&\n                stride_x == stride_x_ && \n                padding_y == padding_y_ &&\n                padding_x == padding_x_\n                )\n            {\n                return;\n            }\n\n            clear();\n            try\n            {\n                window_height = window_height_;\n                window_width = window_width_;\n                stride_x = stride_x_;\n                stride_y = stride_y_;\n                padding_y  = padding_y_;\n                padding_x  = padding_x_;\n                cudnnPoolingDescriptor_t poolingDesc;\n                CHECK_CUDNN(cudnnCreatePoolingDescriptor(&poolingDesc));\n                handle = poolingDesc;\n\n                CHECK_CUDNN(cudnnSetPooling2dDescriptor(poolingDesc,\n                                                (cudnnPoolingMode_t)pooling_mode,\n                                                CUDNN_PROPAGATE_NAN,\n                                                window_height,\n                                                window_width,\n                                                padding_y,\n                                                padding_x,  \n                                                stride_y,\n                                                stride_x));\n            }\n            catch(...)\n            {\n                clear();\n                throw;\n            }\n        }\n\n        void pooling::\n        operator() (\n            resizable_tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(window_width  <= src.nc() + 2*padding_x,\n                \"Pooling windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t window_width: \" << window_width \n                << \"\\n\\t src.nc():  \" << src.nc() \n                << \"\\n\\t padding_x: \" << padding_x \n                );\n            DLIB_CASSERT(window_height <= src.nr() + 2*padding_y,\n                \"Pooling windows must be small enough to fit into the padded image.\"\n                << \"\\n\\t window_height: \" << window_height \n                << \"\\n\\t src.nr():  \" << src.nr() \n                << \"\\n\\t padding_y: \" << padding_y \n                );\n            const float alpha = 1;\n            const float beta = 0;\n            int outN;\n            int outC;\n            int outH;\n            int outW;\n            CHECK_CUDNN(cudnnGetPooling2dForwardOutputDim((const cudnnPoolingDescriptor_t)handle,\n                                                    descriptor(src),\n                                                    &outN,\n                                                    &outC,\n                                                    &outH,\n                                                    &outW));\n\n\n            dest.set_size(outN,outC,outH,outW);\n\n            DLIB_CASSERT(dest.num_samples() == src.num_samples());\n            DLIB_CASSERT(dest.k() == src.k());\n            DLIB_CASSERT(dest.nr() == 1 + (src.nr() + 2*padding_y - window_height)/stride_y, \n                \"\\n stride_y:  \" << stride_y  <<\n                \"\\n padding_y: \" << padding_y  <<\n                \"\\n window_height: \" << window_height  <<\n                \"\\n src.nr(): \" << src.nr()  <<\n                \"\\n dest.nr(): \" << dest.nr()  <<\n                \"\\n src.nr()/stride_y: \" <<  src.nr()/stride_y); \n            DLIB_CASSERT(dest.nc() == 1 + (src.nc() + 2*padding_x - window_width)/stride_x, \n                \"\\n stride_x:  \" << stride_x  <<\n                \"\\n padding_x: \" << padding_x  <<\n                \"\\n window_width: \" << window_width  <<\n                \"\\n src.nc(): \" << src.nc()  <<\n                \"\\n dest.nc(): \" << dest.nc()  <<\n                \"\\n src.nc()/stride_x: \" <<  src.nc()/stride_x); \n\n            CHECK_CUDNN(cudnnPoolingForward(context(),\n                                     (const cudnnPoolingDescriptor_t)handle,\n                                     &alpha,\n                                     descriptor(src),\n                                     src.device(),\n                                     &beta,\n                                     descriptor(dest),\n                                     dest.device()));\n        }\n\n        void pooling::get_gradient(\n            const tensor& gradient_input, \n            const tensor& dest,\n            const tensor& src,\n            tensor& grad \n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(gradient_input,dest));\n            DLIB_CASSERT(have_same_dimensions(src,grad));\n\n            const float alpha = 1;\n            const float beta = 1;\n            CHECK_CUDNN(cudnnPoolingBackward(context(),\n                                       (const cudnnPoolingDescriptor_t)handle,\n                                       &alpha,\n                                       descriptor(dest),\n                                       dest.device(),\n                                       descriptor(gradient_input),\n                                       gradient_input.device(),\n                                       descriptor(src),\n                                       src.device(),\n                                       &beta,\n                                       descriptor(grad),\n                                       grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax(\n            tensor& dest,\n            const tensor& src,\n            operation_mode mode\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest, src));\n            if (src.size() == 0) return;\n\n            const float alpha = 1;\n            const float beta = 0;\n\n            if (mode == operation_mode::CHANNEL_WISE)\n            {\n                CHECK_CUDNN(cudnnSoftmaxForward(context(),\n                    CUDNN_SOFTMAX_ACCURATE,\n                    CUDNN_SOFTMAX_MODE_CHANNEL,\n                    &alpha,\n                    descriptor(src),\n                    src.device(),\n                    &beta,\n                    descriptor(dest),\n                    dest.device()));\n            }\n            else if (mode == operation_mode::PLANE_WISE)\n            {\n                const long num_samples = src.num_samples();\n                const long num_channels = src.k();\n                const size_t plane_size = src.nr() * src.nc();\n\n                for (long s = 0; s < num_samples; ++s)\n                {\n                    for (long k = 0; k < num_channels; ++k)\n                    {\n                        auto src_slice = src.device() + (s * num_channels + k) * plane_size;\n                        auto dest_slice = dest.device() + (s * num_channels + k) * plane_size;\n                        auto a_src_slice = alias_tensor(src.nr(), src.nc())(src, (s * num_channels + k) * plane_size);\n                        auto a_dest_slice = alias_tensor(dest.nr(), dest.nc())(dest, (s * num_channels + k) * plane_size);\n\n                        CHECK_CUDNN(cudnnSoftmaxForward(context(),\n                            CUDNN_SOFTMAX_ACCURATE,\n                            CUDNN_SOFTMAX_MODE_CHANNEL,\n                            &alpha,\n                            descriptor(a_src_slice),\n                            src_slice,\n                            &beta,\n                            descriptor(a_dest_slice),\n                            dest_slice));\n                    }\n                }\n            }\n        }\n\n        void softmax_gradient(\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            operation_mode mode\n        )\n        {\n            DLIB_CASSERT(\n                have_same_dimensions(dest, gradient_input) == true &&\n                have_same_dimensions(dest, grad) == true);\n            if (dest.size() == 0) return;\n\n            const float alpha = 1;\n            const float beta = is_same_object(grad, gradient_input) ? 0 : 1;\n\n            if (mode == operation_mode::CHANNEL_WISE)\n            {\n                CHECK_CUDNN(cudnnSoftmaxBackward(context(),\n                    CUDNN_SOFTMAX_ACCURATE,\n                    CUDNN_SOFTMAX_MODE_CHANNEL,\n                    &alpha,\n                    descriptor(dest),\n                    dest.device(),\n                    descriptor(gradient_input),\n                    gradient_input.device(),\n                    &beta,\n                    descriptor(grad),\n                    grad.device()));\n            }\n            else if (mode == operation_mode::PLANE_WISE)\n            {\n                const long num_samples = dest.num_samples();\n                const long num_channels = dest.k();\n                const size_t plane_size = dest.nr() * dest.nc();\n\n                for (long s = 0; s < num_samples; ++s)\n                {\n                    for (long k = 0; k < num_channels; ++k)\n                    {\n                        auto dest_slice = dest.device() + (s * num_channels + k) * plane_size;\n                        auto gi_slice = gradient_input.device() + (s * num_channels + k) * plane_size;\n                        auto grad_slice = grad.device() + (s * num_channels + k) * plane_size;\n                        auto a_dest_slice = alias_tensor(dest.nr(), dest.nc())(dest, (s * num_channels + k) * plane_size);\n                        auto a_gi_slice = alias_tensor(gradient_input.nr(), gradient_input.nc())(gradient_input, (s * num_channels + k) * plane_size);\n                        auto a_grad_slice = alias_tensor(grad.nr(), grad.nc())(grad, (s * num_channels + k) * plane_size);\n\n                        CHECK_CUDNN(cudnnSoftmaxBackward(context(),\n                            CUDNN_SOFTMAX_ACCURATE,\n                            CUDNN_SOFTMAX_MODE_CHANNEL,\n                            &alpha,\n                            descriptor(a_dest_slice),\n                            dest_slice,\n                            descriptor(a_gi_slice),\n                            gi_slice,\n                            &beta,\n                            descriptor(a_grad_slice),\n                            grad_slice));\n                    }\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax_all (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            if (src.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = 0;\n\n            CHECK_CUDNN(cudnnSoftmaxForward(context(),\n                                      CUDNN_SOFTMAX_ACCURATE,\n                                      CUDNN_SOFTMAX_MODE_INSTANCE,\n                                      &alpha,\n                                      descriptor(src),\n                                      src.device(),\n                                      &beta,\n                                      descriptor(dest),\n                                      dest.device()));\n        }\n\n\n        void softmax_all_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  have_same_dimensions(dest,gradient_input) == true &&\n                  have_same_dimensions(dest,grad) == true );\n            if (dest.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = is_same_object(grad,gradient_input) ? 0 : 1;\n            CHECK_CUDNN(cudnnSoftmaxBackward(context(),\n                                      CUDNN_SOFTMAX_ACCURATE,\n                                      CUDNN_SOFTMAX_MODE_INSTANCE,\n                                      &alpha,\n                                      descriptor(dest),\n                                      dest.device(),\n                                      descriptor(gradient_input),\n                                      gradient_input.device(),\n                                      &beta,\n                                      descriptor(grad),\n                                      grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        void sigmoid (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            if (src.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = 0;\n            CHECK_CUDNN(cudnnActivationForward(context(),\n                                         sigmoid_activation_descriptor(),\n                                         &alpha,\n                                         descriptor(src),\n                                         src.device(),\n                                         &beta,\n                                         descriptor(dest),\n                                         dest.device()));\n        }\n\n        void sigmoid_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  have_same_dimensions(dest,gradient_input) == true &&\n                  have_same_dimensions(dest,grad) == true );\n            if (dest.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = is_same_object(grad,gradient_input) ? 0 : 1;\n            CHECK_CUDNN(cudnnActivationBackward(context(),\n                                          sigmoid_activation_descriptor(),\n                                          &alpha,\n                                          descriptor(dest),\n                                          dest.device(),\n                                          descriptor(gradient_input),\n                                          gradient_input.device(),\n                                          descriptor(dest),\n                                          dest.device(),\n                                          &beta,\n                                          descriptor(grad),\n                                          grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void relu (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            if (src.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = 0;\n            CHECK_CUDNN(cudnnActivationForward(context(),\n                                         relu_activation_descriptor(),\n                                         &alpha,\n                                         descriptor(src),\n                                         src.device(),\n                                         &beta,\n                                         descriptor(dest),\n                                         dest.device()));\n        }\n\n        void relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  have_same_dimensions(dest,gradient_input) == true &&\n                  have_same_dimensions(dest,grad) == true );\n            if (dest.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = is_same_object(grad,gradient_input) ? 0 : 1;\n            CHECK_CUDNN(cudnnActivationBackward(context(),\n                                          relu_activation_descriptor(),\n                                          &alpha,\n                                          descriptor(dest),\n                                          dest.device(),\n                                          descriptor(gradient_input),\n                                          gradient_input.device(),\n                                          descriptor(dest),\n                                          dest.device(),\n                                          &beta,\n                                          descriptor(grad),\n                                          grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void tanh (\n            tensor& dest,\n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(have_same_dimensions(dest,src));\n            if (src.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = 0;\n            CHECK_CUDNN(cudnnActivationForward(context(),\n                                         tanh_activation_descriptor(),\n                                         &alpha,\n                                         descriptor(src),\n                                         src.device(),\n                                         &beta,\n                                         descriptor(dest),\n                                         dest.device()));\n        }\n\n        void tanh_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        )\n        {\n            DLIB_CASSERT(\n                  have_same_dimensions(dest,gradient_input) == true &&\n                  have_same_dimensions(dest,grad) == true);\n            if (dest.size() == 0)\n                return;\n\n            const float alpha = 1;\n            const float beta = is_same_object(grad,gradient_input) ? 0 : 1;\n            CHECK_CUDNN(cudnnActivationBackward(context(),\n                                          tanh_activation_descriptor(),\n                                          &alpha,\n                                          descriptor(dest),\n                                          dest.device(),\n                                          descriptor(gradient_input),\n                                          gradient_input.device(),\n                                          descriptor(dest),\n                                          dest.device(),\n                                          &beta,\n                                          descriptor(grad),\n                                          grad.device()));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuDNN_CPP_\n\n\n"
  },
  {
    "path": "dlib/cuda/cudnn_dlibapi.h",
    "content": "﻿// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuDNN_H_\n#define DLIB_DNN_CuDNN_H_\n\n#include <memory>\n#include \"operation_mode.h\"\n#ifdef DLIB_USE_CUDA\n#include \"cuda_errors.h\"\n#include \"cuda_data_ptr.h\"\n#endif // DLIB_USE_CUDA\n\nnamespace dlib\n{\n    class tensor;\n    class resizable_tensor;\n\n#ifdef DLIB_USE_CUDA\n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        class tensor_descriptor\n        {\n            /*!\n                Each tensor object will carry a tensor_descriptor in it when compiled with\n                CUDA.\n            !*/\n\n        public:\n            // not copyable\n            tensor_descriptor(const tensor_descriptor&) = delete;\n            tensor_descriptor& operator=(const tensor_descriptor&) = delete;\n            // but is movable\n            tensor_descriptor(tensor_descriptor&& item) : tensor_descriptor() { swap(item); }\n            tensor_descriptor& operator=(tensor_descriptor&& item) { swap(item); return *this; }\n\n            tensor_descriptor();\n            ~tensor_descriptor();\n\n            void set_size(\n                int n, \n                int k,\n                int nr, \n                int nc \n            );\n            /*!\n                ensures\n                    - if any of the arguments are 0 then they are all set to 0 in the tensor.\n            !*/\n\n            void get_size (\n                int& n, \n                int& k,\n                int& nr,\n                int& nc \n            ) const;\n\n            const void* get_handle (\n            ) const { return handle; }\n\n        private:\n\n            void swap(tensor_descriptor& item) { std::swap(handle, item.handle); }\n\n            void* handle;\n        };\n\n        // ------------------------------------------------------------------------------------\n\n        void add(\n            float beta,\n            tensor& dest,\n            float alpha,\n            const tensor& src\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void assign_conv_bias_gradient (\n            tensor& grad,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void batch_normalize_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        );\n\n        void batch_normalize (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        );\n\n        void batch_normalize_gradient(\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void batch_normalize_conv_inference (\n            const double eps,\n            resizable_tensor& dest,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta,\n            const tensor& running_means,\n            const tensor& running_variances\n        );\n\n        void batch_normalize_conv (\n            const double eps,\n            resizable_tensor& dest,\n            resizable_tensor& means,\n            resizable_tensor& invstds,\n            const double averaging_factor,\n            resizable_tensor& running_means,\n            resizable_tensor& running_variances,\n            const tensor& src,\n            const tensor& gamma, \n            const tensor& beta \n        );\n\n        void batch_normalize_conv_gradient(\n            const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n        );\n\n    // ------------------------------------------------------------------------------------\n\n        class tensor_conv\n        {\n        public:\n            tensor_conv(const tensor_conv&) = delete;\n            tensor_conv& operator=(const tensor_conv&) = delete;\n\n            tensor_conv();\n\n            void clear(\n            );\n\n            ~tensor_conv (\n            );\n\n            void operator() (\n                const bool add_to_output,\n                resizable_tensor& output,\n                const tensor& data,\n                const tensor& filters\n            );\n\n            void operator() (\n                const bool add_to_output,\n                tensor& output,\n                const tensor& data,\n                const tensor& filters\n            );\n\n            void operator() (\n                const bool add_to_output,\n                resizable_tensor& output,\n                const tensor& data,\n                const tensor& filters,\n                const tensor& biases,\n                bool use_relu\n            );\n\n            void operator() (\n                const bool add_to_output,\n                tensor& output,\n                const tensor& data,\n                const tensor& filters,\n                const tensor& biases,\n                bool use_relu\n            );\n\n            void get_gradient_for_data (\n                const bool add_to_output,\n                const tensor& gradient_input, \n                const tensor& filters,\n                tensor& data_gradient\n            );\n\n            void get_gradient_for_filters (\n                const bool add_to_output,\n                const tensor& gradient_input, \n                const tensor& data,\n                tensor& filters_gradient\n            );\n\n           void setup(\n                const tensor& data,\n                const tensor& filters,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n           void setup(\n                const tensor& data,\n                const tensor& filters,\n                const tensor& biases,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n        private:\n\n            // These variables record the type of data given to the last call to setup().\n            int stride_y;\n            int stride_x;\n            int padding_y;\n            int padding_x;\n            long data_num_samples, data_k, data_nr, data_nc;\n            long filters_num_samples, filters_k, filters_nr, filters_nc;\n\n\n            void* filter_handle;\n            void* conv_handle;\n\n            // dimensions of the output tensor from operator()\n            int out_num_samples;\n            int out_k;\n            int out_nr;\n            int out_nc;\n\n            enum class allow_cache_use { no, yes };\n\n            // sets the three _algo fields.\n            void select_best_algorithms(const tensor& data, const tensor_descriptor& dest_desc, allow_cache_use allow_cache_use);\n            int forward_algo;\n            int backward_data_algo;\n            int backward_filters_algo;\n\n            // sets the three _workspace_size_in_bytes fields.\n            void update_convolution_data_workspace_sizes(const tensor& data, const tensor_descriptor& dest_desc);\n            size_t forward_workspace_size_in_bytes;\n            size_t backward_data_workspace_size_in_bytes;\n            size_t backward_filters_workspace_size_in_bytes;\n\n            cuda_data_void_ptr forward_workspace;\n            cuda_data_void_ptr backward_data_workspace;\n            cuda_data_void_ptr backward_filters_workspace;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        class pooling\n        {\n        public:\n\n            pooling(const pooling&) = delete;\n            pooling& operator=(const pooling&) = delete;\n\n            pooling (\n            );\n\n            ~pooling(\n            );\n\n            void clear(\n            );\n\n            void setup_max_pooling(\n                int window_height,\n                int window_width,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n            void setup_avg_pooling(\n                int window_height,\n                int window_width,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x\n            );\n\n            bool does_max_pooling(\n            ) const { return do_max_pooling; }\n\n            void operator() (\n                resizable_tensor& dest,\n                const tensor& src\n            );\n\n            void get_gradient(\n                const tensor& gradient_input, \n                const tensor& dest,\n                const tensor& src,\n                tensor& grad \n            );\n\n        private:\n\n            void setup(\n                int window_height,\n                int window_width,\n                int stride_y,\n                int stride_x,\n                int padding_y,\n                int padding_x,\n                int pooling_mode\n            );\n\n            void* handle;\n            int window_height;\n            int window_width;\n            int stride_y;\n            int stride_x;\n            int padding_y;\n            int padding_x;\n            bool do_max_pooling;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax (\n            tensor& dest,\n            const tensor& src,\n            operation_mode mode = operation_mode::CHANNEL_WISE\n        );\n\n        void softmax_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input,\n            operation_mode mode = operation_mode::CHANNEL_WISE\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void softmax_all (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void softmax_all_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void sigmoid (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void sigmoid_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void relu (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void relu_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n        void tanh (\n            tensor& dest,\n            const tensor& src\n        );\n\n        void tanh_gradient (\n            tensor& grad,\n            const tensor& dest,\n            const tensor& gradient_input\n        );\n\n    // ------------------------------------------------------------------------------------\n\n    }\n#endif // DLIB_USE_CUDA\n}\n\n#endif // DLIB_DNN_CuDNN_H_\n\n"
  },
  {
    "path": "dlib/cuda/curand_dlibapi.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuRAND_CPP_\n#define DLIB_DNN_CuRAND_CPP_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"curand_dlibapi.h\"\n#include <curand.h>\n#include \"../string.h\"\n\nstatic const char* curand_get_error_string(curandStatus_t s)\n{\n    switch(s)\n    {\n        case CURAND_STATUS_NOT_INITIALIZED: \n            return \"CUDA Runtime API initialization failed.\";\n        case CURAND_STATUS_LENGTH_NOT_MULTIPLE:\n            return \"The requested length must be a multiple of two.\";\n        default:\n            return \"A call to cuRAND failed\";\n    }\n}\n\n// Check the return value of a call to the cuDNN runtime for an error condition.\n#define CHECK_CURAND(call)                                                      \\\ndo{                                                                              \\\n    const curandStatus_t error = call;                                         \\\n    if (error != CURAND_STATUS_SUCCESS)                                        \\\n    {                                                                          \\\n        std::ostringstream sout;                                               \\\n        sout << \"Error while calling \" << #call << \" in file \" << __FILE__ << \":\" << __LINE__ << \". \";\\\n        sout << \"code: \" << error << \", reason: \" << curand_get_error_string(error);\\\n        throw dlib::curand_error(sout.str());                            \\\n    }                                                                          \\\n}while(false)\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // ----------------------------------------------------------------------------------------\n\n        curand_generator::\n        curand_generator(\n            unsigned long long seed\n        ) : handle(nullptr)\n        {\n            curandGenerator_t gen;\n            CHECK_CURAND(curandCreateGenerator(&gen, CURAND_RNG_PSEUDO_DEFAULT));\n            handle = gen;\n\n            CHECK_CURAND(curandSetPseudoRandomGeneratorSeed(gen, seed));\n        }\n\n        curand_generator::\n        ~curand_generator()\n        {\n            if (handle)\n            {\n                curandDestroyGenerator((curandGenerator_t)handle);\n            }\n        }\n\n        void curand_generator::\n        fill_gaussian (\n            tensor& data,\n            float mean,\n            float stddev\n        )\n        {\n            if (data.size() == 0)\n                return;\n\n            CHECK_CURAND(curandGenerateNormal((curandGenerator_t)handle, \n                                        data.device(),\n                                        data.size(),\n                                        mean,\n                                        stddev));\n        }\n\n        void curand_generator::\n        fill_uniform (\n            tensor& data\n        )\n        {\n            if (data.size() == 0)\n                return;\n\n            CHECK_CURAND(curandGenerateUniform((curandGenerator_t)handle, data.device(), data.size()));\n        }\n\n        void curand_generator::\n        fill (\n            cuda_data_ptr<unsigned int>& data\n        )\n        {\n            if (data.size() == 0)\n                return;\n\n            CHECK_CURAND(curandGenerate((curandGenerator_t)handle, data, data.size()));\n        }\n\n    // -----------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuRAND_CPP_\n\n"
  },
  {
    "path": "dlib/cuda/curand_dlibapi.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuRAND_H_\n#define DLIB_DNN_CuRAND_H_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"tensor.h\"\n#include \"cuda_errors.h\"\n#include \"cuda_data_ptr.h\"\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        class curand_generator\n        {\n        public:\n            // not copyable\n            curand_generator(const curand_generator&) = delete;\n            curand_generator& operator=(const curand_generator&) = delete;\n\n            curand_generator() : curand_generator(0) {}\n            curand_generator(unsigned long long seed);\n            ~curand_generator();\n\n            void fill (\n                cuda_data_ptr<unsigned int>& data\n            );\n            /*!\n                ensures\n                    - Fills data with random 32-bit unsigned integers.\n            !*/\n\n            void fill_gaussian (\n                tensor& data,\n                float mean = 0,\n                float stddev = 1\n            );\n            /*!\n                requires\n                    - data.size()%2 == 0\n                    - stddev >= 0\n                ensures\n                    - Fills data with random numbers drawn from a Gaussian distribution\n                      with the given mean and standard deviation.\n            !*/\n\n            void fill_uniform (\n                tensor& data\n            );\n            /*!\n                ensures\n                    - Fills data with uniform random numbers in the range (0.0, 1.0].\n            !*/\n\n        private:\n\n            void* handle;\n        };\n\n    // -----------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuRAND_H_\n\n\n\n"
  },
  {
    "path": "dlib/cuda/cusolver_dlibapi.cu",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuSOLVER_CU_\n#define DLIB_DNN_CuSOLVER_CU_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"cusolver_dlibapi.h\"\n#include <cublas_v2.h>\n#include <cusolverDn.h>\n#include \"cuda_utils.h\"\n\n// ----------------------------------------------------------------------------------------\n\nstatic const char* cusolver_get_error_string(cusolverStatus_t s)\n{\n    switch(s)\n    {\n        case CUSOLVER_STATUS_NOT_INITIALIZED: \n            return \"CUDA Runtime API initialization failed.\";\n        case CUSOLVER_STATUS_ALLOC_FAILED: \n            return \"CUDA Resources could not be allocated.\";\n        default:\n            return \"A call to cuSolver failed\";\n    }\n}\n\n// Check the return value of a call to the cuSolver runtime for an error condition.\n#define CHECK_CUSOLVER(call)                                                      \\\ndo{                                                                              \\\n    const cusolverStatus_t error = call;                                         \\\n    if (error != CUSOLVER_STATUS_SUCCESS)                                        \\\n    {                                                                          \\\n        std::ostringstream sout;                                               \\\n        sout << \"Error while calling \" << #call << \" in file \" << __FILE__ << \":\" << __LINE__ << \". \";\\\n        sout << \"code: \" << error << \", reason: \" << cusolver_get_error_string(error);\\\n        throw dlib::cusolver_error(sout.str());                                \\\n    }                                                                          \\\n}while(false)\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        class cusolver_context\n        {\n        public:\n            // not copyable\n            cusolver_context(const cusolver_context&) = delete;\n            cusolver_context& operator=(const cusolver_context&) = delete;\n\n            cusolver_context()\n            {\n                handles.resize(16);\n            }\n            ~cusolver_context()\n            {\n                for (auto h : handles)\n                {\n                    if (h)\n                        cusolverDnDestroy(h);\n                }\n            }\n\n            cusolverDnHandle_t get_handle (\n            )  \n            { \n                int new_device_id;\n                CHECK_CUDA(cudaGetDevice(&new_device_id));\n                // make room for more devices if needed\n                if (new_device_id >= (long)handles.size())\n                    handles.resize(new_device_id+16);\n\n                // If we don't have a handle already for this device then make one\n                if (!handles[new_device_id])\n                    CHECK_CUSOLVER(cusolverDnCreate(&handles[new_device_id]));\n\n                // Finally, return the handle for the current device\n                return handles[new_device_id];\n            }\n\n        private:\n\n            std::vector<cusolverDnHandle_t> handles;\n        };\n\n        static cusolverDnHandle_t context()\n        {\n            thread_local cusolver_context c;\n            return c.get_handle();\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        __global__ void _cuda_set_to_identity_matrix(float* m, size_t nr)\n        {\n            for (auto j : grid_stride_range(0, nr*nr))\n            {\n                if (j%(nr+1) == 0)\n                    m[j] = 1;\n                else\n                    m[j] = 0;\n            }\n        }\n\n        void set_to_identity_matrix (\n            tensor& m \n        )\n        {\n            DLIB_CASSERT(m.size() == m.num_samples()*m.num_samples());\n            launch_kernel(_cuda_set_to_identity_matrix, max_jobs(m.size()), m.device(), m.num_samples());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inv::~inv()\n        {\n            sync_if_needed();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void inv::\n        operator() (\n            const tensor& m_,\n            resizable_tensor& out\n        )\n        {\n            DLIB_CASSERT(m_.size() == m_.num_samples()*m_.num_samples(), \"Input matrix must be square if you want to invert it.\");\n            m = m_;\n\n            out.copy_size(m);\n            set_to_identity_matrix(out);\n\n            const int nc = m.num_samples();\n            int Lwork;\n            CHECK_CUSOLVER(cusolverDnSgetrf_bufferSize(context(), nc , nc, m.device(), nc, &Lwork));\n\n            if (Lwork > (int)workspace.size())\n            {\n                sync_if_needed();\n                workspace = cuda_data_ptr<float>(Lwork);\n            }\n            if (nc > (int)Ipiv.size())\n            {\n                sync_if_needed();\n                Ipiv = cuda_data_ptr<int>(nc);\n            }\n            if (info.size() != 1)\n            {\n                info = cuda_data_ptr<int>(1);\n            }\n\n            CHECK_CUSOLVER(cusolverDnSgetrf(context(), nc, nc, m.device(), nc, workspace, Ipiv, info));\n            CHECK_CUSOLVER(cusolverDnSgetrs(context(), CUBLAS_OP_N, nc, nc, m.device(), nc, Ipiv, out.device(), nc, info));\n            did_work_lately = true;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        int inv::\n        get_last_status(\n        )\n        {\n            std::vector<int> linfo; \n            memcpy(linfo, info);\n            if (linfo.size() != 0)\n                return linfo[0];\n            else\n                return 0;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void inv::\n        sync_if_needed()\n        {\n            if (did_work_lately)\n            {\n                did_work_lately = false;\n                // make sure we wait until any previous kernel launches have finished\n                // before we do something like deallocate the GPU memory.\n                cudaDeviceSynchronize();\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuSOLVER_CU_\n\n\n"
  },
  {
    "path": "dlib/cuda/cusolver_dlibapi.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNN_CuSOLVER_H_\n#define DLIB_DNN_CuSOLVER_H_\n\n#ifdef DLIB_USE_CUDA\n\n#include \"tensor.h\"\n#include \"cuda_errors.h\"\n#include \"cuda_data_ptr.h\"\n#include \"../noncopyable.h\"\n\nnamespace dlib\n{\n    namespace cuda \n    {\n\n    // -----------------------------------------------------------------------------------\n\n        class inv : noncopyable\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a functor for doing matrix inversion on the GPU.  The only\n                    reason it's an object is to avoid the reallocation of some GPU memory\n                    blocks if you want to do a bunch of matrix inversions in a row.\n            !*/\n\n        public:\n\n            inv() = default;\n            ~inv();\n\n            void operator() (\n                const tensor& m,\n                resizable_tensor& out\n            );\n            /*!\n                requires\n                    - m.size() == m.num_samples()*m.num_samples()\n                      (i.e. mat(m) must be a square matrix)\n                ensures\n                    - out == inv(mat(m));\n            !*/\n\n            int get_last_status(\n            );\n            /*!\n                ensures\n                    - returns 0 if the last matrix inversion was successful and != 0\n                      otherwise.\n            !*/\n\n        private:\n\n            void sync_if_needed();\n\n            bool did_work_lately = false;\n            resizable_tensor m;\n            cuda_data_ptr<float> workspace;\n            cuda_data_ptr<int> Ipiv;\n            cuda_data_ptr<int> info;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n    }  \n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_DNN_CuSOLVER_H_\n\n\n\n"
  },
  {
    "path": "dlib/cuda/gpu_data.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GPU_DaTA_CPP_\n#define DLIB_GPU_DaTA_CPP_\n\n// Only things that require CUDA are declared in this cpp file.  Everything else is in the\n// gpu_data.h header so that it can operate as \"header-only\" code when using just the CPU.\n#ifdef DLIB_USE_CUDA\n\n#include \"gpu_data.h\"\n#include <iostream>\n#include \"cuda_utils.h\"\n#include <cstring>\n#include <cuda.h>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void memcpy (\n        gpu_data& dest, \n        const gpu_data& src\n    )\n    {\n        DLIB_CASSERT(dest.size() == src.size());\n        if (src.size() == 0 || &dest == &src)\n            return;\n\n        memcpy(dest,0, src, 0, src.size());\n    }\n\n    void memcpy (\n        gpu_data& dest, \n        size_t dest_offset,\n        const gpu_data& src,\n        size_t src_offset,\n        size_t num\n    )\n    {\n        DLIB_CASSERT(dest_offset + num <= dest.size());\n        DLIB_CASSERT(src_offset + num <= src.size());\n        if (num == 0)\n            return;\n\n        // if there is aliasing\n        if (&dest == &src && std::max(dest_offset, src_offset) < std::min(dest_offset,src_offset)+num)\n        {\n            // if they perfectly alias each other then there is nothing to do\n            if (dest_offset == src_offset)\n                return;\n            else\n                std::memmove(dest.host()+dest_offset, src.host()+src_offset, sizeof(float)*num);\n        }\n        else\n        {\n            // if we write to the entire thing then we can use device_write_only()\n            if (dest_offset == 0 && num == dest.size())\n            {\n                // copy the memory efficiently based on which copy is current in each object.\n                if (src.device_ready())\n                    CHECK_CUDA(cudaMemcpy(dest.device_write_only(), src.device()+src_offset,  num*sizeof(float), cudaMemcpyDeviceToDevice));\n                else \n                    CHECK_CUDA(cudaMemcpy(dest.device_write_only(), src.host()+src_offset,    num*sizeof(float), cudaMemcpyHostToDevice));\n            }\n            else\n            {\n                // copy the memory efficiently based on which copy is current in each object.\n                if (dest.device_ready() && src.device_ready())\n                    CHECK_CUDA(cudaMemcpy(dest.device()+dest_offset, src.device()+src_offset, num*sizeof(float), cudaMemcpyDeviceToDevice));\n                else if (!dest.device_ready() && src.device_ready())\n                    CHECK_CUDA(cudaMemcpy(dest.host()+dest_offset, src.device()+src_offset,   num*sizeof(float), cudaMemcpyDeviceToHost));\n                else if (dest.device_ready() && !src.device_ready())\n                    CHECK_CUDA(cudaMemcpy(dest.device()+dest_offset, src.host()+src_offset,   num*sizeof(float), cudaMemcpyHostToDevice));\n                else \n                    CHECK_CUDA(cudaMemcpy(dest.host()+dest_offset, src.host()+src_offset,     num*sizeof(float), cudaMemcpyHostToHost));\n            }\n        }\n    }\n// ----------------------------------------------------------------------------------------\n\n    void synchronize_stream(cudaStream_t stream)\n    {\n#if !defined CUDA_VERSION\n#error CUDA_VERSION not defined\n#elif CUDA_VERSION >= 9020 && CUDA_VERSION < 11000\n        // We will stop using this alternative version with cuda V11, hopefully the bug in\n        // cudaStreamSynchronize is fixed by then.\n        //\n        // This should be pretty much the same as cudaStreamSynchronize, which for some\n        // reason makes training freeze in some cases.\n        // (see https://github.com/davisking/dlib/issues/1513)\n        while (true)\n        {\n            cudaError_t err = cudaStreamQuery(stream);\n            switch (err)\n            {\n            case cudaSuccess: return;      // now we are synchronized\n            case cudaErrorNotReady: break; // continue waiting\n            default: CHECK_CUDA(err);      // unexpected error: throw\n            }\n        }\n#else // CUDA_VERSION\n        CHECK_CUDA(cudaStreamSynchronize(stream));\n#endif // CUDA_VERSION\n    }\n\n    void gpu_data::\n    wait_for_transfer_to_finish() const\n    {\n        if (have_active_transfer)\n        {\n            synchronize_stream((cudaStream_t)cuda_stream.get());\n            have_active_transfer = false;\n            // Check for errors.  These calls to cudaGetLastError() are what help us find\n            // out if our kernel launches have been failing.\n            CHECK_CUDA(cudaGetLastError());\n        }\n    }\n\n    void gpu_data::\n    copy_to_device() const\n    {\n        // We want transfers to the device to always be concurrent with any device\n        // computation.  So we use our non-default stream to do the transfer.\n        async_copy_to_device();\n        wait_for_transfer_to_finish();\n    }\n\n    void gpu_data::\n    copy_to_host() const\n    {\n        if (!host_current)\n        {\n            wait_for_transfer_to_finish();\n            CHECK_CUDA(cudaMemcpy(data_host.get(), data_device.get(), data_size*sizeof(float), cudaMemcpyDeviceToHost));\n            host_current = true;\n            // At this point we know our RAM block isn't in use because cudaMemcpy()\n            // implicitly syncs with the device. \n            device_in_use = false;\n            // Check for errors.  These calls to cudaGetLastError() are what help us find\n            // out if our kernel launches have been failing.\n            CHECK_CUDA(cudaGetLastError());\n        }\n    }\n\n    void gpu_data::\n    async_copy_to_device() const\n    {\n        if (!device_current)\n        {\n            if (device_in_use)\n            {\n                // Wait for any possible CUDA kernels that might be using our memory block to\n                // complete before we overwrite the memory.\n                synchronize_stream(0);\n                device_in_use = false;\n            }\n            CHECK_CUDA(cudaMemcpyAsync(data_device.get(), data_host.get(), data_size*sizeof(float), cudaMemcpyHostToDevice, (cudaStream_t)cuda_stream.get()));\n            have_active_transfer = true;\n            device_current = true;\n        }\n    }\n\n    void gpu_data::\n    set_size(\n        size_t new_size\n    )\n    {\n        if (new_size == 0)\n        {\n            if (device_in_use)\n            {\n                // Wait for any possible CUDA kernels that might be using our memory block to\n                // complete before we free the memory.\n                synchronize_stream(0);\n                device_in_use = false;\n            }\n            wait_for_transfer_to_finish();\n            data_size = 0;\n            host_current = true;\n            device_current = true;\n            device_in_use = false;\n            data_host.reset();\n            data_device.reset();\n        }\n        else if (new_size != data_size)\n        {\n            if (device_in_use)\n            {\n                // Wait for any possible CUDA kernels that might be using our memory block to\n                // complete before we free the memory.\n                synchronize_stream(0);\n                device_in_use = false;\n            }\n            wait_for_transfer_to_finish();\n            data_size = new_size;\n            host_current = true;\n            device_current = true;\n            device_in_use = false;\n\n            try\n            {\n                CHECK_CUDA(cudaGetDevice(&the_device_id));\n\n                // free memory blocks before we allocate new ones.\n                data_host.reset();\n                data_device.reset();\n\n                void* data;\n                CHECK_CUDA(cudaMallocHost(&data, new_size*sizeof(float)));\n                // Note that we don't throw exceptions since the free calls are invariably\n                // called in destructors.  They also shouldn't fail anyway unless someone\n                // is resetting the GPU card in the middle of their program.\n                data_host.reset((float*)data, [](float* ptr){\n                    auto err = cudaFreeHost(ptr);\n                    if(err!=cudaSuccess)\n                        std::cerr << \"cudaFreeHost() failed. Reason: \" << cudaGetErrorString(err) << std::endl;\n                });\n\n                CHECK_CUDA(cudaMalloc(&data, new_size*sizeof(float)));\n                data_device.reset((float*)data, [](float* ptr){\n                    auto err = cudaFree(ptr);\n                    if(err!=cudaSuccess)\n                        std::cerr << \"cudaFree() failed. Reason: \" << cudaGetErrorString(err) << std::endl;\n                });\n\n                if (!cuda_stream)\n                {\n                    cudaStream_t cstream;\n                    CHECK_CUDA(cudaStreamCreateWithFlags(&cstream, cudaStreamNonBlocking));\n                    cuda_stream.reset(cstream, [](void* ptr){\n                        auto err = cudaStreamDestroy((cudaStream_t)ptr);\n                        if(err!=cudaSuccess)\n                            std::cerr << \"cudaStreamDestroy() failed. Reason: \" << cudaGetErrorString(err) << std::endl;\n                    });\n                }\n\n            }\n            catch(...)\n            {\n                set_size(0);\n                throw;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_USE_CUDA\n\n#endif // DLIB_GPU_DaTA_CPP_\n\n"
  },
  {
    "path": "dlib/cuda/gpu_data.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GPU_DaTA_H_\n#define DLIB_GPU_DaTA_H_\n\n#include \"gpu_data_abstract.h\"\n#include <memory>\n#include <cstring>\n#include \"cuda_errors.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class gpu_data \n    {\n        /*!\n            CONVENTION\n                - if (size() != 0) then\n                    - data_host == a pointer to size() floats in CPU memory.\n                - if (data_device) then \n                    - data_device == a pointer to size() floats in device memory.\n\n                - if (there might be an active async transfer from host to device) then\n                    - have_active_transfer == true\n\n                - We use the host_current and device_current bools to keep track of which\n                  copy of the data (or both) are most current.  e.g. if the CPU has\n                  modified the data and it hasn't been copied to the device yet then\n                  host_current==true and device_current==false.\n\n                  Similarly, we use device_in_use==true to indicate that device() has been\n                  called and no operation to wait for all CUDA kernel completion has been\n                  executed.  So if device_in_use==true then there might be a CUDA kernel\n                  executing that is using the device memory block contained in this object.\n\n        !*/\n    public:\n\n        gpu_data(\n        ) : data_size(0), host_current(true), device_current(true),have_active_transfer(false),device_in_use(false), the_device_id(0)\n        {\n        }\n\n        // Not copyable\n        gpu_data(const gpu_data&) = delete;\n        gpu_data& operator=(const gpu_data&) = delete;\n\n        // but is movable\n        gpu_data(gpu_data&& item) : gpu_data() { swap(item); }\n        gpu_data& operator=(gpu_data&& item) { swap(item); return *this; }\n\n        int device_id() const { return the_device_id; }\n\n#ifdef DLIB_USE_CUDA\n        void async_copy_to_device() const; \n        void set_size(size_t new_size);\n#else\n        // Note that calls to host() or device() will block until any async transfers are complete.\n        void async_copy_to_device() const{}\n\n        void set_size(size_t new_size)\n        {\n            if (new_size == 0)\n            {\n                data_size = 0;\n                host_current = true;\n                device_current = true;\n                device_in_use = false;\n                data_host.reset();\n                data_device.reset();\n            }\n            else if (new_size != data_size)\n            {\n                data_size = new_size;\n                host_current = true;\n                device_current = true;\n                device_in_use = false;\n                data_host.reset(new float[new_size], std::default_delete<float[]>());\n                data_device.reset();\n            }\n        }\n#endif\n\n        const float* host() const \n        { \n            copy_to_host();\n            return data_host.get(); \n        }\n\n        float* host() \n        {\n            copy_to_host();\n            device_current = false;\n            return data_host.get(); \n        }\n\n        float* host_write_only() \n        {\n            host_current = true;\n            device_current = false;\n            return data_host.get(); \n        }\n\n        const float* device() const \n        { \n#ifndef DLIB_USE_CUDA\n            DLIB_CASSERT(false, \"CUDA NOT ENABLED\");\n#endif\n            copy_to_device();\n            device_in_use = true;\n            return data_device.get(); \n        }\n\n        float* device() \n        {\n#ifndef DLIB_USE_CUDA\n            DLIB_CASSERT(false, \"CUDA NOT ENABLED\");\n#endif\n            copy_to_device();\n            host_current = false;\n            device_in_use = true;\n            return data_device.get(); \n        }\n\n        float* device_write_only()\n        {\n#ifndef DLIB_USE_CUDA\n            DLIB_CASSERT(false, \"CUDA NOT ENABLED\");\n#endif\n            wait_for_transfer_to_finish();\n            host_current = false;\n            device_current = true;\n            device_in_use = true;\n            return data_device.get(); \n        }\n\n        bool host_ready (\n        ) const { return host_current; }\n\n        bool device_ready (\n        ) const { return device_current && !have_active_transfer; }\n\n        size_t size() const { return data_size; }\n\n        void swap (gpu_data& item)\n        {\n            std::swap(data_size, item.data_size);\n            std::swap(host_current, item.host_current);\n            std::swap(device_current, item.device_current);\n            std::swap(have_active_transfer, item.have_active_transfer);\n            std::swap(data_host, item.data_host);\n            std::swap(data_device, item.data_device);\n            std::swap(cuda_stream, item.cuda_stream);\n            std::swap(the_device_id, item.the_device_id);\n        }\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        void copy_to_device() const;\n        void copy_to_host() const;\n        void wait_for_transfer_to_finish() const;\n#else\n        void copy_to_device() const{}\n        void copy_to_host() const{}\n        void wait_for_transfer_to_finish() const{}\n#endif\n\n\n        size_t data_size;\n        mutable bool host_current;\n        mutable bool device_current;\n        mutable bool have_active_transfer;\n        mutable bool device_in_use;\n\n        std::shared_ptr<float> data_host;\n        std::shared_ptr<float> data_device;\n        std::shared_ptr<void> cuda_stream;\n        int the_device_id;\n    };\n\n    inline void serialize(const gpu_data& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.size(), out);\n        auto data = item.host();\n        for (size_t i = 0; i < item.size(); ++i)\n            serialize(data[i], out);\n    }\n\n    inline void deserialize(gpu_data& item, std::istream& in)\n    {\n        int version;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::gpu_data.\");\n        size_t s;\n        deserialize(s, in);\n        item.set_size(s);\n        auto data = item.host();\n        for (size_t i = 0; i < item.size(); ++i)\n            deserialize(data[i], in);\n    }\n\n#ifdef DLIB_USE_CUDA\n    void memcpy (gpu_data& dest, const gpu_data& src);\n\n    void memcpy (\n        gpu_data& dest, \n        size_t dest_offset,\n        const gpu_data& src,\n        size_t src_offset,\n        size_t num\n    );\n\n#else\n\n    inline void memcpy (gpu_data& dest, const gpu_data& src)\n    {\n        DLIB_CASSERT(dest.size() == src.size());\n        if (src.size() == 0 || &dest == &src)\n            return;\n        std::memcpy(dest.host_write_only(), src.host(), sizeof(float)*src.size());\n    }\n\n    inline void memcpy (\n        gpu_data& dest, \n        size_t dest_offset,\n        const gpu_data& src,\n        size_t src_offset,\n        size_t num\n    )\n    {\n        DLIB_CASSERT(dest_offset + num <= dest.size());\n        DLIB_CASSERT(src_offset + num <= src.size());\n        if (num == 0)\n            return;\n        if (&dest == &src && std::max(dest_offset, src_offset) < std::min(dest_offset,src_offset)+num)\n        {\n            // if they perfectly alias each other then there is nothing to do\n            if (dest_offset == src_offset)\n                return;\n            else\n                std::memmove(dest.host()+dest_offset, src.host()+src_offset, sizeof(float)*num);\n        }\n        else\n        {\n            // if we write to the entire thing then we can use host_write_only()\n            if (dest_offset == 0 && num == dest.size())\n                std::memcpy(dest.host_write_only(), src.host()+src_offset, sizeof(float)*num);\n            else\n                std::memcpy(dest.host()+dest_offset, src.host()+src_offset, sizeof(float)*num);\n        }\n    }\n#endif\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GPU_DaTA_H_\n\n"
  },
  {
    "path": "dlib/cuda/gpu_data_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GPU_DaTA_ABSTRACT_H_\n#ifdef DLIB_GPU_DaTA_ABSTRACT_H_\n\n#include \"cuda_errors.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class gpu_data \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a block of size() floats, all stored contiguously in memory.\n                Importantly, it keeps two copies of the floats, one on the host CPU side\n                and another on the GPU device side. It automatically performs the necessary\n                host/device transfers to keep these two copies of the data in sync.\n\n                All transfers to the device happen asynchronously with respect to the\n                default CUDA stream so that CUDA kernel computations can overlap with data\n                transfers.  However, any transfers from the device to the host happen\n                synchronously in the default CUDA stream.  Therefore, you should perform\n                all your CUDA kernel launches on the default stream so that transfers back\n                to the host do not happen before the relevant computations have completed.\n\n                If DLIB_USE_CUDA is not #defined then this object will not use CUDA at all.\n                Instead, it will simply store one host side memory block of floats.  \n\n            THREAD SAFETY\n                Instances of this object are not thread-safe.  So don't touch one from\n                multiple threads at the same time.\n        !*/\n    public:\n\n        gpu_data(\n        );\n        /*!\n            ensures\n                - #size() == 0\n                - #host() == nullptr \n                - #device() == nullptr \n                - #host_ready() == true\n                - #device_ready() == true\n                - #device_id() == 0\n        !*/\n\n        // This object is not copyable, however, it is movable.\n        gpu_data(const gpu_data&) = delete;\n        gpu_data& operator=(const gpu_data&) = delete;\n        gpu_data(gpu_data&& item);\n        gpu_data& operator=(gpu_data&& item);\n\n        int device_id(\n        ) const; \n        /*!\n            ensures\n                - returns the ID of the CUDA device that allocated this memory. I.e. the\n                  number returned by cudaGetDevice() when the memory was allocated.\n                - If CUDA is not being used then this function always returns 0.\n        !*/\n\n        void async_copy_to_device(\n        ); \n        /*!\n            ensures\n                - if (!device_ready()) then\n                    - Begins asynchronously copying host data to the device once it is safe\n                      to do so.  I.e. This function will wait until any previously\n                      scheduled CUDA kernels, which are using the device() memory block,\n                      have completed before transferring the new data to the device.\n                    - A call to device() that happens before the transfer completes will\n                      block until the transfer is complete.  That is, it is safe to call\n                      async_copy_to_device() and then immediately call device().\n        !*/\n\n        void set_size(\n            size_t new_size\n        );\n        /*!\n            ensures\n                - #size() == new_size\n        !*/\n\n        bool host_ready (\n        ) const;\n        /*!\n            ensures\n                - returns true if and only if the host's copy of the data is current.  The\n                  host's data is current if there aren't any modifications to the data\n                  which were made on the device side that have yet to be copied to the\n                  host.\n        !*/\n\n        bool device_ready (\n        ) const; \n        /*!\n            ensures\n                - returns true if and only if the device's copy of the data is current.\n                  The device's data is current if there aren't any modifications to the\n                  data which were made on the host side that have yet to be copied to the\n                  device.\n        !*/\n\n        const float* host(\n        ) const;\n        /*!\n            ensures\n                - returns a pointer to the host memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (!host_ready()) then\n                    - copies the data from the device to the host, while this is happening\n                      the call to host() blocks. \n                - #host_ready() == true \n        !*/\n\n        float* host(\n        );\n        /*!\n            ensures\n                - returns a pointer to the host memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (!host_ready()) then\n                    - copies the data from the device to the host, while this is happening\n                      the call to host() blocks. \n                - #host_ready() == true \n                - #device_ready() == false\n                  I.e. Marks the device side data as out of date so that the next call to\n                  device() will perform a host to device transfer.  If you want to begin\n                  the transfer immediately then you can call async_copy_to_device() after\n                  calling host().\n        !*/\n\n        float* host_write_only(\n        );\n        /*!\n            ensures\n                - This function returns the same pointer as host(), except that it never\n                  performs a device to host memory copy.  Instead, it immediately marks the\n                  device side data as out of date, effectively discarding it.  Therefore,\n                  the values in the data pointed to by host_write_only() are undefined and\n                  you should only call host_write_only() if you are going to assign to\n                  every memory location in the returned memory block.  \n                - #host_ready() == true\n                - #device_ready() == false \n        !*/\n\n        const float* device(\n        ) const;\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - returns a pointer to the device memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (!device_ready()) then\n                    - copies the data from the host to the device, while this is happening\n                      the call to device() blocks. \n                - #device_ready() == true\n        !*/\n\n        float* device(\n        );\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - returns a pointer to the device memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (!device_ready()) then\n                    - copies the data from the host to the device, while this is happening\n                      the call to device() blocks. \n                - #host_ready() == false\n                - #device_ready() == true\n        !*/\n\n        float* device_write_only(\n        );\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - This function returns the same pointer as device(), except that it never\n                  performs a host to device memory copy.  Instead, it immediately marks the\n                  host side data as out of date, effectively discarding it.  Therefore, the\n                  values in the data pointed to by device_write_only() are undefined and\n                  you should only call device_write_only() if you are going to assign to\n                  every memory location in the returned memory block.  \n                - #host_ready() == false \n                - #device_ready() == true \n        !*/\n\n\n        size_t size(\n        ) const; \n        /*!\n            ensures\n                - returns the number of floats contained in this object.\n        !*/\n\n        void swap (\n            gpu_data& item\n        );\n        /*!\n            ensures\n                - swaps the state of *this and item\n        !*/\n\n    };\n\n    void serialize(const gpu_data& item, std::ostream& out);\n    void deserialize(gpu_data& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n    void memcpy (\n        gpu_data& dest, \n        const gpu_data& src\n    );\n    /*!\n        requires\n            - dest.size() == src.size()\n        ensures\n            - Copies the data in src to dest.  If the device data is current (i.e.\n              device_ready()==true) on both src and dest then the copy will happen entirely\n              on the device side.\n            - It doesn't matter what GPU device is selected by cudaSetDevice().  You can\n              always copy gpu_data objects to and from each other regardless.\n            - This function blocks until the copy has completed.\n    !*/\n\n    void memcpy (\n        gpu_data& dest, \n        size_t dest_offset,\n        const gpu_data& src,\n        size_t src_offset,\n        size_t num\n    );\n    /*!\n        requires\n            - dest_offset + num <= dest.size()\n            - src_offset  + num <= src.size()\n        ensures\n            - Copies the data in src to dest, but only copies data in the range\n              [src.host()+src_offset, src.host()+src_offset+num) to\n              [dest.host()+dest_offset, dest.host()+dest_offset+num).  Therefore, it is\n              just like the above memcpy() except that you can specify some subset of data\n              in a gpu_data object to be copied.\n            - Like the above version of memcpy(), the copy will happen in the most\n              efficient way, automatically using the appropriate type of host/device\n              transfers based on where data is currently resident. \n            - It doesn't matter what GPU device is selected by cudaSetDevice().  You can\n              always copy gpu_data objects to and from each other regardless.\n            - This function blocks until the copy has completed.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GPU_DaTA_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/cuda/operation_mode.h",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CUDA_OPERATION_MODE_H\n#define DLIB_CUDA_OPERATION_MODE_H\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        This enum is used to determine the mode of operation for certain functions\n        (such as gemm and softmax) in Dlib. It specifies whether the calculation\n        should be performed based on the matrix field in nr()xnc() or if the matrix\n        should be considered in num_samples()xk(). This helps in organizing tensor\n        computations more efficiently according to the required dimensions.\n    */\n    enum class operation_mode { CHANNEL_WISE = 0, PLANE_WISE = 1 };\n\n// ----------------------------------------------------------------------------------------\n\n} // namespace dlib\n\n#endif // DLIB_CUDA_OPERATION_MODE_H"
  },
  {
    "path": "dlib/cuda/tensor.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_TENSOR_H_\n#define DLIB_DNn_TENSOR_H_\n\n#include \"tensor_abstract.h\"\n#include <cstring>\n#include \"../matrix.h\"\n#include \"cudnn_dlibapi.h\"\n#include \"gpu_data.h\"\n#include \"../byte_orderer.h\"\n#include <memory>\n#include \"../any.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class tensor;\n    namespace cuda\n    {\n        void set_tensor (\n            tensor& t,\n            float value\n        );\n\n        void scale_tensor (\n            tensor& t,\n            float value\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class tensor\n    {\n    public:\n\n        tensor (\n        ) : \n            m_n(0), m_k(0), m_nr(0), m_nc(0), m_size(0)\n        {\n        }\n\n        virtual ~tensor() {}\n\n        long long num_samples() const { return m_n; }\n        long long k() const { return m_k; }\n        long long nr() const { return m_nr; }\n        long long nc() const { return m_nc; }\n        size_t size() const { return m_size; }\n\n        typedef float* iterator;\n        typedef const float* const_iterator;\n        iterator       begin()       { return host(); }\n        const_iterator begin() const { return host(); }\n        iterator       end()         { return host()+size(); }\n        const_iterator end() const   { return host()+size(); }\n\n        void async_copy_to_device() const\n        {\n            data().async_copy_to_device();\n        }\n\n        virtual const float* host() const = 0;\n        virtual float*       host() = 0; \n        virtual float*       host_write_only() = 0;\n        virtual const float* device() const = 0;\n        virtual float*       device() = 0;\n        virtual float*       device_write_only() = 0;\n\n        virtual const any&   annotation() const = 0;\n        virtual any&         annotation() = 0;\n\n        int device_id() const { return data().device_id(); }\n\n        tensor& operator= (float val)\n        {\n#ifdef DLIB_USE_CUDA\n            // If you are using CUDA then presumably you will be mostly using tensors on\n            // the GPU.  So unless you seem to be actively working with the host side's\n            // data then we do this initialization on the device side since this avoids a\n            // host to device transfer that would likely immediately follow.\n            if (data().device_ready())\n            {\n                cuda::set_tensor(*this, val);\n                return *this;\n            }\n#endif\n            auto d = host_write_only();\n            for (size_t i = 0; i < size(); ++i)\n                d[i] = val;\n\n            return *this;\n        }\n\n        tensor& operator*= (float val)\n        {\n#ifdef DLIB_USE_CUDA\n            cuda::scale_tensor(*this, val);\n            return *this;\n#else\n            for (auto& d : *this)\n                d *= val;\n\n            return *this;\n#endif\n        }\n        \n        tensor& operator/= (float val)\n        {\n            *this *= 1.f/val;\n            return *this;\n        }\n\n        template <typename EXP>\n        tensor& operator= (const matrix_exp<EXP>& item)\n        {\n            DLIB_CASSERT(num_samples() == item.nr() &&\n                         nr()*nc()*k() == item.nc());\n            static_assert((is_same_type<float, typename EXP::type>::value == true),\n                \"To assign a matrix to a tensor the matrix must contain float values\");\n\n            set_ptrm(host_write_only(), m_n, m_nr*m_nc*m_k) = item;\n            return *this;\n        }\n\n        template <typename EXP>\n        tensor& operator+= (const matrix_exp<EXP>& item)\n        {\n            DLIB_CASSERT(num_samples() == item.nr() &&\n                         nr()*nc()*k() == item.nc());\n            static_assert((is_same_type<float, typename EXP::type>::value == true),\n                \"To assign a matrix to a tensor the matrix must contain float values\");\n            set_ptrm(host(), m_n, m_nr*m_nc*m_k) += item;\n            return *this;\n        }\n\n        template <typename EXP>\n        tensor& operator-= (const matrix_exp<EXP>& item)\n        {\n            DLIB_CASSERT(num_samples() == item.nr() &&\n                         nr()*nc()*k() == item.nc());\n            static_assert((is_same_type<float, typename EXP::type>::value == true),\n                \"To assign a matrix to a tensor the matrix must contain float values\");\n            set_ptrm(host(), m_n, m_nr*m_nc*m_k) -= item;\n            return *this;\n        }\n\n        template <typename EXP>\n        void set_sample (\n            unsigned long long idx,\n            const matrix_exp<EXP>& item\n        )\n        {\n            DLIB_CASSERT(idx < (unsigned long long)num_samples());\n            DLIB_CASSERT(item.size() == nr()*nc()*k());\n            static_assert((is_same_type<float, typename EXP::type>::value == true),\n                \"To assign a matrix to a tensor the matrix must contain float values\");\n            set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) = item;\n        }\n\n\n        template <typename EXP>\n        void add_to_sample (\n            unsigned long long idx,\n            const matrix_exp<EXP>& item\n        )\n        {\n            DLIB_CASSERT(idx < (unsigned long long)num_samples());\n            DLIB_CASSERT(item.size() == nr()*nc()*k());\n            static_assert((is_same_type<float, typename EXP::type>::value == true),\n                \"To assign a matrix to a tensor the matrix must contain float values\");\n            set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) += item;\n        }\n\n\n#ifdef DLIB_USE_CUDA\n        virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor (\n        ) const = 0; \n#endif\n\n        friend void memcpy (\n            tensor& dest, \n            const tensor& src\n        )\n        {\n            DLIB_CASSERT(dest.size() == src.size());\n            memcpy(dest.data(), dest.get_alias_offset(),  \n                   src.data(),  src.get_alias_offset(), \n                   src.size());\n        }\n\n\n    protected:\n\n        friend class alias_tensor;\n\n        virtual gpu_data& data() = 0;\n        virtual const gpu_data& data() const = 0;\n        virtual size_t get_alias_offset() const { return 0; } // needed by alias_tensor.\n\n        long long m_n;\n        long long m_k;\n        long long m_nr;\n        long long m_nc;\n        long long m_size; // always equal to m_n*m_k*m_nr*m_nc\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool is_vector (\n        const tensor& t\n    )\n    {\n        return t.size() == (size_t)t.num_samples() ||\n               t.size() == (size_t)t.k() ||\n               t.size() == (size_t)t.nr() ||\n               t.size() == (size_t)t.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const matrix_op<op_pointer_to_mat<float> > mat (\n        const tensor& t,\n        long long nr,\n        long long nc\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0 , \n                    \"\\tconst matrix_exp mat(tensor, nr, nc)\"\n                    << \"\\n\\t nr and nc must be >= 0\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n        );\n        DLIB_ASSERT(nr*nc == (long long)t.size() , \n                    \"\\tconst matrix_exp mat(tensor, nr, nc)\"\n                    << \"\\n\\t The sizes don't match up.\"\n                    << \"\\n\\t nr*nc:    \" << nr*nc\n                    << \"\\n\\t t.size(): \" << t.size()\n        );\n        typedef op_pointer_to_mat<float> op;\n        return matrix_op<op>(op(t.host(),nr,nc));\n    }\n\n    inline const matrix_op<op_pointer_to_mat<float> > mat (\n        const tensor& t\n    )\n    {\n        if (t.size() != 0)\n            return mat(t, t.num_samples(), t.size()/t.num_samples());\n        else\n            return mat((float*)0,0,0);\n    }\n\n    inline const matrix_op<op_pointer_to_mat<float> > image_plane (\n        const tensor& t,\n        long long sample = 0,\n        long long k = 0\n    )\n    {\n        DLIB_ASSERT(0 <= sample && sample < t.num_samples() &&\n                    0 <= k && k < t.k() &&\n                    t.size() != 0, \n                    \"\\tconst matrix_exp image_plane(tensor,sample,k)\"\n                    << \"\\n\\t Invalid arguments were given to this function.\"\n                    << \"\\n\\t sample: \" << sample\n                    << \"\\n\\t k:      \" << k \n                    << \"\\n\\t t.num_samples(): \" << t.num_samples() \n                    << \"\\n\\t t.k():           \" << t.k() \n                    << \"\\n\\t t.size():        \" << t.size() \n        );\n\n\n        typedef op_pointer_to_mat<float> op;\n        return matrix_op<op>(op(t.host() + ((sample*t.k() + k)*t.nr())*t.nc(), \n                                t.nr(), \n                                t.nc()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool have_same_dimensions (\n        const tensor& a,\n        const tensor& b\n    )\n    {\n        return a.num_samples() == b.num_samples() &&\n               a.k()  == b.k() &&\n               a.nr() == b.nr() &&\n               a.nc() == b.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class resizable_tensor : public tensor\n    {\n    public:\n        resizable_tensor(\n        )\n        {}\n\n        template <typename EXP>\n        resizable_tensor(\n            const matrix_exp<EXP>& item\n        )\n        {\n            set_size(item.nr(), item.nc());\n            *this = item;\n        }\n\n        explicit resizable_tensor(\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        ) \n        {\n            DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0);\n\n            set_size(n_,k_,nr_,nc_);\n        }\n\n        resizable_tensor(const resizable_tensor& item) : _annotation(item.annotation()) \n        {\n            copy_size(item);\n            memcpy(*this, item);\n        }\n        resizable_tensor(const tensor& item) : _annotation(item.annotation()) \n        {\n            copy_size(item);\n            memcpy(*this, item);\n        }\n\n        resizable_tensor(resizable_tensor&& item) { swap(item); }\n        resizable_tensor& operator=(resizable_tensor&& item) { swap(item); return *this; }\n\n        virtual const float* host() const { return data_instance.host(); }\n        virtual float*       host()       { return data_instance.host(); }\n        virtual float*       host_write_only() { return data_instance.host_write_only(); }\n        virtual const float* device() const { return data_instance.device(); }\n        virtual float*       device()       { return data_instance.device(); }\n        virtual float*       device_write_only() { return data_instance.device_write_only(); }\n\n        virtual const any&   annotation() const { return _annotation; }\n        virtual any&         annotation() { return _annotation; }\n\n        void clear(\n        )\n        {\n            set_size(0,0,0,0);\n            _annotation.clear();\n            // free underlying memory\n            data_instance.set_size(0);\n        }\n\n        void copy_size (\n            const tensor& item\n        )\n        {\n            set_size(item.num_samples(), item.k(), item.nr(), item.nc());\n        }\n\n        resizable_tensor& operator= (float val)\n        {\n            tensor::operator=(val);\n            return *this;\n        }\n\n        template <typename EXP>\n        resizable_tensor& operator= (\n            const matrix_exp<EXP>& item\n        )\n        {\n            if (!(num_samples() == item.nr() && k()*nr()*nc() == item.nc()))\n                set_size(item.nr(), item.nc());\n            tensor::operator=(item);\n            return *this;\n        }\n\n        void set_size(\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        )\n        {\n            DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0);\n\n            m_n = n_;\n            m_k = k_;\n            m_nr = nr_;\n            m_nc = nc_;\n            m_size = n_*k_*nr_*nc_;\n            if ((long long)data_instance.size() < m_size)\n                data_instance.set_size(m_size);\n#ifdef DLIB_USE_CUDA\n            cudnn_descriptor.set_size(m_n,m_k,m_nr,m_nc);\n#endif\n        }\n\n\n        resizable_tensor& operator= (const resizable_tensor& item) \n        {\n            resizable_tensor temp(item);\n            temp.swap(*this);\n            return *this;\n        }\n\n        resizable_tensor& operator= (const tensor& item) \n        {\n            resizable_tensor temp(item);\n            temp.swap(*this);\n            return *this;\n        }\n\n\n        void swap(resizable_tensor& item)\n        {\n            std::swap(m_n,    item.m_n);\n            std::swap(m_k,    item.m_k);\n            std::swap(m_nr,   item.m_nr);\n            std::swap(m_nc,   item.m_nc);\n            std::swap(m_size, item.m_size);\n            std::swap(data_instance, item.data_instance);\n            std::swap(_annotation, item._annotation);\n#ifdef DLIB_USE_CUDA\n            std::swap(cudnn_descriptor, item.cudnn_descriptor);\n#endif\n        }\n\n#ifdef DLIB_USE_CUDA\n        virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor (\n        ) const { return cudnn_descriptor; }\n#endif\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        cuda::tensor_descriptor cudnn_descriptor;\n#endif \n\n        gpu_data data_instance;\n        any _annotation;\n        virtual gpu_data& data() { return data_instance; }\n        virtual const gpu_data& data() const { return data_instance; }\n    };\n\n    inline void serialize(const tensor& item, std::ostream& out)\n    {\n        int version = 2;\n        serialize(version, out);\n        serialize(item.num_samples(), out);\n        serialize(item.k(), out);\n        serialize(item.nr(), out);\n        serialize(item.nc(), out);\n        byte_orderer bo;\n        auto sbuf = out.rdbuf();\n        for (auto d : item)\n        {\n            // Write out our data as 4byte little endian IEEE floats rather than using\n            // dlib's default float serialization.  We do this because it will result in\n            // more compact outputs.  It's slightly less portable but it seems doubtful\n            // that any CUDA enabled platform isn't going to use IEEE floats.  But if one\n            // does we can just update the serialization code here to handle it if such a\n            // platform is encountered.\n            bo.host_to_little(d);\n            static_assert(sizeof(d)==4, \"This serialization code assumes we are writing 4 byte floats\");\n            sbuf->sputn((char*)&d, sizeof(d));\n        }\n    }\n\n    inline void deserialize(resizable_tensor& item, std::istream& in)\n    {\n        int version;\n        deserialize(version, in);\n        if (version != 2)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::resizable_tensor.\");\n\n        long long num_samples=0, k=0, nr=0, nc=0;\n        deserialize(num_samples, in);\n        deserialize(k, in);\n        deserialize(nr, in);\n        deserialize(nc, in);\n        item.set_size(num_samples, k, nr, nc);\n        byte_orderer bo;\n        auto sbuf = in.rdbuf();\n        for (auto& d : item)\n        {\n            static_assert(sizeof(d)==4, \"This serialization code assumes we are writing 4 byte floats\");\n            if (sbuf->sgetn((char*)&d,sizeof(d)) != sizeof(d))\n            {\n                in.setstate(std::ios::badbit);\n                throw serialization_error(\"Error reading data while deserializing dlib::resizable_tensor.\");\n            }\n            bo.little_to_host(d);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double dot(\n        const tensor& a,\n        const tensor& b\n    )\n    {\n        DLIB_CASSERT(a.size() == b.size());\n        const float* da = a.host();\n        const float* db = b.host();\n        double sum = 0;\n        for (size_t i = 0; i < a.size(); ++i)\n            sum += da[i]*db[i];\n        return sum;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class alias_tensor_instance : public tensor\n    {\n        alias_tensor_instance(\n        ) : data_instance(0), _annotation(0), data_offset(0) {}\n\n    public:\n        friend class alias_tensor;\n        friend class alias_tensor_const_instance;\n\n        alias_tensor_instance& operator= (float val)\n        {\n            tensor::operator=(val);\n            return *this;\n        }\n\n        template <typename EXP>\n        alias_tensor_instance& operator= (const matrix_exp<EXP>& item)\n        {\n            tensor::operator=(item);\n            return *this;\n        }\n\n        virtual const float* host() const { return data_instance->host()+data_offset; }\n        virtual float*       host()       { return data_instance->host()+data_offset; }\n        virtual float*       host_write_only()    { return data_instance->host()+data_offset; }\n        virtual const float* device() const { return data_instance->device()+data_offset; }\n        virtual float*       device()       { return data_instance->device()+data_offset; }\n        virtual float*       device_write_only()  { return data_instance->device()+data_offset; }\n\n        virtual const any&   annotation() const { return *_annotation; }\n        virtual any&         annotation() { return *_annotation; }\n\n#ifdef DLIB_USE_CUDA\n        virtual const cuda::tensor_descriptor& get_cudnn_tensor_descriptor (\n        ) const { return *cudnn_descriptor; }\n#endif\n    private:\n\n        virtual size_t get_alias_offset() const { return data_offset; } \n\n#ifdef DLIB_USE_CUDA\n        std::shared_ptr<cuda::tensor_descriptor> cudnn_descriptor;\n#endif\n        gpu_data* data_instance;\n        any* _annotation;\n        size_t data_offset;\n        virtual gpu_data& data() { return *data_instance; }\n        virtual const gpu_data& data() const { return *data_instance; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class alias_tensor_const_instance \n    {\n    public:\n        const tensor& get() const { return inst; }\n        operator const tensor& () { return inst; }\n\n        alias_tensor_const_instance(const alias_tensor_instance& item) : inst(item) {}\n\n    private:\n        alias_tensor_instance inst;\n\n        friend class alias_tensor;\n        alias_tensor_const_instance() {}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class alias_tensor \n    {\n    public:\n\n        alias_tensor (\n        ) {}\n\n        alias_tensor (\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        ) \n        {\n            DLIB_ASSERT( n_ >= 0 && k_ >= 0 && nr_ >= 0 && nc_ >= 0);\n\n            inst.m_n = n_;\n            inst.m_k = k_;\n            inst.m_nr = nr_;\n            inst.m_nc = nc_;\n            inst.m_size = n_*k_*nr_*nc_;\n        }\n\n        long long num_samples(\n        ) const { return inst.m_n; }\n\n        long long k(\n        ) const { return inst.m_k; }\n\n        long long nr(\n        ) const { return inst.m_nr; }\n\n        long long nc(\n        ) const { return inst.m_nc; }\n\n        size_t size(\n        ) const { return inst.m_size; }\n\n        alias_tensor_instance operator() (\n            tensor& t,\n            size_t offset = 0\n        ) const\n        {\n            DLIB_CASSERT(offset+size() <= t.size(), \n                \"offset: \"<<offset <<\"\\n\"<<\n                \"size(): \"<<size() <<\"\\n\"<<\n                \"t.size(): \"<<t.size() <<\"\\n\");\n\n#ifdef DLIB_USE_CUDA\n            if (!inst.cudnn_descriptor)\n            {\n                inst.cudnn_descriptor = std::make_shared<cuda::tensor_descriptor>();\n                inst.cudnn_descriptor->set_size(inst.m_n, inst.m_k, inst.m_nr, inst.m_nc);\n            }\n#endif\n            inst.data_instance = &t.data();\n            inst._annotation   = &t.annotation();\n            // Note that t might already be an aliasing tensor so we need to take that into\n            // account.\n            inst.data_offset = t.get_alias_offset()+offset;\n            return inst;\n        }\n\n        alias_tensor_const_instance operator() (\n            const tensor& t,\n            size_t offset = 0\n        ) const\n        {\n            alias_tensor_const_instance temp;\n            temp.inst = (*this)(const_cast<tensor&>(t),offset);\n            return temp;\n        }\n\n    private:\n        mutable alias_tensor_instance inst;\n    };\n\n    inline void serialize(const alias_tensor& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.num_samples(), out);\n        serialize(item.k(), out);\n        serialize(item.nr(), out);\n        serialize(item.nc(), out);\n    }\n\n    inline void deserialize(alias_tensor& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::alias_tensor.\");\n        long long num_samples, k, nr, nc;\n        deserialize(num_samples, in);\n        deserialize(k, in);\n        deserialize(nr, in);\n        deserialize(nc, in);\n        item = alias_tensor(num_samples, k, nr, nc);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void memcpy (\n        alias_tensor_instance&& dest, \n        const tensor& src\n    ) \n    {\n        memcpy(static_cast<tensor&>(dest), src);\n    }\n\n}\n\n#endif // DLIB_DNn_TENSOR_H_\n\n"
  },
  {
    "path": "dlib/cuda/tensor_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_TENSOR_ABSTRACT_H_\n#ifdef DLIB_DNn_TENSOR_ABSTRACT_H_\n\n#include \"../matrix.h\"\n#include \"../any/any_abstract.h\"\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    class tensor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a 4D array of float values, all stored contiguously\n                in memory.  Importantly, it keeps two copies of the floats, one on the host\n                CPU side and another on the GPU device side. It automatically performs the\n                necessary host/device transfers to keep these two copies of the data in\n                sync.\n\n                All transfers to the device happen asynchronously with respect to the\n                default CUDA stream so that CUDA kernel computations can overlap with data\n                transfers.  However, any transfers from the device to the host happen\n                synchronously in the default CUDA stream.  Therefore, you should perform\n                all your CUDA kernel launches on the default stream so that transfers back\n                to the host do not happen before the relevant computations have completed.\n\n                If DLIB_USE_CUDA is not #defined then this object will not use CUDA at all.\n                Instead, it will simply store one host side memory block of floats.  \n\n                Finally, the convention in dlib code is to interpret the tensor as a set of\n                num_samples() 3D arrays, each of dimension k() by nr() by nc().  Also,\n                while this class does not specify a memory layout, the convention is to\n                assume that indexing into an element at coordinates (sample,k,r,c) can be\n                accomplished via:\n                    host()[((sample*t.k() + k)*t.nr() + r)*t.nc() + c]\n\n            THREAD SAFETY\n                Instances of this object are not thread-safe.  So don't touch one from\n                multiple threads at the same time.\n        !*/\n\n    public:\n\n        virtual ~tensor();\n\n        long long num_samples(\n        ) const; \n        /*!\n            ensures\n                - returns the number of 3D arrays of dimension k() by nr() by nc() there\n                  are in this object.  \n        !*/\n\n        long long k(\n        ) const; \n        /*!\n            ensures\n                - returns the k dimension of this tensor.  Generally, we think of a tensor\n                  as containing num_samples() images of nr() by nc() rows and columns, each\n                  with k() channels.\n        !*/\n\n        long long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in this tensor.\n        !*/\n\n        long long nc(\n        ) const; \n        /*!\n            ensures\n                - returns the number of columns in this tensor.\n        !*/\n\n        size_t size(\n        ) const;\n        /*!\n            ensures\n                - returns num_samples()*k()*nr()*nc()\n                  (i.e. the total number of floats in this tensor)\n        !*/\n\n        void async_copy_to_device(\n        ) const;\n        /*!\n            ensures\n                - This function does not block.\n                - if (the host version of the data is newer than the device's copy) then\n                    - Begins asynchronously copying host data to the device.\n                    - A call to device() that happens before the transfer completes will\n                      block until the transfer is complete.  That is, it is safe to call\n                      async_copy_to_device() and then immediately call device().\n        !*/\n\n        typedef float* iterator;\n        typedef const float* const_iterator;\n        iterator       begin()       { return host(); }\n        const_iterator begin() const { return host(); }\n        iterator       end()         { return host()+size(); }\n        const_iterator end() const   { return host()+size(); }\n        /*!\n            ensures\n                - makes a tensor iterable just like the STL containers.   \n        !*/\n\n        virtual const float* host(\n        ) const = 0;\n        /*!\n            ensures\n                - returns a pointer to the host memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (the host's copy of the data is out of date) then\n                    - copies the data from the device to the host, while this is happening\n                      the call to host() blocks. \n        !*/\n\n        virtual float* host(\n        ) = 0;\n        /*!\n            ensures\n                - returns a pointer to the host memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (the host's copy of the data is out of date) then\n                    - copies the data from the device to the host, while this is happening\n                      the call to host() blocks. \n                - Marks the device side data as out of date so that the next call to\n                  device() will perform a host to device transfer.  If you want to begin\n                  the transfer immediately then you can call async_copy_to_device() after\n                  calling host().\n        !*/\n\n        virtual float* host_write_only(\n        ) = 0;\n        /*!\n            ensures\n                - This function returns the same pointer as host(), except that it never\n                  performs a device to host memory copy.  Instead, it immediately marks the\n                  device side data as out of date, effectively discarding it.  Therefore,\n                  the values in the data pointed to by host_write_only() are undefined and\n                  you should only call host_write_only() if you are going to assign to\n                  every memory location in the returned memory block.  \n        !*/\n\n        virtual const float* device(\n        ) const = 0;\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - returns a pointer to the device memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (the device's copy of the data is out of date) then\n                    - copies the data from the host to the device, while this is happening\n                      the call to device() blocks. \n        !*/\n\n        virtual float* device(\n        ) = 0;\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - returns a pointer to the device memory block of size() contiguous float\n                  values or nullptr if size()==0.\n                - if (the device's copy of the data is out of date) then\n                    - copies the data from the host to the device, while this is happening\n                      the call to device() blocks. \n                - Marks the host side data as out of date so that the next call to\n                  host() will perform a device to host transfer.\n        !*/\n\n        virtual float* device_write_only(\n        ) = 0;\n        /*!\n            requires\n                - DLIB_USE_CUDA is #defined\n            ensures\n                - This function returns the same pointer as device(), except that it never\n                  performs a host to device memory copy.  Instead, it immediately marks the\n                  host side data as out of date, effectively discarding it.  Therefore, the\n                  values in the data pointed to by device_write_only() are undefined and\n                  you should only call device_write_only() if you are going to assign to\n                  every memory location in the returned memory block.  \n        !*/\n\n        virtual const any& annotation(\n        ) const = 0;\n        /*!\n            ensures\n                - returns a const reference to the any object in this tensor.  The any\n                  object can be used to store any additional annotation you like in a\n                  tensor.  However, it should be noted that the annotation() is ignored by\n                  serialize() and therefore not saved when a tensor is serialized.\n        !*/\n\n        virtual any& annotation(\n        ) = 0;\n        /*!\n            ensures\n                - returns a non-const reference to the any object in this tensor.  The any\n                  object can be used to store any additional annotation you like in a\n                  tensor.  However, it should be noted that the annotation() is ignored by\n                  serialize() and therefore not saved when a tensor is serialized.\n        !*/\n\n        int device_id(\n        ) const; \n        /*!\n            ensures\n                - returns the ID of the CUDA device that allocated this memory. I.e. the\n                  number returned by cudaGetDevice() when the memory was allocated.\n                - If CUDA is not being used then this function always returns 0.\n        !*/\n\n        tensor& operator= (\n            float val\n        );\n        /*!\n            ensures\n                - sets all elements of this tensor equal to val.\n                - returns *this\n        !*/\n\n        tensor& operator*= (\n            float val\n        );\n        /*!\n            ensures\n                - pointwise multiplies all elements of *this tensor with val.\n                - returns *this\n        !*/\n        \n        tensor& operator/= (\n            float val\n        );\n        /*!\n            ensures\n                - pointwise divides all elements of *this tensor with val.\n                - returns *this\n        !*/\n\n        template <typename EXP>\n        tensor& operator= (\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - num_samples() == item.nr()\n                - k()*nr()*nc() == item.nc()\n                - item contains float values\n            ensures\n                - Assigns item to *this tensor by performing:\n                  set_ptrm(host(), num_samples(), k()*nr()*nc()) = item;\n        !*/\n\n        template <typename EXP>\n        tensor& operator+= (\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - num_samples() == item.nr()\n                - k()*nr()*nc() == item.nc()\n                - item contains float values\n            ensures\n                - Adds item to *this tensor by performing:\n                  set_ptrm(host(), num_samples(), k()*nr()*nc()) += item;\n        !*/\n\n        template <typename EXP>\n        tensor& operator-= (\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - num_samples() == item.nr()\n                - k()*nr()*nc() == item.nc()\n                - item contains float values\n            ensures\n                - Subtracts item from *this tensor by performing:\n                  set_ptrm(host(), num_samples(), k()*nr()*nc()) -= item;\n        !*/\n\n        template <typename EXP>\n        void set_sample (\n            unsigned long long idx,\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - idx < num_samples()\n                - k()*nr()*nc() == item.size()\n                - item contains float values\n            ensures\n                - Assigns item to the idx'th sample in *this by performing:\n                  set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) = item;\n        !*/\n\n\n        template <typename EXP>\n        void add_to_sample (\n            unsigned long long idx,\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - idx < num_samples()\n                - k()*nr()*nc() == item.size()\n                - item contains float values\n            ensures\n                - Adds item to the idx'th sample in *this by performing:\n                  set_ptrm(host()+idx*item.size(), item.nr(), item.nc()) += item;\n        !*/\n\n    protected:\n\n        // You can't move or copy another tensor into *this since that might modify the\n        // tensor's dimensions.  If you want to do that sort of thing then use a\n        // resizable_tensor.\n        tensor(const tensor& item);  \n        tensor& operator= (const tensor& item); \n        tensor(tensor&& item); \n        tensor& operator=(tensor&& item); \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void memcpy (\n        tensor& dest, \n        const tensor& src\n    );\n    /*!\n        requires\n            - dest.size() == src.size()\n        ensures\n            - Copies the data in src to dest.  If the device data is current on both src\n              and dest then the copy will happen entirely on the device side.\n            - It doesn't matter what GPU device is selected by cudaSetDevice().  You can\n              always copy tensor objects to and from each other regardless.\n            - This function blocks until the copy has completed.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool is_vector (\n        const tensor& t\n    );\n    /*!\n        ensures\n            - returns true if and only if one of the following is true:\n                - t.size() == t.num_samples() \n                - t.size() == t.k() \n                - t.size() == t.nr() \n                - t.size() == t.nc()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp mat (\n        const tensor& t,\n        long long nr,\n        long long nc\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n            - nr*nc == t.size()\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == nr\n                - m.nc() == nc \n                - for all valid r and c:\n                  M(r,c) == t.host()[r*nc + c]\n                  (i.e. the tensor is interpreted as a matrix laid out in memory\n                  in row major order)\n    !*/\n\n    const matrix_exp mat (\n        const tensor& t\n    );\n    /*!\n        ensures\n            - if (t.size() != 0) then\n                - returns mat(t, t.num_samples(), t.size()/t.num_samples())\n            - else\n                - returns an empty matrix.\n    !*/\n\n    const matrix_exp image_plane (\n        const tensor& t,\n        long long sample = 0,\n        long long k = 0\n    );\n    /*!\n        requires\n            - t.size() != 0\n            - 0 <= sample < t.num_samples()\n            - 0 <= k < t.k()\n        ensures\n            - returns the k-th image plane from the sample-th image in t.  That is,\n              returns a matrix M such that:\n                - M contains float valued elements.\n                - M.nr() == t.nr()\n                - M.nc() == t.nc()\n                - for all valid r and c:\n                    - M(r,c) == t.host()[((sample*t.k() + k)*t.nr() + r)*t.nc() + c]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool have_same_dimensions (\n        const tensor& a,\n        const tensor& b\n    );\n    /*!\n        ensures\n            - returns true if and only if all of the fallowing are satisfied:\n                - a.num_samples() == b.num_samples() \n                - a.k()  == b.k() \n                - a.nr() == b.nr() \n                - a.nc() == b.nc()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class resizable_tensor : public tensor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is just a tensor with the additional ability to be resized.\n        !*/\n\n    public:\n        resizable_tensor(\n        );\n        /*!\n            ensures\n                - #size() == 0\n                - #num_samples() == 0\n                - #k() == 0\n                - #nr() == 0\n                - #nc() == 0\n                - #capacity() == 0\n        !*/\n\n        template <typename EXP>\n        resizable_tensor(\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - item contains float values\n            ensures\n                - #num_samples() == item.nr()\n                - #k() == item.nc()\n                - #nr() == 1\n                - #nc() == 1\n                - Assigns item to *this tensor by performing:\n                  set_ptrm(host(), num_samples(), k()*nr()*nc()) = item;\n                - #capacity() == size()\n        !*/\n\n        explicit resizable_tensor(\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        );\n        /*!\n            requires\n                - n_ >= 0\n                - k_ >= 0\n                - nr_ >= 0\n                - nc_ >= 0\n            ensures\n                - #size() == n_*k_*nr_*nc_\n                - #num_samples() == n_\n                - #k() == k_\n                - #nr() == nr_\n                - #nc() == nc_\n                - #capacity() == size()\n        !*/\n\n        // This object is copyable and movable\n        resizable_tensor(const resizable_tensor&) = default;\n        resizable_tensor(resizable_tensor&&) = default;\n        resizable_tensor& operator= (const resizable_tensor&) = default;\n        resizable_tensor& operator= (resizable_tensor&&) = default;\n\n        size_t capacity (\n        ) const;\n        /*!\n            ensures\n                - returns the total number of floats allocated.  This might be different\n                  from the size() since calls to set_size() that make a tensor smaller\n                  don't trigger reallocations.  They simply adjust the nominal dimensions\n                  while keeping the same allocated memory block.  This makes calls to\n                  set_size() very fast.  If you need to deallocate a tensor then use\n                  clear().\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #size() == 0\n                - #num_samples() == 0\n                - #k() == 0\n                - #nr() == 0\n                - #nc() == 0\n                - #annotation().is_empty() == true\n                - #capacity() == 0\n        !*/\n\n        void copy_size (\n            const tensor& item\n        );\n        /*!\n            ensures\n                - resizes *this so that: have_same_dimensions(#*this, item)==true\n        !*/\n\n        void set_size(\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        );\n        /*!\n            requires\n                - n_ >= 0\n                - k_ >= 0\n                - nr_ >= 0\n                - nc_ >= 0\n            ensures\n                - #size() == n_*k_*nr_*nc_\n                - #num_samples() == n_\n                - #k() == k_\n                - #nr() == nr_\n                - #nc() == nc_\n                - #capacity() == max(#size(), capacity())\n                  (i.e. capacity() never goes down when calling set_size().)\n        !*/\n\n        template <typename EXP>\n        resizable_tensor& operator= (\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            requires\n                - item contains float values\n            ensures\n                - if (num_samples() == item.nr() && k()*nr()*nc() == item.nc()) then\n                    - the dimensions of this tensor are not changed\n                - else\n                    - #num_samples() == item.nr()\n                    - #k() == item.nc()\n                    - #nr() == 1\n                    - #nc() == 1\n                - Assigns item to *this tensor by performing:\n                  set_ptrm(host(), num_samples(), k()*nr()*nc()) = item;\n        !*/\n    };\n\n    void serialize(const tensor& item, std::ostream& out);\n    void deserialize(resizable_tensor& item, std::istream& in);\n    /*!\n        provides serialization support for tensor and resizable_tensor.  Note that you can\n        serialize to/from any combination of tenor and resizable_tensor objects.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    double dot(\n        const tensor& a,\n        const tensor& b\n    );\n    /*!\n        requires\n            - a.size() == b.size()\n        ensures\n            - returns the dot product between a and b when they are both treated as\n              a.size() dimensional vectors.  That is, this function pointwise multiplies\n              the vectors together, then sums the result and returns it.\n\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class alias_tensor_instance : public tensor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tensor that aliases another tensor.  That is, it doesn't\n                have its own block of memory but instead simply holds pointers to the\n                memory of another tensor object.  It therefore allows you to efficiently\n                break a tensor into pieces and pass those pieces into functions.\n\n                An alias_tensor_instance doesn't own the resources it points to in any sense.\n                So it is important to make sure that the underlying owning tensor doesn't get\n                destructed before any alias tensors which point to it are destructed.\n        !*/\n\n        // You can't default initialize this object.  You can only get instances of it from\n        // alias_tensor::operator().\n        alias_tensor_instance(\n        ); \n    };\n\n    inline void memcpy (\n        alias_tensor_instance&& dest, \n        const tensor& src\n    ) { memcpy(static_cast<tensor&>(dest), src); }\n    /*!\n        A convenient overload for copying from src to dest when you have a temporary alias tensor.\n    !*/\n\n    class alias_tensor_const_instance \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is essentially a const version of alias_tensor_instance and therefore\n                represents a tensor.  However, due to the mechanics of C++, this object\n                can't inherit from tensor.  So instead it provides a get() and an implicit\n                conversion to const tensor.\n        !*/\n\n    public:\n\n        // non-const alias tensors are convertible to const ones.\n        alias_tensor_const_instance(const alias_tensor_instance& item); \n\n        // Methods that cast the alias to a tensor.\n        const tensor& get() const;\n        operator const tensor& (); \n\n    private:\n        // You can't default initialize this object.  You can only get instances of it from\n        // alias_tensor::operator().\n        alias_tensor_const_instance();\n    };\n\n    class alias_tensor \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for creating tensor objects that alias other tensor objects.\n                That is, it allows you to make a tensor that references the memory space of\n                another tensor object rather than owning its own memory.  This allows you\n                to do things like interpret a single tensor in different ways or even as a\n                group of multiple tensors.\n        !*/\n    public:\n\n        alias_tensor (\n        );\n        /*!\n            ensures\n                - #size() == 0 \n                - #num_samples() == 0\n                - #k() == 0\n                - #nr() == 0\n                - #nc() == 0\n        !*/\n\n        alias_tensor (\n            long long n_, long long k_ = 1, long long nr_ = 1, long long nc_ = 1\n        );\n        /*!\n            requires\n                - n_ >= 0\n                - k_ >= 0\n                - nr_ >= 0\n                - nc_ >= 0\n            ensures\n                - #size() == n_*k_*nr_*nc_\n                - #num_samples() == n_\n                - #k() == k_\n                - #nr() == nr_\n                - #nc() == nc_\n        !*/\n\n        long long num_samples() const;\n        long long k() const;\n        long long nr() const;\n        long long nc() const;\n        size_t size() const;\n\n        alias_tensor_instance operator() (\n            tensor& t,\n            size_t offset = 0\n        ) const;\n        /*!\n            requires\n                - offset+size() <= t.size()\n            ensures\n                - Returns a tensor that simply aliases the elements of t beginning with t's\n                  offset'th element.  Specifically, this function returns an aliasing\n                  tensor T such that:\n                    - T.size()   == size()\n                    - T.num_samples() == num_samples()\n                    - T.k()      == k()\n                    - T.nr()     == nr()\n                    - T.nc()     == nc()\n                    - T.host()   == t.host()+offset\n                    - T.device() == t.device()+offset\n                    - &T.annotation() == &t.annotation()\n        !*/\n\n        alias_tensor_const_instance operator() (\n            const tensor& t,\n            size_t offset = 0\n        ) const;\n        /*!\n            requires\n                - offset+size() <= t.size()\n            ensures\n                - This function is identical to the above version of operator() except that \n                  it takes and returns const tensors instead of non-const tensors.\n        !*/\n    };\n\n    void serialize(const alias_tensor& item, std::ostream& out);\n    void deserialize(alias_tensor& item, std::istream& in);\n    /*!\n        provides serialization support for alias_tensor.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_TENSOR_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/cuda/tensor_tools.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_TeNSOR_TOOLS_CPP_\n#define DLIB_TeNSOR_TOOLS_CPP_\n\n#include \"tensor_tools.h\"\n#include \"../string.h\"\n#include <atomic>\n\nnamespace dlib\n{\n    namespace\n    {\n        std::atomic<bool>& dnn_prefer_fastest_algo (\n        )\n        {\n            static std::atomic<bool> var(true);\n            return var;\n        }\n    }\n\n    bool dnn_prefer_fastest_algorithms (\n    )\n    {\n        return dnn_prefer_fastest_algo();\n    }\n\n    void set_dnn_prefer_fastest_algorithms(\n    )\n    {\n        dnn_prefer_fastest_algo() = true;\n    }\n\n    void set_dnn_prefer_smallest_algorithms(\n    )\n    {\n        dnn_prefer_fastest_algo() = false;\n    }\n}\n\nnamespace dlib { namespace tt\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void inverse_norms (\n        resizable_tensor& invnorms,\n        const tensor& data,\n        const double eps\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::inverse_norms(invnorms, data, eps);\n#else\n        invnorms = reciprocal(sqrt(sum_cols(squared(mat(data))) + eps));\n#endif\n    }\n\n    void dot_prods (\n        resizable_tensor& out,\n        const tensor& lhs,\n        const tensor& rhs\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::dot_prods(out, lhs, rhs);\n#else\n        out = sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n#endif\n    }\n\n    void dot_prods (\n        bool add_to,\n        tensor& out,\n        const tensor& lhs,\n        const tensor& rhs\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::dot_prods(add_to, out, lhs, rhs);\n#else\n        if (add_to)\n            out += sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n        else\n            out = sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n#endif\n    }\n\n    void scale_columns (\n        tensor& out,\n        const tensor& m,\n        const tensor& v\n    )\n    {\n        DLIB_CASSERT(have_same_dimensions(out,m));\n        DLIB_CASSERT(is_vector(v));\n        if (m.size() == 0 && v.size() == 0)\n            return;\n        DLIB_CASSERT(m.size() != 0);\n        DLIB_CASSERT(m.size()/m.num_samples() == v.size());\n\n#ifdef DLIB_USE_CUDA\n        cuda::scale_columns(out, m, v);\n#else\n        out = scale_columns(mat(m), mat(v));\n#endif\n    }\n\n    void scale_rows (\n        tensor& out,\n        const tensor& m,\n        const tensor& v\n    )\n    {\n        DLIB_CASSERT(have_same_dimensions(out,m));\n        DLIB_CASSERT(is_vector(v));\n        if (m.size() == 0 && v.size() == 0)\n            return;\n        DLIB_CASSERT(m.size() != 0);\n        DLIB_CASSERT(m.num_samples() == static_cast<long long>(v.size()));\n\n#ifdef DLIB_USE_CUDA\n        cuda::scale_rows(out, m, v);\n#else\n        out = scale_rows(mat(m), mat(v));\n#endif\n    }\n\n    void scale_rows2 (\n        float beta, \n        tensor& out,\n        const tensor& m1,\n        const tensor& m2,\n        const tensor& v1,\n        const tensor& v2\n    )\n    {\n        DLIB_CASSERT(have_same_dimensions(out,m1));\n        DLIB_CASSERT(have_same_dimensions(out,m2));\n        DLIB_CASSERT(have_same_dimensions(v1,v2));\n        DLIB_CASSERT(is_vector(mat(v1))); \n        DLIB_CASSERT(static_cast<long long>(v1.size()) == m1.num_samples());\n\n#ifdef DLIB_USE_CUDA\n        cuda::scale_rows2(beta, out, m1, m2, v1, v2);\n#else\n        if (beta == 0)\n            out = scale_rows(mat(m1) - scale_rows(mat(m2),mat(v1)), mat(v2));\n        else\n            out = beta*mat(out) + scale_rows(mat(m1) - scale_rows(mat(m2),mat(v1)), mat(v2));\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void exp (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n        DLIB_CASSERT(dest.size() == src.size());\n\n#ifdef DLIB_USE_CUDA\n        cuda::exp(dest,src);\n#else\n        dest = exp(mat(src));\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void log (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n        DLIB_CASSERT(dest.size() == src.size());\n\n#ifdef DLIB_USE_CUDA\n        cuda::log(dest,src);\n#else\n        dest = log(mat(src));\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void log10 (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n        DLIB_CASSERT(dest.size() == src.size());\n\n#ifdef DLIB_USE_CUDA\n        cuda::log10(dest,src);\n#else\n        dest = log10(mat(src));\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void gemm (\n        float beta,\n        tensor& dest,\n        float alpha,\n        const tensor& lhs,\n        bool trans_lhs,\n        const tensor& rhs,\n        bool trans_rhs,\n        operation_mode mode\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::gemm(beta, dest, alpha, lhs, trans_lhs, rhs, trans_rhs, mode);\n#else\n        if (mode == operation_mode::CHANNEL_WISE)\n        {\n            if (beta != 0)\n            {\n                if (trans_lhs && trans_rhs)\n                    dest = alpha * trans(mat(lhs)) * trans(mat(rhs)) + beta * mat(dest);\n                else if (!trans_lhs && trans_rhs)\n                    dest = alpha * mat(lhs) * trans(mat(rhs)) + beta * mat(dest);\n                else if (trans_lhs && !trans_rhs)\n                    dest = alpha * trans(mat(lhs)) * mat(rhs) + beta * mat(dest);\n                else\n                    dest = alpha * mat(lhs) * mat(rhs) + beta * mat(dest);\n            }\n            else\n            {\n                if (trans_lhs && trans_rhs)\n                    dest = alpha * trans(mat(lhs)) * trans(mat(rhs));\n                else if (!trans_lhs && trans_rhs)\n                    dest = alpha * mat(lhs) * trans(mat(rhs));\n                else if (trans_lhs && !trans_rhs)\n                    dest = alpha * trans(mat(lhs)) * mat(rhs);\n                else\n                    dest = alpha * mat(lhs) * mat(rhs);\n            }\n        }\n        else if (mode == operation_mode::PLANE_WISE)\n        {\n            auto is_matrix = [](const auto& tensor) {\n                return ((tensor.num_samples() * tensor.k() == 1 && tensor.nr() * tensor.nc() > 1) ||\n                    (tensor.num_samples() * tensor.k() > 1 && tensor.nr() * tensor.nc() == 1));\n                };\n\n            long num_samples = std::min({ lhs.num_samples(), rhs.num_samples(), dest.num_samples() });\n            long num_channels = std::min({ lhs.k(), rhs.k(), dest.k() });\n            const bool lhs_is_matrix = is_matrix(lhs), rhs_is_matrix = is_matrix(rhs), dest_is_matrix = is_matrix(dest);\n\n            if (lhs_is_matrix && rhs_is_matrix && dest_is_matrix) {\n                num_samples = num_channels = 1;\n            }\n\n            long lhs_rows = (lhs_is_matrix && lhs.num_samples() > 1) ? lhs.num_samples() : lhs.nr();\n            long lhs_cols = (lhs_is_matrix && lhs.k() > 1) ? lhs.k() : lhs.nc();\n            long rhs_rows = (rhs_is_matrix && rhs.num_samples() > 1) ? rhs.num_samples() : rhs.nr();\n            long rhs_cols = (rhs_is_matrix && rhs.k() > 1) ? rhs.k() : rhs.nc();\n            long dest_rows = (dest_is_matrix && dest.num_samples() > 1) ? dest.num_samples() : dest.nr();\n            long dest_cols = (dest_is_matrix && dest.k() > 1) ? dest.k() : dest.nc();\n\n            const size_t lhs_plane_size = lhs_rows * lhs_cols;\n            const size_t rhs_plane_size = rhs_rows * rhs_cols;\n            const size_t dest_plane_size = dest_rows * dest_cols;\n\n            for (long b = 0; b < num_samples; ++b)\n            {\n                for (long c = 0; c < num_channels; ++c)\n                {\n                    auto lhs_slice = lhs_is_matrix ? alias_tensor(lhs_rows, lhs_cols)(lhs, 0) :\n                        alias_tensor(lhs_rows, lhs_cols)(lhs, (b * num_channels + c) * lhs_plane_size);\n                    auto rhs_slice = rhs_is_matrix ? alias_tensor(rhs_rows, rhs_cols)(rhs, 0) :\n                        alias_tensor(rhs_rows, rhs_cols)(rhs, (b * num_channels + c) * rhs_plane_size);\n                    auto dest_slice = dest_is_matrix ? alias_tensor(dest_rows, dest_cols)(dest, 0) :\n                        alias_tensor(dest_rows, dest_cols)(dest, (b * num_channels + c) * dest_plane_size);\n\n                    if (beta != 0)\n                    {\n                        if (trans_lhs && trans_rhs)\n                            dest_slice = alpha * trans(mat(lhs_slice)) * trans(mat(rhs_slice)) + beta * mat(dest_slice);\n                        else if (!trans_lhs && trans_rhs)\n                            dest_slice = alpha * mat(lhs_slice) * trans(mat(rhs_slice)) + beta * mat(dest_slice);\n                        else if (trans_lhs && !trans_rhs)\n                            dest_slice = alpha * trans(mat(lhs_slice)) * mat(rhs_slice) + beta * mat(dest_slice);\n                        else\n                            dest_slice = alpha * mat(lhs_slice) * mat(rhs_slice) + beta * mat(dest_slice);\n                    }\n                    else\n                    {\n                        if (trans_lhs && trans_rhs)\n                            dest_slice = alpha * trans(mat(lhs_slice)) * trans(mat(rhs_slice));\n                        else if (!trans_lhs && trans_rhs)\n                            dest_slice = alpha * mat(lhs_slice) * trans(mat(rhs_slice));\n                        else if (trans_lhs && !trans_rhs)\n                            dest_slice = alpha * trans(mat(lhs_slice)) * mat(rhs_slice);\n                        else\n                            dest_slice = alpha * mat(lhs_slice) * mat(rhs_slice);\n                    }\n                }\n            }\n        }\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    tensor_rand::\n    tensor_rand(\n        unsigned long long seed\n    ) \n#ifdef DLIB_USE_CUDA\n    :rnd(seed){}\n#else\n    {rnd.set_seed(cast_to_string(seed)); }\n#endif\n\n    void tensor_rand::\n    fill_gaussian (\n        tensor& data,\n        float mean,\n        float stddev\n    )\n    {\n        DLIB_CASSERT(data.size()%2 == 0);\n#ifdef DLIB_USE_CUDA\n        rnd.fill_gaussian(data, mean, stddev);\n#else\n        for (auto& x : data) \n            x = rnd.get_random_gaussian()*stddev + mean;\n#endif\n    }\n\n    void tensor_rand::\n    fill_uniform (\n        tensor& data\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        rnd.fill_uniform(data);\n#else\n        for (auto& x : data) \n            x = rnd.get_random_float();\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void multiply (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    )\n    {\n        DLIB_CASSERT(dest.k() == src1.k() && src1.k() == src2.k() &&\n            dest.nr() == src1.nr() && src1.nr() == src2.nr() &&\n            dest.nc() == src1.nc() && src1.nc() == src2.nc() );\n        const long MD = std::max(std::max(dest.num_samples(),src1.num_samples()),src2.num_samples());\n        DLIB_CASSERT((dest.num_samples()==1 || dest.num_samples()==MD) &&\n                    (src1.num_samples()==1 || src1.num_samples()==MD) &&\n                    (src2.num_samples()==1 || src2.num_samples()==MD) );\n#ifdef DLIB_USE_CUDA\n        cuda::multiply(add_to, dest, src1, src2);\n#else\n        cpu::multiply(add_to, dest, src1, src2);\n#endif\n\n    }\n\n    void scale_channels (\n        bool add_to,\n        tensor& dest,\n        const tensor& src,\n        const tensor& scales\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::scale_channels(add_to, dest, src, scales);\n#else\n        cpu::scale_channels(add_to, dest, src, scales);\n#endif\n    }\n\n    void multiply_conv (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::multiply_conv(add_to, dest, src1, src2);\n#else\n        cpu::multiply_conv(add_to, dest, src1, src2);\n#endif\n    }\n\n    void multiply_zero_padded (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::multiply_zero_padded(add_to, dest, src1, src2);\n#else\n        cpu::multiply_zero_padded(add_to, dest, src1, src2);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const float A,\n        const float B\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src,A,B);\n#else\n        cpu::affine_transform(dest,src,A,B);\n#endif\n    }\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const float A\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src,A);\n#else\n        cpu::affine_transform(dest,src,A,0);\n#endif\n    }\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const float A,\n        const float B,\n        const float C\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src1,src2,A,B,C);\n#else\n        cpu::affine_transform(dest,src1,src2,A,B,C);\n#endif\n    }\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const float A,\n        const float B\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src1,src2,A,B);\n#else\n        cpu::affine_transform(dest,src1,src2,A,B,0);\n#endif\n    }\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C,\n        const float D\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src1,src2,src3,A,B,C,D);\n#else\n        cpu::affine_transform(dest,src1,src2,src3,A,B,C,D);\n#endif\n    }\n\n    void affine_transform_range(\n        size_t begin,\n        size_t end,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform_range(begin, end, dest,src1,src2,src3,A,B,C);\n#else\n        cpu::affine_transform_range(begin, end, dest,src1,src2,src3,A,B,C);\n#endif\n    }\n\n    void affine_transform(\n        const rectangle& rect,\n        tensor& dest, \n        const tensor& src1, \n        const tensor& src2, \n        const tensor& src3, \n        float A, \n        float B,\n        float C\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(rect, dest,src1,src2,src3,A,B,C);\n#else\n        cpu::affine_transform(rect, dest,src1,src2,src3,A,B,C);\n#endif\n    }\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform_range(0,dest.size(),dest,src1,src2,src3,A,B,C);\n#else\n        cpu::affine_transform_range(0,dest.size(),dest,src1,src2,src3,A,B,C);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const tensor& A,\n        const tensor& B\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform(dest,src,A,B);\n#else\n        cpu::affine_transform(dest,src,A,B);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform_conv(\n        tensor& dest,\n        const tensor& src,\n        const tensor& A,\n        const tensor& B\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::affine_transform_conv(dest,src,A,B);\n#else\n        cpu::affine_transform_conv(dest,src,A,B);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void compute_adam_update (\n        size_t begin,\n        size_t end,\n        tensor& s,\n        tensor& m,\n        tensor& v,\n        const float t,\n        const float learning_rate,\n        const float weight_decay,\n        const float momentum1,\n        const float momentum2,\n        const tensor& params,\n        const tensor& params_grad\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::compute_adam_update(begin, end, s, m, v, t, learning_rate, weight_decay, momentum1,\n            momentum2, params, params_grad);\n#else\n        cpu::compute_adam_update(begin, end, s, m, v, t, learning_rate, weight_decay, momentum1,\n            momentum2, params, params_grad);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void batch_normalize_inference (\n        const double eps,\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta,\n        const tensor& running_means,\n        const tensor& running_variances\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize_inference(eps,dest,src,gamma,beta,running_means,running_variances);\n#else\n        cpu::batch_normalize_inference(eps,dest,src,gamma,beta,running_means,running_variances);\n#endif\n    }\n\n    void batch_normalize (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& vars,\n        const double averaging_factor,\n        resizable_tensor& running_means,\n        resizable_tensor& running_variances,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta \n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize(eps,dest,means,vars,averaging_factor,running_means,running_variances,src,gamma,beta);\n#else\n        cpu::batch_normalize(eps,dest,means,vars,averaging_factor,running_means,running_variances,src,gamma,beta);\n#endif\n    }\n\n    void batch_normalize_gradient (\n        const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad, \n            tensor& beta_grad \n    )\n    {\n             \n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize_gradient(eps,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);\n#else\n        cpu::batch_normalize_gradient(eps,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void batch_normalize_conv_inference (\n        const double eps,\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta,\n        const tensor& running_means,\n        const tensor& running_variances\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize_conv_inference(eps,dest,src,gamma,beta,running_means,running_variances);\n#else\n        cpu::batch_normalize_conv_inference(eps,dest,src,gamma,beta,running_means,running_variances);\n#endif\n    }\n\n    void batch_normalize_conv (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& vars,\n        const double averaging_factor,\n        resizable_tensor& running_means,\n        resizable_tensor& running_variances,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta \n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize_conv(eps,dest,means,vars,averaging_factor,running_means,running_variances,src,gamma,beta);\n#else\n        cpu::batch_normalize_conv(eps,dest,means,vars,averaging_factor,running_means,running_variances,src,gamma,beta);\n#endif\n    }\n\n    void batch_normalize_conv_gradient (\n        const double eps,\n        const tensor& gradient_input,\n        const tensor& means,\n        const tensor& invstds,\n        const tensor& src,\n        const tensor& gamma,\n        tensor& src_grad,\n        tensor& gamma_grad, \n        tensor& beta_grad \n    )\n    {\n             \n#ifdef DLIB_USE_CUDA\n        cuda::batch_normalize_conv_gradient(eps,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);\n#else\n        cpu::batch_normalize_conv_gradient(eps,gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void layer_normalize (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& vars,\n        const tensor& src,\n        const tensor& gamma,\n        const tensor& beta\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::layer_normalize(eps, dest, means, vars, src, gamma, beta);\n#else\n        cpu::layer_normalize(eps, dest, means, vars, src, gamma, beta);\n#endif\n    }\n\n    void layer_normalize_gradient (\n        const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::layer_normalize_gradient(eps, gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad, dmeans, dvars);\n#else\n        cpu::layer_normalize_gradient(eps, gradient_input, means, invstds, src, gamma, src_grad, gamma_grad, beta_grad, dmeans, dvars);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void rms_normalize(\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& scale,\n        const tensor& src,\n        const tensor& gamma\n    )\n    {            \n#ifdef DLIB_USE_CUDA\n        cuda::rms_normalize(eps, dest, scale, src, gamma);\n#else\n        cpu::rms_normalize(eps, dest, scale, src, gamma);\n#endif\n    }\n\n    void rms_normalize_gradient(\n        const tensor& gradient_input,\n        const tensor& scale,\n        const tensor& src,\n        const tensor& gamma,\n        tensor& src_grad,\n        tensor& gamma_grad,\n        resizable_tensor& dscale\n    )\n    {            \n#ifdef DLIB_USE_CUDA\n        cuda::rms_normalize_gradient(gradient_input, scale, src, gamma, src_grad, gamma_grad, dscale);\n#else\n        cpu::rms_normalize_gradient(gradient_input, scale, src, gamma, src_grad, gamma_grad, dscale);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void threshold (\n        tensor& data,\n        float thresh\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::threshold(data,thresh);\n#else\n        cpu::threshold(data,thresh);\n#endif\n    }\n\n    void dot (\n        const tensor& a,\n        const tensor& b,\n        tensor& result,\n        size_t idx\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::dot(a,b,result,idx);\n#else\n        cpu::dot(a,b,result,idx);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void add(\n        float beta,\n        tensor& dest,\n        float alpha,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::add(beta,dest,alpha,src);\n#else\n        cpu::add(beta,dest,alpha,src);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void add (\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::add(dest, src1, src2);\n#else\n        cpu::add(dest, src1, src2);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void assign_conv_bias_gradient (\n        tensor& grad,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::assign_conv_bias_gradient(grad,gradient_input);\n#else\n        cpu::assign_conv_bias_gradient(grad,gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void assign_bias_gradient (\n        tensor& grad,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::assign_bias_gradient(grad,gradient_input);\n#else\n        cpu::assign_bias_gradient(grad,gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void softmax(\n        tensor& dest,\n        const tensor& src,\n        operation_mode mode\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::softmax(dest, src, mode);\n#else\n        cpu::softmax(dest, src, mode);\n#endif\n    }\n\n    void softmax_gradient(\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        operation_mode mode\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::softmax_gradient(grad, dest, gradient_input, mode);\n#else\n        cpu::softmax_gradient(grad, dest, gradient_input, mode);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void softmax_all (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::softmax_all(dest,src);\n#else\n        cpu::softmax_all(dest,src);\n#endif\n    }\n\n    void softmax_all_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::softmax_all_gradient(grad, dest, gradient_input);\n#else\n        cpu::softmax_all_gradient(grad, dest, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void sigmoid (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::sigmoid(dest,src);\n#else\n        cpu::sigmoid(dest,src);\n#endif\n    }\n\n    void sigmoid_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::sigmoid_gradient(grad, dest, gradient_input);\n#else\n        cpu::sigmoid_gradient(grad, dest, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mish (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::mish(dest,src);\n#else\n        cpu::mish(dest,src);\n#endif\n    }\n\n    void mish_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::mish_gradient(grad, src, gradient_input);\n#else\n        cpu::mish_gradient(grad, src, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void relu (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::relu(dest,src);\n#else\n        cpu::relu(dest,src);\n#endif\n    }\n\n    void relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::relu_gradient(grad, dest, gradient_input);\n#else\n        cpu::relu_gradient(grad, dest, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void prelu (\n        tensor& dest,\n        const tensor& src,\n        const tensor& param\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::prelu(dest, src, param);\n#else\n        cpu::prelu(dest, src, param);\n#endif\n    }\n\n    void prelu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input,\n        const tensor& param,\n        tensor& params_grad \n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::prelu_gradient(grad, src, gradient_input, param, params_grad);\n#else\n        cpu::prelu_gradient(grad, src, gradient_input, param, params_grad);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void leaky_relu (\n        tensor& dest,\n        const tensor& src,\n        const float alpha\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::leaky_relu(dest, src, alpha);\n#else\n        cpu::leaky_relu(dest, src, alpha);\n#endif\n    }\n\n    void leaky_relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float alpha\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::leaky_relu_gradient(grad, dest, gradient_input, alpha);\n#else\n        cpu::leaky_relu_gradient(grad, dest, gradient_input, alpha);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tanh (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::tanh(dest,src);\n#else\n        cpu::tanh(dest,src);\n#endif\n    }\n\n    void tanh_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::tanh_gradient(grad, dest, gradient_input);\n#else\n        cpu::tanh_gradient(grad, dest, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void clipped_relu (\n        tensor& dest,\n        const tensor& src,\n        const float ceiling\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::clipped_relu(dest, src, ceiling);\n#else\n        cpu::clipped_relu(dest, src, ceiling);\n#endif\n    }\n\n    void clipped_relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float ceiling\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::clipped_relu_gradient(grad, dest, gradient_input, ceiling);\n#else\n        cpu::clipped_relu_gradient(grad, dest, gradient_input, ceiling);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void elu (\n        tensor& dest,\n        const tensor& src,\n        const float alpha\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::elu(dest, src, alpha);\n#else\n        cpu::elu(dest, src, alpha);\n#endif\n    }\n\n    void elu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float alpha\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::elu_gradient(grad, dest, gradient_input, alpha);\n#else\n        cpu::elu_gradient(grad, dest, gradient_input, alpha);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void gelu (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::gelu(dest,src);\n#else\n        cpu::gelu(dest,src);\n#endif\n    }\n\n    void gelu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::gelu_gradient(grad, src, gradient_input);\n#else\n        cpu::gelu_gradient(grad, src, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void smelu (\n        tensor& dest,\n        const tensor& src,\n        const float beta\n    )\n    {\n        DLIB_CASSERT(beta > 0);\n#ifdef DLIB_USE_CUDA\n        cuda::smelu(dest, src, beta);\n#else\n        cpu::smelu(dest, src, beta);\n#endif\n    }\n\n    void smelu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float beta\n    )\n    {\n        DLIB_CASSERT(beta > 0);\n#ifdef DLIB_USE_CUDA\n        cuda::smelu_gradient(grad, dest, gradient_input, beta);\n#else\n        cpu::smelu_gradient(grad, dest, gradient_input, beta);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void silu (\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::silu(dest,src);\n#else\n        cpu::silu(dest,src);\n#endif\n    }\n\n    void silu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::silu_gradient(grad, src, gradient_input);\n#else\n        cpu::silu_gradient(grad, src, gradient_input);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void resize_bilinear (\n        tensor& dest,\n        long dest_row_stride,\n        long dest_channel_stride,\n        const tensor& src,\n        long src_row_stride,\n        long src_channel_stride\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::resize_bilinear(dest,dest_row_stride,dest_channel_stride, src,src_row_stride,src_channel_stride);\n#else\n        cpu::resize_bilinear(dest,dest_row_stride,dest_channel_stride, src,src_row_stride,src_channel_stride);\n#endif\n    }\n\n    void resize_bilinear_gradient (\n        tensor& grad,\n        long grad_row_stride,\n        long grad_channel_stride,\n        const tensor& gradient_input,\n        long gradient_input_row_stride,\n        long gradient_input_channel_stride\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::resize_bilinear_gradient(grad,grad_row_stride,grad_channel_stride,  gradient_input,gradient_input_row_stride,gradient_input_channel_stride);\n#else\n        cpu::resize_bilinear_gradient(grad,grad_row_stride,grad_channel_stride,  gradient_input,gradient_input_row_stride,gradient_input_channel_stride);\n#endif\n    }\n\n// ------------------------------------------------------------------------------------\n\n    void reorg (\n        bool add_to,\n        tensor& dest,\n        const int row_stride,\n        const int col_stride,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::reorg(add_to, dest, row_stride, col_stride, src);\n#else\n        cpu::reorg(add_to, dest, row_stride, col_stride, src);\n#endif\n    }\n\n    void reorg_gradient (\n        bool add_to,\n        tensor& grad,\n        const int row_stride,\n        const int col_stride,\n        const tensor& gradient_input\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::reorg_gradient(add_to, grad, row_stride, col_stride, gradient_input);\n#else\n        cpu::reorg_gradient(add_to, grad, row_stride, col_stride, gradient_input);\n#endif\n    }\n\n// ------------------------------------------------------------------------------------\n\n    void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::copy_tensor(add_to, dest, dest_k_offset, src, src_k_offset, count_k);\n#else\n        cpu::copy_tensor(add_to, dest, dest_k_offset, src, src_k_offset, count_k);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void copy_tensor(\n        bool add_to,\n        tensor& dest,\n        size_t dk, size_t dnr, size_t dnc,\n        const tensor& src,\n        size_t sk, size_t snr, size_t snc,\n        size_t k, size_t nr, size_t nc\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::copy_tensor(add_to, dest, dk, dnr, dnc , src, sk, snr, snc, k, nr, nc);\n#else\n        cpu::copy_tensor(add_to, dest, dk, dnr, dnc, src, sk, snr, snc, k, nr, nc);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void inv::\n    operator() (\n        const tensor& m,\n        resizable_tensor& out\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        finv(m,out);\n#else\n        out = dlib::inv(mat(m));\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void transpose(\n        bool add_to,\n        tensor& dest,\n        const tensor& src\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::transpose(add_to, dest, src);\n#else\n        cpu::transpose(add_to, dest, src);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void embeddings(\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& embs\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::embeddings(dest, src, embs);\n#else\n        cpu::embeddings(dest, src, embs);\n#endif\n    }\n\n    void embeddings_gradient(\n        const tensor& prev,\n        const tensor& gradient_input,\n        tensor& grads,\n        const tensor& freqs,\n        float learning_rate,\n        bool scale\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::embeddings_gradient(prev, gradient_input, grads, freqs, learning_rate, scale);\n#else\n        cpu::embeddings_gradient(prev, gradient_input, grads, freqs, learning_rate, scale);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void compute_act_halt_probabilities(\n        resizable_tensor& halt_probs,\n        resizable_tensor& logits,\n        const tensor& input_data,\n        const tensor& halt_params,\n        long batch_size,\n        long seq_len,\n        long feature_dim\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::compute_act_halt_probabilities(halt_probs, logits, input_data, halt_params,\n            batch_size, seq_len, feature_dim);\n#else\n        cpu::compute_act_halt_probabilities(halt_probs, logits, input_data, halt_params,\n            batch_size, seq_len, feature_dim);\n#endif\n    }\n\n    void update_act_state(\n        resizable_tensor& output,\n        const tensor& input_data,\n        const tensor& halt_probs,\n        resizable_tensor& cumulative_halting,\n        resizable_tensor& remainders,\n        resizable_tensor& n_steps,\n        resizable_tensor& effective_weights,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels,\n        float halt_threshold,\n        long current_step\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::update_act_state(output, input_data, halt_probs, cumulative_halting, remainders,\n            n_steps, effective_weights, batch_size, seq_len, d_model, num_channels, halt_threshold, current_step);\n#else\n        cpu::update_act_state(output, input_data, halt_probs, cumulative_halting, remainders,\n            n_steps, effective_weights, batch_size, seq_len, d_model, num_channels, halt_threshold, current_step);\n#endif\n    }\n\n    void finalize_act_output(\n        resizable_tensor& output,\n        const tensor& input_data,\n        const tensor& remainders,\n        resizable_tensor& effective_weights,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::finalize_act_output(output, input_data, remainders, effective_weights,\n            batch_size, seq_len, d_model, num_channels);\n#else\n        cpu::finalize_act_output(output, input_data, remainders, effective_weights,\n            batch_size, seq_len, d_model, num_channels);\n#endif\n    }\n\n    void apply_act_depth_scaling(\n        tensor& gradients,\n        const tensor& n_steps,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels,\n        float max_steps,\n        float scale_factor\n    )\n    {\n#ifdef DLIB_USE_CUDA\n        cuda::apply_act_depth_scaling(gradients, n_steps, batch_size, seq_len,\n            d_model, num_channels, max_steps, scale_factor);\n#else\n        cpu::apply_act_depth_scaling(gradients, n_steps, batch_size, seq_len,\n            d_model, num_channels, max_steps, scale_factor);\n#endif\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n}}\n\n#endif // DLIB_TeNSOR_TOOLS_CPP_\n"
  },
  {
    "path": "dlib/cuda/tensor_tools.h",
    "content": "﻿// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_TeNSOR_TOOLS_H_\n#define DLIB_TeNSOR_TOOLS_H_\n\n#include \"tensor.h\"\n#include \"cudnn_dlibapi.h\"\n#include \"cublas_dlibapi.h\"\n#include \"cusolver_dlibapi.h\"\n#include \"curand_dlibapi.h\"\n#include \"cpu_dlib.h\"\n#include \"cuda_dlib.h\"\n#include \"../rand.h\"\n#include <memory>\n#include \"../geometry/rectangle.h\"\n#include \"../test_for_odr_violations.h\"\n\nnamespace dlib\n{\n    bool dnn_prefer_fastest_algorithms();\n    void set_dnn_prefer_fastest_algorithms();\n    void set_dnn_prefer_smallest_algorithms();\n}\n\nnamespace dlib { namespace tt\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void inverse_norms (\n        resizable_tensor& invnorms,\n        const tensor& data,\n        const double eps\n    );\n    /*!\n        ensures\n            - #invnorms == reciprocal(sqrt(sum_cols(squared(mat(data))) + eps))\n    !*/\n\n    void dot_prods (\n        resizable_tensor& out,\n        const tensor& lhs,\n        const tensor& rhs\n    );\n    /*!\n        requires\n            - have_same_dimensions(lhs,rhs) == true\n        ensures\n            - #out.num_samples() == lhs.num_samples()\n            - #out.k() == #out.nr() == #out.nc() == 1\n            - #out == sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n    !*/\n\n    void dot_prods (\n        bool add_to,\n        tensor& out,\n        const tensor& lhs,\n        const tensor& rhs\n    );\n    /*!\n        requires\n            - have_same_dimensions(lhs,rhs) == true\n            - out.size() == lhs.num_samples()\n            - out.k() == out.nr() == out.nc() == 1\n        ensures\n            - if (add_to) then\n                - #out == mat(out) + sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n            - else\n                - #out == sum_cols(pointwise_multiply(mat(lhs), mat(rhs))); \n    !*/\n\n    void scale_columns (\n        tensor& out,\n        const tensor& m,\n        const tensor& v\n    );\n    /*!\n        requires\n            - have_same_dimensions(out,m) == true\n            - is_vector(v) == true\n            - v.size() == mat(m).nc()\n        ensures\n            - performs: out = scale_columns(mat(m),mat(v));\n    !*/\n\n    void scale_rows (\n        tensor& out,\n        const tensor& m,\n        const tensor& v\n    );\n    /*!\n        requires\n            - have_same_dimensions(out,m) == true\n            - is_vector(v) == true\n            - v.size() == m.num_samples()\n        ensures\n            - performs: out = scale_rows(mat(m),mat(v));\n    !*/\n\n    void scale_rows2 (\n        float beta, \n        tensor& out,\n        const tensor& m1,\n        const tensor& m2,\n        const tensor& v1,\n        const tensor& v2\n    );\n    /*!\n        requires\n            - have_same_dimensions(out,m1) == true\n            - have_same_dimensions(out,m2) == true\n            - have_same_dimensions(v1,v2) == true\n            - is_vector(v1) == true\n            - v1.size() == m1.num_samples()\n        ensures\n            - performs: \n                out = beta*out + scale_rows(mat(m1) - scale_rows(mat(m2),mat(v1)), mat(v2));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n    \n    void exp (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - dest.size() == src.size()\n        ensures\n            - performs: dest = exp(mat(src))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void log (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - dest.size() == src.size()\n        ensures\n            - performs: dest = log(mat(src))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void log10 (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - dest.size() == src.size()\n        ensures\n            - performs: dest = log10(mat(src))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void gemm (\n        float beta,\n        tensor& dest,\n        float alpha,\n        const tensor& lhs,\n        bool trans_lhs,\n        const tensor& rhs,\n        bool trans_rhs,\n        operation_mode mode = operation_mode::CHANNEL_WISE\n    );\n    /*!\n        requires\n            - dest does not alias the memory of lhs or rhs\n            - The dimensions of lhs and rhs must be compatible for matrix multiplication.\n                The specific requirements depend on the mode:\n\n                For CHANNEL_WISE mode (default):\n                    - Let L == trans_lhs ? trans(mat(lhs)) : mat(lhs)\n                    - Let R == trans_rhs ? trans(mat(rhs)) : mat(rhs)\n                    - Let D == mat(dest)\n                    - D.nr() == L.nr() && D.nc() == R.nc()\n                        (i.e. dest must be preallocated and have the correct output dimensions)\n                    - L.nc() == R.nr()\n\n                For PLANE_WISE mode:\n                    - lhs.num_samples() == rhs.num_samples() && lhs.k() == rhs.k()\n                    - If !trans_lhs && !trans_rhs:\n                        lhs.nc() == rhs.nr()\n                        dest.nr() == lhs.nr() && dest.nc() == rhs.nc()\n                    - If trans_lhs && !trans_rhs:\n                        lhs.nr() == rhs.nr()\n                        dest.nr() == lhs.nc() && dest.nc() == rhs.nc()\n                    - If !trans_lhs && trans_rhs:\n                        lhs.nc() == rhs.nc()\n                        dest.nr() == lhs.nr() && dest.nc() == rhs.nr()\n                    - If trans_lhs && trans_rhs:\n                        lhs.nr() == rhs.nc()\n                        dest.nr() == lhs.nc() && dest.nc() == rhs.nr()\n\n        ensures\n            - Performs matrix multiplication based on the specified mode:\n\n                For CHANNEL_WISE mode:\n                    - performs: dest = alpha*L*R + beta*mat(dest)\n                        where L, R, and D are as defined above.\n\n                For PLANE_WISE mode:\n                    - Performs matrix multiplication for each corresponding 2D plane (nr x nc)\n                        in lhs and rhs across all samples and channels.\n                    - The operation is equivalent to performing the following for each sample\n                        and channel:\n                            dest[s][k] = alpha * (lhs[s][k] * rhs[s][k]) + beta * dest[s][k]\n                            where [s][k] represents the 2D plane for sample s and channel k.\n            \n                Note that the PLANE_WISE mode is particularly useful for operations like attention\n                mechanisms in neural networks, where you want to perform matrix multiplications\n                on 2D planes of 4D tensors while preserving the sample and channel dimensions.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class inv\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a functor for doing matrix inversion on the GPU.  The only\n                reason it's an object is to avoid the reallocation of some GPU memory\n                blocks if you want to do a bunch of matrix inversions in a row.\n        !*/\n    public:\n\n        void operator() (\n            const tensor& m,\n            resizable_tensor& out\n        );\n        /*!\n            requires\n                - m.size() == m.num_samples()*m.num_samples()\n                  (i.e. mat(m) must be a square matrix)\n            ensures\n                - out == inv(mat(m));\n        !*/\n\n    private:\n#ifdef DLIB_USE_CUDA\n        cuda::inv finv;\n#endif\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class tensor_rand\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for filling a tensor with random numbers.  \n\n                Note that the sequence of random numbers output by this object is different\n                when dlib is compiled with DLIB_USE_CUDA.  So you should not write code\n                that depends on any specific sequence of numbers coming out of a\n                tensor_rand.\n\n        !*/\n\n    public:\n        // not copyable\n        tensor_rand(const tensor_rand&) = delete;\n        tensor_rand& operator=(const tensor_rand&) = delete;\n\n        tensor_rand() : tensor_rand(0) {}\n        tensor_rand(unsigned long long seed);\n\n        void fill_gaussian (\n            tensor& data,\n            float mean = 0,\n            float stddev = 1\n        );\n        /*!\n            requires\n                - data.size()%2 == 0\n            ensures\n                - Fills data with random numbers drawn from a Gaussian distribution\n                  with the given mean and standard deviation.\n        !*/\n\n        void fill_uniform (\n            tensor& data\n        );\n        /*!\n            ensures\n                - Fills data with uniform random numbers in the range (0.0, 1.0].\n        !*/\n\n#ifdef DLIB_USE_CUDA\n        cuda::curand_generator rnd;\n#else\n        dlib::rand rnd;\n#endif\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void multiply (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    );\n    /*!\n        requires\n            - dest.k()  == src1.k()  == src2.k()\n            - dest.nr() == src1.nr() == src2.nr()\n            - dest.nc() == src1.nc() == src2.nc()\n            - dest.num_samples(), src1.num_samples(), and src2.num_samples() must each\n              either be 1 or whichever ones aren't equal to 1 must have the same values.\n        ensures\n            - let MD = max(dest.num_samples(), src1.num_samples(), src2.num_samples)\n            - This function pointwise multiplies src1 with src2 and stores the result into\n              #dest.  However, how the multiplication happens depends on the dimensions of\n              the tensors.  First, when src1 and src2 are multiplied together, if either\n              has a num_samples() dimension that is != MD, then it is first replicated to\n              produce a tensor with num_samples()==MD dimensions and then they are\n              pointwise multiplied together.\n\n              Second, if dest.num_samples()==1, then after the pointwise multiplication of\n              src1 with src2, the result has its samples summed to produce an output tensor\n              with num_samples()==1 which is then assigned to #dest.\n            - if (add_to) then\n                - Instead of assigning the result to dest, this function adds the result to dest.\n    !*/\n\n    void scale_channels (\n        bool add_to,\n        tensor& dest,\n        const tensor& src,\n        const tensor& scales\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n            - scales.num_samples() == src.num_samples()\n            - scales.k()           == src.k()\n            - scales.nr()          == 1\n            - scales.nc()          == 1\n        ensures\n            - Scales each channel of src by the corresponding value in scales.  To be\n              precise, we will have:\n                - #dest(n,k,r,c) == src(n,k,r,c)*scales(n,k,1,1)\n            - if (add_to) then\n                - Instead of assigning the result to dest, this function adds the result to dest.\n    !*/\n\n    void multiply_conv (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    );\n    /*!\n        requires\n            - if (have_same_dimensions(dest, src1) == true) then\n                - src2.num_samples() == 1\n                - src2.nr() == 1\n                - src2.nc() == 1\n                - src2.k() == src1.k()\n            - else\n                - have_same_dimensions(src1, src2) == true) \n                - dest.num_samples() == 1\n                - dest.nr() == 1\n                - dest.nc() == 1\n                - dest.k() == src1.k()\n        ensures\n            - Performs #dest == src1*src2 \n              In particular, if the elements of dest, src1, and src2 were indexed by (n,k,r,c) then\n              we would have:\n                - if (have_same_dimensions(dest,src1)) then\n                    #dest(n,k,r,c) == src1(n,k,r,c)*src2(k)\n                - else\n                    #dest(k) == sum over {n,r,c} of src1(n,k,r,c)*src2(n,k,r,c)\n            - if (add_to) then\n                - Instead of assigning the result to dest, this function adds the result to dest.\n    !*/\n\n    void multiply_zero_padded (\n        bool add_to,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    );\n    /*!\n        ensures\n            - if (add_to) then\n                - performs: dest += src1 * src2\n            - else\n                - performs: dest = src1 * src2\n            - In either case, the multiplication happens pointwise according to 4D tensor\n              arithmetic.  If the dimensions don't match then missing elements are presumed\n              to be equal to 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const float A,\n        const float B\n    );\n    /*!\n        requires\n            - dest.size()==src.size()\n        ensures\n            - #dest == A*src + B\n    !*/\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const float A\n    );\n    /*!\n        requires\n            - dest.size()==src.size()\n        ensures\n            - #dest == A*src \n    !*/\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const float A,\n        const float B,\n        const float C\n    );\n    /*!\n        requires\n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n        ensures\n            - #dest == A*src1 + B*src2 + C\n    !*/\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const float A,\n        const float B\n    );\n    /*!\n        requires\n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n        ensures\n            - #dest == A*src1 + B*src2\n    !*/\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C,\n        const float D\n    );\n    /*!\n        requires \n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n            - dest.size()==src3.size()\n        ensures\n            - #dest == A*src1 + B*src2 + C*src3 + D\n    !*/\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C\n    );\n    /*!\n        requires \n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n            - dest.size()==src3.size()\n        ensures\n            - #dest == A*src1 + B*src2 + C*src3\n    !*/\n\n    void affine_transform_range(\n        size_t begin,\n        size_t end,\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2,\n        const tensor& src3,\n        const float A,\n        const float B,\n        const float C\n    );\n    /*!\n        requires \n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n            - dest.size()==src3.size()\n            - begin <= end <= dest.size()\n        ensures\n            - This function operates much like\n              affine_transform(dest,src1,src2,src3,A,B,C,0), except that it runs over only\n              the half open range [begin,end) rather than processing the entire tensor.\n              Specifically, it does this:\n                - for i in the range [begin, end):\n                    - #dest.host()[i] == A*src1.host()[i] + B*src2.host()[i] + C*src3.host()[i]\n    !*/\n\n    void affine_transform(\n        const rectangle& rect,\n        tensor& dest, \n        const tensor& src1, \n        const tensor& src2, \n        const tensor& src3, \n        float A, \n        float B,\n        float C\n    );\n    /*!\n        requires\n            - dest.size()==src1.size()\n            - dest.size()==src2.size()\n            - dest.size()==src3.size()\n            - dest.num_samples()==src1.num_samples()\n            - dest.num_samples()==src2.num_samples()\n            - dest.num_samples()==src3.num_samples()\n            - get_rect(mat(dest)).contains(rect) == true\n              (i.e. rect must be entirely contained within dest)\n        ensures\n            - This function operates much like\n              affine_transform(dest,src1,src2,src3,A,B,C,0), except that it runs over only\n              the sub-rectangle indicated by rect.  In particular, this function is equivalent\n              to:\n                set_subm(dest,rect) = A*subm(mat(src1),rect) + B*subm(mat(src2),rect) + C*subm(mat(src3),rect)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform(\n        tensor& dest,\n        const tensor& src,\n        const tensor& A,\n        const tensor& B\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,src) == true\n            - if (A.num_samples() == 1) then\n                - B.num_samples() == 1\n            - else\n                - A.num_samples() == src.num_samples()\n                - B.num_samples() == src.num_samples()\n            - A.nr() == B.nr() == src.nr()\n            - A.nc() == B.nc() == src.nc()\n            - A.k()  == B.k()  == src.k()\n        ensures\n            - if (A.num_samples() == 1) then\n                - #dest == A*src + B\n                    (done for each sample in src)\n            - else\n                - for all valid i:\n                    - #dest.host()[i] == A.host()[i]*src.host()[i] + B.host()[i]  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void affine_transform_conv(\n        tensor& dest,\n        const tensor& src,\n        const tensor& A,\n        const tensor& B\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,src) == true\n            - have_same_dimensions(A, B) == true\n            - A.num_samples() == 1\n            - A.nr() == 1\n            - A.nc() == 1\n            - A.k() == src.k()\n        ensures\n            - Performs #dest == A*src + B\n              In particular, if the elements of dest and src were indexed by (n,k,r,c) then\n              we would have:\n                #dest(n,k,r,c) == A(k)*src(n,k,r,c) + B(k).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void compute_adam_update (\n        size_t begin,\n        size_t end,\n        tensor& s,\n        tensor& m,\n        tensor& v,\n        const float t,\n        const float learning_rate,\n        const float weight_decay,\n        const float momentum1,\n        const float momentum2,\n        const tensor& params,\n        const tensor& params_grad\n    );\n    /*!\n        requires\n            - s.size() == m.size() = v.size() == params.size() == params_grad.size()\n            - t > 0\n            - learning_rate > 0\n            - weight_decay >= 0\n            - 0 <= momentum1 < 1\n            - 0 <= momentum2 < 1\n            - begin <= end <= params.size()\n        ensures\n            - This function implements the ADAM parameter update method described in the paper:\n                Kingma, Diederik P., and Jimmy Ba Adam. \"A method for stochastic\n                optimization.\" International Conference on Learning Representation. 2015.\n              Specifically, it implements the method shown as Algorithm 1.\n            - #s is the update vector that should be added to the parameters.\n            - The function only operates in the half open range [begin,end) of the memory\n              blocks of each tensor.  E.g. to make this function run on the entire tensor\n              set begin to 0 and end to params.size().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void batch_normalize_inference (\n        const double eps,\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta,\n        const tensor& running_means,\n        const tensor& running_variances\n    );\n    /*!\n        requires\n            - eps > 0\n            - gamma.num_samples() == 1 \n            - gamma.nr() == src.nr() \n            - gamma.nc() == src.nc() \n            - gamma.k()  == src.k()\n            - have_same_dimensions(gamma, beta) \n            - have_same_dimensions(gamma, running_means) \n            - have_same_dimensions(gamma, running_variances)\n        ensures\n            - Linearly transforms src as a call to batch_normalize() would if src had means\n              and variances as given by running_means and running_variances.  That is, this\n              function performs: \n                dest = gamma*(src-running_means)/sqrt(running_variances+eps) + beta\n              Note that it does it in a pointwise fashion over the samples in src.\n    !*/\n\n    void batch_normalize (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& invstds,\n        const double averaging_factor,\n        resizable_tensor& running_means,\n        resizable_tensor& running_variances,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta \n    );\n    /*!\n        requires\n            - eps > 0\n            - src.num_samples() > 1\n            - gamma.num_samples() == 1\n            - beta.num_samples() == 1\n            - gamma.nr() == beta.nr() == src.nr()\n            - gamma.nc() == beta.nc() == src.nc()\n            - gamma.k()  == beta.k()  == src.k()\n            - 0 <= averaging_factor <= 1\n            - if (averaging_factor != 1)\n                - have_same_dimensions(running_means, means) == true\n                - have_same_dimensions(running_variances, invstds) == true\n        ensures\n            - have_same_dimensions(#dest, src) == true\n            - #means.num_samples() == 1\n            - #invstds.num_samples() == 1\n            - means.nr() == invstds.nr() == src.nr()\n            - means.nc() == invstds.nc() == src.nc()\n            - means.k()  == invstds.k()  == src.k()\n            - #dest == the batch normalized version of src.\n            - #means == the mean values of the contents of src.\n            - #invstds == 1/(the standard deviation values of the contents of src).\n            - #running_means = (1-averaging_factor)*mat(#running_means) + averaging_factor*mat(#means);\n            - #running_variances = (1-averaging_factor)*mat(#running_variances) + averaging_factor*(variance of contents of src);\n    !*/\n\n    void batch_normalize_gradient (\n        const double eps,\n        const tensor& gradient_input,\n        const tensor& means,\n        const tensor& invstds,\n        const tensor& src,\n        const tensor& gamma,\n        tensor& src_grad,\n        tensor& gamma_grad, \n        tensor& beta_grad \n    );\n    /*!\n        requires\n            - eps > 0\n            - invstds and means should be the output of a call to\n              batch_normalize(eps,dest,means,invstds,src,gamma,beta)\n            - have_same_dimensions(gradient_input, src) == true\n            - have_same_dimensions(src, src_grad) == true\n            - src.num_samples() > 1\n            - gamma.num_samples() == 1\n            - have_same_dimensions(gamma, gamma_grad) == true\n            - have_same_dimensions(gamma, beta_grad) == true\n            - gamma.nr() == src.nr()\n            - gamma.nc() == src.nc()\n            - gamma.k()  == src.k()\n            - have_same_dimensions(means, gamma) == true\n            - have_same_dimensions(invstds, gamma) == true\n        ensures\n            - Let f(src,gamma,beta) == dot(gradient_input, dest output of\n              batch_normalize(eps,dest,means,invstds,src,gamma,beta))\n            - Adds the gradient of f() with respect to src to #src_grad.\n            - Assigns the gradient of f() with respect to gamma to #gamma_grad.\n            - Assigns the gradient of f() with respect to beta to #beta_grad.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void batch_normalize_conv_inference (\n        const double eps,\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta,\n        const tensor& running_means,\n        const tensor& running_variances\n    );\n    /*!\n        requires\n            - eps > 0\n            - gamma.num_samples() == 1 \n            - gamma.nr() == 1 \n            - gamma.nc() == 1 \n            - gamma.k()  == src.k()\n            - have_same_dimensions(gamma, beta) \n            - have_same_dimensions(gamma, running_means) \n            - have_same_dimensions(gamma, running_variances)\n        ensures\n            - Linearly transforms src as a call to batch_normalize_conv() would if src had\n              means and variances as given by running_means and running_variances.  That\n              is, this function performs: \n                dest = gamma*(src-running_means)/sqrt(running_variances+eps) + beta\n              Note that it does this in a pointwise fashion over the samples, rows, and\n              columns in src.\n    !*/\n\n    void batch_normalize_conv (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& invstds,\n        const double averaging_factor,\n        resizable_tensor& running_means,\n        resizable_tensor& running_variances,\n        const tensor& src,\n        const tensor& gamma, \n        const tensor& beta \n    );\n    /*!\n        requires\n            - eps > 0\n            - src.num_samples() > 1\n            - gamma.num_samples()==gamma.nr()==gamma.nc() == 1\n            - beta.num_samples() ==beta.nr() ==gamma.nc() == 1\n            - gamma.k()  == beta.k()  == src.k()\n            - 0 <= averaging_factor <= 1\n            - if (averaging_factor != 1)\n                - have_same_dimensions(running_means, means) == true\n                - have_same_dimensions(running_variances, invstds) == true\n        ensures\n            - have_same_dimensions(#dest, src) == true\n            - #means.num_samples()==means.nr()==means.nc() == 1\n            - #invstds.num_samples() ==invstds.nr() ==invstds.nc() == 1\n            - means.k()  == invstds.k()  == src.k()\n            - #dest == the batch normalized version of src.\n            - #means == the mean values of the contents of src.\n            - #invstds == 1/(the standard deviation values of the contents of src).\n            - #running_means = (1-averaging_factor)*mat(#running_means) + averaging_factor*mat(#means);\n            - #running_variances = (1-averaging_factor)*mat(#running_variances) + averaging_factor*(variance of contents of src);\n    !*/\n\n    void batch_normalize_conv_gradient (\n        const double eps,\n        const tensor& gradient_input,\n        const tensor& means,\n        const tensor& invstds,\n        const tensor& src,\n        const tensor& gamma,\n        tensor& src_grad,\n        tensor& gamma_grad, \n        tensor& beta_grad \n    );\n    /*!\n        requires\n            - eps > 0\n            - invstds and means should be the output of a call to\n              batch_normalize_conv(eps,dest,means,invstds,src,gamma,beta)\n            - have_same_dimensions(gradient_input, src) == true\n            - have_same_dimensions(src, src_grad) == true\n            - src.num_samples() > 1\n            - gamma.num_samples()==gamma.nr()==gamma.nc() == 1\n            - have_same_dimensions(gamma, gamma_grad) == true\n            - have_same_dimensions(gamma, beta_grad) == true\n            - gamma.k()  == src.k()\n            - have_same_dimensions(means, gamma) == true\n            - have_same_dimensions(invstds, gamma) == true\n        ensures\n            - Let f(src,gamma,beta) == dot(gradient_input, dest output of\n              batch_normalize_conv(eps,dest,means,invstds,src,gamma,beta))\n            - Adds the gradient of f() with respect to src to #src_grad.\n            - Assigns the gradient of f() with respect to gamma to #gamma_grad.\n            - Assigns the gradient of f() with respect to beta to #beta_grad.\n    !*/\n\n// -----------------------------------------------------------------------------------\n\n    void layer_normalize (\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& means,\n        resizable_tensor& invstds,\n        const tensor& src,\n        const tensor& gamma,\n        const tensor& beta\n    );\n    /*!\n        requires\n            - eps > 0\n            - src.k() == gamma.size() == beta.size()\n            - gamma.num_samples() == gamma.nr() == gamma.nc() == 1\n            - have_same_dimensions(gamma, beta) == true\n        ensures\n            - have_same_dimensions(#dest, src) == true\n            - #means.size() == invstds.size() == src.num_samples()\n            - #dest == the normalized version of src, sample-wise.\n            - #means == the mean values of the contents of src.\n            - #invstds == 1/(the standard deviation values of the contents of src).\n    !*/\n\n    void layer_normalize_gradient (\n        const double eps,\n            const tensor& gradient_input,\n            const tensor& means,\n            const tensor& invstds,\n            const tensor& src,\n            const tensor& gamma,\n            tensor& src_grad,\n            tensor& gamma_grad,\n            tensor& beta_grad,\n            resizable_tensor& dmeans,\n            resizable_tensor& dvars\n    );\n    /*!\n        requires\n            - eps > 0\n            - invstds and means should be the output of a call to\n              layer_normalize(eps,dest,means,invstds,src,gamma,beta)\n            - have_same_dimensions(gradient_input, src) == true\n            - have_same_dimensions(src, src_grad) == true\n            - have_same_dimensions(gamma, gamma_grad) == true\n            - have_same_dimensions(gamma, beta_grad) == true\n            - means.size() == src.num_samples()\n            - invstds.size() == src.num_samples()\n        ensures\n            - Let f(src,gamma,beta) == dot(gradient_input, dest output of\n              layer_normalize(eps,dest,means,invstds,src,gamma,beta))\n            - Adds the gradient of f() with respect to src to #src_grad.\n            - Assigns the gradient of f() with respect to gamma to #gamma_grad.\n            - Assigns the gradient of f() with respect to beta to #beta_grad.\n    !*/\n\n// -----------------------------------------------------------------------------------\n\n    void rms_normalize(\n        const double eps,\n        resizable_tensor& dest,\n        resizable_tensor& scale,\n        const tensor& src,\n        const tensor& gamma\n    );\n    /*!\n        requires\n            - eps > 0\n            - gamma.k() == src.k()\n            - gamma.nr() == 1\n            - gamma.nc() == 1\n        ensures\n            - have_same_dimensions(#dest, src) == true\n            - #scale.size() == src.num_samples()\n            - #dest == the RMS normalized version of src\n            - #scale contains the RMS (Root Mean Square) values used to normalize each sample of src.\n            - Each element of #dest is computed as:\n                - #dest[n, k, i, j] == src[n, k, i, j] * gamma[k] / scale[n]\n            where n is the sample index, k is the channel index, and i, j are the spatial indices.\n    !*/\n\n    void rms_normalize_gradient(\n        const tensor& gradient_input,\n        const tensor& scale,\n        const tensor& src,\n        const tensor& gamma,\n        tensor& src_grad,\n        tensor& gamma_grad,\n        resizable_tensor& dscale\n    );\n    /*!\n        requires\n            - scale.size() == src.num_samples()\n            - have_same_dimensions(gamma, gamma_grad)\n            - gamma.k() == src.k()\n            - gamma.nr() == 1\n            - gamma.nc() == 1\n            - have_same_dimensions(gradient_input, src)\n            - have_same_dimensions(gradient_input, src_grad)\n        ensures\n            - Let f(src, gamma) == dot(gradient_input, dest output of\n                rms_normalize(eps, dest, scale, src, gamma))\n            - Adds the gradient of f() with respect to src to #src_grad\n            - Assigns the gradient of f() with respect to gamma to #gamma_grad\n            - #dscale contains the gradients of f() with respect to the RMS values.\n    !*/\n\n// -----------------------------------------------------------------------------------\n\n    void threshold (\n        tensor& data,\n        float thresh\n    );\n    /*!\n        ensures\n            - Sets all elements of data to 1 or 0 depending on if they are above or below\n              the given threshold.  Specifically, for all valid i:\n                - #data.host()[i] == data.host()[i]>thresh ? 1 : 0\n    !*/\n\n    void dot (\n        const tensor& a,\n        const tensor& b,\n        tensor& result,\n        size_t idx\n    );\n    /*!\n        requires\n            - a.size() == b.size()\n            - idx < result.size()\n        ensures\n            - #result.host()[idx] == result.host()[idx] + dot(a,b);\n              I.e. Adds the dot product between a and b into the idx-th element of result.\n              The reason you might want to use this more complex version of dot() is\n              because, when using CUDA, it runs by generating asynchronous kernel launches\n              whereas the version of dot() that returns the result immediately as a scalar\n              must block the host while we wait for the result to be computed and then\n              transferred from the GPU do the host for return by dot().  So this version of\n              dot() might be much faster in some cases.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void add(\n        float beta,\n        tensor& dest,\n        float alpha,\n        const tensor& src\n    );\n    /*!\n        requires\n            - One of the following is true: \n                - have_same_dimensions(src, dest)\n                - src.num_samples()==1 && src.k()==dest.k() && src.nr()==1 && src.nc()==1\n                - src.num_samples()==1 && src.k()==dest.k() && src.nr()==dest.nr() && src.nc()==dest.nc()\n                - src.num_samples()==1 && src.k()==1 && src.nr()==dest.nr() && src.nc()==dest.nc()\n                - src.num_samples()==dest.num_samples() && src.k()==1 && src.nr()==1 && src.nc()==1\n            - is_same_object(src,dest) == false\n        ensures\n            - performs: dest = beta*dest + alpha*src\n              However, how the addition happens depends on the dimensions of src.  In\n              particular, this function adds the scaled values of one src tensor to dest.\n              Each dimension of the src tensor must match the corresponding dimension of\n              the dest tensor or must be equal to 1. In the latter case, the same value\n              from the src tensor, for those dimensions, will be used to add into the dest\n              tensor.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void add (\n        tensor& dest,\n        const tensor& src1,\n        const tensor& src2\n    );\n    /*!\n        ensures\n            - performs: dest = src1 + src2\n              The addition happens pointwise according to 4D tensor arithmetic.  If the\n              dimensions don't match then missing elements are presumed to be equal to 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void assign_conv_bias_gradient (\n        tensor& grad,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - grad.num_samples() == 1\n            - grad.k()  >= 1\n            - grad.nr() == 1\n            - grad.nc() == 1\n            - gradient_input.k() == grad.k()\n            - gradient_input.size() > 0\n            - is_same_object(grad,gradient_input) == false\n        ensures\n            - let BIAS be a tensor with the same dimensions as grad.\n            - let OUT be the output of add(1,OUT,1,BIAS)\n            - let f(gradient_input,BIAS) == dot(gradient_input,OUT)\n            - Then this function computes the gradient of f() with respect to BIAS and\n              assigns it to grad.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void assign_bias_gradient (\n        tensor& grad,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - grad.num_samples() == 1\n            - gradient_input.k() == grad.k()\n            - gradient_input.nr() == grad.nr()\n            - gradient_input.nc() == grad.nc()\n            - gradient_input.size() > 0\n            - is_same_object(grad,gradient_input) == false\n        ensures\n            - let BIAS be a tensor with the same dimensions as grad.\n            - let OUT be the output of add(1,OUT,1,BIAS)\n            - let f(gradient_input,BIAS) == dot(gradient_input,OUT)\n            - Then this function computes the gradient of f() with respect to BIAS and\n              assigns it to grad.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class tensor_conv\n    {\n    public:\n        tensor_conv(const tensor_conv&) = delete;\n        tensor_conv& operator=(const tensor_conv&) = delete;\n\n        tensor_conv() {}\n\n        void clear(\n        ) { impl.clear(); }\n\n        void operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters\n        ) { impl(add_to_output,output,data,filters); }\n        /*!\n            requires\n                - setup() has been called.  Specifically, setup() has been called like this:\n                    this->setup(data, filters, stride_y, stride_x, padding_y, padding_x);\n                - is_same_object(output,data) == false\n                - is_same_object(output,filters) == false\n                - filters.k() == data.k()\n                - filters.nr() <= src.nr() + 2*padding_y\n                - filters.nc() <= src.nc() + 2*padding_x\n                - #output.num_samples() == data.num_samples()\n                - #output.k() == filters.num_samples()\n                - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n            ensures\n                - Convolves filters over data.  If add_to_output==true then we add the\n                  results to output, otherwise we assign to output, overwriting the\n                  previous values in output.\n                - filters contains filters.num_samples() filters. \n        !*/\n\n        void operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters\n        ) { impl(add_to_output,output,data,filters); }\n        /*!\n            requires\n                - setup() has been called.  Specifically, setup() has been called like this:\n                    this->setup(data, filters, stride_y, stride_x, padding_y, padding_x);\n                - is_same_object(output,data) == false\n                - is_same_object(output,filters) == false\n                - filters.k() == data.k()\n                - filters.nr() <= src.nr() + 2*padding_y\n                - filters.nc() <= src.nc() + 2*padding_x\n            ensures\n                - Convolves filters over data.  If add_to_output==true then we add the\n                  results to output, otherwise we assign to output, overwriting the\n                  previous values in output.  \n                - filters contains filters.num_samples() filters. \n                - #output.num_samples() == data.num_samples()\n                - #output.k() == filters.num_samples()\n                - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n        !*/\n\n        void operator() (\n            const bool add_to_output,\n            tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        ) { impl(add_to_output,output,data,filters,biases,use_relu); }\n        /*!\n            requires\n                - setup() has been called.  Specifically, setup() has been called like this:\n                    this->setup(data, filters, stride_y, stride_x, padding_y, padding_x);\n                - is_same_object(output,data) == false\n                - is_same_object(output,filters) == false\n                - filters.k() == data.k()\n                - filters.nr() <= src.nr() + 2*padding_y\n                - filters.nc() <= src.nc() + 2*padding_x\n                - filters.num_samples() == biases.k()\n                - #output.num_samples() == data.num_samples()\n                - #output.k() == filters.num_samples()\n                - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n            ensures\n                - Convolves filters over data.  If add_to_output==true then we add the\n                  results to output, otherwise we assign to output, overwriting the\n                  previous values in output.\n                - Adds biases to the result of the convolved data\n                - filters contains filters.num_samples() filters.\n                - If use_relu==true, then a relu activation will be applied to the result\n                  of convolution+bias.\n        !*/\n\n        void operator() (\n            const bool add_to_output,\n            resizable_tensor& output,\n            const tensor& data,\n            const tensor& filters,\n            const tensor& biases,\n            bool use_relu\n        ) { impl(add_to_output,output,data,filters,biases,use_relu); }\n        /*!\n            requires\n                - setup() has been called.  Specifically, setup() has been called like this:\n                    this->setup(data, filters, stride_y, stride_x, padding_y, padding_x);\n                - is_same_object(output,data) == false\n                - is_same_object(output,filters) == false\n                - filters.k() == data.k()\n                - filters.nr() <= src.nr() + 2*padding_y\n                - filters.nc() <= src.nc() + 2*padding_x\n                - filters.num_samples() == biases.k()\n            ensures\n                - Convolves filters over data.  If add_to_output==true then we add the\n                  results to output, otherwise we assign to output, overwriting the\n                  previous values in output.\n                - Adds biases to the result of the convolved data\n                - filters contains filters.num_samples() filters.\n                - #output.num_samples() == data.num_samples()\n                - #output.k() == filters.num_samples()\n                - #output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                - #output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n        !*/\n\n        void get_gradient_for_data (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& filters,\n            tensor& data_gradient\n        ) { impl.get_gradient_for_data(add_to_output,gradient_input,filters,data_gradient); }\n        /*!\n            requires\n                - One of the following must be true:\n                    - filters has the same dimensions as the filters object given to the\n                      last call to operator().  Also, data_gradient has the same dimensions\n                      as the data object given to the last call to operator().\n                    - setup() has been called.  Specifically, setup() has been called like this:\n                      this->setup(data_gradient, filters, stride_y, stride_x, padding_y, padding_x);\n                - gradient_input has the following dimensions:\n                    - gradient_input.num_samples() == data_gradient.num_samples()\n                    - gradient_input.k() == filters.num_samples()\n                    - gradient_input.nr() == 1+(data_gradient.nr() + 2*padding_y - filters.nr())/stride_y\n                    - gradient_input.nc() == 1+(data_gradient.nc() + 2*padding_x - filters.nc())/stride_x\n                    - NOTE, these dimensions are what you would obtain if gradient_input\n                      has the same dimensions as the last output of operator().  \n                - is_same_object(data_gradient,filters) == false\n                - is_same_object(data_gradient,gradient_input) == false\n            ensures\n                - let OUT be the output of (*this)(OUT,data,filters,sx,sy).\n                - let f(data,filters) == dot(OUT, gradient_input)\n                - if (add_to_output) then\n                    - This function finds the gradient of f() with respect to data and adds\n                      this gradient to data_gradient.\n                - else\n                    - This function finds the gradient of f() with respect to data and\n                      assigns this gradient to data_gradient, overwriting the previous\n                      values in data_gradient.\n        !*/\n\n        void get_gradient_for_filters (\n            const bool add_to_output,\n            const tensor& gradient_input, \n            const tensor& data,\n            tensor& filters_gradient\n        ) { impl.get_gradient_for_filters(add_to_output,gradient_input,data,filters_gradient); }\n        /*!\n            requires\n                - One of the following must be true:\n                    - filters_gradient has the same dimensions as the filters object given\n                      to the last call to operator().  Also, data has the same dimensions\n                      as the data object given to the last call to operator().\n                    - setup() has been called.  Specifically, setup() has been called like this:\n                      this->setup(data, filters_gradient, stride_y, stride_x, padding_y, padding_x);\n                - gradient_input has the following dimensions:\n                    - gradient_input.num_samples() == data.num_samples()\n                    - gradient_input.k() == filters.num_samples()\n                    - gradient_input.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                    - gradient_input.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n                    - NOTE, these dimensions are what you would obtain if gradient_input\n                      has the same dimensions as the last output of operator().  \n                - is_same_object(filters_gradient,data) == false\n                - is_same_object(filters_gradient,gradient_input) == false\n            ensures\n                - let OUT be the output of (*this)(OUT,data,filters,sx,sy).\n                - let f(data,filters) == dot(OUT, gradient_input)\n                - if (add_to_output) then\n                    - This function finds the gradient of f() with respect to filters and\n                      adds this gradient to filters_gradient.\n                - else \n                    - This function finds the gradient of f() with respect to filters and\n                      assigns this gradient to filters_gradient, overwriting the previous\n                      values in filters_gradient.\n        !*/\n\n \n        void setup(\n            const tensor& data,\n            const tensor& filters,\n            int stride_y,\n            int stride_x,\n            int padding_y,\n            int padding_x\n        ) {impl.setup(data,filters,stride_y,stride_x,padding_y,padding_x); }\n        /*!\n            requires\n                - filters.k() == data.k()\n                - stride_y > 0\n                - stride_x > 0\n                - 0 <= padding_y < filters.nr()\n                - 0 <= padding_x < filters.nc()\n            ensures\n                - When operator() is called, the output tensor will have these dimensions:\n                    - output.nr() == 1+(data.nr() + 2*padding_y - filters.nr())/stride_y\n                    - output.nc() == 1+(data.nc() + 2*padding_x - filters.nc())/stride_x\n                    - output.num_samples() == data.num_samples()\n                    - output.k() == filters.num_samples()\n                - The point of setup() is to allow this object to gather information about\n                  all the tensor sizes and filter layouts involved in the computation.  In\n                  particular, the reason the tensors are input into setup() is just to\n                  observe their sizes.  setup() doesn't do anything with the contents of\n                  the tensors, or store any kind of references to the data or filter\n                  tensors. \n        !*/\n\n    private:\n#ifdef DLIB_USE_CUDA\n        cuda::tensor_conv impl;\n#else\n        cpu::tensor_conv impl;\n#endif\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class pooling\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                The pooling object is a tool for performing spatial pooling over a tensor.\n                It can be configured to do either max or average pooling.\n        !*/\n    public:\n\n        pooling(const pooling&) = delete;\n        pooling& operator=(const pooling&) = delete;\n\n        pooling (\n        ) = default;\n\n        void clear(\n        ) { impl.clear(); }\n\n        void setup_max_pooling(\n            int window_height,\n            int window_width,\n            int stride_y,\n            int stride_x,\n            int padding_y,\n            int padding_x\n        ) { impl.setup_max_pooling(window_height, window_width, stride_y, stride_x, padding_y, padding_x); }\n        /*!\n            requires\n                - window_height > 0\n                - window_width > 0\n                - stride_y > 0\n                - stride_x > 0\n                - 0 <= padding_y < window_height\n                - 0 <= padding_x < window_width\n            ensures\n                - When you call operator() it will do max pooling with the given\n                  parameters.\n        !*/\n\n        void setup_avg_pooling(\n            int window_height,\n            int window_width,\n            int stride_y,\n            int stride_x,\n            int padding_y,\n            int padding_x\n        ) { impl.setup_avg_pooling(window_height, window_width, stride_y, stride_x, padding_y, padding_x); }\n        /*!\n            requires\n                - window_height > 0\n                - window_width > 0\n                - stride_y > 0\n                - stride_x > 0\n                - 0 <= padding_y < window_height\n                - 0 <= padding_x < window_width\n            ensures\n                - When you call operator() it will do average pooling with the given\n                  parameters.\n        !*/\n\n        bool does_max_pooling(\n        ) const { return impl.does_max_pooling(); }\n\n        void operator() (\n            resizable_tensor& dest,\n            const tensor& src\n        ) { impl(dest, src); }\n        /*!\n            requires\n                - is_same_object(dest,src) == false\n                - either setup_max_pooling() or setup_avg_pooling() has been called.\n                - window_width  <= src.nc() + 2*padding_x\n                - window_height <= src.nr() + 2*padding_y\n            ensures\n                - #dest.num_samples() == src.num_samples()\n                - #dest.k() == src.k()\n                - #dest.nr() == 1 + (src.nr() + 2*padding_y - window_height)/stride_y\n                - #dest.nc() == 1 + (src.nc() + 2*padding_x - window_width)/stride_x\n                - WINDOW == centered_rect(x*stride_x + window_width/2 - padding_x,\n                                          y*stride_y + window_height/2 - padding_y,\n                                          window_width,\n                                          window_height)\n                - for all valid s, k, r, and c:\n                    - if (does_max_pooling()) then\n                        - image_plane(#dest,s,k)(r,c) == max(subm_clipped(image_plane(src,s,k),WINDOW(c,r)))\n                    - else\n                        - image_plane(#dest,s,k)(r,c) == mean(subm_clipped(image_plane(src,s,k),WINDOW(c,r)))\n        !*/\n\n        void get_gradient(\n            const tensor& gradient_input, \n            const tensor& dest,\n            const tensor& src,\n            tensor& grad \n        ) { impl.get_gradient(gradient_input, dest, src, grad); }\n        /*!\n            requires\n                - have_same_dimensions(gradient_input,dest) == true\n                - have_same_dimensions(src,grad) == true\n                - dest contains the result of calling (*this)(dest,src)\n                - is_same_object(grad,gradient_input) == false\n                - is_same_object(grad,dest) == false\n                - is_same_object(grad,src) == false\n            ensures\n                - Recalling that dest is the output of (*this)(dest,src),\n                  let f(src) == dot(gradient_input,dest)\n                - Then this function computes the gradient of f() with respect to src and\n                  adds it to grad.\n        !*/\n\n        private:\n#ifdef DLIB_USE_CUDA\n        cuda::pooling impl;\n#else\n        cpu::pooling impl;\n#endif\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void softmax(\n        tensor& dest,\n        const tensor& src,\n        operation_mode mode = operation_mode::CHANNEL_WISE\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n            - mode == CHANNEL_WISE || mode == PLANE_WISE\n        ensures\n            - Note that the softmax function is a vector valued function:\n              s(x) == exp(x)/sum(exp(x))\n            - Computes the softmax function on src and writes the results to dest.\n            - If mode == CHANNEL_WISE:\n              The softmax is computed per spatial location across the different channels at\n              each location. That is, softmax() outputs a new tensor, #dest, where each of\n              the spatial locations in dest (i.e. image idx, row idx, and column idx)\n              contains the output of s() evaluated over the channel values at each location.\n            - If mode == PLANE_WISE:\n              The softmax is computed across entire planes (nr x nc) of the input tensor.\n              This is useful for operations in Large Language Models (LLMs) and other\n              applications requiring 2D tensor processing.\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void softmax_gradient(\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        operation_mode mode = operation_mode::CHANNEL_WISE\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n            - mode == CHANNEL_WISE || mode == PLANE_WISE\n        ensures\n            - We interpret dest as the output of softmax(dest,SRC,mode) for some SRC tensor.\n            Then let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n            gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n            is_same_object(grad,gradient_input)==true then the output is assigned to\n            grad, replacing its previous contents.  Otherwise the output is added to grad.\n            - The gradient computation takes into account the specified mode:\n            - If mode == CHANNEL_WISE: The gradient is computed per spatial location across channels.\n            - If mode == PLANE_WISE: The gradient is computed across entire planes of the tensor.\n            - This function supports in-place operation, i.e. having\n            is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void softmax_all (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - Note that the softmax function is a vector valued function: \n              s(x) == exp(x)/sum(exp(x)) \n            - Computes the softmax function on src and writes the results to dest.  The\n              softmax is computed over the entire tensor with one invocation of s().  So\n              unlike softmax() which computes many s() evaluations, one for each spatial\n              location, softmax_all() calls s() once for the entire tensor.\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void softmax_all_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true \n            - have_same_dimensions(dest,grad) == true \n            - is_same_object(grad, dest)==false\n        ensures\n            - We interpret dest as the output of softmax_all(dest,SRC) for some SRC tensor.\n              Then let f(SRC) == dot(gradient_input,dest) Then this function computes the\n              gradient of f() with respect to SRC and assigns it to grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void sigmoid (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == 1/(1+std::exp(-src.host()[i])) \n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void sigmoid_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true \n            - have_same_dimensions(dest,grad) == true \n        ensures\n            - Recalling that dest is the output of sigmoid(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void mish (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == src.host()[i]*std::tanh(std::log(1+std::exp(src.host()[i])))\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void mish_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n        ensures\n            - This function computes the gradient of f() with respect to SRC and stores\n              it to grad.  Moreover, if is_same_object(grad,gradient_input)==true then\n              the output is assigned to grad, replacing its previous contents.\n              Otherwise the output is added to grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void relu (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == std::max(0,src.host()[i]) \n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true \n            - have_same_dimensions(dest,grad) == true \n        ensures\n            - Recalling that dest is the output of relu(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void prelu (\n        tensor& dest,\n        const tensor& src,\n        const tensor& param\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n            - param.size() == 1\n        ensures\n            - for all valid i:\n                - if (src.host()[i] > 0) then\n                    - #dest.host()[i] == src.host()[i]\n                - else\n                    - #dest.host()[i] == src.host()[i] * param.host()[0]\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void prelu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input,\n        const tensor& param,\n        tensor& params_grad \n    );\n    /*!\n        requires\n            - have_same_dimensions(grad,src) == true \n            - have_same_dimensions(grad,gradient_input) == true \n            - param.size() == 1\n            - params_grad.size() == 1\n            - is_same_object(grad, gradient_input) == false\n        ensures\n            - Recalling that dest is the output of prelu(dest,src,param) let \n              f(src,param) == dot(gradient_input,dest)\n            - Then this function computes the gradient of f() with respect to src and\n              param.  It assigns the gradient with respect to param to #params_grad and\n              adds the gradient with respect to src to #grad.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void leaky_relu (\n        tensor& dest,\n        const tensor& src,\n        const float alpha\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - if (src.host()[i] > 0) then\n                    - #dest.host()[i] == src.host()[i]\n                - else\n                    - #dest.host()[i] == src.host()[i] * alpha\n    !*/\n\n    void leaky_relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float alpha\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n        ensures\n            - Recalling that dest is the output of leaky_relu(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void tanh (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == std::tanh(src.host()[i]) \n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void tanh_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true \n            - have_same_dimensions(dest,grad) == true \n        ensures\n            - Recalling that dest is the output of tanh(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void clipped_relu (\n        tensor& dest,\n        const tensor& src,\n        const float ceiling\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == std::min(std::max(src.host()[i], 0), ceiling)\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void clipped_relu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float ceiling\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n        ensures\n            - Recalling that dest is the output of clipped_relu(dest,SRC,ceiling) for\n              some SRC tensor, let f(SRC) == dot(gradient_input,dest).  Then this\n              function computes the gradient of f() with respect to SRC and stores it\n              to grad.  Moreover, if is_same_object(grad,gradient_input)==true then the\n              output is assigned to grad, replacing its previous contents.  Otherwise\n              the output is added to grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void elu (\n        tensor& dest,\n        const tensor& src,\n        const float alpha\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - if (src.host()[i] > 0) then\n                    - #dest.host()[i] == src.host()[i]\n                - else\n                    - #dest.host()[i] == alpha * (std::exp(src.host()[i]) - 1)\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void elu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float alpha\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n        ensures\n            - Recalling that dest is the output of elu(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void gelu (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == src.host()[i]/2 * (1 + erf(src.host()[i]/sqrt(2))\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void gelu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(src,gradient_input) == true\n            - have_same_dimensions(src,grad) == true\n        ensures\n            - Recalling that dest is the output of gelu(dest,src), let f(src) ==\n              dot(gradient_input,dest). Then this function computes the gradient of f() with respect\n              to src and stores it to grad.  Moreover, if is_same_object(grad,gradient_input)==true\n              then the output is assigned to grad, replacing its previous contents.  Otherwise the\n              output is added to grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void smelu (\n        tensor& dest,\n        const tensor& src,\n        const float beta\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n            - beta > 0\n        ensures\n            - for all valid i:\n                - if (src.host()[i] > beta) then\n                    - #dest.host()[i] == src.host()[i]\n                - else if (src.host()[i] < -beta) then\n                    - #dest.host()[i] == 0\n                - else\n                    - #dest.host()[i] == std::pow(src.host()[i] + beta), 2) / (4 * beta)\n    !*/\n\n    void smelu_gradient (\n        tensor& grad,\n        const tensor& dest,\n        const tensor& gradient_input,\n        const float beta\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest,gradient_input) == true\n            - have_same_dimensions(dest,grad) == true\n            - beta > 0\n        ensures\n            - Recalling that dest is the output of smelu(dest,SRC) for some SRC tensor,\n              let f(SRC) == dot(gradient_input,dest).  Then this function computes the\n              gradient of f() with respect to SRC and stores it to grad.  Moreover, if\n              is_same_object(grad,gradient_input)==true then the output is assigned to\n              grad, replacing its previous contents.  Otherwise the output is added to\n              grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void silu (\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - have_same_dimensions(dest, src) == true\n        ensures\n            - for all valid i:\n                - #dest.host()[i] == src.host()[i] * sigmoid(src.host()[i])\n            - This function supports in-place operation, i.e. having\n              is_same_object(dest, src)==true\n    !*/\n\n    void silu_gradient (\n        tensor& grad,\n        const tensor& src,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - have_same_dimensions(src,gradient_input) == true\n            - have_same_dimensions(src,grad) == true\n        ensures\n            - Recalling that dest is the output of silu(dest,src), let f(src) ==\n              dot(gradient_input,dest). Then this function computes the gradient of f() with respect\n              to src and stores it to grad.  Moreover, if is_same_object(grad,gradient_input)==true\n              then the output is assigned to grad, replacing its previous contents.  Otherwise the\n              output is added to grad.\n            - This function supports in-place operation, i.e. having\n              is_same_object(grad, gradient_input)==true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void resize_bilinear (\n        tensor& dest,\n        long dest_row_stride,\n        long dest_channel_stride,\n        const tensor& src,\n        long src_row_stride,\n        long src_channel_stride\n    );\n    /*!\n        requires\n            - is_same_object(dest, src)==false\n            - dest.num_samples() == src.num_samples()\n            - dest.k() == src.k()\n        ensures\n            - for all valid i,k:  image_plane(dest,i,k) is a copy of image_plane(src,i,k)\n              that has been bilinearly interpolated to fit into the shape of\n              image_plane(dest,i,k).\n            - Instead of supposing the row stride and channel stride in the tensors is\n              given by tensor::nc() and tensor::nr()*tensor::nc() respectively, we use the\n              provided stride values to transition from one row and channel to the next.\n              This is useful in combination with alias_tensor objects since it allows you\n              to operate on subwindows in an image.\n    !*/\n\n    void resize_bilinear_gradient (\n        tensor& grad,\n        long grad_row_stride,\n        long grad_channel_stride,\n        const tensor& gradient_input,\n        long gradient_input_row_stride,\n        long gradient_input_channel_stride\n    );\n    /*!\n        requires\n            - is_same_object(grad, gradient_input)==false\n            - gradient_input.num_samples() == grad.num_samples()\n            - gradient_input.k() == grad.k()\n        ensures\n            - Suppose that DEST is the output of resize_bilinear(DEST,SRC) for some SRC\n              tensor, let f(SRC) == dot(gradient_input,DEST).  Then this function computes\n              the gradient of f() with respect to SRC and adds it to grad.   It should be\n              noted that we don't need to know the contents of DEST to compute this\n              gradient.  All that matters is that gradient_input have the same dimensions\n              as DEST.\n            - Instead of supposing the row stride and channel stride in the tensors is\n              given by tensor::nc() and tensor::nr()*tensor::nc() respectively, we use the\n              provided stride values to transition from one row and channel to the next.\n              This is useful in combination with alias_tensor objects since it allows you\n              to operate on subwindows in an image.\n    !*/\n\n    inline void resize_bilinear (\n        tensor& dest,\n        const tensor& src\n    ) { resize_bilinear(dest, dest.nc(), dest.nr()*dest.nc(), src, src.nc(), src.nr()*src.nc()); }\n    /*!\n        requires\n            - is_same_object(dest, src)==false\n            - dest.num_samples() == src.num_samples()\n            - dest.k() == src.k()\n        ensures\n            - for all valid i,k:  image_plane(dest,i,k) is a copy of image_plane(src,i,k)\n              that has been bilinearly interpolated to fit into the shape of\n              image_plane(dest,i,k).\n    !*/\n\n    inline void resize_bilinear_gradient (\n        tensor& grad,\n        const tensor& gradient_input\n    ) { resize_bilinear_gradient(grad, grad.nc(), grad.nr()*grad.nc(), gradient_input, gradient_input.nc(), gradient_input.nr()*gradient_input.nc()); }\n    /*!\n        requires\n            - is_same_object(grad, gradient_input)==false\n            - gradient_input.num_samples() == grad.num_samples()\n            - gradient_input.k() == grad.k()\n        ensures\n            - Suppose that DEST is the output of resize_bilinear(DEST,SRC) for some SRC\n              tensor, let f(SRC) == dot(gradient_input,DEST).  Then this function computes\n              the gradient of f() with respect to SRC and adds it to grad.   It should be\n              noted that we don't need to know the contents of DEST to compute this\n              gradient.  All that matters is that gradient_input have the same dimensions\n              as DEST.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void reorg (\n        bool add_to,\n        tensor& dest,\n        const int row_stride,\n        const int col_stride,\n        const tensor& src\n    );\n    /*!\n        requires\n            - !is_same_object(dest, src)\n            - src.nr() % row_stride == 0\n            - src.nc() % col_stride == 0\n            - dest.num_samples() == src.num_samples()\n            - dest.k() == src.k() * row_stride * col_stride\n            - dest.nr() == src.nr() / row_stride\n            - dest.nc() == src.nc() / col_stride\n        ensures\n            - Reorganizes the spatial resolution of src into channel information in dest, effectively\n              shifting spatial data into the channel dimension based on the specified strides.\n            - If add_to is false:\n                - Each element in dest is set to the corresponding reorganized value from src.\n            - If add_to is true:\n                - Each element in dest is incremented by the corresponding reorganized value from src.\n            - Specifically, for all n, k, r, c in dest:\n                - If add_to is false:\n                    dest.host[tensor_index(dest, n, k, r, c)] =\n                        src.host[tensor_index(src,\n                                            n,\n                                            k % src.k(),\n                                            r * row_stride + (k / src.k()) / col_stride,\n                                            c * col_stride + (k / src.k()) % col_stride)];\n                - If add_to is true:\n                    dest.host[tensor_index(dest, n, k, r, c)] +=\n                        src.host[tensor_index(src,\n                                            n,\n                                            k % src.k(),\n                                            r * row_stride + (k / src.k()) / col_stride,\n                                            c * col_stride + (k / src.k()) % col_stride)];\n    !*/\n\n    void reorg_gradient (\n        bool add_to,\n        tensor& grad,\n        const int row_stride,\n        const int col_stride,\n        const tensor& gradient_input\n    );\n    /*!\n        requires\n            - !is_same_object(grad, gradient_input)\n            - gradient_input.nr() % row_stride == 0\n            - gradient_input.nc() % col_stride == 0\n            - grad.num_samples() == gradient_input.num_samples()\n            - grad.k() == gradient_input.k() / row_stride / col_stride\n            - grad.nr() == gradient_input.nr() * row_stride\n            - grad.nc() == gradient_input.nc() * col_stride\n        ensures\n            - Computes the gradient of the function f(SRC) = DEST, where DEST is the result of\n              reorg(DEST, row_stride, col_stride, SRC).\n            - If add_to is false:\n                - Each element in grad is set to the corresponding gradient value.\n            - If add_to is true:\n                - Each element in grad is incremented by the corresponding gradient value.\n            - Specifically, for all n, k, r, c in grad:\n                - If add_to is false:\n                    grad.host[tensor_index(grad, n, k, r, c)] =\n                        gradient_input.host[tensor_index(gradient_input,\n                                                        n,\n                                                        (k*row_stride*col_stride) + (r%row_stride)*col_stride + c%col_stride,\n                                                        r/row_stride,\n                                                        c/col_stride)];\n                - If add_to is true:\n                    grad.host[tensor_index(grad, n, k, r, c)] +=\n                        gradient_input.host[tensor_index(gradient_input,\n                                                        n,\n                                                        (k*row_stride*col_stride) + (r%row_stride)*col_stride + c%col_stride,\n                                                        r/row_stride,\n                                                        c/col_stride)];\n            - This function effectively reverses the reorg operation, distributing gradients\n              from the channel dimension of gradient_input to the spatial dimensions of grad.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void embeddings(\n        resizable_tensor& dest,\n        const tensor& src,\n        const tensor& embs\n    );\n    /*!\n        requires\n            - src.nr() > 0\n            - embs.num_samples() > 0\n            - embs.k() > 0\n            - embs.nr() == 1\n            - embs.nc() == 1\n            - dest.num_samples() == src.num_samples()\n            - dest.k() == src.k()\n            - dest.nr() == src.nr()\n            - dest.nc() == embs.k()\n        ensures\n            - Projects tokens from the input tensor `src` into embeddings stored in `embs`.\n            - The resulting embeddings are stored in the `dest` tensor.\n            - For all valid s (0 <= s < dest.num_samples()),\n                        k (0 <= k < dest.k()),\n                        r (0 <= r < dest.nr()),\n                        c (0 <= c < dest.nc()):\n                - Let token_idx = static_cast<unsigned long>(src(s,k,r,0))\n                - If token_idx < embs.num_samples():\n                    - #dest(s,k,r,c) = embs(token_idx, c, 0, 0)\n                - Else:\n                    - #dest(s,k,r,c) = 0\n            - The function iterates over all elements of src and populates dest accordingly.\n            - If a token index in src is out of range (>= embs.num_samples()),\n              the corresponding embedding in dest is filled with 0's.\n    */\n\n    void embeddings_gradient(\n        const tensor& prev,\n        const tensor& gradient_input,\n        tensor& grads,\n        const tensor& freqs,\n        float learning_rate,\n        bool scale\n    );\n    /*!\n        requires\n            - prev.nr() > 0\n            - gradient_input.num_samples() == prev.num_samples()\n            - gradient_input.k() == prev.k()\n            - gradient_input.nr() == prev.nr()\n            - gradient_input.nc() == grads.k()\n            - grads.num_samples() > 0\n            - grads.k() > 0\n            - grads.nr() == 1\n            - grads.nc() == 1\n            - freqs.num_samples() == grads.num_samples()\n            - freqs.k() == 1\n            - freqs.nr() == 1\n            - freqs.nc() == 1\n        ensures\n            - Updates the `grads` tensor based on the gradients in `gradient_input`.\n            - For each sample s, channel k, and row r in prev:\n                - Retrieves the token index from prev[s,k,r,0]\n                - If the token index is valid (< grads.num_samples()):\n                    - If scale is true:\n                        - Computes a frequency scale factor based on freqs[token_idx]\n                        - The scale factor is min(0.15, max(1.0 / freqs[token_idx], 1.0))\n                    - For each column c in gradient_input:\n                        - Updates grads[token_idx, c] -= gradient_input[s,k,r,c] * learning_rate * freq_scale\n            - The updates to grads are performed atomically to handle concurrent updates to the same embedding.\n            - The function is thread-safe and processes samples in parallel.\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    class multi_device_tensor_averager\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for very quickly averaging a bunch of tensors\n                together.\n        !*/\n    public:\n\n        multi_device_tensor_averager(const multi_device_tensor_averager&) = delete;\n        multi_device_tensor_averager& operator=(const multi_device_tensor_averager&) = delete;\n\n        multi_device_tensor_averager() = default;\n\n        void set(\n            std::vector<tensor*> items\n        )\n        /*!\n            requires\n                - All the tensors in items are the same size\n            ensures\n                - When you call average() we will average the tensors in items.\n                - It's important that the tensors already be allocated to their devices\n                  before you call set().  This is because set() will setup the types of\n                  between device transfers now and use them when you call average().  \n        !*/\n        {\n            using namespace ::dlib::cuda;\n            accessible_groups.clear();\n            epa.clear();\n            if (items.size() < 1)\n                return;\n\n            scale = 1.f/items.size();\n\n            // split item into groups of accessible devices\n            std::vector<tensor*> group, unused;\n            while(items.size() > 0)\n            {\n                group.push_back(items[0]);\n                for(size_t i = 1; i < items.size(); ++i)\n                {\n                    if (can_access_peer(*items[0], *items[i]))\n                        group.push_back(items[i]);\n                    else\n                        unused.push_back(items[i]);\n                }\n                accessible_groups.push_back(group);\n                unused.swap(items);\n                unused.clear();\n                group.clear();\n            }\n            for (auto&& g : accessible_groups)\n            {\n                for (size_t i = 1; i < g.size(); ++i)\n                {\n                    epa.emplace_back(new enable_peer_access(*g[0], *g[i]));\n                }\n            }\n        }\n\n        size_t num_device_groups(\n        ) const { return accessible_groups.size(); }\n        /*!\n            ensures\n                - The devices given to set() are grouped together when they can directly\n                  access each other using GPUDirect.  This function returns the number of\n                  such groups.  For example, if all devices can directly access each other\n                  then the number of groups is 1.\n        !*/\n\n        void average()\n        /*!\n            requires\n                - All the devices have stopped writing to the tensors given to set().  So\n                  you should probably call cudaDeviceSynchronize() on each of the relevant\n                  devices before calling average().\n            ensures\n                - Computes the average of all the tensors given to set() and then sets them\n                  all equal to the average.\n        !*/\n        {\n            using namespace ::dlib::cuda;\n\n\n            // First we average things within each group\n            for (auto&& g : accessible_groups)\n            {\n                raii_set_device set_dev(*g[0]);\n                if (g.size() == 1)\n                    tt::affine_transform(*g[0], *g[0], scale);\n                else \n                    tt::affine_transform(*g[0], *g[0], *g[1], scale, scale);\n\n                for (size_t i = 2; i < g.size(); ++i)\n                    tt::affine_transform(*g[0], *g[0], *g[i], 1, scale);\n            }\n\n            if (accessible_groups.size() > 1)\n            {\n                tensor& total_avg = *accessible_groups[0][0];\n                raii_set_device set_dev(total_avg);\n                accum_buffer.copy_size(total_avg);\n                // now we need to average things across groups\n                for (size_t i = 1; i < accessible_groups.size(); ++i)\n                {\n                    memcpy(accum_buffer, *accessible_groups[i][0]);\n                    tt::add(total_avg, total_avg, accum_buffer);\n                }\n\n                // Now total_avg has the final average in it.  So we need to send\n                // copies of it back to each of the groups.\n                for (size_t i = 1; i < accessible_groups.size(); ++i)\n                {\n                    memcpy(*accessible_groups[i][0], total_avg);\n                }\n            }\n\n\n            // Now propagate averages back out to each element using point to point\n            // communication inside a group.\n            for (auto&& g : accessible_groups)\n            {\n                raii_set_device set_dev(*g[0]);\n                for (size_t i = 1; i < g.size(); ++i)\n                    memcpy(*g[i], *g[0]); \n            }\n        }\n\n    private:\n        std::vector<std::unique_ptr<::dlib::cuda::enable_peer_access>> epa;\n        std::vector<std::vector<tensor*>> accessible_groups;\n        float scale;\n\n        resizable_tensor accum_buffer;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void copy_tensor(\n            bool add_to,\n            tensor& dest,\n            size_t dest_k_offset,\n            const tensor& src,\n            size_t src_k_offset,\n            size_t count_k\n    );\n    /*!\n        requires\n            - dest.nc() == src.nc()\n            - dest.nr() == src.nr()\n            - dest.num_samples() == src.num_samples()\n            - dest.k() - dest_k_offset >= count_k\n            - src.k() - src_k_offset >= count_k\n            - is_same_object(dest,src) == false\n            - The memory areas of src and dest do not overlap.\n        ensures\n            - if (add_to) then\n                - performs: dest[i, k + dest_k_offset, r, c] += src[i, k + src_k_offset, r, c], where k in [0..count_k]\n                  i.e., adds content of each sample from src in to corresponding place of sample at dest.\n            - else\n                - performs: dest[i, k + dest_k_offset, r, c]  = src[i, k + src_k_offset, r, c], where k in [0..count_k]\n                  i.e., copies content of each sample from src in to corresponding place of sample at dest.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void copy_tensor(\n        bool add_to,\n        tensor& dest,\n        size_t dk, size_t dnr, size_t dnc,\n        const tensor& src,\n        size_t sk, size_t snr, size_t snc,\n        size_t k, size_t nr, size_t nc\n    );\n    /*!\n        requires\n            - dest.num_samples() == src.num_samples()\n            - dest.k() - dk >= k\n            - dest.nr() - dnr >= nr\n            - dest.nc() - dnc >= nc\n            - src.k() - sk >= k\n            - src.nr() - snr >= nr\n            - src.nc() - snc >= nc\n            - is_same_object(dest,src) == false\n            - The memory areas of src and dest do not overlap.\n        ensures\n            - if (add_to) then\n                - performs: dest[i, j + dk, r + dnr, c + dnc] += src[i, j + sk, r + snr, c + snc], where j in [0..k],\n                  r in [0..nr] and c in [0..nc]\n                  i.e., adds content of each sample from src in to corresponding place of sample at dest.\n            - else\n                - performs: dest[i, j + dk, r + dnr, c + dnc]  = src[i, j + sk, r + snr, c +snc], where j in [0..k],\n                  r in [0..nr] and c in [0..nc]\n                  i.e., copies content of each sample from src in to corresponding place of sample at dest.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void transpose(\n        bool add_to,\n        tensor& dest,\n        const tensor& src\n    );\n    /*!\n        requires\n            - is_same_object(dest, src) == false\n            - dest.num_samples() == src.num_samples()\n            - dest.k() == src.k()\n            - dest.nr() == src.nc()\n            - dest.nc() == src.nr()            \n        ensures\n            - Performs a transpose operation on the nr() x nc() matrices within src.\n            - If (add_to) is false:\n                - The result is stored in dest, overwriting its previous contents.\n                - For all valid n, k, r, c:\n                    - #dest(n,k,c,r) == src(n,k,r,c)\n            - If (add_to) is true:\n                - The result is added to the existing contents of dest.\n                - For all valid n, k, r, c:\n                    - #dest(n,k,c,r) == dest(n,k,c,r) + src(n,k,r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    // ACT (Adaptive Computation Time) operations\n\n    void compute_act_halt_probabilities(\n        resizable_tensor& halt_probs,\n        resizable_tensor& logits,\n        const tensor& input_data,\n        const tensor& halt_params,\n        long batch_size,\n        long seq_len,\n        long feature_dim\n    );\n    /*!\n        requires\n            - halt_params.size() == feature_dim + 1 (weights + bias)\n            - input_data.num_samples() == batch_size\n            - input_data.k() == num_channels where feature_dim = num_channels * d_model\n            - input_data.nr() == seq_len\n            - input_data.nc() == d_model\n        ensures\n            - Computes halting probabilities for Adaptive Computation Time:\n                - halt_probs contains sigmoid(W_halt^T * input + b_halt) for each position\n                - logits contains the pre-sigmoid values\n            - batch_size: number of samples in the batch\n            - seq_len: sequence length (number of positions to process)\n            - feature_dim: total feature dimension (num_channels × d_model)\n    !*/\n\n    void update_act_state(\n        resizable_tensor& output,\n        const tensor& input_data,\n        const tensor& halt_probs,\n        resizable_tensor& cumulative_halting,\n        resizable_tensor& remainders,\n        resizable_tensor& n_steps,\n        resizable_tensor& effective_weights,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels,\n        float halt_threshold,\n        long current_step\n    );\n    /*!\n        requires\n            - 0 < halt_threshold <= 1.0\n            - current_step >= 0\n            - input_data.num_samples() == batch_size\n            - input_data.k() == num_channels\n            - input_data.nr() == seq_len\n            - input_data.nc() == d_model\n            - output has the same dimensions as input_data\n            - halt_probs.size() == batch_size * seq_len\n            - cumulative_halting.size() == remainders.size() == n_steps.size() == effective_weights.size() == batch_size * seq_len\n        ensures\n            - Core ACT update step that accumulates weighted outputs:\n                - Updates ACT state for all positions\n                - Accumulates weighted outputs: output += α_t^n * input_data\n                - Updates cumulative_halting, remainders, n_steps, and effective_weights\n            - batch_size: number of samples in the batch\n            - seq_len: sequence length (number of positions to process)\n            - d_model: model dimension per channel\n            - num_channels: number of feature channels\n            - halt_threshold: halting threshold (typically 0.99)\n            - current_step: current computation step index (0-based)\n    !*/\n\n    void finalize_act_output(\n        resizable_tensor& output,\n        const tensor& input_data,\n        const tensor& remainders,\n        resizable_tensor& effective_weights,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels\n    );\n    /*!\n        requires\n            - input_data.num_samples() == batch_size\n            - input_data.k() == num_channels\n            - input_data.nr() == seq_len\n            - input_data.nc() == d_model\n            - output has the same dimensions as input_data\n            - remainders.size() == effective_weights.size() == batch_size * seq_len\n        ensures\n            - Finalizes ACT output by adding remainder contributions:\n                - Adds final remainder contributions: output += ρ_t * input_data\n                - Updates effective_weights with remainder values\n                - Applied only to positions with significant remainder (> 1e-6)\n            - batch_size: number of samples in the batch\n            - seq_len: sequence length (number of positions to process)\n            - d_model: model dimension per channel\n            - num_channels: number of feature channels\n    !*/\n\n    void apply_act_depth_scaling(\n        tensor& gradients,\n        const tensor& n_steps,\n        long batch_size,\n        long seq_len,\n        long d_model,\n        long num_channels,\n        float max_steps,\n        float scale_factor\n    );\n    /*!\n        requires\n            - scale_factor >= 0\n            - max_steps > 0\n            - gradients.num_samples() == batch_size\n            - gradients.k() == num_channels\n            - gradients.nr() == seq_len\n            - gradients.nc() == d_model\n            - n_steps.size() == batch_size * seq_len\n        ensures\n            - Applies gradient scaling based on computation depth:\n                - Applies depth-dependent gradient scaling\n                - scale = 1 + scale_factor * (n_steps[pos] / max_steps)\n            - seq_len: sequence length (number of positions to process)\n            - d_model: model dimension per channel\n            - num_channels: number of feature channels\n            - max_steps: maximum allowed computation steps\n            - scale_factor: scaling strength (0 = no scaling)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}}\n\n#ifdef NO_MAKEFILE\n#include \"tensor_tools.cpp\"\n#endif\n\n#endif // DLIB_TeNSOR_TOOLS_H_\n\n\n"
  },
  {
    "path": "dlib/data_io/arc_agi.h",
    "content": "// Copyright (C) 2025  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ARC_AGI_H_\n#define DLIB_ARC_AGI_H_\n\n#include \"arc_agi_abstract.h\"\n#include <string>\n#include <vector>\n#include <map>\n#include <fstream>\n#include <sstream>\n#include <stdexcept>\n#include <algorithm>\n#include <iostream>\n#include \"../matrix.h\"\n#include \"../dir_nav.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    // ----------------------------------------------------------------------------------------\n    // Type aliases and constants\n    // ----------------------------------------------------------------------------------------\n\n    /*!\n        Type aliases for ARC-AGI data structures. Grids are represented as matrices\n        of unsigned char values (0-9), and token sequences are column vectors of long.\n    !*/\n    using arc_grid_t = matrix<unsigned char>;\n    using arc_token_sequence_t = matrix<long, 0, 1>;\n\n    /*!\n        Maximum sequence length for LLM-style training. This constant defines the\n        upper bound for token sequences that can be processed by the model.\n    !*/\n    constexpr long ARC_MAX_SEQUENCE_LENGTH = 4096;\n\n    // ----------------------------------------------------------------------------------------\n    // Token vocabulary\n    // ----------------------------------------------------------------------------------------\n\n    /*!\n        Token vocabulary for the Hierarchical Reasoning Model. The vocabulary includes:\n        - COLOR_0 to COLOR_9: Grid cell colors (10 values)\n        - TOKEN_SEP_IO: Separator between input and output grids\n        - TOKEN_SEP_PAIR: Separator between demonstration pairs\n        - TOKEN_QUERY_START: Marks the beginning of a test query\n        - TOKEN_GEN_START: Marks the beginning of generation phase\n        - TOKEN_END_OF_OUTPUT: Marks the end of generated output\n        - TOKEN_PADDING: Padding token for variable-length sequences\n        - TOKEN_ROW_END: Marks the end of a grid row (for dimension encoding)\n    !*/\n    enum arc_token_id : long\n    {\n        COLOR_0 = 0, COLOR_1 = 1, COLOR_2 = 2, COLOR_3 = 3, COLOR_4 = 4,\n        COLOR_5 = 5, COLOR_6 = 6, COLOR_7 = 7, COLOR_8 = 8, COLOR_9 = 9,\n        TOKEN_SEP_IO = 10,\n        TOKEN_SEP_PAIR = 11,\n        TOKEN_QUERY_START = 12,\n        TOKEN_GEN_START = 13,\n        TOKEN_END_OF_OUTPUT = 14,\n        TOKEN_PADDING = 15,\n        TOKEN_ROW_END = 16\n    };\n\n    /*!\n        Vocabulary size constants for the token set.\n    !*/\n    constexpr long ARC_VOCAB_SIZE_COLORS = 10;\n    constexpr long ARC_VOCAB_SIZE_TOTAL = 17;\n\n    // ----------------------------------------------------------------------------------------\n    // ARC-AGI task data structures\n    // ----------------------------------------------------------------------------------------\n\n    /*!\n        Represents a single input-output pair in an ARC-AGI task. Each pair consists\n        of an input grid and its corresponding output grid, along with their dimensions.\n    !*/\n    struct arc_task_pair\n    {\n        arc_grid_t input;\n        arc_grid_t output;\n        long input_rows;\n        long input_cols;\n        long output_rows;\n        long output_cols;\n\n        friend void serialize(const arc_task_pair& item, std::ostream& out)\n        {\n            dlib::serialize(item.input, out);\n            dlib::serialize(item.output, out);\n            dlib::serialize(item.input_rows, out);\n            dlib::serialize(item.input_cols, out);\n            dlib::serialize(item.output_rows, out);\n            dlib::serialize(item.output_cols, out);\n        }\n\n        friend void deserialize(arc_task_pair& item, std::istream& in)\n        {\n            dlib::deserialize(item.input, in);\n            dlib::deserialize(item.output, in);\n            dlib::deserialize(item.input_rows, in);\n            dlib::deserialize(item.input_cols, in);\n            dlib::deserialize(item.output_rows, in);\n            dlib::deserialize(item.output_cols, in);\n        }\n    };\n\n    /*!\n        Represents a complete ARC-AGI task. Each task contains:\n        - A unique task identifier\n        - A set of training demonstration pairs\n        - A set of test pairs (where outputs are to be predicted)\n    !*/\n    struct arc_task\n    {\n        std::string task_id;\n        std::vector<arc_task_pair> train_pairs;\n        std::vector<arc_task_pair> test_pairs;\n\n        friend void serialize(const arc_task& item, std::ostream& out)\n        {\n            dlib::serialize(item.task_id, out);\n            dlib::serialize(item.train_pairs, out);\n            dlib::serialize(item.test_pairs, out);\n        }\n\n        friend void deserialize(arc_task& item, std::istream& in)\n        {\n            dlib::deserialize(item.task_id, in);\n            dlib::deserialize(item.train_pairs, in);\n            dlib::deserialize(item.test_pairs, in);\n        }\n    };\n\n    // ----------------------------------------------------------------------------------------\n    // Internal JSON parsing utilities\n    // ----------------------------------------------------------------------------------------\n\n    namespace internal\n    {\n        using raw_arc_grid_t = std::vector<std::vector<int>>;\n\n        // ------------------------------------------------------------------------------------\n\n        inline std::string read_file_to_string(const std::string& path)\n        /*!\n            ensures\n                - Reads the entire contents of a file and returns it as a string\n                - Throws std::runtime_error if the file cannot be opened\n        !*/\n        {\n            std::ifstream file(path);\n            if (!file.is_open())\n                throw std::runtime_error(\"Failed to open file: \" + path);\n            std::stringstream buffer;\n            buffer << file.rdbuf();\n            return buffer.str();\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        inline std::vector<int> parse_int_array(const std::string& str)\n        /*!\n            ensures\n                - Parses a comma-separated string of integers\n                - Returns a vector containing the parsed integers\n                - Whitespace around numbers is automatically stripped\n        !*/\n        {\n            std::vector<int> result;\n            std::stringstream ss(str);\n            std::string segment;\n            while (std::getline(ss, segment, ','))\n            {\n                segment.erase(0, segment.find_first_not_of(\" \\t\\n\\r\"));\n                segment.erase(segment.find_last_not_of(\" \\t\\n\\r\") + 1);\n                if (!segment.empty())\n                    result.push_back(std::stoi(segment));\n            }\n            return result;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        inline raw_arc_grid_t parse_arc_grid(std::string::const_iterator& it,\n            const std::string::const_iterator& end)\n        /*!\n            ensures\n                - Parses a 2D grid from JSON array-of-arrays format\n                - Advances the iterator 'it' past the parsed content\n                - Returns a vector of vectors representing the grid rows\n                - Throws std::runtime_error on malformed input\n        !*/\n        {\n            raw_arc_grid_t grid;\n\n            // Locate the opening bracket of the outer array\n            it = std::find(it, end, '[');\n            if (it == end) return grid;\n            ++it;\n\n            // Skip any leading whitespace\n            while (it != end && std::isspace(*it)) ++it;\n\n            // Verify we have an array of arrays (second '[')\n            if (it == end || *it != '[') return grid;\n\n            // Parse each row in the grid\n            while (it != end)\n            {\n                // Skip whitespace between rows\n                while (it != end && std::isspace(*it)) ++it;\n\n                // Check for end of outer array\n                if (it == end || *it == ']') break;\n\n                // Expect a '[' at the start of each row\n                if (*it != '[') {\n                    ++it;\n                    continue;\n                }\n                ++it;\n\n                // Find the closing ']' for this row\n                auto inner_end = std::find(it, end, ']');\n                if (inner_end == end)\n                    throw std::runtime_error(\"Missing inner array closing bracket\");\n\n                // Parse the integers in this row\n                std::string row_str(it, inner_end);\n                auto row = parse_int_array(row_str);\n\n                if (!row.empty())\n                    grid.push_back(row);\n\n                it = inner_end;\n                ++it;\n\n                // Skip trailing whitespace, commas, and newlines\n                while (it != end && (*it == ' ' || *it == ',' || *it == '\\n' ||\n                    *it == '\\r' || *it == '\\t'))\n                    ++it;\n            }\n\n            // Advance past the closing ']' of the outer array\n            if (it != end && *it == ']') ++it;\n\n            return grid;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        inline std::string::const_iterator find_key_value_start(\n            const std::string& content,\n            const std::string& key,\n            std::string::const_iterator start_it)\n        /*!\n            ensures\n                - Searches for a JSON key-value pair starting from start_it\n                - Returns an iterator pointing to the first character of the value\n                - Returns content.end() if the key is not found\n        !*/\n        {\n            std::string search_str = \"\\\"\" + key + \"\\\":\";\n            auto pos = std::search(start_it, content.end(),\n                search_str.begin(), search_str.end());\n            if (pos == content.end()) return content.end();\n            pos += search_str.length();\n            while (pos != content.end() && std::isspace(*pos)) ++pos;\n            return pos;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        inline std::string extract_task_id_from_filename(const std::string& filename)\n        /*!\n            ensures\n                - Extracts the task ID from a filename by removing the file extension\n                - If no extension is found, returns the filename unchanged\n        !*/\n        {\n            size_t dot_pos = filename.find_last_of('.');\n            if (dot_pos == std::string::npos)\n                return filename;\n            return filename.substr(0, dot_pos);\n        }\n\n    } // namespace internal\n\n    // ----------------------------------------------------------------------------------------\n    // arc_agi_manager class\n    // ----------------------------------------------------------------------------------------\n\n    /*!\n        The arc_agi_manager class provides functionality to:\n        - Load ARC-AGI tasks from JSON files\n        - Manage training and evaluation datasets\n        - Convert grids to token sequences for LLM training\n        - Generate training batches with sliding window context\n        - Serialize and deserialize task data\n\n        THREAD SAFETY\n            This class is not thread-safe. External synchronization is required\n            if accessing the same instance from multiple threads.\n\n        TOKENIZATION STRATEGY\n            Grids are tokenized row-by-row with TOKEN_ROW_END markers to preserve\n            dimensional information. This allows the model to learn the structure\n            of non-square grids (ranging from 1x1 to 30x30) without explicit\n            dimension encoding.\n    !*/\n    class arc_agi_manager\n    {\n    private:\n        std::vector<arc_task> training_tasks;\n        std::vector<arc_task> evaluation_tasks;\n        std::map<std::string, size_t> training_task_id_map;\n        std::map<std::string, size_t> evaluation_task_id_map;\n\n        // ------------------------------------------------------------------------------------\n\n        static void append_flat_grid(std::vector<long>& sequence, const arc_grid_t& grid)\n        /*!\n            requires\n                - grid contains valid color values (0-9)\n            ensures\n                - Appends the grid to the sequence in row-major order\n                - Each row is terminated with TOKEN_ROW_END\n                - This encoding preserves grid dimensions for reconstruction\n        !*/\n        {\n            for (long r = 0; r < grid.nr(); ++r)\n            {\n                for (long c = 0; c < grid.nc(); ++c)\n                    sequence.push_back(static_cast<long>(grid(r, c)));\n\n                // Mark the end of this row to encode dimensional information\n                sequence.push_back(TOKEN_ROW_END);\n            }\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        static arc_grid_t to_dlib_matrix(const internal::raw_arc_grid_t& grid)\n        /*!\n            requires\n                - grid is a valid 2D array with consistent row lengths\n                - all values are in the range [0, 9]\n            ensures\n                - Converts a raw vector-of-vectors grid to a dlib matrix\n                - Returns an empty matrix if the input grid is empty\n            throws\n                - DLIB_CASSERT if row lengths are inconsistent\n                - DLIB_CASSERT if pixel values are outside [0, 9]\n        !*/\n        {\n            if (grid.empty()) return arc_grid_t(0, 0);\n            long rows = static_cast<long>(grid.size());\n            long cols = static_cast<long>(grid[0].size());\n            arc_grid_t mat(rows, cols);\n\n            for (long r = 0; r < rows; ++r)\n            {\n                DLIB_CASSERT(static_cast<long>(grid[r].size()) == cols,\n                    \"Inconsistent column size in grid\");\n                for (long c = 0; c < cols; ++c)\n                {\n                    DLIB_CASSERT(grid[r][c] >= 0 && grid[r][c] <= 9,\n                        \"Invalid pixel value (must be 0-9)\");\n                    mat(r, c) = static_cast<unsigned char>(grid[r][c]);\n                }\n            }\n            return mat;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        arc_task parse_arc_task_from_content(const std::string& content,\n            const std::string& filename)\n        /*!\n            ensures\n                - Parses a complete ARC task from JSON content\n                - Returns an arc_task structure with all training and test pairs\n                - Task ID is extracted from the filename\n            throws\n                - std::runtime_error on malformed JSON or missing required fields\n        !*/\n        {\n            arc_task task;\n            task.task_id = internal::extract_task_id_from_filename(filename);\n\n            auto parse_pairs = [&](const std::string& key,\n                std::vector<arc_task_pair>& pairs)\n                {\n                    auto it = internal::find_key_value_start(content, key, content.begin());\n                    if (it == content.end() || *it != '[')\n                        throw std::runtime_error(\"'\" + key + \"' array not found\");\n                    ++it;\n\n                    // Iterate through each object in the array\n                    while (it != content.end())\n                    {\n                        // Skip inter-object whitespace\n                        while (it != content.end() && std::isspace(*it)) ++it;\n\n                        // Check if we've reached the end of the array\n                        if (it == content.end() || *it == ']') break;\n\n                        // Locate the opening brace of this object\n                        if (*it != '{') {\n                            ++it;\n                            continue;\n                        }\n\n                        // Mark boundaries for scoped key searches\n                        auto object_start = it;\n                        ++it;\n\n                        // Find the matching closing brace\n                        int brace_depth = 1;\n                        auto object_end = it;\n                        while (object_end != content.end() && brace_depth > 0)\n                        {\n                            if (*object_end == '{') ++brace_depth;\n                            else if (*object_end == '}') --brace_depth;\n                            ++object_end;\n                        }\n\n                        if (object_end == content.end())\n                            throw std::runtime_error(\"Missing object closing bracket\");\n\n                        arc_task_pair pair;\n\n                        // Parse the \"input\" field within this object's scope\n                        auto input_it = internal::find_key_value_start(content, \"input\", object_start);\n                        if (input_it == content.end() || input_it >= object_end)\n                            throw std::runtime_error(\"'input' not found in \" + key + \" object\");\n\n                        auto raw_input = internal::parse_arc_grid(input_it, object_end);\n                        pair.input = to_dlib_matrix(raw_input);\n                        pair.input_rows = pair.input.nr();\n                        pair.input_cols = pair.input.nc();\n\n                        // Parse the \"output\" field (search starts after input)\n                        auto output_it = internal::find_key_value_start(content, \"output\", input_it);\n                        if (output_it == content.end() || output_it >= object_end)\n                            throw std::runtime_error(\"'output' not found in \" + key + \" object\");\n\n                        auto raw_output = internal::parse_arc_grid(output_it, object_end);\n                        pair.output = to_dlib_matrix(raw_output);\n                        pair.output_rows = pair.output.nr();\n                        pair.output_cols = pair.output.nc();\n\n                        pairs.push_back(pair);\n\n                        // Advance iterator past this object\n                        it = object_end;\n                    }\n                };\n\n            parse_pairs(\"train\", task.train_pairs);\n            parse_pairs(\"test\", task.test_pairs);\n            return task;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        std::vector<arc_task> load_all_tasks(const std::string& directory_path,\n            std::map<std::string, size_t>& id_map)\n        /*!\n            ensures\n                - Loads all .json files from the specified directory\n                - Each file is parsed as an ARC task\n                - Returns a vector of successfully loaded tasks\n                - Populates id_map with task_id to index mappings\n                - Outputs diagnostic information to stdout/stderr\n        !*/\n        {\n            std::vector<arc_task> tasks;\n            std::cout << \"Loading tasks from: \" << directory_path << std::endl;\n\n            try {\n                const dlib::directory dir(directory_path);\n                std::vector<dlib::file> all_files = dir.get_files();\n\n                std::cout << \"Found \" << all_files.size() << \" files in directory\" << std::endl;\n\n                // Filter for JSON files only\n                std::vector<dlib::file> json_files;\n                for (const auto& file : all_files)\n                {\n                    const std::string& filename = file.name();\n                    if (filename.size() >= 5 &&\n                        filename.substr(filename.size() - 5) == \".json\")\n                    {\n                        json_files.push_back(file);\n                    }\n                }\n\n                std::cout << \"Found \" << json_files.size() << \" .json files\" << std::endl;\n\n                if (json_files.empty()) {\n                    std::cout << \"WARNING: No .json files found in \"\n                        << directory_path << std::endl;\n                    return tasks;\n                }\n\n                size_t success_count = 0;\n                size_t error_count = 0;\n\n                // Attempt to load each JSON file\n                for (const auto& file : json_files)\n                {\n                    try {\n                        std::string content = internal::read_file_to_string(file.full_name());\n                        arc_task task = parse_arc_task_from_content(content, file.name());\n                        id_map[task.task_id] = tasks.size();\n                        tasks.push_back(task);\n                        ++success_count;\n                    }\n                    catch (const std::exception& e) {\n                        std::cerr << \"ERROR parsing \" << file.name()\n                            << \": \" << e.what() << std::endl;\n                        ++error_count;\n                    }\n                }\n\n                std::cout << \"Successfully loaded \" << success_count << \" tasks\" << std::endl;\n                if (error_count > 0) {\n                    std::cout << \"Failed to load \" << error_count << \" tasks\" << std::endl;\n                }\n\n            }\n            catch (const dlib::directory::dir_not_found& e) {\n                std::cerr << \"ERROR: Directory not found: \" << directory_path << std::endl;\n                std::cerr << \"Details: \" << e.info << std::endl;\n            }\n            catch (const dlib::directory::listing_error& e) {\n                std::cerr << \"ERROR: Cannot list directory: \" << directory_path << std::endl;\n                std::cerr << \"Details: \" << e.info << std::endl;\n            }\n            catch (const std::exception& e) {\n                std::cerr << \"ERROR during directory navigation: \" << e.what() << std::endl;\n            }\n            return tasks;\n        }\n\n    public:\n        arc_agi_manager() = default;\n\n        // ------------------------------------------------------------------------------------\n\n        void load_data(const std::string& training_path,\n            const std::string& evaluation_path)\n        /*!\n            ensures\n                - Loads all ARC tasks from training and evaluation directories\n                - Clears any previously loaded data\n                - Outputs a summary of loaded tasks to stdout\n        !*/\n        {\n            training_task_id_map.clear();\n            evaluation_task_id_map.clear();\n\n            training_tasks = load_all_tasks(training_path, training_task_id_map);\n            evaluation_tasks = load_all_tasks(evaluation_path, evaluation_task_id_map);\n\n            std::cout << \"--- ARC Data Loading Summary ---\" << std::endl;\n            std::cout << \"Loaded \" << training_tasks.size() << \" training tasks\" << std::endl;\n            std::cout << \"Loaded \" << evaluation_tasks.size() << \" evaluation tasks\" << std::endl;\n            std::cout << \"--------------------------------\" << std::endl;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        const arc_task& get_training_task(size_t index) const\n        /*!\n            requires\n                - index < num_training_tasks()\n            ensures\n                - Returns a const reference to the training task at the given index\n            throws\n                - DLIB_CASSERT if index is out of bounds\n        !*/\n        {\n            DLIB_CASSERT(index < training_tasks.size(),\n                \"Training task index out of bounds\"\n                << \"\\n\\tRequested index: \" << index\n                << \"\\n\\tAvailable tasks: \" << training_tasks.size());\n            return training_tasks[index];\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        const arc_task& get_evaluation_task(size_t index) const\n        /*!\n            requires\n                - index < num_evaluation_tasks()\n            ensures\n                - Returns a const reference to the evaluation task at the given index\n            throws\n                - DLIB_CASSERT if index is out of bounds\n        !*/\n        {\n            DLIB_CASSERT(index < evaluation_tasks.size(),\n                \"Evaluation task index out of bounds\");\n            return evaluation_tasks[index];\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        const arc_task& get_training_task_by_id(const std::string& task_id) const\n        /*!\n            ensures\n                - Returns a const reference to the training task with the given ID\n            throws\n                - std::runtime_error if task_id is not found\n        !*/\n        {\n            auto it = training_task_id_map.find(task_id);\n            if (it == training_task_id_map.end())\n                throw std::runtime_error(\"Training task ID not found: \" + task_id);\n            return training_tasks[it->second];\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        const arc_task& get_evaluation_task_by_id(const std::string& task_id) const\n        /*!\n            ensures\n                - Returns a const reference to the evaluation task with the given ID\n            throws\n                - std::runtime_error if task_id is not found\n        !*/\n        {\n            auto it = evaluation_task_id_map.find(task_id);\n            if (it == evaluation_task_id_map.end())\n                throw std::runtime_error(\"Evaluation task ID not found: \" + task_id);\n            return evaluation_tasks[it->second];\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        size_t num_training_tasks() const { return training_tasks.size(); }\n        size_t num_evaluation_tasks() const { return evaluation_tasks.size(); }\n\n        // ------------------------------------------------------------------------------------\n\n        void serialize(std::ostream& out) const\n        /*!\n            ensures\n                - Serializes the entire dataset to the output stream\n                - Format is versioned for forward compatibility\n        !*/\n        {\n            dlib::serialize(\"arc_agi_v1\", out);\n            dlib::serialize(training_tasks, out);\n            dlib::serialize(evaluation_tasks, out);\n            dlib::serialize(training_task_id_map, out);\n            dlib::serialize(evaluation_task_id_map, out);\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        void deserialize(std::istream& in)\n        /*!\n            ensures\n                - Deserializes a dataset from the input stream\n                - Replaces any existing data in this object\n            throws\n                - serialization_error if version mismatch is detected\n        !*/\n        {\n            std::string version;\n            dlib::deserialize(version, in);\n            if (version != \"arc_agi_v1\")\n                throw serialization_error(\"Unexpected version in arc_agi_manager\");\n            dlib::deserialize(training_tasks, in);\n            dlib::deserialize(evaluation_tasks, in);\n            dlib::deserialize(training_task_id_map, in);\n            dlib::deserialize(evaluation_task_id_map, in);\n        }\n\n        // ----------------------------------------------------------------------------------------\n        // Tokenization for LLM-style training\n        // ----------------------------------------------------------------------------------------\n\n        static arc_token_sequence_t tokenize_input_context(const arc_task& task,\n            const arc_task_pair& test_pair)\n        /*!\n            ensures\n                - Creates a token sequence representing the input context for a test pair\n                - Format: [train_input, SEP_IO, train_output, SEP_PAIR]* QUERY_START test_input GEN_START\n                - Each grid is tokenized with TOKEN_ROW_END markers preserving dimensions\n                - Returns a column vector of tokens\n        !*/\n        {\n            std::vector<long> sequence;\n\n            // Encode all training demonstration pairs\n            for (const auto& pair : task.train_pairs)\n            {\n                append_flat_grid(sequence, pair.input);\n                sequence.push_back(TOKEN_SEP_IO);\n                append_flat_grid(sequence, pair.output);\n                sequence.push_back(TOKEN_SEP_PAIR);\n            }\n\n            // Encode the test query\n            sequence.push_back(TOKEN_QUERY_START);\n            append_flat_grid(sequence, test_pair.input);\n            sequence.push_back(TOKEN_GEN_START);\n\n            // Convert to dlib column vector\n            arc_token_sequence_t result(static_cast<long>(sequence.size()));\n            for (long i = 0; i < static_cast<long>(sequence.size()); ++i)\n                result(i) = sequence[i];\n            return result;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        static arc_token_sequence_t tokenize_target_output(const arc_task_pair& test_pair)\n        /*!\n            ensures\n                - Creates a token sequence for the target output grid\n                - Format: output_grid END_OF_OUTPUT\n                - Output grid includes TOKEN_ROW_END markers\n                - Returns a column vector of tokens\n        !*/\n        {\n            std::vector<long> sequence;\n            append_flat_grid(sequence, test_pair.output);\n            sequence.push_back(TOKEN_END_OF_OUTPUT);\n\n            arc_token_sequence_t result(static_cast<long>(sequence.size()));\n            for (long i = 0; i < static_cast<long>(sequence.size()); ++i)\n                result(i) = sequence[i];\n            return result;\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        static void prepare_training_data_batch(\n            const arc_task& task,\n            long window_len,\n            std::vector<arc_token_sequence_t>& training_X_batch,\n            std::vector<long>& training_Y_batch)\n        /*!\n            requires\n                - window_len > 1\n            ensures\n                - Generates training samples using a sliding window approach\n                - Each X sample contains window_len tokens of context\n                - Each Y label is the next token following the context window\n                - Padding tokens are used when the window extends beyond sequence boundaries\n                - training_X_batch[i] is a column vector of length window_len\n                - training_Y_batch[i] is the target token for training_X_batch[i]\n                - Processes all test pairs in the task\n            throws\n                - DLIB_CASSERT if window_len <= 1\n\n            IMPLEMENTATION NOTES\n                This function implements causal language modeling for ARC tasks.\n                For each position in the concatenated [context + target] sequence,\n                it creates a training example where:\n                - X = [t_{pos-window_len+1}, ..., t_{pos}]\n                - Y = t_{pos+1}\n\n                The sliding window ensures the model learns to predict each token\n                given the appropriate amount of left context.\n        !*/\n        {\n            DLIB_CASSERT(window_len > 1, \"Window length must be greater than 1\");\n\n            training_X_batch.clear();\n            training_Y_batch.clear();\n\n            for (const arc_task_pair& test_pair : task.test_pairs)\n            {\n                // Tokenize the full sequence: context + target\n                arc_token_sequence_t input_context = tokenize_input_context(task, test_pair);\n                arc_token_sequence_t target_output = tokenize_target_output(test_pair);\n\n                long L_in = input_context.size();\n                long L_out = target_output.size();\n                long L_full = L_in + L_out;\n\n                // Build the complete token sequence\n                std::vector<long> S_vec;\n                S_vec.reserve(static_cast<size_t>(L_full));\n\n                for (long i = 0; i < L_in; ++i)\n                    S_vec.push_back(input_context(i));\n                for (long i = 0; i < L_out; ++i)\n                    S_vec.push_back(target_output(i));\n\n                // Generate sliding window samples\n                // For each position, create a context window of length window_len\n                for (long pos = 0; pos < L_full; ++pos)\n                {\n                    arc_token_sequence_t X_window(window_len);\n\n                    // Fill the context window\n                    // Window spans from (pos - window_len + 1) to pos inclusive\n                    for (long i = 0; i < window_len; ++i)\n                    {\n                        long context_idx = pos - window_len + 1 + i;\n\n                        // Use padding for positions before sequence start or after end\n                        if (context_idx < 0 || context_idx >= L_full)\n                            X_window(i) = TOKEN_PADDING;\n                        else\n                            X_window(i) = S_vec[static_cast<size_t>(context_idx)];\n                    }\n\n                    // The target is the next token after the window\n                    long y_token = (pos + 1 < L_full) ?\n                        S_vec[static_cast<size_t>(pos + 1)] : TOKEN_PADDING;\n\n                    training_X_batch.push_back(std::move(X_window));\n                    training_Y_batch.push_back(y_token);\n                }\n            }\n        }\n\n        // ----------------------------------------------------------------------------------------\n        // Detokenization utilities\n        // ----------------------------------------------------------------------------------------\n\n        static arc_grid_t detokenize_to_grid(const arc_token_sequence_t& tokens,\n            long start_idx = 0)\n        /*!\n            ensures\n                - Reconstructs a grid from a tokenized sequence\n                - Uses TOKEN_ROW_END markers to determine row boundaries\n                - Stops at TOKEN_END_OF_OUTPUT, TOKEN_SEP_IO, or TOKEN_SEP_PAIR\n                - Returns a matrix with the reconstructed grid\n                - Returns an empty matrix if no valid grid is found\n            throws\n                - DLIB_CASSERT if row lengths are inconsistent\n\n            IMPLEMENTATION NOTES\n                This function recovers grid dimensions from the token stream by\n                counting tokens between TOKEN_ROW_END markers. This allows the\n                model to generate grids of arbitrary dimensions (1x1 to 30x30)\n                without explicit dimension specification.\n        !*/\n        {\n            // Extract rows from the token sequence\n            std::vector<std::vector<unsigned char>> rows;\n            std::vector<unsigned char> current_row;\n\n            for (long i = start_idx; i < tokens.size(); ++i)\n            {\n                long token = tokens(i);\n\n                if (token == TOKEN_ROW_END)\n                {\n                    // End of current row - save it if non-empty\n                    if (!current_row.empty())\n                    {\n                        rows.push_back(current_row);\n                        current_row.clear();\n                    }\n                }\n                else if (token == TOKEN_END_OF_OUTPUT ||\n                    token == TOKEN_SEP_IO ||\n                    token == TOKEN_SEP_PAIR)\n                {\n                    // End of grid section\n                    break;\n                }\n                else if (token >= COLOR_0 && token <= COLOR_9)\n                {\n                    // Valid color token - add to current row\n                    current_row.push_back(static_cast<unsigned char>(token));\n                }\n                // Ignore other tokens (padding, etc.)\n            }\n\n            // Build the output matrix\n            if (rows.empty())\n                return arc_grid_t(0, 0);\n\n            long n_rows = static_cast<long>(rows.size());\n            long n_cols = static_cast<long>(rows[0].size());\n\n            arc_grid_t grid(n_rows, n_cols);\n            for (long r = 0; r < n_rows; ++r)\n            {\n                DLIB_CASSERT(static_cast<long>(rows[r].size()) == n_cols,\n                    \"Inconsistent row length during detokenization\"\n                    << \"\\n\\tRow \" << r << \" has \" << rows[r].size() << \" columns\"\n                    << \"\\n\\tExpected \" << n_cols << \" columns\");\n                for (long c = 0; c < n_cols; ++c)\n                    grid(r, c) = rows[r][c];\n            }\n\n            return grid;\n        }\n    };\n\n} // namespace dlib\n\n#endif // DLIB_ARC_AGI_H_"
  },
  {
    "path": "dlib/data_io/arc_agi_abstract.h",
    "content": "﻿// Copyright (C) 2025  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ARC_AGI_ABSTRACT_H_\n#ifdef DLIB_ARC_AGI_ABSTRACT_H_\n\n#include <string>\n#include <vector>\n#include <map>\n#include \"../matrix.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n    // Type aliases for ARC-AGI data structures\n    using arc_grid_t = matrix<unsigned char>;\n    using arc_token_sequence_t = matrix<long, 0, 1>;\n\n    // Maximum sequence length for LLM-style training\n    constexpr long ARC_MAX_SEQUENCE_LENGTH = 4096;\n\n    // Token vocabulary for the Hierarchical Reasoning Model\n    enum arc_token_id : long\n    {\n        COLOR_0 = 0, COLOR_1 = 1, COLOR_2 = 2, COLOR_3 = 3, COLOR_4 = 4,\n        COLOR_5 = 5, COLOR_6 = 6, COLOR_7 = 7, COLOR_8 = 8, COLOR_9 = 9,\n        TOKEN_SEP_IO = 10,\n        TOKEN_SEP_PAIR = 11,\n        TOKEN_QUERY_START = 12,\n        TOKEN_GEN_START = 13,\n        TOKEN_END_OF_OUTPUT = 14,\n        TOKEN_PADDING = 15,\n        TOKEN_ROW_END = 16\n    };\n\n    // Vocabulary size constants\n    constexpr long ARC_VOCAB_SIZE_COLORS = 10;\n    constexpr long ARC_VOCAB_SIZE_TOTAL = 17;\n\n    struct arc_task_pair\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                Represents a single Input/Output example pair within an ARC task.\n                Each pair demonstrates a transformation pattern that the model must learn.\n        !*/\n\n        arc_grid_t input;\n        /*!\n            The input grid (2D matrix of color values 0-9)\n        !*/\n\n        arc_grid_t output;\n        /*!\n            The corresponding output grid showing the transformed result\n        !*/\n\n        long input_rows;\n        long input_cols;\n        long output_rows;\n        long output_cols;\n        /*!\n            Dimensions of the input and output grids\n        !*/\n    };\n\n    struct arc_task\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                Represents a complete ARC-AGI reasoning task containing:\n                - Multiple training pairs demonstrating a pattern\n                - One or more test pairs where the model must predict outputs\n        !*/\n\n        std::string task_id;\n        /*!\n            Unique identifier extracted from the JSON filename\n        !*/\n\n        std::vector<arc_task_pair> train_pairs;\n        /*!\n            Training examples demonstrating the pattern to learn\n        !*/\n\n        std::vector<arc_task_pair> test_pairs;\n        /*!\n            Test cases where the model must predict the output\n        !*/\n    };\n\n    class arc_agi_manager\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object provides utilities for loading, accessing, and preparing\n                ARC-AGI (Abstraction and Reasoning Corpus for Artificial General Intelligence)\n                dataset for training Transformer-based models such as the Hierarchical\n                Reasoning Model (HRM).\n\n                The ARC-AGI dataset consists of visual reasoning tasks where each task\n                contains:\n                - Training pairs: Input/Output grid examples demonstrating a pattern\n                - Test pairs: Input grids where the model must predict the output\n\n                Each grid is a 2D matrix of integers (0-9) representing colors/symbols,\n                with maximum dimensions of 30x30.\n\n                TOKENIZATION STRATEGY\n                    Grids are tokenized row-by-row with TOKEN_ROW_END markers inserted\n                    at the end of each row. This encoding preserves dimensional information\n                    implicitly, allowing the model to learn and generate grids of arbitrary\n                    dimensions (1x1 to 30x30, including non-square grids) without requiring\n                    explicit dimension specification.\n\n                The dataset is available from: https://github.com/fchollet/ARC-AGI\n        !*/\n\n    public:\n        arc_agi_manager();\n        /*!\n            ensures\n                - Constructs an empty arc_agi_manager object\n        !*/\n\n        void load_data(\n            const std::string& training_path,\n            const std::string& evaluation_path\n        );\n        /*!\n            ensures\n                - Attempts to load the ARC-AGI dataset from the specified directories\n                - training_path should contain JSON files for training tasks\n                - evaluation_path should contain JSON files for evaluation tasks\n                - Each JSON file represents one task with training and test pairs\n                - Task IDs are extracted from filenames (without .json extension)\n            throws\n                - std::runtime_error if directories cannot be accessed or files\n                  cannot be parsed\n        !*/\n\n        const arc_task& get_training_task(size_t index) const;\n        /*!\n            requires\n                - index < num_training_tasks()\n            ensures\n                - Returns the training task at the specified index\n            throws\n                - std::out_of_range if index is out of bounds\n        !*/\n\n        const arc_task& get_evaluation_task(size_t index) const;\n        /*!\n            requires\n                - index < num_evaluation_tasks()\n            ensures\n                - Returns the evaluation task at the specified index\n            throws\n                - std::out_of_range if index is out of bounds\n        !*/\n\n        const arc_task& get_training_task_by_id(const std::string& task_id) const;\n        /*!\n            requires\n                - task_id is a valid task identifier\n            ensures\n                - Returns the training task with the specified task_id\n            throws\n                - std::runtime_error if task_id is not found\n        !*/\n\n        const arc_task& get_evaluation_task_by_id(const std::string& task_id) const;\n        /*!\n            requires\n                - task_id is a valid task identifier\n            ensures\n                - Returns the evaluation task with the specified task_id\n            throws\n                - std::runtime_error if task_id is not found\n        !*/\n\n        size_t num_training_tasks() const;\n        /*!\n            ensures\n                - Returns the number of loaded training tasks\n        !*/\n\n        size_t num_evaluation_tasks() const;\n        /*!\n            ensures\n                - Returns the number of loaded evaluation tasks\n        !*/\n\n        void serialize(std::ostream& out) const;\n        /*!\n            ensures\n                - Writes the entire dataset to the output stream in Dlib's\n                  serialization format\n                - Can be saved to a .dat file for faster loading\n        !*/\n\n        void deserialize(std::istream& in);\n        /*!\n            ensures\n                - Loads the entire dataset from the input stream\n                - Stream must contain data previously written by serialize()\n            throws\n                - serialization_error if data format is invalid\n        !*/\n\n        static arc_token_sequence_t tokenize_input_context(\n            const arc_task& task,\n            const arc_task_pair& test_pair\n        );\n        /*!\n            ensures\n                - Converts the task's training pairs and the specified test input\n                  into a token sequence suitable for LLM-style training\n                - Returns a sequence: [grid_tokens..., ROW_END, SEP_IO,\n                  grid_tokens..., ROW_END, SEP_PAIR, ..., QUERY_START,\n                  test_input_tokens..., ROW_END, GEN_START]\n                - Each grid is encoded with TOKEN_ROW_END markers at the end of\n                  each row to preserve dimensional information\n                - This represents the context that the model uses to predict the output\n        !*/\n\n        static arc_token_sequence_t tokenize_target_output(\n            const arc_task_pair& test_pair\n        );\n        /*!\n            ensures\n                - Converts the test output grid into a token sequence\n                - Returns a sequence: [grid_tokens..., ROW_END, ..., END_OF_OUTPUT]\n                - Each row is terminated with TOKEN_ROW_END to preserve dimensions\n                - This represents the ground truth that the model should predict\n        !*/\n\n        static void prepare_training_data_batch(\n            const arc_task& task,\n            long window_len,\n            std::vector<arc_token_sequence_t>& training_X_batch,\n            std::vector<long>& training_Y_batch\n        );\n        /*!\n            requires\n                - window_len > 1\n            ensures\n                - Prepares training data in the format required by dlib::dnn::trainer\n                  using a sliding window approach for causal language modeling\n                - For each test pair in the task, generates training samples where:\n                  * Each X sample is a context window of size window_len containing\n                    the previous window_len tokens\n                  * Each Y label is the next token that should follow the context\n                - #training_X_batch.size() == #training_Y_batch.size()\n                - Each training_X_batch[i] is a column vector (matrix<long, 0, 1>)\n                  of size window_len x 1\n                - Each training_Y_batch[i] is a single token (long) representing\n                  the target to predict\n                - Implements left-padding with TOKEN_PADDING when the context window\n                  extends before the sequence start, preserving recent context on\n                  the right side (standard for causal language models)\n                - The concatenated sequence is: [input_context, target_output]\n            throws\n                - std::invalid_argument if window_len <= 1\n\n            EXAMPLE\n                For a sequence [A, B, C, D, E] with window_len=3:\n                X[0] = [PAD, PAD, A]  => Y[0] = B\n                X[1] = [PAD, A, B]    => Y[1] = C\n                X[2] = [A, B, C]      => Y[2] = D\n                X[3] = [B, C, D]      => Y[3] = E\n                X[4] = [C, D, E]      => Y[4] = PAD\n        !*/\n\n        static arc_grid_t detokenize_to_grid(\n            const arc_token_sequence_t& tokens,\n            long start_idx = 0\n        );\n        /*!\n            requires\n                - tokens contains a valid tokenized grid sequence with TOKEN_ROW_END markers\n            ensures\n                - Reconstructs a grid from a tokenized sequence\n                - Uses TOKEN_ROW_END markers to determine row boundaries and infer\n                  grid dimensions\n                - Parsing stops at TOKEN_END_OF_OUTPUT, TOKEN_SEP_IO, or TOKEN_SEP_PAIR\n                - Returns a matrix containing the reconstructed grid\n                - Returns an empty matrix (0x0) if no valid grid is found\n                - Grid dimensions are automatically determined from the token stream:\n                  * Number of rows = count of TOKEN_ROW_END markers\n                  * Number of columns = tokens between consecutive TOKEN_ROW_END markers\n            throws\n                - DLIB_CASSERT if row lengths are inconsistent (indicating malformed data)\n\n            EXAMPLE\n                Input tokens: [1, 2, 3, ROW_END, 4, 5, 6, ROW_END, END_OF_OUTPUT]\n                Returns: 2x3 grid = [[1, 2, 3], [4, 5, 6]]\n        !*/\n    };\n\n} // namespace dlib\n\n#endif // DLIB_ARC_AGI_ABSTRACT_H_"
  },
  {
    "path": "dlib/data_io/cifar.cpp",
    "content": "// Copyright (C) 2020  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CIFAR_CPp_\n#define DLIB_CIFAR_CPp_\n\n#include \"cifar.h\"\n#include <fstream>\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    namespace impl\n    {\n        void load_cifar_10_batch (\n            const std::string& folder_name,\n            const std::string& batch_name,\n            const size_t first_idx,\n            const size_t images_per_batch,\n            std::vector<matrix<rgb_pixel>>& images,\n            std::vector<unsigned long>& labels\n        )\n        {\n            std::ifstream fin(folder_name + \"/\" + batch_name, std::ios::binary);\n            if (!fin) throw error(\"Unable to open file \" + batch_name);\n            const long nr = 32;\n            const long nc = 32;\n            const long plane_size = nr * nc;\n            const long image_size = 3 * plane_size;\n\n            for (size_t i = 0; i < images_per_batch; ++i)\n            {\n                char l;\n                fin.read(&l, 1);\n                labels[first_idx + i] = l;\n                images[first_idx + i].set_size(nr, nc);\n\n                std::array<unsigned char, image_size> buffer;\n                fin.read((char*)(buffer.data()), buffer.size());\n                for (long k = 0; k < plane_size; ++k)\n                {\n                    char r = buffer[0 * plane_size + k];\n                    char g = buffer[1 * plane_size + k];\n                    char b = buffer[2 * plane_size + k];\n                    const long row = k / nr;\n                    const long col = k % nr;\n                    images[first_idx + i](row, col) = rgb_pixel(r, g, b);\n                }\n            }\n\n            if (!fin) throw error(\"Unable to read file \" + batch_name);\n\n            if (fin.get() != EOF) throw error(\"Unexpected bytes at end of \" + batch_name);\n        }\n    }\n\n    void load_cifar_10_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<rgb_pixel>>& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<rgb_pixel>>& testing_images,\n        std::vector<unsigned long>& testing_labels\n    )\n    {\n        using namespace std;\n\n        const size_t images_per_batch = 10000;\n        const size_t num_training_batches = 5;\n        const size_t num_testing_batches = 1;\n\n        training_images.resize(images_per_batch * num_training_batches);\n        training_labels.resize(images_per_batch * num_training_batches);\n        testing_images.resize(images_per_batch * num_testing_batches);\n        testing_labels.resize(images_per_batch * num_testing_batches);\n\n        std::vector<string> training_batches_names{\n            \"data_batch_1.bin\",\n            \"data_batch_2.bin\",\n            \"data_batch_3.bin\",\n            \"data_batch_4.bin\",\n            \"data_batch_5.bin\",\n        };\n\n        for (size_t i = 0; i < num_training_batches; ++i)\n        {\n            impl::load_cifar_10_batch(\n                folder_name,\n                training_batches_names[i],\n                i * images_per_batch,\n                images_per_batch,\n                training_images,\n                training_labels);\n        }\n\n        impl::load_cifar_10_batch(\n            folder_name,\n            \"test_batch.bin\",\n            0,\n            images_per_batch,\n            testing_images,\n            testing_labels);\n    }\n}\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_CIFAR_CPp_\n"
  },
  {
    "path": "dlib/data_io/cifar.h",
    "content": "// Copyright (C) 2020  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CIFAR_Hh_\n#define DLIB_CIFAR_Hh_\n\n#include \"cifar_abstract.h\"\n#include <string>\n#include <vector>\n#include \"../matrix.h\"\n#include \"../pixel.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void load_cifar_10_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<rgb_pixel>>& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<rgb_pixel>>& testing_images,\n        std::vector<unsigned long>& testing_labels\n    );\n}\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef NO_MAKEFILE\n#include \"cifar.cpp\"\n#endif\n\n#endif // DLIB_CIFAR_Hh_\n"
  },
  {
    "path": "dlib/data_io/cifar_abstract.h",
    "content": "// Copyright (C) 2020  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CIFAR_ABSTRACT_Hh_\n#ifdef DLIB_CIFAR_ABSTRACT_Hh_\n\n#include <string>\n#include <vector>\n#include \"../matrix.h\"\n#include \"../pixel.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void load_cifar_10_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<rgb_pixel>>& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<rgb_pixel>>& testing_images,\n        std::vector<unsigned long>& testing_labels\n    );\n    /*!\n        ensures\n            - Attempts to load the CIFAR-10 dataset from the hard drive.  The CIFAR-10\n              dataset consists of 60000 32x32 colour images in 10 classes, with 6000 images\n              per class.  There are 50000 training images and 10000 test images.  It is\n              available from https://www.cs.toronto.edu/~kriz/cifar.html.  In particular,\n              the 6 files comprising the CIFAR-10 dataset should be present in the folder\n              indicated by folder_name.  These six files are:\n                - data_batch_1.bin\n                - data_batch_2.bin\n                - data_batch_3.bin\n                - data_batch_4.bin\n                - data_batch_5.bin\n                - test_batch.bin\n            - #training_images == The 50,000 training images from the dataset.\n            - #training_labels == The labels for the contents of #training_images.\n              I.e. #training_labels[i] is the label of #training_images[i].\n            - #testing_images == The 10,000 testing images from the dataset. \n            - #testing_labels == The labels for the contents of #testing_images.\n              I.e. #testing_labels[i] is the label of #testing_images[i].\n        throws\n            - dlib::error if some problem prevents us from loading the data or the files\n              can't be found.\n    !*/\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_CIFAR_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/data_io/image_dataset_metadata.cpp",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_DAtASET_METADATA_CPPh_\n#define DLIB_IMAGE_DAtASET_METADATA_CPPh_\n\n#include \"image_dataset_metadata.h\"\n\n#include <fstream>\n#include <sstream>\n#include \"../compress_stream.h\"\n#include \"../base64.h\"\n#include \"../xml_parser.h\"\n#include \"../string.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    namespace image_dataset_metadata\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        const std::string get_decoded_string();\n        void create_image_metadata_stylesheet_file(const std::string& main_filename)\n        {\n            std::string path;\n            std::string::size_type pos = main_filename.find_last_of(\"/\\\\\");\n            if (pos != std::string::npos)\n                path = main_filename.substr(0,pos+1);\n\n            std::ofstream fout((path + \"image_metadata_stylesheet.xsl\").c_str());\n            if (!fout)\n                throw dlib::error(\"ERROR: Unable to open image_metadata_stylesheet.xsl for writing.\");\n\n            fout << get_decoded_string();\n\n            if (!fout)\n                throw dlib::error(\"ERROR: Unable to write to image_metadata_stylesheet.xsl.\");\n        }\n\n        void save_image_dataset_metadata (\n            const dataset& meta,\n            const std::string& filename\n        )\n        {\n            create_image_metadata_stylesheet_file(filename);\n\n            const std::vector<image>& images = meta.images;\n\n            std::ofstream fout(filename.c_str());\n            if (!fout)\n                throw dlib::error(\"ERROR: Unable to open \" + filename + \" for writing.\");\n\n            fout << \"<?xml version='1.0' encoding='ISO-8859-1'?>\\n\";\n            fout << \"<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>\\n\";\n            fout << \"<dataset>\\n\";\n            fout << \"<name>\" << meta.name << \"</name>\\n\";\n            fout << \"<comment>\" << meta.comment << \"</comment>\\n\";\n            fout << \"<images>\\n\";\n            for (unsigned long i = 0; i < images.size(); ++i)\n            {\n                fout << \"  <image file='\" << images[i].filename << \"'\";\n                if (images[i].width != 0 && images[i].height != 0)\n                {\n                    fout << \" width='\" << images[i].width << \"'\";\n                    fout << \" height='\" << images[i].height << \"'\";\n                }\n                fout << \">\\n\";\n\n                // save all the boxes\n                for (unsigned long j = 0; j < images[i].boxes.size(); ++j)\n                {\n                    const box& b = images[i].boxes[j];\n                    fout << \"    <box top='\" << b.rect.top() << \"' \"\n                                 << \"left='\" << b.rect.left() << \"' \"\n                                << \"width='\" << b.rect.width() << \"' \"\n                               << \"height='\" << b.rect.height() << \"'\";\n                    if (b.difficult)\n                        fout << \" difficult='\" << b.difficult << \"'\";\n                    if (b.truncated)\n                        fout << \" truncated='\" << b.truncated << \"'\";\n                    if (b.occluded)\n                        fout << \" occluded='\" << b.occluded << \"'\";\n                    if (b.ignore)\n                        fout << \" ignore='\" << b.ignore << \"'\";\n                    if (b.angle != 0)\n                        fout << \" angle='\" << b.angle << \"'\";\n                    if (b.age != 0)\n                        fout << \" age='\" << b.age << \"'\";\n                    if (b.gender == FEMALE)\n                        fout << \" gender='female'\";\n                    else if (b.gender == MALE)\n                        fout << \" gender='male'\";\n                    if (b.pose != 0)\n                        fout << \" pose='\" << b.pose << \"'\";\n                    if (b.detection_score != 0)\n                        fout << \" detection_score='\" << b.detection_score << \"'\";\n\n                    if (b.has_label() || b.parts.size() != 0)\n                    {\n                        fout << \">\\n\";\n\n                        if (b.has_label())\n                            fout << \"      <label>\" << b.label << \"</label>\\n\";\n                        \n                        // save all the parts\n                        std::map<std::string,point>::const_iterator itr;\n                        for (itr = b.parts.begin(); itr != b.parts.end(); ++itr)\n                        {\n                            fout << \"      <part name='\"<< itr->first << \"' x='\"<< itr->second.x() <<\"' y='\"<< itr->second.y() <<\"'/>\\n\";\n                        }\n\n                        fout << \"    </box>\\n\";\n                    }\n                    else\n                    {\n                        fout << \"/>\\n\";\n                    }\n                }\n\n\n\n                fout << \"  </image>\\n\";\n\n                if (!fout)\n                    throw dlib::error(\"ERROR: Unable to write to \" + filename + \".\");\n            }\n            fout << \"</images>\\n\";\n            fout << \"</dataset>\";\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        class doc_handler : public document_handler\n        {\n            std::vector<std::string> ts;\n            image temp_image;\n            box temp_box;\n\n            dataset& meta;\n\n        public:\n\n            doc_handler(\n                dataset& metadata_\n            ):\n                meta(metadata_) \n            {}\n\n\n            virtual void start_document (\n            )\n            {\n                meta = dataset();\n                ts.clear();\n                temp_image = image();\n                temp_box = box();\n            }\n\n            virtual void end_document (\n            )\n            {\n            }\n\n            virtual void start_element ( \n                const unsigned long line_number,\n                const std::string& name,\n                const dlib::attribute_list& atts\n            )\n            {\n                try\n                {\n                    if (ts.size() == 0) \n                    {\n                        if (name != \"dataset\")\n                        {\n                            std::ostringstream sout;\n                            sout << \"Invalid XML document.  Root tag must be <dataset>.  Found <\" << name << \"> instead.\";\n                            throw dlib::error(sout.str());\n                        }\n                        else\n                        {\n                            ts.push_back(name);\n                            return;\n                        }\n                    }\n\n\n                    if (name == \"box\")\n                    {\n                        if (atts.is_in_list(\"top\")) temp_box.rect.top() = sa = atts[\"top\"];\n                        else throw dlib::error(\"<box> missing required attribute 'top'\");\n\n                        if (atts.is_in_list(\"left\")) temp_box.rect.left() = sa = atts[\"left\"];\n                        else throw dlib::error(\"<box> missing required attribute 'left'\");\n\n                        if (atts.is_in_list(\"width\")) temp_box.rect.right() = sa = atts[\"width\"];\n                        else throw dlib::error(\"<box> missing required attribute 'width'\");\n\n                        if (atts.is_in_list(\"height\")) temp_box.rect.bottom() = sa = atts[\"height\"];\n                        else throw dlib::error(\"<box> missing required attribute 'height'\");\n\n                        if (atts.is_in_list(\"difficult\")) temp_box.difficult = sa = atts[\"difficult\"];\n                        if (atts.is_in_list(\"truncated\")) temp_box.truncated = sa = atts[\"truncated\"];\n                        if (atts.is_in_list(\"occluded\"))  temp_box.occluded  = sa = atts[\"occluded\"];\n                        if (atts.is_in_list(\"ignore\"))  temp_box.ignore  = sa = atts[\"ignore\"];\n                        if (atts.is_in_list(\"angle\"))  temp_box.angle  = sa = atts[\"angle\"];\n                        if (atts.is_in_list(\"age\"))  temp_box.age  = sa = atts[\"age\"];\n                        if (atts.is_in_list(\"gender\"))  \n                        {\n                            if (atts[\"gender\"] == \"male\")\n                                temp_box.gender = MALE;\n                            else if (atts[\"gender\"] == \"female\")\n                                temp_box.gender = FEMALE;\n                            else if (atts[\"gender\"] == \"unknown\")\n                                temp_box.gender = UNKNOWN;\n                            else\n                                throw dlib::error(\"Invalid gender string in box attribute.\");\n                        }\n                        if (atts.is_in_list(\"pose\"))  temp_box.pose  = sa = atts[\"pose\"];\n                        if (atts.is_in_list(\"detection_score\"))  temp_box.detection_score  = sa = atts[\"detection_score\"];\n\n                        temp_box.rect.bottom() += temp_box.rect.top()-1;\n                        temp_box.rect.right() += temp_box.rect.left()-1;\n                    }\n                    else if (name == \"part\" && ts.back() == \"box\")\n                    {\n                        point temp;\n                        if (atts.is_in_list(\"x\")) temp.x() = sa = atts[\"x\"];\n                        else throw dlib::error(\"<part> missing required attribute 'x'\");\n\n                        if (atts.is_in_list(\"y\")) temp.y() = sa = atts[\"y\"];\n                        else throw dlib::error(\"<part> missing required attribute 'y'\");\n\n                        if (atts.is_in_list(\"name\")) \n                        {\n                            if (temp_box.parts.count(atts[\"name\"])==0)\n                            {\n                                temp_box.parts[atts[\"name\"]] = temp;\n                            }\n                            else\n                            {\n                                throw dlib::error(\"<part> with name '\" + atts[\"name\"] + \"' is defined more than one time in a single box.\");\n                            }\n                        }\n                        else \n                        {\n                            throw dlib::error(\"<part> missing required attribute 'name'\");\n                        }\n                    }\n                    else if (name == \"image\")\n                    {\n                        temp_image.boxes.clear();\n\n                        if (atts.is_in_list(\"file\")) temp_image.filename = atts[\"file\"];\n                        else throw dlib::error(\"<image> missing required attribute 'file'\");\n\n                        if (atts.is_in_list(\"width\")) temp_image.width = sa = atts[\"width\"];\n                        if (atts.is_in_list(\"height\")) temp_image.height = sa = atts[\"height\"];\n                    }\n\n                    ts.push_back(name);\n                }\n                catch (error& e)\n                {\n                    throw dlib::error(\"Error on line \" + cast_to_string(line_number) + \": \" + e.what());\n                }\n            }\n\n            virtual void end_element ( \n                const unsigned long ,\n                const std::string& name\n            )\n            {\n                ts.pop_back();\n                if (ts.size() == 0)\n                    return;\n\n                if (name == \"box\" && ts.back() == \"image\")\n                {\n                    temp_image.boxes.push_back(temp_box);\n                    temp_box = box();\n                }\n                else if (name == \"image\" && ts.back() == \"images\")\n                {\n                    meta.images.push_back(temp_image);\n                    temp_image = image();\n                }\n            }\n\n            virtual void characters ( \n                const std::string& data\n            )\n            {\n                if (ts.size() == 2 && ts[1] == \"name\")\n                {\n                    meta.name = trim(data);\n                }\n                else if (ts.size() == 2 && ts[1] == \"comment\")\n                {\n                    meta.comment = trim(data);\n                }\n                else if (ts.size() >= 2 && ts[ts.size()-1] == \"label\" && \n                                           ts[ts.size()-2] == \"box\")\n                {\n                    temp_box.label = trim(data);\n                }\n            }\n\n            virtual void processing_instruction (\n                const unsigned long ,\n                const std::string& ,\n                const std::string& \n            )\n            {\n            }\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        class xml_error_handler : public error_handler\n        {\n        public:\n            virtual void error (\n                const unsigned long \n            ) { }\n\n            virtual void fatal_error (\n                const unsigned long line_number\n            )\n            {\n                std::ostringstream sout;\n                sout << \"There is a fatal error on line \" << line_number << \" so parsing will now halt.\";\n                throw dlib::error(sout.str());\n            }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        void load_image_dataset_metadata (\n            dataset& meta,\n            const std::string& filename\n        )\n        {\n            xml_error_handler eh;\n            doc_handler dh(meta);\n\n            std::ifstream fin(filename.c_str());\n            if (!fin)\n                throw dlib::error(\"ERROR: unable to open \" + filename + \" for reading.\");\n\n            xml_parser parser;\n            parser.add_document_handler(dh);\n            parser.add_error_handler(eh);\n            parser.parse(fin);\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        // This function returns the contents of the file 'images.xsl'\n        const std::string get_decoded_string()\n        {\n            dlib::base64 base64_coder;\n            dlib::compress_stream::kernel_1ea compressor;\n            std::ostringstream sout;\n            std::istringstream sin;\n\n            // The base64 encoded data from the file 'image_metadata_stylesheet.xsl' we want to decode and return.\n            sout << \"PFWfgmWfCHr1DkV63lbjjeY2dCc2FbHDOVh0Kd7dkvaOfRYrOG24f0x77/5iMVq8FtE3UBxtGwSd\";\n            sout << \"1ZHOHRSHgieNoeBv8ssJQ75RRxYtFKRY3OTPX5eKQoCN9jUaUnHnR4QZtEHgmKqXSs50Yrdd+2Ah\";\n            sout << \"gNyarPZCiR6nvqNvCjtP2MP5FxleqNf8Fylatm2KdsXmrv5K87LYVN7i7JMkmZ++cTXYSOxDmxZi\";\n            sout << \"OiCH8funXUdF9apDW547gCjz9HOQUI6dkz5dYUeFjfp6dFugpnaJyyprFLKq048Qk7+QiL4CNF/G\";\n            sout << \"7e0VpBw8dMpiyRNi2fSQGSZGfIAUQKKT6+rPwQoRH2spdjsdXVWj4XQAqBX87nmqMnqjMhn/Vd1s\";\n            sout << \"W5aoC0drwRGu3Xe3gn9vBL8hBkRXcJvEy6q/lb9bYnsLemhE5Zp/+nTmTBjfT9UFYLcsmgsjC+4n\";\n            sout << \"Bq6h9QlpuyMYqJ8RvW8pp3mFlvXc3Yg+18t5F0hSMQfaIFYAuDPU2lVzPpY+ba0B39iu9IrPCLsS\";\n            sout << \"+tUtSNSmQ74CtzZgKKjkTMA3nwYP2SDmZE3firq42pihT7hdU5vYkes69K8AQl8WZyLPpMww+r0z\";\n            sout << \"+veEHPlAuxF7kL3ZvVjdB+xABwwqDe0kSRHRZINYdUfJwJdfYLyDnYoMjj6afqIJZ7QOBPZ42tV5\";\n            sout << \"3hYOQTFwTNovOastzJJXQe1kxPg1AQ8ynmfjjJZqD0xKedlyeJybP919mVAA23UryHsq9TVlabou\";\n            sout << \"qNl3xZW/mKKktvVsd/nuH62HIv/kgomyhaEUY5HgupupBUbQFZfyljZ5bl3g3V3Y1400Z1xTM/LL\";\n            sout << \"LJpeLdlqoGzIe/19vAN1zUUVId9F/OLNUl3Zoar63yZERSJHcsuq/Pasisp0HIGi7rfI9EIQF7C/\";\n            sout << \"IhLKLZsJ+LOycreQGOJALZIEZHOqxYLSXG0qaPM5bQL/MQJ2OZfwEhQgYOrjaM7oPOHHEfTq5kcO\";\n            sout << \"daMwzefKfxrF2GXbUs0bYsEXsIGwENIUKMliFaAI4qKLxxb94oc+O3BRjWueZjZty2zKawQyTHNd\";\n            sout << \"ltFJBUzfffdZN9Wq4zbPzntkM3U6Ys4LRztx5M15dtbhFeKx5rAf2tPXT6wU01hx7EJxBJzpvoDE\";\n            sout << \"YwEoYVDSYulRKpgk82cHFzzUDgWXbl4paFSe1L1w8r9KHr67SYJDTUG86Lrm6LJ0rw73Xp0NAFcU\";\n            sout << \"MKpiG9g1cHW74HYbUb/yAbtVWt40eB7M637umdo2jWz/r/vP5WnfSMXEbkyWebsa1fFceg/TLWy6\";\n            sout << \"E8OTc4XKB48h1oFIlGagOiprxho3+F3TIcxDSwA=\";\n\n\n\n            // Put the data into the istream sin\n            sin.str(sout.str());\n            sout.str(\"\");\n\n            // Decode the base64 text into its compressed binary form\n            base64_coder.decode(sin,sout);\n            sin.clear();\n            sin.str(sout.str());\n            sout.str(\"\");\n\n            // Decompress the data into its original form\n            compressor.decompress(sin,sout);\n\n            // Return the decoded and decompressed data\n            return sout.str();\n        }\n\n\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_IMAGE_DAtASET_METADATA_CPPh_\n\n\n"
  },
  {
    "path": "dlib/data_io/image_dataset_metadata.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_DAtASET_METADATA_Hh_\n#define DLIB_IMAGE_DAtASET_METADATA_Hh_\n\n#include <string>\n#include <vector>\n#include \"../geometry.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    namespace image_dataset_metadata\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        enum gender_t\n        {\n            UNKNOWN,\n            MALE,\n            FEMALE\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        struct box\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents an annotated rectangular area of an image.  \n                    It is typically used to mark the location of an object such as a \n                    person, car, etc.\n\n                    The main variable of interest is rect.  It gives the location of \n                    the box.  All the other variables are optional.\n            !*/\n\n            box(\n            ) : \n                difficult(false),\n                truncated(false),\n                occluded(false),\n                ignore(false),\n                pose(0),\n                detection_score(0),\n                angle(0),\n                gender(UNKNOWN),\n                age(0)\n            {}\n\n            box (\n                const rectangle& rect_\n            ) : \n                rect(rect_), \n                difficult(false),\n                truncated(false),\n                occluded(false),\n                ignore(false),\n                pose(0),\n                detection_score(0),\n                angle(0),\n                gender(UNKNOWN),\n                age(0)\n            {}\n\n            rectangle rect;\n\n            std::map<std::string,point> parts;\n\n            // optional fields\n            std::string label;\n            bool difficult;\n            bool truncated;\n            bool occluded;\n            bool ignore;\n            double pose;\n            double detection_score;\n\n            // The angle of the object in radians.  Positive values indicate that the\n            // object at the center of the box is rotated clockwise by angle radians.  A\n            // value of 0 would indicate that the object is in its \"standard\" upright pose.\n            // Therefore, to make the object appear upright we would have to rotate the\n            // image counter-clockwise by angle radians.\n            double angle; \n\n            gender_t gender;\n            double age;\n\n            bool has_label() const { return label.size() != 0; }\n            /*!\n                ensures\n                    - returns true if label metadata is present and false otherwise.\n            !*/\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        struct image\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents an annotated image.\n            !*/\n\n            image() {}\n            image(const std::string& f) : filename(f) {}\n\n            std::string filename;\n            std::vector<box> boxes;\n            long width = 0;\n            long height = 0;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        struct dataset\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a labeled set of images.  In particular, it\n                    contains the filename for each image as well as annotated boxes.\n            !*/\n\n            std::vector<image> images;\n            std::string comment;\n            std::string name;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        void save_image_dataset_metadata (\n            const dataset& meta,\n            const std::string& filename\n        );\n        /*!\n            ensures\n                - Writes the contents of the meta object to a file with the given\n                  filename.  The file will be in an XML format.\n            throws\n                - dlib::error \n                  This exception is thrown if there is an error which prevents\n                  this function from succeeding.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        void load_image_dataset_metadata (\n            dataset& meta,\n            const std::string& filename\n        );\n        /*!\n            ensures\n                - Attempts to interpret filename as a file containing XML formatted data\n                  as produced by the save_image_dataset_metadata() function.  Then\n                  meta is loaded with the contents of the file.\n            throws\n                - dlib::error \n                  This exception is thrown if there is an error which prevents\n                  this function from succeeding.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef NO_MAKEFILE\n#include \"image_dataset_metadata.cpp\"\n#endif\n\n#endif // DLIB_IMAGE_DAtASET_METADATA_Hh_\n\n"
  },
  {
    "path": "dlib/data_io/libsvm_io.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LIBSVM_iO_Hh_\n#define DLIB_LIBSVM_iO_Hh_\n\n#include \"libsvm_io_abstract.h\"\n\n#include <fstream>\n#include <string>\n#include <utility>\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../string.h\"\n#include \"../svm/sparse_vector.h\"\n#include <vector>\n\nnamespace dlib\n{\n    struct sample_data_io_error : public error\n    {\n        sample_data_io_error(const std::string& message): error(message) {}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename sample_type, typename label_type, typename alloc1, typename alloc2>\n    void load_libsvm_formatted_data (\n        const std::string& file_name,\n        std::vector<sample_type, alloc1>& samples,\n        std::vector<label_type, alloc2>& labels\n    )\n    {\n        typedef typename sample_type::value_type pair_type;\n        typedef typename basic_type<typename pair_type::first_type>::type key_type;\n        typedef typename pair_type::second_type value_type;\n\n        // You must use unsigned integral key types in your sparse vectors\n        COMPILE_TIME_ASSERT(is_unsigned_type<key_type>::value);\n\n        samples.clear();\n        labels.clear();\n\n        std::ifstream fin(file_name.c_str());\n\n        if (!fin)\n            throw sample_data_io_error(\"Unable to open file \" + file_name);\n\n        std::string line;\n        std::istringstream sin;\n        key_type key;\n        value_type value;\n        label_type label;\n        sample_type sample;\n        long line_num = 0;\n        while (fin.peek() != EOF)\n        {\n            ++line_num;\n            std::getline(fin, line);\n\n            std::string::size_type pos = line.find_first_not_of(\" \\t\\r\\n\");\n\n            // ignore empty lines or comment lines\n            if (pos == std::string::npos || line[pos] == '#')\n                continue;\n\n            sin.clear();\n            sin.str(line);\n            sample.clear();\n\n            sin >> label;\n\n            if (!sin)\n                throw sample_data_io_error(\"On line: \" + cast_to_string(line_num) + \", error while reading file \" + file_name );\n\n            // eat whitespace\n            sin >> std::ws;\n\n            while (sin.peek() != EOF && sin.peek() != '#')\n            {\n\n                sin >> key >> std::ws;\n\n                // ignore what should be a : character\n                if (sin.get() != ':')\n                    throw sample_data_io_error(\"On line: \" + cast_to_string(line_num) + \", error while reading file \" + file_name);\n\n                sin >> value;\n\n                if (sin && value != 0)\n                {\n                    sample.insert(sample.end(), std::make_pair(key, value));\n                }\n\n                sin >> std::ws;\n            }\n\n            samples.push_back(sample);\n            labels.push_back(label);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename sample_type, typename alloc>\n    typename enable_if<is_const_type<typename sample_type::value_type::first_type> >::type \n    fix_nonzero_indexing (\n        std::vector<sample_type,alloc>& samples\n    )\n    {\n        typedef typename sample_type::value_type pair_type;\n        typedef typename basic_type<typename pair_type::first_type>::type key_type;\n\n        if (samples.size() == 0)\n            return;\n\n        // figure out the min index value\n        key_type min_idx = samples[0].begin()->first;\n        for (unsigned long i = 0; i < samples.size(); ++i)\n            min_idx = std::min(min_idx, samples[i].begin()->first);\n\n        // Now adjust all the samples so that their min index value is zero.\n        if (min_idx != 0)\n        {\n            sample_type temp;\n            for (unsigned long i = 0; i < samples.size(); ++i)\n            {\n                // copy samples[i] into temp but make sure it has a min index of zero.\n                temp.clear();\n                typename sample_type::iterator j;\n                for (j = samples[i].begin(); j != samples[i].end(); ++j)\n                {\n                    temp.insert(temp.end(), std::make_pair(j->first-min_idx, j->second));\n                }\n\n                // replace the current sample with temp.\n                samples[i].swap(temp);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// If the \"first\" values in the std::pair objects are not const then we can modify them \n// directly and that is what this version of fix_nonzero_indexing() does.\n    template <typename sample_type, typename alloc>\n    typename disable_if<is_const_type<typename sample_type::value_type::first_type> >::type \n    fix_nonzero_indexing (\n        std::vector<sample_type,alloc>& samples\n    )\n    {\n        typedef typename sample_type::value_type pair_type;\n        typedef typename basic_type<typename pair_type::first_type>::type key_type;\n\n        if (samples.size() == 0)\n            return;\n\n        // figure out the min index value\n        key_type min_idx = samples[0].begin()->first;\n        for (unsigned long i = 0; i < samples.size(); ++i)\n            min_idx = std::min(min_idx, samples[i].begin()->first);\n\n        // Now adjust all the samples so that their min index value is zero.\n        if (min_idx != 0)\n        {\n            for (unsigned long i = 0; i < samples.size(); ++i)\n            {\n                typename sample_type::iterator j;\n                for (j = samples[i].begin(); j != samples[i].end(); ++j)\n                {\n                    j->first -= min_idx;\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n// This is an overload for sparse vectors\n    template <typename sample_type, typename label_type, typename alloc1, typename alloc2>\n    typename disable_if<is_matrix<sample_type>,void>::type save_libsvm_formatted_data (\n        const std::string& file_name,\n        const std::vector<sample_type, alloc1>& samples,\n        const std::vector<label_type, alloc2>& labels\n    )\n    {\n        typedef typename sample_type::value_type pair_type;\n        typedef typename basic_type<typename pair_type::first_type>::type key_type;\n\n        // You must use unsigned integral key types in your sparse vectors\n        COMPILE_TIME_ASSERT(is_unsigned_type<key_type>::value);\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(samples.size() == labels.size(),\n            \"\\t void save_libsvm_formatted_data()\"\n            << \"\\n\\t You have to have labels for each sample and vice versa\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t labels.size():  \" << labels.size()\n            );\n\n\n        std::ofstream fout(file_name.c_str());\n        fout.precision(14);\n\n        if (!fout)\n            throw sample_data_io_error(\"Unable to open file \" + file_name);\n\n        for (unsigned long i = 0; i < samples.size(); ++i)\n        {\n            fout << labels[i];\n\n            for (typename sample_type::const_iterator j = samples[i].begin(); j != samples[i].end(); ++j)\n            {\n                if (j->second != 0)\n                    fout << \" \" << j->first << \":\" << j->second;\n            }\n            fout << \"\\n\";\n\n            if (!fout)\n                throw sample_data_io_error(\"Error while writing to file \" + file_name);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// This is an overload for dense vectors\n    template <typename sample_type, typename label_type, typename alloc1, typename alloc2>\n    typename enable_if<is_matrix<sample_type>,void>::type save_libsvm_formatted_data (\n        const std::string& file_name,\n        const std::vector<sample_type, alloc1>& samples,\n        const std::vector<label_type, alloc2>& labels\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(samples.size() == labels.size(),\n            \"\\t void save_libsvm_formatted_data()\"\n            << \"\\n\\t You have to have labels for each sample and vice versa\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t labels.size():  \" << labels.size()\n            );\n\n        std::ofstream fout(file_name.c_str());\n        fout.precision(14);\n\n        if (!fout)\n            throw sample_data_io_error(\"Unable to open file \" + file_name);\n\n        for (unsigned long i = 0; i < samples.size(); ++i)\n        {\n            fout << labels[i];\n\n            for (long j = 0; j < samples[i].size(); ++j)\n            {\n                if (samples[i](j) != 0)\n                    fout << \" \" << j << \":\" << samples[i](j);\n            }\n            fout << \"\\n\";\n\n            if (!fout)\n                throw sample_data_io_error(\"Error while writing to file \" + file_name);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LIBSVM_iO_Hh_\n\n"
  },
  {
    "path": "dlib/data_io/libsvm_io_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LIBSVM_iO_ABSTRACT_Hh_\n#ifdef DLIB_LIBSVM_iO_ABSTRACT_Hh_\n\n#include <fstream>\n#include <string>\n#include <utility>\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include <vector>\n\nnamespace dlib\n{\n    struct sample_data_io_error : public error\n    {\n        /*!\n            This is the exception class used by the file IO functions defined below.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type, \n        typename label_type, \n        typename alloc1, \n        typename alloc2\n        >\n    void load_libsvm_formatted_data (\n        const std::string& file_name,\n        std::vector<sample_type, alloc1>& samples,\n        std::vector<label_type, alloc2>& labels\n    );\n    /*!\n        requires\n            - sample_type must be an STL container\n            - sample_type::value_type == std::pair<T,U> where T is some kind of \n              unsigned integral type\n        ensures\n            - attempts to read a file of the given name that should contain libsvm\n              formatted data.  We turn the data into sparse vectors and store it\n              in samples\n            - #labels.size() == #samples.size()\n            - for all valid i: #labels[i] is the label for #samples[i]\n        throws\n            - sample_data_io_error\n                This exception is thrown if there is any problem loading data from file\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type,\n        typename label_type,\n        typename alloc1,\n        typename alloc2\n        >\n    void save_libsvm_formatted_data (\n        const std::string& file_name,\n        const std::vector<sample_type, alloc1>& samples,\n        const std::vector<label_type, alloc2>& labels\n    );\n    /*!\n        requires\n            - sample_type must be an STL container\n            - sample_type::value_type == std::pair<T,U> where T is some kind of \n              unsigned integral type\n            - samples.size() == labels.size()\n        ensures\n            - saves the data to the given file in libsvm format\n        throws\n            - sample_data_io_error\n                This exception is thrown if there is any problem saving data to file\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sample_type, \n        typename label_type, \n        typename alloc1, \n        typename alloc2\n        >\n    void save_libsvm_formatted_data (\n        const std::string& file_name,\n        const std::vector<sample_type, alloc1>& samples,\n        const std::vector<label_type, alloc2>& labels\n    );\n    /*!\n        requires\n            - sample_type == a dense matrix (i.e. dlib::matrix)\n            - for all valid i: is_vector(samples[i]) == true\n            - samples.size() == labels.size()\n        ensures\n            - saves the data to the given file in libsvm format\n        throws\n            - sample_data_io_error\n                This exception is thrown if there is any problem saving data to file\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename sample_type, typename alloc>\n    void fix_nonzero_indexing (\n        std::vector<sample_type,alloc>& samples\n    );\n    /*!\n        requires\n            - samples must only contain valid sparse vectors.  The definition of\n              a sparse vector can be found at the top of dlib/svm/sparse_vector_abstract.h\n        ensures\n            - Adjusts the sparse vectors in samples so that they are zero-indexed.  \n              Or in other words, assume the smallest used index value in any of the sparse \n              vectors is N.  Then this function subtracts N from all the index values in \n              samples.  This is useful, for example, if you load a libsvm formatted datafile \n              with features indexed from 1 rather than 0 and you would like to fix this.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LIBSVM_iO_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/data_io/load_image_dataset.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOAD_IMAGE_DaTASET_Hh_\n#define DLIB_LOAD_IMAGE_DaTASET_Hh_\n\n#include \"load_image_dataset_abstract.h\"\n#include \"../misc_api.h\"\n#include \"../dir_nav.h\"\n#include \"../image_io.h\"\n#include \"../array.h\"\n#include <vector>\n#include \"../geometry.h\"\n#include \"image_dataset_metadata.h\"\n#include <string>\n#include <set>\n#include \"../image_processing/full_object_detection.h\"\n#include <utility>\n#include <limits>\n#include \"../image_transforms/image_pyramid.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_dataset_file\n    {\n    public:\n        image_dataset_file(const std::string& filename)\n        {\n            _skip_empty_images = false;\n            _have_parts = false;\n            _filename = filename;\n            _box_area_thresh = std::numeric_limits<double>::infinity();\n        }\n\n        image_dataset_file boxes_match_label(\n            const std::string& label\n        ) const\n        {\n            image_dataset_file temp(*this);\n            temp._labels.insert(label);\n            return temp;\n        }\n\n        image_dataset_file skip_empty_images(\n        ) const\n        {\n            image_dataset_file temp(*this);\n            temp._skip_empty_images = true;\n            return temp;\n        }\n\n        image_dataset_file boxes_have_parts(\n        ) const\n        {\n            image_dataset_file temp(*this);\n            temp._have_parts = true;\n            return temp;\n        }\n\n        image_dataset_file shrink_big_images(\n            double new_box_area_thresh = 150*150\n        ) const\n        {\n            image_dataset_file temp(*this);\n            temp._box_area_thresh = new_box_area_thresh;\n            return temp;\n        }\n\n        bool should_load_box (\n            const image_dataset_metadata::box& box\n        ) const\n        {\n            if (_have_parts && box.parts.size() == 0)\n                return false;\n            if (_labels.size() == 0)\n                return true;\n            if (_labels.count(box.label) != 0)\n                return true;\n            return false;\n        }\n\n        const std::string& get_filename() const { return _filename; }\n        bool should_skip_empty_images() const { return _skip_empty_images; }\n        bool should_boxes_have_parts() const { return _have_parts; }\n        double box_area_thresh() const { return _box_area_thresh; }\n        const std::set<std::string>& get_selected_box_labels() const { return _labels; }\n\n    private:\n        std::string _filename;\n        std::set<std::string> _labels;\n        bool _skip_empty_images;\n        bool _have_parts;\n        double _box_area_thresh;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations,\n        const image_dataset_file& source\n    )\n    {\n        images.clear();\n        object_locations.clear();\n\n        std::vector<std::vector<rectangle> > ignored_rects;\n\n        using namespace dlib::image_dataset_metadata;\n        dataset data;\n        load_image_dataset_metadata(data, source.get_filename());\n\n        // Set the current directory to be the one that contains the\n        // metadata file. We do this because the file might contain\n        // file paths which are relative to this folder.\n        locally_change_current_dir chdir(get_parent_directory(file(source.get_filename())));\n\n\n        typedef typename array_type::value_type image_type;\n\n\n        image_type img;\n        std::vector<rectangle> rects, ignored;\n        for (unsigned long i = 0; i < data.images.size(); ++i)\n        {\n            double min_rect_size = std::numeric_limits<double>::infinity();\n            rects.clear();\n            ignored.clear();\n            for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)\n            {\n                if (source.should_load_box(data.images[i].boxes[j]))\n                {\n                    if (data.images[i].boxes[j].ignore)\n                    {\n                        ignored.push_back(data.images[i].boxes[j].rect);\n                    }\n                    else\n                    {\n                        rects.push_back(data.images[i].boxes[j].rect);\n                        min_rect_size = std::min<double>(min_rect_size, rects.back().area());\n                    }\n                }\n            }\n\n            if (!source.should_skip_empty_images() || rects.size() != 0)\n            {\n                load_image(img, data.images[i].filename);\n                if (rects.size() != 0)  \n                {\n                    // if shrinking the image would still result in the smallest box being\n                    // bigger than the box area threshold then shrink the image.\n                    while(min_rect_size/2/2 > source.box_area_thresh())\n                    {\n                        pyramid_down<2> pyr;\n                        pyr(img);\n                        min_rect_size *= (1.0/2.0)*(1.0/2.0);\n                        for (auto&& r : rects)\n                            r = pyr.rect_down(r);\n                        for (auto&& r : ignored)\n                            r = pyr.rect_down(r);\n                    }\n                    while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())\n                    {\n                        pyramid_down<3> pyr;\n                        pyr(img);\n                        min_rect_size *= (2.0/3.0)*(2.0/3.0);\n                        for (auto&& r : rects)\n                            r = pyr.rect_down(r);\n                        for (auto&& r : ignored)\n                            r = pyr.rect_down(r);\n                    }\n                }\n                images.push_back(img);\n                object_locations.push_back(rects);\n                ignored_rects.push_back(ignored);\n            }\n        }\n\n        return ignored_rects;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline size_t num_non_ignored_boxes (const std::vector<mmod_rect>& rects)\n        {\n            size_t cnt = 0;\n            for (auto& b : rects)\n            {\n                if (!b.ignore)\n                    cnt++;\n            }\n            return cnt;\n        }\n    }\n\n    template <\n        typename array_type\n        >\n    void load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<mmod_rect> >& object_locations,\n        const image_dataset_file& source\n    )\n    {\n        images.clear();\n        object_locations.clear();\n\n        using namespace dlib::image_dataset_metadata;\n        dataset data;\n        load_image_dataset_metadata(data, source.get_filename());\n\n        // Set the current directory to be the one that contains the\n        // metadata file. We do this because the file might contain\n        // file paths which are relative to this folder.\n        locally_change_current_dir chdir(get_parent_directory(file(source.get_filename())));\n\n        typedef typename array_type::value_type image_type;\n\n        image_type img;\n        std::vector<mmod_rect> rects;\n        for (unsigned long i = 0; i < data.images.size(); ++i)\n        {\n            double min_rect_size = std::numeric_limits<double>::infinity();\n            rects.clear();\n            for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)\n            {\n                if (source.should_load_box(data.images[i].boxes[j]))\n                {\n                    if (data.images[i].boxes[j].ignore)\n                    {\n                        rects.push_back(ignored_mmod_rect(data.images[i].boxes[j].rect));\n                    }\n                    else\n                    {\n                        rects.push_back(mmod_rect(data.images[i].boxes[j].rect));\n                        min_rect_size = std::min<double>(min_rect_size, rects.back().rect.area());\n                    }\n                    rects.back().label = data.images[i].boxes[j].label;\n\n                }\n            }\n\n            if (!source.should_skip_empty_images() || impl::num_non_ignored_boxes(rects) != 0)\n            {\n                load_image(img, data.images[i].filename);\n                if (rects.size() != 0)  \n                {\n                    // if shrinking the image would still result in the smallest box being\n                    // bigger than the box area threshold then shrink the image.\n                    while(min_rect_size/2/2 > source.box_area_thresh())\n                    {\n                        pyramid_down<2> pyr;\n                        pyr(img);\n                        min_rect_size *= (1.0/2.0)*(1.0/2.0);\n                        for (auto&& r : rects)\n                            r.rect = pyr.rect_down(r.rect);\n                    }\n                    while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())\n                    {\n                        pyramid_down<3> pyr;\n                        pyr(img);\n                        min_rect_size *= (2.0/3.0)*(2.0/3.0);\n                        for (auto&& r : rects)\n                            r.rect = pyr.rect_down(r.rect);\n                    }\n                }\n                images.push_back(std::move(img));\n                object_locations.push_back(std::move(rects));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// ******* THIS FUNCTION IS DEPRECATED, you should use another version of load_image_dataset() *******\n    template <\n        typename image_type, \n        typename MM\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array<image_type,MM>& images,\n        std::vector<std::vector<rectangle> >& object_locations,\n        const std::string& filename,\n        const std::string& label,\n        bool skip_empty_images = false\n    )\n    {\n        image_dataset_file f(filename);\n        if (label.size() != 0)\n            f = f.boxes_match_label(label);\n        if (skip_empty_images)\n            f = f.skip_empty_images();\n        return load_image_dataset(images, object_locations, f);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations,\n        const std::string& filename\n    )\n    {\n        return load_image_dataset(images, object_locations, image_dataset_file(filename));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    void load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<mmod_rect>>& object_locations,\n        const std::string& filename\n    )\n    {\n        load_image_dataset(images, object_locations, image_dataset_file(filename));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const image_dataset_file& source,\n        std::vector<std::string>& parts_list\n    )\n    {\n        typedef typename array_type::value_type image_type;\n        parts_list.clear();\n        images.clear();\n        object_locations.clear();\n\n        using namespace dlib::image_dataset_metadata;\n        dataset data;\n        load_image_dataset_metadata(data, source.get_filename());\n\n        // Set the current directory to be the one that contains the\n        // metadata file. We do this because the file might contain\n        // file paths which are relative to this folder.\n        locally_change_current_dir chdir(get_parent_directory(file(source.get_filename())));\n\n\n        std::set<std::string> all_parts;\n\n        // find out what parts are being used in the dataset.  Store results in all_parts.\n        for (unsigned long i = 0; i < data.images.size(); ++i)\n        {\n            for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)\n            {\n                if (source.should_load_box(data.images[i].boxes[j]))\n                {\n                    const std::map<std::string,point>& parts = data.images[i].boxes[j].parts;\n                    std::map<std::string,point>::const_iterator itr;\n\n                    for (itr = parts.begin(); itr != parts.end(); ++itr)\n                    {\n                        all_parts.insert(itr->first);\n                    }\n                }\n            }\n        }\n\n        // make a mapping between part names and the integers [0, all_parts.size())\n        std::map<std::string,int> parts_idx;\n        for (std::set<std::string>::iterator i = all_parts.begin(); i != all_parts.end(); ++i)\n        {\n            parts_idx[*i] = parts_list.size();\n            parts_list.push_back(*i);\n        }\n\n        std::vector<std::vector<rectangle> > ignored_rects;\n        std::vector<rectangle> ignored;\n        image_type img;\n        std::vector<full_object_detection> object_dets;\n        for (unsigned long i = 0; i < data.images.size(); ++i)\n        {\n            double min_rect_size = std::numeric_limits<double>::infinity();\n            object_dets.clear();\n            ignored.clear();\n            for (unsigned long j = 0; j < data.images[i].boxes.size(); ++j)\n            {\n                if (source.should_load_box(data.images[i].boxes[j]))\n                {\n                    if (data.images[i].boxes[j].ignore)\n                    {\n                        ignored.push_back(data.images[i].boxes[j].rect);\n                    }\n                    else\n                    {\n                        std::vector<dpoint> partlist(parts_idx.size(), OBJECT_PART_NOT_PRESENT);\n\n                        // populate partlist with all the parts present in this box.\n                        const std::map<std::string,point>& parts = data.images[i].boxes[j].parts;\n                        std::map<std::string,point>::const_iterator itr;\n                        for (itr = parts.begin(); itr != parts.end(); ++itr)\n                        {\n                            partlist[parts_idx[itr->first]] = itr->second;\n                        }\n\n                        object_dets.push_back(full_object_detection(data.images[i].boxes[j].rect, partlist));\n                        min_rect_size = std::min<double>(min_rect_size, object_dets.back().get_rect().area());\n                    }\n                }\n            }\n\n            if (!source.should_skip_empty_images() || object_dets.size() != 0)\n            {\n                load_image(img, data.images[i].filename);\n                if (object_dets.size() != 0)  \n                {\n                    // if shrinking the image would still result in the smallest box being\n                    // bigger than the box area threshold then shrink the image.\n                    while(min_rect_size/2/2 > source.box_area_thresh())\n                    {\n                        pyramid_down<2> pyr;\n                        pyr(img);\n                        min_rect_size *= (1.0/2.0)*(1.0/2.0);\n                        for (auto&& r : object_dets)\n                        {\n                            r.get_rect() = pyr.rect_down(r.get_rect());\n                            for (unsigned long k = 0; k < r.num_parts(); ++k)\n                                r.part(k) = pyr.point_down(r.part(k));\n                        }\n                        for (auto&& r : ignored)\n                        {\n                            r = pyr.rect_down(r);\n                        }\n                    }\n                    while(min_rect_size*(2.0/3.0)*(2.0/3.0) > source.box_area_thresh())\n                    {\n                        pyramid_down<3> pyr;\n                        pyr(img);\n                        min_rect_size *= (2.0/3.0)*(2.0/3.0);\n                        for (auto&& r : object_dets)\n                        {\n                            r.get_rect() = pyr.rect_down(r.get_rect());\n                            for (unsigned long k = 0; k < r.num_parts(); ++k)\n                                r.part(k) = pyr.point_down(r.part(k));\n                        }\n                        for (auto&& r : ignored)\n                        {\n                            r = pyr.rect_down(r);\n                        }\n                    }\n                }\n                images.push_back(img);\n                object_locations.push_back(object_dets);\n                ignored_rects.push_back(ignored);\n            }\n        }\n\n\n        return ignored_rects;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const image_dataset_file& source \n    )\n    {\n        std::vector<std::string> parts_list;\n        return load_image_dataset(images, object_locations, source, parts_list);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const std::string& filename\n    )\n    {\n        std::vector<std::string> parts_list;\n        return load_image_dataset(images, object_locations, image_dataset_file(filename), parts_list);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LOAD_IMAGE_DaTASET_Hh_\n\n"
  },
  {
    "path": "dlib/data_io/load_image_dataset_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_\n#ifdef DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_\n\n#include \"image_dataset_metadata.h\"\n#include \"../array/array_kernel_abstract.h\"\n#include <string>\n#include <vector>\n#include \"../image_processing/full_object_detection_abstract.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_dataset_file\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool used to tell the load_image_dataset() functions which\n                boxes and images to load from an XML based image dataset file.  By default,\n                this object tells load_image_dataset() to load all images and object boxes.\n        !*/\n\n    public:\n        image_dataset_file(\n            const std::string& filename\n        );\n        /*!\n            ensures\n                - #get_filename() == filename\n                - #should_skip_empty_images() == false\n                - #get_selected_box_labels().size() == 0\n                  This means that, initially, all boxes will be loaded.  Therefore, for all\n                  possible boxes B we have:\n                    - #should_load_box(B) == true\n                - #box_area_thresh() == infinity\n        !*/\n\n        const std::string& get_filename(\n        ) const;\n        /*!\n            ensures\n                - returns the name of the XML image dataset metadata file given to this\n                  object's constructor.\n        !*/\n        \n        bool should_skip_empty_images(\n        ) const;\n        /*!\n            ensures\n                - returns true if we are supposed to skip images that don't have any\n                  non-ignored boxes to load when loading an image dataset using\n                  load_image_dataset().\n        !*/\n\n        image_dataset_file boxes_match_label(\n            const std::string& label\n        ) const;\n        /*!\n            ensures\n                - returns a copy of *this that is identical in all respects to *this except\n                  that label will be included in the labels set (i.e. the set returned by\n                  get_selected_box_labels()).\n        !*/\n\n        const std::set<std::string>& get_selected_box_labels(\n        ) const;\n        /*!\n            ensures\n                - returns the set of box labels currently selected by the should_load_box()\n                  method.  Note that if the set is empty then we select all boxes.\n        !*/\n\n        image_dataset_file skip_empty_images(\n        ) const;\n        /*!\n            ensures\n                - returns a copy of *this that is identical in all respects to *this except\n                  that #should_skip_empty_images() == true.\n        !*/\n\n        bool should_boxes_have_parts(\n        ) const; \n        /*!\n            ensures\n                - returns true if boxes must have some parts defined for them to be loaded.\n        !*/\n\n        image_dataset_file boxes_have_parts(\n        ) const;\n        /*!\n            ensures\n                - returns a copy of *this that is identical in all respects to *this except\n                  that #should_boxes_have_parts() == true.\n        !*/\n\n        bool should_load_box (\n            const image_dataset_metadata::box& box\n        ) const;\n        /*!\n            ensures\n                - returns true if we are supposed to load the given box from an image\n                  dataset XML file.  In particular, if should_load_box() returns false then\n                  the load_image_dataset() routines will not return the box at all, neither\n                  in the ignore rectangles list or in the primary object_locations vector.\n                  The behavior of this function is defined as follows:\n                    - if (should_boxes_have_parts() && boxes.parts.size() == 0) then\n                        - returns false\n                    - else if (get_selected_box_labels().size() == 0) then\n                        - returns true\n                    - else if (get_selected_box_labels().count(box.label) != 0) then\n                        - returns true\n                    - else\n                        - returns false\n        !*/\n\n        image_dataset_file shrink_big_images(\n            double new_box_area_thresh = 150*150\n        ) const;\n        /*!\n            ensures\n                - returns a copy of *this that is identical in all respects to *this except\n                  that #box_area_thresh() == new_box_area_thresh\n        !*/\n\n        double box_area_thresh(\n        ) const;\n        /*!\n            ensures\n                - If the smallest non-ignored rectangle in an image has an area greater\n                  than box_area_thresh() then we will shrink the image until the area of\n                  the box is about equal to box_area_thresh().  This is useful if you have\n                  a dataset containing very high resolution images and you don't want to\n                  load it in its native high resolution.  Setting the box_area_thresh()\n                  allows you to control the resolution of the loaded images.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations,\n        const image_dataset_file& source\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - This routine loads the images and their associated object boxes from the\n              image metadata file indicated by source.get_filename().  This metadata file\n              should be in the XML format used by the save_image_dataset_metadata() routine.\n            - #images.size() == The number of images loaded from the metadata file.  This\n              is all the images listed in the file unless source.should_skip_empty_images()\n              is set to true.\n            - #images.size() == #object_locations.size()\n            - This routine is capable of loading any image format which can be read by the\n              load_image() routine.\n            - let IGNORED_RECTS denote the vector returned from this function.\n            - IGNORED_RECTS.size() == #object_locations.size()\n            - IGNORED_RECTS == a list of the rectangles which have the \"ignore\" flag set to\n              true in the input XML file.\n            - for all valid i:  \n                - #images[i] == a copy of the i-th image from the dataset.\n                - #object_locations[i] == a vector of all the rectangles associated with\n                  #images[i].  These are the rectangles for which source.should_load_box()\n                  returns true and are also not marked as \"ignore\" in the XML file.\n                - IGNORED_RECTS[i] == A vector of all the rectangles associated with #images[i] \n                  that are marked as \"ignore\" but not discarded by source.should_load_box().\n                - if (source.should_skip_empty_images() == true) then\n                    - #object_locations[i].size() != 0\n                      (i.e. we won't load images that don't end up having any object locations)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations,\n        const std::string& filename\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename));\n              (i.e. it ignores box labels and therefore loads all the boxes in the dataset)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    void load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<mmod_rect> >& object_locations,\n        const image_dataset_file& source\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - This function has essentially the same behavior as the above\n              load_image_dataset() routines, except here we output to a vector of\n              mmod_rects instead of rectangles.  In this case, both ignore and non-ignore\n              rectangles go into object_locations since mmod_rect has an ignore boolean\n              field that records the ignored/non-ignored state of each rectangle.  We also store \n              a each box's string label into the mmod_rect::label field as well.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    void load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<mmod_rect> >& object_locations,\n        const std::string& filename\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - performs: load_image_dataset(images, object_locations, image_dataset_file(filename));\n              (i.e. it ignores box labels and therefore loads all the boxes in the dataset)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const image_dataset_file& source,\n        std::vector<std::string>& parts_list\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - This routine loads the images and their associated object locations from the\n              image metadata file indicated by source.get_filename().  This metadata file\n              should be in the XML format used by the save_image_dataset_metadata() routine.\n            - The difference between this function and the version of load_image_dataset()\n              defined above is that this version will also load object part information and\n              thus fully populates the full_object_detection objects.\n            - #images.size() == The number of images loaded from the metadata file.  This\n              is all the images listed in the file unless source.should_skip_empty_images()\n              is set to true.\n            - #images.size() == #object_locations.size()\n            - This routine is capable of loading any image format which can be read\n              by the load_image() routine.\n            - #parts_list == a vector that contains the list of object parts found in the\n              input file and loaded into object_locations.\n            - #parts_list is in lexicographic sorted order.\n            - let IGNORED_RECTS denote the vector returned from this function.\n            - IGNORED_RECTS.size() == #object_locations.size()\n            - IGNORED_RECTS == a list of the rectangles which have the \"ignore\" flag set to\n              true in the input XML file.\n            - for all valid i:  \n                - #images[i] == a copy of the i-th image from the dataset.\n                - #object_locations[i] == a vector of all the rectangles associated with\n                  #images[i].  These are the rectangles for which source.should_load_box()\n                  returns true and are also not marked as \"ignore\" in the XML file.\n                - IGNORED_RECTS[i] == A vector of all the rectangles associated with #images[i] \n                  that are marked as \"ignore\" but not discarded by source.should_load_box().\n                - if (source.should_skip_empty_images() == true) then\n                    - #object_locations[i].size() != 0\n                      (i.e. we won't load images that don't end up having any object locations)\n                - for all valid j:\n                    - #object_locations[i][j].num_parts() == #parts_list.size()\n                    - for all valid k:\n                        - #object_locations[i][j].part(k) == the location of the part\n                          with name #parts_list[k] or OBJECT_PART_NOT_PRESENT if the\n                          part was not indicated for object #object_locations[i][j].\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const image_dataset_file& source \n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - performs: return load_image_dataset(images, object_locations, source, parts_list);\n              (i.e. this function simply calls the above function and discards the output\n              parts_list.  So it is just a convenience function you can call if you don't\n              care about getting the parts list.)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type \n        >\n    std::vector<std::vector<rectangle> > load_image_dataset (\n        array_type& images,\n        std::vector<std::vector<full_object_detection> >& object_locations,\n        const std::string& filename\n    );\n    /*!\n        requires\n            - array_type == An array of images.  This is anything with an interface that\n              looks like std::vector<some generic image type> where a \"generic image\" is\n              anything that implements the generic image interface defined in\n              dlib/image_processing/generic_image.h.\n        ensures\n            - performs: return load_image_dataset(images, object_locations, image_dataset_file(filename));\n              (i.e. it ignores box labels and therefore loads all the boxes in the dataset)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LOAD_IMAGE_DaTASET_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/data_io/mnist.cpp",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MNIST_CPp_\n#define DLIB_MNIST_CPp_\n\n#include \"mnist.h\"\n#include <fstream>\n#include \"../byte_orderer.h\"\n#include \"../uintn.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void load_mnist_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<unsigned char> >& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<unsigned char> >& testing_images,\n        std::vector<unsigned long>& testing_labels\n    )\n    {\n        using namespace std;\n        ifstream fin1((folder_name+\"/train-images-idx3-ubyte\").c_str(), ios::binary);\n        if (!fin1)\n        {\n            fin1.open((folder_name + \"/train-images.idx3-ubyte\").c_str(), ios::binary);\n        }\n\n        ifstream fin2((folder_name+\"/train-labels-idx1-ubyte\").c_str(), ios::binary);\n        if (!fin2)\n        {\n            fin2.open((folder_name + \"/train-labels.idx1-ubyte\").c_str(), ios::binary);\n        }\n\n        ifstream fin3((folder_name+\"/t10k-images-idx3-ubyte\").c_str(), ios::binary);\n        if (!fin3)\n        {\n            fin3.open((folder_name + \"/t10k-images.idx3-ubyte\").c_str(), ios::binary);\n        }\n\n        ifstream fin4((folder_name+\"/t10k-labels-idx1-ubyte\").c_str(), ios::binary);\n        if (!fin4)\n        {\n            fin4.open((folder_name + \"/t10k-labels.idx1-ubyte\").c_str(), ios::binary);\n        }\n\n        if (!fin1) throw error(\"Unable to open file train-images-idx3-ubyte or train-images.idx3-ubyte\");\n        if (!fin2) throw error(\"Unable to open file train-labels-idx1-ubyte or train-labels.idx1-ubyte\");\n        if (!fin3) throw error(\"Unable to open file t10k-images-idx3-ubyte or t10k-images.idx3-ubyte\");\n        if (!fin4) throw error(\"Unable to open file t10k-labels-idx1-ubyte or t10k-labels.idx1-ubyte\");\n\t\t\n        byte_orderer bo;\n\n        // make sure the files have the contents we expect.\n        uint32 magic, num, nr, nc, num2, num3, num4;\n        fin1.read((char*)&magic, sizeof(magic));  bo.big_to_host(magic);\n        fin1.read((char*)&num, sizeof(num));  bo.big_to_host(num);\n        fin1.read((char*)&nr, sizeof(nr));  bo.big_to_host(nr);\n        fin1.read((char*)&nc, sizeof(nc));  bo.big_to_host(nc);\n        if (magic != 2051 || num != 60000 || nr != 28 || nc != 28)\n            throw error(\"mnist dat files are corrupted.\");\n\n        fin2.read((char*)&magic, sizeof(magic));  bo.big_to_host(magic);\n        fin2.read((char*)&num2, sizeof(num2));  bo.big_to_host(num2);\n        if (magic != 2049 || num2 != 60000)\n            throw error(\"mnist dat files are corrupted.\");\n\n        fin3.read((char*)&magic, sizeof(magic));  bo.big_to_host(magic);\n        fin3.read((char*)&num3, sizeof(num3));  bo.big_to_host(num3);\n        fin3.read((char*)&nr, sizeof(nr));  bo.big_to_host(nr);\n        fin3.read((char*)&nc, sizeof(nc));  bo.big_to_host(nc);\n        if (magic != 2051 || num3 != 10000 || nr != 28 || nc != 28)\n            throw error(\"mnist dat files are corrupted.\");\n\n        fin4.read((char*)&magic, sizeof(magic));  bo.big_to_host(magic);\n        fin4.read((char*)&num4, sizeof(num4));  bo.big_to_host(num4);\n        if (magic != 2049 || num4 != 10000)\n            throw error(\"mnist dat files are corrupted.\");\n\n        if (!fin1) throw error(\"Unable to read train-images-idx3-ubyte\");\n        if (!fin2) throw error(\"Unable to read train-labels-idx1-ubyte\");\n        if (!fin3) throw error(\"Unable to read t10k-images-idx3-ubyte\");\n        if (!fin4) throw error(\"Unable to read t10k-labels-idx1-ubyte\");\n\n\n        training_images.resize(60000);\n        training_labels.resize(60000);\n        testing_images.resize(10000);\n        testing_labels.resize(10000);\n\n        for (size_t i = 0; i < training_images.size(); ++i)\n        {\n            training_images[i].set_size(nr,nc);\n            fin1.read((char*)&training_images[i](0,0), nr*nc);\n        }\n        for (size_t i = 0; i < training_labels.size(); ++i)\n        {\n            char l;\n            fin2.read(&l, 1);\n            training_labels[i] = l;\n        }\n\n        for (size_t i = 0; i < testing_images.size(); ++i)\n        {\n            testing_images[i].set_size(nr,nc);\n            fin3.read((char*)&testing_images[i](0,0), nr*nc);\n        }\n        for (size_t i = 0; i < testing_labels.size(); ++i)\n        {\n            char l;\n            fin4.read(&l, 1);\n            testing_labels[i] = l;\n        }\n\n        if (!fin1) throw error(\"Unable to read train-images-idx3-ubyte\");\n        if (!fin2) throw error(\"Unable to read train-labels-idx1-ubyte\");\n        if (!fin3) throw error(\"Unable to read t10k-images-idx3-ubyte\");\n        if (!fin4) throw error(\"Unable to read t10k-labels-idx1-ubyte\");\n\n        if (fin1.get() != EOF) throw error(\"Unexpected bytes at end of train-images-idx3-ubyte\");\n        if (fin2.get() != EOF) throw error(\"Unexpected bytes at end of train-labels-idx1-ubyte\");\n        if (fin3.get() != EOF) throw error(\"Unexpected bytes at end of t10k-images-idx3-ubyte\");\n        if (fin4.get() != EOF) throw error(\"Unexpected bytes at end of t10k-labels-idx1-ubyte\");\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_MNIST_CPp_\n\n\n\n"
  },
  {
    "path": "dlib/data_io/mnist.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MNIST_Hh_\n#define DLIB_MNIST_Hh_\n\n#include \"mnist_abstract.h\"\n#include <string>\n#include <vector>\n#include \"../matrix.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void load_mnist_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<unsigned char> >& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<unsigned char> >& testing_images,\n        std::vector<unsigned long>& testing_labels\n    );\n}\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef NO_MAKEFILE\n#include \"mnist.cpp\"\n#endif\n\n#endif // DLIB_MNIST_Hh_\n\n\n"
  },
  {
    "path": "dlib/data_io/mnist_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MNIST_ABSTRACT_Hh_\n#ifdef DLIB_MNIST_ABSTRACT_Hh_\n\n#include <string>\n#include <vector>\n#include \"../matrix.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void load_mnist_dataset (\n        const std::string& folder_name,\n        std::vector<matrix<unsigned char> >& training_images,\n        std::vector<unsigned long>& training_labels,\n        std::vector<matrix<unsigned char> >& testing_images,\n        std::vector<unsigned long>& testing_labels\n    );\n    /*!\n        ensures\n            - Attempts to load the MNIST dataset from the hard drive.  This is the dataset\n              of handwritten digits available from http://yann.lecun.com/exdb/mnist/. In\n              particular, the 4 files comprising the MNIST dataset should be present in the\n              folder indicated by folder_name.  These four files are:\n                - train-images-idx3-ubyte\n                - train-labels-idx1-ubyte\n                - t10k-images-idx3-ubyte\n                - t10k-labels-idx1-ubyte\n            - #training_images == The 60,000 training images from the dataset. \n            - #training_labels == The labels for the contents of #training_images.  \n              I.e. #training_labels[i] is the label of #training_images[i].\n            - #testing_images == The 10,000 testing images from the dataset. \n            - #testing_labels == The labels for the contents of #testing_images.  \n              I.e. #testing_labels[i] is the label of #testing_images[i].\n        throws\n            - dlib::error if some problem prevents us from loading the data or the files\n              can't be found.\n    !*/\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_MNIST_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/data_io.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DATA_Io_HEADER\n#define DLIB_DATA_Io_HEADER\n\n#include \"data_io/libsvm_io.h\"\n#include \"data_io/image_dataset_metadata.h\"\n#include \"data_io/mnist.h\"\n#include \"data_io/cifar.h\"\n#include \"data_io/arc_agi.h\"\n\n#ifndef DLIB_ISO_CPP_ONLY\n#include \"data_io/load_image_dataset.h\"\n#endif\n\n#endif // DLIB_DATA_Io_HEADER\n\n\n\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_extensions.cpp",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_EXTENSIONs_CPP_\n#define DLIB_DIR_NAV_EXTENSIONs_CPP_\n\n#include \"dir_nav_extensions.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace implementation_details\n    {\n        void get_all_sub_dirs (\n            const directory& top_of_tree,\n            unsigned long max_depth,\n            std::vector<directory>& result,\n            std::vector<directory>& temp\n        )\n        {\n            if (max_depth > 0)\n            {\n                top_of_tree.get_dirs(temp);\n                const unsigned long start = result.size();\n                result.insert(result.end(), temp.begin(), temp.end());\n                const unsigned long end = start + temp.size();\n\n                for (unsigned long i = start; i < end; ++i)\n                {\n                    get_all_sub_dirs(result[i], max_depth-1, result, temp);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool file_exists (\n        const std::string& filename\n    )\n    {\n        try\n        {\n            dlib::file temp(filename);\n            return true;\n        }\n        catch (file::file_not_found&)\n        {\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory_exists (\n        const std::string& dirname\n    )\n    {\n        try\n        {\n            dlib::directory temp(dirname);\n            return true;\n        }\n        catch (directory::dir_not_found&)\n        {\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const directory& dir\n    )\n    {\n        return dir.get_parent();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const file& f\n    )\n    {\n        if (f.full_name().size() == 0)\n            return directory();\n\n        std::string::size_type pos = f.full_name().find_last_of(\"\\\\/\");\n\n        if (pos == std::string::npos)\n            return directory();\n\n        return directory(f.full_name().substr(0,pos));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_oldest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    )\n    {\n        file f1, f2;\n        try{f1 = file(filename1);} catch(file::file_not_found&) { return filename1; }\n        try{f2 = file(filename2);} catch(file::file_not_found&) { return filename2; }\n\n        if (f1.last_modified() < f2.last_modified())\n            return filename1;\n        else\n            return filename2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_newest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    )\n    {\n        file f1, f2;\n        try{f1 = file(filename1);} catch(file::file_not_found&) { return filename2; }\n        try{f2 = file(filename2);} catch(file::file_not_found&) { return filename1; }\n\n        if (f1.last_modified() > f2.last_modified())\n            return filename1;\n        else\n            return filename2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DIR_NAV_EXTENSIONs_CPP_\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_extensions.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_EXTENSIONs_H_\n#define DLIB_DIR_NAV_EXTENSIONs_H_\n\n#include <string>\n#include <vector>\n#include <algorithm>\n#include \"dir_nav_extensions_abstract.h\"\n#include \"../dir_nav.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    bool file_exists (\n        const std::string& filename\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory_exists (\n        const std::string& dirname\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    namespace implementation_details\n    {\n        void get_all_sub_dirs (\n            const directory& top_of_tree,\n            unsigned long max_depth,\n            std::vector<directory>& result,\n            std::vector<directory>& temp\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const std::vector<file> get_files_in_directory_tree (\n        const directory& top_of_tree,\n        const T& add_file,\n        unsigned long max_depth = 30\n    )\n    {\n        std::vector<file> result, temp;\n        std::vector<directory> dirs, dirs_temp;\n        dirs.push_back(top_of_tree);\n\n        // get all the directories in the tree first\n        implementation_details::get_all_sub_dirs(top_of_tree, max_depth, dirs, dirs_temp);\n\n        // now just loop over all the directories and pick out the files we want to keep\n        for (unsigned long d = 0; d < dirs.size(); ++d)\n        {\n            dirs[d].get_files(temp);\n\n            // pick out the members of temp that we should keep\n            for (unsigned long i = 0; i < temp.size(); ++i)\n            {\n                if (add_file(temp[i]))\n                    result.push_back(temp[i]);\n            }\n        }\n\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class match_ending\n    {\n\n    public:\n        match_ending ( \n            const std::string& ending_\n        ) : ending(ending_) {}\n\n        bool operator() (\n            const file& f\n        ) const\n        {\n            // if the ending is bigger than f's name then it obviously doesn't match\n            if (ending.size() > f.name().size())\n                return false;\n\n            // now check if the actual characters that make up the end of the file name \n            // matches what is in ending.\n            return std::equal(ending.begin(), ending.end(), f.name().end()-ending.size());\n        }\n\n    private:\n        std::string ending;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class match_endings\n    {\n\n    public:\n        match_endings ( \n            const std::string& endings_\n        ) \n        {\n            const std::vector<std::string>& s = split(endings_);\n            for (unsigned long i = 0; i < s.size(); ++i)\n            {\n                endings.push_back(match_ending(s[i]));\n            }\n        }\n\n        bool operator() (\n            const file& f\n        ) const\n        {\n            for (unsigned long i = 0; i < endings.size(); ++i)\n            {\n                if (endings[i](f))\n                    return true;\n            }\n\n            return false;\n        }\n\n    private:\n        std::vector<match_ending> endings;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class match_all\n    {\n    public:\n        bool operator() (\n            const file& \n        ) const { return true; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const directory& dir\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const file& f\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_oldest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_newest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"dir_nav_extensions.cpp\"\n#endif\n\n#endif // DLIB_DIR_NAV_EXTENSIONs_H_\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_extensions_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_\n#ifdef DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_\n\n#include <string>\n#include <vector>\n#include \"dir_nav_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    bool file_exists (\n        const std::string& filename\n    );\n    /*!\n        ensures\n            - if (a file with the given filename exists) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory_exists (\n        const std::string& dirname\n    );\n    /*!\n        ensures\n            - if (a directory with the given dirname exists) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const std::vector<file> get_files_in_directory_tree (\n        const directory& top_of_tree,\n        const T& add_file,\n        unsigned long max_depth = 30\n    );\n    /*!\n        requires\n            - add_file must be a function object with the following prototype:\n                bool add_file (file f);\n        ensures\n            - performs a recursive search through the directory top_of_tree and all\n              its sub-directories (up to the given max depth).  All files in these\n              directories are examined by passing them to add_file() and if it \n              returns true then they will be included in the returned std::vector<file>\n              object.\n            - Note that a max_depth of 0 means that only the files in the directory\n              top_of_tree will be considered.  A depth of 1 means that only files in \n              top_of_tree and its immediate sub-directories will be considered.  And\n              so on...\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class match_ending\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that can be used with the\n                above get_files_in_directory_tree() function.  This object\n                just looks for files with a certain ending.\n        !*/\n\n    public:\n        match_ending ( \n            const std::string& ending\n        );\n        /*!\n            ensures\n                - this object will be a function that checks if a file has a \n                  name that ends with the given ending string.\n        !*/\n\n        bool operator() (\n            const file& f\n        ) const;\n        /*!\n            ensures\n                - if (the file f has a name that ends with the ending string given\n                  to this object's constructor) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class match_endings\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that can be used with the\n                above get_files_in_directory_tree() function.  This object\n                allows you to look for files with a number of different \n                endings.\n        !*/\n\n    public:\n        match_endings ( \n            const std::string& ending_list\n        );\n        /*!\n            ensures\n                - ending_list is interpreted as a whitespace separated list\n                  of file endings. \n                - this object will be a function that checks if a file has a \n                  name that ends with one of the strings in ending_list.\n        !*/\n\n        bool operator() (\n            const file& f\n        ) const;\n        /*!\n            ensures\n                - if (the file f has a name that ends with one of the ending strings \n                  given to this object's constructor) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class match_all\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that can be used with the\n                above get_files_in_directory_tree() function.  This object\n                matches all files. \n        !*/\n\n    public:\n        bool operator() (\n            const file& f\n        ) const;\n        /*!\n            ensures\n                - returns true\n                  (i.e. this function doesn't do anything.  It just says it\n                  matches all files no matter what)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const directory& dir\n    );\n    /*!\n        ensures\n            - returns the parent directory of dir.  In particular, this\n              function returns the value of dir.get_parent()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    directory get_parent_directory (\n        const file& f\n    );\n    /*!\n        ensures\n            - if (f.full_name() != \"\") then\n                - returns the directory which contains the given file\n            - else\n                - returns a default initialized directory (i.e. directory())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_oldest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    );\n    /*!\n        ensures\n            - Checks the last modification times of the two given files and returns the\n              filename of the oldest file, i.e., the file that has gone longest since being\n              modified.  Ties are broken arbitrarily. \n            - For the purpose of comparison, a file that doesn't exist is presumed to have\n              a last modification time of -infinity (i.e. very far in the past).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::string select_newest_file (\n        const std::string& filename1,\n        const std::string& filename2\n    );\n    /*!\n        ensures\n            - Checks the last modification times of the two given files and returns the\n              filename that was most recently modified.  Ties are broken arbitrarily. \n            - For the purpose of comparison, a file that doesn't exist is presumed to have\n              a last modification time of -infinity (i.e. very far in the past).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DIR_NAV_EXTENSIONs_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEL_1_CPp_\n#define DLIB_DIR_NAV_KERNEL_1_CPp_\n#include \"../platform.h\"\n\n#ifdef WIN32\n\n#include \"dir_nav_kernel_1.h\"\n#include \"../string.h\"\n\n\n#ifdef __BORLANDC__\n// Apparently the borland compiler doesn't define this.\n#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // file object implementation\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void file::\n    init (\n        const std::string& name\n    )\n    {\n        using namespace std;\n\n\n        char buf[3000];\n        char* str;\n        if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0)\n        {\n            // the file was not found\n            throw file_not_found(\"Unable to find file \" + name);\n        }\n        state.full_name = buf;\n        \n\n        string::size_type pos = state.full_name.find_last_of(directory::get_separator());\n        if (pos == string::npos)\n        {\n            // no valid full path has no separator characters.  \n            throw file_not_found(\"Unable to find file \" + name);\n        }\n        state.name = state.full_name.substr(pos+1);\n\n\n        // now find the size of this file\n        WIN32_FIND_DATAA data;\n        HANDLE ffind = FindFirstFileA(state.full_name.c_str(), &data);\n        if (ffind == INVALID_HANDLE_VALUE ||\n            (data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0)\n        {\n            throw file_not_found(\"Unable to find file \" + name);                \n        }\n        else\n        {\n            uint64 temp = data.nFileSizeHigh;            \n            temp <<= 32;\n            temp |= data.nFileSizeLow;\n            state.file_size = temp;\n            FindClose(ffind);\n\n            ULARGE_INTEGER ull;\n            ull.LowPart = data.ftLastWriteTime.dwLowDateTime;\n            ull.HighPart = data.ftLastWriteTime.dwHighDateTime;\n            std::chrono::nanoseconds epoch(100 * (ull.QuadPart - 116444736000000000));            \n            state.last_modified = std::chrono::time_point<std::chrono::system_clock>(std::chrono::duration_cast<std::chrono::system_clock::duration>(epoch));\n        } \n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool file::\n    operator == (\n        const file& rhs\n    ) const \n    { \n        using namespace std;\n\n        if (state.full_name.size() != rhs.state.full_name.size())\n            return false;\n        \n        // compare the strings but ignore the case because file names\n        // are not case sensitive on windows\n        return tolower(state.full_name) == tolower(rhs.state.full_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // directory object implementation\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void directory::\n    init (\n        const std::string& name\n    )\n    {\n        using namespace std;\n\n        \n        char buf[3000];\n        char* str;\n        if (GetFullPathNameA(name.c_str(),sizeof(buf),buf,&str) == 0)\n        {\n            // the directory was not found\n            throw dir_not_found(\"Unable to find directory \" + name);\n        }\n        state.full_name = buf;\n  \n        \n        const char sep = get_separator();\n        if (is_root_path(state.full_name) == false)\n        {\n            // ensure that thre is not a trialing separator\n            if (state.full_name[state.full_name.size()-1] == sep)\n                state.full_name.erase(state.full_name.size()-1);\n\n            // pick out the directory name\n            string::size_type pos = state.full_name.find_last_of(sep);\n            state.name = state.full_name.substr(pos+1);\n        }\n        else\n        {\n            // ensure that there is a trailing separator\n            if (state.full_name[state.full_name.size()-1] != sep)\n                state.full_name += sep;\n        }\n\n\n        // now check that this is actually a valid directory\n        DWORD attribs = GetFileAttributesA(state.full_name.c_str());\n        if (attribs == INVALID_FILE_ATTRIBUTES ||\n            (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0)\n        {\n            // the directory was not found\n            throw dir_not_found(\"Unable to find directory \" + name);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    char directory::\n    get_separator (\n    ) \n    {\n        return '\\\\';\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory::\n    operator == (\n        const directory& rhs\n    ) const \n    { \n        using namespace std;\n\n        if (state.full_name.size() != rhs.state.full_name.size())\n            return false;\n\n        // compare the strings but ignore the case because file names\n        // are not case sensitive on windows\n        return tolower(state.full_name) == tolower(rhs.state.full_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const directory directory::\n    get_parent (\n    ) const\n    {\n        using namespace std;\n        // if *this is the root then just return *this\n        if (is_root())\n        {\n            return *this;\n        }\n        else\n        {\n            directory temp;\n\n            const char sep = get_separator();\n\n            string::size_type pos = state.full_name.find_last_of(sep);\n            temp.state.full_name = state.full_name.substr(0,pos);\n\n            if ( is_root_path(temp.state.full_name))\n            {\n                temp.state.full_name += sep;\n            }\n            else\n            {\n                pos = temp.state.full_name.find_last_of(sep);\n                if (pos != string::npos)\n                {\n                    temp.state.name = temp.state.full_name.substr(pos+1);\n                }\n                else\n                {\n                    temp.state.full_name += sep;\n                }\n            }\n            return temp;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory::\n    is_root_path (\n        const std::string& path\n    ) const\n    {\n        using namespace std;\n        const char sep = get_separator();\n        bool root_path = false;\n        if (path.size() > 2 && path[0] == sep && path[1] == sep)\n        {\n            // in this case this is a windows share path\n            string::size_type pos = path.find_first_of(sep,2);\n            if (pos != string::npos)\n            {                \n                pos = path.find_first_of(sep,pos+1);\n\n                if (pos == string::npos && path[path.size()-1] != sep)\n                    root_path = true;\n                else if (pos == path.size()-1)\n                    root_path = true;\n            }\n\n        }\n        else if ( (path.size() == 2 || path.size() == 3) && path[1] == ':')\n        {\n            // if this is a valid windows path then it must be a root path\n            root_path = true;\n        }\n\n        return root_path;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // WIN32\n\n#endif // DLIB_DIR_NAV_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEl_1_\n#define DLIB_DIR_NAV_KERNEl_1_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n#include \"../platform.h\"\n\n\n#include \"dir_nav_kernel_abstract.h\"\n#include <string>\n#include \"../uintn.h\"\n#include \"../algs.h\"\n\n#include \"../windows_magic.h\"\n#include <windows.h>\n#include <vector>\n#include \"../stl_checked.h\"\n#include \"../enable_if.h\"\n#include \"../queue.h\"\n#include <chrono>\n\nnamespace dlib\n{\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // file object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    class file\n    {\n        /*!\n            INITIAL VALUES\n                state.name        == name()\n                state.full_name   == full_name()\n                state.file_size   == size()\n                state.last_modified == last_modified()\n\n            CONVENTION\n                state.name        == name()\n                state.full_name   == full_name()\n                state.file_size   == size()\n                state.last_modified == last_modified()\n\n        !*/\n\n        friend class directory;\n\n        struct data\n        {\n            uint64 file_size;\n            std::string name;\n            std::string full_name;\n            std::chrono::time_point<std::chrono::system_clock> last_modified;\n        };\n\n\n        void init ( const std::string& name);\n\n    public:\n\n        struct private_constructor{};\n        inline file (\n            const std::string& name,\n            const std::string& full_name,\n            const uint64 file_size,\n            const std::chrono::time_point<std::chrono::system_clock>& last_modified,\n            private_constructor\n        )\n        {\n            state.file_size = file_size;\n            state.name = name;\n            state.full_name = full_name;\n            state.last_modified = last_modified;\n        }\n\n\n\n\n        class file_not_found : public error { \n            public: file_not_found(const std::string& s): error(s){}\n        };\n        \n        inline file (\n        )\n        {\n            state.file_size = 0;\n        }\n\n        file (\n            const std::string& name\n        ) { init(name); }\n\n        file (\n            const char* name\n        ) { init(name); }\n\n        inline const std::string& name (\n        ) const { return state.name; }\n\n        inline  const std::string& full_name (\n        ) const { return state.full_name; }\n\n        operator std::string (\n        ) const { return full_name(); }\n\n        inline uint64 size (\n        ) const { return state.file_size; }\n\n        inline std::chrono::time_point<std::chrono::system_clock> last_modified (\n        ) const { return state.last_modified; }\n\n        bool operator == (\n            const file& rhs\n        ) const;\n\n        bool operator != (\n            const file& rhs\n        ) const { return !(*this == rhs); }\n\n        inline bool operator < (\n            const file& item\n        ) const { return full_name() < item.full_name(); }\n\n        inline void swap (\n            file& item\n        ) \n        { \n            exchange(state,item.state); \n        }\n\n    private:\n\n        data state;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // directory object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n       \n    class directory\n    {\n        /*!\n            INITIAL VALUES\n                state.name        == name()\n                state.full_name   == full_name()\n\n            CONVENTION\n                state.name        == name()\n                state.full_name   == full_name()\n                is_root()          == state.name.size() == 0\n\n        !*/\n\n        void init (const std::string& name);\n\n    public:\n\n        struct data\n        {\n            std::string name;\n            std::string full_name;\n        };\n\n\n        /*\n            The reason we don't just make this constructor actually\n            private is because doing it this way avoids a bug that \n            sometimes occurs in visual studio 7.1.  The bug has \n            something to do with templated friend functions \n            such as the get_filesystem_roots() function below if \n            it was declared as a friend template of this class. \n        */\n        struct private_constructor{};\n        inline directory (\n            const std::string& name,\n            const std::string& full_name,\n            private_constructor \n        )\n        {\n            state.name = name;\n            state.full_name = full_name;\n        }\n\n\n        class dir_not_found : public error {\n            public: dir_not_found(const std::string& s):error(s){}\n        };\n        class listing_error : public error {\n            public: listing_error(const std::string& s):error(s){}\n        };\n        \n        inline directory (\n        )\n        {\n        }\n\n        directory (\n            const std::string& name\n        ) { init(name); }\n\n        directory (\n            const char* name\n        ) { init(name); }\n\n\n        static char get_separator (\n        );\n\n\n        template <\n            typename queue_of_files\n            >\n        void get_files (\n            queue_of_files& files\n        ) const;\n\n        template <\n            typename queue_of_dirs\n            >\n        void get_dirs (\n            queue_of_dirs& dirs\n        ) const;\n\n        std::vector<file> get_files (\n        ) const\n        {\n            std::vector<file> temp_vector;\n            get_files(temp_vector);\n            return temp_vector;\n        }\n\n        std::vector<directory> get_dirs (\n        ) const\n        {\n            std::vector<directory> temp_vector;\n            get_dirs(temp_vector);\n            return temp_vector;\n        }\n\n        const directory get_parent (\n        ) const;\n       \n        inline bool is_root (\n        ) const { return state.name.size() == 0; }\n\n        inline const std::string& name (\n        ) const { return state.name; }\n\n        inline const std::string& full_name (\n        ) const { return state.full_name; }\n\n        operator std::string (\n        ) const { return full_name(); }\n\n        bool operator == (\n            const directory& rhs\n        ) const;\n\n        bool operator != (\n            const directory& rhs\n        ) const { return !(*this == rhs); }\n\n        inline bool operator < (\n            const directory& item\n        ) const { return full_name() < item.full_name(); }\n\n        inline void swap (\n            directory& item\n        ) \n        { \n            exchange(state,item.state); \n        }\n\n    private:\n\n        // member data\n        data state;\n\n        bool is_root_path (\n            const std::string& path\n        ) const;\n        /*!\n            ensures\n                - returns true if path is a root path.  \n                  Note that this function considers root paths that don't\n                  have a trailing separator to also be valid.\n        !*/\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const directory& item\n    ) { out << (std::string)item; return out; }\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const file& item\n    ) { out << (std::string)item; return out; }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dir\n        >\n    typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (\n        queue_of_dir& roots\n    )\n    {\n        roots.clear();\n        const DWORD mask = GetLogicalDrives();\n        DWORD bit = 1;\n        char buf[] = \"A:\\\\\";\n\n        do\n        {\n            if (mask & bit)\n            {\n                directory dir(\"\",buf,directory::private_constructor());\n                roots.enqueue(dir);\n            }\n            bit <<= 1;\n            ++buf[0];\n        } while (buf[0] != 'Z');\n    }\n\n    template <\n        typename queue_of_dir\n        >\n    typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (\n        queue_of_dir& roots\n    )\n    {\n        roots.clear();\n        const DWORD mask = GetLogicalDrives();\n        DWORD bit = 1;\n        char buf[] = \"A:\\\\\";\n\n        do\n        {\n            if (mask & bit)\n            {\n                directory dir(\"\",buf,directory::private_constructor());\n                roots.push_back(dir);\n            }\n            bit <<= 1;\n            ++buf[0];\n        } while (buf[0] != 'Z');\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        file& a, \n        file& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        directory& a, \n        directory& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // templated member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    typename disable_if<is_std_vector<queue_of_files>,void>::type \n    directory_helper_get_files (\n        const directory::data& state,\n        queue_of_files& files\n    ) \n    {\n        typedef directory::listing_error listing_error;\n        typedef file::private_constructor private_constructor;\n\n        files.clear();\n        if (state.full_name.size() == 0)\n            throw listing_error(\"This directory object currently doesn't represent any directory.\");\n\n        HANDLE ffind = INVALID_HANDLE_VALUE;\n        try\n        {\n            WIN32_FIND_DATAA data;\n            std::string path = state.full_name;\n            // ensure that the path ends with a separator\n            if (path[path.size()-1] != directory::get_separator())\n                path += directory::get_separator();\n            \n            ffind = FindFirstFileA((path+\"*\").c_str(), &data);\n            if (ffind == INVALID_HANDLE_VALUE)\n            {\n                throw listing_error(\"Unable to list the contents of \" + state.full_name);\n            }\n\n\n            bool no_more_files = false;\n            do\n            {\n                if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0)\n                {\n                    uint64 file_size = data.nFileSizeHigh;                                   \n                    file_size <<= 32;\n                    file_size |= data.nFileSizeLow;\n\n                    ULARGE_INTEGER ull;\n                    ull.LowPart = data.ftLastWriteTime.dwLowDateTime;\n                    ull.HighPart = data.ftLastWriteTime.dwHighDateTime;\n                    std::chrono::nanoseconds epoch(100 * (ull.QuadPart - 116444736000000000));\n                    auto last_modified = std::chrono::time_point<std::chrono::system_clock>(std::chrono::duration_cast<std::chrono::system_clock::duration>(epoch));\n                    \n                    // this is a file so add it to the queue\n                    file temp(data.cFileName,path+data.cFileName,file_size, last_modified, private_constructor());\n                    files.enqueue(temp);\n                }\n\n                if (FindNextFileA(ffind,&data) == 0)\n                {\n                    // an error occurred\n                    if ( GetLastError() == ERROR_NO_MORE_FILES)\n                    {\n                        // there are no more files\n                        no_more_files = true;\n                    }\n                    else\n                    {\n                        // there was an error\n                        throw listing_error(\"Unable to list the contents of \" + state.full_name);\n                    }  \n                }\n            } while (no_more_files == false);\n\n            FindClose(ffind); \n            ffind = INVALID_HANDLE_VALUE;\n        }\n        catch (...)\n        {\n            if (ffind != INVALID_HANDLE_VALUE)\n                FindClose(ffind);    \n            files.clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    typename enable_if<is_std_vector<queue_of_files>,void>::type \n    directory_helper_get_files (\n        const directory::data& state,\n        queue_of_files& files\n    ) \n    {\n        queue<file>::kernel_2a temp_files;\n        directory_helper_get_files(state,temp_files);\n\n        files.clear();\n\n        // copy the queue of files into the vector\n        temp_files.reset();\n        while (temp_files.move_next())\n        {\n            files.push_back(temp_files.element());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    void directory::\n    get_files (\n        queue_of_files& files\n    ) const\n    {\n        // the reason for this indirection here is because it avoids a bug in\n        // the mingw version of gcc\n        directory_helper_get_files(state,files);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dirs\n        >\n    typename disable_if<is_std_vector<queue_of_dirs>,void>::type \n    directory_helper_get_dirs (\n        const directory::data& state,\n        queue_of_dirs& dirs\n    ) \n    {\n        typedef directory::listing_error listing_error;\n        typedef directory::private_constructor private_constructor;\n\n        dirs.clear();\n        if (state.full_name.size() == 0)\n            throw listing_error(\"This directory object currently doesn't represent any directory.\");\n\n        HANDLE dfind = INVALID_HANDLE_VALUE;\n        try\n        {\n            WIN32_FIND_DATAA data;\n            std::string path = state.full_name;\n            // ensure that the path ends with a separator\n            if (path[path.size()-1] != directory::get_separator())\n                path += directory::get_separator();\n            \n            dfind = FindFirstFileA((path+\"*\").c_str(), &data);\n            if (dfind == INVALID_HANDLE_VALUE)\n            {\n                throw listing_error(\"Unable to list the contents of \" + state.full_name);\n            }\n\n\n            bool no_more_files = false;\n            do\n            {\n                std::string tname(data.cFileName);\n                if ((data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0 &&\n                    tname != \".\" &&\n                    tname != \"..\")\n                {\n                    // this is a directory so add it to the queue\n                    directory temp(tname,path+tname,private_constructor());\n                    dirs.enqueue(temp);\n                }\n\n                if (FindNextFileA(dfind,&data) == 0)\n                {\n                    // an error occurred\n                    if ( GetLastError() == ERROR_NO_MORE_FILES)\n                    {\n                        // there are no more files\n                        no_more_files = true;\n                    }\n                    else\n                    {\n                        // there was an error\n                        throw listing_error(\"Unable to list the contents of \" + state.full_name);\n                    }  \n                }\n            } while (no_more_files == false);\n\n            FindClose(dfind);  \n            dfind = INVALID_HANDLE_VALUE;\n        }\n        catch (...)\n        {         \n            if (dfind != INVALID_HANDLE_VALUE)\n                FindClose(dfind);\n            dirs.clear();\n            throw;\n        }\n\n    }\n \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dirs\n        >\n    typename enable_if<is_std_vector<queue_of_dirs>,void>::type \n    directory_helper_get_dirs (\n        const directory::data& state,\n        queue_of_dirs& dirs\n    ) \n    {\n        queue<directory>::kernel_2a temp_dirs;\n        directory_helper_get_dirs(state,temp_dirs);\n\n        dirs.clear();\n\n        // copy the queue of dirs into the vector\n        temp_dirs.reset();\n        while (temp_dirs.move_next())\n        {\n            dirs.push_back(temp_dirs.element());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dirs\n        >\n    void directory::\n    get_dirs (\n        queue_of_dirs& dirs\n    ) const\n    {\n        // the reason for this indirection here is because it avoids a bug in\n        // the mingw version of gcc\n        directory_helper_get_dirs(state,dirs);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#ifdef NO_MAKEFILE\n#include \"dir_nav_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_DIR_NAV_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_kernel_2.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEL_2_CPp_\n#define DLIB_DIR_NAV_KERNEL_2_CPp_\n\n#include \"../platform.h\"\n\n#ifdef DLIB_POSIX\n\n\n#include \"dir_nav_kernel_2.h\"\n\n\n\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // file object implementation\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void file::\n    init (\n        const std::string& name\n    )\n    {\n        using namespace std;\n\n\n\n        char buf[PATH_MAX];\n        if (realpath(name.c_str(),buf) == 0)\n        {\n            // the file was not found\n            throw file_not_found(\"Unable to find file \" + name);\n        }\n        state.full_name = buf;\n\n\n        string::size_type pos = state.full_name.find_last_of(directory::get_separator());\n        if (pos == string::npos)\n        {\n            // no valid full path has no separtor characters.  \n            throw file_not_found(\"Unable to find file \" + name);\n        }\n        state.name = state.full_name.substr(pos+1);\n\n\n        // now find the size of this file\n        struct stat64 buffer;\n        if (::stat64(state.full_name.c_str(), &buffer) ||\n            S_ISDIR(buffer.st_mode))\n        {\n            // there was an error during the call to stat64 or\n            // name is actually a directory\n            throw file_not_found(\"Unable to find file \" + name);\n        }\n        else\n        {\n            state.file_size = static_cast<uint64>(buffer.st_size);\n\n\n            state.last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime);\n#ifdef _BSD_SOURCE \n            state.last_modified += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::nanoseconds(buffer.st_atim.tv_nsec));\n#endif\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool file::\n    operator == (\n        const file& rhs\n    ) const \n    { \n        using namespace std;\n        if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0)\n            return true;\n\n        // These files might have different names but actually represent the same\n        // file due to the presence of symbolic links.\n        char buf[PATH_MAX];\n        string left, right;\n        if (realpath(state.full_name.c_str(),buf) == 0)\n            return false;    \n        left = buf;\n\n        if (realpath(rhs.state.full_name.c_str(),buf) == 0)\n            return false;    \n        right = buf;\n\n        return (left == right);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // directory object implementation\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void directory::\n    init (\n        const std::string& name\n    )\n    {\n        using namespace std;\n\n        \n        char buf[PATH_MAX];\n        if (realpath(name.c_str(),buf) == 0)\n        {\n            // the directory was not found\n            throw dir_not_found(\"Unable to find directory \" + name);\n        }\n        state.full_name = buf;\n  \n        \n        const char sep = get_separator();\n        if (is_root_path(state.full_name) == false)\n        {\n            // ensure that thre is not a trialing separator\n            if (state.full_name[state.full_name.size()-1] == sep)\n                state.full_name.erase(state.full_name.size()-1);\n\n            // pick out the directory name\n            string::size_type pos = state.full_name.find_last_of(sep);\n            state.name = state.full_name.substr(pos+1);\n        }\n        else\n        {\n            // ensure that there is a trailing separator\n            if (state.full_name[state.full_name.size()-1] != sep)\n                state.full_name += sep;\n        }\n\n\n        struct stat64 buffer;\n        // now check that this is actually a valid directory\n        if (::stat64(state.full_name.c_str(),&buffer))\n        {\n            // the directory was not found\n            throw dir_not_found(\"Unable to find directory \" + name);\n        }\n        else if (S_ISDIR(buffer.st_mode) == 0)\n        {\n            // It is not a directory\n            throw dir_not_found(\"Unable to find directory \" + name);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    char directory::\n    get_separator (\n    ) \n    {\n        return '/';\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory::\n    operator == (\n        const directory& rhs\n    ) const \n    { \n        using namespace std;\n        if (state.full_name.size() == 0 && rhs.state.full_name.size() == 0)\n            return true;\n\n        // These directories might have different names but actually represent the same\n        // directory due to the presence of symbolic links.\n        char buf[PATH_MAX];\n        string left, right;\n        if (realpath(state.full_name.c_str(),buf) == 0)\n            return false;    \n        left = buf;\n\n        if (realpath(rhs.state.full_name.c_str(),buf) == 0)\n            return false;    \n        right = buf;\n\n        return (left == right);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const directory directory::\n    get_parent (\n    ) const\n    {\n        using namespace std;\n        // if *this is the root then just return *this\n        if (is_root())\n        {\n            return *this;\n        }\n        else\n        {\n            directory temp;\n\n            const char sep = get_separator();\n\n            string::size_type pos = state.full_name.find_last_of(sep);\n            temp.state.full_name = state.full_name.substr(0,pos);\n\n            if ( is_root_path(temp.state.full_name))\n            {\n                temp.state.full_name += sep;\n            }\n            else\n            {\n                pos = temp.state.full_name.find_last_of(sep);\n                if (pos != string::npos)\n                {\n                    temp.state.name = temp.state.full_name.substr(pos+1);\n                }\n                else\n                {\n                    temp.state.full_name += sep;\n                }\n            }\n            return temp;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool directory::\n    is_root_path (\n        const std::string& path\n    ) const\n    {\n        const char sep = get_separator();\n        if (path.size() == 1 && path[0] == sep)\n            return true;\n        else\n            return false;   \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_POSIX\n\n#endif // DLIB_DIR_NAV_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEl_2_\n#define DLIB_DIR_NAV_KERNEl_2_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n\n#include \"dir_nav_kernel_abstract.h\"\n\n#include <string>\n#include \"../uintn.h\"\n#include \"../algs.h\"\n\n#include <sys/types.h>\n#include <dirent.h>\n#include <libgen.h>\n#include <limits.h>\n#include <unistd.h>\n#include <sys/stat.h>\n#include <errno.h>\n#include <stdlib.h>\n#include <chrono>\n\n#if !defined(__USE_LARGEFILE64 ) && !defined(_LARGEFILE64_SOURCE)\n#define stat64 stat\n#endif\n\n#include <vector>\n#include \"../stl_checked.h\"\n#include \"../enable_if.h\"\n#include \"../queue.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // file object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    class file\n    {\n        /*!\n            INITIAL VALUES\n                state.name        == name()\n                state.full_name   == full_name()\n                state.file_size   == size()\n                state.last_modified == last_modified()\n\n            CONVENTION\n                state.name        == name()\n                state.full_name   == full_name()\n                state.file_size   == size()\n                state.last_modified == last_modified()\n\n        !*/\n\n        friend class directory;\n\n        struct data\n        {\n            uint64 file_size;\n            std::string name;\n            std::string full_name;\n            std::chrono::time_point<std::chrono::system_clock> last_modified;\n        };\n\n        void init(const std::string& name);\n\n    public:\n\n        struct private_constructor{};\n        inline file (\n            const std::string& name,\n            const std::string& full_name,\n            const uint64 file_size,\n            const std::chrono::time_point<std::chrono::system_clock>& last_modified,\n            private_constructor\n        )\n        {\n            state.file_size = file_size;\n            state.name = name;\n            state.full_name = full_name;\n            state.last_modified = last_modified;\n        }\n\n\n        class file_not_found : public error { \n            public: file_not_found(const std::string& s): error(s){}\n        };\n        \n        inline file (\n        )\n        {\n            state.file_size = 0;\n        }\n\n        file (\n            const std::string& name\n        ) { init(name); }\n\n        file (\n            const char* name\n        ) { init(name); }\n\n        inline const std::string& name (\n        ) const { return state.name; }\n\n        inline  const std::string& full_name (\n        ) const { return state.full_name; }\n\n        inline uint64 size (\n        ) const { return state.file_size; }\n\n        inline std::chrono::time_point<std::chrono::system_clock> last_modified (\n        ) const { return state.last_modified; }\n\n        operator std::string (\n        ) const { return full_name(); }\n\n        bool operator == (\n            const file& rhs\n        ) const;\n\n        bool operator != (\n            const file& rhs\n        ) const { return !(*this == rhs); }\n\n        inline bool operator < (\n            const file& item\n        ) const { return full_name() < item.full_name(); }\n\n        inline void swap (\n            file& item\n        ) \n        { \n            exchange(state,item.state); \n        }\n\n    private:\n\n        // member data\n        data state;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // directory object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n       \n    class directory\n    {\n        /*!\n            INITIAL VALUES\n                state.name        == name()\n                state.full_name   == full_name()\n\n            CONVENTION\n                state.name        == name()\n                state.full_name   == full_name()\n                is_root()          == state.name.size() == 0\n\n        !*/\n\n        void init(const std::string& name);\n\n    public:\n        struct private_constructor{};\n        inline directory (\n            const std::string& name,\n            const std::string& full_name,\n            private_constructor\n        )\n        {\n            state.name = name;\n            state.full_name = full_name;\n        }\n\n        struct data\n        {\n            std::string name;\n            std::string full_name;\n        };\n\n        class dir_not_found : public error {\n            public: dir_not_found(const std::string& s):error(s){}\n        };\n        class listing_error : public error {\n            public: listing_error(const std::string& s):error(s){}\n        };\n        \n        inline directory (\n        )\n        {\n        }\n\n        directory (\n            const std::string& name\n        ) { init(name); }\n\n        directory (\n            const char* name\n        ) { init(name); }\n\n        static char get_separator (\n        );\n\n        template <\n            typename queue_of_files\n            >\n        void get_files (\n            queue_of_files& files\n        ) const;\n\n        template <\n            typename queue_of_dirs\n            >\n        void get_dirs (\n            queue_of_dirs& dirs\n        ) const;\n\n        std::vector<file> get_files (\n        ) const\n        {\n            std::vector<file> temp_vector;\n            get_files(temp_vector);\n            return temp_vector;\n        }\n\n        std::vector<directory> get_dirs (\n        ) const\n        {\n            std::vector<directory> temp_vector;\n            get_dirs(temp_vector);\n            return temp_vector;\n        }\n\n        const directory get_parent (\n        ) const;\n       \n        inline bool is_root (\n        ) const { return state.name.size() == 0; }\n\n        inline const std::string& name (\n        ) const { return state.name; }\n\n        inline const std::string& full_name (\n        ) const { return state.full_name; }\n\n        operator std::string (\n        ) const { return full_name(); }\n\n        bool operator == (\n            const directory& rhs\n        ) const;\n\n        bool operator != (\n            const directory& rhs\n        ) const { return !(*this == rhs); }\n\n        inline bool operator < (\n            const directory& item\n        ) const { return full_name() < item.full_name(); }\n\n        inline void swap (\n            directory& item\n        ) \n        { \n            exchange(state,item.state); \n        }\n\n    private:\n\n        // member data\n        data state;\n\n        bool is_root_path (\n            const std::string& path\n        ) const;\n        /*!\n            ensures\n                - returns true if path is a root path.  \n                  Note that this function considers root paths that don't\n                  have a trailing separator to also be valid.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const directory& item\n    ) { out << (std::string)item; return out; }\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const file& item\n    ) { out << (std::string)item; return out; }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        file& a, \n        file& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        directory& a, \n        directory& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // templated member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    typename disable_if<is_std_vector<queue_of_files>,void>::type\n    directory_helper_get_files (\n        const directory::data& state,\n        queue_of_files& files\n    ) \n    {\n        files.clear();\n        if (state.full_name.size() == 0)\n            throw directory::listing_error(\"This directory object currently doesn't represent any directory.\");\n\n        DIR* ffind = 0;\n        struct dirent* data;\n        struct stat64 buffer;\n\n        try\n        {\n            std::string path = state.full_name;\n            // ensure that the path ends with a separator\n            if (path[path.size()-1] != directory::get_separator())\n                path += directory::get_separator();\n\n            // get a handle to something we can search with\n            ffind = opendir(state.full_name.c_str());\n            if (ffind == 0)\n            {\n                throw directory::listing_error(\"Unable to list the contents of \" + state.full_name);\n            }\n\n            while(true)\n            {\n                errno = 0;\n                if ( (data = readdir(ffind)) == 0)\n                {                    \n                    // there was an error or no more files\n                    if ( errno == 0)\n                    {\n                        // there are no more files\n                        break;\n                    }\n                    else\n                    {\n                        // there was an error\n                        throw directory::listing_error(\"Unable to list the contents of \" + state.full_name);\n                    }                \n                }\n\n                uint64 file_size;\n                // get a stat64 structure so we can see if this is a file\n                if (::stat64((path+data->d_name).c_str(), &buffer) != 0)\n                {\n                    // this might be a broken symbolic link.  We can check by calling\n                    // readlink and seeing if it finds anything.  \n                    char buf[PATH_MAX];\n                    ssize_t temp = readlink((path+data->d_name).c_str(),buf,sizeof(buf));\n                    if (temp == -1)                    \n                        throw directory::listing_error(\"Unable to list the contents of \" + state.full_name);\n                    else\n                        file_size = static_cast<uint64>(temp);\n                }\n                else\n                {\n                    file_size = static_cast<uint64>(buffer.st_size);\n                }\n                auto last_modified = std::chrono::system_clock::from_time_t(buffer.st_mtime);\n#ifdef _BSD_SOURCE \n                last_modified += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::nanoseconds(buffer.st_atim.tv_nsec));\n#endif\n\n                if (S_ISDIR(buffer.st_mode) == 0)\n                {\n                    // this is actually a file\n                    file temp(\n                        data->d_name,\n                        path+data->d_name,\n                        file_size,\n                        last_modified,\n                        file::private_constructor()\n                        );\n                    files.enqueue(temp);\n                }\n            } // while (true)\n\n            if (ffind != 0)\n            {\n                while (closedir(ffind))\n                {\n                    if (errno != EINTR)\n                        break;\n                }\n                ffind = 0;\n            }\n\n        }\n        catch (...)\n        {\n            if (ffind != 0)\n            {\n                while (closedir(ffind))\n                {\n                    if (errno != EINTR)\n                        break;\n                }\n                ffind = 0;\n            }\n            files.clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    typename enable_if<is_std_vector<queue_of_files>,void>::type \n    directory_helper_get_files (\n        const directory::data& state,\n        queue_of_files& files\n    ) \n    {\n        queue<file>::kernel_2a temp_files;\n        directory_helper_get_files(state,temp_files);\n\n        files.clear();\n\n        // copy the queue of files into the vector\n        temp_files.reset();\n        while (temp_files.move_next())\n        {\n            files.push_back(temp_files.element());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_files\n        >\n    void directory::\n    get_files (\n        queue_of_files& files\n    ) const\n    {\n        // the reason for this indirection here is because it avoids a bug in\n        // the cygwin version of gcc\n        directory_helper_get_files(state,files);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dirs\n        >\n    typename disable_if<is_std_vector<queue_of_dirs>,void>::type \n    directory_helper_get_dirs (\n        const directory::data& state,\n        queue_of_dirs& dirs\n    ) \n    {\n        dirs.clear();\n        if (state.full_name.size() == 0)\n            throw directory::listing_error(\"This directory object currently doesn't represent any directory.\");\n\n        DIR* ffind = 0;\n        struct dirent* data;\n        struct stat64 buffer;\n\n        try\n        {\n            std::string path = state.full_name;\n            // ensure that the path ends with a separator\n            if (path[path.size()-1] != directory::get_separator())\n                path += directory::get_separator();\n\n            // get a handle to something we can search with\n            ffind = opendir(state.full_name.c_str());\n            if (ffind == 0)\n            {\n                throw directory::listing_error(\"Unable to list the contents of \" + state.full_name);\n            }\n\n            while(true)\n            {\n                errno = 0;\n                if ( (data = readdir(ffind)) == 0)\n                {                    \n                    // there was an error or no more files\n                    if ( errno == 0)\n                    {\n                        // there are no more files\n                        break;\n                    }\n                    else\n                    {\n                        // there was an error\n                        throw directory::listing_error(\"Unable to list the contents of \" + state.full_name);\n                    }                \n                }\n\n                // get a stat64 structure so we can see if this is a file\n                if (::stat64((path+data->d_name).c_str(), &buffer) != 0)\n                {\n                    // just assume this isn't a directory.  It is probably a broken\n                    // symbolic link.\n                    continue;\n                }\n\n                std::string dtemp(data->d_name);\n                if (S_ISDIR(buffer.st_mode) &&\n                    dtemp != \".\" &&\n                    dtemp != \"..\" )\n                {\n                    // this is a directory so add it to dirs\n                    directory temp(dtemp,path+dtemp, directory::private_constructor());\n                    dirs.enqueue(temp);\n                }\n            } // while (true)\n\n            if (ffind != 0)\n            {\n                while (closedir(ffind))\n                {\n                    if (errno != EINTR)\n                        break;\n                }\n                ffind = 0;\n            }\n\n        }\n        catch (...)\n        {\n            if (ffind != 0)\n            {\n                while (closedir(ffind))\n                {\n                    if (errno != EINTR)\n                        break;\n                }\n                ffind = 0;\n            }\n            dirs.clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dirs\n        >\n    typename enable_if<is_std_vector<queue_of_dirs>,void>::type \n    directory_helper_get_dirs (\n        const directory::data& state,\n        queue_of_dirs& dirs\n    ) \n    {\n        queue<directory>::kernel_2a temp_dirs;\n        directory_helper_get_dirs(state,temp_dirs);\n\n        dirs.clear();\n\n        // copy the queue of dirs into the vector\n        temp_dirs.reset();\n        while (temp_dirs.move_next())\n        {\n            dirs.push_back(temp_dirs.element());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <\n        typename queue_of_dirs\n        >\n    void directory::\n    get_dirs (\n        queue_of_dirs& dirs\n    ) const\n    {\n        // the reason for this indirection here is because it avoids a bug in\n        // the cygwin version of gcc\n        directory_helper_get_dirs(state,dirs);\n    }\n \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dir\n        >\n    typename disable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (\n        queue_of_dir& roots\n    )\n    {\n        roots.clear();\n        directory dir(\"/\");\n        roots.enqueue(dir);\n    }\n\n    template <\n        typename queue_of_dir\n        >\n    typename enable_if<is_std_vector<queue_of_dir>,void>::type get_filesystem_roots (\n        std::vector<directory>& roots\n    )\n    {\n        roots.clear();\n        directory dir(\"/\");\n        roots.push_back(dir);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#ifdef NO_MAKEFILE\n#include \"dir_nav_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_DIR_NAV_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/dir_nav/dir_nav_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DIR_NAV_KERNEl_ABSTRACT_\n#ifdef DLIB_DIR_NAV_KERNEl_ABSTRACT_\n\n#include <string>\n#include <vector>\n#include \"../uintn.h\"\n#include \"../algs.h\"\n#include <chrono>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        GENERAL WARNING\n            Don't call any of these functions or make any of these objects \n            before main() has been entered.   That means no instances\n            of file or directory at the global scope.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_of_dir\n        >\n    void get_filesystem_roots (\n        queue_of_dir& roots\n    );\n    /*!\n        requires\n            - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T \n              set to directory or a std::vector<directory> or dlib::std_vector_c<directory>.\n        ensures\n            - #roots == a queue containing directories that represent all the roots \n              of the filesystem on this machine.   (e.g. in windows you have c:\\, d:\\ \n              etc.)\n        throws\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // file object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    class file\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a file.\n\n                Note that the size of a file is determined at the time the file\n                object is constructed.  Thus if a file changes sizes after its\n                file object has been created its file object's size() method\n                will not reflect the new file size.    \n        !*/\n\n    public:\n\n        class file_not_found : public error {};\n        \n        file (\n        );\n        /*!\n            ensures\n                - #*this has been properly initialized\n                - #name() == \"\"\n                - #full_name() == \"\"\n                - #size() == 0\n                - #*this does not represent any file\n            throws  \n                - std::bad_alloc\n        !*/\n\n        file (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - #*this has been properly initialized \n                - #*this represents the file given by name\n                  Note that name can be a fully qualified path or just a path\n                  relative to the current working directory.  Also, any symbolic \n                  links in name will be resolved.\n            throws  \n                - std::bad_alloc\n                - file_not_found\n                    This exception is thrown if the file can not be found or\n                    accessed.                    \n        !*/\n\n        file (\n            const char* name\n        );\n        /*!\n            ensures\n                - this function is identical to file(const std::string& name)\n        !*/\n\n        file (\n            const file& item\n        );\n        /*!\n            ensures\n                - #*this == item\n            throws  \n                - std::bad_alloc\n        !*/\n\n        ~file (\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        const std::string& name (\n        ) const;\n        /*!\n            ensures\n                - returns the name of the file.  This is full_name() minus \n                  the path to the file.            \n        !*/\n\n        const std::string& full_name (\n        ) const;\n        /*!\n            ensures\n                - returns the fully qualified name for the file represented by *this \n        !*/\n\n        uint64 size (\n        ) const;\n        /*!\n            ensures\n                - returns the size of this file in bytes.\n        !*/\n\n        std::chrono::time_point<std::chrono::system_clock> last_modified (\n        ) const;\n        /*!\n            ensures\n                - returns the time the file was last modified.\n        !*/\n\n        operator std::string (\n        ) const; \n        /*!\n            ensures\n                - returns full_name()\n                  (i.e. provides an implicit conversion to string from dlib::file)\n        !*/\n\n        file& operator= (\n            const file& rhs\n        );\n        /*!\n            ensures\n                - #*this == rhs\n        !*/\n\n        bool operator == (\n            const file& rhs\n        ) const;\n        /*!\n            ensures\n                - if (*this and rhs represent the same file) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool operator != (\n            const file& rhs\n        ) const;\n        /*!\n            ensures\n                - if (*this and rhs represent the same file) then\n                    - returns false \n                - else\n                    - returns true \n        !*/\n\n        bool operator < (\n            const file& item\n        ) const;\n        /*!\n            ensures\n                - if (full_name() < item.full_name()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void swap (\n            file& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // directory object    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    class directory\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a directory in a file system.  It gives\n                the ability to traverse a directory tree.  \n\n                Note that the directories . and .. are not returned by get_dirs() \n        !*/\n\n    public:\n\n        class dir_not_found : public error {};\n        class listing_error : public error {};\n        \n        directory (\n        );\n        /*!\n            ensures\n                - #*this has been properly initialized\n                - #full_name() == \"\"\n                - #name() == \"\"\n                - #is_root() == true\n                - #*this does not represent any directory\n            throws  \n                - std::bad_alloc\n        !*/\n\n        directory (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - #*this has been properly initialized \n                - #*this represents the directory given by name.\n                  Note that name can be a fully qualified path or just a path\n                  relative to the current working directory. Also, any symbolic \n                  links in name will be resolved.\n            throws  \n                - std::bad_alloc\n                - dir_not_found\n                    This exception is thrown if the directory can not be found or\n                    accessed.    \n        !*/\n\n        directory (\n            const char* name\n        );\n        /*!\n            ensures\n                - this function is identical to directory(const std::string& name)\n        !*/\n\n        directory (\n            const directory& item\n        );\n        /*!\n            ensures\n                - #*this == item\n            throws  \n                - std::bad_alloc\n        !*/\n\n        ~directory (\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        static char get_separator (\n        );\n        /*!\n            ensures\n                - returns the character used to separate directories and file names in a\n                  path.  (i.e.  \\ on windows and / in unix)\n        !*/\n\n        template <\n            typename queue_of_files\n            >\n        void get_files (\n            queue_of_files& files\n        ) const;\n        /*!\n            requires\n                - queue_of_files == an implementation of queue/queue_kernel_abstract.h with T \n                  set to file or a std::vector<file> or dlib::std_vector_c<file>.\n            ensures\n                - #files == A queue containing all the files present in this directory.\n                  (Note that symbolic links will not have been resolved in the names \n                  of the returned files.)\n                - #files.size() == the number of files in this directory\n            throws \n                - bad_alloc\n                    If this exception is thrown then the call to get_files() has\n                    no effect on *this and #files is unusable until files.clear()\n                    is called and succeeds.\n                - listing_error\n                    This exception is thrown if listing access has been denied to this\n                    directory or if some error occurred that prevented us from successfully\n                    getting the contents of this directory.       \n                    If this exception is thrown then the call to get_files() has\n                    no effect on *this and #files.size()==0.         \n        !*/\n\n        std::vector<file> get_files (\n        ) const;\n        /*!\n            ensures\n                - This function simply calls get_files(temp_vector) and then returns temp_vector.\n        !*/\n\n        template <\n            typename queue_of_dirs\n            >\n        void get_dirs (\n            queue_of_dirs& dirs\n        ) const;\n        /*!\n            requires\n                - queue_of_dirs == an implementation of queue/queue_kernel_abstract.h with T \n                  set to directory or a std::vector<directory> or dlib::std_vector_c<directory>.\n            ensures\n                - #dirs == a queue containing all the directories present in this directory.\n                  (note that symbolic links will not have been resolved in the names \n                  of the returned directories.)\n                - #dirs.size() == the number of subdirectories in this directory\n            throws \n                - bad_alloc\n                    If this exception is thrown then the call to get_files() has\n                    no effect on *this and #files is unusable until files.clear()\n                    is called and succeeds.\n                - listing_error\n                    This exception is thrown if listing access has been denied to this\n                    directory or if some error occurred that prevented us from successfully\n                    getting the contents of this directory.\n                    If this exception is thrown then the call to get_dirs() has\n                    no effect on *this and #dirs.size()==0.\n        !*/\n\n        std::vector<directory> get_dirs (\n        ) const;\n        /*!\n            ensures\n                - This function simply calls get_dirs(temp_vector) and then returns temp_vector.\n        !*/\n\n        bool is_root (\n        ) const;\n        /*!\n            ensures\n                - if (*this represents the root of this directory tree) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        const directory get_parent (\n        ) const;\n        /*!\n            ensures\n                - if (is_root()) then\n                    - returns a copy of *this                    \n                - else\n                    - returns the parent directory of *this                    \n            throws\n                - bad_alloc\n                    If this exception is thrown then the call to get_parent() will\n                    have no effect.\n        !*/\n\n        const std::string& name (\n        ) const;\n        /*!\n            ensures\n                - if (is_root()) then\n                    - returns \"\"\n                - else\n                    - returns the name of the directory.  This is full_name() minus \n                      the path to the directory.           \n        !*/\n\n        const std::string& full_name (\n        ) const;\n        /*!\n            ensures\n                - returns the fully qualified directory name for *this \n                - if (is_root()) then\n                    - the last character of #full_name() is get_separator()\n                - else\n                    - the last character of #full_name() is NOT get_separator()\n        !*/\n\n        operator std::string (\n        ) const; \n        /*!\n            ensures\n                - returns full_name()\n                  (i.e. provides an implicit conversion to string from dlib::directory)\n        !*/\n\n        directory& operator= (\n            const directory& rhs\n        );\n        /*!\n            ensures\n                - #*this == rhs\n        !*/\n\n        bool operator == (\n            const directory& rhs\n        ) const;\n        /*!\n            ensures\n                - if (*this and rhs represent the same directory) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool operator != (\n            const directory& rhs\n        ) const;\n        /*!\n            ensures\n                - if (*this and rhs represent the same directory) then\n                    - returns false \n                - else\n                    - returns true \n        !*/\n\n        bool operator < (\n            const directory& item\n        ) const;\n        /*!\n            ensures\n                - if (full_name() < item.full_name()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void swap (\n            directory& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const directory& item\n    );\n    /*!\n        ensures\n            - performs: out << item.full_name()\n            - returns out\n    !*/\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const file& item\n    );\n    /*!\n        ensures\n            - performs: out << item.full_name()\n            - returns out\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        file& a, \n        file& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function for file objects\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void swap (\n        directory& a, \n        directory& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function for directory objects\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DIR_NAV_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/dir_nav/posix.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEl_1_\n#include \"dir_nav_kernel_2.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/dir_nav/windows.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAV_KERNEl_2_\n#include \"dir_nav_kernel_1.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/dir_nav.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIR_NAv_\n#define DLIB_DIR_NAv_\n\n\n#include \"platform.h\"\n\n\n#ifdef WIN32\n#include \"dir_nav/windows.h\"\n#endif\n\n#ifndef WIN32\n#include \"dir_nav/posix.h\"\n#endif\n\n#include \"dir_nav/dir_nav_extensions.h\"\n\n#endif // DLIB_DIR_NAv_\n\n"
  },
  {
    "path": "dlib/directed_graph/directed_graph_kernel_1.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIRECTED_GRAPH_KERNEl_1_\n#define DLIB_DIRECTED_GRAPH_KERNEl_1_\n\n#include <memory>\n#include <vector>\n\n#include \"../serialize.h\"\n#include \"../noncopyable.h\"\n#include \"../std_allocator.h\"\n#include \"../algs.h\"\n#include \"directed_graph_kernel_abstract.h\"\n#include \"../is_kind.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename node_type, typename directed_graph, bool is_checked>\n    struct directed_graph_checker_helper \n    { \n        /*!\n            This object is used to check preconditions based on the value of is_checked\n        !*/\n\n        static void check_parent_edge (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_parents(),\n                         \"\\tnode_type& directed_graph::node_type::parent_edge(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:          \" << edge_index \n                         << \"\\n\\tnumber_of_parents(): \" << self.number_of_parents() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_child_edge (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_children(),\n                         \"\\tnode_type& directed_graph::node_type::child_edge(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:           \" << edge_index \n                         << \"\\n\\tnumber_of_children(): \" << self.number_of_children() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_parent (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_parents(),\n                         \"\\tnode_type& directed_graph::node_type::parent(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:          \" << edge_index \n                         << \"\\n\\tnumber_of_parents(): \" << self.number_of_parents() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_child (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_children(),\n                         \"\\tnode_type& directed_graph::node_type::child(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:           \" << edge_index \n                         << \"\\n\\tnumber_of_children(): \" << self.number_of_children() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_node (\n            unsigned long index,\n            const directed_graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(index < self.number_of_nodes(),\n                         \"\\tnode_type& directed_graph::node(index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tindex:             \" << index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_has_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index,\n            const directed_graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&\n                         child_node_index < self.number_of_nodes(),\n                         \"\\tvoid directed_graph::has_edge(parent_node_index, child_node_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tparent_node_index: \" << parent_node_index \n                         << \"\\n\\tchild_node_index:  \" << child_node_index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_add_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index,\n            const directed_graph& self\n        )\n        {\n            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&\n                         child_node_index < self.number_of_nodes(),\n                         \"\\tvoid directed_graph::add_edge(parent_node_index, child_node_index)\" \n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tparent_node_index: \" << parent_node_index \n                         << \"\\n\\tchild_node_index:  \" << child_node_index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n\n            DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == false,\n                          \"\\tvoid directed_graph::add_edge(parent_node_index, child_node_index)\"\n                          << \"\\n\\tYou can't add an edge if it already exists in the graph\"\n                          << \"\\n\\tparent_node_index: \" << parent_node_index \n                          << \"\\n\\tchild_node_index:  \" << child_node_index \n                          << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                          << \"\\n\\tthis:              \" << &self\n            );\n\n        }\n\n        static void check_remove_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index,\n            const directed_graph& self\n        )\n        {\n            DLIB_CASSERT(parent_node_index < self.number_of_nodes() &&\n                         child_node_index < self.number_of_nodes(),\n                         \"\\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)\" \n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tparent_node_index: \" << parent_node_index \n                         << \"\\n\\tchild_node_index:  \" << child_node_index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n\n            DLIB_CASSERT( self.has_edge(parent_node_index, child_node_index) == true,\n                          \"\\tvoid directed_graph::remove_edge(parent_node_index, child_node_index)\"\n                          << \"\\n\\tYou can't remove an edge if it isn't in the graph\"\n                          << \"\\n\\tparent_node_index: \" << parent_node_index \n                          << \"\\n\\tchild_node_index:  \" << child_node_index \n                          << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                          << \"\\n\\tthis:              \" << &self\n            );\n\n        }\n\n        static void check_remove_node (\n            unsigned long index,\n            const directed_graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(index < self.number_of_nodes(),\n                         \"\\tvoid directed_graph::remove_node(index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tindex:             \" << index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n    };\n\n    template <typename node_type, typename directed_graph>\n    struct directed_graph_checker_helper <node_type, directed_graph, false>\n    { \n        static inline void check_parent ( unsigned long , const node_type&) { }\n        static inline void check_child ( unsigned long , const node_type& ) { }\n        static inline void check_parent_edge ( unsigned long , const node_type&) { }\n        static inline void check_child_edge ( unsigned long , const node_type& ) { }\n        static inline void check_node ( unsigned long , const directed_graph& ) { }\n        static inline void check_has_edge ( unsigned long , unsigned long , const directed_graph& ) { }\n        static inline void check_add_edge ( unsigned long , unsigned long , const directed_graph& ) { }\n        static inline void check_remove_edge ( unsigned long , unsigned long , const directed_graph& ) { }\n        static inline void check_remove_node ( unsigned long , const directed_graph& ) { }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager,\n        bool is_checked = true \n        >\n    class directed_graph_kernel_1 : noncopyable\n    {\n\n        /*!\n            INITIAL VALUE\n                - nodes.size() == 0\n\n            CONVENTION\n                - nodes.size() == number_of_nodes()\n                - for all valid i:\n                    - *nodes[i] == node(i)\n                    - nodes[i]->parents.size() == nodes[i]->number_of_parents(i)\n                    - nodes[i]->children.size() == nodes[i]->number_of_children(i)\n                    - nodes[i]->edge_parents.size() == nodes[i]->number_of_parents(i)\n                    - nodes[i]->edge_children.size() == nodes[i]->number_of_children(i)\n                    - nodes[i]->idx == i == nodes[i]->index()\n                    - for all valid p:\n                        - nodes[i]->parents[p] == pointer to the p'th parent node of i\n                        - *nodes[i]->parents[p] == nodes[i]->parent(p)\n                        - *nodes[i]->edge_parents[p] == nodes[i]->parent_edge(p)\n                    - for all valid c:\n                        - nodes[i]->children[c] == pointer to the c'th child node of i\n                        - *nodes[i]->children[c] == nodes[i]->child(c)\n                        - *nodes[i]->edge_children[c] == nodes[i]->child_edge(c)\n        !*/\n\n    public:\n        struct node_type;\n\n    private:\n        typedef directed_graph_checker_helper<node_type, directed_graph_kernel_1, is_checked> checker;\n\n\n    public:\n\n        typedef T type;\n        typedef E edge_type;\n        typedef mem_manager mem_manager_type;\n\n        template <typename Tr, typename Er, typename MMr>\n        struct rebind {\n            typedef directed_graph_kernel_1<Tr,Er,MMr> other;\n        };\n\n        directed_graph_kernel_1(\n        ) {}\n\n        virtual ~directed_graph_kernel_1(\n        ) {}\n\n        void clear(\n        ) { nodes.clear(); }\n\n        void set_number_of_nodes (\n            unsigned long new_size\n        );\n\n        unsigned long number_of_nodes (\n        ) const { return nodes.size(); }\n\n        node_type& node (\n            unsigned long index\n        ) { checker::check_node(index,*this); return *nodes[index]; }\n\n        const node_type& node (\n            unsigned long index\n        ) const { checker::check_node(index,*this); return *nodes[index]; }\n\n        bool has_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        ) const;\n\n        void add_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        );\n\n        void remove_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        );\n\n        unsigned long add_node (\n        );\n\n        void remove_node (\n            unsigned long index\n        );\n\n        void swap (\n            directed_graph_kernel_1& item\n        ) { nodes.swap(item.nodes); }\n\n    private:\n\n\n    public:\n\n        struct node_type\n        {\n            T data;\n            typedef directed_graph_kernel_1 graph_type;\n\n            unsigned long index(\n            ) const { return idx; }\n\n            unsigned long number_of_parents (\n            ) const { return parents.size(); }\n\n            unsigned long number_of_children (\n            ) const { return children.size(); }\n\n            const node_type& parent (\n                unsigned long edge_index\n            ) const { checker::check_parent(edge_index,*this);  return *parents[edge_index]; }\n\n            node_type& parent (\n                unsigned long edge_index\n            ) { checker::check_parent(edge_index,*this);  return *parents[edge_index]; }\n\n            const node_type& child (\n                unsigned long edge_index\n            ) const { checker::check_child(edge_index,*this);  return *children[edge_index]; }\n\n            node_type& child (\n                unsigned long edge_index\n            ) { checker::check_child(edge_index,*this);  return *children[edge_index]; }\n\n            const E& parent_edge (\n                unsigned long edge_index\n            ) const { checker::check_parent_edge(edge_index,*this);  return *edge_parents[edge_index]; }\n\n            E& parent_edge (\n                unsigned long edge_index\n            ) { checker::check_parent_edge(edge_index,*this);  return *edge_parents[edge_index]; }\n\n            const E& child_edge (\n                unsigned long edge_index\n            ) const { checker::check_child_edge(edge_index,*this);  return *edge_children[edge_index]; }\n\n            E& child_edge (\n                unsigned long edge_index\n            ) { checker::check_child_edge(edge_index,*this);  return *edge_children[edge_index]; }\n\n        private:\n            friend class directed_graph_kernel_1;\n            typedef std_allocator<node_type*,mem_manager> alloc_type;\n            typedef std_allocator<std::shared_ptr<E>,mem_manager> alloc_edge_type;\n            std::vector<node_type*,alloc_type> parents;\n            std::vector<node_type*,alloc_type> children;\n            std::vector<std::shared_ptr<E>,alloc_edge_type> edge_parents;\n            std::vector<std::shared_ptr<E>,alloc_edge_type> edge_children;\n            unsigned long idx;\n        };\n\n    private:\n\n        typedef std_allocator<std::shared_ptr<node_type>,mem_manager> alloc_type;\n        typedef std::vector<std::shared_ptr<node_type>, alloc_type> vector_type;\n        vector_type nodes;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    struct is_directed_graph<directed_graph_kernel_1<T,E,mem_manager, is_checked> >\n    {\n        static const bool value = true; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    inline void swap (\n        directed_graph_kernel_1<T,E,mem_manager,is_checked>& a, \n        directed_graph_kernel_1<T,E,mem_manager,is_checked>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void serialize (\n        const directed_graph_kernel_1<T,E,mem_manager,is_checked>& item,\n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.number_of_nodes(), out);\n\n            // serialize each node\n            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)\n            {\n                serialize(item.node(i).data, out);\n\n                // serialize all the child edges\n                serialize(item.node(i).number_of_children(), out);\n                for (unsigned long c = 0; c < item.node(i).number_of_children(); ++c)\n                {\n                    serialize(item.node(i).child(c).index(), out);\n                    serialize(item.node(i).child_edge(c), out);\n                }\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type directed_graph_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void deserialize (\n        directed_graph_kernel_1<T,E,mem_manager,is_checked>& item,\n        std::istream& in\n    )   \n    {\n        try\n        {\n            unsigned long size;\n            deserialize(size, in);\n\n            item.clear();\n            item.set_number_of_nodes(size);\n\n            // deserialize each node\n            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)\n            {\n                deserialize(item.node(i).data, in);\n\n                unsigned long num_children;\n                deserialize(num_children, in);\n\n                // Add all the edges going to this nodes children nodes\n                for (unsigned long c = 0; c < num_children; ++c)\n                {\n                    unsigned long child_index;\n                    deserialize(child_index, in);\n\n                    item.add_edge(i, child_index);\n\n                    // find the edge we just added\n                    for (unsigned long j = 0; j < item.node(i).number_of_children(); ++j)\n                    {\n                        if (item.node(i).child(j).index() == child_index)\n                        {\n                            deserialize(item.node(i).child_edge(j), in);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type directed_graph_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                             member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    set_number_of_nodes (\n        unsigned long new_size\n    )\n    {\n        try\n        {\n            nodes.resize(new_size);\n            for (unsigned long i = 0; i < nodes.size(); ++i)\n            {\n                nodes[i].reset(new node_type);\n                nodes[i]->idx = i;\n            }\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    bool directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    has_edge (\n        unsigned long parent_node_index,\n        unsigned long child_node_index\n    ) const\n    {\n        checker::check_has_edge(parent_node_index, child_node_index, *this);\n\n        node_type& n = *nodes[parent_node_index];\n\n        // search all the child nodes to see if there is a link to the right node\n        for (unsigned long i = 0; i < n.children.size(); ++i)\n        {\n            if (n.children[i]->idx == child_node_index)\n                return true;\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    add_edge (\n        unsigned long parent_node_index,\n        unsigned long child_node_index\n    )\n    {\n        checker::check_add_edge(parent_node_index, child_node_index, *this);\n        try\n        {\n            node_type& p = *nodes[parent_node_index];\n            node_type& c = *nodes[child_node_index];\n\n            p.children.push_back(&c);\n            c.parents.push_back(&p);\n\n            p.edge_children.push_back(std::shared_ptr<E>(new E));\n            c.edge_parents.push_back(p.edge_children.back());\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    remove_edge (\n        unsigned long parent_node_index,\n        unsigned long child_node_index\n    )\n    {\n        checker::check_remove_edge(parent_node_index, child_node_index, *this);\n\n        node_type& p = *nodes[parent_node_index];\n        node_type& c = *nodes[child_node_index];\n\n        // remove the record of the link from the parent node\n        unsigned long pos = static_cast<unsigned long>(find( p.children.begin(),\n                                  p.children.end(),\n                                  &c) - p.children.begin());\n        p.children.erase(p.children.begin()+pos);\n        p.edge_children.erase(p.edge_children.begin()+pos);\n\n        // remove the record of the link from the child node\n        pos = static_cast<unsigned long>(find( c.parents.begin(),\n                  c.parents.end(),\n                  &p) - c.parents.begin());\n        c.parents.erase(c.parents.begin() + pos);\n        c.edge_parents.erase(c.edge_parents.begin() + pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    unsigned long directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    add_node (\n    )\n    {\n        try\n        {\n            std::shared_ptr<node_type> n(new node_type);\n            n->idx = nodes.size();\n            nodes.push_back(n);\n            return n->idx;\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void directed_graph_kernel_1<T,E,mem_manager,is_checked>::\n    remove_node (\n        unsigned long index\n    )\n    {\n        checker::check_remove_node(index,*this);\n\n        node_type& n = *nodes[index];\n\n        // remove all edges pointing to this node from its parents \n        for (unsigned long i = 0; i < n.parents.size(); ++i)\n        {\n            // remove the edge from this specific parent\n            unsigned long pos = static_cast<unsigned long>(find(n.parents[i]->children.begin(), \n                     n.parents[i]->children.end(), \n                     &n) - n.parents[i]->children.begin());\n\n            n.parents[i]->children.erase(n.parents[i]->children.begin() + pos);\n            n.parents[i]->edge_children.erase(n.parents[i]->edge_children.begin() + pos);\n        }\n\n        // remove all edges pointing to this node from its children \n        for (unsigned long i = 0; i < n.children.size(); ++i)\n        {\n            // remove the edge from this specific child \n            unsigned long pos = static_cast<unsigned long>(find(n.children[i]->parents.begin(),\n                     n.children[i]->parents.end(),\n                     &n) - n.children[i]->parents.begin());\n\n            n.children[i]->parents.erase(n.children[i]->parents.begin() + pos);\n            n.children[i]->edge_parents.erase(n.children[i]->edge_parents.begin() + pos);\n        }\n\n        // now remove this node by replacing it with the last node in the nodes vector\n        nodes[index] = nodes[nodes.size()-1];\n\n        // update the index for the node we just moved\n        nodes[index]->idx = index;\n\n        // now remove the duplicated node at the end of the vector\n        nodes.pop_back();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DIRECTED_GRAPH_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/directed_graph/directed_graph_kernel_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_\n#ifdef DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_\n\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include \"../noncopyable.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager \n        >\n    class directed_graph : noncopyable\n    {\n\n        /*!\n            REQUIREMENTS ON T \n                T must be swappable by a global swap() and\n                T must have a default constructor\n\n            REQUIREMENTS ON E \n                E must be swappable by a global swap() and\n                E must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                The only time pointers or references to nodes or edges become invalid is when\n                they reference nodes or edges that have been removed from a graph.\n\n            INITIAL VALUE\n                number_of_nodes() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a directed graph which is a set of nodes with directed\n                edges connecting various nodes.  \n\n                In this object if there is a directed edge from a node A to a node B then I say \n                that A is the parent of B and B is the child of A.\n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n        !*/\n\n    public:\n\n        typedef T type;\n        typedef E edge_type;\n        typedef mem_manager mem_manager_type;\n\n        template <typename Tr, typename Er, typename MMr>\n        struct rebind {\n            typedef directed_graph<Tr,Er,MMr> other;\n        };\n\n        directed_graph(\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n        !*/\n\n        virtual ~directed_graph(\n        ); \n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then *this is unusable \n                  until clear() is called and succeeds\n        !*/\n\n        void set_number_of_nodes (\n            unsigned long new_size\n        );\n        /*!\n            ensures\n                - #number_of_nodes() == new_size\n                - for all i < new_size:\n                    - number_of_parents(i) == 0\n                    - number_of_children(i) == 0\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in this graph\n        !*/\n\n        struct node_type\n        {\n            T data;\n            typedef directed_graph graph_type;\n\n            unsigned long index(\n            ) const;\n            /*!\n                ensures\n                    - let G be the graph that contains the node *this\n                    - returns a number N such that G.node(N) == *this\n                      (i.e. returns the index of this node in the graph)\n            !*/\n\n            unsigned long number_of_parents (\n            ) const;\n            /*!\n                ensures\n                    - returns the number of parents of this node \n            !*/\n\n            unsigned long number_of_children (\n            ) const;\n            /*!\n                ensures\n                    - returns the number of children of this node \n            !*/\n\n            const node_type& parent (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_parents()\n                ensures\n                    - returns a const reference to the edge_index'th parent of *this\n            !*/\n\n            node_type& parent (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_parents()\n                ensures\n                    - returns a non-const reference to the edge_index'th parent of *this\n            !*/\n\n            const node_type& child (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_children()\n                ensures\n                    - returns a const reference to the edge_index'th child of *this\n            !*/\n\n            node_type& child (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_children()\n                ensures\n                    - returns a non-const reference to the edge_index'th child of *this\n            !*/\n\n            const E& parent_edge (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_parents()\n                ensures\n                    - returns a const reference to the edge_index'th edge data for the\n                      edge connecting to node this->parent(edge_index)\n            !*/\n\n            E& parent_edge (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_parents()\n                ensures\n                    - returns a non-const reference to the edge_index'th edge data for the\n                      edge connecting to node this->parent(edge_index)\n            !*/\n\n            const E& child_edge (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_children()\n                ensures\n                    - returns a const reference to the edge_index'th edge data for the\n                      edge connecting to node this->child(edge_index)\n            !*/\n\n            E& child_edge (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_children()\n                ensures\n                    - returns a non-const reference to the edge_index'th edge data for the\n                      edge connecting to node this->child(edge_index)\n            !*/\n        };\n\n        node_type& node (\n            unsigned long index\n        );\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - returns a non-const reference to the node with the given index\n        !*/\n\n        const node_type& node (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - returns a const reference to the node with the given index\n        !*/\n\n        bool has_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        ) const;\n        /*!\n            requires\n                - parent_node_index < number_of_nodes()\n                - child_node_index < number_of_nodes()\n            ensures\n                - if (there is an edge leading from node(parent_node_index) to\n                  node(child_node_index)) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void add_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        );\n        /*!\n            requires\n                - parent_node_index < number_of_nodes()\n                - child_node_index < number_of_nodes()\n                - has_edge(parent_node_index, child_node_index) == false\n            ensures\n                - #has_edge(parent_node_index, child_node_index) == true \n            throws\n                - std::bad_alloc \n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void remove_edge (\n            unsigned long parent_node_index,\n            unsigned long child_node_index\n        );\n        /*!\n            requires\n                - parent_node_index < number_of_nodes()\n                - child_node_index < number_of_nodes()\n                - has_edge(parent_node_index, child_node_index) == true \n            ensures\n                - #has_edge(parent_node_index, child_node_index) == false \n            throws\n                - std::bad_alloc \n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        unsigned long add_node (\n        );\n        /*!\n            ensures\n                - does not change the index number of existing nodes\n                - adds a node with index N == number_of_nodes() such that:\n                    - #node(N).number_of_parents() == 0 \n                    - #node(N).number_of_children() == 0 \n                    - #number_of_nodes() == number_of_nodes() + 1\n                    - returns N  \n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void remove_node (\n            unsigned long index\n        );\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - removes the node with the given index from the graph. \n                - removes all edges linking the removed node to the rest\n                  of the graph.\n                - the remaining node indexes are remapped so that they remain\n                  contiguous.  (This means that for all valid N, node(N) doesn't\n                  necessarily reference the same node as #node(N))\n                - #number_of_nodes() == number_of_nodes() - 1\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void swap (\n            directed_graph& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };\n\n    template <\n        typename T, \n        typename mem_manager\n        >\n    inline void swap (\n        directed_graph<T,mem_manager>& a, \n        directed_graph<T,mem_manager>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void serialize (\n        const directed_graph<T,mem_manager>& item,\n        std::ostream& out \n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        directed_graph<T,mem_manager>& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n}\n\n#endif // DLIB_DIRECTED_GRAPH_KERNEl_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/directed_graph.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DIRECTED_GRAPh_\n#define DLIB_DIRECTED_GRAPh_\n\n#include \"directed_graph/directed_graph_kernel_1.h\"\n\n#include \"algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager\n        >\n    class directed_graph \n    {\n        directed_graph() {}\n    public:\n                \n\n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     directed_graph_kernel_1<T,E,mem_manager,false>    \n                    kernel_1a;\n        typedef     directed_graph_kernel_1<T,E,mem_manager,true>    \n                    kernel_1a_c;\n \n    };\n}\n\n#endif // DLIB_DIRECTED_GRAPh_ \n\n\n"
  },
  {
    "path": "dlib/disjoint_subsets/disjoint_subsets.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DISJOINT_SUBsETS_Hh_\n#define DLIB_DISJOINT_SUBsETS_Hh_\n\n#include \"disjoint_subsets_abstract.h\"\n#include <vector>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class disjoint_subsets\n    {\n    public:\n\n        void clear (\n        ) noexcept\n        {\n            items.clear();\n        }\n\n        void set_size (\n            unsigned long new_size\n        )\n        {\n            items.resize(new_size);\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                items[i].parent = i;\n                items[i].rank = 0;\n            }\n        }\n\n        size_t size (\n        ) const noexcept\n        {\n            return items.size();\n        }\n\n        unsigned long find_set (\n            unsigned long item\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(item < size(),\n                \"\\t unsigned long disjoint_subsets::find_set()\"\n                << \"\\n\\t item must be less than size()\"\n                << \"\\n\\t item: \" << item\n                << \"\\n\\t size(): \" << size()\n                << \"\\n\\t this: \" << this\n                );\n\n            if (items[item].parent == item)\n            {\n                return item;\n            }\n            else\n            {\n                // find root of item\n                unsigned long x = item;\n                do\n                {\n                    x = items[x].parent;\n                } while (items[x].parent != x);\n\n                // do path compression\n                const unsigned long root = x;\n                x = item;\n                while (items[x].parent != x)\n                {\n                    const unsigned long prev = x;\n                    x = items[x].parent;\n                    items[prev].parent = root;\n                }\n\n                return root;\n            }\n        }\n\n        unsigned long merge_sets (\n            unsigned long a,\n            unsigned long b\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(a != b &&\n                        a < size() &&\n                        b < size() &&\n                        find_set(a) == a &&\n                        find_set(b) == b,\n                \"\\t unsigned long disjoint_subsets::merge_sets(a,b)\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t a: \" << a\n                << \"\\n\\t b: \" << b\n                << \"\\n\\t size(): \" << size()\n                << \"\\n\\t find_set(a): \" << find_set(a)\n                << \"\\n\\t find_set(b): \" << find_set(b)\n                << \"\\n\\t this: \" << this\n                );\n\n            if (items[a].rank > items[b].rank)\n            {\n                items[b].parent = a;\n                return a;\n            }\n            else\n            {\n                items[a].parent = b;\n                if (items[a].rank == items[b].rank)\n                {\n                    items[b].rank = items[b].rank + 1;\n                }\n                return b;\n            }\n        }\n\n    private:\n\n        /*\n            See the book Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein\n            for a discussion of how this algorithm works.\n        */\n\n        struct data\n        {\n            unsigned long rank;\n            unsigned long parent;\n        };\n\n        mutable std::vector<data> items;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DISJOINT_SUBsETS_Hh_\n"
  },
  {
    "path": "dlib/disjoint_subsets/disjoint_subsets_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_\n#ifdef DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class disjoint_subsets\n    {\n        /*!\n            INITIAL VALUE\n                - size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a set of integers which is partitioned into\n                a number of disjoint subsets.  It supports the two fundamental operations\n                of finding which subset a particular integer belongs to as well as\n                merging subsets.\n        !*/\n    public:\n\n        void clear (\n        ) noexcept;\n        /*!\n            ensures\n                - #size() == 0\n                - returns this object to its initial value\n        !*/\n\n        void set_size (\n            unsigned long new_size\n        );\n        /*!\n            ensures\n                - #size() == new_size\n                - for all valid i:\n                    - #find_set(i) == i\n                      (i.e. this object contains new_size subsets, each containing exactly one element)\n        !*/\n\n        size_t size (\n        ) const noexcept;\n        /*!\n            ensures\n                - returns the total number of integer elements represented\n                  by this object.\n        !*/\n\n        unsigned long find_set (\n            unsigned long item\n        ) const;\n        /*!\n            requires\n                - item < size()\n            ensures\n                - Each disjoint subset can be represented by any of its elements (since\n                  the sets are all disjoint).  In particular, for each subset we define\n                  a special \"representative element\" which is used to represent it.\n                  Therefore, this function returns the representative element for the\n                  set which contains item.\n                - find_set(find_set(item)) == find_set(item)\n                - Note that if A and B are both elements of the same subset then we always\n                  have find_set(A) == find_set(B).\n        !*/\n\n        unsigned long merge_sets (\n            unsigned long a,\n            unsigned long b\n        );\n        /*!\n            requires\n                - a != b\n                - a < size()\n                - b < size()\n                - find_set(a) == a\n                  (i.e. a is the representative element of some set)\n                - find_set(b) == b\n                  (i.e. b is the representative element of some set)\n            ensures\n                - #find_set(a) == #find_set(b)\n                  (i.e. merges the set's containing a and b)\n                - returns #find_set(a)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_\n"
  },
  {
    "path": "dlib/disjoint_subsets/disjoint_subsets_sized.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DISJOINT_SUBsETS_SIZED_Hh_\n#define DLIB_DISJOINT_SUBsETS_SIZED_Hh_\n\n#include \"disjoint_subsets_sized_abstract.h\"\n#include \"disjoint_subsets.h\"\n#include <vector>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class disjoint_subsets_sized\n    {\n    public:\n\n        void clear (\n        ) noexcept\n        {\n            disjoint_subsets_.clear();\n            sets_size.clear();\n            number_of_sets = 0;\n        }\n\n        void set_size (\n            unsigned long new_size\n        )\n        {\n            disjoint_subsets_.set_size(new_size);\n            sets_size.assign(new_size, 1);\n            number_of_sets = new_size;\n        }\n\n        size_t size (\n        ) const noexcept\n        {\n            return disjoint_subsets_.size();\n        }\n\n        unsigned long find_set (\n            unsigned long item\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(item < size(),\n                \"\\t unsigned long disjoint_subsets::find_set()\"\n                << \"\\n\\t item must be less than size()\"\n                << \"\\n\\t item: \" << item\n                << \"\\n\\t size(): \" << size()\n                << \"\\n\\t this: \" << this\n                );\n\n            return disjoint_subsets_.find_set(item);\n        }\n\n        unsigned long merge_sets (\n            unsigned long a,\n            unsigned long b\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(a != b &&\n                        a < size() &&\n                        b < size() &&\n                        find_set(a) == a &&\n                        find_set(b) == b,\n                \"\\t unsigned long disjoint_subsets::merge_sets(a,b)\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t a: \" << a\n                << \"\\n\\t b: \" << b\n                << \"\\n\\t size(): \" << size()\n                << \"\\n\\t find_set(a): \" << find_set(a)\n                << \"\\n\\t find_set(b): \" << find_set(b)\n                << \"\\n\\t this: \" << this\n                );\n\n            disjoint_subsets_.merge_sets(a, b);\n\n            if (find_set(a) == a) sets_size[a] += sets_size[b];\n            else sets_size[b] += sets_size[a];\n            --number_of_sets;\n\n            return find_set(a);\n        }\n\n        unsigned long get_number_of_sets (\n        ) const noexcept\n        {\n            return number_of_sets;\n        }\n\n        unsigned long get_size_of_set(\n                unsigned long item\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(item < size() &&\n                        find_set(item) == item,\n                        \"\\t unsigned long disjoint_subsets::get_size_of_set()\"\n                                << \"\\n\\t invalid arguments were given to this function\"\n                                << \"\\n\\t item: \" << item\n                                << \"\\n\\t size(): \" << size()\n                                << \"\\n\\t find_set(item): \" << find_set(item)\n                                << \"\\n\\t this: \" << this\n            );\n\n            return sets_size[item];\n        }\n\n    private:\n\n        /*\n            See the book Introduction to Algorithms by Cormen, Leiserson, Rivest and Stein\n            for a discussion of how this algorithm works.\n        */\n\n        mutable std::vector<unsigned long> sets_size;\n        unsigned long number_of_sets{0};\n        disjoint_subsets disjoint_subsets_;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DISJOINT_SUBsETS_SIZED_Hh_\n"
  },
  {
    "path": "dlib/disjoint_subsets/disjoint_subsets_sized_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DISJOINT_SUBsETS_SIZED_ABSTRACT_Hh_\n#ifdef DLIB_DISJOINT_SUBsETS_SIZED_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class disjoint_subsets_sized \n    {\n        /*!\n            INITIAL VALUE\n                - size() == 0\n                - get_number_of_sets() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a set of integers which is partitioned into\n                a number of disjoint subsets.  It supports the two fundamental operations\n                of finding which subset a particular integer belongs to as well as\n                merging subsets.  It also allows you to find out how big each subset is.  It \n                is therefore essentially the same thing as dlib::disjoint_subsets, except\n                it also keeps track of the size of each subset.\n        !*/\n    public:\n\n        void clear (\n        ) noexcept;\n        /*!\n            ensures\n                - #size() == 0\n                - #get_number_of_sets() == 0\n                - returns this object to its initial value\n        !*/\n\n        void set_size (\n            unsigned long new_size\n        );\n        /*!\n            ensures\n                - #size() == new_size\n                - #get_number_of_sets() == new_size\n                - for all valid i:\n                    - #find_set(i) == i\n                      (i.e. this object contains new_size subsets, each containing exactly one element)\n                    - #get_size_of_set(i) == 1\n        !*/\n\n        size_t size (\n        ) const noexcept;\n        /*!\n            ensures\n                - returns the total number of integer elements represented\n                  by this object.\n        !*/\n\n        unsigned long find_set (\n            unsigned long item\n        ) const;\n        /*!\n            requires\n                - item < size()\n            ensures\n                - Each disjoint subset can be represented by any of its elements (since\n                  the sets are all disjoint).  In particular, for each subset we define\n                  a special \"representative element\" which is used to represent it.\n                  Therefore, this function returns the representative element for the\n                  set which contains item.\n                - find_set(find_set(item)) == find_set(item)\n                - Note that if A and B are both elements of the same subset then we always\n                  have find_set(A) == find_set(B).\n        !*/\n\n        unsigned long merge_sets (\n            unsigned long a,\n            unsigned long b\n        );\n        /*!\n            requires\n                - a != b\n                - a < size()\n                - b < size()\n                - find_set(a) == a\n                  (i.e. a is the representative element of some set)\n                - find_set(b) == b\n                  (i.e. b is the representative element of some set)\n            ensures\n                - #find_set(a) == #find_set(b)\n                  (i.e. merges the set's containing a and b)\n                - #get_size_of_set(#find_set(a)) == get_size_of_set(a) + get_size_of_set(b)\n                - #get_number_of_sets() == get_number_of_sets() - 1\n                - returns #find_set(a)\n        !*/\n\n        unsigned long get_number_of_sets (\n        ) const noexcept;\n        /*!\n            ensures\n                - returns the current number of different subsets.\n        !*/\n\n        unsigned long get_size_of_set(\n                unsigned long item\n        ) const;\n        /*!\n            requires\n                - item < size()\n                - find_set(item) == item\n                  (i.e. item is the representative element of some set)\n            ensures\n                - returns the number of elements which belongs to the set where item is the representative element.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DISJOINT_SUBsETS_ABSTRACT_Hh_\n"
  },
  {
    "path": "dlib/disjoint_subsets.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DISJOINt_SUBSETS_\n#define DLIB_DISJOINt_SUBSETS_\n\n\n#include \"disjoint_subsets/disjoint_subsets.h\"\n#include \"disjoint_subsets/disjoint_subsets_sized.h\"\n\n#endif // DLIB_DISJOINt_SUBSETS_\n\n\n"
  },
  {
    "path": "dlib/dlib_basic_cpp_build_tutorial.txt",
    "content": "#error \"Don't write #include <dlib/all/source.cpp> in your code.\"\n/*\n  In C++, it is generally an error to #include .cpp files.  This is because it\n  can lead to what are called multiply defined symbol errors.  Therefore, you\n  should compile dlib/all/source.cpp into your application just like you would\n  compile any other .cpp file.  \n  \n  If you are using Visual Studio you add .cpp files to your application using\n  the solution explorer window.  Specifically, right click on Source Files,\n  then select Add -> Existing Item and select the .cpp files you want to add.\n\n  For general information on compiling dlib see http://dlib.net/compile.html\n*/\n"
  },
  {
    "path": "dlib/dlib_include_path_tutorial.txt",
    "content": "#error \"Don't put the dlib folder in your include path\"\n/*\n  You are getting this error because you have added the dlib folder to your\n  compiler's include search path.  \n\n  You should *NOT* add the dlib folder itself to your compiler's include path. \n  Doing so will cause the build to fail because of name collisions (such as \n  dlib/string.h and string.h from the standard library). Instead you should \n  add the folder that contains the dlib folder to your include search path \n  and then use include statements of the form #include <dlib/queue.h> or\n  #include \"dlib/queue.h\".  This will ensure that everything builds correctly.\n\n  XCode:\n  \tThe XCode IDE often puts all folders that it knows about into \n\tthe compiler search path.  So if you are using XCode then either \n\tdon't drag the whole dlib folder into the project or alternatively \n\tmodify your XCode project settings to not auto-add all folders to \n\tthe include path.  Instead just make sure that the dlib folder is \n\titself inside a folder in your include path.  \n*/\n"
  },
  {
    "path": "dlib/dnn/core.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_CORE_H_\n#define DLIB_DNn_CORE_H_\n\n#include <iterator>\n#include <memory>\n#include <sstream>\n#include <utility>\n#include <tuple>\n#include <cmath>\n#include <vector>\n#include <type_traits>\n\n#include \"core_abstract.h\"\n#include \"../cuda/tensor.h\"\n#include \"../cuda/tensor_tools.h\"\n#include \"../statistics.h\"\n#include \"../rand.h\"\n#include \"../algs.h\"\n#include \"../metaprogramming.h\"\n#include \"../utility.h\"\n#include \"../constexpr_if.h\"\n\n#ifdef _MSC_VER\n// Tell Visual Studio not to recursively inline functions very much because otherwise it\n// takes hours to compile the DNN code sometimes.  It's crazy.  Hopefully we can remove\n// this some day when the visual studio compiler is more efficient.\n#pragma inline_depth(2)\n#endif\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template<typename T>\n        using has_get_learning_rate_multiplier = decltype(std::declval<T>().get_learning_rate_multiplier());\n    \n        template<typename T>\n        using has_set_learning_rate_multiplier = decltype(std::declval<T>().set_learning_rate_multiplier(double{}));\n\n        template<typename T>\n        using has_get_bias_learning_rate_multiplier = decltype(std::declval<T>().get_bias_learning_rate_multiplier());\n\n        template<typename T>\n        using has_set_bias_learning_rate_multiplier = decltype(std::declval<T>().set_bias_learning_rate_multiplier(double{}));\n    \n        template<typename T>\n        using has_get_weight_decay_multiplier = decltype(std::declval<T>().get_weight_decay_multiplier());\n\n        template<typename T>\n        using has_set_weight_decay_multiplier = decltype(std::declval<T>().set_weight_decay_multiplier(double{}));\n\n        template<typename T>\n        using has_get_bias_weight_decay_multiplier = decltype(std::declval<T>().get_bias_weight_decay_multiplier());\n\n        template<typename T>\n        using has_set_bias_weight_decay_multiplier = decltype(std::declval<T>().set_bias_weight_decay_multiplier(double{}));\n\n        template<typename T>\n        using has_disable_bias = decltype(std::declval<T>().disable_bias());\n\n        template<typename T>\n        using has_clean = decltype(std::declval<T>().clean());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_learning_rate_multiplier(const T& obj) \n    { \n        return switch_(bools(is_detected<impl::has_get_learning_rate_multiplier, T>{}),\n            [&](true_t, auto _) { return _(obj).get_learning_rate_multiplier(); },\n            [](auto...)         { return 1.0; }\n        );\n    }\n\n    template <typename T>\n    void set_learning_rate_multiplier(\n        T& obj,\n        double learning_rate_multiplier\n    )\n    {\n        DLIB_CASSERT(learning_rate_multiplier >= 0);\n        switch_(bools(is_detected<impl::has_set_learning_rate_multiplier, T>{}),\n            [&](true_t, auto _) { _(obj).set_learning_rate_multiplier(learning_rate_multiplier); },\n            [](auto...)         {/*no-op*/}\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_bias_learning_rate_multiplier(const T& obj) \n    {\n        return switch_(bools(is_detected<impl::has_get_bias_learning_rate_multiplier, T>{}),\n            [&](true_t, auto _) { return _(obj).get_bias_learning_rate_multiplier(); },\n            [](auto...)         { return 1.0; }\n        );\n    }\n\n    template <typename T>\n    void set_bias_learning_rate_multiplier(\n        T& obj,\n        double bias_learning_rate_multiplier\n    )\n    {\n        DLIB_CASSERT(bias_learning_rate_multiplier >= 0);\n        switch_(bools(is_detected<impl::has_set_bias_learning_rate_multiplier, T>{}),\n            [&](true_t, auto _) { _(obj).set_bias_learning_rate_multiplier(bias_learning_rate_multiplier); },\n            [](auto...)         {/*no-op*/}\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_weight_decay_multiplier(const T& obj) \n    { \n        return switch_(bools(is_detected<impl::has_get_weight_decay_multiplier, T>{}),\n            [&](true_t, auto _) { return _(obj).get_weight_decay_multiplier(); },\n            [](auto...)         { return 1.0; }\n        );\n    }\n\n    template <typename T>\n    void set_weight_decay_multiplier(\n        T& obj,\n        double weight_decay_multiplier\n    )\n    {\n        DLIB_CASSERT(weight_decay_multiplier >= 0);\n        switch_(bools(is_detected<impl::has_set_weight_decay_multiplier, T>{}),\n            [&](true_t, auto _) { _(obj).set_weight_decay_multiplier(weight_decay_multiplier); },\n            [](auto...)         {/*no-op*/}\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_bias_weight_decay_multiplier(const T& obj)\n    { \n        return switch_(bools(is_detected<impl::has_get_bias_weight_decay_multiplier, T>{}),\n            [&](true_t, auto _) { return _(obj).get_bias_weight_decay_multiplier(); },\n            [](auto...)         { return 1.0; }\n        );\n    }\n\n    template <typename T>\n    void set_bias_weight_decay_multiplier(\n        T& obj,\n        double bias_weight_decay_multiplier\n    )\n    {\n        DLIB_CASSERT(bias_weight_decay_multiplier >= 0);\n        switch_(bools(is_detected<impl::has_set_bias_weight_decay_multiplier, T>{}),\n            [&](true_t, auto _) { _(obj).set_bias_weight_decay_multiplier(bias_weight_decay_multiplier); },\n            [](auto...)         {/*no-op*/}\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void disable_bias(\n        T& obj\n    )\n    {\n        switch_(bools(is_detected<impl::has_disable_bias, T>{}),\n            [&](true_t, auto _) { _(obj).disable_bias(); },\n            [](auto...)         { /*no-op*/ }\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void call_clean_method_if_exists(T& obj) \n    /*!\n        ensures\n            - calls obj.clean() if obj has a .clean() method.\n    !*/\n    { \n        switch_(bools(is_detected<impl::has_clean, T>{}),\n            [&](true_t, auto _) { _(obj).clean(); },\n            [](auto...)         { /*no-op*/ }\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class repeat_input_layer \n        {\n            /*!\n                None of the declarations in this object are really used. The only reason it\n                exists is to allow the repeat object to use a special input layer in its\n                internal networks which will cause add_tag_layer objects that happen to be\n                right at the input to not create copies of their input tensors.  So\n                introducing the repeat_input_layer object allows us to optimize the\n                implementation of add_tag_layer for a special case that arises when it's\n                used in the context of the repeat layer.\n            !*/\n        public:\n            typedef int input_type;\n\n            template <typename forward_iterator>\n            void to_tensor (\n                forward_iterator ,\n                forward_iterator ,\n                resizable_tensor& \n            ) const\n            {\n            }\n\n            friend void serialize(const repeat_input_layer&, std::ostream&){}\n            friend void deserialize(repeat_input_layer&, std::istream&){}\n            friend std::ostream& operator<<(std::ostream& out, const repeat_input_layer&) { return out; }\n        };\n\n        inline std::string tensor_to_str (\n            const tensor& t,\n            int& min_length \n        ) \n        {\n            if (t.size() == 0)\n                return \"\";\n\n            std::ostringstream sout;\n            sout << \"output size=(num:\"<<  t.num_samples() << \", \";\n            sout << \"k:\" << t.k() << \",\";\n            while (sout.tellp() < 28) sout << \" \";\n            sout << \"nr:\" << t.nr() << \",\";\n            while (sout.tellp() < 28+8) sout << \" \";\n            sout << \"nc:\" << t.nc() << \")\";\n            while (sout.tellp() < min_length) sout << \" \";\n            min_length = sout.tellp();\n            sout << \"\\t\";\n            return sout.str();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    // Tell us if T is one of the special layer types (i.e. add_layer, repeat, add_tag_layer, or\n    // add_skip_layer).\n    template <typename T> struct is_nonloss_layer_type : std::false_type {};\n    // Tell us if T is an instance of add_loss_layer.\n    template <typename T> struct is_loss_layer_type : std::false_type {};\n    // Tell us if T is an instance of add_layer\n    template <typename T> struct is_add_layer : std::false_type {};\n\n    namespace impl\n    {\n        template <typename Tuple, size_t... indices>\n        auto tuple_subset(\n            const Tuple& item, \n            std::index_sequence<indices...>\n        )\n        {\n            return std::make_tuple(std::get<indices>(item)...);\n        }\n\n        template <typename ...Types>\n        auto basic_tuple_tail(\n            const std::tuple<Types...>& item\n        )\n        {\n            return tuple_subset(item, pop_front_t<index_sequence_for<Types...>>{});\n        }\n\n        template <typename T>\n        auto tuple_flatten(const T& t) \n        {\n            return std::make_tuple(t);\n        }\n\n        template <size_t... I, typename... T>\n        auto tuple_flatten(\n            const std::tuple<T...>& item, \n            std::index_sequence<I...>\n        )\n        {\n            return std::tuple_cat(tuple_flatten(std::get<I>(item))...);\n        }\n\n        template <typename... T>\n        auto tuple_flatten(const std::tuple<T...>& item)\n        {\n            return tuple_flatten(item, std::index_sequence_for<T...>{});\n        }\n\n        template <typename T>\n        struct tuple_head_helper\n        {\n            typedef T type;\n            static const type& get(const T& item) \n            {\n                return item;\n            }\n        };\n\n        template <typename T, typename... U>\n        struct tuple_head_helper<std::tuple<T, U...>>\n        {\n            typedef typename tuple_head_helper<T>::type type;\n            static const type& get(const std::tuple<T,U...>& item) \n            {\n                return tuple_head_helper<T>::get(std::get<0>(item));\n            }\n        };\n\n        template <typename T> struct alwaysbool { typedef bool type; };\n        // one more structure for VS 2015 UP3 support workaround\n        template <typename T> struct alwaysbool2 { typedef bool type; };\n\n        resizable_tensor& rt();\n\n        // The significance of a layer's backward method requiring forward's outputs is\n        // that such as layer can't have an in-place layer stacked on top of it because\n        // in-place layers overwrite the output of the layer they sit on top of.\n        template <typename layer_type, typename SUBNET>\n        constexpr auto backward_requires_forward_output(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool<decltype(layer.backward(rt(),rt(),sub,rt()))>::type\n        {\n            return true;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto backward_requires_forward_output(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool<decltype(layer.backward(rt(),sub,rt()))>::type\n        {\n            return false;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto backward_requires_forward_output(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool<decltype(layer.backward_inplace(rt(),rt(),sub.get_gradient_input(),rt()))>::type\n        {\n            return true;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto backward_requires_forward_output(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool<decltype(layer.backward_inplace(rt(),sub.get_gradient_input(),rt()))>::type\n        {\n            return false;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto has_inplace_backward(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool2<decltype(layer.backward(rt(),rt(),sub,rt()))>::type\n        {\n            return false;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto has_inplace_backward(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool2<decltype(layer.backward(rt(),sub,rt()))>::type\n        {\n            return false;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto has_inplace_backward(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool2<decltype(layer.backward_inplace(rt(),rt(),sub.get_gradient_input(),rt()))>::type\n        {\n            return true;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto has_inplace_backward(\n            layer_type& layer,\n            SUBNET& sub\n        ) -> typename alwaysbool2<decltype(layer.backward_inplace(rt(),sub.get_gradient_input(),rt()))>::type\n        {\n            return true;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto is_inplace_layer(\n            layer_type& layer,\n            const SUBNET& sub \n        ) -> typename alwaysbool2<decltype(layer.forward(sub,rt()))>::type\n        {\n            return false;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        constexpr auto is_inplace_layer(\n            layer_type& layer,\n            const SUBNET& sub\n        ) -> typename alwaysbool<decltype(layer.forward_inplace(sub.get_output(),rt()))>::type\n        {\n            return true;\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_backward(\n            layer_type& layer,\n            const tensor& computed_output, \n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        ) -> decltype(layer.backward(computed_output,gradient_input,sub,params_grad))\n        {\n            layer.backward(computed_output,gradient_input,sub,params_grad);\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_backward(\n            layer_type& layer,\n            const tensor& , \n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        ) -> decltype(layer.backward(gradient_input,sub,params_grad))\n        {\n            layer.backward(gradient_input,sub,params_grad);\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_backward(\n            layer_type& layer,\n            const tensor& computed_output, \n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        ) -> decltype(layer.backward_inplace(computed_output,gradient_input,sub.get_gradient_input(),params_grad))\n        {\n            layer.backward_inplace(computed_output,gradient_input,sub.get_gradient_input(),params_grad);\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_backward(\n            layer_type& layer,\n            const tensor& , \n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        ) -> decltype(layer.backward_inplace(gradient_input,sub.get_gradient_input(),params_grad))\n        {\n            layer.backward_inplace(gradient_input,sub.get_gradient_input(),params_grad);\n        }\n\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_forward(\n            layer_type& layer,\n            const SUBNET& sub, \n            tensor& /*data_output*/\n        ) -> decltype(layer.forward(sub,rt()))\n        {\n            // This overload of call_layer_forward() is here because this template\n            // naturally gets instantiated but only on code paths that never get executed.\n            // So rather than writing a bunch of hard to read template magic around call\n            // sites we just have this overload that doesn't do anything (and an assert to\n            // make sure that's the case).\n            DLIB_CASSERT(false, \"This should never happen\");\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_forward(\n            layer_type& layer,\n            const SUBNET& sub, \n            resizable_tensor& data_output\n        ) -> decltype(layer.forward(sub,data_output))\n        {\n            layer.forward(sub,data_output);\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_forward(\n            layer_type& layer,\n            const SUBNET& sub, \n            tensor& data_output\n        ) -> decltype(layer.forward_inplace(sub.get_output(),data_output))\n        {\n            layer.forward_inplace(sub.get_output(),data_output);\n        }\n\n        template <typename layer_type, typename SUBNET>\n        auto call_layer_forward(\n            layer_type& layer,\n            const SUBNET& sub, \n            resizable_tensor& data_output\n        ) -> decltype(layer.forward_inplace(sub.get_output(),data_output))\n        {\n            if (!have_same_dimensions(data_output, sub.get_output()))\n                data_output.copy_size(sub.get_output());\n            layer.forward_inplace(sub.get_output(),static_cast<tensor&>(data_output));\n        }\n\n\n    } // end namespace impl\n\n    template <typename... T>\n    auto tuple_head (\n        const std::tuple<T...>& item\n    ) \n    {\n        return impl::tuple_head_helper<std::tuple<T...>>::get(item);\n    }\n\n    template <typename... T>\n    auto tuple_tail(\n        const std::tuple<T...>& item\n    )\n    {\n        return impl::basic_tuple_tail(impl::tuple_flatten(item));\n    }\n\n    inline std::tuple<> tuple_tail(\n        const std::tuple<>& item\n    ) \n    {\n        return item;\n    }\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class sstack\n    {\n    public:\n        typedef T value_type;\n\n        sstack() = delete;\n\n        sstack (\n            T* data_,\n            size_t s\n        ) : data(data_), mysize(s) {}\n\n        const T& top() const \n        { \n            DLIB_CASSERT(size() != 0, \"You can't call top() on an empty stack\");\n            return *data;\n        }\n        T& top()  \n        { \n            DLIB_CASSERT(size() != 0, \"You can't call top() on an empty stack\");\n            return *data;\n        }\n\n        size_t size() const { return mysize; }\n\n        sstack pop(size_t num=1) \n        { \n            DLIB_CASSERT(num <= size(), \"You can't pop more things from the stack than it has in it.\");\n            return sstack(data+num, mysize-num);\n        }\n\n    private:\n\n        T* data;\n        size_t mysize;\n    };\n\n    template <typename T>\n    sstack<T> make_sstack(std::vector<T>& item)\n    {\n        return sstack<T>(item.data(), item.size());\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace dimpl\n    {\n        template <typename T, bool is_first = true, typename enabled=void>\n        class subnet_wrapper\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a tool that makes an add_layer or add_loss_layer object\n                    expose only the part of its interface defined by the SUBNET\n                    type in layers_abstract.h.  This way, when we pass subnetwork\n                    objects to the layer callbacks those callbacks won't be able to \n                    interact with the subnetworks in a way other than specified \n                    by the SUBNET interface spec.\n\n                    We also allow the top layer of a subnet_wrapper stack to call the\n                    private_get_output() and private_get_gradient_input() functions.  This\n                    way, layers that have had their output/gradient overwritten by in-place\n                    layers can only be accessed from the in-place layers that sit directly\n                    on top of them since those in-place layers are the only layers that\n                    know how to interact with them properly.\n            !*/\n\n        public:\n            subnet_wrapper(const subnet_wrapper&) = delete;\n            subnet_wrapper& operator=(const subnet_wrapper&) = delete;\n\n            subnet_wrapper(T& l_, unsigned int sef) : l(l_),_sample_expansion_factor(sef) {}\n            // Not much here because in this case T is one of the input layer types \n            // that doesn't have anything in it.\n            typedef T layer_details_type;\n            typedef T input_layer_type;\n            const layer_details_type& layer_details() const { return l; }\n            const input_layer_type& input_layer() const { return l; }\n            input_layer_type& input_layer() { return l; }\n            unsigned int sample_expansion_factor() const { return _sample_expansion_factor; }\n        private:\n            T& l;\n            unsigned int _sample_expansion_factor;\n        };\n\n        template <typename T>\n        class subnet_wrapper<T,true, typename std::enable_if<is_nonloss_layer_type<T>::value>::type>\n        {\n\n        public:\n            subnet_wrapper(const subnet_wrapper&) = delete;\n            subnet_wrapper& operator=(const subnet_wrapper&) = delete;\n\n            typedef T wrapped_type;\n            const static size_t num_computational_layers = T::num_computational_layers;\n            const static size_t num_layers = T::num_layers;\n            typedef typename T::layer_details_type layer_details_type;\n            typedef typename T::input_layer_type input_layer_type;\n\n            subnet_wrapper(T& l_, unsigned int = 0) : l(l_),subnetwork(l.subnet(), l.sample_expansion_factor()) {}\n\n            const tensor& get_output() const { return l.private_get_output(); }\n            tensor& get_gradient_input() { return l.private_get_gradient_input(); }\n\n            const layer_details_type& layer_details() const { return l.layer_details(); }\n\n            const subnet_wrapper<typename T::subnet_type,false>& subnet() const { return subnetwork; }\n            subnet_wrapper<typename T::subnet_type,false>& subnet() { return subnetwork; }\n            unsigned int sample_expansion_factor() const { return l.sample_expansion_factor(); }\n\n            const input_layer_type& input_layer() const { return l.input_layer(); }\n            input_layer_type& input_layer() { return l.input_layer(); }\n\n        private:\n            T& l;\n            subnet_wrapper<typename T::subnet_type,false> subnetwork;\n        };\n\n        template <typename T>\n        class subnet_wrapper<T,false, typename std::enable_if<is_nonloss_layer_type<T>::value>::type>\n        {\n\n        public:\n            subnet_wrapper(const subnet_wrapper&) = delete;\n            subnet_wrapper& operator=(const subnet_wrapper&) = delete;\n\n            typedef T wrapped_type;\n            const static size_t num_computational_layers = T::num_computational_layers;\n            const static size_t num_layers = T::num_layers;\n            typedef typename T::layer_details_type layer_details_type;\n            typedef typename T::input_layer_type input_layer_type;\n\n            subnet_wrapper(T& l_, unsigned int = 0) : l(l_),subnetwork(l.subnet(), l.sample_expansion_factor()) {}\n\n            const tensor& get_output() const { return l.get_output(); }\n            tensor& get_gradient_input() { return l.get_gradient_input(); }\n\n            const layer_details_type& layer_details() const { return l.layer_details(); }\n\n            const subnet_wrapper<typename T::subnet_type,false>& subnet() const { return subnetwork; }\n            subnet_wrapper<typename T::subnet_type,false>& subnet() { return subnetwork; }\n            unsigned int sample_expansion_factor() const { return l.sample_expansion_factor(); }\n\n            const input_layer_type& input_layer() const { return l.input_layer(); }\n            input_layer_type& input_layer() { return l.input_layer(); }\n\n        private:\n            T& l;\n            subnet_wrapper<typename T::subnet_type,false> subnetwork;\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    enum class zero_gradients : uint8_t\n    {\n        no = 0,\n        yes = 1\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename LAYER_DETAILS, typename SUBNET, typename enabled = void>\n    class add_layer;\n\n    template <typename LAYER_DETAILS, typename SUBNET, typename enabled>\n    void serialize(const add_layer<LAYER_DETAILS,SUBNET,enabled>& item, std::ostream& out);\n    template <typename LAYER_DETAILS, typename SUBNET, typename enabled>\n    void deserialize(add_layer<LAYER_DETAILS,SUBNET,enabled>& item, std::istream& in);\n\n    template <typename T, typename U>\n    struct is_nonloss_layer_type<add_layer<T,U>> : std::true_type {};\n\n    template <typename LAYER_DETAILS, typename SUBNET>\n    class add_layer<LAYER_DETAILS,SUBNET,\n            typename std::enable_if<is_nonloss_layer_type<SUBNET>::value>::type>\n    {\n    public:\n        typedef LAYER_DETAILS layer_details_type;\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        typedef typename subnet_type::input_type input_type;\n        const static size_t num_layers = subnet_type::num_layers + 1;\n        const static size_t num_computational_layers = subnet_type::num_computational_layers + 1;\n\n        add_layer(\n        ):\n            subnetwork(new subnet_type()),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        add_layer(const add_layer& item)\n        {\n            details = item.details;\n            subnetwork.reset(new subnet_type(*item.subnetwork));\n            this_layer_setup_called = item.this_layer_setup_called;\n            gradient_input_is_stale = item.gradient_input_is_stale;\n            get_output_and_gradient_input_disabled = item.get_output_and_gradient_input_disabled;\n            x_grad = item.x_grad;\n            cached_output = item.cached_output; \n            params_grad = item.params_grad; \n            temp_tensor = item.temp_tensor;\n        }\n        add_layer& operator=(const add_layer& item) { add_layer(item).swap(*this); return *this;}\n        add_layer(add_layer&& item) : add_layer() { swap(item); }\n        add_layer& operator=(add_layer&& item) { swap(item); return *this; }\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        // Allow copying networks from one to another as long as their corresponding \n        // layers can be constructed from each other.\n        template <typename T, typename U, typename E>\n        add_layer(\n            const add_layer<T,U,E>& item\n        ) :\n            details(item.layer_details()), \n            subnetwork(new subnet_type(item.subnet())),\n            this_layer_setup_called(item.this_layer_setup_called),\n            gradient_input_is_stale(item.gradient_input_is_stale),\n            get_output_and_gradient_input_disabled(item.get_output_and_gradient_input_disabled),\n            x_grad(item.x_grad),\n            cached_output(item.cached_output)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        template <typename ...T>\n        add_layer(\n            const LAYER_DETAILS& layer_det, \n            T&& ...args\n        ) : \n            details(layer_det), \n            subnetwork(new subnet_type(std::forward<T>(args)...)),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        template <typename T, typename ...U>\n        struct disable_forwarding_constr \n        {\n            const static bool value = std::is_constructible<LAYER_DETAILS,T>::value;\n        };\n        template <typename ...T, typename ...U>\n        struct disable_forwarding_constr<std::tuple<T...>,U...>\n        {\n            const static bool value = disable_forwarding_constr<typename std::remove_reference<T>::type...>::value;\n        };\n        template <typename T, typename ...U>\n        struct disable_forwarding_constr<std::tuple<T>,U...>\n        {\n            const static bool value = disable_forwarding_constr<typename std::remove_reference<T>::type>::value;\n        };\n        template <typename ...U>\n        struct disable_forwarding_constr<std::tuple<>,U...>\n        {\n            const static bool value = true;\n        };\n        template <typename ...T>\n        struct disable_forwarding_constr<add_layer<T...>>\n        {\n            const static bool value = true;\n        };\n\n        template <\n            typename ...T,\n            typename = typename std::enable_if<!disable_forwarding_constr<typename std::remove_reference<T>::type...>::value>::type\n            >\n        add_layer(\n            T&& ...args\n        ) : \n            subnetwork(new subnet_type(std::forward<T>(args)...)),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        template <typename ...T>\n        add_layer(\n            LAYER_DETAILS&& layer_det, \n            T&& ...args\n        ) : \n            details(std::move(layer_det)), \n            subnetwork(new subnet_type(std::forward<T>(args)...)),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        template <typename ...T, typename LD, typename ...U>\n        add_layer(\n            const std::tuple<LD,U...>& layer_det, \n            T&& ...args\n        ) : \n            details(tuple_head(layer_det)), \n            subnetwork(new subnet_type(tuple_tail(layer_det),std::forward<T>(args)...)),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false)\n        {\n            if (this_layer_operates_inplace())\n                subnetwork->disable_output_and_gradient_getters();\n        }\n\n        template <typename ...T, typename LD, typename ...U>\n        add_layer(\n            std::tuple<>,\n            const std::tuple<LD,U...>& layer_det, \n            T&& ...args\n        ) : add_layer(layer_det,args...) { }\n\n        add_layer (\n            std::tuple<>\n        ) : add_layer() {}\n\n        template <typename ...T>\n        add_layer(\n            std::tuple<>, \n            LAYER_DETAILS&& layer_det, \n            T&& ...args\n        ) : add_layer(layer_det, args...) { }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            subnetwork->to_tensor(ibegin,iend,data);\n        }\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return forward(temp_tensor);\n        }\n\n\n        const tensor& operator() (const input_type& x)\n        {\n            return (*this)(&x, &x+1);\n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            subnetwork->forward(x);\n            const dimpl::subnet_wrapper<subnet_type> wsub(*subnetwork);\n            if (!this_layer_setup_called)\n            {\n                details.setup(wsub);\n                this_layer_setup_called = true;\n            }\n            if (this_layer_operates_inplace())\n                impl::call_layer_forward(details, wsub, private_get_output());\n            else\n                impl::call_layer_forward(details, wsub, cached_output);\n\n            gradient_input_is_stale = true;\n            return private_get_output();\n        }\n\n    private:\n        tensor& private_get_output() const\n        { \n            if (const_cast<add_layer&>(*this).this_layer_operates_inplace())\n                return subnetwork->private_get_output();\n            else\n                return const_cast<resizable_tensor&>(cached_output); \n        }\n        tensor& private_get_gradient_input() \n        { \n            if (this_layer_operates_inplace())\n            {\n                return subnetwork->private_get_gradient_input();\n            }\n            else\n            {\n                if (gradient_input_is_stale)\n                {\n                    gradient_input_is_stale = false;\n                    x_grad.copy_size(private_get_output());\n                    x_grad = 0;\n                }\n                return x_grad; \n            }\n        }\n        void disable_output_and_gradient_getters (\n        ) { get_output_and_gradient_input_disabled = true; }\n    public:\n        const tensor& get_output() const \n        { \n            if (get_output_and_gradient_input_disabled)\n                throw dlib::error(\"Accessing this layer's get_output() is disabled because an in-place layer has been stacked on top of it.\");\n            return private_get_output(); \n        }\n        tensor& get_gradient_input() \n        { \n            if (get_output_and_gradient_input_disabled)\n                throw dlib::error(\"Accessing this layer's get_gradient_input() is disabled because an in-place layer has been stacked on top of it.\");\n            return private_get_gradient_input();\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const { return subnetwork->get_final_data_gradient(); }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            back_propagate_error(x, private_get_gradient_input(), zero_grads);\n        }\n        void back_propagate_error(\n            const tensor& x,\n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            dimpl::subnet_wrapper<subnet_type> wsub(*subnetwork);\n            params_grad.copy_size(details.get_layer_params());\n            impl::call_layer_backward(details, private_get_output(),\n                gradient_input, wsub, static_cast<tensor&>(params_grad));\n\n            subnetwork->back_propagate_error(x, zero_grads); \n\n            // zero out get_gradient_input()\n            gradient_input_is_stale = zero_grads == zero_gradients::yes;\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> solvers, double learning_rate)\n        {\n            DLIB_CASSERT(solvers.size()>=num_computational_layers);\n            // Don't try to adjust the parameters if this layer doesn't have any or the\n            // learning rate is disabled for this layer.\n            if (params_grad.size() != 0 && get_learning_rate_multiplier(details) != 0)\n            {\n                const tensor& step = solvers.top()(learning_rate, details, static_cast<const tensor&>(params_grad));\n                tt::add(details.get_layer_params(), details.get_layer_params(), step);\n            }\n            subnetwork->update_parameters(solvers.pop(), learning_rate);\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const tensor& get_parameter_gradient(\n        ) const { return params_grad; }\n\n        tensor& get_parameter_gradient (\n        ) { return params_grad; }\n\n        const subnet_type& subnet() const { return *subnetwork; }\n        subnet_type& subnet() { return *subnetwork; }\n\n        const input_layer_type& input_layer() const { return subnet().input_layer(); } \n        input_layer_type& input_layer() { return subnet().input_layer(); } \n\n        const layer_details_type& layer_details() const { return details; } \n        layer_details_type& layer_details() { return details; } \n\n        unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); }\n\n        void set_gradient_inputs_to_zero()\n        {\n            gradient_input_is_stale = true;\n            subnetwork->set_gradient_inputs_to_zero();\n        }\n\n        void clean()\n        {\n            x_grad.clear();\n            cached_output.clear();\n            params_grad.clear();\n            temp_tensor.clear();\n            gradient_input_is_stale = true;\n            subnetwork->clean();\n            call_clean_method_if_exists(details);\n        }\n\n        friend void serialize(const add_layer& item, std::ostream& out)\n        {\n            int version = 2;\n            serialize(version, out);\n            serialize(*item.subnetwork, out);\n            serialize(item.details, out);\n            serialize(item.this_layer_setup_called, out);\n            serialize(item.gradient_input_is_stale, out);\n            serialize(item.get_output_and_gradient_input_disabled, out);\n            serialize(item.x_grad, out);\n            serialize(item.cached_output, out);\n            serialize(item.params_grad, out);\n        }\n\n        friend void deserialize(add_layer& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (!(1 <= version && version <= 2))\n                throw serialization_error(\"Unexpected version found while deserializing dlib::add_layer.\");\n            deserialize(*item.subnetwork, in);\n            deserialize(item.details, in);\n            deserialize(item.this_layer_setup_called, in);\n            deserialize(item.gradient_input_is_stale, in);\n            deserialize(item.get_output_and_gradient_input_disabled, in);\n            deserialize(item.x_grad, in);\n            deserialize(item.cached_output, in);\n            if (version == 2)\n                deserialize(item.params_grad, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const add_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\" << idx << \">\\t\" << impl::tensor_to_str(private_get_output(), min_length) << layer_details() << \"\\n\";\n            subnet().print(out, idx+1, min_length);\n        }\n\n    private:\n\n        bool this_layer_operates_inplace(\n        ) \n        {\n            // This layer can run in-place if it's an in-place capable layer and also if\n            // the layer it's on top of doesn't need its own output tensor (since in-place\n            // layers overwrite that tensor)\n            return impl::is_inplace_layer(details, *subnetwork) && !subnetwork->this_layer_requires_forward_output();\n        }\n        bool this_layer_requires_forward_output(\n        ) \n        {\n            return impl::backward_requires_forward_output(details, *subnetwork);\n        }\n\n        void swap(add_layer& item)\n        {\n            std::swap(subnetwork,item.subnetwork);\n            std::swap(details, item.details);\n            std::swap(this_layer_setup_called, item.this_layer_setup_called);\n            std::swap(gradient_input_is_stale, item.gradient_input_is_stale);\n            std::swap(get_output_and_gradient_input_disabled, item.get_output_and_gradient_input_disabled);\n            std::swap(x_grad, item.x_grad);\n            std::swap(cached_output, item.cached_output);\n            std::swap(params_grad, item.params_grad);\n        }\n\n\n        LAYER_DETAILS details;\n        std::unique_ptr<subnet_type> subnetwork;\n        bool this_layer_setup_called;\n        bool gradient_input_is_stale;\n        bool get_output_and_gradient_input_disabled;\n        // Note that if this_layer_operates_inplace()==true then x_grad and cached_output\n        // are not used at all.  Instead, this layer uses these variables from the lower\n        // layer.\n        resizable_tensor x_grad;\n        resizable_tensor cached_output; \n\n        resizable_tensor params_grad; \n\n        // temp_tensor doesn't logically contribute to the state of this object.  \n        // It is here only to prevent it from being reallocated over and over.\n        resizable_tensor temp_tensor;\n\n    };\n\n    template <typename T, typename U, typename E>\n    struct is_add_layer<add_layer<T,U,E>> : std::true_type {};\n    template <typename T, typename U, typename E>\n    struct is_add_layer<const add_layer<T,U,E>> : std::true_type {};\n    template <typename T, typename U, typename E>\n    struct is_add_layer<add_layer<T,U,E>&> : std::true_type {};\n    template <typename T, typename U, typename E>\n    struct is_add_layer<const add_layer<T,U,E>&> : std::true_type {};\n\n// ----------------------------------------------------------------------------------------\n\n// This version of add_layer handles the special case where the subnetwork being given is\n// just an input layer object.\n    template <typename LAYER_DETAILS, typename INPUT_LAYER, typename enabled>\n    class add_layer\n    {\n    public:\n        typedef LAYER_DETAILS layer_details_type;\n        typedef INPUT_LAYER subnet_type;\n        typedef INPUT_LAYER input_layer_type;\n        typedef typename INPUT_LAYER::input_type input_type;\n        const static size_t num_layers = 2;\n        const static size_t num_computational_layers = 1;\n\n        add_layer(\n        ): \n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(0)\n        {}\n\n        add_layer(const add_layer&) = default;\n        add_layer(add_layer&& item) : add_layer() { swap(item); }\n        add_layer& operator=(const add_layer&) = default;\n        add_layer& operator=(add_layer&& item) { swap(item); return *this; }\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        // Allow copying networks from one to another as long as their corresponding \n        // layers can be constructed from each other.\n        template <typename T, typename U, typename E>\n        add_layer(\n            const add_layer<T,U,E>& item\n        ):\n            input_layer_(item.subnet()),\n            details(item.layer_details()),\n            this_layer_setup_called(item.this_layer_setup_called),\n            gradient_input_is_stale(item.gradient_input_is_stale),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(item._sample_expansion_factor),\n            x_grad(item.x_grad),\n            cached_output(item.cached_output),\n            grad_final(item.grad_final)\n        {\n        }\n\n        add_layer(\n            const LAYER_DETAILS& layer_det\n        ) : \n            details(layer_det), \n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(0)\n        {}\n\n        add_layer(\n            const INPUT_LAYER& il \n        ) : \n            input_layer_(il), \n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(0)\n        {}\n\n        add_layer(\n            LAYER_DETAILS&& layer_det\n        ) : \n            details(std::move(layer_det)), \n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(0)\n        {}\n\n        add_layer(\n            LAYER_DETAILS layer_det, \n            INPUT_LAYER il\n        ) : \n            details(std::move(layer_det)),\n            input_layer_(std::move(il)),\n            this_layer_setup_called(false),\n            gradient_input_is_stale(true),\n            get_output_and_gradient_input_disabled(false),\n            _sample_expansion_factor(0)\n        {}\n\n        add_layer(\n            std::tuple<>,\n            const LAYER_DETAILS& layer_det\n        ) : add_layer(layer_det) {}\n\n        add_layer(\n            std::tuple<>,\n            LAYER_DETAILS&& layer_det\n        ) : add_layer(layer_det) {}\n\n        add_layer(\n            std::tuple<>,\n            LAYER_DETAILS layer_det, \n            INPUT_LAYER il\n        ) : add_layer(layer_det,il) {}\n\n        add_layer(\n            const std::tuple<LAYER_DETAILS>& layer_det\n        ) : add_layer(tuple_head(layer_det)) {}\n\n        add_layer(\n            const std::tuple<LAYER_DETAILS>& layer_det,\n            INPUT_LAYER il\n        ) : add_layer(tuple_head(layer_det),il) {}\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            input_layer_.to_tensor(ibegin, iend, data);\n            // make sure the input layer's to_tensor() function is implemented properly.\n            DLIB_CASSERT(data.num_samples() >= std::distance(ibegin,iend), \n            \"The input layer can't produce fewer output tensors than there are inputs.\");\n            DLIB_CASSERT(data.num_samples()%std::distance(ibegin,iend) == 0,\n            \"The number of tensors produced by the input layer must be an integer multiple of the number of input objects.\");\n\n            _sample_expansion_factor = data.num_samples()/std::distance(ibegin,iend);\n            data.async_copy_to_device();\n        }\n\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return forward(temp_tensor);\n        }\n\n\n        const tensor& operator() (const input_type& x)\n        {\n            return (*this)(&x, &x+1);\n        }\n\n        const tensor& forward (const tensor& x)\n        {\n            DLIB_CASSERT(sample_expansion_factor() != 0, \"You must call to_tensor() before this function can be used.\");\n            DLIB_CASSERT(x.num_samples()%sample_expansion_factor() == 0);\n            subnet_wrapper wsub(x, grad_final, _sample_expansion_factor);\n            if (!this_layer_setup_called)\n            {\n                details.setup(wsub);\n                this_layer_setup_called = true;\n            }\n            impl::call_layer_forward(details, wsub, cached_output);\n            gradient_input_is_stale = true;\n            return private_get_output();\n        }\n\n    private:\n        tensor& private_get_output() const { return const_cast<resizable_tensor&>(cached_output); }\n        tensor& private_get_gradient_input() \n        { \n            if (gradient_input_is_stale)\n            {\n                gradient_input_is_stale = false;\n                x_grad.copy_size(private_get_output());\n                x_grad = 0;\n            }\n            return x_grad; \n        }\n        void disable_output_and_gradient_getters (\n        ) { get_output_and_gradient_input_disabled = true; }\n    public:\n        const tensor& get_output() const \n        { \n            if (get_output_and_gradient_input_disabled)\n                throw dlib::error(\"Accessing this layer's get_output() is disabled because an in-place layer has been stacked on top of it.\");\n            return private_get_output(); \n        }\n        tensor& get_gradient_input() \n        { \n            if (get_output_and_gradient_input_disabled)\n                throw dlib::error(\"Accessing this layer's get_gradient_input() is disabled because an in-place layer has been stacked on top of it.\");\n            return private_get_gradient_input();\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const { return grad_final; }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            back_propagate_error(x, private_get_gradient_input(), zero_grads);\n        }\n        void back_propagate_error(\n            const tensor& x,\n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            // make sure grad_final is initialized to 0\n            if (!have_same_dimensions(x, grad_final))\n                grad_final.copy_size(x);\n            grad_final = 0;  \n\n            subnet_wrapper wsub(x, grad_final, _sample_expansion_factor);\n            params_grad.copy_size(details.get_layer_params());\n            impl::call_layer_backward(details, private_get_output(),\n                gradient_input, wsub, static_cast<tensor&>(params_grad));\n\n            // zero out get_gradient_input()\n            gradient_input_is_stale = zero_grads == zero_gradients::yes;\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> solvers, double learning_rate)\n        {\n            DLIB_CASSERT(solvers.size()>=num_computational_layers);\n            // Don't try to adjust the parameters if this layer doesn't have any or the\n            // learning rate is disabled for this layer.\n            if (params_grad.size() != 0 && get_learning_rate_multiplier(details) != 0) \n            {\n                const tensor& step = solvers.top()(learning_rate, details, static_cast<const tensor&>(params_grad));\n                tt::add(details.get_layer_params(), details.get_layer_params(), step);\n            }\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const tensor& get_parameter_gradient(\n        ) const { return params_grad; }\n\n        tensor& get_parameter_gradient (\n        )  { return params_grad; }\n\n        const subnet_type& subnet() const { return input_layer_; } \n        subnet_type& subnet() { return input_layer_; } \n\n        const subnet_type& input_layer() const { return input_layer_; } \n        subnet_type& input_layer() { return input_layer_; } \n\n        const layer_details_type& layer_details() const { return details; } \n        layer_details_type& layer_details() { return details; } \n\n        unsigned int sample_expansion_factor() const { return _sample_expansion_factor; }\n\n        void set_gradient_inputs_to_zero()\n        {\n            gradient_input_is_stale = true;\n        }\n\n        void clean()\n        {\n            x_grad.clear();\n            grad_final.clear();\n            cached_output.clear();\n            params_grad.clear();\n            temp_tensor.clear();\n            gradient_input_is_stale = true;\n            call_clean_method_if_exists(details);\n        }\n\n        friend void serialize(const add_layer& item, std::ostream& out)\n        {\n            int version = 3;\n            serialize(version, out);\n            serialize(item.input_layer_, out);\n            serialize(item.details, out);\n            serialize(item.this_layer_setup_called, out);\n            serialize(item.gradient_input_is_stale, out);\n            serialize(item.get_output_and_gradient_input_disabled, out);\n            serialize(item.x_grad, out);\n            serialize(item.cached_output, out);\n            serialize(item.grad_final, out);\n            serialize(item._sample_expansion_factor, out);\n        }\n\n        friend void deserialize(add_layer& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (!(2 <= version && version <= 3))\n                throw serialization_error(\"Unexpected version found while deserializing dlib::add_layer.\");\n            deserialize(item.input_layer_, in);\n            deserialize(item.details, in);\n            deserialize(item.this_layer_setup_called, in);\n            deserialize(item.gradient_input_is_stale, in);\n            deserialize(item.get_output_and_gradient_input_disabled, in);\n            deserialize(item.x_grad, in);\n            deserialize(item.cached_output, in);\n            deserialize(item.grad_final, in);\n            if (version >= 3)\n                deserialize(item._sample_expansion_factor, in);\n            else\n                item._sample_expansion_factor = 1; // all layer types set this to 1 in older dlib versions, so that's what we put here.\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const add_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\" << idx << \">\\t\" << impl::tensor_to_str(private_get_output(), min_length) << layer_details() << \"\\n\";\n\n            // Don't print the repeat_input_layer since it doesn't exist from the user's\n            // point of view.  It's just an artifact of how repeat<> works.\n            if (!std::is_same<subnet_type, impl::repeat_input_layer>::value)\n                out << \"layer<\" << idx+1 << \">\\t\" << subnet() << \"\\n\";\n        }\n\n    private:\n\n        bool this_layer_requires_forward_output(\n        ) \n        {\n            subnet_wrapper wsub(grad_final, grad_final, _sample_expansion_factor);\n            return impl::backward_requires_forward_output(details, wsub);\n        }\n\n        class subnet_wrapper\n        {\n        public:\n            subnet_wrapper(const tensor& x_, resizable_tensor& grad_final_, unsigned int sef) :\n                x(x_), grad_final(grad_final_), _sample_expansion_factor(sef) {}\n\n            subnet_wrapper(const subnet_wrapper&) = delete;\n            subnet_wrapper& operator=(const subnet_wrapper&) = delete;\n\n            unsigned int sample_expansion_factor() const { return _sample_expansion_factor;}\n            const tensor& get_output() const { return x; }\n            tensor& get_gradient_input() \n            { \n                if (!have_same_dimensions(x, grad_final))\n                {\n                    grad_final.copy_size(x);\n                    grad_final = 0;  \n                }\n                return grad_final; \n            }\n\n        private:\n            const tensor& x;\n            resizable_tensor& grad_final;\n            unsigned int _sample_expansion_factor;\n        };\n\n        void swap(add_layer& item)\n        {\n            std::swap(input_layer_, item.input_layer_);\n            std::swap(details, item.details);\n            std::swap(this_layer_setup_called, item.this_layer_setup_called);\n            std::swap(gradient_input_is_stale, item.gradient_input_is_stale);\n            std::swap(get_output_and_gradient_input_disabled, item.get_output_and_gradient_input_disabled);\n            std::swap(x_grad, item.x_grad); \n            std::swap(cached_output, item.cached_output); \n            std::swap(grad_final, item.grad_final); \n            std::swap(_sample_expansion_factor, item._sample_expansion_factor); \n        }\n\n        subnet_type input_layer_;\n        LAYER_DETAILS details;\n        bool this_layer_setup_called;\n        bool gradient_input_is_stale;\n        bool get_output_and_gradient_input_disabled;\n        mutable unsigned int _sample_expansion_factor;\n        resizable_tensor x_grad; \n        resizable_tensor cached_output; \n        resizable_tensor grad_final;\n\n        // The following 2 objects don't logically contribute to the state of this class.\n        // They are only here to prevent them from being reallocated over and over in\n        // member functions.\n        resizable_tensor params_grad; \n        resizable_tensor temp_tensor; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <unsigned long ID, typename SUBNET, typename enabled=void>\n    class add_tag_layer;\n\n    template <template<typename SUBNET> class tag>\n    struct tag_id\n    {\n        const static unsigned long id = tag<impl::repeat_input_layer>::id;\n    };\n\n    template <unsigned long ID, typename SUBNET>\n    class add_tag_layer<ID,SUBNET,\n            typename std::enable_if<is_nonloss_layer_type<SUBNET>::value>::type>\n    {\n    public:\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper.\n        const static size_t num_layers = subnet_type::num_layers + 1;\n        const static size_t num_computational_layers = subnet_type::num_computational_layers;\n        const static unsigned long id = ID;\n\n        add_tag_layer() {};\n        add_tag_layer(const add_tag_layer&) = default;\n        add_tag_layer(add_tag_layer&&) = default;\n        add_tag_layer& operator=(add_tag_layer&&) = default;\n        add_tag_layer& operator=(const add_tag_layer&) = default;\n\n        template <typename T>\n        add_tag_layer(\n            const add_tag_layer<ID,T>& item\n        ) : subnetwork(item.subnet())\n        {}\n\n        template <typename ...T>\n        add_tag_layer(\n            T ...args\n        ) : \n            subnetwork(std::move(args)...) \n        {\n        }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            subnetwork.to_tensor(ibegin,iend,data);\n        }\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            return subnetwork(ibegin,iend);\n        }\n\n        const tensor& operator() (const input_type& x)\n        {\n            return subnetwork(x);\n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            return subnetwork.forward(x);\n        }\n\n        const tensor& get_output() const { return subnetwork.get_output(); }\n\n        tensor& get_gradient_input() \n        { \n            return subnetwork.get_gradient_input();\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const { return subnetwork.get_final_data_gradient(); }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnetwork.back_propagate_error(x, zero_grads);\n        }\n        void back_propagate_error(\n            const tensor& x,\n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnetwork.back_propagate_error(x,gradient_input, zero_grads);\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> solvers, double learning_rate)\n        {\n            subnetwork.update_parameters(solvers, learning_rate);\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const tensor& get_parameter_gradient(\n        ) const { return params_grad; }\n\n        tensor& get_parameter_gradient (\n        ) { return params_grad; }\n\n        const subnet_type& subnet() const { return subnetwork; }\n        subnet_type& subnet() { return subnetwork; }\n\n        const input_layer_type& input_layer() const { return subnet().input_layer(); } \n        input_layer_type& input_layer() { return subnet().input_layer(); } \n\n        unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); }\n\n        void set_gradient_inputs_to_zero()\n        {\n            subnetwork.set_gradient_inputs_to_zero();\n        }\n\n        void clean()\n        {\n            subnetwork.clean();\n        }\n\n        friend void serialize(const add_tag_layer& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.subnetwork, out);\n        }\n\n        friend void deserialize(add_tag_layer& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw serialization_error(\"Unexpected version found while deserializing dlib::add_tag_layer.\");\n            deserialize(item.subnetwork, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const add_tag_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\" << idx << \">\\t\" << impl::tensor_to_str(private_get_output(), min_length) << \"tag\" << ID << \"\\n\";\n            subnet().print(out, idx+1, min_length);\n        }\n\n    private:\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        // You wouldn't put a tag on a layer if you didn't want to access its forward\n        // outputs.  So this is always true.\n        bool this_layer_requires_forward_output(\n        ) { return true; } \n\n        void disable_output_and_gradient_getters (\n        ) \n        { \n            // This should never happen because only inplace layers call\n            // disable_output_and_gradient_getters(), however, putting a tag layer right\n            // before an inplace layer basically means you don't want the following layer\n            // to operate in place.  So the inplace layer should turn itself into an\n            // out-of-place layer and not call disable_output_and_gradient_getters(). \n            DLIB_CASSERT(false,\"This should never happen\");\n        }\n\n        tensor& private_get_output() const\n        { return subnetwork.private_get_output(); }\n        tensor& private_get_gradient_input() \n        { return subnetwork.private_get_gradient_input(); }\n\n        subnet_type subnetwork;\n\n        // This member doesn't logically contribute to the state of the object since it is\n        // always empty. It's just here so we can have the get_parameter_gradient() methods\n        // which have to return something.  So they return this empty tensor.\n        resizable_tensor params_grad;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename ...T>\n    struct decorator_repeat_group\n    {\n        decorator_repeat_group(\n            T&& ...args\n        ) : data(std::forward<T>(args)...) {}\n\n        std::tuple<T...> data;\n    };\n    template <typename ...T>\n    decorator_repeat_group<T...> repeat_group (\n        T&& ...args\n    )\n    {\n        return decorator_repeat_group<T...>(std::forward<T>(args)...);\n    }\n\n    template <\n        size_t num,\n        template<typename> class REPEATED_LAYER, \n        typename SUBNET\n        >\n    class repeat\n    {\n        static_assert(num > 0, \"You can't have a layer repeated 0 times.\");\n    public:\n        typedef SUBNET subnet_type;\n        typedef typename SUBNET::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper.\n        const static size_t comp_layers_in_each_group = (REPEATED_LAYER<SUBNET>::num_computational_layers-SUBNET::num_computational_layers);\n        const static size_t comp_layers_in_repeated_group = comp_layers_in_each_group*num;\n        const static size_t num_computational_layers = comp_layers_in_repeated_group + SUBNET::num_computational_layers;\n\n        const static size_t layers_in_each_group = (REPEATED_LAYER<SUBNET>::num_layers-SUBNET::num_layers);\n        const static size_t layers_in_repeated_group = layers_in_each_group*num;\n        const static size_t num_layers = subnet_type::num_layers + layers_in_repeated_group;\n\n\n        typedef REPEATED_LAYER<impl::repeat_input_layer> repeated_layer_type;\n\n        repeat(\n        ) : \n            details(num)\n        {\n        }\n\n        size_t num_repetitions (\n        ) const { return num; }\n\n        const repeated_layer_type& get_repeated_layer (\n            size_t i \n        ) const\n        { \n            DLIB_CASSERT(i < num_repetitions());\n            return details[i]; \n        }\n\n        repeated_layer_type& get_repeated_layer (\n            size_t i \n        ) \n        { \n            DLIB_CASSERT(i < num_repetitions());\n            return details[i]; \n        }\n\n        repeat(const repeat&) = default;\n        repeat(repeat&&) = default;\n        repeat& operator=(repeat&&) = default;\n        repeat& operator=(const repeat&) = default;\n\n        template <template<typename> class T, typename U>\n        repeat(\n            const repeat<num,T,U>& item\n        ) : \n            subnetwork(item.subnetwork)\n        {\n            for (auto&& d : item.details)\n                details.emplace_back(d);\n        }\n\n        template <typename T, typename ...U>\n        repeat(\n            T arg1,\n            U ...args2\n        ): \n            details(num, std::move(arg1)),\n            subnetwork(std::move(args2)...)\n        {\n        }\n\n        template <typename ...T, typename ...U>\n        repeat(\n            decorator_repeat_group<T...>&& arg1,\n            U ...args2\n        ): \n            details(num, arg1.data),\n            subnetwork(std::move(args2)...)\n        {\n        }\n\n        template <typename T, typename ...U>\n        repeat(\n            std::tuple<>,\n            T arg1,\n            U ...args2\n        ): \n            details(num, std::move(arg1)),\n            subnetwork(std::move(args2)...)\n        {\n        }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            subnetwork.to_tensor(ibegin,iend,data);\n            // call to_tensor on the networks in details just to populate the\n            // _sample_expansion_factor values in those networks.  Other than that this\n            // call is a noop.  \n            for (auto& d : details)\n                d.to_tensor(ibegin, iend, data);\n        }\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return forward(temp_tensor);\n        }\n\n        const tensor& operator() (const input_type& x)\n        {\n            return (*this)(&x, &x+1);\n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            subnetwork.forward(x);\n            details[details.size()-1].forward(subnetwork.get_output());\n            for (long i = details.size()-2; i >= 0; --i)\n                details[i].forward(details[i+1].get_output());\n            return private_get_output();\n        }\n\n    private:\n        tensor& private_get_output() const\n        { \n            return details[0].private_get_output();\n        }\n        tensor& private_get_gradient_input() \n        { \n            return details[0].private_get_gradient_input();\n        }\n    public:\n        const tensor& get_output() const \n        { \n            return details[0].get_output(); \n        }\n        tensor& get_gradient_input() \n        { \n            return details[0].get_gradient_input();\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const { return subnetwork.get_final_data_gradient(); }\n\n        const tensor& get_parameter_gradient(\n        ) const { return details[0].get_parameter_gradient(); }\n\n        tensor& get_parameter_gradient (\n        ) { return details[0].get_parameter_gradient(); }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            back_propagate_error(x, private_get_gradient_input(), zero_grads);\n        }\n        void back_propagate_error(\n            const tensor& x,\n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            if (details.size() > 1)\n            {\n                details[0].back_propagate_error(details[1].get_output(), gradient_input, zero_grads);\n                for (size_t i = 1; i < details.size(); ++i)\n                {\n                    if (i+1 < details.size())\n                        details[i].back_propagate_error(details[i+1].get_output(), details[i-1].get_final_data_gradient(), zero_grads);\n                    else\n                        details[i].back_propagate_error(subnetwork.get_output(), details[i-1].get_final_data_gradient(), zero_grads);\n                }\n            }\n            else\n            {\n                details[0].back_propagate_error(subnetwork.get_output(), gradient_input, zero_grads);\n            }\n            subnetwork.back_propagate_error(x, details.back().get_final_data_gradient(), zero_grads);\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> solvers, double learning_rate)\n        {\n            for (size_t i = 0; i < details.size(); ++i)\n                details[i].update_parameters(solvers.pop(comp_layers_in_each_group*i),learning_rate);\n            subnetwork.update_parameters(solvers.pop(comp_layers_in_each_group*details.size()),learning_rate);\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const subnet_type& subnet() const { return subnetwork; }\n        subnet_type& subnet() { return subnetwork; }\n\n        const input_layer_type& input_layer() const { return subnet().input_layer(); } \n        input_layer_type& input_layer() { return subnet().input_layer(); } \n\n        unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); }\n\n        void set_gradient_inputs_to_zero()\n        {\n            subnetwork.set_gradient_inputs_to_zero();\n        }\n\n        void clean()\n        {\n            temp_tensor.clear();\n            subnetwork.clean();\n            for (auto&& d : details)\n                d.clean();\n        }\n\n        friend void serialize(const repeat& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.details, out);\n            serialize(item.subnetwork, out);\n        }\n\n        friend void deserialize(repeat& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw serialization_error(\"Unexpected version found while deserializing dlib::repeat.\");\n            deserialize(item.details, in);\n            deserialize(item.subnetwork, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const repeat& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            for (size_t i = 0; i < num_repetitions(); ++i)\n            {\n                get_repeated_layer(i).print(out, idx, min_length);\n                idx += layers_in_each_group;\n            }\n            subnet().print(out, idx, min_length);\n        }\n    private:\n\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        bool this_layer_requires_forward_output(\n        ) \n        { \n            return details[0].this_layer_requires_forward_output(); \n        } \n\n        void disable_output_and_gradient_getters (\n        ) \n        { \n            details[0].disable_output_and_gradient_getters();\n        }\n\n\n        std::vector<repeated_layer_type> details; \n        subnet_type subnetwork;\n\n        // temp_tensor doesn't logically contribute to the state of this class.\n        // It is here only to void needing to reallocate it over and over.\n        resizable_tensor temp_tensor;\n    };\n\n    template <\n        size_t num,\n        template<typename> class REPEATED_LAYER, \n        typename SUBNET\n        >\n    struct is_nonloss_layer_type<repeat<num,REPEATED_LAYER,SUBNET>> : std::true_type {};\n\n// ----------------------------------------------------------------------------------------\n\n// This version of add_tag_layer handles the special case where the subnetwork being given\n// is just an input layer object.\n    template <unsigned long ID, typename INPUT_LAYER, typename enabled>\n    class add_tag_layer\n    {\n    public:\n        typedef INPUT_LAYER subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef INPUT_LAYER input_layer_type;\n        typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper.\n        const static size_t num_computational_layers = 0;\n        const static size_t num_layers = 2;\n        const static unsigned long id = ID;\n\n        add_tag_layer():cached_output_ptr(nullptr),gradient_input_is_stale(true),_sample_expansion_factor(0) {}\n\n        add_tag_layer(const add_tag_layer&) = default;\n        add_tag_layer& operator=(const add_tag_layer&) = default;\n        add_tag_layer(add_tag_layer&& item) : add_tag_layer() { swap(item); }\n        add_tag_layer& operator=(add_tag_layer&& item) { swap(item); return *this; }\n\n        template <typename T, typename E>\n        add_tag_layer(\n            const add_tag_layer<ID,T,E>& item\n        ) : input_layer_(item.subnet()), \n            cached_output(item.cached_output),\n            cached_output_ptr(nullptr),\n            grad_final(item.grad_final),\n            gradient_input_is_stale(item.gradient_input_is_stale),\n            _sample_expansion_factor(0)\n        {}\n\n        template <typename ...T>\n        add_tag_layer(\n            T ...args\n        ) : \n            input_layer_(std::move(args)...),\n            cached_output_ptr(nullptr),\n            gradient_input_is_stale(true),\n            _sample_expansion_factor(0)\n        {\n        }\n\n        add_tag_layer (\n            std::tuple<>\n        ) : \n            cached_output_ptr(nullptr),\n            gradient_input_is_stale(true),\n            _sample_expansion_factor(0)\n        {}\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            input_layer_.to_tensor(ibegin,iend,data);\n\n            // make sure the input layer's to_tensor() function is implemented properly.\n            DLIB_CASSERT(data.num_samples() >= std::distance(ibegin,iend), \n            \"The input layer can't produce fewer output tensors than there are inputs.\");\n            DLIB_CASSERT(data.num_samples()%std::distance(ibegin,iend) == 0,\n            \"The number of tensors produced by the input layer must be an integer multiple of the number of input objects.\");\n\n            _sample_expansion_factor = data.num_samples()/std::distance(ibegin,iend);\n            data.async_copy_to_device();\n        }\n\n        unsigned int sample_expansion_factor() const { return _sample_expansion_factor; }\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin, \n            forward_iterator iend\n        )\n        {\n            input_layer_.to_tensor(ibegin,iend,cached_output);\n            cached_output_ptr = nullptr;\n            return get_output();\n        }\n\n        const tensor& operator() (const input_type& x)\n        {\n            return (*this)(&x, &x+1);\n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            // If this tag is the first layer in one of the sub networks inside a repeat\n            // layer then we don't want it to be creating copies of x.  This is because, we\n            // can just hold a pointer to x since the way repeat is constructed guarantees\n            // that x will have a lifetime larger than this pointer. \n            if (is_same_type<INPUT_LAYER, impl::repeat_input_layer>::value)\n                cached_output_ptr = const_cast<tensor*>(&x);\n            else\n                cached_output = x;\n            gradient_input_is_stale = true;\n            return get_output();\n        }\n\n        const tensor& get_output() const \n        { \n            if (cached_output_ptr)\n                return *cached_output_ptr;\n            else\n                return cached_output; \n        }\n\n        const tensor& get_final_data_gradient(\n        ) const { return grad_final; }\n\n        tensor& get_gradient_input() \n        { \n            if (!have_same_dimensions(get_output(), grad_final) ||\n                gradient_input_is_stale)\n            {\n                grad_final.copy_size(get_output());\n                grad_final = 0;\n                gradient_input_is_stale = false;\n            }\n            return grad_final; \n        }\n\n\n        void back_propagate_error(\n            const tensor& /*x*/,\n            zero_gradients /*zero_grads*/ = zero_gradients::yes\n        )\n        {\n            // nothing to do\n        }\n        void back_propagate_error(\n            const tensor& /*x*/,\n            const tensor& /*gradient_input*/,\n            zero_gradients /*zero_grads*/ = zero_gradients::yes\n        )\n        {\n            // nothing to do\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> /*solvers*/, double /*learning_rate*/)\n        {\n            // nothing to do\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const subnet_type& subnet() const { return input_layer_; }\n        subnet_type& subnet() { return input_layer_; }\n\n        const input_layer_type& input_layer() const { return input_layer_; } \n        input_layer_type& input_layer() { return input_layer_; } \n\n        void set_gradient_inputs_to_zero()\n        {\n            // nothing to do\n        }\n\n        void clean()\n        {\n            grad_final.clear();\n            cached_output.clear();\n            cached_output_ptr = 0;\n        }\n\n        friend void serialize(const add_tag_layer& item, std::ostream& out)\n        {\n            int version = 2;\n            serialize(version, out);\n            serialize(item.input_layer_, out);\n            serialize(item.cached_output, out);\n            serialize(item.grad_final, out);\n            serialize(item.gradient_input_is_stale, out);\n            serialize(item._sample_expansion_factor, out);\n        }\n\n        friend void deserialize(add_tag_layer& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (!(1 <= version && version <= 2))\n                throw serialization_error(\"Unexpected version found while deserializing dlib::add_tag_layer.\");\n            deserialize(item.input_layer_, in);\n            deserialize(item.cached_output, in);\n            deserialize(item.grad_final, in);\n            deserialize(item.gradient_input_is_stale, in);\n            item.cached_output_ptr = nullptr;\n            if (version >= 2)\n                deserialize(item._sample_expansion_factor, in);\n            else\n                item._sample_expansion_factor = 1; // all layer types set this to 1 in older dlib versions, so that's what we put here.\n                \n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const add_tag_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\"<<idx << \">\\t\"<<impl::tensor_to_str(private_get_output(), min_length)<< \"tag\" << ID << \"\\n\";\n            // Don't print the repeat_input_layer since it doesn't exist from the user's\n            // point of view.  It's just an artifact of how repeat<> works.\n            if (!std::is_same<subnet_type, impl::repeat_input_layer>::value)\n                out << \"layer<\"<< idx+1 << \">\\t\" << subnet() << \"\\n\";\n        }\n\n    private:\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        // You woudln't put a tag on a layer if you didn't want to access its forward\n        // outputs.  So this is always true.\n        bool this_layer_requires_forward_output(\n        ) { return true; } \n\n        void disable_output_and_gradient_getters (\n        ) \n        { \n            // This should never happen because only inplace layers call\n            // disable_output_and_gradient_getters(), however, putting a tag layer right\n            // before an inplace layer basically means you don't want the following layer\n            // to operate in place.  So the inplace layer should turn itself into an\n            // out-of-place layer and not call disable_output_and_gradient_getters(). \n            DLIB_CASSERT(false,\"This should never happen\");\n        }\n\n        tensor& private_get_output() const\n        { return const_cast<tensor&>(get_output()); }\n        tensor& private_get_gradient_input() \n        { return get_gradient_input(); }\n\n        void swap(add_tag_layer& item)\n        {\n            std::swap(input_layer_, item.input_layer_);\n            std::swap(cached_output, item.cached_output);\n            std::swap(cached_output_ptr, item.cached_output_ptr);\n            std::swap(grad_final, item.grad_final);\n            std::swap(gradient_input_is_stale, item.gradient_input_is_stale);\n            std::swap(_sample_expansion_factor, item._sample_expansion_factor);\n        }\n\n        subnet_type input_layer_;\n        resizable_tensor cached_output;\n        tensor* cached_output_ptr;\n        resizable_tensor grad_final;\n        bool gradient_input_is_stale;\n        mutable unsigned int _sample_expansion_factor;\n    };\n\n    template <unsigned long ID, typename U, typename E>\n    struct is_nonloss_layer_type<add_tag_layer<ID,U,E>> : std::true_type {};\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename LOSS_DETAILS, typename SUBNET>\n    class add_loss_layer;\n\n    class no_label_type\n    {\n    private:\n        // We don't want anyone making these no_label_type objects.  They are here only to\n        // allow add_loss_layer::training_label_type and dnn_trainer::training_label_type\n        // to exist which avoids needing to overload add_loss_layer and dnn_trainer for\n        // supervised an unsupervised losses.  It also can be a type to use in template\n        // metaprogramming to indicate \"no label\".  So here we make the constructor private\n        // with the exception that add_loss_layer objects can make it (again, just to\n        // simplify add_loss_layer's implementation).\n        no_label_type(){};\n        template <typename LOSS_DETAILS, typename SUBNET> friend class add_loss_layer;\n        template < typename net_type, typename solver_type > friend class dnn_trainer; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename LOSS_DETAILS, typename SUBNET>\n    class add_loss_layer\n    {\n        template <typename T, typename enabled=void>\n        struct get_loss_layer_training_label_type\n        {\n            typedef no_label_type type;\n        };\n        template <typename T>\n        struct get_loss_layer_training_label_type<T,typename std::enable_if<sizeof(typename T::training_label_type)!=0>::type>\n        {\n            typedef typename T::training_label_type type;\n        };\n\n        template <typename T, typename enabled=void>\n        struct get_loss_layer_output_label_type\n        {\n            typedef no_label_type type;\n        };\n        template <typename T>\n        struct get_loss_layer_output_label_type<T,typename std::enable_if<sizeof(typename T::output_label_type)!=0>::type>\n        {\n            typedef typename T::output_label_type type;\n        };\n\n    public:\n        typedef LOSS_DETAILS loss_details_type;\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        const static size_t num_layers = subnet_type::num_layers + 1;\n        // Note that the loss layer doesn't count as an additional computational layer.\n        const static size_t num_computational_layers = subnet_type::num_computational_layers;\n        typedef typename get_loss_layer_training_label_type<LOSS_DETAILS>::type training_label_type;\n        typedef typename get_loss_layer_output_label_type<LOSS_DETAILS>::type output_label_type;\n\n        static_assert(is_nonloss_layer_type<SUBNET>::value, \n            \"SUBNET must be of type add_layer, add_skip_layer, or add_tag_layer.\"); \n\n\n        add_loss_layer() {};\n        add_loss_layer(const add_loss_layer&) = default;\n        add_loss_layer& operator=(const add_loss_layer&) = default;\n        add_loss_layer(add_loss_layer&& item) : add_loss_layer() { swap(item); }\n        add_loss_layer& operator=(add_loss_layer&& item) { swap(item); return *this; }\n\n        template <typename T, typename U>\n        add_loss_layer(\n            const add_loss_layer<T,U>& item\n        ) : \n            loss(item.loss_details()),\n            subnetwork(item.subnet())\n        {}\n\n        template <typename ...T>\n        add_loss_layer(\n            const LOSS_DETAILS& layer_det, \n            T&& ...args\n        ) : \n            loss(layer_det), \n            subnetwork(std::forward<T>(args)...)\n        {\n        }\n\n        template <typename ...T>\n        add_loss_layer(\n            LOSS_DETAILS&& layer_det, \n            T&& ...args\n        ) : \n            loss(std::move(layer_det)), \n            subnetwork(std::forward<T>(args)...)\n        {\n        }\n\n        template <typename T, typename ...U>\n        struct disable_forwarding_constr \n        {\n            const static bool value = std::is_constructible<LOSS_DETAILS,T>::value;\n        };\n        template <typename ...T>\n        struct disable_forwarding_constr<add_loss_layer<T...>>\n        {\n            const static bool value = true;\n        };\n\n        template <\n            typename ...T, \n            typename = typename std::enable_if<!disable_forwarding_constr<typename std::remove_reference<T>::type...>::value>::type\n            >\n        add_loss_layer(\n            T&& ...args\n        ) : \n            subnetwork(std::forward<T>(args)...)\n        {\n        }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            subnetwork.to_tensor(ibegin,iend,data);\n        }\n\n        unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); }\n\n        template <typename output_iterator>\n        void operator() (\n            const tensor& x, \n            output_iterator obegin\n        )\n        {\n            subnetwork.forward(x);\n            const dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            loss.to_label(x, wsub, obegin);\n        }\n\n        template <typename forward_iterator, typename output_iterator>\n        void operator() (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            output_iterator obegin\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            (*this)(temp_tensor, obegin);\n        }\n\n        const output_label_type& operator() (const input_type& x)\n        {\n            (*this)(&x, &x+1, &temp_label);\n            return temp_label;\n        }\n\n        template <typename ...T>\n        const output_label_type& process (const input_type& x, T&& ...args)\n        {\n            to_tensor(&x,&x+1,temp_tensor);\n            subnetwork.forward(temp_tensor);\n            const dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            loss.to_label(temp_tensor, wsub, &temp_label, std::forward<T>(args)...);\n            return temp_label;\n        }\n\n        template <typename iterable_type, typename ...T>\n        std::vector<output_label_type> process_batch (const iterable_type& data, size_t batch_size, T&& ...args)\n        {\n            std::vector<output_label_type> results(std::distance(data.begin(), data.end()));\n            auto o = results.begin();\n            auto i = data.begin();\n            auto num_remaining = results.size();\n            while(num_remaining != 0)\n            {\n                auto inc = std::min(batch_size, num_remaining);\n                to_tensor(i,i+inc,temp_tensor);\n                subnetwork.forward(temp_tensor);\n                const dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n                loss.to_label(temp_tensor, wsub, o, std::forward<T>(args)...);\n\n                i += inc;\n                o += inc;\n                num_remaining -= inc;\n            }\n            return results;\n        }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnet().back_propagate_error(x, zero_grads);\n        }\n\n        void back_propagate_error(\n            const tensor& x,\n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnet().back_propagate_error(x, gradient_input, zero_grads);\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const \n        { \n            return subnet().get_final_data_gradient(); \n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            return subnet().forward(x);\n        }\n\n        template <typename iterable_type>\n        std::vector<output_label_type> operator() (\n            const iterable_type& data,\n            size_t batch_size = 128\n        )\n        {\n            std::vector<output_label_type> results(std::distance(data.begin(), data.end()));\n            auto o = results.begin();\n            auto i = data.begin();\n            auto num_remaining = results.size();\n            while(num_remaining != 0)\n            {\n                auto inc = std::min(batch_size, num_remaining);\n                (*this)(i, i+inc, o);\n                i += inc;\n                o += inc;\n                num_remaining -= inc;\n            }\n            return results;\n        }\n\n        template <typename label_iterator>\n        double compute_loss (\n            const tensor& x,\n            label_iterator lbegin \n        )\n        {\n            subnetwork.forward(x);\n            dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            return loss.compute_loss_value_and_gradient(x, lbegin, wsub);\n        }\n\n        template <typename forward_iterator, typename label_iterator>\n        double compute_loss (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            label_iterator lbegin \n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return compute_loss(temp_tensor, lbegin);\n        }\n\n        double compute_loss (\n            const tensor& x\n        )\n        {\n            subnetwork.forward(x);\n            dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            return loss.compute_loss_value_and_gradient(x, wsub);\n        }\n\n        template <typename forward_iterator>\n        double compute_loss (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return compute_loss(temp_tensor);\n        }\n\n        template <typename label_iterator>\n        double compute_parameter_gradients (\n            const tensor& x,\n            label_iterator lbegin,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnetwork.forward(x);\n            dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            double l = loss.compute_loss_value_and_gradient(x, lbegin, wsub);\n            subnetwork.back_propagate_error(x, zero_grads);\n            return l;\n        }\n        template <typename forward_iterator, typename label_iterator>\n        double compute_parameter_gradients (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            label_iterator lbegin,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return compute_parameter_gradients(temp_tensor, lbegin, zero_grads);\n        }\n        double compute_parameter_gradients (\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnetwork.forward(x);\n            dimpl::subnet_wrapper<subnet_type> wsub(subnetwork);\n            double l = loss.compute_loss_value_and_gradient(x, wsub);\n            subnetwork.back_propagate_error(x, zero_grads);\n            return l;\n        }\n        template <typename forward_iterator>\n        double compute_parameter_gradients (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            to_tensor(ibegin,iend,temp_tensor);\n            return compute_parameter_gradients(temp_tensor, zero_grads);\n        }\n\n        template <typename solver_type>\n        void update_parameters (\n            sstack<solver_type> solvers,\n            double learning_rate\n        )\n        {\n            subnetwork.update_parameters(solvers, learning_rate);\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const subnet_type& subnet() const { return subnetwork; }\n        subnet_type& subnet() { return subnetwork; }\n\n        const input_layer_type& input_layer() const { return subnet().input_layer(); } \n        input_layer_type& input_layer() { return subnet().input_layer(); } \n\n        const loss_details_type& loss_details() const { return loss; }\n        loss_details_type& loss_details() { return loss; }\n\n        void set_gradient_inputs_to_zero (\n        )\n        {\n            subnetwork.set_gradient_inputs_to_zero();\n        }\n\n        void clean (\n        )\n        {\n            temp_tensor.clear();\n            subnetwork.clean();\n        }\n\n        template <typename T, typename U>\n        friend void serialize(const add_loss_layer<T,U>& item, std::ostream& out);\n        template <typename T, typename U>\n        friend void deserialize(add_loss_layer<T,U>& item, std::istream& in);\n\n        friend std::ostream& operator<< (std::ostream& out, const add_loss_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\" << idx << \">\\t\" << loss_details() << \"\\n\";\n            subnet().print(out, idx+1, min_length);\n        }\n\n    private:\n\n\n        void swap(add_loss_layer& item)\n        {\n            std::swap(loss, item.loss);\n            std::swap(subnetwork, item.subnetwork);\n        }\n\n        loss_details_type loss;\n        subnet_type subnetwork;\n\n        // These two objects don't logically contribute to the state of this object.  They\n        // are here to prevent them from being reallocated over and over.\n        output_label_type temp_label;\n        resizable_tensor temp_tensor;\n    };\n\n    template <typename LOSS_DETAILS, typename SUBNET>\n    void serialize(const add_loss_layer<LOSS_DETAILS,SUBNET>& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.loss, out);\n        serialize(item.subnetwork, out);\n    }\n\n    template <typename LOSS_DETAILS, typename SUBNET>\n    void deserialize(add_loss_layer<LOSS_DETAILS,SUBNET>& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::add_loss_layer.\");\n        deserialize(item.loss, in);\n        deserialize(item.subnetwork, in);\n    }\n\n\n    template <typename T, typename U>\n    struct is_loss_layer_type<add_loss_layer<T,U>> : std::true_type {};\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <unsigned int i, typename T, typename enabled = void>\n        struct layer_helper\n        {\n            static_assert(i < T::num_layers, \"Call to layer() attempted to access non-existing layer in neural network.\");\n            static T& makeT();\n            // If you get error here mentioning lack of member \"subnet\" in \"dlib::input<...>\",\n            // then likely your \"dlib::layer<...>\" invocation wasn't able to find requested layer.\n            // This could happen for instance when trying to use skip layer for non-existing tag.\n            using next_type = typename std::remove_reference<decltype(makeT().subnet())>::type;\n            using type = typename layer_helper<i-1,next_type>::type;\n            static type& layer(T& n)\n            {\n                return layer_helper<i-1,next_type>::layer(n.subnet());\n            }\n        };\n        template <\n            unsigned int i,\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<i,repeat<N,L,S>, typename std::enable_if<(i!=0&&i>=repeat<N,L,S>::layers_in_repeated_group)>::type>\n        {\n            const static size_t layers_in_repeated_group = repeat<N,L,S>::layers_in_repeated_group;\n\n            static repeat<N,L,S>& makeT();\n            using next_type = typename std::remove_reference<decltype(makeT().subnet())>::type;\n            using type = typename layer_helper<i-layers_in_repeated_group,next_type>::type;\n            static type& layer(repeat<N,L,S>& n)\n            {\n                return layer_helper<i-layers_in_repeated_group,next_type>::layer(n.subnet());\n            }\n        };\n        template <\n            unsigned int i,\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<i,repeat<N,L,S>, typename std::enable_if<(i!=0&&i<repeat<N,L,S>::layers_in_repeated_group)>::type>\n        {\n            const static size_t layers_in_each_group = repeat<N,L,S>::layers_in_each_group;\n            typedef typename repeat<N,L,S>::repeated_layer_type repeated_layer_type;\n            using next_type = repeated_layer_type;\n            using type = typename layer_helper<i%layers_in_each_group,next_type>::type;\n            static type& layer(repeat<N,L,S>& n)\n            {\n                return layer_helper<i%layers_in_each_group,next_type>::layer(n.get_repeated_layer(i/layers_in_each_group));\n            }\n        };\n        template <\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<0,repeat<N,L,S>, void>\n        {\n            typedef typename repeat<N,L,S>::repeated_layer_type repeated_layer_type;\n            using type = repeated_layer_type;\n            static type& layer(repeat<N,L,S>& n)\n            {\n                return n.get_repeated_layer(0);\n            }\n        };\n\n\n\n        template <\n            unsigned int i,\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<i,const repeat<N,L,S>, typename std::enable_if<(i!=0&&i>=repeat<N,L,S>::layers_in_repeated_group)>::type>\n        {\n            const static size_t layers_in_repeated_group = repeat<N,L,S>::layers_in_repeated_group;\n\n            static const repeat<N,L,S>& makeT();\n            using next_type = const typename std::remove_reference<decltype(makeT().subnet())>::type;\n            using type = const typename layer_helper<i-layers_in_repeated_group,next_type>::type;\n            static type& layer(const repeat<N,L,S>& n)\n            {\n                return layer_helper<i-layers_in_repeated_group,next_type>::layer(n.subnet());\n            }\n        };\n        template <\n            unsigned int i,\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<i,const repeat<N,L,S>, typename std::enable_if<(i!=0&&i<repeat<N,L,S>::layers_in_repeated_group)>::type>\n        {\n            const static size_t layers_in_each_group = repeat<N,L,S>::layers_in_each_group;\n            typedef typename repeat<N,L,S>::repeated_layer_type repeated_layer_type;\n            using next_type = const repeated_layer_type;\n            using type = const typename layer_helper<i%layers_in_each_group,next_type>::type;\n            static type& layer(const repeat<N,L,S>& n)\n            {\n                return layer_helper<i%layers_in_each_group,next_type>::layer(n.get_repeated_layer(i/layers_in_each_group));\n            }\n        };\n        template <\n            size_t N, template<typename> class L, typename S\n        >\n        struct layer_helper<0,const repeat<N,L,S>, void>\n        {\n            typedef typename repeat<N,L,S>::repeated_layer_type repeated_layer_type;\n            using type = const repeated_layer_type;\n            static type& layer(const repeat<N,L,S>& n)\n            {\n                return n.get_repeated_layer(0);\n            }\n        };\n\n\n\n        template <typename T>\n        struct layer_helper<0,T,void>\n        {\n            using type = T;\n            static type& layer(T& n)\n            {\n                return n;\n            }\n        };\n\n        template <template<typename> class Match, typename T, unsigned int i, typename enabled = void>\n        struct layer_helper_match\n        {\n            static T& makeT();\n            using next_type = typename std::remove_reference<decltype(makeT().subnet())>::type;\n            using type = typename layer_helper_match<Match,next_type,i>::type;\n            static type& layer(T& n)\n            {\n                return layer_helper_match<Match,next_type,i>::layer(n.subnet());\n            }\n        };\n        // This overload catches add_layer and add_loss_layer templates.\n        template <template<typename> class Match, typename T, unsigned int i>\n        struct layer_helper_match<Match,T,i,\n            typename std::enable_if<std::is_same<const T,const  Match<typename T::subnet_type>>::value>::type>\n        {\n            using type = typename layer_helper<i,T>::type;\n            static type& layer(T& n)\n            {\n                return layer_helper<i,T>::layer(n);\n            }\n        };\n        // This overload catches input templates.\n        template <template<typename> class Match, typename T, unsigned int i>\n        struct layer_helper_match<Match,T,i,\n            typename std::enable_if<std::is_same<const T,const  Match<typename T::input_type>>::value>::type>\n        {\n            using type = typename layer_helper<i,T>::type;\n            static type& layer(T& n)\n            {\n                return layer_helper<i,T>::layer(n);\n            }\n        };\n        // This overload catches subnet_wrapper templates.\n        template <template<typename> class Match, typename T, unsigned int i>\n        struct layer_helper_match<Match,T,i,\n            typename std::enable_if<std::is_same<const typename T::wrapped_type, \n                                                 const Match<typename T::wrapped_type::subnet_type>>::value>::type>\n        {\n            using type = typename layer_helper<i,T>::type;\n            static type& layer(T& n)\n            {\n                return layer_helper<i,T>::layer(n);\n            }\n        };\n    }\n\n    template <unsigned int i, typename T>\n    typename impl::layer_helper<i,T>::type& layer (T& n) \n    {\n        return impl::layer_helper<i,T>::layer(n);\n    }\n\n    template <template<typename> class Match, typename T>\n    typename impl::layer_helper_match<Match,T,0>::type& layer (T& n) \n    {\n        return impl::layer_helper_match<Match,T,0>::layer(n);\n    }\n\n    template <template<typename> class Match, unsigned int i, typename T>\n    typename impl::layer_helper_match<Match,T,i>::type& layer (T& n) \n    {\n        return impl::layer_helper_match<Match,T,i>::layer(n);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    typename net_type::input_layer_type& input_layer (\n        net_type& net\n    )\n    {\n        return net.input_layer();\n    }\n\n    template <typename net_type>\n    const typename net_type::input_layer_type& input_layer (\n        const net_type& net\n    )\n    {\n        return net.input_layer();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <template<typename> class TAG_TYPE, typename SUBNET>\n    class add_skip_layer\n    {\n    public:\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        typedef int layer_details_type; // not really used anywhere, but required by subnet_wrapper.\n        const static size_t num_layers = subnet_type::num_layers + 1;\n        const static size_t num_computational_layers = subnet_type::num_computational_layers;\n        const static unsigned long id = tag_id<TAG_TYPE>::id;\n\n        add_skip_layer() {};\n        add_skip_layer(const add_skip_layer&) = default;\n        add_skip_layer(add_skip_layer&&) = default;\n        add_skip_layer& operator=(add_skip_layer&&) = default;\n        add_skip_layer& operator=(const add_skip_layer&) = default;\n\n        template <typename T>\n        add_skip_layer(\n            const add_skip_layer<TAG_TYPE,T>& item\n        ) : subnetwork(item.subnet())\n        {}\n\n        template <typename ...T>\n        add_skip_layer(\n            T ...args\n        ) : \n            subnetwork(std::move(args)...) \n        {\n        }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            subnetwork.to_tensor(ibegin,iend,data);\n        }\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        )\n        {\n            subnetwork(ibegin,iend);\n            return layer<TAG_TYPE>(subnetwork).get_output();\n        }\n\n        const tensor& operator() (const input_type& x)\n        {\n            subnetwork(x);\n            return layer<TAG_TYPE>(subnetwork).get_output();\n        }\n\n        const tensor& forward(const tensor& x)\n        {\n            subnetwork.forward(x);\n            return layer<TAG_TYPE>(subnetwork).get_output();\n        }\n\n        const tensor& get_output() const \n        { \n            return layer<TAG_TYPE>(subnetwork).get_output();\n        }\n\n        tensor& get_gradient_input() \n        { \n            return layer<TAG_TYPE>(subnetwork).get_gradient_input();\n        }\n\n        const tensor& get_final_data_gradient(\n        ) const \n        { \n            return subnetwork.get_final_data_gradient(); \n        }\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        )\n        {\n            subnetwork.back_propagate_error(x, zero_grads);\n        }\n\n        template <typename solver_type>\n        void update_parameters(sstack<solver_type> solvers, double learning_rate)\n        {\n            subnetwork.update_parameters(solvers, learning_rate);\n        }\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        {\n            update_parameters(make_sstack(solvers), learning_rate);\n        }\n\n        const tensor& get_parameter_gradient(\n        ) const { return params_grad; }\n\n        tensor& get_parameter_gradient (\n        ) { return params_grad; }\n\n\n        const subnet_type& subnet() const \n        { \n            return subnetwork; \n        }\n\n        subnet_type& subnet() \n        { \n            return subnetwork; \n        }\n\n        const input_layer_type& input_layer() const { return subnet().input_layer(); } \n        input_layer_type& input_layer() { return subnet().input_layer(); } \n\n        unsigned int sample_expansion_factor() const { return subnet().sample_expansion_factor(); }\n\n        void set_gradient_inputs_to_zero()\n        {\n            subnetwork.set_gradient_inputs_to_zero();\n        }\n\n        void clean()\n        {\n            subnetwork.clean();\n        }\n\n        friend void serialize(const add_skip_layer& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.subnetwork, out);\n        }\n\n        friend void deserialize(add_skip_layer& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw serialization_error(\"Unexpected version found while deserializing dlib::add_skip_layer.\");\n            deserialize(item.subnetwork, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const add_skip_layer& item)\n        {\n            int min_length = 0;\n            item.print(out, 0, min_length);\n            return out;\n        }\n\n        void print (std::ostream& out, unsigned long idx, int& min_length) const\n        {\n            out << \"layer<\" << idx << \">\\t\"<<impl::tensor_to_str(private_get_output(), min_length) <<\"skip\"<<id<<\"\\n\";\n            subnet().print(out, idx+1, min_length);\n        }\n\n    private:\n\n\n        template <typename T, typename U, typename E>\n        friend class add_layer;\n        template <typename T, bool is_first, typename E>\n        friend class dimpl::subnet_wrapper;\n        template <unsigned long T, typename U, typename E>\n        friend class add_tag_layer;\n        template <template<typename> class T, typename U>\n        friend class add_skip_layer;\n        template <size_t N, template<typename> class L, typename S>\n        friend class repeat;\n\n        bool this_layer_requires_forward_output(\n        ) { return layer<TAG_TYPE>(subnetwork).this_layer_requires_forward_output(); } \n\n        void disable_output_and_gradient_getters (\n        ) { layer<TAG_TYPE>(subnetwork).disable_output_and_gradient_getters(); }\n\n        tensor& private_get_output() const\n        { return layer<TAG_TYPE>(subnetwork).private_get_output(); }\n        tensor& private_get_gradient_input() \n        { return layer<TAG_TYPE>(subnetwork).private_get_gradient_input(); }\n\n        subnet_type subnetwork;\n\n        // This member doesn't logically contribute to the state of the object since it is\n        // always empty. It's just here so we can have the get_parameter_gradient() methods\n        // which have to return something.  So they return this empty tensor.\n        resizable_tensor params_grad;\n    };\n    template <template<typename> class T, typename U>\n    struct is_nonloss_layer_type<add_skip_layer<T,U>> : std::true_type {};\n\n    template <typename SUBNET> using tag1  = add_tag_layer< 1, SUBNET>;\n    template <typename SUBNET> using tag2  = add_tag_layer< 2, SUBNET>;\n    template <typename SUBNET> using tag3  = add_tag_layer< 3, SUBNET>;\n    template <typename SUBNET> using tag4  = add_tag_layer< 4, SUBNET>;\n    template <typename SUBNET> using tag5  = add_tag_layer< 5, SUBNET>;\n    template <typename SUBNET> using tag6  = add_tag_layer< 6, SUBNET>;\n    template <typename SUBNET> using tag7  = add_tag_layer< 7, SUBNET>;\n    template <typename SUBNET> using tag8  = add_tag_layer< 8, SUBNET>;\n    template <typename SUBNET> using tag9  = add_tag_layer< 9, SUBNET>;\n    template <typename SUBNET> using tag10 = add_tag_layer<10, SUBNET>;\n\n    template <typename SUBNET> using skip1  = add_skip_layer< tag1, SUBNET>;\n    template <typename SUBNET> using skip2  = add_skip_layer< tag2, SUBNET>;\n    template <typename SUBNET> using skip3  = add_skip_layer< tag3, SUBNET>;\n    template <typename SUBNET> using skip4  = add_skip_layer< tag4, SUBNET>;\n    template <typename SUBNET> using skip5  = add_skip_layer< tag5, SUBNET>;\n    template <typename SUBNET> using skip6  = add_skip_layer< tag6, SUBNET>;\n    template <typename SUBNET> using skip7  = add_skip_layer< tag7, SUBNET>;\n    template <typename SUBNET> using skip8  = add_skip_layer< tag8, SUBNET>;\n    template <typename SUBNET> using skip9  = add_skip_layer< tag9, SUBNET>;\n    template <typename SUBNET> using skip10 = add_skip_layer<tag10, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    namespace timpl\n    {\n        inline void fill_with_gassuan_random_numbers (\n            tensor& t,\n            dlib::rand& rnd,\n            double sigma = 1\n        )\n        {\n            float* data = t.host();\n            for (size_t i = 0; i < t.size(); ++i)\n                data[i] = rnd.get_random_gaussian()*sigma;\n        }\n\n        class test_layer_subnet \n        {\n        public:\n            test_layer_subnet (\n                dlib::rand& rnd_\n            ) : rnd(rnd_) \n            {\n                // Output and gradient_input have to have the same dimensions in each\n                // layer.\n                const long num_samples = rnd.get_random_32bit_number()%4+3;\n                const long k  = rnd.get_random_32bit_number()%4+2;\n                const long nr = ((rnd.get_random_32bit_number()%4)/2)*2+2;\n                const long nc = ((rnd.get_random_32bit_number()%4)/2)*2+2;\n\n                output.set_size(num_samples, k, nr, nc);\n                gradient_input.set_size(num_samples, k, nr, nc);\n\n                // Use a non-zero initial gradient to make sure the layers add to it\n                // rather than assign and blow away the initial value.\n                fill_with_gassuan_random_numbers(gradient_input, rnd, 0.01);\n\n                fill_with_gassuan_random_numbers(output, rnd);\n            }\n\n\n            tensor& get_mutable_output() { return output; }\n            const tensor& get_output() const { return output; }\n            const tensor& private_get_output() const { return get_output(); }\n            const test_layer_subnet& subnet() const { init_sub(); return *subnetwork; }\n\n            tensor& get_gradient_input() { return gradient_input; }\n            tensor& private_get_gradient_input() { return get_gradient_input(); }\n            test_layer_subnet& subnet() { init_sub(); return *subnetwork; }\n\n\n\n            unsigned long count_outputs() const\n            {\n                if (subnetwork)\n                    return subnetwork->count_outputs() + output.size();\n                else\n                    return output.size();\n            }\n\n            float& get_output_element(unsigned long i)\n            {\n                if (i < output.size())\n                    return output.host()[i];\n                else\n                    return subnet().get_output_element(i-output.size());\n            }\n\n            float get_gradient_input_element(unsigned long i) const\n            {\n                if (i < gradient_input.size())\n                    return gradient_input.host()[i];\n                else\n                    return subnet().get_gradient_input_element(i-gradient_input.size());\n            }\n\n\n        private:\n            // We lazily initialize sub-layers as needed when someone tries to call\n            // subnet()\n            void init_sub() const\n            {\n                if (!subnetwork)\n                    subnetwork.reset(new test_layer_subnet(rnd));\n            }\n\n            dlib::rand& rnd;\n            mutable std::unique_ptr<test_layer_subnet> subnetwork;\n            resizable_tensor output;\n            resizable_tensor gradient_input;\n        };\n\n    }\n\n    struct layer_test_results\n    {\n        layer_test_results() : was_good(true) {}\n        explicit layer_test_results(const std::string& l) : log(l),was_good(false) {}\n\n        std::string log;\n        bool was_good;\n\n        operator bool() const { return was_good; }\n    };\n\n    inline std::ostream& operator<< (std::ostream& out, const layer_test_results& item)\n    {\n        out << item.log;\n        return out;\n    }\n\n    template <\n        typename layer_details_type\n        >\n    layer_test_results impl_test_layer (\n        layer_details_type l,\n        const float base_eps \n    )\n    {\n        using namespace timpl;\n        // Do some setup\n        running_stats<double> rs_data, rs_params;\n        dlib::rand rnd;\n        std::ostringstream sout;\n        for (int iter = 0; iter < 10; ++iter)\n        {\n            test_layer_subnet subnetwork(rnd);\n            resizable_tensor output, out2, out3;\n            // Run setup() and forward() as well to make sure any calls to subnet() have\n            // happened before we start assuming we know how many data elements there are\n            // (since we do a lazy layer creation thing based on calls to subnet() inside\n            // test_layer_subnet).\n            l.setup(subnetwork);\n            impl::call_layer_forward(l, subnetwork, output);\n\n            resizable_tensor input_grad;\n            input_grad.copy_size(output);\n            fill_with_gassuan_random_numbers(input_grad, rnd);\n\n\n            // The f() we are computing gradients of is this thing.  It's value at the current\n            // parameter and data values is:\n            //sout << \"f(data,params): \" << dot(output, input_grad) << std::endl;\n\n            // We are going to save a copy of the subnetwork.get_gradient_input() data before we do\n            // backpropagation since the backward() function is supposed to *add* to the\n            // gradients rather than overwrite them.  We will use this saved data to check if\n            // that is the case.\n            const unsigned long num_data_inputs = subnetwork.count_outputs();\n            std::vector<float> initial_gradient_input(num_data_inputs);\n            for (unsigned long i = 0; i < num_data_inputs; ++i)\n                initial_gradient_input[i] = subnetwork.get_gradient_input_element(i);\n\n\n            // Now tell the layer to compute all the gradients.  In the rest of this function\n            // we will just be checking that these gradients were computed correctly by\n            // comparing them to a central differences approximation.\n            resizable_tensor params_grad;\n            params_grad.copy_size(l.get_layer_params());\n            // But first, set the params grad to something crazy so that it's very obvious if\n            // it doesn't get fully assigned.\n            params_grad = std::numeric_limits<float>::infinity();\n            impl::call_layer_backward(l, output, input_grad, subnetwork, params_grad);\n\n            static_assert(impl::is_inplace_layer(l, subnetwork) == impl::has_inplace_backward(l, subnetwork),\n                \"Layer not defined correctly.  forward and backward methods must either both be in-place or both out-of-place. \");\n\n            // Make sure the outputs of forward() and backward() are the same when they are run\n            // in in-place mode.\n            if (impl::is_inplace_layer(l, subnetwork))\n            {\n                test_layer_subnet subnetwork2(rnd);\n                layer_details_type ll(l);\n                ll.setup(subnetwork2);\n                resizable_tensor ip_out;\n                impl::call_layer_forward(ll, subnetwork2, ip_out);\n                impl::call_layer_forward(ll, subnetwork2, subnetwork2.get_mutable_output());\n                const auto forward_error = max(abs(mat(ip_out) - mat(subnetwork2.get_output())));\n                if (forward_error > 0.00001)\n                {\n                    sout << \"This layer is supposed to support in-place computations but the output of forward_inplace()\\n\";\n                    sout << \"changes when invoked in-place vs. out-of-place. The error was: \" << forward_error << std::endl;\n                    return layer_test_results(sout.str()); \n                }\n\n                resizable_tensor params_grad;\n                params_grad.copy_size(ll.get_layer_params());\n                params_grad = std::numeric_limits<float>::infinity();\n\n                resizable_tensor input_grad;\n                input_grad.copy_size(ip_out);\n                fill_with_gassuan_random_numbers(input_grad, rnd);\n                resizable_tensor params_grad1, params_grad2, data_grad1, data_grad2;\n                params_grad1 = params_grad;\n                params_grad2 = params_grad;\n                // Now call backward() and make sure it works as well.  Recall that when an\n                // in-place layer works in-place it assigns to it's outputs but when it's\n                // not running in-place it adds.  So we initialize to a non-zero value to\n                // check that this is the behavior that really executes.\n                subnetwork2.get_gradient_input() = 9;\n                impl::call_layer_backward(ll, ip_out, input_grad, subnetwork2, params_grad1);\n                data_grad1 = subnetwork2.get_gradient_input();\n\n                subnetwork2.get_gradient_input() = mat(input_grad);\n                impl::call_layer_backward(ll, ip_out, subnetwork2.get_gradient_input(), subnetwork2, params_grad2);\n                data_grad2 = subnetwork2.get_gradient_input();\n                if (params_grad.size() != 0)\n                {\n                    const auto backward_param_error = max(abs(mat(params_grad1) - mat(params_grad2)));\n                    if (backward_param_error > 0.00001)\n                    {\n                        sout << \"This layer is supposed to support in-place computations but the output of backward_inplace()\\n\";\n                        sout << \"changes when invoked in-place vs. out-of-place. The error was: \" << backward_param_error << std::endl;\n                        return layer_test_results(sout.str()); \n                    }\n                }\n                const auto backward_data_error = max(abs(mat(data_grad1)-9 - mat(data_grad2)));\n                if (backward_data_error > 0.00001)\n                {\n                    sout << \"This layer is supposed to support in-place computations but the output of backward_inplace()\\n\";\n                    sout << \"changes when invoked in-place vs. out-of-place. The error was: \" << backward_data_error << std::endl;\n                    return layer_test_results(sout.str()); \n                }\n            }\n\n            // ==================================================================\n            // first validate the way the parameter gradients are computed\n            for (unsigned long i = 0; i < params_grad.size(); ++i)\n            {\n                layer_details_type l1(l);\n\n                float eps = l1.get_layer_params().host()[i]*base_eps;\n                if (eps == 0)\n                    eps = base_eps;\n                const float oldval = l1.get_layer_params().host()[i];\n                l1.get_layer_params().host()[i] = oldval+eps;\n                impl::call_layer_forward(l1, subnetwork, out2);\n                l1.get_layer_params().host()[i] = oldval-eps;\n                impl::call_layer_forward(l1, subnetwork, out3);\n                l1.get_layer_params().host()[i] = oldval;\n\n                // Compute a reference derivative via a central differences approximation and\n                // compare it to the one output by the layer and make sure they match.\n                double reference_derivative = (dot(out2,input_grad)-dot(out3, input_grad))/(2*eps);\n                double output_derivative = params_grad.host()[i];\n                double relative_error;\n                if (reference_derivative*output_derivative != 0)\n                    relative_error = (reference_derivative - output_derivative)/(reference_derivative);\n                else\n                    relative_error = (reference_derivative - output_derivative);\n                double absolute_error = (reference_derivative - output_derivative);\n                rs_params.add(std::abs(relative_error));\n                if (std::abs(relative_error) > 0.05 && std::abs(absolute_error) > 0.006)\n                {\n                    sout << \"Gradient error in parameter #\" << i <<\".  Relative error: \"<< relative_error << std::endl;\n                    sout << \"expected derivative: \" << reference_derivative << std::endl;\n                    sout << \"output derivative:   \" << output_derivative << std::endl;\n                    sout << \"iteration:           \" << iter << std::endl;\n                    return layer_test_results(sout.str()); \n                }\n            }\n\n            // ==================================================================\n            // now validate the data gradients\n            for (unsigned long i = 0; i < num_data_inputs; ++i)\n            {\n                const float oldval = subnetwork.get_output_element(i);\n                float eps = oldval*base_eps;\n                if (eps == 0)\n                    eps = base_eps;\n                subnetwork.get_output_element(i) = oldval+eps;\n                impl::call_layer_forward(l, subnetwork, out2);\n                subnetwork.get_output_element(i) = oldval-eps;\n                impl::call_layer_forward(l, subnetwork, out3);\n                subnetwork.get_output_element(i) = oldval;\n\n                // Compute a reference derivative via a central differences approximation and\n                // compare it to the one output by the layer and make sure they match.\n                double reference_derivative = (dot(out2,input_grad)-dot(out3, input_grad))/(2*eps);\n                double output_derivative = subnetwork.get_gradient_input_element(i);\n                output_derivative -= initial_gradient_input[i];\n                double relative_error;\n                if (reference_derivative*output_derivative != 0)\n                    relative_error = (reference_derivative - output_derivative)/(reference_derivative);\n                else\n                    relative_error = (reference_derivative - output_derivative);\n                double absolute_error = (reference_derivative - output_derivative);\n                rs_data.add(std::abs(relative_error));\n                if (std::abs(relative_error) > 0.05 && std::abs(absolute_error) > 0.006)\n                {\n                    sout << \"Gradient error in data variable #\" << i <<\".  Relative error: \"<< relative_error << std::endl;\n                    sout << \"expected derivative: \" << reference_derivative << std::endl;\n                    sout << \"output derivative:   \" << output_derivative << std::endl;\n                    sout << \"iteration:           \" << iter << std::endl;\n                    return layer_test_results(sout.str()); \n                }\n            }\n\n        } // end for (int iter = 0; iter < 10; ++iter)\n\n        if (rs_params.mean() > 0.003)\n        {\n            sout << \"Average parameter gradient error is somewhat large at: \"<< rs_params.mean() << std::endl;\n            return layer_test_results(sout.str()); \n        }\n        if (rs_data.mean() > 0.003)\n        {\n            sout << \"Average data gradient error is somewhat large at: \"<< rs_data.mean() << std::endl;\n            return layer_test_results(sout.str()); \n        }\n\n        return layer_test_results();\n    }\n\n    template <\n        typename layer_details_type\n        >\n    layer_test_results test_layer (\n        layer_details_type l\n    )\n    {\n        // Try a few different derivative step sizes to see if any work. \n        for (float base_eps = 0.0001; base_eps < 0.1; base_eps *= 2)\n        {\n            auto result = impl_test_layer(l, base_eps);\n            if (result)\n                return result;\n        }\n        // However, if none of the step sizes worked then try this one and probably result\n        // in returning an error.\n        return impl_test_layer(l, 0.01);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <size_t i, size_t num>\n        struct vl_loop\n        {\n            template <\n                typename net_type,\n                typename visitor\n                >\n            static void visit(\n                net_type& net,\n                visitor&& v\n            )\n            {\n                // Call whatever version of the visitor the user provided.\n                call_if_valid(v, i, layer<i>(net));\n                call_if_valid(v, layer<i>(net));\n                vl_loop<i+1, num>::visit(net,v);\n            }\n        };\n\n        template <size_t num>\n        struct vl_loop<num,num>\n        {\n            template <\n                typename net_type,\n                typename visitor\n                >\n            static void visit(\n                net_type&,\n                visitor&& \n            )\n            {\n                // Base case of recursion.  Don't do anything.\n            }\n        };\n\n        template <size_t i, size_t num>\n        struct vl_loop_backwards\n        {\n            template <\n                typename net_type,\n                typename visitor\n                >\n            static void visit(\n                net_type& net,\n                visitor&& v\n            )\n            {\n                vl_loop_backwards<i+1, num>::visit(net,v);\n                // Call whatever version of the visitor the user provided.\n                call_if_valid(v, i, layer<i>(net));\n                call_if_valid(v, layer<i>(net));\n            }\n        };\n\n        template <size_t num>\n        struct vl_loop_backwards<num,num>\n        {\n            template <\n                typename net_type,\n                typename visitor\n                >\n            static void visit(\n                net_type&,\n                visitor&& \n            )\n            {\n                // Base case of recursion.  Don't do anything.\n            }\n        };\n\n    }\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers(\n        net_type& net,\n        visitor v\n    )\n    {\n        impl::vl_loop<0, net_type::num_layers>::visit(net, v);\n    }\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_backwards(\n        net_type& net,\n        visitor v\n    )\n    {\n        impl::vl_loop_backwards<0, net_type::num_layers>::visit(net, v);\n    }\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_range(\n        net_type& net,\n        visitor v\n    )\n    {\n        static_assert(begin <= end, \"Invalid range\");\n        static_assert(end <= net_type::num_layers, \"Invalid range\");\n        impl::vl_loop<begin,end>::visit(net, v);\n    }\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_backwards_range(\n        net_type& net,\n        visitor v\n    )\n    {\n        static_assert(begin <= end, \"Invalid range\");\n        static_assert(end <= net_type::num_layers, \"Invalid range\");\n        impl::vl_loop_backwards<begin,end>::visit(net, v);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <size_t i, unsigned long tag_id>\n        struct vl_until_tag\n        {\n            template <\n                typename net_type,\n                typename next_net_type,\n                typename visitor\n                >\n            static void visit(\n                net_type& net,\n                next_net_type& next_net,\n                visitor&& v\n            )\n            {\n                call_if_valid(v, next_net);\n                vl_until_tag<i+1,tag_id>::visit(net,layer<i+1>(net),v);\n            }\n\n            template <\n                typename net_type,\n                typename SUBNET,\n                typename visitor\n                >\n            static void visit(\n                net_type&,\n                const add_tag_layer<tag_id,SUBNET>& next_net,\n                visitor&& v\n            )\n            {\n                call_if_valid(v, next_net);\n            }\n\n            template <\n                typename net_type,\n                typename SUBNET,\n                typename visitor\n                >\n            static void visit(\n                net_type&,\n                add_tag_layer<tag_id,SUBNET>& next_net,\n                visitor&& v\n            )\n            {\n                call_if_valid(v, next_net);\n            }\n        };\n    }\n\n    template <\n        unsigned long tag_id,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_until_tag(\n        net_type& net,\n        visitor v\n    )\n    {\n        impl::vl_until_tag<0,tag_id>::visit(net, net, v);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl \n    {\n        template <\n            typename visitor\n            >\n        class visitor_computational_layer\n        {\n        public:\n            explicit visitor_computational_layer(visitor& v) : v_(v) {}\n\n            template <typename layer>\n            void do_visit(size_t idx, layer& l) const\n            {\n                // Call whatever version of the visitor the user provided.\n                call_if_valid(v_, idx, l.layer_details());\n                call_if_valid(v_, l.layer_details());\n            }\n\n            // const case\n            template <typename T, typename U, typename E>\n            void operator()(size_t idx, const add_layer<T,U,E>& l) const { do_visit(idx, l); }\n            // non-const cast\n            template <typename T, typename U, typename E>\n            void operator()(size_t idx, add_layer<T,U,E>& l) const { do_visit(idx, l); }\n\n        private:\n\n            visitor& v_;\n        };\n    }\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_computational_layers(\n        net_type& net,\n        visitor v\n    )\n    {\n        visit_layers(net, impl::visitor_computational_layer<visitor>(v));\n    }\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_computational_layers_range(\n        net_type& net,\n        visitor v\n    )\n    {\n        visit_layers_range<begin,end>(net, impl::visitor_computational_layer<visitor>(v));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename visitor\n            >\n        class visit_layer_parameters\n        {\n        public:\n            explicit visit_layer_parameters(visitor& v) : v_(v) {}\n\n            template <typename layer>\n            void operator()(layer& l)\n            {\n                // Call whatever version of the visitor the user provided.\n                const bool visitor_called = call_if_valid(v_, computational_layer_idx, l.get_layer_params()) ||\n                    call_if_valid(v_, l.get_layer_params());\n                DLIB_CASSERT(visitor_called, \"A visitor function with an incorrect signature was given to visit_layer_parameters()\");\n                ++computational_layer_idx;\n            }\n        private:\n\n            size_t computational_layer_idx = 0;\n            visitor& v_;\n        };\n    }\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layer_parameters(\n        net_type& net,\n        visitor v\n    )\n    {\n        visit_computational_layers(net, impl::visit_layer_parameters<visitor>(v));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl \n    {\n        template <\n            typename visitor\n            >\n        class visit_layer_parameter_gradients\n        {\n        public:\n            explicit visit_layer_parameter_gradients(visitor& v) : v_(v) {}\n\n            template <typename layer>\n            void do_visit(layer& l) \n            {\n                // Call whatever version of the visitor the user provided.\n                const bool visitor_called = call_if_valid(v_, computational_layer_idx, l.get_parameter_gradient()) ||\n                    call_if_valid(v_, l.get_parameter_gradient());\n                DLIB_CASSERT(visitor_called, \"A visitor function with an incorrect signature was given to visit_layer_parameter_gradients()\");\n                ++computational_layer_idx;\n            }\n\n            // const version\n            template <typename T, typename U, typename E>\n            void operator()(const add_layer<T,U,E>& l) { do_visit(l); }\n            // non-const version\n            template <typename T, typename U, typename E>\n            void operator()(add_layer<T,U,E>& l) { do_visit(l); }\n\n        private:\n\n            size_t computational_layer_idx = 0;\n            visitor& v_;\n        };\n    }\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layer_parameter_gradients(\n        net_type& net,\n        visitor v\n    )\n    {\n        visit_layers(net, impl::visit_layer_parameter_gradients<visitor>(v));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_CORE_H_\n\n\n"
  },
  {
    "path": "dlib/dnn/core_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_CORE_ABSTRACT_H_\n#ifdef DLIB_DNn_CORE_ABSTRACT_H_\n\n#include \"../cuda/tensor_abstract.h\"\n#include <memory>\n#include <type_traits>\n#include <tuple>\n#include <vector>\n#include \"../rand.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename... T \n        >\n    auto tuple_tail(\n        const std::tuple<T...>& item \n    );\n    /*!\n        ensures\n            - returns a tuple that contains everything in item except for tuple_head(item).\n              The items will be in the same order as they are in item, just without\n              tuple_head(item).\n            - This function will correctly handle nested tuples.\n    !*/\n\n    template <typename... T>\n    auto tuple_head (\n        const std::tuple<T...>& item\n    ); \n    /*!\n        ensures\n            - returns a copy of the first thing in the tuple that isn't a std::tuple.\n              Essentially, this function calls std::get<0>() recursively on item until\n              a non-std::tuple object is found.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_learning_rate_multiplier(\n        const T& obj\n    ); \n    /*!\n        ensures\n            - if (obj has a get_learning_rate_multiplier() member function) then\n                - returns obj.get_learning_rate_multiplier()\n            - else\n                - returns 1\n    !*/\n\n    template <typename T>\n    void set_learning_rate_multiplier(\n        T& obj,\n        double learning_rate_multiplier\n    );\n    /*!\n        requires\n            - learning_rate_multiplier >= 0\n        ensures\n            - if (obj has a set_learning_rate_multiplier() member function) then\n                - calls obj.set_learning_rate_multiplier(learning_rate_multiplier)\n            - else\n                - does nothing\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_bias_learning_rate_multiplier(\n        const T& obj\n    );\n    /*!\n        ensures\n            - if (obj has a get_bias_learning_rate_multiplier() member function) then\n                - returns obj.get_bias_learning_rate_multiplier()\n            - else\n                - returns 1\n    !*/\n\n    template <typename T>\n    void set_bias_learning_rate_multiplier(\n        T& obj,\n        double bias_learning_rate_multiplier\n    );\n    /*!\n        requires\n            - bias_learning_rate_multiplier >= 0\n        ensures\n            - if (obj has a set_bias_learning_rate_multiplier() member function) then\n                - calls obj.set_bias_learning_rate_multiplier(bias_learning_rate_multiplier)\n            - else\n                - does nothing\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_weight_decay_multiplier(\n        const T& obj\n    );\n    /*!\n        ensures\n            - if (obj has a get_weight_decay_multiplier() member function) then\n                - returns obj.get_weight_decay_multiplier()\n            - else\n                - returns 1\n    !*/\n\n    template <typename T>\n    void set_weight_decay_multiplier(\n        T& obj,\n        double weight_decay_multiplier\n    );\n    /*!\n        requires\n            - weight_decay_multiplier >= 0\n        ensures\n            - if (obj has a set_weight_decay_multiplier() member function) then\n                - calls obj.set_weight_decay_multiplier(weight_decay_multiplier)\n            - else\n                - does nothing\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double get_bias_weight_decay_multiplier(\n        const T& obj\n    ); \n    /*!\n        ensures\n            - if (obj has a get_bias_weight_decay_multiplier() member function) then\n                - returns obj.get_bias_weight_decay_multiplier()\n            - else\n                - returns 1\n    !*/\n\n    template <typename T>\n    void set_bias_weight_decay_multiplier(\n        T& obj,\n        double bias_weight_decay_multiplier\n    );\n    /*!\n        requires:\n            - bias_weight_decay_multiplier >= 0\n        ensures\n            - if (obj has a set_bias_weight_decay_multiplier() member function) then\n                - calls obj.set_bias_weight_decay_multiplier(bias_weight_decay_multiplier)\n            - else\n                - does nothing\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void disable_bias(\n        T& obj\n    );\n    /*!\n        ensures\n            - if (obj has a disable_bias() member function) then\n                - calls obj.disable_bias()\n            - else\n                - does nothing\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool dnn_prefer_fastest_algorithms(\n    );\n    /*!\n        ensures\n            - If dlib should prefer to use fast algorithms rather than ones that use less\n              RAM then this function returns true and false otherwise.\n            - On program startup this function will default to true.\n    !*/\n\n    void set_dnn_prefer_fastest_algorithms(\n    );\n    /*!\n        ensures\n            - #dnn_prefer_fastest_algorithms() == true\n    !*/\n\n    void set_dnn_prefer_smallest_algorithms(\n    );\n    /*!\n        ensures\n            - #dnn_prefer_fastest_algorithms() == false \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class sstack\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a basic stack of T objects.  It contains no data itself but simply\n                points to a memory range of T object and allows you to access that block of\n                T objects as a stack.\n        !*/\n\n    public:\n        typedef T value_type;\n\n        sstack() = delete;\n\n        sstack (\n            T* data,\n            size_t s\n        );\n        /*!\n            ensures\n                - #size() == s\n                - #top() == *data\n                - #pop(i).top() == data[i]\n        !*/\n\n        const T& top(\n        ) const;\n        /*!\n            requires\n                - size() != 0\n            ensures\n                - returns the top element of the stack.\n        !*/\n\n        T& top(\n        );\n        /*!\n            requires\n                - size() != 0\n            ensures\n                - returns the top element of the stack.  \n        !*/\n\n        size_t size(\n        ) const;\n        /*!\n            ensures\n                - returns the number of elements in this stack.  \n        !*/\n\n        sstack pop(\n            size_t num = 1\n        ); \n        /*!\n            requires\n                - num <= size()\n            ensures\n                - returns a reference to the sub-stack S such that:\n                    - S.size() == size()-num.\n                    - S.top() is num elements down the stack. \n        !*/\n    };\n\n    template <\n        typename T\n        >\n    sstack<T> make_sstack(\n        std::vector<T>& item\n    ) { return sstack<T>(item.data(), item.size()); }\n    /*!\n        ensures\n            - returns a sstack that sits on top of the given std::vector.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    enum class zero_gradients : uint8_t\n    {\n        no,\n        yes\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename LAYER_DETAILS, \n        typename SUBNET\n        >\n    class add_layer\n    {\n        /*!\n            REQUIREMENTS ON LAYER_DETAILS\n                - Must be a type that implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                  defined in layers_abstract.h\n\n            REQUIREMENTS ON SUBNET\n                - One of the following must be true:\n                    - SUBNET implements the EXAMPLE_INPUT_LAYER interface defined in\n                      input_abstract.h.\n                    - SUBNET is an add_layer object.\n                    - SUBNET is an add_tag_layer object.\n                    - SUBNET is an add_skip_layer object.\n                    - SUBNET is a repeat object.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a deep neural network.  In particular, it is a tool\n                for adding another layer on top of the neural network of type SUBNET, which\n                is specified as a template argument.  The specific layer added is defined\n                by the LAYER_DETAILS details template argument.\n        !*/\n\n    public:\n        typedef LAYER_DETAILS layer_details_type;\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        // num_computational_layers will always give the number of layers in the network\n        // that transform tensors (i.e. layers defined by something that implements the\n        // EXAMPLE_COMPUTATIONAL_LAYER_ interface).  This is all the layers except for\n        // loss, tag, and skip layers.\n        const static size_t num_computational_layers = subnet_type::num_computational_layers + 1;\n        // num_layers counts all the layers in the network regardless of their type.  \n        const static size_t num_layers = subnet_type::num_layers + 1;\n\n        add_layer(\n        );\n        /*!\n            ensures\n                - default constructs all the layers in this network.\n                - #sample_expansion_factor() == 0\n        !*/\n\n        add_layer(const add_layer&) = default;\n        add_layer(add_layer&&) = default;\n        add_layer& operator=(add_layer&&) = default;\n        add_layer& operator=(const add_layer&) = default;\n        /*!\n            ensures\n                - this object is copyable and movable.\n        !*/\n\n        template <typename T, typename U>\n        add_layer(\n            const add_layer<T,U>& item\n        );\n        /*!\n            ensures\n                - This constructor allows you to copy neural network objects from one to\n                  another as long as their corresponding layers can be constructed from\n                  each other.\n                - #layer_details() == layer_details_type(item.layer_details())\n                - #subnet()        == subnet_type(item.subnet())\n                - #sample_expansion_factor() == item.sample_expansion_factor()\n        !*/\n\n        template <typename ...T, typename LD, typename ...U>\n        add_layer(\n            const std::tuple<LD,U...>& layer_det, \n            T&& ...args\n        );\n        /*!\n            ensures\n                - #layer_details() == layer_details_type(tuple_head(layer_det))\n                - #subnet()        == subnet_type(tuple_tail(layer_det),args)\n                - #sample_expansion_factor() == 0 \n        !*/\n\n        template <typename ...T>\n        add_layer(\n            const layer_details_type& layer_det, \n            T&& ...args\n        );\n        /*!\n            ensures\n                - #layer_details() == layer_details_type(layer_det)\n                - #subnet()        == subnet_type(args)\n                - #sample_expansion_factor() == 0 \n        !*/\n\n        template <typename ...T>\n        add_layer(\n            T&& ...args\n        );\n        /*!\n            ensures\n                - This version of the constructor is only called if layer_details_type\n                  can't be constructed from the first thing in args.  In this case, the\n                  args are simply passed on to the sub layers in their entirety.\n                - #layer_details() == layer_details_type()\n                - #subnet()        == subnet_type(args)\n                - #sample_expansion_factor() == 0 \n        !*/\n\n        template <typename ...T>\n        add_layer(\n            layer_details_type&& layer_det, \n            T&& ...args\n        );\n        /*!\n            ensures\n                - #layer_details() == layer_det\n                - #subnet()        == subnet_type(args)\n                - #sample_expansion_factor() == 0 \n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.\n                - #data.num_samples()%distance(ibegin,iend) == 0. \n                - #sample_expansion_factor() == #data.num_samples()/distance(ibegin,iend).\n                - #sample_expansion_factor() > 0\n                - The data in the ith sample of #data corresponds to the input_type object\n                  *(ibegin+i/#sample_expansion_factor()).\n                - Invokes data.async_copy_to_device() so that the data begins transferring\n                  to the GPU device, if present.\n                - This function is implemented by calling the to_tensor() routine defined\n                  at the input layer of this network.  \n        !*/\n\n        unsigned int sample_expansion_factor (\n        ) const;\n        /*!\n            ensures\n                - When to_tensor() is invoked on this network's input layer it converts N\n                  input objects into M samples, all stored inside a resizable_tensor.  It\n                  is always the case that M is some integer multiple of N.\n                  sample_expansion_factor() returns the value of this multiplier.  To be\n                  very specific, it is always true that M==I*N where I is some integer.\n                  This integer I is what is returned by sample_expansion_factor().\n        !*/\n\n        const subnet_type& subnet(\n        ) const; \n        /*!\n            ensures\n                - returns the immediate subnetwork of *this network.  \n        !*/\n\n        subnet_type& subnet(\n        );\n        /*!\n            ensures\n                - returns the immediate subnetwork of *this network.  \n        !*/\n\n        const input_layer_type& input_layer(\n        ) const;  \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        input_layer_type& input_layer(\n        ); \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        const layer_details_type& layer_details(\n        ) const; \n        /*!\n            ensures\n                - returns the layer_details_type instance that defines the behavior of the\n                  layer at the top of this network.  I.e. returns the layer details that\n                  defines the behavior of the layer nearest to the network output rather\n                  than the input layer.\n        !*/\n\n        layer_details_type& layer_details(\n        );\n        /*!\n            ensures\n                - returns the layer_details_type instance that defines the behavior of the\n                  layer at the top of this network.  I.e. returns the layer details that\n                  defines the behavior of the layer nearest to the network output rather\n                  than the input layer.\n        !*/\n\n        template <typename forward_iterator>\n        const tensor& operator() (\n            forward_iterator ibegin,\n            forward_iterator iend\n        );\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - runs [ibegin,iend) through the network and returns the results.\n                  In particular, this function performs:\n                    to_tensor(ibegin,iend,temp_tensor);\n                    return forward(temp_tensor);\n                - The return value from this function is also available in #get_output().\n                  i.e. this function returns #get_output().\n                - have_same_dimensions(#get_gradient_input(), #get_output()) == true.\n                - All elements of #get_gradient_input() are set to 0. \n                  i.e. calling this function clears out #get_gradient_input() and ensures\n                  it has the same dimensions as the most recent output.\n        !*/\n\n        const tensor& operator() (\n            const input_type& x\n        );\n        /*!\n            ensures\n                - runs a single x through the network and returns the output.\n                  I.e. returns (*this)(&x, &x+1);\n        !*/\n\n        const tensor& forward(\n            const tensor& x\n        );\n        /*!\n            requires\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n            ensures\n                - Runs x through the network and returns the results.  In particular, this\n                  function performs the equivalent of:\n                    subnet().forward(x);\n                    if (this is the first time forward() has been called) then\n                        layer_details().setup(subnet());\n                    layer_details().forward(subnet(), get_output());\n                - The return value from this function is also available in #get_output().\n                  i.e. this function returns #get_output().\n                - have_same_dimensions(#get_gradient_input(), #get_output()) == true\n                - All elements of #get_gradient_input() are set to 0. \n                  i.e. calling this function clears out #get_gradient_input() and ensures\n                  it has the same dimensions as the most recent output.\n        !*/\n\n        const tensor& get_output(\n        ) const;\n        /*!\n            ensures\n                - returns the output for the last tensor that was run through the network.\n                  If nothing has been run through the network yet then returns an empty\n                  tensor. \n        !*/\n\n        tensor& get_gradient_input(\n        );\n        /*!\n            ensures\n                - returns the error gradient for this network.  That is, this is the error\n                  gradient that this network will use to compute parameter gradients when\n                  back_propagate_error() is called.  Therefore, when performing back\n                  propagation, layers that sit on top of this network layer write their\n                  back-propagated error gradients into get_gradient_input().  Or to put it\n                  another way, during back-propagation, layers take the contents of their\n                  get_gradient_input() and back-propagate it through themselves and store\n                  the result into their subnetwork's get_gradient_input().\n\n                  This means you should consider get_gradient_input() as an input to the\n                  back_propagate_error() method.  \n        !*/\n\n        const tensor& get_final_data_gradient(\n        ) const;\n        /*!\n            ensures\n                - if back_propagate_error() has been called to back-propagate a gradient\n                  through this network then you can call get_final_data_gradient() to\n                  obtain the last data gradient computed.  That is, this function returns\n                  the gradient of the network with respect to its inputs.\n                - Note that there is only one \"final data gradient\" for an entire network,\n                  not one per layer, since there is only one input to the entire network.\n        !*/\n\n        const tensor& get_parameter_gradient(\n        ) const; \n        /*!\n            ensures\n                - if back_propagate_error() has been called then you can call\n                  get_parameter_gradient() to find the gradient of this layer's parameters.\n                  When we update the parameters by calling update_parameters(), it will use\n                  the gradient in get_parameter_gradient() to perform the update.\n                  Therefore, you should consider get_parameter_gradient() as an input to\n                  update_parameters().\n        !*/\n\n        tensor& get_parameter_gradient (\n        ); \n        /*!\n            ensures\n                - returns a non-const reference to the tensor returned by the above\n                  get_parameter_gradient() method.  You could use this method to modify the\n                  parameter gradient in some way before invoking update_parameters().\n        !*/\n\n        void back_propagate_error(\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - forward(x) was called to forward propagate x though the network.\n                  Moreover, this was the most recent call to forward() and x has not been\n                  subsequently modified in any way.\n                - get_gradient_input() has been set equal to the gradient of this network's\n                  output with respect to some loss function.\n            ensures\n                - Back propagates the error gradient, get_gradient_input(), through this\n                  network and computes parameter and data gradients, via backpropagation.\n                  Specifically, this function populates get_final_data_gradient() and also,\n                  for each layer, the tensor returned by get_parameter_gradient().\n                - All elements of #get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - have_same_dimensions(#get_final_data_gradient(), x) == true.\n                - have_same_dimensions(#get_parameter_gradient(), layer_details().get_layer_params()) == true.\n                - #get_final_data_gradient() contains the gradient of the network with\n                  respect to x.\n        !*/\n\n        void back_propagate_error(\n            const tensor& x, \n            const tensor& gradient_input,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - forward(x) was called to forward propagate x though the network.\n                  Moreover, this was the most recent call to forward() and x has not been\n                  subsequently modified in any way.\n                - have_same_dimensions(gradient_input, get_output()) == true\n            ensures\n                - This function is identical to the version of back_propagate_error()\n                  defined immediately above except that it back-propagates gradient_input\n                  through the network instead of get_gradient_input().  Therefore, this\n                  version of back_propagate_error() is equivalent to performing:\n                    get_gradient_input() = gradient_input;\n                    back_propagate_error(x);\n                  Except that calling back_propagate_error(x,gradient_input) avoids the\n                  copy and is therefore slightly more efficient.\n                - All elements of #get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - have_same_dimensions(#get_final_data_gradient(), x) == true.\n                - have_same_dimensions(#get_parameter_gradient(), layer_details().get_layer_params()) == true.\n                - #get_final_data_gradient() contains the gradient of the network with\n                  respect to x.\n        !*/\n\n        template <typename solver_type>\n        void update_parameters(\n            sstack<solver_type> solvers, \n            double learning_rate\n        );\n        /*!\n            requires\n                - solver_type is an implementation of the EXAMPLE_SOLVER interface defined\n                  in solvers_abstract.h\n                - back_propagate_error() has been called.\n                - The given solvers have only ever been used with this network.  That is,\n                  if you want to call update_parameters() on some other neural network\n                  object then you must NOT reuse the same solvers object.\n                - solvers.size() >= num_computational_layers\n                - 0 < learning_rate <= 1\n            ensures\n                - Updates all the parameters in the network.  In particular, we pass each\n                  layer's parameter gradient (i.e. the tensor returned by the layer's\n                  get_parameter_gradient() member) through that layer's corresponding\n                  solver object.  This produces a parameter delta vector which we add to\n                  the layer's parameters.\n                - The solvers use the given learning rate.\n        !*/\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate)\n        { update_parameters(make_sstack(solvers), learning_rate); }\n        /*!\n            Convenience method for calling update_parameters()\n        !*/\n\n        void set_gradient_inputs_to_zero(\n        );\n        /*!\n            ensures\n                - Sets all elements in all gradient inputs in the network to 0.\n                  That is, for each layer, we will have:\n                    - get_gradient_input() == 0\n                - Note that You only need to call this method if you manually called either\n                    - back_propagate_error\n                    - compute_parameter_gradients\n                  with the zero_grads parameter set to zero_gradients::no.\n                - invokes subnet().set_gradient_inputs_to_zero()\n        !*/\n\n        void clean(\n        );\n        /*!\n            ensures\n                - Causes the network to forget about everything but its parameters.  \n                  That is, for each layer we will have:\n                    - get_output().num_samples() == 0\n                    - get_gradient_input().num_samples() == 0\n                  However, running new input data though this network will still produce\n                  the same output it would have produced regardless of any calls to\n                  clean().  The purpose of clean() is to compact the network object prior\n                  to saving it to disk so that it takes up less space and the IO is\n                  quicker.\n                - This also calls the .clean() method on any layer details objects that \n                  define a .clean() method.\n        !*/\n\n    };\n\n    template <typename T, typename U> \n    std::ostream& operator<<(std::ostream& out, const add_layer<T,U>& item);\n    /*!\n        prints the network architecture to the given output stream.\n    !*/\n\n    template <typename T, typename U> \n    void serialize(const add_layer<T,U>& item, std::ostream& out);\n    template <typename T, typename U> \n    void deserialize(add_layer<T,U>& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class no_label_type;\n\n    template <\n        typename LOSS_DETAILS, \n        typename SUBNET\n        >\n    class add_loss_layer\n    {\n        /*!\n            REQUIREMENTS ON LOSS_DETAILS \n                - Must be a type that implements the EXAMPLE_LOSS_LAYER_ interface defined\n                  in loss_abstract.h\n\n            REQUIREMENTS ON SUBNET\n                - One of the following must be true:\n                    - SUBNET is an add_layer object.\n                    - SUBNET is an add_tag_layer object.\n                    - SUBNET is an add_skip_layer object.\n                    - SUBNET is a repeat object.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a deep neural network.  In particular, it is a tool\n                for adding a loss layer on top of the neural network of type SUBNET, which\n                is specified as a template argument.  The specific layer added is defined\n                by the LOSS_DETAILS details template argument.  Importantly, a loss layer\n                is the last layer in a deep neural network.  So once it is added you can't\n                add any other layers of any type.\n        !*/\n\n    public:\n        typedef LOSS_DETAILS loss_details_type;\n        typedef SUBNET subnet_type;\n        typedef typename subnet_type::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        const static size_t num_computational_layers = subnet_type::num_computational_layers;\n        const static size_t num_layers = subnet_type::num_layers + 1;\n        // If LOSS_DETAILS is an unsupervised loss then training_label_type==no_label_type.\n        // Otherwise it is defined as follows:\n        typedef typename LOSS_DETAILS::training_label_type training_label_type;\n        // Similarly, if LOSS_DETAILS doesn't provide any output conversion then\n        // output_label_type==no_label_type.\n        typedef typename LOSS_DETAILS::output_label_type output_label_type;\n\n\n\n        add_loss_layer() = default;\n        /*!\n            ensures\n                - default constructs all the layers in this network.\n        !*/\n\n        add_loss_layer(const add_loss_layer&) = default;\n        add_loss_layer(add_loss_layer&&) = default;\n        add_loss_layer& operator=(add_loss_layer&&) = default;\n        add_loss_layer& operator=(const add_loss_layer&) = default;\n        /*!\n            ensures\n                - this object is copyable and movable.\n        !*/\n\n        template <typename T, typename U>\n        add_loss_layer(\n            const add_loss_layer<T,U>& item\n        );\n        /*!\n            ensures\n                - This constructor allows you to copy neural network objects from one to\n                  another as long as their corresponding layers can be constructed from\n                  each other.\n                - #loss_details() == loss_details_type(item.loss_details())\n                - #subnet()       == subnet_type(item.subnet())\n        !*/\n\n        template <typename ...T>\n        add_loss_layer(\n            const LOSS_DETAILS& layer_det, \n            T&& ...args\n        ); \n        /*!\n            ensures\n                - #loss_details() == loss_details_type(layer_det)\n                - #subnet()       == subnet_type(args)\n        !*/\n\n        template <typename ...T>\n        add_loss_layer(\n            LOSS_DETAILS&& layer_det, \n            T&& ...args\n        );\n        /*!\n            ensures\n                - #loss_details() == loss_details_type(layer_det)\n                - #subnet()       == subnet_type(args)\n        !*/\n\n        template <typename ...T>\n        add_loss_layer(\n            T&& ...args\n        ); \n        /*!\n            ensures\n                - This version of the constructor is only called if loss_details_type can't\n                  be constructed from the first thing in args.  In this case, the args are\n                  simply passed on to the sub layers in their entirety.\n                - #loss_details() == loss_details_type()\n                - #subnet()       == subnet_type(args)\n        !*/\n\n        const subnet_type& subnet(\n        ) const; \n        /*!\n            ensures\n                - returns the immediate subnetwork of *this network.  \n        !*/\n\n        subnet_type& subnet(\n        ); \n        /*!\n            ensures\n                - returns the immediate subnetwork of *this network.  \n        !*/\n\n        const input_layer_type& input_layer(\n        ) const;  \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        input_layer_type& input_layer(\n        ); \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        const loss_details_type& loss_details(\n        ) const; \n        /*!\n            ensures\n                - returns the loss_details_type instance that defines the behavior of the\n                  loss layer used by this network.\n        !*/\n\n        loss_details_type& loss_details(\n        ); \n        /*!\n            ensures\n                - returns the loss_details_type instance that defines the behavior of the\n                  loss layer used by this network.\n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.\n                - #data.num_samples()%distance(ibegin,iend) == 0. \n                - #sample_expansion_factor() == #data.num_samples()/distance(ibegin,iend).\n                - #sample_expansion_factor() > 0\n                - The data in the ith sample of #data corresponds to the input_type object\n                  *(ibegin+i/sample_expansion_factor()).\n                - Invokes data.async_copy_to_device() so that the data begins transferring\n                  to the GPU device, if present.\n                - This function is implemented by calling the to_tensor() routine defined\n                  at the input layer of this network.  \n        !*/\n\n        unsigned int sample_expansion_factor (\n        ) const;\n        /*!\n            ensures\n                - When to_tensor() is invoked on this network's input layer it converts N\n                  input objects into M samples, all stored inside a resizable_tensor.  It\n                  is always the case that M is some integer multiple of N.\n                  sample_expansion_factor() returns the value of this multiplier.  To be\n                  very specific, it is always true that M==I*N where I is some integer.\n                  This integer I is what is returned by sample_expansion_factor().\n        !*/\n\n    // -------------\n\n        const tensor& forward(const tensor& x\n        ); \n        /*!\n            requires\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n            ensures\n                - Runs x through the network and returns the results as a tensor.  In particular,\n                  this function just performs:\n                    return subnet().forward(x);\n                  So if you want to get the outputs as an output_label_type then call one of the\n                  methods below instead, like operator().\n                - The return value from this function is also available in #subnet().get_output().\n                  i.e. this function returns #subnet().get_output().\n                - have_same_dimensions(#subnet().get_gradient_input(), #subnet().get_output()) == true\n                - All elements of #subnet().get_gradient_input() are set to 0. \n                  i.e. calling this function clears out #subnet().get_gradient_input() and ensures\n                  it has the same dimensions as the most recent output.\n        !*/\n\n        template <typename output_iterator>\n        void operator() (\n            const tensor& x, \n            output_iterator obegin\n        );\n        /*!\n            requires\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n                - obegin == iterator pointing to the start of a range of\n                  x.num_samples()/sample_expansion_factor() output_label_type elements.\n            ensures\n                - runs x through the network and writes the output to the range at obegin.\n                - loss_details().to_label() is used to write the network output into\n                  obegin.\n        !*/\n\n        template <typename forward_iterator, typename label_iterator>\n        void operator() (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            label_iterator obegin\n        );\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - obegin == iterator pointing to the start of a range of\n                  std::distance(ibegin,iend) output_label_type elements.\n            ensures\n                - runs [ibegin,iend) through the network and writes the output to the range\n                  at obegin.\n                - loss_details().to_label() is used to write the network output into\n                  obegin.\n        !*/\n\n    // -------------\n\n        const output_label_type& operator() (\n            const input_type& x\n        );\n        /*!\n            ensures\n                - runs a single object, x, through the network and returns the output.\n                - loss_details().to_label() is used to convert the network output into a\n                  output_label_type.\n        !*/\n\n        template <typename iterable_type>\n        std::vector<output_label_type> operator() (\n            const iterable_type& data,\n            size_t batch_size = 128\n        );\n        /*!\n            requires\n                - batch_size > 0\n                - data must have a .begin() and .end() that supply iterators over a\n                  sequence of input_type elements.  E.g. data could have a type of\n                  std::vector<input_type>\n            ensures\n                - runs all the objects in data through the network and returns their\n                  predicted labels.  This means this function returns a vector V such that:\n                    - V.size() == data.size()\n                    - for all valid i: V[i] == the predicted label of data[i].\n                - Elements of data are run through the network in batches of batch_size\n                  items.  Using a batch_size > 1 can be faster because it better exploits\n                  the available hardware parallelism.\n                - loss_details().to_label() is used to convert the network output into a\n                  output_label_type.\n        !*/\n\n        template <typename ...T>\n        const output_label_type& process (\n            const input_type& x, \n            T&& ...args\n        );\n        /*!\n            ensures\n                - This function is just like (*this)(x), i.e. it runs a single object, x,\n                  through the network and returns the output.  But we additionally pass the \n                  given args to loss_details().to_label() as the 4th argument (or more,\n                  depending on how many things are in args) when converting the network\n                  output to an output_label_type.  This is useful, for instance, with loss\n                  layers like loss_mmod_ which has an optional adjust_threshold argument to\n                  to_label() that adjusts the detection threshold.  Therefore, for such\n                  networks you could call them like: net.process(some_image, -0.5), and -0.5\n                  would be passed so the adjust_threshold argument of to_tensor().\n        !*/\n\n        template <typename iterable_type, typename ...T>\n        std::vector<output_label_type> process_batch (\n            const iterable_type& data, \n            size_t batch_size, \n            T&& ...args\n        );\n        /*!\n            requires\n                - batch_size > 0\n                - data must have a .begin() and .end() that supply iterators over a\n                  sequence of input_type elements.  E.g. data could have a type of\n                  std::vector<input_type>\n            ensures\n                - This function is just like (*this)(data,batch_size), i.e. it runs a\n                  bunch of objects through the network and returns the outputs.  But we\n                  additionally pass the given args to loss_details().to_label() as the 4th\n                  argument (or more, depending on how many things are in args) when\n                  converting the network output to output_label_types.  This is useful,\n                  for instance, with loss layers like loss_mmod_ which has an optional\n                  adjust_threshold argument to to_label() that adjusts the detection\n                  threshold.  Therefore, for such networks you could call them like:\n                  net.process_batch(std::vector<image_type>({some_image, another_image}), 128, -0.5), \n                  and -0.5 would be passed so the adjust_threshold argument of to_tensor().\n        !*/\n\n    // -------------\n\n        template <typename label_iterator>\n        double compute_loss (\n            const tensor& x,\n            label_iterator lbegin \n        );\n        /*!\n            requires\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n                - lbegin == iterator pointing to the start of a range of\n                  x.num_samples()/sample_expansion_factor() training_label_type elements.\n            ensures\n                - runs x through the network, compares the output to the expected output\n                  pointed to by lbegin, and returns the resulting loss. \n                - for all valid k:\n                    - the expected label of the kth sample in x is *(lbegin+k/sample_expansion_factor()).\n                - This function does not update the network parameters.\n                - For sub-layers that are immediate inputs into the loss layer, we also populate the\n                  sub-layer's get_gradient_input() tensor with the gradient of the loss with respect\n                  to the sub-layer's output.\n        !*/\n\n        template <typename forward_iterator, typename label_iterator>\n        double compute_loss (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            label_iterator lbegin \n        );\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - lbegin == iterator pointing to the start of a range of\n                  std::distance(ibegin,iend) training_label_type elements.\n            ensures\n                - runs [ibegin,iend) through the network, compares the output to the\n                  expected output pointed to by lbegin, and returns the resulting loss. \n                - for all valid k:\n                    - the expected label of *(ibegin+k) is *(lbegin+k).\n                - This function does not update the network parameters.\n                - For sub-layers that are immediate inputs into the loss layer, we also populate the\n                  sub-layer's get_gradient_input() tensor with the gradient of the loss with respect\n                  to the sub-layer's output.\n        !*/\n\n    // -------------\n\n        double compute_loss (\n            const tensor& x\n        );\n        /*!\n            requires\n                - LOSS_DETAILS is an unsupervised loss.  i.e. training_label_type==no_label_type.\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n            ensures\n                - runs x through the network and returns the resulting loss. \n                - This function does not update the network parameters.\n                - For sub-layers that are immediate inputs into the loss layer, we also populate the\n                  sub-layer's get_gradient_input() tensor with the gradient of the loss with respect\n                  to the sub-layer's output.\n        !*/\n\n        template <typename forward_iterator>\n        double compute_loss (\n            forward_iterator ibegin,\n            forward_iterator iend,\n        );\n        /*!\n            requires\n                - LOSS_DETAILS is an unsupervised loss.  i.e. training_label_type==no_label_type.\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - runs [ibegin,iend) through the network and returns the resulting loss. \n                - This function does not update the network parameters.\n                - For sub-layers that are immediate inputs into the loss layer, we also populate the\n                  sub-layer's get_gradient_input() tensor with the gradient of the loss with respect\n                  to the sub-layer's output.\n        !*/\n\n    // -------------\n\n        template <typename label_iterator>\n        double compute_parameter_gradients (\n            const tensor& x,\n            label_iterator lbegin,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n                - lbegin == iterator pointing to the start of a range of\n                  x.num_samples()/sample_expansion_factor() training_label_type elements.\n            ensures\n                - runs x through the network, compares the output to the expected output\n                  pointed to by lbegin, and computes parameter and data gradients with\n                  respect to the loss, via backpropagation.  Specifically, this function\n                  updates get_final_data_gradient() and also, for each layer, the tensor\n                  returned by get_parameter_gradient().\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - for all valid k:\n                    - the expected label of the kth sample in x is *(lbegin+k/sample_expansion_factor()).\n                - returns compute_loss(x,lbegin)\n        !*/\n\n        template <typename forward_iterator, typename label_iterator>\n        double compute_parameter_gradients (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            label_iterator lbegin,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - lbegin == iterator pointing to the start of a range of\n                  std::distance(ibegin,iend) training_label_type elements.\n            ensures\n                - runs [ibegin,iend) through the network, compares the output to the\n                  expected output pointed to by lbegin, and computes parameter and data\n                  gradients with respect to the loss, via backpropagation.  Specifically,\n                  this function updates get_final_data_gradient() and also, for each layer,\n                  the tensor returned by get_parameter_gradient().\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - for all valid k:\n                    - the expected label of *(ibegin+k) is *(lbegin+k).\n                - returns compute_loss(ibegin,iend,lbegin)\n        !*/\n\n        double compute_parameter_gradients (\n            const tensor& x,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - LOSS_DETAILS is an unsupervised loss.  i.e. training_label_type==no_label_type.\n                - sample_expansion_factor() != 0\n                  (i.e. to_tensor() must have been called to set sample_expansion_factor()\n                  to something non-zero.)\n                - x.num_samples()%sample_expansion_factor() == 0\n                - x.num_samples() > 0\n            ensures\n                - runs x through the network and computes parameter and data gradients with\n                  respect to the loss, via backpropagation.  Specifically, this function\n                  updates get_final_data_gradient() and also, for each layer, the tensor\n                  returned by get_parameter_gradient().\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - returns compute_loss(x)\n        !*/\n\n        template <typename forward_iterator>\n        double compute_parameter_gradients (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - LOSS_DETAILS is an unsupervised loss.  i.e. training_label_type==no_label_type.\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - runs [ibegin,iend) through the network and computes parameter and data\n                  gradients with respect to the loss, via backpropagation.  Specifically,\n                  this function updates get_final_data_gradient() and also, for each layer,\n                  the tensor returned by get_parameter_gradient().\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - returns compute_loss(ibegin,iend)\n        !*/\n\n        template <typename solver_type>\n        void update_parameters (\n            sstack<solver_type> solvers,\n            double learning_rate\n        );\n        /*!\n            requires\n                - solver_type is an implementation of the EXAMPLE_SOLVER interface defined\n                  in solvers_abstract.h\n                - compute_parameter_gradients() has been called.\n                - The given solvers have only ever been used with this network.  That\n                  is, if you want to call update_parameters() on some other neural network\n                  object then you must NOT reuse the same solvers object.\n                - solvers.size() >= num_computational_layers\n                - 0 < learning_rate <= 1\n            ensures\n                - Updates all the parameters in the network.  In particular, we pass each\n                  layer's parameter gradient (i.e. the tensor returned by the layer's\n                  get_parameter_gradient() member) through that layer's corresponding\n                  solver object.  This produces a parameter delta vector which we add to\n                  the layer's parameters.\n                - The solvers use the given learning rate.\n        !*/\n\n        template <typename solver_type>\n        void update_parameters(std::vector<solver_type>& solvers, double learning_rate\n        ) { update_parameters(make_sstack(solvers), learning_rate); }\n        /*!\n            Convenience method for calling update_parameters()\n        !*/\n\n        void back_propagate_error(\n            const tensor& x\n            zero_gradients zero_grads = zero_gradients::yes\n        );\n        /*!\n            requires\n                - forward(x) was called to forward propagate x though the network.\n                  Moreover, this was the most recent call to forward() and x has not been\n                  subsequently modified in any way.\n                - subnet().get_gradient_input() has been set equal to the gradient of this network's\n                  output with respect to the loss function (generally this will be done by calling\n                  compute_loss()).\n            ensures\n                - Back propagates the error gradient, subnet().get_gradient_input(), through this\n                  network and computes parameter and data gradients, via backpropagation.\n                  Specifically, this function populates get_final_data_gradient() and also,\n                  for each layer, the tensor returned by get_parameter_gradient().\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - have_same_dimensions(#get_final_data_gradient(), x) == true.\n                - #get_final_data_gradient() contains the gradient of the network with\n                  respect to x.\n        !*/\n\n        void back_propagate_error(\n            const tensor& x, \n            const tensor& gradient_input\n        );\n        /*!\n            requires\n                - forward(x) was called to forward propagate x though the network.\n                  Moreover, this was the most recent call to forward() and x has not been\n                  subsequently modified in any way.\n                - have_same_dimensions(gradient_input, subnet().get_output()) == true\n            ensures\n                - This function is identical to the version of back_propagate_error()\n                  defined immediately above except that it back-propagates gradient_input\n                  through the network instead of subnet().get_gradient_input().  Therefore, this\n                  version of back_propagate_error() is equivalent to performing:\n                    subnet().get_gradient_input() = gradient_input;\n                    back_propagate_error(x);\n                  Except that calling back_propagate_error(x,gradient_input) avoids the\n                  copy and is therefore slightly more efficient.\n                - All elements of #subnet().get_gradient_input() are set to 0 if zero_grads == zero_gradients::yes.\n                - have_same_dimensions(#get_final_data_gradient(), x) == true.\n                - #get_final_data_gradient() contains the gradient of the network with\n                  respect to x.\n        !*/\n\n        const tensor& get_final_data_gradient(\n        ) const; \n        /*!\n            ensures\n                - if back_propagate_error() has been called to back-propagate a gradient\n                  through this network then you can call get_final_data_gradient() to\n                  obtain the last data gradient computed.  That is, this function returns\n                  the gradient of the network with respect to its inputs.\n                - Note that there is only one \"final data gradient\" for an entire network,\n                  not one per layer, since there is only one input to the entire network.\n        !*/\n\n        void set_gradient_inputs_to_zero(\n        );\n        /*!\n            ensures\n                - Sets all elements in all gradient inputs in the network to 0.\n                - invokes subnet().set_gradient_inputs_to_zero()\n        !*/\n\n    // -------------\n\n        void clean (\n        );\n        /*!\n            ensures\n                - Causes the network to forget about everything but its parameters.  \n                - invokes subnet().clean()\n        !*/\n    };\n\n    template <typename T, typename U> \n    std::ostream& operator<<(std::ostream& out, const add_loss_layer<T,U>& item);\n    /*!\n        prints the network architecture to the given output stream.\n    !*/\n\n    template <typename T, typename U> \n    void serialize(const add_loss_layer<T,U>& item, std::ostream& out);\n    template <typename T, typename U> \n    void deserialize(add_loss_layer<T,U>& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename ...T>\n    decorator_repeat_group<T...> repeat_group (\n        T&& ...args\n    );\n    /*!\n        ensures\n            - Decorates a group of variables.  This is essentially like std::make_tuple()\n              except it's only purpose is to group variables together so they can be passed\n              to the repeat object's constructor.\n    !*/\n\n    template <\n        size_t num,\n        template<typename> class REPEATED_LAYER, \n        typename SUBNET\n        >\n    class repeat \n    {\n        /*!\n            REQUIREMENTS ON num\n                - num > 0\n\n            REQUIREMENTS ON REPEATED_LAYER\n                - REPEATED_LAYER must be a template that stacks more layers onto a deep neural\n                  network.  For example, if net_type were a network without a loss layer,\n                  then it should be legal to create a deeper network with a type of\n                  REPEATED_LAYER<net_type>.\n\n            REQUIREMENTS ON SUBNET\n                - One of the following must be true:\n                    - SUBNET is an add_layer object.\n                    - SUBNET is an add_tag_layer object.\n                    - SUBNET is an add_skip_layer object.\n                    - SUBNET is a repeat object.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object adds more layers to a deep neural network.  In particular, it\n                adds REPEATED_LAYER on top of SUBNET num times.  So for example, if num were 2 then\n                repeat<2,REPEATED_LAYER,SUBNET> would create a network equivalent to REPEATED_LAYER<REPEATED_LAYER<SUBNET>>.\n\n                Also, this object provides an interface identical to the one defined by the\n                add_layer object except that we add the num_repetitions() and\n                get_repeated_layer() methods.  These additions are shown below along with\n                some additional explanatory comments.\n        !*/\n\n    public:\n\n        typedef SUBNET subnet_type;\n        typedef typename SUBNET::input_type input_type;\n        typedef typename subnet_type::input_layer_type input_layer_type;\n        const static size_t num_computational_layers = (REPEATED_LAYER<SUBNET>::num_computational_layers-SUBNET::num_computational_layers)*num + SUBNET::num_computational_layers;\n        const static size_t num_layers = (REPEATED_LAYER<SUBNET>::num_layers-SUBNET::num_layers)*num + SUBNET::num_layers;\n        typedef REPEATED_LAYER<an_unspecified_input_type> repeated_layer_type;\n\n        template <typename T, typename ...U>\n        repeat(\n            T arg1,\n            U ...args2\n        );\n        /*!\n            ensures\n                - arg1 is used to initialize the num_repetitions() copies of REPEATED_LAYER inside\n                  this object.  That is, all the REPEATED_LAYER elements are initialized identically\n                  by being given copies of arg1.\n                - The rest of the arguments to the constructor, i.e. args2, are passed to\n                  SUBNET's constructor.  \n        !*/\n\n        template <typename ...T, typename ...U>\n        repeat(\n            decorator_repeat_group<T...>&& arg1,\n            U ...args2\n        );\n        /*!\n            ensures\n                - arg1 is used to initialize the num_repetitions() copies of REPEATED_LAYER inside\n                  this object.  That is, all the REPEATED_LAYER elements are initialized identically\n                  by being given copies of an undecorated arg1.\n                - The rest of the arguments to the constructor, i.e. args2, are passed to\n                  SUBNET's constructor.  \n        !*/\n\n        size_t num_repetitions (\n        ) const; \n        /*!\n            ensures\n                - returns num (i.e. the number of times REPEATED_LAYER was stacked on top of SUBNET)\n        !*/\n\n        const repeated_layer_type& get_repeated_layer (\n            size_t i \n        ) const;\n        /*!\n            requires\n                - i < num_repetitions()\n            ensures\n                - returns a reference to the i-th instance of REPEATED_LAYER.  For example,\n                  get_repeated_layer(0) returns the instance of REPEATED_LAYER that is on the top of\n                  the network while get_repeated_layer(num_repetitions()-1) returns the\n                  instance of REPEATED_LAYER that is stacked immediately on top of SUBNET.\n        !*/\n\n        repeated_layer_type& get_repeated_layer (\n            size_t i \n        );\n        /*!\n            requires\n                - i < num_repetitions()\n            ensures\n                - returns a reference to the i-th instance of REPEATED_LAYER.  For example,\n                  get_repeated_layer(0) returns the instance of REPEATED_LAYER that is on the top of\n                  the network while get_repeated_layer(num_repetitions()-1) returns the\n                  instance of REPEATED_LAYER that is stacked immediately on top of SUBNET.\n        !*/\n\n        const subnet_type& subnet(\n        ) const; \n        /*!\n            ensures\n                - returns the SUBNET base network that repeat sits on top of.  If you want\n                  to access the REPEATED_LAYER components then you must use get_repeated_layer(). \n        !*/\n\n        subnet_type& subnet(\n        ); \n        /*!\n            ensures\n                - returns the SUBNET base network that repeat sits on top of.  If you want\n                  to access the REPEATED_LAYER components then you must use get_repeated_layer(). \n        !*/\n\n        const input_layer_type& input_layer(\n        ) const;  \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        input_layer_type& input_layer(\n        ); \n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n    };\n\n    template < size_t num, template<typename> class T, typename U >\n    std::ostream& operator<<(std::ostream& out, const repeat<num,T,U>& item);\n    /*!\n        prints the network architecture to the given output stream.\n    !*/\n\n    template < size_t num, template<typename> class T, typename U >\n    void serialize(const repeat<num,T,U>& item, std::ostream& out);\n    template < size_t num, template<typename> class T, typename U >\n    void deserialize(repeat<num,T,U>& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long ID, \n        typename SUBNET\n        >\n    class add_tag_layer\n    {\n        /*!\n            REQUIREMENTS ON SUBNET\n                - One of the following must be true:\n                    - SUBNET implements the EXAMPLE_INPUT_LAYER interface defined in\n                      input_abstract.h.\n                    - SUBNET is an add_layer object.\n                    - SUBNET is an add_tag_layer object.\n                    - SUBNET is an add_skip_layer object.\n                    - SUBNET is a repeat object.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object adds a new layer to a deep neural network.  However, this layer\n                simply performs the identity transform.  This means it is a no-op and its\n                presence does not change the behavior of the network.  It exists solely to\n                be used by add_skip_layer to reference a particular part of a network.\n\n                Also, this object provides an interface identical to the one defined by the\n                add_layer object.\n        !*/\n    };\n\n    template <unsigned long ID, typename U> \n    std::ostream& operator<<(std::ostream& out, const add_tag_layer<ID,U>& item);\n    /*!\n        prints the network architecture to the given output stream.\n    !*/\n\n    template <unsigned long ID, typename U> \n    void serialize(const add_tag_layer<ID,U>& item, std::ostream& out);\n    template <unsigned long ID, typename U> \n    void deserialize(add_tag_layer<ID,U>& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    template <typename SUBNET> using tag1  = add_tag_layer< 1, SUBNET>;\n    template <typename SUBNET> using tag2  = add_tag_layer< 2, SUBNET>;\n    template <typename SUBNET> using tag3  = add_tag_layer< 3, SUBNET>;\n    template <typename SUBNET> using tag4  = add_tag_layer< 4, SUBNET>;\n    template <typename SUBNET> using tag5  = add_tag_layer< 5, SUBNET>;\n    template <typename SUBNET> using tag6  = add_tag_layer< 6, SUBNET>;\n    template <typename SUBNET> using tag7  = add_tag_layer< 7, SUBNET>;\n    template <typename SUBNET> using tag8  = add_tag_layer< 8, SUBNET>;\n    template <typename SUBNET> using tag9  = add_tag_layer< 9, SUBNET>;\n    template <typename SUBNET> using tag10 = add_tag_layer<10, SUBNET>;\n\n    template <template<typename SUBNET> class tag>\n    struct tag_id\n    {\n        /*!\n            REQUIREMENTS ON tag\n                Tag should be an add_tag_layer template such as tag1, tag2, etc.\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for finding the numeric ID of a tag layer.  For example,\n                tag_id<tag3>::id == 3.\n        !*/\n\n        const static unsigned long id;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class TAG_TYPE, \n        typename SUBNET\n        >\n    class add_skip_layer\n    {\n        /*!\n            REQUIREMENTS ON SUBNET\n                - One of the following must be true:\n                    - SUBNET is an add_layer object.\n                    - SUBNET is an add_tag_layer object.\n                    - SUBNET is an add_skip_layer object.\n                    - SUBNET is a repeat object.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object adds a new layer to a deep neural network which draws its\n                inputs from layer<TAG_TYPE>(subnet()) and performs the identity transform.\n\n                Also, this object provides an interface identical to the one defined by the\n                add_layer object.\n        !*/\n    };\n\n    template <template<typename> class T, typename U>\n    std::ostream& operator<<(std::ostream& out, const add_skip_layer<T,U>& item);\n    /*!\n        prints the network architecture to the given output stream.\n    !*/\n\n    template <template<typename> class T, typename U>\n    void serialize(const add_skip_layer<T,U>& item, std::ostream& out);\n    template <template<typename> class T, typename U>\n    void deserialize(add_skip_layer<T,U>& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    template <typename SUBNET> using skip1  = add_skip_layer< tag1, SUBNET>;\n    template <typename SUBNET> using skip2  = add_skip_layer< tag2, SUBNET>;\n    template <typename SUBNET> using skip3  = add_skip_layer< tag3, SUBNET>;\n    template <typename SUBNET> using skip4  = add_skip_layer< tag4, SUBNET>;\n    template <typename SUBNET> using skip5  = add_skip_layer< tag5, SUBNET>;\n    template <typename SUBNET> using skip6  = add_skip_layer< tag6, SUBNET>;\n    template <typename SUBNET> using skip7  = add_skip_layer< tag7, SUBNET>;\n    template <typename SUBNET> using skip8  = add_skip_layer< tag8, SUBNET>;\n    template <typename SUBNET> using skip9  = add_skip_layer< tag9, SUBNET>;\n    template <typename SUBNET> using skip10 = add_skip_layer<tag10, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned int i, \n        typename net_type\n        >\n    auto& layer (\n        net_type& n\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - i < net_type::num_layers\n        ensures\n            - This function allows you to access any layer in a network by its layer index\n              i.  Therefore, it will walk i steps down the network and return the layer\n              object there.  Since networks can be big, the best way to find layer index\n              numbers is to print a network to the screen since the print out will include\n              indexes for each layer.\n            - In general, this function chains together i calls to n.subnet() and returns\n              the result.  So for example:\n                - if (i == 0)\n                    - returns n\n                - else if (i == 1)\n                    - returns n.subnet()\n                - else if (i == 2)\n                    - returns n.subnet().subnet()\n                - else if (i == 3)\n                    - returns n.subnet().subnet().subnet()\n                - else\n                    - etc.\n              Except that when it hits a repeat layer it recurses into the repeated layers\n              contained inside.  That is, if the layer index indicates a layer in a repeat\n              object this function will make the appropriate call to get_repeated_layer()\n              and do the right thing.\n    !*/\n\n    template <\n        template<typename> class Match, \n        typename net_type \n        >\n    auto& layer (\n        net_type& n\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - returns the first layer in n that is of type Match.  E.g. if net_type is\n              fc<relu<fc<input<sample_type>>>> then calling layer<relu>(n) would return\n              layer<1>(n), that is, a reference to the relu layer.\n    !*/\n\n    template <\n        template<typename> class Match, \n        unsigned int i, \n        typename net_type\n        >\n    auto& layer (\n        net_type& n\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - returns layer<i>(layer<Match>(n))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    auto& input_layer (\n        net_type& net\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, repeat, or\n              add_tag_layer.\n        ensures\n            - returns the input layer of the given network object.  This is the same as just calling\n              net.input_layer().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layer_parameters(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, tensor& t)\n              or:\n                v(tensor& t)\n        ensures\n            - Loops over all the computational layers (i.e. layers with parameters, as\n              opposed to loss, tag, or input layers) in net and passes their parameters to\n              v().  To be specific, this function essentially performs the following:\n\n                size_t computational_layer_idx = 0;\n                for (size_t i = 0; i < net_type::num_layers; ++i)\n                {\n                    if (layer<i>(net) is a computational layer)\n                    {\n                        v(computational_layer_idx, layer<i>(net).layer_details().get_layer_params());\n                        ++computational_layer_idx;\n                    }\n                }\n            - When v() is called, the first argument is always < net_type::num_computational_layers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layer_parameter_gradients(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, tensor& t)\n              or:\n                v(tensor& t)\n        ensures\n            - Loops over all the computational layers (i.e. layers with parameters, as\n              opposed to loss, tag, or input layers) in net and passes their parameter\n              gradients to v().  To be specific, this function essentially performs the\n              following:\n\n                size_t computational_layer_idx = 0;\n                for (size_t i = 0; i < net_type::num_layers; ++i)\n                {\n                    if (layer<i>(net) is a computational layer)\n                    {\n                        v(computational_layer_idx, layer<i>(net).get_parameter_gradient());\n                        ++computational_layer_idx;\n                    }\n                }\n            - When v() is called, the first argument is always < net_type::num_computational_layers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_net_type& t)\n              or:\n                v(any_net_type& t)\n              That is, it takes an optional size_t and then any of the network types such as\n              add_layer, add_loss_layer, etc.\n        ensures\n            - Loops over all the layers in net and calls v() on them.  To be specific, this\n              function essentially performs the following:\n\n                for (size_t i = 0; i < net_type::num_layers; ++i)\n                    v(i, layer<i>(net));\n    !*/\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_backwards(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_net_type& t)\n              or:\n                v(any_net_type& t)\n              That is, it takes an optional size_t and then any of the network types such as\n              add_layer, add_loss_layer, etc.\n        ensures\n            - Loops over all the layers in net and calls v() on them.  The loop happens in\n              the reverse order of visit_layers().  To be specific, this function\n              essentially performs the following:\n\n                for (size_t i = net_type::num_layers; i != 0; --i)\n                    v(i-1, layer<i-1>(net));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type,\n        typename visitor\n        >\n    void visit_computational_layers(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_computational_layer& t)\n              or:\n                v(any_computational_layer& t)\n              That is, it takes an optional size_t and then any of the computational layers.  E.g.\n              one of the layer types defined in dlib/dnn/layers_abstract.h like fc_ or conv_.\n        ensures\n            - Loops over all the computational layers in net and calls v() on them.  To be specific, this\n              function essentially performs the following:\n\n                for (size_t i = 0; i < net_type::num_layers; ++i)\n                    if (layer<i>(net) is an add_layer type, i.e. it adds a computational layer)\n                        v(i, layer<i>(net).layer_details());\n    !*/\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_computational_layers_range(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_computational_layer& t)\n              or:\n                v(any_computational_layer& t)\n              That is, it takes an optional size_t and then any of the computational layers.  E.g.\n              one of the layer types defined in dlib/dnn/layers_abstract.h like fc_ or conv_.\n        ensures\n            - Loops over all the computational layers in the range [begin,end) in net and calls v()\n              on them.  To be specific, this function essentially performs the following:\n\n                for (size_t i = begin; i < end; ++i)\n                    if (layer<i>(net) is an add_layer type, i.e. it adds a computational layer)\n                        v(i, layer<i>(net).layer_details());\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_range(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_net_type& t)\n              or:\n                v(any_net_type& t)\n              That is, it takes an optional size_t and then any of the network types such as\n              add_layer, add_loss_layer, etc.\n            - begin <= end <= net_type::num_layers\n        ensures\n            - Loops over the layers in the range [begin,end) in net and calls v() on them.\n              To be specific, this function essentially performs the following:\n\n                for (size_t i = begin; i < end; ++i)\n                    v(i, layer<i>(net));\n    !*/\n\n    template <\n        size_t begin,\n        size_t end,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_backwards_range(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(size_t idx, any_net_type& t)\n              or:\n                v(any_net_type& t)\n              That is, it takes an optional size_t and then any of the network types such as\n              add_layer, add_loss_layer, etc.\n            - begin <= end <= net_type::num_layers\n        ensures\n            - Loops over the layers in the range [begin,end) in net and calls v() on them.\n              The loop happens in the reverse order of visit_layers_range().  To be specific,\n              this function essentially performs the following:\n\n                for (size_t i = end; i != begin; --i)\n                    v(i-1, layer<i-1>(net));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long tag_id,\n        typename net_type,\n        typename visitor\n        >\n    void visit_layers_until_tag(\n        net_type& net,\n        visitor v\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - v is a function object with a signature equivalent to: \n                v(any_net_type& t)\n              That is, it must take any of the network types such as add_layer,\n              add_loss_layer, etc.\n        ensures\n            - Loops over all the layers in net beginning with layer<0>(net) and going until\n              a tag layer with an ID of tag_id is encountered.  To be specific, this\n              function essentially performs the following:\n\n                size_t i = 0;\n                while(layer<i>(net) isn't an add_tag_layer with ID == tag_id) {\n                    v(layer<i>(net));\n                    ++i;\n                }\n                v(layer<i>(net));  // also visits the tag layer itself at the very end.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct layer_test_results\n    {\n        std::string log;\n        bool was_good;\n\n        operator bool() const { return was_good; }\n    };\n\n    inline std::ostream& operator<< (std::ostream& out, const layer_test_results& item)\n    {\n        out << item.log;\n        return out;\n    }\n\n    template <\n        typename layer_details_type\n        >\n    layer_test_results test_layer (\n        layer_details_type l\n    );\n    /*!\n        ensures\n            - Checks if l correctly implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n              defined in layers_abstract.h.  Importantly, it computes numerical approximations \n              to the gradients and compares them to the outputs of the layer.  \n            - The results of the testing are returned.  In particular, if the returned object\n              is RESULT then we will have:\n                - RESULT.was_good == false if and only if the layer failed the testing.\n                - RESULT.log == a string describing why the testing failed if was_good==false.\n            - Note that this function is only capable of checking layers that take\n              arbitrary subnetworks as input.  So if you have designed a layer that expects\n              only a certain restricted type of subnetwork then you might get a compile or\n              runtime error when you call this function.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_CORE_ABSTRACT_H_ \n\n"
  },
  {
    "path": "dlib/dnn/input.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_INPUT_H_\n#define DLIB_DNn_INPUT_H_\n\n#include \"input_abstract.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_processing.h\"\n#include <sstream>\n#include <array>\n#include \"../cuda/tensor_tools.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class input\n    {\n        const static bool always_false = sizeof(T)!=sizeof(T); \n        static_assert(always_false, \"Unsupported type given to input<>.  input<> only supports \"\n            \"dlib::matrix and dlib::array2d objects.\"); \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t NR, size_t NC=NR>\n    class input_rgb_image_sized;\n\n    class input_rgb_image_pair;\n\n    class input_rgb_image\n    {\n    public:\n        typedef matrix<rgb_pixel> input_type;\n\n        input_rgb_image (\n        ) : \n            avg_red(122.782f),\n            avg_green(117.001f),\n            avg_blue(104.298f)\n        {\n        }\n\n        input_rgb_image (\n            float avg_red_,\n            float avg_green_,\n            float avg_blue_\n        ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_) \n        {}\n\n        template <size_t NR, size_t NC>\n        inline input_rgb_image (\n            const input_rgb_image_sized<NR,NC>& item\n        );\n\n        inline input_rgb_image (\n            const input_rgb_image_pair& item\n        );\n\n        float get_avg_red()   const { return avg_red; }\n        float get_avg_green() const { return avg_green; }\n        float get_avg_blue()  const { return avg_blue; }\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin,iend) > 0);\n            const auto nr = ibegin->nr();\n            const auto nc = ibegin->nc();\n            // make sure all the input matrices have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->nr()==nr && i->nc()==nc,\n                    \"\\t input_rgb_image::to_tensor()\"\n                    << \"\\n\\t All matrices given to to_tensor() must have the same dimensions.\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t i->nr(): \" << i->nr()\n                    << \"\\n\\t i->nc(): \" << i->nc()\n                );\n            }\n\n\n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(std::distance(ibegin,iend), 3, nr, nc);\n\n\n            const size_t offset = nr*nc;\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (long r = 0; r < nr; ++r)\n                {\n                    for (long c = 0; c < nc; ++c)\n                    {\n                        rgb_pixel temp = (*i)(r,c);\n                        auto p = ptr++;\n                        *p = (temp.red-avg_red)/256.0; \n                        p += offset;\n                        *p = (temp.green-avg_green)/256.0; \n                        p += offset;\n                        *p = (temp.blue-avg_blue)/256.0; \n                        p += offset;\n                    }\n                }\n                ptr += offset*(data.k()-1);\n            }\n\n        }\n\n        friend void serialize(const input_rgb_image& item, std::ostream& out)\n        {\n            serialize(\"input_rgb_image\", out);\n            serialize(item.avg_red, out);\n            serialize(item.avg_green, out);\n            serialize(item.avg_blue, out);\n        }\n\n        friend void deserialize(input_rgb_image& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_rgb_image\" && version != \"input_rgb_image_sized\" && version != \"input_rgb_image_pair\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_rgb_image.\");\n            deserialize(item.avg_red, in);\n            deserialize(item.avg_green, in);\n            deserialize(item.avg_blue, in);\n\n            // read and discard the sizes if this was really a sized input layer.\n            if (version == \"input_rgb_image_sized\")\n            {\n                size_t nr, nc;\n                deserialize(nr, in);\n                deserialize(nc, in);\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_rgb_image& item)\n        {\n            out << \"input_rgb_image(\"<<item.avg_red<<\",\"<<item.avg_green<<\",\"<<item.avg_blue<<\")\";\n            return out;\n        }\n\n        friend void to_xml(const input_rgb_image& item, std::ostream& out)\n        {\n            out << \"<input_rgb_image r='\"<<item.avg_red<<\"' g='\"<<item.avg_green<<\"' b='\"<<item.avg_blue<<\"'/>\\n\";\n        }\n\n    private:\n        float avg_red;\n        float avg_green;\n        float avg_blue;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t NR, size_t NC>\n    class input_rgb_image_sized\n    {\n    public:\n        static_assert(NR != 0 && NC != 0, \"The input image can't be empty.\");\n\n        typedef matrix<rgb_pixel> input_type;\n\n        input_rgb_image_sized (\n        ) : \n            avg_red(122.782), \n            avg_green(117.001),\n            avg_blue(104.298) \n        {\n        }\n\n        input_rgb_image_sized (\n            const input_rgb_image& item\n        ) : avg_red(item.get_avg_red()),\n            avg_green(item.get_avg_green()),\n            avg_blue(item.get_avg_blue())\n        {}\n\n        input_rgb_image_sized (\n            float avg_red_,\n            float avg_green_,\n            float avg_blue_\n        ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_) \n        {}\n\n        float get_avg_red()   const { return avg_red; }\n        float get_avg_green() const { return avg_green; }\n        float get_avg_blue()  const { return avg_blue; }\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin,iend) > 0);\n            // make sure all input images have the correct size\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->nr()==NR && i->nc()==NC,\n                    \"\\t input_rgb_image_sized::to_tensor()\"\n                    << \"\\n\\t All input images must have \"<<NR<<\" rows and \"<<NC<< \" columns, but we got one with \"<<i->nr()<<\" rows and \"<<i->nc()<<\" columns.\"\n                );\n            }\n\n\n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(std::distance(ibegin,iend), 3, NR, NC);\n\n\n            const size_t offset = NR*NC;\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (size_t r = 0; r < NR; ++r)\n                {\n                    for (size_t c = 0; c < NC; ++c)\n                    {\n                        rgb_pixel temp = (*i)(r,c);\n                        auto p = ptr++;\n                        *p = (temp.red-avg_red)/256.0; \n                        p += offset;\n                        *p = (temp.green-avg_green)/256.0; \n                        p += offset;\n                        *p = (temp.blue-avg_blue)/256.0; \n                        p += offset;\n                    }\n                }\n                ptr += offset*(data.k()-1);\n            }\n\n        }\n\n        friend void serialize(const input_rgb_image_sized& item, std::ostream& out)\n        {\n            serialize(\"input_rgb_image_sized\", out);\n            serialize(item.avg_red, out);\n            serialize(item.avg_green, out);\n            serialize(item.avg_blue, out);\n            serialize(NR, out);\n            serialize(NC, out);\n        }\n\n        friend void deserialize(input_rgb_image_sized& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_rgb_image_sized\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_rgb_image_sized.\");\n            deserialize(item.avg_red, in);\n            deserialize(item.avg_green, in);\n            deserialize(item.avg_blue, in);\n            size_t nr, nc;\n            deserialize(nr, in);\n            deserialize(nc, in);\n            if (nr != NR || nc != NC)\n            {\n                std::ostringstream sout;\n                sout << \"Wrong image dimensions found while deserializing dlib::input_rgb_image_sized.\\n\";\n                sout << \"Expected \"<<NR<<\" rows and \"<<NC<< \" columns, but found \"<<nr<<\" rows and \"<<nc<<\" columns.\";\n                throw serialization_error(sout.str());\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_rgb_image_sized& item)\n        {\n            out << \"input_rgb_image_sized(\"<<item.avg_red<<\",\"<<item.avg_green<<\",\"<<item.avg_blue<<\") nr=\"<<NR<<\" nc=\"<<NC;\n            return out;\n        }\n\n        friend void to_xml(const input_rgb_image_sized& item, std::ostream& out)\n        {\n            out << \"<input_rgb_image_sized r='\"<<item.avg_red<<\"' g='\"<<item.avg_green<<\"' b='\"<<item.avg_blue<<\"' nr='\"<<NR<<\"' nc='\"<<NC<<\"'/>\\n\";\n        }\n\n    private:\n        float avg_red;\n        float avg_green;\n        float avg_blue;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t NR, size_t NC>\n    input_rgb_image::\n    input_rgb_image (\n        const input_rgb_image_sized<NR,NC>& item\n    ) : avg_red(item.get_avg_red()),\n        avg_green(item.get_avg_green()),\n        avg_blue(item.get_avg_blue())\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    class input_rgb_image_pair\n    {\n    public:\n        typedef std::pair<matrix<rgb_pixel>, matrix<rgb_pixel>> input_type;\n\n        input_rgb_image_pair (\n        ) :\n            avg_red(122.782),\n            avg_green(117.001),\n            avg_blue(104.298)\n        {\n        }\n\n        input_rgb_image_pair (\n            float avg_red,\n            float avg_green,\n            float avg_blue\n        ) : avg_red(avg_red), avg_green(avg_green), avg_blue(avg_blue)\n        {}\n\n        inline input_rgb_image_pair (\n            const input_rgb_image& item\n        ) :\n            avg_red(item.get_avg_red()),\n            avg_green(item.get_avg_green()),\n            avg_blue(item.get_avg_blue())\n        {}\n\n        template <size_t NR, size_t NC>\n        inline input_rgb_image_pair (\n            const input_rgb_image_sized<NR, NC>& item\n        ) :\n            avg_red(item.get_avg_red()),\n            avg_green(item.get_avg_green()),\n            avg_blue(item.get_avg_blue())\n        {}\n\n        float get_avg_red()   const { return avg_red; }\n        float get_avg_green() const { return avg_green; }\n        float get_avg_blue()  const { return avg_blue; }\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin, iend) > 0);\n            const auto nr = ibegin->first.nr();\n            const auto nc = ibegin->first.nc();\n\n            // make sure all the input matrices have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->first.nr() == nr && i->first.nc()==nc &&\n                             i->second.nr() == nr && i->second.nc() == nc,\n                    \"\\t input_rgb_image_pair::to_tensor()\"\n                    << \"\\n\\t All matrices given to to_tensor() must have the same dimensions.\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t i->first.nr(): \" << i->first.nr()\n                    << \"\\n\\t i->first.nc(): \" << i->first.nc()\n                    << \"\\n\\t i->second.nr(): \" << i->second.nr()\n                    << \"\\n\\t i->second.nc(): \" << i->second.nc()\n                );\n            }\n\n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(2 * std::distance(ibegin, iend), 3, nr, nc);\n\n            const size_t offset = nr * nc;\n            const size_t offset2 = data.size() / 2;\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (long r = 0; r < nr; ++r)\n                {\n                    for (long c = 0; c < nc; ++c)\n                    {\n                        rgb_pixel temp_first = i->first(r, c);\n                        rgb_pixel temp_second = i->second(r, c);\n                        auto p = ptr++;\n                        *p = (temp_first.red - avg_red) / 256.0;\n                        *(p + offset2) = (temp_second.red - avg_red) / 256.0;\n                        p += offset;\n                        *p = (temp_first.green - avg_green) / 256.0;\n                        *(p + offset2) = (temp_second.green - avg_green) / 256.0;\n                        p += offset;\n                        *p = (temp_first.blue - avg_blue) / 256.0;\n                        *(p + offset2) = (temp_second.blue - avg_blue) / 256.0;\n                        p += offset;\n                    }\n                }\n                ptr += offset * (data.k() - 1);\n            }\n        }\n\n        friend void serialize(const input_rgb_image_pair& item, std::ostream& out)\n        {\n            serialize(\"input_rgb_image_pair\", out);\n            serialize(item.avg_red, out);\n            serialize(item.avg_green, out);\n            serialize(item.avg_blue, out);\n        }\n\n        friend void deserialize(input_rgb_image_pair& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_rgb_image_pair\" && version != \"input_rgb_image\" && version != \"input_rgb_image_sized\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_rgb_image_pair.\");\n\n            deserialize(item.avg_red, in);\n            deserialize(item.avg_green, in);\n            deserialize(item.avg_blue, in);\n            // read and discard the sizes if this was really a sized input layer.\n            if (version == \"input_rgb_image_sized\")\n            {\n                size_t nr, nc;\n                deserialize(nr, in);\n                deserialize(nc, in);\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_rgb_image_pair& item)\n        {\n            out << \"input_rgb_image_pair(\"<< item.avg_red<<\",\"<<item.avg_green<<\",\"<<item.avg_blue << \")\";\n            return out;\n        }\n\n        friend void to_xml(const input_rgb_image_pair& item, std::ostream& out)\n        {\n            out << \"<input_rgb_image_pair r='\"<<item.avg_red<<\"' g='\"<<item.avg_green<<\"' b='\"<<item.avg_blue<<\"'/>\\n\";\n        }\n\n    private:\n        float avg_red;\n        float avg_green;\n        float avg_blue;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    input_rgb_image::\n    input_rgb_image (\n        const input_rgb_image_pair& item\n    ) : avg_red(item.get_avg_red()),\n        avg_green(item.get_avg_green()),\n        avg_blue(item.get_avg_blue())\n    {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    class input<matrix<T,NR,NC,MM,L>> \n    {\n    public:\n        typedef matrix<T,NR,NC,MM,L> input_type;\n\n        input() {}\n\n        template <typename mm>\n        input(const input<array2d<T,mm>>&) {}\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin,iend) > 0);\n            const auto nr = ibegin->nr();\n            const auto nc = ibegin->nc();\n            // make sure all the input matrices have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->nr()==nr && i->nc()==nc,\n                    \"\\t input::to_tensor()\"\n                    << \"\\n\\t All matrices given to to_tensor() must have the same dimensions.\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t i->nr(): \" << i->nr()\n                    << \"\\n\\t i->nc(): \" << i->nc()\n                );\n            }\n\n            \n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(std::distance(ibegin,iend), pixel_traits<T>::num, nr, nc);\n\n            typedef typename pixel_traits<T>::basic_pixel_type bptype;\n\n            const size_t offset = nr*nc;\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (long r = 0; r < nr; ++r)\n                {\n                    for (long c = 0; c < nc; ++c)\n                    {\n                        auto temp = pixel_to_vector<float>((*i)(r,c));\n                        auto p = ptr++;\n                        for (long j = 0; j < temp.size(); ++j)\n                        {\n                            if (is_same_type<bptype,unsigned char>::value)\n                                *p = temp(j)/256.0;\n                            else\n                                *p = temp(j);\n                            p += offset;\n                        }\n                    }\n                }\n                ptr += offset*(data.k()-1);\n            }\n\n        }\n\n        friend void serialize(const input& /*item*/, std::ostream& out)\n        {\n            serialize(\"input<matrix>\", out);\n        }\n\n        friend void deserialize(input& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input<matrix>\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input& /*item*/)\n        {\n            out << \"input<matrix>\";\n            return out;\n        }\n\n        friend void to_xml(const input& /*item*/, std::ostream& out)\n        {\n            out << \"<input/>\\n\";\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename MM, typename L, size_t K>\n    class input<std::array<matrix<T,NR,NC,MM,L>,K>> \n    {\n    public:\n        typedef std::array<matrix<T,NR,NC,MM,L>,K> input_type;\n\n        input() {}\n        input(const input&) {}\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin,iend) > 0);\n            DLIB_CASSERT(ibegin->size() != 0, \"When using std::array<matrix> inputs you can't give 0 sized arrays.\");\n            const auto nr = (*ibegin)[0].nr();\n            const auto nc = (*ibegin)[0].nc();\n            // make sure all the input matrices have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (size_t k = 0; k < K; ++k)\n                {\n                    const auto& arr = *i;\n                    DLIB_CASSERT(arr[k].nr()==nr && arr[k].nc()==nc,\n                        \"\\t input::to_tensor()\"\n                        << \"\\n\\t When using std::array<matrix> as input, all matrices in a batch must have the same dimensions.\"\n                        << \"\\n\\t nr: \" << nr\n                        << \"\\n\\t nc: \" << nc\n                        << \"\\n\\t k:  \" << k \n                        << \"\\n\\t arr[k].nr(): \" << arr[k].nr()\n                        << \"\\n\\t arr[k].nc(): \" << arr[k].nc()\n                    );\n                }\n            }\n\n            \n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(std::distance(ibegin,iend), K, nr, nc);\n\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (size_t k = 0; k < K; ++k)\n                {\n                    for (long r = 0; r < nr; ++r)\n                    {\n                        for (long c = 0; c < nc; ++c)\n                        {\n                            if (is_same_type<T,unsigned char>::value)\n                                *ptr++ = (*i)[k](r,c)/256.0;\n                            else\n                                *ptr++ = (*i)[k](r,c);\n                        }\n                    }\n                }\n            }\n\n        }\n\n        friend void serialize(const input& /*item*/, std::ostream& out)\n        {\n            serialize(\"input<array<matrix>>\", out);\n        }\n\n        friend void deserialize(input& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input<array<matrix>>\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input<array<matrix>>.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input& /*item*/)\n        {\n            out << \"input<array<matrix>>\";\n            return out;\n        }\n\n        friend void to_xml(const input& /*item*/, std::ostream& out)\n        {\n            out << \"<input/>\\n\";\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename MM>\n    class input<array2d<T,MM>> \n    {\n    public:\n        typedef array2d<T,MM> input_type;\n\n        input() {}\n        input(const input&) {}\n\n        template <long NR, long NC, typename mm, typename L>\n        input(const input<matrix<T,NR,NC,mm,L>>&) {}\n\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin,iend) > 0);\n            const auto nr = ibegin->nr();\n            const auto nc = ibegin->nc();\n            // make sure all the input matrices have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->nr()==nr && i->nc()==nc,\n                    \"\\t input::to_tensor()\"\n                    << \"\\n\\t All array2d objects given to to_tensor() must have the same dimensions.\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t i->nr(): \" << i->nr()\n                    << \"\\n\\t i->nc(): \" << i->nc()\n                );\n            }\n\n            \n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(std::distance(ibegin,iend), pixel_traits<T>::num, nr, nc);\n            typedef typename pixel_traits<T>::basic_pixel_type bptype;\n\n            const size_t offset = nr*nc;\n            auto ptr = data.host();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                for (long r = 0; r < nr; ++r)\n                {\n                    for (long c = 0; c < nc; ++c)\n                    {\n                        auto temp = pixel_to_vector<float>((*i)[r][c]);\n                        auto p = ptr++;\n                        for (long j = 0; j < temp.size(); ++j)\n                        {\n                            if (is_same_type<bptype,unsigned char>::value)\n                                *p = temp(j)/256.0;\n                            else\n                                *p = temp(j);\n                            p += offset;\n                        }\n                    }\n                }\n                ptr += offset*(data.k()-1);\n            }\n\n        }\n\n        friend void serialize(const input&, std::ostream& out)\n        {\n            serialize(\"input<array2d>\", out);\n        }\n\n        friend void deserialize(input&, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input<array2d>\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input.\");\n        }\n        friend std::ostream& operator<<(std::ostream& out, const input&)\n        {\n            out << \"input<array2d>\";\n            return out;\n        }\n\n        friend void to_xml(const input&, std::ostream& out)\n        {\n            out << \"<input/>\\n\";\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail {\n        template <typename PYRAMID_TYPE>\n        class input_image_pyramid\n        {\n        public:\n\n            virtual ~input_image_pyramid() = 0;\n\n            typedef PYRAMID_TYPE pyramid_type;\n\n            unsigned long get_pyramid_padding() const { return pyramid_padding; }\n            void set_pyramid_padding(unsigned long value) { pyramid_padding = value; }\n\n            unsigned long get_pyramid_outer_padding() const { return pyramid_outer_padding; }\n            void set_pyramid_outer_padding(unsigned long value) { pyramid_outer_padding = value; }\n\n            bool image_contained_point(\n                const tensor& data,\n                const point& p\n            ) const\n            {\n                auto&& rects = any_cast<std::vector<rectangle>>(data.annotation());\n                DLIB_CASSERT(rects.size() > 0);\n                return rects[0].contains(p + rects[0].tl_corner());\n            }\n\n            drectangle tensor_space_to_image_space(\n                const tensor& data,\n                drectangle r\n            ) const\n            {\n                auto&& rects = any_cast<std::vector<rectangle>>(data.annotation());\n                return tiled_pyramid_to_image<pyramid_type>(rects, r);\n            }\n\n            drectangle image_space_to_tensor_space (\n                const tensor& data,\n                double scale,\n                drectangle r\n            ) const\n            {\n                DLIB_CASSERT(0 < scale && scale <= 1, \"scale: \" << scale);\n                auto&& rects = any_cast<std::vector<rectangle>>(data.annotation());\n                return image_to_tiled_pyramid<pyramid_type>(rects, scale, r);\n            }\n\n        protected:\n\n            template <typename forward_iterator>\n            void to_tensor_init (\n                forward_iterator ibegin,\n                forward_iterator iend,\n                resizable_tensor &data,\n                unsigned int k\n            ) const\n            {\n\n                DLIB_CASSERT(std::distance(ibegin, iend) > 0);\n                auto nr = ibegin->nr();\n                auto nc = ibegin->nc();\n                // make sure all the input matrices have the same dimensions\n                for (auto i = ibegin; i != iend; ++i)\n                {\n                    DLIB_CASSERT(i->nr() == nr && i->nc() == nc,\n                                 \"\\t input_grayscale_image_pyramid::to_tensor()\"\n                                         << \"\\n\\t All matrices given to to_tensor() must have the same dimensions.\"\n                                         << \"\\n\\t nr: \" << nr\n                                         << \"\\n\\t nc: \" << nc\n                                         << \"\\n\\t i->nr(): \" << i->nr()\n                                         << \"\\n\\t i->nc(): \" << i->nc()\n                    );\n                }\n\n                long NR, NC;\n                pyramid_type pyr;\n                auto& rects = data.annotation().get<std::vector<rectangle>>();\n                impl::compute_tiled_image_pyramid_details(pyr, nr, nc, pyramid_padding, pyramid_outer_padding, rects,\n                                                          NR, NC);\n\n                // initialize data to the right size to contain the stuff in the iterator range.\n                data.set_size(std::distance(ibegin, iend), k, NR, NC);\n\n                // We need to zero the image before doing the pyramid, since the pyramid\n                // creation code doesn't write to all parts of the image.  We also take\n                // care to avoid triggering any device to hosts copies.\n                auto ptr = data.host_write_only();\n                for (size_t i = 0; i < data.size(); ++i)\n                    ptr[i] = 0;\n\n            }\n\n            // now build the image pyramid into data.  This does the same thing as\n            // standard create_tiled_pyramid(), except we use the GPU if one is available.\n            void create_tiled_pyramid (\n                const std::vector<rectangle>& rects,\n                resizable_tensor& data\n            ) const\n            {\n                for (size_t i = 1; i < rects.size(); ++i) {\n                    alias_tensor src(data.num_samples(), data.k(), rects[i - 1].height(), rects[i - 1].width());\n                    alias_tensor dest(data.num_samples(), data.k(), rects[i].height(), rects[i].width());\n\n                    auto asrc = src(data, data.nc() * rects[i - 1].top() + rects[i - 1].left());\n                    auto adest = dest(data, data.nc() * rects[i].top() + rects[i].left());\n\n                    tt::resize_bilinear(adest, data.nc(), data.nr() * data.nc(),\n                                        asrc, data.nc(), data.nr() * data.nc());\n                }\n            }\n\n            unsigned long pyramid_padding = 10;\n            unsigned long pyramid_outer_padding = 11;\n        };\n\n        template <typename PYRAMID_TYPE>\n        input_image_pyramid<PYRAMID_TYPE>::~input_image_pyramid() {}\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename PYRAMID_TYPE>\n    class input_grayscale_image_pyramid : public detail::input_image_pyramid<PYRAMID_TYPE>\n    {\n    public:\n        typedef matrix<unsigned char> input_type;\n        typedef PYRAMID_TYPE pyramid_type;\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            this->to_tensor_init(ibegin, iend, data, 1);\n\n            const auto rects = data.annotation().get<std::vector<rectangle>>();\n            if (rects.size() == 0)\n                return;\n\n            // copy the first raw image into the top part of the tiled pyramid.  We need to\n            // do this for each of the input images/samples in the tensor.\n            auto ptr = data.host_write_only();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                auto& img = *i;\n                ptr += rects[0].top()*data.nc();\n                for (long r = 0; r < img.nr(); ++r)\n                {\n                    auto p = ptr+rects[0].left();\n                    for (long c = 0; c < img.nc(); ++c)\n                        p[c] = (img(r,c))/256.0;\n                    ptr += data.nc();\n                }\n                ptr += data.nc()*(data.nr()-rects[0].bottom()-1);\n            }\n\n            this->create_tiled_pyramid(rects, data);\n        }\n\n        friend void serialize(const input_grayscale_image_pyramid& item, std::ostream& out)\n        {\n            serialize(\"input_grayscale_image_pyramid\", out);\n            serialize(item.pyramid_padding, out);\n            serialize(item.pyramid_outer_padding, out);\n        }\n\n        friend void deserialize(input_grayscale_image_pyramid& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_grayscale_image_pyramid\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_grayscale_image_pyramid.\");\n            deserialize(item.pyramid_padding, in);\n            deserialize(item.pyramid_outer_padding, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_grayscale_image_pyramid& item)\n        {\n            out << \"input_grayscale_image_pyramid()\";\n            out << \" pyramid_padding=\"<<item.pyramid_padding;\n            out << \" pyramid_outer_padding=\"<<item.pyramid_outer_padding;\n            return out;\n        }\n\n        friend void to_xml(const input_grayscale_image_pyramid& item, std::ostream& out)\n        {\n            out << \"<input_grayscale_image_pyramid\"\n                <<\"' pyramid_padding='\"<<item.pyramid_padding\n                <<\"' pyramid_outer_padding='\"<<item.pyramid_outer_padding\n                <<\"'/>\\n\";\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename PYRAMID_TYPE>\n    class input_rgb_image_pyramid : public detail::input_image_pyramid<PYRAMID_TYPE>\n    {\n    public:\n        typedef matrix<rgb_pixel> input_type;\n        typedef PYRAMID_TYPE pyramid_type;\n\n        input_rgb_image_pyramid (\n        ) :\n            avg_red(122.782),\n            avg_green(117.001),\n            avg_blue(104.298)\n        {\n        }\n\n        input_rgb_image_pyramid (\n            float avg_red_,\n            float avg_green_,\n            float avg_blue_\n        ) : avg_red(avg_red_), avg_green(avg_green_), avg_blue(avg_blue_)\n        {}\n\n        float get_avg_red()   const { return avg_red; }\n        float get_avg_green() const { return avg_green; }\n        float get_avg_blue()  const { return avg_blue; }\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            this->to_tensor_init(ibegin, iend, data, 3);\n\n            const auto rects = data.annotation().get<std::vector<rectangle>>();\n            if (rects.size() == 0)\n                return;\n\n            // copy the first raw image into the top part of the tiled pyramid.  We need to\n            // do this for each of the input images/samples in the tensor.\n            auto ptr = data.host_write_only();\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                auto& img = *i;\n                ptr += rects[0].top()*data.nc();\n                for (long r = 0; r < img.nr(); ++r)\n                {\n                    auto p = ptr+rects[0].left();\n                    for (long c = 0; c < img.nc(); ++c)\n                        p[c] = (img(r,c).red-avg_red)/256.0;\n                    ptr += data.nc();\n                }\n                ptr += data.nc()*(data.nr()-rects[0].bottom()-1);\n\n                ptr += rects[0].top()*data.nc();\n                for (long r = 0; r < img.nr(); ++r)\n                {\n                    auto p = ptr+rects[0].left();\n                    for (long c = 0; c < img.nc(); ++c)\n                        p[c] = (img(r,c).green-avg_green)/256.0;\n                    ptr += data.nc();\n                }\n                ptr += data.nc()*(data.nr()-rects[0].bottom()-1);\n\n                ptr += rects[0].top()*data.nc();\n                for (long r = 0; r < img.nr(); ++r)\n                {\n                    auto p = ptr+rects[0].left();\n                    for (long c = 0; c < img.nc(); ++c)\n                        p[c] = (img(r,c).blue-avg_blue)/256.0;\n                    ptr += data.nc();\n                }\n                ptr += data.nc()*(data.nr()-rects[0].bottom()-1);\n            }\n\n            this->create_tiled_pyramid(rects, data);\n        }\n\n        friend void serialize(const input_rgb_image_pyramid& item, std::ostream& out)\n        {\n            serialize(\"input_rgb_image_pyramid2\", out);\n            serialize(item.avg_red, out);\n            serialize(item.avg_green, out);\n            serialize(item.avg_blue, out);\n            serialize(item.pyramid_padding, out);\n            serialize(item.pyramid_outer_padding, out);\n        }\n\n        friend void deserialize(input_rgb_image_pyramid& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_rgb_image_pyramid\" && version != \"input_rgb_image_pyramid2\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_rgb_image_pyramid.\");\n            deserialize(item.avg_red, in);\n            deserialize(item.avg_green, in);\n            deserialize(item.avg_blue, in);\n            if (version == \"input_rgb_image_pyramid2\")\n            {\n                deserialize(item.pyramid_padding, in);\n                deserialize(item.pyramid_outer_padding, in);\n            }\n            else\n            {\n                item.pyramid_padding = 10;\n                item.pyramid_outer_padding = 11;\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_rgb_image_pyramid& item)\n        {\n            out << \"input_rgb_image_pyramid(\"<<item.avg_red<<\",\"<<item.avg_green<<\",\"<<item.avg_blue<<\")\";\n            out << \" pyramid_padding=\"<<item.pyramid_padding;\n            out << \" pyramid_outer_padding=\"<<item.pyramid_outer_padding;\n            return out;\n        }\n\n        friend void to_xml(const input_rgb_image_pyramid& item, std::ostream& out)\n        {\n            out << \"<input_rgb_image_pyramid r='\"<<item.avg_red<<\"' g='\"<<item.avg_green\n                <<\"' b='\"<<item.avg_blue\n                <<\"' pyramid_padding='\"<<item.pyramid_padding\n                <<\"' pyramid_outer_padding='\"<<item.pyramid_outer_padding\n                <<\"'/>\\n\";\n        }\n\n    private:\n        float avg_red;\n        float avg_green;\n        float avg_blue;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class input_tensor\n    {\n    public:\n        typedef tensor input_type;\n\n        input_tensor() {}\n        input_tensor(const input_tensor&) {}\n\n        template<typename forward_iterator>\n        void to_tensor(\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const\n        {\n            DLIB_CASSERT(std::distance(ibegin, iend) > 0);\n            const auto k = ibegin->k();\n            const auto nr = ibegin->nr();\n            const auto nc = ibegin->nc();\n            // make sure all the input tensors have the same dimensions\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                DLIB_CASSERT(i->k() == k && i->nr() == nr && i->nc() == nc,\n                    \"\\t input_tensor::to_tensor()\"\n                    << \"\\n\\t All tensor objects given to to_tensor() must have the same dimensions.\"\n                    << \"\\n\\t k: \" << k\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t i->k(): \" << i->k()\n                    << \"\\n\\t i->nr(): \" << i->nr()\n                    << \"\\n\\t i->nc(): \" << i->nc()\n                );\n            }\n\n            const auto num_samples = count_samples(ibegin, iend);\n            // initialize data to the right size to contain the stuff in the iterator range.\n            data.set_size(num_samples, k, nr, nc);\n\n            const size_t stride = k * nr * nc;\n            size_t offset = 0;\n            for (auto i = ibegin; i != iend; ++i)\n            {\n                alias_tensor slice(i->num_samples(), k, nr, nc);\n                memcpy(slice(data, offset), *i);\n                offset += slice.num_samples() * stride;\n            }\n        }\n\n        friend void serialize(const input_tensor&, std::ostream& out)\n        {\n            serialize(\"input_tensor\", out);\n        }\n\n        friend void deserialize(input_tensor&, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"input_tensor\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::input_tensor.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const input_tensor&)\n        {\n            out << \"input_tensor\";\n            return out;\n        }\n\n        friend void to_xml(const input_tensor&, std::ostream& out)\n        {\n            out << \"<input_tensor/>\\n\";\n        }\n\n    private:\n\n        template<typename forward_iterator>\n        long long count_samples(\n            forward_iterator ibegin,\n            forward_iterator iend\n        ) const\n        {\n            return std::accumulate(ibegin, iend, 0,\n                [](long long a, const auto& b) { return a + b.num_samples(); });\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_INPUT_H_\n\n"
  },
  {
    "path": "dlib/dnn/input_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_INPUT_ABSTRACT_H_\n#ifdef DLIB_DNn_INPUT_ABSTRACT_H_\n\n#include \"../matrix.h\"\n#include \"../pixel.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class EXAMPLE_INPUT_LAYER\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                Each deep neural network model in dlib begins with an input layer. The job\n                of the input layer is to convert an input_type into a tensor.  Nothing more\n                and nothing less.  \n                \n                Note that there is no dlib::EXAMPLE_INPUT_LAYER type.  It is shown here\n                purely to document the interface that an input layer object must implement.\n                If you are using some kind of image or matrix object as your input_type\n                then you can use the provided dlib::input layer defined below.  Otherwise,\n                you need to define your own custom input layer.\n\n            THREAD SAFETY\n                to_tensor() must be thread safe.  That is, multiple threads must be able to\n                make calls to to_tensor() on a single instance of this object at the same\n                time.\n        !*/\n    public:\n\n        EXAMPLE_INPUT_LAYER(\n        );\n        /*!\n            ensures\n                - Default constructs this object.  This function is not required to do\n                  anything in particular but it must exist, that is, it is required that\n                  layer objects be default constructable. \n        !*/\n\n        EXAMPLE_INPUT_LAYER (\n            const EXAMPLE_INPUT_LAYER& item\n        );\n        /*!\n            ensures\n                - EXAMPLE_INPUT_LAYER objects are copy constructable\n        !*/\n\n        EXAMPLE_INPUT_LAYER(\n            const some_other_input_layer_type& item\n        );\n        /*!\n            ensures\n                - Constructs this object from item.  This form of constructor is optional\n                  but it allows you to provide a conversion from one input layer type to\n                  another.  For example, the following code is valid only if my_input_layer2 can\n                  be constructed from my_input_layer1:\n                    relu<fc<relu<fc<my_input_layer1>>>> my_dnn1;\n                    relu<fc<relu<fc<my_input_layer2>>>> my_dnn2(my_dnn1);\n                  This kind of pattern is useful if you want to use one type of input layer\n                  during training but a different type of layer during testing since it\n                  allows you to easily convert between related deep neural network types.  \n        !*/\n\n        typedef whatever_type_to_tensor_expects input_type;\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.\n                - #data.num_samples()%distance(ibegin,iend) == 0. \n                  Normally you would have #data.num_samples() == distance(ibegin,iend) but\n                  you can also expand the output by some integer factor so long as the loss\n                  you use can deal with it correctly.\n                - The data in the ith sample of #data corresponds to the input_type object\n                  *(ibegin+i/sample_expansion_factor).\n                  where sample_expansion_factor==#data.num_samples()/distance(ibegin,iend).\n        !*/\n    };\n\n    std::ostream& operator<<(std::ostream& out, const EXAMPLE_INPUT_LAYER& item);\n    /*!\n        print a string describing this layer.\n    !*/\n\n    void to_xml(const EXAMPLE_INPUT_LAYER& item, std::ostream& out);\n    /*!\n        This function is optional, but required if you want to print your networks with\n        net_to_xml().  Therefore, to_xml() prints a layer as XML.\n    !*/\n\n    void serialize(const EXAMPLE_INPUT_LAYER& item, std::ostream& out);\n    void deserialize(EXAMPLE_INPUT_LAYER& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class input \n    {\n        /*!\n            REQUIREMENTS ON T\n                One of the following must be true:\n                    - T is a matrix or array2d object and it must contain some kind of\n                      pixel type.  I.e. pixel_traits<T::type> must be defined.   \n                    - T is a std::array<matrix<U>> where U is any built in scalar type like\n                      float, double, or unsigned char. \n\n            WHAT THIS OBJECT REPRESENTS\n                This is a basic input layer that simply copies images into a tensor.  \n        !*/\n\n    public:\n        typedef T input_type;\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain image objects that all have the same\n                  dimensions.\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.  In\n                  particular, if the input images have R rows, C columns, and K channels\n                  (where K is given by pixel_traits::num or std::array::size() if\n                  std::array inputs are used) then we will have:\n                    - #data.num_samples() == std::distance(ibegin,iend)\n                    - #data.nr() == R\n                    - #data.nc() == C\n                    - #data.k() == K\n                  For example, a matrix<float,3,3> would turn into a tensor with 3 rows, 3\n                  columns, and k()==1.  Or a matrix<rgb_pixel,4,5> would turn into a tensor\n                  with 4 rows, 5 columns, and k()==3 (since rgb_pixels have 3 channels).\n                  Or a std::array<matrix<float,3,3>,5> would turn into a tensor with 3 rows\n                  and columns, and k()==5 channels.\n                - If the input data contains pixels of type unsigned char, rgb_pixel, or\n                  other pixel types with a basic_pixel_type of unsigned char then each\n                  value written to the output tensor is first divided by 256.0 so that the\n                  resulting outputs are all in the range [0,1].\n        !*/\n\n        // Provided for compatibility with input_rgb_image_pyramid's interface\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class input_rgb_image\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This input layer works with RGB images of type matrix<rgb_pixel>.  It is\n                very similar to the dlib::input layer except that it allows you to subtract\n                the average color value from each color channel when converting an image to\n                a tensor.\n        !*/\n    public:\n        typedef matrix<rgb_pixel> input_type;\n\n        input_rgb_image (\n        );\n        /*!\n            ensures\n                - #get_avg_red()   == 122.782\n                - #get_avg_green() == 117.001\n                - #get_avg_blue()  == 104.298\n        !*/\n\n        input_rgb_image (\n            float avg_red,\n            float avg_green,\n            float avg_blue\n        ); \n        /*!\n            ensures\n                - #get_avg_red() == avg_red\n                - #get_avg_green() == avg_green\n                - #get_avg_blue() == avg_blue\n        !*/\n\n        float get_avg_red(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the red color channel.\n        !*/\n\n        float get_avg_green(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the green color channel.\n        !*/\n\n        float get_avg_blue(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the blue color channel.\n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain images that all have the same\n                  dimensions.\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.  In\n                  particular, if the input images have R rows, C columns then we will have:\n                    - #data.num_samples() == std::distance(ibegin,iend)\n                    - #data.nr() == R\n                    - #data.nc() == C\n                    - #data.k() == 3\n                  Moreover, each color channel is normalized by having its average value\n                  subtracted (according to get_avg_red(), get_avg_green(), or\n                  get_avg_blue()) and then is divided by 256.0.\n        !*/\n\n\n        // Provided for compatibility with input_rgb_image_pyramid's interface\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t NR, size_t NC=NR>\n    class input_rgb_image_sized \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This layer has an interface and behavior identical to input_rgb_image\n                except that it requires input images to have NR rows and NC columns.  This\n                is checked by a DLIB_CASSERT inside to_tensor().\n\n                You can also convert between input_rgb_image and input_rgb_image_sized by\n                copy construction or assignment.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class input_rgb_image_pair\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This input layer works with std::pair of RGB images of type matrix<rgb_pixel>.\n                It is useful when you want to input image pairs that are related to each other,\n                for instance, they are different distorted views of the same original image.\n                It is mainly supposed to be used with unsupervised loss functions such as\n                loss_barlow_twins_. You can also convert between input_rgb_image and\n                input_rgb_image_pair by copy construction or assignment.\n        !*/\n    public:\n        typedef std::pair<matrix<rgb_pixel>, matrix<rgb_pixel>> input_type;\n\n        input_rgb_image_pair (\n        );\n        /*!\n            ensures\n                - #get_avg_red()   == 122.782\n                - #get_avg_green() == 117.001\n                - #get_avg_blue()  == 104.298\n        !*/\n\n        input_rgb_image_pair (\n            float avg_red,\n            float avg_green,\n            float avg_blue\n        );\n        /*!\n            ensures\n                - #get_avg_red() == avg_red\n                - #get_avg_green() == avg_green\n                - #get_avg_blue() == avg_blue\n        !*/\n\n        inline input_rgb_image_pair (\n            const input_rgb_image& item\n        );\n        /*!\n            ensures\n                - #get_avg_red() == item.get_avg_red()\n                - #get_avg_green() == item.get_avg_green()\n                - #get_avg_blue() == item.get_avg_blue()\n        !*/\n\n        template <size_t NR, size_t NC>\n        inline input_rgb_image_pair (\n            const input_rgb_image_sized<NR, NC>& item\n        );\n        /*!\n            ensures\n                - #get_avg_red() == item.get_avg_red()\n                - #get_avg_green() == item.get_avg_green()\n                - #get_avg_blue() == item.get_avg_blue()\n        !*/\n\n        float get_avg_red(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the red color channel.\n        !*/\n\n        float get_avg_green(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the green color channel.\n        !*/\n\n        float get_avg_blue(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the blue color channel.\n        !*/\n\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain images that all have the same\n                  dimensions.\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.  In\n                  particular, if the input images have R rows, C columns then we will have:\n                    - #data.num_samples() == 2 * std::distance(ibegin,iend)\n                    - #data.nr() == R\n                    - #data.nc() == C\n                    - #data.k() == 3\n                  Moreover, each color channel is normalized by having its average value\n                  subtracted (according to get_avg_red(), get_avg_green(), or\n                  get_avg_blue()) and then is divided by 256.0.\n                  Additionally, the first elements in each pair are placed in the first half\n                  of the batch, and the second elements in the second half.\n        !*/\n\n        // Provided for compatibility with input_rgb_image_pyramid's interface\n        bool image_contained_point ( const tensor& data, const point& p) const { return get_rect(data).contains(p); }\n        drectangle tensor_space_to_image_space ( const tensor& /*data*/, drectangle r) const { return r; }\n        drectangle image_space_to_tensor_space ( const tensor& /*data*/, double /*scale*/, drectangle r ) const { return r; }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PYRAMID_TYPE\n        >\n    class input_grayscale_image_pyramid\n    {\n        /*!\n            REQUIREMENTS ON PYRAMID_TYPE\n                PYRAMID_TYPE must be an instance of the dlib::pyramid_down template.\n\n            WHAT THIS OBJECT REPRESENTS\n                This input layer works with gray scale images of type matrix<unsigned char>.\n                It is identical to input layer except that it outputs a tensor containing a tiled\n                image pyramid of each input image rather than a simple copy of each image.\n                The tiled image pyramid is created using create_tiled_pyramid().\n        !*/\n\n    public:\n\n        typedef matrix<unsigned char> input_type;\n        typedef PYRAMID_TYPE pyramid_type;\n        input_grayscale_image_pyramid (\n        );\n        /*!\n            ensures\n                - #get_pyramid_padding() == 10\n                - #get_pyramid_outer_padding() == 11\n        !*/\n\n        unsigned long get_pyramid_padding (\n        ) const;\n        /*!\n            ensures\n                - When this object creates a pyramid it will call create_tiled_pyramid() and\n                  set create_tiled_pyramid's pyramid_padding parameter to get_pyramid_padding().\n        !*/\n\n        void set_pyramid_padding (\n            unsigned long value\n        );\n        /*!\n            ensures\n                - #get_pyramid_padding() == value\n        !*/\n\n        unsigned long get_pyramid_outer_padding (\n        ) const;\n        /*!\n            ensures\n                - When this object creates a pyramid it will call create_tiled_pyramid()\n                  and set create_tiled_pyramid's pyramid_outer_padding parameter to\n                  get_pyramid_outer_padding().\n        !*/\n\n        void set_pyramid_outer_padding (\n            unsigned long value\n        );\n        /*!\n            ensures\n                - #get_pyramid_outer_padding() == value\n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain images that all have the same\n                  dimensions.\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.  In\n                  particular, we will have:\n                    - #data.num_samples() == std::distance(ibegin,iend)\n                    - #data.k() == 1\n                    - Each sample in #data contains a tiled image pyramid of the\n                      corresponding input image.  The tiled pyramid is created by\n                      create_tiled_pyramid().\n                  Moreover, each pixel is normalized, dividing them by 256.0.\n        !*/\n\n        bool image_contained_point (\n            const tensor& data,\n            const point& p\n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n            ensures\n                - Since data is a tensor that is built from a bunch of identically sized\n                  images, we can ask if those images were big enough to contain the point\n                  p.  This function returns the answer to that question.\n        !*/\n\n        drectangle image_space_to_tensor_space (\n            const tensor& data,\n            double scale,\n            drectangle r\n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n                - 0 < scale <= 1\n            ensures\n                - This function maps from to_tensor()'s input image space to its output\n                  tensor space.  Therefore, given that data is a tensor produced by\n                  to_tensor(), image_space_to_tensor_space() allows you to ask for the\n                  rectangle in data that corresponds to a rectangle in the original image\n                  space.\n\n                  Note that since the output tensor contains an image pyramid, there are\n                  multiple points in the output tensor that correspond to any input\n                  location.  So you must also specify a scale so we know what level of the\n                  pyramid is needed.  So given a rectangle r in an input image, you can\n                  ask, what rectangle in data corresponds to r when things are scale times\n                  smaller?  That rectangle is returned by this function.\n                - A scale of 1 means we don't move anywhere in the pyramid scale space relative\n                  to the input image while smaller values of scale mean we move down the\n                  pyramid.\n        !*/\n\n        drectangle tensor_space_to_image_space (\n            const tensor& data,\n            drectangle r\n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n            ensures\n                - This function maps from to_tensor()'s output tensor space to its input\n                  image space.  Therefore, given that data is a tensor produced by\n                  to_tensor(), tensor_space_to_image_space() allows you to ask for the\n                  rectangle in the input image that corresponds to a rectangle in data.\n                - It should be noted that this function isn't always an inverse of\n                  image_space_to_tensor_space().  This is because you can ask\n                  image_space_to_tensor_space() for the coordinates of points outside the input\n                  image and they will be mapped to somewhere that doesn't have an inverse.\n                  But for points actually inside the input image this function performs an\n                  approximate inverse mapping.  I.e. when image_contained_point(data,center(r))==true\n                  there is an approximate inverse.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PYRAMID_TYPE\n        >\n    class input_rgb_image_pyramid\n    {\n        /*!\n            REQUIREMENTS ON PYRAMID_TYPE\n                PYRAMID_TYPE must be an instance of the dlib::pyramid_down template.\n\n            WHAT THIS OBJECT REPRESENTS\n                This input layer works with RGB images of type matrix<rgb_pixel>.  It is\n                identical to input_rgb_image except that it outputs a tensor containing a\n                tiled image pyramid of each input image rather than a simple copy of each\n                image.  The tiled image pyramid is created using create_tiled_pyramid().\n        !*/\n\n    public:\n\n        typedef matrix<rgb_pixel> input_type;\n        typedef PYRAMID_TYPE pyramid_type;\n\n        input_rgb_image_pyramid (\n        );\n        /*!\n            ensures\n                - #get_avg_red()   == 122.782\n                - #get_avg_green() == 117.001\n                - #get_avg_blue()  == 104.298\n                - #get_pyramid_padding() == 10\n                - #get_pyramid_outer_padding() == 11\n        !*/\n\n        input_rgb_image_pyramid (\n            float avg_red,\n            float avg_green,\n            float avg_blue\n        ); \n        /*!\n            ensures\n                - #get_avg_red() == avg_red\n                - #get_avg_green() == avg_green\n                - #get_avg_blue() == avg_blue\n                - #get_pyramid_padding() == 10\n                - #get_pyramid_outer_padding() == 11\n        !*/\n\n        float get_avg_red(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the red color channel.\n        !*/\n\n        float get_avg_green(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the green color channel.\n        !*/\n\n        float get_avg_blue(\n        ) const;\n        /*!\n            ensures\n                - returns the value subtracted from the blue color channel.\n        !*/\n\n        unsigned long get_pyramid_padding (\n        ) const; \n        /*!\n            ensures\n                - When this object creates a pyramid it will call create_tiled_pyramid() and\n                  set create_tiled_pyramid's pyramid_padding parameter to get_pyramid_padding().\n        !*/\n        void set_pyramid_padding (\n            unsigned long value\n        );\n        /*!\n            ensures\n                - #get_pyramid_padding() == value\n        !*/\n\n        unsigned long get_pyramid_outer_padding (\n        ) const; \n        /*!\n            ensures\n                - When this object creates a pyramid it will call create_tiled_pyramid()\n                  and set create_tiled_pyramid's pyramid_outer_padding parameter to\n                  get_pyramid_outer_padding().\n        !*/\n        void set_pyramid_outer_padding (\n            unsigned long value\n        );\n        /*!\n            ensures\n                - #get_pyramid_outer_padding() == value\n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor (\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain images that all have the same\n                  dimensions.\n            ensures\n                - Converts the iterator range into a tensor and stores it into #data.  In\n                  particular, we will have:\n                    - #data.num_samples() == std::distance(ibegin,iend)\n                    - #data.k() == 3\n                    - Each sample in #data contains a tiled image pyramid of the\n                      corresponding input image.  The tiled pyramid is created by\n                      create_tiled_pyramid().\n                  Moreover, each color channel is normalized by having its average value\n                  subtracted (according to get_avg_red(), get_avg_green(), or\n                  get_avg_blue()) and then is divided by 256.0.\n        !*/\n\n        bool image_contained_point (\n            const tensor& data,\n            const point& p\n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n            ensures\n                - Since data is a tensor that is built from a bunch of identically sized\n                  images, we can ask if those images were big enough to contain the point\n                  p.  This function returns the answer to that question.\n        !*/\n\n        drectangle image_space_to_tensor_space (\n            const tensor& data,\n            double scale,\n            drectangle r \n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n                - 0 < scale <= 1\n            ensures\n                - This function maps from to_tensor()'s input image space to its output\n                  tensor space.  Therefore, given that data is a tensor produced by\n                  to_tensor(), image_space_to_tensor_space() allows you to ask for the\n                  rectangle in data that corresponds to a rectangle in the original image\n                  space.\n\n                  Note that since the output tensor contains an image pyramid, there are\n                  multiple points in the output tensor that correspond to any input\n                  location.  So you must also specify a scale so we know what level of the\n                  pyramid is needed.  So given a rectangle r in an input image, you can\n                  ask, what rectangle in data corresponds to r when things are scale times\n                  smaller?  That rectangle is returned by this function.\n                - A scale of 1 means we don't move anywhere in the pyramid scale space relative\n                  to the input image while smaller values of scale mean we move down the\n                  pyramid.\n        !*/\n\n        drectangle tensor_space_to_image_space (\n            const tensor& data,\n            drectangle r\n        ) const;\n        /*!\n            requires\n                - data is a tensor that was produced by this->to_tensor()\n            ensures\n                - This function maps from to_tensor()'s output tensor space to its input\n                  image space.  Therefore, given that data is a tensor produced by\n                  to_tensor(), tensor_space_to_image_space() allows you to ask for the\n                  rectangle in the input image that corresponds to a rectangle in data.\n                - It should be noted that this function isn't always an inverse of\n                  image_space_to_tensor_space().  This is because you can ask\n                  image_space_to_tensor_space() for the coordinates of points outside the input\n                  image and they will be mapped to somewhere that doesn't have an inverse.\n                  But for points actually inside the input image this function performs an\n                  approximate inverse mapping.  I.e. when image_contained_point(data,center(r))==true \n                  there is an approximate inverse.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class input_tensor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This input layer works with dlib::tensor objects. It is very similar to\n                the dlib::input layer except that it allows for concatenating data that\n                already resides in GPU memory.\n        !*/\n\n    public:\n        typedef tensor input_type;\n\n        input_tensor(\n        );\n        /*!\n            ensures\n                - input_tensor objects are default constructable\n        !*/\n\n        input_tensor(\n            const input_tensor& item\n        );\n        /*!\n            ensures\n                - input_tensor objects are copy constructable\n        !*/\n\n        template <typename forward_iterator>\n        void to_tensor(\n            forward_iterator ibegin,\n            forward_iterator iend,\n            resizable_tensor& data\n        ) const;\n        /*!\n            requires\n                - [ibegin, iend) is an iterator range over input_type objects.\n                - std::distance(ibegin,iend) > 0\n                - The input range should contain tensor objects that all have the same\n                  dimensions.\n            ensures\n                - Copies the iterator range into #data.  In particular, if the input tensors\n                  have R rows, C columns, and K channels then we will have:\n                    - #data.num_samples() == count_samples(ibegin,iend)\n                    - #data.nr() == R\n                    - #data.nc() == C\n                    - #data.k() == K\n                  This results in a tensor concatenation along the sample dimension.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_DNn_INPUT_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/dnn/layers.h",
    "content": "﻿// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_LAYERS_H_\n#define DLIB_DNn_LAYERS_H_\n\n#include \"layers_abstract.h\"\n#include \"../cuda/tensor.h\"\n#include \"core.h\"\n#include <iostream>\n#include <string>\n#include \"../rand.h\"\n#include \"../string.h\"\n#include \"../cuda/tensor_tools.h\"\n#include \"../vectorstream.h\"\n#include \"utilities.h\"\n#include \"../cuda/operation_mode.h\"\n#include <sstream>\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct num_con_outputs\n    {\n        num_con_outputs(unsigned long n) : num_outputs(n) {}\n        unsigned long num_outputs;\n    };\n\n    template <\n        long _num_filters,\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class con_\n    {\n    public:\n\n        static_assert(_num_filters > 0, \"The number of filters must be > 0\");\n        static_assert(_nr >= 0, \"The number of rows in a filter must be >= 0\");\n        static_assert(_nc >= 0, \"The number of columns in a filter must be >= 0\");\n        static_assert(_stride_y > 0, \"The filter stride must be > 0\");\n        static_assert(_stride_x > 0, \"The filter stride must be > 0\");\n        static_assert(_nr==0 || (0 <= _padding_y && _padding_y < _nr), \"The padding must be smaller than the filter size.\");\n        static_assert(_nc==0 || (0 <= _padding_x && _padding_x < _nc), \"The padding must be smaller than the filter size.\");\n        static_assert(_nr!=0 || 0 == _padding_y, \"If _nr==0 then the padding must be set to 0 as well.\");\n        static_assert(_nc!=0 || 0 == _padding_x, \"If _nr==0 then the padding must be set to 0 as well.\");\n\n        con_(\n            num_con_outputs o\n        ) : \n            learning_rate_multiplier(1),\n            weight_decay_multiplier(1),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(0),\n            num_filters_(o.num_outputs),\n            padding_y_(_padding_y),\n            padding_x_(_padding_x),\n            use_bias(true),\n            use_relu(false)\n        {\n            DLIB_CASSERT(num_filters_ > 0);\n        }\n\n        con_() : con_(num_con_outputs(_num_filters)) {}\n\n        long num_filters() const { return num_filters_; }\n        long nr() const \n        { \n            if (_nr==0)\n                return filters.nr();\n            else\n                return _nr;\n        }\n        long nc() const \n        { \n            if (_nc==0)\n                return filters.nc();\n            else\n                return _nc;\n        }\n        long stride_y() const { return _stride_y; }\n        long stride_x() const { return _stride_x; }\n        long padding_y() const { return padding_y_; }\n        long padding_x() const { return padding_x_; }\n\n        void set_num_filters(long num) \n        {\n            DLIB_CASSERT(num > 0);\n            if (num != num_filters_)\n            {\n                DLIB_CASSERT(get_layer_params().size() == 0, \n                    \"You can't change the number of filters in con_ if the parameter tensor has already been allocated.\");\n                num_filters_ = num;\n            }\n        }\n\n        double get_learning_rate_multiplier () const  { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier () const   { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val)  { weight_decay_multiplier  = val; }\n\n        double get_bias_learning_rate_multiplier () const  { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier () const   { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val)  { bias_weight_decay_multiplier  = val; }\n\n        bool relu_is_disabled() const { return !use_relu; }\n\n        void disable_relu()\n        {\n            use_relu = false;\n        }\n\n        void enable_relu()\n        {\n            use_relu = true;\n        }\n\n        bool bias_is_disabled() const { return !use_bias; }\n\n        void disable_bias()\n        {\n            if (use_bias == false)\n                return;\n\n            use_bias = false;\n            if (params.size() == 0)\n                return;\n\n            DLIB_CASSERT(params.size() == filters.size() + num_filters_);\n            auto temp = params;\n            params.set_size(params.size() - num_filters_);\n            std::copy(temp.begin(), temp.end() - num_filters_, params.begin());\n            biases = alias_tensor();\n        }\n\n        void enable_bias()\n        {\n            if (use_bias == true)\n                return;\n\n            use_bias = true;\n            if (params.size() == 0)\n                return;\n\n            DLIB_CASSERT(params.size() == filters.size());\n            auto temp = params;\n            params.set_size(params.size() + num_filters_);\n            std::copy(temp.begin(), temp.end(), params.begin());\n            biases = alias_tensor(1, num_filters_);\n            biases(params, filters.size()) = 0;\n        }\n\n        inline dpoint map_input_to_output (\n            dpoint p\n        ) const\n        {\n            p.x() = (p.x()+padding_x()-nc()/2)/stride_x();\n            p.y() = (p.y()+padding_y()-nr()/2)/stride_y();\n            return p;\n        }\n\n        inline dpoint map_output_to_input (\n            dpoint p\n        ) const\n        {\n            p.x() = p.x()*stride_x() - padding_x() + nc()/2;\n            p.y() = p.y()*stride_y() - padding_y() + nr()/2;\n            return p;\n        }\n\n        con_ (\n            const con_& item\n        ) : \n            params(item.params),\n            filters(item.filters),\n            biases(item.biases),\n            learning_rate_multiplier(item.learning_rate_multiplier),\n            weight_decay_multiplier(item.weight_decay_multiplier),\n            bias_learning_rate_multiplier(item.bias_learning_rate_multiplier),\n            bias_weight_decay_multiplier(item.bias_weight_decay_multiplier),\n            num_filters_(item.num_filters_),\n            padding_y_(item.padding_y_),\n            padding_x_(item.padding_x_),\n            use_bias(item.use_bias),\n            use_relu(item.use_relu)\n        {\n            // this->conv is non-copyable and basically stateless, so we have to write our\n            // own copy to avoid trying to copy it and getting an error.\n        }\n\n        con_& operator= (\n            const con_& item\n        )\n        {\n            if (this == &item)\n                return *this;\n\n            // this->conv is non-copyable and basically stateless, so we have to write our\n            // own copy to avoid trying to copy it and getting an error.\n            params = item.params;\n            filters = item.filters;\n            biases = item.biases;\n            padding_y_ = item.padding_y_;\n            padding_x_ = item.padding_x_;\n            learning_rate_multiplier = item.learning_rate_multiplier;\n            weight_decay_multiplier = item.weight_decay_multiplier;\n            bias_learning_rate_multiplier = item.bias_learning_rate_multiplier;\n            bias_weight_decay_multiplier = item.bias_weight_decay_multiplier;\n            num_filters_ = item.num_filters_;\n            use_bias = item.use_bias;\n            use_relu = item.use_relu;\n            return *this;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            const long filt_nr = _nr!=0 ? _nr : sub.get_output().nr();\n            const long filt_nc = _nc!=0 ? _nc : sub.get_output().nc();\n\n            long num_inputs = filt_nr*filt_nc*sub.get_output().k();\n            long num_outputs = num_filters_;\n            // allocate params for the filters and also for the filter bias values.\n            params.set_size(num_inputs*num_filters_ + static_cast<int>(use_bias) * num_filters_);\n\n            dlib::rand rnd(std::rand());\n            randomize_parameters(params, num_inputs+num_outputs, rnd);\n\n            filters = alias_tensor(num_filters_, sub.get_output().k(), filt_nr, filt_nc);\n            if (use_bias)\n            {\n                biases = alias_tensor(1,num_filters_);\n                // set the initial bias values to zero\n                biases(params,filters.size()) = 0;\n            }\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            conv.setup(sub.get_output(),\n                       filters(params,0),\n                       _stride_y,\n                       _stride_x,\n                       padding_y_,\n                       padding_x_);\n\n            if (use_bias)\n            {\n                conv(false, output,\n                     sub.get_output(),\n                     filters(params,0),\n                     biases(params, filters.size()),\n                     use_relu);\n            }\n            else\n            {\n                conv(false, output,\n                     sub.get_output(),\n                     filters(params,0));\n            }\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            conv.get_gradient_for_data (true, gradient_input, filters(params,0), sub.get_gradient_input());\n            // no point computing the parameter gradients if they won't be used.\n            if (learning_rate_multiplier != 0)\n            {\n                auto filt = filters(params_grad,0);\n                conv.get_gradient_for_filters (false, gradient_input, sub.get_output(), filt);\n                if (use_bias)\n                {\n                    auto b = biases(params_grad, filters.size());\n                    tt::assign_conv_bias_gradient(b, gradient_input);\n                }\n            }\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const con_& item, std::ostream& out)\n        {\n            serialize(\"con_6\", out);\n            serialize(item.params, out);\n            serialize(item.num_filters_, out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n            serialize(_stride_y, out);\n            serialize(_stride_x, out);\n            serialize(item.padding_y_, out);\n            serialize(item.padding_x_, out);\n            serialize(item.filters, out);\n            serialize(item.biases, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.use_bias, out);\n            serialize(item.use_relu, out);\n        }\n\n        friend void deserialize(con_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            long nr;\n            long nc;\n            int stride_y;\n            int stride_x;\n            if (version == \"con_4\" || version == \"con_5\" || version == \"con_6\")\n            {\n                deserialize(item.params, in);\n                deserialize(item.num_filters_, in);\n                deserialize(nr, in);\n                deserialize(nc, in);\n                deserialize(stride_y, in);\n                deserialize(stride_x, in);\n                deserialize(item.padding_y_, in);\n                deserialize(item.padding_x_, in);\n                deserialize(item.filters, in);\n                deserialize(item.biases, in);\n                deserialize(item.learning_rate_multiplier, in);\n                deserialize(item.weight_decay_multiplier, in);\n                deserialize(item.bias_learning_rate_multiplier, in);\n                deserialize(item.bias_weight_decay_multiplier, in);\n                if (item.padding_y_ != _padding_y) throw serialization_error(\"Wrong padding_y found while deserializing dlib::con_\");\n                if (item.padding_x_ != _padding_x) throw serialization_error(\"Wrong padding_x found while deserializing dlib::con_\");\n                if (nr != _nr) throw serialization_error(\"Wrong nr found while deserializing dlib::con_\");\n                if (nc != _nc) throw serialization_error(\"Wrong nc found while deserializing dlib::con_\");\n                if (stride_y != _stride_y) throw serialization_error(\"Wrong stride_y found while deserializing dlib::con_\");\n                if (stride_x != _stride_x) throw serialization_error(\"Wrong stride_x found while deserializing dlib::con_\");\n                if (version == \"con_5\" || version == \"con_6\")\n                {\n                    deserialize(item.use_bias, in);\n                }\n                if (version == \"con_6\")\n                {\n                    deserialize(item.use_relu, in);\n                }\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::con_.\");\n            }\n        }\n\n\n        friend std::ostream& operator<<(std::ostream& out, const con_& item)\n        {\n            out << \"con\\t (\"\n                << \"num_filters=\"<<item.num_filters_\n                << \", nr=\"<<item.nr()\n                << \", nc=\"<<item.nc()\n                << \", stride_y=\"<<_stride_y\n                << \", stride_x=\"<<_stride_x\n                << \", padding_y=\"<<item.padding_y_\n                << \", padding_x=\"<<item.padding_x_\n                << \")\";\n            out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n            out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n            if (item.use_bias)\n            {\n                out << \" bias_learning_rate_mult=\"<<item.bias_learning_rate_multiplier;\n                out << \" bias_weight_decay_mult=\"<<item.bias_weight_decay_multiplier;\n            }\n            else\n            {\n                out << \" use_bias=false\";\n            }\n            if (item.use_relu)\n            {\n                out << \" use_relu=\"<< std::boolalpha << item.use_relu;\n            }\n            return out;\n        }\n\n        friend void to_xml(const con_& item, std::ostream& out)\n        {\n            out << \"<con\"\n                << \" num_filters='\"<<item.num_filters_<<\"'\"\n                << \" nr='\"<<item.nr()<<\"'\"\n                << \" nc='\"<<item.nc()<<\"'\"\n                << \" stride_y='\"<<_stride_y<<\"'\"\n                << \" stride_x='\"<<_stride_x<<\"'\"\n                << \" padding_y='\"<<item.padding_y_<<\"'\"\n                << \" padding_x='\"<<item.padding_x_<<\"'\"\n                << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\"\n                << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\"\n                << \" bias_learning_rate_mult='\"<<item.bias_learning_rate_multiplier<<\"'\"\n                << \" bias_weight_decay_mult='\"<<item.bias_weight_decay_multiplier<<\"'\"\n                << \" use_bias='\"<<(item.use_bias?\"true\":\"false\")<<\"'\"\n                << \" use_relu='\"<<(item.use_relu?\"true\":\"false\")<<\"'\"\n                << \">\\n\";\n            out << mat(item.params);\n            out << \"</con>\\n\";\n        }\n\n    private:\n\n        resizable_tensor params;\n        alias_tensor filters, biases;\n\n        tt::tensor_conv conv;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        long num_filters_;\n\n        // These are here only because older versions of con (which you might encounter\n        // serialized to disk) used different padding settings.\n        int padding_y_;\n        int padding_x_;\n        bool use_bias;\n        bool use_relu;\n    };\n\n    template <\n        long num_filters,\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using con = add_layer<con_<num_filters,nr,nc,stride_y,stride_x>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _num_filters,\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class cont_\n    {\n    public:\n\n        static_assert(_num_filters > 0, \"The number of filters must be > 0\");\n        static_assert(_nr > 0, \"The number of rows in a filter must be > 0\");\n        static_assert(_nc > 0, \"The number of columns in a filter must be > 0\");\n        static_assert(_stride_y > 0, \"The filter stride must be > 0\");\n        static_assert(_stride_x > 0, \"The filter stride must be > 0\");\n        static_assert(0 <= _padding_y && _padding_y < _nr, \"The padding must be smaller than the filter size.\");\n        static_assert(0 <= _padding_x && _padding_x < _nc, \"The padding must be smaller than the filter size.\");\n\n        cont_(\n            num_con_outputs o\n        ) : \n            learning_rate_multiplier(1),\n            weight_decay_multiplier(1),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(0),\n            num_filters_(o.num_outputs),\n            padding_y_(_padding_y),\n            padding_x_(_padding_x),\n            use_bias(true)\n        {\n            DLIB_CASSERT(num_filters_ > 0);\n        }\n\n        cont_() : cont_(num_con_outputs(_num_filters)) {}\n\n        long num_filters() const { return num_filters_; }\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n        long stride_y() const { return _stride_y; }\n        long stride_x() const { return _stride_x; }\n        long padding_y() const { return padding_y_; }\n        long padding_x() const { return padding_x_; }\n\n        void set_num_filters(long num)\n        {\n            DLIB_CASSERT(num > 0);\n            if (num != num_filters_)\n            {\n                DLIB_CASSERT(get_layer_params().size() == 0,\n                    \"You can't change the number of filters in cont_ if the parameter tensor has already been allocated.\");\n                num_filters_ = num;\n            }\n        }\n\n        double get_learning_rate_multiplier () const  { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier () const   { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val)  { weight_decay_multiplier  = val; }\n\n        double get_bias_learning_rate_multiplier () const  { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier () const   { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val)  { bias_weight_decay_multiplier  = val; }\n        void disable_bias() { use_bias = false; }\n        bool bias_is_disabled() const { return !use_bias; }\n\n        inline dpoint map_output_to_input (\n            dpoint p\n        ) const\n        {\n            p.x() = (p.x()+padding_x()-nc()/2)/stride_x();\n            p.y() = (p.y()+padding_y()-nr()/2)/stride_y();\n            return p;\n        }\n\n        inline dpoint map_input_to_output (\n            dpoint p\n        ) const\n        {\n            p.x() = p.x()*stride_x() - padding_x() + nc()/2;\n            p.y() = p.y()*stride_y() - padding_y() + nr()/2;\n            return p;\n        }\n\n        cont_ (\n            const cont_& item\n        ) : \n            params(item.params),\n            filters(item.filters),\n            biases(item.biases),\n            learning_rate_multiplier(item.learning_rate_multiplier),\n            weight_decay_multiplier(item.weight_decay_multiplier),\n            bias_learning_rate_multiplier(item.bias_learning_rate_multiplier),\n            bias_weight_decay_multiplier(item.bias_weight_decay_multiplier),\n            num_filters_(item.num_filters_),\n            padding_y_(item.padding_y_),\n            padding_x_(item.padding_x_),\n            use_bias(item.use_bias)\n        {\n            // this->conv is non-copyable and basically stateless, so we have to write our\n            // own copy to avoid trying to copy it and getting an error.\n        }\n\n        cont_& operator= (\n            const cont_& item\n        )\n        {\n            if (this == &item)\n                return *this;\n\n            // this->conv is non-copyable and basically stateless, so we have to write our\n            // own copy to avoid trying to copy it and getting an error.\n            params = item.params;\n            filters = item.filters;\n            biases = item.biases;\n            padding_y_ = item.padding_y_;\n            padding_x_ = item.padding_x_;\n            learning_rate_multiplier = item.learning_rate_multiplier;\n            weight_decay_multiplier = item.weight_decay_multiplier;\n            bias_learning_rate_multiplier = item.bias_learning_rate_multiplier;\n            bias_weight_decay_multiplier = item.bias_weight_decay_multiplier;\n            num_filters_ = item.num_filters_;\n            use_bias = item.use_bias;\n            return *this;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            long num_inputs = _nr*_nc*sub.get_output().k();\n            long num_outputs = num_filters_;\n            // allocate params for the filters and also for the filter bias values.\n            params.set_size(num_inputs*num_filters_ + num_filters_ * static_cast<int>(use_bias));\n\n            dlib::rand rnd(std::rand());\n            randomize_parameters(params, num_inputs+num_outputs, rnd);\n\n            filters = alias_tensor(sub.get_output().k(), num_filters_, _nr, _nc);\n            if (use_bias)\n            {\n                biases = alias_tensor(1,num_filters_);\n                // set the initial bias values to zero\n                biases(params,filters.size()) = 0;\n            }\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto filt = filters(params,0);\n            unsigned int gnr = _stride_y * (sub.get_output().nr() - 1) + filt.nr() - 2 * padding_y_;\n            unsigned int gnc = _stride_x * (sub.get_output().nc() - 1) + filt.nc() - 2 * padding_x_;\n            unsigned int gnsamps = sub.get_output().num_samples();\n            unsigned int gk = filt.k();\n            output.set_size(gnsamps,gk,gnr,gnc);\n            conv.setup(output,filt,_stride_y,_stride_x,padding_y_,padding_x_);\n            conv.get_gradient_for_data(false, sub.get_output(),filt,output);            \n            if (use_bias)\n            {\n                tt::add(1,output,1,biases(params,filters.size()));\n            }\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            auto filt = filters(params,0);           \n            conv(true, sub.get_gradient_input(),gradient_input, filt);\n            // no point computing the parameter gradients if they won't be used.\n            if (learning_rate_multiplier != 0)\n            {\n                auto filt = filters(params_grad,0);                \n                conv.get_gradient_for_filters (false, sub.get_output(),gradient_input, filt);\n                if (use_bias)\n                {\n                    auto b = biases(params_grad, filters.size());\n                    tt::assign_conv_bias_gradient(b, gradient_input);\n                }\n            }\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const cont_& item, std::ostream& out)\n        {\n            serialize(\"cont_2\", out);\n            serialize(item.params, out);\n            serialize(item.num_filters_, out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n            serialize(_stride_y, out);\n            serialize(_stride_x, out);\n            serialize(item.padding_y_, out);\n            serialize(item.padding_x_, out);\n            serialize(item.filters, out);\n            serialize(item.biases, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.use_bias, out);\n        }\n\n        friend void deserialize(cont_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            long nr;\n            long nc;\n            int stride_y;\n            int stride_x;\n            if (version == \"cont_1\" || version == \"cont_2\")\n            {\n                deserialize(item.params, in);\n                deserialize(item.num_filters_, in);\n                deserialize(nr, in);\n                deserialize(nc, in);\n                deserialize(stride_y, in);\n                deserialize(stride_x, in);\n                deserialize(item.padding_y_, in);\n                deserialize(item.padding_x_, in);\n                deserialize(item.filters, in);\n                deserialize(item.biases, in);\n                deserialize(item.learning_rate_multiplier, in);\n                deserialize(item.weight_decay_multiplier, in);\n                deserialize(item.bias_learning_rate_multiplier, in);\n                deserialize(item.bias_weight_decay_multiplier, in);\n                if (item.padding_y_ != _padding_y) throw serialization_error(\"Wrong padding_y found while deserializing dlib::con_\");\n                if (item.padding_x_ != _padding_x) throw serialization_error(\"Wrong padding_x found while deserializing dlib::con_\");\n                if (nr != _nr) throw serialization_error(\"Wrong nr found while deserializing dlib::con_\");\n                if (nc != _nc) throw serialization_error(\"Wrong nc found while deserializing dlib::con_\");\n                if (stride_y != _stride_y) throw serialization_error(\"Wrong stride_y found while deserializing dlib::con_\");\n                if (stride_x != _stride_x) throw serialization_error(\"Wrong stride_x found while deserializing dlib::con_\");\n                if (version == \"cont_2\")\n                {\n                    deserialize(item.use_bias, in);\n                }\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::con_.\");\n            }\n        }\n\n\n        friend std::ostream& operator<<(std::ostream& out, const cont_& item)\n        {\n            out << \"cont\\t (\"\n                << \"num_filters=\"<<item.num_filters_\n                << \", nr=\"<<_nr\n                << \", nc=\"<<_nc\n                << \", stride_y=\"<<_stride_y\n                << \", stride_x=\"<<_stride_x\n                << \", padding_y=\"<<item.padding_y_\n                << \", padding_x=\"<<item.padding_x_\n                << \")\";\n            out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n            out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n            if (item.use_bias)\n            {\n                out << \" bias_learning_rate_mult=\"<<item.bias_learning_rate_multiplier;\n                out << \" bias_weight_decay_mult=\"<<item.bias_weight_decay_multiplier;\n            }\n            else\n            {\n                out << \" use_bias=false\";\n            }\n            return out;\n        }\n\n        friend void to_xml(const cont_& item, std::ostream& out)\n        {\n            out << \"<cont\"\n                << \" num_filters='\"<<item.num_filters_<<\"'\"\n                << \" nr='\"<<_nr<<\"'\"\n                << \" nc='\"<<_nc<<\"'\"\n                << \" stride_y='\"<<_stride_y<<\"'\"\n                << \" stride_x='\"<<_stride_x<<\"'\"\n                << \" padding_y='\"<<item.padding_y_<<\"'\"\n                << \" padding_x='\"<<item.padding_x_<<\"'\"\n                << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\"\n                << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\"\n                << \" bias_learning_rate_mult='\"<<item.bias_learning_rate_multiplier<<\"'\"\n                << \" bias_weight_decay_mult='\"<<item.bias_weight_decay_multiplier<<\"'\"\n                << \" use_bias='\"<<(item.use_bias?\"true\":\"false\")<<\"'>\\n\";\n            out << mat(item.params);\n            out << \"</cont>\\n\";\n        }\n\n    private:\n\n        resizable_tensor params;\n        alias_tensor filters, biases;\n\n        tt::tensor_conv conv;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        long num_filters_;\n\n        int padding_y_;\n        int padding_x_;\n\n        bool use_bias;\n\n    };\n\n    template <\n        long num_filters,\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using cont = add_layer<cont_<num_filters,nr,nc,stride_y,stride_x>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        int scale_y, \n        int scale_x \n        >\n    class upsample_\n    {\n    public:\n        static_assert(scale_y >= 1, \"upsampling scale factor can't be less than 1.\");\n        static_assert(scale_x >= 1, \"upsampling scale factor can't be less than 1.\");\n\n        upsample_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            output.set_size(\n                sub.get_output().num_samples(),\n                sub.get_output().k(),\n                scale_y*sub.get_output().nr(),\n                scale_x*sub.get_output().nc());\n            tt::resize_bilinear(output, sub.get_output());\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            tt::resize_bilinear_gradient(sub.get_gradient_input(), gradient_input);\n        }\n\n        inline dpoint map_input_to_output (dpoint p) const \n        { \n            p.x() = p.x()*scale_x;\n            p.y() = p.y()*scale_y;\n            return p; \n        }\n        inline dpoint map_output_to_input (dpoint p) const \n        { \n            p.x() = p.x()/scale_x;\n            p.y() = p.y()/scale_y;\n            return p; \n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const upsample_& /*item*/, std::ostream& out)\n        {\n            serialize(\"upsample_\", out);\n            serialize(scale_y, out);\n            serialize(scale_x, out);\n        }\n\n        friend void deserialize(upsample_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"upsample_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::upsample_.\");\n\n            int _scale_y;\n            int _scale_x;\n            deserialize(_scale_y, in);\n            deserialize(_scale_x, in);\n            if (_scale_y != scale_y || _scale_x != scale_x)\n                throw serialization_error(\"Wrong scale found while deserializing dlib::upsample_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const upsample_& /*item*/)\n        {\n            out << \"upsample\\t (\"\n                << \"scale_y=\"<<scale_y\n                << \", scale_x=\"<<scale_x\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const upsample_& /*item*/, std::ostream& out)\n        {\n            out << \"<upsample\"\n                << \" scale_y='\"<<scale_y<<\"'\"\n                << \" scale_x='\"<<scale_x<<\"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <\n        int scale,\n        typename SUBNET\n        >\n    using upsample = add_layer<upsample_<scale,scale>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR_, \n        long NC_\n        >\n    class resize_to_\n    {\n    public:\n        static_assert(NR_ >= 1, \"NR resize parameter can't be less than 1.\");\n        static_assert(NC_ >= 1, \"NC resize parameter can't be less than 1.\");\n        \n        resize_to_()\n        {\n        }\n        \n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n    \n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            scale_y = (double)NR_/(double)sub.get_output().nr();\n            scale_x = (double)NC_/(double)sub.get_output().nc();\n            \n            output.set_size(\n                sub.get_output().num_samples(),\n                sub.get_output().k(),\n                NR_,\n                NC_);\n            tt::resize_bilinear(output, sub.get_output());\n        } \n        \n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            tt::resize_bilinear_gradient(sub.get_gradient_input(), gradient_input);\n        }\n        \n        inline dpoint map_input_to_output (dpoint p) const \n        { \n            p.x() = p.x()*scale_x;\n            p.y() = p.y()*scale_y;\n            return p; \n        }\n\n        inline dpoint map_output_to_input (dpoint p) const \n        { \n            p.x() = p.x()/scale_x;\n            p.y() = p.y()/scale_y;\n            return p; \n        }\n        \n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n        \n        friend void serialize(const resize_to_& item, std::ostream& out)\n        {\n            serialize(\"resize_to_\", out);\n            serialize(NR_, out);\n            serialize(NC_, out);\n            serialize(item.scale_y, out);\n            serialize(item.scale_x, out);\n        }\n        \n        friend void deserialize(resize_to_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"resize_to_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::resize_to_.\");\n\n            long _nr;\n            long _nc;\n            deserialize(_nr, in);\n            deserialize(_nc, in);\n            deserialize(item.scale_y, in);\n            deserialize(item.scale_x, in);\n            if (_nr != NR_ || _nc != NC_)\n                throw serialization_error(\"Wrong size found while deserializing dlib::resize_to_\");\n        }\n        \n        friend std::ostream& operator<<(std::ostream& out, const resize_to_& /*item*/)\n        {\n            out << \"resize_to (\"\n                << \"nr=\" << NR_\n                << \", nc=\" << NC_\n                << \")\";\n            return out;\n        }\n        \n        friend void to_xml(const resize_to_& /*item*/, std::ostream& out)\n        {\n            out << \"<resize_to\";\n            out << \" nr='\" << NR_ << \"'\" ;\n            out << \" nc='\" << NC_ << \"'/>\\n\";\n        }\n    private:\n        resizable_tensor params;\n        double scale_y;\n        double scale_x;\n    \n    };  // end of class resize_to_\n    \n    \n    template <\n        long NR,\n        long NC,\n        typename SUBNET\n        >\n    using resize_to = add_layer<resize_to_<NR,NC>, SUBNET>;\n    \n// ----------------------------------------------------------------------------------------\n\n    template <long k_ = -1, long nr_ = -1, long nc_ = -1>\n    class reshape_to_\n    {\n    public:\n        explicit reshape_to_() :\n            output_k(k_),\n            output_nr(nr_),\n            output_nc(nc_)\n        {\n            static_assert(k_ == -1 || k_ > 0, \"Output k must be positive or -1\");\n            static_assert(nr_ == -1 || nr_ > 0, \"Output nr must be positive or -1\");\n            static_assert(nc_ == -1 || nc_ > 0, \"Output nc must be positive or -1\");\n\n            input_k = input_nr = input_nc = 0;\n            needs_rescale = false;\n        }\n\n        // Getters for dimensions\n        long get_output_k() const { return output_k; }\n        long get_output_nr() const { return output_nr; }\n        long get_output_nc() const { return output_nc; }\n\n        // Setters for dimensions\n        void set_output_k(long k) {\n            DLIB_CASSERT(k == -1 || k > 0, \"Output k must be positive or -1 to keep original dimension\");\n            output_k = k;\n        }\n        void set_output_nr(long nr) {\n            DLIB_CASSERT(nr == -1 || nr > 0, \"output nr must be positive or -1 to keep original dimension\");\n            output_nr = nr;\n        }\n        void set_output_nc(long nc) {\n            DLIB_CASSERT(nc == -1 || nc > 0, \"output nc must be positive or -1 to keep original dimension\");\n            output_nc = nc;\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& sub)\n        {\n            const auto& input = sub.get_output();\n            input_k = input.k();\n            input_nr = input.nr();\n            input_nc = input.nc();\n\n            // Calculate output dimensions using input dims where target is -1\n            if (k_ == -1) output_k = input_k;\n            if (nr_ == -1) output_nr = input_nr;\n            if (nc_ == -1) output_nc = input_nc;\n\n            // Check if this is well a pure reshape\n            long input_elements = input_k * input_nr * input_nc;\n            long output_elements = output_k * output_nr * output_nc;\n            if (input_elements != output_elements && input_k == output_k) needs_rescale = true;\n            DLIB_CASSERT(input_elements == output_elements || needs_rescale,\n                \"Cannot reshape tensor of \" << input_elements <<\n                \" elements into shape with \" << output_elements << \" elements. \" <<\n                \"For spatial rescaling, the channel dimension (k) must remain constant.\");\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            // Set the output size (always preserving batch dimension)\n            const tensor& input = sub.get_output();\n            output.set_size(input.num_samples(), output_k, output_nr, output_nc);\n\n            if (!needs_rescale)\n            {\n                // Create an alias of the input tensor with the output shape\n                alias_tensor input_alias(output.num_samples(), output_k, output_nr, output_nc);\n                // Get a view of the input tensor with the new shape\n                auto input_reshaped = input_alias(const_cast<tensor&>(input), 0);\n                // Copy the view to the output tensor\n                tt::copy_tensor(false, output, 0, input_reshaped, 0, input_reshaped.k());\n            }\n            else\n            {\n                // Only spatial dimensions need to be resized\n                tt::resize_bilinear(output, input);\n            }\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto& grad = sub.get_gradient_input();\n\n            if (!needs_rescale) {\n                // Create an alias of the gradient tensor with the original input shape\n                alias_tensor grad_alias(grad.num_samples(), grad.k(), grad.nr(), grad.nc());\n                // Get a view of the input gradient with the required shape\n                auto grad_reshaped = grad_alias(const_cast<tensor&>(gradient_input), 0);\n                // Copy the view to the output gradient\n                tt::copy_tensor(true, grad, 0, grad_reshaped, 0, grad_reshaped.k());\n            }\n            else\n            {\n                // Only spatial dimensions were resized\n                tt::resize_bilinear_gradient(grad, gradient_input);\n            }\n        }\n\n        // Mapping functions for coordinate transformations\n        inline dpoint map_input_to_output(const dpoint& p) const {\n            double scale_x = output_nc / static_cast<double>(input_nc);\n            double scale_y = output_nr / static_cast<double>(input_nr);\n            return dpoint(p.x() * scale_x, p.y() * scale_y);\n        }\n        inline dpoint map_output_to_input(const dpoint& p) const {\n            double scale_x = input_nc / static_cast<double>(output_nc);\n            double scale_y = input_nr / static_cast<double>(output_nr);\n            return dpoint(p.x() * scale_x, p.y() * scale_y);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const reshape_to_& item, std::ostream& out)\n        {\n            serialize(\"reshape_to_\", out);\n            serialize(item.input_k, out);\n            serialize(item.input_nr, out);\n            serialize(item.input_nc, out);\n            serialize(item.output_k, out);\n            serialize(item.output_nr, out);\n            serialize(item.output_nc, out);\n            serialize(item.needs_rescale, out);\n        }\n\n        friend void deserialize(reshape_to_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"reshape_to_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::reshape_to_.\");\n            deserialize(item.input_k, in);\n            deserialize(item.input_nr, in);\n            deserialize(item.input_nc, in);\n            deserialize(item.output_k, in);\n            deserialize(item.output_nr, in);\n            deserialize(item.output_nc, in);\n            deserialize(item.needs_rescale, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const reshape_to_& item)\n        {\n            out << \"reshape_to (\";\n            out << \"k=\" << std::to_string(item.output_k);\n            out << \", nr=\" << std::to_string(item.output_nr);\n            out << \", nc=\" << std::to_string(item.output_nc);\n            out << \", mode=\" << (item.needs_rescale ? \"spatial_rescale\" : \"pure_reshape\");\n            out << \")\";\n            return out;\n        }\n\n        friend void to_xml(const reshape_to_& item, std::ostream& out)\n        {\n            out << \"<reshape_to\"\n                << \" k='\" << item.output_k << \"'\"\n                << \" nr='\" << item.output_nr << \"'\"\n                << \" nc='\" << item.output_nc << \"'\"\n                << \" mode='\" << (item.needs_rescale ? \"spatial_rescale\" : \"pure_reshape\") << \"'\"\n                << \"/>\\n\";\n        }\n\n    private:        \n        long input_k, input_nr, input_nc;       // Input dimensions        \n\t\tlong output_k, output_nr, output_nc;    // Output dimensions        \n        bool needs_rescale;        \n        resizable_tensor params;                // No trainable parameters\n    };\n\n    template <long k, long nr, long nc, typename SUBNET>\n    using reshape_to = add_layer<reshape_to_<k, nr, nc>, SUBNET>;\n\n    template <long k, long nr, long nc, typename SUBNET>\n    using flatten = add_layer<reshape_to_<k * nr * nc, 1, 1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class max_pool_\n    {\n        static_assert(_nr >= 0, \"The number of rows in a filter must be >= 0\");\n        static_assert(_nc >= 0, \"The number of columns in a filter must be >= 0\");\n        static_assert(_stride_y > 0, \"The filter stride must be > 0\");\n        static_assert(_stride_x > 0, \"The filter stride must be > 0\");\n        static_assert(0 <= _padding_y && ((_nr==0 && _padding_y == 0) || (_nr!=0 && _padding_y < _nr)), \n            \"The padding must be smaller than the filter size, unless the filters size is 0.\");\n        static_assert(0 <= _padding_x && ((_nc==0 && _padding_x == 0) || (_nc!=0 && _padding_x < _nc)), \n            \"The padding must be smaller than the filter size, unless the filters size is 0.\");\n    public:\n\n\n        max_pool_(\n        ) :\n            padding_y_(_padding_y),\n            padding_x_(_padding_x)\n        {}\n\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n        long stride_y() const { return _stride_y; }\n        long stride_x() const { return _stride_x; }\n        long padding_y() const { return padding_y_; }\n        long padding_x() const { return padding_x_; }\n\n        inline dpoint map_input_to_output (\n            dpoint p\n        ) const\n        {\n            p.x() = (p.x()+padding_x()-nc()/2)/stride_x();\n            p.y() = (p.y()+padding_y()-nr()/2)/stride_y();\n            return p;\n        }\n\n        inline dpoint map_output_to_input (\n            dpoint p\n        ) const\n        {\n            p.x() = p.x()*stride_x() - padding_x() + nc()/2;\n            p.y() = p.y()*stride_y() - padding_y() + nr()/2;\n            return p;\n        }\n\n        max_pool_ (\n            const max_pool_& item\n        )  :\n            padding_y_(item.padding_y_),\n            padding_x_(item.padding_x_)\n        {\n            // this->mp is non-copyable so we have to write our own copy to avoid trying to\n            // copy it and getting an error.\n        }\n\n        max_pool_& operator= (\n            const max_pool_& item\n        )\n        {\n            if (this == &item)\n                return *this;\n\n            padding_y_ = item.padding_y_;\n            padding_x_ = item.padding_x_;\n\n            // this->mp is non-copyable so we have to write our own copy to avoid trying to\n            // copy it and getting an error.\n            return *this;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            mp.setup_max_pooling(_nr!=0?_nr:sub.get_output().nr(), \n                                 _nc!=0?_nc:sub.get_output().nc(),\n                                 _stride_y, _stride_x, padding_y_, padding_x_);\n\n            mp(output, sub.get_output());\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            mp.setup_max_pooling(_nr!=0?_nr:sub.get_output().nr(), \n                                 _nc!=0?_nc:sub.get_output().nc(),\n                                 _stride_y, _stride_x, padding_y_, padding_x_);\n\n            mp.get_gradient(gradient_input, computed_output, sub.get_output(), sub.get_gradient_input());\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const max_pool_& item, std::ostream& out)\n        {\n            serialize(\"max_pool_2\", out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n            serialize(_stride_y, out);\n            serialize(_stride_x, out);\n            serialize(item.padding_y_, out);\n            serialize(item.padding_x_, out);\n        }\n\n        friend void deserialize(max_pool_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            long nr;\n            long nc;\n            int stride_y;\n            int stride_x;\n            if (version == \"max_pool_2\")\n            {\n                deserialize(nr, in);\n                deserialize(nc, in);\n                deserialize(stride_y, in);\n                deserialize(stride_x, in);\n                deserialize(item.padding_y_, in);\n                deserialize(item.padding_x_, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::max_pool_.\");\n            }\n\n            if (item.padding_y_ != _padding_y) throw serialization_error(\"Wrong padding_y found while deserializing dlib::max_pool_\");\n            if (item.padding_x_ != _padding_x) throw serialization_error(\"Wrong padding_x found while deserializing dlib::max_pool_\");\n            if (_nr != nr) throw serialization_error(\"Wrong nr found while deserializing dlib::max_pool_\");\n            if (_nc != nc) throw serialization_error(\"Wrong nc found while deserializing dlib::max_pool_\");\n            if (_stride_y != stride_y) throw serialization_error(\"Wrong stride_y found while deserializing dlib::max_pool_\");\n            if (_stride_x != stride_x) throw serialization_error(\"Wrong stride_x found while deserializing dlib::max_pool_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const max_pool_& item)\n        {\n            out << \"max_pool (\"\n                << \"nr=\"<<_nr\n                << \", nc=\"<<_nc\n                << \", stride_y=\"<<_stride_y\n                << \", stride_x=\"<<_stride_x\n                << \", padding_y=\"<<item.padding_y_\n                << \", padding_x=\"<<item.padding_x_\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const max_pool_& item, std::ostream& out)\n        {\n            out << \"<max_pool\"\n                << \" nr='\"<<_nr<<\"'\"\n                << \" nc='\"<<_nc<<\"'\"\n                << \" stride_y='\"<<_stride_y<<\"'\"\n                << \" stride_x='\"<<_stride_x<<\"'\"\n                << \" padding_y='\"<<item.padding_y_<<\"'\"\n                << \" padding_x='\"<<item.padding_x_<<\"'\"\n                << \"/>\\n\";\n        }\n\n\n    private:\n\n\n        tt::pooling mp;\n        resizable_tensor params;\n\n        int padding_y_;\n        int padding_x_;\n    };\n\n    template <\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using max_pool = add_layer<max_pool_<nr,nc,stride_y,stride_x>, SUBNET>;\n\n    template <\n        typename SUBNET\n        >\n    using max_pool_everything = add_layer<max_pool_<0,0,1,1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class avg_pool_\n    {\n    public:\n        static_assert(_nr >= 0, \"The number of rows in a filter must be >= 0\");\n        static_assert(_nc >= 0, \"The number of columns in a filter must be >= 0\");\n        static_assert(_stride_y > 0, \"The filter stride must be > 0\");\n        static_assert(_stride_x > 0, \"The filter stride must be > 0\");\n        static_assert(0 <= _padding_y && ((_nr==0 && _padding_y == 0) || (_nr!=0 && _padding_y < _nr)), \n            \"The padding must be smaller than the filter size, unless the filters size is 0.\");\n        static_assert(0 <= _padding_x && ((_nc==0 && _padding_x == 0) || (_nc!=0 && _padding_x < _nc)), \n            \"The padding must be smaller than the filter size, unless the filters size is 0.\");\n\n        avg_pool_(\n        ) :\n            padding_y_(_padding_y),\n            padding_x_(_padding_x)\n        {}\n\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n        long stride_y() const { return _stride_y; }\n        long stride_x() const { return _stride_x; }\n        long padding_y() const { return padding_y_; }\n        long padding_x() const { return padding_x_; }\n\n        inline dpoint map_input_to_output (\n            dpoint p\n        ) const\n        {\n            p.x() = (p.x()+padding_x()-nc()/2)/stride_x();\n            p.y() = (p.y()+padding_y()-nr()/2)/stride_y();\n            return p;\n        }\n\n        inline dpoint map_output_to_input (\n            dpoint p\n        ) const\n        {\n            p.x() = p.x()*stride_x() - padding_x() + nc()/2;\n            p.y() = p.y()*stride_y() - padding_y() + nr()/2;\n            return p;\n        }\n\n        avg_pool_ (\n            const avg_pool_& item\n        )  :\n            padding_y_(item.padding_y_),\n            padding_x_(item.padding_x_)\n        {\n            // this->ap is non-copyable so we have to write our own copy to avoid trying to\n            // copy it and getting an error.\n        }\n\n        avg_pool_& operator= (\n            const avg_pool_& item\n        )\n        {\n            if (this == &item)\n                return *this;\n\n            padding_y_ = item.padding_y_;\n            padding_x_ = item.padding_x_;\n\n            // this->ap is non-copyable so we have to write our own copy to avoid trying to\n            // copy it and getting an error.\n            return *this;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            ap.setup_avg_pooling(_nr!=0?_nr:sub.get_output().nr(), \n                                 _nc!=0?_nc:sub.get_output().nc(),\n                                 _stride_y, _stride_x, padding_y_, padding_x_);\n\n            ap(output, sub.get_output());\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            ap.setup_avg_pooling(_nr!=0?_nr:sub.get_output().nr(), \n                                 _nc!=0?_nc:sub.get_output().nc(),\n                                 _stride_y, _stride_x, padding_y_, padding_x_);\n\n            ap.get_gradient(gradient_input, computed_output, sub.get_output(), sub.get_gradient_input());\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const avg_pool_& item, std::ostream& out)\n        {\n            serialize(\"avg_pool_2\", out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n            serialize(_stride_y, out);\n            serialize(_stride_x, out);\n            serialize(item.padding_y_, out);\n            serialize(item.padding_x_, out);\n        }\n\n        friend void deserialize(avg_pool_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n\n            long nr;\n            long nc;\n            int stride_y;\n            int stride_x;\n            if (version == \"avg_pool_2\")\n            {\n                deserialize(nr, in);\n                deserialize(nc, in);\n                deserialize(stride_y, in);\n                deserialize(stride_x, in);\n                deserialize(item.padding_y_, in);\n                deserialize(item.padding_x_, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::avg_pool_.\");\n            }\n\n            if (item.padding_y_ != _padding_y) throw serialization_error(\"Wrong padding_y found while deserializing dlib::avg_pool_\");\n            if (item.padding_x_ != _padding_x) throw serialization_error(\"Wrong padding_x found while deserializing dlib::avg_pool_\");\n            if (_nr != nr) throw serialization_error(\"Wrong nr found while deserializing dlib::avg_pool_\");\n            if (_nc != nc) throw serialization_error(\"Wrong nc found while deserializing dlib::avg_pool_\");\n            if (_stride_y != stride_y) throw serialization_error(\"Wrong stride_y found while deserializing dlib::avg_pool_\");\n            if (_stride_x != stride_x) throw serialization_error(\"Wrong stride_x found while deserializing dlib::avg_pool_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const avg_pool_& item)\n        {\n            out << \"avg_pool (\"\n                << \"nr=\"<<_nr\n                << \", nc=\"<<_nc\n                << \", stride_y=\"<<_stride_y\n                << \", stride_x=\"<<_stride_x\n                << \", padding_y=\"<<item.padding_y_\n                << \", padding_x=\"<<item.padding_x_\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const avg_pool_& item, std::ostream& out)\n        {\n            out << \"<avg_pool\"\n                << \" nr='\"<<_nr<<\"'\"\n                << \" nc='\"<<_nc<<\"'\"\n                << \" stride_y='\"<<_stride_y<<\"'\"\n                << \" stride_x='\"<<_stride_x<<\"'\"\n                << \" padding_y='\"<<item.padding_y_<<\"'\"\n                << \" padding_x='\"<<item.padding_x_<<\"'\"\n                << \"/>\\n\";\n        }\n    private:\n\n        tt::pooling ap;\n        resizable_tensor params;\n\n        int padding_y_;\n        int padding_x_;\n    };\n\n    template <\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using avg_pool = add_layer<avg_pool_<nr,nc,stride_y,stride_x>, SUBNET>;\n\n    template <\n        typename SUBNET\n        >\n    using avg_pool_everything = add_layer<avg_pool_<0,0,1,1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    const double DEFAULT_LAYER_NORM_EPS = 1e-5;\n\n    class layer_norm_\n    {\n    public:\n        explicit layer_norm_(\n            double eps_ = DEFAULT_LAYER_NORM_EPS\n        ) :\n            learning_rate_multiplier(1),\n            weight_decay_multiplier(0),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(1),\n            eps(eps_)\n        {\n        }\n\n        double get_eps() const { return eps; }\n\n        double get_learning_rate_multiplier () const  { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier () const   { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val)  { weight_decay_multiplier  = val; }\n\n        double get_bias_learning_rate_multiplier () const  { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier () const   { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val)  { bias_weight_decay_multiplier  = val; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            gamma = alias_tensor(1, sub.get_output().k());\n            beta = gamma;\n\n            params.set_size(gamma.size()+beta.size());\n\n            gamma(params,0) = 1;\n            beta(params,gamma.size()) = 0;\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto g = gamma(params,0);\n            auto b = beta(params,gamma.size());\n            tt::layer_normalize(eps, output, means, invstds, sub.get_output(), g, b);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            auto g = gamma(params, 0);\n            auto g_grad = gamma(params_grad, 0);\n            auto b_grad = beta(params_grad, gamma.size());\n            tt::layer_normalize_gradient(eps, gradient_input, means, invstds, sub.get_output(), g, sub.get_gradient_input(), g_grad, b_grad, dmeans, dvars);\n        }\n\n        const tensor& get_layer_params() const { return params; };\n        tensor& get_layer_params() { return params; };\n\n        friend void serialize(const layer_norm_& item, std::ostream& out)\n        {\n            serialize(\"layer_norm_\", out);\n            serialize(item.params, out);\n            serialize(item.gamma, out);\n            serialize(item.beta, out);\n            serialize(item.means, out);\n            serialize(item.invstds, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.eps, out);\n        }\n\n        friend void deserialize(layer_norm_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"layer_norm_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::layer_norm_.\");\n            deserialize(item.params, in);\n            deserialize(item.gamma, in);\n            deserialize(item.beta, in);\n            deserialize(item.means, in);\n            deserialize(item.invstds, in);\n            deserialize(item.learning_rate_multiplier, in);\n            deserialize(item.weight_decay_multiplier, in);\n            deserialize(item.bias_learning_rate_multiplier, in);\n            deserialize(item.bias_weight_decay_multiplier, in);\n            deserialize(item.eps, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const layer_norm_& item)\n        {\n            out << \"layer_norm\";\n            out << \" eps=\"<<item.eps;\n            out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n            out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n            out << \" bias_learning_rate_mult=\"<<item.bias_learning_rate_multiplier;\n            out << \" bias_weight_decay_mult=\"<<item.bias_weight_decay_multiplier;\n            return out;\n        }\n\n        friend void to_xml(const layer_norm_& item, std::ostream& out)\n        {\n            out << \"<layer_norm\";\n            out << \" eps='\"<<item.eps<<\"'\";\n            out << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\";\n            out << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\";\n            out << \" bias_learning_rate_mult='\"<<item.bias_learning_rate_multiplier<<\"'\";\n            out << \" bias_weight_decay_mult='\"<<item.bias_weight_decay_multiplier<<\"'\";\n            out << \">\\n\";\n            out << mat(item.params);\n            out << \"</layer_norm>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        alias_tensor gamma, beta;\n        resizable_tensor means, invstds;\n        resizable_tensor dmeans, dvars;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        double eps;\n    };\n\n    template <typename SUBNET>\n    using layer_norm = add_layer<layer_norm_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n    \n    const double DEFAULT_RMS_NORM_EPS = 1e-5;\n\n    class rms_norm_\n    {\n    public:\n        explicit rms_norm_(\n            double eps_ = DEFAULT_RMS_NORM_EPS\n        ) :\n            learning_rate_multiplier(1),\n            weight_decay_multiplier(0),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(1),\n            eps(eps_)\n        {\n        }\n\n        double get_eps() const { return eps; }\n\n        double get_learning_rate_multiplier() const { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier() const { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val) { weight_decay_multiplier = val; }\n\n        double get_bias_learning_rate_multiplier() const { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier() const { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val) { bias_weight_decay_multiplier = val; }\n\n        inline dpoint map_input_to_output(const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input(const dpoint& p) const { return p; }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& sub)\n        {\n            gamma = alias_tensor(1, sub.get_output().k());\n            params.set_size(gamma.size());\n            gamma(params, 0) = 1;\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto g = gamma(params, 0);\n            tt::rms_normalize(eps, output, scale, sub.get_output(), g);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            auto g = gamma(params, 0);\n            auto g_grad = gamma(params_grad, 0);\n            tt::rms_normalize_gradient(gradient_input, scale, sub.get_output(), g, sub.get_gradient_input(), g_grad, dscale);\n        }\n\n        const tensor& get_layer_params() const { return params; };\n        tensor& get_layer_params() { return params; };\n\n        friend void serialize(const rms_norm_& item, std::ostream& out)\n        {\n            serialize(\"rms_norm_\", out);\n            serialize(item.params, out);\n            serialize(item.gamma, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.eps, out);\n        }\n\n        friend void deserialize(rms_norm_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"rms_norm_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::rms_norm_.\");\n            deserialize(item.params, in);\n            deserialize(item.gamma, in);\n            deserialize(item.learning_rate_multiplier, in);\n            deserialize(item.weight_decay_multiplier, in);\n            deserialize(item.bias_learning_rate_multiplier, in);\n            deserialize(item.bias_weight_decay_multiplier, in);\n            deserialize(item.eps, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const rms_norm_& item)\n        {\n            out << \"rms_norm\";\n            out << \" (eps=\" << item.eps << \")\";\n            out << \" learning_rate_mult=\" << item.learning_rate_multiplier;\n            out << \" weight_decay_mult=\" << item.weight_decay_multiplier;\n            out << \" bias_learning_rate_mult=\" << item.bias_learning_rate_multiplier;\n            out << \" bias_weight_decay_mult=\" << item.bias_weight_decay_multiplier;\n            return out;\n        }\n\n        friend void to_xml(const rms_norm_& item, std::ostream& out)\n        {\n            out << \"<rms_norm\";\n            out << \" eps='\" << item.eps << \"'\";\n            out << \" learning_rate_mult='\" << item.learning_rate_multiplier << \"'\";\n            out << \" weight_decay_mult='\" << item.weight_decay_multiplier << \"'\";\n            out << \" bias_learning_rate_mult='\" << item.bias_learning_rate_multiplier << \"'\";\n            out << \" bias_weight_decay_mult='\" << item.bias_weight_decay_multiplier << \"'\";\n            out << \">\\n\";\n            out << mat(item.params);\n            out << \"</rms_norm>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        alias_tensor gamma;\n        resizable_tensor scale;\n        resizable_tensor dscale;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        double eps;\n    };\n\n    template <typename SUBNET>\n    using rms_norm = add_layer<rms_norm_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n    enum layer_mode\n    {\n        CONV_MODE = 0,\n        FC_MODE = 1\n    };\n\n    const double DEFAULT_BATCH_NORM_EPS = 0.0001;\n\n    template <\n        layer_mode mode\n        >\n    class bn_\n    {\n    public:\n        explicit bn_(\n            unsigned long window_size,\n            double eps_ = DEFAULT_BATCH_NORM_EPS\n        ) : \n            num_updates(0), \n            running_stats_window_size(window_size),\n            learning_rate_multiplier(1),\n            weight_decay_multiplier(0),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(1),\n            eps(eps_)\n        {\n            DLIB_CASSERT(window_size > 0, \"The batch normalization running stats window size can't be 0.\");\n        }\n\n        bn_() : bn_(100) {}\n\n        layer_mode get_mode() const { return mode; }\n        unsigned long get_running_stats_window_size () const { return running_stats_window_size; }\n        void set_running_stats_window_size (unsigned long new_window_size ) \n        { \n            DLIB_CASSERT(new_window_size > 0, \"The batch normalization running stats window size can't be 0.\");\n            running_stats_window_size = new_window_size; \n        }\n        double get_eps() const { return eps; }\n\n        double get_learning_rate_multiplier () const  { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier () const   { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val)  { weight_decay_multiplier  = val; }\n\n        double get_bias_learning_rate_multiplier () const  { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier () const   { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val)  { bias_weight_decay_multiplier  = val; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            if (mode == FC_MODE)\n            {\n                gamma = alias_tensor(1,\n                                sub.get_output().k(),\n                                sub.get_output().nr(),\n                                sub.get_output().nc());\n            }\n            else\n            {\n                gamma = alias_tensor(1, sub.get_output().k());\n            }\n            beta = gamma;\n\n            params.set_size(gamma.size()+beta.size());\n\n            gamma(params,0) = 1;\n            beta(params,gamma.size()) = 0;\n\n            running_means.copy_size(gamma(params,0));\n            running_variances.copy_size(gamma(params,0));\n            running_means = 0;\n            running_variances = 1;\n            num_updates = 0;\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto g = gamma(params,0);\n            auto b = beta(params,gamma.size());\n            if (sub.get_output().num_samples() > 1)\n            {\n                const double decay = 1.0 - num_updates/(num_updates+1.0);\n                ++num_updates;\n                if (num_updates > running_stats_window_size)\n                    num_updates = running_stats_window_size;\n\n                if (mode == FC_MODE)\n                    tt::batch_normalize(eps, output, means, invstds, decay, running_means, running_variances, sub.get_output(), g, b);\n                else \n                    tt::batch_normalize_conv(eps, output, means, invstds, decay, running_means, running_variances, sub.get_output(), g, b);\n            }\n            else // we are running in testing mode so we just linearly scale the input tensor.\n            {\n                if (mode == FC_MODE)\n                    tt::batch_normalize_inference(eps, output, sub.get_output(), g, b, running_means, running_variances);\n                else\n                    tt::batch_normalize_conv_inference(eps, output, sub.get_output(), g, b, running_means, running_variances);\n            }\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            auto g = gamma(params,0);\n            auto g_grad = gamma(params_grad, 0);\n            auto b_grad = beta(params_grad, gamma.size());\n            if (mode == FC_MODE)\n                tt::batch_normalize_gradient(eps, gradient_input, means, invstds, sub.get_output(), g, sub.get_gradient_input(), g_grad, b_grad );\n            else\n                tt::batch_normalize_conv_gradient(eps, gradient_input, means, invstds, sub.get_output(), g, sub.get_gradient_input(), g_grad, b_grad );\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const bn_& item, std::ostream& out)\n        {\n            if (mode == CONV_MODE)\n                serialize(\"bn_con2\", out);\n            else // if FC_MODE\n                serialize(\"bn_fc2\", out);\n            serialize(item.params, out);\n            serialize(item.gamma, out);\n            serialize(item.beta, out);\n            serialize(item.means, out);\n            serialize(item.invstds, out);\n            serialize(item.running_means, out);\n            serialize(item.running_variances, out);\n            serialize(item.num_updates, out);\n            serialize(item.running_stats_window_size, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.eps, out);\n        }\n\n        friend void deserialize(bn_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (mode == CONV_MODE) \n            {\n                if (version != \"bn_con2\")\n                    throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::bn_.\");\n            }\n            else // must be in FC_MODE\n            {\n                if (version != \"bn_fc2\")\n                    throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::bn_.\");\n            }\n\n            deserialize(item.params, in);\n            deserialize(item.gamma, in);\n            deserialize(item.beta, in);\n            deserialize(item.means, in);\n            deserialize(item.invstds, in);\n            deserialize(item.running_means, in);\n            deserialize(item.running_variances, in);\n            deserialize(item.num_updates, in);\n            deserialize(item.running_stats_window_size, in);\n            deserialize(item.learning_rate_multiplier, in);\n            deserialize(item.weight_decay_multiplier, in);\n            deserialize(item.bias_learning_rate_multiplier, in);\n            deserialize(item.bias_weight_decay_multiplier, in);\n            deserialize(item.eps, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const bn_& item)\n        {\n            if (mode == CONV_MODE)\n                out << \"bn_con  \";\n            else\n                out << \"bn_fc   \";\n            out << \" eps=\"<<item.eps;\n            out << \" running_stats_window_size=\"<<item.running_stats_window_size;\n            out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n            out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n            out << \" bias_learning_rate_mult=\"<<item.bias_learning_rate_multiplier;\n            out << \" bias_weight_decay_mult=\"<<item.bias_weight_decay_multiplier;\n            return out;\n        }\n\n        friend void to_xml(const bn_& item, std::ostream& out)\n        {\n            if (mode==CONV_MODE)\n                out << \"<bn_con\";\n            else\n                out << \"<bn_fc\";\n\n            out << \" eps='\"<<item.eps<<\"'\";\n            out << \" running_stats_window_size='\"<<item.running_stats_window_size<<\"'\";\n            out << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\";\n            out << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\";\n            out << \" bias_learning_rate_mult='\"<<item.bias_learning_rate_multiplier<<\"'\";\n            out << \" bias_weight_decay_mult='\"<<item.bias_weight_decay_multiplier<<\"'\";\n            out << \">\\n\";\n\n            out << mat(item.params);\n\n            if (mode==CONV_MODE)\n                out << \"</bn_con>\\n\";\n            else\n                out << \"</bn_fc>\\n\";\n        }\n\n    private:\n\n        friend class affine_;\n\n        resizable_tensor params;\n        alias_tensor gamma, beta;\n        resizable_tensor means, running_means;\n        resizable_tensor invstds, running_variances;\n        unsigned long num_updates;\n        unsigned long running_stats_window_size;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        double eps;\n    };\n\n    template <typename SUBNET>\n    using bn_con = add_layer<bn_<CONV_MODE>, SUBNET>;\n    template <typename SUBNET>\n    using bn_fc = add_layer<bn_<FC_MODE>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    enum fc_bias_mode\n    {\n        FC_HAS_BIAS = 0,\n        FC_NO_BIAS = 1\n    };\n\n    struct num_fc_outputs\n    {\n        num_fc_outputs(unsigned long n) : num_outputs(n) {}\n        unsigned long num_outputs;\n    };\n\n    template <\n        unsigned long num_outputs_,\n        fc_bias_mode bias_mode\n        >\n    class fc_\n    {\n        static_assert(num_outputs_ > 0, \"The number of outputs from a fc_ layer must be > 0\");\n\n    public:\n        fc_(num_fc_outputs o) : num_outputs(o.num_outputs), num_inputs(0),\n            learning_rate_multiplier(1),\n            weight_decay_multiplier(1),\n            bias_learning_rate_multiplier(1),\n            bias_weight_decay_multiplier(0),\n            use_bias(true)\n        {}\n\n        fc_() : fc_(num_fc_outputs(num_outputs_)) {}\n\n        double get_learning_rate_multiplier () const  { return learning_rate_multiplier; }\n        double get_weight_decay_multiplier () const   { return weight_decay_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        void set_weight_decay_multiplier(double val)  { weight_decay_multiplier  = val; }\n\n        double get_bias_learning_rate_multiplier () const  { return bias_learning_rate_multiplier; }\n        double get_bias_weight_decay_multiplier () const   { return bias_weight_decay_multiplier; }\n        void set_bias_learning_rate_multiplier(double val) { bias_learning_rate_multiplier = val; }\n        void set_bias_weight_decay_multiplier(double val)  { bias_weight_decay_multiplier  = val; }\n        void disable_bias() { use_bias = false; }\n        bool bias_is_disabled() const { return !use_bias; }\n\n        unsigned long get_num_outputs (\n        ) const { return num_outputs; }\n\n        void set_num_outputs(long num) \n        {\n            DLIB_CASSERT(num > 0);\n            if (num != (long)num_outputs)\n            {\n                DLIB_CASSERT(get_layer_params().size() == 0, \n                    \"You can't change the number of filters in fc_ if the parameter tensor has already been allocated.\");\n                num_outputs = num;\n            }\n        }\n\n        fc_bias_mode get_bias_mode (\n        ) const { return bias_mode; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            num_inputs = sub.get_output().nr()*sub.get_output().nc()*sub.get_output().k();\n            if (bias_mode == FC_HAS_BIAS && use_bias)\n                params.set_size(num_inputs+1, num_outputs);\n            else\n                params.set_size(num_inputs, num_outputs);\n\n            dlib::rand rnd(std::rand());\n            randomize_parameters(params, num_inputs+num_outputs, rnd);\n\n            weights = alias_tensor(num_inputs, num_outputs);\n\n            if (bias_mode == FC_HAS_BIAS && use_bias)\n            {\n                biases = alias_tensor(1,num_outputs);\n                // set the initial bias values to zero\n                biases(params,weights.size()) = 0;\n            }\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            DLIB_CASSERT((long)num_inputs == sub.get_output().nr()*sub.get_output().nc()*sub.get_output().k(),\n                \"The size of the input tensor to this fc layer doesn't match the size the fc layer was trained with.\");\n            output.set_size(sub.get_output().num_samples(), num_outputs);\n\n            auto w = weights(params, 0);\n            tt::gemm(0,output, 1,sub.get_output(),false, w,false);\n            if (bias_mode == FC_HAS_BIAS && use_bias)\n            {\n                auto b = biases(params, weights.size());\n                tt::add(1,output,1,b);\n            }\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            // no point computing the parameter gradients if they won't be used.\n            if (learning_rate_multiplier != 0)\n            {\n                // compute the gradient of the weight parameters.  \n                auto pw = weights(params_grad, 0);\n                tt::gemm(0,pw, 1,sub.get_output(),true, gradient_input,false);\n\n                if (bias_mode == FC_HAS_BIAS && use_bias)\n                {\n                    // compute the gradient of the bias parameters.  \n                    auto pb = biases(params_grad, weights.size());\n                    tt::assign_bias_gradient(pb, gradient_input);\n                }\n            }\n\n            // compute the gradient for the data\n            auto w = weights(params, 0);\n            tt::gemm(1,sub.get_gradient_input(), 1,gradient_input,false, w,true);\n        }\n\n        alias_tensor_instance get_weights()\n        {\n            return weights(params, 0);\n        }\n\n        alias_tensor_const_instance get_weights() const\n        {\n            return weights(params, 0);\n        }\n\n        alias_tensor_instance get_biases()\n        {\n            static_assert(bias_mode == FC_HAS_BIAS, \"This fc_ layer doesn't have a bias vector \"\n                \"to be retrieved, as per template parameter 'bias_mode'.\");\n            return biases(params, weights.size());\n        }\n\n        alias_tensor_const_instance get_biases() const\n        {\n            static_assert(bias_mode == FC_HAS_BIAS, \"This fc_ layer doesn't have a bias vector \"\n                \"to be retrieved, as per template parameter 'bias_mode'.\");\n            return biases(params, weights.size());\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const fc_& item, std::ostream& out)\n        {\n            serialize(\"fc_3\", out);\n            serialize(item.num_outputs, out);\n            serialize(item.num_inputs, out);\n            serialize(item.params, out);\n            serialize(item.weights, out);\n            serialize(item.biases, out);\n            serialize((int)bias_mode, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.weight_decay_multiplier, out);\n            serialize(item.bias_learning_rate_multiplier, out);\n            serialize(item.bias_weight_decay_multiplier, out);\n            serialize(item.use_bias, out);\n        }\n\n        friend void deserialize(fc_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"fc_2\" || version == \"fc_3\")\n            {\n                deserialize(item.num_outputs, in);\n                deserialize(item.num_inputs, in);\n                deserialize(item.params, in);\n                deserialize(item.weights, in);\n                deserialize(item.biases, in);\n                int bmode = 0;\n                deserialize(bmode, in);\n                if (bias_mode != (fc_bias_mode)bmode) throw serialization_error(\"Wrong fc_bias_mode found while deserializing dlib::fc_\");\n                deserialize(item.learning_rate_multiplier, in);\n                deserialize(item.weight_decay_multiplier, in);\n                deserialize(item.bias_learning_rate_multiplier, in);\n                deserialize(item.bias_weight_decay_multiplier, in);\n                if (version == \"fc_3\")\n                {\n                    deserialize(item.use_bias, in);\n                }\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::fc_.\");\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const fc_& item)\n        {\n            if (bias_mode == FC_HAS_BIAS)\n            {\n                out << \"fc\\t (\"\n                    << \"num_outputs=\"<<item.num_outputs\n                    << \")\";\n                out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n                out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n                if (item.use_bias)\n                {\n                    out << \" bias_learning_rate_mult=\"<<item.bias_learning_rate_multiplier;\n                    out << \" bias_weight_decay_mult=\"<<item.bias_weight_decay_multiplier;\n                }\n                else\n                {\n                    out << \" use_bias=false\";\n                }\n            }\n            else\n            {\n                out << \"fc_no_bias (\"\n                    << \"num_outputs=\"<<item.num_outputs\n                    << \")\";\n                out << \" learning_rate_mult=\"<<item.learning_rate_multiplier;\n                out << \" weight_decay_mult=\"<<item.weight_decay_multiplier;\n            }\n            return out;\n        }\n\n        friend void to_xml(const fc_& item, std::ostream& out)\n        {\n            if (bias_mode==FC_HAS_BIAS)\n            {\n                out << \"<fc\"\n                    << \" num_outputs='\"<<item.num_outputs<<\"'\"\n                    << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\"\n                    << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\"\n                    << \" bias_learning_rate_mult='\"<<item.bias_learning_rate_multiplier<<\"'\"\n                    << \" bias_weight_decay_mult='\"<<item.bias_weight_decay_multiplier<<\"'\"\n                    << \" use_bias='\"<<(item.use_bias?\"true\":\"false\")<<\"'>\\n\";\n                out << mat(item.params);\n                out << \"</fc>\\n\";\n            }\n            else\n            {\n                out << \"<fc_no_bias\"\n                    << \" num_outputs='\"<<item.num_outputs<<\"'\"\n                    << \" learning_rate_mult='\"<<item.learning_rate_multiplier<<\"'\"\n                    << \" weight_decay_mult='\"<<item.weight_decay_multiplier<<\"'\";\n                out << \">\\n\";\n                out << mat(item.params);\n                out << \"</fc_no_bias>\\n\";\n            }\n        }\n\n    private:\n\n        unsigned long num_outputs;\n        unsigned long num_inputs;\n        resizable_tensor params;\n        alias_tensor weights, biases;\n        double learning_rate_multiplier;\n        double weight_decay_multiplier;\n        double bias_learning_rate_multiplier;\n        double bias_weight_decay_multiplier;\n        bool use_bias;\n    };\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n        >\n    using fc = add_layer<fc_<num_outputs,FC_HAS_BIAS>, SUBNET>;\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n        >\n    using fc_no_bias = add_layer<fc_<num_outputs,FC_NO_BIAS>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n    \n    enum linear_bias_mode { LINEAR_HAS_BIAS = 0, LINEAR_NO_BIAS = 1 };\n\n    template <\n        unsigned long num_outputs_,\n        linear_bias_mode bias_mode_ = LINEAR_HAS_BIAS\n    >\n    class linear_\n    {\n        static_assert(num_outputs_ > 0, \"The number of outputs from a linear_ layer must be > 0\");\n\n    public:\n        explicit linear_() :\n            num_outputs(num_outputs_),\n            num_inputs(0),                        \n            learning_rate_multiplier(1),\n            bias_mode(bias_mode_) {\n        }\n\n        linear_(const linear_& other) :\n            num_outputs(other.num_outputs),\n            num_inputs(other.num_inputs),\n            learning_rate_multiplier(other.learning_rate_multiplier),\n            bias_mode(other.bias_mode),\n            params(other.params),\n            weights(other.weights),\n            biases(other.biases) {\n        }\n\n        linear_& operator=(const linear_& other) {\n            if (this != &other) {\n                num_outputs = other.num_outputs;\n                num_inputs = other.num_inputs;\n                learning_rate_multiplier = other.learning_rate_multiplier;\n                bias_mode = other.bias_mode;\n                params = other.params;\n                weights = other.weights;\n                biases = other.biases;\n            }\n            return *this;\n        }\n\n        double get_learning_rate_multiplier() const { return learning_rate_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n        \n        unsigned long get_num_outputs() const { return num_outputs; }\n        void set_num_outputs(long num)\n        {\n            DLIB_CASSERT(num > 0, \"The number of outputs must be > 0, but num == \" << num);\n            if (num != (long)num_outputs)\n            {\n                DLIB_CASSERT(get_layer_params().size() == 0,\n                    \"You can't change the number of filters in linear_ if the parameter tensor has already been allocated.\");\n                num_outputs = num;\n            }\n        }\n        unsigned long get_num_inputs() const { return num_inputs; }\n        linear_bias_mode get_bias_mode() const { return bias_mode; }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& sub)\n        {\n            num_inputs = sub.get_output().nc();\n            if (bias_mode == LINEAR_HAS_BIAS)\n                params.set_size(num_inputs + 1, num_outputs);\n            else\n                params.set_size(num_inputs, num_outputs);\n\n            dlib::rand rnd(std::rand());\n            randomize_parameters(params, num_inputs + num_outputs, rnd);\n            weights = alias_tensor(num_inputs, num_outputs);\n\n            if (bias_mode == LINEAR_HAS_BIAS) {\n                biases = alias_tensor(1, num_outputs);\n                biases(params, weights.size()) = 0;\n            }\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            const auto& prev_output = sub.get_output();\n            DLIB_CASSERT((long)num_inputs == prev_output.nc(),\n                \"The size of the input tensor to this linear layer doesn't match the size the linear layer was trained with.\");            \n            output.set_size(prev_output.num_samples(), prev_output.k(), prev_output.nr(), num_outputs);\n\n            auto o = alias_tensor(output.num_samples() * output.k() * output.nr(), num_outputs)(output, 0);\n            auto so = alias_tensor(prev_output.num_samples() * prev_output.k() * prev_output.nr(), num_inputs)(prev_output, 0);\n\n            auto w = weights(params, 0);\n            tt::gemm(0, (tensor&)o, 1, so, false, w, false);\n\n            if (bias_mode == LINEAR_HAS_BIAS)\n            {\n                auto b = biases(params, weights.size());\n                tt::add(1, (tensor&)o, 1, b);\n            }\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad)\n        {\n            auto gi = alias_tensor(gradient_input.num_samples() * gradient_input.k() * gradient_input.nr(), num_outputs)(gradient_input, 0);\n            if (learning_rate_multiplier != 0)\n            {\n                const auto& prev_output = sub.get_output();\n                auto pw = weights(params_grad, 0);\n                auto so = alias_tensor(prev_output.num_samples() * prev_output.k() * prev_output.nr(), num_inputs)(prev_output, 0);\n                tt::gemm(0, pw, learning_rate_multiplier, so, true, gi, false);\n\n                if (bias_mode == LINEAR_HAS_BIAS)\n                {\n                    auto pb = biases(params_grad, weights.size());\n                    tt::assign_bias_gradient(pb, gi);\n                }\n            }\n            \n            //prev_gradient is not const, so that sgi isn't const\n            //since sgi is used as a destination for tt::gemm\n            auto& prev_gradient = sub.get_gradient_input();\n            alias_tensor_instance sgi = alias_tensor(prev_gradient.num_samples() * prev_gradient.k() * prev_gradient.nr(), num_inputs)(prev_gradient, 0);\n            auto w = weights(params, 0);\n            tt::gemm(1, sgi, 1, gi, false, w, true);\n        }\n\n        alias_tensor_instance get_weights() { return weights(params, 0); }\n        alias_tensor_const_instance get_weights() const { return weights(params, 0); }\n        alias_tensor_instance get_biases()\n        {\n            static_assert(bias_mode == LINEAR_HAS_BIAS, \"This linear_ layer doesn't have a bias vector \"\n                \"to be retrieved, as per template parameter 'bias_mode'.\");\n            return biases(params, weights.size());\n        }\n        alias_tensor_const_instance get_biases() const\n        {\n            static_assert(bias_mode == LINEAR_HAS_BIAS, \"This linear_ layer doesn't have a bias vector \"\n                \"to be retrieved, as per template parameter 'bias_mode'.\");\n            return biases(params, weights.size());\n        }\n\n        inline dpoint map_input_to_output(const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input(const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const linear_& item, std::ostream& out)\n        {\n            serialize(\"linear_\", out);\n            serialize(item.num_outputs, out);\n            serialize(item.num_inputs, out);\n            serialize(item.params, out);\n            serialize(item.weights, out);\n            serialize(item.biases, out);\n            serialize((int)item.bias_mode, out);\n            serialize(item.learning_rate_multiplier, out);\n        }\n\n        friend void deserialize(linear_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"linear_\")\n            {\n                deserialize(item.num_outputs, in);\n                deserialize(item.num_inputs, in);\n                deserialize(item.params, in);\n                deserialize(item.weights, in);\n                deserialize(item.biases, in);\n                int bmode;\n                deserialize(bmode, in);\n                item.bias_mode = static_cast<linear_bias_mode>(bmode);\n                if (bias_mode_ != item.bias_mode) throw serialization_error(\"Wrong bias_mode found while deserializing dlib::linear_\");\n                deserialize(item.learning_rate_multiplier, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::linear_.\");\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const linear_& item)\n        {\n            out << \"linear\\t (num_outputs=\" << item.num_outputs;\n            if (item.bias_mode == LINEAR_HAS_BIAS)\n                out << \", bias=true\";\n            else\n                out << \", bias=false\";\n            out << \")\";\n            out << \" learning_rate_mult=\" << item.learning_rate_multiplier;\n            return out;\n        }\n\n        friend void to_xml(const linear_& item, std::ostream& out)\n        {\n            out << \"<linear\"\n                << \" num_outputs='\" << item.num_outputs << \"'\"\n                << \" bias='\" << ((item.bias_mode == LINEAR_HAS_BIAS) ? \"true\" : \"false\") << \"'\"\n                << \" learning_rate_mult='\" << item.learning_rate_multiplier << \"'>\\n\";\n            out << mat(item.params);\n            out << \"</linear>\\n\";\n        }\n\n    private:\n        unsigned long num_outputs;\n        unsigned long num_inputs;        \n        double learning_rate_multiplier;\n        linear_bias_mode bias_mode;\n        resizable_tensor params;\n        alias_tensor weights, biases;\n    };\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n    >\n    using linear = add_layer<linear_<num_outputs>, SUBNET>;\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n    >\n    using linear_no_bias = add_layer<linear_<num_outputs, LINEAR_NO_BIAS>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class dropout_\n    {\n    public:\n        explicit dropout_(\n            float drop_rate_ = 0.5\n        ) :\n            drop_rate(drop_rate_),\n            rnd(std::rand())\n        {\n            DLIB_CASSERT(0 <= drop_rate && drop_rate <= 1);\n        }\n\n        // We have to add a copy constructor and assignment operator because the rnd object\n        // is non-copyable.\n        dropout_(\n            const dropout_& item\n        ) : drop_rate(item.drop_rate), mask(item.mask), rnd(std::rand())\n        {}\n\n        dropout_& operator= (\n            const dropout_& item\n        )\n        {\n            if (this == &item)\n                return *this;\n\n            drop_rate = item.drop_rate;\n            mask = item.mask;\n            return *this;\n        }\n\n        float get_drop_rate (\n        ) const { return drop_rate; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            // create a random mask and use it to filter the data\n            mask.copy_size(input);\n            rnd.fill_uniform(mask);\n            tt::threshold(mask, drop_rate);\n            tt::multiply(false, output, input, mask);\n        } \n\n        void backward_inplace(\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& /*params_grad*/\n        )\n        {\n            if (is_same_object(gradient_input, data_grad))\n                tt::multiply(false, data_grad, mask, gradient_input);\n            else\n                tt::multiply(true, data_grad, mask, gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const dropout_& item, std::ostream& out)\n        {\n            serialize(\"dropout_\", out);\n            serialize(item.drop_rate, out);\n            serialize(item.mask, out);\n        }\n\n        friend void deserialize(dropout_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"dropout_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::dropout_.\");\n            deserialize(item.drop_rate, in);\n            deserialize(item.mask, in);\n        }\n\n        void clean(\n        ) \n        {\n            mask.clear();\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const dropout_& item)\n        {\n            out << \"dropout\\t (\"\n                << \"drop_rate=\"<<item.drop_rate\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const dropout_& item, std::ostream& out)\n        {\n            out << \"<dropout\"\n                << \" drop_rate='\"<<item.drop_rate<<\"'\";\n            out << \"/>\\n\";\n        }\n\n    private:\n        float drop_rate;\n        resizable_tensor mask;\n\n        tt::tensor_rand rnd;\n        resizable_tensor params; // unused\n    };\n\n\n    template <typename SUBNET>\n    using dropout = add_layer<dropout_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <int DROP_RATE_PERCENT>\n    class dropout_rate_ : public dropout_\n    {\n    public:\n        explicit dropout_rate_() : dropout_(static_cast<float>(DROP_RATE_PERCENT) / 100.0f)\n        {\n            static_assert(DROP_RATE_PERCENT >= 0 && DROP_RATE_PERCENT <= 100,\n                \"DROP_RATE_PERCENT must be between 0 and 100, inclusive.\");\n        }\n    };\n    \n    template <int DROP_RATE, typename SUBNET>\n    using dropout_rate = add_layer<dropout_rate_<DROP_RATE>, SUBNET>;\n    template <typename SUBNET>\n    using dropout_10 = add_layer<dropout_rate_<10>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class multiply_\n    {\n    public:\n        explicit multiply_(\n            float val_ = 0.5\n        ) :\n            val(val_)\n        {\n        }\n\n        multiply_ (\n            const dropout_& item\n        ) : val(1-item.get_drop_rate()) {}\n\n        float get_multiply_value (\n        ) const { return val; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::affine_transform(output, input, val);\n        } \n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        void backward_inplace(\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& /*params_grad*/\n        )\n        {\n            if (is_same_object(gradient_input, data_grad))\n                tt::affine_transform(data_grad, gradient_input, val);\n            else\n                tt::affine_transform(data_grad, data_grad, gradient_input, 1, val);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const multiply_& item, std::ostream& out)\n        {\n            serialize(\"multiply_\", out);\n            serialize(item.val, out);\n        }\n\n        friend void deserialize(multiply_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"dropout_\")\n            {\n                // Since we can build a multiply_ from a dropout_ we check if that's what\n                // is in the stream and if so then just convert it right here.\n                unserialize sin(version, in);\n                dropout_ temp;\n                deserialize(temp, sin);\n                item = temp;\n                return;\n            }\n\n            if (version != \"multiply_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::multiply_.\");\n            deserialize(item.val, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const multiply_& item)\n        {\n            out << \"multiply (\"\n                << \"val=\"<<item.val\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const multiply_& item, std::ostream& out)\n        {\n            out << \"<multiply\"\n                << \" val='\"<<item.val<<\"'\";\n            out << \"/>\\n\";\n        }\n    private:\n        float val;\n        resizable_tensor params; // unused\n    };\n\n    template <typename SUBNET>\n    using multiply = add_layer<multiply_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class affine_\n    {\n    public:\n        affine_(\n        ) : mode(FC_MODE)\n        {\n        }\n\n        affine_(\n            layer_mode mode_\n        ) : mode(mode_)\n        {\n        }\n\n        template <\n            layer_mode bnmode\n            >\n        affine_(\n            const bn_<bnmode>& item\n        )\n        {\n            gamma = item.gamma;\n            beta = item.beta;\n            mode = bnmode;\n\n            params.copy_size(item.params);\n\n            auto g = gamma(params,0);\n            auto b = beta(params,gamma.size());\n\n            resizable_tensor temp(item.params);\n            auto sg = gamma(temp,0);\n            auto sb = beta(temp,gamma.size());\n\n            g = pointwise_divide(mat(sg), sqrt(mat(item.running_variances)+item.get_eps()));\n            b = mat(sb) - pointwise_multiply(mat(g), mat(item.running_means));\n        }\n\n        layer_mode get_mode() const { return mode; }\n\n        void disable()\n        {\n            params.clear();\n            disabled = true;\n        }\n\n        bool is_disabled() const { return disabled; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            if (disabled)\n                return;\n\n            if (mode == FC_MODE)\n            {\n                gamma = alias_tensor(1,\n                                sub.get_output().k(),\n                                sub.get_output().nr(),\n                                sub.get_output().nc());\n            }\n            else\n            {\n                gamma = alias_tensor(1, sub.get_output().k());\n            }\n            beta = gamma;\n\n            params.set_size(gamma.size()+beta.size());\n\n            gamma(params,0) = 1;\n            beta(params,gamma.size()) = 0;\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            if (disabled)\n                return;\n\n            auto g = gamma(params,0);\n            auto b = beta(params,gamma.size());\n            if (mode == FC_MODE)\n                tt::affine_transform(output, input, g, b);\n            else\n                tt::affine_transform_conv(output, input, g, b);\n        } \n\n        void backward_inplace(\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& /*params_grad*/\n        )\n        {\n            if (disabled)\n                return;\n\n            auto g = gamma(params,0);\n            auto b = beta(params,gamma.size());\n\n            // We are computing the gradient of dot(gradient_input, computed_output*g + b)\n            if (mode == FC_MODE)\n            {\n                if (is_same_object(gradient_input, data_grad))\n                    tt::multiply(false, data_grad, gradient_input, g);\n                else\n                    tt::multiply(true, data_grad, gradient_input, g);\n            }\n            else\n            {\n                if (is_same_object(gradient_input, data_grad))\n                    tt::multiply_conv(false, data_grad, gradient_input, g);\n                else\n                    tt::multiply_conv(true, data_grad, gradient_input, g);\n            }\n        }\n\n        alias_tensor_instance get_gamma() { return gamma(params, 0); };\n        alias_tensor_const_instance get_gamma() const { return gamma(params, 0); };\n\n        alias_tensor_instance get_beta() { return beta(params, gamma.size()); };\n        alias_tensor_const_instance get_beta() const { return beta(params, gamma.size()); };\n\n        const tensor& get_layer_params() const { return empty_params; }\n        tensor& get_layer_params() { return empty_params; }\n\n        friend void serialize(const affine_& item, std::ostream& out)\n        {\n            serialize(\"affine_2\", out);\n            serialize(item.params, out);\n            serialize(item.gamma, out);\n            serialize(item.beta, out);\n            serialize((int)item.mode, out);\n            serialize(item.disabled, out);\n        }\n\n        friend void deserialize(affine_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"bn_con2\")\n            {\n                // Since we can build an affine_ from a bn_ we check if that's what is in\n                // the stream and if so then just convert it right here.\n                unserialize sin(version, in);\n                bn_<CONV_MODE> temp;\n                deserialize(temp, sin);\n                item = temp;\n                return;\n            }\n            else if (version == \"bn_fc2\")\n            {\n                // Since we can build an affine_ from a bn_ we check if that's what is in\n                // the stream and if so then just convert it right here.\n                unserialize sin(version, in);\n                bn_<FC_MODE> temp;\n                deserialize(temp, sin);\n                item = temp;\n                return;\n            }\n\n            if (version != \"affine_\" && version != \"affine_2\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::affine_.\");\n            deserialize(item.params, in);\n            deserialize(item.gamma, in);\n            deserialize(item.beta, in);\n            int mode;\n            deserialize(mode, in);\n            item.mode = (layer_mode)mode;\n            if (version == \"affine_2\")\n                deserialize(item.disabled, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const affine_& item)\n        {\n            out << \"affine\";\n            if (item.disabled)\n                out << \"\\t (disabled)\";\n            return out;\n        }\n\n        friend void to_xml(const affine_& item, std::ostream& out)\n        {\n            if (item.mode==CONV_MODE)\n                out << \"<affine_con\";\n            else\n                out << \"<affine_fc\";\n            if (item.disabled)\n                out << \" disabled='\"<< std::boolalpha << item.disabled << \"'\";\n            out << \">\\n\";\n            out << mat(item.params);\n\n            if (item.mode==CONV_MODE)\n                out << \"</affine_con>\\n\";\n            else\n                out << \"</affine_fc>\\n\";\n        }\n\n    private:\n        resizable_tensor params, empty_params; \n        alias_tensor gamma, beta;\n        layer_mode mode;\n        bool disabled = false;\n    };\n\n    template <typename SUBNET>\n    using affine = add_layer<affine_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class add_prev_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        add_prev_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto&& t1 = sub.get_output();\n            auto&& t2 = layer<tag>(sub).get_output();\n            output.set_size(std::max(t1.num_samples(),t2.num_samples()),\n                            std::max(t1.k(),t2.k()),\n                            std::max(t1.nr(),t2.nr()),\n                            std::max(t1.nc(),t2.nc()));\n            tt::add(output, t1, t2);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            // The gradient just flows backwards to the two layers that forward() added\n            // together.\n            tt::add(sub.get_gradient_input(), sub.get_gradient_input(), gradient_input);\n            tt::add(layer<tag>(sub).get_gradient_input(), layer<tag>(sub).get_gradient_input(), gradient_input);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        friend void serialize(const add_prev_& /*item*/, std::ostream& out)\n        {\n            serialize(\"add_prev_\", out);\n        }\n\n        friend void deserialize(add_prev_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"add_prev_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::add_prev_.\");\n        }\n        friend std::ostream& operator<<(std::ostream& out, const add_prev_& /*item*/)\n        {\n            out << \"add_prev\"<<id;\n            return out;\n        }\n\n        friend void to_xml(const add_prev_& /*item*/, std::ostream& out)\n        {\n            out << \"<add_prev tag='\"<<id<<\"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using add_prev = add_layer<add_prev_<tag>, SUBNET>;\n\n    template <typename SUBNET> using add_prev1  = add_prev<tag1, SUBNET>;\n    template <typename SUBNET> using add_prev2  = add_prev<tag2, SUBNET>;\n    template <typename SUBNET> using add_prev3  = add_prev<tag3, SUBNET>;\n    template <typename SUBNET> using add_prev4  = add_prev<tag4, SUBNET>;\n    template <typename SUBNET> using add_prev5  = add_prev<tag5, SUBNET>;\n    template <typename SUBNET> using add_prev6  = add_prev<tag6, SUBNET>;\n    template <typename SUBNET> using add_prev7  = add_prev<tag7, SUBNET>;\n    template <typename SUBNET> using add_prev8  = add_prev<tag8, SUBNET>;\n    template <typename SUBNET> using add_prev9  = add_prev<tag9, SUBNET>;\n    template <typename SUBNET> using add_prev10 = add_prev<tag10, SUBNET>;\n\n    using add_prev1_  = add_prev_<tag1>;\n    using add_prev2_  = add_prev_<tag2>;\n    using add_prev3_  = add_prev_<tag3>;\n    using add_prev4_  = add_prev_<tag4>;\n    using add_prev5_  = add_prev_<tag5>;\n    using add_prev6_  = add_prev_<tag6>;\n    using add_prev7_  = add_prev_<tag7>;\n    using add_prev8_  = add_prev_<tag8>;\n    using add_prev9_  = add_prev_<tag9>;\n    using add_prev10_ = add_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class mult_prev_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        mult_prev_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto&& t1 = sub.get_output();\n            auto&& t2 = layer<tag>(sub).get_output();\n            output.set_size(std::max(t1.num_samples(),t2.num_samples()),\n                            std::max(t1.k(),t2.k()),\n                            std::max(t1.nr(),t2.nr()),\n                            std::max(t1.nc(),t2.nc()));\n            tt::multiply_zero_padded(false, output, t1, t2);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto&& t1 = sub.get_output();\n            auto&& t2 = layer<tag>(sub).get_output();\n            // The gradient just flows backwards to the two layers that forward()\n            // multiplied together.\n            tt::multiply_zero_padded(true, sub.get_gradient_input(), t2, gradient_input);\n            tt::multiply_zero_padded(true, layer<tag>(sub).get_gradient_input(), t1, gradient_input);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        friend void serialize(const mult_prev_& /*item*/, std::ostream& out)\n        {\n            serialize(\"mult_prev_\", out);\n        }\n\n        friend void deserialize(mult_prev_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"mult_prev_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::mult_prev_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const mult_prev_& /*item*/)\n        {\n            out << \"mult_prev\"<<id;\n            return out;\n        }\n\n        friend void to_xml(const mult_prev_& /*item*/, std::ostream& out)\n        {\n            out << \"<mult_prev tag='\"<<id<<\"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using mult_prev = add_layer<mult_prev_<tag>, SUBNET>;\n\n    template <typename SUBNET> using mult_prev1  = mult_prev<tag1, SUBNET>;\n    template <typename SUBNET> using mult_prev2  = mult_prev<tag2, SUBNET>;\n    template <typename SUBNET> using mult_prev3  = mult_prev<tag3, SUBNET>;\n    template <typename SUBNET> using mult_prev4  = mult_prev<tag4, SUBNET>;\n    template <typename SUBNET> using mult_prev5  = mult_prev<tag5, SUBNET>;\n    template <typename SUBNET> using mult_prev6  = mult_prev<tag6, SUBNET>;\n    template <typename SUBNET> using mult_prev7  = mult_prev<tag7, SUBNET>;\n    template <typename SUBNET> using mult_prev8  = mult_prev<tag8, SUBNET>;\n    template <typename SUBNET> using mult_prev9  = mult_prev<tag9, SUBNET>;\n    template <typename SUBNET> using mult_prev10 = mult_prev<tag10, SUBNET>;\n\n    using mult_prev1_  = mult_prev_<tag1>;\n    using mult_prev2_  = mult_prev_<tag2>;\n    using mult_prev3_  = mult_prev_<tag3>;\n    using mult_prev4_  = mult_prev_<tag4>;\n    using mult_prev5_  = mult_prev_<tag5>;\n    using mult_prev6_  = mult_prev_<tag6>;\n    using mult_prev7_  = mult_prev_<tag7>;\n    using mult_prev8_  = mult_prev_<tag8>;\n    using mult_prev9_  = mult_prev_<tag9>;\n    using mult_prev10_ = mult_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class multm_prev_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        multm_prev_() {}\n        template <typename SUBNET> void setup(const SUBNET& /*sub*/) {}\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto& t1 = sub.get_output();\n            auto& t2 = layer<tag>(sub).get_output();\n            output.set_size(t1.num_samples(), t1.k(), t1.nr(), t2.nc());\n\n            tt::gemm(0, output, 1, t1, false, t2, false, operation_mode::PLANE_WISE);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto& t1 = sub.get_output();\n            auto& t2 = layer<tag>(sub).get_output();\n            auto& prev = sub.get_gradient_input();\n            auto& prev_tag = layer<tag>(sub).get_gradient_input();            \n\n            tt::gemm(1, prev, 1, gradient_input, false, t2, true, operation_mode::PLANE_WISE);\n            tt::gemm(1, prev_tag, 1, t1, true, gradient_input, false, operation_mode::PLANE_WISE);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        inline dpoint map_input_to_output(const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input(const dpoint& p) const { return p; }\n\n        friend void serialize(const multm_prev_& /*item*/, std::ostream& out)\n        {\n            serialize(\"multm_prev_\", out);\n        }\n        friend void deserialize(multm_prev_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"multm_prev_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::multm_prev_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const multm_prev_& /*item*/)\n        {\n            out << \"multm_prev\" << id;\n            return out;\n        }\n        friend void to_xml(const multm_prev_& /*item*/, std::ostream& out)\n        {\n            out << \"<multm_prev tag='\" << id << \"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params; // unused\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using multm_prev = add_layer<multm_prev_<tag>, SUBNET>;\n\n    template <typename SUBNET> using multm_prev1 = multm_prev<tag1, SUBNET>;\n    template <typename SUBNET> using multm_prev2 = multm_prev<tag2, SUBNET>;\n    template <typename SUBNET> using multm_prev3 = multm_prev<tag3, SUBNET>;\n    template <typename SUBNET> using multm_prev4 = multm_prev<tag4, SUBNET>;\n    template <typename SUBNET> using multm_prev5 = multm_prev<tag5, SUBNET>;\n    template <typename SUBNET> using multm_prev6 = multm_prev<tag6, SUBNET>;\n    template <typename SUBNET> using multm_prev7 = multm_prev<tag7, SUBNET>;\n    template <typename SUBNET> using multm_prev8 = multm_prev<tag8, SUBNET>;\n    template <typename SUBNET> using multm_prev9 = multm_prev<tag9, SUBNET>;\n    template <typename SUBNET> using multm_prev10 = multm_prev<tag10, SUBNET>;\n    using multm_prev1_ = multm_prev_<tag1>;\n    using multm_prev2_ = multm_prev_<tag2>;\n    using multm_prev3_ = multm_prev_<tag3>;\n    using multm_prev4_ = multm_prev_<tag4>;\n    using multm_prev5_ = multm_prev_<tag5>;\n    using multm_prev6_ = multm_prev_<tag6>;\n    using multm_prev7_ = multm_prev_<tag7>;\n    using multm_prev8_ = multm_prev_<tag8>;\n    using multm_prev9_ = multm_prev_<tag9>;\n    using multm_prev10_ = multm_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class resize_prev_to_tagged_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        resize_prev_to_tagged_()\n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto& prev = sub.get_output();\n            auto& tagged = layer<tag>(sub).get_output();\n\n            DLIB_CASSERT(prev.num_samples() == tagged.num_samples());\n\n            output.set_size(prev.num_samples(),\n                            prev.k(),\n                            tagged.nr(),\n                            tagged.nc());\n\n            if (prev.nr() == tagged.nr() && prev.nc() == tagged.nc())\n            {\n                tt::copy_tensor(false, output, 0, prev, 0, prev.k());\n            }\n            else\n            {\n                tt::resize_bilinear(output, prev);\n            }\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto& prev = sub.get_gradient_input();\n\n            DLIB_CASSERT(prev.k() == gradient_input.k());\n            DLIB_CASSERT(prev.num_samples() == gradient_input.num_samples());\n\n            if (prev.nr() == gradient_input.nr() && prev.nc() == gradient_input.nc())\n            {\n                tt::copy_tensor(true, prev, 0, gradient_input, 0, prev.k());\n            }\n            else\n            {\n                tt::resize_bilinear_gradient(prev, gradient_input);\n            }\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        friend void serialize(const resize_prev_to_tagged_& /*item*/, std::ostream& out)\n        {\n            serialize(\"resize_prev_to_tagged_\", out);\n        }\n\n        friend void deserialize(resize_prev_to_tagged_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"resize_prev_to_tagged_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::resize_prev_to_tagged_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const resize_prev_to_tagged_& /*item*/)\n        {\n            out << \"resize_prev_to_tagged\"<<id;\n            return out;\n        }\n\n        friend void to_xml(const resize_prev_to_tagged_& /*item*/, std::ostream& out)\n        {\n            out << \"<resize_prev_to_tagged tag='\"<<id<<\"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using resize_prev_to_tagged = add_layer<resize_prev_to_tagged_<tag>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class scale_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        scale_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto&& scales = sub.get_output();\n            auto&& src = layer<tag>(sub).get_output();\n            DLIB_CASSERT(scales.num_samples() == src.num_samples() &&\n                         scales.k()           == src.k() &&\n                         scales.nr()          == 1 &&\n                         scales.nc()          == 1, \n                         \"scales.k(): \" << scales.k() <<\n                         \"\\nsrc.k(): \" << src.k() \n                         );\n\n            output.copy_size(src);\n            tt::scale_channels(false, output, src, scales);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto&& scales = sub.get_output();\n            auto&& src = layer<tag>(sub).get_output();\n            // The gradient just flows backwards to the two layers that forward()\n            // read from.\n            tt::scale_channels(true, layer<tag>(sub).get_gradient_input(), gradient_input, scales);\n\n            if (reshape_src.num_samples() != src.num_samples())\n            {\n                reshape_scales = alias_tensor(src.num_samples()*src.k());\n                reshape_src = alias_tensor(src.num_samples()*src.k(),src.nr()*src.nc());\n            }\n\n            auto&& scales_grad = sub.get_gradient_input();\n            auto sgrad = reshape_scales(scales_grad);\n            tt::dot_prods(true, sgrad, reshape_src(src), reshape_src(gradient_input));\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const scale_& item, std::ostream& out)\n        {\n            serialize(\"scale_\", out);\n            serialize(item.reshape_scales, out);\n            serialize(item.reshape_src, out);\n        }\n\n        friend void deserialize(scale_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"scale_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::scale_.\");\n            deserialize(item.reshape_scales, in);\n            deserialize(item.reshape_src, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const scale_& /*item*/)\n        {\n            out << \"scale\"<<id;\n            return out;\n        }\n\n        friend void to_xml(const scale_& /*item*/, std::ostream& out)\n        {\n            out << \"<scale tag='\"<<id<<\"'/>\\n\";\n        }\n\n    private:\n        alias_tensor reshape_scales;\n        alias_tensor reshape_src;\n        resizable_tensor params;\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using scale = add_layer<scale_<tag>, SUBNET>;\n\n    template <typename SUBNET> using scale1  = scale<tag1, SUBNET>;\n    template <typename SUBNET> using scale2  = scale<tag2, SUBNET>;\n    template <typename SUBNET> using scale3  = scale<tag3, SUBNET>;\n    template <typename SUBNET> using scale4  = scale<tag4, SUBNET>;\n    template <typename SUBNET> using scale5  = scale<tag5, SUBNET>;\n    template <typename SUBNET> using scale6  = scale<tag6, SUBNET>;\n    template <typename SUBNET> using scale7  = scale<tag7, SUBNET>;\n    template <typename SUBNET> using scale8  = scale<tag8, SUBNET>;\n    template <typename SUBNET> using scale9  = scale<tag9, SUBNET>;\n    template <typename SUBNET> using scale10 = scale<tag10, SUBNET>;\n\n    using scale1_  = scale_<tag1>;\n    using scale2_  = scale_<tag2>;\n    using scale3_  = scale_<tag3>;\n    using scale4_  = scale_<tag4>;\n    using scale5_  = scale_<tag5>;\n    using scale6_  = scale_<tag6>;\n    using scale7_  = scale_<tag7>;\n    using scale8_  = scale_<tag8>;\n    using scale9_  = scale_<tag9>;\n    using scale10_ = scale_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class scale_prev_\n    {\n    public:\n        const static unsigned long id = tag_id<tag>::id;\n\n        scale_prev_()\n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto&& src = sub.get_output();\n            auto&& scales = layer<tag>(sub).get_output();\n            DLIB_CASSERT(scales.num_samples() == src.num_samples() &&\n                         scales.k()           == src.k() &&\n                         scales.nr()          == 1 &&\n                         scales.nc()          == 1,\n                         \"scales.k(): \" << scales.k() <<\n                         \"\\nsrc.k(): \" << src.k()\n                         );\n\n            output.copy_size(src);\n            tt::scale_channels(false, output, src, scales);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto&& src = sub.get_output();\n            auto&& scales = layer<tag>(sub).get_output();\n            tt::scale_channels(true, sub.get_gradient_input(), gradient_input, scales);\n\n            if (reshape_src.num_samples() != src.num_samples())\n            {\n                reshape_scales = alias_tensor(src.num_samples()*src.k());\n                reshape_src = alias_tensor(src.num_samples()*src.k(),src.nr()*src.nc());\n            }\n\n            auto&& scales_grad = layer<tag>(sub).get_gradient_input();\n            auto sgrad = reshape_scales(scales_grad);\n            tt::dot_prods(true, sgrad, reshape_src(src), reshape_src(gradient_input));\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        friend void serialize(const scale_prev_& item, std::ostream& out)\n        {\n            serialize(\"scale_prev_\", out);\n            serialize(item.reshape_scales, out);\n            serialize(item.reshape_src, out);\n        }\n\n        friend void deserialize(scale_prev_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"scale_prev_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::scale_prev_.\");\n            deserialize(item.reshape_scales, in);\n            deserialize(item.reshape_src, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const scale_prev_& /*item*/)\n        {\n            out << \"scale_prev\"<<id;\n            return out;\n        }\n\n        friend void to_xml(const scale_prev_& /*item*/, std::ostream& out)\n        {\n            out << \"<scale_prev tag='\"<<id<<\"'/>\\n\";\n        }\n\n    private:\n        alias_tensor reshape_scales;\n        alias_tensor reshape_src;\n        resizable_tensor params;\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using scale_prev = add_layer<scale_prev_<tag>, SUBNET>;\n\n    template <typename SUBNET> using scale_prev1  = scale_prev<tag1, SUBNET>;\n    template <typename SUBNET> using scale_prev2  = scale_prev<tag2, SUBNET>;\n    template <typename SUBNET> using scale_prev3  = scale_prev<tag3, SUBNET>;\n    template <typename SUBNET> using scale_prev4  = scale_prev<tag4, SUBNET>;\n    template <typename SUBNET> using scale_prev5  = scale_prev<tag5, SUBNET>;\n    template <typename SUBNET> using scale_prev6  = scale_prev<tag6, SUBNET>;\n    template <typename SUBNET> using scale_prev7  = scale_prev<tag7, SUBNET>;\n    template <typename SUBNET> using scale_prev8  = scale_prev<tag8, SUBNET>;\n    template <typename SUBNET> using scale_prev9  = scale_prev<tag9, SUBNET>;\n    template <typename SUBNET> using scale_prev10 = scale_prev<tag10, SUBNET>;\n\n    using scale_prev1_  = scale_prev_<tag1>;\n    using scale_prev2_  = scale_prev_<tag2>;\n    using scale_prev3_  = scale_prev_<tag3>;\n    using scale_prev4_  = scale_prev_<tag4>;\n    using scale_prev5_  = scale_prev_<tag5>;\n    using scale_prev6_  = scale_prev_<tag6>;\n    using scale_prev7_  = scale_prev_<tag7>;\n    using scale_prev8_  = scale_prev_<tag8>;\n    using scale_prev9_  = scale_prev_<tag9>;\n    using scale_prev10_ = scale_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    class relu_\n    {\n    public:\n        relu_()\n        {\n        }\n\n        void disable()\n        {\n            params.clear();\n            disabled = true;\n        }\n\n        bool is_disabled() const { return disabled; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            if (disabled)\n                return;\n\n            tt::relu(output, input);\n        } \n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& \n        )\n        {\n            if (disabled)\n                return;\n\n            tt::relu_gradient(data_grad, computed_output, gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const relu_& item, std::ostream& out)\n        {\n            serialize(\"relu_2\", out);\n            serialize(item.disabled, out);\n        }\n\n        friend void deserialize(relu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"relu_2\")\n            {\n                deserialize(item.disabled, in);\n                return;\n            }\n            if (version != \"relu_\" && version != \"relu_2\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::relu_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const relu_& item)\n        {\n            out << \"relu\";\n            if (item.disabled)\n            {\n                out << \"\\t (disabled)\";\n            }\n            return out;\n        }\n\n        friend void to_xml(const relu_& item, std::ostream& out)\n        {\n            out << \"<relu\";\n            if (item.disabled)\n            {\n                out << \" disabled='\"<< std::boolalpha << item.disabled << \"'\";\n            }\n            out << \"/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        bool disabled = false;\n    };\n\n\n    template <typename SUBNET>\n    using relu = add_layer<relu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class prelu_\n    {\n    public:\n        explicit prelu_(\n            float initial_param_value_ = 0.25\n        ) : initial_param_value(initial_param_value_)\n        {\n        }\n\n        float get_initial_param_value (\n        ) const { return initial_param_value; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n            params.set_size(1);\n            params = initial_param_value;\n        }\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub, \n            resizable_tensor& data_output\n        )\n        {\n            data_output.copy_size(sub.get_output());\n            tt::prelu(data_output, sub.get_output(), params);\n        }\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        )\n        {\n            tt::prelu_gradient(sub.get_gradient_input(), sub.get_output(), \n                gradient_input, params, params_grad);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const prelu_& item, std::ostream& out)\n        {\n            serialize(\"prelu_\", out);\n            serialize(item.params, out);\n            serialize(item.initial_param_value, out);\n        }\n\n        friend void deserialize(prelu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"prelu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::prelu_.\");\n            deserialize(item.params, in);\n            deserialize(item.initial_param_value, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const prelu_& item)\n        {\n            out << \"prelu\\t (\"\n                << \"initial_param_value=\"<<item.initial_param_value\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const prelu_& item, std::ostream& out)\n        {\n            out << \"<prelu initial_param_value='\"<<item.initial_param_value<<\"'>\\n\";\n            out << mat(item.params);\n            out << \"</prelu>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        float initial_param_value;\n    };\n\n    template <typename SUBNET>\n    using prelu = add_layer<prelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class leaky_relu_\n    {\n    public:\n        explicit leaky_relu_(\n            float alpha_ = 0.01f\n        ) : alpha(alpha_)\n        {\n        }\n\n        float get_alpha(\n        ) const {\n            return alpha;\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::leaky_relu(output, input, alpha);\n        }\n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor&\n        )\n        {\n            tt::leaky_relu_gradient(data_grad, computed_output, gradient_input, alpha);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const leaky_relu_& item, std::ostream& out)\n        {\n            serialize(\"leaky_relu_\", out);\n            serialize(item.alpha, out);\n        }\n\n        friend void deserialize(leaky_relu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"leaky_relu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::leaky_relu_.\");\n            deserialize(item.alpha, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const leaky_relu_& item)\n        {\n            out << \"leaky_relu\\t(\"\n                << \"alpha=\" << item.alpha\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const leaky_relu_& item, std::ostream& out)\n        {\n            out << \"<leaky_relu alpha='\"<< item.alpha << \"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        float alpha;\n    };\n\n    template <typename SUBNET>\n    using leaky_relu = add_layer<leaky_relu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class sig_\n    {\n    public:\n        sig_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::sigmoid(output, input);\n        } \n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& \n        )\n        {\n            tt::sigmoid_gradient(data_grad, computed_output, gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const sig_& /*item*/, std::ostream& out)\n        {\n            serialize(\"sig_\", out);\n        }\n\n        friend void deserialize(sig_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"sig_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::sig_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const sig_& /*item*/)\n        {\n            out << \"sig\";\n            return out;\n        }\n\n        friend void to_xml(const sig_& /*item*/, std::ostream& out)\n        {\n            out << \"<sig/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n    };\n\n\n    template <typename SUBNET>\n    using sig = add_layer<sig_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class mish_\n    {\n    public:\n        mish_()\n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub,\n            resizable_tensor& data_output\n        )\n        {\n            data_output.copy_size(sub.get_output());\n            tt::mish(data_output, sub.get_output());\n        }\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor&\n        )\n        {\n            tt::mish_gradient(sub.get_gradient_input(), sub.get_output(), gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const mish_& /*item*/, std::ostream& out)\n        {\n            serialize(\"mish_\", out);\n        }\n\n        friend void deserialize(mish_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"mish_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::mish_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const mish_& /*item*/)\n        {\n            out << \"mish\";\n            return out;\n        }\n\n        friend void to_xml(const mish_& /*item*/, std::ostream& out)\n        {\n            out << \"<mish/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n    };\n\n\n    template <typename SUBNET>\n    using mish = add_layer<mish_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class htan_\n    {\n    public:\n        htan_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::tanh(output, input);\n        } \n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& \n        )\n        {\n            tt::tanh_gradient(data_grad, computed_output, gradient_input);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const htan_& /*item*/, std::ostream& out)\n        {\n            serialize(\"htan_\", out);\n        }\n\n        friend void deserialize(htan_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"htan_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::htan_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const htan_& /*item*/)\n        {\n            out << \"htan\";\n            return out;\n        }\n\n        friend void to_xml(const htan_& /*item*/, std::ostream& out)\n        {\n            out << \"<htan/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n    };\n\n\n    template <typename SUBNET>\n    using htan = add_layer<htan_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class clipped_relu_\n    {\n    public:\n        clipped_relu_(\n            const float ceiling_ = 6.0f\n        ) : ceiling(ceiling_)\n        {\n        }\n\n        float get_ceiling(\n        ) const {\n            return ceiling;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::clipped_relu(output, input, ceiling);\n        }\n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor&\n        )\n        {\n            tt::clipped_relu_gradient(data_grad, computed_output, gradient_input, ceiling);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const clipped_relu_& item, std::ostream& out)\n        {\n            serialize(\"clipped_relu_\", out);\n            serialize(item.ceiling, out);\n        }\n\n        friend void deserialize(clipped_relu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"clipped_relu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::clipped_relu_.\");\n            deserialize(item.ceiling, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const clipped_relu_& item)\n        {\n            out << \"clipped_relu\\t(\"\n                << \"ceiling=\" << item.ceiling\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const clipped_relu_& item, std::ostream& out)\n        {\n            out << \"<clipped_relu ceiling='\" << item.ceiling << \"'/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n        float ceiling;\n    };\n\n    template <typename SUBNET>\n    using clipped_relu = add_layer<clipped_relu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class elu_\n    {\n    public:\n        elu_(\n            const float alpha_ = 1.0f\n        ) : alpha(alpha_)\n        {\n        }\n\n        float get_alpha(\n        ) const {\n            return alpha;\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::elu(output, input, alpha);\n        }\n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor&\n        )\n        {\n            tt::elu_gradient(data_grad, computed_output, gradient_input, alpha);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const elu_& item, std::ostream& out)\n        {\n            serialize(\"elu_\", out);\n            serialize(item.alpha, out);\n        }\n\n        friend void deserialize(elu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"elu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::elu_.\");\n            deserialize(item.alpha, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const elu_& item)\n        {\n            out << \"elu\\t (\"\n                << \"alpha=\" << item.alpha\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const elu_& item, std::ostream& out)\n        {\n            out << \"<elu alpha='\" << item.alpha << \"'/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n        float alpha;\n    };\n\n    template <typename SUBNET>\n    using elu = add_layer<elu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class gelu_\n    {\n    public:\n        gelu_()\n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub,\n            resizable_tensor& data_output\n        )\n        {\n            data_output.copy_size(sub.get_output());\n            tt::gelu(data_output, sub.get_output());\n        }\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor&\n        )\n        {\n            tt::gelu_gradient(sub.get_gradient_input(), sub.get_output(), gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const gelu_& /*item*/, std::ostream& out)\n        {\n            serialize(\"gelu_\", out);\n        }\n\n        friend void deserialize(gelu_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"gelu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::gelu_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const gelu_& /*item*/)\n        {\n            out << \"gelu\";\n            return out;\n        }\n\n        friend void to_xml(const gelu_& /*item*/, std::ostream& out)\n        {\n            out << \"<gelu/>\\n\";\n        }\n\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <typename SUBNET>\n    using gelu = add_layer<gelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class smelu_\n    {\n    public:\n        explicit smelu_(\n            float beta_ = 1\n        ) : beta(beta_)\n        {\n        }\n\n        float get_beta(\n        ) const {\n            return beta;\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::smelu(output, input, beta);\n        }\n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor&\n        )\n        {\n            tt::smelu_gradient(data_grad, computed_output, gradient_input, beta);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const smelu_& item, std::ostream& out)\n        {\n            serialize(\"smelu_\", out);\n            serialize(item.beta, out);\n        }\n\n        friend void deserialize(smelu_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"smelu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::smelu_.\");\n            deserialize(item.beta, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const smelu_& item)\n        {\n            out << \"smelu\\t (\"\n                << \"beta=\" << item.beta\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const smelu_& item, std::ostream& out)\n        {\n            out << \"<smelu beta='\"<< item.beta << \"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n        float beta;\n    };\n\n    template <typename SUBNET>\n    using smelu = add_layer<smelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class silu_\n    {\n    public:\n        silu_(\n        )\n        {\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/)\n        {\n        }\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub,\n            resizable_tensor& data_ouput)\n        {\n            data_ouput.copy_size(sub.get_output());\n            tt::silu(data_ouput, sub.get_output());\n        }\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor&\n        )\n        {\n            tt::silu_gradient(sub.get_gradient_input(), sub.get_output(), gradient_input);\n        }\n\n        inline dpoint map_input_to_output (const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input (const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const silu_& /*item*/, std::ostream& out)\n        {\n            serialize(\"silu_\", out);\n        }\n\n        friend void deserialize(silu_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"silu_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::silu_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const silu_& /*item*/)\n        {\n            out << \"silu\";\n            return out;\n        }\n\n        friend void to_xml(const silu_& /*item*/, std::ostream& out)\n        {\n            out << \"<silu/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <typename SUBNET>\n    using silu = add_layer<silu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <operation_mode s_mode_>\n    class softmax_\n    {\n    public:\n        softmax_() {}\n\n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/) {}\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::softmax(output, input, s_mode_);\n        }\n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor& /*params_grad*/\n        )\n        {\n            tt::softmax_gradient(data_grad, computed_output, gradient_input, s_mode_);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const softmax_& /*item*/, std::ostream& out)\n        {\n            serialize(\"softmax_\", out);\n        }\n\n        friend void deserialize(softmax_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"softmax_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::softmax_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const softmax_& /*item*/)\n        {\n            out << \"softmax (mode=\" << (s_mode_ == operation_mode::CHANNEL_WISE\n                ? \"channel_wise\" : \"plane_wise\") << \")\";\n            return out;\n        }\n\n        friend void to_xml(const softmax_& /*item*/, std::ostream& out)\n        {\n            out << \"<softmax mode='\" << (s_mode_ == operation_mode::CHANNEL_WISE\n                ? \"channel_wise\" : \"plane_wise\") << \"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params; // unused\n    };\n\n    template <typename SUBNET>\n    using softmax = add_layer<softmax_<operation_mode::CHANNEL_WISE>, SUBNET>;\n\n    template <typename SUBNET>\n    using softmaxm = add_layer<softmax_<operation_mode::PLANE_WISE>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class softmax_all_\n    {\n    public:\n        softmax_all_() \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::softmax_all(output, input);\n        } \n\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& \n        )\n        {\n            tt::softmax_all_gradient(data_grad, computed_output, gradient_input);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const softmax_all_& /*item*/, std::ostream& out)\n        {\n            serialize(\"softmax_all_\", out);\n        }\n\n        friend void deserialize(softmax_all_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"softmax_all_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::softmax_all_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const softmax_all_& /*item*/)\n        {\n            out << \"softmax_all\";\n            return out;\n        }\n\n        friend void to_xml(const softmax_all_& /*item*/, std::ostream& out)\n        {\n            out << \"<softmax_all/>\\n\";\n        }\n\n    private:\n        resizable_tensor params;\n    };\n\n    template <typename SUBNET>\n    using softmax_all = add_layer<softmax_all_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <template<typename> class TAG_TYPE, template<typename> class... TAG_TYPES>\n        struct concat_helper_impl{\n\n            constexpr static size_t tag_count() {return 1 + concat_helper_impl<TAG_TYPES...>::tag_count();}\n            static void list_tags(std::ostream& out)\n            {\n                out << tag_id<TAG_TYPE>::id << (tag_count() > 1 ? \",\" : \"\");\n                concat_helper_impl<TAG_TYPES...>::list_tags(out);\n            }\n\n            template<typename SUBNET>\n            static void resize_out(resizable_tensor& out, const SUBNET& sub, long sum_k)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_output();\n                concat_helper_impl<TAG_TYPES...>::resize_out(out, sub, sum_k + t.k());\n            }\n            template<typename SUBNET>\n            static void concat(tensor& out, const SUBNET& sub, size_t k_offset)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_output();\n                tt::copy_tensor(false, out, k_offset, t, 0, t.k());\n                k_offset += t.k();\n                concat_helper_impl<TAG_TYPES...>::concat(out, sub, k_offset);\n            }\n            template<typename SUBNET>\n            static void split(const tensor& input, SUBNET& sub, size_t k_offset)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_gradient_input();\n                tt::copy_tensor(true, t, 0, input, k_offset, t.k());\n                k_offset += t.k();\n                concat_helper_impl<TAG_TYPES...>::split(input, sub, k_offset);\n            }\n        };\n        template <template<typename> class TAG_TYPE>\n        struct concat_helper_impl<TAG_TYPE>{\n            constexpr static size_t tag_count() {return 1;}\n            static void list_tags(std::ostream& out) \n            { \n                out << tag_id<TAG_TYPE>::id;\n            }\n\n            template<typename SUBNET>\n            static void resize_out(resizable_tensor& out, const SUBNET& sub, long sum_k)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_output();\n                out.set_size(t.num_samples(), t.k() + sum_k, t.nr(), t.nc());\n            }\n            template<typename SUBNET>\n            static void concat(tensor& out, const SUBNET& sub, size_t k_offset)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_output();\n                tt::copy_tensor(false, out, k_offset, t, 0, t.k());\n            }\n            template<typename SUBNET>\n            static void split(const tensor& input, SUBNET& sub, size_t k_offset)\n            {\n                auto& t = layer<TAG_TYPE>(sub).get_gradient_input();\n                tt::copy_tensor(true, t, 0, input, k_offset, t.k());\n            }\n        };\n    }\n    // concat layer\n    template<\n        template<typename> class... TAG_TYPES\n        >\n    class concat_\n    {\n        static void list_tags(std::ostream& out) { impl::concat_helper_impl<TAG_TYPES...>::list_tags(out);};\n\n    public:\n        constexpr static size_t tag_count() {return impl::concat_helper_impl<TAG_TYPES...>::tag_count();};\n\n        template <typename SUBNET>\n        void setup (const SUBNET&)\n        {\n            // do nothing\n        }\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            // the total depth of result is the sum of depths from all tags\n            impl::concat_helper_impl<TAG_TYPES...>::resize_out(output, sub, 0);\n\n            // copy output from each tag into different part result\n            impl::concat_helper_impl<TAG_TYPES...>::concat(output, sub, 0);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor&)\n        {\n            // Gradient is split into parts for each tag layer\n            impl::concat_helper_impl<TAG_TYPES...>::split(gradient_input, sub, 0);\n        }\n\n        dpoint map_input_to_output(dpoint p) const { return p; }\n        dpoint map_output_to_input(dpoint p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const concat_& /*item*/, std::ostream& out)\n        {\n            serialize(\"concat_\", out);\n            size_t count = tag_count();\n            serialize(count, out);\n        }\n\n        friend void deserialize(concat_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"concat_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::concat_.\");\n            size_t count_tags;\n            deserialize(count_tags, in);\n            if (count_tags != tag_count())\n                throw serialization_error(\"Invalid count of tags \"+ std::to_string(count_tags) +\", expecting \" +\n                                          std::to_string(tag_count()) +\n                                                  \" found while deserializing dlib::concat_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const concat_& /*item*/)\n        {\n            out << \"concat\\t (\";\n            list_tags(out);\n            out << \")\";\n            return out;\n        }\n\n        friend void to_xml(const concat_& /*item*/, std::ostream& out)\n        {\n            out << \"<concat tags='\";\n            list_tags(out);\n            out << \"'/>\\n\";\n        }\n\n    private:\n        resizable_tensor params; // unused\n    };\n\n\n    // concat layer definitions\n    template <template<typename> class TAG1,\n            template<typename> class TAG2,\n            typename SUBNET>\n    using concat2 = add_layer<concat_<TAG1, TAG2>, SUBNET>;\n\n    template <template<typename> class TAG1,\n            template<typename> class TAG2,\n            template<typename> class TAG3,\n            typename SUBNET>\n    using concat3 = add_layer<concat_<TAG1, TAG2, TAG3>, SUBNET>;\n\n    template <template<typename> class TAG1,\n            template<typename> class TAG2,\n            template<typename> class TAG3,\n            template<typename> class TAG4,\n            typename SUBNET>\n    using concat4 = add_layer<concat_<TAG1, TAG2, TAG3, TAG4>, SUBNET>;\n\n    template <template<typename> class TAG1,\n            template<typename> class TAG2,\n            template<typename> class TAG3,\n            template<typename> class TAG4,\n            template<typename> class TAG5,\n            typename SUBNET>\n    using concat5 = add_layer<concat_<TAG1, TAG2, TAG3, TAG4, TAG5>, SUBNET>;\n\n    // inception layer will use tags internally. If user will use tags too, some conflicts\n    // possible to exclude them, here are new tags specially for inceptions\n    template <typename SUBNET> using itag0  = add_tag_layer< 1000 + 0, SUBNET>;\n    template <typename SUBNET> using itag1  = add_tag_layer< 1000 + 1, SUBNET>;\n    template <typename SUBNET> using itag2  = add_tag_layer< 1000 + 2, SUBNET>;\n    template <typename SUBNET> using itag3  = add_tag_layer< 1000 + 3, SUBNET>;\n    template <typename SUBNET> using itag4  = add_tag_layer< 1000 + 4, SUBNET>;\n    template <typename SUBNET> using itag5  = add_tag_layer< 1000 + 5, SUBNET>;\n    // skip to inception input\n    template <typename SUBNET> using iskip  = add_skip_layer< itag0, SUBNET>;\n\n    // here are some templates to be used for creating inception layer groups\n    template <template<typename>class B1,\n            template<typename>class B2,\n            typename SUBNET>\n    using inception2 = concat2<itag1, itag2, itag1<B1<iskip< itag2<B2< itag0<SUBNET>>>>>>>;\n\n    template <template<typename>class B1,\n            template<typename>class B2,\n            template<typename>class B3,\n            typename SUBNET>\n    using inception3 = concat3<itag1, itag2, itag3, itag1<B1<iskip< itag2<B2<iskip< itag3<B3<  itag0<SUBNET>>>>>>>>>>;\n\n    template <template<typename>class B1,\n            template<typename>class B2,\n            template<typename>class B3,\n            template<typename>class B4,\n            typename SUBNET>\n    using inception4 = concat4<itag1, itag2, itag3, itag4,\n                itag1<B1<iskip< itag2<B2<iskip< itag3<B3<iskip<  itag4<B4<  itag0<SUBNET>>>>>>>>>>>>>;\n\n    template <template<typename>class B1,\n            template<typename>class B2,\n            template<typename>class B3,\n            template<typename>class B4,\n            template<typename>class B5,\n            typename SUBNET>\n    using inception5 = concat5<itag1, itag2, itag3, itag4, itag5,\n                itag1<B1<iskip< itag2<B2<iskip< itag3<B3<iskip<  itag4<B4<iskip<  itag5<B5<  itag0<SUBNET>>>>>>>>>>>>>>>>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const double DEFAULT_L2_NORM_EPS = 1e-5;\n\n    class l2normalize_\n    {\n    public:\n        explicit l2normalize_(\n            double eps_ = DEFAULT_L2_NORM_EPS\n        ) : \n            eps(eps_)\n        {\n        }\n\n        double get_eps() const { return eps; }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& /*sub*/)\n        {\n        }\n\n        void forward_inplace(const tensor& input, tensor& output)\n        {\n            tt::inverse_norms(norm, input, eps);\n            tt::scale_rows(output, input, norm);\n        } \n\n        void backward_inplace(\n            const tensor& computed_output, \n            const tensor& gradient_input, \n            tensor& data_grad, \n            tensor& /*params_grad*/\n        )\n        {\n            if (is_same_object(gradient_input, data_grad))\n            {\n                tt::dot_prods(temp, gradient_input, computed_output);\n                tt::scale_rows2(0, data_grad, gradient_input, computed_output, temp, norm);\n            }\n            else\n            {\n                tt::dot_prods(temp, gradient_input, computed_output);\n                tt::scale_rows2(1, data_grad, gradient_input, computed_output, temp, norm);\n            }\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const l2normalize_& item, std::ostream& out)\n        {\n            serialize(\"l2normalize_\", out);\n            serialize(item.eps, out);\n        }\n\n        friend void deserialize(l2normalize_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"l2normalize_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::l2normalize_.\");\n            deserialize(item.eps, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const l2normalize_& item)\n        {\n            out << \"l2normalize\";\n            out << \" eps=\"<<item.eps;\n            return out;\n        }\n\n        friend void to_xml(const l2normalize_& item, std::ostream& out)\n        {\n            out << \"<l2normalize\";\n            out << \" eps='\"<<item.eps<<\"'\";\n            out << \"/>\\n\";\n        }\n    private:\n        double eps;\n\n        resizable_tensor params; // unused\n        // Here only to avoid reallocation and as a cache between forward/backward\n        // functions.  \n        resizable_tensor norm;\n        resizable_tensor temp;\n    };\n\n    template <typename SUBNET>\n    using l2normalize = add_layer<l2normalize_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _offset,\n        long _k,\n        long _nr,\n        long _nc\n        >\n    class extract_\n    {\n        static_assert(_offset >= 0, \"The offset must be >= 0.\");\n        static_assert(_k > 0,  \"The number of channels must be > 0.\");\n        static_assert(_nr > 0, \"The number of rows must be > 0.\");\n        static_assert(_nc > 0, \"The number of columns must be > 0.\");\n    public:\n        extract_(\n        )  \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            DLIB_CASSERT((long)sub.get_output().size() >= sub.get_output().num_samples()*(_offset+_k*_nr*_nc), \n                \"The tensor we are trying to extract from the input tensor is too big to fit into the input tensor.\");\n\n            aout = alias_tensor(sub.get_output().num_samples(), _k*_nr*_nc);\n            ain = alias_tensor(sub.get_output().num_samples(),  sub.get_output().size()/sub.get_output().num_samples());\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            if (aout.num_samples() != sub.get_output().num_samples())\n            {\n                aout = alias_tensor(sub.get_output().num_samples(), _k*_nr*_nc);\n                ain = alias_tensor(sub.get_output().num_samples(),  sub.get_output().size()/sub.get_output().num_samples());\n            }\n\n            output.set_size(sub.get_output().num_samples(), _k, _nr, _nc);\n            auto out = aout(output,0);\n            auto in = ain(sub.get_output(),0);\n            tt::copy_tensor(false, out, 0, in, _offset, _k*_nr*_nc);\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto out = ain(sub.get_gradient_input(),0);\n            auto in = aout(gradient_input,0);\n            tt::copy_tensor(true, out, _offset, in, 0, _k*_nr*_nc);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const extract_& /*item*/, std::ostream& out)\n        {\n            serialize(\"extract_\", out);\n            serialize(_offset, out);\n            serialize(_k, out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n        }\n\n        friend void deserialize(extract_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"extract_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::extract_.\");\n\n            long offset;\n            long k;\n            long nr;\n            long nc;\n            deserialize(offset, in);\n            deserialize(k, in);\n            deserialize(nr, in);\n            deserialize(nc, in);\n\n            if (offset != _offset) throw serialization_error(\"Wrong offset found while deserializing dlib::extract_\");\n            if (k != _k)   throw serialization_error(\"Wrong k found while deserializing dlib::extract_\");\n            if (nr != _nr) throw serialization_error(\"Wrong nr found while deserializing dlib::extract_\");\n            if (nc != _nc) throw serialization_error(\"Wrong nc found while deserializing dlib::extract_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const extract_& /*item*/)\n        {\n            out << \"extract\\t (\"\n                << \"offset=\"<<_offset\n                << \", k=\"<<_k\n                << \", nr=\"<<_nr\n                << \", nc=\"<<_nc\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const extract_& /*item*/, std::ostream& out)\n        {\n            out << \"<extract\";\n            out << \" offset='\"<<_offset<<\"'\";\n            out << \" k='\"<<_k<<\"'\";\n            out << \" nr='\"<<_nr<<\"'\";\n            out << \" nc='\"<<_nc<<\"'\";\n            out << \"/>\\n\";\n        }\n    private:\n        alias_tensor aout, ain;\n\n        resizable_tensor params; // unused\n    };\n\n    template <\n        long offset,\n        long k,\n        long nr,\n        long nc,\n        typename SUBNET\n        >\n    using extract = add_layer<extract_<offset,k,nr,nc>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _offset_k,\n        long _offset_nr,\n        long _offset_nc,\n        long _k,\n        long _nr,\n        long _nc\n        >\n    class slice_\n    {\n        static_assert(_offset_k >= 0, \"The channel offset must be >= 0.\");\n        static_assert(_offset_nr >= 0, \"The row offset must be >= 0.\");\n        static_assert(_offset_nc >= 0, \"The column offset must be >= 0.\");\n        static_assert(_k > 0,  \"The number of channels must be > 0.\");\n        static_assert(_nr > 0, \"The number of rows must be > 0.\");\n        static_assert(_nc > 0, \"The number of columns must be > 0.\");\n    public:\n        slice_(\n        )  \n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            DLIB_CASSERT((long)sub.get_output().size() >= sub.get_output().num_samples()*(_offset_k+_offset_nr+_offset_nc+_k*_nr*_nc), \n                \"The tensor we are trying to slice from the input tensor is too big to fit into the input tensor.\");\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            output.set_size(sub.get_output().num_samples(), _k, _nr, _nc);\n            tt::copy_tensor(false, output, 0, 0, 0, sub.get_output(), _offset_k, _offset_nr, _offset_nc, _k, _nr, _nc);\n        } \n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            tt::copy_tensor(true, sub.get_gradient_input(), _offset_k, _offset_nr, _offset_nc, gradient_input, 0, 0, 0, _k, _nr, _nc);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const slice_& /*item*/, std::ostream& out)\n        {\n            serialize(\"slice_\", out);\n            serialize(_offset_k, out);\n            serialize(_offset_nr, out);\n            serialize(_offset_nc, out);\n            serialize(_k, out);\n            serialize(_nr, out);\n            serialize(_nc, out);\n        }\n\n        friend void deserialize(slice_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"slice_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::slice_.\");\n\n            long offset_k;\n            long offset_nr;\n            long offset_nc;\n            long k;\n            long nr;\n            long nc;\n            deserialize(offset_k, in);\n            deserialize(offset_nr, in);\n            deserialize(offset_nc, in);\n            deserialize(k, in);\n            deserialize(nr, in);\n            deserialize(nc, in);\n\n            if (offset_k != _offset_k) throw serialization_error(\"Wrong offset_k found while deserializing dlib::slice_\");\n            if (offset_nr != _offset_nr) throw serialization_error(\"Wrong offset_nr found while deserializing dlib::slice_\");\n            if (offset_nc != _offset_nc) throw serialization_error(\"Wrong offset_nc found while deserializing dlib::slice_\");\n            if (k != _k)   throw serialization_error(\"Wrong k found while deserializing dlib::slice_\");\n            if (nr != _nr) throw serialization_error(\"Wrong nr found while deserializing dlib::slice_\");\n            if (nc != _nc) throw serialization_error(\"Wrong nc found while deserializing dlib::slice_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const slice_& /*item*/)\n        {\n            out << \"slice\\t (\"\n                << \"offset_k=\"<<_offset_k\n                << \"offset_nr=\"<<_offset_nr\n                << \"offset_nc=\"<<_offset_nc\n                << \", k=\"<<_k\n                << \", nr=\"<<_nr\n                << \", nc=\"<<_nc\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const slice_& /*item*/, std::ostream& out)\n        {\n            out << \"<slice\";\n            out << \" offset_k='\"<<_offset_k<<\"'\";\n            out << \" offset_nr='\"<<_offset_nr<<\"'\";\n            out << \" offset_nr='\"<<_offset_nc<<\"'\";\n            out << \" k='\"<<_k<<\"'\";\n            out << \" nr='\"<<_nr<<\"'\";\n            out << \" nc='\"<<_nc<<\"'\";\n            out << \"/>\\n\";\n        }\n    private:\n        resizable_tensor params; // unused\n    };\n\n    template <\n        long offset_k,\n        long offset_nr,\n        long offset_nc,\n        long k,\n        long nr,\n        long nc,\n        typename SUBNET\n        >\n    using slice = add_layer<slice_<offset_k,offset_nr,offset_nc,k,nr,nc>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <long long row_stride = 2, long long col_stride = 2>\n    class reorg_\n    {\n        static_assert(row_stride >= 1, \"The row_stride must be >= 1\");\n        static_assert(row_stride >= 1, \"The col_stride must be >= 1\");\n\n    public:\n        reorg_(\n        )\n        {\n        }\n\n        template <typename SUBNET>\n        void setup (const SUBNET& sub)\n        {\n            DLIB_CASSERT(sub.get_output().nr() % row_stride == 0);\n            DLIB_CASSERT(sub.get_output().nc() % col_stride == 0);\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            output.set_size(\n                sub.get_output().num_samples(),\n                sub.get_output().k() * col_stride * row_stride,\n                sub.get_output().nr() / row_stride,\n                sub.get_output().nc() / col_stride\n            );\n            tt::reorg(false, output, row_stride, col_stride, sub.get_output());\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            tt::reorg_gradient(true, sub.get_gradient_input(), row_stride, col_stride, gradient_input);\n        }\n\n        inline dpoint map_input_to_output (dpoint p) const\n        {\n            p.x() = p.x() / col_stride;\n            p.y() = p.y() / row_stride;\n            return p;\n        }\n        inline dpoint map_output_to_input (dpoint p) const\n        {\n            p.x() = p.x() * col_stride;\n            p.y() = p.y() * row_stride;\n            return p;\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const reorg_& /*item*/, std::ostream& out)\n        {\n            serialize(\"reorg_\", out);\n            serialize(row_stride, out);\n            serialize(col_stride, out);\n        }\n\n        friend void deserialize(reorg_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"reorg_\")\n                throw serialization_error(\"Unexpected version '\"+version+\"' found while deserializing dlib::reorg_.\");\n            long long rs;\n            long long cs;\n            deserialize(rs, in);\n            deserialize(cs, in);\n            if (rs != row_stride) throw serialization_error(\"Wrong row_stride found while deserializing dlib::reorg_\");\n            if (cs != col_stride) throw serialization_error(\"Wrong col_stride found while deserializing dlib::reorg_\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const reorg_& /*item*/)\n        {\n            out << \"reorg\\t (\"\n                << \"row_stride=\" << row_stride\n                << \", col_stride=\" << col_stride\n                << \")\";\n            return out;\n        }\n\n        friend void to_xml(const reorg_ /*item*/, std::ostream& out)\n        {\n            out << \"<reorg\";\n            out << \" row_stride='\" << row_stride << \"'\";\n            out << \" col_stride='\" << col_stride << \"'\";\n            out << \"/>\\n\";\n        }\n\n    private:\n        resizable_tensor params; // unused\n\n    };\n\n    template <typename SUBNET>\n    using reorg = add_layer<reorg_<2, 2>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class transpose_ {\n    public:\n        transpose_() {}\n        template <typename SUBNET> void setup(const SUBNET& /*sub*/) {}\n\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output) {\n            auto& prev = sub.get_output();\n\n            output.set_size(prev.num_samples(), prev.k(), prev.nc(), prev.nr());\n            tt::transpose(false, output, prev);           \n        }\n\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/) {\n            auto& prev = sub.get_gradient_input();\n            tt::transpose(true, prev, gradient_input);\n        }\n\n        inline dpoint map_input_to_output(dpoint p) const\n        {\n            dpoint temp_p;\n            temp_p.x() = p.y();\n            temp_p.y() = p.x();\n            return temp_p;\n        }\n        inline dpoint map_output_to_input(dpoint p) const\n        {\n            dpoint temp_p;\n            temp_p.x() = p.y();\n            temp_p.y() = p.x();\n            return temp_p;\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        friend void serialize(const transpose_& /*item*/, std::ostream& out) {\n            serialize(\"transpose_\", out);\n        }\n        friend void deserialize(transpose_& /*item*/, std::istream& in) {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"transpose_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::transpose_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const transpose_& /*item*/) {\n            out << \"transpose\";\n            return out;\n        }\n        friend void to_xml(const transpose_& /*item*/, std::ostream& out) {\n            out << \"<transpose />\\n\";\n        }\n\n    private:\n        dlib::resizable_tensor params; // unused\n    };\n\n    template <typename SUBNET> using transpose = add_layer<transpose_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class positional_encodings_ {\n    public:\n        positional_encodings_(unsigned long sequence_dim_ = 1, unsigned long embedding_dim_ = 1) :\n            sequence_dim(sequence_dim_), embedding_dim(embedding_dim_)\n        {\n        }\n        positional_encodings_(const positional_encodings_& item) : \n            pe(item.pe), sequence_dim(item.sequence_dim), embedding_dim(item.embedding_dim)\n        {\n        }\n        positional_encodings_& operator= (const positional_encodings_& item) {\n            if (this == &item) return *this;\n            pe = item.pe;\n            sequence_dim = item.sequence_dim;\n            embedding_dim = item.embedding_dim;\n            return *this;\n        }\n        \n        template <typename SUBNET>\n        void setup(const SUBNET& sub)\n        {\n            auto& prev = sub.get_output();\n\n            sequence_dim = prev.nr();\n            embedding_dim = prev.nc();\n            const unsigned long ns = prev.num_samples();\n            const unsigned long nk = prev.k();\n            const float n = 10000.0f;\n\n            pe.set_size(ns, nk, sequence_dim, embedding_dim);              \n            for (unsigned long s = 0; s < ns; ++s)\n            {\n                for (unsigned long k = 0; k < nk; ++k)\n                {\n                    for (unsigned long r = 0; r < sequence_dim; ++r)\n                    {\n                        for (unsigned long c = 0; c < embedding_dim; ++c)\n                        {\n                            float theta = static_cast<float>(r) / std::pow(n, static_cast<float>(c) / embedding_dim);\n                            if (c % 2 == 0) pe.host()[tensor_index(pe, s, k, r, c)] = std::sin(theta);\n                            else pe.host()[tensor_index(pe, s, k, r, c)] = std::cos(theta);\n                        }\n                    }\n                }\n            }\n        }\n        \n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {            \n            const auto& prev_output = sub.get_output();            \n            if (!have_same_dimensions(pe, prev_output)) setup(sub);\n            \n            output.set_size(prev_output.num_samples(), prev_output.k(), sequence_dim, embedding_dim);\n            tt::add(output, prev_output, pe);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto& prev_grad = sub.get_gradient_input();\n            tt::add(prev_grad, prev_grad, gradient_input);\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        const tensor& get_positional_encodings() const { return pe; }\n        tensor& get_positional_encodings() { return pe; }\n\n        friend void serialize(const positional_encodings_& /*item*/, std::ostream& out)\n        {\n            serialize(\"positional_encodings_\", out);\n        }\n        friend void deserialize(positional_encodings_& /*item*/, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"positional_encodings_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::positional_encodings_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const positional_encodings_& /*item*/)\n        {\n            out << \"positional_encodings\";\n            return out;\n        }\n        friend void to_xml(const positional_encodings_& /*item*/, std::ostream& out)\n        {\n            out << \"<positional_encodings />\\n\";\n        }\n\n    private:\n        resizable_tensor params; // unused\n        resizable_tensor pe;\n        unsigned long sequence_dim, embedding_dim;\n    };\n\n    template <typename SUBNET>\n    using positional_encodings = add_layer<positional_encodings_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template<\n        unsigned long num_embeddings_,\n        unsigned long embedding_dim_\n        >\n    class embeddings_\n    {\n        static_assert(num_embeddings_ > 0, \"The size of the embedding dictionary must be > 0\");\n        static_assert(embedding_dim_ > 0, \"The size of each embedding vector must be > 0\");\n\n    public:\n        embeddings_() : num_embeddings(num_embeddings_),\n            embedding_dim(embedding_dim_),\n            learning_rate_multiplier(1.0f),\n            scale_by_freq(true)\n        {\n        }\n\n        double get_learning_rate_multiplier() const { return learning_rate_multiplier; }\n        void set_learning_rate_multiplier(double val) { learning_rate_multiplier = val; }\n\n        void set_scale_by_freq(bool val) { scale_by_freq = val; }\n        bool get_scale_by_freq() const { return scale_by_freq; }\n\n        unsigned long get_num_embeddings() const { return num_embeddings; }\n        void set_num_embeddings(unsigned long num)\n        {\n            DLIB_CASSERT(num > 0);\n            if (num != num_embeddings)\n            {\n                DLIB_CASSERT(get_embeddings().size() == 0,\n                    \"It is not possible to change the size of the embedding dictionary if the parameter has already been assigned.\");                \n            }\n        }\n\n        unsigned long get_embedding_dim() const { return embedding_dim; }\n        void set_embedding_dim(unsigned long dim)\n        {\n            DLIB_CASSERT(dim > 0);\n            if (dim != embedding_dim)\n            {\n                DLIB_CASSERT(get_embeddings().size() == 0,\n                    \"It is not possible to change the size of the embedding dictionary if the parameter has already been assigned.\");\n            }\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/)\n        {\n            embs.set_size(num_embeddings, embedding_dim);\n            tt::tensor_rand rnd(std::rand());\n            rnd.fill_gaussian(embs);\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            const auto& prev = sub.get_output();\n            output.set_size(prev.num_samples(), prev.k(), prev.nr(), embedding_dim);\n\n            tt::embeddings(output, prev, embs);\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            // Because this class is expected to be directly after an <input> layer,\n            // it's not necessary to propagate the gradient.\n            // Additionally, this layer is treated as constant during backpropagation,\n            // so it technically doesn't contribute to the gradient computation.\n            if (learning_rate_multiplier != 0)\n            {\n                auto& prev_src = sub.get_output();\n                \n                calc_token_freqs(prev_src, gradient_input);\n                tt::embeddings_gradient(prev_src, gradient_input, embs, freqs, learning_rate_multiplier, scale_by_freq);\n            }\n        }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n\n        const tensor& get_embeddings() const { return embs; }\n        tensor& get_embeddings() { return embs; }\n\n        friend void serialize(const embeddings_& item, std::ostream& out)\n        {\n            serialize(\"embeddings_\", out);\n            serialize(item.embs, out);\n            serialize(item.num_embeddings, out);\n            serialize(item.embedding_dim, out);\n            serialize(item.learning_rate_multiplier, out);\n            serialize(item.scale_by_freq, out);\n        }\n        friend void deserialize(embeddings_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"embeddings_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::embeddings_.\");\n            deserialize(item.embs, in);\n            deserialize(item.num_embeddings, in);\n            deserialize(item.embedding_dim, in);\n            deserialize(item.learning_rate_multiplier, in);\n            deserialize(item.scale_by_freq, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const embeddings_& item)\n        {\n            out << \"embeddings (num_embeddings=\" << item.num_embeddings\n                << \", embedding_dim=\" << item.embedding_dim\n                << \") learning_rate_mult=\" << item.learning_rate_multiplier;\n            return out;\n        }\n        friend void to_xml(const embeddings_& item, std::ostream& out)\n        {\n            out << \"<embeddings num_embeddings='\" << item.num_embeddings\n                << \"' embedding_dim='\" << item.embedding_dim\n                << \"' learning_rate_mult='\"\n                << item.learning_rate_multiplier << \"'>\\n\";\n            out << mat(item.embs);\n            out << \"</embeddings>\\n\";\n        }\n\n    private:\n        void calc_token_freqs(const tensor& prev, const tensor& input) {\n            if (freqs.size() == 0) freqs.set_size(num_embeddings, 1, 1, 1);\n            freqs = 0;\n\n            const float* prev_data = prev.host();\n            float* freqs_data = freqs.host();\n            for (long s = 0; s < input.num_samples(); ++s)\n            {\n                for (long k = 0; k < input.k(); ++k)\n                {\n                    for (long r = 0; r < input.nr(); ++r)\n                    {\n                        const unsigned long token_idx = static_cast<unsigned long>(prev_data[tensor_index(prev, s, k, r, 0)]);\n                        if (token_idx < num_embeddings) freqs_data[tensor_index(freqs, token_idx, 0, 0, 0)]++;\n                    }\n                }\n            }\n        }\n\n        resizable_tensor params; // unused\n        resizable_tensor embs, freqs;\n        unsigned long num_embeddings, embedding_dim;\n        double learning_rate_multiplier;\n        bool scale_by_freq;\n    };\n\n    template <\n        unsigned long nb_embeddings,\n        unsigned long embedding_length,\n        typename SUBNET\n        >\n    using embeddings = add_layer<embeddings_<nb_embeddings, embedding_length>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n  \n    struct neg_infinity_tag {};\n    struct zero_tag {};\n\n    template<typename T>\n    struct is_special_value : std::false_type {};\n    template<>\n    struct is_special_value<neg_infinity_tag> : std::true_type {};\n    template<>\n    struct is_special_value<zero_tag> : std::true_type {};\n\n    template<long diag_, typename tag_, long num_ = 0, long den_ = 1>\n    class tril_\n    {\n    public:\n        tril_(): diag(diag_), diag_value(compute_diag_value()) {}\n        \n        template <typename SUBNET>\n        void setup(const SUBNET& /*sub*/)\n        {\n        }\n        \n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output)\n        {\n            auto& prev = sub.get_output();\n            output.set_size(prev.num_samples(), prev.k(), prev.nr(), prev.nc());\n\n            check_mask(prev);\n            tt::multiply(false, output, prev, binary_mask);\n            if (diag_value != 0.0f) tt::add(1, output, 1, output_mask);\n        }\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& /*params_grad*/)\n        {\n            auto& prev_grad = sub.get_gradient_input();\n            tt::multiply(true, prev_grad, gradient_input, binary_mask);\n        }\n\n        inline dpoint map_input_to_output(const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input(const dpoint& p) const { return p; }\n\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n        \n        friend void serialize(const tril_& item, std::ostream& out)\n        {\n            serialize(\"tril_\", out);\n            serialize(item.diag, out);\n            serialize(item.diag_value, out);\n        }\n        friend void deserialize(tril_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"tril_\")\n                throw serialization_error(\"Unexpected version '\" + version + \"' found while deserializing dlib::tril_.\");\n            deserialize(item.diag, in);\n            deserialize(item.diag_value, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const tril_& item)\n        {\n            out << \"tril (diag=\" << item.diag << \", diag_value=\" << item.diag_value << \")\";\n            return out;\n        }\n        friend void to_xml(const tril_& item, std::ostream& out)\n        {\n            out << \"<tril diag='\" << item.diag << \"' diag_value='\" << item.diag_value << \"'/>\\n\";\n        }\n\n    private:\n        float compute_diag_value() const {\n            if (std::is_same<tag_, neg_infinity_tag>::value)\n                return -std::numeric_limits<float>::infinity();\n            else if (std::is_same<tag_, zero_tag>::value)\n                return 0.0f;\n            else\n                return static_cast<float>(num_) / static_cast<float>(den_);\n        }\n\n        void check_mask(const tensor& t)\n        {\n            if (!have_same_dimensions(binary_mask, t)) {\n                binary_mask.copy_size(t);\n                binary_mask = 1;\n                if (diag_value != 0.0f) {\n                    output_mask.copy_size(t);\n                    output_mask = 0;\n                }                                \n                for (long s = 0; s < output_mask.num_samples(); ++s)\n                {\n                    for (long k = 0; k < output_mask.k(); ++k)\n                    {\n                        for (long r = 0; r < output_mask.nr(); ++r)\n                        {\n                            for (long c = std::max(r + diag + 1, 0L); c < output_mask.nc(); ++c)\n                            {\n                                if (diag_value != 0.0f) output_mask.host()[tensor_index(output_mask, s, k, r, c)] = diag_value;\n                                binary_mask.host()[tensor_index(binary_mask, s, k, r, c)] = 0;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        template <typename T>\n        struct always_false : std::false_type {};\n\n        resizable_tensor params; // unused\n        resizable_tensor binary_mask, output_mask;\n        long diag;\n        float diag_value;\n    };\n\n    template <typename SUBNET>\n    using tril = add_layer<tril_<0, zero_tag>, SUBNET>;\n\n    template <typename SUBNET>\n    using tril_mask = add_layer<tril_<0, neg_infinity_tag>, SUBNET>;\n\n    template <long diag, long num, long den, typename SUBNET>\n    using tril_diag = add_layer<tril_<diag, void, num, den>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <long max_steps = 8>\n    class adaptive_computation_time_ {\n    public:\n        explicit adaptive_computation_time_() :\n            max_steps_(max_steps),\n            halt_threshold_(0.99f),     // theta in Graves' notation\n            ponder_penalty_(0.01f),     // lambda (ponder cost weight)\n            enable_depth_scaling_(false),\n            batch_size_(0),\n            seq_len_(0),\n            d_model_(0),\n            num_channels_(0),\n            feature_dim_(0),\n            ponder_cost_(0),\n            avg_steps_(0)\n        {\n        }\n\n        adaptive_computation_time_(const adaptive_computation_time_& item) :\n            max_steps_(item.max_steps_),\n            halt_threshold_(item.halt_threshold_),\n            ponder_penalty_(item.ponder_penalty_),\n            enable_depth_scaling_(item.enable_depth_scaling_),\n            batch_size_(item.batch_size_),\n            seq_len_(item.seq_len_),\n            d_model_(item.d_model_),\n            num_channels_(item.num_channels_),\n            feature_dim_(item.feature_dim_),\n            ponder_cost_(item.ponder_cost_),\n            avg_steps_(item.avg_steps_),\n            params(item.params),\n            halting_probs_(item.halting_probs_),\n            cumulative_halting_(item.cumulative_halting_),\n            remainders_(item.remainders_),\n            n_steps_(item.n_steps_),\n            logits_(item.logits_),\n            grad_logits_(item.grad_logits_),\n            input_cache_(item.input_cache_),\n            true_effective_weights_(item.true_effective_weights_)\n        {\n        }\n\n        adaptive_computation_time_& operator=(const adaptive_computation_time_& item)\n        {\n            if (this == &item)\n                return *this;\n\n            max_steps_ = item.max_steps_;\n            halt_threshold_ = item.halt_threshold_;\n            ponder_penalty_ = item.ponder_penalty_;\n            enable_depth_scaling_ = item.enable_depth_scaling_;\n            batch_size_ = item.batch_size_;\n            seq_len_ = item.seq_len_;\n            d_model_ = item.d_model_;\n            num_channels_ = item.num_channels_;\n            feature_dim_ = item.feature_dim_;\n            ponder_cost_ = item.ponder_cost_;\n            avg_steps_ = item.avg_steps_;\n            params = item.params;\n            halting_probs_ = item.halting_probs_;\n            cumulative_halting_ = item.cumulative_halting_;\n            remainders_ = item.remainders_;\n            n_steps_ = item.n_steps_;\n            logits_ = item.logits_;\n            grad_logits_ = item.grad_logits_;\n            input_cache_ = item.input_cache_;\n            true_effective_weights_ = item.true_effective_weights_;\n\n            return *this;\n        }\n\n        template <typename SUBNET>\n        void setup(const SUBNET& sub) {\n            const auto& input = sub.get_output();\n\n            // Store expected dimensions for parameter initialization\n            batch_size_ = input.num_samples();\n            seq_len_ = input.nr();\n            d_model_ = input.nc();\n            num_channels_ = input.k();\n            feature_dim_ = d_model_ * num_channels_;\n\n            // Initialize halting parameters\n            params.set_size(1, 1, feature_dim_ + 1, 1);\n\n            // He initialization for stability\n            dlib::rand rnd(std::rand());\n            const float scale = std::sqrt(2.0f / feature_dim_);\n            float* p = params.host();\n\n            // Initialize weight matrix W_halt\n            for (long i = 0; i < feature_dim_; ++i)\n                p[i] = rnd.get_random_gaussian() * scale;\n\n            // Initialize bias b_halt (typically zero)\n            p[feature_dim_] = 0.0f;\n\n            // Pre-allocate workspace for maximum expected size\n            allocate_workspace();\n        }\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output) {\n            const tensor& input = sub.get_output();\n            output.copy_size(input);\n\n            // Ensure workspace is allocated for current batch dimensions\n            const long curr_batch = input.num_samples();\n            if (curr_batch != batch_size_) {\n                batch_size_ = curr_batch;\n                allocate_workspace();\n            }\n\n            // Initialize output for weighted accumulation\n            output = 0;\n\n            // Initialize ACT state vectors\n            const long total_positions = batch_size_ * seq_len_;\n            float* cum_halt_ptr = cumulative_halting_.host();\n            float* remainders_ptr = remainders_.host();\n            float* n_steps_ptr = n_steps_.host();\n\n            for (long i = 0; i < total_positions; ++i) {\n                cum_halt_ptr[i] = 0.0f;      // h_t^n: cumulative halting probability\n                remainders_ptr[i] = 1.0f;    // ρ_t: remaining probability mass  \n                n_steps_ptr[i] = 0.0f;       // N(t): number of computation steps\n            }\n\n            // Cache input for backward pass\n            input_cache_.copy_size(input);\n            tt::copy_tensor(false, input_cache_, 0, input, 0, input.k());\n\n            // Initialize effective weights tracker for gradient computation\n            true_effective_weights_.set_size(total_positions, 1, 1, 1);\n            true_effective_weights_ = 0;\n\n            // Main ACT computation loop\n            for (long step = 0; step < max_steps_; ++step) {\n\n                // Compute halting probabilities: p_t^n = sigmoid(W_halt^T * s_t^n + b_halt)\n                tt::compute_act_halt_probabilities(\n                    halting_probs_, logits_, input, params,\n                    batch_size_, seq_len_, feature_dim_);\n\n                // Update ACT state and accumulate weighted outputs\n                tt::update_act_state(\n                    output, input, halting_probs_,\n                    cumulative_halting_, remainders_, n_steps_,\n                    true_effective_weights_,\n                    batch_size_, seq_len_, d_model_, num_channels_,\n                    halt_threshold_, step\n                );\n\n                // Early termination optimization\n                if (all_positions_halted(cumulative_halting_)) break;\n            }\n\n            // Finalize with remainder contributions\n            tt::finalize_act_output(\n                output, input, remainders_,\n                true_effective_weights_,\n                batch_size_, seq_len_, d_model_, num_channels_);\n\n            // Compute statistics for monitoring and regularization\n            compute_ponder_stats();\n        }\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad) {                     \n            tensor& input_grad = sub.get_gradient_input();\n\n            const float* grad_in = gradient_input.host();\n            const float* eff_weights = true_effective_weights_.host();\n            float* grad_out = input_grad.host();\n\n            for (long n = 0; n < batch_size_; ++n) {\n                for (long s = 0; s < seq_len_; ++s) {\n                    const long pos = n * seq_len_ + s;\n                    const float weight = eff_weights[pos];\n\n                    for (long c = 0; c < num_channels_; ++c) {\n                        for (long d = 0; d < d_model_; ++d) {\n                            const long idx = ((n * num_channels_ + c) * seq_len_ + s) * d_model_ + d;\n                            grad_out[idx] += weight * grad_in[idx];\n                        }\n                    }\n                }\n            }\n\n            // Compute parameter gradients from ponder cost regularization\n            params_grad = 0;\n\n            // Optional: Apply depth-dependent gradient scaling\n            if (enable_depth_scaling_) {\n                tt::apply_act_depth_scaling(\n                    input_grad, n_steps_,\n                    batch_size_, seq_len_, d_model_, num_channels_,\n                    static_cast<float>(max_steps_), 0.1f\n                );\n            }\n        }\n\n        // Accessor methods\n        const tensor& get_layer_params() const { return params; }\n        tensor& get_layer_params() { return params; }\n        long get_max_steps() const { return max_steps_; }\n        float get_halt_threshold() const { return halt_threshold_; }\n        float get_ponder_penalty() const { return ponder_penalty_; }\n\n        void set_halt_threshold(float threshold) {\n            if (threshold > 0 && threshold <= 1.0f)\n                halt_threshold_ = threshold;\n        }\n        void set_ponder_penalty(float penalty) {\n            if (penalty >= 0)\n                ponder_penalty_ = penalty;\n        }\n\n        // Statistics for monitoring and regularization\n        float get_ponder_cost() const { return ponder_cost_; }  // R(x)\n        float get_average_steps() const { return avg_steps_; }  // Average N(t)\n\n        // Depth scaling control\n        void enable_depth_scaling() { enable_depth_scaling_ = true; }\n        void disable_depth_scaling() { enable_depth_scaling_ = false; }\n        bool depth_scaling_enabled() const { return enable_depth_scaling_; }\n\n        inline dpoint map_input_to_output(const dpoint& p) const { return p; }\n        inline dpoint map_output_to_input(const dpoint& p) const { return p; }\n\n        // Serialization methods\n        friend void serialize(const adaptive_computation_time_& item, std::ostream& out) {\n            dlib::serialize(\"act_\", out);\n            dlib::serialize(item.max_steps_, out);\n            dlib::serialize(item.halt_threshold_, out);\n            dlib::serialize(item.ponder_penalty_, out);\n            dlib::serialize(item.enable_depth_scaling_, out);\n            dlib::serialize(item.batch_size_, out);\n            dlib::serialize(item.seq_len_, out);\n            dlib::serialize(item.d_model_, out);\n            dlib::serialize(item.num_channels_, out);\n            dlib::serialize(item.feature_dim_, out);\n            dlib::serialize(item.params, out);\n        }\n\n        friend void deserialize(adaptive_computation_time_& item, std::istream& in) {\n            std::string version;\n            dlib::deserialize(version, in);\n            if (version != \"act_\")\n                throw serialization_error(\"Unexpected version: \" + version);\n            dlib::deserialize(item.max_steps_, in);\n            dlib::deserialize(item.halt_threshold_, in);\n            dlib::deserialize(item.ponder_penalty_, in);\n            dlib::deserialize(item.enable_depth_scaling_, in);\n            dlib::deserialize(item.batch_size_, in);\n            dlib::deserialize(item.seq_len_, in);\n            dlib::deserialize(item.d_model_, in);\n            dlib::deserialize(item.num_channels_, in);\n            dlib::deserialize(item.feature_dim_, in);\n            dlib::deserialize(item.params, in);\n\n            item.allocate_workspace();\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const adaptive_computation_time_& item) {\n            out << \"act (steps=\" << item.max_steps_\n                << \", dim=\" << item.feature_dim_\n                << \", threshold=\" << item.halt_threshold_\n                << \", penalty=\" << item.ponder_penalty_ << \")\";\n            return out;\n        }\n\n        friend void to_xml(const adaptive_computation_time_& item, std::ostream& out) {\n            out << \"<act\"\n                << \" steps='\" << item.max_steps_ << \"'\"\n                << \" dim='\" << item.feature_dim_ << \"'\"\n                << \" threshold='\" << item.halt_threshold_ << \"'\"\n                << \" penalty='\" << item.ponder_penalty_ << \"'\"\n                << \" depth_scaling='\" << (item.enable_depth_scaling_ ? \"true\" : \"false\") << \"'\"\n                << \">\\n\";\n            out << mat(item.params);\n            out << \"</act>\\n\";\n        }\n\n    private:\n        void allocate_workspace() {\n            const long total_positions = batch_size_ * seq_len_;\n\n            // Allocate state tensors for maximum expected size\n            // These track the ACT state for each position (batch, sequence)\n            halting_probs_.set_size(total_positions, 1, 1, 1);      // p_t^n\n            cumulative_halting_.set_size(total_positions, 1, 1, 1); // h_t^n\n            remainders_.set_size(total_positions, 1, 1, 1);         // rho_t\n            n_steps_.set_size(total_positions, 1, 1, 1);            // N(t)\n            logits_.set_size(total_positions, 1, 1, 1);             // logits before sigmoid\n            grad_logits_.set_size(total_positions, 1, 1, 1);        // gradient w.r.t. logits\n            true_effective_weights_.set_size(total_positions, 1, 1, 1);\n\n            // Input cache needs full dimensions for gradient computation\n            input_cache_.set_size(batch_size_, num_channels_, seq_len_, d_model_);\n        }\n\n        bool all_positions_halted(const resizable_tensor& ch) const {\n            const float* cum_halt = ch.host();\n            const long total = batch_size_ * seq_len_;\n\n            for (long i = 0; i < total; ++i) {\n                if (cum_halt[i] < halt_threshold_) return false;\n            }\n            return true;\n        }\n\n        void compute_ponder_stats() {\n            const float* steps = n_steps_.host();\n            const long total = batch_size_ * seq_len_;\n\n            // Compute average number of steps: (1/T) * SUM N(t)\n            float sum_steps = 0;\n            for (long i = 0; i < total; ++i) sum_steps += steps[i];\n            avg_steps_ = sum_steps / total;\n\n            // Normalize ponder cost by maximum possible steps\n            ponder_cost_ = avg_steps_ / max_steps_;\n        }\n\n        // Configuration parameters\n        long max_steps_;                // Maximum computation steps per position\n        float halt_threshold_;          // theta: Halting threshold (typically 0.99)\n        float ponder_penalty_;          // lambda: Ponder cost weight for regularization\n        bool enable_depth_scaling_;     // Enable depth-dependent gradient scaling\n\n        // Dimension tracking\n        long batch_size_;\n        long seq_len_;\n        long d_model_;\n        long num_channels_;\n        long feature_dim_;\n\n        // Learnable parameters\n        resizable_tensor params;\n\n        // Working memory\n        resizable_tensor halting_probs_;        // p_t^n: Halting probabilities\n        resizable_tensor cumulative_halting_;   // h_t^n: Cumulative halting probabilities\n        resizable_tensor remainders_;           // rho_t: Remaining probability mass\n        resizable_tensor n_steps_;              // N(t): Number of steps taken\n        resizable_tensor logits_;               // Raw logits before sigmoid\n        resizable_tensor grad_logits_;          // Gradients w.r.t. logits\n        resizable_tensor input_cache_;          // Cached input for backward pass\n        resizable_tensor true_effective_weights_;\n\n        // Statistics for monitoring\n        float ponder_cost_;      // R(x): Current ponder cost\n        float avg_steps_;        // Average number of computation steps\n    };\n\n    template <long max_steps, typename SUBNET>\n    using adaptive_computation_time = add_layer<adaptive_computation_time_<max_steps>, SUBNET>;\n\n    template <typename SUBNET>\n    using act = add_layer<adaptive_computation_time_<8>, SUBNET>;       // Default 8 steps\n\n    template <typename SUBNET>\n    using act4 = add_layer<adaptive_computation_time_<4>, SUBNET>;      // Fast version\n\n    template <typename SUBNET>\n    using act16 = add_layer<adaptive_computation_time_<16>, SUBNET>;    // Deep version\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_LAYERS_H_\n"
  },
  {
    "path": "dlib/dnn/layers_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_LAYERS_ABSTRACT_H_\n#ifdef DLIB_DNn_LAYERS_ABSTRACT_H_\n\n#include \"../cuda/tensor_abstract.h\"\n#include \"core_abstract.h\"\n#include \"../cuda/operation_mode.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class SUBNET \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a deep neural network.  In particular, it is\n                the simplified interface through which layer objects interact with their\n                subnetworks.  A layer's two important tasks are to (1) take outputs from its\n                subnetwork and forward propagate them through itself and (2) to backwards\n                propagate an error gradient through itself and onto its subnetwork.\n                The idea of a subnetwork is illustrated in the following diagram:\n\n                  +---------------------------------------------------------+\n                  | loss <-- layer1 <-- layer2 <-- ... <-- layern <-- input |\n                  +---------------------------------------------------------+\n                                      ^                            ^\n                                      \\__ subnetwork for layer1 __/\n\n                Therefore, by \"subnetwork\" we mean the part of the network closer to the\n                input.\n\n                Note that there is no dlib::SUBNET type.  It is shown here purely to\n                document the interface layer objects expect to see when they interact\n                with a network.\n        !*/\n\n    public:\n        // You aren't allowed to copy subnetworks from inside a layer.\n        SUBNET(const SUBNET&) = delete;\n        SUBNET& operator=(const SUBNET&) = delete;\n\n        const tensor& get_output(\n        ) const;\n        /*!\n            ensures\n                - returns the output of this subnetwork.  This is the data that the next\n                  layer in the network will take as input.\n                - have_same_dimensions(#get_gradient_input(), get_output()) == true\n        !*/\n\n        tensor& get_gradient_input(\n        );\n        /*!\n            ensures\n                - returns the error gradient for this subnetwork.  That is, this is the\n                  error gradient that this network will use to update itself.  Therefore,\n                  when performing back propagation, layers that sit on top of this\n                  subnetwork write their back propagated error gradients into\n                  get_gradient_input().  Or to put it another way, during back propagation,\n                  layers take the contents of their get_gradient_input() and back propagate\n                  it through themselves and store the results into their subnetwork's\n                  get_gradient_input().\n        !*/\n\n        const NEXT_SUBNET& subnet(\n        ) const;\n        /*!\n            ensures\n                - returns the subnetwork of *this network.  With respect to the diagram\n                  above, if *this was layer1 then subnet() would return the network that\n                  begins with layer2.\n        !*/\n\n        NEXT_SUBNET& subnet(\n        );\n        /*!\n            ensures\n                - returns the subnetwork of *this network.  With respect to the diagram\n                  above, if *this was layer1 then subnet() would return the network that\n                  begins with layer2.\n        !*/\n\n        const INPUT_LAYER& input_layer(\n        ) const;\n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        INPUT_LAYER& input_layer(\n        );\n        /*!\n            ensures\n                - returns the very first layer in *this network.  It's equivalent to calling\n                  subnet() recursively until you get to the first layer.  This means it will return\n                  the object that is an implementation of the EXAMPLE_INPUT_LAYER interface defined\n                  in input_abstract.h\n        !*/\n\n        const layer_details_type& layer_details(\n        ) const; \n        /*!\n            ensures\n                - returns the layer_details_type instance that defines the behavior of the\n                  layer at the top of this network.  I.e. returns the layer details that\n                  defines the behavior of the layer nearest to the network output rather\n                  than the input layer.  For computational layers, this is the object\n                  implementing the EXAMPLE_COMPUTATIONAL_LAYER_ interface that defines the\n                  layer's behavior.\n        !*/\n\n        unsigned int sample_expansion_factor (\n        ) const;\n        /*!\n            ensures\n                - When to_tensor() is invoked on this network's input layer it converts N\n                  input objects into M samples, all stored inside a resizable_tensor.  It\n                  is always the case that M is some integer multiple of N.\n                  sample_expansion_factor() returns the value of this multiplier.  To be\n                  very specific, it is always true that M==I*N where I is some integer.\n                  This integer I is what is returned by sample_expansion_factor().\n\n                  It should be noted that computational layers likely do not care about the\n                  sample expansion factor.  It is only really of concern inside a loss\n                  layer where you need to know its value so that tensor samples can be\n                  matched against truth objects.  Moreover, in most cases the sample\n                  expansion factor is 1.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class EXAMPLE_COMPUTATIONAL_LAYER_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                Each computational layer in a deep neural network can be thought of as a\n                function, f(data,parameters), that takes in a data tensor, some parameters,\n                and produces an output tensor.  You create an entire deep network by\n                composing these functions.  Importantly, you are able to use a wide range\n                of different functions to accommodate the task you are trying to\n                accomplish.  Therefore, dlib includes a number of common layer types but if\n                you want to define your own then you simply implement a class with the same\n                interface as EXAMPLE_COMPUTATIONAL_LAYER_.\n\n                Note that there is no dlib::EXAMPLE_COMPUTATIONAL_LAYER_ type.  It is shown\n                here purely to document the interface that a layer object must implement.\n\n                The central work of defining a layer is implementing the forward and backward\n                methods.  When you do this you have four options:\n                    - Implement the forward() and backward() methods according to the\n                      specification shown below.  Do not implement forward_inplace() and\n                      backward_inplace().\n                    - Implement the forward() and backward() methods according to the\n                      specification shown below, except exclude the computed_output\n                      parameter from backward().  Doing this will allow dlib to make some\n                      layers execute in-place and therefore run a little faster and use\n                      less memory. Do not implement forward_inplace() and\n                      backward_inplace().\n                    - Implement the forward_inplace() and backward_inplace() methods\n                      according to the specification shown below.  Do not implement\n                      forward() and backward().  These in-place methods allow some types of\n                      layers to be implemented more efficiently.\n                    - Implement the forward_inplace() and backward_inplace() methods\n                      according to the specification shown below, except exclude the\n                      computed_output parameter from backward_inplace().  Doing this will\n                      allow dlib to make some layers execute in-place and therefore run a\n                      little faster and use less memory.  Do not implement forward() and\n                      backward().\n\n\n                It should also be noted that layers may define additional layer specific\n                fields and the solvers can use these fields as they see fit.  For example,\n                some layers define get_learning_rate_multiplier() and\n                get_weight_decay_multiplier() methods.  The solvers that come with dlib\n                look at these methods, if they exist, and adjust the learning rate or\n                weight decay for that layer according to the multiplier.  Therefore, you\n                can add these methods to your layer types if you want, or even define new\n                fields and new solvers that use those fields in some way.  \n        !*/\n\n    public:\n\n        EXAMPLE_COMPUTATIONAL_LAYER_(\n        );\n        /*!\n            ensures\n                - Default constructs this object.  This function is not required to do\n                  anything in particular but it must exist, that is, it is required that\n                  layer objects be default constructable. \n        !*/\n\n        EXAMPLE_COMPUTATIONAL_LAYER_ (\n            const EXAMPLE_COMPUTATIONAL_LAYER_& item\n        );\n        /*!\n            ensures\n                - EXAMPLE_COMPUTATIONAL_LAYER_ objects are copy constructable\n        !*/\n\n        EXAMPLE_COMPUTATIONAL_LAYER_(\n            const some_other_layer_type& item\n        );\n        /*!\n            ensures\n                - Constructs this object from item.  This form of constructor is optional\n                  but it allows you to provide a conversion from one layer type to another.\n                  For example, the following code is valid only if my_layer2 can be\n                  constructed from my_layer1:\n                    relu<fc<my_layer1<fc<input<matrix<float>>>>>> my_dnn1;\n                    relu<fc<my_layer2<fc<input<matrix<float>>>>>> my_dnn2(my_dnn1);\n                  This kind of pattern is useful if you want to use one type of layer\n                  during training but a different type of layer during testing since it\n                  allows you to easily convert between related deep neural network types.  \n\n                  Additionally, if you provide a constructor to build a layer from another\n                  layer type you should also write your layer's deserialize() routine such\n                  that it can read that other layer's serialized data in addition to your\n                  own serialized data.  \n        !*/\n\n        template <typename SUBNET>\n        void setup (\n            const SUBNET& sub\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n            ensures\n                - performs any necessary initial memory allocations and/or sets parameters\n                  to their initial values prior to learning.  Therefore, calling setup\n                  destroys any previously learned parameters.  Also, typically setup()\n                  would look at the dimensions of the outputs of sub and configure the\n                  number of parameters in *this accordingly.\n        !*/\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub, \n            resizable_tensor& data_output\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n            ensures\n                - Runs the output of the subnetwork through this layer and stores the\n                  results into #data_output.  In particular, forward() can use any of the\n                  outputs in sub (e.g. sub.get_output(), sub.subnet().get_output(), etc.)\n                  to compute whatever it wants.\n        !*/\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& computed_output, // this parameter is optional\n            const tensor& gradient_input, \n            SUBNET& sub, \n            tensor& params_grad\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n                - computed_output is the tensor resulting from calling forward(sub,computed_output).  \n                  Moreover, this was the most recent call to forward().  This means that\n                  forward() is allowed to cache intermediate results so they can be used\n                  during the backward computation.\n                - have_same_dimensions(gradient_input, computed_output) == true\n                - have_same_dimensions(sub.get_gradient_input(), sub.get_output()) == true\n                - have_same_dimensions(params_grad, get_layer_params()) == true\n            ensures\n                - This function outputs the gradients of this layer with respect to the\n                  input data from sub and also with respect to this layer's parameters.\n                  These gradients are stored into #sub and #params_grad, respectively. To be\n                  precise, the gradients are taken of a function f(sub,get_layer_params())\n                  which is defined thusly:   \n                    - Recalling that computed_output is a function of both sub and get_layer_params(), \n                      since it is the result of calling forward(sub,computed_output):\n                      let f(sub,get_layer_params()) == dot(computed_output, gradient_input)\n                  Then we define the following gradient vectors: \n                    - PARAMETER_GRADIENT == gradient of f(sub,get_layer_params()) with\n                      respect to get_layer_params(). \n                    - for all valid I:\n                        - DATA_GRADIENT_I == gradient of f(sub,get_layer_params()) with\n                          respect to layer<I>(sub).get_output() (recall that forward() can\n                          draw inputs from the immediate sub layer, sub.subnet(), or\n                          any earlier layer.  So you must consider the gradients with\n                          respect to all inputs drawn from sub)\n                  Finally, backward() outputs these gradients by performing:\n                    - params_grad = PARAMETER_GRADIENT \n                    - for all valid I:\n                        - layer<I>(sub).get_gradient_input() += DATA_GRADIENT_I\n        !*/\n\n        void forward_inplace(\n            const tensor& data_input, \n            tensor& data_output\n        );\n        /*!\n            requires\n                - have_same_dimensions(data_input,data_output) == true\n                - setup() has been called.\n            ensures\n                - Runs the data_input tensor through this layer and stores the output into\n                  #data_output.\n                - This function supports in-place operation, i.e. having\n                  is_same_object(data_input, data_output)==true\n        !*/\n\n        void backward_inplace(\n            const tensor& computed_output, // this parameter is optional\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor& params_grad\n        );\n        /*!\n            requires\n                - setup() has been called.\n                - computed_output is the tensor resulting from the most recent call to\n                  forward_inplace().  This means that forward_inplace() is allowed to cache\n                  intermediate results so they can be used during the backward computation.\n                - have_same_dimensions(gradient_input, data_grad) == true\n                - have_same_dimensions(gradient_input, computed_output) == true\n                - have_same_dimensions(params_grad, get_layer_params()) == true\n            ensures\n                - This function supports in-place operation, i.e. having\n                  is_same_object(gradient_input, data_grad)==true\n                - This function outputs the gradients of this layer with respect to the\n                  input data from a sublayer and also with respect to this layer's parameters.\n                  These gradients are stored into #data_grad and #params_grad, respectively. To be\n                  precise, the gradients are taken of a function f(data_input,get_layer_params())\n                  which is defined thusly:   \n                    - Recalling that computed_output is a function of both the input to\n                      forward_inplace() and get_layer_params(), since it is the result of\n                      calling forward_inplace(data_input,computed_output):\n                      let f(data_input,get_layer_params()) == dot(computed_output, gradient_input)\n                  Then we define the following gradient vectors: \n                    - PARAMETER_GRADIENT == gradient of f(data_input,get_layer_params()) with\n                      respect to get_layer_params(). \n                    - DATA_GRADIENT == gradient of f(data_input,get_layer_params()) with respect\n                      to data_input. \n                  Finally, backward_inplace() outputs these gradients by performing:\n                    - params_grad = PARAMETER_GRADIENT \n                    - if (is_same_object(gradient_input, data_grad)) then\n                        - data_grad = DATA_GRADIENT\n                    - else\n                        - data_grad += DATA_GRADIENT\n        !*/\n\n        const tensor& get_layer_params(\n        ) const; \n        /*!\n            ensures\n                - returns the parameters that define the behavior of forward().\n        !*/\n\n        tensor& get_layer_params(\n        ); \n        /*!\n            ensures\n                - returns the parameters that define the behavior of forward().\n        !*/\n\n\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        /*!\n            These two functions are optional.  If provided, they should map between\n            (column,row) coordinates in input and output tensors of forward().  Providing\n            these functions allows you to use global utility functions like\n            input_tensor_to_output_tensor().\n        !*/\n\n        void clean (\n        );\n        /*!\n            Implementing this function is optional.  If you don't need it then you don't\n            have to provide a clean().  But if you do provide it then it must behave as\n            follows:\n\n            ensures\n                - calling clean() causes this object to forget about everything except its\n                  parameters.  This is useful if your layer caches information between\n                  forward and backward passes and you want to clean out that cache\n                  information before saving the network to disk.  \n        !*/\n\n    };\n\n    std::ostream& operator<<(std::ostream& out, const EXAMPLE_COMPUTATIONAL_LAYER_& item);\n    /*!\n        print a string describing this layer.\n    !*/\n\n    void to_xml(const EXAMPLE_COMPUTATIONAL_LAYER_& item, std::ostream& out);\n    /*!\n        This function is optional, but required if you want to print your networks with\n        net_to_xml().  Therefore, to_xml() prints a layer as XML.\n    !*/\n\n    void serialize(const EXAMPLE_COMPUTATIONAL_LAYER_& item, std::ostream& out);\n    void deserialize(EXAMPLE_COMPUTATIONAL_LAYER_& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    // For each layer you define, always define an add_layer template so that layers can be\n    // easily composed.  Moreover, the convention is that the layer class ends with an _\n    // while the add_layer template has the same name but without the trailing _.\n    template <typename SUBNET>\n    using EXAMPLE_COMPUTATIONAL_LAYER = add_layer<EXAMPLE_COMPUTATIONAL_LAYER_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum fc_bias_mode\n    {\n        FC_HAS_BIAS = 0,\n        FC_NO_BIAS = 1\n    };\n\n    struct num_fc_outputs\n    {\n        num_fc_outputs(unsigned long n) : num_outputs(n) {}\n        unsigned long num_outputs;\n    };\n\n    template <\n        unsigned long num_outputs,\n        fc_bias_mode bias_mode\n        >\n    class fc_\n    {\n        /*!\n            REQUIREMENTS ON num_outputs\n                num_outputs > 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a fully connected layer that\n                takes an input tensor and multiplies it by a weight matrix and outputs the\n                results.\n\n                The dimensions of the tensors output by this layer are as follows (letting\n                IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == get_num_outputs()\n                    - OUT.nr() == 1\n                    - OUT.nc() == 1\n        !*/\n\n    public:\n\n        fc_(\n        );\n        /*!\n            ensures\n                - #get_num_outputs() == num_outputs\n                - #get_bias_mode() == bias_mode \n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        fc_(\n            num_fc_outputs o\n        );\n        /*!\n            ensures\n                - #get_num_outputs() == o.num_outputs \n                - #get_bias_mode() == bias_mode \n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        unsigned long get_num_outputs (\n        ) const; \n        /*!\n            ensures\n                - This layer outputs column vectors that contain get_num_outputs()\n                  elements. That is, the output tensor T from forward() will be such that:\n                    - T.num_samples() == however many samples were given to forward().\n                    - T.k() == get_num_outputs()\n                    - The rest of the dimensions of T will be 1.\n        !*/\n\n        void set_num_outputs(\n            long num\n        );\n        /*!\n            requires\n                - num > 0\n                - get_layer_params().size() == 0 || get_num_outputs() == num\n                  (i.e. You can't change the number of outputs in fc_ if the parameter\n                  tensor has already been allocated.)\n            ensures\n                - #get_num_outputs() == num\n        !*/\n\n        fc_bias_mode get_bias_mode (\n        ) const;\n        /*!\n            ensures\n                - returns the bias mode which determines if this layer includes bias terms.\n                  That is, if the bias mode is FC_HAS_BIAS then a different constant scalar\n                  is added to each of the outputs of this layer. \n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;  \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its parameters be\n                  multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its parameters be\n                  multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its bias parameters be\n                  multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its bias parameters be\n                  multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        void disable_bias(\n        );\n        /*!\n            ensures\n                - bias_is_disabled() returns true\n        !*/\n\n        bool bias_is_disabled(\n        ) const;\n        /*!\n            ensures\n                - returns true if bias learning is disabled for this layer.  This means the biases will\n                  not be learned during the training and they will not be used in the forward or backward\n                  methods either.\n        !*/\n\n        alias_tensor_const_instance get_weights(\n        ) const;\n        /*!\n            ensures\n                - returns an alias of get_layer_params(), containing the weights matrix of\n                  the fully connected layer.\n                - #get_weights().num_samples() is the number of elements in input sample,\n                  i.e. sublayer's output's k * nc * nr.\n                - #get_bias().k() == #get_num_outputs()\n                - if get_bias_mode() == FC_HAS_BIAS:\n                    - #get_layer_params().size() == (#get_weights().size() + #get_biases().size())\n                - else:\n                    - #get_layer_params().size() == #get_weights().size()\n        !*/\n\n        alias_tensor_instance get_weights(\n        );\n        /*!\n            ensures\n                - returns an alias of get_layer_params(), containing the weights matrix of\n                  the fully connected layer.\n                - #get_weights().num_samples() is the number of elements in input sample,\n                  i.e. sublayer's output's k * nc * nr.\n                - #get_bias().k() == #get_num_outputs()\n                - if get_bias_mode() == FC_HAS_BIAS:\n                    - #get_layer_params().size() == (#get_weights().size() + #get_biases().size())\n                - else:\n                    - #get_layer_params().size() == #get_weights().size()\n        !*/\n\n        alias_tensor_const_instance get_biases(\n        ) const;\n        /*!\n            requires\n                - #get_bias_mode() == FC_HAS_BIAS\n            ensures\n                - returns an alias of get_layer_params(), containing the bias vector of\n                  the fully connected layer.\n                - #get_bias().num_samples() == 1\n                - #get_bias().k() == #get_num_outputs()\n                - #get_layer_params().size() == (#get_weights().size() + #get_biases().size())\n        !*/\n\n        alias_tensor_instance get_biases(\n        );\n        /*!\n            requires\n                - #get_bias_mode() == FC_HAS_BIAS\n            ensures\n                - returns an alias of get_layer_params(), containing the bias vector of\n                  the fully connected layer.\n                - #get_bias().num_samples() == 1\n                - #get_bias().k() == #get_num_outputs()\n                - #get_layer_params().size() == (#get_weights().size() + #get_biases().size())\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n\n    };\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n        >\n    using fc = add_layer<fc_<num_outputs,FC_HAS_BIAS>, SUBNET>;\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n        >\n    using fc_no_bias = add_layer<fc_<num_outputs,FC_NO_BIAS>, SUBNET>;\n\n    // ----------------------------------------------------------------------------------------\n\n// ----------------------------------------------------------------------------------------\n\n    enum linear_bias_mode\n    {\n        LINEAR_HAS_BIAS,\n        LINEAR_NO_BIAS\n    };\n\n    template <\n        unsigned long num_outputs,\n        linear_bias_mode bias_mode = LINEAR_HAS_BIAS\n    >\n    class linear_\n    {\n        /*!\n            REQUIREMENTS ON num_outputs\n                num_outputs > 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of a linear layer, which applies a linear\n                transformation to the input data. For a layer with bias, the transformation\n                is:\n                    output = input * weights + bias\n                For a layer without bias, it's simply:\n                    output = input * weights\n\n                The input tensor can have any number of sample, k (channel), and nr (row)\n                dimensions, but the nc (column) dimension must match the number of input features.\n                The output tensor will have the same dimensions as the input tensor, except for\n                the nc dimension which will be equal to num_outputs.\n\n                This layer is similar to the fc_ layer, but optimized for the case where the\n                input and output tensors maintain the same dimensions, excluding the feature\n                dimension (nc). This makes it useful for working with multi-dimensional data.\n        !*/\n\n    public:\n        linear_(\n        );\n        /*!\n            ensures\n                - #get_num_outputs() == num_outputs\n                - #get_bias_mode() == bias_mode\n                - #get_learning_rate_multiplier() == 1\n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier that will be applied to the gradient of this layer during\n                  training. This value appears as a multiplicative factor in the update rule. So\n                  if get_learning_rate_multiplier() == 1 then the learning rate will be multiplied\n                  by 1 and thus not modified. However, if get_learning_rate_multiplier() == 0.1 then\n                  the learning rate will be multiplied by 0.1, making the layer update 10 times\n                  slower than it would otherwise be.\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        unsigned long get_num_inputs(\n        ) const;\n        /*!\n            ensures\n                - Returns the number of input features this layer expects.\n                - For an uninitialized layer (i.e., one that has not seen any data during setup\n                  or forward pass), this will be zero.\n        !*/\n\n        unsigned long get_num_outputs(\n        ) const;\n        /*!\n            ensures\n                - Returns the number of output features this layer produces.\n                  I.e., this value is num_outputs.\n        !*/\n\n        void set_num_outputs(\n            long num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_num_outputs() == num\n            throws\n                - std::runtime_error if this function is called after the layer parameters\n                  have been allocated and the new number of outputs doesn't match the\n                  previously set number of outputs.\n        !*/\n\n        linear_bias_mode get_bias_mode(\n        ) const;\n        /*!\n            ensures\n                - Returns a value indicating whether this layer has a bias term.\n                  I.e. returns bias_mode.\n        !*/\n\n        template <typename SUBNET>\n        void setup(\n            const SUBNET& sub\n        );\n        /*!\n            ensures\n                - Performs the necessary setup work to process data through this layer.\n                - Sets the input size based on the dimensions of the input tensor from sub.\n                - Allocates the parameter tensor and initializes its values.\n                - #get_num_inputs() == the number of columns in sub.get_output() (i.e., nc).\n        !*/\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub,\n            resizable_tensor& output\n        );\n        /*!\n            requires\n                - setup() has been called\n                - sub.get_output().nc() == get_num_inputs()\n            ensures\n                - Applies the linear transformation to the input tensor from sub and stores\n                  the results in output.\n                - #output.num_samples() == sub.get_output().num_samples()\n                - #output.k()           == sub.get_output().k()\n                - #output.nr()          == sub.get_output().nr()\n                - #output.nc()          == get_num_outputs()\n        !*/\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor& params_grad\n        );\n        /*!\n            requires\n                - setup() has been called\n                - sub.get_output().nc() == get_num_inputs()\n                - gradient_input has the same dimensions as the output of forward()\n            ensures\n                - Computes the gradients of this layer with respect to the parameters\n                  and the input tensor, and updates the corresponding gradient tensors.\n                - Updates params_grad based on the gradients of the weights\n                  and biases (if present).\n                - Updates sub's gradient_input based on the gradients of the\n                  inputs to this layer.\n        !*/\n\n        alias_tensor_instance get_weights(\n        );\n        /*!\n            requires\n                - setup() has been called\n            ensures\n                - Returns a reference to the weights matrix of this layer.\n        !*/\n\n        alias_tensor_const_instance get_weights(\n        ) const;\n        /*!\n            requires\n                - setup() has been called\n            ensures\n                - Returns a const reference to the weights matrix of this layer.\n        !*/\n\n        alias_tensor_instance get_biases(\n        );\n        /*!\n            requires\n                - bias_mode == LINEAR_HAS_BIAS\n                - setup() has been called\n            ensures\n                - Returns a reference to the bias vector of this layer.\n            throws\n                - static_assert failure if bias_mode != LINEAR_HAS_BIAS\n        !*/\n\n        alias_tensor_const_instance get_biases(\n        ) const;\n        /*!\n            requires\n                - bias_mode == LINEAR_HAS_BIAS\n                - setup() has been called\n            ensures\n                - Returns a const reference to the bias vector of this layer.\n            throws\n                - static_assert failure if bias_mode != LINEAR_HAS_BIAS\n        !*/\n\n        dpoint map_input_to_output(\n            const dpoint& p\n        ) const;\n        /*!\n            ensures\n                - Returns p, since the linear layer maintains the same spatial dimensions.\n        !*/\n\n        dpoint map_output_to_input(\n            const dpoint& p\n        ) const;\n        /*!\n            ensures\n                - Returns p, since the linear layer maintains the same spatial dimensions.\n        !*/\n\n        const tensor& get_layer_params(\n        ) const;\n        /*!\n            ensures\n                - Returns the parameters that define this layer, i.e., the weights and biases\n                  (if present) that are updated during training.\n        !*/\n\n        tensor& get_layer_params(\n        );\n        /*!\n            ensures\n                - Returns the parameters that define this layer, i.e., the weights and biases\n                  (if present) that are updated during training.\n        !*/\n\n        friend void serialize(const linear_& item, std::ostream& out);\n        friend void deserialize(linear_& item, std::istream& in);\n        /*!\n            provides serialization support\n        !*/\n    };\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n    >\n    using linear = add_layer<linear_<num_outputs, LINEAR_HAS_BIAS>, SUBNET>;\n    /*!\n        This is a layer that applies a linear transformation with bias to the input:\n        output = input * weights + bias\n    !*/\n\n    template <\n        unsigned long num_outputs,\n        typename SUBNET\n    >\n    using linear_no_bias = add_layer<linear_<num_outputs, LINEAR_NO_BIAS>, SUBNET>;\n    /*!\n        This is a layer that applies a linear transformation without bias to the input:\n        output = input * weights\n    !*/\n\n    // ----------------------------------------------------------------------------------------\n\n// ----------------------------------------------------------------------------------------\n\n    struct num_con_outputs\n    {\n        num_con_outputs(unsigned long n) : num_outputs(n) {}\n        unsigned long num_outputs;\n    };\n\n    template <\n        long _num_filters,\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class con_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - _num_filters > 0\n                - _nr >= 0\n                - _nc >= 0\n                - _stride_y > 0\n                - _stride_x > 0\n                - _padding_y >= 0\n                - _padding_x >= 0\n                - Also, we require that:\n                    - if (_nr == 0) then\n                        - _padding_y == 0\n                    - else\n                        - _padding_y < _nr\n                    - if (_nc == 0) then\n                        - _padding_x == 0\n                    - else\n                        - _padding_x < _nc\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a convolution layer that takes an\n                input tensor (nominally representing an image) and convolves it with a set\n                of filters and then outputs the results. \n\n                The dimensions of the tensors output by this layer are as follows (letting\n                IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == num_filters()\n                    - OUT.nr() == 1+(IN.nr() + 2*padding_y() - nr())/stride_y()\n                    - OUT.nc() == 1+(IN.nc() + 2*padding_x() - nc())/stride_x()\n\n                Note also that setting _nr or _nc to 0 has a special meaning of \"set the\n                filter size equal to the input image size\".  Specifically, it means: \n                    - if (_nr == 0) then\n                        - nr() == IN.nr()\n                        - OUT.nr() == 1\n                    - if (_nc == 0) then\n                        - nc() == IN.nc()\n                        - OUT.nc() == 1\n        !*/\n\n    public:\n        con_(\n        );\n        /*!\n            ensures\n                - #num_filters() == _num_filters\n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        con_(\n            num_con_outputs o\n        );\n        /*!\n            ensures\n                - #num_filters() == o.num_outputs \n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        long num_filters(\n        ) const; \n        /*!\n            ensures\n                - returns the number of filters contained in this layer.  The k dimension\n                  of the output tensors produced by this layer will be equal to the number\n                  of filters.\n        !*/\n\n        void set_num_filters(\n            long num\n        );\n        /*!\n            requires\n                - num > 0\n                - get_layer_params().size() == 0 || num_filters() == num\n                  (i.e. You can't change the number of filters in con_ if the parameter\n                  tensor has already been allocated.)\n            ensures\n                - #num_filters() == num\n        !*/\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in the filters in this layer.  Note that if\n                  nr()==0 then it means the size of the filter is not yet assigned, but\n                  once setup() is called nr() will be set to the input tensor's nr().\n                  Therefore, nr()==0 has the special interpretation of \"be the same size as\n                  the input tensor\".\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in the filters in this layer.  Note that if\n                  nc()==0 then it means the size of the filter is not yet assigned, but\n                  once setup() is called nc() will be set to the input tensor's nc().\n                  Therefore, nc()==0 has the special interpretation of \"be the same size as\n                  the input tensor\".\n        !*/\n\n        long stride_y(\n        ) const; \n        /*!\n            ensures\n                - returns the vertical stride used when convolving the filters over an\n                  image.  That is, each filter will be moved stride_y() pixels down at a\n                  time when it moves over the image.\n        !*/\n\n        long stride_x(\n        ) const;\n        /*!\n            ensures\n                - returns the horizontal stride used when convolving the filters over an\n                  image.  That is, each filter will be moved stride_x() pixels right at a\n                  time when it moves over the image.\n        !*/\n\n        long padding_y(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the top and bottom\n                  sides of the image.\n        !*/\n\n        long padding_x(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the left and right \n                  sides of the image.\n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;  \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its parameters be\n                  multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its parameters be\n                  multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its bias parameters be\n                  multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its bias parameters be\n                  multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        void disable_relu(\n        );\n        /*!\n            ensures\n                - relu_is_disabled() returns true\n        !*/\n\n        void enable_relu(\n        );\n        /*!\n            ensures\n                - relu_is_disabled() returns false\n        !*/\n\n        bool relu_is_disabled(\n        ) const;\n        /*!\n            ensures\n                - returns true if relu is disabled for this layer. This means no activation function\n                  will be applied after the convolution when calling forward.\n        !*/\n\n        void disable_bias(\n        );\n        /*!\n            ensures\n                - bias_is_disabled() returns true\n                - if bias was enabled and allocated, it resizes the layer parameters\n                  to accommodate the filter parameters only, and free the bias parameters.\n        !*/\n\n        void enable_bias(\n        );\n        /*!\n            ensures\n                - bias_is_disabled() returns false\n                - if bias was disabled and not allocated, it resizes the layer parameters\n                  to accommodate the new zero-inizialized biases\n        !*/\n\n        bool bias_is_disabled(\n        ) const;\n        /*!\n            ensures\n                - returns true if bias learning is disabled for this layer.  This means the biases will\n                  not be learned during the training and they will not be used in the forward or backward\n                  methods either.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n\n    };\n\n    template <\n        long num_filters,\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using con = add_layer<con_<num_filters,nr,nc,stride_y,stride_x>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _num_filters,\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class cont_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                All of them must be > 0.\n                Also, we require that:\n                    - 0 <= _padding_y && _padding_y < _nr\n                    - 0 <= _padding_x && _padding_x < _nc\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a transposed convolution layer\n                that takes an input tensor and transpose convolves (sometimes called\n                \"deconvolution\") it with a set of filters and then outputs the results. \n\n                This is essentially a convolutional layer that allows fractional strides.\n                Therefore, you can make output tensors that are larger than the input\n                tensors using this layer type. \n\n                \n                The dimensions of the tensors output by this layer are as follows (letting\n                IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == num_filters()\n                    - OUT.nr() == stride_y()*(IN.nr()-1) + nr() - 2*padding_y()\n                    - OUT.nc() == stride_x()*(IN.nc()-1) + nc() - 2*padding_x()\n        !*/\n\n    public:\n        cont_(\n        );\n        /*!\n            ensures\n                - #num_filters() == _num_filters\n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        cont_(\n            num_con_outputs o\n        );\n        /*!\n            ensures\n                - #num_filters() == o.num_outputs \n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 1\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 0\n        !*/\n\n        long num_filters(\n        ) const; \n        /*!\n            ensures\n                - returns the number of filters contained in this layer.  The k dimension\n                  of the output tensors produced by this layer will be equal to the number\n                  of filters.\n        !*/\n\n        void set_num_filters(\n            long num\n        );\n        /*!\n            requires\n                - num > 0\n                - get_layer_params().size() == 0 || num_filters() == num\n                  (i.e. You can't change the number of filters in cont_ if the parameter\n                  tensor has already been allocated.)\n            ensures\n                - #num_filters() == num\n        !*/\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in the filters in this layer.\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in the filters in this layer.\n        !*/\n\n        long stride_y(\n        ) const; \n        /*!\n            ensures\n                - returns the vertical stride used when convolving the filters over an\n                  image.  That is, each filter will be moved 1.0/stride_y() pixels down at\n                  a time when it moves over the image.\n        !*/\n\n        long stride_x(\n        ) const;\n        /*!\n            ensures\n                - returns the horizontal stride used when convolving the filters over an\n                  image.  That is, each filter will be moved 1.0/stride_x() pixels right at\n                  a time when it moves over the image.\n        !*/\n\n        long padding_y(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the top and bottom\n                  sides of the image.\n        !*/\n\n        long padding_x(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the left and right \n                  sides of the image.\n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;  \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its parameters be\n                  multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its parameters be\n                  multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its bias parameters be\n                  multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its bias parameters be\n                  multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        void disable_bias(\n        );\n        /*!\n            ensures\n                - bias_is_disabled() returns true\n        !*/\n\n        bool bias_is_disabled(\n        ) const;\n        /*!\n            ensures\n                - returns true if bias learning is disabled for this layer.  This means the biases will\n                  not be learned during the training and they will not be used in the forward or backward\n                  methods either.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n\n    };\n\n    template <\n        long num_filters,\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using cont = add_layer<cont_<num_filters,nr,nc,stride_y,stride_x>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        int scale_y, \n        int scale_x \n        >\n    class upsample_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                All of them must be >= 1.\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it allows you to upsample a layer using\n                bilinear interpolation.  To be very specific, it upsamples each of the\n                channels in an input tensor.  Therefore, if IN is the input tensor to this\n                layer and OUT the output tensor, then we will have:\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k() \n                    - OUT.nr() == IN.nr()*scale_y\n                    - OUT.nc() == IN.nc()*scale_x\n                    - for all valid i,k:  image_plane(OUT,i,k) is a copy of\n                      image_plane(IN,i,k) that has been bilinearly interpolated to fit into\n                      the shape of image_plane(OUT,i,k).\n        !*/\n    public:\n\n        upsample_(\n        );\n        /*!\n            ensures\n                - This object has no state, so the constructor does nothing, aside from\n                  providing default constructability.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        int scale,\n        typename SUBNET\n        >\n    using upsample = add_layer<upsample_<scale,scale>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR_, \n        long NC_\n        >\n    class resize_to_\n    {\n        /*!\n            REQUIREMENTS ON THE INPUT ARGUMENTS\n                - NR_ >= 1\n                - NC_ >= 1\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it allows you to resize a layer using\n                bilinear interpolation.  To be very specific, it resizes each of the\n                channels in an input tensor.  Therefore, if IN is the input tensor to this\n                layer and OUT the output tensor, then we will have:\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k() \n                    - OUT.nr() == NR_\n                    - OUT.nc() == NC_\n                    - for all valid i,k:  image_plane(OUT,i,k) is a copy of\n                      image_plane(IN,i,k) that has been bilinearly interpolated to fit into\n                      the shape of image_plane(OUT,i,k).\n        !*/\n    public:\n\n        resize_to_(\n        );\n        /*!\n            ensures\n                - This object has no state, so the constructor does nothing, aside from\n                  providing default constructability.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        long NR,\n        long NC,\n        typename SUBNET\n        >\n    using resize_to = add_layer<resize_to_<NR,NC>, SUBNET>;\n    \n// ----------------------------------------------------------------------------------------\n\n    template <long k_ = -1, long nr_ = -1, long nc_ = -1>\n    class reshape_to_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - k_, nr_, and nc_ must be either -1 or greater than 0.\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above. It defines a layer that reshapes or resizes an input tensor\n                into a different shape. The layer operates in two modes:\n\n                1. Pure Reshape Mode: When the total number of elements in the input tensor\n                   equals the total number of elements in the output tensor, this layer\n                   performs a simple reshaping operation without changing the values.\n\n                2. Spatial Rescaling Mode: When the channel dimension (k) remains constant\n                   but the total number of elements changes, this layer performs bilinear\n                   interpolation to resize the spatial dimensions while preserving the\n                   channel information.\n\n                The dimensions of the output tensor are determined by the template parameters:\n                    - If k_ is -1, the output tensor will have the same number of channels as the input.\n                    - If nr_ is -1, the output tensor will have the same number of rows as the input.\n                    - If nc_ is -1, the output tensor will have the same number of columns as the input.\n\n                Setting a value of -1 for any dimension means \"keep the original dimension from the input.\"\n\n                Note that this layer will throw an exception if you attempt to change both the\n                channel count (k) and the total number of elements. Either:\n                - Keep the total number of elements the same (Pure Reshape Mode), or\n                - Keep the channel count the same and only change spatial dimensions (Spatial Rescaling Mode)\n        !*/\n\n    public:\n        explicit reshape_to_();\n        /*!\n            ensures\n                - #get_output_k() == k_\n                - #get_output_nr() == nr_\n                - #get_output_nc() == nc_\n        !*/\n\n        long get_output_k() const;\n        /*!\n            ensures\n                - Returns the number of channels in the output tensor. If this value is -1,\n                  then the output will have the same number of channels as the input.\n        !*/\n\n        long get_output_nr() const;\n        /*!\n            ensures\n                - Returns the number of rows in the output tensor. If this value is -1,\n                  then the output will have the same number of rows as the input.\n        !*/\n\n        long get_output_nc() const;\n        /*!\n            ensures\n                - Returns the number of columns in the output tensor. If this value is -1,\n                  then the output will have the same number of columns as the input.\n        !*/\n\n        void set_output_k(long k);\n        /*!\n            requires\n                - k == -1 || k > 0\n            ensures\n                - #get_output_k() == k\n        !*/\n\n        void set_output_nr(long nr);\n        /*!\n            requires\n                - nr == -1 || nr > 0\n            ensures\n                - #get_output_nr() == nr\n        !*/\n\n        void set_output_nc(long nc);\n        /*!\n            requires\n                - nc == -1 || nc > 0\n            ensures\n                - #get_output_nc() == nc\n        !*/\n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n            ensures\n                - Configures this layer to operate on the output of sub.\n                - If the total number of elements in the input tensor doesn't match the total\n                  number of elements in the output tensor and the channel dimension is different,\n                  an exception will be thrown.\n        !*/\n\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n            ensures\n                - Reshapes or resizes the output of sub and stores it in #output.\n                - If is_spatial_rescale() == false, then performs a pure reshape operation.\n                - If is_spatial_rescale() == true, then performs bilinear interpolation to resize\n                  the spatial dimensions while preserving the channel information.\n                - #output.num_samples() == sub.get_output().num_samples()\n                - #output.k() == get_output_k() if get_output_k() != -1, otherwise sub.get_output().k()\n                - #output.nr() == get_output_nr() if get_output_nr() != -1, otherwise sub.get_output().nr()\n                - #output.nc() == get_output_nc() if get_output_nc() != -1, otherwise sub.get_output().nc()\n        !*/\n\n        template <typename SUBNET> void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor& params_grad\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n                - gradient_input has the same dimensions as the output of forward().\n            ensures\n                - Computes the gradients of this layer with respect to the input tensor and\n                  parameters, and stores them in sub.get_gradient_input() and params_grad,\n                  respectively.\n                - This function supports both pure reshaping and spatial rescaling operations.\n        !*/\n\n        dpoint map_input_to_output(dpoint p) const;\n        /*!\n            ensures\n                - Maps a point in the input tensor's coordinate system to the corresponding point\n                  in the output tensor. This is useful for tracking how spatial locations change\n                  through the network, especially during spatial rescaling.\n        !*/\n\n        dpoint map_output_to_input(dpoint p) const;\n        /*!\n            ensures\n                - Maps a point in the output tensor's coordinate system to the corresponding point\n                  in the input tensor. This is the inverse of map_input_to_output().\n        !*/\n\n        const tensor& get_layer_params() const;\n        /*!\n            ensures\n                - Returns the layer's parameters. This layer has no parameters,\n                  so this always returns an empty tensor.\n        !*/\n\n        tensor& get_layer_params();\n        /*!\n            ensures\n                - Returns the layer's parameters. This layer has no parameters,\n                  so this always returns an empty tensor.\n        !*/\n    };\n\n    template <long k, long nr, long nc, typename SUBNET>\n    using reshape_to = add_layer<reshape_to_<k, nr, nc>, SUBNET>;\n\n    template <long k, long nr, long nc, typename SUBNET>\n    using flatten = add_layer<reshape_to_<k * nr, * nc, 1, 1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class dropout_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a dropout layer.  Therefore, it\n                passes its inputs through the stochastic function f(x) which outputs either\n                0 or x.  The probability of 0 being output is given by the drop_rate\n                argument to this object's constructor.\n\n                Note that, after you finish training a network with dropout, it is a good\n                idea to replace each dropout_ layer with a multiply_ layer because the\n                multiply_ layer is faster and deterministic. \n        !*/\n\n    public:\n\n        explicit dropout_(\n            float drop_rate = 0.5\n        );\n        /*!\n            requires\n                - 0 <= drop_rate <= 1\n            ensures\n                - #get_drop_rate() == drop_rate\n        !*/\n\n        float get_drop_rate (\n        ) const; \n        /*!\n            ensures\n                - returns the probability that an individual input value to this layer will\n                  be replaced with 0.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using dropout = add_layer<dropout_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <int DROP_RATE_PERCENT>\n    class dropout_rate_ : public dropout_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a customizable dropout layer that inherits from\n                the dropout_ class. It allows specifying the dropout rate at compile-time,\n                which is particularly useful for deep networks with many layers where it\n                might be cumbersome to explicitly modify the dropout rate for each layer\n                individually.\n\n                The main advantage of this layer is that it offers the possibility to specify\n                the dropout rate at the moment of network construction, providing more\n                flexibility and clarity in the network architecture definition.\n\n            TEMPLATE PARAMETERS\n                - DROP_RATE_PERCENT: A int value between 0 and 100 that specifies the dropout rate.\n                  This value is set at compile-time and cannot be changed during runtime.\n        !*/\n\n    public:\n        explicit dropout_rate_();\n        /*!\n            ensures\n                - Constructs a dropout layer with a dropout rate of DROP_RATE.\n                - Calls the base class constructor dropout_(DROP_RATE).\n        !*/\n    };\n\n    template <int DROP_RATE, typename SUBNET>\n    using dropout_rate = add_layer<dropout_rate_<DROP_RATE>, SUBNET>;\n    template <typename SUBNET>\n    using dropout_10 = add_layer<dropout_rate_<10>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class multiply_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a basic layer that just\n                multiplies its input tensor with a constant value and returns the result.\n                It therefore has no learnable parameters.\n        !*/\n\n    public:\n        explicit multiply_(\n            float val = 0.5\n        ); \n        /*!\n            ensures\n                - #get_multiply_value() == val\n        !*/\n\n        multiply_ (\n            const dropout_& item\n        ); \n        /*!\n            ensures\n                - #get_multiply_value() == 1-item.get_drop_rate()\n                  (i.e. We construct the multiply_ layer so that it is essentially a\n                  deterministic version of the given dropout_ layer)\n        !*/\n\n        float get_multiply_value (\n        ) const;\n        /*!\n            ensures\n                - this layer simply multiplies its input tensor by get_multiply_value() and\n                  produces the result as output.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using multiply = add_layer<multiply_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    const double DEFAULT_LAYER_NORM_EPS = 1e-5;\n\n    class layer_norm_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a batch normalization layer that\n                implements the method described in the paper:\n                    Layer Normalization by Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton\n\n                In particular, this layer produces output tensors with the same\n                dimensionality as the input tensors, except that the mean and variances of\n                the elements in each sample have been standardized to 0 and 1 respectively.\n                This is different from batch normalization, since this layer learns one scaling\n                factor and one bias for each sample in the batch, independently.  As a result,\n                this layer is batch-size independent.\n        !*/\n    public:\n        layer_norm_(\n        );\n        /*!\n            ensures\n                - #get_learning_rate_multiplier()       == 1\n                - #get_weight_decay_multiplier()        == 0\n                - #get_bias_learning_rate_multiplier()  == 1\n                - #get_bias_weight_decay_multiplier()   == 1\n                - #get_eps() == DEFAULT_LAYER_NORM_EPS\n        !*/\n\n        explicit layer_norm_(\n            double eps_ = DEFAULT_LAYER_NORM_EPS\n        )\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 0\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 1\n                - #get_eps() == eps\n        !*/\n\n        double get_eps(\n        ) const;\n        /*!\n            ensures\n                - When doing layer normalization, we are dividing by the standard\n                  deviation.  This epsilon value returned by this function is added to the\n                  variance to prevent the division from dividing by zero.\n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its parameters be\n                  multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its parameters be\n                  multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its bias parameters be\n                  multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its bias parameters be\n                  multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const float DEFAULT_RMS_NORM_EPS = 1e-5f;\n\n    class rms_norm_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above, specifically defining a root mean square (RMS) normalization layer.\n\n                RMS normalization is a technique that normalizes the input tensor based on the\n                root mean square (RMS) of its elements. Unlike traditional layer normalization,\n                which both centers and scales the data, RMS normalization only scales by the RMS\n                value. This makes it computationally more efficient, as it avoids the need to\n                compute the mean and subtract it from each element.\n\n                This layer produces output tensors with the same dimensionality as the input tensors.\n                Specifically, for an input tensor with shape [num_samples, k, nr, nc], the RMS\n                normalization is applied across the [nr, nc] dimensions independently for each\n                element in the [k] dimension and for each sample in the [num_samples] dimension.\n                The scaling factor (RMS) and the learnable scaling parameter (gamma) are both of\n                size [k].\n\n                The key characteristics of this layer are:\n                - The RMS of the elements in each sample is standardized to 1.\n                - It does not center the data (i.e., it does not subtract the mean).\n                - A learnable scaling factor (gamma) is applied after normalization, allowing the\n                model to adapt the scaling dynamically.\n\n                This layer is particularly effective in various natural language processing tasks,\n                where it has been shown to provide performance similar to or better than traditional\n                layer normalization, with reduced computational overhead.\n        !*/\n\n    public:\n        rms_norm_(\n        );\n        /*!\n            ensures\n                - #get_learning_rate_multiplier() == 1\n                - #get_weight_decay_multiplier()  == 0\n                - #get_bias_learning_rate_multiplier()  == 1\n                - #get_bias_weight_decay_multiplier()   == 1            \n                - #get_eps() == DEFAULT_RMS_NORM_EPS\n        !*/\n\n        explicit rms_norm_(\n            float eps_ = DEFAULT_RMS_NORM_EPS\n        );\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_learning_rate_multiplier() == 1\n                - #get_weight_decay_multiplier()  == 0\n                - #get_bias_learning_rate_multiplier()  == 1\n                - #get_bias_weight_decay_multiplier()   == 1            \n                - #get_eps() == eps_\n        !*/\n\n        float get_eps(\n        ) const;\n        /*!\n            ensures\n                - When doing RMS normalization, we are dividing by the root mean square.\n                This epsilon value returned by this function is added to the\n                mean square to prevent division by zero.\n        !*/\n\n        void set_eps(\n            float val\n        );\n        /*!\n            requires\n                - val > 0\n            ensures\n                - #get_eps() == val\n        !*/    \n\n        double get_learning_rate_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number. The interpretation is that this object is\n                requesting that the learning rate used to optimize its parameters be\n                multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number. The interpretation is that this object is\n                requesting that the weight decay used to optimize its parameters be\n                multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                requesting that the learning rate used to optimize its bias parameters be\n                multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const;\n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                requesting that the weight decay used to optimize its bias parameters be\n                multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using rms_norm = add_layer<rms_norm_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    enum layer_mode\n    {\n        CONV_MODE = 0, // convolutional mode\n        FC_MODE = 1    // fully connected mode\n    };\n\n    const double DEFAULT_BATCH_NORM_EPS = 0.0001;\n\n    template <\n        layer_mode mode\n        >\n    class bn_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a batch normalization layer that\n                implements the method described in the paper: \n                    Batch Normalization: Accelerating Deep Network Training by Reducing\n                    Internal Covariate Shift by Sergey Ioffe and Christian Szegedy\n                \n                In particular, this layer produces output tensors with the same\n                dimensionality as the input tensors, except that the mean and variances of\n                the elements have been standardized to 0 and 1 respectively. \n\n                It should also be noted that when tensors with a num_samples() dimension of\n                1 are passed to this layer it doesn't perform batch normalization.\n                Instead, it runs in \"inference mode\" where the learned linear normalizing\n                transformation is used to transform the tensor. \n\n                Finally, after you finish training a batch normalized network, it is a good\n                idea to replace each bn_ layer with an affine_ layer because the affine_\n                layer is faster and will never surprise you by performing batch\n                normalization on tensors that have a num_samples() dimension > 1.  This allows\n                you to run large mini-batches of samples through your final network without\n                batch normalization executing at all. \n        !*/\n\n    public:\n        bn_(\n        );\n        /*!\n            ensures\n                - #get_mode() == mode\n                - #get_running_stats_window_size()      == 100\n                - #get_learning_rate_multiplier()       == 1\n                - #get_weight_decay_multiplier()        == 0\n                - #get_bias_learning_rate_multiplier()  == 1\n                - #get_bias_weight_decay_multiplier()   == 1\n                - #get_eps() == tt::DEFAULT_BATCH_NORM_EPS\n        !*/\n\n        explicit bn_(\n            unsigned long window_size,\n            double eps = tt::DEFAULT_BATCH_NORM_EPS\n        );\n        /*!\n            requires\n                - eps > 0\n                - window_size > 0\n            ensures\n                - #get_mode() == mode \n                - #get_running_stats_window_size()     == window_size\n                - #get_learning_rate_multiplier()      == 1\n                - #get_weight_decay_multiplier()       == 0\n                - #get_bias_learning_rate_multiplier() == 1\n                - #get_bias_weight_decay_multiplier()  == 1\n                - #get_eps() == eps\n        !*/\n\n        layer_mode get_mode(\n        ) const; \n        /*!\n            ensures\n                - returns the mode of this layer, either CONV_MODE or FC_MODE.\n                  If the mode is FC_MODE then the normalization is applied across the\n                  samples in a tensor (i.e. k()*nr()*nc() different things will be\n                  normalized).  Otherwise, normalization is applied across everything\n                  except for the k() dimension, resulting in there being only k()\n                  normalization equations that are applied spatially over the tensor.\n\n                  Therefore, if you are putting batch normalization after a fully connected\n                  layer you should use FC_MODE.  Otherwise, if you are putting batch\n                  normalization after a convolutional layer you should use CONV_MODE.\n        !*/\n\n        double get_eps(\n        ) const; \n        /*!\n            ensures\n                - When doing batch normalization, we are dividing by the standard\n                  deviation.  This epsilon value returned by this function is added to the\n                  variance to prevent the division from dividing by zero.\n        !*/\n\n        unsigned long get_running_stats_window_size (\n        ) const; \n        /*!\n            ensures\n                - Just as recommended in the batch normalization paper, this object keeps a\n                  running average of the mean and standard deviations of the features.\n                  These averages are used during \"inference mode\" so you can run a single\n                  object through a batch normalized network.  They are also what is used to\n                  initialize an affine_ layer that is constructed from a bn_ layer.  This\n                  function returns the effective number of recent samples used to compute\n                  the running average.\n        !*/\n\n        void set_running_stats_window_size (\n            unsigned long new_window_size\n        );\n        /*!\n            requires\n                - new_window_size > 0\n            ensures\n                - #get_running_stats_window_size() == new_window_size\n        !*/\n\n        double get_learning_rate_multiplier(\n        ) const;  \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its parameters be\n                  multiplied by get_learning_rate_multiplier().\n        !*/\n\n        double get_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its parameters be\n                  multiplied by get_weight_decay_multiplier().\n        !*/\n\n        void set_learning_rate_multiplier(\n            double val\n        );\n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_learning_rate_multiplier() == val\n        !*/\n\n        void set_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_weight_decay_multiplier() == val\n        !*/\n\n        double get_bias_learning_rate_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the learning rate used to optimize its bias parameters be\n                  multiplied by get_learning_rate_multiplier()*get_bias_learning_rate_multiplier().\n        !*/\n\n        double get_bias_weight_decay_multiplier(\n        ) const; \n        /*!\n            ensures\n                - returns a multiplier number.  The interpretation is that this object is\n                  requesting that the weight decay used to optimize its bias parameters be\n                  multiplied by get_weight_decay_multiplier()*get_bias_weight_decay_multiplier().\n        !*/\n\n        void set_bias_learning_rate_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_learning_rate_multiplier() == val\n        !*/\n\n        void set_bias_weight_decay_multiplier(\n            double val\n        ); \n        /*!\n            requires\n                - val >= 0\n            ensures\n                - #get_bias_weight_decay_multiplier() == val\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using bn_con = add_layer<bn_<CONV_MODE>, SUBNET>;\n    template <typename SUBNET>\n    using bn_fc = add_layer<bn_<FC_MODE>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class affine_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it applies a simple pointwise linear\n                transformation to an input tensor.  You can think of it as having two\n                parameter tensors, gamma and beta.  If the input tensor is called INPUT\n                then the output of this layer is:\n                    gamma*INPUT+beta\n                where all operations are performed element wise and each sample in the\n                INPUT tensor is processed separately.\n\n                Moreover, this object has two modes that affect the dimensionalities of\n                gamma and beta and how they are applied to compute gamma*INPUT+beta.  If\n                get_mode()==FC_MODE then gamma and beta each have the same dimensionality\n                as the input tensor, except their num_samples() dimensions are 1.  If\n                get_mode()==CONV_MODE then gamma and beta have all their dimensions set\n                to 1 except for k(), which is equal to INPUT.k().\n\n                In either case, the computation of gamma*INPUT+beta is performed pointwise\n                over all the elements of INPUT using either:\n                    OUTPUT(n,k,r,c) == gamma(1,k,r,c)*INPUT(n,k,r,c)+beta(1,k,r,c)\n                or\n                    OUTPUT(n,k,r,c) == gamma(1,k,1,1)*INPUT(n,k,r,c)+beta(1,k,1,1)\n                as appropriate.\n\n\n                Finally, note that the parameters of this layer are not learnable and\n                therefore not modified during network updates.  Instead, the layer will\n                perform the identity transformation unless it is initialized with a bn_\n                layer, in which case it will perform whatever transformation the bn_ layer\n                has learned.\n        !*/\n\n    public:\n\n        affine_(\n        );\n        /*!\n            ensures\n                - #get_mode() == FC_MODE \n        !*/\n\n        affine_(\n            layer_mode mode\n        );\n        /*!\n            ensures\n                - #get_mode() == mode\n        !*/\n\n        template <\n            layer_mode mode\n            >\n        affine_(\n            const bn_<mode>& layer\n        );\n        /*!\n            ensures\n                - Constructs affine_ so that it performs the same transformation as the\n                  supplied batch normalization layer.  You would want to do this after you\n                  finish training a network with bn_ layers because the affine_ layer will\n                  execute faster.  \n                - #get_mode() == layer.get_mode()\n        !*/\n\n        layer_mode get_mode(\n        ) const; \n        /*!\n            ensures\n                - returns the mode of this layer, either CONV_MODE or FC_MODE.  \n        !*/\n\n        void disable(\n        );\n        /*!\n            ensures\n                - #get_layer_params().size() == 0.\n                - when forward_inplace and backward_inplace are called, they return immediately doing nothing.\n                  Causing this layer to trivially perform the an identity transform.\n        !*/\n\n        alias_tensor_instance get_gamma();\n        /*!\n            ensures\n                - returns the gamma parameter that defines the behavior of forward().\n        !*/\n\n        alias_tensor_const_instance get_gamma() const;\n        /*!\n            ensures\n                - returns the gamma parameter that defines the behavior of forward().\n        !*/\n\n        alias_tensor_instance get_beta();\n        /*!\n            ensures\n                - returns the beta parameter that defines the behavior of forward().\n        !*/\n\n        alias_tensor_const_instance get_beta() const;\n        /*!\n            ensures\n                - returns the beta parameter that defines the behavior of forward().\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the\n            EXAMPLE_COMPUTATIONAL_LAYER_ interface.  Also note that get_layer_params()\n            always returns an empty tensor since there are no learnable parameters in this\n            object.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using affine = add_layer<affine_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class max_pool_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - _nr >= 0\n                - _nc >= 0\n                - _stride_y > 0\n                - _stride_x > 0\n                - _padding_y >= 0\n                - _padding_x >= 0\n                - if (_nr != 0) then\n                    - _padding_y < _nr\n                - else\n                    - _padding_y == 0\n                - if (_nc != 0) then\n                    - _padding_x < _nr\n                - else\n                    - _padding_x == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a max pooling layer that takes an\n                input tensor and downsamples it.  It does this by sliding a window over the\n                images in an input tensor and outputting, for each channel, the maximum\n                element within the window.  \n\n                If _nr == 0 then it means the filter size covers all the rows in the input\n                tensor, similarly for the _nc parameter.  To be precise, if we call the\n                input tensor IN and the output tensor OUT, then OUT is defined as follows:\n                    - let FILT_NR == (nr()==0) ? IN.nr() : nr()\n                    - let FILT_NC == (nc()==0) ? IN.nc() : nc()\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k()\n                    - OUT.nr() == 1+(IN.nr() + 2*padding_y() - FILT_NR)/stride_y()\n                    - OUT.nc() == 1+(IN.nc() + 2*padding_x() - FILT_NC)/stride_x()\n                    - for all valid s, k, r, and c:\n                        - image_plane(OUT,s,k)(r,c) == max(subm_clipped(image_plane(IN,s,k),\n                                                                  centered_rect(x*stride_x() + FILT_NC/2 - padding_x(),\n                                                                                y*stride_y() + FILT_NR/2 - padding_y(),\n                                                                                FILT_NC,\n                                                                                FILT_NR)))\n        !*/\n\n    public:\n\n        max_pool_ (\n        );\n        /*!\n            ensures\n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n        !*/\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in the pooling window or 0 if the window size\n                  is \"the entire input tensor\".\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in the pooling window or 0 if the window size\n                  is \"the entire input tensor\".\n        !*/\n\n        long stride_y(\n        ) const; \n        /*!\n            ensures\n                - returns the vertical stride used when scanning the max pooling window\n                  over an image.  That is, each window will be moved stride_y() pixels down\n                  at a time when it moves over the image.\n        !*/\n\n        long stride_x(\n        ) const;\n        /*!\n            ensures\n                - returns the horizontal stride used when scanning the max pooling window\n                  over an image.  That is, each window will be moved stride_x() pixels down\n                  at a time when it moves over the image.\n        !*/\n\n        long padding_y(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the top and bottom\n                  sides of the image.\n        !*/\n\n        long padding_x(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the left and right \n                  sides of the image.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using max_pool = add_layer<max_pool_<nr,nc,stride_y,stride_x>, SUBNET>;\n\n    template <\n        typename SUBNET\n        >\n    using max_pool_everything = add_layer<max_pool_<0,0,1,1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _nr,\n        long _nc,\n        int _stride_y,\n        int _stride_x,\n        int _padding_y = _stride_y!=1? 0 : _nr/2,\n        int _padding_x = _stride_x!=1? 0 : _nc/2\n        >\n    class avg_pool_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - _nr >= 0\n                - _nc >= 0\n                - _stride_y > 0\n                - _stride_x > 0\n                - _padding_y >= 0\n                - _padding_x >= 0\n                - if (_nr != 0) then\n                    - _padding_y < _nr\n                - else\n                    - _padding_y == 0\n                - if (_nc != 0) then\n                    - _padding_x < _nr\n                - else\n                    - _padding_x == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines an average pooling layer that\n                takes an input tensor and downsamples it.  It does this by sliding a window\n                over the images in an input tensor and outputting, for each channel, the\n                average element within the window.  \n\n                If _nr == 0 then it means the filter size covers all the rows in the input\n                tensor, similarly for the _nc parameter.  To be precise, if we call the\n                input tensor IN and the output tensor OUT, then OUT is defined as follows:\n                    - let FILT_NR == (nr()==0) ? IN.nr() : nr()\n                    - let FILT_NC == (nc()==0) ? IN.nc() : nc()\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k()\n                    - OUT.nr() == 1+(IN.nr() + 2*padding_y() - FILT_NR)/stride_y()\n                    - OUT.nc() == 1+(IN.nc() + 2*padding_x() - FILT_NC)/stride_x()\n                    - for all valid s, k, r, and c:\n                        - image_plane(OUT,s,k)(r,c) == mean(subm_clipped(image_plane(IN,s,k),\n                                                                  centered_rect(x*stride_x() + FILT_NC/2 - padding_x(),\n                                                                                y*stride_y() + FILT_NR/2 - padding_y(),\n                                                                                FILT_NC,\n                                                                                FILT_NR)))\n        !*/\n\n    public:\n\n        avg_pool_ (\n        );\n        /*!\n            ensures\n                - #nr() == _nr\n                - #nc() == _nc\n                - #stride_y() == _stride_y\n                - #stride_x() == _stride_x\n                - #padding_y() == _padding_y\n                - #padding_x() == _padding_x\n        !*/\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in the pooling window or 0 if the window size\n                  is \"the entire input tensor\".\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in the pooling window or 0 if the window size\n                  is \"the entire input tensor\".\n        !*/\n\n        long stride_y(\n        ) const; \n        /*!\n            ensures\n                - returns the vertical stride used when scanning the pooling window\n                  over an image.  That is, each window will be moved stride_y() pixels down\n                  at a time when it moves over the image.\n        !*/\n\n        long stride_x(\n        ) const;\n        /*!\n            ensures\n                - returns the horizontal stride used when scanning the pooling window\n                  over an image.  That is, each window will be moved stride_x() pixels down\n                  at a time when it moves over the image.\n        !*/\n\n        long padding_y(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the top and bottom\n                  sides of the image.\n        !*/\n\n        long padding_x(\n        ) const; \n        /*!\n            ensures\n                - returns the number of pixels of zero padding added to the left and right \n                  sides of the image.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& computed_output, const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n\n    };\n\n    template <\n        long nr,\n        long nc,\n        int stride_y,\n        int stride_x,\n        typename SUBNET\n        >\n    using avg_pool = add_layer<avg_pool_<nr,nc,stride_y,stride_x>, SUBNET>;\n\n    template <\n        typename SUBNET\n        >\n    using avg_pool_everything = add_layer<avg_pool_<0,0,1,1>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class relu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a rectified linear layer.\n                Therefore, it passes its inputs through the function \n                    f(x)=max(x,0) \n                where f() is applied pointwise across the input tensor.\n        !*/\n\n    public:\n\n        relu_(\n        );\n\n        void disable(\n        );\n        /*!\n            ensures\n                - #get_layer_params().size() == 0.\n                - when forward_inplace and backward_inplace are called, they return immediately doing nothing.\n                  Causing this layer to trivially perform the an identity transform.\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using relu = add_layer<relu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class prelu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a parametric rectified linear\n                layer.  Therefore, it passes its inputs through the function \n                    f(x) = x>0 ? x : p*x \n                where f() is applied pointwise across the input tensor and p is a scalar\n                parameter learned by this layer.\n\n\n                This is the layer type introduced in the paper:\n                    He, Kaiming, et al. \"Delving deep into rectifiers: Surpassing\n                    human-level performance on imagenet classification.\" Proceedings of the\n                    IEEE International Conference on Computer Vision. 2015.\n        !*/\n\n    public:\n\n        explicit prelu_(\n            float initial_param_value = 0.25\n        );\n        /*!\n            ensures\n                - The p parameter will be initialized with initial_param_value.\n                - #get_initial_param_value() == initial_param_value.\n        !*/\n\n        float get_initial_param_value (\n        ) const;\n        /*!\n            ensures\n                - returns the initial value of the prelu parameter. \n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using prelu = add_layer<prelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class leaky_relu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a leaky rectified linear\n                layer.  Therefore, it passes its inputs through the function\n                    f(x) = x>0 ? x : alpha*x\n                where f() is applied pointwise across the input tensor and alpha is a\n                non-learned scalar.\n\n                This is the layer type introduced in the paper:\n                    A. L. Maas, A. Y. Hannun, and A. Y. Ng. \"Rectifier nonlinearities improve\n                    neural network acoustic models\". In ICML, 2013.\n        !*/\n\n    public:\n        explicit leaky_relu_(\n            float alpha = 0.01f\n        );\n        /*!\n            ensures\n                - the alpha parameter will be initialized with the alpha value\n        !*/\n\n        float get_alpha(\n        ) const;\n        /*!\n            ensures\n                - returns the alpha parameter of the leaky_relu\n        !*/\n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using leaky_relu = add_layer<prelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class sig_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a sigmoid layer.  Therefore, it\n                passes its inputs through the function \n                    f(x)=1/(1+exp(-x)) \n                where f() is applied pointwise across the input tensor.\n        !*/\n\n    public:\n\n        sig_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using sig = add_layer<sig_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class mish_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a mish layer.  Therefore, it\n                passes its inputs through the function\n                    f(x)= x*tanh(log(1+exp(x)))\n                where f() is applied pointwise across the input tensor.\n\n                This is the layer type introduced in the paper:\n                Diganta Misra. \"Mish: A Self Regularized Non-Monotonic Activation Function\"\n        !*/\n\n    public:\n\n        mish_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& data_output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor&);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using mish = add_layer<mish_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class htan_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a hyperbolic tangent layer.\n                Therefore, it passes its inputs through the function \n                    f(x)=std::tanh(x)\n                where f() is applied pointwise across the input tensor.\n        !*/\n\n    public:\n\n        htan_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using htan = add_layer<htan_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class clipped_relu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a clipped version of the relu layer.\n                Therefore, it passes its inputs through the function\n                    f(x) = min(max(x, 0), ceiling)\n                where f() is applied pointwise across the input tensor and ceiling is a\n                non-learned scalar.\n        !*/\n\n    public:\n\n        clipped_relu_(\n            const float ceiling = 6.0f\n        );\n        /*!\n            ensures\n                - the ceiling parameter will be initialized with the ceiling value\n        !*/\n\n        float get_ceiling() const;\n        /*!\n            ensures\n                - returns the celiling parameter of the clipped_relu\n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using clipped_relu = add_layer<clipped_relu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class elu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines an exponential linear unit.\n                Therefore, it passes its inputs through the function\n                    f(x) = x>0 ? x : alpha*(exp(x)-1)\n                where f() is applied pointwise across the input tensor and alpha is a\n                non-learned scalar.\n\n                This is the layer type introduced in the paper:\n                Djork-Arné Clevert, Thomas Unterthiner, Sepp Hochreiter.\n                \"Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)\".\n        !*/\n\n    public:\n\n        elu_(\n            const float alpha = 1.0f\n        );\n        /*!\n            ensures\n                - the alpha parameter will be initialized with the alpha value\n        !*/\n\n        float get_alpha() const;\n        /*!\n            ensures\n                - returns the alpha parameter of the elu\n        !*/\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using elu = add_layer<elu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class gelu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a gelu layer.  Therefore, it\n                passes its inputs through the function\n                        f(x)= x/2 * (1 + erf(x/sqrt(2))\n                where f() is applied pointwise across the input tensor.\n\n                This is the layer type introduced in the paper:\n                Dan Hendrycks, Kevin Gimpel. \"Gaussian Error Linear Units (GELUs)\".\n        !*/\n\n    public:\n\n        gelu_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& data_output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor&);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using gelu = add_layer<gelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class smelu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a smooth rectified linear\n                layer.  Therefore, it passes its inputs through the function f(x):\n                    - if (x > beta) 1\n                    - if (x < -beta) 0\n                    - else std::pow(x + beta, 2) / (4 * beta)\n                where f() is applied pointwise across the input tensor and beta is a\n                non-learned scalar.\n\n                This is the layer type introduced in the paper:\n                \"Smooth activations and reproducibility in deep networks\" by\n                Gil I. Shamir, Dong Lin, Lorenzo Coviello (https://arxiv.org/abs/2010.09931)\n        !*/\n\n    public:\n        explicit smelu_(\n            float beta = 1\n        );\n        /*!\n            ensures\n                - the beta parameter will be initialized with the beta value\n        !*/\n\n        float get_beta(\n        ) const;\n        /*!\n            ensures\n                - returns the beta parameter of the smelu\n        !*/\n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using smelu = add_layer<prelu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class silu_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a silu layer.  Therefore, it\n                passes its inputs through the function\n                        f(x)= x * sigmoid(x) = x / (1 + exp(-x))\n                where f() is applied pointwise across the input tensor.\n\n                This is the layer type introduced in the paper:\n                Dan Hendrycks, Kevin Gimpel. \"Gaussian Error Linear Units (GELUs)\".\n        !*/\n\n    public:\n\n        silu_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& data_output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor&);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using silu = add_layer<silu_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <operation_mode s_mode_>\n    class softmax_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above. It defines a softmax layer with two modes of operation:\n                channel-wise and plane-wise.\n\n                The softmax function s(x) is defined as:\n                    s(x) == exp(x)/sum(exp(x))\n                where x is a vector.\n\n                1. Channel-wise mode (s_mode_ == CHANNEL_WISE):\n                This mode treats the input tensor as a collection of multi-channel images\n                and applies s() to each spatial location in each image. The tensor::k()\n                channel elements at each position are input to s() and then replaced by\n                the outputs of s().\n\n                2. Plane-wise mode (s_mode_ == PLANE_WISE):\n                This mode applies the softmax function across entire planes (nr x nc) of\n                the input tensor, useful for operations in Large Language Models (LLMs)\n                and other applications requiring 2D tensor processing.\n\n                In both modes, the sum of the outputs of s() will always be equal to 1 for\n                each application of the function.\n\n            TEMPLATE PARAMETERS\n                - s_mode_: Determines the mode of operation (CHANNEL_WISE or PLANE_WISE)\n        !*/\n\n    public:\n        softmax_();\n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(\n            const tensor& computed_output,\n            const tensor& gradient_input,\n            tensor& data_grad,\n            tensor& params_grad\n        );\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_\n            interface. Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n\n        friend void serialize(const softmax_& item, std::ostream& out);\n        friend void deserialize(softmax_& item, std::istream& in);\n        friend std::ostream& operator<<(std::ostream& out, const softmax_& item);\n        friend void to_xml(const softmax_& item, std::ostream& out);\n    };\n\n    template <typename SUBNET>\n    using softmax = add_layer<softmax_<operation_mode::CHANNEL_WISE>, SUBNET>;\n\n    template <typename SUBNET>\n    using softmaxm = add_layer<softmax_<operation_mode::PLANE_WISE>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class softmax_all_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, it defines a softmax layer.  To be precise,\n                we define the softmax function s(x) as:\n                    s(x) == exp(x)/sum(exp(x)) \n                where x is a vector.  Then this layer treats its input tensor as a\n                collection of tensor::num_samples() vectors and applies s() to each vector\n                in the tensor.  Therefore, there are logically tensor::num_samples()\n                invocations of s().\n        !*/\n\n    public:\n\n        softmax_all_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ \n            interface.  Note that this layer doesn't have any parameters, so the tensor\n            returned by get_layer_params() is always empty.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using softmax_all = add_layer<softmax_all_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class add_prev_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer simply adds the output of two previous layers.\n                In particular, it adds the tensor from its immediate predecessor layer,\n                sub.get_output(), with the tensor from a deeper layer,\n                layer<tag>(sub).get_output().\n\n                Therefore, you supply a tag via add_prev_'s template argument that tells it\n                what layer to add to the output of the previous layer.  The result of this\n                addition is output by add_prev_.  Finally, the addition happens pointwise\n                according to 4D tensor arithmetic.  If the dimensions don't match then\n                missing elements are presumed to be equal to 0.  Moreover, each dimension\n                of the output tensor is equal to the maximum dimension of either of the\n                inputs.  That is, if the tensors A and B are being added to produce C then:\n                    - C.num_samples() == max(A.num_samples(), B.num_samples())\n                    - C.k()  == max(A.k(), B.k())\n                    - C.nr() == max(A.nr(), B.nr())\n                    - C.nc() == max(A.nc(), B.nc())\n        !*/\n\n    public:\n        add_prev_(\n        ); \n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using add_prev = add_layer<add_prev_<tag>, SUBNET>;\n\n    // Here we add some convenient aliases for using add_prev_ with the tag layers. \n    template <typename SUBNET> using add_prev1  = add_prev<tag1, SUBNET>;\n    template <typename SUBNET> using add_prev2  = add_prev<tag2, SUBNET>;\n    template <typename SUBNET> using add_prev3  = add_prev<tag3, SUBNET>;\n    template <typename SUBNET> using add_prev4  = add_prev<tag4, SUBNET>;\n    template <typename SUBNET> using add_prev5  = add_prev<tag5, SUBNET>;\n    template <typename SUBNET> using add_prev6  = add_prev<tag6, SUBNET>;\n    template <typename SUBNET> using add_prev7  = add_prev<tag7, SUBNET>;\n    template <typename SUBNET> using add_prev8  = add_prev<tag8, SUBNET>;\n    template <typename SUBNET> using add_prev9  = add_prev<tag9, SUBNET>;\n    template <typename SUBNET> using add_prev10 = add_prev<tag10, SUBNET>;\n    using add_prev1_  = add_prev_<tag1>;\n    using add_prev2_  = add_prev_<tag2>;\n    using add_prev3_  = add_prev_<tag3>;\n    using add_prev4_  = add_prev_<tag4>;\n    using add_prev5_  = add_prev_<tag5>;\n    using add_prev6_  = add_prev_<tag6>;\n    using add_prev7_  = add_prev_<tag7>;\n    using add_prev8_  = add_prev_<tag8>;\n    using add_prev9_  = add_prev_<tag9>;\n    using add_prev10_ = add_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class mult_prev_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer simply multiplies the output of two previous\n                layers.  In particular, it multiplies the tensor from its immediate\n                predecessor layer, sub.get_output(), with the tensor from a deeper layer,\n                layer<tag>(sub).get_output().\n\n                Therefore, you supply a tag via mult_prev_'s template argument that tells\n                it what layer to multiply with the output of the previous layer.  The\n                result of this multiplication is output by mult_prev_.  Finally, the\n                multiplication happens pointwise according to 4D tensor arithmetic.  If the\n                dimensions don't match then missing elements are presumed to be equal to 0.\n                Moreover, each dimension of the output tensor is equal to the maximum\n                dimension of either of the inputs.  That is, if the tensors A and B are\n                being multiplied to produce C then:\n                    - C.num_samples() == max(A.num_samples(), B.num_samples())\n                    - C.k()  == max(A.k(), B.k())\n                    - C.nr() == max(A.nr(), B.nr())\n                    - C.nc() == max(A.nc(), B.nc())\n        !*/\n\n    public:\n        mult_prev_(\n        ); \n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using mult_prev = add_layer<mult_prev_<tag>, SUBNET>;\n\n    // Here we add some convenient aliases for using mult_prev_ with the tag layers. \n    template <typename SUBNET> using mult_prev1  = mult_prev<tag1, SUBNET>;\n    template <typename SUBNET> using mult_prev2  = mult_prev<tag2, SUBNET>;\n    template <typename SUBNET> using mult_prev3  = mult_prev<tag3, SUBNET>;\n    template <typename SUBNET> using mult_prev4  = mult_prev<tag4, SUBNET>;\n    template <typename SUBNET> using mult_prev5  = mult_prev<tag5, SUBNET>;\n    template <typename SUBNET> using mult_prev6  = mult_prev<tag6, SUBNET>;\n    template <typename SUBNET> using mult_prev7  = mult_prev<tag7, SUBNET>;\n    template <typename SUBNET> using mult_prev8  = mult_prev<tag8, SUBNET>;\n    template <typename SUBNET> using mult_prev9  = mult_prev<tag9, SUBNET>;\n    template <typename SUBNET> using mult_prev10 = mult_prev<tag10, SUBNET>;\n    using mult_prev1_  = mult_prev_<tag1>;\n    using mult_prev2_  = mult_prev_<tag2>;\n    using mult_prev3_  = mult_prev_<tag3>;\n    using mult_prev4_  = mult_prev_<tag4>;\n    using mult_prev5_  = mult_prev_<tag5>;\n    using mult_prev6_  = mult_prev_<tag6>;\n    using mult_prev7_  = mult_prev_<tag7>;\n    using mult_prev8_  = mult_prev_<tag8>;\n    using mult_prev9_  = mult_prev_<tag9>;\n    using mult_prev10_ = mult_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class multm_prev_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above. This layer performs matrix multiplication on the output\n                of two previous layers. It multiplies the tensor from its immediate\n                predecessor layer, sub.get_output(), with the tensor from a deeper layer,\n                layer<tag>(sub).get_output().\n\n                The tag template argument specifies which layer to multiply with the\n                output of the previous layer. The result of this multiplication is\n                output by multm_prev_. The multiplication is performed using a modified\n                version of gemm() to account for the 2D matrix dimension in the nr()xnc()\n                planes of Dlib's 4D tensors.\n\n                This layer is similar to mult_prev_, but it considers the full matrix\n                in the nr()xnc() planes of the tensor, rather than just the upper\n                num_samples()xk() plane. This makes it suitable for implementing\n                mechanisms like attention, especially when the k() channel plane is\n                used to model multiple heads for parallel matrix processing.\n\n                The output tensor dimensions are determined as follows:\n                    - output.num_samples() == t1.num_samples()\n                    - output.k() == t1.k()\n                    - output.nr() == t1.nr()\n                    - output.nc() == t2.nc()\n                where t1 is sub.get_output() and t2 is layer<tag>(sub).get_output().\n        !*/\n\n    public:\n        multm_prev_(\n        ); \n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;        \n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using multm_prev = add_layer<multm_prev_<tag>, SUBNET>;\n\n    // Here we add some convenient aliases for using multm_prev_ with the tag layers. \n    template <typename SUBNET> using multm_prev1  = multm_prev<tag1, SUBNET>;\n    template <typename SUBNET> using multm_prev2  = multm_prev<tag2, SUBNET>;\n    template <typename SUBNET> using multm_prev3  = multm_prev<tag3, SUBNET>;\n    template <typename SUBNET> using multm_prev4  = multm_prev<tag4, SUBNET>;\n    template <typename SUBNET> using multm_prev5  = multm_prev<tag5, SUBNET>;\n    template <typename SUBNET> using multm_prev6  = multm_prev<tag6, SUBNET>;\n    template <typename SUBNET> using multm_prev7  = multm_prev<tag7, SUBNET>;\n    template <typename SUBNET> using multm_prev8  = multm_prev<tag8, SUBNET>;\n    template <typename SUBNET> using multm_prev9  = multm_prev<tag9, SUBNET>;\n    template <typename SUBNET> using multm_prev10 = multm_prev<tag10, SUBNET>;\n    using multm_prev1_  = multm_prev_<tag1>;\n    using multm_prev2_  = multm_prev_<tag2>;\n    using multm_prev3_  = multm_prev_<tag3>;\n    using multm_prev4_  = multm_prev_<tag4>;\n    using multm_prev5_  = multm_prev_<tag5>;\n    using multm_prev6_  = multm_prev_<tag6>;\n    using multm_prev7_  = multm_prev_<tag7>;\n    using multm_prev8_  = multm_prev_<tag8>;\n    using multm_prev9_  = multm_prev_<tag9>;\n    using multm_prev10_ = multm_prev_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class resize_prev_to_tagged_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer resizes the output channels of the previous layer\n                to have the same number of rows and columns as the output of the tagged layer.\n\n                This layer uses bilinear interpolation. If the sizes match already, then it\n                simply copies the data.\n\n                Therefore, you supply a tag via resize_prev_to_tagged's template argument that\n                tells it what layer to use for the target size.\n\n                If tensor PREV is resized to size of tensor TAGGED, then a tensor OUT is\n                produced such that:\n                    - OUT.num_samples() == PREV.num_samples()\n                    - OUT.k()  == PREV.k()\n                    - OUT.nr() == TAGGED.nr()\n                    - OUT.nc() == TAGGED.nc()\n        !*/\n\n    public:\n        resize_prev_to_tagged_(\n        ); \n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using resize_prev_to_tagged = add_layer<resize_prev_to_tagged_<tag>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class scale_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer scales the output channels of the tagged layer\n                by multiplying it with the output of the previous layer.  To be specific:\n                    - Let INPUT  == layer<tag>(sub).get_output()\n                    - Let SCALES == sub.get_output()\n                    - This layer takes INPUT and SCALES as input.\n                    - The output of this layer has the same dimensions as INPUT.\n                    - This layer requires:\n                        - SCALES.num_samples() == INPUT.num_samples()\n                        - SCALES.k()  == INPUT.k()\n                        - SCALES.nr() == 1\n                        - SCALES.nc() == 1\n                    - The output tensor is produced by pointwise multiplying SCALES with\n                      INPUT at each spatial location.  Therefore, if OUT is the output of\n                      this layer then we would have:\n                        OUT(n,k,r,c) == INPUT(n,k,r,c)*SCALES(n,k)\n        !*/\n\n    public:\n        scale_(\n        ); \n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using scale = add_layer<scale_<tag>, SUBNET>;\n\n    // Here we add some convenient aliases for using scale_ with the tag layers. \n    template <typename SUBNET> using scale1  = scale<tag1, SUBNET>;\n    template <typename SUBNET> using scale2  = scale<tag2, SUBNET>;\n    template <typename SUBNET> using scale3  = scale<tag3, SUBNET>;\n    template <typename SUBNET> using scale4  = scale<tag4, SUBNET>;\n    template <typename SUBNET> using scale5  = scale<tag5, SUBNET>;\n    template <typename SUBNET> using scale6  = scale<tag6, SUBNET>;\n    template <typename SUBNET> using scale7  = scale<tag7, SUBNET>;\n    template <typename SUBNET> using scale8  = scale<tag8, SUBNET>;\n    template <typename SUBNET> using scale9  = scale<tag9, SUBNET>;\n    template <typename SUBNET> using scale10 = scale<tag10, SUBNET>;\n    using scale1_  = scale_<tag1>;\n    using scale2_  = scale_<tag2>;\n    using scale3_  = scale_<tag3>;\n    using scale4_  = scale_<tag4>;\n    using scale5_  = scale_<tag5>;\n    using scale6_  = scale_<tag6>;\n    using scale7_  = scale_<tag7>;\n    using scale8_  = scale_<tag8>;\n    using scale9_  = scale_<tag9>;\n    using scale10_ = scale_<tag10>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template<typename> class tag\n        >\n    class scale_prev_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer scales the output channels of the tagged layer\n                by multiplying it with the output of the previous layer.  It is excatly the\n                same as the scale_ layer, but with the inputs swapped, which is useful since\n                it allows mapping between inputs and outputs of this layer.  To be specific:\n                    - Let INPUT == sub.get_output()\n                    - Let SCALES == layer<tag>(sub).get_output()\n                    - This layer takes INPUT and SCALES as input.\n                    - The output of this layer has the same dimensions as INPUT.\n                    - This layer requires:\n                        - SCALES.num_samples() == INPUT.num_samples()\n                        - SCALES.k()  == INPUT.k()\n                        - SCALES.nr() == 1\n                        - SCALES.nc() == 1\n                    - The output tensor is produced by pointwise multiplying SCALES with\n                      INPUT at each spatial location.  Therefore, if OUT is the output of\n                      this layer then we would have:\n                        OUT(n,k,r,c) == INPUT(n,k,r,c)*SCALES(n,k)\n        !*/\n\n    public:\n        scale_prev_(\n        );\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    template <\n        template<typename> class tag,\n        typename SUBNET\n        >\n    using scale_prev = add_layer<scale_prev_<tag>, SUBNET>;\n\n    // Here we add some convenient aliases for using scale_prev_ with the tag layers.\n    template <typename SUBNET> using scale_prev1  = scale_prev<tag1, SUBNET>;\n    template <typename SUBNET> using scale_prev2  = scale_prev<tag2, SUBNET>;\n    template <typename SUBNET> using scale_prev3  = scale_prev<tag3, SUBNET>;\n    template <typename SUBNET> using scale_prev4  = scale_prev<tag4, SUBNET>;\n    template <typename SUBNET> using scale_prev5  = scale_prev<tag5, SUBNET>;\n    template <typename SUBNET> using scale_prev6  = scale_prev<tag6, SUBNET>;\n    template <typename SUBNET> using scale_prev7  = scale_prev<tag7, SUBNET>;\n    template <typename SUBNET> using scale_prev8  = scale_prev<tag8, SUBNET>;\n    template <typename SUBNET> using scale_prev9  = scale_prev<tag9, SUBNET>;\n    template <typename SUBNET> using scale_prev10 = scale_prev<tag10, SUBNET>;\n    using scale_prev1_  = scale_prev_<tag1>;\n    using scale_prev2_  = scale_prev_<tag2>;\n    using scale_prev3_  = scale_prev_<tag3>;\n    using scale_prev4_  = scale_prev_<tag4>;\n    using scale_prev5_  = scale_prev_<tag5>;\n    using scale_prev6_  = scale_prev_<tag6>;\n    using scale_prev7_  = scale_prev_<tag7>;\n    using scale_prev8_  = scale_prev_<tag8>;\n    using scale_prev9_  = scale_prev_<tag9>;\n    using scale_prev10_ = scale_prev_<tag10>;\n\n    // ----------------------------------------------------------------------------------------\n\n    template<\n        template<typename> class... TAG_TYPES\n        >\n    class concat_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  This layer simply concatenates the output of tagged layers.\n                Importantly, each input layer must have the same dimensions (i.e.\n                num_samples, nr, and nc) except for the k channel, which may vary.  This is\n                because the concatenation happens along the k dimension.  That is, the\n                output of this network is a tensor, OUT, that is the concatenation of the\n                tensors:\n                    for each (tag in TAG_TYPES)\n                        layer<tag>(subnet).get_output()\n                Therefore, out.num_samples(), out.nr(), and out.nc() match the dimensions\n                of the input tensors while OUT.k() is the sum of the input layer's k()\n                dimensions.\n        !*/\n\n    public:\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n\n    // concat layer definitions\n    template <template<typename> class TAG1,\n              template<typename> class TAG2,\n              typename SUBNET>\n    using concat2 = add_layer<concat_<TAG1, TAG2>, SUBNET>;\n\n    template <template<typename> class TAG1,\n              template<typename> class TAG2,\n              template<typename> class TAG3,\n              typename SUBNET>\n    using concat3 = add_layer<concat_<TAG1, TAG2, TAG3>, SUBNET>;\n\n    template <template<typename> class TAG1,\n              template<typename> class TAG2,\n              template<typename> class TAG3,\n              template<typename> class TAG4,\n              typename SUBNET>\n    using concat4 = add_layer<concat_<TAG1, TAG2, TAG3, TAG4>, SUBNET>;\n\n    template <template<typename> class TAG1,\n              template<typename> class TAG2,\n              template<typename> class TAG3,\n              template<typename> class TAG4,\n              template<typename> class TAG5,\n              typename SUBNET>\n    using concat5 = add_layer<concat_<TAG1, TAG2, TAG3, TAG4, TAG5>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n    \n    /*!A inception layer definitions !*/\n\n    // Now define inception layer tag types.  These layer aliases allow creating\n    // the networks described in the paper: \n    //   Szegedy, Christian, et al. \"Going deeper with convolutions.\" Proceedings of\n    //   the IEEE Conference on Computer Vision and Pattern Recognition. 2015.\n    // See the dnn_inception_ex.cpp example for a complete example of their use.  Note also\n    // that we use tag ID numbers >= 1000 to avoid conflict with user's tag layers.\n    template <typename SUBNET> using itag0  = add_tag_layer< 1000 + 0, SUBNET>;\n    template <typename SUBNET> using itag1  = add_tag_layer< 1000 + 1, SUBNET>;\n    template <typename SUBNET> using itag2  = add_tag_layer< 1000 + 2, SUBNET>;\n    template <typename SUBNET> using itag3  = add_tag_layer< 1000 + 3, SUBNET>;\n    template <typename SUBNET> using itag4  = add_tag_layer< 1000 + 4, SUBNET>;\n    template <typename SUBNET> using itag5  = add_tag_layer< 1000 + 5, SUBNET>;\n    // skip to inception input\n    template <typename SUBNET> using iskip  = add_skip_layer< itag0, SUBNET>;\n\n    // here are some templates to be used for creating inception layer groups\n    template <template<typename>class B1,\n              template<typename>class B2,\n              typename SUBNET>\n    using inception2 = concat2<itag1, itag2, itag1<B1<iskip< itag2<B2< itag0<SUBNET>>>>>>>;\n\n    template <template<typename>class B1,\n              template<typename>class B2,\n              template<typename>class B3,\n              typename SUBNET>\n    using inception3 = concat3<itag1, itag2, itag3, itag1<B1<iskip< itag2<B2<iskip< itag3<B3<  itag0<SUBNET>>>>>>>>>>;\n\n    template <template<typename>class B1,\n              template<typename>class B2,\n              template<typename>class B3,\n              template<typename>class B4,\n              typename SUBNET>\n    using inception4 = concat4<itag1, itag2, itag3, itag4,\n                itag1<B1<iskip< itag2<B2<iskip< itag3<B3<iskip<  itag4<B4<  itag0<SUBNET>>>>>>>>>>>>>;\n\n    template <template<typename>class B1,\n              template<typename>class B2,\n              template<typename>class B3,\n              template<typename>class B4,\n              template<typename>class B5,\n              typename SUBNET>\n    using inception5 = concat5<itag1, itag2, itag3, itag4, itag5,\n                itag1<B1<iskip< itag2<B2<iskip< itag3<B3<iskip<  itag4<B4<iskip<  itag5<B5<  itag0<SUBNET>>>>>>>>>>>>>>>>;\n\n// ----------------------------------------------------------------------------------------\n\n    const double DEFAULT_L2_NORM_EPS = 1e-5;\n\n    class l2normalize_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  It takes tensors as input and L2 normalizes them.  In particular,\n                it has the following properties:\n                    - The output tensors from this layer have the same dimensions as the\n                      input tensors.\n                    - If you think of each input tensor as a set of tensor::num_samples()\n                      vectors, then the output tensor contains the same vectors except they\n                      have been length normalized so that their L2 norms are all 1.  I.e. \n                      for each vector v we will have ||v||==1.\n        !*/\n\n    public:\n\n        explicit l2normalize_(\n            double eps = tt::DEFAULT_L2_NORM_EPS\n        );\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_eps() == eps\n        !*/\n\n        double get_eps(\n        ) const; \n        /*!\n            ensures\n                - When we normalize a vector we divide it by its L2 norm.  However, the\n                  get_eps() value is added to the squared norm prior to division to avoid\n                  ever dividing by zero. \n        !*/\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        void forward_inplace(const tensor& input, tensor& output);\n        void backward_inplace(const tensor& computed_output, const tensor& gradient_input, tensor& data_grad, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _offset,\n        long _k,\n        long _nr,\n        long _nc\n        >\n    class extract_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - 0 <= _offset\n                - 0 < _k\n                - 0 < _nr\n                - 0 < _nc\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, the output of this layer is simply a copy of\n                the input tensor.  However, you can configure the extract layer to output\n                only some subset of the input tensor and also to reshape it.  Therefore,\n                the dimensions of the tensor output by this layer are as follows (letting\n                IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == _k \n                    - OUT.nr() == _nr \n                    - OUT.nc() == _nc \n\n                So the output will always have the same number of samples as the input, but\n                within each sample (the k,nr,nc part) we will copy only a subset of the\n                values.  Moreover, the _offset parameter controls which part of each sample\n                we take.  To be very precise, we will have:\n                    - let IN_SIZE   = IN.k()*IN.nr()*IN.nc()\n                    - let OUT_SIZE  = _k*_nr*_nc \n                    - for i in range[0,IN.num_samples()) and j in range[0,OUT_SIZE):\n                        - OUT.host()[i*OUT_SIZE+j] == IN.host()[i*IN_SIZE+_offset+j]\n\n\n                Finally, all this means that the input tensor to this layer must have a big\n                enough size to accommodate taking a _k*_nr*_nc slice from each of its\n                samples.  \n        !*/\n\n    public:\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        long offset,\n        long k,\n        long nr,\n        long nc,\n        typename SUBNET\n        >\n    using extract = add_layer<extract_<offset,k,nr,nc>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long _offset_k,\n        long _offset_nr,\n        long _offset_nc,\n        long _k,\n        long _nr,\n        long _nc\n        >\n    class slice_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - 0 <= _offset_k\n                - 0 <= _offset_nr\n                - 0 <= _offset_nc\n                - 0 < _k\n                - 0 < _nr\n                - 0 < _nc\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above.  In particular, the output of this layer is simply a copy of\n                the input tensor. It is similar to extract in that you can configure the\n                slice layer to output only some subset of the input tensor, but slice allows\n                copies of non-contiguous regions of the input which enables three dimensional\n                cropping of a tensor. The dimensions of the tensor output by this layer\n                are as follows (letting IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == _k \n                    - OUT.nr() == _nr \n                    - OUT.nc() == _nc \n\n                So the output will always have the same number of samples as the input, but\n                within each sample (the k,nr,nc part) we will copy only a subset of the\n                values. Moreover, the _offset_k, _offset_nr, and _offset_nc parameters\n                control which channels, rows, and columns of each sample we take.\n                To be very precise, we will have:\n                    - let IN_SIZE   = IN.k()*IN.nr()*IN.nc()\n                    - let OUT_SIZE  = _k*_nr*_nc \n                    - for i in range[0,IN.num_samples()) and j in range[0,OUT_SIZE):\n                        - let k = (j / (OUT.nr()*OUT.nc())) % OUT.k()\n                        - let r = (j / OUT.nc()) % IN.nr()\n                        - let c = j % OUT.nc()\n                        - OUT.host()[i*OUT_SIZE+j] == IN.host()[i*IN_SIZE+\n                                                                k_stride*(_offset_k+k)+\n                                                                row_stride*(_offset_nr+r)+\n                                                                col_stride*(_offset_nc+c)]\n\n\n                Finally, all this means that the input tensor to this layer must have a big\n                enough size to accommodate taking a _k*_nr*_nc slice from each of its\n                samples.  \n        !*/\n\n    public:\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        long offset_k,\n        long offset_nr,\n        long offset_nc,\n        long k,\n        long nr,\n        long nc,\n        typename SUBNET\n        >\n    using slice = add_layer<slice_<offset_k,offset_nr,offset_nc,k,nr,nc>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <long long row_stride = 2, long long col_stride = 2>\n    class reorg_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - row_stride >= 1\n                - col_stride >= 1\n\n            WHAT THIS OBJECT REPRESENTS\n                This class implements the EXAMPLE_COMPUTATIONAL_LAYER_ interface, performing a \n                reorganization of tensor data. It rearranges spatial information along the channel\n                dimension, effectively \"folding\" spatial dimensions into channels.\n                \n                The dimensions of the output tensor are as follows (letting IN be the input tensor\n                and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k() * row_stride * col_stride\n                    - OUT.nr() == IN.nr() / row_stride\n                    - OUT.nc() == IN.nc() / col_stride\n\n                Therefore, the output tensor maintains the same number of samples as the input but\n                alters the channel and spatial dimensions based on the specified strides.\n                \n                Specifically, for all n, k, r, c in OUT:\n                    OUT.host[tensor_index(OUT, n, k, r, c)] ==\n                    IN.host[tensor_index(IN,\n                                        n,\n                                        k % IN.k(),\n                                        r * row_stride + (k / IN.k()) / col_stride,\n                                        c * col_stride + (k / IN.k()) % col_stride)]\n\n                **Enhancement Note:**  \n                The underlying utility functions (`reorg` and `reorg_gradient`) now include an\n                optional `bool add_to` parameter. While the current implementation uses the default\n                value to maintain existing behavior, this parameter allows for future reversible\n                operations and gradient accumulation flexibility within neural network layers.\n\n                You can think of this layer as an alternative to a strided convolutional layer for\n                downsampling tensors, offering similar spatial reduction with different internal\n                gradient propagation mechanics.\n        !*/\n\n    public:\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output (dpoint p) const;\n        dpoint map_output_to_input (dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using reorg = add_layer<reorg_<2, 2>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class transpose_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above. In particular, this layer performs a 2D matrix transposition\n                on each of the k planes within each sample of a 4D tensor.\n\n                The dimensions of the tensor output by this layer are as follows (letting\n                IN be the input tensor and OUT the output tensor):\n                    - OUT.num_samples() == IN.num_samples()\n                    - OUT.k()  == IN.k()\n                    - OUT.nr() == IN.nc()\n                    - OUT.nc() == IN.nr()\n\n                The transposition is performed as follows:\n                    - For each sample i and each k-plane j:\n                        - OUT[i][j][r][c] = IN[i][j][c][r] for all r in [0, IN.nc()) and c in [0, IN.nr())\n\n                This layer does not have any learnable parameters.\n        !*/\n\n    public:\n\n        transpose_() = default;\n\n        template <typename SUBNET> void setup (const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        \n        inline dpoint map_input_to_output(dpoint p) const;\n        inline dpoint map_output_to_input(dpoint p) const;\n\n        const tensor& get_layer_params() const; \n        tensor& get_layer_params(); \n\n        friend void serialize(const transpose_& item, std::ostream& out);\n        friend void deserialize(transpose_& item, std::istream& in);\n\n        friend std::ostream& operator<<(std::ostream& out, const transpose_& item);\n        friend void to_xml(const transpose_& item, std::ostream& out);\n\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    private:\n        resizable_tensor params; // unused\n    };\n\n    template <typename SUBNET>\n    using transpose = add_layer<transpose_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class positional_encodings_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n                It defines a positional encoding layer that adds position information to\n                the input tensor. This is particularly useful in transformer architectures\n                where the order of the sequence matters.\n\n                The dimensions of the tensors output by this layer are the same as the input\n                tensor dimensions.\n\n                This implementation is based on the positional encoding described in:\n                Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., \n                Kaiser, Ł., & Polosukhin, I. (2017). Attention is all you need. In Advances \n                in neural information processing systems (pp. 5998-6008).\n\n                The encoding uses sine and cosine functions of different frequencies:\n                PE(pos, 2i)   = sin(pos / 10000^(2i/d_model))\n                PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))\n                where pos is the position and i is the dimension.\n        !*/\n\n    public:\n\n        positional_encodings_(\n            unsigned long sequence_dim_ = 1,\n            unsigned long embedding_dim_ = 1\n        );\n        /*!\n            ensures\n                - #sequence_dim == sequence_dim_\n                - #embedding_dim == embedding_dim_\n        !*/\n\n        positional_encodings_ (\n            const positional_encodings_& item\n        );\n        /*!\n            ensures\n                - EXAMPLE_COMPUTATIONAL_LAYER_ objects are copy constructable\n        !*/\n\n        positional_encodings_& operator=(\n            const positional_encodings_& item\n        );\n        /*!\n            ensures\n                - EXAMPLE_COMPUTATIONAL_LAYER_ objects are assignable\n        !*/\n\n        template <typename SUBNET>\n        void setup (\n            const SUBNET& sub\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n            ensures\n                - performs any necessary setup for the layer, including the calculation\n                of positional encodings based on the dimensions of the input.\n        !*/\n\n        template <typename SUBNET>\n        void forward(\n            const SUBNET& sub,\n            resizable_tensor& output\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n            ensures\n                - Adds the positional encodings to the output of the subnetwork and \n                stores the results into #output.\n        !*/\n\n        template <typename SUBNET>\n        void backward(\n            const tensor& gradient_input,\n            SUBNET& sub,\n            tensor& params_grad\n        );\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of this file.\n                - setup() has been called.\n                - #params_grad is unused in this layer as there are no learnable parameters.\n            ensures\n                - Computes the gradient of the layer with respect to the input, which\n                is simply the input gradient itself as positional encodings are constant.\n        !*/\n\n        const tensor& get_layer_params(\n        ) const;\n        /*!\n            ensures\n                - returns the parameters that define the behavior of forward().\n                Note: This layer has no learnable parameters, so this returns an empty tensor.\n        !*/\n\n        tensor& get_layer_params(\n        );\n        /*!\n            ensures\n                - returns the parameters that define the behavior of forward().\n                Note: This layer has no learnable parameters, so this returns an empty tensor.\n        !*/\n\n        const tensor& get_positional_encodings(\n        ) const;\n        /*!\n            ensures\n                - returns the computed positional encodings.\n        !*/\n\n        tensor& get_positional_encodings(\n        );\n        /*!\n            ensures\n                - returns the computed positional encodings.\n        !*/\n\n        friend void serialize(const positional_encodings_& item, std::ostream& out);\n        friend void deserialize(positional_encodings_& item, std::istream& in);\n        /*!\n            provides serialization support\n        !*/\n\n        friend std::ostream& operator<<(std::ostream& out, const positional_encodings_& item);\n        /*!\n            print a string describing this layer.\n        !*/\n\n        friend void to_xml(const positional_encodings_& item, std::ostream& out);\n        /*!\n            This function is optional, but required if you want to print your networks with\n            net_to_xml(). It prints a layer as XML.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using positional_encodings = add_layer<positional_encodings_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long num_embeddings_,\n        unsigned long embedding_dim_\n        >\n    class embeddings_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an embedding layer in a neural network. It maps discrete\n                tokens to continuous vector representations. This is a fundamental technique in\n                natural language processing and other domains dealing with categorical data.\n\n                The layer takes as input a tensor of integer indices and outputs a tensor of \n                the same shape (except for the last dimension) where each index is replaced by \n                its corresponding embedding vector.\n\n                For more information on embeddings, see:\n                Mikolov, T., Sutskever, I., Chen, K., Corrado, G. S., & Dean, J. (2013). \n                Distributed representations of words and phrases and their compositionality. \n                In Advances in neural information processing systems (pp. 3111-3119).\n\n            TEMPLATE PARAMETERS\n                - num_embeddings_: The size of the embedding dictionary, i.e., the number of \n                                discrete tokens that can be embedded.\n                - embedding_dim_: The dimensionality of each embedding vector.\n\n            CONVENTION\n                - get_embeddings() returns the tensor of embedding vectors.\n                - get_num_embeddings() == num_embeddings_\n                - get_embedding_dim() == embedding_dim_\n                - get_learning_rate_multiplier() returns the learning rate multiplier for this layer.\n                - get_scale_by_freq() returns whether to scale gradients by token frequency.\n        */        \n    public:\n        embeddings_() = default;\n\n        unsigned long get_num_embeddings() const;\n        unsigned long get_embedding_dim() const;\n        double get_learning_rate_multiplier() const;\n        bool get_scale_by_freq() const;\n\n        void set_num_embeddings(unsigned long num);\n        void set_embedding_dim(unsigned long dim);\n        void set_learning_rate_multiplier(double val);\n        void set_scale_by_freq(bool val);\n\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n        const tensor& get_embeddings() const;\n        tensor& get_embeddings();\n\n        friend void serialize(const embeddings_& item, std::ostream& out);\n        friend void deserialize(embeddings_& item, std::istream& in);\n        friend std::ostream& operator<<(std::ostream& out, const embeddings_& item);\n        friend void to_xml(const embeddings_& item, std::ostream& out);\n\n        /*!\n            These functions are implemented as described in the EXAMPLE_COMPUTATIONAL_LAYER_ interface.\n        !*/\n    };\n\n    template <\n        unsigned long num_embeddings,\n        unsigned long embedding_dim,\n        typename SUBNET\n        >\n    using embeddings = add_layer<embeddings_<num_embeddings, embedding_dim>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    struct neg_infinity_tag {};\n    struct zero_tag {};\n\n    template<typename T>\n    struct is_special_value : std::false_type {};\n    template<>\n    struct is_special_value<neg_infinity_tag> : std::true_type {};\n    template<>\n    struct is_special_value<zero_tag> : std::true_type {};\n\n    template<long diag_, typename tag_, long num_ = 0, long den_ = 1>\n    class tril_\n    {\n        /*!\n            TEMPLATE PARAMETERS\n                - diag_: A long integer specifying the diagonal offset.\n                - tag_: A type tag specifying special values or void for numeric values.\n                - num_: Numerator for numeric diagonal value (default is 0, only used if tag_ is void).\n                - den_: Denominator for numeric diagonal value (default is 1, only used if tag_ is void).\n\n            REQUIREMENTS\n                - diag_ must be an integer.\n                - tag_ must be either neg_infinity_tag, zero_tag, or void.\n                - If tag_ is void, num_ and den_ are used to compute the diagonal value.\n                - If tag_ is neg_infinity_tag or zero_tag, num_ and den_ are ignored.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object implements a layer in a deep neural network that applies a lower triangular mask to\n                its input tensor. The mask is defined such that all elements above the specified diagonal are set\n                to a given value. The diagonal offset and the mask value are determined by the template parameters.\n\n            DIAGONAL VALUE DETERMINATION\n                - If tag_ is neg_infinity_tag: diagonal value is set to negative infinity.\n                - If tag_ is zero_tag: diagonal value is set to zero.\n                - If tag_ is void: diagonal value is set to num_ / den_ as a float.\n\n            DIAGONAL OFFSET\n                The diag_ parameter determines the diagonal above which elements are masked:\n                - diag_ = 0: main diagonal\n                - diag_ > 0: diag_ steps above the main diagonal\n                - diag_ < 0: |diag_| steps below the main diagonal\n\n            EXAMPLE USAGE\n                // Create a layer that masks all elements above the main diagonal with -inf\n                tril_<0, neg_infinity_tag> layer1;\n\n                // Create a layer that masks all elements above the main diagonal with 0\n                tril_<0, zero_tag> layer2;\n\n                // Create a layer that masks all elements above the main diagonal with 0.5\n                tril_<0, void, 1, 2> layer3;\n\n                // Create a layer that masks all elements 5 positions above the main diagonal with -inf\n                tril_<5, neg_infinity_tag> layer4;\n\n                // Create a layer that masks all elements 3 positions below the main diagonal with 0.25\n                tril_<-3, void, 1, 4> layer5;\n\n            SERIALIZATION SUPPORT\n                This object supports serialization and deserialization via the serialize() and deserialize() functions.\n        !*/\n\n    public:\n        tril_() = default;\n        /*!\n            ensures\n                - This object is properly initialized.\n        !*/\n\n        template <typename SUBNET>\n        void setup(const SUBNET& sub);\n        /*!\n            requires\n                - SUBNET is a valid network layer type.\n            ensures\n                - Initializes the mask based on the dimensions of the input tensor from sub.\n        !*/\n\n        template <typename SUBNET>\n        void forward(const SUBNET& sub, resizable_tensor& output);\n        /*!\n            requires\n                - SUBNET is a valid network layer type.\n            ensures\n                - Applies the lower triangular mask to the input tensor from sub and stores the result in output.\n        !*/\n\n        template <typename SUBNET>\n        void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        /*!\n            requires\n                - SUBNET is a valid network layer type.\n            ensures\n                - Computes the gradient of the loss with respect to the input tensor and stores it in sub.\n        !*/\n\n        inline dpoint map_input_to_output(const dpoint& p) const;\n        /*!\n            ensures\n                - Maps a point from the input tensor to the corresponding point in the output tensor.\n        !*/\n\n        inline dpoint map_output_to_input(const dpoint& p) const;\n        /*!\n            ensures\n                - Maps a point from the output tensor to the corresponding point in the input tensor.\n        !*/\n\n        const tensor& get_layer_params() const;\n        /*!\n            ensures\n                - Returns the parameters of this layer.\n        !*/\n\n        tensor& get_layer_params();\n        /*!\n            ensures\n                - Returns the parameters of this layer.\n        !*/\n\n        friend void serialize(const tril_& item, std::ostream& out);\n        /*!\n            ensures\n                - Serializes the state of this object to the given output stream.\n        !*/\n\n        friend void deserialize(tril_& item, std::istream& in);\n        /*!\n            ensures\n                - Deserializes the state of this object from the given input stream.\n        !*/\n\n        friend std::ostream& operator<<(std::ostream& out, const tril_& item);\n        /*!\n            ensures\n                - Prints a human-readable representation of this object to the given output stream.\n        !*/\n\n        friend void to_xml(const tril_& item, std::ostream& out);\n        /*!\n            ensures\n                - Serializes the state of this object to XML format and writes it to the given output stream.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using tril = add_layer<tril_<0, zero_tag>, SUBNET>;\n\n    template <typename SUBNET>\n    using tril_mask = add_layer<tril_<0, neg_infinity_tag>, SUBNET>;\n\n    template <long diag, long num, long den, typename SUBNET>\n    using tril_diag = add_layer<tril_<diag, void, num, den>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <long max_steps>\n    class adaptive_computation_time_\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE ARGUMENTS\n                - max_steps > 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the EXAMPLE_COMPUTATIONAL_LAYER_ interface\n                defined above. It implements Adaptive Computation Time (ACT) following\n                Graves (2016) \"Adaptive Computation Time for Recurrent Neural Networks\"\n                (arXiv:1603.08983).\n\n                ACT allows the network to adaptively determine how many computational steps\n                to perform for each position in the input sequence, spending more computation\n                on difficult parts while quickly processing easier parts.\n\n            MATHEMATICAL FOUNDATION:\n                Core ACT Algorithm:\n                - For each sequence position t, perform up to max_steps computational steps\n                - At step n, compute halting probability: p_t^n = sigmoid(W_halt^T * s_t^n + b_halt)\n                - Cumulative halting probability: h_t^n = sum_{i=1 to n} p_t^i\n                - Stop when h_t^n >= theta (threshold, typically 0.99)\n                - Final output: y_t = sum_{n=1 to N(t)} alpha_t^n * y_hat_t^n\n\n                Where alpha_t^n (effective weight) is computed as:\n                - alpha_t^n = p_t^n * rho_t^{n-1} for intermediate steps\n                - alpha_t^{N(t)} = 1 - h_t^{N(t)-1} (remainder for final step)\n                - rho_t^n = 1 - h_t^n (remaining probability mass)\n\n                PONDER COST (Regularization):\n                - R(x) = (1/T) * sum_t (N(t) + rho_t^{N(t)})\n                - Total loss: L = L_task + lambda * R(x)\n                - lambda is controlled by get_ponder_penalty()\n\n            IMPLEMENTATION DETAILS:\n                - Input/Output tensors have identical dimensions\n                - Learnable parameters: W_halt in R^{d x k}, b_halt in R\n                - State tracking per position: cumulative halting, remainders, step counts\n                - Early termination when all positions halt\n        !*/\n\n    public:\n        adaptive_computation_time_();\n        /*!\n            ensures\n                - #get_max_steps() == max_steps\n                - #get_halt_threshold() == 0.99f\n                - #get_ponder_penalty() == 0.01f\n        !*/\n\n        // Configuration accessors\n        long get_max_steps() const;\n        float get_halt_threshold() const;\n        float get_ponder_penalty() const;\n\n        void set_halt_threshold(float threshold);\n        /*!\n            requires\n                - 0 < threshold <= 1.0f\n            ensures\n                - #get_halt_threshold() == threshold\n        !*/\n\n        void set_ponder_penalty(float penalty);\n        /*!\n            requires\n                - penalty >= 0\n            ensures\n                - #get_ponder_penalty() == penalty\n        !*/\n\n        // Runtime statistics\n        float get_ponder_cost() const;\n        /*!\n            ensures\n                - returns the ponder cost R(x) from the most recent forward pass\n                - value represents average computational cost per position\n        !*/\n\n        float get_average_steps() const;\n        /*!\n            ensures\n                - returns the average number of computation steps per position\n                - value is between 1.0 and max_steps\n        !*/\n\n        // Layer interface\n        template <typename SUBNET> void setup(const SUBNET& sub);\n        template <typename SUBNET> void forward(const SUBNET& sub, resizable_tensor& output);\n        template <typename SUBNET> void backward(const tensor& gradient_input, SUBNET& sub, tensor& params_grad);\n        dpoint map_input_to_output(dpoint p) const;\n        dpoint map_output_to_input(dpoint p) const;\n        const tensor& get_layer_params() const;\n        tensor& get_layer_params();\n\n        friend void serialize(const adaptive_computation_time_& item, std::ostream& out);\n        friend void deserialize(adaptive_computation_time_& item, std::istream& in);\n        friend std::ostream& operator<<(std::ostream& out, const adaptive_computation_time_& item);\n        friend void to_xml(const adaptive_computation_time_& item, std::ostream& out);\n        /*!\n            provides serialization support and output operators\n        !*/\n    };\n\n    template <long max_steps, typename SUBNET>\n    using adaptive_computation_time = add_layer<adaptive_computation_time_<max_steps>, SUBNET>;\n\n    template <typename SUBNET>\n    using act = add_layer<adaptive_computation_time_<8>, SUBNET>;\n\n    template <typename SUBNET>\n    using act4 = add_layer<adaptive_computation_time_<4>, SUBNET>;\n\n    template <typename SUBNET>\n    using act16 = add_layer<adaptive_computation_time_<16>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_LAYERS_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/dnn/loss.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_LOSS_H_\n#define DLIB_DNn_LOSS_H_\n\n#include \"loss_abstract.h\"\n#include \"core.h\"\n#include \"utilities.h\"\n#include \"../matrix.h\"\n#include \"../cuda/tensor_tools.h\"\n#include \"../geometry.h\"\n#include \"../image_processing/box_overlap_testing.h\"\n#include \"../image_processing/full_object_detection.h\"\n#include \"../svm/ranking_tools.h\"\n#include <sstream>\n#include <map>\n#include <unordered_map>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_hinge_ \n    {\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 && \n                         output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = out_data[i];\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 && \n                         output_tensor.k() == 1);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            const float* out_data = output_tensor.host();\n            float* g = grad.host_write_only();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const float y = *truth++;\n                DLIB_CASSERT(y == +1 || y == -1, \"y: \" << y);\n                const float temp = 1-y*out_data[i];\n                if (temp > 0)\n                {\n                    loss += scale*temp;\n                    g[i] = -scale*y;\n                }\n                else\n                {\n                    g[i] = 0;\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_binary_hinge_& , std::ostream& out)\n        {\n            serialize(\"loss_binary_hinge_\", out);\n        }\n\n        friend void deserialize(loss_binary_hinge_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_binary_hinge_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_binary_hinge_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_binary_hinge_& )\n        {\n            out << \"loss_binary_hinge\";\n            return out;\n        }\n\n        friend void to_xml(const loss_binary_hinge_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_binary_hinge/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_binary_hinge = add_loss_layer<loss_binary_hinge_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_log_ \n    {\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 && \n                         output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = out_data[i];\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 && \n                         output_tensor.k() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && \n                         grad.nc() == 1 && \n                         grad.k() == 1);\n\n            tt::sigmoid(grad, output_tensor);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const float y = *truth++;\n                DLIB_CASSERT(y != 0, \"y: \" << y);\n                float temp;\n                if (y > 0)\n                {\n                    temp = log1pexp(-out_data[i]);\n                    loss += y*scale*temp;\n                    g[i] = y*scale*(g[i]-1);\n                }\n                else\n                {\n                    temp = -(-out_data[i]-log1pexp(-out_data[i]));\n                    loss += -y*scale*temp;\n                    g[i] = -y*scale*g[i];\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_binary_log_& , std::ostream& out)\n        {\n            serialize(\"loss_binary_log_\", out);\n        }\n\n        friend void deserialize(loss_binary_log_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_binary_log_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_binary_log_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_binary_log_& )\n        {\n            out << \"loss_binary_log\";\n            return out;\n        }\n\n        friend void to_xml(const loss_binary_log_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_binary_log/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_binary_log = add_loss_layer<loss_binary_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_ \n    {\n    public:\n\n        typedef unsigned long training_label_type;\n        typedef unsigned long output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 );\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n\n            // Note that output_tensor.k() should match the number of labels.\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                // The index of the largest output for this sample is the label.\n                *iter++ = index_of_max(rowm(mat(output_tensor),i));\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && \n                         grad.nc() == 1);\n\n            tt::softmax(grad, output_tensor);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const long y = (long)*truth++;\n                // The network must produce a number of outputs that is equal to the number\n                // of labels when using this type of loss.\n                DLIB_CASSERT(y < output_tensor.k(), \"y: \" << y << \", output_tensor.k(): \" << output_tensor.k());\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    const unsigned long idx = i*output_tensor.k()+k;\n                    if (k == y)\n                    {\n                        loss += scale*-safe_log(g[idx]);\n                        g[idx] = scale*(g[idx]-1);\n                    }\n                    else\n                    {\n                        g[idx] = scale*g[idx];\n                    }\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_multiclass_log_& , std::ostream& out)\n        {\n            serialize(\"loss_multiclass_log_\", out);\n        }\n\n        friend void deserialize(loss_multiclass_log_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_multiclass_log_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multiclass_log_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_& )\n        {\n            out << \"loss_multiclass_log\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multiclass_log_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_multiclass_log/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log = add_loss_layer<loss_multiclass_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_weighted_\n    {\n    public:\n\n        typedef dlib::weighted_label<unsigned long> weighted_label;\n        typedef weighted_label training_label_type;\n        typedef unsigned long output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 );\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n\n            // Note that output_tensor.k() should match the number of labels.\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                // The index of the largest output for this sample is the label.\n                *iter++ = index_of_max(rowm(mat(output_tensor),i));\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 &&\n                         grad.nc() == 1);\n\n            tt::softmax(grad, output_tensor);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const auto wl = *truth++;\n                const long y = wl.label;\n                const float weight = wl.weight;\n                // The network must produce a number of outputs that is equal to the number\n                // of labels when using this type of loss.\n                DLIB_CASSERT(y < output_tensor.k(), \"y: \" << y << \", output_tensor.k(): \" << output_tensor.k());\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    const unsigned long idx = i*output_tensor.k()+k;\n                    if (k == y)\n                    {\n                        loss += weight*scale*-safe_log(g[idx]);\n                        g[idx] =weight*scale*(g[idx]-1);\n                    }\n                    else\n                    {\n                        g[idx] = weight*scale*g[idx];\n                    }\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_multiclass_log_weighted_& , std::ostream& out)\n        {\n            serialize(\"loss_multiclass_log_weighted_\", out);\n        }\n\n        friend void deserialize(loss_multiclass_log_weighted_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_multiclass_log_weighted_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multiclass_log_weighted_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_weighted_& )\n        {\n            out << \"loss_multiclass_log_weighted\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multiclass_log_weighted_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_multiclass_log_weighted/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_weighted = add_loss_layer<loss_multiclass_log_weighted_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multimulticlass_log_ \n    {\n\n    public:\n\n        loss_multimulticlass_log_ () = default;\n\n        loss_multimulticlass_log_ (\n            const std::map<std::string,std::vector<std::string>>& labels\n        )\n        {\n            for (auto& l : labels)\n            {\n                possible_labels[l.first] = std::make_shared<decltype(l.second)>(l.second);\n                DLIB_CASSERT(l.second.size() >= 2, \"Each classifier must have at least two possible labels.\");\n\n                for (size_t i = 0; i < l.second.size(); ++i)\n                {\n                    label_idx_lookup[l.first][l.second[i]] = i;\n                    ++total_num_labels;\n                }\n            }\n        }\n\n        unsigned long number_of_labels() const { return total_num_labels; }\n\n        unsigned long number_of_classifiers() const { return possible_labels.size(); }\n\n        std::map<std::string,std::vector<std::string>> get_labels ( \n        ) const \n        {\n            std::map<std::string,std::vector<std::string>> info; \n            for (auto& i : possible_labels)\n            {\n                for (auto& label : *i.second)\n                    info[i.first].emplace_back(label);\n            }\n            return info;\n        }\n\n        class classifier_output\n        {\n\n        public:\n            classifier_output() = default;\n\n            size_t num_classes() const { return class_probs.size(); }\n\n            double probability_of_class (\n                size_t i\n            ) const \n            { \n                DLIB_CASSERT(i < num_classes());\n                return class_probs(i); \n            }\n\n            const std::string& label(\n                size_t i\n            ) const \n            { \n                DLIB_CASSERT(i < num_classes()); \n                return (*_labels)[i]; \n            }\n\n            operator std::string(\n            ) const\n            {\n                DLIB_CASSERT(num_classes() != 0); \n                return (*_labels)[index_of_max(class_probs)];\n            }\n\n            friend std::ostream& operator<< (std::ostream& out, const classifier_output& item)\n            {\n                DLIB_ASSERT(item.num_classes() != 0); \n                out << static_cast<std::string>(item);\n                return out;\n            }\n\n        private:\n\n            friend class loss_multimulticlass_log_;\n\n            template <typename EXP>\n            classifier_output(\n                const matrix_exp<EXP>& class_probs,\n                const std::shared_ptr<std::vector<std::string>>& _labels\n            ) : \n                class_probs(class_probs), \n                _labels(_labels)\n            {\n            }\n\n            matrix<float,1,0> class_probs;\n            std::shared_ptr<std::vector<std::string>> _labels;\n        };\n\n        typedef std::map<std::string,std::string> training_label_type;\n        typedef std::map<std::string,classifier_output> output_label_type;\n\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter_begin\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1 );\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            DLIB_CASSERT(number_of_labels() != 0, \"You must give the loss_multimulticlass_log_'s constructor label data before you can use it!\");\n            DLIB_CASSERT(output_tensor.k() == (long)number_of_labels(), \"The output tensor must have \" << number_of_labels() << \" channels.\");\n\n\n            long k_offset = 0;\n            for (auto& l : possible_labels)\n            {\n                auto iter = iter_begin;\n                const std::string& classifier_name = l.first;\n                const auto& labels = (*l.second); \n                scratch.set_size(output_tensor.num_samples(), labels.size());\n                tt::copy_tensor(false, scratch, 0, output_tensor, k_offset, labels.size());\n\n                tt::softmax(scratch, scratch);\n\n                for (long i = 0; i < scratch.num_samples(); ++i)\n                    (*iter++)[classifier_name] = classifier_output(rowm(mat(scratch),i), l.second);\n\n                k_offset += labels.size();\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth_begin, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && \n                         grad.nc() == 1);\n            DLIB_CASSERT(number_of_labels() != 0, \"You must give the loss_multimulticlass_log_'s constructor label data before you can use it!\");\n            DLIB_CASSERT(output_tensor.k() == (long)number_of_labels(), \"The output tensor must have \" << number_of_labels() << \" channels.\");\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            long k_offset = 0;\n            for (auto& l : label_idx_lookup)\n            {\n                const std::string& classifier_name = l.first;\n                const auto& int_labels = l.second; \n                scratch.set_size(output_tensor.num_samples(), int_labels.size());\n                tt::copy_tensor(false, scratch, 0, output_tensor, k_offset, int_labels.size());\n\n                tt::softmax(scratch, scratch);\n\n\n                auto truth = truth_begin;\n                float* g = scratch.host();\n                for (long i = 0; i < scratch.num_samples(); ++i)\n                {\n                    const long y = int_labels.at(truth->at(classifier_name));\n                    ++truth;\n\n                    for (long k = 0; k < scratch.k(); ++k)\n                    {\n                        const unsigned long idx = i*scratch.k()+k;\n                        if (k == y)\n                        {\n                            loss += scale*-std::log(g[idx]);\n                            g[idx] = scale*(g[idx]-1);\n                        }\n                        else\n                        {\n                            g[idx] = scale*g[idx];\n                        }\n                    }\n                }\n\n                tt::copy_tensor(false, grad, k_offset, scratch, 0, int_labels.size());\n\n                k_offset += int_labels.size();\n            }\n            return loss;\n        }\n\n\n        friend void serialize(const loss_multimulticlass_log_& item, std::ostream& out)\n        {\n            serialize(\"loss_multimulticlass_log_\", out);\n            serialize(item.get_labels(), out);\n        }\n\n        friend void deserialize(loss_multimulticlass_log_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_multimulticlass_log_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multimulticlass_log_.\");\n\n            std::map<std::string,std::vector<std::string>> info; \n            deserialize(info, in);\n            item = loss_multimulticlass_log_(info);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multimulticlass_log_& item)\n        {\n            out << \"loss_multimulticlass_log, labels={\";\n            for (auto i = item.possible_labels.begin(); i != item.possible_labels.end(); )\n            {\n                auto& category = i->first;\n                auto& labels = *(i->second);\n                out << category << \":(\";\n                for (size_t j = 0; j < labels.size(); ++j)\n                {\n                    out << labels[j];\n                    if (j+1 < labels.size())\n                        out << \",\";\n                }\n\n                out << \")\";\n                if (++i != item.possible_labels.end())\n                    out << \", \";\n            }\n            out << \"}\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multimulticlass_log_& item, std::ostream& out)\n        {\n            out << \"<loss_multimulticlass_log>\\n\";\n            out << item;\n            out << \"\\n</loss_multimulticlass_log>\\n\";\n        }\n\n    private:\n\n        std::map<std::string,std::shared_ptr<std::vector<std::string>>> possible_labels;\n        unsigned long total_num_labels = 0;\n\n        // We make it true that: possible_labels[classifier][label_idx_lookup[classifier][label]] == label\n        std::map<std::string, std::map<std::string, size_t>> label_idx_lookup;\n\n\n        // Scratch doesn't logically contribute to the state of this object.  It's just\n        // temporary scratch space used by this class.  \n        mutable resizable_tensor scratch;\n\n\n    };\n\n    template <typename SUBNET>\n    using loss_multimulticlass_log = add_loss_layer<loss_multimulticlass_log_, SUBNET>;\n\n    inline bool operator== (const std::string& lhs, const loss_multimulticlass_log_::classifier_output& rhs)\n    { return lhs == static_cast<const std::string&>(rhs); }\n    inline bool operator== (const loss_multimulticlass_log_::classifier_output& lhs, const std::string& rhs)\n    { return rhs == static_cast<const std::string&>(lhs); }\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multibinary_log_\n    {\n    public:\n        typedef std::vector<float> training_label_type;\n        typedef std::vector<float> output_label_type;\n\n        loss_multibinary_log_() = default;\n\n        loss_multibinary_log_(double gamma) : gamma(gamma)\n        {\n            DLIB_CASSERT(gamma >= 0);\n        }\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(output_tensor.nr() == 1 && output_tensor.nc() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            // Note that output_tensor.k() should match the number of labels.\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                output_label_type predictions(output_tensor.k(), 0);\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    predictions[k] = out_data[i * output_tensor.k() + k];\n                }\n                *iter++ = std::move(predictions);\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples() % sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && grad.nc() == 1);\n\n            tt::sigmoid(grad, output_tensor);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0 / output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host();\n            const float* out_data  = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                const long long num_label_categories = truth->size();\n                DLIB_CASSERT(output_tensor.k() == num_label_categories,\n                    \"Number of label types should match the number of output channels. \"\n                    \"output_tensor.k(): \" << output_tensor.k() \n                    << \", num_label_categories: \"<< num_label_categories);\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    const float y = (*truth)[k];\n                    DLIB_CASSERT(y != 0, \"y: \" << y);\n                    const size_t idx = i * output_tensor.k() + k;\n                    if (y > 0)\n                    {\n                        const float temp = log1pexp(-out_data[idx]);\n                        const float focus = std::pow(1 - g[idx], gamma);\n                        loss += y * scale * temp * focus;\n                        g[idx] = y * scale * focus * (g[idx] * (gamma * temp + 1) - 1);\n                    }\n                    else\n                    {\n                        const float temp = -(-out_data[idx] - log1pexp(-out_data[idx]));\n                        const float focus = std::pow(g[idx], gamma);\n                        loss += -y * scale * temp * focus;\n                        g[idx] = -y * scale * focus * g[idx] * (gamma * temp + 1);\n                    }\n                }\n            }\n            return loss;\n        }\n\n        double get_gamma () const { return gamma; }\n\n        friend void serialize(const loss_multibinary_log_& item, std::ostream& out)\n        {\n            serialize(\"loss_multibinary_log_2\", out);\n            serialize(item.gamma, out);\n        }\n\n        friend void deserialize(loss_multibinary_log_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"loss_multibinary_log_\")\n            {\n                item.gamma = 0;\n                return;\n            }\n            else if (version == \"loss_multibinary_log_2\")\n            {\n                deserialize(item.gamma, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multibinary_log_.\");\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multibinary_log_& item)\n        {\n            out << \"loss_multibinary_log (gamma=\" << item.gamma << \")\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multibinary_log_& item, std::ostream& out)\n        {\n            out << \"<loss_multibinary_log gamma='\" << item.gamma << \"'/>\\n\";\n        }\n\n    private:\n        double gamma = 0;\n    };\n\n    template <typename SUBNET>\n    using loss_multibinary_log = add_loss_layer<loss_multibinary_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum class use_image_pyramid : uint8_t\n    {\n        no,\n        yes\n    };\n\n    struct mmod_options\n    {\n    public:\n\n        struct detector_window_details\n        {\n            detector_window_details() = default; \n            detector_window_details(unsigned long w, unsigned long h) : width(w), height(h) {}\n            detector_window_details(unsigned long w, unsigned long h, const std::string& l) : width(w), height(h), label(l) {}\n\n            unsigned long width = 0;\n            unsigned long height = 0;\n            std::string label;\n\n            friend inline void serialize(const detector_window_details& item, std::ostream& out)\n            {\n                int version = 2;\n                serialize(version, out);\n                serialize(item.width, out);\n                serialize(item.height, out);\n                serialize(item.label, out);\n            }\n\n            friend inline void deserialize(detector_window_details& item, std::istream& in)\n            {\n                int version = 0;\n                deserialize(version, in);\n                if (version != 1 && version != 2)\n                    throw serialization_error(\"Unexpected version found while deserializing dlib::mmod_options::detector_window_details\");\n                deserialize(item.width, in);\n                deserialize(item.height, in);\n                if (version == 2)\n                    deserialize(item.label, in);\n            }\n\n        };\n\n        mmod_options() = default;\n\n        std::vector<detector_window_details> detector_windows;\n        double loss_per_false_alarm = 1;\n        double loss_per_missed_target = 1;\n        double truth_match_iou_threshold = 0.5;\n        test_box_overlap overlaps_nms = test_box_overlap(0.4);\n        test_box_overlap overlaps_ignore;\n        bool use_bounding_box_regression = false; \n        double bbr_lambda = 100; \n        // This field is intentionally not serialized because I want people to really think hard\n        // about ignoring the warnings that this suppresses.\n        bool be_quiet = false;\n\n        use_image_pyramid assume_image_pyramid = use_image_pyramid::yes;\n\n        mmod_options (\n            const std::vector<std::vector<mmod_rect>>& boxes,\n            const unsigned long target_size,       // We want the length of the longest dimension of the detector window to be this.\n            const unsigned long min_target_size,   // But we require that the smallest dimension of the detector window be at least this big.\n            const double min_detector_window_overlap_iou = 0.75\n        )\n        {\n            DLIB_CASSERT(0 < min_target_size && min_target_size <= target_size);\n            DLIB_CASSERT(0.5 < min_detector_window_overlap_iou && min_detector_window_overlap_iou < 1);\n\n            // Figure out what detector windows we will need.\n            for (auto& label : get_labels(boxes))\n            {\n                for (auto ratio : find_covering_aspect_ratios(boxes, test_box_overlap(min_detector_window_overlap_iou), label))\n                {\n                    double detector_width;\n                    double detector_height;\n                    if (ratio < 1)\n                    {\n                        detector_height = target_size;\n                        detector_width = ratio*target_size;\n                        if (detector_width < min_target_size)\n                        {\n                            detector_height = min_target_size/ratio;\n                            detector_width = min_target_size;\n                        }\n                    }\n                    else\n                    {\n                        detector_width = target_size;\n                        detector_height = target_size/ratio;\n                        if (detector_height < min_target_size)\n                        {\n                            detector_width = min_target_size*ratio;\n                            detector_height = min_target_size;\n                        }\n                    }\n\n                    detector_window_details p((unsigned long)std::round(detector_width), (unsigned long)std::round(detector_height), label);\n                    detector_windows.push_back(p);\n                }\n            }\n\n            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).\");\n\n            set_overlap_nms(boxes);\n        }\n\n        mmod_options(\n            use_image_pyramid assume_image_pyramid,\n            const std::vector<std::vector<mmod_rect>>& boxes,\n            const double min_detector_window_overlap_iou = 0.75\n        )\n            : assume_image_pyramid(assume_image_pyramid)\n        {\n            DLIB_CASSERT(assume_image_pyramid == use_image_pyramid::no);\n            DLIB_CASSERT(0.5 < min_detector_window_overlap_iou && min_detector_window_overlap_iou < 1);\n\n            // Figure out what detector windows we will need.\n            for (auto& label : get_labels(boxes))\n            {\n                for (auto rectangle : find_covering_rectangles(boxes, test_box_overlap(min_detector_window_overlap_iou), label))\n                {\n                    detector_windows.push_back(detector_window_details(rectangle.width(), rectangle.height(), label));\n                }\n            }\n\n            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).\");\n\n            set_overlap_nms(boxes);\n        }\n\n    private:\n\n        void set_overlap_nms(const std::vector<std::vector<mmod_rect>>& boxes)\n        {\n            // Convert from mmod_rect to rectangle so we can call\n            // find_tight_overlap_tester().\n            std::vector<std::vector<rectangle>> temp;\n            for (auto&& bi : boxes)\n            {\n                std::vector<rectangle> rtemp;\n                for (auto&& b : bi)\n                {\n                    if (b.ignore)\n                        continue;\n                    rtemp.push_back(b.rect);\n                }\n                temp.push_back(std::move(rtemp));\n            }\n            overlaps_nms = find_tight_overlap_tester(temp);\n            // Relax the non-max-suppression a little so that it doesn't accidentally make\n            // it impossible for the detector to output boxes matching the training data.\n            // This could be a problem with the tightest possible nms test since there is\n            // some small variability in how boxes get positioned between the training data\n            // and the coordinate system used by the detector when it runs.  So relaxing it\n            // here takes care of that.\n            auto iou_thresh             = advance_toward_1(overlaps_nms.get_iou_thresh());\n            auto percent_covered_thresh = advance_toward_1(overlaps_nms.get_percent_covered_thresh());\n            overlaps_nms = test_box_overlap(iou_thresh, percent_covered_thresh);\n        }\n\n        static double advance_toward_1 (\n            double val\n        )\n        {\n            if (val < 1)\n                val += (1-val)*0.1;\n            return val;\n        }\n\n        static size_t count_overlaps (\n            const std::vector<rectangle>& rects,\n            const test_box_overlap& overlaps,\n            const rectangle& ref_box\n        )\n        {\n            size_t cnt = 0;\n            for (auto& b : rects)\n            {\n                if (overlaps(b, ref_box))\n                    ++cnt;\n            }\n            return cnt;\n        }\n\n        static std::vector<rectangle> find_rectangles_overlapping_all_others (\n            std::vector<rectangle> rects,\n            const test_box_overlap& overlaps\n        )\n        {\n            std::vector<rectangle> exemplars;\n            dlib::rand rnd;\n\n            while(rects.size() > 0)\n            {\n                // Pick boxes at random and see if they overlap a lot of other boxes.  We will try\n                // 500 different boxes each iteration and select whichever hits the most others to\n                // add to our exemplar set.\n                rectangle best_ref_box;\n                size_t best_cnt = 0;\n                for (int iter = 0; iter < 500; ++iter)\n                {\n                    rectangle ref_box = rects[rnd.get_random_64bit_number()%rects.size()];\n                    size_t cnt = count_overlaps(rects, overlaps, ref_box);\n                    if (cnt >= best_cnt)\n                    {\n                        best_cnt = cnt;\n                        best_ref_box = ref_box;\n                    }\n                }\n\n                // Now mark all the boxes the new ref box hit as hit.\n                for (size_t i = 0; i < rects.size(); ++i)\n                {\n                    if (overlaps(rects[i], best_ref_box))\n                    {\n                        // remove box from rects so we don't hit it again later\n                        swap(rects[i], rects.back());\n                        rects.pop_back();\n                        --i;\n                    }\n                }\n\n                exemplars.push_back(best_ref_box);\n            }\n\n            return exemplars;\n        }\n\n        static std::set<std::string> get_labels (\n            const std::vector<std::vector<mmod_rect>>& rects\n        )\n        {\n            std::set<std::string> labels;\n            for (auto& rr : rects)\n            {\n                for (auto& r : rr)\n                    labels.insert(r.label);\n            }\n            return labels;\n        }\n\n        static std::vector<double> find_covering_aspect_ratios (\n            const std::vector<std::vector<mmod_rect>>& rects,\n            const test_box_overlap& overlaps,\n            const std::string& label\n        )\n        {\n            std::vector<rectangle> boxes;\n            // Make sure all the boxes have the same size and position, so that the only thing our\n            // checks for overlap will care about is aspect ratio (i.e. scale and x,y position are\n            // ignored).\n            for (auto& bb : rects)\n            {\n                for (auto&& b : bb)\n                {\n                    if (!b.ignore && b.label == label)\n                        boxes.push_back(move_rect(set_rect_area(b.rect,400*400), point(0,0)));\n                }\n            }\n\n            std::vector<double> ratios;\n            for (auto r : find_rectangles_overlapping_all_others(boxes, overlaps))\n                ratios.push_back(r.width()/(double)r.height());\n            return ratios;\n        }\n\n        static std::vector<dlib::rectangle> find_covering_rectangles (\n            const std::vector<std::vector<mmod_rect>>& rects,\n            const test_box_overlap& overlaps,\n            const std::string& label\n        )\n        {\n            std::vector<rectangle> boxes;\n            // Make sure all the boxes have the same position, so that the we only check for\n            // width and height.\n            for (auto& bb : rects)\n            {\n                for (auto&& b : bb)\n                {\n                    if (!b.ignore && b.label == label)\n                        boxes.push_back(rectangle(b.rect.width(), b.rect.height()));\n                }\n            }\n\n            return find_rectangles_overlapping_all_others(boxes, overlaps);\n        }\n    };\n\n    inline void serialize(const mmod_options& item, std::ostream& out)\n    {\n        int version = 4;\n\n        serialize(version, out);\n        serialize(item.detector_windows, out);\n        serialize(item.loss_per_false_alarm, out);\n        serialize(item.loss_per_missed_target, out);\n        serialize(item.truth_match_iou_threshold, out);\n        serialize(item.overlaps_nms, out);\n        serialize(item.overlaps_ignore, out);\n        serialize(static_cast<uint8_t>(item.assume_image_pyramid), out);\n        serialize(item.use_bounding_box_regression, out);\n        serialize(item.bbr_lambda, out);\n    }\n\n    inline void deserialize(mmod_options& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (!(1 <= version && version <= 4))\n            throw serialization_error(\"Unexpected version found while deserializing dlib::mmod_options\");\n        if (version == 1)\n        {\n            unsigned long width;\n            unsigned long height;\n            deserialize(width, in);\n            deserialize(height, in);\n            item.detector_windows = {mmod_options::detector_window_details(width, height)};\n        }\n        else\n        {\n            deserialize(item.detector_windows, in);\n        }\n        deserialize(item.loss_per_false_alarm, in);\n        deserialize(item.loss_per_missed_target, in);\n        deserialize(item.truth_match_iou_threshold, in);\n        deserialize(item.overlaps_nms, in);\n        deserialize(item.overlaps_ignore, in);\n        item.assume_image_pyramid = use_image_pyramid::yes;\n        if (version >= 3)\n        {\n            uint8_t assume_image_pyramid = 0;\n            deserialize(assume_image_pyramid, in);\n            item.assume_image_pyramid = static_cast<use_image_pyramid>(assume_image_pyramid);\n        }\n        item.use_bounding_box_regression = mmod_options().use_bounding_box_regression; // use default value since this wasn't provided\n        item.bbr_lambda = mmod_options().bbr_lambda; // use default value since this wasn't provided\n        if (version >= 4)\n        {\n            deserialize(item.use_bounding_box_regression, in);\n            deserialize(item.bbr_lambda, in);\n        }\n    }\n\n    inline std::ostream& operator<<(std::ostream& out, const std::vector<mmod_options::detector_window_details>& detector_windows)\n    {\n        // write detector windows grouped by label\n        // example output: aeroplane:74x30,131x30,70x45,54x70,198x30;bicycle:70x57,32x70,70x32,51x70,128x30,30x121;car:70x36,70x60,99x30,52x70,30x83,30x114,30x200\n\n        std::map<std::string, std::deque<mmod_options::detector_window_details>> detector_windows_by_label;\n        for (const auto& detector_window : detector_windows)\n            detector_windows_by_label[detector_window.label].push_back(detector_window);\n\n        size_t label_count = 0;\n        for (const auto& i : detector_windows_by_label)\n        {\n            const auto& label = i.first;\n            const auto& detector_windows = i.second;\n\n            if (label_count++ > 0)\n                out << \";\";\n            out << label << \":\";\n\n            for (size_t j = 0; j < detector_windows.size(); ++j)\n            {\n                out << detector_windows[j].width << \"x\" << detector_windows[j].height;\n                if (j + 1 < detector_windows.size())\n                    out << \",\";\n            }\n        }\n\n        return out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mmod_ \n    {\n        struct intermediate_detection\n        {\n            intermediate_detection() = default; \n\n            intermediate_detection(\n                rectangle rect_\n            ) : rect(rect_), rect_bbr(rect_) {}\n\n            intermediate_detection(\n                rectangle rect_,\n                double detection_confidence_,\n                size_t tensor_offset_,\n                long channel\n            ) : rect(rect_), detection_confidence(detection_confidence_), tensor_offset(tensor_offset_), tensor_channel(channel), rect_bbr(rect_) {}\n\n            // rect is the rectangle you get without any bounding box regression.  So it's\n            // the basic sliding window box (aka, the \"anchor box\").\n            rectangle rect;\n            double detection_confidence = 0;\n            size_t tensor_offset = 0;\n            long tensor_channel = 0;\n\n            // rect_bbr = rect + bounding box regression.  So more accurate.  Or if bbr is off then\n            // this is just rect.  The important thing about rect_bbr is that its the\n            // rectangle we use for doing NMS.\n            drectangle rect_bbr; \n            size_t tensor_offset_dx = 0;\n            size_t tensor_offset_dy = 0;\n            size_t tensor_offset_dw = 0;\n            size_t tensor_offset_dh = 0;\n\n            bool operator<(const intermediate_detection& item) const { return detection_confidence < item.detection_confidence; }\n        };\n\n    public:\n\n        typedef std::vector<mmod_rect> training_label_type;\n        typedef std::vector<mmod_rect> output_label_type;\n\n        loss_mmod_() {}\n\n        loss_mmod_(mmod_options options_) : options(options_) {}\n\n        const mmod_options& get_options (\n        ) const { return options; }\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter,\n            double adjust_threshold = 0\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            if (options.use_bounding_box_regression)\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()*5);\n            }\n            else\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size());\n            }\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1,  sub.sample_expansion_factor());\n\n            std::vector<intermediate_detection> dets_accum;\n            output_label_type final_dets;\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                tensor_to_dets(input_tensor, output_tensor, i, dets_accum, adjust_threshold, sub);\n\n                // Do non-max suppression\n                final_dets.clear();\n                for (unsigned long i = 0; i < dets_accum.size(); ++i)\n                {\n                    if (overlaps_any_box_nms(final_dets, dets_accum[i].rect_bbr))\n                        continue;\n\n                    final_dets.push_back(mmod_rect(dets_accum[i].rect_bbr,\n                                                   dets_accum[i].detection_confidence,\n                                                   options.detector_windows[dets_accum[i].tensor_channel].label));\n                }\n\n                *iter++ = std::move(final_dets);\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            if (options.use_bounding_box_regression)\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()*5);\n            }\n            else\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size());\n            }\n\n            double det_thresh_speed_adjust = 0;\n\n            // we will scale the loss so that it doesn't get really huge\n            const double scale = 1.0/(output_tensor.nr()*output_tensor.nc()*output_tensor.num_samples()*options.detector_windows.size());\n            double loss = 0;\n\n            float* g = grad.host_write_only();\n            for (size_t i = 0; i < grad.size(); ++i)\n                g[i] = 0;\n\n            const float* out_data = output_tensor.host();\n\n            std::vector<intermediate_detection> dets;\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                tensor_to_dets(input_tensor, output_tensor, i, dets, -options.loss_per_false_alarm + det_thresh_speed_adjust, sub);\n\n                const unsigned long max_num_dets = 50 + truth->size()*5;\n                // Prevent calls to tensor_to_dets() from running for a really long time\n                // due to the production of an obscene number of detections.\n                const unsigned long max_num_initial_dets = max_num_dets*100;\n                if (dets.size() > max_num_initial_dets)\n                {\n                    det_thresh_speed_adjust = std::max(det_thresh_speed_adjust,dets[max_num_initial_dets].detection_confidence + options.loss_per_false_alarm);\n                }\n\n                std::vector<int> truth_idxs;\n                truth_idxs.reserve(truth->size());\n\n                std::unordered_map<size_t, rectangle> idx_to_truth_rect;\n\n                // The loss will measure the number of incorrect detections.  A detection is\n                // incorrect if it doesn't hit a truth rectangle or if it is a duplicate detection\n                // on a truth rectangle.\n                loss += truth->size()*options.loss_per_missed_target;\n                for (auto&& x : *truth)\n                {\n                    if (!x.ignore)\n                    {\n                        size_t k;\n                        point p;\n                        if(image_rect_to_feat_coord(p, input_tensor, x, x.label, sub, k, options.assume_image_pyramid))\n                        {\n                            // Ignore boxes that can't be detected by the CNN.\n                            loss -= options.loss_per_missed_target;\n                            truth_idxs.push_back(-1);\n                            continue;\n                        }\n                        const size_t idx = (k*output_tensor.nr() + p.y())*output_tensor.nc() + p.x();\n                        const auto i = idx_to_truth_rect.find(idx);\n                        if (i != idx_to_truth_rect.end())\n                        {\n                            if (!options.be_quiet) \n                            {\n                                // Ignore duplicate truth box in feature coordinates.\n                                std::cout << \"Warning, ignoring object.  We encountered a truth rectangle located at \" << x.rect;\n                                std::cout << \", and we are ignoring it because it maps to the exact same feature coordinates \";\n                                std::cout << \"as another truth rectangle located at \" << i->second << \".\" << std::endl;\n                            }\n\n                            loss -= options.loss_per_missed_target;\n                            truth_idxs.push_back(-1);\n                            continue;\n                        }\n                        loss -= out_data[idx];\n                        // compute gradient\n                        g[idx] = -scale;\n                        truth_idxs.push_back(idx);\n                        idx_to_truth_rect[idx] = x.rect;\n                    }\n                    else\n                    {\n                        // This box was ignored so shouldn't have been counted in the loss.\n                        loss -= options.loss_per_missed_target;\n                        truth_idxs.push_back(-1);\n                    }\n                }\n\n                // Measure the loss augmented score for the detections which hit a truth rect.\n                std::vector<double> truth_score_hits(truth->size(), 0);\n\n                // keep track of which truth boxes we have hit so far.\n                std::vector<bool> hit_truth_table(truth->size(), false);\n\n                std::vector<intermediate_detection> final_dets;\n                // The point of this loop is to fill out the truth_score_hits array. \n                for (size_t i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i)\n                {\n                    if (overlaps_any_box_nms(final_dets, dets[i].rect_bbr))\n                        continue;\n\n                    const auto& det_label = options.detector_windows[dets[i].tensor_channel].label;\n\n                    const std::pair<double,unsigned int> hittruth = find_best_match(*truth, hit_truth_table, dets[i].rect, det_label);\n\n                    final_dets.push_back(dets[i].rect);\n\n                    const double truth_match = hittruth.first;\n                    // if hit truth rect\n                    if (truth_match > options.truth_match_iou_threshold)\n                    {\n                        // if this is the first time we have seen a detect which hit (*truth)[hittruth.second]\n                        const double score = dets[i].detection_confidence;\n                        if (hit_truth_table[hittruth.second] == false)\n                        {\n                            hit_truth_table[hittruth.second] = true;\n                            truth_score_hits[hittruth.second] += score;\n                        }\n                        else\n                        {\n                            truth_score_hits[hittruth.second] += score + options.loss_per_false_alarm;\n                        }\n                    }\n                }\n\n                // Check if any of the truth boxes are unobtainable because the NMS is\n                // killing them.  If so, automatically set those unobtainable boxes to\n                // ignore and print a warning message to the user.\n                for (size_t i = 0; i < hit_truth_table.size(); ++i)\n                {\n                    if (!hit_truth_table[i] && !(*truth)[i].ignore) \n                    {\n                        // So we didn't hit this truth box.  Is that because there is\n                        // another, different truth box, that overlaps it according to NMS?\n                        const std::pair<double,unsigned int> hittruth = find_best_match(*truth, (*truth)[i], i);\n                        if (hittruth.second == i || (*truth)[hittruth.second].ignore)\n                            continue;\n                        rectangle best_matching_truth_box = (*truth)[hittruth.second];\n                        if (options.overlaps_nms(best_matching_truth_box, (*truth)[i]))\n                        {\n                            const int idx = truth_idxs[i];\n                            if (idx != -1)\n                            {\n                                // We are ignoring this box so we shouldn't have counted it in the\n                                // loss in the first place.  So we subtract out the loss values we\n                                // added for it in the code above.\n                                loss -= options.loss_per_missed_target-out_data[idx];\n                                g[idx] = 0;\n                                if (!options.be_quiet) \n                                {\n                                    std::cout << \"Warning, ignoring object.  We encountered a truth rectangle located at \" << (*truth)[i].rect;\n                                    std::cout << \" that is suppressed by non-max-suppression \";\n                                    std::cout << \"because it is overlapped by another truth rectangle located at \" << best_matching_truth_box \n                                        << \" (IoU:\"<< box_intersection_over_union(best_matching_truth_box,(*truth)[i]) <<\", Percent covered:\" \n                                        << box_percent_covered(best_matching_truth_box,(*truth)[i]) << \").\" << std::endl;\n                                }\n                            }\n                        }\n                    }\n                }\n\n                hit_truth_table.assign(hit_truth_table.size(), false);\n                final_dets.clear();\n\n                // Now figure out which detections jointly maximize the loss and detection score sum.  We\n                // need to take into account the fact that allowing a true detection in the output, while \n                // initially reducing the loss, may allow us to increase the loss later with many duplicate\n                // detections.\n                for (unsigned long i = 0; i < dets.size() && final_dets.size() < max_num_dets; ++i)\n                {\n                    if (overlaps_any_box_nms(final_dets, dets[i].rect_bbr))\n                        continue;\n\n                    const auto& det_label = options.detector_windows[dets[i].tensor_channel].label;\n\n                    const std::pair<double,unsigned int> hittruth = find_best_match(*truth, hit_truth_table, dets[i].rect, det_label);\n\n                    const double truth_match = hittruth.first;\n                    if (truth_match > options.truth_match_iou_threshold)\n                    {\n                        if (truth_score_hits[hittruth.second] > options.loss_per_missed_target)\n                        {\n                            if (!hit_truth_table[hittruth.second])\n                            {\n                                hit_truth_table[hittruth.second] = true;\n                                final_dets.push_back(dets[i]);\n                                loss -= options.loss_per_missed_target;\n\n                                // Now account for BBR loss and gradient if appropriate.\n                                if (options.use_bounding_box_regression)\n                                {\n                                    double dx = out_data[dets[i].tensor_offset_dx];\n                                    double dy = out_data[dets[i].tensor_offset_dy];\n                                    double dw = out_data[dets[i].tensor_offset_dw];\n                                    double dh = out_data[dets[i].tensor_offset_dh];\n\n                                    dpoint p = dcenter(dets[i].rect);\n                                    double w = dets[i].rect.width()-1;\n                                    double h = dets[i].rect.height()-1;\n                                    drectangle truth_box = (*truth)[hittruth.second].rect;\n                                    dpoint p_truth = dcenter(truth_box); \n\n                                    DLIB_CASSERT(w > 0);\n                                    DLIB_CASSERT(h > 0);\n\n                                    double target_dx = (p_truth.x() - p.x())/w;\n                                    double target_dy = (p_truth.y() - p.y())/h;\n                                    double target_dw = std::log((truth_box.width()-1)/w);\n                                    double target_dh = std::log((truth_box.height()-1)/h);\n\n\n                                    // compute smoothed L1 loss on BBR outputs.  This loss\n                                    // is just the MSE loss when the loss is small and L1\n                                    // when large.\n                                    dx = dx-target_dx;\n                                    dy = dy-target_dy;\n                                    dw = dw-target_dw;\n                                    dh = dh-target_dh;\n\n                                    // use smoothed L1 \n                                    double ldx = std::abs(dx)<1 ? 0.5*dx*dx : std::abs(dx)-0.5;\n                                    double ldy = std::abs(dy)<1 ? 0.5*dy*dy : std::abs(dy)-0.5;\n                                    double ldw = std::abs(dw)<1 ? 0.5*dw*dw : std::abs(dw)-0.5;\n                                    double ldh = std::abs(dh)<1 ? 0.5*dh*dh : std::abs(dh)-0.5;\n\n                                    loss += options.bbr_lambda*(ldx + ldy + ldw + ldh);\n      \n                                    // now compute the derivatives of the smoothed L1 loss\n                                    ldx = put_in_range(-1,1, dx);\n                                    ldy = put_in_range(-1,1, dy);\n                                    ldw = put_in_range(-1,1, dw);\n                                    ldh = put_in_range(-1,1, dh);\n\n\n                                    // also smoothed L1 gradient goes to gradient output\n                                    g[dets[i].tensor_offset_dx] += scale*options.bbr_lambda*ldx;\n                                    g[dets[i].tensor_offset_dy] += scale*options.bbr_lambda*ldy;\n                                    g[dets[i].tensor_offset_dw] += scale*options.bbr_lambda*ldw;\n                                    g[dets[i].tensor_offset_dh] += scale*options.bbr_lambda*ldh;\n                                }\n                            }\n                            else\n                            {\n                                final_dets.push_back(dets[i]);\n                                loss += options.loss_per_false_alarm;\n                            }\n                        }\n                    }\n                    else if (!overlaps_ignore_box(*truth, dets[i].rect))\n                    {\n                        // didn't hit anything\n                        final_dets.push_back(dets[i]);\n                        loss += options.loss_per_false_alarm;\n                    }\n                }\n\n                for (auto&& x : final_dets)\n                {\n                    loss += out_data[x.tensor_offset];\n                    g[x.tensor_offset] += scale;\n                }\n\n                ++truth;\n                g        += output_tensor.k()*output_tensor.nr()*output_tensor.nc();\n                out_data += output_tensor.k()*output_tensor.nr()*output_tensor.nc();\n            } // END for (long i = 0; i < output_tensor.num_samples(); ++i)\n\n\n            // Here we scale the loss so that it's roughly equal to the number of mistakes\n            // in an image.  Note that this scaling is different than the scaling we\n            // applied to the gradient but it doesn't matter since the loss value isn't\n            // used to update parameters.  It's used only for display and to check if we\n            // have converged.  So it doesn't matter that they are scaled differently and\n            // this way the loss that is displayed is readily interpretable to the user.\n            return loss/output_tensor.num_samples();\n        }\n\n\n        friend void serialize(const loss_mmod_& item, std::ostream& out)\n        {\n            serialize(\"loss_mmod_\", out);\n            serialize(item.options, out);\n        }\n\n        friend void deserialize(loss_mmod_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_mmod_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_mmod_.\");\n            deserialize(item.options, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_mmod_& item)\n        {\n            out << \"loss_mmod\\t (\";\n\n            auto& opts = item.options;\n\n            out << \"detector_windows:(\" << opts.detector_windows << \")\";\n\n            out << \", loss per FA:\" << opts.loss_per_false_alarm;\n            out << \", loss per miss:\" << opts.loss_per_missed_target;\n            out << \", truth match IOU thresh:\" << opts.truth_match_iou_threshold;\n            out << \", use_bounding_box_regression:\" << opts.use_bounding_box_regression;\n            if (opts.use_bounding_box_regression)\n                out << \", bbr_lambda:\" << opts.bbr_lambda;\n            out << \", overlaps_nms:(\"<<opts.overlaps_nms.get_iou_thresh()<<\",\"<<opts.overlaps_nms.get_percent_covered_thresh()<<\")\";\n            out << \", overlaps_ignore:(\"<<opts.overlaps_ignore.get_iou_thresh()<<\",\"<<opts.overlaps_ignore.get_percent_covered_thresh()<<\")\";\n\n            out << \")\";\n            return out;\n        }\n\n        friend void to_xml(const loss_mmod_& /*item*/, std::ostream& out)\n        {\n            // TODO, add options fields\n            out << \"<loss_mmod/>\\n\";\n        }\n\n    private:\n\n        template <typename net_type>\n        void tensor_to_dets (\n            const tensor& input_tensor,\n            const tensor& output_tensor,\n            long i,\n            std::vector<intermediate_detection>& dets_accum,\n            double adjust_threshold,\n            const net_type& net \n        ) const\n        {\n            DLIB_CASSERT(net.sample_expansion_factor() == 1,net.sample_expansion_factor());\n            if (options.use_bounding_box_regression)\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size()*5);\n            }\n            else\n            {\n                DLIB_CASSERT(output_tensor.k() == (long)options.detector_windows.size());\n            }\n\n            const float* out_data = output_tensor.host() + output_tensor.k()*output_tensor.nr()*output_tensor.nc()*i;\n            // scan the final layer and output the positive scoring locations\n            dets_accum.clear();\n            for (long k = 0; k < (long)options.detector_windows.size(); ++k)\n            {\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        double score = out_data[(k*output_tensor.nr() + r)*output_tensor.nc() + c];\n                        if (score > adjust_threshold)\n                        {\n                            dpoint p = output_tensor_to_input_tensor(net, point(c,r));\n                            drectangle rect = centered_drect(p, options.detector_windows[k].width, options.detector_windows[k].height);\n                            rect = input_layer(net).tensor_space_to_image_space(input_tensor,rect);\n\n                            dets_accum.push_back(intermediate_detection(rect, score, (k*output_tensor.nr() + r)*output_tensor.nc() + c, k));\n\n                            if (options.use_bounding_box_regression)\n                            {\n                                const auto offset = options.detector_windows.size() + k*4;\n                                dets_accum.back().tensor_offset_dx = ((offset+0)*output_tensor.nr() + r)*output_tensor.nc() + c;\n                                dets_accum.back().tensor_offset_dy = ((offset+1)*output_tensor.nr() + r)*output_tensor.nc() + c;\n                                dets_accum.back().tensor_offset_dw = ((offset+2)*output_tensor.nr() + r)*output_tensor.nc() + c;\n                                dets_accum.back().tensor_offset_dh = ((offset+3)*output_tensor.nr() + r)*output_tensor.nc() + c;\n\n                                // apply BBR to dets_accum.back()\n                                double dx = out_data[dets_accum.back().tensor_offset_dx];\n                                double dy = out_data[dets_accum.back().tensor_offset_dy];\n                                double dw = out_data[dets_accum.back().tensor_offset_dw];\n                                double dh = out_data[dets_accum.back().tensor_offset_dh];\n                                dw = std::exp(dw);\n                                dh = std::exp(dh);\n                                double w = rect.width()-1;\n                                double h = rect.height()-1;\n                                rect = translate_rect(rect, dpoint(dx*w,dy*h));\n                                rect = centered_drect(rect, w*dw+1, h*dh+1);\n                                dets_accum.back().rect_bbr = rect;\n                            }\n                        }\n                    }\n                }\n            }\n            std::sort(dets_accum.rbegin(), dets_accum.rend());\n        }\n\n        size_t find_best_detection_window (\n            rectangle rect,\n            const std::string& label,\n            use_image_pyramid assume_image_pyramid\n        ) const\n        {\n            if (assume_image_pyramid == use_image_pyramid::yes)\n            {\n                rect = move_rect(set_rect_area(rect, 400*400), point(0,0));\n            }\n            else\n            {\n                rect = rectangle(rect.width(), rect.height());\n            }\n\n            // Figure out which detection window in options.detector_windows is most similar to rect\n            // (in terms of aspect ratio, if assume_image_pyramid == use_image_pyramid::yes).\n            size_t best_i = 0;\n            double best_ratio_diff = -std::numeric_limits<double>::infinity();\n            for (size_t i = 0; i < options.detector_windows.size(); ++i)\n            {\n                if (options.detector_windows[i].label != label)\n                    continue;\n\n                rectangle det_window;\n                \n                if (options.assume_image_pyramid == use_image_pyramid::yes)\n                {\n                    det_window = centered_rect(point(0,0), options.detector_windows[i].width, options.detector_windows[i].height);\n                    det_window = move_rect(set_rect_area(det_window, 400*400), point(0,0));\n                }\n                else\n                {\n                    det_window = rectangle(options.detector_windows[i].width, options.detector_windows[i].height);\n                }\n\n                double iou = box_intersection_over_union(rect, det_window);\n                if (iou > best_ratio_diff)\n                {\n                    best_ratio_diff = iou;\n                    best_i = i;\n                }\n            }\n            return best_i;\n        }\n\n        template <typename net_type>\n        bool image_rect_to_feat_coord (\n            point& tensor_p,\n            const tensor& input_tensor,\n            const rectangle& rect,\n            const std::string& label,\n            const net_type& net,\n            size_t& det_idx,\n            use_image_pyramid assume_image_pyramid\n        ) const \n        {\n            if (!input_layer(net).image_contained_point(input_tensor,center(rect)))\n            {\n                std::ostringstream sout;\n                sout << \"Encountered a truth rectangle located at \" << rect << \" that is outside the image.\" << std::endl;\n                sout << \"The center of each truth rectangle must be within the image.\" << std::endl;\n                throw impossible_labeling_error(sout.str());\n            }\n\n            det_idx = find_best_detection_window(rect,label,assume_image_pyramid);\n\n            double scale = 1.0;\n            if (options.assume_image_pyramid == use_image_pyramid::yes)\n            {\n                // Compute the scale we need to be at to get from rect to our detection window.\n                // Note that we compute the scale as the max of two numbers.  It doesn't\n                // actually matter which one we pick, because if they are very different then\n                // it means the box can't be matched by the sliding window.  But picking the\n                // max causes the right error message to be selected in the logic below.\n                scale = std::max(options.detector_windows[det_idx].width/(double)rect.width(), options.detector_windows[det_idx].height/(double)rect.height());\n            }\n            else\n            {\n                // We don't want invariance to scale.\n                scale = 1.0;\n            }\n\n            const rectangle mapped_rect = input_layer(net).image_space_to_tensor_space(input_tensor, std::min(1.0,scale), rect);\n\n            // compute the detection window that we would use at this position.\n            tensor_p = center(mapped_rect);\n            rectangle det_window = centered_rect(tensor_p, options.detector_windows[det_idx].width,options.detector_windows[det_idx].height);\n            det_window = input_layer(net).tensor_space_to_image_space(input_tensor, det_window);\n\n            // make sure the rect can actually be represented by the image pyramid we are\n            // using.\n            if (box_intersection_over_union(rect, det_window) <= options.truth_match_iou_threshold)\n            {\n                std::cout << \"Warning, ignoring object.  We encountered a truth rectangle with a width and height of \" << rect.width() << \" and \" << rect.height() << \".  \";\n                std::cout << \"The image pyramid and sliding windows can't output a rectangle of this shape.  \";\n                const double detector_area = options.detector_windows[det_idx].width*options.detector_windows[det_idx].height;\n                if (mapped_rect.area()/detector_area <= options.truth_match_iou_threshold)\n                {\n                    std::cout << \"This is because the rectangle is smaller than the best matching detection window, which has a width \";\n                    std::cout << \"and height of \" << options.detector_windows[det_idx].width << \" and \" << options.detector_windows[det_idx].height << \".\" << std::endl;\n                }\n                else\n                {\n                    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 \";\n                    std::cout << \"or (2) because the rectangle's aspect ratio is too different from the best matching detection window, \";\n                    std::cout << \"which has a width and height of \" << options.detector_windows[det_idx].width << \" and \" << options.detector_windows[det_idx].height << \".\" << std::endl;\n                }\n                return true;\n            }\n\n            // now map through the CNN to the output layer.\n            tensor_p = input_tensor_to_output_tensor(net,tensor_p);\n\n            const tensor& output_tensor = net.get_output();\n            if (!get_rect(output_tensor).contains(tensor_p))\n            {\n                std::cout << \"Warning, ignoring object.  We encountered a truth rectangle located at \" << rect << \" that is too close to the edge \";\n                std::cout << \"of the image to be captured by the CNN features.\" << std::endl;\n                return true;\n            }\n\n            return false;\n        }\n\n\n        bool overlaps_ignore_box (\n            const std::vector<mmod_rect>& boxes,\n            const rectangle& rect\n        ) const\n        {\n            for (auto&& b : boxes)\n            {\n                if (b.ignore && options.overlaps_ignore(b, rect))\n                    return true;\n            }\n            return false;\n        }\n\n        std::pair<double,unsigned int> find_best_match(\n            const std::vector<mmod_rect>& boxes,\n            const std::vector<bool>& hit_truth_table,\n            const rectangle& rect,\n            const std::string& label\n        ) const\n        {\n            double match = 0;\n            unsigned int best_idx = 0;\n\n            for (int allow_duplicate_hit = 0; allow_duplicate_hit <= 1 && match == 0; ++allow_duplicate_hit)\n            {\n                for (unsigned long i = 0; i < boxes.size(); ++i)\n                {\n                    if (boxes[i].ignore || boxes[i].label != label)\n                        continue;\n                    if (!allow_duplicate_hit && hit_truth_table[i])\n                        continue;\n\n                    const double new_match = box_intersection_over_union(rect, boxes[i]);\n                    if (new_match > match)\n                    {\n                        match = new_match;\n                        best_idx = i;\n                    }\n                }\n            }\n\n            return std::make_pair(match,best_idx);\n        }\n\n        std::pair<double,unsigned int> find_best_match(\n            const std::vector<mmod_rect>& boxes,\n            const rectangle& rect,\n            const size_t excluded_idx\n        ) const\n        {\n            double match = 0;\n            unsigned int best_idx = 0;\n            for (unsigned long i = 0; i < boxes.size(); ++i)\n            {\n                if (boxes[i].ignore || excluded_idx == i)\n                    continue;\n\n                const double new_match = box_intersection_over_union(rect, boxes[i]);\n                if (new_match > match)\n                {\n                    match = new_match;\n                    best_idx = i;\n                }\n            }\n\n            return std::make_pair(match,best_idx);\n        }\n\n        template <typename T>\n        inline bool overlaps_any_box_nms (\n            const std::vector<T>& rects,\n            const rectangle& rect\n        ) const\n        {\n            for (auto&& r : rects)\n            {\n                if (options.overlaps_nms(r.rect, rect))\n                    return true;\n            }\n            return false;\n        }\n\n\n        mmod_options options;\n\n    };\n\n    template <typename SUBNET>\n    using loss_mmod = add_loss_layer<loss_mmod_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_metric_ \n    {\n    public:\n\n        typedef unsigned long training_label_type;\n        typedef matrix<float,0,1> output_label_type;\n\n        loss_metric_() = default;\n\n        loss_metric_(\n            float margin_,\n            float dist_thresh_\n        ) : margin(margin_), dist_thresh(dist_thresh_) \n        {\n            DLIB_CASSERT(margin_ > 0);\n            DLIB_CASSERT(dist_thresh_ > 0);\n        }\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1);\n\n            const float* p = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter = mat(p,output_tensor.k(),1);\n\n                ++iter;\n                p += output_tensor.k();\n            }\n        }\n\n\n        float get_margin() const { return margin; }\n        float get_distance_threshold() const { return dist_thresh; }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && \n                         output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && \n                         grad.nc() == 1);\n\n\n\n            temp.set_size(output_tensor.num_samples(), output_tensor.num_samples());\n            grad_mul.copy_size(temp);\n\n            tt::gemm(0, temp, 1, output_tensor, false, output_tensor, true);\n\n\n            std::vector<double> temp_threshs;\n            const float* d = temp.host();\n            double loss = 0;\n            double num_pos_samps = 0.0001;\n            double num_neg_samps = 0.0001;\n            for (long r = 0; r < temp.num_samples(); ++r)\n            {\n                auto xx = d[r*temp.num_samples() + r];\n                const auto x_label = *(truth + r);\n                for (long c = r+1; c < temp.num_samples(); ++c)\n                {\n                    const auto y_label = *(truth + c);\n                    if (x_label == y_label)\n                    {\n                        ++num_pos_samps;\n                    }\n                    else\n                    {\n                        ++num_neg_samps;\n\n                        // Figure out what distance threshold, when applied to the negative pairs,\n                        // causes there to be an equal number of positive and negative pairs.\n                        auto yy = d[c*temp.num_samples() + c];\n                        auto xy = d[r*temp.num_samples() + c];\n                        // compute the distance between x and y samples.\n                        auto d2 = xx + yy - 2*xy;\n                        if (d2 < 0)\n                            d2 = 0;\n                        temp_threshs.push_back(d2);\n                    }\n                }\n            }\n            // The whole objective function is multiplied by this to scale the loss\n            // relative to the number of things in the mini-batch.\n            const double scale = 0.5/num_pos_samps;\n            DLIB_CASSERT(num_pos_samps>=1, \"Make sure each mini-batch contains both positive pairs and negative pairs\");\n            DLIB_CASSERT(num_neg_samps>=1, \"Make sure each mini-batch contains both positive pairs and negative pairs\");\n\n            std::sort(temp_threshs.begin(), temp_threshs.end());\n            const float neg_thresh = std::sqrt(temp_threshs[std::min(num_pos_samps,num_neg_samps)-1]);\n\n            // loop over all the pairs of training samples and compute the loss and\n            // gradients.  Note that we only use the hardest negative pairs and that in\n            // particular we pick the number of negative pairs equal to the number of\n            // positive pairs so everything is balanced.\n            float* gm = grad_mul.host();\n            for (long r = 0; r < temp.num_samples(); ++r)\n            {\n                gm[r*temp.num_samples() + r] = 0;\n                const auto x_label = *(truth + r);\n                auto xx = d[r*temp.num_samples() + r];\n                for (long c = 0; c < temp.num_samples(); ++c)\n                {\n                    if (r==c)\n                        continue;\n                    const auto y_label = *(truth + c);\n                    auto yy = d[c*temp.num_samples() + c];\n                    auto xy = d[r*temp.num_samples() + c];\n\n                    // compute the distance between x and y samples.\n                    auto d2 = xx + yy - 2*xy;\n                    if (d2 <= 0)\n                        d2 = 0;\n                    else \n                        d2 = std::sqrt(d2);\n\n                    // It should be noted that the derivative of length(x-y) with respect\n                    // to the x vector is the unit vector (x-y)/length(x-y).  If you stare\n                    // at the code below long enough you will see that it's just an\n                    // application of this formula.\n\n                    if (x_label == y_label)\n                    {\n                        // Things with the same label should have distances < dist_thresh between\n                        // them.  If not then we experience non-zero loss.\n                        if (d2 < dist_thresh-margin)\n                        {\n                            gm[r*temp.num_samples() + c] = 0;\n                        }\n                        else\n                        {\n                            loss += scale*(d2 - (dist_thresh-margin));\n                            gm[r*temp.num_samples() + r] += scale/d2;\n                            gm[r*temp.num_samples() + c] = -scale/d2;\n                        }\n                    }\n                    else\n                    {\n                        // Things with different labels should have distances > dist_thresh between\n                        // them.  If not then we experience non-zero loss.\n                        if (d2 > dist_thresh+margin || d2 > neg_thresh)\n                        {\n                            gm[r*temp.num_samples() + c] = 0;\n                        }\n                        else\n                        {\n                            loss += scale*((dist_thresh+margin) - d2);\n                            // don't divide by zero (or a really small number)\n                            d2 = std::max(d2, 0.001f);\n                            gm[r*temp.num_samples() + r] -= scale/d2;\n                            gm[r*temp.num_samples() + c] = scale/d2;\n                        }\n                    }\n                }\n            }\n\n\n            tt::gemm(0, grad, 1, grad_mul, false, output_tensor, false); \n\n            return loss;\n        }\n\n        friend void serialize(const loss_metric_& item, std::ostream& out)\n        {\n            serialize(\"loss_metric_2\", out);\n            serialize(item.margin, out);\n            serialize(item.dist_thresh, out);\n        }\n\n        friend void deserialize(loss_metric_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"loss_metric_\")\n            {\n                // These values used to be hard coded, so for this version of the metric\n                // learning loss we just use these values.\n                item.margin = 0.1f;\n                item.dist_thresh = 0.75f;\n                return;\n            }\n            else if (version == \"loss_metric_2\")\n            {\n                deserialize(item.margin, in);\n                deserialize(item.dist_thresh, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_metric_.  Instead found \" + version);\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_metric_& item )\n        {\n            out << \"loss_metric (margin=\"<<item.margin<<\", distance_threshold=\"<<item.dist_thresh<<\")\";\n            return out;\n        }\n\n        friend void to_xml(const loss_metric_& item, std::ostream& out)\n        {\n            out << \"<loss_metric margin='\"<<item.margin<<\"' distance_threshold='\"<<item.dist_thresh<<\"'/>\\n\";\n        }\n\n    private:\n        float margin = 0.04f;\n        float dist_thresh = 0.6f;\n\n\n        // These variables are only here to avoid being reallocated over and over in\n        // compute_loss_value_and_gradient()\n        mutable resizable_tensor temp, grad_mul;\n\n    };\n\n    template <typename SUBNET>\n    using loss_metric = add_loss_layer<loss_metric_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_ranking_\n    {\n    public:\n\n        typedef float training_label_type; // nominally +1/-1\n        typedef float output_label_type; // ranking score\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = out_data[i];\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(grad.nr() == 1 &&\n                         grad.nc() == 1 &&\n                         grad.k() == 1);\n\n\n            std::vector<double> rel_scores;\n            std::vector<double> nonrel_scores;\n            std::vector<long> rel_idx, nonrel_idx;\n\n            const float* out_data = output_tensor.host();\n            float* g = grad.host_write_only();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const float y = *truth++;\n                if (y > 0)\n                {\n                    rel_scores.push_back(out_data[i]-y);\n                    rel_idx.push_back(i);\n                }\n                else if (y < 0)\n                {\n                    nonrel_scores.push_back(out_data[i]-y);\n                    nonrel_idx.push_back(i);\n                }\n                else\n                {\n                    g[i] = 0;\n                }\n            }\n\n\n            std::vector<unsigned long> rel_counts;\n            std::vector<unsigned long> nonrel_counts;\n            count_ranking_inversions(rel_scores, nonrel_scores, rel_counts, nonrel_counts);\n            const unsigned long total_pairs = rel_scores.size()*nonrel_scores.size();\n            DLIB_CASSERT(total_pairs > 0, \"You can't give a ranking mini-batch that contains only one class.  Both classes must be represented.\");\n            const double scale = 1.0/total_pairs;\n\n\n            double loss = 0;\n            for (unsigned long k = 0; k < rel_counts.size(); ++k)\n            {\n                loss -= rel_counts[k]*rel_scores[k];\n                g[rel_idx[k]] = -1.0*rel_counts[k]*scale;\n            }\n\n            for (unsigned long k = 0; k < nonrel_counts.size(); ++k)\n            {\n                loss += nonrel_counts[k]*nonrel_scores[k];\n                g[nonrel_idx[k]] = nonrel_counts[k]*scale;\n            }\n\n            return loss*scale;\n        }\n\n        friend void serialize(const loss_ranking_& , std::ostream& out)\n        {\n            serialize(\"loss_ranking_\", out);\n        }\n\n        friend void deserialize(loss_ranking_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_ranking_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_ranking_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_ranking_& )\n        {\n            out << \"loss_ranking\";\n            return out;\n        }\n\n        friend void to_xml(const loss_ranking_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_ranking/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_ranking = add_loss_layer<loss_ranking_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_\n    {\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = out_data[i];\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(grad.nr() == 1 &&\n                         grad.nc() == 1 &&\n                         grad.k() == 1);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host_write_only();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const float y = *truth++;\n                const float temp1 = y - out_data[i];\n                const float temp2 = scale*temp1;\n                loss += temp2*temp1;\n                g[i] = -temp2;\n\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_mean_squared_& , std::ostream& out)\n        {\n            serialize(\"loss_mean_squared_\", out);\n        }\n\n        friend void deserialize(loss_mean_squared_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_mean_squared_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_mean_squared_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_& )\n        {\n            out << \"loss_mean_squared\";\n            return out;\n        }\n\n        friend void to_xml(const loss_mean_squared_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_mean_squared/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared = add_loss_layer<loss_mean_squared_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_epsilon_insensitive_\n    {\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        loss_epsilon_insensitive_() = default;\n        loss_epsilon_insensitive_(double eps) : eps(eps) \n        {\n            DLIB_CASSERT(eps >= 0, \"You can't set a negative error epsilon.\");\n        }\n\n        double get_epsilon () const { return eps; }\n        void set_epsilon(double e)\n        {\n            DLIB_CASSERT(e >= 0, \"You can't set a negative error epsilon.\");\n            eps = e;\n        }\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = out_data[i];\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1 &&\n                         output_tensor.k() == 1);\n            DLIB_CASSERT(grad.nr() == 1 &&\n                         grad.nc() == 1 &&\n                         grad.k() == 1);\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host_write_only();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                const float y = *truth++;\n                const float err = out_data[i]-y;\n                if (err > eps)\n                {\n                    loss += scale*(err-eps);\n                    g[i] = scale;\n                }\n                else if (err < -eps)\n                {\n                    loss += scale*(eps-err);\n                    g[i] = -scale;\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_epsilon_insensitive_& item, std::ostream& out)\n        {\n            serialize(\"loss_epsilon_insensitive_\", out);\n            serialize(item.eps, out);\n        }\n\n        friend void deserialize(loss_epsilon_insensitive_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_epsilon_insensitive_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_epsilon_insensitive_.\");\n            deserialize(item.eps, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_epsilon_insensitive_& item)\n        {\n            out << \"loss_epsilon_insensitive epsilon: \" << item.eps;\n            return out;\n        }\n\n        friend void to_xml(const loss_epsilon_insensitive_& item, std::ostream& out)\n        {\n            out << \"<loss_epsilon_insensitive_ epsilon='\" << item.eps << \"'/>\\n\";\n        }\n\n    private:\n        double eps = 1;\n\n    };\n\n    template <typename SUBNET>\n    using loss_epsilon_insensitive = add_loss_layer<loss_epsilon_insensitive_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_multioutput_\n    {\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1)\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                *iter++ = mat(out_data, output_tensor.k(), 1);\n                out_data += output_tensor.k();\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 &&\n                         output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 &&\n                         grad.nc() == 1);\n            DLIB_CASSERT(grad.k() == output_tensor.k());\n            const long k = output_tensor.k();\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT((*truth_matrix_ptr).nr() == k &&\n                             (*truth_matrix_ptr).nc() == 1);\n            }\n\n            // The loss we output is the average loss over the mini-batch.\n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host_write_only();\n            const float* out_data = output_tensor.host();\n            matrix<float> ytrue;\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                ytrue = *truth++;\n                for (long j = 0; j < output_tensor.k(); ++j)\n                {\n                    const float y = ytrue(j, 0);\n                    const float temp1 = y - *out_data++;\n                    const float temp2 = scale*temp1;\n                    loss += temp2*temp1;\n                    *g = -temp2;\n                    ++g;\n                }\n\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_mean_squared_multioutput_& , std::ostream& out)\n        {\n            serialize(\"loss_mean_squared_multioutput_\", out);\n        }\n\n        friend void deserialize(loss_mean_squared_multioutput_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_mean_squared_multioutput_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_mean_squared_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_multioutput_& )\n        {\n            out << \"loss_mean_squared_multioutput\";\n            return out;\n        }\n\n        friend void to_xml(const loss_mean_squared_multioutput_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_mean_squared_multioutput/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared_multioutput = add_loss_layer<loss_mean_squared_multioutput_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_log_per_pixel_\n    {\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        static void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        )\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.k() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* const out_data = output_tensor.host();\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter) \n            {\n                iter->set_size(output_tensor.nr(), output_tensor.nc());\n                for (long r = 0; r < output_tensor.nr(); ++r) \n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c) \n                    {\n                        iter->operator()(r, c) = out_data[tensor_index(output_tensor, i, 0, r, c)];\n                    }\n                }\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.k() == 1);\n            DLIB_CASSERT(output_tensor.nr() == grad.nr() &&\n                         output_tensor.nc() == grad.nc() &&\n                         output_tensor.k() == grad.k());\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() &&\n                             truth_matrix_ptr->nc() == output_tensor.nc(),\n                             \"truth size = \" << truth_matrix_ptr->nr() << \" x \" << truth_matrix_ptr->nc() << \", \"\n                             \"output size = \" << output_tensor.nr() << \" x \" << output_tensor.nc());\n            }\n\n            double loss;\n#ifdef DLIB_USE_CUDA\n            cuda_compute(truth, output_tensor, grad, loss);\n#else\n            cpu_compute(truth, output_tensor, grad, loss);\n#endif\n            return loss;\n        }\n\n        friend void serialize(const loss_binary_log_per_pixel_& , std::ostream& out)\n        {\n            serialize(\"loss_binary_log_per_pixel_\", out);\n        }\n\n        friend void deserialize(loss_binary_log_per_pixel_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_binary_log_per_pixel_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_binary_log_per_pixel_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_binary_log_per_pixel_& )\n        {\n            out << \"loss_binary_log_per_pixel\";\n            return out;\n        }\n\n        friend void to_xml(const loss_binary_log_per_pixel_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_binary_log_per_pixel/>\\n\";\n        }\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        cuda::compute_loss_binary_log_per_pixel cuda_compute;\n#else\n        cpu::compute_loss_binary_log_per_pixel cpu_compute;\n#endif\n    };\n\n    template <typename SUBNET>\n    using loss_binary_log_per_pixel = add_loss_layer<loss_binary_log_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_per_pixel_\n    {\n    public:\n\n        // In semantic segmentation, if you don't know the ground-truth of some pixel,\n        // set the label of that pixel to this value. When you do so, the pixel will be\n        // ignored when computing gradients.\n        static const uint16_t label_to_ignore = std::numeric_limits<uint16_t>::max();\n\n\n        // In semantic segmentation, 65535 classes ought to be enough for anybody.\n        typedef matrix<uint16_t> training_label_type;\n        typedef matrix<uint16_t> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        static void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        )\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.k() >= 1); // Note that output_tensor.k() should match the number of labels.\n            DLIB_CASSERT(output_tensor.k() < std::numeric_limits<uint16_t>::max());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* const out_data = output_tensor.host();\n\n            // The index of the largest output for each element is the label.\n            const auto find_label = [&](long sample, long r, long c) \n            {\n                uint16_t label = 0;\n                float max_value = out_data[tensor_index(output_tensor, sample, 0, r, c)];\n                for (long k = 1; k < output_tensor.k(); ++k) \n                {\n                    const float value = out_data[tensor_index(output_tensor, sample, k, r, c)];\n                    if (value > max_value) \n                    {\n                        label = static_cast<uint16_t>(k);\n                        max_value = value;\n                    }\n                }\n                return label;\n            };\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter) \n            {\n                iter->set_size(output_tensor.nr(), output_tensor.nc());\n                for (long r = 0; r < output_tensor.nr(); ++r) \n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c) \n                    {\n                        // The index of the largest output for this element is the label.\n                        iter->operator()(r, c) = find_label(i, r, c);\n                    }\n                }\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.k() >= 1);\n            DLIB_CASSERT(output_tensor.k() < std::numeric_limits<uint16_t>::max());\n            DLIB_CASSERT(output_tensor.nr() == grad.nr() &&\n                         output_tensor.nc() == grad.nc() &&\n                         output_tensor.k() == grad.k());\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() &&\n                             truth_matrix_ptr->nc() == output_tensor.nc(),\n                             \"truth size = \" << truth_matrix_ptr->nr() << \" x \" << truth_matrix_ptr->nc() << \", \"\n                             \"output size = \" << output_tensor.nr() << \" x \" << output_tensor.nc());\n            }\n\n\n            double loss;\n#ifdef DLIB_USE_CUDA\n            cuda_compute(truth, output_tensor, grad, loss);\n#else\n            cpu_compute(truth, output_tensor, grad, loss);\n#endif\n            return loss;\n        }\n\n        friend void serialize(const loss_multiclass_log_per_pixel_& , std::ostream& out)\n        {\n            serialize(\"loss_multiclass_log_per_pixel_\", out);\n        }\n\n        friend void deserialize(loss_multiclass_log_per_pixel_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_multiclass_log_per_pixel_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multiclass_log_per_pixel_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_per_pixel_& )\n        {\n            out << \"loss_multiclass_log_per_pixel\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multiclass_log_per_pixel_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_multiclass_log_per_pixel/>\\n\";\n        }\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        cuda::compute_loss_multiclass_log_per_pixel cuda_compute;\n#else\n        cpu::compute_loss_multiclass_log_per_pixel cpu_compute;\n#endif\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_per_pixel = add_loss_layer<loss_multiclass_log_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_per_pixel_weighted_\n    {\n    public:\n\n        typedef dlib::weighted_label<uint16_t> weighted_label;\n        typedef matrix<weighted_label> training_label_type;\n        typedef matrix<uint16_t> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        static void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        )\n        {\n            loss_multiclass_log_per_pixel_::to_label(input_tensor, sub, iter);\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.k() >= 1);\n            DLIB_CASSERT(output_tensor.k() < std::numeric_limits<uint16_t>::max());\n            DLIB_CASSERT(output_tensor.nr() == grad.nr() &&\n                         output_tensor.nc() == grad.nc() &&\n                         output_tensor.k() == grad.k());\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() &&\n                             truth_matrix_ptr->nc() == output_tensor.nc(),\n                             \"truth size = \" << truth_matrix_ptr->nr() << \" x \" << truth_matrix_ptr->nc() << \", \"\n                             \"output size = \" << output_tensor.nr() << \" x \" << output_tensor.nc());\n            }\n\n            double loss;\n#ifdef DLIB_USE_CUDA\n            cuda_compute(truth, output_tensor, grad, loss);\n#else\n            cpu_compute(truth, output_tensor, grad, loss);\n#endif\n            return loss;\n        }\n\n        friend void serialize(const loss_multiclass_log_per_pixel_weighted_& , std::ostream& out)\n        {\n            serialize(\"loss_multiclass_log_per_pixel_weighted_\", out);\n        }\n\n        friend void deserialize(loss_multiclass_log_per_pixel_weighted_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_multiclass_log_per_pixel_weighted_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_multiclass_log_per_pixel_weighted_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_multiclass_log_per_pixel_weighted_& )\n        {\n            out << \"loss_multiclass_log_per_pixel_weighted\";\n            return out;\n        }\n\n        friend void to_xml(const loss_multiclass_log_per_pixel_weighted_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_multiclass_log_per_pixel_weighted/>\\n\";\n        }\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        cuda::compute_loss_multiclass_log_per_pixel_weighted cuda_compute;\n#else\n        cpu::compute_loss_multiclass_log_per_pixel_weighted cpu_compute;\n#endif\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_per_pixel_weighted = add_loss_layer<loss_multiclass_log_per_pixel_weighted_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_per_pixel_\n    {\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.k() == 1, \"output k = \" << output_tensor.k());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter)\n            {\n                iter->set_size(output_tensor.nr(), output_tensor.nc());\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        iter->operator()(r, c) = out_data[tensor_index(output_tensor, i, 0, r, c)];\n                    }\n                }\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples() % sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.k() >= 1);\n            DLIB_CASSERT(output_tensor.k() < std::numeric_limits<uint16_t>::max());\n            DLIB_CASSERT(output_tensor.nr() == grad.nr() &&\n                output_tensor.nc() == grad.nc() &&\n                output_tensor.k() == grad.k());\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT(truth_matrix_ptr->nr() == output_tensor.nr() &&\n                    truth_matrix_ptr->nc() == output_tensor.nc(),\n                    \"truth size = \" << truth_matrix_ptr->nr() << \" x \" << truth_matrix_ptr->nc() << \", \"\n                    \"output size = \" << output_tensor.nr() << \" x \" << output_tensor.nc());\n            }\n\n            // The loss we output is the average loss over the mini-batch, and also over each element of the matrix output.\n            const double scale = 1.0 / (output_tensor.num_samples() * output_tensor.nr() * output_tensor.nc());\n            double loss = 0;\n            float* const g = grad.host();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++truth)\n            {\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        const float y = truth->operator()(r, c);\n                        const size_t idx = tensor_index(output_tensor, i, 0, r, c);\n                        const float temp1 = y - out_data[idx];\n                        const float temp2 = scale*temp1;\n                        loss += temp2*temp1;\n                        g[idx] = -temp2;\n                    }\n                }\n            }\n            return loss;\n        }\n\n        friend void serialize(const loss_mean_squared_per_pixel_& , std::ostream& out)\n        {\n            serialize(\"loss_mean_squared_per_pixel_\", out);\n        }\n\n        friend void deserialize(loss_mean_squared_per_pixel_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_mean_squared_per_pixel_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_mean_squared_per_pixel_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_per_pixel_& )\n        {\n            out << \"loss_mean_squared_per_pixel\";\n            return out;\n        }\n\n        friend void to_xml(const loss_mean_squared_per_pixel_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_mean_squared_per_pixel/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared_per_pixel = add_loss_layer<loss_mean_squared_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template<long _num_channels>\n    class loss_mean_squared_per_channel_and_pixel_\n    {\n    public:\n\n        typedef std::array<matrix<float>, _num_channels> training_label_type;\n        typedef std::array<matrix<float>, _num_channels> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n\n            const tensor& output_tensor = sub.get_output();\n\n            DLIB_CASSERT(output_tensor.k() == _num_channels, \"output k = \" << output_tensor.k());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const float* out_data = output_tensor.host();\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i, ++iter)\n            {\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    (*iter)[k].set_size(output_tensor.nr(), output_tensor.nc());\n                    for (long r = 0; r < output_tensor.nr(); ++r)\n                    {\n                        for (long c = 0; c < output_tensor.nc(); ++c)\n                        {\n                            (*iter)[k].operator()(r, c) = out_data[tensor_index(output_tensor, i, k, r, c)];\n                        }\n                    }\n                }\n            }\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples() % sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.k() == _num_channels);\n            DLIB_CASSERT(output_tensor.nr() == grad.nr() &&\n                output_tensor.nc() == grad.nc() &&\n                output_tensor.k() == grad.k());\n            for (long idx = 0; idx < output_tensor.num_samples(); ++idx)\n            {\n                const_label_iterator truth_matrix_ptr = (truth + idx);\n                DLIB_CASSERT((*truth_matrix_ptr).size() == _num_channels);\n                for (long k = 0; k < output_tensor.k(); ++k)\n                {\n                    DLIB_CASSERT((*truth_matrix_ptr)[k].nr() == output_tensor.nr() &&\n                        (*truth_matrix_ptr)[k].nc() == output_tensor.nc(),\n                        \"truth size = \" << (*truth_matrix_ptr)[k].nr() << \" x \" << (*truth_matrix_ptr)[k].nc() << \", \"\n                        \"output size = \" << output_tensor.nr() << \" x \" << output_tensor.nc());\n                }\n            }\n            double loss;\n#ifdef DLIB_USE_CUDA\n            cuda_compute(truth, output_tensor, grad, loss);\n#else\n            cpu_compute(truth, output_tensor, grad, loss);\n#endif\n            return loss;\n        }\n\n        friend void serialize(const loss_mean_squared_per_channel_and_pixel_& , std::ostream& out)\n        {\n            serialize(\"loss_mean_squared_per_channel_and_pixel_\", out);\n        }\n\n        friend void deserialize(loss_mean_squared_per_channel_and_pixel_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_mean_squared_per_channel_and_pixel_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_mean_squared_per_channel_and_pixel_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_mean_squared_per_channel_and_pixel_& )\n        {\n            out << \"loss_mean_squared_per_channel_and_pixel\";\n            return out;\n        }\n\n        friend void to_xml(const loss_mean_squared_per_channel_and_pixel_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_mean_squared_per_channel_and_pixel/>\\n\";\n        }\n\n    private:\n\n#ifdef DLIB_USE_CUDA\n        cuda::compute_loss_mean_squared_per_channel_and_pixel cuda_compute;\n#else\n        cpu::compute_loss_mean_squared_per_channel_and_pixel cpu_compute;\n#endif\n    };\n\n    template <long num_channels, typename SUBNET>\n    using loss_mean_squared_per_channel_and_pixel = add_loss_layer<loss_mean_squared_per_channel_and_pixel_<num_channels>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_dot_\n    {\n    public:\n\n        typedef matrix<float,0,1> training_label_type;\n        typedef matrix<float,0,1> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n                *iter++ = trans(rowm(mat(output_tensor),i));\n        }\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples()%sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n\n            const long network_output_dims = output_tensor.size()/output_tensor.num_samples();\n\n\n            // The loss we output is the average loss over the mini-batch. \n            const double scale = 1.0/output_tensor.num_samples();\n            double loss = 0;\n            float* g = grad.host();\n            const float* out_data = output_tensor.host();\n            for (long i = 0; i < output_tensor.num_samples(); ++i)\n            {\n                DLIB_CASSERT(truth->size() == network_output_dims, \"The network must output a vector with the same dimensionality as the training labels. \"\n                    << \"\\ntruth->size():       \" << truth->size()\n                    << \"\\nnetwork_output_dims: \" << network_output_dims); \n\n                const float* t = &(*truth++)(0);\n\n                for (long j = 0; j < network_output_dims; ++j)\n                {\n                    g[j] = -t[j]*scale;\n                    loss -= out_data[j]*t[j];\n                }\n\n                g += network_output_dims;\n                out_data += network_output_dims;\n            }\n            return loss*scale;\n        }\n\n        friend void serialize(const loss_dot_& , std::ostream& out)\n        {\n            serialize(\"loss_dot_\", out);\n        }\n\n        friend void deserialize(loss_dot_& , std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_dot_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_dot_.\");\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_dot_& )\n        {\n            out << \"loss_dot\";\n            return out;\n        }\n\n        friend void to_xml(const loss_dot_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_dot/>\\n\";\n        }\n\n    };\n\n    template <typename SUBNET>\n    using loss_dot = add_loss_layer<loss_dot_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    struct yolo_options\n    {\n    public:\n        struct anchor_box_details\n        {\n            anchor_box_details() = default;\n            anchor_box_details(unsigned long w, unsigned long h) : width(w), height(h) {}\n\n            unsigned long width = 0;\n            unsigned long height = 0;\n\n            friend inline void serialize(const anchor_box_details& item, std::ostream& out)\n            {\n                int version = 0;\n                serialize(version, out);\n                serialize(item.width, out);\n                serialize(item.height, out);\n            }\n\n            friend inline void deserialize(anchor_box_details& item, std::istream& in)\n            {\n                int version = 0;\n                deserialize(version, in);\n                deserialize(item.width, in);\n                deserialize(item.height, in);\n            }\n        };\n\n        yolo_options() = default;\n\n        template <template <typename> class TAG_TYPE>\n        void add_anchors(const std::vector<anchor_box_details>& boxes)\n        {\n            anchors[tag_id<TAG_TYPE>::id] = boxes;\n        }\n\n        // map between the stride and the anchor boxes\n        std::map<int, std::vector<anchor_box_details>> anchors;\n        std::vector<std::string> labels;\n        double iou_ignore_threshold = 0.7;\n        double iou_anchor_threshold = 1.0;\n        test_box_overlap overlaps_nms = test_box_overlap(0.45, 1.0);\n        bool classwise_nms = true;\n        double lambda_obj = 1.0;\n        double lambda_box = 1.0;\n        double lambda_cls = 1.0;\n        double gamma_obj = 0.0;\n        double gamma_cls = 0.0;\n\n    };\n\n    inline void serialize(const yolo_options& item, std::ostream& out)\n    {\n        int version = 2;\n        serialize(version, out);\n        serialize(item.anchors, out);\n        serialize(item.labels, out);\n        serialize(item.iou_ignore_threshold, out);\n        serialize(item.iou_anchor_threshold, out);\n        serialize(item.classwise_nms, out);\n        serialize(item.overlaps_nms, out);\n        serialize(item.lambda_obj, out);\n        serialize(item.lambda_box, out);\n        serialize(item.lambda_cls, out);\n        serialize(item.gamma_obj, out);\n        serialize(item.gamma_cls, out);\n    }\n\n    inline void deserialize(yolo_options& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (!(1 <= version && version <= 2))\n            throw serialization_error(\"Unexpected version found while deserializing dlib::yolo_options.\");\n        deserialize(item.anchors, in);\n        deserialize(item.labels, in);\n        deserialize(item.iou_ignore_threshold, in);\n        deserialize(item.iou_anchor_threshold, in);\n        deserialize(item.classwise_nms, in);\n        deserialize(item.overlaps_nms, in);\n        deserialize(item.lambda_obj, in);\n        deserialize(item.lambda_box, in);\n        deserialize(item.lambda_cls, in);\n        if (version >= 2)\n        {\n            deserialize(item.gamma_obj, in);\n            deserialize(item.gamma_cls, in);\n        }\n    }\n\n    inline std::ostream& operator<<(std::ostream& out, const std::map<int, std::vector<yolo_options::anchor_box_details>>& anchors)\n    {\n        // write anchor boxes grouped by tag id\n        size_t tag_count = 0;\n        for (const auto& i : anchors)\n        {\n            const auto& tag_id = i.first;\n            const auto& details = i.second;\n            if (tag_count++ > 0)\n                out << \";\";\n            out << \"tag\" << tag_id << \":\";\n            for (size_t a = 0; a < details.size(); ++a)\n            {\n                out << details[a].width << \"x\" << details[a].height;\n                if (a + 1 < details.size())\n                    out << \",\";\n            }\n        }\n        return out;\n    }\n\n    namespace impl\n    {\n        template <template <typename> class TAG_TYPE, template <typename> class... TAG_TYPES>\n        struct yolo_helper_impl\n        {\n            constexpr static size_t tag_count()\n            {\n                return 1 + yolo_helper_impl<TAG_TYPES...>::tag_count();\n            }\n\n            static void list_tags(std::ostream& out)\n            {\n                out << \"tag\" << tag_id<TAG_TYPE>::id << (tag_count() > 1 ? \",\" : \"\");\n                yolo_helper_impl<TAG_TYPES...>::list_tags(out);\n            }\n\n            template <typename SUBNET>\n            static void tensor_to_dets (\n                const tensor& input_tensor,\n                const SUBNET& sub,\n                const long n,\n                const yolo_options& options,\n                const double adjust_threshold,\n                std::vector<yolo_rect>& dets\n            )\n            {\n                yolo_helper_impl<TAG_TYPE>::tensor_to_dets(input_tensor, sub, n, options, adjust_threshold, dets);\n                yolo_helper_impl<TAG_TYPES...>::tensor_to_dets(input_tensor, sub, n, options, adjust_threshold, dets);\n            }\n\n            template <\n                typename const_label_iterator,\n                typename SUBNET\n            >\n            static void tensor_to_loss (\n                const tensor& input_tensor,\n                const_label_iterator truth,\n                SUBNET& sub,\n                const long n,\n                const yolo_options& options,\n                double& loss\n            )\n            {\n                yolo_helper_impl<TAG_TYPE>::tensor_to_loss(input_tensor, truth, sub, n, options, loss);\n                yolo_helper_impl<TAG_TYPES...>::tensor_to_loss(input_tensor, truth, sub, n, options, loss);\n            }\n        };\n\n        template <template <typename> class TAG_TYPE>\n        struct yolo_helper_impl<TAG_TYPE>\n        {\n            constexpr static size_t tag_count() { return 1; }\n\n            static void list_tags(std::ostream& out) { out << \"tag\" << tag_id<TAG_TYPE>::id; }\n\n            template <typename SUBNET>\n            static void tensor_to_dets (\n                const tensor& input_tensor,\n                const SUBNET& sub,\n                const long n,\n                const yolo_options& options,\n                const double adjust_threshold,\n                std::vector<yolo_rect>& dets\n            )\n            {\n                const auto& anchors = options.anchors.at(tag_id<TAG_TYPE>::id);\n                const tensor& output_tensor = layer<TAG_TYPE>(sub).get_output();\n                DLIB_CASSERT(static_cast<size_t>(output_tensor.k()) == anchors.size() * (options.labels.size() + 5));\n                const auto stride_x = static_cast<double>(input_tensor.nc()) / output_tensor.nc();\n                const auto stride_y = static_cast<double>(input_tensor.nr()) / output_tensor.nr();\n                const long num_feats = output_tensor.k() / anchors.size();\n                const long num_classes = num_feats - 5;\n                const float* const out_data = output_tensor.host();\n\n                for (size_t a = 0; a < anchors.size(); ++a)\n                {\n                    const long k = a * num_feats;\n                    for (long r = 0; r < output_tensor.nr(); ++r)\n                    {\n                        for (long c = 0; c < output_tensor.nc(); ++c)\n                        {\n                            const double obj = out_data[tensor_index(output_tensor, n, k + 4, r, c)];\n                            if (obj > adjust_threshold)\n                            {\n                                // The scaling and shifting in the x and y coordinates avoids the grid sensitivity\n                                // effect by allowing the network to output centers along the grid boundaries.\n                                const double x = out_data[tensor_index(output_tensor, n, k + 0, r, c)] * 2.0 - 0.5;\n                                const double y = out_data[tensor_index(output_tensor, n, k + 1, r, c)] * 2.0 - 0.5;\n                                const double w = out_data[tensor_index(output_tensor, n, k + 2, r, c)];\n                                const double h = out_data[tensor_index(output_tensor, n, k + 3, r, c)];\n                                yolo_rect det(centered_drect(dpoint((x + c) * stride_x, (y + r) * stride_y),\n                                                             w / (1 - w) * anchors[a].width,\n                                                             h / (1 - h) * anchors[a].height));\n                                for (long i = 0; i < num_classes; ++i)\n                                {\n                                    const double conf = obj * out_data[tensor_index(output_tensor, n, k + 5 + i, r, c)];\n                                    if (conf > adjust_threshold)\n                                        det.labels.emplace_back(conf, options.labels[i]);\n                                }\n                                if (!det.labels.empty())\n                                {\n                                    std::sort(det.labels.rbegin(), det.labels.rend());\n                                    det.detection_confidence = det.labels[0].first;\n                                    det.label = det.labels[0].second;\n                                    dets.push_back(std::move(det));\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            template <\n                typename const_label_iterator,\n                typename SUBNET\n            >\n            static void tensor_to_loss (\n                const tensor& input_tensor,\n                const_label_iterator truth,\n                SUBNET& sub,\n                const long n,\n                const yolo_options& options,\n                double& loss\n            )\n            {\n                const tensor& output_tensor = layer<TAG_TYPE>(sub).get_output();\n                const auto& anchors = options.anchors.at(tag_id<TAG_TYPE>::id);\n                DLIB_CASSERT(static_cast<size_t>(output_tensor.k()) == anchors.size() * (options.labels.size() + 5));\n                const auto stride_x = static_cast<double>(input_tensor.nc()) / output_tensor.nc();\n                const auto stride_y = static_cast<double>(input_tensor.nr()) / output_tensor.nr();\n                const long num_feats = output_tensor.k() / anchors.size();\n                const long num_classes = num_feats - 5;\n                const float* const out_data = output_tensor.host();\n                tensor& grad = layer<TAG_TYPE>(sub).get_gradient_input();\n                DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n                DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n                const drectangle input_rect = rectangle(input_tensor.nr(), input_tensor.nc());\n                const auto input_area = input_rect.area();\n                float* g = grad.host();\n\n                // Compute the objectness loss for all grid cells\n                for (long r = 0; r < output_tensor.nr(); ++r)\n                {\n                    for (long c = 0; c < output_tensor.nc(); ++c)\n                    {\n                        for (size_t a = 0; a < anchors.size(); ++a)\n                        {\n                            const long k = a * num_feats;\n                            const double x = out_data[tensor_index(output_tensor, n, k + 0, r, c)] * 2.0 - 0.5;\n                            const double y = out_data[tensor_index(output_tensor, n, k + 1, r, c)] * 2.0 - 0.5;\n                            const double w = out_data[tensor_index(output_tensor, n, k + 2, r, c)];\n                            const double h = out_data[tensor_index(output_tensor, n, k + 3, r, c)];\n\n                            // The prediction at r, c for anchor a\n                            const yolo_rect pred(centered_drect(dpoint((x + c) * stride_x, (y + r) * stride_y),\n                                                                w / (1 - w) * anchors[a].width,\n                                                                h / (1 - h) * anchors[a].height));\n\n                            // Find the best IoU for all ground truth boxes\n                            double best_iou = 0;\n                            for (const yolo_rect& truth_box : *truth)\n                            {\n                                if (truth_box.ignore || !input_rect.contains(center(truth_box.rect)))\n                                    continue;\n                                best_iou = std::max(best_iou, box_intersection_over_union(truth_box.rect, pred.rect));\n                            }\n\n                            // Incur loss for the boxes that are below a certain IoU threshold with any truth box\n                            if (best_iou < options.iou_ignore_threshold)\n                            {\n                                const auto o_idx = tensor_index(output_tensor, n, k + 4, r, c);\n                                const double p = out_data[o_idx];\n                                const double focus = std::pow(p, options.gamma_obj);\n                                const double g_obj = focus * (options.gamma_obj * (1 - p) * safe_log(1 - p) + p);\n                                g[o_idx] = options.lambda_obj * g_obj;\n                            }\n                        }\n                    }\n                }\n\n                // Now find the best anchor box for each truth box\n                for (const yolo_rect& truth_box : *truth)\n                {\n                    if (truth_box.ignore || !input_rect.contains(center(truth_box.rect)))\n                        continue;\n                    const auto truth_box_area = truth_box.rect.area();\n                    const auto t_center = center(truth_box.rect);\n                    double best_iou = 0;\n                    size_t best_a = 0;\n                    size_t best_tag_id = 0;\n                    running_stats<double> ious;\n                    for (const auto& item : options.anchors)\n                    {\n                        const auto tag_id = item.first;\n                        const auto details = item.second;\n                        for (size_t a = 0; a < details.size(); ++a)\n                        {\n                            const auto anchor(centered_drect(t_center, details[a].width, details[a].height));\n                            const double iou = box_intersection_over_union(truth_box.rect, anchor);\n                            if (iou > best_iou)\n                            {\n                                best_iou = iou;\n                                best_a = a;\n                                best_tag_id = tag_id;\n                                ious.add(iou);\n                            }\n                        }\n                    }\n\n                    // ATSS: Adaptive Training Sample Selection\n                    double iou_anchor_threshold = options.iou_anchor_threshold;\n                    if (iou_anchor_threshold == 0)\n                        iou_anchor_threshold = ious.mean() + ious.stddev();\n\n                    for (size_t a = 0; a < anchors.size(); ++a)\n                    {\n                        // We will always backpropagate on the best anchor, regardless of its IOU.\n                        // For other anchors, only if they have an IOU >= iou_anchor_threshold.\n                        if (!(best_tag_id == tag_id<TAG_TYPE>::id && best_a == a))\n                        {\n                            if (iou_anchor_threshold >= 1)\n                                continue;\n                            const auto anchor(centered_drect(t_center, anchors[a].width, anchors[a].height));\n                            if (box_intersection_over_union(truth_box.rect, anchor) < iou_anchor_threshold)\n                                continue;\n                        }\n\n                        const long c = t_center.x() / stride_x;\n                        const long r = t_center.y() / stride_y;\n                        const long k = a * num_feats;\n\n                        // Get the truth box target values\n                        const double tx = t_center.x() / stride_x - c;\n                        const double ty = t_center.y() / stride_y - r;\n                        const double tw = truth_box.rect.width() / (anchors[a].width + truth_box.rect.width());\n                        const double th = truth_box.rect.height() / (anchors[a].height + truth_box.rect.height());\n\n                        // Scale regression error according to the truth size\n                        const double scale_box = options.lambda_box * (2.0 - truth_box_area / input_area);\n\n                        // Compute the smoothed L1 gradient for the box coordinates\n                        const auto x_idx = tensor_index(output_tensor, n, k + 0, r, c);\n                        const auto y_idx = tensor_index(output_tensor, n, k + 1, r, c);\n                        const auto w_idx = tensor_index(output_tensor, n, k + 2, r, c);\n                        const auto h_idx = tensor_index(output_tensor, n, k + 3, r, c);\n                        g[x_idx] = scale_box * put_in_range(-1, 1, (out_data[x_idx] * 2.0 - 0.5 - tx)) * 2.0f;\n                        g[y_idx] = scale_box * put_in_range(-1, 1, (out_data[y_idx] * 2.0 - 0.5 - ty)) * 2.0f;\n                        g[w_idx] = scale_box * put_in_range(-1, 1, (out_data[w_idx] - tw));\n                        g[h_idx] = scale_box * put_in_range(-1, 1, (out_data[h_idx] - th));\n\n                        // This grid cell should detect an object\n                        const auto o_idx = tensor_index(output_tensor, n, k + 4, r, c);\n                        {\n                            const auto p = out_data[o_idx];\n                            const double focus = std::pow(1 - p, options.gamma_obj);\n                            const double g_obj = focus * (options.gamma_obj * p * safe_log(p) + p - 1);\n                            g[o_idx] = options.lambda_obj * g_obj;\n                        }\n\n                        // Compute the classification error using the truth weights and the focal loss\n                        for (long i = 0; i < num_classes; ++i)\n                        {\n                            const auto c_idx = tensor_index(output_tensor, n, k + 5 + i, r, c);\n                            const auto p = out_data[c_idx];\n                            if (truth_box.label == options.labels[i])\n                            {\n                                const double focus = std::pow(1 - p, options.gamma_cls);\n                                const double g_cls = focus * (options.gamma_cls * p * safe_log(p) + p - 1);\n                                g[c_idx] = truth_box.detection_confidence * options.lambda_cls * g_cls;\n                            }\n                            else\n                            {\n                                const double focus = std::pow(p, options.gamma_cls);\n                                const double g_cls = focus * (options.gamma_cls * (1 - p) * safe_log(1 - p) + p);\n                                g[c_idx] = options.lambda_cls * g_cls;\n                            }\n                        }\n                    }\n                }\n\n                // The loss is the squared norm of the gradient\n                loss += 0.5 * length_squared(rowm(mat(grad), n));\n            }\n        };\n    }\n\n    template <template <typename> class... TAG_TYPES>\n    class loss_yolo_\n    {\n        static void list_tags(std::ostream& out) { impl::yolo_helper_impl<TAG_TYPES...>::list_tags(out); }\n\n    public:\n\n        typedef std::vector<yolo_rect> training_label_type;\n        typedef std::vector<yolo_rect> output_label_type;\n\n        constexpr static size_t tag_count() { return impl::yolo_helper_impl<TAG_TYPES...>::tag_count(); }\n\n        loss_yolo_() {};\n\n        loss_yolo_(const yolo_options& options) : options(options) { }\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter,\n            double adjust_threshold = 0.25\n        ) const\n        {\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1, sub.sample_expansion_factor());\n            std::vector<yolo_rect> dets_accum;\n            std::vector<yolo_rect> final_dets;\n            for (long i = 0; i < input_tensor.num_samples(); ++i)\n            {\n                dets_accum.clear();\n                impl::yolo_helper_impl<TAG_TYPES...>::tensor_to_dets(input_tensor, sub, i, options, adjust_threshold, dets_accum);\n\n                // Do non-max suppression\n                std::sort(dets_accum.rbegin(), dets_accum.rend());\n                final_dets.clear();\n                for (size_t j = 0; j < dets_accum.size(); ++j)\n                {\n                    if (overlaps_any_box_nms(final_dets, dets_accum[j]))\n                        continue;\n\n                    final_dets.push_back(dets_accum[j]);\n                }\n\n                *iter++ = std::move(final_dets);\n            }\n        }\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n        >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const\n        {\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(sub.sample_expansion_factor() == 1, sub.sample_expansion_factor());\n            double loss = 0;\n            for (long i = 0; i < input_tensor.num_samples(); ++i)\n            {\n                impl::yolo_helper_impl<TAG_TYPES...>::tensor_to_loss(input_tensor, truth, sub, i, options, loss);\n                ++truth;\n            }\n            return loss / input_tensor.num_samples();\n        }\n\n        const yolo_options& get_options() const { return options; }\n\n        void adjust_nms(double iou_thresh, double percent_covered_thresh = 1, bool classwise = true)\n        {\n            options.overlaps_nms = test_box_overlap(iou_thresh, percent_covered_thresh);\n            options.classwise_nms = classwise;\n        }\n\n        friend void serialize(const loss_yolo_& item, std::ostream& out)\n        {\n            serialize(\"loss_yolo_\", out);\n            size_t count = tag_count();\n            serialize(count, out);\n            serialize(item.options, out);\n        }\n\n        friend void deserialize(loss_yolo_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"loss_yolo_\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_yolo_.\");\n            size_t count = 0;\n            deserialize(count, in);\n            if (count != tag_count())\n                throw serialization_error(\"Invalid number of detection tags \" + std::to_string(count) +\n                                          \", while deserializing dlib::loss_yolo_, expecting \" +\n                                          std::to_string(tag_count()) + \" tags instead.\");\n            deserialize(item.options, in);\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_yolo_& item)\n        {\n            out << \"loss_yolo\\t (\";\n            const auto& opts = item.options;\n            out << tag_count() << \" output\" << (tag_count() != 1 ? \"s\" : \"\") << \":(\";\n            list_tags(out);\n            out << \")\";\n            out << \", anchor_boxes:(\" << opts.anchors << \")\";\n            out << \", \" << opts.labels.size() << \" label\" << (opts.labels.size() != 1 ? \"s\" : \"\") << \":(\";\n            for (size_t i = 0; i < opts.labels.size(); ++i)\n            {\n                out << opts.labels[i];\n                if (i + 1 < opts.labels.size())\n                    out << \",\";\n            }\n            out << \")\";\n            out << \", iou_ignore_threshold: \" << opts.iou_ignore_threshold;\n            out << \", iou_anchor_threshold: \" << opts.iou_anchor_threshold;\n            out << \", lambda_obj:\" << opts.lambda_obj;\n            out << \", lambda_box:\" << opts.lambda_box;\n            out << \", lambda_cls:\" << opts.lambda_cls;\n            out << \", gamma_obj:\" << opts.gamma_obj;\n            out << \", gamma_cls:\" << opts.gamma_cls;\n            out << \", overlaps_nms:(\" << opts.overlaps_nms.get_iou_thresh() << \",\" << opts.overlaps_nms.get_percent_covered_thresh() << \")\";\n            out << \", classwise_nms:\" << std::boolalpha << opts.classwise_nms;\n            out << \")\";\n            return out;\n        }\n\n        friend void to_xml(const loss_yolo_& /*item*/, std::ostream& out)\n        {\n            out << \"<loss_yolo/>\\n\";\n        }\n\n    private:\n\n        yolo_options options;\n\n        inline bool overlaps_any_box_nms (\n            const std::vector<yolo_rect>& boxes,\n            const yolo_rect& box\n        ) const\n        {\n            for (const auto& b : boxes)\n            {\n                if (options.overlaps_nms(b.rect, box.rect))\n                {\n                    if (options.classwise_nms)\n                    {\n                        if (b.label == box.label)\n                            return true;\n                    }\n                    else\n                    {\n                        return true;\n                    }\n                }\n            }\n            return false;\n        }\n    };\n\n    template <template <typename> class TAG_1, template <typename> class TAG_2, template <typename> class TAG_3, typename SUBNET>\n    using loss_yolo = add_loss_layer<loss_yolo_<TAG_1, TAG_2, TAG_3>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_barlow_twins_\n    {\n    public:\n\n        loss_barlow_twins_() = default;\n\n        loss_barlow_twins_(float lambda) : lambda(lambda)\n        {\n            DLIB_CASSERT(lambda > 0);\n        }\n\n        template <\n            typename SUBNET\n        >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            SUBNET& sub\n        ) const\n        {\n            const tensor& output_tensor = sub.get_output();\n            tensor& grad = sub.get_gradient_input();\n\n            DLIB_CASSERT(sub.sample_expansion_factor() == 2);\n            DLIB_CASSERT(input_tensor.num_samples() != 0);\n            DLIB_CASSERT(input_tensor.num_samples() % sub.sample_expansion_factor() == 0);\n            DLIB_CASSERT(input_tensor.num_samples() == grad.num_samples());\n            DLIB_CASSERT(input_tensor.num_samples() == output_tensor.num_samples());\n            DLIB_CASSERT(output_tensor.nr() == 1 && output_tensor.nc() == 1);\n            DLIB_CASSERT(grad.nr() == 1 && grad.nc() == 1);\n\n            const auto batch_size = output_tensor.num_samples() / 2;\n            const auto sample_size = output_tensor.k();\n            const auto offset = batch_size * sample_size;\n\n            // Alias helpers to access the samples in the batch\n            alias_tensor split(batch_size, sample_size);\n            auto za = split(output_tensor);\n            auto zb = split(output_tensor, offset);\n\n            // Normalize both batches independently across the batch dimension\n            const double eps = 1e-4;\n            g.set_size(1, sample_size);\n            g = 1;\n            b.set_size(1, sample_size);\n            b = 0;\n            tt::batch_normalize(eps, za_norm, means_a, invstds_a, 1, rms, rvs, za, g, b);\n            tt::batch_normalize(eps, zb_norm, means_b, invstds_b, 1, rms, rvs, zb, g, b);\n\n            // Compute the empirical cross-correlation matrix\n            eccm.set_size(sample_size, sample_size);\n            tt::gemm(0, eccm, 1, za_norm, true, zb_norm, false);\n            eccm /= batch_size;\n\n            // Set sizes and setup auxiliary tensors\n            if (!have_same_dimensions(eccm, identity))\n                identity = identity_matrix<float>(sample_size);\n            if (!have_same_dimensions(eccm, cdiag))\n                cdiag.copy_size(eccm);\n            if (!have_same_dimensions(eccm, cdiag_1))\n                cdiag_1.copy_size(eccm);\n            if (!have_same_dimensions(eccm, off_mask))\n                off_mask = ones_matrix<float>(sample_size, sample_size) - identity_matrix<float>(sample_size);\n            if (!have_same_dimensions(eccm, off_diag))\n                off_diag.copy_size(eccm);\n            if (!have_same_dimensions(grad, grad_input))\n                grad_input.copy_size(grad);\n            if (!have_same_dimensions(g_grad, g))\n                g_grad.copy_size(g);\n            if (!have_same_dimensions(b_grad, b))\n                b_grad.copy_size(b);\n\n            // Loss gradient, which will be used as the input of the batch normalization gradient\n            auto grad_input_a = split(grad_input);\n            auto grad_input_b = split(grad_input, offset);\n\n            // Compute the loss: notation from http://www.matrixcalculus.org/\n            // A = za_norm\n            // B = zb_norm\n            // C = eccm\n            // D = off_mask: a mask that keeps only the elements outside the diagonal\n\n            // A diagonal matrix containing the diagonal of eccm\n            tt::multiply(false, cdiag, eccm, identity);\n            // The diagonal of eccm minus the identity matrix\n            tt::affine_transform(cdiag_1, cdiag, identity, 1, -1);\n\n            // diagonal term: sum((diag(A' * B) - vector(1)).^2)\n            // --------------------------------------------\n            // \t=> d/dA = 2 * B * diag(diag(A' * B) - vector(1)) = 2 * B * diag(diag(C) - vector(1))\n            // \t=> d/dB = 2 * A * diag(diag(A' * B) - vector(1)) = 2 * A * diag(diag(C) - vector(1))\n            tt::gemm(0, grad_input_a, 2.0 / batch_size, zb_norm, false, cdiag_1, false);\n            tt::gemm(0, grad_input_b, 2.0 / batch_size, za_norm, false, cdiag_1, false);\n\n            // off-diag term: sum(((A'* B) .* D).^2)\n            // --------------------------------\n            //  => d/dA = 2 * B * ((B' * A) .* (D .* D)') = 2 * B * (C' .* (D .* D)) = 2 * B * (C' .* D)\n            //  => d/dB = 2 * A * ((A' * B) .* (D .* D))  = 2 * A * (C .* (D .* D)) = 2 * A * (C .* D)\n            tt::multiply(false, off_diag, eccm, off_mask);\n            tt::gemm(1, grad_input_a, lambda * 2.0 / batch_size, zb_norm, false, off_diag, true);\n            tt::gemm(1, grad_input_b, lambda * 2.0 / batch_size, za_norm, false, off_diag, false);\n\n            // Compute the batch norm gradients, g and b grads are not used\n            auto gza = split(grad);\n            auto gzb = split(grad, offset);\n            tt::batch_normalize_gradient(eps, grad_input_a, means_a, invstds_a, za, g, gza, g_grad, b_grad);\n            tt::batch_normalize_gradient(eps, grad_input_b, means_b, invstds_b, zb, g, gzb, g_grad, b_grad);\n\n            // Compute the loss: MSE between eccm and the identity matrix.\n            // Off-diagonal terms are weighed by lambda.\n            const double diagonal_loss = sum(squared(mat(cdiag_1)));\n            const double off_diag_loss = sum(squared(mat(off_diag)));\n            return diagonal_loss + lambda * off_diag_loss;\n        }\n\n        float get_lambda() const  { return lambda; }\n\n        tensor& get_eccm() { return eccm; }\n        const tensor& get_eccm() const { return eccm; }\n\n        friend void serialize(const loss_barlow_twins_& item, std::ostream& out)\n        {\n            serialize(\"loss_barlow_twins_\", out);\n            serialize(item.lambda, out);\n        }\n\n        friend void deserialize(loss_barlow_twins_& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version == \"loss_barlow_twins_\")\n            {\n                deserialize(item.lambda, in);\n            }\n            else\n            {\n                throw serialization_error(\"Unexpected version found while deserializing dlib::loss_barlow_twins_.  Instead found \" + version);\n            }\n        }\n\n        friend std::ostream& operator<<(std::ostream& out, const loss_barlow_twins_& item)\n        {\n            out << \"loss_barlow_twins (lambda=\" << item.lambda << \")\";\n            return out;\n        }\n\n        friend void to_xml(const loss_barlow_twins_& item, std::ostream& out)\n        {\n            out << \"<loss_barlow_twins lambda='\" << item.lambda << \"'/>\\n\";\n        }\n\n    private:\n        float lambda = 0.0051;\n        mutable resizable_tensor za_norm, means_a, invstds_a;\n        mutable resizable_tensor zb_norm, means_b, invstds_b;\n        mutable resizable_tensor rms, rvs, g, b;\n        mutable resizable_tensor eccm, grad_input, g_grad, b_grad;\n        mutable resizable_tensor cdiag, cdiag_1, identity, off_mask, off_diag;\n    };\n\n    template <typename SUBNET>\n    using loss_barlow_twins = add_loss_layer<loss_barlow_twins_, SUBNET>;\n\n}\n\n#endif // DLIB_DNn_LOSS_H_\n\n"
  },
  {
    "path": "dlib/dnn/loss_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_LOSS_ABSTRACT_H_\n#ifdef DLIB_DNn_LOSS_ABSTRACT_H_\n\n#include \"core_abstract.h\"\n#include \"../image_processing/full_object_detection_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class EXAMPLE_LOSS_LAYER_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                A loss layer is the final layer in a deep neural network.  It computes the\n                task loss.  That is, it computes a number that tells us how well the\n                network is performing on some task, such as predicting a binary label.  \n\n                You can use one of the loss layers that comes with dlib (defined below).\n                But importantly, you are able to define your own loss layers to suit your\n                needs.  You do this by creating a class that defines an interface matching\n                the one described by this EXAMPLE_LOSS_LAYER_ class.  Note that there is no\n                dlib::EXAMPLE_LOSS_LAYER_ type.  It is shown here purely to document the\n                interface that a loss layer must implement.\n\n                A loss layer can optionally provide a to_label() method that converts the\n                output of a network into a user defined type.  If to_label() is not\n                provided then the operator() methods of add_loss_layer will not be\n                available, but otherwise everything will function as normal.\n\n                Finally, note that there are two broad flavors of loss layer, supervised\n                and unsupervised.  The EXAMPLE_LOSS_LAYER_ as shown here is a supervised\n                layer.  To make an unsupervised loss you simply leave out the\n                training_label_type typedef and the truth iterator argument to\n                compute_loss_value_and_gradient().\n        !*/\n\n    public:\n\n        // In most cases training_label_type and output_label_type will be the same type.\n        typedef whatever_type_you_use_for_training_labels training_label_type;\n        typedef whatever_type_you_use_for_outout_labels   output_label_type;\n\n        EXAMPLE_LOSS_LAYER_ (\n        );\n        /*!\n            ensures\n                - EXAMPLE_LOSS_LAYER_ objects are default constructable.\n        !*/\n\n        EXAMPLE_LOSS_LAYER_ (\n            const EXAMPLE_LOSS_LAYER_& item\n        );\n        /*!\n            ensures\n                - EXAMPLE_LOSS_LAYER_ objects are copy constructable.\n        !*/\n\n        // Implementing to_label() is optional.\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of\n                  layers_abstract.h.\n                - input_tensor was given as input to the network sub and the outputs are\n                  now visible in layer<i>(sub).get_output(), for all valid i.\n                - input_tensor.num_samples() > 0\n                - input_tensor.num_samples()%sub.sample_expansion_factor() == 0.\n                - iter == an iterator pointing to the beginning of a range of\n                  input_tensor.num_samples()/sub.sample_expansion_factor() elements.  Moreover,\n                  they must be output_label_type elements.\n            ensures\n                - Converts the output of the provided network to output_label_type objects and\n                  stores the results into the range indicated by iter.  In particular, for\n                  all valid i, it will be the case that:\n                    *(iter+i/sub.sample_expansion_factor()) is populated based on the output of\n                    sub and corresponds to the ith sample in input_tensor.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            requires\n                - SUBNET implements the SUBNET interface defined at the top of\n                  layers_abstract.h.\n                - input_tensor was given as input to the network sub and the outputs are\n                  now visible in layer<i>(sub).get_output(), for all valid i.\n                - input_tensor.num_samples() > 0\n                - input_tensor.num_samples()%sub.sample_expansion_factor() == 0.\n                - for all valid i:\n                    - layer<i>(sub).get_gradient_input() has the same dimensions as\n                      layer<i>(sub).get_output().\n                    - layer<i>(sub).get_gradient_input() contains all zeros (i.e.\n                      initially, all input gradients are 0).\n                - truth == an iterator pointing to the beginning of a range of\n                  input_tensor.num_samples()/sub.sample_expansion_factor() elements.  Moreover,\n                  they must be training_label_type elements.\n                - for all valid i:\n                    - *(truth+i/sub.sample_expansion_factor()) is the label of the ith sample in\n                      input_tensor.\n            ensures\n                - This function computes a loss function that describes how well the output\n                  of sub matches the expected labels given by truth.  Let's write the loss\n                  function as L(input_tensor, truth, sub).  \n                - Then compute_loss_value_and_gradient() computes the gradient of L() with\n                  respect to the outputs in sub.  Specifically, compute_loss_value_and_gradient() \n                  assigns the gradients into sub by performing the following tensor\n                  assignments, for all valid i: \n                    - layer<i>(sub).get_gradient_input() = the gradient of\n                      L(input_tensor,truth,sub) with respect to layer<i>(sub).get_output().\n                      Note that, since get_gradient_input() is zero initialized, you don't\n                      have to write gradient information to layers that have a zero\n                      loss gradient.\n                - returns L(input_tensor,truth,sub)\n        !*/\n    };\n\n    std::ostream& operator<<(std::ostream& out, const EXAMPLE_LOSS_LAYER_& item);\n    /*!\n        print a string describing this layer.\n    !*/\n\n    void to_xml(const EXAMPLE_LOSS_LAYER_& item, std::ostream& out);\n    /*!\n        This function is optional, but required if you want to print your networks with\n        net_to_xml().  Therefore, to_xml() prints a layer as XML.\n    !*/\n\n    void serialize(const EXAMPLE_LOSS_LAYER_& item, std::ostream& out);\n    void deserialize(EXAMPLE_LOSS_LAYER_& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    // For each loss layer you define, always define an add_loss_layer template so that\n    // layers can be easily composed.  Moreover, the convention is that the layer class\n    // ends with an _ while the add_loss_layer template has the same name but without the\n    // trailing _.\n    template <typename SUBNET>\n    using EXAMPLE_LOSS_LAYER = add_loss_layer<EXAMPLE_LOSS_LAYER_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_hinge_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the hinge loss, which is\n                appropriate for binary classification problems.  Therefore, the possible\n                labels when using this loss are +1 and -1.  Moreover, it will cause the\n                network to produce outputs > 0 when predicting a member of the +1 class and\n                values < 0 otherwise.\n        !*/\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the raw score for each classified object.  If the score\n            is > 0 then the classifier is predicting the +1 class, otherwise it is\n            predicting the -1 class.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all values pointed to by truth are +1 or -1.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_binary_hinge = add_loss_layer<loss_binary_hinge_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_log_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the log loss, which is\n                appropriate for binary classification problems.  Therefore, there are two possible\n                classes of labels: positive (> 0) and negative (< 0) when using this loss.\n                The absolute value of the label represents its weight.  Putting a larger weight\n                on a sample increases the importance of getting its prediction correct during \n                training.  A good rule of thumb is to use weights with absolute value 1 unless \n                you have a very unbalanced training dataset, in that case, give larger weight\n                to the class with less training examples.\n                \n                This loss will cause the network to produce outputs > 0 when predicting a\n                member of the positive class and values < 0 otherwise.\n\n                To be more specific, this object contains a sigmoid layer followed by a \n                cross-entropy layer.  \n        !*/\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the raw score for each classified object.  If the score\n            is > 0 then the classifier is predicting the +1 class, otherwise it is\n            predicting the -1 class.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all values pointed to by truth are non-zero.  Nominally they should be +1 or -1,\n                  each indicating the desired class label.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_binary_log = add_loss_layer<loss_binary_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the multiclass logistic\n                regression loss (e.g. negative log-likelihood loss), which is appropriate\n                for multiclass classification problems.  This means that the possible\n                labels when using this loss are integers >= 0.  \n                \n                Moreover, if after training you were to replace the loss layer of the\n                network with a softmax layer, the network outputs would give the\n                probabilities of each class assignment.  That is, if you have K classes\n                then the network should output tensors with the tensor::k()'th dimension\n                equal to K.  Applying softmax to these K values gives the probabilities of\n                each class.  The index into that K dimensional vector with the highest\n                probability is the predicted class label.\n        !*/\n\n    public:\n\n        typedef unsigned long training_label_type;\n        typedef unsigned long output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted class for each classified object.  The number\n            of possible output classes is sub.get_output().k().\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all values pointed to by truth are < sub.get_output().k()\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log = add_loss_layer<loss_multiclass_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename label_type>\n    struct weighted_label\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the truth label of a single sample, together with\n                an associated weight (the higher the weight, the more emphasis the\n                corresponding sample is given during the training).\n                For technical reasons, it is defined in misc.h\n                This object is used in the following loss layers:\n                    - loss_multiclass_log_weighted_ with unsigned long as label_type\n                    - loss_multiclass_log_per_pixel_weighted_ with uint16_t as label_type,\n                      since, in semantic segmentation, 65536 classes ought to be enough for\n                      anybody.\n        !*/\n        weighted_label()\n        {}\n\n        weighted_label(label_type label, float weight = 1.f)\n            : label(label), weight(weight)\n        {}\n\n        // The ground truth label\n        label_type label{};\n\n        // The weight of the corresponding sample\n        float weight = 1.f;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_weighted_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the multiclass logistic\n                regression loss (e.g. negative log-likelihood loss), which is appropriate\n                for multiclass classification problems.  It is basically just like the\n                loss_multiclass_log except that it lets you define per-sample weights,\n                which might be useful e.g. if you want to emphasize rare classes while\n                training.  If the classification problem is difficult, a flat weight\n                structure may lead the network to always predict the most common label,\n                in particular if the degree of imbalance is high.  To emphasize a certain\n                class or classes, simply increase the weights of the corresponding samples,\n                relative to the weights of other pixels.\n\n                Note that if you set all the weights equals to 1, then you get\n                loss_multiclass_log_ as a special case.\n        !*/\n\n    public:\n\n        typedef dlib::weighted_label<unsigned long> weighted_label;\n        typedef weighted_label training_label_type;\n        typedef unsigned long output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted class for each classified object.  The number\n            of possible output classes is sub.get_output().k().\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all values pointed to by truth are < sub.get_output().k()\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_weighted = add_loss_layer<loss_multiclass_log_weighted_, SUBNET>;// ----------------------------------------------------------------------------------------\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multimulticlass_log_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements a collection of\n                multiclass classifiers.  An example will make its use clear.  So suppose,\n                for example, that you want to make something that takes a picture of a\n                vehicle and answers the following questions:\n                    - What type of vehicle is it? A sedan or a truck?\n                    - What color is it? red, green, blue, gray, or black?\n                You need two separate multi-class classifiers to do this.  One to decide\n                the type of vehicle, and another to decide the color.  The\n                loss_multimulticlass_log_ allows you to pack these two classifiers into one\n                neural network.  This means that when you use the network to process an\n                image it will output 2 labels for each image, the type label and the color\n                label.  \n\n                To create a loss_multimulticlass_log_ for the above case you would\n                construct it as follows:\n                    std::map<std::string,std::vector<std::string>> labels;\n                    labels[\"type\"] = {\"sedan\", \"truck\"};\n                    labels[\"color\"] = {\"red\", \"green\", \"blue\", \"gray\", \"black\"};\n                    loss_multimulticlass_log_ myloss(labels);\n                Then you could use myloss with a network object and train it to do this\n                task.  More generally, you can use any number of classifiers and labels\n                when using this object.  Finally, each of the classifiers uses a standard\n                multi-class logistic regression loss.\n        !*/\n\n    public:\n\n        loss_multimulticlass_log_(\n        ); \n        /*!\n            ensures\n                - #number_of_labels() == 0\n                - #get_labels().size() == 0\n        !*/\n\n        loss_multimulticlass_log_ (\n            const std::map<std::string,std::vector<std::string>>& labels\n        );\n        /*!\n            requires\n                - Each vector in labels must contain at least 2 strings.  I.e. each\n                  classifier must have at least two possible labels.\n            ensures\n                - #number_of_labels() == the total number of strings in all the\n                  std::vectors in labels.\n                - #number_of_classifiers() == labels.size()\n                - #get_labels() == labels\n        !*/\n\n        unsigned long number_of_labels(\n        ) const; \n        /*!\n            ensures\n                - returns the total number of labels known to this loss.  This is the count of \n                  all the labels in each classifier.\n        !*/\n\n        unsigned long number_of_classifiers(\n        ) const; \n        /*!\n            ensures\n                - returns the number of classifiers defined by this loss.\n        !*/\n\n        std::map<std::string,std::vector<std::string>> get_labels ( \n        ) const;\n        /*!\n            ensures\n                - returns the names of the classifiers and labels used by this loss.  In\n                  particular, if the returned object is L then:\n                    - L[CLASS] == the set of labels used by the classifier CLASS.\n                    - L.size() == number_of_classifiers()\n                    - The count of strings in the vectors in L == number_of_labels()\n        !*/\n\n        class classifier_output\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object stores the predictions from one of the classifiers in\n                    loss_multimulticlass_log_.  It allows you to find out the most likely\n                    string label predicted by that classifier, as well as get the class\n                    conditional probability of any of the classes in the classifier.\n            !*/\n\n        public:\n\n            classifier_output(\n            );\n            /*!\n                ensures\n                    - #num_classes() == 0\n            !*/\n\n            size_t num_classes(\n            ) const; \n            /*!\n                ensures\n                    - returns the number of possible classes output by this classifier.\n            !*/\n\n            double probability_of_class (\n                size_t i\n            ) const;\n            /*!\n                requires\n                    - i < num_classes()\n                ensures\n                    - returns the probability that the true class has a label of label(i).\n                    - The sum of probability_of_class(j) for j in the range [0, num_classes()) is always 1.\n            !*/\n\n            const std::string& label(\n                size_t i\n            ) const;\n            /*!\n                requires\n                    - i < num_classes()\n                ensures\n                    - returns the string label for the ith class.\n            !*/\n\n            operator std::string(\n            ) const;\n            /*!\n                requires\n                    - num_classes() != 0\n                ensures\n                    - returns the string label for the most probable class.\n            !*/\n\n            friend std::ostream& operator<< (std::ostream& out, const classifier_output& item);\n            /*!\n                requires\n                    - num_classes() != 0\n                ensures\n                    - prints the most probable class label to out.\n            !*/\n\n        };\n\n        // Both training_label_type and output_label_type should always have sizes equal to\n        // number_of_classifiers().  That is, the std::map should have an entry for every\n        // classifier known to this loss.\n        typedef std::map<std::string,std::string> training_label_type;\n        typedef std::map<std::string,classifier_output> output_label_type;\n\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - number_of_labels() != 0\n                - sub.get_output().k() == number_of_labels()\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - number_of_labels() != 0\n                - sub.get_output().k() == number_of_labels()\n                    It should be noted that the last layer in your network should usually\n                    be an fc layer.  If so, you can satisfy this requirement of k() being\n                    number_of_labels() by calling set_num_outputs() prior to training your\n                    network like so:\n                    your_network.subnet().layer_details().set_num_outputs(your_network.loss_details().number_of_labels());\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - All the std::maps pointed to by truth contain entries for all the\n                  classifiers known to this loss.  That is, it must be valid to call\n                  truth[i][classifier] for any of the classifiers known to this loss.  To\n                  say this another way, all the training samples must contain labels for\n                  each of the classifiers defined by this loss.\n\n                  To really belabor this, this also means that truth[i].size() ==\n                  get_labels().size() and that both truth[i] and get_labels() have the same\n                  set of key strings.  It also means that the value strings in truth[i]\n                  must be strings known to the loss, i.e. they are valid labels according\n                  to get_labels().\n        !*/\n    };\n\n    template <typename SUBNET>\n    using loss_multimulticlass_log = add_loss_layer<loss_multimulticlass_log_, SUBNET>;\n\n    // Allow comparison between classifier_outputs and std::string to check if the\n    // predicted class is a particular string.\n    inline bool operator== (const std::string& lhs, const loss_multimulticlass_log_::classifier_output& rhs)\n    { return lhs == static_cast<const std::string&>(rhs); }\n    inline bool operator== (const loss_multimulticlass_log_::classifier_output& lhs, const std::string& rhs)\n    { return rhs == static_cast<const std::string&>(lhs); }\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multibinary_log_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements a collection of\n                binary classifiers using the log loss, which is appropriate for\n                binary classification problems where each sample can belong to zero\n                or more categories.  Therefore, there are two possible classes of labels:\n                positive (> 0) and negative (< 0) when using this loss.\n                The absolute value of the label represents its weight.  Putting a larger\n                weight on a sample increases its importance of getting its prediction\n                correct during training.  A good rule of thumb is to use weights with\n                absolute value 1 unless you have a very unbalanced training dataset,\n                in that case, give larger weight to the class with less training examples.\n\n                This loss will cause the network to produce outputs > 0 when predicting a\n                member of the positive classes and values < 0 otherwise.\n\n                To be more specific, this object contains a sigmoid layer followed by a\n                cross-entropy layer.\n\n                Additionaly, this layer also contains a focusing parameter gamma, which\n                acts as a modulating factor to the cross-entropy layer by reducing the\n                relative loss for well-classified examples, and focusing on the difficult\n                ones.  This gamma parameter makes this layer behave like the Focal loss,\n                presented in the paper:\n                    Focal Loss for Dense Object Detection\n                    by Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He, Piotr Dollár\n                    (https://arxiv.org/abs/1708.02002)\n\n                An example will make its use clear.  So suppose, for example, that you want\n                to make a classifier for cats and dogs, but what happens if they both\n                appear in one image? Or none of them? This layer allows you to handle\n                those use cases by using the following labels:\n                    - std::vector<float> dog_label = {1.f, -1.f};\n                    - std::vector<float> cat_label = {-1.f , 1.f};\n                    - std::vector<float> both_label = {1.f, 1.f};\n                    - std::vector<float> none_label = {-1.f, -1.f};\n        !*/\n\n    public:\n        typedef std::vector<float> training_label_type;\n        typedef std::vector<float> output_label_type;\n\n        loss_multibinary_log_ (\n        );\n        /*!\n            ensures\n                - #get_gamma() == 0\n        !*/\n\n        loss_multibinary_log_(double gamma);\n        /*!\n            requires\n                - gamma >= 0\n            ensures\n                - #get_gamma() == gamma\n        !*/\n\n        double get_gamma() const;\n        /*!\n            ensures\n                - returns the gamma value used by the loss function.\n        !*/\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output labels are the raw scores for each classified object.  If a score\n            is > 0 then the classifier is predicting the +1 class for that category, otherwise\n            it is predicting the -1 class.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - truth points to training_label_type elements, each of size sub.get_output.k().\n                  The elements of each truth training_label_type instance are nominally +1 or -1,\n                  each representing a binary class label.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_multibinary_log = add_loss_layer<loss_multibinary_log_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum class use_image_pyramid : uint8_t\n    {\n        no,\n        yes\n    };\n\n    struct mmod_options\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object contains all the parameters that control the behavior of loss_mmod_.\n        !*/\n\n    public:\n\n        struct detector_window_details\n        {\n            detector_window_details() = default; \n            detector_window_details(unsigned long w, unsigned long h) : width(w), height(h) {}\n            detector_window_details(unsigned long w, unsigned long h, const std::string& l) : width(w), height(h), label(l) {}\n\n            unsigned long width = 0;\n            unsigned long height = 0;\n            std::string label;\n\n            friend inline void serialize(const detector_window_details& item, std::ostream& out);\n            friend inline void deserialize(detector_window_details& item, std::istream& in);\n        };\n\n        mmod_options() = default;\n\n        // This kind of object detector is a sliding window detector.  The detector_windows\n        // field determines how many sliding windows we will use and what the shape of each\n        // window is.  It also determines the output label applied to each detection\n        // identified by each window.  Since you will usually use the MMOD loss with an\n        // image pyramid, the detector sizes also determine the size of the smallest object\n        // you can detect.\n        std::vector<detector_window_details> detector_windows;\n\n        // These parameters control how we penalize different kinds of mistakes.  See \n        // Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046)\n        // for further details.\n        double loss_per_false_alarm = 1;\n        double loss_per_missed_target = 1;\n\n        // A detection must have an intersection-over-union value greater than this for us\n        // to consider it a match against a ground truth box.\n        double truth_match_iou_threshold = 0.5;\n\n        // When doing non-max suppression, we use overlaps_nms to decide if a box overlaps\n        // an already output detection and should therefore be thrown out.\n        test_box_overlap overlaps_nms = test_box_overlap(0.4);\n\n        // Any mmod_rect in the training data that has its ignore field set to true defines\n        // an \"ignore zone\" in an image.  Any detection from that area is totally ignored\n        // by the optimizer.  Therefore, this overlaps_ignore field defines how we decide\n        // if a box falls into an ignore zone.  You use these ignore zones if there are\n        // objects in your dataset that you are unsure if you want to detect or otherwise\n        // don't care if the detector gets them or not.  \n        test_box_overlap overlaps_ignore;\n\n        // Usually the detector would be scale-invariant, and used with an image pyramid.\n        // However, sometimes scale-invariance may not be desired.\n        use_image_pyramid assume_image_pyramid = use_image_pyramid::yes;\n\n        // By default, the mmod loss doesn't train any bounding box regression model.  But\n        // if you set use_bounding_box_regression == true then it expects the network to\n        // output a tensor with detector_windows.size()*5 channels rather than just\n        // detector_windows.size() channels.  The 4 extra channels per window are trained\n        // to give a bounding box regression output that improves the positioning of the\n        // output detection box.\n        bool use_bounding_box_regression = false; \n        // When using bounding box regression, bbr_lambda determines how much you care\n        // about getting the bounding box shape correct vs just getting the detector to\n        // find objects.  That is, the objective function being optimized is\n        // basic_mmod_loss + bbr_lambda*bounding_box_regression_loss.  So setting\n        // bbr_lambda to a larger value will cause the overall loss to care more about\n        // getting the bounding box shape correct.\n        double bbr_lambda = 100; \n\n        // Tell the loss not to print warnings about impossible labels.  You should think very hard\n        // before turning this off as it's very often telling you something is really wrong with\n        // your training data.\n        bool be_quiet = false;\n\n        mmod_options (\n            const std::vector<std::vector<mmod_rect>>& boxes,\n            const unsigned long target_size,      \n            const unsigned long min_target_size,   \n            const double min_detector_window_overlap_iou = 0.75\n        );\n        /*!\n            requires\n                - 0 < min_target_size <= target_size\n                - 0.5 < min_detector_window_overlap_iou < 1\n            ensures\n                - use_image_pyramid_ == use_image_pyramid::yes\n                - This function should be used when scale-invariance is desired, and\n                  input_rgb_image_pyramid is therefore used as the input layer.\n                - This function tries to automatically set the MMOD options to reasonable\n                  values, assuming you have a training dataset of boxes.size() images, where\n                  the ith image contains objects boxes[i] you want to detect.\n                - The most important thing this function does is decide what detector\n                  windows should be used.  This is done by finding a set of detector\n                  windows that are sized such that:\n                    - When slid over an image pyramid, each box in boxes will have an\n                      intersection-over-union with one of the detector windows of at least\n                      min_detector_window_overlap_iou.  That is, we will make sure that\n                      each box in boxes could potentially be detected by one of the\n                      detector windows.  This essentially comes down to picking detector\n                      windows with aspect ratios similar to the aspect ratios in boxes.\n                      Note that we also make sure that each box can be detected by a window\n                      with the same label.  For example, if all the boxes had the same\n                      aspect ratio but there were 4 different labels used in boxes then\n                      there would be 4 resulting detector windows, one for each label.\n                    - The longest edge of each detector window is target_size pixels in\n                      length, unless the window's shortest side would be less than\n                      min_target_size pixels in length.  In this case the shortest side\n                      will be set to min_target_size length, and the other side sized to\n                      preserve the aspect ratio of the window.  \n                  This means that target_size and min_target_size control the size of the\n                  detector windows, while the aspect ratios of the detector windows are\n                  automatically determined by the contents of boxes.  It should also be\n                  emphasized that the detector isn't going to be able to detect objects\n                  smaller than any of the detector windows.  So consider that when setting\n                  these sizes.\n                - This function will also set the overlaps_nms tester to the most\n                  restrictive tester that doesn't reject anything in boxes.\n        !*/\n\n        mmod_options (\n            use_image_pyramid use_image_pyramid,\n            const std::vector<std::vector<mmod_rect>>& boxes,\n            const double min_detector_window_overlap_iou = 0.75\n        );\n        /*!\n            requires\n                - use_image_pyramid == use_image_pyramid::no\n                - 0.5 < min_detector_window_overlap_iou < 1\n            ensures\n                - This function should be used when scale-invariance is not desired, and\n                  there is no intention to apply an image pyramid.\n                - This function tries to automatically set the MMOD options to reasonable\n                  values, assuming you have a training dataset of boxes.size() images, where\n                  the ith image contains objects boxes[i] you want to detect.\n                - The most important thing this function does is decide what detector\n                  windows should be used.  This is done by finding a set of detector\n                  windows that are sized such that:\n                    - When slid over an image, each box in boxes will have an\n                      intersection-over-union with one of the detector windows of at least\n                      min_detector_window_overlap_iou.  That is, we will make sure that\n                      each box in boxes could potentially be detected by one of the\n                      detector windows.\n                - This function will also set the overlaps_nms tester to the most\n                  restrictive tester that doesn't reject anything in boxes.\n        !*/\n    };\n\n    void serialize(const mmod_options& item, std::ostream& out);\n    void deserialize(mmod_options& item, std::istream& in);\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mmod_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the Max Margin Object\n                Detection loss defined in the paper:\n                    Max-Margin Object Detection by Davis E. King (http://arxiv.org/abs/1502.00046).\n               \n                This means you use this loss if you want to detect the locations of objects\n                in images.\n\n                It should also be noted that this loss layer requires an input layer that\n                defines the following functions:\n                    - image_contained_point()\n                    - tensor_space_to_image_space()\n                    - image_space_to_tensor_space()\n                A reference implementation of them and their definitions can be found in\n                the input_rgb_image_pyramid object, which is the recommended input layer to\n                be used with loss_mmod_.\n        !*/\n\n    public:\n\n        typedef std::vector<mmod_rect> training_label_type;\n        typedef std::vector<mmod_rect> output_label_type;\n\n        loss_mmod_(\n        );\n        /*!\n            ensures\n                - #get_options() == mmod_options()\n        !*/\n\n        loss_mmod_(\n            mmod_options options_\n        );\n        /*!\n            ensures\n                - #get_options() == options_\n        !*/\n\n        const mmod_options& get_options (\n        ) const;\n        /*!\n            ensures\n                - returns the options object that defines the general behavior of this loss layer.\n        !*/\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter,\n            double adjust_threshold = 0\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            Also, the output labels are std::vectors of mmod_rects where, for each mmod_rect R,\n            we have the following interpretations:\n                - R.rect == the location of an object in the image.\n                - R.detection_confidence the score for the object, the bigger the score the\n                  more confident the detector is that an object is really there.  Only\n                  objects with a detection_confidence > adjust_threshold are output.  So if\n                  you want to output more objects (that are also of less confidence) you\n                  can call to_label() with a smaller value of adjust_threshold.\n                - R.ignore == false (this value is unused by to_label()).\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            Also, the loss value returned is roughly equal to the average number of\n            mistakes made per image.  This is the sum of false alarms and missed\n            detections, weighted by the loss weights for these types of mistakes specified\n            in the mmod_options.\n        !*/\n    };\n\n    template <typename SUBNET>\n    using loss_mmod = add_loss_layer<loss_mmod_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_metric_ \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it allows you to learn to map objects\n                into a vector space where objects sharing the same class label are close to\n                each other, while objects with different labels are far apart.   \n\n                To be specific, it optimizes the following loss function which considers\n                all pairs of objects in a mini-batch and computes a different loss depending \n                on their respective class labels.  So if objects A1 and A2 in a mini-batch\n                share the same class label then their contribution to the loss is:\n                    max(0, length(A1-A2)-get_distance_threshold() + get_margin())\n\n                While if A1 and B1 have different class labels then their contribution to\n                the loss function is:\n                    max(0, get_distance_threshold()-length(A1-B1) + get_margin())\n\n                Therefore, this loss layer optimizes a version of the hinge loss.\n                Moreover, the loss is trying to make sure that all objects with the same\n                label are within get_distance_threshold() distance of each other.\n                Conversely, if two objects have different labels then they should be more\n                than get_distance_threshold() distance from each other in the learned\n                embedding.  So this loss function gives you a natural decision boundary for\n                deciding if two objects are from the same class.\n\n                Finally, the loss balances the number of negative pairs relative to the\n                number of positive pairs.  Therefore, if there are N pairs that share the\n                same identity in a mini-batch then the algorithm will only include the N\n                worst non-matching pairs in the loss.  That is, the algorithm performs hard\n                negative mining on the non-matching pairs.  This is important since there\n                are in general way more non-matching pairs than matching pairs.  So to\n                avoid imbalance in the loss this kind of hard negative mining is useful.\n        !*/\n    public:\n\n        typedef unsigned long training_label_type;\n        typedef matrix<float,0,1> output_label_type;\n\n        loss_metric_(\n        );\n        /*!\n            ensures\n                - #get_margin() == 0.04\n                - #get_distance_threshold() == 0.6\n        !*/\n\n        loss_metric_(\n            float margin,\n            float dist_thresh\n        );\n        /*!\n            requires\n                - margin > 0\n                - dist_thresh > 0\n            ensures\n                - #get_margin() == margin\n                - #get_distance_threshold() == dist_thresh\n        !*/\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            This loss expects the network to produce a single vector (per sample) as\n            output.  This vector is the learned embedding.  Therefore, to_label() just\n            copies these output vectors from the network into the output label_iterators\n            given to this function, one for each sample in the input_tensor.\n        !*/\n\n        float get_margin() const; \n        /*!\n            ensures\n                - returns the margin value used by the loss function.  See the discussion\n                  in WHAT THIS OBJECT REPRESENTS for details.\n        !*/\n\n        float get_distance_threshold() const; \n        /*!\n            ensures\n                - returns the distance threshold value used by the loss function.  See the discussion\n                  in WHAT THIS OBJECT REPRESENTS for details.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_metric = add_loss_layer<loss_metric_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_ranking_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the pairwise ranking\n                loss described in the paper:\n                    Optimizing Search Engines using Clickthrough Data by Thorsten Joachims\n\n                This is the same loss function used by the dlib::svm_rank_trainer object.\n                Therefore, it is generally appropriate when you have a two class problem\n                and you want to learn a function that ranks one class before the other.  \n\n                So for example, suppose you have two classes of data.  Objects of type A\n                and objects of type B.  Moreover, suppose that you want to sort the objects\n                so that A objects always come before B objects.  This loss will help you\n                learn a function that assigns a real number to each object such that A\n                objects get a larger number assigned to them than B objects.  This lets you\n                then sort the objects according to the output of the neural network and\n                obtain the desired result of having A objects come before B objects.\n\n                The training labels should be positive values for objects you want to get\n                high scores and negative for objects that should get small scores.  So\n                relative to our A/B example, you would give A objects labels of +1 and B\n                objects labels of -1.  This should cause the learned network to give A\n                objects large positive values and B objects negative values.\n\n\n                Finally, the specific loss function is:\n                    For all pairs of positive vs negative training examples A_i and B_j respectively:\n                      sum_ij:  max(0, B_i - A_j + margin_ij)\n                where margin_ij = the label for A_j minus the label for B_i.  If you\n                always use +1 and -1 labels then the margin is always 2.  However, this\n                formulation allows you to give certain training samples different weight by\n                adjusting the training labels appropriately.  \n        !*/\n\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted ranking score.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_ranking = add_loss_layer<loss_ranking_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_epsilon_insensitive_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the epsilon insensitive\n                loss, which is appropriate for regression problems.  In particular, this\n                loss function is;\n                    loss(y1,y2) = abs(y1-y2)<epsilon ? 0 : abs(y1-y2)-epsilon\n\n                Therefore, the loss is basically just the abs() loss except there is a dead\n                zone around zero, causing the loss to not care about mistakes of magnitude\n                smaller than epsilon.\n        !*/\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        loss_epsilon_insensitive_(\n        ) = default;\n        /*!\n            ensures\n                - #get_epsilon() == 1\n        !*/\n\n        loss_epsilon_insensitive_(\n            double eps\n        );\n        /*!\n            requires\n                - eps >= 0\n            ensures\n                - #get_epsilon() == eps\n        !*/\n\n        double get_epsilon (\n        ) const;\n        /*!\n            ensures\n                - returns the epsilon value used in the loss function.  Mistakes in the\n                  regressor smaller than get_epsilon() are ignored by the loss function.\n        !*/\n\n        void set_epsilon(\n            double eps\n        );\n        /*!\n            requires\n                - eps >= 0\n            ensures\n                - #get_epsilon() == eps\n        !*/\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted continuous variable.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_epsilon_insensitive = add_loss_layer<loss_epsilon_insensitive_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the mean squared loss, which is\n                appropriate for regression problems.\n        !*/\n    public:\n\n        typedef float training_label_type;\n        typedef float output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted continuous variable.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared = add_loss_layer<loss_mean_squared_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_multioutput_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the mean squared loss,\n                which is appropriate for regression problems.  It is basically just like\n                loss_mean_squared_ except that it lets you define multiple outputs instead\n                of just 1.\n        !*/\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted continuous variable.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - (*(truth + idx)).nc() == 1 for all idx such that 0 <= idx < sub.get_output().num_samples()\n                - (*(truth + idx)).nr() == sub.get_output().k() for all idx such that 0 <= idx < sub.get_output().num_samples()\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared_multioutput = add_loss_layer<loss_mean_squared_multioutput_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_binary_log_per_pixel_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the log loss, which is\n                appropriate for binary classification problems.  It is basically just like\n                loss_binary_log_ except that it lets you define matrix outputs instead\n                of scalar outputs.  It should be useful, for example, in segmentation\n                where we want to classify each pixel of an image, and also get at least\n                some sort of confidence estimate for each pixel.\n        !*/\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the raw score for each classified object.  If the score\n            is > 0 then the classifier is predicting the +1 class, otherwise it is\n            predicting the -1 class.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all pixel values pointed to by truth correspond to the desired target values.\n                  Nominally they should be +1 or -1, each indicating the desired class label,\n                  or 0 to indicate that the corresponding pixel is to be ignored.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_binary_log_per_pixel = add_loss_layer<loss_binary_log_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_per_pixel_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the multiclass logistic\n                regression loss (e.g. negative log-likelihood loss), which is appropriate\n                for multiclass classification problems.  It is basically just like\n                loss_multiclass_log_ except that it lets you define matrix outputs instead\n                of scalar outputs.  It should be useful, for example, in semantic\n                segmentation where we want to classify each pixel of an image.\n        !*/\n    public:\n\n        // In semantic segmentation, if you don't know the ground-truth of some pixel,\n        // set the label of that pixel to this value. When you do so, the pixel will be\n        // ignored when computing gradients.\n        static const uint16_t label_to_ignore = std::numeric_limits<uint16_t>::max();\n\n        // In semantic segmentation, 65535 classes ought to be enough for anybody.\n        typedef matrix<uint16_t> training_label_type;\n        typedef matrix<uint16_t> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted class for each classified element.  The number\n            of possible output classes is sub.get_output().k().\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all values pointed to by truth are < sub.get_output().k() or are equal to label_to_ignore.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_per_pixel = add_loss_layer<loss_multiclass_log_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_multiclass_log_per_pixel_weighted_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the multiclass logistic\n                regression loss (e.g. negative log-likelihood loss), which is appropriate\n                for multiclass classification problems.  It is basically just like\n                loss_multiclass_log_per_pixel_ except that it lets you define per-pixel\n                weights, which may be useful e.g. if you want to emphasize rare classes\n                while training.  (If the classification problem is difficult, a flat weight\n                structure may lead the network to always predict the most common label, in\n                particular if the degree of imbalance is high.  To emphasize a certain\n                class or classes, simply increase the weights of the corresponding pixels,\n                relative to the weights of the other pixels.)\n\n                Note that if you set the weight to 0 whenever a pixel's label is equal to\n                loss_multiclass_log_per_pixel_::label_to_ignore, and to 1 otherwise, then\n                you essentially get loss_multiclass_log_per_pixel_ as a special case.\n        !*/\n    public:\n\n        typedef dlib::weighted_label<uint16_t> weighted_label;\n        typedef matrix<weighted_label> training_label_type;\n        typedef matrix<uint16_t> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output label is the predicted class for each classified element.  The number\n            of possible output classes is sub.get_output().k().\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - all labels pointed to by truth are < sub.get_output().k(), or the corresponding weight\n                  is zero.\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_multiclass_log_per_pixel_weighted = add_loss_layer<loss_multiclass_log_per_pixel_weighted_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_mean_squared_per_pixel_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the mean squared loss,\n                which is appropriate for regression problems.  It is basically just like\n                loss_mean_squared_multioutput_ except that it lets you define matrix or\n                image outputs, instead of vector.\n        !*/\n    public:\n\n        typedef matrix<float> training_label_type;\n        typedef matrix<float> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output labels are the predicted continuous variables.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().k() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - for all idx such that 0 <= idx < sub.get_output().num_samples():\n                    - sub.get_output().nr() == (*(truth + idx)).nr()\n                    - sub.get_output().nc() == (*(truth + idx)).nc()\n        !*/\n    };\n\n    template <typename SUBNET>\n    using loss_mean_squared_per_pixel = add_loss_layer<loss_mean_squared_per_pixel_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    template<long _num_channels>\n    class loss_mean_squared_per_channel_and_pixel_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the mean squared loss,\n                which is appropriate for regression problems.  It is basically just like\n                loss_mean_squared_per_pixel_ except that it computes the loss over all\n                channels, not just the first one.\n        !*/\n    public:\n\n        typedef std::array<matrix<float>, _num_channels> training_label_type;\n        typedef std::array<matrix<float>, _num_channels> output_label_type;\n\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.get_output().k() == _num_channels\n                - sub.sample_expansion_factor() == 1\n            and the output labels are the predicted continuous variables.\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().k() == _num_channels\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - for all idx such that 0 <= idx < sub.get_output().num_samples():\n                    - sub.get_output().nr() == (*(truth + idx)).nr()\n                    - sub.get_output().nc() == (*(truth + idx)).nc()\n        !*/\n    };\n\n    template <long num_channels, typename SUBNET>\n    using loss_mean_squared_per_channel_and_pixel = add_loss_layer<loss_mean_squared_per_channel_and_pixel_<num_channels>, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_dot_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, selecting this loss means you want\n                maximize the dot product between the output of a network and a set of\n                training vectors.  The loss is therefore the negative dot product.  To be\n                very specific, if X is the output vector of a network and Y is a training\n                label (also a vector), then the loss for this training sample is: -dot(X,Y)\n        !*/\n\n    public:\n\n        typedef matrix<float,0,1> training_label_type;\n        typedef matrix<float,0,1> output_label_type;\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            and the output labels are simply the final network outputs stuffed into a\n            vector.  To be very specific, the output is the following for all valid i:\n                *(iter+i) == trans(rowm(mat(sub.get_output()),i))\n        !*/\n\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n                - Let NETWORK_OUTPUT_DIMS == sub.get_output().size()/sub.get_output().num_samples()\n                - for all idx such that 0 <= idx < sub.get_output().num_samples():\n                    - NETWORK_OUTPUT_DIMS == (*(truth + idx)).size()\n        !*/\n    };\n\n    template <typename SUBNET>\n    using loss_dot = add_loss_layer<loss_dot_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    struct yolo_options\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object contains all the parameters that control the behavior of loss_yolo_.\n        !*/\n    public:\n        struct anchor_box_details\n        {\n            anchor_box_details() = default;\n            anchor_box_details(unsigned long w, unsigned long h) : width(w), height(h) {}\n\n            unsigned long width = 0;\n            unsigned long height = 0;\n\n            friend inline void serialize(const anchor_box_details& item, std::ostream& out);\n            friend inline void deserialize(anchor_box_details& item, std::istream& in);\n        };\n\n        yolo_options() = default;\n\n        // This kind of object detector is a multi-scale object detector with bounding box\n        // regression for anchor boxes.  The anchors field determines which anchors will be\n        // used at the output pointed by the tag layer whose id is the key of the map.\n        std::unordered_map<int, std::vector<anchor_box_details>> anchors;\n\n        template <template <typename> class TAG_TYPE>\n        void add_anchors(\n            const std::vector<anchor_box_details>& boxes\n        );\n        /*!\n            ensures\n                - anchors.at(tag_id<TAG_TYPE>::id) == boxes\n        !*/\n\n        // This field contains the labels of all the possible objects this detector can find.\n        std::vector<std::string> labels;\n        // When computing the objectness loss, any detection that has an IoU above\n        // iou_ignore_threshold with a ground truth box will not incur any loss.\n        double iou_ignore_threshold = 0.7;\n        // When computing the YOLO loss (objectness + bounding box regression + classification),\n        // the best match between a truth and an anchor is always used, regardless of the IoU.\n        // However, if other anchors have an IoU with a truth box above iou_anchor_threshold, they\n        // will also experience loss against that truth box as well.  Setting iou_anchor_threshold\n        // to 1 will make the model use only the best anchor for each ground truth, so other\n        // anchors can be used for other ground truth boxes in the same cell (useful for detecting\n        // objects in crowds).  This setting is meant to be used with \"high capacity\" models, not\n        // small ones.  Additionaly, when this value is set to 0, it will adaptively compute the\n        // IOU threshold based on the statistics of the IOUS from all anchors with the current\n        // target truth box. In particular, it follows the adaptive training sample selection\n        // (ATSS) from the paper: \"Bridging the Gap Between Anchor-based and Anchor-free Detection\n        // via Adaptive Training Sample Selection\" by Shifeng Zhang, et al.\n        // (https://arxiv.org/abs/1912.02424)\n        double iou_anchor_threshold = 1.0;\n        // When doing non-max suppression, we use overlaps_nms to decide if a box overlaps\n        // an already output detection and should therefore be thrown out.\n        test_box_overlap overlaps_nms = test_box_overlap(0.45, 1.0);\n        // When set to true, NMS will only be applied between objects with the same class label.\n        bool classwise_nms = true;\n        // These parameters control how we penalize different kinds of mistakes: notably the\n        // objectness loss, the box (bounding box regression) loss, and the classification loss.\n        double lambda_obj = 1.0;\n        double lambda_box = 1.0;\n        double lambda_cls = 1.0;\n        // This parameter makes YOLO behave like the Focal loss, presented in the paper:\n        // \"Focal Loss for Dense Object Detection\", by Tsung-Yi Lin, et al.\n        // (https://arxiv.org/abs/1708.02002)\n        // The gamma_obj and gamma_cls act as a modulating factor to the cross-entropy layers of\n        // objectness and classification by reducing the relative loss for well-classified\n        // examples, and focusing on the difficult ones.\n        double gamma_obj = 0.0;\n        double gamma_cls = 0.0;\n\n    };\n\n    void serialize(const yolo_options& item, std::ostream& out)\n    void deserialize(yolo_options& item, std::istream& in)\n\n// ----------------------------------------------------------------------------------------\n\n    template <template <typename> class... TAG_TYPES>\n    class loss_yolo_\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the YOLO detection\n                loss defined in the paper:\n                    YOLOv3: An Incremental Improvement by Joseph Redmon and Ali Farhadi.\n\n                This means you use this loss if you want to detect the locations of objects\n                in images.\n\n                It should also be noted that this loss layer requires tag layers as template\n                parameters, which in turn require a subnetwork to be of type:\n                layer<TAG_TYPE>(net).subnet(): sig<con<(num_classes + 5) * num_anchors), SUBNET>>\n\n                Where num_classes is the number of categories that the detector is trained on,\n                and num_anchors is the number of priors or anchor boxes at the output pointed\n                by the tag layer. The number 5 corresponds to the objectness plus the 4 coordinates\n                for performing bounding box regression.\n        !*/\n\n    public:\n\n        typedef std::vector<yolo_rect> training_label_type;\n        typedef std::vector<yolo_rect> output_label_type;\n\n        loss_yolo_(\n        );\n        /*!\n            ensures\n                - #get_options() == yolo_options()\n        !*/\n\n        loss_yolo_(\n            yolo_options options_\n        );\n        /*!\n            ensures\n                - #get_options() == options_\n        !*/\n\n        const yolo_options& get_options (\n        ) const;\n        /*!\n            ensures\n                - returns the options object that defines the general behavior of this loss layer.\n        !*/\n\n        template <\n            typename SUB_TYPE,\n            typename label_iterator\n            >\n        void to_label (\n            const tensor& input_tensor,\n            const SUB_TYPE& sub,\n            label_iterator iter,\n            double adjust_threshold = 0.25\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::to_label() except\n            it has the additional calling requirements that:\n                - layer<TAG_TYPE>(sub).get_output().k() == options.anchors.at(tag_id<TAG_TYPE>::id).size() * (5 + options.labels.size());\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            Also, the output labels are std::vectors of yolo_rects where, for each yolo_rect R,\n            we have the following interpretations:\n                - R.rect == the location of an object in the image.\n                - R.detection_confidence == the score for the object, between 0 and 1.  Only\n                  objects with a detection_confidence > adjust_threshold are output.  So if\n                  you want to output more objects (that are also of less confidence) you\n                  can call to_label() with a smaller value of adjust_threshold.\n                - R.label == the label of the detected object.\n                - R.labels == a std::vector<std::pair<double, std::string>> containing all the confidence values\n                  and labels that have a detection score > adjust_threshold, since this loss allows\n                  for multi-label outputs.  Note that the following is true:\n                      - R.labels[0].first == R.detection_confidence\n                      - R.labels[0].second == R.label\n                - R.ignore == false (this value is unused by to_label()).\n        !*/\n\n        template <\n            typename const_label_iterator,\n            typename SUBNET\n            >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            const_label_iterator truth, \n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient() \n            except it has the additional calling requirements that: \n                - layer<TAG_TYPE>(sub).get_output().k() == options.anchors.at(tag_id<TAG_TYPE>::id).size() * (5 + options.labels.size());\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 1\n            Also, the loss value returned corresponds to the squared norm of the error gradient.\n        !*/\n\n        void adjust_nms (\n            double iou_thresh,\n            double percent_covered_thresh = 1,\n            bool classwise = true\n        );\n        /*!\n            ensures\n                - #get_options().overlaps_nms == test_box_overlap(iou_thresh, percent_covered_thresh)\n                - #get_options().classwise_nms == classwise\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_yolo = add_loss_layer<loss_yolo_, SUBNET>;\n\n// ----------------------------------------------------------------------------------------\n\n    class loss_barlow_twins_\n    {\n    public:\n\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the loss layer interface defined above by\n                EXAMPLE_LOSS_LAYER_.  In particular, it implements the Barlow Twins loss\n                layer presented in the paper:\n                    Barlow Twins: Self-Supervised Learning via Redundancy Reduction\n                    by Jure Zbontar, Li Jing, Ishan Misra, Yann LeCun, Stéphane Deny\n                    (https://arxiv.org/abs/2103.03230)\n\n                This means you use this loss to learn useful representations from data that\n                has no label information.  Useful representations mean that can be used to\n                train another downstream task, such as classification.\n                In particular, this loss function applies the redundancy reduction principle\n                to the representations learned by the network it sits on top of.\n\n                To be specific, this layer requires the sample_expansion_factor to be 2, and\n                in each batch, the second half contains distorted versions of the first half.\n                Let Z_A and Z_B be the first and second half of the batch that goes into this\n                loss layer, respectively.  Z_A and Z_B have dimensions N rows and D columns,\n                where N is half the batch size and D is the dimensionality of the output tensor.\n                Each row in Z_B should contain a distorted version of the corresponding row\n                in Z_A.  Then, this loss computes the empirical cross-correlation matrix between\n                the batch-normalized versions of Z_A and Z_B:\n\n                    C = trans(bn(Z_A)) * bn(Z_B)\n\n                It then applies the redundancy reduction principle by trying to make C as\n                close to the identity matrix as possible:\n\n                    L = squared(diag(C) - 1) + lambda * squared(off_diag(C))\n\n                where off_diag grabs all the elements that are not on the diagonal of C and\n                lambda provides a trade-off between both terms in the loss function.  The C\n                matrix has dimensions D x D: there are only D diagonal terms, but D * (D - 1)\n                off-diagonal elements.  A reasonable value for lambda is 1 / D.\n        !*/\n\n        loss_barlow_twins_(\n        );\n        /*!\n            ensures\n                - #get_lambda() == 0.0051\n        !*/\n\n        loss_barlow_twins_(float lambda);\n        /*!\n            ensures\n                - #get_lambda() == lambda\n        !*/\n\n        float get_lambda() const;\n        /*!\n            ensures\n                - returns the lambda value used by the loss function.  See the discussion\n                  in WHAT THIS OBJECT REPRESENTS for details.\n        !*/\n\n        tensor& get_eccm();\n        /*!\n            ensures\n                - returns the empirical cross-correlation matrix computed by the loss.\n                - this is only meant to be used for visualization/debugging purposes.\n        !*/\n\n        const tensor& get_eccm() const;\n        /*!\n            ensures\n                - returns the empirical cross-correlation matrix computed by the loss.\n                - this is only meant to be used for visualization/debugging purposes.\n        !*/\n\n        template <\n            typename SUBNET\n        >\n        double compute_loss_value_and_gradient (\n            const tensor& input_tensor,\n            SUBNET& sub\n        ) const;\n        /*!\n            This function has the same interface as EXAMPLE_LOSS_LAYER_::compute_loss_value_and_gradient()\n            except it has the additional calling requirements that:\n                - sub.get_output().nr() == 1\n                - sub.get_output().nc() == 1\n                - sub.get_output().num_samples() == input_tensor.num_samples()\n                - sub.sample_expansion_factor() == 2\n        !*/\n\n    };\n\n    template <typename SUBNET>\n    using loss_barlow_twins = add_loss_layer<loss_barlow_twins_, SUBNET>;\n\n}\n\n#endif // DLIB_DNn_LOSS_ABSTRACT_H_\n"
  },
  {
    "path": "dlib/dnn/solvers.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_SOLVERS_H_\n#define DLIB_DNn_SOLVERS_H_\n\n#include \"solvers_abstract.h\"\n#include \"../cuda/tensor.h\"\n#include <iostream>\n#include \"layers.h\"\n\nnamespace dlib\n{\n    class sgd\n    {\n    public:\n\n        explicit sgd(\n            float weight_decay_,\n            float momentum_ = 0.9\n        ) \n        { \n            weight_decay = weight_decay_;\n            momentum = momentum_;\n        }\n\n        sgd(\n        ) : sgd(0.0005f, 0.9f)\n        { \n        }\n\n        float get_momentum (\n        ) const { return momentum; }\n\n        float get_weight_decay (\n        ) const { return weight_decay; }\n\n        template <typename layer_type> \n        const tensor& operator() (\n            const float learning_rate,\n            const layer_type& l,\n            const tensor& params_grad\n        )\n        {\n            const tensor& params = l.get_layer_params();\n\n            DLIB_CASSERT(params.size() != 0);\n            if (v.size() == 0)\n            {\n                v.copy_size(params_grad);\n                v = 0;\n            }\n\n            const double lr = learning_rate*get_learning_rate_multiplier(l);\n            const double wd = weight_decay*get_weight_decay_multiplier(l);\n            \n            //perform: v = momentum*mat(v) - wd*lr*mat(params) - lr*mat(params_grad);\n            tt::affine_transform(v, v, params, params_grad, momentum, -wd*lr, -lr);\n\n            return v;\n        }\n\n        template <unsigned long N>\n        const tensor& operator() (\n            const float learning_rate,\n            const fc_<N,FC_HAS_BIAS>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.get_num_outputs());\n            return v;\n        }\n\n        template <\n            long _num_filters,\n            long _nr,\n            long _nc,\n            int _stride_y,\n            int _stride_x,\n            int _padding_y,\n            int _padding_x\n            >\n        const tensor& operator() (\n            const float learning_rate,\n            const con_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters());\n            return v;\n        }\n\n        template <\n            long _num_filters,\n            long _nr,\n            long _nc,\n            int _stride_y,\n            int _stride_x,\n            int _padding_y,\n            int _padding_x\n            >\n        const tensor& operator() (\n            const float learning_rate,\n            const cont_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters());\n            return v;\n        }\n\n        template < layer_mode mode >\n        const tensor& operator() (\n            const float learning_rate,\n            const bn_<mode>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()/2);\n            return v;\n        }\n\n        friend void serialize(const sgd& item, std::ostream& out)\n        {\n            serialize(\"sgd2\", out);\n            serialize(item.v, out);\n            serialize(item.weight_decay, out);\n            serialize(item.momentum, out);\n        }\n\n        friend void deserialize(sgd& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"sgd2\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::sgd.\");\n            deserialize(item.v, in);\n            deserialize(item.weight_decay, in);\n            deserialize(item.momentum, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const sgd& item)\n        {\n            out << \"sgd: weight_decay=\"<<item.get_weight_decay() << \", momentum=\"<<item.get_momentum(); \n            return out;\n        }\n\n    private:\n\n        template <typename layer_type> \n        void update_considering_bias(\n            const float learning_rate,\n            const layer_type& l,\n            const tensor& params_grad,\n            unsigned long bias_offset\n        )\n        {\n            const tensor& params = l.get_layer_params();\n\n            DLIB_CASSERT(params.size() != 0);\n            if (v.size() == 0)\n            {\n                v.copy_size(params_grad);\n                v = 0;\n            }\n\n            double lr = learning_rate*get_learning_rate_multiplier(l);\n            double wd = weight_decay*get_weight_decay_multiplier(l);\n            \n            //perform: v = momentum*mat(v) - wd*lr*mat(params) - lr*mat(params_grad);\n\n            if (l.get_bias_learning_rate_multiplier() == 1 && l.get_bias_weight_decay_multiplier() == 1)\n            {\n                tt::affine_transform(v, v, params, params_grad, momentum, -wd*lr, -lr);\n            }\n            else\n            {\n\n                tt::affine_transform_range(0, bias_offset, v, v, params, params_grad, momentum, -wd*lr, -lr);\n\n                // now update the biases but apply their multipliers\n                lr *= l.get_bias_learning_rate_multiplier();\n                wd *= l.get_bias_weight_decay_multiplier();\n                tt::affine_transform_range(bias_offset, v.size(), v, v, params, params_grad, momentum, -wd*lr, -lr);\n            }\n        }\n\n        resizable_tensor v;\n        float weight_decay;\n        float momentum;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class adam \n    {\n    public:\n\n        adam(\n            float weight_decay_,\n            float momentum1_, \n            float momentum2_\n        ) \n        { \n            weight_decay = weight_decay_;\n            momentum1 = momentum1_;\n            momentum2 = momentum2_;\n            t = 0;\n        }\n\n        adam(\n        ) : adam(0.0005f, 0.9f, 0.999f)\n        {}\n\n        float get_momentum1 (\n        ) const { return momentum1; }\n\n        float get_momentum2 (\n        ) const { return momentum2; }\n\n        float get_weight_decay (\n        ) const { return weight_decay; }\n\n        template <typename layer_type>\n        const tensor& operator() (\n            const float learning_rate,\n            const layer_type& l,\n            const tensor& params_grad\n        )\n        {\n            const tensor& params = l.get_layer_params();\n            DLIB_CASSERT(params.size() != 0);\n            if (v.size() == 0)\n            {\n                m.copy_size(params_grad);\n                m = 0;\n                v.copy_size(params_grad);\n                v = 0;\n                s.copy_size(params_grad);\n            }\n\n            ++t;\n\n            \n            tt::compute_adam_update(0, params.size(), s, m, v, t,\n                learning_rate*get_learning_rate_multiplier(l),\n                weight_decay*get_weight_decay_multiplier(l), \n                momentum1, momentum2, params, params_grad);\n\n            return s;\n        }\n\n        template <unsigned long N>\n        const tensor& operator() (\n            const float learning_rate,\n            const fc_<N,FC_HAS_BIAS>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.get_num_outputs());\n            return s;\n        }\n\n        template <\n            long _num_filters,\n            long _nr,\n            long _nc,\n            int _stride_y,\n            int _stride_x,\n            int _padding_y,\n            int _padding_x\n            >\n        const tensor& operator() (\n            const float learning_rate,\n            const con_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters());\n            return s;\n        }\n\n        template <\n            long _num_filters,\n            long _nr,\n            long _nc,\n            int _stride_y,\n            int _stride_x,\n            int _padding_y,\n            int _padding_x\n            >\n        const tensor& operator() (\n            const float learning_rate,\n            const cont_<_num_filters,_nr,_nc,_stride_y,_stride_x,_padding_y,_padding_x>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()-l.num_filters());\n            return s;\n        }\n\n        template < layer_mode mode >\n        const tensor& operator() (\n            const float learning_rate,\n            const bn_<mode>& l,\n            const tensor& params_grad\n        )\n        {\n            update_considering_bias(learning_rate, l, params_grad, params_grad.size()/2);\n            return s;\n        }\n\n\n        friend void serialize(const adam& item, std::ostream& out)\n        {\n            serialize(\"adam2\", out);\n            serialize(item.m, out);\n            serialize(item.v, out);\n            serialize(item.s, out);\n            serialize(item.weight_decay, out);\n            serialize(item.momentum1, out);\n            serialize(item.momentum2, out);\n            serialize(item.t, out);\n        }\n\n        friend void deserialize(adam& item, std::istream& in)\n        {\n            std::string version;\n            deserialize(version, in);\n            if (version != \"adam2\")\n                throw serialization_error(\"Unexpected version found while deserializing dlib::adam.\");\n            deserialize(item.m, in);\n            deserialize(item.v, in);\n            deserialize(item.s, in);\n            deserialize(item.weight_decay, in);\n            deserialize(item.momentum1, in);\n            deserialize(item.momentum2, in);\n            deserialize(item.t, in);\n        }\n\n        friend std::ostream& operator<< (std::ostream& out, const adam& item)\n        {\n            out << \"adam: weight_decay=\"<<item.get_weight_decay() << \", momentum1=\"<<item.get_momentum1() << \", momentum2=\"<<item.get_momentum2(); \n            return out;\n        }\n\n    private:\n\n        template <typename layer_type> \n        void update_considering_bias(\n            const float learning_rate,\n            const layer_type& l,\n            const tensor& params_grad,\n            unsigned long bias_offset\n        )\n        {\n            const tensor& params = l.get_layer_params();\n            DLIB_CASSERT(params.size() != 0);\n            if (v.size() == 0)\n            {\n                m.copy_size(params_grad);\n                m = 0;\n                v.copy_size(params_grad);\n                v = 0;\n                s.copy_size(params_grad);\n            }\n\n\n            ++t;\n\n            if (l.get_bias_learning_rate_multiplier() == 1 && l.get_bias_weight_decay_multiplier() == 1)\n            {\n                tt::compute_adam_update(0, params.size(), s, m, v, t,\n                    learning_rate*get_learning_rate_multiplier(l),\n                    weight_decay*get_weight_decay_multiplier(l), \n                    momentum1, momentum2, params, params_grad);\n            }\n            else\n            {\n                tt::compute_adam_update(0, bias_offset, s, m, v, t,\n                    learning_rate*get_learning_rate_multiplier(l),\n                    weight_decay*get_weight_decay_multiplier(l), \n                    momentum1, momentum2, params, params_grad);\n\n                tt::compute_adam_update(bias_offset, params.size(), s, m, v, t,\n                    learning_rate*get_learning_rate_multiplier(l)*l.get_bias_learning_rate_multiplier(),\n                    weight_decay*get_weight_decay_multiplier(l)*l.get_bias_weight_decay_multiplier(), \n                    momentum1, momentum2, params, params_grad);\n            }\n        }\n        resizable_tensor m;\n        resizable_tensor v;\n        resizable_tensor s;\n        float weight_decay;\n        float momentum1;\n        float momentum2;\n        float t;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_SOLVERS_H_\n\n"
  },
  {
    "path": "dlib/dnn/solvers_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_SOLVERS_ABSTRACT_H_\n#ifdef DLIB_DNn_SOLVERS_ABSTRACT_H_\n\n#include \"../cuda/tensor_abstract.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class EXAMPLE_SOLVER \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                A solver defines the parameter update rule for a single layer in a deep\n                neural network.  It takes a parameter gradient vector and the layer's\n                parameters and tells you how the parameters should be updated.\n                Importantly, each solver instance is used with only one layer in a network.\n                This allows us to define solvers that have per layer state, for example, a\n                solver may keep a momentum term and apply it to its update rule.\n\n                Note that there is no dlib::EXAMPLE_SOLVER type.  It is shown here purely\n                to document the interface a solver object must implement.\n        !*/\n\n    public:\n\n        EXAMPLE_SOLVER(\n        );\n\n        template <typename layer_type>\n        const tensor& operator() (\n            const float learning_rate,\n            const layer_type& l,\n            const tensor& params_grad\n        )\n        /*!\n            requires\n                - l.get_layer_params().size() != 0\n                - have_same_dimensions(l.get_layer_params(), params_grad) == true.\n                - When this function is invoked on a particular solver instance, it is\n                  always supplied with the same layer instance, l.  That is, the solver is\n                  allowed to remember things from one invocation to another and to assume\n                  that it is being serially applied to optimize the same layer's\n                  parameters. \n            ensures\n                - Returns a step vector V that is intended to be used to update the\n                  parameters by adding V to l.get_layer_params().\n                - This function will use the given \"learning rate\" to compute V.  How the\n                  learning rate is used is solver dependent.  But in general the learning\n                  rate should be used to select the step size, i.e. to somehow determine\n                  the magnitude of V.\n        !*/\n    };\n\n    void serialize(const EXAMPLE_SOLVER& item, std::ostream& out);\n    void deserialize(EXAMPLE_SOLVER& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    std::ostream& operator<< (std::ostream& out, const EXAMPLE_SOLVER& item);\n    /*!\n        Prints the solver's name and parameters to out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class sgd\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the EXAMPLE_SOLVER interface defined above.  It is a\n                basic stochastic gradient descent solver which uses momentum and weight\n                decay.  In particular, it computes the update vector V according to:\n                    V = momentum*V - weight_decay*learning_rate*l.get_layer_params() - learning_rate*params_grad;\n                Here V is a momentum term that is remembered by the solver from one\n                invocation of operator() to the next.  \n\n\n                Note that the actual learning rate and weight decay used by the solver are\n                multiplied by the per layer multipliers.  That is, the solver will call\n                get_learning_rate_multiplier(l) and get_weight_decay_multiplier(l) and\n                multiply these values with the nominal learning rate and weight decay,\n                respectively, to determine the values it will use during each step.  It is\n                also overloaded to allow additional learning rate multipliers to be applied\n                to fc_ and con_ bias parameters.\n        !*/\n    public:\n\n        sgd(\n        ); \n        /*!\n            ensures\n                - #get_weight_decay()  == 0.0005 \n                - #get_momentum()      == 0.9 \n        !*/\n\n        explicit sgd(\n            float weight_decay,\n            float momentum = 0.9\n        ); \n        /*!\n            requires\n                - weight_decay >= 0\n                - momentum >= 0\n            ensures\n                - #get_weight_decay()  == weight_decay \n                - #get_momentum()      == momentum \n        !*/\n\n        float get_weight_decay () const;\n        float get_momentum () const; \n    };\n\n    void serialize(const sgd& item, std::ostream& out);\n    void deserialize(sgd& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    std::ostream& operator<< (std::ostream& out, const sgd& item);\n    /*!\n        Prints the solver's name and parameters to out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class adam\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the EXAMPLE_SOLVER interface defined above.  In\n                particular, it implements the ADAM parameter update method described in the\n                paper:\n                    Kingma, Diederik P., and Jimmy Ba Adam. \"A method for stochastic\n                    optimization.\" International Conference on Learning Representation. 2015.\n\n\n                Note that the actual learning rate and weight decay used by the solver are\n                multiplied by the per layer multipliers.  That is, the solver will call\n                get_learning_rate_multiplier(l) and get_weight_decay_multiplier(l) and\n                multiply these values with the nominal learning rate and weight decay,\n                respectively, to determine the values it will use during each step.  It is\n                also overloaded to allow additional learning rate multipliers to be applied\n                to fc_ and con_ bias parameters.\n        !*/\n\n    public:\n\n        adam(\n        ); \n        /*!\n            ensures\n                - #get_weight_decay()  == 0.0005 \n                - #get_momentum1()     == 0.9 \n                - #get_momentum2()     == 0.999 \n        !*/\n\n        adam(\n            float weight_decay,\n            float momentum1, \n            float momentum2 \n        ); \n        /*!\n            requires\n                - weight_decay >= 0\n                - 0 <= momentum1 < 1\n                - 0 <= momentum2 < 1\n            ensures\n                - #get_weight_decay()  == weight_decay \n                - #get_momentum1()     == momentum1\n                - #get_momentum2()     == momentum2\n        !*/\n\n        float get_weight_decay () const;\n        float get_momentum1 () const; \n        float get_momentum2 () const; \n    };\n\n    void serialize(const adam& item, std::ostream& out);\n    void deserialize(adam& item, std::istream& in);\n    /*!\n        provides serialization support  \n    !*/\n\n    std::ostream& operator<< (std::ostream& out, const adam& item);\n    /*!\n        Prints the solver's name and parameters to out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_SOLVERS_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/dnn/trainer.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_TRAINER_H_\n#define DLIB_DNn_TRAINER_H_\n\n#include \"trainer_abstract.h\"\n#include \"core.h\"\n#include \"solvers.h\"\n#include \"../statistics.h\"\n#include <chrono>\n#include <fstream>\n#include <sstream>\n#include \"../serialize.h\"\n\n#include \"../pipe.h\"\n#include \"../threads.h\"\n#include \"../cuda/cuda_dlib.h\"\n#include \"../statistics/running_gradient.h\"\n#include <atomic>\n#include <cstdio>\n#include <set>\n#include <future>\n#include <exception>\n#include <mutex>\n#include \"../dir_nav.h\"\n#include \"../md5.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename training_label_type>\n        struct dnn_job_t\n        {\n            dnn_job_t() = default;\n            dnn_job_t(const dnn_job_t&) = delete;\n            dnn_job_t& operator=(const dnn_job_t&) = delete;\n\n            std::vector<std::vector<training_label_type>> labels;\n            std::vector<resizable_tensor> t;\n            std::vector<int> have_data;  // have_data[i] is true if there is data in labels[i] and t[i].\n            bool test_only = false;\n        };\n\n        template <typename training_label_type>\n        void swap(dnn_job_t<training_label_type>& a, dnn_job_t<training_label_type>& b)\n        {\n            a.labels.swap(b.labels);\n            a.t.swap(b.t);\n            a.have_data.swap(b.have_data);\n            std::swap(a.test_only,b.test_only);\n        }\n    }\n\n    enum class force_flush_to_disk {\n        no = 0,\n        yes = 1\n    };\n\n    template <\n        typename net_type, \n        typename solver_type = sgd\n        >\n    class dnn_trainer : private threaded_object\n    {\n    public:\n\n        static_assert(is_loss_layer_type<net_type>::value, \n            \"The last layer in a network must be a loss layer.\");\n\n        typedef typename net_type::training_label_type training_label_type;\n        typedef typename net_type::input_type input_type;\n        const static size_t num_computational_layers = net_type::num_computational_layers;\n        const static size_t num_layers = net_type::num_layers;\n        using threads = std::vector<std::shared_ptr<thread_pool>>;\n    private:\n        typedef impl::dnn_job_t<training_label_type> job_t;\n    public:\n\n        dnn_trainer() = delete;\n        dnn_trainer(const dnn_trainer&) = delete;\n        dnn_trainer& operator=(const dnn_trainer&) = delete;\n\n        explicit dnn_trainer(net_type& net_) : job_pipe(0), net(net_)\n        {\n            solver_type default_solver;\n            devices.push_back(std::make_shared<device_data>(dlib::cuda::get_device(), net, default_solver));\n\n            init();\n        }\n\n        dnn_trainer(\n            net_type& net_, \n            const solver_type& solver_\n        ) : job_pipe(0), net(net_) \n        {\n            devices.push_back(std::make_shared<device_data>(dlib::cuda::get_device(), net, solver_));\n\n            init();\n        }\n\n        dnn_trainer(\n            net_type& net_, \n            const solver_type& solver_,\n            const std::vector<int>& cuda_extra_devices,\n            std::shared_ptr<threads> thread_pools_ = std::shared_ptr<threads>()\n        ) : job_pipe(0), thread_pools(thread_pools_), net(net_)\n        {\n            devices.push_back(std::make_shared<device_data>(dlib::cuda::get_device(), net, solver_));\n\n            const int total_devices = dlib::cuda::get_num_devices();\n\n            // Make device contexts for the extra device ids but be careful to avoid any\n            // duplicate ids.\n            std::set<int> temp(cuda_extra_devices.begin(), cuda_extra_devices.end());\n            temp.erase(devices[0]->device_id);\n            for (auto id : temp)\n            {\n                DLIB_CASSERT(0 <= id && id < total_devices, \"Invalid CUDA device id given to dnn_trainer.\");\n                // Switch to this device so that any tensor objects that get allocated when\n                // we create the device context happen on this device.\n                dlib::cuda::set_device(id);\n                devices.push_back(std::make_shared<device_data>(id, net, solver_, clone_net()));\n            }\n            // Set the current device back to what it was before this constructor was\n            // called.\n            dlib::cuda::set_device(devices[0]->device_id);\n\n            init();\n        }\n\n        ~dnn_trainer(\n        )\n        {\n            job_pipe.disable();\n            stop();\n            wait();\n        }\n\n        net_type& get_net (\n            force_flush_to_disk force_flush = force_flush_to_disk::yes\n        )  \n        { \n            wait_for_thread_to_pause();\n            sync_to_disk(force_flush == force_flush_to_disk::yes);\n            propagate_exception();\n            return net; \n        }\n\n\n        unsigned long get_mini_batch_size (\n        ) const { return mini_batch_size; }\n\n        void set_mini_batch_size (\n            unsigned long batch_size \n        )\n        {\n            DLIB_CASSERT(batch_size > 0);\n            mini_batch_size = batch_size;\n        }\n\n        unsigned long get_max_num_epochs (\n        ) const { return max_num_epochs; }\n\n        void set_max_num_epochs (\n            unsigned long num\n        )  \n        {\n            DLIB_CASSERT(num > 0);\n            max_num_epochs = num;\n        }\n\n        void be_verbose (\n        )\n        {\n            verbose = true;\n        }\n\n        void be_quiet (\n        )\n        {\n            verbose = false;\n        }\n\n\n        const std::vector<solver_type>& get_solvers (\n        ) const \n        { \n            wait_for_thread_to_pause();\n            propagate_exception();\n            return devices[0]->solvers; \n        }\n\n        void train_one_step (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        )\n        {\n            DLIB_CASSERT(data.size() == labels.size());\n\n            train_one_step(data.begin(), data.end(), labels.begin());\n        }\n\n        template <\n            typename data_iterator,\n            typename label_iterator\n            >\n        void train_one_step (\n            data_iterator dbegin, \n            data_iterator dend,\n            label_iterator lbegin\n        )\n        {\n            DLIB_CASSERT(std::distance(dbegin, dend) > 0);\n\n            print_periodic_verbose_status();\n            sync_to_disk();\n            send_job(false, dbegin, dend, lbegin);\n\n            ++train_one_step_calls;\n        }\n\n        void train_one_step (\n            const std::vector<input_type>& data\n        )\n        {\n            train_one_step(data.begin(), data.end());\n        }\n\n        template <\n            typename data_iterator\n            >\n        void train_one_step (\n            data_iterator dbegin, \n            data_iterator dend\n        )\n        {\n            DLIB_CASSERT(std::distance(dbegin, dend) > 0);\n            print_periodic_verbose_status();\n            sync_to_disk();\n            send_job(false, dbegin, dend);\n            ++train_one_step_calls;\n        }\n\n        void test_one_step (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        )\n        {\n            DLIB_CASSERT(data.size() == labels.size());\n\n            test_one_step(data.begin(), data.end(), labels.begin());\n        }\n\n        template <\n            typename data_iterator,\n            typename label_iterator\n            >\n        void test_one_step (\n            data_iterator dbegin, \n            data_iterator dend,\n            label_iterator lbegin\n        )\n        {\n            DLIB_CASSERT(std::distance(dbegin, dend) > 0);\n\n            print_periodic_verbose_status();\n            sync_to_disk();\n            send_job(true, dbegin, dend, lbegin);\n\n            ++test_one_step_calls;\n        }\n\n        void test_one_step (\n            const std::vector<input_type>& data\n        )\n        {\n            test_one_step(data.begin(), data.end());\n        }\n\n        template <\n            typename data_iterator\n            >\n        void test_one_step (\n            data_iterator dbegin, \n            data_iterator dend\n        )\n        {\n            DLIB_CASSERT(std::distance(dbegin, dend) > 0);\n            print_periodic_verbose_status();\n            sync_to_disk();\n            send_job(true, dbegin, dend);\n            ++test_one_step_calls;\n        }\n\n        void train (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        ) \n        {\n            DLIB_CASSERT(data.size() == labels.size() && data.size() > 0);\n\n            // The reason these two loops don't initialize their counter variables but\n            // instead use class members is so we can include the state of the loops in the\n            // stuff written by sync_to_disk()\n            for (; \n                epoch_iteration < max_num_epochs && learning_rate >= min_learning_rate; \n                ++epoch_iteration)\n            {\n                last_time = std::chrono::system_clock::now();\n                clear_average_loss();\n                for (; epoch_pos < data.size() && learning_rate >= min_learning_rate; epoch_pos += mini_batch_size)\n                {\n                    if (verbose)\n                    {\n                        auto now_time = std::chrono::system_clock::now();\n                        if (now_time-last_time > std::chrono::seconds(20))\n                        {\n                            last_time = now_time;\n                            auto iter = epoch_iteration + epoch_pos/(double)data.size();\n                            std::cout << \"epoch: \" << rpad(cast_to_string(iter),epoch_string_pad) << \"  \" \n                                      << \"learning rate: \" << rpad(cast_to_string(learning_rate),lr_string_pad) << \"  \"\n                                      << \"average loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                            print_progress();\n                        }\n                    }\n\n                    sync_to_disk();\n                    send_job(false, data.begin()+epoch_pos, \n                              data.begin()+std::min(epoch_pos+mini_batch_size,data.size()), \n                              labels.begin()+epoch_pos);\n                }\n                epoch_pos = 0;\n\n                if (verbose)\n                {\n                    // Capitalize the E in Epoch so it's easy to grep out the lines that\n                    // are for full epoch status statements.\n                    std::cout << \"Epoch: \" << rpad(cast_to_string(epoch_iteration+1),epoch_string_pad) << \"  \" \n                              << \"learning rate: \" << rpad(cast_to_string(learning_rate),lr_string_pad) << \"  \"\n                              << \"average loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                    print_progress();\n                }\n            }\n            wait_for_thread_to_pause();\n            // if we modified the network at all then be sure to sync the final result.\n            sync_to_disk(true);\n        }\n\n        void train (\n            const std::vector<input_type>& data\n        ) \n        {\n            DLIB_CASSERT(data.size() > 0);\n\n            const bool has_unsupervised_loss = std::is_same<no_label_type, training_label_type>::value; \n            static_assert(has_unsupervised_loss, \n                \"You can only call this version of train() when using an unsupervised loss.\");\n\n            // The reason these two loops don't initialize their counter variables but\n            // instead use class members is so we can include the state of the loops in the\n            // stuff written by sync_to_disk()\n            for (; \n                epoch_iteration < max_num_epochs && learning_rate >= min_learning_rate; \n                ++epoch_iteration)\n            {\n                last_time = std::chrono::system_clock::now();\n                clear_average_loss();\n                for (; epoch_pos < data.size() && learning_rate >= min_learning_rate; epoch_pos += mini_batch_size)\n                {\n                    if (verbose)\n                    {\n                        auto now_time = std::chrono::system_clock::now();\n                        if (now_time-last_time > std::chrono::seconds(20))\n                        {\n                            last_time = now_time;\n                            auto iter = epoch_iteration + epoch_pos/(double)data.size();\n                            std::cout << \"epoch: \" << rpad(cast_to_string(iter),epoch_string_pad) << \"  \" \n                                      << \"learning rate: \" << rpad(cast_to_string(learning_rate),lr_string_pad) << \"  \"\n                                      << \"average loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                            print_progress();\n                        }\n                    }\n\n                    sync_to_disk();\n                    send_job(false, data.begin()+epoch_pos, \n                             data.begin()+std::min(epoch_pos+mini_batch_size,data.size()));\n                }\n                epoch_pos = 0;\n\n                if (verbose)\n                {\n                    // Capitalize the E in Epoch so it's easy to grep out the lines that\n                    // are for full epoch status statements.\n                    std::cout << \"Epoch: \" << rpad(cast_to_string(epoch_iteration+1),epoch_string_pad) << \"  \" \n                              << \"learning rate: \" << rpad(cast_to_string(learning_rate),lr_string_pad) << \"  \"\n                              << \"average loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                    print_progress();\n                }\n            }\n            wait_for_thread_to_pause();\n            // if we modified the network at all then be sure to sync the final result.\n            sync_to_disk(true);\n        }\n\n        void set_synchronization_file (\n            const std::string& filename,\n            std::chrono::seconds time_between_syncs_ = std::chrono::minutes(15)\n        )\n        {\n            last_sync_time = std::chrono::system_clock::now();\n            sync_filename = filename;\n            time_between_syncs = time_between_syncs_;\n\n            // check if the sync file already exists, if it does we should load it.\n            std::ifstream fin(newest_syncfile(), std::ios::binary);\n            if (fin)\n                deserialize(*this, fin);\n        }\n\n        const std::string& get_synchronization_file (\n        )\n        {\n            return sync_filename;\n        }\n\n        double get_average_loss (\n        ) const \n        { \n            wait_for_thread_to_pause();\n            return rs.mean();\n        }\n\n        double get_average_test_loss (\n        ) const\n        {\n            wait_for_thread_to_pause();\n            return rs_test.mean();\n        }\n\n        void clear_average_loss (\n        )\n        {\n            wait_for_thread_to_pause();\n            rs.clear();\n        }\n\n        void set_learning_rate (\n            double lr\n        )\n        {\n            DLIB_CASSERT(lr > 0);\n            wait_for_thread_to_pause();\n            if (learning_rate != lr)\n            {\n                steps_without_progress = 0;\n                test_steps_without_progress = 0;\n                previous_loss_values.clear();\n                test_previous_loss_values.clear();\n                previous_loss_values_to_keep_until_disk_sync.clear();\n            }\n            learning_rate = lr;\n            lr_schedule.set_size(0);\n        }\n\n        double get_learning_rate(\n        ) const \n        {\n            return learning_rate;\n        }\n\n        void set_min_learning_rate (\n            double lr\n        )\n        {\n            DLIB_CASSERT(lr > 0);\n            wait_for_thread_to_pause();\n            lr_schedule.set_size(0);\n            min_learning_rate = lr;\n        }\n\n        double get_min_learning_rate (\n        ) const\n        {\n            return min_learning_rate;\n        }\n\n        template <typename EXP>\n        void set_learning_rate_schedule (\n            const matrix_exp<EXP>& schedule\n        )\n        {\n            DLIB_CASSERT(schedule.size() > 0);\n            DLIB_CASSERT(min(schedule) > 0);\n            set_learning_rate(schedule(0,0));\n            set_min_learning_rate(min(schedule));\n            set_learning_rate_shrink_factor(1);\n            lr_schedule = matrix_cast<double>(reshape_to_column_vector(schedule));\n            lr_schedule_pos = 0;\n        }\n\n        const matrix<double,0,1>& get_learning_rate_schedule (\n        ) const\n        {\n            return lr_schedule;\n        }\n\n        void set_iterations_without_progress_threshold (\n            unsigned long thresh \n        )\n        {\n            wait_for_thread_to_pause();\n            lr_schedule.set_size(0);\n            iter_without_progress_thresh = thresh;\n        }\n\n        unsigned long get_iterations_without_progress_threshold (\n        ) const\n        {\n            return iter_without_progress_thresh;\n        }\n\n        unsigned long get_steps_without_progress (\n        ) const\n        {\n            return steps_without_progress;\n        }\n\n        void set_test_iterations_without_progress_threshold (\n            unsigned long thresh \n        )\n        {\n            wait_for_thread_to_pause();\n            lr_schedule.set_size(0);\n            test_iter_without_progress_thresh = thresh;\n        }\n\n        unsigned long get_test_iterations_without_progress_threshold (\n        ) const\n        {\n            return test_iter_without_progress_thresh;\n        }\n\n        unsigned long get_test_steps_without_progress (\n        ) const\n        {\n            return test_steps_without_progress;\n        }\n\n        void set_learning_rate_shrink_factor (\n            double shrink\n        )\n        {\n            DLIB_CASSERT(0 < shrink && shrink <= 1);\n            wait_for_thread_to_pause();\n            lr_schedule.set_size(0);\n            learning_rate_shrink = shrink;\n            steps_without_progress = 0;\n            test_steps_without_progress = 0;\n        }\n\n        double get_learning_rate_shrink_factor (\n        ) const\n        {\n            return learning_rate_shrink;\n        }\n\n        unsigned long long get_train_one_step_calls (\n        ) const\n        {\n            return train_one_step_calls;\n        }\n\n        unsigned long long get_test_one_step_calls (\n        ) const\n        {\n            return test_one_step_calls;\n        }\n\n    private:\n\n        void record_test_loss(double loss)\n        {\n            test_previous_loss_values.push_back(loss);\n            if (is_finite(loss))\n                rs_test.add(loss);\n            // discard really old loss values.\n            while (test_previous_loss_values.size() > test_iter_without_progress_thresh)\n                test_previous_loss_values.pop_front();\n        }\n\n        void record_loss(double loss)\n        {\n            // This kind of budgeting causes our gradient checking to use a fixed amount of\n            // computational resources, regardless of the size of iter_without_progress_thresh.\n            gradient_check_budget += 200;\n\n            rs.add(loss);\n            previous_loss_values.push_back(loss);\n            // discard really old loss values.\n            while (previous_loss_values.size() > iter_without_progress_thresh)\n                previous_loss_values.pop_front();\n\n            // separately keep another loss history until disk sync\n            // (but only if disk sync is enabled)\n            if (!sync_filename.empty())\n                previous_loss_values_to_keep_until_disk_sync.push_back(loss);\n        }\n\n        template <typename T>\n        double compute_parameter_gradients(size_t device, job_t& next_job, const T&)\n        {\n            if (next_job.have_data[device])\n            {\n                auto&& dev = *devices[device];\n                dlib::cuda::set_device(dev.device_id);\n                if (next_job.test_only)\n                    return dev.net.compute_loss(next_job.t[device], next_job.labels[device].begin());\n                else\n                    return dev.net.compute_parameter_gradients(next_job.t[device], next_job.labels[device].begin());\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        double compute_parameter_gradients(size_t device, job_t& next_job, const no_label_type&)\n        {\n            if (next_job.have_data[device])\n            {\n                auto&& dev = *devices[device];\n                dlib::cuda::set_device(dev.device_id);\n                no_label_type pick_which_run_update;\n                if (next_job.test_only)\n                    return dev.net.compute_loss(next_job.t[device]);\n                else\n                    return dev.net.compute_parameter_gradients(next_job.t[device]);\n            }\n            else\n            {\n                return 0;\n            }\n        }\n\n        void update_parameters(size_t device)\n        {\n            auto&& dev = *devices[device];\n            dlib::cuda::set_device(dev.device_id);\n            dev.net.update_parameters(make_sstack(dev.solvers), learning_rate);\n        }\n\n        void thread() try\n        {\n            training_label_type pick_which_run_update;\n            job_t next_job;\n\n            std::vector<dlib::future<double>> losses(devices.size());\n\n            std::vector<tt::multi_device_tensor_averager> averagers;\n            // An array of all the parameter tensors in the first network.  We will\n            // periodically copy these tensors to all the other devices to make sure the\n            // different GPUs don't go out of sync.\n            std::vector<tensor*> reference_params;\n            visit_layer_parameters(devices[0]->net, [&](tensor& t) { reference_params.push_back(&t); });\n\n            // If no external thread pools vector was passed, then create one that will\n            // be automatically destructed as soon as the dnn_trainer object goes out of\n            // scope.\n            if (!thread_pools)\n                thread_pools = std::make_shared<threads>();\n\n            auto& tp = *thread_pools;\n\n            // We make separate thread pools with just one thread in them because we want\n            // to make sure each device is always executed on the same thread.  We care\n            // about this because there are thread_local context variables for some cuda\n            // components and they get allocated for each combination of thread and device.\n            // So if we make sure the same device always uses the same thread this will\n            // reduce the number of contexts we allocate from num_devices*num_devices to\n            // just num_devices. \n            while (tp.size() < devices.size())\n                tp.push_back(std::make_shared<thread_pool>(1));\n\n\n            main_iteration_counter = 0;\n            while(job_pipe.dequeue(next_job))\n            {\n                if (next_job.test_only)\n                {\n                    // compute the testing loss\n                    for (size_t i = 0; i < devices.size(); ++i)\n                        tp[i]->add_task_by_value([&,i](double& loss){ loss = compute_parameter_gradients(i, next_job, pick_which_run_update); }, losses[i]);\n                    // aggregate loss values from all the network computations.\n                    double theloss = 0;\n                    for (auto&& loss : losses)\n                        theloss += loss.get();\n                    record_test_loss(theloss/losses.size());\n\n                    // Check if we should shrink the learning rate based on how the test\n                    // error has been doing lately.\n                    if (learning_rate_shrink != 1)\n                    {\n                        test_steps_without_progress = count_steps_without_decrease(test_previous_loss_values);\n                        if (test_steps_without_progress >= test_iter_without_progress_thresh)\n                        {\n                            test_steps_without_progress = count_steps_without_decrease_robust(test_previous_loss_values);\n                            if (test_steps_without_progress >= test_iter_without_progress_thresh)\n                            {\n                                // optimization has flattened out, so drop the learning rate. \n                                learning_rate = learning_rate_shrink*learning_rate;\n                                test_steps_without_progress = 0;\n\n                                // Empty out some of the previous loss values so that test_steps_without_progress \n                                // will decrease below test_iter_without_progress_thresh.  \n                                drop_some_test_previous_loss_values();\n                            }\n                        }\n                    }\n                    continue;\n                }\n\n                updated_net_since_last_sync = true;\n                ++main_iteration_counter;\n                // Call compute_parameter_gradients() and update_parameters() but pick the\n                // right version for unsupervised or supervised training based on the type\n                // of training_label_type.\n                for (size_t i = 0; i < devices.size(); ++i)\n                    tp[i]->add_task_by_value([&,i](double& loss){ loss = compute_parameter_gradients(i, next_job, pick_which_run_update); }, losses[i]);\n                // aggregate loss values from all the network computations.\n                double theloss = 0;\n                for (auto&& loss : losses)\n                    theloss += loss.get();\n                record_loss(theloss/losses.size());\n\n                // Now, if there is more than one active device we need to synchronize the\n                // gradient updates between devices.  So we do that now.\n                if (devices.size() > 1)\n                {\n                    // if this is the first iteration then we need to setup the averagers.\n                    // We can't do this outside the loop because the tensors that get\n                    // averaged need to be allocated to their devices before we call set()\n                    // so that the averagers can determine how best to average them.\n                    if (averagers.size() == 0 || sync_file_reloaded)\n                    {\n                        averagers = std::vector<tt::multi_device_tensor_averager>(net_type::num_computational_layers);\n                        // setup the averagers to point to the tensors in the networks.\n                        std::vector<std::vector<tensor*>> all_tensors(devices.size());\n                        for (size_t i = 0; i < all_tensors.size(); ++i)\n                        {\n                            all_tensors[i].resize(net_type::num_computational_layers);\n                            visit_layer_parameter_gradients(devices[i]->net, [&](size_t j, tensor& t){\n                                all_tensors[i][j] = &t;\n                            });\n                        }\n                        // Now set each averager to average the tensors at the same layer in each\n                        // network.\n                        for (size_t i = 0; i < net_type::num_computational_layers; ++i)\n                        {\n                            std::vector<tensor*> temp(all_tensors.size());\n                            for (size_t j = 0; j < all_tensors.size(); ++j)\n                            {\n                                temp[j] = all_tensors[j][i];\n                                DLIB_CASSERT(temp[0]->size() == temp[j]->size(),\n                                \"Make sure you don't modify the network structure \"\n                                \"or number of parameters after constructing the trainer.\");\n                            }\n                            // ignore layers that don't have parameters\n                            if (temp[0]->size() != 0)\n                                averagers[i].set(temp);\n                        }\n\n                        sync_file_reloaded = false;\n                    }\n\n\n                    for (auto&& d : devices)\n                        cuda::device_synchronize(d->device_id);\n\n                    for (auto&& avg : averagers)\n                        avg.average();\n                }\n\n\n                // Now apply all the updates to each device.\n                for (size_t i = 0; i < devices.size(); ++i)\n                    tp[i]->add_task_by_value([&,i](){ if (next_job.have_data[i]) update_parameters(i); });\n                // and wait for the updates to all happen.\n                for (size_t i = 0; i < devices.size(); ++i)\n                    tp[i]->wait_for_all_tasks();\n\n\n                // Every now and then force all the parameters to be the same just to make\n                // sure they aren't drifting apart due to any non-deterministic behavior on\n                // the GPU.  It's also important to do this on the first iteration because\n                // the different networks may be initialized differently when tensor data\n                // is first passed through them.  So this code block deals with these\n                // issues.\n                if (devices.size() > 1 && main_iteration_counter%2000 == 1)\n                {\n                    for (size_t i = 1; i < devices.size(); ++i)\n                    {\n                        visit_layer_parameters(devices[i]->net, [&](size_t j, tensor& t) \n                        { \n                            memcpy(t, *reference_params[j]);\n                        });\n                    }\n                }\n\n                // If we have been running for a while then check if the loss is still\n                // dropping.  If it isn't then we will reduce the learning rate.  Note that we\n                // have a \"budget\" that prevents us from calling\n                // count_steps_without_decrease() every iteration.  We do this because\n                // it can be expensive to compute when previous_loss_values is large.\n                if (gradient_check_budget > iter_without_progress_thresh && learning_rate_shrink != 1)\n                {\n                    gradient_check_budget = 0;\n                    steps_without_progress = count_steps_without_decrease(previous_loss_values);\n                    if (steps_without_progress >= iter_without_progress_thresh)\n                    {\n                        // Double check that we aren't seeing decrease.  This second check\n                        // discards the top 10% largest values and checks again.  We do\n                        // this because sometimes a mini-batch might be bad and cause the\n                        // loss to suddenly jump up, making count_steps_without_decrease()\n                        // return a large number.  But if we discard the top 10% of the\n                        // values in previous_loss_values then we are robust to that kind\n                        // of noise.  Another way of looking at it, if the reason\n                        // count_steps_without_decrease() returns a large value is only\n                        // because the most recent loss values have suddenly been large,\n                        // then we shouldn't stop or lower the learning rate.  We should\n                        // keep going until whatever disturbance we hit is damped down.  \n                        steps_without_progress = count_steps_without_decrease_robust(previous_loss_values);\n                        if (steps_without_progress >= iter_without_progress_thresh)\n                        {\n                            // optimization has flattened out, so drop the learning rate. \n                            learning_rate = learning_rate_shrink*learning_rate;\n                            steps_without_progress = 0;\n\n                            // Empty out some of the previous loss values so that steps_without_progress \n                            // will decrease below iter_without_progress_thresh.  \n                            drop_some_previous_loss_values();\n                        }\n                    }\n                }\n                else if (lr_schedule.size() != 0) // or use the learning rate schedule if we have one.\n                {\n                    if (lr_schedule_pos < lr_schedule.size())\n                        learning_rate = lr_schedule(lr_schedule_pos++);\n                    else\n                        learning_rate = lr_schedule(lr_schedule.size()-1)*0.99;\n                }\n            }\n        }\n        catch(...)\n        {\n            // If an exception happens then permanently disable the trainer object.\n            job_pipe.disable();\n            std::lock_guard<std::mutex> lock(eptr_mutex);\n            eptr = std::current_exception();\n        }\n\n        void wait_for_thread_to_pause() const\n        {\n            job_pipe.wait_for_num_blocked_dequeues(1);\n        }\n\n        const static long string_pad = 11;\n        const static long epoch_string_pad = 4;\n        const static long lr_string_pad = 4;\n\n        void init()\n        {\n            max_num_epochs = 10000;\n            mini_batch_size = 128;\n            verbose = false;\n            learning_rate = 1e-2;\n            min_learning_rate = 1e-5;\n            iter_without_progress_thresh = 2000;\n            steps_without_progress = 0;\n            test_iter_without_progress_thresh = 500;\n            test_steps_without_progress = 0;\n\n            learning_rate_shrink = 0.1;\n            epoch_iteration = 0;\n            epoch_pos = 0;\n            train_one_step_calls = 0;\n            test_one_step_calls = 0;\n            gradient_check_budget = 0;\n            lr_schedule_pos = 0;\n\n            main_iteration_counter = 0;\n            main_iteration_counter_at_last_disk_sync = 0;\n            prob_loss_increasing_thresh_default_value = 0.99;\n            prob_loss_increasing_thresh_max_value = 0.99999;\n            prob_loss_increasing_thresh = prob_loss_increasing_thresh_default_value;\n            updated_net_since_last_sync = false;\n            sync_file_reloaded = false;\n            previous_loss_values_dump_amount = 400;\n            test_previous_loss_values_dump_amount = 100;\n\n            rs_test = running_stats_decayed<double>(200);\n\n            start();\n        }\n\n        // serialize and deserialize are private because we hold net by reference so\n        // allowing someone to serialize this training object is weird and will likely\n        // result in user errors.  However, we use these functions as part of the automatic\n        // sync code in this object.\n        friend void serialize(const dnn_trainer& item, std::ostream& out)\n        {\n            item.wait_for_thread_to_pause();\n            int version = 13;\n            serialize(version, out);\n\n            size_t nl = dnn_trainer::num_layers;\n            serialize(nl, out);\n            serialize(item.rs, out);\n            serialize(item.rs_test, out);\n            serialize(item.previous_loss_values, out);\n            serialize(item.max_num_epochs, out);\n            serialize(item.mini_batch_size, out);\n            serialize(item.verbose, out);\n            serialize(item.net, out);\n            serialize(item.devices[0]->solvers, out);\n            serialize(item.learning_rate.load(), out);\n            serialize(item.min_learning_rate, out);\n            serialize(item.iter_without_progress_thresh.load(), out);\n            serialize(item.steps_without_progress.load(), out);\n            serialize(item.learning_rate_shrink.load(), out);\n            serialize(item.epoch_iteration, out);\n            serialize(item.epoch_pos, out);\n            serialize(item.train_one_step_calls, out);\n            serialize(item.test_one_step_calls, out);\n            serialize(item.lr_schedule, out);\n            serialize(item.lr_schedule_pos, out);\n            serialize(item.test_iter_without_progress_thresh.load(), out);\n            serialize(item.test_steps_without_progress.load(), out);\n            serialize(item.test_previous_loss_values, out);\n            serialize(item.previous_loss_values_dump_amount, out);\n            serialize(item.test_previous_loss_values_dump_amount, out);\n            serialize(item.previous_loss_values_to_keep_until_disk_sync, out);\n        }\n        friend void deserialize(dnn_trainer& item, std::istream& in)\n        {\n            item.wait_for_thread_to_pause();\n            int version = 0;\n            deserialize(version, in);\n            if (version != 13)\n                throw serialization_error(\"Unexpected version found while deserializing dlib::dnn_trainer.\");\n\n            size_t num_layers = 0;\n            deserialize(num_layers, in);\n            if (num_layers != dnn_trainer::num_layers)\n            {\n                std::ostringstream sout;\n                sout << \"Error deserializing dlib::dnn_trainer.  The saved sync file is for a network with \" << std::endl;\n                sout << \"a different number of layers.  We expected the number of layers to be \" << dnn_trainer::num_layers << \" but\" << std::endl;\n                sout << \"instead the file contains \" << num_layers << \" layers.\" << std::endl;\n                throw serialization_error(sout.str());\n            }\n\n            double dtemp; long ltemp;\n            deserialize(item.rs, in);\n            deserialize(item.rs_test, in);\n            deserialize(item.previous_loss_values, in);\n            deserialize(item.max_num_epochs, in);\n            deserialize(item.mini_batch_size, in);\n            deserialize(item.verbose, in);\n            deserialize(item.net, in);\n            deserialize(item.devices[0]->solvers, in);\n            deserialize(dtemp, in); item.learning_rate = dtemp;\n            deserialize(item.min_learning_rate, in);\n            deserialize(ltemp, in); item.iter_without_progress_thresh = ltemp;\n            deserialize(ltemp, in); item.steps_without_progress = ltemp;\n            deserialize(dtemp, in); item.learning_rate_shrink = dtemp;\n            deserialize(item.epoch_iteration, in);\n            deserialize(item.epoch_pos, in);\n            deserialize(item.train_one_step_calls, in);\n            deserialize(item.test_one_step_calls, in);\n            deserialize(item.lr_schedule, in);\n            deserialize(item.lr_schedule_pos, in);\n            deserialize(ltemp, in); item.test_iter_without_progress_thresh = ltemp;\n            deserialize(ltemp, in); item.test_steps_without_progress = ltemp;\n            deserialize(item.test_previous_loss_values, in);\n            deserialize(item.previous_loss_values_dump_amount, in);\n            deserialize(item.test_previous_loss_values_dump_amount, in);\n            deserialize(item.previous_loss_values_to_keep_until_disk_sync, in);\n\n            if (item.devices.size() > 1)\n            {\n                const auto prev_dev = dlib::cuda::get_device();\n                // initialize all the other device networks and solver objects\n                for (size_t i = 1; i < item.devices.size(); ++i)\n                {\n                    // Switch to this device so that any tensor objects that get allocated when\n                    // we copy this stuff happen on this device.\n                    dlib::cuda::set_device(item.devices[i]->device_id);\n                    item.devices[i]->solvers = item.devices[0]->solvers;\n                    item.devices[i]->net = item.devices[0]->net;\n                }\n                dlib::cuda::set_device(prev_dev);\n            }\n        }\n\n        // Empty out some of the previous loss values so that steps_without_progress will decrease below iter_without_progress_thresh.  \n        void drop_some_previous_loss_values()\n        {\n            for (unsigned long cnt = 0; cnt < previous_loss_values_dump_amount + iter_without_progress_thresh / 10 && previous_loss_values.size() > 0; ++cnt)\n                previous_loss_values.pop_front();\n        }\n\n        // Empty out some of the previous test loss values so that test_steps_without_progress will decrease below test_iter_without_progress_thresh.  \n        void drop_some_test_previous_loss_values()\n        {\n            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)\n                test_previous_loss_values.pop_front();\n        }\n\n        void sync_to_disk (\n            bool do_it_now = false\n        ) \n        {\n            // don't sync anything if we haven't updated the network since the last sync\n            if (!updated_net_since_last_sync)\n                return;\n\n            // If the sync file isn't set then don't do anything.\n            if (sync_filename.size() == 0)\n                return;\n\n            // Only sync if it has been long enough since the last sync or we are being\n            // explicitly forced to do it.\n            if (std::chrono::system_clock::now() - last_sync_time > time_between_syncs ||\n                do_it_now)\n            {\n                wait_for_thread_to_pause();\n\n                // compact network before saving to disk.\n                this->net.clean(); \n\n                // if the loss has actually been going up since the last time we saved our\n                // state to disk then something has probably gone wrong in the\n                // optimization.  So in this case we do the opposite and recall the\n                // previously saved state in the hopes that the problem won't reoccur.\n                if (loss_increased_since_last_disk_sync()) \n                {\n                    std::ifstream fin(newest_syncfile(), std::ios::binary);\n                    deserialize(*this, fin);\n                    sync_file_reloaded = true;\n                    if (verbose)\n                        std::cout << \"Loss has been increasing, reloading saved state from \" << newest_syncfile() << std::endl;\n\n                    // Are we repeatedly hitting our head against the wall? If so, then we\n                    // might be better off giving up at this learning rate, and trying a\n                    // lower one instead.\n                    if (prob_loss_increasing_thresh >= prob_loss_increasing_thresh_max_value)\n                    {\n                        if (verbose && learning_rate_shrink != 1)\n                            std::cout << \"(and while at it, also shrinking the learning rate)\" << std::endl;\n\n                        learning_rate = learning_rate_shrink * learning_rate;\n                        steps_without_progress = 0;\n                        test_steps_without_progress = 0;\n\n                        drop_some_previous_loss_values();\n                        drop_some_test_previous_loss_values();\n                    }\n                }\n                else\n                {\n\n                    const std::string filename = oldest_syncfile();\n                    serialize(filename) << *this;\n\n                    if (verbose)\n                        std::cout << \"Saved state to \" << filename << std::endl;\n                }\n\n                last_sync_time = std::chrono::system_clock::now();\n                main_iteration_counter_at_last_disk_sync = main_iteration_counter;\n                updated_net_since_last_sync = false;\n            }\n        }\n\n        std::string newest_syncfile (\n        )\n        {\n            return select_newest_file(sync_filename, sync_filename + \"_\");\n        }\n\n        std::string oldest_syncfile (\n        )\n        {\n            return select_oldest_file(sync_filename, sync_filename + \"_\");\n        }\n\n        bool loss_increased_since_last_disk_sync() \n        {\n            size_t gradient_updates_since_last_sync = main_iteration_counter - main_iteration_counter_at_last_disk_sync;\n\n            // if we haven't synced anything to disk yet then return false.\n            if (!std::ifstream(newest_syncfile(), std::ios::binary))\n                return false;\n\n            // Now look at the data since a little before the last disk sync.  We will\n            // check if the loss is getting better or worse.\n            while (previous_loss_values_to_keep_until_disk_sync.size() > 2 * gradient_updates_since_last_sync)\n                previous_loss_values_to_keep_until_disk_sync.pop_front();\n\n            // Always retry if there are any nan or inf values\n            for (auto x : previous_loss_values_to_keep_until_disk_sync)\n            {\n                if (std::isnan(x) || std::isinf(x))\n                    return true;\n            }\n\n            // if we haven't seen much data yet then just say false.\n            if (previous_loss_values_to_keep_until_disk_sync.size() < 30)\n                return false;\n\n            // if the loss is very likely to be increasing then return true\n            const double prob1 = probability_values_are_increasing(previous_loss_values_to_keep_until_disk_sync);\n            const double prob2 = probability_values_are_increasing_robust(previous_loss_values_to_keep_until_disk_sync);\n            if (std::max(prob1, prob2) > prob_loss_increasing_thresh)\n            {\n                // Exponentially decay the threshold towards 1 so that if we keep finding\n                // the loss to be increasing over and over we will make the test\n                // progressively harder and harder until it fails, therefore ensuring we\n                // can't get stuck reloading from a previous state over and over. \n                prob_loss_increasing_thresh = std::min(\n                    0.1*prob_loss_increasing_thresh + 0.9*1,\n                    prob_loss_increasing_thresh_max_value\n                );\n                return true;\n            }\n            else\n            {\n                // decay back to the default threshold\n                prob_loss_increasing_thresh = std::pow(prob_loss_increasing_thresh, 10.0);\n                // but don't decay below the default value\n                prob_loss_increasing_thresh = std::max(prob_loss_increasing_thresh, prob_loss_increasing_thresh_default_value);\n\n                return false;\n            }\n        }\n\n\n        struct clone_net{};\n\n        // per device state.  All the containers have the same number of objects in them.\n        struct device_data\n        {\n            device_data(\n                int device_id_,\n                net_type& net_,\n                const solver_type& solver_\n            ) : device_id(device_id_), net(net_), solvers(num_computational_layers, solver_) {}\n\n            device_data(\n                int device_id_,\n                net_type& net_,\n                const solver_type& solver_,\n                clone_net\n            ) : device_id(device_id_), net_copy(std::make_shared<net_type>(net_)), net(*net_copy), solvers(num_computational_layers, solver_) {}\n\n            int device_id;\n            std::shared_ptr<net_type> net_copy;\n            net_type& net;\n            std::vector<solver_type> solvers;\n        };\n\n        template <\n            typename data_iterator,\n            typename label_iterator\n            >\n        void send_job (\n            bool test_only,\n            data_iterator dbegin, \n            data_iterator dend,\n            label_iterator lbegin\n        )\n        {\n            propagate_exception();\n            size_t num = std::distance(dbegin, dend);\n            size_t devs = devices.size();\n            job.t.resize(devs);\n            job.labels.resize(devs);\n            job.have_data.resize(devs);\n            job.test_only = test_only;\n\n            // chop the data into devs blocks, each of about block_size elements.\n            const double block_size = num / static_cast<double>(devs);\n\n            const auto prev_dev = dlib::cuda::get_device();\n\n            const bool has_unsupervised_loss = std::is_same<no_label_type, training_label_type>::value;\n\n            double j = 0;\n\n            for (size_t i = 0; i < devs; ++i)\n            {\n                dlib::cuda::set_device(devices[i]->device_id);\n\n                const size_t start = static_cast<size_t>(std::round(j));\n                const size_t stop  = static_cast<size_t>(std::round(j + block_size));\n\n                if (start < stop)\n                {\n                    devices[i]->net.to_tensor(dbegin+start, dbegin+stop, job.t[i]);\n                    if (!has_unsupervised_loss)\n                        job.labels[i].assign(lbegin+start, lbegin+stop);\n                    job.have_data[i] = true;\n                }\n                else\n                {\n                    job.have_data[i] = false;\n                }\n\n                j += block_size;\n            }\n\n            DLIB_ASSERT(std::fabs(j - num) < 1e-10);\n\n            dlib::cuda::set_device(prev_dev);\n            job_pipe.enqueue(job);\n        }\n\n        template <\n            typename data_iterator\n            >\n        void send_job (\n            bool test_only,\n            data_iterator dbegin, \n            data_iterator dend\n        )\n        {\n            typename std::vector<training_label_type>::iterator nothing;\n            send_job(test_only, dbegin, dend, nothing);\n        }\n\n        void print_progress()\n        {\n            if (lr_schedule.size() == 0)\n            {\n                if (test_previous_loss_values.size() == 0)\n                    std::cout << \"steps without apparent progress: \" << steps_without_progress;\n                else\n                    std::cout << \"steps without apparent progress: train=\" << steps_without_progress << \", test=\" << test_steps_without_progress;\n            }\n            else\n            {\n                std::ostringstream sout;\n                sout << \"percent complete: \" << std::fixed << std::setprecision(2) << 100.0*lr_schedule_pos/(double)lr_schedule.size() << \"%\";\n                std::cout << sout.str();\n            }\n            std::cout << std::endl;\n        }\n\n        void print_periodic_verbose_status()\n        {\n            if (verbose)\n            {\n                auto now_time = std::chrono::system_clock::now();\n                if (now_time-last_time > std::chrono::seconds(40))\n                {\n                    last_time = now_time;\n                    std::cout << \"step#: \" << rpad(cast_to_string(train_one_step_calls),epoch_string_pad) << \"  \" \n                              << \"learning rate: \" << rpad(cast_to_string(learning_rate),lr_string_pad) << \"  \";\n                    if (test_previous_loss_values.size() == 0)\n                    {\n                        std::cout << \"average loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                    }\n                    else\n                    {\n                        std::cout << \"train loss: \" << rpad(cast_to_string(get_average_loss()),string_pad) << \"  \";\n                        std::cout << \"test loss: \" << rpad(cast_to_string(get_average_test_loss()),string_pad) << \"  \";\n                    }\n                    print_progress();\n                    clear_average_loss();\n                }\n            }\n        }\n\n        std::vector<std::shared_ptr<device_data>> devices;\n        dlib::pipe<job_t> job_pipe;\n        std::shared_ptr<threads> thread_pools;\n        job_t job;\n\n\n        running_stats<double> rs;\n        running_stats_decayed<double> rs_test;\n        std::deque<double> previous_loss_values;\n        unsigned long max_num_epochs;\n        size_t mini_batch_size;\n        bool verbose;\n        net_type& net;\n        std::atomic<double> learning_rate;\n        double min_learning_rate;\n        std::atomic<unsigned long> iter_without_progress_thresh;\n        std::atomic<unsigned long> steps_without_progress;\n\n        std::atomic<unsigned long> test_iter_without_progress_thresh;\n        std::atomic<unsigned long> test_steps_without_progress;\n        std::deque<double> test_previous_loss_values;\n\n        std::deque<double> previous_loss_values_to_keep_until_disk_sync;\n\n        std::atomic<double> learning_rate_shrink;\n        std::chrono::time_point<std::chrono::system_clock> last_sync_time;\n        std::string sync_filename;\n        std::chrono::seconds time_between_syncs;\n        unsigned long epoch_iteration;\n        size_t epoch_pos;\n        std::chrono::time_point<std::chrono::system_clock> last_time;\n        unsigned long long train_one_step_calls;\n        unsigned long long test_one_step_calls;\n        matrix<double,0,1> lr_schedule;\n        long lr_schedule_pos;\n        unsigned long gradient_check_budget;\n\n        std::exception_ptr eptr = nullptr;\n        mutable std::mutex eptr_mutex;\n        void propagate_exception() const\n        {\n            std::lock_guard<std::mutex> lock(eptr_mutex);\n            if (eptr)\n                std::rethrow_exception(eptr);\n        }\n\n        // These 5 variables are not serialized \n        size_t main_iteration_counter;\n        size_t main_iteration_counter_at_last_disk_sync;\n        double prob_loss_increasing_thresh_default_value;\n        double prob_loss_increasing_thresh_max_value;\n        double prob_loss_increasing_thresh;\n        std::atomic<bool> updated_net_since_last_sync;\n\n        bool sync_file_reloaded;\n        unsigned long previous_loss_values_dump_amount;\n        unsigned long test_previous_loss_values_dump_amount;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type, \n        typename solver_type \n        >\n    std::ostream& operator<< (\n        std::ostream& out,\n        dnn_trainer<net_type,solver_type>& trainer\n    )\n    {\n        using std::endl;\n        out << \"dnn_trainer details: \\n\";\n        out << \"  net_type::num_layers:  \" << net_type::num_layers << endl;\n        // figure out how big the net is in MB.\n        std::ostringstream sout;\n        net_type temp = trainer.get_net(); // make a copy so that we can clean it without mutating the trainer's net.\n        temp.clean();\n        serialize(temp, sout);\n        out << \"  net size: \" << sout.str().size()/1024.0/1024.0 << \" MiB\";\n        const auto num_params = count_parameters(temp);\n        if (num_params > 0)\n            out << \" (\" << num_params << \" parameters)\";\n        out << endl;\n        // Don't include the loss params in the hash since we print them on the next line.\n        // They also aren't really part of the \"architecture\" of the network.\n        out << \"  net architecture hash: \" << md5(cast_to_string(trainer.get_net().subnet())) << endl;\n        out << \"  loss: \" << trainer.get_net().loss_details() << endl;\n\n        out << \"  get_train_one_step_calls():                 \" << trainer.get_train_one_step_calls() << endl;\n        out << \"  synchronization file:                       \" << trainer.get_synchronization_file() << endl;\n        out << \"  trainer.get_solvers()[0]:                   \" << trainer.get_solvers()[0] << endl;\n        out << \"  mini batch size:                            \" << trainer.get_mini_batch_size() << endl;\n        auto sched = trainer.get_learning_rate_schedule();\n        if (sched.size() != 0)\n        {\n            out << \"  using explicit user-supplied learning rate schedule\" << endl;\n        }\n        else\n        {\n            out << \"  learning rate:                              \"<< trainer.get_learning_rate() << endl;\n            out << \"  learning rate shrink factor:                \"<< trainer.get_learning_rate_shrink_factor() << endl;\n            out << \"  min learning rate:                          \"<< trainer.get_min_learning_rate() << endl;\n            out << \"  iterations without progress threshold:      \"<< trainer.get_iterations_without_progress_threshold() << endl;\n            out << \"  test iterations without progress threshold: \"<< trainer.get_test_iterations_without_progress_threshold() << endl;\n        }\n        return out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_TRAINER_H_\n\n"
  },
  {
    "path": "dlib/dnn/trainer_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_TRAINER_ABSTRACT_H_\n#ifdef DLIB_DNn_TRAINER_ABSTRACT_H_\n\n#include \"core_abstract.h\"\n#include \"solvers_abstract.h\"\n#include <vector>\n#include <chrono>\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    enum class force_flush_to_disk {\n        no = 0,\n        yes = 1\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type, \n        typename solver_type = sgd\n        >\n    class dnn_trainer\n    {\n        /*!\n            REQUIREMENTS ON net_type\n                - net_type is an add_loss_layer object.\n\n            REQUIREMENTS ON solver_type\n                - solver_type is an implementation of the EXAMPLE_SOLVER interface defined\n                  in solvers_abstract.h\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool training a deep neural network. To use it you supply\n                a neural network type and a solver, then you call train() with your\n                training data and it will output a new network instance that has hopefully\n                learned something useful from your training data.\n\n                If you are compiling with CUDA then this object will use the GPU that is\n                currently selected (i.e. the one indicated by cudaGetDevice()) when\n                dnn_trainer is constructed.  It will continue to use that device even if\n                you later change it by a call to cudaSetDevice().\n\n            EXCEPTIONS\n                If an exception is thrown by any part of the neural network during training\n                then the exception will be propagated out of the trainer to the user.\n                Moreover, the trainer instance will be unusable and should be destroyed.\n        !*/\n\n    public:\n\n        typedef typename net_type::training_label_type training_label_type;\n        typedef typename net_type::input_type input_type;\n        const static size_t num_computational_layers = net_type::num_computational_layers;\n\n        using threads = std::vector<std::shared_ptr<thread_pool>>;\n\n        dnn_trainer() = delete;\n        dnn_trainer(const dnn_trainer&) = delete;\n        dnn_trainer& operator=(const dnn_trainer&) = delete;\n\n        dnn_trainer(\n            net_type& net, \n            const solver_type& solver = solver_type(),\n            const std::vector<int>& cuda_extra_devices = {},\n            std::shared_ptr<threads> thread_pools = std::shared_ptr<threads>()\n        ); \n        /*!\n            requires\n                - for all valid i:\n                    - 0 <= cuda_extra_devices[i] < dlib::cuda::get_num_devices()\n            ensures\n                - &#get_net() == &net \n                  (i.e. The dnn_trainer holds a reference to net, it does not copy it.\n                  Therefore, you must ensure net has a lifetime at least as long as the\n                  dnn_trainer).\n                - #get_solvers() == a set of solvers that are all initialized with the\n                  provided solver instance.\n                - #get_max_num_epochs() == 10000\n                - #get_mini_batch_size() == 128\n                - #get_learning_rate() == 1e-2 \n                - #get_min_learning_rate() == 1e-5\n                - #get_iterations_without_progress_threshold() == 2000\n                - #get_test_iterations_without_progress_threshold() == 500\n                - #get_learning_rate_shrink_factor() == 0.1\n                - #get_learning_rate_schedule().size() == 0\n                - #get_train_one_step_calls() == 0\n                - #get_test_one_step_calls() == 0\n                - #get_synchronization_file() == \"\"\n                - if (cuda_extra_devices.size() > 0) then\n                    - This object will use multiple graphics cards to run the learning\n                      algorithms.  In particular, it will always use whatever device is\n                      currently selected on the calling thread (the device indicated by\n                      cudaGetDevice()).  In addition, you can ask to use additional\n                      devices, which you do by putting their device numbers into\n                      cuda_extra_devices.\n                - if (thread_pools.get() != nullptr) then\n                    - Any new threads spun within the trainer will execute within the\n                      passed thread pools vector. This means that the same threads can\n                      be re-used across different dnn_trainer instances. Otherwise, the\n                      CUDA runtime may leak memory. This, however, is relevant only if\n                      your program is going to instantiate a large number of trainers,\n                      and generally stay up and running for a very long time. If not,\n                      then you need not worry about this.\n                      NB: Any particular thread pools vector should be passed to max\n                          one trainer instance at a time.\n                      NB: The mentioned leak isn't happening because dlib is or isn't\n                          doing something. Instead, it is a limitation of the CUDA\n                          runtime that dlib has no control over.\n        !*/\n\n        net_type& get_net (\n            force_flush_to_disk force_flush = force_flush_to_disk::yes\n        ); \n        /*!\n            ensures\n                - returns the neural network object used by this trainer.  This is the\n                  network that is optimized when you call train() or train_one_step().\n                  Recall that the dnn_trainer doesn't contain the net_type object but\n                  simply holds a reference to an external network which was provided to the\n                  dnn_trainer's constructor.\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n                - If force_flush is yes, then this function will sync the trainer state to\n                  disk if the current state hasn't already been synced to disk since the\n                  last network modification.\n        !*/\n\n        const std::vector<solver_type>& get_solvers (\n        ) const; \n        /*!\n            ensures\n                - returns the solvers used to optimize each layer of the neural network\n                  get_net().  In particular, the first layer's solver is\n                  get_solvers()[0], the second layer's solver is\n                  get_solvers()[1], and so on.\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        unsigned long get_mini_batch_size (\n        ) const; \n        /*!\n            ensures\n                - During training, we call the network's update() routine over and over\n                  with training data.  The number of training samples we give to each call\n                  to update is the \"mini-batch size\", which is defined by\n                  get_mini_batch_size().\n        !*/\n\n        void set_mini_batch_size (\n            unsigned long batch_size \n        );\n        /*!\n            requires\n                - batch_size > 0\n            ensures\n                - #get_mini_batch_size() == batch_size\n        !*/\n\n        unsigned long get_max_num_epochs (\n        ) const; \n        /*!\n            ensures\n                - train() will execute at most get_max_num_epochs() iterations over the\n                  training data before returning.\n        !*/\n\n        void set_max_num_epochs (\n            unsigned long num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_max_num_epochs() == num\n        !*/\n\n        void set_learning_rate (\n            double lr\n        );\n        /*!\n            requires\n                - lr > 0\n            ensures\n                - #get_learning_rate() == lr\n                - #get_learning_rate_schedule().size() == 0\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        double get_learning_rate(\n        ) const;\n        /*!\n            ensures\n                - During each training step, a solver tells us how to modify the parameters\n                  of each layer in the network.  It does this by outputting a step vector\n                  that, when added to the parameters, will hopefully result in improved\n                  network performance.  The learning rate is one of the inputs to the\n                  solver and influences the size of this step vector.  This function\n                  returns the current learning rate, that is, the learning rate that will\n                  be used during the next training step.\n        !*/\n\n        void set_min_learning_rate (\n            double lr\n        );\n        /*!\n            requires\n                - lr > 0\n            ensures\n                - #get_min_learning_rate() == lr\n                - #get_learning_rate_schedule().size() == 0\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        double get_min_learning_rate (\n        ) const;\n        /*!\n            ensures\n                - During training via this->train(), this object will test if progress is\n                  still being made and if it isn't then it will reduce get_learning_rate()\n                  by setting it to get_learning_rate()*get_learning_rate_shrink_factor().\n                  However, it will not reduce it below get_min_learning_rate().  Once this\n                  minimum learning rate is crossed the training will terminate.\n                - get_min_learning_rate() doesn't apply if you are using train_one_step().  \n                  You can keep calling train_one_step() as many times as you want and the\n                  learning rate will drop infinitely close to 0 if you run long enough.\n        !*/\n\n        template <typename EXP>\n        void set_learning_rate_schedule (\n            const matrix_exp<EXP>& schedule\n        );\n        /*!\n            requires\n                - schedule.size() > 0\n                - min(schedule) > 0\n            ensures\n                - #get_learning_rate_schedule() == reshape_to_column_vector(schedule)\n                - #get_learning_rate() == schedule(0,0)\n                - #get_min_learning_rate() == min(schedule)\n                - #set_learning_rate_shrink_factor() == 1\n        !*/\n\n        const matrix<double,0,1>& get_learning_rate_schedule (\n        ) const;\n        /*!\n            ensures\n                - if (this function returns a non-empty matrix) then\n                    - This trainer will use an explicit learning rate schedule defined by\n                      the learning rate values in get_learning_rate_schedule().  For\n                      example, if get_learning_rate_schedule() returned {0.1, 0.09, 0.08,\n                      0.07, 0.06} then the first training mini-batch would use a learning\n                      rate of 0.1, then the next training mini-batch uses 0.09, and then\n                      0.8, and so on until the end of the schedule is reached.  \n                      \n                      If you continue to run training after the end of the schedule has\n                      been reached then the learning rate will be fixed to 0.99 times the\n                      final value.  So in our example, eventually the learning rate would\n                      be fixed to 0.99*0.06.  This allows you to test if we have reached the\n                      end of the schedule by checking if get_learning_rate() >= 0.06.\n        !*/\n\n        unsigned long get_steps_without_progress (\n        ) const;\n        /*!\n            ensures\n                - if (get_learning_rate_shrink_factor() != 1) then\n                    - returns an estimate of how many mini-batches have executed without us\n                      observing a statistically significant decrease in the training error.\n                - else\n                    - returns 0\n        !*/\n\n        void set_iterations_without_progress_threshold (\n            unsigned long thresh \n        );\n        /*!\n            ensures\n                - #get_iterations_without_progress_threshold() == thresh\n                - #get_learning_rate_schedule().size() == 0\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        unsigned long get_iterations_without_progress_threshold (\n        ) const;\n        /*!\n            ensures\n                - This object monitors the progress of training and estimates if the\n                  training error is being reduced.  It does this by looking at the previous\n                  get_iterations_without_progress_threshold() mini-batch results and\n                  applying the statistical test defined by the running_gradient object to\n                  see if the training error is getting smaller.  If it isn't being reduced\n                  then get_learning_rate() is made smaller by a factor of get_learning_rate_shrink_factor().\n\n                  Therefore, get_iterations_without_progress_threshold() should always be\n                  set to something sensibly large so that this test can be done with\n                  reasonably high confidence.  Think of this test as saying \"if the loss\n                  hasn't decreased for the previous get_iterations_without_progress_threshold() \n                  then shrink the learning rate\".\n        !*/\n\n        void set_learning_rate_shrink_factor (\n            double shrink\n        );\n        /*!\n            requires\n                - 0 < shrink && shrink <= 1\n            ensures\n                - #get_learning_rate_shrink_factor() == shrink\n                - #get_learning_rate_schedule().size() == 0\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        double get_learning_rate_shrink_factor (\n        ) const;\n        /*!\n            ensures\n                - Whenever the training routine thinks it isn't making progress anymore it\n                  will reduce get_learning_rate() by multiplying it by get_learning_rate_shrink_factor().\n                - You can disable the automatic learning rate reduction by setting\n                  get_learning_rate_shrink_factor() to 1.\n        !*/\n\n        unsigned long long get_train_one_step_calls (\n        ) const;\n        /*!\n            ensures\n                - returns the number of times train_one_step() has been called.\n        !*/\n\n        unsigned long long get_test_one_step_calls (\n        ) const;\n        /*!\n            ensures\n                - returns the number of times test_one_step() has been called.\n        !*/\n\n        void be_verbose (\n        );\n        /*!\n            ensures\n                - This object will print status messages to standard out so that a \n                  user can observe the progress of the algorithm.\n        !*/\n\n        void be_quiet (\n        );\n        /*!\n            ensures\n                - This object will not print anything to standard out\n        !*/\n\n        void set_synchronization_file (\n            const std::string& filename,\n            std::chrono::seconds time_between_syncs = std::chrono::minutes(15)\n        );\n        /*!\n            ensures\n                - #get_synchronization_file() == filename\n                - While training is running, either via train() or repeated calls to\n                  train_one_step(), this object will save its entire state, including the\n                  state of get_net(), to disk in the file named filename every\n                  time_between_syncs seconds.\n                - If the filename file already exists then the state of this trainer will\n                  be loaded from that file by this call to set_synchronization_file().\n                  This allows you to resume a training session which was previously\n                  interrupted.\n                - It should be noted that when saving, the trainer will alternate between\n                  saving to a file called filename and another file called filename+\"_\".\n                  We do this because it's possible that your computer might crash (not\n                  because of dlib, just in general) before the data is safely saved to\n                  disk.  This way, you will always have a backup file if the write to disk\n                  gets corrupted or is incomplete.  Moreover, when loading, we will always\n                  load from the newest of the two possible files.\n        !*/\n\n        const std::string& get_synchronization_file (\n        );\n        /*!\n            ensures\n                - Returns the name of the file the dnn_trainer will periodically save it's\n                  state to.  If the return value is \"\" then synchronization is disabled.\n        !*/\n\n        void train (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        ); \n        /*!\n            requires\n                - data.size() == labels.size()\n                - data.size() > 0\n                - net_type uses a supervised loss.  \n                  i.e. net_type::training_label_type != no_label_type.\n            ensures\n                - Trains a supervised neural network based on the given training data.\n                  The goal of training is to find the network parameters that minimize\n                  get_net().compute_loss(data.begin(), data.end(), labels.begin()). \n                - The optimizer will run until get_learning_rate() < get_min_learning_rate() \n                  or get_max_num_epochs() training epochs have been executed. \n                - Each layer in the network will be optimized by its corresponding solver\n                  in get_solvers().  \n                - Each call to train DOES NOT reinitialize the state of get_net() or\n                  get_solvers().  That is, the existing state of the solvers and network is\n                  the starting point for the optimization each time train() is called.  In\n                  particular, if you use the set_synchronization_file() method you can\n                  resume an interrupted train() call by simply calling train() again and it\n                  will pick up from the last synchronization point.  \n                - You can obtain the average loss value during the final training epoch by\n                  calling get_average_loss().\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        void train (\n            const std::vector<input_type>& data\n        );\n        /*!\n            requires \n                - data.size() > 0\n                - net_type uses an unsupervised loss.  \n                  i.e. net_type::training_label_type == no_label_type.\n            ensures\n                - Trains an unsupervised neural network based on the given training data.\n                  The goal of training is to find the network parameters that minimize\n                  get_net().compute_loss(data.begin(), data.end()). \n                - The optimizer will run until get_learning_rate() < get_min_learning_rate() \n                  or get_max_num_epochs() training epochs have been executed. \n                - Each layer in the network will be optimized by its corresponding solver\n                  in get_solvers().  \n                - Each call to train DOES NOT reinitialize the state of get_net() or\n                  get_solvers().  That is, the existing state of the solvers and network is\n                  the starting point for the optimization each time train() is called.  In\n                  particular, if you use the set_synchronization_file() method you can\n                  resume an interrupted train() call by simply calling train() again and it\n                  will pick up from the last synchronization point.  \n                - You can obtain the average loss value during the final training epoch by\n                  calling get_average_loss().\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        void train_one_step (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        );\n        /*!\n            requires\n                - data.size() == labels.size()\n                - data.size() > 0\n                - net_type uses a supervised loss.  \n                  i.e. net_type::training_label_type != no_label_type.\n            ensures\n                - Performs one stochastic gradient update step based on the mini-batch of\n                  data and labels supplied to this function.  In particular, calling\n                  train_one_step() in a loop is equivalent to calling the train() method\n                  defined above.  However, train_one_step() allows you to stream data from\n                  disk into the training process while train() requires you to first load\n                  all the training data into RAM.  Otherwise, these training methods are\n                  equivalent.\n                - You can observe the current average loss value by calling get_average_loss().\n                - The network training will happen in another thread.  Therefore, after\n                  calling this function you should call get_net() before you touch the net\n                  object from the calling thread to ensure no other threads are still\n                  accessing the network.\n                - #get_train_one_step_calls() == get_train_one_step_calls() + 1.\n        !*/\n\n        template <\n            typename data_iterator,\n            typename label_iterator\n            >\n        void train_one_step (\n            data_iterator dbegin,\n            data_iterator dend,\n            label_iterator lbegin\n        );\n        /*!\n            requires\n                - std::advance(lbegin, std::distance(dbegin, dend) - 1) is dereferencable\n                - std::distance(dbegin, dend) > 0\n                - net_type uses a supervised loss.  \n                  i.e. net_type::training_label_type != no_label_type.\n            ensures\n                - Performs one stochastic gradient update step based on the mini-batch of\n                  data and labels supplied to this function.  In particular, calling\n                  train_one_step() in a loop is equivalent to calling the train() method\n                  defined above.  However, train_one_step() allows you to stream data from\n                  disk into the training process while train() requires you to first load\n                  all the training data into RAM.  Otherwise, these training methods are\n                  equivalent.\n                - You can observe the current average loss value by calling get_average_loss().\n                - The network training will happen in another thread.  Therefore, after\n                  calling this function you should call get_net() before you touch the net\n                  object from the calling thread to ensure no other threads are still\n                  accessing the network.\n                - #get_train_one_step_calls() == get_train_one_step_calls() + 1.\n        !*/\n\n        void train_one_step (\n            const std::vector<input_type>& data\n        );\n        /*!\n            requires\n                - data.size() > 0\n                - net_type uses an unsupervised loss.  \n                  i.e. net_type::training_label_type == no_label_type.\n            ensures\n                - Performs one stochastic gradient update step based on the mini-batch of\n                  data supplied to this function.  In particular, calling train_one_step()\n                  in a loop is equivalent to calling the train() method defined above.\n                  However, train_one_step() allows you to stream data from disk into the\n                  training process while train() requires you to first load all the\n                  training data into RAM.  Otherwise, these training methods are\n                  equivalent.\n                - You can observe the current average loss value by calling get_average_loss().\n                - The network training will happen in another thread.  Therefore, after\n                  calling this function you should call get_net() before you touch the net\n                  object from the calling thread to ensure no other threads are still\n                  accessing the network.\n                - #get_train_one_step_calls() == get_train_one_step_calls() + 1.\n        !*/\n\n        template <\n            typename data_iterator\n            >\n        void train_one_step (\n            data_iterator dbegin,\n            data_iterator dend\n        );\n        /*!\n            requires\n                - std::distance(dbegin, dend) > 0\n                - net_type uses an unsupervised loss.  \n                  i.e. net_type::training_label_type == no_label_type.\n            ensures\n                - Performs one stochastic gradient update step based on the mini-batch of\n                  data supplied to this function.  In particular, calling train_one_step()\n                  in a loop is equivalent to calling the train() method defined above.\n                  However, train_one_step() allows you to stream data from disk into the\n                  training process while train() requires you to first load all the\n                  training data into RAM.  Otherwise, these training methods are\n                  equivalent.\n                - You can observe the current average loss value by calling get_average_loss().\n                - The network training will happen in another thread.  Therefore, after\n                  calling this function you should call get_net() before you touch the net\n                  object from the calling thread to ensure no other threads are still\n                  accessing the network.\n                - #get_train_one_step_calls() == get_train_one_step_calls() + 1.\n        !*/\n        \n        double get_average_loss (\n        ) const;\n        /*!\n            ensures\n                - returns the average loss value observed during previous calls to\n                  train_one_step() or train().  That is, the average output of\n                  net_type::update() during the previous mini-batch updates.\n                - Note that, if be_verbose() has been called, then this object will\n                  automatically call clear_average_loss() periodically when it logs the\n                  loss to the console.\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        void clear_average_loss (\n        );\n        /*!\n            ensures\n                - #get_average_loss() == 0\n                - get_average_loss() uses a dlib::running_stats object to keep a running\n                  average of the loss values seen during the previous mini-batch updates\n                  applied during training.  Calling clear_average_loss() resets the\n                  running_stats object so it forgets about all previous loss values\n                  observed.\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n    // ----------------------\n\n        double get_average_test_loss (\n        ) const;\n        /*!\n            ensures\n                - returns the average loss value observed during previous calls to\n                  test_one_step(). \n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        void test_one_step (\n            const std::vector<input_type>& data,\n            const std::vector<training_label_type>& labels \n        );\n        /*!\n            requires\n                - data.size() == labels.size()\n                - data.size() > 0\n                - net_type uses a supervised loss.  \n                  i.e. net_type::training_label_type != no_label_type.\n            ensures\n                - Runs the given data through the network and computes and records the loss.  \n                - This call does not modify network parameters.  The point of\n                  test_one_step() is two fold, to allow you to observe the accuracy of the\n                  network on hold out data during training, and to allow the trainer to\n                  automatically adjust the learning rate when the test loss stops\n                  improving.  It should be noted that you are not required to use\n                  test_one_step() at all, but if you want to do this kind of thing it is\n                  available.\n                - You can observe the current average loss value by calling get_average_test_loss().\n                - The computation will happen in another thread.  Therefore, after calling\n                  this function you should call get_net() before you touch the net object\n                  from the calling thread to ensure no other threads are still accessing\n                  the network.\n                - #get_test_one_step_calls() == get_test_one_step_calls() + 1.\n        !*/\n\n        template <\n            typename data_iterator,\n            typename label_iterator\n            >\n        void test_one_step (\n            data_iterator dbegin, \n            data_iterator dend,\n            label_iterator lbegin\n        );\n        /*!\n            requires\n                - std::advance(lbegin, std::distance(dbegin, dend) - 1) is dereferencable\n                - std::distance(dbegin, dend) > 0\n                - net_type uses a supervised loss.  \n                  i.e. net_type::training_label_type != no_label_type.\n            ensures\n                - Runs the given data through the network and computes and records the loss.  \n                - This call does not modify network parameters.  The point of\n                  test_one_step() is two fold, to allow you to observe the accuracy of the\n                  network on hold out data during training, and to allow the trainer to\n                  automatically adjust the learning rate when the test loss stops\n                  improving.  It should be noted that you are not required to use\n                  test_one_step() at all, but if you want to do this kind of thing it is\n                  available.\n                - You can observe the current average loss value by calling get_average_test_loss().\n                - The computation will happen in another thread.  Therefore, after calling\n                  this function you should call get_net() before you touch the net object\n                  from the calling thread to ensure no other threads are still accessing\n                  the network.\n                - #get_test_one_step_calls() == get_test_one_step_calls() + 1.\n        !*/\n\n        void test_one_step (\n            const std::vector<input_type>& data\n        );\n        /*!\n            requires\n                - data.size() > 0\n                - net_type uses an unsupervised loss.  \n                  i.e. net_type::training_label_type == no_label_type.\n            ensures\n                - Runs the given data through the network and computes and records the loss.  \n                - This call does not modify network parameters.  The point of\n                  test_one_step() is two fold, to allow you to observe the accuracy of the\n                  network on hold out data during training, and to allow the trainer to\n                  automatically adjust the learning rate when the test loss stops\n                  improving.  It should be noted that you are not required to use\n                  test_one_step() at all, but if you want to do this kind of thing it is\n                  available.\n                - You can observe the current average loss value by calling get_average_test_loss().\n                - The computation will happen in another thread.  Therefore, after calling\n                  this function you should call get_net() before you touch the net object\n                  from the calling thread to ensure no other threads are still accessing\n                  the network.\n                - #get_test_one_step_calls() == get_test_one_step_calls() + 1.\n        !*/\n\n        template <\n            typename data_iterator\n            >\n        void test_one_step (\n            data_iterator dbegin, \n            data_iterator dend\n        );\n        /*!\n            requires\n                - std::distance(dbegin, dend) > 0\n                - net_type uses an unsupervised loss.  \n                  i.e. net_type::training_label_type == no_label_type.\n            ensures\n                - Runs the given data through the network and computes and records the loss.  \n                - This call does not modify network parameters.  The point of\n                  test_one_step() is two fold, to allow you to observe the accuracy of the\n                  network on hold out data during training, and to allow the trainer to\n                  automatically adjust the learning rate when the test loss stops\n                  improving.  It should be noted that you are not required to use\n                  test_one_step() at all, but if you want to do this kind of thing it is\n                  available.\n                - You can observe the current average loss value by calling get_average_test_loss().\n                - The computation will happen in another thread.  Therefore, after calling\n                  this function you should call get_net() before you touch the net object\n                  from the calling thread to ensure no other threads are still accessing\n                  the network.\n                - #get_test_one_step_calls() == get_test_one_step_calls() + 1.\n        !*/\n\n        void set_test_iterations_without_progress_threshold (\n            unsigned long thresh \n        );\n        /*!\n            ensures\n                - #get_test_iterations_without_progress_threshold() == thresh\n                - #get_learning_rate_schedule().size() == 0\n                - This function blocks until all threads inside the dnn_trainer have\n                  stopped touching the net. \n        !*/\n\n        unsigned long get_test_iterations_without_progress_threshold (\n        ) const;\n        /*!\n            ensures\n                - This object monitors the progress of training and estimates if the\n                  testing error is being reduced.  It does this by looking at the previous\n                  get_test_iterations_without_progress_threshold() mini-batch results from\n                  test_one_step() and applying the statistical test defined by the\n                  running_gradient object to see if the testing error is getting smaller.\n                  If it isn't being reduced then get_learning_rate() is made smaller by a\n                  factor of get_learning_rate_shrink_factor().\n\n                  Therefore, get_test_iterations_without_progress_threshold() should always be\n                  set to something sensibly large so that this test can be done with\n                  reasonably high confidence.  Think of this test as saying \"if the testing loss\n                  hasn't decreased for the previous get_test_iterations_without_progress_threshold() \n                  calls to test_one_step() then shrink the learning rate\".\n        !*/\n\n        unsigned long get_test_steps_without_progress (\n        ) const;\n        /*!\n            ensures\n                - if (get_learning_rate_shrink_factor() != 1) then\n                    - returns an estimate of how many mini-batches have executed without us\n                      observing a statistically significant decrease in the testing error\n                      (i.e. the error on the data given to the trainer via test_one_step()\n                      calls).\n                - else\n                    - returns 0\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename net_type, \n        typename solver_type \n        >\n    std::ostream& operator<< (\n        std::ostream& out,\n        dnn_trainer<net_type,solver_type>& trainer\n    );\n    /*!\n        ensures\n            - Prints a log of the current parameters of trainer to out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_TRAINER_ABSTRACT_H_ \n\n\n"
  },
  {
    "path": "dlib/dnn/utilities.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_UTILITIES_H_\n#define DLIB_DNn_UTILITIES_H_\n\n#include \"../cuda/tensor.h\"\n#include \"utilities_abstract.h\"\n#include \"../geometry.h\"\n#include <fstream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline void randomize_parameters (\n        tensor& params,\n        unsigned long num_inputs_and_outputs,\n        dlib::rand& rnd\n    )\n    {\n        for (auto& val : params)\n        {\n            // Draw a random number to initialize the layer according to formula (16)\n            // from Understanding the difficulty of training deep feedforward neural\n            // networks by Xavier Glorot and Yoshua Bengio.\n            val = 2*rnd.get_random_float()-1;\n            val *= std::sqrt(6.0/(num_inputs_and_outputs));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename label_type>\n    struct weighted_label\n    {\n        weighted_label()\n        {}\n\n        weighted_label(label_type label, float weight = 1.f)\n            : label(label), weight(weight)\n        {}\n\n        label_type label{};\n        float weight = 1.f;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline double log1pexp(double x)\n    {\n        using std::exp;\n        if (x <= -37)\n            return exp(x);\n        else if (-37 < x && x <= 18)\n            return log1p(exp(x));\n        else if (18 < x && x <= 33.3)\n            return x + exp(-x);\n        else\n            return x;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    T safe_log(T input, T epsilon = 1e-10)\n    {\n        // Prevent trying to calculate the logarithm of a very small number (let alone zero)\n        return std::log(std::max(input, epsilon));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline size_t tensor_index(\n        const tensor& t,\n        const long sample,\n        const long k,\n        const long r,\n        const long c\n    )\n    {\n        return ((sample * t.k() + k) * t.nr() + r) * t.nc() + c;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_UTILITIES_H_ \n\n\n\n"
  },
  {
    "path": "dlib/dnn/utilities_abstract.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_UTILITIES_ABSTRACT_H_\n#ifdef DLIB_DNn_UTILITIES_ABSTRACT_H_\n\n#include \"core_abstract.h\"\n#include \"../geometry/vector_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    double log1pexp(\n        double x\n    );\n    /*!\n        ensures\n            - returns log(1+exp(x))\n              (except computes it using a numerically accurate method)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void randomize_parameters (\n        tensor& params,\n        unsigned long num_inputs_and_outputs,\n        dlib::rand& rnd\n    );\n    /*!\n        ensures\n            - This function assigns random values into params based on the given random\n              number generator.  In particular, it uses the parameter initialization method\n              of formula 16 from the paper \"Understanding the difficulty of training deep\n              feedforward neural networks\" by Xavier Glorot and Yoshua Bengio.\n            - It is assumed that the total number of inputs and outputs from the layer is\n              num_inputs_and_outputs.  That is, you should set num_inputs_and_outputs to\n              the sum of the dimensionalities of the vectors going into and out of the\n              layer that uses params as its parameters.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_DNn_UTILITIES_ABSTRACT_H_ \n\n\n"
  },
  {
    "path": "dlib/dnn/validation.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_VALIDATION_H_\n#define DLIB_DNn_VALIDATION_H_\n\n#include \"../svm/cross_validate_object_detection_trainer_abstract.h\"\n#include \"../svm/cross_validate_object_detection_trainer.h\"\n#include \"layers.h\"\n#include <set>\n\nnamespace dlib\n{\n    namespace impl\n    {\n        inline std::set<std::string> get_labels (\n            const std::vector<mmod_rect>& rects1,\n            const std::vector<mmod_rect>& rects2\n        )\n        {\n            std::set<std::string> labels;\n            for (auto& rr : rects1)\n                labels.insert(rr.label);\n            for (auto& rr : rects2)\n                labels.insert(rr.label);\n            return labels;\n        }\n    }\n\n    template <\n        typename SUBNET,\n        typename image_array_type\n        >\n    const matrix<double,1,3> test_object_detection_function (\n        loss_mmod<SUBNET>& detector,\n        const image_array_type& images,\n        const std::vector<std::vector<mmod_rect>>& truth_dets,\n        const test_box_overlap& overlap_tester = test_box_overlap(),\n        const double adjust_threshold = 0,\n        const test_box_overlap& overlaps_ignore_tester = test_box_overlap()\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( is_learning_problem(images,truth_dets) == true , \n                    \"\\t matrix test_object_detection_function()\"\n                    << \"\\n\\t invalid inputs were given to this function\"\n                    << \"\\n\\t is_learning_problem(images,truth_dets): \" << is_learning_problem(images,truth_dets)\n                    << \"\\n\\t images.size(): \" << images.size() \n                    );\n\n\n\n        double correct_hits = 0;\n        double total_true_targets = 0;\n\n        std::vector<std::pair<double,bool> > all_dets;\n        unsigned long missing_detections = 0;\n\n        resizable_tensor temp;\n\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            std::vector<mmod_rect> hits; \n            detector.to_tensor(&images[i], &images[i]+1, temp);\n            detector.subnet().forward(temp);\n            detector.loss_details().to_label(temp, detector.subnet(), &hits, adjust_threshold);\n\n\n            for (auto& label : impl::get_labels(truth_dets[i], hits))\n            {\n                std::vector<full_object_detection> truth_boxes;\n                std::vector<rectangle> ignore;\n                std::vector<std::pair<double,rectangle>> boxes;\n                // copy hits and truth_dets into the above three objects\n                for (auto&& b : truth_dets[i])\n                {\n                    if (b.ignore)\n                    {\n                        ignore.push_back(b);\n                    }\n                    else if (b.label == label)\n                    {\n                        truth_boxes.push_back(full_object_detection(b.rect));\n                        ++total_true_targets;\n                    }\n                }\n                for (auto&& b : hits)\n                {\n                    if (b.label == label)\n                        boxes.push_back(std::make_pair(b.detection_confidence, b.rect));\n                }\n\n                correct_hits += impl::number_of_truth_hits(truth_boxes, ignore, boxes, overlap_tester, all_dets, missing_detections, overlaps_ignore_tester);\n            }\n        }\n\n        std::sort(all_dets.rbegin(), all_dets.rend());\n\n        double precision, recall;\n\n        double total_hits = all_dets.size();\n\n        if (total_hits == 0)\n            precision = 1;\n        else\n            precision = correct_hits / total_hits;\n\n        if (total_true_targets == 0)\n            recall = 1;\n        else\n            recall = correct_hits / total_true_targets;\n\n        matrix<double, 1, 3> res;\n        res = precision, recall, average_precision(all_dets, missing_detections);\n        return res;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_VALIDATION_H_\n\n"
  },
  {
    "path": "dlib/dnn/visitors.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_VISITORS_H_\n#define DLIB_DNn_VISITORS_H_\n\n#include \"visitors_abstract.h\"\n#include \"input.h\"\n#include \"layers.h\"\n#include \"loss.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n        class visitor_net_map_input_to_output\n        {\n        public:\n\n            visitor_net_map_input_to_output(dpoint& p_) : p(p_) {}\n\n            dpoint& p;\n\n            template<typename input_layer_type>\n            void operator()(const input_layer_type& )\n            {\n            }\n\n            template <typename T, typename U>\n            void operator()(const add_loss_layer<T,U>& net)\n            {\n                (*this)(net.subnet());\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(const add_layer<T,U,E>& net)\n            {\n                (*this)(net.subnet());\n                p = net.layer_details().map_input_to_output(p);\n            }\n            template <bool B, typename T, typename U, typename E>\n            void operator()(const dimpl::subnet_wrapper<add_layer<T,U,E>,B>& net)\n            {\n                (*this)(net.subnet());\n                p = net.layer_details().map_input_to_output(p);\n            }\n            template <size_t N, template <typename> class R, typename U>\n            void operator()(const repeat<N, R, U>& net)\n            {\n                (*this)(net.subnet());\n                for (size_t i = 0; i < N; ++i)\n                {\n                    (*this)(net.get_repeated_layer(N-1-i).subnet());\n                }\n            }\n\n\n            template <unsigned long ID, typename U, typename E>\n            void operator()(const add_tag_layer<ID,U,E>& net)\n            {\n                // tag layers are an identity transform, so do nothing\n                (*this)(net.subnet());\n            }\n            template <bool is_first, unsigned long ID, typename U, typename E>\n            void operator()(const dimpl::subnet_wrapper<add_tag_layer<ID,U,E>,is_first>& net)\n            {\n                // tag layers are an identity transform, so do nothing\n                (*this)(net.subnet());\n            }\n\n\n            template <template<typename> class TAG_TYPE, typename U>\n            void operator()(const add_skip_layer<TAG_TYPE,U>& net)\n            {\n                (*this)(layer<TAG_TYPE>(net));\n            }\n            template <bool is_first, template<typename> class TAG_TYPE, typename SUBNET>\n            void operator()(const dimpl::subnet_wrapper<add_skip_layer<TAG_TYPE,SUBNET>,is_first>& net)\n            {\n                // skip layers are an identity transform, so do nothing\n                (*this)(layer<TAG_TYPE>(net));\n            }\n\n        };\n\n        class visitor_net_map_output_to_input\n        {\n        public:\n            visitor_net_map_output_to_input(dpoint& p_) : p(p_) {}\n\n            dpoint& p;\n\n            template<typename input_layer_type>\n            void operator()(const input_layer_type& )\n            {\n            }\n\n            template <typename T, typename U>\n            void operator()(const add_loss_layer<T,U>& net)\n            {\n                (*this)(net.subnet());\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(const add_layer<T,U,E>& net)\n            {\n                p = net.layer_details().map_output_to_input(p);\n                (*this)(net.subnet());\n            }\n            template <bool B, typename T, typename U, typename E>\n            void operator()(const dimpl::subnet_wrapper<add_layer<T,U,E>,B>& net)\n            {\n                p = net.layer_details().map_output_to_input(p);\n                (*this)(net.subnet());\n            }\n            template <size_t N, template <typename> class R, typename U>\n            void operator()(const repeat<N, R, U>& net)\n            {\n                for (size_t i = 0; i < N; ++i)\n                {\n                    (*this)(net.get_repeated_layer(i).subnet());\n                }\n                (*this)(net.subnet());\n            }\n\n\n            template <unsigned long ID, typename U, typename E>\n            void operator()(const add_tag_layer<ID,U,E>& net)\n            {\n                // tag layers are an identity transform, so do nothing\n                (*this)(net.subnet());\n            }\n            template <bool is_first, unsigned long ID, typename U, typename E>\n            void operator()(const dimpl::subnet_wrapper<add_tag_layer<ID,U,E>,is_first>& net)\n            {\n                // tag layers are an identity transform, so do nothing\n                (*this)(net.subnet());\n            }\n\n\n            template <template<typename> class TAG_TYPE, typename U>\n            void operator()(const add_skip_layer<TAG_TYPE,U>& net)\n            {\n                (*this)(layer<TAG_TYPE>(net));\n            }\n            template <bool is_first, template<typename> class TAG_TYPE, typename SUBNET>\n            void operator()(const dimpl::subnet_wrapper<add_skip_layer<TAG_TYPE,SUBNET>,is_first>& net)\n            {\n                // skip layers are an identity transform, so do nothing\n                (*this)(layer<TAG_TYPE>(net));\n            }\n\n        };\n    }\n\n    template <typename net_type>\n    inline dpoint input_tensor_to_output_tensor(\n        const net_type& net,\n        dpoint p\n    )\n    {\n        impl::visitor_net_map_input_to_output temp(p);\n        temp(net);\n        return p;\n    }\n\n    template <typename net_type>\n    inline dpoint output_tensor_to_input_tensor(\n        const net_type& net,\n        dpoint p\n    )\n    {\n        impl::visitor_net_map_output_to_input temp(p);\n        temp(net);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    size_t count_parameters(\n        const net_type& net\n    )\n    {\n        size_t num_parameters = 0;\n        visit_layer_parameters(net, [&](const tensor& t) { num_parameters += t.size(); });\n        return num_parameters;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_learning_rate_multiplier\n        {\n        public:\n            visitor_learning_rate_multiplier(double new_learning_rate_multiplier_) :\n                new_learning_rate_multiplier(new_learning_rate_multiplier_) {}\n\n            template <typename layer>\n            void operator()(layer& l) const\n            {\n                set_learning_rate_multiplier(l, new_learning_rate_multiplier);\n            }\n\n        private:\n\n            double new_learning_rate_multiplier;\n        };\n    }\n\n    template <typename net_type>\n    void set_all_learning_rate_multipliers(\n        net_type& net,\n        double learning_rate_multiplier\n    )\n    {\n        DLIB_CASSERT(learning_rate_multiplier >= 0);\n        impl::visitor_learning_rate_multiplier temp(learning_rate_multiplier);\n        visit_computational_layers(net, temp);\n    }\n\n    template <size_t begin, size_t end, typename net_type>\n    void set_learning_rate_multipliers_range(\n        net_type& net,\n        double learning_rate_multiplier\n    )\n    {\n        static_assert(begin <= end, \"Invalid range\");\n        static_assert(end <= net_type::num_layers, \"Invalid range\");\n        DLIB_CASSERT(learning_rate_multiplier >= 0);\n        impl::visitor_learning_rate_multiplier temp(learning_rate_multiplier);\n        visit_computational_layers_range<begin, end>(net, temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_bn_running_stats_window_size\n        {\n        public:\n\n            visitor_bn_running_stats_window_size(unsigned long new_window_size_) : new_window_size(new_window_size_) {}\n\n            template <typename T>\n            void set_window_size(T&) const\n            {\n                // ignore other layer detail types\n            }\n\n            template < layer_mode mode >\n            void set_window_size(bn_<mode>& l) const\n            {\n                l.set_running_stats_window_size(new_window_size);\n            }\n\n            template<typename input_layer_type>\n            void operator()(size_t , input_layer_type& )  const\n            {\n                // ignore other layers\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(size_t , add_layer<T,U,E>& l)  const\n            {\n                set_window_size(l.layer_details());\n            }\n\n        private:\n\n            unsigned long new_window_size;\n        };\n    }\n\n    template <typename net_type>\n    void set_all_bn_running_stats_window_sizes (\n        net_type& net,\n        unsigned long new_window_size\n    )\n    {\n        visit_layers(net, impl::visitor_bn_running_stats_window_size(new_window_size));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_disable_input_bias\n        {\n        public:\n\n            template <typename T>\n            void disable_input_bias(T&) const\n            {\n                // ignore other layer types\n            }\n\n            // handle the standard case\n            template <typename U, typename E>\n            void disable_input_bias(add_layer<layer_norm_, U, E>& l)\n            {\n                disable_bias(l.subnet().layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().layer_details(), 0);\n            }\n\n            template <typename U, typename E>\n            void disable_input_bias(add_layer<rms_norm_, U, E>& l)\n            {\n                disable_bias(l.subnet().layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().layer_details(), 0);\n            }            \n\n            template <layer_mode mode, typename U, typename E>\n            void disable_input_bias(add_layer<bn_<mode>, U, E>& l)\n            {\n                disable_bias(l.subnet().layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().layer_details(), 0);\n            }\n\n            // handle input repeat layer case\n            template <layer_mode mode, size_t N, template <typename> class R, typename U, typename E>\n            void disable_input_bias(add_layer<bn_<mode>, repeat<N, R, U>, E>& l)\n            {\n                disable_bias(l.subnet().get_repeated_layer(0).layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n            }\n\n            template <size_t N, template <typename> class R, typename U, typename E>\n            void disable_input_bias(add_layer<layer_norm_, repeat<N, R, U>, E>& l)\n            {\n                disable_bias(l.subnet().get_repeated_layer(0).layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n            }\n\n            template <size_t N, template <typename> class R, typename U, typename E>\n            void disable_input_bias(add_layer<rms_norm_, repeat<N, R, U>, E>& l)\n            {\n                disable_bias(l.subnet().get_repeated_layer(0).layer_details());\n                set_bias_learning_rate_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n                set_bias_weight_decay_multiplier(l.subnet().get_repeated_layer(0).layer_details(), 0);\n            }            \n\n            // handle input repeat layer with tag case\n            template <layer_mode mode, unsigned long ID, typename E>\n            void disable_input_bias(add_layer<bn_<mode>, add_tag_layer<ID, impl::repeat_input_layer>, E>& )\n            {\n            }\n\n            template <unsigned long ID, typename E>\n            void disable_input_bias(add_layer<layer_norm_, add_tag_layer<ID, impl::repeat_input_layer>, E>& )\n            {\n            }\n\n            template <unsigned long ID, typename E>\n            void disable_input_bias(add_layer<rms_norm_, add_tag_layer<ID, impl::repeat_input_layer>, E>& )\n            {\n            }            \n\n            // handle tag layer case\n            template <layer_mode mode, unsigned long ID, typename U, typename E>\n            void disable_input_bias(add_layer<bn_<mode>, add_tag_layer<ID, U>, E>& )\n            {\n            }\n\n            template <unsigned long ID, typename U, typename E>\n            void disable_input_bias(add_layer<layer_norm_, add_tag_layer<ID, U>, E>& )\n            {\n            }\n\n            template <unsigned long ID, typename U, typename E>\n            void disable_input_bias(add_layer<rms_norm_, add_tag_layer<ID, U>, E>& )\n            {\n            }            \n\n            // handle skip layer case\n            template <layer_mode mode, template <typename> class TAG, typename U, typename E>\n            void disable_input_bias(add_layer<bn_<mode>, add_skip_layer<TAG, U>, E>& )\n            {\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void disable_input_bias(add_layer<layer_norm_, add_skip_layer<TAG, U>, E>& )\n            {\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void disable_input_bias(add_layer<rms_norm_, add_skip_layer<TAG, U>, E>& )\n            {\n            }            \n\n            template<typename input_layer_type>\n            void operator()(size_t , input_layer_type& ) const\n            {\n                // ignore other layers\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(size_t , add_layer<T,U,E>& l)\n            {\n                disable_input_bias(l);\n            }\n        };\n    }\n\n\n    template <typename net_type>\n    void disable_duplicative_biases (\n        net_type& net\n    )\n    {\n        visit_layers(net, impl::visitor_disable_input_bias());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_fuse_layers\n        {\n            public:\n            template <typename T>\n            void fuse_convolution(T&) const\n            {\n                // disable other layer types\n            }\n\n            // handle the case of convolutional layer followed by relu\n            template <long nf, long nr, long nc, int sy, int sx, int py, int px, typename U, typename R>\n            void fuse_convolution(add_layer<relu_, add_layer<con_<nf, nr, nc, sy, sx, py, px>, U>, R>& l)\n            {\n                if (l.layer_details().is_disabled())\n                    return;\n\n                // get the convolution below the relu layer\n                auto& conv = l.subnet().layer_details();\n\n                conv.enable_relu();\n\n                // disable the relu layer\n                l.layer_details().disable();\n            }\n\n            // handle the case of convolutional layer followed by affine followed by relu\n            template <long nf, long nr, long nc, int sy, int sx, int py, int px, typename U, typename E, typename R>\n            void fuse_convolution(add_layer<relu_, add_layer<affine_, add_layer<con_<nf, nr, nc, sy, sx, py, px>, U>, E>, R>& l)\n            {\n                if (l.layer_details().is_disabled())\n                    return;\n\n                // fuse the convolutional layer followed by affine\n                fuse_convolution(l.subnet());\n\n                // get the convolution below the affine layer\n                auto& conv = l.subnet().subnet().layer_details();\n\n                conv.enable_relu();\n\n                // disable the relu layer\n                l.layer_details().disable();\n            }\n\n            // handle the case of convolutional layer followed by affine\n            template <long nf, long nr, long nc, int sy, int sx, int py, int px, typename U, typename E>\n            void fuse_convolution(add_layer<affine_, add_layer<con_<nf, nr, nc, sy, sx, py, px>, U>, E>& l)\n            {\n                if (l.layer_details().is_disabled())\n                    return;\n\n                // get the convolution below the affine layer\n                auto& conv = l.subnet().layer_details();\n\n                // get the parameters from the affine layer as alias_tensor_instance\n                alias_tensor_instance gamma = l.layer_details().get_gamma();\n                alias_tensor_instance beta = l.layer_details().get_beta();\n\n                if (conv.bias_is_disabled())\n                {\n                    conv.enable_bias();\n                }\n\n                tensor& params = conv.get_layer_params();\n\n                // update the biases\n                auto biases = alias_tensor(1, conv.num_filters());\n                biases(params, params.size() - conv.num_filters()) += mat(beta);\n\n                // guess the number of input channels\n                const long k_in = (params.size() - conv.num_filters()) / conv.num_filters() / conv.nr() / conv.nc();\n\n                // rescale the filters\n                DLIB_CASSERT(conv.num_filters() == gamma.k());\n                alias_tensor filter(1, k_in, conv.nr(), conv.nc());\n                const float* g = gamma.host();\n                for (long n = 0; n < conv.num_filters(); ++n)\n                {\n                    filter(params, n * filter.size()) *= g[n];\n                }\n\n                // disable the affine layer\n                l.layer_details().disable();\n            }\n\n            template <typename input_layer_type>\n            void operator()(size_t , input_layer_type& ) const\n            {\n                // ignore other layers\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(size_t , add_layer<T, U, E>& l)\n            {\n                fuse_convolution(l);\n            }\n        };\n    }\n\n    template <typename net_type>\n    void fuse_layers (\n        net_type& net\n    )\n    {\n        DLIB_CASSERT(count_parameters(net) > 0, \"The network has to be allocated before fusing the layers.\");\n        visit_layers(net, impl::visitor_fuse_layers());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_net_to_xml\n        {\n        public:\n\n            visitor_net_to_xml(std::ostream& out_) : out(out_) {}\n\n            template<typename input_layer_type>\n            void operator()(size_t idx, const input_layer_type& l)\n            {\n                out << \"<layer idx='\"<<idx<<\"' type='input'>\\n\";\n                to_xml(l,out);\n                out << \"</layer>\\n\";\n            }\n\n            template <typename T, typename U>\n            void operator()(size_t idx, const add_loss_layer<T,U>& l)\n            {\n                out << \"<layer idx='\"<<idx<<\"' type='loss'>\\n\";\n                to_xml(l.loss_details(),out);\n                out << \"</layer>\\n\";\n            }\n\n            template <typename T, typename U, typename E>\n            void operator()(size_t idx, const add_layer<T,U,E>& l)\n            {\n                out << \"<layer idx='\"<<idx<<\"' type='comp'>\\n\";\n                to_xml(l.layer_details(),out);\n                out << \"</layer>\\n\";\n            }\n\n            template <unsigned long ID, typename U, typename E>\n            void operator()(size_t idx, const add_tag_layer<ID,U,E>& /*l*/)\n            {\n                out << \"<layer idx='\"<<idx<<\"' type='tag' id='\"<<ID<<\"'/>\\n\";\n            }\n\n            template <template<typename> class T, typename U>\n            void operator()(size_t idx, const add_skip_layer<T,U>& /*l*/)\n            {\n                out << \"<layer idx='\"<<idx<<\"' type='skip' id='\"<<(tag_id<T>::id)<<\"'/>\\n\";\n            }\n\n        private:\n\n            std::ostream& out;\n        };\n    }\n\n    template <typename net_type>\n    void net_to_xml (\n        const net_type& net,\n        std::ostream& out\n    )\n    {\n        auto old_precision = out.precision(9);\n        out << \"<net>\\n\";\n        visit_layers(net, impl::visitor_net_to_xml(out));\n        out << \"</net>\\n\";\n        // restore the original stream precision.\n        out.precision(old_precision);\n    }\n\n    template <typename net_type>\n    void net_to_xml (\n        const net_type& net,\n        const std::string& filename\n    )\n    {\n        std::ofstream fout(filename);\n        net_to_xml(net, fout);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class visitor_net_to_dot\n        {\n        public:\n\n            visitor_net_to_dot(std::ostream& out) : out(out) {}\n\n            template <typename input_layer_type>\n            void operator()(size_t i, input_layer_type&)\n            {\n                start_node(i, \"input\");\n                end_node();\n                from = i;\n            }\n\n            template <typename T, typename U>\n            void operator()(size_t i, const add_loss_layer<T, U>&)\n            {\n                start_node(i, \"loss\");\n                end_node();\n                update(i);\n            }\n\n            template <template <typename> class... TAGS, typename U>\n            void operator()(size_t i, const add_loss_layer<loss_yolo_<TAGS...>, U>&)\n            {\n                start_node(i, \"loss_yolo\");\n                end_node();\n                std::ostringstream sout;\n                concat_helper_impl<TAGS...>::list_tags(sout);\n                const auto tags = dlib::split(sout.str(), \",\");\n                for (const auto& tag : tags)\n                    out << tag_to_layer.at(std::stoul(tag)) << \" -> \" << i << '\\n';\n            }\n\n            template <unsigned long ID, typename U, typename E>\n            void operator()(size_t i, const add_tag_layer<ID, U, E>&)\n            {\n                // check for consecutive tag layers\n                tagged_layers.push_back(i);\n                std::sort(tagged_layers.begin(), tagged_layers.end());\n                std::vector<unsigned long> diffs;\n                std::adjacent_difference(tagged_layers.begin(), tagged_layers.end(), std::back_inserter(diffs));\n                from = i + 1;\n                if (diffs.size() > 1 && diffs[1] == 1)\n                {\n                    for (size_t id = 1; id < diffs.size(); ++id)\n                    {\n                        if (diffs[id] == 1)\n                            ++from;\n                        else\n                            break;\n                    }\n                }\n                tag_to_layer[ID] = from;\n\n                // In case we wanted to draw the tagged layers, instead:\n                // tag_to_layer[ID] = i;\n                // start_node(i, \"tag\", \"Mrecord\");\n                // out << \" | {id|{\" << ID << \"}}\";\n                // end_node();\n                // update(i);\n            }\n\n            // Handle the special case when the tag layer is followed by a skip layer\n            template <unsigned long ID, template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_tag_layer<ID, add_skip_layer<TAG, U>, E>&)\n            {\n                tagged_layers.push_back(i);\n                const auto t = tag_id<TAG>::id;\n                tag_to_layer.at(t) = from;\n            }\n\n            template <template <typename> class TAG, typename U>\n            void operator()(size_t, const add_skip_layer<TAG, U>&)\n            {\n                const auto t = tag_id<TAG>::id;\n                from = tag_to_layer.at(t);\n            }\n\n            template <long nf, long nr, long nc, int sy, int sx, int py, int px, typename U, typename E>\n            void operator()(size_t i, const add_layer<con_<nf, nr, nc, sy, sx, py, px>, U, E>& l)\n            {\n                start_node(i, \"con\");\n                out << \" | {filters|{\" << l.layer_details().num_filters() << \"}}\";\n                out << \" | {size|{\" << nr << \",\" << nc << \"}}\";\n                if (sy != 1 || sx != 1)\n                    out << \" | {stride|{\" << sy<< \",\" << sx << \"}}\";\n                if (py != 0 || px != 0)\n                    out << \" | {pad|{\" << py<< \",\" << px << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <long nf, long nr, long nc, int sy, int sx, int py, int px, typename U, typename E>\n            void operator()(size_t i, const add_layer<cont_<nf, nr, nc, sy, sx, py, px>, U, E>& l)\n            {\n                start_node(i, \"cont\");\n                out << \" | {filters|{\" << l.layer_details().num_filters() << \"}}\";\n                out << \" | {size|{\" << nr << \",\" << nc << \"}}\";\n                if (sy != 1 || sx != 1)\n                    out << \" | {stride|{\" << sy<< \",\" << sx << \"}}\";\n                if (py != 0 || px != 0)\n                    out << \" | {pad|{\" << py<< \",\" << px << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <int sy, int sx, typename U, typename E>\n            void operator()(size_t i, const add_layer<upsample_<sy, sx>, U, E>&)\n            {\n                start_node(i, \"upsample\");\n                if (sy != 1 || sx != 1)\n                    out << \" | {scale|{\" << sy<< \",\" << sx << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <int NR, int NC, typename U, typename E>\n            void operator()(size_t i, const add_layer<resize_to_<NR, NC>, U, E>&)\n            {\n                start_node(i, \"resize_to\");\n                out << \" | {size|{\" << NR << \",\" << NC << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <long nr, long nc, int sy, int sx, int py, int px, typename U, typename E>\n            void operator()(size_t i, const add_layer<max_pool_<nr, nc, sy, sx, py, px>, U, E>&)\n            {\n                start_node(i, \"max_pool\");\n                out << \" | {size|{\" << nr << \",\" << nc << \"}}\";\n                if (sy != 1 || sx != 1)\n                    out << \" | {stride|{\" << sy<< \",\" << sx << \"}}\";\n                if (py != 0 || px != 0)\n                    out << \" | {pad|{\" << py<< \",\" << px << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <long nr, long nc, int sy, int sx, int py, int px, typename U, typename E>\n            void operator()(size_t i, const add_layer<avg_pool_<nr, nc, sy, sx, py, px>, U, E>&)\n            {\n                start_node(i, \"avg_pool\");\n                out << \" | {size|{\" << nr << \",\" << nc << \"}}\";\n                if (sy != 1 || sx != 1)\n                    out << \" | {stride|{\" << sy<< \",\" << sx << \"}}\";\n                if (py != 0 || px != 0)\n                    out << \" | {pad|{\" << py<< \",\" << px << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<layer_norm_, U, E>&)\n            {\n                start_node(i, \"layer_norm\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<rms_norm_, U, E>&)\n            {\n                start_node(i, \"rms_norm\");\n                end_node();\n                update(i);\n            }            \n\n            template <layer_mode MODE, typename U, typename E>\n            void operator()(size_t i, const add_layer<bn_<MODE>, U, E>&)\n            {\n                start_node(i, \"batch_norm\");\n                end_node();\n                update(i);\n            }\n\n            template <unsigned long no, fc_bias_mode bm, typename U, typename E>\n            void operator()(size_t i, const add_layer<fc_<no, bm>, U, E>& l)\n            {\n                start_node(i, \"fc\");\n                out << \" | { outputs |{\" << l.layer_details().get_num_outputs() << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <unsigned long no, linear_bias_mode bm, typename U, typename E>\n            void operator()(size_t i, const add_layer<linear_<no, bm>, U, E>& l)\n            {\n                start_node(i, \"linear\");\n                out << \" | { outputs |{\" << l.layer_details().get_num_outputs() << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<dropout_, U, E>&)\n            {\n                start_node(i, \"dropout\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<multiply_, U, E>&)\n            {\n                start_node(i, \"multiply\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<affine_, U, E>&)\n            {\n                start_node(i, \"affine\");\n                end_node();\n                update(i);\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<add_prev_<TAG>, U, E>&)\n            {\n                start_node(i, \"add\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << tag_to_layer.at(t) << \" -> \" << i << '\\n';\n                update(i);\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<mult_prev_<TAG>, U, E>&)\n            {\n                start_node(i, \"mult\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << tag_to_layer.at(t) << \" -> \" << i << '\\n';\n                update(i);\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<multm_prev_<TAG>, U, E>&)\n            {\n                start_node(i, \"multm\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << tag_to_layer.at(t) << \" -> \" << i << '\\n';\n                update(i);\n            }            \n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<resize_prev_to_tagged_<TAG>, U, E>&)\n            {\n                start_node(i, \"resize_as\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << i << \" -> \" << tag_to_layer.at(t) << \"[style=dashed]\\n\";\n                update(i);\n                from = i;\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<scale_<TAG>, U, E>&)\n            {\n                start_node(i, \"scale\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << tag_to_layer.at(t) << \" -> \" << i << '\\n';\n                update(i);\n            }\n\n            template <template <typename> class TAG, typename U, typename E>\n            void operator()(size_t i, const add_layer<scale_prev_<TAG>, U, E>&)\n            {\n                start_node(i, \"scale\");\n                end_node();\n                const auto t = tag_id<TAG>::id;\n                out << tag_to_layer.at(t) << \" -> \" << i << '\\n';\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<relu_, U, E>&)\n            {\n                start_node(i, \"relu\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<prelu_, U, E>&)\n            {\n                start_node(i, \"prelu\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<leaky_relu_, U, E>& l)\n            {\n                start_node(i, \"leaky_relu\");\n                out << \" | { alpha |{\" << l.layer_details().get_alpha() << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<sig_, U, E>&)\n            {\n                start_node(i, \"sigmoid\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<mish_, U, E>&)\n            {\n                start_node(i, \"mish\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<htan_, U, E>&)\n            {\n                start_node(i, \"htan\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<clipped_relu_, U, E>&)\n            {\n                start_node(i, \"clipped_relu\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<elu_, U, E>&)\n            {\n                start_node(i, \"elu\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<gelu_, U, E>&)\n            {\n                start_node(i, \"gelu\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<smelu_, U, E>& l)\n            {\n                start_node(i, \"smelu\");\n                out << \" | { beta |{\" << l.layer_details().get_beta() << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<silu_, U, E>&)\n            {\n                start_node(i, \"silu\");\n                end_node();\n                update(i);\n            }\n\n            template <operation_mode sm, typename U, typename E>\n            void operator()(size_t i, const add_layer<softmax_<sm>, U, E>&)\n            {\n                start_node(i, \"softmax\");\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<softmax_all_, U, E>&)\n            {\n                start_node(i, \"softmax_all\");\n                end_node();\n                update(i);\n            }\n\n            template <template <typename> class... TAGS, typename U, typename E>\n            void operator()(size_t i, const add_layer<concat_<TAGS...>, U, E>&)\n            {\n                start_node(i, \"concat\");\n                end_node();\n                std::ostringstream sout;\n                concat_helper_impl<TAGS...>::list_tags(sout);\n                const auto tags = dlib::split(sout.str(), \",\");\n                for (const auto& tag : tags)\n                    out << tag_to_layer.at(std::stoul(tag)) << \" -> \" << i << '\\n';\n                from = i;\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<l2normalize_, U, E>&)\n            {\n                start_node(i, \"l2normalize\");\n                end_node();\n                update(i);\n            }\n\n            template <long offset, long k, int nr, int nc, typename U, typename E>\n            void operator()(size_t i, const add_layer<extract_<offset, k, nr, nc>, U, E>&)\n            {\n                start_node(i, \"extract\");\n                out << \" | {offset|{\" << offset << \"}}\";\n                out << \" | {k|{\" << k << \"}}\";\n                out << \" | {nr|{\" << nr << \"}}\";\n                out << \" | {nc|{\" << nc << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <long long sy, long long sx, typename U, typename E>\n            void operator()(size_t i, const add_layer<reorg_<sy, sx>, U, E>&)\n            {\n                start_node(i, \"reorg\");\n                if (sy != 1 || sx != 1)\n                    out << \" | {stride|{\" << sy<< \",\" << sx << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <long k, long nr, long nc, typename U, typename E>\n            void operator()(size_t i, const add_layer<reshape_to_<k, nr, nc>, U, E>&)\n            {\n                start_node(i, \"reshape_to\");\n                if (k == -1) out << \" | {k|{unchanged}}\";\n                else out << \" | {k|{\" << k << \"}}\";\n                if (nr == -1) out << \" | {nr|{unchanged}}\";\n                else out << \" | {nr|{\" << nr << \"}}\";\n                if (nc == -1) out << \" | {nc|{unchanged}}\";\n                else out << \" | {nc|{\" << nc << \"}}\";\n                end_node();\n                update(i);\n            }\n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<transpose_, U, E>&)\n            {\n                start_node(i, \"transpose\");\n                end_node();\n                update(i);\n            }\n\n            template <unsigned long ne, unsigned long ed, typename U, typename E>\n            void operator()(size_t i, const add_layer<embeddings_<ne, ed>, U, E>& l)\n            {\n                start_node(i, \"embeddings\");\n                out << \" | {num_embeddings|{\" << l.layer_details().get_num_embeddings() << \"}}\";\n                out << \" | {embedding_dim|{\" << l.layer_details().get_embedding_dim() << \"}}\";\n                end_node();\n                update(i);\n            }            \n\n            template <typename U, typename E>\n            void operator()(size_t i, const add_layer<positional_encodings_, U, E>&)\n            {\n                start_node(i, \"positional_encodings\");\n                end_node();\n                update(i);\n            }\n\n            template <long diag, typename tag, long num, long den, typename U, typename E>\n            void operator()(size_t i, const add_layer<tril_<diag, tag, num, den>, U, E>&)\n            {\n                start_node(i, \"tril\");\n                out << \" | {diag|{\" << diag << \"}}\";\n                out << \" | {diag_value|{\";\n                \n                if (std::is_same<tag, neg_infinity_tag>::value) out << \"-inf\";\n                else if (std::is_same<tag, zero_tag>::value) out << \"0\";\n                else out << static_cast<float>(num) / static_cast<float>(den);\n                \n                out << \"}}\";\n                end_node();\n                update(i);\n            }\n            \n            template <typename T, typename U, typename E>\n            void operator()(size_t i, const add_layer<T, U, E>&)\n            {\n                start_node(i, \"unhandled layer\");\n                update(i);\n            }\n\n        private:\n            size_t from;\n            std::ostream& out;\n            std::unordered_map<size_t, size_t> tag_to_layer;\n            std::vector<size_t> tagged_layers;\n            void update(const size_t i)\n            {\n                out << from << \" -> \" << i << '\\n';\n                from = i;\n            }\n            void start_node(const size_t i, const std::string& name, const std::string& shape = \"record\")\n            {\n                out << i << \" [shape=\" << shape << \", label=\\\"{layer|{\" << i << \"}} | \" << name;\n            }\n            void end_node()\n            {\n                out << \"\\\"]\\n\";\n            }\n\n        };\n    }\n    template <typename net_type>\n    void net_to_dot (\n        const net_type& net,\n        std::ostream& out\n    )\n    {\n        out << \"digraph G {\\n\";\n        out << \"rankdir = BT\\n\";\n        visit_layers_backwards(net, impl::visitor_net_to_dot(out));\n        out << \"}\";\n    }\n\n    template <typename net_type>\n    void net_to_dot (\n        const net_type& net,\n        const std::string& filename\n    )\n    {\n        std::ofstream fout(filename);\n        net_to_dot(net, fout);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DNn_VISITORS_H_\n\n"
  },
  {
    "path": "dlib/dnn/visitors_abstract.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DNn_VISITORS_ABSTRACT_H_\n#ifdef DLIB_DNn_VISITORS_ABSTRACT_H_\n\n#include \"input.h\"\n#include \"layers.h\"\n#include \"loss.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    void set_all_bn_running_stats_window_sizes (\n        const net_type& net,\n        unsigned long new_window_size\n    );\n    /*!\n        requires\n            - new_window_size > 0\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - Sets the get_running_stats_window_size() field of all bn_ layers in net to\n              new_window_size.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    void disable_duplicative_biases (\n        const net_type& net\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - Disables bias for all bn_, layer_norm_ and rms_norms_ inputs.\n            - Sets the get_bias_learning_rate_multiplier() and get_bias_weight_decay_multiplier()\n              to zero of all bn_, layer_norm_  and rms_norm_ inputs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    void fuse_layers (\n        net_type& net\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - net has been properly allocated, that is: count_parameters(net) > 0.\n        ensures\n            - Disables all the affine_ layers that have a convolution as an input.\n            - Updates the convolution weights beneath the affine_ layers to produce the same\n              output as with the affine_ layers enabled.\n            - Disables all the relu_ layers that have a convolution as input.\n            - Disables all the relu_ layers that have an affine_ layer as input, with a\n              convolution as input.\n            - Updates the convolution to apply a relu activation function, to produce the same\n              output as with the relu_ layer enabled.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    void net_to_xml (\n        const net_type& net,\n        std::ostream& out\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - All layers in the net must provide to_xml() functions.\n        ensures\n            - Prints the given neural network object as an XML document to the given output\n              stream.\n    !*/\n\n    template <typename net_type>\n    void net_to_xml (\n        const net_type& net,\n        const std::string& filename\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - All layers in the net must provide to_xml() functions.\n        ensures\n            - This function is just like the above net_to_xml(), except it writes to a file\n              rather than an ostream.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    dpoint input_tensor_to_output_tensor(\n        const net_type& net,\n        dpoint p \n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_skip_layer, or add_tag_layer.\n            - All layers in the net must provide map_input_to_output() functions.\n        ensures\n            - Given a dpoint (i.e. a row,column coordinate) in the input tensor given to\n              net, this function returns the corresponding dpoint in the output tensor\n              net.get_output().  This kind of mapping is useful when working with fully\n              convolutional networks as you will often want to know what parts of the\n              output feature maps correspond to what parts of the input.\n            - If the network contains skip layers then any layers skipped over by the skip\n              layer are ignored for the purpose of computing this coordinate mapping.  That\n              is, if you walk the network from the output layer to the input layer, where\n              each time you encounter a skip layer you jump to the layer indicated by the\n              skip layer, you will visit exactly the layers in the network involved in the\n              input_tensor_to_output_tensor() calculation. This behavior is useful since it\n              allows you to compute some auxiliary DNN as a separate branch of computation\n              that is separate from the main network's job of running some kind of fully\n              convolutional network over an image.  For instance, you might want to have a\n              branch in your network that computes some global image level\n              summarization/feature.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    dpoint output_tensor_to_input_tensor(\n        const net_type& net,\n        dpoint p  \n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_skip_layer, or add_tag_layer.\n            - All layers in the net must provide map_output_to_input() functions.\n        ensures\n            - This function provides the reverse mapping of input_tensor_to_output_tensor().\n              That is, given a dpoint in net.get_output(), what is the corresponding dpoint\n              in the input tensor?\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    inline size_t count_parameters(\n        const net_type& net\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - Returns the number of allocated parameters in the network. E.g. if the network has not\n              been trained then, since nothing has been allocated yet, it will return 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename net_type>\n    void set_all_learning_rate_multipliers(\n        net_type& net,\n        double learning_rate_multiplier\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - learning_rate_multiplier >= 0\n        ensures\n            - Sets all learning_rate_multipliers and bias_learning_rate_multipliers in net\n              to learning_rate_multiplier.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t begin, size_t end, typename net_type>\n    void set_learning_rate_multipliers_range(\n        net_type& net,\n        double learning_rate_multiplier\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n            - learning_rate_multiplier >= 0\n            - begin <= end <= net_type::num_layers\n        ensures\n            - Loops over the layers in the range [begin,end) in net and calls\n              set_learning_rate_multiplier on them with the value of\n              learning_rate_multiplier.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename net_type>\n    void net_to_dot (\n        const net_type& net,\n        std::ostream& out\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - Prints the given neural network object as an DOT document to the given output\n              stream.\n            - The contents of #out can be used by the dot program from Graphviz to export\n              the network diagram to any supported format.\n    !*/\n\n    template <typename net_type>\n    void net_to_dot (\n        const net_type& net,\n        const std::string& filename\n    );\n    /*!\n        requires\n            - net_type is an object of type add_layer, add_loss_layer, add_skip_layer, or\n              add_tag_layer.\n        ensures\n            - This function is just like the above net_to_dot(), except it writes to a file\n              rather than an ostream.\n    !*/\n}\n\n#endif // DLIB_DNn_VISITORS_ABSTRACT_H_\n"
  },
  {
    "path": "dlib/dnn.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNn_\n#define DLIB_DNn_\n\n// DNN module uses template-based network declaration that leads to very long\n// type names. Visual Studio will produce Warning C4503 in such cases\n#ifdef _MSC_VER\n#   pragma warning( disable: 4503 )\n#endif\n\n#include \"cuda/tensor.h\"\n#include \"dnn/input.h\"\n\n// Problem:    Visual Studio's vcpkgsrv.exe constantly uses a single CPU core,\n//             apparently never finishing whatever it's trying to do. Moreover,\n//             this issue prevents some operations like switching from Debug to\n//             Release (and vice versa) in the IDE. (Your mileage may vary.)\n// Workaround: Keep manually killing the vcpkgsrv.exe process.\n// Solution:   Disable IntelliSense for some files. Which files? Unfortunately\n//             this seems to be a trial-and-error process.\n#ifndef __INTELLISENSE__\n#include \"dnn/layers.h\"\n#endif // __INTELLISENSE__\n\n#include \"dnn/loss.h\"\n#include \"dnn/core.h\"\n#include \"dnn/solvers.h\"\n#include \"dnn/trainer.h\"\n#include \"cuda/cpu_dlib.h\"\n#include \"cuda/tensor_tools.h\"\n#include \"dnn/utilities.h\"\n#include \"dnn/validation.h\"\n#include \"dnn/visitors.h\"\n\n#endif // DLIB_DNn_\n\n\n"
  },
  {
    "path": "dlib/enable_if.h",
    "content": "// Copyright 2003 (C) The Trustees of Indiana University.\n// Use, modification, and distribution is subject to the Boost Software\n// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at\n// http://www.boost.org/LICENSE_1_0.txt)\n//    Authors: Jaakko Jarvi (jajarvi at osl.iu.edu)\n//             Jeremiah Willcock (jewillco at osl.iu.edu)\n//             Andrew Lumsdaine (lums at osl.iu.edu)\n#ifndef DLIB_BOOST_UTILITY_ENABLE_IF_HPP\n#define DLIB_BOOST_UTILITY_ENABLE_IF_HPP\n\nnamespace dlib \n{\n \n  template <bool B, class T = void>\n  struct enable_if_c {\n    typedef T type;\n  };\n\n  template <class T>\n  struct enable_if_c<false, T> {};\n\n  template <class Cond, class T = void> \n  struct enable_if : public enable_if_c<Cond::value, T> {};\n\n  template <bool B, class T>\n  struct lazy_enable_if_c {\n    typedef typename T::type type;\n  };\n\n  template <class T>\n  struct lazy_enable_if_c<false, T> {};\n\n  template <class Cond, class T> \n  struct lazy_enable_if : public lazy_enable_if_c<Cond::value, T> {};\n\n\n  template <bool B, class T = void>\n  struct disable_if_c {\n    typedef T type;\n  };\n\n  template <class T>\n  struct disable_if_c<true, T> {};\n\n  template <class Cond, class T = void> \n  struct disable_if : public disable_if_c<Cond::value, T> {};\n\n  template <bool B, class T>\n  struct lazy_disable_if_c {\n    typedef typename T::type type;\n  };\n\n  template <class T>\n  struct lazy_disable_if_c<true, T> {};\n\n  template <class Cond, class T> \n  struct lazy_disable_if : public lazy_disable_if_c<Cond::value, T> {};\n\n} // namespace dlib \n\n#endif // DLIB_BOOST_UTILITY_ENABLE_IF_HPP\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_KERNEL_1_CPp_\n#define DLIB_ENTROPY_DECODER_KERNEL_1_CPp_\n#include \"entropy_decoder_kernel_1.h\"\n#include <iostream>\n#include <streambuf>\n#include <sstream>\n\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_decoder_kernel_1::\n    entropy_decoder_kernel_1(\n    ) :\n        initial_low(0x00000001),\n        initial_high(0xffffffff),\n        in(0),\n        low(initial_low),\n        high(initial_high),\n        buf(0),\n        buf_used(0),\n        target(0x00000000),\n        r(0)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_decoder_kernel_1::\n    ~entropy_decoder_kernel_1 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_1::\n    clear(\n    )\n    {\n        in       = 0;\n        buf_used = 0;\n        buf      = 0;\n        r        = 0;\n        low      = initial_low;\n        high     = initial_high;\n        target   = 0x00000000;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_1::\n    set_stream (\n        std::istream& in_\n    )\n    {\n        buf_used = 0;\n        buf      = 0;\n        r        = 0;\n        low      = initial_low;\n        high     = initial_high;\n        target   = 0x00000000;\n\n        in = &in_;\n        streambuf = in_.rdbuf();\n\n\n\n        unsigned char ch;\n\n        \n        streambuf->sgetn((char*)&ch,1);\n        target = ch;\n        \n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n\n\n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n\n\n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_decoder_kernel_1::\n    stream_is_set (\n    ) const\n    {\n        if (in != 0)\n            return true;\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::istream& entropy_decoder_kernel_1::\n    get_stream (\n    ) const\n    {\n        return *in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_1::\n    decode (\n        uint32 low_count,\n        uint32 high_count\n    )\n    {\n        // note that we must subtract 1 to preserve the convention that\n        // high == the real upper range - 1\n        high = low + r*high_count - 1;\n        low = low + r*low_count;\n        r = 0;\n\n\n\n        while (true)\n        {\n\n            // if the highest order bit in high and low is the same\n            if ( low >= 0x80000000 || high < 0x80000000)\n            {\n                // make sure buf isn't empty\n                if (buf_used == 0)\n                {\n                    buf_used = 8;\n                    if (streambuf->sgetn(reinterpret_cast<char*>(&buf),1)==0)\n                    {\n                        // if there isn't anything else in the streambuffer then just\n                        // make buf zero.  \n                        buf = 0;      \n                    }\n                }\n\n                // we will be taking one bit from buf to replace the one we threw away\n                --buf_used;\n\n                // roll off the bit in target\n                target <<= 1;  \n\n                // roll off the bit\n                high <<= 1;\n                low <<= 1;                \n                high |= 1;  // note that it is ok to add one to high here because\n                            // of the convention that high == real upper range - 1.\n                            // so that means that if we want to shift the upper range\n                            // left by one then we must shift a one into high also\n                            // since real upper range == high + 0.999999999...\n\n                // make sure low is never zero\n                if (low == 0)\n                    low = 1;\n\n                  // take a bit from buf to fill in the one we threw away                \n                target += (buf>>buf_used)&0x01;   \n            }\n            // if the distance between high and low is small and there aren't\n            // any bits we can roll off then round low up or high down.\n            else if (high-low < 0x10000)\n            {\n                if (high == 0x80000000)\n                    high = 0x7fffffff;\n                else\n                    low = 0x80000000;\n            }\n            else\n            {\n                break;\n            }\n        } // while (true)\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_decoder_kernel_1::\n    get_target_called (        \n    ) const\n    {           \n        return (r != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    uint32 entropy_decoder_kernel_1::\n    get_target (\n        uint32 total\n    ) \n    {   \n        // note that we must add one because of the convention that\n        // high == the real upper range minus 1\n        r = (high-low+1)/total;                   \n        uint32 temp = (target-low)/r;\n        if (temp < total)\n            return temp;\n        else\n            return total-1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_ENTROPY_DECODER_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_KERNEl_1_\n#define DLIB_ENTROPY_DECODER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_kernel_abstract.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_decoder_kernel_1 \n    {\n        /*!\n            GENERAL NOTES\n                this decoder is implemented using arithmetic coding\n\n            INITIAL VALUE\n                in       == 0\n                buf_used == 0\n                buf      == 0\n                initial_low      == 0x00000001  (slightly more than zero)\n                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)\n                target   == 0x00000000  (zero)\n                low      == initial_low\n                high     == initial_high\n                r        == 0\n\n            CONVENTION\n                if (in != 0)\n                    *in       == get_stream()\n                    true      == stream_is_set()\n                    streambuf == in->rdbuf()\n                else\n                    false   == stream_is_set()\n\n                buf      == used to hold fractional byte values which are fed to target.  \n                buf_used == the number of low order bits in buf that are currently \n                            in use\n                low      == the low end of the range used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)\n\n                            low is also never allowed to be zero to avoid overflow\n                            in the calculation (high-low+1)/total.\n\n                high     == the high end of the range - 1 used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so when we\n                            interpret high as a real number then it is always in the\n                            range [0,1)\n\n                            the range for arithmetic encoding is always \n                            [low,high + 0.9999999...)   the 0.9999999... is why\n                            high == real upper range - 1\n\n                target  ==  32 bits of the fraction produced from an arithmetic encoder.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)      \n\n                r       ==  the value (high-low+1)/total from the last call to \n                            get_target() or 0 if get_target_called() should be false\n\n                get_target_called() == (r != 0)\n\n        !*/\n\n    public:\n\n        entropy_decoder_kernel_1 (\n        );\n\n        virtual ~entropy_decoder_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        void set_stream (\n            std::istream& in\n        );\n\n        bool stream_is_set (\n        ) const;\n\n        std::istream& get_stream (\n        ) const;\n\n        void decode (\n            uint32 low_count,\n            uint32 high_count\n        );\n\n        bool get_target_called (\n        ) const;\n\n        uint32 get_target (\n            uint32 total\n        );\n\n    private:\n\n        // restricted functions\n        entropy_decoder_kernel_1(entropy_decoder_kernel_1&);        // copy constructor\n        entropy_decoder_kernel_1& operator=(entropy_decoder_kernel_1&);    // assignment operator\n\n        // data members\n        const uint32 initial_low;\n        const uint32 initial_high;\n        std::istream* in;\n        uint32 low;\n        uint32 high;\n        unsigned char buf; \n        uint32 buf_used; \n        uint32 target;\n        uint32 r;\n        std::streambuf* streambuf;\n\n    };   \n\n}\n\n#ifdef NO_MAKEFILE\n#include \"entropy_decoder_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_ENTROPY_DECODER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_2.cpp",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_KERNEL_2_CPp_\n#define DLIB_ENTROPY_DECODER_KERNEL_2_CPp_\n#include \"entropy_decoder_kernel_2.h\"\n#include <iostream>\n#include <streambuf>\n#include <sstream>\n\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_decoder_kernel_2::\n    entropy_decoder_kernel_2(\n    ) :\n        initial_low(0x00000001),\n        initial_high(0xffffffff),\n        in(0),\n        low(initial_low),\n        high(initial_high),\n        target(0x00000000),\n        r(0)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_decoder_kernel_2::\n    ~entropy_decoder_kernel_2 (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_2::\n    clear(\n    )\n    {\n        in       = 0;\n        r        = 0;\n        low      = initial_low;\n        high     = initial_high;\n        target   = 0x00000000;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_2::\n    set_stream (\n        std::istream& in_\n    )\n    {\n        r        = 0;\n        low      = initial_low;\n        high     = initial_high;\n        target   = 0x00000000;\n\n        in = &in_;\n        streambuf = in_.rdbuf();\n\n\n\n        unsigned char ch;\n\n        \n        streambuf->sgetn((char*)&ch,1);\n        target = ch;\n        \n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n\n\n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n\n\n        target <<= 8;\n        if (streambuf->sgetn((char*)&ch,1))\n            target += ch;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_decoder_kernel_2::\n    stream_is_set (\n    ) const\n    {\n        if (in != 0)\n            return true;\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::istream& entropy_decoder_kernel_2::\n    get_stream (\n    ) const\n    {\n        return *in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_decoder_kernel_2::\n    decode (\n        uint32 low_count,\n        uint32 high_count\n    )\n    {\n        // note that we must subtract 1 to preserve the convention that\n        // high == the real upper range - 1\n        high = low + r*high_count - 1;\n        low = low + r*low_count;\n        r = 0;\n\n\n        while (true )\n        {\n\n            // if high and low don't have the same 8 high order bits\n            if ((high&0xFF000000) != (low&0xFF000000)) \n            {   \n                // if the distance between high and low is small and there aren't\n                // any bits we can roll off then force high and low to have common high \n                // order bits.\n                if ((high-low < 0x10000))\n                {\n                    if (high-low > 0x1000)\n                    {\n                        high>>=1;\n                        low>>=1;\n                        high = low = high+low;\n                        high += 0xFF;\n                        low -= 0xFF;\n                    } \n                    else /**/\n                    {\n                        high>>=1;\n                        low>>=1;\n                        high = low = high+low;\n                    }\n                }\n                else\n                {\n                    // there are no bits to roll off and high and low are not\n                    // too close so just quit the loop\n                    break;\n                }\n                \n            }  \n            // else if there are 8 bits we can roll off\n            else\n            {\n                unsigned char buf;\n                if (streambuf->sgetn(reinterpret_cast<char*>(&buf),1)==0)\n                {\n                    // if there isn't anything else in the streambuffer then just\n                    // make buf zero.  \n                    buf = 0;      \n                }\n\n                // also roll off the bits in target\n                target <<= 8;  \n\n                // roll off the bits\n                high <<= 8;\n                low <<= 8;             \n                high |= 0xFF;  // note that it is ok to add 0xFF to high here because\n                            // of the convention that high == real upper range - 1.\n                            // so that means that if we want to shift the upper range\n                            // left by one then we must shift a one into high also\n                            // since real upper range == high + 0.999999999...\n\n                // make sure low is never zero\n                if (low == 0)\n                    low = 1;\n        \n\n                // put the new bits into target            \n                target |= static_cast<uint32>(buf);               \n            }\n\n        } // while (true)\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_decoder_kernel_2::\n    get_target_called (        \n    ) const\n    {           \n        return (r != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    uint32 entropy_decoder_kernel_2::\n    get_target (\n        uint32 total\n    ) \n    {   \n        // note that we must add one because of the convention that\n        // high == the real upper range minus 1\n        r = (high-low+1)/total;   \n        uint32 temp = (target-low)/r;\n        if (temp < total)\n            return temp;\n        else\n            return total-1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_ENTROPY_DECODER_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_KERNEl_2_\n#define DLIB_ENTROPY_DECODER_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_kernel_abstract.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_decoder_kernel_2 \n    {\n        /*!\n            GENERAL NOTES\n                this decoder is implemented using \"range\" coding\n\n            INITIAL VALUE\n                in       == 0\n                initial_low      == 0x00000001  (slightly more than zero)\n                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)\n                target   == 0x00000000  (zero)\n                low      == initial_low\n                high     == initial_high\n                r        == 0\n\n            CONVENTION\n                if (in != 0)\n                    *in       == get_stream()\n                    true      == stream_is_set()\n                    streambuf == in->rdbuf()\n                else\n                    false   == stream_is_set()\n\n\n                low      == the low end of the range used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)\n\n                            low is also never allowed to be zero to avoid overflow\n                            in the calculation (high-low+1)/total.\n\n                high     == the high end of the range - 1 used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so when we\n                            interpret high as a real number then it is always in the\n                            range [0,1)\n\n                            the range for arithmetic encoding is always \n                            [low,high + 0.9999999...)   the 0.9999999... is why\n                            high == real upper range - 1\n\n                target  ==  32 bits of the fraction produced from an arithmetic encoder.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)      \n\n                r       ==  the value (high-low+1)/total from the last call to \n                            get_target() or 0 if get_target_called() should be false\n\n                get_target_called() == (r != 0)\n\n        !*/\n\n    public:\n\n        entropy_decoder_kernel_2 (\n        );\n\n        virtual ~entropy_decoder_kernel_2 (\n        );\n\n        void clear(\n        );\n\n        void set_stream (\n            std::istream& in\n        );\n\n        bool stream_is_set (\n        ) const;\n\n        std::istream& get_stream (\n        ) const;\n\n        void decode (\n            uint32 low_count,\n            uint32 high_count\n        );\n\n        bool get_target_called (\n        ) const;\n\n        uint32 get_target (\n            uint32 total\n        );\n\n    private:\n\n        // restricted functions\n        entropy_decoder_kernel_2(entropy_decoder_kernel_2&);        // copy constructor\n        entropy_decoder_kernel_2& operator=(entropy_decoder_kernel_2&);    // assignment operator\n\n        // data members\n        const uint32 initial_low;\n        const uint32 initial_high;\n        std::istream* in;\n        uint32 low;\n        uint32 high;\n        uint32 target;\n        uint32 r;\n        std::streambuf* streambuf;\n\n    };   \n   \n\n}\n\n#ifdef NO_MAKEFILE\n#include \"entropy_decoder_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_ENTROPY_DECODER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_\n#ifdef DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_decoder \n    {\n        /*!\n            INITIAL VALUE\n                stream_is_set() == false\n                get_target_called() == false\n\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an entropy decoder (could be implemented as an \n                arithmetic decoder for example).    \n                \n                Note that all implementations of entropy_encoder and entropy_decoder \n                are paired. This means that if you use entropy_encoder_kernel_n to \n                encode something then you must use the corresponding \n                entropy_decoder_kernel_n to decode it.\n\n\n                WHERE IS EOF?\n                It is important to note that this object will not give any indication\n                that is has hit the end of the input stream when it occurs.  It is\n                up to you to use some kind of coding scheme to detect this in the\n                compressed data stream.\n\n                Another important thing to know is that decode() must be called\n                exactly the same number of times as encode() and with the same values\n                supplied for TOTAL, high_count, and low_count.  Doing this ensures\n                that the decoder consumes exactly all the bytes from the input \n                stream that were written by the entropy_encoder.\n\n            NOTATION:              \n                At any moment each symbol has a certain probability of appearing in \n                the input stream.  These probabilities may change as each symbol is \n                decoded and the probability model is updated accordingly.\n\n\n                - Before considering current symbol:\n\n                let P(i) be a function which gives the probability of seeing the ith  \n                symbol of an N symbol alphabet. Note that P(i) refers to the probability \n                of seeing the ith symbol WITHOUT considering the symbol currently given \n                by get_target(TOTAL).  ( The domain of P(i) is from 0 to N-1. )\n                \n                for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers\n                and TOTAL is the same number for all P(i) but COUNT may vary.\n                   \n                let LOW_COUNT(i)  be the sum of all P(x)*TOTAL from x == 0 to x == i-1\n                  (note that LOW_COUNT(0) == 0)\n                let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i\n\n\n                - After considering current symbol:\n\n                let #P(i) be a function which gives the probability of seeing the ith\n                symbol after we have updated our probability model to take the symbol\n                given by get_target(TOTAL) into account.\n\n                for each i: #P(i) == #COUNT/#TOTAL where #COUNT and #TOTAL are integers \n                and #TOTAL is the same number for all #P(i) but #COUNT may vary.\n        !*/\n\n    public:\n\n        entropy_decoder (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~entropy_decoder (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n                - if (stream_is_set())\n                    - clears any state accumulated in *this from decoding data from \n                      the stream get_stream()\n            throws\n                - any exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void set_stream (\n            std::istream& in\n        );\n        /*!\n            ensures\n                - #*this will read data from in and decode it\n                - #stream_is_set() == true\n                - #get_target() == a number representing the first symbol from in\n                - #get_target_called() == false\n                - if (stream_is_set())\n                    - clears any state accumulated in *this from decoding data from \n                      the stream get_stream()\n            throws\n                - any exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        bool stream_is_set (\n        ) const;\n        /*!\n            ensures\n                - returns true if a stream has been associated with *this by calling\n                  set_stream()\n        !*/\n\n        std::istream& get_stream (\n        ) const;\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - returns a reference to the istream object that *this is reading \n                  encoded data from\n        !*/\n\n\n        void decode (\n            uint32 low_count,\n            uint32 high_count\n        );\n        /*!\n            requires\n                - get_target_called() == true\n                - stream_is_set()     == true\n                - low_count  == LOW_COUNT(S) where S is the symbol represented \n                  by get_target(TOTAL)\n                - high_count == HIGH_COUNT(S) where S is the symbol represented \n                  by get_target(TOTAL)\n                - low_count  <= get_target(TOTAL) < high_count <= TOTAL                      \n            ensures\n                - #get_target(#TOTAL) == a number which represents the next symbol\n                - #get_target_called() == false\n            throws\n                - any exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        bool get_target_called (\n        ) const;\n        /*!\n            ensures\n                - returns true if get_target() has been called and since then decode()\n                  and set_stream() have not been called\n                - returns false otherwise\n        !*/\n\n        uint32 get_target (\n            uint32 total\n        );\n        /*!\n            requires \n                - 0 < total < 65536 (2^16)     \n                - total == TOTAL\n                - stream_is_set() == true\n            ensures\n                - in the next call to decode() the value of TOTAL will be\n                  considered to be total\n                - #get_target_called() == true\n                - returns a number N such that:\n                    - N is in the range 0 to total - 1\n                    - N represents a symbol S where\n                      LOW_COUNT(S) <= N < HIGH_COUNT(S)\n            throws\n                - any exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n    private:\n\n        // restricted functions\n        entropy_decoder(entropy_decoder&);        // copy constructor\n        entropy_decoder& operator=(entropy_decoder&);    // assignment operator\n\n    };   \n   \n}\n\n#endif // DLIB_ENTROPY_DECODER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/entropy_decoder/entropy_decoder_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_KERNEl_C_\n#define DLIB_ENTROPY_DECODER_KERNEl_C_\n\n#include \"entropy_decoder_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename decoder\n        >\n    class entropy_decoder_kernel_c : public decoder\n    {\n        \n        public:\n            std::istream& get_stream (\n            ) const;\n\n            void decode (\n                uint32 low_count,\n                uint32 high_count\n            );\n\n            uint32 get_target (\n                uint32 total\n            );\n\n    private:\n        uint32 _get_target;\n        uint32 TOTAL;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename decoder\n        >\n    std::istream& entropy_decoder_kernel_c<decoder>::\n    get_stream (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tstd::istream& entropy_decoder::get_stream()\"\n            << \"\\n\\tyou must set a stream for this object before you can get it\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return decoder::get_stream();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename decoder\n        >\n    void entropy_decoder_kernel_c<decoder>::\n    decode (\n        uint32 low_count,\n        uint32 high_count\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (low_count <= _get_target) && (_get_target < high_count) && \n                (high_count <= TOTAL) &&\n                (this->stream_is_set() == true) && (this->get_target_called() == true),\n            \"\\tvoid entropy_decoder::decode()\"\n            << \"\\n\\tRefer to the ensures clause for this function for further information.\"\n            << \"\\n\\tNote that _get_target refers to get_target(TOTAL)\" \n            << \"\\n\\tthis:                \" << this\n            << \"\\n\\tlow_count:           \" << low_count\n            << \"\\n\\thigh_count:          \" << high_count\n            << \"\\n\\tTOTAL:               \" << TOTAL\n            << \"\\n\\tget_target(TOTAL):   \" << _get_target\n            << \"\\n\\tis_stream_set():     \" << (this->stream_is_set() ? \"true\" : \"false\" )\n            << \"\\n\\tget_target_called(): \" << (this->get_target_called() ? \"true\" : \"false\" )\n            );\n\n        // call the real function\n        decoder::decode(low_count,high_count);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename decoder\n        >\n    uint32 entropy_decoder_kernel_c<decoder>::\n    get_target (\n        uint32 total\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (total > 0) && (total < 65536) && (this->stream_is_set() == true),\n            \"\\tvoid entropy_decoder::get_target()\"\n            << \"\\n\\tyou must set a stream for this object before you can get the \"\n            << \"\\n\\rnext target.\"\n            << \"\\n\\tthis: \" << this\n            << \"\\n\\ttotal: \" << total\n            );\n\n        // call the real function\n        _get_target = decoder::get_target(total);\n        TOTAL = total;\n        return _get_target;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/entropy_decoder.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODEr_\n#define DLIB_ENTROPY_DECODEr_\n\n#include \"entropy_decoder/entropy_decoder_kernel_1.h\"\n#include \"entropy_decoder/entropy_decoder_kernel_2.h\"\n#include \"entropy_decoder/entropy_decoder_kernel_c.h\"\n\n\n\n\nnamespace dlib\n{\n\n\n    class entropy_decoder\n    {\n        entropy_decoder() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     entropy_decoder_kernel_1\n                    kernel_1a;\n        typedef     entropy_decoder_kernel_c<kernel_1a>\n                    kernel_1a_c;\n          \n\n        // kernel_2a        \n        typedef     entropy_decoder_kernel_2\n                    kernel_2a;\n        typedef     entropy_decoder_kernel_c<kernel_2a>\n                    kernel_2a_c;\n          \n\n    };\n}\n\n#endif // DLIB_ENTROPY_DECODEr_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_1.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc\n        >\n    class entropy_decoder_model_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n\n            INITIAL VALUE\n                Initially this object's finite context model is empty\n\n            CONVENTION\n                &get_entropy_decoder() == coder\n                &order_0.get_global_state() == &gs\n\n                This is an order-0 model. The last symbol in the order-0 context is \n                an escape into the order minus 1 context.           \n        !*/\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_1 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_1 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_decoder& coder;\n        typename cc::global_state_type gs;\n        cc order_0;\n\n        // restricted functions\n        entropy_decoder_model_kernel_1(entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>&);        // copy constructor\n        entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>& operator=(entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc\n        >\n    entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::\n    entropy_decoder_model_kernel_1 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc\n        >\n    entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::\n    ~entropy_decoder_model_kernel_1 (\n    )\n    {\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc\n        >\n    void entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::\n    clear(\n    )\n    {\n        order_0.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc\n        >\n    void entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc>::\n    decode (\n        unsigned long& symbol\n    )\n    {\n        unsigned long current_symbol, low_count, high_count, target;\n\n        // look in the order-0 context\n        target = coder.get_target(order_0.get_total());\n        order_0.get_symbol(target,current_symbol,low_count,high_count);\n\n\n        // have coder decode the next symbol\n        coder.decode(low_count,high_count);\n\n        // if current_symbol is not an escape from the order-0 context\n        if (current_symbol != alphabet_size)\n        {\n            // update the count for this symbol\n            order_0.increment_count(current_symbol,2);\n\n            symbol = current_symbol;\n            return;\n        }\n\n        // update the count for the escape symbol\n        order_0.increment_count(alphabet_size);\n\n\n        // go into the order minus one context\n        target = coder.get_target(alphabet_size);\n        coder.decode(target,target+1);\n\n\n        // update the count for this symbol in the order-0 context\n        order_0.increment_count(target,2);\n\n        symbol = target;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n  \n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename ccbig\n        >\n    class entropy_decoder_model_kernel_2 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n                this will be used for the order-0 context\n\n            REQUIREMENTS ON ccbig\n                ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                ccbig::get_alphabet_size() == alphabet_size+1\n                this will be used for the order-1 context\n\n            INITIAL VALUE\n                Initially this object's finite context model is empty\n                previous_symbol == 0\n\n            CONVENTION\n                &get_entropy_decoder() == coder\n                &order_0.get_global_state() == &gs\n                &order_1[i]->get_global_state() == &gsbig\n\n\n                This is an order-1-0 model. The last symbol in the order-0 and order-1\n                context is an escape into the lower context.        \n\n                previous_symbol == the last symbol seen\n        !*/\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_2 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_2 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_decoder& coder;\n        typename cc::global_state_type gs;\n        typename ccbig::global_state_type gsbig;\n        cc order_0;\n        ccbig* order_1[alphabet_size];\n        unsigned long previous_symbol;\n\n\n        // restricted functions\n        entropy_decoder_model_kernel_2(entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>&);        // copy constructor\n        entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>& operator=(entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename ccbig\n        >\n    entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::\n    entropy_decoder_model_kernel_2 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs),\n        previous_symbol(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);\n\n        unsigned long i;\n        try\n        {\n            for (i = 0; i < alphabet_size; ++i)\n            {\n                order_1[i] = new ccbig(gsbig);\n            }\n        }\n        catch (...)\n        {\n            for (unsigned long j = 0; j < i; ++j)\n            {\n                delete order_1[j];\n            }\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename ccbig\n        >\n    entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::\n    ~entropy_decoder_model_kernel_2 (\n    )\n    {\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            delete order_1[i];\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename ccbig\n        >\n    void entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::\n    clear(\n    )\n    {\n        previous_symbol = 0;\n        order_0.clear();\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            order_1[i]->clear();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename ccbig\n        >\n    void entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc,ccbig>::\n    decode (\n        unsigned long& symbol\n    )\n    {\n        unsigned long current_symbol, low_count, high_count, target;\n\n        // look in the order-1 context\n        target = coder.get_target(order_1[previous_symbol]->get_total());\n        order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count);\n\n        // have the coder decode the next symbol\n        coder.decode(low_count,high_count);\n\n        // if the current_symbol is not an escape from the order-1 context\n        if (current_symbol != alphabet_size)\n        {\n            symbol = current_symbol;\n            order_1[previous_symbol]->increment_count(current_symbol,2);\n            previous_symbol = current_symbol;\n            return;\n        }\n            \n        // since this is an escape to order-0 we should increment\n        // the escape symbol\n        order_1[previous_symbol]->increment_count(alphabet_size);\n\n\n\n        // look in the order-0 context\n        target = coder.get_target(order_0.get_total());\n        order_0.get_symbol(target,current_symbol,low_count,high_count);\n\n        // have coder decode the next symbol\n        coder.decode(low_count,high_count);\n\n        // if current_symbol is not an escape from the order-0 context\n        if (current_symbol != alphabet_size)\n        {\n            // update the count for this symbol            \n            order_1[previous_symbol]->increment_count(current_symbol,2);\n            order_0.increment_count(current_symbol,2);\n\n            symbol = current_symbol;\n            previous_symbol = current_symbol;\n            return;\n        }\n\n        // update the count for the escape symbol\n        order_0.increment_count(current_symbol);\n\n\n        // go into the order minus one context\n        target = coder.get_target(alphabet_size);\n        coder.decode(target,target+1);\n\n\n        // update the count for this symbol             \n        order_1[previous_symbol]->increment_count(target,2);\n        order_0.increment_count(target,2);\n\n        symbol = target;\n        previous_symbol = target;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n  \n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_3.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename cc_high\n        >\n    class entropy_decoder_model_kernel_3 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n\n            REQUIREMENTS ON cc_high\n                cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc_high::get_alphabet_size() == alphabet_size+1\n\n            INITIAL VALUE\n                - Initially this object's finite context model is empty\n                - previous_symbol == 0\n                - previous_symbol2 == 0\n                - order_1 == pointer to an array of alphabet_size elements\n                - order_2 == pointer to an array of alphabet_size*alphabet_size elements\n                - for all values of i: order_2[i] == 0\n\n            CONVENTION\n                &get_entropy_encoder() == coder\n                &order_0.get_global_state() == &gs\n                &order_1[i]->get_global_state() == &gs\n\n                if (order_2[i] != 0) then\n                    &order_2[i]->get_global_state() == &gs_high\n\n                This is an order-2-1-0 model. The last symbol in the order-2, order-1 and \n                order-0 contexts is an escape into the lower context.\n\n                previous_symbol == the last symbol seen\n                previous_symbol2 == the symbol we saw before previous_symbol\n        !*/\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_3 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_3 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_decoder& coder;\n        typename cc::global_state_type gs;\n        typename cc_high::global_state_type gs_high;\n        cc order_0;\n        cc** order_1;\n        unsigned long previous_symbol;\n        cc_high** order_2;\n        unsigned long previous_symbol2;\n\n        // restricted functions\n        entropy_decoder_model_kernel_3(entropy_decoder_model_kernel_3&);        // copy constructor\n        entropy_decoder_model_kernel_3& operator=(entropy_decoder_model_kernel_3&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename cc_high\n        >\n    entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::\n    entropy_decoder_model_kernel_3 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs),\n        order_1(0),\n        previous_symbol(0),\n        order_2(0),\n        previous_symbol2(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);\n\n        try\n        {\n            order_1 = new cc*[alphabet_size];\n            order_2 = new cc_high*[alphabet_size*alphabet_size];\n        }\n        catch (...)\n        {\n            if (order_1) delete [] order_1;\n            if (order_2) delete [] order_2;\n            throw;\n        }\n\n\n        unsigned long i;\n\n        for (i = 0; i < alphabet_size*alphabet_size; ++i)\n        {\n            order_2[i] = 0;\n        }\n\n        try\n        {\n            for (i = 0; i < alphabet_size; ++i)\n            {\n                order_1[i] = new cc(gs);\n            }\n        }\n        catch (...)\n        {\n            for (unsigned long j = 0; j < i; ++j)\n            {\n                delete order_1[j];\n            }\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename cc_high\n        >\n    entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::\n    ~entropy_decoder_model_kernel_3 (\n    )\n    {\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            delete order_1[i];\n        }\n\n        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)\n        {\n            if (order_2[i] != 0)\n                delete order_2[i];\n        }\n        delete [] order_1;\n        delete [] order_2;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename cc_high\n        >\n    void entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::\n    clear(\n    )\n    {\n        previous_symbol = 0;\n        previous_symbol2 = 0;\n        order_0.clear();\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            order_1[i]->clear();\n        }\n\n        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)\n        {\n            if (order_2[i] != 0)\n            {\n                delete order_2[i];\n                order_2[i] = 0;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        typename cc,\n        typename cc_high\n        >\n    void entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc,cc_high>::\n    decode (\n        unsigned long& symbol\n    )\n    {\n        unsigned long current_symbol, low_count, high_count, target;\n\n\n        // look in the order-2 context        \n        unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size);\n        if (order_2[temp] != 0)\n        {\n            target = coder.get_target(order_2[temp]->get_total());\n            order_2[temp]->get_symbol(target,current_symbol,low_count,high_count);\n\n            // have the coder decode the next symbol\n            coder.decode(low_count,high_count);\n\n            // if the current_symbol is not an escape from the order-2 context\n            if (current_symbol != alphabet_size)\n            {\n                symbol = current_symbol;\n                order_2[temp]->increment_count(current_symbol,2);\n                previous_symbol2 = previous_symbol;\n                previous_symbol = current_symbol;\n                return;\n            }\n\n            // since this is an escape to order-1 we should increment\n            // the escape symbol\n            order_2[temp]->increment_count(alphabet_size);\n        }\n        else\n        {\n            order_2[temp] = new cc_high(gs_high);\n        }\n        \n\n\n\n\n\n        // look in the order-1 context\n        target = coder.get_target(order_1[previous_symbol]->get_total());\n        order_1[previous_symbol]->get_symbol(target,current_symbol,low_count,high_count);\n\n        // have the coder decode the next symbol\n        coder.decode(low_count,high_count);\n\n        // if the current_symbol is not an escape from the order-1 context\n        if (current_symbol != alphabet_size)\n        {\n            symbol = current_symbol;\n            order_2[temp]->increment_count(current_symbol,2);\n            order_1[previous_symbol]->increment_count(current_symbol,2);            \n            previous_symbol2 = previous_symbol;\n            previous_symbol = current_symbol;\n            return;\n        }\n            \n        // since this is an escape to order-0 we should increment\n        // the escape symbol\n        order_1[previous_symbol]->increment_count(alphabet_size);\n\n\n\n        // look in the order-0 context\n        target = coder.get_target(order_0.get_total());\n        order_0.get_symbol(target,current_symbol,low_count,high_count);\n\n        // have coder decode the next symbol\n        coder.decode(low_count,high_count);\n\n        // if current_symbol is not an escape from the order-0 context\n        if (current_symbol != alphabet_size)\n        {\n            // update the count for this symbol\n            order_2[temp]->increment_count(current_symbol,2);            \n            order_1[previous_symbol]->increment_count(current_symbol,2);\n            order_0.increment_count(current_symbol,2);\n            \n\n            symbol = current_symbol;\n            previous_symbol2 = previous_symbol;\n            previous_symbol = current_symbol;\n            return;\n        }\n\n        // update the count for the escape symbol\n        order_0.increment_count(current_symbol);\n\n\n        // go into the order minus one context\n        target = coder.get_target(alphabet_size);\n        coder.decode(target,target+1);\n\n\n        // update the count for this symbol \n        order_2[temp]->increment_count(target,2);            \n        order_1[previous_symbol]->increment_count(target,2);\n        order_0.increment_count(target,2);\n        \n\n        symbol = target;\n        previous_symbol2 = previous_symbol;\n        previous_symbol = target;\n    \n       \n    }\n\n// ----------------------------------------------------------------------------------------\n  \n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_3_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_4.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\n\nnamespace dlib\n{\n\n    namespace edmk4\n    {\n        struct node\n        {            \n            node* next;\n            node* child_context;\n            node* parent_context;\n\n            unsigned short symbol;\n            unsigned short count;\n            unsigned short total;\n            unsigned short escapes;\n        };\n    }\n\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    class entropy_decoder_model_kernel_4 \n    {\n        /*!\n            REQUIREMENTS ON total_nodes\n                - 4096 < total_nodes\n                - this is the total number of nodes that we will use in the tree\n\n            REQUIREMENTS ON order\n                - 0 <= order\n                - this is the maximum depth-1 the tree will be allowed to go (note \n                  that the root level is depth 0).  \n\n\n            GENERAL NOTES\n                This implementation follows more or less the implementation \n                strategy laid out by Alistair Moffat in his paper\n                Implementing the PPM data compression scheme.  Published in IEEE \n                Transactions on Communications, 38(11):1917-1921, 1990.\n\n                The escape method used will be method D. \n\n\n            INITIAL VALUE\n                - root == pointer to an array of total_nodes nodes\n                - next_node == 1\n                - cur == root\n                - cur_order = 0\n                - root->next == 0\n                - root->parent_context == 0\n                - root->child_context == 0\n                - root->escapes == 0\n                - root->total == 0\n                - stack_size == 0\n\n            CONVENTION\n                - pop() == stack[stack_size-1] \n                - &get_entropy_decoder() == coder\n                - root == pointer to an array of total_nodes nodes.\n                  this is also the root of the tree.\n\n                - if (next_node < total_nodes) then\n                    - next_node == the next node in root that has not yet been allocated                                \n\n\n                - root->next == 0\n                - root->parent_context == 0\n              \n\n                - for every node in the tree:\n                  {\n                    - NOTATION: \n                        - The \"context\" of a node is the string of symbols seen\n                          when you go from the root of the tree down (down though\n                          child context pointers) to the node, including the symbol at \n                          the node itself.  (note that the context of the root node \n                          is \"\" or the empty string)\n                        - A set of nodes is in the same \"context set\" if all the node's\n                          contexts are of length n and all the node's contexts share\n                          the same prefix of length n-1.\n                        - The \"child context set\" of a node is a set of nodes with\n                          contexts that are one symbol longer and prefixed by the node's \n                          context.  For example, if a node has a context \"abc\" then the \n                          nodes for contexts \"abca\", \"abcb\", \"abcc\", etc. are all in \n                          the child context set of the node.\n                        - The \"parent context\" of a node is the context that is one \n                          symbol shorter than the node's context and includes the \n                          symbol in the node.  So the parent context of a node with \n                          context \"abcd\" would be the context \"bcd\".\n\n\n                    - if (next != 0) then \n                        - next == pointer to the next node in the same context set\n                    - if (child_context != 0) then\n                        - child_context == pointer to the first node of the child \n                          context set for this node.\n                    - if (parent_context != 0) then\n                        - parent_context == pointer to the parent context of this node.\n                    - else\n                        - this node is the root node of the tree\n                  \n\n                    - if (this is not the root node) then\n                        - symbol == the symbol represented with this node\n                        - count == the number of times this symbol has been seen in its\n                          parent context.\n                    - else\n                        - the root doesn't have a symbol.  i.e. the context for the\n                          root node is \"\" or the empty string.\n\n                    - total == The sum of the counts of all the nodes \n                      in the child context set + escapes. \n                    - escapes == the escape count for the context represented\n                      by the node.\n                }\n\n\n                - cur_order < order\n                - cur_order == the depth of the node cur in the tree.\n                  (note that the root node has depth 0)\n                - cur == pointer to the node in the tree who's context matches\n                  the most recent symbols we have seen.\n\n\n        !*/\n\n        typedef edmk4::node node;\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_4 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_4 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n\n        inline void push (\n            edmk4::node* n\n        );\n        /*!\n            requires\n                - stack_size <= order\n            ensures\n                - #pop() == n\n        !*/\n\n        inline edmk4::node* pop (\n        );\n        /*!\n            requires\n                - stack_size > 0\n            ensures\n                - returns the node at the top of the stack\n        !*/\n\n        inline edmk4::node* allocate_node (\n        );\n        /*!\n            requires\n                - space_left() == true\n            ensures\n                - returns a pointer to a new node\n        !*/\n\n        inline void destroy_tree (\n        );\n        /*!\n            ensures\n                - deallocates all nodes except the root\n                - #root->child_context == 0\n                - #root->escapes == 0\n                - #root->total == 0\n                - #cur == root\n                - #cur_order == 0\n                - #stack_size == 0\n        !*/\n\n\n        inline bool space_left (\n        ) const;\n        /*!\n            ensures\n                - returns true if there is at least 1 free node left.\n                - returns false otherwise\n        !*/\n\n    \n        inline void scale_counts (\n            node* n\n        );\n        /*!\n            ensures\n                - divides all the counts in the child context set of n by 2.\n                - none of the nodes in the child context set will have a count of 0\n        !*/\n\n\n        entropy_decoder& coder;\n        unsigned long next_node;        \n        node* root;\n        node* cur;\n        unsigned long cur_order;\n        node* stack[order+1];\n        unsigned long stack_size;\n\n        // restricted functions\n        entropy_decoder_model_kernel_4(entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>&);        // copy constructor\n        entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>& operator=(entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    entropy_decoder_model_kernel_4 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_),\n        next_node(1),\n        cur_order(0),\n        stack_size(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);\n        COMPILE_TIME_ASSERT( 4096 < total_nodes );\n\n        root = new node[total_nodes];  \n        cur = root;\n\n        root->child_context = 0;\n        root->escapes = 0;\n        root->next = 0;\n        root->parent_context = 0;\n        root->total = 0; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    ~entropy_decoder_model_kernel_4 (\n    )\n    {\n        delete [] root;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    clear(\n    )\n    {\n        destroy_tree();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    decode (\n        unsigned long& symbol\n    )\n    {        \n        node* temp = cur;\n        cur = 0;\n        unsigned long low_count, high_count, total_count;\n        unsigned long target;\n        node* new_node = 0;\n\n        // local_order will track the level of temp in the tree\n        unsigned long local_order = cur_order;\n\n\n        while (true)\n        {            \n            high_count = 0;\n            if (space_left())\n            {\n                total_count = temp->total;\n                \n                if (total_count > 0)\n                {\n                    // check if we need to scale the counts\n                    if (total_count > 10000)\n                    {\n                        scale_counts(temp);\n                        total_count = temp->total;\n                    }\n\n                    target = coder.get_target(total_count);\n\n                    // find either the symbol we are looking for or the \n                    // end of the context set\n                    node* n = temp->child_context;\n                    node* last = 0;   \n                    while (true)\n                    {\n                        high_count += n->count;\n                        \n                        if (high_count > target || n->next == 0)\n                            break;\n                        last = n;\n                        n = n->next;\n                    }             \n\n                    low_count = high_count - n->count;\n             \n                    // if we found the symbol\n                    if (high_count > target)\n                    {\n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = n;                            \n                        }\n\n                        symbol = n->symbol;\n            \n                        coder.decode(low_count,high_count);\n                        n->count += 8;\n                        temp->total += 8;\n\n                        // move this node to the front \n                        if (last)\n                        {\n                            last->next = n->next;\n                            n->next = temp->child_context;\n                            temp->child_context = n;\n                        }\n\n\n                        if (cur == 0)\n                        {\n                            if (local_order < order)\n                            {\n                                cur_order = local_order+1;\n                                cur = n;\n                            }  \n                            else\n                            {\n                                cur = n->parent_context;\n                                cur_order = local_order;\n                            }\n                        }\n\n                        break;                    \n                     \n                    }\n                    // if we hit the end of the context set without finding the symbol\n                    else\n                    {   \n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = allocate_node();\n                            new_node = new_node->parent_context;\n                        }\n                        else\n                        {\n                            new_node = allocate_node();\n                        }\n\n                        n->next = new_node;\n\n                        // get the escape code\n                        coder.decode(high_count,total_count);\n                    }\n                        \n                } \n                else // if (total_count == 0)\n                {\n                    // this means that temp->child_context == 0 so we should make\n                    // a new node here.\n                    if (new_node != 0)\n                    {\n                        new_node->parent_context = allocate_node();\n                        new_node = new_node->parent_context;\n                    }\n                    else\n                    {\n                        new_node = allocate_node();\n                    }\n\n                    temp->child_context = new_node;\n                }\n\n                if (cur == 0 && local_order < order)\n                {\n                    cur = new_node;\n                    cur_order = local_order+1;\n                }\n\n                // fill out the new node\n                new_node->child_context = 0;\n                new_node->count = 4;\n                new_node->escapes = 0;\n                new_node->next = 0;\n                push(new_node);\n                new_node->total = 0;\n                temp->escapes += 4;\n                temp->total += 8;\n\n              \n                if (temp != root)\n                {\n                    temp = temp->parent_context;\n                    --local_order;\n                    continue;\n                }\n\n                // since this is the root we are going to the order-(-1) context\n                // so we can just take care of that here.\n                target = coder.get_target(alphabet_size);\n                new_node->parent_context = root;\n                coder.decode(target,target+1);\n                symbol = target;\n\n                if (cur == 0)\n                {\n                    cur = root;\n                    cur_order = 0;\n                }                    \n                break;               \n            }\n            else \n            {\n                // there isn't enough space so we should rebuild the tree\n                destroy_tree();\n                temp = cur;\n                local_order = cur_order;\n                cur = 0;        \n                new_node = 0;\n            }\n        } // while (true)\n\n        while (stack_size > 0)\n        {\n            pop()->symbol = static_cast<unsigned short>(symbol);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    edmk4::node* entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    allocate_node (\n    )    \n    {\n        node* temp;\n        temp = root + next_node;\n        ++next_node;\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    destroy_tree (\n    )\n    {        \n        next_node = 1;\n        root->child_context = 0;\n        root->escapes = 0;\n        root->total = 0;\n        cur = root;\n        cur_order = 0;\n        stack_size = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    space_left (\n    ) const\n    {\n        return (next_node < total_nodes);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    push (\n        edmk4::node* n\n    )\n    {\n        stack[stack_size] = n;\n        ++stack_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    edmk4::node* entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    pop (\n    )\n    {   \n        --stack_size;\n        return stack[stack_size];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,total_nodes,order>::\n    scale_counts (\n        node* temp\n    )\n    {\n        if (temp->escapes > 1)\n            temp->escapes >>= 1;\n        temp->total = temp->escapes;\n\n        node* n = temp->child_context;\n        while (n != 0)\n        {\n            if (n->count > 1)\n                n->count >>= 1;\n\n            temp->total += n->count;\n            n = n->next;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_4_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_5.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\n\nnamespace dlib\n{\n\n    namespace edmk5\n    {\n        struct node\n        {            \n            node* next;\n            node* child_context;\n            node* parent_context;\n\n            unsigned short symbol;\n            unsigned short count;\n            unsigned short total;\n            unsigned short escapes;\n        };\n    }\n\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    class entropy_decoder_model_kernel_5 \n    {\n        /*!\n            REQUIREMENTS ON total_nodes\n                - 4096 < total_nodes\n                - this is the total number of nodes that we will use in the tree\n\n            REQUIREMENTS ON order\n                - 0 <= order\n                - this is the maximum depth-1 the tree will be allowed to go (note \n                  that the root level is depth 0).  \n\n\n            GENERAL NOTES\n                This implementation follows more or less the implementation \n                strategy laid out by Alistair Moffat in his paper\n                Implementing the PPM data compression scheme.  Published in IEEE \n                Transactions on Communications, 38(11):1917-1921, 1990.\n\n                The escape method used will be method D. \n\n                This also uses Dmitry Shkarin's Information Inheritance scheme.\n                (described in \"PPM: one step to practicality\" and \"Improving the \n                Efficiency of the PPM Algorithm\")\n\n\n            INITIAL VALUE\n                - root == pointer to an array of total_nodes nodes\n                - next_node == 1\n                - cur == root\n                - cur_order = 0\n                - root->next == 0\n                - root->parent_context == 0\n                - root->child_context == 0\n                - root->escapes == 0\n                - root->total == 0\n                - stack_size == 0\n                - exc_used == false\n                - for all i: exc[i] == 0\n\n            CONVENTION\n                - exc_used == something_is_excluded()\n                - pop() == stack[stack_size-1].n and stack[stack_size-1].nc\n                - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5]\n                - &get_entropy_decoder() == coder\n                - root == pointer to an array of total_nodes nodes.\n                  this is also the root of the tree.\n                - if (next_node < total_nodes) then\n                    - next_node == the next node in root that has not yet been allocated                                \n\n                - root->next == 0\n                - root->parent_context == 0\n              \n\n                - for every node in the tree:\n                  {\n                    - NOTATION: \n                        - The \"context\" of a node is the string of symbols seen\n                          when you go from the root of the tree down (down though\n                          child context pointers) to the node, including the symbol at \n                          the node itself.  (note that the context of the root node \n                          is \"\" or the empty string)\n                        - A set of nodes is in the same \"context set\" if all the node's\n                          contexts are of length n and all the node's contexts share\n                          the same prefix of length n-1.\n                        - The \"child context set\" of a node is a set of nodes with\n                          contexts that are one symbol longer and prefixed by the node's \n                          context.  For example, if a node has a context \"abc\" then the \n                          nodes for contexts \"abca\", \"abcb\", \"abcc\", etc. are all in \n                          the child context set of the node.\n                        - The \"parent context\" of a node is the context that is one \n                          symbol shorter than the node's context and includes the \n                          symbol in the node.  So the parent context of a node with \n                          context \"abcd\" would be the context \"bcd\".\n\n\n                    - if (next != 0) then \n                        - next == pointer to the next node in the same context set\n                    - if (child_context != 0) then\n                        - child_context == pointer to the first node of the child \n                          context set for this node.\n                        - escapes > 0 \n                    - if (parent_context != 0) then\n                        - parent_context == pointer to the parent context of this node.\n                    - else\n                        - this node is the root node of the tree\n                  \n\n                    - if (this is not the root node) then\n                        - symbol == the symbol represented with this node\n                        - count == the number of times this symbol has been seen in its\n                          parent context.\n                    - else\n                        - the root doesn't have a symbol.  i.e. the context for the\n                          root node is \"\" or the empty string.\n\n                    - total == The sum of the counts of all the nodes \n                      in the child context set + escapes. \n                    - escapes == the escape count for the context represented\n                      by the node.\n                    - count > 0\n                }\n\n\n                - cur_order < order\n                - cur_order == the depth of the node cur in the tree.\n                  (note that the root node has depth 0)\n                - cur == pointer to the node in the tree who's context matches\n                  the most recent symbols we have seen.\n\n\n        !*/\n\n        typedef edmk5::node node;\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_5 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_5 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n\n        inline void push (\n            node* n,\n            node* nc\n        );\n        /*!\n            requires\n                - stack_size < order\n            ensures\n                - #pop(a,b): a == n && b == nc\n        !*/\n\n        inline void pop (\n            node*& n,\n            node*& nc\n        );\n        /*!\n            requires\n                - stack_size > 0\n            ensures\n                - returns the two nodes at the top of the stack\n        !*/\n\n        inline edmk5::node* allocate_node (\n        );\n        /*!\n            requires\n                - space_left() == true\n            ensures\n                - returns a pointer to a new node\n        !*/\n\n        inline bool space_left (\n        ) const;\n        /*!\n            ensures\n                - returns true if there is at least 1 free node left.\n                - returns false otherwise\n        !*/\n\n        inline void exclude (\n            unsigned short symbol\n        );\n        /*!\n            ensures\n                - #is_excluded(symbol) == true\n                - #something_is_excluded() == true\n        !*/\n\n        inline bool is_excluded (\n            unsigned short symbol\n        );\n        /*!\n            ensures\n                - if (symbol has been excluded) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        inline bool something_is_excluded (\n        );\n        /*!\n            ensures\n                - returns true if some symbol has been excluded.\n                  returns false otherwise\n        !*/\n\n        inline void clear_exclusions (\n        );\n        /*!\n            ensures\n                - for all symbols #is_excluded(symbol) == false\n                - #something_is_excluded() == false\n        !*/\n\n        inline void scale_counts (\n            node* n\n        );\n        /*!\n            ensures\n                - divides all the counts in the child context set of n by 2.\n                - none of the nodes in the child context set will have a count of 0\n        !*/\n\n        struct nodes\n        {\n            node* n;\n            node* nc;\n        };\n\n        entropy_decoder& coder;\n        unsigned long next_node;        \n        node* root;\n        node* cur;\n        unsigned long cur_order;\n        unsigned long exc[alphabet_size/32+1];\n        nodes stack[order+1];\n        unsigned long stack_size;\n        bool exc_used;\n\n        // restricted functions\n        entropy_decoder_model_kernel_5(entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>&);        // copy constructor\n        entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>& operator=(entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    entropy_decoder_model_kernel_5 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_),\n        next_node(1),\n        cur_order(0),\n        stack_size(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535);\n        COMPILE_TIME_ASSERT( 4096 < total_nodes );\n\n        root = new node[total_nodes];  \n        cur = root;\n\n        root->child_context = 0;\n        root->escapes = 0;\n        root->next = 0;\n        root->parent_context = 0;\n        root->total = 0; \n\n        clear_exclusions();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    ~entropy_decoder_model_kernel_5 (\n    )\n    {\n        delete [] root;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    clear(\n    )\n    {\n        next_node = 1;\n        root->child_context = 0;\n        root->escapes = 0;\n        root->total = 0;\n        cur = root;\n        cur_order = 0;\n        stack_size = 0;\n\n        clear_exclusions();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    decode (\n        unsigned long& symbol\n    )\n    {        \n        node* temp = cur;\n        cur = 0;\n        unsigned long low_count, high_count, total_count;\n        unsigned long target;\n        node* new_node = 0;\n\n        // local_order will track the level of temp in the tree\n        unsigned long local_order = cur_order;\n\n\n        unsigned short c; // c == t(a|sk)\n        unsigned short t; // t == T(sk)\n\n\n        if (something_is_excluded())\n            clear_exclusions();\n\n        while (true)\n        {            \n            high_count = 0;\n            if (space_left())\n            {\n                total_count = temp->total;\n                \n                if (total_count > 0)\n                {\n                    // check if we need to scale the counts\n                    if (total_count > 10000)\n                    {\n                        scale_counts(temp);\n                        total_count = temp->total;\n                    }\n\n                    if (something_is_excluded())\n                    {\n                        node* n = temp->child_context;\n                        total_count = temp->escapes;\n                        while (true)\n                        {\n                            if (is_excluded(n->symbol) == false)\n                            {\n                                total_count += n->count;\n                            }\n                            if (n->next == 0)\n                                break;\n                            n = n->next;\n                        }\n                    }\n                   \n\n\n                    target = coder.get_target(total_count);\n\n                    // find either the symbol we are looking for or the \n                    // end of the context set\n                    node* n = temp->child_context;\n                    node* last = 0;   \n                    while (true)\n                    {\n                        if (is_excluded(n->symbol) == false)\n                        {\n                            high_count += n->count;\n                            exclude(n->symbol);\n                        }\n\n                        \n                        if (high_count > target || n->next == 0)\n                            break;\n                        last = n;\n                        n = n->next;\n                    }             \n\n\n                    // if we found the symbol\n                    if (high_count > target)\n                    {\n                        low_count = high_count - n->count;\n\n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = n;                            \n                        }\n\n                        symbol = n->symbol;\n            \n                        coder.decode(low_count,high_count);\n                        c = n->count += 8;\n                        t = temp->total += 8;\n\n\n                        // move this node to the front \n                        if (last)\n                        {\n                            last->next = n->next;\n                            n->next = temp->child_context;\n                            temp->child_context = n;\n                        }\n\n                        if (cur == 0)\n                        {\n                            if (local_order < order)\n                            {\n                                cur_order = local_order+1;\n                                cur = n;\n                            }  \n                            else\n                            {\n                                cur = n->parent_context;\n                                cur_order = local_order;\n                            }\n                        }\n\n                        break;\n                     \n                     \n                    }\n                    // if we hit the end of the context set without finding the symbol\n                    else\n                    {   \n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = allocate_node();\n                            new_node = new_node->parent_context;\n                        }\n                        else\n                        {\n                            new_node = allocate_node();\n                        }\n\n                        n->next = new_node;\n\n                        // get the escape code\n                        coder.decode(high_count,total_count);\n                    }\n                        \n                } \n                else // if (total_count == 0)\n                {\n                    // this means that temp->child_context == 0 so we should make\n                    // a new node here.\n                    if (new_node != 0)\n                    {\n                        new_node->parent_context = allocate_node();\n                        new_node = new_node->parent_context;\n                    }\n                    else\n                    {\n                        new_node = allocate_node();\n                    }\n\n                    temp->child_context = new_node;\n                }\n\n                if (cur == 0 && local_order < order)\n                {\n                    cur = new_node;\n                    cur_order = local_order+1;\n                }\n\n                // fill out the new node\n                new_node->child_context = 0;\n                new_node->escapes = 0;\n                new_node->next = 0;\n                push(new_node,temp);\n                new_node->total = 0;\n\n\n              \n                if (temp != root)\n                {\n                    temp = temp->parent_context;\n                    --local_order;\n                    continue;\n                }\n                \n                t = 2056;\n                c = 8;\n\n                // since this is the root we are going to the order-(-1) context\n                // so we can just take care of that here.\n                target = coder.get_target(alphabet_size);\n                new_node->parent_context = root;\n                coder.decode(target,target+1);\n                symbol = target;\n\n                if (cur == 0)\n                {\n                    cur = root;\n                    cur_order = 0;\n                }\n                break;                          \n            }\n            else \n            {\n                // there isn't enough space so we should rebuild the tree                \n                clear();\n                temp = cur;\n                local_order = cur_order;\n                cur = 0;   \n                new_node = 0;\n            }\n        } // while (true)\n\n        // initialize the counts and symbol for any new nodes we have added\n        // to the tree.\n        node* n, *nc;\n        while (stack_size > 0)\n        {            \n            pop(n,nc);        \n\n            n->symbol = static_cast<unsigned short>(symbol);\n\n            // if nc is not a determnistic context\n            if (nc->total)\n            {\n                unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes;\n                unsigned long temp = nc->total;\n                temp *= c;\n                temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero\n                temp += 2;\n                if (temp > 50000) temp = 50000;\n                n->count = static_cast<unsigned short>(temp);\n\n               \n                nc->escapes += 4;\n                nc->total += static_cast<unsigned short>(temp) + 4;\n            }\n            else\n            {\n                n->count = 3 + 5*(c)/(t-c);\n\n                nc->escapes = 4;\n                nc->total = n->count + 4;\n            }\n        \n            while (nc->total > 10000)\n            {\n                scale_counts(nc);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    edmk5::node* entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    allocate_node (\n    )    \n    {\n        node* temp;\n        temp = root + next_node;\n        ++next_node;\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    space_left (\n    ) const\n    {\n        return (next_node < total_nodes);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    exclude (\n        unsigned short symbol\n    )\n    {\n        exc_used = true;\n        unsigned long temp = 1;\n        temp <<= symbol&0x1F;\n        exc[symbol>>5] |= temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    is_excluded (\n        unsigned short symbol\n    )\n    {\n        unsigned long temp = 1;\n        temp <<= symbol&0x1F;\n        return ((exc[symbol>>5]&temp) != 0);     \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    clear_exclusions (\n    )\n    {\n        exc_used = false;\n        for (unsigned long i = 0; i < alphabet_size/32+1; ++i)\n        {\n            exc[i] = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    push (\n        node* n,\n        node* nc\n    )\n    {\n        stack[stack_size].n = n;\n        stack[stack_size].nc = nc;\n        ++stack_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    pop (\n        node*& n,\n        node*& nc\n    )\n    {   \n        --stack_size;\n        n = stack[stack_size].n;\n        nc = stack[stack_size].nc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    something_is_excluded (\n    )\n    {\n        return exc_used;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,total_nodes,order>::\n    scale_counts (\n        node* temp\n    )\n    {\n        if (temp->escapes > 1)\n            temp->escapes >>= 1;\n        temp->total = temp->escapes;\n\n        node* n = temp->child_context;\n        while (n != 0)\n        {\n            if (n->count > 1)\n                n->count >>= 1;\n\n            temp->total += n->count;\n            n = n->next;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_5_\n\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_6.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_\n#define DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_\n\n#include \"../algs.h\"\n#include \"entropy_decoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    class entropy_decoder_model_kernel_6 \n    {\n        /*!\n            INITIAL VALUE\n                This object has no state\n\n            CONVENTION\n                &get_entropy_decoder() == coder\n                \n                This is an order-(-1) model.  So it doesn't really do anything.\n                Every symbol has the same probability.\n        !*/\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model_kernel_6 (\n            entropy_decoder& coder\n        );\n\n        virtual ~entropy_decoder_model_kernel_6 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void decode (\n            unsigned long& symbol\n        );\n\n        entropy_decoder& get_entropy_decoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_decoder& coder;\n\n        // restricted functions\n        entropy_decoder_model_kernel_6(entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>&);        // copy constructor\n        entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>& operator=(entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::\n    entropy_decoder_model_kernel_6 (\n        entropy_decoder& coder_\n    ) : \n        coder(coder_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::\n    ~entropy_decoder_model_kernel_6 (\n    )\n    {\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    void entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::\n    clear(\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    void entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>::\n    decode (\n        unsigned long& symbol\n    )\n    {\n        unsigned long target;\n\n        target = coder.get_target(alphabet_size);\n        coder.decode(target,target+1);\n\n        symbol = target;\n    }\n\n// ----------------------------------------------------------------------------------------\n  \n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_6_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model/entropy_decoder_model_kernel_abstract.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_\n#ifdef DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    class entropy_decoder_model \n    {\n        /*!\n            REQUIREMENTS ON alphabet_size\n                1 < alphabet_size < 65535\n\n            REQUIREMENTS ON entropy_decoder\n                is an implementation of entropy_decoder/entropy_decoder_kernel_abstract.h\n\n            INITIAL VALUE\n                Initially this object is at some predefined empty or ground state.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some kind of statistical model.  You\n                can use it to read symbols from an entropy_decoder and it will calculate\n                the cumulative counts/probabilities and manage contexts for you.\n\n                Note that all implementations of entropy_encoder_model and \n                entropy_decoder_model are paired. This means that if you use \n                entropy_encoder_model_kernel_n to encode something then you must \n                use the corresponding entropy_decoder_model_kernel_n to decode it.\n\n                Also note that this object does not perform any buffering of symbols.  It\n                reads them from its associated entropy_decoder simply as it needs them.\n                This makes it safe to use multiple entropy_decoder_model objects with\n                a single entropy_decoder without them trampling each other.\n        !*/\n\n    public:\n\n        typedef entropy_decoder entropy_decoder_type;\n\n        entropy_decoder_model (\n            entropy_decoder& coder\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n                - &#get_entropy_decoder() == &coder\n            throws\n                - any exception\n        !*/\n\n        virtual ~entropy_decoder_model (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n                - does not modify get_entropy_decoder()\n            throws\n                - any exception\n                    if this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void decode (\n            unsigned long& symbol\n        );\n        /*!\n            ensures\n                - decodes the next symbol\n                - #symbol == the next symbol\n                - #symbol < alphabet_size                \n            throws\n                - any exception\n                    If this exception is thrown then #*this is unusable until \n                    clear() is called and succeeds.\n        !*/\n        \n        entropy_decoder& get_entropy_decoder (\n        );\n        /*!\n            ensures\n                - returns a reference to the entropy_decoder used by *this\n        !*/\n\n        static unsigned long get_alphabet_size (\n        );\n        /*!\n            ensures\n                - returns alphabet_size\n        !*/\n\n    private:\n\n        // restricted functions\n        entropy_decoder_model(entropy_decoder_model<alphabet_size>&);        // copy constructor\n        entropy_decoder_model<alphabet_size>& operator=(entropy_decoder_model<alphabet_size>&);    // assignment operator\n\n    };   \n\n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEL_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/entropy_decoder_model.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_DECODER_MODEl_\n#define DLIB_ENTROPY_DECODER_MODEl_\n\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_1.h\"\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_2.h\"\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_3.h\"\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_4.h\"\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_5.h\"\n#include \"entropy_decoder_model/entropy_decoder_model_kernel_6.h\"\n\n#include \"conditioning_class.h\"\n#include \"memory_manager.h\"\n\nnamespace dlib\n{\n\n    \n    template <\n        unsigned long alphabet_size,\n        typename entropy_decoder\n        >\n    class entropy_decoder_model\n    {\n        entropy_decoder_model() {}\n\n        typedef typename conditioning_class<alphabet_size+1>::kernel_1a cc1;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_2a cc2;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_3a cc3;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4a cc4a;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4b cc4b;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4c cc4c;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4d cc4d;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1        \n        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc1>\n                    kernel_1a;\n    \n        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc2>\n                    kernel_1b;\n\n        typedef     entropy_decoder_model_kernel_1<alphabet_size,entropy_decoder,cc3>\n                    kernel_1c;\n\n        // --------------------\n\n        // kernel_2      \n        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc1,cc1>\n                    kernel_2a;\n    \n        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc2,cc2>\n                    kernel_2b;\n\n        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc3,cc3>\n                    kernel_2c;\n\n        typedef     entropy_decoder_model_kernel_2<alphabet_size,entropy_decoder,cc2,cc4b>\n                    kernel_2d;\n\n        // --------------------\n\n        // kernel_3       \n        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc1,cc4b>\n                    kernel_3a;\n    \n        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc2,cc4b>\n                    kernel_3b;\n\n        typedef     entropy_decoder_model_kernel_3<alphabet_size,entropy_decoder,cc3,cc4b>\n                    kernel_3c;\n\n        // --------------------\n\n        // kernel_4       \n        typedef     entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,200000,4>\n                    kernel_4a;\n        typedef     entropy_decoder_model_kernel_4<alphabet_size,entropy_decoder,1000000,5>\n                    kernel_4b;\n\n\n        // --------------------\n\n        // kernel_5       \n        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,200000,4>\n                    kernel_5a;\n        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,1000000,5>\n                    kernel_5b;\n        typedef     entropy_decoder_model_kernel_5<alphabet_size,entropy_decoder,2500000,7>\n                    kernel_5c;\n\n\n        // --------------------\n\n        // kernel_6       \n        typedef     entropy_decoder_model_kernel_6<alphabet_size,entropy_decoder>\n                    kernel_6a;\n\n\n    };\n}\n\n#endif // DLIB_ENTROPY_DECODER_MODEl_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_\n#define DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_\n#include \"entropy_encoder_kernel_1.h\"\n#include <iostream>\n#include <streambuf>\n\nnamespace dlib\n{\n\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_encoder_kernel_1::\n    entropy_encoder_kernel_1(\n    ) :\n        initial_low(0x00000001),\n        initial_high(0xffffffff),\n        out(0),\n        low(initial_low),\n        high(initial_high),\n        buf(0),\n        buf_used(0)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_encoder_kernel_1::\n    ~entropy_encoder_kernel_1 (\n    )\n    {\n        try {\n            if (out != 0)\n            {\n                flush();\n            }\n        } catch (...) {}\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_1::\n    clear(\n    )\n    {\n        if (out != 0)\n        {\n            flush();\n        }\n        out = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_1::\n    set_stream (\n        std::ostream& out_\n    )\n    {\n        if (out != 0)\n        {\n            // if a stream is currently set then flush the buffers to it before\n            // we switch to the new stream\n            flush();\n        }\n    \n        out = &out_;\n        streambuf = out_.rdbuf();\n\n        // reset the encoder state\n        buf_used = 0;\n        buf = 0;\n        low = initial_low;\n        high = initial_high;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_encoder_kernel_1::\n    stream_is_set (\n    ) const\n    {\n        if (out != 0)\n            return true;\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& entropy_encoder_kernel_1::\n    get_stream (\n    ) const\n    {\n        return *out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_1::\n    encode (\n        uint32 low_count,\n        uint32 high_count,\n        uint32 total\n    )\n    {\n        // note that we must add one because of the convention that\n        // high == the real upper range minus 1\n        uint32 r = (high-low+1)/total;                 \n\n        // note that we must subtract 1 to preserve the convention that\n        // high == the real upper range - 1\n        high = low + r*high_count-1;\n        low = low + r*low_count;\n\n\n        while (true)\n        {\n\n            // if the highest order bit in high and low is the same\n            if ( low >= 0x80000000 || high < 0x80000000)\n            {              \n                // if buf is full then write it out\n                if (buf_used == 8)\n                {\n                    if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n                    {\n                        throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n                    }\n                    buf = 0;\n                    buf_used = 0;\n                }   \n\n\n                // write the high order bit from low into buf\n                buf <<= 1;\n                ++buf_used;                \n                if (low&0x80000000)\n                    buf |= 0x1;\n\n                // roll off the bit we just wrote to buf\n                low <<= 1;                \n                high <<= 1;  \n                high |= 1;     // note that it is ok to add one to high here because\n                            // of the convention that high == real upper range - 1.\n                            // so that means that if we want to shift the upper range\n                            // left by one then we must shift a one into high also\n                            // since real upper range == high + 0.999999999...\n\n                // make sure low is never zero\n                if (low == 0)\n                    low = 1;\n            }\n            // if the distance between high and low is small and there aren't\n            // any bits we can roll off then round low up or high down.\n            else if (high-low < 0x10000)\n            {\n                if (high == 0x80000000)\n                    high = 0x7fffffff;\n                else\n                    low = 0x80000000;\n            }\n            else\n            {\n                break;\n            }\n        } // while (true)\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_1::\n    flush (\n    )\n    {\n        // flush the next 4 or 5 bytes that are buffered\n        // thats whatever is contained in buf and then all of low plus any extra \n        // bits needed to pad that to be an even 4 or 5 bytes\n\n\n        if (buf_used != 8)\n        {\n            buf <<= (8-buf_used);   \n            buf |= static_cast<unsigned char>(low>>(24+buf_used));         \n            low <<= (8-buf_used);\n        }\n\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n        buf = static_cast<unsigned char>((low >> 24)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n\n        buf = static_cast<unsigned char>((low >> 16)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n        buf = static_cast<unsigned char>((low >> 8)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n        if (buf_used != 0)\n        {\n            buf = static_cast<unsigned char>((low)&0xFF);\n            if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n                throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n        }\n    \n\n        \n        // make sure the stream buffer flushes to its I/O channel\n        streambuf->pubsync();\n\n\n        // reset the encoder state\n        buf_used = 0;\n        buf = 0;\n        low = initial_low;\n        high = initial_high;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_ENTROPY_ENCODER_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_KERNEl_1_\n#define DLIB_ENTROPY_ENCODER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_kernel_abstract.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_encoder_kernel_1 \n    {\n        /*!\n            GENERAL NOTES\n                this encoder is implemented using arithmetic coding\n\n            INITIAL VALUE\n                out      == 0\n                buf_used == 0\n                buf      == 0\n                initial_low      == 0x00000001  (slightly more than zero)\n                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)\n                low      == initial_low\n                high     == initial_high\n\n            CONVENTION\n                if (out != 0)\n                    *out      == get_stream()\n                    true      == stream_is_set()\n                    streambuf == out->rdbuf()\n                else\n                    false     == stream_is_set()\n\n                buf      == used to accumulate bits before writing them to out.  \n                buf_used == the number of low order bits in buf that are currently \n                            in use\n                low      == the low end of the range used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)\n\n                            low is also never allowed to be zero to avoid overflow\n                            in the calculation (high-low+1)/total.\n\n                high     == the high end of the range - 1 used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so when we\n                            interpret high as a real number then it is always in the\n                            range [0,1)\n\n                            the range for arithmetic encoding is always \n                            [low,high + 0.9999999...)   the 0.9999999... is why\n                            high == real upper range - 1         \n \n        !*/\n\n    public:\n\n        entropy_encoder_kernel_1 (\n        );\n\n        virtual ~entropy_encoder_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        void set_stream (\n            std::ostream& out\n        );\n\n        bool stream_is_set (\n        ) const;\n\n        std::ostream& get_stream (\n        ) const;\n\n        void encode (\n            uint32 low_count,\n            uint32 high_count,\n            uint32 total\n        );\n\n    private:\n\n        void flush ( \n        );\n        /*!\n            requires\n                out != 0 (i.e.  there is a stream object to flush the data to \n        !*/\n\n        // restricted functions\n        entropy_encoder_kernel_1(entropy_encoder_kernel_1&);        // copy constructor\n        entropy_encoder_kernel_1& operator=(entropy_encoder_kernel_1&);    // assignment operator\n\n        // data members\n        const uint32 initial_low;\n        const uint32 initial_high;\n        std::ostream* out;\n        uint32 low;\n        uint32 high;\n        unsigned char buf; \n        uint32 buf_used; \n        std::streambuf* streambuf;\n\n    };   \n   \n}\n\n#ifdef NO_MAKEFILE\n#include \"entropy_encoder_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_ENTROPY_ENCODER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_2.cpp",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_\n#define DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_\n#include \"entropy_encoder_kernel_2.h\"\n#include <iostream>\n#include <streambuf>\n\nnamespace dlib\n{\n\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_encoder_kernel_2::\n    entropy_encoder_kernel_2(\n    ) :\n        initial_low(0x00000001),\n        initial_high(0xffffffff),\n        out(0),\n        low(initial_low),\n        high(initial_high)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    entropy_encoder_kernel_2::\n    ~entropy_encoder_kernel_2 (\n    )\n    {\n        try {\n            if (out != 0)\n            {\n                flush();\n            }\n        } catch (...) {}\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_2::\n    clear(\n    )\n    {\n        if (out != 0)\n        {\n            flush();\n        }\n        out = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_2::\n    set_stream (\n        std::ostream& out_\n    )\n    {\n        if (out != 0)\n        {\n            // if a stream is currently set then flush the buffers to it before\n            // we switch to the new stream\n            flush();\n        }\n    \n        out = &out_;\n        streambuf = out_.rdbuf();\n\n        // reset the encoder state\n        low = initial_low;\n        high = initial_high;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool entropy_encoder_kernel_2::\n    stream_is_set (\n    ) const\n    {\n        if (out != 0)\n            return true;\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& entropy_encoder_kernel_2::\n    get_stream (\n    ) const\n    {\n        return *out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_2::\n    encode (\n        uint32 low_count,\n        uint32 high_count,\n        uint32 total\n    )\n    {\n        // note that we must add one because of the convention that\n        // high == the real upper range minus 1\n        uint32 r = (high-low+1)/total;                 \n\n        // note that we must subtract 1 to preserve the convention that\n        // high == the real upper range - 1\n        high = low + r*high_count-1;\n        low = low + r*low_count;\n\n\n\n        while (true )\n        {\n\n            // if high and low don't have the same 8 high order bits\n            if ((high&0xFF000000) != (low&0xFF000000)) \n            {   \n                // if the distance between high and low is small and there aren't\n                // any bits we can roll off then force high and low to have common high \n                // order bits.\n                if ((high-low < 0x10000))\n                {\n                    if (high-low > 0x1000)\n                    {\n                        high>>=1;\n                        low>>=1;\n                        high = low = high+low;\n                        high += 0xFF;\n                        low -= 0xFF;\n                    } \n                    else /**/\n                    {\n                        high>>=1;\n                        low>>=1;\n                        high = low = high+low;\n                    }\n                }\n                else\n                {\n                    // there are no bits to roll off and high and low are not\n                    // too close so just quit the loop\n                    break;\n                }\n                \n            }  \n            // else if there are 8 bits we can roll off\n            else\n            {\n                // write the 8 high order bits from low into buf\n                unsigned char buf = static_cast<unsigned char>(low>>24);\n\n\n                // roll off the bits we just wrote to buf\n                high <<= 8;  \n                low <<= 8;               \n                high |= 0xFF;  // note that it is ok to add 0xFF to high here because\n                            // of the convention that high == real upper range - 1.\n                            // so that means that if we want to shift the upper range\n                            // left by one then we must shift a one into high also\n                            // since real upper range == high + 0.999999999...\n\n                // make sure low is never zero\n                if (low == 0)\n                    low = 1;\n\n                // write buf to the output stream\n                if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n                {\n                    throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n                }                   \n                \n            } \n\n        } // while (true)\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void entropy_encoder_kernel_2::\n    flush (\n    )\n    {\n\n        // flush low to the output stream\n\n\n        unsigned char buf;\n\n\n        buf = static_cast<unsigned char>((low >> 24)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1) == 0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n\n        buf = static_cast<unsigned char>((low >> 16)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n\n        buf = static_cast<unsigned char>((low >> 8)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n\n\n        buf = static_cast<unsigned char>((low)&0xFF);\n        if (streambuf->sputn(reinterpret_cast<char*>(&buf),1)==0)\n            throw std::ios_base::failure(\"error occurred in the entropy_encoder object\");\n        \n    \n\n        \n        // make sure the stream buffer flushes to its I/O channel\n        streambuf->pubsync();\n\n\n        // reset the encoder state\n        low = initial_low;\n        high = initial_high;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_ENTROPY_ENCODER_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_KERNEl_2_\n#define DLIB_ENTROPY_ENCODER_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_kernel_abstract.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_encoder_kernel_2 \n    {\n        /*!\n            GENERAL NOTES\n                this encoder is implemented using \"range\" coding\n\n            INITIAL VALUE\n                out      == 0\n                initial_low      == 0x00000001  (slightly more than zero)\n                initial_high     == 0xffffffff  (slightly less than one, 0.99999999976717)\n                low      == initial_low\n                high     == initial_high\n\n            CONVENTION\n                if (out != 0)\n                    *out      == get_stream()\n                    true      == stream_is_set()\n                    streambuf == out->rdbuf()\n                else\n                    false     == stream_is_set()\n\n\n                low      == the low end of the range used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so it is\n                            always in the range [0,1)\n\n                            low is also never allowed to be zero to avoid overflow\n                            in the calculation (high-low+1)/total.\n\n                high     == the high end of the range - 1 used for arithmetic encoding.\n                            this number is used as a 32bit fixed point real number. \n                            the point is fixed just before the first bit, so when we\n                            interpret high as a real number then it is always in the\n                            range [0,1)\n\n                            the range for arithmetic encoding is always \n                            [low,high + 0.9999999...)   the 0.9999999... is why\n                            high == real upper range - 1         \n         !*/\n\n    public:\n\n        entropy_encoder_kernel_2 (\n        );\n\n        virtual ~entropy_encoder_kernel_2 (\n        );\n\n        void clear(\n        );\n\n        void set_stream (\n            std::ostream& out\n        );\n\n        bool stream_is_set (\n        ) const;\n\n        std::ostream& get_stream (\n        ) const;\n\n        void encode (\n            uint32 low_count,\n            uint32 high_count,\n            uint32 total\n        );\n\n    private:\n\n        void flush ( \n        );\n        /*!\n            requires\n                out != 0 (i.e.  there is a stream object to flush the data to \n        !*/\n\n        // restricted functions\n        entropy_encoder_kernel_2(entropy_encoder_kernel_2&);        // copy constructor\n        entropy_encoder_kernel_2& operator=(entropy_encoder_kernel_2&);    // assignment operator\n\n        // data members\n        const uint32 initial_low;\n        const uint32 initial_high;\n        std::ostream* out;\n        uint32 low;\n        uint32 high;\n        std::streambuf* streambuf;\n\n    };   \n\n}\n\n#ifdef NO_MAKEFILE\n#include \"entropy_encoder_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_ENTROPY_ENCODER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_\n#ifdef DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n#include <iosfwd>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class entropy_encoder \n    {\n        /*!\n            INITIAL VALUE\n                stream_is_set() == false\n\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an entropy encoder (could be implemented as an \n                arithmetic encoder for example).      \n                \n                Note that all implementations of entropy_encoder and entropy_decoder \n                are paired. This means that if you use entropy_encoder_kernel_n to \n                encode something then you must use the corresponding \n                entropy_decoder_kernel_n to decode it.\n\n            NOTATION:              \n                At any moment each symbol has a certain probability of appearing in \n                the input stream.  These probabilities may change as each symbol is \n                encountered and the probability model is updated accordingly.\n\n\n                let P(i) be a function which gives the probability of seeing the ith \n                symbol of an N symbol alphabet BEFORE the probability model is updated\n                to account for the current symbol.  ( The domain of P(i) is from 0 to N-1. )\n\n                for each i: P(i) == COUNT/TOTAL where COUNT and TOTAL are integers.\n                and TOTAL is the same number for all P(i) but COUNT may vary.\n                   \n                let LOW_COUNT(i)  be the sum of all P(x)*TOTAL from x == 0 to x == i-1\n                  (note that LOW_COUNT(0) == 0)\n                let HIGH_COUNT(i) be the sum of all P(x)*TOTAL from x == 0 to x == i\n        !*/\n\n    public:\n\n        entropy_encoder (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~entropy_encoder (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n                - if (stream_is_set()) then\n                    - any buffered data in *this will be written to get_stream() \n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n                - if (stream_is_set()) then\n                    - any buffered data in *this will be written to get_stream() \n                    - clears any memory of all previous calls to encode() from #*this\n            throws\n                - std::ios_base::failure\n                    if (stream_is_set() && there was a problem writing to get_stream())\n                    then this exception will be thrown.  #*this will be unusable until\n                    clear() is called and succeeds\n                - any other exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n\n        void set_stream (\n            std::ostream& out\n        );\n        /*!\n            ensures\n                - #get_stream()    == out\n                - #stream_is_set() == true\n                - if (stream_is_set()) then\n                    - any buffered data in *this will be written to get_stream() \n                    - clears any memory of all previous calls to encode() from #*this\n            throws\n                - std::ios_base::failure\n                    if (stream_is_set() && there was a problem writing to get_stream())\n                    then this exception will be thrown.  #*this will be unusable until\n                    clear() is called and succeeds\n                - any other exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        bool stream_is_set (\n        ) const;\n        /*!\n            ensures\n                - returns true if a stream has been associated with *this by calling\n                  set_stream()\n        !*/\n\n        std::ostream& get_stream (\n        ) const;\n        /*!\n            requires\n                - stream_is_set() == true\n            ensures\n                - returns a reference to the ostream object that *this writes its \n                  encoded data to\n        !*/\n\n        void encode (\n            uint32 low_count,\n            uint32 high_count,\n            uint32 total\n        );\n        /*!\n            requires\n                - 0 < total <  65536 (2^16)\n                - total == TOTAL\n                - low_count < high_count <= total    \n                - stream_is_set() == true\n            ensures\n                - encodes the symbol S where: \n                    - LOW_COUNT(S)  == low_count\n                    - HIGH_COUNT(S) == high_count\n            throws\n                - std::ios_base::failure\n                    if (there was a problem writing to get_stream()) then\n                    this exception will be thrown.  #*this will be unusable until\n                    clear() is called and succeeds\n                - any other exception\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n\n    private:\n\n        // restricted functions\n        entropy_encoder(entropy_encoder&);        // copy constructor\n        entropy_encoder& operator=(entropy_encoder&);    // assignment operator\n\n    };   \n   \n}\n\n#endif // DLIB_ENTROPY_ENCODER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/entropy_encoder/entropy_encoder_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_KERNEl_C_\n#define DLIB_ENTROPY_ENCODER_KERNEl_C_\n\n#include \"entropy_encoder_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename encoder\n        >\n    class entropy_encoder_kernel_c : public encoder\n    {\n        \n        public:\n            std::ostream& get_stream (\n            ) const;\n\n            void encode (\n                uint32 low_count,\n                uint32 high_count,\n                uint32 total\n            );\n\n            void flush (\n            );\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename encoder\n        >\n    std::ostream& entropy_encoder_kernel_c<encoder>::\n    get_stream (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tstd::ostream& entropy_encoder::get_stream()\"\n            << \"\\n\\tyou must set a stream for this object before you can get it\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return encoder::get_stream();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename encoder\n        >\n    void entropy_encoder_kernel_c<encoder>::\n    encode (\n        uint32 low_count,\n        uint32 high_count,\n        uint32 total\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (0 < total) && (total < 65536) && (low_count < high_count) && (high_count <= total) &&\n                (this->stream_is_set() == true),\n            \"\\tvoid entropy_encoder::encode()\"\n            << \"\\n\\trefer to the ensures clause for this function for further information\"\n            << \"\\n\\tthis:            \" << this\n            << \"\\n\\ttotal:           \" << total\n            << \"\\n\\tlow_count:       \" << low_count\n            << \"\\n\\thigh_count:      \" << high_count\n            << \"\\n\\tis_stream_set(): \" << (this->stream_is_set() ? \"true\" : \"false\" )\n            );\n\n        // call the real function\n        encoder::encode(low_count,high_count,total);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename encoder\n        >\n    void entropy_encoder_kernel_c<encoder>::\n    flush (\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->stream_is_set() == true,\n            \"\\tvoid entropy_encoder::flush()\"\n            << \"\\n\\tyou must set a stream for this object before you can flush to it\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        encoder::flush();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/entropy_encoder.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODEr_\n#define DLIB_ENTROPY_ENCODEr_\n\n#include \"entropy_encoder/entropy_encoder_kernel_1.h\"\n#include \"entropy_encoder/entropy_encoder_kernel_2.h\"\n#include \"entropy_encoder/entropy_encoder_kernel_c.h\"\n\n\n\n\nnamespace dlib\n{\n\n\n    class entropy_encoder\n    {\n        entropy_encoder() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     entropy_encoder_kernel_1\n                    kernel_1a;\n        typedef     entropy_encoder_kernel_c<kernel_1a>\n                    kernel_1a_c;\n          \n\n        // kernel_2a        \n        typedef     entropy_encoder_kernel_2\n                    kernel_2a;\n        typedef     entropy_encoder_kernel_c<kernel_2a>\n                    kernel_2a_c;\n\n    };\n}\n\n#endif // DLIB_ENTROPY_ENCODEr_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_1.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc\n        >\n    class entropy_encoder_model_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n\n            INITIAL VALUE\n                Initially this object's finite context model is empty\n\n            CONVENTION\n                &get_entropy_encoder() == coder\n                &order_0.get_global_state() == &gs\n\n                This is an order-0 model. The last symbol in the order-0 context is \n                an escape into the order minus 1 context.\n        !*/\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_1 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_1 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_encoder& coder;\n        typename cc::global_state_type gs;\n        cc order_0;\n\n        // restricted functions\n        entropy_encoder_model_kernel_1(entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>&);        // copy constructor\n        entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>& operator=(entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc\n        >\n    entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::\n    entropy_encoder_model_kernel_1 (\n        entropy_encoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc\n        >\n    entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::\n    ~entropy_encoder_model_kernel_1 (\n    )\n    {\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc\n        >\n    void entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::\n    clear(\n    )\n    {\n        order_0.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc\n        >\n    void entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc>::\n    encode (\n        unsigned long symbol\n    )\n    {\n        unsigned long low_count = 0, high_count = 0, total_count = 0;\n\n        // if we have seen this symbol in the order-0 context\n        if (order_0.get_range(symbol,low_count,high_count,total_count))\n        {\n            // update the count for this symbol\n            order_0.increment_count(symbol,2);\n            // encode this symbol\n            coder.encode(low_count,high_count,total_count);                \n            return;\n        }\n    \n        // if we are here then the symbol does not appear in the order-0 context\n\n        \n        // since we have never seen the current symbol in this context\n        // escape from order-0 context\n        order_0.get_range(alphabet_size,low_count,high_count,total_count);\n        coder.encode(low_count,high_count,total_count);\n        // increment the count for the escape symbol\n        order_0.increment_count(alphabet_size);  \n\n        // update the count for this symbol\n        order_0.increment_count(symbol,2);\n\n        // use order minus one context\n        coder.encode(symbol,symbol+1,alphabet_size);\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename ccbig\n        >\n    class entropy_encoder_model_kernel_2 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n                this will be used for the order-0 context\n\n            REQUIREMENTS ON ccbig\n                ccbig is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                ccbig::get_alphabet_size() == alphabet_size+1\n                this will be used for the order-1 context\n\n            INITIAL VALUE\n                Initially this object's finite context model is empty\n                previous_symbol == 0\n\n            CONVENTION\n                &get_entropy_encoder() == coder\n                &order_0.get_global_state() == &gs\n                &order_1[i]->get_global_state() == &gsbig\n\n\n                This is an order-1-0 model. The last symbol in the order-0 and order-1\n                context is an escape into the lower context.\n\n                previous_symbol == the last symbol seen                \n        !*/\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_2 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_2 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_encoder& coder;\n        typename cc::global_state_type gs;\n        typename ccbig::global_state_type gsbig;\n        cc order_0;\n        ccbig* order_1[alphabet_size];\n        unsigned long previous_symbol;\n        \n\n        // restricted functions\n        entropy_encoder_model_kernel_2(entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>&);        // copy constructor\n        entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>& operator=(entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename ccbig\n        >\n    entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::\n    entropy_encoder_model_kernel_2 (\n        entropy_encoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs),\n        previous_symbol(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n\n        unsigned long i;\n        try\n        {\n            for (i = 0; i < alphabet_size; ++i)\n            {\n                order_1[i] = new ccbig(gsbig);\n            }\n        }\n        catch (...)\n        {\n            for (unsigned long j = 0; j < i; ++j)\n            {\n                delete order_1[j];\n            }\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename ccbig\n        >\n    entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::\n    ~entropy_encoder_model_kernel_2 (\n    )\n    {\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {           \n            delete order_1[i];\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename ccbig\n        >\n    void entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::\n    clear(\n    )\n    {\n        previous_symbol = 0;\n        order_0.clear();\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            order_1[i]->clear();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename ccbig\n        >\n    void entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc,ccbig>::\n    encode (\n        unsigned long symbol\n    )\n    {\n        unsigned long low_count = 0, high_count = 0, total_count = 0;\n\n\n        ccbig& context = *order_1[previous_symbol];\n\n        // if we have seen this symbol in the order-1 context\n        if (context.get_range(symbol,low_count,high_count,total_count))\n        {\n            // update the count for this symbol\n            context.increment_count(symbol,2);\n            // encode this symbol\n            coder.encode(low_count,high_count,total_count);\n            previous_symbol = symbol;\n            return;\n        }       \n\n        // we didn't find the symbol in the order-1 context so we must escape to a \n        // lower context.\n\n        // escape to the order-0 context\n        context.get_range(alphabet_size,low_count,high_count,total_count);\n        coder.encode(low_count,high_count,total_count);\n\n\n        // increment counts for the escape symbol and the current symbol\n        context.increment_count(alphabet_size);\n        context.increment_count(symbol,2);\n        \n        previous_symbol = symbol;\n\n\n\n\n\n        // if we have seen this symbol in the order-0 context\n        if (order_0.get_range(symbol,low_count,high_count,total_count))\n        {\n            // update the count for this symbol\n            order_0.increment_count(symbol,2);\n            // encode this symbol\n            coder.encode(low_count,high_count,total_count);                \n            return;\n        }\n    \n        // if we are here then the symbol does not appear in the order-0 context\n\n        \n        // since we have never seen the current symbol in this context\n        // escape from order-0 context\n        order_0.get_range(alphabet_size,low_count,high_count,total_count);\n        coder.encode(low_count,high_count,total_count);\n        // increment the count for the escape symbol\n        order_0.increment_count(alphabet_size);  \n\n        // update the count for this symbol\n        order_0.increment_count(symbol,2);\n\n        // use order minus one context\n        coder.encode(symbol,symbol+1,alphabet_size);\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_3.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename cc_high\n        >\n    class entropy_encoder_model_kernel_3 \n    {\n        /*!\n            REQUIREMENTS ON cc\n                cc is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc::get_alphabet_size() == alphabet_size+1\n\n            REQUIREMENTS ON cc_high\n                cc_high is an implementation of conditioning_class/conditioning_class_kernel_abstract.h\n                cc_high::get_alphabet_size() == alphabet_size+1\n\n            INITIAL VALUE\n                - Initially this object's finite context model is empty\n                - previous_symbol == 0\n                - previous_symbol2 == 0\n                - order_1 == pointer to an array of alphabet_size elements\n                - order_2 == pointer to an array of alphabet_size*alphabet_size elements\n                - order_2[i] == 0\n\n            CONVENTION\n                &get_entropy_encoder() == coder\n                &order_0.get_global_state() == &gs\n                &order_1[i]->get_global_state() == &gs\n\n                if (order_2[i] != 0) then\n                    &order_2[i]->get_global_state() == &gs_high\n\n                This is an order-2-1-0 model. The last symbol in the order-2, order-1 and \n                order-0 contexts is an escape into the lower context.\n\n                previous_symbol == the last symbol seen\n                previous_symbol2 == the symbol we saw before previous_symbol\n        !*/\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_3 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_3 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_encoder& coder;\n        typename cc::global_state_type gs;\n        typename cc_high::global_state_type gs_high;\n        cc order_0;\n        cc** order_1;\n        unsigned long previous_symbol;\n        cc_high** order_2;\n        unsigned long previous_symbol2;\n        \n\n        // restricted functions\n        entropy_encoder_model_kernel_3(entropy_encoder_model_kernel_3&);        // copy constructor\n        entropy_encoder_model_kernel_3& operator=(entropy_encoder_model_kernel_3&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename cc_high\n        >\n    entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::\n    entropy_encoder_model_kernel_3 (\n        entropy_encoder& coder_\n    ) : \n        coder(coder_),\n        order_0(gs),\n        order_1(0),\n        previous_symbol(0),\n        order_2(0),\n        previous_symbol2(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n\n        try\n        {\n            order_1 = new cc*[alphabet_size];\n            order_2 = new cc_high*[alphabet_size*alphabet_size];\n        }\n        catch (...)\n        {\n            if (order_1) delete [] order_1;\n            if (order_2) delete [] order_2;\n            throw;\n        }\n\n        unsigned long i;\n\n        for (i = 0; i < (alphabet_size*alphabet_size); ++i)\n        {\n            order_2[i] = 0;\n        }\n\n        try\n        {\n            for (i = 0; i < alphabet_size; ++i)\n            {\n                order_1[i] = new cc(gs);\n            }\n        }\n        catch (...)\n        {\n            for (unsigned long j = 0; j < i; ++j)\n            {\n                delete order_1[j];\n            }\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename cc_high\n        >\n    entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::\n    ~entropy_encoder_model_kernel_3 (\n    )\n    {\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {           \n            delete order_1[i];\n        }\n\n        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)\n        {\n            if (order_2[i] != 0)\n                delete order_2[i];\n        }\n        delete [] order_1;\n        delete [] order_2;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename cc_high\n        >\n    void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::\n    clear(\n    )\n    {\n        previous_symbol = 0;\n        previous_symbol2 = 0;\n        order_0.clear();\n        for (unsigned long i = 0; i < alphabet_size; ++i)\n        {\n            order_1[i]->clear();\n        }\n\n        for (unsigned long i = 0; i < alphabet_size*alphabet_size; ++i)\n        {\n            if (order_2[i] != 0)\n            {\n                delete order_2[i];\n                order_2[i] = 0;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        typename cc,\n        typename cc_high\n        >\n    void entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc,cc_high>::\n    encode (\n        unsigned long symbol\n    )\n    {\n        unsigned long low_count = 0, high_count = 0, total_count = 0;\n\n        \n        // order-2 context stuff\n        {\n            unsigned long temp = previous_symbol + (previous_symbol2 * alphabet_size);\n            previous_symbol2 = previous_symbol;\n\n            if (order_2[temp] != 0)\n            {\n                if (order_2[temp]->get_range(symbol,low_count,high_count,total_count))\n                {\n                    // there was an entry for this symbol in this context\n\n                    // update the count for this symbol\n                    order_2[temp]->increment_count(symbol,2);\n                    // encode this symbol\n                    coder.encode(low_count,high_count,total_count);\n                    previous_symbol = symbol;\n                    return;\n                }\n\n                // there was no entry for this symbol in this context so we must\n                // escape to order-1\n\n                // escape to the order-1 context\n                order_2[temp]->get_range(alphabet_size,low_count,high_count,total_count);\n                coder.encode(low_count,high_count,total_count);\n\n                // increment the count for the escape symbol\n                order_2[temp]->increment_count(alphabet_size);\n                \n            }\n            else\n            {                \n                order_2[temp] = new cc_high(gs_high);\n\n                // in this case the decoder knows to escape to order-1 because \n                // there was no conditioning_class object in this context yet.\n                // so we don't need to actually write the escape symbol\n            }            \n\n            // update the count for this symbol in this context\n            order_2[temp]->increment_count(symbol,2);\n        }\n\n\n\n\n        // order-1 context stuff\n        {\n            cc& context = *order_1[previous_symbol];\n\n            // if we have seen this symbol in the order-1 context\n            if (context.get_range(symbol,low_count,high_count,total_count))\n            {\n                // update the count for this symbol\n                context.increment_count(symbol,2);\n                // encode this symbol\n                coder.encode(low_count,high_count,total_count);\n                previous_symbol = symbol;\n                return;\n            }       \n\n            // we didn't find the symbol in the order-1 context so we must escape to a \n            // lower context.\n\n            // escape to the order-0 context\n            context.get_range(alphabet_size,low_count,high_count,total_count);\n            coder.encode(low_count,high_count,total_count);\n\n\n            // increment counts for the escape symbol and the current symbol\n            context.increment_count(alphabet_size);\n            context.increment_count(symbol,2);\n        }\n        \n        previous_symbol = symbol;\n\n\n\n\n\n        // if we have seen this symbol in the order-0 context\n        if (order_0.get_range(symbol,low_count,high_count,total_count))\n        {\n            // update the count for this symbol\n            order_0.increment_count(symbol,2);\n            // encode this symbol\n            coder.encode(low_count,high_count,total_count);                \n            return;\n        }\n    \n        // if we are here then the symbol does not appear in the order-0 context\n\n        \n        // since we have never seen the current symbol in this context\n        // escape from order-0 context\n        order_0.get_range(alphabet_size,low_count,high_count,total_count);\n        coder.encode(low_count,high_count,total_count);\n        // increment the count for the escape symbol\n        order_0.increment_count(alphabet_size);  \n\n        // update the count for this symbol\n        order_0.increment_count(symbol,2);\n\n        // use order minus one context\n        coder.encode(symbol,symbol+1,alphabet_size);\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_3_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_4.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\n\n\nnamespace dlib\n{\n\n    namespace eemk4\n    {\n        struct node\n        {            \n            node* next;\n            node* child_context;\n            node* parent_context;\n\n            unsigned short symbol;\n            unsigned short count;\n            unsigned short total;\n            unsigned short escapes;\n        };\n    }\n\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    class entropy_encoder_model_kernel_4 \n    {\n        /*!\n            REQUIREMENTS ON total_nodes\n                - 4096 < total_nodes\n                - this is the total number of nodes that we will use in the tree\n\n            REQUIREMENTS ON order\n                - 0 <= order\n                - this is the maximum depth-1 the tree will be allowed to go (note \n                  that the root level is depth 0).  \n\n            GENERAL NOTES\n                This implementation follows more or less the implementation \n                strategy laid out by Alistair Moffat in his paper\n                Implementing the PPM data compression scheme.  Published in IEEE \n                Transactions on Communications, 38(11):1917-1921, 1990.\n\n                The escape method used will be method D. \n\n\n            INITIAL VALUE\n                - root == pointer to an array of total_nodes nodes\n                - next_node == 1\n                - cur == root\n                - cur_order = 0\n                - root->next == 0\n                - root->parent_context == 0\n                - root->child_context == 0\n                - root->escapes == 0\n                - root->total == 0\n\n            CONVENTION\n                - &get_entropy_encoder() == coder\n                - root == pointer to an array of total_nodes nodes.\n                  this is also the root of the tree.\n\n                - if (next_node < total_nodes) then\n                    - next_node == the next node in root that has not yet been allocated                                \n\n                - root->next == 0\n                - root->parent_context == 0\n              \n\n                - for every node in the tree:\n                  {\n                    - NOTATION: \n                        - The \"context\" of a node is the string of symbols seen\n                          when you go from the root of the tree down (down though\n                          child context pointers) to the node, including the symbol at \n                          the node itself.  (note that the context of the root node \n                          is \"\" or the empty string)\n                        - A set of nodes is in the same \"context set\" if all the node's\n                          contexts are of length n and all the node's contexts share\n                          the same prefix of length n-1.\n                        - The \"child context set\" of a node is a set of nodes with\n                          contexts that are one symbol longer and prefixed by the node's \n                          context.  For example, if a node has a context \"abc\" then the \n                          nodes for contexts \"abca\", \"abcb\", \"abcc\", etc. are all in \n                          the child context set of the node.\n                        - The \"parent context\" of a node is the context that is one \n                          symbol shorter than the node's context and includes the \n                          symbol in the node.  So the parent context of a node with \n                          context \"abcd\" would be the context \"bcd\".\n\n\n                    - if (next != 0) then \n                        - next == pointer to the next node in the same context set\n                    - if (child_context != 0) then\n                        - child_context == pointer to the first node of the child \n                          context set for this node.\n                    - if (parent_context != 0) then\n                        - parent_context == pointer to the parent context of this node.\n                    - else\n                        - this node is the root node of the tree\n                  \n\n                    - if (this is not the root node) then\n                        - symbol == the symbol represented with this node\n                        - count == the number of times this symbol has been seen in its\n                          parent context.\n                    - else\n                        - the root doesn't have a symbol.  i.e. the context for the\n                          root node is \"\" or the empty string.\n\n                    - total == The sum of the counts of all the nodes \n                      in the child context set + escapes. \n                    - escapes == the escape count for the context represented\n                      by the node.\n                }\n\n\n                - cur_order < order\n                - cur_order == the depth of the node cur in the tree.\n                  (note that the root node has depth 0)\n                - cur == pointer to the node in the tree who's context matches\n                  the most recent symbols we have seen.\n\n\n        !*/\n\n        typedef eemk4::node node;\n\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_4 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_4 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        inline eemk4::node* allocate_node (\n        );\n        /*!\n            requires\n                - space_left() == true\n            ensures\n                - returns a pointer to a new node\n        !*/\n\n        inline void destroy_tree (\n        );\n        /*!\n            ensures\n                - deallocates all nodes except the root\n                - #root->child_context == 0\n                - #root->escapes == 0\n                - #root->total == 0\n                - #cur == root\n                - #cur_order == 0\n        !*/\n\n\n        inline bool space_left (\n        ) const;\n        /*!\n            ensures\n                - returns true if there is at least 1 free node left.\n                - returns false otherwise\n        !*/\n\n\n        inline void scale_counts (\n            node* n\n        );\n        /*!\n            ensures\n                - divides all the counts in the child context set of n by 2.\n                - none of the nodes in the child context set will have a count of 0\n        !*/\n\n\n        unsigned long next_node;        \n        entropy_encoder& coder;\n        node* root;\n        node* cur;\n        unsigned long cur_order;\n\n        \n        // restricted functions\n        entropy_encoder_model_kernel_4(entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>&);        // copy constructor\n        entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>& operator=(entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    entropy_encoder_model_kernel_4 (\n        entropy_encoder& coder_\n    ) : \n        next_node(1),\n        coder(coder_),\n        cur_order(0)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n        COMPILE_TIME_ASSERT( 4096 < total_nodes );\n\n        root = new node[total_nodes];  \n        cur = root;\n\n        root->child_context = 0;\n        root->escapes = 0;\n        root->next = 0;\n        root->parent_context = 0;\n        root->total = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    ~entropy_encoder_model_kernel_4 (\n    )\n    {\n        delete [] root;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    clear(\n    )\n    {\n        destroy_tree();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    encode (\n        unsigned long sym\n    )\n    {\n        unsigned short symbol = static_cast<unsigned short>(sym);\n        node* temp = cur;\n        cur = 0;\n        unsigned short low_count, high_count, total_count;\n        node* new_node = 0;\n\n        // local_order will track the level of temp in the tree\n        unsigned long local_order = cur_order;\n\n        while (true)\n        {            \n            high_count = 0;\n            if (space_left())\n            {\n                total_count = temp->total;\n                \n                if (total_count > 0)\n                {\n                    // check if we need to scale the counts\n                    if (total_count > 10000)\n                    {\n                        scale_counts(temp);\n                        total_count = temp->total;\n                    }\n\n                    // find either the symbol we are looking for or the \n                    // end of the context set\n                    node* n = temp->child_context;\n                    node* last = 0;   \n                    while (true)\n                    {\n                        high_count += n->count;\n                        \n                        if (n->symbol == symbol || n->next == 0)\n                            break;\n                        last = n;\n                        n = n->next;\n                    }             \n\n                    low_count = high_count - n->count;\n\n                    // if we found the symbol\n                    if (n->symbol == symbol)\n                    {\n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = n;                            \n                        }\n\n                        coder.encode(low_count,high_count,total_count);\n                        n->count += 8;\n                        temp->total += 8;\n\n\n                        // move this node to the front \n                        if (last)\n                        {\n                            last->next = n->next;\n                            n->next = temp->child_context;\n                            temp->child_context = n;\n                        }\n\n\n                        if (cur == 0)\n                        {\n                            if (local_order < order)\n                            {\n                                cur_order = local_order+1;\n                                cur = n;\n                            }  \n                            else\n                            {\n                                cur = n->parent_context;\n                                cur_order = local_order;\n                            }\n                        }\n\n                        break;\n                    \n                    }\n                    // if we hit the end of the context set without finding the symbol\n                    else\n                    {   \n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = allocate_node();\n                            new_node = new_node->parent_context;\n                        }\n                        else\n                        {\n                            new_node = allocate_node();\n                        }\n\n                        n->next = new_node;\n\n                        // write an escape to a lower context\n                        coder.encode(high_count,total_count,total_count);\n                    }\n                        \n                } \n                else // if (total_count == 0)\n                {\n                    // this means that temp->child_context == 0 so we should make\n                    // a new node here.\n                    if (new_node != 0)\n                    {\n                        new_node->parent_context = allocate_node();\n                        new_node = new_node->parent_context;\n                    }\n                    else\n                    {\n                        new_node = allocate_node();\n                    }\n\n                    temp->child_context = new_node;\n                }\n\n                if (cur == 0 && local_order < order)\n                {\n                    cur = new_node;\n                    cur_order = local_order+1;\n                }\n\n                // fill out the new node\n                new_node->child_context = 0;\n                new_node->count = 4;\n                new_node->escapes = 0;\n                new_node->next = 0;\n                new_node->symbol = static_cast<unsigned short>(symbol);\n                new_node->total = 0;\n                temp->escapes += 4;\n                temp->total += 8;\n\n              \n                if (temp != root)\n                {\n                    temp = temp->parent_context;\n                    --local_order;\n                    continue;\n                }\n\n                // since this is the root we are going to the order-(-1) context\n                // so we can just take care of that here.\n                new_node->parent_context = root;\n                coder.encode(symbol,symbol+1,alphabet_size);\n\n                if (cur == 0)\n                {\n                    cur = root;\n                    cur_order = 0;\n                }\n                break;\n            }\n            else \n            {\n                // there isn't enough space so we should rebuild the tree\n                destroy_tree();\n                temp = cur;\n                local_order = cur_order;\n                cur = 0;                  \n                new_node = 0;\n            }\n        } // while (true)\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    eemk4::node* entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    allocate_node (\n    )    \n    {\n        node* temp;\n        temp = root + next_node;\n        ++next_node;\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    destroy_tree (\n    )\n    {        \n        next_node = 1;\n        root->child_context = 0;\n        root->escapes = 0;\n        root->total = 0;\n        cur = root;\n        cur_order = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    space_left (\n    ) const\n    {\n        return (next_node < total_nodes);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,total_nodes,order>::\n    scale_counts (\n        node* temp\n    )\n    {\n        if (temp->escapes > 1)\n            temp->escapes >>= 1;\n        temp->total = temp->escapes;\n\n        node* n = temp->child_context;\n        while (n != 0)\n        {\n            if (n->count > 1)\n                n->count >>= 1;\n\n            temp->total += n->count;\n            n = n->next;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_4_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_5.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\n\n\nnamespace dlib\n{\n\n    namespace eemk5\n    {\n        struct node\n        {            \n            node* next;\n            node* child_context;\n            node* parent_context;\n\n            unsigned short symbol;\n            unsigned short count;\n            unsigned short total;\n            unsigned short escapes;\n        };\n    }\n\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    class entropy_encoder_model_kernel_5 \n    {\n        /*!\n            REQUIREMENTS ON total_nodes\n                - 4096 < total_nodes\n                - this is the total number of nodes that we will use in the tree\n\n            REQUIREMENTS ON order\n                - 0 <= order\n                - this is the maximum depth-1 the tree will be allowed to go (note \n                  that the root level is depth 0).  \n\n            GENERAL NOTES\n                This implementation follows more or less the implementation \n                strategy laid out by Alistair Moffat in his paper\n                Implementing the PPM data compression scheme.  Published in IEEE \n                Transactions on Communications, 38(11):1917-1921, 1990.\n\n                The escape method used will be method D. \n\n                This also uses Dmitry Shkarin's Information Inheritance scheme.\n                (described in \"PPM: one step to practicality\" and \"Improving the \n                Efficiency of the PPM Algorithm\")\n\n\n            INITIAL VALUE\n                - root == pointer to an array of total_nodes nodes\n                - next_node == 1\n                - cur == root\n                - cur_order = 0\n                - root->next == 0\n                - root->parent_context == 0\n                - root->child_context == 0\n                - root->escapes == 0\n                - root->total == 0\n                - stack_size == 0\n                - exc_used == false\n                - for all i: exc[i] == 0\n\n            CONVENTION\n                - pop() == stack[stack_size-1].n and stack[stack_size-1].nc\n                - exc_used == something_is_excluded()\n                - is_excluded(symbol) == bit symbol&0x1F from exc[symbol>>5]\n                - &get_entropy_encoder() == coder\n                - root == pointer to an array of total_nodes nodes.\n                  this is also the root of the tree.\n                - if (next_node < total_nodes) then\n                    - next_node == the next node in root that has not yet been allocated                                \n\n                - root->next == 0\n                - root->parent_context == 0\n              \n\n                - for every node in the tree:\n                  {\n                    - NOTATION: \n                        - The \"context\" of a node is the string of symbols seen\n                          when you go from the root of the tree down (down though\n                          child context pointers) to the node, including the symbol at \n                          the node itself.  (note that the context of the root node \n                          is \"\" or the empty string)\n                        - A set of nodes is in the same \"context set\" if all the node's\n                          contexts are of length n and all the node's contexts share\n                          the same prefix of length n-1.\n                        - The \"child context set\" of a node is a set of nodes with\n                          contexts that are one symbol longer and prefixed by the node's \n                          context.  For example, if a node has a context \"abc\" then the \n                          nodes for contexts \"abca\", \"abcb\", \"abcc\", etc. are all in \n                          the child context set of the node.\n                        - The \"parent context\" of a node is the context that is one \n                          symbol shorter than the node's context and includes the \n                          symbol in the node.  So the parent context of a node with \n                          context \"abcd\" would be the context \"bcd\".\n\n\n                    - if (next != 0) then \n                        - next == pointer to the next node in the same context set\n                    - if (child_context != 0) then\n                        - child_context == pointer to the first node of the child \n                          context set for this node.\n                        - escapes > 0\n                    - if (parent_context != 0) then\n                        - parent_context == pointer to the parent context of this node.\n                    - else\n                        - this node is the root node of the tree\n                  \n\n                    - if (this is not the root node) then\n                        - symbol == the symbol represented with this node\n                        - count == the number of times this symbol has been seen in its\n                          parent context.\n                    - else\n                        - the root doesn't have a symbol.  i.e. the context for the\n                          root node is \"\" or the empty string.\n\n                    - total == The sum of the counts of all the nodes \n                      in the child context set + escapes. \n                    - escapes == the escape count for the context represented\n                      by the node.                   \n                    - count > 0                    \n                }\n\n\n                - cur_order < order\n                - cur_order == the depth of the node cur in the tree.\n                  (note that the root node has depth 0)\n                - cur == pointer to the node in the tree who's context matches\n                  the most recent symbols we have seen.\n\n\n        !*/\n\n        typedef eemk5::node node;\n\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_5 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_5 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        inline eemk5::node* allocate_node (\n        );\n        /*!\n            requires\n                - space_left() == true\n            ensures\n                - returns a pointer to a new node\n        !*/\n\n        inline bool space_left (\n        ) const;\n        /*!\n            ensures\n                - returns true if there is at least 1 free node left.\n                - returns false otherwise\n        !*/\n\n        inline void exclude (\n            unsigned short symbol\n        );\n        /*!\n            ensures\n                - #is_excluded(symbol) == true\n                - #something_is_excluded() == true\n        !*/\n\n        inline bool something_is_excluded (\n        );\n        /*!\n            ensures\n                - returns true if some symbol has been excluded.\n                  returns false otherwise\n        !*/\n\n        inline bool is_excluded (\n            unsigned short symbol\n        );\n        /*!\n            ensures\n                - if (symbol has been excluded) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        inline void clear_exclusions (\n        );\n        /*!\n            ensures\n                - for all symbols #is_excluded(symbol) == false\n                - #something_is_excluded() == true\n        !*/\n\n        inline void scale_counts (\n            node* n\n        );\n        /*!\n            ensures\n                - divides all the counts in the child context set of n by 2.\n                - none of the nodes in the child context set will have a count of 0\n        !*/\n\n        inline void push (\n            node* n,\n            node* nc\n        );\n        /*!\n            requires\n                - stack_size < order\n            ensures\n                - #pop(a,b): a == n && b == nc\n        !*/\n\n        inline void pop (\n            node*& n,\n            node*& nc\n        );\n        /*!\n            requires\n                - stack_size > 0\n            ensures\n                - returns the two nodes at the top of the stack\n        !*/\n\n        struct nodes\n        {\n            node* n;\n            node* nc;\n        };\n\n        unsigned long next_node;        \n        entropy_encoder& coder;\n        node* root;\n        node* cur;\n        unsigned long cur_order;\n        unsigned long exc[alphabet_size/32+1];\n        bool exc_used;\n        nodes stack[order+1];\n        unsigned long stack_size;\n        \n        // restricted functions\n        entropy_encoder_model_kernel_5(entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>&);        // copy constructor\n        entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>& operator=(entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    entropy_encoder_model_kernel_5 (\n        entropy_encoder& coder_\n    ) : \n        next_node(1),\n        coder(coder_),\n        cur_order(0),\n        stack_size(0) \n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n        COMPILE_TIME_ASSERT( 4096 < total_nodes );\n\n        root = new node[total_nodes];  \n        cur = root;\n\n        root->child_context = 0;\n        root->escapes = 0;\n        root->next = 0;\n        root->parent_context = 0;\n        root->total = 0;\n\n        clear_exclusions();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    ~entropy_encoder_model_kernel_5 (\n    )\n    {\n        delete [] root;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    clear(\n    )\n    {\n        next_node = 1;\n        root->child_context = 0;\n        root->escapes = 0;\n        root->total = 0;\n        cur = root;\n        cur_order = 0;\n        stack_size = 0;\n\n        clear_exclusions();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    encode (\n        unsigned long sym\n    )\n    {\n        unsigned short symbol = static_cast<unsigned short>(sym);\n        node* temp = cur;\n        cur = 0;\n        unsigned short low_count, high_count, total_count;\n        node* new_node = 0;\n\n        // local_order will track the level of temp in the tree\n        unsigned long local_order = cur_order;\n\n\n        unsigned short c; // c == t(a|sk)\n        unsigned short t; // t == T(sk)\n\n \n        if (something_is_excluded())\n            clear_exclusions();\n\n        while (true)\n        {\n            low_count = 0;\n            high_count = 0;\n            if (space_left())\n            {\n                total_count = temp->total;\n                \n                if (total_count > 0)\n                {\n                    // check if we need to scale the counts\n                    if (total_count > 10000)\n                    {\n                        scale_counts(temp);\n                        total_count = temp->total;\n                    }\n\n\n                    // find the symbol we are looking for and put a pointer to it\n                    // into found_symbol.  If it isn't found then found_symbol == 0.\n                    // also, low_count and high_count will be correctly set.\n                    node* n = temp->child_context;\n                    node* found_symbol = 0;\n                    node* last = 0;\n                    if (something_is_excluded())\n                    {\n                        node* templast = 0;\n                        while (true)\n                        {\n                            if (is_excluded(n->symbol) == false)\n                            {\n                                exclude(n->symbol);\n                                if (found_symbol == 0)\n                                {\n                                    high_count += n->count;\n                                    if (n->symbol == symbol)\n                                    {\n                                        found_symbol = n;\n                                        last = templast;\n                                        low_count = high_count - n->count;\n                                    }\n                                }\n                            }\n                            else\n                            {\n                                total_count -= n->count;\n                            }\n                            \n                            if (n->next == 0)\n                                break;\n                            templast = n;\n                            n = n->next;\n                        }                         \n                    }\n                    else\n                    {\n                        while (true)\n                        {\n                            high_count += n->count;\n                            exclude(n->symbol);\n                           \n                            if (n->symbol == symbol)\n                            {\n                                found_symbol = n;\n                                low_count = high_count - n->count;\n                                break;\n                            }\n\n                            if (n->next == 0)\n                                break;\n                            last = n;\n                            n = n->next;\n                        }   \n                    }\n\n\n\n\n\n                    // if we found the symbol\n                    if (found_symbol)\n                    {\n                        n = found_symbol;\n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = found_symbol;\n                        }\n\n\n                        coder.encode(low_count,high_count,total_count);\n                        c = n->count += 8;\n                        t = temp->total += 8;\n\n                        // move this node to the front \n                        if (last)\n                        {\n                            last->next = n->next;\n                            n->next = temp->child_context;\n                            temp->child_context = n;\n                        }\n\n\n                        if (cur == 0)\n                        {\n                            if (local_order >= order)\n                            {\n                                cur = n->parent_context;\n                                cur_order = local_order;\n                            }  \n                            else\n                            {\n                                cur_order = local_order+1;\n                                cur = n;\n                            }\n                        }\n\n                        break;\n                \n                    }\n                    // if we hit the end of the context set without finding the symbol\n                    else\n                    {   \n                        // finish excluding all the symbols\n                        while (n->next)\n                        {\n                            exclude(n->symbol);\n                            n = n->next;\n                        }\n\n                        if (new_node != 0)\n                        {\n                            new_node->parent_context = allocate_node();\n                            new_node = new_node->parent_context;\n                        }\n                        else\n                        {\n                            new_node = allocate_node();\n                        }\n\n                        n->next = new_node;\n\n                        // write an escape to a lower context\n                        coder.encode(high_count,total_count,total_count);\n                    }\n                        \n                } \n                else // if (total_count == 0)\n                {\n                    // this means that temp->child_context == 0 so we should make\n                    // a new node here.\n                    if (new_node != 0)\n                    {\n                        new_node->parent_context = allocate_node();\n                        new_node = new_node->parent_context;\n                    }\n                    else\n                    {\n                        new_node = allocate_node();\n                    }\n\n                    temp->child_context = new_node;\n                }\n\n                if (cur == 0 && local_order < order)\n                {\n                    cur = new_node;\n                    cur_order = local_order+1;\n                }\n\n                // fill out the new node\n                new_node->child_context = 0;\n                new_node->escapes = 0;\n                new_node->next = 0;           \n                new_node->total = 0;\n                push(new_node,temp);\n              \n                if (temp != root)\n                {\n                    temp = temp->parent_context;\n                    --local_order;\n                    continue; \n                }\n                \n                t = 2056;\n                c = 8;\n\n                // since this is the root we are going to the order-(-1) context\n                // so we can just take care of that here.\n                new_node->parent_context = root;\n                coder.encode(symbol,symbol+1,alphabet_size);\n\n                if (cur == 0)\n                {\n                    cur = root;\n                    cur_order = 0;\n                }\n                break;\n            }\n            else \n            {\n                // there isn't enough space so we should throw away the tree\n                clear();\n                temp = cur;\n                local_order = cur_order;\n                cur = 0;      \n                new_node = 0;\n            }\n        } // while (true)\n\n\n        // initialize the counts and symbol for any new nodes we have added\n        // to the tree.\n        node* n, *nc;\n        while (stack_size > 0)\n        {            \n            pop(n,nc);        \n\n            n->symbol = static_cast<unsigned short>(symbol);\n\n            // if nc is not a determnistic context\n            if (nc->total)\n            {\n                unsigned long temp2 = t-c+nc->total - nc->escapes - nc->escapes;\n                unsigned long temp = nc->total;\n                temp *= c;\n                temp /= (temp2|1); // this oring by 1 is just to make sure that temp2 is never zero\n                temp += 2;\n                if (temp > 50000) temp = 50000;\n                n->count = static_cast<unsigned short>(temp);\n\n               \n                nc->escapes += 4;\n                nc->total += static_cast<unsigned short>(temp) + 4;\n            }\n            else\n            {\n                n->count = 3 + 5*(c)/(t-c);\n\n                nc->escapes = 4;\n                nc->total = n->count + 4;\n            }\n        \n            while (nc->total > 10000)\n            {\n                scale_counts(nc);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    eemk5::node* entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    allocate_node (\n    )    \n    {\n        node* temp;\n        temp = root + next_node;\n        ++next_node;\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    space_left (\n    ) const\n    {\n        return (next_node < total_nodes);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    exclude (\n        unsigned short symbol\n    )\n    {\n        exc_used = true;\n        unsigned long temp = 1;\n        temp <<= symbol&0x1F;\n        exc[symbol>>5] |= temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    is_excluded (\n        unsigned short symbol\n    )\n    {\n        unsigned long temp = 1;\n        temp <<= symbol&0x1F;\n        return ((exc[symbol>>5]&temp) != 0);     \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    clear_exclusions (\n    )\n    {\n        exc_used = false;\n        for (unsigned long i = 0; i < alphabet_size/32+1; ++i)\n        {\n            exc[i] = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    bool entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    something_is_excluded (\n    )\n    {\n        return exc_used;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    push (\n        node* n,\n        node* nc\n    )\n    {\n        stack[stack_size].n = n;\n        stack[stack_size].nc = nc;\n        ++stack_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    pop (\n        node*& n,\n        node*& nc\n    )\n    {   \n        --stack_size;\n        n = stack[stack_size].n;\n        nc = stack[stack_size].nc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder,\n        unsigned long total_nodes,\n        unsigned long order\n        >\n    void entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,total_nodes,order>::\n    scale_counts (\n        node* temp\n    )\n    {\n        if (temp->escapes > 1)\n            temp->escapes >>= 1;\n        temp->total = temp->escapes;\n\n        node* n = temp->child_context;\n        while (n != 0)\n        {\n            if (n->count > 1)\n                n->count >>= 1;\n\n            temp->total += n->count;\n            n = n->next;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_5_\n\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_6.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_\n\n#include \"../algs.h\"\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder \n        >\n    class entropy_encoder_model_kernel_6 \n    {\n        /*!\n            INITIAL VALUE\n                Initially this object's finite context model is empty\n\n            CONVENTION\n                &get_entropy_encoder() == coder\n           \n                This is an order-(-1) model.  So it doesn't really do anything.\n                Every symbol has the same probability.\n        !*/\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n\n        entropy_encoder_model_kernel_6 (\n            entropy_encoder& coder\n        );\n\n        virtual ~entropy_encoder_model_kernel_6 (\n        );\n        \n        inline void clear(\n        );\n\n        inline void encode (\n            unsigned long symbol\n        );\n\n        entropy_encoder& get_entropy_encoder (\n        ) { return coder; }\n\n        static unsigned long get_alphabet_size (\n        ) { return alphabet_size; }\n\n    private:\n\n        entropy_encoder& coder;\n\n        // restricted functions\n        entropy_encoder_model_kernel_6(entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>&);        // copy constructor\n        entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>& operator=(entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>&);    // assignment operator\n\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder \n        >\n    entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::\n    entropy_encoder_model_kernel_6 (\n        entropy_encoder& coder_\n    ) : \n        coder(coder_)\n    {\n        COMPILE_TIME_ASSERT( 1 < alphabet_size && alphabet_size < 65535 );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder \n        >\n    entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::\n    ~entropy_encoder_model_kernel_6 (\n    )\n    {\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder \n        >\n    void entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::\n    clear(\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder \n        >\n    void entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>::\n    encode (\n        unsigned long symbol\n    )\n    {\n        // use order minus one context\n        coder.encode(symbol,symbol+1,alphabet_size);  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_6_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_abstract.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_\n#ifdef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder\n        >\n    class entropy_encoder_model \n    {\n        /*!\n            REQUIREMENTS ON alphabet_size\n                1 < alphabet_size < 65535\n\n            REQUIREMENTS ON entropy_encoder\n                is an implementation of entropy_encoder/entropy_encoder_kernel_abstract.h\n\n            INITIAL VALUE\n                Initially this object is at some predefined empty or ground state.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some kind of statistical model.  You\n                can use it to write symbols to an entropy_encoder and it will calculate\n                the cumulative counts/probabilities and manage contexts for you.\n\n                Note that all implementations of entropy_encoder_model and \n                entropy_decoder_model are paired. This means that if you use \n                entropy_encoder_model_kernel_n to encode something then you must \n                use the corresponding entropy_decoder_model_kernel_n to decode it.\n\n                Also note that this object does not perform any buffering of symbols.  It\n                writes them to its associated entropy_encoder immediately.\n                This makes it safe to use multiple entropy_encoder_model objects with\n                a single entropy_encoder without them trampling each other.\n        !*/\n\n    public:\n\n        typedef entropy_encoder entropy_encoder_type;\n    \n        entropy_encoder_model (\n            entropy_encoder& coder\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n                - &#get_entropy_encoder() == &coder\n            throws\n                - any exception\n        !*/\n\n        virtual ~entropy_encoder_model (\n        );\n        /*!\n            ensures\n                - all memory associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n                - does not modify get_entropy_encoder()\n            throws\n                - any exception\n                    if this exception is thrown then *this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void encode (\n            unsigned long symbol\n        );\n        /*!\n            requires\n                - symbol < alphabet_size\n            ensures\n                - encodes and writes the symbol to get_entropy_encoder().\n                  This also means that there is no internal buffering.  symbol is\n                  written immediately to the entropy_encoder.\n            throws\n                - any exception\n                    If this exception is thrown then #*this is unusable until \n                    clear() is called and succeeds.\n        !*/\n\n        entropy_encoder& get_entropy_encoder (\n        );\n        /*!\n            ensures\n                - returns a reference to the entropy_encoder used by *this\n        !*/\n\n        static unsigned long get_alphabet_size (\n        );\n        /*!\n            ensures\n                - returns alphabet_size\n        !*/\n\n    private:\n\n        // restricted functions\n        entropy_encoder_model(entropy_encoder_model<alphabet_size,entropy_encoder>&);        // copy constructor\n        entropy_encoder_model<alphabet_size,entropy_encoder>& operator=(entropy_encoder_model<alphabet_size,entropy_encoder>&);    // assignment operator\n\n    };   \n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model/entropy_encoder_model_kernel_c.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_\n#define DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_\n\n#include \"entropy_encoder_model_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename eem_base\n        >\n    class entropy_encoder_model_kernel_c : public eem_base\n    {\n        const unsigned long alphabet_size;\n        typedef typename eem_base::entropy_encoder_type entropy_encoder;\n        \n        public:\n\n            entropy_encoder_model_kernel_c (\n                entropy_encoder& coder\n            ) : eem_base(coder), alphabet_size(eem_base::get_alphabet_size()) {}\n\n            void encode (\n                unsigned long symbol\n            );\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename eem_base\n        >\n    void entropy_encoder_model_kernel_c<eem_base>::\n    encode (\n        unsigned long symbol\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(symbol < alphabet_size,\n            \"\\tvoid entropy_encoder_model::encode()\"\n            << \"\\n\\tthe symbol must be in the range 0 to alphabet_size-1\"\n            << \"\\n\\talphabet_size: \" << alphabet_size\n            << \"\\n\\tsymbol:        \" << symbol\n            << \"\\n\\tthis:          \" << this\n            );\n\n        // call the real function\n        eem_base::encode(symbol);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEL_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/entropy_encoder_model.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENTROPY_ENCODER_MODEl_\n#define DLIB_ENTROPY_ENCODER_MODEl_\n\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_1.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_2.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_3.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_4.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_5.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_6.h\"\n#include \"entropy_encoder_model/entropy_encoder_model_kernel_c.h\"\n\n#include \"conditioning_class.h\"\n#include \"memory_manager.h\"\n#include \"sliding_buffer.h\"\n\n\nnamespace dlib\n{\n\n    \n    template <\n        unsigned long alphabet_size,\n        typename entropy_encoder\n        >\n    class entropy_encoder_model\n    {\n        entropy_encoder_model() {}\n\n        typedef typename conditioning_class<alphabet_size+1>::kernel_1a cc1;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_2a cc2;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_3a cc3;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4a cc4a;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4b cc4b;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4c cc4c;\n        typedef typename conditioning_class<alphabet_size+1>::kernel_4d cc4d;\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1        \n        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc1>\n                    kernel_1a;\n        typedef     entropy_encoder_model_kernel_c<kernel_1a>\n                    kernel_1a_c;\n    \n        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc2>\n                    kernel_1b;\n        typedef     entropy_encoder_model_kernel_c<kernel_1b>\n                    kernel_1b_c;\n\n        typedef     entropy_encoder_model_kernel_1<alphabet_size,entropy_encoder,cc3>\n                    kernel_1c;\n        typedef     entropy_encoder_model_kernel_c<kernel_1c>\n                    kernel_1c_c;\n\n        // --------------------\n\n        // kernel_2        \n        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc1,cc1>\n                    kernel_2a;\n        typedef     entropy_encoder_model_kernel_c<kernel_2a>\n                    kernel_2a_c;\n    \n        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc2,cc2>\n                    kernel_2b;\n        typedef     entropy_encoder_model_kernel_c<kernel_2b>\n                    kernel_2b_c;\n\n        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc3,cc3>\n                    kernel_2c;\n        typedef     entropy_encoder_model_kernel_c<kernel_2c>\n                    kernel_2c_c;\n\n        typedef     entropy_encoder_model_kernel_2<alphabet_size,entropy_encoder,cc2,cc4b>\n                    kernel_2d;\n        typedef     entropy_encoder_model_kernel_c<kernel_2d>\n                    kernel_2d_c;\n\n        // --------------------\n\n        // kernel_3        \n        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc1,cc4b>\n                    kernel_3a;\n        typedef     entropy_encoder_model_kernel_c<kernel_3a>\n                    kernel_3a_c;\n    \n        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc2,cc4b>\n                    kernel_3b;\n        typedef     entropy_encoder_model_kernel_c<kernel_3b>\n                    kernel_3b_c;\n\n        typedef     entropy_encoder_model_kernel_3<alphabet_size,entropy_encoder,cc3,cc4b>\n                    kernel_3c;\n        typedef     entropy_encoder_model_kernel_c<kernel_3c>\n                    kernel_3c_c;\n\n        // --------------------\n\n        // kernel_4        \n        typedef     entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,200000,4>\n                    kernel_4a;\n        typedef     entropy_encoder_model_kernel_c<kernel_4a>\n                    kernel_4a_c;\n\n        typedef     entropy_encoder_model_kernel_4<alphabet_size,entropy_encoder,1000000,5>\n                    kernel_4b;\n        typedef     entropy_encoder_model_kernel_c<kernel_4b>\n                    kernel_4b_c;\n\n        // --------------------\n\n        // kernel_5        \n        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,200000,4>\n                    kernel_5a;\n        typedef     entropy_encoder_model_kernel_c<kernel_5a>\n                    kernel_5a_c;\n\n        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,1000000,5>\n                    kernel_5b;\n        typedef     entropy_encoder_model_kernel_c<kernel_5b>\n                    kernel_5b_c;\n\n        typedef     entropy_encoder_model_kernel_5<alphabet_size,entropy_encoder,2500000,7>\n                    kernel_5c;\n        typedef     entropy_encoder_model_kernel_c<kernel_5c>\n                    kernel_5c_c;\n    \n        // --------------------\n\n        // kernel_6        \n        typedef     entropy_encoder_model_kernel_6<alphabet_size,entropy_encoder>\n                    kernel_6a;\n        typedef     entropy_encoder_model_kernel_c<kernel_6a>\n                    kernel_6a_c;\n\n\n    \n    };\n}\n\n#endif // DLIB_ENTROPY_ENCODER_MODEl_\n\n"
  },
  {
    "path": "dlib/error.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ERROr_ \n#define DLIB_ERROr_ \n\n#include <string>\n#include <new>          // for std::bad_alloc\n#include <iostream>\n#include <cassert>\n#include <cstdlib>\n#include <exception>\n\n// -------------------------------\n// ------ exception classes ------\n// -------------------------------\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    enum error_type\n    {       \n        EPORT_IN_USE,  \n        ETIMEOUT,     \n        ECONNECTION, \n        ELISTENER, \n        ERESOLVE,     \n        EMONITOR,   \n        ECREATE_THREAD,    \n        ECREATE_MUTEX,    \n        ECREATE_SIGNALER,\n        EUNSPECIFIED,   \n        EGENERAL_TYPE1,\n        EGENERAL_TYPE2,  \n        EGENERAL_TYPE3,  \n        EINVALID_OPTION,\n        ETOO_FEW_ARGS,\n        ETOO_MANY_ARGS,\n        ESOCKET,\n        ETHREAD,\n        EGUI,\n        EFATAL,\n        EBROKEN_ASSERT,\n        EIMAGE_LOAD,\n        EDIR_CREATE,\n        EINCOMPATIBLE_OPTIONS,\n        EMISSING_REQUIRED_OPTION,\n        EINVALID_OPTION_ARG,\n        EMULTIPLE_OCCURANCES,\n        ECONFIG_READER,\n        EIMAGE_SAVE,\n        ECAST_TO_STRING,\n        ESTRING_CAST,\n        EUTF8_TO_UTF32,\n        EOPTION_PARSE\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    // the base exception class\n    class error : public std::exception\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the base exception class for the dlib library.  i.e. all \n                exceptions in this library inherit from this class.\n        !*/\n\n    public:\n        error(\n            error_type t,\n            const std::string& a\n        ): info(a), type(t) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == a\n        !*/\n\n        error(\n            error_type t\n        ): type(t) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == \"\"\n        !*/\n\n        error(\n            const std::string& a\n        ): info(a), type(EUNSPECIFIED) {}\n        /*!\n            ensures\n                - #type == EUNSPECIFIED\n                - #info == a\n        !*/\n\n        error(\n        ): type(EUNSPECIFIED) {}\n        /*!\n            ensures\n                - #type == EUNSPECIFIED\n                - #info == \"\"\n        !*/\n\n        virtual ~error(\n        ) noexcept {}\n        /*!\n            ensures\n                - does nothing\n        !*/\n\n        const char* what(\n        ) const noexcept\n        /*!\n            ensures\n                - if (info.size() != 0) then\n                    - returns info.c_str()\n                - else\n                    - returns type_to_string(type)\n        !*/\n        {\n            if (info.size() > 0)\n                return info.c_str(); \n            else\n                return type_to_string();\n        }\n\n        const char* type_to_string (\n        ) const noexcept\n        /*!\n            ensures\n                - returns a string that names the contents of the type member.\n        !*/\n        {\n            if ( type == EPORT_IN_USE) return \"EPORT_IN_USE\";\n            else if ( type == ETIMEOUT) return \"ETIMEOUT\";\n            else if ( type == ECONNECTION) return \"ECONNECTION\"; \n            else if ( type == ELISTENER) return \"ELISTENER\"; \n            else if ( type == ERESOLVE) return \"ERESOLVE\";     \n            else if ( type == EMONITOR) return \"EMONITOR\";   \n            else if ( type == ECREATE_THREAD) return \"ECREATE_THREAD\";    \n            else if ( type == ECREATE_MUTEX) return \"ECREATE_MUTEX\";    \n            else if ( type == ECREATE_SIGNALER) return \"ECREATE_SIGNALER\";\n            else if ( type == EUNSPECIFIED) return \"EUNSPECIFIED\";   \n            else if ( type == EGENERAL_TYPE1) return \"EGENERAL_TYPE1\";\n            else if ( type == EGENERAL_TYPE2) return \"EGENERAL_TYPE2\";  \n            else if ( type == EGENERAL_TYPE3) return \"EGENERAL_TYPE3\";  \n            else if ( type == EINVALID_OPTION) return \"EINVALID_OPTION\";\n            else if ( type == ETOO_FEW_ARGS) return \"ETOO_FEW_ARGS\";\n            else if ( type == ETOO_MANY_ARGS) return \"ETOO_MANY_ARGS\";\n            else if ( type == ESOCKET) return \"ESOCKET\";\n            else if ( type == ETHREAD) return \"ETHREAD\";\n            else if ( type == EGUI) return \"EGUI\";\n            else if ( type == EFATAL) return \"EFATAL\";\n            else if ( type == EBROKEN_ASSERT) return \"EBROKEN_ASSERT\";\n            else if ( type == EIMAGE_LOAD) return \"EIMAGE_LOAD\";\n            else if ( type == EDIR_CREATE) return \"EDIR_CREATE\";\n            else if ( type == EINCOMPATIBLE_OPTIONS) return \"EINCOMPATIBLE_OPTIONS\";\n            else if ( type == EMISSING_REQUIRED_OPTION) return \"EMISSING_REQUIRED_OPTION\";\n            else if ( type == EINVALID_OPTION_ARG) return \"EINVALID_OPTION_ARG\";\n            else if ( type == EMULTIPLE_OCCURANCES) return \"EMULTIPLE_OCCURANCES\";\n            else if ( type == ECONFIG_READER) return \"ECONFIG_READER\";\n            else if ( type == EIMAGE_SAVE) return \"EIMAGE_SAVE\";\n            else if ( type == ECAST_TO_STRING) return \"ECAST_TO_STRING\";\n            else if ( type == ESTRING_CAST) return \"ESTRING_CAST\";\n            else if ( type == EUTF8_TO_UTF32) return \"EUTF8_TO_UTF32\";\n            else if ( type == EOPTION_PARSE) return \"EOPTION_PARSE\";\n            else return \"undefined error type\";\n        }\n\n        const std::string info;  // info about the error\n        const error_type type; // the type of the error\n\n    private:\n        const error& operator=(const error&);\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class fatal_error : public error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                As the name says, this object represents some kind of fatal error.  \n                That is, it represents an unrecoverable error and any program that\n                throws this exception is, by definition, buggy and needs to be fixed.\n\n                Note that a fatal_error exception can only be thrown once.  The second\n                time an application attempts to construct a fatal_error it will be \n                immediately aborted and an error message will be printed to std::cerr. \n                The reason for this is because the first fatal_error was apparently ignored\n                so the second fatal_error is going to make itself impossible to ignore \n                by calling abort.  The lesson here is that you should not try to ignore \n                fatal errors.\n\n                This is also the exception thrown by the DLIB_ASSERT and DLIB_CASSERT macros.\n        !*/\n\n    public:\n        fatal_error(\n            error_type t,\n            const std::string& a\n        ): error(t,a) {check_for_previous_fatal_errors();}\n        /*!\n            ensures\n                - #type == t\n                - #info == a\n        !*/\n\n        fatal_error(\n            error_type t\n        ): error(t) {check_for_previous_fatal_errors();}\n        /*!\n            ensures\n                - #type == t\n                - #info == \"\"\n        !*/\n\n        fatal_error(\n            const std::string& a\n        ): error(EFATAL,a) {check_for_previous_fatal_errors();}\n        /*!\n            ensures\n                - #type == EFATAL\n                - #info == a\n        !*/\n\n        fatal_error(\n        ): error(EFATAL) {check_for_previous_fatal_errors();}\n        /*!\n            ensures\n                - #type == EFATAL\n                - #info == \"\"\n        !*/\n\n    private:\n\n        static inline char* message ()\n        { \n            static char buf[2000];\n            buf[1999] = '\\0'; // just to be extra safe\n            return buf;\n        }\n\n        static inline void dlib_fatal_error_terminate (\n        )\n        {\n            std::cerr << \"\\n**************************** FATAL ERROR DETECTED ****************************\";\n            std::cerr << message() << std::endl;\n            std::cerr << \"******************************************************************************\\n\" << std::endl;\n        }\n\n        void check_for_previous_fatal_errors()\n        {\n            // If dlib is being use to create plugins for some other application, like\n            // MATLAB, then don't do these checks since it terminates the over arching\n            // system.  Just let the errors go to the plugin handler and it will deal with\n            // them.\n#if defined(MATLAB_MEX_FILE) || defined(DLIB_NO_ABORT_ON_2ND_FATAL_ERROR)\n            return;\n#else\n            static bool is_first_fatal_error = true;\n            if (is_first_fatal_error == false)\n            {\n                std::cerr << \"\\n\\n ************************** FATAL ERROR DETECTED ************************** \" << std::endl;\n                std::cerr << \" ************************** FATAL ERROR DETECTED ************************** \" << std::endl;\n                std::cerr << \" ************************** FATAL ERROR DETECTED ************************** \\n\" << std::endl;\n                std::cerr << \"Two fatal errors have been detected, the first was inappropriately ignored. \\n\"\n                          << \"To prevent further fatal errors from being ignored this application will be \\n\"\n                          << \"terminated immediately and you should go fix this buggy program.\\n\\n\"\n                          << \"The error message from this fatal error was:\\n\" << this->what() << \"\\n\\n\" << std::endl;\n                assert(false);\n                abort();\n            }\n            else\n            {\n                // copy the message into the fixed message buffer so that it can be recalled by dlib_fatal_error_terminate\n                // if needed.\n                char* msg = message();\n                unsigned long i;\n                for (i = 0; i < 2000-1 && i < this->info.size(); ++i)\n                    msg[i] = info[i];\n                msg[i] = '\\0';\n\n                // set this termination handler so that if the user doesn't catch this dlib::fatal_error that is being\n                // thrown then it will eventually be printed to standard error\n                std::set_terminate(&dlib_fatal_error_terminate);\n            }\n            is_first_fatal_error = false;\n#endif\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class gui_error : public error\n    {\n    public:\n        gui_error(\n            error_type t,\n            const std::string& a\n        ): error(t,a) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == a\n        !*/\n\n        gui_error(\n            error_type t\n        ): error(t) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == \"\"\n        !*/\n\n        gui_error(\n            const std::string& a\n        ): error(EGUI,a) {}\n        /*!\n            ensures\n                - #type == EGUI \n                - #info == a\n        !*/\n\n        gui_error(\n        ): error(EGUI) {}\n        /*!\n            ensures\n                - #type == EGUI\n                - #info == \"\"\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class socket_error : public error\n    {\n    public:\n        socket_error(\n            error_type t,\n            const std::string& a\n        ): error(t,a) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == a\n        !*/\n\n        socket_error(\n            error_type t\n        ): error(t) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == \"\"\n        !*/\n\n        socket_error(\n            const std::string& a\n        ): error(ESOCKET,a) {}\n        /*!\n            ensures\n                - #type == ESOCKET\n                - #info == a\n        !*/\n\n        socket_error(\n        ): error(ESOCKET) {}\n        /*!\n            ensures\n                - #type == ESOCKET\n                - #info == \"\"\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class thread_error : public error\n    {\n    public:\n        thread_error(\n            error_type t,\n            const std::string& a\n        ): error(t,a) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == a\n        !*/\n\n        thread_error(\n            error_type t\n        ): error(t) {}\n        /*!\n            ensures\n                - #type == t\n                - #info == \"\"\n        !*/\n\n        thread_error(\n            const std::string& a\n        ): error(ETHREAD,a) {}\n        /*!\n            ensures\n                - #type == ETHREAD\n                - #info == a\n        !*/\n\n        thread_error(\n        ): error(ETHREAD) {}\n        /*!\n            ensures\n                - #type == ETHREAD\n                - #info == \"\"\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class impossible_labeling_error : public dlib::error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown by code that trains object detectors (e.g.\n                structural_svm_object_detection_problem) when they detect that the set of\n                truth boxes given to the training algorithm contains some impossible to\n                obtain outputs.  \n                \n                This kind of problem can happen when the set of image positions scanned by\n                the underlying object detection method doesn't include the truth rectangle\n                as a possible output.  Another possibility is when two truth boxes are very\n                close together and hard coded non-max suppression logic would prevent two\n                boxes in such close proximity from being output.\n        !*/\n    public: \n        impossible_labeling_error(const std::string& msg) : dlib::error(msg) {};\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ERROr_\n\n"
  },
  {
    "path": "dlib/external/cblas/CMakeLists.txt",
    "content": "#\n# This is a CMake makefile.  You can find the cmake utility and\n# information about it at http://www.cmake.org\n#\n\n\ncmake_minimum_required(VERSION 3.8.0)\nproject(cblas)\n\n\nenable_language (Fortran)\n\nset(CMAKE_POSITION_INDEPENDENT_CODE True)\nadd_definitions(-DADD_ -DF77_INT=ptrdiff_t)\n\nadd_library(cblas STATIC \n   cblas_caxpy.c\n   #cblas_ccopy.c\n   cblas_cdotc_sub.c\n   cblas_cdotu_sub.c\n   #cblas_cgbmv.c\n   cblas_cgemm.c\n   cblas_cgemv.c\n   cblas_cgerc.c\n   cblas_cgeru.c\n   #cblas_chbmv.c\n   #cblas_chemm.c\n   #cblas_chemv.c\n   #cblas_cher2.c\n   #cblas_cher2k.c\n   #cblas_cher.c\n   #cblas_cherk.c\n   #cblas_chpmv.c\n   #cblas_chpr2.c\n   #cblas_chpr.c\n   cblas_cscal.c\n   #cblas_csscal.c\n   #cblas_cswap.c\n   #cblas_csymm.c\n   #cblas_csyr2k.c\n   #cblas_csyrk.c\n   #cblas_ctbmv.c\n   #cblas_ctbsv.c\n   #cblas_ctpmv.c\n   #cblas_ctpsv.c\n   #cblas_ctrmm.c\n   #cblas_ctrmv.c\n   cblas_ctrsm.c\n   #cblas_ctrsv.c\n   #cblas_dasum.c\n   cblas_daxpy.c\n   #cblas_dcopy.c\n   cblas_ddot.c\n   #cblas_dgbmv.c\n   cblas_dgemm.c\n   cblas_dgemv.c\n   cblas_dger.c\n   #cblas_dnrm2.c\n   #cblas_drot.c\n   #cblas_drotg.c\n   #cblas_drotm.c\n   #cblas_drotmg.c\n   #cblas_dsbmv.c\n   cblas_dscal.c\n   #cblas_dsdot.c\n   #cblas_dspmv.c\n   #cblas_dspr2.c\n   #cblas_dspr.c\n   #cblas_dswap.c\n   #cblas_dsymm.c\n   #cblas_dsymv.c\n   #cblas_dsyr2.c\n   #cblas_dsyr2k.c\n   #cblas_dsyr.c\n   #cblas_dsyrk.c\n   #cblas_dtbmv.c\n   #cblas_dtbsv.c\n   #cblas_dtpmv.c\n   #cblas_dtpsv.c\n   #cblas_dtrmm.c\n   #cblas_dtrmv.c\n   cblas_dtrsm.c\n   #cblas_dtrsv.c\n   #cblas_dzasum.c\n   #cblas_dznrm2.c\n   #cblas_icamax.c\n   #cblas_idamax.c\n   #cblas_isamax.c\n   #cblas_izamax.c\n   #cblas_sasum.c\n   cblas_saxpy.c\n   #cblas_scasum.c\n   #cblas_scnrm2.c\n   #cblas_scopy.c\n   cblas_sdot.c\n   #cblas_sdsdot.c\n   #cblas_sgbmv.c\n   cblas_sgemm.c\n   cblas_sgemv.c\n   cblas_sger.c\n   #cblas_snrm2.c\n   #cblas_srot.c\n   #cblas_srotg.c\n   #cblas_srotm.c\n   #cblas_srotmg.c\n   #cblas_ssbmv.c\n   cblas_sscal.c\n   #cblas_sspmv.c\n   #cblas_sspr2.c\n   #cblas_sspr.c\n   #cblas_sswap.c\n   #cblas_ssymm.c\n   #cblas_ssymv.c\n   #cblas_ssyr2.c\n   #cblas_ssyr2k.c\n   #cblas_ssyr.c\n   #cblas_ssyrk.c\n   #cblas_stbmv.c\n   #cblas_stbsv.c\n   #cblas_stpmv.c\n   #cblas_stpsv.c\n   #cblas_strmm.c\n   #cblas_strmv.c\n   cblas_strsm.c\n   #cblas_strsv.c\n   cblas_xerbla.c\n   cblas_zaxpy.c\n   #cblas_zcopy.c\n   cblas_zdotc_sub.c\n   cblas_zdotu_sub.c\n   #cblas_zdscal.c\n   #cblas_zgbmv.c\n   cblas_zgemm.c\n   cblas_zgemv.c\n   cblas_zgerc.c\n   cblas_zgeru.c\n   #cblas_zhbmv.c\n   #cblas_zhemm.c\n   #cblas_zhemv.c\n   #cblas_zher2.c\n   #cblas_zher2k.c\n   #cblas_zher.c\n   #cblas_zherk.c\n   #cblas_zhpmv.c\n   #cblas_zhpr2.c\n   #cblas_zhpr.c\n   cblas_zscal.c\n   #cblas_zswap.c\n   #cblas_zsymm.c\n   #cblas_zsyr2k.c\n   #cblas_zsyrk.c\n   #cblas_ztbmv.c\n   #cblas_ztbsv.c\n   #cblas_ztpmv.c\n   #cblas_ztpsv.c\n   #cblas_ztrmm.c\n   #cblas_ztrmv.c\n   cblas_ztrsm.c\n   #cblas_ztrsv.c\n\n   cdotcsub.f\n   cdotusub.f\n   dasumsub.f\n   ddotsub.f\n   dnrm2sub.f\n   dsdotsub.f\n   dzasumsub.f\n   dznrm2sub.f\n   icamaxsub.f\n   idamaxsub.f\n   isamaxsub.f\n   izamaxsub.f\n   sasumsub.f\n   scasumsub.f\n   scnrm2sub.f\n   sdotsub.f\n   sdsdotsub.f\n   snrm2sub.f\n   zdotcsub.f\n   zdotusub.f\n      )\n\n"
  },
  {
    "path": "dlib/external/cblas/README",
    "content": "This folder contains a copy of CBLAS (from http://www.netlib.org/blas/) which\nhas been setup so you can compile it with CMake.  It also only compiles the\npart of CBLAS needed by dlib.\n\nMost BLAS libraries come with CBLAS, however, some don't.  In particular, if\nyou are using the BLAS that comes with MATLAB then you will need this CBLAS\ncode linked into your own to get dlib working with MATLAB's built in BLAS.\n"
  },
  {
    "path": "dlib/external/cblas/cblas.h",
    "content": "#ifndef CBLAS_H\n#define CBLAS_H\n#include <stddef.h>\n#include <stdint.h>\n\n/*\n * Enumerated and derived types\n */\n#define CBLAS_INDEX size_t  /* this may vary between platforms */\n\nenum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};\nenum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};\nenum CBLAS_UPLO {CblasUpper=121, CblasLower=122};\nenum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};\nenum CBLAS_SIDE {CblasLeft=141, CblasRight=142};\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef CBLAS_INT_TYPE\n#define CBLAS_INT_TYPE int \n#endif\n\n/*\n * ===========================================================================\n * Prototypes for level 1 BLAS functions (complex are recast as routines)\n * ===========================================================================\n */\nfloat  cblas_sdsdot(const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                    const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY);\ndouble cblas_dsdot(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, const float *Y,\n                   const CBLAS_INT_TYPE incY);\nfloat  cblas_sdot(const CBLAS_INT_TYPE N, const float  *X, const CBLAS_INT_TYPE incX,\n                  const float  *Y, const CBLAS_INT_TYPE incY);\ndouble cblas_ddot(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX,\n                  const double *Y, const CBLAS_INT_TYPE incY);\n\n/*\n * Functions having prefixes Z and C only\n */\nvoid   cblas_cdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                       const void *Y, const CBLAS_INT_TYPE incY, void *dotu);\nvoid   cblas_cdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                       const void *Y, const CBLAS_INT_TYPE incY, void *dotc);\n\nvoid   cblas_zdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                       const void *Y, const CBLAS_INT_TYPE incY, void *dotu);\nvoid   cblas_zdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                       const void *Y, const CBLAS_INT_TYPE incY, void *dotc);\n\n\n/*\n * Functions having prefixes S D SC DZ\n */\nfloat  cblas_snrm2(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX);\nfloat  cblas_sasum(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX);\n\ndouble cblas_dnrm2(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX);\ndouble cblas_dasum(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX);\n\nfloat  cblas_scnrm2(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX);\nfloat  cblas_scasum(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX);\n\ndouble cblas_dznrm2(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX);\ndouble cblas_dzasum(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX);\n\n\n/*\n * Functions having standard 4 prefixes (S D C Z)\n */\nCBLAS_INDEX cblas_isamax(const CBLAS_INT_TYPE N, const float  *X, const CBLAS_INT_TYPE incX);\nCBLAS_INDEX cblas_idamax(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX);\nCBLAS_INDEX cblas_icamax(const CBLAS_INT_TYPE N, const void   *X, const CBLAS_INT_TYPE incX);\nCBLAS_INDEX cblas_izamax(const CBLAS_INT_TYPE N, const void   *X, const CBLAS_INT_TYPE incX);\n\n/*\n * ===========================================================================\n * Prototypes for level 1 BLAS routines\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (s, d, c, z)\n */\nvoid cblas_sswap(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, \n                 float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_scopy(const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX, \n                 float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_saxpy(const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                 const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY);\n\nvoid cblas_dswap(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, \n                 double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dcopy(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX, \n                 double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_daxpy(const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                 const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY);\n\nvoid cblas_cswap(const CBLAS_INT_TYPE N, void *X, const CBLAS_INT_TYPE incX, \n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_ccopy(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, \n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_caxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                 const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY);\n\nvoid cblas_zswap(const CBLAS_INT_TYPE N, void *X, const CBLAS_INT_TYPE incX, \n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zcopy(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX, \n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zaxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                 const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY);\n\n\n/* \n * Routines with S and D prefix only\n */\nvoid cblas_srotg(float *a, float *b, float *c, float *s);\nvoid cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P);\nvoid cblas_srot(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX,\n                float *Y, const CBLAS_INT_TYPE incY, const float c, const float s);\nvoid cblas_srotm(const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX,\n                float *Y, const CBLAS_INT_TYPE incY, const float *P);\n\nvoid cblas_drotg(double *a, double *b, double *c, double *s);\nvoid cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P);\nvoid cblas_drot(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX,\n                double *Y, const CBLAS_INT_TYPE incY, const double c, const double  s);\nvoid cblas_drotm(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX,\n                double *Y, const CBLAS_INT_TYPE incY, const double *P);\n\n\n/* \n * Routines with S D C Z CS and ZD prefixes\n */\nvoid cblas_sscal(const CBLAS_INT_TYPE N, const float alpha, float *X, const CBLAS_INT_TYPE incX);\nvoid cblas_dscal(const CBLAS_INT_TYPE N, const double alpha, double *X, const CBLAS_INT_TYPE incX);\nvoid cblas_cscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_zscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_csscal(const CBLAS_INT_TYPE N, const float alpha, void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_zdscal(const CBLAS_INT_TYPE N, const double alpha, void *X, const CBLAS_INT_TYPE incX);\n\n/*\n * ===========================================================================\n * Prototypes for level 2 BLAS\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (S, D, C, Z)\n */\nvoid cblas_sgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 const float *X, const CBLAS_INT_TYPE incX, const float beta,\n                 float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_sgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const float alpha,\n                 const float *A, const CBLAS_INT_TYPE lda, const float *X,\n                 const CBLAS_INT_TYPE incX, const float beta, float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float *A, const CBLAS_INT_TYPE lda, \n                 float *X, const CBLAS_INT_TYPE incX);\nvoid cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float *A, const CBLAS_INT_TYPE lda, \n                 float *X, const CBLAS_INT_TYPE incX);\nvoid cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float *Ap, float *X, const CBLAS_INT_TYPE incX);\nvoid cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float *A, const CBLAS_INT_TYPE lda, float *X,\n                 const CBLAS_INT_TYPE incX);\nvoid cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float *A, const CBLAS_INT_TYPE lda,\n                 float *X, const CBLAS_INT_TYPE incX);\nvoid cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float *Ap, float *X, const CBLAS_INT_TYPE incX);\n\nvoid cblas_dgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                 const double *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const double alpha,\n                 const double *A, const CBLAS_INT_TYPE lda, const double *X,\n                 const CBLAS_INT_TYPE incX, const double beta, double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double *A, const CBLAS_INT_TYPE lda, \n                 double *X, const CBLAS_INT_TYPE incX);\nvoid cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double *A, const CBLAS_INT_TYPE lda, \n                 double *X, const CBLAS_INT_TYPE incX);\nvoid cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double *Ap, double *X, const CBLAS_INT_TYPE incX);\nvoid cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double *A, const CBLAS_INT_TYPE lda, double *X,\n                 const CBLAS_INT_TYPE incX);\nvoid cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double *A, const CBLAS_INT_TYPE lda,\n                 double *X, const CBLAS_INT_TYPE incX);\nvoid cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double *Ap, double *X, const CBLAS_INT_TYPE incX);\n\nvoid cblas_cgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_cgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const void *alpha,\n                 const void *A, const CBLAS_INT_TYPE lda, const void *X,\n                 const CBLAS_INT_TYPE incX, const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, \n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, \n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, void *X,\n                 const CBLAS_INT_TYPE incX);\nvoid cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda,\n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX);\n\nvoid cblas_zgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU, const void *alpha,\n                 const void *A, const CBLAS_INT_TYPE lda, const void *X,\n                 const CBLAS_INT_TYPE incX, const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, \n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda, \n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *A, const CBLAS_INT_TYPE lda, void *X,\n                 const CBLAS_INT_TYPE incX);\nvoid cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *A, const CBLAS_INT_TYPE lda,\n                 void *X, const CBLAS_INT_TYPE incX);\nvoid cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void *Ap, void *X, const CBLAS_INT_TYPE incX);\n\n\n/* \n * Routines with S and D prefixes only\n */\nvoid cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const float alpha, const float *A,\n                 const CBLAS_INT_TYPE lda, const float *X, const CBLAS_INT_TYPE incX,\n                 const float beta, float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float alpha, const float *A,\n                 const CBLAS_INT_TYPE lda, const float *X, const CBLAS_INT_TYPE incX,\n                 const float beta, float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const float alpha, const float *Ap,\n                 const float *X, const CBLAS_INT_TYPE incX,\n                 const float beta, float *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_sger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                const float alpha, const float *X, const CBLAS_INT_TYPE incX,\n                const float *Y, const CBLAS_INT_TYPE incY, float *A, const CBLAS_INT_TYPE lda);\nvoid cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                const CBLAS_INT_TYPE incX, float *A, const CBLAS_INT_TYPE lda);\nvoid cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                const CBLAS_INT_TYPE incX, float *Ap);\nvoid cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY, float *A,\n                const CBLAS_INT_TYPE lda);\nvoid cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY, float *A);\n\nvoid cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const double alpha, const double *A,\n                 const CBLAS_INT_TYPE lda, const double *X, const CBLAS_INT_TYPE incX,\n                 const double beta, double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double alpha, const double *A,\n                 const CBLAS_INT_TYPE lda, const double *X, const CBLAS_INT_TYPE incX,\n                 const double beta, double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const double alpha, const double *Ap,\n                 const double *X, const CBLAS_INT_TYPE incX,\n                 const double beta, double *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_dger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                const double alpha, const double *X, const CBLAS_INT_TYPE incX,\n                const double *Y, const CBLAS_INT_TYPE incY, double *A, const CBLAS_INT_TYPE lda);\nvoid cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                const CBLAS_INT_TYPE incX, double *A, const CBLAS_INT_TYPE lda);\nvoid cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                const CBLAS_INT_TYPE incX, double *Ap);\nvoid cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                const CBLAS_INT_TYPE incX, const double *Y, const CBLAS_INT_TYPE incY, double *A,\n                const CBLAS_INT_TYPE lda);\nvoid cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                const CBLAS_INT_TYPE incX, const double *Y, const CBLAS_INT_TYPE incY, double *A);\n\n\n/* \n * Routines with C and Z prefixes only\n */\nvoid cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *Ap,\n                 const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_cgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_cgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const void *X, const CBLAS_INT_TYPE incX,\n                void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const void *X,\n                const CBLAS_INT_TYPE incX, void *A);\nvoid cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                const void *Y, const CBLAS_INT_TYPE incY, void *Ap);\n\nvoid cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *Ap,\n                 const void *X, const CBLAS_INT_TYPE incX,\n                 const void *beta, void *Y, const CBLAS_INT_TYPE incY);\nvoid cblas_zgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_zgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const void *X, const CBLAS_INT_TYPE incX,\n                void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const void *X,\n                const CBLAS_INT_TYPE incX, void *A);\nvoid cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\nvoid cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                const void *Y, const CBLAS_INT_TYPE incY, void *Ap);\n\n/*\n * ===========================================================================\n * Prototypes for level 3 BLAS\n * ===========================================================================\n */\n\n/* \n * Routines with standard 4 prefixes (S, D, C, Z)\n */\nvoid cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const float alpha, const float *A,\n                 const CBLAS_INT_TYPE lda, const float *B, const CBLAS_INT_TYPE ldb,\n                 const float beta, float *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 const float *B, const CBLAS_INT_TYPE ldb, const float beta,\n                 float *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 const float beta, float *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                  const float *B, const CBLAS_INT_TYPE ldb, const float beta,\n                  float *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 float *B, const CBLAS_INT_TYPE ldb);\nvoid cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 float *B, const CBLAS_INT_TYPE ldb);\n\nvoid cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const double alpha, const double *A,\n                 const CBLAS_INT_TYPE lda, const double *B, const CBLAS_INT_TYPE ldb,\n                 const double beta, double *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                 const double *B, const CBLAS_INT_TYPE ldb, const double beta,\n                 double *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                 const double beta, double *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                  const double *B, const CBLAS_INT_TYPE ldb, const double beta,\n                  double *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                 double *B, const CBLAS_INT_TYPE ldb);\nvoid cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                 double *B, const CBLAS_INT_TYPE ldb);\n\nvoid cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb,\n                 const void *beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                  void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 void *B, const CBLAS_INT_TYPE ldb);\nvoid cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 void *B, const CBLAS_INT_TYPE ldb);\n\nvoid cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                 const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb,\n                 const void *beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                  void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 void *B, const CBLAS_INT_TYPE ldb);\nvoid cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 void *B, const CBLAS_INT_TYPE ldb);\n\n\n/* \n * Routines with prefixes C and Z only\n */\nvoid cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const float alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const float beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const float beta,\n                  void *C, const CBLAS_INT_TYPE ldc);\n\nvoid cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const double alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const double beta, void *C, const CBLAS_INT_TYPE ldc);\nvoid cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const double beta,\n                  void *C, const CBLAS_INT_TYPE ldc);\n\nvoid cblas_xerbla(int p, const char *rout, const char *form, ...);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "dlib/external/cblas/cblas_caxpy.c",
    "content": "/*\n * cblas_caxpy.c\n *\n * The program is a C interface to caxpy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_caxpy( const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                       const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_caxpy( &F77_N, alpha, X, &F77_incX, Y, &F77_incY);\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_ccopy.c",
    "content": "/*\n * cblas_ccopy.c\n *\n * The program is a C interface to ccopy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ccopy( const CBLAS_INT_TYPE N, const void *X,\n                      const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_ccopy( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cdotc_sub.c",
    "content": "/*\n * cblas_cdotc_sub.c\n *\n * The program is a C interface to cdotc.\n * It calls the fortran wrapper before calling cdotc.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cdotc_sub( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                    const void *Y, const CBLAS_INT_TYPE incY,void *dotc)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_cdotc_sub( &F77_N, X, &F77_incX, Y, &F77_incY, dotc);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cdotu_sub.c",
    "content": "/*\n * cblas_cdotu_sub.f\n *\n * The program is a C interface to cdotu.\n * It calls the forteran wrapper before calling cdotu.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cdotu_sub( const CBLAS_INT_TYPE N, const void *X,\n                     const CBLAS_INT_TYPE incX, const void *Y, const CBLAS_INT_TYPE incY,void *dotu)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_cdotu_sub( &F77_N, X, &F77_incX, Y, &F77_incY, dotu);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cgbmv.c",
    "content": "/*\n * cblas_cgbmv.c\n * The program is a C interface of cgbmv\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n   F77_INT F77_KL=KL,F77_KU=KU;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_KL KL\n   #define F77_KU KU\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n=0, i=0, incx=incX;\n   const float *xx= (float *)X, *alp= (float *)alpha, *bet = (float *)beta;\n   float ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   float *x=(float *)X, *y=(float *)Y, *st=0, *tx=0;\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_cgbmv(F77_TA, &F77_M, &F77_N, &F77_KL, &F77_KU, alpha,  \n                     A, &F77_lda, X, &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         ALPHA[0]= *alp;\n         ALPHA[1]= -alp[1];\n         BETA[0]= *bet;\n         BETA[1]= -bet[1];\n         TA = 'N';\n         if (M > 0)\n         {\n            n = M << 1;\n            x = malloc(n*sizeof(float));\n            tx = x;\n\n            if( incX > 0 ) {\n               i = incX << 1 ;\n               tincx = 2;\n               st= x+n;\n            } else {\n               i = incX *(-2);\n               tincx = -2;\n               st = x-2;\n               x +=(n-2);\n            }\n            do\n            {\n               *x = *xx;\n               x[1] = -xx[1];\n               x += tincx ;\n               xx += i;\n            }\n            while (x != st);\n            x=tx;\n\n            #ifdef F77_INT\n               F77_incX = 1;\n            #else\n               incx = 1;\n            #endif\n\n            if( incY > 0 )\n              tincY = incY;\n            else\n              tincY = -incY;\n\n            y++;\n \n            if (N > 0)\n            {\n               i = tincY << 1;\n               n = i * N ;\n               st = y + n;\n               do {\n                  *y = -(*y);\n                  y += i;\n               } while(y != st);\n               y -= n;\n            }\n         }\n         else x = (float *) X;\n\n \n      }\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      if (TransA == CblasConjTrans)\n         F77_cgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, ALPHA, \n                        A ,&F77_lda, x,&F77_incX, BETA, Y, &F77_incY);\n      else\n         F77_cgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, alpha, \n                        A ,&F77_lda, x,&F77_incX, beta, Y, &F77_incY);\n      if (TransA == CblasConjTrans)\n      {\n         if (x != X) free(x);\n         if (N > 0)\n         {\n            do\n            {\n               *y = -(*y);\n               y += i;\n            }\n            while (y != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_cgbmv\", \"Illegal Order setting, %d\\n\", order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cgemm.c",
    "content": "/*\n *\n * cblas_cgemm.c\n * This program is a C interface to cgemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const void *alpha, const void  *A,\n                 const CBLAS_INT_TYPE lda, const void  *B, const CBLAS_INT_TYPE ldb,\n                 const void *beta, void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char TA, TB;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_TB;\n#else\n   #define F77_TA &TA  \n   #define F77_TB &TB  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if(TransA == CblasTrans) TA='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgemm\", \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if(TransB == CblasTrans) TB='T';\n      else if ( TransB == CblasConjTrans ) TB='C';\n      else if ( TransB == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cgemm\", \"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_cgemm(F77_TA, F77_TB, &F77_M, &F77_N, &F77_K, alpha, A,\n                     &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if(TransA == CblasTrans) TB='T';\n      else if ( TransA == CblasConjTrans ) TB='C';\n      else if ( TransA == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgemm\", \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if(TransB == CblasTrans) TA='T';\n      else if ( TransB == CblasConjTrans ) TA='C';\n      else if ( TransB == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgemm\", \"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_cgemm(F77_TA, F77_TB, &F77_N, &F77_M, &F77_K, alpha, B,\n                  &F77_ldb, A, &F77_lda, beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_cgemm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cgemv.c",
    "content": "/*\n * cblas_cgemv.c\n * The program is a C interface of cgemv\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n\n   CBLAS_INT_TYPE n=0, i=0, incx=incX;\n   const float *xx= (const float *)X;\n   float ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   float *x=(float *)X, *y=(float *)Y, *st=0, *tx=0;\n   const float *stx = x;\n\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_cgemv(F77_TA, &F77_M, &F77_N, alpha, A, &F77_lda, X, &F77_incX, \n                beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n         \n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         ALPHA[0]=    *( (const float *)  alpha    );\n         ALPHA[1]= -( *( (const float *)  alpha+1) );\n         BETA[0]=     *( (const float *)  beta     );\n         BETA[1]= -(  *( (const float *)  beta+1 ) );\n         TA = 'N';\n         if (M > 0)\n         {\n            n = M << 1;\n            x = malloc(n*sizeof(float));\n            tx = x;\n            if( incX > 0 ) {\n               i = incX << 1 ;\n               tincx = 2;\n               st= x+n;\n            } else { \n               i = incX *(-2);\n               tincx = -2;\n               st = x-2; \n               x +=(n-2); \n            }\n\n            do\n            {\n               *x = *xx;\n               x[1] = -xx[1];\n               x += tincx ;\n               xx += i;\n            }\n            while (x != st);\n            x=tx;\n\n            F77_incX = 1;\n\n            if(incY > 0)\n               tincY = incY; \n            else\n               tincY = -incY; \n\n            y++;\n\n            if (N > 0)\n            {\n               i = tincY << 1;\n               n = i * N ;\n               st = y + n;\n               do {\n                  *y = -(*y);\n                  y += i;\n               } while(y != st); \n               y -= n;\n            }\n            stx = x;\n         }\n         else stx = (const float *)X;\n      }\n      else \n      {\n         cblas_xerbla(2, \"cblas_cgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      if (TransA == CblasConjTrans)\n         F77_cgemv(F77_TA, &F77_N, &F77_M, ALPHA, A, &F77_lda, stx,\n                &F77_incX, BETA, Y, &F77_incY);\n      else\n         F77_cgemv(F77_TA, &F77_N, &F77_M, alpha, A, &F77_lda, x,\n                &F77_incX, beta, Y, &F77_incY);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (x != (const float *)X) free(x);\n         if (N > 0)\n         {\n            do\n            {\n               *y = -(*y);\n               y += i;\n            }\n            while (y != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_cgemv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cgerc.c",
    "content": "/*\n * cblas_cgerc.c\n * The program is a C interface to cgerc.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incy\n   #define F77_lda lda   \n#endif\n\n   CBLAS_INT_TYPE n, i, tincy, incy=incY;\n   float *y=(float *)Y, *yy=(float *)Y, *ty, *st;\n\n\n   if (order == CblasColMajor)\n   {\n      F77_cgerc( &F77_M, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, A, \n                      &F77_lda);\n   }  else if (order == CblasRowMajor)   \n   {\n      if (N > 0)\n      {\n         n = N << 1;\n         y = malloc(n*sizeof(float));\n\n         ty = y;\n         if( incY > 0 ) {\n            i = incY << 1;\n            tincy = 2;\n            st= y+n;\n         } else { \n            i = incY *(-2);\n            tincy = -2;\n            st = y-2; \n            y +=(n-2); \n         }\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += tincy ;\n            yy += i;\n         }\n         while (y != st);\n         y = ty;\n\n         #ifdef F77_INT\n            F77_incY = 1;\n         #else\n            incy = 1;\n         #endif\n      }\n      else y = (float *) Y;\n\n      F77_cgeru( &F77_N, &F77_M, alpha, y, &F77_incY, X, &F77_incX, A, \n                      &F77_lda);\n      if(Y!=y)\n         free(y);\n\n   } else cblas_xerbla(1, \"cblas_cgerc\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cgeru.c",
    "content": "/*\n * cblas_cgeru.c\n * The program is a C interface to cgeru.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda lda\n#endif\n\n\n\n   if (order == CblasColMajor)\n   {\n      F77_cgeru( &F77_M, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, A,\n                      &F77_lda);\n   }\n   else if (order == CblasRowMajor)\n   {\n      F77_cgeru( &F77_N, &F77_M, alpha, Y, &F77_incY, X, &F77_incX, A, \n                      &F77_lda);\n   }\n   else cblas_xerbla(1, \"cblas_cgeru\",\"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chbmv.c",
    "content": "/*\n * cblas_chbmv.c\n * The program is a C interface to chbmv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\n#include <stdio.h>\n#include <stdlib.h>\nvoid cblas_chbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo,const CBLAS_INT_TYPE N,const CBLAS_INT_TYPE K,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const float *xx= (float *)X, *alp= (float *)alpha, *bet = (float *)beta;\n   float ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   float *x=(float *)X, *y=(float *)Y, *st=0, *tx;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chbmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_chbmv(F77_UL, &F77_N, &F77_K, alpha, A, &F77_lda, X,  \n                     &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1 ;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (float *) X; \n\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_chbmv(F77_UL, &F77_N, &F77_K, ALPHA, \n                     A ,&F77_lda, x,&F77_incX, BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_chbmv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor )\n   {\n      if(X!=x)\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n      }\n   }\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chemm.c",
    "content": "/*\n *\n * cblas_chemm.c\n * This program is a C interface to chemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_chemm(const enum CBLAS_ORDER Order, const  enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chemm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_chemm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_chemm(F77_SD, F77_UL, &F77_M, &F77_N, alpha, A, &F77_lda, \n                     B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chemm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_chemm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_chemm(F77_SD, F77_UL, &F77_N, &F77_M, alpha, A,\n                 &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_chemm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chemv.c",
    "content": "/*\n * cblas_chemv.c\n * The program is a C interface to chemv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_chemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n=0, i=0, incx=incX;\n   const float *xx= (float *)X, *alp= (float *)alpha, *bet = (float *)beta;\n   float ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   float *x=(float *)X, *y=(float *)Y, *st=0, *tx;\n\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chemv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_chemv(F77_UL, &F77_N, alpha, A, &F77_lda, X, &F77_incX, \n                beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1 ;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (float *) X;\n\n          \n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chemv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_chemv(F77_UL, &F77_N, ALPHA, A, &F77_lda, x, &F77_incX, \n                BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_chemv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor )\n   {\n      if ( X != x )\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n     }\n   }\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cher.c",
    "content": "/*\n * cblas_cher.c\n * The program is a C interface to cher.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const void *X, const CBLAS_INT_TYPE incX\n                ,void *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n#endif\n   CBLAS_INT_TYPE n, i, tincx, incx=incX;\n   float *x=(float *)X, *xx=(float *)X, *tx, *st;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_cher(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n         tx = x;\n         if( incX > 0 ) {\n            i = incX << 1 ;\n            tincx = 2;\n            st= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            st = x-2; \n            x +=(n-2); \n         }\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n         #ifdef F77_INT\n           F77_incX = 1;\n         #else\n           incx = 1;\n         #endif\n      }\n      else x = (float *) X;\n      F77_cher(F77_UL, &F77_N, &alpha, x, &F77_incX, A, &F77_lda);\n   } else \n   {\n      cblas_xerbla(1, \"cblas_cher\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x) \n      free(x);\n   \n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cher2.c",
    "content": "/*\n * cblas_cher2.c\n * The program is a C interface to cher2.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incy\n#endif\n   CBLAS_INT_TYPE n, i, j, tincx, tincy, incx=incX, incy=incY;\n   float *x=(float *)X, *xx=(float *)X, *y=(float *)Y, \n         *yy=(float *)Y, *tx, *ty, *stx, *sty;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_cher2(F77_UL, &F77_N, alpha, X, &F77_incX, \n                                            Y, &F77_incY, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher2\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n         y = malloc(n*sizeof(float));         \n         tx = x;\n         ty = y;\n         if( incX > 0 ) {\n            i = incX << 1 ;\n            tincx = 2;\n            stx= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            stx = x-2; \n            x +=(n-2); \n         }\n         \n         if( incY > 0 ) {\n            j = incY << 1;\n            tincy = 2;\n            sty= y+n;\n         } else { \n            j = incY *(-2);\n            tincy = -2;\n            sty = y-2; \n            y +=(n-2); \n         }\n\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != stx);\n\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += tincy ;\n            yy += j;\n         }\n         while (y != sty);\n\n         x=tx;\n         y=ty;\n\n         #ifdef F77_INT\n            F77_incX = 1;\n            F77_incY = 1;\n         #else\n            incx = 1;\n            incy = 1;\n         #endif\n      }  else \n      {\n         x = (float *) X;\n         y = (float *) Y;\n      }\n      F77_cher2(F77_UL, &F77_N, alpha, y, &F77_incY, x, \n                                      &F77_incX, A, &F77_lda);\n   } else \n   {\n      cblas_xerbla(1, \"cblas_cher2\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n      free(x);\n   if(Y!=y)\n      free(y);\n\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cher2k.c",
    "content": "/*\n *\n * cblas_cher2k.c\n * This program is a C interface to cher2k.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const float beta,\n                  void *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n   float ALPHA[2]; \n   const float *alp=(float *)alpha;\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cher2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_cher2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      \n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cher2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cher2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      F77_cher2k(F77_UL,F77_TR, &F77_N, &F77_K, ALPHA, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_cher2k\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cherk.c",
    "content": "/*\n *\n * cblas_cherk.c\n * This program is a C interface to cherk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const float alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const float beta, void *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_cherk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cherk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_cherk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                     &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cherk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_cherk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_cherk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                &beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_cherk\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chpmv.c",
    "content": "/*\n * cblas_chpmv.c\n * The program is a C interface of chpmv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_chpmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo,const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *AP,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const float *xx= (float *)X, *alp= (float *)alpha, *bet = (float *)beta;\n   float ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   float *x=(float *)X, *y=(float *)Y, *st=0, *tx;\n\n   if (order == CblasColMajor)\n   { \n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_chpmv(F77_UL, &F77_N, alpha, AP, X,  \n                     &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (float *) X;\n\n\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpmv\",\"Illegal Uplo setting, %d\\n\", Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_chpmv(F77_UL, &F77_N, ALPHA, \n                     AP, x, &F77_incX, BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_chpmv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor ) \n   {\n      if(X!=x)\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n     }\n  }\n\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chpr.c",
    "content": "/*\n * cblas_chpr.c\n * The program is a C interface to chpr.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float alpha, const void *X,\n                const CBLAS_INT_TYPE incX, void *A)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incx\n#endif\n   CBLAS_INT_TYPE n, i, tincx, incx=incX;\n   float *x=(float *)X, *xx=(float *)X, *tx, *st;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_chpr(F77_UL, &F77_N, &alpha, X, &F77_incX, A);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpr\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n         tx = x;\n         if( incX > 0 ) {\n            i = incX << 1;\n            tincx = 2;\n            st= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            st = x-2; \n            x +=(n-2); \n         }\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != st);\n         x=tx;\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n      }\n      else x = (float *) X;\n\n      F77_chpr(F77_UL, &F77_N, &alpha, x, &F77_incX, A);\n\n   } else \n   {\n      cblas_xerbla(1, \"cblas_chpr\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n     free(x);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_chpr2.c",
    "content": "/*\n * cblas_chpr2.c\n * The program is a C interface to chpr2.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                      const CBLAS_INT_TYPE N,const void *alpha, const void *X, \n                      const CBLAS_INT_TYPE incX,const void *Y, const CBLAS_INT_TYPE incY, void *Ap)\n\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N,  F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incx\n   #define F77_incY incy\n#endif\n   CBLAS_INT_TYPE n, i, j, tincx, tincy, incx=incX, incy=incY;\n   float *x=(float *)X, *xx=(float *)X, *y=(float *)Y,\n         *yy=(float *)Y, *tx, *ty, *stx, *sty;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_chpr2(F77_UL, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, Ap);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_chpr2\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(float));\n         y = malloc(n*sizeof(float));\n         tx = x;\n         ty = y;\n         if( incX > 0 ) {\n            i = incX << 1 ;\n            tincx = 2;\n            stx= x+n;\n         } else {\n            i = incX *(-2);\n            tincx = -2;\n            stx = x-2;\n            x +=(n-2);\n         }\n \n         if( incY > 0 ) {\n            j = incY << 1;\n            tincy = 2;\n            sty= y+n;\n         } else {\n            j = incY *(-2);\n            tincy = -2;\n            sty = y-2;\n            y +=(n-2);\n         }\n \n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != stx);\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += tincy ;\n            yy += j;\n         }\n         while (y != sty);\n \n         x=tx;\n         y=ty;\n \n         #ifdef F77_INT\n            F77_incX = 1;\n            F77_incY = 1;\n         #else\n            incx = 1;\n            incy = 1;\n         #endif\n\n      }  else \n      {\n         x = (float *) X;\n         y = (void  *) Y;\n      }\n      F77_chpr2(F77_UL, &F77_N, alpha, y, &F77_incY, x, &F77_incX, Ap);\n   } else \n   {\n      cblas_xerbla(1, \"cblas_chpr2\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n      free(x);\n   if(Y!=y)\n      free(y);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cscal.c",
    "content": "/*\n * cblas_cscal.c\n *\n * The program is a C interface to cscal.f.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cscal( const CBLAS_INT_TYPE N, const void *alpha, void *X, \n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_cscal( &F77_N, alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_csscal.c",
    "content": "/*\n * cblas_csscal.c\n *\n * The program is a C interface to csscal.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_csscal( const CBLAS_INT_TYPE N, const float alpha, void *X,\n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_csscal( &F77_N, &alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_cswap.c",
    "content": "/*\n * cblas_cswap.c\n *\n * The program is a C interface to cswap.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_cswap( const CBLAS_INT_TYPE N, void *X, const CBLAS_INT_TYPE incX, void *Y,\n                       const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_cswap( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_csymm.c",
    "content": "/*\n *\n * cblas_csymm.c\n * This program is a C interface to csymm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_csymm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csymm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_csymm(F77_SD, F77_UL, &F77_M, &F77_N, alpha, A, &F77_lda,\n                      B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_csymm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csymm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_csymm(F77_SD, F77_UL, &F77_N, &F77_M, alpha, A, &F77_lda,\n                     B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_csymm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_csyr2k.c",
    "content": "/*\n *\n * cblas_csyr2k.c\n * This program is a C interface to csyr2k.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                  const void  *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                  void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_csyr2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyr2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_csyr2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                      B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyr2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyr2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_csyr2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_csyr2k\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_csyrk.c",
    "content": "/*\n *\n * cblas_csyrk.c\n * This program is a C interface to csyrk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void *beta, void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_csyrk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyrk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_csyrk(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyrk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_csyrk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_csyrk(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                     beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_csyrk\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctbmv.c",
    "content": "/*\n * cblas_ctbmv.c\n * The program is a C interface to ctbmv.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0, *x=(float *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctbmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            x++;\n            st = x + n;\n            do\n            {\n               *x = -(*x);\n               x+= i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctbsv.c",
    "content": "/*\n * cblas_ctbsv.c\n * The program is a C interface to ctbsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0,*x=(float *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n  \n            x++;\n\n            st=x+n;\n\n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x+= i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctbsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctpmv.c",
    "content": "/*\n * cblas_ctpmv.c\n * The program is a C interface to ctpmv.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *Ap, void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0,*x=(float *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            x++;\n            st = x + n;\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctpmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctpsv.c",
    "content": "/*\n * cblas_ctpsv.c\n * The program is a C interface to ctpsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *Ap, void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0, *x=(float*)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n \n            x++;\n\n            st=x+n;\n\n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctpsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctrmm.c",
    "content": "/*\n *\n * cblas_ctrmm.c\n * This program is a C interface to ctrmm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const  enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight ) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrmm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper ) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrmm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans ) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrmm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else cblas_xerbla(5, \"cblas_ctrmm\", \n                       \"Illegal Diag setting, %d\\n\", Diag);\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, alpha, A, &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight ) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrmm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper ) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrmm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans ) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrmm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ctrmm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, alpha, A, &F77_lda, B, &F77_ldb);\n   } \n   else  cblas_xerbla(1, \"cblas_ctrmm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctrmv.c",
    "content": "/*\n * cblas_ctrmv.c\n * The program is a C interface to ctrmv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0,*x=(float *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            st = x + n;\n            do\n            {\n               x[1] = -x[1];\n               x+= i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n         F77_ctrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               x[1] = -x[1];\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctrmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctrsm.c",
    "content": "/*\n *\n * cblas_ctrsm.c\n * This program is a C interface to ctrsm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ctrsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ctrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, alpha, A,\n                &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ctrsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n\n      F77_ctrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, alpha, A,\n                &F77_lda, B, &F77_ldb);\n   } \n   else cblas_xerbla(1, \"cblas_ctrsm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ctrsv.c",
    "content": "/*\n * cblas_ctrsv.c\n * The program is a C interface to ctrsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *A, const CBLAS_INT_TYPE lda, void  *X,\n                 const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   float *st=0,*x=(float *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ctrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n            x++;\n            st=x+n; \n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ctrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ctrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ctrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ctrsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dasum.c",
    "content": "/*\n * cblas_dasum.c\n *\n * The program is a C interface to dasum.\n * It calls the fortran wrapper before calling dasum.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble cblas_dasum( const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX) \n{\n   double asum;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_dasum_sub( &F77_N, X, &F77_incX, &asum);\n   return asum;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_daxpy.c",
    "content": "/*\n * cblas_daxpy.c\n *\n * The program is a C interface to daxpy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_daxpy( const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                       const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_daxpy( &F77_N, &alpha, X, &F77_incX, Y, &F77_incY);\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_dcopy.c",
    "content": "/*\n * cblas_dcopy.c\n *\n * The program is a C interface to dcopy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dcopy( const CBLAS_INT_TYPE N, const double *X,\n                      const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_dcopy( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ddot.c",
    "content": "/*\n * cblas_ddot.c\n *\n * The program is a C interface to ddot.\n * It calls the fortran wrapper before calling ddot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble cblas_ddot( const CBLAS_INT_TYPE N, const double *X,\n                      const CBLAS_INT_TYPE incX, const double *Y, const CBLAS_INT_TYPE incY)\n{\n   double dot;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_ddot_sub( &F77_N, X, &F77_incX, Y, &F77_incY, &dot);\n   return dot;\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_dgbmv.c",
    "content": "/*\n *\n * cblas_dgbmv.c\n * This program is a C interface to dgbmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double  *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n   F77_INT F77_KL=KL,F77_KU=KU;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_KL KL\n   #define F77_KU KU\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_dgbmv(F77_TA, &F77_M, &F77_N, &F77_KL, &F77_KU, &alpha,  \n                     A, &F77_lda, X, &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_dgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, &alpha, \n                     A ,&F77_lda, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_dgbmv\", \"Illegal Order setting, %d\\n\", order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dgemm.c",
    "content": "/*\n *\n * cblas_dgemm.c\n * This program is a C interface to dgemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const double alpha, const double  *A,\n                 const CBLAS_INT_TYPE lda, const double  *B, const CBLAS_INT_TYPE ldb,\n                 const double beta, double  *C, const CBLAS_INT_TYPE ldc)\n{\n   char TA, TB;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_TB;\n#else\n   #define F77_TA &TA  \n   #define F77_TB &TB  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if(TransA == CblasTrans) TA='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgemm\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if(TransB == CblasTrans) TB='T';\n      else if ( TransB == CblasConjTrans ) TB='C';\n      else if ( TransB == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dgemm\",\"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_dgemm(F77_TA, F77_TB, &F77_M, &F77_N, &F77_K, &alpha, A,\n       &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if(TransA == CblasTrans) TB='T';\n      else if ( TransA == CblasConjTrans ) TB='C';\n      else if ( TransA == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgemm\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if(TransB == CblasTrans) TA='T';\n      else if ( TransB == CblasConjTrans ) TA='C';\n      else if ( TransB == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgemm\",\"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_dgemm(F77_TA, F77_TB, &F77_N, &F77_M, &F77_K, &alpha, B,\n                  &F77_ldb, A, &F77_lda, &beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_dgemm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dgemv.c",
    "content": "/*\n *\n * cblas_dgemv.c\n * This program is a C interface to dgemv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double  *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_dgemv(F77_TA, &F77_M, &F77_N, &alpha, A, &F77_lda, X, &F77_incX, \n                &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_dgemv(F77_TA, &F77_N, &F77_M, &alpha, A, &F77_lda, X,\n                &F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_dgemv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dger.c",
    "content": "/*\n *\n * cblas_dger.c\n * This program is a C interface to dger.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                const double alpha, const double  *X, const CBLAS_INT_TYPE incX,\n                const double  *Y, const CBLAS_INT_TYPE incY, double  *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda lda\n#endif\n\n\n   if (order == CblasColMajor)\n   {\n      F77_dger( &F77_M, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A, \n                      &F77_lda);\n   }\n   else if (order == CblasRowMajor)\n   {\n      F77_dger( &F77_N, &F77_M ,&alpha, Y, &F77_incY, X, &F77_incX, A, \n                      &F77_lda);\n\n   }\n   else cblas_xerbla(1, \"cblas_dger\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dnrm2.c",
    "content": "/*\n * cblas_dnrm2.c\n *\n * The program is a C interface to dnrm2.\n * It calls the fortranwrapper before calling dnrm2.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble cblas_dnrm2( const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX) \n{\n   double nrm2;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_dnrm2_sub( &F77_N, X, &F77_incX, &nrm2);\n   return nrm2;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_drot.c",
    "content": "/*\n * cblas_drot.c\n *\n * The program is a C interface to drot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_drot(const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX,\n   double *Y, const CBLAS_INT_TYPE incY, const double c, const double s)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N \n   #define F77_incX incX \n   #define F77_incY incY \n#endif\n   F77_drot(&F77_N, X, &F77_incX, Y, &F77_incY, &c, &s);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_drotg.c",
    "content": "/*\n * cblas_drotg.c\n *\n * The program is a C interface to drotg.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_drotg(  double *a, double *b, double *c, double *s)\n{\n   F77_drotg(a,b,c,s);    \n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_drotm.c",
    "content": "#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_drotm( const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, double *Y, \n                       const CBLAS_INT_TYPE incY, const double *P)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_drotm( &F77_N, X, &F77_incX, Y, &F77_incY, P);\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_drotmg.c",
    "content": "/*\n * cblas_drotmg.c\n *\n * The program is a C interface to drotmg.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_drotmg( double *d1, double *d2, double *b1, \n                        const double b2, double *p)\n{\n   F77_drotmg(d1,d2,b1,&b2,p);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsbmv.c",
    "content": "/*\n *\n * cblas_dsbmv.c\n * This program is a C interface to dsbmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double  *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsbmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dsbmv(F77_UL, &F77_N, &F77_K, &alpha, A, &F77_lda, X,  \n                     &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dsbmv(F77_UL, &F77_N, &F77_K, &alpha, \n                     A ,&F77_lda, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_dsbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dscal.c",
    "content": "/*\n * cblas_dscal.c\n *\n * The program is a C interface to dscal.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dscal( const CBLAS_INT_TYPE N, const double alpha, double *X, \n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_dscal( &F77_N, &alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsdot.c",
    "content": "/*\n * cblas_dsdot.c\n *\n * The program is a C interface to dsdot.\n * It calls fthe fortran wrapper before calling dsdot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble  cblas_dsdot( const CBLAS_INT_TYPE N, const float *X,\n                      const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY)\n{\n   double dot;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_dsdot_sub( &F77_N, X, &F77_incX, Y, &F77_incY, &dot);\n   return dot;\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_dspmv.c",
    "content": "/*\n *\n * cblas_dspmv.c\n * This program is a C interface to dspmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n \n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dspmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *AP,\n                 const double  *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dspmv(F77_UL, &F77_N, &alpha, AP, X,  \n                     &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dspmv(F77_UL, &F77_N, &alpha, \n                     AP, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_dspmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dspr.c",
    "content": "/*\n *\n * cblas_dspr.c\n * This program is a C interface to dspr.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                const CBLAS_INT_TYPE incX, double *Ap)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_dspr(F77_UL, &F77_N, &alpha, X, &F77_incX, Ap);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_dspr(F77_UL, &F77_N, &alpha, X, &F77_incX, Ap); \n   } else cblas_xerbla(1, \"cblas_dspr\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dspr2.c",
    "content": "/*\n * cblas_dspr2.c\n * The program is a C interface to dspr2.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double  alpha, const double  *X,\n                const CBLAS_INT_TYPE incX, const double  *Y, const CBLAS_INT_TYPE incY, double  *A)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_dspr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dspr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_dspr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY,  A); \n   } else cblas_xerbla(1, \"cblas_dspr2\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dswap.c",
    "content": "/*\n * cblas_dswap.c\n *\n * The program is a C interface to dswap.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dswap( const CBLAS_INT_TYPE N, double *X, const CBLAS_INT_TYPE incX, double *Y,\n                       const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_dswap( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsymm.c",
    "content": "/*\n *\n * cblas_dsymm.c\n * This program is a C interface to dsymm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double  *B, const CBLAS_INT_TYPE ldb, const double beta,\n                 double  *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsymm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsymm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_dsymm(F77_SD, F77_UL, &F77_M, &F77_N, &alpha, A, &F77_lda,\n                      B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsymm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsymm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_dsymm(F77_SD, F77_UL, &F77_N, &F77_M, &alpha, A, &F77_lda, B,\n                 &F77_ldb, &beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_dsymm\",\"Illegal Order setting, %d\\n\", Order); \n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsymv.c",
    "content": "/*\n *\n * cblas_dsymv.c\n * This program is a C interface to dsymv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsymv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double  *X, const CBLAS_INT_TYPE incX, const double beta,\n                 double  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsymv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dsymv(F77_UL, &F77_N, &alpha, A, &F77_lda, X,  \n                     &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsymv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_dsymv(F77_UL, &F77_N, &alpha, \n                     A ,&F77_lda, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_dsymv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsyr.c",
    "content": "/*\n *\n * cblas_dsyr.c\n * This program is a C interface to dsyr.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double  alpha, const double  *X,\n                const CBLAS_INT_TYPE incX, double  *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_lda=lda;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_lda  lda\n#endif\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_dsyr(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_dsyr(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda); \n   } else cblas_xerbla(1, \"cblas_dsyr\", \"Illegal Order setting, %d\\n\", order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsyr2.c",
    "content": "/*\n *\n * cblas_dsyr2.c\n * This program is a C interface to dsyr2.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double  alpha, const double  *X,\n                const CBLAS_INT_TYPE incX, const double  *Y, const CBLAS_INT_TYPE incY, double  *A,\n                const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY, F77_lda=lda;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda  lda\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_dsyr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A, \n                    &F77_lda);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_dsyr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY,  A, \n                    &F77_lda); \n   } else cblas_xerbla(1, \"cblas_dsyr2\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsyr2k.c",
    "content": "/*\n *\n * cblas_dsyr2k.c\n * This program is a C interface to dsyr2k.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                  const double  *B, const CBLAS_INT_TYPE ldb, const double beta,\n                  double  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyr2k\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyr2k\",\"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_dsyr2k(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                      B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyr2k\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyr2k\",\"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_dsyr2k(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda, B, \n                &F77_ldb, &beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_dsyr2k\",\"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dsyrk.c",
    "content": "/*\n *\n * cblas_dsyrk.c\n * This program is a C interface to dsyrk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 const double beta, double  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dsyrk\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyrk\",\"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_dsyrk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyrk\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dsyrk\",\"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_dsyrk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                     &beta, C, &F77_ldc);\n   } \n   else cblas_xerbla(1, \"cblas_dsyrk\",\"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtbmv.c",
    "content": "/*\n * cblas_dtbmv.c\n * The program is a C interface to dtbmv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double  *A, const CBLAS_INT_TYPE lda,\n                 double  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtbmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n\n   }\n   else cblas_xerbla(1, \"cblas_dtbmv\", \"Illegal Order setting, %d\\n\", order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtbsv.c",
    "content": "/*\n * cblas_dtbsv.c\n * The program is a C interface to dtbsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const double  *A, const CBLAS_INT_TYPE lda,\n                 double  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_dtbsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtpmv.c",
    "content": "/*\n * cblas_dtpmv.c\n * The program is a C interface to dtpmv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double  *Ap, double  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_dtpmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtpsv.c",
    "content": "/*\n * cblas_dtpsv.c\n * The program is a C interface to dtpsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double  *Ap, double  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n\n   }\n   else cblas_xerbla(1, \"cblas_dtpsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtrmm.c",
    "content": "/*\n *\n * cblas_dtrmm.c\n * This program is a C interface to dtrmm.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const  enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 double  *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrmm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrmm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrmm\",\"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_dtrmm\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, &alpha, A, &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrmm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrmm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrmm\",\"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_dtrmm\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, &alpha, A, &F77_lda, B, &F77_ldb);\n   } \n   else cblas_xerbla(1, \"cblas_dtrmm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtrmv.c",
    "content": "/*\n *\n * cblas_dtrmv.c\n * This program is a C interface to sgemv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n \n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double  *A, const CBLAS_INT_TYPE lda,\n                 double  *X, const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   } else cblas_xerbla(1, \"cblas_dtrmv\", \"Illegal order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtrsm.c",
    "content": "/*\n *\n * cblas_dtrsm.c\n * This program is a C interface to dtrsm.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const double alpha, const double  *A, const CBLAS_INT_TYPE lda,\n                 double  *B, const CBLAS_INT_TYPE ldb)\n\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if      ( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrsm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if      ( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrsm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if      ( TransA == CblasTrans    ) TA='T';\n      else if ( TransA == CblasConjTrans) TA='C';\n      else if ( TransA == CblasNoTrans  ) TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrsm\",\"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if      ( Diag == CblasUnit   ) DI='U';\n      else if ( Diag == CblasNonUnit) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_dtrsm\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, &alpha,\n                A, &F77_lda, B, &F77_ldb);\n   } \n   else if (Order == CblasRowMajor)\n   {\n      if      ( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrsm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if      ( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrsm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if      ( TransA == CblasTrans    ) TA='T';\n      else if ( TransA == CblasConjTrans) TA='C';\n      else if ( TransA == CblasNoTrans  ) TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrsm\",\"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if      ( Diag == CblasUnit   ) DI='U';\n      else if ( Diag == CblasNonUnit) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_dtrsm\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_dtrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, &alpha, A, \n               &F77_lda, B, &F77_ldb);\n   } \n   else cblas_xerbla(1, \"cblas_dtrsm\",\"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dtrsv.c",
    "content": "/*\n * cblas_dtrsv.c\n * The program is a C interface to dtrsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const double  *A, const CBLAS_INT_TYPE lda, double  *X,\n                 const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_dtrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_dtrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_dtrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_dtrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_dtrsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dzasum.c",
    "content": "/*\n * cblas_dzasum.c\n *\n * The program is a C interface to dzasum.\n * It calls the fortran wrapper before calling dzasum.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble cblas_dzasum( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX) \n{\n   double asum;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_dzasum_sub( &F77_N, X, &F77_incX, &asum);\n   return asum;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_dznrm2.c",
    "content": "/*\n * cblas_dznrm2.c\n *\n * The program is a C interface to dznrm2.\n * It calls the fortran wrapper before calling dznrm2.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\ndouble cblas_dznrm2( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX) \n{\n   double nrm2;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_dznrm2_sub( &F77_N, X, &F77_incX, &nrm2);\n   return nrm2;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_f77.h",
    "content": "/*\n * cblas_f77.h\n * Written by Keita Teranishi\n *\n * Updated by Jeff Horner\n * Merged cblas_f77.h and cblas_fortran_header.h\n */\n\n#ifndef CBLAS_F77_H\n#define CBLAS_f77_H\n\n#ifdef CRAY\n   #include <fortran.h>\n   #define F77_CHAR _fcd\n   #define C2F_CHAR(a) ( _cptofcd( (a), 1 ) )\n   #define C2F_STR(a, i) ( _cptofcd( (a), (i) ) )\n   #define F77_STRLEN(a) (_fcdlen)\n#endif\n\n#ifdef WeirdNEC\n   #define F77_INT long\n#endif\n\n#ifdef  F77_CHAR\n   #define FCHAR F77_CHAR\n#else\n   #define FCHAR char *\n#endif\n\n#ifdef F77_INT\n   #define FINT const F77_INT *\n   #define FINT2 F77_INT *\n#else\n   #define FINT const int *\n   #define FINT2 int *\n#endif\n\n#if defined(ADD_)\n/*\n * Level 1 BLAS\n */\n#define F77_xerbla xerbla_\n   #define F77_srotg      srotg_\n   #define F77_srotmg     srotmg_\n   #define F77_srot       srot_\n   #define F77_srotm      srotm_\n   #define F77_drotg      drotg_\n   #define F77_drotmg     drotmg_\n   #define F77_drot       drot_\n   #define F77_drotm      drotm_\n   #define F77_sswap      sswap_\n   #define F77_scopy      scopy_\n   #define F77_saxpy      saxpy_\n   #define F77_isamax_sub isamaxsub_\n   #define F77_dswap      dswap_\n   #define F77_dcopy      dcopy_\n   #define F77_daxpy      daxpy_\n   #define F77_idamax_sub idamaxsub_\n   #define F77_cswap      cswap_\n   #define F77_ccopy      ccopy_\n   #define F77_caxpy      caxpy_\n   #define F77_icamax_sub icamaxsub_\n   #define F77_zswap      zswap_\n   #define F77_zcopy      zcopy_\n   #define F77_zaxpy      zaxpy_\n   #define F77_izamax_sub izamaxsub_\n   #define F77_sdot_sub   sdotsub_\n   #define F77_ddot_sub   ddotsub_\n   #define F77_dsdot_sub   dsdotsub_\n   #define F77_sscal      sscal_\n   #define F77_dscal      dscal_\n   #define F77_cscal      cscal_\n   #define F77_zscal      zscal_\n   #define F77_csscal      csscal_\n   #define F77_zdscal      zdscal_\n   #define F77_cdotu_sub  cdotusub_\n   #define F77_cdotc_sub  cdotcsub_\n   #define F77_zdotu_sub  zdotusub_\n   #define F77_zdotc_sub  zdotcsub_\n   #define F77_snrm2_sub  snrm2sub_\n   #define F77_sasum_sub  sasumsub_\n   #define F77_dnrm2_sub  dnrm2sub_\n   #define F77_dasum_sub  dasumsub_\n   #define F77_scnrm2_sub  scnrm2sub_\n   #define F77_scasum_sub  scasumsub_\n   #define F77_dznrm2_sub  dznrm2sub_\n   #define F77_dzasum_sub  dzasumsub_\n   #define F77_sdsdot_sub   sdsdotsub_\n/*\n * Level 2 BLAS\n */\n   #define F77_ssymv      ssymv_\n   #define F77_ssbmv      ssbmv_\n   #define F77_sspmv      sspmv_\n   #define F77_sger       sger_\n   #define F77_ssyr       ssyr_\n   #define F77_sspr       sspr_\n   #define F77_ssyr2      ssyr2_\n   #define F77_sspr2      sspr2_\n   #define F77_dsymv      dsymv_\n   #define F77_dsbmv      dsbmv_\n   #define F77_dspmv      dspmv_\n   #define F77_dger       dger_\n   #define F77_dsyr       dsyr_\n   #define F77_dspr       dspr_\n   #define F77_dsyr2      dsyr2_\n   #define F77_dspr2      dspr2_\n   #define F77_chemv      chemv_\n   #define F77_chbmv      chbmv_\n   #define F77_chpmv      chpmv_\n   #define F77_cgeru      cgeru_\n   #define F77_cgerc      cgerc_\n   #define F77_cher       cher_\n   #define F77_chpr       chpr_\n   #define F77_cher2      cher2_\n   #define F77_chpr2      chpr2_\n   #define F77_zhemv      zhemv_\n   #define F77_zhbmv      zhbmv_\n   #define F77_zhpmv      zhpmv_\n   #define F77_zgeru      zgeru_\n   #define F77_zgerc      zgerc_\n   #define F77_zher       zher_\n   #define F77_zhpr       zhpr_\n   #define F77_zher2      zher2_\n   #define F77_zhpr2      zhpr2_\n   #define F77_sgemv      sgemv_\n   #define F77_sgbmv      sgbmv_\n   #define F77_strmv      strmv_\n   #define F77_stbmv      stbmv_\n   #define F77_stpmv      stpmv_\n   #define F77_strsv      strsv_\n   #define F77_stbsv      stbsv_\n   #define F77_stpsv      stpsv_\n   #define F77_dgemv      dgemv_\n   #define F77_dgbmv      dgbmv_\n   #define F77_dtrmv      dtrmv_\n   #define F77_dtbmv      dtbmv_\n   #define F77_dtpmv      dtpmv_\n   #define F77_dtrsv      dtrsv_\n   #define F77_dtbsv      dtbsv_\n   #define F77_dtpsv      dtpsv_\n   #define F77_cgemv      cgemv_\n   #define F77_cgbmv      cgbmv_\n   #define F77_ctrmv      ctrmv_\n   #define F77_ctbmv      ctbmv_\n   #define F77_ctpmv      ctpmv_\n   #define F77_ctrsv      ctrsv_\n   #define F77_ctbsv      ctbsv_\n   #define F77_ctpsv      ctpsv_\n   #define F77_zgemv      zgemv_\n   #define F77_zgbmv      zgbmv_\n   #define F77_ztrmv      ztrmv_\n   #define F77_ztbmv      ztbmv_\n   #define F77_ztpmv      ztpmv_\n   #define F77_ztrsv      ztrsv_\n   #define F77_ztbsv      ztbsv_\n   #define F77_ztpsv      ztpsv_\n/*\n * Level 3 BLAS\n */\n   #define F77_chemm      chemm_\n   #define F77_cherk      cherk_\n   #define F77_cher2k     cher2k_\n   #define F77_zhemm      zhemm_\n   #define F77_zherk      zherk_\n   #define F77_zher2k     zher2k_\n   #define F77_sgemm      sgemm_\n   #define F77_ssymm      ssymm_\n   #define F77_ssyrk      ssyrk_\n   #define F77_ssyr2k     ssyr2k_\n   #define F77_strmm      strmm_\n   #define F77_strsm      strsm_\n   #define F77_dgemm      dgemm_\n   #define F77_dsymm      dsymm_\n   #define F77_dsyrk      dsyrk_\n   #define F77_dsyr2k     dsyr2k_\n   #define F77_dtrmm      dtrmm_\n   #define F77_dtrsm      dtrsm_\n   #define F77_cgemm      cgemm_\n   #define F77_csymm      csymm_\n   #define F77_csyrk      csyrk_\n   #define F77_csyr2k     csyr2k_\n   #define F77_ctrmm      ctrmm_\n   #define F77_ctrsm      ctrsm_\n   #define F77_zgemm      zgemm_\n   #define F77_zsymm      zsymm_\n   #define F77_zsyrk      zsyrk_\n   #define F77_zsyr2k     zsyr2k_\n   #define F77_ztrmm      ztrmm_\n   #define F77_ztrsm      ztrsm_\n#elif defined(UPCASE)\n/*\n * Level 1 BLAS\n */\n#define F77_xerbla  XERBLA\n   #define F77_srotg      SROTG\n   #define F77_srotmg     SROTMG\n   #define F77_srot       SROT\n   #define F77_srotm      SROTM\n   #define F77_drotg      DROTG\n   #define F77_drotmg     DROTMG\n   #define F77_drot       DROT\n   #define F77_drotm      DROTM\n   #define F77_sswap      SSWAP\n   #define F77_scopy      SCOPY\n   #define F77_saxpy      SAXPY\n   #define F77_isamax_sub ISAMAXSUB\n   #define F77_dswap      DSWAP\n   #define F77_dcopy      DCOPY\n   #define F77_daxpy      DAXPY\n   #define F77_idamax_sub IDAMAXSUB\n   #define F77_cswap      CSWAP\n   #define F77_ccopy      CCOPY\n   #define F77_caxpy      CAXPY\n   #define F77_icamax_sub ICAMAXSUB\n   #define F77_zswap      ZSWAP\n   #define F77_zcopy      ZCOPY\n   #define F77_zaxpy      ZAXPY\n   #define F77_izamax_sub IZAMAXSUB\n   #define F77_sdot_sub   SDOTSUB\n   #define F77_ddot_sub   DDOTSUB\n   #define F77_dsdot_sub   DSDOTSUB\n   #define F77_sscal      SSCAL\n   #define F77_dscal      DSCAL\n   #define F77_cscal      CSCAL\n   #define F77_zscal      ZSCAL\n   #define F77_csscal      CSSCAL\n   #define F77_zdscal      ZDSCAL\n   #define F77_cdotu_sub  CDOTUSUB\n   #define F77_cdotc_sub  CDOTCSUB\n   #define F77_zdotu_sub  ZDOTUSUB\n   #define F77_zdotc_sub  ZDOTCSUB\n   #define F77_snrm2_sub  SNRM2SUB\n   #define F77_sasum_sub  SASUMSUB\n   #define F77_dnrm2_sub  DNRM2SUB\n   #define F77_dasum_sub  DASUMSUB\n   #define F77_scnrm2_sub  SCNRM2SUB\n   #define F77_scasum_sub  SCASUMSUB\n   #define F77_dznrm2_sub  DZNRM2SUB\n   #define F77_dzasum_sub  DZASUMSUB\n   #define F77_sdsdot_sub   SDSDOTSUB\n/*\n * Level 2 BLAS\n */\n   #define F77_ssymv      SSYMV\n   #define F77_ssbmv      SSBMV\n   #define F77_sspmv      SSPMV\n   #define F77_sger       SGER\n   #define F77_ssyr       SSYR\n   #define F77_sspr       SSPR\n   #define F77_ssyr2      SSYR2\n   #define F77_sspr2      SSPR2\n   #define F77_dsymv      DSYMV\n   #define F77_dsbmv      DSBMV\n   #define F77_dspmv      DSPMV\n   #define F77_dger       DGER\n   #define F77_dsyr       DSYR\n   #define F77_dspr       DSPR\n   #define F77_dsyr2      DSYR2\n   #define F77_dspr2      DSPR2\n   #define F77_chemv      CHEMV\n   #define F77_chbmv      CHBMV\n   #define F77_chpmv      CHPMV\n   #define F77_cgeru      CGERU\n   #define F77_cgerc      CGERC\n   #define F77_cher       CHER\n   #define F77_chpr       CHPR\n   #define F77_cher2      CHER2\n   #define F77_chpr2      CHPR2\n   #define F77_zhemv      ZHEMV\n   #define F77_zhbmv      ZHBMV\n   #define F77_zhpmv      ZHPMV\n   #define F77_zgeru      ZGERU\n   #define F77_zgerc      ZGERC\n   #define F77_zher       ZHER\n   #define F77_zhpr       ZHPR\n   #define F77_zher2      ZHER2\n   #define F77_zhpr2      ZHPR2\n   #define F77_sgemv      SGEMV\n   #define F77_sgbmv      SGBMV\n   #define F77_strmv      STRMV\n   #define F77_stbmv      STBMV\n   #define F77_stpmv      STPMV\n   #define F77_strsv      STRSV\n   #define F77_stbsv      STBSV\n   #define F77_stpsv      STPSV\n   #define F77_dgemv      DGEMV\n   #define F77_dgbmv      DGBMV\n   #define F77_dtrmv      DTRMV\n   #define F77_dtbmv      DTBMV\n   #define F77_dtpmv      DTPMV\n   #define F77_dtrsv      DTRSV\n   #define F77_dtbsv      DTBSV\n   #define F77_dtpsv      DTPSV\n   #define F77_cgemv      CGEMV\n   #define F77_cgbmv      CGBMV\n   #define F77_ctrmv      CTRMV\n   #define F77_ctbmv      CTBMV\n   #define F77_ctpmv      CTPMV\n   #define F77_ctrsv      CTRSV\n   #define F77_ctbsv      CTBSV\n   #define F77_ctpsv      CTPSV\n   #define F77_zgemv      ZGEMV\n   #define F77_zgbmv      ZGBMV\n   #define F77_ztrmv      ZTRMV\n   #define F77_ztbmv      ZTBMV\n   #define F77_ztpmv      ZTPMV\n   #define F77_ztrsv      ZTRSV\n   #define F77_ztbsv      ZTBSV\n   #define F77_ztpsv      ZTPSV\n/*\n * Level 3 BLAS\n */\n   #define F77_chemm      CHEMM\n   #define F77_cherk      CHERK\n   #define F77_cher2k     CHER2K\n   #define F77_zhemm      ZHEMM\n   #define F77_zherk      ZHERK\n   #define F77_zher2k     ZHER2K\n   #define F77_sgemm      SGEMM\n   #define F77_ssymm      SSYMM\n   #define F77_ssyrk      SSYRK\n   #define F77_ssyr2k     SSYR2K\n   #define F77_strmm      STRMM\n   #define F77_strsm      STRSM\n   #define F77_dgemm      DGEMM\n   #define F77_dsymm      DSYMM\n   #define F77_dsyrk      DSYRK\n   #define F77_dsyr2k     DSYR2K\n   #define F77_dtrmm      DTRMM\n   #define F77_dtrsm      DTRSM\n   #define F77_cgemm      CGEMM\n   #define F77_csymm      CSYMM\n   #define F77_csyrk      CSYRK\n   #define F77_csyr2k     CSYR2K\n   #define F77_ctrmm      CTRMM\n   #define F77_ctrsm      CTRSM\n   #define F77_zgemm      ZGEMM\n   #define F77_zsymm      ZSYMM\n   #define F77_zsyrk      ZSYRK\n   #define F77_zsyr2k     ZSYR2K\n   #define F77_ztrmm      ZTRMM\n   #define F77_ztrsm      ZTRSM\n#elif defined(NOCHANGE)\n/*\n * Level 1 BLAS\n */\n#define F77_xerbla  xerbla\n   #define F77_srotg      srotg\n   #define F77_srotmg     srotmg\n   #define F77_srot       srot\n   #define F77_srotm      srotm\n   #define F77_drotg      drotg\n   #define F77_drotmg     drotmg\n   #define F77_drot       drot\n   #define F77_drotm      drotm\n   #define F77_sswap      sswap\n   #define F77_scopy      scopy\n   #define F77_saxpy      saxpy\n   #define F77_isamax_sub isamaxsub\n   #define F77_dswap      dswap\n   #define F77_dcopy      dcopy\n   #define F77_daxpy      daxpy\n   #define F77_idamax_sub idamaxsub\n   #define F77_cswap      cswap\n   #define F77_ccopy      ccopy\n   #define F77_caxpy      caxpy\n   #define F77_icamax_sub icamaxsub\n   #define F77_zswap      zswap\n   #define F77_zcopy      zcopy\n   #define F77_zaxpy      zaxpy\n   #define F77_izamax_sub izamaxsub\n   #define F77_sdot_sub   sdotsub\n   #define F77_ddot_sub   ddotsub\n   #define F77_dsdot_sub   dsdotsub\n   #define F77_sscal      sscal\n   #define F77_dscal      dscal\n   #define F77_cscal      cscal\n   #define F77_zscal      zscal\n   #define F77_csscal      csscal\n   #define F77_zdscal      zdscal\n   #define F77_cdotu_sub  cdotusub\n   #define F77_cdotc_sub  cdotcsub\n   #define F77_zdotu_sub  zdotusub\n   #define F77_zdotc_sub  zdotcsub\n   #define F77_snrm2_sub  snrm2sub\n   #define F77_sasum_sub  sasumsub\n   #define F77_dnrm2_sub  dnrm2sub\n   #define F77_dasum_sub  dasumsub\n   #define F77_scnrm2_sub  scnrm2sub\n   #define F77_scasum_sub  scasumsub\n   #define F77_dznrm2_sub  dznrm2sub\n   #define F77_dzasum_sub  dzasumsub\n   #define F77_sdsdot_sub   sdsdotsub\n/*\n * Level 2 BLAS\n */\n   #define F77_ssymv      ssymv\n   #define F77_ssbmv      ssbmv\n   #define F77_sspmv      sspmv\n   #define F77_sger       sger\n   #define F77_ssyr       ssyr\n   #define F77_sspr       sspr\n   #define F77_ssyr2      ssyr2\n   #define F77_sspr2      sspr2\n   #define F77_dsymv      dsymv\n   #define F77_dsbmv      dsbmv\n   #define F77_dspmv      dspmv\n   #define F77_dger       dger\n   #define F77_dsyr       dsyr\n   #define F77_dspr       dspr\n   #define F77_dsyr2      dsyr2\n   #define F77_dspr2      dspr2\n   #define F77_chemv      chemv\n   #define F77_chbmv      chbmv\n   #define F77_chpmv      chpmv\n   #define F77_cgeru      cgeru\n   #define F77_cgerc      cgerc\n   #define F77_cher       cher\n   #define F77_chpr       chpr\n   #define F77_cher2      cher2\n   #define F77_chpr2      chpr2\n   #define F77_zhemv      zhemv\n   #define F77_zhbmv      zhbmv\n   #define F77_zhpmv      zhpmv\n   #define F77_zgeru      zgeru\n   #define F77_zgerc      zgerc\n   #define F77_zher       zher\n   #define F77_zhpr       zhpr\n   #define F77_zher2      zher2\n   #define F77_zhpr2      zhpr2\n   #define F77_sgemv      sgemv\n   #define F77_sgbmv      sgbmv\n   #define F77_strmv      strmv\n   #define F77_stbmv      stbmv\n   #define F77_stpmv      stpmv\n   #define F77_strsv      strsv\n   #define F77_stbsv      stbsv\n   #define F77_stpsv      stpsv\n   #define F77_dgemv      dgemv\n   #define F77_dgbmv      dgbmv\n   #define F77_dtrmv      dtrmv\n   #define F77_dtbmv      dtbmv\n   #define F77_dtpmv      dtpmv\n   #define F77_dtrsv      dtrsv\n   #define F77_dtbsv      dtbsv\n   #define F77_dtpsv      dtpsv\n   #define F77_cgemv      cgemv\n   #define F77_cgbmv      cgbmv\n   #define F77_ctrmv      ctrmv\n   #define F77_ctbmv      ctbmv\n   #define F77_ctpmv      ctpmv\n   #define F77_ctrsv      ctrsv\n   #define F77_ctbsv      ctbsv\n   #define F77_ctpsv      ctpsv\n   #define F77_zgemv      zgemv\n   #define F77_zgbmv      zgbmv\n   #define F77_ztrmv      ztrmv\n   #define F77_ztbmv      ztbmv\n   #define F77_ztpmv      ztpmv\n   #define F77_ztrsv      ztrsv\n   #define F77_ztbsv      ztbsv\n   #define F77_ztpsv      ztpsv\n/*\n * Level 3 BLAS\n */\n   #define F77_chemm      chemm\n   #define F77_cherk      cherk\n   #define F77_cher2k     cher2k\n   #define F77_zhemm      zhemm\n   #define F77_zherk      zherk\n   #define F77_zher2k     zher2k\n   #define F77_sgemm      sgemm\n   #define F77_ssymm      ssymm\n   #define F77_ssyrk      ssyrk\n   #define F77_ssyr2k     ssyr2k\n   #define F77_strmm      strmm\n   #define F77_strsm      strsm\n   #define F77_dgemm      dgemm\n   #define F77_dsymm      dsymm\n   #define F77_dsyrk      dsyrk\n   #define F77_dsyr2k     dsyr2k\n   #define F77_dtrmm      dtrmm\n   #define F77_dtrsm      dtrsm\n   #define F77_cgemm      cgemm\n   #define F77_csymm      csymm\n   #define F77_csyrk      csyrk\n   #define F77_csyr2k     csyr2k\n   #define F77_ctrmm      ctrmm\n   #define F77_ctrsm      ctrsm\n   #define F77_zgemm      zgemm\n   #define F77_zsymm      zsymm\n   #define F77_zsyrk      zsyrk\n   #define F77_zsyr2k     zsyr2k\n   #define F77_ztrmm      ztrmm\n   #define F77_ztrsm      ztrsm\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n   void F77_xerbla(FCHAR, void *);\n/*\n * Level 1 Fortran Prototypes\n */\n\n/* Single Precision */\n\n   void F77_srot(FINT, float *, FINT, float *, FINT, const float *, const float *);\n   void F77_srotg(float *,float *,float *,float *);    \n   void F77_srotm( FINT, float *, FINT, float *, FINT, const float *);\n   void F77_srotmg(float *,float *,float *,const float *, float *);\n   void F77_sswap( FINT, float *, FINT, float *, FINT);\n   void F77_scopy( FINT, const float *, FINT, float *, FINT);\n   void F77_saxpy( FINT, const float *, const float *, FINT, float *, FINT);\n   void F77_sdot_sub(FINT, const float *, FINT, const float *, FINT, float *);\n   void F77_sdsdot_sub( FINT, const float *, const float *, FINT, const float *, FINT, float *);\n   void F77_sscal( FINT, const float *, float *, FINT);\n   void F77_snrm2_sub( FINT, const float *, FINT, float *);\n   void F77_sasum_sub( FINT, const float *, FINT, float *);\n   void F77_isamax_sub( FINT, const float * , FINT, FINT2);\n\n/* Double Precision */\n\n   void F77_drot(FINT, double *, FINT, double *, FINT, const double *, const double *);\n   void F77_drotg(double *,double *,double *,double *);    \n   void F77_drotm( FINT, double *, FINT, double *, FINT, const double *);\n   void F77_drotmg(double *,double *,double *,const double *, double *);\n   void F77_dswap( FINT, double *, FINT, double *, FINT);\n   void F77_dcopy( FINT, const double *, FINT, double *, FINT);\n   void F77_daxpy( FINT, const double *, const double *, FINT, double *, FINT);\n   void F77_dswap( FINT, double *, FINT, double *, FINT);\n   void F77_dsdot_sub(FINT, const float *, FINT, const float *, FINT, double *);\n   void F77_ddot_sub( FINT, const double *, FINT, const double *, FINT, double *);\n   void F77_dscal( FINT, const double *, double *, FINT);\n   void F77_dnrm2_sub( FINT, const double *, FINT, double *);\n   void F77_dasum_sub( FINT, const double *, FINT, double *);\n   void F77_idamax_sub( FINT, const double * , FINT, FINT2);\n\n/* Single Complex Precision */\n\n   void F77_cswap( FINT, void *, FINT, void *, FINT);\n   void F77_ccopy( FINT, const void *, FINT, void *, FINT);\n   void F77_caxpy( FINT, const void *, const void *, FINT, void *, FINT);\n   void F77_cswap( FINT, void *, FINT, void *, FINT);\n   void F77_cdotc_sub( FINT, const void *, FINT, const void *, FINT, void *);\n   void F77_cdotu_sub( FINT, const void *, FINT, const void *, FINT, void *);\n   void F77_cscal( FINT, const void *, void *, FINT);\n   void F77_icamax_sub( FINT, const void *, FINT, FINT2);\n   void F77_csscal( FINT, const float *, void *, FINT);\n   void F77_scnrm2_sub( FINT, const void *, FINT, float *);\n   void F77_scasum_sub( FINT, const void *, FINT, float *);\n\n/* Double Complex Precision */\n\n   void F77_zswap( FINT, void *, FINT, void *, FINT);\n   void F77_zcopy( FINT, const void *, FINT, void *, FINT);\n   void F77_zaxpy( FINT, const void *, const void *, FINT, void *, FINT);\n   void F77_zswap( FINT, void *, FINT, void *, FINT);\n   void F77_zdotc_sub( FINT, const void *, FINT, const void *, FINT, void *);\n   void F77_zdotu_sub( FINT, const void *, FINT, const void *, FINT, void *);\n   void F77_zdscal( FINT, const double *, void *, FINT);\n   void F77_zscal( FINT, const void *, void *, FINT);\n   void F77_dznrm2_sub( FINT, const void *, FINT, double *);\n   void F77_dzasum_sub( FINT, const void *, FINT, double *);\n   void F77_izamax_sub( FINT, const void *, FINT, FINT2);\n\n/*\n * Level 2 Fortran Prototypes\n */\n\n/* Single Precision */\n\n   void F77_sgemv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_sgbmv(FCHAR, FINT, FINT, FINT, FINT, const float *,  const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_ssymv(FCHAR, FINT, const float *, const float *, FINT, const float *,  FINT, const float *, float *, FINT);\n   void F77_ssbmv(FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_sspmv(FCHAR, FINT, const float *, const float *, const float *, FINT, const float *, float *, FINT);\n   void F77_strmv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT);\n   void F77_stbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT);\n   void F77_strsv( FCHAR, FCHAR, FCHAR, FINT, const float *, FINT, float *, FINT);\n   void F77_stbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, FINT, float *, FINT);\n   void F77_stpmv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT);\n   void F77_stpsv( FCHAR, FCHAR, FCHAR, FINT, const float *, float *, FINT);\n   void F77_sger( FINT, FINT, const float *, const float *, FINT, const float *, FINT, float *, FINT);\n   void F77_ssyr(FCHAR, FINT, const float *, const float *, FINT, float *, FINT);\n   void F77_sspr(FCHAR, FINT, const float *, const float *, FINT, float *); \n   void F77_sspr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT,  float *); \n   void F77_ssyr2(FCHAR, FINT, const float *, const float *, FINT, const float *, FINT,  float *, FINT);\n\n/* Double Precision */\n\n   void F77_dgemv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dgbmv(FCHAR, FINT, FINT, FINT, FINT, const double *,  const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dsymv(FCHAR, FINT, const double *, const double *, FINT, const double *,  FINT, const double *, double *, FINT);\n   void F77_dsbmv(FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dspmv(FCHAR, FINT, const double *, const double *, const double *, FINT, const double *, double *, FINT);\n   void F77_dtrmv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT);\n   void F77_dtbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT);\n   void F77_dtrsv( FCHAR, FCHAR, FCHAR, FINT, const double *, FINT, double *, FINT);\n   void F77_dtbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, FINT, double *, FINT);\n   void F77_dtpmv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT);\n   void F77_dtpsv( FCHAR, FCHAR, FCHAR, FINT, const double *, double *, FINT);\n   void F77_dger( FINT, FINT, const double *, const double *, FINT, const double *, FINT, double *, FINT);\n   void F77_dsyr(FCHAR, FINT, const double *, const double *, FINT, double *, FINT);\n   void F77_dspr(FCHAR, FINT, const double *, const double *, FINT, double *); \n   void F77_dspr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT,  double *); \n   void F77_dsyr2(FCHAR, FINT, const double *, const double *, FINT, const double *, FINT,  double *, FINT);\n\n/* Single Complex Precision */\n\n   void F77_cgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_cgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *,  const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_chemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_chbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_chpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT);\n   void F77_ctrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);\n   void F77_ctbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);\n   void F77_ctpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT);\n   void F77_ctrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);\n   void F77_ctbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);\n   void F77_ctpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT);\n   void F77_cgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);\n   void F77_cgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *,  FINT);\n   void F77_cher(FCHAR, FINT, const float *, const void *, FINT, void *, FINT);\n   void F77_cher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);\n   void F77_chpr(FCHAR, FINT, const float *, const void *, FINT, void *);\n   void F77_chpr2(FCHAR, FINT, const float *, const void *, FINT, const void *, FINT, void *);\n\n/* Double Complex Precision */\n\n   void F77_zgemv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_zgbmv(FCHAR, FINT, FINT, FINT, FINT, const void *,  const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_zhemv(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_zhbmv(FCHAR, FINT, FINT, const void *, const void *, FINT, const void *, FINT, const void *, void *, FINT);\n   void F77_zhpmv(FCHAR, FINT, const void *, const void *, const void *, FINT, const void *, void *, FINT);\n   void F77_ztrmv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);\n   void F77_ztbmv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);\n   void F77_ztpmv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *, FINT);\n   void F77_ztrsv( FCHAR, FCHAR, FCHAR, FINT, const void *, FINT, void *, FINT);\n   void F77_ztbsv( FCHAR, FCHAR, FCHAR, FINT, FINT, const void *, FINT, void *, FINT);\n   void F77_ztpsv( FCHAR, FCHAR, FCHAR, FINT, const void *, void *,FINT);\n   void F77_zgerc( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);\n   void F77_zgeru( FINT, FINT, const void *, const void *, FINT, const void *, FINT, void *,  FINT);\n   void F77_zher(FCHAR, FINT, const double *, const void *, FINT, void *, FINT);\n   void F77_zher2(FCHAR, FINT, const void *, const void *, FINT, const void *, FINT, void *, FINT);\n   void F77_zhpr(FCHAR, FINT, const double *, const void *, FINT, void *);\n   void F77_zhpr2(FCHAR, FINT, const double *, const void *, FINT, const void *, FINT, void *);\n\n/*\n * Level 3 Fortran Prototypes\n */\n\n/* Single Precision */\n\n   void F77_sgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_ssymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_ssyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);\n   void F77_ssyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_strmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);\n   void F77_strsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);\n\n/* Double Precision */\n\n   void F77_dgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);\n   void F77_dsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_dtrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);\n   void F77_dtrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);\n\n/* Single Complex Precision */\n\n   void F77_cgemm(FCHAR, FCHAR, FINT, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_csymm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_chemm(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_csyrk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);\n   void F77_cherk(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, float *, FINT);\n   void F77_csyr2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_cher2k(FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, const float *, FINT, const float *, float *, FINT);\n   void F77_ctrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);\n   void F77_ctrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const float *, const float *, FINT, float *, FINT);\n\n/* Double Complex Precision */\n\n   void F77_zgemm(FCHAR, FCHAR, FINT, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_zsymm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_zhemm(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_zsyrk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);\n   void F77_zherk(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, double *, FINT);\n   void F77_zsyr2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_zher2k(FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, const double *, FINT, const double *, double *, FINT);\n   void F77_ztrmm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);\n   void F77_ztrsm(FCHAR, FCHAR, FCHAR, FCHAR, FINT, FINT, const double *, const double *, FINT, double *, FINT);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*  CBLAS_F77_H */\n"
  },
  {
    "path": "dlib/external/cblas/cblas_icamax.c",
    "content": "/*\n * cblas_icamax.c\n *\n * The program is a C interface to icamax.\n * It calls the fortran wrapper before calling icamax.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nCBLAS_INDEX cblas_icamax( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX)\n{\n   F77_INT iamax;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_icamax_sub( &F77_N, X, &F77_incX, &iamax);\n   return iamax ? iamax-1 : 0;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_idamax.c",
    "content": "/*\n * cblas_idamax.c\n *\n * The program is a C interface to idamax.\n * It calls the fortran wrapper before calling idamax.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nCBLAS_INDEX cblas_idamax( const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX)\n{\n   F77_INT iamax;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_idamax_sub( &F77_N, X, &F77_incX, &iamax);\n   return iamax ? iamax-1 : 0;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_isamax.c",
    "content": "/*\n * cblas_isamax.c\n *\n * The program is a C interface to isamax.\n * It calls the fortran wrapper before calling isamax.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nCBLAS_INDEX cblas_isamax( const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX)\n{\n   F77_INT iamax;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_isamax_sub( &F77_N, X, &F77_incX, &iamax);\n   return iamax ? iamax-1 : 0;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_izamax.c",
    "content": "/*\n * cblas_izamax.c\n *\n * The program is a C interface to izamax.\n * It calls the fortran wrapper before calling izamax.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nCBLAS_INDEX cblas_izamax( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX)\n{\n   F77_INT iamax;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_izamax_sub( &F77_N, X, &F77_incX, &iamax);\n   return (iamax ? iamax-1 : 0);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sasum.c",
    "content": "/*\n * cblas_sasum.c\n *\n * The program is a C interface to sasum.\n * It calls the fortran wrapper before calling sasum.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_sasum( const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX) \n{\n   float asum;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_sasum_sub( &F77_N, X, &F77_incX, &asum);\n   return asum;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_saxpy.c",
    "content": "/*\n * cblas_saxpy.c\n *\n * The program is a C interface to saxpy.\n * It calls the fortran wrapper before calling saxpy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_saxpy( const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                       const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_saxpy( &F77_N, &alpha, X, &F77_incX, Y, &F77_incY);\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_scasum.c",
    "content": "/*\n * cblas_scasum.c\n *\n * The program is a C interface to scasum.\n * It calls the fortran wrapper before calling scasum.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_scasum( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX) \n{\n   float asum;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_scasum_sub( &F77_N, X, &F77_incX, &asum);\n   return asum;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_scnrm2.c",
    "content": "/*\n * cblas_scnrm2.c\n *\n * The program is a C interface to scnrm2.\n * It calls the fortran wrapper before calling scnrm2.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_scnrm2( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX) \n{\n   float nrm2;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_scnrm2_sub( &F77_N, X, &F77_incX, &nrm2);\n   return nrm2;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_scopy.c",
    "content": "/*\n * cblas_scopy.c\n *\n * The program is a C interface to scopy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_scopy( const CBLAS_INT_TYPE N, const float *X,\n                      const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_scopy( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sdot.c",
    "content": "/*\n * cblas_sdot.c\n *\n * The program is a C interface to sdot.\n * It calls the fortran wrapper before calling sdot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_sdot( const CBLAS_INT_TYPE N, const float *X,\n                      const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY)\n{\n   float dot;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_sdot_sub( &F77_N, X, &F77_incX, Y, &F77_incY, &dot);\n   return dot;\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_sdsdot.c",
    "content": "/*\n * cblas_sdsdot.c\n *\n * The program is a C interface to sdsdot.\n * It calls the fortran wrapper before calling sdsdot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_sdsdot( const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                      const CBLAS_INT_TYPE incX, const float *Y, const CBLAS_INT_TYPE incY)\n{\n   float dot;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_sdsdot_sub( &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, &dot);\n   return dot;\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_sgbmv.c",
    "content": "/*\n *\n * cblas_sgbmv.c\n * This program is a C interface to sgbmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 const float  *X, const CBLAS_INT_TYPE incX, const float beta,\n                 float  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n   F77_INT F77_KL=KL,F77_KU=KU;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_KL KL\n   #define F77_KU KU\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_sgbmv(F77_TA, &F77_M, &F77_N, &F77_KL, &F77_KU, &alpha,  \n                     A, &F77_lda, X, &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_sgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, &alpha, \n                     A ,&F77_lda, X, &F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_sgbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sgemm.c",
    "content": "/*\n *\n * cblas_sgemm.c\n * This program is a C interface to sgemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const float alpha, const float  *A,\n                 const CBLAS_INT_TYPE lda, const float  *B, const CBLAS_INT_TYPE ldb,\n                 const float beta, float  *C, const CBLAS_INT_TYPE ldc)\n{\n   char TA, TB;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_TB;\n#else\n   #define F77_TA &TA  \n   #define F77_TB &TB  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n   \n   if( Order == CblasColMajor )\n   {\n      if(TransA == CblasTrans) TA='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgemm\", \n                       \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if(TransB == CblasTrans) TB='T';\n      else if ( TransB == CblasConjTrans ) TB='C';\n      else if ( TransB == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_sgemm\", \n                       \"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_sgemm(F77_TA, F77_TB, &F77_M, &F77_N, &F77_K, &alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if(TransA == CblasTrans) TB='T';\n      else if ( TransA == CblasConjTrans ) TB='C';\n      else if ( TransA == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgemm\", \n                       \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if(TransB == CblasTrans) TA='T';\n      else if ( TransB == CblasConjTrans ) TA='C';\n      else if ( TransB == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgemm\", \n                       \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_sgemm(F77_TA, F77_TB, &F77_N, &F77_M, &F77_K, &alpha, B, &F77_ldb, A, &F77_lda, &beta, C, &F77_ldc);\n   } else  \n     cblas_xerbla(1, \"cblas_sgemm\",\n                     \"Illegal Order setting, %d\\n\", Order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sgemv.c",
    "content": "/*\n *\n * cblas_sgemv.c\n * This program is a C interface to sgemv.\n * Written by Keita Teranishi\n * 4/6/1998\n * \n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                 const float  *X, const CBLAS_INT_TYPE incX, const float beta,\n                 float  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_sgemv(F77_TA, &F77_M, &F77_N, &alpha, A, &F77_lda, X, &F77_incX, \n                &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sgemv\", \"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_sgemv(F77_TA, &F77_N, &F77_M, &alpha, A, &F77_lda, X,\n                &F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_sgemv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sger.c",
    "content": "/*\n *\n * cblas_sger.c\n * This program is a C interface to sger.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sger(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                const float  alpha, const float  *X, const CBLAS_INT_TYPE incX,\n                const float  *Y, const CBLAS_INT_TYPE incY, float  *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda lda\n#endif\n\n\n   if (order == CblasColMajor)\n   {\n      F77_sger( &F77_M, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A,\n       &F77_lda);\n   }\n   else if (order == CblasRowMajor)\n   {\n      F77_sger( &F77_N, &F77_M, &alpha, Y, &F77_incY, X, &F77_incX, A, \n        &F77_lda);\n   }\n   else cblas_xerbla(1, \"cblas_sger\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_snrm2.c",
    "content": "/*\n * cblas_snrm2.c\n *\n * The program is a C interface to snrm2.\n * It calls the fortran wrapper before calling snrm2.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nfloat cblas_snrm2( const CBLAS_INT_TYPE N, const float *X, const CBLAS_INT_TYPE incX) \n{\n   float nrm2;\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_snrm2_sub( &F77_N, X, &F77_incX, &nrm2);\n   return nrm2;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_srot.c",
    "content": "/*\n * cblas_srot.c\n *\n * The program is a C interface to srot.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_srot( const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, float *Y, \n                      const CBLAS_INT_TYPE incY, const float  c, const float  s)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_srot(&F77_N, X, &F77_incX, Y, &F77_incY, &c, &s);\n}  \n"
  },
  {
    "path": "dlib/external/cblas/cblas_srotg.c",
    "content": "/*\n * cblas_srotg.c\n *\n * The program is a C interface to srotg.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_srotg(  float *a, float *b, float *c, float *s)\n{\n   F77_srotg(a,b,c,s);    \n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_srotm.c",
    "content": "/*\n * cblas_srotm.c\n *\n * The program is a C interface to srotm.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_srotm( const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, float *Y, \n                       const CBLAS_INT_TYPE incY, const float *P)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_srotm( &F77_N, X, &F77_incX, Y, &F77_incY, P);\n}   \n"
  },
  {
    "path": "dlib/external/cblas/cblas_srotmg.c",
    "content": "/*\n * cblas_srotmg.c\n *\n * The program is a C interface to srotmg.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_srotmg( float *d1, float *d2, float *b1, \n                        const float b2, float *p)\n{\n   F77_srotmg(d1,d2,b1,&b2,p);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssbmv.c",
    "content": "/*\n *\n * cblas_ssbmv.c\n * This program is a C interface to ssbmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n           const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float alpha, const float *A,\n           const CBLAS_INT_TYPE lda, const float *X, const CBLAS_INT_TYPE incX,\n           const float beta, float *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n   \n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssbmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_ssbmv(F77_UL, &F77_N, &F77_K, &alpha, A, &F77_lda, X,\n      &F77_incX, &beta, Y, &F77_incY);\n   }else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_ssbmv(F77_UL, &F77_N, &F77_K, &alpha, A, &F77_lda, X,\n      &F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_ssbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sscal.c",
    "content": "/*\n * cblas_sscal.c\n *\n * The program is a C interface to sscal.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sscal( const CBLAS_INT_TYPE N, const float alpha, float *X, \n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_sscal( &F77_N, &alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sspmv.c",
    "content": "/*\n *\n * cblas_sspmv.c\n * This program is a C interface to sspmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sspmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const float alpha, const float  *AP,\n                 const float  *X, const CBLAS_INT_TYPE incX, const float beta,\n                 float  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_sspmv(F77_UL, &F77_N, &alpha, AP, X,  \n                     &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_sspmv(F77_UL, &F77_N, &alpha, \n                     AP, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_sspmv\", \"Illegal Order setting, %d\\n\", order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sspr.c",
    "content": "/*\n *\n * cblas_sspr.c\n * This program is a C interface to sspr.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const  float alpha, const float *X,\n                const CBLAS_INT_TYPE incX, float *Ap)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_sspr(F77_UL, &F77_N, &alpha, X, &F77_incX, Ap);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_sspr(F77_UL, &F77_N, &alpha, X, &F77_incX, Ap); \n   } else cblas_xerbla(1, \"cblas_sspr\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sspr2.c",
    "content": "/*\n *\n * cblas_sspr2.c\n * This program is a C interface to sspr2.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float  alpha, const float  *X,\n                const CBLAS_INT_TYPE incX, const float  *Y, const CBLAS_INT_TYPE incY, float  *A)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_sspr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_sspr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_sspr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY,  A); \n   } else cblas_xerbla(1, \"cblas_sspr2\", \"Illegal Order setting, %d\\n\", order);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_sswap.c",
    "content": "/*\n * cblas_sswap.c\n *\n * The program is a C interface to sswap.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_sswap( const CBLAS_INT_TYPE N, float *X, const CBLAS_INT_TYPE incX, float *Y,\n                       const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_sswap( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssymm.c",
    "content": "/*\n *\n * cblas_ssymm.c\n * This program is a C interface to ssymm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                 const float  *B, const CBLAS_INT_TYPE ldb, const float beta,\n                 float  *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssymm\", \n                       \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssymm\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_ssymm(F77_SD, F77_UL, &F77_M, &F77_N, &alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssymm\", \n                       \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssymm\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_ssymm(F77_SD, F77_UL, &F77_N, &F77_M, &alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else  cblas_xerbla(1, \"cblas_ssymm\",\n                     \"Illegal Order setting, %d\\n\", Order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssymv.c",
    "content": "/*\n *\n * cblas_ssymv.c\n * This program is a C interface to ssymv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssymv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                 const float  *X, const CBLAS_INT_TYPE incX, const float beta,\n                 float  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssymv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_ssymv(F77_UL, &F77_N, &alpha, A, &F77_lda, X,  \n                     &F77_incX, &beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssymv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_ssymv(F77_UL, &F77_N, &alpha, \n                     A ,&F77_lda, X,&F77_incX, &beta, Y, &F77_incY);\n   }\n   else cblas_xerbla(1, \"cblas_ssymv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssyr.c",
    "content": "/*\n *\n * cblas_ssyr.c\n * This program is a C interface to ssyr.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float  alpha, const float  *X,\n                const CBLAS_INT_TYPE incX, float  *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_lda=lda;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_lda  lda\n#endif\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_ssyr(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_ssyr(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda); \n   } else cblas_xerbla(1, \"cblas_ssyr\", \"Illegal Order setting, %d\\n\", order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssyr2.c",
    "content": "/*\n *\n * cblas_ssyr2.c\n * This program is a C interface to ssyr2.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const float  alpha, const float  *X,\n                const CBLAS_INT_TYPE incX, const float  *Y, const CBLAS_INT_TYPE incY, float  *A,\n                const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY, F77_lda=lda;\n#else\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda  lda\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_ssyr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY, A, \n                    &F77_lda);\n\n   }  else if (order == CblasRowMajor) \n   {\n      if (Uplo == CblasLower) UL = 'U';\n      else if (Uplo == CblasUpper) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif  \n      F77_ssyr2(F77_UL, &F77_N, &alpha, X, &F77_incX, Y, &F77_incY,  A, \n                    &F77_lda); \n   } else cblas_xerbla(1, \"cblas_ssyr2\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssyr2k.c",
    "content": "/*\n *\n * cblas_ssyr2k.c\n * This program is a C interface to ssyr2k.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                  const float  *B, const CBLAS_INT_TYPE ldb, const float beta,\n                  float  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyr2k\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyr2k\", \n                       \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_ssyr2k(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyr2k\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyr2k\", \n                       \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_ssyr2k(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else  cblas_xerbla(1, \"cblas_ssyr2k\",\n                     \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ssyrk.c",
    "content": "/*\n *\n * cblas_ssyrk.c\n * This program is a C interface to ssyrk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                 const float beta, float  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ssyrk\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyrk\", \n                       \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_ssyrk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyrk\", \n                       \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ssyrk\", \n                       \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_ssyrk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda, &beta, C, &F77_ldc);\n   } else  cblas_xerbla(1, \"cblas_ssyrk\",\n                     \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n\n"
  },
  {
    "path": "dlib/external/cblas/cblas_stbmv.c",
    "content": "/*\n * cblas_stbmv.c       \n * This program is a C interface to stbmv.\n * Written by Keita Teranishi\n * 3/3/1998\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\n\nvoid cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float  *A, const CBLAS_INT_TYPE lda,\n                 float  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stbmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_stbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_stbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_stbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_stbsv.c",
    "content": "/*\n * cblas_stbsv.c\n * The program is a C interface to stbsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const float  *A, const CBLAS_INT_TYPE lda,\n                 float  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL  = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_stbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_stbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_stbsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_stpmv.c",
    "content": "/*\n *\n * cblas_stpmv.c\n * This program is a C interface to stpmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float  *Ap, float  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_stpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_stpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_stpmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_stpsv.c",
    "content": "/*\n * cblas_stpsv.c\n * The program is a C interface to stpsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float  *Ap, float  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_stpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_stpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_stpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_stpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_stpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n\n   }\n   else cblas_xerbla(1, \"cblas_stpsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_strmm.c",
    "content": "/*\n *\n * cblas_strmm.c\n * This program is a C interface to strmm.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const  enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                 float *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strmm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strmm\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strmm\",\"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_strmm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_strmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, &alpha, A, &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strmm\",\"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strmm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strmm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_strmm\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n#ifdef F77_CHAR\n    F77_UL = C2F_CHAR(&UL);\n    F77_TA = C2F_CHAR(&TA);\n    F77_SD = C2F_CHAR(&SD);\n    F77_DI = C2F_CHAR(&DI);\n#endif\n      F77_strmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, &alpha, A,\n      &F77_lda, B, &F77_ldb);\n   } \n   else  cblas_xerbla(1, \"cblas_strmm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_strmv.c",
    "content": "/*\n *\n * cblas_strmv.c\n * This program is a C interface to strmv.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float  *A, const CBLAS_INT_TYPE lda,\n                 float  *X, const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_strmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_strmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_strmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_strsm.c",
    "content": "/*\n *\n * cblas_strsm.c\n * This program is a C interface to strsm.\n * Written by Keita Teranishi\n * 4/6/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const float alpha, const float  *A, const CBLAS_INT_TYPE lda,\n                 float  *B, const CBLAS_INT_TYPE ldb)\n\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_strsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_strsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, &alpha, A, &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_strsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_strsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, &alpha, A, &F77_lda, B, &F77_ldb);\n   } \n   else  cblas_xerbla(1, \"cblas_strsm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_strsv.c",
    "content": "/*\n * cblas_strsv.c\n * The program is a C interface to strsv.\n *\n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const float  *A, const CBLAS_INT_TYPE lda, float  *X,\n                 const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_strsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_strsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans) TA = 'N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_strsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_strsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_strsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else cblas_xerbla(1, \"cblas_strsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_xerbla.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdarg.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\n\nvoid cblas_xerbla(int info, const char *rout, const char *form, ...)\n{\n   char empty[1] = \"\";\n   va_list argptr;\n\n   va_start(argptr, form);\n\n   {\n      if (strstr(rout,\"gemm\") != 0)\n      {\n         if      (info == 5 ) info =  4;\n         else if (info == 4 ) info =  5;\n         else if (info == 11) info =  9;\n         else if (info == 9 ) info = 11;\n      }\n      else if (strstr(rout,\"symm\") != 0 || strstr(rout,\"hemm\") != 0)\n      {\n         if      (info == 5 ) info =  4;\n         else if (info == 4 ) info =  5;\n      }\n      else if (strstr(rout,\"trmm\") != 0 || strstr(rout,\"trsm\") != 0)\n      {\n         if      (info == 7 ) info =  6;\n         else if (info == 6 ) info =  7;\n      }\n      else if (strstr(rout,\"gemv\") != 0)\n      {\n         if      (info == 4)  info = 3;\n         else if (info == 3)  info = 4;\n      }\n      else if (strstr(rout,\"gbmv\") != 0)\n      {\n         if      (info == 4)  info = 3;\n         else if (info == 3)  info = 4;\n         else if (info == 6)  info = 5;\n         else if (info == 5)  info = 6;\n      }\n      else if (strstr(rout,\"ger\") != 0)\n      {\n         if      (info == 3) info = 2;\n         else if (info == 2) info = 3;\n         else if (info == 8) info = 6;\n         else if (info == 6) info = 8;\n      }\n      else if ( (strstr(rout,\"her2\") != 0 || strstr(rout,\"hpr2\") != 0)\n                 && strstr(rout,\"her2k\") == 0 )\n      {\n         if      (info == 8) info = 6;\n         else if (info == 6) info = 8;\n      }\n   }\n   if (info)\n      fprintf(stderr, \"Parameter %d to routine %s was incorrect\\n\", info, rout);\n   vfprintf(stderr, form, argptr);\n   va_end(argptr);\n   if (info && !info) \n      F77_xerbla(empty, &info); /* Force link of our F77 error handler */\n   exit(-1);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zaxpy.c",
    "content": "/*\n * cblas_zaxpy.c\n *\n * The program is a C interface to zaxpy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zaxpy( const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                       const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_zaxpy( &F77_N, alpha, X, &F77_incX, Y, &F77_incY);\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_zcopy.c",
    "content": "/*\n * cblas_zcopy.c\n *\n * The program is a C interface to zcopy.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zcopy( const CBLAS_INT_TYPE N, const void *X,\n                      const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_zcopy( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zdotc_sub.c",
    "content": "/*\n * cblas_zdotc_sub.c\n *\n * The program is a C interface to zdotc.\n * It calls the fortran wrapper before calling zdotc.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zdotc_sub( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                    const void *Y, const CBLAS_INT_TYPE incY, void *dotc)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_zdotc_sub( &F77_N, X, &F77_incX, Y, &F77_incY, dotc);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zdotu_sub.c",
    "content": "/*\n * cblas_zdotu_sub.c\n *\n * The program is a C interface to zdotu.\n * It calls the fortran wrapper before calling zdotu.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zdotu_sub( const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                      const void *Y, const CBLAS_INT_TYPE incY, void *dotu)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_zdotu_sub( &F77_N, X, &F77_incX, Y, &F77_incY, dotu);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zdscal.c",
    "content": "/*\n * cblas_zdscal.c\n *\n * The program is a C interface to zdscal.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zdscal( const CBLAS_INT_TYPE N, const double alpha, void  *X,\n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_zdscal( &F77_N, &alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zgbmv.c",
    "content": "/*\n * cblas_zgbmv.c\n * The program is a C interface of zgbmv\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zgbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE KL, const CBLAS_INT_TYPE KU,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n   F77_INT F77_KL=KL,F77_KU=KU;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_KL KL\n   #define F77_KU KU\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const double *xx= (double *)X, *alp= (double *)alpha, *bet = (double *)beta;\n   double ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   double *x=(double *)X, *y=(double *)Y, *st=0, *tx;\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_zgbmv(F77_TA, &F77_M, &F77_N, &F77_KL, &F77_KU, alpha,  \n                     A, &F77_lda, X, &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         ALPHA[0]= *alp;\n         ALPHA[1]= -alp[1];\n         BETA[0]= *bet;\n         BETA[1]= -bet[1];\n         TA = 'N';\n         if (M > 0)\n         {\n            n = M << 1;\n            x = malloc(n*sizeof(double));\n            tx = x;\n\n            if( incX > 0 ) {\n               i = incX << 1 ;\n               tincx = 2;\n               st= x+n;\n            } else {\n               i = incX *(-2);\n               tincx = -2;\n               st = x-2;\n               x +=(n-2);\n            }\n            do\n            {\n               *x = *xx;\n               x[1] = -xx[1];\n               x += tincx ;\n               xx += i;\n            }\n            while (x != st);\n            x=tx;\n\n            #ifdef F77_INT\n               F77_incX = 1;\n            #else\n               incx = 1;\n            #endif\n\n            if( incY > 0 )\n              tincY = incY;\n            else\n              tincY = -incY;\n\n            y++;\n \n            if (N > 0)\n            {\n               i = tincY << 1;\n               n = i * N ;\n               st = y + n;\n               do {\n                  *y = -(*y);\n                  y += i;\n               } while(y != st);\n               y -= n;\n            }\n         }\n         else x = (double *) X;\n\n \n      }\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      if (TransA == CblasConjTrans)\n         F77_zgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, ALPHA, \n                        A ,&F77_lda, x,&F77_incX, BETA, Y, &F77_incY);\n      else\n         F77_zgbmv(F77_TA, &F77_N, &F77_M, &F77_KU, &F77_KL, alpha, \n                        A ,&F77_lda, x,&F77_incX, beta, Y, &F77_incY);\n      if (TransA == CblasConjTrans)\n      {\n         if (x != X) free(x);\n         if (N > 0)\n         {\n            do\n            {\n               *y = -(*y);\n               y += i;\n            }\n            while (y != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_zgbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zgemm.c",
    "content": "/*\n *\n * cblas_zgemm.c\n * This program is a C interface to zgemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const CBLAS_INT_TYPE K, const void *alpha, const void  *A,\n                 const CBLAS_INT_TYPE lda, const void  *B, const CBLAS_INT_TYPE ldb,\n                 const void *beta, void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char TA, TB;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_TB;\n#else\n   #define F77_TA &TA  \n   #define F77_TB &TB  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if(TransA == CblasTrans) TA='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgemm\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if(TransB == CblasTrans) TB='T';\n      else if ( TransB == CblasConjTrans ) TB='C';\n      else if ( TransB == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zgemm\",\"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_zgemm(F77_TA, F77_TB, &F77_M, &F77_N, &F77_K, alpha, A,\n                     &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if(TransA == CblasTrans) TB='T';\n      else if ( TransA == CblasConjTrans ) TB='C';\n      else if ( TransA == CblasNoTrans )   TB='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgemm\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if(TransB == CblasTrans) TA='T';\n      else if ( TransB == CblasConjTrans ) TA='C';\n      else if ( TransB == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgemm\",\"Illegal TransB setting, %d\\n\", TransB);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n         F77_TB = C2F_CHAR(&TB);\n      #endif\n\n      F77_zgemm(F77_TA, F77_TB, &F77_N, &F77_M, &F77_K, alpha, B,\n                  &F77_ldb, A, &F77_lda, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zgemm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zgemv.c",
    "content": "/*\n * cblas_zgemv.c\n * The program is a C interface of zgemv\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zgemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char TA;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA;\n#else\n   #define F77_TA &TA   \n#endif\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const double *xx= (double *)X, *alp= (double *)alpha, *bet = (double *)beta;\n   double ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   double *x=(double *)X, *y=(double *)Y, *st=0, *tx;\n\n\n   if (order == CblasColMajor)\n   {\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      F77_zgemv(F77_TA, &F77_M, &F77_N, alpha, A, &F77_lda, X, &F77_incX, \n                beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n         \n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         ALPHA[0]= *alp;\n         ALPHA[1]= -alp[1];\n         BETA[0]= *bet;\n         BETA[1]= -bet[1];\n         TA = 'N';\n         if (M > 0)\n         {\n            n = M << 1;\n            x = malloc(n*sizeof(double));\n            tx = x;\n            if( incX > 0 ) {\n               i = incX << 1 ;\n               tincx = 2;\n               st= x+n;\n            } else { \n               i = incX *(-2);\n               tincx = -2;\n               st = x-2; \n               x +=(n-2); \n            }\n\n            do\n            {\n               *x = *xx;\n               x[1] = -xx[1];\n               x += tincx ;\n               xx += i;\n            }\n            while (x != st);\n            x=tx;\n\n            #ifdef F77_INT\n               F77_incX = 1;\n            #else\n               incx = 1;\n            #endif\n\n            if(incY > 0)\n               tincY = incY; \n            else\n               tincY = -incY; \n\n            y++;\n\n            if (N > 0)\n            {\n               i = tincY << 1;\n               n = i * N ;\n               st = y + n;\n               do {\n                  *y = -(*y);\n                  y += i;\n               } while(y != st); \n               y -= n;\n            }\n         }\n         else x = (double *) X;\n      }\n      else \n      {\n         cblas_xerbla(2, \"cblas_zgemv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_TA = C2F_CHAR(&TA);\n      #endif\n      if (TransA == CblasConjTrans)\n         F77_zgemv(F77_TA, &F77_N, &F77_M, ALPHA, A, &F77_lda, x,\n                &F77_incX, BETA, Y, &F77_incY);\n      else\n         F77_zgemv(F77_TA, &F77_N, &F77_M, alpha, A, &F77_lda, x,\n                &F77_incX, beta, Y, &F77_incY);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (x != (double *)X) free(x);\n         if (N > 0)\n         {\n            do\n            {\n               *y = -(*y);\n               y += i;\n            }\n            while (y != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_zgemv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zgerc.c",
    "content": "/*\n * cblas_zgerc.c\n * The program is a C interface to zgerc.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zgerc(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incy\n   #define F77_lda lda   \n#endif\n\n   CBLAS_INT_TYPE n, i, tincy, incy=incY;\n   double *y=(double *)Y, *yy=(double *)Y, *ty, *st;\n\n\n   if (order == CblasColMajor)\n   {\n      F77_zgerc( &F77_M, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, A, \n                      &F77_lda);\n   }  else if (order == CblasRowMajor)   \n   {\n      if (N > 0)\n      {\n         n = N << 1;\n         y = malloc(n*sizeof(double));\n\n         ty = y;\n         if( incY > 0 ) {\n            i = incY << 1;\n            tincy = 2;\n            st= y+n;\n         } else { \n            i = incY *(-2);\n            tincy = -2;\n            st = y-2; \n            y +=(n-2); \n         }\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += tincy ;\n            yy += i;\n         }\n         while (y != st);\n         y = ty;\n\n         #ifdef F77_INT\n            F77_incY = 1;\n         #else\n            incy = 1;\n         #endif\n      }\n      else y = (double *) Y;\n\n      F77_zgeru( &F77_N, &F77_M, alpha, y, &F77_incY, X, &F77_incX, A, \n                      &F77_lda);\n      if(Y!=y)\n         free(y);\n\n   } else cblas_xerbla(1, \"cblas_zgerc\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zgeru.c",
    "content": "/*\n * cblas_zgeru.c\n * The program is a C interface to zgeru.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zgeru(const enum CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n   #define F77_lda lda\n#endif\n\n\n   if (order == CblasColMajor)\n   {\n      F77_zgeru( &F77_M, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, A,\n                      &F77_lda);\n   }\n   else if (order == CblasRowMajor)\n   {\n      F77_zgeru( &F77_N, &F77_M, alpha, Y, &F77_incY, X, &F77_incX, A, \n                      &F77_lda);\n   }\n   else cblas_xerbla(1, \"cblas_zgeru\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhbmv.c",
    "content": "/*\n * cblas_zhbmv.c\n * The program is a C interface to zhbmv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\n#include <stdio.h>\n#include <stdlib.h>\nvoid cblas_zhbmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo,const CBLAS_INT_TYPE N,const CBLAS_INT_TYPE K,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const double *xx= (double *)X, *alp= (double *)alpha, *bet = (double *)beta;\n   double ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   double *x=(double *)X, *y=(double *)Y, *st=0, *tx;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhbmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_zhbmv(F77_UL, &F77_N, &F77_K, alpha, A, &F77_lda, X,  \n                     &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1 ;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (double *) X; \n\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_zhbmv(F77_UL, &F77_N, &F77_K, ALPHA, \n                     A ,&F77_lda, x,&F77_incX, BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_zhbmv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor )\n   {\n      if(X!=x)\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n      }\n   }\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhemm.c",
    "content": "/*\n *\n * cblas_zhemm.c\n * This program is a C interface to zhemm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zhemm(const enum CBLAS_ORDER Order, const  enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhemm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zhemm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_zhemm(F77_SD, F77_UL, &F77_M, &F77_N, alpha, A, &F77_lda, \n                     B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhemm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zhemm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_zhemm(F77_SD, F77_UL, &F77_N, &F77_M, alpha, A,\n                 &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zhemm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhemv.c",
    "content": "/*\n * cblas_zhemv.c\n * The program is a C interface to zhemv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zhemv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const double *xx= (double *)X, *alp= (double *)alpha, *bet = (double *)beta;\n   double ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   double *x=(double *)X, *y=(double *)Y, *st=0, *tx;\n\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhemv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_zhemv(F77_UL, &F77_N, alpha, A, &F77_lda, X, &F77_incX, \n                beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1 ;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (double *) X;\n\n          \n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhemv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_zhemv(F77_UL, &F77_N, ALPHA, A, &F77_lda, x, &F77_incX, \n                BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_zhemv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor )\n   {\n      if ( X != x )\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n     }\n   }\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zher.c",
    "content": "/*\n * cblas_zher.c\n * The program is a C interface to zher.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const void *X, const CBLAS_INT_TYPE incX\n                ,void *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n#endif\n   CBLAS_INT_TYPE n, i, tincx, incx=incX;\n   double *x=(double *)X, *xx=(double *)X, *tx, *st;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_zher(F77_UL, &F77_N, &alpha, X, &F77_incX, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n         tx = x;\n         if( incX > 0 ) {\n            i = incX << 1 ;\n            tincx = 2;\n            st= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            st = x-2; \n            x +=(n-2); \n         }\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n         #ifdef F77_INT\n           F77_incX = 1;\n         #else\n           incx = 1;\n         #endif\n      }\n      else x = (double *) X;\n      F77_zher(F77_UL, &F77_N, &alpha, x, &F77_incX, A, &F77_lda);\n   } else cblas_xerbla(1, \"cblas_zher\", \"Illegal Order setting, %d\\n\", order);\n   if(X!=x) \n      free(x);\n   \n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zher2.c",
    "content": "/*\n * cblas_zher2.c\n * The program is a C interface to zher2.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const CBLAS_INT_TYPE N, const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                 const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incx\n   #define F77_incY incy\n#endif\n   CBLAS_INT_TYPE n, i, j, tincx, tincy, incx=incX, incy=incY;\n   double *x=(double *)X, *xx=(double *)X, *y=(double *)Y, \n         *yy=(double *)Y, *tx, *ty, *stx, *sty;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher2\", \"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_zher2(F77_UL, &F77_N, alpha, X, &F77_incX, \n                                            Y, &F77_incY, A, &F77_lda);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher2\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n         y = malloc(n*sizeof(double));         \n         tx = x;\n         ty = y;\n         if( incX > 0 ) {\n            i = incX << 1 ;\n            tincx = 2;\n            stx= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            stx = x-2; \n            x +=(n-2); \n         }\n         \n         if( incY > 0 ) {\n            j = incY << 1;\n            tincy = 2;\n            sty= y+n;\n         } else { \n            j = incY *(-2);\n            tincy = -2;\n            sty = y-2; \n            y +=(n-2); \n         }\n\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != stx);\n\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += tincy ;\n            yy += j;\n         }\n         while (y != sty);\n\n         x=tx;\n         y=ty;\n\n         #ifdef F77_INT\n            F77_incX = 1;\n            F77_incY = 1;\n         #else\n            incx = 1;\n            incy = 1;\n         #endif\n      }  else \n      {\n         x = (double *) X;\n         y = (double *) Y;\n      }\n      F77_zher2(F77_UL, &F77_N, alpha, y, &F77_incY, x, \n                                      &F77_incX, A, &F77_lda);\n   } \n   else \n   {\n      cblas_xerbla(1, \"cblas_zher2\", \"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n      free(x);\n   if(Y!=y)\n      free(y);\n\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zher2k.c",
    "content": "/*\n *\n * cblas_zher2k.c\n * This program is a C interface to zher2k.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                  const void *B, const CBLAS_INT_TYPE ldb, const double beta,\n                  void *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n   double ALPHA[2]; \n   const double *alp=(double *)alpha;\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zher2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zher2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      \n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zher2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zher2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      F77_zher2k(F77_UL,F77_TR, &F77_N, &F77_K, ALPHA, A, &F77_lda, B, &F77_ldb, &beta, C, &F77_ldc);\n   } else  cblas_xerbla(1, \"cblas_zher2k\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zherk.c",
    "content": "/*\n *\n * cblas_zherk.c\n * This program is a C interface to zherk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const double alpha, const void *A, const CBLAS_INT_TYPE lda,\n                 const double beta, void *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zherk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zherk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zherk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                     &beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zherk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zherk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_zherk(F77_UL, F77_TR, &F77_N, &F77_K, &alpha, A, &F77_lda,\n                &beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zherk\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhpmv.c",
    "content": "/*\n * cblas_zhpmv.c\n * The program is a C interface of zhpmv\n * \n * Keita Teranishi  5/18/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zhpmv(const enum CBLAS_ORDER order,\n                 const enum CBLAS_UPLO Uplo,const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *AP,\n                 const void  *X, const CBLAS_INT_TYPE incX, const void *beta,\n                 void  *Y, const CBLAS_INT_TYPE incY)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incx\n   #define F77_incY incY\n#endif\n   CBLAS_INT_TYPE n, i=0, incx=incX;\n   const double *xx= (double *)X, *alp= (double *)alpha, *bet = (double *)beta;\n   double ALPHA[2],BETA[2];\n   CBLAS_INT_TYPE tincY, tincx;\n   double *x=(double *)X, *y=(double *)Y, *st=0, *tx;\n\n   if (order == CblasColMajor)\n   { \n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpmv\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      F77_zhpmv(F77_UL, &F77_N, alpha, AP, X,  \n                     &F77_incX, beta, Y, &F77_incY);\n   }\n   else if (order == CblasRowMajor)\n   {\n      ALPHA[0]= *alp;\n      ALPHA[1]= -alp[1];\n      BETA[0]= *bet;\n      BETA[1]= -bet[1];\n\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n \n         tx = x;\n         if( incX > 0 ) {\n           i = incX << 1;\n           tincx = 2;\n           st= x+n;\n         } else {\n           i = incX *(-2);\n           tincx = -2;\n           st = x-2;\n           x +=(n-2);\n         }\n\n         do\n         {\n           *x = *xx;\n           x[1] = -xx[1];\n           x += tincx ;\n           xx += i;\n         }\n         while (x != st);\n         x=tx;\n\n\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n \n         if(incY > 0)\n           tincY = incY;\n         else\n           tincY = -incY;\n         y++;\n\n         i = tincY << 1;\n         n = i * N ;\n         st = y + n;\n         do {\n            *y = -(*y);\n            y += i;\n         } while(y != st);\n         y -= n;\n      }  else\n         x = (double *) X;\n\n\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpmv\",\"Illegal Uplo setting, %d\\n\", Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_zhpmv(F77_UL, &F77_N, ALPHA, \n                     AP, x, &F77_incX, BETA, Y, &F77_incY);\n   }\n   else \n   {\n      cblas_xerbla(1, \"cblas_zhpmv\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if ( order == CblasRowMajor ) \n   {\n      if(X!=x)\n         free(x);\n      if (N > 0)\n      {\n         do\n         {\n            *y = -(*y);\n            y += i;\n         }\n         while (y != st);\n     }\n  }\n\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhpr.c",
    "content": "/*\n * cblas_zhpr.c\n * The program is a C interface to zhpr.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                const CBLAS_INT_TYPE N, const double alpha, const void *X,\n                const CBLAS_INT_TYPE incX, void *A)\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incx\n#endif\n   CBLAS_INT_TYPE n, i, tincx, incx=incX;\n   double *x=(double *)X, *xx=(double *)X, *tx, *st;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpr\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_zhpr(F77_UL, &F77_N, &alpha, X, &F77_incX, A);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpr\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n         tx = x;\n         if( incX > 0 ) {\n            i = incX << 1;\n            tincx = 2;\n            st= x+n;\n         } else { \n            i = incX *(-2);\n            tincx = -2;\n            st = x-2; \n            x +=(n-2); \n         }\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += tincx ;\n            xx += i;\n         }\n         while (x != st);\n         x=tx;\n         #ifdef F77_INT\n            F77_incX = 1;\n         #else\n            incx = 1;\n         #endif\n      }\n      else x = (double *) X;\n\n      F77_zhpr(F77_UL, &F77_N, &alpha, x, &F77_incX, A);\n\n   } else \n   {\n      cblas_xerbla(1, \"cblas_zhpr\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n     free(x);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zhpr2.c",
    "content": "/*\n * cblas_zhpr2.c\n * The program is a C interface to zhpr2.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include <stdio.h>\n#include <stdlib.h>\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                      const CBLAS_INT_TYPE N,const void *alpha, const void *X, \n                      const CBLAS_INT_TYPE incX,const void *Y, const CBLAS_INT_TYPE incY, void *Ap)\n\n{\n   char UL;\n#ifdef F77_CHAR\n   F77_CHAR F77_UL;\n#else\n   #define F77_UL &UL\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N,  F77_incX=incX, F77_incY=incY;\n#else\n   #define F77_N N\n   #define F77_incX incx\n   #define F77_incY incy\n#endif\n   CBLAS_INT_TYPE n, i, j, incx=incX, incy=incY;\n   double *x=(double *)X, *xx=(double *)X, *y=(double *)Y,\n         *yy=(double *)Y, *stx, *sty;\n\n \n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasLower) UL = 'L';\n      else if (Uplo == CblasUpper) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpr2\",\"Illegal Uplo setting, %d\\n\",Uplo );\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n\n      F77_zhpr2(F77_UL, &F77_N, alpha, X, &F77_incX, Y, &F77_incY, Ap);\n\n   }  else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zhpr2\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n      #endif\n      if (N > 0)\n      {\n         n = N << 1;\n         x = malloc(n*sizeof(double));\n         y = malloc(n*sizeof(double));         \n         stx = x + n;\n         sty = y + n;\n         if( incX > 0 )\n            i = incX << 1;\n         else\n            i = incX *(-2);\n \n         if( incY > 0 )\n            j = incY << 1;\n         else\n            j = incY *(-2);\n         do\n         {\n            *x = *xx;\n            x[1] = -xx[1];\n            x += 2;\n            xx += i;\n         } while (x != stx);\n         do\n         {\n            *y = *yy;\n            y[1] = -yy[1];\n            y += 2;\n            yy += j;\n         }\n         while (y != sty);\n         x -= n;\n         y -= n;\n\n         #ifdef F77_INT\n            if(incX > 0 )\n               F77_incX = 1;\n            else\n               F77_incX = -1;\n \n            if(incY > 0 )\n               F77_incY = 1;\n            else\n               F77_incY = -1;\n \n         #else\n            if(incX > 0 )\n               incx = 1;\n            else\n               incx = -1;\n \n            if(incY > 0 )\n               incy = 1;\n            else\n               incy = -1;\n         #endif\n\n      }  else \n      {\n         x = (double *) X;\n         y = (void  *) Y;\n      }\n      F77_zhpr2(F77_UL, &F77_N, alpha, y, &F77_incY, x, &F77_incX, Ap);\n   } \n   else \n   {\n      cblas_xerbla(1, \"cblas_zhpr2\",\"Illegal Order setting, %d\\n\", order);\n      return;\n   }\n   if(X!=x)\n      free(x);\n   if(Y!=y)\n      free(y);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zscal.c",
    "content": "/*\n * cblas_zscal.c\n *\n * The program is a C interface to zscal.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zscal( const CBLAS_INT_TYPE N, const void *alpha, void *X, \n                       const CBLAS_INT_TYPE incX)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else \n   #define F77_N N\n   #define F77_incX incX\n#endif\n   F77_zscal( &F77_N, alpha, X, &F77_incX);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zswap.c",
    "content": "/*\n * cblas_zswap.c\n *\n * The program is a C interface to zswap.\n *\n * Written by Keita Teranishi.  2/11/1998\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zswap( const CBLAS_INT_TYPE N, void  *X, const CBLAS_INT_TYPE incX, void  *Y,\n                       const CBLAS_INT_TYPE incY)\n{\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX, F77_incY=incY;\n#else \n   #define F77_N N\n   #define F77_incX incX\n   #define F77_incY incY\n#endif\n   F77_zswap( &F77_N, X, &F77_incX, Y, &F77_incY);\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zsymm.c",
    "content": "/*\n *\n * cblas_zsymm.c\n * This program is a C interface to zsymm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void  *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                 void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char SD, UL;   \n#ifdef F77_CHAR\n   F77_CHAR F77_SD, F77_UL;\n#else\n   #define F77_SD &SD  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zsymm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsymm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_zsymm(F77_SD, F77_UL, &F77_M, &F77_N, alpha, A, &F77_lda,\n                      B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zsymm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsymm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_SD = C2F_CHAR(&SD);\n      #endif\n\n      F77_zsymm(F77_SD, F77_UL, &F77_N, &F77_M, alpha, A, &F77_lda,\n                     B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zsymm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n} \n"
  },
  {
    "path": "dlib/external/cblas/cblas_zsyr2k.c",
    "content": "/*\n *\n * cblas_zsyr2k.c\n * This program is a C interface to zsyr2k.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                  const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                  const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                  const void  *B, const CBLAS_INT_TYPE ldb, const void *beta,\n                  void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda, F77_ldb=ldb;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldb ldb\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zsyr2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyr2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zsyr2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                      B, &F77_ldb, beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyr2k\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyr2k\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zsyr2k(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda, B, &F77_ldb, beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zsyr2k\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_zsyrk.c",
    "content": "/*\n *\n * cblas_zsyrk.c\n * This program is a C interface to zsyrk.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE Trans, const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 const void *beta, void  *C, const CBLAS_INT_TYPE ldc)\n{\n   char UL, TR;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TR, F77_UL;\n#else\n   #define F77_TR &TR  \n   #define F77_UL &UL  \n#endif\n\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_K=K, F77_lda=lda;\n   F77_INT F77_ldc=ldc;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_ldc ldc\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_zsyrk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( Trans == CblasTrans) TR ='T';\n      else if ( Trans == CblasConjTrans ) TR='C';\n      else if ( Trans == CblasNoTrans )   TR='N';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyrk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zsyrk(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                beta, C, &F77_ldc);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyrk\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if( Trans == CblasTrans) TR ='N';\n      else if ( Trans == CblasConjTrans ) TR='N';\n      else if ( Trans == CblasNoTrans )   TR='T';\n      else \n      {\n         cblas_xerbla(3, \"cblas_zsyrk\", \"Illegal Trans setting, %d\\n\", Trans);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TR = C2F_CHAR(&TR);\n      #endif\n\n      F77_zsyrk(F77_UL, F77_TR, &F77_N, &F77_K, alpha, A, &F77_lda,\n                     beta, C, &F77_ldc);\n   } \n   else  cblas_xerbla(1, \"cblas_zsyrk\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztbmv.c",
    "content": "/*\n * cblas_ztbmv.c\n * The program is a C interface to ztbmv.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0, *x=(double *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztbmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            x++;\n            st = x + n;\n            do\n            {\n               *x = -(*x);\n               x+= i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztbmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztbmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztbmv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztbmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztbsv.c",
    "content": "/*\n * cblas_ztbsv.c\n * The program is a C interface to ztbsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const CBLAS_INT_TYPE K, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_K=K, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_K K\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0,*x=(double *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztbsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n  \n            x++;\n\n            st=x+n;\n\n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztbsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztbsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztbsv( F77_UL, F77_TA, F77_DI, &F77_N, &F77_K, A, &F77_lda, X,\n                      &F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x+= i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztbsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztpmv.c",
    "content": "/*\n * cblas_ztpmv.c\n * The program is a C interface to ztpmv.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *Ap, void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0,*x=(double *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztpmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            x++;\n            st = x + n;\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztpmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztpmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztpmv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztpmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztpsv.c",
    "content": "/*\n * cblas_ztpsv.c\n * The program is a C interface to ztpsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *Ap, void  *X, const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0, *x=(double*)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X, &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztpsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n \n            x++;\n\n            st=x+n;\n\n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztpsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztpsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztpsv( F77_UL, F77_TA, F77_DI, &F77_N, Ap, X,&F77_incX);\n\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztpsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztrmm.c",
    "content": "/*\n *\n * cblas_ztrmm.c\n * This program is a C interface to ztrmm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const  enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;   \n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA  \n   #define F77_UL &UL  \n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n      if( Side == CblasRight ) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrmm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n      if( Uplo == CblasUpper ) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrmm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans ) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrmm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ztrmm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, alpha, A, &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n      if( Side == CblasRight ) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrmm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper ) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrmm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans ) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrmm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ztrmm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztrmm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, alpha, A, &F77_lda, B, &F77_ldb);\n   } \n   else  cblas_xerbla(1, \"cblas_ztrmm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztrmv.c",
    "content": "/*\n * cblas_ztrmv.c\n * The program is a C interface to ztrmv.\n * \n * Keita Teranishi  5/20/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *X, const CBLAS_INT_TYPE incX)\n\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0,*x=(double *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrmv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if(incX > 0)\n               tincX = incX;\n            else\n               tincX = -incX;\n            i = tincX << 1;\n            n = i * N;\n            x++;\n            st = x + n;\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrmv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrmv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n         F77_ztrmv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztrmv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztrsm.c",
    "content": "/*\n *\n * cblas_ztrsm.c\n * This program is a C interface to ztrsm.\n * Written by Keita Teranishi\n * 4/8/1998\n *\n */\n\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,\n                 const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,\n                 const enum CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                 const void *alpha, const void  *A, const CBLAS_INT_TYPE lda,\n                 void  *B, const CBLAS_INT_TYPE ldb)\n{\n   char UL, TA, SD, DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_SD, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_SD &SD\n   #define F77_DI &DI\n#endif\n\n#ifdef F77_INT\n   F77_INT F77_M=M, F77_N=N, F77_lda=lda, F77_ldb=ldb;\n#else\n   #define F77_M M\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_ldb ldb\n#endif\n\n\n   if( Order == CblasColMajor )\n   {\n\n      if( Side == CblasRight) SD='R';\n      else if ( Side == CblasLeft ) SD='L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='U';\n      else if ( Uplo == CblasLower ) UL='L';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ztrsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n      F77_ztrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_M, &F77_N, alpha, A,\n                &F77_lda, B, &F77_ldb);\n   } else if (Order == CblasRowMajor)\n   {\n\n      if( Side == CblasRight) SD='L';\n      else if ( Side == CblasLeft ) SD='R';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrsm\", \"Illegal Side setting, %d\\n\", Side);\n         return;\n      }\n\n      if( Uplo == CblasUpper) UL='L';\n      else if ( Uplo == CblasLower ) UL='U';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrsm\", \"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if( TransA == CblasTrans) TA ='T';\n      else if ( TransA == CblasConjTrans ) TA='C';\n      else if ( TransA == CblasNoTrans )   TA='N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrsm\", \"Illegal Trans setting, %d\\n\", TransA);\n         return;\n      }\n\n      if( Diag == CblasUnit ) DI='U';\n      else if ( Diag == CblasNonUnit ) DI='N';\n      else \n      {\n         cblas_xerbla(5, \"cblas_ztrsm\", \"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_SD = C2F_CHAR(&SD);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n\n\n      F77_ztrsm(F77_SD, F77_UL, F77_TA, F77_DI, &F77_N, &F77_M, alpha, A,\n                &F77_lda, B, &F77_ldb);\n   } \n   else  cblas_xerbla(1, \"cblas_ztrsm\", \"Illegal Order setting, %d\\n\", Order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cblas_ztrsv.c",
    "content": "/*\n * cblas_ztrsv.c\n * The program is a C interface to ztrsv.\n * \n * Keita Teranishi  3/23/98\n *\n */\n#include \"cblas.h\"\n#include \"cblas_f77.h\"\nvoid cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,\n                 const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,\n                 const CBLAS_INT_TYPE N, const void  *A, const CBLAS_INT_TYPE lda, void  *X,\n                 const CBLAS_INT_TYPE incX)\n{\n   char TA;\n   char UL;\n   char DI;\n#ifdef F77_CHAR\n   F77_CHAR F77_TA, F77_UL, F77_DI;\n#else\n   #define F77_TA &TA\n   #define F77_UL &UL\n   #define F77_DI &DI   \n#endif\n#ifdef F77_INT\n   F77_INT F77_N=N, F77_lda=lda, F77_incX=incX;\n#else\n   #define F77_N N\n   #define F77_lda lda\n   #define F77_incX incX\n#endif\n   CBLAS_INT_TYPE n, i=0, tincX; \n   double *st=0,*x=(double *)X;\n\n   if (order == CblasColMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'U';\n      else if (Uplo == CblasLower) UL = 'L';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n      if (TransA == CblasNoTrans) TA = 'N';\n      else if (TransA == CblasTrans) TA = 'T';\n      else if (TransA == CblasConjTrans) TA = 'C';\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n   }\n   else if (order == CblasRowMajor)\n   {\n      if (Uplo == CblasUpper) UL = 'L';\n      else if (Uplo == CblasLower) UL = 'U';\n      else \n      {\n         cblas_xerbla(2, \"cblas_ztrsv\",\"Illegal Uplo setting, %d\\n\", Uplo);\n         return;\n      }\n\n      if (TransA == CblasNoTrans) TA = 'T';\n      else if (TransA == CblasTrans) TA = 'N';\n      else if (TransA == CblasConjTrans)\n      {\n         TA = 'N';\n         if ( N > 0)\n         {\n            if ( incX > 0 )\n               tincX = incX;\n            else\n               tincX = -incX;\n \n            n = N*2*(tincX);\n            x++;\n            st=x+n; \n            i = tincX << 1;\n            do\n            {\n               *x = -(*x);\n               x+=i;\n            }\n            while (x != st);\n            x -= n;\n         }\n      }\n      else \n      {\n         cblas_xerbla(3, \"cblas_ztrsv\",\"Illegal TransA setting, %d\\n\", TransA);\n         return;\n      }\n\n      if (Diag == CblasUnit) DI = 'U';\n      else if (Diag == CblasNonUnit) DI = 'N';\n      else \n      {\n         cblas_xerbla(4, \"cblas_ztrsv\",\"Illegal Diag setting, %d\\n\", Diag);\n         return;\n      }\n      #ifdef F77_CHAR\n         F77_UL = C2F_CHAR(&UL);\n         F77_TA = C2F_CHAR(&TA);\n         F77_DI = C2F_CHAR(&DI);\n      #endif\n      F77_ztrsv( F77_UL, F77_TA, F77_DI, &F77_N, A, &F77_lda, X,\n                      &F77_incX);\n      if (TransA == CblasConjTrans)\n      {\n         if (N > 0)\n         {\n            do\n            {\n               *x = -(*x);\n               x += i;\n            }\n            while (x != st);\n         }\n      }\n   }\n   else cblas_xerbla(1, \"cblas_ztrsv\", \"Illegal Order setting, %d\\n\", order);\n   return;\n}\n"
  },
  {
    "path": "dlib/external/cblas/cdotcsub.f",
    "content": "c     cdotcsub.f\nc\nc     The program is a fortran wrapper for cdotc.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine cdotcsub(n,x,incx,y,incy,dotc)\nc\n      external cdotc\n      complex cdotc,dotc\n      integer n,incx,incy\n      complex x(*),y(*)\nc\n      dotc=cdotc(n,x,incx,y,incy)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/cdotusub.f",
    "content": "c     cdotusub.f\nc\nc     The program is a fortran wrapper for cdotu.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine cdotusub(n,x,incx,y,incy,dotu)\nc\n      external cdotu\n      complex cdotu,dotu\n      integer n,incx,incy\n      complex x(*),y(*)\nc\n      dotu=cdotu(n,x,incx,y,incy)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/dasumsub.f",
    "content": "c     dasumsun.f\nc\nc     The program is a fortran wrapper for dasum..\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine dasumsub(n,x,incx,asum)\nc\n      external dasum\n      double precision dasum,asum\n      integer n,incx\n      double precision x(*)\nc\n      asum=dasum(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/ddotsub.f",
    "content": "c     ddotsub.f\nc\nc     The program is a fortran wrapper for ddot.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine ddotsub(n,x,incx,y,incy,dot)\nc\n      external ddot\n      double precision ddot\n      integer n,incx,incy\n      double precision x(*),y(*),dot\nc\n      dot=ddot(n,x,incx,y,incy)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/dnrm2sub.f",
    "content": "c     dnrm2sub.f\nc\nc     The program is a fortran wrapper for dnrm2.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine dnrm2sub(n,x,incx,nrm2)\nc\n      external dnrm2\n      double precision dnrm2,nrm2\n      integer n,incx\n      double precision x(*)\nc\n      nrm2=dnrm2(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/dsdotsub.f",
    "content": "c     dsdotsub.f\nc\nc     The program is a fortran wrapper for dsdot.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine dsdotsub(n,x,incx,y,incy,dot)\nc\n      external dsdot\n      double precision dsdot,dot\n      integer n,incx,incy\n      real x(*),y(*)\nc\n      dot=dsdot(n,x,incx,y,incy)\n      return\n      end      \n"
  },
  {
    "path": "dlib/external/cblas/dzasumsub.f",
    "content": "c     dzasumsub.f\nc\nc     The program is a fortran wrapper for dzasum.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine dzasumsub(n,x,incx,asum)\nc\n      external dzasum\n      double precision dzasum,asum\n      integer n,incx\n      double complex x(*)\nc\n      asum=dzasum(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/dznrm2sub.f",
    "content": "c     dznrm2sub.f\nc\nc     The program is a fortran wrapper for dznrm2.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine dznrm2sub(n,x,incx,nrm2)\nc\n      external dznrm2\n      double precision dznrm2,nrm2\n      integer n,incx\n      double complex x(*)\nc\n      nrm2=dznrm2(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/icamaxsub.f",
    "content": "c     icamaxsub.f\nc\nc     The program is a fortran wrapper for icamax.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine icamaxsub(n,x,incx,iamax)\nc\n      external icamax\n      integer  icamax,iamax\n      integer n,incx\n      complex x(*)\nc\n      iamax=icamax(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/idamaxsub.f",
    "content": "c     icamaxsub.f\nc\nc     The program is a fortran wrapper for idamax.\nc     Witten by Keita Teranishi.  2/22/1998\nc\n      subroutine idamaxsub(n,x,incx,iamax)\nc\n      external idamax\n      integer  idamax,iamax\n      integer n,incx\n      double precision x(*)\nc\n      iamax=idamax(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/isamaxsub.f",
    "content": "c     isamaxsub.f\nc\nc     The program is a fortran wrapper for isamax.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine isamaxsub(n,x,incx,iamax)\nc\n      external isamax\n      integer  isamax,iamax\n      integer n,incx\n      real x(*)\nc\n      iamax=isamax(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/izamaxsub.f",
    "content": "c     izamaxsub.f\nc\nc     The program is a fortran wrapper for izamax.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine izamaxsub(n,x,incx,iamax)\nc\n      external izamax\n      integer  izamax,iamax\n      integer n,incx\n      double complex x(*)\nc\n      iamax=izamax(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/sasumsub.f",
    "content": "c     sasumsub.f\nc\nc     The program is a fortran wrapper for sasum.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine sasumsub(n,x,incx,asum)\nc\n      external sasum\n      real sasum,asum\n      integer n,incx\n      real x(*)\nc\n      asum=sasum(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/scasumsub.f",
    "content": "c     scasumsub.f\nc\nc     The program is a fortran wrapper for scasum.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine scasumsub(n,x,incx,asum)\nc\n      external scasum\n      real scasum,asum\n      integer n,incx\n      complex x(*)\nc\n      asum=scasum(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/scnrm2sub.f",
    "content": "c     scnrm2sub.f\nc\nc     The program is a fortran wrapper for scnrm2.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine scnrm2sub(n,x,incx,nrm2)\nc\n      external scnrm2\n      real scnrm2,nrm2\n      integer n,incx\n      complex x(*)\nc\n      nrm2=scnrm2(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/sdotsub.f",
    "content": "c     sdotsub.f\nc\nc     The program is a fortran wrapper for sdot.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine sdotsub(n,x,incx,y,incy,dot)\nc\n      external sdot\n      real sdot\n      integer n,incx,incy\n      real x(*),y(*),dot\nc\n      dot=sdot(n,x,incx,y,incy)\n      return\n      end      \n"
  },
  {
    "path": "dlib/external/cblas/sdsdotsub.f",
    "content": "c     sdsdotsub.f\nc\nc     The program is a fortran wrapper for sdsdot.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine sdsdotsub(n,x,incx,y,incy,dot)\nc\n      external sdsdot\n      real sdsdot,dot\n      integer n,incx,incy\n      real x(*),y(*)\nc\n      dot=sdsdot(n,x,incx,y,incy)\n      return\n      end      \n"
  },
  {
    "path": "dlib/external/cblas/snrm2sub.f",
    "content": "c     snrm2sub.f\nc\nc     The program is a fortran wrapper for snrm2.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine snrm2sub(n,x,incx,nrm2)\nc\n      external snrm2\n      real snrm2,nrm2\n      integer n,incx\n      real x(*)\nc\n      nrm2=snrm2(n,x,incx)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/zdotcsub.f",
    "content": "c     zdotcsub.f\nc\nc     The program is a fortran wrapper for zdotc.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine zdotcsub(n,x,incx,y,incy,dotc)\nc\n      external zdotc\n      double complex zdotc,dotc\n      integer n,incx,incy\n      double complex x(*),y(*)\nc\n      dotc=zdotc(n,x,incx,y,incy)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/cblas/zdotusub.f",
    "content": "c     zdotusub.f\nc\nc     The program is a fortran wrapper for zdotu.\nc     Witten by Keita Teranishi.  2/11/1998\nc\n      subroutine zdotusub(n,x,incx,y,incy,dotu)\nc\n      external zdotu\n      double complex zdotu,dotu\n      integer n,incx,incy\n      double complex x(*),y(*)\nc\n      dotu=zdotu(n,x,incx,y,incy)\n      return\n      end\n"
  },
  {
    "path": "dlib/external/libjpeg/README",
    "content": "The Independent JPEG Group's JPEG software\n==========================================\n\nREADME for release 9e of 16-Jan-2022\n====================================\n\nThis distribution contains the ninth public release of the Independent JPEG\nGroup's free JPEG software.  You are welcome to redistribute this software and\nto use it for any purpose, subject to the conditions under LEGAL ISSUES, below.\n\nThis software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,\nBill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,\nJohn Korejwa, Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi,\nGe' Weijers, and other members of the Independent JPEG Group.\n\nIJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee\n(previously known as JPEG, together with ITU-T SG16).\n\n\nDOCUMENTATION ROADMAP\n=====================\n\nThis file contains the following sections:\n\nOVERVIEW            General description of JPEG and the IJG software.\nLEGAL ISSUES        Copyright, lack of warranty, terms of distribution.\nREFERENCES          Where to learn more about JPEG.\nARCHIVE LOCATIONS   Where to find newer versions of this software.\nACKNOWLEDGMENTS     Special thanks.\nFILE FORMAT WARS    Software *not* to get.\nTO DO               Plans for future IJG releases.\n\nOther documentation files in the distribution are:\n\nUser documentation:\n  install.txt       How to configure and install the IJG software.\n  usage.txt         Usage instructions for cjpeg, djpeg, jpegtran,\n                    rdjpgcom, and wrjpgcom.\n  *.1               Unix-style man pages for programs (same info as usage.txt).\n  wizard.txt        Advanced usage instructions for JPEG wizards only.\n  cdaltui.txt       Description of alternate user interface for cjpeg/djpeg.\n  change.log        Version-to-version change highlights.\nProgrammer and internal documentation:\n  libjpeg.txt       How to use the JPEG library in your own programs.\n  example.c         Sample code for calling the JPEG library.\n  structure.txt     Overview of the JPEG library's internal structure.\n  filelist.txt      Road map of IJG files.\n  coderules.txt     Coding style rules --- please read if you contribute code.\n\nPlease read at least the files install.txt and usage.txt.  Some information\ncan also be found in the JPEG FAQ (Frequently Asked Questions) article.  See\nARCHIVE LOCATIONS below to find out where to obtain the FAQ article.\n\nIf you want to understand how the JPEG code works, we suggest reading one or\nmore of the REFERENCES, then looking at the documentation files (in roughly\nthe order listed) before diving into the code.\n\n\nOVERVIEW\n========\n\nThis package contains C software to implement JPEG image encoding, decoding,\nand transcoding.  JPEG (pronounced \"jay-peg\") is a standardized compression\nmethod for full-color and grayscale images.\n\nThis software implements JPEG baseline, extended-sequential, and progressive\ncompression processes.  Provision is made for supporting all variants of these\nprocesses, although some uncommon parameter settings aren't implemented yet.\nWe have made no provision for supporting the hierarchical or lossless\nprocesses defined in the standard.\n\nWe provide a set of library routines for reading and writing JPEG image files,\nplus two sample applications \"cjpeg\" and \"djpeg\", which use the library to\nperform conversion between JPEG and some other popular image file formats.\nThe library is intended to be reused in other applications.\n\nIn order to support file conversion and viewing software, we have included\nconsiderable functionality beyond the bare JPEG coding/decoding capability;\nfor example, the color quantization modules are not strictly part of JPEG\ndecoding, but they are essential for output to colormapped file formats or\ncolormapped displays.  These extra functions can be compiled out of the\nlibrary if not required for a particular application.\n\nWe have also included \"jpegtran\", a utility for lossless transcoding between\ndifferent JPEG processes, and \"rdjpgcom\" and \"wrjpgcom\", two simple\napplications for inserting and extracting textual comments in JFIF files.\n\nThe emphasis in designing this software has been on achieving portability and\nflexibility, while also making it fast enough to be useful.  In particular,\nthe software is not intended to be read as a tutorial on JPEG.  (See the\nREFERENCES section for introductory material.)  Rather, it is intended to\nbe reliable, portable, industrial-strength code.  We do not claim to have\nachieved that goal in every aspect of the software, but we strive for it.\n\nWe welcome the use of this software as a component of commercial products.\nNo royalty is required, but we do ask for an acknowledgement in product\ndocumentation, as described under LEGAL ISSUES.\n\n\nLEGAL ISSUES\n============\n\nIn plain English:\n\n1. We don't promise that this software works.  (But if you find any bugs,\n   please let us know!)\n2. You can use this software for whatever you want.  You don't have to pay us.\n3. You may not pretend that you wrote this software.  If you use it in a\n   program, you must acknowledge somewhere in your documentation that\n   you've used the IJG code.\n\nIn legalese:\n\nThe authors make NO WARRANTY or representation, either express or implied,\nwith respect to this software, its quality, accuracy, merchantability, or\nfitness for a particular purpose.  This software is provided \"AS IS\", and you,\nits user, assume the entire risk as to its quality and accuracy.\n\nThis software is copyright (C) 1991-2022, Thomas G. Lane, Guido Vollbeding.\nAll Rights Reserved except as specified below.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsoftware (or portions thereof) for any purpose, without fee, subject to these\nconditions:\n(1) If any part of the source code for this software is distributed, then this\nREADME file must be included, with this copyright and no-warranty notice\nunaltered; and any additions, deletions, or changes to the original files\nmust be clearly indicated in accompanying documentation.\n(2) If only executable code is distributed, then the accompanying\ndocumentation must state that \"this software is based in part on the work of\nthe Independent JPEG Group\".\n(3) Permission for use of this software is granted only if the user accepts\nfull responsibility for any undesirable consequences; the authors accept\nNO LIABILITY for damages of any kind.\n\nThese conditions apply to any software derived from or based on the IJG code,\nnot just to the unmodified library.  If you use our work, you ought to\nacknowledge us.\n\nPermission is NOT granted for the use of any IJG author's name or company name\nin advertising or publicity relating to this software or products derived from\nit.  This software may be referred to only as \"the Independent JPEG Group's\nsoftware\".\n\nWe specifically permit and encourage the use of this software as the basis of\ncommercial products, provided that all warranty or liability claims are\nassumed by the product vendor.\n\n\nThe Unix configuration script \"configure\" was produced with GNU Autoconf.\nIt is copyright by the Free Software Foundation but is freely distributable.\nThe same holds for its supporting scripts (config.guess, config.sub,\nltmain.sh).  Another support script, install-sh, is copyright by X Consortium\nbut is also freely distributable.\n\n\nREFERENCES\n==========\n\nWe recommend reading one or more of these references before trying to\nunderstand the innards of the JPEG software.\n\nThe best short technical introduction to the JPEG compression algorithm is\n\tWallace, Gregory K.  \"The JPEG Still Picture Compression Standard\",\n\tCommunications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.\n(Adjacent articles in that issue discuss MPEG motion picture compression,\napplications of JPEG, and related topics.)  If you don't have the CACM issue\nhandy, a PDF file containing a revised version of Wallace's article is\navailable at https://www.ijg.org/files/Wallace.JPEG.pdf.  The file (actually\na preprint for an article that appeared in IEEE Trans. Consumer Electronics)\nomits the sample images that appeared in CACM, but it includes corrections\nand some added material.  Note: the Wallace article is copyright ACM and IEEE,\nand it may not be used for commercial purposes.\n\nA somewhat less technical, more leisurely introduction to JPEG can be found in\n\"The Data Compression Book\" by Mark Nelson and Jean-loup Gailly, published by\nM&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1.  This book provides\ngood explanations and example C code for a multitude of compression methods\nincluding JPEG.  It is an excellent source if you are comfortable reading C\ncode but don't know much about data compression in general.  The book's JPEG\nsample code is far from industrial-strength, but when you are ready to look\nat a full implementation, you've got one here...\n\nThe best currently available description of JPEG is the textbook \"JPEG Still\nImage Data Compression Standard\" by William B. Pennebaker and Joan L.\nMitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.\nPrice US$59.95, 638 pp.  The book includes the complete text of the ISO JPEG\nstandards (DIS 10918-1 and draft DIS 10918-2).\nAlthough this is by far the most detailed and comprehensive exposition of\nJPEG publicly available, we point out that it is still missing an explanation\nof the most essential properties and algorithms of the underlying DCT\ntechnology.\nIf you think that you know about DCT-based JPEG after reading this book,\nthen you are in delusion.  The real fundamentals and corresponding potential\nof DCT-based JPEG are not publicly known so far, and that is the reason for\nall the mistaken developments taking place in the image coding domain.\n\nThe original JPEG standard is divided into two parts, Part 1 being the actual\nspecification, while Part 2 covers compliance testing methods.  Part 1 is\ntitled \"Digital Compression and Coding of Continuous-tone Still Images,\nPart 1: Requirements and guidelines\" and has document numbers ISO/IEC IS\n10918-1, ITU-T T.81.  Part 2 is titled \"Digital Compression and Coding of\nContinuous-tone Still Images, Part 2: Compliance testing\" and has document\nnumbers ISO/IEC IS 10918-2, ITU-T T.83.\nIJG JPEG 8 introduced an implementation of the JPEG SmartScale extension\nwhich is specified in two documents:  A contributed document at ITU and ISO\nwith title \"ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced\nImage Coding\", April 2006, Geneva, Switzerland.  The latest version of this\ndocument is Revision 3.  And a contributed document ISO/IEC JTC1/SC29/WG1 N\n5799 with title \"Evolution of JPEG\", June/July 2011, Berlin, Germany.\nIJG JPEG 9 introduces a reversible color transform for improved lossless\ncompression which is described in a contributed document ISO/IEC JTC1/SC29/\nWG1 N 6080 with title \"JPEG 9 Lossless Coding\", June/July 2012, Paris, France.\n\nThe JPEG standard does not specify all details of an interchangeable file\nformat.  For the omitted details we follow the \"JFIF\" conventions, version 2.\nJFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) :\nInformation technology - Digital compression and coding of continuous-tone\nstill images: JPEG File Interchange Format (JFIF).  It is available as a\nfree download in PDF file format from https://www.itu.int/rec/T-REC-T.871.\nA PDF file of the older JFIF document is available at\nhttps://www.w3.org/Graphics/JPEG/jfif3.pdf.\n\nThe TIFF 6.0 file format specification can be obtained by FTP from\nftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz.  The JPEG incorporation scheme\nfound in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.\nIJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).\nInstead, we recommend the JPEG design proposed by TIFF Technical Note #2\n(Compression tag 7).  Copies of this Note can be obtained from\nhttps://www.ijg.org/files/.  It is expected that the next revision\nof the TIFF spec will replace the 6.0 JPEG design with the Note's design.\nAlthough IJG's own code does not support TIFF/JPEG, the free libtiff library\nuses our library to implement TIFF/JPEG per the Note.\n\n\nARCHIVE LOCATIONS\n=================\n\nThe \"official\" archive site for this software is www.ijg.org.\nThe most recent released version can always be found there in\ndirectory \"files\".  This particular version will be archived\nin Windows-compatible \"zip\" archive format as\nhttps://www.ijg.org/files/jpegsr9e.zip, and\nin Unix-compatible \"tar.gz\" archive format as\nhttps://www.ijg.org/files/jpegsrc.v9e.tar.gz.\n\nThe JPEG FAQ (Frequently Asked Questions) article is a source of some\ngeneral information about JPEG.\nIt is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/\nand other news.answers archive sites, including the official news.answers\narchive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.\nIf you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu\nwith body\n\tsend usenet/news.answers/jpeg-faq/part1\n\tsend usenet/news.answers/jpeg-faq/part2\n\n\nACKNOWLEDGMENTS\n===============\n\nThank to Juergen Bruder for providing me with a copy of the common DCT\nalgorithm article, only to find out that I had come to the same result\nin a more direct and comprehensible way with a more generative approach.\n\nThank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the\nITU JPEG (Study Group 16) meeting in Geneva, Switzerland.\n\nThank to Thomas Wiegand and Gary Sullivan for inviting me to the\nJoint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.\n\nThank to Thomas Richter and Daniel Lee for inviting me to the\nISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16)\nmeeting in Berlin, Germany.\n\nThank to John Korejwa and Massimo Ballerini for inviting me to\nfruitful consultations in Boston, MA and Milan, Italy.\n\nThank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther\nMaier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel\nfor corresponding business development.\n\nThank to Nico Zschach and Dirk Stelling of the technical support team\nat the Digital Images company in Halle for providing me with extra\nequipment for configuration tests.\n\nThank to Richard F. Lyon (then of Foveon Inc.) for fruitful\ncommunication about JPEG configuration in Sigma Photo Pro software.\n\nThank to Andrew Finkenstadt for hosting the ijg.org site.\n\nThank to Thomas G. Lane for the original design and development\nof this singular software package.\n\nThank to Lars Goehler, Andreas Heinecke, Sebastian Fuss,\nYvonne Roebert, Andrej Werner, Ulf-Dietrich Braumann,\nand Nina Ssymank for support and public relations.\n\n\nFILE FORMAT WARS\n================\n\nThe ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG,\ntogether with ITU-T SG16) currently promotes different formats containing\nthe name \"JPEG\" which is misleading because these formats are incompatible\nwith original DCT-based JPEG and are based on faulty technologies.\nIJG therefore does not and will not support such momentary mistakes\n(see REFERENCES).\nThere exist also distributions under the name \"OpenJPEG\" promoting such\nkind of formats which is misleading because they don't support original\nJPEG images.\nWe have no sympathy for the promotion of inferior formats.  Indeed, one of\nthe original reasons for developing this free software was to help force\nconvergence on common, interoperable format standards for JPEG files.\nDon't use an incompatible file format!\n(In any case, our decoder will remain capable of reading existing JPEG\nimage files indefinitely.)\n\nThe ISO committee pretends to be \"responsible for the popular JPEG\" in their\npublic reports which is not true because they don't respond to actual\nrequirements for the maintenance of the original JPEG specification.\nFurthermore, the ISO committee pretends to \"ensure interoperability\" with\ntheir standards which is not true because their \"standards\" support only\napplication-specific and proprietary use cases and contain mathematically\nincorrect code.\n\nThere are currently different distributions in circulation containing the\nname \"libjpeg\" which is misleading because they don't have the features and\nare incompatible with formats supported by actual IJG libjpeg distributions.\nOne of those fakes is released by members of the ISO committee and just uses\nthe name of libjpeg for misdirection of people, similar to the abuse of the\nname JPEG as described above, while having nothing in common with actual IJG\nlibjpeg distributions and containing mathematically incorrect code.\nThe other one claims to be a \"derivative\" or \"fork\" of the original libjpeg,\nbut violates the license conditions as described under LEGAL ISSUES above\nand violates basic C programming properties.\nWe have no sympathy for the release of misleading, incorrect and illegal\ndistributions derived from obsolete code bases.\nDon't use an obsolete code base!\n\nAccording to the UCC (Uniform Commercial Code) law, IJG has the lawful and\nlegal right to foreclose on certain standardization bodies and other\ninstitutions or corporations that knowingly perform substantial and\nsystematic deceptive acts and practices, fraud, theft, and damaging of the\nvalue of the people of this planet without their knowing, willing and\nintentional consent.\nThe titles, ownership, and rights of these institutions and all their assets\nare now duly secured and held in trust for the free people of this planet.\nPeople of the planet, on every country, may have a financial interest in\nthe assets of these former principals, agents, and beneficiaries of the\nforeclosed institutions and corporations.\nIJG asserts what is: that each man, woman, and child has unalienable value\nand rights granted and deposited in them by the Creator and not any one of\nthe people is subordinate to any artificial principality, corporate fiction\nor the special interest of another without their appropriate knowing,\nwilling and intentional consent made by contract or accommodation agreement.\nIJG expresses that which already was.\nThe people have already determined and demanded that public administration\nentities, national governments, and their supporting judicial systems must\nbe fully transparent, accountable, and liable.\nIJG has secured the value for all concerned free people of the planet.\n\nA partial list of foreclosed institutions and corporations (\"Hall of Shame\")\nis currently prepared and will be published later.\n\n\nTO DO\n=====\n\nVersion 9 is the second release of a new generation JPEG standard\nto overcome the limitations of the original JPEG specification,\nand is the first true source reference JPEG codec.\nMore features are being prepared for coming releases...\n\nPlease send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.\n"
  },
  {
    "path": "dlib/external/libjpeg/cderror.h",
    "content": "/*\n * cderror.h\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2009-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file defines the error and message codes for the cjpeg/djpeg\n * applications.  These strings are not needed as part of the JPEG library\n * proper.\n * Edit this file to add new codes, or to translate the message strings to\n * some other language.\n */\n\n/*\n * To define the enum list of message codes, include this file without\n * defining macro JMESSAGE.  To create a message string table, include it\n * again with a suitable JMESSAGE definition (see jerror.c for an example).\n */\n#ifndef JMESSAGE\n#ifndef CDERROR_H\n#define CDERROR_H\n/* First time through, define the enum list */\n#define JMAKE_ENUM_LIST\n#else\n/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */\n#define JMESSAGE(code,string)\n#endif /* CDERROR_H */\n#endif /* JMESSAGE */\n\n#ifdef JMAKE_ENUM_LIST\n\ntypedef enum {\n\n#define JMESSAGE(code,string)\tcode ,\n\n#endif /* JMAKE_ENUM_LIST */\n\nJMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */\n\n#ifdef BMP_SUPPORTED\nJMESSAGE(JERR_BMP_BADCMAP, \"Unsupported BMP colormap format\")\nJMESSAGE(JERR_BMP_BADDEPTH, \"Only 8-, 24-, and 32-bit BMP files are supported\")\nJMESSAGE(JERR_BMP_BADHEADER, \"Invalid BMP file: bad header length\")\nJMESSAGE(JERR_BMP_BADPLANES, \"Invalid BMP file: biPlanes not equal to 1\")\nJMESSAGE(JERR_BMP_COLORSPACE, \"BMP output must be grayscale or RGB\")\nJMESSAGE(JERR_BMP_COMPRESSED, \"Sorry, compressed BMPs not yet supported\")\nJMESSAGE(JERR_BMP_NOT, \"Not a BMP file - does not start with BM\")\nJMESSAGE(JERR_BMP_OUTOFRANGE, \"Numeric value out of range in BMP file\")\nJMESSAGE(JTRC_BMP, \"%ux%u %d-bit BMP image\")\nJMESSAGE(JTRC_BMP_MAPPED, \"%ux%u 8-bit colormapped BMP image\")\nJMESSAGE(JTRC_BMP_OS2, \"%ux%u %d-bit OS2 BMP image\")\nJMESSAGE(JTRC_BMP_OS2_MAPPED, \"%ux%u 8-bit colormapped OS2 BMP image\")\n#endif /* BMP_SUPPORTED */\n\n#ifdef GIF_SUPPORTED\nJMESSAGE(JERR_GIF_BUG, \"GIF output got confused\")\nJMESSAGE(JERR_GIF_CODESIZE, \"Bogus GIF codesize %d\")\nJMESSAGE(JERR_GIF_COLORSPACE, \"GIF output must be grayscale or RGB\")\nJMESSAGE(JERR_GIF_IMAGENOTFOUND, \"Too few images in GIF file\")\nJMESSAGE(JERR_GIF_NOT, \"Not a GIF file\")\nJMESSAGE(JERR_GIF_OUTOFRANGE, \"Numeric value out of range in GIF file\")\nJMESSAGE(JTRC_GIF, \"%ux%ux%d GIF image\")\nJMESSAGE(JTRC_GIF_BADVERSION,\n\t \"Warning: unexpected GIF version number '%c%c%c'\")\nJMESSAGE(JTRC_GIF_EXTENSION, \"Ignoring GIF extension block of type 0x%02x\")\nJMESSAGE(JTRC_GIF_NONSQUARE, \"Caution: nonsquare pixels in input\")\nJMESSAGE(JWRN_GIF_BADDATA, \"Corrupt data in GIF file\")\nJMESSAGE(JWRN_GIF_CHAR, \"Bogus char 0x%02x in GIF file, ignoring\")\nJMESSAGE(JWRN_GIF_ENDCODE, \"Premature end of GIF image\")\nJMESSAGE(JWRN_GIF_NOMOREDATA, \"Ran out of GIF bits\")\n#endif /* GIF_SUPPORTED */\n\n#ifdef PPM_SUPPORTED\nJMESSAGE(JERR_PPM_COLORSPACE, \"PPM output must be grayscale or RGB\")\nJMESSAGE(JERR_PPM_NONNUMERIC, \"Nonnumeric data in PPM file\")\nJMESSAGE(JERR_PPM_NOT, \"Not a PPM/PGM file\")\nJMESSAGE(JERR_PPM_OUTOFRANGE, \"Numeric value out of range in PPM file\")\nJMESSAGE(JTRC_PGM, \"%ux%u PGM image\")\nJMESSAGE(JTRC_PGM_TEXT, \"%ux%u text PGM image\")\nJMESSAGE(JTRC_PPM, \"%ux%u PPM image\")\nJMESSAGE(JTRC_PPM_TEXT, \"%ux%u text PPM image\")\n#endif /* PPM_SUPPORTED */\n\n#ifdef RLE_SUPPORTED\nJMESSAGE(JERR_RLE_BADERROR, \"Bogus error code from RLE library\")\nJMESSAGE(JERR_RLE_COLORSPACE, \"RLE output must be grayscale or RGB\")\nJMESSAGE(JERR_RLE_DIMENSIONS, \"Image dimensions (%ux%u) too large for RLE\")\nJMESSAGE(JERR_RLE_EMPTY, \"Empty RLE file\")\nJMESSAGE(JERR_RLE_EOF, \"Premature EOF in RLE header\")\nJMESSAGE(JERR_RLE_MEM, \"Insufficient memory for RLE header\")\nJMESSAGE(JERR_RLE_NOT, \"Not an RLE file\")\nJMESSAGE(JERR_RLE_TOOMANYCHANNELS, \"Cannot handle %d output channels for RLE\")\nJMESSAGE(JERR_RLE_UNSUPPORTED, \"Cannot handle this RLE setup\")\nJMESSAGE(JTRC_RLE, \"%ux%u full-color RLE file\")\nJMESSAGE(JTRC_RLE_FULLMAP, \"%ux%u full-color RLE file with map of length %d\")\nJMESSAGE(JTRC_RLE_GRAY, \"%ux%u grayscale RLE file\")\nJMESSAGE(JTRC_RLE_MAPGRAY, \"%ux%u grayscale RLE file with map of length %d\")\nJMESSAGE(JTRC_RLE_MAPPED, \"%ux%u colormapped RLE file with map of length %d\")\n#endif /* RLE_SUPPORTED */\n\n#ifdef TARGA_SUPPORTED\nJMESSAGE(JERR_TGA_BADCMAP, \"Unsupported Targa colormap format\")\nJMESSAGE(JERR_TGA_BADPARMS, \"Invalid or unsupported Targa file\")\nJMESSAGE(JERR_TGA_COLORSPACE, \"Targa output must be grayscale or RGB\")\nJMESSAGE(JTRC_TGA, \"%ux%u RGB Targa image\")\nJMESSAGE(JTRC_TGA_GRAY, \"%ux%u grayscale Targa image\")\nJMESSAGE(JTRC_TGA_MAPPED, \"%ux%u colormapped Targa image\")\n#else\nJMESSAGE(JERR_TGA_NOTCOMP, \"Targa support was not compiled\")\n#endif /* TARGA_SUPPORTED */\n\nJMESSAGE(JERR_BAD_CMAP_FILE,\n\t \"Color map file is invalid or of unsupported format\")\nJMESSAGE(JERR_TOO_MANY_COLORS,\n\t \"Output file format cannot handle %d colormap entries\")\nJMESSAGE(JERR_UNGETC_FAILED, \"ungetc failed\")\n#ifdef TARGA_SUPPORTED\nJMESSAGE(JERR_UNKNOWN_FORMAT,\n\t \"Unrecognized input file format --- perhaps you need -targa\")\n#else\nJMESSAGE(JERR_UNKNOWN_FORMAT, \"Unrecognized input file format\")\n#endif\nJMESSAGE(JERR_UNSUPPORTED_FORMAT, \"Unsupported output file format\")\n\n#ifdef JMAKE_ENUM_LIST\n\n  JMSG_LASTADDONCODE\n} ADDON_MESSAGE_CODE;\n\n#undef JMAKE_ENUM_LIST\n#endif /* JMAKE_ENUM_LIST */\n\n/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */\n#undef JMESSAGE\n"
  },
  {
    "path": "dlib/external/libjpeg/cdjpeg.h",
    "content": "/*\n * cdjpeg.h\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains common declarations for the sample applications\n * cjpeg and djpeg.  It is NOT used by the core JPEG library.\n */\n\n#define JPEG_CJPEG_DJPEG\t/* define proper options in jconfig.h */\n#define JPEG_INTERNAL_OPTIONS\t/* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jerror.h\"\t\t/* get library error codes too */\n#include \"cderror.h\"\t\t/* get application-specific error codes */\n\n\n/*\n * Object interface for cjpeg's source file decoding modules\n */\n\ntypedef struct cjpeg_source_struct * cjpeg_source_ptr;\n\nstruct cjpeg_source_struct {\n  JMETHOD(void, start_input, (j_compress_ptr cinfo,\n\t\t\t      cjpeg_source_ptr sinfo));\n  JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,\n\t\t\t\t       cjpeg_source_ptr sinfo));\n  JMETHOD(void, finish_input, (j_compress_ptr cinfo,\n\t\t\t       cjpeg_source_ptr sinfo));\n\n  FILE *input_file;\n\n  JSAMPARRAY buffer;\n  JDIMENSION buffer_height;\n};\n\n\n/*\n * Object interface for djpeg's output file encoding modules\n */\n\ntypedef struct djpeg_dest_struct * djpeg_dest_ptr;\n\nstruct djpeg_dest_struct {\n  /* start_output is called after jpeg_start_decompress finishes.\n   * The color map will be ready at this time, if one is needed.\n   */\n  JMETHOD(void, start_output, (j_decompress_ptr cinfo,\n\t\t\t       djpeg_dest_ptr dinfo));\n  /* Emit the specified number of pixel rows from the buffer. */\n  JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo,\n\t\t\t\t djpeg_dest_ptr dinfo,\n\t\t\t\t JDIMENSION rows_supplied));\n  /* Finish up at the end of the image. */\n  JMETHOD(void, finish_output, (j_decompress_ptr cinfo,\n\t\t\t\tdjpeg_dest_ptr dinfo));\n\n  /* Target file spec; filled in by djpeg.c after object is created. */\n  FILE * output_file;\n\n  /* Output pixel-row buffer.  Created by module init or start_output.\n   * Width is cinfo->output_width * cinfo->output_components;\n   * height is buffer_height.\n   */\n  JSAMPARRAY buffer;\n  JDIMENSION buffer_height;\n};\n\n\n/*\n * cjpeg/djpeg may need to perform extra passes to convert to or from\n * the source/destination file format.  The JPEG library does not know\n * about these passes, but we'd like them to be counted by the progress\n * monitor.  We use an expanded progress monitor object to hold the\n * additional pass count.\n */\n\nstruct cdjpeg_progress_mgr {\n  struct jpeg_progress_mgr pub;\t/* fields known to JPEG library */\n  int completed_extra_passes;\t/* extra passes completed */\n  int total_extra_passes;\t/* total extra */\n  /* last printed percentage stored here to avoid multiple printouts */\n  int percent_done;\n};\n\ntypedef struct cdjpeg_progress_mgr * cd_progress_ptr;\n\n\n/* Short forms of external names for systems with brain-damaged linkers. */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jinit_read_bmp\t\tjIRdBMP\n#define jinit_write_bmp\t\tjIWrBMP\n#define jinit_read_gif\t\tjIRdGIF\n#define jinit_write_gif\t\tjIWrGIF\n#define jinit_read_ppm\t\tjIRdPPM\n#define jinit_write_ppm\t\tjIWrPPM\n#define jinit_read_rle\t\tjIRdRLE\n#define jinit_write_rle\t\tjIWrRLE\n#define jinit_read_targa\tjIRdTarga\n#define jinit_write_targa\tjIWrTarga\n#define read_quant_tables\tRdQTables\n#define read_scan_script\tRdScnScript\n#define set_quality_ratings     SetQRates\n#define set_quant_slots\t\tSetQSlots\n#define set_sample_factors\tSetSFacts\n#define read_color_map\t\tRdCMap\n#define enable_signal_catcher\tEnSigCatcher\n#define start_progress_monitor\tStProgMon\n#define end_progress_monitor\tEnProgMon\n#define read_stdin\t\tRdStdin\n#define write_stdout\t\tWrStdout\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n/* Module selection routines for I/O modules. */\n\nEXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo));\nEXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t    boolean is_os2));\nEXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo));\nEXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t    boolean is_lzw));\nEXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo));\nEXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo));\nEXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo));\nEXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo));\nEXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo));\nEXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo));\n\n/* cjpeg support routines (in rdswitch.c) */\n\nEXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,\n\t\t\t\t       boolean force_baseline));\nEXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));\nEXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg,\n\t\t\t\t\t boolean force_baseline));\nEXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));\nEXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));\n\n/* djpeg support routines (in rdcolmap.c) */\n\nEXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile));\n\n/* common support routines (in cdjpeg.c) */\n\nEXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo));\nEXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo,\n\t\t\t\t\t cd_progress_ptr progress));\nEXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo));\nEXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars));\nEXTERN(FILE *) read_stdin JPP((void));\nEXTERN(FILE *) write_stdout JPP((void));\n\n/* miscellaneous useful macros */\n\n#ifdef DONT_USE_B_MODE\t\t/* define mode parameters for fopen() */\n#define READ_BINARY\t\"r\"\n#define WRITE_BINARY\t\"w\"\n#else\n#ifdef VMS\t\t\t/* VMS is very nonstandard */\n#define READ_BINARY\t\"rb\", \"ctx=stm\"\n#define WRITE_BINARY\t\"wb\", \"ctx=stm\"\n#else\t\t\t\t/* standard ANSI-compliant case */\n#define READ_BINARY\t\"rb\"\n#define WRITE_BINARY\t\"wb\"\n#endif\n#endif\n\n#ifndef EXIT_FAILURE\t\t/* define exit() codes if not provided */\n#define EXIT_FAILURE  1\n#endif\n#ifndef EXIT_SUCCESS\n#ifdef VMS\n#define EXIT_SUCCESS  1\t\t/* VMS is very nonstandard */\n#else\n#define EXIT_SUCCESS  0\n#endif\n#endif\n#ifndef EXIT_WARNING\n#ifdef VMS\n#define EXIT_WARNING  1\t\t/* VMS is very nonstandard */\n#else\n#define EXIT_WARNING  2\n#endif\n#endif\n"
  },
  {
    "path": "dlib/external/libjpeg/jaricom.c",
    "content": "/*\n * jaricom.c\n *\n * Developed 1997-2011 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains probability estimation tables for common use in\n * arithmetic entropy encoding and decoding routines.\n *\n * This data represents Table D.3 in the JPEG spec (D.2 in the draft),\n * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24\n * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n/* The following #define specifies the packing of the four components\n * into the compact INT32 representation.\n * Note that this formula must match the actual arithmetic encoder\n * and decoder implementation.  The implementation has to be changed\n * if this formula is changed.\n * The current organization is leaned on Markus Kuhn's JBIG\n * implementation (jbig_tab.c).\n */\n\n#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)\n\nconst INT32 jpeg_aritab[113+1] = {\n/*\n * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS\n */\n  V(   0, 0x5a1d,   1,   1, 1 ),\n  V(   1, 0x2586,  14,   2, 0 ),\n  V(   2, 0x1114,  16,   3, 0 ),\n  V(   3, 0x080b,  18,   4, 0 ),\n  V(   4, 0x03d8,  20,   5, 0 ),\n  V(   5, 0x01da,  23,   6, 0 ),\n  V(   6, 0x00e5,  25,   7, 0 ),\n  V(   7, 0x006f,  28,   8, 0 ),\n  V(   8, 0x0036,  30,   9, 0 ),\n  V(   9, 0x001a,  33,  10, 0 ),\n  V(  10, 0x000d,  35,  11, 0 ),\n  V(  11, 0x0006,   9,  12, 0 ),\n  V(  12, 0x0003,  10,  13, 0 ),\n  V(  13, 0x0001,  12,  13, 0 ),\n  V(  14, 0x5a7f,  15,  15, 1 ),\n  V(  15, 0x3f25,  36,  16, 0 ),\n  V(  16, 0x2cf2,  38,  17, 0 ),\n  V(  17, 0x207c,  39,  18, 0 ),\n  V(  18, 0x17b9,  40,  19, 0 ),\n  V(  19, 0x1182,  42,  20, 0 ),\n  V(  20, 0x0cef,  43,  21, 0 ),\n  V(  21, 0x09a1,  45,  22, 0 ),\n  V(  22, 0x072f,  46,  23, 0 ),\n  V(  23, 0x055c,  48,  24, 0 ),\n  V(  24, 0x0406,  49,  25, 0 ),\n  V(  25, 0x0303,  51,  26, 0 ),\n  V(  26, 0x0240,  52,  27, 0 ),\n  V(  27, 0x01b1,  54,  28, 0 ),\n  V(  28, 0x0144,  56,  29, 0 ),\n  V(  29, 0x00f5,  57,  30, 0 ),\n  V(  30, 0x00b7,  59,  31, 0 ),\n  V(  31, 0x008a,  60,  32, 0 ),\n  V(  32, 0x0068,  62,  33, 0 ),\n  V(  33, 0x004e,  63,  34, 0 ),\n  V(  34, 0x003b,  32,  35, 0 ),\n  V(  35, 0x002c,  33,   9, 0 ),\n  V(  36, 0x5ae1,  37,  37, 1 ),\n  V(  37, 0x484c,  64,  38, 0 ),\n  V(  38, 0x3a0d,  65,  39, 0 ),\n  V(  39, 0x2ef1,  67,  40, 0 ),\n  V(  40, 0x261f,  68,  41, 0 ),\n  V(  41, 0x1f33,  69,  42, 0 ),\n  V(  42, 0x19a8,  70,  43, 0 ),\n  V(  43, 0x1518,  72,  44, 0 ),\n  V(  44, 0x1177,  73,  45, 0 ),\n  V(  45, 0x0e74,  74,  46, 0 ),\n  V(  46, 0x0bfb,  75,  47, 0 ),\n  V(  47, 0x09f8,  77,  48, 0 ),\n  V(  48, 0x0861,  78,  49, 0 ),\n  V(  49, 0x0706,  79,  50, 0 ),\n  V(  50, 0x05cd,  48,  51, 0 ),\n  V(  51, 0x04de,  50,  52, 0 ),\n  V(  52, 0x040f,  50,  53, 0 ),\n  V(  53, 0x0363,  51,  54, 0 ),\n  V(  54, 0x02d4,  52,  55, 0 ),\n  V(  55, 0x025c,  53,  56, 0 ),\n  V(  56, 0x01f8,  54,  57, 0 ),\n  V(  57, 0x01a4,  55,  58, 0 ),\n  V(  58, 0x0160,  56,  59, 0 ),\n  V(  59, 0x0125,  57,  60, 0 ),\n  V(  60, 0x00f6,  58,  61, 0 ),\n  V(  61, 0x00cb,  59,  62, 0 ),\n  V(  62, 0x00ab,  61,  63, 0 ),\n  V(  63, 0x008f,  61,  32, 0 ),\n  V(  64, 0x5b12,  65,  65, 1 ),\n  V(  65, 0x4d04,  80,  66, 0 ),\n  V(  66, 0x412c,  81,  67, 0 ),\n  V(  67, 0x37d8,  82,  68, 0 ),\n  V(  68, 0x2fe8,  83,  69, 0 ),\n  V(  69, 0x293c,  84,  70, 0 ),\n  V(  70, 0x2379,  86,  71, 0 ),\n  V(  71, 0x1edf,  87,  72, 0 ),\n  V(  72, 0x1aa9,  87,  73, 0 ),\n  V(  73, 0x174e,  72,  74, 0 ),\n  V(  74, 0x1424,  72,  75, 0 ),\n  V(  75, 0x119c,  74,  76, 0 ),\n  V(  76, 0x0f6b,  74,  77, 0 ),\n  V(  77, 0x0d51,  75,  78, 0 ),\n  V(  78, 0x0bb6,  77,  79, 0 ),\n  V(  79, 0x0a40,  77,  48, 0 ),\n  V(  80, 0x5832,  80,  81, 1 ),\n  V(  81, 0x4d1c,  88,  82, 0 ),\n  V(  82, 0x438e,  89,  83, 0 ),\n  V(  83, 0x3bdd,  90,  84, 0 ),\n  V(  84, 0x34ee,  91,  85, 0 ),\n  V(  85, 0x2eae,  92,  86, 0 ),\n  V(  86, 0x299a,  93,  87, 0 ),\n  V(  87, 0x2516,  86,  71, 0 ),\n  V(  88, 0x5570,  88,  89, 1 ),\n  V(  89, 0x4ca9,  95,  90, 0 ),\n  V(  90, 0x44d9,  96,  91, 0 ),\n  V(  91, 0x3e22,  97,  92, 0 ),\n  V(  92, 0x3824,  99,  93, 0 ),\n  V(  93, 0x32b4,  99,  94, 0 ),\n  V(  94, 0x2e17,  93,  86, 0 ),\n  V(  95, 0x56a8,  95,  96, 1 ),\n  V(  96, 0x4f46, 101,  97, 0 ),\n  V(  97, 0x47e5, 102,  98, 0 ),\n  V(  98, 0x41cf, 103,  99, 0 ),\n  V(  99, 0x3c3d, 104, 100, 0 ),\n  V( 100, 0x375e,  99,  93, 0 ),\n  V( 101, 0x5231, 105, 102, 0 ),\n  V( 102, 0x4c0f, 106, 103, 0 ),\n  V( 103, 0x4639, 107, 104, 0 ),\n  V( 104, 0x415e, 103,  99, 0 ),\n  V( 105, 0x5627, 105, 106, 1 ),\n  V( 106, 0x50e7, 108, 107, 0 ),\n  V( 107, 0x4b85, 109, 103, 0 ),\n  V( 108, 0x5597, 110, 109, 0 ),\n  V( 109, 0x504f, 111, 107, 0 ),\n  V( 110, 0x5a10, 110, 111, 1 ),\n  V( 111, 0x5522, 112, 109, 0 ),\n  V( 112, 0x59eb, 112, 111, 1 ),\n/*\n * This last entry is used for fixed probability estimate of 0.5\n * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851.\n */\n  V( 113, 0x5a1d, 113, 113, 0 )\n};\n"
  },
  {
    "path": "dlib/external/libjpeg/jcapimin.c",
    "content": "/*\n * jcapimin.c\n *\n * Copyright (C) 1994-1998, Thomas G. Lane.\n * Modified 2003-2010 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains application interface code for the compression half\n * of the JPEG library.  These are the \"minimum\" API routines that may be\n * needed in either the normal full-compression case or the transcoding-only\n * case.\n *\n * Most of the routines intended to be called directly by an application\n * are in this file or in jcapistd.c.  But also see jcparam.c for\n * parameter-setup helper routines, jcomapi.c for routines shared by\n * compression and decompression, and jctrans.c for the transcoding case.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Initialization of a JPEG compression object.\n * The error manager must already be set up (in case memory manager fails).\n */\n\nGLOBAL(void)\njpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)\n{\n  int i;\n\n  /* Guard against version mismatches between library and caller. */\n  cinfo->mem = NULL;\t\t/* so jpeg_destroy knows mem mgr not called */\n  if (version != JPEG_LIB_VERSION)\n    ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);\n  if (structsize != SIZEOF(struct jpeg_compress_struct))\n    ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, \n\t     (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);\n\n  /* For debugging purposes, we zero the whole master structure.\n   * But the application has already set the err pointer, and may have set\n   * client_data, so we have to save and restore those fields.\n   * Note: if application hasn't set client_data, tools like Purify may\n   * complain here.\n   */\n  {\n    struct jpeg_error_mgr * err = cinfo->err;\n    void * client_data = cinfo->client_data; /* ignore Purify complaint here */\n    MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));\n    cinfo->err = err;\n    cinfo->client_data = client_data;\n  }\n  cinfo->is_decompressor = FALSE;\n\n  /* Initialize a memory manager instance for this object */\n  jinit_memory_mgr((j_common_ptr) cinfo);\n\n  /* Zero out pointers to permanent structures. */\n  cinfo->progress = NULL;\n  cinfo->dest = NULL;\n\n  cinfo->comp_info = NULL;\n\n  for (i = 0; i < NUM_QUANT_TBLS; i++) {\n    cinfo->quant_tbl_ptrs[i] = NULL;\n    cinfo->q_scale_factor[i] = 100;\n  }\n\n  for (i = 0; i < NUM_HUFF_TBLS; i++) {\n    cinfo->dc_huff_tbl_ptrs[i] = NULL;\n    cinfo->ac_huff_tbl_ptrs[i] = NULL;\n  }\n\n  /* Must do it here for emit_dqt in case jpeg_write_tables is used */\n  cinfo->block_size = DCTSIZE;\n  cinfo->natural_order = jpeg_natural_order;\n  cinfo->lim_Se = DCTSIZE2-1;\n\n  cinfo->script_space = NULL;\n\n  cinfo->input_gamma = 1.0;\t/* in case application forgets */\n\n  /* OK, I'm ready */\n  cinfo->global_state = CSTATE_START;\n}\n\n\n/*\n * Destruction of a JPEG compression object\n */\n\nGLOBAL(void)\njpeg_destroy_compress (j_compress_ptr cinfo)\n{\n  jpeg_destroy((j_common_ptr) cinfo); /* use common routine */\n}\n\n\n/*\n * Abort processing of a JPEG compression operation,\n * but don't destroy the object itself.\n */\n\nGLOBAL(void)\njpeg_abort_compress (j_compress_ptr cinfo)\n{\n  jpeg_abort((j_common_ptr) cinfo); /* use common routine */\n}\n\n\n/*\n * Forcibly suppress or un-suppress all quantization and Huffman tables.\n * Marks all currently defined tables as already written (if suppress)\n * or not written (if !suppress).  This will control whether they get emitted\n * by a subsequent jpeg_start_compress call.\n *\n * This routine is exported for use by applications that want to produce\n * abbreviated JPEG datastreams.  It logically belongs in jcparam.c, but\n * since it is called by jpeg_start_compress, we put it here --- otherwise\n * jcparam.o would be linked whether the application used it or not.\n */\n\nGLOBAL(void)\njpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)\n{\n  int i;\n  JQUANT_TBL * qtbl;\n  JHUFF_TBL * htbl;\n\n  for (i = 0; i < NUM_QUANT_TBLS; i++) {\n    if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)\n      qtbl->sent_table = suppress;\n  }\n\n  for (i = 0; i < NUM_HUFF_TBLS; i++) {\n    if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)\n      htbl->sent_table = suppress;\n    if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)\n      htbl->sent_table = suppress;\n  }\n}\n\n\n/*\n * Finish JPEG compression.\n *\n * If a multipass operating mode was selected, this may do a great deal of\n * work including most of the actual output.\n */\n\nGLOBAL(void)\njpeg_finish_compress (j_compress_ptr cinfo)\n{\n  JDIMENSION iMCU_row;\n\n  if (cinfo->global_state == CSTATE_SCANNING ||\n      cinfo->global_state == CSTATE_RAW_OK) {\n    /* Terminate first pass */\n    if (cinfo->next_scanline < cinfo->image_height)\n      ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);\n    (*cinfo->master->finish_pass) (cinfo);\n  } else if (cinfo->global_state != CSTATE_WRCOEFS)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  /* Perform any remaining passes */\n  while (! cinfo->master->is_last_pass) {\n    (*cinfo->master->prepare_for_pass) (cinfo);\n    for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {\n      if (cinfo->progress != NULL) {\n\tcinfo->progress->pass_counter = (long) iMCU_row;\n\tcinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;\n\t(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n      }\n      /* We bypass the main controller and invoke coef controller directly;\n       * all work is being done from the coefficient buffer.\n       */\n      if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))\n\tERREXIT(cinfo, JERR_CANT_SUSPEND);\n    }\n    (*cinfo->master->finish_pass) (cinfo);\n  }\n  /* Write EOI, do final cleanup */\n  (*cinfo->marker->write_file_trailer) (cinfo);\n  (*cinfo->dest->term_destination) (cinfo);\n  /* We can use jpeg_abort to release memory and reset global_state */\n  jpeg_abort((j_common_ptr) cinfo);\n}\n\n\n/*\n * Write a special marker.\n * This is only recommended for writing COM or APPn markers.\n * Must be called after jpeg_start_compress() and before\n * first call to jpeg_write_scanlines() or jpeg_write_raw_data().\n */\n\nGLOBAL(void)\njpeg_write_marker (j_compress_ptr cinfo, int marker,\n\t\t   const JOCTET *dataptr, unsigned int datalen)\n{\n  JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));\n\n  if (cinfo->next_scanline != 0 ||\n      (cinfo->global_state != CSTATE_SCANNING &&\n       cinfo->global_state != CSTATE_RAW_OK &&\n       cinfo->global_state != CSTATE_WRCOEFS))\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);\n  write_marker_byte = cinfo->marker->write_marker_byte;\t/* copy for speed */\n  while (datalen--) {\n    (*write_marker_byte) (cinfo, *dataptr);\n    dataptr++;\n  }\n}\n\n/* Same, but piecemeal. */\n\nGLOBAL(void)\njpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen)\n{\n  if (cinfo->next_scanline != 0 ||\n      (cinfo->global_state != CSTATE_SCANNING &&\n       cinfo->global_state != CSTATE_RAW_OK &&\n       cinfo->global_state != CSTATE_WRCOEFS))\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);\n}\n\nGLOBAL(void)\njpeg_write_m_byte (j_compress_ptr cinfo, int val)\n{\n  (*cinfo->marker->write_marker_byte) (cinfo, val);\n}\n\n\n/*\n * Alternate compression function: just write an abbreviated table file.\n * Before calling this, all parameters and a data destination must be set up.\n *\n * To produce a pair of files containing abbreviated tables and abbreviated\n * image data, one would proceed as follows:\n *\n *\t\tinitialize JPEG object\n *\t\tset JPEG parameters\n *\t\tset destination to table file\n *\t\tjpeg_write_tables(cinfo);\n *\t\tset destination to image file\n *\t\tjpeg_start_compress(cinfo, FALSE);\n *\t\twrite data...\n *\t\tjpeg_finish_compress(cinfo);\n *\n * jpeg_write_tables has the side effect of marking all tables written\n * (same as jpeg_suppress_tables(..., TRUE)).  Thus a subsequent start_compress\n * will not re-emit the tables unless it is passed write_all_tables=TRUE.\n */\n\nGLOBAL(void)\njpeg_write_tables (j_compress_ptr cinfo)\n{\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  /* (Re)initialize error mgr and destination modules */\n  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);\n  (*cinfo->dest->init_destination) (cinfo);\n  /* Initialize the marker writer ... bit of a crock to do it here. */\n  jinit_marker_writer(cinfo);\n  /* Write them tables! */\n  (*cinfo->marker->write_tables_only) (cinfo);\n  /* And clean up. */\n  (*cinfo->dest->term_destination) (cinfo);\n  /*\n   * In library releases up through v6a, we called jpeg_abort() here to free\n   * any working memory allocated by the destination manager and marker\n   * writer.  Some applications had a problem with that: they allocated space\n   * of their own from the library memory manager, and didn't want it to go\n   * away during write_tables.  So now we do nothing.  This will cause a\n   * memory leak if an app calls write_tables repeatedly without doing a full\n   * compression cycle or otherwise resetting the JPEG object.  However, that\n   * seems less bad than unexpectedly freeing memory in the normal case.\n   * An app that prefers the old behavior can call jpeg_abort for itself after\n   * each call to jpeg_write_tables().\n   */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcapistd.c",
    "content": "/*\n * jcapistd.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2013 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains application interface code for the compression half\n * of the JPEG library.  These are the \"standard\" API routines that are\n * used in the normal full-compression case.  They are not used by a\n * transcoding-only application.  Note that if an application links in\n * jpeg_start_compress, it will end up linking in the entire compressor.\n * We thus must separate this file from jcapimin.c to avoid linking the\n * whole compression library into a transcoder.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Compression initialization.\n * Before calling this, all parameters and a data destination must be set up.\n *\n * We require a write_all_tables parameter as a failsafe check when writing\n * multiple datastreams from the same compression object.  Since prior runs\n * will have left all the tables marked sent_table=TRUE, a subsequent run\n * would emit an abbreviated stream (no tables) by default.  This may be what\n * is wanted, but for safety's sake it should not be the default behavior:\n * programmers should have to make a deliberate choice to emit abbreviated\n * images.  Therefore the documentation and examples should encourage people\n * to pass write_all_tables=TRUE; then it will take active thought to do the\n * wrong thing.\n */\n\nGLOBAL(void)\njpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)\n{\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  if (write_all_tables)\n    jpeg_suppress_tables(cinfo, FALSE);\t/* mark all tables to be written */\n\n  /* (Re)initialize error mgr and destination modules */\n  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);\n  (*cinfo->dest->init_destination) (cinfo);\n  /* Perform master selection of active modules */\n  jinit_compress_master(cinfo);\n  /* Set up for the first pass */\n  (*cinfo->master->prepare_for_pass) (cinfo);\n  /* Ready for application to drive first pass through jpeg_write_scanlines\n   * or jpeg_write_raw_data.\n   */\n  cinfo->next_scanline = 0;\n  cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);\n}\n\n\n/*\n * Write some scanlines of data to the JPEG compressor.\n *\n * The return value will be the number of lines actually written.\n * This should be less than the supplied num_lines only in case that\n * the data destination module has requested suspension of the compressor,\n * or if more than image_height scanlines are passed in.\n *\n * Note: we warn about excess calls to jpeg_write_scanlines() since\n * this likely signals an application programmer error.  However,\n * excess scanlines passed in the last valid call are *silently* ignored,\n * so that the application need not adjust num_lines for end-of-image\n * when using a multiple-scanline buffer.\n */\n\nGLOBAL(JDIMENSION)\njpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,\n\t\t      JDIMENSION num_lines)\n{\n  JDIMENSION row_ctr, rows_left;\n\n  if (cinfo->global_state != CSTATE_SCANNING)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  if (cinfo->next_scanline >= cinfo->image_height)\n    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);\n\n  /* Call progress monitor hook if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->pass_counter = (long) cinfo->next_scanline;\n    cinfo->progress->pass_limit = (long) cinfo->image_height;\n    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n  }\n\n  /* Give master control module another chance if this is first call to\n   * jpeg_write_scanlines.  This lets output of the frame/scan headers be\n   * delayed so that application can write COM, etc, markers between\n   * jpeg_start_compress and jpeg_write_scanlines.\n   */\n  if (cinfo->master->call_pass_startup)\n    (*cinfo->master->pass_startup) (cinfo);\n\n  /* Ignore any extra scanlines at bottom of image. */\n  rows_left = cinfo->image_height - cinfo->next_scanline;\n  if (num_lines > rows_left)\n    num_lines = rows_left;\n\n  row_ctr = 0;\n  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);\n  cinfo->next_scanline += row_ctr;\n  return row_ctr;\n}\n\n\n/*\n * Alternate entry point to write raw data.\n * Processes exactly one iMCU row per call, unless suspended.\n */\n\nGLOBAL(JDIMENSION)\njpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,\n\t\t     JDIMENSION num_lines)\n{\n  JDIMENSION lines_per_iMCU_row;\n\n  if (cinfo->global_state != CSTATE_RAW_OK)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  if (cinfo->next_scanline >= cinfo->image_height) {\n    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);\n    return 0;\n  }\n\n  /* Call progress monitor hook if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->pass_counter = (long) cinfo->next_scanline;\n    cinfo->progress->pass_limit = (long) cinfo->image_height;\n    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n  }\n\n  /* Give master control module another chance if this is first call to\n   * jpeg_write_raw_data.  This lets output of the frame/scan headers be\n   * delayed so that application can write COM, etc, markers between\n   * jpeg_start_compress and jpeg_write_raw_data.\n   */\n  if (cinfo->master->call_pass_startup)\n    (*cinfo->master->pass_startup) (cinfo);\n\n  /* Verify that at least one iMCU row has been passed. */\n  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;\n  if (num_lines < lines_per_iMCU_row)\n    ERREXIT(cinfo, JERR_BUFFER_SIZE);\n\n  /* Directly compress the row. */\n  if (! (*cinfo->coef->compress_data) (cinfo, data)) {\n    /* If compressor did not consume the whole row, suspend processing. */\n    return 0;\n  }\n\n  /* OK, we processed one iMCU row. */\n  cinfo->next_scanline += lines_per_iMCU_row;\n  return lines_per_iMCU_row;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcarith.c",
    "content": "/*\n * jcarith.c\n *\n * Developed 1997-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains portable arithmetic entropy encoding routines for JPEG\n * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).\n *\n * Both sequential and progressive modes are supported in this single module.\n *\n * Suspension is not currently supported in this module.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Expanded entropy encoder object for arithmetic encoding. */\n\ntypedef struct {\n  struct jpeg_entropy_encoder pub; /* public fields */\n\n  INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */\n  INT32 a;               /* A register, normalized size of coding interval */\n  INT32 sc;        /* counter for stacked 0xFF values which might overflow */\n  INT32 zc;          /* counter for pending 0x00 output values which might *\n                          * be discarded at the end (\"Pacman\" termination) */\n  int ct;  /* bit shift counter, determines when next byte will be written */\n  int buffer;                /* buffer for most recent output byte != 0xFF */\n\n  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */\n  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */\n\n  unsigned int restarts_to_go;\t/* MCUs left in this restart interval */\n  int next_restart_num;\t\t/* next restart number to write (0-7) */\n\n  /* Pointers to statistics areas (these workspaces have image lifespan) */\n  unsigned char * dc_stats[NUM_ARITH_TBLS];\n  unsigned char * ac_stats[NUM_ARITH_TBLS];\n\n  /* Statistics bin for coding with fixed probability 0.5 */\n  unsigned char fixed_bin[4];\n} arith_entropy_encoder;\n\ntypedef arith_entropy_encoder * arith_entropy_ptr;\n\n/* The following two definitions specify the allocation chunk size\n * for the statistics area.\n * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least\n * 49 statistics bins for DC, and 245 statistics bins for AC coding.\n *\n * We use a compact representation with 1 byte per statistics bin,\n * thus the numbers directly represent byte sizes.\n * This 1 byte per statistics bin contains the meaning of the MPS\n * (more probable symbol) in the highest bit (mask 0x80), and the\n * index into the probability estimation state machine table\n * in the lower bits (mask 0x7F).\n */\n\n#define DC_STAT_BINS 64\n#define AC_STAT_BINS 256\n\n/* NOTE: Uncomment the following #define if you want to use the\n * given formula for calculating the AC conditioning parameter Kx\n * for spectral selection progressive coding in section G.1.3.2\n * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).\n * Although the spec and P&M authors claim that this \"has proven\n * to give good results for 8 bit precision samples\", I'm not\n * convinced yet that this is really beneficial.\n * Early tests gave only very marginal compression enhancements\n * (a few - around 5 or so - bytes even for very large files),\n * which would turn out rather negative if we'd suppress the\n * DAC (Define Arithmetic Conditioning) marker segments for\n * the default parameters in the future.\n * Note that currently the marker writing module emits 12-byte\n * DAC segments for a full-component scan in a color image.\n * This is not worth worrying about IMHO. However, since the\n * spec defines the default values to be used if the tables\n * are omitted (unlike Huffman tables, which are required\n * anyway), one might optimize this behaviour in the future,\n * and then it would be disadvantageous to use custom tables if\n * they don't provide sufficient gain to exceed the DAC size.\n *\n * On the other hand, I'd consider it as a reasonable result\n * that the conditioning has no significant influence on the\n * compression performance. This means that the basic\n * statistical model is already rather stable.\n *\n * Thus, at the moment, we use the default conditioning values\n * anyway, and do not use the custom formula.\n *\n#define CALCULATE_SPECTRAL_CONDITIONING\n */\n\n/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.\n * We assume that int right shift is unsigned if INT32 right shift is,\n * which should be safe.\n */\n\n#ifdef RIGHT_SHIFT_IS_UNSIGNED\n#define ISHIFT_TEMPS\tint ishift_temp;\n#define IRIGHT_SHIFT(x,shft)  \\\n\t((ishift_temp = (x)) < 0 ? \\\n\t (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \\\n\t (ishift_temp >> (shft)))\n#else\n#define ISHIFT_TEMPS\n#define IRIGHT_SHIFT(x,shft)\t((x) >> (shft))\n#endif\n\n\nLOCAL(void)\nemit_byte (int val, j_compress_ptr cinfo)\n/* Write next output byte; we do not support suspension in this module. */\n{\n  struct jpeg_destination_mgr * dest = cinfo->dest;\n\n  *dest->next_output_byte++ = (JOCTET) val;\n  if (--dest->free_in_buffer == 0)\n    if (! (*dest->empty_output_buffer) (cinfo))\n      ERREXIT(cinfo, JERR_CANT_SUSPEND);\n}\n\n\n/*\n * Finish up at the end of an arithmetic-compressed scan.\n */\n\nMETHODDEF(void)\nfinish_pass (j_compress_ptr cinfo)\n{\n  arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;\n  INT32 temp;\n\n  /* Section D.1.8: Termination of encoding */\n\n  /* Find the e->c in the coding interval with the largest\n   * number of trailing zero bits */\n  if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)\n    e->c = temp + 0x8000L;\n  else\n    e->c = temp;\n  /* Send remaining bytes to output */\n  e->c <<= e->ct;\n  if (e->c & 0xF8000000L) {\n    /* One final overflow has to be handled */\n    if (e->buffer >= 0) {\n      if (e->zc)\n\tdo emit_byte(0x00, cinfo);\n\twhile (--e->zc);\n      emit_byte(e->buffer + 1, cinfo);\n      if (e->buffer + 1 == 0xFF)\n\temit_byte(0x00, cinfo);\n    }\n    e->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */\n    e->sc = 0;\n  } else {\n    if (e->buffer == 0)\n      ++e->zc;\n    else if (e->buffer >= 0) {\n      if (e->zc)\n\tdo emit_byte(0x00, cinfo);\n\twhile (--e->zc);\n      emit_byte(e->buffer, cinfo);\n    }\n    if (e->sc) {\n      if (e->zc)\n\tdo emit_byte(0x00, cinfo);\n\twhile (--e->zc);\n      do {\n\temit_byte(0xFF, cinfo);\n\temit_byte(0x00, cinfo);\n      } while (--e->sc);\n    }\n  }\n  /* Output final bytes only if they are not 0x00 */\n  if (e->c & 0x7FFF800L) {\n    if (e->zc)  /* output final pending zero bytes */\n      do emit_byte(0x00, cinfo);\n      while (--e->zc);\n    emit_byte((int) ((e->c >> 19) & 0xFF), cinfo);\n    if (((e->c >> 19) & 0xFF) == 0xFF)\n      emit_byte(0x00, cinfo);\n    if (e->c & 0x7F800L) {\n      emit_byte((int) ((e->c >> 11) & 0xFF), cinfo);\n      if (((e->c >> 11) & 0xFF) == 0xFF)\n\temit_byte(0x00, cinfo);\n    }\n  }\n}\n\n\n/*\n * The core arithmetic encoding routine (common in JPEG and JBIG).\n * This needs to go as fast as possible.\n * Machine-dependent optimization facilities\n * are not utilized in this portable implementation.\n * However, this code should be fairly efficient and\n * may be a good base for further optimizations anyway.\n *\n * Parameter 'val' to be encoded may be 0 or 1 (binary decision).\n *\n * Note: I've added full \"Pacman\" termination support to the\n * byte output routines, which is equivalent to the optional\n * Discard_final_zeros procedure (Figure D.15) in the spec.\n * Thus, we always produce the shortest possible output\n * stream compliant to the spec (no trailing zero bytes,\n * except for FF stuffing).\n *\n * I've also introduced a new scheme for accessing\n * the probability estimation state machine table,\n * derived from Markus Kuhn's JBIG implementation.\n */\n\nLOCAL(void)\narith_encode (j_compress_ptr cinfo, unsigned char *st, int val) \n{\n  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;\n  register unsigned char nl, nm;\n  register INT32 qe, temp;\n  register int sv;\n\n  /* Fetch values from our compact representation of Table D.3(D.2):\n   * Qe values and probability estimation state machine\n   */\n  sv = *st;\n  qe = jpeg_aritab[sv & 0x7F];\t/* => Qe_Value */\n  nl = qe & 0xFF; qe >>= 8;\t/* Next_Index_LPS + Switch_MPS */\n  nm = qe & 0xFF; qe >>= 8;\t/* Next_Index_MPS */\n\n  /* Encode & estimation procedures per sections D.1.4 & D.1.5 */\n  e->a -= qe;\n  if (val != (sv >> 7)) {\n    /* Encode the less probable symbol */\n    if (e->a >= qe) {\n      /* If the interval size (qe) for the less probable symbol (LPS)\n       * is larger than the interval size for the MPS, then exchange\n       * the two symbols for coding efficiency, otherwise code the LPS\n       * as usual: */\n      e->c += e->a;\n      e->a = qe;\n    }\n    *st = (sv & 0x80) ^ nl;\t/* Estimate_after_LPS */\n  } else {\n    /* Encode the more probable symbol */\n    if (e->a >= 0x8000L)\n      return;  /* A >= 0x8000 -> ready, no renormalization required */\n    if (e->a < qe) {\n      /* If the interval size (qe) for the less probable symbol (LPS)\n       * is larger than the interval size for the MPS, then exchange\n       * the two symbols for coding efficiency: */\n      e->c += e->a;\n      e->a = qe;\n    }\n    *st = (sv & 0x80) ^ nm;\t/* Estimate_after_MPS */\n  }\n\n  /* Renormalization & data output per section D.1.6 */\n  do {\n    e->a <<= 1;\n    e->c <<= 1;\n    if (--e->ct == 0) {\n      /* Another byte is ready for output */\n      temp = e->c >> 19;\n      if (temp > 0xFF) {\n\t/* Handle overflow over all stacked 0xFF bytes */\n\tif (e->buffer >= 0) {\n\t  if (e->zc)\n\t    do emit_byte(0x00, cinfo);\n\t    while (--e->zc);\n\t  emit_byte(e->buffer + 1, cinfo);\n\t  if (e->buffer + 1 == 0xFF)\n\t    emit_byte(0x00, cinfo);\n\t}\n\te->zc += e->sc;  /* carry-over converts stacked 0xFF bytes to 0x00 */\n\te->sc = 0;\n\t/* Note: The 3 spacer bits in the C register guarantee\n\t * that the new buffer byte can't be 0xFF here\n\t * (see page 160 in the P&M JPEG book). */\n\t/* New output byte, might overflow later */\n\te->buffer = (int) (temp & 0xFF);\n      } else if (temp == 0xFF) {\n\t++e->sc;  /* stack 0xFF byte (which might overflow later) */\n      } else {\n\t/* Output all stacked 0xFF bytes, they will not overflow any more */\n\tif (e->buffer == 0)\n\t  ++e->zc;\n\telse if (e->buffer >= 0) {\n\t  if (e->zc)\n\t    do emit_byte(0x00, cinfo);\n\t    while (--e->zc);\n\t  emit_byte(e->buffer, cinfo);\n\t}\n\tif (e->sc) {\n\t  if (e->zc)\n\t    do emit_byte(0x00, cinfo);\n\t    while (--e->zc);\n\t  do {\n\t    emit_byte(0xFF, cinfo);\n\t    emit_byte(0x00, cinfo);\n\t  } while (--e->sc);\n\t}\n\t/* New output byte (can still overflow) */\n\te->buffer = (int) (temp & 0xFF);\n      }\n      e->c &= 0x7FFFFL;\n      e->ct += 8;\n    }\n  } while (e->a < 0x8000L);\n}\n\n\n/*\n * Emit a restart marker & resynchronize predictions.\n */\n\nLOCAL(void)\nemit_restart (j_compress_ptr cinfo, int restart_num)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  int ci;\n  jpeg_component_info * compptr;\n\n  finish_pass(cinfo);\n\n  emit_byte(0xFF, cinfo);\n  emit_byte(JPEG_RST0 + restart_num, cinfo);\n\n  /* Re-initialize statistics areas */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    /* DC needs no table for refinement scan */\n    if (cinfo->Ss == 0 && cinfo->Ah == 0) {\n      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);\n      /* Reset DC predictions to 0 */\n      entropy->last_dc_val[ci] = 0;\n      entropy->dc_context[ci] = 0;\n    }\n    /* AC needs no table when not present */\n    if (cinfo->Se) {\n      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);\n    }\n  }\n\n  /* Reset arithmetic encoding variables */\n  entropy->c = 0;\n  entropy->a = 0x10000L;\n  entropy->sc = 0;\n  entropy->zc = 0;\n  entropy->ct = 11;\n  entropy->buffer = -1;  /* empty */\n}\n\n\n/*\n * MCU encoding for DC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\nencode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  unsigned char *st;\n  int blkn, ci, tbl;\n  int v, v2, m;\n  ISHIFT_TEMPS\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      emit_restart(cinfo, entropy->next_restart_num);\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    ci = cinfo->MCU_membership[blkn];\n    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;\n\n    /* Compute the DC value after the required point transform by Al.\n     * This is simply an arithmetic right shift.\n     */\n    m = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al);\n\n    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */\n\n    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */\n    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];\n\n    /* Figure F.4: Encode_DC_DIFF */\n    if ((v = m - entropy->last_dc_val[ci]) == 0) {\n      arith_encode(cinfo, st, 0);\n      entropy->dc_context[ci] = 0;\t/* zero diff category */\n    } else {\n      entropy->last_dc_val[ci] = m;\n      arith_encode(cinfo, st, 1);\n      /* Figure F.6: Encoding nonzero value v */\n      /* Figure F.7: Encoding the sign of v */\n      if (v > 0) {\n\tarith_encode(cinfo, st + 1, 0);\t/* Table F.4: SS = S0 + 1 */\n\tst += 2;\t\t\t/* Table F.4: SP = S0 + 2 */\n\tentropy->dc_context[ci] = 4;\t/* small positive diff category */\n      } else {\n\tv = -v;\n\tarith_encode(cinfo, st + 1, 1);\t/* Table F.4: SS = S0 + 1 */\n\tst += 3;\t\t\t/* Table F.4: SN = S0 + 3 */\n\tentropy->dc_context[ci] = 8;\t/* small negative diff category */\n      }\n      /* Figure F.8: Encoding the magnitude category of v */\n      m = 0;\n      if (v -= 1) {\n\tarith_encode(cinfo, st, 1);\n\tm = 1;\n\tv2 = v;\n\tst = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */\n\twhile (v2 >>= 1) {\n\t  arith_encode(cinfo, st, 1);\n\t  m <<= 1;\n\t  st += 1;\n\t}\n      }\n      arith_encode(cinfo, st, 0);\n      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */\n      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))\n\tentropy->dc_context[ci] = 0;\t/* zero diff category */\n      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))\n\tentropy->dc_context[ci] += 8;\t/* large diff category */\n      /* Figure F.9: Encoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tarith_encode(cinfo, st, (m & v) ? 1 : 0);\n    }\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for AC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\nencode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  JBLOCKROW block;\n  unsigned char *st;\n  int tbl, k, ke;\n  int v, v2, m;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      emit_restart(cinfo, entropy->next_restart_num);\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  natural_order = cinfo->natural_order;\n\n  /* Encode the MCU data block */\n  block = MCU_data[0];\n  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;\n\n  /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */\n\n  /* Establish EOB (end-of-block) index */\n  ke = cinfo->Se;\n  do {\n    /* We must apply the point transform by Al.  For AC coefficients this\n     * is an integer division with rounding towards 0.  To do this portably\n     * in C, we shift after obtaining the absolute value.\n     */\n    if ((v = (*block)[natural_order[ke]]) >= 0) {\n      if (v >>= cinfo->Al) break;\n    } else {\n      v = -v;\n      if (v >>= cinfo->Al) break;\n    }\n  } while (--ke);\n\n  /* Figure F.5: Encode_AC_Coefficients */\n  for (k = cinfo->Ss - 1; k < ke;) {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    arith_encode(cinfo, st, 0);\t\t/* EOB decision */\n    for (;;) {\n      if ((v = (*block)[natural_order[++k]]) >= 0) {\n\tif (v >>= cinfo->Al) {\n\t  arith_encode(cinfo, st + 1, 1);\n\t  arith_encode(cinfo, entropy->fixed_bin, 0);\n\t  break;\n\t}\n      } else {\n\tv = -v;\n\tif (v >>= cinfo->Al) {\n\t  arith_encode(cinfo, st + 1, 1);\n\t  arith_encode(cinfo, entropy->fixed_bin, 1);\n\t  break;\n\t}\n      }\n      arith_encode(cinfo, st + 1, 0);\n      st += 3;\n    }\n    st += 2;\n    /* Figure F.8: Encoding the magnitude category of v */\n    m = 0;\n    if (v -= 1) {\n      arith_encode(cinfo, st, 1);\n      m = 1;\n      v2 = v;\n      if (v2 >>= 1) {\n\tarith_encode(cinfo, st, 1);\n\tm <<= 1;\n\tst = entropy->ac_stats[tbl] +\n\t     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);\n\twhile (v2 >>= 1) {\n\t  arith_encode(cinfo, st, 1);\n\t  m <<= 1;\n\t  st += 1;\n\t}\n      }\n    }\n    arith_encode(cinfo, st, 0);\n    /* Figure F.9: Encoding the magnitude bit pattern of v */\n    st += 14;\n    while (m >>= 1)\n      arith_encode(cinfo, st, (m & v) ? 1 : 0);\n  }\n  /* Encode EOB decision only if k < cinfo->Se */\n  if (k < cinfo->Se) {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    arith_encode(cinfo, st, 1);\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for DC successive approximation refinement scan.\n * Note: we assume such scans can be multi-component,\n * although the spec is not very clear on the point.\n */\n\nMETHODDEF(boolean)\nencode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  unsigned char *st;\n  int Al, blkn;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      emit_restart(cinfo, entropy->next_restart_num);\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  st = entropy->fixed_bin;\t/* use fixed probability estimation */\n  Al = cinfo->Al;\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    /* We simply emit the Al'th bit of the DC coefficient value. */\n    arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for AC successive approximation refinement scan.\n */\n\nMETHODDEF(boolean)\nencode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  JBLOCKROW block;\n  unsigned char *st;\n  int tbl, k, ke, kex;\n  int v;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      emit_restart(cinfo, entropy->next_restart_num);\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  natural_order = cinfo->natural_order;\n\n  /* Encode the MCU data block */\n  block = MCU_data[0];\n  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;\n\n  /* Section G.1.3.3: Encoding of AC coefficients */\n\n  /* Establish EOB (end-of-block) index */\n  ke = cinfo->Se;\n  do {\n    /* We must apply the point transform by Al.  For AC coefficients this\n     * is an integer division with rounding towards 0.  To do this portably\n     * in C, we shift after obtaining the absolute value.\n     */\n    if ((v = (*block)[natural_order[ke]]) >= 0) {\n      if (v >>= cinfo->Al) break;\n    } else {\n      v = -v;\n      if (v >>= cinfo->Al) break;\n    }\n  } while (--ke);\n\n  /* Establish EOBx (previous stage end-of-block) index */\n  for (kex = ke; kex > 0; kex--)\n    if ((v = (*block)[natural_order[kex]]) >= 0) {\n      if (v >>= cinfo->Ah) break;\n    } else {\n      v = -v;\n      if (v >>= cinfo->Ah) break;\n    }\n\n  /* Figure G.10: Encode_AC_Coefficients_SA */\n  for (k = cinfo->Ss - 1; k < ke;) {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    if (k >= kex)\n      arith_encode(cinfo, st, 0);\t/* EOB decision */\n    for (;;) {\n      if ((v = (*block)[natural_order[++k]]) >= 0) {\n\tif (v >>= cinfo->Al) {\n\t  if (v >> 1)\t\t\t/* previously nonzero coef */\n\t    arith_encode(cinfo, st + 2, (v & 1));\n\t  else {\t\t\t/* newly nonzero coef */\n\t    arith_encode(cinfo, st + 1, 1);\n\t    arith_encode(cinfo, entropy->fixed_bin, 0);\n\t  }\n\t  break;\n\t}\n      } else {\n\tv = -v;\n\tif (v >>= cinfo->Al) {\n\t  if (v >> 1)\t\t\t/* previously nonzero coef */\n\t    arith_encode(cinfo, st + 2, (v & 1));\n\t  else {\t\t\t/* newly nonzero coef */\n\t    arith_encode(cinfo, st + 1, 1);\n\t    arith_encode(cinfo, entropy->fixed_bin, 1);\n\t  }\n\t  break;\n\t}\n      }\n      arith_encode(cinfo, st + 1, 0);\n      st += 3;\n    }\n  }\n  /* Encode EOB decision only if k < cinfo->Se */\n  if (k < cinfo->Se) {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    arith_encode(cinfo, st, 1);\n  }\n\n  return TRUE;\n}\n\n\n/*\n * Encode and output one MCU's worth of arithmetic-compressed coefficients.\n */\n\nMETHODDEF(boolean)\nencode_mcu (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  JBLOCKROW block;\n  unsigned char *st;\n  int tbl, k, ke;\n  int v, v2, m;\n  int blkn, ci;\n  jpeg_component_info * compptr;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      emit_restart(cinfo, entropy->next_restart_num);\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  natural_order = cinfo->natural_order;\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    block = MCU_data[blkn];\n    ci = cinfo->MCU_membership[blkn];\n    compptr = cinfo->cur_comp_info[ci];\n\n    /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */\n\n    tbl = compptr->dc_tbl_no;\n\n    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */\n    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];\n\n    /* Figure F.4: Encode_DC_DIFF */\n    if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {\n      arith_encode(cinfo, st, 0);\n      entropy->dc_context[ci] = 0;\t/* zero diff category */\n    } else {\n      entropy->last_dc_val[ci] = (*block)[0];\n      arith_encode(cinfo, st, 1);\n      /* Figure F.6: Encoding nonzero value v */\n      /* Figure F.7: Encoding the sign of v */\n      if (v > 0) {\n\tarith_encode(cinfo, st + 1, 0);\t/* Table F.4: SS = S0 + 1 */\n\tst += 2;\t\t\t/* Table F.4: SP = S0 + 2 */\n\tentropy->dc_context[ci] = 4;\t/* small positive diff category */\n      } else {\n\tv = -v;\n\tarith_encode(cinfo, st + 1, 1);\t/* Table F.4: SS = S0 + 1 */\n\tst += 3;\t\t\t/* Table F.4: SN = S0 + 3 */\n\tentropy->dc_context[ci] = 8;\t/* small negative diff category */\n      }\n      /* Figure F.8: Encoding the magnitude category of v */\n      m = 0;\n      if (v -= 1) {\n\tarith_encode(cinfo, st, 1);\n\tm = 1;\n\tv2 = v;\n\tst = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */\n\twhile (v2 >>= 1) {\n\t  arith_encode(cinfo, st, 1);\n\t  m <<= 1;\n\t  st += 1;\n\t}\n      }\n      arith_encode(cinfo, st, 0);\n      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */\n      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))\n\tentropy->dc_context[ci] = 0;\t/* zero diff category */\n      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))\n\tentropy->dc_context[ci] += 8;\t/* large diff category */\n      /* Figure F.9: Encoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tarith_encode(cinfo, st, (m & v) ? 1 : 0);\n    }\n\n    /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */\n\n    if ((ke = cinfo->lim_Se) == 0) continue;\n    tbl = compptr->ac_tbl_no;\n\n    /* Establish EOB (end-of-block) index */\n    do {\n      if ((*block)[natural_order[ke]]) break;\n    } while (--ke);\n\n    /* Figure F.5: Encode_AC_Coefficients */\n    for (k = 0; k < ke;) {\n      st = entropy->ac_stats[tbl] + 3 * k;\n      arith_encode(cinfo, st, 0);\t/* EOB decision */\n      while ((v = (*block)[natural_order[++k]]) == 0) {\n\tarith_encode(cinfo, st + 1, 0);\n\tst += 3;\n      }\n      arith_encode(cinfo, st + 1, 1);\n      /* Figure F.6: Encoding nonzero value v */\n      /* Figure F.7: Encoding the sign of v */\n      if (v > 0) {\n\tarith_encode(cinfo, entropy->fixed_bin, 0);\n      } else {\n\tv = -v;\n\tarith_encode(cinfo, entropy->fixed_bin, 1);\n      }\n      st += 2;\n      /* Figure F.8: Encoding the magnitude category of v */\n      m = 0;\n      if (v -= 1) {\n\tarith_encode(cinfo, st, 1);\n\tm = 1;\n\tv2 = v;\n\tif (v2 >>= 1) {\n\t  arith_encode(cinfo, st, 1);\n\t  m <<= 1;\n\t  st = entropy->ac_stats[tbl] +\n\t       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);\n\t  while (v2 >>= 1) {\n\t    arith_encode(cinfo, st, 1);\n\t    m <<= 1;\n\t    st += 1;\n\t  }\n\t}\n      }\n      arith_encode(cinfo, st, 0);\n      /* Figure F.9: Encoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tarith_encode(cinfo, st, (m & v) ? 1 : 0);\n    }\n    /* Encode EOB decision only if k < cinfo->lim_Se */\n    if (k < cinfo->lim_Se) {\n      st = entropy->ac_stats[tbl] + 3 * k;\n      arith_encode(cinfo, st, 1);\n    }\n  }\n\n  return TRUE;\n}\n\n\n/*\n * Initialize for an arithmetic-compressed scan.\n */\n\nMETHODDEF(void)\nstart_pass (j_compress_ptr cinfo, boolean gather_statistics)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  int ci, tbl;\n  jpeg_component_info * compptr;\n\n  if (gather_statistics)\n    /* Make sure to avoid that in the master control logic!\n     * We are fully adaptive here and need no extra\n     * statistics gathering pass!\n     */\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n\n  /* We assume jcmaster.c already validated the progressive scan parameters. */\n\n  /* Select execution routines */\n  if (cinfo->progressive_mode) {\n    if (cinfo->Ah == 0) {\n      if (cinfo->Ss == 0)\n\tentropy->pub.encode_mcu = encode_mcu_DC_first;\n      else\n\tentropy->pub.encode_mcu = encode_mcu_AC_first;\n    } else {\n      if (cinfo->Ss == 0)\n\tentropy->pub.encode_mcu = encode_mcu_DC_refine;\n      else\n\tentropy->pub.encode_mcu = encode_mcu_AC_refine;\n    }\n  } else\n    entropy->pub.encode_mcu = encode_mcu;\n\n  /* Allocate & initialize requested statistics areas */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    /* DC needs no table for refinement scan */\n    if (cinfo->Ss == 0 && cinfo->Ah == 0) {\n      tbl = compptr->dc_tbl_no;\n      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)\n\tERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);\n      if (entropy->dc_stats[tbl] == NULL)\n\tentropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)\n\t  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);\n      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);\n      /* Initialize DC predictions to 0 */\n      entropy->last_dc_val[ci] = 0;\n      entropy->dc_context[ci] = 0;\n    }\n    /* AC needs no table when not present */\n    if (cinfo->Se) {\n      tbl = compptr->ac_tbl_no;\n      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)\n\tERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);\n      if (entropy->ac_stats[tbl] == NULL)\n\tentropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)\n\t  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);\n      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);\n#ifdef CALCULATE_SPECTRAL_CONDITIONING\n      if (cinfo->progressive_mode)\n\t/* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */\n\tcinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);\n#endif\n    }\n  }\n\n  /* Initialize arithmetic encoding variables */\n  entropy->c = 0;\n  entropy->a = 0x10000L;\n  entropy->sc = 0;\n  entropy->zc = 0;\n  entropy->ct = 11;\n  entropy->buffer = -1;  /* empty */\n\n  /* Initialize restart stuff */\n  entropy->restarts_to_go = cinfo->restart_interval;\n  entropy->next_restart_num = 0;\n}\n\n\n/*\n * Module initialization routine for arithmetic entropy encoding.\n */\n\nGLOBAL(void)\njinit_arith_encoder (j_compress_ptr cinfo)\n{\n  arith_entropy_ptr entropy;\n  int i;\n\n  entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(arith_entropy_encoder));\n  cinfo->entropy = &entropy->pub;\n  entropy->pub.start_pass = start_pass;\n  entropy->pub.finish_pass = finish_pass;\n\n  /* Mark tables unallocated */\n  for (i = 0; i < NUM_ARITH_TBLS; i++) {\n    entropy->dc_stats[i] = NULL;\n    entropy->ac_stats[i] = NULL;\n  }\n\n  /* Initialize index for fixed probability estimation */\n  entropy->fixed_bin[0] = 113;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jccoefct.c",
    "content": "/*\n * jccoefct.c\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the coefficient buffer controller for compression.\n * This controller is the top level of the JPEG compressor proper.\n * The coefficient buffer lies between forward-DCT and entropy encoding steps.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* We use a full-image coefficient buffer when doing Huffman optimization,\n * and also for writing multiple-scan JPEG files.  In all cases, the DCT\n * step is run during the first pass, and subsequent passes need only read\n * the buffered coefficients.\n */\n#ifdef ENTROPY_OPT_SUPPORTED\n#define FULL_COEF_BUFFER_SUPPORTED\n#else\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n#define FULL_COEF_BUFFER_SUPPORTED\n#endif\n#endif\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_c_coef_controller pub; /* public fields */\n\n  JDIMENSION iMCU_row_num;\t/* iMCU row # within image */\n  JDIMENSION MCU_ctr;\t\t/* counts MCUs processed in current row */\n  int MCU_vert_offset;\t\t/* counts MCU rows within iMCU row */\n  int MCU_rows_per_iMCU_row;\t/* number of such rows needed */\n\n  /* For single-pass compression, it's sufficient to buffer just one MCU\n   * (although this may prove a bit slow in practice).  We append a\n   * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it\n   * for each MCU constructed and sent.\n   * In multi-pass modes, this array points to the current MCU's blocks\n   * within the virtual arrays.\n   */\n  JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];\n\n  /* In multi-pass modes, we need a virtual block array for each component. */\n  jvirt_barray_ptr whole_image[MAX_COMPONENTS];\n\n  /* Workspace for single-pass compression (omitted otherwise). */\n  JBLOCK blk_buffer[C_MAX_BLOCKS_IN_MCU];\n} my_coef_controller;\n\ntypedef my_coef_controller * my_coef_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(boolean) compress_data\n    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));\n#ifdef FULL_COEF_BUFFER_SUPPORTED\nMETHODDEF(boolean) compress_first_pass\n    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));\nMETHODDEF(boolean) compress_output\n    JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));\n#endif\n\n\nLOCAL(void)\nstart_iMCU_row (j_compress_ptr cinfo)\n/* Reset within-iMCU-row counters for a new row */\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  /* In an interleaved scan, an MCU row is the same as an iMCU row.\n   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.\n   * But at the bottom of the image, process only what's left.\n   */\n  if (cinfo->comps_in_scan > 1) {\n    coef->MCU_rows_per_iMCU_row = 1;\n  } else {\n    if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;\n    else\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;\n  }\n\n  coef->MCU_ctr = 0;\n  coef->MCU_vert_offset = 0;\n}\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  coef->iMCU_row_num = 0;\n  start_iMCU_row(cinfo);\n\n  switch (pass_mode) {\n  case JBUF_PASS_THRU:\n    if (coef->whole_image[0] != NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    coef->pub.compress_data = compress_data;\n    break;\n#ifdef FULL_COEF_BUFFER_SUPPORTED\n  case JBUF_SAVE_AND_PASS:\n    if (coef->whole_image[0] == NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    coef->pub.compress_data = compress_first_pass;\n    break;\n  case JBUF_CRANK_DEST:\n    if (coef->whole_image[0] == NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    coef->pub.compress_data = compress_output;\n    break;\n#endif\n  default:\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n  }\n}\n\n\n/*\n * Process some data in the single-pass case.\n * We process the equivalent of one fully interleaved MCU row (\"iMCU\" row)\n * per call, ie, v_samp_factor block rows for each component in the image.\n * Returns TRUE if the iMCU row is completed, FALSE if suspended.\n *\n * NB: input_buf contains a plane for each component in image,\n * which we index according to the component's SOF position.\n */\n\nMETHODDEF(boolean)\ncompress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION MCU_col_num;\t/* index of current MCU within row */\n  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  int ci, xindex, yindex, yoffset, blockcnt;\n  JBLOCKROW blkp;\n  JSAMPARRAY input_ptr;\n  JDIMENSION xpos;\n  jpeg_component_info *compptr;\n  forward_DCT_ptr forward_DCT;\n\n  /* Loop to write as much as one whole iMCU row */\n  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;\n       yoffset++) {\n    for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;\n\t MCU_col_num++) {\n      /* Determine where data comes from in input_buf and do the DCT thing.\n       * Each call on forward_DCT processes a horizontal row of DCT blocks as\n       * wide as an MCU.  Dummy blocks at the right or bottom edge are filled in\n       * specially.  The data in them does not matter for image reconstruction,\n       * so we fill them with values that will encode to the smallest amount of\n       * data, viz: all zeroes in the AC entries, DC entries equal to previous\n       * block's DC value.  (Thanks to Thomas Kinsman for this idea.)\n       */\n      blkp = coef->blk_buffer;\t/* pointer to current DCT block within MCU */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n\tcompptr = cinfo->cur_comp_info[ci];\n\tforward_DCT = cinfo->fdct->forward_DCT[compptr->component_index];\n\tinput_ptr = input_buf[compptr->component_index] +\n\t  yoffset * compptr->DCT_v_scaled_size;\n\t/* ypos == (yoffset + yindex) * compptr->DCT_v_scaled_size */\n\tblockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width\n\t\t\t\t\t\t: compptr->last_col_width;\n\txpos = MCU_col_num * compptr->MCU_sample_width;\n\tfor (yindex = 0; yindex < compptr->MCU_height; yindex++) {\n\t  if (coef->iMCU_row_num < last_iMCU_row ||\n\t      yoffset + yindex < compptr->last_row_height) {\n\t    (*forward_DCT) (cinfo, compptr, input_ptr, blkp,\n\t\t\t    xpos, (JDIMENSION) blockcnt);\n\t    input_ptr += compptr->DCT_v_scaled_size;\n\t    blkp += blockcnt;\n\t    /* Dummy blocks at right edge */\n\t    if ((xindex = compptr->MCU_width - blockcnt) == 0)\n\t      continue;\n\t  } else {\n\t    /* At bottom of image, need a whole row of dummy blocks */\n\t    xindex = compptr->MCU_width;\n\t  }\n\t  /* Fill in any dummy blocks needed in this row */\n\t  MEMZERO(blkp, xindex * SIZEOF(JBLOCK));\n\t  do {\n\t    blkp[0][0] = blkp[-1][0];\n\t    blkp++;\n\t  } while (--xindex);\n\t}\n      }\n      /* Try to write the MCU.  In event of a suspension failure, we will\n       * re-DCT the MCU on restart (a bit inefficient, could be fixed...)\n       */\n      if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {\n\t/* Suspension forced; update state counters and exit */\n\tcoef->MCU_vert_offset = yoffset;\n\tcoef->MCU_ctr = MCU_col_num;\n\treturn FALSE;\n      }\n    }\n    /* Completed an MCU row, but perhaps not an iMCU row */\n    coef->MCU_ctr = 0;\n  }\n  /* Completed the iMCU row, advance counters for next one */\n  coef->iMCU_row_num++;\n  start_iMCU_row(cinfo);\n  return TRUE;\n}\n\n\n#ifdef FULL_COEF_BUFFER_SUPPORTED\n\n/*\n * Process some data in the first pass of a multi-pass case.\n * We process the equivalent of one fully interleaved MCU row (\"iMCU\" row)\n * per call, ie, v_samp_factor block rows for each component in the image.\n * This amount of data is read from the source buffer, DCT'd and quantized,\n * and saved into the virtual arrays.  We also generate suitable dummy blocks\n * as needed at the right and lower edges.  (The dummy blocks are constructed\n * in the virtual arrays, which have been padded appropriately.)  This makes\n * it possible for subsequent passes not to worry about real vs. dummy blocks.\n *\n * We must also emit the data to the entropy encoder.  This is conveniently\n * done by calling compress_output() after we've loaded the current strip\n * of the virtual arrays.\n *\n * NB: input_buf contains a plane for each component in image.  All\n * components are DCT'd and loaded into the virtual arrays in this pass.\n * However, it may be that only a subset of the components are emitted to\n * the entropy encoder during this first pass; be careful about looking\n * at the scan-dependent variables (MCU dimensions, etc).\n */\n\nMETHODDEF(boolean)\ncompress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  JDIMENSION blocks_across, MCUs_across, MCUindex;\n  int bi, ci, h_samp_factor, block_row, block_rows, ndummy;\n  JCOEF lastDC;\n  jpeg_component_info *compptr;\n  JBLOCKARRAY buffer;\n  JBLOCKROW thisblockrow, lastblockrow;\n  JSAMPARRAY input_ptr;\n  forward_DCT_ptr forward_DCT;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Align the virtual buffer for this component. */\n    buffer = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef->whole_image[ci],\n       coef->iMCU_row_num * compptr->v_samp_factor,\n       (JDIMENSION) compptr->v_samp_factor, TRUE);\n    /* Count non-dummy DCT block rows in this iMCU row. */\n    if (coef->iMCU_row_num < last_iMCU_row)\n      block_rows = compptr->v_samp_factor;\n    else {\n      /* NB: can't use last_row_height here, since may not be set! */\n      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);\n      if (block_rows == 0) block_rows = compptr->v_samp_factor;\n    }\n    blocks_across = compptr->width_in_blocks;\n    h_samp_factor = compptr->h_samp_factor;\n    /* Count number of dummy blocks to be added at the right margin. */\n    ndummy = (int) (blocks_across % h_samp_factor);\n    if (ndummy > 0)\n      ndummy = h_samp_factor - ndummy;\n    forward_DCT = cinfo->fdct->forward_DCT[ci];\n    input_ptr = input_buf[ci];\n    /* Perform DCT for all non-dummy blocks in this iMCU row.  Each call\n     * on forward_DCT processes a complete horizontal row of DCT blocks.\n     */\n    for (block_row = 0; block_row < block_rows; block_row++) {\n      thisblockrow = buffer[block_row];\n      (*forward_DCT) (cinfo, compptr, input_ptr, thisblockrow,\n\t\t      (JDIMENSION) 0, blocks_across);\n      input_ptr += compptr->DCT_v_scaled_size;\n      if (ndummy > 0) {\n\t/* Create dummy blocks at the right edge of the image. */\n\tthisblockrow += blocks_across; /* => first dummy block */\n\tFMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));\n\tlastDC = thisblockrow[-1][0];\n\tfor (bi = 0; bi < ndummy; bi++) {\n\t  thisblockrow[bi][0] = lastDC;\n\t}\n      }\n    }\n    /* If at end of image, create dummy block rows as needed.\n     * The tricky part here is that within each MCU, we want the DC values\n     * of the dummy blocks to match the last real block's DC value.\n     * This squeezes a few more bytes out of the resulting file...\n     */\n    if (block_row < compptr->v_samp_factor) {\n      blocks_across += ndummy;\t/* include lower right corner */\n      MCUs_across = blocks_across / h_samp_factor;\n      do {\n\tthisblockrow = buffer[block_row];\n\tlastblockrow = buffer[block_row-1];\n\tFMEMZERO((void FAR *) thisblockrow,\n\t\t (size_t) blocks_across * SIZEOF(JBLOCK));\n\tfor (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {\n\t  lastDC = lastblockrow[h_samp_factor-1][0];\n\t  for (bi = 0; bi < h_samp_factor; bi++) {\n\t    thisblockrow[bi][0] = lastDC;\n\t  }\n\t  thisblockrow += h_samp_factor; /* advance to next MCU in row */\n\t  lastblockrow += h_samp_factor;\n\t}\n      } while (++block_row < compptr->v_samp_factor);\n    }\n  }\n  /* NB: compress_output will increment iMCU_row_num if successful.\n   * A suspension return will result in redoing all the work above next time.\n   */\n\n  /* Emit data to the entropy encoder, sharing code with subsequent passes */\n  return compress_output(cinfo, input_buf);\n}\n\n\n/*\n * Process some data in subsequent passes of a multi-pass case.\n * We process the equivalent of one fully interleaved MCU row (\"iMCU\" row)\n * per call, ie, v_samp_factor block rows for each component in the scan.\n * The data is obtained from the virtual arrays and fed to the entropy coder.\n * Returns TRUE if the iMCU row is completed, FALSE if suspended.\n *\n * NB: input_buf is ignored; it is likely to be a NULL pointer.\n */\n\nMETHODDEF(boolean)\ncompress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION MCU_col_num;\t/* index of current MCU within row */\n  int ci, xindex, yindex, yoffset;\n  JDIMENSION start_col;\n  JBLOCKARRAY blkp;\n  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];\n  JBLOCKROW buffer_ptr;\n  jpeg_component_info *compptr;\n\n  /* Align the virtual buffers for the components used in this scan.\n   * NB: during first pass, this is safe only because the buffers will\n   * already be aligned properly, so jmemmgr.c won't need to do any I/O.\n   */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    buffer[ci] = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],\n       coef->iMCU_row_num * compptr->v_samp_factor,\n       (JDIMENSION) compptr->v_samp_factor, FALSE);\n  }\n\n  /* Loop to process one whole iMCU row */\n  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;\n       yoffset++) {\n    for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;\n\t MCU_col_num++) {\n      /* Construct list of pointers to DCT blocks belonging to this MCU */\n      blkp = coef->MCU_buffer;\t/* pointer to current DCT block within MCU */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n\tcompptr = cinfo->cur_comp_info[ci];\n\tstart_col = MCU_col_num * compptr->MCU_width;\n\tfor (yindex = 0; yindex < compptr->MCU_height; yindex++) {\n\t  buffer_ptr = buffer[ci][yoffset + yindex] + start_col;\n\t  xindex = compptr->MCU_width;\n\t  do {\n\t    *blkp++ = buffer_ptr++;\n\t  } while (--xindex);\n\t}\n      }\n      /* Try to write the MCU. */\n      if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {\n\t/* Suspension forced; update state counters and exit */\n\tcoef->MCU_vert_offset = yoffset;\n\tcoef->MCU_ctr = MCU_col_num;\n\treturn FALSE;\n      }\n    }\n    /* Completed an MCU row, but perhaps not an iMCU row */\n    coef->MCU_ctr = 0;\n  }\n  /* Completed the iMCU row, advance counters for next one */\n  coef->iMCU_row_num++;\n  start_iMCU_row(cinfo);\n  return TRUE;\n}\n\n#endif /* FULL_COEF_BUFFER_SUPPORTED */\n\n\n/*\n * Initialize coefficient buffer controller.\n */\n\nGLOBAL(void)\njinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)\n{\n  my_coef_ptr coef;\n\n  if (need_full_buffer) {\n#ifdef FULL_COEF_BUFFER_SUPPORTED\n    /* Allocate a full-image virtual array for each component, */\n    /* padded to a multiple of samp_factor DCT blocks in each direction. */\n    int ci;\n    jpeg_component_info *compptr;\n\n    coef = (my_coef_ptr) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       SIZEOF(my_coef_controller) - SIZEOF(coef->blk_buffer));\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n\t (JDIMENSION) jround_up((long) compptr->width_in_blocks,\n\t\t\t\t(long) compptr->h_samp_factor),\n\t (JDIMENSION) jround_up((long) compptr->height_in_blocks,\n\t\t\t\t(long) compptr->v_samp_factor),\n\t (JDIMENSION) compptr->v_samp_factor);\n    }\n#else\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n#endif\n  } else {\n    /* We only need a single-MCU buffer. */\n    JBLOCKARRAY blkp;\n    JBLOCKROW buffer_ptr;\n    int bi;\n\n    coef = (my_coef_ptr) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller));\n    blkp = coef->MCU_buffer;\n    buffer_ptr = coef->blk_buffer;\n    bi = C_MAX_BLOCKS_IN_MCU;\n    do {\n      *blkp++ = buffer_ptr++;\n    } while (--bi);\n    coef->whole_image[0] = NULL; /* flag for no virtual arrays */\n  }\n\n  coef->pub.start_pass = start_pass_coef;\n  cinfo->coef = &coef->pub;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jccolor.c",
    "content": "/*\n * jccolor.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2011-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains input colorspace conversion routines.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_color_converter pub; /* public fields */\n\n  /* Private state for RGB->YCC conversion */\n  INT32 * rgb_ycc_tab;\t\t/* => table for RGB to YCbCr conversion */\n} my_color_converter;\n\ntypedef my_color_converter * my_cconvert_ptr;\n\n\n/**************** RGB -> YCbCr conversion: most common case **************/\n\n/*\n * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011),\n * previously known as Recommendation CCIR 601-1, except that Cb and Cr\n * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.\n * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999.\n * sYCC (standard luma-chroma-chroma color space with extended gamut)\n * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F.\n * bg-sRGB and bg-sYCC (big gamut standard color spaces)\n * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G.\n * Note that the derived conversion coefficients given in some of these\n * documents are imprecise.  The general conversion equations are\n *\tY  = Kr * R + (1 - Kr - Kb) * G + Kb * B\n *\tCb = 0.5 * (B - Y) / (1 - Kb)\n *\tCr = 0.5 * (R - Y) / (1 - Kr)\n * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993\n * from the 1953 FCC NTSC primaries and CIE Illuminant C),\n * the conversion equations to be implemented are therefore\n *\tY  =  0.299 * R + 0.587 * G + 0.114 * B\n *\tCb = -0.168735892 * R - 0.331264108 * G + 0.5 * B + CENTERJSAMPLE\n *\tCr =  0.5 * R - 0.418687589 * G - 0.081312411 * B + CENTERJSAMPLE\n * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,\n * rather than CENTERJSAMPLE, for Cb and Cr.  This gave equal positive and\n * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)\n * were not represented exactly.  Now we sacrifice exact representation of\n * maximum red and maximum blue in order to get exact grayscales.\n *\n * To avoid floating-point arithmetic, we represent the fractional constants\n * as integers scaled up by 2^16 (about 4 digits precision); we have to divide\n * the products by 2^16, with appropriate rounding, to get the correct answer.\n *\n * For even more speed, we avoid doing any multiplications in the inner loop\n * by precalculating the constants times R,G,B for all possible values.\n * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);\n * for 9-bit to 12-bit samples it is still acceptable.  It's not very\n * reasonable for 16-bit samples, but if you want lossless storage you\n * shouldn't be changing colorspace anyway.\n * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included\n * in the tables to save adding them separately in the inner loop.\n */\n\n#define SCALEBITS\t16\t/* speediest right-shift on some machines */\n#define CBCR_OFFSET\t((INT32) CENTERJSAMPLE << SCALEBITS)\n#define ONE_HALF\t((INT32) 1 << (SCALEBITS-1))\n#define FIX(x)\t\t((INT32) ((x) * (1L<<SCALEBITS) + 0.5))\n\n/* We allocate one big table and divide it up into eight parts, instead of\n * doing eight alloc_small requests.  This lets us use a single table base\n * address, which can be held in a register in the inner loops on many\n * machines (more than can hold all eight addresses, anyway).\n */\n\n#define R_Y_OFF\t\t0\t\t\t/* offset to R => Y section */\n#define G_Y_OFF\t\t(1*(MAXJSAMPLE+1))\t/* offset to G => Y section */\n#define B_Y_OFF\t\t(2*(MAXJSAMPLE+1))\t/* etc. */\n#define R_CB_OFF\t(3*(MAXJSAMPLE+1))\n#define G_CB_OFF\t(4*(MAXJSAMPLE+1))\n#define B_CB_OFF\t(5*(MAXJSAMPLE+1))\n#define R_CR_OFF\tB_CB_OFF\t\t/* B=>Cb, R=>Cr are the same */\n#define G_CR_OFF\t(6*(MAXJSAMPLE+1))\n#define B_CR_OFF\t(7*(MAXJSAMPLE+1))\n#define TABLE_SIZE\t(8*(MAXJSAMPLE+1))\n\n\n/*\n * Initialize for RGB->YCC colorspace conversion.\n */\n\nMETHODDEF(void)\nrgb_ycc_start (j_compress_ptr cinfo)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  INT32 * rgb_ycc_tab;\n  INT32 i;\n\n  /* Allocate and fill in the conversion tables. */\n  cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)\n    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\tTABLE_SIZE * SIZEOF(INT32));\n\n  for (i = 0; i <= MAXJSAMPLE; i++) {\n    rgb_ycc_tab[i+R_Y_OFF] = FIX(0.299) * i;\n    rgb_ycc_tab[i+G_Y_OFF] = FIX(0.587) * i;\n    rgb_ycc_tab[i+B_Y_OFF] = FIX(0.114) * i   + ONE_HALF;\n    rgb_ycc_tab[i+R_CB_OFF] = (- FIX(0.168735892)) * i;\n    rgb_ycc_tab[i+G_CB_OFF] = (- FIX(0.331264108)) * i;\n    /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.\n     * This ensures that the maximum output will round to MAXJSAMPLE\n     * not MAXJSAMPLE+1, and thus that we don't have to range-limit.\n     */\n    rgb_ycc_tab[i+B_CB_OFF] = FIX(0.5) * i    + CBCR_OFFSET + ONE_HALF-1;\n/*  B=>Cb and R=>Cr tables are the same\n    rgb_ycc_tab[i+R_CR_OFF] = FIX(0.5) * i    + CBCR_OFFSET + ONE_HALF-1;\n*/\n    rgb_ycc_tab[i+G_CR_OFF] = (- FIX(0.418687589)) * i;\n    rgb_ycc_tab[i+B_CR_OFF] = (- FIX(0.081312411)) * i;\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n *\n * Note that we change from the application's interleaved-pixel format\n * to our internal noninterleaved, one-plane-per-component format.  The\n * input buffer is therefore three times as wide as the output buffer.\n *\n * A starting row offset is provided only for the output buffer.  The\n * caller can easily adjust the passed input_buf value to accommodate\n * any row offset required on that side.\n */\n\nMETHODDEF(void)\nrgb_ycc_convert (j_compress_ptr cinfo,\n\t\t JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t JDIMENSION output_row, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_ycc_tab;\n  register JSAMPROW inptr;\n  register JSAMPROW outptr0, outptr1, outptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr0 = output_buf[0][output_row];\n    outptr1 = output_buf[1][output_row];\n    outptr2 = output_buf[2][output_row];\n    output_row++;\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr[RGB_RED]);\n      g = GETJSAMPLE(inptr[RGB_GREEN]);\n      b = GETJSAMPLE(inptr[RGB_BLUE]);\n      inptr += RGB_PIXELSIZE;\n      /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations\n       * must be too; we do not need an explicit range-limiting operation.\n       * Hence the value being shifted is never negative, and we don't\n       * need the general RIGHT_SHIFT macro.\n       */\n      /* Y */\n      outptr0[col] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n      /* Cb */\n      outptr1[col] = (JSAMPLE)\n\t\t((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])\n\t\t >> SCALEBITS);\n      /* Cr */\n      outptr2[col] = (JSAMPLE)\n\t\t((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])\n\t\t >> SCALEBITS);\n    }\n  }\n}\n\n\n/**************** Cases other than RGB -> YCbCr **************/\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * This version handles RGB->grayscale conversion, which is the same\n * as the RGB->Y portion of RGB->YCbCr.\n * We assume rgb_ycc_start has been called (we only use the Y tables).\n */\n\nMETHODDEF(void)\nrgb_gray_convert (j_compress_ptr cinfo,\n\t\t  JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t  JDIMENSION output_row, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_ycc_tab;\n  register JSAMPROW inptr;\n  register JSAMPROW outptr;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr = output_buf[0][output_row++];\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr[RGB_RED]);\n      g = GETJSAMPLE(inptr[RGB_GREEN]);\n      b = GETJSAMPLE(inptr[RGB_BLUE]);\n      inptr += RGB_PIXELSIZE;\n      /* Y */\n      outptr[col] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * This version handles Adobe-style CMYK->YCCK conversion,\n * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the\n * same conversion as above, while passing K (black) unchanged.\n * We assume rgb_ycc_start has been called.\n */\n\nMETHODDEF(void)\ncmyk_ycck_convert (j_compress_ptr cinfo,\n\t\t   JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t   JDIMENSION output_row, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_ycc_tab;\n  register JSAMPROW inptr;\n  register JSAMPROW outptr0, outptr1, outptr2, outptr3;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr0 = output_buf[0][output_row];\n    outptr1 = output_buf[1][output_row];\n    outptr2 = output_buf[2][output_row];\n    outptr3 = output_buf[3][output_row];\n    output_row++;\n    for (col = 0; col < num_cols; col++) {\n      r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);\n      g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);\n      b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);\n      /* K passes through as-is */\n      outptr3[col] = inptr[3];\t/* don't need GETJSAMPLE here */\n      inptr += 4;\n      /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations\n       * must be too; we do not need an explicit range-limiting operation.\n       * Hence the value being shifted is never negative, and we don't\n       * need the general RIGHT_SHIFT macro.\n       */\n      /* Y */\n      outptr0[col] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n      /* Cb */\n      outptr1[col] = (JSAMPLE)\n\t\t((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])\n\t\t >> SCALEBITS);\n      /* Cr */\n      outptr2[col] = (JSAMPLE)\n\t\t((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])\n\t\t >> SCALEBITS);\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * [R,G,B] to [R-G,G,B-G] conversion with modulo calculation\n * (forward reversible color transform).\n * This can be seen as an adaption of the general RGB->YCbCr\n * conversion equation with Kr = Kb = 0, while replacing the\n * normalization by modulo calculation.\n */\n\nMETHODDEF(void)\nrgb_rgb1_convert (j_compress_ptr cinfo,\n\t\t  JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t  JDIMENSION output_row, int num_rows)\n{\n  register int r, g, b;\n  register JSAMPROW inptr;\n  register JSAMPROW outptr0, outptr1, outptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr0 = output_buf[0][output_row];\n    outptr1 = output_buf[1][output_row];\n    outptr2 = output_buf[2][output_row];\n    output_row++;\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr[RGB_RED]);\n      g = GETJSAMPLE(inptr[RGB_GREEN]);\n      b = GETJSAMPLE(inptr[RGB_BLUE]);\n      inptr += RGB_PIXELSIZE;\n      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD\n       * (modulo) operator is equivalent to the bitmask operator AND.\n       */\n      outptr0[col] = (JSAMPLE) ((r - g + CENTERJSAMPLE) & MAXJSAMPLE);\n      outptr1[col] = (JSAMPLE) g;\n      outptr2[col] = (JSAMPLE) ((b - g + CENTERJSAMPLE) & MAXJSAMPLE);\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * This version handles grayscale output with no conversion.\n * The source can be either plain grayscale or YCC (since Y == gray).\n */\n\nMETHODDEF(void)\ngrayscale_convert (j_compress_ptr cinfo,\n\t\t   JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t   JDIMENSION output_row, int num_rows)\n{\n  register JSAMPROW inptr;\n  register JSAMPROW outptr;\n  register JDIMENSION count;\n  register int instride = cinfo->input_components;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr = output_buf[0][output_row++];\n    for (count = num_cols; count > 0; count--) {\n      *outptr++ = *inptr;\t/* don't need GETJSAMPLE() here */\n      inptr += instride;\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * No colorspace conversion, but change from interleaved\n * to separate-planes representation.\n */\n\nMETHODDEF(void)\nrgb_convert (j_compress_ptr cinfo,\n\t     JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t     JDIMENSION output_row, int num_rows)\n{\n  register JSAMPROW inptr;\n  register JSAMPROW outptr0, outptr1, outptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->image_width;\n\n  while (--num_rows >= 0) {\n    inptr = *input_buf++;\n    outptr0 = output_buf[0][output_row];\n    outptr1 = output_buf[1][output_row];\n    outptr2 = output_buf[2][output_row];\n    output_row++;\n    for (col = 0; col < num_cols; col++) {\n      /* We can dispense with GETJSAMPLE() here */\n      outptr0[col] = inptr[RGB_RED];\n      outptr1[col] = inptr[RGB_GREEN];\n      outptr2[col] = inptr[RGB_BLUE];\n      inptr += RGB_PIXELSIZE;\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the JPEG colorspace.\n * This version handles multi-component colorspaces without conversion.\n * We assume input_components == num_components.\n */\n\nMETHODDEF(void)\nnull_convert (j_compress_ptr cinfo,\n\t      JSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t      JDIMENSION output_row, int num_rows)\n{\n  register JSAMPROW inptr;\n  register JSAMPROW outptr;\n  register JDIMENSION count;\n  register int num_comps = cinfo->num_components;\n  JDIMENSION num_cols = cinfo->image_width;\n  int ci;\n\n  while (--num_rows >= 0) {\n    /* It seems fastest to make a separate pass for each component. */\n    for (ci = 0; ci < num_comps; ci++) {\n      inptr = input_buf[0] + ci;\n      outptr = output_buf[ci][output_row];\n      for (count = num_cols; count > 0; count--) {\n\t*outptr++ = *inptr;\t/* don't need GETJSAMPLE() here */\n\tinptr += num_comps;\n      }\n    }\n    input_buf++;\n    output_row++;\n  }\n}\n\n\n/*\n * Empty method for start_pass.\n */\n\nMETHODDEF(void)\nnull_method (j_compress_ptr cinfo)\n{\n  /* no work needed */\n}\n\n\n/*\n * Module initialization routine for input colorspace conversion.\n */\n\nGLOBAL(void)\njinit_color_converter (j_compress_ptr cinfo)\n{\n  my_cconvert_ptr cconvert;\n\n  cconvert = (my_cconvert_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_color_converter));\n  cinfo->cconvert = &cconvert->pub;\n  /* set start_pass to null method until we find out differently */\n  cconvert->pub.start_pass = null_method;\n\n  /* Make sure input_components agrees with in_color_space */\n  switch (cinfo->in_color_space) {\n  case JCS_GRAYSCALE:\n    if (cinfo->input_components != 1)\n      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n    break;\n\n  case JCS_RGB:\n  case JCS_BG_RGB:\n#if RGB_PIXELSIZE != 3\n    if (cinfo->input_components != RGB_PIXELSIZE)\n      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n    break;\n#endif /* else share code with YCbCr */\n\n  case JCS_YCbCr:\n  case JCS_BG_YCC:\n    if (cinfo->input_components != 3)\n      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n    break;\n\n  case JCS_CMYK:\n  case JCS_YCCK:\n    if (cinfo->input_components != 4)\n      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n    break;\n\n  default:\t\t\t/* JCS_UNKNOWN can be anything */\n    if (cinfo->input_components < 1)\n      ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n  }\n\n  /* Support color transform only for RGB colorspaces */\n  if (cinfo->color_transform &&\n      cinfo->jpeg_color_space != JCS_RGB &&\n      cinfo->jpeg_color_space != JCS_BG_RGB)\n    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n\n  /* Check num_components, set conversion method based on requested space */\n  switch (cinfo->jpeg_color_space) {\n  case JCS_GRAYSCALE:\n    if (cinfo->num_components != 1)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    switch (cinfo->in_color_space) {\n    case JCS_GRAYSCALE:\n    case JCS_YCbCr:\n    case JCS_BG_YCC:\n      cconvert->pub.color_convert = grayscale_convert;\n      break;\n    case JCS_RGB:\n      cconvert->pub.start_pass = rgb_ycc_start;\n      cconvert->pub.color_convert = rgb_gray_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_RGB:\n  case JCS_BG_RGB:\n    if (cinfo->num_components != 3)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    if (cinfo->in_color_space != cinfo->jpeg_color_space)\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    switch (cinfo->color_transform) {\n    case JCT_NONE:\n      cconvert->pub.color_convert = rgb_convert;\n      break;\n    case JCT_SUBTRACT_GREEN:\n      cconvert->pub.color_convert = rgb_rgb1_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_YCbCr:\n    if (cinfo->num_components != 3)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    switch (cinfo->in_color_space) {\n    case JCS_RGB:\n      cconvert->pub.start_pass = rgb_ycc_start;\n      cconvert->pub.color_convert = rgb_ycc_convert;\n      break;\n    case JCS_YCbCr:\n      cconvert->pub.color_convert = null_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_BG_YCC:\n    if (cinfo->num_components != 3)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    switch (cinfo->in_color_space) {\n    case JCS_RGB:\n      /* For conversion from normal RGB input to BG_YCC representation,\n       * the Cb/Cr values are first computed as usual, and then\n       * quantized further after DCT processing by a factor of\n       * 2 in reference to the nominal quantization factor.\n       */\n      /* need quantization scale by factor of 2 after DCT */\n      cinfo->comp_info[1].component_needed = TRUE;\n      cinfo->comp_info[2].component_needed = TRUE;\n      /* compute normal YCC first */\n      cconvert->pub.start_pass = rgb_ycc_start;\n      cconvert->pub.color_convert = rgb_ycc_convert;\n      break;\n    case JCS_YCbCr:\n      /* need quantization scale by factor of 2 after DCT */\n      cinfo->comp_info[1].component_needed = TRUE;\n      cinfo->comp_info[2].component_needed = TRUE;\n      /*FALLTHROUGH*/\n    case JCS_BG_YCC:\n      /* Pass through for BG_YCC input */\n      cconvert->pub.color_convert = null_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_CMYK:\n    if (cinfo->num_components != 4)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    if (cinfo->in_color_space != JCS_CMYK)\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    cconvert->pub.color_convert = null_convert;\n    break;\n\n  case JCS_YCCK:\n    if (cinfo->num_components != 4)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    switch (cinfo->in_color_space) {\n    case JCS_CMYK:\n      cconvert->pub.start_pass = rgb_ycc_start;\n      cconvert->pub.color_convert = cmyk_ycck_convert;\n      break;\n    case JCS_YCCK:\n      cconvert->pub.color_convert = null_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  default:\t\t\t/* allow null conversion of JCS_UNKNOWN */\n    if (cinfo->jpeg_color_space != cinfo->in_color_space ||\n\tcinfo->num_components != cinfo->input_components)\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    cconvert->pub.color_convert = null_convert;\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcdctmgr.c",
    "content": "/*\n * jcdctmgr.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the forward-DCT management logic.\n * This code selects a particular DCT implementation to be used,\n * and it performs related housekeeping chores including coefficient\n * quantization.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n\n/* Private subobject for this module */\n\ntypedef struct {\n  struct jpeg_forward_dct pub;\t/* public fields */\n\n  /* Pointer to the DCT routine actually in use */\n  forward_DCT_method_ptr do_dct[MAX_COMPONENTS];\n\n#ifdef DCT_FLOAT_SUPPORTED\n  /* Same as above for the floating-point case. */\n  float_DCT_method_ptr do_float_dct[MAX_COMPONENTS];\n#endif\n} my_fdct_controller;\n\ntypedef my_fdct_controller * my_fdct_ptr;\n\n\n/* The allocated post-DCT divisor tables -- big enough for any\n * supported variant and not identical to the quant table entries,\n * because of scaling (especially for an unnormalized DCT) --\n * are pointed to by dct_table in the per-component comp_info\n * structures.  Each table is given in normal array order.\n */\n\ntypedef union {\n  DCTELEM int_array[DCTSIZE2];\n#ifdef DCT_FLOAT_SUPPORTED\n  FAST_FLOAT float_array[DCTSIZE2];\n#endif\n} divisor_table;\n\n\n/* The current scaled-DCT routines require ISLOW-style divisor tables,\n * so be sure to compile that code if either ISLOW or SCALING is requested.\n */\n#ifdef DCT_ISLOW_SUPPORTED\n#define PROVIDE_ISLOW_TABLES\n#else\n#ifdef DCT_SCALING_SUPPORTED\n#define PROVIDE_ISLOW_TABLES\n#endif\n#endif\n\n\n/*\n * Perform forward DCT on one or more blocks of a component.\n *\n * The input samples are taken from the sample_data[] array starting at\n * position start_col, and moving to the right for any additional blocks.\n * The quantized coefficients are returned in coef_blocks[].\n */\n\nMETHODDEF(void)\nforward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t     JSAMPARRAY sample_data, JBLOCKROW coef_blocks,\n\t     JDIMENSION start_col, JDIMENSION num_blocks)\n/* This version is used for integer DCT implementations. */\n{\n  /* This routine is heavily used, so it's worth coding it tightly. */\n  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;\n  forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index];\n  DCTELEM * divisors = (DCTELEM *) compptr->dct_table;\n  DCTELEM workspace[DCTSIZE2];\t/* work area for FDCT subroutine */\n  JDIMENSION bi;\n\n  for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {\n    /* Perform the DCT */\n    (*do_dct) (workspace, sample_data, start_col);\n\n    /* Quantize/descale the coefficients, and store into coef_blocks[] */\n    { register DCTELEM temp, qval;\n      register int i;\n      register JCOEFPTR output_ptr = coef_blocks[bi];\n\n      for (i = 0; i < DCTSIZE2; i++) {\n\tqval = divisors[i];\n\ttemp = workspace[i];\n\t/* Divide the coefficient value by qval, ensuring proper rounding.\n\t * Since C does not specify the direction of rounding for negative\n\t * quotients, we have to force the dividend positive for portability.\n\t *\n\t * In most files, at least half of the output values will be zero\n\t * (at default quantization settings, more like three-quarters...)\n\t * so we should ensure that this case is fast.  On many machines,\n\t * a comparison is enough cheaper than a divide to make a special test\n\t * a win.  Since both inputs will be nonnegative, we need only test\n\t * for a < b to discover whether a/b is 0.\n\t * If your machine's division is fast enough, define FAST_DIVIDE.\n\t */\n#ifdef FAST_DIVIDE\n#define DIVIDE_BY(a,b)\ta /= b\n#else\n#define DIVIDE_BY(a,b)\tif (a >= b) a /= b; else a = 0\n#endif\n\tif (temp < 0) {\n\t  temp = -temp;\n\t  temp += qval>>1;\t/* for rounding */\n\t  DIVIDE_BY(temp, qval);\n\t  temp = -temp;\n\t} else {\n\t  temp += qval>>1;\t/* for rounding */\n\t  DIVIDE_BY(temp, qval);\n\t}\n\toutput_ptr[i] = (JCOEF) temp;\n      }\n    }\n  }\n}\n\n\n#ifdef DCT_FLOAT_SUPPORTED\n\nMETHODDEF(void)\nforward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t   JSAMPARRAY sample_data, JBLOCKROW coef_blocks,\n\t\t   JDIMENSION start_col, JDIMENSION num_blocks)\n/* This version is used for floating-point DCT implementations. */\n{\n  /* This routine is heavily used, so it's worth coding it tightly. */\n  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;\n  float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index];\n  FAST_FLOAT * divisors = (FAST_FLOAT *) compptr->dct_table;\n  FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */\n  JDIMENSION bi;\n\n  for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {\n    /* Perform the DCT */\n    (*do_dct) (workspace, sample_data, start_col);\n\n    /* Quantize/descale the coefficients, and store into coef_blocks[] */\n    { register FAST_FLOAT temp;\n      register int i;\n      register JCOEFPTR output_ptr = coef_blocks[bi];\n\n      for (i = 0; i < DCTSIZE2; i++) {\n\t/* Apply the quantization and scaling factor */\n\ttemp = workspace[i] * divisors[i];\n\t/* Round to nearest integer.\n\t * Since C does not specify the direction of rounding for negative\n\t * quotients, we have to force the dividend positive for portability.\n\t * The maximum coefficient size is +-16K (for 12-bit data), so this\n\t * code should work for either 16-bit or 32-bit ints.\n\t */\n\toutput_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);\n      }\n    }\n  }\n}\n\n#endif /* DCT_FLOAT_SUPPORTED */\n\n\n/*\n * Initialize for a processing pass.\n * Verify that all referenced Q-tables are present, and set up\n * the divisor table for each one.\n * In the current implementation, DCT of all components is done during\n * the first pass, even if only some components will be output in the\n * first scan.  Hence all components should be examined here.\n */\n\nMETHODDEF(void)\nstart_pass_fdctmgr (j_compress_ptr cinfo)\n{\n  my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;\n  int ci, qtblno, i;\n  jpeg_component_info *compptr;\n  int method = 0;\n  JQUANT_TBL * qtbl;\n  DCTELEM * dtbl;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Select the proper DCT routine for this component's scaling */\n    switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {\n#ifdef DCT_SCALING_SUPPORTED\n    case ((1 << 8) + 1):\n      fdct->do_dct[ci] = jpeg_fdct_1x1;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((2 << 8) + 2):\n      fdct->do_dct[ci] = jpeg_fdct_2x2;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((3 << 8) + 3):\n      fdct->do_dct[ci] = jpeg_fdct_3x3;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((4 << 8) + 4):\n      fdct->do_dct[ci] = jpeg_fdct_4x4;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((5 << 8) + 5):\n      fdct->do_dct[ci] = jpeg_fdct_5x5;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((6 << 8) + 6):\n      fdct->do_dct[ci] = jpeg_fdct_6x6;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((7 << 8) + 7):\n      fdct->do_dct[ci] = jpeg_fdct_7x7;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((9 << 8) + 9):\n      fdct->do_dct[ci] = jpeg_fdct_9x9;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((10 << 8) + 10):\n      fdct->do_dct[ci] = jpeg_fdct_10x10;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((11 << 8) + 11):\n      fdct->do_dct[ci] = jpeg_fdct_11x11;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((12 << 8) + 12):\n      fdct->do_dct[ci] = jpeg_fdct_12x12;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((13 << 8) + 13):\n      fdct->do_dct[ci] = jpeg_fdct_13x13;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((14 << 8) + 14):\n      fdct->do_dct[ci] = jpeg_fdct_14x14;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((15 << 8) + 15):\n      fdct->do_dct[ci] = jpeg_fdct_15x15;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((16 << 8) + 16):\n      fdct->do_dct[ci] = jpeg_fdct_16x16;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((16 << 8) + 8):\n      fdct->do_dct[ci] = jpeg_fdct_16x8;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((14 << 8) + 7):\n      fdct->do_dct[ci] = jpeg_fdct_14x7;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((12 << 8) + 6):\n      fdct->do_dct[ci] = jpeg_fdct_12x6;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((10 << 8) + 5):\n      fdct->do_dct[ci] = jpeg_fdct_10x5;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((8 << 8) + 4):\n      fdct->do_dct[ci] = jpeg_fdct_8x4;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((6 << 8) + 3):\n      fdct->do_dct[ci] = jpeg_fdct_6x3;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((4 << 8) + 2):\n      fdct->do_dct[ci] = jpeg_fdct_4x2;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((2 << 8) + 1):\n      fdct->do_dct[ci] = jpeg_fdct_2x1;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((8 << 8) + 16):\n      fdct->do_dct[ci] = jpeg_fdct_8x16;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((7 << 8) + 14):\n      fdct->do_dct[ci] = jpeg_fdct_7x14;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((6 << 8) + 12):\n      fdct->do_dct[ci] = jpeg_fdct_6x12;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((5 << 8) + 10):\n      fdct->do_dct[ci] = jpeg_fdct_5x10;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((4 << 8) + 8):\n      fdct->do_dct[ci] = jpeg_fdct_4x8;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((3 << 8) + 6):\n      fdct->do_dct[ci] = jpeg_fdct_3x6;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((2 << 8) + 4):\n      fdct->do_dct[ci] = jpeg_fdct_2x4;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n    case ((1 << 8) + 2):\n      fdct->do_dct[ci] = jpeg_fdct_1x2;\n      method = JDCT_ISLOW;\t/* jfdctint uses islow-style table */\n      break;\n#endif\n    case ((DCTSIZE << 8) + DCTSIZE):\n      switch (cinfo->dct_method) {\n#ifdef DCT_ISLOW_SUPPORTED\n      case JDCT_ISLOW:\n\tfdct->do_dct[ci] = jpeg_fdct_islow;\n\tmethod = JDCT_ISLOW;\n\tbreak;\n#endif\n#ifdef DCT_IFAST_SUPPORTED\n      case JDCT_IFAST:\n\tfdct->do_dct[ci] = jpeg_fdct_ifast;\n\tmethod = JDCT_IFAST;\n\tbreak;\n#endif\n#ifdef DCT_FLOAT_SUPPORTED\n      case JDCT_FLOAT:\n\tfdct->do_float_dct[ci] = jpeg_fdct_float;\n\tmethod = JDCT_FLOAT;\n\tbreak;\n#endif\n      default:\n\tERREXIT(cinfo, JERR_NOT_COMPILED);\n      }\n      break;\n    default:\n      ERREXIT2(cinfo, JERR_BAD_DCTSIZE,\n\t       compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);\n    }\n    qtblno = compptr->quant_tbl_no;\n    /* Make sure specified quantization table is present */\n    if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||\n\tcinfo->quant_tbl_ptrs[qtblno] == NULL)\n      ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);\n    qtbl = cinfo->quant_tbl_ptrs[qtblno];\n    /* Create divisor table from quant table */\n    switch (method) {\n#ifdef PROVIDE_ISLOW_TABLES\n    case JDCT_ISLOW:\n      /* For LL&M IDCT method, divisors are equal to raw quantization\n       * coefficients multiplied by 8 (to counteract scaling).\n       */\n      dtbl = (DCTELEM *) compptr->dct_table;\n      for (i = 0; i < DCTSIZE2; i++) {\n\tdtbl[i] =\n\t  ((DCTELEM) qtbl->quantval[i]) << (compptr->component_needed ? 4 : 3);\n      }\n      fdct->pub.forward_DCT[ci] = forward_DCT;\n      break;\n#endif\n#ifdef DCT_IFAST_SUPPORTED\n    case JDCT_IFAST:\n      {\n\t/* For AA&N IDCT method, divisors are equal to quantization\n\t * coefficients scaled by scalefactor[row]*scalefactor[col], where\n\t *   scalefactor[0] = 1\n\t *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7\n\t * We apply a further scale factor of 8.\n\t */\n#define CONST_BITS 14\n\tstatic const INT16 aanscales[DCTSIZE2] = {\n\t  /* precomputed values scaled up by 14 bits */\n\t  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,\n\t  22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,\n\t  21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,\n\t  19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,\n\t  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,\n\t  12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,\n\t   8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,\n\t   4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247\n\t};\n\tSHIFT_TEMPS\n\n\tdtbl = (DCTELEM *) compptr->dct_table;\n\tfor (i = 0; i < DCTSIZE2; i++) {\n\t  dtbl[i] = (DCTELEM)\n\t    DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],\n\t\t\t\t  (INT32) aanscales[i]),\n\t\t    compptr->component_needed ? CONST_BITS-4 : CONST_BITS-3);\n\t}\n      }\n      fdct->pub.forward_DCT[ci] = forward_DCT;\n      break;\n#endif\n#ifdef DCT_FLOAT_SUPPORTED\n    case JDCT_FLOAT:\n      {\n\t/* For float AA&N IDCT method, divisors are equal to quantization\n\t * coefficients scaled by scalefactor[row]*scalefactor[col], where\n\t *   scalefactor[0] = 1\n\t *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7\n\t * We apply a further scale factor of 8.\n\t * What's actually stored is 1/divisor so that the inner loop can\n\t * use a multiplication rather than a division.\n\t */\n\tFAST_FLOAT * fdtbl = (FAST_FLOAT *) compptr->dct_table;\n\tint row, col;\n\tstatic const double aanscalefactor[DCTSIZE] = {\n\t  1.0, 1.387039845, 1.306562965, 1.175875602,\n\t  1.0, 0.785694958, 0.541196100, 0.275899379\n\t};\n\n\ti = 0;\n\tfor (row = 0; row < DCTSIZE; row++) {\n\t  for (col = 0; col < DCTSIZE; col++) {\n\t    fdtbl[i] = (FAST_FLOAT)\n\t      (1.0 / ((double) qtbl->quantval[i] *\n\t\t      aanscalefactor[row] * aanscalefactor[col] *\n\t\t      (compptr->component_needed ? 16.0 : 8.0)));\n\t    i++;\n\t  }\n\t}\n      }\n      fdct->pub.forward_DCT[ci] = forward_DCT_float;\n      break;\n#endif\n    default:\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n    }\n  }\n}\n\n\n/*\n * Initialize FDCT manager.\n */\n\nGLOBAL(void)\njinit_forward_dct (j_compress_ptr cinfo)\n{\n  my_fdct_ptr fdct;\n  int ci;\n  jpeg_component_info *compptr;\n\n  fdct = (my_fdct_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_fdct_controller));\n  cinfo->fdct = &fdct->pub;\n  fdct->pub.start_pass = start_pass_fdctmgr;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Allocate a divisor table for each component */\n    compptr->dct_table = (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(divisor_table));\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jchuff.c",
    "content": "/*\n * jchuff.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2006-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains Huffman entropy encoding routines.\n * Both sequential and progressive modes are supported in this single module.\n *\n * Much of the complexity here has to do with supporting output suspension.\n * If the data destination module demands suspension, we want to be able to\n * back up to the start of the current MCU.  To do this, we copy state\n * variables into local working storage, and update them back to the\n * permanent JPEG objects only upon successful completion of an MCU.\n *\n * We do not support output suspension for the progressive JPEG mode, since\n * the library currently does not allow multiple-scan files to be written\n * with output suspension.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* The legal range of a DCT coefficient is\n *  -1024 .. +1023  for 8-bit data;\n * -16384 .. +16383 for 12-bit data.\n * Hence the magnitude should always fit in 10 or 14 bits respectively.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define MAX_COEF_BITS 10\n#else\n#define MAX_COEF_BITS 14\n#endif\n\n/* Derived data constructed for each Huffman table */\n\ntypedef struct {\n  unsigned int ehufco[256];\t/* code for each symbol */\n  char ehufsi[256];\t\t/* length of code for each symbol */\n  /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */\n} c_derived_tbl;\n\n\n/* Expanded entropy encoder object for Huffman encoding.\n *\n * The savable_state subrecord contains fields that change within an MCU,\n * but must not be updated permanently until we complete the MCU.\n */\n\ntypedef struct {\n  INT32 put_buffer;\t\t/* current bit-accumulation buffer */\n  int put_bits;\t\t\t/* # of bits now in it */\n  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */\n} savable_state;\n\n/* This macro is to work around compilers with missing or broken\n * structure assignment.  You'll need to fix this code if you have\n * such a compiler and you change MAX_COMPS_IN_SCAN.\n */\n\n#ifndef NO_STRUCT_ASSIGN\n#define ASSIGN_STATE(dest,src)  ((dest) = (src))\n#else\n#if MAX_COMPS_IN_SCAN == 4\n#define ASSIGN_STATE(dest,src)  \\\n\t((dest).put_buffer = (src).put_buffer, \\\n\t (dest).put_bits = (src).put_bits, \\\n\t (dest).last_dc_val[0] = (src).last_dc_val[0], \\\n\t (dest).last_dc_val[1] = (src).last_dc_val[1], \\\n\t (dest).last_dc_val[2] = (src).last_dc_val[2], \\\n\t (dest).last_dc_val[3] = (src).last_dc_val[3])\n#endif\n#endif\n\n\ntypedef struct {\n  struct jpeg_entropy_encoder pub; /* public fields */\n\n  savable_state saved;\t\t/* Bit buffer & DC state at start of MCU */\n\n  /* These fields are NOT loaded into local working state. */\n  unsigned int restarts_to_go;\t/* MCUs left in this restart interval */\n  int next_restart_num;\t\t/* next restart number to write (0-7) */\n\n  /* Pointers to derived tables (these workspaces have image lifespan) */\n  c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];\n  c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];\n\n  /* Statistics tables for optimization */\n  long * dc_count_ptrs[NUM_HUFF_TBLS];\n  long * ac_count_ptrs[NUM_HUFF_TBLS];\n\n  /* Following fields used only in progressive mode */\n\n  /* Mode flag: TRUE for optimization, FALSE for actual data output */\n  boolean gather_statistics;\n\n  /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.\n   */\n  JOCTET * next_output_byte;\t/* => next byte to write in buffer */\n  size_t free_in_buffer;\t/* # of byte spaces remaining in buffer */\n  j_compress_ptr cinfo;\t\t/* link to cinfo (needed for dump_buffer) */\n\n  /* Coding status for AC components */\n  int ac_tbl_no;\t\t/* the table number of the single component */\n  unsigned int EOBRUN;\t\t/* run length of EOBs */\n  unsigned int BE;\t\t/* # of buffered correction bits before MCU */\n  char * bit_buffer;\t\t/* buffer for correction bits (1 per char) */\n  /* packing correction bits tightly would save some space but cost time... */\n} huff_entropy_encoder;\n\ntypedef huff_entropy_encoder * huff_entropy_ptr;\n\n/* Working state while writing an MCU (sequential mode).\n * This struct contains all the fields that are needed by subroutines.\n */\n\ntypedef struct {\n  JOCTET * next_output_byte;\t/* => next byte to write in buffer */\n  size_t free_in_buffer;\t/* # of byte spaces remaining in buffer */\n  savable_state cur;\t\t/* Current bit buffer & DC state */\n  j_compress_ptr cinfo;\t\t/* dump_buffer needs access to this */\n} working_state;\n\n/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit\n * buffer can hold.  Larger sizes may slightly improve compression, but\n * 1000 is already well into the realm of overkill.\n * The minimum safe size is 64 bits.\n */\n\n#define MAX_CORR_BITS  1000\t/* Max # of correction bits I can buffer */\n\n/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.\n * We assume that int right shift is unsigned if INT32 right shift is,\n * which should be safe.\n */\n\n#ifdef RIGHT_SHIFT_IS_UNSIGNED\n#define ISHIFT_TEMPS\tint ishift_temp;\n#define IRIGHT_SHIFT(x,shft)  \\\n\t((ishift_temp = (x)) < 0 ? \\\n\t (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \\\n\t (ishift_temp >> (shft)))\n#else\n#define ISHIFT_TEMPS\n#define IRIGHT_SHIFT(x,shft)\t((x) >> (shft))\n#endif\n\n\n/*\n * Compute the derived values for a Huffman table.\n * This routine also performs some validation checks on the table.\n */\n\nLOCAL(void)\njpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,\n\t\t\t c_derived_tbl ** pdtbl)\n{\n  JHUFF_TBL *htbl;\n  c_derived_tbl *dtbl;\n  int p, i, l, lastp, si, maxsymbol;\n  char huffsize[257];\n  unsigned int huffcode[257];\n  unsigned int code;\n\n  /* Note that huffsize[] and huffcode[] are filled in code-length order,\n   * paralleling the order of the symbols themselves in htbl->huffval[].\n   */\n\n  /* Find the input Huffman table */\n  if (tblno < 0 || tblno >= NUM_HUFF_TBLS)\n    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);\n  htbl =\n    isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];\n  if (htbl == NULL)\n    htbl = jpeg_std_huff_table((j_common_ptr) cinfo, isDC, tblno);\n\n  /* Allocate a workspace if we haven't already done so. */\n  if (*pdtbl == NULL)\n    *pdtbl = (c_derived_tbl *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(c_derived_tbl));\n  dtbl = *pdtbl;\n  \n  /* Figure C.1: make table of Huffman code length for each symbol */\n\n  p = 0;\n  for (l = 1; l <= 16; l++) {\n    i = (int) htbl->bits[l];\n    if (i < 0 || p + i > 256)\t/* protect against table overrun */\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    while (i--)\n      huffsize[p++] = (char) l;\n  }\n  huffsize[p] = 0;\n  lastp = p;\n  \n  /* Figure C.2: generate the codes themselves */\n  /* We also validate that the counts represent a legal Huffman code tree. */\n\n  code = 0;\n  si = huffsize[0];\n  p = 0;\n  while (huffsize[p]) {\n    while (((int) huffsize[p]) == si) {\n      huffcode[p++] = code;\n      code++;\n    }\n    /* code is now 1 more than the last code used for codelength si; but\n     * it must still fit in si bits, since no code is allowed to be all ones.\n     */\n    if (((INT32) code) >= (((INT32) 1) << si))\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    code <<= 1;\n    si++;\n  }\n  \n  /* Figure C.3: generate encoding tables */\n  /* These are code and size indexed by symbol value */\n\n  /* Set all codeless symbols to have code length 0;\n   * this lets us detect duplicate VAL entries here, and later\n   * allows emit_bits to detect any attempt to emit such symbols.\n   */\n  MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));\n\n  /* This is also a convenient place to check for out-of-range\n   * and duplicated VAL entries.  We allow 0..255 for AC symbols\n   * but only 0..15 for DC.  (We could constrain them further\n   * based on data depth and mode, but this seems enough.)\n   */\n  maxsymbol = isDC ? 15 : 255;\n\n  for (p = 0; p < lastp; p++) {\n    i = htbl->huffval[p];\n    if (i < 0 || i > maxsymbol || dtbl->ehufsi[i])\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    dtbl->ehufco[i] = huffcode[p];\n    dtbl->ehufsi[i] = huffsize[p];\n  }\n}\n\n\n/* Outputting bytes to the file.\n * NB: these must be called only when actually outputting,\n * that is, entropy->gather_statistics == FALSE.\n */\n\n/* Emit a byte, taking 'action' if must suspend. */\n#define emit_byte_s(state,val,action)  \\\n\t{ *(state)->next_output_byte++ = (JOCTET) (val);  \\\n\t  if (--(state)->free_in_buffer == 0)  \\\n\t    if (! dump_buffer_s(state))  \\\n\t      { action; } }\n\n/* Emit a byte */\n#define emit_byte_e(entropy,val)  \\\n\t{ *(entropy)->next_output_byte++ = (JOCTET) (val);  \\\n\t  if (--(entropy)->free_in_buffer == 0)  \\\n\t    dump_buffer_e(entropy); }\n\n\nLOCAL(boolean)\ndump_buffer_s (working_state * state)\n/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */\n{\n  struct jpeg_destination_mgr * dest = state->cinfo->dest;\n\n  if (! (*dest->empty_output_buffer) (state->cinfo))\n    return FALSE;\n  /* After a successful buffer dump, must reset buffer pointers */\n  state->next_output_byte = dest->next_output_byte;\n  state->free_in_buffer = dest->free_in_buffer;\n  return TRUE;\n}\n\n\nLOCAL(void)\ndump_buffer_e (huff_entropy_ptr entropy)\n/* Empty the output buffer; we do not support suspension in this case. */\n{\n  struct jpeg_destination_mgr * dest = entropy->cinfo->dest;\n\n  if (! (*dest->empty_output_buffer) (entropy->cinfo))\n    ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);\n  /* After a successful buffer dump, must reset buffer pointers */\n  entropy->next_output_byte = dest->next_output_byte;\n  entropy->free_in_buffer = dest->free_in_buffer;\n}\n\n\n/* Outputting bits to the file */\n\n/* Only the right 24 bits of put_buffer are used; the valid bits are\n * left-justified in this part.  At most 16 bits can be passed to emit_bits\n * in one call, and we never retain more than 7 bits in put_buffer\n * between calls, so 24 bits are sufficient.\n */\n\nINLINE\nLOCAL(boolean)\nemit_bits_s (working_state * state, unsigned int code, int size)\n/* Emit some bits; return TRUE if successful, FALSE if must suspend */\n{\n  /* This routine is heavily used, so it's worth coding tightly. */\n  register INT32 put_buffer;\n  register int put_bits;\n\n  /* if size is 0, caller used an invalid Huffman table entry */\n  if (size == 0)\n    ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);\n\n  /* mask off any extra bits in code */\n  put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1);\n\n  /* new number of bits in buffer */\n  put_bits = size + state->cur.put_bits;\n\n  put_buffer <<= 24 - put_bits; /* align incoming bits */\n\n  /* and merge with old buffer contents */\n  put_buffer |= state->cur.put_buffer;\n\n  while (put_bits >= 8) {\n    int c = (int) ((put_buffer >> 16) & 0xFF);\n\n    emit_byte_s(state, c, return FALSE);\n    if (c == 0xFF) {\t\t/* need to stuff a zero byte? */\n      emit_byte_s(state, 0, return FALSE);\n    }\n    put_buffer <<= 8;\n    put_bits -= 8;\n  }\n\n  state->cur.put_buffer = put_buffer; /* update state variables */\n  state->cur.put_bits = put_bits;\n\n  return TRUE;\n}\n\n\nINLINE\nLOCAL(void)\nemit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size)\n/* Emit some bits, unless we are in gather mode */\n{\n  /* This routine is heavily used, so it's worth coding tightly. */\n  register INT32 put_buffer;\n  register int put_bits;\n\n  /* if size is 0, caller used an invalid Huffman table entry */\n  if (size == 0)\n    ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);\n\n  if (entropy->gather_statistics)\n    return;\t\t\t/* do nothing if we're only getting stats */\n\n  /* mask off any extra bits in code */\n  put_buffer = ((INT32) code) & ((((INT32) 1) << size) - 1);\n\n  /* new number of bits in buffer */\n  put_bits = size + entropy->saved.put_bits;\n\n  put_buffer <<= 24 - put_bits; /* align incoming bits */\n\n  /* and merge with old buffer contents */\n  put_buffer |= entropy->saved.put_buffer;\n\n  while (put_bits >= 8) {\n    int c = (int) ((put_buffer >> 16) & 0xFF);\n\n    emit_byte_e(entropy, c);\n    if (c == 0xFF) {\t\t/* need to stuff a zero byte? */\n      emit_byte_e(entropy, 0);\n    }\n    put_buffer <<= 8;\n    put_bits -= 8;\n  }\n\n  entropy->saved.put_buffer = put_buffer; /* update variables */\n  entropy->saved.put_bits = put_bits;\n}\n\n\nLOCAL(boolean)\nflush_bits_s (working_state * state)\n{\n  if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */\n    return FALSE;\n  state->cur.put_buffer = 0;\t     /* and reset bit-buffer to empty */\n  state->cur.put_bits = 0;\n  return TRUE;\n}\n\n\nLOCAL(void)\nflush_bits_e (huff_entropy_ptr entropy)\n{\n  emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */\n  entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */\n  entropy->saved.put_bits = 0;\n}\n\n\n/*\n * Emit (or just count) a Huffman symbol.\n */\n\nINLINE\nLOCAL(void)\nemit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)\n{\n  if (entropy->gather_statistics)\n    entropy->dc_count_ptrs[tbl_no][symbol]++;\n  else {\n    c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no];\n    emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);\n  }\n}\n\n\nINLINE\nLOCAL(void)\nemit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)\n{\n  if (entropy->gather_statistics)\n    entropy->ac_count_ptrs[tbl_no][symbol]++;\n  else {\n    c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no];\n    emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);\n  }\n}\n\n\n/*\n * Emit bits from a correction bit buffer.\n */\n\nLOCAL(void)\nemit_buffered_bits (huff_entropy_ptr entropy, char * bufstart,\n\t\t    unsigned int nbits)\n{\n  if (entropy->gather_statistics)\n    return;\t\t\t/* no real work */\n\n  while (nbits > 0) {\n    emit_bits_e(entropy, (unsigned int) (*bufstart), 1);\n    bufstart++;\n    nbits--;\n  }\n}\n\n\n/*\n * Emit any pending EOBRUN symbol.\n */\n\nLOCAL(void)\nemit_eobrun (huff_entropy_ptr entropy)\n{\n  register int temp, nbits;\n\n  if (entropy->EOBRUN > 0) {\t/* if there is any pending EOBRUN */\n    temp = entropy->EOBRUN;\n    nbits = 0;\n    while ((temp >>= 1))\n      nbits++;\n    /* safety check: shouldn't happen given limited correction-bit buffer */\n    if (nbits > 14)\n      ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);\n\n    emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4);\n    if (nbits)\n      emit_bits_e(entropy, entropy->EOBRUN, nbits);\n\n    entropy->EOBRUN = 0;\n\n    /* Emit any buffered correction bits */\n    emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);\n    entropy->BE = 0;\n  }\n}\n\n\n/*\n * Emit a restart marker & resynchronize predictions.\n */\n\nLOCAL(boolean)\nemit_restart_s (working_state * state, int restart_num)\n{\n  int ci;\n\n  if (! flush_bits_s(state))\n    return FALSE;\n\n  emit_byte_s(state, 0xFF, return FALSE);\n  emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE);\n\n  /* Re-initialize DC predictions to 0 */\n  for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)\n    state->cur.last_dc_val[ci] = 0;\n\n  /* The restart counter is not updated until we successfully write the MCU. */\n\n  return TRUE;\n}\n\n\nLOCAL(void)\nemit_restart_e (huff_entropy_ptr entropy, int restart_num)\n{\n  int ci;\n\n  emit_eobrun(entropy);\n\n  if (! entropy->gather_statistics) {\n    flush_bits_e(entropy);\n    emit_byte_e(entropy, 0xFF);\n    emit_byte_e(entropy, JPEG_RST0 + restart_num);\n  }\n\n  if (entropy->cinfo->Ss == 0) {\n    /* Re-initialize DC predictions to 0 */\n    for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)\n      entropy->saved.last_dc_val[ci] = 0;\n  } else {\n    /* Re-initialize all AC-related fields to 0 */\n    entropy->EOBRUN = 0;\n    entropy->BE = 0;\n  }\n}\n\n\n/*\n * MCU encoding for DC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\nencode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  register int temp, temp2;\n  register int nbits;\n  int blkn, ci, tbl;\n  ISHIFT_TEMPS\n\n  entropy->next_output_byte = cinfo->dest->next_output_byte;\n  entropy->free_in_buffer = cinfo->dest->free_in_buffer;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval)\n    if (entropy->restarts_to_go == 0)\n      emit_restart_e(entropy, entropy->next_restart_num);\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    ci = cinfo->MCU_membership[blkn];\n    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;\n\n    /* Compute the DC value after the required point transform by Al.\n     * This is simply an arithmetic right shift.\n     */\n    temp = IRIGHT_SHIFT((int) (MCU_data[blkn][0][0]), cinfo->Al);\n\n    /* DC differences are figured on the point-transformed values. */\n    temp2 = temp - entropy->saved.last_dc_val[ci];\n    entropy->saved.last_dc_val[ci] = temp;\n\n    /* Encode the DC coefficient difference per section G.1.2.1 */\n    temp = temp2;\n    if (temp < 0) {\n      temp = -temp;\t\t/* temp is abs value of input */\n      /* For a negative input, want temp2 = bitwise complement of abs(input) */\n      /* This code assumes we are on a two's complement machine */\n      temp2--;\n    }\n\n    /* Find the number of bits needed for the magnitude of the coefficient */\n    nbits = 0;\n    while (temp) {\n      nbits++;\n      temp >>= 1;\n    }\n    /* Check for out-of-range coefficient values.\n     * Since we're encoding a difference, the range limit is twice as much.\n     */\n    if (nbits > MAX_COEF_BITS+1)\n      ERREXIT(cinfo, JERR_BAD_DCT_COEF);\n\n    /* Count/emit the Huffman-coded symbol for the number of bits */\n    emit_dc_symbol(entropy, tbl, nbits);\n\n    /* Emit that number of bits of the value, if positive, */\n    /* or the complement of its magnitude, if negative. */\n    if (nbits)\t\t\t/* emit_bits rejects calls with size 0 */\n      emit_bits_e(entropy, (unsigned int) temp2, nbits);\n  }\n\n  cinfo->dest->next_output_byte = entropy->next_output_byte;\n  cinfo->dest->free_in_buffer = entropy->free_in_buffer;\n\n  /* Update restart-interval state too */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for AC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\nencode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  JBLOCKROW block;\n  register int temp, temp2;\n  register int nbits;\n  register int r, k;\n  int Se, Al;\n\n  entropy->next_output_byte = cinfo->dest->next_output_byte;\n  entropy->free_in_buffer = cinfo->dest->free_in_buffer;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval)\n    if (entropy->restarts_to_go == 0)\n      emit_restart_e(entropy, entropy->next_restart_num);\n\n  Se = cinfo->Se;\n  Al = cinfo->Al;\n  natural_order = cinfo->natural_order;\n\n  /* Encode the MCU data block */\n  block = MCU_data[0];\n\n  /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */\n  \n  r = 0;\t\t\t/* r = run length of zeros */\n   \n  for (k = cinfo->Ss; k <= Se; k++) {\n    if ((temp = (*block)[natural_order[k]]) == 0) {\n      r++;\n      continue;\n    }\n    /* We must apply the point transform by Al.  For AC coefficients this\n     * is an integer division with rounding towards 0.  To do this portably\n     * in C, we shift after obtaining the absolute value; so the code is\n     * interwoven with finding the abs value (temp) and output bits (temp2).\n     */\n    if (temp < 0) {\n      temp = -temp;\t\t/* temp is abs value of input */\n      temp >>= Al;\t\t/* apply the point transform */\n      /* For a negative coef, want temp2 = bitwise complement of abs(coef) */\n      temp2 = ~temp;\n    } else {\n      temp >>= Al;\t\t/* apply the point transform */\n      temp2 = temp;\n    }\n    /* Watch out for case that nonzero coef is zero after point transform */\n    if (temp == 0) {\n      r++;\n      continue;\n    }\n\n    /* Emit any pending EOBRUN */\n    if (entropy->EOBRUN > 0)\n      emit_eobrun(entropy);\n    /* if run length > 15, must emit special run-length-16 codes (0xF0) */\n    while (r > 15) {\n      emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);\n      r -= 16;\n    }\n\n    /* Find the number of bits needed for the magnitude of the coefficient */\n    nbits = 1;\t\t\t/* there must be at least one 1 bit */\n    while ((temp >>= 1))\n      nbits++;\n    /* Check for out-of-range coefficient values */\n    if (nbits > MAX_COEF_BITS)\n      ERREXIT(cinfo, JERR_BAD_DCT_COEF);\n\n    /* Count/emit Huffman symbol for run length / number of bits */\n    emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);\n\n    /* Emit that number of bits of the value, if positive, */\n    /* or the complement of its magnitude, if negative. */\n    emit_bits_e(entropy, (unsigned int) temp2, nbits);\n\n    r = 0;\t\t\t/* reset zero run length */\n  }\n\n  if (r > 0) {\t\t\t/* If there are trailing zeroes, */\n    entropy->EOBRUN++;\t\t/* count an EOB */\n    if (entropy->EOBRUN == 0x7FFF)\n      emit_eobrun(entropy);\t/* force it out to avoid overflow */\n  }\n\n  cinfo->dest->next_output_byte = entropy->next_output_byte;\n  cinfo->dest->free_in_buffer = entropy->free_in_buffer;\n\n  /* Update restart-interval state too */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for DC successive approximation refinement scan.\n * Note: we assume such scans can be multi-component,\n * although the spec is not very clear on the point.\n */\n\nMETHODDEF(boolean)\nencode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int Al, blkn;\n\n  entropy->next_output_byte = cinfo->dest->next_output_byte;\n  entropy->free_in_buffer = cinfo->dest->free_in_buffer;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval)\n    if (entropy->restarts_to_go == 0)\n      emit_restart_e(entropy, entropy->next_restart_num);\n\n  Al = cinfo->Al;\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    /* We simply emit the Al'th bit of the DC coefficient value. */\n    emit_bits_e(entropy, (unsigned int) (MCU_data[blkn][0][0] >> Al), 1);\n  }\n\n  cinfo->dest->next_output_byte = entropy->next_output_byte;\n  cinfo->dest->free_in_buffer = entropy->free_in_buffer;\n\n  /* Update restart-interval state too */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU encoding for AC successive approximation refinement scan.\n */\n\nMETHODDEF(boolean)\nencode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  JBLOCKROW block;\n  register int temp;\n  register int r, k;\n  int Se, Al;\n  int EOB;\n  char *BR_buffer;\n  unsigned int BR;\n  int absvalues[DCTSIZE2];\n\n  entropy->next_output_byte = cinfo->dest->next_output_byte;\n  entropy->free_in_buffer = cinfo->dest->free_in_buffer;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval)\n    if (entropy->restarts_to_go == 0)\n      emit_restart_e(entropy, entropy->next_restart_num);\n\n  Se = cinfo->Se;\n  Al = cinfo->Al;\n  natural_order = cinfo->natural_order;\n\n  /* Encode the MCU data block */\n  block = MCU_data[0];\n\n  /* It is convenient to make a pre-pass to determine the transformed\n   * coefficients' absolute values and the EOB position.\n   */\n  EOB = 0;\n  for (k = cinfo->Ss; k <= Se; k++) {\n    temp = (*block)[natural_order[k]];\n    /* We must apply the point transform by Al.  For AC coefficients this\n     * is an integer division with rounding towards 0.  To do this portably\n     * in C, we shift after obtaining the absolute value.\n     */\n    if (temp < 0)\n      temp = -temp;\t\t/* temp is abs value of input */\n    temp >>= Al;\t\t/* apply the point transform */\n    absvalues[k] = temp;\t/* save abs value for main pass */\n    if (temp == 1)\n      EOB = k;\t\t\t/* EOB = index of last newly-nonzero coef */\n  }\n\n  /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */\n  \n  r = 0;\t\t\t/* r = run length of zeros */\n  BR = 0;\t\t\t/* BR = count of buffered bits added now */\n  BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */\n\n  for (k = cinfo->Ss; k <= Se; k++) {\n    if ((temp = absvalues[k]) == 0) {\n      r++;\n      continue;\n    }\n\n    /* Emit any required ZRLs, but not if they can be folded into EOB */\n    while (r > 15 && k <= EOB) {\n      /* emit any pending EOBRUN and the BE correction bits */\n      emit_eobrun(entropy);\n      /* Emit ZRL */\n      emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);\n      r -= 16;\n      /* Emit buffered correction bits that must be associated with ZRL */\n      emit_buffered_bits(entropy, BR_buffer, BR);\n      BR_buffer = entropy->bit_buffer; /* BE bits are gone now */\n      BR = 0;\n    }\n\n    /* If the coef was previously nonzero, it only needs a correction bit.\n     * NOTE: a straight translation of the spec's figure G.7 would suggest\n     * that we also need to test r > 15.  But if r > 15, we can only get here\n     * if k > EOB, which implies that this coefficient is not 1.\n     */\n    if (temp > 1) {\n      /* The correction bit is the next bit of the absolute value. */\n      BR_buffer[BR++] = (char) (temp & 1);\n      continue;\n    }\n\n    /* Emit any pending EOBRUN and the BE correction bits */\n    emit_eobrun(entropy);\n\n    /* Count/emit Huffman symbol for run length / number of bits */\n    emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);\n\n    /* Emit output bit for newly-nonzero coef */\n    temp = ((*block)[natural_order[k]] < 0) ? 0 : 1;\n    emit_bits_e(entropy, (unsigned int) temp, 1);\n\n    /* Emit buffered correction bits that must be associated with this code */\n    emit_buffered_bits(entropy, BR_buffer, BR);\n    BR_buffer = entropy->bit_buffer; /* BE bits are gone now */\n    BR = 0;\n    r = 0;\t\t\t/* reset zero run length */\n  }\n\n  if (r > 0 || BR > 0) {\t/* If there are trailing zeroes, */\n    entropy->EOBRUN++;\t\t/* count an EOB */\n    entropy->BE += BR;\t\t/* concat my correction bits to older ones */\n    /* We force out the EOB if we risk either:\n     * 1. overflow of the EOB counter;\n     * 2. overflow of the correction bit buffer during the next MCU.\n     */\n    if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))\n      emit_eobrun(entropy);\n  }\n\n  cinfo->dest->next_output_byte = entropy->next_output_byte;\n  cinfo->dest->free_in_buffer = entropy->free_in_buffer;\n\n  /* Update restart-interval state too */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  return TRUE;\n}\n\n\n/* Encode a single block's worth of coefficients */\n\nLOCAL(boolean)\nencode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,\n\t\t  c_derived_tbl *dctbl, c_derived_tbl *actbl)\n{\n  register int temp, temp2;\n  register int nbits;\n  register int r, k;\n  int Se = state->cinfo->lim_Se;\n  const int * natural_order = state->cinfo->natural_order;\n\n  /* Encode the DC coefficient difference per section F.1.2.1 */\n\n  temp = temp2 = block[0] - last_dc_val;\n\n  if (temp < 0) {\n    temp = -temp;\t\t/* temp is abs value of input */\n    /* For a negative input, want temp2 = bitwise complement of abs(input) */\n    /* This code assumes we are on a two's complement machine */\n    temp2--;\n  }\n\n  /* Find the number of bits needed for the magnitude of the coefficient */\n  nbits = 0;\n  while (temp) {\n    nbits++;\n    temp >>= 1;\n  }\n  /* Check for out-of-range coefficient values.\n   * Since we're encoding a difference, the range limit is twice as much.\n   */\n  if (nbits > MAX_COEF_BITS+1)\n    ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);\n\n  /* Emit the Huffman-coded symbol for the number of bits */\n  if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))\n    return FALSE;\n\n  /* Emit that number of bits of the value, if positive, */\n  /* or the complement of its magnitude, if negative. */\n  if (nbits)\t\t\t/* emit_bits rejects calls with size 0 */\n    if (! emit_bits_s(state, (unsigned int) temp2, nbits))\n      return FALSE;\n\n  /* Encode the AC coefficients per section F.1.2.2 */\n\n  r = 0;\t\t\t/* r = run length of zeros */\n\n  for (k = 1; k <= Se; k++) {\n    if ((temp2 = block[natural_order[k]]) == 0) {\n      r++;\n    } else {\n      /* if run length > 15, must emit special run-length-16 codes (0xF0) */\n      while (r > 15) {\n\tif (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))\n\t  return FALSE;\n\tr -= 16;\n      }\n\n      temp = temp2;\n      if (temp < 0) {\n\ttemp = -temp;\t\t/* temp is abs value of input */\n\t/* This code assumes we are on a two's complement machine */\n\ttemp2--;\n      }\n\n      /* Find the number of bits needed for the magnitude of the coefficient */\n      nbits = 1;\t\t/* there must be at least one 1 bit */\n      while ((temp >>= 1))\n\tnbits++;\n      /* Check for out-of-range coefficient values */\n      if (nbits > MAX_COEF_BITS)\n\tERREXIT(state->cinfo, JERR_BAD_DCT_COEF);\n\n      /* Emit Huffman symbol for run length / number of bits */\n      temp = (r << 4) + nbits;\n      if (! emit_bits_s(state, actbl->ehufco[temp], actbl->ehufsi[temp]))\n\treturn FALSE;\n\n      /* Emit that number of bits of the value, if positive, */\n      /* or the complement of its magnitude, if negative. */\n      if (! emit_bits_s(state, (unsigned int) temp2, nbits))\n\treturn FALSE;\n\n      r = 0;\n    }\n  }\n\n  /* If the last coef(s) were zero, emit an end-of-block code */\n  if (r > 0)\n    if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0]))\n      return FALSE;\n\n  return TRUE;\n}\n\n\n/*\n * Encode and output one MCU's worth of Huffman-compressed coefficients.\n */\n\nMETHODDEF(boolean)\nencode_mcu_huff (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  working_state state;\n  int blkn, ci;\n  jpeg_component_info * compptr;\n\n  /* Load up working state */\n  state.next_output_byte = cinfo->dest->next_output_byte;\n  state.free_in_buffer = cinfo->dest->free_in_buffer;\n  ASSIGN_STATE(state.cur, entropy->saved);\n  state.cinfo = cinfo;\n\n  /* Emit restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! emit_restart_s(&state, entropy->next_restart_num))\n\treturn FALSE;\n  }\n\n  /* Encode the MCU data blocks */\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    ci = cinfo->MCU_membership[blkn];\n    compptr = cinfo->cur_comp_info[ci];\n    if (! encode_one_block(&state,\n\t\t\t   MCU_data[blkn][0], state.cur.last_dc_val[ci],\n\t\t\t   entropy->dc_derived_tbls[compptr->dc_tbl_no],\n\t\t\t   entropy->ac_derived_tbls[compptr->ac_tbl_no]))\n      return FALSE;\n    /* Update last_dc_val */\n    state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];\n  }\n\n  /* Completed MCU, so update state */\n  cinfo->dest->next_output_byte = state.next_output_byte;\n  cinfo->dest->free_in_buffer = state.free_in_buffer;\n  ASSIGN_STATE(entropy->saved, state.cur);\n\n  /* Update restart-interval state too */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      entropy->restarts_to_go = cinfo->restart_interval;\n      entropy->next_restart_num++;\n      entropy->next_restart_num &= 7;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  return TRUE;\n}\n\n\n/*\n * Finish up at the end of a Huffman-compressed scan.\n */\n\nMETHODDEF(void)\nfinish_pass_huff (j_compress_ptr cinfo)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  working_state state;\n\n  if (cinfo->progressive_mode) {\n    entropy->next_output_byte = cinfo->dest->next_output_byte;\n    entropy->free_in_buffer = cinfo->dest->free_in_buffer;\n\n    /* Flush out any buffered data */\n    emit_eobrun(entropy);\n    flush_bits_e(entropy);\n\n    cinfo->dest->next_output_byte = entropy->next_output_byte;\n    cinfo->dest->free_in_buffer = entropy->free_in_buffer;\n  } else {\n    /* Load up working state ... flush_bits needs it */\n    state.next_output_byte = cinfo->dest->next_output_byte;\n    state.free_in_buffer = cinfo->dest->free_in_buffer;\n    ASSIGN_STATE(state.cur, entropy->saved);\n    state.cinfo = cinfo;\n\n    /* Flush out the last data */\n    if (! flush_bits_s(&state))\n      ERREXIT(cinfo, JERR_CANT_SUSPEND);\n\n    /* Update state */\n    cinfo->dest->next_output_byte = state.next_output_byte;\n    cinfo->dest->free_in_buffer = state.free_in_buffer;\n    ASSIGN_STATE(entropy->saved, state.cur);\n  }\n}\n\n\n/*\n * Huffman coding optimization.\n *\n * We first scan the supplied data and count the number of uses of each symbol\n * that is to be Huffman-coded. (This process MUST agree with the code above.)\n * Then we build a Huffman coding tree for the observed counts.\n * Symbols which are not needed at all for the particular image are not\n * assigned any code, which saves space in the DHT marker as well as in\n * the compressed data.\n */\n\n\n/* Process a single block's worth of coefficients */\n\nLOCAL(void)\nhtest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,\n\t\t long dc_counts[], long ac_counts[])\n{\n  register int temp;\n  register int nbits;\n  register int r, k;\n  int Se = cinfo->lim_Se;\n  const int * natural_order = cinfo->natural_order;\n\n  /* Encode the DC coefficient difference per section F.1.2.1 */\n\n  temp = block[0] - last_dc_val;\n  if (temp < 0)\n    temp = -temp;\n\n  /* Find the number of bits needed for the magnitude of the coefficient */\n  nbits = 0;\n  while (temp) {\n    nbits++;\n    temp >>= 1;\n  }\n  /* Check for out-of-range coefficient values.\n   * Since we're encoding a difference, the range limit is twice as much.\n   */\n  if (nbits > MAX_COEF_BITS+1)\n    ERREXIT(cinfo, JERR_BAD_DCT_COEF);\n\n  /* Count the Huffman symbol for the number of bits */\n  dc_counts[nbits]++;\n\n  /* Encode the AC coefficients per section F.1.2.2 */\n\n  r = 0;\t\t\t/* r = run length of zeros */\n\n  for (k = 1; k <= Se; k++) {\n    if ((temp = block[natural_order[k]]) == 0) {\n      r++;\n    } else {\n      /* if run length > 15, must emit special run-length-16 codes (0xF0) */\n      while (r > 15) {\n\tac_counts[0xF0]++;\n\tr -= 16;\n      }\n\n      /* Find the number of bits needed for the magnitude of the coefficient */\n      if (temp < 0)\n\ttemp = -temp;\n\n      /* Find the number of bits needed for the magnitude of the coefficient */\n      nbits = 1;\t\t/* there must be at least one 1 bit */\n      while ((temp >>= 1))\n\tnbits++;\n      /* Check for out-of-range coefficient values */\n      if (nbits > MAX_COEF_BITS)\n\tERREXIT(cinfo, JERR_BAD_DCT_COEF);\n\n      /* Count Huffman symbol for run length / number of bits */\n      ac_counts[(r << 4) + nbits]++;\n\n      r = 0;\n    }\n  }\n\n  /* If the last coef(s) were zero, emit an end-of-block code */\n  if (r > 0)\n    ac_counts[0]++;\n}\n\n\n/*\n * Trial-encode one MCU's worth of Huffman-compressed coefficients.\n * No data is actually output, so no suspension return is possible.\n */\n\nMETHODDEF(boolean)\nencode_mcu_gather (j_compress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int blkn, ci;\n  jpeg_component_info * compptr;\n\n  /* Take care of restart intervals if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0) {\n      /* Re-initialize DC predictions to 0 */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++)\n\tentropy->saved.last_dc_val[ci] = 0;\n      /* Update restart state */\n      entropy->restarts_to_go = cinfo->restart_interval;\n    }\n    entropy->restarts_to_go--;\n  }\n\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    ci = cinfo->MCU_membership[blkn];\n    compptr = cinfo->cur_comp_info[ci];\n    htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],\n\t\t    entropy->dc_count_ptrs[compptr->dc_tbl_no],\n\t\t    entropy->ac_count_ptrs[compptr->ac_tbl_no]);\n    entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];\n  }\n\n  return TRUE;\n}\n\n\n/*\n * Generate the best Huffman code table for the given counts, fill htbl.\n *\n * The JPEG standard requires that no symbol be assigned a codeword of all\n * one bits (so that padding bits added at the end of a compressed segment\n * can't look like a valid code).  Because of the canonical ordering of\n * codewords, this just means that there must be an unused slot in the\n * longest codeword length category.  Section K.2 of the JPEG spec suggests\n * reserving such a slot by pretending that symbol 256 is a valid symbol\n * with count 1.  In theory that's not optimal; giving it count zero but\n * including it in the symbol set anyway should give a better Huffman code.\n * But the theoretically better code actually seems to come out worse in\n * practice, because it produces more all-ones bytes (which incur stuffed\n * zero bytes in the final file).  In any case the difference is tiny.\n *\n * The JPEG standard requires Huffman codes to be no more than 16 bits long.\n * If some symbols have a very small but nonzero probability, the Huffman tree\n * must be adjusted to meet the code length restriction.  We currently use\n * the adjustment method suggested in JPEG section K.2.  This method is *not*\n * optimal; it may not choose the best possible limited-length code.  But\n * typically only very-low-frequency symbols will be given less-than-optimal\n * lengths, so the code is almost optimal.  Experimental comparisons against\n * an optimal limited-length-code algorithm indicate that the difference is\n * microscopic --- usually less than a hundredth of a percent of total size.\n * So the extra complexity of an optimal algorithm doesn't seem worthwhile.\n */\n\nLOCAL(void)\njpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])\n{\n#define MAX_CLEN 32\t\t/* assumed maximum initial code length */\n  UINT8 bits[MAX_CLEN+1];\t/* bits[k] = # of symbols with code length k */\n  int codesize[257];\t\t/* codesize[k] = code length of symbol k */\n  int others[257];\t\t/* next symbol in current branch of tree */\n  int c1, c2, i, j;\n  UINT8 *p;\n  long v;\n\n  freq[256] = 1;\t\t/* make sure 256 has a nonzero count */\n  /* Including the pseudo-symbol 256 in the Huffman procedure guarantees\n   * that no real symbol is given code-value of all ones, because 256\n   * will be placed last in the largest codeword category.\n   * In the symbol list build procedure this element serves as sentinel\n   * for the zero run loop.\n   */\n\n#ifndef DONT_USE_FANCY_HUFF_OPT\n\n  /* Build list of symbols sorted in order of descending frequency */\n  /* This approach has several benefits (thank to John Korejwa for the idea):\n   *     1.\n   * If a codelength category is split during the length limiting procedure\n   * below, the feature that more frequent symbols are assigned shorter\n   * codewords remains valid for the adjusted code.\n   *     2.\n   * To reduce consecutive ones in a Huffman data stream (thus reducing the\n   * number of stuff bytes in JPEG) it is preferable to follow 0 branches\n   * (and avoid 1 branches) as much as possible.  This is easily done by\n   * assigning symbols to leaves of the Huffman tree in order of decreasing\n   * frequency, with no secondary sort based on codelengths.\n   *     3.\n   * The symbol list can be built independently from the assignment of code\n   * lengths by the Huffman procedure below.\n   * Note: The symbol list build procedure must be performed first, because\n   * the Huffman procedure assigning the codelengths clobbers the frequency\n   * counts!\n   */\n\n  /* Here we use the others array as a linked list of nonzero frequencies\n   * to be sorted.  Already sorted elements are removed from the list.\n   */\n\n  /* Building list */\n\n  /* This item does not correspond to a valid symbol frequency and is used\n   * as starting index.\n   */\n  j = 256;\n\n  for (i = 0;; i++) {\n    if (freq[i] == 0)\t\t/* skip zero frequencies */\n      continue;\n    if (i > 255)\n      break;\n    others[j] = i;\t\t/* this symbol value */\n    j = i;\t\t\t/* previous symbol value */\n  }\n  others[j] = -1;\t\t/* mark end of list */\n\n  /* Sorting list */\n\n  p = htbl->huffval;\n  while ((c1 = others[256]) >= 0) {\n    v = freq[c1];\n    i = c1;\t\t\t/* first symbol value */\n    j = 256;\t\t\t/* pseudo symbol value for starting index */\n    while ((c2 = others[c1]) >= 0) {\n      if (freq[c2] > v) {\n\tv = freq[c2];\n\ti = c2;\t\t\t/* this symbol value */\n\tj = c1;\t\t\t/* previous symbol value */\n      }\n      c1 = c2;\n    }\n    others[j] = others[i];\t/* remove this symbol i from list */\n    *p++ = (UINT8) i;\n  }\n\n#endif /* DONT_USE_FANCY_HUFF_OPT */\n\n  /* This algorithm is explained in section K.2 of the JPEG standard */\n\n  MEMZERO(bits, SIZEOF(bits));\n  MEMZERO(codesize, SIZEOF(codesize));\n  for (i = 0; i < 257; i++)\n    others[i] = -1;\t\t/* init links to empty */\n\n  /* Huffman's basic algorithm to assign optimal code lengths to symbols */\n\n  for (;;) {\n    /* Find the smallest nonzero frequency, set c1 = its symbol */\n    /* In case of ties, take the larger symbol number */\n    c1 = -1;\n    v = 1000000000L;\n    for (i = 0; i <= 256; i++) {\n      if (freq[i] && freq[i] <= v) {\n\tv = freq[i];\n\tc1 = i;\n      }\n    }\n\n    /* Find the next smallest nonzero frequency, set c2 = its symbol */\n    /* In case of ties, take the larger symbol number */\n    c2 = -1;\n    v = 1000000000L;\n    for (i = 0; i <= 256; i++) {\n      if (freq[i] && freq[i] <= v && i != c1) {\n\tv = freq[i];\n\tc2 = i;\n      }\n    }\n\n    /* Done if we've merged everything into one frequency */\n    if (c2 < 0)\n      break;\n\n    /* Else merge the two counts/trees */\n    freq[c1] += freq[c2];\n    freq[c2] = 0;\n\n    /* Increment the codesize of everything in c1's tree branch */\n    codesize[c1]++;\n    while (others[c1] >= 0) {\n      c1 = others[c1];\n      codesize[c1]++;\n    }\n\n    others[c1] = c2;\t\t/* chain c2 onto c1's tree branch */\n\n    /* Increment the codesize of everything in c2's tree branch */\n    codesize[c2]++;\n    while (others[c2] >= 0) {\n      c2 = others[c2];\n      codesize[c2]++;\n    }\n  }\n\n  /* Now count the number of symbols of each code length */\n  for (i = 0; i <= 256; i++) {\n    if (codesize[i]) {\n      /* The JPEG standard seems to think that this can't happen, */\n      /* but I'm paranoid... */\n      if (codesize[i] > MAX_CLEN)\n\tERREXIT(cinfo, JERR_HUFF_CLEN_OUTOFBOUNDS);\n\n      bits[codesize[i]]++;\n    }\n  }\n\n  /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure\n   * Huffman procedure assigned any such lengths, we must adjust the coding.\n   * Here is what the JPEG spec says about how this next bit works:\n   * Since symbols are paired for the longest Huffman code, the symbols are\n   * removed from this length category two at a time.  The prefix for the pair\n   * (which is one bit shorter) is allocated to one of the pair; then,\n   * skipping the BITS entry for that prefix length, a code word from the next\n   * shortest nonzero BITS entry is converted into a prefix for two code words\n   * one bit longer.\n   */\n\n  for (i = MAX_CLEN; i > 16; i--) {\n    while (bits[i] > 0) {\n      j = i - 2;\t\t/* find length of new prefix to be used */\n      while (bits[j] == 0) {\n\tif (j == 0)\n\t  ERREXIT(cinfo, JERR_HUFF_CLEN_OUTOFBOUNDS);\n\tj--;\n      }\n\n      bits[i] -= 2;\t\t/* remove two symbols */\n      bits[i-1]++;\t\t/* one goes in this length */\n      bits[j+1] += 2;\t\t/* two new symbols in this length */\n      bits[j]--;\t\t/* symbol of this length is now a prefix */\n    }\n  }\n\n  /* Remove the count for the pseudo-symbol 256 from the largest codelength */\n  while (bits[i] == 0)\t\t/* find largest codelength still in use */\n    i--;\n  bits[i]--;\n\n  /* Return final symbol counts (only for lengths 0..16) */\n  MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));\n\n#ifdef DONT_USE_FANCY_HUFF_OPT\n\n  /* Return a list of the symbols sorted by code length */\n  /* Note: Due to the codelength changes made above, it can happen\n   * that more frequent symbols are assigned longer codewords.\n   */\n  p = htbl->huffval;\n  for (i = 1; i <= MAX_CLEN; i++) {\n    for (j = 0; j <= 255; j++) {\n      if (codesize[j] == i) {\n\t*p++ = (UINT8) j;\n      }\n    }\n  }\n\n#endif /* DONT_USE_FANCY_HUFF_OPT */\n\n  /* Set sent_table FALSE so updated table will be written to JPEG file. */\n  htbl->sent_table = FALSE;\n}\n\n\n/*\n * Finish up a statistics-gathering pass and create the new Huffman tables.\n */\n\nMETHODDEF(void)\nfinish_pass_gather (j_compress_ptr cinfo)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int ci, tbl;\n  jpeg_component_info * compptr;\n  JHUFF_TBL **htblptr;\n  boolean did_dc[NUM_HUFF_TBLS];\n  boolean did_ac[NUM_HUFF_TBLS];\n\n  if (cinfo->progressive_mode)\n    /* Flush out buffered data (all we care about is counting the EOB symbol) */\n    emit_eobrun(entropy);\n\n  /* It's important not to apply jpeg_gen_optimal_table more than once\n   * per table, because it clobbers the input frequency counts!\n   */\n  MEMZERO(did_dc, SIZEOF(did_dc));\n  MEMZERO(did_ac, SIZEOF(did_ac));\n\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    /* DC needs no table for refinement scan */\n    if (cinfo->Ss == 0 && cinfo->Ah == 0) {\n      tbl = compptr->dc_tbl_no;\n      if (! did_dc[tbl]) {\n\thtblptr = & cinfo->dc_huff_tbl_ptrs[tbl];\n\tif (*htblptr == NULL)\n\t  *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);\n\tjpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]);\n\tdid_dc[tbl] = TRUE;\n      }\n    }\n    /* AC needs no table when not present */\n    if (cinfo->Se) {\n      tbl = compptr->ac_tbl_no;\n      if (! did_ac[tbl]) {\n\thtblptr = & cinfo->ac_huff_tbl_ptrs[tbl];\n\tif (*htblptr == NULL)\n\t  *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);\n\tjpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]);\n\tdid_ac[tbl] = TRUE;\n      }\n    }\n  }\n}\n\n\n/*\n * Initialize for a Huffman-compressed scan.\n * If gather_statistics is TRUE, we do not output anything during the scan,\n * just count the Huffman symbols used and generate Huffman code tables.\n */\n\nMETHODDEF(void)\nstart_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int ci, tbl;\n  jpeg_component_info * compptr;\n\n  if (gather_statistics)\n    entropy->pub.finish_pass = finish_pass_gather;\n  else\n    entropy->pub.finish_pass = finish_pass_huff;\n\n  if (cinfo->progressive_mode) {\n    entropy->cinfo = cinfo;\n    entropy->gather_statistics = gather_statistics;\n\n    /* We assume jcmaster.c already validated the scan parameters. */\n\n    /* Select execution routine */\n    if (cinfo->Ah == 0) {\n      if (cinfo->Ss == 0)\n\tentropy->pub.encode_mcu = encode_mcu_DC_first;\n      else\n\tentropy->pub.encode_mcu = encode_mcu_AC_first;\n    } else {\n      if (cinfo->Ss == 0)\n\tentropy->pub.encode_mcu = encode_mcu_DC_refine;\n      else {\n\tentropy->pub.encode_mcu = encode_mcu_AC_refine;\n\t/* AC refinement needs a correction bit buffer */\n\tif (entropy->bit_buffer == NULL)\n\t  entropy->bit_buffer = (char *) (*cinfo->mem->alloc_small)\n\t    ((j_common_ptr) cinfo, JPOOL_IMAGE, MAX_CORR_BITS * SIZEOF(char));\n      }\n    }\n\n    /* Initialize AC stuff */\n    entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no;\n    entropy->EOBRUN = 0;\n    entropy->BE = 0;\n  } else {\n    if (gather_statistics)\n      entropy->pub.encode_mcu = encode_mcu_gather;\n    else\n      entropy->pub.encode_mcu = encode_mcu_huff;\n  }\n\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    /* DC needs no table for refinement scan */\n    if (cinfo->Ss == 0 && cinfo->Ah == 0) {\n      tbl = compptr->dc_tbl_no;\n      if (gather_statistics) {\n\t/* Check for invalid table index */\n\t/* (make_c_derived_tbl does this in the other path) */\n\tif (tbl < 0 || tbl >= NUM_HUFF_TBLS)\n\t  ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);\n\t/* Allocate and zero the statistics tables */\n\t/* Note that jpeg_gen_optimal_table expects 257 entries in each table! */\n\tif (entropy->dc_count_ptrs[tbl] == NULL)\n\t  entropy->dc_count_ptrs[tbl] = (long *) (*cinfo->mem->alloc_small)\n\t    ((j_common_ptr) cinfo, JPOOL_IMAGE, 257 * SIZEOF(long));\n\tMEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long));\n      } else {\n\t/* Compute derived values for Huffman tables */\n\t/* We may do this more than once for a table, but it's not expensive */\n\tjpeg_make_c_derived_tbl(cinfo, TRUE, tbl,\n\t\t\t\t& entropy->dc_derived_tbls[tbl]);\n      }\n      /* Initialize DC predictions to 0 */\n      entropy->saved.last_dc_val[ci] = 0;\n    }\n    /* AC needs no table when not present */\n    if (cinfo->Se) {\n      tbl = compptr->ac_tbl_no;\n      if (gather_statistics) {\n\tif (tbl < 0 || tbl >= NUM_HUFF_TBLS)\n\t  ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);\n\tif (entropy->ac_count_ptrs[tbl] == NULL)\n\t  entropy->ac_count_ptrs[tbl] = (long *) (*cinfo->mem->alloc_small)\n\t    ((j_common_ptr) cinfo, JPOOL_IMAGE, 257 * SIZEOF(long));\n\tMEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long));\n      } else {\n\tjpeg_make_c_derived_tbl(cinfo, FALSE, tbl,\n\t\t\t\t& entropy->ac_derived_tbls[tbl]);\n      }\n    }\n  }\n\n  /* Initialize bit buffer to empty */\n  entropy->saved.put_buffer = 0;\n  entropy->saved.put_bits = 0;\n\n  /* Initialize restart stuff */\n  entropy->restarts_to_go = cinfo->restart_interval;\n  entropy->next_restart_num = 0;\n}\n\n\n/*\n * Module initialization routine for Huffman entropy encoding.\n */\n\nGLOBAL(void)\njinit_huff_encoder (j_compress_ptr cinfo)\n{\n  huff_entropy_ptr entropy;\n  int i;\n\n  entropy = (huff_entropy_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(huff_entropy_encoder));\n  cinfo->entropy = &entropy->pub;\n  entropy->pub.start_pass = start_pass_huff;\n\n  /* Mark tables unallocated */\n  for (i = 0; i < NUM_HUFF_TBLS; i++) {\n    entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;\n    entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;\n  }\n\n  if (cinfo->progressive_mode)\n    entropy->bit_buffer = NULL;\t/* needed only in AC refinement scan */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcinit.c",
    "content": "/*\n * jcinit.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2003-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains initialization logic for the JPEG compressor.\n * This routine is in charge of selecting the modules to be executed and\n * making an initialization call to each one.\n *\n * Logically, this code belongs in jcmaster.c.  It's split out because\n * linking this routine implies linking the entire compression library.\n * For a transcoding-only application, we want to be able to use jcmaster.c\n * without linking in the whole library.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Compute JPEG image dimensions and related values.\n * NOTE: this is exported for possible use by application.\n * Hence it mustn't do anything that can't be done twice.\n */\n\nGLOBAL(void)\njpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)\n/* Do computations that are needed before master selection phase */\n{\n  /* Sanity check on input image dimensions to prevent overflow in\n   * following calculations.\n   * We do check jpeg_width and jpeg_height in initial_setup in jcmaster.c,\n   * but image_width and image_height can come from arbitrary data,\n   * and we need some space for multiplication by block_size.\n   */\n  if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24))\n    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);\n\n#ifdef DCT_SCALING_SUPPORTED\n\n  /* Compute actual JPEG image dimensions and DCT scaling choices. */\n  if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/1 scaling */\n    cinfo->jpeg_width = cinfo->image_width * cinfo->block_size;\n    cinfo->jpeg_height = cinfo->image_height * cinfo->block_size;\n    cinfo->min_DCT_h_scaled_size = 1;\n    cinfo->min_DCT_v_scaled_size = 1;\n  } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/2 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L);\n    cinfo->min_DCT_h_scaled_size = 2;\n    cinfo->min_DCT_v_scaled_size = 2;\n  } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/3 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L);\n    cinfo->min_DCT_h_scaled_size = 3;\n    cinfo->min_DCT_v_scaled_size = 3;\n  } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/4 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L);\n    cinfo->min_DCT_h_scaled_size = 4;\n    cinfo->min_DCT_v_scaled_size = 4;\n  } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/5 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L);\n    cinfo->min_DCT_h_scaled_size = 5;\n    cinfo->min_DCT_v_scaled_size = 5;\n  } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/6 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L);\n    cinfo->min_DCT_h_scaled_size = 6;\n    cinfo->min_DCT_v_scaled_size = 6;\n  } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/7 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L);\n    cinfo->min_DCT_h_scaled_size = 7;\n    cinfo->min_DCT_v_scaled_size = 7;\n  } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/8 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L);\n    cinfo->min_DCT_h_scaled_size = 8;\n    cinfo->min_DCT_v_scaled_size = 8;\n  } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/9 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L);\n    cinfo->min_DCT_h_scaled_size = 9;\n    cinfo->min_DCT_v_scaled_size = 9;\n  } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/10 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L);\n    cinfo->min_DCT_h_scaled_size = 10;\n    cinfo->min_DCT_v_scaled_size = 10;\n  } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/11 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L);\n    cinfo->min_DCT_h_scaled_size = 11;\n    cinfo->min_DCT_v_scaled_size = 11;\n  } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/12 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L);\n    cinfo->min_DCT_h_scaled_size = 12;\n    cinfo->min_DCT_v_scaled_size = 12;\n  } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/13 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L);\n    cinfo->min_DCT_h_scaled_size = 13;\n    cinfo->min_DCT_v_scaled_size = 13;\n  } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/14 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L);\n    cinfo->min_DCT_h_scaled_size = 14;\n    cinfo->min_DCT_v_scaled_size = 14;\n  } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) {\n    /* Provide block_size/15 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L);\n    cinfo->min_DCT_h_scaled_size = 15;\n    cinfo->min_DCT_v_scaled_size = 15;\n  } else {\n    /* Provide block_size/16 scaling */\n    cinfo->jpeg_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L);\n    cinfo->jpeg_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L);\n    cinfo->min_DCT_h_scaled_size = 16;\n    cinfo->min_DCT_v_scaled_size = 16;\n  }\n\n#else /* !DCT_SCALING_SUPPORTED */\n\n  /* Hardwire it to \"no scaling\" */\n  cinfo->jpeg_width = cinfo->image_width;\n  cinfo->jpeg_height = cinfo->image_height;\n  cinfo->min_DCT_h_scaled_size = DCTSIZE;\n  cinfo->min_DCT_v_scaled_size = DCTSIZE;\n\n#endif /* DCT_SCALING_SUPPORTED */\n}\n\n\n/*\n * Master selection of compression modules.\n * This is done once at the start of processing an image.  We determine\n * which modules will be used and give them appropriate initialization calls.\n */\n\nGLOBAL(void)\njinit_compress_master (j_compress_ptr cinfo)\n{\n  long samplesperrow;\n  JDIMENSION jd_samplesperrow;\n\n  /* For now, precision must match compiled-in value... */\n  if (cinfo->data_precision != BITS_IN_JSAMPLE)\n    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);\n\n  /* Sanity check on input image dimensions */\n  if (cinfo->image_height <= 0 || cinfo->image_width <= 0 ||\n      cinfo->input_components <= 0)\n    ERREXIT(cinfo, JERR_EMPTY_IMAGE);\n\n  /* Width of an input scanline must be representable as JDIMENSION. */\n  samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;\n  jd_samplesperrow = (JDIMENSION) samplesperrow;\n  if ((long) jd_samplesperrow != samplesperrow)\n    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\n\n  /* Compute JPEG image dimensions and related values. */\n  jpeg_calc_jpeg_dimensions(cinfo);\n\n  /* Initialize master control (includes parameter checking/processing) */\n  jinit_c_master_control(cinfo, FALSE /* full compression */);\n\n  /* Preprocessing */\n  if (! cinfo->raw_data_in) {\n    jinit_color_converter(cinfo);\n    jinit_downsampler(cinfo);\n    jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);\n  }\n  /* Forward DCT */\n  jinit_forward_dct(cinfo);\n  /* Entropy encoding: either Huffman or arithmetic coding. */\n  if (cinfo->arith_code)\n    jinit_arith_encoder(cinfo);\n  else {\n    jinit_huff_encoder(cinfo);\n  }\n\n  /* Need a full-image coefficient buffer in any multi-pass mode. */\n  jinit_c_coef_controller(cinfo,\n\t\t(boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));\n  jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);\n\n  jinit_marker_writer(cinfo);\n\n  /* We can now tell the memory manager to allocate virtual arrays. */\n  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);\n\n  /* Write the datastream header (SOI) immediately.\n   * Frame and scan headers are postponed till later.\n   * This lets application insert special markers after the SOI.\n   */\n  (*cinfo->marker->write_file_header) (cinfo);\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcmainct.c",
    "content": "/*\n * jcmainct.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2003-2012 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the main buffer controller for compression.\n * The main buffer lies between the pre-processor and the JPEG\n * compressor proper; it holds downsampled data in the JPEG colorspace.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Note: currently, there is no operating mode in which a full-image buffer\n * is needed at this step.  If there were, that mode could not be used with\n * \"raw data\" input, since this module is bypassed in that case.  However,\n * we've left the code here for possible use in special applications.\n */\n#undef FULL_MAIN_BUFFER_SUPPORTED\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_c_main_controller pub; /* public fields */\n\n  JDIMENSION cur_iMCU_row;\t/* number of current iMCU row */\n  JDIMENSION rowgroup_ctr;\t/* counts row groups received in iMCU row */\n  boolean suspended;\t\t/* remember if we suspended output */\n  J_BUF_MODE pass_mode;\t\t/* current operating mode */\n\n  /* If using just a strip buffer, this points to the entire set of buffers\n   * (we allocate one for each component).  In the full-image case, this\n   * points to the currently accessible strips of the virtual arrays.\n   */\n  JSAMPARRAY buffer[MAX_COMPONENTS];\n\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n  /* If using full-image storage, this array holds pointers to virtual-array\n   * control blocks for each component.  Unused if not full-image storage.\n   */\n  jvirt_sarray_ptr whole_image[MAX_COMPONENTS];\n#endif\n} my_main_controller;\n\ntypedef my_main_controller * my_main_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(void) process_data_simple_main\n\tJPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,\n\t     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\nMETHODDEF(void) process_data_buffer_main\n\tJPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,\n\t     JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));\n#endif\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n\n  /* Do nothing in raw-data mode. */\n  if (cinfo->raw_data_in)\n    return;\n\n  mainp->cur_iMCU_row = 0;\t/* initialize counters */\n  mainp->rowgroup_ctr = 0;\n  mainp->suspended = FALSE;\n  mainp->pass_mode = pass_mode;\t/* save mode for use by process_data */\n\n  switch (pass_mode) {\n  case JBUF_PASS_THRU:\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n    if (mainp->whole_image[0] != NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n#endif\n    mainp->pub.process_data = process_data_simple_main;\n    break;\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n  case JBUF_SAVE_SOURCE:\n  case JBUF_CRANK_DEST:\n  case JBUF_SAVE_AND_PASS:\n    if (mainp->whole_image[0] == NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    mainp->pub.process_data = process_data_buffer_main;\n    break;\n#endif\n  default:\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    break;\n  }\n}\n\n\n/*\n * Process some data.\n * This routine handles the simple pass-through mode,\n * where we have only a strip buffer.\n */\n\nMETHODDEF(void)\nprocess_data_simple_main (j_compress_ptr cinfo,\n\t\t\t  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,\n\t\t\t  JDIMENSION in_rows_avail)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n\n  while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {\n    /* Read input data if we haven't filled the main buffer yet */\n    if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)\n      (*cinfo->prep->pre_process_data) (cinfo,\n\t\t\t\t\tinput_buf, in_row_ctr, in_rows_avail,\n\t\t\t\t\tmainp->buffer, &mainp->rowgroup_ctr,\n\t\t\t\t\t(JDIMENSION) cinfo->min_DCT_v_scaled_size);\n\n    /* If we don't have a full iMCU row buffered, return to application for\n     * more data.  Note that preprocessor will always pad to fill the iMCU row\n     * at the bottom of the image.\n     */\n    if (mainp->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)\n      return;\n\n    /* Send the completed row to the compressor */\n    if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {\n      /* If compressor did not consume the whole row, then we must need to\n       * suspend processing and return to the application.  In this situation\n       * we pretend we didn't yet consume the last input row; otherwise, if\n       * it happened to be the last row of the image, the application would\n       * think we were done.\n       */\n      if (! mainp->suspended) {\n\t(*in_row_ctr)--;\n\tmainp->suspended = TRUE;\n      }\n      return;\n    }\n    /* We did finish the row.  Undo our little suspension hack if a previous\n     * call suspended; then mark the main buffer empty.\n     */\n    if (mainp->suspended) {\n      (*in_row_ctr)++;\n      mainp->suspended = FALSE;\n    }\n    mainp->rowgroup_ctr = 0;\n    mainp->cur_iMCU_row++;\n  }\n}\n\n\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n\n/*\n * Process some data.\n * This routine handles all of the modes that use a full-size buffer.\n */\n\nMETHODDEF(void)\nprocess_data_buffer_main (j_compress_ptr cinfo,\n\t\t\t  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,\n\t\t\t  JDIMENSION in_rows_avail)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n  int ci;\n  jpeg_component_info *compptr;\n  boolean writing = (mainp->pass_mode != JBUF_CRANK_DEST);\n\n  while (mainp->cur_iMCU_row < cinfo->total_iMCU_rows) {\n    /* Realign the virtual buffers if at the start of an iMCU row. */\n    if (mainp->rowgroup_ctr == 0) {\n      for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t   ci++, compptr++) {\n\tmainp->buffer[ci] = (*cinfo->mem->access_virt_sarray)\n\t  ((j_common_ptr) cinfo, mainp->whole_image[ci], mainp->cur_iMCU_row *\n\t   ((JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size)),\n\t   (JDIMENSION) (compptr->v_samp_factor * cinfo->min_DCT_v_scaled_size),\n\t   writing);\n      }\n      /* In a read pass, pretend we just read some source data. */\n      if (! writing) {\n\t*in_row_ctr += (JDIMENSION)\n\t  (cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size);\n\tmainp->rowgroup_ctr = (JDIMENSION) cinfo->min_DCT_v_scaled_size;\n      }\n    }\n\n    /* If a write pass, read input data until the current iMCU row is full. */\n    /* Note: preprocessor will pad if necessary to fill the last iMCU row. */\n    if (writing) {\n      (*cinfo->prep->pre_process_data) (cinfo,\n\t\t\t\t\tinput_buf, in_row_ctr, in_rows_avail,\n\t\t\t\t\tmainp->buffer, &mainp->rowgroup_ctr,\n\t\t\t\t\t(JDIMENSION) cinfo->min_DCT_v_scaled_size);\n      /* Return to application if we need more data to fill the iMCU row. */\n      if (mainp->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)\n\treturn;\n    }\n\n    /* Emit data, unless this is a sink-only pass. */\n    if (mainp->pass_mode != JBUF_SAVE_SOURCE) {\n      if (! (*cinfo->coef->compress_data) (cinfo, mainp->buffer)) {\n\t/* If compressor did not consume the whole row, then we must need to\n\t * suspend processing and return to the application.  In this situation\n\t * we pretend we didn't yet consume the last input row; otherwise, if\n\t * it happened to be the last row of the image, the application would\n\t * think we were done.\n\t */\n\tif (! mainp->suspended) {\n\t  (*in_row_ctr)--;\n\t  mainp->suspended = TRUE;\n\t}\n\treturn;\n      }\n      /* We did finish the row.  Undo our little suspension hack if a previous\n       * call suspended; then mark the main buffer empty.\n       */\n      if (mainp->suspended) {\n\t(*in_row_ctr)++;\n\tmainp->suspended = FALSE;\n      }\n    }\n\n    /* If get here, we are done with this iMCU row.  Mark buffer empty. */\n    mainp->rowgroup_ctr = 0;\n    mainp->cur_iMCU_row++;\n  }\n}\n\n#endif /* FULL_MAIN_BUFFER_SUPPORTED */\n\n\n/*\n * Initialize main buffer controller.\n */\n\nGLOBAL(void)\njinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)\n{\n  my_main_ptr mainp;\n  int ci;\n  jpeg_component_info *compptr;\n\n  mainp = (my_main_ptr)\n    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\tSIZEOF(my_main_controller));\n  cinfo->main = &mainp->pub;\n  mainp->pub.start_pass = start_pass_main;\n\n  /* We don't need to create a buffer in raw-data mode. */\n  if (cinfo->raw_data_in)\n    return;\n\n  /* Create the buffer.  It holds downsampled data, so each component\n   * may be of a different size.\n   */\n  if (need_full_buffer) {\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n    /* Allocate a full-image virtual array for each component */\n    /* Note we pad the bottom to a multiple of the iMCU height */\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      mainp->whole_image[ci] = (*cinfo->mem->request_virt_sarray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n\t compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),\n\t ((JDIMENSION) jround_up((long) compptr->height_in_blocks,\n\t\t\t\t (long) compptr->v_samp_factor)) *\n\t ((JDIMENSION) cinfo->min_DCT_v_scaled_size),\n\t (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));\n    }\n#else\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n#endif\n  } else {\n#ifdef FULL_MAIN_BUFFER_SUPPORTED\n    mainp->whole_image[0] = NULL; /* flag for no virtual arrays */\n#endif\n    /* Allocate a strip buffer for each component */\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      mainp->buffer[ci] = (*cinfo->mem->alloc_sarray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),\n\t (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));\n    }\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcmarker.c",
    "content": "/*\n * jcmarker.c\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modified 2003-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write JPEG datastream markers.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\ntypedef enum {\t\t\t/* JPEG marker codes */\n  M_SOF0  = 0xc0,\n  M_SOF1  = 0xc1,\n  M_SOF2  = 0xc2,\n  M_SOF3  = 0xc3,\n\n  M_SOF5  = 0xc5,\n  M_SOF6  = 0xc6,\n  M_SOF7  = 0xc7,\n\n  M_JPG   = 0xc8,\n  M_SOF9  = 0xc9,\n  M_SOF10 = 0xca,\n  M_SOF11 = 0xcb,\n\n  M_SOF13 = 0xcd,\n  M_SOF14 = 0xce,\n  M_SOF15 = 0xcf,\n\n  M_DHT   = 0xc4,\n\n  M_DAC   = 0xcc,\n\n  M_RST0  = 0xd0,\n  M_RST1  = 0xd1,\n  M_RST2  = 0xd2,\n  M_RST3  = 0xd3,\n  M_RST4  = 0xd4,\n  M_RST5  = 0xd5,\n  M_RST6  = 0xd6,\n  M_RST7  = 0xd7,\n\n  M_SOI   = 0xd8,\n  M_EOI   = 0xd9,\n  M_SOS   = 0xda,\n  M_DQT   = 0xdb,\n  M_DNL   = 0xdc,\n  M_DRI   = 0xdd,\n  M_DHP   = 0xde,\n  M_EXP   = 0xdf,\n\n  M_APP0  = 0xe0,\n  M_APP1  = 0xe1,\n  M_APP2  = 0xe2,\n  M_APP3  = 0xe3,\n  M_APP4  = 0xe4,\n  M_APP5  = 0xe5,\n  M_APP6  = 0xe6,\n  M_APP7  = 0xe7,\n  M_APP8  = 0xe8,\n  M_APP9  = 0xe9,\n  M_APP10 = 0xea,\n  M_APP11 = 0xeb,\n  M_APP12 = 0xec,\n  M_APP13 = 0xed,\n  M_APP14 = 0xee,\n  M_APP15 = 0xef,\n\n  M_JPG0  = 0xf0,\n  M_JPG8  = 0xf8,\n  M_JPG13 = 0xfd,\n  M_COM   = 0xfe,\n\n  M_TEM   = 0x01,\n\n  M_ERROR = 0x100\n} JPEG_MARKER;\n\n\n/* Private state */\n\ntypedef struct {\n  struct jpeg_marker_writer pub; /* public fields */\n\n  unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */\n} my_marker_writer;\n\ntypedef my_marker_writer * my_marker_ptr;\n\n\n/*\n * Basic output routines.\n *\n * Note that we do not support suspension while writing a marker.\n * Therefore, an application using suspension must ensure that there is\n * enough buffer space for the initial markers (typ. 600-700 bytes) before\n * calling jpeg_start_compress, and enough space to write the trailing EOI\n * (a few bytes) before calling jpeg_finish_compress.  Multipass compression\n * modes are not supported at all with suspension, so those two are the only\n * points where markers will be written.\n */\n\nLOCAL(void)\nemit_byte (j_compress_ptr cinfo, int val)\n/* Emit a byte */\n{\n  struct jpeg_destination_mgr * dest = cinfo->dest;\n\n  *(dest->next_output_byte)++ = (JOCTET) val;\n  if (--dest->free_in_buffer == 0) {\n    if (! (*dest->empty_output_buffer) (cinfo))\n      ERREXIT(cinfo, JERR_CANT_SUSPEND);\n  }\n}\n\n\nLOCAL(void)\nemit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)\n/* Emit a marker code */\n{\n  emit_byte(cinfo, 0xFF);\n  emit_byte(cinfo, (int) mark);\n}\n\n\nLOCAL(void)\nemit_2bytes (j_compress_ptr cinfo, int value)\n/* Emit a 2-byte integer; these are always MSB first in JPEG files */\n{\n  emit_byte(cinfo, (value >> 8) & 0xFF);\n  emit_byte(cinfo, value & 0xFF);\n}\n\n\n/*\n * Routines to write specific marker types.\n */\n\nLOCAL(int)\nemit_dqt (j_compress_ptr cinfo, int index)\n/* Emit a DQT marker */\n/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */\n{\n  JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];\n  int prec;\n  int i;\n\n  if (qtbl == NULL)\n    ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);\n\n  prec = 0;\n  for (i = 0; i <= cinfo->lim_Se; i++) {\n    if (qtbl->quantval[cinfo->natural_order[i]] > 255)\n      prec = 1;\n  }\n\n  if (! qtbl->sent_table) {\n    emit_marker(cinfo, M_DQT);\n\n    emit_2bytes(cinfo,\n      prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2);\n\n    emit_byte(cinfo, index + (prec<<4));\n\n    for (i = 0; i <= cinfo->lim_Se; i++) {\n      /* The table entries must be emitted in zigzag order. */\n      unsigned int qval = qtbl->quantval[cinfo->natural_order[i]];\n      if (prec)\n\temit_byte(cinfo, (int) (qval >> 8));\n      emit_byte(cinfo, (int) (qval & 0xFF));\n    }\n\n    qtbl->sent_table = TRUE;\n  }\n\n  return prec;\n}\n\n\nLOCAL(void)\nemit_dht (j_compress_ptr cinfo, int index, boolean is_ac)\n/* Emit a DHT marker */\n{\n  JHUFF_TBL * htbl;\n  int length, i;\n  \n  if (is_ac) {\n    htbl = cinfo->ac_huff_tbl_ptrs[index];\n    index += 0x10;\t\t/* output index has AC bit set */\n  } else {\n    htbl = cinfo->dc_huff_tbl_ptrs[index];\n  }\n\n  if (htbl == NULL)\n    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);\n  \n  if (! htbl->sent_table) {\n    emit_marker(cinfo, M_DHT);\n    \n    length = 0;\n    for (i = 1; i <= 16; i++)\n      length += htbl->bits[i];\n    \n    emit_2bytes(cinfo, length + 2 + 1 + 16);\n    emit_byte(cinfo, index);\n    \n    for (i = 1; i <= 16; i++)\n      emit_byte(cinfo, htbl->bits[i]);\n    \n    for (i = 0; i < length; i++)\n      emit_byte(cinfo, htbl->huffval[i]);\n    \n    htbl->sent_table = TRUE;\n  }\n}\n\n\nLOCAL(void)\nemit_dac (j_compress_ptr cinfo)\n/* Emit a DAC marker */\n/* Since the useful info is so small, we want to emit all the tables in */\n/* one DAC marker.  Therefore this routine does its own scan of the table. */\n{\n#ifdef C_ARITH_CODING_SUPPORTED\n  char dc_in_use[NUM_ARITH_TBLS];\n  char ac_in_use[NUM_ARITH_TBLS];\n  int length, i;\n  jpeg_component_info *compptr;\n\n  for (i = 0; i < NUM_ARITH_TBLS; i++)\n    dc_in_use[i] = ac_in_use[i] = 0;\n\n  for (i = 0; i < cinfo->comps_in_scan; i++) {\n    compptr = cinfo->cur_comp_info[i];\n    /* DC needs no table for refinement scan */\n    if (cinfo->Ss == 0 && cinfo->Ah == 0)\n      dc_in_use[compptr->dc_tbl_no] = 1;\n    /* AC needs no table when not present */\n    if (cinfo->Se)\n      ac_in_use[compptr->ac_tbl_no] = 1;\n  }\n\n  length = 0;\n  for (i = 0; i < NUM_ARITH_TBLS; i++)\n    length += dc_in_use[i] + ac_in_use[i];\n\n  if (length) {\n    emit_marker(cinfo, M_DAC);\n\n    emit_2bytes(cinfo, length*2 + 2);\n\n    for (i = 0; i < NUM_ARITH_TBLS; i++) {\n      if (dc_in_use[i]) {\n\temit_byte(cinfo, i);\n\temit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));\n      }\n      if (ac_in_use[i]) {\n\temit_byte(cinfo, i + 0x10);\n\temit_byte(cinfo, cinfo->arith_ac_K[i]);\n      }\n    }\n  }\n#endif /* C_ARITH_CODING_SUPPORTED */\n}\n\n\nLOCAL(void)\nemit_dri (j_compress_ptr cinfo)\n/* Emit a DRI marker */\n{\n  emit_marker(cinfo, M_DRI);\n  \n  emit_2bytes(cinfo, 4);\t/* fixed length */\n\n  emit_2bytes(cinfo, (int) cinfo->restart_interval);\n}\n\n\nLOCAL(void)\nemit_lse_ict (j_compress_ptr cinfo)\n/* Emit an LSE inverse color transform specification marker */\n{\n  /* Support only 1 transform */\n  if (cinfo->color_transform != JCT_SUBTRACT_GREEN ||\n      cinfo->num_components < 3)\n    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n\n  emit_marker(cinfo, M_JPG8);\n  \n  emit_2bytes(cinfo, 24);\t/* fixed length */\n\n  emit_byte(cinfo, 0x0D);\t/* ID inverse transform specification */\n  emit_2bytes(cinfo, MAXJSAMPLE);\t/* MAXTRANS */\n  emit_byte(cinfo, 3);\t\t/* Nt=3 */\n  emit_byte(cinfo, cinfo->comp_info[1].component_id);\n  emit_byte(cinfo, cinfo->comp_info[0].component_id);\n  emit_byte(cinfo, cinfo->comp_info[2].component_id);\n  emit_byte(cinfo, 0x80);\t/* F1: CENTER1=1, NORM1=0 */\n  emit_2bytes(cinfo, 0);\t/* A(1,1)=0 */\n  emit_2bytes(cinfo, 0);\t/* A(1,2)=0 */\n  emit_byte(cinfo, 0);\t\t/* F2: CENTER2=0, NORM2=0 */\n  emit_2bytes(cinfo, 1);\t/* A(2,1)=1 */\n  emit_2bytes(cinfo, 0);\t/* A(2,2)=0 */\n  emit_byte(cinfo, 0);\t\t/* F3: CENTER3=0, NORM3=0 */\n  emit_2bytes(cinfo, 1);\t/* A(3,1)=1 */\n  emit_2bytes(cinfo, 0);\t/* A(3,2)=0 */\n}\n\n\nLOCAL(void)\nemit_sof (j_compress_ptr cinfo, JPEG_MARKER code)\n/* Emit a SOF marker */\n{\n  int ci;\n  jpeg_component_info *compptr;\n  \n  emit_marker(cinfo, code);\n  \n  emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */\n\n  /* Make sure image isn't bigger than SOF field can handle */\n  if ((long) cinfo->jpeg_height > 65535L ||\n      (long) cinfo->jpeg_width > 65535L)\n    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);\n\n  emit_byte(cinfo, cinfo->data_precision);\n  emit_2bytes(cinfo, (int) cinfo->jpeg_height);\n  emit_2bytes(cinfo, (int) cinfo->jpeg_width);\n\n  emit_byte(cinfo, cinfo->num_components);\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    emit_byte(cinfo, compptr->component_id);\n    emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);\n    emit_byte(cinfo, compptr->quant_tbl_no);\n  }\n}\n\n\nLOCAL(void)\nemit_sos (j_compress_ptr cinfo)\n/* Emit a SOS marker */\n{\n  int i, td, ta;\n  jpeg_component_info *compptr;\n  \n  emit_marker(cinfo, M_SOS);\n  \n  emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */\n  \n  emit_byte(cinfo, cinfo->comps_in_scan);\n  \n  for (i = 0; i < cinfo->comps_in_scan; i++) {\n    compptr = cinfo->cur_comp_info[i];\n    emit_byte(cinfo, compptr->component_id);\n\n    /* We emit 0 for unused field(s); this is recommended by the P&M text\n     * but does not seem to be specified in the standard.\n     */\n\n    /* DC needs no table for refinement scan */\n    td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0;\n    /* AC needs no table when not present */\n    ta = cinfo->Se ? compptr->ac_tbl_no : 0;\n\n    emit_byte(cinfo, (td << 4) + ta);\n  }\n\n  emit_byte(cinfo, cinfo->Ss);\n  emit_byte(cinfo, cinfo->Se);\n  emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);\n}\n\n\nLOCAL(void)\nemit_pseudo_sos (j_compress_ptr cinfo)\n/* Emit a pseudo SOS marker */\n{\n  emit_marker(cinfo, M_SOS);\n  \n  emit_2bytes(cinfo, 2 + 1 + 3); /* length */\n  \n  emit_byte(cinfo, 0); /* Ns */\n\n  emit_byte(cinfo, 0); /* Ss */\n  emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */\n  emit_byte(cinfo, 0); /* Ah/Al */\n}\n\n\nLOCAL(void)\nemit_jfif_app0 (j_compress_ptr cinfo)\n/* Emit a JFIF-compliant APP0 marker */\n{\n  /*\n   * Length of APP0 block\t(2 bytes)\n   * Block ID\t\t\t(4 bytes - ASCII \"JFIF\")\n   * Zero byte\t\t\t(1 byte to terminate the ID string)\n   * Version Major, Minor\t(2 bytes - major first)\n   * Units\t\t\t(1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)\n   * Xdpu\t\t\t(2 bytes - dots per unit horizontal)\n   * Ydpu\t\t\t(2 bytes - dots per unit vertical)\n   * Thumbnail X size\t\t(1 byte)\n   * Thumbnail Y size\t\t(1 byte)\n   */\n  \n  emit_marker(cinfo, M_APP0);\n  \n  emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */\n\n  emit_byte(cinfo, 0x4A);\t/* Identifier: ASCII \"JFIF\" */\n  emit_byte(cinfo, 0x46);\n  emit_byte(cinfo, 0x49);\n  emit_byte(cinfo, 0x46);\n  emit_byte(cinfo, 0);\n  emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */\n  emit_byte(cinfo, cinfo->JFIF_minor_version);\n  emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */\n  emit_2bytes(cinfo, (int) cinfo->X_density);\n  emit_2bytes(cinfo, (int) cinfo->Y_density);\n  emit_byte(cinfo, 0);\t\t/* No thumbnail image */\n  emit_byte(cinfo, 0);\n}\n\n\nLOCAL(void)\nemit_adobe_app14 (j_compress_ptr cinfo)\n/* Emit an Adobe APP14 marker */\n{\n  /*\n   * Length of APP14 block\t(2 bytes)\n   * Block ID\t\t\t(5 bytes - ASCII \"Adobe\")\n   * Version Number\t\t(2 bytes - currently 100)\n   * Flags0\t\t\t(2 bytes - currently 0)\n   * Flags1\t\t\t(2 bytes - currently 0)\n   * Color transform\t\t(1 byte)\n   *\n   * Although Adobe TN 5116 mentions Version = 101, all the Adobe files\n   * now in circulation seem to use Version = 100, so that's what we write.\n   *\n   * We write the color transform byte as 1 if the JPEG color space is\n   * YCbCr, 2 if it's YCCK, 0 otherwise.  Adobe's definition has to do with\n   * whether the encoder performed a transformation, which is pretty useless.\n   */\n  \n  emit_marker(cinfo, M_APP14);\n  \n  emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */\n\n  emit_byte(cinfo, 0x41);\t/* Identifier: ASCII \"Adobe\" */\n  emit_byte(cinfo, 0x64);\n  emit_byte(cinfo, 0x6F);\n  emit_byte(cinfo, 0x62);\n  emit_byte(cinfo, 0x65);\n  emit_2bytes(cinfo, 100);\t/* Version */\n  emit_2bytes(cinfo, 0);\t/* Flags0 */\n  emit_2bytes(cinfo, 0);\t/* Flags1 */\n  switch (cinfo->jpeg_color_space) {\n  case JCS_YCbCr:\n    emit_byte(cinfo, 1);\t/* Color transform = 1 */\n    break;\n  case JCS_YCCK:\n    emit_byte(cinfo, 2);\t/* Color transform = 2 */\n    break;\n  default:\n    emit_byte(cinfo, 0);\t/* Color transform = 0 */\n  }\n}\n\n\n/*\n * These routines allow writing an arbitrary marker with parameters.\n * The only intended use is to emit COM or APPn markers after calling\n * write_file_header and before calling write_frame_header.\n * Other uses are not guaranteed to produce desirable results.\n * Counting the parameter bytes properly is the caller's responsibility.\n */\n\nMETHODDEF(void)\nwrite_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)\n/* Emit an arbitrary marker header */\n{\n  if (datalen > (unsigned int) 65533)\t\t/* safety check */\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  emit_marker(cinfo, (JPEG_MARKER) marker);\n\n  emit_2bytes(cinfo, (int) (datalen + 2));\t/* total length */\n}\n\nMETHODDEF(void)\nwrite_marker_byte (j_compress_ptr cinfo, int val)\n/* Emit one byte of marker parameters following write_marker_header */\n{\n  emit_byte(cinfo, val);\n}\n\n\n/*\n * Write datastream header.\n * This consists of an SOI and optional APPn markers.\n * We recommend use of the JFIF marker, but not the Adobe marker,\n * when using YCbCr or grayscale data.  The JFIF marker is also used\n * for other standard JPEG colorspaces.  The Adobe marker is helpful\n * to distinguish RGB, CMYK, and YCCK colorspaces.\n * Note that an application can write additional header markers after\n * jpeg_start_compress returns.\n */\n\nMETHODDEF(void)\nwrite_file_header (j_compress_ptr cinfo)\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n\n  emit_marker(cinfo, M_SOI);\t/* first the SOI */\n\n  /* SOI is defined to reset restart interval to 0 */\n  marker->last_restart_interval = 0;\n\n  if (cinfo->write_JFIF_header)\t/* next an optional JFIF APP0 */\n    emit_jfif_app0(cinfo);\n  if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */\n    emit_adobe_app14(cinfo);\n}\n\n\n/*\n * Write frame header.\n * This consists of DQT and SOFn markers,\n * a conditional LSE marker and a conditional pseudo SOS marker.\n * Note that we do not emit the SOF until we have emitted the DQT(s).\n * This avoids compatibility problems with incorrect implementations that\n * try to error-check the quant table numbers as soon as they see the SOF.\n */\n\nMETHODDEF(void)\nwrite_frame_header (j_compress_ptr cinfo)\n{\n  int ci, prec;\n  boolean is_baseline;\n  jpeg_component_info *compptr;\n  \n  /* Emit DQT for each quantization table.\n   * Note that emit_dqt() suppresses any duplicate tables.\n   */\n  prec = 0;\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    prec += emit_dqt(cinfo, compptr->quant_tbl_no);\n  }\n  /* now prec is nonzero iff there are any 16-bit quant tables. */\n\n  /* Check for a non-baseline specification.\n   * Note we assume that Huffman table numbers won't be changed later.\n   */\n  if (cinfo->arith_code || cinfo->progressive_mode ||\n      cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) {\n    is_baseline = FALSE;\n  } else {\n    is_baseline = TRUE;\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)\n\tis_baseline = FALSE;\n    }\n    if (prec && is_baseline) {\n      is_baseline = FALSE;\n      /* If it's baseline except for quantizer size, warn the user */\n      TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);\n    }\n  }\n\n  /* Emit the proper SOF marker */\n  if (cinfo->arith_code) {\n    if (cinfo->progressive_mode)\n      emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */\n    else\n      emit_sof(cinfo, M_SOF9);  /* SOF code for sequential arithmetic */\n  } else {\n    if (cinfo->progressive_mode)\n      emit_sof(cinfo, M_SOF2);\t/* SOF code for progressive Huffman */\n    else if (is_baseline)\n      emit_sof(cinfo, M_SOF0);\t/* SOF code for baseline implementation */\n    else\n      emit_sof(cinfo, M_SOF1);\t/* SOF code for non-baseline Huffman file */\n  }\n\n  /* Check to emit LSE inverse color transform specification marker */\n  if (cinfo->color_transform)\n    emit_lse_ict(cinfo);\n\n  /* Check to emit pseudo SOS marker */\n  if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE)\n    emit_pseudo_sos(cinfo);\n}\n\n\n/*\n * Write scan header.\n * This consists of DHT or DAC markers, optional DRI, and SOS.\n * Compressed data will be written following the SOS.\n */\n\nMETHODDEF(void)\nwrite_scan_header (j_compress_ptr cinfo)\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n  int i;\n  jpeg_component_info *compptr;\n\n  if (cinfo->arith_code) {\n    /* Emit arith conditioning info.  We may have some duplication\n     * if the file has multiple scans, but it's so small it's hardly\n     * worth worrying about.\n     */\n    emit_dac(cinfo);\n  } else {\n    /* Emit Huffman tables.\n     * Note that emit_dht() suppresses any duplicate tables.\n     */\n    for (i = 0; i < cinfo->comps_in_scan; i++) {\n      compptr = cinfo->cur_comp_info[i];\n      /* DC needs no table for refinement scan */\n      if (cinfo->Ss == 0 && cinfo->Ah == 0)\n\temit_dht(cinfo, compptr->dc_tbl_no, FALSE);\n      /* AC needs no table when not present */\n      if (cinfo->Se)\n\temit_dht(cinfo, compptr->ac_tbl_no, TRUE);\n    }\n  }\n\n  /* Emit DRI if required --- note that DRI value could change for each scan.\n   * We avoid wasting space with unnecessary DRIs, however.\n   */\n  if (cinfo->restart_interval != marker->last_restart_interval) {\n    emit_dri(cinfo);\n    marker->last_restart_interval = cinfo->restart_interval;\n  }\n\n  emit_sos(cinfo);\n}\n\n\n/*\n * Write datastream trailer.\n */\n\nMETHODDEF(void)\nwrite_file_trailer (j_compress_ptr cinfo)\n{\n  emit_marker(cinfo, M_EOI);\n}\n\n\n/*\n * Write an abbreviated table-specification datastream.\n * This consists of SOI, DQT and DHT tables, and EOI.\n * Any table that is defined and not marked sent_table = TRUE will be\n * emitted.  Note that all tables will be marked sent_table = TRUE at exit.\n */\n\nMETHODDEF(void)\nwrite_tables_only (j_compress_ptr cinfo)\n{\n  int i;\n\n  emit_marker(cinfo, M_SOI);\n\n  for (i = 0; i < NUM_QUANT_TBLS; i++) {\n    if (cinfo->quant_tbl_ptrs[i] != NULL)\n      (void) emit_dqt(cinfo, i);\n  }\n\n  if (! cinfo->arith_code) {\n    for (i = 0; i < NUM_HUFF_TBLS; i++) {\n      if (cinfo->dc_huff_tbl_ptrs[i] != NULL)\n\temit_dht(cinfo, i, FALSE);\n      if (cinfo->ac_huff_tbl_ptrs[i] != NULL)\n\temit_dht(cinfo, i, TRUE);\n    }\n  }\n\n  emit_marker(cinfo, M_EOI);\n}\n\n\n/*\n * Initialize the marker writer module.\n */\n\nGLOBAL(void)\njinit_marker_writer (j_compress_ptr cinfo)\n{\n  my_marker_ptr marker;\n\n  /* Create the subobject */\n  marker = (my_marker_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_marker_writer));\n  cinfo->marker = &marker->pub;\n  /* Initialize method pointers */\n  marker->pub.write_file_header = write_file_header;\n  marker->pub.write_frame_header = write_frame_header;\n  marker->pub.write_scan_header = write_scan_header;\n  marker->pub.write_file_trailer = write_file_trailer;\n  marker->pub.write_tables_only = write_tables_only;\n  marker->pub.write_marker_header = write_marker_header;\n  marker->pub.write_marker_byte = write_marker_byte;\n  /* Initialize private state */\n  marker->last_restart_interval = 0;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcmaster.c",
    "content": "/*\n * jcmaster.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains master control logic for the JPEG compressor.\n * These routines are concerned with parameter validation, initial setup,\n * and inter-pass control (determining the number of passes and the work \n * to be done in each pass).\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Private state */\n\ntypedef enum {\n\tmain_pass,\t\t/* input data, also do first output step */\n\thuff_opt_pass,\t\t/* Huffman code optimization pass */\n\toutput_pass\t\t/* data output pass */\n} c_pass_type;\n\ntypedef struct {\n  struct jpeg_comp_master pub;\t/* public fields */\n\n  c_pass_type pass_type;\t/* the type of the current pass */\n\n  int pass_number;\t\t/* # of passes completed */\n  int total_passes;\t\t/* total # of passes needed */\n\n  int scan_number;\t\t/* current index in scan_info[] */\n} my_comp_master;\n\ntypedef my_comp_master * my_master_ptr;\n\n\n/*\n * Support routines that do various essential calculations.\n */\n\nLOCAL(void)\ninitial_setup (j_compress_ptr cinfo)\n/* Do computations that are needed before master selection phase */\n{\n  int ci, ssize;\n  jpeg_component_info *compptr;\n\n  /* Sanity check on block_size */\n  if (cinfo->block_size < 1 || cinfo->block_size > 16)\n    ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size);\n\n  /* Derive natural_order from block_size */\n  switch (cinfo->block_size) {\n  case 2: cinfo->natural_order = jpeg_natural_order2; break;\n  case 3: cinfo->natural_order = jpeg_natural_order3; break;\n  case 4: cinfo->natural_order = jpeg_natural_order4; break;\n  case 5: cinfo->natural_order = jpeg_natural_order5; break;\n  case 6: cinfo->natural_order = jpeg_natural_order6; break;\n  case 7: cinfo->natural_order = jpeg_natural_order7; break;\n  default: cinfo->natural_order = jpeg_natural_order;\n  }\n\n  /* Derive lim_Se from block_size */\n  cinfo->lim_Se = cinfo->block_size < DCTSIZE ?\n    cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1;\n\n  /* Sanity check on image dimensions */\n  if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||\n      cinfo->num_components <= 0)\n    ERREXIT(cinfo, JERR_EMPTY_IMAGE);\n\n  /* Make sure image isn't bigger than I can handle */\n  if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||\n      (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)\n    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);\n\n  /* Only 8 to 12 bits data precision are supported for DCT based JPEG */\n  if (cinfo->data_precision < 8 || cinfo->data_precision > 12)\n    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);\n\n  /* Check that number of components won't exceed internal array sizes */\n  if (cinfo->num_components > MAX_COMPONENTS)\n    ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,\n\t     MAX_COMPONENTS);\n\n  /* Compute maximum sampling factors; check factor validity */\n  cinfo->max_h_samp_factor = 1;\n  cinfo->max_v_samp_factor = 1;\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||\n\tcompptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)\n      ERREXIT(cinfo, JERR_BAD_SAMPLING);\n    cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,\n\t\t\t\t   compptr->h_samp_factor);\n    cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,\n\t\t\t\t   compptr->v_samp_factor);\n  }\n\n  /* Compute dimensions of components */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Fill in the correct component_index value; don't rely on application */\n    compptr->component_index = ci;\n    /* In selecting the actual DCT scaling for each component, we try to\n     * scale down the chroma components via DCT scaling rather than downsampling.\n     * This saves time if the downsampler gets to use 1:1 scaling.\n     * Note this code adapts subsampling ratios which are powers of 2.\n     */\n    ssize = 1;\n#ifdef DCT_SCALING_SUPPORTED\n    if (! cinfo->raw_data_in)\n      while (cinfo->min_DCT_h_scaled_size * ssize <=\n\t     (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&\n\t     (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) ==\n\t     0) {\n\tssize = ssize * 2;\n      }\n#endif\n    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;\n    ssize = 1;\n#ifdef DCT_SCALING_SUPPORTED\n    if (! cinfo->raw_data_in)\n      while (cinfo->min_DCT_v_scaled_size * ssize <=\n\t     (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&\n\t     (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) ==\n\t     0) {\n\tssize = ssize * 2;\n      }\n#endif\n    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;\n\n    /* We don't support DCT ratios larger than 2. */\n    if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)\n\tcompptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;\n    else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)\n\tcompptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;\n\n    /* Size in DCT blocks */\n    compptr->width_in_blocks = (JDIMENSION)\n      jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    compptr->height_in_blocks = (JDIMENSION)\n      jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,\n\t\t    (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n    /* Size in samples */\n    compptr->downsampled_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->jpeg_width *\n\t\t    (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    compptr->downsampled_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->jpeg_height *\n\t\t    (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),\n\t\t    (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n    /* Don't need quantization scale after DCT,\n     * until color conversion says otherwise.\n     */\n    compptr->component_needed = FALSE;\n  }\n\n  /* Compute number of fully interleaved MCU rows (number of times that\n   * main controller will call coefficient controller).\n   */\n  cinfo->total_iMCU_rows = (JDIMENSION)\n    jdiv_round_up((long) cinfo->jpeg_height,\n\t\t  (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n}\n\n\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n\nLOCAL(void)\nvalidate_script (j_compress_ptr cinfo)\n/* Verify that the scan script in cinfo->scan_info[] is valid; also\n * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.\n */\n{\n  const jpeg_scan_info * scanptr;\n  int scanno, ncomps, ci, coefi, thisi;\n  int Ss, Se, Ah, Al;\n  boolean component_sent[MAX_COMPONENTS];\n#ifdef C_PROGRESSIVE_SUPPORTED\n  int * last_bitpos_ptr;\n  int last_bitpos[MAX_COMPONENTS][DCTSIZE2];\n  /* -1 until that coefficient has been seen; then last Al for it */\n#endif\n\n  if (cinfo->num_scans <= 0)\n    ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);\n\n  /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;\n   * for progressive JPEG, no scan can have this.\n   */\n  scanptr = cinfo->scan_info;\n  if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {\n#ifdef C_PROGRESSIVE_SUPPORTED\n    cinfo->progressive_mode = TRUE;\n    last_bitpos_ptr = & last_bitpos[0][0];\n    for (ci = 0; ci < cinfo->num_components; ci++) \n      for (coefi = 0; coefi < DCTSIZE2; coefi++)\n\t*last_bitpos_ptr++ = -1;\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n  } else {\n    cinfo->progressive_mode = FALSE;\n    for (ci = 0; ci < cinfo->num_components; ci++) \n      component_sent[ci] = FALSE;\n  }\n\n  for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {\n    /* Validate component indexes */\n    ncomps = scanptr->comps_in_scan;\n    if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)\n      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);\n    for (ci = 0; ci < ncomps; ci++) {\n      thisi = scanptr->component_index[ci];\n      if (thisi < 0 || thisi >= cinfo->num_components)\n\tERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);\n      /* Components must appear in SOF order within each scan */\n      if (ci > 0 && thisi <= scanptr->component_index[ci-1])\n\tERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);\n    }\n    /* Validate progression parameters */\n    Ss = scanptr->Ss;\n    Se = scanptr->Se;\n    Ah = scanptr->Ah;\n    Al = scanptr->Al;\n    if (cinfo->progressive_mode) {\n#ifdef C_PROGRESSIVE_SUPPORTED\n      /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that\n       * seems wrong: the upper bound ought to depend on data precision.\n       * Perhaps they really meant 0..N+1 for N-bit precision.\n       * Here we allow 0..10 for 8-bit data; Al larger than 10 results in\n       * out-of-range reconstructed DC values during the first DC scan,\n       * which might cause problems for some decoders.\n       */\n      if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||\n\t  Ah < 0 || Ah > (cinfo->data_precision > 8 ? 13 : 10) ||\n\t  Al < 0 || Al > (cinfo->data_precision > 8 ? 13 : 10))\n\tERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n      if (Ss == 0) {\n\tif (Se != 0)\t\t/* DC and AC together not OK */\n\t  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n      } else {\n\tif (ncomps != 1)\t/* AC scans must be for only one component */\n\t  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n      }\n      for (ci = 0; ci < ncomps; ci++) {\n\tlast_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];\n\tif (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */\n\t  ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n\tfor (coefi = Ss; coefi <= Se; coefi++) {\n\t  if (last_bitpos_ptr[coefi] < 0) {\n\t    /* first scan of this coefficient */\n\t    if (Ah != 0)\n\t      ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n\t  } else {\n\t    /* not first scan */\n\t    if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)\n\t      ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n\t  }\n\t  last_bitpos_ptr[coefi] = Al;\n\t}\n      }\n#endif\n    } else {\n      /* For sequential JPEG, all progression parameters must be these: */\n      if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)\n\tERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);\n      /* Make sure components are not sent twice */\n      for (ci = 0; ci < ncomps; ci++) {\n\tthisi = scanptr->component_index[ci];\n\tif (component_sent[thisi])\n\t  ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);\n\tcomponent_sent[thisi] = TRUE;\n      }\n    }\n  }\n\n  /* Now verify that everything got sent. */\n  if (cinfo->progressive_mode) {\n#ifdef C_PROGRESSIVE_SUPPORTED\n    /* For progressive mode, we only check that at least some DC data\n     * got sent for each component; the spec does not require that all bits\n     * of all coefficients be transmitted.  Would it be wiser to enforce\n     * transmission of all coefficient bits??\n     */\n    for (ci = 0; ci < cinfo->num_components; ci++) {\n      if (last_bitpos[ci][0] < 0)\n\tERREXIT(cinfo, JERR_MISSING_DATA);\n    }\n#endif\n  } else {\n    for (ci = 0; ci < cinfo->num_components; ci++) {\n      if (! component_sent[ci])\n\tERREXIT(cinfo, JERR_MISSING_DATA);\n    }\n  }\n}\n\n\nLOCAL(void)\nreduce_script (j_compress_ptr cinfo)\n/* Adapt scan script for use with reduced block size;\n * assume that script has been validated before.\n */\n{\n  jpeg_scan_info * scanptr;\n  int idxout, idxin;\n\n  /* Circumvent const declaration for this function */\n  scanptr = (jpeg_scan_info *) cinfo->scan_info;\n  idxout = 0;\n\n  for (idxin = 0; idxin < cinfo->num_scans; idxin++) {\n    /* After skipping, idxout becomes smaller than idxin */\n    if (idxin != idxout)\n      /* Copy rest of data;\n       * note we stay in given chunk of allocated memory.\n       */\n      scanptr[idxout] = scanptr[idxin];\n    if (scanptr[idxout].Ss > cinfo->lim_Se)\n      /* Entire scan out of range - skip this entry */\n      continue;\n    if (scanptr[idxout].Se > cinfo->lim_Se)\n      /* Limit scan to end of block */\n      scanptr[idxout].Se = cinfo->lim_Se;\n    idxout++;\n  }\n\n  cinfo->num_scans = idxout;\n}\n\n#endif /* C_MULTISCAN_FILES_SUPPORTED */\n\n\nLOCAL(void)\nselect_scan_parameters (j_compress_ptr cinfo)\n/* Set up the scan parameters for the current scan */\n{\n  int ci;\n\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n  if (cinfo->scan_info != NULL) {\n    /* Prepare for current scan --- the script is already validated */\n    my_master_ptr master = (my_master_ptr) cinfo->master;\n    const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;\n\n    cinfo->comps_in_scan = scanptr->comps_in_scan;\n    for (ci = 0; ci < scanptr->comps_in_scan; ci++) {\n      cinfo->cur_comp_info[ci] =\n\t&cinfo->comp_info[scanptr->component_index[ci]];\n    }\n    if (cinfo->progressive_mode) {\n      cinfo->Ss = scanptr->Ss;\n      cinfo->Se = scanptr->Se;\n      cinfo->Ah = scanptr->Ah;\n      cinfo->Al = scanptr->Al;\n      return;\n    }\n  }\n  else\n#endif\n  {\n    /* Prepare for single sequential-JPEG scan containing all components */\n    if (cinfo->num_components > MAX_COMPS_IN_SCAN)\n      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,\n\t       MAX_COMPS_IN_SCAN);\n    cinfo->comps_in_scan = cinfo->num_components;\n    for (ci = 0; ci < cinfo->num_components; ci++) {\n      cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];\n    }\n  }\n  cinfo->Ss = 0;\n  cinfo->Se = cinfo->block_size * cinfo->block_size - 1;\n  cinfo->Ah = 0;\n  cinfo->Al = 0;\n}\n\n\nLOCAL(void)\nper_scan_setup (j_compress_ptr cinfo)\n/* Do computations that are needed before processing a JPEG scan */\n/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */\n{\n  int ci, mcublks, tmp;\n  jpeg_component_info *compptr;\n\n  if (cinfo->comps_in_scan == 1) {\n\n    /* Noninterleaved (single-component) scan */\n    compptr = cinfo->cur_comp_info[0];\n\n    /* Overall image size in MCUs */\n    cinfo->MCUs_per_row = compptr->width_in_blocks;\n    cinfo->MCU_rows_in_scan = compptr->height_in_blocks;\n\n    /* For noninterleaved scan, always one block per MCU */\n    compptr->MCU_width = 1;\n    compptr->MCU_height = 1;\n    compptr->MCU_blocks = 1;\n    compptr->MCU_sample_width = compptr->DCT_h_scaled_size;\n    compptr->last_col_width = 1;\n    /* For noninterleaved scans, it is convenient to define last_row_height\n     * as the number of block rows present in the last iMCU row.\n     */\n    tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);\n    if (tmp == 0) tmp = compptr->v_samp_factor;\n    compptr->last_row_height = tmp;\n\n    /* Prepare array describing MCU composition */\n    cinfo->blocks_in_MCU = 1;\n    cinfo->MCU_membership[0] = 0;\n\n  } else {\n\n    /* Interleaved (multi-component) scan */\n    if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)\n      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,\n\t       MAX_COMPS_IN_SCAN);\n\n    /* Overall image size in MCUs */\n    cinfo->MCUs_per_row = (JDIMENSION)\n      jdiv_round_up((long) cinfo->jpeg_width,\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    cinfo->MCU_rows_in_scan = cinfo->total_iMCU_rows;\n\n    cinfo->blocks_in_MCU = 0;\n\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      compptr = cinfo->cur_comp_info[ci];\n      /* Sampling factors give # of blocks of component in each MCU */\n      compptr->MCU_width = compptr->h_samp_factor;\n      compptr->MCU_height = compptr->v_samp_factor;\n      compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;\n      compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;\n      /* Figure number of non-dummy blocks in last MCU column & row */\n      tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);\n      if (tmp == 0) tmp = compptr->MCU_width;\n      compptr->last_col_width = tmp;\n      tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);\n      if (tmp == 0) tmp = compptr->MCU_height;\n      compptr->last_row_height = tmp;\n      /* Prepare array describing MCU composition */\n      mcublks = compptr->MCU_blocks;\n      if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)\n\tERREXIT(cinfo, JERR_BAD_MCU_SIZE);\n      while (mcublks-- > 0) {\n\tcinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;\n      }\n    }\n\n  }\n\n  /* Convert restart specified in rows to actual MCU count. */\n  /* Note that count must fit in 16 bits, so we provide limiting. */\n  if (cinfo->restart_in_rows > 0) {\n    long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;\n    cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);\n  }\n}\n\n\n/*\n * Per-pass setup.\n * This is called at the beginning of each pass.  We determine which modules\n * will be active during this pass and give them appropriate start_pass calls.\n * We also set is_last_pass to indicate whether any more passes will be\n * required.\n */\n\nMETHODDEF(void)\nprepare_for_pass (j_compress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n\n  switch (master->pass_type) {\n  case main_pass:\n    /* Initial pass: will collect input data, and do either Huffman\n     * optimization or data output for the first scan.\n     */\n    select_scan_parameters(cinfo);\n    per_scan_setup(cinfo);\n    if (! cinfo->raw_data_in) {\n      (*cinfo->cconvert->start_pass) (cinfo);\n      (*cinfo->downsample->start_pass) (cinfo);\n      (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);\n    }\n    (*cinfo->fdct->start_pass) (cinfo);\n    (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);\n    (*cinfo->coef->start_pass) (cinfo,\n\t\t\t\t(master->total_passes > 1 ?\n\t\t\t\t JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));\n    (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);\n    if (cinfo->optimize_coding) {\n      /* No immediate data output; postpone writing frame/scan headers */\n      master->pub.call_pass_startup = FALSE;\n    } else {\n      /* Will write frame/scan headers at first jpeg_write_scanlines call */\n      master->pub.call_pass_startup = TRUE;\n    }\n    break;\n#ifdef ENTROPY_OPT_SUPPORTED\n  case huff_opt_pass:\n    /* Do Huffman optimization for a scan after the first one. */\n    select_scan_parameters(cinfo);\n    per_scan_setup(cinfo);\n    if (cinfo->Ss != 0 || cinfo->Ah == 0) {\n      (*cinfo->entropy->start_pass) (cinfo, TRUE);\n      (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);\n      master->pub.call_pass_startup = FALSE;\n      break;\n    }\n    /* Special case: Huffman DC refinement scans need no Huffman table\n     * and therefore we can skip the optimization pass for them.\n     */\n    master->pass_type = output_pass;\n    master->pass_number++;\n    /*FALLTHROUGH*/\n#endif\n  case output_pass:\n    /* Do a data-output pass. */\n    /* We need not repeat per-scan setup if prior optimization pass did it. */\n    if (! cinfo->optimize_coding) {\n      select_scan_parameters(cinfo);\n      per_scan_setup(cinfo);\n    }\n    (*cinfo->entropy->start_pass) (cinfo, FALSE);\n    (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);\n    /* We emit frame/scan headers now */\n    if (master->scan_number == 0)\n      (*cinfo->marker->write_frame_header) (cinfo);\n    (*cinfo->marker->write_scan_header) (cinfo);\n    master->pub.call_pass_startup = FALSE;\n    break;\n  default:\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n  }\n\n  master->pub.is_last_pass = (master->pass_number == master->total_passes-1);\n\n  /* Set up progress monitor's pass info if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->completed_passes = master->pass_number;\n    cinfo->progress->total_passes = master->total_passes;\n  }\n}\n\n\n/*\n * Special start-of-pass hook.\n * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.\n * In single-pass processing, we need this hook because we don't want to\n * write frame/scan headers during jpeg_start_compress; we want to let the\n * application write COM markers etc. between jpeg_start_compress and the\n * jpeg_write_scanlines loop.\n * In multi-pass processing, this routine is not used.\n */\n\nMETHODDEF(void)\npass_startup (j_compress_ptr cinfo)\n{\n  cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */\n\n  (*cinfo->marker->write_frame_header) (cinfo);\n  (*cinfo->marker->write_scan_header) (cinfo);\n}\n\n\n/*\n * Finish up at end of pass.\n */\n\nMETHODDEF(void)\nfinish_pass_master (j_compress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n\n  /* The entropy coder always needs an end-of-pass call,\n   * either to analyze statistics or to flush its output buffer.\n   */\n  (*cinfo->entropy->finish_pass) (cinfo);\n\n  /* Update state for next pass */\n  switch (master->pass_type) {\n  case main_pass:\n    /* next pass is either output of scan 0 (after optimization)\n     * or output of scan 1 (if no optimization).\n     */\n    master->pass_type = output_pass;\n    if (! cinfo->optimize_coding)\n      master->scan_number++;\n    break;\n  case huff_opt_pass:\n    /* next pass is always output of current scan */\n    master->pass_type = output_pass;\n    break;\n  case output_pass:\n    /* next pass is either optimization or output of next scan */\n    if (cinfo->optimize_coding)\n      master->pass_type = huff_opt_pass;\n    master->scan_number++;\n    break;\n  }\n\n  master->pass_number++;\n}\n\n\n/*\n * Initialize master compression control.\n */\n\nGLOBAL(void)\njinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)\n{\n  my_master_ptr master;\n\n  master = (my_master_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_comp_master));\n  cinfo->master = &master->pub;\n  master->pub.prepare_for_pass = prepare_for_pass;\n  master->pub.pass_startup = pass_startup;\n  master->pub.finish_pass = finish_pass_master;\n  master->pub.is_last_pass = FALSE;\n\n  /* Validate parameters, determine derived values */\n  initial_setup(cinfo);\n\n  if (cinfo->scan_info != NULL) {\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n    validate_script(cinfo);\n    if (cinfo->block_size < DCTSIZE)\n      reduce_script(cinfo);\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n  } else {\n    cinfo->progressive_mode = FALSE;\n    cinfo->num_scans = 1;\n  }\n\n  if (cinfo->optimize_coding)\n    cinfo->arith_code = FALSE; /* disable arithmetic coding */\n  else if (! cinfo->arith_code &&\n\t   (cinfo->progressive_mode ||\n\t    (cinfo->block_size > 1 && cinfo->block_size < DCTSIZE)))\n    /* TEMPORARY HACK ??? */\n    /* assume default tables no good for progressive or reduced AC mode */\n    cinfo->optimize_coding = TRUE; /* force Huffman optimization */\n\n  /* Initialize my private state */\n  if (transcode_only) {\n    /* no main pass in transcoding */\n    if (cinfo->optimize_coding)\n      master->pass_type = huff_opt_pass;\n    else\n      master->pass_type = output_pass;\n  } else {\n    /* for normal compression, first pass is always this type: */\n    master->pass_type = main_pass;\n  }\n  master->scan_number = 0;\n  master->pass_number = 0;\n  if (cinfo->optimize_coding)\n    master->total_passes = cinfo->num_scans * 2;\n  else\n    master->total_passes = cinfo->num_scans;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcomapi.c",
    "content": "/*\n * jcomapi.c\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains application interface routines that are used for both\n * compression and decompression.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Abort processing of a JPEG compression or decompression operation,\n * but don't destroy the object itself.\n *\n * For this, we merely clean up all the nonpermanent memory pools.\n * Note that temp files (virtual arrays) are not allowed to belong to\n * the permanent pool, so we will be able to close all temp files here.\n * Closing a data source or destination, if necessary, is the application's\n * responsibility.\n */\n\nGLOBAL(void)\njpeg_abort (j_common_ptr cinfo)\n{\n  int pool;\n\n  /* Do nothing if called on a not-initialized or destroyed JPEG object. */\n  if (cinfo->mem == NULL)\n    return;\n\n  /* Releasing pools in reverse order might help avoid fragmentation\n   * with some (brain-damaged) malloc libraries.\n   */\n  for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {\n    (*cinfo->mem->free_pool) (cinfo, pool);\n  }\n\n  /* Reset overall state for possible reuse of object */\n  if (cinfo->is_decompressor) {\n    cinfo->global_state = DSTATE_START;\n    /* Try to keep application from accessing now-deleted marker list.\n     * A bit kludgy to do it here, but this is the most central place.\n     */\n    ((j_decompress_ptr) cinfo)->marker_list = NULL;\n  } else {\n    cinfo->global_state = CSTATE_START;\n  }\n}\n\n\n/*\n * Destruction of a JPEG object.\n *\n * Everything gets deallocated except the master jpeg_compress_struct itself\n * and the error manager struct.  Both of these are supplied by the application\n * and must be freed, if necessary, by the application.  (Often they are on\n * the stack and so don't need to be freed anyway.)\n * Closing a data source or destination, if necessary, is the application's\n * responsibility.\n */\n\nGLOBAL(void)\njpeg_destroy (j_common_ptr cinfo)\n{\n  /* We need only tell the memory manager to release everything. */\n  /* NB: mem pointer is NULL if memory mgr failed to initialize. */\n  if (cinfo->mem != NULL)\n    (*cinfo->mem->self_destruct) (cinfo);\n  cinfo->mem = NULL;\t\t/* be safe if jpeg_destroy is called twice */\n  cinfo->global_state = 0;\t/* mark it destroyed */\n}\n\n\n/*\n * Convenience routines for allocating quantization and Huffman tables.\n * (Would jutils.c be a more reasonable place to put these?)\n */\n\nGLOBAL(JQUANT_TBL *)\njpeg_alloc_quant_table (j_common_ptr cinfo)\n{\n  JQUANT_TBL *tbl;\n\n  tbl = (JQUANT_TBL *)\n    (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));\n  tbl->sent_table = FALSE;\t/* make sure this is false in any new table */\n  return tbl;\n}\n\n\nGLOBAL(JHUFF_TBL *)\njpeg_alloc_huff_table (j_common_ptr cinfo)\n{\n  JHUFF_TBL *tbl;\n\n  tbl = (JHUFF_TBL *)\n    (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));\n  tbl->sent_table = FALSE;\t/* make sure this is false in any new table */\n  return tbl;\n}\n\n\n/*\n * Set up the standard Huffman tables (cf. JPEG standard section K.3).\n * IMPORTANT: these are only valid for 8-bit data precision!\n * (Would jutils.c be a more reasonable place to put this?)\n */\n\nGLOBAL(JHUFF_TBL *)\njpeg_std_huff_table (j_common_ptr cinfo, boolean isDC, int tblno)\n{\n  JHUFF_TBL **htblptr, *htbl;\n  const UINT8 *bits, *val;\n  int nsymbols, len;\n\n  static const UINT8 bits_dc_luminance[17] =\n    { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };\n  static const UINT8 val_dc_luminance[] =\n    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };\n\n  static const UINT8 bits_dc_chrominance[17] =\n    { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };\n  static const UINT8 val_dc_chrominance[] =\n    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };\n\n  static const UINT8 bits_ac_luminance[17] =\n    { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };\n  static const UINT8 val_ac_luminance[] =\n    { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,\n      0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,\n      0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,\n      0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,\n      0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,\n      0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,\n      0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,\n      0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,\n      0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,\n      0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,\n      0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,\n      0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,\n      0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,\n      0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n      0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,\n      0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,\n      0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,\n      0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,\n      0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,\n      0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,\n      0xf9, 0xfa };\n\n  static const UINT8 bits_ac_chrominance[17] =\n    { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };\n  static const UINT8 val_ac_chrominance[] =\n    { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,\n      0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,\n      0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,\n      0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,\n      0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,\n      0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,\n      0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,\n      0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n      0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,\n      0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n      0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,\n      0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n      0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,\n      0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,\n      0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,\n      0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,\n      0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,\n      0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,\n      0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,\n      0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,\n      0xf9, 0xfa };\n\n  if (cinfo->is_decompressor) {\n    if (isDC)\n      htblptr = ((j_decompress_ptr) cinfo)->dc_huff_tbl_ptrs;\n    else\n      htblptr = ((j_decompress_ptr) cinfo)->ac_huff_tbl_ptrs;\n  } else {\n    if (isDC)\n      htblptr = ((j_compress_ptr) cinfo)->dc_huff_tbl_ptrs;\n    else\n      htblptr = ((j_compress_ptr) cinfo)->ac_huff_tbl_ptrs;\n  }\n\n  switch (tblno) {\n  case 0:\n    if (isDC) {\n      bits = bits_dc_luminance;\n      val = val_dc_luminance;\n    } else {\n      bits = bits_ac_luminance;\n      val = val_ac_luminance;\n    }\n    break;\n  case 1:\n    if (isDC) {\n      bits = bits_dc_chrominance;\n      val = val_dc_chrominance;\n    } else {\n      bits = bits_ac_chrominance;\n      val = val_ac_chrominance;\n    }\n    break;\n  default:\n    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);\n    return NULL; /* avoid compiler warnings for uninitialized variables */\n  }\n\n  if (htblptr[tblno] == NULL)\n    htblptr[tblno] = jpeg_alloc_huff_table(cinfo);\n\n  htbl = htblptr[tblno];\n\n  /* Copy the number-of-symbols-of-each-code-length counts */\n  MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));\n\n  /* Validate the counts.  We do this here mainly so we can copy the right\n   * number of symbols from the val[] array, without risking marching off\n   * the end of memory.  jxhuff.c will do a more thorough test later.\n   */\n  nsymbols = 0;\n  for (len = 1; len <= 16; len++)\n    nsymbols += bits[len];\n  if (nsymbols > 256)\n    ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n\n  if (nsymbols > 0)\n    MEMCOPY(htbl->huffval, val, nsymbols * SIZEOF(UINT8));\n\n  /* Initialize sent_table FALSE so table will be written to JPEG file. */\n  htbl->sent_table = FALSE;\n\n  return htbl;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jconfig.h",
    "content": "/* jconfig.h.  Generated from jconfig.cfg by configure.  */\n/* jconfig.cfg --- source file edited by configure script */\n/* see jconfig.txt for explanations */\n\n#define HAVE_PROTOTYPES 1\n#define HAVE_UNSIGNED_CHAR 1\n#define HAVE_UNSIGNED_SHORT 1\n/* #undef void */\n/* #undef const */\n/* #undef CHAR_IS_UNSIGNED */\n#define HAVE_STDDEF_H 1\n#define HAVE_STDLIB_H 1\n#define HAVE_LOCALE_H 1\n/* #undef NEED_BSD_STRINGS */\n/* #undef NEED_SYS_TYPES_H */\n/* #undef NEED_FAR_POINTERS */\n/* #undef NEED_SHORT_EXTERNAL_NAMES */\n/* Define this if you get warnings about undefined structures. */\n/* #undef INCOMPLETE_TYPES_BROKEN */\n\n/* Define \"boolean\" as unsigned char, not enum, on Windows systems. */\n#ifdef _WIN32\n#ifndef __RPCNDR_H__\t\t/* don't conflict if rpcndr.h already read */\ntypedef unsigned char boolean;\n#endif\n#ifndef FALSE\t\t\t/* in case these macros already exist */\n#define FALSE\t0\t\t/* values of boolean */\n#endif\n#ifndef TRUE\n#define TRUE\t1\n#endif\n#define HAVE_BOOLEAN\t\t/* prevent jmorecfg.h from redefining it */\n#endif\n\n#ifdef JPEG_INTERNALS\n\n/* #undef RIGHT_SHIFT_IS_UNSIGNED */\n/* #define INLINE __inline__ */\n/* These are for configuring the JPEG memory manager. */\n/* #undef DEFAULT_MAX_MEM */\n/* #undef NO_MKTEMP */\n\n#endif /* JPEG_INTERNALS */\n\n#ifdef JPEG_CJPEG_DJPEG\n\n#define BMP_SUPPORTED\t\t/* BMP image file format */\n#define GIF_SUPPORTED\t\t/* GIF image file format */\n#define PPM_SUPPORTED\t\t/* PBMPLUS PPM/PGM image file format */\n/* #undef RLE_SUPPORTED */\n#define TARGA_SUPPORTED\t\t/* Targa image file format */\n\n/* #undef TWO_FILE_COMMANDLINE */\n/* #undef NEED_SIGNAL_CATCHER */\n/* #undef DONT_USE_B_MODE */\n\n/* Define this if you want percent-done progress reports from cjpeg/djpeg. */\n/* #undef PROGRESS_REPORT */\n\n#endif /* JPEG_CJPEG_DJPEG */\n"
  },
  {
    "path": "dlib/external/libjpeg/jcparam.c",
    "content": "/*\n * jcparam.c\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modified 2003-2022 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains optional default-setting code for the JPEG compressor.\n * Applications do not have to use this file, but those that don't use it\n * must know a lot more about the innards of the JPEG code.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Quantization table setup routines\n */\n\nGLOBAL(void)\njpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,\n\t\t      const unsigned int *basic_table,\n\t\t      int scale_factor, boolean force_baseline)\n/* Define a quantization table equal to the basic_table times\n * a scale factor (given as a percentage).\n * If force_baseline is TRUE, the computed quantization table entries\n * are limited to 1..255 for JPEG baseline compatibility.\n */\n{\n  JQUANT_TBL ** qtblptr;\n  int i;\n  long temp;\n\n  /* Safety check to ensure start_compress not called yet. */\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS)\n    ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl);\n\n  qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];\n\n  if (*qtblptr == NULL)\n    *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);\n\n  for (i = 0; i < DCTSIZE2; i++) {\n    temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;\n    /* limit the values to the valid range */\n    if (temp <= 0L) temp = 1L;\n    if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */\n    if (force_baseline && temp > 255L)\n      temp = 255L;\t\t/* limit to baseline range if requested */\n    (*qtblptr)->quantval[i] = (UINT16) temp;\n  }\n\n  /* Initialize sent_table FALSE so table will be written to JPEG file. */\n  (*qtblptr)->sent_table = FALSE;\n}\n\n\n/* These are the sample quantization tables given in JPEG spec section K.1.\n * NOTE: chrominance DC value is changed from 17 to 16 for lossless support.\n * The spec says that the values given produce \"good\" quality,\n * and when divided by 2, \"very good\" quality.\n */\nstatic const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {\n  16,  11,  10,  16,  24,  40,  51,  61,\n  12,  12,  14,  19,  26,  58,  60,  55,\n  14,  13,  16,  24,  40,  57,  69,  56,\n  14,  17,  22,  29,  51,  87,  80,  62,\n  18,  22,  37,  56,  68, 109, 103,  77,\n  24,  35,  55,  64,  81, 104, 113,  92,\n  49,  64,  78,  87, 103, 121, 120, 101,\n  72,  92,  95,  98, 112, 100, 103,  99\n};\nstatic const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {\n  16,  18,  24,  47,  99,  99,  99,  99,\n  18,  21,  26,  66,  99,  99,  99,  99,\n  24,  26,  56,  99,  99,  99,  99,  99,\n  47,  66,  99,  99,  99,  99,  99,  99,\n  99,  99,  99,  99,  99,  99,  99,  99,\n  99,  99,  99,  99,  99,  99,  99,  99,\n  99,  99,  99,  99,  99,  99,  99,  99,\n  99,  99,  99,  99,  99,  99,  99,  99\n};\n\n\nGLOBAL(void)\njpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)\n/* Set or change the 'quality' (quantization) setting, using default tables\n * and straight percentage-scaling quality scales.\n * This entry point allows different scalings for luminance and chrominance.\n */\n{\n  /* Set up two quantization tables using the specified scaling */\n  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,\n\t\t       cinfo->q_scale_factor[0], force_baseline);\n  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,\n\t\t       cinfo->q_scale_factor[1], force_baseline);\n}\n\n\nGLOBAL(void)\njpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,\n\t\t\t boolean force_baseline)\n/* Set or change the 'quality' (quantization) setting, using default tables\n * and a straight percentage-scaling quality scale.  In most cases it's better\n * to use jpeg_set_quality (below); this entry point is provided for\n * applications that insist on a linear percentage scaling.\n */\n{\n  /* Set up two quantization tables using the specified scaling */\n  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,\n\t\t       scale_factor, force_baseline);\n  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,\n\t\t       scale_factor, force_baseline);\n}\n\n\nGLOBAL(int)\njpeg_quality_scaling (int quality)\n/* Convert a user-specified quality rating to a percentage scaling factor\n * for an underlying quantization table, using our recommended scaling curve.\n * The input 'quality' factor should be 0 (terrible) to 100 (very good).\n */\n{\n  /* Safety limit on quality factor.  Convert 0 to 1 to avoid zero divide. */\n  if (quality <= 0) quality = 1;\n  if (quality > 100) quality = 100;\n\n  /* The basic table is used as-is (scaling 100) for a quality of 50.\n   * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;\n   * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table\n   * to make all the table entries 1 (hence, minimum quantization loss).\n   * Qualities 1..50 are converted to scaling percentage 5000/Q.\n   */\n  if (quality < 50)\n    quality = 5000 / quality;\n  else\n    quality = 200 - quality*2;\n\n  return quality;\n}\n\n\nGLOBAL(void)\njpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)\n/* Set or change the 'quality' (quantization) setting, using default tables.\n * This is the standard quality-adjusting entry point for typical user\n * interfaces; only those who want detailed control over quantization tables\n * would use the preceding routines directly.\n */\n{\n  /* Convert user 0-100 rating to percentage scaling */\n  quality = jpeg_quality_scaling(quality);\n\n  /* Set up standard quality tables */\n  jpeg_set_linear_quality(cinfo, quality, force_baseline);\n}\n\n\n/*\n * Reset standard Huffman tables\n */\n\nLOCAL(void)\nstd_huff_tables (j_compress_ptr cinfo)\n{\n  if (cinfo->dc_huff_tbl_ptrs[0] != NULL)\n    (void) jpeg_std_huff_table((j_common_ptr) cinfo, TRUE, 0);\n\n  if (cinfo->ac_huff_tbl_ptrs[0] != NULL)\n    (void) jpeg_std_huff_table((j_common_ptr) cinfo, FALSE, 0);\n\n  if (cinfo->dc_huff_tbl_ptrs[1] != NULL)\n    (void) jpeg_std_huff_table((j_common_ptr) cinfo, TRUE, 1);\n\n  if (cinfo->ac_huff_tbl_ptrs[1] != NULL)\n    (void) jpeg_std_huff_table((j_common_ptr) cinfo, FALSE, 1);\n}\n\n\n/*\n * Default parameter setup for compression.\n *\n * Applications that don't choose to use this routine must do their\n * own setup of all these parameters.  Alternately, you can call this\n * to establish defaults and then alter parameters selectively.  This\n * is the recommended approach since, if we add any new parameters,\n * your code will still work (they'll be set to reasonable defaults).\n */\n\nGLOBAL(void)\njpeg_set_defaults (j_compress_ptr cinfo)\n{\n  int i;\n\n  /* Safety check to ensure start_compress not called yet. */\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  /* Allocate comp_info array large enough for maximum component count.\n   * Array is made permanent in case application wants to compress\n   * multiple images at same param settings.\n   */\n  if (cinfo->comp_info == NULL)\n    cinfo->comp_info = (jpeg_component_info *)\n      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,\n\t\t\t\t  MAX_COMPONENTS * SIZEOF(jpeg_component_info));\n\n  /* Initialize everything not dependent on the color space */\n\n  cinfo->scale_num = 1;\t\t/* 1:1 scaling */\n  cinfo->scale_denom = 1;\n  cinfo->data_precision = BITS_IN_JSAMPLE;\n  /* Set up two quantization tables using default quality of 75 */\n  jpeg_set_quality(cinfo, 75, TRUE);\n  /* Reset standard Huffman tables */\n  std_huff_tables(cinfo);\n\n  /* Initialize default arithmetic coding conditioning */\n  for (i = 0; i < NUM_ARITH_TBLS; i++) {\n    cinfo->arith_dc_L[i] = 0;\n    cinfo->arith_dc_U[i] = 1;\n    cinfo->arith_ac_K[i] = 5;\n  }\n\n  /* Default is no multiple-scan output */\n  cinfo->scan_info = NULL;\n  cinfo->num_scans = 0;\n\n  /* Expect normal source image, not raw downsampled data */\n  cinfo->raw_data_in = FALSE;\n\n  /* The standard Huffman tables are only valid for 8-bit data precision.\n   * If the precision is higher, use arithmetic coding.\n   * (Alternatively, using Huffman coding would be possible with forcing\n   * optimization on so that usable tables will be computed, or by\n   * supplying default tables that are valid for the desired precision.)\n   * Otherwise, use Huffman coding by default.\n   */\n  cinfo->arith_code = cinfo->data_precision > 8 ? TRUE : FALSE;\n\n  /* By default, don't do extra passes to optimize entropy coding */\n  cinfo->optimize_coding = FALSE;\n\n  /* By default, use the simpler non-cosited sampling alignment */\n  cinfo->CCIR601_sampling = FALSE;\n\n  /* By default, apply fancy downsampling */\n  cinfo->do_fancy_downsampling = TRUE;\n\n  /* No input smoothing */\n  cinfo->smoothing_factor = 0;\n\n  /* DCT algorithm preference */\n  cinfo->dct_method = JDCT_DEFAULT;\n\n  /* No restart markers */\n  cinfo->restart_interval = 0;\n  cinfo->restart_in_rows = 0;\n\n  /* Fill in default JFIF marker parameters.  Note that whether the marker\n   * will actually be written is determined by jpeg_set_colorspace.\n   *\n   * By default, the library emits JFIF version code 1.01.\n   * An application that wants to emit JFIF 1.02 extension markers should set\n   * JFIF_minor_version to 2.  We could probably get away with just defaulting\n   * to 1.02, but there may still be some decoders in use that will complain\n   * about that; saying 1.01 should minimize compatibility problems.\n   *\n   * For wide gamut colorspaces (BG_RGB and BG_YCC), the major version will be\n   * overridden by jpeg_set_colorspace and set to 2.\n   */\n  cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */\n  cinfo->JFIF_minor_version = 1;\n  cinfo->density_unit = 0;\t/* Pixel size is unknown by default */\n  cinfo->X_density = 1;\t\t/* Pixel aspect ratio is square by default */\n  cinfo->Y_density = 1;\n\n  /* No color transform */\n  cinfo->color_transform = JCT_NONE;\n\n  /* Choose JPEG colorspace based on input space, set defaults accordingly */\n\n  jpeg_default_colorspace(cinfo);\n}\n\n\n/*\n * Select an appropriate JPEG colorspace for in_color_space.\n */\n\nGLOBAL(void)\njpeg_default_colorspace (j_compress_ptr cinfo)\n{\n  switch (cinfo->in_color_space) {\n  case JCS_UNKNOWN:\n    jpeg_set_colorspace(cinfo, JCS_UNKNOWN);\n    break;\n  case JCS_GRAYSCALE:\n    jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);\n    break;\n  case JCS_RGB:\n    jpeg_set_colorspace(cinfo, JCS_YCbCr);\n    break;\n  case JCS_YCbCr:\n    jpeg_set_colorspace(cinfo, JCS_YCbCr);\n    break;\n  case JCS_CMYK:\n    jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */\n    break;\n  case JCS_YCCK:\n    jpeg_set_colorspace(cinfo, JCS_YCCK);\n    break;\n  case JCS_BG_RGB:\n    /* No translation for now -- conversion to BG_YCC not yet supportet */\n    jpeg_set_colorspace(cinfo, JCS_BG_RGB);\n    break;\n  case JCS_BG_YCC:\n    jpeg_set_colorspace(cinfo, JCS_BG_YCC);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);\n  }\n}\n\n\n/*\n * Set the JPEG colorspace, and choose colorspace-dependent default values.\n */\n\nGLOBAL(void)\njpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)\n{\n  jpeg_component_info * compptr;\n  int ci;\n\n#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl)  \\\n  (compptr = &cinfo->comp_info[index], \\\n   compptr->component_id = (id), \\\n   compptr->h_samp_factor = (hsamp), \\\n   compptr->v_samp_factor = (vsamp), \\\n   compptr->quant_tbl_no = (quant), \\\n   compptr->dc_tbl_no = (dctbl), \\\n   compptr->ac_tbl_no = (actbl) )\n\n  /* Safety check to ensure start_compress not called yet. */\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  /* For all colorspaces, we use Q and Huff tables 0 for luminance components,\n   * tables 1 for chrominance components.\n   */\n\n  cinfo->jpeg_color_space = colorspace;\n\n  cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */\n  cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */\n\n  switch (colorspace) {\n  case JCS_UNKNOWN:\n    cinfo->num_components = cinfo->input_components;\n    if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)\n      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,\n\t       MAX_COMPONENTS);\n    for (ci = 0; ci < cinfo->num_components; ci++) {\n      SET_COMP(ci, ci, 1,1, 0, 0,0);\n    }\n    break;\n  case JCS_GRAYSCALE:\n    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */\n    cinfo->num_components = 1;\n    /* JFIF specifies component ID 1 */\n    SET_COMP(0, 0x01, 1,1, 0, 0,0);\n    break;\n  case JCS_RGB:\n    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */\n    cinfo->num_components = 3;\n    SET_COMP(0, 0x52 /* 'R' */, 1,1,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);\n    SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);\n    SET_COMP(2, 0x42 /* 'B' */, 1,1,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);\n    break;\n  case JCS_YCbCr:\n    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */\n    cinfo->num_components = 3;\n    /* JFIF specifies component IDs 1,2,3 */\n    /* We default to 2x2 subsamples of chrominance */\n    SET_COMP(0, 0x01, 2,2, 0, 0,0);\n    SET_COMP(1, 0x02, 1,1, 1, 1,1);\n    SET_COMP(2, 0x03, 1,1, 1, 1,1);\n    break;\n  case JCS_CMYK:\n    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */\n    cinfo->num_components = 4;\n    SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);\n    SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);\n    SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);\n    SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);\n    break;\n  case JCS_YCCK:\n    cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */\n    cinfo->num_components = 4;\n    SET_COMP(0, 0x01, 2,2, 0, 0,0);\n    SET_COMP(1, 0x02, 1,1, 1, 1,1);\n    SET_COMP(2, 0x03, 1,1, 1, 1,1);\n    SET_COMP(3, 0x04, 2,2, 0, 0,0);\n    break;\n  case JCS_BG_RGB:\n    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */\n    cinfo->JFIF_major_version = 2;   /* Set JFIF major version = 2 */\n    cinfo->num_components = 3;\n    /* Add offset 0x20 to the normal R/G/B component IDs */\n    SET_COMP(0, 0x72 /* 'r' */, 1,1,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);\n    SET_COMP(1, 0x67 /* 'g' */, 1,1, 0, 0,0);\n    SET_COMP(2, 0x62 /* 'b' */, 1,1,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0,\n\t\tcinfo->color_transform == JCT_SUBTRACT_GREEN ? 1 : 0);\n    break;\n  case JCS_BG_YCC:\n    cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */\n    cinfo->JFIF_major_version = 2;   /* Set JFIF major version = 2 */\n    cinfo->num_components = 3;\n    /* Add offset 0x20 to the normal Cb/Cr component IDs */\n    /* We default to 2x2 subsamples of chrominance */\n    SET_COMP(0, 0x01, 2,2, 0, 0,0);\n    SET_COMP(1, 0x22, 1,1, 1, 1,1);\n    SET_COMP(2, 0x23, 1,1, 1, 1,1);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n  }\n}\n\n\n#ifdef C_PROGRESSIVE_SUPPORTED\n\nLOCAL(jpeg_scan_info *)\nfill_a_scan (jpeg_scan_info * scanptr, int ci,\n\t     int Ss, int Se, int Ah, int Al)\n/* Support routine: generate one scan for specified component */\n{\n  scanptr->comps_in_scan = 1;\n  scanptr->component_index[0] = ci;\n  scanptr->Ss = Ss;\n  scanptr->Se = Se;\n  scanptr->Ah = Ah;\n  scanptr->Al = Al;\n  scanptr++;\n  return scanptr;\n}\n\nLOCAL(jpeg_scan_info *)\nfill_scans (jpeg_scan_info * scanptr, int ncomps,\n\t    int Ss, int Se, int Ah, int Al)\n/* Support routine: generate one scan for each component */\n{\n  int ci;\n\n  for (ci = 0; ci < ncomps; ci++) {\n    scanptr->comps_in_scan = 1;\n    scanptr->component_index[0] = ci;\n    scanptr->Ss = Ss;\n    scanptr->Se = Se;\n    scanptr->Ah = Ah;\n    scanptr->Al = Al;\n    scanptr++;\n  }\n  return scanptr;\n}\n\nLOCAL(jpeg_scan_info *)\nfill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)\n/* Support routine: generate interleaved DC scan if possible, else N scans */\n{\n  int ci;\n\n  if (ncomps <= MAX_COMPS_IN_SCAN) {\n    /* Single interleaved DC scan */\n    scanptr->comps_in_scan = ncomps;\n    for (ci = 0; ci < ncomps; ci++)\n      scanptr->component_index[ci] = ci;\n    scanptr->Ss = scanptr->Se = 0;\n    scanptr->Ah = Ah;\n    scanptr->Al = Al;\n    scanptr++;\n  } else {\n    /* Noninterleaved DC scan for each component */\n    scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);\n  }\n  return scanptr;\n}\n\n\n/*\n * Create a recommended progressive-JPEG script.\n * cinfo->num_components and cinfo->jpeg_color_space must be correct.\n */\n\nGLOBAL(void)\njpeg_simple_progression (j_compress_ptr cinfo)\n{\n  int ncomps = cinfo->num_components;\n  int nscans;\n  jpeg_scan_info * scanptr;\n\n  /* Safety check to ensure start_compress not called yet. */\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  /* Figure space needed for script.  Calculation must match code below! */\n  if (ncomps == 3 &&\n      (cinfo->jpeg_color_space == JCS_YCbCr ||\n       cinfo->jpeg_color_space == JCS_BG_YCC)) {\n    /* Custom script for YCC color images. */\n    nscans = 10;\n  } else {\n    /* All-purpose script for other color spaces. */\n    if (ncomps > MAX_COMPS_IN_SCAN)\n      nscans = 6 * ncomps;\t/* 2 DC + 4 AC scans per component */\n    else\n      nscans = 2 + 4 * ncomps;\t/* 2 DC scans; 4 AC scans per component */\n  }\n\n  /* Allocate space for script.\n   * We need to put it in the permanent pool in case the application performs\n   * multiple compressions without changing the settings.  To avoid a memory\n   * leak if jpeg_simple_progression is called repeatedly for the same JPEG\n   * object, we try to re-use previously allocated space, and we allocate\n   * enough space to handle YCC even if initially asked for grayscale.\n   */\n  if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {\n    cinfo->script_space_size = MAX(nscans, 10);\n    cinfo->script_space = (jpeg_scan_info *)\n      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,\n\t\t\tcinfo->script_space_size * SIZEOF(jpeg_scan_info));\n  }\n  scanptr = cinfo->script_space;\n  cinfo->scan_info = scanptr;\n  cinfo->num_scans = nscans;\n\n  if (ncomps == 3 &&\n      (cinfo->jpeg_color_space == JCS_YCbCr ||\n       cinfo->jpeg_color_space == JCS_BG_YCC)) {\n    /* Custom script for YCC color images. */\n    /* Initial DC scan */\n    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);\n    /* Initial AC scan: get some luma data out in a hurry */\n    scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);\n    /* Chroma data is too small to be worth expending many scans on */\n    scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);\n    scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);\n    /* Complete spectral selection for luma AC */\n    scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);\n    /* Refine next bit of luma AC */\n    scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);\n    /* Finish DC successive approximation */\n    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);\n    /* Finish AC successive approximation */\n    scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);\n    scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);\n    /* Luma bottom bit comes last since it's usually largest scan */\n    scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);\n  } else {\n    /* All-purpose script for other color spaces. */\n    /* Successive approximation first pass */\n    scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);\n    scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);\n    scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);\n    /* Successive approximation second pass */\n    scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);\n    /* Successive approximation final pass */\n    scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);\n    scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);\n  }\n}\n\n#endif /* C_PROGRESSIVE_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jcprepct.c",
    "content": "/*\n * jcprepct.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the compression preprocessing controller.\n * This controller manages the color conversion, downsampling,\n * and edge expansion steps.\n *\n * Most of the complexity here is associated with buffering input rows\n * as required by the downsampler.  See the comments at the head of\n * jcsample.c for the downsampler's needs.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* At present, jcsample.c can request context rows only for smoothing.\n * In the future, we might also need context rows for CCIR601 sampling\n * or other more-complex downsampling procedures.  The code to support\n * context rows should be compiled only if needed.\n */\n#ifdef INPUT_SMOOTHING_SUPPORTED\n#define CONTEXT_ROWS_SUPPORTED\n#endif\n\n\n/*\n * For the simple (no-context-row) case, we just need to buffer one\n * row group's worth of pixels for the downsampling step.  At the bottom of\n * the image, we pad to a full row group by replicating the last pixel row.\n * The downsampler's last output row is then replicated if needed to pad\n * out to a full iMCU row.\n *\n * When providing context rows, we must buffer three row groups' worth of\n * pixels.  Three row groups are physically allocated, but the row pointer\n * arrays are made five row groups high, with the extra pointers above and\n * below \"wrapping around\" to point to the last and first real row groups.\n * This allows the downsampler to access the proper context rows.\n * At the top and bottom of the image, we create dummy context rows by\n * copying the first or last real pixel row.  This copying could be avoided\n * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the\n * trouble on the compression side.\n */\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_c_prep_controller pub; /* public fields */\n\n  /* Downsampling input buffer.  This buffer holds color-converted data\n   * until we have enough to do a downsample step.\n   */\n  JSAMPARRAY color_buf[MAX_COMPONENTS];\n\n  JDIMENSION rows_to_go;\t/* counts rows remaining in source image */\n  int next_buf_row;\t\t/* index of next row to store in color_buf */\n\n#ifdef CONTEXT_ROWS_SUPPORTED\t/* only needed for context case */\n  int this_row_group;\t\t/* starting row index of group to process */\n  int next_buf_stop;\t\t/* downsample when we reach this index */\n#endif\n} my_prep_controller;\n\ntypedef my_prep_controller * my_prep_ptr;\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;\n\n  if (pass_mode != JBUF_PASS_THRU)\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n\n  /* Initialize total-height counter for detecting bottom of image */\n  prep->rows_to_go = cinfo->image_height;\n  /* Mark the conversion buffer empty */\n  prep->next_buf_row = 0;\n#ifdef CONTEXT_ROWS_SUPPORTED\n  /* Preset additional state variables for context mode.\n   * These aren't used in non-context mode, so we needn't test which mode.\n   */\n  prep->this_row_group = 0;\n  /* Set next_buf_stop to stop after two row groups have been read in. */\n  prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;\n#endif\n}\n\n\n/*\n * Expand an image vertically from height input_rows to height output_rows,\n * by duplicating the bottom row.\n */\n\nLOCAL(void)\nexpand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,\n\t\t    int input_rows, int output_rows)\n{\n  register int row;\n\n  for (row = input_rows; row < output_rows; row++) {\n    jcopy_sample_rows(image_data + input_rows - 1,\n\t\t      image_data + row,\n\t\t      1, num_cols);\n  }\n}\n\n\n/*\n * Process some data in the simple no-context case.\n *\n * Preprocessor output data is counted in \"row groups\".  A row group\n * is defined to be v_samp_factor sample rows of each component.\n * Downsampling will produce this much data from each max_v_samp_factor\n * input rows.\n */\n\nMETHODDEF(void)\npre_process_data (j_compress_ptr cinfo,\n\t\t  JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,\n\t\t  JDIMENSION in_rows_avail,\n\t\t  JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,\n\t\t  JDIMENSION out_row_groups_avail)\n{\n  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;\n  int numrows, ci;\n  JDIMENSION inrows;\n  jpeg_component_info * compptr;\n\n  while (*in_row_ctr < in_rows_avail &&\n\t *out_row_group_ctr < out_row_groups_avail) {\n    /* Do color conversion to fill the conversion buffer. */\n    inrows = in_rows_avail - *in_row_ctr;\n    numrows = cinfo->max_v_samp_factor - prep->next_buf_row;\n    numrows = (int) MIN((JDIMENSION) numrows, inrows);\n    (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,\n\t\t\t\t       prep->color_buf,\n\t\t\t\t       (JDIMENSION) prep->next_buf_row,\n\t\t\t\t       numrows);\n    *in_row_ctr += numrows;\n    prep->next_buf_row += numrows;\n    prep->rows_to_go -= numrows;\n    /* If at bottom of image, pad to fill the conversion buffer. */\n    if (prep->rows_to_go == 0 &&\n\tprep->next_buf_row < cinfo->max_v_samp_factor) {\n      for (ci = 0; ci < cinfo->num_components; ci++) {\n\texpand_bottom_edge(prep->color_buf[ci], cinfo->image_width,\n\t\t\t   prep->next_buf_row, cinfo->max_v_samp_factor);\n      }\n      prep->next_buf_row = cinfo->max_v_samp_factor;\n    }\n    /* If we've filled the conversion buffer, empty it. */\n    if (prep->next_buf_row == cinfo->max_v_samp_factor) {\n      (*cinfo->downsample->downsample) (cinfo,\n\t\t\t\t\tprep->color_buf, (JDIMENSION) 0,\n\t\t\t\t\toutput_buf, *out_row_group_ctr);\n      prep->next_buf_row = 0;\n      (*out_row_group_ctr)++;\n    }\n    /* If at bottom of image, pad the output to a full iMCU height.\n     * Note we assume the caller is providing a one-iMCU-height output buffer!\n     */\n    if (prep->rows_to_go == 0 &&\n\t*out_row_group_ctr < out_row_groups_avail) {\n      for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t   ci++, compptr++) {\n\tnumrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n\t\t  cinfo->min_DCT_v_scaled_size;\n\texpand_bottom_edge(output_buf[ci],\n\t\t\t   compptr->width_in_blocks * compptr->DCT_h_scaled_size,\n\t\t\t   (int) (*out_row_group_ctr * numrows),\n\t\t\t   (int) (out_row_groups_avail * numrows));\n      }\n      *out_row_group_ctr = out_row_groups_avail;\n      break;\t\t\t/* can exit outer loop without test */\n    }\n  }\n}\n\n\n#ifdef CONTEXT_ROWS_SUPPORTED\n\n/*\n * Process some data in the context case.\n */\n\nMETHODDEF(void)\npre_process_context (j_compress_ptr cinfo,\n\t\t     JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,\n\t\t     JDIMENSION in_rows_avail,\n\t\t     JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,\n\t\t     JDIMENSION out_row_groups_avail)\n{\n  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;\n  int numrows, ci;\n  int buf_height = cinfo->max_v_samp_factor * 3;\n  JDIMENSION inrows;\n\n  while (*out_row_group_ctr < out_row_groups_avail) {\n    if (*in_row_ctr < in_rows_avail) {\n      /* Do color conversion to fill the conversion buffer. */\n      inrows = in_rows_avail - *in_row_ctr;\n      numrows = prep->next_buf_stop - prep->next_buf_row;\n      numrows = (int) MIN((JDIMENSION) numrows, inrows);\n      (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,\n\t\t\t\t\t prep->color_buf,\n\t\t\t\t\t (JDIMENSION) prep->next_buf_row,\n\t\t\t\t\t numrows);\n      /* Pad at top of image, if first time through */\n      if (prep->rows_to_go == cinfo->image_height) {\n\tfor (ci = 0; ci < cinfo->num_components; ci++) {\n\t  int row;\n\t  for (row = 1; row <= cinfo->max_v_samp_factor; row++) {\n\t    jcopy_sample_rows(prep->color_buf[ci],\n\t\t\t      prep->color_buf[ci] - row,\n\t\t\t      1, cinfo->image_width);\n\t  }\n\t}\n      }\n      *in_row_ctr += numrows;\n      prep->next_buf_row += numrows;\n      prep->rows_to_go -= numrows;\n    } else {\n      /* Return for more data, unless we are at the bottom of the image. */\n      if (prep->rows_to_go != 0)\n\tbreak;\n      /* When at bottom of image, pad to fill the conversion buffer. */\n      if (prep->next_buf_row < prep->next_buf_stop) {\n\tfor (ci = 0; ci < cinfo->num_components; ci++) {\n\t  expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,\n\t\t\t     prep->next_buf_row, prep->next_buf_stop);\n\t}\n\tprep->next_buf_row = prep->next_buf_stop;\n      }\n    }\n    /* If we've gotten enough data, downsample a row group. */\n    if (prep->next_buf_row == prep->next_buf_stop) {\n      (*cinfo->downsample->downsample) (cinfo,\n\t\t\t\t\tprep->color_buf,\n\t\t\t\t\t(JDIMENSION) prep->this_row_group,\n\t\t\t\t\toutput_buf, *out_row_group_ctr);\n      (*out_row_group_ctr)++;\n      /* Advance pointers with wraparound as necessary. */\n      prep->this_row_group += cinfo->max_v_samp_factor;\n      if (prep->this_row_group >= buf_height)\n\tprep->this_row_group = 0;\n      if (prep->next_buf_row >= buf_height)\n\tprep->next_buf_row = 0;\n      prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;\n    }\n  }\n}\n\n\n/*\n * Create the wrapped-around downsampling input buffer needed for context mode.\n */\n\nLOCAL(void)\ncreate_context_buffer (j_compress_ptr cinfo)\n{\n  my_prep_ptr prep = (my_prep_ptr) cinfo->prep;\n  int rgroup_height = cinfo->max_v_samp_factor;\n  int ci, i;\n  jpeg_component_info * compptr;\n  JSAMPARRAY true_buffer, fake_buffer;\n\n  /* Grab enough space for fake row pointers for all the components;\n   * we need five row groups' worth of pointers for each component.\n   */\n  fake_buffer = (JSAMPARRAY) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE,\n     (cinfo->num_components * 5 * rgroup_height) * SIZEOF(JSAMPROW));\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Allocate the actual buffer space (3 row groups) for this component.\n     * We make the buffer wide enough to allow the downsampler to edge-expand\n     * horizontally within the buffer, if it so chooses.\n     */\n    true_buffer = (*cinfo->mem->alloc_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       (JDIMENSION) (((long) compptr->width_in_blocks *\n\t\t      cinfo->min_DCT_h_scaled_size *\n\t\t      cinfo->max_h_samp_factor) / compptr->h_samp_factor),\n       (JDIMENSION) (3 * rgroup_height));\n    /* Copy true buffer row pointers into the middle of the fake row array */\n    MEMCOPY(fake_buffer + rgroup_height, true_buffer,\n\t    3 * rgroup_height * SIZEOF(JSAMPROW));\n    /* Fill in the above and below wraparound pointers */\n    for (i = 0; i < rgroup_height; i++) {\n      fake_buffer[i] = true_buffer[2 * rgroup_height + i];\n      fake_buffer[4 * rgroup_height + i] = true_buffer[i];\n    }\n    prep->color_buf[ci] = fake_buffer + rgroup_height;\n    fake_buffer += 5 * rgroup_height; /* point to space for next component */\n  }\n}\n\n#endif /* CONTEXT_ROWS_SUPPORTED */\n\n\n/*\n * Initialize preprocessing controller.\n */\n\nGLOBAL(void)\njinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)\n{\n  my_prep_ptr prep;\n  int ci;\n  jpeg_component_info * compptr;\n\n  if (need_full_buffer)\t\t/* safety check */\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n\n  prep = (my_prep_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_prep_controller));\n  cinfo->prep = &prep->pub;\n  prep->pub.start_pass = start_pass_prep;\n\n  /* Allocate the color conversion buffer.\n   * We make the buffer wide enough to allow the downsampler to edge-expand\n   * horizontally within the buffer, if it so chooses.\n   */\n  if (cinfo->downsample->need_context_rows) {\n    /* Set up to provide context rows */\n#ifdef CONTEXT_ROWS_SUPPORTED\n    prep->pub.pre_process_data = pre_process_context;\n    create_context_buffer(cinfo);\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n  } else {\n    /* No context, just make it tall enough for one row group */\n    prep->pub.pre_process_data = pre_process_data;\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t (JDIMENSION) (((long) compptr->width_in_blocks *\n\t\t\tcinfo->min_DCT_h_scaled_size *\n\t\t\tcinfo->max_h_samp_factor) / compptr->h_samp_factor),\n\t (JDIMENSION) cinfo->max_v_samp_factor);\n    }\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jcsample.c",
    "content": "/*\n * jcsample.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains downsampling routines.\n *\n * Downsampling input data is counted in \"row groups\".  A row group\n * is defined to be max_v_samp_factor pixel rows of each component,\n * from which the downsampler produces v_samp_factor sample rows.\n * A single row group is processed in each call to the downsampler module.\n *\n * The downsampler is responsible for edge-expansion of its output data\n * to fill an integral number of DCT blocks horizontally.  The source buffer\n * may be modified if it is helpful for this purpose (the source buffer is\n * allocated wide enough to correspond to the desired output width).\n * The caller (the prep controller) is responsible for vertical padding.\n *\n * The downsampler may request \"context rows\" by setting need_context_rows\n * during startup.  In this case, the input arrays will contain at least\n * one row group's worth of pixels above and below the passed-in data;\n * the caller will create dummy rows at image top and bottom by replicating\n * the first or last real pixel row.\n *\n * An excellent reference for image resampling is\n *   Digital Image Warping, George Wolberg, 1990.\n *   Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.\n *\n * The downsampling algorithm used here is a simple average of the source\n * pixels covered by the output pixel.  The hi-falutin sampling literature\n * refers to this as a \"box filter\".  In general the characteristics of a box\n * filter are not very good, but for the specific cases we normally use (1:1\n * and 2:1 ratios) the box is equivalent to a \"triangle filter\" which is not\n * nearly so bad.  If you intend to use other sampling ratios, you'd be well\n * advised to improve this code.\n *\n * A simple input-smoothing capability is provided.  This is mainly intended\n * for cleaning up color-dithered GIF input files (if you find it inadequate,\n * we suggest using an external filtering program such as pnmconvol).  When\n * enabled, each input pixel P is replaced by a weighted sum of itself and its\n * eight neighbors.  P's weight is 1-8*SF and each neighbor's weight is SF,\n * where SF = (smoothing_factor / 1024).\n * Currently, smoothing is only supported for 2h2v sampling factors.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Pointer to routine to downsample a single component */\ntypedef JMETHOD(void, downsample1_ptr,\n\t\t(j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JSAMPARRAY input_data, JSAMPARRAY output_data));\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_downsampler pub;\t/* public fields */\n\n  /* Downsampling method pointers, one per component */\n  downsample1_ptr methods[MAX_COMPONENTS];\n\n  /* Height of an output row group for each component. */\n  int rowgroup_height[MAX_COMPONENTS];\n\n  /* These arrays save pixel expansion factors so that int_downsample need not\n   * recompute them each time.  They are unused for other downsampling methods.\n   */\n  UINT8 h_expand[MAX_COMPONENTS];\n  UINT8 v_expand[MAX_COMPONENTS];\n} my_downsampler;\n\ntypedef my_downsampler * my_downsample_ptr;\n\n\n/*\n * Initialize for a downsampling pass.\n */\n\nMETHODDEF(void)\nstart_pass_downsample (j_compress_ptr cinfo)\n{\n  /* no work for now */\n}\n\n\n/*\n * Expand a component horizontally from width input_cols to width output_cols,\n * by duplicating the rightmost samples.\n */\n\nLOCAL(void)\nexpand_right_edge (JSAMPARRAY image_data, int num_rows,\n\t\t   JDIMENSION input_cols, JDIMENSION output_cols)\n{\n  register JSAMPROW ptr;\n  register JSAMPLE pixval;\n  register int count;\n  int row;\n  int numcols = (int) (output_cols - input_cols);\n\n  if (numcols > 0) {\n    for (row = 0; row < num_rows; row++) {\n      ptr = image_data[row] + input_cols;\n      pixval = ptr[-1];\t\t/* don't need GETJSAMPLE() here */\n      for (count = numcols; count > 0; count--)\n\t*ptr++ = pixval;\n    }\n  }\n}\n\n\n/*\n * Do downsampling for a whole row group (all components).\n *\n * In this version we simply downsample each component independently.\n */\n\nMETHODDEF(void)\nsep_downsample (j_compress_ptr cinfo,\n\t\tJSAMPIMAGE input_buf, JDIMENSION in_row_index,\n\t\tJSAMPIMAGE output_buf, JDIMENSION out_row_group_index)\n{\n  my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;\n  int ci;\n  jpeg_component_info * compptr;\n  JSAMPARRAY in_ptr, out_ptr;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    in_ptr = input_buf[ci] + in_row_index;\n    out_ptr = output_buf[ci] +\n\t      (out_row_group_index * downsample->rowgroup_height[ci]);\n    (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);\n  }\n}\n\n\n/*\n * Downsample pixel values of a single component.\n * One row group is processed per call.\n * This version handles arbitrary integral sampling ratios, without smoothing.\n * Note that this version is not actually used for customary sampling ratios.\n */\n\nMETHODDEF(void)\nint_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;\n  int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;\n  JDIMENSION outcol, outcol_h;\t/* outcol_h == outcol*h_expand */\n  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;\n  JSAMPROW inptr, outptr;\n  INT32 outvalue;\n\n  h_expand = downsample->h_expand[compptr->component_index];\n  v_expand = downsample->v_expand[compptr->component_index];\n  numpix = h_expand * v_expand;\n  numpix2 = numpix/2;\n\n  /* Expand input data enough to let all the output samples be generated\n   * by the standard loop.  Special-casing padded output would be more\n   * efficient.\n   */\n  expand_right_edge(input_data, cinfo->max_v_samp_factor,\n\t\t    cinfo->image_width, output_cols * h_expand);\n\n  inrow = outrow = 0;\n  while (inrow < cinfo->max_v_samp_factor) {\n    outptr = output_data[outrow];\n    for (outcol = 0, outcol_h = 0; outcol < output_cols;\n\t outcol++, outcol_h += h_expand) {\n      outvalue = 0;\n      for (v = 0; v < v_expand; v++) {\n\tinptr = input_data[inrow+v] + outcol_h;\n\tfor (h = 0; h < h_expand; h++) {\n\t  outvalue += (INT32) GETJSAMPLE(*inptr++);\n\t}\n      }\n      *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);\n    }\n    inrow += v_expand;\n    outrow++;\n  }\n}\n\n\n/*\n * Downsample pixel values of a single component.\n * This version handles the special case of a full-size component,\n * without smoothing.\n */\n\nMETHODDEF(void)\nfullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t     JSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  /* Copy the data */\n  jcopy_sample_rows(input_data, output_data,\n\t\t    cinfo->max_v_samp_factor, cinfo->image_width);\n  /* Edge-expand */\n  expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,\n\t\t    compptr->width_in_blocks * compptr->DCT_h_scaled_size);\n}\n\n\n/*\n * Downsample pixel values of a single component.\n * This version handles the common case of 2:1 horizontal and 1:1 vertical,\n * without smoothing.\n *\n * A note about the \"bias\" calculations: when rounding fractional values to\n * integer, we do not want to always round 0.5 up to the next integer.\n * If we did that, we'd introduce a noticeable bias towards larger values.\n * Instead, this code is arranged so that 0.5 will be rounded up or down at\n * alternate pixel locations (a simple ordered dither pattern).\n */\n\nMETHODDEF(void)\nh2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  int inrow;\n  JDIMENSION outcol;\n  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;\n  register JSAMPROW inptr, outptr;\n  register int bias;\n\n  /* Expand input data enough to let all the output samples be generated\n   * by the standard loop.  Special-casing padded output would be more\n   * efficient.\n   */\n  expand_right_edge(input_data, cinfo->max_v_samp_factor,\n\t\t    cinfo->image_width, output_cols * 2);\n\n  for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {\n    outptr = output_data[inrow];\n    inptr = input_data[inrow];\n    bias = 0;\t\t\t/* bias = 0,1,0,1,... for successive samples */\n    for (outcol = 0; outcol < output_cols; outcol++) {\n      *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])\n\t\t\t      + bias) >> 1);\n      bias ^= 1;\t\t/* 0=>1, 1=>0 */\n      inptr += 2;\n    }\n  }\n}\n\n\n/*\n * Downsample pixel values of a single component.\n * This version handles the standard case of 2:1 horizontal and 2:1 vertical,\n * without smoothing.\n */\n\nMETHODDEF(void)\nh2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  int inrow, outrow;\n  JDIMENSION outcol;\n  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;\n  register JSAMPROW inptr0, inptr1, outptr;\n  register int bias;\n\n  /* Expand input data enough to let all the output samples be generated\n   * by the standard loop.  Special-casing padded output would be more\n   * efficient.\n   */\n  expand_right_edge(input_data, cinfo->max_v_samp_factor,\n\t\t    cinfo->image_width, output_cols * 2);\n\n  inrow = outrow = 0;\n  while (inrow < cinfo->max_v_samp_factor) {\n    outptr = output_data[outrow];\n    inptr0 = input_data[inrow];\n    inptr1 = input_data[inrow+1];\n    bias = 1;\t\t\t/* bias = 1,2,1,2,... for successive samples */\n    for (outcol = 0; outcol < output_cols; outcol++) {\n      *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +\n\t\t\t      GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])\n\t\t\t      + bias) >> 2);\n      bias ^= 3;\t\t/* 1=>2, 2=>1 */\n      inptr0 += 2; inptr1 += 2;\n    }\n    inrow += 2;\n    outrow++;\n  }\n}\n\n\n#ifdef INPUT_SMOOTHING_SUPPORTED\n\n/*\n * Downsample pixel values of a single component.\n * This version handles the standard case of 2:1 horizontal and 2:1 vertical,\n * with smoothing.  One row of context is required.\n */\n\nMETHODDEF(void)\nh2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t\tJSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  int inrow, outrow;\n  JDIMENSION colctr;\n  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;\n  register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;\n  INT32 membersum, neighsum, memberscale, neighscale;\n\n  /* Expand input data enough to let all the output samples be generated\n   * by the standard loop.  Special-casing padded output would be more\n   * efficient.\n   */\n  expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,\n\t\t    cinfo->image_width, output_cols * 2);\n\n  /* We don't bother to form the individual \"smoothed\" input pixel values;\n   * we can directly compute the output which is the average of the four\n   * smoothed values.  Each of the four member pixels contributes a fraction\n   * (1-8*SF) to its own smoothed image and a fraction SF to each of the three\n   * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final\n   * output.  The four corner-adjacent neighbor pixels contribute a fraction\n   * SF to just one smoothed pixel, or SF/4 to the final output; while the\n   * eight edge-adjacent neighbors contribute SF to each of two smoothed\n   * pixels, or SF/2 overall.  In order to use integer arithmetic, these\n   * factors are scaled by 2^16 = 65536.\n   * Also recall that SF = smoothing_factor / 1024.\n   */\n\n  memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */\n  neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */\n\n  inrow = outrow = 0;\n  while (inrow < cinfo->max_v_samp_factor) {\n    outptr = output_data[outrow];\n    inptr0 = input_data[inrow];\n    inptr1 = input_data[inrow+1];\n    above_ptr = input_data[inrow-1];\n    below_ptr = input_data[inrow+2];\n\n    /* Special case for first column: pretend column -1 is same as column 0 */\n    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +\n\t\tGETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);\n    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +\n\t       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +\n\t       GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +\n\t       GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);\n    neighsum += neighsum;\n    neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +\n\t\tGETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);\n    membersum = membersum * memberscale + neighsum * neighscale;\n    *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);\n    inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;\n\n    for (colctr = output_cols - 2; colctr > 0; colctr--) {\n      /* sum of pixels directly mapped to this output element */\n      membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +\n\t\t  GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);\n      /* sum of edge-neighbor pixels */\n      neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +\n\t\t GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +\n\t\t GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +\n\t\t GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);\n      /* The edge-neighbors count twice as much as corner-neighbors */\n      neighsum += neighsum;\n      /* Add in the corner-neighbors */\n      neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +\n\t\t  GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);\n      /* form final output scaled up by 2^16 */\n      membersum = membersum * memberscale + neighsum * neighscale;\n      /* round, descale and output it */\n      *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);\n      inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;\n    }\n\n    /* Special case for last column */\n    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +\n\t\tGETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);\n    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +\n\t       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +\n\t       GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +\n\t       GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);\n    neighsum += neighsum;\n    neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +\n\t\tGETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);\n    membersum = membersum * memberscale + neighsum * neighscale;\n    *outptr = (JSAMPLE) ((membersum + 32768) >> 16);\n\n    inrow += 2;\n    outrow++;\n  }\n}\n\n\n/*\n * Downsample pixel values of a single component.\n * This version handles the special case of a full-size component,\n * with smoothing.  One row of context is required.\n */\n\nMETHODDEF(void)\nfullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,\n\t\t\t    JSAMPARRAY input_data, JSAMPARRAY output_data)\n{\n  int inrow;\n  JDIMENSION colctr;\n  JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;\n  register JSAMPROW inptr, above_ptr, below_ptr, outptr;\n  INT32 membersum, neighsum, memberscale, neighscale;\n  int colsum, lastcolsum, nextcolsum;\n\n  /* Expand input data enough to let all the output samples be generated\n   * by the standard loop.  Special-casing padded output would be more\n   * efficient.\n   */\n  expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,\n\t\t    cinfo->image_width, output_cols);\n\n  /* Each of the eight neighbor pixels contributes a fraction SF to the\n   * smoothed pixel, while the main pixel contributes (1-8*SF).  In order\n   * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.\n   * Also recall that SF = smoothing_factor / 1024.\n   */\n\n  memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */\n  neighscale = cinfo->smoothing_factor * 64; /* scaled SF */\n\n  for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {\n    outptr = output_data[inrow];\n    inptr = input_data[inrow];\n    above_ptr = input_data[inrow-1];\n    below_ptr = input_data[inrow+1];\n\n    /* Special case for first column */\n    colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +\n\t     GETJSAMPLE(*inptr);\n    membersum = GETJSAMPLE(*inptr++);\n    nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +\n\t\t GETJSAMPLE(*inptr);\n    neighsum = colsum + (colsum - membersum) + nextcolsum;\n    membersum = membersum * memberscale + neighsum * neighscale;\n    *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);\n    lastcolsum = colsum; colsum = nextcolsum;\n\n    for (colctr = output_cols - 2; colctr > 0; colctr--) {\n      membersum = GETJSAMPLE(*inptr++);\n      above_ptr++; below_ptr++;\n      nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +\n\t\t   GETJSAMPLE(*inptr);\n      neighsum = lastcolsum + (colsum - membersum) + nextcolsum;\n      membersum = membersum * memberscale + neighsum * neighscale;\n      *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);\n      lastcolsum = colsum; colsum = nextcolsum;\n    }\n\n    /* Special case for last column */\n    membersum = GETJSAMPLE(*inptr);\n    neighsum = lastcolsum + (colsum - membersum) + colsum;\n    membersum = membersum * memberscale + neighsum * neighscale;\n    *outptr = (JSAMPLE) ((membersum + 32768) >> 16);\n\n  }\n}\n\n#endif /* INPUT_SMOOTHING_SUPPORTED */\n\n\n/*\n * Module initialization routine for downsampling.\n * Note that we must select a routine for each component.\n */\n\nGLOBAL(void)\njinit_downsampler (j_compress_ptr cinfo)\n{\n  my_downsample_ptr downsample;\n  int ci;\n  jpeg_component_info * compptr;\n  boolean smoothok = TRUE;\n  int h_in_group, v_in_group, h_out_group, v_out_group;\n\n  downsample = (my_downsample_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_downsampler));\n  cinfo->downsample = &downsample->pub;\n  downsample->pub.start_pass = start_pass_downsample;\n  downsample->pub.downsample = sep_downsample;\n  downsample->pub.need_context_rows = FALSE;\n\n  if (cinfo->CCIR601_sampling)\n    ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);\n\n  /* Verify we can handle the sampling factors, and set up method pointers */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Compute size of an \"output group\" for DCT scaling.  This many samples\n     * are to be converted from max_h_samp_factor * max_v_samp_factor pixels.\n     */\n    h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /\n\t\t  cinfo->min_DCT_h_scaled_size;\n    v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n\t\t  cinfo->min_DCT_v_scaled_size;\n    h_in_group = cinfo->max_h_samp_factor;\n    v_in_group = cinfo->max_v_samp_factor;\n    downsample->rowgroup_height[ci] = v_out_group; /* save for use later */\n    if (h_in_group == h_out_group && v_in_group == v_out_group) {\n#ifdef INPUT_SMOOTHING_SUPPORTED\n      if (cinfo->smoothing_factor) {\n\tdownsample->methods[ci] = fullsize_smooth_downsample;\n\tdownsample->pub.need_context_rows = TRUE;\n      } else\n#endif\n\tdownsample->methods[ci] = fullsize_downsample;\n    } else if (h_in_group == h_out_group * 2 &&\n\t       v_in_group == v_out_group) {\n      smoothok = FALSE;\n      downsample->methods[ci] = h2v1_downsample;\n    } else if (h_in_group == h_out_group * 2 &&\n\t       v_in_group == v_out_group * 2) {\n#ifdef INPUT_SMOOTHING_SUPPORTED\n      if (cinfo->smoothing_factor) {\n\tdownsample->methods[ci] = h2v2_smooth_downsample;\n\tdownsample->pub.need_context_rows = TRUE;\n      } else\n#endif\n\tdownsample->methods[ci] = h2v2_downsample;\n    } else if ((h_in_group % h_out_group) == 0 &&\n\t       (v_in_group % v_out_group) == 0) {\n      smoothok = FALSE;\n      downsample->methods[ci] = int_downsample;\n      downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group);\n      downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group);\n    } else\n      ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);\n  }\n\n#ifdef INPUT_SMOOTHING_SUPPORTED\n  if (cinfo->smoothing_factor && !smoothok)\n    TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);\n#endif\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jctrans.c",
    "content": "/*\n * jctrans.c\n *\n * Copyright (C) 1995-1998, Thomas G. Lane.\n * Modified 2000-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains library routines for transcoding compression,\n * that is, writing raw DCT coefficient arrays to an output JPEG file.\n * The routines in jcapimin.c will also be needed by a transcoder.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Forward declarations */\nLOCAL(void) transencode_master_selection\n\tJPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));\nLOCAL(void) transencode_coef_controller\n\tJPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));\n\n\n/*\n * Compression initialization for writing raw-coefficient data.\n * Before calling this, all parameters and a data destination must be set up.\n * Call jpeg_finish_compress() to actually write the data.\n *\n * The number of passed virtual arrays must match cinfo->num_components.\n * Note that the virtual arrays need not be filled or even realized at\n * the time write_coefficients is called; indeed, if the virtual arrays\n * were requested from this compression object's memory manager, they\n * typically will be realized during this routine and filled afterwards.\n */\n\nGLOBAL(void)\njpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)\n{\n  if (cinfo->global_state != CSTATE_START)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  /* Mark all tables to be written */\n  jpeg_suppress_tables(cinfo, FALSE);\n  /* (Re)initialize error mgr and destination modules */\n  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);\n  (*cinfo->dest->init_destination) (cinfo);\n  /* Perform master selection of active modules */\n  transencode_master_selection(cinfo, coef_arrays);\n  /* Wait for jpeg_finish_compress() call */\n  cinfo->next_scanline = 0;\t/* so jpeg_write_marker works */\n  cinfo->global_state = CSTATE_WRCOEFS;\n}\n\n\n/*\n * Initialize the compression object with default parameters,\n * then copy from the source object all parameters needed for lossless\n * transcoding.  Parameters that can be varied without loss (such as\n * scan script and Huffman optimization) are left in their default states.\n */\n\nGLOBAL(void)\njpeg_copy_critical_parameters (j_decompress_ptr srcinfo,\n\t\t\t       j_compress_ptr dstinfo)\n{\n  JQUANT_TBL ** qtblptr;\n  jpeg_component_info *incomp, *outcomp;\n  JQUANT_TBL *c_quant, *slot_quant;\n  int tblno, ci, coefi;\n\n  /* Safety check to ensure start_compress not called yet. */\n  if (dstinfo->global_state != CSTATE_START)\n    ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);\n  /* Copy fundamental image dimensions */\n  dstinfo->image_width = srcinfo->image_width;\n  dstinfo->image_height = srcinfo->image_height;\n  dstinfo->input_components = srcinfo->num_components;\n  dstinfo->in_color_space = srcinfo->jpeg_color_space;\n  dstinfo->jpeg_width = srcinfo->output_width;\n  dstinfo->jpeg_height = srcinfo->output_height;\n  dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;\n  dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;\n  /* Initialize all parameters to default values */\n  jpeg_set_defaults(dstinfo);\n  /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.\n   * Fix it to get the right header markers for the image colorspace.\n   * Note: Entropy table assignment in jpeg_set_colorspace\n   * depends on color_transform.\n   * Adaption is also required for setting the appropriate\n   * entropy coding mode dependent on image data precision.\n   */\n  dstinfo->color_transform = srcinfo->color_transform;\n  jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);\n  dstinfo->data_precision = srcinfo->data_precision;\n  dstinfo->arith_code = srcinfo->data_precision > 8 ? TRUE : FALSE;\n  dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;\n  /* Copy the source's quantization tables. */\n  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {\n    if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {\n      qtblptr = & dstinfo->quant_tbl_ptrs[tblno];\n      if (*qtblptr == NULL)\n\t*qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);\n      MEMCOPY((*qtblptr)->quantval,\n\t      srcinfo->quant_tbl_ptrs[tblno]->quantval,\n\t      SIZEOF((*qtblptr)->quantval));\n      (*qtblptr)->sent_table = FALSE;\n    }\n  }\n  /* Copy the source's per-component info.\n   * Note we assume jpeg_set_defaults has allocated the dest comp_info array.\n   */\n  dstinfo->num_components = srcinfo->num_components;\n  if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)\n    ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,\n\t     MAX_COMPONENTS);\n  for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;\n       ci < dstinfo->num_components; ci++, incomp++, outcomp++) {\n    outcomp->component_id = incomp->component_id;\n    outcomp->h_samp_factor = incomp->h_samp_factor;\n    outcomp->v_samp_factor = incomp->v_samp_factor;\n    outcomp->quant_tbl_no = incomp->quant_tbl_no;\n    /* Make sure saved quantization table for component matches the qtable\n     * slot.  If not, the input file re-used this qtable slot.\n     * IJG encoder currently cannot duplicate this.\n     */\n    tblno = outcomp->quant_tbl_no;\n    if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||\n\tsrcinfo->quant_tbl_ptrs[tblno] == NULL)\n      ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);\n    slot_quant = srcinfo->quant_tbl_ptrs[tblno];\n    c_quant = incomp->quant_table;\n    if (c_quant != NULL) {\n      for (coefi = 0; coefi < DCTSIZE2; coefi++) {\n\tif (c_quant->quantval[coefi] != slot_quant->quantval[coefi])\n\t  ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);\n      }\n    }\n    /* Note: we do not copy the source's entropy table assignments;\n     * instead we rely on jpeg_set_colorspace to have made a suitable choice.\n     */\n  }\n  /* Also copy JFIF version and resolution information, if available.\n   * Strictly speaking this isn't \"critical\" info, but it's nearly\n   * always appropriate to copy it if available.  In particular,\n   * if the application chooses to copy JFIF 1.02 extension markers from\n   * the source file, we need to copy the version to make sure we don't\n   * emit a file that has 1.02 extensions but a claimed version of 1.01.\n   */\n  if (srcinfo->saw_JFIF_marker) {\n    if (srcinfo->JFIF_major_version == 1 ||\n\tsrcinfo->JFIF_major_version == 2) {\n      dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;\n      dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;\n    }\n    dstinfo->density_unit = srcinfo->density_unit;\n    dstinfo->X_density = srcinfo->X_density;\n    dstinfo->Y_density = srcinfo->Y_density;\n  }\n}\n\n\nLOCAL(void)\njpeg_calc_trans_dimensions (j_compress_ptr cinfo)\n/* Do computations that are needed before master selection phase */\n{\n  if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size)\n    ERREXIT2(cinfo, JERR_BAD_DCTSIZE,\n\t     cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size);\n\n  cinfo->block_size = cinfo->min_DCT_h_scaled_size;\n}\n\n\n/*\n * Master selection of compression modules for transcoding.\n * This substitutes for jcinit.c's initialization of the full compressor.\n */\n\nLOCAL(void)\ntransencode_master_selection (j_compress_ptr cinfo,\n\t\t\t      jvirt_barray_ptr * coef_arrays)\n{\n  /* Do computations that are needed before master selection phase */\n  jpeg_calc_trans_dimensions(cinfo);\n\n  /* Initialize master control (includes parameter checking/processing) */\n  jinit_c_master_control(cinfo, TRUE /* transcode only */);\n\n  /* Entropy encoding: either Huffman or arithmetic coding. */\n  if (cinfo->arith_code)\n    jinit_arith_encoder(cinfo);\n  else {\n    jinit_huff_encoder(cinfo);\n  }\n\n  /* We need a special coefficient buffer controller. */\n  transencode_coef_controller(cinfo, coef_arrays);\n\n  jinit_marker_writer(cinfo);\n\n  /* We can now tell the memory manager to allocate virtual arrays. */\n  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);\n\n  /* Write the datastream header (SOI, JFIF) immediately.\n   * Frame and scan headers are postponed till later.\n   * This lets application insert special markers after the SOI.\n   */\n  (*cinfo->marker->write_file_header) (cinfo);\n}\n\n\n/*\n * The rest of this file is a special implementation of the coefficient\n * buffer controller.  This is similar to jccoefct.c, but it handles only\n * output from presupplied virtual arrays.  Furthermore, we generate any\n * dummy padding blocks on-the-fly rather than expecting them to be present\n * in the arrays.\n */\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_c_coef_controller pub; /* public fields */\n\n  JDIMENSION iMCU_row_num;\t/* iMCU row # within image */\n  JDIMENSION MCU_ctr;\t\t/* counts MCUs processed in current row */\n  int MCU_vert_offset;\t\t/* counts MCU rows within iMCU row */\n  int MCU_rows_per_iMCU_row;\t/* number of such rows needed */\n\n  /* Virtual block array for each component. */\n  jvirt_barray_ptr * whole_image;\n\n  /* Workspace for constructing dummy blocks at right/bottom edges. */\n  JBLOCK dummy_buffer[C_MAX_BLOCKS_IN_MCU];\n} my_coef_controller;\n\ntypedef my_coef_controller * my_coef_ptr;\n\n\nLOCAL(void)\nstart_iMCU_row (j_compress_ptr cinfo)\n/* Reset within-iMCU-row counters for a new row */\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  /* In an interleaved scan, an MCU row is the same as an iMCU row.\n   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.\n   * But at the bottom of the image, process only what's left.\n   */\n  if (cinfo->comps_in_scan > 1) {\n    coef->MCU_rows_per_iMCU_row = 1;\n  } else {\n    if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;\n    else\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;\n  }\n\n  coef->MCU_ctr = 0;\n  coef->MCU_vert_offset = 0;\n}\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  if (pass_mode != JBUF_CRANK_DEST)\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n\n  coef->iMCU_row_num = 0;\n  start_iMCU_row(cinfo);\n}\n\n\n/*\n * Process some data.\n * We process the equivalent of one fully interleaved MCU row (\"iMCU\" row)\n * per call, ie, v_samp_factor block rows for each component in the scan.\n * The data is obtained from the virtual arrays and fed to the entropy coder.\n * Returns TRUE if the iMCU row is completed, FALSE if suspended.\n *\n * NB: input_buf is ignored; it is likely to be a NULL pointer.\n */\n\nMETHODDEF(boolean)\ncompress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION MCU_col_num;\t/* index of current MCU within row */\n  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  int blkn, ci, xindex, yindex, yoffset, blockcnt;\n  JDIMENSION start_col;\n  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];\n  JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];\n  JBLOCKROW buffer_ptr;\n  jpeg_component_info *compptr;\n\n  /* Align the virtual buffers for the components used in this scan. */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    buffer[ci] = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],\n       coef->iMCU_row_num * compptr->v_samp_factor,\n       (JDIMENSION) compptr->v_samp_factor, FALSE);\n  }\n\n  /* Loop to process one whole iMCU row */\n  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;\n       yoffset++) {\n    for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;\n\t MCU_col_num++) {\n      /* Construct list of pointers to DCT blocks belonging to this MCU */\n      blkn = 0;\t\t\t/* index of current DCT block within MCU */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n\tcompptr = cinfo->cur_comp_info[ci];\n\tblockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width\n\t\t\t\t\t\t: compptr->last_col_width;\n\tstart_col = MCU_col_num * compptr->MCU_width;\n\tfor (yindex = 0; yindex < compptr->MCU_height; yindex++) {\n\t  if (coef->iMCU_row_num < last_iMCU_row ||\n\t      yoffset + yindex < compptr->last_row_height) {\n\t    /* Fill in pointers to real blocks in this row */\n\t    buffer_ptr = buffer[ci][yoffset + yindex] + start_col;\n\t    xindex = blockcnt;\n\t    do {\n\t      MCU_buffer[blkn++] = buffer_ptr++;\n\t    } while (--xindex);\n\t    /* Dummy blocks at right edge */\n\t    if ((xindex = compptr->MCU_width - blockcnt) == 0)\n\t      continue;\n\t  } else {\n\t    /* At bottom of image, need a whole row of dummy blocks */\n\t    xindex = compptr->MCU_width;\n\t  }\n\t  /* Fill in any dummy blocks needed in this row.\n\t   * Dummy blocks are filled in the same way as in jccoefct.c:\n\t   * all zeroes in the AC entries, DC entries equal to previous\n\t   * block's DC value.  The init routine has already zeroed the\n\t   * AC entries, so we need only set the DC entries correctly.\n\t   */\n\t  buffer_ptr = coef->dummy_buffer + blkn;\n\t  do {\n\t    buffer_ptr[0][0] = MCU_buffer[blkn-1][0][0];\n\t    MCU_buffer[blkn++] = buffer_ptr++;\n\t  } while (--xindex);\n\t}\n      }\n      /* Try to write the MCU. */\n      if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {\n\t/* Suspension forced; update state counters and exit */\n\tcoef->MCU_vert_offset = yoffset;\n\tcoef->MCU_ctr = MCU_col_num;\n\treturn FALSE;\n      }\n    }\n    /* Completed an MCU row, but perhaps not an iMCU row */\n    coef->MCU_ctr = 0;\n  }\n  /* Completed the iMCU row, advance counters for next one */\n  coef->iMCU_row_num++;\n  start_iMCU_row(cinfo);\n  return TRUE;\n}\n\n\n/*\n * Initialize coefficient buffer controller.\n *\n * Each passed coefficient array must be the right size for that\n * coefficient: width_in_blocks wide and height_in_blocks high,\n * with unitheight at least v_samp_factor.\n */\n\nLOCAL(void)\ntransencode_coef_controller (j_compress_ptr cinfo,\n\t\t\t     jvirt_barray_ptr * coef_arrays)\n{\n  my_coef_ptr coef;\n\n  coef = (my_coef_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller));\n  cinfo->coef = &coef->pub;\n  coef->pub.start_pass = start_pass_coef;\n  coef->pub.compress_data = compress_output;\n\n  /* Save pointer to virtual arrays */\n  coef->whole_image = coef_arrays;\n\n  /* Pre-zero space for dummy DCT blocks */\n  MEMZERO(coef->dummy_buffer, SIZEOF(coef->dummy_buffer));\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdapimin.c",
    "content": "/*\n * jdapimin.c\n *\n * Copyright (C) 1994-1998, Thomas G. Lane.\n * Modified 2009-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains application interface code for the decompression half\n * of the JPEG library.  These are the \"minimum\" API routines that may be\n * needed in either the normal full-decompression case or the\n * transcoding-only case.\n *\n * Most of the routines intended to be called directly by an application\n * are in this file or in jdapistd.c.  But also see jcomapi.c for routines\n * shared by compression and decompression, and jdtrans.c for the transcoding\n * case.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * Initialization of a JPEG decompression object.\n * The error manager must already be set up (in case memory manager fails).\n */\n\nGLOBAL(void)\njpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)\n{\n  int i;\n\n  /* Guard against version mismatches between library and caller. */\n  cinfo->mem = NULL;\t\t/* so jpeg_destroy knows mem mgr not called */\n  if (version != JPEG_LIB_VERSION)\n    ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);\n  if (structsize != SIZEOF(struct jpeg_decompress_struct))\n    ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE, \n\t     (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);\n\n  /* For debugging purposes, we zero the whole master structure.\n   * But the application has already set the err pointer, and may have set\n   * client_data, so we have to save and restore those fields.\n   * Note: if application hasn't set client_data, tools like Purify may\n   * complain here.\n   */\n  {\n    struct jpeg_error_mgr * err = cinfo->err;\n    void * client_data = cinfo->client_data; /* ignore Purify complaint here */\n    MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));\n    cinfo->err = err;\n    cinfo->client_data = client_data;\n  }\n  cinfo->is_decompressor = TRUE;\n\n  /* Initialize a memory manager instance for this object */\n  jinit_memory_mgr((j_common_ptr) cinfo);\n\n  /* Zero out pointers to permanent structures. */\n  cinfo->progress = NULL;\n  cinfo->src = NULL;\n\n  for (i = 0; i < NUM_QUANT_TBLS; i++)\n    cinfo->quant_tbl_ptrs[i] = NULL;\n\n  for (i = 0; i < NUM_HUFF_TBLS; i++) {\n    cinfo->dc_huff_tbl_ptrs[i] = NULL;\n    cinfo->ac_huff_tbl_ptrs[i] = NULL;\n  }\n\n  /* Initialize marker processor so application can override methods\n   * for COM, APPn markers before calling jpeg_read_header.\n   */\n  cinfo->marker_list = NULL;\n  jinit_marker_reader(cinfo);\n\n  /* And initialize the overall input controller. */\n  jinit_input_controller(cinfo);\n\n  /* OK, I'm ready */\n  cinfo->global_state = DSTATE_START;\n}\n\n\n/*\n * Destruction of a JPEG decompression object\n */\n\nGLOBAL(void)\njpeg_destroy_decompress (j_decompress_ptr cinfo)\n{\n  jpeg_destroy((j_common_ptr) cinfo); /* use common routine */\n}\n\n\n/*\n * Abort processing of a JPEG decompression operation,\n * but don't destroy the object itself.\n */\n\nGLOBAL(void)\njpeg_abort_decompress (j_decompress_ptr cinfo)\n{\n  jpeg_abort((j_common_ptr) cinfo); /* use common routine */\n}\n\n\n/*\n * Set default decompression parameters.\n */\n\nLOCAL(void)\ndefault_decompress_parms (j_decompress_ptr cinfo)\n{\n  int cid0, cid1, cid2, cid3;\n\n  /* Guess the input colorspace, and set output colorspace accordingly. */\n  /* Note application may override our guesses. */\n  switch (cinfo->num_components) {\n  case 1:\n    cinfo->jpeg_color_space = JCS_GRAYSCALE;\n    cinfo->out_color_space = JCS_GRAYSCALE;\n    break;\n\n  case 3:\n    cid0 = cinfo->comp_info[0].component_id;\n    cid1 = cinfo->comp_info[1].component_id;\n    cid2 = cinfo->comp_info[2].component_id;\n\n    /* For robust detection of standard colorspaces\n     * regardless of the presence of special markers,\n     * check component IDs from SOF marker first.\n     */\n    if      (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03)\n      cinfo->jpeg_color_space = JCS_YCbCr;\n    else if (cid0 == 0x01 && cid1 == 0x22 && cid2 == 0x23)\n      cinfo->jpeg_color_space = JCS_BG_YCC;\n    else if (cid0 == 0x52 && cid1 == 0x47 && cid2 == 0x42)\n      cinfo->jpeg_color_space = JCS_RGB;\t/* ASCII 'R', 'G', 'B' */\n    else if (cid0 == 0x72 && cid1 == 0x67 && cid2 == 0x62)\n      cinfo->jpeg_color_space = JCS_BG_RGB;\t/* ASCII 'r', 'g', 'b' */\n    else if (cinfo->saw_JFIF_marker)\n      cinfo->jpeg_color_space = JCS_YCbCr;\t/* assume it's YCbCr */\n    else if (cinfo->saw_Adobe_marker) {\n      switch (cinfo->Adobe_transform) {\n      case 0:\n\tcinfo->jpeg_color_space = JCS_RGB;\n\tbreak;\n      case 1:\n\tcinfo->jpeg_color_space = JCS_YCbCr;\n\tbreak;\n      default:\n\tWARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);\n\tcinfo->jpeg_color_space = JCS_YCbCr;\t/* assume it's YCbCr */\n      }\n    } else {\n      TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);\n      cinfo->jpeg_color_space = JCS_YCbCr;\t/* assume it's YCbCr */\n    }\n    /* Always guess RGB is proper output colorspace. */\n    cinfo->out_color_space = JCS_RGB;\n    break;\n\n  case 4:\n    cid0 = cinfo->comp_info[0].component_id;\n    cid1 = cinfo->comp_info[1].component_id;\n    cid2 = cinfo->comp_info[2].component_id;\n    cid3 = cinfo->comp_info[3].component_id;\n\n    /* For robust detection of standard colorspaces\n     * regardless of the presence of special markers,\n     * check component IDs from SOF marker first.\n     */\n    if      (cid0 == 0x01 && cid1 == 0x02 && cid2 == 0x03 && cid3 == 0x04)\n      cinfo->jpeg_color_space = JCS_YCCK;\n    else if (cid0 == 0x43 && cid1 == 0x4D && cid2 == 0x59 && cid3 == 0x4B)\n      cinfo->jpeg_color_space = JCS_CMYK;   /* ASCII 'C', 'M', 'Y', 'K' */\n    else if (cinfo->saw_Adobe_marker) {\n      switch (cinfo->Adobe_transform) {\n      case 0:\n\tcinfo->jpeg_color_space = JCS_CMYK;\n\tbreak;\n      case 2:\n\tcinfo->jpeg_color_space = JCS_YCCK;\n\tbreak;\n      default:\n\tWARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);\n\tcinfo->jpeg_color_space = JCS_YCCK;\t/* assume it's YCCK */\n      }\n    } else {\n      /* Unknown IDs and no special markers, assume straight CMYK. */\n      cinfo->jpeg_color_space = JCS_CMYK;\n    }\n    cinfo->out_color_space = JCS_CMYK;\n    break;\n\n  default:\n    cinfo->jpeg_color_space = JCS_UNKNOWN;\n    cinfo->out_color_space = JCS_UNKNOWN;\n  }\n\n  /* Set defaults for other decompression parameters. */\n  cinfo->scale_num = cinfo->block_size;\t\t/* 1:1 scaling */\n  cinfo->scale_denom = cinfo->block_size;\n  cinfo->output_gamma = 1.0;\n  cinfo->buffered_image = FALSE;\n  cinfo->raw_data_out = FALSE;\n  cinfo->dct_method = JDCT_DEFAULT;\n  cinfo->do_fancy_upsampling = TRUE;\n  cinfo->do_block_smoothing = TRUE;\n  cinfo->quantize_colors = FALSE;\n  /* We set these in case application only sets quantize_colors. */\n  cinfo->dither_mode = JDITHER_FS;\n#ifdef QUANT_2PASS_SUPPORTED\n  cinfo->two_pass_quantize = TRUE;\n#else\n  cinfo->two_pass_quantize = FALSE;\n#endif\n  cinfo->desired_number_of_colors = 256;\n  cinfo->colormap = NULL;\n  /* Initialize for no mode change in buffered-image mode. */\n  cinfo->enable_1pass_quant = FALSE;\n  cinfo->enable_external_quant = FALSE;\n  cinfo->enable_2pass_quant = FALSE;\n}\n\n\n/*\n * Decompression startup: read start of JPEG datastream to see what's there.\n * Need only initialize JPEG object and supply a data source before calling.\n *\n * This routine will read as far as the first SOS marker (ie, actual start of\n * compressed data), and will save all tables and parameters in the JPEG\n * object.  It will also initialize the decompression parameters to default\n * values, and finally return JPEG_HEADER_OK.  On return, the application may\n * adjust the decompression parameters and then call jpeg_start_decompress.\n * (Or, if the application only wanted to determine the image parameters,\n * the data need not be decompressed.  In that case, call jpeg_abort or\n * jpeg_destroy to release any temporary space.)\n * If an abbreviated (tables only) datastream is presented, the routine will\n * return JPEG_HEADER_TABLES_ONLY upon reaching EOI.  The application may then\n * re-use the JPEG object to read the abbreviated image datastream(s).\n * It is unnecessary (but OK) to call jpeg_abort in this case.\n * The JPEG_SUSPENDED return code only occurs if the data source module\n * requests suspension of the decompressor.  In this case the application\n * should load more source data and then re-call jpeg_read_header to resume\n * processing.\n * If a non-suspending data source is used and require_image is TRUE, then the\n * return code need not be inspected since only JPEG_HEADER_OK is possible.\n *\n * This routine is now just a front end to jpeg_consume_input, with some\n * extra error checking.\n */\n\nGLOBAL(int)\njpeg_read_header (j_decompress_ptr cinfo, boolean require_image)\n{\n  int retcode;\n\n  if (cinfo->global_state != DSTATE_START &&\n      cinfo->global_state != DSTATE_INHEADER)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  retcode = jpeg_consume_input(cinfo);\n\n  switch (retcode) {\n  case JPEG_REACHED_SOS:\n    retcode = JPEG_HEADER_OK;\n    break;\n  case JPEG_REACHED_EOI:\n    if (require_image)\t\t/* Complain if application wanted an image */\n      ERREXIT(cinfo, JERR_NO_IMAGE);\n    /* Reset to start state; it would be safer to require the application to\n     * call jpeg_abort, but we can't change it now for compatibility reasons.\n     * A side effect is to free any temporary memory (there shouldn't be any).\n     */\n    jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */\n    retcode = JPEG_HEADER_TABLES_ONLY;\n    break;\n  case JPEG_SUSPENDED:\n    /* no work */\n    break;\n  }\n\n  return retcode;\n}\n\n\n/*\n * Consume data in advance of what the decompressor requires.\n * This can be called at any time once the decompressor object has\n * been created and a data source has been set up.\n *\n * This routine is essentially a state machine that handles a couple\n * of critical state-transition actions, namely initial setup and\n * transition from header scanning to ready-for-start_decompress.\n * All the actual input is done via the input controller's consume_input\n * method.\n */\n\nGLOBAL(int)\njpeg_consume_input (j_decompress_ptr cinfo)\n{\n  int retcode = JPEG_SUSPENDED;\n\n  /* NB: every possible DSTATE value should be listed in this switch */\n  switch (cinfo->global_state) {\n  case DSTATE_START:\n    /* Start-of-datastream actions: reset appropriate modules */\n    (*cinfo->inputctl->reset_input_controller) (cinfo);\n    /* Initialize application's data source module */\n    (*cinfo->src->init_source) (cinfo);\n    cinfo->global_state = DSTATE_INHEADER;\n    /*FALLTHROUGH*/\n  case DSTATE_INHEADER:\n    retcode = (*cinfo->inputctl->consume_input) (cinfo);\n    if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */\n      /* Set up default parameters based on header data */\n      default_decompress_parms(cinfo);\n      /* Set global state: ready for start_decompress */\n      cinfo->global_state = DSTATE_READY;\n    }\n    break;\n  case DSTATE_READY:\n    /* Can't advance past first SOS until start_decompress is called */\n    retcode = JPEG_REACHED_SOS;\n    break;\n  case DSTATE_PRELOAD:\n  case DSTATE_PRESCAN:\n  case DSTATE_SCANNING:\n  case DSTATE_RAW_OK:\n  case DSTATE_BUFIMAGE:\n  case DSTATE_BUFPOST:\n  case DSTATE_STOPPING:\n    retcode = (*cinfo->inputctl->consume_input) (cinfo);\n    break;\n  default:\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  }\n  return retcode;\n}\n\n\n/*\n * Have we finished reading the input file?\n */\n\nGLOBAL(boolean)\njpeg_input_complete (j_decompress_ptr cinfo)\n{\n  /* Check for valid jpeg object */\n  if (cinfo->global_state < DSTATE_START ||\n      cinfo->global_state > DSTATE_STOPPING)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  return cinfo->inputctl->eoi_reached;\n}\n\n\n/*\n * Is there more than one scan?\n */\n\nGLOBAL(boolean)\njpeg_has_multiple_scans (j_decompress_ptr cinfo)\n{\n  /* Only valid after jpeg_read_header completes */\n  if (cinfo->global_state < DSTATE_READY ||\n      cinfo->global_state > DSTATE_STOPPING)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  return cinfo->inputctl->has_multiple_scans;\n}\n\n\n/*\n * Finish JPEG decompression.\n *\n * This will normally just verify the file trailer and release temp storage.\n *\n * Returns FALSE if suspended.  The return value need be inspected only if\n * a suspending data source is used.\n */\n\nGLOBAL(boolean)\njpeg_finish_decompress (j_decompress_ptr cinfo)\n{\n  if ((cinfo->global_state == DSTATE_SCANNING ||\n       cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {\n    /* Terminate final pass of non-buffered mode */\n    if (cinfo->output_scanline < cinfo->output_height)\n      ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);\n    (*cinfo->master->finish_output_pass) (cinfo);\n    cinfo->global_state = DSTATE_STOPPING;\n  } else if (cinfo->global_state == DSTATE_BUFIMAGE) {\n    /* Finishing after a buffered-image operation */\n    cinfo->global_state = DSTATE_STOPPING;\n  } else if (cinfo->global_state != DSTATE_STOPPING) {\n    /* STOPPING = repeat call after a suspension, anything else is error */\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  }\n  /* Read until EOI */\n  while (! cinfo->inputctl->eoi_reached) {\n    if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)\n      return FALSE;\t\t/* Suspend, come back later */\n  }\n  /* Do final cleanup */\n  (*cinfo->src->term_source) (cinfo);\n  /* We can use jpeg_abort to release memory and reset global_state */\n  jpeg_abort((j_common_ptr) cinfo);\n  return TRUE;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdapistd.c",
    "content": "/*\n * jdapistd.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2002-2013 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains application interface code for the decompression half\n * of the JPEG library.  These are the \"standard\" API routines that are\n * used in the normal full-decompression case.  They are not used by a\n * transcoding-only application.  Note that if an application links in\n * jpeg_start_decompress, it will end up linking in the entire decompressor.\n * We thus must separate this file from jdapimin.c to avoid linking the\n * whole decompression library into a transcoder.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Forward declarations */\nLOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));\n\n\n/*\n * Decompression initialization.\n * jpeg_read_header must be completed before calling this.\n *\n * If a multipass operating mode was selected, this will do all but the\n * last pass, and thus may take a great deal of time.\n *\n * Returns FALSE if suspended.  The return value need be inspected only if\n * a suspending data source is used.\n */\n\nGLOBAL(boolean)\njpeg_start_decompress (j_decompress_ptr cinfo)\n{\n  if (cinfo->global_state == DSTATE_READY) {\n    /* First call: initialize master control, select active modules */\n    jinit_master_decompress(cinfo);\n    if (cinfo->buffered_image) {\n      /* No more work here; expecting jpeg_start_output next */\n      cinfo->global_state = DSTATE_BUFIMAGE;\n      return TRUE;\n    }\n    cinfo->global_state = DSTATE_PRELOAD;\n  }\n  if (cinfo->global_state == DSTATE_PRELOAD) {\n    /* If file has multiple scans, absorb them all into the coef buffer */\n    if (cinfo->inputctl->has_multiple_scans) {\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n      for (;;) {\n\tint retcode;\n\t/* Call progress monitor hook if present */\n\tif (cinfo->progress != NULL)\n\t  (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n\t/* Absorb some more input */\n\tretcode = (*cinfo->inputctl->consume_input) (cinfo);\n\tif (retcode == JPEG_SUSPENDED)\n\t  return FALSE;\n\tif (retcode == JPEG_REACHED_EOI)\n\t  break;\n\t/* Advance progress counter if appropriate */\n\tif (cinfo->progress != NULL &&\n\t    (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {\n\t  if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {\n\t    /* jdmaster underestimated number of scans; ratchet up one scan */\n\t    cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;\n\t  }\n\t}\n      }\n#else\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif /* D_MULTISCAN_FILES_SUPPORTED */\n    }\n    cinfo->output_scan_number = cinfo->input_scan_number;\n  } else if (cinfo->global_state != DSTATE_PRESCAN)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  /* Perform any dummy output passes, and set up for the final pass */\n  return output_pass_setup(cinfo);\n}\n\n\n/*\n * Set up for an output pass, and perform any dummy pass(es) needed.\n * Common subroutine for jpeg_start_decompress and jpeg_start_output.\n * Entry: global_state = DSTATE_PRESCAN only if previously suspended.\n * Exit: If done, returns TRUE and sets global_state for proper output mode.\n *       If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.\n */\n\nLOCAL(boolean)\noutput_pass_setup (j_decompress_ptr cinfo)\n{\n  if (cinfo->global_state != DSTATE_PRESCAN) {\n    /* First call: do pass setup */\n    (*cinfo->master->prepare_for_output_pass) (cinfo);\n    cinfo->output_scanline = 0;\n    cinfo->global_state = DSTATE_PRESCAN;\n  }\n  /* Loop over any required dummy passes */\n  while (cinfo->master->is_dummy_pass) {\n#ifdef QUANT_2PASS_SUPPORTED\n    /* Crank through the dummy pass */\n    while (cinfo->output_scanline < cinfo->output_height) {\n      JDIMENSION last_scanline;\n      /* Call progress monitor hook if present */\n      if (cinfo->progress != NULL) {\n\tcinfo->progress->pass_counter = (long) cinfo->output_scanline;\n\tcinfo->progress->pass_limit = (long) cinfo->output_height;\n\t(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n      }\n      /* Process some data */\n      last_scanline = cinfo->output_scanline;\n      (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,\n\t\t\t\t    &cinfo->output_scanline, (JDIMENSION) 0);\n      if (cinfo->output_scanline == last_scanline)\n\treturn FALSE;\t\t/* No progress made, must suspend */\n    }\n    /* Finish up dummy pass, and set up for another one */\n    (*cinfo->master->finish_output_pass) (cinfo);\n    (*cinfo->master->prepare_for_output_pass) (cinfo);\n    cinfo->output_scanline = 0;\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif /* QUANT_2PASS_SUPPORTED */\n  }\n  /* Ready for application to drive output pass through\n   * jpeg_read_scanlines or jpeg_read_raw_data.\n   */\n  cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;\n  return TRUE;\n}\n\n\n/*\n * Read some scanlines of data from the JPEG decompressor.\n *\n * The return value will be the number of lines actually read.\n * This may be less than the number requested in several cases,\n * including bottom of image, data source suspension, and operating\n * modes that emit multiple scanlines at a time.\n *\n * Note: we warn about excess calls to jpeg_read_scanlines() since\n * this likely signals an application programmer error.  However,\n * an oversize buffer (max_lines > scanlines remaining) is not an error.\n */\n\nGLOBAL(JDIMENSION)\njpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,\n\t\t     JDIMENSION max_lines)\n{\n  JDIMENSION row_ctr;\n\n  if (cinfo->global_state != DSTATE_SCANNING)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  if (cinfo->output_scanline >= cinfo->output_height) {\n    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);\n    return 0;\n  }\n\n  /* Call progress monitor hook if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->pass_counter = (long) cinfo->output_scanline;\n    cinfo->progress->pass_limit = (long) cinfo->output_height;\n    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n  }\n\n  /* Process some data */\n  row_ctr = 0;\n  (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);\n  cinfo->output_scanline += row_ctr;\n  return row_ctr;\n}\n\n\n/*\n * Alternate entry point to read raw data.\n * Processes exactly one iMCU row per call, unless suspended.\n */\n\nGLOBAL(JDIMENSION)\njpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,\n\t\t    JDIMENSION max_lines)\n{\n  JDIMENSION lines_per_iMCU_row;\n\n  if (cinfo->global_state != DSTATE_RAW_OK)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  if (cinfo->output_scanline >= cinfo->output_height) {\n    WARNMS(cinfo, JWRN_TOO_MUCH_DATA);\n    return 0;\n  }\n\n  /* Call progress monitor hook if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->pass_counter = (long) cinfo->output_scanline;\n    cinfo->progress->pass_limit = (long) cinfo->output_height;\n    (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n  }\n\n  /* Verify that at least one iMCU row can be returned. */\n  lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;\n  if (max_lines < lines_per_iMCU_row)\n    ERREXIT(cinfo, JERR_BUFFER_SIZE);\n\n  /* Decompress directly into user's buffer. */\n  if (! (*cinfo->coef->decompress_data) (cinfo, data))\n    return 0;\t\t\t/* suspension forced, can do nothing more */\n\n  /* OK, we processed one iMCU row. */\n  cinfo->output_scanline += lines_per_iMCU_row;\n  return lines_per_iMCU_row;\n}\n\n\n/* Additional entry points for buffered-image mode. */\n\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n\n/*\n * Initialize for an output pass in buffered-image mode.\n */\n\nGLOBAL(boolean)\njpeg_start_output (j_decompress_ptr cinfo, int scan_number)\n{\n  if (cinfo->global_state != DSTATE_BUFIMAGE &&\n      cinfo->global_state != DSTATE_PRESCAN)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  /* Limit scan number to valid range */\n  if (scan_number <= 0)\n    scan_number = 1;\n  if (cinfo->inputctl->eoi_reached &&\n      scan_number > cinfo->input_scan_number)\n    scan_number = cinfo->input_scan_number;\n  cinfo->output_scan_number = scan_number;\n  /* Perform any dummy output passes, and set up for the real pass */\n  return output_pass_setup(cinfo);\n}\n\n\n/*\n * Finish up after an output pass in buffered-image mode.\n *\n * Returns FALSE if suspended.  The return value need be inspected only if\n * a suspending data source is used.\n */\n\nGLOBAL(boolean)\njpeg_finish_output (j_decompress_ptr cinfo)\n{\n  if ((cinfo->global_state == DSTATE_SCANNING ||\n       cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {\n    /* Terminate this pass. */\n    /* We do not require the whole pass to have been completed. */\n    (*cinfo->master->finish_output_pass) (cinfo);\n    cinfo->global_state = DSTATE_BUFPOST;\n  } else if (cinfo->global_state != DSTATE_BUFPOST) {\n    /* BUFPOST = repeat call after a suspension, anything else is error */\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  }\n  /* Read markers looking for SOS or EOI */\n  while (cinfo->input_scan_number <= cinfo->output_scan_number &&\n\t ! cinfo->inputctl->eoi_reached) {\n    if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)\n      return FALSE;\t\t/* Suspend, come back later */\n  }\n  cinfo->global_state = DSTATE_BUFIMAGE;\n  return TRUE;\n}\n\n#endif /* D_MULTISCAN_FILES_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jdarith.c",
    "content": "/*\n * jdarith.c\n *\n * Developed 1997-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains portable arithmetic entropy decoding routines for JPEG\n * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).\n *\n * Both sequential and progressive modes are supported in this single module.\n *\n * Suspension is not currently supported in this module.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Expanded entropy decoder object for arithmetic decoding. */\n\ntypedef struct {\n  struct jpeg_entropy_decoder pub; /* public fields */\n\n  INT32 c;       /* C register, base of coding interval + input bit buffer */\n  INT32 a;               /* A register, normalized size of coding interval */\n  int ct;     /* bit shift counter, # of bits left in bit buffer part of C */\n                                                         /* init: ct = -16 */\n                                                         /* run: ct = 0..7 */\n                                                         /* error: ct = -1 */\n  int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */\n  int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */\n\n  unsigned int restarts_to_go;\t/* MCUs left in this restart interval */\n\n  /* Pointers to statistics areas (these workspaces have image lifespan) */\n  unsigned char * dc_stats[NUM_ARITH_TBLS];\n  unsigned char * ac_stats[NUM_ARITH_TBLS];\n\n  /* Statistics bin for coding with fixed probability 0.5 */\n  unsigned char fixed_bin[4];\n} arith_entropy_decoder;\n\ntypedef arith_entropy_decoder * arith_entropy_ptr;\n\n/* The following two definitions specify the allocation chunk size\n * for the statistics area.\n * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least\n * 49 statistics bins for DC, and 245 statistics bins for AC coding.\n *\n * We use a compact representation with 1 byte per statistics bin,\n * thus the numbers directly represent byte sizes.\n * This 1 byte per statistics bin contains the meaning of the MPS\n * (more probable symbol) in the highest bit (mask 0x80), and the\n * index into the probability estimation state machine table\n * in the lower bits (mask 0x7F).\n */\n\n#define DC_STAT_BINS 64\n#define AC_STAT_BINS 256\n\n\nLOCAL(int)\nget_byte (j_decompress_ptr cinfo)\n/* Read next input byte; we do not support suspension in this module. */\n{\n  struct jpeg_source_mgr * src = cinfo->src;\n\n  if (src->bytes_in_buffer == 0)\n    if (! (*src->fill_input_buffer) (cinfo))\n      ERREXIT(cinfo, JERR_CANT_SUSPEND);\n  src->bytes_in_buffer--;\n  return GETJOCTET(*src->next_input_byte++);\n}\n\n\n/*\n * The core arithmetic decoding routine (common in JPEG and JBIG).\n * This needs to go as fast as possible.\n * Machine-dependent optimization facilities\n * are not utilized in this portable implementation.\n * However, this code should be fairly efficient and\n * may be a good base for further optimizations anyway.\n *\n * Return value is 0 or 1 (binary decision).\n *\n * Note: I've changed the handling of the code base & bit\n * buffer register C compared to other implementations\n * based on the standards layout & procedures.\n * While it also contains both the actual base of the\n * coding interval (16 bits) and the next-bits buffer,\n * the cut-point between these two parts is floating\n * (instead of fixed) with the bit shift counter CT.\n * Thus, we also need only one (variable instead of\n * fixed size) shift for the LPS/MPS decision, and\n * we can do away with any renormalization update\n * of C (except for new data insertion, of course).\n *\n * I've also introduced a new scheme for accessing\n * the probability estimation state machine table,\n * derived from Markus Kuhn's JBIG implementation.\n */\n\nLOCAL(int)\narith_decode (j_decompress_ptr cinfo, unsigned char *st)\n{\n  register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;\n  register unsigned char nl, nm;\n  register INT32 qe, temp;\n  register int sv, data;\n\n  /* Renormalization & data input per section D.2.6 */\n  while (e->a < 0x8000L) {\n    if (--e->ct < 0) {\n      /* Need to fetch next data byte */\n      if (cinfo->unread_marker)\n\tdata = 0;\t\t/* stuff zero data */\n      else {\n\tdata = get_byte(cinfo);\t/* read next input byte */\n\tif (data == 0xFF) {\t/* zero stuff or marker code */\n\t  do data = get_byte(cinfo);\n\t  while (data == 0xFF);\t/* swallow extra 0xFF bytes */\n\t  if (data == 0)\n\t    data = 0xFF;\t/* discard stuffed zero byte */\n\t  else {\n\t    /* Note: Different from the Huffman decoder, hitting\n\t     * a marker while processing the compressed data\n\t     * segment is legal in arithmetic coding.\n\t     * The convention is to supply zero data\n\t     * then until decoding is complete.\n\t     */\n\t    cinfo->unread_marker = data;\n\t    data = 0;\n\t  }\n\t}\n      }\n      e->c = (e->c << 8) | data; /* insert data into C register */\n      if ((e->ct += 8) < 0)\t /* update bit shift counter */\n\t/* Need more initial bytes */\n\tif (++e->ct == 0)\n\t  /* Got 2 initial bytes -> re-init A and exit loop */\n\t  e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */\n    }\n    e->a <<= 1;\n  }\n\n  /* Fetch values from our compact representation of Table D.3(D.2):\n   * Qe values and probability estimation state machine\n   */\n  sv = *st;\n  qe = jpeg_aritab[sv & 0x7F];\t/* => Qe_Value */\n  nl = qe & 0xFF; qe >>= 8;\t/* Next_Index_LPS + Switch_MPS */\n  nm = qe & 0xFF; qe >>= 8;\t/* Next_Index_MPS */\n\n  /* Decode & estimation procedures per sections D.2.4 & D.2.5 */\n  temp = e->a - qe;\n  e->a = temp;\n  temp <<= e->ct;\n  if (e->c >= temp) {\n    e->c -= temp;\n    /* Conditional LPS (less probable symbol) exchange */\n    if (e->a < qe) {\n      e->a = qe;\n      *st = (sv & 0x80) ^ nm;\t/* Estimate_after_MPS */\n    } else {\n      e->a = qe;\n      *st = (sv & 0x80) ^ nl;\t/* Estimate_after_LPS */\n      sv ^= 0x80;\t\t/* Exchange LPS/MPS */\n    }\n  } else if (e->a < 0x8000L) {\n    /* Conditional MPS (more probable symbol) exchange */\n    if (e->a < qe) {\n      *st = (sv & 0x80) ^ nl;\t/* Estimate_after_LPS */\n      sv ^= 0x80;\t\t/* Exchange LPS/MPS */\n    } else {\n      *st = (sv & 0x80) ^ nm;\t/* Estimate_after_MPS */\n    }\n  }\n\n  return sv >> 7;\n}\n\n\n/*\n * Check for a restart marker & resynchronize decoder.\n */\n\nLOCAL(void)\nprocess_restart (j_decompress_ptr cinfo)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  int ci;\n  jpeg_component_info * compptr;\n\n  /* Advance past the RSTn marker */\n  if (! (*cinfo->marker->read_restart_marker) (cinfo))\n    ERREXIT(cinfo, JERR_CANT_SUSPEND);\n\n  /* Re-initialize statistics areas */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {\n      MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);\n      /* Reset DC predictions to 0 */\n      entropy->last_dc_val[ci] = 0;\n      entropy->dc_context[ci] = 0;\n    }\n    if ((! cinfo->progressive_mode && cinfo->lim_Se) ||\n\t(cinfo->progressive_mode && cinfo->Ss)) {\n      MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);\n    }\n  }\n\n  /* Reset arithmetic decoding variables */\n  entropy->c = 0;\n  entropy->a = 0;\n  entropy->ct = -16;\t/* force reading 2 initial bytes to fill C */\n\n  /* Reset restart counter */\n  entropy->restarts_to_go = cinfo->restart_interval;\n}\n\n\n/*\n * Arithmetic MCU decoding.\n * Each of these routines decodes and returns one MCU's worth of\n * arithmetic-compressed coefficients.\n * The coefficients are reordered from zigzag order into natural array order,\n * but are not dequantized.\n *\n * The i'th block of the MCU is stored into the block pointed to by\n * MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.\n */\n\n/*\n * MCU decoding for DC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\ndecode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  JBLOCKROW block;\n  unsigned char *st;\n  int blkn, ci, tbl, sign;\n  int v, m;\n\n  /* Process restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      process_restart(cinfo);\n    entropy->restarts_to_go--;\n  }\n\n  if (entropy->ct == -1) return TRUE;\t/* if error do nothing */\n\n  /* Outer loop handles each block in the MCU */\n\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    block = MCU_data[blkn];\n    ci = cinfo->MCU_membership[blkn];\n    tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;\n\n    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */\n\n    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */\n    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];\n\n    /* Figure F.19: Decode_DC_DIFF */\n    if (arith_decode(cinfo, st) == 0)\n      entropy->dc_context[ci] = 0;\n    else {\n      /* Figure F.21: Decoding nonzero value v */\n      /* Figure F.22: Decoding the sign of v */\n      sign = arith_decode(cinfo, st + 1);\n      st += 2; st += sign;\n      /* Figure F.23: Decoding the magnitude category of v */\n      if ((m = arith_decode(cinfo, st)) != 0) {\n\tst = entropy->dc_stats[tbl] + 20;\t/* Table F.4: X1 = 20 */\n\twhile (arith_decode(cinfo, st)) {\n\t  if ((m <<= 1) == (int) 0x8000U) {\n\t    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\t    entropy->ct = -1;\t\t\t/* magnitude overflow */\n\t    return TRUE;\n\t  }\n\t  st += 1;\n\t}\n      }\n      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */\n      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))\n\tentropy->dc_context[ci] = 0;\t\t   /* zero diff category */\n      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))\n\tentropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */\n      else\n\tentropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */\n      v = m;\n      /* Figure F.24: Decoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tif (arith_decode(cinfo, st)) v |= m;\n      v += 1; if (sign) v = -v;\n      entropy->last_dc_val[ci] += v;\n    }\n\n    /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */\n    (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for AC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\ndecode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  JBLOCKROW block;\n  unsigned char *st;\n  int tbl, sign, k;\n  int v, m;\n  const int * natural_order;\n\n  /* Process restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      process_restart(cinfo);\n    entropy->restarts_to_go--;\n  }\n\n  if (entropy->ct == -1) return TRUE;\t/* if error do nothing */\n\n  natural_order = cinfo->natural_order;\n\n  /* There is always only one block per MCU */\n  block = MCU_data[0];\n  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;\n\n  /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */\n\n  /* Figure F.20: Decode_AC_coefficients */\n  k = cinfo->Ss - 1;\n  do {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    if (arith_decode(cinfo, st)) break;\t\t/* EOB flag */\n    for (;;) {\n      k++;\n      if (arith_decode(cinfo, st + 1)) break;\n      st += 3;\n      if (k >= cinfo->Se) {\n\tWARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\tentropy->ct = -1;\t\t\t/* spectral overflow */\n\treturn TRUE;\n      }\n    }\n    /* Figure F.21: Decoding nonzero value v */\n    /* Figure F.22: Decoding the sign of v */\n    sign = arith_decode(cinfo, entropy->fixed_bin);\n    st += 2;\n    /* Figure F.23: Decoding the magnitude category of v */\n    if ((m = arith_decode(cinfo, st)) != 0) {\n      if (arith_decode(cinfo, st)) {\n\tm <<= 1;\n\tst = entropy->ac_stats[tbl] +\n\t     (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);\n\twhile (arith_decode(cinfo, st)) {\n\t  if ((m <<= 1) == (int) 0x8000U) {\n\t    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\t    entropy->ct = -1;\t\t\t/* magnitude overflow */\n\t    return TRUE;\n\t  }\n\t  st += 1;\n\t}\n      }\n    }\n    v = m;\n    /* Figure F.24: Decoding the magnitude bit pattern of v */\n    st += 14;\n    while (m >>= 1)\n      if (arith_decode(cinfo, st)) v |= m;\n    v += 1; if (sign) v = -v;\n    /* Scale and output coefficient in natural (dezigzagged) order */\n    (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al);\n  } while (k < cinfo->Se);\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for DC successive approximation refinement scan.\n * Note: we assume such scans can be multi-component,\n * although the spec is not very clear on the point.\n */\n\nMETHODDEF(boolean)\ndecode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  unsigned char *st;\n  JCOEF p1;\n  int blkn;\n\n  /* Process restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      process_restart(cinfo);\n    entropy->restarts_to_go--;\n  }\n\n  st = entropy->fixed_bin;\t/* use fixed probability estimation */\n  p1 = 1 << cinfo->Al;\t\t/* 1 in the bit position being coded */\n\n  /* Outer loop handles each block in the MCU */\n\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    /* Encoded data is simply the next bit of the two's-complement DC value */\n    if (arith_decode(cinfo, st))\n      MCU_data[blkn][0][0] |= p1;\n  }\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for AC successive approximation refinement scan.\n */\n\nMETHODDEF(boolean)\ndecode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  JBLOCKROW block;\n  JCOEFPTR thiscoef;\n  unsigned char *st;\n  int tbl, k, kex;\n  JCOEF p1, m1;\n  const int * natural_order;\n\n  /* Process restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      process_restart(cinfo);\n    entropy->restarts_to_go--;\n  }\n\n  if (entropy->ct == -1) return TRUE;\t/* if error do nothing */\n\n  natural_order = cinfo->natural_order;\n\n  /* There is always only one block per MCU */\n  block = MCU_data[0];\n  tbl = cinfo->cur_comp_info[0]->ac_tbl_no;\n\n  p1 = 1 << cinfo->Al;\t\t/* 1 in the bit position being coded */\n  m1 = -p1;\t\t\t/* -1 in the bit position being coded */\n\n  /* Establish EOBx (previous stage end-of-block) index */\n  kex = cinfo->Se;\n  do {\n    if ((*block)[natural_order[kex]]) break;\n  } while (--kex);\n\n  k = cinfo->Ss - 1;\n  do {\n    st = entropy->ac_stats[tbl] + 3 * k;\n    if (k >= kex)\n      if (arith_decode(cinfo, st)) break;\t/* EOB flag */\n    for (;;) {\n      thiscoef = *block + natural_order[++k];\n      if (*thiscoef) {\t\t\t\t/* previously nonzero coef */\n\tif (arith_decode(cinfo, st + 2)) {\n\t  if (*thiscoef < 0)\n\t    *thiscoef += m1;\n\t  else\n\t    *thiscoef += p1;\n\t}\n\tbreak;\n      }\n      if (arith_decode(cinfo, st + 1)) {\t/* newly nonzero coef */\n\tif (arith_decode(cinfo, entropy->fixed_bin))\n\t  *thiscoef = m1;\n\telse\n\t  *thiscoef = p1;\n\tbreak;\n      }\n      st += 3;\n      if (k >= cinfo->Se) {\n\tWARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\tentropy->ct = -1;\t\t\t/* spectral overflow */\n\treturn TRUE;\n      }\n    }\n  } while (k < cinfo->Se);\n\n  return TRUE;\n}\n\n\n/*\n * Decode one MCU's worth of arithmetic-compressed coefficients.\n */\n\nMETHODDEF(boolean)\ndecode_mcu (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  jpeg_component_info * compptr;\n  JBLOCKROW block;\n  unsigned char *st;\n  int blkn, ci, tbl, sign, k;\n  int v, m;\n  const int * natural_order;\n\n  /* Process restart marker if needed */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      process_restart(cinfo);\n    entropy->restarts_to_go--;\n  }\n\n  if (entropy->ct == -1) return TRUE;\t/* if error do nothing */\n\n  natural_order = cinfo->natural_order;\n\n  /* Outer loop handles each block in the MCU */\n\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    block = MCU_data[blkn];\n    ci = cinfo->MCU_membership[blkn];\n    compptr = cinfo->cur_comp_info[ci];\n\n    /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */\n\n    tbl = compptr->dc_tbl_no;\n\n    /* Table F.4: Point to statistics bin S0 for DC coefficient coding */\n    st = entropy->dc_stats[tbl] + entropy->dc_context[ci];\n\n    /* Figure F.19: Decode_DC_DIFF */\n    if (arith_decode(cinfo, st) == 0)\n      entropy->dc_context[ci] = 0;\n    else {\n      /* Figure F.21: Decoding nonzero value v */\n      /* Figure F.22: Decoding the sign of v */\n      sign = arith_decode(cinfo, st + 1);\n      st += 2; st += sign;\n      /* Figure F.23: Decoding the magnitude category of v */\n      if ((m = arith_decode(cinfo, st)) != 0) {\n\tst = entropy->dc_stats[tbl] + 20;\t/* Table F.4: X1 = 20 */\n\twhile (arith_decode(cinfo, st)) {\n\t  if ((m <<= 1) == (int) 0x8000U) {\n\t    WARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\t    entropy->ct = -1;\t\t\t/* magnitude overflow */\n\t    return TRUE;\n\t  }\n\t  st += 1;\n\t}\n      }\n      /* Section F.1.4.4.1.2: Establish dc_context conditioning category */\n      if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))\n\tentropy->dc_context[ci] = 0;\t\t   /* zero diff category */\n      else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))\n\tentropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */\n      else\n\tentropy->dc_context[ci] = 4 + (sign * 4);  /* small diff category */\n      v = m;\n      /* Figure F.24: Decoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tif (arith_decode(cinfo, st)) v |= m;\n      v += 1; if (sign) v = -v;\n      entropy->last_dc_val[ci] += v;\n    }\n\n    (*block)[0] = (JCOEF) entropy->last_dc_val[ci];\n\n    /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */\n\n    if (cinfo->lim_Se == 0) continue;\n    tbl = compptr->ac_tbl_no;\n    k = 0;\n\n    /* Figure F.20: Decode_AC_coefficients */\n    do {\n      st = entropy->ac_stats[tbl] + 3 * k;\n      if (arith_decode(cinfo, st)) break;\t/* EOB flag */\n      for (;;) {\n\tk++;\n\tif (arith_decode(cinfo, st + 1)) break;\n\tst += 3;\n\tif (k >= cinfo->lim_Se) {\n\t  WARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\t  entropy->ct = -1;\t\t\t/* spectral overflow */\n\t  return TRUE;\n\t}\n      }\n      /* Figure F.21: Decoding nonzero value v */\n      /* Figure F.22: Decoding the sign of v */\n      sign = arith_decode(cinfo, entropy->fixed_bin);\n      st += 2;\n      /* Figure F.23: Decoding the magnitude category of v */\n      if ((m = arith_decode(cinfo, st)) != 0) {\n\tif (arith_decode(cinfo, st)) {\n\t  m <<= 1;\n\t  st = entropy->ac_stats[tbl] +\n\t       (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);\n\t  while (arith_decode(cinfo, st)) {\n\t    if ((m <<= 1) == (int) 0x8000U) {\n\t      WARNMS(cinfo, JWRN_ARITH_BAD_CODE);\n\t      entropy->ct = -1;\t\t\t/* magnitude overflow */\n\t      return TRUE;\n\t    }\n\t    st += 1;\n\t  }\n\t}\n      }\n      v = m;\n      /* Figure F.24: Decoding the magnitude bit pattern of v */\n      st += 14;\n      while (m >>= 1)\n\tif (arith_decode(cinfo, st)) v |= m;\n      v += 1; if (sign) v = -v;\n      (*block)[natural_order[k]] = (JCOEF) v;\n    } while (k < cinfo->lim_Se);\n  }\n\n  return TRUE;\n}\n\n\n/*\n * Initialize for an arithmetic-compressed scan.\n */\n\nMETHODDEF(void)\nstart_pass (j_decompress_ptr cinfo)\n{\n  arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;\n  int ci, tbl;\n  jpeg_component_info * compptr;\n\n  if (cinfo->progressive_mode) {\n    /* Validate progressive scan parameters */\n    if (cinfo->Ss == 0) {\n      if (cinfo->Se != 0)\n\tgoto bad;\n    } else {\n      /* need not check Ss/Se < 0 since they came from unsigned bytes */\n      if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)\n\tgoto bad;\n      /* AC scans may have only one component */\n      if (cinfo->comps_in_scan != 1)\n\tgoto bad;\n    }\n    if (cinfo->Ah != 0) {\n      /* Successive approximation refinement scan: must have Al = Ah-1. */\n      if (cinfo->Ah-1 != cinfo->Al)\n\tgoto bad;\n    }\n    if (cinfo->Al > 13) {\t/* need not check for < 0 */\n      bad:\n      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,\n\t       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);\n    }\n    /* Update progression status, and verify that scan order is legal.\n     * Note that inter-scan inconsistencies are treated as warnings\n     * not fatal errors ... not clear if this is right way to behave.\n     */\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;\n      int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];\n      if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */\n\tWARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);\n      for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {\n\tint expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];\n\tif (cinfo->Ah != expected)\n\t  WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);\n\tcoef_bit_ptr[coefi] = cinfo->Al;\n      }\n    }\n    /* Select MCU decoding routine */\n    if (cinfo->Ah == 0) {\n      if (cinfo->Ss == 0)\n\tentropy->pub.decode_mcu = decode_mcu_DC_first;\n      else\n\tentropy->pub.decode_mcu = decode_mcu_AC_first;\n    } else {\n      if (cinfo->Ss == 0)\n\tentropy->pub.decode_mcu = decode_mcu_DC_refine;\n      else\n\tentropy->pub.decode_mcu = decode_mcu_AC_refine;\n    }\n  } else {\n    /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.\n     * This ought to be an error condition, but we make it a warning.\n     */\n    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||\n\t(cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se))\n      WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);\n    /* Select MCU decoding routine */\n    entropy->pub.decode_mcu = decode_mcu;\n  }\n\n  /* Allocate & initialize requested statistics areas */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {\n      tbl = compptr->dc_tbl_no;\n      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)\n\tERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);\n      if (entropy->dc_stats[tbl] == NULL)\n\tentropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)\n\t  ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);\n      MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);\n      /* Initialize DC predictions to 0 */\n      entropy->last_dc_val[ci] = 0;\n      entropy->dc_context[ci] = 0;\n    }\n    if ((! cinfo->progressive_mode && cinfo->lim_Se) ||\n\t(cinfo->progressive_mode && cinfo->Ss)) {\n      tbl = compptr->ac_tbl_no;\n      if (tbl < 0 || tbl >= NUM_ARITH_TBLS)\n\tERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);\n      if (entropy->ac_stats[tbl] == NULL)\n\tentropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)\n\t  ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);\n      MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);\n    }\n  }\n\n  /* Initialize arithmetic decoding variables */\n  entropy->c = 0;\n  entropy->a = 0;\n  entropy->ct = -16;\t/* force reading 2 initial bytes to fill C */\n\n  /* Initialize restart counter */\n  entropy->restarts_to_go = cinfo->restart_interval;\n}\n\n\n/*\n * Finish up at the end of an arithmetic-compressed scan.\n */\n\nMETHODDEF(void)\nfinish_pass (j_decompress_ptr cinfo)\n{\n  /* no work necessary here */\n}\n\n\n/*\n * Module initialization routine for arithmetic entropy decoding.\n */\n\nGLOBAL(void)\njinit_arith_decoder (j_decompress_ptr cinfo)\n{\n  arith_entropy_ptr entropy;\n  int i;\n\n  entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(arith_entropy_decoder));\n  cinfo->entropy = &entropy->pub;\n  entropy->pub.start_pass = start_pass;\n  entropy->pub.finish_pass = finish_pass;\n\n  /* Mark tables unallocated */\n  for (i = 0; i < NUM_ARITH_TBLS; i++) {\n    entropy->dc_stats[i] = NULL;\n    entropy->ac_stats[i] = NULL;\n  }\n\n  /* Initialize index for fixed probability estimation */\n  entropy->fixed_bin[0] = 113;\n\n  if (cinfo->progressive_mode) {\n    /* Create progression status table */\n    int *coef_bit_ptr, ci;\n    cinfo->coef_bits = (int (*)[DCTSIZE2]) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       cinfo->num_components * DCTSIZE2 * SIZEOF(int));\n    coef_bit_ptr = & cinfo->coef_bits[0][0];\n    for (ci = 0; ci < cinfo->num_components; ci++) \n      for (i = 0; i < DCTSIZE2; i++)\n\t*coef_bit_ptr++ = -1;\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdatadst.c",
    "content": "/*\n * jdatadst.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2009-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains compression data destination routines for the case of\n * emitting JPEG data to memory or to a file (or any stdio stream).\n * While these routines are sufficient for most applications,\n * some will want to use a different destination manager.\n * IMPORTANT: we assume that fwrite() will correctly transcribe an array of\n * JOCTETs into 8-bit-wide elements on external storage.  If char is wider\n * than 8 bits on your machine, you may need to do some tweaking.\n */\n\n/* this is not a core library module, so it doesn't define JPEG_INTERNALS */\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jerror.h\"\n\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare malloc(),free() */\nextern void * malloc JPP((size_t size));\nextern void free JPP((void *ptr));\n#endif\n\n\n/* Expanded data destination object for stdio output */\n\ntypedef struct {\n  struct jpeg_destination_mgr pub; /* public fields */\n\n  FILE * outfile;\t\t/* target stream */\n  JOCTET * buffer;\t\t/* start of buffer */\n} my_destination_mgr;\n\ntypedef my_destination_mgr * my_dest_ptr;\n\n#define OUTPUT_BUF_SIZE  4096\t/* choose an efficiently fwrite'able size */\n\n\n/* Expanded data destination object for memory output */\n\ntypedef struct {\n  struct jpeg_destination_mgr pub; /* public fields */\n\n  unsigned char ** outbuffer;\t/* target buffer */\n  size_t * outsize;\n  unsigned char * newbuffer;\t/* newly allocated buffer */\n  JOCTET * buffer;\t\t/* start of buffer */\n  size_t bufsize;\n} my_mem_destination_mgr;\n\ntypedef my_mem_destination_mgr * my_mem_dest_ptr;\n\n\n/*\n * Initialize destination --- called by jpeg_start_compress\n * before any data is actually written.\n */\n\nMETHODDEF(void)\ninit_destination (j_compress_ptr cinfo)\n{\n  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;\n\n  /* Allocate the output buffer --- it will be released when done with image */\n  dest->buffer = (JOCTET *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * SIZEOF(JOCTET));\n\n  dest->pub.next_output_byte = dest->buffer;\n  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;\n}\n\nMETHODDEF(void)\ninit_mem_destination (j_compress_ptr cinfo)\n{\n  /* no work necessary here */\n}\n\n\n/*\n * Empty the output buffer --- called whenever buffer fills up.\n *\n * In typical applications, this should write the entire output buffer\n * (ignoring the current state of next_output_byte & free_in_buffer),\n * reset the pointer & count to the start of the buffer, and return TRUE\n * indicating that the buffer has been dumped.\n *\n * In applications that need to be able to suspend compression due to output\n * overrun, a FALSE return indicates that the buffer cannot be emptied now.\n * In this situation, the compressor will return to its caller (possibly with\n * an indication that it has not accepted all the supplied scanlines).  The\n * application should resume compression after it has made more room in the\n * output buffer.  Note that there are substantial restrictions on the use of\n * suspension --- see the documentation.\n *\n * When suspending, the compressor will back up to a convenient restart point\n * (typically the start of the current MCU). next_output_byte & free_in_buffer\n * indicate where the restart point will be if the current call returns FALSE.\n * Data beyond this point will be regenerated after resumption, so do not\n * write it out when emptying the buffer externally.\n */\n\nMETHODDEF(boolean)\nempty_output_buffer (j_compress_ptr cinfo)\n{\n  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;\n\n  if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=\n      (size_t) OUTPUT_BUF_SIZE)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n\n  dest->pub.next_output_byte = dest->buffer;\n  dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;\n\n  return TRUE;\n}\n\nMETHODDEF(boolean)\nempty_mem_output_buffer (j_compress_ptr cinfo)\n{\n  size_t nextsize;\n  JOCTET * nextbuffer;\n  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;\n\n  /* Try to allocate new buffer with double size */\n  nextsize = dest->bufsize * 2;\n  nextbuffer = (JOCTET *) malloc(nextsize);\n\n  if (nextbuffer == NULL)\n    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 11);\n\n  MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);\n\n  if (dest->newbuffer != NULL)\n    free(dest->newbuffer);\n\n  dest->newbuffer = nextbuffer;\n\n  dest->pub.next_output_byte = nextbuffer + dest->bufsize;\n  dest->pub.free_in_buffer = dest->bufsize;\n\n  dest->buffer = nextbuffer;\n  dest->bufsize = nextsize;\n\n  return TRUE;\n}\n\n\n/*\n * Terminate destination --- called by jpeg_finish_compress\n * after all data has been written.  Usually needs to flush buffer.\n *\n * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding\n * application must deal with any cleanup that should happen even\n * for error exit.\n */\n\nMETHODDEF(void)\nterm_destination (j_compress_ptr cinfo)\n{\n  my_dest_ptr dest = (my_dest_ptr) cinfo->dest;\n  size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;\n\n  /* Write any data remaining in the buffer */\n  if (datacount > 0) {\n    if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)\n      ERREXIT(cinfo, JERR_FILE_WRITE);\n  }\n  JFFLUSH(dest->outfile);\n  /* Make sure we wrote the output file OK */\n  if (JFERROR(dest->outfile))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\nMETHODDEF(void)\nterm_mem_destination (j_compress_ptr cinfo)\n{\n  my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;\n\n  *dest->outbuffer = dest->buffer;\n  *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;\n}\n\n\n/*\n * Prepare for output to a stdio stream.\n * The caller must have already opened the stream, and is responsible\n * for closing it after finishing compression.\n */\n\nGLOBAL(void)\njpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)\n{\n  my_dest_ptr dest;\n\n  /* The destination object is made permanent so that multiple JPEG images\n   * can be written to the same file without re-executing jpeg_stdio_dest.\n   * This makes it dangerous to use this manager and a different destination\n   * manager serially with the same JPEG object, because their private object\n   * sizes may be different.  Caveat programmer.\n   */\n  if (cinfo->dest == NULL) {\t/* first time for this JPEG object? */\n    cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_destination_mgr));\n  }\n\n  dest = (my_dest_ptr) cinfo->dest;\n  dest->pub.init_destination = init_destination;\n  dest->pub.empty_output_buffer = empty_output_buffer;\n  dest->pub.term_destination = term_destination;\n  dest->outfile = outfile;\n}\n\n\n/*\n * Prepare for output to a memory buffer.\n * The caller may supply an own initial buffer with appropriate size.\n * Otherwise, or when the actual data output exceeds the given size,\n * the library adapts the buffer size as necessary.\n * The standard library functions malloc/free are used for allocating\n * larger memory, so the buffer is available to the application after\n * finishing compression, and then the application is responsible for\n * freeing the requested memory.\n * Note:  An initial buffer supplied by the caller is expected to be\n * managed by the application.  The library does not free such buffer\n * when allocating a larger buffer.\n */\n\nGLOBAL(void)\njpeg_mem_dest (j_compress_ptr cinfo,\n\t       unsigned char ** outbuffer, size_t * outsize)\n{\n  my_mem_dest_ptr dest;\n\n  if (outbuffer == NULL || outsize == NULL)\t/* sanity check */\n    ERREXIT(cinfo, JERR_BUFFER_SIZE);\n\n  /* The destination object is made permanent so that multiple JPEG images\n   * can be written to the same buffer without re-executing jpeg_mem_dest.\n   */\n  if (cinfo->dest == NULL) {\t/* first time for this JPEG object? */\n    cinfo->dest = (struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_mem_destination_mgr));\n  }\n\n  dest = (my_mem_dest_ptr) cinfo->dest;\n  dest->pub.init_destination = init_mem_destination;\n  dest->pub.empty_output_buffer = empty_mem_output_buffer;\n  dest->pub.term_destination = term_mem_destination;\n  dest->outbuffer = outbuffer;\n  dest->outsize = outsize;\n  dest->newbuffer = NULL;\n\n  if (*outbuffer == NULL || *outsize == 0) {\n    /* Allocate initial buffer */\n    dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);\n    if (dest->newbuffer == NULL)\n      ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);\n    *outsize = OUTPUT_BUF_SIZE;\n  }\n\n  dest->pub.next_output_byte = dest->buffer = *outbuffer;\n  dest->pub.free_in_buffer = dest->bufsize = *outsize;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdatasrc.c",
    "content": "/*\n * jdatasrc.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2009-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains decompression data source routines for the case of\n * reading JPEG data from memory or from a file (or any stdio stream).\n * While these routines are sufficient for most applications,\n * some will want to use a different source manager.\n * IMPORTANT: we assume that fread() will correctly transcribe an array of\n * JOCTETs from 8-bit-wide elements on external storage.  If char is wider\n * than 8 bits on your machine, you may need to do some tweaking.\n */\n\n/* this is not a core library module, so it doesn't define JPEG_INTERNALS */\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jerror.h\"\n\n\n/* Expanded data source object for stdio input */\n\ntypedef struct {\n  struct jpeg_source_mgr pub;\t/* public fields */\n\n  FILE * infile;\t\t/* source stream */\n  JOCTET * buffer;\t\t/* start of buffer */\n  boolean start_of_file;\t/* have we gotten any data yet? */\n} my_source_mgr;\n\ntypedef my_source_mgr * my_src_ptr;\n\n#define INPUT_BUF_SIZE  4096\t/* choose an efficiently fread'able size */\n\n\n/*\n * Initialize source --- called by jpeg_read_header\n * before any data is actually read.\n */\n\nMETHODDEF(void)\ninit_source (j_decompress_ptr cinfo)\n{\n  my_src_ptr src = (my_src_ptr) cinfo->src;\n\n  /* We reset the empty-input-file flag for each image,\n   * but we don't clear the input buffer.\n   * This is correct behavior for reading a series of images from one source.\n   */\n  src->start_of_file = TRUE;\n}\n\nMETHODDEF(void)\ninit_mem_source (j_decompress_ptr cinfo)\n{\n  /* no work necessary here */\n}\n\n\n/*\n * Fill the input buffer --- called whenever buffer is emptied.\n *\n * In typical applications, this should read fresh data into the buffer\n * (ignoring the current state of next_input_byte & bytes_in_buffer),\n * reset the pointer & count to the start of the buffer, and return TRUE\n * indicating that the buffer has been reloaded.  It is not necessary to\n * fill the buffer entirely, only to obtain at least one more byte.\n *\n * There is no such thing as an EOF return.  If the end of the file has been\n * reached, the routine has a choice of ERREXIT() or inserting fake data into\n * the buffer.  In most cases, generating a warning message and inserting a\n * fake EOI marker is the best course of action --- this will allow the\n * decompressor to output however much of the image is there.  However,\n * the resulting error message is misleading if the real problem is an empty\n * input file, so we handle that case specially.\n *\n * In applications that need to be able to suspend compression due to input\n * not being available yet, a FALSE return indicates that no more data can be\n * obtained right now, but more may be forthcoming later.  In this situation,\n * the decompressor will return to its caller (with an indication of the\n * number of scanlines it has read, if any).  The application should resume\n * decompression after it has loaded more data into the input buffer.  Note\n * that there are substantial restrictions on the use of suspension --- see\n * the documentation.\n *\n * When suspending, the decompressor will back up to a convenient restart point\n * (typically the start of the current MCU). next_input_byte & bytes_in_buffer\n * indicate where the restart point will be if the current call returns FALSE.\n * Data beyond this point must be rescanned after resumption, so move it to\n * the front of the buffer rather than discarding it.\n */\n\nMETHODDEF(boolean)\nfill_input_buffer (j_decompress_ptr cinfo)\n{\n  my_src_ptr src = (my_src_ptr) cinfo->src;\n  size_t nbytes;\n\n  nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);\n\n  if (nbytes <= 0) {\n    if (src->start_of_file)\t/* Treat empty input file as fatal error */\n      ERREXIT(cinfo, JERR_INPUT_EMPTY);\n    WARNMS(cinfo, JWRN_JPEG_EOF);\n    /* Insert a fake EOI marker */\n    src->buffer[0] = (JOCTET) 0xFF;\n    src->buffer[1] = (JOCTET) JPEG_EOI;\n    nbytes = 2;\n  }\n\n  src->pub.next_input_byte = src->buffer;\n  src->pub.bytes_in_buffer = nbytes;\n  src->start_of_file = FALSE;\n\n  return TRUE;\n}\n\nMETHODDEF(boolean)\nfill_mem_input_buffer (j_decompress_ptr cinfo)\n{\n  static const JOCTET mybuffer[4] = {\n    (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0\n  };\n\n  /* The whole JPEG data is expected to reside in the supplied memory\n   * buffer, so any request for more data beyond the given buffer size\n   * is treated as an error.\n   */\n  WARNMS(cinfo, JWRN_JPEG_EOF);\n\n  /* Insert a fake EOI marker */\n\n  cinfo->src->next_input_byte = mybuffer;\n  cinfo->src->bytes_in_buffer = 2;\n\n  return TRUE;\n}\n\n\n/*\n * Skip data --- used to skip over a potentially large amount of\n * uninteresting data (such as an APPn marker).\n *\n * Writers of suspendable-input applications must note that skip_input_data\n * is not granted the right to give a suspension return.  If the skip extends\n * beyond the data currently in the buffer, the buffer can be marked empty so\n * that the next read will cause a fill_input_buffer call that can suspend.\n * Arranging for additional bytes to be discarded before reloading the input\n * buffer is the application writer's problem.\n */\n\nMETHODDEF(void)\nskip_input_data (j_decompress_ptr cinfo, long num_bytes)\n{\n  struct jpeg_source_mgr * src = cinfo->src;\n  size_t nbytes;\n\n  /* Just a dumb implementation for now.  Could use fseek() except\n   * it doesn't work on pipes.  Not clear that being smart is worth\n   * any trouble anyway --- large skips are infrequent.\n   */\n  if (num_bytes > 0) {\n    nbytes = (size_t) num_bytes;\n    while (nbytes > src->bytes_in_buffer) {\n      nbytes -= src->bytes_in_buffer;\n      (void) (*src->fill_input_buffer) (cinfo);\n      /* note we assume that fill_input_buffer will never return FALSE,\n       * so suspension need not be handled.\n       */\n    }\n    src->next_input_byte += nbytes;\n    src->bytes_in_buffer -= nbytes;\n  }\n}\n\n\n/*\n * An additional method that can be provided by data source modules is the\n * resync_to_restart method for error recovery in the presence of RST markers.\n * For the moment, this source module just uses the default resync method\n * provided by the JPEG library.  That method assumes that no backtracking\n * is possible.\n */\n\n\n/*\n * Terminate source --- called by jpeg_finish_decompress\n * after all data has been read.  Often a no-op.\n *\n * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding\n * application must deal with any cleanup that should happen even\n * for error exit.\n */\n\nMETHODDEF(void)\nterm_source (j_decompress_ptr cinfo)\n{\n  /* no work necessary here */\n}\n\n\n/*\n * Prepare for input from a stdio stream.\n * The caller must have already opened the stream, and is responsible\n * for closing it after finishing decompression.\n */\n\nGLOBAL(void)\njpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)\n{\n  my_src_ptr src;\n\n  /* The source object and input buffer are made permanent so that a series\n   * of JPEG images can be read from the same file by calling jpeg_stdio_src\n   * only before the first one.  (If we discarded the buffer at the end of\n   * one image, we'd likely lose the start of the next one.)\n   * This makes it unsafe to use this manager and a different source\n   * manager serially with the same JPEG object.  Caveat programmer.\n   */\n  if (cinfo->src == NULL) {\t/* first time for this JPEG object? */\n    cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_source_mgr));\n    src = (my_src_ptr) cinfo->src;\n    src->buffer = (JOCTET *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_PERMANENT, INPUT_BUF_SIZE * SIZEOF(JOCTET));\n  }\n\n  src = (my_src_ptr) cinfo->src;\n  src->pub.init_source = init_source;\n  src->pub.fill_input_buffer = fill_input_buffer;\n  src->pub.skip_input_data = skip_input_data;\n  src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */\n  src->pub.term_source = term_source;\n  src->infile = infile;\n  src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */\n  src->pub.next_input_byte = NULL; /* until buffer loaded */\n}\n\n\n/*\n * Prepare for input from a supplied memory buffer.\n * The buffer must contain the whole JPEG data.\n */\n\nGLOBAL(void)\njpeg_mem_src (j_decompress_ptr cinfo,\n\t      const unsigned char * inbuffer, size_t insize)\n{\n  struct jpeg_source_mgr * src;\n\n  if (inbuffer == NULL || insize == 0)\t/* Treat empty input as fatal error */\n    ERREXIT(cinfo, JERR_INPUT_EMPTY);\n\n  /* The source object is made permanent so that a series of JPEG images\n   * can be read from the same buffer by calling jpeg_mem_src only before\n   * the first one.\n   */\n  if (cinfo->src == NULL) {\t/* first time for this JPEG object? */\n    cinfo->src = (struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(struct jpeg_source_mgr));\n  }\n\n  src = cinfo->src;\n  src->init_source = init_mem_source;\n  src->fill_input_buffer = fill_mem_input_buffer;\n  src->skip_input_data = skip_input_data;\n  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */\n  src->term_source = term_source;\n  src->bytes_in_buffer = insize;\n  src->next_input_byte = (const JOCTET *) inbuffer;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdcoefct.c",
    "content": "/*\n * jdcoefct.c\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the coefficient buffer controller for decompression.\n * This controller is the top level of the JPEG decompressor proper.\n * The coefficient buffer lies between entropy decoding and inverse-DCT steps.\n *\n * In buffered-image mode, this controller is the interface between\n * input-oriented processing and output-oriented processing.\n * Also, the input side (only) is used when reading a file for transcoding.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Block smoothing is only applicable for progressive JPEG, so: */\n#ifndef D_PROGRESSIVE_SUPPORTED\n#undef BLOCK_SMOOTHING_SUPPORTED\n#endif\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_d_coef_controller pub; /* public fields */\n\n  /* These variables keep track of the current location of the input side. */\n  /* cinfo->input_iMCU_row is also used for this. */\n  JDIMENSION MCU_ctr;\t\t/* counts MCUs processed in current row */\n  int MCU_vert_offset;\t\t/* counts MCU rows within iMCU row */\n  int MCU_rows_per_iMCU_row;\t/* number of such rows needed */\n\n  /* The output side's location is represented by cinfo->output_iMCU_row. */\n\n  /* In single-pass modes, it's sufficient to buffer just one MCU.\n   * We append a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,\n   * and let the entropy decoder write into that workspace each time.\n   * In multi-pass modes, this array points to the current MCU's blocks\n   * within the virtual arrays; it is used only by the input side.\n   */\n  JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];\n\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n  /* In multi-pass modes, we need a virtual block array for each component. */\n  jvirt_barray_ptr whole_image[MAX_COMPONENTS];\n#endif\n\n#ifdef BLOCK_SMOOTHING_SUPPORTED\n  /* When doing block smoothing, we latch coefficient Al values here */\n  int * coef_bits_latch;\n#define SAVED_COEFS  6\t\t/* we save coef_bits[0..5] */\n#endif\n\n  /* Workspace for single-pass modes (omitted otherwise). */\n  JBLOCK blk_buffer[D_MAX_BLOCKS_IN_MCU];\n} my_coef_controller;\n\ntypedef my_coef_controller * my_coef_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(int) decompress_onepass\n\tJPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));\n#ifdef D_MULTISCAN_FILES_SUPPORTED\nMETHODDEF(int) decompress_data\n\tJPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));\n#endif\n#ifdef BLOCK_SMOOTHING_SUPPORTED\nLOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));\nMETHODDEF(int) decompress_smooth_data\n\tJPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));\n#endif\n\n\nLOCAL(void)\nstart_iMCU_row (j_decompress_ptr cinfo)\n/* Reset within-iMCU-row counters for a new row (input side) */\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  /* In an interleaved scan, an MCU row is the same as an iMCU row.\n   * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.\n   * But at the bottom of the image, process only what's left.\n   */\n  if (cinfo->comps_in_scan > 1) {\n    coef->MCU_rows_per_iMCU_row = 1;\n  } else {\n    if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;\n    else\n      coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;\n  }\n\n  coef->MCU_ctr = 0;\n  coef->MCU_vert_offset = 0;\n}\n\n\n/*\n * Initialize for an input processing pass.\n */\n\nMETHODDEF(void)\nstart_input_pass (j_decompress_ptr cinfo)\n{\n  cinfo->input_iMCU_row = 0;\n  start_iMCU_row(cinfo);\n}\n\n\n/*\n * Initialize for an output processing pass.\n */\n\nMETHODDEF(void)\nstart_output_pass (j_decompress_ptr cinfo)\n{\n#ifdef BLOCK_SMOOTHING_SUPPORTED\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n\n  /* If multipass, check to see whether to use block smoothing on this pass */\n  if (coef->pub.coef_arrays != NULL) {\n    if (cinfo->do_block_smoothing && smoothing_ok(cinfo))\n      coef->pub.decompress_data = decompress_smooth_data;\n    else\n      coef->pub.decompress_data = decompress_data;\n  }\n#endif\n  cinfo->output_iMCU_row = 0;\n}\n\n\n/*\n * Decompress and return some data in the single-pass case.\n * Always attempts to emit one fully interleaved MCU row (\"iMCU\" row).\n * Input and output must run in lockstep since we have only a one-MCU buffer.\n * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.\n *\n * NB: output_buf contains a plane for each component in image,\n * which we index according to the component's SOF position.\n */\n\nMETHODDEF(int)\ndecompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION MCU_col_num;\t/* index of current MCU within row */\n  JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  int ci, xindex, yindex, yoffset, useful_width;\n  JBLOCKROW blkp;\n  JSAMPARRAY output_ptr;\n  JDIMENSION start_col, output_col;\n  jpeg_component_info *compptr;\n  inverse_DCT_method_ptr inverse_DCT;\n\n  /* Loop to process as much as one whole iMCU row */\n  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;\n       yoffset++) {\n    for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;\n\t MCU_col_num++) {\n      blkp = coef->blk_buffer;\t/* pointer to current DCT block within MCU */\n      /* Try to fetch an MCU.  Entropy decoder expects buffer to be zeroed. */\n      if (cinfo->lim_Se)\t/* can bypass in DC only case */\n\tMEMZERO(blkp, cinfo->blocks_in_MCU * SIZEOF(JBLOCK));\n      if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {\n\t/* Suspension forced; update state counters and exit */\n\tcoef->MCU_vert_offset = yoffset;\n\tcoef->MCU_ctr = MCU_col_num;\n\treturn JPEG_SUSPENDED;\n      }\n      /* Determine where data should go in output_buf and do the IDCT thing.\n       * We skip dummy blocks at the right and bottom edges (but blkp gets\n       * incremented past them!).\n       */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n\tcompptr = cinfo->cur_comp_info[ci];\n\t/* Don't bother to IDCT an uninteresting component. */\n\tif (! compptr->component_needed) {\n\t  blkp += compptr->MCU_blocks;\n\t  continue;\n\t}\n\tinverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];\n\toutput_ptr = output_buf[compptr->component_index] +\n\t  yoffset * compptr->DCT_v_scaled_size;\n\tuseful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width\n\t\t\t\t\t\t    : compptr->last_col_width;\n\tstart_col = MCU_col_num * compptr->MCU_sample_width;\n\tfor (yindex = 0; yindex < compptr->MCU_height; yindex++) {\n\t  if (cinfo->input_iMCU_row < last_iMCU_row ||\n\t      yoffset + yindex < compptr->last_row_height) {\n\t    output_col = start_col;\n\t    for (xindex = 0; xindex < useful_width; xindex++) {\n\t      (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) (blkp + xindex),\n\t\t\t      output_ptr, output_col);\n\t      output_col += compptr->DCT_h_scaled_size;\n\t    }\n\t    output_ptr += compptr->DCT_v_scaled_size;\n\t  }\n\t  blkp += compptr->MCU_width;\n\t}\n      }\n    }\n    /* Completed an MCU row, but perhaps not an iMCU row */\n    coef->MCU_ctr = 0;\n  }\n  /* Completed the iMCU row, advance counters for next one */\n  cinfo->output_iMCU_row++;\n  if (++(cinfo->input_iMCU_row) <= last_iMCU_row) {\n    start_iMCU_row(cinfo);\n    return JPEG_ROW_COMPLETED;\n  }\n  /* Completed the scan */\n  (*cinfo->inputctl->finish_input_pass) (cinfo);\n  return JPEG_SCAN_COMPLETED;\n}\n\n\n/*\n * Dummy consume-input routine for single-pass operation.\n */\n\nMETHODDEF(int)\ndummy_consume_data (j_decompress_ptr cinfo)\n{\n  return JPEG_SUSPENDED;\t/* Always indicate nothing was done */\n}\n\n\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n\n/*\n * Consume input data and store it in the full-image coefficient buffer.\n * We read as much as one fully interleaved MCU row (\"iMCU\" row) per call,\n * ie, v_samp_factor block rows for each component in the scan.\n * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.\n */\n\nMETHODDEF(int)\nconsume_data (j_decompress_ptr cinfo)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION MCU_col_num;\t/* index of current MCU within row */\n  int ci, xindex, yindex, yoffset;\n  JDIMENSION start_col;\n  JBLOCKARRAY blkp;\n  JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];\n  JBLOCKROW buffer_ptr;\n  jpeg_component_info *compptr;\n\n  /* Align the virtual buffers for the components used in this scan. */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    buffer[ci] = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],\n       cinfo->input_iMCU_row * compptr->v_samp_factor,\n       (JDIMENSION) compptr->v_samp_factor, TRUE);\n    /* Note: entropy decoder expects buffer to be zeroed,\n     * but this is handled automatically by the memory manager\n     * because we requested a pre-zeroed array.\n     */\n  }\n\n  /* Loop to process one whole iMCU row */\n  for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;\n       yoffset++) {\n    for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;\n\t MCU_col_num++) {\n      /* Construct list of pointers to DCT blocks belonging to this MCU */\n      blkp = coef->MCU_buffer;\t/* pointer to current DCT block within MCU */\n      for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n\tcompptr = cinfo->cur_comp_info[ci];\n\tstart_col = MCU_col_num * compptr->MCU_width;\n\tfor (yindex = 0; yindex < compptr->MCU_height; yindex++) {\n\t  buffer_ptr = buffer[ci][yoffset + yindex] + start_col;\n\t  xindex = compptr->MCU_width;\n\t  do {\n\t    *blkp++ = buffer_ptr++;\n\t  } while (--xindex);\n\t}\n      }\n      /* Try to fetch the MCU. */\n      if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {\n\t/* Suspension forced; update state counters and exit */\n\tcoef->MCU_vert_offset = yoffset;\n\tcoef->MCU_ctr = MCU_col_num;\n\treturn JPEG_SUSPENDED;\n      }\n    }\n    /* Completed an MCU row, but perhaps not an iMCU row */\n    coef->MCU_ctr = 0;\n  }\n  /* Completed the iMCU row, advance counters for next one */\n  if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {\n    start_iMCU_row(cinfo);\n    return JPEG_ROW_COMPLETED;\n  }\n  /* Completed the scan */\n  (*cinfo->inputctl->finish_input_pass) (cinfo);\n  return JPEG_SCAN_COMPLETED;\n}\n\n\n/*\n * Decompress and return some data in the multi-pass case.\n * Always attempts to emit one fully interleaved MCU row (\"iMCU\" row).\n * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.\n *\n * NB: output_buf contains a plane for each component in image.\n */\n\nMETHODDEF(int)\ndecompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  JDIMENSION block_num;\n  int ci, block_row, block_rows;\n  JBLOCKARRAY buffer;\n  JBLOCKROW buffer_ptr;\n  JSAMPARRAY output_ptr;\n  JDIMENSION output_col;\n  jpeg_component_info *compptr;\n  inverse_DCT_method_ptr inverse_DCT;\n\n  /* Force some input to be done if we are getting ahead of the input. */\n  while (cinfo->input_scan_number < cinfo->output_scan_number ||\n\t (cinfo->input_scan_number == cinfo->output_scan_number &&\n\t  cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {\n    if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)\n      return JPEG_SUSPENDED;\n  }\n\n  /* OK, output from the virtual arrays. */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Don't bother to IDCT an uninteresting component. */\n    if (! compptr->component_needed)\n      continue;\n    /* Align the virtual buffer for this component. */\n    buffer = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef->whole_image[ci],\n       cinfo->output_iMCU_row * compptr->v_samp_factor,\n       (JDIMENSION) compptr->v_samp_factor, FALSE);\n    /* Count non-dummy DCT block rows in this iMCU row. */\n    if (cinfo->output_iMCU_row < last_iMCU_row)\n      block_rows = compptr->v_samp_factor;\n    else {\n      /* NB: can't use last_row_height here; it is input-side-dependent! */\n      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);\n      if (block_rows == 0) block_rows = compptr->v_samp_factor;\n    }\n    inverse_DCT = cinfo->idct->inverse_DCT[ci];\n    output_ptr = output_buf[ci];\n    /* Loop over all DCT blocks to be processed. */\n    for (block_row = 0; block_row < block_rows; block_row++) {\n      buffer_ptr = buffer[block_row];\n      output_col = 0;\n      for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {\n\t(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,\n\t\t\toutput_ptr, output_col);\n\tbuffer_ptr++;\n\toutput_col += compptr->DCT_h_scaled_size;\n      }\n      output_ptr += compptr->DCT_v_scaled_size;\n    }\n  }\n\n  if (++(cinfo->output_iMCU_row) <= last_iMCU_row)\n    return JPEG_ROW_COMPLETED;\n  return JPEG_SCAN_COMPLETED;\n}\n\n#endif /* D_MULTISCAN_FILES_SUPPORTED */\n\n\n#ifdef BLOCK_SMOOTHING_SUPPORTED\n\n/*\n * This code applies interblock smoothing as described by section K.8\n * of the JPEG standard: the first 5 AC coefficients are estimated from\n * the DC values of a DCT block and its 8 neighboring blocks.\n * We apply smoothing only for progressive JPEG decoding, and only if\n * the coefficients it can estimate are not yet known to full precision.\n */\n\n/* Natural-order array positions of the first 5 zigzag-order coefficients */\n#define Q01_POS  1\n#define Q10_POS  8\n#define Q20_POS  16\n#define Q11_POS  9\n#define Q02_POS  2\n\n/*\n * Determine whether block smoothing is applicable and safe.\n * We also latch the current states of the coef_bits[] entries for the\n * AC coefficients; otherwise, if the input side of the decompressor\n * advances into a new scan, we might think the coefficients are known\n * more accurately than they really are.\n */\n\nLOCAL(boolean)\nsmoothing_ok (j_decompress_ptr cinfo)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  boolean smoothing_useful = FALSE;\n  int ci, coefi;\n  jpeg_component_info *compptr;\n  JQUANT_TBL * qtable;\n  int * coef_bits;\n  int * coef_bits_latch;\n\n  if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)\n    return FALSE;\n\n  /* Allocate latch area if not already done */\n  if (coef->coef_bits_latch == NULL)\n    coef->coef_bits_latch = (int *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       cinfo->num_components * (SAVED_COEFS * SIZEOF(int)));\n  coef_bits_latch = coef->coef_bits_latch;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* All components' quantization values must already be latched. */\n    if ((qtable = compptr->quant_table) == NULL)\n      return FALSE;\n    /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */\n    if (qtable->quantval[0] == 0 ||\n\tqtable->quantval[Q01_POS] == 0 ||\n\tqtable->quantval[Q10_POS] == 0 ||\n\tqtable->quantval[Q20_POS] == 0 ||\n\tqtable->quantval[Q11_POS] == 0 ||\n\tqtable->quantval[Q02_POS] == 0)\n      return FALSE;\n    /* DC values must be at least partly known for all components. */\n    coef_bits = cinfo->coef_bits[ci];\n    if (coef_bits[0] < 0)\n      return FALSE;\n    /* Block smoothing is helpful if some AC coefficients remain inaccurate. */\n    for (coefi = 1; coefi <= 5; coefi++) {\n      coef_bits_latch[coefi] = coef_bits[coefi];\n      if (coef_bits[coefi] != 0)\n\tsmoothing_useful = TRUE;\n    }\n    coef_bits_latch += SAVED_COEFS;\n  }\n\n  return smoothing_useful;\n}\n\n\n/*\n * Variant of decompress_data for use when doing block smoothing.\n */\n\nMETHODDEF(int)\ndecompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)\n{\n  my_coef_ptr coef = (my_coef_ptr) cinfo->coef;\n  JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;\n  JDIMENSION block_num, last_block_column;\n  int ci, block_row, block_rows, access_rows;\n  JBLOCKARRAY buffer;\n  JBLOCKROW buffer_ptr, prev_block_row, next_block_row;\n  JSAMPARRAY output_ptr;\n  JDIMENSION output_col;\n  jpeg_component_info *compptr;\n  inverse_DCT_method_ptr inverse_DCT;\n  boolean first_row, last_row;\n  JBLOCK workspace;\n  int *coef_bits;\n  JQUANT_TBL *quanttbl;\n  INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;\n  int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;\n  int Al, pred;\n\n  /* Force some input to be done if we are getting ahead of the input. */\n  while (cinfo->input_scan_number <= cinfo->output_scan_number &&\n\t ! cinfo->inputctl->eoi_reached) {\n    if (cinfo->input_scan_number == cinfo->output_scan_number) {\n      /* If input is working on current scan, we ordinarily want it to\n       * have completed the current row.  But if input scan is DC,\n       * we want it to keep one row ahead so that next block row's DC\n       * values are up to date.\n       */\n      JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;\n      if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)\n\tbreak;\n    }\n    if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)\n      return JPEG_SUSPENDED;\n  }\n\n  /* OK, output from the virtual arrays. */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Don't bother to IDCT an uninteresting component. */\n    if (! compptr->component_needed)\n      continue;\n    /* Count non-dummy DCT block rows in this iMCU row. */\n    if (cinfo->output_iMCU_row < last_iMCU_row) {\n      block_rows = compptr->v_samp_factor;\n      access_rows = block_rows * 2; /* this and next iMCU row */\n      last_row = FALSE;\n    } else {\n      /* NB: can't use last_row_height here; it is input-side-dependent! */\n      block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);\n      if (block_rows == 0) block_rows = compptr->v_samp_factor;\n      access_rows = block_rows; /* this iMCU row only */\n      last_row = TRUE;\n    }\n    /* Align the virtual buffer for this component. */\n    if (cinfo->output_iMCU_row > 0) {\n      access_rows += compptr->v_samp_factor; /* prior iMCU row too */\n      buffer = (*cinfo->mem->access_virt_barray)\n\t((j_common_ptr) cinfo, coef->whole_image[ci],\n\t (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,\n\t (JDIMENSION) access_rows, FALSE);\n      buffer += compptr->v_samp_factor;\t/* point to current iMCU row */\n      first_row = FALSE;\n    } else {\n      buffer = (*cinfo->mem->access_virt_barray)\n\t((j_common_ptr) cinfo, coef->whole_image[ci],\n\t (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);\n      first_row = TRUE;\n    }\n    /* Fetch component-dependent info */\n    coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);\n    quanttbl = compptr->quant_table;\n    Q00 = quanttbl->quantval[0];\n    Q01 = quanttbl->quantval[Q01_POS];\n    Q10 = quanttbl->quantval[Q10_POS];\n    Q20 = quanttbl->quantval[Q20_POS];\n    Q11 = quanttbl->quantval[Q11_POS];\n    Q02 = quanttbl->quantval[Q02_POS];\n    inverse_DCT = cinfo->idct->inverse_DCT[ci];\n    output_ptr = output_buf[ci];\n    /* Loop over all DCT blocks to be processed. */\n    for (block_row = 0; block_row < block_rows; block_row++) {\n      buffer_ptr = buffer[block_row];\n      if (first_row && block_row == 0)\n\tprev_block_row = buffer_ptr;\n      else\n\tprev_block_row = buffer[block_row-1];\n      if (last_row && block_row == block_rows-1)\n\tnext_block_row = buffer_ptr;\n      else\n\tnext_block_row = buffer[block_row+1];\n      /* We fetch the surrounding DC values using a sliding-register approach.\n       * Initialize all nine here so as to do the right thing on narrow pics.\n       */\n      DC1 = DC2 = DC3 = (int) prev_block_row[0][0];\n      DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];\n      DC7 = DC8 = DC9 = (int) next_block_row[0][0];\n      output_col = 0;\n      last_block_column = compptr->width_in_blocks - 1;\n      for (block_num = 0; block_num <= last_block_column; block_num++) {\n\t/* Fetch current DCT block into workspace so we can modify it. */\n\tjcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);\n\t/* Update DC values */\n\tif (block_num < last_block_column) {\n\t  DC3 = (int) prev_block_row[1][0];\n\t  DC6 = (int) buffer_ptr[1][0];\n\t  DC9 = (int) next_block_row[1][0];\n\t}\n\t/* Compute coefficient estimates per K.8.\n\t * An estimate is applied only if coefficient is still zero,\n\t * and is not known to be fully accurate.\n\t */\n\t/* AC01 */\n\tif ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {\n\t  num = 36 * Q00 * (DC4 - DC6);\n\t  if (num >= 0) {\n\t    pred = (int) (((Q01<<7) + num) / (Q01<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t  } else {\n\t    pred = (int) (((Q01<<7) - num) / (Q01<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t    pred = -pred;\n\t  }\n\t  workspace[1] = (JCOEF) pred;\n\t}\n\t/* AC10 */\n\tif ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {\n\t  num = 36 * Q00 * (DC2 - DC8);\n\t  if (num >= 0) {\n\t    pred = (int) (((Q10<<7) + num) / (Q10<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t  } else {\n\t    pred = (int) (((Q10<<7) - num) / (Q10<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t    pred = -pred;\n\t  }\n\t  workspace[8] = (JCOEF) pred;\n\t}\n\t/* AC20 */\n\tif ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {\n\t  num = 9 * Q00 * (DC2 + DC8 - 2*DC5);\n\t  if (num >= 0) {\n\t    pred = (int) (((Q20<<7) + num) / (Q20<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t  } else {\n\t    pred = (int) (((Q20<<7) - num) / (Q20<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t    pred = -pred;\n\t  }\n\t  workspace[16] = (JCOEF) pred;\n\t}\n\t/* AC11 */\n\tif ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {\n\t  num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);\n\t  if (num >= 0) {\n\t    pred = (int) (((Q11<<7) + num) / (Q11<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t  } else {\n\t    pred = (int) (((Q11<<7) - num) / (Q11<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t    pred = -pred;\n\t  }\n\t  workspace[9] = (JCOEF) pred;\n\t}\n\t/* AC02 */\n\tif ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {\n\t  num = 9 * Q00 * (DC4 + DC6 - 2*DC5);\n\t  if (num >= 0) {\n\t    pred = (int) (((Q02<<7) + num) / (Q02<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t  } else {\n\t    pred = (int) (((Q02<<7) - num) / (Q02<<8));\n\t    if (Al > 0 && pred >= (1<<Al))\n\t      pred = (1<<Al)-1;\n\t    pred = -pred;\n\t  }\n\t  workspace[2] = (JCOEF) pred;\n\t}\n\t/* OK, do the IDCT */\n\t(*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,\n\t\t\toutput_ptr, output_col);\n\t/* Advance for next column */\n\tDC1 = DC2; DC2 = DC3;\n\tDC4 = DC5; DC5 = DC6;\n\tDC7 = DC8; DC8 = DC9;\n\tbuffer_ptr++, prev_block_row++, next_block_row++;\n\toutput_col += compptr->DCT_h_scaled_size;\n      }\n      output_ptr += compptr->DCT_v_scaled_size;\n    }\n  }\n\n  if (++(cinfo->output_iMCU_row) <= last_iMCU_row)\n    return JPEG_ROW_COMPLETED;\n  return JPEG_SCAN_COMPLETED;\n}\n\n#endif /* BLOCK_SMOOTHING_SUPPORTED */\n\n\n/*\n * Initialize coefficient buffer controller.\n */\n\nGLOBAL(void)\njinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)\n{\n  my_coef_ptr coef;\n\n  if (need_full_buffer) {\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n    /* Allocate a full-image virtual array for each component, */\n    /* padded to a multiple of samp_factor DCT blocks in each direction. */\n    /* Note we ask for a pre-zeroed array. */\n    int ci, access_rows;\n    jpeg_component_info *compptr;\n\n    coef = (my_coef_ptr) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       SIZEOF(my_coef_controller) - SIZEOF(coef->blk_buffer));\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      access_rows = compptr->v_samp_factor;\n#ifdef BLOCK_SMOOTHING_SUPPORTED\n      /* If block smoothing could be used, need a bigger window */\n      if (cinfo->progressive_mode)\n\taccess_rows *= 3;\n#endif\n      coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,\n\t (JDIMENSION) jround_up((long) compptr->width_in_blocks,\n\t\t\t\t(long) compptr->h_samp_factor),\n\t (JDIMENSION) jround_up((long) compptr->height_in_blocks,\n\t\t\t\t(long) compptr->v_samp_factor),\n\t (JDIMENSION) access_rows);\n    }\n    coef->pub.consume_data = consume_data;\n    coef->pub.decompress_data = decompress_data;\n    coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n  } else {\n    /* We only need a single-MCU buffer. */\n    JBLOCKARRAY blkp;\n    JBLOCKROW buffer_ptr;\n    int bi;\n\n    coef = (my_coef_ptr) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_coef_controller));\n    buffer_ptr = coef->blk_buffer;\n    if (cinfo->lim_Se == 0)\t/* DC only case: want to bypass later */\n      MEMZERO(buffer_ptr, SIZEOF(coef->blk_buffer));\n    blkp = coef->MCU_buffer;\n    bi = D_MAX_BLOCKS_IN_MCU;\n    do {\n      *blkp++ = buffer_ptr++;\n    } while (--bi);\n    coef->pub.consume_data = dummy_consume_data;\n    coef->pub.decompress_data = decompress_onepass;\n    coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */\n  }\n\n  coef->pub.start_input_pass = start_input_pass;\n  coef->pub.start_output_pass = start_output_pass;\n#ifdef BLOCK_SMOOTHING_SUPPORTED\n  coef->coef_bits_latch = NULL;\n#endif\n  cinfo->coef = &coef->pub;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdcolor.c",
    "content": "/*\n * jdcolor.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2011-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains output colorspace conversion routines.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n#if RANGE_BITS < 2\n  /* Deliberate syntax err */\n  Sorry, this code requires 2 or more range extension bits.\n#endif\n\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_color_deconverter pub; /* public fields */\n\n  /* Private state for YCbCr->RGB and BG_YCC->RGB conversion */\n  int * Cr_r_tab;\t\t/* => table for Cr to R conversion */\n  int * Cb_b_tab;\t\t/* => table for Cb to B conversion */\n  INT32 * Cr_g_tab;\t\t/* => table for Cr to G conversion */\n  INT32 * Cb_g_tab;\t\t/* => table for Cb to G conversion */\n\n  /* Private state for RGB->Y conversion */\n  INT32 * rgb_y_tab;\t\t/* => table for RGB to Y conversion */\n} my_color_deconverter;\n\ntypedef my_color_deconverter * my_cconvert_ptr;\n\n\n/***************  YCbCr -> RGB conversion: most common case **************/\n/*************** BG_YCC -> RGB conversion: less common case **************/\n/***************    RGB -> Y   conversion: less common case **************/\n\n/*\n * YCbCr is defined per Recommendation ITU-R BT.601-7 (03/2011),\n * previously known as Recommendation CCIR 601-1, except that Cb and Cr\n * are normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.\n * sRGB (standard RGB color space) is defined per IEC 61966-2-1:1999.\n * sYCC (standard luma-chroma-chroma color space with extended gamut)\n * is defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex F.\n * bg-sRGB and bg-sYCC (big gamut standard color spaces)\n * are defined per IEC 61966-2-1:1999 Amendment A1:2003 Annex G.\n * Note that the derived conversion coefficients given in some of these\n * documents are imprecise.  The general conversion equations are\n *\n *\tR = Y + K * (1 - Kr) * Cr\n *\tG = Y - K * (Kb * (1 - Kb) * Cb + Kr * (1 - Kr) * Cr) / (1 - Kr - Kb)\n *\tB = Y + K * (1 - Kb) * Cb\n *\n *\tY = Kr * R + (1 - Kr - Kb) * G + Kb * B\n *\n * With Kr = 0.299 and Kb = 0.114 (derived according to SMPTE RP 177-1993\n * from the 1953 FCC NTSC primaries and CIE Illuminant C), K = 2 for sYCC,\n * the conversion equations to be implemented are therefore\n *\n *\tR = Y + 1.402 * Cr\n *\tG = Y - 0.344136286 * Cb - 0.714136286 * Cr\n *\tB = Y + 1.772 * Cb\n *\n *\tY = 0.299 * R + 0.587 * G + 0.114 * B\n *\n * where Cb and Cr represent the incoming values less CENTERJSAMPLE.\n * For bg-sYCC, with K = 4, the equations are\n *\n *\tR = Y + 2.804 * Cr\n *\tG = Y - 0.688272572 * Cb - 1.428272572 * Cr\n *\tB = Y + 3.544 * Cb\n *\n * To avoid floating-point arithmetic, we represent the fractional constants\n * as integers scaled up by 2^16 (about 4 digits precision); we have to divide\n * the products by 2^16, with appropriate rounding, to get the correct answer.\n * Notice that Y, being an integral input, does not contribute any fraction\n * so it need not participate in the rounding.\n *\n * For even more speed, we avoid doing any multiplications in the inner loop\n * by precalculating the constants times Cb and Cr for all possible values.\n * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);\n * for 9-bit to 12-bit samples it is still acceptable.  It's not very\n * reasonable for 16-bit samples, but if you want lossless storage you\n * shouldn't be changing colorspace anyway.\n * The Cr=>R and Cb=>B values can be rounded to integers in advance; the\n * values for the G calculation are left scaled up, since we must add them\n * together before rounding.\n */\n\n#define SCALEBITS\t16\t/* speediest right-shift on some machines */\n#define ONE_HALF\t((INT32) 1 << (SCALEBITS-1))\n#define FIX(x)\t\t((INT32) ((x) * (1L<<SCALEBITS) + 0.5))\n\n/* We allocate one big table for RGB->Y conversion and divide it up into\n * three parts, instead of doing three alloc_small requests.  This lets us\n * use a single table base address, which can be held in a register in the\n * inner loops on many machines (more than can hold all three addresses,\n * anyway).\n */\n\n#define R_Y_OFF\t\t0\t\t\t/* offset to R => Y section */\n#define G_Y_OFF\t\t(1*(MAXJSAMPLE+1))\t/* offset to G => Y section */\n#define B_Y_OFF\t\t(2*(MAXJSAMPLE+1))\t/* etc. */\n#define TABLE_SIZE\t(3*(MAXJSAMPLE+1))\n\n\n/*\n * Initialize tables for YCbCr->RGB and BG_YCC->RGB colorspace conversion.\n */\n\nLOCAL(void)\nbuild_ycc_rgb_table (j_decompress_ptr cinfo)\n/* Normal case, sYCC */\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  int i;\n  INT32 x;\n  SHIFT_TEMPS\n\n  cconvert->Cr_r_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  cconvert->Cb_b_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  cconvert->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n  cconvert->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n\n  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {\n    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */\n    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */\n    /* Cr=>R value is nearest int to 1.402 * x */\n    cconvert->Cr_r_tab[i] = (int) DESCALE(FIX(1.402) * x, SCALEBITS);\n    /* Cb=>B value is nearest int to 1.772 * x */\n    cconvert->Cb_b_tab[i] = (int) DESCALE(FIX(1.772) * x, SCALEBITS);\n    /* Cr=>G value is scaled-up -0.714136286 * x */\n    cconvert->Cr_g_tab[i] = (- FIX(0.714136286)) * x;\n    /* Cb=>G value is scaled-up -0.344136286 * x */\n    /* We also add in ONE_HALF so that need not do it in inner loop */\n    cconvert->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF;\n  }\n}\n\n\nLOCAL(void)\nbuild_bg_ycc_rgb_table (j_decompress_ptr cinfo)\n/* Wide gamut case, bg-sYCC */\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  int i;\n  INT32 x;\n  SHIFT_TEMPS\n\n  cconvert->Cr_r_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  cconvert->Cb_b_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  cconvert->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n  cconvert->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n\n  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {\n    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */\n    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */\n    /* Cr=>R value is nearest int to 2.804 * x */\n    cconvert->Cr_r_tab[i] = (int) DESCALE(FIX(2.804) * x, SCALEBITS);\n    /* Cb=>B value is nearest int to 3.544 * x */\n    cconvert->Cb_b_tab[i] = (int) DESCALE(FIX(3.544) * x, SCALEBITS);\n    /* Cr=>G value is scaled-up -1.428272572 * x */\n    cconvert->Cr_g_tab[i] = (- FIX(1.428272572)) * x;\n    /* Cb=>G value is scaled-up -0.688272572 * x */\n    /* We also add in ONE_HALF so that need not do it in inner loop */\n    cconvert->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF;\n  }\n}\n\n\n/*\n * Convert some rows of samples to the output colorspace.\n *\n * Note that we change from noninterleaved, one-plane-per-component format\n * to interleaved-pixel format.  The output buffer is therefore three times\n * as wide as the input buffer.\n *\n * A starting row offset is provided only for the input buffer.  The caller\n * can easily adjust the passed output_buf value to accommodate any row\n * offset required on that side.\n */\n\nMETHODDEF(void)\nycc_rgb_convert (j_decompress_ptr cinfo,\n\t\t JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t JSAMPARRAY output_buf, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int y, cb, cr;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n  /* copy these pointers into registers if possible */\n  register JSAMPLE * range_limit = cinfo->sample_range_limit;\n  register int * Crrtab = cconvert->Cr_r_tab;\n  register int * Cbbtab = cconvert->Cb_b_tab;\n  register INT32 * Crgtab = cconvert->Cr_g_tab;\n  register INT32 * Cbgtab = cconvert->Cb_g_tab;\n  SHIFT_TEMPS\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      y  = GETJSAMPLE(inptr0[col]);\n      cb = GETJSAMPLE(inptr1[col]);\n      cr = GETJSAMPLE(inptr2[col]);\n      /* Range-limiting is essential due to noise introduced by DCT losses,\n       * for extended gamut (sYCC) and wide gamut (bg-sYCC) encodings.\n       */\n      outptr[RGB_RED]   = range_limit[y + Crrtab[cr]];\n      outptr[RGB_GREEN] = range_limit[y +\n\t\t\t      ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],\n\t\t\t\t\t\t SCALEBITS))];\n      outptr[RGB_BLUE]  = range_limit[y + Cbbtab[cb]];\n      outptr += RGB_PIXELSIZE;\n    }\n  }\n}\n\n\n/**************** Cases other than YCC -> RGB ****************/\n\n\n/*\n * Initialize for RGB->grayscale colorspace conversion.\n */\n\nLOCAL(void)\nbuild_rgb_y_table (j_decompress_ptr cinfo)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  INT32 * rgb_y_tab;\n  INT32 i;\n\n  /* Allocate and fill in the conversion tables. */\n  cconvert->rgb_y_tab = rgb_y_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, TABLE_SIZE * SIZEOF(INT32));\n\n  for (i = 0; i <= MAXJSAMPLE; i++) {\n    rgb_y_tab[i+R_Y_OFF] = FIX(0.299) * i;\n    rgb_y_tab[i+G_Y_OFF] = FIX(0.587) * i;\n    rgb_y_tab[i+B_Y_OFF] = FIX(0.114) * i + ONE_HALF;\n  }\n}\n\n\n/*\n * Convert RGB to grayscale.\n */\n\nMETHODDEF(void)\nrgb_gray_convert (j_decompress_ptr cinfo,\n\t\t  JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t  JSAMPARRAY output_buf, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_y_tab;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr0[col]);\n      g = GETJSAMPLE(inptr1[col]);\n      b = GETJSAMPLE(inptr2[col]);\n      /* Y */\n      outptr[col] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the output colorspace.\n * [R-G,G,B-G] to [R,G,B] conversion with modulo calculation\n * (inverse color transform).\n * This can be seen as an adaption of the general YCbCr->RGB\n * conversion equation with Kr = Kb = 0, while replacing the\n * normalization by modulo calculation.\n */\n\nMETHODDEF(void)\nrgb1_rgb_convert (j_decompress_ptr cinfo,\n\t\t  JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t  JSAMPARRAY output_buf, int num_rows)\n{\n  register int r, g, b;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr0[col]);\n      g = GETJSAMPLE(inptr1[col]);\n      b = GETJSAMPLE(inptr2[col]);\n      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD\n       * (modulo) operator is equivalent to the bitmask operator AND.\n       */\n      outptr[RGB_RED]   = (JSAMPLE) ((r + g - CENTERJSAMPLE) & MAXJSAMPLE);\n      outptr[RGB_GREEN] = (JSAMPLE) g;\n      outptr[RGB_BLUE]  = (JSAMPLE) ((b + g - CENTERJSAMPLE) & MAXJSAMPLE);\n      outptr += RGB_PIXELSIZE;\n    }\n  }\n}\n\n\n/*\n * [R-G,G,B-G] to grayscale conversion with modulo calculation\n * (inverse color transform).\n */\n\nMETHODDEF(void)\nrgb1_gray_convert (j_decompress_ptr cinfo,\n\t\t   JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t   JSAMPARRAY output_buf, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_y_tab;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      r = GETJSAMPLE(inptr0[col]);\n      g = GETJSAMPLE(inptr1[col]);\n      b = GETJSAMPLE(inptr2[col]);\n      /* Assume that MAXJSAMPLE+1 is a power of 2, so that the MOD\n       * (modulo) operator is equivalent to the bitmask operator AND.\n       */\n      r = (r + g - CENTERJSAMPLE) & MAXJSAMPLE;\n      b = (b + g - CENTERJSAMPLE) & MAXJSAMPLE;\n      /* Y */\n      outptr[col] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the output colorspace.\n * No colorspace change, but conversion from separate-planes\n * to interleaved representation.\n */\n\nMETHODDEF(void)\nrgb_convert (j_decompress_ptr cinfo,\n\t     JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t     JSAMPARRAY output_buf, int num_rows)\n{\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      /* We can dispense with GETJSAMPLE() here */\n      outptr[RGB_RED]   = inptr0[col];\n      outptr[RGB_GREEN] = inptr1[col];\n      outptr[RGB_BLUE]  = inptr2[col];\n      outptr += RGB_PIXELSIZE;\n    }\n  }\n}\n\n\n/*\n * Color conversion for no colorspace change: just copy the data,\n * converting from separate-planes to interleaved representation.\n * Note: Omit uninteresting components in output buffer.\n */\n\nMETHODDEF(void)\nnull_convert (j_decompress_ptr cinfo,\n\t      JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t      JSAMPARRAY output_buf, int num_rows)\n{\n  register JSAMPROW outptr;\n  register JSAMPROW inptr;\n  register JDIMENSION count;\n  register int out_comps = cinfo->out_color_components;\n  JDIMENSION num_cols = cinfo->output_width;\n  JSAMPROW startptr;\n  int ci;\n  jpeg_component_info *compptr;\n\n  while (--num_rows >= 0) {\n    /* It seems fastest to make a separate pass for each component. */\n    startptr = *output_buf++;\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      if (! compptr->component_needed)\n\tcontinue;\t\t/* skip uninteresting component */\n      inptr = input_buf[ci][input_row];\n      outptr = startptr++;\n      for (count = num_cols; count > 0; count--) {\n\t*outptr = *inptr++;\t/* don't need GETJSAMPLE() here */\n\toutptr += out_comps;\n      }\n    }\n    input_row++;\n  }\n}\n\n\n/*\n * Color conversion for grayscale: just copy the data.\n * This also works for YCC -> grayscale conversion, in which\n * we just copy the Y (luminance) component and ignore chrominance.\n */\n\nMETHODDEF(void)\ngrayscale_convert (j_decompress_ptr cinfo,\n\t\t   JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t   JSAMPARRAY output_buf, int num_rows)\n{\n  jcopy_sample_rows(input_buf[0] + input_row, output_buf,\n\t\t    num_rows, cinfo->output_width);\n}\n\n\n/*\n * Convert grayscale to RGB: just duplicate the graylevel three times.\n * This is provided to support applications that don't want to cope\n * with grayscale as a separate case.\n */\n\nMETHODDEF(void)\ngray_rgb_convert (j_decompress_ptr cinfo,\n\t\t  JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t  JSAMPARRAY output_buf, int num_rows)\n{\n  register JSAMPROW outptr;\n  register JSAMPROW inptr;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr = input_buf[0][input_row++];\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      /* We can dispense with GETJSAMPLE() here */\n      outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];\n      outptr += RGB_PIXELSIZE;\n    }\n  }\n}\n\n\n/*\n * Convert some rows of samples to the output colorspace.\n * This version handles Adobe-style YCCK->CMYK conversion,\n * where we convert YCbCr to R=1-C, G=1-M, and B=1-Y using the\n * same conversion as above, while passing K (black) unchanged.\n * We assume build_ycc_rgb_table has been called.\n */\n\nMETHODDEF(void)\nycck_cmyk_convert (j_decompress_ptr cinfo,\n\t\t   JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t   JSAMPARRAY output_buf, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int y, cb, cr;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2, inptr3;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n  /* copy these pointers into registers if possible */\n  register JSAMPLE * range_limit = cinfo->sample_range_limit;\n  register int * Crrtab = cconvert->Cr_r_tab;\n  register int * Cbbtab = cconvert->Cb_b_tab;\n  register INT32 * Crgtab = cconvert->Cr_g_tab;\n  register INT32 * Cbgtab = cconvert->Cb_g_tab;\n  SHIFT_TEMPS\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    inptr3 = input_buf[3][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      y  = GETJSAMPLE(inptr0[col]);\n      cb = GETJSAMPLE(inptr1[col]);\n      cr = GETJSAMPLE(inptr2[col]);\n      /* Range-limiting is essential due to noise introduced by DCT losses,\n       * and for extended gamut encodings (sYCC).\n       */\n      outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])];\t/* red */\n      outptr[1] = range_limit[MAXJSAMPLE - (y +\t\t\t/* green */\n\t\t\t      ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],\n\t\t\t\t\t\t SCALEBITS)))];\n      outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])];\t/* blue */\n      /* K passes through unchanged */\n      outptr[3] = inptr3[col];\t/* don't need GETJSAMPLE here */\n      outptr += 4;\n    }\n  }\n}\n\n\n/*\n * Convert CMYK to YK part of YCCK for colorless output.\n * We assume build_rgb_y_table has been called.\n */\n\nMETHODDEF(void)\ncmyk_yk_convert (j_decompress_ptr cinfo,\n\t\t JSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t JSAMPARRAY output_buf, int num_rows)\n{\n  my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;\n  register int r, g, b;\n  register INT32 * ctab = cconvert->rgb_y_tab;\n  register JSAMPROW outptr;\n  register JSAMPROW inptr0, inptr1, inptr2, inptr3;\n  register JDIMENSION col;\n  JDIMENSION num_cols = cinfo->output_width;\n\n  while (--num_rows >= 0) {\n    inptr0 = input_buf[0][input_row];\n    inptr1 = input_buf[1][input_row];\n    inptr2 = input_buf[2][input_row];\n    inptr3 = input_buf[3][input_row];\n    input_row++;\n    outptr = *output_buf++;\n    for (col = 0; col < num_cols; col++) {\n      r = MAXJSAMPLE - GETJSAMPLE(inptr0[col]);\n      g = MAXJSAMPLE - GETJSAMPLE(inptr1[col]);\n      b = MAXJSAMPLE - GETJSAMPLE(inptr2[col]);\n      /* Y */\n      outptr[0] = (JSAMPLE)\n\t\t((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])\n\t\t >> SCALEBITS);\n      /* K passes through unchanged */\n      outptr[1] = inptr3[col];\t/* don't need GETJSAMPLE here */\n      outptr += 2;\n    }\n  }\n}\n\n\n/*\n * Empty method for start_pass.\n */\n\nMETHODDEF(void)\nstart_pass_dcolor (j_decompress_ptr cinfo)\n{\n  /* no work needed */\n}\n\n\n/*\n * Module initialization routine for output colorspace conversion.\n */\n\nGLOBAL(void)\njinit_color_deconverter (j_decompress_ptr cinfo)\n{\n  my_cconvert_ptr cconvert;\n  int ci, i;\n\n  cconvert = (my_cconvert_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_color_deconverter));\n  cinfo->cconvert = &cconvert->pub;\n  cconvert->pub.start_pass = start_pass_dcolor;\n\n  /* Make sure num_components agrees with jpeg_color_space */\n  switch (cinfo->jpeg_color_space) {\n  case JCS_GRAYSCALE:\n    if (cinfo->num_components != 1)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    break;\n\n  case JCS_RGB:\n  case JCS_YCbCr:\n  case JCS_BG_RGB:\n  case JCS_BG_YCC:\n    if (cinfo->num_components != 3)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    break;\n\n  case JCS_CMYK:\n  case JCS_YCCK:\n    if (cinfo->num_components != 4)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n    break;\n\n  default:\t\t\t/* JCS_UNKNOWN can be anything */\n    if (cinfo->num_components < 1)\n      ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);\n  }\n\n  /* Support color transform only for RGB colorspaces */\n  if (cinfo->color_transform &&\n      cinfo->jpeg_color_space != JCS_RGB &&\n      cinfo->jpeg_color_space != JCS_BG_RGB)\n    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n\n  /* Set out_color_components and conversion method based on requested space.\n   * Also adjust the component_needed flags for any unused components,\n   * so that earlier pipeline stages can avoid useless computation.\n   */\n\n  switch (cinfo->out_color_space) {\n  case JCS_GRAYSCALE:\n    cinfo->out_color_components = 1;\n    switch (cinfo->jpeg_color_space) {\n    case JCS_GRAYSCALE:\n    case JCS_YCbCr:\n    case JCS_BG_YCC:\n      cconvert->pub.color_convert = grayscale_convert;\n      /* For color->grayscale conversion, only the Y (0) component is needed */\n      for (ci = 1; ci < cinfo->num_components; ci++)\n\tcinfo->comp_info[ci].component_needed = FALSE;\n      break;\n    case JCS_RGB:\n      switch (cinfo->color_transform) {\n      case JCT_NONE:\n\tcconvert->pub.color_convert = rgb_gray_convert;\n\tbreak;\n      case JCT_SUBTRACT_GREEN:\n\tcconvert->pub.color_convert = rgb1_gray_convert;\n\tbreak;\n      default:\n\tERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n      }\n      build_rgb_y_table(cinfo);\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_RGB:\n    cinfo->out_color_components = RGB_PIXELSIZE;\n    switch (cinfo->jpeg_color_space) {\n    case JCS_GRAYSCALE:\n      cconvert->pub.color_convert = gray_rgb_convert;\n      break;\n    case JCS_YCbCr:\n      cconvert->pub.color_convert = ycc_rgb_convert;\n      build_ycc_rgb_table(cinfo);\n      break;\n    case JCS_BG_YCC:\n      cconvert->pub.color_convert = ycc_rgb_convert;\n      build_bg_ycc_rgb_table(cinfo);\n      break;\n    case JCS_RGB:\n      switch (cinfo->color_transform) {\n      case JCT_NONE:\n\tcconvert->pub.color_convert = rgb_convert;\n\tbreak;\n      case JCT_SUBTRACT_GREEN:\n\tcconvert->pub.color_convert = rgb1_rgb_convert;\n\tbreak;\n      default:\n\tERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n      }\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_BG_RGB:\n    if (cinfo->jpeg_color_space != JCS_BG_RGB)\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    cinfo->out_color_components = RGB_PIXELSIZE;\n    switch (cinfo->color_transform) {\n    case JCT_NONE:\n      cconvert->pub.color_convert = rgb_convert;\n      break;\n    case JCT_SUBTRACT_GREEN:\n      cconvert->pub.color_convert = rgb1_rgb_convert;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    }\n    break;\n\n  case JCS_CMYK:\n    if (cinfo->jpeg_color_space != JCS_YCCK)\n      goto def_label;\n    cinfo->out_color_components = 4;\n    cconvert->pub.color_convert = ycck_cmyk_convert;\n    build_ycc_rgb_table(cinfo);\n    break;\n\n  case JCS_YCCK:\n    if (cinfo->jpeg_color_space != JCS_CMYK ||\n\t/* Support only YK part of YCCK for colorless output */\n\t! cinfo->comp_info[0].component_needed ||\n\t  cinfo->comp_info[1].component_needed ||\n\t  cinfo->comp_info[2].component_needed ||\n\t! cinfo->comp_info[3].component_needed)\n      goto def_label;\n    cinfo->out_color_components = 2;\n    /* Need all components on input side */\n    cinfo->comp_info[1].component_needed = TRUE;\n    cinfo->comp_info[2].component_needed = TRUE;\n    cconvert->pub.color_convert = cmyk_yk_convert;\n    build_rgb_y_table(cinfo);\n    break;\n\n  default: def_label:\t/* permit null conversion to same output space */\n    if (cinfo->out_color_space != cinfo->jpeg_color_space)\n      /* unsupported non-null conversion */\n      ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n    i = 0;\n    for (ci = 0; ci < cinfo->num_components; ci++)\n      if (cinfo->comp_info[ci].component_needed)\n\ti++;\t\t/* count output color components */\n    cinfo->out_color_components = i;\n    cconvert->pub.color_convert = null_convert;\n  }\n\n  if (cinfo->quantize_colors)\n    cinfo->output_components = 1; /* single colormapped output component */\n  else\n    cinfo->output_components = cinfo->out_color_components;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdct.h",
    "content": "/*\n * jdct.h\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2002-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This include file contains common declarations for the forward and\n * inverse DCT modules.  These declarations are private to the DCT managers\n * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.\n * The individual DCT algorithms are kept in separate files to ease \n * machine-dependent tuning (e.g., assembly coding).\n */\n\n\n/*\n * A forward DCT routine is given a pointer to an input sample array and\n * a pointer to a work area of type DCTELEM[]; the DCT is to be performed\n * in-place in that buffer.  Type DCTELEM is int for 8-bit samples, INT32\n * for 12-bit samples.  (NOTE: Floating-point DCT implementations use an\n * array of type FAST_FLOAT, instead.)\n * The input data is to be fetched from the sample array starting at a\n * specified column.  (Any row offset needed will be applied to the array\n * pointer before it is passed to the FDCT code.)\n * Note that the number of samples fetched by the FDCT routine is\n * DCT_h_scaled_size * DCT_v_scaled_size.\n * The DCT outputs are returned scaled up by a factor of 8; they therefore\n * have a range of +-8K for 8-bit data, +-128K for 12-bit data.  This\n * convention improves accuracy in integer implementations and saves some\n * work in floating-point ones.\n * Quantization of the output coefficients is done by jcdctmgr.c.\n */\n\n#if BITS_IN_JSAMPLE == 8\ntypedef int DCTELEM;\t\t/* 16 or 32 bits is fine */\n#else\ntypedef INT32 DCTELEM;\t\t/* must have 32 bits */\n#endif\n\ntypedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data,\n\t\t\t\t\t       JSAMPARRAY sample_data,\n\t\t\t\t\t       JDIMENSION start_col));\ntypedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data,\n\t\t\t\t\t     JSAMPARRAY sample_data,\n\t\t\t\t\t     JDIMENSION start_col));\n\n\n/*\n * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer\n * to an output sample array.  The routine must dequantize the input data as\n * well as perform the IDCT; for dequantization, it uses the multiplier table\n * pointed to by compptr->dct_table.  The output data is to be placed into the\n * sample array starting at a specified column.  (Any row offset needed will\n * be applied to the array pointer before it is passed to the IDCT code.)\n * Note that the number of samples emitted by the IDCT routine is\n * DCT_h_scaled_size * DCT_v_scaled_size.\n */\n\n/* typedef inverse_DCT_method_ptr is declared in jpegint.h */\n\n/*\n * Each IDCT routine has its own ideas about the best dct_table element type.\n */\n\ntypedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */\n#if BITS_IN_JSAMPLE == 8\ntypedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */\n#define IFAST_SCALE_BITS  2\t/* fractional bits in scale factors */\n#else\ntypedef INT32 IFAST_MULT_TYPE;\t/* need 32 bits for scaled quantizers */\n#define IFAST_SCALE_BITS  13\t/* fractional bits in scale factors */\n#endif\ntypedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */\n\n\n/*\n * Each IDCT routine is responsible for range-limiting its results and\n * converting them to unsigned form (0..MAXJSAMPLE).  The raw outputs could\n * be quite far out of range if the input data is corrupt, so a bulletproof\n * range-limiting step is required.  We use a mask-and-table-lookup method\n * to do the combined operations quickly, assuming that RANGE_CENTER\n * (defined in jpegint.h) is a power of 2.  See the comments with\n * prepare_range_limit_table (in jdmaster.c) for more info.\n */\n\n#define RANGE_MASK  (RANGE_CENTER * 2 - 1)\n#define RANGE_SUBSET  (RANGE_CENTER - CENTERJSAMPLE)\n\n#define IDCT_range_limit(cinfo)  ((cinfo)->sample_range_limit - RANGE_SUBSET)\n\n\n/* Short forms of external names for systems with brain-damaged linkers. */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jpeg_fdct_islow\t\tjFDislow\n#define jpeg_fdct_ifast\t\tjFDifast\n#define jpeg_fdct_float\t\tjFDfloat\n#define jpeg_fdct_7x7\t\tjFD7x7\n#define jpeg_fdct_6x6\t\tjFD6x6\n#define jpeg_fdct_5x5\t\tjFD5x5\n#define jpeg_fdct_4x4\t\tjFD4x4\n#define jpeg_fdct_3x3\t\tjFD3x3\n#define jpeg_fdct_2x2\t\tjFD2x2\n#define jpeg_fdct_1x1\t\tjFD1x1\n#define jpeg_fdct_9x9\t\tjFD9x9\n#define jpeg_fdct_10x10\t\tjFD10x10\n#define jpeg_fdct_11x11\t\tjFD11x11\n#define jpeg_fdct_12x12\t\tjFD12x12\n#define jpeg_fdct_13x13\t\tjFD13x13\n#define jpeg_fdct_14x14\t\tjFD14x14\n#define jpeg_fdct_15x15\t\tjFD15x15\n#define jpeg_fdct_16x16\t\tjFD16x16\n#define jpeg_fdct_16x8\t\tjFD16x8\n#define jpeg_fdct_14x7\t\tjFD14x7\n#define jpeg_fdct_12x6\t\tjFD12x6\n#define jpeg_fdct_10x5\t\tjFD10x5\n#define jpeg_fdct_8x4\t\tjFD8x4\n#define jpeg_fdct_6x3\t\tjFD6x3\n#define jpeg_fdct_4x2\t\tjFD4x2\n#define jpeg_fdct_2x1\t\tjFD2x1\n#define jpeg_fdct_8x16\t\tjFD8x16\n#define jpeg_fdct_7x14\t\tjFD7x14\n#define jpeg_fdct_6x12\t\tjFD6x12\n#define jpeg_fdct_5x10\t\tjFD5x10\n#define jpeg_fdct_4x8\t\tjFD4x8\n#define jpeg_fdct_3x6\t\tjFD3x6\n#define jpeg_fdct_2x4\t\tjFD2x4\n#define jpeg_fdct_1x2\t\tjFD1x2\n#define jpeg_idct_islow\t\tjRDislow\n#define jpeg_idct_ifast\t\tjRDifast\n#define jpeg_idct_float\t\tjRDfloat\n#define jpeg_idct_7x7\t\tjRD7x7\n#define jpeg_idct_6x6\t\tjRD6x6\n#define jpeg_idct_5x5\t\tjRD5x5\n#define jpeg_idct_4x4\t\tjRD4x4\n#define jpeg_idct_3x3\t\tjRD3x3\n#define jpeg_idct_2x2\t\tjRD2x2\n#define jpeg_idct_1x1\t\tjRD1x1\n#define jpeg_idct_9x9\t\tjRD9x9\n#define jpeg_idct_10x10\t\tjRD10x10\n#define jpeg_idct_11x11\t\tjRD11x11\n#define jpeg_idct_12x12\t\tjRD12x12\n#define jpeg_idct_13x13\t\tjRD13x13\n#define jpeg_idct_14x14\t\tjRD14x14\n#define jpeg_idct_15x15\t\tjRD15x15\n#define jpeg_idct_16x16\t\tjRD16x16\n#define jpeg_idct_16x8\t\tjRD16x8\n#define jpeg_idct_14x7\t\tjRD14x7\n#define jpeg_idct_12x6\t\tjRD12x6\n#define jpeg_idct_10x5\t\tjRD10x5\n#define jpeg_idct_8x4\t\tjRD8x4\n#define jpeg_idct_6x3\t\tjRD6x3\n#define jpeg_idct_4x2\t\tjRD4x2\n#define jpeg_idct_2x1\t\tjRD2x1\n#define jpeg_idct_8x16\t\tjRD8x16\n#define jpeg_idct_7x14\t\tjRD7x14\n#define jpeg_idct_6x12\t\tjRD6x12\n#define jpeg_idct_5x10\t\tjRD5x10\n#define jpeg_idct_4x8\t\tjRD4x8\n#define jpeg_idct_3x6\t\tjRD3x8\n#define jpeg_idct_2x4\t\tjRD2x4\n#define jpeg_idct_1x2\t\tjRD1x2\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n/* Extern declarations for the forward and inverse DCT routines. */\n\nEXTERN(void) jpeg_fdct_islow\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_ifast\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_float\n    JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_7x7\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_6x6\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_5x5\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_4x4\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_3x3\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_2x2\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_1x1\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_9x9\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_10x10\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_11x11\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_12x12\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_13x13\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_14x14\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_15x15\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_16x16\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_16x8\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_14x7\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_12x6\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_10x5\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_8x4\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_6x3\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_4x2\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_2x1\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_8x16\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_7x14\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_6x12\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_5x10\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_4x8\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_3x6\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_2x4\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\nEXTERN(void) jpeg_fdct_1x2\n    JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));\n\nEXTERN(void) jpeg_idct_islow\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_ifast\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_float\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_7x7\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_6x6\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_5x5\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_4x4\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_3x3\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_2x2\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_1x1\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_9x9\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_10x10\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_11x11\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_12x12\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_13x13\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_14x14\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_15x15\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_16x16\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_16x8\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_14x7\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_12x6\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_10x5\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_8x4\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_6x3\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_4x2\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_2x1\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_8x16\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_7x14\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_6x12\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_5x10\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_4x8\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_3x6\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_2x4\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\nEXTERN(void) jpeg_idct_1x2\n    JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));\n\n\n/*\n * Macros for handling fixed-point arithmetic; these are used by many\n * but not all of the DCT/IDCT modules.\n *\n * All values are expected to be of type INT32.\n * Fractional constants are scaled left by CONST_BITS bits.\n * CONST_BITS is defined within each module using these macros,\n * and may differ from one module to the next.\n */\n\n#define ONE\t((INT32) 1)\n#define CONST_SCALE (ONE << CONST_BITS)\n\n/* Convert a positive real constant to an integer scaled by CONST_SCALE.\n * Caution: some C compilers fail to reduce \"FIX(constant)\" at compile time,\n * thus causing a lot of useless floating-point operations at run time.\n */\n\n#define FIX(x)\t((INT32) ((x) * CONST_SCALE + 0.5))\n\n/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.\n * This macro is used only when the two inputs will actually be no more than\n * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a\n * full 32x32 multiply.  This provides a useful speedup on many machines.\n * Unfortunately there is no way to specify a 16x16->32 multiply portably\n * in C, but some C compilers will do the right thing if you provide the\n * correct combination of casts.\n */\n\n#ifdef SHORTxSHORT_32\t\t/* may work if 'int' is 32 bits */\n#define MULTIPLY16C16(var,const)  (((INT16) (var)) * ((INT16) (const)))\n#endif\n#ifdef SHORTxLCONST_32\t\t/* known to work with Microsoft C 6.0 */\n#define MULTIPLY16C16(var,const)  (((INT16) (var)) * ((INT32) (const)))\n#endif\n\n#ifndef MULTIPLY16C16\t\t/* default definition */\n#define MULTIPLY16C16(var,const)  ((var) * (const))\n#endif\n\n/* Same except both inputs are variables. */\n\n#ifdef SHORTxSHORT_32\t\t/* may work if 'int' is 32 bits */\n#define MULTIPLY16V16(var1,var2)  (((INT16) (var1)) * ((INT16) (var2)))\n#endif\n\n#ifndef MULTIPLY16V16\t\t/* default definition */\n#define MULTIPLY16V16(var1,var2)  ((var1) * (var2))\n#endif\n\n/* Like RIGHT_SHIFT, but applies to a DCTELEM.\n * We assume that int right shift is unsigned if INT32 right shift is.\n */\n\n#ifdef RIGHT_SHIFT_IS_UNSIGNED\n#define ISHIFT_TEMPS\tDCTELEM ishift_temp;\n#if BITS_IN_JSAMPLE == 8\n#define DCTELEMBITS  16\t\t/* DCTELEM may be 16 or 32 bits */\n#else\n#define DCTELEMBITS  32\t\t/* DCTELEM must be 32 bits */\n#endif\n#define IRIGHT_SHIFT(x,shft)  \\\n    ((ishift_temp = (x)) < 0 ? \\\n     (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \\\n     (ishift_temp >> (shft)))\n#else\n#define ISHIFT_TEMPS\n#define IRIGHT_SHIFT(x,shft)\t((x) >> (shft))\n#endif\n"
  },
  {
    "path": "dlib/external/libjpeg/jddctmgr.c",
    "content": "/*\n * jddctmgr.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2002-2013 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the inverse-DCT management logic.\n * This code selects a particular IDCT implementation to be used,\n * and it performs related housekeeping chores.  No code in this file\n * is executed per IDCT step, only during output pass setup.\n *\n * Note that the IDCT routines are responsible for performing coefficient\n * dequantization as well as the IDCT proper.  This module sets up the\n * dequantization multiplier table needed by the IDCT routine.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n\n/*\n * The decompressor input side (jdinput.c) saves away the appropriate\n * quantization table for each component at the start of the first scan\n * involving that component.  (This is necessary in order to correctly\n * decode files that reuse Q-table slots.)\n * When we are ready to make an output pass, the saved Q-table is converted\n * to a multiplier table that will actually be used by the IDCT routine.\n * The multiplier table contents are IDCT-method-dependent.  To support\n * application changes in IDCT method between scans, we can remake the\n * multiplier tables if necessary.\n * In buffered-image mode, the first output pass may occur before any data\n * has been seen for some components, and thus before their Q-tables have\n * been saved away.  To handle this case, multiplier tables are preset\n * to zeroes; the result of the IDCT will be a neutral gray level.\n */\n\n\n/* Private subobject for this module */\n\ntypedef struct {\n  struct jpeg_inverse_dct pub;\t/* public fields */\n\n  /* This array contains the IDCT method code that each multiplier table\n   * is currently set up for, or -1 if it's not yet set up.\n   * The actual multiplier tables are pointed to by dct_table in the\n   * per-component comp_info structures.\n   */\n  int cur_method[MAX_COMPONENTS];\n} my_idct_controller;\n\ntypedef my_idct_controller * my_idct_ptr;\n\n\n/* Allocated multiplier tables: big enough for any supported variant */\n\ntypedef union {\n  ISLOW_MULT_TYPE islow_array[DCTSIZE2];\n#ifdef DCT_IFAST_SUPPORTED\n  IFAST_MULT_TYPE ifast_array[DCTSIZE2];\n#endif\n#ifdef DCT_FLOAT_SUPPORTED\n  FLOAT_MULT_TYPE float_array[DCTSIZE2];\n#endif\n} multiplier_table;\n\n\n/* The current scaled-IDCT routines require ISLOW-style multiplier tables,\n * so be sure to compile that code if either ISLOW or SCALING is requested.\n */\n#ifdef DCT_ISLOW_SUPPORTED\n#define PROVIDE_ISLOW_TABLES\n#else\n#ifdef IDCT_SCALING_SUPPORTED\n#define PROVIDE_ISLOW_TABLES\n#endif\n#endif\n\n\n/*\n * Prepare for an output pass.\n * Here we select the proper IDCT routine for each component and build\n * a matching multiplier table.\n */\n\nMETHODDEF(void)\nstart_pass (j_decompress_ptr cinfo)\n{\n  my_idct_ptr idct = (my_idct_ptr) cinfo->idct;\n  int ci, i;\n  jpeg_component_info *compptr;\n  int method = 0;\n  inverse_DCT_method_ptr method_ptr = NULL;\n  JQUANT_TBL * qtbl;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Select the proper IDCT routine for this component's scaling */\n    switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {\n#ifdef IDCT_SCALING_SUPPORTED\n    case ((1 << 8) + 1):\n      method_ptr = jpeg_idct_1x1;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((2 << 8) + 2):\n      method_ptr = jpeg_idct_2x2;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((3 << 8) + 3):\n      method_ptr = jpeg_idct_3x3;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((4 << 8) + 4):\n      method_ptr = jpeg_idct_4x4;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((5 << 8) + 5):\n      method_ptr = jpeg_idct_5x5;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((6 << 8) + 6):\n      method_ptr = jpeg_idct_6x6;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((7 << 8) + 7):\n      method_ptr = jpeg_idct_7x7;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((9 << 8) + 9):\n      method_ptr = jpeg_idct_9x9;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((10 << 8) + 10):\n      method_ptr = jpeg_idct_10x10;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((11 << 8) + 11):\n      method_ptr = jpeg_idct_11x11;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((12 << 8) + 12):\n      method_ptr = jpeg_idct_12x12;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((13 << 8) + 13):\n      method_ptr = jpeg_idct_13x13;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((14 << 8) + 14):\n      method_ptr = jpeg_idct_14x14;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((15 << 8) + 15):\n      method_ptr = jpeg_idct_15x15;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((16 << 8) + 16):\n      method_ptr = jpeg_idct_16x16;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((16 << 8) + 8):\n      method_ptr = jpeg_idct_16x8;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((14 << 8) + 7):\n      method_ptr = jpeg_idct_14x7;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((12 << 8) + 6):\n      method_ptr = jpeg_idct_12x6;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((10 << 8) + 5):\n      method_ptr = jpeg_idct_10x5;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((8 << 8) + 4):\n      method_ptr = jpeg_idct_8x4;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((6 << 8) + 3):\n      method_ptr = jpeg_idct_6x3;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((4 << 8) + 2):\n      method_ptr = jpeg_idct_4x2;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((2 << 8) + 1):\n      method_ptr = jpeg_idct_2x1;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((8 << 8) + 16):\n      method_ptr = jpeg_idct_8x16;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((7 << 8) + 14):\n      method_ptr = jpeg_idct_7x14;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((6 << 8) + 12):\n      method_ptr = jpeg_idct_6x12;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((5 << 8) + 10):\n      method_ptr = jpeg_idct_5x10;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((4 << 8) + 8):\n      method_ptr = jpeg_idct_4x8;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((3 << 8) + 6):\n      method_ptr = jpeg_idct_3x6;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((2 << 8) + 4):\n      method_ptr = jpeg_idct_2x4;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n    case ((1 << 8) + 2):\n      method_ptr = jpeg_idct_1x2;\n      method = JDCT_ISLOW;\t/* jidctint uses islow-style table */\n      break;\n#endif\n    case ((DCTSIZE << 8) + DCTSIZE):\n      switch (cinfo->dct_method) {\n#ifdef DCT_ISLOW_SUPPORTED\n      case JDCT_ISLOW:\n\tmethod_ptr = jpeg_idct_islow;\n\tmethod = JDCT_ISLOW;\n\tbreak;\n#endif\n#ifdef DCT_IFAST_SUPPORTED\n      case JDCT_IFAST:\n\tmethod_ptr = jpeg_idct_ifast;\n\tmethod = JDCT_IFAST;\n\tbreak;\n#endif\n#ifdef DCT_FLOAT_SUPPORTED\n      case JDCT_FLOAT:\n\tmethod_ptr = jpeg_idct_float;\n\tmethod = JDCT_FLOAT;\n\tbreak;\n#endif\n      default:\n\tERREXIT(cinfo, JERR_NOT_COMPILED);\n\tbreak;\n      }\n      break;\n    default:\n      ERREXIT2(cinfo, JERR_BAD_DCTSIZE,\n\t       compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);\n      break;\n    }\n    idct->pub.inverse_DCT[ci] = method_ptr;\n    /* Create multiplier table from quant table.\n     * However, we can skip this if the component is uninteresting\n     * or if we already built the table.  Also, if no quant table\n     * has yet been saved for the component, we leave the\n     * multiplier table all-zero; we'll be reading zeroes from the\n     * coefficient controller's buffer anyway.\n     */\n    if (! compptr->component_needed || idct->cur_method[ci] == method)\n      continue;\n    qtbl = compptr->quant_table;\n    if (qtbl == NULL)\t\t/* happens if no data yet for component */\n      continue;\n    idct->cur_method[ci] = method;\n    switch (method) {\n#ifdef PROVIDE_ISLOW_TABLES\n    case JDCT_ISLOW:\n      {\n\t/* For LL&M IDCT method, multipliers are equal to raw quantization\n\t * coefficients, but are stored as ints to ensure access efficiency.\n\t */\n\tISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;\n\tfor (i = 0; i < DCTSIZE2; i++) {\n\t  ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];\n\t}\n      }\n      break;\n#endif\n#ifdef DCT_IFAST_SUPPORTED\n    case JDCT_IFAST:\n      {\n\t/* For AA&N IDCT method, multipliers are equal to quantization\n\t * coefficients scaled by scalefactor[row]*scalefactor[col], where\n\t *   scalefactor[0] = 1\n\t *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7\n\t * For integer operation, the multiplier table is to be scaled by\n\t * IFAST_SCALE_BITS.\n\t */\n\tIFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;\n#define CONST_BITS 14\n\tstatic const INT16 aanscales[DCTSIZE2] = {\n\t  /* precomputed values scaled up by 14 bits */\n\t  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,\n\t  22725, 31521, 29692, 26722, 22725, 17855, 12299,  6270,\n\t  21407, 29692, 27969, 25172, 21407, 16819, 11585,  5906,\n\t  19266, 26722, 25172, 22654, 19266, 15137, 10426,  5315,\n\t  16384, 22725, 21407, 19266, 16384, 12873,  8867,  4520,\n\t  12873, 17855, 16819, 15137, 12873, 10114,  6967,  3552,\n\t   8867, 12299, 11585, 10426,  8867,  6967,  4799,  2446,\n\t   4520,  6270,  5906,  5315,  4520,  3552,  2446,  1247\n\t};\n\tSHIFT_TEMPS\n\n\tfor (i = 0; i < DCTSIZE2; i++) {\n\t  ifmtbl[i] = (IFAST_MULT_TYPE)\n\t    DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],\n\t\t\t\t  (INT32) aanscales[i]),\n\t\t    CONST_BITS-IFAST_SCALE_BITS);\n\t}\n      }\n      break;\n#endif\n#ifdef DCT_FLOAT_SUPPORTED\n    case JDCT_FLOAT:\n      {\n\t/* For float AA&N IDCT method, multipliers are equal to quantization\n\t * coefficients scaled by scalefactor[row]*scalefactor[col], where\n\t *   scalefactor[0] = 1\n\t *   scalefactor[k] = cos(k*PI/16) * sqrt(2)    for k=1..7\n\t * We apply a further scale factor of 1/8.\n\t */\n\tFLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;\n\tint row, col;\n\tstatic const double aanscalefactor[DCTSIZE] = {\n\t  1.0, 1.387039845, 1.306562965, 1.175875602,\n\t  1.0, 0.785694958, 0.541196100, 0.275899379\n\t};\n\n\ti = 0;\n\tfor (row = 0; row < DCTSIZE; row++) {\n\t  for (col = 0; col < DCTSIZE; col++) {\n\t    fmtbl[i] = (FLOAT_MULT_TYPE)\n\t      ((double) qtbl->quantval[i] *\n\t       aanscalefactor[row] * aanscalefactor[col] * 0.125);\n\t    i++;\n\t  }\n\t}\n      }\n      break;\n#endif\n    default:\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n      break;\n    }\n  }\n}\n\n\n/*\n * Initialize IDCT manager.\n */\n\nGLOBAL(void)\njinit_inverse_dct (j_decompress_ptr cinfo)\n{\n  my_idct_ptr idct;\n  int ci;\n  jpeg_component_info *compptr;\n\n  idct = (my_idct_ptr)\n    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\tSIZEOF(my_idct_controller));\n  cinfo->idct = &idct->pub;\n  idct->pub.start_pass = start_pass;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Allocate and pre-zero a multiplier table for each component */\n    compptr->dct_table =\n      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\t  SIZEOF(multiplier_table));\n    MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));\n    /* Mark multiplier table not yet set up for any method */\n    idct->cur_method[ci] = -1;\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdhuff.c",
    "content": "/*\n * jdhuff.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2006-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains Huffman entropy decoding routines.\n * Both sequential and progressive modes are supported in this single module.\n *\n * Much of the complexity here has to do with supporting input suspension.\n * If the data source module demands suspension, we want to be able to back\n * up to the start of the current MCU.  To do this, we copy state variables\n * into local working storage, and update them back to the permanent\n * storage only upon successful completion of an MCU.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Derived data constructed for each Huffman table */\n\n#define HUFF_LOOKAHEAD\t8\t/* # of bits of lookahead */\n\ntypedef struct {\n  /* Basic tables: (element [0] of each array is unused) */\n  INT32 maxcode[18];\t\t/* largest code of length k (-1 if none) */\n  /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */\n  INT32 valoffset[17];\t\t/* huffval[] offset for codes of length k */\n  /* valoffset[k] = huffval[] index of 1st symbol of code length k, less\n   * the smallest code of length k; so given a code of length k, the\n   * corresponding symbol is huffval[code + valoffset[k]]\n   */\n\n  /* Link to public Huffman table (needed only in jpeg_huff_decode) */\n  JHUFF_TBL *pub;\n\n  /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of\n   * the input data stream.  If the next Huffman code is no more\n   * than HUFF_LOOKAHEAD bits long, we can obtain its length and\n   * the corresponding symbol directly from these tables.\n   */\n  int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */\n  UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */\n} d_derived_tbl;\n\n\n/*\n * Fetching the next N bits from the input stream is a time-critical operation\n * for the Huffman decoders.  We implement it with a combination of inline\n * macros and out-of-line subroutines.  Note that N (the number of bits\n * demanded at one time) never exceeds 15 for JPEG use.\n *\n * We read source bytes into get_buffer and dole out bits as needed.\n * If get_buffer already contains enough bits, they are fetched in-line\n * by the macros CHECK_BIT_BUFFER and GET_BITS.  When there aren't enough\n * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer\n * as full as possible (not just to the number of bits needed; this\n * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).\n * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.\n * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains\n * at least the requested number of bits --- dummy zeroes are inserted if\n * necessary.\n */\n\ntypedef INT32 bit_buf_type;\t/* type of bit-extraction buffer */\n#define BIT_BUF_SIZE  32\t/* size of buffer in bits */\n\n/* If long is > 32 bits on your machine, and shifting/masking longs is\n * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE\n * appropriately should be a win.  Unfortunately we can't define the size\n * with something like  #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)\n * because not all machines measure sizeof in 8-bit bytes.\n */\n\ntypedef struct {\t\t/* Bitreading state saved across MCUs */\n  bit_buf_type get_buffer;\t/* current bit-extraction buffer */\n  int bits_left;\t\t/* # of unused bits in it */\n} bitread_perm_state;\n\ntypedef struct {\t\t/* Bitreading working state within an MCU */\n  /* Current data source location */\n  /* We need a copy, rather than munging the original, in case of suspension */\n  const JOCTET * next_input_byte; /* => next byte to read from source */\n  size_t bytes_in_buffer;\t/* # of bytes remaining in source buffer */\n  /* Bit input buffer --- note these values are kept in register variables,\n   * not in this struct, inside the inner loops.\n   */\n  bit_buf_type get_buffer;\t/* current bit-extraction buffer */\n  int bits_left;\t\t/* # of unused bits in it */\n  /* Pointer needed by jpeg_fill_bit_buffer. */\n  j_decompress_ptr cinfo;\t/* back link to decompress master record */\n} bitread_working_state;\n\n/* Macros to declare and load/save bitread local variables. */\n#define BITREAD_STATE_VARS  \\\n\tregister bit_buf_type get_buffer;  \\\n\tregister int bits_left;  \\\n\tbitread_working_state br_state\n\n#define BITREAD_LOAD_STATE(cinfop,permstate)  \\\n\tbr_state.cinfo = cinfop; \\\n\tbr_state.next_input_byte = cinfop->src->next_input_byte; \\\n\tbr_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \\\n\tget_buffer = permstate.get_buffer; \\\n\tbits_left = permstate.bits_left;\n\n#define BITREAD_SAVE_STATE(cinfop,permstate)  \\\n\tcinfop->src->next_input_byte = br_state.next_input_byte; \\\n\tcinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \\\n\tpermstate.get_buffer = get_buffer; \\\n\tpermstate.bits_left = bits_left\n\n/*\n * These macros provide the in-line portion of bit fetching.\n * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer\n * before using GET_BITS, PEEK_BITS, or DROP_BITS.\n * The variables get_buffer and bits_left are assumed to be locals,\n * but the state struct might not be (jpeg_huff_decode needs this).\n *\tCHECK_BIT_BUFFER(state,n,action);\n *\t\tEnsure there are N bits in get_buffer; if suspend, take action.\n *      val = GET_BITS(n);\n *\t\tFetch next N bits.\n *      val = PEEK_BITS(n);\n *\t\tFetch next N bits without removing them from the buffer.\n *\tDROP_BITS(n);\n *\t\tDiscard next N bits.\n * The value N should be a simple variable, not an expression, because it\n * is evaluated multiple times.\n */\n\n#define CHECK_BIT_BUFFER(state,nbits,action) \\\n\t{ if (bits_left < (nbits)) {  \\\n\t    if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits))  \\\n\t      { action; }  \\\n\t    get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }\n\n#define GET_BITS(nbits) \\\n\t(((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits))\n\n#define PEEK_BITS(nbits) \\\n\t(((int) (get_buffer >> (bits_left -  (nbits)))) & BIT_MASK(nbits))\n\n#define DROP_BITS(nbits) \\\n\t(bits_left -= (nbits))\n\n\n/*\n * Code for extracting next Huffman-coded symbol from input bit stream.\n * Again, this is time-critical and we make the main paths be macros.\n *\n * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits\n * without looping.  Usually, more than 95% of the Huffman codes will be 8\n * or fewer bits long.  The few overlength codes are handled with a loop,\n * which need not be inline code.\n *\n * Notes about the HUFF_DECODE macro:\n * 1. Near the end of the data segment, we may fail to get enough bits\n *    for a lookahead.  In that case, we do it the hard way.\n * 2. If the lookahead table contains no entry, the next code must be\n *    more than HUFF_LOOKAHEAD bits long.\n * 3. jpeg_huff_decode returns -1 if forced to suspend.\n */\n\n#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \\\n{ register int nb, look; \\\n  if (bits_left < HUFF_LOOKAHEAD) { \\\n    if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \\\n    get_buffer = state.get_buffer; bits_left = state.bits_left; \\\n    if (bits_left < HUFF_LOOKAHEAD) { \\\n      nb = 1; goto slowlabel; \\\n    } \\\n  } \\\n  look = PEEK_BITS(HUFF_LOOKAHEAD); \\\n  if ((nb = htbl->look_nbits[look]) != 0) { \\\n    DROP_BITS(nb); \\\n    result = htbl->look_sym[look]; \\\n  } else { \\\n    nb = HUFF_LOOKAHEAD+1; \\\nslowlabel: \\\n    if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \\\n\t{ failaction; } \\\n    get_buffer = state.get_buffer; bits_left = state.bits_left; \\\n  } \\\n}\n\n\n/*\n * Expanded entropy decoder object for Huffman decoding.\n *\n * The savable_state subrecord contains fields that change within an MCU,\n * but must not be updated permanently until we complete the MCU.\n */\n\ntypedef struct {\n  unsigned int EOBRUN;\t\t\t/* remaining EOBs in EOBRUN */\n  int last_dc_val[MAX_COMPS_IN_SCAN];\t/* last DC coef for each component */\n} savable_state;\n\n/* This macro is to work around compilers with missing or broken\n * structure assignment.  You'll need to fix this code if you have\n * such a compiler and you change MAX_COMPS_IN_SCAN.\n */\n\n#ifndef NO_STRUCT_ASSIGN\n#define ASSIGN_STATE(dest,src)  ((dest) = (src))\n#else\n#if MAX_COMPS_IN_SCAN == 4\n#define ASSIGN_STATE(dest,src)  \\\n\t((dest).EOBRUN = (src).EOBRUN, \\\n\t (dest).last_dc_val[0] = (src).last_dc_val[0], \\\n\t (dest).last_dc_val[1] = (src).last_dc_val[1], \\\n\t (dest).last_dc_val[2] = (src).last_dc_val[2], \\\n\t (dest).last_dc_val[3] = (src).last_dc_val[3])\n#endif\n#endif\n\n\ntypedef struct {\n  struct jpeg_entropy_decoder pub; /* public fields */\n\n  /* These fields are loaded into local variables at start of each MCU.\n   * In case of suspension, we exit WITHOUT updating them.\n   */\n  bitread_perm_state bitstate;\t/* Bit buffer at start of MCU */\n  savable_state saved;\t\t/* Other state at start of MCU */\n\n  /* These fields are NOT loaded into local working state. */\n  boolean insufficient_data;\t/* set TRUE after emitting warning */\n  unsigned int restarts_to_go;\t/* MCUs left in this restart interval */\n\n  /* Following two fields used only in progressive mode */\n\n  /* Pointers to derived tables (these workspaces have image lifespan) */\n  d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];\n\n  d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */\n\n  /* Following fields used only in sequential mode */\n\n  /* Pointers to derived tables (these workspaces have image lifespan) */\n  d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];\n  d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];\n\n  /* Precalculated info set up by start_pass for use in decode_mcu: */\n\n  /* Pointers to derived tables to be used for each block within an MCU */\n  d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];\n  d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];\n  /* Whether we care about the DC and AC coefficient values for each block */\n  int coef_limit[D_MAX_BLOCKS_IN_MCU];\n} huff_entropy_decoder;\n\ntypedef huff_entropy_decoder * huff_entropy_ptr;\n\n\nstatic const int jpeg_zigzag_order[8][8] = {\n  {  0,  1,  5,  6, 14, 15, 27, 28 },\n  {  2,  4,  7, 13, 16, 26, 29, 42 },\n  {  3,  8, 12, 17, 25, 30, 41, 43 },\n  {  9, 11, 18, 24, 31, 40, 44, 53 },\n  { 10, 19, 23, 32, 39, 45, 52, 54 },\n  { 20, 22, 33, 38, 46, 51, 55, 60 },\n  { 21, 34, 37, 47, 50, 56, 59, 61 },\n  { 35, 36, 48, 49, 57, 58, 62, 63 }\n};\n\nstatic const int jpeg_zigzag_order7[7][7] = {\n  {  0,  1,  5,  6, 14, 15, 27 },\n  {  2,  4,  7, 13, 16, 26, 28 },\n  {  3,  8, 12, 17, 25, 29, 38 },\n  {  9, 11, 18, 24, 30, 37, 39 },\n  { 10, 19, 23, 31, 36, 40, 45 },\n  { 20, 22, 32, 35, 41, 44, 46 },\n  { 21, 33, 34, 42, 43, 47, 48 }\n};\n\nstatic const int jpeg_zigzag_order6[6][6] = {\n  {  0,  1,  5,  6, 14, 15 },\n  {  2,  4,  7, 13, 16, 25 },\n  {  3,  8, 12, 17, 24, 26 },\n  {  9, 11, 18, 23, 27, 32 },\n  { 10, 19, 22, 28, 31, 33 },\n  { 20, 21, 29, 30, 34, 35 }\n};\n\nstatic const int jpeg_zigzag_order5[5][5] = {\n  {  0,  1,  5,  6, 14 },\n  {  2,  4,  7, 13, 15 },\n  {  3,  8, 12, 16, 21 },\n  {  9, 11, 17, 20, 22 },\n  { 10, 18, 19, 23, 24 }\n};\n\nstatic const int jpeg_zigzag_order4[4][4] = {\n  { 0,  1,  5,  6 },\n  { 2,  4,  7, 12 },\n  { 3,  8, 11, 13 },\n  { 9, 10, 14, 15 }\n};\n\nstatic const int jpeg_zigzag_order3[3][3] = {\n  { 0, 1, 5 },\n  { 2, 4, 6 },\n  { 3, 7, 8 }\n};\n\nstatic const int jpeg_zigzag_order2[2][2] = {\n  { 0, 1 },\n  { 2, 3 }\n};\n\n\n/*\n * Compute the derived values for a Huffman table.\n * This routine also performs some validation checks on the table.\n */\n\nLOCAL(void)\njpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,\n\t\t\t d_derived_tbl ** pdtbl)\n{\n  JHUFF_TBL *htbl;\n  d_derived_tbl *dtbl;\n  int p, i, l, si, numsymbols;\n  int lookbits, ctr;\n  char huffsize[257];\n  unsigned int huffcode[257];\n  unsigned int code;\n\n  /* Note that huffsize[] and huffcode[] are filled in code-length order,\n   * paralleling the order of the symbols themselves in htbl->huffval[].\n   */\n\n  /* Find the input Huffman table */\n  if (tblno < 0 || tblno >= NUM_HUFF_TBLS)\n    ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);\n  htbl =\n    isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];\n  if (htbl == NULL)\n    htbl = jpeg_std_huff_table((j_common_ptr) cinfo, isDC, tblno);\n\n  /* Allocate a workspace if we haven't already done so. */\n  if (*pdtbl == NULL)\n    *pdtbl = (d_derived_tbl *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(d_derived_tbl));\n  dtbl = *pdtbl;\n  dtbl->pub = htbl;\t\t/* fill in back link */\n  \n  /* Figure C.1: make table of Huffman code length for each symbol */\n\n  p = 0;\n  for (l = 1; l <= 16; l++) {\n    i = (int) htbl->bits[l];\n    if (i < 0 || p + i > 256)\t/* protect against table overrun */\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    while (i--)\n      huffsize[p++] = (char) l;\n  }\n  huffsize[p] = 0;\n  numsymbols = p;\n  \n  /* Figure C.2: generate the codes themselves */\n  /* We also validate that the counts represent a legal Huffman code tree. */\n  \n  code = 0;\n  si = huffsize[0];\n  p = 0;\n  while (huffsize[p]) {\n    while (((int) huffsize[p]) == si) {\n      huffcode[p++] = code;\n      code++;\n    }\n    /* code is now 1 more than the last code used for codelength si; but\n     * it must still fit in si bits, since no code is allowed to be all ones.\n     */\n    if (((INT32) code) >= (((INT32) 1) << si))\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    code <<= 1;\n    si++;\n  }\n\n  /* Figure F.15: generate decoding tables for bit-sequential decoding */\n\n  p = 0;\n  for (l = 1; l <= 16; l++) {\n    if (htbl->bits[l]) {\n      /* valoffset[l] = huffval[] index of 1st symbol of code length l,\n       * minus the minimum code of length l\n       */\n      dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];\n      p += htbl->bits[l];\n      dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */\n    } else {\n      dtbl->maxcode[l] = -1;\t/* -1 if no codes of this length */\n    }\n  }\n  dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */\n\n  /* Compute lookahead tables to speed up decoding.\n   * First we set all the table entries to 0, indicating \"too long\";\n   * then we iterate through the Huffman codes that are short enough and\n   * fill in all the entries that correspond to bit sequences starting\n   * with that code.\n   */\n\n  MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));\n\n  p = 0;\n  for (l = 1; l <= HUFF_LOOKAHEAD; l++) {\n    for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {\n      /* l = current code's length, p = its index in huffcode[] & huffval[]. */\n      /* Generate left-justified code followed by all possible bit sequences */\n      lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);\n      for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {\n\tdtbl->look_nbits[lookbits] = l;\n\tdtbl->look_sym[lookbits] = htbl->huffval[p];\n\tlookbits++;\n      }\n    }\n  }\n\n  /* Validate symbols as being reasonable.\n   * For AC tables, we make no check, but accept all byte values 0..255.\n   * For DC tables, we require the symbols to be in range 0..15.\n   * (Tighter bounds could be applied depending on the data depth and mode,\n   * but this is sufficient to ensure safe decoding.)\n   */\n  if (isDC) {\n    for (i = 0; i < numsymbols; i++) {\n      int sym = htbl->huffval[i];\n      if (sym < 0 || sym > 15)\n\tERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n    }\n  }\n}\n\n\n/*\n * Out-of-line code for bit fetching.\n * Note: current values of get_buffer and bits_left are passed as parameters,\n * but are returned in the corresponding fields of the state struct.\n *\n * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width\n * of get_buffer to be used.  (On machines with wider words, an even larger\n * buffer could be used.)  However, on some machines 32-bit shifts are\n * quite slow and take time proportional to the number of places shifted.\n * (This is true with most PC compilers, for instance.)  In this case it may\n * be a win to set MIN_GET_BITS to the minimum value of 15.  This reduces the\n * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.\n */\n\n#ifdef SLOW_SHIFT_32\n#define MIN_GET_BITS  15\t/* minimum allowable value */\n#else\n#define MIN_GET_BITS  (BIT_BUF_SIZE-7)\n#endif\n\n\nLOCAL(boolean)\njpeg_fill_bit_buffer (bitread_working_state * state,\n\t\t      register bit_buf_type get_buffer, register int bits_left,\n\t\t      int nbits)\n/* Load up the bit buffer to a depth of at least nbits */\n{\n  /* Copy heavily used state fields into locals (hopefully registers) */\n  register const JOCTET * next_input_byte = state->next_input_byte;\n  register size_t bytes_in_buffer = state->bytes_in_buffer;\n  j_decompress_ptr cinfo = state->cinfo;\n\n  /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */\n  /* (It is assumed that no request will be for more than that many bits.) */\n  /* We fail to do so only if we hit a marker or are forced to suspend. */\n\n  if (cinfo->unread_marker == 0) {\t/* cannot advance past a marker */\n    while (bits_left < MIN_GET_BITS) {\n      register int c;\n\n      /* Attempt to read a byte */\n      if (bytes_in_buffer == 0) {\n\tif (! (*cinfo->src->fill_input_buffer) (cinfo))\n\t  return FALSE;\n\tnext_input_byte = cinfo->src->next_input_byte;\n\tbytes_in_buffer = cinfo->src->bytes_in_buffer;\n      }\n      bytes_in_buffer--;\n      c = GETJOCTET(*next_input_byte++);\n\n      /* If it's 0xFF, check and discard stuffed zero byte */\n      if (c == 0xFF) {\n\t/* Loop here to discard any padding FF's on terminating marker,\n\t * so that we can save a valid unread_marker value.  NOTE: we will\n\t * accept multiple FF's followed by a 0 as meaning a single FF data\n\t * byte.  This data pattern is not valid according to the standard.\n\t */\n\tdo {\n\t  if (bytes_in_buffer == 0) {\n\t    if (! (*cinfo->src->fill_input_buffer) (cinfo))\n\t      return FALSE;\n\t    next_input_byte = cinfo->src->next_input_byte;\n\t    bytes_in_buffer = cinfo->src->bytes_in_buffer;\n\t  }\n\t  bytes_in_buffer--;\n\t  c = GETJOCTET(*next_input_byte++);\n\t} while (c == 0xFF);\n\n\tif (c == 0) {\n\t  /* Found FF/00, which represents an FF data byte */\n\t  c = 0xFF;\n\t} else {\n\t  /* Oops, it's actually a marker indicating end of compressed data.\n\t   * Save the marker code for later use.\n\t   * Fine point: it might appear that we should save the marker into\n\t   * bitread working state, not straight into permanent state.  But\n\t   * once we have hit a marker, we cannot need to suspend within the\n\t   * current MCU, because we will read no more bytes from the data\n\t   * source.  So it is OK to update permanent state right away.\n\t   */\n\t  cinfo->unread_marker = c;\n\t  /* See if we need to insert some fake zero bits. */\n\t  goto no_more_bytes;\n\t}\n      }\n\n      /* OK, load c into get_buffer */\n      get_buffer = (get_buffer << 8) | c;\n      bits_left += 8;\n    } /* end while */\n  } else {\n  no_more_bytes:\n    /* We get here if we've read the marker that terminates the compressed\n     * data segment.  There should be enough bits in the buffer register\n     * to satisfy the request; if so, no problem.\n     */\n    if (nbits > bits_left) {\n      /* Uh-oh.  Report corrupted data to user and stuff zeroes into\n       * the data stream, so that we can produce some kind of image.\n       * We use a nonvolatile flag to ensure that only one warning message\n       * appears per data segment.\n       */\n      if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) {\n\tWARNMS(cinfo, JWRN_HIT_MARKER);\n\t((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE;\n      }\n      /* Fill the buffer with zero bits */\n      get_buffer <<= MIN_GET_BITS - bits_left;\n      bits_left = MIN_GET_BITS;\n    }\n  }\n\n  /* Unload the local registers */\n  state->next_input_byte = next_input_byte;\n  state->bytes_in_buffer = bytes_in_buffer;\n  state->get_buffer = get_buffer;\n  state->bits_left = bits_left;\n\n  return TRUE;\n}\n\n\n/*\n * Figure F.12: extend sign bit.\n * On some machines, a shift and sub will be faster than a table lookup.\n */\n\n#ifdef AVOID_TABLES\n\n#define BIT_MASK(nbits)   ((1<<(nbits))-1)\n#define HUFF_EXTEND(x,s)  ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x))\n\n#else\n\n#define BIT_MASK(nbits)   bmask[nbits]\n#define HUFF_EXTEND(x,s)  ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x))\n\nstatic const int bmask[16] =\t/* bmask[n] is mask for n rightmost bits */\n  { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,\n    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };\n\n#endif /* AVOID_TABLES */\n\n\n/*\n * Out-of-line code for Huffman code decoding.\n */\n\nLOCAL(int)\njpeg_huff_decode (bitread_working_state * state,\n\t\t  register bit_buf_type get_buffer, register int bits_left,\n\t\t  d_derived_tbl * htbl, int min_bits)\n{\n  register int l = min_bits;\n  register INT32 code;\n\n  /* HUFF_DECODE has determined that the code is at least min_bits */\n  /* bits long, so fetch that many bits in one swoop. */\n\n  CHECK_BIT_BUFFER(*state, l, return -1);\n  code = GET_BITS(l);\n\n  /* Collect the rest of the Huffman code one bit at a time. */\n  /* This is per Figure F.16 in the JPEG spec. */\n\n  while (code > htbl->maxcode[l]) {\n    code <<= 1;\n    CHECK_BIT_BUFFER(*state, 1, return -1);\n    code |= GET_BITS(1);\n    l++;\n  }\n\n  /* Unload the local registers */\n  state->get_buffer = get_buffer;\n  state->bits_left = bits_left;\n\n  /* With garbage input we may reach the sentinel value l = 17. */\n\n  if (l > 16) {\n    WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);\n    return 0;\t\t\t/* fake a zero as the safest result */\n  }\n\n  return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];\n}\n\n\n/*\n * Finish up at the end of a Huffman-compressed scan.\n */\n\nMETHODDEF(void)\nfinish_pass_huff (j_decompress_ptr cinfo)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n\n  /* Throw away any unused bits remaining in bit buffer; */\n  /* include any full bytes in next_marker's count of discarded bytes */\n  cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;\n  entropy->bitstate.bits_left = 0;\n}\n\n\n/*\n * Check for a restart marker & resynchronize decoder.\n * Returns FALSE if must suspend.\n */\n\nLOCAL(boolean)\nprocess_restart (j_decompress_ptr cinfo)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int ci;\n\n  finish_pass_huff(cinfo);\n\n  /* Advance past the RSTn marker */\n  if (! (*cinfo->marker->read_restart_marker) (cinfo))\n    return FALSE;\n\n  /* Re-initialize DC predictions to 0 */\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++)\n    entropy->saved.last_dc_val[ci] = 0;\n  /* Re-init EOB run count, too */\n  entropy->saved.EOBRUN = 0;\n\n  /* Reset restart counter */\n  entropy->restarts_to_go = cinfo->restart_interval;\n\n  /* Reset out-of-data flag, unless read_restart_marker left us smack up\n   * against a marker.  In that case we will end up treating the next data\n   * segment as empty, and we can avoid producing bogus output pixels by\n   * leaving the flag set.\n   */\n  if (cinfo->unread_marker == 0)\n    entropy->insufficient_data = FALSE;\n\n  return TRUE;\n}\n\n\n/*\n * Huffman MCU decoding.\n * Each of these routines decodes and returns one MCU's worth of\n * Huffman-compressed coefficients. \n * The coefficients are reordered from zigzag order into natural array order,\n * but are not dequantized.\n *\n * The i'th block of the MCU is stored into the block pointed to by\n * MCU_data[i].  WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.\n * (Wholesale zeroing is usually a little faster than retail...)\n *\n * We return FALSE if data source requested suspension.  In that case no\n * changes have been made to permanent state.  (Exception: some output\n * coefficients may already have been assigned.  This is harmless for\n * spectral selection, since we'll just re-assign them on the next call.\n * Successive approximation AC refinement has to be more careful, however.)\n */\n\n/*\n * MCU decoding for DC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\ndecode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int Al = cinfo->Al;\n  register int s, r;\n  int blkn, ci;\n  JBLOCKROW block;\n  BITREAD_STATE_VARS;\n  savable_state state;\n  d_derived_tbl * tbl;\n  jpeg_component_info * compptr;\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* If we've run out of data, just leave the MCU set to zeroes.\n   * This way, we return uniform gray for the remainder of the segment.\n   */\n  if (! entropy->insufficient_data) {\n\n    /* Load up working state */\n    BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(state, entropy->saved);\n\n    /* Outer loop handles each block in the MCU */\n\n    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n      block = MCU_data[blkn];\n      ci = cinfo->MCU_membership[blkn];\n      compptr = cinfo->cur_comp_info[ci];\n      tbl = entropy->derived_tbls[compptr->dc_tbl_no];\n\n      /* Decode a single block's worth of coefficients */\n\n      /* Section F.2.2.1: decode the DC coefficient difference */\n      HUFF_DECODE(s, br_state, tbl, return FALSE, label1);\n      if (s) {\n\tCHECK_BIT_BUFFER(br_state, s, return FALSE);\n\tr = GET_BITS(s);\n\ts = HUFF_EXTEND(r, s);\n      }\n\n      /* Convert DC difference to actual value, update last_dc_val */\n      s += state.last_dc_val[ci];\n      state.last_dc_val[ci] = s;\n      /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */\n      (*block)[0] = (JCOEF) (s << Al);\n    }\n\n    /* Completed MCU, so update state */\n    BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(entropy->saved, state);\n  }\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for AC initial scan (either spectral selection,\n * or first pass of successive approximation).\n */\n\nMETHODDEF(boolean)\ndecode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  register int s, k, r;\n  unsigned int EOBRUN;\n  int Se, Al;\n  const int * natural_order;\n  JBLOCKROW block;\n  BITREAD_STATE_VARS;\n  d_derived_tbl * tbl;\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* If we've run out of data, just leave the MCU set to zeroes.\n   * This way, we return uniform gray for the remainder of the segment.\n   */\n  if (! entropy->insufficient_data) {\n\n    /* Load up working state.\n     * We can avoid loading/saving bitread state if in an EOB run.\n     */\n    EOBRUN = entropy->saved.EOBRUN;\t/* only part of saved state we need */\n\n    /* There is always only one block per MCU */\n\n    if (EOBRUN)\t\t\t/* if it's a band of zeroes... */\n      EOBRUN--;\t\t\t/* ...process it now (we do nothing) */\n    else {\n      BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n      Se = cinfo->Se;\n      Al = cinfo->Al;\n      natural_order = cinfo->natural_order;\n      block = MCU_data[0];\n      tbl = entropy->ac_derived_tbl;\n\n      for (k = cinfo->Ss; k <= Se; k++) {\n\tHUFF_DECODE(s, br_state, tbl, return FALSE, label2);\n\tr = s >> 4;\n\ts &= 15;\n\tif (s) {\n\t  k += r;\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  r = GET_BITS(s);\n\t  s = HUFF_EXTEND(r, s);\n\t  /* Scale and output coefficient in natural (dezigzagged) order */\n\t  (*block)[natural_order[k]] = (JCOEF) (s << Al);\n\t} else {\n\t  if (r != 15) {\t/* EOBr, run length is 2^r + appended bits */\n\t    if (r) {\t\t/* EOBr, r > 0 */\n\t      EOBRUN = 1 << r;\n\t      CHECK_BIT_BUFFER(br_state, r, return FALSE);\n\t      r = GET_BITS(r);\n\t      EOBRUN += r;\n\t      EOBRUN--;\t\t/* this band is processed at this moment */\n\t    }\n\t    break;\t\t/* force end-of-band */\n\t  }\n\t  k += 15;\t\t/* ZRL: skip 15 zeroes in band */\n\t}\n      }\n\n      BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n    }\n\n    /* Completed MCU, so update state */\n    entropy->saved.EOBRUN = EOBRUN;\t/* only part of saved state we need */\n  }\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for DC successive approximation refinement scan.\n * Note: we assume such scans can be multi-component,\n * although the spec is not very clear on the point.\n */\n\nMETHODDEF(boolean)\ndecode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  JCOEF p1;\n  int blkn;\n  BITREAD_STATE_VARS;\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* Not worth the cycles to check insufficient_data here,\n   * since we will not change the data anyway if we read zeroes.\n   */\n\n  /* Load up working state */\n  BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n\n  p1 = 1 << cinfo->Al;\t\t/* 1 in the bit position being coded */\n\n  /* Outer loop handles each block in the MCU */\n\n  for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n    /* Encoded data is simply the next bit of the two's-complement DC value */\n    CHECK_BIT_BUFFER(br_state, 1, return FALSE);\n    if (GET_BITS(1))\n      MCU_data[blkn][0][0] |= p1;\n    /* Note: since we use |=, repeating the assignment later is safe */\n  }\n\n  /* Completed MCU, so update state */\n  BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n}\n\n\n/*\n * MCU decoding for AC successive approximation refinement scan.\n */\n\nMETHODDEF(boolean)\ndecode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  register int s, k, r;\n  unsigned int EOBRUN;\n  int Se;\n  JCOEF p1, m1;\n  const int * natural_order;\n  JBLOCKROW block;\n  JCOEFPTR thiscoef;\n  BITREAD_STATE_VARS;\n  d_derived_tbl * tbl;\n  int num_newnz;\n  int newnz_pos[DCTSIZE2];\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* If we've run out of data, don't modify the MCU.\n   */\n  if (! entropy->insufficient_data) {\n\n    Se = cinfo->Se;\n    p1 = 1 << cinfo->Al;\t/* 1 in the bit position being coded */\n    m1 = -p1;\t\t\t/* -1 in the bit position being coded */\n    natural_order = cinfo->natural_order;\n\n    /* Load up working state */\n    BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n    EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */\n\n    /* There is always only one block per MCU */\n    block = MCU_data[0];\n    tbl = entropy->ac_derived_tbl;\n\n    /* If we are forced to suspend, we must undo the assignments to any newly\n     * nonzero coefficients in the block, because otherwise we'd get confused\n     * next time about which coefficients were already nonzero.\n     * But we need not undo addition of bits to already-nonzero coefficients;\n     * instead, we can test the current bit to see if we already did it.\n     */\n    num_newnz = 0;\n\n    /* initialize coefficient loop counter to start of band */\n    k = cinfo->Ss;\n\n    if (EOBRUN == 0) {\n      do {\n\tHUFF_DECODE(s, br_state, tbl, goto undoit, label3);\n\tr = s >> 4;\n\ts &= 15;\n\tif (s) {\n\t  if (s != 1)\t\t/* size of new coef should always be 1 */\n\t    WARNMS(cinfo, JWRN_HUFF_BAD_CODE);\n\t  CHECK_BIT_BUFFER(br_state, 1, goto undoit);\n\t  if (GET_BITS(1))\n\t    s = p1;\t\t/* newly nonzero coef is positive */\n\t  else\n\t    s = m1;\t\t/* newly nonzero coef is negative */\n\t} else {\n\t  if (r != 15) {\n\t    EOBRUN = 1 << r;\t/* EOBr, run length is 2^r + appended bits */\n\t    if (r) {\n\t      CHECK_BIT_BUFFER(br_state, r, goto undoit);\n\t      r = GET_BITS(r);\n\t      EOBRUN += r;\n\t    }\n\t    break;\t\t/* rest of block is handled by EOB logic */\n\t  }\n\t  /* note s = 0 for processing ZRL */\n\t}\n\t/* Advance over already-nonzero coefs and r still-zero coefs,\n\t * appending correction bits to the nonzeroes.  A correction bit is 1\n\t * if the absolute value of the coefficient must be increased.\n\t */\n\tdo {\n\t  thiscoef = *block + natural_order[k];\n\t  if (*thiscoef) {\n\t    CHECK_BIT_BUFFER(br_state, 1, goto undoit);\n\t    if (GET_BITS(1)) {\n\t      if ((*thiscoef & p1) == 0) { /* do nothing if already set it */\n\t\tif (*thiscoef >= 0)\n\t\t  *thiscoef += p1;\n\t\telse\n\t\t  *thiscoef += m1;\n\t      }\n\t    }\n\t  } else {\n\t    if (--r < 0)\n\t      break;\t\t/* reached target zero coefficient */\n\t  }\n\t  k++;\n\t} while (k <= Se);\n\tif (s) {\n\t  int pos = natural_order[k];\n\t  /* Output newly nonzero coefficient */\n\t  (*block)[pos] = (JCOEF) s;\n\t  /* Remember its position in case we have to suspend */\n\t  newnz_pos[num_newnz++] = pos;\n\t}\n\tk++;\n      } while (k <= Se);\n    }\n\n    if (EOBRUN) {\n      /* Scan any remaining coefficient positions after the end-of-band\n       * (the last newly nonzero coefficient, if any).  Append a correction\n       * bit to each already-nonzero coefficient.  A correction bit is 1\n       * if the absolute value of the coefficient must be increased.\n       */\n      do {\n\tthiscoef = *block + natural_order[k];\n\tif (*thiscoef) {\n\t  CHECK_BIT_BUFFER(br_state, 1, goto undoit);\n\t  if (GET_BITS(1)) {\n\t    if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */\n\t      if (*thiscoef >= 0)\n\t\t*thiscoef += p1;\n\t      else\n\t\t*thiscoef += m1;\n\t    }\n\t  }\n\t}\n\tk++;\n      } while (k <= Se);\n      /* Count one block completed in EOB run */\n      EOBRUN--;\n    }\n\n    /* Completed MCU, so update state */\n    BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n    entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */\n  }\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n\nundoit:\n  /* Re-zero any output coefficients that we made newly nonzero */\n  while (num_newnz)\n    (*block)[newnz_pos[--num_newnz]] = 0;\n\n  return FALSE;\n}\n\n\n/*\n * Decode one MCU's worth of Huffman-compressed coefficients,\n * partial blocks.\n */\n\nMETHODDEF(boolean)\ndecode_mcu_sub (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  const int * natural_order;\n  int Se, blkn;\n  BITREAD_STATE_VARS;\n  savable_state state;\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* If we've run out of data, just leave the MCU set to zeroes.\n   * This way, we return uniform gray for the remainder of the segment.\n   */\n  if (! entropy->insufficient_data) {\n\n    natural_order = cinfo->natural_order;\n    Se = cinfo->lim_Se;\n\n    /* Load up working state */\n    BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(state, entropy->saved);\n\n    /* Outer loop handles each block in the MCU */\n\n    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n      JBLOCKROW block = MCU_data[blkn];\n      d_derived_tbl * htbl;\n      register int s, k, r;\n      int coef_limit, ci;\n\n      /* Decode a single block's worth of coefficients */\n\n      /* Section F.2.2.1: decode the DC coefficient difference */\n      htbl = entropy->dc_cur_tbls[blkn];\n      HUFF_DECODE(s, br_state, htbl, return FALSE, label1);\n\n      htbl = entropy->ac_cur_tbls[blkn];\n      k = 1;\n      coef_limit = entropy->coef_limit[blkn];\n      if (coef_limit) {\n\t/* Convert DC difference to actual value, update last_dc_val */\n\tif (s) {\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  r = GET_BITS(s);\n\t  s = HUFF_EXTEND(r, s);\n\t}\n\tci = cinfo->MCU_membership[blkn];\n\ts += state.last_dc_val[ci];\n\tstate.last_dc_val[ci] = s;\n\t/* Output the DC coefficient */\n\t(*block)[0] = (JCOEF) s;\n\n\t/* Section F.2.2.2: decode the AC coefficients */\n\t/* Since zeroes are skipped, output area must be cleared beforehand */\n\tfor (; k < coef_limit; k++) {\n\t  HUFF_DECODE(s, br_state, htbl, return FALSE, label2);\n\n\t  r = s >> 4;\n\t  s &= 15;\n\n\t  if (s) {\n\t    k += r;\n\t    CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t    r = GET_BITS(s);\n\t    s = HUFF_EXTEND(r, s);\n\t    /* Output coefficient in natural (dezigzagged) order.\n\t     * Note: the extra entries in natural_order[] will save us\n\t     * if k > Se, which could happen if the data is corrupted.\n\t     */\n\t    (*block)[natural_order[k]] = (JCOEF) s;\n\t  } else {\n\t    if (r != 15)\n\t      goto EndOfBlock;\n\t    k += 15;\n\t  }\n\t}\n      } else {\n\tif (s) {\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  DROP_BITS(s);\n\t}\n      }\n\n      /* Section F.2.2.2: decode the AC coefficients */\n      /* In this path we just discard the values */\n      for (; k <= Se; k++) {\n\tHUFF_DECODE(s, br_state, htbl, return FALSE, label3);\n\n\tr = s >> 4;\n\ts &= 15;\n\n\tif (s) {\n\t  k += r;\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  DROP_BITS(s);\n\t} else {\n\t  if (r != 15)\n\t    break;\n\t  k += 15;\n\t}\n      }\n\n      EndOfBlock: ;\n    }\n\n    /* Completed MCU, so update state */\n    BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(entropy->saved, state);\n  }\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n}\n\n\n/*\n * Decode one MCU's worth of Huffman-compressed coefficients,\n * full-size blocks.\n */\n\nMETHODDEF(boolean)\ndecode_mcu (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int blkn;\n  BITREAD_STATE_VARS;\n  savable_state state;\n\n  /* Process restart marker if needed; may have to suspend */\n  if (cinfo->restart_interval) {\n    if (entropy->restarts_to_go == 0)\n      if (! process_restart(cinfo))\n\treturn FALSE;\n  }\n\n  /* If we've run out of data, just leave the MCU set to zeroes.\n   * This way, we return uniform gray for the remainder of the segment.\n   */\n  if (! entropy->insufficient_data) {\n\n    /* Load up working state */\n    BITREAD_LOAD_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(state, entropy->saved);\n\n    /* Outer loop handles each block in the MCU */\n\n    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n      JBLOCKROW block = MCU_data[blkn];\n      d_derived_tbl * htbl;\n      register int s, k, r;\n      int coef_limit, ci;\n\n      /* Decode a single block's worth of coefficients */\n\n      /* Section F.2.2.1: decode the DC coefficient difference */\n      htbl = entropy->dc_cur_tbls[blkn];\n      HUFF_DECODE(s, br_state, htbl, return FALSE, label1);\n\n      htbl = entropy->ac_cur_tbls[blkn];\n      k = 1;\n      coef_limit = entropy->coef_limit[blkn];\n      if (coef_limit) {\n\t/* Convert DC difference to actual value, update last_dc_val */\n\tif (s) {\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  r = GET_BITS(s);\n\t  s = HUFF_EXTEND(r, s);\n\t}\n\tci = cinfo->MCU_membership[blkn];\n\ts += state.last_dc_val[ci];\n\tstate.last_dc_val[ci] = s;\n\t/* Output the DC coefficient */\n\t(*block)[0] = (JCOEF) s;\n\n\t/* Section F.2.2.2: decode the AC coefficients */\n\t/* Since zeroes are skipped, output area must be cleared beforehand */\n\tfor (; k < coef_limit; k++) {\n\t  HUFF_DECODE(s, br_state, htbl, return FALSE, label2);\n\n\t  r = s >> 4;\n\t  s &= 15;\n\n\t  if (s) {\n\t    k += r;\n\t    CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t    r = GET_BITS(s);\n\t    s = HUFF_EXTEND(r, s);\n\t    /* Output coefficient in natural (dezigzagged) order.\n\t     * Note: the extra entries in jpeg_natural_order[] will save us\n\t     * if k >= DCTSIZE2, which could happen if the data is corrupted.\n\t     */\n\t    (*block)[jpeg_natural_order[k]] = (JCOEF) s;\n\t  } else {\n\t    if (r != 15)\n\t      goto EndOfBlock;\n\t    k += 15;\n\t  }\n\t}\n      } else {\n\tif (s) {\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  DROP_BITS(s);\n\t}\n      }\n\n      /* Section F.2.2.2: decode the AC coefficients */\n      /* In this path we just discard the values */\n      for (; k < DCTSIZE2; k++) {\n\tHUFF_DECODE(s, br_state, htbl, return FALSE, label3);\n\n\tr = s >> 4;\n\ts &= 15;\n\n\tif (s) {\n\t  k += r;\n\t  CHECK_BIT_BUFFER(br_state, s, return FALSE);\n\t  DROP_BITS(s);\n\t} else {\n\t  if (r != 15)\n\t    break;\n\t  k += 15;\n\t}\n      }\n\n      EndOfBlock: ;\n    }\n\n    /* Completed MCU, so update state */\n    BITREAD_SAVE_STATE(cinfo, entropy->bitstate);\n    ASSIGN_STATE(entropy->saved, state);\n  }\n\n  /* Account for restart interval if using restarts */\n  if (cinfo->restart_interval)\n    entropy->restarts_to_go--;\n\n  return TRUE;\n}\n\n\n/*\n * Initialize for a Huffman-compressed scan.\n */\n\nMETHODDEF(void)\nstart_pass_huff_decoder (j_decompress_ptr cinfo)\n{\n  huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;\n  int ci, blkn, tbl, i;\n  jpeg_component_info * compptr;\n\n  if (cinfo->progressive_mode) {\n    /* Validate progressive scan parameters */\n    if (cinfo->Ss == 0) {\n      if (cinfo->Se != 0)\n\tgoto bad;\n    } else {\n      /* need not check Ss/Se < 0 since they came from unsigned bytes */\n      if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)\n\tgoto bad;\n      /* AC scans may have only one component */\n      if (cinfo->comps_in_scan != 1)\n\tgoto bad;\n    }\n    if (cinfo->Ah != 0) {\n      /* Successive approximation refinement scan: must have Al = Ah-1. */\n      if (cinfo->Ah-1 != cinfo->Al)\n\tgoto bad;\n    }\n    if (cinfo->Al > 13) {\t/* need not check for < 0 */\n      /* Arguably the maximum Al value should be less than 13 for 8-bit\n       * precision, but the spec doesn't say so, and we try to be liberal\n       * about what we accept.  Note: large Al values could result in\n       * out-of-range DC coefficients during early scans, leading to bizarre\n       * displays due to overflows in the IDCT math.  But we won't crash.\n       */\n      bad:\n      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,\n\t       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);\n    }\n    /* Update progression status, and verify that scan order is legal.\n     * Note that inter-scan inconsistencies are treated as warnings\n     * not fatal errors ... not clear if this is right way to behave.\n     */\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;\n      int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];\n      if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */\n\tWARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);\n      for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {\n\tint expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];\n\tif (cinfo->Ah != expected)\n\t  WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);\n\tcoef_bit_ptr[coefi] = cinfo->Al;\n      }\n    }\n\n    /* Select MCU decoding routine */\n    if (cinfo->Ah == 0) {\n      if (cinfo->Ss == 0)\n\tentropy->pub.decode_mcu = decode_mcu_DC_first;\n      else\n\tentropy->pub.decode_mcu = decode_mcu_AC_first;\n    } else {\n      if (cinfo->Ss == 0)\n\tentropy->pub.decode_mcu = decode_mcu_DC_refine;\n      else\n\tentropy->pub.decode_mcu = decode_mcu_AC_refine;\n    }\n\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      compptr = cinfo->cur_comp_info[ci];\n      /* Make sure requested tables are present, and compute derived tables.\n       * We may build same derived table more than once, but it's not expensive.\n       */\n      if (cinfo->Ss == 0) {\n\tif (cinfo->Ah == 0) {\t/* DC refinement needs no table */\n\t  tbl = compptr->dc_tbl_no;\n\t  jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,\n\t\t\t\t  & entropy->derived_tbls[tbl]);\n\t}\n      } else {\n\ttbl = compptr->ac_tbl_no;\n\tjpeg_make_d_derived_tbl(cinfo, FALSE, tbl,\n\t\t\t\t& entropy->derived_tbls[tbl]);\n\t/* remember the single active table */\n\tentropy->ac_derived_tbl = entropy->derived_tbls[tbl];\n      }\n      /* Initialize DC predictions to 0 */\n      entropy->saved.last_dc_val[ci] = 0;\n    }\n\n    /* Initialize private state variables */\n    entropy->saved.EOBRUN = 0;\n  } else {\n    /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.\n     * This ought to be an error condition, but we make it a warning because\n     * there are some baseline files out there with all zeroes in these bytes.\n     */\n    if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||\n\t((cinfo->is_baseline || cinfo->Se < DCTSIZE2) &&\n\tcinfo->Se != cinfo->lim_Se))\n      WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);\n\n    /* Select MCU decoding routine */\n    /* We retain the hard-coded case for full-size blocks.\n     * This is not necessary, but it appears that this version is slightly\n     * more performant in the given implementation.\n     * With an improved implementation we would prefer a single optimized\n     * function.\n     */\n    if (cinfo->lim_Se != DCTSIZE2-1)\n      entropy->pub.decode_mcu = decode_mcu_sub;\n    else\n      entropy->pub.decode_mcu = decode_mcu;\n\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      compptr = cinfo->cur_comp_info[ci];\n      /* Compute derived values for Huffman tables */\n      /* We may do this more than once for a table, but it's not expensive */\n      tbl = compptr->dc_tbl_no;\n      jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,\n\t\t\t      & entropy->dc_derived_tbls[tbl]);\n      if (cinfo->lim_Se) {\t/* AC needs no table when not present */\n\ttbl = compptr->ac_tbl_no;\n\tjpeg_make_d_derived_tbl(cinfo, FALSE, tbl,\n\t\t\t\t& entropy->ac_derived_tbls[tbl]);\n      }\n      /* Initialize DC predictions to 0 */\n      entropy->saved.last_dc_val[ci] = 0;\n    }\n\n    /* Precalculate decoding info for each block in an MCU of this scan */\n    for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {\n      ci = cinfo->MCU_membership[blkn];\n      compptr = cinfo->cur_comp_info[ci];\n      /* Precalculate which table to use for each block */\n      entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];\n      entropy->ac_cur_tbls[blkn] =\t/* AC needs no table when not present */\n\tcinfo->lim_Se ? entropy->ac_derived_tbls[compptr->ac_tbl_no] : NULL;\n      /* Decide whether we really care about the coefficient values */\n      if (compptr->component_needed) {\n\tci = compptr->DCT_v_scaled_size;\n\ti = compptr->DCT_h_scaled_size;\n\tswitch (cinfo->lim_Se) {\n\tcase (1*1-1):\n\t  entropy->coef_limit[blkn] = 1;\n\t  break;\n\tcase (2*2-1):\n\t  if (ci <= 0 || ci > 2) ci = 2;\n\t  if (i <= 0 || i > 2) i = 2;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1];\n\t  break;\n\tcase (3*3-1):\n\t  if (ci <= 0 || ci > 3) ci = 3;\n\t  if (i <= 0 || i > 3) i = 3;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1];\n\t  break;\n\tcase (4*4-1):\n\t  if (ci <= 0 || ci > 4) ci = 4;\n\t  if (i <= 0 || i > 4) i = 4;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1];\n\t  break;\n\tcase (5*5-1):\n\t  if (ci <= 0 || ci > 5) ci = 5;\n\t  if (i <= 0 || i > 5) i = 5;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1];\n\t  break;\n\tcase (6*6-1):\n\t  if (ci <= 0 || ci > 6) ci = 6;\n\t  if (i <= 0 || i > 6) i = 6;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1];\n\t  break;\n\tcase (7*7-1):\n\t  if (ci <= 0 || ci > 7) ci = 7;\n\t  if (i <= 0 || i > 7) i = 7;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1];\n\t  break;\n\tdefault:\n\t  if (ci <= 0 || ci > 8) ci = 8;\n\t  if (i <= 0 || i > 8) i = 8;\n\t  entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1];\n\t}\n      } else {\n\tentropy->coef_limit[blkn] = 0;\n      }\n    }\n  }\n\n  /* Initialize bitread state variables */\n  entropy->bitstate.bits_left = 0;\n  entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */\n  entropy->insufficient_data = FALSE;\n\n  /* Initialize restart counter */\n  entropy->restarts_to_go = cinfo->restart_interval;\n}\n\n\n/*\n * Module initialization routine for Huffman entropy decoding.\n */\n\nGLOBAL(void)\njinit_huff_decoder (j_decompress_ptr cinfo)\n{\n  huff_entropy_ptr entropy;\n  int i;\n\n  entropy = (huff_entropy_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(huff_entropy_decoder));\n  cinfo->entropy = &entropy->pub;\n  entropy->pub.start_pass = start_pass_huff_decoder;\n  entropy->pub.finish_pass = finish_pass_huff;\n\n  if (cinfo->progressive_mode) {\n    /* Create progression status table */\n    int *coef_bit_ptr, ci;\n    cinfo->coef_bits = (int (*)[DCTSIZE2]) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       cinfo->num_components * DCTSIZE2 * SIZEOF(int));\n    coef_bit_ptr = & cinfo->coef_bits[0][0];\n    for (ci = 0; ci < cinfo->num_components; ci++)\n      for (i = 0; i < DCTSIZE2; i++)\n\t*coef_bit_ptr++ = -1;\n\n    /* Mark derived tables unallocated */\n    for (i = 0; i < NUM_HUFF_TBLS; i++) {\n      entropy->derived_tbls[i] = NULL;\n    }\n  } else {\n    /* Mark derived tables unallocated */\n    for (i = 0; i < NUM_HUFF_TBLS; i++) {\n      entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;\n    }\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdinput.c",
    "content": "/*\n * jdinput.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains input control logic for the JPEG decompressor.\n * These routines are concerned with controlling the decompressor's input\n * processing (marker reading and coefficient decoding).  The actual input\n * reading is done in jdmarker.c, jdhuff.c, and jdarith.c.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Private state */\n\ntypedef struct {\n  struct jpeg_input_controller pub; /* public fields */\n\n  int inheaders;\t\t/* Nonzero until first SOS is reached */\n} my_input_controller;\n\ntypedef my_input_controller * my_inputctl_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));\n\n\n/*\n * Routines to calculate various quantities related to the size of the image.\n */\n\n\n/*\n * Compute output image dimensions and related values.\n * NOTE: this is exported for possible use by application.\n * Hence it mustn't do anything that can't be done twice.\n */\n\nGLOBAL(void)\njpeg_core_output_dimensions (j_decompress_ptr cinfo)\n/* Do computations that are needed before master selection phase.\n * This function is used for transcoding and full decompression.\n */\n{\n#ifdef IDCT_SCALING_SUPPORTED\n  int ci;\n  jpeg_component_info *compptr;\n\n  /* Compute actual output image dimensions and DCT scaling choices. */\n  if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) {\n    /* Provide 1/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 1;\n    cinfo->min_DCT_v_scaled_size = 1;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) {\n    /* Provide 2/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 2;\n    cinfo->min_DCT_v_scaled_size = 2;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) {\n    /* Provide 3/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 3;\n    cinfo->min_DCT_v_scaled_size = 3;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) {\n    /* Provide 4/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 4;\n    cinfo->min_DCT_v_scaled_size = 4;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) {\n    /* Provide 5/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 5;\n    cinfo->min_DCT_v_scaled_size = 5;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) {\n    /* Provide 6/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 6;\n    cinfo->min_DCT_v_scaled_size = 6;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) {\n    /* Provide 7/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 7;\n    cinfo->min_DCT_v_scaled_size = 7;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) {\n    /* Provide 8/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 8;\n    cinfo->min_DCT_v_scaled_size = 8;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) {\n    /* Provide 9/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 9;\n    cinfo->min_DCT_v_scaled_size = 9;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) {\n    /* Provide 10/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 10;\n    cinfo->min_DCT_v_scaled_size = 10;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) {\n    /* Provide 11/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 11;\n    cinfo->min_DCT_v_scaled_size = 11;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) {\n    /* Provide 12/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 12;\n    cinfo->min_DCT_v_scaled_size = 12;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) {\n    /* Provide 13/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 13;\n    cinfo->min_DCT_v_scaled_size = 13;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) {\n    /* Provide 14/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 14;\n    cinfo->min_DCT_v_scaled_size = 14;\n  } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) {\n    /* Provide 15/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 15;\n    cinfo->min_DCT_v_scaled_size = 15;\n  } else {\n    /* Provide 16/block_size scaling */\n    cinfo->output_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size);\n    cinfo->output_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size);\n    cinfo->min_DCT_h_scaled_size = 16;\n    cinfo->min_DCT_v_scaled_size = 16;\n  }\n\n  /* Recompute dimensions of components */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size;\n    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size;\n  }\n\n#else /* !IDCT_SCALING_SUPPORTED */\n\n  /* Hardwire it to \"no scaling\" */\n  cinfo->output_width = cinfo->image_width;\n  cinfo->output_height = cinfo->image_height;\n  /* initial_setup has already initialized DCT_scaled_size,\n   * and has computed unscaled downsampled_width and downsampled_height.\n   */\n\n#endif /* IDCT_SCALING_SUPPORTED */\n}\n\n\nLOCAL(void)\ninitial_setup (j_decompress_ptr cinfo)\n/* Called once, when first SOS marker is reached */\n{\n  int ci;\n  jpeg_component_info *compptr;\n\n  /* Make sure image isn't bigger than I can handle */\n  if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||\n      (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)\n    ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);\n\n  /* Only 8 to 12 bits data precision are supported for DCT based JPEG */\n  if (cinfo->data_precision < 8 || cinfo->data_precision > 12)\n    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);\n\n  /* Check that number of components won't exceed internal array sizes */\n  if (cinfo->num_components > MAX_COMPONENTS)\n    ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,\n\t     MAX_COMPONENTS);\n\n  /* Compute maximum sampling factors; check factor validity */\n  cinfo->max_h_samp_factor = 1;\n  cinfo->max_v_samp_factor = 1;\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||\n\tcompptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)\n      ERREXIT(cinfo, JERR_BAD_SAMPLING);\n    cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,\n\t\t\t\t   compptr->h_samp_factor);\n    cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,\n\t\t\t\t   compptr->v_samp_factor);\n  }\n\n  /* Derive block_size, natural_order, and lim_Se */\n  if (cinfo->is_baseline || (cinfo->progressive_mode &&\n      cinfo->comps_in_scan)) { /* no pseudo SOS marker */\n    cinfo->block_size = DCTSIZE;\n    cinfo->natural_order = jpeg_natural_order;\n    cinfo->lim_Se = DCTSIZE2-1;\n  } else\n    switch (cinfo->Se) {\n    case (1*1-1):\n      cinfo->block_size = 1;\n      cinfo->natural_order = jpeg_natural_order; /* not needed */\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (2*2-1):\n      cinfo->block_size = 2;\n      cinfo->natural_order = jpeg_natural_order2;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (3*3-1):\n      cinfo->block_size = 3;\n      cinfo->natural_order = jpeg_natural_order3;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (4*4-1):\n      cinfo->block_size = 4;\n      cinfo->natural_order = jpeg_natural_order4;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (5*5-1):\n      cinfo->block_size = 5;\n      cinfo->natural_order = jpeg_natural_order5;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (6*6-1):\n      cinfo->block_size = 6;\n      cinfo->natural_order = jpeg_natural_order6;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (7*7-1):\n      cinfo->block_size = 7;\n      cinfo->natural_order = jpeg_natural_order7;\n      cinfo->lim_Se = cinfo->Se;\n      break;\n    case (8*8-1):\n      cinfo->block_size = 8;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (9*9-1):\n      cinfo->block_size = 9;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (10*10-1):\n      cinfo->block_size = 10;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (11*11-1):\n      cinfo->block_size = 11;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (12*12-1):\n      cinfo->block_size = 12;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (13*13-1):\n      cinfo->block_size = 13;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (14*14-1):\n      cinfo->block_size = 14;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (15*15-1):\n      cinfo->block_size = 15;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    case (16*16-1):\n      cinfo->block_size = 16;\n      cinfo->natural_order = jpeg_natural_order;\n      cinfo->lim_Se = DCTSIZE2-1;\n      break;\n    default:\n      ERREXIT4(cinfo, JERR_BAD_PROGRESSION,\n\t       cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);\n    }\n\n  /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size.\n   * In the full decompressor,\n   * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c;\n   * but in the transcoder,\n   * jpeg_calc_output_dimensions is not used, so we must do it here.\n   */\n  cinfo->min_DCT_h_scaled_size = cinfo->block_size;\n  cinfo->min_DCT_v_scaled_size = cinfo->block_size;\n\n  /* Compute dimensions of components */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    compptr->DCT_h_scaled_size = cinfo->block_size;\n    compptr->DCT_v_scaled_size = cinfo->block_size;\n    /* Size in DCT blocks */\n    compptr->width_in_blocks = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    compptr->height_in_blocks = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,\n\t\t    (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n    /* downsampled_width and downsampled_height will also be overridden by\n     * jdmaster.c if we are doing full decompression.  The transcoder library\n     * doesn't use these values, but the calling application might.\n     */\n    /* Size in samples */\n    compptr->downsampled_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,\n\t\t    (long) cinfo->max_h_samp_factor);\n    compptr->downsampled_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,\n\t\t    (long) cinfo->max_v_samp_factor);\n    /* Mark component needed, until color conversion says otherwise */\n    compptr->component_needed = TRUE;\n    /* Mark no quantization table yet saved for component */\n    compptr->quant_table = NULL;\n  }\n\n  /* Compute number of fully interleaved MCU rows. */\n  cinfo->total_iMCU_rows = (JDIMENSION)\n    jdiv_round_up((long) cinfo->image_height,\n\t          (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n\n  /* Decide whether file contains multiple scans */\n  if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)\n    cinfo->inputctl->has_multiple_scans = TRUE;\n  else\n    cinfo->inputctl->has_multiple_scans = FALSE;\n}\n\n\nLOCAL(void)\nper_scan_setup (j_decompress_ptr cinfo)\n/* Do computations that are needed before processing a JPEG scan */\n/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */\n{\n  int ci, mcublks, tmp;\n  jpeg_component_info *compptr;\n\n  if (cinfo->comps_in_scan == 1) {\n\n    /* Noninterleaved (single-component) scan */\n    compptr = cinfo->cur_comp_info[0];\n\n    /* Overall image size in MCUs */\n    cinfo->MCUs_per_row = compptr->width_in_blocks;\n    cinfo->MCU_rows_in_scan = compptr->height_in_blocks;\n\n    /* For noninterleaved scan, always one block per MCU */\n    compptr->MCU_width = 1;\n    compptr->MCU_height = 1;\n    compptr->MCU_blocks = 1;\n    compptr->MCU_sample_width = compptr->DCT_h_scaled_size;\n    compptr->last_col_width = 1;\n    /* For noninterleaved scans, it is convenient to define last_row_height\n     * as the number of block rows present in the last iMCU row.\n     */\n    tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);\n    if (tmp == 0) tmp = compptr->v_samp_factor;\n    compptr->last_row_height = tmp;\n\n    /* Prepare array describing MCU composition */\n    cinfo->blocks_in_MCU = 1;\n    cinfo->MCU_membership[0] = 0;\n\n  } else {\n\n    /* Interleaved (multi-component) scan */\n    if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)\n      ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,\n\t       MAX_COMPS_IN_SCAN);\n\n    /* Overall image size in MCUs */\n    cinfo->MCUs_per_row = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width,\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    cinfo->MCU_rows_in_scan = cinfo->total_iMCU_rows;\n\n    cinfo->blocks_in_MCU = 0;\n\n    for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n      compptr = cinfo->cur_comp_info[ci];\n      /* Sampling factors give # of blocks of component in each MCU */\n      compptr->MCU_width = compptr->h_samp_factor;\n      compptr->MCU_height = compptr->v_samp_factor;\n      compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;\n      compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;\n      /* Figure number of non-dummy blocks in last MCU column & row */\n      tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);\n      if (tmp == 0) tmp = compptr->MCU_width;\n      compptr->last_col_width = tmp;\n      tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);\n      if (tmp == 0) tmp = compptr->MCU_height;\n      compptr->last_row_height = tmp;\n      /* Prepare array describing MCU composition */\n      mcublks = compptr->MCU_blocks;\n      if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)\n\tERREXIT(cinfo, JERR_BAD_MCU_SIZE);\n      while (mcublks-- > 0) {\n\tcinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;\n      }\n    }\n\n  }\n}\n\n\n/*\n * Save away a copy of the Q-table referenced by each component present\n * in the current scan, unless already saved during a prior scan.\n *\n * In a multiple-scan JPEG file, the encoder could assign different components\n * the same Q-table slot number, but change table definitions between scans\n * so that each component uses a different Q-table.  (The IJG encoder is not\n * currently capable of doing this, but other encoders might.)  Since we want\n * to be able to dequantize all the components at the end of the file, this\n * means that we have to save away the table actually used for each component.\n * We do this by copying the table at the start of the first scan containing\n * the component.\n * The JPEG spec prohibits the encoder from changing the contents of a Q-table\n * slot between scans of a component using that slot.  If the encoder does so\n * anyway, this decoder will simply use the Q-table values that were current\n * at the start of the first scan for the component.\n *\n * The decompressor output side looks only at the saved quant tables,\n * not at the current Q-table slots.\n */\n\nLOCAL(void)\nlatch_quant_tables (j_decompress_ptr cinfo)\n{\n  int ci, qtblno;\n  jpeg_component_info *compptr;\n  JQUANT_TBL * qtbl;\n\n  for (ci = 0; ci < cinfo->comps_in_scan; ci++) {\n    compptr = cinfo->cur_comp_info[ci];\n    /* No work if we already saved Q-table for this component */\n    if (compptr->quant_table != NULL)\n      continue;\n    /* Make sure specified quantization table is present */\n    qtblno = compptr->quant_tbl_no;\n    if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||\n\tcinfo->quant_tbl_ptrs[qtblno] == NULL)\n      ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);\n    /* OK, save away the quantization table */\n    qtbl = (JQUANT_TBL *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(JQUANT_TBL));\n    MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));\n    compptr->quant_table = qtbl;\n  }\n}\n\n\n/*\n * Initialize the input modules to read a scan of compressed data.\n * The first call to this is done by jdmaster.c after initializing\n * the entire decompressor (during jpeg_start_decompress).\n * Subsequent calls come from consume_markers, below.\n */\n\nMETHODDEF(void)\nstart_input_pass (j_decompress_ptr cinfo)\n{\n  per_scan_setup(cinfo);\n  latch_quant_tables(cinfo);\n  (*cinfo->entropy->start_pass) (cinfo);\n  (*cinfo->coef->start_input_pass) (cinfo);\n  cinfo->inputctl->consume_input = cinfo->coef->consume_data;\n}\n\n\n/*\n * Finish up after inputting a compressed-data scan.\n * This is called by the coefficient controller after it's read all\n * the expected data of the scan.\n */\n\nMETHODDEF(void)\nfinish_input_pass (j_decompress_ptr cinfo)\n{\n  (*cinfo->entropy->finish_pass) (cinfo);\n  cinfo->inputctl->consume_input = consume_markers;\n}\n\n\n/*\n * Read JPEG markers before, between, or after compressed-data scans.\n * Change state as necessary when a new scan is reached.\n * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.\n *\n * The consume_input method pointer points either here or to the\n * coefficient controller's consume_data routine, depending on whether\n * we are reading a compressed data segment or inter-segment markers.\n *\n * Note: This function should NOT return a pseudo SOS marker (with zero\n * component number) to the caller.  A pseudo marker received by\n * read_markers is processed and then skipped for other markers.\n */\n\nMETHODDEF(int)\nconsume_markers (j_decompress_ptr cinfo)\n{\n  my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;\n  int val;\n\n  if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */\n    return JPEG_REACHED_EOI;\n\n  for (;;) {\t\t\t/* Loop to pass pseudo SOS marker */\n    val = (*cinfo->marker->read_markers) (cinfo);\n\n    switch (val) {\n    case JPEG_REACHED_SOS:\t/* Found SOS */\n      if (inputctl->inheaders) { /* 1st SOS */\n\tif (inputctl->inheaders == 1)\n\t  initial_setup(cinfo);\n\tif (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */\n\t  inputctl->inheaders = 2;\n\t  break;\n\t}\n\tinputctl->inheaders = 0;\n\t/* Note: start_input_pass must be called by jdmaster.c\n\t * before any more input can be consumed.  jdapimin.c is\n\t * responsible for enforcing this sequencing.\n\t */\n      } else {\t\t\t/* 2nd or later SOS marker */\n\tif (! inputctl->pub.has_multiple_scans)\n\t  ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */\n\tif (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */\n\t  break;\n\tstart_input_pass(cinfo);\n      }\n      return val;\n    case JPEG_REACHED_EOI:\t/* Found EOI */\n      inputctl->pub.eoi_reached = TRUE;\n      if (inputctl->inheaders) { /* Tables-only datastream, apparently */\n\tif (cinfo->marker->saw_SOF)\n\t  ERREXIT(cinfo, JERR_SOF_NO_SOS);\n      } else {\n\t/* Prevent infinite loop in coef ctlr's decompress_data routine\n\t * if user set output_scan_number larger than number of scans.\n\t */\n\tif (cinfo->output_scan_number > cinfo->input_scan_number)\n\t  cinfo->output_scan_number = cinfo->input_scan_number;\n      }\n      return val;\n    case JPEG_SUSPENDED:\n      return val;\n    default:\n      return val;\n    }\n  }\n}\n\n\n/*\n * Reset state to begin a fresh datastream.\n */\n\nMETHODDEF(void)\nreset_input_controller (j_decompress_ptr cinfo)\n{\n  my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;\n\n  inputctl->pub.consume_input = consume_markers;\n  inputctl->pub.has_multiple_scans = FALSE; /* \"unknown\" would be better */\n  inputctl->pub.eoi_reached = FALSE;\n  inputctl->inheaders = 1;\n  /* Reset other modules */\n  (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);\n  (*cinfo->marker->reset_marker_reader) (cinfo);\n  /* Reset progression state -- would be cleaner if entropy decoder did this */\n  cinfo->coef_bits = NULL;\n}\n\n\n/*\n * Initialize the input controller module.\n * This is called only once, when the decompression object is created.\n */\n\nGLOBAL(void)\njinit_input_controller (j_decompress_ptr cinfo)\n{\n  my_inputctl_ptr inputctl;\n\n  /* Create subobject in permanent pool */\n  inputctl = (my_inputctl_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_input_controller));\n  cinfo->inputctl = &inputctl->pub;\n  /* Initialize method pointers */\n  inputctl->pub.consume_input = consume_markers;\n  inputctl->pub.reset_input_controller = reset_input_controller;\n  inputctl->pub.start_input_pass = start_input_pass;\n  inputctl->pub.finish_input_pass = finish_input_pass;\n  /* Initialize state: can't use reset_input_controller since we don't\n   * want to try to reset other modules yet.\n   */\n  inputctl->pub.has_multiple_scans = FALSE; /* \"unknown\" would be better */\n  inputctl->pub.eoi_reached = FALSE;\n  inputctl->inheaders = 1;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdmainct.c",
    "content": "/*\n * jdmainct.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the main buffer controller for decompression.\n * The main buffer lies between the JPEG decompressor proper and the\n * post-processor; it holds downsampled data in the JPEG colorspace.\n *\n * Note that this code is bypassed in raw-data mode, since the application\n * supplies the equivalent of the main buffer in that case.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * In the current system design, the main buffer need never be a full-image\n * buffer; any full-height buffers will be found inside the coefficient or\n * postprocessing controllers.  Nonetheless, the main controller is not\n * trivial.  Its responsibility is to provide context rows for upsampling/\n * rescaling, and doing this in an efficient fashion is a bit tricky.\n *\n * Postprocessor input data is counted in \"row groups\".  A row group is\n * defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size)\n * sample rows of each component.  (We require DCT_scaled_size values to be\n * chosen such that these numbers are integers.  In practice DCT_scaled_size\n * values will likely be powers of two, so we actually have the stronger\n * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)\n * Upsampling will typically produce max_v_samp_factor pixel rows from each\n * row group (times any additional scale factor that the upsampler is\n * applying).\n *\n * The coefficient controller will deliver data to us one iMCU row at a time;\n * each iMCU row contains v_samp_factor * DCT_v_scaled_size sample rows, or\n * exactly min_DCT_v_scaled_size row groups.  (This amount of data corresponds\n * to one row of MCUs when the image is fully interleaved.)  Note that the\n * number of sample rows varies across components, but the number of row\n * groups does not.  Some garbage sample rows may be included in the last iMCU\n * row at the bottom of the image.\n *\n * Depending on the vertical scaling algorithm used, the upsampler may need\n * access to the sample row(s) above and below its current input row group.\n * The upsampler is required to set need_context_rows TRUE at global selection\n * time if so.  When need_context_rows is FALSE, this controller can simply\n * obtain one iMCU row at a time from the coefficient controller and dole it\n * out as row groups to the postprocessor.\n *\n * When need_context_rows is TRUE, this controller guarantees that the buffer\n * passed to postprocessing contains at least one row group's worth of samples\n * above and below the row group(s) being processed.  Note that the context\n * rows \"above\" the first passed row group appear at negative row offsets in\n * the passed buffer.  At the top and bottom of the image, the required\n * context rows are manufactured by duplicating the first or last real sample\n * row; this avoids having special cases in the upsampling inner loops.\n *\n * The amount of context is fixed at one row group just because that's a\n * convenient number for this controller to work with.  The existing\n * upsamplers really only need one sample row of context.  An upsampler\n * supporting arbitrary output rescaling might wish for more than one row\n * group of context when shrinking the image; tough, we don't handle that.\n * (This is justified by the assumption that downsizing will be handled mostly\n * by adjusting the DCT_scaled_size values, so that the actual scale factor at\n * the upsample step needn't be much less than one.)\n *\n * To provide the desired context, we have to retain the last two row groups\n * of one iMCU row while reading in the next iMCU row.  (The last row group\n * can't be processed until we have another row group for its below-context,\n * and so we have to save the next-to-last group too for its above-context.)\n * We could do this most simply by copying data around in our buffer, but\n * that'd be very slow.  We can avoid copying any data by creating a rather\n * strange pointer structure.  Here's how it works.  We allocate a workspace\n * consisting of M+2 row groups (where M = min_DCT_v_scaled_size is the number\n * of row groups per iMCU row).  We create two sets of redundant pointers to\n * the workspace.  Labeling the physical row groups 0 to M+1, the synthesized\n * pointer lists look like this:\n *                   M+1                          M-1\n * master pointer --> 0         master pointer --> 0\n *                    1                            1\n *                   ...                          ...\n *                   M-3                          M-3\n *                   M-2                           M\n *                   M-1                          M+1\n *                    M                           M-2\n *                   M+1                          M-1\n *                    0                            0\n * We read alternate iMCU rows using each master pointer; thus the last two\n * row groups of the previous iMCU row remain un-overwritten in the workspace.\n * The pointer lists are set up so that the required context rows appear to\n * be adjacent to the proper places when we pass the pointer lists to the\n * upsampler.\n *\n * The above pictures describe the normal state of the pointer lists.\n * At top and bottom of the image, we diddle the pointer lists to duplicate\n * the first or last sample row as necessary (this is cheaper than copying\n * sample rows around).\n *\n * This scheme breaks down if M < 2, ie, min_DCT_v_scaled_size is 1.  In that\n * situation each iMCU row provides only one row group so the buffering logic\n * must be different (eg, we must read two iMCU rows before we can emit the\n * first row group).  For now, we simply do not support providing context\n * rows when min_DCT_v_scaled_size is 1.  That combination seems unlikely to\n * be worth providing --- if someone wants a 1/8th-size preview, they probably\n * want it quick and dirty, so a context-free upsampler is sufficient.\n */\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_d_main_controller pub; /* public fields */\n\n  /* Pointer to allocated workspace (M or M+2 row groups). */\n  JSAMPARRAY buffer[MAX_COMPONENTS];\n\n  JDIMENSION rowgroup_ctr;\t/* counts row groups output to postprocessor */\n  JDIMENSION rowgroups_avail;\t/* row groups available to postprocessor */\n\n  /* Remaining fields are only used in the context case. */\n\n  boolean buffer_full;\t\t/* Have we gotten an iMCU row from decoder? */\n\n  /* These are the master pointers to the funny-order pointer lists. */\n  JSAMPIMAGE xbuffer[2];\t/* pointers to weird pointer lists */\n\n  int whichptr;\t\t\t/* indicates which pointer set is now in use */\n  int context_state;\t\t/* process_data state machine status */\n  JDIMENSION iMCU_row_ctr;\t/* counts iMCU rows to detect image top/bot */\n} my_main_controller;\n\ntypedef my_main_controller * my_main_ptr;\n\n/* context_state values: */\n#define CTX_PREPARE_FOR_IMCU\t0\t/* need to prepare for MCU row */\n#define CTX_PROCESS_IMCU\t1\t/* feeding iMCU to postprocessor */\n#define CTX_POSTPONED_ROW\t2\t/* feeding postponed row group */\n\n\n/* Forward declarations */\nMETHODDEF(void) process_data_simple_main\n\tJPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));\nMETHODDEF(void) process_data_context_main\n\tJPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));\n#ifdef QUANT_2PASS_SUPPORTED\nMETHODDEF(void) process_data_crank_post\n\tJPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t     JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));\n#endif\n\n\nLOCAL(void)\nalloc_funny_pointers (j_decompress_ptr cinfo)\n/* Allocate space for the funny pointer lists.\n * This is done only once, not once per pass.\n */\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n  int ci, rgroup;\n  int M = cinfo->min_DCT_v_scaled_size;\n  jpeg_component_info *compptr;\n  JSAMPARRAY xbuf;\n\n  /* Get top-level space for component array pointers.\n   * We alloc both arrays with one call to save a few cycles.\n   */\n  mainp->xbuffer[0] = (JSAMPIMAGE) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE,\n     cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));\n  mainp->xbuffer[1] = mainp->xbuffer[0] + cinfo->num_components;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (! compptr->component_needed)\n      continue;\t\t\t/* skip uninteresting component */\n    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */\n    /* Get space for pointer lists --- M+4 row groups in each list.\n     * We alloc both pointer lists with one call to save a few cycles.\n     */\n    xbuf = (JSAMPARRAY) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,\n      JPOOL_IMAGE, 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));\n    xbuf += rgroup;\t\t/* want one row group at negative offsets */\n    mainp->xbuffer[0][ci] = xbuf;\n    xbuf += rgroup * (M + 4);\n    mainp->xbuffer[1][ci] = xbuf;\n  }\n}\n\n\nLOCAL(void)\nmake_funny_pointers (j_decompress_ptr cinfo)\n/* Create the funny pointer lists discussed in the comments above.\n * The actual workspace is already allocated (in mainp->buffer),\n * and the space for the pointer lists is allocated too.\n * This routine just fills in the curiously ordered lists.\n * This will be repeated at the beginning of each pass.\n */\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n  int ci, i, rgroup;\n  int M = cinfo->min_DCT_v_scaled_size;\n  jpeg_component_info *compptr;\n  JSAMPARRAY buf, xbuf0, xbuf1;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (! compptr->component_needed)\n      continue;\t\t\t/* skip uninteresting component */\n    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */\n    xbuf0 = mainp->xbuffer[0][ci];\n    xbuf1 = mainp->xbuffer[1][ci];\n    /* First copy the workspace pointers as-is */\n    buf = mainp->buffer[ci];\n    for (i = 0; i < rgroup * (M + 2); i++) {\n      xbuf0[i] = xbuf1[i] = buf[i];\n    }\n    /* In the second list, put the last four row groups in swapped order */\n    for (i = 0; i < rgroup * 2; i++) {\n      xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];\n      xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];\n    }\n    /* The wraparound pointers at top and bottom will be filled later\n     * (see set_wraparound_pointers, below).  Initially we want the \"above\"\n     * pointers to duplicate the first actual data line.  This only needs\n     * to happen in xbuffer[0].\n     */\n    for (i = 0; i < rgroup; i++) {\n      xbuf0[i - rgroup] = xbuf0[0];\n    }\n  }\n}\n\n\nLOCAL(void)\nset_wraparound_pointers (j_decompress_ptr cinfo)\n/* Set up the \"wraparound\" pointers at top and bottom of the pointer lists.\n * This changes the pointer list state from top-of-image to the normal state.\n */\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n  int ci, i, rgroup;\n  int M = cinfo->min_DCT_v_scaled_size;\n  jpeg_component_info *compptr;\n  JSAMPARRAY xbuf0, xbuf1;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (! compptr->component_needed)\n      continue;\t\t\t/* skip uninteresting component */\n    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */\n    xbuf0 = mainp->xbuffer[0][ci];\n    xbuf1 = mainp->xbuffer[1][ci];\n    for (i = 0; i < rgroup; i++) {\n      xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];\n      xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];\n      xbuf0[rgroup*(M+2) + i] = xbuf0[i];\n      xbuf1[rgroup*(M+2) + i] = xbuf1[i];\n    }\n  }\n}\n\n\nLOCAL(void)\nset_bottom_pointers (j_decompress_ptr cinfo)\n/* Change the pointer lists to duplicate the last sample row at the bottom\n * of the image.  whichptr indicates which xbuffer holds the final iMCU row.\n * Also sets rowgroups_avail to indicate number of nondummy row groups in row.\n */\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n  int ci, i, rgroup, iMCUheight, rows_left;\n  jpeg_component_info *compptr;\n  JSAMPARRAY xbuf;\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (! compptr->component_needed)\n      continue;\t\t\t/* skip uninteresting component */\n    /* Count sample rows in one iMCU row and in one row group */\n    iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size;\n    rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size;\n    /* Count nondummy sample rows remaining for this component */\n    rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);\n    if (rows_left == 0) rows_left = iMCUheight;\n    /* Count nondummy row groups.  Should get same answer for each component,\n     * so we need only do it once.\n     */\n    if (ci == 0) {\n      mainp->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);\n    }\n    /* Duplicate the last real sample row rgroup*2 times; this pads out the\n     * last partial rowgroup and ensures at least one full rowgroup of context.\n     */\n    xbuf = mainp->xbuffer[mainp->whichptr][ci];\n    for (i = 0; i < rgroup * 2; i++) {\n      xbuf[rows_left + i] = xbuf[rows_left-1];\n    }\n  }\n}\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n\n  switch (pass_mode) {\n  case JBUF_PASS_THRU:\n    if (cinfo->upsample->need_context_rows) {\n      mainp->pub.process_data = process_data_context_main;\n      make_funny_pointers(cinfo); /* Create the xbuffer[] lists */\n      mainp->whichptr = 0;\t/* Read first iMCU row into xbuffer[0] */\n      mainp->context_state = CTX_PREPARE_FOR_IMCU;\n      mainp->iMCU_row_ctr = 0;\n      mainp->buffer_full = FALSE; /* Mark buffer empty */\n    } else {\n      /* Simple case with no context needed */\n      mainp->pub.process_data = process_data_simple_main;\n      mainp->rowgroup_ctr = mainp->rowgroups_avail; /* Mark buffer empty */\n    }\n    break;\n#ifdef QUANT_2PASS_SUPPORTED\n  case JBUF_CRANK_DEST:\n    /* For last pass of 2-pass quantization, just crank the postprocessor */\n    mainp->pub.process_data = process_data_crank_post;\n    break;\n#endif\n  default:\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n  }\n}\n\n\n/*\n * Process some data.\n * This handles the simple case where no context is required.\n */\n\nMETHODDEF(void)\nprocess_data_simple_main (j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t\t\t  JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n\n  /* Read input data if we haven't filled the main buffer yet */\n  if (mainp->rowgroup_ctr >= mainp->rowgroups_avail) {\n    if (! (*cinfo->coef->decompress_data) (cinfo, mainp->buffer))\n      return;\t\t\t/* suspension forced, can do nothing more */\n    mainp->rowgroup_ctr = 0;\t/* OK, we have an iMCU row to work with */\n  }\n\n  /* Note: at the bottom of the image, we may pass extra garbage row groups\n   * to the postprocessor.  The postprocessor has to check for bottom\n   * of image anyway (at row resolution), so no point in us doing it too.\n   */\n\n  /* Feed the postprocessor */\n  (*cinfo->post->post_process_data) (cinfo, mainp->buffer,\n\t\t\t&mainp->rowgroup_ctr, mainp->rowgroups_avail,\n\t\t\toutput_buf, out_row_ctr, out_rows_avail);\n}\n\n\n/*\n * Process some data.\n * This handles the case where context rows must be provided.\n */\n\nMETHODDEF(void)\nprocess_data_context_main (j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t\t\t   JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)\n{\n  my_main_ptr mainp = (my_main_ptr) cinfo->main;\n\n  /* Read input data if we haven't filled the main buffer yet */\n  if (! mainp->buffer_full) {\n    if (! (*cinfo->coef->decompress_data) (cinfo,\n\t\t\t\t\t   mainp->xbuffer[mainp->whichptr]))\n      return;\t\t\t/* suspension forced, can do nothing more */\n    mainp->buffer_full = TRUE;\t/* OK, we have an iMCU row to work with */\n    mainp->iMCU_row_ctr++;\t/* count rows received */\n  }\n\n  /* Postprocessor typically will not swallow all the input data it is handed\n   * in one call (due to filling the output buffer first).  Must be prepared\n   * to exit and restart.  This switch lets us keep track of how far we got.\n   * Note that each case falls through to the next on successful completion.\n   */\n  switch (mainp->context_state) {\n  case CTX_POSTPONED_ROW:\n    /* Call postprocessor using previously set pointers for postponed row */\n    (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr],\n\t\t\t&mainp->rowgroup_ctr, mainp->rowgroups_avail,\n\t\t\toutput_buf, out_row_ctr, out_rows_avail);\n    if (mainp->rowgroup_ctr < mainp->rowgroups_avail)\n      return;\t\t\t/* Need to suspend */\n    mainp->context_state = CTX_PREPARE_FOR_IMCU;\n    if (*out_row_ctr >= out_rows_avail)\n      return;\t\t\t/* Postprocessor exactly filled output buf */\n    /*FALLTHROUGH*/\n  case CTX_PREPARE_FOR_IMCU:\n    /* Prepare to process first M-1 row groups of this iMCU row */\n    mainp->rowgroup_ctr = 0;\n    mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);\n    /* Check for bottom of image: if so, tweak pointers to \"duplicate\"\n     * the last sample row, and adjust rowgroups_avail to ignore padding rows.\n     */\n    if (mainp->iMCU_row_ctr == cinfo->total_iMCU_rows)\n      set_bottom_pointers(cinfo);\n    mainp->context_state = CTX_PROCESS_IMCU;\n    /*FALLTHROUGH*/\n  case CTX_PROCESS_IMCU:\n    /* Call postprocessor using previously set pointers */\n    (*cinfo->post->post_process_data) (cinfo, mainp->xbuffer[mainp->whichptr],\n\t\t\t&mainp->rowgroup_ctr, mainp->rowgroups_avail,\n\t\t\toutput_buf, out_row_ctr, out_rows_avail);\n    if (mainp->rowgroup_ctr < mainp->rowgroups_avail)\n      return;\t\t\t/* Need to suspend */\n    /* After the first iMCU, change wraparound pointers to normal state */\n    if (mainp->iMCU_row_ctr == 1)\n      set_wraparound_pointers(cinfo);\n    /* Prepare to load new iMCU row using other xbuffer list */\n    mainp->whichptr ^= 1;\t/* 0=>1 or 1=>0 */\n    mainp->buffer_full = FALSE;\n    /* Still need to process last row group of this iMCU row, */\n    /* which is saved at index M+1 of the other xbuffer */\n    mainp->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);\n    mainp->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);\n    mainp->context_state = CTX_POSTPONED_ROW;\n  }\n}\n\n\n/*\n * Process some data.\n * Final pass of two-pass quantization: just call the postprocessor.\n * Source data will be the postprocessor controller's internal buffer.\n */\n\n#ifdef QUANT_2PASS_SUPPORTED\n\nMETHODDEF(void)\nprocess_data_crank_post (j_decompress_ptr cinfo, JSAMPARRAY output_buf,\n\t\t\t JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)\n{\n  (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,\n\t\t\t(JDIMENSION *) NULL, (JDIMENSION) 0,\n\t\t\toutput_buf, out_row_ctr, out_rows_avail);\n}\n\n#endif /* QUANT_2PASS_SUPPORTED */\n\n\n/*\n * Initialize main buffer controller.\n */\n\nGLOBAL(void)\njinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)\n{\n  my_main_ptr mainp;\n  int ci, rgroup, ngroups;\n  jpeg_component_info *compptr;\n\n  mainp = (my_main_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_main_controller));\n  cinfo->main = &mainp->pub;\n  mainp->pub.start_pass = start_pass_main;\n\n  if (need_full_buffer)\t\t/* shouldn't happen */\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n\n  /* Allocate the workspace.\n   * ngroups is the number of row groups we need.\n   */\n  if (cinfo->upsample->need_context_rows) {\n    if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */\n      ERREXIT(cinfo, JERR_NOTIMPL);\n    alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */\n    ngroups = cinfo->min_DCT_v_scaled_size + 2;\n  } else {\n    /* There are always min_DCT_v_scaled_size row groups in an iMCU row. */\n    ngroups = cinfo->min_DCT_v_scaled_size;\n    mainp->rowgroups_avail = (JDIMENSION) ngroups;\n  }\n\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    if (! compptr->component_needed)\n      continue;\t\t\t/* skip uninteresting component */\n    rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n      cinfo->min_DCT_v_scaled_size; /* height of a row group of component */\n    mainp->buffer[ci] = (*cinfo->mem->alloc_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       compptr->width_in_blocks * ((JDIMENSION) compptr->DCT_h_scaled_size),\n       (JDIMENSION) (rgroup * ngroups));\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdmarker.c",
    "content": "/*\n * jdmarker.c\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modified 2009-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to decode JPEG datastream markers.\n * Most of the complexity arises from our desire to support input\n * suspension: if not all of the data for a marker is available,\n * we must exit back to the application.  On resumption, we reprocess\n * the marker.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\ntypedef enum {\t\t\t/* JPEG marker codes */\n  M_SOF0  = 0xc0,\n  M_SOF1  = 0xc1,\n  M_SOF2  = 0xc2,\n  M_SOF3  = 0xc3,\n\n  M_SOF5  = 0xc5,\n  M_SOF6  = 0xc6,\n  M_SOF7  = 0xc7,\n\n  M_JPG   = 0xc8,\n  M_SOF9  = 0xc9,\n  M_SOF10 = 0xca,\n  M_SOF11 = 0xcb,\n\n  M_SOF13 = 0xcd,\n  M_SOF14 = 0xce,\n  M_SOF15 = 0xcf,\n\n  M_DHT   = 0xc4,\n\n  M_DAC   = 0xcc,\n\n  M_RST0  = 0xd0,\n  M_RST1  = 0xd1,\n  M_RST2  = 0xd2,\n  M_RST3  = 0xd3,\n  M_RST4  = 0xd4,\n  M_RST5  = 0xd5,\n  M_RST6  = 0xd6,\n  M_RST7  = 0xd7,\n\n  M_SOI   = 0xd8,\n  M_EOI   = 0xd9,\n  M_SOS   = 0xda,\n  M_DQT   = 0xdb,\n  M_DNL   = 0xdc,\n  M_DRI   = 0xdd,\n  M_DHP   = 0xde,\n  M_EXP   = 0xdf,\n\n  M_APP0  = 0xe0,\n  M_APP1  = 0xe1,\n  M_APP2  = 0xe2,\n  M_APP3  = 0xe3,\n  M_APP4  = 0xe4,\n  M_APP5  = 0xe5,\n  M_APP6  = 0xe6,\n  M_APP7  = 0xe7,\n  M_APP8  = 0xe8,\n  M_APP9  = 0xe9,\n  M_APP10 = 0xea,\n  M_APP11 = 0xeb,\n  M_APP12 = 0xec,\n  M_APP13 = 0xed,\n  M_APP14 = 0xee,\n  M_APP15 = 0xef,\n\n  M_JPG0  = 0xf0,\n  M_JPG8  = 0xf8,\n  M_JPG13 = 0xfd,\n  M_COM   = 0xfe,\n\n  M_TEM   = 0x01,\n\n  M_ERROR = 0x100\n} JPEG_MARKER;\n\n\n/* Private state */\n\ntypedef struct {\n  struct jpeg_marker_reader pub; /* public fields */\n\n  /* Application-overridable marker processing methods */\n  jpeg_marker_parser_method process_COM;\n  jpeg_marker_parser_method process_APPn[16];\n\n  /* Limit on marker data length to save for each marker type */\n  unsigned int length_limit_COM;\n  unsigned int length_limit_APPn[16];\n\n  /* Status of COM/APPn marker saving */\n  jpeg_saved_marker_ptr cur_marker;\t/* NULL if not processing a marker */\n  unsigned int bytes_read;\t\t/* data bytes read so far in marker */\n  /* Note: cur_marker is not linked into marker_list until it's all read. */\n} my_marker_reader;\n\ntypedef my_marker_reader * my_marker_ptr;\n\n\n/*\n * Macros for fetching data from the data source module.\n *\n * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect\n * the current restart point; we update them only when we have reached a\n * suitable place to restart if a suspension occurs.\n */\n\n/* Declare and initialize local copies of input pointer/count */\n#define INPUT_VARS(cinfo)  \\\n\tstruct jpeg_source_mgr * datasrc = (cinfo)->src;  \\\n\tconst JOCTET * next_input_byte = datasrc->next_input_byte;  \\\n\tsize_t bytes_in_buffer = datasrc->bytes_in_buffer\n\n/* Unload the local copies --- do this only at a restart boundary */\n#define INPUT_SYNC(cinfo)  \\\n\t( datasrc->next_input_byte = next_input_byte,  \\\n\t  datasrc->bytes_in_buffer = bytes_in_buffer )\n\n/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */\n#define INPUT_RELOAD(cinfo)  \\\n\t( next_input_byte = datasrc->next_input_byte,  \\\n\t  bytes_in_buffer = datasrc->bytes_in_buffer )\n\n/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.\n * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,\n * but we must reload the local copies after a successful fill.\n */\n#define MAKE_BYTE_AVAIL(cinfo,action)  \\\n\tif (bytes_in_buffer == 0) {  \\\n\t  if (! (*datasrc->fill_input_buffer) (cinfo))  \\\n\t    { action; }  \\\n\t  INPUT_RELOAD(cinfo);  \\\n\t}\n\n/* Read a byte into variable V.\n * If must suspend, take the specified action (typically \"return FALSE\").\n */\n#define INPUT_BYTE(cinfo,V,action)  \\\n\tMAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \\\n\t\t  bytes_in_buffer--; \\\n\t\t  V = GETJOCTET(*next_input_byte++); )\n\n/* As above, but read two bytes interpreted as an unsigned 16-bit integer.\n * V should be declared unsigned int or perhaps INT32.\n */\n#define INPUT_2BYTES(cinfo,V,action)  \\\n\tMAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \\\n\t\t  bytes_in_buffer--; \\\n\t\t  V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \\\n\t\t  MAKE_BYTE_AVAIL(cinfo,action); \\\n\t\t  bytes_in_buffer--; \\\n\t\t  V += GETJOCTET(*next_input_byte++); )\n\n\n/*\n * Routines to process JPEG markers.\n *\n * Entry condition: JPEG marker itself has been read and its code saved\n *   in cinfo->unread_marker; input restart point is just after the marker.\n *\n * Exit: if return TRUE, have read and processed any parameters, and have\n *   updated the restart point to point after the parameters.\n *   If return FALSE, was forced to suspend before reaching end of\n *   marker parameters; restart point has not been moved.  Same routine\n *   will be called again after application supplies more input data.\n *\n * This approach to suspension assumes that all of a marker's parameters\n * can fit into a single input bufferload.  This should hold for \"normal\"\n * markers.  Some COM/APPn markers might have large parameter segments\n * that might not fit.  If we are simply dropping such a marker, we use\n * skip_input_data to get past it, and thereby put the problem on the\n * source manager's shoulders.  If we are saving the marker's contents\n * into memory, we use a slightly different convention: when forced to\n * suspend, the marker processor updates the restart point to the end of\n * what it's consumed (ie, the end of the buffer) before returning FALSE.\n * On resumption, cinfo->unread_marker still contains the marker code,\n * but the data source will point to the next chunk of marker data.\n * The marker processor must retain internal state to deal with this.\n *\n * Note that we don't bother to avoid duplicate trace messages if a\n * suspension occurs within marker parameters.  Other side effects\n * require more care.\n */\n\n\nLOCAL(boolean)\nget_soi (j_decompress_ptr cinfo)\n/* Process an SOI marker */\n{\n  int i;\n  \n  TRACEMS(cinfo, 1, JTRC_SOI);\n\n  if (cinfo->marker->saw_SOI)\n    ERREXIT(cinfo, JERR_SOI_DUPLICATE);\n\n  /* Reset all parameters that are defined to be reset by SOI */\n\n  for (i = 0; i < NUM_ARITH_TBLS; i++) {\n    cinfo->arith_dc_L[i] = 0;\n    cinfo->arith_dc_U[i] = 1;\n    cinfo->arith_ac_K[i] = 5;\n  }\n  cinfo->restart_interval = 0;\n\n  /* Set initial assumptions for colorspace etc */\n\n  cinfo->jpeg_color_space = JCS_UNKNOWN;\n  cinfo->color_transform = JCT_NONE;\n  cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */\n\n  cinfo->saw_JFIF_marker = FALSE;\n  cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */\n  cinfo->JFIF_minor_version = 1;\n  cinfo->density_unit = 0;\n  cinfo->X_density = 1;\n  cinfo->Y_density = 1;\n  cinfo->saw_Adobe_marker = FALSE;\n  cinfo->Adobe_transform = 0;\n\n  cinfo->marker->saw_SOI = TRUE;\n\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nget_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog,\n\t boolean is_arith)\n/* Process a SOFn marker */\n{\n  INT32 length;\n  int c, ci, i;\n  jpeg_component_info * compptr;\n  INPUT_VARS(cinfo);\n\n  cinfo->is_baseline = is_baseline;\n  cinfo->progressive_mode = is_prog;\n  cinfo->arith_code = is_arith;\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n\n  INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);\n  INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);\n  INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);\n  INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);\n\n  length -= 8;\n\n  TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,\n\t   (int) cinfo->image_width, (int) cinfo->image_height,\n\t   cinfo->num_components);\n\n  if (cinfo->marker->saw_SOF)\n    ERREXIT(cinfo, JERR_SOF_DUPLICATE);\n\n  /* We don't support files in which the image height is initially specified */\n  /* as 0 and is later redefined by DNL.  As long as we have to check that,  */\n  /* might as well have a general sanity check. */\n  if (cinfo->image_height <= 0 || cinfo->image_width <= 0 ||\n      cinfo->num_components <= 0)\n    ERREXIT(cinfo, JERR_EMPTY_IMAGE);\n\n  if (length != (cinfo->num_components * 3))\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  if (cinfo->comp_info == NULL)\t/* do only once, even if suspend */\n    cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)\n\t\t\t((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t cinfo->num_components * SIZEOF(jpeg_component_info));\n\n  for (ci = 0; ci < cinfo->num_components; ci++) {\n    INPUT_BYTE(cinfo, c, return FALSE);\n    /* Check to see whether component id has already been seen   */\n    /* (in violation of the spec, but unfortunately seen in some */\n    /* files).  If so, create \"fake\" component id equal to the   */\n    /* max id seen so far + 1. */\n    for (i = 0, compptr = cinfo->comp_info; i < ci; i++, compptr++) {\n      if (c == compptr->component_id) {\n\tcompptr = cinfo->comp_info;\n\tc = compptr->component_id;\n\tcompptr++;\n\tfor (i = 1; i < ci; i++, compptr++) {\n\t  if (compptr->component_id > c) c = compptr->component_id;\n\t}\n\tc++;\n\tbreak;\n      }\n    }\n    compptr->component_id = c;\n    compptr->component_index = ci;\n    INPUT_BYTE(cinfo, c, return FALSE);\n    compptr->h_samp_factor = (c >> 4) & 15;\n    compptr->v_samp_factor = (c     ) & 15;\n    INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);\n\n    TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,\n\t     compptr->component_id, compptr->h_samp_factor,\n\t     compptr->v_samp_factor, compptr->quant_tbl_no);\n  }\n\n  cinfo->marker->saw_SOF = TRUE;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nget_sos (j_decompress_ptr cinfo)\n/* Process a SOS marker */\n{\n  INT32 length;\n  int c, ci, i, n;\n  jpeg_component_info * compptr;\n  INPUT_VARS(cinfo);\n\n  if (! cinfo->marker->saw_SOF)\n    ERREXITS(cinfo, JERR_SOF_BEFORE, \"SOS\");\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n\n  INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */\n\n  TRACEMS1(cinfo, 1, JTRC_SOS, n);\n\n  if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN ||\n      (n == 0 && !cinfo->progressive_mode))\n      /* pseudo SOS marker only allowed in progressive mode */\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  cinfo->comps_in_scan = n;\n\n  /* Collect the component-spec parameters */\n\n  for (i = 0; i < n; i++) {\n    INPUT_BYTE(cinfo, c, return FALSE);\n\n    /* Detect the case where component id's are not unique, and, if so, */\n    /* create a fake component id using the same logic as in get_sof.   */\n    /* Note:  This also ensures that all of the SOF components are      */\n    /* referenced in the single scan case, which prevents access to     */\n    /* uninitialized memory in later decoding stages. */\n    for (ci = 0; ci < i; ci++) {\n      if (c == cinfo->cur_comp_info[ci]->component_id) {\n\tc = cinfo->cur_comp_info[0]->component_id;\n\tfor (ci = 1; ci < i; ci++) {\n\t  compptr = cinfo->cur_comp_info[ci];\n\t  if (compptr->component_id > c) c = compptr->component_id;\n\t}\n\tc++;\n\tbreak;\n      }\n    }\n\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      if (c == compptr->component_id)\n\tgoto id_found;\n    }\n\n    ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, c);\n\n  id_found:\n\n    cinfo->cur_comp_info[i] = compptr;\n    INPUT_BYTE(cinfo, c, return FALSE);\n    compptr->dc_tbl_no = (c >> 4) & 15;\n    compptr->ac_tbl_no = (c     ) & 15;\n\n    TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, compptr->component_id,\n\t     compptr->dc_tbl_no, compptr->ac_tbl_no);\n  }\n\n  /* Collect the additional scan parameters Ss, Se, Ah/Al. */\n  INPUT_BYTE(cinfo, c, return FALSE);\n  cinfo->Ss = c;\n  INPUT_BYTE(cinfo, c, return FALSE);\n  cinfo->Se = c;\n  INPUT_BYTE(cinfo, c, return FALSE);\n  cinfo->Ah = (c >> 4) & 15;\n  cinfo->Al = (c     ) & 15;\n\n  TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,\n\t   cinfo->Ah, cinfo->Al);\n\n  /* Prepare to scan data & restart markers */\n  cinfo->marker->next_restart_num = 0;\n\n  /* Count another (non-pseudo) SOS marker */\n  if (n) cinfo->input_scan_number++;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\n#ifdef D_ARITH_CODING_SUPPORTED\n\nLOCAL(boolean)\nget_dac (j_decompress_ptr cinfo)\n/* Process a DAC marker */\n{\n  INT32 length;\n  int index, val;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  length -= 2;\n  \n  while (length > 0) {\n    INPUT_BYTE(cinfo, index, return FALSE);\n    INPUT_BYTE(cinfo, val, return FALSE);\n\n    length -= 2;\n\n    TRACEMS2(cinfo, 1, JTRC_DAC, index, val);\n\n    if (index < 0 || index >= (2*NUM_ARITH_TBLS))\n      ERREXIT1(cinfo, JERR_DAC_INDEX, index);\n\n    if (index >= NUM_ARITH_TBLS) { /* define AC table */\n      cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;\n    } else {\t\t\t/* define DC table */\n      cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);\n      cinfo->arith_dc_U[index] = (UINT8) (val >> 4);\n      if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])\n\tERREXIT1(cinfo, JERR_DAC_VALUE, val);\n    }\n  }\n\n  if (length != 0)\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n#else /* ! D_ARITH_CODING_SUPPORTED */\n\n#define get_dac(cinfo)  skip_variable(cinfo)\n\n#endif /* D_ARITH_CODING_SUPPORTED */\n\n\nLOCAL(boolean)\nget_dht (j_decompress_ptr cinfo)\n/* Process a DHT marker */\n{\n  INT32 length;\n  UINT8 bits[17];\n  UINT8 huffval[256];\n  int i, index, count;\n  JHUFF_TBL **htblptr;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  length -= 2;\n  \n  while (length > 16) {\n    INPUT_BYTE(cinfo, index, return FALSE);\n\n    TRACEMS1(cinfo, 1, JTRC_DHT, index);\n      \n    bits[0] = 0;\n    count = 0;\n    for (i = 1; i <= 16; i++) {\n      INPUT_BYTE(cinfo, bits[i], return FALSE);\n      count += bits[i];\n    }\n\n    length -= 1 + 16;\n\n    TRACEMS8(cinfo, 2, JTRC_HUFFBITS,\n\t     bits[1], bits[2], bits[3], bits[4],\n\t     bits[5], bits[6], bits[7], bits[8]);\n    TRACEMS8(cinfo, 2, JTRC_HUFFBITS,\n\t     bits[9], bits[10], bits[11], bits[12],\n\t     bits[13], bits[14], bits[15], bits[16]);\n\n    /* Here we just do minimal validation of the counts to avoid walking\n     * off the end of our table space.  jdhuff.c will check more carefully.\n     */\n    if (count > 256 || ((INT32) count) > length)\n      ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);\n\n    for (i = 0; i < count; i++)\n      INPUT_BYTE(cinfo, huffval[i], return FALSE);\n\n    length -= count;\n\n    if (index & 0x10) {\t\t/* AC table definition */\n      index -= 0x10;\n      htblptr = &cinfo->ac_huff_tbl_ptrs[index];\n    } else {\t\t\t/* DC table definition */\n      htblptr = &cinfo->dc_huff_tbl_ptrs[index];\n    }\n\n    if (index < 0 || index >= NUM_HUFF_TBLS)\n      ERREXIT1(cinfo, JERR_DHT_INDEX, index);\n\n    if (*htblptr == NULL)\n      *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);\n  \n    MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));\n    if (count > 0)\n      MEMCOPY((*htblptr)->huffval, huffval, count * SIZEOF(UINT8));\n  }\n\n  if (length != 0)\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nget_dqt (j_decompress_ptr cinfo)\n/* Process a DQT marker */\n{\n  INT32 length, count, i;\n  int n, prec;\n  unsigned int tmp;\n  JQUANT_TBL *quant_ptr;\n  const int *natural_order;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  length -= 2;\n\n  while (length > 0) {\n    length--;\n    INPUT_BYTE(cinfo, n, return FALSE);\n    prec = n >> 4;\n    n &= 0x0F;\n\n    TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);\n\n    if (n >= NUM_QUANT_TBLS)\n      ERREXIT1(cinfo, JERR_DQT_INDEX, n);\n      \n    if (cinfo->quant_tbl_ptrs[n] == NULL)\n      cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);\n    quant_ptr = cinfo->quant_tbl_ptrs[n];\n\n    if (prec) {\n      if (length < DCTSIZE2 * 2) {\n\t/* Initialize full table for safety. */\n\tfor (i = 0; i < DCTSIZE2; i++) {\n\t  quant_ptr->quantval[i] = 1;\n\t}\n\tcount = length >> 1;\n      } else\n\tcount = DCTSIZE2;\n    } else {\n      if (length < DCTSIZE2) {\n\t/* Initialize full table for safety. */\n\tfor (i = 0; i < DCTSIZE2; i++) {\n\t  quant_ptr->quantval[i] = 1;\n\t}\n\tcount = length;\n      } else\n\tcount = DCTSIZE2;\n    }\n\n    switch ((int) count) {\n    case (2*2): natural_order = jpeg_natural_order2; break;\n    case (3*3): natural_order = jpeg_natural_order3; break;\n    case (4*4): natural_order = jpeg_natural_order4; break;\n    case (5*5): natural_order = jpeg_natural_order5; break;\n    case (6*6): natural_order = jpeg_natural_order6; break;\n    case (7*7): natural_order = jpeg_natural_order7; break;\n    default:    natural_order = jpeg_natural_order;\n    }\n\n    for (i = 0; i < count; i++) {\n      if (prec)\n\tINPUT_2BYTES(cinfo, tmp, return FALSE);\n      else\n\tINPUT_BYTE(cinfo, tmp, return FALSE);\n      /* We convert the zigzag-order table to natural array order. */\n      quant_ptr->quantval[natural_order[i]] = (UINT16) tmp;\n    }\n\n    if (cinfo->err->trace_level >= 2) {\n      for (i = 0; i < DCTSIZE2; i += 8) {\n\tTRACEMS8(cinfo, 2, JTRC_QUANTVALS,\n\t\t quant_ptr->quantval[i],   quant_ptr->quantval[i+1],\n\t\t quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],\n\t\t quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],\n\t\t quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);\n      }\n    }\n\n    length -= count;\n    if (prec) length -= count;\n  }\n\n  if (length != 0)\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nget_dri (j_decompress_ptr cinfo)\n/* Process a DRI marker */\n{\n  INT32 length;\n  unsigned int tmp;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  \n  if (length != 4)\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n\n  TRACEMS1(cinfo, 1, JTRC_DRI, tmp);\n\n  cinfo->restart_interval = tmp;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nget_lse (j_decompress_ptr cinfo)\n/* Process an LSE marker */\n{\n  INT32 length;\n  unsigned int tmp;\n  int cid;\n  INPUT_VARS(cinfo);\n\n  if (! cinfo->marker->saw_SOF)\n    ERREXITS(cinfo, JERR_SOF_BEFORE, \"LSE\");\n\n  if (cinfo->num_components < 3) goto bad;\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n\n  if (length != 24)\n    ERREXIT(cinfo, JERR_BAD_LENGTH);\n\n  INPUT_BYTE(cinfo, tmp, return FALSE);\n  if (tmp != 0x0D)\t/* ID inverse transform specification */\n    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != MAXJSAMPLE) goto bad;\t\t/* MAXTRANS */\n  INPUT_BYTE(cinfo, tmp, return FALSE);\n  if (tmp != 3) goto bad;\t\t\t/* Nt=3 */\n  INPUT_BYTE(cinfo, cid, return FALSE);\n  if (cid != cinfo->comp_info[1].component_id) goto bad;\n  INPUT_BYTE(cinfo, cid, return FALSE);\n  if (cid != cinfo->comp_info[0].component_id) goto bad;\n  INPUT_BYTE(cinfo, cid, return FALSE);\n  if (cid != cinfo->comp_info[2].component_id) goto bad;\n  INPUT_BYTE(cinfo, tmp, return FALSE);\n  if (tmp != 0x80) goto bad;\t\t/* F1: CENTER1=1, NORM1=0 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 0) goto bad;\t\t\t/* A(1,1)=0 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 0) goto bad;\t\t\t/* A(1,2)=0 */\n  INPUT_BYTE(cinfo, tmp, return FALSE);\n  if (tmp != 0) goto bad;\t\t/* F2: CENTER2=0, NORM2=0 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 1) goto bad;\t\t\t/* A(2,1)=1 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 0) goto bad;\t\t\t/* A(2,2)=0 */\n  INPUT_BYTE(cinfo, tmp, return FALSE);\n  if (tmp != 0) goto bad;\t\t/* F3: CENTER3=0, NORM3=0 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 1) goto bad;\t\t\t/* A(3,1)=1 */\n  INPUT_2BYTES(cinfo, tmp, return FALSE);\n  if (tmp != 0) {\t\t\t\t/* A(3,2)=0 */\n    bad:\n    ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);\n  }\n\n  /* OK, valid transform that we can handle. */\n  cinfo->color_transform = JCT_SUBTRACT_GREEN;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\n/*\n * Routines for processing APPn and COM markers.\n * These are either saved in memory or discarded, per application request.\n * APP0 and APP14 are specially checked to see if they are\n * JFIF and Adobe markers, respectively.\n */\n\n#define APP0_DATA_LEN\t14\t/* Length of interesting data in APP0 */\n#define APP14_DATA_LEN\t12\t/* Length of interesting data in APP14 */\n#define APPN_DATA_LEN\t14\t/* Must be the largest of the above!! */\n\n\nLOCAL(void)\nexamine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data,\n\t      unsigned int datalen, INT32 remaining)\n/* Examine first few bytes from an APP0.\n * Take appropriate action if it is a JFIF marker.\n * datalen is # of bytes at data[], remaining is length of rest of marker data.\n */\n{\n  INT32 totallen = (INT32) datalen + remaining;\n\n  if (datalen >= APP0_DATA_LEN &&\n      GETJOCTET(data[0]) == 0x4A &&\n      GETJOCTET(data[1]) == 0x46 &&\n      GETJOCTET(data[2]) == 0x49 &&\n      GETJOCTET(data[3]) == 0x46 &&\n      GETJOCTET(data[4]) == 0) {\n    /* Found JFIF APP0 marker: save info */\n    cinfo->saw_JFIF_marker = TRUE;\n    cinfo->JFIF_major_version = GETJOCTET(data[5]);\n    cinfo->JFIF_minor_version = GETJOCTET(data[6]);\n    cinfo->density_unit = GETJOCTET(data[7]);\n    cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);\n    cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);\n    /* Check version.\n     * Major version must be 1 or 2, anything else signals an incompatible\n     * change.\n     * (We used to treat this as an error, but now it's a nonfatal warning,\n     * because some bozo at Hijaak couldn't read the spec.)\n     * Minor version should be 0..2, but process anyway if newer.\n     */\n    if (cinfo->JFIF_major_version != 1 && cinfo->JFIF_major_version != 2)\n      WARNMS2(cinfo, JWRN_JFIF_MAJOR,\n\t      cinfo->JFIF_major_version, cinfo->JFIF_minor_version);\n    /* Generate trace messages */\n    TRACEMS5(cinfo, 1, JTRC_JFIF,\n\t     cinfo->JFIF_major_version, cinfo->JFIF_minor_version,\n\t     cinfo->X_density, cinfo->Y_density, cinfo->density_unit);\n    /* Validate thumbnail dimensions and issue appropriate messages */\n    if (GETJOCTET(data[12]) | GETJOCTET(data[13]))\n      TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,\n\t       GETJOCTET(data[12]), GETJOCTET(data[13]));\n    totallen -= APP0_DATA_LEN;\n    if (totallen !=\n\t((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))\n      TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);\n  } else if (datalen >= 6 &&\n      GETJOCTET(data[0]) == 0x4A &&\n      GETJOCTET(data[1]) == 0x46 &&\n      GETJOCTET(data[2]) == 0x58 &&\n      GETJOCTET(data[3]) == 0x58 &&\n      GETJOCTET(data[4]) == 0) {\n    /* Found JFIF \"JFXX\" extension APP0 marker */\n    /* The library doesn't actually do anything with these,\n     * but we try to produce a helpful trace message.\n     */\n    switch (GETJOCTET(data[5])) {\n    case 0x10:\n      TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);\n      break;\n    case 0x11:\n      TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);\n      break;\n    case 0x13:\n      TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);\n      break;\n    default:\n      TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,\n\t       GETJOCTET(data[5]), (int) totallen);\n    }\n  } else {\n    /* Start of APP0 does not match \"JFIF\" or \"JFXX\", or too short */\n    TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);\n  }\n}\n\n\nLOCAL(void)\nexamine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data,\n\t       unsigned int datalen, INT32 remaining)\n/* Examine first few bytes from an APP14.\n * Take appropriate action if it is an Adobe marker.\n * datalen is # of bytes at data[], remaining is length of rest of marker data.\n */\n{\n  unsigned int version, flags0, flags1, transform;\n\n  if (datalen >= APP14_DATA_LEN &&\n      GETJOCTET(data[0]) == 0x41 &&\n      GETJOCTET(data[1]) == 0x64 &&\n      GETJOCTET(data[2]) == 0x6F &&\n      GETJOCTET(data[3]) == 0x62 &&\n      GETJOCTET(data[4]) == 0x65) {\n    /* Found Adobe APP14 marker */\n    version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);\n    flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);\n    flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);\n    transform = GETJOCTET(data[11]);\n    TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);\n    cinfo->saw_Adobe_marker = TRUE;\n    cinfo->Adobe_transform = (UINT8) transform;\n  } else {\n    /* Start of APP14 does not match \"Adobe\", or too short */\n    TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));\n  }\n}\n\n\nMETHODDEF(boolean)\nget_interesting_appn (j_decompress_ptr cinfo)\n/* Process an APP0 or APP14 marker without saving it */\n{\n  INT32 length;\n  JOCTET b[APPN_DATA_LEN];\n  unsigned int i, numtoread;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  length -= 2;\n\n  /* get the interesting part of the marker data */\n  if (length >= APPN_DATA_LEN)\n    numtoread = APPN_DATA_LEN;\n  else if (length > 0)\n    numtoread = (unsigned int) length;\n  else\n    numtoread = 0;\n  for (i = 0; i < numtoread; i++)\n    INPUT_BYTE(cinfo, b[i], return FALSE);\n  length -= numtoread;\n\n  /* process it */\n  switch (cinfo->unread_marker) {\n  case M_APP0:\n    examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length);\n    break;\n  case M_APP14:\n    examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length);\n    break;\n  default:\n    /* can't get here unless jpeg_save_markers chooses wrong processor */\n    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);\n  }\n\n  /* skip any remaining data -- could be lots */\n  INPUT_SYNC(cinfo);\n  if (length > 0)\n    (*cinfo->src->skip_input_data) (cinfo, (long) length);\n\n  return TRUE;\n}\n\n\n#ifdef SAVE_MARKERS_SUPPORTED\n\nMETHODDEF(boolean)\nsave_marker (j_decompress_ptr cinfo)\n/* Save an APPn or COM marker into the marker list */\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n  jpeg_saved_marker_ptr cur_marker = marker->cur_marker;\n  unsigned int bytes_read, data_length;\n  JOCTET FAR * data;\n  INT32 length = 0;\n  INPUT_VARS(cinfo);\n\n  if (cur_marker == NULL) {\n    /* begin reading a marker */\n    INPUT_2BYTES(cinfo, length, return FALSE);\n    length -= 2;\n    if (length >= 0) {\t\t/* watch out for bogus length word */\n      /* figure out how much we want to save */\n      unsigned int limit;\n      if (cinfo->unread_marker == (int) M_COM)\n\tlimit = marker->length_limit_COM;\n      else\n\tlimit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0];\n      if ((unsigned int) length < limit)\n\tlimit = (unsigned int) length;\n      /* allocate and initialize the marker item */\n      cur_marker = (jpeg_saved_marker_ptr)\n\t(*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\t    SIZEOF(struct jpeg_marker_struct) + limit);\n      cur_marker->next = NULL;\n      cur_marker->marker = (UINT8) cinfo->unread_marker;\n      cur_marker->original_length = (unsigned int) length;\n      cur_marker->data_length = limit;\n      /* data area is just beyond the jpeg_marker_struct */\n      data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1);\n      marker->cur_marker = cur_marker;\n      marker->bytes_read = 0;\n      bytes_read = 0;\n      data_length = limit;\n    } else {\n      /* deal with bogus length word */\n      bytes_read = data_length = 0;\n      data = NULL;\n    }\n  } else {\n    /* resume reading a marker */\n    bytes_read = marker->bytes_read;\n    data_length = cur_marker->data_length;\n    data = cur_marker->data + bytes_read;\n  }\n\n  while (bytes_read < data_length) {\n    INPUT_SYNC(cinfo);\t\t/* move the restart point to here */\n    marker->bytes_read = bytes_read;\n    /* If there's not at least one byte in buffer, suspend */\n    MAKE_BYTE_AVAIL(cinfo, return FALSE);\n    /* Copy bytes with reasonable rapidity */\n    while (bytes_read < data_length && bytes_in_buffer > 0) {\n      *data++ = *next_input_byte++;\n      bytes_in_buffer--;\n      bytes_read++;\n    }\n  }\n\n  /* Done reading what we want to read */\n  if (cur_marker != NULL) {\t/* will be NULL if bogus length word */\n    /* Add new marker to end of list */\n    if (cinfo->marker_list == NULL) {\n      cinfo->marker_list = cur_marker;\n    } else {\n      jpeg_saved_marker_ptr prev = cinfo->marker_list;\n      while (prev->next != NULL)\n\tprev = prev->next;\n      prev->next = cur_marker;\n    }\n    /* Reset pointer & calc remaining data length */\n    data = cur_marker->data;\n    length = cur_marker->original_length - data_length;\n  }\n  /* Reset to initial state for next marker */\n  marker->cur_marker = NULL;\n\n  /* Process the marker if interesting; else just make a generic trace msg */\n  switch (cinfo->unread_marker) {\n  case M_APP0:\n    examine_app0(cinfo, data, data_length, length);\n    break;\n  case M_APP14:\n    examine_app14(cinfo, data, data_length, length);\n    break;\n  default:\n    TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,\n\t     (int) (data_length + length));\n  }\n\n  /* skip any remaining data -- could be lots */\n  INPUT_SYNC(cinfo);\t\t/* do before skip_input_data */\n  if (length > 0)\n    (*cinfo->src->skip_input_data) (cinfo, (long) length);\n\n  return TRUE;\n}\n\n#endif /* SAVE_MARKERS_SUPPORTED */\n\n\nMETHODDEF(boolean)\nskip_variable (j_decompress_ptr cinfo)\n/* Skip over an unknown or uninteresting variable-length marker */\n{\n  INT32 length;\n  INPUT_VARS(cinfo);\n\n  INPUT_2BYTES(cinfo, length, return FALSE);\n  length -= 2;\n  \n  TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);\n\n  INPUT_SYNC(cinfo);\t\t/* do before skip_input_data */\n  if (length > 0)\n    (*cinfo->src->skip_input_data) (cinfo, (long) length);\n\n  return TRUE;\n}\n\n\n/*\n * Find the next JPEG marker, save it in cinfo->unread_marker.\n * Returns FALSE if had to suspend before reaching a marker;\n * in that case cinfo->unread_marker is unchanged.\n *\n * Note that the result might not be a valid marker code,\n * but it will never be 0 or FF.\n */\n\nLOCAL(boolean)\nnext_marker (j_decompress_ptr cinfo)\n{\n  int c;\n  INPUT_VARS(cinfo);\n\n  for (;;) {\n    INPUT_BYTE(cinfo, c, return FALSE);\n    /* Skip any non-FF bytes.\n     * This may look a bit inefficient, but it will not occur in a valid file.\n     * We sync after each discarded byte so that a suspending data source\n     * can discard the byte from its buffer.\n     */\n    while (c != 0xFF) {\n      cinfo->marker->discarded_bytes++;\n      INPUT_SYNC(cinfo);\n      INPUT_BYTE(cinfo, c, return FALSE);\n    }\n    /* This loop swallows any duplicate FF bytes.  Extra FFs are legal as\n     * pad bytes, so don't count them in discarded_bytes.  We assume there\n     * will not be so many consecutive FF bytes as to overflow a suspending\n     * data source's input buffer.\n     */\n    do {\n      INPUT_BYTE(cinfo, c, return FALSE);\n    } while (c == 0xFF);\n    if (c != 0)\n      break;\t\t\t/* found a valid marker, exit loop */\n    /* Reach here if we found a stuffed-zero data sequence (FF/00).\n     * Discard it and loop back to try again.\n     */\n    cinfo->marker->discarded_bytes += 2;\n    INPUT_SYNC(cinfo);\n  }\n\n  if (cinfo->marker->discarded_bytes != 0) {\n    WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);\n    cinfo->marker->discarded_bytes = 0;\n  }\n\n  cinfo->unread_marker = c;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\nLOCAL(boolean)\nfirst_marker (j_decompress_ptr cinfo)\n/* Like next_marker, but used to obtain the initial SOI marker. */\n/* For this marker, we do not allow preceding garbage or fill; otherwise,\n * we might well scan an entire input file before realizing it ain't JPEG.\n * If an application wants to process non-JFIF files, it must seek to the\n * SOI before calling the JPEG library.\n */\n{\n  int c, c2;\n  INPUT_VARS(cinfo);\n\n  INPUT_BYTE(cinfo, c, return FALSE);\n  INPUT_BYTE(cinfo, c2, return FALSE);\n  if (c != 0xFF || c2 != (int) M_SOI)\n    ERREXIT2(cinfo, JERR_NO_SOI, c, c2);\n\n  cinfo->unread_marker = c2;\n\n  INPUT_SYNC(cinfo);\n  return TRUE;\n}\n\n\n/*\n * Read markers until SOS or EOI.\n *\n * Returns same codes as are defined for jpeg_consume_input:\n * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.\n *\n * Note: This function may return a pseudo SOS marker (with zero\n * component number) for treat by input controller's consume_input.\n * consume_input itself should filter out (skip) the pseudo marker\n * after processing for the caller.\n */\n\nMETHODDEF(int)\nread_markers (j_decompress_ptr cinfo)\n{\n  /* Outer loop repeats once for each marker. */\n  for (;;) {\n    /* Collect the marker proper, unless we already did. */\n    /* NB: first_marker() enforces the requirement that SOI appear first. */\n    if (cinfo->unread_marker == 0) {\n      if (! cinfo->marker->saw_SOI) {\n\tif (! first_marker(cinfo))\n\t  return JPEG_SUSPENDED;\n      } else {\n\tif (! next_marker(cinfo))\n\t  return JPEG_SUSPENDED;\n      }\n    }\n    /* At this point cinfo->unread_marker contains the marker code and the\n     * input point is just past the marker proper, but before any parameters.\n     * A suspension will cause us to return with this state still true.\n     */\n    switch (cinfo->unread_marker) {\n    case M_SOI:\n      if (! get_soi(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_SOF0:\t\t/* Baseline */\n      if (! get_sof(cinfo, TRUE, FALSE, FALSE))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_SOF1:\t\t/* Extended sequential, Huffman */\n      if (! get_sof(cinfo, FALSE, FALSE, FALSE))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_SOF2:\t\t/* Progressive, Huffman */\n      if (! get_sof(cinfo, FALSE, TRUE, FALSE))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_SOF9:\t\t/* Extended sequential, arithmetic */\n      if (! get_sof(cinfo, FALSE, FALSE, TRUE))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_SOF10:\t\t/* Progressive, arithmetic */\n      if (! get_sof(cinfo, FALSE, TRUE, TRUE))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    /* Currently unsupported SOFn types */\n    case M_SOF3:\t\t/* Lossless, Huffman */\n    case M_SOF5:\t\t/* Differential sequential, Huffman */\n    case M_SOF6:\t\t/* Differential progressive, Huffman */\n    case M_SOF7:\t\t/* Differential lossless, Huffman */\n    case M_JPG:\t\t\t/* Reserved for JPEG extensions */\n    case M_SOF11:\t\t/* Lossless, arithmetic */\n    case M_SOF13:\t\t/* Differential sequential, arithmetic */\n    case M_SOF14:\t\t/* Differential progressive, arithmetic */\n    case M_SOF15:\t\t/* Differential lossless, arithmetic */\n      ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);\n      break;\n\n    case M_SOS:\n      if (! get_sos(cinfo))\n\treturn JPEG_SUSPENDED;\n      cinfo->unread_marker = 0;\t/* processed the marker */\n      return JPEG_REACHED_SOS;\n\n    case M_EOI:\n      TRACEMS(cinfo, 1, JTRC_EOI);\n      cinfo->unread_marker = 0;\t/* processed the marker */\n      return JPEG_REACHED_EOI;\n\n    case M_DAC:\n      if (! get_dac(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_DHT:\n      if (! get_dht(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_DQT:\n      if (! get_dqt(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_DRI:\n      if (! get_dri(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_JPG8:\n      if (! get_lse(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_APP0:\n    case M_APP1:\n    case M_APP2:\n    case M_APP3:\n    case M_APP4:\n    case M_APP5:\n    case M_APP6:\n    case M_APP7:\n    case M_APP8:\n    case M_APP9:\n    case M_APP10:\n    case M_APP11:\n    case M_APP12:\n    case M_APP13:\n    case M_APP14:\n    case M_APP15:\n      if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[\n\t\tcinfo->unread_marker - (int) M_APP0]) (cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_COM:\n      if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    case M_RST0:\t\t/* these are all parameterless */\n    case M_RST1:\n    case M_RST2:\n    case M_RST3:\n    case M_RST4:\n    case M_RST5:\n    case M_RST6:\n    case M_RST7:\n    case M_TEM:\n      TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);\n      break;\n\n    case M_DNL:\t\t\t/* Ignore DNL ... perhaps the wrong thing */\n      if (! skip_variable(cinfo))\n\treturn JPEG_SUSPENDED;\n      break;\n\n    default:\t\t\t/* must be DHP, EXP, JPGn, or RESn */\n      /* For now, we treat the reserved markers as fatal errors since they are\n       * likely to be used to signal incompatible JPEG Part 3 extensions.\n       * Once the JPEG 3 version-number marker is well defined, this code\n       * ought to change!\n       */\n      ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);\n    }\n    /* Successfully processed marker, so reset state variable */\n    cinfo->unread_marker = 0;\n  } /* end loop */\n}\n\n\n/*\n * Read a restart marker, which is expected to appear next in the datastream;\n * if the marker is not there, take appropriate recovery action.\n * Returns FALSE if suspension is required.\n *\n * This is called by the entropy decoder after it has read an appropriate\n * number of MCUs.  cinfo->unread_marker may be nonzero if the entropy decoder\n * has already read a marker from the data source.  Under normal conditions\n * cinfo->unread_marker will be reset to 0 before returning; if not reset,\n * it holds a marker which the decoder will be unable to read past.\n */\n\nMETHODDEF(boolean)\nread_restart_marker (j_decompress_ptr cinfo)\n{\n  /* Obtain a marker unless we already did. */\n  /* Note that next_marker will complain if it skips any data. */\n  if (cinfo->unread_marker == 0) {\n    if (! next_marker(cinfo))\n      return FALSE;\n  }\n\n  if (cinfo->unread_marker ==\n      ((int) M_RST0 + cinfo->marker->next_restart_num)) {\n    /* Normal case --- swallow the marker and let entropy decoder continue */\n    TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);\n    cinfo->unread_marker = 0;\n  } else {\n    /* Uh-oh, the restart markers have been messed up. */\n    /* Let the data source manager determine how to resync. */\n    if (! (*cinfo->src->resync_to_restart) (cinfo,\n\t\t\t\t\t    cinfo->marker->next_restart_num))\n      return FALSE;\n  }\n\n  /* Update next-restart state */\n  cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;\n\n  return TRUE;\n}\n\n\n/*\n * This is the default resync_to_restart method for data source managers\n * to use if they don't have any better approach.  Some data source managers\n * may be able to back up, or may have additional knowledge about the data\n * which permits a more intelligent recovery strategy; such managers would\n * presumably supply their own resync method.\n *\n * read_restart_marker calls resync_to_restart if it finds a marker other than\n * the restart marker it was expecting.  (This code is *not* used unless\n * a nonzero restart interval has been declared.)  cinfo->unread_marker is\n * the marker code actually found (might be anything, except 0 or FF).\n * The desired restart marker number (0..7) is passed as a parameter.\n * This routine is supposed to apply whatever error recovery strategy seems\n * appropriate in order to position the input stream to the next data segment.\n * Note that cinfo->unread_marker is treated as a marker appearing before\n * the current data-source input point; usually it should be reset to zero\n * before returning.\n * Returns FALSE if suspension is required.\n *\n * This implementation is substantially constrained by wanting to treat the\n * input as a data stream; this means we can't back up.  Therefore, we have\n * only the following actions to work with:\n *   1. Simply discard the marker and let the entropy decoder resume at next\n *      byte of file.\n *   2. Read forward until we find another marker, discarding intervening\n *      data.  (In theory we could look ahead within the current bufferload,\n *      without having to discard data if we don't find the desired marker.\n *      This idea is not implemented here, in part because it makes behavior\n *      dependent on buffer size and chance buffer-boundary positions.)\n *   3. Leave the marker unread (by failing to zero cinfo->unread_marker).\n *      This will cause the entropy decoder to process an empty data segment,\n *      inserting dummy zeroes, and then we will reprocess the marker.\n *\n * #2 is appropriate if we think the desired marker lies ahead, while #3 is\n * appropriate if the found marker is a future restart marker (indicating\n * that we have missed the desired restart marker, probably because it got\n * corrupted).\n * We apply #2 or #3 if the found marker is a restart marker no more than\n * two counts behind or ahead of the expected one.  We also apply #2 if the\n * found marker is not a legal JPEG marker code (it's certainly bogus data).\n * If the found marker is a restart marker more than 2 counts away, we do #1\n * (too much risk that the marker is erroneous; with luck we will be able to\n * resync at some future point).\n * For any valid non-restart JPEG marker, we apply #3.  This keeps us from\n * overrunning the end of a scan.  An implementation limited to single-scan\n * files might find it better to apply #2 for markers other than EOI, since\n * any other marker would have to be bogus data in that case.\n */\n\nGLOBAL(boolean)\njpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)\n{\n  int marker = cinfo->unread_marker;\n  int action = 1;\n  \n  /* Always put up a warning. */\n  WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);\n  \n  /* Outer loop handles repeated decision after scanning forward. */\n  for (;;) {\n    if (marker < (int) M_SOF0)\n      action = 2;\t\t/* invalid marker */\n    else if (marker < (int) M_RST0 || marker > (int) M_RST7)\n      action = 3;\t\t/* valid non-restart marker */\n    else {\n      if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||\n\t  marker == ((int) M_RST0 + ((desired+2) & 7)))\n\taction = 3;\t\t/* one of the next two expected restarts */\n      else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||\n\t       marker == ((int) M_RST0 + ((desired-2) & 7)))\n\taction = 2;\t\t/* a prior restart, so advance */\n      else\n\taction = 1;\t\t/* desired restart or too far away */\n    }\n    TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);\n    switch (action) {\n    case 1:\n      /* Discard marker and let entropy decoder resume processing. */\n      cinfo->unread_marker = 0;\n      return TRUE;\n    case 2:\n      /* Scan to the next marker, and repeat the decision loop. */\n      if (! next_marker(cinfo))\n\treturn FALSE;\n      marker = cinfo->unread_marker;\n      break;\n    case 3:\n      /* Return without advancing past this marker. */\n      /* Entropy decoder will be forced to process an empty segment. */\n      return TRUE;\n    }\n  } /* end loop */\n}\n\n\n/*\n * Reset marker processing state to begin a fresh datastream.\n */\n\nMETHODDEF(void)\nreset_marker_reader (j_decompress_ptr cinfo)\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n\n  cinfo->comp_info = NULL;\t\t/* until allocated by get_sof */\n  cinfo->input_scan_number = 0;\t\t/* no SOS seen yet */\n  cinfo->unread_marker = 0;\t\t/* no pending marker */\n  marker->pub.saw_SOI = FALSE;\t\t/* set internal state too */\n  marker->pub.saw_SOF = FALSE;\n  marker->pub.discarded_bytes = 0;\n  marker->cur_marker = NULL;\n}\n\n\n/*\n * Initialize the marker reader module.\n * This is called only once, when the decompression object is created.\n */\n\nGLOBAL(void)\njinit_marker_reader (j_decompress_ptr cinfo)\n{\n  my_marker_ptr marker;\n  int i;\n\n  /* Create subobject in permanent pool */\n  marker = (my_marker_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_PERMANENT, SIZEOF(my_marker_reader));\n  cinfo->marker = &marker->pub;\n  /* Initialize public method pointers */\n  marker->pub.reset_marker_reader = reset_marker_reader;\n  marker->pub.read_markers = read_markers;\n  marker->pub.read_restart_marker = read_restart_marker;\n  /* Initialize COM/APPn processing.\n   * By default, we examine and then discard APP0 and APP14,\n   * but simply discard COM and all other APPn.\n   */\n  marker->process_COM = skip_variable;\n  marker->length_limit_COM = 0;\n  for (i = 0; i < 16; i++) {\n    marker->process_APPn[i] = skip_variable;\n    marker->length_limit_APPn[i] = 0;\n  }\n  marker->process_APPn[0] = get_interesting_appn;\n  marker->process_APPn[14] = get_interesting_appn;\n  /* Reset marker processing state */\n  reset_marker_reader(cinfo);\n}\n\n\n/*\n * Control saving of COM and APPn markers into marker_list.\n */\n\n#ifdef SAVE_MARKERS_SUPPORTED\n\nGLOBAL(void)\njpeg_save_markers (j_decompress_ptr cinfo, int marker_code,\n\t\t   unsigned int length_limit)\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n  long maxlength;\n  jpeg_marker_parser_method processor;\n\n  /* Length limit mustn't be larger than what we can allocate\n   * (should only be a concern in a 16-bit environment).\n   */\n  maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct);\n  if (((long) length_limit) > maxlength)\n    length_limit = (unsigned int) maxlength;\n\n  /* Choose processor routine to use.\n   * APP0/APP14 have special requirements.\n   */\n  if (length_limit) {\n    processor = save_marker;\n    /* If saving APP0/APP14, save at least enough for our internal use. */\n    if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN)\n      length_limit = APP0_DATA_LEN;\n    else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN)\n      length_limit = APP14_DATA_LEN;\n  } else {\n    processor = skip_variable;\n    /* If discarding APP0/APP14, use our regular on-the-fly processor. */\n    if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14)\n      processor = get_interesting_appn;\n  }\n\n  if (marker_code == (int) M_COM) {\n    marker->process_COM = processor;\n    marker->length_limit_COM = length_limit;\n  } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) {\n    marker->process_APPn[marker_code - (int) M_APP0] = processor;\n    marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit;\n  } else\n    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);\n}\n\n#endif /* SAVE_MARKERS_SUPPORTED */\n\n\n/*\n * Install a special processing method for COM or APPn markers.\n */\n\nGLOBAL(void)\njpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,\n\t\t\t   jpeg_marker_parser_method routine)\n{\n  my_marker_ptr marker = (my_marker_ptr) cinfo->marker;\n\n  if (marker_code == (int) M_COM)\n    marker->process_COM = routine;\n  else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15)\n    marker->process_APPn[marker_code - (int) M_APP0] = routine;\n  else\n    ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdmaster.c",
    "content": "/*\n * jdmaster.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains master control logic for the JPEG decompressor.\n * These routines are concerned with selecting the modules to be executed\n * and with determining the number of passes and the work to be done in each\n * pass.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Private state */\n\ntypedef struct {\n  struct jpeg_decomp_master pub; /* public fields */\n\n  int pass_number;\t\t/* # of passes completed */\n\n  boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */\n\n  /* Saved references to initialized quantizer modules,\n   * in case we need to switch modes.\n   */\n  struct jpeg_color_quantizer * quantizer_1pass;\n  struct jpeg_color_quantizer * quantizer_2pass;\n} my_decomp_master;\n\ntypedef my_decomp_master * my_master_ptr;\n\n\n/*\n * Determine whether merged upsample/color conversion should be used.\n * CRUCIAL: this must match the actual capabilities of jdmerge.c!\n */\n\nLOCAL(boolean)\nuse_merged_upsample (j_decompress_ptr cinfo)\n{\n#ifdef UPSAMPLE_MERGING_SUPPORTED\n  /* Merging is the equivalent of plain box-filter upsampling. */\n  /* The following condition is only needed if fancy shall select\n   * a different upsampling method.  In our current implementation\n   * fancy only affects the DCT scaling, thus we can use fancy\n   * upsampling and merged upsample simultaneously, in particular\n   * with scaled DCT sizes larger than the default DCTSIZE.\n   */\n#if 0\n  if (cinfo->do_fancy_upsampling)\n    return FALSE;\n#endif\n  if (cinfo->CCIR601_sampling)\n    return FALSE;\n  /* jdmerge.c only supports YCC=>RGB color conversion */\n  if ((cinfo->jpeg_color_space != JCS_YCbCr &&\n       cinfo->jpeg_color_space != JCS_BG_YCC) ||\n      cinfo->num_components != 3 ||\n      cinfo->out_color_space != JCS_RGB ||\n      cinfo->out_color_components != RGB_PIXELSIZE ||\n      cinfo->color_transform)\n    return FALSE;\n  /* and it only handles 2h1v or 2h2v sampling ratios */\n  if (cinfo->comp_info[0].h_samp_factor != 2 ||\n      cinfo->comp_info[1].h_samp_factor != 1 ||\n      cinfo->comp_info[2].h_samp_factor != 1 ||\n      cinfo->comp_info[0].v_samp_factor >  2 ||\n      cinfo->comp_info[1].v_samp_factor != 1 ||\n      cinfo->comp_info[2].v_samp_factor != 1)\n    return FALSE;\n  /* furthermore, it doesn't work if we've scaled the IDCTs differently */\n  if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||\n      cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||\n      cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||\n      cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||\n      cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||\n      cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size)\n    return FALSE;\n  /* ??? also need to test for upsample-time rescaling, when & if supported */\n  return TRUE;\t\t\t/* by golly, it'll work... */\n#else\n  return FALSE;\n#endif\n}\n\n\n/*\n * Compute output image dimensions and related values.\n * NOTE: this is exported for possible use by application.\n * Hence it mustn't do anything that can't be done twice.\n * Also note that it may be called before the master module is initialized!\n */\n\nGLOBAL(void)\njpeg_calc_output_dimensions (j_decompress_ptr cinfo)\n/* Do computations that are needed before master selection phase.\n * This function is used for full decompression.\n */\n{\n  int ci, i;\n  jpeg_component_info *compptr;\n\n  /* Prevent application from calling me at wrong times */\n  if (cinfo->global_state != DSTATE_READY)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  /* Compute core output image dimensions and DCT scaling choices. */\n  jpeg_core_output_dimensions(cinfo);\n\n#ifdef IDCT_SCALING_SUPPORTED\n\n  /* In selecting the actual DCT scaling for each component, we try to\n   * scale up the chroma components via IDCT scaling rather than upsampling.\n   * This saves time if the upsampler gets to use 1:1 scaling.\n   * Note this code adapts subsampling ratios which are powers of 2.\n   */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    int ssize = 1;\n    if (! cinfo->raw_data_out)\n      while (cinfo->min_DCT_h_scaled_size * ssize <=\n\t     (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&\n\t     (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) ==\n\t     0) {\n\tssize = ssize * 2;\n      }\n    compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;\n    ssize = 1;\n    if (! cinfo->raw_data_out)\n      while (cinfo->min_DCT_v_scaled_size * ssize <=\n\t     (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&\n\t     (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) ==\n\t     0) {\n\tssize = ssize * 2;\n      }\n    compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;\n\n    /* We don't support IDCT ratios larger than 2. */\n    if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)\n\tcompptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;\n    else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)\n\tcompptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;\n\n    /* Recompute downsampled dimensions of components;\n     * application needs to know these if using raw downsampled data.\n     */\n    /* Size in samples, after IDCT scaling */\n    compptr->downsampled_width = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_width *\n\t\t    (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),\n\t\t    (long) (cinfo->max_h_samp_factor * cinfo->block_size));\n    compptr->downsampled_height = (JDIMENSION)\n      jdiv_round_up((long) cinfo->image_height *\n\t\t    (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),\n\t\t    (long) (cinfo->max_v_samp_factor * cinfo->block_size));\n  }\n\n#endif /* IDCT_SCALING_SUPPORTED */\n\n  /* Report number of components in selected colorspace. */\n  /* This should correspond to the actual code in the color conversion module. */\n  switch (cinfo->out_color_space) {\n  case JCS_GRAYSCALE:\n    cinfo->out_color_components = 1;\n    break;\n  case JCS_RGB:\n  case JCS_BG_RGB:\n    cinfo->out_color_components = RGB_PIXELSIZE;\n    break;\n  default:\t/* YCCK <=> CMYK conversion or same colorspace as in file */\n    i = 0;\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++)\n      if (compptr->component_needed)\n\ti++;\t/* count output color components */\n    cinfo->out_color_components = i;\n  }\n  cinfo->output_components = (cinfo->quantize_colors ? 1 :\n\t\t\t      cinfo->out_color_components);\n\n  /* See if upsampler will want to emit more than one row at a time */\n  if (use_merged_upsample(cinfo))\n    cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;\n  else\n    cinfo->rec_outbuf_height = 1;\n}\n\n\n/*\n * Several decompression processes need to range-limit values to the range\n * 0..MAXJSAMPLE; the input value may fall somewhat outside this range\n * due to noise introduced by quantization, roundoff error, etc.  These\n * processes are inner loops and need to be as fast as possible.  On most\n * machines, particularly CPUs with pipelines or instruction prefetch,\n * a (subscript-check-less) C table lookup\n *\t\tx = sample_range_limit[x];\n * is faster than explicit tests\n *\t\tif (x < 0)  x = 0;\n *\t\telse if (x > MAXJSAMPLE)  x = MAXJSAMPLE;\n * These processes all use a common table prepared by the routine below.\n *\n * For most steps we can mathematically guarantee that the initial value\n * of x is within 2*(MAXJSAMPLE+1) of the legal range, so a table running\n * from -2*(MAXJSAMPLE+1) to 3*MAXJSAMPLE+2 is sufficient.  But for the\n * initial limiting step (just after the IDCT), a wildly out-of-range value\n * is possible if the input data is corrupt.  To avoid any chance of indexing\n * off the end of memory and getting a bad-pointer trap, we perform the\n * post-IDCT limiting thus:\n *\t\tx = (sample_range_limit - SUBSET)[(x + CENTER) & MASK];\n * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit\n * samples.  Under normal circumstances this is more than enough range and\n * a correct output will be generated; with bogus input data the mask will\n * cause wraparound, and we will safely generate a bogus-but-in-range output.\n * For the post-IDCT step, we want to convert the data from signed to unsigned\n * representation by adding CENTERJSAMPLE at the same time that we limit it.\n * This is accomplished with SUBSET = CENTER - CENTERJSAMPLE.\n *\n * Note that the table is allocated in near data space on PCs; it's small\n * enough and used often enough to justify this.\n */\n\nLOCAL(void)\nprepare_range_limit_table (j_decompress_ptr cinfo)\n/* Allocate and fill in the sample_range_limit table */\n{\n  JSAMPLE * table;\n  int i;\n\n  table = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, (RANGE_CENTER * 2 + MAXJSAMPLE + 1) * SIZEOF(JSAMPLE));\n  /* First segment of range limit table: limit[x] = 0 for x < 0 */\n  MEMZERO(table, RANGE_CENTER * SIZEOF(JSAMPLE));\n  table += RANGE_CENTER;\t/* allow negative subscripts of table */\n  cinfo->sample_range_limit = table;\n  /* Main part of range limit table: limit[x] = x */\n  for (i = 0; i <= MAXJSAMPLE; i++)\n    table[i] = (JSAMPLE) i;\n  /* End of range limit table: limit[x] = MAXJSAMPLE for x > MAXJSAMPLE */\n  for (; i <=  MAXJSAMPLE + RANGE_CENTER; i++)\n    table[i] = MAXJSAMPLE;\n}\n\n\n/*\n * Master selection of decompression modules.\n * This is done once at jpeg_start_decompress time.  We determine\n * which modules will be used and give them appropriate initialization calls.\n * We also initialize the decompressor input side to begin consuming data.\n *\n * Since jpeg_read_header has finished, we know what is in the SOF\n * and (first) SOS markers.  We also have all the application parameter\n * settings.\n */\n\nLOCAL(void)\nmaster_selection (j_decompress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n  boolean use_c_buffer;\n  long samplesperrow;\n  JDIMENSION jd_samplesperrow;\n\n  /* For now, precision must match compiled-in value... */\n  if (cinfo->data_precision != BITS_IN_JSAMPLE)\n    ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);\n\n  /* Initialize dimensions and other stuff */\n  jpeg_calc_output_dimensions(cinfo);\n  prepare_range_limit_table(cinfo);\n\n  /* Sanity check on image dimensions */\n  if (cinfo->output_height <= 0 || cinfo->output_width <= 0 ||\n      cinfo->out_color_components <= 0)\n    ERREXIT(cinfo, JERR_EMPTY_IMAGE);\n\n  /* Width of an output scanline must be representable as JDIMENSION. */\n  samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;\n  jd_samplesperrow = (JDIMENSION) samplesperrow;\n  if ((long) jd_samplesperrow != samplesperrow)\n    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\n\n  /* Initialize my private state */\n  master->pass_number = 0;\n  master->using_merged_upsample = use_merged_upsample(cinfo);\n\n  /* Color quantizer selection */\n  master->quantizer_1pass = NULL;\n  master->quantizer_2pass = NULL;\n  /* No mode changes if not using buffered-image mode. */\n  if (! cinfo->quantize_colors || ! cinfo->buffered_image) {\n    cinfo->enable_1pass_quant = FALSE;\n    cinfo->enable_external_quant = FALSE;\n    cinfo->enable_2pass_quant = FALSE;\n  }\n  if (cinfo->quantize_colors) {\n    if (cinfo->raw_data_out)\n      ERREXIT(cinfo, JERR_NOTIMPL);\n    /* 2-pass quantizer only works in 3-component color space. */\n    if (cinfo->out_color_components != 3) {\n      cinfo->enable_1pass_quant = TRUE;\n      cinfo->enable_external_quant = FALSE;\n      cinfo->enable_2pass_quant = FALSE;\n      cinfo->colormap = NULL;\n    } else if (cinfo->colormap != NULL) {\n      cinfo->enable_external_quant = TRUE;\n    } else if (cinfo->two_pass_quantize) {\n      cinfo->enable_2pass_quant = TRUE;\n    } else {\n      cinfo->enable_1pass_quant = TRUE;\n    }\n\n    if (cinfo->enable_1pass_quant) {\n#ifdef QUANT_1PASS_SUPPORTED\n      jinit_1pass_quantizer(cinfo);\n      master->quantizer_1pass = cinfo->cquantize;\n#else\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n    }\n\n    /* We use the 2-pass code to map to external colormaps. */\n    if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {\n#ifdef QUANT_2PASS_SUPPORTED\n      jinit_2pass_quantizer(cinfo);\n      master->quantizer_2pass = cinfo->cquantize;\n#else\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n    }\n    /* If both quantizers are initialized, the 2-pass one is left active;\n     * this is necessary for starting with quantization to an external map.\n     */\n  }\n\n  /* Post-processing: in particular, color conversion first */\n  if (! cinfo->raw_data_out) {\n    if (master->using_merged_upsample) {\n#ifdef UPSAMPLE_MERGING_SUPPORTED\n      jinit_merged_upsampler(cinfo); /* does color conversion too */\n#else\n      ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif\n    } else {\n      jinit_color_deconverter(cinfo);\n      jinit_upsampler(cinfo);\n    }\n    jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);\n  }\n  /* Inverse DCT */\n  jinit_inverse_dct(cinfo);\n  /* Entropy decoding: either Huffman or arithmetic coding. */\n  if (cinfo->arith_code)\n    jinit_arith_decoder(cinfo);\n  else {\n    jinit_huff_decoder(cinfo);\n  }\n\n  /* Initialize principal buffer controllers. */\n  use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;\n  jinit_d_coef_controller(cinfo, use_c_buffer);\n\n  if (! cinfo->raw_data_out)\n    jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);\n\n  /* We can now tell the memory manager to allocate virtual arrays. */\n  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);\n\n  /* Initialize input side of decompressor to consume first scan. */\n  (*cinfo->inputctl->start_input_pass) (cinfo);\n\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n  /* If jpeg_start_decompress will read the whole file, initialize\n   * progress monitoring appropriately.  The input step is counted\n   * as one pass.\n   */\n  if (cinfo->progress != NULL && ! cinfo->buffered_image &&\n      cinfo->inputctl->has_multiple_scans) {\n    int nscans;\n    /* Estimate number of scans to set pass_limit. */\n    if (cinfo->progressive_mode) {\n      /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */\n      nscans = 2 + 3 * cinfo->num_components;\n    } else {\n      /* For a nonprogressive multiscan file, estimate 1 scan per component. */\n      nscans = cinfo->num_components;\n    }\n    cinfo->progress->pass_counter = 0L;\n    cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;\n    cinfo->progress->completed_passes = 0;\n    cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);\n    /* Count the input pass as done */\n    master->pass_number++;\n  }\n#endif /* D_MULTISCAN_FILES_SUPPORTED */\n}\n\n\n/*\n * Per-pass setup.\n * This is called at the beginning of each output pass.  We determine which\n * modules will be active during this pass and give them appropriate\n * start_pass calls.  We also set is_dummy_pass to indicate whether this\n * is a \"real\" output pass or a dummy pass for color quantization.\n * (In the latter case, jdapistd.c will crank the pass to completion.)\n */\n\nMETHODDEF(void)\nprepare_for_output_pass (j_decompress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n\n  if (master->pub.is_dummy_pass) {\n#ifdef QUANT_2PASS_SUPPORTED\n    /* Final pass of 2-pass quantization */\n    master->pub.is_dummy_pass = FALSE;\n    (*cinfo->cquantize->start_pass) (cinfo, FALSE);\n    (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);\n    (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);\n#else\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n#endif /* QUANT_2PASS_SUPPORTED */\n  } else {\n    if (cinfo->quantize_colors && cinfo->colormap == NULL) {\n      /* Select new quantization method */\n      if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {\n\tcinfo->cquantize = master->quantizer_2pass;\n\tmaster->pub.is_dummy_pass = TRUE;\n      } else if (cinfo->enable_1pass_quant) {\n\tcinfo->cquantize = master->quantizer_1pass;\n      } else {\n\tERREXIT(cinfo, JERR_MODE_CHANGE);\n      }\n    }\n    (*cinfo->idct->start_pass) (cinfo);\n    (*cinfo->coef->start_output_pass) (cinfo);\n    if (! cinfo->raw_data_out) {\n      if (! master->using_merged_upsample)\n\t(*cinfo->cconvert->start_pass) (cinfo);\n      (*cinfo->upsample->start_pass) (cinfo);\n      if (cinfo->quantize_colors)\n\t(*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);\n      (*cinfo->post->start_pass) (cinfo,\n\t    (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));\n      (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);\n    }\n  }\n\n  /* Set up progress monitor's pass info if present */\n  if (cinfo->progress != NULL) {\n    cinfo->progress->completed_passes = master->pass_number;\n    cinfo->progress->total_passes = master->pass_number +\n\t\t\t\t    (master->pub.is_dummy_pass ? 2 : 1);\n    /* In buffered-image mode, we assume one more output pass if EOI not\n     * yet reached, but no more passes if EOI has been reached.\n     */\n    if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {\n      cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);\n    }\n  }\n}\n\n\n/*\n * Finish up at end of an output pass.\n */\n\nMETHODDEF(void)\nfinish_output_pass (j_decompress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n\n  if (cinfo->quantize_colors)\n    (*cinfo->cquantize->finish_pass) (cinfo);\n  master->pass_number++;\n}\n\n\n#ifdef D_MULTISCAN_FILES_SUPPORTED\n\n/*\n * Switch to a new external colormap between output passes.\n */\n\nGLOBAL(void)\njpeg_new_colormap (j_decompress_ptr cinfo)\n{\n  my_master_ptr master = (my_master_ptr) cinfo->master;\n\n  /* Prevent application from calling me at wrong times */\n  if (cinfo->global_state != DSTATE_BUFIMAGE)\n    ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n\n  if (cinfo->quantize_colors && cinfo->enable_external_quant &&\n      cinfo->colormap != NULL) {\n    /* Select 2-pass quantizer for external colormap use */\n    cinfo->cquantize = master->quantizer_2pass;\n    /* Notify quantizer of colormap change */\n    (*cinfo->cquantize->new_color_map) (cinfo);\n    master->pub.is_dummy_pass = FALSE; /* just in case */\n  } else\n    ERREXIT(cinfo, JERR_MODE_CHANGE);\n}\n\n#endif /* D_MULTISCAN_FILES_SUPPORTED */\n\n\n/*\n * Initialize master decompression control and select active modules.\n * This is performed at the start of jpeg_start_decompress.\n */\n\nGLOBAL(void)\njinit_master_decompress (j_decompress_ptr cinfo)\n{\n  my_master_ptr master;\n\n  master = (my_master_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_decomp_master));\n  cinfo->master = &master->pub;\n  master->pub.prepare_for_output_pass = prepare_for_output_pass;\n  master->pub.finish_output_pass = finish_output_pass;\n\n  master->pub.is_dummy_pass = FALSE;\n\n  master_selection(cinfo);\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdmerge.c",
    "content": "/*\n * jdmerge.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2013-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains code for merged upsampling/color conversion.\n *\n * This file combines functions from jdsample.c and jdcolor.c;\n * read those files first to understand what's going on.\n *\n * When the chroma components are to be upsampled by simple replication\n * (ie, box filtering), we can save some work in color conversion by\n * calculating all the output pixels corresponding to a pair of chroma\n * samples at one time.  In the conversion equations\n *\tR = Y           + K1 * Cr\n *\tG = Y + K2 * Cb + K3 * Cr\n *\tB = Y + K4 * Cb\n * only the Y term varies among the group of pixels corresponding to a pair\n * of chroma samples, so the rest of the terms can be calculated just once.\n * At typical sampling ratios, this eliminates half or three-quarters of the\n * multiplications needed for color conversion.\n *\n * This file currently provides implementations for the following cases:\n *\tYCC => RGB color conversion only (YCbCr or BG_YCC).\n *\tSampling ratios of 2h1v or 2h2v.\n *\tNo scaling needed at upsample time.\n *\tCorner-aligned (non-CCIR601) sampling alignment.\n * Other special cases could be added, but in most applications these are\n * the only common cases.  (For uncommon cases we fall back on the more\n * general code in jdsample.c and jdcolor.c.)\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n#ifdef UPSAMPLE_MERGING_SUPPORTED\n\n\n#if RANGE_BITS < 2\n  /* Deliberate syntax err */\n  Sorry, this code requires 2 or more range extension bits.\n#endif\n\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_upsampler pub;\t/* public fields */\n\n  /* Pointer to routine to do actual upsampling/conversion of one row group */\n  JMETHOD(void, upmethod, (j_decompress_ptr cinfo,\n\t\t\t   JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,\n\t\t\t   JSAMPARRAY output_buf));\n\n  /* Private state for YCC->RGB conversion */\n  int * Cr_r_tab;\t\t/* => table for Cr to R conversion */\n  int * Cb_b_tab;\t\t/* => table for Cb to B conversion */\n  INT32 * Cr_g_tab;\t\t/* => table for Cr to G conversion */\n  INT32 * Cb_g_tab;\t\t/* => table for Cb to G conversion */\n\n  /* For 2:1 vertical sampling, we produce two output rows at a time.\n   * We need a \"spare\" row buffer to hold the second output row if the\n   * application provides just a one-row buffer; we also use the spare\n   * to discard the dummy last row if the image height is odd.\n   */\n  JSAMPROW spare_row;\n  boolean spare_full;\t\t/* T if spare buffer is occupied */\n\n  JDIMENSION out_row_width;\t/* samples per output row */\n  JDIMENSION rows_to_go;\t/* counts rows remaining in image */\n} my_upsampler;\n\ntypedef my_upsampler * my_upsample_ptr;\n\n#define SCALEBITS\t16\t/* speediest right-shift on some machines */\n#define ONE_HALF\t((INT32) 1 << (SCALEBITS-1))\n#define FIX(x)\t\t((INT32) ((x) * (1L<<SCALEBITS) + 0.5))\n\n\n/*\n * Initialize tables for YCbCr->RGB and BG_YCC->RGB colorspace conversion.\n * This is taken directly from jdcolor.c; see that file for more info.\n */\n\nLOCAL(void)\nbuild_ycc_rgb_table (j_decompress_ptr cinfo)\n/* Normal case, sYCC */\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  int i;\n  INT32 x;\n  SHIFT_TEMPS\n\n  upsample->Cr_r_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  upsample->Cb_b_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  upsample->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n  upsample->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n\n  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {\n    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */\n    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */\n    /* Cr=>R value is nearest int to 1.402 * x */\n    upsample->Cr_r_tab[i] = (int) DESCALE(FIX(1.402) * x, SCALEBITS);\n    /* Cb=>B value is nearest int to 1.772 * x */\n    upsample->Cb_b_tab[i] = (int) DESCALE(FIX(1.772) * x, SCALEBITS);\n    /* Cr=>G value is scaled-up -0.714136286 * x */\n    upsample->Cr_g_tab[i] = (- FIX(0.714136286)) * x;\n    /* Cb=>G value is scaled-up -0.344136286 * x */\n    /* We also add in ONE_HALF so that need not do it in inner loop */\n    upsample->Cb_g_tab[i] = (- FIX(0.344136286)) * x + ONE_HALF;\n  }\n}\n\n\nLOCAL(void)\nbuild_bg_ycc_rgb_table (j_decompress_ptr cinfo)\n/* Wide gamut case, bg-sYCC */\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  int i;\n  INT32 x;\n  SHIFT_TEMPS\n\n  upsample->Cr_r_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  upsample->Cb_b_tab = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(int));\n  upsample->Cr_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n  upsample->Cb_g_tab = (INT32 *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE+1) * SIZEOF(INT32));\n\n  for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {\n    /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */\n    /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */\n    /* Cr=>R value is nearest int to 2.804 * x */\n    upsample->Cr_r_tab[i] = (int) DESCALE(FIX(2.804) * x, SCALEBITS);\n    /* Cb=>B value is nearest int to 3.544 * x */\n    upsample->Cb_b_tab[i] = (int) DESCALE(FIX(3.544) * x, SCALEBITS);\n    /* Cr=>G value is scaled-up -1.428272572 * x */\n    upsample->Cr_g_tab[i] = (- FIX(1.428272572)) * x;\n    /* Cb=>G value is scaled-up -0.688272572 * x */\n    /* We also add in ONE_HALF so that need not do it in inner loop */\n    upsample->Cb_g_tab[i] = (- FIX(0.688272572)) * x + ONE_HALF;\n  }\n}\n\n\n/*\n * Initialize for an upsampling pass.\n */\n\nMETHODDEF(void)\nstart_pass_merged_upsample (j_decompress_ptr cinfo)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n\n  /* Mark the spare buffer empty */\n  upsample->spare_full = FALSE;\n  /* Initialize total-height counter for detecting bottom of image */\n  upsample->rows_to_go = cinfo->output_height;\n}\n\n\n/*\n * Control routine to do upsampling (and color conversion).\n *\n * The control routine just handles the row buffering considerations.\n */\n\nMETHODDEF(void)\nmerged_2v_upsample (j_decompress_ptr cinfo,\n\t\t    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t\t    JDIMENSION in_row_groups_avail,\n\t\t    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t    JDIMENSION out_rows_avail)\n/* 2:1 vertical sampling case: may need a spare row. */\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  JSAMPROW work_ptrs[2];\n  JDIMENSION num_rows;\t\t/* number of rows returned to caller */\n\n  if (upsample->spare_full) {\n    /* If we have a spare row saved from a previous cycle, just return it. */\n    jcopy_sample_rows(& upsample->spare_row, output_buf + *out_row_ctr,\n\t\t      1, upsample->out_row_width);\n    num_rows = 1;\n    upsample->spare_full = FALSE;\n  } else {\n    /* Figure number of rows to return to caller. */\n    num_rows = 2;\n    /* Not more than the distance to the end of the image. */\n    if (num_rows > upsample->rows_to_go)\n      num_rows = upsample->rows_to_go;\n    /* And not more than what the client can accept: */\n    out_rows_avail -= *out_row_ctr;\n    if (num_rows > out_rows_avail)\n      num_rows = out_rows_avail;\n    /* Create output pointer array for upsampler. */\n    work_ptrs[0] = output_buf[*out_row_ctr];\n    if (num_rows > 1) {\n      work_ptrs[1] = output_buf[*out_row_ctr + 1];\n    } else {\n      work_ptrs[1] = upsample->spare_row;\n      upsample->spare_full = TRUE;\n    }\n    /* Now do the upsampling. */\n    (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);\n  }\n\n  /* Adjust counts */\n  *out_row_ctr += num_rows;\n  upsample->rows_to_go -= num_rows;\n  /* When the buffer is emptied, declare this input row group consumed */\n  if (! upsample->spare_full)\n    (*in_row_group_ctr)++;\n}\n\n\nMETHODDEF(void)\nmerged_1v_upsample (j_decompress_ptr cinfo,\n\t\t    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t\t    JDIMENSION in_row_groups_avail,\n\t\t    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t    JDIMENSION out_rows_avail)\n/* 1:1 vertical sampling case: much easier, never need a spare row. */\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n\n  /* Just do the upsampling. */\n  (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,\n\t\t\t output_buf + *out_row_ctr);\n  /* Adjust counts */\n  (*out_row_ctr)++;\n  (*in_row_group_ctr)++;\n}\n\n\n/*\n * These are the routines invoked by the control routines to do\n * the actual upsampling/conversion.  One row group is processed per call.\n *\n * Note: since we may be writing directly into application-supplied buffers,\n * we have to be honest about the output width; we can't assume the buffer\n * has been rounded up to an even width.\n */\n\n\n/*\n * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.\n */\n\nMETHODDEF(void)\nh2v1_merged_upsample (j_decompress_ptr cinfo,\n\t\t      JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,\n\t\t      JSAMPARRAY output_buf)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  register int y, cred, cgreen, cblue;\n  int cb, cr;\n  register JSAMPROW outptr;\n  JSAMPROW inptr0, inptr1, inptr2;\n  JDIMENSION col;\n  /* copy these pointers into registers if possible */\n  register JSAMPLE * range_limit = cinfo->sample_range_limit;\n  int * Crrtab = upsample->Cr_r_tab;\n  int * Cbbtab = upsample->Cb_b_tab;\n  INT32 * Crgtab = upsample->Cr_g_tab;\n  INT32 * Cbgtab = upsample->Cb_g_tab;\n  SHIFT_TEMPS\n\n  inptr0 = input_buf[0][in_row_group_ctr];\n  inptr1 = input_buf[1][in_row_group_ctr];\n  inptr2 = input_buf[2][in_row_group_ctr];\n  outptr = output_buf[0];\n  /* Loop for each pair of output pixels */\n  for (col = cinfo->output_width >> 1; col > 0; col--) {\n    /* Do the chroma part of the calculation */\n    cb = GETJSAMPLE(*inptr1++);\n    cr = GETJSAMPLE(*inptr2++);\n    cred   = Crrtab[cr];\n    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);\n    cblue  = Cbbtab[cb];\n    /* Fetch 2 Y values and emit 2 pixels */\n    y  = GETJSAMPLE(*inptr0++);\n    outptr[RGB_RED]   = range_limit[y + cred];\n    outptr[RGB_GREEN] = range_limit[y + cgreen];\n    outptr[RGB_BLUE]  = range_limit[y + cblue];\n    outptr += RGB_PIXELSIZE;\n    y  = GETJSAMPLE(*inptr0++);\n    outptr[RGB_RED]   = range_limit[y + cred];\n    outptr[RGB_GREEN] = range_limit[y + cgreen];\n    outptr[RGB_BLUE]  = range_limit[y + cblue];\n    outptr += RGB_PIXELSIZE;\n  }\n  /* If image width is odd, do the last output column separately */\n  if (cinfo->output_width & 1) {\n    cb = GETJSAMPLE(*inptr1);\n    cr = GETJSAMPLE(*inptr2);\n    cred   = Crrtab[cr];\n    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);\n    cblue  = Cbbtab[cb];\n    y  = GETJSAMPLE(*inptr0);\n    outptr[RGB_RED]   = range_limit[y + cred];\n    outptr[RGB_GREEN] = range_limit[y + cgreen];\n    outptr[RGB_BLUE]  = range_limit[y + cblue];\n  }\n}\n\n\n/*\n * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.\n */\n\nMETHODDEF(void)\nh2v2_merged_upsample (j_decompress_ptr cinfo,\n\t\t      JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,\n\t\t      JSAMPARRAY output_buf)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  register int y, cred, cgreen, cblue;\n  int cb, cr;\n  register JSAMPROW outptr0, outptr1;\n  JSAMPROW inptr00, inptr01, inptr1, inptr2;\n  JDIMENSION col;\n  /* copy these pointers into registers if possible */\n  register JSAMPLE * range_limit = cinfo->sample_range_limit;\n  int * Crrtab = upsample->Cr_r_tab;\n  int * Cbbtab = upsample->Cb_b_tab;\n  INT32 * Crgtab = upsample->Cr_g_tab;\n  INT32 * Cbgtab = upsample->Cb_g_tab;\n  SHIFT_TEMPS\n\n  inptr00 = input_buf[0][in_row_group_ctr*2];\n  inptr01 = input_buf[0][in_row_group_ctr*2 + 1];\n  inptr1 = input_buf[1][in_row_group_ctr];\n  inptr2 = input_buf[2][in_row_group_ctr];\n  outptr0 = output_buf[0];\n  outptr1 = output_buf[1];\n  /* Loop for each group of output pixels */\n  for (col = cinfo->output_width >> 1; col > 0; col--) {\n    /* Do the chroma part of the calculation */\n    cb = GETJSAMPLE(*inptr1++);\n    cr = GETJSAMPLE(*inptr2++);\n    cred   = Crrtab[cr];\n    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);\n    cblue  = Cbbtab[cb];\n    /* Fetch 4 Y values and emit 4 pixels */\n    y  = GETJSAMPLE(*inptr00++);\n    outptr0[RGB_RED]   = range_limit[y + cred];\n    outptr0[RGB_GREEN] = range_limit[y + cgreen];\n    outptr0[RGB_BLUE]  = range_limit[y + cblue];\n    outptr0 += RGB_PIXELSIZE;\n    y  = GETJSAMPLE(*inptr00++);\n    outptr0[RGB_RED]   = range_limit[y + cred];\n    outptr0[RGB_GREEN] = range_limit[y + cgreen];\n    outptr0[RGB_BLUE]  = range_limit[y + cblue];\n    outptr0 += RGB_PIXELSIZE;\n    y  = GETJSAMPLE(*inptr01++);\n    outptr1[RGB_RED]   = range_limit[y + cred];\n    outptr1[RGB_GREEN] = range_limit[y + cgreen];\n    outptr1[RGB_BLUE]  = range_limit[y + cblue];\n    outptr1 += RGB_PIXELSIZE;\n    y  = GETJSAMPLE(*inptr01++);\n    outptr1[RGB_RED]   = range_limit[y + cred];\n    outptr1[RGB_GREEN] = range_limit[y + cgreen];\n    outptr1[RGB_BLUE]  = range_limit[y + cblue];\n    outptr1 += RGB_PIXELSIZE;\n  }\n  /* If image width is odd, do the last output column separately */\n  if (cinfo->output_width & 1) {\n    cb = GETJSAMPLE(*inptr1);\n    cr = GETJSAMPLE(*inptr2);\n    cred   = Crrtab[cr];\n    cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);\n    cblue  = Cbbtab[cb];\n    y  = GETJSAMPLE(*inptr00);\n    outptr0[RGB_RED]   = range_limit[y + cred];\n    outptr0[RGB_GREEN] = range_limit[y + cgreen];\n    outptr0[RGB_BLUE]  = range_limit[y + cblue];\n    y  = GETJSAMPLE(*inptr01);\n    outptr1[RGB_RED]   = range_limit[y + cred];\n    outptr1[RGB_GREEN] = range_limit[y + cgreen];\n    outptr1[RGB_BLUE]  = range_limit[y + cblue];\n  }\n}\n\n\n/*\n * Module initialization routine for merged upsampling/color conversion.\n *\n * NB: this is called under the conditions determined by use_merged_upsample()\n * in jdmaster.c.  That routine MUST correspond to the actual capabilities\n * of this module; no safety checks are made here.\n */\n\nGLOBAL(void)\njinit_merged_upsampler (j_decompress_ptr cinfo)\n{\n  my_upsample_ptr upsample;\n\n  upsample = (my_upsample_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_upsampler));\n  cinfo->upsample = &upsample->pub;\n  upsample->pub.start_pass = start_pass_merged_upsample;\n  upsample->pub.need_context_rows = FALSE;\n\n  upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;\n\n  if (cinfo->max_v_samp_factor == 2) {\n    upsample->pub.upsample = merged_2v_upsample;\n    upsample->upmethod = h2v2_merged_upsample;\n    /* Allocate a spare row buffer */\n    upsample->spare_row = (JSAMPROW) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       (size_t) upsample->out_row_width * SIZEOF(JSAMPLE));\n  } else {\n    upsample->pub.upsample = merged_1v_upsample;\n    upsample->upmethod = h2v1_merged_upsample;\n    /* No spare row needed */\n    upsample->spare_row = NULL;\n  }\n\n  if (cinfo->jpeg_color_space == JCS_BG_YCC)\n    build_bg_ycc_rgb_table(cinfo);\n  else\n    build_ycc_rgb_table(cinfo);\n}\n\n#endif /* UPSAMPLE_MERGING_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jdpostct.c",
    "content": "/*\n * jdpostct.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the decompression postprocessing controller.\n * This controller manages the upsampling, color conversion, and color\n * quantization/reduction steps; specifically, it controls the buffering\n * between upsample/color conversion and color quantization/reduction.\n *\n * If no color quantization/reduction is required, then this module has no\n * work to do, and it just hands off to the upsample/color conversion code.\n * An integrated upsample/convert/quantize process would replace this module\n * entirely.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Private buffer controller object */\n\ntypedef struct {\n  struct jpeg_d_post_controller pub; /* public fields */\n\n  /* Color quantization source buffer: this holds output data from\n   * the upsample/color conversion step to be passed to the quantizer.\n   * For two-pass color quantization, we need a full-image buffer;\n   * for one-pass operation, a strip buffer is sufficient.\n   */\n  jvirt_sarray_ptr whole_image;\t/* virtual array, or NULL if one-pass */\n  JSAMPARRAY buffer;\t\t/* strip buffer, or current strip of virtual */\n  JDIMENSION strip_height;\t/* buffer size in rows */\n  /* for two-pass mode only: */\n  JDIMENSION starting_row;\t/* row # of first row in current strip */\n  JDIMENSION next_row;\t\t/* index of next row to fill/empty in strip */\n} my_post_controller;\n\ntypedef my_post_controller * my_post_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(void) post_process_1pass\n\tJPP((j_decompress_ptr cinfo,\n\t     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t     JDIMENSION in_row_groups_avail,\n\t     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t     JDIMENSION out_rows_avail));\n#ifdef QUANT_2PASS_SUPPORTED\nMETHODDEF(void) post_process_prepass\n\tJPP((j_decompress_ptr cinfo,\n\t     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t     JDIMENSION in_row_groups_avail,\n\t     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t     JDIMENSION out_rows_avail));\nMETHODDEF(void) post_process_2pass\n\tJPP((j_decompress_ptr cinfo,\n\t     JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t     JDIMENSION in_row_groups_avail,\n\t     JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t     JDIMENSION out_rows_avail));\n#endif\n\n\n/*\n * Initialize for a processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)\n{\n  my_post_ptr post = (my_post_ptr) cinfo->post;\n\n  switch (pass_mode) {\n  case JBUF_PASS_THRU:\n    if (cinfo->quantize_colors) {\n      /* Single-pass processing with color quantization. */\n      post->pub.post_process_data = post_process_1pass;\n      /* We could be doing buffered-image output before starting a 2-pass\n       * color quantization; in that case, jinit_d_post_controller did not\n       * allocate a strip buffer.  Use the virtual-array buffer as workspace.\n       */\n      if (post->buffer == NULL) {\n\tpost->buffer = (*cinfo->mem->access_virt_sarray)\n\t  ((j_common_ptr) cinfo, post->whole_image,\n\t   (JDIMENSION) 0, post->strip_height, TRUE);\n      }\n    } else {\n      /* For single-pass processing without color quantization,\n       * I have no work to do; just call the upsampler directly.\n       */\n      post->pub.post_process_data = cinfo->upsample->upsample;\n    }\n    break;\n#ifdef QUANT_2PASS_SUPPORTED\n  case JBUF_SAVE_AND_PASS:\n    /* First pass of 2-pass quantization */\n    if (post->whole_image == NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    post->pub.post_process_data = post_process_prepass;\n    break;\n  case JBUF_CRANK_DEST:\n    /* Second pass of 2-pass quantization */\n    if (post->whole_image == NULL)\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    post->pub.post_process_data = post_process_2pass;\n    break;\n#endif /* QUANT_2PASS_SUPPORTED */\n  default:\n    ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n    break;\n  }\n  post->starting_row = post->next_row = 0;\n}\n\n\n/*\n * Process some data in the one-pass (strip buffer) case.\n * This is used for color precision reduction as well as one-pass quantization.\n */\n\nMETHODDEF(void)\npost_process_1pass (j_decompress_ptr cinfo,\n\t\t    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t\t    JDIMENSION in_row_groups_avail,\n\t\t    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t    JDIMENSION out_rows_avail)\n{\n  my_post_ptr post = (my_post_ptr) cinfo->post;\n  JDIMENSION num_rows, max_rows;\n\n  /* Fill the buffer, but not more than what we can dump out in one go. */\n  /* Note we rely on the upsampler to detect bottom of image. */\n  max_rows = out_rows_avail - *out_row_ctr;\n  if (max_rows > post->strip_height)\n    max_rows = post->strip_height;\n  num_rows = 0;\n  (*cinfo->upsample->upsample) (cinfo,\n\t\tinput_buf, in_row_group_ctr, in_row_groups_avail,\n\t\tpost->buffer, &num_rows, max_rows);\n  /* Quantize and emit data. */\n  (*cinfo->cquantize->color_quantize) (cinfo,\n\t\tpost->buffer, output_buf + *out_row_ctr, (int) num_rows);\n  *out_row_ctr += num_rows;\n}\n\n\n#ifdef QUANT_2PASS_SUPPORTED\n\n/*\n * Process some data in the first pass of 2-pass quantization.\n */\n\nMETHODDEF(void)\npost_process_prepass (j_decompress_ptr cinfo,\n\t\t      JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t\t      JDIMENSION in_row_groups_avail,\n\t\t      JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t      JDIMENSION out_rows_avail)\n{\n  my_post_ptr post = (my_post_ptr) cinfo->post;\n  JDIMENSION old_next_row, num_rows;\n\n  /* Reposition virtual buffer if at start of strip. */\n  if (post->next_row == 0) {\n    post->buffer = (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, post->whole_image,\n\t post->starting_row, post->strip_height, TRUE);\n  }\n\n  /* Upsample some data (up to a strip height's worth). */\n  old_next_row = post->next_row;\n  (*cinfo->upsample->upsample) (cinfo,\n\t\tinput_buf, in_row_group_ctr, in_row_groups_avail,\n\t\tpost->buffer, &post->next_row, post->strip_height);\n\n  /* Allow quantizer to scan new data.  No data is emitted, */\n  /* but we advance out_row_ctr so outer loop can tell when we're done. */\n  if (post->next_row > old_next_row) {\n    num_rows = post->next_row - old_next_row;\n    (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,\n\t\t\t\t\t (JSAMPARRAY) NULL, (int) num_rows);\n    *out_row_ctr += num_rows;\n  }\n\n  /* Advance if we filled the strip. */\n  if (post->next_row >= post->strip_height) {\n    post->starting_row += post->strip_height;\n    post->next_row = 0;\n  }\n}\n\n\n/*\n * Process some data in the second pass of 2-pass quantization.\n */\n\nMETHODDEF(void)\npost_process_2pass (j_decompress_ptr cinfo,\n\t\t    JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t\t    JDIMENSION in_row_groups_avail,\n\t\t    JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t    JDIMENSION out_rows_avail)\n{\n  my_post_ptr post = (my_post_ptr) cinfo->post;\n  JDIMENSION num_rows, max_rows;\n\n  /* Reposition virtual buffer if at start of strip. */\n  if (post->next_row == 0) {\n    post->buffer = (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, post->whole_image,\n\t post->starting_row, post->strip_height, FALSE);\n  }\n\n  /* Determine number of rows to emit. */\n  num_rows = post->strip_height - post->next_row; /* available in strip */\n  max_rows = out_rows_avail - *out_row_ctr; /* available in output area */\n  if (num_rows > max_rows)\n    num_rows = max_rows;\n  /* We have to check bottom of image here, can't depend on upsampler. */\n  max_rows = cinfo->output_height - post->starting_row;\n  if (num_rows > max_rows)\n    num_rows = max_rows;\n\n  /* Quantize and emit data. */\n  (*cinfo->cquantize->color_quantize) (cinfo,\n\t\tpost->buffer + post->next_row, output_buf + *out_row_ctr,\n\t\t(int) num_rows);\n  *out_row_ctr += num_rows;\n\n  /* Advance if we filled the strip. */\n  post->next_row += num_rows;\n  if (post->next_row >= post->strip_height) {\n    post->starting_row += post->strip_height;\n    post->next_row = 0;\n  }\n}\n\n#endif /* QUANT_2PASS_SUPPORTED */\n\n\n/*\n * Initialize postprocessing controller.\n */\n\nGLOBAL(void)\njinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)\n{\n  my_post_ptr post;\n\n  post = (my_post_ptr)\n    (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t\t\t\tSIZEOF(my_post_controller));\n  cinfo->post = (struct jpeg_d_post_controller *) post;\n  post->pub.start_pass = start_pass_dpost;\n  post->whole_image = NULL;\t/* flag for no virtual arrays */\n  post->buffer = NULL;\t\t/* flag for no strip buffer */\n\n  /* Create the quantization buffer, if needed */\n  if (cinfo->quantize_colors) {\n    /* The buffer strip height is max_v_samp_factor, which is typically\n     * an efficient number of rows for upsampling to return.\n     * (In the presence of output rescaling, we might want to be smarter?)\n     */\n    post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;\n    if (need_full_buffer) {\n      /* Two-pass color quantization: need full-image storage. */\n      /* We round up the number of rows to a multiple of the strip height. */\n#ifdef QUANT_2PASS_SUPPORTED\n      post->whole_image = (*cinfo->mem->request_virt_sarray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n\t cinfo->output_width * cinfo->out_color_components,\n\t (JDIMENSION) jround_up((long) cinfo->output_height,\n\t\t\t\t(long) post->strip_height),\n\t post->strip_height);\n#else\n      ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);\n#endif /* QUANT_2PASS_SUPPORTED */\n    } else {\n      /* One-pass color quantization: just make a strip buffer. */\n      post->buffer = (*cinfo->mem->alloc_sarray)\n\t((j_common_ptr) cinfo, JPOOL_IMAGE,\n\t cinfo->output_width * cinfo->out_color_components,\n\t post->strip_height);\n    }\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdsample.c",
    "content": "/*\n * jdsample.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains upsampling routines.\n *\n * Upsampling input data is counted in \"row groups\".  A row group\n * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size)\n * sample rows of each component.  Upsampling will normally produce\n * max_v_samp_factor pixel rows from each row group (but this could vary\n * if the upsampler is applying a scale factor of its own).\n *\n * An excellent reference for image resampling is\n *   Digital Image Warping, George Wolberg, 1990.\n *   Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Pointer to routine to upsample a single component */\ntypedef JMETHOD(void, upsample1_ptr,\n\t\t(j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr));\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_upsampler pub;\t/* public fields */\n\n  /* Color conversion buffer.  When using separate upsampling and color\n   * conversion steps, this buffer holds one upsampled row group until it\n   * has been color converted and output.\n   * Note: we do not allocate any storage for component(s) which are full-size,\n   * ie do not need rescaling.  The corresponding entry of color_buf[] is\n   * simply set to point to the input data array, thereby avoiding copying.\n   */\n  JSAMPARRAY color_buf[MAX_COMPONENTS];\n\n  /* Per-component upsampling method pointers */\n  upsample1_ptr methods[MAX_COMPONENTS];\n\n  int next_row_out;\t\t/* counts rows emitted from color_buf */\n  JDIMENSION rows_to_go;\t/* counts rows remaining in image */\n\n  /* Height of an input row group for each component. */\n  int rowgroup_height[MAX_COMPONENTS];\n\n  /* These arrays save pixel expansion factors so that int_expand need not\n   * recompute them each time.  They are unused for other upsampling methods.\n   */\n  UINT8 h_expand[MAX_COMPONENTS];\n  UINT8 v_expand[MAX_COMPONENTS];\n} my_upsampler;\n\ntypedef my_upsampler * my_upsample_ptr;\n\n\n/*\n * Initialize for an upsampling pass.\n */\n\nMETHODDEF(void)\nstart_pass_upsample (j_decompress_ptr cinfo)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n\n  /* Mark the conversion buffer empty */\n  upsample->next_row_out = cinfo->max_v_samp_factor;\n  /* Initialize total-height counter for detecting bottom of image */\n  upsample->rows_to_go = cinfo->output_height;\n}\n\n\n/*\n * Control routine to do upsampling (and color conversion).\n *\n * In this version we upsample each component independently.\n * We upsample one row group into the conversion buffer, then apply\n * color conversion a row at a time.\n */\n\nMETHODDEF(void)\nsep_upsample (j_decompress_ptr cinfo,\n\t      JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,\n\t      JDIMENSION in_row_groups_avail,\n\t      JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t      JDIMENSION out_rows_avail)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  int ci;\n  jpeg_component_info * compptr;\n  JDIMENSION num_rows;\n\n  /* Fill the conversion buffer, if it's empty */\n  if (upsample->next_row_out >= cinfo->max_v_samp_factor) {\n    for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n\t ci++, compptr++) {\n      /* Don't bother to upsample an uninteresting component. */\n      if (! compptr->component_needed)\n\tcontinue;\n      /* Invoke per-component upsample method.  Notice we pass a POINTER\n       * to color_buf[ci], so that fullsize_upsample can change it.\n       */\n      (*upsample->methods[ci]) (cinfo, compptr,\n\tinput_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),\n\tupsample->color_buf + ci);\n    }\n    upsample->next_row_out = 0;\n  }\n\n  /* Color-convert and emit rows */\n\n  /* How many we have in the buffer: */\n  num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);\n  /* Not more than the distance to the end of the image.  Need this test\n   * in case the image height is not a multiple of max_v_samp_factor:\n   */\n  if (num_rows > upsample->rows_to_go) \n    num_rows = upsample->rows_to_go;\n  /* And not more than what the client can accept: */\n  out_rows_avail -= *out_row_ctr;\n  if (num_rows > out_rows_avail)\n    num_rows = out_rows_avail;\n\n  (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,\n\t\t\t\t     (JDIMENSION) upsample->next_row_out,\n\t\t\t\t     output_buf + *out_row_ctr,\n\t\t\t\t     (int) num_rows);\n\n  /* Adjust counts */\n  *out_row_ctr += num_rows;\n  upsample->rows_to_go -= num_rows;\n  upsample->next_row_out += num_rows;\n  /* When the buffer is emptied, declare this input row group consumed */\n  if (upsample->next_row_out >= cinfo->max_v_samp_factor)\n    (*in_row_group_ctr)++;\n}\n\n\n/*\n * These are the routines invoked by sep_upsample to upsample pixel values\n * of a single component.  One row group is processed per call.\n */\n\n\n/*\n * For full-size components, we just make color_buf[ci] point at the\n * input buffer, and thus avoid copying any data.  Note that this is\n * safe only because sep_upsample doesn't declare the input row group\n * \"consumed\" until we are done color converting and emitting it.\n */\n\nMETHODDEF(void)\nfullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t   JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr)\n{\n  *output_data_ptr = input_data;\n}\n\n\n/*\n * This version handles any integral sampling ratios.\n * This is not used for typical JPEG files, so it need not be fast.\n * Nor, for that matter, is it particularly accurate: the algorithm is\n * simple replication of the input pixel onto the corresponding output\n * pixels.  The hi-falutin sampling literature refers to this as a\n * \"box filter\".  A box filter tends to introduce visible artifacts,\n * so if you are actually going to use 3:1 or 4:1 sampling ratios\n * you would be well advised to improve this code.\n */\n\nMETHODDEF(void)\nint_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t      JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr)\n{\n  my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;\n  JSAMPARRAY output_data, output_end;\n  register JSAMPROW inptr, outptr;\n  register JSAMPLE invalue;\n  register int h;\n  JSAMPROW outend;\n  int h_expand, v_expand;\n\n  h_expand = upsample->h_expand[compptr->component_index];\n  v_expand = upsample->v_expand[compptr->component_index];\n\n  output_data = *output_data_ptr;\n  output_end = output_data + cinfo->max_v_samp_factor;\n  for (; output_data < output_end; output_data += v_expand) {\n    /* Generate one output row with proper horizontal expansion */\n    inptr = *input_data++;\n    outptr = *output_data;\n    outend = outptr + cinfo->output_width;\n    while (outptr < outend) {\n      invalue = *inptr++;\t/* don't need GETJSAMPLE() here */\n      for (h = h_expand; h > 0; h--) {\n\t*outptr++ = invalue;\n      }\n    }\n    /* Generate any additional output rows by duplicating the first one */\n    if (v_expand > 1) {\n      jcopy_sample_rows(output_data, output_data + 1,\n\t\t\tv_expand - 1, cinfo->output_width);\n    }\n  }\n}\n\n\n/*\n * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.\n * It's still a box filter.\n */\n\nMETHODDEF(void)\nh2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr)\n{\n  JSAMPARRAY output_data = *output_data_ptr;\n  register JSAMPROW inptr, outptr;\n  register JSAMPLE invalue;\n  JSAMPROW outend;\n  int outrow;\n\n  for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) {\n    inptr = input_data[outrow];\n    outptr = output_data[outrow];\n    outend = outptr + cinfo->output_width;\n    while (outptr < outend) {\n      invalue = *inptr++;\t/* don't need GETJSAMPLE() here */\n      *outptr++ = invalue;\n      *outptr++ = invalue;\n    }\n  }\n}\n\n\n/*\n * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.\n * It's still a box filter.\n */\n\nMETHODDEF(void)\nh2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JSAMPARRAY input_data, JSAMPIMAGE output_data_ptr)\n{\n  JSAMPARRAY output_data, output_end;\n  register JSAMPROW inptr, outptr;\n  register JSAMPLE invalue;\n  JSAMPROW outend;\n\n  output_data = *output_data_ptr;\n  output_end = output_data + cinfo->max_v_samp_factor;\n  for (; output_data < output_end; output_data += 2) {\n    inptr = *input_data++;\n    outptr = *output_data;\n    outend = outptr + cinfo->output_width;\n    while (outptr < outend) {\n      invalue = *inptr++;\t/* don't need GETJSAMPLE() here */\n      *outptr++ = invalue;\n      *outptr++ = invalue;\n    }\n    jcopy_sample_rows(output_data, output_data + 1,\n\t\t      1, cinfo->output_width);\n  }\n}\n\n\n/*\n * Module initialization routine for upsampling.\n */\n\nGLOBAL(void)\njinit_upsampler (j_decompress_ptr cinfo)\n{\n  my_upsample_ptr upsample;\n  int ci;\n  jpeg_component_info * compptr;\n  int h_in_group, v_in_group, h_out_group, v_out_group;\n\n  upsample = (my_upsample_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_upsampler));\n  cinfo->upsample = &upsample->pub;\n  upsample->pub.start_pass = start_pass_upsample;\n  upsample->pub.upsample = sep_upsample;\n  upsample->pub.need_context_rows = FALSE; /* until we find out differently */\n\n  if (cinfo->CCIR601_sampling)\t/* this isn't supported */\n    ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);\n\n  /* Verify we can handle the sampling factors, select per-component methods,\n   * and create storage as needed.\n   */\n  for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;\n       ci++, compptr++) {\n    /* Don't bother to upsample an uninteresting component. */\n    if (! compptr->component_needed)\n      continue;\n    /* Compute size of an \"input group\" after IDCT scaling.  This many samples\n     * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.\n     */\n    h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /\n\t\t cinfo->min_DCT_h_scaled_size;\n    v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /\n\t\t cinfo->min_DCT_v_scaled_size;\n    h_out_group = cinfo->max_h_samp_factor;\n    v_out_group = cinfo->max_v_samp_factor;\n    upsample->rowgroup_height[ci] = v_in_group; /* save for use later */\n    if (h_in_group == h_out_group && v_in_group == v_out_group) {\n      /* Fullsize components can be processed without any work. */\n      upsample->methods[ci] = fullsize_upsample;\n      continue;\t\t/* don't need to allocate buffer */\n    }\n    if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) {\n      /* Special case for 2h1v upsampling */\n      upsample->methods[ci] = h2v1_upsample;\n    } else if (h_in_group * 2 == h_out_group &&\n\t       v_in_group * 2 == v_out_group) {\n      /* Special case for 2h2v upsampling */\n      upsample->methods[ci] = h2v2_upsample;\n    } else if ((h_out_group % h_in_group) == 0 &&\n\t       (v_out_group % v_in_group) == 0) {\n      /* Generic integral-factors upsampling method */\n      upsample->methods[ci] = int_upsample;\n      upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);\n      upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);\n    } else\n      ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);\n    upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       (JDIMENSION) jround_up((long) cinfo->output_width,\n\t\t\t      (long) cinfo->max_h_samp_factor),\n       (JDIMENSION) cinfo->max_v_samp_factor);\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jdtrans.c",
    "content": "/*\n * jdtrans.c\n *\n * Copyright (C) 1995-1997, Thomas G. Lane.\n * Modified 2000-2009 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains library routines for transcoding decompression,\n * that is, reading raw DCT coefficient arrays from an input JPEG file.\n * The routines in jdapimin.c will also be needed by a transcoder.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/* Forward declarations */\nLOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));\n\n\n/*\n * Read the coefficient arrays from a JPEG file.\n * jpeg_read_header must be completed before calling this.\n *\n * The entire image is read into a set of virtual coefficient-block arrays,\n * one per component.  The return value is a pointer to the array of\n * virtual-array descriptors.  These can be manipulated directly via the\n * JPEG memory manager, or handed off to jpeg_write_coefficients().\n * To release the memory occupied by the virtual arrays, call\n * jpeg_finish_decompress() when done with the data.\n *\n * An alternative usage is to simply obtain access to the coefficient arrays\n * during a buffered-image-mode decompression operation.  This is allowed\n * after any jpeg_finish_output() call.  The arrays can be accessed until\n * jpeg_finish_decompress() is called.  (Note that any call to the library\n * may reposition the arrays, so don't rely on access_virt_barray() results\n * to stay valid across library calls.)\n *\n * Returns NULL if suspended.  This case need be checked only if\n * a suspending data source is used.\n */\n\nGLOBAL(jvirt_barray_ptr *)\njpeg_read_coefficients (j_decompress_ptr cinfo)\n{\n  if (cinfo->global_state == DSTATE_READY) {\n    /* First call: initialize active modules */\n    transdecode_master_selection(cinfo);\n    cinfo->global_state = DSTATE_RDCOEFS;\n  }\n  if (cinfo->global_state == DSTATE_RDCOEFS) {\n    /* Absorb whole file into the coef buffer */\n    for (;;) {\n      int retcode;\n      /* Call progress monitor hook if present */\n      if (cinfo->progress != NULL)\n\t(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);\n      /* Absorb some more input */\n      retcode = (*cinfo->inputctl->consume_input) (cinfo);\n      if (retcode == JPEG_SUSPENDED)\n\treturn NULL;\n      if (retcode == JPEG_REACHED_EOI)\n\tbreak;\n      /* Advance progress counter if appropriate */\n      if (cinfo->progress != NULL &&\n\t  (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {\n\tif (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {\n\t  /* startup underestimated number of scans; ratchet up one scan */\n\t  cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;\n\t}\n      }\n    }\n    /* Set state so that jpeg_finish_decompress does the right thing */\n    cinfo->global_state = DSTATE_STOPPING;\n  }\n  /* At this point we should be in state DSTATE_STOPPING if being used\n   * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access\n   * to the coefficients during a full buffered-image-mode decompression.\n   */\n  if ((cinfo->global_state == DSTATE_STOPPING ||\n       cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {\n    return cinfo->coef->coef_arrays;\n  }\n  /* Oops, improper usage */\n  ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);\n  return NULL;\t\t\t/* keep compiler happy */\n}\n\n\n/*\n * Master selection of decompression modules for transcoding.\n * This substitutes for jdmaster.c's initialization of the full decompressor.\n */\n\nLOCAL(void)\ntransdecode_master_selection (j_decompress_ptr cinfo)\n{\n  /* This is effectively a buffered-image operation. */\n  cinfo->buffered_image = TRUE;\n\n  /* Compute output image dimensions and related values. */\n  jpeg_core_output_dimensions(cinfo);\n\n  /* Entropy decoding: either Huffman or arithmetic coding. */\n  if (cinfo->arith_code)\n    jinit_arith_decoder(cinfo);\n  else {\n    jinit_huff_decoder(cinfo);\n  }\n\n  /* Always get a full-image coefficient buffer. */\n  jinit_d_coef_controller(cinfo, TRUE);\n\n  /* We can now tell the memory manager to allocate virtual arrays. */\n  (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);\n\n  /* Initialize input side of decompressor to consume first scan. */\n  (*cinfo->inputctl->start_input_pass) (cinfo);\n\n  /* Initialize progress monitoring. */\n  if (cinfo->progress != NULL) {\n    int nscans;\n    /* Estimate number of scans to set pass_limit. */\n    if (cinfo->progressive_mode) {\n      /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */\n      nscans = 2 + 3 * cinfo->num_components;\n    } else if (cinfo->inputctl->has_multiple_scans) {\n      /* For a nonprogressive multiscan file, estimate 1 scan per component. */\n      nscans = cinfo->num_components;\n    } else {\n      nscans = 1;\n    }\n    cinfo->progress->pass_counter = 0L;\n    cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;\n    cinfo->progress->completed_passes = 0;\n    cinfo->progress->total_passes = 1;\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jerror.c",
    "content": "/*\n * jerror.c\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modified 2012-2015 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains simple error-reporting and trace-message routines.\n * These are suitable for Unix-like systems and others where writing to\n * stderr is the right thing to do.  Many applications will want to replace\n * some or all of these routines.\n *\n * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,\n * you get a Windows-specific hack to display error messages in a dialog box.\n * It ain't much, but it beats dropping error messages into the bit bucket,\n * which is what happens to output to stderr under most Windows C compilers.\n *\n * These routines are used by both the compression and decompression code.\n */\n\n#ifdef USE_WINDOWS_MESSAGEBOX\n#include <windows.h>\n#endif\n\n/* this is not a core library module, so it doesn't define JPEG_INTERNALS */\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jversion.h\"\n#include \"jerror.h\"\n\n#ifndef EXIT_FAILURE\t\t/* define exit() codes if not provided */\n#define EXIT_FAILURE  1\n#endif\n\n\n/*\n * Create the message string table.\n * We do this from the master message list in jerror.h by re-reading\n * jerror.h with a suitable definition for macro JMESSAGE.\n * The message table is made an external symbol just in case any applications\n * want to refer to it directly.\n */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jpeg_std_message_table\tjMsgTable\n#endif\n\n#define JMESSAGE(code,string)\tstring ,\n\nconst char * const jpeg_std_message_table[] = {\n#include \"jerror.h\"\n  NULL\n};\n\n\n/*\n * Error exit handler: must not return to caller.\n *\n * Applications may override this if they want to get control back after\n * an error.  Typically one would longjmp somewhere instead of exiting.\n * The setjmp buffer can be made a private field within an expanded error\n * handler object.  Note that the info needed to generate an error message\n * is stored in the error object, so you can generate the message now or\n * later, at your convenience.\n * You should make sure that the JPEG object is cleaned up (with jpeg_abort\n * or jpeg_destroy) at some point.\n */\n\nMETHODDEF(noreturn_t)\nerror_exit (j_common_ptr cinfo)\n{\n  /* Always display the message */\n  (*cinfo->err->output_message) (cinfo);\n\n  /* Let the memory manager delete any temp files before we die */\n  jpeg_destroy(cinfo);\n\n  exit(EXIT_FAILURE);\n}\n\n\n/*\n * Actual output of an error or trace message.\n * Applications may override this method to send JPEG messages somewhere\n * other than stderr.\n *\n * On Windows, printing to stderr is generally completely useless,\n * so we provide optional code to produce an error-dialog popup.\n * Most Windows applications will still prefer to override this routine,\n * but if they don't, it'll do something at least marginally useful.\n *\n * NOTE: to use the library in an environment that doesn't support the\n * C stdio library, you may have to delete the call to fprintf() entirely,\n * not just not use this routine.\n */\n\nMETHODDEF(void)\noutput_message (j_common_ptr cinfo)\n{\n  char buffer[JMSG_LENGTH_MAX];\n\n  /* Create the message */\n  (*cinfo->err->format_message) (cinfo, buffer);\n\n#ifdef USE_WINDOWS_MESSAGEBOX\n  /* Display it in a message dialog box */\n  MessageBox(GetActiveWindow(), buffer, \"JPEG Library Error\",\n\t     MB_OK | MB_ICONERROR);\n#else\n  /* Send it to stderr, adding a newline */\n  fprintf(stderr, \"%s\\n\", buffer);\n#endif\n}\n\n\n/*\n * Decide whether to emit a trace or warning message.\n * msg_level is one of:\n *   -1: recoverable corrupt-data warning, may want to abort.\n *    0: important advisory messages (always display to user).\n *    1: first level of tracing detail.\n *    2,3,...: successively more detailed tracing messages.\n * An application might override this method if it wanted to abort on warnings\n * or change the policy about which messages to display.\n */\n\nMETHODDEF(void)\nemit_message (j_common_ptr cinfo, int msg_level)\n{\n  struct jpeg_error_mgr * err = cinfo->err;\n\n  if (msg_level < 0) {\n    /* It's a warning message.  Since corrupt files may generate many warnings,\n     * the policy implemented here is to show only the first warning,\n     * unless trace_level >= 3.\n     */\n    if (err->num_warnings == 0 || err->trace_level >= 3)\n      (*err->output_message) (cinfo);\n    /* Always count warnings in num_warnings. */\n    err->num_warnings++;\n  } else {\n    /* It's a trace message.  Show it if trace_level >= msg_level. */\n    if (err->trace_level >= msg_level)\n      (*err->output_message) (cinfo);\n  }\n}\n\n\n/*\n * Format a message string for the most recent JPEG error or message.\n * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX\n * characters.  Note that no '\\n' character is added to the string.\n * Few applications should need to override this method.\n */\n\nMETHODDEF(void)\nformat_message (j_common_ptr cinfo, char * buffer)\n{\n  struct jpeg_error_mgr * err = cinfo->err;\n  int msg_code = err->msg_code;\n  const char * msgtext = NULL;\n  const char * msgptr;\n  char ch;\n  boolean isstring;\n\n  /* Look up message string in proper table */\n  if (msg_code > 0 && msg_code <= err->last_jpeg_message) {\n    msgtext = err->jpeg_message_table[msg_code];\n  } else if (err->addon_message_table != NULL &&\n\t     msg_code >= err->first_addon_message &&\n\t     msg_code <= err->last_addon_message) {\n    msgtext = err->addon_message_table[msg_code - err->first_addon_message];\n  }\n\n  /* Defend against bogus message number */\n  if (msgtext == NULL) {\n    err->msg_parm.i[0] = msg_code;\n    msgtext = err->jpeg_message_table[0];\n  }\n\n  /* Check for string parameter, as indicated by %s in the message text */\n  isstring = FALSE;\n  msgptr = msgtext;\n  while ((ch = *msgptr++) != '\\0') {\n    if (ch == '%') {\n      if (*msgptr == 's') isstring = TRUE;\n      break;\n    }\n  }\n\n  /* Format the message into the passed buffer */\n  if (isstring)\n    sprintf(buffer, msgtext, err->msg_parm.s);\n  else\n    sprintf(buffer, msgtext,\n\t    err->msg_parm.i[0], err->msg_parm.i[1],\n\t    err->msg_parm.i[2], err->msg_parm.i[3],\n\t    err->msg_parm.i[4], err->msg_parm.i[5],\n\t    err->msg_parm.i[6], err->msg_parm.i[7]);\n}\n\n\n/*\n * Reset error state variables at start of a new image.\n * This is called during compression startup to reset trace/error\n * processing to default state, without losing any application-specific\n * method pointers.  An application might possibly want to override\n * this method if it has additional error processing state.\n */\n\nMETHODDEF(void)\nreset_error_mgr (j_common_ptr cinfo)\n{\n  cinfo->err->num_warnings = 0;\n  /* trace_level is not reset since it is an application-supplied parameter */\n  cinfo->err->msg_code = 0;\t/* may be useful as a flag for \"no error\" */\n}\n\n\n/*\n * Fill in the standard error-handling methods in a jpeg_error_mgr object.\n * Typical call is:\n *\tstruct jpeg_compress_struct cinfo;\n *\tstruct jpeg_error_mgr err;\n *\n *\tcinfo.err = jpeg_std_error(&err);\n * after which the application may override some of the methods.\n */\n\nGLOBAL(struct jpeg_error_mgr *)\njpeg_std_error (struct jpeg_error_mgr * err)\n{\n  err->error_exit = error_exit;\n  err->emit_message = emit_message;\n  err->output_message = output_message;\n  err->format_message = format_message;\n  err->reset_error_mgr = reset_error_mgr;\n\n  err->trace_level = 0;\t\t/* default = no tracing */\n  err->num_warnings = 0;\t/* no warnings emitted yet */\n  err->msg_code = 0;\t\t/* may be useful as a flag for \"no error\" */\n\n  /* Initialize message table pointers */\n  err->jpeg_message_table = jpeg_std_message_table;\n  err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;\n\n  err->addon_message_table = NULL;\n  err->first_addon_message = 0;\t/* for safety */\n  err->last_addon_message = 0;\n\n  return err;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jerror.h",
    "content": "/*\n * jerror.h\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 1997-2018 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file defines the error and message codes for the JPEG library.\n * Edit this file to add new codes, or to translate the message strings to\n * some other language.\n * A set of error-reporting macros are defined too.  Some applications using\n * the JPEG library may wish to include this file to get the error codes\n * and/or the macros.\n */\n\n/*\n * To define the enum list of message codes, include this file without\n * defining macro JMESSAGE.  To create a message string table, include it\n * again with a suitable JMESSAGE definition (see jerror.c for an example).\n */\n#ifndef JMESSAGE\n#ifndef JERROR_H\n/* First time through, define the enum list */\n#define JMAKE_ENUM_LIST\n#else\n/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */\n#define JMESSAGE(code,string)\n#endif /* JERROR_H */\n#endif /* JMESSAGE */\n\n#ifdef JMAKE_ENUM_LIST\n\ntypedef enum {\n\n#define JMESSAGE(code,string)\tcode ,\n\n#endif /* JMAKE_ENUM_LIST */\n\nJMESSAGE(JMSG_NOMESSAGE, \"Bogus message code %d\") /* Must be first entry! */\n\n/* For maintenance convenience, list is alphabetical by message code name */\nJMESSAGE(JERR_BAD_ALIGN_TYPE, \"ALIGN_TYPE is wrong, please fix\")\nJMESSAGE(JERR_BAD_ALLOC_CHUNK, \"MAX_ALLOC_CHUNK is wrong, please fix\")\nJMESSAGE(JERR_BAD_BUFFER_MODE, \"Bogus buffer control mode\")\nJMESSAGE(JERR_BAD_COMPONENT_ID, \"Invalid component ID %d in SOS\")\nJMESSAGE(JERR_BAD_CROP_SPEC, \"Invalid crop request\")\nJMESSAGE(JERR_BAD_DCT_COEF, \"DCT coefficient out of range\")\nJMESSAGE(JERR_BAD_DCTSIZE, \"DCT scaled block size %dx%d not supported\")\nJMESSAGE(JERR_BAD_DROP_SAMPLING,\n\t \"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c\")\nJMESSAGE(JERR_BAD_HUFF_TABLE, \"Bogus Huffman table definition\")\nJMESSAGE(JERR_BAD_IN_COLORSPACE, \"Bogus input colorspace\")\nJMESSAGE(JERR_BAD_J_COLORSPACE, \"Bogus JPEG colorspace\")\nJMESSAGE(JERR_BAD_LENGTH, \"Bogus marker length\")\nJMESSAGE(JERR_BAD_LIB_VERSION,\n\t \"Wrong JPEG library version: library is %d, caller expects %d\")\nJMESSAGE(JERR_BAD_MCU_SIZE, \"Sampling factors too large for interleaved scan\")\nJMESSAGE(JERR_BAD_POOL_ID, \"Invalid memory pool code %d\")\nJMESSAGE(JERR_BAD_PRECISION, \"Unsupported JPEG data precision %d\")\nJMESSAGE(JERR_BAD_PROGRESSION,\n\t \"Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d\")\nJMESSAGE(JERR_BAD_PROG_SCRIPT,\n\t \"Invalid progressive parameters at scan script entry %d\")\nJMESSAGE(JERR_BAD_SAMPLING, \"Bogus sampling factors\")\nJMESSAGE(JERR_BAD_SCAN_SCRIPT, \"Invalid scan script at entry %d\")\nJMESSAGE(JERR_BAD_STATE, \"Improper call to JPEG library in state %d\")\nJMESSAGE(JERR_BAD_STRUCT_SIZE,\n\t \"JPEG parameter struct mismatch: library thinks size is %u, caller expects %u\")\nJMESSAGE(JERR_BAD_VIRTUAL_ACCESS, \"Bogus virtual array access\")\nJMESSAGE(JERR_BUFFER_SIZE, \"Buffer passed to JPEG library is too small\")\nJMESSAGE(JERR_CANT_SUSPEND, \"Suspension not allowed here\")\nJMESSAGE(JERR_CCIR601_NOTIMPL, \"CCIR601 sampling not implemented yet\")\nJMESSAGE(JERR_COMPONENT_COUNT, \"Too many color components: %d, max %d\")\nJMESSAGE(JERR_CONVERSION_NOTIMPL, \"Unsupported color conversion request\")\nJMESSAGE(JERR_DAC_INDEX, \"Bogus DAC index %d\")\nJMESSAGE(JERR_DAC_VALUE, \"Bogus DAC value 0x%x\")\nJMESSAGE(JERR_DHT_INDEX, \"Bogus DHT index %d\")\nJMESSAGE(JERR_DQT_INDEX, \"Bogus DQT index %d\")\nJMESSAGE(JERR_EMPTY_IMAGE, \"Empty JPEG image (DNL not supported)\")\nJMESSAGE(JERR_EMS_READ, \"Read from EMS failed\")\nJMESSAGE(JERR_EMS_WRITE, \"Write to EMS failed\")\nJMESSAGE(JERR_EOI_EXPECTED, \"Didn't expect more than one scan\")\nJMESSAGE(JERR_FILE_READ, \"Input file read error\")\nJMESSAGE(JERR_FILE_WRITE, \"Output file write error --- out of disk space?\")\nJMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, \"Fractional sampling not implemented yet\")\nJMESSAGE(JERR_HUFF_CLEN_OUTOFBOUNDS, \"Huffman code size table out of bounds\")\nJMESSAGE(JERR_HUFF_MISSING_CODE, \"Missing Huffman code table entry\")\nJMESSAGE(JERR_IMAGE_TOO_BIG, \"Maximum supported image dimension is %u pixels\")\nJMESSAGE(JERR_INPUT_EMPTY, \"Empty input file\")\nJMESSAGE(JERR_INPUT_EOF, \"Premature end of input file\")\nJMESSAGE(JERR_MISMATCHED_QUANT_TABLE,\n\t \"Cannot transcode due to multiple use of quantization table %d\")\nJMESSAGE(JERR_MISSING_DATA, \"Scan script does not transmit all data\")\nJMESSAGE(JERR_MODE_CHANGE, \"Invalid color quantization mode change\")\nJMESSAGE(JERR_NOTIMPL, \"Not implemented yet\")\nJMESSAGE(JERR_NOT_COMPILED, \"Requested feature was omitted at compile time\")\nJMESSAGE(JERR_NO_ARITH_TABLE, \"Arithmetic table 0x%02x was not defined\")\nJMESSAGE(JERR_NO_BACKING_STORE, \"Backing store not supported\")\nJMESSAGE(JERR_NO_HUFF_TABLE, \"Huffman table 0x%02x was not defined\")\nJMESSAGE(JERR_NO_IMAGE, \"JPEG datastream contains no image\")\nJMESSAGE(JERR_NO_QUANT_TABLE, \"Quantization table 0x%02x was not defined\")\nJMESSAGE(JERR_NO_SOI, \"Not a JPEG file: starts with 0x%02x 0x%02x\")\nJMESSAGE(JERR_OUT_OF_MEMORY, \"Insufficient memory (case %d)\")\nJMESSAGE(JERR_QUANT_COMPONENTS,\n\t \"Cannot quantize more than %d color components\")\nJMESSAGE(JERR_QUANT_FEW_COLORS, \"Cannot quantize to fewer than %d colors\")\nJMESSAGE(JERR_QUANT_MANY_COLORS, \"Cannot quantize to more than %d colors\")\nJMESSAGE(JERR_SOF_BEFORE, \"Invalid JPEG file structure: %s before SOF\")\nJMESSAGE(JERR_SOF_DUPLICATE, \"Invalid JPEG file structure: two SOF markers\")\nJMESSAGE(JERR_SOF_NO_SOS, \"Invalid JPEG file structure: missing SOS marker\")\nJMESSAGE(JERR_SOF_UNSUPPORTED, \"Unsupported JPEG process: SOF type 0x%02x\")\nJMESSAGE(JERR_SOI_DUPLICATE, \"Invalid JPEG file structure: two SOI markers\")\nJMESSAGE(JERR_TFILE_CREATE, \"Failed to create temporary file %s\")\nJMESSAGE(JERR_TFILE_READ, \"Read failed on temporary file\")\nJMESSAGE(JERR_TFILE_SEEK, \"Seek failed on temporary file\")\nJMESSAGE(JERR_TFILE_WRITE,\n\t \"Write failed on temporary file --- out of disk space?\")\nJMESSAGE(JERR_TOO_LITTLE_DATA, \"Application transferred too few scanlines\")\nJMESSAGE(JERR_UNKNOWN_MARKER, \"Unsupported marker type 0x%02x\")\nJMESSAGE(JERR_VIRTUAL_BUG, \"Virtual array controller messed up\")\nJMESSAGE(JERR_WIDTH_OVERFLOW, \"Image too wide for this implementation\")\nJMESSAGE(JERR_XMS_READ, \"Read from XMS failed\")\nJMESSAGE(JERR_XMS_WRITE, \"Write to XMS failed\")\nJMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)\nJMESSAGE(JMSG_VERSION, JVERSION)\nJMESSAGE(JTRC_16BIT_TABLES,\n\t \"Caution: quantization tables are too coarse for baseline JPEG\")\nJMESSAGE(JTRC_ADOBE,\n\t \"Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d\")\nJMESSAGE(JTRC_APP0, \"Unknown APP0 marker (not JFIF), length %u\")\nJMESSAGE(JTRC_APP14, \"Unknown APP14 marker (not Adobe), length %u\")\nJMESSAGE(JTRC_DAC, \"Define Arithmetic Table 0x%02x: 0x%02x\")\nJMESSAGE(JTRC_DHT, \"Define Huffman Table 0x%02x\")\nJMESSAGE(JTRC_DQT, \"Define Quantization Table %d  precision %d\")\nJMESSAGE(JTRC_DRI, \"Define Restart Interval %u\")\nJMESSAGE(JTRC_EMS_CLOSE, \"Freed EMS handle %u\")\nJMESSAGE(JTRC_EMS_OPEN, \"Obtained EMS handle %u\")\nJMESSAGE(JTRC_EOI, \"End Of Image\")\nJMESSAGE(JTRC_HUFFBITS, \"        %3d %3d %3d %3d %3d %3d %3d %3d\")\nJMESSAGE(JTRC_JFIF, \"JFIF APP0 marker: version %d.%02d, density %dx%d  %d\")\nJMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,\n\t \"Warning: thumbnail image size does not match data length %u\")\nJMESSAGE(JTRC_JFIF_EXTENSION,\n\t \"JFIF extension marker: type 0x%02x, length %u\")\nJMESSAGE(JTRC_JFIF_THUMBNAIL, \"    with %d x %d thumbnail image\")\nJMESSAGE(JTRC_MISC_MARKER, \"Miscellaneous marker 0x%02x, length %u\")\nJMESSAGE(JTRC_PARMLESS_MARKER, \"Unexpected marker 0x%02x\")\nJMESSAGE(JTRC_QUANTVALS, \"        %4u %4u %4u %4u %4u %4u %4u %4u\")\nJMESSAGE(JTRC_QUANT_3_NCOLORS, \"Quantizing to %d = %d*%d*%d colors\")\nJMESSAGE(JTRC_QUANT_NCOLORS, \"Quantizing to %d colors\")\nJMESSAGE(JTRC_QUANT_SELECTED, \"Selected %d colors for quantization\")\nJMESSAGE(JTRC_RECOVERY_ACTION, \"At marker 0x%02x, recovery action %d\")\nJMESSAGE(JTRC_RST, \"RST%d\")\nJMESSAGE(JTRC_SMOOTH_NOTIMPL,\n\t \"Smoothing not supported with nonstandard sampling ratios\")\nJMESSAGE(JTRC_SOF, \"Start Of Frame 0x%02x: width=%u, height=%u, components=%d\")\nJMESSAGE(JTRC_SOF_COMPONENT, \"    Component %d: %dhx%dv q=%d\")\nJMESSAGE(JTRC_SOI, \"Start of Image\")\nJMESSAGE(JTRC_SOS, \"Start Of Scan: %d components\")\nJMESSAGE(JTRC_SOS_COMPONENT, \"    Component %d: dc=%d ac=%d\")\nJMESSAGE(JTRC_SOS_PARAMS, \"  Ss=%d, Se=%d, Ah=%d, Al=%d\")\nJMESSAGE(JTRC_TFILE_CLOSE, \"Closed temporary file %s\")\nJMESSAGE(JTRC_TFILE_OPEN, \"Opened temporary file %s\")\nJMESSAGE(JTRC_THUMB_JPEG,\n\t \"JFIF extension marker: JPEG-compressed thumbnail image, length %u\")\nJMESSAGE(JTRC_THUMB_PALETTE,\n\t \"JFIF extension marker: palette thumbnail image, length %u\")\nJMESSAGE(JTRC_THUMB_RGB,\n\t \"JFIF extension marker: RGB thumbnail image, length %u\")\nJMESSAGE(JTRC_UNKNOWN_IDS,\n\t \"Unrecognized component IDs %d %d %d, assuming YCbCr\")\nJMESSAGE(JTRC_XMS_CLOSE, \"Freed XMS handle %u\")\nJMESSAGE(JTRC_XMS_OPEN, \"Obtained XMS handle %u\")\nJMESSAGE(JWRN_ADOBE_XFORM, \"Unknown Adobe color transform code %d\")\nJMESSAGE(JWRN_ARITH_BAD_CODE, \"Corrupt JPEG data: bad arithmetic code\")\nJMESSAGE(JWRN_BOGUS_PROGRESSION,\n\t \"Inconsistent progression sequence for component %d coefficient %d\")\nJMESSAGE(JWRN_EXTRANEOUS_DATA,\n\t \"Corrupt JPEG data: %u extraneous bytes before marker 0x%02x\")\nJMESSAGE(JWRN_HIT_MARKER, \"Corrupt JPEG data: premature end of data segment\")\nJMESSAGE(JWRN_HUFF_BAD_CODE, \"Corrupt JPEG data: bad Huffman code\")\nJMESSAGE(JWRN_JFIF_MAJOR, \"Warning: unknown JFIF revision number %d.%02d\")\nJMESSAGE(JWRN_JPEG_EOF, \"Premature end of JPEG file\")\nJMESSAGE(JWRN_MUST_RESYNC,\n\t \"Corrupt JPEG data: found marker 0x%02x instead of RST%d\")\nJMESSAGE(JWRN_NOT_SEQUENTIAL, \"Invalid SOS parameters for sequential JPEG\")\nJMESSAGE(JWRN_TOO_MUCH_DATA, \"Application transferred too many scanlines\")\n\n#ifdef JMAKE_ENUM_LIST\n\n  JMSG_LASTMSGCODE\n} J_MESSAGE_CODE;\n\n#undef JMAKE_ENUM_LIST\n#endif /* JMAKE_ENUM_LIST */\n\n/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */\n#undef JMESSAGE\n\n\n#ifndef JERROR_H\n#define JERROR_H\n\n/* Macros to simplify using the error and trace message stuff */\n/* The first parameter is either type of cinfo pointer */\n\n/* Fatal errors (print message and exit) */\n#define ERREXIT(cinfo,code)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXIT1(cinfo,code,p1)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXIT2(cinfo,code,p1,p2)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXIT3(cinfo,code,p1,p2,p3)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (cinfo)->err->msg_parm.i[2] = (p3), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXIT4(cinfo,code,p1,p2,p3,p4)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (cinfo)->err->msg_parm.i[2] = (p3), \\\n   (cinfo)->err->msg_parm.i[3] = (p4), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (cinfo)->err->msg_parm.i[2] = (p3), \\\n   (cinfo)->err->msg_parm.i[3] = (p4), \\\n   (cinfo)->err->msg_parm.i[4] = (p5), \\\n   (cinfo)->err->msg_parm.i[5] = (p6), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n#define ERREXITS(cinfo,code,str)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \\\n   (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))\n\n#define MAKESTMT(stuff)\t\tdo { stuff } while (0)\n\n/* Nonfatal errors (we can keep going, but the data is probably corrupt) */\n#define WARNMS(cinfo,code)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))\n#define WARNMS1(cinfo,code,p1)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))\n#define WARNMS2(cinfo,code,p1,p2)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))\n\n/* Informational/debugging messages */\n#define TRACEMS(cinfo,lvl,code)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))\n#define TRACEMS1(cinfo,lvl,code,p1)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))\n#define TRACEMS2(cinfo,lvl,code,p1,p2)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   (cinfo)->err->msg_parm.i[0] = (p1), \\\n   (cinfo)->err->msg_parm.i[1] = (p2), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))\n#define TRACEMS3(cinfo,lvl,code,p1,p2,p3)  \\\n  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \\\n\t   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \\\n\t   (cinfo)->err->msg_code = (code); \\\n\t   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )\n#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4)  \\\n  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \\\n\t   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \\\n\t   (cinfo)->err->msg_code = (code); \\\n\t   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )\n#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5)  \\\n  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \\\n\t   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \\\n\t   _mp[4] = (p5); \\\n\t   (cinfo)->err->msg_code = (code); \\\n\t   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )\n#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8)  \\\n  MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \\\n\t   _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \\\n\t   _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \\\n\t   (cinfo)->err->msg_code = (code); \\\n\t   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )\n#define TRACEMSS(cinfo,lvl,code,str)  \\\n  ((cinfo)->err->msg_code = (code), \\\n   strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \\\n   (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))\n\n#endif /* JERROR_H */\n"
  },
  {
    "path": "dlib/external/libjpeg/jfdctflt.c",
    "content": "/*\n * jfdctflt.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2003-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a floating-point implementation of the\n * forward DCT (Discrete Cosine Transform).\n *\n * This implementation should be more accurate than either of the integer\n * DCT implementations.  However, it may not give the same results on all\n * machines because of differences in roundoff behavior.  Speed will depend\n * on the hardware's floating point capacity.\n *\n * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT\n * on each column.  Direct algorithms are also available, but they are\n * much more complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on Arai, Agui, and Nakajima's algorithm for\n * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in\n * Japanese, but the algorithm is described in the Pennebaker & Mitchell\n * JPEG textbook (see REFERENCES section in file README).  The following code\n * is based directly on figure 4-8 in P&M.\n * While an 8-point DCT cannot be done in less than 11 multiplies, it is\n * possible to arrange the computation so that many of the multiplies are\n * simple scalings of the final outputs.  These multiplies can then be\n * folded into the multiplications or divisions by the JPEG quantization\n * table entries.  The AA&N method leaves only 5 multiplies and 29 adds\n * to be done in the DCT itself.\n * The primary disadvantage of this method is that with a fixed-point\n * implementation, accuracy is lost due to imprecise representation of the\n * scaled quantization values.  However, that problem does not arise if\n * we use floating point arithmetic.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_FLOAT_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/*\n * Perform the forward DCT on one block of samples.\n *\n * cK represents cos(K*pi/16).\n */\n\nGLOBAL(void)\njpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  FAST_FLOAT tmp10, tmp11, tmp12, tmp13;\n  FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;\n  FAST_FLOAT *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n\n  /* Pass 1: process rows. */\n\n  dataptr = data;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Load data into workspace */\n    tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]));\n    tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]));\n    tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]));\n    tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]));\n    tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]));\n    tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]));\n    tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]));\n    tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]));\n\n    /* Even part */\n\n    tmp10 = tmp0 + tmp3;\t/* phase 2 */\n    tmp13 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp12 = tmp1 - tmp2;\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */\n    dataptr[4] = tmp10 - tmp11;\n\n    z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */\n    dataptr[2] = tmp13 + z1;\t/* phase 5 */\n    dataptr[6] = tmp13 - z1;\n\n    /* Odd part */\n\n    tmp10 = tmp4 + tmp5;\t/* phase 2 */\n    tmp11 = tmp5 + tmp6;\n    tmp12 = tmp6 + tmp7;\n\n    /* The rotator is modified from fig 4-8 to avoid extra negations. */\n    z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */\n    z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */\n    z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */\n    z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */\n\n    z11 = tmp7 + z3;\t\t/* phase 5 */\n    z13 = tmp7 - z3;\n\n    dataptr[5] = z13 + z2;\t/* phase 6 */\n    dataptr[3] = z13 - z2;\n    dataptr[1] = z11 + z4;\n    dataptr[7] = z11 - z4;\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns. */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];\n    tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];\n    tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];\n    tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];\n\n    /* Even part */\n\n    tmp10 = tmp0 + tmp3;\t/* phase 2 */\n    tmp13 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp12 = tmp1 - tmp2;\n\n    dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */\n    dataptr[DCTSIZE*4] = tmp10 - tmp11;\n\n    z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */\n    dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */\n    dataptr[DCTSIZE*6] = tmp13 - z1;\n\n    /* Odd part */\n\n    tmp10 = tmp4 + tmp5;\t/* phase 2 */\n    tmp11 = tmp5 + tmp6;\n    tmp12 = tmp6 + tmp7;\n\n    /* The rotator is modified from fig 4-8 to avoid extra negations. */\n    z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */\n    z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */\n    z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */\n    z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */\n\n    z11 = tmp7 + z3;\t\t/* phase 5 */\n    z13 = tmp7 - z3;\n\n    dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */\n    dataptr[DCTSIZE*3] = z13 - z2;\n    dataptr[DCTSIZE*1] = z11 + z4;\n    dataptr[DCTSIZE*7] = z11 - z4;\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n#endif /* DCT_FLOAT_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jfdctfst.c",
    "content": "/*\n * jfdctfst.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2003-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a fast, not so accurate integer implementation of the\n * forward DCT (Discrete Cosine Transform).\n *\n * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT\n * on each column.  Direct algorithms are also available, but they are\n * much more complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on Arai, Agui, and Nakajima's algorithm for\n * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in\n * Japanese, but the algorithm is described in the Pennebaker & Mitchell\n * JPEG textbook (see REFERENCES section in file README).  The following code\n * is based directly on figure 4-8 in P&M.\n * While an 8-point DCT cannot be done in less than 11 multiplies, it is\n * possible to arrange the computation so that many of the multiplies are\n * simple scalings of the final outputs.  These multiplies can then be\n * folded into the multiplications or divisions by the JPEG quantization\n * table entries.  The AA&N method leaves only 5 multiplies and 29 adds\n * to be done in the DCT itself.\n * The primary disadvantage of this method is that with fixed-point math,\n * accuracy is lost due to imprecise representation of the scaled\n * quantization values.  The smaller the quantization table entry, the less\n * precise the scaled value, so this implementation does worse with high-\n * quality-setting files than with low-quality ones.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_IFAST_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/* Scaling decisions are generally the same as in the LL&M algorithm;\n * see jfdctint.c for more details.  However, we choose to descale\n * (right shift) multiplication products as soon as they are formed,\n * rather than carrying additional fractional bits into subsequent additions.\n * This compromises accuracy slightly, but it lets us save a few shifts.\n * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)\n * everywhere except in the multiplications proper; this saves a good deal\n * of work on 16-bit-int machines.\n *\n * Again to save a few shifts, the intermediate results between pass 1 and\n * pass 2 are not upscaled, but are represented only to integral precision.\n *\n * A final compromise is to represent the multiplicative constants to only\n * 8 fractional bits, rather than 13.  This saves some shifting work on some\n * machines, and may also reduce the cost of multiplication (since there\n * are fewer one-bits in the constants).\n */\n\n#define CONST_BITS  8\n\n\n/* Some C compilers fail to reduce \"FIX(constant)\" at compile time, thus\n * causing a lot of useless floating-point operations at run time.\n * To get around this we use the following pre-calculated constants.\n * If you change CONST_BITS you may want to add appropriate values.\n * (With a reasonable C compiler, you can just rely on the FIX() macro...)\n */\n\n#if CONST_BITS == 8\n#define FIX_0_382683433  ((INT32)   98)\t\t/* FIX(0.382683433) */\n#define FIX_0_541196100  ((INT32)  139)\t\t/* FIX(0.541196100) */\n#define FIX_0_707106781  ((INT32)  181)\t\t/* FIX(0.707106781) */\n#define FIX_1_306562965  ((INT32)  334)\t\t/* FIX(1.306562965) */\n#else\n#define FIX_0_382683433  FIX(0.382683433)\n#define FIX_0_541196100  FIX(0.541196100)\n#define FIX_0_707106781  FIX(0.707106781)\n#define FIX_1_306562965  FIX(1.306562965)\n#endif\n\n\n/* We can gain a little more speed, with a further compromise in accuracy,\n * by omitting the addition in a descaling shift.  This yields an incorrectly\n * rounded result half the time...\n */\n\n#ifndef USE_ACCURATE_ROUNDING\n#undef DESCALE\n#define DESCALE(x,n)  RIGHT_SHIFT(x, n)\n#endif\n\n\n/* Multiply a DCTELEM variable by an INT32 constant, and immediately\n * descale to yield a DCTELEM result.\n */\n\n#define MULTIPLY(var,const)  ((DCTELEM) DESCALE((var) * (const), CONST_BITS))\n\n\n/*\n * Perform the forward DCT on one block of samples.\n *\n * cK represents cos(K*pi/16).\n */\n\nGLOBAL(void)\njpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  DCTELEM tmp10, tmp11, tmp12, tmp13;\n  DCTELEM z1, z2, z3, z4, z5, z11, z13;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows. */\n\n  dataptr = data;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Load data into workspace */\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);\n    tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);\n    tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);\n    tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);\n    tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);\n\n    /* Even part */\n\n    tmp10 = tmp0 + tmp3;\t/* phase 2 */\n    tmp13 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp12 = tmp1 - tmp2;\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */\n    dataptr[4] = tmp10 - tmp11;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */\n    dataptr[2] = tmp13 + z1;\t/* phase 5 */\n    dataptr[6] = tmp13 - z1;\n\n    /* Odd part */\n\n    tmp10 = tmp4 + tmp5;\t/* phase 2 */\n    tmp11 = tmp5 + tmp6;\n    tmp12 = tmp6 + tmp7;\n\n    /* The rotator is modified from fig 4-8 to avoid extra negations. */\n    z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */\n    z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */\n    z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */\n    z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */\n\n    z11 = tmp7 + z3;\t\t/* phase 5 */\n    z13 = tmp7 - z3;\n\n    dataptr[5] = z13 + z2;\t/* phase 6 */\n    dataptr[3] = z13 - z2;\n    dataptr[1] = z11 + z4;\n    dataptr[7] = z11 - z4;\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns. */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];\n    tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];\n    tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];\n    tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];\n\n    /* Even part */\n\n    tmp10 = tmp0 + tmp3;\t/* phase 2 */\n    tmp13 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp12 = tmp1 - tmp2;\n\n    dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */\n    dataptr[DCTSIZE*4] = tmp10 - tmp11;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */\n    dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */\n    dataptr[DCTSIZE*6] = tmp13 - z1;\n\n    /* Odd part */\n\n    tmp10 = tmp4 + tmp5;\t/* phase 2 */\n    tmp11 = tmp5 + tmp6;\n    tmp12 = tmp6 + tmp7;\n\n    /* The rotator is modified from fig 4-8 to avoid extra negations. */\n    z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */\n    z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */\n    z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */\n    z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */\n\n    z11 = tmp7 + z3;\t\t/* phase 5 */\n    z13 = tmp7 - z3;\n\n    dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */\n    dataptr[DCTSIZE*3] = z13 - z2;\n    dataptr[DCTSIZE*1] = z11 + z4;\n    dataptr[DCTSIZE*7] = z11 - z4;\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n#endif /* DCT_IFAST_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jfdctint.c",
    "content": "/*\n * jfdctint.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modification developed 2003-2018 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a slow-but-accurate integer implementation of the\n * forward DCT (Discrete Cosine Transform).\n *\n * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT\n * on each column.  Direct algorithms are also available, but they are\n * much more complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on an algorithm described in\n *   C. Loeffler, A. Ligtenberg and G. Moschytz, \"Practical Fast 1-D DCT\n *   Algorithms with 11 Multiplications\", Proc. Int'l. Conf. on Acoustics,\n *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.\n * The primary algorithm described there uses 11 multiplies and 29 adds.\n * We use their alternate method with 12 multiplies and 32 adds.\n * The advantage of this method is that no data path contains more than one\n * multiplication; this allows a very simple and accurate implementation in\n * scaled fixed-point arithmetic, with a minimal number of shifts.\n *\n * We also provide FDCT routines with various input sample block sizes for\n * direct resolution reduction or enlargement and for direct resolving the\n * common 2x1 and 1x2 subsampling cases without additional resampling: NxN\n * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block.\n *\n * For N<8 we fill the remaining block coefficients with zero.\n * For N>8 we apply a partial N-point FDCT on the input samples, computing\n * just the lower 8 frequency coefficients and discarding the rest.\n *\n * We must scale the output coefficients of the N-point FDCT appropriately\n * to the standard 8-point FDCT level by 8/N per 1-D pass.  This scaling\n * is folded into the constant multipliers (pass 2) and/or final/initial\n * shifting.\n *\n * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases\n * since there would be too many additional constants to pre-calculate.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_ISLOW_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/*\n * The poop on this scaling stuff is as follows:\n *\n * Each 1-D DCT step produces outputs which are a factor of sqrt(N)\n * larger than the true DCT outputs.  The final outputs are therefore\n * a factor of N larger than desired; since N=8 this can be cured by\n * a simple right shift at the end of the algorithm.  The advantage of\n * this arrangement is that we save two multiplications per 1-D DCT,\n * because the y0 and y4 outputs need not be divided by sqrt(N).\n * In the IJG code, this factor of 8 is removed by the quantization step\n * (in jcdctmgr.c), NOT in this module.\n *\n * We have to do addition and subtraction of the integer inputs, which\n * is no problem, and multiplication by fractional constants, which is\n * a problem to do in integer arithmetic.  We multiply all the constants\n * by CONST_SCALE and convert them to integer constants (thus retaining\n * CONST_BITS bits of precision in the constants).  After doing a\n * multiplication we have to divide the product by CONST_SCALE, with proper\n * rounding, to produce the correct output.  This division can be done\n * cheaply as a right shift of CONST_BITS bits.  We postpone shifting\n * as long as possible so that partial sums can be added together with\n * full fractional precision.\n *\n * The outputs of the first pass are scaled up by PASS1_BITS bits so that\n * they are represented to better-than-integral precision.  These outputs\n * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word\n * with the recommended scaling.  (For 12-bit sample data, the intermediate\n * array is INT32 anyway.)\n *\n * To avoid overflow of the 32-bit intermediate results in pass 2, we must\n * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis\n * shows that the values given below are the most effective.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define CONST_BITS  13\n#define PASS1_BITS  2\n#else\n#define CONST_BITS  13\n#define PASS1_BITS  1\t\t/* lose a little precision to avoid overflow */\n#endif\n\n/* Some C compilers fail to reduce \"FIX(constant)\" at compile time, thus\n * causing a lot of useless floating-point operations at run time.\n * To get around this we use the following pre-calculated constants.\n * If you change CONST_BITS you may want to add appropriate values.\n * (With a reasonable C compiler, you can just rely on the FIX() macro...)\n */\n\n#if CONST_BITS == 13\n#define FIX_0_298631336  ((INT32)  2446)\t/* FIX(0.298631336) */\n#define FIX_0_390180644  ((INT32)  3196)\t/* FIX(0.390180644) */\n#define FIX_0_541196100  ((INT32)  4433)\t/* FIX(0.541196100) */\n#define FIX_0_765366865  ((INT32)  6270)\t/* FIX(0.765366865) */\n#define FIX_0_899976223  ((INT32)  7373)\t/* FIX(0.899976223) */\n#define FIX_1_175875602  ((INT32)  9633)\t/* FIX(1.175875602) */\n#define FIX_1_501321110  ((INT32)  12299)\t/* FIX(1.501321110) */\n#define FIX_1_847759065  ((INT32)  15137)\t/* FIX(1.847759065) */\n#define FIX_1_961570560  ((INT32)  16069)\t/* FIX(1.961570560) */\n#define FIX_2_053119869  ((INT32)  16819)\t/* FIX(2.053119869) */\n#define FIX_2_562915447  ((INT32)  20995)\t/* FIX(2.562915447) */\n#define FIX_3_072711026  ((INT32)  25172)\t/* FIX(3.072711026) */\n#else\n#define FIX_0_298631336  FIX(0.298631336)\n#define FIX_0_390180644  FIX(0.390180644)\n#define FIX_0_541196100  FIX(0.541196100)\n#define FIX_0_765366865  FIX(0.765366865)\n#define FIX_0_899976223  FIX(0.899976223)\n#define FIX_1_175875602  FIX(1.175875602)\n#define FIX_1_501321110  FIX(1.501321110)\n#define FIX_1_847759065  FIX(1.847759065)\n#define FIX_1_961570560  FIX(1.961570560)\n#define FIX_2_053119869  FIX(2.053119869)\n#define FIX_2_562915447  FIX(2.562915447)\n#define FIX_3_072711026  FIX(3.072711026)\n#endif\n\n\n/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.\n * For 8-bit samples with the recommended scaling, all the variable\n * and constant values involved are no more than 16 bits wide, so a\n * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.\n * For 12-bit samples, a full 32-bit multiplication will be needed.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)\n#else\n#define MULTIPLY(var,const)  ((var) * (const))\n#endif\n\n\n/*\n * Perform the forward DCT on one block of samples.\n */\n\nGLOBAL(void)\njpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);\n\n    tmp10 = tmp0 + tmp3;\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    dataptr[2] = (DCTELEM)\n      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS-PASS1_BITS);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];\n\n    /* Add fudge factor here for final descale. */\n    tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n#ifdef DCT_SCALING_SUPPORTED\n\n\n/*\n * Perform the forward DCT on a 7x7 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12;\n  INT32 z1, z2, z3;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * cK represents sqrt(2) * cos(K*pi/14).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 7; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);\n    tmp3 = GETJSAMPLE(elemptr[3]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);\n\n    z1 = tmp0 + tmp2;\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);\n    tmp3 += tmp3;\n    z1 -= tmp3;\n    z1 -= tmp3;\n    z1 = MULTIPLY(z1, FIX(0.353553391));                /* (c2+c6-c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002));       /* (c2+c4-c6)/2 */\n    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123));       /* c6 */\n    dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);\n    z1 -= z2;\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734));       /* c4 */\n    dataptr[4] = (DCTELEM)\n      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347));   /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339));   /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */\n    tmp1 += tmp2;\n    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268));   /* c5 */\n    tmp0 += tmp3;\n    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693));   /* c3+c1-c5 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/7)**2 = 64/49, which we fold\n   * into the constant multipliers:\n   * cK now represents sqrt(2) * cos(K*pi/14) * 64/49.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 7; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];\n    tmp3 = dataptr[DCTSIZE*3];\n\n    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];\n    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];\n\n    z1 = tmp0 + tmp2;\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp3 += tmp3;\n    z1 -= tmp3;\n    z1 -= tmp3;\n    z1 = MULTIPLY(z1, FIX(0.461784020));                /* (c2+c6-c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084));       /* (c2+c4-c6)/2 */\n    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446));       /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS);\n    z1 -= z2;\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509));       /* c4 */\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677));   /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464));   /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */\n    tmp1 += tmp2;\n    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310));   /* c5 */\n    tmp0 += tmp3;\n    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355));   /* c3+c1-c5 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 6x6 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2;\n  INT32 tmp10, tmp11, tmp12;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 6; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);\n    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */\n\t\t    CONST_BITS-PASS1_BITS);\n\n    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));\n    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);\n    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/6)**2 = 16/9, which we fold\n   * into the constant multipliers:\n   * cK now represents sqrt(2) * cos(K*pi/12) * 16/9.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 6; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];\n    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 5x5 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2;\n  INT32 tmp10, tmp11;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * cK represents sqrt(2) * cos(K*pi/10).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 5; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);\n    tmp2 = GETJSAMPLE(elemptr[2]);\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1));\n    tmp11 = MULTIPLY(tmp11, FIX(0.790569415));          /* (c2+c4)/2 */\n    tmp10 -= tmp2 << 2;\n    tmp10 = MULTIPLY(tmp10, FIX(0.353553391));          /* (c2-c4)/2 */\n    dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1);\n    dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876));    /* c3 */\n\n    dataptr[1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */\n\t      CONST_BITS-PASS1_BITS-1);\n    dataptr[3] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */\n\t      CONST_BITS-PASS1_BITS-1);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/5)**2 = 64/25, which we partially\n   * fold into the constant multipliers (other part was done in pass 1):\n   * cK now represents sqrt(2) * cos(K*pi/10) * 32/25.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 5; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];\n    tmp2 = dataptr[DCTSIZE*2];\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)),        /* 32/25 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp11 = MULTIPLY(tmp11, FIX(1.011928851));          /* (c2+c4)/2 */\n    tmp10 -= tmp2 << 2;\n    tmp10 = MULTIPLY(tmp10, FIX(0.452548340));          /* (c2-c4)/2 */\n    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961));    /* c3 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 4x4 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1;\n  INT32 tmp10, tmp11;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We must also scale the output by (8/4)**2 = 2**2, which we add here.\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 4; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2));\n    dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2));\n\n    /* Odd part */\n\n    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-3);\n\n    dataptr[1] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS-PASS1_BITS-2);\n    dataptr[3] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS-PASS1_BITS-2);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 4; ctr++) {\n    /* Even part */\n\n    /* Add fudge factor here for final descale. */\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];\n\n    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);\n\n    /* Odd part */\n\n    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 3x3 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We scale the results further by 2**2 as part of output adaption\n   * scaling for different DCT size.\n   * cK represents sqrt(2) * cos(K*pi/6).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 3; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);\n    tmp1 = GETJSAMPLE(elemptr[1]);\n\n    tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2));\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */\n\t      CONST_BITS-PASS1_BITS-2);\n\n    /* Odd part */\n\n    dataptr[1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2, FIX(1.224744871)),               /* c1 */\n\t      CONST_BITS-PASS1_BITS-2);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/3)**2 = 64/9, which we partially\n   * fold into the constant multipliers (other part was done in pass 1):\n   * cK now represents sqrt(2) * cos(K*pi/6) * 16/9.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 3; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];\n    tmp1 = dataptr[DCTSIZE*1];\n\n    tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),        /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2, FIX(2.177324216)),               /* c1 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 2x2 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM tmp0, tmp1, tmp2, tmp3;\n  JSAMPROW elemptr;\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   */\n\n  /* Row 0 */\n  elemptr = sample_data[0] + start_col;\n\n  tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);\n  tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);\n\n  /* Row 1 */\n  elemptr = sample_data[1] + start_col;\n\n  tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);\n  tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/2)**2 = 2**4.\n   */\n\n  /* Column 0 */\n  /* Apply unsigned->signed conversion. */\n  data[DCTSIZE*0] = (tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4;\n  data[DCTSIZE*1] = (tmp0 - tmp2) << 4;\n\n  /* Column 1 */\n  data[DCTSIZE*0+1] = (tmp1 + tmp3) << 4;\n  data[DCTSIZE*1+1] = (tmp1 - tmp3) << 4;\n}\n\n\n/*\n * Perform the forward DCT on a 1x1 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM dcval;\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  dcval = GETJSAMPLE(sample_data[0][start_col]);\n\n  /* We leave the result scaled up by an overall factor of 8. */\n  /* We must also scale the output by (8/1)**2 = 2**6. */\n  /* Apply unsigned->signed conversion. */\n  data[0] = (dcval - CENTERJSAMPLE) << 6;\n}\n\n\n/*\n * Perform the forward DCT on a 9x9 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1, z2;\n  DCTELEM workspace[8];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * we scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * cK represents sqrt(2) * cos(K*pi/18).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]);\n    tmp4 = GETJSAMPLE(elemptr[4]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]);\n    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]);\n\n    z1 = tmp0 + tmp2 + tmp3;\n    z2 = tmp1 + tmp4;\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1);\n    dataptr[6] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)),  /* c6 */\n\t      CONST_BITS-1);\n    z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049));        /* c2 */\n    z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441))    /* c4 */\n\t      + z1 + z2, CONST_BITS-1);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608))    /* c8 */\n\t      + z1 - z2, CONST_BITS-1);\n\n    /* Odd part */\n\n    dataptr[3] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */\n\t      CONST_BITS-1);\n\n    tmp11 = MULTIPLY(tmp11, FIX(1.224744871));        /* c3 */\n    tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */\n    tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1);\n\n    tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */\n\n    dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1);\n    dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 9)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/9)**2 = 64/81, which we partially\n   * fold into the constant multipliers and final/initial shifting:\n   * cK now represents sqrt(2) * cos(K*pi/18) * 128/81.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5];\n    tmp4 = dataptr[DCTSIZE*4];\n\n    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7];\n    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6];\n    tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5];\n\n    z1 = tmp0 + tmp2 + tmp3;\n    z2 = tmp1 + tmp4;\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)),       /* 128/81 */\n\t      CONST_BITS+2);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)),  /* c6 */\n\t      CONST_BITS+2);\n    z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287));        /* c2 */\n    z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190))    /* c4 */\n\t      + z1 + z2, CONST_BITS+2);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096))    /* c8 */\n\t      + z1 - z2, CONST_BITS+2);\n\n    /* Odd part */\n\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */\n\t      CONST_BITS+2);\n\n    tmp11 = MULTIPLY(tmp11, FIX(1.935399303));        /* c3 */\n    tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */\n    tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2);\n\n    tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */\n\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2);\n    dataptr[DCTSIZE*7] = (DCTELEM)\n      DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 10x10 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  DCTELEM workspace[8*2];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * we scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * cK represents sqrt(2) * cos(K*pi/20).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);\n    tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);\n\n    tmp10 = tmp0 + tmp4;\n    tmp13 = tmp0 - tmp4;\n    tmp11 = tmp1 + tmp3;\n    tmp14 = tmp1 - tmp3;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1);\n    tmp12 += tmp12;\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */\n\t      MULTIPLY(tmp11 - tmp12, FIX(0.437016024)),  /* c8 */\n\t      CONST_BITS-1);\n    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876));    /* c6 */\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)),  /* c2-c6 */\n\t      CONST_BITS-1);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)),  /* c2+c6 */\n\t      CONST_BITS-1);\n\n    /* Odd part */\n\n    tmp10 = tmp0 + tmp4;\n    tmp11 = tmp1 - tmp3;\n    dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1);\n    tmp2 <<= CONST_BITS;\n    dataptr[1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) +          /* c1 */\n\t      MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 +   /* c3 */\n\t      MULTIPLY(tmp3, FIX(0.642039522)) +          /* c7 */\n\t      MULTIPLY(tmp4, FIX(0.221231742)),           /* c9 */\n\t      CONST_BITS-1);\n    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) -     /* (c3+c7)/2 */\n\t    MULTIPLY(tmp1 + tmp3, FIX(0.587785252));      /* (c1-c9)/2 */\n    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) +   /* (c3-c7)/2 */\n\t    (tmp11 << (CONST_BITS - 1)) - tmp2;\n    dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1);\n    dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 10)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/10)**2 = 16/25, which we partially\n   * fold into the constant multipliers and final/initial shifting:\n   * cK now represents sqrt(2) * cos(K*pi/20) * 32/25.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];\n    tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];\n    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];\n\n    tmp10 = tmp0 + tmp4;\n    tmp13 = tmp0 - tmp4;\n    tmp11 = tmp1 + tmp3;\n    tmp14 = tmp1 - tmp3;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];\n    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];\n    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */\n\t      CONST_BITS+2);\n    tmp12 += tmp12;\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */\n\t      MULTIPLY(tmp11 - tmp12, FIX(0.559380511)),  /* c8 */\n\t      CONST_BITS+2);\n    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961));    /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)),  /* c2-c6 */\n\t      CONST_BITS+2);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)),  /* c2+c6 */\n\t      CONST_BITS+2);\n\n    /* Odd part */\n\n    tmp10 = tmp0 + tmp4;\n    tmp11 = tmp1 - tmp3;\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)),  /* 32/25 */\n\t      CONST_BITS+2);\n    tmp2 = MULTIPLY(tmp2, FIX(1.28));                     /* 32/25 */\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) +          /* c1 */\n\t      MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 +   /* c3 */\n\t      MULTIPLY(tmp3, FIX(0.821810588)) +          /* c7 */\n\t      MULTIPLY(tmp4, FIX(0.283176630)),           /* c9 */\n\t      CONST_BITS+2);\n    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) -     /* (c3+c7)/2 */\n\t    MULTIPLY(tmp1 + tmp3, FIX(0.752365123));      /* (c1-c9)/2 */\n    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) +   /* (c3-c7)/2 */\n\t    MULTIPLY(tmp11, FIX(0.64)) - tmp2;            /* 16/25 */\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on an 11x11 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 z1, z2, z3;\n  DCTELEM workspace[8*3];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * we scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * cK represents sqrt(2) * cos(K*pi/22).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]);\n    tmp5 = GETJSAMPLE(elemptr[5]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]);\n    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]);\n    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1);\n    tmp5 += tmp5;\n    tmp0 -= tmp5;\n    tmp1 -= tmp5;\n    tmp2 -= tmp5;\n    tmp3 -= tmp5;\n    tmp4 -= tmp5;\n    z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) +       /* c2 */\n\t MULTIPLY(tmp2 + tmp4, FIX(0.201263574));        /* c10 */\n    z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931));        /* c6 */\n    z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156));        /* c4 */\n    dataptr[2] = (DCTELEM)\n      DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */\n\t      - MULTIPLY(tmp4, FIX(1.390975730)),        /* c4+c10 */\n\t      CONST_BITS-1);\n    dataptr[4] = (DCTELEM)\n      DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */\n\t      - MULTIPLY(tmp2, FIX(1.356927976))         /* c2 */\n\t      + MULTIPLY(tmp4, FIX(0.587485545)),        /* c8 */\n\t      CONST_BITS-1);\n    dataptr[6] = (DCTELEM)\n      DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */\n\t      - MULTIPLY(tmp2, FIX(0.788749120)),        /* c8+c10 */\n\t      CONST_BITS-1);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905));    /* c3 */\n    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298));    /* c5 */\n    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576));    /* c7 */\n    tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */\n\t   + MULTIPLY(tmp14, FIX(0.398430003));          /* c9 */\n    tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576));  /* -c7 */\n    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907));  /* -c1 */\n    tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */\n\t    - MULTIPLY(tmp14, FIX(1.068791298));         /* c5 */\n    tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003));   /* c9 */\n    tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */\n\t    + MULTIPLY(tmp14, FIX(1.399818907));         /* c1 */\n    tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */\n\t    - MULTIPLY(tmp14, FIX(1.286413905));         /* c3 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1);\n    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 11)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/11)**2 = 64/121, which we partially\n   * fold into the constant multipliers and final/initial shifting:\n   * cK now represents sqrt(2) * cos(K*pi/22) * 128/121.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7];\n    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6];\n    tmp5 = dataptr[DCTSIZE*5];\n\n    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2];\n    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1];\n    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0];\n    tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7];\n    tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5,\n\t\t       FIX(1.057851240)),                /* 128/121 */\n\t      CONST_BITS+2);\n    tmp5 += tmp5;\n    tmp0 -= tmp5;\n    tmp1 -= tmp5;\n    tmp2 -= tmp5;\n    tmp3 -= tmp5;\n    tmp4 -= tmp5;\n    z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) +       /* c2 */\n\t MULTIPLY(tmp2 + tmp4, FIX(0.212906922));        /* c10 */\n    z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713));        /* c6 */\n    z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479));        /* c4 */\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */\n\t      - MULTIPLY(tmp4, FIX(1.471445400)),        /* c4+c10 */\n\t      CONST_BITS+2);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */\n\t      - MULTIPLY(tmp2, FIX(1.435427942))         /* c2 */\n\t      + MULTIPLY(tmp4, FIX(0.621472312)),        /* c8 */\n\t      CONST_BITS+2);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */\n\t      - MULTIPLY(tmp2, FIX(0.834379234)),        /* c8+c10 */\n\t      CONST_BITS+2);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544));    /* c3 */\n    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199));    /* c5 */\n    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568));    /* c7 */\n    tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */\n\t   + MULTIPLY(tmp14, FIX(0.421479672));          /* c9 */\n    tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568));  /* -c7 */\n    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167));  /* -c1 */\n    tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */\n\t    - MULTIPLY(tmp14, FIX(1.130622199));         /* c5 */\n    tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672));   /* c9 */\n    tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */\n\t    + MULTIPLY(tmp14, FIX(1.480800167));         /* c1 */\n    tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */\n\t    - MULTIPLY(tmp14, FIX(1.360834544));         /* c3 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 12x12 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  DCTELEM workspace[8*4];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   * cK represents sqrt(2) * cos(K*pi/24).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);\n\n    tmp10 = tmp0 + tmp5;\n    tmp13 = tmp0 - tmp5;\n    tmp11 = tmp1 + tmp4;\n    tmp14 = tmp1 - tmp4;\n    tmp12 = tmp2 + tmp3;\n    tmp15 = tmp2 - tmp3;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE);\n    dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */\n\t      CONST_BITS);\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */\n\t      CONST_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100);    /* c9 */\n    tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865);   /* c3-c9 */\n    tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065);   /* c3+c9 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054));   /* c5 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669));   /* c7 */\n    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */\n\t    + MULTIPLY(tmp5, FIX(0.184591911));        /* c11 */\n    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */\n    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */\n\t    + MULTIPLY(tmp5, FIX(0.860918669));        /* c7 */\n    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */\n\t    - MULTIPLY(tmp5, FIX(1.121971054));        /* c5 */\n    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */\n\t    - MULTIPLY(tmp2 + tmp5, FIX_0_541196100);  /* c9 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 12)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/12)**2 = 4/9, which we partially\n   * fold into the constant multipliers and final shifting:\n   * cK now represents sqrt(2) * cos(K*pi/24) * 8/9.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];\n    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];\n    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];\n\n    tmp10 = tmp0 + tmp5;\n    tmp13 = tmp0 - tmp5;\n    tmp11 = tmp1 + tmp4;\n    tmp14 = tmp1 - tmp4;\n    tmp12 = tmp2 + tmp3;\n    tmp15 = tmp2 - tmp3;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];\n    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];\n    tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */\n\t      CONST_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */\n\t      CONST_BITS+1);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)),         /* c4 */\n\t      CONST_BITS+1);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) +        /* 8/9 */\n\t      MULTIPLY(tmp13 + tmp15, FIX(1.214244803)),         /* c2 */\n\t      CONST_BITS+1);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200));   /* c9 */\n    tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102));  /* c3-c9 */\n    tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502));  /* c3+c9 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603));   /* c5 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039));   /* c7 */\n    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */\n\t    + MULTIPLY(tmp5, FIX(0.164081699));        /* c11 */\n    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */\n    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */\n\t    + MULTIPLY(tmp5, FIX(0.765261039));        /* c7 */\n    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */\n\t    - MULTIPLY(tmp5, FIX(0.997307603));        /* c5 */\n    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */\n\t    - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 13x13 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  INT32 z1, z2;\n  DCTELEM workspace[8*5];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   * cK represents sqrt(2) * cos(K*pi/26).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]);\n    tmp6 = GETJSAMPLE(elemptr[6]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]);\n    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]);\n    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]);\n    tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE);\n    tmp6 += tmp6;\n    tmp0 -= tmp6;\n    tmp1 -= tmp6;\n    tmp2 -= tmp6;\n    tmp3 -= tmp6;\n    tmp4 -= tmp6;\n    tmp5 -= tmp6;\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) +   /* c2 */\n\t      MULTIPLY(tmp1, FIX(1.058554052)) +   /* c6 */\n\t      MULTIPLY(tmp2, FIX(0.501487041)) -   /* c10 */\n\t      MULTIPLY(tmp3, FIX(0.170464608)) -   /* c12 */\n\t      MULTIPLY(tmp4, FIX(0.803364869)) -   /* c8 */\n\t      MULTIPLY(tmp5, FIX(1.252223920)),    /* c4 */\n\t      CONST_BITS);\n    z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */\n\t MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */\n\t MULTIPLY(tmp1 - tmp5, FIX(0.316450131));  /* (c8-c12)/2 */\n    z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */\n\t MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */\n\t MULTIPLY(tmp1 + tmp5, FIX(0.486914739));  /* (c8+c12)/2 */\n\n    dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS);\n    dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651));   /* c3 */\n    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945));   /* c5 */\n    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) +  /* c7 */\n\t   MULTIPLY(tmp14 + tmp15, FIX(0.338443458));   /* c11 */\n    tmp0 = tmp1 + tmp2 + tmp3 -\n\t   MULTIPLY(tmp10, FIX(2.020082300)) +          /* c3+c5+c7-c1 */\n\t   MULTIPLY(tmp14, FIX(0.318774355));           /* c9-c11 */\n    tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) -  /* c7 */\n\t   MULTIPLY(tmp11 + tmp12, FIX(0.338443458));   /* c11 */\n    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */\n    tmp1 += tmp4 + tmp5 +\n\t    MULTIPLY(tmp11, FIX(0.837223564)) -         /* c5+c9+c11-c3 */\n\t    MULTIPLY(tmp14, FIX(2.341699410));          /* c1+c7 */\n    tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */\n    tmp2 += tmp4 + tmp6 -\n\t    MULTIPLY(tmp12, FIX(1.572116027)) +         /* c1+c5-c9-c11 */\n\t    MULTIPLY(tmp15, FIX(2.260109708));          /* c3+c7 */\n    tmp3 += tmp5 + tmp6 +\n\t    MULTIPLY(tmp13, FIX(2.205608352)) -         /* c3+c5+c9-c7 */\n\t    MULTIPLY(tmp15, FIX(1.742345811));          /* c1+c11 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 13)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/13)**2 = 64/169, which we partially\n   * fold into the constant multipliers and final shifting:\n   * cK now represents sqrt(2) * cos(K*pi/26) * 128/169.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0];\n    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7];\n    tmp6 = dataptr[DCTSIZE*6];\n\n    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4];\n    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3];\n    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2];\n    tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1];\n    tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0];\n    tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6,\n\t\t       FIX(0.757396450)),          /* 128/169 */\n\t      CONST_BITS+1);\n    tmp6 += tmp6;\n    tmp0 -= tmp6;\n    tmp1 -= tmp6;\n    tmp2 -= tmp6;\n    tmp3 -= tmp6;\n    tmp4 -= tmp6;\n    tmp5 -= tmp6;\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) +   /* c2 */\n\t      MULTIPLY(tmp1, FIX(0.801745081)) +   /* c6 */\n\t      MULTIPLY(tmp2, FIX(0.379824504)) -   /* c10 */\n\t      MULTIPLY(tmp3, FIX(0.129109289)) -   /* c12 */\n\t      MULTIPLY(tmp4, FIX(0.608465700)) -   /* c8 */\n\t      MULTIPLY(tmp5, FIX(0.948429952)),    /* c4 */\n\t      CONST_BITS+1);\n    z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */\n\t MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */\n\t MULTIPLY(tmp1 - tmp5, FIX(0.239678205));  /* (c8-c12)/2 */\n    z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */\n\t MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */\n\t MULTIPLY(tmp1 + tmp5, FIX(0.368787494));  /* (c8+c12)/2 */\n\n    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908));   /* c3 */\n    tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751));   /* c5 */\n    tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) +  /* c7 */\n\t   MULTIPLY(tmp14 + tmp15, FIX(0.256335874));   /* c11 */\n    tmp0 = tmp1 + tmp2 + tmp3 -\n\t   MULTIPLY(tmp10, FIX(1.530003162)) +          /* c3+c5+c7-c1 */\n\t   MULTIPLY(tmp14, FIX(0.241438564));           /* c9-c11 */\n    tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) -  /* c7 */\n\t   MULTIPLY(tmp11 + tmp12, FIX(0.256335874));   /* c11 */\n    tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */\n    tmp1 += tmp4 + tmp5 +\n\t    MULTIPLY(tmp11, FIX(0.634110155)) -         /* c5+c9+c11-c3 */\n\t    MULTIPLY(tmp14, FIX(1.773594819));          /* c1+c7 */\n    tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */\n    tmp2 += tmp4 + tmp6 -\n\t    MULTIPLY(tmp12, FIX(1.190715098)) +         /* c1+c5-c9-c11 */\n\t    MULTIPLY(tmp15, FIX(1.711799069));          /* c3+c7 */\n    tmp3 += tmp5 + tmp6 +\n\t    MULTIPLY(tmp13, FIX(1.670519935)) -         /* c3+c5+c9-c7 */\n\t    MULTIPLY(tmp15, FIX(1.319646532));          /* c1+c11 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 14x14 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  DCTELEM workspace[8*6];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   * cK represents sqrt(2) * cos(K*pi/28).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);\n    tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);\n    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);\n\n    tmp10 = tmp0 + tmp6;\n    tmp14 = tmp0 - tmp6;\n    tmp11 = tmp1 + tmp5;\n    tmp15 = tmp1 - tmp5;\n    tmp12 = tmp2 + tmp4;\n    tmp16 = tmp2 - tmp4;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);\n    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE);\n    tmp13 += tmp13;\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */\n\t      MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */\n\t      MULTIPLY(tmp12 - tmp13, FIX(0.881747734)),  /* c8 */\n\t      CONST_BITS);\n\n    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686));    /* c6 */\n\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590))   /* c2-c6 */\n\t      + MULTIPLY(tmp16, FIX(0.613604268)),        /* c10 */\n\t      CONST_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954))   /* c6+c10 */\n\t      - MULTIPLY(tmp16, FIX(1.378756276)),        /* c2 */\n\t      CONST_BITS);\n\n    /* Odd part */\n\n    tmp10 = tmp1 + tmp2;\n    tmp11 = tmp5 - tmp4;\n    dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6);\n    tmp3 <<= CONST_BITS;\n    tmp10 = MULTIPLY(tmp10, - FIX(0.158341681));          /* -c13 */\n    tmp11 = MULTIPLY(tmp11, FIX(1.405321284));            /* c1 */\n    tmp10 += tmp11 - tmp3;\n    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) +     /* c5 */\n\t    MULTIPLY(tmp4 + tmp6, FIX(0.752406978));      /* c9 */\n    dataptr[5] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */\n\t      + MULTIPLY(tmp4, FIX(1.119999435)),         /* c1+c11-c9 */\n\t      CONST_BITS);\n    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) +     /* c3 */\n\t    MULTIPLY(tmp5 - tmp6, FIX(0.467085129));      /* c11 */\n    dataptr[3] = (DCTELEM)\n      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */\n\t      - MULTIPLY(tmp5, FIX(3.069855259)),         /* c1+c5+c11 */\n\t      CONST_BITS);\n    dataptr[1] = (DCTELEM)\n      DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -\n\t      MULTIPLY(tmp0 + tmp6, FIX(1.126980169)),    /* c3+c5-c1 */\n\t      CONST_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 14)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/14)**2 = 16/49, which we partially\n   * fold into the constant multipliers and final shifting:\n   * cK now represents sqrt(2) * cos(K*pi/28) * 32/49.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];\n    tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];\n    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];\n    tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];\n\n    tmp10 = tmp0 + tmp6;\n    tmp14 = tmp0 - tmp6;\n    tmp11 = tmp1 + tmp5;\n    tmp15 = tmp1 - tmp5;\n    tmp12 = tmp2 + tmp4;\n    tmp16 = tmp2 - tmp4;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];\n    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];\n    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];\n    tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,\n\t\t       FIX(0.653061224)),                 /* 32/49 */\n\t      CONST_BITS+1);\n    tmp13 += tmp13;\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */\n\t      MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */\n\t      MULTIPLY(tmp12 - tmp13, FIX(0.575835255)),  /* c8 */\n\t      CONST_BITS+1);\n\n    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570));    /* c6 */\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691))   /* c2-c6 */\n\t      + MULTIPLY(tmp16, FIX(0.400721155)),        /* c10 */\n\t      CONST_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725))   /* c6+c10 */\n\t      - MULTIPLY(tmp16, FIX(0.900412262)),        /* c2 */\n\t      CONST_BITS+1);\n\n    /* Odd part */\n\n    tmp10 = tmp1 + tmp2;\n    tmp11 = tmp5 - tmp4;\n    dataptr[DCTSIZE*7] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,\n\t\t       FIX(0.653061224)),                 /* 32/49 */\n\t      CONST_BITS+1);\n    tmp3  = MULTIPLY(tmp3 , FIX(0.653061224));            /* 32/49 */\n    tmp10 = MULTIPLY(tmp10, - FIX(0.103406812));          /* -c13 */\n    tmp11 = MULTIPLY(tmp11, FIX(0.917760839));            /* c1 */\n    tmp10 += tmp11 - tmp3;\n    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) +     /* c5 */\n\t    MULTIPLY(tmp4 + tmp6, FIX(0.491367823));      /* c9 */\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */\n\t      + MULTIPLY(tmp4, FIX(0.731428202)),         /* c1+c11-c9 */\n\t      CONST_BITS+1);\n    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) +     /* c3 */\n\t    MULTIPLY(tmp5 - tmp6, FIX(0.305035186));      /* c11 */\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */\n\t      - MULTIPLY(tmp5, FIX(2.004803435)),         /* c1+c5+c11 */\n\t      CONST_BITS+1);\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp11 + tmp12 + tmp3\n\t      - MULTIPLY(tmp0, FIX(0.735987049))          /* c3+c5-c1 */\n\t      - MULTIPLY(tmp6, FIX(0.082925825)),         /* c9-c11-c13 */\n\t      CONST_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 15x15 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 z1, z2, z3;\n  DCTELEM workspace[8*7];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   * cK represents sqrt(2) * cos(K*pi/30).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]);\n    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]);\n    tmp7 = GETJSAMPLE(elemptr[7]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]);\n    tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]);\n    tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]);\n    tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]);\n    tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]);\n\n    z1 = tmp0 + tmp4 + tmp5;\n    z2 = tmp1 + tmp3 + tmp6;\n    z3 = tmp2 + tmp7;\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE);\n    z3 += z3;\n    dataptr[6] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */\n\t      MULTIPLY(z2 - z3, FIX(0.437016024)),  /* c12 */\n\t      CONST_BITS);\n    tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;\n    z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) -  /* c2+c14 */\n         MULTIPLY(tmp6 - tmp2, FIX(2.238241955));   /* c4+c8 */\n    z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) -  /* c8-c14 */\n\t MULTIPLY(tmp0 - tmp2, FIX(0.091361227));   /* c2-c4 */\n    z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) +  /* c2 */\n\t MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) +  /* c8 */\n\t MULTIPLY(tmp1 - tmp4, FIX(0.790569415));   /* (c6+c12)/2 */\n\n    dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS);\n    dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS);\n\n    /* Odd part */\n\n    tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,\n\t\t    FIX(1.224744871));                         /* c5 */\n    tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */\n\t   MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876));  /* c9 */\n    tmp12 = MULTIPLY(tmp12, FIX(1.224744871));                 /* c5 */\n    tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) +         /* c1 */\n\t   MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) +         /* c3 */\n\t   MULTIPLY(tmp13 + tmp15, FIX(0.575212477));          /* c11 */\n    tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) -                 /* c7-c11 */\n\t   MULTIPLY(tmp14, FIX(0.513743148)) +                 /* c3-c9 */\n\t   MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12;   /* c1+c13 */\n    tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) -               /* -(c1-c7) */\n\t   MULTIPLY(tmp11, FIX(2.176250899)) -                 /* c3+c9 */\n\t   MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12;   /* c11+c13 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 15)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/15)**2 = 64/225, which we partially\n   * fold into the constant multipliers and final shifting:\n   * cK now represents sqrt(2) * cos(K*pi/30) * 256/225.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2];\n    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1];\n    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0];\n    tmp7 = dataptr[DCTSIZE*7];\n\n    tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6];\n    tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5];\n    tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4];\n    tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3];\n    tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2];\n    tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1];\n    tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0];\n\n    z1 = tmp0 + tmp4 + tmp5;\n    z2 = tmp1 + tmp3 + tmp6;\n    z3 = tmp2 + tmp7;\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */\n\t      CONST_BITS+2);\n    z3 += z3;\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */\n\t      MULTIPLY(z2 - z3, FIX(0.497227121)),  /* c12 */\n\t      CONST_BITS+2);\n    tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;\n    z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) -  /* c2+c14 */\n         MULTIPLY(tmp6 - tmp2, FIX(2.546621957));   /* c4+c8 */\n    z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) -  /* c8-c14 */\n\t MULTIPLY(tmp0 - tmp2, FIX(0.103948774));   /* c2-c4 */\n    z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) +  /* c2 */\n\t MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) +  /* c8 */\n\t MULTIPLY(tmp1 - tmp4, FIX(0.899492312));   /* (c6+c12)/2 */\n\n    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2);\n    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2);\n\n    /* Odd part */\n\n    tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,\n\t\t    FIX(1.393487498));                         /* c5 */\n    tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */\n\t   MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187));  /* c9 */\n    tmp12 = MULTIPLY(tmp12, FIX(1.393487498));                 /* c5 */\n    tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) +         /* c1 */\n\t   MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) +         /* c3 */\n\t   MULTIPLY(tmp13 + tmp15, FIX(0.654463974));          /* c11 */\n    tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) -                 /* c7-c11 */\n\t   MULTIPLY(tmp14, FIX(0.584525538)) +                 /* c3-c9 */\n\t   MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12;   /* c1+c13 */\n    tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) -               /* -(c1-c7) */\n\t   MULTIPLY(tmp11, FIX(2.476089912)) -                 /* c3+c9 */\n\t   MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12;   /* c11+c13 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 16x16 sample block.\n */\n\nGLOBAL(void)\njpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;\n  DCTELEM workspace[DCTSIZE2];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);\n    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);\n    tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);\n\n    tmp10 = tmp0 + tmp7;\n    tmp14 = tmp0 - tmp7;\n    tmp11 = tmp1 + tmp6;\n    tmp15 = tmp1 - tmp6;\n    tmp12 = tmp2 + tmp5;\n    tmp16 = tmp2 - tmp5;\n    tmp13 = tmp3 + tmp4;\n    tmp17 = tmp3 - tmp4;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);\n    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);\n    tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */\n\t      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */\n\t      CONST_BITS-PASS1_BITS);\n\n    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */\n\t    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */\n\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */\n\t      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */\n\t      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */\n\t    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */\n\t    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */\n\t    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */\n    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */\n\t    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */\n    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */\n\t    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */\n    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */\n\t    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */\n\t    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */\n    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */\n\t     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */\n    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */\n\t     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */\n    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */\n\t     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == DCTSIZE * 2)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/16)**2 = 1/2**2.\n   * cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];\n    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];\n    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];\n    tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];\n\n    tmp10 = tmp0 + tmp7;\n    tmp14 = tmp0 - tmp7;\n    tmp11 = tmp1 + tmp6;\n    tmp15 = tmp1 - tmp6;\n    tmp12 = tmp2 + tmp5;\n    tmp16 = tmp2 - tmp5;\n    tmp13 = tmp3 + tmp4;\n    tmp17 = tmp3 - tmp4;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];\n    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];\n    tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];\n    tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */\n\t      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */\n\t      CONST_BITS+PASS1_BITS+2);\n\n    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */\n\t    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */\n\t      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+10 */\n\t      CONST_BITS+PASS1_BITS+2);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */\n\t      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */\n\t      CONST_BITS+PASS1_BITS+2);\n\n    /* Odd part */\n\n    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */\n\t    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */\n\t    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */\n\t    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */\n    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */\n\t    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */\n    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */\n\t    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */\n    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */\n\t    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */\n\t    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */\n    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */\n\t     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */\n    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */\n\t     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */\n    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */\n\t     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 16x8 sample block.\n *\n * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;\n  INT32 z1;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);\n    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);\n    tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);\n\n    tmp10 = tmp0 + tmp7;\n    tmp14 = tmp0 - tmp7;\n    tmp11 = tmp1 + tmp6;\n    tmp15 = tmp1 - tmp6;\n    tmp12 = tmp2 + tmp5;\n    tmp16 = tmp2 - tmp5;\n    tmp13 = tmp3 + tmp4;\n    tmp17 = tmp3 - tmp4;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);\n    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);\n    tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */\n\t      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */\n\t      CONST_BITS-PASS1_BITS);\n\n    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */\n\t    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */\n\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */\n\t      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */\n\t      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */\n\t    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */\n\t    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */\n\t    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */\n    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */\n\t    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */\n    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */\n\t    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */\n    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */\n\t    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */\n\t    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */\n    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */\n\t     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */\n    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */\n\t     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */\n    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */\n\t     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by 8/16 = 1/2.\n   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];\n\n    tmp10 = tmp0 + tmp3;\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1);\n    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1);\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);   /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t      CONST_BITS+PASS1_BITS+1);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);   /*  c3 */\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);      /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);      /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);   /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);          /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);          /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);   /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);          /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);          /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+PASS1_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 14x7 sample block.\n *\n * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 z1, z2, z3;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Zero bottom row of output coefficient block. */\n  MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 7; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);\n    tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);\n    tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);\n\n    tmp10 = tmp0 + tmp6;\n    tmp14 = tmp0 - tmp6;\n    tmp11 = tmp1 + tmp5;\n    tmp15 = tmp1 - tmp5;\n    tmp12 = tmp2 + tmp4;\n    tmp16 = tmp2 - tmp4;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);\n    tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS);\n    tmp13 += tmp13;\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */\n\t      MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */\n\t      MULTIPLY(tmp12 - tmp13, FIX(0.881747734)),  /* c8 */\n\t      CONST_BITS-PASS1_BITS);\n\n    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686));    /* c6 */\n\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590))   /* c2-c6 */\n\t      + MULTIPLY(tmp16, FIX(0.613604268)),        /* c10 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954))   /* c6+c10 */\n\t      - MULTIPLY(tmp16, FIX(1.378756276)),        /* c2 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = tmp1 + tmp2;\n    tmp11 = tmp5 - tmp4;\n    dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS);\n    tmp3 <<= CONST_BITS;\n    tmp10 = MULTIPLY(tmp10, - FIX(0.158341681));          /* -c13 */\n    tmp11 = MULTIPLY(tmp11, FIX(1.405321284));            /* c1 */\n    tmp10 += tmp11 - tmp3;\n    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) +     /* c5 */\n\t    MULTIPLY(tmp4 + tmp6, FIX(0.752406978));      /* c9 */\n    dataptr[5] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */\n\t      + MULTIPLY(tmp4, FIX(1.119999435)),         /* c1+c11-c9 */\n\t      CONST_BITS-PASS1_BITS);\n    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) +     /* c3 */\n\t    MULTIPLY(tmp5 - tmp6, FIX(0.467085129));      /* c11 */\n    dataptr[3] = (DCTELEM)\n      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */\n\t      - MULTIPLY(tmp5, FIX(3.069855259)),         /* c1+c5+c11 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[1] = (DCTELEM)\n      DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -\n\t      MULTIPLY(tmp0 + tmp6, FIX(1.126980169)),    /* c3+c5-c1 */\n\t      CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/14)*(8/7) = 32/49, which we\n   * partially fold into the constant multipliers and final shifting:\n   * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49.\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];\n    tmp3 = dataptr[DCTSIZE*3];\n\n    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];\n    tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];\n\n    z1 = tmp0 + tmp2;\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */\n\t      CONST_BITS+PASS1_BITS+1);\n    tmp3 += tmp3;\n    z1 -= tmp3;\n    z1 -= tmp3;\n    z1 = MULTIPLY(z1, FIX(0.461784020));                /* (c2+c6-c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084));       /* (c2+c4-c6)/2 */\n    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446));       /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1);\n    z1 -= z2;\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509));       /* c4 */\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677));   /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464));   /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */\n    tmp1 += tmp2;\n    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310));   /* c5 */\n    tmp0 += tmp3;\n    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355));   /* c3+c1-c5 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 12x6 sample block.\n *\n * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Zero 2 bottom rows of output coefficient block. */\n  MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 6; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);\n    tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);\n\n    tmp10 = tmp0 + tmp5;\n    tmp13 = tmp0 - tmp5;\n    tmp11 = tmp1 + tmp4;\n    tmp14 = tmp1 - tmp4;\n    tmp12 = tmp2 + tmp3;\n    tmp15 = tmp2 - tmp3;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);\n    tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100);    /* c9 */\n    tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865);   /* c3-c9 */\n    tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065);   /* c3+c9 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054));   /* c5 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669));   /* c7 */\n    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */\n\t    + MULTIPLY(tmp5, FIX(0.184591911));        /* c11 */\n    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */\n    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */\n\t    + MULTIPLY(tmp5, FIX(0.860918669));        /* c7 */\n    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */\n\t    - MULTIPLY(tmp5, FIX(1.121971054));        /* c5 */\n    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */\n\t    - MULTIPLY(tmp2 + tmp5, FIX_0_541196100);  /* c9 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/12)*(8/6) = 8/9, which we\n   * partially fold into the constant multipliers and final shifting:\n   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];\n    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */\n\t      CONST_BITS+PASS1_BITS+1);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 10x5 sample block.\n *\n * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Zero 3 bottom rows of output coefficient block. */\n  MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 5; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);\n    tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);\n    tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);\n\n    tmp10 = tmp0 + tmp4;\n    tmp13 = tmp0 - tmp4;\n    tmp11 = tmp1 + tmp3;\n    tmp14 = tmp1 - tmp3;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);\n    tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS);\n    tmp12 += tmp12;\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */\n\t      MULTIPLY(tmp11 - tmp12, FIX(0.437016024)),  /* c8 */\n\t      CONST_BITS-PASS1_BITS);\n    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876));    /* c6 */\n    dataptr[2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)),  /* c2-c6 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)),  /* c2+c6 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = tmp0 + tmp4;\n    tmp11 = tmp1 - tmp3;\n    dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS);\n    tmp2 <<= CONST_BITS;\n    dataptr[1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) +          /* c1 */\n\t      MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 +   /* c3 */\n\t      MULTIPLY(tmp3, FIX(0.642039522)) +          /* c7 */\n\t      MULTIPLY(tmp4, FIX(0.221231742)),           /* c9 */\n\t      CONST_BITS-PASS1_BITS);\n    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) -     /* (c3+c7)/2 */\n\t    MULTIPLY(tmp1 + tmp3, FIX(0.587785252));      /* (c1-c9)/2 */\n    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) +   /* (c3-c7)/2 */\n\t    (tmp11 << (CONST_BITS - 1)) - tmp2;\n    dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/10)*(8/5) = 32/25, which we\n   * fold into the constant multipliers:\n   * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25.\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];\n    tmp2 = dataptr[DCTSIZE*2];\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)),        /* 32/25 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp11 = MULTIPLY(tmp11, FIX(1.011928851));          /* (c2+c4)/2 */\n    tmp10 -= tmp2 << 2;\n    tmp10 = MULTIPLY(tmp10, FIX(0.452548340));          /* (c2-c4)/2 */\n    dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961));    /* c3 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on an 8x4 sample block.\n *\n * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Zero 4 bottom rows of output coefficient block. */\n  MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We must also scale the output by 8/4 = 2, which we add here.\n   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 4; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);\n\n    tmp10 = tmp0 + tmp3;\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1));\n    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1));\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-2);\n\n    dataptr[2] = (DCTELEM)\n      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS-PASS1_BITS-1);\n    dataptr[6] = (DCTELEM)\n      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS-PASS1_BITS-1);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-2);\n\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS-PASS1_BITS-1);\n    dataptr[3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS-PASS1_BITS-1);\n    dataptr[5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS-1);\n    dataptr[7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS-PASS1_BITS-1);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * 4-point FDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  dataptr = data;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    /* Add fudge factor here for final descale. */\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];\n\n    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);\n\n    /* Odd part */\n\n    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 6x3 sample block.\n *\n * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2;\n  INT32 tmp10, tmp11, tmp12;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 3; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);\n    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1));\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */\n\t      CONST_BITS-PASS1_BITS-1);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */\n\t      CONST_BITS-PASS1_BITS-1);\n\n    /* Odd part */\n\n    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */\n\t\t    CONST_BITS-PASS1_BITS-1);\n\n    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1)));\n    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1));\n    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1)));\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially\n   * fold into the constant multipliers (other part was done in pass 1):\n   * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 6; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];\n    tmp1 = dataptr[DCTSIZE*1];\n\n    tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),        /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2, FIX(2.177324216)),               /* c1 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 4x2 sample block.\n *\n * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM tmp0, tmp2, tmp10, tmp12, tmp4, tmp5;\n  INT32 tmp1, tmp3, tmp11, tmp13;\n  INT32 z1, z2, z3;\n  JSAMPROW elemptr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   * 4-point FDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  /* Row 0 */\n  elemptr = sample_data[0] + start_col;\n\n  /* Even part */\n\n  tmp4 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);\n  tmp5 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);\n\n  tmp0 = tmp4 + tmp5;\n  tmp2 = tmp4 - tmp5;\n\n  /* Odd part */\n\n  z2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);\n  z3 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);\n\n  z1 = MULTIPLY(z2 + z3, FIX_0_541196100);    /* c6 */\n  /* Add fudge factor here for final descale. */\n  z1 += ONE << (CONST_BITS-3-1);\n  tmp1 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n  tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n  /* Row 1 */\n  elemptr = sample_data[1] + start_col;\n\n  /* Even part */\n\n  tmp4 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);\n  tmp5 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);\n\n  tmp10 = tmp4 + tmp5;\n  tmp12 = tmp4 - tmp5;\n\n  /* Odd part */\n\n  z2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);\n  z3 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);\n\n  z1 = MULTIPLY(z2 + z3, FIX_0_541196100);    /* c6 */\n  tmp11 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n  tmp13 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/4)*(8/2) = 2**3.\n   */\n\n  /* Column 0 */\n  /* Apply unsigned->signed conversion. */\n  data[DCTSIZE*0] = (tmp0 + tmp10 - 8 * CENTERJSAMPLE) << 3;\n  data[DCTSIZE*1] = (tmp0 - tmp10) << 3;\n\n  /* Column 1 */\n  data[DCTSIZE*0+1] = (DCTELEM) RIGHT_SHIFT(tmp1 + tmp11, CONST_BITS-3);\n  data[DCTSIZE*1+1] = (DCTELEM) RIGHT_SHIFT(tmp1 - tmp11, CONST_BITS-3);\n\n  /* Column 2 */\n  data[DCTSIZE*0+2] = (tmp2 + tmp12) << 3;\n  data[DCTSIZE*1+2] = (tmp2 - tmp12) << 3;\n\n  /* Column 3 */\n  data[DCTSIZE*0+3] = (DCTELEM) RIGHT_SHIFT(tmp3 + tmp13, CONST_BITS-3);\n  data[DCTSIZE*1+3] = (DCTELEM) RIGHT_SHIFT(tmp3 - tmp13, CONST_BITS-3);\n}\n\n\n/*\n * Perform the forward DCT on a 2x1 sample block.\n *\n * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM tmp0, tmp1;\n  JSAMPROW elemptr;\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  elemptr = sample_data[0] + start_col;\n\n  tmp0 = GETJSAMPLE(elemptr[0]);\n  tmp1 = GETJSAMPLE(elemptr[1]);\n\n  /* We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/2)*(8/1) = 2**5.\n   */\n\n  /* Even part */\n\n  /* Apply unsigned->signed conversion. */\n  data[0] = (tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5;\n\n  /* Odd part */\n\n  data[1] = (tmp0 - tmp1) << 5;\n}\n\n\n/*\n * Perform the forward DCT on an 8x16 sample block.\n *\n * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;\n  INT32 z1;\n  DCTELEM workspace[DCTSIZE2];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);\n\n    tmp10 = tmp0 + tmp3;\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);\n    tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);   /* c6 */\n    dataptr[2] = (DCTELEM)\n      DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM)\n      DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);   /*  c3 */\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);      /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);      /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);   /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);          /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);          /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);   /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);          /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);          /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);\n    dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-PASS1_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == DCTSIZE * 2)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by 8/16 = 1/2.\n   * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];\n    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];\n    tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];\n    tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];\n\n    tmp10 = tmp0 + tmp7;\n    tmp14 = tmp0 - tmp7;\n    tmp11 = tmp1 + tmp6;\n    tmp15 = tmp1 - tmp6;\n    tmp12 = tmp2 + tmp5;\n    tmp16 = tmp2 - tmp5;\n    tmp13 = tmp3 + tmp4;\n    tmp17 = tmp3 - tmp4;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];\n    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];\n    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];\n    tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];\n    tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */\n\t      MULTIPLY(tmp11 - tmp12, FIX_0_541196100),   /* c12[16] = c6[8] */\n\t      CONST_BITS+PASS1_BITS+1);\n\n    tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) +   /* c14[16] = c7[8] */\n\t    MULTIPLY(tmp14 - tmp16, FIX(1.387039845));    /* c2[16] = c1[8] */\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982))   /* c6+c14 */\n\t      + MULTIPLY(tmp16, FIX(2.172734804)),        /* c2+c10 */\n\t      CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243))   /* c2-c6 */\n\t      - MULTIPLY(tmp17, FIX(1.061594338)),        /* c10+c14 */\n\t      CONST_BITS+PASS1_BITS+1);\n\n    /* Odd part */\n\n    tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) +         /* c3 */\n\t    MULTIPLY(tmp6 - tmp7, FIX(0.410524528));          /* c13 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) +         /* c5 */\n\t    MULTIPLY(tmp5 + tmp7, FIX(0.666655658));          /* c11 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) +         /* c7 */\n\t    MULTIPLY(tmp4 - tmp7, FIX(0.897167586));          /* c9 */\n    tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) +         /* c15 */\n\t    MULTIPLY(tmp6 - tmp5, FIX(1.407403738));          /* c1 */\n    tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) +       /* -c11 */\n\t    MULTIPLY(tmp4 + tmp6, - FIX(1.247225013));        /* -c5 */\n    tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) +       /* -c3 */\n\t    MULTIPLY(tmp5 - tmp4, FIX(0.410524528));          /* c13 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(tmp0, FIX(2.286341144)) +                /* c7+c5+c3-c1 */\n\t    MULTIPLY(tmp7, FIX(0.779653625));                 /* c15+c13-c11+c9 */\n    tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */\n\t     - MULTIPLY(tmp6, FIX(1.663905119));              /* c7+c13+c1-c5 */\n    tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */\n\t     + MULTIPLY(tmp5, FIX(1.227391138));              /* c9-c11+c1-c13 */\n    tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */\n\t     + MULTIPLY(tmp4, FIX(2.167985692));              /* c1+c13+c5-c9 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 7x14 sample block.\n *\n * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 z1, z2, z3;\n  DCTELEM workspace[8*6];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);\n    tmp3 = GETJSAMPLE(elemptr[3]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);\n    tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);\n\n    z1 = tmp0 + tmp2;\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);\n    tmp3 += tmp3;\n    z1 -= tmp3;\n    z1 -= tmp3;\n    z1 = MULTIPLY(z1, FIX(0.353553391));                /* (c2+c6-c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002));       /* (c2+c4-c6)/2 */\n    z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123));       /* c6 */\n    dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);\n    z1 -= z2;\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734));       /* c4 */\n    dataptr[4] = (DCTELEM)\n      DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347));   /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339));   /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */\n    tmp1 += tmp2;\n    tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268));   /* c5 */\n    tmp0 += tmp3;\n    tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693));   /* c3+c1-c5 */\n\n    dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);\n    dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 14)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/7)*(8/14) = 32/49, which we\n   * fold into the constant multipliers:\n   * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 7; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];\n    tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];\n    tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];\n    tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];\n    tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];\n\n    tmp10 = tmp0 + tmp6;\n    tmp14 = tmp0 - tmp6;\n    tmp11 = tmp1 + tmp5;\n    tmp15 = tmp1 - tmp5;\n    tmp12 = tmp2 + tmp4;\n    tmp16 = tmp2 - tmp4;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];\n    tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];\n    tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];\n    tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,\n\t\t       FIX(0.653061224)),                 /* 32/49 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp13 += tmp13;\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */\n\t      MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */\n\t      MULTIPLY(tmp12 - tmp13, FIX(0.575835255)),  /* c8 */\n\t      CONST_BITS+PASS1_BITS);\n\n    tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570));    /* c6 */\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691))   /* c2-c6 */\n\t      + MULTIPLY(tmp16, FIX(0.400721155)),        /* c10 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725))   /* c6+c10 */\n\t      - MULTIPLY(tmp16, FIX(0.900412262)),        /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = tmp1 + tmp2;\n    tmp11 = tmp5 - tmp4;\n    dataptr[DCTSIZE*7] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,\n\t\t       FIX(0.653061224)),                 /* 32/49 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp3  = MULTIPLY(tmp3 , FIX(0.653061224));            /* 32/49 */\n    tmp10 = MULTIPLY(tmp10, - FIX(0.103406812));          /* -c13 */\n    tmp11 = MULTIPLY(tmp11, FIX(0.917760839));            /* c1 */\n    tmp10 += tmp11 - tmp3;\n    tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) +     /* c5 */\n\t    MULTIPLY(tmp4 + tmp6, FIX(0.491367823));      /* c9 */\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */\n\t      + MULTIPLY(tmp4, FIX(0.731428202)),         /* c1+c11-c9 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) +     /* c3 */\n\t    MULTIPLY(tmp5 - tmp6, FIX(0.305035186));      /* c11 */\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */\n\t      - MULTIPLY(tmp5, FIX(2.004803435)),         /* c1+c5+c11 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp11 + tmp12 + tmp3\n\t      - MULTIPLY(tmp0, FIX(0.735987049))          /* c3+c5-c1 */\n\t      - MULTIPLY(tmp6, FIX(0.082925825)),         /* c9-c11-c13 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 6x12 sample block.\n *\n * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  DCTELEM workspace[8*4];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);\n    tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);\n    tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(1.224744871)),                 /* c2 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */\n\t      CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)),     /* c5 */\n\t\t    CONST_BITS-PASS1_BITS);\n\n    dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));\n    dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);\n    dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 12)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/6)*(8/12) = 8/9, which we\n   * fold into the constant multipliers:\n   * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];\n    tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];\n    tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];\n    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];\n    tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];\n\n    tmp10 = tmp0 + tmp5;\n    tmp13 = tmp0 - tmp5;\n    tmp11 = tmp1 + tmp4;\n    tmp14 = tmp1 - tmp4;\n    tmp12 = tmp2 + tmp3;\n    tmp15 = tmp2 - tmp3;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];\n    tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];\n    tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];\n    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];\n    tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)),         /* c4 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) +        /* 8/9 */\n\t      MULTIPLY(tmp13 + tmp15, FIX(1.214244803)),         /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200));   /* c9 */\n    tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102));  /* c3-c9 */\n    tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502));  /* c3+c9 */\n    tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603));   /* c5 */\n    tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039));   /* c7 */\n    tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */\n\t    + MULTIPLY(tmp5, FIX(0.164081699));        /* c11 */\n    tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */\n    tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */\n\t    + MULTIPLY(tmp5, FIX(0.765261039));        /* c7 */\n    tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */\n\t    - MULTIPLY(tmp5, FIX(0.997307603));        /* c5 */\n    tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */\n\t    - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 5x10 sample block.\n *\n * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp4;\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  DCTELEM workspace[8*2];\n  DCTELEM *dataptr;\n  DCTELEM *wsptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10).\n   */\n\n  dataptr = data;\n  ctr = 0;\n  for (;;) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);\n    tmp2 = GETJSAMPLE(elemptr[2]);\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n\n    tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);\n    tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS);\n    tmp11 = MULTIPLY(tmp11, FIX(0.790569415));          /* (c2+c4)/2 */\n    tmp10 -= tmp2 << 2;\n    tmp10 = MULTIPLY(tmp10, FIX(0.353553391));          /* (c2-c4)/2 */\n    dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS);\n    dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876));    /* c3 */\n\n    dataptr[1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */\n\t      CONST_BITS-PASS1_BITS);\n    dataptr[3] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */\n\t      CONST_BITS-PASS1_BITS);\n\n    ctr++;\n\n    if (ctr != DCTSIZE) {\n      if (ctr == 10)\n\tbreak;\t\t\t/* Done. */\n      dataptr += DCTSIZE;\t/* advance pointer to next row */\n    } else\n      dataptr = workspace;\t/* switch pointer to extended workspace */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/5)*(8/10) = 32/25, which we\n   * fold into the constant multipliers:\n   * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25.\n   */\n\n  dataptr = data;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 5; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];\n    tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];\n    tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];\n    tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];\n\n    tmp10 = tmp0 + tmp4;\n    tmp13 = tmp0 - tmp4;\n    tmp11 = tmp1 + tmp3;\n    tmp14 = tmp1 - tmp3;\n\n    tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];\n    tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];\n    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];\n    tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp12 += tmp12;\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */\n\t      MULTIPLY(tmp11 - tmp12, FIX(0.559380511)),  /* c8 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961));    /* c6 */\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)),  /* c2-c6 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)),  /* c2+c6 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = tmp0 + tmp4;\n    tmp11 = tmp1 - tmp3;\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)),  /* 32/25 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp2 = MULTIPLY(tmp2, FIX(1.28));                     /* 32/25 */\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) +          /* c1 */\n\t      MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 +   /* c3 */\n\t      MULTIPLY(tmp3, FIX(0.821810588)) +          /* c7 */\n\t      MULTIPLY(tmp4, FIX(0.283176630)),           /* c9 */\n\t      CONST_BITS+PASS1_BITS);\n    tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) -     /* (c3+c7)/2 */\n\t    MULTIPLY(tmp1 + tmp3, FIX(0.752365123));      /* (c1-c9)/2 */\n    tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) +   /* (c3-c7)/2 */\n\t    MULTIPLY(tmp11, FIX(0.64)) - tmp2;            /* 16/25 */\n    dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n    wsptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 4x8 sample block.\n *\n * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We must also scale the output by 8/4 = 2, which we add here.\n   * 4-point FDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);\n    tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);\n\n    tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);\n    tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1));\n    dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1));\n\n    /* Odd part */\n\n    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-2);\n\n    dataptr[1] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS-PASS1_BITS-1);\n    dataptr[3] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS-PASS1_BITS-1);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 4; ctr++) {\n    /* Even part per LL&M figure 1 --- note that published figure is faulty;\n     * rotator \"c1\" should be \"c6\".\n     */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];\n\n    /* Add fudge factor here for final descale. */\n    tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));\n    tmp12 = tmp0 - tmp3;\n    tmp11 = tmp1 + tmp2;\n    tmp13 = tmp1 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];\n    tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*6] = (DCTELEM)\n      RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS+PASS1_BITS);\n\n    /* Odd part per figure 8 --- note paper omits factor of sqrt(2).\n     * i0..i3 in the paper are tmp0..tmp3 here.\n     */\n\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602);       /*  c3 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS+PASS1_BITS-1);\n\n    tmp12 = MULTIPLY(tmp12, - FIX_0_390180644);          /* -c3+c5 */\n    tmp13 = MULTIPLY(tmp13, - FIX_1_961570560);          /* -c3-c5 */\n    tmp12 += z1;\n    tmp13 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223);       /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_1_501321110);              /*  c1+c3-c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_0_298631336);              /* -c1+c3+c5-c7 */\n    tmp0 += z1 + tmp12;\n    tmp3 += z1 + tmp13;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447);       /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_3_072711026);              /*  c1+c3+c5-c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_2_053119869);              /*  c1+c3-c5+c7 */\n    tmp1 += z1 + tmp13;\n    tmp2 += z1 + tmp12;\n\n    dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM) RIGHT_SHIFT(tmp1, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM) RIGHT_SHIFT(tmp2, CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*7] = (DCTELEM) RIGHT_SHIFT(tmp3, CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 3x6 sample block.\n *\n * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1, tmp2;\n  INT32 tmp10, tmp11, tmp12;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * We scale the results further by 2 as part of output adaption\n   * scaling for different DCT size.\n   * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6).\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 6; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);\n    tmp1 = GETJSAMPLE(elemptr[1]);\n\n    tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM)\n      ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1));\n    dataptr[2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */\n\t      CONST_BITS-PASS1_BITS-1);\n\n    /* Odd part */\n\n    dataptr[1] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp2, FIX(1.224744871)),               /* c1 */\n\t      CONST_BITS-PASS1_BITS-1);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We remove the PASS1_BITS scaling, but leave the results scaled up\n   * by an overall factor of 8.\n   * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially\n   * fold into the constant multipliers (other part was done in pass 1):\n   * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 3; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];\n    tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];\n\n    tmp10 = tmp0 + tmp2;\n    tmp12 = tmp0 - tmp2;\n\n    tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];\n    tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];\n    tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];\n\n    dataptr[DCTSIZE*0] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)),         /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*2] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp12, FIX(2.177324216)),                 /* c2 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*4] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */\n\t      CONST_BITS+PASS1_BITS);\n\n    /* Odd part */\n\n    tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829));             /* c5 */\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)),    /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n    dataptr[DCTSIZE*5] = (DCTELEM)\n      DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)),   /* 16/9 */\n\t      CONST_BITS+PASS1_BITS);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 2x4 sample block.\n *\n * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  INT32 tmp0, tmp1;\n  INT32 tmp10, tmp11;\n  DCTELEM *dataptr;\n  JSAMPROW elemptr;\n  int ctr;\n  SHIFT_TEMPS\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: process rows.\n   * Note results are scaled up by sqrt(8) compared to a true DCT.\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 4; ctr++) {\n    elemptr = sample_data[ctr] + start_col;\n\n    /* Even part */\n\n    tmp0 = GETJSAMPLE(elemptr[0]);\n    tmp1 = GETJSAMPLE(elemptr[1]);\n\n    /* Apply unsigned->signed conversion. */\n    dataptr[0] = (DCTELEM) (tmp0 + tmp1 - 2 * CENTERJSAMPLE);\n\n    /* Odd part */\n\n    dataptr[1] = (DCTELEM) (tmp0 - tmp1);\n\n    dataptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/2)*(8/4) = 2**3.\n   * 4-point FDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].\n   */\n\n  dataptr = data;\n  for (ctr = 0; ctr < 2; ctr++) {\n    /* Even part */\n\n    tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3];\n    tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];\n\n    tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];\n    tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];\n\n    dataptr[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1) << 3);\n    dataptr[DCTSIZE*2] = (DCTELEM) ((tmp0 - tmp1) << 3);\n\n    /* Odd part */\n\n    tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100);       /* c6 */\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-3-1);\n\n    dataptr[DCTSIZE*1] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */\n\t\t  CONST_BITS-3);\n    dataptr[DCTSIZE*3] = (DCTELEM)\n      RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */\n\t\t  CONST_BITS-3);\n\n    dataptr++;\t\t\t/* advance pointer to next column */\n  }\n}\n\n\n/*\n * Perform the forward DCT on a 1x2 sample block.\n *\n * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).\n */\n\nGLOBAL(void)\njpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)\n{\n  DCTELEM tmp0, tmp1;\n\n  /* Pre-zero output coefficient block. */\n  MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);\n\n  /* Pass 1: empty. */\n\n  /* Pass 2: process columns.\n   * We leave the results scaled up by an overall factor of 8.\n   * We must also scale the output by (8/1)*(8/2) = 2**5.\n   */\n\n  /* Even part */\n\n  tmp0 = GETJSAMPLE(sample_data[0][start_col]);\n  tmp1 = GETJSAMPLE(sample_data[1][start_col]);\n\n  /* Apply unsigned->signed conversion. */\n  data[DCTSIZE*0] = (tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5;\n\n  /* Odd part */\n\n  data[DCTSIZE*1] = (tmp0 - tmp1) << 5;\n}\n\n#endif /* DCT_SCALING_SUPPORTED */\n#endif /* DCT_ISLOW_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jidctflt.c",
    "content": "/*\n * jidctflt.c\n *\n * Copyright (C) 1994-1998, Thomas G. Lane.\n * Modified 2010-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a floating-point implementation of the\n * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine\n * must also perform dequantization of the input coefficients.\n *\n * This implementation should be more accurate than either of the integer\n * IDCT implementations.  However, it may not give the same results on all\n * machines because of differences in roundoff behavior.  Speed will depend\n * on the hardware's floating point capacity.\n *\n * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT\n * on each row (or vice versa, but it's more convenient to emit a row at\n * a time).  Direct algorithms are also available, but they are much more\n * complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on Arai, Agui, and Nakajima's algorithm for\n * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in\n * Japanese, but the algorithm is described in the Pennebaker & Mitchell\n * JPEG textbook (see REFERENCES section in file README).  The following code\n * is based directly on figure 4-8 in P&M.\n * While an 8-point DCT cannot be done in less than 11 multiplies, it is\n * possible to arrange the computation so that many of the multiplies are\n * simple scalings of the final outputs.  These multiplies can then be\n * folded into the multiplications or divisions by the JPEG quantization\n * table entries.  The AA&N method leaves only 5 multiplies and 29 adds\n * to be done in the DCT itself.\n * The primary disadvantage of this method is that with a fixed-point\n * implementation, accuracy is lost due to imprecise representation of the\n * scaled quantization values.  However, that problem does not arise if\n * we use floating point arithmetic.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_FLOAT_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/* Dequantize a coefficient by multiplying it by the multiplier-table\n * entry; produce a float result.\n */\n\n#define DEQUANTIZE(coef,quantval)  (((FAST_FLOAT) (coef)) * (quantval))\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients.\n *\n * cK represents cos(K*pi/16).\n */\n\nGLOBAL(void)\njpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  FAST_FLOAT tmp10, tmp11, tmp12, tmp13;\n  FAST_FLOAT z5, z10, z11, z12, z13;\n  JCOEFPTR inptr;\n  FLOAT_MULT_TYPE * quantptr;\n  FAST_FLOAT * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = DCTSIZE; ctr > 0; ctr--) {\n    /* Due to quantization, we will usually find that many of the input\n     * coefficients are zero, especially the AC terms.  We can exploit this\n     * by short-circuiting the IDCT calculation for any column in which all\n     * the AC terms are zero.  In that case each output is equal to the\n     * DC coefficient (with scale factor as needed).\n     * With typical images and quantization tables, half or more of the\n     * column DCT calculations can be simplified this way.\n     */\n\n    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&\n\tinptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&\n\tinptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&\n\tinptr[DCTSIZE*7] == 0) {\n      /* AC terms all zero */\n      FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n\n      wsptr[DCTSIZE*0] = dcval;\n      wsptr[DCTSIZE*1] = dcval;\n      wsptr[DCTSIZE*2] = dcval;\n      wsptr[DCTSIZE*3] = dcval;\n      wsptr[DCTSIZE*4] = dcval;\n      wsptr[DCTSIZE*5] = dcval;\n      wsptr[DCTSIZE*6] = dcval;\n      wsptr[DCTSIZE*7] = dcval;\n\n      inptr++;\t\t\t/* advance pointers to next column */\n      quantptr++;\n      wsptr++;\n      continue;\n    }\n\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp10 = tmp0 + tmp2;\t/* phase 3 */\n    tmp11 = tmp0 - tmp2;\n\n    tmp13 = tmp1 + tmp3;\t/* phases 5-3 */\n    tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */\n\n    tmp0 = tmp10 + tmp13;\t/* phase 2 */\n    tmp3 = tmp10 - tmp13;\n    tmp1 = tmp11 + tmp12;\n    tmp2 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    z13 = tmp6 + tmp5;\t\t/* phase 6 */\n    z10 = tmp6 - tmp5;\n    z11 = tmp4 + tmp7;\n    z12 = tmp4 - tmp7;\n\n    tmp7 = z11 + z13;\t\t/* phase 5 */\n    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */\n\n    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */\n    tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */\n    tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */\n\n    tmp6 = tmp12 - tmp7;\t/* phase 2 */\n    tmp5 = tmp11 - tmp6;\n    tmp4 = tmp10 - tmp5;\n\n    wsptr[DCTSIZE*0] = tmp0 + tmp7;\n    wsptr[DCTSIZE*7] = tmp0 - tmp7;\n    wsptr[DCTSIZE*1] = tmp1 + tmp6;\n    wsptr[DCTSIZE*6] = tmp1 - tmp6;\n    wsptr[DCTSIZE*2] = tmp2 + tmp5;\n    wsptr[DCTSIZE*5] = tmp2 - tmp5;\n    wsptr[DCTSIZE*3] = tmp3 + tmp4;\n    wsptr[DCTSIZE*4] = tmp3 - tmp4;\n\n    inptr++;\t\t\t/* advance pointers to next column */\n    quantptr++;\n    wsptr++;\n  }\n\n  /* Pass 2: process rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n    /* Rows of zeroes can be exploited in the same way as we did with columns.\n     * However, the column calculation has created many nonzero AC terms, so\n     * the simplification applies less often (typically 5% to 10% of the time).\n     * And testing floats for zero is relatively expensive, so we don't bother.\n     */\n\n    /* Even part */\n\n    /* Prepare range-limit and float->int conversion */\n    z5 = wsptr[0] + (((FAST_FLOAT) RANGE_CENTER) + ((FAST_FLOAT) 0.5));\n    tmp10 = z5 + wsptr[4];\n    tmp11 = z5 - wsptr[4];\n\n    tmp13 = wsptr[2] + wsptr[6];\n    tmp12 = (wsptr[2] - wsptr[6]) *\n\t      ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */\n\n    tmp0 = tmp10 + tmp13;\n    tmp3 = tmp10 - tmp13;\n    tmp1 = tmp11 + tmp12;\n    tmp2 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z13 = wsptr[5] + wsptr[3];\n    z10 = wsptr[5] - wsptr[3];\n    z11 = wsptr[1] + wsptr[7];\n    z12 = wsptr[1] - wsptr[7];\n\n    tmp7 = z11 + z13;\t\t/* phase 5 */\n    tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */\n\n    z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */\n    tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */\n    tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */\n\n    tmp6 = tmp12 - tmp7;\t/* phase 2 */\n    tmp5 = tmp11 - tmp6;\n    tmp4 = tmp10 - tmp5;\n\n    /* Final output stage: float->int conversion and range-limit */\n\n    outptr[0] = range_limit[(int) (tmp0 + tmp7) & RANGE_MASK];\n    outptr[7] = range_limit[(int) (tmp0 - tmp7) & RANGE_MASK];\n    outptr[1] = range_limit[(int) (tmp1 + tmp6) & RANGE_MASK];\n    outptr[6] = range_limit[(int) (tmp1 - tmp6) & RANGE_MASK];\n    outptr[2] = range_limit[(int) (tmp2 + tmp5) & RANGE_MASK];\n    outptr[5] = range_limit[(int) (tmp2 - tmp5) & RANGE_MASK];\n    outptr[3] = range_limit[(int) (tmp3 + tmp4) & RANGE_MASK];\n    outptr[4] = range_limit[(int) (tmp3 - tmp4) & RANGE_MASK];\n\n    wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n}\n\n#endif /* DCT_FLOAT_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jidctfst.c",
    "content": "/*\n * jidctfst.c\n *\n * Copyright (C) 1994-1998, Thomas G. Lane.\n * Modified 2015-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a fast, not so accurate integer implementation of the\n * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine\n * must also perform dequantization of the input coefficients.\n *\n * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT\n * on each row (or vice versa, but it's more convenient to emit a row at\n * a time).  Direct algorithms are also available, but they are much more\n * complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on Arai, Agui, and Nakajima's algorithm for\n * scaled DCT.  Their original paper (Trans. IEICE E-71(11):1095) is in\n * Japanese, but the algorithm is described in the Pennebaker & Mitchell\n * JPEG textbook (see REFERENCES section in file README).  The following code\n * is based directly on figure 4-8 in P&M.\n * While an 8-point DCT cannot be done in less than 11 multiplies, it is\n * possible to arrange the computation so that many of the multiplies are\n * simple scalings of the final outputs.  These multiplies can then be\n * folded into the multiplications or divisions by the JPEG quantization\n * table entries.  The AA&N method leaves only 5 multiplies and 29 adds\n * to be done in the DCT itself.\n * The primary disadvantage of this method is that with fixed-point math,\n * accuracy is lost due to imprecise representation of the scaled\n * quantization values.  The smaller the quantization table entry, the less\n * precise the scaled value, so this implementation does worse with high-\n * quality-setting files than with low-quality ones.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_IFAST_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/* Scaling decisions are generally the same as in the LL&M algorithm;\n * see jidctint.c for more details.  However, we choose to descale\n * (right shift) multiplication products as soon as they are formed,\n * rather than carrying additional fractional bits into subsequent additions.\n * This compromises accuracy slightly, but it lets us save a few shifts.\n * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)\n * everywhere except in the multiplications proper; this saves a good deal\n * of work on 16-bit-int machines.\n *\n * The dequantized coefficients are not integers because the AA&N scaling\n * factors have been incorporated.  We represent them scaled up by PASS1_BITS,\n * so that the first and second IDCT rounds have the same input scaling.\n * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to\n * avoid a descaling shift; this compromises accuracy rather drastically\n * for small quantization table entries, but it saves a lot of shifts.\n * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,\n * so we use a much larger scaling factor to preserve accuracy.\n *\n * A final compromise is to represent the multiplicative constants to only\n * 8 fractional bits, rather than 13.  This saves some shifting work on some\n * machines, and may also reduce the cost of multiplication (since there\n * are fewer one-bits in the constants).\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define CONST_BITS  8\n#define PASS1_BITS  2\n#else\n#define CONST_BITS  8\n#define PASS1_BITS  1\t\t/* lose a little precision to avoid overflow */\n#endif\n\n/* Some C compilers fail to reduce \"FIX(constant)\" at compile time, thus\n * causing a lot of useless floating-point operations at run time.\n * To get around this we use the following pre-calculated constants.\n * If you change CONST_BITS you may want to add appropriate values.\n * (With a reasonable C compiler, you can just rely on the FIX() macro...)\n */\n\n#if CONST_BITS == 8\n#define FIX_1_082392200  ((INT32)  277)\t\t/* FIX(1.082392200) */\n#define FIX_1_414213562  ((INT32)  362)\t\t/* FIX(1.414213562) */\n#define FIX_1_847759065  ((INT32)  473)\t\t/* FIX(1.847759065) */\n#define FIX_2_613125930  ((INT32)  669)\t\t/* FIX(2.613125930) */\n#else\n#define FIX_1_082392200  FIX(1.082392200)\n#define FIX_1_414213562  FIX(1.414213562)\n#define FIX_1_847759065  FIX(1.847759065)\n#define FIX_2_613125930  FIX(2.613125930)\n#endif\n\n\n/* We can gain a little more speed, with a further compromise in accuracy,\n * by omitting the addition in a descaling shift.  This yields an incorrectly\n * rounded result half the time...\n */\n\n#ifndef USE_ACCURATE_ROUNDING\n#undef DESCALE\n#define DESCALE(x,n)  RIGHT_SHIFT(x, n)\n#endif\n\n\n/* Multiply a DCTELEM variable by an INT32 constant, and immediately\n * descale to yield a DCTELEM result.\n */\n\n#define MULTIPLY(var,const)  ((DCTELEM) DESCALE((var) * (const), CONST_BITS))\n\n\n/* Dequantize a coefficient by multiplying it by the multiplier-table\n * entry; produce a DCTELEM result.  For 8-bit data a 16x16->16\n * multiplication will do.  For 12-bit data, the multiplier table is\n * declared INT32, so a 32-bit multiply will be used.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define DEQUANTIZE(coef,quantval)  (((IFAST_MULT_TYPE) (coef)) * (quantval))\n#else\n#define DEQUANTIZE(coef,quantval)  \\\n\tDESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)\n#endif\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients.\n *\n * cK represents cos(K*pi/16).\n */\n\nGLOBAL(void)\njpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\n  DCTELEM tmp10, tmp11, tmp12, tmp13;\n  DCTELEM z5, z10, z11, z12, z13;\n  JCOEFPTR inptr;\n  IFAST_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[DCTSIZE2];\t/* buffers data between passes */\n  SHIFT_TEMPS\t\t\t/* for DESCALE */\n  ISHIFT_TEMPS\t\t\t/* for IRIGHT_SHIFT */\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = DCTSIZE; ctr > 0; ctr--) {\n    /* Due to quantization, we will usually find that many of the input\n     * coefficients are zero, especially the AC terms.  We can exploit this\n     * by short-circuiting the IDCT calculation for any column in which all\n     * the AC terms are zero.  In that case each output is equal to the\n     * DC coefficient (with scale factor as needed).\n     * With typical images and quantization tables, half or more of the\n     * column DCT calculations can be simplified this way.\n     */\n    \n    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&\n\tinptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&\n\tinptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&\n\tinptr[DCTSIZE*7] == 0) {\n      /* AC terms all zero */\n      int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n\n      wsptr[DCTSIZE*0] = dcval;\n      wsptr[DCTSIZE*1] = dcval;\n      wsptr[DCTSIZE*2] = dcval;\n      wsptr[DCTSIZE*3] = dcval;\n      wsptr[DCTSIZE*4] = dcval;\n      wsptr[DCTSIZE*5] = dcval;\n      wsptr[DCTSIZE*6] = dcval;\n      wsptr[DCTSIZE*7] = dcval;\n      \n      inptr++;\t\t\t/* advance pointers to next column */\n      quantptr++;\n      wsptr++;\n      continue;\n    }\n    \n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp10 = tmp0 + tmp2;\t/* phase 3 */\n    tmp11 = tmp0 - tmp2;\n\n    tmp13 = tmp1 + tmp3;\t/* phases 5-3 */\n    tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */\n\n    tmp0 = tmp10 + tmp13;\t/* phase 2 */\n    tmp3 = tmp10 - tmp13;\n    tmp1 = tmp11 + tmp12;\n    tmp2 = tmp11 - tmp12;\n    \n    /* Odd part */\n\n    tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    z13 = tmp6 + tmp5;\t\t/* phase 6 */\n    z10 = tmp6 - tmp5;\n    z11 = tmp4 + tmp7;\n    z12 = tmp4 - tmp7;\n\n    tmp7 = z11 + z13;\t\t/* phase 5 */\n    tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */\n\n    z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */\n    tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */\n    tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */\n\n    tmp6 = tmp12 - tmp7;\t/* phase 2 */\n    tmp5 = tmp11 - tmp6;\n    tmp4 = tmp10 - tmp5;\n\n    wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);\n    wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);\n    wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);\n    wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);\n    wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);\n    wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);\n    wsptr[DCTSIZE*3] = (int) (tmp3 + tmp4);\n    wsptr[DCTSIZE*4] = (int) (tmp3 - tmp4);\n\n    inptr++;\t\t\t/* advance pointers to next column */\n    quantptr++;\n    wsptr++;\n  }\n  \n  /* Pass 2: process rows from work array, store into output array.\n   * Note that we must descale the results by a factor of 8 == 2**3,\n   * and also undo the PASS1_BITS scaling.\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z5 = (DCTELEM) wsptr[0] +\n\t   ((((DCTELEM) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (1 << (PASS1_BITS+2)));\n\n    /* Rows of zeroes can be exploited in the same way as we did with columns.\n     * However, the column calculation has created many nonzero AC terms, so\n     * the simplification applies less often (typically 5% to 10% of the time).\n     * On machines with very fast multiplication, it's possible that the\n     * test takes more time than it's worth.  In that case this section\n     * may be commented out.\n     */\n    \n#ifndef NO_ZERO_ROW_TEST\n    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&\n\twsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {\n      /* AC terms all zero */\n      JSAMPLE dcval = range_limit[(int) IRIGHT_SHIFT(z5, PASS1_BITS+3)\n\t\t\t\t  & RANGE_MASK];\n      \n      outptr[0] = dcval;\n      outptr[1] = dcval;\n      outptr[2] = dcval;\n      outptr[3] = dcval;\n      outptr[4] = dcval;\n      outptr[5] = dcval;\n      outptr[6] = dcval;\n      outptr[7] = dcval;\n\n      wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n      continue;\n    }\n#endif\n    \n    /* Even part */\n\n    tmp10 = z5 + (DCTELEM) wsptr[4];\n    tmp11 = z5 - (DCTELEM) wsptr[4];\n\n    tmp13 = (DCTELEM) wsptr[2] + (DCTELEM) wsptr[6];\n    tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6],\n\t\t     FIX_1_414213562) - tmp13; /* 2*c4 */\n\n    tmp0 = tmp10 + tmp13;\n    tmp3 = tmp10 - tmp13;\n    tmp1 = tmp11 + tmp12;\n    tmp2 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];\n    z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];\n    z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];\n    z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];\n\n    tmp7 = z11 + z13;\t\t/* phase 5 */\n    tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */\n\n    z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */\n    tmp10 = z5 - MULTIPLY(z12, FIX_1_082392200); /* 2*(c2-c6) */\n    tmp12 = z5 - MULTIPLY(z10, FIX_2_613125930); /* 2*(c2+c6) */\n\n    tmp6 = tmp12 - tmp7;\t/* phase 2 */\n    tmp5 = tmp11 - tmp6;\n    tmp4 = tmp10 - tmp5;\n\n    /* Final output stage: scale down by a factor of 8 and range-limit */\n\n    outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp7, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp7, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp1 + tmp6, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) IRIGHT_SHIFT(tmp1 - tmp6, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp5, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp5, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) IRIGHT_SHIFT(tmp3 + tmp4, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) IRIGHT_SHIFT(tmp3 - tmp4, PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n}\n\n#endif /* DCT_IFAST_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jidctint.c",
    "content": "/*\n * jidctint.c\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modification developed 2002-2018 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a slow-but-accurate integer implementation of the\n * inverse DCT (Discrete Cosine Transform).  In the IJG code, this routine\n * must also perform dequantization of the input coefficients.\n *\n * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT\n * on each row (or vice versa, but it's more convenient to emit a row at\n * a time).  Direct algorithms are also available, but they are much more\n * complex and seem not to be any faster when reduced to code.\n *\n * This implementation is based on an algorithm described in\n *   C. Loeffler, A. Ligtenberg and G. Moschytz, \"Practical Fast 1-D DCT\n *   Algorithms with 11 Multiplications\", Proc. Int'l. Conf. on Acoustics,\n *   Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.\n * The primary algorithm described there uses 11 multiplies and 29 adds.\n * We use their alternate method with 12 multiplies and 32 adds.\n * The advantage of this method is that no data path contains more than one\n * multiplication; this allows a very simple and accurate implementation in\n * scaled fixed-point arithmetic, with a minimal number of shifts.\n *\n * We also provide IDCT routines with various output sample block sizes for\n * direct resolution reduction or enlargement and for direct resolving the\n * common 2x1 and 1x2 subsampling cases without additional resampling: NxN\n * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block.\n *\n * For N<8 we simply take the corresponding low-frequency coefficients of\n * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block\n * to yield the downscaled outputs.\n * This can be seen as direct low-pass downsampling from the DCT domain\n * point of view rather than the usual spatial domain point of view,\n * yielding significant computational savings and results at least\n * as good as common bilinear (averaging) spatial downsampling.\n *\n * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as\n * lower frequencies and higher frequencies assumed to be zero.\n * It turns out that the computational effort is similar to the 8x8 IDCT\n * regarding the output size.\n * Furthermore, the scaling and descaling is the same for all IDCT sizes.\n *\n * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases\n * since there would be too many additional constants to pre-calculate.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jdct.h\"\t\t/* Private declarations for DCT subsystem */\n\n#ifdef DCT_ISLOW_SUPPORTED\n\n\n/*\n * This module is specialized to the case DCTSIZE = 8.\n */\n\n#if DCTSIZE != 8\n  Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */\n#endif\n\n\n/*\n * The poop on this scaling stuff is as follows:\n *\n * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)\n * larger than the true IDCT outputs.  The final outputs are therefore\n * a factor of N larger than desired; since N=8 this can be cured by\n * a simple right shift at the end of the algorithm.  The advantage of\n * this arrangement is that we save two multiplications per 1-D IDCT,\n * because the y0 and y4 inputs need not be divided by sqrt(N).\n *\n * We have to do addition and subtraction of the integer inputs, which\n * is no problem, and multiplication by fractional constants, which is\n * a problem to do in integer arithmetic.  We multiply all the constants\n * by CONST_SCALE and convert them to integer constants (thus retaining\n * CONST_BITS bits of precision in the constants).  After doing a\n * multiplication we have to divide the product by CONST_SCALE, with proper\n * rounding, to produce the correct output.  This division can be done\n * cheaply as a right shift of CONST_BITS bits.  We postpone shifting\n * as long as possible so that partial sums can be added together with\n * full fractional precision.\n *\n * The outputs of the first pass are scaled up by PASS1_BITS bits so that\n * they are represented to better-than-integral precision.  These outputs\n * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word\n * with the recommended scaling.  (To scale up 12-bit sample data further, an\n * intermediate INT32 array would be needed.)\n *\n * To avoid overflow of the 32-bit intermediate results in pass 2, we must\n * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26.  Error analysis\n * shows that the values given below are the most effective.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define CONST_BITS  13\n#define PASS1_BITS  2\n#else\n#define CONST_BITS  13\n#define PASS1_BITS  1\t\t/* lose a little precision to avoid overflow */\n#endif\n\n/* Some C compilers fail to reduce \"FIX(constant)\" at compile time, thus\n * causing a lot of useless floating-point operations at run time.\n * To get around this we use the following pre-calculated constants.\n * If you change CONST_BITS you may want to add appropriate values.\n * (With a reasonable C compiler, you can just rely on the FIX() macro...)\n */\n\n#if CONST_BITS == 13\n#define FIX_0_298631336  ((INT32)  2446)\t/* FIX(0.298631336) */\n#define FIX_0_390180644  ((INT32)  3196)\t/* FIX(0.390180644) */\n#define FIX_0_541196100  ((INT32)  4433)\t/* FIX(0.541196100) */\n#define FIX_0_765366865  ((INT32)  6270)\t/* FIX(0.765366865) */\n#define FIX_0_899976223  ((INT32)  7373)\t/* FIX(0.899976223) */\n#define FIX_1_175875602  ((INT32)  9633)\t/* FIX(1.175875602) */\n#define FIX_1_501321110  ((INT32)  12299)\t/* FIX(1.501321110) */\n#define FIX_1_847759065  ((INT32)  15137)\t/* FIX(1.847759065) */\n#define FIX_1_961570560  ((INT32)  16069)\t/* FIX(1.961570560) */\n#define FIX_2_053119869  ((INT32)  16819)\t/* FIX(2.053119869) */\n#define FIX_2_562915447  ((INT32)  20995)\t/* FIX(2.562915447) */\n#define FIX_3_072711026  ((INT32)  25172)\t/* FIX(3.072711026) */\n#else\n#define FIX_0_298631336  FIX(0.298631336)\n#define FIX_0_390180644  FIX(0.390180644)\n#define FIX_0_541196100  FIX(0.541196100)\n#define FIX_0_765366865  FIX(0.765366865)\n#define FIX_0_899976223  FIX(0.899976223)\n#define FIX_1_175875602  FIX(1.175875602)\n#define FIX_1_501321110  FIX(1.501321110)\n#define FIX_1_847759065  FIX(1.847759065)\n#define FIX_1_961570560  FIX(1.961570560)\n#define FIX_2_053119869  FIX(2.053119869)\n#define FIX_2_562915447  FIX(2.562915447)\n#define FIX_3_072711026  FIX(3.072711026)\n#endif\n\n\n/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.\n * For 8-bit samples with the recommended scaling, all the variable\n * and constant values involved are no more than 16 bits wide, so a\n * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.\n * For 12-bit samples, a full 32-bit multiplication will be needed.\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define MULTIPLY(var,const)  MULTIPLY16C16(var,const)\n#else\n#define MULTIPLY(var,const)  ((var) * (const))\n#endif\n\n\n/* Dequantize a coefficient by multiplying it by the multiplier-table\n * entry; produce an int result.  In this module, both inputs and result\n * are 16 bits or less, so either int or short multiply will work.\n */\n\n#define DEQUANTIZE(coef,quantval)  (((ISLOW_MULT_TYPE) (coef)) * (quantval))\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients.\n *\n * Optimized algorithm with 12 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/16).\n */\n\nGLOBAL(void)\njpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[DCTSIZE2];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * Note results are scaled up by sqrt(8) compared to a true IDCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = DCTSIZE; ctr > 0; ctr--) {\n    /* Due to quantization, we will usually find that many of the input\n     * coefficients are zero, especially the AC terms.  We can exploit this\n     * by short-circuiting the IDCT calculation for any column in which all\n     * the AC terms are zero.  In that case each output is equal to the\n     * DC coefficient (with scale factor as needed).\n     * With typical images and quantization tables, half or more of the\n     * column DCT calculations can be simplified this way.\n     */\n\n    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&\n\tinptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&\n\tinptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&\n\tinptr[DCTSIZE*7] == 0) {\n      /* AC terms all zero */\n      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;\n\n      wsptr[DCTSIZE*0] = dcval;\n      wsptr[DCTSIZE*1] = dcval;\n      wsptr[DCTSIZE*2] = dcval;\n      wsptr[DCTSIZE*3] = dcval;\n      wsptr[DCTSIZE*4] = dcval;\n      wsptr[DCTSIZE*5] = dcval;\n      wsptr[DCTSIZE*6] = dcval;\n      wsptr[DCTSIZE*7] = dcval;\n\n      inptr++;\t\t\t/* advance pointers to next column */\n      quantptr++;\n      wsptr++;\n      continue;\n    }\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z2 <<= CONST_BITS;\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z2 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    tmp0 = z2 + z3;\n    tmp1 = z2 - z3;\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);\n\n    inptr++;\t\t\t/* advance pointers to next column */\n    quantptr++;\n    wsptr++;\n  }\n\n  /* Pass 2: process rows from work array, store into output array.\n   * Note that we must descale the results by a factor of 8 == 2**3,\n   * and also undo the PASS1_BITS scaling.\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < DCTSIZE; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z2 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n\n    /* Rows of zeroes can be exploited in the same way as we did with columns.\n     * However, the column calculation has created many nonzero AC terms, so\n     * the simplification applies less often (typically 5% to 10% of the time).\n     * On machines with very fast multiplication, it's possible that the\n     * test takes more time than it's worth.  In that case this section\n     * may be commented out.\n     */\n\n#ifndef NO_ZERO_ROW_TEST\n    if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&\n\twsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {\n      /* AC terms all zero */\n      JSAMPLE dcval = range_limit[(int) RIGHT_SHIFT(z2, PASS1_BITS+3)\n\t\t\t\t  & RANGE_MASK];\n\n      outptr[0] = dcval;\n      outptr[1] = dcval;\n      outptr[2] = dcval;\n      outptr[3] = dcval;\n      outptr[4] = dcval;\n      outptr[5] = dcval;\n      outptr[6] = dcval;\n      outptr[7] = dcval;\n\n      wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n      continue;\n    }\n#endif\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    z3 = (INT32) wsptr[4];\n\n    tmp0 = (z2 + z3) << CONST_BITS;\n    tmp1 = (z2 - z3) << CONST_BITS;\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[6];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = (INT32) wsptr[7];\n    tmp1 = (INT32) wsptr[5];\n    tmp2 = (INT32) wsptr[3];\n    tmp3 = (INT32) wsptr[1];\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n}\n\n#ifdef IDCT_SCALING_SUPPORTED\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 7x7 output block.\n *\n * Optimized algorithm with 12 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/14).\n */\n\nGLOBAL(void)\njpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[7*7];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp13 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp13 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734));     /* c4 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123));     /* c6 */\n    tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */\n    tmp0 = z1 + z3;\n    z2 -= tmp0;\n    tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */\n    tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536));  /* c2-c4-c6 */\n    tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249));  /* c2+c4+c6 */\n    tmp13 += MULTIPLY(z2, FIX(1.414213562));         /* c0 */\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n\n    tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347));      /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339));      /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276));    /* -c1 */\n    tmp1 += tmp2;\n    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));        /* c5 */\n    tmp0 += z2;\n    tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693));     /* c3+c1-c5 */\n\n    /* Final output stage */\n\n    wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 7 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 7; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp13 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp13 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[4];\n    z3 = (INT32) wsptr[6];\n\n    tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734));     /* c4 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123));     /* c6 */\n    tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */\n    tmp0 = z1 + z3;\n    z2 -= tmp0;\n    tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */\n    tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536));  /* c2-c4-c6 */\n    tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249));  /* c2+c4+c6 */\n    tmp13 += MULTIPLY(z2, FIX(1.414213562));         /* c0 */\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n\n    tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347));      /* (c3+c1-c5)/2 */\n    tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339));      /* (c3+c5-c1)/2 */\n    tmp0 = tmp1 - tmp2;\n    tmp1 += tmp2;\n    tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276));    /* -c1 */\n    tmp1 += tmp2;\n    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));        /* c5 */\n    tmp0 += z2;\n    tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693));     /* c3+c1-c5 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 7;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 6x6 output block.\n *\n * Optimized algorithm with 3 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/12).\n */\n\nGLOBAL(void)\njpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[6*6];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */\n    tmp1 = tmp0 + tmp10;\n    tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);\n    tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */\n    tmp10 = tmp1 + tmp0;\n    tmp12 = tmp1 - tmp0;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);\n    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);\n    tmp1 = (z1 - z2 - z3) << PASS1_BITS;\n\n    /* Final output stage */\n\n    wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[6*1] = (int) (tmp11 + tmp1);\n    wsptr[6*4] = (int) (tmp11 - tmp1);\n    wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 6 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n    tmp2 = (INT32) wsptr[4];\n    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */\n    tmp1 = tmp0 + tmp10;\n    tmp11 = tmp0 - tmp10 - tmp10;\n    tmp10 = (INT32) wsptr[2];\n    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */\n    tmp10 = tmp1 + tmp0;\n    tmp12 = tmp1 - tmp0;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);\n    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);\n    tmp1 = (z1 - z2 - z3) << CONST_BITS;\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 6;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 5x5 output block.\n *\n * Optimized algorithm with 5 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/10).\n */\n\nGLOBAL(void)\njpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp10, tmp11, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[5*5];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp12 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */\n    z3 = tmp12 + z2;\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z1;\n    tmp12 -= z2 << 2;\n\n    /* Odd part */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));     /* c3 */\n    tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148));   /* c1-c3 */\n    tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899));   /* c1+c3 */\n\n    /* Final output stage */\n\n    wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 5 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 5; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp12 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp12 <<= CONST_BITS;\n    tmp0 = (INT32) wsptr[2];\n    tmp1 = (INT32) wsptr[4];\n    z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */\n    z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */\n    z3 = tmp12 + z2;\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z1;\n    tmp12 -= z2 << 2;\n\n    /* Odd part */\n\n    z2 = (INT32) wsptr[1];\n    z3 = (INT32) wsptr[3];\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));     /* c3 */\n    tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148));   /* c1-c3 */\n    tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899));   /* c1+c3 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 5;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 4x4 output block.\n *\n * Optimized algorithm with 3 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].\n */\n\nGLOBAL(void)\njpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp2, tmp10, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[4*4];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    \n    tmp10 = (tmp0 + tmp2) << PASS1_BITS;\n    tmp12 = (tmp0 - tmp2) << PASS1_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);               /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */\n\t\t       CONST_BITS-PASS1_BITS);\n    tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */\n\t\t       CONST_BITS-PASS1_BITS);\n\n    /* Final output stage */\n\n    wsptr[4*0] = (int) (tmp10 + tmp0);\n    wsptr[4*3] = (int) (tmp10 - tmp0);\n    wsptr[4*1] = (int) (tmp12 + tmp2);\n    wsptr[4*2] = (int) (tmp12 - tmp2);\n  }\n\n  /* Pass 2: process 4 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 4; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp2 = (INT32) wsptr[2];\n\n    tmp10 = (tmp0 + tmp2) << CONST_BITS;\n    tmp12 = (tmp0 - tmp2) << CONST_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = (INT32) wsptr[1];\n    z3 = (INT32) wsptr[3];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */\n    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 4;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 3x3 output block.\n *\n * Optimized algorithm with 2 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/6).\n */\n\nGLOBAL(void)\njpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp2, tmp10, tmp12;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[3*3];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */\n    tmp10 = tmp0 + tmp12;\n    tmp2 = tmp0 - tmp12 - tmp12;\n\n    /* Odd part */\n\n    tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */\n\n    /* Final output stage */\n\n    wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 3 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 3; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n    tmp2 = (INT32) wsptr[2];\n    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */\n    tmp10 = tmp0 + tmp12;\n    tmp2 = tmp0 - tmp12 - tmp12;\n\n    /* Odd part */\n\n    tmp12 = (INT32) wsptr[1];\n    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 3;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 2x2 output block.\n *\n * Multiplication-less algorithm.\n */\n\nGLOBAL(void)\njpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;\n  ISLOW_MULT_TYPE * quantptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  ISHIFT_TEMPS\n\n  /* Pass 1: process columns from input. */\n\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n\n  /* Column 0 */\n  tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);\n  tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);\n  /* Add range center and fudge factor for final descale and range-limit. */\n  tmp4 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2);\n\n  tmp0 = tmp4 + tmp5;\n  tmp2 = tmp4 - tmp5;\n\n  /* Column 1 */\n  tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]);\n  tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]);\n\n  tmp1 = tmp4 + tmp5;\n  tmp3 = tmp4 - tmp5;\n\n  /* Pass 2: process 2 rows, store into output array. */\n\n  /* Row 0 */\n  outptr = output_buf[0] + output_col;\n\n  outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];\n  outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];\n\n  /* Row 1 */\n  outptr = output_buf[1] + output_col;\n\n  outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK];\n  outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK];\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a reduced-size 1x1 output block.\n *\n * We hardly need an inverse DCT routine for this: just take the\n * average pixel value, which is one-eighth of the DC coefficient.\n */\n\nGLOBAL(void)\njpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  DCTELEM dcval;\n  ISLOW_MULT_TYPE * quantptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  ISHIFT_TEMPS\n\n  /* 1x1 is trivial: just take the DC coefficient divided by 8. */\n\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n\n  dcval = DEQUANTIZE(coef_block[0], quantptr[0]);\n  /* Add range center and fudge factor for descale and range-limit. */\n  dcval += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2);\n\n  output_buf[0][output_col] =\n    range_limit[(int) IRIGHT_SHIFT(dcval, 3) & RANGE_MASK];\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 9x9 output block.\n *\n * Optimized algorithm with 10 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/18).\n */\n\nGLOBAL(void)\njpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*9];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp3 = MULTIPLY(z3, FIX(0.707106781));      /* c6 */\n    tmp1 = tmp0 + tmp3;\n    tmp2 = tmp0 - tmp3 - tmp3;\n\n    tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */\n    tmp11 = tmp2 + tmp0;\n    tmp14 = tmp2 - tmp0 - tmp0;\n\n    tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */\n    tmp2 = MULTIPLY(z1, FIX(1.083350441));      /* c4 */\n    tmp3 = MULTIPLY(z2, FIX(0.245575608));      /* c8 */\n\n    tmp10 = tmp1 + tmp0 - tmp3;\n    tmp12 = tmp1 - tmp0 + tmp2;\n    tmp13 = tmp1 - tmp2 + tmp3;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    z2 = MULTIPLY(z2, - FIX(1.224744871));           /* -c3 */\n\n    tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955));      /* c5 */\n    tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525));      /* c7 */\n    tmp0 = tmp2 + tmp3 - z2;\n    tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481));      /* c1 */\n    tmp2 += z2 - tmp1;\n    tmp3 += z2 + tmp1;\n    tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 9 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 9; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[4];\n    z3 = (INT32) wsptr[6];\n\n    tmp3 = MULTIPLY(z3, FIX(0.707106781));      /* c6 */\n    tmp1 = tmp0 + tmp3;\n    tmp2 = tmp0 - tmp3 - tmp3;\n\n    tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */\n    tmp11 = tmp2 + tmp0;\n    tmp14 = tmp2 - tmp0 - tmp0;\n\n    tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */\n    tmp2 = MULTIPLY(z1, FIX(1.083350441));      /* c4 */\n    tmp3 = MULTIPLY(z2, FIX(0.245575608));      /* c8 */\n\n    tmp10 = tmp1 + tmp0 - tmp3;\n    tmp12 = tmp1 - tmp0 + tmp2;\n    tmp13 = tmp1 - tmp2 + tmp3;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    z2 = MULTIPLY(z2, - FIX(1.224744871));           /* -c3 */\n\n    tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955));      /* c5 */\n    tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525));      /* c7 */\n    tmp0 = tmp2 + tmp3 - z2;\n    tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481));      /* c1 */\n    tmp2 += z2 - tmp1;\n    tmp3 += z2 + tmp1;\n    tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 10x10 output block.\n *\n * Optimized algorithm with 12 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/20).\n */\n\nGLOBAL(void)\njpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;\n  INT32 z1, z2, z3, z4, z5;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*10];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z3 += ONE << (CONST_BITS-PASS1_BITS-1);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */\n    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z2;\n\n    tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1),   /* c0 = (c4-c8)*2 */\n\t\t\tCONST_BITS-PASS1_BITS);\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */\n    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */\n    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */\n\n    tmp20 = tmp10 + tmp12;\n    tmp24 = tmp10 - tmp12;\n    tmp21 = tmp11 + tmp13;\n    tmp23 = tmp11 - tmp13;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = z2 + z4;\n    tmp13 = z2 - z4;\n\n    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */\n    z5 = z3 << CONST_BITS;\n\n    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */\n    z4 = z5 + tmp12;\n\n    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */\n    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */\n    z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));\n\n    tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;\n\n    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */\n    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2] = (int) (tmp22 + tmp12);\n    wsptr[8*7] = (int) (tmp22 - tmp12);\n    wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 10 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 10; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z3 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 <<= CONST_BITS;\n    z4 = (INT32) wsptr[4];\n    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */\n    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z2;\n\n    tmp22 = z3 - ((z1 - z2) << 1);               /* c0 = (c4-c8)*2 */\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[6];\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */\n    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */\n    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */\n\n    tmp20 = tmp10 + tmp12;\n    tmp24 = tmp10 - tmp12;\n    tmp21 = tmp11 + tmp13;\n    tmp23 = tmp11 - tmp13;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z3 <<= CONST_BITS;\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = z2 + z4;\n    tmp13 = z2 - z4;\n\n    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */\n    z4 = z3 + tmp12;\n\n    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */\n    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */\n    z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));\n\n    tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;\n\n    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */\n    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing an 11x11 output block.\n *\n * Optimized algorithm with 24 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/22).\n */\n\nGLOBAL(void)\njpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*11];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp10 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132));     /* c2+c4 */\n    tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045));     /* c2-c6 */\n    z4 = z1 + z3;\n    tmp24 = MULTIPLY(z4, - FIX(1.155664402));        /* -(c2-c10) */\n    z4 -= z2;\n    tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976));  /* c2 */\n    tmp21 = tmp20 + tmp23 + tmp25 -\n\t    MULTIPLY(z2, FIX(1.821790775));          /* c2+c4+c10-c6 */\n    tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */\n    tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */\n    tmp24 += tmp25;\n    tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120));  /* c8+c10 */\n    tmp24 += MULTIPLY(z2, FIX(1.944413522)) -        /* c2+c8 */\n\t     MULTIPLY(z1, FIX(1.390975730));         /* c4+c10 */\n    tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562));  /* c0 */\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = z1 + z2;\n    tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */\n    tmp11 = MULTIPLY(tmp11, FIX(0.887983902));           /* c3-c9 */\n    tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295));         /* c5-c9 */\n    tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(z1, FIX(0.923107866));              /* c7+c5+c3-c1-2*c9 */\n    z1    = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */\n    tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588));        /* c1+c7+3*c9-c3 */\n    tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623));        /* c3+c5-c7-c9 */\n    z1    = MULTIPLY(z2 + z4, - FIX(1.798248910));       /* -(c1+c9) */\n    tmp11 += z1;\n    tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632));        /* c1+c5+c9-c7 */\n    tmp14 += MULTIPLY(z2, - FIX(1.467221301)) +          /* -(c5+c9) */\n\t     MULTIPLY(z3, FIX(1.001388905)) -            /* c1-c9 */\n\t     MULTIPLY(z4, FIX(1.684843907));             /* c3+c9 */\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 11 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 11; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp10 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp10 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[4];\n    z3 = (INT32) wsptr[6];\n\n    tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132));     /* c2+c4 */\n    tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045));     /* c2-c6 */\n    z4 = z1 + z3;\n    tmp24 = MULTIPLY(z4, - FIX(1.155664402));        /* -(c2-c10) */\n    z4 -= z2;\n    tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976));  /* c2 */\n    tmp21 = tmp20 + tmp23 + tmp25 -\n\t    MULTIPLY(z2, FIX(1.821790775));          /* c2+c4+c10-c6 */\n    tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */\n    tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */\n    tmp24 += tmp25;\n    tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120));  /* c8+c10 */\n    tmp24 += MULTIPLY(z2, FIX(1.944413522)) -        /* c2+c8 */\n\t     MULTIPLY(z1, FIX(1.390975730));         /* c4+c10 */\n    tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562));  /* c0 */\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = z1 + z2;\n    tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */\n    tmp11 = MULTIPLY(tmp11, FIX(0.887983902));           /* c3-c9 */\n    tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295));         /* c5-c9 */\n    tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(z1, FIX(0.923107866));              /* c7+c5+c3-c1-2*c9 */\n    z1    = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */\n    tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588));        /* c1+c7+3*c9-c3 */\n    tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623));        /* c3+c5-c7-c9 */\n    z1    = MULTIPLY(z2 + z4, - FIX(1.798248910));       /* -(c1+c9) */\n    tmp11 += z1;\n    tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632));        /* c1+c5+c9-c7 */\n    tmp14 += MULTIPLY(z2, - FIX(1.467221301)) +          /* -(c5+c9) */\n\t     MULTIPLY(z3, FIX(1.001388905)) -            /* c1-c9 */\n\t     MULTIPLY(z4, FIX(1.684843907));             /* c3+c9 */\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 12x12 output block.\n *\n * Optimized algorithm with 15 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/24).\n */\n\nGLOBAL(void)\njpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*12];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z3 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */\n    z1 <<= CONST_BITS;\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n    z2 <<= CONST_BITS;\n\n    tmp12 = z1 - z2;\n\n    tmp21 = z3 + tmp12;\n    tmp24 = z3 - tmp12;\n\n    tmp12 = z4 + z2;\n\n    tmp20 = tmp10 + tmp12;\n    tmp25 = tmp10 - tmp12;\n\n    tmp12 = z4 - z1 - z2;\n\n    tmp22 = tmp11 + tmp12;\n    tmp23 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */\n    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */\n\n    tmp10 = z1 + z3;\n    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */\n    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */\n    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */\n    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */\n    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */\n    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */\n    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */\n\t     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */\n\n    z1 -= z4;\n    z2 -= z3;\n    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */\n    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */\n    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 12 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 12; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z3 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 <<= CONST_BITS;\n\n    z4 = (INT32) wsptr[4];\n    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    z1 = (INT32) wsptr[2];\n    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */\n    z1 <<= CONST_BITS;\n    z2 = (INT32) wsptr[6];\n    z2 <<= CONST_BITS;\n\n    tmp12 = z1 - z2;\n\n    tmp21 = z3 + tmp12;\n    tmp24 = z3 - tmp12;\n\n    tmp12 = z4 + z2;\n\n    tmp20 = tmp10 + tmp12;\n    tmp25 = tmp10 - tmp12;\n\n    tmp12 = z4 - z1 - z2;\n\n    tmp22 = tmp11 + tmp12;\n    tmp23 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */\n    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */\n\n    tmp10 = z1 + z3;\n    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */\n    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */\n    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */\n    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */\n    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */\n    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */\n    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */\n\t     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */\n\n    z1 -= z4;\n    z2 -= z3;\n    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */\n    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */\n    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 13x13 output block.\n *\n * Optimized algorithm with 29 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/26).\n */\n\nGLOBAL(void)\njpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*13];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z1 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    tmp12 = MULTIPLY(tmp10, FIX(1.155388986));                /* (c4+c6)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1;           /* (c4-c6)/2 */\n\n    tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13;   /* c2 */\n    tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13;   /* c10 */\n\n    tmp12 = MULTIPLY(tmp10, FIX(0.316450131));                /* (c8-c12)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1;           /* (c8+c12)/2 */\n\n    tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13;   /* c6 */\n    tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */\n\n    tmp12 = MULTIPLY(tmp10, FIX(0.435816023));                /* (c2-c10)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1;           /* (c2+c10)/2 */\n\n    tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */\n    tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */\n\n    tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1;      /* c0 */\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651));     /* c3 */\n    tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945));     /* c5 */\n    tmp15 = z1 + z4;\n    tmp13 = MULTIPLY(tmp15, FIX(0.937797057));       /* c7 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(z1, FIX(2.020082300));          /* c7+c5+c3-c1 */\n    tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458));   /* -c11 */\n    tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */\n    tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */\n    tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945));   /* -c5 */\n    tmp11 += tmp14;\n    tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */\n    tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813));   /* -c9 */\n    tmp12 += tmp14;\n    tmp13 += tmp14;\n    tmp15 = MULTIPLY(tmp15, FIX(0.338443458));       /* c11 */\n    tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */\n\t    MULTIPLY(z2, FIX(0.466105296));          /* c1-c7 */\n    z1    = MULTIPLY(z3 - z2, FIX(0.937797057));     /* c7 */\n    tmp14 += z1;\n    tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) -   /* c3-c7 */\n\t     MULTIPLY(z4, FIX(1.742345811));         /* c1+c11 */\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 13 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 13; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z1 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z1 <<= CONST_BITS;\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[4];\n    z4 = (INT32) wsptr[6];\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    tmp12 = MULTIPLY(tmp10, FIX(1.155388986));                /* (c4+c6)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1;           /* (c4-c6)/2 */\n\n    tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13;   /* c2 */\n    tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13;   /* c10 */\n\n    tmp12 = MULTIPLY(tmp10, FIX(0.316450131));                /* (c8-c12)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1;           /* (c8+c12)/2 */\n\n    tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13;   /* c6 */\n    tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */\n\n    tmp12 = MULTIPLY(tmp10, FIX(0.435816023));                /* (c2-c10)/2 */\n    tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1;           /* (c2+c10)/2 */\n\n    tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */\n    tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */\n\n    tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1;      /* c0 */\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651));     /* c3 */\n    tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945));     /* c5 */\n    tmp15 = z1 + z4;\n    tmp13 = MULTIPLY(tmp15, FIX(0.937797057));       /* c7 */\n    tmp10 = tmp11 + tmp12 + tmp13 -\n\t    MULTIPLY(z1, FIX(2.020082300));          /* c7+c5+c3-c1 */\n    tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458));   /* -c11 */\n    tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */\n    tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */\n    tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945));   /* -c5 */\n    tmp11 += tmp14;\n    tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */\n    tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813));   /* -c9 */\n    tmp12 += tmp14;\n    tmp13 += tmp14;\n    tmp15 = MULTIPLY(tmp15, FIX(0.338443458));       /* c11 */\n    tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */\n\t    MULTIPLY(z2, FIX(0.466105296));          /* c1-c7 */\n    z1    = MULTIPLY(z3 - z2, FIX(0.937797057));     /* c7 */\n    tmp14 += z1;\n    tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) -   /* c3-c7 */\n\t     MULTIPLY(z4, FIX(1.742345811));         /* c1+c11 */\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 14x14 output block.\n *\n * Optimized algorithm with 20 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/28).\n */\n\nGLOBAL(void)\njpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*14];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z1 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */\n    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */\n    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */\n\n    tmp10 = z1 + z2;\n    tmp11 = z1 + z3;\n    tmp12 = z1 - z4;\n\n    tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */\n\t\t\tCONST_BITS-PASS1_BITS);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */\n\n    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */\n    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */\n    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */\n\t    MULTIPLY(z2, FIX(1.378756276));      /* c2 */\n\n    tmp20 = tmp10 + tmp13;\n    tmp26 = tmp10 - tmp13;\n    tmp21 = tmp11 + tmp14;\n    tmp25 = tmp11 - tmp14;\n    tmp22 = tmp12 + tmp15;\n    tmp24 = tmp12 - tmp15;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n    tmp13 = z4 << CONST_BITS;\n\n    tmp14 = z1 + z3;\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */\n    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */\n    tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */\n    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */\n    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */\n    z1    -= z2;\n    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13;        /* c11 */\n    tmp16 += tmp15;\n    z1    += z4;\n    z4    = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */\n    tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948));          /* c3-c9-c13 */\n    tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773));          /* c3+c5-c13 */\n    z4    = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */\n    tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */\n    tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567));          /* c1+c11-c5 */\n\n    tmp13 = (z1 - z3) << PASS1_BITS;\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) (tmp23 + tmp13);\n    wsptr[8*10] = (int) (tmp23 - tmp13);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 14 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 14; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z1 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z1 <<= CONST_BITS;\n    z4 = (INT32) wsptr[4];\n    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */\n    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */\n    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */\n\n    tmp10 = z1 + z2;\n    tmp11 = z1 + z3;\n    tmp12 = z1 - z4;\n\n    tmp23 = z1 - ((z2 + z3 - z4) << 1);          /* c0 = (c4+c12-c8)*2 */\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[6];\n\n    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */\n\n    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */\n    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */\n    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */\n\t    MULTIPLY(z2, FIX(1.378756276));      /* c2 */\n\n    tmp20 = tmp10 + tmp13;\n    tmp26 = tmp10 - tmp13;\n    tmp21 = tmp11 + tmp14;\n    tmp25 = tmp11 - tmp14;\n    tmp22 = tmp12 + tmp15;\n    tmp24 = tmp12 - tmp15;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n    z4 <<= CONST_BITS;\n\n    tmp14 = z1 + z3;\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */\n    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */\n    tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */\n    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */\n    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */\n    z1    -= z2;\n    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4;           /* c11 */\n    tmp16 += tmp15;\n    tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4;    /* -c13 */\n    tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948));       /* c3-c9-c13 */\n    tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773));       /* c3+c5-c13 */\n    tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */\n    tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */\n    tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567));       /* c1+c11-c5 */\n\n    tmp13 = ((z1 - z3) << CONST_BITS) + z4;\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 15x15 output block.\n *\n * Optimized algorithm with 22 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/30).\n */\n\nGLOBAL(void)\njpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*15];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z1 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */\n    tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */\n\n    tmp12 = z1 - tmp10;\n    tmp13 = z1 + tmp11;\n    z1 -= (tmp11 - tmp10) << 1;             /* c0 = (c6-c12)*2 */\n\n    z4 = z2 - z3;\n    z3 += z2;\n    tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */\n    z2 = MULTIPLY(z2, FIX(1.439773946));    /* c4+c14 */\n\n    tmp20 = tmp13 + tmp10 + tmp11;\n    tmp23 = tmp12 - tmp10 + tmp11 + z2;\n\n    tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */\n\n    tmp25 = tmp13 - tmp10 - tmp11;\n    tmp26 = tmp12 + tmp10 - tmp11 - z2;\n\n    tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */\n\n    tmp21 = tmp12 + tmp10 + tmp11;\n    tmp24 = tmp13 - tmp10 + tmp11;\n    tmp11 += tmp11;\n    tmp22 = z1 + tmp11;                     /* c10 = c6-c12 */\n    tmp27 = z1 - tmp11 - tmp11;             /* c0 = (c6-c12)*2 */\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z3 = MULTIPLY(z4, FIX(1.224744871));                    /* c5 */\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp13 = z2 - z4;\n    tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876));         /* c9 */\n    tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148));         /* c3-c9 */\n    tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899));      /* c3+c9 */\n\n    tmp13 = MULTIPLY(z2, - FIX(0.831253876));               /* -c9 */\n    tmp15 = MULTIPLY(z2, - FIX(1.344997024));               /* -c3 */\n    z2 = z1 - z4;\n    tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353));            /* c1 */\n\n    tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */\n    tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */\n    tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3;            /* c5 */\n    z2 = MULTIPLY(z1 + z4, FIX(0.575212477));               /* c11 */\n    tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3;      /* c7-c11 */\n    tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3;      /* c11+c13 */\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 15 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 15; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z1 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z1 <<= CONST_BITS;\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[4];\n    z4 = (INT32) wsptr[6];\n\n    tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */\n    tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */\n\n    tmp12 = z1 - tmp10;\n    tmp13 = z1 + tmp11;\n    z1 -= (tmp11 - tmp10) << 1;             /* c0 = (c6-c12)*2 */\n\n    z4 = z2 - z3;\n    z3 += z2;\n    tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */\n    z2 = MULTIPLY(z2, FIX(1.439773946));    /* c4+c14 */\n\n    tmp20 = tmp13 + tmp10 + tmp11;\n    tmp23 = tmp12 - tmp10 + tmp11 + z2;\n\n    tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */\n\n    tmp25 = tmp13 - tmp10 - tmp11;\n    tmp26 = tmp12 + tmp10 - tmp11 - z2;\n\n    tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */\n    tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */\n\n    tmp21 = tmp12 + tmp10 + tmp11;\n    tmp24 = tmp13 - tmp10 + tmp11;\n    tmp11 += tmp11;\n    tmp22 = z1 + tmp11;                     /* c10 = c6-c12 */\n    tmp27 = z1 - tmp11 - tmp11;             /* c0 = (c6-c12)*2 */\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z4 = (INT32) wsptr[5];\n    z3 = MULTIPLY(z4, FIX(1.224744871));                    /* c5 */\n    z4 = (INT32) wsptr[7];\n\n    tmp13 = z2 - z4;\n    tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876));         /* c9 */\n    tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148));         /* c3-c9 */\n    tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899));      /* c3+c9 */\n\n    tmp13 = MULTIPLY(z2, - FIX(0.831253876));               /* -c9 */\n    tmp15 = MULTIPLY(z2, - FIX(1.344997024));               /* -c3 */\n    z2 = z1 - z4;\n    tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353));            /* c1 */\n\n    tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */\n    tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */\n    tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3;            /* c5 */\n    z2 = MULTIPLY(z1 + z4, FIX(0.575212477));               /* c11 */\n    tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3;      /* c7-c11 */\n    tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3;      /* c11+c13 */\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 16x16 output block.\n *\n * Optimized algorithm with 28 multiplications in the 1-D kernel.\n * cK represents sqrt(2) * cos(K*pi/32).\n */\n\nGLOBAL(void)\njpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*16];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */\n    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n    z3 = z1 - z2;\n    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */\n    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */\n\n    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */\n    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */\n    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */\n    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */\n\n    tmp20 = tmp10 + tmp0;\n    tmp27 = tmp10 - tmp0;\n    tmp21 = tmp12 + tmp1;\n    tmp26 = tmp12 - tmp1;\n    tmp22 = tmp13 + tmp2;\n    tmp25 = tmp13 - tmp2;\n    tmp23 = tmp11 + tmp3;\n    tmp24 = tmp11 - tmp3;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = z1 + z3;\n\n    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */\n    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */\n    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */\n    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */\n    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */\n    tmp0  = tmp1 + tmp2 + tmp3 -\n\t    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */\n    tmp13 = tmp10 + tmp11 + tmp12 -\n\t    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */\n    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */\n    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */\n    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */\n    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */\n    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */\n    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */\n    z2    += z4;\n    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */\n    tmp1  += z1;\n    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */\n    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */\n    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */\n    tmp12 += z2;\n    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */\n    tmp2  += z2;\n    tmp3  += z2;\n    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */\n    tmp10 += z2;\n    tmp11 += z2;\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp0,  CONST_BITS-PASS1_BITS);\n    wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0,  CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp1,  CONST_BITS-PASS1_BITS);\n    wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1,  CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp2,  CONST_BITS-PASS1_BITS);\n    wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2,  CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp3,  CONST_BITS-PASS1_BITS);\n    wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3,  CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 16 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 16; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[4];\n    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */\n    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[6];\n    z3 = z1 - z2;\n    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */\n    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */\n\n    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */\n    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */\n    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */\n    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */\n\n    tmp20 = tmp10 + tmp0;\n    tmp27 = tmp10 - tmp0;\n    tmp21 = tmp12 + tmp1;\n    tmp26 = tmp12 - tmp1;\n    tmp22 = tmp13 + tmp2;\n    tmp25 = tmp13 - tmp2;\n    tmp23 = tmp11 + tmp3;\n    tmp24 = tmp11 - tmp3;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = z1 + z3;\n\n    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */\n    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */\n    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */\n    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */\n    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */\n    tmp0  = tmp1 + tmp2 + tmp3 -\n\t    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */\n    tmp13 = tmp10 + tmp11 + tmp12 -\n\t    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */\n    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */\n    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */\n    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */\n    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */\n    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */\n    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */\n    z2    += z4;\n    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */\n    tmp1  += z1;\n    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */\n    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */\n    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */\n    tmp12 += z2;\n    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */\n    tmp2  += z2;\n    tmp3  += z2;\n    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */\n    tmp10 += z2;\n    tmp11 += z2;\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 16x8 output block.\n *\n * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*8];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * Note results are scaled up by sqrt(8) compared to a true IDCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = DCTSIZE; ctr > 0; ctr--) {\n    /* Due to quantization, we will usually find that many of the input\n     * coefficients are zero, especially the AC terms.  We can exploit this\n     * by short-circuiting the IDCT calculation for any column in which all\n     * the AC terms are zero.  In that case each output is equal to the\n     * DC coefficient (with scale factor as needed).\n     * With typical images and quantization tables, half or more of the\n     * column DCT calculations can be simplified this way.\n     */\n\n    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&\n\tinptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&\n\tinptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&\n\tinptr[DCTSIZE*7] == 0) {\n      /* AC terms all zero */\n      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;\n\n      wsptr[DCTSIZE*0] = dcval;\n      wsptr[DCTSIZE*1] = dcval;\n      wsptr[DCTSIZE*2] = dcval;\n      wsptr[DCTSIZE*3] = dcval;\n      wsptr[DCTSIZE*4] = dcval;\n      wsptr[DCTSIZE*5] = dcval;\n      wsptr[DCTSIZE*6] = dcval;\n      wsptr[DCTSIZE*7] = dcval;\n\n      inptr++;\t\t\t/* advance pointers to next column */\n      quantptr++;\n      wsptr++;\n      continue;\n    }\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z2 <<= CONST_BITS;\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z2 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    tmp0 = z2 + z3;\n    tmp1 = z2 - z3;\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);\n\n    inptr++;\t\t\t/* advance pointers to next column */\n    quantptr++;\n    wsptr++;\n  }\n\n  /* Pass 2: process 8 rows from work array, store into output array.\n   * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[4];\n    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */\n    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[6];\n    z3 = z1 - z2;\n    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */\n    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */\n\n    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */\n    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */\n    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */\n    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */\n\n    tmp20 = tmp10 + tmp0;\n    tmp27 = tmp10 - tmp0;\n    tmp21 = tmp12 + tmp1;\n    tmp26 = tmp12 - tmp1;\n    tmp22 = tmp13 + tmp2;\n    tmp25 = tmp13 - tmp2;\n    tmp23 = tmp11 + tmp3;\n    tmp24 = tmp11 - tmp3;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = z1 + z3;\n\n    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */\n    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */\n    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */\n    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */\n    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */\n    tmp0  = tmp1 + tmp2 + tmp3 -\n\t    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */\n    tmp13 = tmp10 + tmp11 + tmp12 -\n\t    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */\n    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */\n    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */\n    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */\n    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */\n    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */\n    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */\n    z2    += z4;\n    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */\n    tmp1  += z1;\n    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */\n    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */\n    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */\n    tmp12 += z2;\n    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */\n    tmp2  += z2;\n    tmp3  += z2;\n    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */\n    tmp10 += z2;\n    tmp11 += z2;\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 14x7 output block.\n *\n * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*7];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp23 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp23 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734));       /* c4 */\n    tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123));       /* c6 */\n    tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */\n    tmp10 = z1 + z3;\n    z2 -= tmp10;\n    tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */\n    tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536));   /* c2-c4-c6 */\n    tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249));   /* c2+c4+c6 */\n    tmp23 += MULTIPLY(z2, FIX(1.414213562));           /* c0 */\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n\n    tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347));       /* (c3+c1-c5)/2 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339));       /* (c3+c5-c1)/2 */\n    tmp10 = tmp11 - tmp12;\n    tmp11 += tmp12;\n    tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276));     /* -c1 */\n    tmp11 += tmp12;\n    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));          /* c5 */\n    tmp10 += z2;\n    tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693));      /* c3+c1-c5 */\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 7 rows from work array, store into output array.\n   * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 7; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z1 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z1 <<= CONST_BITS;\n    z4 = (INT32) wsptr[4];\n    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */\n    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */\n    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */\n\n    tmp10 = z1 + z2;\n    tmp11 = z1 + z3;\n    tmp12 = z1 - z4;\n\n    tmp23 = z1 - ((z2 + z3 - z4) << 1);          /* c0 = (c4+c12-c8)*2 */\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[6];\n\n    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */\n\n    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */\n    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */\n    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */\n\t    MULTIPLY(z2, FIX(1.378756276));      /* c2 */\n\n    tmp20 = tmp10 + tmp13;\n    tmp26 = tmp10 - tmp13;\n    tmp21 = tmp11 + tmp14;\n    tmp25 = tmp11 - tmp14;\n    tmp22 = tmp12 + tmp15;\n    tmp24 = tmp12 - tmp15;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n    z4 <<= CONST_BITS;\n\n    tmp14 = z1 + z3;\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */\n    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */\n    tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */\n    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */\n    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */\n    z1    -= z2;\n    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4;           /* c11 */\n    tmp16 += tmp15;\n    tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4;    /* -c13 */\n    tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948));       /* c3-c9-c13 */\n    tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773));       /* c3+c5-c13 */\n    tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */\n    tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */\n    tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567));       /* c1+c11-c5 */\n\n    tmp13 = ((z1 - z3) << CONST_BITS) + z4;\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 12x6 output block.\n *\n * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*6];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp10 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp20 = MULTIPLY(tmp12, FIX(0.707106781));   /* c4 */\n    tmp11 = tmp10 + tmp20;\n    tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS);\n    tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp10 = MULTIPLY(tmp20, FIX(1.224744871));   /* c2 */\n    tmp20 = tmp11 + tmp10;\n    tmp22 = tmp11 - tmp10;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);\n    tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);\n    tmp11 = (z1 - z2 - z3) << PASS1_BITS;\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*1] = (int) (tmp21 + tmp11);\n    wsptr[8*4] = (int) (tmp21 - tmp11);\n    wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 6 rows from work array, store into output array.\n   * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z3 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 <<= CONST_BITS;\n\n    z4 = (INT32) wsptr[4];\n    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    z1 = (INT32) wsptr[2];\n    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */\n    z1 <<= CONST_BITS;\n    z2 = (INT32) wsptr[6];\n    z2 <<= CONST_BITS;\n\n    tmp12 = z1 - z2;\n\n    tmp21 = z3 + tmp12;\n    tmp24 = z3 - tmp12;\n\n    tmp12 = z4 + z2;\n\n    tmp20 = tmp10 + tmp12;\n    tmp25 = tmp10 - tmp12;\n\n    tmp12 = z4 - z1 - z2;\n\n    tmp22 = tmp11 + tmp12;\n    tmp23 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */\n    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */\n\n    tmp10 = z1 + z3;\n    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */\n    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */\n    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */\n    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */\n    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */\n    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */\n    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */\n\t     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */\n\n    z1 -= z4;\n    z2 -= z3;\n    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */\n    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */\n    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */\n\n    /* Final output stage */\n\n    outptr[0]  = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[1]  = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[2]  = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[9]  = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[3]  = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[8]  = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[4]  = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[7]  = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[5]  = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n    outptr[6]  = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,\n\t\t\t\t\t       CONST_BITS+PASS1_BITS+3)\n\t\t\t     & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 10x5 output block.\n *\n * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*5];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp12 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */\n    z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */\n    z3 = tmp12 + z2;\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z1;\n    tmp12 -= z2 << 2;\n\n    /* Odd part */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));       /* c3 */\n    tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148));    /* c1-c3 */\n    tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899));    /* c1+c3 */\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 5 rows from work array, store into output array.\n   * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 5; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z3 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 <<= CONST_BITS;\n    z4 = (INT32) wsptr[4];\n    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */\n    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z2;\n\n    tmp22 = z3 - ((z1 - z2) << 1);               /* c0 = (c4-c8)*2 */\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[6];\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */\n    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */\n    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */\n\n    tmp20 = tmp10 + tmp12;\n    tmp24 = tmp10 - tmp12;\n    tmp21 = tmp11 + tmp13;\n    tmp23 = tmp11 - tmp13;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    z3 <<= CONST_BITS;\n    z4 = (INT32) wsptr[7];\n\n    tmp11 = z2 + z4;\n    tmp13 = z2 - z4;\n\n    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */\n    z4 = z3 + tmp12;\n\n    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */\n    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */\n    z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));\n\n    tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;\n\n    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */\n    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 8;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing an 8x4 output block.\n *\n * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*4];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 4-point IDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n\n    tmp10 = (tmp0 + tmp2) << PASS1_BITS;\n    tmp12 = (tmp0 - tmp2) << PASS1_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);               /* c6 */\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */\n\t\t       CONST_BITS-PASS1_BITS);\n    tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */\n\t\t       CONST_BITS-PASS1_BITS);\n\n    /* Final output stage */\n\n    wsptr[8*0] = (int) (tmp10 + tmp0);\n    wsptr[8*3] = (int) (tmp10 - tmp0);\n    wsptr[8*1] = (int) (tmp12 + tmp2);\n    wsptr[8*2] = (int) (tmp12 - tmp2);\n  }\n\n  /* Pass 2: process rows from work array, store into output array.\n   * Note that we must descale the results by a factor of 8 == 2**3,\n   * and also undo the PASS1_BITS scaling.\n   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 4; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z2 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 = (INT32) wsptr[4];\n\n    tmp0 = (z2 + z3) << CONST_BITS;\n    tmp1 = (z2 - z3) << CONST_BITS;\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[6];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = (INT32) wsptr[7];\n    tmp1 = (INT32) wsptr[5];\n    tmp2 = (INT32) wsptr[3];\n    tmp3 = (INT32) wsptr[1];\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 6x3 output block.\n *\n * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[6*3];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */\n    tmp10 = tmp0 + tmp12;\n    tmp2 = tmp0 - tmp12 - tmp12;\n\n    /* Odd part */\n\n    tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */\n\n    /* Final output stage */\n\n    wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);\n  }\n  \n  /* Pass 2: process 3 rows from work array, store into output array.\n   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 3; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n    tmp2 = (INT32) wsptr[4];\n    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */\n    tmp1 = tmp0 + tmp10;\n    tmp11 = tmp0 - tmp10 - tmp10;\n    tmp10 = (INT32) wsptr[2];\n    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */\n    tmp10 = tmp1 + tmp0;\n    tmp12 = tmp1 - tmp0;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);\n    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);\n    tmp1 = (z1 - z2 - z3) << CONST_BITS;\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 6;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 4x2 output block.\n *\n * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp2, tmp10, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  INT32 * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  INT32 workspace[4*2];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array. */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n\n    /* Odd part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n\n    /* Final output stage */\n\n    wsptr[4*0] = tmp10 + tmp0;\n    wsptr[4*1] = tmp10 - tmp0;\n  }\n\n  /* Pass 2: process 2 rows from work array, store into output array.\n   * 4-point IDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 2; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = wsptr[0] + ((((INT32) RANGE_CENTER) << 3) + (ONE << 2));\n    tmp2 = wsptr[2];\n\n    tmp10 = (tmp0 + tmp2) << CONST_BITS;\n    tmp12 = (tmp0 - tmp2) << CONST_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = wsptr[1];\n    z3 = wsptr[3];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */\n    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 4;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 2x1 output block.\n *\n * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  DCTELEM tmp0, tmp1;\n  ISLOW_MULT_TYPE * quantptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  ISHIFT_TEMPS\n\n  /* Pass 1: empty. */\n\n  /* Pass 2: process 1 row from input, store into output array. */\n\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  outptr = output_buf[0] + output_col;\n\n  /* Even part */\n\n  tmp0 = DEQUANTIZE(coef_block[0], quantptr[0]);\n  /* Add range center and fudge factor for final descale and range-limit. */\n  tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2);\n\n  /* Odd part */\n\n  tmp1 = DEQUANTIZE(coef_block[1], quantptr[1]);\n\n  /* Final output stage */\n\n  outptr[0] = range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];\n  outptr[1] = range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing an 8x16 output block.\n *\n * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[8*16];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp1 = MULTIPLY(z1, FIX(1.306562965));      /* c4[16] = c2[8] */\n    tmp2 = MULTIPLY(z1, FIX_0_541196100);       /* c12[16] = c6[8] */\n\n    tmp10 = tmp0 + tmp1;\n    tmp11 = tmp0 - tmp1;\n    tmp12 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n    z3 = z1 - z2;\n    z4 = MULTIPLY(z3, FIX(0.275899379));        /* c14[16] = c7[8] */\n    z3 = MULTIPLY(z3, FIX(1.387039845));        /* c2[16] = c1[8] */\n\n    tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447);  /* (c6+c2)[16] = (c3+c1)[8] */\n    tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223);  /* (c6-c14)[16] = (c3-c7)[8] */\n    tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */\n    tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */\n\n    tmp20 = tmp10 + tmp0;\n    tmp27 = tmp10 - tmp0;\n    tmp21 = tmp12 + tmp1;\n    tmp26 = tmp12 - tmp1;\n    tmp22 = tmp13 + tmp2;\n    tmp25 = tmp13 - tmp2;\n    tmp23 = tmp11 + tmp3;\n    tmp24 = tmp11 - tmp3;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = z1 + z3;\n\n    tmp1  = MULTIPLY(z1 + z2, FIX(1.353318001));   /* c3 */\n    tmp2  = MULTIPLY(tmp11,   FIX(1.247225013));   /* c5 */\n    tmp3  = MULTIPLY(z1 + z4, FIX(1.093201867));   /* c7 */\n    tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586));   /* c9 */\n    tmp11 = MULTIPLY(tmp11,   FIX(0.666655658));   /* c11 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528));   /* c13 */\n    tmp0  = tmp1 + tmp2 + tmp3 -\n\t    MULTIPLY(z1, FIX(2.286341144));        /* c7+c5+c3-c1 */\n    tmp13 = tmp10 + tmp11 + tmp12 -\n\t    MULTIPLY(z1, FIX(1.835730603));        /* c9+c11+c13-c15 */\n    z1    = MULTIPLY(z2 + z3, FIX(0.138617169));   /* c15 */\n    tmp1  += z1 + MULTIPLY(z2, FIX(0.071888074));  /* c9+c11-c3-c15 */\n    tmp2  += z1 - MULTIPLY(z3, FIX(1.125726048));  /* c5+c7+c15-c3 */\n    z1    = MULTIPLY(z3 - z2, FIX(1.407403738));   /* c1 */\n    tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282));  /* c1+c11-c9-c13 */\n    tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411));  /* c1+c5+c13-c7 */\n    z2    += z4;\n    z1    = MULTIPLY(z2, - FIX(0.666655658));      /* -c11 */\n    tmp1  += z1;\n    tmp3  += z1 + MULTIPLY(z4, FIX(1.065388962));  /* c3+c11+c15-c7 */\n    z2    = MULTIPLY(z2, - FIX(1.247225013));      /* -c5 */\n    tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809));  /* c1+c5+c9-c13 */\n    tmp12 += z2;\n    z2    = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */\n    tmp2  += z2;\n    tmp3  += z2;\n    z2    = MULTIPLY(z4 - z3, FIX(0.410524528));   /* c13 */\n    tmp10 += z2;\n    tmp11 += z2;\n\n    /* Final output stage */\n\n    wsptr[8*0]  = (int) RIGHT_SHIFT(tmp20 + tmp0,  CONST_BITS-PASS1_BITS);\n    wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0,  CONST_BITS-PASS1_BITS);\n    wsptr[8*1]  = (int) RIGHT_SHIFT(tmp21 + tmp1,  CONST_BITS-PASS1_BITS);\n    wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1,  CONST_BITS-PASS1_BITS);\n    wsptr[8*2]  = (int) RIGHT_SHIFT(tmp22 + tmp2,  CONST_BITS-PASS1_BITS);\n    wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2,  CONST_BITS-PASS1_BITS);\n    wsptr[8*3]  = (int) RIGHT_SHIFT(tmp23 + tmp3,  CONST_BITS-PASS1_BITS);\n    wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3,  CONST_BITS-PASS1_BITS);\n    wsptr[8*4]  = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[8*5]  = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[8*6]  = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*9]  = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[8*7]  = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[8*8]  = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process rows from work array, store into output array.\n   * Note that we must descale the results by a factor of 8 == 2**3,\n   * and also undo the PASS1_BITS scaling.\n   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 16; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    z2 = (INT32) wsptr[0] +\n\t   ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t    (ONE << (PASS1_BITS+2)));\n    z3 = (INT32) wsptr[4];\n\n    tmp0 = (z2 + z3) << CONST_BITS;\n    tmp1 = (z2 - z3) << CONST_BITS;\n\n    z2 = (INT32) wsptr[2];\n    z3 = (INT32) wsptr[6];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = (INT32) wsptr[7];\n    tmp1 = (INT32) wsptr[5];\n    tmp2 = (INT32) wsptr[3];\n    tmp3 = (INT32) wsptr[1];\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += DCTSIZE;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 7x14 output block.\n *\n * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[7*14];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z1 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z1 += ONE << (CONST_BITS-PASS1_BITS-1);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z2 = MULTIPLY(z4, FIX(1.274162392));         /* c4 */\n    z3 = MULTIPLY(z4, FIX(0.314692123));         /* c12 */\n    z4 = MULTIPLY(z4, FIX(0.881747734));         /* c8 */\n\n    tmp10 = z1 + z2;\n    tmp11 = z1 + z3;\n    tmp12 = z1 - z4;\n\n    tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */\n\t\t\tCONST_BITS-PASS1_BITS);\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z3 = MULTIPLY(z1 + z2, FIX(1.105676686));    /* c6 */\n\n    tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */\n    tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */\n    tmp15 = MULTIPLY(z1, FIX(0.613604268)) -     /* c10 */\n\t    MULTIPLY(z2, FIX(1.378756276));      /* c2 */\n\n    tmp20 = tmp10 + tmp13;\n    tmp26 = tmp10 - tmp13;\n    tmp21 = tmp11 + tmp14;\n    tmp25 = tmp11 - tmp14;\n    tmp22 = tmp12 + tmp15;\n    tmp24 = tmp12 - tmp15;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n    tmp13 = z4 << CONST_BITS;\n\n    tmp14 = z1 + z3;\n    tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607));           /* c3 */\n    tmp12 = MULTIPLY(tmp14, FIX(1.197448846));             /* c5 */\n    tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */\n    tmp14 = MULTIPLY(tmp14, FIX(0.752406978));             /* c9 */\n    tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426));        /* c9+c11-c13 */\n    z1    -= z2;\n    tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13;        /* c11 */\n    tmp16 += tmp15;\n    z1    += z4;\n    z4    = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */\n    tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948));          /* c3-c9-c13 */\n    tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773));          /* c3+c5-c13 */\n    z4    = MULTIPLY(z3 - z2, FIX(1.405321284));           /* c1 */\n    tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */\n    tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567));          /* c1+c11-c5 */\n\n    tmp13 = (z1 - z3) << PASS1_BITS;\n\n    /* Final output stage */\n\n    wsptr[7*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[7*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[7*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[7*3]  = (int) (tmp23 + tmp13);\n    wsptr[7*10] = (int) (tmp23 - tmp13);\n    wsptr[7*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[7*9]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[7*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[7*8]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[7*6]  = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);\n    wsptr[7*7]  = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 14 rows from work array, store into output array.\n   * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 14; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp23 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp23 <<= CONST_BITS;\n\n    z1 = (INT32) wsptr[2];\n    z2 = (INT32) wsptr[4];\n    z3 = (INT32) wsptr[6];\n\n    tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734));       /* c4 */\n    tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123));       /* c6 */\n    tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */\n    tmp10 = z1 + z3;\n    z2 -= tmp10;\n    tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */\n    tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536));   /* c2-c4-c6 */\n    tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249));   /* c2+c4+c6 */\n    tmp23 += MULTIPLY(z2, FIX(1.414213562));           /* c0 */\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n\n    tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347));       /* (c3+c1-c5)/2 */\n    tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339));       /* (c3+c5-c1)/2 */\n    tmp10 = tmp11 - tmp12;\n    tmp11 += tmp12;\n    tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276));     /* -c1 */\n    tmp11 += tmp12;\n    z2 = MULTIPLY(z1 + z3, FIX(0.613604268));          /* c5 */\n    tmp10 += z2;\n    tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693));      /* c3+c1-c5 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 7;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 6x12 output block.\n *\n * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;\n  INT32 z1, z2, z3, z4;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[6*12];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z3 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */\n\n    tmp10 = z3 + z4;\n    tmp11 = z3 - z4;\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */\n    z1 <<= CONST_BITS;\n    z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n    z2 <<= CONST_BITS;\n\n    tmp12 = z1 - z2;\n\n    tmp21 = z3 + tmp12;\n    tmp24 = z3 - tmp12;\n\n    tmp12 = z4 + z2;\n\n    tmp20 = tmp10 + tmp12;\n    tmp25 = tmp10 - tmp12;\n\n    tmp12 = z4 - z1 - z2;\n\n    tmp22 = tmp11 + tmp12;\n    tmp23 = tmp11 - tmp12;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = MULTIPLY(z2, FIX(1.306562965));                  /* c3 */\n    tmp14 = MULTIPLY(z2, - FIX_0_541196100);                 /* -c9 */\n\n    tmp10 = z1 + z3;\n    tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669));          /* c7 */\n    tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384));       /* c5-c7 */\n    tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716));  /* c1-c5 */\n    tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580));           /* -(c7+c11) */\n    tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */\n    tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */\n    tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) -        /* c7-c11 */\n\t     MULTIPLY(z4, FIX(1.982889723));                 /* c5+c7 */\n\n    z1 -= z4;\n    z2 -= z3;\n    z3 = MULTIPLY(z1 + z2, FIX_0_541196100);                 /* c9 */\n    tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865);              /* c3-c9 */\n    tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065);              /* c3+c9 */\n\n    /* Final output stage */\n\n    wsptr[6*0]  = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[6*1]  = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[6*2]  = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[6*9]  = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);\n    wsptr[6*3]  = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[6*8]  = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[6*4]  = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[6*7]  = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[6*5]  = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);\n    wsptr[6*6]  = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 12 rows from work array, store into output array.\n   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 12; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp10 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp10 <<= CONST_BITS;\n    tmp12 = (INT32) wsptr[4];\n    tmp20 = MULTIPLY(tmp12, FIX(0.707106781));   /* c4 */\n    tmp11 = tmp10 + tmp20;\n    tmp21 = tmp10 - tmp20 - tmp20;\n    tmp20 = (INT32) wsptr[2];\n    tmp10 = MULTIPLY(tmp20, FIX(1.224744871));   /* c2 */\n    tmp20 = tmp11 + tmp10;\n    tmp22 = tmp11 - tmp10;\n\n    /* Odd part */\n\n    z1 = (INT32) wsptr[1];\n    z2 = (INT32) wsptr[3];\n    z3 = (INT32) wsptr[5];\n    tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);\n    tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);\n    tmp11 = (z1 - z2 - z3) << CONST_BITS;\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 6;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 5x10 output block.\n *\n * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\tJCOEFPTR coef_block,\n\t\tJSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp10, tmp11, tmp12, tmp13, tmp14;\n  INT32 tmp20, tmp21, tmp22, tmp23, tmp24;\n  INT32 z1, z2, z3, z4, z5;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[5*10];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z3 += ONE << (CONST_BITS-PASS1_BITS-1);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z1 = MULTIPLY(z4, FIX(1.144122806));         /* c4 */\n    z2 = MULTIPLY(z4, FIX(0.437016024));         /* c8 */\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z2;\n\n    tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1),   /* c0 = (c4-c8)*2 */\n\t\t\tCONST_BITS-PASS1_BITS);\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));    /* c6 */\n    tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */\n    tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */\n\n    tmp20 = tmp10 + tmp12;\n    tmp24 = tmp10 - tmp12;\n    tmp21 = tmp11 + tmp13;\n    tmp23 = tmp11 - tmp13;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n\n    tmp11 = z2 + z4;\n    tmp13 = z2 - z4;\n\n    tmp12 = MULTIPLY(tmp13, FIX(0.309016994));        /* (c3-c7)/2 */\n    z5 = z3 << CONST_BITS;\n\n    z2 = MULTIPLY(tmp11, FIX(0.951056516));           /* (c3+c7)/2 */\n    z4 = z5 + tmp12;\n\n    tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */\n    tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */\n\n    z2 = MULTIPLY(tmp11, FIX(0.587785252));           /* (c1-c9)/2 */\n    z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));\n\n    tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;\n\n    tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */\n    tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */\n\n    /* Final output stage */\n\n    wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);\n    wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);\n    wsptr[5*2] = (int) (tmp22 + tmp12);\n    wsptr[5*7] = (int) (tmp22 - tmp12);\n    wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);\n    wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);\n    wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 10 rows from work array, store into output array.\n   * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 10; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp12 = (INT32) wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t       (ONE << (PASS1_BITS+2)));\n    tmp12 <<= CONST_BITS;\n    tmp13 = (INT32) wsptr[2];\n    tmp14 = (INT32) wsptr[4];\n    z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */\n    z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */\n    z3 = tmp12 + z2;\n    tmp10 = z3 + z1;\n    tmp11 = z3 - z1;\n    tmp12 -= z2 << 2;\n\n    /* Odd part */\n\n    z2 = (INT32) wsptr[1];\n    z3 = (INT32) wsptr[3];\n\n    z1 = MULTIPLY(z2 + z3, FIX(0.831253876));       /* c3 */\n    tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148));    /* c1-c3 */\n    tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899));    /* c1+c3 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 5;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 4x8 output block.\n *\n * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp3;\n  INT32 tmp10, tmp11, tmp12, tmp13;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[4*8];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * Note results are scaled up by sqrt(8) compared to a true IDCT;\n   * furthermore, we scale the results by 2**PASS1_BITS.\n   * 8-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 4; ctr > 0; ctr--) {\n    /* Due to quantization, we will usually find that many of the input\n     * coefficients are zero, especially the AC terms.  We can exploit this\n     * by short-circuiting the IDCT calculation for any column in which all\n     * the AC terms are zero.  In that case each output is equal to the\n     * DC coefficient (with scale factor as needed).\n     * With typical images and quantization tables, half or more of the\n     * column DCT calculations can be simplified this way.\n     */\n\n    if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&\n\tinptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&\n\tinptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&\n\tinptr[DCTSIZE*7] == 0) {\n      /* AC terms all zero */\n      int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;\n\n      wsptr[4*0] = dcval;\n      wsptr[4*1] = dcval;\n      wsptr[4*2] = dcval;\n      wsptr[4*3] = dcval;\n      wsptr[4*4] = dcval;\n      wsptr[4*5] = dcval;\n      wsptr[4*6] = dcval;\n      wsptr[4*7] = dcval;\n\n      inptr++;\t\t\t/* advance pointers to next column */\n      quantptr++;\n      wsptr++;\n      continue;\n    }\n\n    /* Even part: reverse the even part of the forward DCT.\n     * The rotator is c(-6).\n     */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    z2 <<= CONST_BITS;\n    z3 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    z2 += ONE << (CONST_BITS-PASS1_BITS-1);\n\n    tmp0 = z2 + z3;\n    tmp1 = z2 - z3;\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */\n    tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */\n    tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */\n\n    tmp10 = tmp0 + tmp2;\n    tmp13 = tmp0 - tmp2;\n    tmp11 = tmp1 + tmp3;\n    tmp12 = tmp1 - tmp3;\n\n    /* Odd part per figure 8; the matrix is unitary and hence its\n     * transpose is its inverse.  i0..i3 are y7,y5,y3,y1 respectively.\n     */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);\n    tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n\n    z2 = tmp0 + tmp2;\n    z3 = tmp1 + tmp3;\n\n    z1 = MULTIPLY(z2 + z3, FIX_1_175875602);       /*  c3 */\n    z2 = MULTIPLY(z2, - FIX_1_961570560);          /* -c3-c5 */\n    z3 = MULTIPLY(z3, - FIX_0_390180644);          /* -c3+c5 */\n    z2 += z1;\n    z3 += z1;\n\n    z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* -c3+c7 */\n    tmp0 = MULTIPLY(tmp0, FIX_0_298631336);        /* -c1+c3+c5-c7 */\n    tmp3 = MULTIPLY(tmp3, FIX_1_501321110);        /*  c1+c3-c5-c7 */\n    tmp0 += z1 + z2;\n    tmp3 += z1 + z3;\n\n    z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* -c1-c3 */\n    tmp1 = MULTIPLY(tmp1, FIX_2_053119869);        /*  c1+c3-c5+c7 */\n    tmp2 = MULTIPLY(tmp2, FIX_3_072711026);        /*  c1+c3+c5-c7 */\n    tmp1 += z1 + z3;\n    tmp2 += z1 + z2;\n\n    /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */\n\n    wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);\n    wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);\n    wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);\n\n    inptr++;\t\t\t/* advance pointers to next column */\n    quantptr++;\n    wsptr++;\n  }\n\n  /* Pass 2: process 8 rows from work array, store into output array.\n   * 4-point IDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 8; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp2 = (INT32) wsptr[2];\n\n    tmp10 = (tmp0 + tmp2) << CONST_BITS;\n    tmp12 = (tmp0 - tmp2) << CONST_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = (INT32) wsptr[1];\n    z3 = (INT32) wsptr[3];\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */\n    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 4;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 3x6 output block.\n *\n * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  int * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  int workspace[3*6];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp0 <<= CONST_BITS;\n    /* Add fudge factor here for final descale. */\n    tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);\n    tmp10 = MULTIPLY(tmp2, FIX(0.707106781));   /* c4 */\n    tmp1 = tmp0 + tmp10;\n    tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);\n    tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n    tmp0 = MULTIPLY(tmp10, FIX(1.224744871));   /* c2 */\n    tmp10 = tmp1 + tmp0;\n    tmp12 = tmp1 - tmp0;\n\n    /* Odd part */\n\n    z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);\n    tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */\n    tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);\n    tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);\n    tmp1 = (z1 - z2 - z3) << PASS1_BITS;\n\n    /* Final output stage */\n\n    wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);\n    wsptr[3*1] = (int) (tmp11 + tmp1);\n    wsptr[3*4] = (int) (tmp11 - tmp1);\n    wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);\n    wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);\n  }\n\n  /* Pass 2: process 6 rows from work array, store into output array.\n   * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).\n   */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 6; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp0 = (INT32) wsptr[0] +\n\t     ((((INT32) RANGE_CENTER) << (PASS1_BITS+3)) +\n\t      (ONE << (PASS1_BITS+2)));\n    tmp0 <<= CONST_BITS;\n    tmp2 = (INT32) wsptr[2];\n    tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */\n    tmp10 = tmp0 + tmp12;\n    tmp2 = tmp0 - tmp12 - tmp12;\n\n    /* Odd part */\n\n    tmp12 = (INT32) wsptr[1];\n    tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,\n\t\t\t\t\t      CONST_BITS+PASS1_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 3;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 2x4 output block.\n *\n * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  INT32 tmp0, tmp2, tmp10, tmp12;\n  INT32 z1, z2, z3;\n  JCOEFPTR inptr;\n  ISLOW_MULT_TYPE * quantptr;\n  INT32 * wsptr;\n  JSAMPROW outptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  int ctr;\n  INT32 workspace[2*4];\t/* buffers data between passes */\n  SHIFT_TEMPS\n\n  /* Pass 1: process columns from input, store into work array.\n   * 4-point IDCT kernel,\n   * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].\n   */\n\n  inptr = coef_block;\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n  wsptr = workspace;\n  for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) {\n    /* Even part */\n\n    tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);\n    tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);\n\n    tmp10 = (tmp0 + tmp2) << CONST_BITS;\n    tmp12 = (tmp0 - tmp2) << CONST_BITS;\n\n    /* Odd part */\n    /* Same rotation as in the even part of the 8x8 LL&M IDCT */\n\n    z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);\n    z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);\n\n    z1 = MULTIPLY(z2 + z3, FIX_0_541196100);   /* c6 */\n    tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */\n    tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */\n\n    /* Final output stage */\n\n    wsptr[2*0] = tmp10 + tmp0;\n    wsptr[2*3] = tmp10 - tmp0;\n    wsptr[2*1] = tmp12 + tmp2;\n    wsptr[2*2] = tmp12 - tmp2;\n  }\n\n  /* Pass 2: process 4 rows from work array, store into output array. */\n\n  wsptr = workspace;\n  for (ctr = 0; ctr < 4; ctr++) {\n    outptr = output_buf[ctr] + output_col;\n\n    /* Even part */\n\n    /* Add range center and fudge factor for final descale and range-limit. */\n    tmp10 = wsptr[0] +\n\t      ((((INT32) RANGE_CENTER) << (CONST_BITS+3)) +\n\t       (ONE << (CONST_BITS+2)));\n\n    /* Odd part */\n\n    tmp0 = wsptr[1];\n\n    /* Final output stage */\n\n    outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n    outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3)\n\t\t\t    & RANGE_MASK];\n\n    wsptr += 2;\t\t/* advance pointer to next row */\n  }\n}\n\n\n/*\n * Perform dequantization and inverse DCT on one block of coefficients,\n * producing a 1x2 output block.\n *\n * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows).\n */\n\nGLOBAL(void)\njpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t       JCOEFPTR coef_block,\n\t       JSAMPARRAY output_buf, JDIMENSION output_col)\n{\n  DCTELEM tmp0, tmp1;\n  ISLOW_MULT_TYPE * quantptr;\n  JSAMPLE *range_limit = IDCT_range_limit(cinfo);\n  ISHIFT_TEMPS\n\n  /* Process 1 column from input, store into output array. */\n\n  quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;\n\n  /* Even part */\n\n  tmp0 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);\n  /* Add range center and fudge factor for final descale and range-limit. */\n  tmp0 += (((DCTELEM) RANGE_CENTER) << 3) + (1 << 2);\n\n  /* Odd part */\n\n  tmp1 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);\n\n  /* Final output stage */\n\n  output_buf[0][output_col] =\n    range_limit[(int) IRIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];\n  output_buf[1][output_col] =\n    range_limit[(int) IRIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];\n}\n\n#endif /* IDCT_SCALING_SUPPORTED */\n#endif /* DCT_ISLOW_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jinclude.h",
    "content": "/*\n * jinclude.h\n *\n * Copyright (C) 1991-1994, Thomas G. Lane.\n * Modified 2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file exists to provide a single place to fix any problems with\n * including the wrong system include files.  (Common problems are taken\n * care of by the standard jconfig symbols, but on really weird systems\n * you may have to edit this file.)\n *\n * NOTE: this file is NOT intended to be included by applications using the\n * JPEG library.  Most applications need only include jpeglib.h.\n */\n\n\n/* Include auto-config file to find out which system include files we need. */\n\n#include \"jconfig.h\"\t\t/* auto configuration options */\n#define JCONFIG_INCLUDED\t/* so that jpeglib.h doesn't do it again */\n\n/*\n * We need the NULL macro and size_t typedef.\n * On an ANSI-conforming system it is sufficient to include <stddef.h>.\n * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to\n * pull in <sys/types.h> as well.\n * Note that the core JPEG library does not require <stdio.h>;\n * only the default error handler and data source/destination modules do.\n * But we must pull it in because of the references to FILE in jpeglib.h.\n * You can remove those references if you want to compile without <stdio.h>.\n */\n\n#ifdef HAVE_STDDEF_H\n#include <stddef.h>\n#endif\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#ifdef NEED_SYS_TYPES_H\n#include <sys/types.h>\n#endif\n\n#include <stdio.h>\n\n/*\n * We need memory copying and zeroing functions, plus strncpy().\n * ANSI and System V implementations declare these in <string.h>.\n * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().\n * Some systems may declare memset and memcpy in <memory.h>.\n *\n * NOTE: we assume the size parameters to these functions are of type size_t.\n * Change the casts in these macros if not!\n */\n\n#ifdef NEED_BSD_STRINGS\n\n#include <strings.h>\n#define MEMZERO(target,size)\tbzero((void *)(target), (size_t)(size))\n#define MEMCOPY(dest,src,size)\tbcopy((const void *)(src), (void *)(dest), (size_t)(size))\n\n#else /* not BSD, assume ANSI/SysV string lib */\n\n#include <string.h>\n#define MEMZERO(target,size)\tmemset((void *)(target), 0, (size_t)(size))\n#define MEMCOPY(dest,src,size)\tmemcpy((void *)(dest), (const void *)(src), (size_t)(size))\n\n#endif\n\n/*\n * In ANSI C, and indeed any rational implementation, size_t is also the\n * type returned by sizeof().  However, it seems there are some irrational\n * implementations out there, in which sizeof() returns an int even though\n * size_t is defined as long or unsigned long.  To ensure consistent results\n * we always use this SIZEOF() macro in place of using sizeof() directly.\n */\n\n#define SIZEOF(object)\t((size_t) sizeof(object))\n\n/*\n * The modules that use fread() and fwrite() always invoke them through\n * these macros.  On some systems you may need to twiddle the argument casts.\n * CAUTION: argument order is different from underlying functions!\n *\n * Furthermore, macros are provided for fflush() and ferror() in order\n * to facilitate adaption by applications using an own FILE class.\n */\n\n#define JFREAD(file,buf,sizeofbuf)  \\\n  ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))\n#define JFWRITE(file,buf,sizeofbuf)  \\\n  ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))\n#define JFFLUSH(file)\tfflush(file)\n#define JFERROR(file)\tferror(file)\n"
  },
  {
    "path": "dlib/external/libjpeg/jmemansi.c",
    "content": "/*\n * jmemansi.c\n *\n * Copyright (C) 1992-1996, Thomas G. Lane.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file provides a simple generic implementation of the system-\n * dependent portion of the JPEG memory manager.  This implementation\n * assumes that you have the ANSI-standard library routine tmpfile().\n * Also, the problem of determining the amount of memory available\n * is shoved onto the user.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jmemsys.h\"\t\t/* import the system-dependent declarations */\n\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare malloc(),free() */\nextern void * malloc JPP((size_t size));\nextern void free JPP((void *ptr));\n#endif\n\n#ifndef SEEK_SET\t\t/* pre-ANSI systems may not define this; */\n#define SEEK_SET  0\t\t/* if not, assume 0 is correct */\n#endif\n\n\n/*\n * Memory allocation and freeing are controlled by the regular library\n * routines malloc() and free().\n */\n\nGLOBAL(void *)\njpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * \"Large\" objects are treated the same as \"small\" ones.\n * NB: although we include FAR keywords in the routine declarations,\n * this file won't actually work in 80x86 small/medium model; at least,\n * you probably won't be able to process useful-size images in only 64KB.\n */\n\nGLOBAL(void FAR *)\njpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void FAR *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * This routine computes the total memory space available for allocation.\n * It's impossible to do this in a portable way; our current solution is\n * to make the user tell us (with a default value set at compile time).\n * If you can actually get the available space, it's a good idea to subtract\n * a slop factor of 5% or so.\n */\n\n#ifndef DEFAULT_MAX_MEM\t\t/* so can override from makefile */\n#define DEFAULT_MAX_MEM\t\t1000000L /* default: one megabyte */\n#endif\n\nGLOBAL(long)\njpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,\n\t\t    long max_bytes_needed, long already_allocated)\n{\n  return cinfo->mem->max_memory_to_use - already_allocated;\n}\n\n\n/*\n * Backing store (temporary file) management.\n * Backing store objects are only used when the value returned by\n * jpeg_mem_available is less than the total space needed.  You can dispense\n * with these routines if you have plenty of virtual memory; see jmemnobs.c.\n */\n\n\nMETHODDEF(void)\nread_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t    void FAR * buffer_address,\n\t\t    long file_offset, long byte_count)\n{\n  if (fseek(info->temp_file, file_offset, SEEK_SET))\n    ERREXIT(cinfo, JERR_TFILE_SEEK);\n  if (JFREAD(info->temp_file, buffer_address, byte_count)\n      != (size_t) byte_count)\n    ERREXIT(cinfo, JERR_TFILE_READ);\n}\n\n\nMETHODDEF(void)\nwrite_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t     void FAR * buffer_address,\n\t\t     long file_offset, long byte_count)\n{\n  if (fseek(info->temp_file, file_offset, SEEK_SET))\n    ERREXIT(cinfo, JERR_TFILE_SEEK);\n  if (JFWRITE(info->temp_file, buffer_address, byte_count)\n      != (size_t) byte_count)\n    ERREXIT(cinfo, JERR_TFILE_WRITE);\n}\n\n\nMETHODDEF(void)\nclose_backing_store (j_common_ptr cinfo, backing_store_ptr info)\n{\n  fclose(info->temp_file);\n  /* Since this implementation uses tmpfile() to create the file,\n   * no explicit file deletion is needed.\n   */\n}\n\n\n/*\n * Initial opening of a backing-store object.\n *\n * This version uses tmpfile(), which constructs a suitable file name\n * behind the scenes.  We don't have to use info->temp_name[] at all;\n * indeed, we can't even find out the actual name of the temp file.\n */\n\nGLOBAL(void)\njpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t\t long total_bytes_needed)\n{\n  if ((info->temp_file = tmpfile()) == NULL)\n    ERREXITS(cinfo, JERR_TFILE_CREATE, \"\");\n  info->read_backing_store = read_backing_store;\n  info->write_backing_store = write_backing_store;\n  info->close_backing_store = close_backing_store;\n}\n\n\n/*\n * These routines take care of any system-dependent initialization and\n * cleanup required.\n */\n\nGLOBAL(long)\njpeg_mem_init (j_common_ptr cinfo)\n{\n  return DEFAULT_MAX_MEM;\t/* default for max_memory_to_use */\n}\n\nGLOBAL(void)\njpeg_mem_term (j_common_ptr cinfo)\n{\n  /* no work */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jmemmgr.c",
    "content": "/*\n * jmemmgr.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2011-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains the JPEG system-independent memory management\n * routines.  This code is usable across a wide variety of machines; most\n * of the system dependencies have been isolated in a separate file.\n * The major functions provided here are:\n *   * pool-based allocation and freeing of memory;\n *   * policy decisions about how to divide available memory among the\n *     virtual arrays;\n *   * control logic for swapping virtual arrays between main memory and\n *     backing storage.\n * The separate system-dependent file provides the actual backing-storage\n * access code, and it contains the policy decision about how much total\n * main memory to use.\n * This file is system-dependent in the sense that some of its functions\n * are unnecessary in some systems.  For example, if there is enough virtual\n * memory so that backing storage will never be used, much of the virtual\n * array control logic could be removed.  (Of course, if you have that much\n * memory then you shouldn't care about a little bit of unused code...)\n */\n\n#define JPEG_INTERNALS\n#define AM_MEMORY_MANAGER\t/* we define jvirt_Xarray_control structs */\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jmemsys.h\"\t\t/* import the system-dependent declarations */\n\n#ifndef NO_GETENV\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare getenv() */\nextern char * getenv JPP((const char * name));\n#endif\n#endif\n\n\n/*\n * Some important notes:\n *   The allocation routines provided here must never return NULL.\n *   They should exit to error_exit if unsuccessful.\n *\n *   It's not a good idea to try to merge the sarray and barray routines,\n *   even though they are textually almost the same, because samples are\n *   usually stored as bytes while coefficients are shorts or ints.  Thus,\n *   in machines where byte pointers have a different representation from\n *   word pointers, the resulting machine code could not be the same.\n */\n\n\n/*\n * Many machines require storage alignment: longs must start on 4-byte\n * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()\n * always returns pointers that are multiples of the worst-case alignment\n * requirement, and we had better do so too.\n * There isn't any really portable way to determine the worst-case alignment\n * requirement.  This module assumes that the alignment requirement is\n * multiples of sizeof(ALIGN_TYPE).\n * By default, we define ALIGN_TYPE as double.  This is necessary on some\n * workstations (where doubles really do need 8-byte alignment) and will work\n * fine on nearly everything.  If your machine has lesser alignment needs,\n * you can save a few bytes by making ALIGN_TYPE smaller.\n * The only place I know of where this will NOT work is certain Macintosh\n * 680x0 compilers that define double as a 10-byte IEEE extended float.\n * Doing 10-byte alignment is counterproductive because longwords won't be\n * aligned well.  Put \"#define ALIGN_TYPE long\" in jconfig.h if you have\n * such a compiler.\n */\n\n#ifndef ALIGN_TYPE\t\t/* so can override from jconfig.h */\n#define ALIGN_TYPE  double\n#endif\n\n\n/*\n * We allocate objects from \"pools\", where each pool is gotten with a single\n * request to jpeg_get_small() or jpeg_get_large().  There is no per-object\n * overhead within a pool, except for alignment padding.  Each pool has a\n * header with a link to the next pool of the same class.\n * Small and large pool headers are identical except that the latter's\n * link pointer must be FAR on 80x86 machines.\n * Notice that the \"real\" header fields are union'ed with a dummy ALIGN_TYPE\n * field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple\n * of the alignment requirement of ALIGN_TYPE.\n */\n\ntypedef union small_pool_struct * small_pool_ptr;\n\ntypedef union small_pool_struct {\n  struct {\n    small_pool_ptr next;\t/* next in list of pools */\n    size_t bytes_used;\t\t/* how many bytes already used within pool */\n    size_t bytes_left;\t\t/* bytes still available in this pool */\n  } hdr;\n  ALIGN_TYPE dummy;\t\t/* included in union to ensure alignment */\n} small_pool_hdr;\n\ntypedef union large_pool_struct FAR * large_pool_ptr;\n\ntypedef union large_pool_struct {\n  struct {\n    large_pool_ptr next;\t/* next in list of pools */\n    size_t bytes_used;\t\t/* how many bytes already used within pool */\n    size_t bytes_left;\t\t/* bytes still available in this pool */\n  } hdr;\n  ALIGN_TYPE dummy;\t\t/* included in union to ensure alignment */\n} large_pool_hdr;\n\n\n/*\n * Here is the full definition of a memory manager object.\n */\n\ntypedef struct {\n  struct jpeg_memory_mgr pub;\t/* public fields */\n\n  /* Each pool identifier (lifetime class) names a linked list of pools. */\n  small_pool_ptr small_list[JPOOL_NUMPOOLS];\n  large_pool_ptr large_list[JPOOL_NUMPOOLS];\n\n  /* Since we only have one lifetime class of virtual arrays, only one\n   * linked list is necessary (for each datatype).  Note that the virtual\n   * array control blocks being linked together are actually stored somewhere\n   * in the small-pool list.\n   */\n  jvirt_sarray_ptr virt_sarray_list;\n  jvirt_barray_ptr virt_barray_list;\n\n  /* This counts total space obtained from jpeg_get_small/large */\n  size_t total_space_allocated;\n\n  /* alloc_sarray and alloc_barray set this value for use by virtual\n   * array routines.\n   */\n  JDIMENSION last_rowsperchunk;\t/* from most recent alloc_sarray/barray */\n} my_memory_mgr;\n\ntypedef my_memory_mgr * my_mem_ptr;\n\n\n/*\n * The control blocks for virtual arrays.\n * Note that these blocks are allocated in the \"small\" pool area.\n * System-dependent info for the associated backing store (if any) is hidden\n * inside the backing_store_info struct.\n */\n\nstruct jvirt_sarray_control {\n  JSAMPARRAY mem_buffer;\t/* => the in-memory buffer */\n  JDIMENSION rows_in_array;\t/* total virtual array height */\n  JDIMENSION samplesperrow;\t/* width of array (and of memory buffer) */\n  JDIMENSION maxaccess;\t\t/* max rows accessed by access_virt_sarray */\n  JDIMENSION rows_in_mem;\t/* height of memory buffer */\n  JDIMENSION rowsperchunk;\t/* allocation chunk size in mem_buffer */\n  JDIMENSION cur_start_row;\t/* first logical row # in the buffer */\n  JDIMENSION first_undef_row;\t/* row # of first uninitialized row */\n  boolean pre_zero;\t\t/* pre-zero mode requested? */\n  boolean dirty;\t\t/* do current buffer contents need written? */\n  boolean b_s_open;\t\t/* is backing-store data valid? */\n  jvirt_sarray_ptr next;\t/* link to next virtual sarray control block */\n  backing_store_info b_s_info;\t/* System-dependent control info */\n};\n\nstruct jvirt_barray_control {\n  JBLOCKARRAY mem_buffer;\t/* => the in-memory buffer */\n  JDIMENSION rows_in_array;\t/* total virtual array height */\n  JDIMENSION blocksperrow;\t/* width of array (and of memory buffer) */\n  JDIMENSION maxaccess;\t\t/* max rows accessed by access_virt_barray */\n  JDIMENSION rows_in_mem;\t/* height of memory buffer */\n  JDIMENSION rowsperchunk;\t/* allocation chunk size in mem_buffer */\n  JDIMENSION cur_start_row;\t/* first logical row # in the buffer */\n  JDIMENSION first_undef_row;\t/* row # of first uninitialized row */\n  boolean pre_zero;\t\t/* pre-zero mode requested? */\n  boolean dirty;\t\t/* do current buffer contents need written? */\n  boolean b_s_open;\t\t/* is backing-store data valid? */\n  jvirt_barray_ptr next;\t/* link to next virtual barray control block */\n  backing_store_info b_s_info;\t/* System-dependent control info */\n};\n\n\n#ifdef MEM_STATS\t\t/* optional extra stuff for statistics */\n\nLOCAL(void)\nprint_mem_stats (j_common_ptr cinfo, int pool_id)\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  small_pool_ptr shdr_ptr;\n  large_pool_ptr lhdr_ptr;\n\n  /* Since this is only a debugging stub, we can cheat a little by using\n   * fprintf directly rather than going through the trace message code.\n   * This is helpful because message parm array can't handle longs.\n   */\n  fprintf(stderr, \"Freeing pool %d, total space = %ld\\n\",\n\t  pool_id, (long) mem->total_space_allocated);\n\n  for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;\n       lhdr_ptr = lhdr_ptr->hdr.next) {\n    fprintf(stderr, \"  Large chunk used %ld\\n\",\n\t    (long) lhdr_ptr->hdr.bytes_used);\n  }\n\n  for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;\n       shdr_ptr = shdr_ptr->hdr.next) {\n    fprintf(stderr, \"  Small chunk used %ld free %ld\\n\",\n\t    (long) shdr_ptr->hdr.bytes_used,\n\t    (long) shdr_ptr->hdr.bytes_left);\n  }\n}\n\n#endif /* MEM_STATS */\n\n\nLOCAL(noreturn_t)\nout_of_memory (j_common_ptr cinfo, int which)\n/* Report an out-of-memory error and stop execution */\n/* If we compiled MEM_STATS support, report alloc requests before dying */\n{\n#ifdef MEM_STATS\n  cinfo->err->trace_level = 2;\t/* force self_destruct to report stats */\n#endif\n  ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);\n}\n\n\n/*\n * Allocation of \"small\" objects.\n *\n * For these, we use pooled storage.  When a new pool must be created,\n * we try to get enough space for the current request plus a \"slop\" factor,\n * where the slop will be the amount of leftover space in the new pool.\n * The speed vs. space tradeoff is largely determined by the slop values.\n * A different slop value is provided for each pool class (lifetime),\n * and we also distinguish the first pool of a class from later ones.\n * NOTE: the values given work fairly well on both 16- and 32-bit-int\n * machines, but may be too small if longs are 64 bits or more.\n */\n\nstatic const size_t first_pool_slop[JPOOL_NUMPOOLS] = \n{\n\t1600,\t\t\t/* first PERMANENT pool */\n\t16000\t\t\t/* first IMAGE pool */\n};\n\nstatic const size_t extra_pool_slop[JPOOL_NUMPOOLS] = \n{\n\t0,\t\t\t/* additional PERMANENT pools */\n\t5000\t\t\t/* additional IMAGE pools */\n};\n\n#define MIN_SLOP  50\t\t/* greater than 0 to avoid futile looping */\n\n\nMETHODDEF(void *)\nalloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)\n/* Allocate a \"small\" object */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  small_pool_ptr hdr_ptr, prev_hdr_ptr;\n  size_t odd_bytes, min_request, slop;\n  char * data_ptr;\n\n  /* Check for unsatisfiable request (do now to ensure no overflow below) */\n  if (sizeofobject > (size_t) MAX_ALLOC_CHUNK - SIZEOF(small_pool_hdr))\n    out_of_memory(cinfo, 1);\t/* request exceeds malloc's ability */\n\n  /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */\n  odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);\n  if (odd_bytes > 0)\n    sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;\n\n  /* See if space is available in any existing pool */\n  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\n    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);\t/* safety check */\n  prev_hdr_ptr = NULL;\n  hdr_ptr = mem->small_list[pool_id];\n  while (hdr_ptr != NULL) {\n    if (hdr_ptr->hdr.bytes_left >= sizeofobject)\n      break;\t\t\t/* found pool with enough space */\n    prev_hdr_ptr = hdr_ptr;\n    hdr_ptr = hdr_ptr->hdr.next;\n  }\n\n  /* Time to make a new pool? */\n  if (hdr_ptr == NULL) {\n    /* min_request is what we need now, slop is what will be leftover */\n    min_request = sizeofobject + SIZEOF(small_pool_hdr);\n    if (prev_hdr_ptr == NULL)\t/* first pool in class? */\n      slop = first_pool_slop[pool_id];\n    else\n      slop = extra_pool_slop[pool_id];\n    /* Don't ask for more than MAX_ALLOC_CHUNK */\n    if (slop > (size_t) MAX_ALLOC_CHUNK - min_request)\n      slop = (size_t) MAX_ALLOC_CHUNK - min_request;\n    /* Try to get space, if fail reduce slop and try again */\n    for (;;) {\n      hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);\n      if (hdr_ptr != NULL)\n\tbreak;\n      slop /= 2;\n      if (slop < MIN_SLOP)\t/* give up when it gets real small */\n\tout_of_memory(cinfo, 2); /* jpeg_get_small failed */\n    }\n    mem->total_space_allocated += min_request + slop;\n    /* Success, initialize the new pool header and add to end of list */\n    hdr_ptr->hdr.next = NULL;\n    hdr_ptr->hdr.bytes_used = 0;\n    hdr_ptr->hdr.bytes_left = sizeofobject + slop;\n    if (prev_hdr_ptr == NULL)\t/* first pool in class? */\n      mem->small_list[pool_id] = hdr_ptr;\n    else\n      prev_hdr_ptr->hdr.next = hdr_ptr;\n  }\n\n  /* OK, allocate the object from the current pool */\n  data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */\n  data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */\n  hdr_ptr->hdr.bytes_used += sizeofobject;\n  hdr_ptr->hdr.bytes_left -= sizeofobject;\n\n  return (void *) data_ptr;\n}\n\n\n/*\n * Allocation of \"large\" objects.\n *\n * The external semantics of these are the same as \"small\" objects,\n * except that FAR pointers are used on 80x86.  However the pool\n * management heuristics are quite different.  We assume that each\n * request is large enough that it may as well be passed directly to\n * jpeg_get_large; the pool management just links everything together\n * so that we can free it all on demand.\n * Note: the major use of \"large\" objects is in JSAMPARRAY and JBLOCKARRAY\n * structures.  The routines that create these structures (see below)\n * deliberately bunch rows together to ensure a large request size.\n */\n\nMETHODDEF(void FAR *)\nalloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)\n/* Allocate a \"large\" object */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  large_pool_ptr hdr_ptr;\n  size_t odd_bytes;\n\n  /* Check for unsatisfiable request (do now to ensure no overflow below) */\n  if (sizeofobject > (size_t) MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr))\n    out_of_memory(cinfo, 3);\t/* request exceeds malloc's ability */\n\n  /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */\n  odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);\n  if (odd_bytes > 0)\n    sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;\n\n  /* Always make a new pool */\n  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\n    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);\t/* safety check */\n\n  hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +\n\t\t\t\t\t    SIZEOF(large_pool_hdr));\n  if (hdr_ptr == NULL)\n    out_of_memory(cinfo, 4);\t/* jpeg_get_large failed */\n  mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);\n\n  /* Success, initialize the new pool header and add to list */\n  hdr_ptr->hdr.next = mem->large_list[pool_id];\n  /* We maintain space counts in each pool header for statistical purposes,\n   * even though they are not needed for allocation.\n   */\n  hdr_ptr->hdr.bytes_used = sizeofobject;\n  hdr_ptr->hdr.bytes_left = 0;\n  mem->large_list[pool_id] = hdr_ptr;\n\n  return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */\n}\n\n\n/*\n * Creation of 2-D sample arrays.\n * The pointers are in near heap, the samples themselves in FAR heap.\n *\n * To minimize allocation overhead and to allow I/O of large contiguous\n * blocks, we allocate the sample rows in groups of as many rows as possible\n * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.\n * NB: the virtual array control routines, later in this file, know about\n * this chunking of rows.  The rowsperchunk value is left in the mem manager\n * object so that it can be saved away if this sarray is the workspace for\n * a virtual array.\n */\n\nMETHODDEF(JSAMPARRAY)\nalloc_sarray (j_common_ptr cinfo, int pool_id,\n\t      JDIMENSION samplesperrow, JDIMENSION numrows)\n/* Allocate a 2-D sample array */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  JSAMPARRAY result;\n  JSAMPROW workspace;\n  JDIMENSION rowsperchunk, currow, i;\n  long ltemp;\n\n  /* Calculate max # of rows allowed in one allocation chunk */\n  ltemp = (MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr)) /\n\t  ((long) samplesperrow * SIZEOF(JSAMPLE));\n  if (ltemp <= 0)\n    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\n  if (ltemp < (long) numrows)\n    rowsperchunk = (JDIMENSION) ltemp;\n  else\n    rowsperchunk = numrows;\n  mem->last_rowsperchunk = rowsperchunk;\n\n  /* Get space for row pointers (small object) */\n  result = (JSAMPARRAY) alloc_small(cinfo, pool_id,\n\t\t\t\t    (size_t) numrows * SIZEOF(JSAMPROW));\n\n  /* Get the rows themselves (large objects) */\n  currow = 0;\n  while (currow < numrows) {\n    rowsperchunk = MIN(rowsperchunk, numrows - currow);\n    workspace = (JSAMPROW) alloc_large(cinfo, pool_id,\n      (size_t) rowsperchunk * (size_t) samplesperrow * SIZEOF(JSAMPLE));\n    for (i = rowsperchunk; i > 0; i--) {\n      result[currow++] = workspace;\n      workspace += samplesperrow;\n    }\n  }\n\n  return result;\n}\n\n\n/*\n * Creation of 2-D coefficient-block arrays.\n * This is essentially the same as the code for sample arrays, above.\n */\n\nMETHODDEF(JBLOCKARRAY)\nalloc_barray (j_common_ptr cinfo, int pool_id,\n\t      JDIMENSION blocksperrow, JDIMENSION numrows)\n/* Allocate a 2-D coefficient-block array */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  JBLOCKARRAY result;\n  JBLOCKROW workspace;\n  JDIMENSION rowsperchunk, currow, i;\n  long ltemp;\n\n  /* Calculate max # of rows allowed in one allocation chunk */\n  ltemp = (MAX_ALLOC_CHUNK - SIZEOF(large_pool_hdr)) /\n\t  ((long) blocksperrow * SIZEOF(JBLOCK));\n  if (ltemp <= 0)\n    ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);\n  if (ltemp < (long) numrows)\n    rowsperchunk = (JDIMENSION) ltemp;\n  else\n    rowsperchunk = numrows;\n  mem->last_rowsperchunk = rowsperchunk;\n\n  /* Get space for row pointers (small object) */\n  result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,\n\t\t\t\t     (size_t) numrows * SIZEOF(JBLOCKROW));\n\n  /* Get the rows themselves (large objects) */\n  currow = 0;\n  while (currow < numrows) {\n    rowsperchunk = MIN(rowsperchunk, numrows - currow);\n    workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,\n      (size_t) rowsperchunk * (size_t) blocksperrow * SIZEOF(JBLOCK));\n    for (i = rowsperchunk; i > 0; i--) {\n      result[currow++] = workspace;\n      workspace += blocksperrow;\n    }\n  }\n\n  return result;\n}\n\n\n/*\n * About virtual array management:\n *\n * The above \"normal\" array routines are only used to allocate strip buffers\n * (as wide as the image, but just a few rows high).  Full-image-sized buffers\n * are handled as \"virtual\" arrays.  The array is still accessed a strip at a\n * time, but the memory manager must save the whole array for repeated\n * accesses.  The intended implementation is that there is a strip buffer in\n * memory (as high as is possible given the desired memory limit), plus a\n * backing file that holds the rest of the array.\n *\n * The request_virt_array routines are told the total size of the image and\n * the maximum number of rows that will be accessed at once.  The in-memory\n * buffer must be at least as large as the maxaccess value.\n *\n * The request routines create control blocks but not the in-memory buffers.\n * That is postponed until realize_virt_arrays is called.  At that time the\n * total amount of space needed is known (approximately, anyway), so free\n * memory can be divided up fairly.\n *\n * The access_virt_array routines are responsible for making a specific strip\n * area accessible (after reading or writing the backing file, if necessary).\n * Note that the access routines are told whether the caller intends to modify\n * the accessed strip; during a read-only pass this saves having to rewrite\n * data to disk.  The access routines are also responsible for pre-zeroing\n * any newly accessed rows, if pre-zeroing was requested.\n *\n * In current usage, the access requests are usually for nonoverlapping\n * strips; that is, successive access start_row numbers differ by exactly\n * num_rows = maxaccess.  This means we can get good performance with simple\n * buffer dump/reload logic, by making the in-memory buffer be a multiple\n * of the access height; then there will never be accesses across bufferload\n * boundaries.  The code will still work with overlapping access requests,\n * but it doesn't handle bufferload overlaps very efficiently.\n */\n\n\nMETHODDEF(jvirt_sarray_ptr)\nrequest_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,\n\t\t     JDIMENSION samplesperrow, JDIMENSION numrows,\n\t\t     JDIMENSION maxaccess)\n/* Request a virtual 2-D sample array */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  jvirt_sarray_ptr result;\n\n  /* Only IMAGE-lifetime virtual arrays are currently supported */\n  if (pool_id != JPOOL_IMAGE)\n    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);\t/* safety check */\n\n  /* get control block */\n  result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,\n\t\t\t\t\t  SIZEOF(struct jvirt_sarray_control));\n\n  result->mem_buffer = NULL;\t/* marks array not yet realized */\n  result->rows_in_array = numrows;\n  result->samplesperrow = samplesperrow;\n  result->maxaccess = maxaccess;\n  result->pre_zero = pre_zero;\n  result->b_s_open = FALSE;\t/* no associated backing-store object */\n  result->next = mem->virt_sarray_list; /* add to list of virtual arrays */\n  mem->virt_sarray_list = result;\n\n  return result;\n}\n\n\nMETHODDEF(jvirt_barray_ptr)\nrequest_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,\n\t\t     JDIMENSION blocksperrow, JDIMENSION numrows,\n\t\t     JDIMENSION maxaccess)\n/* Request a virtual 2-D coefficient-block array */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  jvirt_barray_ptr result;\n\n  /* Only IMAGE-lifetime virtual arrays are currently supported */\n  if (pool_id != JPOOL_IMAGE)\n    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);\t/* safety check */\n\n  /* get control block */\n  result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,\n\t\t\t\t\t  SIZEOF(struct jvirt_barray_control));\n\n  result->mem_buffer = NULL;\t/* marks array not yet realized */\n  result->rows_in_array = numrows;\n  result->blocksperrow = blocksperrow;\n  result->maxaccess = maxaccess;\n  result->pre_zero = pre_zero;\n  result->b_s_open = FALSE;\t/* no associated backing-store object */\n  result->next = mem->virt_barray_list; /* add to list of virtual arrays */\n  mem->virt_barray_list = result;\n\n  return result;\n}\n\n\nMETHODDEF(void)\nrealize_virt_arrays (j_common_ptr cinfo)\n/* Allocate the in-memory buffers for any unrealized virtual arrays */\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  long bytesperrow, space_per_minheight, maximum_space;\n  long avail_mem, minheights, max_minheights;\n  jvirt_sarray_ptr sptr;\n  jvirt_barray_ptr bptr;\n\n  /* Compute the minimum space needed (maxaccess rows in each buffer)\n   * and the maximum space needed (full image height in each buffer).\n   * These may be of use to the system-dependent jpeg_mem_available routine.\n   */\n  space_per_minheight = 0;\n  maximum_space = 0;\n  for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\n    if (sptr->mem_buffer == NULL) { /* if not realized yet */\n      bytesperrow = (long) sptr->samplesperrow * SIZEOF(JSAMPLE);\n      space_per_minheight += (long) sptr->maxaccess * bytesperrow;\n      maximum_space += (long) sptr->rows_in_array * bytesperrow;\n    }\n  }\n  for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\n    if (bptr->mem_buffer == NULL) { /* if not realized yet */\n      bytesperrow = (long) bptr->blocksperrow * SIZEOF(JBLOCK);\n      space_per_minheight += (long) bptr->maxaccess * bytesperrow;\n      maximum_space += (long) bptr->rows_in_array * bytesperrow;\n    }\n  }\n\n  if (space_per_minheight <= 0)\n    return;\t\t\t/* no unrealized arrays, no work */\n\n  /* Determine amount of memory to actually use; this is system-dependent. */\n  avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,\n\t\t\t\t (long) mem->total_space_allocated);\n\n  /* If the maximum space needed is available, make all the buffers full\n   * height; otherwise parcel it out with the same number of minheights\n   * in each buffer.\n   */\n  if (avail_mem >= maximum_space)\n    max_minheights = 1000000000L;\n  else {\n    max_minheights = avail_mem / space_per_minheight;\n    /* If there doesn't seem to be enough space, try to get the minimum\n     * anyway.  This allows a \"stub\" implementation of jpeg_mem_available().\n     */\n    if (max_minheights <= 0)\n      max_minheights = 1;\n  }\n\n  /* Allocate the in-memory buffers and initialize backing store as needed. */\n\n  for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\n    if (sptr->mem_buffer == NULL) { /* if not realized yet */\n      minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;\n      if (minheights <= max_minheights) {\n\t/* This buffer fits in memory */\n\tsptr->rows_in_mem = sptr->rows_in_array;\n      } else {\n\t/* It doesn't fit in memory, create backing store. */\n\tsptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);\n\tjpeg_open_backing_store(cinfo, & sptr->b_s_info,\n\t\t\t\t(long) sptr->rows_in_array *\n\t\t\t\t(long) sptr->samplesperrow *\n\t\t\t\t(long) SIZEOF(JSAMPLE));\n\tsptr->b_s_open = TRUE;\n      }\n      sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,\n\t\t\t\t      sptr->samplesperrow, sptr->rows_in_mem);\n      sptr->rowsperchunk = mem->last_rowsperchunk;\n      sptr->cur_start_row = 0;\n      sptr->first_undef_row = 0;\n      sptr->dirty = FALSE;\n    }\n  }\n\n  for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\n    if (bptr->mem_buffer == NULL) { /* if not realized yet */\n      minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;\n      if (minheights <= max_minheights) {\n\t/* This buffer fits in memory */\n\tbptr->rows_in_mem = bptr->rows_in_array;\n      } else {\n\t/* It doesn't fit in memory, create backing store. */\n\tbptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);\n\tjpeg_open_backing_store(cinfo, & bptr->b_s_info,\n\t\t\t\t(long) bptr->rows_in_array *\n\t\t\t\t(long) bptr->blocksperrow *\n\t\t\t\t(long) SIZEOF(JBLOCK));\n\tbptr->b_s_open = TRUE;\n      }\n      bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,\n\t\t\t\t      bptr->blocksperrow, bptr->rows_in_mem);\n      bptr->rowsperchunk = mem->last_rowsperchunk;\n      bptr->cur_start_row = 0;\n      bptr->first_undef_row = 0;\n      bptr->dirty = FALSE;\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)\n/* Do backing store read or write of a virtual sample array */\n{\n  long bytesperrow, file_offset, byte_count, rows, thisrow, i;\n\n  bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);\n  file_offset = (long) ptr->cur_start_row * bytesperrow;\n  /* Loop to read or write each allocation chunk in mem_buffer */\n  for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {\n    /* One chunk, but check for short chunk at end of buffer */\n    rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);\n    /* Transfer no more than is currently defined */\n    thisrow = (long) ptr->cur_start_row + i;\n    rows = MIN(rows, (long) ptr->first_undef_row - thisrow);\n    /* Transfer no more than fits in file */\n    rows = MIN(rows, (long) ptr->rows_in_array - thisrow);\n    if (rows <= 0)\t\t/* this chunk might be past end of file! */\n      break;\n    byte_count = rows * bytesperrow;\n    if (writing)\n      (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,\n\t\t\t\t\t    (void FAR *) ptr->mem_buffer[i],\n\t\t\t\t\t    file_offset, byte_count);\n    else\n      (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,\n\t\t\t\t\t   (void FAR *) ptr->mem_buffer[i],\n\t\t\t\t\t   file_offset, byte_count);\n    file_offset += byte_count;\n  }\n}\n\n\nLOCAL(void)\ndo_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)\n/* Do backing store read or write of a virtual coefficient-block array */\n{\n  long bytesperrow, file_offset, byte_count, rows, thisrow, i;\n\n  bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);\n  file_offset = (long) ptr->cur_start_row * bytesperrow;\n  /* Loop to read or write each allocation chunk in mem_buffer */\n  for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {\n    /* One chunk, but check for short chunk at end of buffer */\n    rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);\n    /* Transfer no more than is currently defined */\n    thisrow = (long) ptr->cur_start_row + i;\n    rows = MIN(rows, (long) ptr->first_undef_row - thisrow);\n    /* Transfer no more than fits in file */\n    rows = MIN(rows, (long) ptr->rows_in_array - thisrow);\n    if (rows <= 0)\t\t/* this chunk might be past end of file! */\n      break;\n    byte_count = rows * bytesperrow;\n    if (writing)\n      (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,\n\t\t\t\t\t    (void FAR *) ptr->mem_buffer[i],\n\t\t\t\t\t    file_offset, byte_count);\n    else\n      (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,\n\t\t\t\t\t   (void FAR *) ptr->mem_buffer[i],\n\t\t\t\t\t   file_offset, byte_count);\n    file_offset += byte_count;\n  }\n}\n\n\nMETHODDEF(JSAMPARRAY)\naccess_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,\n\t\t    JDIMENSION start_row, JDIMENSION num_rows,\n\t\t    boolean writable)\n/* Access the part of a virtual sample array starting at start_row */\n/* and extending for num_rows rows.  writable is true if  */\n/* caller intends to modify the accessed area. */\n{\n  JDIMENSION end_row = start_row + num_rows;\n  JDIMENSION undef_row;\n\n  /* debugging check */\n  if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||\n      ptr->mem_buffer == NULL)\n    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n\n  /* Make the desired part of the virtual array accessible */\n  if (start_row < ptr->cur_start_row ||\n      end_row > ptr->cur_start_row + ptr->rows_in_mem) {\n    if (! ptr->b_s_open)\n      ERREXIT(cinfo, JERR_VIRTUAL_BUG);\n    /* Flush old buffer contents if necessary */\n    if (ptr->dirty) {\n      do_sarray_io(cinfo, ptr, TRUE);\n      ptr->dirty = FALSE;\n    }\n    /* Decide what part of virtual array to access.\n     * Algorithm: if target address > current window, assume forward scan,\n     * load starting at target address.  If target address < current window,\n     * assume backward scan, load so that target area is top of window.\n     * Note that when switching from forward write to forward read, will have\n     * start_row = 0, so the limiting case applies and we load from 0 anyway.\n     */\n    if (start_row > ptr->cur_start_row) {\n      ptr->cur_start_row = start_row;\n    } else {\n      /* use long arithmetic here to avoid overflow & unsigned problems */\n      long ltemp;\n\n      ltemp = (long) end_row - (long) ptr->rows_in_mem;\n      if (ltemp < 0)\n\tltemp = 0;\t\t/* don't fall off front end of file */\n      ptr->cur_start_row = (JDIMENSION) ltemp;\n    }\n    /* Read in the selected part of the array.\n     * During the initial write pass, we will do no actual read\n     * because the selected part is all undefined.\n     */\n    do_sarray_io(cinfo, ptr, FALSE);\n  }\n  /* Ensure the accessed part of the array is defined; prezero if needed.\n   * To improve locality of access, we only prezero the part of the array\n   * that the caller is about to access, not the entire in-memory array.\n   */\n  if (ptr->first_undef_row < end_row) {\n    if (ptr->first_undef_row < start_row) {\n      if (writable)\t\t/* writer skipped over a section of array */\n\tERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n      undef_row = start_row;\t/* but reader is allowed to read ahead */\n    } else {\n      undef_row = ptr->first_undef_row;\n    }\n    if (writable)\n      ptr->first_undef_row = end_row;\n    if (ptr->pre_zero) {\n      size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);\n      undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */\n      end_row -= ptr->cur_start_row;\n      while (undef_row < end_row) {\n\tFMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);\n\tundef_row++;\n      }\n    } else {\n      if (! writable)\t\t/* reader looking at undefined data */\n\tERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n    }\n  }\n  /* Flag the buffer dirty if caller will write in it */\n  if (writable)\n    ptr->dirty = TRUE;\n  /* Return address of proper part of the buffer */\n  return ptr->mem_buffer + (start_row - ptr->cur_start_row);\n}\n\n\nMETHODDEF(JBLOCKARRAY)\naccess_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,\n\t\t    JDIMENSION start_row, JDIMENSION num_rows,\n\t\t    boolean writable)\n/* Access the part of a virtual block array starting at start_row */\n/* and extending for num_rows rows.  writable is true if  */\n/* caller intends to modify the accessed area. */\n{\n  JDIMENSION end_row = start_row + num_rows;\n  JDIMENSION undef_row;\n\n  /* debugging check */\n  if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||\n      ptr->mem_buffer == NULL)\n    ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n\n  /* Make the desired part of the virtual array accessible */\n  if (start_row < ptr->cur_start_row ||\n      end_row > ptr->cur_start_row + ptr->rows_in_mem) {\n    if (! ptr->b_s_open)\n      ERREXIT(cinfo, JERR_VIRTUAL_BUG);\n    /* Flush old buffer contents if necessary */\n    if (ptr->dirty) {\n      do_barray_io(cinfo, ptr, TRUE);\n      ptr->dirty = FALSE;\n    }\n    /* Decide what part of virtual array to access.\n     * Algorithm: if target address > current window, assume forward scan,\n     * load starting at target address.  If target address < current window,\n     * assume backward scan, load so that target area is top of window.\n     * Note that when switching from forward write to forward read, will have\n     * start_row = 0, so the limiting case applies and we load from 0 anyway.\n     */\n    if (start_row > ptr->cur_start_row) {\n      ptr->cur_start_row = start_row;\n    } else {\n      /* use long arithmetic here to avoid overflow & unsigned problems */\n      long ltemp;\n\n      ltemp = (long) end_row - (long) ptr->rows_in_mem;\n      if (ltemp < 0)\n\tltemp = 0;\t\t/* don't fall off front end of file */\n      ptr->cur_start_row = (JDIMENSION) ltemp;\n    }\n    /* Read in the selected part of the array.\n     * During the initial write pass, we will do no actual read\n     * because the selected part is all undefined.\n     */\n    do_barray_io(cinfo, ptr, FALSE);\n  }\n  /* Ensure the accessed part of the array is defined; prezero if needed.\n   * To improve locality of access, we only prezero the part of the array\n   * that the caller is about to access, not the entire in-memory array.\n   */\n  if (ptr->first_undef_row < end_row) {\n    if (ptr->first_undef_row < start_row) {\n      if (writable)\t\t/* writer skipped over a section of array */\n\tERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n      undef_row = start_row;\t/* but reader is allowed to read ahead */\n    } else {\n      undef_row = ptr->first_undef_row;\n    }\n    if (writable)\n      ptr->first_undef_row = end_row;\n    if (ptr->pre_zero) {\n      size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);\n      undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */\n      end_row -= ptr->cur_start_row;\n      while (undef_row < end_row) {\n\tFMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);\n\tundef_row++;\n      }\n    } else {\n      if (! writable)\t\t/* reader looking at undefined data */\n\tERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);\n    }\n  }\n  /* Flag the buffer dirty if caller will write in it */\n  if (writable)\n    ptr->dirty = TRUE;\n  /* Return address of proper part of the buffer */\n  return ptr->mem_buffer + (start_row - ptr->cur_start_row);\n}\n\n\n/*\n * Release all objects belonging to a specified pool.\n */\n\nMETHODDEF(void)\nfree_pool (j_common_ptr cinfo, int pool_id)\n{\n  my_mem_ptr mem = (my_mem_ptr) cinfo->mem;\n  small_pool_ptr shdr_ptr;\n  large_pool_ptr lhdr_ptr;\n  size_t space_freed;\n\n  if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)\n    ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id);\t/* safety check */\n\n#ifdef MEM_STATS\n  if (cinfo->err->trace_level > 1)\n    print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */\n#endif\n\n  /* If freeing IMAGE pool, close any virtual arrays first */\n  if (pool_id == JPOOL_IMAGE) {\n    jvirt_sarray_ptr sptr;\n    jvirt_barray_ptr bptr;\n\n    for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {\n      if (sptr->b_s_open) {\t/* there may be no backing store */\n\tsptr->b_s_open = FALSE;\t/* prevent recursive close if error */\n\t(*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);\n      }\n    }\n    mem->virt_sarray_list = NULL;\n    for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {\n      if (bptr->b_s_open) {\t/* there may be no backing store */\n\tbptr->b_s_open = FALSE;\t/* prevent recursive close if error */\n\t(*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);\n      }\n    }\n    mem->virt_barray_list = NULL;\n  }\n\n  /* Release large objects */\n  lhdr_ptr = mem->large_list[pool_id];\n  mem->large_list[pool_id] = NULL;\n\n  while (lhdr_ptr != NULL) {\n    large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;\n    space_freed = lhdr_ptr->hdr.bytes_used +\n\t\t  lhdr_ptr->hdr.bytes_left +\n\t\t  SIZEOF(large_pool_hdr);\n    jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);\n    mem->total_space_allocated -= space_freed;\n    lhdr_ptr = next_lhdr_ptr;\n  }\n\n  /* Release small objects */\n  shdr_ptr = mem->small_list[pool_id];\n  mem->small_list[pool_id] = NULL;\n\n  while (shdr_ptr != NULL) {\n    small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;\n    space_freed = shdr_ptr->hdr.bytes_used +\n\t\t  shdr_ptr->hdr.bytes_left +\n\t\t  SIZEOF(small_pool_hdr);\n    jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);\n    mem->total_space_allocated -= space_freed;\n    shdr_ptr = next_shdr_ptr;\n  }\n}\n\n\n/*\n * Close up shop entirely.\n * Note that this cannot be called unless cinfo->mem is non-NULL.\n */\n\nMETHODDEF(void)\nself_destruct (j_common_ptr cinfo)\n{\n  int pool;\n\n  /* Close all backing store, release all memory.\n   * Releasing pools in reverse order might help avoid fragmentation\n   * with some (brain-damaged) malloc libraries.\n   */\n  for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {\n    free_pool(cinfo, pool);\n  }\n\n  /* Release the memory manager control block too. */\n  jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));\n  cinfo->mem = NULL;\t\t/* ensures I will be called only once */\n\n  jpeg_mem_term(cinfo);\t\t/* system-dependent cleanup */\n}\n\n\n/*\n * Memory manager initialization.\n * When this is called, only the error manager pointer is valid in cinfo!\n */\n\nGLOBAL(void)\njinit_memory_mgr (j_common_ptr cinfo)\n{\n  my_mem_ptr mem;\n  long max_to_use;\n  int pool;\n  size_t test_mac;\n\n  cinfo->mem = NULL;\t\t/* for safety if init fails */\n\n  /* Check for configuration errors.\n   * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably\n   * doesn't reflect any real hardware alignment requirement.\n   * The test is a little tricky: for X>0, X and X-1 have no one-bits\n   * in common if and only if X is a power of 2, ie has only one one-bit.\n   * Some compilers may give an \"unreachable code\" warning here; ignore it.\n   */\n  if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)\n    ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);\n  /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be\n   * a multiple of SIZEOF(ALIGN_TYPE).\n   * Again, an \"unreachable code\" warning may be ignored here.\n   * But a \"constant too large\" warning means you need to fix MAX_ALLOC_CHUNK.\n   */\n  test_mac = (size_t) MAX_ALLOC_CHUNK;\n  if ((long) test_mac != MAX_ALLOC_CHUNK ||\n      (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)\n    ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);\n\n  max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */\n\n  /* Attempt to allocate memory manager's control block */\n  mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));\n\n  if (mem == NULL) {\n    jpeg_mem_term(cinfo);\t/* system-dependent cleanup */\n    ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);\n  }\n\n  /* OK, fill in the method pointers */\n  mem->pub.alloc_small = alloc_small;\n  mem->pub.alloc_large = alloc_large;\n  mem->pub.alloc_sarray = alloc_sarray;\n  mem->pub.alloc_barray = alloc_barray;\n  mem->pub.request_virt_sarray = request_virt_sarray;\n  mem->pub.request_virt_barray = request_virt_barray;\n  mem->pub.realize_virt_arrays = realize_virt_arrays;\n  mem->pub.access_virt_sarray = access_virt_sarray;\n  mem->pub.access_virt_barray = access_virt_barray;\n  mem->pub.free_pool = free_pool;\n  mem->pub.self_destruct = self_destruct;\n\n  /* Make MAX_ALLOC_CHUNK accessible to other modules */\n  mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;\n\n  /* Initialize working state */\n  mem->pub.max_memory_to_use = max_to_use;\n\n  for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {\n    mem->small_list[pool] = NULL;\n    mem->large_list[pool] = NULL;\n  }\n  mem->virt_sarray_list = NULL;\n  mem->virt_barray_list = NULL;\n\n  mem->total_space_allocated = SIZEOF(my_memory_mgr);\n\n  /* Declare ourselves open for business */\n  cinfo->mem = &mem->pub;\n\n  /* Check for an environment variable JPEGMEM; if found, override the\n   * default max_memory setting from jpeg_mem_init.  Note that the\n   * surrounding application may again override this value.\n   * If your system doesn't support getenv(), define NO_GETENV to disable\n   * this feature.\n   */\n#ifndef NO_GETENV\n  { char * memenv;\n\n    if ((memenv = getenv(\"JPEGMEM\")) != NULL) {\n      char ch = 'x';\n\n      if (sscanf(memenv, \"%ld%c\", &max_to_use, &ch) > 0) {\n\tif (ch == 'm' || ch == 'M')\n\t  max_to_use *= 1000L;\n\tmem->pub.max_memory_to_use = max_to_use * 1000L;\n      }\n    }\n  }\n#endif\n\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jmemname.c",
    "content": "/*\n * jmemname.c\n *\n * Copyright (C) 1992-1997, Thomas G. Lane.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file provides a generic implementation of the system-dependent\n * portion of the JPEG memory manager.  This implementation assumes that\n * you must explicitly construct a name for each temp file.\n * Also, the problem of determining the amount of memory available\n * is shoved onto the user.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jmemsys.h\"\t\t/* import the system-dependent declarations */\n\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare malloc(),free() */\nextern void * malloc JPP((size_t size));\nextern void free JPP((void *ptr));\n#endif\n\n#ifndef SEEK_SET\t\t/* pre-ANSI systems may not define this; */\n#define SEEK_SET  0\t\t/* if not, assume 0 is correct */\n#endif\n\n#ifdef DONT_USE_B_MODE\t\t/* define mode parameters for fopen() */\n#define READ_BINARY\t\"r\"\n#define RW_BINARY\t\"w+\"\n#else\n#ifdef VMS\t\t\t/* VMS is very nonstandard */\n#define READ_BINARY\t\"rb\", \"ctx=stm\"\n#define RW_BINARY\t\"w+b\", \"ctx=stm\"\n#else\t\t\t\t/* standard ANSI-compliant case */\n#define READ_BINARY\t\"rb\"\n#define RW_BINARY\t\"w+b\"\n#endif\n#endif\n\n\n/*\n * Selection of a file name for a temporary file.\n * This is system-dependent!\n *\n * The code as given is suitable for most Unix systems, and it is easily\n * modified for most non-Unix systems.  Some notes:\n *  1.  The temp file is created in the directory named by TEMP_DIRECTORY.\n *      The default value is /usr/tmp, which is the conventional place for\n *      creating large temp files on Unix.  On other systems you'll probably\n *      want to change the file location.  You can do this by editing the\n *      #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.\n *\n *  2.  If you need to change the file name as well as its location,\n *      you can override the TEMP_FILE_NAME macro.  (Note that this is\n *      actually a printf format string; it must contain %s and %d.)\n *      Few people should need to do this.\n *\n *  3.  mktemp() is used to ensure that multiple processes running\n *      simultaneously won't select the same file names.  If your system\n *      doesn't have mktemp(), define NO_MKTEMP to do it the hard way.\n *      (If you don't have <errno.h>, also define NO_ERRNO_H.)\n *\n *  4.  You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c\n *      will cause the temp files to be removed if you stop the program early.\n */\n\n#ifndef TEMP_DIRECTORY\t\t/* can override from jconfig.h or Makefile */\n#define TEMP_DIRECTORY  \"/usr/tmp/\" /* recommended setting for Unix */\n#endif\n\nstatic int next_file_num;\t/* to distinguish among several temp files */\n\n#ifdef NO_MKTEMP\n\n#ifndef TEMP_FILE_NAME\t\t/* can override from jconfig.h or Makefile */\n#define TEMP_FILE_NAME  \"%sJPG%03d.TMP\"\n#endif\n\n#ifndef NO_ERRNO_H\n#include <errno.h>\t\t/* to define ENOENT */\n#endif\n\n/* ANSI C specifies that errno is a macro, but on older systems it's more\n * likely to be a plain int variable.  And not all versions of errno.h\n * bother to declare it, so we have to in order to be most portable.  Thus:\n */\n#ifndef errno\nextern int errno;\n#endif\n\n\nLOCAL(void)\nselect_file_name (char * fname)\n{\n  FILE * tfile;\n\n  /* Keep generating file names till we find one that's not in use */\n  for (;;) {\n    next_file_num++;\t\t/* advance counter */\n    sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);\n    if ((tfile = fopen(fname, READ_BINARY)) == NULL) {\n      /* fopen could have failed for a reason other than the file not\n       * being there; for example, file there but unreadable.\n       * If <errno.h> isn't available, then we cannot test the cause.\n       */\n#ifdef ENOENT\n      if (errno != ENOENT)\n\tcontinue;\n#endif\n      break;\n    }\n    fclose(tfile);\t\t/* oops, it's there; close tfile & try again */\n  }\n}\n\n#else /* ! NO_MKTEMP */\n\n/* Note that mktemp() requires the initial filename to end in six X's */\n#ifndef TEMP_FILE_NAME\t\t/* can override from jconfig.h or Makefile */\n#define TEMP_FILE_NAME  \"%sJPG%dXXXXXX\"\n#endif\n\nLOCAL(void)\nselect_file_name (char * fname)\n{\n  next_file_num++;\t\t/* advance counter */\n  sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);\n  mktemp(fname);\t\t/* make sure file name is unique */\n  /* mktemp replaces the trailing XXXXXX with a unique string of characters */\n}\n\n#endif /* NO_MKTEMP */\n\n\n/*\n * Memory allocation and freeing are controlled by the regular library\n * routines malloc() and free().\n */\n\nGLOBAL(void *)\njpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * \"Large\" objects are treated the same as \"small\" ones.\n * NB: although we include FAR keywords in the routine declarations,\n * this file won't actually work in 80x86 small/medium model; at least,\n * you probably won't be able to process useful-size images in only 64KB.\n */\n\nGLOBAL(void FAR *)\njpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void FAR *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * This routine computes the total memory space available for allocation.\n * It's impossible to do this in a portable way; our current solution is\n * to make the user tell us (with a default value set at compile time).\n * If you can actually get the available space, it's a good idea to subtract\n * a slop factor of 5% or so.\n */\n\n#ifndef DEFAULT_MAX_MEM\t\t/* so can override from makefile */\n#define DEFAULT_MAX_MEM\t\t1000000L /* default: one megabyte */\n#endif\n\nGLOBAL(long)\njpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,\n\t\t    long max_bytes_needed, long already_allocated)\n{\n  return cinfo->mem->max_memory_to_use - already_allocated;\n}\n\n\n/*\n * Backing store (temporary file) management.\n * Backing store objects are only used when the value returned by\n * jpeg_mem_available is less than the total space needed.  You can dispense\n * with these routines if you have plenty of virtual memory; see jmemnobs.c.\n */\n\n\nMETHODDEF(void)\nread_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t    void FAR * buffer_address,\n\t\t    long file_offset, long byte_count)\n{\n  if (fseek(info->temp_file, file_offset, SEEK_SET))\n    ERREXIT(cinfo, JERR_TFILE_SEEK);\n  if (JFREAD(info->temp_file, buffer_address, byte_count)\n      != (size_t) byte_count)\n    ERREXIT(cinfo, JERR_TFILE_READ);\n}\n\n\nMETHODDEF(void)\nwrite_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t     void FAR * buffer_address,\n\t\t     long file_offset, long byte_count)\n{\n  if (fseek(info->temp_file, file_offset, SEEK_SET))\n    ERREXIT(cinfo, JERR_TFILE_SEEK);\n  if (JFWRITE(info->temp_file, buffer_address, byte_count)\n      != (size_t) byte_count)\n    ERREXIT(cinfo, JERR_TFILE_WRITE);\n}\n\n\nMETHODDEF(void)\nclose_backing_store (j_common_ptr cinfo, backing_store_ptr info)\n{\n  fclose(info->temp_file);\t/* close the file */\n  unlink(info->temp_name);\t/* delete the file */\n/* If your system doesn't have unlink(), use remove() instead.\n * remove() is the ANSI-standard name for this function, but if\n * your system was ANSI you'd be using jmemansi.c, right?\n */\n  TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);\n}\n\n\n/*\n * Initial opening of a backing-store object.\n */\n\nGLOBAL(void)\njpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t\t long total_bytes_needed)\n{\n  select_file_name(info->temp_name);\n  if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)\n    ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);\n  info->read_backing_store = read_backing_store;\n  info->write_backing_store = write_backing_store;\n  info->close_backing_store = close_backing_store;\n  TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);\n}\n\n\n/*\n * These routines take care of any system-dependent initialization and\n * cleanup required.\n */\n\nGLOBAL(long)\njpeg_mem_init (j_common_ptr cinfo)\n{\n  next_file_num = 0;\t\t/* initialize temp file name generator */\n  return DEFAULT_MAX_MEM;\t/* default for max_memory_to_use */\n}\n\nGLOBAL(void)\njpeg_mem_term (j_common_ptr cinfo)\n{\n  /* no work */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jmemnobs.c",
    "content": "/*\n * jmemnobs.c\n *\n * Copyright (C) 1992-1996, Thomas G. Lane.\n * Modified 2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file provides a really simple implementation of the system-\n * dependent portion of the JPEG memory manager.  This implementation\n * assumes that no backing-store files are needed: all required space\n * can be obtained from malloc().\n * This is very portable in the sense that it'll compile on almost anything,\n * but you'd better have lots of main memory (or virtual memory) if you want\n * to process big images.\n * Note that the max_memory_to_use option is respected by this implementation.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"jmemsys.h\"\t\t/* import the system-dependent declarations */\n\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare malloc(),free() */\nextern void * malloc JPP((size_t size));\nextern void free JPP((void *ptr));\n#endif\n\n\n/*\n * Memory allocation and freeing are controlled by the regular library\n * routines malloc() and free().\n */\n\nGLOBAL(void *)\njpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * \"Large\" objects are treated the same as \"small\" ones.\n * NB: although we include FAR keywords in the routine declarations,\n * this file won't actually work in 80x86 small/medium model; at least,\n * you probably won't be able to process useful-size images in only 64KB.\n */\n\nGLOBAL(void FAR *)\njpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)\n{\n  return (void FAR *) malloc(sizeofobject);\n}\n\nGLOBAL(void)\njpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)\n{\n  free(object);\n}\n\n\n/*\n * This routine computes the total memory space available for allocation.\n */\n\nGLOBAL(long)\njpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,\n\t\t    long max_bytes_needed, long already_allocated)\n{\n  if (cinfo->mem->max_memory_to_use)\n    return cinfo->mem->max_memory_to_use - already_allocated;\n\n  /* Here we say, \"we got all you want bud!\" */\n  return max_bytes_needed;\n}\n\n\n/*\n * Backing store (temporary file) management.\n * Since jpeg_mem_available always promised the moon,\n * this should never be called and we can just error out.\n */\n\nGLOBAL(void)\njpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,\n\t\t\t long total_bytes_needed)\n{\n  ERREXIT(cinfo, JERR_NO_BACKING_STORE);\n}\n\n\n/*\n * These routines take care of any system-dependent initialization and\n * cleanup required.  Here, there isn't any.\n */\n\nGLOBAL(long)\njpeg_mem_init (j_common_ptr cinfo)\n{\n  return 0;\t\t\t/* just set max_memory_to_use to 0 */\n}\n\nGLOBAL(void)\njpeg_mem_term (j_common_ptr cinfo)\n{\n  /* no work */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jmemsys.h",
    "content": "/*\n * jmemsys.h\n *\n * Copyright (C) 1992-1997, Thomas G. Lane.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This include file defines the interface between the system-independent\n * and system-dependent portions of the JPEG memory manager.  No other\n * modules need include it.  (The system-independent portion is jmemmgr.c;\n * there are several different versions of the system-dependent portion.)\n *\n * This file works as-is for the system-dependent memory managers supplied\n * in the IJG distribution.  You may need to modify it if you write a\n * custom memory manager.  If system-dependent changes are needed in\n * this file, the best method is to #ifdef them based on a configuration\n * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR\n * and USE_MAC_MEMMGR.\n */\n\n\n/* Short forms of external names for systems with brain-damaged linkers. */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jpeg_get_small\t\tjGetSmall\n#define jpeg_free_small\t\tjFreeSmall\n#define jpeg_get_large\t\tjGetLarge\n#define jpeg_free_large\t\tjFreeLarge\n#define jpeg_mem_available\tjMemAvail\n#define jpeg_open_backing_store\tjOpenBackStore\n#define jpeg_mem_init\t\tjMemInit\n#define jpeg_mem_term\t\tjMemTerm\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n\n/*\n * These two functions are used to allocate and release small chunks of\n * memory.  (Typically the total amount requested through jpeg_get_small is\n * no more than 20K or so; this will be requested in chunks of a few K each.)\n * Behavior should be the same as for the standard library functions malloc\n * and free; in particular, jpeg_get_small must return NULL on failure.\n * On most systems, these ARE malloc and free.  jpeg_free_small is passed the\n * size of the object being freed, just in case it's needed.\n * On an 80x86 machine using small-data memory model, these manage near heap.\n */\n\nEXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));\nEXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,\n\t\t\t\t  size_t sizeofobject));\n\n/*\n * These two functions are used to allocate and release large chunks of\n * memory (up to the total free space designated by jpeg_mem_available).\n * The interface is the same as above, except that on an 80x86 machine,\n * far pointers are used.  On most other machines these are identical to\n * the jpeg_get/free_small routines; but we keep them separate anyway,\n * in case a different allocation strategy is desirable for large chunks.\n */\n\nEXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,\n\t\t\t\t       size_t sizeofobject));\nEXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,\n\t\t\t\t  size_t sizeofobject));\n\n/*\n * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may\n * be requested in a single call to jpeg_get_large (and jpeg_get_small for that\n * matter, but that case should never come into play).  This macro is needed\n * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.\n * On those machines, we expect that jconfig.h will provide a proper value.\n * On machines with 32-bit flat address spaces, any large constant may be used.\n *\n * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type\n * size_t and will be a multiple of sizeof(align_type).\n */\n\n#ifndef MAX_ALLOC_CHUNK\t\t/* may be overridden in jconfig.h */\n#define MAX_ALLOC_CHUNK  1000000000L\n#endif\n\n/*\n * This routine computes the total space still available for allocation by\n * jpeg_get_large.  If more space than this is needed, backing store will be\n * used.  NOTE: any memory already allocated must not be counted.\n *\n * There is a minimum space requirement, corresponding to the minimum\n * feasible buffer sizes; jmemmgr.c will request that much space even if\n * jpeg_mem_available returns zero.  The maximum space needed, enough to hold\n * all working storage in memory, is also passed in case it is useful.\n * Finally, the total space already allocated is passed.  If no better\n * method is available, cinfo->mem->max_memory_to_use - already_allocated\n * is often a suitable calculation.\n *\n * It is OK for jpeg_mem_available to underestimate the space available\n * (that'll just lead to more backing-store access than is really necessary).\n * However, an overestimate will lead to failure.  Hence it's wise to subtract\n * a slop factor from the true available space.  5% should be enough.\n *\n * On machines with lots of virtual memory, any large constant may be returned.\n * Conversely, zero may be returned to always use the minimum amount of memory.\n */\n\nEXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,\n\t\t\t\t     long min_bytes_needed,\n\t\t\t\t     long max_bytes_needed,\n\t\t\t\t     long already_allocated));\n\n\n/*\n * This structure holds whatever state is needed to access a single\n * backing-store object.  The read/write/close method pointers are called\n * by jmemmgr.c to manipulate the backing-store object; all other fields\n * are private to the system-dependent backing store routines.\n */\n\n#define TEMP_NAME_LENGTH   64\t/* max length of a temporary file's name */\n\n\n#ifdef USE_MSDOS_MEMMGR\t\t/* DOS-specific junk */\n\ntypedef unsigned short XMSH;\t/* type of extended-memory handles */\ntypedef unsigned short EMSH;\t/* type of expanded-memory handles */\n\ntypedef union {\n  short file_handle;\t\t/* DOS file handle if it's a temp file */\n  XMSH xms_handle;\t\t/* handle if it's a chunk of XMS */\n  EMSH ems_handle;\t\t/* handle if it's a chunk of EMS */\n} handle_union;\n\n#endif /* USE_MSDOS_MEMMGR */\n\n#ifdef USE_MAC_MEMMGR\t\t/* Mac-specific junk */\n#include <Files.h>\n#endif /* USE_MAC_MEMMGR */\n\n\ntypedef struct backing_store_struct * backing_store_ptr;\n\ntypedef struct backing_store_struct {\n  /* Methods for reading/writing/closing this backing-store object */\n  JMETHOD(void, read_backing_store, (j_common_ptr cinfo,\n\t\t\t\t     backing_store_ptr info,\n\t\t\t\t     void FAR * buffer_address,\n\t\t\t\t     long file_offset, long byte_count));\n  JMETHOD(void, write_backing_store, (j_common_ptr cinfo,\n\t\t\t\t      backing_store_ptr info,\n\t\t\t\t      void FAR * buffer_address,\n\t\t\t\t      long file_offset, long byte_count));\n  JMETHOD(void, close_backing_store, (j_common_ptr cinfo,\n\t\t\t\t      backing_store_ptr info));\n\n  /* Private fields for system-dependent backing-store management */\n#ifdef USE_MSDOS_MEMMGR\n  /* For the MS-DOS manager (jmemdos.c), we need: */\n  handle_union handle;\t\t/* reference to backing-store storage object */\n  char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */\n#else\n#ifdef USE_MAC_MEMMGR\n  /* For the Mac manager (jmemmac.c), we need: */\n  short temp_file;\t\t/* file reference number to temp file */\n  FSSpec tempSpec;\t\t/* the FSSpec for the temp file */\n  char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */\n#else\n  /* For a typical implementation with temp files, we need: */\n  FILE * temp_file;\t\t/* stdio reference to temp file */\n  char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */\n#endif\n#endif\n} backing_store_info;\n\n\n/*\n * Initial opening of a backing-store object.  This must fill in the\n * read/write/close pointers in the object.  The read/write routines\n * may take an error exit if the specified maximum file size is exceeded.\n * (If jpeg_mem_available always returns a large value, this routine can\n * just take an error exit.)\n */\n\nEXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,\n\t\t\t\t\t  backing_store_ptr info,\n\t\t\t\t\t  long total_bytes_needed));\n\n\n/*\n * These routines take care of any system-dependent initialization and\n * cleanup required.  jpeg_mem_init will be called before anything is\n * allocated (and, therefore, nothing in cinfo is of use except the error\n * manager pointer).  It should return a suitable default value for\n * max_memory_to_use; this may subsequently be overridden by the surrounding\n * application.  (Note that max_memory_to_use is only important if\n * jpeg_mem_available chooses to consult it ... no one else will.)\n * jpeg_mem_term may assume that all requested memory has been freed and that\n * all opened backing-store objects have been closed.\n */\n\nEXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));\nEXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));\n"
  },
  {
    "path": "dlib/external/libjpeg/jmorecfg.h",
    "content": "/*\n * jmorecfg.h\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 1997-2013 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains additional configuration options that customize the\n * JPEG software for special applications or support machine-dependent\n * optimizations.  Most users will not need to touch this file.\n */\n\n\n/*\n * Define BITS_IN_JSAMPLE as either\n *   8   for 8-bit sample values (the usual setting)\n *   9   for 9-bit sample values\n *   10  for 10-bit sample values\n *   11  for 11-bit sample values\n *   12  for 12-bit sample values\n * Only 8, 9, 10, 11, and 12 bits sample data precision are supported for\n * full-feature DCT processing.  Further depths up to 16-bit may be added\n * later for the lossless modes of operation.\n * Run-time selection and conversion of data precision will be added later\n * and are currently not supported, sorry.\n * Exception:  The transcoding part (jpegtran) supports all settings in a\n * single instance, since it operates on the level of DCT coefficients and\n * not sample values.  The DCT coefficients are of the same type (16 bits)\n * in all cases (see below).\n */\n\n#define BITS_IN_JSAMPLE  8\t/* use 8, 9, 10, 11, or 12 */\n\n\n/*\n * Maximum number of components (color channels) allowed in JPEG image.\n * To meet the letter of the JPEG spec, set this to 255.  However, darn\n * few applications need more than 4 channels (maybe 5 for CMYK + alpha\n * mask).  We recommend 10 as a reasonable compromise; use 4 if you are\n * really short on memory.  (Each allowed component costs a hundred or so\n * bytes of storage, whether actually used in an image or not.)\n */\n\n#define MAX_COMPONENTS  10\t/* maximum number of image components */\n\n\n/*\n * Basic data types.\n * You may need to change these if you have a machine with unusual data\n * type sizes; for example, \"char\" not 8 bits, \"short\" not 16 bits,\n * or \"long\" not 32 bits.  We don't care whether \"int\" is 16 or 32 bits,\n * but it had better be at least 16.\n */\n\n/* Representation of a single sample (pixel element value).\n * We frequently allocate large arrays of these, so it's important to keep\n * them small.  But if you have memory to burn and access to char or short\n * arrays is very slow on your hardware, you might want to change these.\n */\n\n#if BITS_IN_JSAMPLE == 8\n/* JSAMPLE should be the smallest type that will hold the values 0..255.\n * You can use a signed char by having GETJSAMPLE mask it with 0xFF.\n */\n\n#ifdef HAVE_UNSIGNED_CHAR\n\ntypedef unsigned char JSAMPLE;\n#define GETJSAMPLE(value)  ((int) (value))\n\n#else /* not HAVE_UNSIGNED_CHAR */\n\ntypedef char JSAMPLE;\n#ifdef CHAR_IS_UNSIGNED\n#define GETJSAMPLE(value)  ((int) (value))\n#else\n#define GETJSAMPLE(value)  ((int) (value) & 0xFF)\n#endif /* CHAR_IS_UNSIGNED */\n\n#endif /* HAVE_UNSIGNED_CHAR */\n\n#define MAXJSAMPLE\t255\n#define CENTERJSAMPLE\t128\n\n#endif /* BITS_IN_JSAMPLE == 8 */\n\n\n#if BITS_IN_JSAMPLE == 9\n/* JSAMPLE should be the smallest type that will hold the values 0..511.\n * On nearly all machines \"short\" will do nicely.\n */\n\ntypedef short JSAMPLE;\n#define GETJSAMPLE(value)  ((int) (value))\n\n#define MAXJSAMPLE\t511\n#define CENTERJSAMPLE\t256\n\n#endif /* BITS_IN_JSAMPLE == 9 */\n\n\n#if BITS_IN_JSAMPLE == 10\n/* JSAMPLE should be the smallest type that will hold the values 0..1023.\n * On nearly all machines \"short\" will do nicely.\n */\n\ntypedef short JSAMPLE;\n#define GETJSAMPLE(value)  ((int) (value))\n\n#define MAXJSAMPLE\t1023\n#define CENTERJSAMPLE\t512\n\n#endif /* BITS_IN_JSAMPLE == 10 */\n\n\n#if BITS_IN_JSAMPLE == 11\n/* JSAMPLE should be the smallest type that will hold the values 0..2047.\n * On nearly all machines \"short\" will do nicely.\n */\n\ntypedef short JSAMPLE;\n#define GETJSAMPLE(value)  ((int) (value))\n\n#define MAXJSAMPLE\t2047\n#define CENTERJSAMPLE\t1024\n\n#endif /* BITS_IN_JSAMPLE == 11 */\n\n\n#if BITS_IN_JSAMPLE == 12\n/* JSAMPLE should be the smallest type that will hold the values 0..4095.\n * On nearly all machines \"short\" will do nicely.\n */\n\ntypedef short JSAMPLE;\n#define GETJSAMPLE(value)  ((int) (value))\n\n#define MAXJSAMPLE\t4095\n#define CENTERJSAMPLE\t2048\n\n#endif /* BITS_IN_JSAMPLE == 12 */\n\n\n/* Representation of a DCT frequency coefficient.\n * This should be a signed value of at least 16 bits; \"short\" is usually OK.\n * Again, we allocate large arrays of these, but you can change to int\n * if you have memory to burn and \"short\" is really slow.\n */\n\ntypedef short JCOEF;\n\n\n/* Compressed datastreams are represented as arrays of JOCTET.\n * These must be EXACTLY 8 bits wide, at least once they are written to\n * external storage.  Note that when using the stdio data source/destination\n * managers, this is also the data type passed to fread/fwrite.\n */\n\n#ifdef HAVE_UNSIGNED_CHAR\n\ntypedef unsigned char JOCTET;\n#define GETJOCTET(value)  (value)\n\n#else /* not HAVE_UNSIGNED_CHAR */\n\ntypedef char JOCTET;\n#ifdef CHAR_IS_UNSIGNED\n#define GETJOCTET(value)  (value)\n#else\n#define GETJOCTET(value)  ((value) & 0xFF)\n#endif /* CHAR_IS_UNSIGNED */\n\n#endif /* HAVE_UNSIGNED_CHAR */\n\n\n/* These typedefs are used for various table entries and so forth.\n * They must be at least as wide as specified; but making them too big\n * won't cost a huge amount of memory, so we don't provide special\n * extraction code like we did for JSAMPLE.  (In other words, these\n * typedefs live at a different point on the speed/space tradeoff curve.)\n */\n\n/* UINT8 must hold at least the values 0..255. */\n\n#ifdef HAVE_UNSIGNED_CHAR\ntypedef unsigned char UINT8;\n#else /* not HAVE_UNSIGNED_CHAR */\n#ifdef CHAR_IS_UNSIGNED\ntypedef char UINT8;\n#else /* not CHAR_IS_UNSIGNED */\ntypedef short UINT8;\n#endif /* CHAR_IS_UNSIGNED */\n#endif /* HAVE_UNSIGNED_CHAR */\n\n/* UINT16 must hold at least the values 0..65535. */\n\n#ifdef HAVE_UNSIGNED_SHORT\ntypedef unsigned short UINT16;\n#else /* not HAVE_UNSIGNED_SHORT */\ntypedef unsigned int UINT16;\n#endif /* HAVE_UNSIGNED_SHORT */\n\n/* INT16 must hold at least the values -32768..32767. */\n\n#ifndef XMD_H\t\t\t/* X11/xmd.h correctly defines INT16 */\ntypedef short INT16;\n#endif\n\n/* INT32 must hold at least signed 32-bit values. */\n\n#ifndef XMD_H\t\t\t/* X11/xmd.h correctly defines INT32 */\n#ifndef _BASETSD_H_\t\t/* Microsoft defines it in basetsd.h */\n#ifndef _BASETSD_H\t\t/* MinGW is slightly different */\n#ifndef QGLOBAL_H\t\t/* Qt defines it in qglobal.h */\ntypedef long INT32;\n#endif\n#endif\n#endif\n#endif\n\n/* Datatype used for image dimensions.  The JPEG standard only supports\n * images up to 64K*64K due to 16-bit fields in SOF markers.  Therefore\n * \"unsigned int\" is sufficient on all machines.  However, if you need to\n * handle larger images and you don't mind deviating from the spec, you\n * can change this datatype.\n */\n\ntypedef unsigned int JDIMENSION;\n\n#define JPEG_MAX_DIMENSION  65500L  /* a tad under 64K to prevent overflows */\n\n\n/* These macros are used in all function definitions and extern declarations.\n * You could modify them if you need to change function linkage conventions;\n * in particular, you'll need to do that to make the library a Windows DLL.\n * Another application is to make all functions global for use with debuggers\n * or code profilers that require it.\n */\n\n/* a function called through method pointers: */\n#define METHODDEF(type)\t\tstatic type\n/* a function used only in its module: */\n#define LOCAL(type)\t\tstatic type\n/* a function referenced thru EXTERNs: */\n#define GLOBAL(type)\t\ttype\n/* a reference to a GLOBAL function: */\n#define EXTERN(type)\t\textern type\n\n\n/* This macro is used to declare a \"method\", that is, a function pointer.\n * We want to supply prototype parameters if the compiler can cope.\n * Note that the arglist parameter must be parenthesized!\n * Again, you can customize this if you need special linkage keywords.\n */\n\n#ifdef HAVE_PROTOTYPES\n#define JMETHOD(type,methodname,arglist)  type (*methodname) arglist\n#else\n#define JMETHOD(type,methodname,arglist)  type (*methodname) ()\n#endif\n\n\n/* The noreturn type identifier is used to declare functions\n * which cannot return.\n * Compilers can thus create more optimized code and perform\n * better checks for warnings and errors.\n * Static analyzer tools can make improved inferences about\n * execution paths and are prevented from giving false alerts.\n *\n * Unfortunately, the proposed specifications of corresponding\n * extensions in the Dec 2011 ISO C standard revision (C11),\n * GCC, MSVC, etc. are not viable.\n * Thus we introduce a user defined type to declare noreturn\n * functions at least for clarity.  A proper compiler would\n * have a suitable noreturn type to match in place of void.\n */\n\n#ifndef HAVE_NORETURN_T\ntypedef void noreturn_t;\n#endif\n\n\n/* Here is the pseudo-keyword for declaring pointers that must be \"far\"\n * on 80x86 machines.  Most of the specialized coding for 80x86 is handled\n * by just saying \"FAR *\" where such a pointer is needed.  In a few places\n * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.\n */\n\n#ifndef FAR\n#ifdef NEED_FAR_POINTERS\n#define FAR  far\n#else\n#define FAR\n#endif\n#endif\n\n\n/*\n * On a few systems, type boolean and/or its values FALSE, TRUE may appear\n * in standard header files.  Or you may have conflicts with application-\n * specific header files that you want to include together with these files.\n * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.\n */\n\n#ifndef HAVE_BOOLEAN\n#if defined FALSE || defined TRUE || defined QGLOBAL_H\n/* Qt3 defines FALSE and TRUE as \"const\" variables in qglobal.h */\ntypedef int boolean;\n#ifndef FALSE\t\t\t/* in case these macros already exist */\n#define FALSE\t0\t\t/* values of boolean */\n#endif\n#ifndef TRUE\n#define TRUE\t1\n#endif\n#else\ntypedef enum { FALSE = 0, TRUE = 1 } boolean;\n#endif\n#endif\n\n\n/*\n * The remaining options affect code selection within the JPEG library,\n * but they don't need to be visible to most applications using the library.\n * To minimize application namespace pollution, the symbols won't be\n * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.\n */\n\n#ifdef JPEG_INTERNALS\n#define JPEG_INTERNAL_OPTIONS\n#endif\n\n#ifdef JPEG_INTERNAL_OPTIONS\n\n\n/*\n * These defines indicate whether to include various optional functions.\n * Undefining some of these symbols will produce a smaller but less capable\n * library.  Note that you can leave certain source files out of the\n * compilation/linking process if you've #undef'd the corresponding symbols.\n * (You may HAVE to do that if your compiler doesn't like null source files.)\n */\n\n/* Capability options common to encoder and decoder: */\n\n#define DCT_ISLOW_SUPPORTED\t/* slow but accurate integer algorithm */\n#define DCT_IFAST_SUPPORTED\t/* faster, less accurate integer method */\n#define DCT_FLOAT_SUPPORTED\t/* floating-point: accurate, fast on fast HW */\n\n/* Encoder capability options: */\n\n#define C_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */\n#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */\n#define C_PROGRESSIVE_SUPPORTED\t    /* Progressive JPEG? (Requires MULTISCAN)*/\n#define DCT_SCALING_SUPPORTED\t    /* Input rescaling via DCT? (Requires DCT_ISLOW)*/\n#define ENTROPY_OPT_SUPPORTED\t    /* Optimization of entropy coding parms? */\n/* Note: if you selected more than 8-bit data precision, it is dangerous to\n * turn off ENTROPY_OPT_SUPPORTED.  The standard Huffman tables are only\n * good for 8-bit precision, so arithmetic coding is recommended for higher\n * precision.  The Huffman encoder normally uses entropy optimization to\n * compute usable tables for higher precision.  Otherwise, you'll have to\n * supply different default Huffman tables.\n * The exact same statements apply for progressive JPEG: the default tables\n * don't work for progressive mode.  (This may get fixed, however.)\n */\n#define INPUT_SMOOTHING_SUPPORTED   /* Input image smoothing option? */\n\n/* Decoder capability options: */\n\n#define D_ARITH_CODING_SUPPORTED    /* Arithmetic coding back end? */\n#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */\n#define D_PROGRESSIVE_SUPPORTED\t    /* Progressive JPEG? (Requires MULTISCAN)*/\n#define IDCT_SCALING_SUPPORTED\t    /* Output rescaling via IDCT? (Requires DCT_ISLOW)*/\n#define SAVE_MARKERS_SUPPORTED\t    /* jpeg_save_markers() needed? */\n#define BLOCK_SMOOTHING_SUPPORTED   /* Block smoothing? (Progressive only) */\n#undef  UPSAMPLE_SCALING_SUPPORTED  /* Output rescaling at upsample stage? */\n#define UPSAMPLE_MERGING_SUPPORTED  /* Fast path for sloppy upsampling? */\n#define QUANT_1PASS_SUPPORTED\t    /* 1-pass color quantization? */\n#define QUANT_2PASS_SUPPORTED\t    /* 2-pass color quantization? */\n\n/* more capability options later, no doubt */\n\n\n/*\n * Ordering of RGB data in scanlines passed to or from the application.\n * If your application wants to deal with data in the order B,G,R, just\n * change these macros.  You can also deal with formats such as R,G,B,X\n * (one extra byte per pixel) by changing RGB_PIXELSIZE.  Note that changing\n * the offsets will also change the order in which colormap data is organized.\n * RESTRICTIONS:\n * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.\n * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE\n *    is not 3 (they don't understand about dummy color components!).  So you\n *    can't use color quantization if you change that value.\n */\n\n#define RGB_RED\t\t0\t/* Offset of Red in an RGB scanline element */\n#define RGB_GREEN\t1\t/* Offset of Green */\n#define RGB_BLUE\t2\t/* Offset of Blue */\n#define RGB_PIXELSIZE\t3\t/* JSAMPLEs per RGB scanline element */\n\n\n/* Definitions for speed-related optimizations. */\n\n\n/* If your compiler supports inline functions, define INLINE\n * as the inline keyword; otherwise define it as empty.\n */\n\n#ifndef INLINE\n#ifdef __GNUC__\t\t\t/* for instance, GNU C knows about inline */\n#define INLINE __inline__\n#endif\n#ifndef INLINE\n#define INLINE\t\t\t/* default is to define it as empty */\n#endif\n#endif\n\n\n/* On some machines (notably 68000 series) \"int\" is 32 bits, but multiplying\n * two 16-bit shorts is faster than multiplying two ints.  Define MULTIPLIER\n * as short on such a machine.  MULTIPLIER must be at least 16 bits wide.\n */\n\n#ifndef MULTIPLIER\n#define MULTIPLIER  int\t\t/* type for fastest integer multiply */\n#endif\n\n\n/* FAST_FLOAT should be either float or double, whichever is done faster\n * by your compiler.  (Note that this type is only used in the floating point\n * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)\n * Typically, float is faster in ANSI C compilers, while double is faster in\n * pre-ANSI compilers (because they insist on converting to double anyway).\n * The code below therefore chooses float if we have ANSI-style prototypes.\n */\n\n#ifndef FAST_FLOAT\n#ifdef HAVE_PROTOTYPES\n#define FAST_FLOAT  float\n#else\n#define FAST_FLOAT  double\n#endif\n#endif\n\n#endif /* JPEG_INTERNAL_OPTIONS */\n"
  },
  {
    "path": "dlib/external/libjpeg/jpegint.h",
    "content": "/*\n * jpegint.h\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 1997-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file provides common declarations for the various JPEG modules.\n * These declarations are considered internal to the JPEG library; most\n * applications using the library shouldn't need to include this file.\n */\n\n\n/* Declarations for both compression & decompression */\n\ntypedef enum {\t\t\t/* Operating modes for buffer controllers */\n\tJBUF_PASS_THRU,\t\t/* Plain stripwise operation */\n\t/* Remaining modes require a full-image buffer to have been created */\n\tJBUF_SAVE_SOURCE,\t/* Run source subobject only, save output */\n\tJBUF_CRANK_DEST,\t/* Run dest subobject only, using saved data */\n\tJBUF_SAVE_AND_PASS\t/* Run both subobjects, save output */\n} J_BUF_MODE;\n\n/* Values of global_state field (jdapi.c has some dependencies on ordering!) */\n#define CSTATE_START\t100\t/* after create_compress */\n#define CSTATE_SCANNING\t101\t/* start_compress done, write_scanlines OK */\n#define CSTATE_RAW_OK\t102\t/* start_compress done, write_raw_data OK */\n#define CSTATE_WRCOEFS\t103\t/* jpeg_write_coefficients done */\n#define DSTATE_START\t200\t/* after create_decompress */\n#define DSTATE_INHEADER\t201\t/* reading header markers, no SOS yet */\n#define DSTATE_READY\t202\t/* found SOS, ready for start_decompress */\n#define DSTATE_PRELOAD\t203\t/* reading multiscan file in start_decompress*/\n#define DSTATE_PRESCAN\t204\t/* performing dummy pass for 2-pass quant */\n#define DSTATE_SCANNING\t205\t/* start_decompress done, read_scanlines OK */\n#define DSTATE_RAW_OK\t206\t/* start_decompress done, read_raw_data OK */\n#define DSTATE_BUFIMAGE\t207\t/* expecting jpeg_start_output */\n#define DSTATE_BUFPOST\t208\t/* looking for SOS/EOI in jpeg_finish_output */\n#define DSTATE_RDCOEFS\t209\t/* reading file in jpeg_read_coefficients */\n#define DSTATE_STOPPING\t210\t/* looking for EOI in jpeg_finish_decompress */\n\n\n/* Declarations for compression modules */\n\n/* Master control module */\nstruct jpeg_comp_master {\n  JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));\n  JMETHOD(void, pass_startup, (j_compress_ptr cinfo));\n  JMETHOD(void, finish_pass, (j_compress_ptr cinfo));\n\n  /* State variables made visible to other modules */\n  boolean call_pass_startup;\t/* True if pass_startup must be called */\n  boolean is_last_pass;\t\t/* True during last pass */\n};\n\n/* Main buffer control (downsampled-data buffer) */\nstruct jpeg_c_main_controller {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));\n  JMETHOD(void, process_data, (j_compress_ptr cinfo,\n\t\t\t       JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,\n\t\t\t       JDIMENSION in_rows_avail));\n};\n\n/* Compression preprocessing (downsampling input buffer control) */\nstruct jpeg_c_prep_controller {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));\n  JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,\n\t\t\t\t   JSAMPARRAY input_buf,\n\t\t\t\t   JDIMENSION *in_row_ctr,\n\t\t\t\t   JDIMENSION in_rows_avail,\n\t\t\t\t   JSAMPIMAGE output_buf,\n\t\t\t\t   JDIMENSION *out_row_group_ctr,\n\t\t\t\t   JDIMENSION out_row_groups_avail));\n};\n\n/* Coefficient buffer control */\nstruct jpeg_c_coef_controller {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));\n  JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,\n\t\t\t\t   JSAMPIMAGE input_buf));\n};\n\n/* Colorspace conversion */\nstruct jpeg_color_converter {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo));\n  JMETHOD(void, color_convert, (j_compress_ptr cinfo,\n\t\t\t\tJSAMPARRAY input_buf, JSAMPIMAGE output_buf,\n\t\t\t\tJDIMENSION output_row, int num_rows));\n};\n\n/* Downsampling */\nstruct jpeg_downsampler {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo));\n  JMETHOD(void, downsample, (j_compress_ptr cinfo,\n\t\t\t     JSAMPIMAGE input_buf, JDIMENSION in_row_index,\n\t\t\t     JSAMPIMAGE output_buf,\n\t\t\t     JDIMENSION out_row_group_index));\n\n  boolean need_context_rows;\t/* TRUE if need rows above & below */\n};\n\n/* Forward DCT (also controls coefficient quantization) */\ntypedef JMETHOD(void, forward_DCT_ptr,\n\t\t(j_compress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JSAMPARRAY sample_data, JBLOCKROW coef_blocks,\n\t\t JDIMENSION start_col, JDIMENSION num_blocks));\n\nstruct jpeg_forward_dct {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo));\n  /* It is useful to allow each component to have a separate FDCT method. */\n  forward_DCT_ptr forward_DCT[MAX_COMPONENTS];\n};\n\n/* Entropy encoding */\nstruct jpeg_entropy_encoder {\n  JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));\n  JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKARRAY MCU_data));\n  JMETHOD(void, finish_pass, (j_compress_ptr cinfo));\n};\n\n/* Marker writing */\nstruct jpeg_marker_writer {\n  JMETHOD(void, write_file_header, (j_compress_ptr cinfo));\n  JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));\n  JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));\n  JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));\n  JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));\n  /* These routines are exported to allow insertion of extra markers */\n  /* Probably only COM and APPn markers should be written this way */\n  JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker,\n\t\t\t\t      unsigned int datalen));\n  JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));\n};\n\n\n/* Declarations for decompression modules */\n\n/* Master control module */\nstruct jpeg_decomp_master {\n  JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));\n  JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));\n\n  /* State variables made visible to other modules */\n  boolean is_dummy_pass;\t/* True during 1st pass for 2-pass quant */\n};\n\n/* Input control module */\nstruct jpeg_input_controller {\n  JMETHOD(int, consume_input, (j_decompress_ptr cinfo));\n  JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));\n  JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));\n  JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));\n\n  /* State variables made visible to other modules */\n  boolean has_multiple_scans;\t/* True if file has multiple scans */\n  boolean eoi_reached;\t\t/* True when EOI has been consumed */\n};\n\n/* Main buffer control (downsampled-data buffer) */\nstruct jpeg_d_main_controller {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));\n  JMETHOD(void, process_data, (j_decompress_ptr cinfo,\n\t\t\t       JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,\n\t\t\t       JDIMENSION out_rows_avail));\n};\n\n/* Coefficient buffer control */\nstruct jpeg_d_coef_controller {\n  JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));\n  JMETHOD(int, consume_data, (j_decompress_ptr cinfo));\n  JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));\n  JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,\n\t\t\t\t JSAMPIMAGE output_buf));\n  /* Pointer to array of coefficient virtual arrays, or NULL if none */\n  jvirt_barray_ptr *coef_arrays;\n};\n\n/* Decompression postprocessing (color quantization buffer control) */\nstruct jpeg_d_post_controller {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));\n  JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,\n\t\t\t\t    JSAMPIMAGE input_buf,\n\t\t\t\t    JDIMENSION *in_row_group_ctr,\n\t\t\t\t    JDIMENSION in_row_groups_avail,\n\t\t\t\t    JSAMPARRAY output_buf,\n\t\t\t\t    JDIMENSION *out_row_ctr,\n\t\t\t\t    JDIMENSION out_rows_avail));\n};\n\n/* Marker reading & parsing */\nstruct jpeg_marker_reader {\n  JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));\n  /* Read markers until SOS or EOI.\n   * Returns same codes as are defined for jpeg_consume_input:\n   * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.\n   */\n  JMETHOD(int, read_markers, (j_decompress_ptr cinfo));\n  /* Read a restart marker --- exported for use by entropy decoder only */\n  jpeg_marker_parser_method read_restart_marker;\n\n  /* State of marker reader --- nominally internal, but applications\n   * supplying COM or APPn handlers might like to know the state.\n   */\n  boolean saw_SOI;\t\t/* found SOI? */\n  boolean saw_SOF;\t\t/* found SOF? */\n  int next_restart_num;\t\t/* next restart number expected (0-7) */\n  unsigned int discarded_bytes;\t/* # of bytes skipped looking for a marker */\n};\n\n/* Entropy decoding */\nstruct jpeg_entropy_decoder {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));\n  JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKARRAY MCU_data));\n  JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));\n};\n\n/* Inverse DCT (also performs dequantization) */\ntypedef JMETHOD(void, inverse_DCT_method_ptr,\n\t\t(j_decompress_ptr cinfo, jpeg_component_info * compptr,\n\t\t JCOEFPTR coef_block,\n\t\t JSAMPARRAY output_buf, JDIMENSION output_col));\n\nstruct jpeg_inverse_dct {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));\n  /* It is useful to allow each component to have a separate IDCT method. */\n  inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];\n};\n\n/* Upsampling (note that upsampler must also call color converter) */\nstruct jpeg_upsampler {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));\n  JMETHOD(void, upsample, (j_decompress_ptr cinfo,\n\t\t\t   JSAMPIMAGE input_buf,\n\t\t\t   JDIMENSION *in_row_group_ctr,\n\t\t\t   JDIMENSION in_row_groups_avail,\n\t\t\t   JSAMPARRAY output_buf,\n\t\t\t   JDIMENSION *out_row_ctr,\n\t\t\t   JDIMENSION out_rows_avail));\n\n  boolean need_context_rows;\t/* TRUE if need rows above & below */\n};\n\n/* Colorspace conversion */\nstruct jpeg_color_deconverter {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo));\n  JMETHOD(void, color_convert, (j_decompress_ptr cinfo,\n\t\t\t\tJSAMPIMAGE input_buf, JDIMENSION input_row,\n\t\t\t\tJSAMPARRAY output_buf, int num_rows));\n};\n\n/* Color quantization or color precision reduction */\nstruct jpeg_color_quantizer {\n  JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));\n  JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,\n\t\t\t\t JSAMPARRAY input_buf, JSAMPARRAY output_buf,\n\t\t\t\t int num_rows));\n  JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));\n  JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));\n};\n\n\n/* Definition of range extension bits for decompression processes.\n * See the comments with prepare_range_limit_table (in jdmaster.c)\n * for more info.\n * The recommended default value for normal applications is 2.\n * Applications with special requirements may use a different value.\n * For example, Ghostscript wants to use 3 for proper handling of\n * wacky images with oversize coefficient values.\n */\n\n#define RANGE_BITS\t2\n#define RANGE_CENTER\t(CENTERJSAMPLE << RANGE_BITS)\n\n\n/* Miscellaneous useful macros */\n\n#undef MAX\n#define MAX(a,b)\t((a) > (b) ? (a) : (b))\n#undef MIN\n#define MIN(a,b)\t((a) < (b) ? (a) : (b))\n\n\n/* We assume that right shift corresponds to signed division by 2 with\n * rounding towards minus infinity.  This is correct for typical \"arithmetic\n * shift\" instructions that shift in copies of the sign bit.  But some\n * C compilers implement >> with an unsigned shift.  For these machines you\n * must define RIGHT_SHIFT_IS_UNSIGNED.\n * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.\n * It is only applied with constant shift counts.  SHIFT_TEMPS must be\n * included in the variables of any routine using RIGHT_SHIFT.\n */\n\n#ifdef RIGHT_SHIFT_IS_UNSIGNED\n#define SHIFT_TEMPS\tINT32 shift_temp;\n#define RIGHT_SHIFT(x,shft)  \\\n\t((shift_temp = (x)) < 0 ? \\\n\t (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \\\n\t (shift_temp >> (shft)))\n#else\n#define SHIFT_TEMPS\n#define RIGHT_SHIFT(x,shft)\t((x) >> (shft))\n#endif\n\n/* Descale and correctly round an INT32 value that's scaled by N bits.\n * We assume RIGHT_SHIFT rounds towards minus infinity, so adding\n * the fudge factor is correct for either sign of X.\n */\n\n#define DESCALE(x,n)\tRIGHT_SHIFT((x) + ((INT32) 1 << ((n)-1)), n)\n\n\n/* Short forms of external names for systems with brain-damaged linkers. */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jinit_compress_master\tjICompress\n#define jinit_c_master_control\tjICMaster\n#define jinit_c_main_controller\tjICMainC\n#define jinit_c_prep_controller\tjICPrepC\n#define jinit_c_coef_controller\tjICCoefC\n#define jinit_color_converter\tjICColor\n#define jinit_downsampler\tjIDownsampler\n#define jinit_forward_dct\tjIFDCT\n#define jinit_huff_encoder\tjIHEncoder\n#define jinit_arith_encoder\tjIAEncoder\n#define jinit_marker_writer\tjIMWriter\n#define jinit_master_decompress\tjIDMaster\n#define jinit_d_main_controller\tjIDMainC\n#define jinit_d_coef_controller\tjIDCoefC\n#define jinit_d_post_controller\tjIDPostC\n#define jinit_input_controller\tjIInCtlr\n#define jinit_marker_reader\tjIMReader\n#define jinit_huff_decoder\tjIHDecoder\n#define jinit_arith_decoder\tjIADecoder\n#define jinit_inverse_dct\tjIIDCT\n#define jinit_upsampler\t\tjIUpsampler\n#define jinit_color_deconverter\tjIDColor\n#define jinit_1pass_quantizer\tjI1Quant\n#define jinit_2pass_quantizer\tjI2Quant\n#define jinit_merged_upsampler\tjIMUpsampler\n#define jinit_memory_mgr\tjIMemMgr\n#define jdiv_round_up\t\tjDivRound\n#define jround_up\t\tjRound\n#define jzero_far\t\tjZeroFar\n#define jcopy_sample_rows\tjCopySamples\n#define jcopy_block_row\t\tjCopyBlocks\n#define jpeg_zigzag_order\tjZIGTable\n#define jpeg_natural_order\tjZAGTable\n#define jpeg_natural_order7\tjZAG7Table\n#define jpeg_natural_order6\tjZAG6Table\n#define jpeg_natural_order5\tjZAG5Table\n#define jpeg_natural_order4\tjZAG4Table\n#define jpeg_natural_order3\tjZAG3Table\n#define jpeg_natural_order2\tjZAG2Table\n#define jpeg_aritab\t\tjAriTab\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n\n/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays\n * and coefficient-block arrays.  This won't work on 80x86 because the arrays\n * are FAR and we're assuming a small-pointer memory model.  However, some\n * DOS compilers provide far-pointer versions of memcpy() and memset() even\n * in the small-model libraries.  These will be used if USE_FMEM is defined.\n * Otherwise, the routines in jutils.c do it the hard way.\n */\n\n#ifndef NEED_FAR_POINTERS\t/* normal case, same as regular macro */\n#define FMEMZERO(target,size)\tMEMZERO(target,size)\n#else\t\t\t\t/* 80x86 case */\n#ifdef USE_FMEM\n#define FMEMZERO(target,size)\t_fmemset((void FAR *)(target), 0, (size_t)(size))\n#else\nEXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));\n#define FMEMZERO(target,size)\tjzero_far(target, size)\n#endif\n#endif\n\n\n/* Compression module initialization routines */\nEXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,\n\t\t\t\t\t boolean transcode_only));\nEXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo));\nEXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));\n/* Decompression module initialization routines */\nEXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t  boolean need_full_buffer));\nEXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));\nEXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));\n/* Memory manager initialization */\nEXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));\n\n/* Utility routines in jutils.c */\nEXTERN(long) jdiv_round_up JPP((long a, long b));\nEXTERN(long) jround_up JPP((long a, long b));\nEXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array,\n\t\t\t\t    JSAMPARRAY output_array,\n\t\t\t\t    int num_rows, JDIMENSION num_cols));\nEXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,\n\t\t\t\t  JDIMENSION num_blocks));\n/* Constant tables in jutils.c */\n#if 0\t\t\t\t/* This table is not actually needed in v6a */\nextern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */\n#endif\nextern const int jpeg_natural_order[]; /* zigzag coef order to natural order */\nextern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */\nextern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */\nextern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */\nextern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */\nextern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */\nextern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */\n\n/* Arithmetic coding probability estimation tables in jaricom.c */\nextern const INT32 jpeg_aritab[];\n\n/* Suppress undefined-structure complaints if necessary. */\n\n#ifdef INCOMPLETE_TYPES_BROKEN\n#ifndef AM_MEMORY_MANAGER\t/* only jmemmgr.c defines these */\nstruct jvirt_sarray_control { long dummy; };\nstruct jvirt_barray_control { long dummy; };\n#endif\n#endif /* INCOMPLETE_TYPES_BROKEN */\n"
  },
  {
    "path": "dlib/external/libjpeg/jpeglib.h",
    "content": "/*\n * jpeglib.h\n *\n * Copyright (C) 1991-1998, Thomas G. Lane.\n * Modified 2002-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file defines the application interface for the JPEG library.\n * Most applications using the library need only include this file,\n * and perhaps jerror.h if they want to know the exact error codes.\n */\n\n#ifndef JPEGLIB_H\n#define JPEGLIB_H\n\n/*\n * First we include the configuration files that record how this\n * installation of the JPEG library is set up.  jconfig.h can be\n * generated automatically for many systems.  jmorecfg.h contains\n * manual configuration options that most people need not worry about.\n */\n\n#ifndef JCONFIG_INCLUDED\t/* in case jinclude.h already did */\n#include \"jconfig.h\"\t\t/* widely used configuration options */\n#endif\n#include \"jmorecfg.h\"\t\t/* seldom changed options */\n\n\n#ifdef __cplusplus\n#ifndef DONT_USE_EXTERN_C\nextern \"C\" {\n#endif\n#endif\n\n/* Version IDs for the JPEG library.\n * Might be useful for tests like \"#if JPEG_LIB_VERSION >= 90\".\n */\n\n#define JPEG_LIB_VERSION        90\t/* Compatibility version 9.0 */\n#define JPEG_LIB_VERSION_MAJOR  9\n#define JPEG_LIB_VERSION_MINOR  5\n\n\n/* Various constants determining the sizes of things.\n * All of these are specified by the JPEG standard,\n * so don't change them if you want to be compatible.\n */\n\n#define DCTSIZE\t\t    8\t/* The basic DCT block is 8x8 coefficients */\n#define DCTSIZE2\t    64\t/* DCTSIZE squared; # of elements in a block */\n#define NUM_QUANT_TBLS      4\t/* Quantization tables are numbered 0..3 */\n#define NUM_HUFF_TBLS       4\t/* Huffman tables are numbered 0..3 */\n#define NUM_ARITH_TBLS      16\t/* Arith-coding tables are numbered 0..15 */\n#define MAX_COMPS_IN_SCAN   4\t/* JPEG limit on # of components in one scan */\n#define MAX_SAMP_FACTOR     4\t/* JPEG limit on sampling factors */\n/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;\n * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.\n * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU\n * to handle it.  We even let you do this from the jconfig.h file.  However,\n * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe\n * sometimes emits noncompliant files doesn't mean you should too.\n */\n#define C_MAX_BLOCKS_IN_MCU   10 /* compressor's limit on blocks per MCU */\n#ifndef D_MAX_BLOCKS_IN_MCU\n#define D_MAX_BLOCKS_IN_MCU   10 /* decompressor's limit on blocks per MCU */\n#endif\n\n\n/* Data structures for images (arrays of samples and of DCT coefficients).\n * On 80x86 machines, the image arrays are too big for near pointers,\n * but the pointer arrays can fit in near memory.\n */\n\ntypedef JSAMPLE FAR *JSAMPROW;\t/* ptr to one image row of pixel samples. */\ntypedef JSAMPROW *JSAMPARRAY;\t/* ptr to some rows (a 2-D sample array) */\ntypedef JSAMPARRAY *JSAMPIMAGE;\t/* a 3-D sample array: top index is color */\n\ntypedef JCOEF JBLOCK[DCTSIZE2];\t/* one block of coefficients */\ntypedef JBLOCK FAR *JBLOCKROW;\t/* pointer to one row of coefficient blocks */\ntypedef JBLOCKROW *JBLOCKARRAY;\t\t/* a 2-D array of coefficient blocks */\ntypedef JBLOCKARRAY *JBLOCKIMAGE;\t/* a 3-D array of coefficient blocks */\n\ntypedef JCOEF FAR *JCOEFPTR;\t/* useful in a couple of places */\n\n\n/* Types for JPEG compression parameters and working tables. */\n\n\n/* DCT coefficient quantization tables. */\n\ntypedef struct {\n  /* This array gives the coefficient quantizers in natural array order\n   * (not the zigzag order in which they are stored in a JPEG DQT marker).\n   * CAUTION: IJG versions prior to v6a kept this array in zigzag order.\n   */\n  UINT16 quantval[DCTSIZE2];\t/* quantization step for each coefficient */\n  /* This field is used only during compression.  It's initialized FALSE when\n   * the table is created, and set TRUE when it's been output to the file.\n   * You could suppress output of a table by setting this to TRUE.\n   * (See jpeg_suppress_tables for an example.)\n   */\n  boolean sent_table;\t\t/* TRUE when table has been output */\n} JQUANT_TBL;\n\n\n/* Huffman coding tables. */\n\ntypedef struct {\n  /* These two fields directly represent the contents of a JPEG DHT marker */\n  UINT8 bits[17];\t\t/* bits[k] = # of symbols with codes of */\n\t\t\t\t/* length k bits; bits[0] is unused */\n  UINT8 huffval[256];\t\t/* The symbols, in order of incr code length */\n  /* This field is used only during compression.  It's initialized FALSE when\n   * the table is created, and set TRUE when it's been output to the file.\n   * You could suppress output of a table by setting this to TRUE.\n   * (See jpeg_suppress_tables for an example.)\n   */\n  boolean sent_table;\t\t/* TRUE when table has been output */\n} JHUFF_TBL;\n\n\n/* Basic info about one component (color channel). */\n\ntypedef struct {\n  /* These values are fixed over the whole image. */\n  /* For compression, they must be supplied by parameter setup; */\n  /* for decompression, they are read from the SOF marker. */\n  int component_id;\t\t/* identifier for this component (0..255) */\n  int component_index;\t\t/* its index in SOF or cinfo->comp_info[] */\n  int h_samp_factor;\t\t/* horizontal sampling factor (1..4) */\n  int v_samp_factor;\t\t/* vertical sampling factor (1..4) */\n  int quant_tbl_no;\t\t/* quantization table selector (0..3) */\n  /* These values may vary between scans. */\n  /* For compression, they must be supplied by parameter setup; */\n  /* for decompression, they are read from the SOS marker. */\n  /* The decompressor output side may not use these variables. */\n  int dc_tbl_no;\t\t/* DC entropy table selector (0..3) */\n  int ac_tbl_no;\t\t/* AC entropy table selector (0..3) */\n\n  /* Remaining fields should be treated as private by applications. */\n\n  /* These values are computed during compression or decompression startup: */\n  /* Component's size in DCT blocks.\n   * Any dummy blocks added to complete an MCU are not counted; therefore\n   * these values do not depend on whether a scan is interleaved or not.\n   */\n  JDIMENSION width_in_blocks;\n  JDIMENSION height_in_blocks;\n  /* Size of a DCT block in samples,\n   * reflecting any scaling we choose to apply during the DCT step.\n   * Values from 1 to 16 are supported.\n   * Note that different components may receive different DCT scalings.\n   */\n  int DCT_h_scaled_size;\n  int DCT_v_scaled_size;\n  /* The downsampled dimensions are the component's actual, unpadded number\n   * of samples at the main buffer (preprocessing/compression interface);\n   * DCT scaling is included, so\n   * downsampled_width =\n   *   ceil(image_width * Hi/Hmax * DCT_h_scaled_size/block_size)\n   * and similarly for height.\n   */\n  JDIMENSION downsampled_width;\t /* actual width in samples */\n  JDIMENSION downsampled_height; /* actual height in samples */\n  /* For decompression, in cases where some of the components will be\n   * ignored (eg grayscale output from YCbCr image), we can skip most\n   * computations for the unused components.\n   * For compression, some of the components will need further quantization\n   * scale by factor of 2 after DCT (eg BG_YCC output from normal RGB input).\n   * The field is first set TRUE for decompression, FALSE for compression\n   * in initial_setup, and then adapted in color conversion setup.\n   */\n  boolean component_needed;\n\n  /* These values are computed before starting a scan of the component. */\n  /* The decompressor output side may not use these variables. */\n  int MCU_width;\t\t/* number of blocks per MCU, horizontally */\n  int MCU_height;\t\t/* number of blocks per MCU, vertically */\n  int MCU_blocks;\t\t/* MCU_width * MCU_height */\n  int MCU_sample_width;\t/* MCU width in samples: MCU_width * DCT_h_scaled_size */\n  int last_col_width;\t\t/* # of non-dummy blocks across in last MCU */\n  int last_row_height;\t\t/* # of non-dummy blocks down in last MCU */\n\n  /* Saved quantization table for component; NULL if none yet saved.\n   * See jdinput.c comments about the need for this information.\n   * This field is currently used only for decompression.\n   */\n  JQUANT_TBL * quant_table;\n\n  /* Private per-component storage for DCT or IDCT subsystem. */\n  void * dct_table;\n} jpeg_component_info;\n\n\n/* The script for encoding a multiple-scan file is an array of these: */\n\ntypedef struct {\n  int comps_in_scan;\t\t/* number of components encoded in this scan */\n  int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */\n  int Ss, Se;\t\t\t/* progressive JPEG spectral selection parms */\n  int Ah, Al;\t\t\t/* progressive JPEG successive approx. parms */\n} jpeg_scan_info;\n\n/* The decompressor can save APPn and COM markers in a list of these: */\n\ntypedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr;\n\nstruct jpeg_marker_struct {\n  jpeg_saved_marker_ptr next;\t/* next in list, or NULL */\n  UINT8 marker;\t\t\t/* marker code: JPEG_COM, or JPEG_APP0+n */\n  unsigned int original_length;\t/* # bytes of data in the file */\n  unsigned int data_length;\t/* # bytes of data saved at data[] */\n  JOCTET FAR * data;\t\t/* the data contained in the marker */\n  /* the marker length word is not counted in data_length or original_length */\n};\n\n/* Known color spaces. */\n\ntypedef enum {\n\tJCS_UNKNOWN,\t\t/* error/unspecified */\n\tJCS_GRAYSCALE,\t\t/* monochrome */\n\tJCS_RGB,\t\t/* red/green/blue, standard RGB (sRGB) */\n\tJCS_YCbCr,\t\t/* Y/Cb/Cr (also known as YUV), standard YCC */\n\tJCS_CMYK,\t\t/* C/M/Y/K */\n\tJCS_YCCK,\t\t/* Y/Cb/Cr/K */\n\tJCS_BG_RGB,\t\t/* big gamut red/green/blue, bg-sRGB */\n\tJCS_BG_YCC\t\t/* big gamut Y/Cb/Cr, bg-sYCC */\n} J_COLOR_SPACE;\n\n/* Supported color transforms. */\n\ntypedef enum {\n\tJCT_NONE           = 0,\n\tJCT_SUBTRACT_GREEN = 1\n} J_COLOR_TRANSFORM;\n\n/* DCT/IDCT algorithm options. */\n\ntypedef enum {\n\tJDCT_ISLOW,\t\t/* slow but accurate integer algorithm */\n\tJDCT_IFAST,\t\t/* faster, less accurate integer method */\n\tJDCT_FLOAT\t\t/* floating-point: accurate, fast on fast HW */\n} J_DCT_METHOD;\n\n#ifndef JDCT_DEFAULT\t\t/* may be overridden in jconfig.h */\n#define JDCT_DEFAULT  JDCT_ISLOW\n#endif\n#ifndef JDCT_FASTEST\t\t/* may be overridden in jconfig.h */\n#define JDCT_FASTEST  JDCT_IFAST\n#endif\n\n/* Dithering options for decompression. */\n\ntypedef enum {\n\tJDITHER_NONE,\t\t/* no dithering */\n\tJDITHER_ORDERED,\t/* simple ordered dither */\n\tJDITHER_FS\t\t/* Floyd-Steinberg error diffusion dither */\n} J_DITHER_MODE;\n\n\n/* Common fields between JPEG compression and decompression master structs. */\n\n#define jpeg_common_fields \\\n  struct jpeg_error_mgr * err;\t/* Error handler module */\\\n  struct jpeg_memory_mgr * mem;\t/* Memory manager module */\\\n  struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\\\n  void * client_data;\t\t/* Available for use by application */\\\n  boolean is_decompressor;\t/* So common code can tell which is which */\\\n  int global_state\t\t/* For checking call sequence validity */\n\n/* Routines that are to be used by both halves of the library are declared\n * to receive a pointer to this structure.  There are no actual instances of\n * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.\n */\nstruct jpeg_common_struct {\n  jpeg_common_fields;\t\t/* Fields common to both master struct types */\n  /* Additional fields follow in an actual jpeg_compress_struct or\n   * jpeg_decompress_struct.  All three structs must agree on these\n   * initial fields!  (This would be a lot cleaner in C++.)\n   */\n};\n\ntypedef struct jpeg_common_struct * j_common_ptr;\ntypedef struct jpeg_compress_struct * j_compress_ptr;\ntypedef struct jpeg_decompress_struct * j_decompress_ptr;\n\n\n/* Master record for a compression instance */\n\nstruct jpeg_compress_struct {\n  jpeg_common_fields;\t\t/* Fields shared with jpeg_decompress_struct */\n\n  /* Destination for compressed data */\n  struct jpeg_destination_mgr * dest;\n\n  /* Description of source image --- these fields must be filled in by\n   * outer application before starting compression.  in_color_space must\n   * be correct before you can even call jpeg_set_defaults().\n   */\n\n  JDIMENSION image_width;\t/* input image width */\n  JDIMENSION image_height;\t/* input image height */\n  int input_components;\t\t/* # of color components in input image */\n  J_COLOR_SPACE in_color_space;\t/* colorspace of input image */\n\n  double input_gamma;\t\t/* image gamma of input image */\n\n  /* Compression parameters --- these fields must be set before calling\n   * jpeg_start_compress().  We recommend calling jpeg_set_defaults() to\n   * initialize everything to reasonable defaults, then changing anything\n   * the application specifically wants to change.  That way you won't get\n   * burnt when new parameters are added.  Also note that there are several\n   * helper routines to simplify changing parameters.\n   */\n\n  unsigned int scale_num, scale_denom; /* fraction by which to scale image */\n\n  JDIMENSION jpeg_width;\t/* scaled JPEG image width */\n  JDIMENSION jpeg_height;\t/* scaled JPEG image height */\n  /* Dimensions of actual JPEG image that will be written to file,\n   * derived from input dimensions by scaling factors above.\n   * These fields are computed by jpeg_start_compress().\n   * You can also use jpeg_calc_jpeg_dimensions() to determine these values\n   * in advance of calling jpeg_start_compress().\n   */\n\n  int data_precision;\t\t/* bits of precision in image data */\n\n  int num_components;\t\t/* # of color components in JPEG image */\n  J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */\n\n  jpeg_component_info * comp_info;\n  /* comp_info[i] describes component that appears i'th in SOF */\n\n  JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];\n  int q_scale_factor[NUM_QUANT_TBLS];\n  /* ptrs to coefficient quantization tables, or NULL if not defined,\n   * and corresponding scale factors (percentage, initialized 100).\n   */\n\n  JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];\n  JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];\n  /* ptrs to Huffman coding tables, or NULL if not defined */\n\n  UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */\n  UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */\n  UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */\n\n  int num_scans;\t\t/* # of entries in scan_info array */\n  const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */\n  /* The default value of scan_info is NULL, which causes a single-scan\n   * sequential JPEG file to be emitted.  To create a multi-scan file,\n   * set num_scans and scan_info to point to an array of scan definitions.\n   */\n\n  boolean raw_data_in;\t\t/* TRUE=caller supplies downsampled data */\n  boolean arith_code;\t\t/* TRUE=arithmetic coding, FALSE=Huffman */\n  boolean optimize_coding;\t/* TRUE=optimize entropy encoding parms */\n  boolean CCIR601_sampling;\t/* TRUE=first samples are cosited */\n  boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */\n  int smoothing_factor;\t\t/* 1..100, or 0 for no input smoothing */\n  J_DCT_METHOD dct_method;\t/* DCT algorithm selector */\n\n  /* The restart interval can be specified in absolute MCUs by setting\n   * restart_interval, or in MCU rows by setting restart_in_rows\n   * (in which case the correct restart_interval will be figured\n   * for each scan).\n   */\n  unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */\n  int restart_in_rows;\t\t/* if > 0, MCU rows per restart interval */\n\n  /* Parameters controlling emission of special markers. */\n\n  boolean write_JFIF_header;\t/* should a JFIF marker be written? */\n  UINT8 JFIF_major_version;\t/* What to write for the JFIF version number */\n  UINT8 JFIF_minor_version;\n  /* These three values are not used by the JPEG code, merely copied */\n  /* into the JFIF APP0 marker.  density_unit can be 0 for unknown, */\n  /* 1 for dots/inch, or 2 for dots/cm.  Note that the pixel aspect */\n  /* ratio is defined by X_density/Y_density even when density_unit=0. */\n  UINT8 density_unit;\t\t/* JFIF code for pixel size units */\n  UINT16 X_density;\t\t/* Horizontal pixel density */\n  UINT16 Y_density;\t\t/* Vertical pixel density */\n  boolean write_Adobe_marker;\t/* should an Adobe marker be written? */\n\n  J_COLOR_TRANSFORM color_transform;\n  /* Color transform identifier, writes LSE marker if nonzero */\n\n  /* State variable: index of next scanline to be written to\n   * jpeg_write_scanlines().  Application may use this to control its\n   * processing loop, e.g., \"while (next_scanline < image_height)\".\n   */\n\n  JDIMENSION next_scanline;\t/* 0 .. image_height-1  */\n\n  /* Remaining fields are known throughout compressor, but generally\n   * should not be touched by a surrounding application.\n   */\n\n  /*\n   * These fields are computed during compression startup\n   */\n  boolean progressive_mode;\t/* TRUE if scan script uses progressive mode */\n  int max_h_samp_factor;\t/* largest h_samp_factor */\n  int max_v_samp_factor;\t/* largest v_samp_factor */\n\n  int min_DCT_h_scaled_size;\t/* smallest DCT_h_scaled_size of any component */\n  int min_DCT_v_scaled_size;\t/* smallest DCT_v_scaled_size of any component */\n\n  JDIMENSION total_iMCU_rows;\t/* # of iMCU rows to be input to coef ctlr */\n  /* The coefficient controller receives data in units of MCU rows as defined\n   * for fully interleaved scans (whether the JPEG file is interleaved or not).\n   * There are v_samp_factor * DCT_v_scaled_size sample rows of each component\n   * in an \"iMCU\" (interleaved MCU) row.\n   */\n\n  /*\n   * These fields are valid during any one scan.\n   * They describe the components and MCUs actually appearing in the scan.\n   */\n  int comps_in_scan;\t\t/* # of JPEG components in this scan */\n  jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];\n  /* *cur_comp_info[i] describes component that appears i'th in SOS */\n\n  JDIMENSION MCUs_per_row;\t/* # of MCUs across the image */\n  JDIMENSION MCU_rows_in_scan;\t/* # of MCU rows in the image */\n\n  int blocks_in_MCU;\t\t/* # of DCT blocks per MCU */\n  int MCU_membership[C_MAX_BLOCKS_IN_MCU];\n  /* MCU_membership[i] is index in cur_comp_info of component owning */\n  /* i'th block in an MCU */\n\n  int Ss, Se, Ah, Al;\t\t/* progressive JPEG parameters for scan */\n\n  int block_size;\t\t/* the basic DCT block size: 1..16 */\n  const int * natural_order;\t/* natural-order position array */\n  int lim_Se;\t\t\t/* min( Se, DCTSIZE2-1 ) */\n\n  /*\n   * Links to compression subobjects (methods and private variables of modules)\n   */\n  struct jpeg_comp_master * master;\n  struct jpeg_c_main_controller * main;\n  struct jpeg_c_prep_controller * prep;\n  struct jpeg_c_coef_controller * coef;\n  struct jpeg_marker_writer * marker;\n  struct jpeg_color_converter * cconvert;\n  struct jpeg_downsampler * downsample;\n  struct jpeg_forward_dct * fdct;\n  struct jpeg_entropy_encoder * entropy;\n  jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */\n  int script_space_size;\n};\n\n\n/* Master record for a decompression instance */\n\nstruct jpeg_decompress_struct {\n  jpeg_common_fields;\t\t/* Fields shared with jpeg_compress_struct */\n\n  /* Source of compressed data */\n  struct jpeg_source_mgr * src;\n\n  /* Basic description of image --- filled in by jpeg_read_header(). */\n  /* Application may inspect these values to decide how to process image. */\n\n  JDIMENSION image_width;\t/* nominal image width (from SOF marker) */\n  JDIMENSION image_height;\t/* nominal image height */\n  int num_components;\t\t/* # of color components in JPEG image */\n  J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */\n\n  /* Decompression processing parameters --- these fields must be set before\n   * calling jpeg_start_decompress().  Note that jpeg_read_header() initializes\n   * them to default values.\n   */\n\n  J_COLOR_SPACE out_color_space; /* colorspace for output */\n\n  unsigned int scale_num, scale_denom; /* fraction by which to scale image */\n\n  double output_gamma;\t\t/* image gamma wanted in output */\n\n  boolean buffered_image;\t/* TRUE=multiple output passes */\n  boolean raw_data_out;\t\t/* TRUE=downsampled data wanted */\n\n  J_DCT_METHOD dct_method;\t/* IDCT algorithm selector */\n  boolean do_fancy_upsampling;\t/* TRUE=apply fancy upsampling */\n  boolean do_block_smoothing;\t/* TRUE=apply interblock smoothing */\n\n  boolean quantize_colors;\t/* TRUE=colormapped output wanted */\n  /* the following are ignored if not quantize_colors: */\n  J_DITHER_MODE dither_mode;\t/* type of color dithering to use */\n  boolean two_pass_quantize;\t/* TRUE=use two-pass color quantization */\n  int desired_number_of_colors;\t/* max # colors to use in created colormap */\n  /* these are significant only in buffered-image mode: */\n  boolean enable_1pass_quant;\t/* enable future use of 1-pass quantizer */\n  boolean enable_external_quant;/* enable future use of external colormap */\n  boolean enable_2pass_quant;\t/* enable future use of 2-pass quantizer */\n\n  /* Description of actual output image that will be returned to application.\n   * These fields are computed by jpeg_start_decompress().\n   * You can also use jpeg_calc_output_dimensions() to determine these values\n   * in advance of calling jpeg_start_decompress().\n   */\n\n  JDIMENSION output_width;\t/* scaled image width */\n  JDIMENSION output_height;\t/* scaled image height */\n  int out_color_components;\t/* # of color components in out_color_space */\n  int output_components;\t/* # of color components returned */\n  /* output_components is 1 (a colormap index) when quantizing colors;\n   * otherwise it equals out_color_components.\n   */\n  int rec_outbuf_height;\t/* min recommended height of scanline buffer */\n  /* If the buffer passed to jpeg_read_scanlines() is less than this many rows\n   * high, space and time will be wasted due to unnecessary data copying.\n   * Usually rec_outbuf_height will be 1 or 2, at most 4.\n   */\n\n  /* When quantizing colors, the output colormap is described by these fields.\n   * The application can supply a colormap by setting colormap non-NULL before\n   * calling jpeg_start_decompress; otherwise a colormap is created during\n   * jpeg_start_decompress or jpeg_start_output.\n   * The map has out_color_components rows and actual_number_of_colors columns.\n   */\n  int actual_number_of_colors;\t/* number of entries in use */\n  JSAMPARRAY colormap;\t\t/* The color map as a 2-D pixel array */\n\n  /* State variables: these variables indicate the progress of decompression.\n   * The application may examine these but must not modify them.\n   */\n\n  /* Row index of next scanline to be read from jpeg_read_scanlines().\n   * Application may use this to control its processing loop, e.g.,\n   * \"while (output_scanline < output_height)\".\n   */\n  JDIMENSION output_scanline;\t/* 0 .. output_height-1  */\n\n  /* Current input scan number and number of iMCU rows completed in scan.\n   * These indicate the progress of the decompressor input side.\n   */\n  int input_scan_number;\t/* Number of SOS markers seen so far */\n  JDIMENSION input_iMCU_row;\t/* Number of iMCU rows completed */\n\n  /* The \"output scan number\" is the notional scan being displayed by the\n   * output side.  The decompressor will not allow output scan/row number\n   * to get ahead of input scan/row, but it can fall arbitrarily far behind.\n   */\n  int output_scan_number;\t/* Nominal scan number being displayed */\n  JDIMENSION output_iMCU_row;\t/* Number of iMCU rows read */\n\n  /* Current progression status.  coef_bits[c][i] indicates the precision\n   * with which component c's DCT coefficient i (in zigzag order) is known.\n   * It is -1 when no data has yet been received, otherwise it is the point\n   * transform (shift) value for the most recent scan of the coefficient\n   * (thus, 0 at completion of the progression).\n   * This pointer is NULL when reading a non-progressive file.\n   */\n  int (*coef_bits)[DCTSIZE2];\t/* -1 or current Al value for each coef */\n\n  /* Internal JPEG parameters --- the application usually need not look at\n   * these fields.  Note that the decompressor output side may not use\n   * any parameters that can change between scans.\n   */\n\n  /* Quantization and Huffman tables are carried forward across input\n   * datastreams when processing abbreviated JPEG datastreams.\n   */\n\n  JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];\n  /* ptrs to coefficient quantization tables, or NULL if not defined */\n\n  JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];\n  JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];\n  /* ptrs to Huffman coding tables, or NULL if not defined */\n\n  /* These parameters are never carried across datastreams, since they\n   * are given in SOF/SOS markers or defined to be reset by SOI.\n   */\n\n  int data_precision;\t\t/* bits of precision in image data */\n\n  jpeg_component_info * comp_info;\n  /* comp_info[i] describes component that appears i'th in SOF */\n\n  boolean is_baseline;\t\t/* TRUE if Baseline SOF0 encountered */\n  boolean progressive_mode;\t/* TRUE if SOFn specifies progressive mode */\n  boolean arith_code;\t\t/* TRUE=arithmetic coding, FALSE=Huffman */\n\n  UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */\n  UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */\n  UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */\n\n  unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */\n\n  /* These fields record data obtained from optional markers recognized by\n   * the JPEG library.\n   */\n  boolean saw_JFIF_marker;\t/* TRUE iff a JFIF APP0 marker was found */\n  /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */\n  UINT8 JFIF_major_version;\t/* JFIF version number */\n  UINT8 JFIF_minor_version;\n  UINT8 density_unit;\t\t/* JFIF code for pixel size units */\n  UINT16 X_density;\t\t/* Horizontal pixel density */\n  UINT16 Y_density;\t\t/* Vertical pixel density */\n  boolean saw_Adobe_marker;\t/* TRUE iff an Adobe APP14 marker was found */\n  UINT8 Adobe_transform;\t/* Color transform code from Adobe marker */\n\n  J_COLOR_TRANSFORM color_transform;\n  /* Color transform identifier derived from LSE marker, otherwise zero */\n\n  boolean CCIR601_sampling;\t/* TRUE=first samples are cosited */\n\n  /* Aside from the specific data retained from APPn markers known to the\n   * library, the uninterpreted contents of any or all APPn and COM markers\n   * can be saved in a list for examination by the application.\n   */\n  jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */\n\n  /* Remaining fields are known throughout decompressor, but generally\n   * should not be touched by a surrounding application.\n   */\n\n  /*\n   * These fields are computed during decompression startup\n   */\n  int max_h_samp_factor;\t/* largest h_samp_factor */\n  int max_v_samp_factor;\t/* largest v_samp_factor */\n\n  int min_DCT_h_scaled_size;\t/* smallest DCT_h_scaled_size of any component */\n  int min_DCT_v_scaled_size;\t/* smallest DCT_v_scaled_size of any component */\n\n  JDIMENSION total_iMCU_rows;\t/* # of iMCU rows in image */\n  /* The coefficient controller's input and output progress is measured in\n   * units of \"iMCU\" (interleaved MCU) rows.  These are the same as MCU rows\n   * in fully interleaved JPEG scans, but are used whether the scan is\n   * interleaved or not.  We define an iMCU row as v_samp_factor DCT block\n   * rows of each component.  Therefore, the IDCT output contains\n   * v_samp_factor * DCT_v_scaled_size sample rows of a component per iMCU row.\n   */\n\n  JSAMPLE * sample_range_limit; /* table for fast range-limiting */\n\n  /*\n   * These fields are valid during any one scan.\n   * They describe the components and MCUs actually appearing in the scan.\n   * Note that the decompressor output side must not use these fields.\n   */\n  int comps_in_scan;\t\t/* # of JPEG components in this scan */\n  jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];\n  /* *cur_comp_info[i] describes component that appears i'th in SOS */\n\n  JDIMENSION MCUs_per_row;\t/* # of MCUs across the image */\n  JDIMENSION MCU_rows_in_scan;\t/* # of MCU rows in the image */\n\n  int blocks_in_MCU;\t\t/* # of DCT blocks per MCU */\n  int MCU_membership[D_MAX_BLOCKS_IN_MCU];\n  /* MCU_membership[i] is index in cur_comp_info of component owning */\n  /* i'th block in an MCU */\n\n  int Ss, Se, Ah, Al;\t\t/* progressive JPEG parameters for scan */\n\n  /* These fields are derived from Se of first SOS marker.\n   */\n  int block_size;\t\t/* the basic DCT block size: 1..16 */\n  const int * natural_order; /* natural-order position array for entropy decode */\n  int lim_Se;\t\t\t/* min( Se, DCTSIZE2-1 ) for entropy decode */\n\n  /* This field is shared between entropy decoder and marker parser.\n   * It is either zero or the code of a JPEG marker that has been\n   * read from the data source, but has not yet been processed.\n   */\n  int unread_marker;\n\n  /*\n   * Links to decompression subobjects (methods, private variables of modules)\n   */\n  struct jpeg_decomp_master * master;\n  struct jpeg_d_main_controller * main;\n  struct jpeg_d_coef_controller * coef;\n  struct jpeg_d_post_controller * post;\n  struct jpeg_input_controller * inputctl;\n  struct jpeg_marker_reader * marker;\n  struct jpeg_entropy_decoder * entropy;\n  struct jpeg_inverse_dct * idct;\n  struct jpeg_upsampler * upsample;\n  struct jpeg_color_deconverter * cconvert;\n  struct jpeg_color_quantizer * cquantize;\n};\n\n\n/* \"Object\" declarations for JPEG modules that may be supplied or called\n * directly by the surrounding application.\n * As with all objects in the JPEG library, these structs only define the\n * publicly visible methods and state variables of a module.  Additional\n * private fields may exist after the public ones.\n */\n\n\n/* Error handler object */\n\nstruct jpeg_error_mgr {\n  /* Error exit handler: does not return to caller */\n  JMETHOD(noreturn_t, error_exit, (j_common_ptr cinfo));\n  /* Conditionally emit a trace or warning message */\n  JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));\n  /* Routine that actually outputs a trace or error message */\n  JMETHOD(void, output_message, (j_common_ptr cinfo));\n  /* Format a message string for the most recent JPEG error or message */\n  JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));\n#define JMSG_LENGTH_MAX  200\t/* recommended size of format_message buffer */\n  /* Reset error state variables at start of a new image */\n  JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));\n\n  /* The message ID code and any parameters are saved here.\n   * A message can have one string parameter or up to 8 int parameters.\n   */\n  int msg_code;\n#define JMSG_STR_PARM_MAX  80\n  union {\n    int i[8];\n    char s[JMSG_STR_PARM_MAX];\n  } msg_parm;\n\n  /* Standard state variables for error facility */\n\n  int trace_level;\t\t/* max msg_level that will be displayed */\n\n  /* For recoverable corrupt-data errors, we emit a warning message,\n   * but keep going unless emit_message chooses to abort.  emit_message\n   * should count warnings in num_warnings.  The surrounding application\n   * can check for bad data by seeing if num_warnings is nonzero at the\n   * end of processing.\n   */\n  long num_warnings;\t\t/* number of corrupt-data warnings */\n\n  /* These fields point to the table(s) of error message strings.\n   * An application can change the table pointer to switch to a different\n   * message list (typically, to change the language in which errors are\n   * reported).  Some applications may wish to add additional error codes\n   * that will be handled by the JPEG library error mechanism; the second\n   * table pointer is used for this purpose.\n   *\n   * First table includes all errors generated by JPEG library itself.\n   * Error code 0 is reserved for a \"no such error string\" message.\n   */\n  const char * const * jpeg_message_table; /* Library errors */\n  int last_jpeg_message;    /* Table contains strings 0..last_jpeg_message */\n  /* Second table can be added by application (see cjpeg/djpeg for example).\n   * It contains strings numbered first_addon_message..last_addon_message.\n   */\n  const char * const * addon_message_table; /* Non-library errors */\n  int first_addon_message;\t/* code for first string in addon table */\n  int last_addon_message;\t/* code for last string in addon table */\n};\n\n\n/* Progress monitor object */\n\nstruct jpeg_progress_mgr {\n  JMETHOD(void, progress_monitor, (j_common_ptr cinfo));\n\n  long pass_counter;\t\t/* work units completed in this pass */\n  long pass_limit;\t\t/* total number of work units in this pass */\n  int completed_passes;\t\t/* passes completed so far */\n  int total_passes;\t\t/* total number of passes expected */\n};\n\n\n/* Data destination object for compression */\n\nstruct jpeg_destination_mgr {\n  JOCTET * next_output_byte;\t/* => next byte to write in buffer */\n  size_t free_in_buffer;\t/* # of byte spaces remaining in buffer */\n\n  JMETHOD(void, init_destination, (j_compress_ptr cinfo));\n  JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));\n  JMETHOD(void, term_destination, (j_compress_ptr cinfo));\n};\n\n\n/* Data source object for decompression */\n\nstruct jpeg_source_mgr {\n  const JOCTET * next_input_byte; /* => next byte to read from buffer */\n  size_t bytes_in_buffer;\t/* # of bytes remaining in buffer */\n\n  JMETHOD(void, init_source, (j_decompress_ptr cinfo));\n  JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));\n  JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));\n  JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));\n  JMETHOD(void, term_source, (j_decompress_ptr cinfo));\n};\n\n\n/* Memory manager object.\n * Allocates \"small\" objects (a few K total), \"large\" objects (tens of K),\n * and \"really big\" objects (virtual arrays with backing store if needed).\n * The memory manager does not allow individual objects to be freed; rather,\n * each created object is assigned to a pool, and whole pools can be freed\n * at once.  This is faster and more convenient than remembering exactly what\n * to free, especially where malloc()/free() are not too speedy.\n * NB: alloc routines never return NULL.  They exit to error_exit if not\n * successful.\n */\n\n#define JPOOL_PERMANENT\t0\t/* lasts until master record is destroyed */\n#define JPOOL_IMAGE\t1\t/* lasts until done with image/datastream */\n#define JPOOL_NUMPOOLS\t2\n\ntypedef struct jvirt_sarray_control * jvirt_sarray_ptr;\ntypedef struct jvirt_barray_control * jvirt_barray_ptr;\n\n\nstruct jpeg_memory_mgr {\n  /* Method pointers */\n  JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,\n\t\t\t\tsize_t sizeofobject));\n  JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,\n\t\t\t\t     size_t sizeofobject));\n  JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,\n\t\t\t\t     JDIMENSION samplesperrow,\n\t\t\t\t     JDIMENSION numrows));\n  JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,\n\t\t\t\t      JDIMENSION blocksperrow,\n\t\t\t\t      JDIMENSION numrows));\n  JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,\n\t\t\t\t\t\t  int pool_id,\n\t\t\t\t\t\t  boolean pre_zero,\n\t\t\t\t\t\t  JDIMENSION samplesperrow,\n\t\t\t\t\t\t  JDIMENSION numrows,\n\t\t\t\t\t\t  JDIMENSION maxaccess));\n  JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,\n\t\t\t\t\t\t  int pool_id,\n\t\t\t\t\t\t  boolean pre_zero,\n\t\t\t\t\t\t  JDIMENSION blocksperrow,\n\t\t\t\t\t\t  JDIMENSION numrows,\n\t\t\t\t\t\t  JDIMENSION maxaccess));\n  JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));\n  JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,\n\t\t\t\t\t   jvirt_sarray_ptr ptr,\n\t\t\t\t\t   JDIMENSION start_row,\n\t\t\t\t\t   JDIMENSION num_rows,\n\t\t\t\t\t   boolean writable));\n  JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,\n\t\t\t\t\t    jvirt_barray_ptr ptr,\n\t\t\t\t\t    JDIMENSION start_row,\n\t\t\t\t\t    JDIMENSION num_rows,\n\t\t\t\t\t    boolean writable));\n  JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));\n  JMETHOD(void, self_destruct, (j_common_ptr cinfo));\n\n  /* Limit on memory allocation for this JPEG object.  (Note that this is\n   * merely advisory, not a guaranteed maximum; it only affects the space\n   * used for virtual-array buffers.)  May be changed by outer application\n   * after creating the JPEG object.\n   */\n  long max_memory_to_use;\n\n  /* Maximum allocation request accepted by alloc_large. */\n  long max_alloc_chunk;\n};\n\n\n/* Routine signature for application-supplied marker processing methods.\n * Need not pass marker code since it is stored in cinfo->unread_marker.\n */\ntypedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));\n\n\n/* Declarations for routines called by application.\n * The JPP macro hides prototype parameters from compilers that can't cope.\n * Note JPP requires double parentheses.\n */\n\n#ifdef HAVE_PROTOTYPES\n#define JPP(arglist)\targlist\n#else\n#define JPP(arglist)\t()\n#endif\n\n\n/* Short forms of external names for systems with brain-damaged linkers.\n * We shorten external names to be unique in the first six letters, which\n * is good enough for all known systems.\n * (If your compiler itself needs names to be unique in less than 15 \n * characters, you are out of luck.  Get a better compiler.)\n */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jpeg_std_error\t\tjStdError\n#define jpeg_CreateCompress\tjCreaCompress\n#define jpeg_CreateDecompress\tjCreaDecompress\n#define jpeg_destroy_compress\tjDestCompress\n#define jpeg_destroy_decompress\tjDestDecompress\n#define jpeg_stdio_dest\t\tjStdDest\n#define jpeg_stdio_src\t\tjStdSrc\n#define jpeg_mem_dest\t\tjMemDest\n#define jpeg_mem_src\t\tjMemSrc\n#define jpeg_set_defaults\tjSetDefaults\n#define jpeg_set_colorspace\tjSetColorspace\n#define jpeg_default_colorspace\tjDefColorspace\n#define jpeg_set_quality\tjSetQuality\n#define jpeg_set_linear_quality\tjSetLQuality\n#define jpeg_default_qtables\tjDefQTables\n#define jpeg_add_quant_table\tjAddQuantTable\n#define jpeg_quality_scaling\tjQualityScaling\n#define jpeg_simple_progression\tjSimProgress\n#define jpeg_suppress_tables\tjSuppressTables\n#define jpeg_alloc_quant_table\tjAlcQTable\n#define jpeg_alloc_huff_table\tjAlcHTable\n#define jpeg_std_huff_table\tjStdHTable\n#define jpeg_start_compress\tjStrtCompress\n#define jpeg_write_scanlines\tjWrtScanlines\n#define jpeg_finish_compress\tjFinCompress\n#define jpeg_calc_jpeg_dimensions\tjCjpegDimensions\n#define jpeg_write_raw_data\tjWrtRawData\n#define jpeg_write_marker\tjWrtMarker\n#define jpeg_write_m_header\tjWrtMHeader\n#define jpeg_write_m_byte\tjWrtMByte\n#define jpeg_write_tables\tjWrtTables\n#define jpeg_read_header\tjReadHeader\n#define jpeg_start_decompress\tjStrtDecompress\n#define jpeg_read_scanlines\tjReadScanlines\n#define jpeg_finish_decompress\tjFinDecompress\n#define jpeg_read_raw_data\tjReadRawData\n#define jpeg_has_multiple_scans\tjHasMultScn\n#define jpeg_start_output\tjStrtOutput\n#define jpeg_finish_output\tjFinOutput\n#define jpeg_input_complete\tjInComplete\n#define jpeg_new_colormap\tjNewCMap\n#define jpeg_consume_input\tjConsumeInput\n#define jpeg_core_output_dimensions\tjCoreDimensions\n#define jpeg_calc_output_dimensions\tjCalcDimensions\n#define jpeg_save_markers\tjSaveMarkers\n#define jpeg_set_marker_processor\tjSetMarker\n#define jpeg_read_coefficients\tjReadCoefs\n#define jpeg_write_coefficients\tjWrtCoefs\n#define jpeg_copy_critical_parameters\tjCopyCrit\n#define jpeg_abort_compress\tjAbrtCompress\n#define jpeg_abort_decompress\tjAbrtDecompress\n#define jpeg_abort\t\tjAbort\n#define jpeg_destroy\t\tjDestroy\n#define jpeg_resync_to_restart\tjResyncRestart\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n\n/* Default error-management setup */\nEXTERN(struct jpeg_error_mgr *) jpeg_std_error\n\tJPP((struct jpeg_error_mgr * err));\n\n/* Initialization of JPEG compression objects.\n * jpeg_create_compress() and jpeg_create_decompress() are the exported\n * names that applications should call.  These expand to calls on\n * jpeg_CreateCompress and jpeg_CreateDecompress with additional information\n * passed for version mismatch checking.\n * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx.\n */\n#define jpeg_create_compress(cinfo) \\\n    jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \\\n\t\t\t(size_t) sizeof(struct jpeg_compress_struct))\n#define jpeg_create_decompress(cinfo) \\\n    jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \\\n\t\t\t  (size_t) sizeof(struct jpeg_decompress_struct))\nEXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo,\n\t\t\t\t      int version, size_t structsize));\nEXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo,\n\t\t\t\t\tint version, size_t structsize));\n/* Destruction of JPEG compression objects */\nEXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo));\nEXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));\n\n/* Standard data source and destination managers: stdio streams. */\n/* Caller is responsible for opening the file before and closing after. */\nEXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));\nEXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));\n\n/* Data source and destination managers: memory buffers. */\nEXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,\n\t\t\t       unsigned char ** outbuffer,\n\t\t\t       size_t * outsize));\nEXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,\n\t\t\t      const unsigned char * inbuffer,\n\t\t\t      size_t insize));\n\n/* Default parameter setup for compression */\nEXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));\n/* Compression parameter setup aids */\nEXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo,\n\t\t\t\t      J_COLOR_SPACE colorspace));\nEXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo));\nEXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,\n\t\t\t\t   boolean force_baseline));\nEXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,\n\t\t\t\t\t  int scale_factor,\n\t\t\t\t\t  boolean force_baseline));\nEXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo,\n\t\t\t\t       boolean force_baseline));\nEXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,\n\t\t\t\t       const unsigned int *basic_table,\n\t\t\t\t       int scale_factor,\n\t\t\t\t       boolean force_baseline));\nEXTERN(int) jpeg_quality_scaling JPP((int quality));\nEXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));\nEXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,\n\t\t\t\t       boolean suppress));\nEXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo));\nEXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo));\nEXTERN(JHUFF_TBL *) jpeg_std_huff_table JPP((j_common_ptr cinfo,\n\t\t\t\t\t     boolean isDC, int tblno));\n\n/* Main entry points for compression */\nEXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo,\n\t\t\t\t      boolean write_all_tables));\nEXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo,\n\t\t\t\t\t     JSAMPARRAY scanlines,\n\t\t\t\t\t     JDIMENSION num_lines));\nEXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));\n\n/* Precalculate JPEG dimensions for current compression parameters. */\nEXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo));\n\n/* Replaces jpeg_write_scanlines when writing raw downsampled data. */\nEXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,\n\t\t\t\t\t    JSAMPIMAGE data,\n\t\t\t\t\t    JDIMENSION num_lines));\n\n/* Write a special marker.  See libjpeg.txt concerning safe usage. */\nEXTERN(void) jpeg_write_marker\n\tJPP((j_compress_ptr cinfo, int marker,\n\t     const JOCTET * dataptr, unsigned int datalen));\n/* Same, but piecemeal. */\nEXTERN(void) jpeg_write_m_header\n\tJPP((j_compress_ptr cinfo, int marker, unsigned int datalen));\nEXTERN(void) jpeg_write_m_byte\n\tJPP((j_compress_ptr cinfo, int val));\n\n/* Alternate compression function: just write an abbreviated table file */\nEXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo));\n\n/* Decompression startup: read start of JPEG datastream to see what's there */\nEXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,\n\t\t\t\t  boolean require_image));\n/* Return value is one of: */\n#define JPEG_SUSPENDED\t\t0 /* Suspended due to lack of input data */\n#define JPEG_HEADER_OK\t\t1 /* Found valid image datastream */\n#define JPEG_HEADER_TABLES_ONLY\t2 /* Found valid table-specs-only datastream */\n/* If you pass require_image = TRUE (normal case), you need not check for\n * a TABLES_ONLY return code; an abbreviated file will cause an error exit.\n * JPEG_SUSPENDED is only possible if you use a data source module that can\n * give a suspension return (the stdio source module doesn't).\n */\n\n/* Main entry points for decompression */\nEXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));\nEXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t    JSAMPARRAY scanlines,\n\t\t\t\t\t    JDIMENSION max_lines));\nEXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo));\n\n/* Replaces jpeg_read_scanlines when reading raw downsampled data. */\nEXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t   JSAMPIMAGE data,\n\t\t\t\t\t   JDIMENSION max_lines));\n\n/* Additional entry points for buffered-image mode. */\nEXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));\nEXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,\n\t\t\t\t       int scan_number));\nEXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo));\nEXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo));\nEXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo));\nEXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo));\n/* Return value is one of: */\n/* #define JPEG_SUSPENDED\t0    Suspended due to lack of input data */\n#define JPEG_REACHED_SOS\t1 /* Reached start of new scan */\n#define JPEG_REACHED_EOI\t2 /* Reached end of image */\n#define JPEG_ROW_COMPLETED\t3 /* Completed one iMCU row */\n#define JPEG_SCAN_COMPLETED\t4 /* Completed last iMCU row of a scan */\n\n/* Precalculate output dimensions for current decompression parameters. */\nEXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo));\nEXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));\n\n/* Control saving of COM and APPn markers into marker_list. */\nEXTERN(void) jpeg_save_markers\n\tJPP((j_decompress_ptr cinfo, int marker_code,\n\t     unsigned int length_limit));\n\n/* Install a special processing method for COM or APPn markers. */\nEXTERN(void) jpeg_set_marker_processor\n\tJPP((j_decompress_ptr cinfo, int marker_code,\n\t     jpeg_marker_parser_method routine));\n\n/* Read or write raw DCT coefficients --- useful for lossless transcoding. */\nEXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo));\nEXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo,\n\t\t\t\t\t  jvirt_barray_ptr * coef_arrays));\nEXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo,\n\t\t\t\t\t\tj_compress_ptr dstinfo));\n\n/* If you choose to abort compression or decompression before completing\n * jpeg_finish_(de)compress, then you need to clean up to release memory,\n * temporary files, etc.  You can just call jpeg_destroy_(de)compress\n * if you're done with the JPEG object, but if you want to clean it up and\n * reuse it, call this:\n */\nEXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo));\nEXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo));\n\n/* Generic versions of jpeg_abort and jpeg_destroy that work on either\n * flavor of JPEG object.  These may be more convenient in some places.\n */\nEXTERN(void) jpeg_abort JPP((j_common_ptr cinfo));\nEXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));\n\n/* Default restart-marker-resync procedure for use by data source modules */\nEXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,\n\t\t\t\t\t    int desired));\n\n\n/* These marker codes are exported since applications and data source modules\n * are likely to want to use them.\n */\n\n#define JPEG_RST0\t0xD0\t/* RST0 marker code */\n#define JPEG_EOI\t0xD9\t/* EOI marker code */\n#define JPEG_APP0\t0xE0\t/* APP0 marker code */\n#define JPEG_COM\t0xFE\t/* COM marker code */\n\n\n/* If we have a brain-damaged compiler that emits warnings (or worse, errors)\n * for structure definitions that are never filled in, keep it quiet by\n * supplying dummy definitions for the various substructures.\n */\n\n#ifdef INCOMPLETE_TYPES_BROKEN\n#ifndef JPEG_INTERNALS\t\t/* will be defined in jpegint.h */\nstruct jvirt_sarray_control { long dummy; };\nstruct jvirt_barray_control { long dummy; };\nstruct jpeg_comp_master { long dummy; };\nstruct jpeg_c_main_controller { long dummy; };\nstruct jpeg_c_prep_controller { long dummy; };\nstruct jpeg_c_coef_controller { long dummy; };\nstruct jpeg_marker_writer { long dummy; };\nstruct jpeg_color_converter { long dummy; };\nstruct jpeg_downsampler { long dummy; };\nstruct jpeg_forward_dct { long dummy; };\nstruct jpeg_entropy_encoder { long dummy; };\nstruct jpeg_decomp_master { long dummy; };\nstruct jpeg_d_main_controller { long dummy; };\nstruct jpeg_d_coef_controller { long dummy; };\nstruct jpeg_d_post_controller { long dummy; };\nstruct jpeg_input_controller { long dummy; };\nstruct jpeg_marker_reader { long dummy; };\nstruct jpeg_entropy_decoder { long dummy; };\nstruct jpeg_inverse_dct { long dummy; };\nstruct jpeg_upsampler { long dummy; };\nstruct jpeg_color_deconverter { long dummy; };\nstruct jpeg_color_quantizer { long dummy; };\n#endif /* JPEG_INTERNALS */\n#endif /* INCOMPLETE_TYPES_BROKEN */\n\n\n/*\n * The JPEG library modules define JPEG_INTERNALS before including this file.\n * The internal structure declarations are read only when that is true.\n * Applications using the library should not include jpegint.h, but may wish\n * to include jerror.h.\n */\n\n#ifdef JPEG_INTERNALS\n#include \"jpegint.h\"\t\t/* fetch private declarations */\n#include \"jerror.h\"\t\t/* fetch error codes too */\n#endif\n\n#ifdef __cplusplus\n#ifndef DONT_USE_EXTERN_C\n}\n#endif\n#endif\n\n#endif /* JPEGLIB_H */\n"
  },
  {
    "path": "dlib/external/libjpeg/jpegtran.c",
    "content": "/*\n * jpegtran.c\n *\n * Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a command-line user interface for JPEG transcoding.\n * It is very similar to cjpeg.c, and partly to djpeg.c, but provides\n * lossless transcoding between different JPEG file formats.  It also\n * provides some lossless and sort-of-lossless transformations of JPEG data.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n#include \"transupp.h\"\t\t/* Support routines for jpegtran */\n#include \"jversion.h\"\t\t/* for version message */\n\n#ifdef USE_CCOMMAND\t\t/* command-line reader for Macintosh */\n#ifdef __MWERKS__\n#include <SIOUX.h>              /* Metrowerks needs this */\n#include <console.h>\t\t/* ... and this */\n#endif\n#ifdef THINK_C\n#include <console.h>\t\t/* Think declares it here */\n#endif\n#endif\n\n\n/*\n * Argument-parsing code.\n * The switch parser is designed to be useful with DOS-style command line\n * syntax, ie, intermixed switches and file names, where only the switches\n * to the left of a given file name affect processing of that file.\n * The main program in this file doesn't actually use this capability...\n */\n\n\nstatic const char * progname;\t/* program name for error messages */\nstatic char * outfilename;\t/* for -outfile switch */\nstatic char * dropfilename;\t/* for -drop switch */\nstatic char * scaleoption;\t/* -scale switch */\nstatic JCOPY_OPTION copyoption;\t/* -copy switch */\nstatic jpeg_transform_info transformoption; /* image transformation options */\n\n\nLOCAL(void)\nusage (void)\n/* complain about bad command line */\n{\n  fprintf(stderr, \"usage: %s [switches] \", progname);\n#ifdef TWO_FILE_COMMANDLINE\n  fprintf(stderr, \"inputfile outputfile\\n\");\n#else\n  fprintf(stderr, \"[inputfile]\\n\");\n#endif\n\n  fprintf(stderr, \"Switches (names may be abbreviated):\\n\");\n  fprintf(stderr, \"  -copy none     Copy no extra markers from source file\\n\");\n  fprintf(stderr, \"  -copy comments Copy only comment markers (default)\\n\");\n  fprintf(stderr, \"  -copy all      Copy all extra markers\\n\");\n#ifdef ENTROPY_OPT_SUPPORTED\n  fprintf(stderr, \"  -optimize      Optimize Huffman table (smaller file, but slow compression)\\n\");\n#endif\n#ifdef C_PROGRESSIVE_SUPPORTED\n  fprintf(stderr, \"  -progressive   Create progressive JPEG file\\n\");\n#endif\n  fprintf(stderr, \"Switches for modifying the image:\\n\");\n#if TRANSFORMS_SUPPORTED\n  fprintf(stderr, \"  -crop WxH+X+Y  Crop to a rectangular subarea\\n\");\n  fprintf(stderr, \"  -drop +X+Y filename          Drop another image\\n\");\n  fprintf(stderr, \"  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\\n\");\n  fprintf(stderr, \"  -grayscale     Reduce to grayscale (omit color data)\\n\");\n  fprintf(stderr, \"  -perfect       Fail if there is non-transformable edge blocks\\n\");\n  fprintf(stderr, \"  -rotate [90|180|270]         Rotate image (degrees clockwise)\\n\");\n#endif\n  fprintf(stderr, \"  -scale M/N     Scale output image by fraction M/N, eg, 1/8\\n\");\n#if TRANSFORMS_SUPPORTED\n  fprintf(stderr, \"  -transpose     Transpose image\\n\");\n  fprintf(stderr, \"  -transverse    Transverse transpose image\\n\");\n  fprintf(stderr, \"  -trim          Drop non-transformable edge blocks\\n\");\n  fprintf(stderr, \"                 with -drop: Requantize drop file to source file\\n\");\n  fprintf(stderr, \"  -wipe WxH+X+Y  Wipe (gray out) a rectangular subarea\\n\");\n#endif\n  fprintf(stderr, \"Switches for advanced users:\\n\");\n#ifdef C_ARITH_CODING_SUPPORTED\n  fprintf(stderr, \"  -arithmetic    Use arithmetic coding\\n\");\n#endif\n  fprintf(stderr, \"  -restart N     Set restart interval in rows, or in blocks with B\\n\");\n  fprintf(stderr, \"  -maxmemory N   Maximum memory to use (in kbytes)\\n\");\n  fprintf(stderr, \"  -outfile name  Specify name for output file\\n\");\n  fprintf(stderr, \"  -verbose  or  -debug   Emit debug output\\n\");\n  fprintf(stderr, \"Switches for wizards:\\n\");\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n  fprintf(stderr, \"  -scans file    Create multi-scan JPEG per script file\\n\");\n#endif\n  exit(EXIT_FAILURE);\n}\n\n\nLOCAL(void)\nselect_transform (JXFORM_CODE transform)\n/* Silly little routine to detect multiple transform options,\n * which we can't handle.\n */\n{\n#if TRANSFORMS_SUPPORTED\n  if (transformoption.transform == JXFORM_NONE ||\n      transformoption.transform == transform) {\n    transformoption.transform = transform;\n  } else {\n    fprintf(stderr, \"%s: can only do one image transformation at a time\\n\",\n\t    progname);\n    usage();\n  }\n#else\n  fprintf(stderr, \"%s: sorry, image transformation was not compiled\\n\",\n\t  progname);\n  exit(EXIT_FAILURE);\n#endif\n}\n\n\nLOCAL(int)\nparse_switches (j_compress_ptr cinfo, int argc, char **argv,\n\t\tint last_file_arg_seen, boolean for_real)\n/* Parse optional switches.\n * Returns argv[] index of first file-name argument (== argc if none).\n * Any file names with indexes <= last_file_arg_seen are ignored;\n * they have presumably been processed in a previous iteration.\n * (Pass 0 for last_file_arg_seen on the first or only iteration.)\n * for_real is FALSE on the first (dummy) pass; we may skip any expensive\n * processing.\n */\n{\n  int argn;\n  char * arg;\n  boolean simple_progressive;\n  char * scansarg = NULL;\t/* saves -scans parm if any */\n\n  /* Set up default JPEG parameters. */\n  simple_progressive = FALSE;\n  outfilename = NULL;\n  scaleoption = NULL;\n  copyoption = JCOPYOPT_DEFAULT;\n  transformoption.transform = JXFORM_NONE;\n  transformoption.perfect = FALSE;\n  transformoption.trim = FALSE;\n  transformoption.force_grayscale = FALSE;\n  transformoption.crop = FALSE;\n  cinfo->err->trace_level = 0;\n\n  /* Scan command line options, adjust parameters */\n\n  for (argn = 1; argn < argc; argn++) {\n    arg = argv[argn];\n    if (*arg != '-') {\n      /* Not a switch, must be a file name argument */\n      if (argn <= last_file_arg_seen) {\n\toutfilename = NULL;\t/* -outfile applies to just one input file */\n\tcontinue;\t\t/* ignore this name if previously processed */\n      }\n      break;\t\t\t/* else done parsing switches */\n    }\n    arg++;\t\t\t/* advance past switch marker character */\n\n    if (keymatch(arg, \"arithmetic\", 1)) {\n      /* Use arithmetic coding. */\n#ifdef C_ARITH_CODING_SUPPORTED\n      cinfo->arith_code = TRUE;\n#else\n      fprintf(stderr, \"%s: sorry, arithmetic coding not supported\\n\",\n\t      progname);\n      exit(EXIT_FAILURE);\n#endif\n\n    } else if (keymatch(arg, \"copy\", 2)) {\n      /* Select which extra markers to copy. */\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (keymatch(argv[argn], \"none\", 1)) {\n\tcopyoption = JCOPYOPT_NONE;\n      } else if (keymatch(argv[argn], \"comments\", 1)) {\n\tcopyoption = JCOPYOPT_COMMENTS;\n      } else if (keymatch(argv[argn], \"all\", 1)) {\n\tcopyoption = JCOPYOPT_ALL;\n      } else\n\tusage();\n\n    } else if (keymatch(arg, \"crop\", 2)) {\n      /* Perform lossless cropping. */\n#if TRANSFORMS_SUPPORTED\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||\n\t  ! jtransform_parse_crop_spec(&transformoption, argv[argn])) {\n\tfprintf(stderr, \"%s: bogus -crop argument '%s'\\n\",\n\t\tprogname, argv[argn]);\n\texit(EXIT_FAILURE);\n      }\n#else\n      select_transform(JXFORM_NONE);\t/* force an error */\n#endif\n\n    } else if (keymatch(arg, \"drop\", 2)) {\n#if TRANSFORMS_SUPPORTED\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||\n\t  ! jtransform_parse_crop_spec(&transformoption, argv[argn]) ||\n\t  transformoption.crop_width_set != JCROP_UNSET ||\n\t  transformoption.crop_height_set != JCROP_UNSET) {\n\tfprintf(stderr, \"%s: bogus -drop argument '%s'\\n\",\n\t\tprogname, argv[argn]);\n\texit(EXIT_FAILURE);\n      }\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      dropfilename = argv[argn];\n      select_transform(JXFORM_DROP);\n#else\n      select_transform(JXFORM_NONE);\t/* force an error */\n#endif\n\n    } else if (keymatch(arg, \"debug\", 1) || keymatch(arg, \"verbose\", 1)) {\n      /* Enable debug printouts. */\n      /* On first -d, print version identification */\n      static boolean printed_version = FALSE;\n\n      if (! printed_version) {\n\tfprintf(stderr, \"Independent JPEG Group's JPEGTRAN, version %s\\n%s\\n\",\n\t\tJVERSION, JCOPYRIGHT);\n\tprinted_version = TRUE;\n      }\n      cinfo->err->trace_level++;\n\n    } else if (keymatch(arg, \"flip\", 1)) {\n      /* Mirror left-right or top-bottom. */\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (keymatch(argv[argn], \"horizontal\", 1))\n\tselect_transform(JXFORM_FLIP_H);\n      else if (keymatch(argv[argn], \"vertical\", 1))\n\tselect_transform(JXFORM_FLIP_V);\n      else\n\tusage();\n\n    } else if (keymatch(arg, \"grayscale\", 1) || keymatch(arg, \"greyscale\",1)) {\n      /* Force to grayscale. */\n#if TRANSFORMS_SUPPORTED\n      transformoption.force_grayscale = TRUE;\n#else\n      select_transform(JXFORM_NONE);\t/* force an error */\n#endif\n\n    } else if (keymatch(arg, \"maxmemory\", 3)) {\n      /* Maximum memory in Kb (or Mb with 'm'). */\n      long lval;\n      char ch = 'x';\n\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (sscanf(argv[argn], \"%ld%c\", &lval, &ch) < 1)\n\tusage();\n      if (ch == 'm' || ch == 'M')\n\tlval *= 1000L;\n      cinfo->mem->max_memory_to_use = lval * 1000L;\n\n    } else if (keymatch(arg, \"optimize\", 1) || keymatch(arg, \"optimise\", 1)) {\n      /* Enable entropy parm optimization. */\n#ifdef ENTROPY_OPT_SUPPORTED\n      cinfo->optimize_coding = TRUE;\n#else\n      fprintf(stderr, \"%s: sorry, entropy optimization was not compiled\\n\",\n\t      progname);\n      exit(EXIT_FAILURE);\n#endif\n\n    } else if (keymatch(arg, \"outfile\", 4)) {\n      /* Set output file name. */\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      outfilename = argv[argn];\t/* save it away for later use */\n\n    } else if (keymatch(arg, \"perfect\", 2)) {\n      /* Fail if there is any partial edge MCUs that the transform can't\n       * handle. */\n      transformoption.perfect = TRUE;\n\n    } else if (keymatch(arg, \"progressive\", 2)) {\n      /* Select simple progressive mode. */\n#ifdef C_PROGRESSIVE_SUPPORTED\n      simple_progressive = TRUE;\n      /* We must postpone execution until num_components is known. */\n#else\n      fprintf(stderr, \"%s: sorry, progressive output was not compiled\\n\",\n\t      progname);\n      exit(EXIT_FAILURE);\n#endif\n\n    } else if (keymatch(arg, \"restart\", 1)) {\n      /* Restart interval in MCU rows (or in MCUs with 'b'). */\n      long lval;\n      char ch = 'x';\n\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (sscanf(argv[argn], \"%ld%c\", &lval, &ch) < 1)\n\tusage();\n      if (lval < 0 || lval > 65535L)\n\tusage();\n      if (ch == 'b' || ch == 'B') {\n\tcinfo->restart_interval = (unsigned int) lval;\n\tcinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */\n      } else {\n\tcinfo->restart_in_rows = (int) lval;\n\t/* restart_interval will be computed during startup */\n      }\n\n    } else if (keymatch(arg, \"rotate\", 2)) {\n      /* Rotate 90, 180, or 270 degrees (measured clockwise). */\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (keymatch(argv[argn], \"90\", 2))\n\tselect_transform(JXFORM_ROT_90);\n      else if (keymatch(argv[argn], \"180\", 3))\n\tselect_transform(JXFORM_ROT_180);\n      else if (keymatch(argv[argn], \"270\", 3))\n\tselect_transform(JXFORM_ROT_270);\n      else\n\tusage();\n\n    } else if (keymatch(arg, \"scale\", 4)) {\n      /* Scale the output image by a fraction M/N. */\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      scaleoption = argv[argn];\n      /* We must postpone processing until decompression startup. */\n\n    } else if (keymatch(arg, \"scans\", 1)) {\n      /* Set scan script. */\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      scansarg = argv[argn];\n      /* We must postpone reading the file in case -progressive appears. */\n#else\n      fprintf(stderr, \"%s: sorry, multi-scan output was not compiled\\n\",\n\t      progname);\n      exit(EXIT_FAILURE);\n#endif\n\n    } else if (keymatch(arg, \"transpose\", 1)) {\n      /* Transpose (across UL-to-LR axis). */\n      select_transform(JXFORM_TRANSPOSE);\n\n    } else if (keymatch(arg, \"transverse\", 6)) {\n      /* Transverse transpose (across UR-to-LL axis). */\n      select_transform(JXFORM_TRANSVERSE);\n\n    } else if (keymatch(arg, \"trim\", 3)) {\n      /* Trim off any partial edge MCUs that the transform can't handle. */\n      transformoption.trim = TRUE;\n\n    } else if (keymatch(arg, \"wipe\", 1)) {\n#if TRANSFORMS_SUPPORTED\n      if (++argn >= argc)\t/* advance to next argument */\n\tusage();\n      if (transformoption.crop /* reject multiple crop/drop/wipe requests */ ||\n\t  ! jtransform_parse_crop_spec(&transformoption, argv[argn])) {\n\tfprintf(stderr, \"%s: bogus -wipe argument '%s'\\n\",\n\t\tprogname, argv[argn]);\n\texit(EXIT_FAILURE);\n      }\n      select_transform(JXFORM_WIPE);\n#else\n      select_transform(JXFORM_NONE);\t/* force an error */\n#endif\n\n    } else {\n      usage();\t\t\t/* bogus switch */\n    }\n  }\n\n  /* Post-switch-scanning cleanup */\n\n  if (for_real) {\n\n#ifdef C_PROGRESSIVE_SUPPORTED\n    if (simple_progressive)\t/* process -progressive; -scans can override */\n      jpeg_simple_progression(cinfo);\n#endif\n\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n    if (scansarg != NULL)\t/* process -scans if it was present */\n      if (! read_scan_script(cinfo, scansarg))\n\tusage();\n#endif\n  }\n\n  return argn;\t\t\t/* return index of next arg (file name) */\n}\n\n\n/*\n * The main program.\n */\n\nint\nmain (int argc, char **argv)\n{\n  struct jpeg_decompress_struct srcinfo;\n  struct jpeg_error_mgr jsrcerr;\n#if TRANSFORMS_SUPPORTED\n  struct jpeg_decompress_struct dropinfo;\n  struct jpeg_error_mgr jdroperr;\n  FILE * drop_file;\n#endif\n  struct jpeg_compress_struct dstinfo;\n  struct jpeg_error_mgr jdsterr;\n#ifdef PROGRESS_REPORT\n  struct cdjpeg_progress_mgr progress;\n#endif\n  jvirt_barray_ptr * src_coef_arrays;\n  jvirt_barray_ptr * dst_coef_arrays;\n  int file_index;\n  /* We assume all-in-memory processing and can therefore use only a\n   * single file pointer for sequential input and output operation. \n   */\n  FILE * fp;\n\n  /* On Mac, fetch a command line. */\n#ifdef USE_CCOMMAND\n  argc = ccommand(&argv);\n#endif\n\n  progname = argv[0];\n  if (progname == NULL || progname[0] == 0)\n    progname = \"jpegtran\";\t/* in case C library doesn't provide it */\n\n  /* Initialize the JPEG decompression object with default error handling. */\n  srcinfo.err = jpeg_std_error(&jsrcerr);\n  jpeg_create_decompress(&srcinfo);\n  /* Initialize the JPEG compression object with default error handling. */\n  dstinfo.err = jpeg_std_error(&jdsterr);\n  jpeg_create_compress(&dstinfo);\n\n  /* Now safe to enable signal catcher.\n   * Note: we assume only the decompression object will have virtual arrays.\n   */\n#ifdef NEED_SIGNAL_CATCHER\n  enable_signal_catcher((j_common_ptr) &srcinfo);\n#endif\n\n  /* Scan command line to find file names.\n   * It is convenient to use just one switch-parsing routine, but the switch\n   * values read here are mostly ignored; we will rescan the switches after\n   * opening the input file.  Also note that most of the switches affect the\n   * destination JPEG object, so we parse into that and then copy over what\n   * needs to affect the source too.\n   */\n\n  file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);\n  jsrcerr.trace_level = jdsterr.trace_level;\n  srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;\n\n#ifdef TWO_FILE_COMMANDLINE\n  /* Must have either -outfile switch or explicit output file name */\n  if (outfilename == NULL) {\n    if (file_index != argc-2) {\n      fprintf(stderr, \"%s: must name one input and one output file\\n\",\n\t      progname);\n      usage();\n    }\n    outfilename = argv[file_index+1];\n  } else {\n    if (file_index != argc-1) {\n      fprintf(stderr, \"%s: must name one input and one output file\\n\",\n\t      progname);\n      usage();\n    }\n  }\n#else\n  /* Unix style: expect zero or one file name */\n  if (file_index < argc-1) {\n    fprintf(stderr, \"%s: only one input file\\n\", progname);\n    usage();\n  }\n#endif /* TWO_FILE_COMMANDLINE */\n\n  /* Open the input file. */\n  if (file_index < argc) {\n    if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open %s for reading\\n\", progname, argv[file_index]);\n      exit(EXIT_FAILURE);\n    }\n  } else {\n    /* default input file is stdin */\n    fp = read_stdin();\n  }\n\n#if TRANSFORMS_SUPPORTED\n  /* Open the drop file. */\n  if (dropfilename != NULL) {\n    if ((drop_file = fopen(dropfilename, READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open %s for reading\\n\", progname, dropfilename);\n      exit(EXIT_FAILURE);\n    }\n    dropinfo.err = jpeg_std_error(&jdroperr);\n    jpeg_create_decompress(&dropinfo);\n    jpeg_stdio_src(&dropinfo, drop_file);\n  } else {\n    drop_file = NULL;\n  }\n#endif\n\n#ifdef PROGRESS_REPORT\n  start_progress_monitor((j_common_ptr) &dstinfo, &progress);\n#endif\n\n  /* Specify data source for decompression */\n  jpeg_stdio_src(&srcinfo, fp);\n\n  /* Enable saving of extra markers that we want to copy */\n  jcopy_markers_setup(&srcinfo, copyoption);\n\n  /* Read file header */\n  (void) jpeg_read_header(&srcinfo, TRUE);\n\n  /* Adjust default decompression parameters */\n  if (scaleoption != NULL)\n    if (sscanf(scaleoption, \"%u/%u\",\n\t&srcinfo.scale_num, &srcinfo.scale_denom) < 1)\n      usage();\n\n#if TRANSFORMS_SUPPORTED\n  if (dropfilename != NULL) {\n    (void) jpeg_read_header(&dropinfo, TRUE);\n    transformoption.crop_width = dropinfo.image_width;\n    transformoption.crop_width_set = JCROP_POS;\n    transformoption.crop_height = dropinfo.image_height;\n    transformoption.crop_height_set = JCROP_POS;\n    transformoption.drop_ptr = &dropinfo;\n  }\n#endif\n\n  /* Any space needed by a transform option must be requested before\n   * jpeg_read_coefficients so that memory allocation will be done right.\n   */\n#if TRANSFORMS_SUPPORTED\n  /* Fail right away if -perfect is given and transformation is not perfect.\n   */\n  if (!jtransform_request_workspace(&srcinfo, &transformoption)) {\n    fprintf(stderr, \"%s: transformation is not perfect\\n\", progname);\n    exit(EXIT_FAILURE);\n  }\n#endif\n\n  /* Read source file as DCT coefficients */\n  src_coef_arrays = jpeg_read_coefficients(&srcinfo);\n\n#if TRANSFORMS_SUPPORTED\n  if (dropfilename != NULL) {\n    transformoption.drop_coef_arrays = jpeg_read_coefficients(&dropinfo);\n  }\n#endif\n\n  /* Initialize destination compression parameters from source values */\n  jpeg_copy_critical_parameters(&srcinfo, &dstinfo);\n\n  /* Adjust destination parameters if required by transform options;\n   * also find out which set of coefficient arrays will hold the output.\n   */\n#if TRANSFORMS_SUPPORTED\n  dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,\n\t\t\t\t\t\t src_coef_arrays,\n\t\t\t\t\t\t &transformoption);\n#else\n  dst_coef_arrays = src_coef_arrays;\n#endif\n\n  /* Close input file, if we opened it.\n   * Note: we assume that jpeg_read_coefficients consumed all input\n   * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will\n   * only consume more while (! cinfo->inputctl->eoi_reached).\n   * We cannot call jpeg_finish_decompress here since we still need the\n   * virtual arrays allocated from the source object for processing.\n   */\n  if (fp != stdin)\n    fclose(fp);\n\n  /* Open the output file. */\n  if (outfilename != NULL) {\n    if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open %s for writing\\n\", progname, outfilename);\n      exit(EXIT_FAILURE);\n    }\n  } else {\n    /* default output file is stdout */\n    fp = write_stdout();\n  }\n\n  /* Adjust default compression parameters by re-parsing the options */\n  file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);\n\n  /* Specify data destination for compression */\n  jpeg_stdio_dest(&dstinfo, fp);\n\n  /* Start compressor (note no image data is actually written here) */\n  jpeg_write_coefficients(&dstinfo, dst_coef_arrays);\n\n  /* Copy to the output file any extra markers that we want to preserve */\n  jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);\n\n  /* Execute image transformation, if any */\n#if TRANSFORMS_SUPPORTED\n  jtransform_execute_transformation(&srcinfo, &dstinfo,\n\t\t\t\t    src_coef_arrays,\n\t\t\t\t    &transformoption);\n#endif\n\n  /* Finish compression and release memory */\n  jpeg_finish_compress(&dstinfo);\n  jpeg_destroy_compress(&dstinfo);\n#if TRANSFORMS_SUPPORTED\n  if (dropfilename != NULL) {\n    (void) jpeg_finish_decompress(&dropinfo);\n    jpeg_destroy_decompress(&dropinfo);\n  }\n#endif\n  (void) jpeg_finish_decompress(&srcinfo);\n  jpeg_destroy_decompress(&srcinfo);\n\n  /* Close output file, if we opened it */\n  if (fp != stdout)\n    fclose(fp);\n#if TRANSFORMS_SUPPORTED\n  if (drop_file != NULL)\n    fclose(drop_file);\n#endif\n\n#ifdef PROGRESS_REPORT\n  end_progress_monitor((j_common_ptr) &dstinfo);\n#endif\n\n  /* All done. */\n#if TRANSFORMS_SUPPORTED\n  if (dropfilename != NULL)\n    exit(jsrcerr.num_warnings + jdroperr.num_warnings +\n\t jdsterr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);\n#endif\n  exit(jsrcerr.num_warnings + jdsterr.num_warnings ?\n       EXIT_WARNING : EXIT_SUCCESS);\n  return 0;\t/* suppress no-return-value warnings */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jquant1.c",
    "content": "/*\n * jquant1.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2011-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains 1-pass color quantization (color mapping) routines.\n * These routines provide mapping to a fixed color map using equally spaced\n * color values.  Optional Floyd-Steinberg or ordered dithering is available.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n#ifdef QUANT_1PASS_SUPPORTED\n\n\n/*\n * The main purpose of 1-pass quantization is to provide a fast, if not very\n * high quality, colormapped output capability.  A 2-pass quantizer usually\n * gives better visual quality; however, for quantized grayscale output this\n * quantizer is perfectly adequate.  Dithering is highly recommended with this\n * quantizer, though you can turn it off if you really want to.\n *\n * In 1-pass quantization the colormap must be chosen in advance of seeing the\n * image.  We use a map consisting of all combinations of Ncolors[i] color\n * values for the i'th component.  The Ncolors[] values are chosen so that\n * their product, the total number of colors, is no more than that requested.\n * (In most cases, the product will be somewhat less.)\n *\n * Since the colormap is orthogonal, the representative value for each color\n * component can be determined without considering the other components;\n * then these indexes can be combined into a colormap index by a standard\n * N-dimensional-array-subscript calculation.  Most of the arithmetic involved\n * can be precalculated and stored in the lookup table colorindex[].\n * colorindex[i][j] maps pixel value j in component i to the nearest\n * representative value (grid plane) for that component; this index is\n * multiplied by the array stride for component i, so that the\n * index of the colormap entry closest to a given pixel value is just\n *    sum( colorindex[component-number][pixel-component-value] )\n * Aside from being fast, this scheme allows for variable spacing between\n * representative values with no additional lookup cost.\n *\n * If gamma correction has been applied in color conversion, it might be wise\n * to adjust the color grid spacing so that the representative colors are\n * equidistant in linear space.  At this writing, gamma correction is not\n * implemented by jdcolor, so nothing is done here.\n */\n\n\n/* Declarations for ordered dithering.\n *\n * We use a standard 16x16 ordered dither array.  The basic concept of ordered\n * dithering is described in many references, for instance Dale Schumacher's\n * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).\n * In place of Schumacher's comparisons against a \"threshold\" value, we add a\n * \"dither\" value to the input pixel and then round the result to the nearest\n * output value.  The dither value is equivalent to (0.5 - threshold) times\n * the distance between output values.  For ordered dithering, we assume that\n * the output colors are equally spaced; if not, results will probably be\n * worse, since the dither may be too much or too little at a given point.\n *\n * The normal calculation would be to form pixel value + dither, range-limit\n * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.\n * We can skip the separate range-limiting step by extending the colorindex\n * table in both directions.\n */\n\n#define ODITHER_SIZE  16\t/* dimension of dither matrix */\n/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */\n#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE)\t/* # cells in matrix */\n#define ODITHER_MASK  (ODITHER_SIZE-1) /* mask for wrapping around counters */\n\ntypedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];\ntypedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];\n\nstatic const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {\n  /* Bayer's order-4 dither array.  Generated by the code given in\n   * Stephen Hawley's article \"Ordered Dithering\" in Graphics Gems I.\n   * The values in this array must range from 0 to ODITHER_CELLS-1.\n   */\n  {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },\n  { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },\n  {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },\n  { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },\n  {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },\n  { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },\n  {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },\n  { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },\n  {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },\n  { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },\n  {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },\n  { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },\n  {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },\n  { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },\n  {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },\n  { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }\n};\n\n\n/* Declarations for Floyd-Steinberg dithering.\n *\n * Errors are accumulated into the array fserrors[], at a resolution of\n * 1/16th of a pixel count.  The error at a given pixel is propagated\n * to its not-yet-processed neighbors using the standard F-S fractions,\n *\t\t...\t(here)\t7/16\n *\t\t3/16\t5/16\t1/16\n * We work left-to-right on even rows, right-to-left on odd rows.\n *\n * We can get away with a single array (holding one row's worth of errors)\n * by using it to store the current row's errors at pixel columns not yet\n * processed, but the next row's errors at columns already processed.  We\n * need only a few extra variables to hold the errors immediately around the\n * current column.  (If we are lucky, those variables are in registers, but\n * even if not, they're probably cheaper to access than array elements are.)\n *\n * The fserrors[] array is indexed [component#][position].\n * We provide (#columns + 2) entries per component; the extra entry at each\n * end saves us from special-casing the first and last pixels.\n *\n * Note: on a wide image, we might not have enough room in a PC's near data\n * segment to hold the error array; so it is allocated with alloc_large.\n */\n\n#if BITS_IN_JSAMPLE == 8\ntypedef INT16 FSERROR;\t\t/* 16 bits should be enough */\ntypedef int LOCFSERROR;\t\t/* use 'int' for calculation temps */\n#else\ntypedef INT32 FSERROR;\t\t/* may need more than 16 bits */\ntypedef INT32 LOCFSERROR;\t/* be sure calculation temps are big enough */\n#endif\n\ntypedef FSERROR FAR *FSERRPTR;\t/* pointer to error array (in FAR storage!) */\n\n\n/* Private subobject */\n\n#define MAX_Q_COMPS 4\t\t/* max components I can handle */\n\ntypedef struct {\n  struct jpeg_color_quantizer pub; /* public fields */\n\n  /* Initially allocated colormap is saved here */\n  JSAMPARRAY sv_colormap;\t/* The color map as a 2-D pixel array */\n  int sv_actual;\t\t/* number of entries in use */\n\n  JSAMPARRAY colorindex;\t/* Precomputed mapping for speed */\n  /* colorindex[i][j] = index of color closest to pixel value j in component i,\n   * premultiplied as described above.  Since colormap indexes must fit into\n   * JSAMPLEs, the entries of this array will too.\n   */\n  boolean is_padded;\t\t/* is the colorindex padded for odither? */\n\n  int Ncolors[MAX_Q_COMPS];\t/* # of values alloced to each component */\n\n  /* Variables for ordered dithering */\n  int row_index;\t\t/* cur row's vertical index in dither matrix */\n  ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */\n\n  /* Variables for Floyd-Steinberg dithering */\n  FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */\n  boolean on_odd_row;\t\t/* flag to remember which row we are on */\n} my_cquantizer;\n\ntypedef my_cquantizer * my_cquantize_ptr;\n\n\n/*\n * Policy-making subroutines for create_colormap and create_colorindex.\n * These routines determine the colormap to be used.  The rest of the module\n * only assumes that the colormap is orthogonal.\n *\n *  * select_ncolors decides how to divvy up the available colors\n *    among the components.\n *  * output_value defines the set of representative values for a component.\n *  * largest_input_value defines the mapping from input values to\n *    representative values for a component.\n * Note that the latter two routines may impose different policies for\n * different components, though this is not currently done.\n */\n\n\nLOCAL(int)\nselect_ncolors (j_decompress_ptr cinfo, int Ncolors[])\n/* Determine allocation of desired colors to components, */\n/* and fill in Ncolors[] array to indicate choice. */\n/* Return value is total number of colors (product of Ncolors[] values). */\n{\n  int nc = cinfo->out_color_components; /* number of color components */\n  int max_colors = cinfo->desired_number_of_colors;\n  int total_colors, iroot, i, j;\n  boolean changed;\n  long temp;\n  static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };\n\n  /* We can allocate at least the nc'th root of max_colors per component. */\n  /* Compute floor(nc'th root of max_colors). */\n  iroot = 1;\n  do {\n    iroot++;\n    temp = iroot;\t\t/* set temp = iroot ** nc */\n    for (i = 1; i < nc; i++)\n      temp *= iroot;\n  } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */\n  iroot--;\t\t\t/* now iroot = floor(root) */\n\n  /* Must have at least 2 color values per component */\n  if (iroot < 2)\n    ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);\n\n  /* Initialize to iroot color values for each component */\n  total_colors = 1;\n  for (i = 0; i < nc; i++) {\n    Ncolors[i] = iroot;\n    total_colors *= iroot;\n  }\n  /* We may be able to increment the count for one or more components without\n   * exceeding max_colors, though we know not all can be incremented.\n   * Sometimes, the first component can be incremented more than once!\n   * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)\n   * In RGB colorspace, try to increment G first, then R, then B.\n   */\n  do {\n    changed = FALSE;\n    for (i = 0; i < nc; i++) {\n      j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);\n      /* calculate new total_colors if Ncolors[j] is incremented */\n      temp = total_colors / Ncolors[j];\n      temp *= Ncolors[j]+1;\t/* done in long arith to avoid oflo */\n      if (temp > (long) max_colors)\n\tbreak;\t\t\t/* won't fit, done with this pass */\n      Ncolors[j]++;\t\t/* OK, apply the increment */\n      total_colors = (int) temp;\n      changed = TRUE;\n    }\n  } while (changed);\n\n  return total_colors;\n}\n\n\nLOCAL(int)\noutput_value (j_decompress_ptr cinfo, int ci, int j, int maxj)\n/* Return j'th output value, where j will range from 0 to maxj */\n/* The output values must fall in 0..MAXJSAMPLE in increasing order */\n{\n  /* We always provide values 0 and MAXJSAMPLE for each component;\n   * any additional values are equally spaced between these limits.\n   * (Forcing the upper and lower values to the limits ensures that\n   * dithering can't produce a color outside the selected gamut.)\n   */\n  return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);\n}\n\n\nLOCAL(int)\nlargest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)\n/* Return largest input value that should map to j'th output value */\n/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */\n{\n  /* Breakpoints are halfway between values returned by output_value */\n  return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));\n}\n\n\n/*\n * Create the colormap.\n */\n\nLOCAL(void)\ncreate_colormap (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  JSAMPARRAY colormap;\t\t/* Created colormap */\n  int total_colors;\t\t/* Number of distinct output colors */\n  int i,j,k, nci, blksize, blkdist, ptr, val;\n\n  /* Select number of colors for each component */\n  total_colors = select_ncolors(cinfo, cquantize->Ncolors);\n\n  /* Report selected color counts */\n  if (cinfo->out_color_components == 3)\n    TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,\n\t     total_colors, cquantize->Ncolors[0],\n\t     cquantize->Ncolors[1], cquantize->Ncolors[2]);\n  else\n    TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);\n\n  /* Allocate and fill in the colormap. */\n  /* The colors are ordered in the map in standard row-major order, */\n  /* i.e. rightmost (highest-indexed) color changes most rapidly. */\n\n  colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE,\n     (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);\n\n  /* blksize is number of adjacent repeated entries for a component */\n  /* blkdist is distance between groups of identical entries for a component */\n  blkdist = total_colors;\n\n  for (i = 0; i < cinfo->out_color_components; i++) {\n    /* fill in colormap entries for i'th color component */\n    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */\n    blksize = blkdist / nci;\n    for (j = 0; j < nci; j++) {\n      /* Compute j'th output value (out of nci) for component */\n      val = output_value(cinfo, i, j, nci-1);\n      /* Fill in all colormap entries that have this value of this component */\n      for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {\n\t/* fill in blksize entries beginning at ptr */\n\tfor (k = 0; k < blksize; k++)\n\t  colormap[i][ptr+k] = (JSAMPLE) val;\n      }\n    }\n    blkdist = blksize;\t\t/* blksize of this color is blkdist of next */\n  }\n\n  /* Save the colormap in private storage,\n   * where it will survive color quantization mode changes.\n   */\n  cquantize->sv_colormap = colormap;\n  cquantize->sv_actual = total_colors;\n}\n\n\n/*\n * Create the color index table.\n */\n\nLOCAL(void)\ncreate_colorindex (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  JSAMPROW indexptr;\n  int i,j,k, nci, blksize, val, pad;\n\n  /* For ordered dither, we pad the color index tables by MAXJSAMPLE in\n   * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).\n   * This is not necessary in the other dithering modes.  However, we\n   * flag whether it was done in case user changes dithering mode.\n   */\n  if (cinfo->dither_mode == JDITHER_ORDERED) {\n    pad = MAXJSAMPLE*2;\n    cquantize->is_padded = TRUE;\n  } else {\n    pad = 0;\n    cquantize->is_padded = FALSE;\n  }\n\n  cquantize->colorindex = (*cinfo->mem->alloc_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE,\n     (JDIMENSION) (MAXJSAMPLE+1 + pad),\n     (JDIMENSION) cinfo->out_color_components);\n\n  /* blksize is number of adjacent repeated entries for a component */\n  blksize = cquantize->sv_actual;\n\n  for (i = 0; i < cinfo->out_color_components; i++) {\n    /* fill in colorindex entries for i'th color component */\n    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */\n    blksize = blksize / nci;\n\n    /* adjust colorindex pointers to provide padding at negative indexes. */\n    if (pad)\n      cquantize->colorindex[i] += MAXJSAMPLE;\n\n    /* in loop, val = index of current output value, */\n    /* and k = largest j that maps to current val */\n    indexptr = cquantize->colorindex[i];\n    val = 0;\n    k = largest_input_value(cinfo, i, 0, nci-1);\n    for (j = 0; j <= MAXJSAMPLE; j++) {\n      while (j > k)\t\t/* advance val if past boundary */\n\tk = largest_input_value(cinfo, i, ++val, nci-1);\n      /* premultiply so that no multiplication needed in main processing */\n      indexptr[j] = (JSAMPLE) (val * blksize);\n    }\n    /* Pad at both ends if necessary */\n    if (pad)\n      for (j = 1; j <= MAXJSAMPLE; j++) {\n\tindexptr[-j] = indexptr[0];\n\tindexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];\n      }\n  }\n}\n\n\n/*\n * Create an ordered-dither array for a component having ncolors\n * distinct output values.\n */\n\nLOCAL(ODITHER_MATRIX_PTR)\nmake_odither_array (j_decompress_ptr cinfo, int ncolors)\n{\n  ODITHER_MATRIX_PTR odither;\n  int j,k;\n  INT32 num,den;\n\n  odither = (ODITHER_MATRIX_PTR) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ODITHER_MATRIX));\n  /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).\n   * Hence the dither value for the matrix cell with fill order f\n   * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).\n   * On 16-bit-int machine, be careful to avoid overflow.\n   */\n  den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));\n  for (j = 0; j < ODITHER_SIZE; j++) {\n    for (k = 0; k < ODITHER_SIZE; k++) {\n      num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))\n\t    * MAXJSAMPLE;\n      /* Ensure round towards zero despite C's lack of consistency\n       * about rounding negative values in integer division...\n       */\n      odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);\n    }\n  }\n  return odither;\n}\n\n\n/*\n * Create the ordered-dither tables.\n * Components having the same number of representative colors may \n * share a dither table.\n */\n\nLOCAL(void)\ncreate_odither_tables (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  ODITHER_MATRIX_PTR odither;\n  int i, j, nci;\n\n  for (i = 0; i < cinfo->out_color_components; i++) {\n    nci = cquantize->Ncolors[i]; /* # of distinct values for this color */\n    odither = NULL;\t\t/* search for matching prior component */\n    for (j = 0; j < i; j++) {\n      if (nci == cquantize->Ncolors[j]) {\n\todither = cquantize->odither[j];\n\tbreak;\n      }\n    }\n    if (odither == NULL)\t/* need a new table? */\n      odither = make_odither_array(cinfo, nci);\n    cquantize->odither[i] = odither;\n  }\n}\n\n\n/*\n * Map some rows of pixels to the output colormapped representation.\n */\n\nMETHODDEF(void)\ncolor_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\tJSAMPARRAY output_buf, int num_rows)\n/* General case, no dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  JSAMPARRAY colorindex = cquantize->colorindex;\n  register int pixcode, ci;\n  register JSAMPROW ptrin, ptrout;\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n  register int nc = cinfo->out_color_components;\n\n  for (row = 0; row < num_rows; row++) {\n    ptrin = input_buf[row];\n    ptrout = output_buf[row];\n    for (col = width; col > 0; col--) {\n      pixcode = 0;\n      for (ci = 0; ci < nc; ci++) {\n\tpixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);\n      }\n      *ptrout++ = (JSAMPLE) pixcode;\n    }\n  }\n}\n\n\nMETHODDEF(void)\ncolor_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\t JSAMPARRAY output_buf, int num_rows)\n/* Fast path for out_color_components==3, no dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  register int pixcode;\n  register JSAMPROW ptrin, ptrout;\n  JSAMPROW colorindex0 = cquantize->colorindex[0];\n  JSAMPROW colorindex1 = cquantize->colorindex[1];\n  JSAMPROW colorindex2 = cquantize->colorindex[2];\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n\n  for (row = 0; row < num_rows; row++) {\n    ptrin = input_buf[row];\n    ptrout = output_buf[row];\n    for (col = width; col > 0; col--) {\n      pixcode  = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);\n      pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);\n      pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);\n      *ptrout++ = (JSAMPLE) pixcode;\n    }\n  }\n}\n\n\nMETHODDEF(void)\nquantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\t     JSAMPARRAY output_buf, int num_rows)\n/* General case, with ordered dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  register JSAMPROW input_ptr;\n  register JSAMPROW output_ptr;\n  JSAMPROW colorindex_ci;\n  int * dither;\t\t\t/* points to active row of dither matrix */\n  int row_index, col_index;\t/* current indexes into dither matrix */\n  int nc = cinfo->out_color_components;\n  int ci;\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n\n  for (row = 0; row < num_rows; row++) {\n    /* Initialize output values to 0 so can process components separately */\n    FMEMZERO((void FAR *) output_buf[row], (size_t) width * SIZEOF(JSAMPLE));\n    row_index = cquantize->row_index;\n    for (ci = 0; ci < nc; ci++) {\n      input_ptr = input_buf[row] + ci;\n      output_ptr = output_buf[row];\n      colorindex_ci = cquantize->colorindex[ci];\n      dither = cquantize->odither[ci][row_index];\n      col_index = 0;\n\n      for (col = width; col > 0; col--) {\n\t/* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,\n\t * select output value, accumulate into output code for this pixel.\n\t * Range-limiting need not be done explicitly, as we have extended\n\t * the colorindex table to produce the right answers for out-of-range\n\t * inputs.  The maximum dither is +- MAXJSAMPLE; this sets the\n\t * required amount of padding.\n\t */\n\t*output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];\n\tinput_ptr += nc;\n\toutput_ptr++;\n\tcol_index = (col_index + 1) & ODITHER_MASK;\n      }\n    }\n    /* Advance row index for next row */\n    row_index = (row_index + 1) & ODITHER_MASK;\n    cquantize->row_index = row_index;\n  }\n}\n\n\nMETHODDEF(void)\nquantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\t      JSAMPARRAY output_buf, int num_rows)\n/* Fast path for out_color_components==3, with ordered dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  register int pixcode;\n  register JSAMPROW input_ptr;\n  register JSAMPROW output_ptr;\n  JSAMPROW colorindex0 = cquantize->colorindex[0];\n  JSAMPROW colorindex1 = cquantize->colorindex[1];\n  JSAMPROW colorindex2 = cquantize->colorindex[2];\n  int * dither0;\t\t/* points to active row of dither matrix */\n  int * dither1;\n  int * dither2;\n  int row_index, col_index;\t/* current indexes into dither matrix */\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n\n  for (row = 0; row < num_rows; row++) {\n    row_index = cquantize->row_index;\n    input_ptr = input_buf[row];\n    output_ptr = output_buf[row];\n    dither0 = cquantize->odither[0][row_index];\n    dither1 = cquantize->odither[1][row_index];\n    dither2 = cquantize->odither[2][row_index];\n    col_index = 0;\n\n    for (col = width; col > 0; col--) {\n      pixcode  = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +\n\t\t\t\t\tdither0[col_index]]);\n      pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +\n\t\t\t\t\tdither1[col_index]]);\n      pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +\n\t\t\t\t\tdither2[col_index]]);\n      *output_ptr++ = (JSAMPLE) pixcode;\n      col_index = (col_index + 1) & ODITHER_MASK;\n    }\n    row_index = (row_index + 1) & ODITHER_MASK;\n    cquantize->row_index = row_index;\n  }\n}\n\n\nMETHODDEF(void)\nquantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\t    JSAMPARRAY output_buf, int num_rows)\n/* General case, with Floyd-Steinberg dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  register LOCFSERROR cur;\t/* current error or pixel value */\n  LOCFSERROR belowerr;\t\t/* error for pixel below cur */\n  LOCFSERROR bpreverr;\t\t/* error for below/prev col */\n  LOCFSERROR bnexterr;\t\t/* error for below/next col */\n  LOCFSERROR delta;\n  register FSERRPTR errorptr;\t/* => fserrors[] at column before current */\n  register JSAMPROW input_ptr;\n  register JSAMPROW output_ptr;\n  JSAMPROW colorindex_ci;\n  JSAMPROW colormap_ci;\n  int pixcode;\n  int nc = cinfo->out_color_components;\n  int dir;\t\t\t/* 1 for left-to-right, -1 for right-to-left */\n  int dirnc;\t\t\t/* dir * nc */\n  int ci;\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n  JSAMPLE *range_limit = cinfo->sample_range_limit;\n  SHIFT_TEMPS\n\n  for (row = 0; row < num_rows; row++) {\n    /* Initialize output values to 0 so can process components separately */\n    FMEMZERO((void FAR *) output_buf[row], (size_t) width * SIZEOF(JSAMPLE));\n    for (ci = 0; ci < nc; ci++) {\n      input_ptr = input_buf[row] + ci;\n      output_ptr = output_buf[row];\n      if (cquantize->on_odd_row) {\n\t/* work right to left in this row */\n\tinput_ptr += (width-1) * nc; /* so point to rightmost pixel */\n\toutput_ptr += width-1;\n\tdir = -1;\n\tdirnc = -nc;\n\terrorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */\n      } else {\n\t/* work left to right in this row */\n\tdir = 1;\n\tdirnc = nc;\n\terrorptr = cquantize->fserrors[ci]; /* => entry before first column */\n      }\n      colorindex_ci = cquantize->colorindex[ci];\n      colormap_ci = cquantize->sv_colormap[ci];\n      /* Preset error values: no error propagated to first pixel from left */\n      cur = 0;\n      /* and no error propagated to row below yet */\n      belowerr = bpreverr = 0;\n\n      for (col = width; col > 0; col--) {\n\t/* cur holds the error propagated from the previous pixel on the\n\t * current line.  Add the error propagated from the previous line\n\t * to form the complete error correction term for this pixel, and\n\t * round the error term (which is expressed * 16) to an integer.\n\t * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct\n\t * for either sign of the error value.\n\t * Note: errorptr points to *previous* column's array entry.\n\t */\n\tcur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);\n\t/* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.\n\t * The maximum error is +- MAXJSAMPLE; this sets the required size\n\t * of the range_limit array.\n\t */\n\tcur += GETJSAMPLE(*input_ptr);\n\tcur = GETJSAMPLE(range_limit[cur]);\n\t/* Select output value, accumulate into output code for this pixel */\n\tpixcode = GETJSAMPLE(colorindex_ci[cur]);\n\t*output_ptr += (JSAMPLE) pixcode;\n\t/* Compute actual representation error at this pixel */\n\t/* Note: we can do this even though we don't have the final */\n\t/* pixel code, because the colormap is orthogonal. */\n\tcur -= GETJSAMPLE(colormap_ci[pixcode]);\n\t/* Compute error fractions to be propagated to adjacent pixels.\n\t * Add these into the running sums, and simultaneously shift the\n\t * next-line error sums left by 1 column.\n\t */\n\tbnexterr = cur;\n\tdelta = cur * 2;\n\tcur += delta;\t\t/* form error * 3 */\n\terrorptr[0] = (FSERROR) (bpreverr + cur);\n\tcur += delta;\t\t/* form error * 5 */\n\tbpreverr = belowerr + cur;\n\tbelowerr = bnexterr;\n\tcur += delta;\t\t/* form error * 7 */\n\t/* At this point cur contains the 7/16 error value to be propagated\n\t * to the next pixel on the current line, and all the errors for the\n\t * next line have been shifted over. We are therefore ready to move on.\n\t */\n\tinput_ptr += dirnc;\t/* advance input ptr to next column */\n\toutput_ptr += dir;\t/* advance output ptr to next column */\n\terrorptr += dir;\t/* advance errorptr to current column */\n      }\n      /* Post-loop cleanup: we must unload the final error value into the\n       * final fserrors[] entry.  Note we need not unload belowerr because\n       * it is for the dummy column before or after the actual array.\n       */\n      errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */\n    }\n    cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);\n  }\n}\n\n\n/*\n * Allocate workspace for Floyd-Steinberg errors.\n */\n\nLOCAL(void)\nalloc_fs_workspace (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  size_t arraysize;\n  int i;\n\n  arraysize = ((size_t) cinfo->output_width + (size_t) 2) * SIZEOF(FSERROR);\n  for (i = 0; i < cinfo->out_color_components; i++) {\n    cquantize->fserrors[i] = (FSERRPTR) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);\n  }\n}\n\n\n/*\n * Initialize for one-pass color quantization.\n */\n\nMETHODDEF(void)\nstart_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  size_t arraysize;\n  int i;\n\n  /* Install my colormap. */\n  cinfo->colormap = cquantize->sv_colormap;\n  cinfo->actual_number_of_colors = cquantize->sv_actual;\n\n  /* Initialize for desired dithering mode. */\n  switch (cinfo->dither_mode) {\n  case JDITHER_NONE:\n    if (cinfo->out_color_components == 3)\n      cquantize->pub.color_quantize = color_quantize3;\n    else\n      cquantize->pub.color_quantize = color_quantize;\n    break;\n  case JDITHER_ORDERED:\n    if (cinfo->out_color_components == 3)\n      cquantize->pub.color_quantize = quantize3_ord_dither;\n    else\n      cquantize->pub.color_quantize = quantize_ord_dither;\n    cquantize->row_index = 0;\t/* initialize state for ordered dither */\n    /* If user changed to ordered dither from another mode,\n     * we must recreate the color index table with padding.\n     * This will cost extra space, but probably isn't very likely.\n     */\n    if (! cquantize->is_padded)\n      create_colorindex(cinfo);\n    /* Create ordered-dither tables if we didn't already. */\n    if (cquantize->odither[0] == NULL)\n      create_odither_tables(cinfo);\n    break;\n  case JDITHER_FS:\n    cquantize->pub.color_quantize = quantize_fs_dither;\n    cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */\n    /* Allocate Floyd-Steinberg workspace if didn't already. */\n    if (cquantize->fserrors[0] == NULL)\n      alloc_fs_workspace(cinfo);\n    /* Initialize the propagated errors to zero. */\n    arraysize = ((size_t) cinfo->output_width + (size_t) 2) * SIZEOF(FSERROR);\n    for (i = 0; i < cinfo->out_color_components; i++)\n      FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_NOT_COMPILED);\n  }\n}\n\n\n/*\n * Finish up at the end of the pass.\n */\n\nMETHODDEF(void)\nfinish_pass_1_quant (j_decompress_ptr cinfo)\n{\n  /* no work in 1-pass case */\n}\n\n\n/*\n * Switch to a new external colormap between output passes.\n * Shouldn't get to this module!\n */\n\nMETHODDEF(void)\nnew_color_map_1_quant (j_decompress_ptr cinfo)\n{\n  ERREXIT(cinfo, JERR_MODE_CHANGE);\n}\n\n\n/*\n * Module initialization routine for 1-pass color quantization.\n */\n\nGLOBAL(void)\njinit_1pass_quantizer (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize;\n\n  cquantize = (my_cquantize_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_cquantizer));\n  cinfo->cquantize = &cquantize->pub;\n  cquantize->pub.start_pass = start_pass_1_quant;\n  cquantize->pub.finish_pass = finish_pass_1_quant;\n  cquantize->pub.new_color_map = new_color_map_1_quant;\n  cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */\n  cquantize->odither[0] = NULL;\t/* Also flag odither arrays not allocated */\n\n  /* Make sure my internal arrays won't overflow */\n  if (cinfo->out_color_components > MAX_Q_COMPS)\n    ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);\n  /* Make sure colormap indexes can be represented by JSAMPLEs */\n  if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))\n    ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);\n\n  /* Create the colormap and color index table. */\n  create_colormap(cinfo);\n  create_colorindex(cinfo);\n\n  /* Allocate Floyd-Steinberg workspace now if requested.\n   * We do this now since it is FAR storage and may affect the memory\n   * manager's space calculations.  If the user changes to FS dither\n   * mode in a later pass, we will allocate the space then, and will\n   * possibly overrun the max_memory_to_use setting.\n   */\n  if (cinfo->dither_mode == JDITHER_FS)\n    alloc_fs_workspace(cinfo);\n}\n\n#endif /* QUANT_1PASS_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jquant2.c",
    "content": "/*\n * jquant2.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2011-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains 2-pass color quantization (color mapping) routines.\n * These routines provide selection of a custom color map for an image,\n * followed by mapping of the image to that color map, with optional\n * Floyd-Steinberg dithering.\n * It is also possible to use just the second pass to map to an arbitrary\n * externally-given color map.\n *\n * Note: ordered dithering is not supported, since there isn't any fast\n * way to compute intercolor distances; it's unclear that ordered dither's\n * fundamental assumptions even hold with an irregularly spaced color map.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n#ifdef QUANT_2PASS_SUPPORTED\n\n\n/*\n * This module implements the well-known Heckbert paradigm for color\n * quantization.  Most of the ideas used here can be traced back to\n * Heckbert's seminal paper\n *   Heckbert, Paul.  \"Color Image Quantization for Frame Buffer Display\",\n *   Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.\n *\n * In the first pass over the image, we accumulate a histogram showing the\n * usage count of each possible color.  To keep the histogram to a reasonable\n * size, we reduce the precision of the input; typical practice is to retain\n * 5 or 6 bits per color, so that 8 or 4 different input values are counted\n * in the same histogram cell.\n *\n * Next, the color-selection step begins with a box representing the whole\n * color space, and repeatedly splits the \"largest\" remaining box until we\n * have as many boxes as desired colors.  Then the mean color in each\n * remaining box becomes one of the possible output colors.\n * \n * The second pass over the image maps each input pixel to the closest output\n * color (optionally after applying a Floyd-Steinberg dithering correction).\n * This mapping is logically trivial, but making it go fast enough requires\n * considerable care.\n *\n * Heckbert-style quantizers vary a good deal in their policies for choosing\n * the \"largest\" box and deciding where to cut it.  The particular policies\n * used here have proved out well in experimental comparisons, but better ones\n * may yet be found.\n *\n * In earlier versions of the IJG code, this module quantized in YCbCr color\n * space, processing the raw upsampled data without a color conversion step.\n * This allowed the color conversion math to be done only once per colormap\n * entry, not once per pixel.  However, that optimization precluded other\n * useful optimizations (such as merging color conversion with upsampling)\n * and it also interfered with desired capabilities such as quantizing to an\n * externally-supplied colormap.  We have therefore abandoned that approach.\n * The present code works in the post-conversion color space, typically RGB.\n *\n * To improve the visual quality of the results, we actually work in scaled\n * RGB space, giving G distances more weight than R, and R in turn more than\n * B.  To do everything in integer math, we must use integer scale factors.\n * The 2/3/1 scale factors used here correspond loosely to the relative\n * weights of the colors in the NTSC grayscale equation.\n * If you want to use this code to quantize a non-RGB color space, you'll\n * probably need to change these scale factors.\n */\n\n#define R_SCALE 2\t\t/* scale R distances by this much */\n#define G_SCALE 3\t\t/* scale G distances by this much */\n#define B_SCALE 1\t\t/* and B by this much */\n\n/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined\n * in jmorecfg.h.  As the code stands, it will do the right thing for R,G,B\n * and B,G,R orders.  If you define some other weird order in jmorecfg.h,\n * you'll get compile errors until you extend this logic.  In that case\n * you'll probably want to tweak the histogram sizes too.\n */\n\n#if RGB_RED == 0\n#define C0_SCALE R_SCALE\n#endif\n#if RGB_BLUE == 0\n#define C0_SCALE B_SCALE\n#endif\n#if RGB_GREEN == 1\n#define C1_SCALE G_SCALE\n#endif\n#if RGB_RED == 2\n#define C2_SCALE R_SCALE\n#endif\n#if RGB_BLUE == 2\n#define C2_SCALE B_SCALE\n#endif\n\n\n/*\n * First we have the histogram data structure and routines for creating it.\n *\n * The number of bits of precision can be adjusted by changing these symbols.\n * We recommend keeping 6 bits for G and 5 each for R and B.\n * If you have plenty of memory and cycles, 6 bits all around gives marginally\n * better results; if you are short of memory, 5 bits all around will save\n * some space but degrade the results.\n * To maintain a fully accurate histogram, we'd need to allocate a \"long\"\n * (preferably unsigned long) for each cell.  In practice this is overkill;\n * we can get by with 16 bits per cell.  Few of the cell counts will overflow,\n * and clamping those that do overflow to the maximum value will give close-\n * enough results.  This reduces the recommended histogram size from 256Kb\n * to 128Kb, which is a useful savings on PC-class machines.\n * (In the second pass the histogram space is re-used for pixel mapping data;\n * in that capacity, each cell must be able to store zero to the number of\n * desired colors.  16 bits/cell is plenty for that too.)\n * Since the JPEG code is intended to run in small memory model on 80x86\n * machines, we can't just allocate the histogram in one chunk.  Instead\n * of a true 3-D array, we use a row of pointers to 2-D arrays.  Each\n * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and\n * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries.  Note that\n * on 80x86 machines, the pointer row is in near memory but the actual\n * arrays are in far memory (same arrangement as we use for image arrays).\n */\n\n#define MAXNUMCOLORS  (MAXJSAMPLE+1) /* maximum size of colormap */\n\n/* These will do the right thing for either R,G,B or B,G,R color order,\n * but you may not like the results for other color orders.\n */\n#define HIST_C0_BITS  5\t\t/* bits of precision in R/B histogram */\n#define HIST_C1_BITS  6\t\t/* bits of precision in G histogram */\n#define HIST_C2_BITS  5\t\t/* bits of precision in B/R histogram */\n\n/* Number of elements along histogram axes. */\n#define HIST_C0_ELEMS  (1<<HIST_C0_BITS)\n#define HIST_C1_ELEMS  (1<<HIST_C1_BITS)\n#define HIST_C2_ELEMS  (1<<HIST_C2_BITS)\n\n/* These are the amounts to shift an input value to get a histogram index. */\n#define C0_SHIFT  (BITS_IN_JSAMPLE-HIST_C0_BITS)\n#define C1_SHIFT  (BITS_IN_JSAMPLE-HIST_C1_BITS)\n#define C2_SHIFT  (BITS_IN_JSAMPLE-HIST_C2_BITS)\n\n\ntypedef UINT16 histcell;\t/* histogram cell; prefer an unsigned type */\n\ntypedef histcell FAR * histptr;\t/* for pointers to histogram cells */\n\ntypedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */\ntypedef hist1d FAR * hist2d;\t/* type for the 2nd-level pointers */\ntypedef hist2d * hist3d;\t/* type for top-level pointer */\n\n\n/* Declarations for Floyd-Steinberg dithering.\n *\n * Errors are accumulated into the array fserrors[], at a resolution of\n * 1/16th of a pixel count.  The error at a given pixel is propagated\n * to its not-yet-processed neighbors using the standard F-S fractions,\n *\t\t...\t(here)\t7/16\n *\t\t3/16\t5/16\t1/16\n * We work left-to-right on even rows, right-to-left on odd rows.\n *\n * We can get away with a single array (holding one row's worth of errors)\n * by using it to store the current row's errors at pixel columns not yet\n * processed, but the next row's errors at columns already processed.  We\n * need only a few extra variables to hold the errors immediately around the\n * current column.  (If we are lucky, those variables are in registers, but\n * even if not, they're probably cheaper to access than array elements are.)\n *\n * The fserrors[] array has (#columns + 2) entries; the extra entry at\n * each end saves us from special-casing the first and last pixels.\n * Each entry is three values long, one value for each color component.\n *\n * Note: on a wide image, we might not have enough room in a PC's near data\n * segment to hold the error array; so it is allocated with alloc_large.\n */\n\n#if BITS_IN_JSAMPLE == 8\ntypedef INT16 FSERROR;\t\t/* 16 bits should be enough */\ntypedef int LOCFSERROR;\t\t/* use 'int' for calculation temps */\n#else\ntypedef INT32 FSERROR;\t\t/* may need more than 16 bits */\ntypedef INT32 LOCFSERROR;\t/* be sure calculation temps are big enough */\n#endif\n\ntypedef FSERROR FAR *FSERRPTR;\t/* pointer to error array (in FAR storage!) */\n\n\n/* Private subobject */\n\ntypedef struct {\n  struct jpeg_color_quantizer pub; /* public fields */\n\n  /* Space for the eventually created colormap is stashed here */\n  JSAMPARRAY sv_colormap;\t/* colormap allocated at init time */\n  int desired;\t\t\t/* desired # of colors = size of colormap */\n\n  /* Variables for accumulating image statistics */\n  hist3d histogram;\t\t/* pointer to the histogram */\n\n  boolean needs_zeroed;\t\t/* TRUE if next pass must zero histogram */\n\n  /* Variables for Floyd-Steinberg dithering */\n  FSERRPTR fserrors;\t\t/* accumulated errors */\n  boolean on_odd_row;\t\t/* flag to remember which row we are on */\n  int * error_limiter;\t\t/* table for clamping the applied error */\n} my_cquantizer;\n\ntypedef my_cquantizer * my_cquantize_ptr;\n\n\n/*\n * Prescan some rows of pixels.\n * In this module the prescan simply updates the histogram, which has been\n * initialized to zeroes by start_pass.\n * An output_buf parameter is required by the method signature, but no data\n * is actually output (in fact the buffer controller is probably passing a\n * NULL pointer).\n */\n\nMETHODDEF(void)\nprescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,\n\t\t  JSAMPARRAY output_buf, int num_rows)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  register JSAMPROW ptr;\n  register histptr histp;\n  register hist3d histogram = cquantize->histogram;\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n\n  for (row = 0; row < num_rows; row++) {\n    ptr = input_buf[row];\n    for (col = width; col > 0; col--) {\n      /* get pixel value and index into the histogram */\n      histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]\n\t\t\t [GETJSAMPLE(ptr[1]) >> C1_SHIFT]\n\t\t\t [GETJSAMPLE(ptr[2]) >> C2_SHIFT];\n      /* increment, check for overflow and undo increment if so. */\n      if (++(*histp) <= 0)\n\t(*histp)--;\n      ptr += 3;\n    }\n  }\n}\n\n\n/*\n * Next we have the really interesting routines: selection of a colormap\n * given the completed histogram.\n * These routines work with a list of \"boxes\", each representing a rectangular\n * subset of the input color space (to histogram precision).\n */\n\ntypedef struct {\n  /* The bounds of the box (inclusive); expressed as histogram indexes */\n  int c0min, c0max;\n  int c1min, c1max;\n  int c2min, c2max;\n  /* The volume (actually 2-norm) of the box */\n  INT32 volume;\n  /* The number of nonzero histogram cells within this box */\n  long colorcount;\n} box;\n\ntypedef box * boxptr;\n\n\nLOCAL(boxptr)\nfind_biggest_color_pop (boxptr boxlist, int numboxes)\n/* Find the splittable box with the largest color population */\n/* Returns NULL if no splittable boxes remain */\n{\n  register boxptr boxp;\n  register int i;\n  register long maxc = 0;\n  boxptr which = NULL;\n  \n  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {\n    if (boxp->colorcount > maxc && boxp->volume > 0) {\n      which = boxp;\n      maxc = boxp->colorcount;\n    }\n  }\n  return which;\n}\n\n\nLOCAL(boxptr)\nfind_biggest_volume (boxptr boxlist, int numboxes)\n/* Find the splittable box with the largest (scaled) volume */\n/* Returns NULL if no splittable boxes remain */\n{\n  register boxptr boxp;\n  register int i;\n  register INT32 maxv = 0;\n  boxptr which = NULL;\n  \n  for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {\n    if (boxp->volume > maxv) {\n      which = boxp;\n      maxv = boxp->volume;\n    }\n  }\n  return which;\n}\n\n\nLOCAL(void)\nupdate_box (j_decompress_ptr cinfo, boxptr boxp)\n/* Shrink the min/max bounds of a box to enclose only nonzero elements, */\n/* and recompute its volume and population */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  histptr histp;\n  int c0,c1,c2;\n  int c0min,c0max,c1min,c1max,c2min,c2max;\n  INT32 dist0,dist1,dist2;\n  long ccount;\n  \n  c0min = boxp->c0min;  c0max = boxp->c0max;\n  c1min = boxp->c1min;  c1max = boxp->c1max;\n  c2min = boxp->c2min;  c2max = boxp->c2max;\n  \n  if (c0max > c0min)\n    for (c0 = c0min; c0 <= c0max; c0++)\n      for (c1 = c1min; c1 <= c1max; c1++) {\n\thistp = & histogram[c0][c1][c2min];\n\tfor (c2 = c2min; c2 <= c2max; c2++)\n\t  if (*histp++ != 0) {\n\t    boxp->c0min = c0min = c0;\n\t    goto have_c0min;\n\t  }\n      }\n have_c0min:\n  if (c0max > c0min)\n    for (c0 = c0max; c0 >= c0min; c0--)\n      for (c1 = c1min; c1 <= c1max; c1++) {\n\thistp = & histogram[c0][c1][c2min];\n\tfor (c2 = c2min; c2 <= c2max; c2++)\n\t  if (*histp++ != 0) {\n\t    boxp->c0max = c0max = c0;\n\t    goto have_c0max;\n\t  }\n      }\n have_c0max:\n  if (c1max > c1min)\n    for (c1 = c1min; c1 <= c1max; c1++)\n      for (c0 = c0min; c0 <= c0max; c0++) {\n\thistp = & histogram[c0][c1][c2min];\n\tfor (c2 = c2min; c2 <= c2max; c2++)\n\t  if (*histp++ != 0) {\n\t    boxp->c1min = c1min = c1;\n\t    goto have_c1min;\n\t  }\n      }\n have_c1min:\n  if (c1max > c1min)\n    for (c1 = c1max; c1 >= c1min; c1--)\n      for (c0 = c0min; c0 <= c0max; c0++) {\n\thistp = & histogram[c0][c1][c2min];\n\tfor (c2 = c2min; c2 <= c2max; c2++)\n\t  if (*histp++ != 0) {\n\t    boxp->c1max = c1max = c1;\n\t    goto have_c1max;\n\t  }\n      }\n have_c1max:\n  if (c2max > c2min)\n    for (c2 = c2min; c2 <= c2max; c2++)\n      for (c0 = c0min; c0 <= c0max; c0++) {\n\thistp = & histogram[c0][c1min][c2];\n\tfor (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)\n\t  if (*histp != 0) {\n\t    boxp->c2min = c2min = c2;\n\t    goto have_c2min;\n\t  }\n      }\n have_c2min:\n  if (c2max > c2min)\n    for (c2 = c2max; c2 >= c2min; c2--)\n      for (c0 = c0min; c0 <= c0max; c0++) {\n\thistp = & histogram[c0][c1min][c2];\n\tfor (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)\n\t  if (*histp != 0) {\n\t    boxp->c2max = c2max = c2;\n\t    goto have_c2max;\n\t  }\n      }\n have_c2max:\n\n  /* Update box volume.\n   * We use 2-norm rather than real volume here; this biases the method\n   * against making long narrow boxes, and it has the side benefit that\n   * a box is splittable iff norm > 0.\n   * Since the differences are expressed in histogram-cell units,\n   * we have to shift back to JSAMPLE units to get consistent distances;\n   * after which, we scale according to the selected distance scale factors.\n   */\n  dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;\n  dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;\n  dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;\n  boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;\n  \n  /* Now scan remaining volume of box and compute population */\n  ccount = 0;\n  for (c0 = c0min; c0 <= c0max; c0++)\n    for (c1 = c1min; c1 <= c1max; c1++) {\n      histp = & histogram[c0][c1][c2min];\n      for (c2 = c2min; c2 <= c2max; c2++, histp++)\n\tif (*histp != 0) {\n\t  ccount++;\n\t}\n    }\n  boxp->colorcount = ccount;\n}\n\n\nLOCAL(int)\nmedian_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,\n\t    int desired_colors)\n/* Repeatedly select and split the largest box until we have enough boxes */\n{\n  int n,lb;\n  int c0,c1,c2,cmax;\n  register boxptr b1,b2;\n\n  while (numboxes < desired_colors) {\n    /* Select box to split.\n     * Current algorithm: by population for first half, then by volume.\n     */\n    if (numboxes*2 <= desired_colors) {\n      b1 = find_biggest_color_pop(boxlist, numboxes);\n    } else {\n      b1 = find_biggest_volume(boxlist, numboxes);\n    }\n    if (b1 == NULL)\t\t/* no splittable boxes left! */\n      break;\n    b2 = &boxlist[numboxes];\t/* where new box will go */\n    /* Copy the color bounds to the new box. */\n    b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;\n    b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;\n    /* Choose which axis to split the box on.\n     * Current algorithm: longest scaled axis.\n     * See notes in update_box about scaling distances.\n     */\n    c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;\n    c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;\n    c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;\n    /* We want to break any ties in favor of green, then red, blue last.\n     * This code does the right thing for R,G,B or B,G,R color orders only.\n     */\n#if RGB_RED == 0\n    cmax = c1; n = 1;\n    if (c0 > cmax) { cmax = c0; n = 0; }\n    if (c2 > cmax) { n = 2; }\n#else\n    cmax = c1; n = 1;\n    if (c2 > cmax) { cmax = c2; n = 2; }\n    if (c0 > cmax) { n = 0; }\n#endif\n    /* Choose split point along selected axis, and update box bounds.\n     * Current algorithm: split at halfway point.\n     * (Since the box has been shrunk to minimum volume,\n     * any split will produce two nonempty subboxes.)\n     * Note that lb value is max for lower box, so must be < old max.\n     */\n    switch (n) {\n    case 0:\n      lb = (b1->c0max + b1->c0min) / 2;\n      b1->c0max = lb;\n      b2->c0min = lb+1;\n      break;\n    case 1:\n      lb = (b1->c1max + b1->c1min) / 2;\n      b1->c1max = lb;\n      b2->c1min = lb+1;\n      break;\n    case 2:\n      lb = (b1->c2max + b1->c2min) / 2;\n      b1->c2max = lb;\n      b2->c2min = lb+1;\n      break;\n    }\n    /* Update stats for boxes */\n    update_box(cinfo, b1);\n    update_box(cinfo, b2);\n    numboxes++;\n  }\n  return numboxes;\n}\n\n\nLOCAL(void)\ncompute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)\n/* Compute representative color for a box, put it in colormap[icolor] */\n{\n  /* Current algorithm: mean weighted by pixels (not colors) */\n  /* Note it is important to get the rounding correct! */\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  histptr histp;\n  int c0,c1,c2;\n  int c0min,c0max,c1min,c1max,c2min,c2max;\n  long count;\n  long total = 0;\n  long c0total = 0;\n  long c1total = 0;\n  long c2total = 0;\n  \n  c0min = boxp->c0min;  c0max = boxp->c0max;\n  c1min = boxp->c1min;  c1max = boxp->c1max;\n  c2min = boxp->c2min;  c2max = boxp->c2max;\n  \n  for (c0 = c0min; c0 <= c0max; c0++)\n    for (c1 = c1min; c1 <= c1max; c1++) {\n      histp = & histogram[c0][c1][c2min];\n      for (c2 = c2min; c2 <= c2max; c2++) {\n\tif ((count = *histp++) != 0) {\n\t  total += count;\n\t  c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count;\n\t  c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count;\n\t  c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count;\n\t}\n      }\n    }\n  \n  cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);\n  cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);\n  cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);\n}\n\n\nLOCAL(void)\nselect_colors (j_decompress_ptr cinfo, int desired_colors)\n/* Master routine for color selection */\n{\n  boxptr boxlist;\n  int numboxes;\n  int i;\n\n  /* Allocate workspace for box list */\n  boxlist = (boxptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));\n  /* Initialize one box containing whole space */\n  numboxes = 1;\n  boxlist[0].c0min = 0;\n  boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;\n  boxlist[0].c1min = 0;\n  boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;\n  boxlist[0].c2min = 0;\n  boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;\n  /* Shrink it to actually-used volume and set its statistics */\n  update_box(cinfo, & boxlist[0]);\n  /* Perform median-cut to produce final box list */\n  numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);\n  /* Compute the representative color for each box, fill colormap */\n  for (i = 0; i < numboxes; i++)\n    compute_color(cinfo, & boxlist[i], i);\n  cinfo->actual_number_of_colors = numboxes;\n  TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);\n}\n\n\n/*\n * These routines are concerned with the time-critical task of mapping input\n * colors to the nearest color in the selected colormap.\n *\n * We re-use the histogram space as an \"inverse color map\", essentially a\n * cache for the results of nearest-color searches.  All colors within a\n * histogram cell will be mapped to the same colormap entry, namely the one\n * closest to the cell's center.  This may not be quite the closest entry to\n * the actual input color, but it's almost as good.  A zero in the cache\n * indicates we haven't found the nearest color for that cell yet; the array\n * is cleared to zeroes before starting the mapping pass.  When we find the\n * nearest color for a cell, its colormap index plus one is recorded in the\n * cache for future use.  The pass2 scanning routines call fill_inverse_cmap\n * when they need to use an unfilled entry in the cache.\n *\n * Our method of efficiently finding nearest colors is based on the \"locally\n * sorted search\" idea described by Heckbert and on the incremental distance\n * calculation described by Spencer W. Thomas in chapter III.1 of Graphics\n * Gems II (James Arvo, ed.  Academic Press, 1991).  Thomas points out that\n * the distances from a given colormap entry to each cell of the histogram can\n * be computed quickly using an incremental method: the differences between\n * distances to adjacent cells themselves differ by a constant.  This allows a\n * fairly fast implementation of the \"brute force\" approach of computing the\n * distance from every colormap entry to every histogram cell.  Unfortunately,\n * it needs a work array to hold the best-distance-so-far for each histogram\n * cell (because the inner loop has to be over cells, not colormap entries).\n * The work array elements have to be INT32s, so the work array would need\n * 256Kb at our recommended precision.  This is not feasible in DOS machines.\n *\n * To get around these problems, we apply Thomas' method to compute the\n * nearest colors for only the cells within a small subbox of the histogram.\n * The work array need be only as big as the subbox, so the memory usage\n * problem is solved.  Furthermore, we need not fill subboxes that are never\n * referenced in pass2; many images use only part of the color gamut, so a\n * fair amount of work is saved.  An additional advantage of this\n * approach is that we can apply Heckbert's locality criterion to quickly\n * eliminate colormap entries that are far away from the subbox; typically\n * three-fourths of the colormap entries are rejected by Heckbert's criterion,\n * and we need not compute their distances to individual cells in the subbox.\n * The speed of this approach is heavily influenced by the subbox size: too\n * small means too much overhead, too big loses because Heckbert's criterion\n * can't eliminate as many colormap entries.  Empirically the best subbox\n * size seems to be about 1/512th of the histogram (1/8th in each direction).\n *\n * Thomas' article also describes a refined method which is asymptotically\n * faster than the brute-force method, but it is also far more complex and\n * cannot efficiently be applied to small subboxes.  It is therefore not\n * useful for programs intended to be portable to DOS machines.  On machines\n * with plenty of memory, filling the whole histogram in one shot with Thomas'\n * refined method might be faster than the present code --- but then again,\n * it might not be any faster, and it's certainly more complicated.\n */\n\n\n/* log2(histogram cells in update box) for each axis; this can be adjusted */\n#define BOX_C0_LOG  (HIST_C0_BITS-3)\n#define BOX_C1_LOG  (HIST_C1_BITS-3)\n#define BOX_C2_LOG  (HIST_C2_BITS-3)\n\n#define BOX_C0_ELEMS  (1<<BOX_C0_LOG) /* # of hist cells in update box */\n#define BOX_C1_ELEMS  (1<<BOX_C1_LOG)\n#define BOX_C2_ELEMS  (1<<BOX_C2_LOG)\n\n#define BOX_C0_SHIFT  (C0_SHIFT + BOX_C0_LOG)\n#define BOX_C1_SHIFT  (C1_SHIFT + BOX_C1_LOG)\n#define BOX_C2_SHIFT  (C2_SHIFT + BOX_C2_LOG)\n\n\n/*\n * The next three routines implement inverse colormap filling.  They could\n * all be folded into one big routine, but splitting them up this way saves\n * some stack space (the mindist[] and bestdist[] arrays need not coexist)\n * and may allow some compilers to produce better code by registerizing more\n * inner-loop variables.\n */\n\nLOCAL(int)\nfind_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,\n\t\t    JSAMPLE colorlist[])\n/* Locate the colormap entries close enough to an update box to be candidates\n * for the nearest entry to some cell(s) in the update box.  The update box\n * is specified by the center coordinates of its first cell.  The number of\n * candidate colormap entries is returned, and their colormap indexes are\n * placed in colorlist[].\n * This routine uses Heckbert's \"locally sorted search\" criterion to select\n * the colors that need further consideration.\n */\n{\n  int numcolors = cinfo->actual_number_of_colors;\n  int maxc0, maxc1, maxc2;\n  int centerc0, centerc1, centerc2;\n  int i, x, ncolors;\n  INT32 minmaxdist, min_dist, max_dist, tdist;\n  INT32 mindist[MAXNUMCOLORS];\t/* min distance to colormap entry i */\n\n  /* Compute true coordinates of update box's upper corner and center.\n   * Actually we compute the coordinates of the center of the upper-corner\n   * histogram cell, which are the upper bounds of the volume we care about.\n   * Note that since \">>\" rounds down, the \"center\" values may be closer to\n   * min than to max; hence comparisons to them must be \"<=\", not \"<\".\n   */\n  maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));\n  centerc0 = (minc0 + maxc0) >> 1;\n  maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));\n  centerc1 = (minc1 + maxc1) >> 1;\n  maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));\n  centerc2 = (minc2 + maxc2) >> 1;\n\n  /* For each color in colormap, find:\n   *  1. its minimum squared-distance to any point in the update box\n   *     (zero if color is within update box);\n   *  2. its maximum squared-distance to any point in the update box.\n   * Both of these can be found by considering only the corners of the box.\n   * We save the minimum distance for each color in mindist[];\n   * only the smallest maximum distance is of interest.\n   */\n  minmaxdist = 0x7FFFFFFFL;\n\n  for (i = 0; i < numcolors; i++) {\n    /* We compute the squared-c0-distance term, then add in the other two. */\n    x = GETJSAMPLE(cinfo->colormap[0][i]);\n    if (x < minc0) {\n      tdist = (x - minc0) * C0_SCALE;\n      min_dist = tdist*tdist;\n      tdist = (x - maxc0) * C0_SCALE;\n      max_dist = tdist*tdist;\n    } else if (x > maxc0) {\n      tdist = (x - maxc0) * C0_SCALE;\n      min_dist = tdist*tdist;\n      tdist = (x - minc0) * C0_SCALE;\n      max_dist = tdist*tdist;\n    } else {\n      /* within cell range so no contribution to min_dist */\n      min_dist = 0;\n      if (x <= centerc0) {\n\ttdist = (x - maxc0) * C0_SCALE;\n\tmax_dist = tdist*tdist;\n      } else {\n\ttdist = (x - minc0) * C0_SCALE;\n\tmax_dist = tdist*tdist;\n      }\n    }\n\n    x = GETJSAMPLE(cinfo->colormap[1][i]);\n    if (x < minc1) {\n      tdist = (x - minc1) * C1_SCALE;\n      min_dist += tdist*tdist;\n      tdist = (x - maxc1) * C1_SCALE;\n      max_dist += tdist*tdist;\n    } else if (x > maxc1) {\n      tdist = (x - maxc1) * C1_SCALE;\n      min_dist += tdist*tdist;\n      tdist = (x - minc1) * C1_SCALE;\n      max_dist += tdist*tdist;\n    } else {\n      /* within cell range so no contribution to min_dist */\n      if (x <= centerc1) {\n\ttdist = (x - maxc1) * C1_SCALE;\n\tmax_dist += tdist*tdist;\n      } else {\n\ttdist = (x - minc1) * C1_SCALE;\n\tmax_dist += tdist*tdist;\n      }\n    }\n\n    x = GETJSAMPLE(cinfo->colormap[2][i]);\n    if (x < minc2) {\n      tdist = (x - minc2) * C2_SCALE;\n      min_dist += tdist*tdist;\n      tdist = (x - maxc2) * C2_SCALE;\n      max_dist += tdist*tdist;\n    } else if (x > maxc2) {\n      tdist = (x - maxc2) * C2_SCALE;\n      min_dist += tdist*tdist;\n      tdist = (x - minc2) * C2_SCALE;\n      max_dist += tdist*tdist;\n    } else {\n      /* within cell range so no contribution to min_dist */\n      if (x <= centerc2) {\n\ttdist = (x - maxc2) * C2_SCALE;\n\tmax_dist += tdist*tdist;\n      } else {\n\ttdist = (x - minc2) * C2_SCALE;\n\tmax_dist += tdist*tdist;\n      }\n    }\n\n    mindist[i] = min_dist;\t/* save away the results */\n    if (max_dist < minmaxdist)\n      minmaxdist = max_dist;\n  }\n\n  /* Now we know that no cell in the update box is more than minmaxdist\n   * away from some colormap entry.  Therefore, only colors that are\n   * within minmaxdist of some part of the box need be considered.\n   */\n  ncolors = 0;\n  for (i = 0; i < numcolors; i++) {\n    if (mindist[i] <= minmaxdist)\n      colorlist[ncolors++] = (JSAMPLE) i;\n  }\n  return ncolors;\n}\n\n\nLOCAL(void)\nfind_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,\n\t\t  int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])\n/* Find the closest colormap entry for each cell in the update box,\n * given the list of candidate colors prepared by find_nearby_colors.\n * Return the indexes of the closest entries in the bestcolor[] array.\n * This routine uses Thomas' incremental distance calculation method to\n * find the distance from a colormap entry to successive cells in the box.\n */\n{\n  int ic0, ic1, ic2;\n  int i, icolor;\n  register INT32 * bptr;\t/* pointer into bestdist[] array */\n  JSAMPLE * cptr;\t\t/* pointer into bestcolor[] array */\n  INT32 dist0, dist1;\t\t/* initial distance values */\n  register INT32 dist2;\t\t/* current distance in inner loop */\n  INT32 xx0, xx1;\t\t/* distance increments */\n  register INT32 xx2;\n  INT32 inc0, inc1, inc2;\t/* initial values for increments */\n  /* This array holds the distance to the nearest-so-far color for each cell */\n  INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];\n\n  /* Initialize best-distance for each cell of the update box */\n  bptr = bestdist;\n  for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)\n    *bptr++ = 0x7FFFFFFFL;\n  \n  /* For each color selected by find_nearby_colors,\n   * compute its distance to the center of each cell in the box.\n   * If that's less than best-so-far, update best distance and color number.\n   */\n  \n  /* Nominal steps between cell centers (\"x\" in Thomas article) */\n#define STEP_C0  ((1 << C0_SHIFT) * C0_SCALE)\n#define STEP_C1  ((1 << C1_SHIFT) * C1_SCALE)\n#define STEP_C2  ((1 << C2_SHIFT) * C2_SCALE)\n  \n  for (i = 0; i < numcolors; i++) {\n    icolor = GETJSAMPLE(colorlist[i]);\n    /* Compute (square of) distance from minc0/c1/c2 to this color */\n    inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;\n    dist0 = inc0*inc0;\n    inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;\n    dist0 += inc1*inc1;\n    inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;\n    dist0 += inc2*inc2;\n    /* Form the initial difference increments */\n    inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;\n    inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;\n    inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;\n    /* Now loop over all cells in box, updating distance per Thomas method */\n    bptr = bestdist;\n    cptr = bestcolor;\n    xx0 = inc0;\n    for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {\n      dist1 = dist0;\n      xx1 = inc1;\n      for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {\n\tdist2 = dist1;\n\txx2 = inc2;\n\tfor (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {\n\t  if (dist2 < *bptr) {\n\t    *bptr = dist2;\n\t    *cptr = (JSAMPLE) icolor;\n\t  }\n\t  dist2 += xx2;\n\t  xx2 += 2 * STEP_C2 * STEP_C2;\n\t  bptr++;\n\t  cptr++;\n\t}\n\tdist1 += xx1;\n\txx1 += 2 * STEP_C1 * STEP_C1;\n      }\n      dist0 += xx0;\n      xx0 += 2 * STEP_C0 * STEP_C0;\n    }\n  }\n}\n\n\nLOCAL(void)\nfill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)\n/* Fill the inverse-colormap entries in the update box that contains */\n/* histogram cell c0/c1/c2.  (Only that one cell MUST be filled, but */\n/* we can fill as many others as we wish.) */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  int minc0, minc1, minc2;\t/* lower left corner of update box */\n  int ic0, ic1, ic2;\n  register JSAMPLE * cptr;\t/* pointer into bestcolor[] array */\n  register histptr cachep;\t/* pointer into main cache array */\n  /* This array lists the candidate colormap indexes. */\n  JSAMPLE colorlist[MAXNUMCOLORS];\n  int numcolors;\t\t/* number of candidate colors */\n  /* This array holds the actually closest colormap index for each cell. */\n  JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];\n\n  /* Convert cell coordinates to update box ID */\n  c0 >>= BOX_C0_LOG;\n  c1 >>= BOX_C1_LOG;\n  c2 >>= BOX_C2_LOG;\n\n  /* Compute true coordinates of update box's origin corner.\n   * Actually we compute the coordinates of the center of the corner\n   * histogram cell, which are the lower bounds of the volume we care about.\n   */\n  minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);\n  minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);\n  minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);\n  \n  /* Determine which colormap entries are close enough to be candidates\n   * for the nearest entry to some cell in the update box.\n   */\n  numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);\n\n  /* Determine the actually nearest colors. */\n  find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,\n\t\t   bestcolor);\n\n  /* Save the best color numbers (plus 1) in the main cache array */\n  c0 <<= BOX_C0_LOG;\t\t/* convert ID back to base cell indexes */\n  c1 <<= BOX_C1_LOG;\n  c2 <<= BOX_C2_LOG;\n  cptr = bestcolor;\n  for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {\n    for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {\n      cachep = & histogram[c0+ic0][c1+ic1][c2];\n      for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {\n\t*cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);\n      }\n    }\n  }\n}\n\n\n/*\n * Map some rows of pixels to the output colormapped representation.\n */\n\nMETHODDEF(void)\npass2_no_dither (j_decompress_ptr cinfo,\n\t\t JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)\n/* This version performs no dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  register JSAMPROW inptr, outptr;\n  register histptr cachep;\n  register int c0, c1, c2;\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n\n  for (row = 0; row < num_rows; row++) {\n    inptr = input_buf[row];\n    outptr = output_buf[row];\n    for (col = width; col > 0; col--) {\n      /* get pixel value and index into the cache */\n      c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;\n      c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;\n      c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;\n      cachep = & histogram[c0][c1][c2];\n      /* If we have not seen this color before, find nearest colormap entry */\n      /* and update the cache */\n      if (*cachep == 0)\n\tfill_inverse_cmap(cinfo, c0,c1,c2);\n      /* Now emit the colormap index for this cell */\n      *outptr++ = (JSAMPLE) (*cachep - 1);\n    }\n  }\n}\n\n\nMETHODDEF(void)\npass2_fs_dither (j_decompress_ptr cinfo,\n\t\t JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)\n/* This version performs Floyd-Steinberg dithering */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  register LOCFSERROR cur0, cur1, cur2;\t/* current error or pixel value */\n  LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */\n  LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */\n  register FSERRPTR errorptr;\t/* => fserrors[] at column before current */\n  JSAMPROW inptr;\t\t/* => current input pixel */\n  JSAMPROW outptr;\t\t/* => current output pixel */\n  histptr cachep;\n  int dir;\t\t\t/* +1 or -1 depending on direction */\n  int dir3;\t\t\t/* 3*dir, for advancing inptr & errorptr */\n  int row;\n  JDIMENSION col;\n  JDIMENSION width = cinfo->output_width;\n  JSAMPLE *range_limit = cinfo->sample_range_limit;\n  int *error_limit = cquantize->error_limiter;\n  JSAMPROW colormap0 = cinfo->colormap[0];\n  JSAMPROW colormap1 = cinfo->colormap[1];\n  JSAMPROW colormap2 = cinfo->colormap[2];\n  SHIFT_TEMPS\n\n  for (row = 0; row < num_rows; row++) {\n    inptr = input_buf[row];\n    outptr = output_buf[row];\n    if (cquantize->on_odd_row) {\n      /* work right to left in this row */\n      inptr += (width-1) * 3;\t/* so point to rightmost pixel */\n      outptr += width-1;\n      dir = -1;\n      dir3 = -3;\n      errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */\n      cquantize->on_odd_row = FALSE; /* flip for next time */\n    } else {\n      /* work left to right in this row */\n      dir = 1;\n      dir3 = 3;\n      errorptr = cquantize->fserrors; /* => entry before first real column */\n      cquantize->on_odd_row = TRUE; /* flip for next time */\n    }\n    /* Preset error values: no error propagated to first pixel from left */\n    cur0 = cur1 = cur2 = 0;\n    /* and no error propagated to row below yet */\n    belowerr0 = belowerr1 = belowerr2 = 0;\n    bpreverr0 = bpreverr1 = bpreverr2 = 0;\n\n    for (col = width; col > 0; col--) {\n      /* curN holds the error propagated from the previous pixel on the\n       * current line.  Add the error propagated from the previous line\n       * to form the complete error correction term for this pixel, and\n       * round the error term (which is expressed * 16) to an integer.\n       * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct\n       * for either sign of the error value.\n       * Note: errorptr points to *previous* column's array entry.\n       */\n      cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);\n      cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);\n      cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);\n      /* Limit the error using transfer function set by init_error_limit.\n       * See comments with init_error_limit for rationale.\n       */\n      cur0 = error_limit[cur0];\n      cur1 = error_limit[cur1];\n      cur2 = error_limit[cur2];\n      /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.\n       * The maximum error is +- MAXJSAMPLE (or less with error limiting);\n       * this sets the required size of the range_limit array.\n       */\n      cur0 += GETJSAMPLE(inptr[0]);\n      cur1 += GETJSAMPLE(inptr[1]);\n      cur2 += GETJSAMPLE(inptr[2]);\n      cur0 = GETJSAMPLE(range_limit[cur0]);\n      cur1 = GETJSAMPLE(range_limit[cur1]);\n      cur2 = GETJSAMPLE(range_limit[cur2]);\n      /* Index into the cache with adjusted pixel value */\n      cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];\n      /* If we have not seen this color before, find nearest colormap */\n      /* entry and update the cache */\n      if (*cachep == 0)\n\tfill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);\n      /* Now emit the colormap index for this cell */\n      { register int pixcode = *cachep - 1;\n\t*outptr = (JSAMPLE) pixcode;\n\t/* Compute representation error for this pixel */\n\tcur0 -= GETJSAMPLE(colormap0[pixcode]);\n\tcur1 -= GETJSAMPLE(colormap1[pixcode]);\n\tcur2 -= GETJSAMPLE(colormap2[pixcode]);\n      }\n      /* Compute error fractions to be propagated to adjacent pixels.\n       * Add these into the running sums, and simultaneously shift the\n       * next-line error sums left by 1 column.\n       */\n      { register LOCFSERROR bnexterr, delta;\n\n\tbnexterr = cur0;\t/* Process component 0 */\n\tdelta = cur0 * 2;\n\tcur0 += delta;\t\t/* form error * 3 */\n\terrorptr[0] = (FSERROR) (bpreverr0 + cur0);\n\tcur0 += delta;\t\t/* form error * 5 */\n\tbpreverr0 = belowerr0 + cur0;\n\tbelowerr0 = bnexterr;\n\tcur0 += delta;\t\t/* form error * 7 */\n\tbnexterr = cur1;\t/* Process component 1 */\n\tdelta = cur1 * 2;\n\tcur1 += delta;\t\t/* form error * 3 */\n\terrorptr[1] = (FSERROR) (bpreverr1 + cur1);\n\tcur1 += delta;\t\t/* form error * 5 */\n\tbpreverr1 = belowerr1 + cur1;\n\tbelowerr1 = bnexterr;\n\tcur1 += delta;\t\t/* form error * 7 */\n\tbnexterr = cur2;\t/* Process component 2 */\n\tdelta = cur2 * 2;\n\tcur2 += delta;\t\t/* form error * 3 */\n\terrorptr[2] = (FSERROR) (bpreverr2 + cur2);\n\tcur2 += delta;\t\t/* form error * 5 */\n\tbpreverr2 = belowerr2 + cur2;\n\tbelowerr2 = bnexterr;\n\tcur2 += delta;\t\t/* form error * 7 */\n      }\n      /* At this point curN contains the 7/16 error value to be propagated\n       * to the next pixel on the current line, and all the errors for the\n       * next line have been shifted over.  We are therefore ready to move on.\n       */\n      inptr += dir3;\t\t/* Advance pixel pointers to next column */\n      outptr += dir;\n      errorptr += dir3;\t\t/* advance errorptr to current column */\n    }\n    /* Post-loop cleanup: we must unload the final error values into the\n     * final fserrors[] entry.  Note we need not unload belowerrN because\n     * it is for the dummy column before or after the actual array.\n     */\n    errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */\n    errorptr[1] = (FSERROR) bpreverr1;\n    errorptr[2] = (FSERROR) bpreverr2;\n  }\n}\n\n\n/*\n * Initialize the error-limiting transfer function (lookup table).\n * The raw F-S error computation can potentially compute error values of up to\n * +- MAXJSAMPLE.  But we want the maximum correction applied to a pixel to be\n * much less, otherwise obviously wrong pixels will be created.  (Typical\n * effects include weird fringes at color-area boundaries, isolated bright\n * pixels in a dark area, etc.)  The standard advice for avoiding this problem\n * is to ensure that the \"corners\" of the color cube are allocated as output\n * colors; then repeated errors in the same direction cannot cause cascading\n * error buildup.  However, that only prevents the error from getting\n * completely out of hand; Aaron Giles reports that error limiting improves\n * the results even with corner colors allocated.\n * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty\n * well, but the smoother transfer function used below is even better.  Thanks\n * to Aaron Giles for this idea.\n */\n\nLOCAL(void)\ninit_error_limit (j_decompress_ptr cinfo)\n/* Allocate and fill in the error_limiter table */\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  int * table;\n  int in, out;\n\n  table = (int *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));\n  table += MAXJSAMPLE;\t\t/* so can index -MAXJSAMPLE .. +MAXJSAMPLE */\n  cquantize->error_limiter = table;\n\n#define STEPSIZE ((MAXJSAMPLE+1)/16)\n  /* Map errors 1:1 up to +- MAXJSAMPLE/16 */\n  out = 0;\n  for (in = 0; in < STEPSIZE; in++, out++) {\n    table[in] = out; table[-in] = -out;\n  }\n  /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */\n  for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {\n    table[in] = out; table[-in] = -out;\n  }\n  /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */\n  for (; in <= MAXJSAMPLE; in++) {\n    table[in] = out; table[-in] = -out;\n  }\n#undef STEPSIZE\n}\n\n\n/*\n * Finish up at the end of each pass.\n */\n\nMETHODDEF(void)\nfinish_pass1 (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n\n  /* Select the representative colors and fill in cinfo->colormap */\n  cinfo->colormap = cquantize->sv_colormap;\n  select_colors(cinfo, cquantize->desired);\n  /* Force next pass to zero the color index table */\n  cquantize->needs_zeroed = TRUE;\n}\n\n\nMETHODDEF(void)\nfinish_pass2 (j_decompress_ptr cinfo)\n{\n  /* no work */\n}\n\n\n/*\n * Initialize for each processing pass.\n */\n\nMETHODDEF(void)\nstart_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n  hist3d histogram = cquantize->histogram;\n  int i;\n\n  /* Only F-S dithering or no dithering is supported. */\n  /* If user asks for ordered dither, give him F-S. */\n  if (cinfo->dither_mode != JDITHER_NONE)\n    cinfo->dither_mode = JDITHER_FS;\n\n  if (is_pre_scan) {\n    /* Set up method pointers */\n    cquantize->pub.color_quantize = prescan_quantize;\n    cquantize->pub.finish_pass = finish_pass1;\n    cquantize->needs_zeroed = TRUE; /* Always zero histogram */\n  } else {\n    /* Set up method pointers */\n    if (cinfo->dither_mode == JDITHER_FS)\n      cquantize->pub.color_quantize = pass2_fs_dither;\n    else\n      cquantize->pub.color_quantize = pass2_no_dither;\n    cquantize->pub.finish_pass = finish_pass2;\n\n    /* Make sure color count is acceptable */\n    i = cinfo->actual_number_of_colors;\n    if (i < 1)\n      ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);\n    if (i > MAXNUMCOLORS)\n      ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);\n\n    if (cinfo->dither_mode == JDITHER_FS) {\n      size_t arraysize = ((size_t) cinfo->output_width + (size_t) 2)\n\t* (3 * SIZEOF(FSERROR));\n      /* Allocate Floyd-Steinberg workspace if we didn't already. */\n      if (cquantize->fserrors == NULL)\n\tcquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)\n\t  ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);\n      /* Initialize the propagated errors to zero. */\n      FMEMZERO((void FAR *) cquantize->fserrors, arraysize);\n      /* Make the error-limit table if we didn't already. */\n      if (cquantize->error_limiter == NULL)\n\tinit_error_limit(cinfo);\n      cquantize->on_odd_row = FALSE;\n    }\n\n  }\n  /* Zero the histogram or inverse color map, if necessary */\n  if (cquantize->needs_zeroed) {\n    for (i = 0; i < HIST_C0_ELEMS; i++) {\n      FMEMZERO((void FAR *) histogram[i],\n\t       HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));\n    }\n    cquantize->needs_zeroed = FALSE;\n  }\n}\n\n\n/*\n * Switch to a new external colormap between output passes.\n */\n\nMETHODDEF(void)\nnew_color_map_2_quant (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;\n\n  /* Reset the inverse color map */\n  cquantize->needs_zeroed = TRUE;\n}\n\n\n/*\n * Module initialization routine for 2-pass color quantization.\n */\n\nGLOBAL(void)\njinit_2pass_quantizer (j_decompress_ptr cinfo)\n{\n  my_cquantize_ptr cquantize;\n  int i;\n\n  cquantize = (my_cquantize_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(my_cquantizer));\n  cinfo->cquantize = &cquantize->pub;\n  cquantize->pub.start_pass = start_pass_2_quant;\n  cquantize->pub.new_color_map = new_color_map_2_quant;\n  cquantize->fserrors = NULL;\t/* flag optional arrays not allocated */\n  cquantize->error_limiter = NULL;\n\n  /* Make sure jdmaster didn't give me a case I can't handle */\n  if (cinfo->out_color_components != 3)\n    ERREXIT(cinfo, JERR_NOTIMPL);\n\n  /* Allocate the histogram/inverse colormap storage */\n  cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));\n  for (i = 0; i < HIST_C0_ELEMS; i++) {\n    cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));\n  }\n  cquantize->needs_zeroed = TRUE; /* histogram is garbage now */\n\n  /* Allocate storage for the completed colormap, if required.\n   * We do this now since it is FAR storage and may affect\n   * the memory manager's space calculations.\n   */\n  if (cinfo->enable_2pass_quant) {\n    /* Make sure color count is acceptable */\n    int desired = cinfo->desired_number_of_colors;\n    /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */\n    if (desired < 8)\n      ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);\n    /* Make sure colormap indexes can be represented by JSAMPLEs */\n    if (desired > MAXNUMCOLORS)\n      ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);\n    cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       (JDIMENSION) desired, (JDIMENSION) 3);\n    cquantize->desired = desired;\n  } else\n    cquantize->sv_colormap = NULL;\n\n  /* Only F-S dithering or no dithering is supported. */\n  /* If user asks for ordered dither, give him F-S. */\n  if (cinfo->dither_mode != JDITHER_NONE)\n    cinfo->dither_mode = JDITHER_FS;\n\n  /* Allocate Floyd-Steinberg workspace if necessary.\n   * This isn't really needed until pass 2, but again it is FAR storage.\n   * Although we will cope with a later change in dither_mode,\n   * we do not promise to honor max_memory_to_use if dither_mode changes.\n   */\n  if (cinfo->dither_mode == JDITHER_FS) {\n    cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       ((size_t) cinfo->output_width + (size_t) 2) * (3 * SIZEOF(FSERROR)));\n    /* Might as well create the error-limiting table too. */\n    init_error_limit(cinfo);\n  }\n}\n\n#endif /* QUANT_2PASS_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/jutils.c",
    "content": "/*\n * jutils.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2009-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains tables and miscellaneous utility routines needed\n * for both compression and decompression.\n * Note we prefix all global names with \"j\" to minimize conflicts with\n * a surrounding application.\n */\n\n#define JPEG_INTERNALS\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n\n\n/*\n * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element\n * of a DCT block read in natural order (left to right, top to bottom).\n */\n\n#if 0\t\t\t\t/* This table is not actually needed in v6a */\n\nconst int jpeg_zigzag_order[DCTSIZE2] = {\n   0,  1,  5,  6, 14, 15, 27, 28,\n   2,  4,  7, 13, 16, 26, 29, 42,\n   3,  8, 12, 17, 25, 30, 41, 43,\n   9, 11, 18, 24, 31, 40, 44, 53,\n  10, 19, 23, 32, 39, 45, 52, 54,\n  20, 22, 33, 38, 46, 51, 55, 60,\n  21, 34, 37, 47, 50, 56, 59, 61,\n  35, 36, 48, 49, 57, 58, 62, 63\n};\n\n#endif\n\n/*\n * jpeg_natural_order[i] is the natural-order position of the i'th element\n * of zigzag order.\n *\n * When reading corrupted data, the Huffman decoders could attempt\n * to reference an entry beyond the end of this array (if the decoded\n * zero run length reaches past the end of the block).  To prevent\n * wild stores without adding an inner-loop test, we put some extra\n * \"63\"s after the real entries.  This will cause the extra coefficient\n * to be stored in location 63 of the block, not somewhere random.\n * The worst case would be a run-length of 15, which means we need 16\n * fake entries.\n */\n\nconst int jpeg_natural_order[DCTSIZE2+16] = {\n   0,  1,  8, 16,  9,  2,  3, 10,\n  17, 24, 32, 25, 18, 11,  4,  5,\n  12, 19, 26, 33, 40, 48, 41, 34,\n  27, 20, 13,  6,  7, 14, 21, 28,\n  35, 42, 49, 56, 57, 50, 43, 36,\n  29, 22, 15, 23, 30, 37, 44, 51,\n  58, 59, 52, 45, 38, 31, 39, 46,\n  53, 60, 61, 54, 47, 55, 62, 63,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order7[7*7+16] = {\n   0,  1,  8, 16,  9,  2,  3, 10,\n  17, 24, 32, 25, 18, 11,  4,  5,\n  12, 19, 26, 33, 40, 48, 41, 34,\n  27, 20, 13,  6, 14, 21, 28, 35,\n  42, 49, 50, 43, 36, 29, 22, 30,\n  37, 44, 51, 52, 45, 38, 46, 53,\n  54,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order6[6*6+16] = {\n   0,  1,  8, 16,  9,  2,  3, 10,\n  17, 24, 32, 25, 18, 11,  4,  5,\n  12, 19, 26, 33, 40, 41, 34, 27,\n  20, 13, 21, 28, 35, 42, 43, 36,\n  29, 37, 44, 45,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order5[5*5+16] = {\n   0,  1,  8, 16,  9,  2,  3, 10,\n  17, 24, 32, 25, 18, 11,  4, 12,\n  19, 26, 33, 34, 27, 20, 28, 35,\n  36,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order4[4*4+16] = {\n   0,  1,  8, 16,  9,  2,  3, 10,\n  17, 24, 25, 18, 11, 19, 26, 27,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order3[3*3+16] = {\n   0,  1,  8, 16,  9,  2, 10, 17,\n  18,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\nconst int jpeg_natural_order2[2*2+16] = {\n   0,  1,  8,  9,\n  63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */\n  63, 63, 63, 63, 63, 63, 63, 63\n};\n\n\n/*\n * Arithmetic utilities\n */\n\nGLOBAL(long)\njdiv_round_up (long a, long b)\n/* Compute a/b rounded up to next integer, ie, ceil(a/b) */\n/* Assumes a >= 0, b > 0 */\n{\n  return (a + b - 1L) / b;\n}\n\n\nGLOBAL(long)\njround_up (long a, long b)\n/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */\n/* Assumes a >= 0, b > 0 */\n{\n  a += b - 1L;\n  return a - (a % b);\n}\n\n\n/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays\n * and coefficient-block arrays.  This won't work on 80x86 because the arrays\n * are FAR and we're assuming a small-pointer memory model.  However, some\n * DOS compilers provide far-pointer versions of memcpy() and memset() even\n * in the small-model libraries.  These will be used if USE_FMEM is defined.\n * Otherwise, the routines below do it the hard way.  (The performance cost\n * is not all that great, because these routines aren't very heavily used.)\n */\n\n#ifndef NEED_FAR_POINTERS\t/* normal case, same as regular macro */\n#define FMEMCOPY(dest,src,size)\tMEMCOPY(dest,src,size)\n#else\t\t\t\t/* 80x86 case, define if we can */\n#ifdef USE_FMEM\n#define FMEMCOPY(dest,src,size)\t_fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))\n#else\n/* This function is for use by the FMEMZERO macro defined in jpegint.h.\n * Do not call this function directly, use the FMEMZERO macro instead.\n */\nGLOBAL(void)\njzero_far (void FAR * target, size_t bytestozero)\n/* Zero out a chunk of FAR memory. */\n/* This might be sample-array data, block-array data, or alloc_large data. */\n{\n  register char FAR * ptr = (char FAR *) target;\n  register size_t count;\n\n  for (count = bytestozero; count > 0; count--) {\n    *ptr++ = 0;\n  }\n}\n#endif\n#endif\n\n\nGLOBAL(void)\njcopy_sample_rows (JSAMPARRAY input_array,\n\t\t   JSAMPARRAY output_array,\n\t\t   int num_rows, JDIMENSION num_cols)\n/* Copy some rows of samples from one place to another.\n * num_rows rows are copied from *input_array++ to *output_array++;\n * these areas may overlap for duplication.\n * The source and destination arrays must be at least as wide as num_cols.\n */\n{\n  register JSAMPROW inptr, outptr;\n#ifdef FMEMCOPY\n  register size_t count = (size_t) num_cols * SIZEOF(JSAMPLE);\n#else\n  register JDIMENSION count;\n#endif\n  register int row;\n\n  for (row = num_rows; row > 0; row--) {\n    inptr = *input_array++;\n    outptr = *output_array++;\n#ifdef FMEMCOPY\n    FMEMCOPY(outptr, inptr, count);\n#else\n    for (count = num_cols; count > 0; count--)\n      *outptr++ = *inptr++;\t/* needn't bother with GETJSAMPLE() here */\n#endif\n  }\n}\n\n\nGLOBAL(void)\njcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,\n\t\t JDIMENSION num_blocks)\n/* Copy a row of coefficient blocks from one place to another. */\n{\n#ifdef FMEMCOPY\n  FMEMCOPY(output_row, input_row, (size_t) num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));\n#else\n  register JCOEFPTR inptr, outptr;\n  register long count;\n\n  inptr = (JCOEFPTR) input_row;\n  outptr = (JCOEFPTR) output_row;\n  for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {\n    *outptr++ = *inptr++;\n  }\n#endif\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/jversion.h",
    "content": "/*\n * jversion.h\n *\n * Copyright (C) 1991-2022, Thomas G. Lane, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains software version identification.\n */\n\n\n#define JVERSION\t\"9e  16-Jan-2022\"\n\n#define JCOPYRIGHT\t\"Copyright (C) 2022, Thomas G. Lane, Guido Vollbeding\"\n"
  },
  {
    "path": "dlib/external/libjpeg/rdbmp.c",
    "content": "/*\n * rdbmp.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2009-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to read input images in Microsoft \"BMP\"\n * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).\n * Currently, only 8-, 24-, and 32-bit images are supported, not 1-bit or\n * 4-bit (feeding such low-depth images into JPEG would be silly anyway).\n * Also, we don't support RLE-compressed files.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume input from\n * an ordinary stdio stream.  They further assume that reading begins\n * at the start of the file; start_input may need work if the\n * user interface has already read some data (e.g., to determine that\n * the file is indeed BMP format).\n *\n * This code contributed by James Arthur Boucher.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef BMP_SUPPORTED\n\n\n/* Macros to deal with unsigned chars as efficiently as compiler allows */\n\n#ifdef HAVE_UNSIGNED_CHAR\ntypedef unsigned char U_CHAR;\n#define UCH(x)\t((int) (x))\n#else /* !HAVE_UNSIGNED_CHAR */\ntypedef char U_CHAR;\n#ifdef CHAR_IS_UNSIGNED\n#define UCH(x)\t((int) (x))\n#else\n#define UCH(x)\t((int) (x) & 0xFF)\n#endif\n#endif /* HAVE_UNSIGNED_CHAR */\n\n\n#define\tReadOK(file,buffer,len)\t(JFREAD(file,buffer,len) == ((size_t) (len)))\n\n\n/* Private version of data source object */\n\ntypedef struct _bmp_source_struct * bmp_source_ptr;\n\ntypedef struct _bmp_source_struct {\n  struct cjpeg_source_struct pub; /* public fields */\n\n  j_compress_ptr cinfo;\t\t/* back link saves passing separate parm */\n\n  JSAMPARRAY colormap;\t\t/* BMP colormap (converted to my format) */\n\n  jvirt_sarray_ptr whole_image;\t/* Needed to reverse row order */\n  JDIMENSION source_row;\t/* Current source row number */\n  JDIMENSION row_width;\t\t/* Physical width of scanlines in file */\n\n  int bits_per_pixel;\t\t/* remembers 8-, 24-, or 32-bit format */\n  int cmap_length;\t\t/* colormap length */\n} bmp_source_struct;\n\n\nLOCAL(int)\nread_byte (bmp_source_ptr sinfo)\n/* Read next byte from BMP file */\n{\n  register FILE *infile = sinfo->pub.input_file;\n  register int c;\n\n  if ((c = getc(infile)) == EOF)\n    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);\n  return c;\n}\n\n\nLOCAL(void)\nread_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)\n/* Read the colormap from a BMP file */\n{\n  int i;\n\n  switch (mapentrysize) {\n  case 3:\n    /* BGR format (occurs in OS/2 files) */\n    for (i = 0; i < cmaplen; i++) {\n      sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);\n      sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);\n      sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);\n    }\n    break;\n  case 4:\n    /* BGR0 format (occurs in MS Windows files) */\n    for (i = 0; i < cmaplen; i++) {\n      sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);\n      sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);\n      sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);\n      (void) read_byte(sinfo);\n    }\n    break;\n  default:\n    ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);\n  }\n}\n\n\n/*\n * Read one row of pixels.\n * The image has been read into the whole_image array, but is otherwise\n * unprocessed.  We must read it out in top-to-bottom row order, and if\n * it is an 8-bit image, we must expand colormapped pixels to 24bit format.\n */\n\nMETHODDEF(JDIMENSION)\nget_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 8-bit colormap indexes */\n{\n  bmp_source_ptr source = (bmp_source_ptr) sinfo;\n  register JSAMPROW inptr, outptr;\n  register JSAMPARRAY colormap;\n  register JDIMENSION col;\n  register int t;\n  int cmaplen;\n\n  /* Fetch next row from virtual array */\n  source->source_row--;\n  inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);\n\n  /* Expand the colormap indexes to real data */\n  outptr = source->pub.buffer[0];\n  colormap = source->colormap;\n  cmaplen = source->cmap_length;\n  for (col = cinfo->image_width; col > 0; col--) {\n    t = GETJSAMPLE(*inptr++);\n    if (t >= cmaplen)\n      ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);\n    *outptr++ = colormap[0][t];\t/* can omit GETJSAMPLE() safely */\n    *outptr++ = colormap[1][t];\n    *outptr++ = colormap[2][t];\n  }\n\n  return 1;\n}\n\nMETHODDEF(JDIMENSION)\nget_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 24-bit pixels */\n{\n  bmp_source_ptr source = (bmp_source_ptr) sinfo;\n  register JSAMPROW inptr, outptr;\n  register JDIMENSION col;\n\n  /* Fetch next row from virtual array */\n  source->source_row--;\n  inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);\n\n  /* Transfer data.  Note source values are in BGR order\n   * (even though Microsoft's own documents say the opposite).\n   */\n  outptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    outptr[2] = *inptr++;\t/* can omit GETJSAMPLE() safely */\n    outptr[1] = *inptr++;\n    outptr[0] = *inptr++;\n    outptr += 3;\n  }\n\n  return 1;\n}\n\nMETHODDEF(JDIMENSION)\nget_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 32-bit pixels */\n{\n  bmp_source_ptr source = (bmp_source_ptr) sinfo;\n  register JSAMPROW inptr, outptr;\n  register JDIMENSION col;\n\n  /* Fetch next row from virtual array */\n  source->source_row--;\n  inptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    source->whole_image, source->source_row, (JDIMENSION) 1, FALSE);\n\n  /* Transfer data.  Note source values are in BGR order\n   * (even though Microsoft's own documents say the opposite).\n   */\n  outptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    outptr[2] = *inptr++;\t/* can omit GETJSAMPLE() safely */\n    outptr[1] = *inptr++;\n    outptr[0] = *inptr++;\n    inptr++;\t\t\t/* skip the 4th byte (Alpha channel) */\n    outptr += 3;\n  }\n\n  return 1;\n}\n\n\n/*\n * This method loads the image into whole_image during the first call on\n * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call\n * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.\n */\n\nMETHODDEF(JDIMENSION)\npreload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  bmp_source_ptr source = (bmp_source_ptr) sinfo;\n  register FILE *infile = source->pub.input_file;\n  register int c;\n  register JSAMPROW out_ptr;\n  JDIMENSION row, col;\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n\n  /* Read the data into a virtual array in input-file row order. */\n  for (row = 0; row < cinfo->image_height; row++) {\n    if (progress != NULL) {\n      progress->pub.pass_counter = (long) row;\n      progress->pub.pass_limit = (long) cinfo->image_height;\n      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n    }\n    out_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n      source->whole_image, row, (JDIMENSION) 1, TRUE);\n    for (col = source->row_width; col > 0; col--) {\n      /* inline copy of read_byte() for speed */\n      if ((c = getc(infile)) == EOF)\n\tERREXIT(cinfo, JERR_INPUT_EOF);\n      *out_ptr++ = (JSAMPLE) c;\n    }\n  }\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n\n  /* Set up to read from the virtual array in top-to-bottom order */\n  switch (source->bits_per_pixel) {\n  case 8:\n    source->pub.get_pixel_rows = get_8bit_row;\n    break;\n  case 24:\n    source->pub.get_pixel_rows = get_24bit_row;\n    break;\n  case 32:\n    source->pub.get_pixel_rows = get_32bit_row;\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BMP_BADDEPTH);\n  }\n  source->source_row = cinfo->image_height;\n\n  /* And read the first row */\n  return (*source->pub.get_pixel_rows) (cinfo, sinfo);\n}\n\n\n/*\n * Read the file header; return image size and component count.\n */\n\nMETHODDEF(void)\nstart_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  bmp_source_ptr source = (bmp_source_ptr) sinfo;\n  U_CHAR bmpfileheader[14];\n  U_CHAR bmpinfoheader[64];\n#define GET_2B(array, offset)  ((unsigned int) UCH(array[offset]) + \\\n\t\t\t\t(((unsigned int) UCH(array[offset+1])) << 8))\n#define GET_4B(array, offset)  ((INT32) UCH(array[offset]) + \\\n\t\t\t\t(((INT32) UCH(array[offset+1])) << 8) + \\\n\t\t\t\t(((INT32) UCH(array[offset+2])) << 16) + \\\n\t\t\t\t(((INT32) UCH(array[offset+3])) << 24))\n  INT32 bfOffBits;\n  INT32 headerSize;\n  INT32 biWidth;\n  INT32 biHeight;\n  unsigned int biPlanes;\n  INT32 biCompression;\n  INT32 biXPelsPerMeter,biYPelsPerMeter;\n  INT32 biClrUsed = 0;\n  int mapentrysize = 0;\t\t/* 0 indicates no colormap */\n  INT32 bPad;\n  JDIMENSION row_width;\n\n  /* Read and verify the bitmap file header */\n  if (! ReadOK(source->pub.input_file, bmpfileheader, 14))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  if (GET_2B(bmpfileheader, 0) != 0x4D42) /* 'BM' */\n    ERREXIT(cinfo, JERR_BMP_NOT);\n  bfOffBits = GET_4B(bmpfileheader, 10);\n  /* We ignore the remaining fileheader fields */\n\n  /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),\n   * or 64 bytes (OS/2 2.x).  Check the first 4 bytes to find out which.\n   */\n  if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  headerSize = GET_4B(bmpinfoheader, 0);\n  if (headerSize < 12 || headerSize > 64)\n    ERREXIT(cinfo, JERR_BMP_BADHEADER);\n  if (! ReadOK(source->pub.input_file, bmpinfoheader + 4, headerSize - 4))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n\n  switch ((int) headerSize) {\n  case 12:\n    /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */\n    biWidth = (INT32) GET_2B(bmpinfoheader, 4);\n    biHeight = (INT32) GET_2B(bmpinfoheader, 6);\n    biPlanes = GET_2B(bmpinfoheader, 8);\n    source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 10);\n\n    switch (source->bits_per_pixel) {\n    case 8:\t\t\t/* colormapped image */\n      mapentrysize = 3;\t\t/* OS/2 uses RGBTRIPLE colormap */\n      TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);\n      break;\n    case 24:\t\t\t/* RGB image */\n    case 32:\t\t\t/* RGB image + Alpha channel */\n      TRACEMS3(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight,\n\t       source->bits_per_pixel);\n      break;\n    default:\n      ERREXIT(cinfo, JERR_BMP_BADDEPTH);\n    }\n    break;\n  case 40:\n  case 64:\n    /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */\n    /* or OS/2 2.x header, which has additional fields that we ignore */\n    biWidth = GET_4B(bmpinfoheader, 4);\n    biHeight = GET_4B(bmpinfoheader, 8);\n    biPlanes = GET_2B(bmpinfoheader, 12);\n    source->bits_per_pixel = (int) GET_2B(bmpinfoheader, 14);\n    biCompression = GET_4B(bmpinfoheader, 16);\n    biXPelsPerMeter = GET_4B(bmpinfoheader, 24);\n    biYPelsPerMeter = GET_4B(bmpinfoheader, 28);\n    biClrUsed = GET_4B(bmpinfoheader, 32);\n    /* biSizeImage, biClrImportant fields are ignored */\n\n    switch (source->bits_per_pixel) {\n    case 8:\t\t\t/* colormapped image */\n      mapentrysize = 4;\t\t/* Windows uses RGBQUAD colormap */\n      TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);\n      break;\n    case 24:\t\t\t/* RGB image */\n    case 32:\t\t\t/* RGB image + Alpha channel */\n      TRACEMS3(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight,\n\t       source->bits_per_pixel);\n      break;\n    default:\n      ERREXIT(cinfo, JERR_BMP_BADDEPTH);\n    }\n    if (biCompression != 0)\n      ERREXIT(cinfo, JERR_BMP_COMPRESSED);\n\n    if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {\n      /* Set JFIF density parameters from the BMP data */\n      cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */\n      cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);\n      cinfo->density_unit = 2;\t/* dots/cm */\n    }\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BMP_BADHEADER);\n    return;\t/* avoid compiler warnings for uninitialized variables */\n  }\n\n  if (biPlanes != 1)\n    ERREXIT(cinfo, JERR_BMP_BADPLANES);\n  /* Sanity check for buffer allocation below */\n  if (biWidth <= 0 || biHeight <= 0 || (biWidth >> 24) || (biHeight >> 24))\n    ERREXIT(cinfo, JERR_BMP_OUTOFRANGE);\n\n  /* Compute distance to bitmap data --- will adjust for colormap below */\n  bPad = bfOffBits - (headerSize + 14);\n\n  /* Read the colormap, if any */\n  if (mapentrysize > 0) {\n    if (biClrUsed <= 0)\n      biClrUsed = 256;\t\t/* assume it's 256 */\n    else if (biClrUsed > 256)\n      ERREXIT(cinfo, JERR_BMP_BADCMAP);\n    /* Allocate space to store the colormap */\n    source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n      JPOOL_IMAGE, (JDIMENSION) biClrUsed, (JDIMENSION) 3);\n    source->cmap_length = (int) biClrUsed;\n    /* and read it from the file */\n    read_colormap(source, (int) biClrUsed, mapentrysize);\n    /* account for size of colormap */\n    bPad -= biClrUsed * mapentrysize;\n  }\n\n  /* Skip any remaining pad bytes */\n  if (bPad < 0)\t\t\t/* incorrect bfOffBits value? */\n    ERREXIT(cinfo, JERR_BMP_BADHEADER);\n  while (--bPad >= 0) {\n    (void) read_byte(source);\n  }\n\n  /* Compute row width in file, including padding to 4-byte boundary */\n  if (source->bits_per_pixel == 24)\n    row_width = (JDIMENSION) (biWidth * 3);\n  else if (source->bits_per_pixel == 32)\n    row_width = (JDIMENSION) (biWidth * 4);\n  else\n    row_width = (JDIMENSION) biWidth;\n  while ((row_width & 3) != 0) row_width++;\n  source->row_width = row_width;\n\n  /* Allocate space for inversion array, prepare for preload pass */\n  source->whole_image = (*cinfo->mem->request_virt_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n     row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);\n  source->pub.get_pixel_rows = preload_image;\n  if (cinfo->progress != NULL) {\n    cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n    progress->total_extra_passes++; /* count file input as separate pass */\n  }\n\n  /* Allocate one-row buffer for returned data */\n  source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);\n  source->pub.buffer_height = 1;\n\n  cinfo->in_color_space = JCS_RGB;\n  cinfo->input_components = 3;\n  cinfo->data_precision = 8;\n  cinfo->image_width = (JDIMENSION) biWidth;\n  cinfo->image_height = (JDIMENSION) biHeight;\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  /* no work */\n}\n\n\n/*\n * The module selection routine for BMP format input.\n */\n\nGLOBAL(cjpeg_source_ptr)\njinit_read_bmp (j_compress_ptr cinfo)\n{\n  bmp_source_ptr source;\n\n  /* Create module interface object */\n  source = (bmp_source_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_source_struct));\n  source->cinfo = cinfo;\t/* make back link for subroutines */\n  /* Fill in method ptrs, except get_pixel_rows which start_input sets */\n  source->pub.start_input = start_input_bmp;\n  source->pub.finish_input = finish_input_bmp;\n\n  return &source->pub;\n}\n\n#endif /* BMP_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/rdcolmap.c",
    "content": "/*\n * rdcolmap.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file implements djpeg's \"-map file\" switch.  It reads a source image\n * and constructs a colormap to be supplied to the JPEG decompressor.\n *\n * Currently, these file formats are supported for the map file:\n *   GIF: the contents of the GIF's global colormap are used.\n *   PPM (either text or raw flavor): the entire file is read and\n *      each unique pixel value is entered in the map.\n * Note that reading a large PPM file will be horrendously slow.\n * Typically, a PPM-format map file should contain just one pixel\n * of each desired color.  Such a file can be extracted from an\n * ordinary image PPM file with ppmtomap(1).\n *\n * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not\n * currently implemented.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef QUANT_2PASS_SUPPORTED\t/* otherwise can't quantize to supplied map */\n\n/* Portions of this code are based on the PBMPLUS library, which is:\n**\n** Copyright (C) 1988 by Jef Poskanzer.\n**\n** Permission to use, copy, modify, and distribute this software and its\n** documentation for any purpose and without fee is hereby granted, provided\n** that the above copyright notice appear in all copies and that both that\n** copyright notice and this permission notice appear in supporting\n** documentation.  This software is provided \"as is\" without express or\n** implied warranty.\n*/\n\n\n/*\n * Add a (potentially) new color to the color map.\n */\n\nLOCAL(void)\nadd_map_entry (j_decompress_ptr cinfo, int R, int G, int B)\n{\n  JSAMPROW colormap0 = cinfo->colormap[0];\n  JSAMPROW colormap1 = cinfo->colormap[1];\n  JSAMPROW colormap2 = cinfo->colormap[2];\n  int ncolors = cinfo->actual_number_of_colors;\n  int index;\n\n  /* Check for duplicate color. */\n  for (index = 0; index < ncolors; index++) {\n    if (GETJSAMPLE(colormap0[index]) == R &&\n\tGETJSAMPLE(colormap1[index]) == G &&\n\tGETJSAMPLE(colormap2[index]) == B)\n      return;\t\t\t/* color is already in map */\n  }\n\n  /* Check for map overflow. */\n  if (ncolors >= (MAXJSAMPLE+1))\n    ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));\n\n  /* OK, add color to map. */\n  colormap0[ncolors] = (JSAMPLE) R;\n  colormap1[ncolors] = (JSAMPLE) G;\n  colormap2[ncolors] = (JSAMPLE) B;\n  cinfo->actual_number_of_colors++;\n}\n\n\n/*\n * Extract color map from a GIF file.\n */\n\nLOCAL(void)\nread_gif_map (j_decompress_ptr cinfo, FILE * infile)\n{\n  int header[13];\n  int i, colormaplen;\n  int R, G, B;\n\n  /* Initial 'G' has already been read by read_color_map */\n  /* Read the rest of the GIF header and logical screen descriptor */\n  for (i = 1; i < 13; i++) {\n    if ((header[i] = getc(infile)) == EOF)\n      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n  }\n\n  /* Verify GIF Header */\n  if (header[1] != 'I' || header[2] != 'F')\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n\n  /* There must be a global color map. */\n  if ((header[10] & 0x80) == 0)\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n\n  /* OK, fetch it. */\n  colormaplen = 2 << (header[10] & 0x07);\n\n  for (i = 0; i < colormaplen; i++) {\n    R = getc(infile);\n    G = getc(infile);\n    B = getc(infile);\n    if (R == EOF || G == EOF || B == EOF)\n      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n    add_map_entry(cinfo,\n\t\t  R << (BITS_IN_JSAMPLE-8),\n\t\t  G << (BITS_IN_JSAMPLE-8),\n\t\t  B << (BITS_IN_JSAMPLE-8));\n  }\n}\n\n\n/* Support routines for reading PPM */\n\n\nLOCAL(int)\npbm_getc (FILE * infile)\n/* Read next char, skipping over any comments */\n/* A comment/newline sequence is returned as a newline */\n{\n  register int ch;\n  \n  ch = getc(infile);\n  if (ch == '#') {\n    do {\n      ch = getc(infile);\n    } while (ch != '\\n' && ch != EOF);\n  }\n  return ch;\n}\n\n\nLOCAL(unsigned int)\nread_pbm_integer (j_decompress_ptr cinfo, FILE * infile)\n/* Read an unsigned decimal integer from the PPM file */\n/* Swallows one trailing character after the integer */\n/* Note that on a 16-bit-int machine, only values up to 64k can be read. */\n/* This should not be a problem in practice. */\n{\n  register int ch;\n  register unsigned int val;\n  \n  /* Skip any leading whitespace */\n  do {\n    ch = pbm_getc(infile);\n    if (ch == EOF)\n      ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n  } while (ch == ' ' || ch == '\\t' || ch == '\\n' || ch == '\\r');\n  \n  if (ch < '0' || ch > '9')\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n  \n  val = ch - '0';\n  while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {\n    val *= 10;\n    val += ch - '0';\n  }\n  return val;\n}\n\n\n/*\n * Extract color map from a PPM file.\n */\n\nLOCAL(void)\nread_ppm_map (j_decompress_ptr cinfo, FILE * infile)\n{\n  int c;\n  unsigned int w, h, maxval, row, col;\n  int R, G, B;\n\n  /* Initial 'P' has already been read by read_color_map */\n  c = getc(infile);\t\t/* save format discriminator for a sec */\n\n  /* while we fetch the remaining header info */\n  w = read_pbm_integer(cinfo, infile);\n  h = read_pbm_integer(cinfo, infile);\n  maxval = read_pbm_integer(cinfo, infile);\n\n  if (w <= 0 || h <= 0 || maxval <= 0) /* error check */\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n\n  /* For now, we don't support rescaling from an unusual maxval. */\n  if (maxval != (unsigned int) MAXJSAMPLE)\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n\n  switch (c) {\n  case '3':\t\t\t/* it's a text-format PPM file */\n    for (row = 0; row < h; row++) {\n      for (col = 0; col < w; col++) {\n\tR = read_pbm_integer(cinfo, infile);\n\tG = read_pbm_integer(cinfo, infile);\n\tB = read_pbm_integer(cinfo, infile);\n\tadd_map_entry(cinfo, R, G, B);\n      }\n    }\n    break;\n\n  case '6':\t\t\t/* it's a raw-format PPM file */\n    for (row = 0; row < h; row++) {\n      for (col = 0; col < w; col++) {\n\tR = getc(infile);\n\tG = getc(infile);\n\tB = getc(infile);\n\tif (R == EOF || G == EOF || B == EOF)\n\t  ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n\tadd_map_entry(cinfo, R, G, B);\n      }\n    }\n    break;\n\n  default:\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n    break;\n  }\n}\n\n\n/*\n * Main entry point from djpeg.c.\n *  Input: opened input file (from file name argument on command line).\n *  Output: colormap and actual_number_of_colors fields are set in cinfo.\n */\n\nGLOBAL(void)\nread_color_map (j_decompress_ptr cinfo, FILE * infile)\n{\n  /* Allocate space for a color map of maximum supported size. */\n  cinfo->colormap = (*cinfo->mem->alloc_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE,\n     (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);\n  cinfo->actual_number_of_colors = 0; /* initialize map to empty */\n\n  /* Read first byte to determine file format */\n  switch (getc(infile)) {\n  case 'G':\n    read_gif_map(cinfo, infile);\n    break;\n  case 'P':\n    read_ppm_map(cinfo, infile);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BAD_CMAP_FILE);\n    break;\n  }\n}\n\n#endif /* QUANT_2PASS_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/rdgif.c",
    "content": "/*\n * rdgif.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2019-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to read input images in GIF format.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume input from\n * an ordinary stdio stream.  They further assume that reading begins\n * at the start of the file; start_input may need work if the\n * user interface has already read some data (e.g., to determine that\n * the file is indeed GIF format).\n */\n\n/*\n * This code is loosely based on giftoppm from the PBMPLUS distribution\n * of Feb. 1991.  That file contains the following copyright notice:\n * +-------------------------------------------------------------------+\n * | Copyright 1990, David Koblas.                                     |\n * |   Permission to use, copy, modify, and distribute this software   |\n * |   and its documentation for any purpose and without fee is hereby |\n * |   granted, provided that the above copyright notice appear in all |\n * |   copies and that both that copyright notice and this permission  |\n * |   notice appear in supporting documentation.  This software is    |\n * |   provided \"as is\" without express or implied warranty.           |\n * +-------------------------------------------------------------------+\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef GIF_SUPPORTED\n\n\n/* Macros to deal with unsigned chars as efficiently as compiler allows */\n\n#ifdef HAVE_UNSIGNED_CHAR\ntypedef unsigned char U_CHAR;\n#define UCH(x)\t((int) (x))\n#else /* !HAVE_UNSIGNED_CHAR */\ntypedef char U_CHAR;\n#ifdef CHAR_IS_UNSIGNED\n#define UCH(x)\t((int) (x))\n#else\n#define UCH(x)\t((int) (x) & 0xFF)\n#endif\n#endif /* HAVE_UNSIGNED_CHAR */\n\n\n#define\tReadOK(file,buffer,len)\t(JFREAD(file,buffer,len) == ((size_t) (len)))\n\n\n#define\tMAXCOLORMAPSIZE\t256\t/* max # of colors in a GIF colormap */\n#define NUMCOLORS\t3\t/* # of colors */\n#define CM_RED\t\t0\t/* color component numbers */\n#define CM_GREEN\t1\n#define CM_BLUE\t\t2\n\n#define\tMAX_LZW_BITS\t12\t/* maximum LZW code size */\n#define LZW_TABLE_SIZE\t(1<<MAX_LZW_BITS) /* # of possible LZW symbols */\n\n/* Macros for extracting header data --- note we assume chars may be signed */\n\n#define LM_to_uint(array, offset)  ((unsigned int) UCH(array[offset]) + \\\n\t\t\t\t(((unsigned int) UCH(array[offset+1])) << 8))\n\n#define BitSet(byte, bit)\t((byte) & (bit))\n#define INTERLACE\t0x40\t/* mask for bit signifying interlaced image */\n#define COLORMAPFLAG\t0x80\t/* mask for bit signifying colormap presence */\n\n\n/*\n * LZW decompression tables look like this:\n *   symbol_head[K] = prefix symbol of any LZW symbol K (0..LZW_TABLE_SIZE-1)\n *   symbol_tail[K] = suffix byte   of any LZW symbol K (0..LZW_TABLE_SIZE-1)\n * Note that entries 0..end_code of the above tables are not used,\n * since those symbols represent raw bytes or special codes.\n *\n * The stack represents the not-yet-used expansion of the last LZW symbol.\n * In the worst case, a symbol could expand to as many bytes as there are\n * LZW symbols, so we allocate LZW_TABLE_SIZE bytes for the stack.\n * (This is conservative since that number includes the raw-byte symbols.)\n *\n * The tables are allocated from FAR heap space since they would use up\n * rather a lot of the near data space in a PC.\n */\n\n\n/* Private version of data source object */\n\ntypedef struct {\n  struct cjpeg_source_struct pub; /* public fields */\n\n  j_compress_ptr cinfo;\t\t/* back link saves passing separate parm */\n\n  JSAMPARRAY colormap;\t\t/* GIF colormap (converted to my format) */\n\n  /* State for GetCode and LZWReadByte */\n  U_CHAR code_buf[256+4];\t/* current input data block */\n  int last_byte;\t\t/* # of bytes in code_buf */\n  int last_bit;\t\t\t/* # of bits in code_buf */\n  int cur_bit;\t\t\t/* next bit index to read */\n  boolean first_time;\t\t/* flags first call to GetCode */\n  boolean out_of_blocks;\t/* TRUE if hit terminator data block */\n\n  int input_code_size;\t\t/* codesize given in GIF file */\n  int clear_code, end_code;\t/* values for Clear and End codes */\n\n  int code_size;\t\t/* current actual code size */\n  int limit_code;\t\t/* 2^code_size */\n  int max_code;\t\t\t/* first unused code value */\n\n  /* Private state for LZWReadByte */\n  int oldcode;\t\t\t/* previous LZW symbol */\n  int firstcode;\t\t/* first byte of oldcode's expansion */\n\n  /* LZW symbol table and expansion stack */\n  UINT16 FAR *symbol_head;\t/* => table of prefix symbols */\n  UINT8  FAR *symbol_tail;\t/* => table of suffix bytes */\n  UINT8  FAR *symbol_stack;\t/* => stack for symbol expansions */\n  UINT8  FAR *sp;\t\t/* stack pointer */\n\n  /* State for interlaced image processing */\n  boolean is_interlaced;\t/* TRUE if have interlaced image */\n  jvirt_sarray_ptr interlaced_image; /* full image in interlaced order */\n  JDIMENSION cur_row_number;\t/* need to know actual row number */\n  JDIMENSION pass2_offset;\t/* # of pixel rows in pass 1 */\n  JDIMENSION pass3_offset;\t/* # of pixel rows in passes 1&2 */\n  JDIMENSION pass4_offset;\t/* # of pixel rows in passes 1,2,3 */\n} gif_source_struct;\n\ntypedef gif_source_struct * gif_source_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(JDIMENSION) get_pixel_rows\n\tJPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));\nMETHODDEF(JDIMENSION) load_interlaced_image\n\tJPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));\nMETHODDEF(JDIMENSION) get_interlaced_row\n\tJPP((j_compress_ptr cinfo, cjpeg_source_ptr sinfo));\n\n\nLOCAL(int)\nReadByte (gif_source_ptr sinfo)\n/* Read next byte from GIF file */\n{\n  register FILE *infile = sinfo->pub.input_file;\n  register int c;\n\n  if ((c = getc(infile)) == EOF)\n    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);\n  return c;\n}\n\n\nLOCAL(int)\nGetDataBlock (gif_source_ptr sinfo, U_CHAR *buf)\n/* Read a GIF data block, which has a leading count byte */\n/* A zero-length block marks the end of a data block sequence */\n{\n  int count;\n\n  count = ReadByte(sinfo);\n  if (count > 0) {\n    if (! ReadOK(sinfo->pub.input_file, buf, count))\n      ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);\n  }\n  return count;\n}\n\n\nLOCAL(void)\nSkipDataBlocks (gif_source_ptr sinfo)\n/* Skip a series of data blocks, until a block terminator is found */\n{\n  U_CHAR buf[256];\n\n  while (GetDataBlock(sinfo, buf) > 0)\n    /* skip */;\n}\n\n\nLOCAL(void)\nReInitLZW (gif_source_ptr sinfo)\n/* (Re)initialize LZW state; shared code for startup and Clear processing */\n{\n  sinfo->code_size = sinfo->input_code_size + 1;\n  sinfo->limit_code = sinfo->clear_code << 1;\t/* 2^code_size */\n  sinfo->max_code = sinfo->clear_code + 2;\t/* first unused code value */\n  sinfo->sp = sinfo->symbol_stack;\t\t/* init stack to empty */\n}\n\n\nLOCAL(void)\nInitLZWCode (gif_source_ptr sinfo)\n/* Initialize for a series of LZWReadByte (and hence GetCode) calls */\n{\n  /* GetCode initialization */\n  sinfo->last_byte = 2;\t\t/* make safe to \"recopy last two bytes\" */\n  sinfo->code_buf[0] = 0;\n  sinfo->code_buf[1] = 0;\n  sinfo->last_bit = 0;\t\t/* nothing in the buffer */\n  sinfo->cur_bit = 0;\t\t/* force buffer load on first call */\n  sinfo->first_time = TRUE;\n  sinfo->out_of_blocks = FALSE;\n\n  /* LZWReadByte initialization: */\n  /* compute special code values (note that these do not change later) */\n  sinfo->clear_code = 1 << sinfo->input_code_size;\n  sinfo->end_code = sinfo->clear_code + 1;\n  ReInitLZW(sinfo);\n}\n\n\nLOCAL(int)\nGetCode (gif_source_ptr sinfo)\n/* Fetch the next code_size bits from the GIF data */\n/* We assume code_size is less than 16 */\n{\n  register INT32 accum;\n  int offs, count;\n\n  while (sinfo->cur_bit + sinfo->code_size > sinfo->last_bit) {\n    /* Time to reload the buffer */\n    /* First time, share code with Clear case */\n    if (sinfo->first_time) {\n      sinfo->first_time = FALSE;\n      return sinfo->clear_code;\n    }\n    if (sinfo->out_of_blocks) {\n      WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);\n      return sinfo->end_code;\t/* fake something useful */\n    }\n    /* preserve last two bytes of what we have -- assume code_size <= 16 */\n    sinfo->code_buf[0] = sinfo->code_buf[sinfo->last_byte-2];\n    sinfo->code_buf[1] = sinfo->code_buf[sinfo->last_byte-1];\n    /* Load more bytes; set flag if we reach the terminator block */\n    if ((count = GetDataBlock(sinfo, &sinfo->code_buf[2])) == 0) {\n      sinfo->out_of_blocks = TRUE;\n      WARNMS(sinfo->cinfo, JWRN_GIF_NOMOREDATA);\n      return sinfo->end_code;\t/* fake something useful */\n    }\n    /* Reset counters */\n    sinfo->cur_bit = (sinfo->cur_bit - sinfo->last_bit) + 16;\n    sinfo->last_byte = 2 + count;\n    sinfo->last_bit = sinfo->last_byte * 8;\n  }\n\n  /* Form up next 24 bits in accum */\n  offs = sinfo->cur_bit >> 3;\t/* byte containing cur_bit */\n  accum = (INT32) UCH(sinfo->code_buf[offs+2]);\n  accum <<= 8;\n  accum |= (INT32) UCH(sinfo->code_buf[offs+1]);\n  accum <<= 8;\n  accum |= (INT32) UCH(sinfo->code_buf[offs]);\n\n  /* Right-align cur_bit in accum, then mask off desired number of bits */\n  accum >>= (sinfo->cur_bit & 7);\n  sinfo->cur_bit += sinfo->code_size;\n  return ((int) accum) & ((1 << sinfo->code_size) - 1);\n}\n\n\nLOCAL(int)\nLZWReadByte (gif_source_ptr sinfo)\n/* Read an LZW-compressed byte */\n{\n  register int code;\t\t/* current working code */\n  int incode;\t\t\t/* saves actual input code */\n\n  /* If any codes are stacked from a previously read symbol, return them */\n  if (sinfo->sp > sinfo->symbol_stack)\n    return (int) *(-- sinfo->sp);\n\n  /* Time to read a new symbol */\n  code = GetCode(sinfo);\n\n  if (code == sinfo->clear_code) {\n    /* Reinit state, swallow any extra Clear codes, and */\n    /* return next code, which is expected to be a raw byte. */\n    ReInitLZW(sinfo);\n    do {\n      code = GetCode(sinfo);\n    } while (code == sinfo->clear_code);\n    if (code > sinfo->clear_code) { /* make sure it is a raw byte */\n      WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);\n      code = 0;\t\t\t/* use something valid */\n    }\n    /* make firstcode, oldcode valid! */\n    sinfo->firstcode = sinfo->oldcode = code;\n    return code;\n  }\n\n  if (code == sinfo->end_code) {\n    /* Skip the rest of the image, unless GetCode already read terminator */\n    if (! sinfo->out_of_blocks) {\n      SkipDataBlocks(sinfo);\n      sinfo->out_of_blocks = TRUE;\n    }\n    /* Complain that there's not enough data */\n    WARNMS(sinfo->cinfo, JWRN_GIF_ENDCODE);\n    /* Pad data with 0's */\n    return 0;\t\t\t/* fake something usable */\n  }\n\n  /* Got normal raw byte or LZW symbol */\n  incode = code;\t\t/* save for a moment */\n  \n  if (code >= sinfo->max_code) { /* special case for not-yet-defined symbol */\n    /* code == max_code is OK; anything bigger is bad data */\n    if (code > sinfo->max_code) {\n      WARNMS(sinfo->cinfo, JWRN_GIF_BADDATA);\n      incode = 0;\t\t/* prevent creation of loops in symbol table */\n    }\n    /* this symbol will be defined as oldcode/firstcode */\n    *(sinfo->sp++) = (UINT8) sinfo->firstcode;\n    code = sinfo->oldcode;\n  }\n\n  /* If it's a symbol, expand it into the stack */\n  while (code >= sinfo->clear_code) {\n    *(sinfo->sp++) = sinfo->symbol_tail[code]; /* tail is a byte value */\n    code = sinfo->symbol_head[code]; /* head is another LZW symbol */\n  }\n  /* At this point code just represents a raw byte */\n  sinfo->firstcode = code;\t/* save for possible future use */\n\n  /* If there's room in table... */\n  if ((code = sinfo->max_code) < LZW_TABLE_SIZE) {\n    /* Define a new symbol = prev sym + head of this sym's expansion */\n    sinfo->symbol_head[code] = (UINT16) sinfo->oldcode;\n    sinfo->symbol_tail[code] = (UINT8) sinfo->firstcode;\n    sinfo->max_code++;\n    /* Is it time to increase code_size? */\n    if (sinfo->max_code >= sinfo->limit_code &&\n\tsinfo->code_size < MAX_LZW_BITS) {\n      sinfo->code_size++;\n      sinfo->limit_code <<= 1;\t/* keep equal to 2^code_size */\n    }\n  }\n  \n  sinfo->oldcode = incode;\t/* save last input symbol for future use */\n  return sinfo->firstcode;\t/* return first byte of symbol's expansion */\n}\n\n\nLOCAL(void)\nReadColorMap (gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap)\n/* Read a GIF colormap */\n{\n  int i;\n\n  for (i = 0; i < cmaplen; i++) {\n#if BITS_IN_JSAMPLE == 8\n#define UPSCALE(x)  (x)\n#else\n#define UPSCALE(x)  ((x) << (BITS_IN_JSAMPLE-8))\n#endif\n    cmap[CM_RED  ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));\n    cmap[CM_GREEN][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));\n    cmap[CM_BLUE ][i] = (JSAMPLE) UPSCALE(ReadByte(sinfo));\n  }\n}\n\n\nLOCAL(void)\nDoExtension (gif_source_ptr sinfo)\n/* Process an extension block */\n/* Currently we ignore 'em all */\n{\n  int extlabel;\n\n  /* Read extension label byte */\n  extlabel = ReadByte(sinfo);\n  TRACEMS1(sinfo->cinfo, 1, JTRC_GIF_EXTENSION, extlabel);\n  /* Skip the data block(s) associated with the extension */\n  SkipDataBlocks(sinfo);\n}\n\n\n/*\n * Read the file header; return image size and component count.\n */\n\nMETHODDEF(void)\nstart_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  gif_source_ptr source = (gif_source_ptr) sinfo;\n  U_CHAR hdrbuf[10];\t\t/* workspace for reading control blocks */\n  unsigned int width, height;\t/* image dimensions */\n  int colormaplen, aspectRatio;\n  int c;\n\n  /* Read and verify GIF Header */\n  if (! ReadOK(source->pub.input_file, hdrbuf, 6))\n    ERREXIT(cinfo, JERR_GIF_NOT);\n  if (hdrbuf[0] != 'G' || hdrbuf[1] != 'I' || hdrbuf[2] != 'F')\n    ERREXIT(cinfo, JERR_GIF_NOT);\n  /* Check for expected version numbers.\n   * If unknown version, give warning and try to process anyway;\n   * this is per recommendation in GIF89a standard.\n   */\n  if ((hdrbuf[3] != '8' || hdrbuf[4] != '7' || hdrbuf[5] != 'a') &&\n      (hdrbuf[3] != '8' || hdrbuf[4] != '9' || hdrbuf[5] != 'a'))\n    TRACEMS3(cinfo, 1, JTRC_GIF_BADVERSION, hdrbuf[3], hdrbuf[4], hdrbuf[5]);\n\n  /* Read and decipher Logical Screen Descriptor */\n  if (! ReadOK(source->pub.input_file, hdrbuf, 7))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  width = LM_to_uint(hdrbuf, 0);\n  height = LM_to_uint(hdrbuf, 2);\n  /* we ignore the color resolution, sort flag, and background color index */\n  aspectRatio = UCH(hdrbuf[6]);\n  if (aspectRatio != 0 && aspectRatio != 49)\n    TRACEMS(cinfo, 1, JTRC_GIF_NONSQUARE);\n\n  /* Allocate space to store the colormap */\n  source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, (JDIMENSION) MAXCOLORMAPSIZE, (JDIMENSION) NUMCOLORS);\n  colormaplen = 0; \t\t/* indicate initialization */\n\n  /* Read global colormap if header indicates it is present */\n  if (BitSet(hdrbuf[4], COLORMAPFLAG)) {\n    colormaplen = 2 << (hdrbuf[4] & 0x07);\n    ReadColorMap(source, colormaplen, source->colormap);\n  }\n\n  /* Scan until we reach start of desired image.\n   * We don't currently support skipping images, but could add it easily.\n   */\n  for (;;) {\n    c = ReadByte(source);\n\n    if (c == ';')\t\t/* GIF terminator?? */\n      ERREXIT(cinfo, JERR_GIF_IMAGENOTFOUND);\n\n    if (c == '!') {\t\t/* Extension */\n      DoExtension(source);\n      continue;\n    }\n    \n    if (c != ',') {\t\t/* Not an image separator? */\n      WARNMS1(cinfo, JWRN_GIF_CHAR, c);\n      continue;\n    }\n\n    /* Read and decipher Local Image Descriptor */\n    if (! ReadOK(source->pub.input_file, hdrbuf, 9))\n      ERREXIT(cinfo, JERR_INPUT_EOF);\n    /* we ignore top/left position info, also sort flag */\n    width = LM_to_uint(hdrbuf, 4);\n    height = LM_to_uint(hdrbuf, 6);\n    if (width <= 0 || height <= 0)\n      ERREXIT(cinfo, JERR_GIF_OUTOFRANGE);\n    source->is_interlaced = (BitSet(hdrbuf[8], INTERLACE) != 0);\n\n    /* Read local colormap if header indicates it is present */\n    /* Note: if we wanted to support skipping images, */\n    /* we'd need to skip rather than read colormap for ignored images */\n    if (BitSet(hdrbuf[8], COLORMAPFLAG)) {\n      colormaplen = 2 << (hdrbuf[8] & 0x07);\n      ReadColorMap(source, colormaplen, source->colormap);\n    }\n\n    source->input_code_size = ReadByte(source); /* get min-code-size byte */\n    if (source->input_code_size < 2 || source->input_code_size > 8)\n      ERREXIT1(cinfo, JERR_GIF_CODESIZE, source->input_code_size);\n\n    /* Reached desired image, so break out of loop */\n    /* If we wanted to skip this image, */\n    /* we'd call SkipDataBlocks and then continue the loop */\n    break;\n  }\n\n  /* Prepare to read selected image: first initialize LZW decompressor */\n  source->symbol_head = (UINT16 FAR *) (*cinfo->mem->alloc_large)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT16));\n  source->symbol_tail = (UINT8 FAR *) (*cinfo->mem->alloc_large)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8));\n  source->symbol_stack = (UINT8 FAR *) (*cinfo->mem->alloc_large)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, LZW_TABLE_SIZE * SIZEOF(UINT8));\n  InitLZWCode(source);\n\n  /*\n   * If image is interlaced, we read it into a full-size sample array,\n   * decompressing as we go; then get_interlaced_row selects rows from the\n   * sample array in the proper order.\n   */\n  if (source->is_interlaced) {\n    /* We request the virtual array now, but can't access it until virtual\n     * arrays have been allocated.  Hence, the actual work of reading the\n     * image is postponed until the first call to get_pixel_rows.\n     */\n    source->interlaced_image = (*cinfo->mem->request_virt_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n       (JDIMENSION) width, (JDIMENSION) height, (JDIMENSION) 1);\n    if (cinfo->progress != NULL) {\n      cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n      progress->total_extra_passes++; /* count file input as separate pass */\n    }\n    source->pub.get_pixel_rows = load_interlaced_image;\n  } else {\n    source->pub.get_pixel_rows = get_pixel_rows;\n  }\n\n  /* Create compressor input buffer. */\n  source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, (JDIMENSION) width * NUMCOLORS, (JDIMENSION) 1);\n  source->pub.buffer_height = 1;\n\n  /* Pad colormap for safety. */\n  for (c = colormaplen; c < source->clear_code; c++) {\n    source->colormap[CM_RED  ][c] =\n    source->colormap[CM_GREEN][c] =\n    source->colormap[CM_BLUE ][c] = CENTERJSAMPLE;\n  }\n\n  /* Return info about the image. */\n  cinfo->in_color_space = JCS_RGB;\n  cinfo->input_components = NUMCOLORS;\n  cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */\n  cinfo->image_width = width;\n  cinfo->image_height = height;\n\n  TRACEMS3(cinfo, 1, JTRC_GIF, width, height, colormaplen);\n}\n\n\n/*\n * Read one row of pixels.\n * This version is used for noninterlaced GIF images:\n * we read directly from the GIF file.\n */\n\nMETHODDEF(JDIMENSION)\nget_pixel_rows (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  gif_source_ptr source = (gif_source_ptr) sinfo;\n  register int c;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n  register JSAMPARRAY colormap = source->colormap;\n  \n  ptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    c = LZWReadByte(source);\n    *ptr++ = colormap[CM_RED  ][c];\n    *ptr++ = colormap[CM_GREEN][c];\n    *ptr++ = colormap[CM_BLUE ][c];\n  }\n  return 1;\n}\n\n\n/*\n * Read one row of pixels.\n * This version is used for the first call on get_pixel_rows when\n * reading an interlaced GIF file: we read the whole image into memory.\n */\n\nMETHODDEF(JDIMENSION)\nload_interlaced_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  gif_source_ptr source = (gif_source_ptr) sinfo;\n  register JSAMPROW sptr;\n  register JDIMENSION col;\n  JDIMENSION row;\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n\n  /* Read the interlaced image into the virtual array we've created. */\n  for (row = 0; row < cinfo->image_height; row++) {\n    if (progress != NULL) {\n      progress->pub.pass_counter = (long) row;\n      progress->pub.pass_limit = (long) cinfo->image_height;\n      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n    }\n    sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n      source->interlaced_image, row, (JDIMENSION) 1, TRUE);\n    for (col = cinfo->image_width; col > 0; col--) {\n      *sptr++ = (JSAMPLE) LZWReadByte(source);\n    }\n  }\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n\n  /* Replace method pointer so subsequent calls don't come here. */\n  source->pub.get_pixel_rows = get_interlaced_row;\n  /* Initialize for get_interlaced_row, and perform first call on it. */\n  source->cur_row_number = 0;\n  source->pass2_offset = (cinfo->image_height + 7) / 8;\n  source->pass3_offset = source->pass2_offset + (cinfo->image_height + 3) / 8;\n  source->pass4_offset = source->pass3_offset + (cinfo->image_height + 1) / 4;\n\n  return get_interlaced_row(cinfo, sinfo);\n}\n\n\n/*\n * Read one row of pixels.\n * This version is used for interlaced GIF images:\n * we read from the virtual array.\n */\n\nMETHODDEF(JDIMENSION)\nget_interlaced_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  gif_source_ptr source = (gif_source_ptr) sinfo;\n  register int c;\n  register JSAMPROW sptr, ptr;\n  register JDIMENSION col;\n  register JSAMPARRAY colormap = source->colormap;\n  JDIMENSION irow;\n\n  /* Figure out which row of interlaced image is needed, and access it. */\n  switch ((int) (source->cur_row_number & 7)) {\n  case 0:\t\t\t/* first-pass row */\n    irow = source->cur_row_number >> 3;\n    break;\n  case 4:\t\t\t/* second-pass row */\n    irow = (source->cur_row_number >> 3) + source->pass2_offset;\n    break;\n  case 2:\t\t\t/* third-pass row */\n  case 6:\n    irow = (source->cur_row_number >> 2) + source->pass3_offset;\n    break;\n  default:\t\t\t/* fourth-pass row */\n    irow = (source->cur_row_number >> 1) + source->pass4_offset;\n  }\n  sptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    source->interlaced_image, irow, (JDIMENSION) 1, FALSE);\n  /* Scan the row, expand colormap, and output */\n  ptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    c = GETJSAMPLE(*sptr++);\n    *ptr++ = colormap[CM_RED  ][c];\n    *ptr++ = colormap[CM_GREEN][c];\n    *ptr++ = colormap[CM_BLUE ][c];\n  }\n  source->cur_row_number++;\t/* for next time */\n  return 1;\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_input_gif (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  /* no work */\n}\n\n\n/*\n * The module selection routine for GIF format input.\n */\n\nGLOBAL(cjpeg_source_ptr)\njinit_read_gif (j_compress_ptr cinfo)\n{\n  gif_source_ptr source;\n\n  /* Create module interface object */\n  source = (gif_source_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_source_struct));\n  source->cinfo = cinfo;\t/* make back link for subroutines */\n  /* Fill in method ptrs, except get_pixel_rows which start_input sets */\n  source->pub.start_input = start_input_gif;\n  source->pub.finish_input = finish_input_gif;\n\n  return &source->pub;\n}\n\n#endif /* GIF_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/rdjpgcom.c",
    "content": "/*\n * rdjpgcom.c\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2009 by Bill Allombert, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a very simple stand-alone application that displays\n * the text in COM (comment) markers in a JFIF file.\n * This may be useful as an example of the minimum logic needed to parse\n * JPEG markers.\n */\n\n#define JPEG_CJPEG_DJPEG\t/* to get the command-line config symbols */\n#include \"jinclude.h\"\t\t/* get auto-config symbols, <stdio.h> */\n\n#ifdef HAVE_LOCALE_H\n#include <locale.h>\t\t/* Bill Allombert: use locale for isprint */\n#endif\n#include <ctype.h>\t\t/* to declare isupper(), tolower() */\n#ifdef USE_SETMODE\n#include <fcntl.h>\t\t/* to declare setmode()'s parameter macros */\n/* If you have setmode() but not <io.h>, just delete this line: */\n#include <io.h>\t\t\t/* to declare setmode() */\n#endif\n\n#ifdef USE_CCOMMAND\t\t/* command-line reader for Macintosh */\n#ifdef __MWERKS__\n#include <SIOUX.h>              /* Metrowerks needs this */\n#include <console.h>\t\t/* ... and this */\n#endif\n#ifdef THINK_C\n#include <console.h>\t\t/* Think declares it here */\n#endif\n#endif\n\n#ifdef DONT_USE_B_MODE\t\t/* define mode parameters for fopen() */\n#define READ_BINARY\t\"r\"\n#else\n#ifdef VMS\t\t\t/* VMS is very nonstandard */\n#define READ_BINARY\t\"rb\", \"ctx=stm\"\n#else\t\t\t\t/* standard ANSI-compliant case */\n#define READ_BINARY\t\"rb\"\n#endif\n#endif\n\n#ifndef EXIT_FAILURE\t\t/* define exit() codes if not provided */\n#define EXIT_FAILURE  1\n#endif\n#ifndef EXIT_SUCCESS\n#ifdef VMS\n#define EXIT_SUCCESS  1\t\t/* VMS is very nonstandard */\n#else\n#define EXIT_SUCCESS  0\n#endif\n#endif\n\n\n/*\n * These macros are used to read the input file.\n * To reuse this code in another application, you might need to change these.\n */\n\nstatic FILE * infile;\t\t/* input JPEG file */\n\n/* Return next input byte, or EOF if no more */\n#define NEXTBYTE()  getc(infile)\n\n\n/* Error exit handler */\n#define ERREXIT(msg)  (fprintf(stderr, \"%s\\n\", msg), exit(EXIT_FAILURE))\n\n\n/* Read one byte, testing for EOF */\nstatic int\nread_1_byte (void)\n{\n  int c;\n\n  c = NEXTBYTE();\n  if (c == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  return c;\n}\n\n/* Read 2 bytes, convert to unsigned int */\n/* All 2-byte quantities in JPEG markers are MSB first */\nstatic unsigned int\nread_2_bytes (void)\n{\n  int c1, c2;\n\n  c1 = NEXTBYTE();\n  if (c1 == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  c2 = NEXTBYTE();\n  if (c2 == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  return (((unsigned int) c1) << 8) + ((unsigned int) c2);\n}\n\n\n/*\n * JPEG markers consist of one or more 0xFF bytes, followed by a marker\n * code byte (which is not an FF).  Here are the marker codes of interest\n * in this program.  (See jdmarker.c for a more complete list.)\n */\n\n#define M_SOF0  0xC0\t\t/* Start Of Frame N */\n#define M_SOF1  0xC1\t\t/* N indicates which compression process */\n#define M_SOF2  0xC2\t\t/* Only SOF0-SOF2 are now in common use */\n#define M_SOF3  0xC3\n#define M_SOF5  0xC5\t\t/* NB: codes C4 and CC are NOT SOF markers */\n#define M_SOF6  0xC6\n#define M_SOF7  0xC7\n#define M_SOF9  0xC9\n#define M_SOF10 0xCA\n#define M_SOF11 0xCB\n#define M_SOF13 0xCD\n#define M_SOF14 0xCE\n#define M_SOF15 0xCF\n#define M_SOI   0xD8\t\t/* Start Of Image (beginning of datastream) */\n#define M_EOI   0xD9\t\t/* End Of Image (end of datastream) */\n#define M_SOS   0xDA\t\t/* Start Of Scan (begins compressed data) */\n#define M_APP0\t0xE0\t\t/* Application-specific marker, type N */\n#define M_APP12\t0xEC\t\t/* (we don't bother to list all 16 APPn's) */\n#define M_COM   0xFE\t\t/* COMment */\n\n\n/*\n * Find the next JPEG marker and return its marker code.\n * We expect at least one FF byte, possibly more if the compressor used FFs\n * to pad the file.\n * There could also be non-FF garbage between markers.  The treatment of such\n * garbage is unspecified; we choose to skip over it but emit a warning msg.\n * NB: this routine must not be used after seeing SOS marker, since it will\n * not deal correctly with FF/00 sequences in the compressed image data...\n */\n\nstatic int\nnext_marker (void)\n{\n  int c;\n  int discarded_bytes = 0;\n\n  /* Find 0xFF byte; count and skip any non-FFs. */\n  c = read_1_byte();\n  while (c != 0xFF) {\n    discarded_bytes++;\n    c = read_1_byte();\n  }\n  /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs\n   * are legal as pad bytes, so don't count them in discarded_bytes.\n   */\n  do {\n    c = read_1_byte();\n  } while (c == 0xFF);\n\n  if (discarded_bytes != 0) {\n    fprintf(stderr, \"Warning: garbage data found in JPEG file\\n\");\n  }\n\n  return c;\n}\n\n\n/*\n * Read the initial marker, which should be SOI.\n * For a JFIF file, the first two bytes of the file should be literally\n * 0xFF M_SOI.  To be more general, we could use next_marker, but if the\n * input file weren't actually JPEG at all, next_marker might read the whole\n * file and then return a misleading error message...\n */\n\nstatic int\nfirst_marker (void)\n{\n  int c1, c2;\n\n  c1 = NEXTBYTE();\n  c2 = NEXTBYTE();\n  if (c1 != 0xFF || c2 != M_SOI)\n    ERREXIT(\"Not a JPEG file\");\n  return c2;\n}\n\n\n/*\n * Most types of marker are followed by a variable-length parameter segment.\n * This routine skips over the parameters for any marker we don't otherwise\n * want to process.\n * Note that we MUST skip the parameter segment explicitly in order not to\n * be fooled by 0xFF bytes that might appear within the parameter segment;\n * such bytes do NOT introduce new markers.\n */\n\nstatic void\nskip_variable (void)\n/* Skip over an unknown or uninteresting variable-length marker */\n{\n  unsigned int length;\n\n  /* Get the marker parameter length count */\n  length = read_2_bytes();\n  /* Length includes itself, so must be at least 2 */\n  if (length < 2)\n    ERREXIT(\"Erroneous JPEG marker length\");\n  length -= 2;\n  /* Skip over the remaining bytes */\n  while (length > 0) {\n    (void) read_1_byte();\n    length--;\n  }\n}\n\n\n/*\n * Process a COM marker.\n * We want to print out the marker contents as legible text;\n * we must guard against non-text junk and varying newline representations.\n */\n\nstatic void\nprocess_COM (int raw)\n{\n  unsigned int length;\n  int ch;\n  int lastch = 0;\n\n  /* Bill Allombert: set locale properly for isprint */\n#ifdef HAVE_LOCALE_H\n  setlocale(LC_CTYPE, \"\");\n#endif\n\n  /* Get the marker parameter length count */\n  length = read_2_bytes();\n  /* Length includes itself, so must be at least 2 */\n  if (length < 2)\n    ERREXIT(\"Erroneous JPEG marker length\");\n  length -= 2;\n\n  while (length > 0) {\n    ch = read_1_byte();\n    if (raw) {\n      putc(ch, stdout);\n    /* Emit the character in a readable form.\n     * Nonprintables are converted to \\nnn form,\n     * while \\ is converted to \\\\.\n     * Newlines in CR, CR/LF, or LF form will be printed as one newline.\n     */\n    } else if (ch == '\\r') {\n      printf(\"\\n\");\n    } else if (ch == '\\n') {\n      if (lastch != '\\r')\n\tprintf(\"\\n\");\n    } else if (ch == '\\\\') {\n      printf(\"\\\\\\\\\");\n    } else if (isprint(ch)) {\n      putc(ch, stdout);\n    } else {\n      printf(\"\\\\%03o\", ch);\n    }\n    lastch = ch;\n    length--;\n  }\n  printf(\"\\n\");\n\n  /* Bill Allombert: revert to C locale */\n#ifdef HAVE_LOCALE_H\n  setlocale(LC_CTYPE, \"C\");\n#endif\n}\n\n\n/*\n * Process a SOFn marker.\n * This code is only needed if you want to know the image dimensions...\n */\n\nstatic void\nprocess_SOFn (int marker)\n{\n  unsigned int length;\n  unsigned int image_height, image_width;\n  int data_precision, num_components;\n  const char * process;\n  int ci;\n\n  length = read_2_bytes();\t/* usual parameter length count */\n\n  data_precision = read_1_byte();\n  image_height = read_2_bytes();\n  image_width = read_2_bytes();\n  num_components = read_1_byte();\n\n  switch (marker) {\n  case M_SOF0:\tprocess = \"Baseline\";  break;\n  case M_SOF1:\tprocess = \"Extended sequential\";  break;\n  case M_SOF2:\tprocess = \"Progressive\";  break;\n  case M_SOF3:\tprocess = \"Lossless\";  break;\n  case M_SOF5:\tprocess = \"Differential sequential\";  break;\n  case M_SOF6:\tprocess = \"Differential progressive\";  break;\n  case M_SOF7:\tprocess = \"Differential lossless\";  break;\n  case M_SOF9:\tprocess = \"Extended sequential, arithmetic coding\";  break;\n  case M_SOF10:\tprocess = \"Progressive, arithmetic coding\";  break;\n  case M_SOF11:\tprocess = \"Lossless, arithmetic coding\";  break;\n  case M_SOF13:\tprocess = \"Differential sequential, arithmetic coding\";  break;\n  case M_SOF14:\tprocess = \"Differential progressive, arithmetic coding\"; break;\n  case M_SOF15:\tprocess = \"Differential lossless, arithmetic coding\";  break;\n  default:\tprocess = \"Unknown\";  break;\n  }\n\n  printf(\"JPEG image is %uw * %uh, %d color components, %d bits per sample\\n\",\n\t image_width, image_height, num_components, data_precision);\n  printf(\"JPEG process: %s\\n\", process);\n\n  if (length != (unsigned int) (8 + num_components * 3))\n    ERREXIT(\"Bogus SOF marker length\");\n\n  for (ci = 0; ci < num_components; ci++) {\n    (void) read_1_byte();\t/* Component ID code */\n    (void) read_1_byte();\t/* H, V sampling factors */\n    (void) read_1_byte();\t/* Quantization table number */\n  }\n}\n\n\n/*\n * Parse the marker stream until SOS or EOI is seen;\n * display any COM markers.\n * While the companion program wrjpgcom will always insert COM markers before\n * SOFn, other implementations might not, so we scan to SOS before stopping.\n * If we were only interested in the image dimensions, we would stop at SOFn.\n * (Conversely, if we only cared about COM markers, there would be no need\n * for special code to handle SOFn; we could treat it like other markers.)\n */\n\nstatic int\nscan_JPEG_header (int verbose, int raw)\n{\n  int marker;\n\n  /* Expect SOI at start of file */\n  if (first_marker() != M_SOI)\n    ERREXIT(\"Expected SOI marker first\");\n\n  /* Scan miscellaneous markers until we reach SOS. */\n  for (;;) {\n    marker = next_marker();\n    switch (marker) {\n      /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,\n       * treated as SOFn.  C4 in particular is actually DHT.\n       */\n    case M_SOF0:\t\t/* Baseline */\n    case M_SOF1:\t\t/* Extended sequential, Huffman */\n    case M_SOF2:\t\t/* Progressive, Huffman */\n    case M_SOF3:\t\t/* Lossless, Huffman */\n    case M_SOF5:\t\t/* Differential sequential, Huffman */\n    case M_SOF6:\t\t/* Differential progressive, Huffman */\n    case M_SOF7:\t\t/* Differential lossless, Huffman */\n    case M_SOF9:\t\t/* Extended sequential, arithmetic */\n    case M_SOF10:\t\t/* Progressive, arithmetic */\n    case M_SOF11:\t\t/* Lossless, arithmetic */\n    case M_SOF13:\t\t/* Differential sequential, arithmetic */\n    case M_SOF14:\t\t/* Differential progressive, arithmetic */\n    case M_SOF15:\t\t/* Differential lossless, arithmetic */\n      if (verbose)\n\tprocess_SOFn(marker);\n      else\n\tskip_variable();\n      break;\n\n    case M_SOS:\t\t\t/* stop before hitting compressed data */\n      return marker;\n\n    case M_EOI:\t\t\t/* in case it's a tables-only JPEG stream */\n      return marker;\n\n    case M_COM:\n      process_COM(raw);\n      break;\n\n    case M_APP12:\n      /* Some digital camera makers put useful textual information into\n       * APP12 markers, so we print those out too when in -verbose mode.\n       */\n      if (verbose) {\n\tprintf(\"APP12 contains:\\n\");\n\tprocess_COM(raw);\n      } else\n\tskip_variable();\n      break;\n\n    default:\t\t\t/* Anything else just gets skipped */\n      skip_variable();\t\t/* we assume it has a parameter count... */\n      break;\n    }\n  } /* end loop */\n}\n\n\n/* Command line parsing code */\n\nstatic const char * progname;\t/* program name for error messages */\n\n\nstatic void\nusage (void)\n/* complain about bad command line */\n{\n  fprintf(stderr, \"rdjpgcom displays any textual comments in a JPEG file.\\n\");\n\n  fprintf(stderr, \"Usage: %s [switches] [inputfile]\\n\", progname);\n\n  fprintf(stderr, \"Switches (names may be abbreviated):\\n\");\n  fprintf(stderr, \"  -raw        Display non-printable characters in comments (unsafe)\\n\");\n  fprintf(stderr, \"  -verbose    Also display dimensions of JPEG image\\n\");\n\n  exit(EXIT_FAILURE);\n}\n\n\nstatic int\nkeymatch (char * arg, const char * keyword, int minchars)\n/* Case-insensitive matching of (possibly abbreviated) keyword switches. */\n/* keyword is the constant keyword (must be lower case already), */\n/* minchars is length of minimum legal abbreviation. */\n{\n  register int ca, ck;\n  register int nmatched = 0;\n\n  while ((ca = *arg++) != '\\0') {\n    if ((ck = *keyword++) == '\\0')\n      return 0;\t\t\t/* arg longer than keyword, no good */\n    if (isupper(ca))\t\t/* force arg to lcase (assume ck is already) */\n      ca = tolower(ca);\n    if (ca != ck)\n      return 0;\t\t\t/* no good */\n    nmatched++;\t\t\t/* count matched characters */\n  }\n  /* reached end of argument; fail if it's too short for unique abbrev */\n  if (nmatched < minchars)\n    return 0;\n  return 1;\t\t\t/* A-OK */\n}\n\n\n/*\n * The main program.\n */\n\nint\nmain (int argc, char **argv)\n{\n  int argn;\n  char * arg;\n  int verbose = 0, raw = 0;\n\n  /* On Mac, fetch a command line. */\n#ifdef USE_CCOMMAND\n  argc = ccommand(&argv);\n#endif\n\n  progname = argv[0];\n  if (progname == NULL || progname[0] == 0)\n    progname = \"rdjpgcom\";\t/* in case C library doesn't provide it */\n\n  /* Parse switches, if any */\n  for (argn = 1; argn < argc; argn++) {\n    arg = argv[argn];\n    if (arg[0] != '-')\n      break;\t\t\t/* not switch, must be file name */\n    arg++;\t\t\t/* advance over '-' */\n    if (keymatch(arg, \"verbose\", 1)) {\n      verbose++;\n    } else if (keymatch(arg, \"raw\", 1)) {\n      raw = 1;\n    } else\n      usage();\n  }\n\n  /* Open the input file. */\n  /* Unix style: expect zero or one file name */\n  if (argn < argc-1) {\n    fprintf(stderr, \"%s: only one input file\\n\", progname);\n    usage();\n  }\n  if (argn < argc) {\n    if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open %s\\n\", progname, argv[argn]);\n      exit(EXIT_FAILURE);\n    }\n  } else {\n    /* default input file is stdin */\n#ifdef USE_SETMODE\t\t/* need to hack file mode? */\n    setmode(fileno(stdin), O_BINARY);\n#endif\n#ifdef USE_FDOPEN\t\t/* need to re-open in binary mode? */\n    if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open stdin\\n\", progname);\n      exit(EXIT_FAILURE);\n    }\n#else\n    infile = stdin;\n#endif\n  }\n\n  /* Scan the JPEG headers. */\n  (void) scan_JPEG_header(verbose, raw);\n\n  /* All done. */\n  exit(EXIT_SUCCESS);\n  return 0;\t\t\t/* suppress no-return-value warnings */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/rdppm.c",
    "content": "/*\n * rdppm.c\n *\n * Copyright (C) 1991-1997, Thomas G. Lane.\n * Modified 2009-2020 by Bill Allombert, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to read input images in PPM/PGM format.\n * The extended 2-byte-per-sample raw PPM/PGM formats are supported.\n * The PBMPLUS library is NOT required to compile this software\n * (but it is highly useful as a set of PPM image manipulation programs).\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume input from\n * an ordinary stdio stream.  They further assume that reading begins\n * at the start of the file; start_input may need work if the\n * user interface has already read some data (e.g., to determine that\n * the file is indeed PPM format).\n */\n\n/* Portions of this code are based on the PBMPLUS library, which is:\n**\n** Copyright (C) 1988 by Jef Poskanzer.\n**\n** Permission to use, copy, modify, and distribute this software and its\n** documentation for any purpose and without fee is hereby granted, provided\n** that the above copyright notice appear in all copies and that both that\n** copyright notice and this permission notice appear in supporting\n** documentation.  This software is provided \"as is\" without express or\n** implied warranty.\n*/\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef PPM_SUPPORTED\n\n\n/* Macros to deal with unsigned chars as efficiently as compiler allows */\n\n#ifdef HAVE_UNSIGNED_CHAR\ntypedef unsigned char U_CHAR;\n#define UCH(x)\t((int) (x))\n#else /* !HAVE_UNSIGNED_CHAR */\ntypedef char U_CHAR;\n#ifdef CHAR_IS_UNSIGNED\n#define UCH(x)\t((int) (x))\n#else\n#define UCH(x)\t((int) (x) & 0xFF)\n#endif\n#endif /* HAVE_UNSIGNED_CHAR */\n\n\n#define\tReadOK(file,buffer,len)\t(JFREAD(file,buffer,len) == ((size_t) (len)))\n\n\n/*\n * On most systems, reading individual bytes with getc() is drastically less\n * efficient than buffering a row at a time with fread().  On PCs, we must\n * allocate the buffer in near data space, because we are assuming small-data\n * memory model, wherein fread() can't reach far memory.  If you need to\n * process very wide images on a PC, you might have to compile in large-memory\n * model, or else replace fread() with a getc() loop --- which will be much\n * slower.\n */\n\n\n/* Private version of data source object */\n\ntypedef struct {\n  struct cjpeg_source_struct pub; /* public fields */\n\n  /* Usually these two pointers point to the same place: */\n  U_CHAR *iobuffer;\t\t/* fread's I/O buffer */\n  JSAMPROW pixrow;\t\t/* compressor input buffer */\n  size_t buffer_width;\t\t/* width of I/O buffer */\n  JSAMPLE *rescale;\t\t/* => maxval-remapping array, or NULL */\n  unsigned int maxval;\n} ppm_source_struct;\n\ntypedef ppm_source_struct * ppm_source_ptr;\n\n\nLOCAL(int)\npbm_getc (FILE * infile)\n/* Read next char, skipping over any comments */\n/* A comment/newline sequence is returned as a newline */\n{\n  register int ch;\n\n  ch = getc(infile);\n  if (ch == '#') {\n    do {\n      ch = getc(infile);\n    } while (ch != '\\n' && ch != EOF);\n  }\n  return ch;\n}\n\n\nLOCAL(unsigned int)\nread_pbm_integer (j_compress_ptr cinfo, FILE * infile)\n/* Read an unsigned decimal integer from the PPM file */\n/* Swallows one trailing character after the integer */\n/* Note that on a 16-bit-int machine, only values up to 64k can be read. */\n/* This should not be a problem in practice. */\n{\n  register int ch;\n  register unsigned int val;\n\n  /* Skip any leading whitespace */\n  do {\n    ch = pbm_getc(infile);\n    if (ch == EOF)\n      ERREXIT(cinfo, JERR_INPUT_EOF);\n  } while (ch == ' ' || ch == '\\t' || ch == '\\n' || ch == '\\r');\n\n  if (ch < '0' || ch > '9')\n    ERREXIT(cinfo, JERR_PPM_NONNUMERIC);\n\n  val = ch - '0';\n  while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {\n    val *= 10;\n    val += ch - '0';\n  }\n  return val;\n}\n\n\n/*\n * Read one row of pixels.\n *\n * We provide several different versions depending on input file format.\n * In all cases, input is scaled to the size of JSAMPLE.\n *\n * A really fast path is provided for reading byte/sample raw files with\n * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.\n */\n\n\nMETHODDEF(JDIMENSION)\nget_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading text-format PGM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  FILE * infile = source->pub.input_file;\n  register JSAMPROW ptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  ptr = source->pixrow;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = read_pbm_integer(cinfo, infile);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading text-format PPM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  FILE * infile = source->pub.input_file;\n  register JSAMPROW ptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  ptr = source->pixrow;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = read_pbm_integer(cinfo, infile);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = read_pbm_integer(cinfo, infile);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = read_pbm_integer(cinfo, infile);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading raw-byte-format PGM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register U_CHAR * bufferptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  ptr = source->pixrow;\n  bufferptr = source->iobuffer;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading raw-byte-format PPM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register U_CHAR * bufferptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  ptr = source->pixrow;\n  bufferptr = source->iobuffer;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.\n * In this case we just read right into the JSAMPLE buffer!\n * Note that same code works for PPM and PGM files.\n */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n\n  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading raw-word-format PGM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register U_CHAR * bufferptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  ptr = source->pixrow;\n  bufferptr = source->iobuffer;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = ((unsigned int) UCH(*bufferptr++)) << 8;\n    temp |= (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\nMETHODDEF(JDIMENSION)\nget_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading raw-word-format PPM files with any maxval */\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register U_CHAR * bufferptr;\n  register JSAMPLE *rescale = source->rescale;\n  unsigned int maxval = source->maxval;\n  JDIMENSION col;\n\n  if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n  ptr = source->pixrow;\n  bufferptr = source->iobuffer;\n  for (col = cinfo->image_width; col > 0; col--) {\n    register unsigned int temp;\n    temp = ((unsigned int) UCH(*bufferptr++)) << 8;\n    temp |= (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = ((unsigned int) UCH(*bufferptr++)) << 8;\n    temp |= (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n    temp = ((unsigned int) UCH(*bufferptr++)) << 8;\n    temp |= (unsigned int) UCH(*bufferptr++);\n    if (temp > maxval)\n      ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n    *ptr++ = rescale[temp];\n  }\n  return 1;\n}\n\n\n/*\n * Read the file header; return image size and component count.\n */\n\nMETHODDEF(void)\nstart_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  ppm_source_ptr source = (ppm_source_ptr) sinfo;\n  int c;\n  unsigned int w, h, maxval;\n  boolean need_iobuffer, use_raw_buffer, need_rescale;\n\n  if (getc(source->pub.input_file) != 'P')\n    ERREXIT(cinfo, JERR_PPM_NOT);\n\n  c = getc(source->pub.input_file); /* subformat discriminator character */\n\n  /* detect unsupported variants (ie, PBM) before trying to read header */\n  switch (c) {\n  case '2':\t\t\t/* it's a text-format PGM file */\n  case '3':\t\t\t/* it's a text-format PPM file */\n  case '5':\t\t\t/* it's a raw-format PGM file */\n  case '6':\t\t\t/* it's a raw-format PPM file */\n    break;\n  default:\n    ERREXIT(cinfo, JERR_PPM_NOT);\n  }\n\n  /* fetch the remaining header info */\n  w = read_pbm_integer(cinfo, source->pub.input_file);\n  h = read_pbm_integer(cinfo, source->pub.input_file);\n  maxval = read_pbm_integer(cinfo, source->pub.input_file);\n\n  if (w <= 0 || h <= 0 || maxval <= 0) /* error check */\n    ERREXIT(cinfo, JERR_PPM_NOT);\n\n  if (((long) w      >> 24) ||\t/* sanity check for buffer allocation below */\n      ((long) maxval >> 16))\t/* support max 16-bit (2-byte) sample values */\n    ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);\n\n  cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */\n  cinfo->image_width = (JDIMENSION) w;\n  cinfo->image_height = (JDIMENSION) h;\n  source->maxval = maxval;\n\n  /* initialize flags to most common settings */\n  need_iobuffer = TRUE;\t\t/* do we need an I/O buffer? */\n  use_raw_buffer = FALSE;\t/* do we map input buffer onto I/O buffer? */\n  need_rescale = TRUE;\t\t/* do we need a rescale array? */\n\n  switch (c) {\n  case '2':\t\t\t/* it's a text-format PGM file */\n    cinfo->input_components = 1;\n    cinfo->in_color_space = JCS_GRAYSCALE;\n    TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);\n    source->pub.get_pixel_rows = get_text_gray_row;\n    need_iobuffer = FALSE;\n    break;\n\n  case '3':\t\t\t/* it's a text-format PPM file */\n    cinfo->input_components = 3;\n    cinfo->in_color_space = JCS_RGB;\n    TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);\n    source->pub.get_pixel_rows = get_text_rgb_row;\n    need_iobuffer = FALSE;\n    break;\n\n  case '5':\t\t\t/* it's a raw-format PGM file */\n    cinfo->input_components = 1;\n    cinfo->in_color_space = JCS_GRAYSCALE;\n    TRACEMS2(cinfo, 1, JTRC_PGM, w, h);\n    if (maxval > 255) {\n      source->pub.get_pixel_rows = get_word_gray_row;\n    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {\n      source->pub.get_pixel_rows = get_raw_row;\n      use_raw_buffer = TRUE;\n      need_rescale = FALSE;\n    } else {\n      source->pub.get_pixel_rows = get_scaled_gray_row;\n    }\n    break;\n\n  case '6':\t\t\t/* it's a raw-format PPM file */\n    cinfo->input_components = 3;\n    cinfo->in_color_space = JCS_RGB;\n    TRACEMS2(cinfo, 1, JTRC_PPM, w, h);\n    if (maxval > 255) {\n      source->pub.get_pixel_rows = get_word_rgb_row;\n    } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {\n      source->pub.get_pixel_rows = get_raw_row;\n      use_raw_buffer = TRUE;\n      need_rescale = FALSE;\n    } else {\n      source->pub.get_pixel_rows = get_scaled_rgb_row;\n    }\n    break;\n  }\n\n  /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */\n  if (need_iobuffer) {\n    source->buffer_width = (size_t) w * (size_t) cinfo->input_components *\n      ((maxval <= 255) ? SIZEOF(U_CHAR) : (2 * SIZEOF(U_CHAR)));\n    source->iobuffer = (U_CHAR *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, source->buffer_width);\n  }\n\n  /* Create compressor input buffer. */\n  if (use_raw_buffer) {\n    /* For unscaled raw-input case, we can just map it onto the I/O buffer. */\n    /* Cast here implies near->far pointer conversion on PCs */\n    source->pixrow = (JSAMPROW) source->iobuffer;\n  } else {\n    /* Need to translate anyway, so make a separate sample buffer. */\n    source->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) w *\n       (size_t) cinfo->input_components * SIZEOF(JSAMPLE));\n  }\n  /* Synthesize a JSAMPARRAY pointer structure */\n  source->pub.buffer = & source->pixrow;\n  source->pub.buffer_height = 1;\n\n  /* Compute the rescaling array if required. */\n  if (need_rescale) {\n    INT32 val, half_maxval;\n\n    /* On 16-bit-int machines we have to be careful of maxval = 65535 */\n    source->rescale = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,\n      JPOOL_IMAGE, ((size_t) maxval + (size_t) 1) * SIZEOF(JSAMPLE));\n    half_maxval = maxval / 2;\n    for (val = 0; val <= (INT32) maxval; val++) {\n      /* The multiplication here must be done in 32 bits to avoid overflow */\n      source->rescale[val] = (JSAMPLE) ((val * MAXJSAMPLE + half_maxval) / maxval);\n    }\n  }\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  /* no work */\n}\n\n\n/*\n * The module selection routine for PPM format input.\n */\n\nGLOBAL(cjpeg_source_ptr)\njinit_read_ppm (j_compress_ptr cinfo)\n{\n  ppm_source_ptr source;\n\n  /* Create module interface object */\n  source = (ppm_source_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_source_struct));\n  /* Fill in method ptrs, except get_pixel_rows which start_input sets */\n  source->pub.start_input = start_input_ppm;\n  source->pub.finish_input = finish_input_ppm;\n\n  return &source->pub;\n}\n\n#endif /* PPM_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/rdrle.c",
    "content": "/*\n * rdrle.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to read input images in Utah RLE format.\n * The Utah Raster Toolkit library is required (version 3.1 or later).\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume input from\n * an ordinary stdio stream.  They further assume that reading begins\n * at the start of the file; start_input may need work if the\n * user interface has already read some data (e.g., to determine that\n * the file is indeed RLE format).\n *\n * Based on code contributed by Mike Lijewski,\n * with updates from Robert Hutchinson.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef RLE_SUPPORTED\n\n/* rle.h is provided by the Utah Raster Toolkit. */\n\n#include <rle.h>\n\n/*\n * We assume that JSAMPLE has the same representation as rle_pixel,\n * to wit, \"unsigned char\".  Hence we can't cope with 12- or 16-bit samples.\n */\n\n#if BITS_IN_JSAMPLE != 8\n  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */\n#endif\n\n/*\n * We support the following types of RLE files:\n *   \n *   GRAYSCALE   - 8 bits, no colormap\n *   MAPPEDGRAY  - 8 bits, 1 channel colomap\n *   PSEUDOCOLOR - 8 bits, 3 channel colormap\n *   TRUECOLOR   - 24 bits, 3 channel colormap\n *   DIRECTCOLOR - 24 bits, no colormap\n *\n * For now, we ignore any alpha channel in the image.\n */\n\ntypedef enum\n  { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;\n\n\n/*\n * Since RLE stores scanlines bottom-to-top, we have to invert the image\n * to conform to JPEG's top-to-bottom order.  To do this, we read the\n * incoming image into a virtual array on the first get_pixel_rows call,\n * then fetch the required row from the virtual array on subsequent calls.\n */\n\ntypedef struct _rle_source_struct * rle_source_ptr;\n\ntypedef struct _rle_source_struct {\n  struct cjpeg_source_struct pub; /* public fields */\n\n  rle_kind visual;              /* actual type of input file */\n  jvirt_sarray_ptr image;       /* virtual array to hold the image */\n  JDIMENSION row;\t\t/* current row # in the virtual array */\n  rle_hdr header;               /* Input file information */\n  rle_pixel **rle_row;          /* holds a row returned by rle_getrow() */\n\n} rle_source_struct;\n\n\n/*\n * Read the file header; return image size and component count.\n */\n\nMETHODDEF(void)\nstart_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  rle_source_ptr source = (rle_source_ptr) sinfo;\n  JDIMENSION width, height;\n#ifdef PROGRESS_REPORT\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n#endif\n\n  /* Use RLE library routine to get the header info */\n  source->header = *rle_hdr_init(NULL);\n  source->header.rle_file = source->pub.input_file;\n  switch (rle_get_setup(&(source->header))) {\n  case RLE_SUCCESS:\n    /* A-OK */\n    break;\n  case RLE_NOT_RLE:\n    ERREXIT(cinfo, JERR_RLE_NOT);\n  case RLE_NO_SPACE:\n    ERREXIT(cinfo, JERR_RLE_MEM);\n  case RLE_EMPTY:\n    ERREXIT(cinfo, JERR_RLE_EMPTY);\n  case RLE_EOF:\n    ERREXIT(cinfo, JERR_RLE_EOF);\n  default:\n    ERREXIT(cinfo, JERR_RLE_BADERROR);\n  }\n\n  /* Figure out what we have, set private vars and return values accordingly */\n  \n  width  = source->header.xmax - source->header.xmin + 1;\n  height = source->header.ymax - source->header.ymin + 1;\n  source->header.xmin = 0;\t\t/* realign horizontally */\n  source->header.xmax = width-1;\n\n  cinfo->image_width      = width;\n  cinfo->image_height     = height;\n  cinfo->data_precision   = 8;  /* we can only handle 8 bit data */\n\n  if (source->header.ncolors == 1 && source->header.ncmap == 0) {\n    source->visual     = GRAYSCALE;\n    TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);\n  } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {\n    source->visual     = MAPPEDGRAY;\n    TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,\n             1 << source->header.cmaplen);\n  } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {\n    source->visual     = PSEUDOCOLOR;\n    TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,\n\t     1 << source->header.cmaplen);\n  } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {\n    source->visual     = TRUECOLOR;\n    TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,\n\t     1 << source->header.cmaplen);\n  } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {\n    source->visual     = DIRECTCOLOR;\n    TRACEMS2(cinfo, 1, JTRC_RLE, width, height);\n  } else\n    ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);\n  \n  if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {\n    cinfo->in_color_space   = JCS_GRAYSCALE;\n    cinfo->input_components = 1;\n  } else {\n    cinfo->in_color_space   = JCS_RGB;\n    cinfo->input_components = 3;\n  }\n\n  /*\n   * A place to hold each scanline while it's converted.\n   * (GRAYSCALE scanlines don't need converting)\n   */\n  if (source->visual != GRAYSCALE) {\n    source->rle_row = (rle_pixel **) (*cinfo->mem->alloc_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE,\n       width, (JDIMENSION) cinfo->input_components);\n  }\n\n  /* request a virtual array to hold the image */\n  source->image = (*cinfo->mem->request_virt_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n     width * (JDIMENSION) source->header.ncolors, height, (JDIMENSION) 1);\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL) {\n    /* count file input as separate pass */\n    progress->total_extra_passes++;\n  }\n#endif\n\n  source->pub.buffer_height = 1;\n}\n\n\n/*\n * Read one row of pixels.\n * Called only after load_image has read the image into the virtual array.\n * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.\n */\n\nMETHODDEF(JDIMENSION)\nget_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  rle_source_ptr source = (rle_source_ptr) sinfo;\n\n  source->row--;\n  source->pub.buffer = (*cinfo->mem->access_virt_sarray)\n    ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);\n\n  return 1;\n}\n\n/*\n * Read one row of pixels.\n * Called only after load_image has read the image into the virtual array.\n * Used for PSEUDOCOLOR images.\n */\n\nMETHODDEF(JDIMENSION)\nget_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  rle_source_ptr source = (rle_source_ptr) sinfo;\n  JSAMPROW src_row, dest_row;\n  JDIMENSION col;\n  rle_map *colormap;\n  int val;\n\n  colormap = source->header.cmap;\n  dest_row = source->pub.buffer[0];\n  source->row--;\n  src_row = * (*cinfo->mem->access_virt_sarray)\n    ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);\n\n  for (col = cinfo->image_width; col > 0; col--) {\n    val = GETJSAMPLE(*src_row++);\n    *dest_row++ = (JSAMPLE) (colormap[val      ] >> 8);\n    *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);\n    *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);\n  }\n\n  return 1;\n}\n\n\n/*\n * Load the image into a virtual array.  We have to do this because RLE\n * files start at the lower left while the JPEG standard has them starting\n * in the upper left.  This is called the first time we want to get a row\n * of input.  What we do is load the RLE data into the array and then call\n * the appropriate routine to read one row from the array.  Before returning,\n * we set source->pub.get_pixel_rows so that subsequent calls go straight to\n * the appropriate row-reading routine.\n */\n\nMETHODDEF(JDIMENSION)\nload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  rle_source_ptr source = (rle_source_ptr) sinfo;\n  JDIMENSION row, col;\n  JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;\n  rle_pixel **rle_row;\n  rle_map *colormap;\n  char channel;\n#ifdef PROGRESS_REPORT\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n#endif\n\n  /* Read the RLE data into our virtual array.\n   * We assume here that (a) rle_pixel is represented the same as JSAMPLE,\n   * and (b) we are not on a machine where FAR pointers differ from regular.\n   */\n  RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL) {\n    progress->pub.pass_limit = cinfo->image_height;\n    progress->pub.pass_counter = 0;\n    (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n  }\n#endif\n\n  switch (source->visual) {\n\n  case GRAYSCALE:\n  case PSEUDOCOLOR:\n    for (row = 0; row < cinfo->image_height; row++) {\n      rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);\n      rle_getrow(&source->header, rle_row);\n#ifdef PROGRESS_REPORT\n      if (progress != NULL) {\n\tprogress->pub.pass_counter++;\n\t(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n      }\n#endif\n    }\n    break;\n\n  case MAPPEDGRAY:\n  case TRUECOLOR:\n    rle_row = source->rle_row;\n    colormap = source->header.cmap;\n    for (row = 0; row < cinfo->image_height; row++) {\n      rle_getrow(&source->header, rle_row);\n      scanline = * (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);\n\n      for (col = 0; col < cinfo->image_width; col++) {\n\tfor (channel = 0; channel < source->header.ncolors; channel++) {\n\t  *scanline++ = (JSAMPLE)\n\t    (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);\n\t}\n      }\n\n#ifdef PROGRESS_REPORT\n      if (progress != NULL) {\n\tprogress->pub.pass_counter++;\n\t(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n      }\n#endif\n    }\n    break;\n\n  case DIRECTCOLOR:\n    rle_row = source->rle_row;\n    for (row = 0; row < cinfo->image_height; row++) {\n      rle_getrow(&source->header, rle_row);\n      scanline = * (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);\n\n      red_ptr   = rle_row[0];\n      green_ptr = rle_row[1];\n      blue_ptr  = rle_row[2];\n\n      for (col = cinfo->image_width; col > 0; col--) {\n\t*scanline++ = *red_ptr++;\n\t*scanline++ = *green_ptr++;\n\t*scanline++ = *blue_ptr++;\n      }\n\n#ifdef PROGRESS_REPORT\n      if (progress != NULL) {\n\tprogress->pub.pass_counter++;\n\t(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n      }\n#endif\n    }\n  }\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n#endif\n\n  /* Set up to call proper row-extraction routine in future */\n  if (source->visual == PSEUDOCOLOR) {\n    source->pub.buffer = source->rle_row;\n    source->pub.get_pixel_rows = get_pseudocolor_row;\n  } else {\n    source->pub.get_pixel_rows = get_rle_row;\n  }\n  source->row = cinfo->image_height;\n\n  /* And fetch the topmost (bottommost) row */\n  return (*source->pub.get_pixel_rows) (cinfo, sinfo);   \n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  /* no work */\n}\n\n\n/*\n * The module selection routine for RLE format input.\n */\n\nGLOBAL(cjpeg_source_ptr)\njinit_read_rle (j_compress_ptr cinfo)\n{\n  rle_source_ptr source;\n\n  /* Create module interface object */\n  source = (rle_source_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_source_struct));\n  /* Fill in method ptrs */\n  source->pub.start_input = start_input_rle;\n  source->pub.finish_input = finish_input_rle;\n  source->pub.get_pixel_rows = load_image;\n\n  return &source->pub;\n}\n\n#endif /* RLE_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/rdswitch.c",
    "content": "/*\n * rdswitch.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2003-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to process some of cjpeg's more complicated\n * command-line switches.  Switches processed here are:\n *\t-qtables file\t\tRead quantization tables from text file\n *\t-scans file\t\tRead scan script from text file\n *\t-quality N[,N,...]\tSet quality ratings\n *\t-qslots N[,N,...]\tSet component quantization table selectors\n *\t-sample HxV[,HxV,...]\tSet component sampling factors\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n#include <ctype.h>\t\t/* to declare isdigit(), isspace() */\n\n\nLOCAL(int)\ntext_getc (FILE * file)\n/* Read next char, skipping over any comments (# to end of line) */\n/* A comment/newline sequence is returned as a newline */\n{\n  register int ch;\n  \n  ch = getc(file);\n  if (ch == '#') {\n    do {\n      ch = getc(file);\n    } while (ch != '\\n' && ch != EOF);\n  }\n  return ch;\n}\n\n\nLOCAL(boolean)\nread_text_integer (FILE * file, long * result, int * termchar)\n/* Read an unsigned decimal integer from a file, store it in result */\n/* Reads one trailing character after the integer; returns it in termchar */\n{\n  register int ch;\n  register long val;\n  \n  /* Skip any leading whitespace, detect EOF */\n  do {\n    ch = text_getc(file);\n    if (ch == EOF) {\n      *termchar = ch;\n      return FALSE;\n    }\n  } while (isspace(ch));\n  \n  if (! isdigit(ch)) {\n    *termchar = ch;\n    return FALSE;\n  }\n\n  val = ch - '0';\n  while ((ch = text_getc(file)) != EOF) {\n    if (! isdigit(ch))\n      break;\n    val *= 10;\n    val += ch - '0';\n  }\n  *result = val;\n  *termchar = ch;\n  return TRUE;\n}\n\n\nGLOBAL(boolean)\nread_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)\n/* Read a set of quantization tables from the specified file.\n * The file is plain ASCII text: decimal numbers with whitespace between.\n * Comments preceded by '#' may be included in the file.\n * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.\n * The tables are implicitly numbered 0,1,etc.\n * NOTE: does not affect the qslots mapping, which will default to selecting\n * table 0 for luminance (or primary) components, 1 for chrominance components.\n * You must use -qslots if you want a different component->table mapping.\n */\n{\n  FILE * fp;\n  int tblno, i, termchar;\n  long val;\n  unsigned int table[DCTSIZE2];\n\n  if ((fp = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Can't open table file %s\\n\", filename);\n    return FALSE;\n  }\n  tblno = 0;\n\n  while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */\n    if (tblno >= NUM_QUANT_TBLS) {\n      fprintf(stderr, \"Too many tables in file %s\\n\", filename);\n      fclose(fp);\n      return FALSE;\n    }\n    table[0] = (unsigned int) val;\n    for (i = 1; i < DCTSIZE2; i++) {\n      if (! read_text_integer(fp, &val, &termchar)) {\n\tfprintf(stderr, \"Invalid table data in file %s\\n\", filename);\n\tfclose(fp);\n\treturn FALSE;\n      }\n      table[i] = (unsigned int) val;\n    }\n    jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],\n\t\t\t force_baseline);\n    tblno++;\n  }\n\n  if (termchar != EOF) {\n    fprintf(stderr, \"Non-numeric data in file %s\\n\", filename);\n    fclose(fp);\n    return FALSE;\n  }\n\n  fclose(fp);\n  return TRUE;\n}\n\n\n#ifdef C_MULTISCAN_FILES_SUPPORTED\n\nLOCAL(boolean)\nread_scan_integer (FILE * file, long * result, int * termchar)\n/* Variant of read_text_integer that always looks for a non-space termchar;\n * this simplifies parsing of punctuation in scan scripts.\n */\n{\n  register int ch;\n\n  if (! read_text_integer(file, result, termchar))\n    return FALSE;\n  ch = *termchar;\n  while (ch != EOF && isspace(ch))\n    ch = text_getc(file);\n  if (isdigit(ch)) {\t\t/* oops, put it back */\n    if (ungetc(ch, file) == EOF)\n      return FALSE;\n    ch = ' ';\n  } else {\n    /* Any separators other than ';' and ':' are ignored;\n     * this allows user to insert commas, etc, if desired.\n     */\n    if (ch != EOF && ch != ';' && ch != ':')\n      ch = ' ';\n  }\n  *termchar = ch;\n  return TRUE;\n}\n\n\nGLOBAL(boolean)\nread_scan_script (j_compress_ptr cinfo, char * filename)\n/* Read a scan script from the specified text file.\n * Each entry in the file defines one scan to be emitted.\n * Entries are separated by semicolons ';'.\n * An entry contains one to four component indexes,\n * optionally followed by a colon ':' and four progressive-JPEG parameters.\n * The component indexes denote which component(s) are to be transmitted\n * in the current scan.  The first component has index 0.\n * Sequential JPEG is used if the progressive-JPEG parameters are omitted.\n * The file is free format text: any whitespace may appear between numbers\n * and the ':' and ';' punctuation marks.  Also, other punctuation (such\n * as commas or dashes) can be placed between numbers if desired.\n * Comments preceded by '#' may be included in the file.\n * Note: we do very little validity checking here;\n * jcmaster.c will validate the script parameters.\n */\n{\n  FILE * fp;\n  int scanno, ncomps, termchar;\n  long val;\n  jpeg_scan_info * scanptr;\n#define MAX_SCANS  100\t\t/* quite arbitrary limit */\n  jpeg_scan_info scans[MAX_SCANS];\n\n  if ((fp = fopen(filename, \"r\")) == NULL) {\n    fprintf(stderr, \"Can't open scan definition file %s\\n\", filename);\n    return FALSE;\n  }\n  scanptr = scans;\n  scanno = 0;\n\n  while (read_scan_integer(fp, &val, &termchar)) {\n    if (scanno >= MAX_SCANS) {\n      fprintf(stderr, \"Too many scans defined in file %s\\n\", filename);\n      fclose(fp);\n      return FALSE;\n    }\n    scanptr->component_index[0] = (int) val;\n    ncomps = 1;\n    while (termchar == ' ') {\n      if (ncomps >= MAX_COMPS_IN_SCAN) {\n\tfprintf(stderr, \"Too many components in one scan in file %s\\n\",\n\t\tfilename);\n\tfclose(fp);\n\treturn FALSE;\n      }\n      if (! read_scan_integer(fp, &val, &termchar))\n\tgoto bogus;\n      scanptr->component_index[ncomps] = (int) val;\n      ncomps++;\n    }\n    scanptr->comps_in_scan = ncomps;\n    if (termchar == ':') {\n      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')\n\tgoto bogus;\n      scanptr->Ss = (int) val;\n      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')\n\tgoto bogus;\n      scanptr->Se = (int) val;\n      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')\n\tgoto bogus;\n      scanptr->Ah = (int) val;\n      if (! read_scan_integer(fp, &val, &termchar))\n\tgoto bogus;\n      scanptr->Al = (int) val;\n    } else {\n      /* set non-progressive parameters */\n      scanptr->Ss = 0;\n      scanptr->Se = DCTSIZE2-1;\n      scanptr->Ah = 0;\n      scanptr->Al = 0;\n    }\n    if (termchar != ';' && termchar != EOF) {\nbogus:\n      fprintf(stderr, \"Invalid scan entry format in file %s\\n\", filename);\n      fclose(fp);\n      return FALSE;\n    }\n    scanptr++, scanno++;\n  }\n\n  if (termchar != EOF) {\n    fprintf(stderr, \"Non-numeric data in file %s\\n\", filename);\n    fclose(fp);\n    return FALSE;\n  }\n\n  if (scanno > 0) {\n    /* Stash completed scan list in cinfo structure.\n     * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,\n     * but if you want to compress multiple images you'd want JPOOL_PERMANENT.\n     */\n    scanptr = (jpeg_scan_info *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, scanno * SIZEOF(jpeg_scan_info));\n    MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));\n    cinfo->scan_info = scanptr;\n    cinfo->num_scans = scanno;\n  }\n\n  fclose(fp);\n  return TRUE;\n}\n\n#endif /* C_MULTISCAN_FILES_SUPPORTED */\n\n\nGLOBAL(boolean)\nset_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)\n/* Process a quality-ratings parameter string, of the form\n *     N[,N,...]\n * If there are more q-table slots than parameters, the last value is replicated.\n */\n{\n  int val = 75;\t\t\t/* default value */\n  int tblno;\n  char ch;\n\n  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {\n    if (*arg) {\n      ch = ',';\t\t\t/* if not set by sscanf, will be ',' */\n      if (sscanf(arg, \"%d%c\", &val, &ch) < 1)\n\treturn FALSE;\n      if (ch != ',')\t\t/* syntax check */\n\treturn FALSE;\n      /* Convert user 0-100 rating to percentage scaling */\n      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);\n      while (*arg && *arg++ != ','); /* advance to next segment of arg string */\n    } else {\n      /* reached end of parameter, set remaining factors to last value */\n      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);\n    }\n  }\n  jpeg_default_qtables(cinfo, force_baseline);\n  return TRUE;\n}\n\n\nGLOBAL(boolean)\nset_quant_slots (j_compress_ptr cinfo, char *arg)\n/* Process a quantization-table-selectors parameter string, of the form\n *     N[,N,...]\n * If there are more components than parameters, the last value is replicated.\n */\n{\n  int val = 0;\t\t\t/* default table # */\n  int ci;\n  char ch;\n\n  for (ci = 0; ci < MAX_COMPONENTS; ci++) {\n    if (*arg) {\n      ch = ',';\t\t\t/* if not set by sscanf, will be ',' */\n      if (sscanf(arg, \"%d%c\", &val, &ch) < 1)\n\treturn FALSE;\n      if (ch != ',')\t\t/* syntax check */\n\treturn FALSE;\n      if (val < 0 || val >= NUM_QUANT_TBLS) {\n\tfprintf(stderr, \"JPEG quantization tables are numbered 0..%d\\n\",\n\t\tNUM_QUANT_TBLS-1);\n\treturn FALSE;\n      }\n      cinfo->comp_info[ci].quant_tbl_no = val;\n      while (*arg && *arg++ != ','); /* advance to next segment of arg string */\n    } else {\n      /* reached end of parameter, set remaining components to last table */\n      cinfo->comp_info[ci].quant_tbl_no = val;\n    }\n  }\n  return TRUE;\n}\n\n\nGLOBAL(boolean)\nset_sample_factors (j_compress_ptr cinfo, char *arg)\n/* Process a sample-factors parameter string, of the form\n *     HxV[,HxV,...]\n * If there are more components than parameters, \"1x1\" is assumed for the rest.\n */\n{\n  int ci, val1, val2;\n  char ch1, ch2;\n\n  for (ci = 0; ci < MAX_COMPONENTS; ci++) {\n    if (*arg) {\n      ch2 = ',';\t\t/* if not set by sscanf, will be ',' */\n      if (sscanf(arg, \"%d%c%d%c\", &val1, &ch1, &val2, &ch2) < 3)\n\treturn FALSE;\n      if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */\n\treturn FALSE;\n      if (val1 <= 0 || val1 > MAX_SAMP_FACTOR ||\n\t  val2 <= 0 || val2 > MAX_SAMP_FACTOR) {\n\tfprintf(stderr, \"JPEG sampling factors must be 1..%d\\n\", MAX_SAMP_FACTOR);\n\treturn FALSE;\n      }\n      cinfo->comp_info[ci].h_samp_factor = val1;\n      cinfo->comp_info[ci].v_samp_factor = val2;\n      while (*arg && *arg++ != ','); /* advance to next segment of arg string */\n    } else {\n      /* reached end of parameter, set remaining components to 1x1 sampling */\n      cinfo->comp_info[ci].h_samp_factor = 1;\n      cinfo->comp_info[ci].v_samp_factor = 1;\n    }\n  }\n  return TRUE;\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/rdtarga.c",
    "content": "/*\n * rdtarga.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2017-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to read input images in Targa format.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume input from\n * an ordinary stdio stream.  They further assume that reading begins\n * at the start of the file; start_input may need work if the\n * user interface has already read some data (e.g., to determine that\n * the file is indeed Targa format).\n *\n * Based on code contributed by Lee Daniel Crocker.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef TARGA_SUPPORTED\n\n\n/* Macros to deal with unsigned chars as efficiently as compiler allows */\n\n#ifdef HAVE_UNSIGNED_CHAR\ntypedef unsigned char U_CHAR;\n#define UCH(x)\t((int) (x))\n#else /* !HAVE_UNSIGNED_CHAR */\ntypedef char U_CHAR;\n#ifdef CHAR_IS_UNSIGNED\n#define UCH(x)\t((int) (x))\n#else\n#define UCH(x)\t((int) (x) & 0xFF)\n#endif\n#endif /* HAVE_UNSIGNED_CHAR */\n\n\n#define\tReadOK(file,buffer,len)\t(JFREAD(file,buffer,len) == ((size_t) (len)))\n\n\n/* Private version of data source object */\n\ntypedef struct _tga_source_struct * tga_source_ptr;\n\ntypedef struct _tga_source_struct {\n  struct cjpeg_source_struct pub; /* public fields */\n\n  j_compress_ptr cinfo;\t\t/* back link saves passing separate parm */\n\n  JSAMPARRAY colormap;\t\t/* Targa colormap (converted to my format) */\n\n  jvirt_sarray_ptr whole_image;\t/* Needed if funny input row order */\n  JDIMENSION current_row;\t/* Current logical row number to read */\n\n  /* Pointer to routine to extract next Targa pixel from input file */\n  JMETHOD(void, read_pixel, (tga_source_ptr sinfo));\n\n  /* Result of read_pixel is delivered here: */\n  U_CHAR tga_pixel[4];\n\n  int pixel_size;\t\t/* Bytes per Targa pixel (1 to 4) */\n  int cmap_length;\t\t/* colormap length */\n\n  /* State info for reading RLE-coded pixels; both counts must be init to 0 */\n  int block_count;\t\t/* # of pixels remaining in RLE block */\n  int dup_pixel_count;\t\t/* # of times to duplicate previous pixel */\n\n  /* This saves the correct pixel-row-expansion method for preload_image */\n  JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,\n\t\t\t\t       cjpeg_source_ptr sinfo));\n} tga_source_struct;\n\n\n/* For expanding 5-bit pixel values to 8-bit with best rounding */\n\nstatic const UINT8 c5to8bits[32] = {\n    0,   8,  16,  25,  33,  41,  49,  58,\n   66,  74,  82,  90,  99, 107, 115, 123,\n  132, 140, 148, 156, 165, 173, 181, 189,\n  197, 206, 214, 222, 230, 239, 247, 255\n};\n\n\n\nLOCAL(int)\nread_byte (tga_source_ptr sinfo)\n/* Read next byte from Targa file */\n{\n  register FILE *infile = sinfo->pub.input_file;\n  register int c;\n\n  if ((c = getc(infile)) == EOF)\n    ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);\n  return c;\n}\n\n\nLOCAL(void)\nread_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)\n/* Read the colormap from a Targa file */\n{\n  int i;\n\n  /* Presently only handles 24-bit BGR format */\n  if (mapentrysize != 24)\n    ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);\n\n  for (i = 0; i < cmaplen; i++) {\n    sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);\n    sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);\n    sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);\n  }\n}\n\n\n/*\n * read_pixel methods: get a single pixel from Targa file into tga_pixel[]\n */\n\nMETHODDEF(void)\nread_non_rle_pixel (tga_source_ptr sinfo)\n/* Read one Targa pixel from the input file; no RLE expansion */\n{\n  register int i;\n\n  for (i = 0; i < sinfo->pixel_size; i++) {\n    sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo);\n  }\n}\n\nMETHODDEF(void)\nread_rle_pixel (tga_source_ptr sinfo)\n/* Read one Targa pixel from the input file, expanding RLE data as needed */\n{\n  register int i;\n\n  /* Duplicate previously read pixel? */\n  if (sinfo->dup_pixel_count > 0) {\n    sinfo->dup_pixel_count--;\n    return;\n  }\n\n  /* Time to read RLE block header? */\n  if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */\n    i = read_byte(sinfo);\n    if (i & 0x80) {\t\t/* Start of duplicate-pixel block? */\n      sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */\n      sinfo->block_count = 0;\t/* then read new block header */\n    } else {\n      sinfo->block_count = i & 0x7F; /* number of pixels after this one */\n    }\n  }\n\n  /* Read next pixel */\n  for (i = 0; i < sinfo->pixel_size; i++) {\n    sinfo->tga_pixel[i] = (U_CHAR) read_byte(sinfo);\n  }\n}\n\n\n/*\n * Read one row of pixels.\n *\n * We provide several different versions depending on input file format.\n */\n\nMETHODDEF(JDIMENSION)\nget_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 8-bit grayscale pixels */\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n\n  ptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */\n    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);\n  }\n  return 1;\n}\n\nMETHODDEF(JDIMENSION)\nget_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 8-bit colormap indexes */\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register JSAMPARRAY colormap;\n  register JDIMENSION col;\n  register int t;\n  int cmaplen;\n\n  ptr = source->pub.buffer[0];\n  colormap = source->colormap;\n  cmaplen = source->cmap_length;\n  for (col = cinfo->image_width; col > 0; col--) {\n    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */\n    t = UCH(source->tga_pixel[0]);\n    if (t >= cmaplen)\n      ERREXIT(cinfo, JERR_TGA_BADPARMS);\n    *ptr++ = colormap[0][t];\n    *ptr++ = colormap[1][t];\n    *ptr++ = colormap[2][t];\n  }\n  return 1;\n}\n\nMETHODDEF(JDIMENSION)\nget_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 16-bit pixels */\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  register int t;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n\n  ptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */\n    t = UCH(source->tga_pixel[0]);\n    t += UCH(source->tga_pixel[1]) << 8;\n    /* We expand 5 bit data to 8 bit sample width.\n     * The format of the 16-bit (LSB first) input word is\n     *     xRRRRRGGGGGBBBBB\n     */\n    ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];\n    t >>= 5;\n    ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];\n    t >>= 5;\n    ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];\n    ptr += 3;\n  }\n  return 1;\n}\n\nMETHODDEF(JDIMENSION)\nget_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n/* This version is for reading 24-bit pixels */\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n\n  ptr = source->pub.buffer[0];\n  for (col = cinfo->image_width; col > 0; col--) {\n    (*source->read_pixel) (source); /* Load next pixel into tga_pixel */\n    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */\n    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);\n    *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);\n  }\n  return 1;\n}\n\n/*\n * Targa also defines a 32-bit pixel format with order B,G,R,A.\n * We presently ignore the attribute byte, so the code for reading\n * these pixels is identical to the 24-bit routine above.\n * This works because the actual pixel length is only known to read_pixel.\n */\n\n#define get_32bit_row  get_24bit_row\n\n\n/*\n * This method is for re-reading the input data in standard top-down\n * row order.  The entire image has already been read into whole_image\n * with proper conversion of pixel format, but it's in a funny row order.\n */\n\nMETHODDEF(JDIMENSION)\nget_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  JDIMENSION source_row;\n\n  /* Compute row of source that maps to current_row of normal order */\n  /* For now, assume image is bottom-up and not interlaced. */\n  /* NEEDS WORK to support interlaced images! */\n  source_row = cinfo->image_height - source->current_row - 1;\n\n  /* Fetch that row from virtual array */\n  source->pub.buffer = (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    source->whole_image, source_row, (JDIMENSION) 1, FALSE);\n\n  source->current_row++;\n  return 1;\n}\n\n\n/*\n * This method loads the image into whole_image during the first call on\n * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call\n * get_memory_row on subsequent calls.\n */\n\nMETHODDEF(JDIMENSION)\npreload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  JDIMENSION row;\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n\n  /* Read the data into a virtual array in input-file row order. */\n  for (row = 0; row < cinfo->image_height; row++) {\n    if (progress != NULL) {\n      progress->pub.pass_counter = (long) row;\n      progress->pub.pass_limit = (long) cinfo->image_height;\n      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n    }\n    source->pub.buffer = (*cinfo->mem->access_virt_sarray)\n      ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);\n    (*source->get_pixel_rows) (cinfo, sinfo);\n  }\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n\n  /* Set up to read from the virtual array in unscrambled order */\n  source->pub.get_pixel_rows = get_memory_row;\n  source->current_row = 0;\n  /* And read the first row */\n  return get_memory_row(cinfo, sinfo);\n}\n\n\n/*\n * Read the file header; return image size and component count.\n */\n\nMETHODDEF(void)\nstart_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  tga_source_ptr source = (tga_source_ptr) sinfo;\n  U_CHAR targaheader[18];\n  int idlen, cmaptype, subtype, flags, interlace_type, components;\n  unsigned int width, height, maplen;\n  boolean is_bottom_up;\n\n#define GET_2B(offset)\t((unsigned int) UCH(targaheader[offset]) + \\\n\t\t\t (((unsigned int) UCH(targaheader[offset+1])) << 8))\n\n  if (! ReadOK(source->pub.input_file, targaheader, 18))\n    ERREXIT(cinfo, JERR_INPUT_EOF);\n\n  /* Pretend \"15-bit\" pixels are 16-bit --- we ignore attribute bit anyway */\n  if (targaheader[16] == 15)\n    targaheader[16] = 16;\n\n  idlen = UCH(targaheader[0]);\n  cmaptype = UCH(targaheader[1]);\n  subtype = UCH(targaheader[2]);\n  maplen = GET_2B(5);\n  width = GET_2B(12);\n  height = GET_2B(14);\n  source->pixel_size = UCH(targaheader[16]) >> 3;\n  flags = UCH(targaheader[17]);\t/* Image Descriptor byte */\n\n  is_bottom_up = ((flags & 0x20) == 0);\t/* bit 5 set => top-down */\n  interlace_type = flags >> 6;\t/* bits 6/7 are interlace code */\n\n  if (cmaptype > 1 ||\t\t/* cmaptype must be 0 or 1 */\n      width <= 0 || height <= 0 ||\n      source->pixel_size < 1 || source->pixel_size > 4 ||\n      (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */\n      interlace_type != 0 ||      /* currently don't allow interlaced image */\n      width == 0 || height == 0)  /* image width/height must be non-zero */\n    ERREXIT(cinfo, JERR_TGA_BADPARMS);\n\n  if (subtype > 8) {\n    /* It's an RLE-coded file */\n    source->read_pixel = read_rle_pixel;\n    source->block_count = source->dup_pixel_count = 0;\n    subtype -= 8;\n  } else {\n    /* Non-RLE file */\n    source->read_pixel = read_non_rle_pixel;\n  }\n\n  /* Now should have subtype 1, 2, or 3 */\n  components = 3;\t\t/* until proven different */\n  cinfo->in_color_space = JCS_RGB;\n\n  switch (subtype) {\n  case 1:\t\t\t/* Colormapped image */\n    if (source->pixel_size == 1 && cmaptype == 1)\n      source->get_pixel_rows = get_8bit_row;\n    else\n      ERREXIT(cinfo, JERR_TGA_BADPARMS);\n    TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);\n    break;\n  case 2:\t\t\t/* RGB image */\n    switch (source->pixel_size) {\n    case 2:\n      source->get_pixel_rows = get_16bit_row;\n      break;\n    case 3:\n      source->get_pixel_rows = get_24bit_row;\n      break;\n    case 4:\n      source->get_pixel_rows = get_32bit_row;\n      break;\n    default:\n      ERREXIT(cinfo, JERR_TGA_BADPARMS);\n    }\n    TRACEMS2(cinfo, 1, JTRC_TGA, width, height);\n    break;\n  case 3:\t\t\t/* Grayscale image */\n    components = 1;\n    cinfo->in_color_space = JCS_GRAYSCALE;\n    if (source->pixel_size == 1)\n      source->get_pixel_rows = get_8bit_gray_row;\n    else\n      ERREXIT(cinfo, JERR_TGA_BADPARMS);\n    TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_TGA_BADPARMS);\n  }\n\n  if (is_bottom_up) {\n    /* Create a virtual array to buffer the upside-down image. */\n    source->whole_image = (*cinfo->mem->request_virt_sarray)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n       (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);\n    if (cinfo->progress != NULL) {\n      cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n      progress->total_extra_passes++; /* count file input as separate pass */\n    }\n    /* source->pub.buffer will point to the virtual array. */\n    source->pub.buffer_height = 1; /* in case anyone looks at it */\n    source->pub.get_pixel_rows = preload_image;\n  } else {\n    /* Don't need a virtual array, but do need a one-row input buffer. */\n    source->whole_image = NULL;\n    source->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n      JPOOL_IMAGE, (JDIMENSION) width * components, (JDIMENSION) 1);\n    source->pub.buffer_height = 1;\n    source->pub.get_pixel_rows = source->get_pixel_rows;\n  }\n\n  while (idlen--)\t\t/* Throw away ID field */\n    (void) read_byte(source);\n\n  if (maplen > 0) {\n    if (maplen > 256 || GET_2B(3) != 0)\n      ERREXIT(cinfo, JERR_TGA_BADCMAP);\n    /* Allocate space to store the colormap */\n    source->colormap = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n      JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);\n    source->cmap_length = (int) maplen;\n    /* and read it from the file */\n    read_colormap(source, (int) maplen, UCH(targaheader[7]));\n  } else {\n    if (cmaptype)\t\t/* but you promised a cmap! */\n      ERREXIT(cinfo, JERR_TGA_BADPARMS);\n    source->colormap = NULL;\n    source->cmap_length = 0;\n  }\n\n  cinfo->input_components = components;\n  cinfo->data_precision = 8;\n  cinfo->image_width = width;\n  cinfo->image_height = height;\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)\n{\n  /* no work */\n}\n\n\n/*\n * The module selection routine for Targa format input.\n */\n\nGLOBAL(cjpeg_source_ptr)\njinit_read_targa (j_compress_ptr cinfo)\n{\n  tga_source_ptr source;\n\n  /* Create module interface object */\n  source = (tga_source_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_source_struct));\n  source->cinfo = cinfo;\t/* make back link for subroutines */\n  /* Fill in method ptrs, except get_pixel_rows which start_input sets */\n  source->pub.start_input = start_input_tga;\n  source->pub.finish_input = finish_input_tga;\n\n  return &source->pub;\n}\n\n#endif /* TARGA_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/transupp.c",
    "content": "/*\n * transupp.c\n *\n * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains image transformation routines and other utility code\n * used by the jpegtran sample application.  These are NOT part of the core\n * JPEG library.  But we keep these routines separate from jpegtran.c to\n * ease the task of maintaining jpegtran-like programs that have other user\n * interfaces.\n */\n\n/* Although this file really shouldn't have access to the library internals,\n * it's helpful to let it call jround_up() and jcopy_block_row().\n * Also, the (switchable) virtual memory adaptation code for\n * the drop feature has dependencies on library internals.\n */\n#define JPEG_INTERNALS\n\n#include \"jinclude.h\"\n#include \"jpeglib.h\"\n#include \"transupp.h\"\t\t/* My own external interface */\n#include <ctype.h>\t\t/* to declare isdigit() */\n\n\n#if TRANSFORMS_SUPPORTED\n\n/*\n * Lossless image transformation routines.  These routines work on DCT\n * coefficient arrays and thus do not require any lossy decompression\n * or recompression of the image.\n * Thanks to Guido Vollbeding for the initial design and code of this feature,\n * and to Ben Jackson for introducing the cropping feature.\n *\n * Horizontal flipping is done in-place, using a single top-to-bottom\n * pass through the virtual source array.  It will thus be much the\n * fastest option for images larger than main memory.\n *\n * The other routines require a set of destination virtual arrays, so they\n * need twice as much memory as jpegtran normally does.  The destination\n * arrays are always written in normal scan order (top to bottom) because\n * the virtual array manager expects this.  The source arrays will be scanned\n * in the corresponding order, which means multiple passes through the source\n * arrays for most of the transforms.  That could result in much thrashing\n * if the image is larger than main memory.\n *\n * If cropping or trimming is involved, the destination arrays may be smaller\n * than the source arrays.  Note it is not possible to do horizontal flip\n * in-place when a nonzero Y crop offset is specified, since we'd have to move\n * data from one block row to another but the virtual array manager doesn't\n * guarantee we can touch more than one row at a time.  So in that case,\n * we have to use a separate destination array.\n *\n * Some notes about the operating environment of the individual transform\n * routines:\n * 1. Both the source and destination virtual arrays are allocated from the\n *    source JPEG object, and therefore should be manipulated by calling the\n *    source's memory manager.\n * 2. The destination's component count should be used.  It may be smaller\n *    than the source's when forcing to grayscale.\n * 3. Likewise the destination's sampling factors should be used.  When\n *    forcing to grayscale the destination's sampling factors will be all 1,\n *    and we may as well take that as the effective iMCU size.\n * 4. When \"trim\" is in effect, the destination's dimensions will be the\n *    trimmed values but the source's will be untrimmed.\n * 5. When \"crop\" is in effect, the destination's dimensions will be the\n *    cropped values but the source's will be uncropped.  Each transform\n *    routine is responsible for picking up source data starting at the\n *    correct X and Y offset for the crop region.  (The X and Y offsets\n *    passed to the transform routines are measured in iMCU blocks of the\n *    destination.)\n * 6. All the routines assume that the source and destination buffers are\n *    padded out to a full iMCU boundary.  This is true, although for the\n *    source buffer it is an undocumented property of jdcoefct.c.\n */\n\n\n/* Drop code may be used with or without virtual memory adaptation code.\n * This code has some dependencies on internal library behavior, so you\n * may choose to disable it.  For example, it doesn't make a difference\n * if you only use jmemnobs anyway.\n */\n#ifndef DROP_REQUEST_FROM_SRC\n#define DROP_REQUEST_FROM_SRC 1\t\t/* 0 disables adaptation */\n#endif\n\n\n#if DROP_REQUEST_FROM_SRC\n/* Force jpeg_read_coefficients to request\n * the virtual coefficient arrays from\n * the source decompression object.\n */\nMETHODDEF(jvirt_barray_ptr)\ndrop_request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,\n\t\t\t  JDIMENSION blocksperrow, JDIMENSION numrows,\n\t\t\t  JDIMENSION maxaccess)\n{\n  j_common_ptr srcinfo = (j_common_ptr) cinfo->client_data;\n\n  return (*srcinfo->mem->request_virt_barray)\n\t  (srcinfo, pool_id, pre_zero,\n\t   blocksperrow, numrows, maxaccess);\n}\n\n\n/* Force jpeg_read_coefficients to return\n * after requesting and before accessing\n * the virtual coefficient arrays.\n */\nMETHODDEF(int)\ndrop_consume_input (j_decompress_ptr cinfo)\n{\n  return JPEG_SUSPENDED;\n}\n\n\nMETHODDEF(void)\ndrop_start_input_pass (j_decompress_ptr cinfo)\n{\n  cinfo->inputctl->consume_input = drop_consume_input;\n}\n\n\nLOCAL(void)\ndrop_request_from_src (j_decompress_ptr dropinfo, j_decompress_ptr srcinfo)\n{\n  void *save_client_data;\n  JMETHOD(jvirt_barray_ptr, save_request_virt_barray,\n\t  (j_common_ptr cinfo, int pool_id, boolean pre_zero,\n\t   JDIMENSION blocksperrow, JDIMENSION numrows, JDIMENSION maxaccess));\n  JMETHOD(void, save_start_input_pass, (j_decompress_ptr cinfo));\n\n  /* Set custom method pointers, save original pointers */\n  save_client_data = dropinfo->client_data;\n  dropinfo->client_data = (void *) srcinfo;\n  save_request_virt_barray = dropinfo->mem->request_virt_barray;\n  dropinfo->mem->request_virt_barray = drop_request_virt_barray;\n  save_start_input_pass = dropinfo->inputctl->start_input_pass;\n  dropinfo->inputctl->start_input_pass = drop_start_input_pass;\n\n  /* Execute only initialization part.\n   * Requested coefficient arrays will be realized later by the srcinfo object.\n   * Next call to the same function will then do the actual data reading.\n   * NB: since we request the coefficient arrays from another object,\n   * the inherent realization call is effectively a no-op.\n   */\n  (void) jpeg_read_coefficients(dropinfo);\n\n  /* Reset method pointers */\n  dropinfo->client_data = save_client_data;\n  dropinfo->mem->request_virt_barray = save_request_virt_barray;\n  dropinfo->inputctl->start_input_pass = save_start_input_pass;\n  /* Do input initialization for first scan now,\n   * which also resets the consume_input method.\n   */\n  (*save_start_input_pass)(dropinfo);\n}\n#endif /* DROP_REQUEST_FROM_SRC */\n\n\nLOCAL(void)\ndequant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr,\n\t      jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)\n{\n  JDIMENSION blk_x, blk_y;\n  int offset_y, k;\n  JQUANT_TBL *qtblptr;\n  JBLOCKARRAY buffer;\n  JBLOCKROW block;\n  JCOEFPTR ptr;\n\n  qtblptr = compptr->quant_table;\n  for (blk_y = 0; blk_y < compptr->height_in_blocks;\n       blk_y += compptr->v_samp_factor) {\n    buffer = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef_array, blk_y,\n       (JDIMENSION) compptr->v_samp_factor, TRUE);\n    for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n      block = buffer[offset_y];\n      for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {\n\tptr = block[blk_x];\n\tfor (k = 0; k < DCTSIZE2; k++)\n\t  if (qtblptr->quantval[k] != qtblptr1->quantval[k])\n\t    ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k];\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\nrequant_comp (j_decompress_ptr cinfo, jpeg_component_info *compptr,\n\t      jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)\n{\n  JDIMENSION blk_x, blk_y;\n  int offset_y, k;\n  JQUANT_TBL *qtblptr;\n  JBLOCKARRAY buffer;\n  JBLOCKROW block;\n  JCOEFPTR ptr;\n  JCOEF temp, qval;\n\n  qtblptr = compptr->quant_table;\n  for (blk_y = 0; blk_y < compptr->height_in_blocks;\n       blk_y += compptr->v_samp_factor) {\n    buffer = (*cinfo->mem->access_virt_barray)\n      ((j_common_ptr) cinfo, coef_array, blk_y,\n       (JDIMENSION) compptr->v_samp_factor, TRUE);\n    for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n      block = buffer[offset_y];\n      for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {\n\tptr = block[blk_x];\n\tfor (k = 0; k < DCTSIZE2; k++) {\n\t  temp = qtblptr->quantval[k];\n\t  qval = qtblptr1->quantval[k];\n\t  if (temp != qval) {\n\t    temp *= ptr[k];\n\t    /* The following quantization code is a copy from jcdctmgr.c */\n#ifdef FAST_DIVIDE\n#define DIVIDE_BY(a,b)\ta /= b\n#else\n#define DIVIDE_BY(a,b)\tif (a >= b) a /= b; else a = 0\n#endif\n\t    if (temp < 0) {\n\t      temp = -temp;\n\t      temp += qval>>1;\t/* for rounding */\n\t      DIVIDE_BY(temp, qval);\n\t      temp = -temp;\n\t    } else {\n\t      temp += qval>>1;\t/* for rounding */\n\t      DIVIDE_BY(temp, qval);\n\t    }\n\t    ptr[k] = temp;\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\n/* Calculate largest common denominator with Euclid's algorithm.\n */\nLOCAL(JCOEF)\nlargest_common_denominator(JCOEF a, JCOEF b)\n{\n  JCOEF c;\n\n  do {\n    c = a % b;\n    a = b;\n    b = c;\n  } while (c);\n\n  return a;\n}\n\n\nLOCAL(void)\nadjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays,\n\t     j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,\n\t     boolean trim, j_compress_ptr dstinfo)\n{\n  jpeg_component_info *compptr1, *compptr2;\n  JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3;\n  int ci, k;\n\n  for (ci = 0; ci < dstinfo->num_components &&\n\t       ci < dropinfo->num_components; ci++) {\n    compptr1 = srcinfo->comp_info + ci;\n    compptr2 = dropinfo->comp_info + ci;\n    qtblptr1 = compptr1->quant_table;\n    qtblptr2 = compptr2->quant_table;\n    for (k = 0; k < DCTSIZE2; k++) {\n      if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {\n\tif (trim)\n\t  requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1);\n\telse {\n\t  qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no];\n\t  for (k = 0; k < DCTSIZE2; k++)\n\t    if (qtblptr1->quantval[k] != qtblptr2->quantval[k])\n\t      qtblptr3->quantval[k] = largest_common_denominator\n\t\t(qtblptr1->quantval[k], qtblptr2->quantval[k]);\n\t  dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3);\n\t  dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3);\n\t}\n\tbreak;\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_drop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t jvirt_barray_ptr *src_coef_arrays,\n\t j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,\n\t JDIMENSION drop_width, JDIMENSION drop_height)\n/* Drop.  If the dropinfo component number is smaller than the destination's,\n * we fill in the remaining components with zero.  This provides the feature\n * of dropping grayscale into (arbitrarily sampled) color images.\n */\n{\n  JDIMENSION comp_width, comp_height;\n  JDIMENSION blk_y, x_drop_blocks, y_drop_blocks;\n  int ci, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  jpeg_component_info *compptr;\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = drop_width * compptr->h_samp_factor;\n    comp_height = drop_height * compptr->v_samp_factor;\n    x_drop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_drop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (ci < dropinfo->num_components) {\n#if DROP_REQUEST_FROM_SRC\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, drop_coef_arrays[ci], blk_y,\n#else\n\tsrc_buffer = (*dropinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) dropinfo, drop_coef_arrays[ci], blk_y,\n#endif\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n\tfor (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t  jcopy_block_row(src_buffer[offset_y],\n\t\t\t  dst_buffer[offset_y] + x_drop_blocks,\n\t\t\t  comp_width);\n\t}\n      } else {\n\tfor (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t  FMEMZERO(dst_buffer[offset_y] + x_drop_blocks,\n\t\t   comp_width * SIZEOF(JBLOCK));\n\t} \t\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t jvirt_barray_ptr *src_coef_arrays,\n\t jvirt_barray_ptr *dst_coef_arrays)\n/* Crop.  This is only used when no rotate/flip is requested with the crop. */\n{\n  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;\n  int ci, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  jpeg_component_info *compptr;\n\n  /* We simply have to copy the right amount of data (the destination's\n   * image size) starting at the given X and Y offsets in the source.\n   */\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      src_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t dst_blk_y + y_crop_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, FALSE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tjcopy_block_row(src_buffer[offset_y] + x_crop_blocks,\n\t\t\tdst_buffer[offset_y],\n\t\t\tcompptr->width_in_blocks);\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_crop_ext_zero (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t\t  JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t\t  jvirt_barray_ptr *src_coef_arrays,\n\t\t  jvirt_barray_ptr *dst_coef_arrays)\n/* Crop.  This is only used when no rotate/flip is requested with the crop.\n * Extension: If the destination size is larger than the source, we fill in\n * the extra area with zero (neutral gray).  Note we also have to zero partial\n * iMCUs at the right and bottom edge of the source image area in this case.\n */\n{\n  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;\n  JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;\n  int ci, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  jpeg_component_info *compptr;\n\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n  MCU_rows = srcinfo->output_height /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (dstinfo->jpeg_height > srcinfo->output_height) {\n\tif (dst_blk_y < y_crop_blocks ||\n\t    dst_blk_y >= y_crop_blocks + comp_height) {\n\t  for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t    FMEMZERO(dst_buffer[offset_y],\n\t\t     compptr->width_in_blocks * SIZEOF(JBLOCK));\n\t  }\n\t  continue;\n\t}\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y - y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      } else {\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y + y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      }\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tif (dstinfo->jpeg_width > srcinfo->output_width) {\n\t  if (x_crop_blocks > 0) {\n\t    FMEMZERO(dst_buffer[offset_y],\n\t\t     x_crop_blocks * SIZEOF(JBLOCK));\n\t  }\n\t  jcopy_block_row(src_buffer[offset_y],\n\t\t\t  dst_buffer[offset_y] + x_crop_blocks,\n\t\t\t  comp_width);\n\t  if (compptr->width_in_blocks > x_crop_blocks + comp_width) {\n\t    FMEMZERO(dst_buffer[offset_y] +\n\t\t       x_crop_blocks + comp_width,\n\t\t     (compptr->width_in_blocks -\n\t\t       x_crop_blocks - comp_width) * SIZEOF(JBLOCK));\n\t  }\n\t} else {\n\t  jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,\n\t\t\t  dst_buffer[offset_y],\n\t\t\t  compptr->width_in_blocks);\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_crop_ext_flat (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t\t  JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t\t  jvirt_barray_ptr *src_coef_arrays,\n\t\t  jvirt_barray_ptr *dst_coef_arrays)\n/* Crop.  This is only used when no rotate/flip is requested with the crop.\n * Extension: The destination width is larger than the source and we fill in\n * the extra area with the DC of the adjacent block.  Note we also have to\n * fill partial iMCUs at the right and bottom edge of the source image area\n * in this case.\n */\n{\n  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;\n  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;\n  int ci, offset_y;\n  JCOEF dc;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  jpeg_component_info *compptr;\n\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n  MCU_rows = srcinfo->output_height /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (dstinfo->jpeg_height > srcinfo->output_height) {\n\tif (dst_blk_y < y_crop_blocks ||\n\t    dst_blk_y >= y_crop_blocks + comp_height) {\n\t  for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t    FMEMZERO(dst_buffer[offset_y],\n\t\t     compptr->width_in_blocks * SIZEOF(JBLOCK));\n\t  }\n\t  continue;\n\t}\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y - y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      } else {\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y + y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      }\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tif (x_crop_blocks > 0) {\n\t  FMEMZERO(dst_buffer[offset_y],\n\t\t   x_crop_blocks * SIZEOF(JBLOCK));\n\t  dc = src_buffer[offset_y][0][0];\n\t  for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {\n\t    dst_buffer[offset_y][dst_blk_x][0] = dc;\n\t  }\n\t}\n\tjcopy_block_row(src_buffer[offset_y],\n\t\t\tdst_buffer[offset_y] + x_crop_blocks,\n\t\t\tcomp_width);\n\tif (compptr->width_in_blocks > x_crop_blocks + comp_width) {\n\t  FMEMZERO(dst_buffer[offset_y] +\n\t\t     x_crop_blocks + comp_width,\n\t\t   (compptr->width_in_blocks -\n\t\t     x_crop_blocks - comp_width) * SIZEOF(JBLOCK));\n\t  dc = src_buffer[offset_y][comp_width - 1][0];\n\t  for (dst_blk_x = x_crop_blocks + comp_width;\n\t       dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {\n\t    dst_buffer[offset_y][dst_blk_x][0] = dc;\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_crop_ext_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t\t     JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t\t     jvirt_barray_ptr *src_coef_arrays,\n\t\t     jvirt_barray_ptr *dst_coef_arrays)\n/* Crop.  This is only used when no rotate/flip is requested with the crop.\n * Extension: The destination width is larger than the source and we fill in\n * the extra area with repeated reflections of the source region.  Note we\n * also have to fill partial iMCUs at the right and bottom edge of the source\n * image area in this case.\n */\n{\n  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x;\n  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;\n  int ci, k, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JBLOCKROW src_row_ptr, dst_row_ptr;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n  MCU_rows = srcinfo->output_height /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (dstinfo->jpeg_height > srcinfo->output_height) {\n\tif (dst_blk_y < y_crop_blocks ||\n\t    dst_blk_y >= y_crop_blocks + comp_height) {\n\t  for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t    FMEMZERO(dst_buffer[offset_y],\n\t\t     compptr->width_in_blocks * SIZEOF(JBLOCK));\n\t  }\n\t  continue;\n\t}\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y - y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      } else {\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y + y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      }\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t/* Copy source region */\n\tjcopy_block_row(src_buffer[offset_y],\n\t\t\tdst_buffer[offset_y] + x_crop_blocks,\n\t\t\tcomp_width);\n\tif (x_crop_blocks > 0) {\n\t  /* Reflect to left */\n\t  dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks;\n\t  for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) {\n\t    src_row_ptr = dst_row_ptr;\t   /* (re)set axis of reflection */\n\t    for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;\n\t\t src_blk_x--, dst_blk_x--) {\n\t      dst_ptr = *--dst_row_ptr;\t   /* destination goes left */\n\t      src_ptr = *src_row_ptr++;\t   /* source goes right */\n\t      /* this unrolled loop doesn't need to know which row it's on... */\n\t      for (k = 0; k < DCTSIZE2; k += 2) {\n\t\t*dst_ptr++ = *src_ptr++;   /* copy even column */\n\t\t*dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */\n\t      }\n\t    }\n\t  }\n\t}\n\tif (compptr->width_in_blocks > x_crop_blocks + comp_width) {\n\t  /* Reflect to right */\n\t  dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width;\n\t  for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width;\n\t       dst_blk_x > 0;) {\n\t    src_row_ptr = dst_row_ptr;\t   /* (re)set axis of reflection */\n\t    for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;\n\t\t src_blk_x--, dst_blk_x--) {\n\t      dst_ptr = *dst_row_ptr++;\t   /* destination goes right */\n\t      src_ptr = *--src_row_ptr;\t   /* source goes left */\n\t      /* this unrolled loop doesn't need to know which row it's on... */\n\t      for (k = 0; k < DCTSIZE2; k += 2) {\n\t\t*dst_ptr++ = *src_ptr++;   /* copy even column */\n\t\t*dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */\n\t      }\n\t    }\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_wipe (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t jvirt_barray_ptr *src_coef_arrays,\n\t JDIMENSION drop_width, JDIMENSION drop_height)\n/* Wipe - drop content of specified area, fill with zero (neutral gray) */\n{\n  JDIMENSION x_wipe_blocks, wipe_width;\n  JDIMENSION y_wipe_blocks, wipe_bottom;\n  int ci, offset_y;\n  JBLOCKARRAY buffer;\n  jpeg_component_info *compptr;\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;\n    wipe_width = drop_width * compptr->h_samp_factor;\n    y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;\n    wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;\n    for (; y_wipe_blocks < wipe_bottom;\n\t y_wipe_blocks += compptr->v_samp_factor) {\n      buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tFMEMZERO(buffer[offset_y] + x_wipe_blocks,\n\t\t wipe_width * SIZEOF(JBLOCK));\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_flatten (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t    jvirt_barray_ptr *src_coef_arrays,\n\t    JDIMENSION drop_width, JDIMENSION drop_height)\n/* Flatten - drop content of specified area, similar to wipe,\n * but fill with average of adjacent blocks, instead of zero.\n */\n{\n  JDIMENSION x_wipe_blocks, wipe_width, wipe_right;\n  JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;\n  int ci, offset_y, dc_left_value, dc_right_value, average;\n  JBLOCKARRAY buffer;\n  jpeg_component_info *compptr;\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;\n    wipe_width = drop_width * compptr->h_samp_factor;\n    wipe_right = wipe_width + x_wipe_blocks;\n    y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;\n    wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;\n    for (; y_wipe_blocks < wipe_bottom;\n\t y_wipe_blocks += compptr->v_samp_factor) {\n      buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tFMEMZERO(buffer[offset_y] + x_wipe_blocks,\n\t\t wipe_width * SIZEOF(JBLOCK));\n\tif (x_wipe_blocks > 0) {\n\t  dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];\n\t  if (wipe_right < compptr->width_in_blocks) {\n\t    dc_right_value = buffer[offset_y][wipe_right][0];\n\t    average = (dc_left_value + dc_right_value) >> 1;\n\t  } else {\n\t    average = dc_left_value;\n\t  }\n\t} else if (wipe_right < compptr->width_in_blocks) {\n\t  average = buffer[offset_y][wipe_right][0];\n\t} else continue;\n\tfor (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {\n\t  buffer[offset_y][blk_x][0] = (JCOEF) average;\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_reflect (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t    JDIMENSION x_crop_offset,\n\t    jvirt_barray_ptr *src_coef_arrays,\n\t    JDIMENSION drop_width, JDIMENSION drop_height)\n/* Reflect - drop content of specified area, similar to wipe, but\n * fill with repeated reflections of the outside area, instead of zero.\n * NB: y_crop_offset is assumed to be zero.\n */\n{\n  JDIMENSION x_wipe_blocks, wipe_width;\n  JDIMENSION y_wipe_blocks, wipe_bottom;\n  JDIMENSION src_blk_x, dst_blk_x;\n  int ci, k, offset_y;\n  JBLOCKARRAY buffer;\n  JBLOCKROW src_row_ptr, dst_row_ptr;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;\n    wipe_width = drop_width * compptr->h_samp_factor;\n    wipe_bottom = drop_height * compptr->v_samp_factor;\n    for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;\n\t y_wipe_blocks += compptr->v_samp_factor) {\n      buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci], y_wipe_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tif (x_wipe_blocks > 0) {\n\t  /* Reflect from left */\n\t  dst_row_ptr = buffer[offset_y] + x_wipe_blocks;\n\t  for (dst_blk_x = wipe_width; dst_blk_x > 0;) {\n\t    src_row_ptr = dst_row_ptr;\t   /* (re)set axis of reflection */\n\t    for (src_blk_x = x_wipe_blocks;\n\t\t src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {\n\t      dst_ptr = *dst_row_ptr++;\t   /* destination goes right */\n\t      src_ptr = *--src_row_ptr;\t   /* source goes left */\n\t      /* this unrolled loop doesn't need to know which row it's on... */\n\t      for (k = 0; k < DCTSIZE2; k += 2) {\n\t\t*dst_ptr++ = *src_ptr++;   /* copy even column */\n\t\t*dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */\n\t      }\n\t    }\n\t  }\n\t} else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {\n\t  /* Reflect from right */\n\t  dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;\n\t  for (dst_blk_x = wipe_width; dst_blk_x > 0;) {\n\t    src_row_ptr = dst_row_ptr;\t   /* (re)set axis of reflection */\n\t    src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;\n\t    for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {\n\t      dst_ptr = *--dst_row_ptr;\t   /* destination goes left */\n\t      src_ptr = *src_row_ptr++;\t   /* source goes right */\n\t      /* this unrolled loop doesn't need to know which row it's on... */\n\t      for (k = 0; k < DCTSIZE2; k += 2) {\n\t\t*dst_ptr++ = *src_ptr++;   /* copy even column */\n\t\t*dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */\n\t      }\n\t    }\n\t  }\n\t} else {\n\t  FMEMZERO(buffer[offset_y] + x_wipe_blocks,\n\t\t   wipe_width * SIZEOF(JBLOCK));\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t\t   JDIMENSION x_crop_offset,\n\t\t   jvirt_barray_ptr *src_coef_arrays)\n/* Horizontal flip; done in-place, so no separate dest array is required.\n * NB: this only works when y_crop_offset is zero.\n */\n{\n  JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;\n  int ci, k, offset_y;\n  JBLOCKARRAY buffer;\n  JCOEFPTR ptr1, ptr2;\n  JCOEF temp1, temp2;\n  jpeg_component_info *compptr;\n\n  /* Horizontal mirroring of DCT blocks is accomplished by swapping\n   * pairs of blocks in-place.  Within a DCT block, we perform horizontal\n   * mirroring by changing the signs of odd-numbered columns.\n   * Partial iMCUs at the right edge are left untouched.\n   */\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    for (blk_y = 0; blk_y < compptr->height_in_blocks;\n\t blk_y += compptr->v_samp_factor) {\n      buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\t/* Do the mirroring */\n\tfor (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {\n\t  ptr1 = buffer[offset_y][blk_x];\n\t  ptr2 = buffer[offset_y][comp_width - blk_x - 1];\n\t  /* this unrolled loop doesn't need to know which row it's on... */\n\t  for (k = 0; k < DCTSIZE2; k += 2) {\n\t    temp1 = *ptr1;\t/* swap even column */\n\t    temp2 = *ptr2;\n\t    *ptr1++ = temp2;\n\t    *ptr2++ = temp1;\n\t    temp1 = *ptr1;\t/* swap odd column with sign change */\n\t    temp2 = *ptr2;\n\t    *ptr1++ = -temp2;\n\t    *ptr2++ = -temp1;\n\t  }\n\t}\n\tif (x_crop_blocks > 0) {\n\t  /* Now left-justify the portion of the data to be kept.\n\t   * We can't use a single jcopy_block_row() call because that routine\n\t   * depends on memcpy(), whose behavior is unspecified for overlapping\n\t   * source and destination areas.  Sigh.\n\t   */\n\t  for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {\n\t    jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,\n\t\t\t    buffer[offset_y] + blk_x,\n\t\t\t    (JDIMENSION) 1);\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t   jvirt_barray_ptr *src_coef_arrays,\n\t   jvirt_barray_ptr *dst_coef_arrays)\n/* Horizontal flip in general cropping case */\n{\n  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, k, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JBLOCKROW src_row_ptr, dst_row_ptr;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  /* Here we must output into a separate array because we can't touch\n   * different rows of a single virtual array simultaneously.  Otherwise,\n   * this is essentially the same as the routine above.\n   */\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      src_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t dst_blk_y + y_crop_blocks,\n\t (JDIMENSION) compptr->v_samp_factor, FALSE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tdst_row_ptr = dst_buffer[offset_y];\n\tsrc_row_ptr = src_buffer[offset_y];\n\tfor (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {\n\t  if (x_crop_blocks + dst_blk_x < comp_width) {\n\t    /* Do the mirrorable blocks */\n\t    dst_ptr = dst_row_ptr[dst_blk_x];\n\t    src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];\n\t    /* this unrolled loop doesn't need to know which row it's on... */\n\t    for (k = 0; k < DCTSIZE2; k += 2) {\n\t      *dst_ptr++ = *src_ptr++;\t /* copy even column */\n\t      *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */\n\t    }\n\t  } else {\n\t    /* Copy last partial block(s) verbatim */\n\t    jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,\n\t\t\t    dst_row_ptr + dst_blk_x,\n\t\t\t    (JDIMENSION) 1);\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t   jvirt_barray_ptr *src_coef_arrays,\n\t   jvirt_barray_ptr *dst_coef_arrays)\n/* Vertical flip */\n{\n  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JBLOCKROW src_row_ptr, dst_row_ptr;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  /* We output into a separate array because we can't touch different\n   * rows of the source virtual array simultaneously.  Otherwise, this\n   * is a pretty straightforward analog of horizontal flip.\n   * Within a DCT block, vertical mirroring is done by changing the signs\n   * of odd-numbered rows.\n   * Partial iMCUs at the bottom edge are copied verbatim.\n   */\n  MCU_rows = srcinfo->output_height /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (y_crop_blocks + dst_blk_y < comp_height) {\n\t/* Row is within the mirrorable area. */\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   comp_height - y_crop_blocks - dst_blk_y -\n\t   (JDIMENSION) compptr->v_samp_factor,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      } else {\n\t/* Bottom-edge blocks will be copied verbatim. */\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y + y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      }\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tif (y_crop_blocks + dst_blk_y < comp_height) {\n\t  /* Row is within the mirrorable area. */\n\t  dst_row_ptr = dst_buffer[offset_y];\n\t  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];\n\t  src_row_ptr += x_crop_blocks;\n\t  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;\n\t       dst_blk_x++) {\n\t    dst_ptr = dst_row_ptr[dst_blk_x];\n\t    src_ptr = src_row_ptr[dst_blk_x];\n\t    for (i = 0; i < DCTSIZE; i += 2) {\n\t      /* copy even row */\n\t      for (j = 0; j < DCTSIZE; j++)\n\t\t*dst_ptr++ = *src_ptr++;\n\t      /* copy odd row with sign change */\n\t      for (j = 0; j < DCTSIZE; j++)\n\t\t*dst_ptr++ = - *src_ptr++;\n\t    }\n\t  }\n\t} else {\n\t  /* Just copy row verbatim. */\n\t  jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,\n\t\t\t  dst_buffer[offset_y],\n\t\t\t  compptr->width_in_blocks);\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t      JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t      jvirt_barray_ptr *src_coef_arrays,\n\t      jvirt_barray_ptr *dst_coef_arrays)\n/* Transpose source into destination */\n{\n  JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_x, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  /* Transposing pixels within a block just requires transposing the\n   * DCT coefficients.\n   * Partial iMCUs at the edges require no special treatment; we simply\n   * process all the available DCT blocks for every component.\n   */\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tfor (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;\n\t     dst_blk_x += compptr->h_samp_factor) {\n\t  src_buffer = (*srcinfo->mem->access_virt_barray)\n\t    ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t     dst_blk_x + x_crop_blocks,\n\t     (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {\n\t    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];\n\t    src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];\n\t    for (i = 0; i < DCTSIZE; i++)\n\t      for (j = 0; j < DCTSIZE; j++)\n\t\tdst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t   JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t   jvirt_barray_ptr *src_coef_arrays,\n\t   jvirt_barray_ptr *dst_coef_arrays)\n/* 90 degree rotation is equivalent to\n *   1. Transposing the image;\n *   2. Horizontal mirroring.\n * These two steps are merged into a single processing routine.\n */\n{\n  JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_x, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  /* Because of the horizontal mirror step, we can't process partial iMCUs\n   * at the (output) right edge properly.  They just get transposed and\n   * not mirrored.\n   */\n  MCU_cols = srcinfo->output_height /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tfor (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;\n\t     dst_blk_x += compptr->h_samp_factor) {\n\t  if (x_crop_blocks + dst_blk_x < comp_width) {\n\t    /* Block is within the mirrorable area. */\n\t    src_buffer = (*srcinfo->mem->access_virt_barray)\n\t      ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t       comp_width - x_crop_blocks - dst_blk_x -\n\t       (JDIMENSION) compptr->h_samp_factor,\n\t       (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  } else {\n\t    /* Edge blocks are transposed but not mirrored. */\n\t    src_buffer = (*srcinfo->mem->access_virt_barray)\n\t      ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t       dst_blk_x + x_crop_blocks,\n\t       (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  }\n\t  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {\n\t    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];\n\t    if (x_crop_blocks + dst_blk_x < comp_width) {\n\t      /* Block is within the mirrorable area. */\n\t      src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]\n\t\t[dst_blk_y + offset_y + y_crop_blocks];\n\t      for (i = 0; i < DCTSIZE; i++) {\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\ti++;\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t      }\n\t    } else {\n\t      /* Edge blocks are transposed but not mirrored. */\n\t      src_ptr = src_buffer[offset_x]\n\t\t[dst_blk_y + offset_y + y_crop_blocks];\n\t      for (i = 0; i < DCTSIZE; i++)\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t    }\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t    jvirt_barray_ptr *src_coef_arrays,\n\t    jvirt_barray_ptr *dst_coef_arrays)\n/* 270 degree rotation is equivalent to\n *   1. Horizontal mirroring;\n *   2. Transposing the image.\n * These two steps are merged into a single processing routine.\n */\n{\n  JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_x, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  /* Because of the horizontal mirror step, we can't process partial iMCUs\n   * at the (output) bottom edge properly.  They just get transposed and\n   * not mirrored.\n   */\n  MCU_rows = srcinfo->output_width /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tfor (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;\n\t     dst_blk_x += compptr->h_samp_factor) {\n\t  src_buffer = (*srcinfo->mem->access_virt_barray)\n\t    ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t     dst_blk_x + x_crop_blocks,\n\t     (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {\n\t    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];\n\t    if (y_crop_blocks + dst_blk_y < comp_height) {\n\t      /* Block is within the mirrorable area. */\n\t      src_ptr = src_buffer[offset_x]\n\t\t[comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];\n\t      for (i = 0; i < DCTSIZE; i++) {\n\t\tfor (j = 0; j < DCTSIZE; j++) {\n\t\t  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\t  j++;\n\t\t  dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t\t}\n\t      }\n\t    } else {\n\t      /* Edge blocks are transposed but not mirrored. */\n\t      src_ptr = src_buffer[offset_x]\n\t\t[dst_blk_y + offset_y + y_crop_blocks];\n\t      for (i = 0; i < DCTSIZE; i++)\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t    }\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t    JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t    jvirt_barray_ptr *src_coef_arrays,\n\t    jvirt_barray_ptr *dst_coef_arrays)\n/* 180 degree rotation is equivalent to\n *   1. Vertical mirroring;\n *   2. Horizontal mirroring.\n * These two steps are merged into a single processing routine.\n */\n{\n  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JBLOCKROW src_row_ptr, dst_row_ptr;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  MCU_cols = srcinfo->output_width /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n  MCU_rows = srcinfo->output_height /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      if (y_crop_blocks + dst_blk_y < comp_height) {\n\t/* Row is within the vertically mirrorable area. */\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   comp_height - y_crop_blocks - dst_blk_y -\n\t   (JDIMENSION) compptr->v_samp_factor,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      } else {\n\t/* Bottom-edge rows are only mirrored horizontally. */\n\tsrc_buffer = (*srcinfo->mem->access_virt_barray)\n\t  ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t   dst_blk_y + y_crop_blocks,\n\t   (JDIMENSION) compptr->v_samp_factor, FALSE);\n      }\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tdst_row_ptr = dst_buffer[offset_y];\n\tif (y_crop_blocks + dst_blk_y < comp_height) {\n\t  /* Row is within the mirrorable area. */\n\t  src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];\n\t  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {\n\t    dst_ptr = dst_row_ptr[dst_blk_x];\n\t    if (x_crop_blocks + dst_blk_x < comp_width) {\n\t      /* Process the blocks that can be mirrored both ways. */\n\t      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];\n\t      for (i = 0; i < DCTSIZE; i += 2) {\n\t\t/* For even row, negate every odd column. */\n\t\tfor (j = 0; j < DCTSIZE; j += 2) {\n\t\t  *dst_ptr++ = *src_ptr++;\n\t\t  *dst_ptr++ = - *src_ptr++;\n\t\t}\n\t\t/* For odd row, negate every even column. */\n\t\tfor (j = 0; j < DCTSIZE; j += 2) {\n\t\t  *dst_ptr++ = - *src_ptr++;\n\t\t  *dst_ptr++ = *src_ptr++;\n\t\t}\n\t      }\n\t    } else {\n\t      /* Any remaining right-edge blocks are only mirrored vertically. */\n\t      src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];\n\t      for (i = 0; i < DCTSIZE; i += 2) {\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  *dst_ptr++ = *src_ptr++;\n\t\tfor (j = 0; j < DCTSIZE; j++)\n\t\t  *dst_ptr++ = - *src_ptr++;\n\t      }\n\t    }\n\t  }\n\t} else {\n\t  /* Remaining rows are just mirrored horizontally. */\n\t  src_row_ptr = src_buffer[offset_y];\n\t  for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {\n\t    if (x_crop_blocks + dst_blk_x < comp_width) {\n\t      /* Process the blocks that can be mirrored. */\n\t      dst_ptr = dst_row_ptr[dst_blk_x];\n\t      src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];\n\t      for (i = 0; i < DCTSIZE2; i += 2) {\n\t\t*dst_ptr++ = *src_ptr++;\n\t\t*dst_ptr++ = - *src_ptr++;\n\t      }\n\t    } else {\n\t      /* Any remaining right-edge blocks are only copied. */\n\t      jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,\n\t\t\t      dst_row_ptr + dst_blk_x,\n\t\t\t      (JDIMENSION) 1);\n\t    }\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\nLOCAL(void)\ndo_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t       JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,\n\t       jvirt_barray_ptr *src_coef_arrays,\n\t       jvirt_barray_ptr *dst_coef_arrays)\n/* Transverse transpose is equivalent to\n *   1. 180 degree rotation;\n *   2. Transposition;\n * or\n *   1. Horizontal mirroring;\n *   2. Transposition;\n *   3. Horizontal mirroring.\n * These steps are merged into a single processing routine.\n */\n{\n  JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;\n  JDIMENSION x_crop_blocks, y_crop_blocks;\n  int ci, i, j, offset_x, offset_y;\n  JBLOCKARRAY src_buffer, dst_buffer;\n  JCOEFPTR src_ptr, dst_ptr;\n  jpeg_component_info *compptr;\n\n  MCU_cols = srcinfo->output_height /\n    (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);\n  MCU_rows = srcinfo->output_width /\n    (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);\n\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    comp_width = MCU_cols * compptr->h_samp_factor;\n    comp_height = MCU_rows * compptr->v_samp_factor;\n    x_crop_blocks = x_crop_offset * compptr->h_samp_factor;\n    y_crop_blocks = y_crop_offset * compptr->v_samp_factor;\n    for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;\n\t dst_blk_y += compptr->v_samp_factor) {\n      dst_buffer = (*srcinfo->mem->access_virt_barray)\n\t((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,\n\t (JDIMENSION) compptr->v_samp_factor, TRUE);\n      for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {\n\tfor (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;\n\t     dst_blk_x += compptr->h_samp_factor) {\n\t  if (x_crop_blocks + dst_blk_x < comp_width) {\n\t    /* Block is within the mirrorable area. */\n\t    src_buffer = (*srcinfo->mem->access_virt_barray)\n\t      ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t       comp_width - x_crop_blocks - dst_blk_x -\n\t       (JDIMENSION) compptr->h_samp_factor,\n\t       (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  } else {\n\t    src_buffer = (*srcinfo->mem->access_virt_barray)\n\t      ((j_common_ptr) srcinfo, src_coef_arrays[ci],\n\t       dst_blk_x + x_crop_blocks,\n\t       (JDIMENSION) compptr->h_samp_factor, FALSE);\n\t  }\n\t  for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {\n\t    dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];\n\t    if (y_crop_blocks + dst_blk_y < comp_height) {\n\t      if (x_crop_blocks + dst_blk_x < comp_width) {\n\t\t/* Block is within the mirrorable area. */\n\t\tsrc_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]\n\t\t  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];\n\t\tfor (i = 0; i < DCTSIZE; i++) {\n\t\t  for (j = 0; j < DCTSIZE; j++) {\n\t\t    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\t    j++;\n\t\t    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t\t  }\n\t\t  i++;\n\t\t  for (j = 0; j < DCTSIZE; j++) {\n\t\t    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t\t    j++;\n\t\t    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\t  }\n\t\t}\n\t      } else {\n\t\t/* Right-edge blocks are mirrored in y only */\n\t\tsrc_ptr = src_buffer[offset_x]\n\t\t  [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];\n\t\tfor (i = 0; i < DCTSIZE; i++) {\n\t\t  for (j = 0; j < DCTSIZE; j++) {\n\t\t    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\t    j++;\n\t\t    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t\t  }\n\t\t}\n\t      }\n\t    } else {\n\t      if (x_crop_blocks + dst_blk_x < comp_width) {\n\t\t/* Bottom-edge blocks are mirrored in x only */\n\t\tsrc_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]\n\t\t  [dst_blk_y + offset_y + y_crop_blocks];\n\t\tfor (i = 0; i < DCTSIZE; i++) {\n\t\t  for (j = 0; j < DCTSIZE; j++)\n\t\t    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t\t  i++;\n\t\t  for (j = 0; j < DCTSIZE; j++)\n\t\t    dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];\n\t\t}\n\t      } else {\n\t\t/* At lower right corner, just transpose, no mirroring */\n\t\tsrc_ptr = src_buffer[offset_x]\n\t\t  [dst_blk_y + offset_y + y_crop_blocks];\n\t\tfor (i = 0; i < DCTSIZE; i++)\n\t\t  for (j = 0; j < DCTSIZE; j++)\n\t\t    dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];\n\t      }\n\t    }\n\t  }\n\t}\n      }\n    }\n  }\n}\n\n\n/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.\n * Returns TRUE if valid integer found, FALSE if not.\n * *strptr is advanced over the digit string, and *result is set to its value.\n */\n\nLOCAL(boolean)\njt_read_integer (const char ** strptr, JDIMENSION * result)\n{\n  const char * ptr = *strptr;\n  JDIMENSION val = 0;\n\n  for (; isdigit(*ptr); ptr++) {\n    val = val * 10 + (JDIMENSION) (*ptr - '0');\n  }\n  *result = val;\n  if (ptr == *strptr)\n    return FALSE;\t\t/* oops, no digits */\n  *strptr = ptr;\n  return TRUE;\n}\n\n\n/* Parse a crop specification (written in X11 geometry style).\n * The routine returns TRUE if the spec string is valid, FALSE if not.\n *\n * The crop spec string should have the format\n *\t<width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>\n * where width, height, xoffset, and yoffset are unsigned integers.\n * Each of the elements can be omitted to indicate a default value.\n * (A weakness of this style is that it is not possible to omit xoffset\n * while specifying yoffset, since they look alike.)\n *\n * This code is loosely based on XParseGeometry from the X11 distribution.\n */\n\nGLOBAL(boolean)\njtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)\n{\n  info->crop = FALSE;\n  info->crop_width_set = JCROP_UNSET;\n  info->crop_height_set = JCROP_UNSET;\n  info->crop_xoffset_set = JCROP_UNSET;\n  info->crop_yoffset_set = JCROP_UNSET;\n\n  if (isdigit(*spec)) {\n    /* fetch width */\n    if (! jt_read_integer(&spec, &info->crop_width))\n      return FALSE;\n    if (*spec == 'f' || *spec == 'F') {\n      spec++;\n      info->crop_width_set = JCROP_FORCE;\n    } else if (*spec == 'r' || *spec == 'R') {\n      spec++;\n      info->crop_width_set = JCROP_REFLECT;\n    } else\n      info->crop_width_set = JCROP_POS;\n  }\n  if (*spec == 'x' || *spec == 'X') {\n    /* fetch height */\n    spec++;\n    if (! jt_read_integer(&spec, &info->crop_height))\n      return FALSE;\n    if (*spec == 'f' || *spec == 'F') {\n      spec++;\n      info->crop_height_set = JCROP_FORCE;\n    } else if (*spec == 'r' || *spec == 'R') {\n      spec++;\n      info->crop_height_set = JCROP_REFLECT;\n    } else\n      info->crop_height_set = JCROP_POS;\n  }\n  if (*spec == '+' || *spec == '-') {\n    /* fetch xoffset */\n    info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;\n    spec++;\n    if (! jt_read_integer(&spec, &info->crop_xoffset))\n      return FALSE;\n  }\n  if (*spec == '+' || *spec == '-') {\n    /* fetch yoffset */\n    info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;\n    spec++;\n    if (! jt_read_integer(&spec, &info->crop_yoffset))\n      return FALSE;\n  }\n  /* We had better have gotten to the end of the string. */\n  if (*spec != '\\0')\n    return FALSE;\n  info->crop = TRUE;\n  return TRUE;\n}\n\n\n/* Trim off any partial iMCUs on the indicated destination edge */\n\nLOCAL(void)\ntrim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)\n{\n  JDIMENSION MCU_cols;\n\n  MCU_cols = info->output_width / info->iMCU_sample_width;\n  if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==\n      full_width / info->iMCU_sample_width)\n    info->output_width = MCU_cols * info->iMCU_sample_width;\n}\n\nLOCAL(void)\ntrim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)\n{\n  JDIMENSION MCU_rows;\n\n  MCU_rows = info->output_height / info->iMCU_sample_height;\n  if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==\n      full_height / info->iMCU_sample_height)\n    info->output_height = MCU_rows * info->iMCU_sample_height;\n}\n\n\n/* Request any required workspace.\n *\n * This routine figures out the size that the output image will be\n * (which implies that all the transform parameters must be set before\n * it is called).\n *\n * We allocate the workspace virtual arrays from the source decompression\n * object, so that all the arrays (both the original data and the workspace)\n * will be taken into account while making memory management decisions.\n * Hence, this routine must be called after jpeg_read_header (which reads\n * the image dimensions) and before jpeg_read_coefficients (which realizes\n * the source's virtual arrays).\n *\n * This function returns FALSE right away if -perfect is given\n * and transformation is not perfect.  Otherwise returns TRUE.\n */\n\nGLOBAL(boolean)\njtransform_request_workspace (j_decompress_ptr srcinfo,\n\t\t\t      jpeg_transform_info *info)\n{\n  jvirt_barray_ptr *coef_arrays;\n  boolean need_workspace, transpose_it;\n  jpeg_component_info *compptr;\n  JDIMENSION xoffset, yoffset, dtemp;\n  JDIMENSION width_in_iMCUs, height_in_iMCUs;\n  JDIMENSION width_in_blocks, height_in_blocks;\n  int itemp, ci, h_samp_factor, v_samp_factor;\n\n  /* Determine number of components in output image */\n  if (info->force_grayscale &&\n      (srcinfo->jpeg_color_space == JCS_YCbCr ||\n       srcinfo->jpeg_color_space == JCS_BG_YCC) &&\n      srcinfo->num_components == 3)\n    /* We'll only process the first component */\n    info->num_components = 1;\n  else\n    /* Process all the components */\n    info->num_components = srcinfo->num_components;\n\n  /* Compute output image dimensions and related values. */\n  jpeg_core_output_dimensions(srcinfo);\n\n  /* Return right away if -perfect is given and transformation is not perfect.\n   */\n  if (info->perfect) {\n    if (info->num_components == 1) {\n      if (!jtransform_perfect_transform(srcinfo->output_width,\n\t  srcinfo->output_height,\n\t  srcinfo->min_DCT_h_scaled_size,\n\t  srcinfo->min_DCT_v_scaled_size,\n\t  info->transform))\n\treturn FALSE;\n    } else {\n      if (!jtransform_perfect_transform(srcinfo->output_width,\n\t  srcinfo->output_height,\n\t  srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,\n\t  srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,\n\t  info->transform))\n\treturn FALSE;\n    }\n  }\n\n  /* If there is only one output component, force the iMCU size to be 1;\n   * else use the source iMCU size.  (This allows us to do the right thing\n   * when reducing color to grayscale, and also provides a handy way of\n   * cleaning up \"funny\" grayscale images whose sampling factors are not 1x1.)\n   */\n  switch (info->transform) {\n  case JXFORM_TRANSPOSE:\n  case JXFORM_TRANSVERSE:\n  case JXFORM_ROT_90:\n  case JXFORM_ROT_270:\n    info->output_width = srcinfo->output_height;\n    info->output_height = srcinfo->output_width;\n    if (info->num_components == 1) {\n      info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;\n      info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;\n    } else {\n      info->iMCU_sample_width =\n\tsrcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;\n      info->iMCU_sample_height =\n\tsrcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;\n    }\n    break;\n  default:\n    info->output_width = srcinfo->output_width;\n    info->output_height = srcinfo->output_height;\n    if (info->num_components == 1) {\n      info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;\n      info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;\n    } else {\n      info->iMCU_sample_width =\n\tsrcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;\n      info->iMCU_sample_height =\n\tsrcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;\n    }\n  }\n\n  /* If cropping has been requested, compute the crop area's position and\n   * dimensions, ensuring that its upper left corner falls at an iMCU boundary.\n   */\n  if (info->crop) {\n    /* Insert default values for unset crop parameters */\n    if (info->crop_xoffset_set == JCROP_UNSET)\n      info->crop_xoffset = 0;\t/* default to +0 */\n    if (info->crop_yoffset_set == JCROP_UNSET)\n      info->crop_yoffset = 0;\t/* default to +0 */\n    if (info->crop_width_set == JCROP_UNSET) {\n      if (info->crop_xoffset >= info->output_width)\n\tERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      info->crop_width = info->output_width - info->crop_xoffset;\n    } else {\n      /* Check for crop extension */\n      if (info->crop_width > info->output_width) {\n\t/* Crop extension does not work when transforming! */\n\tif (info->transform != JXFORM_NONE ||\n\t    info->crop_xoffset >= info->crop_width ||\n\t    info->crop_xoffset > info->crop_width - info->output_width)\n\t  ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      } else {\n\tif (info->crop_xoffset >= info->output_width ||\n\t    info->crop_width <= 0 ||\n\t    info->crop_xoffset > info->output_width - info->crop_width)\n\t  ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      }\n    }\n    if (info->crop_height_set == JCROP_UNSET) {\n      if (info->crop_yoffset >= info->output_height)\n\tERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      info->crop_height = info->output_height - info->crop_yoffset;\n    } else {\n      /* Check for crop extension */\n      if (info->crop_height > info->output_height) {\n\t/* Crop extension does not work when transforming! */\n\tif (info->transform != JXFORM_NONE ||\n\t    info->crop_yoffset >= info->crop_height ||\n\t    info->crop_yoffset > info->crop_height - info->output_height)\n\t  ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      } else {\n\tif (info->crop_yoffset >= info->output_height ||\n\t    info->crop_height <= 0 ||\n\t    info->crop_yoffset > info->output_height - info->crop_height)\n\t  ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);\n      }\n    }\n    /* Convert negative crop offsets into regular offsets */\n    if (info->crop_xoffset_set != JCROP_NEG)\n      xoffset = info->crop_xoffset;\n    else if (info->crop_width > info->output_width) /* crop extension */\n      xoffset = info->crop_width - info->output_width - info->crop_xoffset;\n    else\n      xoffset = info->output_width - info->crop_width - info->crop_xoffset;\n    if (info->crop_yoffset_set != JCROP_NEG)\n      yoffset = info->crop_yoffset;\n    else if (info->crop_height > info->output_height) /* crop extension */\n      yoffset = info->crop_height - info->output_height - info->crop_yoffset;\n    else\n      yoffset = info->output_height - info->crop_height - info->crop_yoffset;\n    /* Now adjust so that upper left corner falls at an iMCU boundary */\n    switch (info->transform) {\n    case JXFORM_DROP:\n      /* Ensure the effective drop region will not exceed the requested */\n      itemp = info->iMCU_sample_width;\n      dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);\n      xoffset += dtemp;\n      if (info->crop_width <= dtemp)\n\tinfo->drop_width = 0;\n      else if (xoffset + info->crop_width - dtemp == info->output_width)\n\t/* Matching right edge: include partial iMCU */\n\tinfo->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;\n      else\n\tinfo->drop_width = (info->crop_width - dtemp) / itemp;\n      itemp = info->iMCU_sample_height;\n      dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);\n      yoffset += dtemp;\n      if (info->crop_height <= dtemp)\n\tinfo->drop_height = 0;\n      else if (yoffset + info->crop_height - dtemp == info->output_height)\n\t/* Matching bottom edge: include partial iMCU */\n\tinfo->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;\n      else\n\tinfo->drop_height = (info->crop_height - dtemp) / itemp;\n      /* Check if sampling factors match for dropping */\n      if (info->drop_width != 0 && info->drop_height != 0)\n\tfor (ci = 0; ci < info->num_components &&\n\t\t     ci < info->drop_ptr->num_components; ci++) {\n\t  if (info->drop_ptr->comp_info[ci].h_samp_factor *\n\t      srcinfo->max_h_samp_factor !=\n\t      srcinfo->comp_info[ci].h_samp_factor *\n\t      info->drop_ptr->max_h_samp_factor)\n\t    ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,\n\t      info->drop_ptr->comp_info[ci].h_samp_factor,\n\t      info->drop_ptr->max_h_samp_factor,\n\t      srcinfo->comp_info[ci].h_samp_factor,\n\t      srcinfo->max_h_samp_factor, 'h');\n\t  if (info->drop_ptr->comp_info[ci].v_samp_factor *\n\t      srcinfo->max_v_samp_factor !=\n\t      srcinfo->comp_info[ci].v_samp_factor *\n\t      info->drop_ptr->max_v_samp_factor)\n\t    ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,\n\t      info->drop_ptr->comp_info[ci].v_samp_factor,\n\t      info->drop_ptr->max_v_samp_factor,\n\t      srcinfo->comp_info[ci].v_samp_factor,\n\t      srcinfo->max_v_samp_factor, 'v');\n\t}\n      break;\n    case JXFORM_WIPE:\n      /* Ensure the effective wipe region will cover the requested */\n      info->drop_width = (JDIMENSION) jdiv_round_up\n\t((long) (info->crop_width + (xoffset % info->iMCU_sample_width)),\n\t (long) info->iMCU_sample_width);\n      info->drop_height = (JDIMENSION) jdiv_round_up\n\t((long) (info->crop_height + (yoffset % info->iMCU_sample_height)),\n\t (long) info->iMCU_sample_height);\n      break;\n    default:\n      /* Ensure the effective crop region will cover the requested */\n      if (info->crop_width_set == JCROP_FORCE ||\n\t  info->crop_width > info->output_width)\n\tinfo->output_width = info->crop_width;\n      else\n\tinfo->output_width =\n\t  info->crop_width + (xoffset % info->iMCU_sample_width);\n      if (info->crop_height_set == JCROP_FORCE ||\n\t  info->crop_height > info->output_height)\n\tinfo->output_height = info->crop_height;\n      else\n\tinfo->output_height =\n\t  info->crop_height + (yoffset % info->iMCU_sample_height);\n    }\n    /* Save x/y offsets measured in iMCUs */\n    info->x_crop_offset = xoffset / info->iMCU_sample_width;\n    info->y_crop_offset = yoffset / info->iMCU_sample_height;\n  } else {\n    info->x_crop_offset = 0;\n    info->y_crop_offset = 0;\n  }\n\n  /* Figure out whether we need workspace arrays,\n   * and if so whether they are transposed relative to the source.\n   */\n  need_workspace = FALSE;\n  transpose_it = FALSE;\n  switch (info->transform) {\n  case JXFORM_NONE:\n    if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||\n\tinfo->output_width > srcinfo->output_width ||\n\tinfo->output_height > srcinfo->output_height)\n      need_workspace = TRUE;\n    /* No workspace needed if neither cropping nor transforming */\n    break;\n  case JXFORM_FLIP_H:\n    if (info->trim)\n      trim_right_edge(info, srcinfo->output_width);\n    if (info->y_crop_offset != 0)\n      need_workspace = TRUE;\n    /* do_flip_h_no_crop doesn't need a workspace array */\n    break;\n  case JXFORM_FLIP_V:\n    if (info->trim)\n      trim_bottom_edge(info, srcinfo->output_height);\n    /* Need workspace arrays having same dimensions as source image. */\n    need_workspace = TRUE;\n    break;\n  case JXFORM_TRANSPOSE:\n    /* transpose does NOT have to trim anything */\n    /* Need workspace arrays having transposed dimensions. */\n    need_workspace = TRUE;\n    transpose_it = TRUE;\n    break;\n  case JXFORM_TRANSVERSE:\n    if (info->trim) {\n      trim_right_edge(info, srcinfo->output_height);\n      trim_bottom_edge(info, srcinfo->output_width);\n    }\n    /* Need workspace arrays having transposed dimensions. */\n    need_workspace = TRUE;\n    transpose_it = TRUE;\n    break;\n  case JXFORM_ROT_90:\n    if (info->trim)\n      trim_right_edge(info, srcinfo->output_height);\n    /* Need workspace arrays having transposed dimensions. */\n    need_workspace = TRUE;\n    transpose_it = TRUE;\n    break;\n  case JXFORM_ROT_180:\n    if (info->trim) {\n      trim_right_edge(info, srcinfo->output_width);\n      trim_bottom_edge(info, srcinfo->output_height);\n    }\n    /* Need workspace arrays having same dimensions as source image. */\n    need_workspace = TRUE;\n    break;\n  case JXFORM_ROT_270:\n    if (info->trim)\n      trim_bottom_edge(info, srcinfo->output_width);\n    /* Need workspace arrays having transposed dimensions. */\n    need_workspace = TRUE;\n    transpose_it = TRUE;\n    break;\n  case JXFORM_WIPE:\n    break;\n  case JXFORM_DROP:\n#if DROP_REQUEST_FROM_SRC\n    drop_request_from_src(info->drop_ptr, srcinfo);\n#endif\n    break;\n  }\n\n  /* Allocate workspace if needed.\n   * Note that we allocate arrays padded out to the next iMCU boundary,\n   * so that transform routines need not worry about missing edge blocks.\n   */\n  if (need_workspace) {\n    coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small)\n      ((j_common_ptr) srcinfo, JPOOL_IMAGE,\n       SIZEOF(jvirt_barray_ptr) * info->num_components);\n    width_in_iMCUs = (JDIMENSION) jdiv_round_up\n      ((long) info->output_width, (long) info->iMCU_sample_width);\n    height_in_iMCUs = (JDIMENSION) jdiv_round_up\n      ((long) info->output_height, (long) info->iMCU_sample_height);\n    for (ci = 0; ci < info->num_components; ci++) {\n      compptr = srcinfo->comp_info + ci;\n      if (info->num_components == 1) {\n\t/* we're going to force samp factors to 1x1 in this case */\n\th_samp_factor = v_samp_factor = 1;\n      } else if (transpose_it) {\n\th_samp_factor = compptr->v_samp_factor;\n\tv_samp_factor = compptr->h_samp_factor;\n      } else {\n\th_samp_factor = compptr->h_samp_factor;\n\tv_samp_factor = compptr->v_samp_factor;\n      }\n      width_in_blocks = width_in_iMCUs * h_samp_factor;\n      height_in_blocks = height_in_iMCUs * v_samp_factor;\n      coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)\n\t((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,\n\t width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);\n    }\n    info->workspace_coef_arrays = coef_arrays;\n  } else\n    info->workspace_coef_arrays = NULL;\n\n  return TRUE;\n}\n\n\n/* Transpose destination image parameters */\n\nLOCAL(void)\ntranspose_critical_parameters (j_compress_ptr dstinfo)\n{\n  int tblno, i, j, ci, itemp;\n  jpeg_component_info *compptr;\n  JQUANT_TBL *qtblptr;\n  JDIMENSION jtemp;\n  UINT16 qtemp;\n\n  /* Transpose image dimensions */\n  jtemp = dstinfo->image_width;\n  dstinfo->image_width = dstinfo->image_height;\n  dstinfo->image_height = jtemp;\n  itemp = dstinfo->min_DCT_h_scaled_size;\n  dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;\n  dstinfo->min_DCT_v_scaled_size = itemp;\n\n  /* Transpose sampling factors */\n  for (ci = 0; ci < dstinfo->num_components; ci++) {\n    compptr = dstinfo->comp_info + ci;\n    itemp = compptr->h_samp_factor;\n    compptr->h_samp_factor = compptr->v_samp_factor;\n    compptr->v_samp_factor = itemp;\n  }\n\n  /* Transpose quantization tables */\n  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {\n    qtblptr = dstinfo->quant_tbl_ptrs[tblno];\n    if (qtblptr != NULL) {\n      for (i = 0; i < DCTSIZE; i++) {\n\tfor (j = 0; j < i; j++) {\n\t  qtemp = qtblptr->quantval[i*DCTSIZE+j];\n\t  qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];\n\t  qtblptr->quantval[j*DCTSIZE+i] = qtemp;\n\t}\n      }\n    }\n  }\n}\n\n\n/* Adjust Exif image parameters.\n *\n * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.\n */\n\nLOCAL(void)\nadjust_exif_parameters (JOCTET FAR * data, unsigned int length,\n\t\t\tJDIMENSION new_width, JDIMENSION new_height)\n{\n  boolean is_motorola; /* Flag for byte order */\n  unsigned int number_of_tags, tagnum;\n  unsigned int firstoffset, offset;\n  JDIMENSION new_value;\n\n  if (length < 12) return; /* Length of an IFD entry */\n\n  /* Discover byte order */\n  if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)\n    is_motorola = FALSE;\n  else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)\n    is_motorola = TRUE;\n  else\n    return;\n\n  /* Check Tag Mark */\n  if (is_motorola) {\n    if (GETJOCTET(data[2]) != 0) return;\n    if (GETJOCTET(data[3]) != 0x2A) return;\n  } else {\n    if (GETJOCTET(data[3]) != 0) return;\n    if (GETJOCTET(data[2]) != 0x2A) return;\n  }\n\n  /* Get first IFD offset (offset to IFD0) */\n  if (is_motorola) {\n    if (GETJOCTET(data[4]) != 0) return;\n    if (GETJOCTET(data[5]) != 0) return;\n    firstoffset = GETJOCTET(data[6]);\n    firstoffset <<= 8;\n    firstoffset += GETJOCTET(data[7]);\n  } else {\n    if (GETJOCTET(data[7]) != 0) return;\n    if (GETJOCTET(data[6]) != 0) return;\n    firstoffset = GETJOCTET(data[5]);\n    firstoffset <<= 8;\n    firstoffset += GETJOCTET(data[4]);\n  }\n  if (firstoffset > length - 2) return; /* check end of data segment */\n\n  /* Get the number of directory entries contained in this IFD */\n  if (is_motorola) {\n    number_of_tags = GETJOCTET(data[firstoffset]);\n    number_of_tags <<= 8;\n    number_of_tags += GETJOCTET(data[firstoffset+1]);\n  } else {\n    number_of_tags = GETJOCTET(data[firstoffset+1]);\n    number_of_tags <<= 8;\n    number_of_tags += GETJOCTET(data[firstoffset]);\n  }\n  if (number_of_tags == 0) return;\n  firstoffset += 2;\n\n  /* Search for ExifSubIFD offset Tag in IFD0 */\n  for (;;) {\n    if (firstoffset > length - 12) return; /* check end of data segment */\n    /* Get Tag number */\n    if (is_motorola) {\n      tagnum = GETJOCTET(data[firstoffset]);\n      tagnum <<= 8;\n      tagnum += GETJOCTET(data[firstoffset+1]);\n    } else {\n      tagnum = GETJOCTET(data[firstoffset+1]);\n      tagnum <<= 8;\n      tagnum += GETJOCTET(data[firstoffset]);\n    }\n    if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */\n    if (--number_of_tags == 0) return;\n    firstoffset += 12;\n  }\n\n  /* Get the ExifSubIFD offset */\n  if (is_motorola) {\n    if (GETJOCTET(data[firstoffset+8]) != 0) return;\n    if (GETJOCTET(data[firstoffset+9]) != 0) return;\n    offset = GETJOCTET(data[firstoffset+10]);\n    offset <<= 8;\n    offset += GETJOCTET(data[firstoffset+11]);\n  } else {\n    if (GETJOCTET(data[firstoffset+11]) != 0) return;\n    if (GETJOCTET(data[firstoffset+10]) != 0) return;\n    offset = GETJOCTET(data[firstoffset+9]);\n    offset <<= 8;\n    offset += GETJOCTET(data[firstoffset+8]);\n  }\n  if (offset > length - 2) return; /* check end of data segment */\n\n  /* Get the number of directory entries contained in this SubIFD */\n  if (is_motorola) {\n    number_of_tags = GETJOCTET(data[offset]);\n    number_of_tags <<= 8;\n    number_of_tags += GETJOCTET(data[offset+1]);\n  } else {\n    number_of_tags = GETJOCTET(data[offset+1]);\n    number_of_tags <<= 8;\n    number_of_tags += GETJOCTET(data[offset]);\n  }\n  if (number_of_tags < 2) return;\n  offset += 2;\n\n  /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */\n  do {\n    if (offset > length - 12) return; /* check end of data segment */\n    /* Get Tag number */\n    if (is_motorola) {\n      tagnum = GETJOCTET(data[offset]);\n      tagnum <<= 8;\n      tagnum += GETJOCTET(data[offset+1]);\n    } else {\n      tagnum = GETJOCTET(data[offset+1]);\n      tagnum <<= 8;\n      tagnum += GETJOCTET(data[offset]);\n    }\n    if (tagnum == 0xA002 || tagnum == 0xA003) {\n      if (tagnum == 0xA002)\n\tnew_value = new_width; /* ExifImageWidth Tag */\n      else\n\tnew_value = new_height; /* ExifImageHeight Tag */\n      if (is_motorola) {\n\tdata[offset+2] = 0; /* Format = unsigned long (4 octets) */\n\tdata[offset+3] = 4;\n\tdata[offset+4] = 0; /* Number Of Components = 1 */\n\tdata[offset+5] = 0;\n\tdata[offset+6] = 0;\n\tdata[offset+7] = 1;\n\tdata[offset+8] = 0;\n\tdata[offset+9] = 0;\n\tdata[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);\n\tdata[offset+11] = (JOCTET)(new_value & 0xFF);\n      } else {\n\tdata[offset+2] = 4; /* Format = unsigned long (4 octets) */\n\tdata[offset+3] = 0;\n\tdata[offset+4] = 1; /* Number Of Components = 1 */\n\tdata[offset+5] = 0;\n\tdata[offset+6] = 0;\n\tdata[offset+7] = 0;\n\tdata[offset+8] = (JOCTET)(new_value & 0xFF);\n\tdata[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);\n\tdata[offset+10] = 0;\n\tdata[offset+11] = 0;\n      }\n    }\n    offset += 12;\n  } while (--number_of_tags);\n}\n\n\n/* Adjust output image parameters as needed.\n *\n * This must be called after jpeg_copy_critical_parameters()\n * and before jpeg_write_coefficients().\n *\n * The return value is the set of virtual coefficient arrays to be written\n * (either the ones allocated by jtransform_request_workspace, or the\n * original source data arrays).  The caller will need to pass this value\n * to jpeg_write_coefficients().\n */\n\nGLOBAL(jvirt_barray_ptr *)\njtransform_adjust_parameters (j_decompress_ptr srcinfo,\n\t\t\t      j_compress_ptr dstinfo,\n\t\t\t      jvirt_barray_ptr *src_coef_arrays,\n\t\t\t      jpeg_transform_info *info)\n{\n  /* If force-to-grayscale is requested, adjust destination parameters */\n  if (info->force_grayscale) {\n    /* First, ensure we have YCC or grayscale data, and that the source's\n     * Y channel is full resolution.  (No reasonable person would make Y\n     * be less than full resolution, so actually coping with that case\n     * isn't worth extra code space.  But we check it to avoid crashing.)\n     */\n    if ((((dstinfo->jpeg_color_space == JCS_YCbCr ||\n\t   dstinfo->jpeg_color_space == JCS_BG_YCC) &&\n\t  dstinfo->num_components == 3) ||\n\t (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&\n\t  dstinfo->num_components == 1)) &&\n\tsrcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&\n\tsrcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {\n      /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed\n       * properly.  Among other things, it sets the target h_samp_factor &\n       * v_samp_factor to 1, which typically won't match the source.\n       * We have to preserve the source's quantization table number, however.\n       */\n      int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;\n      jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);\n      dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;\n    } else {\n      /* Sorry, can't do it */\n      ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);\n    }\n  } else if (info->num_components == 1) {\n    /* For a single-component source, we force the destination sampling factors\n     * to 1x1, with or without force_grayscale.  This is useful because some\n     * decoders choke on grayscale images with other sampling factors.\n     */\n    dstinfo->comp_info[0].h_samp_factor = 1;\n    dstinfo->comp_info[0].v_samp_factor = 1;\n  }\n\n  /* Correct the destination's image dimensions as necessary\n   * for rotate/flip, resize, and crop operations.\n   */\n  dstinfo->jpeg_width = info->output_width;\n  dstinfo->jpeg_height = info->output_height;\n\n  /* Transpose destination image parameters, adjust quantization */\n  switch (info->transform) {\n  case JXFORM_TRANSPOSE:\n  case JXFORM_TRANSVERSE:\n  case JXFORM_ROT_90:\n  case JXFORM_ROT_270:\n    transpose_critical_parameters(dstinfo);\n    break;\n  case JXFORM_DROP:\n    if (info->drop_width != 0 && info->drop_height != 0)\n      adjust_quant(srcinfo, src_coef_arrays,\n\t\t   info->drop_ptr, info->drop_coef_arrays,\n\t\t   info->trim, dstinfo);\n    break;\n  default:\n    break;\n  }\n\n  /* Adjust Exif properties */\n  if (srcinfo->marker_list != NULL &&\n      srcinfo->marker_list->marker == JPEG_APP0+1 &&\n      srcinfo->marker_list->data_length >= 6 &&\n      GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&\n      GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&\n      GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&\n      GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&\n      GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&\n      GETJOCTET(srcinfo->marker_list->data[5]) == 0) {\n    /* Suppress output of JFIF marker */\n    dstinfo->write_JFIF_header = FALSE;\n    /* Adjust Exif image parameters */\n    if (dstinfo->jpeg_width != srcinfo->image_width ||\n\tdstinfo->jpeg_height != srcinfo->image_height)\n      /* Align data segment to start of TIFF structure for parsing */\n      adjust_exif_parameters(srcinfo->marker_list->data + 6,\n\tsrcinfo->marker_list->data_length - 6,\n\tdstinfo->jpeg_width, dstinfo->jpeg_height);\n  }\n\n  /* Return the appropriate output data set */\n  if (info->workspace_coef_arrays != NULL)\n    return info->workspace_coef_arrays;\n  return src_coef_arrays;\n}\n\n\n/* Execute the actual transformation, if any.\n *\n * This must be called *after* jpeg_write_coefficients, because it depends\n * on jpeg_write_coefficients to have computed subsidiary values such as\n * the per-component width and height fields in the destination object.\n *\n * Note that some transformations will modify the source data arrays!\n */\n\nGLOBAL(void)\njtransform_execute_transform (j_decompress_ptr srcinfo,\n\t\t\t      j_compress_ptr dstinfo,\n\t\t\t      jvirt_barray_ptr *src_coef_arrays,\n\t\t\t      jpeg_transform_info *info)\n{\n  jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;\n\n  /* Note: conditions tested here should match those in switch statement\n   * in jtransform_request_workspace()\n   */\n  switch (info->transform) {\n  case JXFORM_NONE:\n    if (info->output_width > srcinfo->output_width ||\n\tinfo->output_height > srcinfo->output_height) {\n      if (info->output_width > srcinfo->output_width &&\n\t  info->crop_width_set == JCROP_REFLECT)\n\tdo_crop_ext_reflect(srcinfo, dstinfo,\n\t\t\t    info->x_crop_offset, info->y_crop_offset,\n\t\t\t    src_coef_arrays, dst_coef_arrays);\n      else if (info->output_width > srcinfo->output_width &&\n\t       info->crop_width_set == JCROP_FORCE)\n\tdo_crop_ext_flat(srcinfo, dstinfo,\n\t\t\t info->x_crop_offset, info->y_crop_offset,\n\t\t\t src_coef_arrays, dst_coef_arrays);\n      else\n\tdo_crop_ext_zero(srcinfo, dstinfo,\n\t\t\t info->x_crop_offset, info->y_crop_offset,\n\t\t\t src_coef_arrays, dst_coef_arrays);\n    } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)\n      do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t      src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_FLIP_H:\n    if (info->y_crop_offset != 0)\n      do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t\tsrc_coef_arrays, dst_coef_arrays);\n    else\n      do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,\n\t\t\tsrc_coef_arrays);\n    break;\n  case JXFORM_FLIP_V:\n    do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t      src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_TRANSPOSE:\n    do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t\t src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_TRANSVERSE:\n    do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t\t  src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_ROT_90:\n    do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t      src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_ROT_180:\n    do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t       src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_ROT_270:\n    do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t       src_coef_arrays, dst_coef_arrays);\n    break;\n  case JXFORM_WIPE:\n    if (info->crop_width_set == JCROP_REFLECT &&\n\tinfo->y_crop_offset == 0 && info->drop_height ==\n\t(JDIMENSION) jdiv_round_up\n\t  ((long) info->output_height, (long) info->iMCU_sample_height) &&\n\t(info->x_crop_offset == 0 ||\n\t info->x_crop_offset + info->drop_width ==\n\t (JDIMENSION) jdiv_round_up\n\t   ((long) info->output_width, (long) info->iMCU_sample_width)))\n      do_reflect(srcinfo, dstinfo, info->x_crop_offset,\n\t\t src_coef_arrays, info->drop_width, info->drop_height);\n    else if (info->crop_width_set == JCROP_FORCE)\n      do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t\t src_coef_arrays, info->drop_width, info->drop_height);\n    else\n      do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t      src_coef_arrays, info->drop_width, info->drop_height);\n    break;\n  case JXFORM_DROP:\n    if (info->drop_width != 0 && info->drop_height != 0)\n      do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,\n\t      src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,\n\t      info->drop_width, info->drop_height);\n    break;\n  }\n}\n\n/* jtransform_perfect_transform\n *\n * Determine whether lossless transformation is perfectly\n * possible for a specified image and transformation.\n *\n * Inputs:\n *   image_width, image_height: source image dimensions.\n *   MCU_width, MCU_height: pixel dimensions of MCU.\n *   transform: transformation identifier.\n * Parameter sources from initialized jpeg_struct\n * (after reading source header):\n *   image_width = cinfo.image_width\n *   image_height = cinfo.image_height\n *   MCU_width = cinfo.max_h_samp_factor * cinfo.block_size\n *   MCU_height = cinfo.max_v_samp_factor * cinfo.block_size\n * Result:\n *   TRUE = perfect transformation possible\n *   FALSE = perfect transformation not possible\n *           (may use custom action then)\n */\n\nGLOBAL(boolean)\njtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,\n\t\t\t     int MCU_width, int MCU_height,\n\t\t\t     JXFORM_CODE transform)\n{\n  boolean result = TRUE; /* initialize TRUE */\n\n  switch (transform) {\n  case JXFORM_FLIP_H:\n  case JXFORM_ROT_270:\n    if (image_width % (JDIMENSION) MCU_width)\n      result = FALSE;\n    break;\n  case JXFORM_FLIP_V:\n  case JXFORM_ROT_90:\n    if (image_height % (JDIMENSION) MCU_height)\n      result = FALSE;\n    break;\n  case JXFORM_TRANSVERSE:\n  case JXFORM_ROT_180:\n    if (image_width % (JDIMENSION) MCU_width)\n      result = FALSE;\n    if (image_height % (JDIMENSION) MCU_height)\n      result = FALSE;\n    break;\n  default:\n    break;\n  }\n\n  return result;\n}\n\n#endif /* TRANSFORMS_SUPPORTED */\n\n\n/* Setup decompression object to save desired markers in memory.\n * This must be called before jpeg_read_header() to have the desired effect.\n */\n\nGLOBAL(void)\njcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)\n{\n#ifdef SAVE_MARKERS_SUPPORTED\n  int m;\n\n  /* Save comments except under NONE option */\n  if (option != JCOPYOPT_NONE) {\n    jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);\n  }\n  /* Save all types of APPn markers iff ALL option */\n  if (option == JCOPYOPT_ALL) {\n    for (m = 0; m < 16; m++)\n      jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);\n  }\n#endif /* SAVE_MARKERS_SUPPORTED */\n}\n\n/* Copy markers saved in the given source object to the destination object.\n * This should be called just after jpeg_start_compress() or\n * jpeg_write_coefficients().\n * Note that those routines will have written the SOI, and also the\n * JFIF APP0 or Adobe APP14 markers if selected.\n */\n\nGLOBAL(void)\njcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t\t       JCOPY_OPTION option)\n{\n  jpeg_saved_marker_ptr marker;\n\n  /* In the current implementation, we don't actually need to examine the\n   * option flag here; we just copy everything that got saved.\n   * But to avoid confusion, we do not output JFIF and Adobe APP14 markers\n   * if the encoder library already wrote one.\n   */\n  for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {\n    if (dstinfo->write_JFIF_header &&\n\tmarker->marker == JPEG_APP0 &&\n\tmarker->data_length >= 5 &&\n\tGETJOCTET(marker->data[0]) == 0x4A &&\n\tGETJOCTET(marker->data[1]) == 0x46 &&\n\tGETJOCTET(marker->data[2]) == 0x49 &&\n\tGETJOCTET(marker->data[3]) == 0x46 &&\n\tGETJOCTET(marker->data[4]) == 0)\n      continue;\t\t\t/* reject duplicate JFIF */\n    if (dstinfo->write_Adobe_marker &&\n\tmarker->marker == JPEG_APP0+14 &&\n\tmarker->data_length >= 5 &&\n\tGETJOCTET(marker->data[0]) == 0x41 &&\n\tGETJOCTET(marker->data[1]) == 0x64 &&\n\tGETJOCTET(marker->data[2]) == 0x6F &&\n\tGETJOCTET(marker->data[3]) == 0x62 &&\n\tGETJOCTET(marker->data[4]) == 0x65)\n      continue;\t\t\t/* reject duplicate Adobe */\n#ifdef NEED_FAR_POINTERS\n    /* We could use jpeg_write_marker if the data weren't FAR... */\n    {\n      unsigned int i;\n      jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);\n      for (i = 0; i < marker->data_length; i++)\n\tjpeg_write_m_byte(dstinfo, marker->data[i]);\n    }\n#else\n    jpeg_write_marker(dstinfo, marker->marker,\n\t\t      marker->data, marker->data_length);\n#endif\n  }\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/transupp.h",
    "content": "/*\n * transupp.h\n *\n * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains declarations for image transformation routines and\n * other utility code used by the jpegtran sample application.  These are\n * NOT part of the core JPEG library.  But we keep these routines separate\n * from jpegtran.c to ease the task of maintaining jpegtran-like programs\n * that have other user interfaces.\n *\n * NOTE: all the routines declared here have very specific requirements\n * about when they are to be executed during the reading and writing of the\n * source and destination files.  See the comments in transupp.c, or see\n * jpegtran.c for an example of correct usage.\n */\n\n/* If you happen not to want the image transform support, disable it here */\n#ifndef TRANSFORMS_SUPPORTED\n#define TRANSFORMS_SUPPORTED 1\t\t/* 0 disables transform code */\n#endif\n\n/*\n * Although rotating and flipping data expressed as DCT coefficients is not\n * hard, there is an asymmetry in the JPEG format specification for images\n * whose dimensions aren't multiples of the iMCU size.  The right and bottom\n * image edges are padded out to the next iMCU boundary with junk data; but\n * no padding is possible at the top and left edges.  If we were to flip\n * the whole image including the pad data, then pad garbage would become\n * visible at the top and/or left, and real pixels would disappear into the\n * pad margins --- perhaps permanently, since encoders & decoders may not\n * bother to preserve DCT blocks that appear to be completely outside the\n * nominal image area.  So, we have to exclude any partial iMCUs from the\n * basic transformation.\n *\n * Transpose is the only transformation that can handle partial iMCUs at the\n * right and bottom edges completely cleanly.  flip_h can flip partial iMCUs\n * at the bottom, but leaves any partial iMCUs at the right edge untouched.\n * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched.\n * The other transforms are defined as combinations of these basic transforms\n * and process edge blocks in a way that preserves the equivalence.\n *\n * The \"trim\" option causes untransformable partial iMCUs to be dropped;\n * this is not strictly lossless, but it usually gives the best-looking\n * result for odd-size images.  Note that when this option is active,\n * the expected mathematical equivalences between the transforms may not hold.\n * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim\n * followed by -rot 180 -trim trims both edges.)\n *\n * We also offer a lossless-crop option, which discards data outside a given\n * image region but losslessly preserves what is inside.  Like the rotate and\n * flip transforms, lossless crop is restricted by the current JPEG format: the\n * upper left corner of the selected region must fall on an iMCU boundary.  If\n * this does not hold for the given crop parameters, we silently move the upper\n * left corner up and/or left to make it so, simultaneously increasing the\n * region dimensions to keep the lower right crop corner unchanged.  (Thus, the\n * output image covers at least the requested region, but may cover more.)\n * The adjustment of the region dimensions may be optionally disabled.\n *\n * A complementary lossless-wipe option is provided to discard (gray out) data\n * inside a given image region while losslessly preserving what is outside.\n * Another option is lossless-drop, which replaces data at a given image\n * position by another image.  Both source images must have the same\n * subsampling values.  It is best if they also have the same quantization,\n * otherwise quantization adaption occurs.  The trim option can be used with\n * the drop option to requantize the drop file to the source file.\n *\n * We also provide a lossless-resize option, which is kind of a lossless-crop\n * operation in the DCT coefficient block domain - it discards higher-order\n * coefficients and losslessly preserves lower-order coefficients of a\n * sub-block.\n *\n * Rotate/flip transform, resize, and crop can be requested together in a\n * single invocation.  The crop is applied last --- that is, the crop region\n * is specified in terms of the destination image after transform/resize.\n *\n * We also offer a \"force to grayscale\" option, which simply discards the\n * chrominance channels of a YCbCr image.  This is lossless in the sense that\n * the luminance channel is preserved exactly.  It's not the same kind of\n * thing as the rotate/flip transformations, but it's convenient to handle it\n * as part of this package, mainly because the transformation routines have to\n * be aware of the option to know how many components to work on.\n */\n\n\n/* Short forms of external names for systems with brain-damaged linkers. */\n\n#ifdef NEED_SHORT_EXTERNAL_NAMES\n#define jtransform_parse_crop_spec\tjTrParCrop\n#define jtransform_request_workspace\tjTrRequest\n#define jtransform_adjust_parameters\tjTrAdjust\n#define jtransform_execute_transform\tjTrExec\n#define jtransform_perfect_transform\tjTrPerfect\n#define jcopy_markers_setup\t\tjCMrkSetup\n#define jcopy_markers_execute\t\tjCMrkExec\n#endif /* NEED_SHORT_EXTERNAL_NAMES */\n\n\n/*\n * Codes for supported types of image transformations.\n */\n\ntypedef enum {\n\tJXFORM_NONE,\t\t/* no transformation */\n\tJXFORM_FLIP_H,\t\t/* horizontal flip */\n\tJXFORM_FLIP_V,\t\t/* vertical flip */\n\tJXFORM_TRANSPOSE,\t/* transpose across UL-to-LR axis */\n\tJXFORM_TRANSVERSE,\t/* transpose across UR-to-LL axis */\n\tJXFORM_ROT_90,\t\t/* 90-degree clockwise rotation */\n\tJXFORM_ROT_180,\t\t/* 180-degree rotation */\n\tJXFORM_ROT_270,\t\t/* 270-degree clockwise (or 90 ccw) */\n\tJXFORM_WIPE,\t\t/* wipe */\n\tJXFORM_DROP\t\t/* drop */\n} JXFORM_CODE;\n\n/*\n * Codes for crop parameters, which can individually be unspecified,\n * positive or negative for xoffset or yoffset,\n * positive or force or reflect for width or height.\n */\n\ntypedef enum {\n\tJCROP_UNSET,\n\tJCROP_POS,\n\tJCROP_NEG,\n\tJCROP_FORCE,\n\tJCROP_REFLECT\n} JCROP_CODE;\n\n/*\n * Transform parameters struct.\n * NB: application must not change any elements of this struct after\n * calling jtransform_request_workspace.\n */\n\ntypedef struct {\n  /* Options: set by caller */\n  JXFORM_CODE transform;\t/* image transform operator */\n  boolean perfect;\t\t/* if TRUE, fail if partial MCUs are requested */\n  boolean trim;\t\t\t/* if TRUE, trim partial MCUs as needed */\n  boolean force_grayscale;\t/* if TRUE, convert color image to grayscale */\n  boolean crop;\t\t\t/* if TRUE, crop or wipe source image, or drop */\n\n  /* Crop parameters: application need not set these unless crop is TRUE.\n   * These can be filled in by jtransform_parse_crop_spec().\n   */\n  JDIMENSION crop_width;\t/* Width of selected region */\n  JCROP_CODE crop_width_set;\t/* (force disables adjustment) */\n  JDIMENSION crop_height;\t/* Height of selected region */\n  JCROP_CODE crop_height_set;\t/* (force disables adjustment) */\n  JDIMENSION crop_xoffset;\t/* X offset of selected region */\n  JCROP_CODE crop_xoffset_set;\t/* (negative measures from right edge) */\n  JDIMENSION crop_yoffset;\t/* Y offset of selected region */\n  JCROP_CODE crop_yoffset_set;\t/* (negative measures from bottom edge) */\n\n  /* Drop parameters: set by caller for drop request */\n  j_decompress_ptr drop_ptr;\n  jvirt_barray_ptr * drop_coef_arrays;\n\n  /* Internal workspace: caller should not touch these */\n  int num_components;\t\t/* # of components in workspace */\n  jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */\n  JDIMENSION output_width;\t/* cropped destination dimensions */\n  JDIMENSION output_height;\n  JDIMENSION x_crop_offset;\t/* destination crop offsets measured in iMCUs */\n  JDIMENSION y_crop_offset;\n  JDIMENSION drop_width;\t/* drop/wipe dimensions measured in iMCUs */\n  JDIMENSION drop_height;\n  int iMCU_sample_width;\t/* destination iMCU size */\n  int iMCU_sample_height;\n} jpeg_transform_info;\n\n\n#if TRANSFORMS_SUPPORTED\n\n/* Parse a crop specification (written in X11 geometry style) */\nEXTERN(boolean) jtransform_parse_crop_spec\n\tJPP((jpeg_transform_info *info, const char *spec));\n/* Request any required workspace */\nEXTERN(boolean) jtransform_request_workspace\n\tJPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));\n/* Adjust output image parameters */\nEXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters\n\tJPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t     jvirt_barray_ptr *src_coef_arrays,\n\t     jpeg_transform_info *info));\n/* Execute the actual transformation, if any */\nEXTERN(void) jtransform_execute_transform\n\tJPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t     jvirt_barray_ptr *src_coef_arrays,\n\t     jpeg_transform_info *info));\n/* Determine whether lossless transformation is perfectly\n * possible for a specified image and transformation.\n */\nEXTERN(boolean) jtransform_perfect_transform\n\tJPP((JDIMENSION image_width, JDIMENSION image_height,\n\t     int MCU_width, int MCU_height,\n\t     JXFORM_CODE transform));\n\n/* jtransform_execute_transform used to be called\n * jtransform_execute_transformation, but some compilers complain about\n * routine names that long.  This macro is here to avoid breaking any\n * old source code that uses the original name...\n */\n#define jtransform_execute_transformation\tjtransform_execute_transform\n\n#endif /* TRANSFORMS_SUPPORTED */\n\n\n/*\n * Support for copying optional markers from source to destination file.\n */\n\ntypedef enum {\n\tJCOPYOPT_NONE,\t\t/* copy no optional markers */\n\tJCOPYOPT_COMMENTS,\t/* copy only comment (COM) markers */\n\tJCOPYOPT_ALL\t\t/* copy all optional markers */\n} JCOPY_OPTION;\n\n#define JCOPYOPT_DEFAULT  JCOPYOPT_COMMENTS\t/* recommended default */\n\n/* Setup decompression object to save desired markers in memory */\nEXTERN(void) jcopy_markers_setup\n\tJPP((j_decompress_ptr srcinfo, JCOPY_OPTION option));\n/* Copy markers saved in the given source object to the destination object */\nEXTERN(void) jcopy_markers_execute\n\tJPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,\n\t     JCOPY_OPTION option));\n"
  },
  {
    "path": "dlib/external/libjpeg/wrbmp.c",
    "content": "/*\n * wrbmp.c\n *\n * Copyright (C) 1994-1996, Thomas G. Lane.\n * Modified 2017-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write output images in Microsoft \"BMP\"\n * format (MS Windows 3.x and OS/2 1.x flavors).\n * Either 8-bit colormapped or 24-bit full-color format can be written.\n * No compression is supported.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume output to\n * an ordinary stdio stream.\n *\n * This code contributed by James Arthur Boucher.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef BMP_SUPPORTED\n\n\n/*\n * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.\n * This is not yet implemented.\n */\n\n#if BITS_IN_JSAMPLE != 8\n  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */\n#endif\n\n/*\n * Since BMP stores scanlines bottom-to-top, we have to invert the image\n * from JPEG's top-to-bottom order.  To do this, we save the outgoing data\n * in a virtual array during put_pixel_row calls, then actually emit the\n * BMP file during finish_output.  The virtual array contains one JSAMPLE per\n * pixel if the output is grayscale or colormapped, three if it is full color.\n */\n\n/* Private version of data destination object */\n\ntypedef struct {\n  struct djpeg_dest_struct pub;\t/* public fields */\n\n  boolean is_os2;\t\t/* saves the OS2 format request flag */\n\n  jvirt_sarray_ptr whole_image;\t/* needed to reverse row order */\n  JDIMENSION data_width;\t/* JSAMPLEs per row */\n  JDIMENSION row_width;\t\t/* physical width of one row in the BMP file */\n  int pad_bytes;\t\t/* number of padding bytes needed per row */\n  JDIMENSION cur_output_row;\t/* next row# to write to virtual array */\n} bmp_dest_struct;\n\ntypedef bmp_dest_struct * bmp_dest_ptr;\n\n\n/* Forward declarations */\nLOCAL(void) write_colormap\n\tJPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,\n\t     int map_colors, int map_entry_size));\n\n\n/*\n * Write some pixel data.\n * In this module rows_supplied will always be 1.\n */\n\nMETHODDEF(void)\nput_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\tJDIMENSION rows_supplied)\n/* This version is for writing 24-bit pixels */\n{\n  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;\n  register JSAMPROW inptr, outptr;\n  register JDIMENSION col;\n  int pad;\n\n  /* Access next row in virtual array */\n  outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);\n  dest->cur_output_row++;\n\n  /* Transfer data.  Note destination values must be in BGR order\n   * (even though Microsoft's own documents say the opposite).\n   */\n  inptr = dest->pub.buffer[0];\n  for (col = cinfo->output_width; col > 0; col--) {\n    outptr[2] = *inptr++;\t/* can omit GETJSAMPLE() safely */\n    outptr[1] = *inptr++;\n    outptr[0] = *inptr++;\n    outptr += 3;\n  }\n\n  /* Zero out the pad bytes. */\n  pad = dest->pad_bytes;\n  while (--pad >= 0)\n    *outptr++ = 0;\n}\n\nMETHODDEF(void)\nput_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t       JDIMENSION rows_supplied)\n/* This version is for grayscale OR quantized color output */\n{\n  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;\n  register JSAMPROW inptr, outptr;\n  register JDIMENSION col;\n  int pad;\n\n  /* Access next row in virtual array */\n  outptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n    dest->whole_image, dest->cur_output_row, (JDIMENSION) 1, TRUE);\n  dest->cur_output_row++;\n\n  /* Transfer data. */\n  inptr = dest->pub.buffer[0];\n  for (col = cinfo->output_width; col > 0; col--) {\n    *outptr++ = *inptr++;\t/* can omit GETJSAMPLE() safely */\n  }\n\n  /* Zero out the pad bytes. */\n  pad = dest->pad_bytes;\n  while (--pad >= 0)\n    *outptr++ = 0;\n}\n\n\n/*\n * Startup: normally writes the file header.\n * In this module we may as well postpone everything until finish_output.\n */\n\nMETHODDEF(void)\nstart_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  /* no work here */\n}\n\n\n/*\n * Finish up at the end of the file.\n *\n * Here is where we really output the BMP file.\n *\n * First, routines to write the Windows and OS/2 variants of the file header.\n */\n\nLOCAL(void)\nwrite_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)\n/* Write a Windows-style BMP file header, including colormap if needed */\n{\n  char bmpfileheader[14];\n  char bmpinfoheader[40];\n#define PUT_2B(array, offset, value)  \\\n\t(array[offset] = (char) ((value) & 0xFF), \\\n\t array[offset+1] = (char) (((value) >> 8) & 0xFF))\n#define PUT_4B(array, offset, value)  \\\n\t(array[offset] = (char) ((value) & 0xFF), \\\n\t array[offset+1] = (char) (((value) >> 8) & 0xFF), \\\n\t array[offset+2] = (char) (((value) >> 16) & 0xFF), \\\n\t array[offset+3] = (char) (((value) >> 24) & 0xFF))\n  INT32 headersize, bfSize;\n  int bits_per_pixel, cmap_entries;\n\n  /* Compute colormap size and total file size */\n  if (cinfo->out_color_space == JCS_RGB) {\n    if (cinfo->quantize_colors) {\n      /* Colormapped RGB */\n      bits_per_pixel = 8;\n      cmap_entries = 256;\n    } else {\n      /* Unquantized, full color RGB */\n      bits_per_pixel = 24;\n      cmap_entries = 0;\n    }\n  } else {\n    /* Grayscale output.  We need to fake a 256-entry colormap. */\n    bits_per_pixel = 8;\n    cmap_entries = 256;\n  }\n  /* File size */\n  headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */\n  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;\n\n  /* Set unused fields of header to 0 */\n  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));\n  MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));\n\n  /* Fill the file header */\n  bmpfileheader[0] = 0x42;\t/* first 2 bytes are ASCII 'B', 'M' */\n  bmpfileheader[1] = 0x4D;\n  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */\n  /* we leave bfReserved1 & bfReserved2 = 0 */\n  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */\n\n  /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */\n  PUT_2B(bmpinfoheader, 0, 40);\t/* biSize */\n  PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */\n  PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */\n  PUT_2B(bmpinfoheader, 12, 1);\t/* biPlanes - must be 1 */\n  PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */\n  /* we leave biCompression = 0, for none */\n  /* we leave biSizeImage = 0; this is correct for uncompressed data */\n  if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */\n    PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */\n    PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */\n  }\n  PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */\n  /* we leave biClrImportant = 0 */\n\n  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n  if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n\n  if (cmap_entries > 0)\n    write_colormap(cinfo, dest, cmap_entries, 4);\n}\n\n\nLOCAL(void)\nwrite_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)\n/* Write an OS2-style BMP file header, including colormap if needed */\n{\n  char bmpfileheader[14];\n  char bmpcoreheader[12];\n  INT32 headersize, bfSize;\n  int bits_per_pixel, cmap_entries;\n\n  /* Compute colormap size and total file size */\n  if (cinfo->out_color_space == JCS_RGB) {\n    if (cinfo->quantize_colors) {\n      /* Colormapped RGB */\n      bits_per_pixel = 8;\n      cmap_entries = 256;\n    } else {\n      /* Unquantized, full color RGB */\n      bits_per_pixel = 24;\n      cmap_entries = 0;\n    }\n  } else {\n    /* Grayscale output.  We need to fake a 256-entry colormap. */\n    bits_per_pixel = 8;\n    cmap_entries = 256;\n  }\n  /* File size */\n  headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */\n  bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;\n\n  /* Set unused fields of header to 0 */\n  MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));\n  MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));\n\n  /* Fill the file header */\n  bmpfileheader[0] = 0x42;\t/* first 2 bytes are ASCII 'B', 'M' */\n  bmpfileheader[1] = 0x4D;\n  PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */\n  /* we leave bfReserved1 & bfReserved2 = 0 */\n  PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */\n\n  /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */\n  PUT_2B(bmpcoreheader, 0, 12);\t/* bcSize */\n  PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */\n  PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */\n  PUT_2B(bmpcoreheader, 8, 1);\t/* bcPlanes - must be 1 */\n  PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */\n\n  if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n  if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n\n  if (cmap_entries > 0)\n    write_colormap(cinfo, dest, cmap_entries, 3);\n}\n\n\n/*\n * Write the colormap.\n * Windows uses BGR0 map entries; OS/2 uses BGR entries.\n */\n\nLOCAL(void)\nwrite_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,\n\t\tint map_colors, int map_entry_size)\n{\n  JSAMPARRAY colormap = cinfo->colormap;\n  int num_colors = cinfo->actual_number_of_colors;\n  FILE * outfile = dest->pub.output_file;\n  int i;\n\n  if (colormap != NULL) {\n    if (cinfo->out_color_components == 3) {\n      /* Normal case with RGB colormap */\n      for (i = 0; i < num_colors; i++) {\n\tputc(GETJSAMPLE(colormap[2][i]), outfile);\n\tputc(GETJSAMPLE(colormap[1][i]), outfile);\n\tputc(GETJSAMPLE(colormap[0][i]), outfile);\n\tif (map_entry_size == 4)\n\t  putc(0, outfile);\n      }\n    } else {\n      /* Grayscale colormap (only happens with grayscale quantization) */\n      for (i = 0; i < num_colors; i++) {\n\tputc(GETJSAMPLE(colormap[0][i]), outfile);\n\tputc(GETJSAMPLE(colormap[0][i]), outfile);\n\tputc(GETJSAMPLE(colormap[0][i]), outfile);\n\tif (map_entry_size == 4)\n\t  putc(0, outfile);\n      }\n    }\n  } else {\n    /* If no colormap, must be grayscale data.  Generate a linear \"map\". */\n    for (i = 0; i < 256; i++) {\n      putc(i, outfile);\n      putc(i, outfile);\n      putc(i, outfile);\n      if (map_entry_size == 4)\n\tputc(0, outfile);\n    }\n  }\n  /* Pad colormap to ensure specified number of colormap entries */ \n  if (i > map_colors)\n    ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);\n  for (; i < map_colors; i++) {\n    putc(CENTERJSAMPLE, outfile);\n    putc(CENTERJSAMPLE, outfile);\n    putc(CENTERJSAMPLE, outfile);\n    if (map_entry_size == 4)\n      putc(0, outfile);\n  }\n}\n\n\nMETHODDEF(void)\nfinish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;\n  register FILE * outfile = dest->pub.output_file;\n  register JSAMPROW data_ptr;\n  JDIMENSION row;\n  register JDIMENSION col;\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n\n  /* Write the header and colormap */\n  if (dest->is_os2)\n    write_os2_header(cinfo, dest);\n  else\n    write_bmp_header(cinfo, dest);\n\n  /* Write the file body from our virtual array */\n  for (row = cinfo->output_height; row > 0; row--) {\n    if (progress != NULL) {\n      progress->pub.pass_counter = (long) (cinfo->output_height - row);\n      progress->pub.pass_limit = (long) cinfo->output_height;\n      (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n    }\n    data_ptr = * (*cinfo->mem->access_virt_sarray) ((j_common_ptr) cinfo,\n      dest->whole_image, row - 1, (JDIMENSION) 1, FALSE);\n    for (col = dest->row_width; col > 0; col--) {\n      putc(GETJSAMPLE(*data_ptr), outfile);\n      data_ptr++;\n    }\n  }\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n\n  /* Make sure we wrote the output file OK */\n  JFFLUSH(outfile);\n  if (JFERROR(outfile))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * The module selection routine for BMP format output.\n */\n\nGLOBAL(djpeg_dest_ptr)\njinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)\n{\n  bmp_dest_ptr dest;\n  JDIMENSION row_width;\n\n  /* Create module interface object, fill in method pointers */\n  dest = (bmp_dest_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(bmp_dest_struct));\n  dest->pub.start_output = start_output_bmp;\n  dest->pub.finish_output = finish_output_bmp;\n  dest->is_os2 = is_os2;\n\n  switch (cinfo->out_color_space) {\n  case JCS_GRAYSCALE:\n    dest->pub.put_pixel_rows = put_gray_rows;\n    break;\n  case JCS_RGB:\n    if (cinfo->quantize_colors)\n      dest->pub.put_pixel_rows = put_gray_rows;\n    else\n      dest->pub.put_pixel_rows = put_pixel_rows;\n    break;\n  default:\n    ERREXIT(cinfo, JERR_BMP_COLORSPACE);\n  }\n\n  /* Calculate output image dimensions so we can allocate space */\n  jpeg_calc_output_dimensions(cinfo);\n\n  /* Determine width of rows in the BMP file (padded to 4-byte boundary). */\n  row_width = cinfo->output_width * cinfo->output_components;\n  dest->data_width = row_width;\n  while ((row_width & 3) != 0) row_width++;\n  dest->row_width = row_width;\n  dest->pad_bytes = (int) (row_width - dest->data_width);\n\n  /* Allocate space for inversion array, prepare for write pass */\n  dest->whole_image = (*cinfo->mem->request_virt_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n     row_width, cinfo->output_height, (JDIMENSION) 1);\n  dest->cur_output_row = 0;\n  if (cinfo->progress != NULL) {\n    cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n    progress->total_extra_passes++; /* count file input as separate pass */\n  }\n\n  /* Create decompressor output buffer. */\n  dest->pub.buffer = (*cinfo->mem->alloc_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);\n  dest->pub.buffer_height = 1;\n\n  return &dest->pub;\n}\n\n#endif /* BMP_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/wrgif.c",
    "content": "/*\n * wrgif.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2015-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write output images in GIF format.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume output to\n * an ordinary stdio stream.\n */\n\n/*\n * This code is loosely based on ppmtogif from the PBMPLUS distribution\n * of Feb. 1991.  That file contains the following copyright notice:\n *    Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.\n *    Lempel-Ziv compression based on \"compress\" by Spencer W. Thomas et al.\n *    Copyright (C) 1989 by Jef Poskanzer.\n *    Permission to use, copy, modify, and distribute this software and its\n *    documentation for any purpose and without fee is hereby granted, provided\n *    that the above copyright notice appear in all copies and that both that\n *    copyright notice and this permission notice appear in supporting\n *    documentation.  This software is provided \"as is\" without express or\n *    implied warranty.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef GIF_SUPPORTED\n\n\n#define\tMAX_LZW_BITS\t12\t/* maximum LZW code size (4096 symbols) */\n\ntypedef INT16 code_int;\t\t/* must hold -1 .. 2**MAX_LZW_BITS */\n\n#define LZW_TABLE_SIZE\t((code_int) 1 << MAX_LZW_BITS)\n\n#define HSIZE\t\t5003\t/* hash table size for 80% occupancy */\n\ntypedef int hash_int;\t\t/* must hold -2*HSIZE..2*HSIZE */\n\n#define MAXCODE(n_bits)\t(((code_int) 1 << (n_bits)) - 1)\n\n\n/*\n * The LZW hash table consists of two parallel arrays:\n *   hash_code[i]\tcode of symbol in slot i, or 0 if empty slot\n *   hash_value[i]\tsymbol's value; undefined if empty slot\n * where slot values (i) range from 0 to HSIZE-1.  The symbol value is\n * its prefix symbol's code concatenated with its suffix character.\n *\n * Algorithm:  use open addressing double hashing (no chaining) on the\n * prefix code / suffix character combination.  We do a variant of Knuth's\n * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime\n * secondary probe.\n *\n * The hash_value[] table is allocated from FAR heap space since it would\n * use up rather a lot of the near data space in a PC.\n */\n\ntypedef INT32 hash_entry;\t/* must hold (code_int<<8) | byte */\n\n#define HASH_ENTRY(prefix, suffix)  ((((hash_entry) (prefix)) << 8) | (suffix))\n\n\n/* Private version of data destination object */\n\ntypedef struct {\n  struct djpeg_dest_struct pub;\t/* public fields */\n\n  j_decompress_ptr cinfo;\t/* back link saves passing separate parm */\n\n  /* State for packing variable-width codes into a bitstream */\n  int n_bits;\t\t\t/* current number of bits/code */\n  code_int maxcode;\t\t/* maximum code, given n_bits */\n  int init_bits;\t\t/* initial n_bits ... restored after clear */\n  INT32 cur_accum;\t\t/* holds bits not yet output */\n  int cur_bits;\t\t\t/* # of bits in cur_accum */\n\n  /* LZW string construction */\n  code_int waiting_code;\t/* symbol not yet output; may be extendable */\n  boolean first_byte;\t\t/* if TRUE, waiting_code is not valid */\n\n  /* State for GIF code assignment */\n  code_int ClearCode;\t\t/* clear code (doesn't change) */\n  code_int EOFCode;\t\t/* EOF code (ditto) */\n  code_int free_code;\t\t/* LZW: first not-yet-used symbol code */\n  code_int code_counter;\t/* not LZW: counts output symbols */\n\n  /* LZW hash table */\n  code_int *hash_code;\t\t/* => hash table of symbol codes */\n  hash_entry FAR *hash_value;\t/* => hash table of symbol values */\n\n  /* GIF data packet construction buffer */\n  int bytesinpkt;\t\t/* # of bytes in current packet */\n  char packetbuf[256];\t\t/* workspace for accumulating packet */\n\n} gif_dest_struct;\n\ntypedef gif_dest_struct * gif_dest_ptr;\n\n\n/*\n * Routines to package finished data bytes into GIF data blocks.\n * A data block consists of a count byte (1..255) and that many data bytes.\n */\n\nLOCAL(void)\nflush_packet (gif_dest_ptr dinfo)\n/* flush any accumulated data */\n{\n  if (dinfo->bytesinpkt > 0) {\t/* never write zero-length packet */\n    dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;\n    if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)\n\t!= (size_t) dinfo->bytesinpkt)\n      ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);\n    dinfo->bytesinpkt = 0;\n  }\n}\n\n\n/* Add a character to current packet; flush to disk if necessary */\n#define CHAR_OUT(dinfo, c)  \\\n\t{ (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c);  \\\n\t    if ((dinfo)->bytesinpkt >= 255)  \\\n\t      flush_packet(dinfo);  \\\n\t}\n\n\n/* Routine to convert variable-width codes into a byte stream */\n\nLOCAL(void)\noutput (gif_dest_ptr dinfo, code_int code)\n/* Emit a code of n_bits bits */\n/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */\n{\n  dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;\n  dinfo->cur_bits += dinfo->n_bits;\n\n  while (dinfo->cur_bits >= 8) {\n    CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);\n    dinfo->cur_accum >>= 8;\n    dinfo->cur_bits -= 8;\n  }\n\n  /*\n   * If the next entry is going to be too big for the code size,\n   * then increase it, if possible.  We do this here to ensure\n   * that it's done in sync with the decoder's codesize increases.\n   */\n  if (dinfo->free_code > dinfo->maxcode) {\n    dinfo->n_bits++;\n    if (dinfo->n_bits == MAX_LZW_BITS)\n      dinfo->maxcode = LZW_TABLE_SIZE; /* free_code will never exceed this */\n    else\n      dinfo->maxcode = MAXCODE(dinfo->n_bits);\n  }\n}\n\n\n/* Compression initialization & termination */\n\n\nLOCAL(void)\nclear_hash (gif_dest_ptr dinfo)\n/* Fill the hash table with empty entries */\n{\n  /* It's sufficient to zero hash_code[] */\n  MEMZERO(dinfo->hash_code, HSIZE * SIZEOF(code_int));\n}\n\n\nLOCAL(void)\nclear_block (gif_dest_ptr dinfo)\n/* Reset compressor and issue a Clear code */\n{\n  clear_hash(dinfo);\t\t\t/* delete all the symbols */\n  dinfo->free_code = dinfo->ClearCode + 2;\n  output(dinfo, dinfo->ClearCode);\t/* inform decoder */\n  dinfo->n_bits = dinfo->init_bits;\t/* reset code size */\n  dinfo->maxcode = MAXCODE(dinfo->n_bits);\n}\n\n\nLOCAL(void)\ncompress_init (gif_dest_ptr dinfo, int i_bits)\n/* Initialize compressor */\n{\n  /* init all the state variables */\n  dinfo->n_bits = dinfo->init_bits = i_bits;\n  dinfo->maxcode = MAXCODE(dinfo->n_bits);\n  dinfo->ClearCode = ((code_int) 1 << (i_bits - 1));\n  dinfo->EOFCode = dinfo->ClearCode + 1;\n  dinfo->code_counter = dinfo->free_code = dinfo->ClearCode + 2;\n  dinfo->first_byte = TRUE;\t/* no waiting symbol yet */\n  /* init output buffering vars */\n  dinfo->bytesinpkt = 0;\n  dinfo->cur_accum = 0;\n  dinfo->cur_bits = 0;\n  /* clear hash table */\n  if (dinfo->hash_code != NULL)\n    clear_hash(dinfo);\n  /* GIF specifies an initial Clear code */\n  output(dinfo, dinfo->ClearCode);\n}\n\n\nLOCAL(void)\ncompress_term (gif_dest_ptr dinfo)\n/* Clean up at end */\n{\n  /* Flush out the buffered LZW code */\n  if (! dinfo->first_byte)\n    output(dinfo, dinfo->waiting_code);\n  /* Send an EOF code */\n  output(dinfo, dinfo->EOFCode);\n  /* Flush the bit-packing buffer */\n  if (dinfo->cur_bits > 0) {\n    CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);\n  }\n  /* Flush the packet buffer */\n  flush_packet(dinfo);\n}\n\n\n/* GIF header construction */\n\n\nLOCAL(void)\nput_word (gif_dest_ptr dinfo, unsigned int w)\n/* Emit a 16-bit word, LSB first */\n{\n  putc(w & 0xFF, dinfo->pub.output_file);\n  putc((w >> 8) & 0xFF, dinfo->pub.output_file);\n}\n\n\nLOCAL(void)\nput_3bytes (gif_dest_ptr dinfo, int val)\n/* Emit 3 copies of same byte value --- handy subr for colormap construction */\n{\n  putc(val, dinfo->pub.output_file);\n  putc(val, dinfo->pub.output_file);\n  putc(val, dinfo->pub.output_file);\n}\n\n\nLOCAL(void)\nemit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)\n/* Output the GIF file header, including color map */\n/* If colormap == NULL, synthesize a grayscale colormap */\n{\n  int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;\n  int cshift = dinfo->cinfo->data_precision - 8;\n  int i;\n\n  if (num_colors > 256)\n    ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);\n  /* Compute bits/pixel and related values */\n  BitsPerPixel = 1;\n  while (num_colors > (1 << BitsPerPixel))\n    BitsPerPixel++;\n  ColorMapSize = 1 << BitsPerPixel;\n  if (BitsPerPixel <= 1)\n    InitCodeSize = 2;\n  else\n    InitCodeSize = BitsPerPixel;\n  /*\n   * Write the GIF header.\n   * Note that we generate a plain GIF87 header for maximum compatibility.\n   */\n  putc('G', dinfo->pub.output_file);\n  putc('I', dinfo->pub.output_file);\n  putc('F', dinfo->pub.output_file);\n  putc('8', dinfo->pub.output_file);\n  putc('7', dinfo->pub.output_file);\n  putc('a', dinfo->pub.output_file);\n  /* Write the Logical Screen Descriptor */\n  put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);\n  put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);\n  FlagByte = 0x80;\t\t/* Yes, there is a global color table */\n  FlagByte |= (BitsPerPixel - 1) << 4;\t/* color resolution */\n  FlagByte |= (BitsPerPixel - 1);\t/* size of global color table */\n  putc(FlagByte, dinfo->pub.output_file);\n  putc(0, dinfo->pub.output_file); /* Background color index */\n  putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */\n  /* Write the Global Color Map */\n  /* If the color map is more than 8 bits precision, */\n  /* we reduce it to 8 bits by shifting */\n  for (i = 0; i < ColorMapSize; i++) {\n    if (i < num_colors) {\n      if (colormap != NULL) {\n\tif (dinfo->cinfo->out_color_space == JCS_RGB) {\n\t  /* Normal case: RGB color map */\n\t  putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);\n\t  putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);\n\t  putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);\n\t} else {\n\t  /* Grayscale \"color map\": possible if quantizing grayscale image */\n\t  put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);\n\t}\n      } else {\n\t/* Create a grayscale map of num_colors values, range 0..255 */\n\tput_3bytes(dinfo, (i * 255 + (num_colors - 1) / 2) / (num_colors - 1));\n      }\n    } else {\n      /* fill out the map to a power of 2 */\n      put_3bytes(dinfo, CENTERJSAMPLE >> cshift);\n    }\n  }\n  /* Write image separator and Image Descriptor */\n  putc(',', dinfo->pub.output_file); /* separator */\n  put_word(dinfo, 0);\t\t/* left/top offset */\n  put_word(dinfo, 0);\n  put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */\n  put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);\n  /* flag byte: not interlaced, no local color map */\n  putc(0x00, dinfo->pub.output_file);\n  /* Write Initial Code Size byte */\n  putc(InitCodeSize, dinfo->pub.output_file);\n\n  /* Initialize for compression of image data */\n  compress_init(dinfo, InitCodeSize + 1);\n}\n\n\n/*\n * Startup: write the file header.\n */\n\nMETHODDEF(void)\nstart_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  gif_dest_ptr dest = (gif_dest_ptr) dinfo;\n\n  if (cinfo->quantize_colors)\n    emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);\n  else\n    emit_header(dest, 256, (JSAMPARRAY) NULL);\n}\n\n\n/*\n * Write some pixel data.\n * In this module rows_supplied will always be 1.\n */\n\n\n/*\n * The LZW algorithm proper\n */\n\nMETHODDEF(void)\nput_LZW_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t    JDIMENSION rows_supplied)\n{\n  gif_dest_ptr dest = (gif_dest_ptr) dinfo;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n  code_int c;\n  register hash_int i;\n  register hash_int disp;\n  register hash_entry probe_value;\n\n  ptr = dest->pub.buffer[0];\n  for (col = cinfo->output_width; col > 0; col--) {\n    /* Accept and compress one 8-bit byte */\n    c = (code_int) GETJSAMPLE(*ptr++);\n\n    if (dest->first_byte) {\t/* need to initialize waiting_code */\n      dest->waiting_code = c;\n      dest->first_byte = FALSE;\n      continue;\n    }\n\n    /* Probe hash table to see if a symbol exists for\n     * waiting_code followed by c.\n     * If so, replace waiting_code by that symbol and continue.\n     */\n    i = ((hash_int) c << (MAX_LZW_BITS-8)) + dest->waiting_code;\n    /* i is less than twice 2**MAX_LZW_BITS, therefore less than twice HSIZE */\n    if (i >= HSIZE)\n      i -= HSIZE;\n\n    probe_value = HASH_ENTRY(dest->waiting_code, c);\n\n    if (dest->hash_code[i] == 0) {\n      /* hit empty slot; desired symbol not in table */\n      output(dest, dest->waiting_code);\n      if (dest->free_code < LZW_TABLE_SIZE) {\n\tdest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */\n\tdest->hash_value[i] = probe_value;\n      } else\n\tclear_block(dest);\n      dest->waiting_code = c;\n      continue;\n    }\n    if (dest->hash_value[i] == probe_value) {\n      dest->waiting_code = dest->hash_code[i];\n      continue;\n    }\n\n    if (i == 0)\t\t\t/* secondary hash (after G. Knott) */\n      disp = 1;\n    else\n      disp = HSIZE - i;\n    for (;;) {\n      i -= disp;\n      if (i < 0)\n\ti += HSIZE;\n      if (dest->hash_code[i] == 0) {\n\t/* hit empty slot; desired symbol not in table */\n\toutput(dest, dest->waiting_code);\n\tif (dest->free_code < LZW_TABLE_SIZE) {\n\t  dest->hash_code[i] = dest->free_code++; /* add symbol to hashtable */\n\t  dest->hash_value[i] = probe_value;\n\t} else\n\t  clear_block(dest);\n\tdest->waiting_code = c;\n\tbreak;\n      }\n      if (dest->hash_value[i] == probe_value) {\n\tdest->waiting_code = dest->hash_code[i];\n\tbreak;\n      }\n    }\n  }\n}\n\n\n/*\n * The pseudo-compression algorithm.\n *\n * In this version we simply output each pixel value as a separate symbol;\n * thus, no compression occurs.  In fact, there is expansion of one bit per\n * pixel, because we use a symbol width one bit wider than the pixel width.\n *\n * GIF ordinarily uses variable-width symbols, and the decoder will expect\n * to ratchet up the symbol width after a fixed number of symbols.\n * To simplify the logic and keep the expansion penalty down, we emit a\n * GIF Clear code to reset the decoder just before the width would ratchet up.\n * Thus, all the symbols in the output file will have the same bit width.\n * Note that emitting the Clear codes at the right times is a mere matter of\n * counting output symbols and is in no way dependent on the LZW algorithm.\n *\n * With a small basic pixel width (low color count), Clear codes will be\n * needed very frequently, causing the file to expand even more.  So this\n * simplistic approach wouldn't work too well on bilevel images, for example.\n * But for output of JPEG conversions the pixel width will usually be 8 bits\n * (129 to 256 colors), so the overhead added by Clear symbols is only about\n * one symbol in every 256.\n */\n\nMETHODDEF(void)\nput_raw_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t    JDIMENSION rows_supplied)\n{\n  gif_dest_ptr dest = (gif_dest_ptr) dinfo;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n  code_int c;\n\n  ptr = dest->pub.buffer[0];\n  for (col = cinfo->output_width; col > 0; col--) {\n    c = (code_int) GETJSAMPLE(*ptr++);\n    /* Accept and output one pixel value.\n     * The given value must be less than n_bits wide.\n     */\n\n    /* Output the given pixel value as a symbol. */\n    output(dest, c);\n    /* Issue Clear codes often enough to keep the reader from ratcheting up\n     * its symbol size.\n     */\n    if (dest->code_counter < dest->maxcode) {\n      dest->code_counter++;\n    } else {\n      output(dest, dest->ClearCode);\n      dest->code_counter = dest->ClearCode + 2;\t/* reset the counter */\n    }\n  }\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  gif_dest_ptr dest = (gif_dest_ptr) dinfo;\n\n  /* Flush compression mechanism */\n  compress_term(dest);\n  /* Write a zero-length data block to end the series */\n  putc(0, dest->pub.output_file);\n  /* Write the GIF terminator mark */\n  putc(';', dest->pub.output_file);\n  /* Make sure we wrote the output file OK */\n  JFFLUSH(dest->pub.output_file);\n  if (JFERROR(dest->pub.output_file))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * The module selection routine for GIF format output.\n */\n\nGLOBAL(djpeg_dest_ptr)\njinit_write_gif (j_decompress_ptr cinfo, boolean is_lzw)\n{\n  gif_dest_ptr dest;\n\n  /* Create module interface object, fill in method pointers */\n  dest = (gif_dest_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(gif_dest_struct));\n  dest->cinfo = cinfo;\t\t/* make back link for subroutines */\n  dest->pub.start_output = start_output_gif;\n  dest->pub.finish_output = finish_output_gif;\n\n  if (cinfo->out_color_space != JCS_GRAYSCALE &&\n      cinfo->out_color_space != JCS_RGB)\n    ERREXIT(cinfo, JERR_GIF_COLORSPACE);\n\n  /* Force quantization if color or if > 8 bits input */\n  if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {\n    /* Force quantization to at most 256 colors */\n    cinfo->quantize_colors = TRUE;\n    if (cinfo->desired_number_of_colors > 256)\n      cinfo->desired_number_of_colors = 256;\n  }\n\n  /* Calculate output image dimensions so we can allocate space */\n  jpeg_calc_output_dimensions(cinfo);\n\n  if (cinfo->output_components != 1) /* safety check: just one component? */\n    ERREXIT(cinfo, JERR_GIF_BUG);\n\n  /* Create decompressor output buffer. */\n  dest->pub.buffer = (*cinfo->mem->alloc_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);\n  dest->pub.buffer_height = 1;\n\n  if (is_lzw) {\n    dest->pub.put_pixel_rows = put_LZW_pixel_rows;\n    /* Allocate space for hash table */\n    dest->hash_code = (code_int *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(code_int));\n    dest->hash_value = (hash_entry FAR *) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, HSIZE * SIZEOF(hash_entry));\n  } else {\n    dest->pub.put_pixel_rows = put_raw_pixel_rows;\n    /* Mark tables unused */\n    dest->hash_code = NULL;\n    dest->hash_value = NULL;\n  }\n\n  return &dest->pub;\n}\n\n#endif /* GIF_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/wrjpgcom.c",
    "content": "/*\n * wrjpgcom.c\n *\n * Copyright (C) 1994-1997, Thomas G. Lane.\n * Modified 2015-2017 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains a very simple stand-alone application that inserts\n * user-supplied text as a COM (comment) marker in a JFIF file.\n * This may be useful as an example of the minimum logic needed to parse\n * JPEG markers.\n */\n\n#define JPEG_CJPEG_DJPEG\t/* to get the command-line config symbols */\n#include \"jinclude.h\"\t\t/* get auto-config symbols, <stdio.h> */\n\n#ifndef HAVE_STDLIB_H\t\t/* <stdlib.h> should declare malloc() */\nextern void * malloc ();\n#endif\n#include <ctype.h>\t\t/* to declare isupper(), tolower() */\n#ifdef USE_SETMODE\n#include <fcntl.h>\t\t/* to declare setmode()'s parameter macros */\n/* If you have setmode() but not <io.h>, just delete this line: */\n#include <io.h>\t\t\t/* to declare setmode() */\n#endif\n\n#ifdef USE_CCOMMAND\t\t/* command-line reader for Macintosh */\n#ifdef __MWERKS__\n#include <SIOUX.h>              /* Metrowerks needs this */\n#include <console.h>\t\t/* ... and this */\n#endif\n#ifdef THINK_C\n#include <console.h>\t\t/* Think declares it here */\n#endif\n#endif\n\n#ifdef DONT_USE_B_MODE\t\t/* define mode parameters for fopen() */\n#define READ_BINARY\t\"r\"\n#define WRITE_BINARY\t\"w\"\n#else\n#ifdef VMS\t\t\t/* VMS is very nonstandard */\n#define READ_BINARY\t\"rb\", \"ctx=stm\"\n#define WRITE_BINARY\t\"wb\", \"ctx=stm\"\n#else\t\t\t\t/* standard ANSI-compliant case */\n#define READ_BINARY\t\"rb\"\n#define WRITE_BINARY\t\"wb\"\n#endif\n#endif\n\n#ifndef EXIT_FAILURE\t\t/* define exit() codes if not provided */\n#define EXIT_FAILURE  1\n#endif\n#ifndef EXIT_SUCCESS\n#ifdef VMS\n#define EXIT_SUCCESS  1\t\t/* VMS is very nonstandard */\n#else\n#define EXIT_SUCCESS  0\n#endif\n#endif\n\n/* Reduce this value if your malloc() can't allocate blocks up to 64K.\n * On DOS, compiling in large model is usually a better solution.\n */\n\n#ifndef MAX_COM_LENGTH\n#define MAX_COM_LENGTH 65000L\t/* must be <= 65533 in any case */\n#endif\n\n\n/*\n * These macros are used to read the input file and write the output file.\n * To reuse this code in another application, you might need to change these.\n */\n\nstatic FILE * infile;\t\t/* input JPEG file */\n\n/* Return next input byte, or EOF if no more */\n#define NEXTBYTE()  getc(infile)\n\nstatic FILE * outfile;\t\t/* output JPEG file */\n\n/* Emit an output byte */\n#define PUTBYTE(x)  putc((x), outfile)\n\n\n/* Error exit handler */\n#define ERREXIT(msg)  (fprintf(stderr, \"%s\\n\", msg), exit(EXIT_FAILURE))\n\n\n/* Read one byte, testing for EOF */\nstatic int\nread_1_byte (void)\n{\n  int c;\n\n  c = NEXTBYTE();\n  if (c == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  return c;\n}\n\n/* Read 2 bytes, convert to unsigned int */\n/* All 2-byte quantities in JPEG markers are MSB first */\nstatic unsigned int\nread_2_bytes (void)\n{\n  int c1, c2;\n\n  c1 = NEXTBYTE();\n  if (c1 == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  c2 = NEXTBYTE();\n  if (c2 == EOF)\n    ERREXIT(\"Premature EOF in JPEG file\");\n  return (((unsigned int) c1) << 8) + ((unsigned int) c2);\n}\n\n\n/* Routines to write data to output file */\n\nstatic void\nwrite_1_byte (int c)\n{\n  PUTBYTE(c);\n}\n\nstatic void\nwrite_2_bytes (unsigned int val)\n{\n  PUTBYTE((val >> 8) & 0xFF);\n  PUTBYTE(val & 0xFF);\n}\n\nstatic void\nwrite_marker (int marker)\n{\n  PUTBYTE(0xFF);\n  PUTBYTE(marker);\n}\n\nstatic void\ncopy_rest_of_file (void)\n{\n  int c;\n\n  while ((c = NEXTBYTE()) != EOF)\n    PUTBYTE(c);\n}\n\n\n/*\n * JPEG markers consist of one or more 0xFF bytes, followed by a marker\n * code byte (which is not an FF).  Here are the marker codes of interest\n * in this program.  (See jdmarker.c for a more complete list.)\n */\n\n#define M_SOF0  0xC0\t\t/* Start Of Frame N */\n#define M_SOF1  0xC1\t\t/* N indicates which compression process */\n#define M_SOF2  0xC2\t\t/* Only SOF0-SOF2 are now in common use */\n#define M_SOF3  0xC3\n#define M_SOF5  0xC5\t\t/* NB: codes C4 and CC are NOT SOF markers */\n#define M_SOF6  0xC6\n#define M_SOF7  0xC7\n#define M_SOF9  0xC9\n#define M_SOF10 0xCA\n#define M_SOF11 0xCB\n#define M_SOF13 0xCD\n#define M_SOF14 0xCE\n#define M_SOF15 0xCF\n#define M_SOI   0xD8\t\t/* Start Of Image (beginning of datastream) */\n#define M_EOI   0xD9\t\t/* End Of Image (end of datastream) */\n#define M_SOS   0xDA\t\t/* Start Of Scan (begins compressed data) */\n#define M_COM   0xFE\t\t/* COMment */\n\n\n/*\n * Find the next JPEG marker and return its marker code.\n * We expect at least one FF byte, possibly more if the compressor used FFs\n * to pad the file.  (Padding FFs will NOT be replicated in the output file.)\n * There could also be non-FF garbage between markers.  The treatment of such\n * garbage is unspecified; we choose to skip over it but emit a warning msg.\n * NB: this routine must not be used after seeing SOS marker, since it will\n * not deal correctly with FF/00 sequences in the compressed image data...\n */\n\nstatic int\nnext_marker (void)\n{\n  int c;\n  int discarded_bytes = 0;\n\n  /* Find 0xFF byte; count and skip any non-FFs. */\n  c = read_1_byte();\n  while (c != 0xFF) {\n    discarded_bytes++;\n    c = read_1_byte();\n  }\n  /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs\n   * are legal as pad bytes, so don't count them in discarded_bytes.\n   */\n  do {\n    c = read_1_byte();\n  } while (c == 0xFF);\n\n  if (discarded_bytes != 0) {\n    fprintf(stderr, \"Warning: garbage data found in JPEG file\\n\");\n  }\n\n  return c;\n}\n\n\n/*\n * Read the initial marker, which should be SOI.\n * For a JFIF file, the first two bytes of the file should be literally\n * 0xFF M_SOI.  To be more general, we could use next_marker, but if the\n * input file weren't actually JPEG at all, next_marker might read the whole\n * file and then return a misleading error message...\n */\n\nstatic int\nfirst_marker (void)\n{\n  int c1, c2;\n\n  c1 = NEXTBYTE();\n  c2 = NEXTBYTE();\n  if (c1 != 0xFF || c2 != M_SOI)\n    ERREXIT(\"Not a JPEG file\");\n  return c2;\n}\n\n\n/*\n * Most types of marker are followed by a variable-length parameter segment.\n * This routine skips over the parameters for any marker we don't otherwise\n * want to process.\n * Note that we MUST skip the parameter segment explicitly in order not to\n * be fooled by 0xFF bytes that might appear within the parameter segment;\n * such bytes do NOT introduce new markers.\n */\n\nstatic void\ncopy_variable (void)\n/* Copy an unknown or uninteresting variable-length marker */\n{\n  unsigned int length;\n\n  /* Get the marker parameter length count */\n  length = read_2_bytes();\n  write_2_bytes(length);\n  /* Length includes itself, so must be at least 2 */\n  if (length < 2)\n    ERREXIT(\"Erroneous JPEG marker length\");\n  length -= 2;\n  /* Copy the remaining bytes */\n  while (length > 0) {\n    write_1_byte(read_1_byte());\n    length--;\n  }\n}\n\nstatic void\nskip_variable (void)\n/* Skip over an unknown or uninteresting variable-length marker */\n{\n  unsigned int length;\n\n  /* Get the marker parameter length count */\n  length = read_2_bytes();\n  /* Length includes itself, so must be at least 2 */\n  if (length < 2)\n    ERREXIT(\"Erroneous JPEG marker length\");\n  length -= 2;\n  /* Skip over the remaining bytes */\n  while (length > 0) {\n    (void) read_1_byte();\n    length--;\n  }\n}\n\n\n/*\n * Parse the marker stream until SOFn or EOI is seen;\n * copy data to output, but discard COM markers unless keep_COM is true.\n */\n\nstatic int\nscan_JPEG_header (int keep_COM)\n{\n  int marker;\n\n  /* Expect SOI at start of file */\n  if (first_marker() != M_SOI)\n    ERREXIT(\"Expected SOI marker first\");\n  write_marker(M_SOI);\n\n  /* Scan miscellaneous markers until we reach SOFn. */\n  for (;;) {\n    marker = next_marker();\n    switch (marker) {\n      /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,\n       * treated as SOFn.  C4 in particular is actually DHT.\n       */\n    case M_SOF0:\t\t/* Baseline */\n    case M_SOF1:\t\t/* Extended sequential, Huffman */\n    case M_SOF2:\t\t/* Progressive, Huffman */\n    case M_SOF3:\t\t/* Lossless, Huffman */\n    case M_SOF5:\t\t/* Differential sequential, Huffman */\n    case M_SOF6:\t\t/* Differential progressive, Huffman */\n    case M_SOF7:\t\t/* Differential lossless, Huffman */\n    case M_SOF9:\t\t/* Extended sequential, arithmetic */\n    case M_SOF10:\t\t/* Progressive, arithmetic */\n    case M_SOF11:\t\t/* Lossless, arithmetic */\n    case M_SOF13:\t\t/* Differential sequential, arithmetic */\n    case M_SOF14:\t\t/* Differential progressive, arithmetic */\n    case M_SOF15:\t\t/* Differential lossless, arithmetic */\n      return marker;\n\n    case M_SOS:\t\t\t/* should not see compressed data before SOF */\n      ERREXIT(\"SOS without prior SOFn\");\n      break;\n\n    case M_EOI:\t\t\t/* in case it's a tables-only JPEG stream */\n      return marker;\n\n    case M_COM:\t\t\t/* Existing COM: conditionally discard */\n      if (keep_COM) {\n\twrite_marker(marker);\n\tcopy_variable();\n      } else {\n\tskip_variable();\n      }\n      break;\n\n    default:\t\t\t/* Anything else just gets copied */\n      write_marker(marker);\n      copy_variable();\t\t/* we assume it has a parameter count... */\n      break;\n    }\n  } /* end loop */\n}\n\n\n/* Command line parsing code */\n\nstatic const char * progname;\t/* program name for error messages */\n\n\nstatic void\nusage (void)\n/* complain about bad command line */\n{\n  fprintf(stderr, \"wrjpgcom inserts a textual comment in a JPEG file.\\n\");\n  fprintf(stderr, \"You can add to or replace any existing comment(s).\\n\");\n\n  fprintf(stderr, \"Usage: %s [switches] \", progname);\n#ifdef TWO_FILE_COMMANDLINE\n  fprintf(stderr, \"inputfile outputfile\\n\");\n#else\n  fprintf(stderr, \"[inputfile]\\n\");\n#endif\n\n  fprintf(stderr, \"Switches (names may be abbreviated):\\n\");\n  fprintf(stderr, \"  -replace         Delete any existing comments\\n\");\n  fprintf(stderr, \"  -comment \\\"text\\\"  Insert comment with given text\\n\");\n  fprintf(stderr, \"  -cfile name      Read comment from named file\\n\");\n  fprintf(stderr, \"Notice that you must put quotes around the comment text\\n\");\n  fprintf(stderr, \"when you use -comment.\\n\");\n  fprintf(stderr, \"If you do not give either -comment or -cfile on the command line,\\n\");\n  fprintf(stderr, \"then the comment text is read from standard input.\\n\");\n  fprintf(stderr, \"It can be multiple lines, up to %u characters total.\\n\",\n\t  (unsigned int) MAX_COM_LENGTH);\n#ifndef TWO_FILE_COMMANDLINE\n  fprintf(stderr, \"You must specify an input JPEG file name when supplying\\n\");\n  fprintf(stderr, \"comment text from standard input.\\n\");\n#endif\n\n  exit(EXIT_FAILURE);\n}\n\n\nstatic int\nkeymatch (char * arg, const char * keyword, int minchars)\n/* Case-insensitive matching of (possibly abbreviated) keyword switches. */\n/* keyword is the constant keyword (must be lower case already), */\n/* minchars is length of minimum legal abbreviation. */\n{\n  register int ca, ck;\n  register int nmatched = 0;\n\n  while ((ca = *arg++) != '\\0') {\n    if ((ck = *keyword++) == '\\0')\n      return 0;\t\t\t/* arg longer than keyword, no good */\n    if (isupper(ca))\t\t/* force arg to lcase (assume ck is already) */\n      ca = tolower(ca);\n    if (ca != ck)\n      return 0;\t\t\t/* no good */\n    nmatched++;\t\t\t/* count matched characters */\n  }\n  /* reached end of argument; fail if it's too short for unique abbrev */\n  if (nmatched < minchars)\n    return 0;\n  return 1;\t\t\t/* A-OK */\n}\n\n\n/*\n * The main program.\n */\n\nint\nmain (int argc, char **argv)\n{\n  int argn;\n  char * arg;\n  int keep_COM = 1;\n  char * comment_arg = NULL;\n  FILE * comment_file = NULL;\n  unsigned int comment_length = 0;\n  int marker;\n\n  /* On Mac, fetch a command line. */\n#ifdef USE_CCOMMAND\n  argc = ccommand(&argv);\n#endif\n\n  progname = argv[0];\n  if (progname == NULL || progname[0] == 0)\n    progname = \"wrjpgcom\";\t/* in case C library doesn't provide it */\n\n  /* Parse switches, if any */\n  for (argn = 1; argn < argc; argn++) {\n    arg = argv[argn];\n    if (arg[0] != '-')\n      break;\t\t\t/* not switch, must be file name */\n    arg++;\t\t\t/* advance over '-' */\n    if (keymatch(arg, \"replace\", 1)) {\n      keep_COM = 0;\n    } else if (keymatch(arg, \"cfile\", 2)) {\n      if (++argn >= argc) usage();\n      if ((comment_file = fopen(argv[argn], \"r\")) == NULL) {\n\tfprintf(stderr, \"%s: can't open %s\\n\", progname, argv[argn]);\n\texit(EXIT_FAILURE);\n      }\n    } else if (keymatch(arg, \"comment\", 1)) {\n      if (++argn >= argc) usage();\n      comment_arg = argv[argn];\n      /* If the comment text starts with '\"', then we are probably running\n       * under MS-DOG and must parse out the quoted string ourselves.  Sigh.\n       */\n      if (comment_arg[0] == '\"') {\n\tcomment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);\n\tif (comment_arg == NULL)\n\t  ERREXIT(\"Insufficient memory\");\n\tif (strlen(argv[argn]+1) >= (size_t) MAX_COM_LENGTH) {\n\t  fprintf(stderr, \"Comment text may not exceed %u bytes\\n\",\n\t\t  (unsigned int) MAX_COM_LENGTH);\n\t  exit(EXIT_FAILURE);\n\t}\n\tstrcpy(comment_arg, argv[argn]+1);\n\tfor (;;) {\n\t  comment_length = (unsigned int) strlen(comment_arg);\n\t  if (comment_length > 0 && comment_arg[comment_length-1] == '\"') {\n\t    comment_arg[comment_length-1] = '\\0'; /* zap terminating quote */\n\t    break;\n\t  }\n\t  if (++argn >= argc)\n\t    ERREXIT(\"Missing ending quote mark\");\n\t  if (strlen(comment_arg) + 1 + strlen(argv[argn]) >=\n\t      (size_t) MAX_COM_LENGTH) {\n\t    fprintf(stderr, \"Comment text may not exceed %u bytes\\n\",\n\t\t    (unsigned int) MAX_COM_LENGTH);\n\t    exit(EXIT_FAILURE);\n\t  }\n\t  strcat(comment_arg, \" \");\n\t  strcat(comment_arg, argv[argn]);\n\t}\n      } else if (strlen(comment_arg) >= (size_t) MAX_COM_LENGTH) {\n\tfprintf(stderr, \"Comment text may not exceed %u bytes\\n\",\n\t\t(unsigned int) MAX_COM_LENGTH);\n\texit(EXIT_FAILURE);\n      }\n      comment_length = (unsigned int) strlen(comment_arg);\n    } else\n      usage();\n  }\n\n  /* Cannot use both -comment and -cfile. */\n  if (comment_arg != NULL && comment_file != NULL)\n    usage();\n  /* If there is neither -comment nor -cfile, we will read the comment text\n   * from stdin; in this case there MUST be an input JPEG file name.\n   */\n  if (comment_arg == NULL && comment_file == NULL && argn >= argc)\n    usage();\n\n  /* Open the input file. */\n  if (argn < argc) {\n    if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open %s\\n\", progname, argv[argn]);\n      exit(EXIT_FAILURE);\n    }\n  } else {\n    /* default input file is stdin */\n#ifdef USE_SETMODE\t\t/* need to hack file mode? */\n    setmode(fileno(stdin), O_BINARY);\n#endif\n#ifdef USE_FDOPEN\t\t/* need to re-open in binary mode? */\n    if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {\n      fprintf(stderr, \"%s: can't open stdin\\n\", progname);\n      exit(EXIT_FAILURE);\n    }\n#else\n    infile = stdin;\n#endif\n  }\n\n  /* Open the output file. */\n#ifdef TWO_FILE_COMMANDLINE\n  /* Must have explicit output file name */\n  if (argn != argc-2) {\n    fprintf(stderr, \"%s: must name one input and one output file\\n\",\n\t    progname);\n    usage();\n  }\n  if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {\n    fprintf(stderr, \"%s: can't open %s\\n\", progname, argv[argn+1]);\n    exit(EXIT_FAILURE);\n  }\n#else\n  /* Unix style: expect zero or one file name */\n  if (argn < argc-1) {\n    fprintf(stderr, \"%s: only one input file\\n\", progname);\n    usage();\n  }\n  /* default output file is stdout */\n#ifdef USE_SETMODE\t\t/* need to hack file mode? */\n  setmode(fileno(stdout), O_BINARY);\n#endif\n#ifdef USE_FDOPEN\t\t/* need to re-open in binary mode? */\n  if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {\n    fprintf(stderr, \"%s: can't open stdout\\n\", progname);\n    exit(EXIT_FAILURE);\n  }\n#else\n  outfile = stdout;\n#endif\n#endif /* TWO_FILE_COMMANDLINE */\n\n  /* Collect comment text from comment_file or stdin, if necessary */\n  if (comment_arg == NULL) {\n    FILE * src_file;\n    int c;\n\n    comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);\n    if (comment_arg == NULL)\n      ERREXIT(\"Insufficient memory\");\n    comment_length = 0;\n    src_file = (comment_file != NULL ? comment_file : stdin);\n    while ((c = getc(src_file)) != EOF) {\n      if (comment_length >= (unsigned int) MAX_COM_LENGTH) {\n\tfprintf(stderr, \"Comment text may not exceed %u bytes\\n\",\n\t\t(unsigned int) MAX_COM_LENGTH);\n\texit(EXIT_FAILURE);\n      }\n      comment_arg[comment_length++] = (char) c;\n    }\n    if (comment_file != NULL)\n      fclose(comment_file);\n  }\n\n  /* Copy JPEG headers until SOFn marker;\n   * we will insert the new comment marker just before SOFn.\n   * This (a) causes the new comment to appear after, rather than before,\n   * existing comments; and (b) ensures that comments come after any JFIF\n   * or JFXX markers, as required by the JFIF specification.\n   */\n  marker = scan_JPEG_header(keep_COM);\n  /* Insert the new COM marker, but only if nonempty text has been supplied */\n  if (comment_length > 0) {\n    write_marker(M_COM);\n    write_2_bytes(comment_length + 2);\n    while (comment_length > 0) {\n      write_1_byte(*comment_arg++);\n      comment_length--;\n    }\n  }\n  /* Duplicate the remainder of the source file.\n   * Note that any COM markers occuring after SOF will not be touched.\n   */\n  write_marker(marker);\n  copy_rest_of_file();\n\n  /* All done. */\n  exit(EXIT_SUCCESS);\n  return 0;\t\t\t/* suppress no-return-value warnings */\n}\n"
  },
  {
    "path": "dlib/external/libjpeg/wrppm.c",
    "content": "/*\n * wrppm.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2009-2020 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write output images in PPM/PGM format.\n * The extended 2-byte-per-sample raw PPM/PGM formats are supported.\n * The PBMPLUS library is NOT required to compile this software\n * (but it is highly useful as a set of PPM image manipulation programs).\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume output to\n * an ordinary stdio stream.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef PPM_SUPPORTED\n\n\n/*\n * For 12-bit JPEG data, we either downscale the values to 8 bits\n * (to write standard byte-per-sample PPM/PGM files), or output\n * nonstandard word-per-sample PPM/PGM files.  Downscaling is done\n * if PPM_NORAWWORD is defined (this can be done in the Makefile\n * or in jconfig.h).\n * (When the core library supports data precision reduction, a cleaner\n * implementation will be to ask for that instead.)\n */\n\n#if BITS_IN_JSAMPLE == 8\n#define PUTPPMSAMPLE(ptr,v)  *ptr++ = (char) (v)\n#define BYTESPERSAMPLE 1\n#define PPM_MAXVAL 255\n#else\n#ifdef PPM_NORAWWORD\n#define PUTPPMSAMPLE(ptr,v)  *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8))\n#define BYTESPERSAMPLE 1\n#define PPM_MAXVAL 255\n#else\n/* The word-per-sample format always puts the MSB first. */\n#define PUTPPMSAMPLE(ptr,v)\t\t\t\\\n\t{ register int val_ = v;\t\t\\\n\t  *ptr++ = (char) ((val_ >> 8) & 0xFF);\t\\\n\t  *ptr++ = (char) (val_ & 0xFF);\t\\\n\t}\n#define BYTESPERSAMPLE 2\n#define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1)\n#endif\n#endif\n\n\n/*\n * When JSAMPLE is the same size as char, we can just fwrite() the\n * decompressed data to the PPM or PGM file.  On PCs, in order to make this\n * work the output buffer must be allocated in near data space, because we are\n * assuming small-data memory model wherein fwrite() can't reach far memory.\n * If you need to process very wide images on a PC, you might have to compile\n * in large-memory model, or else replace fwrite() with a putc() loop ---\n * which will be much slower.\n */\n\n\n/* Private version of data destination object */\n\ntypedef struct {\n  struct djpeg_dest_struct pub;\t/* public fields */\n\n  /* Usually these two pointers point to the same place: */\n  char *iobuffer;\t\t/* fwrite's I/O buffer */\n  JSAMPROW pixrow;\t\t/* decompressor output buffer */\n  size_t buffer_width;\t\t/* width of I/O buffer */\n  JDIMENSION samples_per_row;\t/* JSAMPLEs per output row */\n} ppm_dest_struct;\n\ntypedef ppm_dest_struct * ppm_dest_ptr;\n\n\n/*\n * Write some pixel data.\n * In this module rows_supplied will always be 1.\n *\n * put_pixel_rows handles the \"normal\" 8-bit case where the decompressor\n * output buffer is physically the same as the fwrite buffer.\n */\n\nMETHODDEF(void)\nput_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\tJDIMENSION rows_supplied)\n{\n  ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;\n\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\n\n/*\n * This code is used when we have to copy the data and apply a pixel\n * format translation.  Typically this only happens in 12-bit mode.\n */\n\nMETHODDEF(void)\ncopy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t JDIMENSION rows_supplied)\n{\n  ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;\n  register char * bufferptr;\n  register JSAMPROW ptr;\n  register JDIMENSION col;\n\n  ptr = dest->pixrow;\n  bufferptr = dest->iobuffer;\n  for (col = dest->samples_per_row; col > 0; col--) {\n    PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\n\n/*\n * Write some pixel data when color quantization is in effect.\n * We have to demap the color index values to straight data.\n */\n\nMETHODDEF(void)\nput_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t  JDIMENSION rows_supplied)\n{\n  ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;\n  register char * bufferptr;\n  register int pixval;\n  register JSAMPROW ptr;\n  register JSAMPROW color_map0 = cinfo->colormap[0];\n  register JSAMPROW color_map1 = cinfo->colormap[1];\n  register JSAMPROW color_map2 = cinfo->colormap[2];\n  register JDIMENSION col;\n\n  ptr = dest->pixrow;\n  bufferptr = dest->iobuffer;\n  for (col = cinfo->output_width; col > 0; col--) {\n    pixval = GETJSAMPLE(*ptr++);\n    PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval]));\n    PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval]));\n    PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval]));\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\nMETHODDEF(void)\nput_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t   JDIMENSION rows_supplied)\n{\n  ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;\n  register char * bufferptr;\n  register JSAMPROW ptr;\n  register JSAMPROW color_map0 = cinfo->colormap[0];\n  register JDIMENSION col;\n\n  ptr = dest->pixrow;\n  bufferptr = dest->iobuffer;\n  for (col = cinfo->output_width; col > 0; col--) {\n    PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[GETJSAMPLE(*ptr++)]));\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\n\n/*\n * Startup: write the file header.\n */\n\nMETHODDEF(void)\nstart_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  /* Emit file header */\n  switch (cinfo->out_color_space) {\n  case JCS_GRAYSCALE:\n    /* emit header for raw PGM format */\n    fprintf(dinfo->output_file, \"P5\\n%ld %ld\\n%d\\n\",\n\t    (long) cinfo->output_width, (long) cinfo->output_height,\n\t    PPM_MAXVAL);\n    break;\n  case JCS_RGB:\n    /* emit header for raw PPM format */\n    fprintf(dinfo->output_file, \"P6\\n%ld %ld\\n%d\\n\",\n\t    (long) cinfo->output_width, (long) cinfo->output_height,\n\t    PPM_MAXVAL);\n    break;\n  default:\n    ERREXIT(cinfo, JERR_PPM_COLORSPACE);\n  }\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  /* Make sure we wrote the output file OK */\n  JFFLUSH(dinfo->output_file);\n  if (JFERROR(dinfo->output_file))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * The module selection routine for PPM format output.\n */\n\nGLOBAL(djpeg_dest_ptr)\njinit_write_ppm (j_decompress_ptr cinfo)\n{\n  ppm_dest_ptr dest;\n\n  /* Create module interface object, fill in method pointers */\n  dest = (ppm_dest_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(ppm_dest_struct));\n  dest->pub.start_output = start_output_ppm;\n  dest->pub.finish_output = finish_output_ppm;\n\n  /* Calculate output image dimensions so we can allocate space */\n  jpeg_calc_output_dimensions(cinfo);\n\n  /* Create physical I/O buffer.  Note we make this near on a PC. */\n  dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;\n  dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char));\n  dest->iobuffer = (char *) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);\n\n  if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||\n      SIZEOF(JSAMPLE) != SIZEOF(char)) {\n    /* When quantizing, we need an output buffer for colormap indexes\n     * that's separate from the physical I/O buffer.  We also need a\n     * separate buffer if pixel format translation must take place.\n     */\n    dest->pixrow = (JSAMPROW) (*cinfo->mem->alloc_large)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, (size_t) cinfo->output_width *\n       (size_t) cinfo->output_components * SIZEOF(JSAMPLE));\n    if (! cinfo->quantize_colors)\n      dest->pub.put_pixel_rows = copy_pixel_rows;\n    else if (cinfo->out_color_space == JCS_GRAYSCALE)\n      dest->pub.put_pixel_rows = put_demapped_gray;\n    else\n      dest->pub.put_pixel_rows = put_demapped_rgb;\n  } else {\n    /* We will fwrite() directly from decompressor output buffer. */\n    /* Cast here implies near->far pointer conversion on PCs */\n    dest->pixrow = (JSAMPROW) dest->iobuffer;\n    dest->pub.put_pixel_rows = put_pixel_rows;\n  }\n  /* Synthesize a JSAMPARRAY pointer structure */\n  dest->pub.buffer = & dest->pixrow;\n  dest->pub.buffer_height = 1;\n\n  return &dest->pub;\n}\n\n#endif /* PPM_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/wrrle.c",
    "content": "/*\n * wrrle.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2017-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write output images in RLE format.\n * The Utah Raster Toolkit library is required (version 3.1 or later).\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume output to\n * an ordinary stdio stream.\n *\n * Based on code contributed by Mike Lijewski,\n * with updates from Robert Hutchinson.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef RLE_SUPPORTED\n\n/* rle.h is provided by the Utah Raster Toolkit. */\n\n#include <rle.h>\n\n/*\n * We assume that JSAMPLE has the same representation as rle_pixel,\n * to wit, \"unsigned char\".  Hence we can't cope with 12- or 16-bit samples.\n */\n\n#if BITS_IN_JSAMPLE != 8\n  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */\n#endif\n\n\n/*\n * Since RLE stores scanlines bottom-to-top, we have to invert the image\n * from JPEG's top-to-bottom order.  To do this, we save the outgoing data\n * in a virtual array during put_pixel_row calls, then actually emit the\n * RLE file during finish_output.\n */\n\n\n/*\n * For now, if we emit an RLE color map then it is always 256 entries long,\n * though not all of the entries need be used.\n */\n\n#define CMAPBITS\t8\n#define CMAPLENGTH\t(1<<(CMAPBITS))\n\ntypedef struct {\n  struct djpeg_dest_struct pub; /* public fields */\n\n  jvirt_sarray_ptr image;\t/* virtual array to store the output image */\n  rle_map *colormap;\t \t/* RLE-style color map, or NULL if none */\n  rle_pixel **rle_row;\t\t/* To pass rows to rle_putrow() */\n\n} rle_dest_struct;\n\ntypedef rle_dest_struct * rle_dest_ptr;\n\n\n/* Forward declarations */\nMETHODDEF(void) rle_put_pixel_rows\n    JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t JDIMENSION rows_supplied));\n\n\n/*\n * Write the file header.\n *\n * In this module it's easier to wait till finish_output to write anything.\n */\n\nMETHODDEF(void)\nstart_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  rle_dest_ptr dest = (rle_dest_ptr) dinfo;\n  size_t cmapsize;\n  int ci, i;\n#ifdef PROGRESS_REPORT\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n#endif\n\n  /*\n   * Make sure the image can be stored in RLE format.\n   *\n   * - RLE stores image dimensions as *signed* 16 bit integers.  JPEG\n   *   uses unsigned, so we have to check the width.\n   *\n   * - Colorspace is expected to be grayscale or RGB.\n   *\n   * - The number of channels (components) is expected to be 1 (grayscale/\n   *   pseudocolor) or 3 (truecolor/directcolor).\n   *   (could be 2 or 4 if using an alpha channel, but we aren't)\n   */\n\n  if (cinfo->output_width > 32767 || cinfo->output_height > 32767)\n    ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width, \n\t     cinfo->output_height);\n\n  if (cinfo->out_color_space != JCS_GRAYSCALE &&\n      cinfo->out_color_space != JCS_RGB)\n    ERREXIT(cinfo, JERR_RLE_COLORSPACE);\n\n  if (cinfo->output_components != 1 && cinfo->output_components != 3)\n    ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);\n\n  /* Convert colormap, if any, to RLE format. */\n\n  dest->colormap = NULL;\n\n  if (cinfo->quantize_colors) {\n    /* Allocate storage for RLE-style cmap, zero any extra entries */\n    cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);\n    dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)\n      ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);\n    MEMZERO(dest->colormap, cmapsize);\n\n    /* Save away data in RLE format --- note 8-bit left shift! */\n    /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */\n    for (ci = 0; ci < cinfo->out_color_components; ci++) {\n      for (i = 0; i < cinfo->actual_number_of_colors; i++) {\n\tdest->colormap[ci * CMAPLENGTH + i] =\n\t  GETJSAMPLE(cinfo->colormap[ci][i]) << 8;\n      }\n    }\n  }\n\n  /* Set the output buffer to the first row */\n  dest->pub.buffer = (*cinfo->mem->access_virt_sarray)\n    ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);\n  dest->pub.buffer_height = 1;\n\n  dest->pub.put_pixel_rows = rle_put_pixel_rows;\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL) {\n    progress->total_extra_passes++;  /* count file writing as separate pass */\n  }\n#endif\n}\n\n\n/*\n * Write some pixel data.\n *\n * This routine just saves the data away in a virtual array.\n */\n\nMETHODDEF(void)\nrle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t    JDIMENSION rows_supplied)\n{\n  rle_dest_ptr dest = (rle_dest_ptr) dinfo;\n\n  if (cinfo->output_scanline < cinfo->output_height) {\n    dest->pub.buffer = (*cinfo->mem->access_virt_sarray)\n      ((j_common_ptr) cinfo, dest->image,\n       cinfo->output_scanline, (JDIMENSION) 1, TRUE);\n  }\n}\n\n\n/*\n * Finish up at the end of the file.\n *\n * Here is where we really output the RLE file.\n */\n\nMETHODDEF(void)\nfinish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  rle_dest_ptr dest = (rle_dest_ptr) dinfo;\n  rle_hdr header;\t\t/* Output file information */\n  rle_pixel **rle_row, *red_ptr, *green_ptr, *blue_ptr;\n  JSAMPROW output_row;\n  char cmapcomment[80];\n  int row, col;\n  int ci;\n#ifdef PROGRESS_REPORT\n  cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;\n#endif\n\n  /* Initialize the header info */\n  header = *rle_hdr_init(NULL);\n  header.rle_file = dest->pub.output_file;\n  header.xmin     = 0;\n  header.xmax     = cinfo->output_width  - 1;\n  header.ymin     = 0;\n  header.ymax     = cinfo->output_height - 1;\n  header.alpha    = 0;\n  header.ncolors  = cinfo->output_components;\n  for (ci = 0; ci < cinfo->output_components; ci++) {\n    RLE_SET_BIT(header, ci);\n  }\n  if (cinfo->quantize_colors) {\n    header.ncmap   = cinfo->out_color_components;\n    header.cmaplen = CMAPBITS;\n    header.cmap    = dest->colormap;\n    /* Add a comment to the output image with the true colormap length. */\n    sprintf(cmapcomment, \"color_map_length=%d\", cinfo->actual_number_of_colors);\n    rle_putcom(cmapcomment, &header);\n  }\n\n  /* Emit the RLE header and color map (if any) */\n  rle_put_setup(&header);\n\n  /* Now output the RLE data from our virtual array.\n   * We assume here that (a) rle_pixel is represented the same as JSAMPLE,\n   * and (b) we are not on a machine where FAR pointers differ from regular.\n   */\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL) {\n    progress->pub.pass_limit = cinfo->output_height;\n    progress->pub.pass_counter = 0;\n    (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n  }\n#endif\n\n  if (cinfo->output_components == 1) {\n    for (row = cinfo->output_height - 1; row >= 0; row--) {\n      rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, dest->image,\n\t (JDIMENSION) row, (JDIMENSION) 1, FALSE);\n      rle_putrow(rle_row, (int) cinfo->output_width, &header);\n#ifdef PROGRESS_REPORT\n      if (progress != NULL) {\n\tprogress->pub.pass_counter++;\n\t(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n      }\n#endif\n    }\n  } else {\n    for (row = cinfo->output_height - 1; row >= 0; row--) {\n      output_row = * (*cinfo->mem->access_virt_sarray)\n\t((j_common_ptr) cinfo, dest->image,\n\t (JDIMENSION) row, (JDIMENSION) 1, FALSE);\n      rle_row = dest->rle_row;\n      red_ptr   = rle_row[0];\n      green_ptr = rle_row[1];\n      blue_ptr  = rle_row[2];\n      for (col = cinfo->output_width; col > 0; col--) {\n\t*red_ptr++   = GETJSAMPLE(*output_row++);\n\t*green_ptr++ = GETJSAMPLE(*output_row++);\n\t*blue_ptr++  = GETJSAMPLE(*output_row++);\n      }\n      rle_putrow(rle_row, (int) cinfo->output_width, &header);\n#ifdef PROGRESS_REPORT\n      if (progress != NULL) {\n\tprogress->pub.pass_counter++;\n\t(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);\n      }\n#endif\n    }\n  }\n\n#ifdef PROGRESS_REPORT\n  if (progress != NULL)\n    progress->completed_extra_passes++;\n#endif\n\n  /* Emit file trailer */\n  rle_puteof(&header);\n  JFFLUSH(dest->pub.output_file);\n  if (JFERROR(dest->pub.output_file))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * The module selection routine for RLE format output.\n */\n\nGLOBAL(djpeg_dest_ptr)\njinit_write_rle (j_decompress_ptr cinfo)\n{\n  rle_dest_ptr dest;\n\n  /* Create module interface object, fill in method pointers */\n  dest = (rle_dest_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_dest_struct));\n  dest->pub.start_output = start_output_rle;\n  dest->pub.finish_output = finish_output_rle;\n\n  /* Calculate output image dimensions so we can allocate space */\n  jpeg_calc_output_dimensions(cinfo);\n\n  /* Allocate a work array for output to the RLE library. */\n  dest->rle_row = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) cinfo->output_components);\n\n  /* Allocate a virtual array to hold the image. */\n  dest->image = (*cinfo->mem->request_virt_sarray)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,\n     cinfo->output_width * (JDIMENSION) cinfo->output_components,\n     cinfo->output_height, (JDIMENSION) 1);\n\n  return &dest->pub;\n}\n\n#endif /* RLE_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libjpeg/wrtarga.c",
    "content": "/*\n * wrtarga.c\n *\n * Copyright (C) 1991-1996, Thomas G. Lane.\n * Modified 2015-2019 by Guido Vollbeding.\n * This file is part of the Independent JPEG Group's software.\n * For conditions of distribution and use, see the accompanying README file.\n *\n * This file contains routines to write output images in Targa format.\n *\n * These routines may need modification for non-Unix environments or\n * specialized applications.  As they stand, they assume output to\n * an ordinary stdio stream.\n *\n * Based on code contributed by Lee Daniel Crocker.\n */\n\n#include \"cdjpeg.h\"\t\t/* Common decls for cjpeg/djpeg applications */\n\n#ifdef TARGA_SUPPORTED\n\n\n/*\n * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.\n * This is not yet implemented.\n */\n\n#if BITS_IN_JSAMPLE != 8\n  Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */\n#endif\n\n/*\n * The output buffer needs to be writable by fwrite().  On PCs, we must\n * allocate the buffer in near data space, because we are assuming small-data\n * memory model, wherein fwrite() can't reach far memory.  If you need to\n * process very wide images on a PC, you might have to compile in large-memory\n * model, or else replace fwrite() with a putc() loop --- which will be much\n * slower.\n */\n\n\n/* Private version of data destination object */\n\ntypedef struct {\n  struct djpeg_dest_struct pub;\t/* public fields */\n\n  char *iobuffer;\t\t/* physical I/O buffer */\n  JDIMENSION buffer_width;\t/* width of one row */\n} tga_dest_struct;\n\ntypedef tga_dest_struct * tga_dest_ptr;\n\n\nLOCAL(void)\nwrite_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors)\n/* Create and write a Targa header */\n{\n  char targaheader[18];\n\n  /* Set unused fields of header to 0 */\n  MEMZERO(targaheader, SIZEOF(targaheader));\n\n  if (num_colors > 0) {\n    targaheader[1] = 1;\t\t/* color map type 1 */\n    targaheader[5] = (char) (num_colors & 0xFF);\n    targaheader[6] = (char) (num_colors >> 8);\n    targaheader[7] = 24;\t/* 24 bits per cmap entry */\n  }\n\n  targaheader[12] = (char) (cinfo->output_width & 0xFF);\n  targaheader[13] = (char) (cinfo->output_width >> 8);\n  targaheader[14] = (char) (cinfo->output_height & 0xFF);\n  targaheader[15] = (char) (cinfo->output_height >> 8);\n  targaheader[17] = 0x20;\t/* Top-down, non-interlaced */\n\n  if (cinfo->out_color_space == JCS_GRAYSCALE) {\n    targaheader[2] = 3;\t\t/* image type = uncompressed grayscale */\n    targaheader[16] = 8;\t/* bits per pixel */\n  } else {\t\t\t/* must be RGB */\n    if (num_colors > 0) {\n      targaheader[2] = 1;\t/* image type = colormapped RGB */\n      targaheader[16] = 8;\n    } else {\n      targaheader[2] = 2;\t/* image type = uncompressed RGB */\n      targaheader[16] = 24;\n    }\n  }\n\n  if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18)\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * Write some pixel data.\n * In this module rows_supplied will always be 1.\n */\n\nMETHODDEF(void)\nput_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\tJDIMENSION rows_supplied)\n/* used for unquantized full-color output */\n{\n  tga_dest_ptr dest = (tga_dest_ptr) dinfo;\n  register JSAMPROW inptr;\n  register char * outptr;\n  register JDIMENSION col;\n\n  inptr = dest->pub.buffer[0];\n  outptr = dest->iobuffer;\n  for (col = cinfo->output_width; col > 0; col--) {\n    outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */\n    outptr[1] = (char) GETJSAMPLE(inptr[1]);\n    outptr[2] = (char) GETJSAMPLE(inptr[0]);\n    inptr += 3, outptr += 3;\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\nMETHODDEF(void)\nput_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t       JDIMENSION rows_supplied)\n/* used for grayscale OR quantized color output */\n{\n  tga_dest_ptr dest = (tga_dest_ptr) dinfo;\n  register JSAMPROW inptr;\n  register char * outptr;\n  register JDIMENSION col;\n\n  inptr = dest->pub.buffer[0];\n  outptr = dest->iobuffer;\n  for (col = cinfo->output_width; col > 0; col--) {\n    *outptr++ = (char) GETJSAMPLE(*inptr++);\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\n\n/*\n * Write some demapped pixel data when color quantization is in effect.\n * For Targa, this is only applied to grayscale data.\n */\n\nMETHODDEF(void)\nput_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,\n\t\t   JDIMENSION rows_supplied)\n{\n  tga_dest_ptr dest = (tga_dest_ptr) dinfo;\n  register JSAMPROW inptr;\n  register char * outptr;\n  register JSAMPROW color_map0 = cinfo->colormap[0];\n  register JDIMENSION col;\n\n  inptr = dest->pub.buffer[0];\n  outptr = dest->iobuffer;\n  for (col = cinfo->output_width; col > 0; col--) {\n    *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]);\n  }\n  (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);\n}\n\n\n/*\n * Startup: write the file header.\n */\n\nMETHODDEF(void)\nstart_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  int num_colors, i;\n  FILE *outfile;\n\n  switch (cinfo->out_color_space) {\n  case JCS_GRAYSCALE:\n    /* Targa doesn't have a mapped grayscale format, so we will */\n    /* demap quantized gray output.  Never emit a colormap. */\n    write_header(cinfo, dinfo, 0);\n    if (cinfo->quantize_colors)\n      dinfo->put_pixel_rows = put_demapped_gray;\n    else\n      dinfo->put_pixel_rows = put_gray_rows;\n    break;\n  case JCS_RGB:\n    if (cinfo->quantize_colors) {\n      /* We only support 8-bit colormap indexes, so only 256 colors */\n      num_colors = cinfo->actual_number_of_colors;\n      if (num_colors > 256)\n\tERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors);\n      write_header(cinfo, dinfo, num_colors);\n      /* Write the colormap.  Note Targa uses BGR byte order */\n      outfile = dinfo->output_file;\n      for (i = 0; i < num_colors; i++) {\n\tputc(GETJSAMPLE(cinfo->colormap[2][i]), outfile);\n\tputc(GETJSAMPLE(cinfo->colormap[1][i]), outfile);\n\tputc(GETJSAMPLE(cinfo->colormap[0][i]), outfile);\n      }\n      dinfo->put_pixel_rows = put_gray_rows;\n    } else {\n      write_header(cinfo, dinfo, 0);\n      dinfo->put_pixel_rows = put_pixel_rows;\n    }\n    break;\n  default:\n    ERREXIT(cinfo, JERR_TGA_COLORSPACE);\n  }\n}\n\n\n/*\n * Finish up at the end of the file.\n */\n\nMETHODDEF(void)\nfinish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)\n{\n  /* Make sure we wrote the output file OK */\n  JFFLUSH(dinfo->output_file);\n  if (JFERROR(dinfo->output_file))\n    ERREXIT(cinfo, JERR_FILE_WRITE);\n}\n\n\n/*\n * The module selection routine for Targa format output.\n */\n\nGLOBAL(djpeg_dest_ptr)\njinit_write_targa (j_decompress_ptr cinfo)\n{\n  tga_dest_ptr dest;\n\n  /* Create module interface object, fill in method pointers */\n  dest = (tga_dest_ptr) (*cinfo->mem->alloc_small)\n    ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(tga_dest_struct));\n  dest->pub.start_output = start_output_tga;\n  dest->pub.finish_output = finish_output_tga;\n\n  /* Calculate output image dimensions so we can allocate space */\n  jpeg_calc_output_dimensions(cinfo);\n\n  /* Create I/O buffer.  Note we make this near on a PC. */\n  dest->buffer_width = cinfo->output_width * cinfo->output_components;\n  dest->iobuffer = (char *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, (size_t) dest->buffer_width * SIZEOF(char));\n\n  /* Create decompressor output buffer. */\n  dest->pub.buffer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo,\n    JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1);\n  dest->pub.buffer_height = 1;\n\n  return &dest->pub;\n}\n\n#endif /* TARGA_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libpng/LICENSE",
    "content": "\nThis copy of the libpng notices is provided for your convenience.  In case of\nany discrepancy between this copy and the notices in the file png.h that is\nincluded in the libpng distribution, the latter shall prevail.\n\nCOPYRIGHT NOTICE, DISCLAIMER, and LICENSE:\n\nIf you modify libpng you may insert additional notices immediately following\nthis sentence.\n\nThis code is released under the libpng license.\n\nlibpng versions 1.2.6, August 15, 2004, through 1.6.7, November 14, 2013, are\nCopyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are\ndistributed according to the same disclaimer and license as libpng-1.2.5\nwith the following individual added to the list of Contributing Authors\n\n   Cosmin Truta\n\nlibpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are\nCopyright (c) 2000-2002 Glenn Randers-Pehrson, and are\ndistributed according to the same disclaimer and license as libpng-1.0.6\nwith the following individuals added to the list of Contributing Authors\n\n   Simon-Pierre Cadieux\n   Eric S. Raymond\n   Gilles Vollant\n\nand with the following additions to the disclaimer:\n\n   There is no warranty against interference with your enjoyment of the\n   library or against infringement.  There is no warranty that our\n   efforts or the library will fulfill any of your particular purposes\n   or needs.  This library is provided with all faults, and the entire\n   risk of satisfactory quality, performance, accuracy, and effort is with\n   the user.\n\nlibpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\nCopyright (c) 1998, 1999 Glenn Randers-Pehrson, and are\ndistributed according to the same disclaimer and license as libpng-0.96,\nwith the following individuals added to the list of Contributing Authors:\n\n   Tom Lane\n   Glenn Randers-Pehrson\n   Willem van Schaik\n\nlibpng versions 0.89, June 1996, through 0.96, May 1997, are\nCopyright (c) 1996, 1997 Andreas Dilger\nDistributed according to the same disclaimer and license as libpng-0.88,\nwith the following individuals added to the list of Contributing Authors:\n\n   John Bowler\n   Kevin Bracey\n   Sam Bushell\n   Magnus Holmgren\n   Greg Roelofs\n   Tom Tanner\n\nlibpng versions 0.5, May 1995, through 0.88, January 1996, are\nCopyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.\n\nFor the purposes of this copyright and license, \"Contributing Authors\"\nis defined as the following set of individuals:\n\n   Andreas Dilger\n   Dave Martindale\n   Guy Eric Schalnat\n   Paul Schmidt\n   Tim Wegner\n\nThe PNG Reference Library is supplied \"AS IS\".  The Contributing Authors\nand Group 42, Inc. disclaim all warranties, expressed or implied,\nincluding, without limitation, the warranties of merchantability and of\nfitness for any purpose.  The Contributing Authors and Group 42, Inc.\nassume no liability for direct, indirect, incidental, special, exemplary,\nor consequential damages, which may result from the use of the PNG\nReference Library, even if advised of the possibility of such damage.\n\nPermission is hereby granted to use, copy, modify, and distribute this\nsource code, or portions hereof, for any purpose, without fee, subject\nto the following restrictions:\n\n1. The origin of this source code must not be misrepresented.\n\n2. Altered versions must be plainly marked as such and must not\n   be misrepresented as being the original source.\n\n3. This Copyright notice may not be removed or altered from any\n   source or altered source distribution.\n\nThe Contributing Authors and Group 42, Inc. specifically permit, without\nfee, and encourage the use of this source code as a component to\nsupporting the PNG file format in commercial products.  If you use this\nsource code in a product, acknowledgment is not required but would be\nappreciated.\n\n\nA \"png_get_copyright\" function is available, for convenient use in \"about\"\nboxes and the like:\n\n   printf(\"%s\",png_get_copyright(NULL));\n\nAlso, the PNG logo (in PNG format, of course) is supplied in the\nfiles \"pngbar.png\" and \"pngbar.jpg (88x31) and \"pngnow.png\" (98x31).\n\nLibpng is OSI Certified Open Source Software.  OSI Certified Open Source is a\ncertification mark of the Open Source Initiative.\n\nGlenn Randers-Pehrson\nglennrp at users.sourceforge.net\nNovember 14, 2013\n"
  },
  {
    "path": "dlib/external/libpng/README",
    "content": "README for libpng version 1.6.37 - April 14, 2019\n=================================================\n\nSee the note about version numbers near the top of png.h.\nSee INSTALL for instructions on how to install libpng.\n\nLibpng comes in several distribution formats.  Get libpng-*.tar.gz or\nlibpng-*.tar.xz or if you want UNIX-style line endings in the text\nfiles, or lpng*.7z or lpng*.zip if you want DOS-style line endings.\n\nVersion 0.89 was the first official release of libpng.  Don't let the\nfact that it's the first release fool you.  The libpng library has been\nin extensive use and testing since mid-1995.  By late 1997 it had\nfinally gotten to the stage where there hadn't been significant\nchanges to the API in some time, and people have a bad feeling about\nlibraries with versions < 1.0.  Version 1.0.0 was released in\nMarch 1998.\n\n****\nNote that some of the changes to the png_info structure render this\nversion of the library binary incompatible with libpng-0.89 or\nearlier versions if you are using a shared library.  The type of the\n\"filler\" parameter for png_set_filler() has changed from png_byte to\npng_uint_32, which will affect shared-library applications that use\nthis function.\n\nTo avoid problems with changes to the internals of the png info_struct,\nnew APIs have been made available in 0.95 to avoid direct application\naccess to info_ptr.  These functions are the png_set_<chunk> and\npng_get_<chunk> functions.  These functions should be used when\naccessing/storing the info_struct data, rather than manipulating it\ndirectly, to avoid such problems in the future.\n\nIt is important to note that the APIs did not make current programs\nthat access the info struct directly incompatible with the new\nlibrary, through libpng-1.2.x.  In libpng-1.4.x, which was meant to\nbe a transitional release, members of the png_struct and the\ninfo_struct can still be accessed, but the compiler will issue a\nwarning about deprecated usage.  Since libpng-1.5.0, direct access\nto these structs is not allowed, and the definitions of the structs\nreside in private pngstruct.h and pnginfo.h header files that are not\naccessible to applications.  It is strongly suggested that new\nprograms use the new APIs (as shown in example.c and pngtest.c), and\nolder programs be converted to the new format, to facilitate upgrades\nin the future.\n****\n\nAdditions since 0.90 include the ability to compile libpng as a\nWindows DLL, and new APIs for accessing data in the info struct.\nExperimental functions include the ability to set weighting and cost\nfactors for row filter selection, direct reads of integers from buffers\non big-endian processors that support misaligned data access, faster\nmethods of doing alpha composition, and more accurate 16->8 bit color\nconversion.\n\nThe additions since 0.89 include the ability to read from a PNG stream\nwhich has had some (or all) of the signature bytes read by the calling\napplication.  This also allows the reading of embedded PNG streams that\ndo not have the PNG file signature.  As well, it is now possible to set\nthe library action on the detection of chunk CRC errors.  It is possible\nto set different actions based on whether the CRC error occurred in a\ncritical or an ancillary chunk.\n\nFor a detailed description on using libpng, read libpng-manual.txt.\nFor examples of libpng in a program, see example.c and pngtest.c.  For\nusage information and restrictions (what little they are) on libpng,\nsee png.h.  For a description on using zlib (the compression library\nused by libpng) and zlib's restrictions, see zlib.h\n\nI have included a general makefile, as well as several machine and\ncompiler specific ones, but you may have to modify one for your own\nneeds.\n\nYou should use zlib 1.0.4 or later to run this, but it MAY work with\nversions as old as zlib 0.95.  Even so, there are bugs in older zlib\nversions which can cause the output of invalid compression streams for\nsome images.\n\nYou should also note that zlib is a compression library that is useful\nfor more things than just PNG files.  You can use zlib as a drop-in\nreplacement for fread() and fwrite(), if you are so inclined.\n\nzlib should be available at the same place that libpng is, or at\nhttps://zlib.net.\n\nYou may also want a copy of the PNG specification.  It is available\nas an RFC, a W3C Recommendation, and an ISO/IEC Standard.  You can find\nthese at http://www.libpng.org/pub/png/pngdocs.html .\n\nThis code is currently being archived at libpng.sourceforge.io in the\n[DOWNLOAD] area, and at http://libpng.download/src .\n\nThis release, based in a large way on Glenn's, Guy's and Andreas'\nearlier work, was created and will be supported by myself and the PNG\ndevelopment group.\n\nSend comments/corrections/commendations to png-mng-implement at\nlists.sourceforge.net (subscription required; visit\nhttps://lists.sourceforge.net/lists/listinfo/png-mng-implement\nto subscribe).\n\nSend general questions about the PNG specification to png-mng-misc\nat lists.sourceforge.net (subscription required; visit\nhttps://lists.sourceforge.net/lists/listinfo/png-mng-misc to\nsubscribe).\n\nFiles in this distribution:\n\n      ANNOUNCE      =>  Announcement of this version, with recent changes\n      AUTHORS       =>  List of contributing authors\n      CHANGES       =>  Description of changes between libpng versions\n      KNOWNBUG      =>  List of known bugs and deficiencies\n      LICENSE       =>  License to use and redistribute libpng\n      README        =>  This file\n      TODO          =>  Things not implemented in the current library\n      TRADEMARK     =>  Trademark information\n      example.c     =>  Example code for using libpng functions\n      libpng.3      =>  manual page for libpng (includes libpng-manual.txt)\n      libpng-manual.txt  =>  Description of libpng and its functions\n      libpngpf.3    =>  manual page for libpng's private functions\n      png.5         =>  manual page for the PNG format\n      png.c         =>  Basic interface functions common to library\n      png.h         =>  Library function and interface declarations (public)\n      pngpriv.h     =>  Library function and interface declarations (private)\n      pngconf.h     =>  System specific library configuration (public)\n      pngstruct.h   =>  png_struct declaration (private)\n      pnginfo.h     =>  png_info struct declaration (private)\n      pngdebug.h    =>  debugging macros (private)\n      pngerror.c    =>  Error/warning message I/O functions\n      pngget.c      =>  Functions for retrieving info from struct\n      pngmem.c      =>  Memory handling functions\n      pngbar.png    =>  PNG logo, 88x31\n      pngnow.png    =>  PNG logo, 98x31\n      pngpread.c    =>  Progressive reading functions\n      pngread.c     =>  Read data/helper high-level functions\n      pngrio.c      =>  Lowest-level data read I/O functions\n      pngrtran.c    =>  Read data transformation functions\n      pngrutil.c    =>  Read data utility functions\n      pngset.c      =>  Functions for storing data into the info_struct\n      pngtest.c     =>  Library test program\n      pngtest.png   =>  Library test sample image\n      pngtrans.c    =>  Common data transformation functions\n      pngwio.c      =>  Lowest-level write I/O functions\n      pngwrite.c    =>  High-level write functions\n      pngwtran.c    =>  Write data transformations\n      pngwutil.c    =>  Write utility functions\n      arm           =>  Contains optimized code for the ARM platform\n      powerpc       =>  Contains optimized code for the PowerPC platform\n      contrib       =>  Contributions\n       arm-neon         =>  Optimized code for ARM-NEON platform\n       powerpc-vsx      =>  Optimized code for POWERPC-VSX platform\n       examples         =>  Example programs\n       gregbook         =>  source code for PNG reading and writing, from\n                            Greg Roelofs' \"PNG: The Definitive Guide\",\n                            O'Reilly, 1999\n       libtests         =>  Test programs\n       mips-msa         =>  Optimized code for MIPS-MSA platform\n       pngminim         =>  Minimal decoder, encoder, and progressive decoder\n                            programs demonstrating use of pngusr.dfa\n       pngminus         =>  Simple pnm2png and png2pnm programs\n       pngsuite         =>  Test images\n       testpngs\n       tools            =>  Various tools\n       visupng          =>  Contains a MSVC workspace for VisualPng\n      intel             =>  Optimized code for INTEL-SSE2 platform\n      mips              =>  Optimized code for MIPS platform\n      projects      =>  Contains project files and workspaces for\n                        building a DLL\n       owatcom          =>  Contains a WATCOM project for building libpng\n       visualc71        =>  Contains a Microsoft Visual C++ (MSVC)\n                            workspace for building libpng and zlib\n       vstudio          =>  Contains a Microsoft Visual C++ (MSVC)\n                            workspace for building libpng and zlib\n      scripts       =>  Directory containing scripts for building libpng:\n                            (see scripts/README.txt for the list of scripts)\n\nGood luck, and happy coding!\n\n * Cosmin Truta (current maintainer, since 2018)\n * Glenn Randers-Pehrson (former maintainer, 1998-2018)\n * Andreas Eric Dilger (former maintainer, 1996-1997)\n * Guy Eric Schalnat (original author and former maintainer, 1995-1996)\n   (formerly of Group 42, Inc.)\n"
  },
  {
    "path": "dlib/external/libpng/arm/arm_init.c",
    "content": "\n/* arm_init.c - NEON optimised filter functions\n *\n * Copyright (c) 2013 Glenn Randers-Pehrson\n * Written by Mans Rullgard, 2011.\n * Last changed in libpng 1.6.6 [September 16, 2013]\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are\n * called.\n */\n#define _POSIX_SOURCE 1\n\n#include \"../pngpriv.h\"\n\n#ifdef PNG_READ_SUPPORTED\n#if PNG_ARM_NEON_OPT > 0\n#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */\n#include <signal.h> /* for sig_atomic_t */\n\n#ifdef __ANDROID__\n/* Linux provides access to information about CPU capabilites via\n * /proc/self/auxv, however Android blocks this while still claiming to be\n * Linux.  The Andoid NDK, however, provides appropriate support.\n *\n * Documentation: http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html\n */\n#include <cpu-features.h>\n\nstatic int\npng_have_neon(png_structp png_ptr)\n{\n   /* This is a whole lot easier than the mess below, however it is probably\n    * implemented as below, therefore it is better to cache the result (these\n    * function calls may be slow!)\n    */\n   PNG_UNUSED(png_ptr)\n   return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&\n      (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;\n}\n#elif defined(__linux__)\n/* The generic __linux__ implementation requires reading /proc/self/auxv and\n * looking at each element for one that records NEON capabilities.\n */\n#include <unistd.h> /* for POSIX 1003.1 */\n#include <errno.h>  /* for EINTR */\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n#include <elf.h>\n#include <asm/hwcap.h>\n\n/* A read call may be interrupted, in which case it returns -1 and sets errno to\n * EINTR if nothing was done, otherwise (if something was done) a partial read\n * may result.\n */\nstatic size_t\nsafe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)\n{\n   size_t ntotal = 0;\n   char *buffer = png_voidcast(char*, buffer_in);\n\n   while (nbytes > 0)\n   {\n      unsigned int nread;\n      int iread;\n\n      /* Passing nread > INT_MAX to read is implementation defined in POSIX\n       * 1003.1, therefore despite the unsigned argument portable code must\n       * limit the value to INT_MAX!\n       */\n      if (nbytes > INT_MAX)\n         nread = INT_MAX;\n\n      else\n         nread = (unsigned int)/*SAFE*/nbytes;\n\n      iread = read(fd, buffer, nread);\n\n      if (iread == -1)\n      {\n         /* This is the devil in the details, a read can terminate early with 0\n          * bytes read because of EINTR, yet it still returns -1 otherwise end\n          * of file cannot be distinguished.\n          */\n         if (errno != EINTR)\n         {\n            png_warning(png_ptr, \"/proc read failed\");\n            return 0; /* I.e. a permanent failure */\n         }\n      }\n\n      else if (iread < 0)\n      {\n         /* Not a valid 'read' result: */\n         png_warning(png_ptr, \"OS /proc read bug\");\n         return 0;\n      }\n\n      else if (iread > 0)\n      {\n         /* Continue reading until a permanent failure, or EOF */\n         buffer += iread;\n         nbytes -= (unsigned int)/*SAFE*/iread;\n         ntotal += (unsigned int)/*SAFE*/iread;\n      }\n\n      else\n         return ntotal;\n   }\n\n   return ntotal; /* nbytes == 0 */\n}\n\nstatic int\npng_have_neon(png_structp png_ptr)\n{\n   int fd = open(\"/proc/self/auxv\", O_RDONLY);\n   Elf32_auxv_t aux;\n\n   /* Failsafe: failure to open means no NEON */\n   if (fd == -1)\n   {\n      png_warning(png_ptr, \"/proc/self/auxv open failed\");\n      return 0;\n   }\n\n   while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)\n   {\n      if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)\n      {\n         close(fd);\n         return 1;\n      }\n   }\n\n   close(fd);\n   return 0;\n}\n#else\n   /* We don't know how to do a run-time check on this system */\n#  error \"no support for run-time ARM NEON checks\"\n#endif /* OS checks */\n#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */\n\n#ifndef PNG_ALIGNED_MEMORY_SUPPORTED\n#  error \"ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED\"\n#endif\n\nvoid\npng_init_filter_functions_neon(png_structp pp, unsigned int bpp)\n{\n   /* The switch statement is compiled in for ARM_NEON_API, the call to\n    * png_have_neon is compiled in for ARM_NEON_CHECK.  If both are defined\n    * the check is only performed if the API has not set the NEON option on\n    * or off explicitly.  In this case the check controls what happens.\n    *\n    * If the CHECK is not compiled in and the option is UNSET the behavior prior\n    * to 1.6.7 was to use the NEON code - this was a bug caused by having the\n    * wrong order of the 'ON' and 'default' cases.  UNSET now defaults to OFF,\n    * as documented in png.h\n    */\n#ifdef PNG_ARM_NEON_API_SUPPORTED\n   switch ((pp->options >> PNG_ARM_NEON) & 3)\n   {\n      case PNG_OPTION_UNSET:\n         /* Allow the run-time check to execute if it has been enabled -\n          * thus both API and CHECK can be turned on.  If it isn't supported\n          * this case will fall through to the 'default' below, which just\n          * returns.\n          */\n#endif /* PNG_ARM_NEON_API_SUPPORTED */\n#ifdef PNG_ARM_NEON_CHECK_SUPPORTED\n         {\n            static volatile sig_atomic_t no_neon = -1; /* not checked */\n\n            if (no_neon < 0)\n               no_neon = !png_have_neon(pp);\n\n            if (no_neon)\n               return;\n         }\n#ifdef PNG_ARM_NEON_API_SUPPORTED\n         break;\n#endif\n#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */\n\n#ifdef PNG_ARM_NEON_API_SUPPORTED\n      default: /* OFF or INVALID */\n         return;\n\n      case PNG_OPTION_ON:\n         /* Option turned on */\n         break;\n   }\n#endif\n\n   /* IMPORTANT: any new external functions used here must be declared using\n    * PNG_INTERNAL_FUNCTION in ../pngpriv.h.  This is required so that the\n    * 'prefix' option to configure works:\n    *\n    *    ./configure --with-libpng-prefix=foobar_\n    *\n    * Verify you have got this right by running the above command, doing a build\n    * and examining pngprefix.h; it must contain a #define for every external\n    * function you add.  (Notice that this happens automatically for the\n    * initialization function.)\n    */\n   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;\n\n   if (bpp == 3)\n   {\n      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;\n      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;\n      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =\n         png_read_filter_row_paeth3_neon;\n   }\n\n   else if (bpp == 4)\n   {\n      pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;\n      pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;\n      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =\n          png_read_filter_row_paeth4_neon;\n   }\n}\n#endif /* PNG_ARM_NEON_OPT > 0 */\n#endif /* PNG_READ_SUPPORTED */\n"
  },
  {
    "path": "dlib/external/libpng/arm/filter_neon.S",
    "content": "\n/* filter_neon.S - NEON optimised filter functions\n *\n * Copyright (c) 2013 Glenn Randers-Pehrson\n * Written by Mans Rullgard, 2011.\n * Last changed in libpng 1.6.7 [November 14, 2013]\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n/* This is required to get the symbol renames, which are #defines, and also\n * includes the definition (or not) of PNG_ARM_NEON_OPT.\n */\n#define PNG_VERSION_INFO_ONLY\n#include \"../pngpriv.h\"\n\n#if defined(__linux__) && defined(__ELF__)\n.section .note.GNU-stack,\"\",%progbits /* mark stack as non-executable */\n#endif\n\n/* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for\n * ARM64).  The code in arm/filter_neon_intrinsics.c supports ARM64, however it\n * only works if -mfpu=neon is specified on the GCC command line.  See pngpriv.h\n * for the logic which sets PNG_USE_ARM_NEON_ASM:\n */\n#if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */\n\n#ifdef PNG_READ_SUPPORTED\n#if PNG_ARM_NEON_OPT > 0\n\n#ifdef __ELF__\n#   define ELF\n#else\n#   define ELF @\n#endif\n\n        .arch armv7-a\n        .fpu  neon\n\n.macro  func    name, export=0\n    .macro endfunc\nELF     .size   \\name, . - \\name\n        .endfunc\n        .purgem endfunc\n    .endm\n        .text\n    .if \\export\n        .global \\name\n    .endif\nELF     .type   \\name, STT_FUNC\n        .func   \\name\n\\name:\n.endm\n\nfunc    png_read_filter_row_sub4_neon, export=1\n        ldr             r3,  [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n1:\n        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]\n        vadd.u8         d0,  d3,  d4\n        vadd.u8         d1,  d0,  d5\n        vadd.u8         d2,  d1,  d6\n        vadd.u8         d3,  d2,  d7\n        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!\n        subs            r3,  r3,  #16\n        bgt             1b\n\n        bx              lr\nendfunc\n\nfunc    png_read_filter_row_sub3_neon, export=1\n        ldr             r3,  [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n        mov             r0,  r1\n        mov             r2,  #3\n        mov             r12, #12\n        vld1.8          {q11},    [r0], r12\n1:\n        vext.8          d5,  d22, d23, #3\n        vadd.u8         d0,  d3,  d22\n        vext.8          d6,  d22, d23, #6\n        vadd.u8         d1,  d0,  d5\n        vext.8          d7,  d23, d23, #1\n        vld1.8          {q11},    [r0], r12\n        vst1.32         {d0[0]},  [r1,:32], r2\n        vadd.u8         d2,  d1,  d6\n        vst1.32         {d1[0]},  [r1], r2\n        vadd.u8         d3,  d2,  d7\n        vst1.32         {d2[0]},  [r1], r2\n        vst1.32         {d3[0]},  [r1], r2\n        subs            r3,  r3,  #12\n        bgt             1b\n\n        bx              lr\nendfunc\n\nfunc    png_read_filter_row_up_neon, export=1\n        ldr             r3,  [r0, #4]           @ rowbytes\n1:\n        vld1.8          {q0}, [r1,:128]\n        vld1.8          {q1}, [r2,:128]!\n        vadd.u8         q0,  q0,  q1\n        vst1.8          {q0}, [r1,:128]!\n        subs            r3,  r3,  #16\n        bgt             1b\n\n        bx              lr\nendfunc\n\nfunc    png_read_filter_row_avg4_neon, export=1\n        ldr             r12, [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n1:\n        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]\n        vld4.32         {d16[],d17[],d18[],d19[]},[r2,:128]!\n        vhadd.u8        d0,  d3,  d16\n        vadd.u8         d0,  d0,  d4\n        vhadd.u8        d1,  d0,  d17\n        vadd.u8         d1,  d1,  d5\n        vhadd.u8        d2,  d1,  d18\n        vadd.u8         d2,  d2,  d6\n        vhadd.u8        d3,  d2,  d19\n        vadd.u8         d3,  d3,  d7\n        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!\n        subs            r12, r12, #16\n        bgt             1b\n\n        bx              lr\nendfunc\n\nfunc    png_read_filter_row_avg3_neon, export=1\n        push            {r4,lr}\n        ldr             r12, [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n        mov             r0,  r1\n        mov             r4,  #3\n        mov             lr,  #12\n        vld1.8          {q11},    [r0], lr\n1:\n        vld1.8          {q10},    [r2], lr\n        vext.8          d5,  d22, d23, #3\n        vhadd.u8        d0,  d3,  d20\n        vext.8          d17, d20, d21, #3\n        vadd.u8         d0,  d0,  d22\n        vext.8          d6,  d22, d23, #6\n        vhadd.u8        d1,  d0,  d17\n        vext.8          d18, d20, d21, #6\n        vadd.u8         d1,  d1,  d5\n        vext.8          d7,  d23, d23, #1\n        vld1.8          {q11},    [r0], lr\n        vst1.32         {d0[0]},  [r1,:32], r4\n        vhadd.u8        d2,  d1,  d18\n        vst1.32         {d1[0]},  [r1], r4\n        vext.8          d19, d21, d21, #1\n        vadd.u8         d2,  d2,  d6\n        vhadd.u8        d3,  d2,  d19\n        vst1.32         {d2[0]},  [r1], r4\n        vadd.u8         d3,  d3,  d7\n        vst1.32         {d3[0]},  [r1], r4\n        subs            r12, r12, #12\n        bgt             1b\n\n        pop             {r4,pc}\nendfunc\n\n.macro  paeth           rx,  ra,  rb,  rc\n        vaddl.u8        q12, \\ra, \\rb           @ a + b\n        vaddl.u8        q15, \\rc, \\rc           @ 2*c\n        vabdl.u8        q13, \\rb, \\rc           @ pa\n        vabdl.u8        q14, \\ra, \\rc           @ pb\n        vabd.u16        q15, q12, q15           @ pc\n        vcle.u16        q12, q13, q14           @ pa <= pb\n        vcle.u16        q13, q13, q15           @ pa <= pc\n        vcle.u16        q14, q14, q15           @ pb <= pc\n        vand            q12, q12, q13           @ pa <= pb && pa <= pc\n        vmovn.u16       d28, q14\n        vmovn.u16       \\rx, q12\n        vbsl            d28, \\rb, \\rc\n        vbsl            \\rx, \\ra, d28\n.endm\n\nfunc    png_read_filter_row_paeth4_neon, export=1\n        ldr             r12, [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n        vmov.i8         d20, #0\n1:\n        vld4.32         {d4[],d5[],d6[],d7[]},    [r1,:128]\n        vld4.32         {d16[],d17[],d18[],d19[]},[r2,:128]!\n        paeth           d0,  d3,  d16, d20\n        vadd.u8         d0,  d0,  d4\n        paeth           d1,  d0,  d17, d16\n        vadd.u8         d1,  d1,  d5\n        paeth           d2,  d1,  d18, d17\n        vadd.u8         d2,  d2,  d6\n        paeth           d3,  d2,  d19, d18\n        vmov            d20, d19\n        vadd.u8         d3,  d3,  d7\n        vst4.32         {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!\n        subs            r12, r12, #16\n        bgt             1b\n\n        bx              lr\nendfunc\n\nfunc    png_read_filter_row_paeth3_neon, export=1\n        push            {r4,lr}\n        ldr             r12, [r0, #4]           @ rowbytes\n        vmov.i8         d3,  #0\n        vmov.i8         d4,  #0\n        mov             r0,  r1\n        mov             r4,  #3\n        mov             lr,  #12\n        vld1.8          {q11},    [r0], lr\n1:\n        vld1.8          {q10},    [r2], lr\n        paeth           d0,  d3,  d20, d4\n        vext.8          d5,  d22, d23, #3\n        vadd.u8         d0,  d0,  d22\n        vext.8          d17, d20, d21, #3\n        paeth           d1,  d0,  d17, d20\n        vst1.32         {d0[0]},  [r1,:32], r4\n        vext.8          d6,  d22, d23, #6\n        vadd.u8         d1,  d1,  d5\n        vext.8          d18, d20, d21, #6\n        paeth           d2,  d1,  d18, d17\n        vext.8          d7,  d23, d23, #1\n        vld1.8          {q11},    [r0], lr\n        vst1.32         {d1[0]},  [r1], r4\n        vadd.u8         d2,  d2,  d6\n        vext.8          d19, d21, d21, #1\n        paeth           d3,  d2,  d19, d18\n        vst1.32         {d2[0]},  [r1], r4\n        vmov            d4,  d19\n        vadd.u8         d3,  d3,  d7\n        vst1.32         {d3[0]},  [r1], r4\n        subs            r12, r12, #12\n        bgt             1b\n\n        pop             {r4,pc}\nendfunc\n#endif /* PNG_ARM_NEON_OPT > 0 */\n#endif /* PNG_READ_SUPPORTED */\n#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */\n"
  },
  {
    "path": "dlib/external/libpng/arm/filter_neon_intrinsics.c",
    "content": "\n/* filter_neon_intrinsics.c - NEON optimised filter functions\n *\n * Copyright (c) 2013 Glenn Randers-Pehrson\n * Written by James Yu <james.yu at linaro.org>, October 2013.\n * Based on filter_neon.S, written by Mans Rullgard, 2011.\n *\n * Last changed in libpng 1.6.7 [November 14, 2013]\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"../pngpriv.h\"\n\n/* This code requires -mfpu=neon on the command line: */\n#if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code */\n\n#include <arm_neon.h>\n\n/* libpng row pointers are not necessarily aligned to any particular boundary,\n * however this code will only work with appropriate alignment.  arm/arm_init.c\n * checks for this (and will not compile unless it is done), this code uses\n * variants of png_aligncast to avoid compiler warnings.\n */\n#define png_ptr(type,pointer) png_aligncast(type *,pointer)\n#define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer)\n\n/* The following relies on a variable 'temp_pointer' being declared with type\n * 'type'.  This is written this way just to hide the GCC strict aliasing\n * warning; note that the code is safe because there never is an alias between\n * the input and output pointers.\n */\n#define png_ldr(type,pointer)\\\n   (temp_pointer = png_ptr(type,pointer), *temp_pointer)\n\n#ifdef PNG_READ_SUPPORTED\n#if PNG_ARM_NEON_OPT > 0\n\nvoid\npng_read_filter_row_up_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n   png_const_bytep pp = prev_row;\n\n   for (; rp < rp_stop; rp += 16, pp += 16)\n   {\n      uint8x16_t qrp, qpp;\n\n      qrp = vld1q_u8(rp);\n      qpp = vld1q_u8(pp);\n      qrp = vaddq_u8(qrp, qpp);\n      vst1q_u8(rp, qrp);\n   }\n}\n\nvoid\npng_read_filter_row_sub3_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n\n   uint8x16_t vtmp = vld1q_u8(rp);\n   uint8x8x2_t *vrpt = png_ptr(uint8x8x2_t, &vtmp);\n   uint8x8x2_t vrp = *vrpt;\n\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   for (; rp < rp_stop;)\n   {\n      uint8x8_t vtmp1, vtmp2;\n      uint32x2_t *temp_pointer;\n\n      vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);\n      vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]);\n      vtmp2 = vext_u8(vrp.val[0], vrp.val[1], 6);\n      vdest.val[1] = vadd_u8(vdest.val[0], vtmp1);\n\n      vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);\n      vdest.val[2] = vadd_u8(vdest.val[1], vtmp2);\n      vdest.val[3] = vadd_u8(vdest.val[2], vtmp1);\n\n      vtmp = vld1q_u8(rp + 12);\n      vrpt = png_ptr(uint8x8x2_t, &vtmp);\n      vrp = *vrpt;\n\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);\n      rp += 3;\n   }\n\n   PNG_UNUSED(prev_row)\n}\n\nvoid\npng_read_filter_row_sub4_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   for (; rp < rp_stop; rp += 16)\n   {\n      uint32x2x4_t vtmp = vld4_u32(png_ptr(uint32_t,rp));\n      uint8x8x4_t *vrpt = png_ptr(uint8x8x4_t,&vtmp);\n      uint8x8x4_t vrp = *vrpt;\n      uint32x2x4_t *temp_pointer;\n\n      vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]);\n      vdest.val[1] = vadd_u8(vdest.val[0], vrp.val[1]);\n      vdest.val[2] = vadd_u8(vdest.val[1], vrp.val[2]);\n      vdest.val[3] = vadd_u8(vdest.val[2], vrp.val[3]);\n      vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0);\n   }\n\n   PNG_UNUSED(prev_row)\n}\n\nvoid\npng_read_filter_row_avg3_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_const_bytep pp = prev_row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n\n   uint8x16_t vtmp;\n   uint8x8x2_t *vrpt;\n   uint8x8x2_t vrp;\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   vtmp = vld1q_u8(rp);\n   vrpt = png_ptr(uint8x8x2_t,&vtmp);\n   vrp = *vrpt;\n\n   for (; rp < rp_stop; pp += 12)\n   {\n      uint8x8_t vtmp1, vtmp2, vtmp3;\n\n      uint8x8x2_t *vppt;\n      uint8x8x2_t vpp;\n\n      uint32x2_t *temp_pointer;\n\n      vtmp = vld1q_u8(pp);\n      vppt = png_ptr(uint8x8x2_t,&vtmp);\n      vpp = *vppt;\n\n      vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);\n      vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]);\n      vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);\n\n      vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3);\n      vtmp3 = vext_u8(vrp.val[0], vrp.val[1], 6);\n      vdest.val[1] = vhadd_u8(vdest.val[0], vtmp2);\n      vdest.val[1] = vadd_u8(vdest.val[1], vtmp1);\n\n      vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 6);\n      vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);\n\n      vtmp = vld1q_u8(rp + 12);\n      vrpt = png_ptr(uint8x8x2_t,&vtmp);\n      vrp = *vrpt;\n\n      vdest.val[2] = vhadd_u8(vdest.val[1], vtmp2);\n      vdest.val[2] = vadd_u8(vdest.val[2], vtmp3);\n\n      vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1);\n\n      vdest.val[3] = vhadd_u8(vdest.val[2], vtmp2);\n      vdest.val[3] = vadd_u8(vdest.val[3], vtmp1);\n\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);\n      rp += 3;\n   }\n}\n\nvoid\npng_read_filter_row_avg4_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n   png_const_bytep pp = prev_row;\n\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   for (; rp < rp_stop; rp += 16, pp += 16)\n   {\n      uint32x2x4_t vtmp;\n      uint8x8x4_t *vrpt, *vppt;\n      uint8x8x4_t vrp, vpp;\n      uint32x2x4_t *temp_pointer;\n\n      vtmp = vld4_u32(png_ptr(uint32_t,rp));\n      vrpt = png_ptr(uint8x8x4_t,&vtmp);\n      vrp = *vrpt;\n      vtmp = vld4_u32(png_ptrc(uint32_t,pp));\n      vppt = png_ptr(uint8x8x4_t,&vtmp);\n      vpp = *vppt;\n\n      vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]);\n      vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);\n      vdest.val[1] = vhadd_u8(vdest.val[0], vpp.val[1]);\n      vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]);\n      vdest.val[2] = vhadd_u8(vdest.val[1], vpp.val[2]);\n      vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]);\n      vdest.val[3] = vhadd_u8(vdest.val[2], vpp.val[3]);\n      vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]);\n\n      vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0);\n   }\n}\n\nstatic uint8x8_t\npaeth(uint8x8_t a, uint8x8_t b, uint8x8_t c)\n{\n   uint8x8_t d, e;\n   uint16x8_t p1, pa, pb, pc;\n\n   p1 = vaddl_u8(a, b); /* a + b */\n   pc = vaddl_u8(c, c); /* c * 2 */\n   pa = vabdl_u8(b, c); /* pa */\n   pb = vabdl_u8(a, c); /* pb */\n   pc = vabdq_u16(p1, pc); /* pc */\n\n   p1 = vcleq_u16(pa, pb); /* pa <= pb */\n   pa = vcleq_u16(pa, pc); /* pa <= pc */\n   pb = vcleq_u16(pb, pc); /* pb <= pc */\n\n   p1 = vandq_u16(p1, pa); /* pa <= pb && pa <= pc */\n\n   d = vmovn_u16(pb);\n   e = vmovn_u16(p1);\n\n   d = vbsl_u8(d, b, c);\n   e = vbsl_u8(e, a, d);\n\n   return e;\n}\n\nvoid\npng_read_filter_row_paeth3_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_const_bytep pp = prev_row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n\n   uint8x16_t vtmp;\n   uint8x8x2_t *vrpt;\n   uint8x8x2_t vrp;\n   uint8x8_t vlast = vdup_n_u8(0);\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   vtmp = vld1q_u8(rp);\n   vrpt = png_ptr(uint8x8x2_t,&vtmp);\n   vrp = *vrpt;\n\n   for (; rp < rp_stop; pp += 12)\n   {\n      uint8x8x2_t *vppt;\n      uint8x8x2_t vpp;\n      uint8x8_t vtmp1, vtmp2, vtmp3;\n      uint32x2_t *temp_pointer;\n\n      vtmp = vld1q_u8(pp);\n      vppt = png_ptr(uint8x8x2_t,&vtmp);\n      vpp = *vppt;\n\n      vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast);\n      vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);\n\n      vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);\n      vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3);\n      vdest.val[1] = paeth(vdest.val[0], vtmp2, vpp.val[0]);\n      vdest.val[1] = vadd_u8(vdest.val[1], vtmp1);\n\n      vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6);\n      vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6);\n      vdest.val[2] = paeth(vdest.val[1], vtmp3, vtmp2);\n      vdest.val[2] = vadd_u8(vdest.val[2], vtmp1);\n\n      vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);\n      vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1);\n\n      vtmp = vld1q_u8(rp + 12);\n      vrpt = png_ptr(uint8x8x2_t,&vtmp);\n      vrp = *vrpt;\n\n      vdest.val[3] = paeth(vdest.val[2], vtmp2, vtmp3);\n      vdest.val[3] = vadd_u8(vdest.val[3], vtmp1);\n\n      vlast = vtmp2;\n\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);\n      rp += 3;\n      vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);\n      rp += 3;\n   }\n}\n\nvoid\npng_read_filter_row_paeth4_neon(png_row_infop row_info, png_bytep row,\n   png_const_bytep prev_row)\n{\n   png_bytep rp = row;\n   png_bytep rp_stop = row + row_info->rowbytes;\n   png_const_bytep pp = prev_row;\n\n   uint8x8_t vlast = vdup_n_u8(0);\n   uint8x8x4_t vdest;\n   vdest.val[3] = vdup_n_u8(0);\n\n   for (; rp < rp_stop; rp += 16, pp += 16)\n   {\n      uint32x2x4_t vtmp;\n      uint8x8x4_t *vrpt, *vppt;\n      uint8x8x4_t vrp, vpp;\n      uint32x2x4_t *temp_pointer;\n\n      vtmp = vld4_u32(png_ptr(uint32_t,rp));\n      vrpt = png_ptr(uint8x8x4_t,&vtmp);\n      vrp = *vrpt;\n      vtmp = vld4_u32(png_ptrc(uint32_t,pp));\n      vppt = png_ptr(uint8x8x4_t,&vtmp);\n      vpp = *vppt;\n\n      vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast);\n      vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);\n      vdest.val[1] = paeth(vdest.val[0], vpp.val[1], vpp.val[0]);\n      vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]);\n      vdest.val[2] = paeth(vdest.val[1], vpp.val[2], vpp.val[1]);\n      vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]);\n      vdest.val[3] = paeth(vdest.val[2], vpp.val[3], vpp.val[2]);\n      vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]);\n\n      vlast = vpp.val[3];\n\n      vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0);\n   }\n}\n\n#endif /* PNG_ARM_NEON_OPT > 0 */\n#endif /* PNG_READ_SUPPORTED */\n#endif /* PNG_ARM_NEON_IMPLEMENTATION == 1 (intrinsics) */\n"
  },
  {
    "path": "dlib/external/libpng/arm/palette_neon_intrinsics.c",
    "content": "\n/* palette_neon_intrinsics.c - NEON optimised palette expansion functions\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 2017-2018 Arm Holdings. All rights reserved.\n * Written by Richard Townsend <Richard.Townsend@arm.com>, February 2017.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"../pngpriv.h\"\n\n#if PNG_ARM_NEON_IMPLEMENTATION == 1\n\n#if defined(_MSC_VER) && defined(_M_ARM64)\n#  include <arm64_neon.h>\n#else\n#  include <arm_neon.h>\n#endif\n\n/* Build an RGBA8 palette from the separate RGB and alpha palettes. */\nvoid\npng_riffle_palette_neon(png_structrp png_ptr)\n{\n   png_const_colorp palette = png_ptr->palette;\n   png_bytep riffled_palette = png_ptr->riffled_palette;\n   png_const_bytep trans_alpha = png_ptr->trans_alpha;\n   int num_trans = png_ptr->num_trans;\n   int i;\n\n   png_debug(1, \"in png_riffle_palette_neon\");\n\n   /* Initially black, opaque. */\n   uint8x16x4_t w = {{\n      vdupq_n_u8(0x00),\n      vdupq_n_u8(0x00),\n      vdupq_n_u8(0x00),\n      vdupq_n_u8(0xff),\n   }};\n\n   /* First, riffle the RGB colours into an RGBA8 palette.\n    * The alpha component is set to opaque for now.\n    */\n   for (i = 0; i < 256; i += 16)\n   {\n      uint8x16x3_t v = vld3q_u8((png_const_bytep)(palette + i));\n      w.val[0] = v.val[0];\n      w.val[1] = v.val[1];\n      w.val[2] = v.val[2];\n      vst4q_u8(riffled_palette + (i << 2), w);\n   }\n\n   /* Fix up the missing transparency values. */\n   for (i = 0; i < num_trans; i++)\n      riffled_palette[(i << 2) + 3] = trans_alpha[i];\n}\n\n/* Expands a palettized row into RGBA8. */\nint\npng_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info,\n    png_const_bytep row, png_bytepp ssp, png_bytepp ddp)\n{\n   png_uint_32 row_width = row_info->width;\n   const png_uint_32 *riffled_palette =\n      (const png_uint_32 *)png_ptr->riffled_palette;\n   const png_int_32 pixels_per_chunk = 4;\n   int i;\n\n   png_debug(1, \"in png_do_expand_palette_rgba8_neon\");\n\n   if (row_width < pixels_per_chunk)\n      return 0;\n\n   /* This function originally gets the last byte of the output row.\n    * The NEON part writes forward from a given position, so we have\n    * to seek this back by 4 pixels x 4 bytes.\n    */\n   *ddp = *ddp - ((pixels_per_chunk * sizeof(png_uint_32)) - 1);\n\n   for (i = 0; i < row_width; i += pixels_per_chunk)\n   {\n      uint32x4_t cur;\n      png_bytep sp = *ssp - i, dp = *ddp - (i << 2);\n      cur = vld1q_dup_u32 (riffled_palette + *(sp - 3));\n      cur = vld1q_lane_u32(riffled_palette + *(sp - 2), cur, 1);\n      cur = vld1q_lane_u32(riffled_palette + *(sp - 1), cur, 2);\n      cur = vld1q_lane_u32(riffled_palette + *(sp - 0), cur, 3);\n      vst1q_u32((void *)dp, cur);\n   }\n   if (i != row_width)\n   {\n      /* Remove the amount that wasn't processed. */\n      i -= pixels_per_chunk;\n   }\n\n   /* Decrement output pointers. */\n   *ssp = *ssp - i;\n   *ddp = *ddp - (i << 2);\n   return i;\n}\n\n/* Expands a palettized row into RGB8. */\nint\npng_do_expand_palette_rgb8_neon(png_structrp png_ptr, png_row_infop row_info,\n    png_const_bytep row, png_bytepp ssp, png_bytepp ddp)\n{\n   png_uint_32 row_width = row_info->width;\n   png_const_bytep palette = (png_const_bytep)png_ptr->palette;\n   const png_uint_32 pixels_per_chunk = 8;\n   int i;\n\n   png_debug(1, \"in png_do_expand_palette_rgb8_neon\");\n\n   if (row_width <= pixels_per_chunk)\n      return 0;\n\n   /* Seeking this back by 8 pixels x 3 bytes. */\n   *ddp = *ddp - ((pixels_per_chunk * sizeof(png_color)) - 1);\n\n   for (i = 0; i < row_width; i += pixels_per_chunk)\n   {\n      uint8x8x3_t cur;\n      png_bytep sp = *ssp - i, dp = *ddp - ((i << 1) + i);\n      cur = vld3_dup_u8(palette + sizeof(png_color) * (*(sp - 7)));\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 6)), cur, 1);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 5)), cur, 2);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 4)), cur, 3);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 3)), cur, 4);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 2)), cur, 5);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 1)), cur, 6);\n      cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 0)), cur, 7);\n      vst3_u8((void *)dp, cur);\n   }\n\n   if (i != row_width)\n   {\n      /* Remove the amount that wasn't processed. */\n      i -= pixels_per_chunk;\n   }\n\n   /* Decrement output pointers. */\n   *ssp = *ssp - i;\n   *ddp = *ddp - ((i << 1) + i);\n   return i;\n}\n\n#endif /* PNG_ARM_NEON_IMPLEMENTATION */\n"
  },
  {
    "path": "dlib/external/libpng/png.c",
    "content": "\n/* png.c - location for general purpose libpng functions\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n\n/* Generate a compiler error if there is an old png.h in the search path. */\ntypedef png_libpng_version_1_6_37 Your_png_h_is_not_version_1_6_37;\n\n#ifdef __GNUC__\n/* The version tests may need to be added to, but the problem warning has\n * consistently been fixed in GCC versions which obtain wide-spread release.\n * The problem is that many versions of GCC rearrange comparison expressions in\n * the optimizer in such a way that the results of the comparison will change\n * if signed integer overflow occurs.  Such comparisons are not permitted in\n * ANSI C90, however GCC isn't clever enough to work out that that do not occur\n * below in png_ascii_from_fp and png_muldiv, so it produces a warning with\n * -Wextra.  Unfortunately this is highly dependent on the optimizer and the\n * machine architecture so the warning comes and goes unpredictably and is\n * impossible to \"fix\", even were that a good idea.\n */\n#if __GNUC__ == 7 && __GNUC_MINOR__ == 1\n#define GCC_STRICT_OVERFLOW 1\n#endif /* GNU 7.1.x */\n#endif /* GNU */\n#ifndef GCC_STRICT_OVERFLOW\n#define GCC_STRICT_OVERFLOW 0\n#endif\n\n/* Tells libpng that we have already handled the first \"num_bytes\" bytes\n * of the PNG file signature.  If the PNG data is embedded into another\n * stream we can set num_bytes = 8 so that libpng will not attempt to read\n * or write any of the magic bytes before it starts on the IHDR.\n */\n\n#ifdef PNG_READ_SUPPORTED\nvoid PNGAPI\npng_set_sig_bytes(png_structrp png_ptr, int num_bytes)\n{\n   unsigned int nb = (unsigned int)num_bytes;\n\n   png_debug(1, \"in png_set_sig_bytes\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (num_bytes < 0)\n      nb = 0;\n\n   if (nb > 8)\n      png_error(png_ptr, \"Too many bytes for PNG signature\");\n\n   png_ptr->sig_bytes = (png_byte)nb;\n}\n\n/* Checks whether the supplied bytes match the PNG signature.  We allow\n * checking less than the full 8-byte signature so that those apps that\n * already read the first few bytes of a file to determine the file type\n * can simply check the remaining bytes for extra assurance.  Returns\n * an integer less than, equal to, or greater than zero if sig is found,\n * respectively, to be less than, to match, or be greater than the correct\n * PNG signature (this is the same behavior as strcmp, memcmp, etc).\n */\nint PNGAPI\npng_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check)\n{\n   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};\n\n   if (num_to_check > 8)\n      num_to_check = 8;\n\n   else if (num_to_check < 1)\n      return (-1);\n\n   if (start > 7)\n      return (-1);\n\n   if (start + num_to_check > 8)\n      num_to_check = 8 - start;\n\n   return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));\n}\n\n#endif /* READ */\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n/* Function to allocate memory for zlib */\nPNG_FUNCTION(voidpf /* PRIVATE */,\npng_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)\n{\n   png_alloc_size_t num_bytes = size;\n\n   if (png_ptr == NULL)\n      return NULL;\n\n   if (items >= (~(png_alloc_size_t)0)/size)\n   {\n      png_warning (png_voidcast(png_structrp, png_ptr),\n          \"Potential overflow in png_zalloc()\");\n      return NULL;\n   }\n\n   num_bytes *= items;\n   return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes);\n}\n\n/* Function to free memory for zlib */\nvoid /* PRIVATE */\npng_zfree(voidpf png_ptr, voidpf ptr)\n{\n   png_free(png_voidcast(png_const_structrp,png_ptr), ptr);\n}\n\n/* Reset the CRC variable to 32 bits of 1's.  Care must be taken\n * in case CRC is > 32 bits to leave the top bits 0.\n */\nvoid /* PRIVATE */\npng_reset_crc(png_structrp png_ptr)\n{\n   /* The cast is safe because the crc is a 32-bit value. */\n   png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0);\n}\n\n/* Calculate the CRC over a section of data.  We can only pass as\n * much data to this routine as the largest single buffer size.  We\n * also check that this data will actually be used before going to the\n * trouble of calculating it.\n */\nvoid /* PRIVATE */\npng_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length)\n{\n   int need_crc = 1;\n\n   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)\n   {\n      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==\n          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))\n         need_crc = 0;\n   }\n\n   else /* critical */\n   {\n      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)\n         need_crc = 0;\n   }\n\n   /* 'uLong' is defined in zlib.h as unsigned long; this means that on some\n    * systems it is a 64-bit value.  crc32, however, returns 32 bits so the\n    * following cast is safe.  'uInt' may be no more than 16 bits, so it is\n    * necessary to perform a loop here.\n    */\n   if (need_crc != 0 && length > 0)\n   {\n      uLong crc = png_ptr->crc; /* Should never issue a warning */\n\n      do\n      {\n         uInt safe_length = (uInt)length;\n#ifndef __COVERITY__\n         if (safe_length == 0)\n            safe_length = (uInt)-1; /* evil, but safe */\n#endif\n\n         crc = crc32(crc, ptr, safe_length);\n\n         /* The following should never issue compiler warnings; if they do the\n          * target system has characteristics that will probably violate other\n          * assumptions within the libpng code.\n          */\n         ptr += safe_length;\n         length -= safe_length;\n      }\n      while (length > 0);\n\n      /* And the following is always safe because the crc is only 32 bits. */\n      png_ptr->crc = (png_uint_32)crc;\n   }\n}\n\n/* Check a user supplied version number, called from both read and write\n * functions that create a png_struct.\n */\nint\npng_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)\n{\n   /* Libpng versions 1.0.0 and later are binary compatible if the version\n    * string matches through the second '.'; we must recompile any\n    * applications that use any older library version.\n    */\n\n   if (user_png_ver != NULL)\n   {\n      int i = -1;\n      int found_dots = 0;\n\n      do\n      {\n         i++;\n         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])\n            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;\n         if (user_png_ver[i] == '.')\n            found_dots++;\n      } while (found_dots < 2 && user_png_ver[i] != 0 &&\n            PNG_LIBPNG_VER_STRING[i] != 0);\n   }\n\n   else\n      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;\n\n   if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0)\n   {\n#ifdef PNG_WARNINGS_SUPPORTED\n      size_t pos = 0;\n      char m[128];\n\n      pos = png_safecat(m, (sizeof m), pos,\n          \"Application built with libpng-\");\n      pos = png_safecat(m, (sizeof m), pos, user_png_ver);\n      pos = png_safecat(m, (sizeof m), pos, \" but running with \");\n      pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);\n      PNG_UNUSED(pos)\n\n      png_warning(png_ptr, m);\n#endif\n\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\n      png_ptr->flags = 0;\n#endif\n\n      return 0;\n   }\n\n   /* Success return. */\n   return 1;\n}\n\n/* Generic function to create a png_struct for either read or write - this\n * contains the common initialization.\n */\nPNG_FUNCTION(png_structp /* PRIVATE */,\npng_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,\n    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)\n{\n   png_struct create_struct;\n#  ifdef PNG_SETJMP_SUPPORTED\n      jmp_buf create_jmp_buf;\n#  endif\n\n   /* This temporary stack-allocated structure is used to provide a place to\n    * build enough context to allow the user provided memory allocator (if any)\n    * to be called.\n    */\n   memset(&create_struct, 0, (sizeof create_struct));\n\n   /* Added at libpng-1.2.6 */\n#  ifdef PNG_USER_LIMITS_SUPPORTED\n      create_struct.user_width_max = PNG_USER_WIDTH_MAX;\n      create_struct.user_height_max = PNG_USER_HEIGHT_MAX;\n\n#     ifdef PNG_USER_CHUNK_CACHE_MAX\n      /* Added at libpng-1.2.43 and 1.4.0 */\n      create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;\n#     endif\n\n#     ifdef PNG_USER_CHUNK_MALLOC_MAX\n      /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists\n       * in png_struct regardless.\n       */\n      create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;\n#     endif\n#  endif\n\n   /* The following two API calls simply set fields in png_struct, so it is safe\n    * to do them now even though error handling is not yet set up.\n    */\n#  ifdef PNG_USER_MEM_SUPPORTED\n      png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn);\n#  else\n      PNG_UNUSED(mem_ptr)\n      PNG_UNUSED(malloc_fn)\n      PNG_UNUSED(free_fn)\n#  endif\n\n   /* (*error_fn) can return control to the caller after the error_ptr is set,\n    * this will result in a memory leak unless the error_fn does something\n    * extremely sophisticated.  The design lacks merit but is implicit in the\n    * API.\n    */\n   png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn);\n\n#  ifdef PNG_SETJMP_SUPPORTED\n      if (!setjmp(create_jmp_buf))\n#  endif\n      {\n#  ifdef PNG_SETJMP_SUPPORTED\n         /* Temporarily fake out the longjmp information until we have\n          * successfully completed this function.  This only works if we have\n          * setjmp() support compiled in, but it is safe - this stuff should\n          * never happen.\n          */\n         create_struct.jmp_buf_ptr = &create_jmp_buf;\n         create_struct.jmp_buf_size = 0; /*stack allocation*/\n         create_struct.longjmp_fn = longjmp;\n#  endif\n         /* Call the general version checker (shared with read and write code):\n          */\n         if (png_user_version_check(&create_struct, user_png_ver) != 0)\n         {\n            png_structrp png_ptr = png_voidcast(png_structrp,\n                png_malloc_warn(&create_struct, (sizeof *png_ptr)));\n\n            if (png_ptr != NULL)\n            {\n               /* png_ptr->zstream holds a back-pointer to the png_struct, so\n                * this can only be done now:\n                */\n               create_struct.zstream.zalloc = png_zalloc;\n               create_struct.zstream.zfree = png_zfree;\n               create_struct.zstream.opaque = png_ptr;\n\n#              ifdef PNG_SETJMP_SUPPORTED\n               /* Eliminate the local error handling: */\n               create_struct.jmp_buf_ptr = NULL;\n               create_struct.jmp_buf_size = 0;\n               create_struct.longjmp_fn = 0;\n#              endif\n\n               *png_ptr = create_struct;\n\n               /* This is the successful return point */\n               return png_ptr;\n            }\n         }\n      }\n\n   /* A longjmp because of a bug in the application storage allocator or a\n    * simple failure to allocate the png_struct.\n    */\n   return NULL;\n}\n\n/* Allocate the memory for an info_struct for the application. */\nPNG_FUNCTION(png_infop,PNGAPI\npng_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED)\n{\n   png_inforp info_ptr;\n\n   png_debug(1, \"in png_create_info_struct\");\n\n   if (png_ptr == NULL)\n      return NULL;\n\n   /* Use the internal API that does not (or at least should not) error out, so\n    * that this call always returns ok.  The application typically sets up the\n    * error handling *after* creating the info_struct because this is the way it\n    * has always been done in 'example.c'.\n    */\n   info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr,\n       (sizeof *info_ptr)));\n\n   if (info_ptr != NULL)\n      memset(info_ptr, 0, (sizeof *info_ptr));\n\n   return info_ptr;\n}\n\n/* This function frees the memory associated with a single info struct.\n * Normally, one would use either png_destroy_read_struct() or\n * png_destroy_write_struct() to free an info struct, but this may be\n * useful for some applications.  From libpng 1.6.0 this function is also used\n * internally to implement the png_info release part of the 'struct' destroy\n * APIs.  This ensures that all possible approaches free the same data (all of\n * it).\n */\nvoid PNGAPI\npng_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr)\n{\n   png_inforp info_ptr = NULL;\n\n   png_debug(1, \"in png_destroy_info_struct\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (info_ptr_ptr != NULL)\n      info_ptr = *info_ptr_ptr;\n\n   if (info_ptr != NULL)\n   {\n      /* Do this first in case of an error below; if the app implements its own\n       * memory management this can lead to png_free calling png_error, which\n       * will abort this routine and return control to the app error handler.\n       * An infinite loop may result if it then tries to free the same info\n       * ptr.\n       */\n      *info_ptr_ptr = NULL;\n\n      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);\n      memset(info_ptr, 0, (sizeof *info_ptr));\n      png_free(png_ptr, info_ptr);\n   }\n}\n\n/* Initialize the info structure.  This is now an internal function (0.89)\n * and applications using it are urged to use png_create_info_struct()\n * instead.  Use deprecated in 1.6.0, internal use removed (used internally it\n * is just a memset).\n *\n * NOTE: it is almost inconceivable that this API is used because it bypasses\n * the user-memory mechanism and the user error handling/warning mechanisms in\n * those cases where it does anything other than a memset.\n */\nPNG_FUNCTION(void,PNGAPI\npng_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size),\n    PNG_DEPRECATED)\n{\n   png_inforp info_ptr = *ptr_ptr;\n\n   png_debug(1, \"in png_info_init_3\");\n\n   if (info_ptr == NULL)\n      return;\n\n   if ((sizeof (png_info)) > png_info_struct_size)\n   {\n      *ptr_ptr = NULL;\n      /* The following line is why this API should not be used: */\n      free(info_ptr);\n      info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL,\n          (sizeof *info_ptr)));\n      if (info_ptr == NULL)\n         return;\n      *ptr_ptr = info_ptr;\n   }\n\n   /* Set everything to 0 */\n   memset(info_ptr, 0, (sizeof *info_ptr));\n}\n\n/* The following API is not called internally */\nvoid PNGAPI\npng_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,\n    int freer, png_uint_32 mask)\n{\n   png_debug(1, \"in png_data_freer\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if (freer == PNG_DESTROY_WILL_FREE_DATA)\n      info_ptr->free_me |= mask;\n\n   else if (freer == PNG_USER_WILL_FREE_DATA)\n      info_ptr->free_me &= ~mask;\n\n   else\n      png_error(png_ptr, \"Unknown freer parameter in png_data_freer\");\n}\n\nvoid PNGAPI\npng_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,\n    int num)\n{\n   png_debug(1, \"in png_free_data\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n#ifdef PNG_TEXT_SUPPORTED\n   /* Free text item num or (if num == -1) all text items */\n   if (info_ptr->text != NULL &&\n       ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)\n   {\n      if (num != -1)\n      {\n         png_free(png_ptr, info_ptr->text[num].key);\n         info_ptr->text[num].key = NULL;\n      }\n\n      else\n      {\n         int i;\n\n         for (i = 0; i < info_ptr->num_text; i++)\n            png_free(png_ptr, info_ptr->text[i].key);\n\n         png_free(png_ptr, info_ptr->text);\n         info_ptr->text = NULL;\n         info_ptr->num_text = 0;\n         info_ptr->max_text = 0;\n      }\n   }\n#endif\n\n#ifdef PNG_tRNS_SUPPORTED\n   /* Free any tRNS entry */\n   if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0)\n   {\n      info_ptr->valid &= ~PNG_INFO_tRNS;\n      png_free(png_ptr, info_ptr->trans_alpha);\n      info_ptr->trans_alpha = NULL;\n      info_ptr->num_trans = 0;\n   }\n#endif\n\n#ifdef PNG_sCAL_SUPPORTED\n   /* Free any sCAL entry */\n   if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0)\n   {\n      png_free(png_ptr, info_ptr->scal_s_width);\n      png_free(png_ptr, info_ptr->scal_s_height);\n      info_ptr->scal_s_width = NULL;\n      info_ptr->scal_s_height = NULL;\n      info_ptr->valid &= ~PNG_INFO_sCAL;\n   }\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\n   /* Free any pCAL entry */\n   if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)\n   {\n      png_free(png_ptr, info_ptr->pcal_purpose);\n      png_free(png_ptr, info_ptr->pcal_units);\n      info_ptr->pcal_purpose = NULL;\n      info_ptr->pcal_units = NULL;\n\n      if (info_ptr->pcal_params != NULL)\n         {\n            int i;\n\n            for (i = 0; i < info_ptr->pcal_nparams; i++)\n               png_free(png_ptr, info_ptr->pcal_params[i]);\n\n            png_free(png_ptr, info_ptr->pcal_params);\n            info_ptr->pcal_params = NULL;\n         }\n      info_ptr->valid &= ~PNG_INFO_pCAL;\n   }\n#endif\n\n#ifdef PNG_iCCP_SUPPORTED\n   /* Free any profile entry */\n   if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0)\n   {\n      png_free(png_ptr, info_ptr->iccp_name);\n      png_free(png_ptr, info_ptr->iccp_profile);\n      info_ptr->iccp_name = NULL;\n      info_ptr->iccp_profile = NULL;\n      info_ptr->valid &= ~PNG_INFO_iCCP;\n   }\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\n   /* Free a given sPLT entry, or (if num == -1) all sPLT entries */\n   if (info_ptr->splt_palettes != NULL &&\n       ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)\n   {\n      if (num != -1)\n      {\n         png_free(png_ptr, info_ptr->splt_palettes[num].name);\n         png_free(png_ptr, info_ptr->splt_palettes[num].entries);\n         info_ptr->splt_palettes[num].name = NULL;\n         info_ptr->splt_palettes[num].entries = NULL;\n      }\n\n      else\n      {\n         int i;\n\n         for (i = 0; i < info_ptr->splt_palettes_num; i++)\n         {\n            png_free(png_ptr, info_ptr->splt_palettes[i].name);\n            png_free(png_ptr, info_ptr->splt_palettes[i].entries);\n         }\n\n         png_free(png_ptr, info_ptr->splt_palettes);\n         info_ptr->splt_palettes = NULL;\n         info_ptr->splt_palettes_num = 0;\n         info_ptr->valid &= ~PNG_INFO_sPLT;\n      }\n   }\n#endif\n\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n   if (info_ptr->unknown_chunks != NULL &&\n       ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)\n   {\n      if (num != -1)\n      {\n          png_free(png_ptr, info_ptr->unknown_chunks[num].data);\n          info_ptr->unknown_chunks[num].data = NULL;\n      }\n\n      else\n      {\n         int i;\n\n         for (i = 0; i < info_ptr->unknown_chunks_num; i++)\n            png_free(png_ptr, info_ptr->unknown_chunks[i].data);\n\n         png_free(png_ptr, info_ptr->unknown_chunks);\n         info_ptr->unknown_chunks = NULL;\n         info_ptr->unknown_chunks_num = 0;\n      }\n   }\n#endif\n\n#ifdef PNG_eXIf_SUPPORTED\n   /* Free any eXIf entry */\n   if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)\n   {\n# ifdef PNG_READ_eXIf_SUPPORTED\n      if (info_ptr->eXIf_buf)\n      {\n         png_free(png_ptr, info_ptr->eXIf_buf);\n         info_ptr->eXIf_buf = NULL;\n      }\n# endif\n      if (info_ptr->exif)\n      {\n         png_free(png_ptr, info_ptr->exif);\n         info_ptr->exif = NULL;\n      }\n      info_ptr->valid &= ~PNG_INFO_eXIf;\n   }\n#endif\n\n#ifdef PNG_hIST_SUPPORTED\n   /* Free any hIST entry */\n   if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)\n   {\n      png_free(png_ptr, info_ptr->hist);\n      info_ptr->hist = NULL;\n      info_ptr->valid &= ~PNG_INFO_hIST;\n   }\n#endif\n\n   /* Free any PLTE entry that was internally allocated */\n   if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0)\n   {\n      png_free(png_ptr, info_ptr->palette);\n      info_ptr->palette = NULL;\n      info_ptr->valid &= ~PNG_INFO_PLTE;\n      info_ptr->num_palette = 0;\n   }\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\n   /* Free any image bits attached to the info structure */\n   if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)\n   {\n      if (info_ptr->row_pointers != NULL)\n      {\n         png_uint_32 row;\n         for (row = 0; row < info_ptr->height; row++)\n            png_free(png_ptr, info_ptr->row_pointers[row]);\n\n         png_free(png_ptr, info_ptr->row_pointers);\n         info_ptr->row_pointers = NULL;\n      }\n      info_ptr->valid &= ~PNG_INFO_IDAT;\n   }\n#endif\n\n   if (num != -1)\n      mask &= ~PNG_FREE_MUL;\n\n   info_ptr->free_me &= ~mask;\n}\n#endif /* READ || WRITE */\n\n/* This function returns a pointer to the io_ptr associated with the user\n * functions.  The application should free any memory associated with this\n * pointer before png_write_destroy() or png_read_destroy() are called.\n */\npng_voidp PNGAPI\npng_get_io_ptr(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return (NULL);\n\n   return (png_ptr->io_ptr);\n}\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n#  ifdef PNG_STDIO_SUPPORTED\n/* Initialize the default input/output functions for the PNG file.  If you\n * use your own read or write routines, you can call either png_set_read_fn()\n * or png_set_write_fn() instead of png_init_io().  If you have defined\n * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a\n * function of your own because \"FILE *\" isn't necessarily available.\n */\nvoid PNGAPI\npng_init_io(png_structrp png_ptr, png_FILE_p fp)\n{\n   png_debug(1, \"in png_init_io\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->io_ptr = (png_voidp)fp;\n}\n#  endif\n\n#  ifdef PNG_SAVE_INT_32_SUPPORTED\n/* PNG signed integers are saved in 32-bit 2's complement format.  ANSI C-90\n * defines a cast of a signed integer to an unsigned integer either to preserve\n * the value, if it is positive, or to calculate:\n *\n *     (UNSIGNED_MAX+1) + integer\n *\n * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the\n * negative integral value is added the result will be an unsigned value\n * correspnding to the 2's complement representation.\n */\nvoid PNGAPI\npng_save_int_32(png_bytep buf, png_int_32 i)\n{\n   png_save_uint_32(buf, (png_uint_32)i);\n}\n#  endif\n\n#  ifdef PNG_TIME_RFC1123_SUPPORTED\n/* Convert the supplied time into an RFC 1123 string suitable for use in\n * a \"Creation Time\" or other text-based time string.\n */\nint PNGAPI\npng_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)\n{\n   static const char short_months[12][4] =\n        {\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n         \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"};\n\n   if (out == NULL)\n      return 0;\n\n   if (ptime->year > 9999 /* RFC1123 limitation */ ||\n       ptime->month == 0    ||  ptime->month > 12  ||\n       ptime->day   == 0    ||  ptime->day   > 31  ||\n       ptime->hour  > 23    ||  ptime->minute > 59 ||\n       ptime->second > 60)\n      return 0;\n\n   {\n      size_t pos = 0;\n      char number_buf[5]; /* enough for a four-digit year */\n\n#     define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))\n#     define APPEND_NUMBER(format, value)\\\n         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))\n#     define APPEND(ch) if (pos < 28) out[pos++] = (ch)\n\n      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day);\n      APPEND(' ');\n      APPEND_STRING(short_months[(ptime->month - 1)]);\n      APPEND(' ');\n      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);\n      APPEND(' ');\n      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);\n      APPEND(':');\n      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);\n      APPEND(':');\n      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);\n      APPEND_STRING(\" +0000\"); /* This reliably terminates the buffer */\n      PNG_UNUSED (pos)\n\n#     undef APPEND\n#     undef APPEND_NUMBER\n#     undef APPEND_STRING\n   }\n\n   return 1;\n}\n\n#    if PNG_LIBPNG_VER < 10700\n/* To do: remove the following from libpng-1.7 */\n/* Original API that uses a private buffer in png_struct.\n * Deprecated because it causes png_struct to carry a spurious temporary\n * buffer (png_struct::time_buffer), better to have the caller pass this in.\n */\npng_const_charp PNGAPI\npng_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime)\n{\n   if (png_ptr != NULL)\n   {\n      /* The only failure above if png_ptr != NULL is from an invalid ptime */\n      if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0)\n         png_warning(png_ptr, \"Ignoring invalid time value\");\n\n      else\n         return png_ptr->time_buffer;\n   }\n\n   return NULL;\n}\n#    endif /* LIBPNG_VER < 10700 */\n#  endif /* TIME_RFC1123 */\n\n#endif /* READ || WRITE */\n\npng_const_charp PNGAPI\npng_get_copyright(png_const_structrp png_ptr)\n{\n   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */\n#ifdef PNG_STRING_COPYRIGHT\n   return PNG_STRING_COPYRIGHT\n#else\n   return PNG_STRING_NEWLINE \\\n      \"libpng version 1.6.37\" PNG_STRING_NEWLINE \\\n      \"Copyright (c) 2018-2019 Cosmin Truta\" PNG_STRING_NEWLINE \\\n      \"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\" \\\n      PNG_STRING_NEWLINE \\\n      \"Copyright (c) 1996-1997 Andreas Dilger\" PNG_STRING_NEWLINE \\\n      \"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\" \\\n      PNG_STRING_NEWLINE;\n#endif\n}\n\n/* The following return the library version as a short string in the\n * format 1.0.0 through 99.99.99zz.  To get the version of *.h files\n * used with your application, print out PNG_LIBPNG_VER_STRING, which\n * is defined in png.h.\n * Note: now there is no difference between png_get_libpng_ver() and\n * png_get_header_ver().  Due to the version_nn_nn_nn typedef guard,\n * it is guaranteed that png.c uses the correct version of png.h.\n */\npng_const_charp PNGAPI\npng_get_libpng_ver(png_const_structrp png_ptr)\n{\n   /* Version of *.c files used when building libpng */\n   return png_get_header_ver(png_ptr);\n}\n\npng_const_charp PNGAPI\npng_get_header_ver(png_const_structrp png_ptr)\n{\n   /* Version of *.h files used when building libpng */\n   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */\n   return PNG_LIBPNG_VER_STRING;\n}\n\npng_const_charp PNGAPI\npng_get_header_version(png_const_structrp png_ptr)\n{\n   /* Returns longer string containing both version and date */\n   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */\n#ifdef __STDC__\n   return PNG_HEADER_VERSION_STRING\n#  ifndef PNG_READ_SUPPORTED\n      \" (NO READ SUPPORT)\"\n#  endif\n      PNG_STRING_NEWLINE;\n#else\n   return PNG_HEADER_VERSION_STRING;\n#endif\n}\n\n#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED\n/* NOTE: this routine is not used internally! */\n/* Build a grayscale palette.  Palette is assumed to be 1 << bit_depth\n * large of png_color.  This lets grayscale images be treated as\n * paletted.  Most useful for gamma correction and simplification\n * of code.  This API is not used internally.\n */\nvoid PNGAPI\npng_build_grayscale_palette(int bit_depth, png_colorp palette)\n{\n   int num_palette;\n   int color_inc;\n   int i;\n   int v;\n\n   png_debug(1, \"in png_do_build_grayscale_palette\");\n\n   if (palette == NULL)\n      return;\n\n   switch (bit_depth)\n   {\n      case 1:\n         num_palette = 2;\n         color_inc = 0xff;\n         break;\n\n      case 2:\n         num_palette = 4;\n         color_inc = 0x55;\n         break;\n\n      case 4:\n         num_palette = 16;\n         color_inc = 0x11;\n         break;\n\n      case 8:\n         num_palette = 256;\n         color_inc = 1;\n         break;\n\n      default:\n         num_palette = 0;\n         color_inc = 0;\n         break;\n   }\n\n   for (i = 0, v = 0; i < num_palette; i++, v += color_inc)\n   {\n      palette[i].red = (png_byte)(v & 0xff);\n      palette[i].green = (png_byte)(v & 0xff);\n      palette[i].blue = (png_byte)(v & 0xff);\n   }\n}\n#endif\n\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\nint PNGAPI\npng_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name)\n{\n   /* Check chunk_name and return \"keep\" value if it's on the list, else 0 */\n   png_const_bytep p, p_end;\n\n   if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0)\n      return PNG_HANDLE_CHUNK_AS_DEFAULT;\n\n   p_end = png_ptr->chunk_list;\n   p = p_end + png_ptr->num_chunk_list*5; /* beyond end */\n\n   /* The code is the fifth byte after each four byte string.  Historically this\n    * code was always searched from the end of the list, this is no longer\n    * necessary because the 'set' routine handles duplicate entries correctly.\n    */\n   do /* num_chunk_list > 0, so at least one */\n   {\n      p -= 5;\n\n      if (memcmp(chunk_name, p, 4) == 0)\n         return p[4];\n   }\n   while (p > p_end);\n\n   /* This means that known chunks should be processed and unknown chunks should\n    * be handled according to the value of png_ptr->unknown_default; this can be\n    * confusing because, as a result, there are two levels of defaulting for\n    * unknown chunks.\n    */\n   return PNG_HANDLE_CHUNK_AS_DEFAULT;\n}\n\n#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\\\n   defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)\nint /* PRIVATE */\npng_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name)\n{\n   png_byte chunk_string[5];\n\n   PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name);\n   return png_handle_as_unknown(png_ptr, chunk_string);\n}\n#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */\n#endif /* SET_UNKNOWN_CHUNKS */\n\n#ifdef PNG_READ_SUPPORTED\n/* This function, added to libpng-1.0.6g, is untested. */\nint PNGAPI\npng_reset_zstream(png_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return Z_STREAM_ERROR;\n\n   /* WARNING: this resets the window bits to the maximum! */\n   return (inflateReset(&png_ptr->zstream));\n}\n#endif /* READ */\n\n/* This function was added to libpng-1.0.7 */\npng_uint_32 PNGAPI\npng_access_version_number(void)\n{\n   /* Version of *.c files used when building libpng */\n   return((png_uint_32)PNG_LIBPNG_VER);\n}\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n/* Ensure that png_ptr->zstream.msg holds some appropriate error message string.\n * If it doesn't 'ret' is used to set it to something appropriate, even in cases\n * like Z_OK or Z_STREAM_END where the error code is apparently a success code.\n */\nvoid /* PRIVATE */\npng_zstream_error(png_structrp png_ptr, int ret)\n{\n   /* Translate 'ret' into an appropriate error string, priority is given to the\n    * one in zstream if set.  This always returns a string, even in cases like\n    * Z_OK or Z_STREAM_END where the error code is a success code.\n    */\n   if (png_ptr->zstream.msg == NULL) switch (ret)\n   {\n      default:\n      case Z_OK:\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"unexpected zlib return code\");\n         break;\n\n      case Z_STREAM_END:\n         /* Normal exit */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"unexpected end of LZ stream\");\n         break;\n\n      case Z_NEED_DICT:\n         /* This means the deflate stream did not have a dictionary; this\n          * indicates a bogus PNG.\n          */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"missing LZ dictionary\");\n         break;\n\n      case Z_ERRNO:\n         /* gz APIs only: should not happen */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"zlib IO error\");\n         break;\n\n      case Z_STREAM_ERROR:\n         /* internal libpng error */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"bad parameters to zlib\");\n         break;\n\n      case Z_DATA_ERROR:\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"damaged LZ stream\");\n         break;\n\n      case Z_MEM_ERROR:\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"insufficient memory\");\n         break;\n\n      case Z_BUF_ERROR:\n         /* End of input or output; not a problem if the caller is doing\n          * incremental read or write.\n          */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"truncated\");\n         break;\n\n      case Z_VERSION_ERROR:\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"unsupported zlib version\");\n         break;\n\n      case PNG_UNEXPECTED_ZLIB_RETURN:\n         /* Compile errors here mean that zlib now uses the value co-opted in\n          * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above\n          * and change pngpriv.h.  Note that this message is \"... return\",\n          * whereas the default/Z_OK one is \"... return code\".\n          */\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"unexpected zlib return\");\n         break;\n   }\n}\n\n/* png_convert_size: a PNGAPI but no longer in png.h, so deleted\n * at libpng 1.5.5!\n */\n\n/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */\n#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */\nstatic int\npng_colorspace_check_gamma(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, png_fixed_point gAMA, int from)\n   /* This is called to check a new gamma value against an existing one.  The\n    * routine returns false if the new gamma value should not be written.\n    *\n    * 'from' says where the new gamma value comes from:\n    *\n    *    0: the new gamma value is the libpng estimate for an ICC profile\n    *    1: the new gamma value comes from a gAMA chunk\n    *    2: the new gamma value comes from an sRGB chunk\n    */\n{\n   png_fixed_point gtest;\n\n   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&\n       (png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) == 0  ||\n      png_gamma_significant(gtest) != 0))\n   {\n      /* Either this is an sRGB image, in which case the calculated gamma\n       * approximation should match, or this is an image with a profile and the\n       * value libpng calculates for the gamma of the profile does not match the\n       * value recorded in the file.  The former, sRGB, case is an error, the\n       * latter is just a warning.\n       */\n      if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)\n      {\n         png_chunk_report(png_ptr, \"gamma value does not match sRGB\",\n             PNG_CHUNK_ERROR);\n         /* Do not overwrite an sRGB value */\n         return from == 2;\n      }\n\n      else /* sRGB tag not involved */\n      {\n         png_chunk_report(png_ptr, \"gamma value does not match libpng estimate\",\n             PNG_CHUNK_WARNING);\n         return from == 1;\n      }\n   }\n\n   return 1;\n}\n\nvoid /* PRIVATE */\npng_colorspace_set_gamma(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, png_fixed_point gAMA)\n{\n   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't\n    * occur.  Since the fixed point representation is asymmetrical it is\n    * possible for 1/gamma to overflow the limit of 21474 and this means the\n    * gamma value must be at least 5/100000 and hence at most 20000.0.  For\n    * safety the limits here are a little narrower.  The values are 0.00016 to\n    * 6250.0, which are truly ridiculous gamma values (and will produce\n    * displays that are all black or all white.)\n    *\n    * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk\n    * handling code, which only required the value to be >0.\n    */\n   png_const_charp errmsg;\n\n   if (gAMA < 16 || gAMA > 625000000)\n      errmsg = \"gamma value out of range\";\n\n#  ifdef PNG_READ_gAMA_SUPPORTED\n   /* Allow the application to set the gamma value more than once */\n   else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&\n      (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)\n      errmsg = \"duplicate\";\n#  endif\n\n   /* Do nothing if the colorspace is already invalid */\n   else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)\n      return;\n\n   else\n   {\n      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,\n          1/*from gAMA*/) != 0)\n      {\n         /* Store this gamma value. */\n         colorspace->gamma = gAMA;\n         colorspace->flags |=\n            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);\n      }\n\n      /* At present if the check_gamma test fails the gamma of the colorspace is\n       * not updated however the colorspace is not invalidated.  This\n       * corresponds to the case where the existing gamma comes from an sRGB\n       * chunk or profile.  An error message has already been output.\n       */\n      return;\n   }\n\n   /* Error exit - errmsg has been set. */\n   colorspace->flags |= PNG_COLORSPACE_INVALID;\n   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);\n}\n\nvoid /* PRIVATE */\npng_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)\n{\n   if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)\n   {\n      /* Everything is invalid */\n      info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|\n         PNG_INFO_iCCP);\n\n#     ifdef PNG_COLORSPACE_SUPPORTED\n      /* Clean up the iCCP profile now if it won't be used. */\n      png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);\n#     else\n      PNG_UNUSED(png_ptr)\n#     endif\n   }\n\n   else\n   {\n#     ifdef PNG_COLORSPACE_SUPPORTED\n      /* Leave the INFO_iCCP flag set if the pngset.c code has already set\n       * it; this allows a PNG to contain a profile which matches sRGB and\n       * yet still have that profile retrievable by the application.\n       */\n      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0)\n         info_ptr->valid |= PNG_INFO_sRGB;\n\n      else\n         info_ptr->valid &= ~PNG_INFO_sRGB;\n\n      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n         info_ptr->valid |= PNG_INFO_cHRM;\n\n      else\n         info_ptr->valid &= ~PNG_INFO_cHRM;\n#     endif\n\n      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0)\n         info_ptr->valid |= PNG_INFO_gAMA;\n\n      else\n         info_ptr->valid &= ~PNG_INFO_gAMA;\n   }\n}\n\n#ifdef PNG_READ_SUPPORTED\nvoid /* PRIVATE */\npng_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)\n{\n   if (info_ptr == NULL) /* reduce code size; check here not in the caller */\n      return;\n\n   info_ptr->colorspace = png_ptr->colorspace;\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n#endif\n#endif /* GAMMA */\n\n#ifdef PNG_COLORSPACE_SUPPORTED\n/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for\n * cHRM, as opposed to using chromaticities.  These internal APIs return\n * non-zero on a parameter error.  The X, Y and Z values are required to be\n * positive and less than 1.0.\n */\nstatic int\npng_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)\n{\n   png_int_32 d, dwhite, whiteX, whiteY;\n\n   d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z;\n   if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)\n      return 1;\n   if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)\n      return 1;\n   dwhite = d;\n   whiteX = XYZ->red_X;\n   whiteY = XYZ->red_Y;\n\n   d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z;\n   if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)\n      return 1;\n   if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)\n      return 1;\n   dwhite += d;\n   whiteX += XYZ->green_X;\n   whiteY += XYZ->green_Y;\n\n   d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z;\n   if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)\n      return 1;\n   if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)\n      return 1;\n   dwhite += d;\n   whiteX += XYZ->blue_X;\n   whiteY += XYZ->blue_Y;\n\n   /* The reference white is simply the sum of the end-point (X,Y,Z) vectors,\n    * thus:\n    */\n   if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0)\n      return 1;\n   if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)\n      return 1;\n\n   return 0;\n}\n\nstatic int\npng_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)\n{\n   png_fixed_point red_inverse, green_inverse, blue_scale;\n   png_fixed_point left, right, denominator;\n\n   /* Check xy and, implicitly, z.  Note that wide gamut color spaces typically\n    * have end points with 0 tristimulus values (these are impossible end\n    * points, but they are used to cover the possible colors).  We check\n    * xy->whitey against 5, not 0, to avoid a possible integer overflow.\n    */\n   if (xy->redx   < 0 || xy->redx > PNG_FP_1) return 1;\n   if (xy->redy   < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;\n   if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;\n   if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;\n   if (xy->bluex  < 0 || xy->bluex > PNG_FP_1) return 1;\n   if (xy->bluey  < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;\n   if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;\n   if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1;\n\n   /* The reverse calculation is more difficult because the original tristimulus\n    * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8\n    * derived values were recorded in the cHRM chunk;\n    * (red,green,blue,white)x(x,y).  This loses one degree of freedom and\n    * therefore an arbitrary ninth value has to be introduced to undo the\n    * original transformations.\n    *\n    * Think of the original end-points as points in (X,Y,Z) space.  The\n    * chromaticity values (c) have the property:\n    *\n    *           C\n    *   c = ---------\n    *       X + Y + Z\n    *\n    * For each c (x,y,z) from the corresponding original C (X,Y,Z).  Thus the\n    * three chromaticity values (x,y,z) for each end-point obey the\n    * relationship:\n    *\n    *   x + y + z = 1\n    *\n    * This describes the plane in (X,Y,Z) space that intersects each axis at the\n    * value 1.0; call this the chromaticity plane.  Thus the chromaticity\n    * calculation has scaled each end-point so that it is on the x+y+z=1 plane\n    * and chromaticity is the intersection of the vector from the origin to the\n    * (X,Y,Z) value with the chromaticity plane.\n    *\n    * To fully invert the chromaticity calculation we would need the three\n    * end-point scale factors, (red-scale, green-scale, blue-scale), but these\n    * were not recorded.  Instead we calculated the reference white (X,Y,Z) and\n    * recorded the chromaticity of this.  The reference white (X,Y,Z) would have\n    * given all three of the scale factors since:\n    *\n    *    color-C = color-c * color-scale\n    *    white-C = red-C + green-C + blue-C\n    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale\n    *\n    * But cHRM records only white-x and white-y, so we have lost the white scale\n    * factor:\n    *\n    *    white-C = white-c*white-scale\n    *\n    * To handle this the inverse transformation makes an arbitrary assumption\n    * about white-scale:\n    *\n    *    Assume: white-Y = 1.0\n    *    Hence:  white-scale = 1/white-y\n    *    Or:     red-Y + green-Y + blue-Y = 1.0\n    *\n    * Notice the last statement of the assumption gives an equation in three of\n    * the nine values we want to calculate.  8 more equations come from the\n    * above routine as summarised at the top above (the chromaticity\n    * calculation):\n    *\n    *    Given: color-x = color-X / (color-X + color-Y + color-Z)\n    *    Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0\n    *\n    * This is 9 simultaneous equations in the 9 variables \"color-C\" and can be\n    * solved by Cramer's rule.  Cramer's rule requires calculating 10 9x9 matrix\n    * determinants, however this is not as bad as it seems because only 28 of\n    * the total of 90 terms in the various matrices are non-zero.  Nevertheless\n    * Cramer's rule is notoriously numerically unstable because the determinant\n    * calculation involves the difference of large, but similar, numbers.  It is\n    * difficult to be sure that the calculation is stable for real world values\n    * and it is certain that it becomes unstable where the end points are close\n    * together.\n    *\n    * So this code uses the perhaps slightly less optimal but more\n    * understandable and totally obvious approach of calculating color-scale.\n    *\n    * This algorithm depends on the precision in white-scale and that is\n    * (1/white-y), so we can immediately see that as white-y approaches 0 the\n    * accuracy inherent in the cHRM chunk drops off substantially.\n    *\n    * libpng arithmetic: a simple inversion of the above equations\n    * ------------------------------------------------------------\n    *\n    *    white_scale = 1/white-y\n    *    white-X = white-x * white-scale\n    *    white-Y = 1.0\n    *    white-Z = (1 - white-x - white-y) * white_scale\n    *\n    *    white-C = red-C + green-C + blue-C\n    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale\n    *\n    * This gives us three equations in (red-scale,green-scale,blue-scale) where\n    * all the coefficients are now known:\n    *\n    *    red-x*red-scale + green-x*green-scale + blue-x*blue-scale\n    *       = white-x/white-y\n    *    red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1\n    *    red-z*red-scale + green-z*green-scale + blue-z*blue-scale\n    *       = (1 - white-x - white-y)/white-y\n    *\n    * In the last equation color-z is (1 - color-x - color-y) so we can add all\n    * three equations together to get an alternative third:\n    *\n    *    red-scale + green-scale + blue-scale = 1/white-y = white-scale\n    *\n    * So now we have a Cramer's rule solution where the determinants are just\n    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve\n    * multiplication of three coefficients so we can't guarantee to avoid\n    * overflow in the libpng fixed point representation.  Using Cramer's rule in\n    * floating point is probably a good choice here, but it's not an option for\n    * fixed point.  Instead proceed to simplify the first two equations by\n    * eliminating what is likely to be the largest value, blue-scale:\n    *\n    *    blue-scale = white-scale - red-scale - green-scale\n    *\n    * Hence:\n    *\n    *    (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale =\n    *                (white-x - blue-x)*white-scale\n    *\n    *    (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale =\n    *                1 - blue-y*white-scale\n    *\n    * And now we can trivially solve for (red-scale,green-scale):\n    *\n    *    green-scale =\n    *                (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale\n    *                -----------------------------------------------------------\n    *                                  green-x - blue-x\n    *\n    *    red-scale =\n    *                1 - blue-y*white-scale - (green-y - blue-y) * green-scale\n    *                ---------------------------------------------------------\n    *                                  red-y - blue-y\n    *\n    * Hence:\n    *\n    *    red-scale =\n    *          ( (green-x - blue-x) * (white-y - blue-y) -\n    *            (green-y - blue-y) * (white-x - blue-x) ) / white-y\n    * -------------------------------------------------------------------------\n    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)\n    *\n    *    green-scale =\n    *          ( (red-y - blue-y) * (white-x - blue-x) -\n    *            (red-x - blue-x) * (white-y - blue-y) ) / white-y\n    * -------------------------------------------------------------------------\n    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)\n    *\n    * Accuracy:\n    * The input values have 5 decimal digits of accuracy.  The values are all in\n    * the range 0 < value < 1, so simple products are in the same range but may\n    * need up to 10 decimal digits to preserve the original precision and avoid\n    * underflow.  Because we are using a 32-bit signed representation we cannot\n    * match this; the best is a little over 9 decimal digits, less than 10.\n    *\n    * The approach used here is to preserve the maximum precision within the\n    * signed representation.  Because the red-scale calculation above uses the\n    * difference between two products of values that must be in the range -1..+1\n    * it is sufficient to divide the product by 7; ceil(100,000/32767*2).  The\n    * factor is irrelevant in the calculation because it is applied to both\n    * numerator and denominator.\n    *\n    * Note that the values of the differences of the products of the\n    * chromaticities in the above equations tend to be small, for example for\n    * the sRGB chromaticities they are:\n    *\n    * red numerator:    -0.04751\n    * green numerator:  -0.08788\n    * denominator:      -0.2241 (without white-y multiplication)\n    *\n    *  The resultant Y coefficients from the chromaticities of some widely used\n    *  color space definitions are (to 15 decimal places):\n    *\n    *  sRGB\n    *    0.212639005871510 0.715168678767756 0.072192315360734\n    *  Kodak ProPhoto\n    *    0.288071128229293 0.711843217810102 0.000085653960605\n    *  Adobe RGB\n    *    0.297344975250536 0.627363566255466 0.075291458493998\n    *  Adobe Wide Gamut RGB\n    *    0.258728243040113 0.724682314948566 0.016589442011321\n    */\n   /* By the argument, above overflow should be impossible here. The return\n    * value of 2 indicates an internal error to the caller.\n    */\n   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0)\n      return 2;\n   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)\n      return 2;\n   denominator = left - right;\n\n   /* Now find the red numerator. */\n   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)\n      return 2;\n   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)\n      return 2;\n\n   /* Overflow is possible here and it indicates an extreme set of PNG cHRM\n    * chunk values.  This calculation actually returns the reciprocal of the\n    * scale value because this allows us to delay the multiplication of white-y\n    * into the denominator, which tends to produce a small number.\n    */\n   if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 ||\n       red_inverse <= xy->whitey /* r+g+b scales = white scale */)\n      return 1;\n\n   /* Similarly for green_inverse: */\n   if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)\n      return 2;\n   if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)\n      return 2;\n   if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||\n       green_inverse <= xy->whitey)\n      return 1;\n\n   /* And the blue scale, the checks above guarantee this can't overflow but it\n    * can still produce 0 for extreme cHRM values.\n    */\n   blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -\n       png_reciprocal(green_inverse);\n   if (blue_scale <= 0)\n      return 1;\n\n\n   /* And fill in the png_XYZ: */\n   if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,\n       red_inverse) == 0)\n      return 1;\n\n   if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,\n       green_inverse) == 0)\n      return 1;\n\n   if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0)\n      return 1;\n   if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,\n       PNG_FP_1) == 0)\n      return 1;\n\n   return 0; /*success*/\n}\n\nstatic int\npng_XYZ_normalize(png_XYZ *XYZ)\n{\n   png_int_32 Y;\n\n   if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 ||\n      XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||\n      XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)\n      return 1;\n\n   /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1.\n    * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore\n    * relying on addition of two positive values producing a negative one is not\n    * safe.\n    */\n   Y = XYZ->red_Y;\n   if (0x7fffffff - Y < XYZ->green_X)\n      return 1;\n   Y += XYZ->green_Y;\n   if (0x7fffffff - Y < XYZ->blue_X)\n      return 1;\n   Y += XYZ->blue_Y;\n\n   if (Y != PNG_FP_1)\n   {\n      if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)\n         return 1;\n\n      if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)\n         return 1;\n\n      if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)\n         return 1;\n      if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)\n         return 1;\n   }\n\n   return 0;\n}\n\nstatic int\npng_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta)\n{\n   /* Allow an error of +/-0.01 (absolute value) on each chromaticity */\n   if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||\n       PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||\n       PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||\n       PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||\n       PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||\n       PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||\n       PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||\n       PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta))\n      return 0;\n   return 1;\n}\n\n/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM\n * chunk chromaticities.  Earlier checks used to simply look for the overflow\n * condition (where the determinant of the matrix to solve for XYZ ends up zero\n * because the chromaticity values are not all distinct.)  Despite this it is\n * theoretically possible to produce chromaticities that are apparently valid\n * but that rapidly degrade to invalid, potentially crashing, sets because of\n * arithmetic inaccuracies when calculations are performed on them.  The new\n * check is to round-trip xy -> XYZ -> xy and then check that the result is\n * within a small percentage of the original.\n */\nstatic int\npng_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy)\n{\n   int result;\n   png_xy xy_test;\n\n   /* As a side-effect this routine also returns the XYZ endpoints. */\n   result = png_XYZ_from_xy(XYZ, xy);\n   if (result != 0)\n      return result;\n\n   result = png_xy_from_XYZ(&xy_test, XYZ);\n   if (result != 0)\n      return result;\n\n   if (png_colorspace_endpoints_match(xy, &xy_test,\n       5/*actually, the math is pretty accurate*/) != 0)\n      return 0;\n\n   /* Too much slip */\n   return 1;\n}\n\n/* This is the check going the other way.  The XYZ is modified to normalize it\n * (another side-effect) and the xy chromaticities are returned.\n */\nstatic int\npng_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ)\n{\n   int result;\n   png_XYZ XYZtemp;\n\n   result = png_XYZ_normalize(XYZ);\n   if (result != 0)\n      return result;\n\n   result = png_xy_from_XYZ(xy, XYZ);\n   if (result != 0)\n      return result;\n\n   XYZtemp = *XYZ;\n   return png_colorspace_check_xy(&XYZtemp, xy);\n}\n\n/* Used to check for an endpoint match against sRGB */\nstatic const png_xy sRGB_xy = /* From ITU-R BT.709-3 */\n{\n   /* color      x       y */\n   /* red   */ 64000, 33000,\n   /* green */ 30000, 60000,\n   /* blue  */ 15000,  6000,\n   /* white */ 31270, 32900\n};\n\nstatic int\npng_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,\n    int preferred)\n{\n   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)\n      return 0;\n\n   /* The consistency check is performed on the chromaticities; this factors out\n    * variations because of the normalization (or not) of the end point Y\n    * values.\n    */\n   if (preferred < 2 &&\n       (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      /* The end points must be reasonably close to any we already have.  The\n       * following allows an error of up to +/-.001\n       */\n      if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy,\n          100) == 0)\n      {\n         colorspace->flags |= PNG_COLORSPACE_INVALID;\n         png_benign_error(png_ptr, \"inconsistent chromaticities\");\n         return 0; /* failed */\n      }\n\n      /* Only overwrite with preferred values */\n      if (preferred == 0)\n         return 1; /* ok, but no change */\n   }\n\n   colorspace->end_points_xy = *xy;\n   colorspace->end_points_XYZ = *XYZ;\n   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;\n\n   /* The end points are normally quoted to two decimal digits, so allow +/-0.01\n    * on this test.\n    */\n   if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0)\n      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;\n\n   else\n      colorspace->flags &= PNG_COLORSPACE_CANCEL(\n         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);\n\n   return 2; /* ok and changed */\n}\n\nint /* PRIVATE */\npng_colorspace_set_chromaticities(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, const png_xy *xy, int preferred)\n{\n   /* We must check the end points to ensure they are reasonable - in the past\n    * color management systems have crashed as a result of getting bogus\n    * colorant values, while this isn't the fault of libpng it is the\n    * responsibility of libpng because PNG carries the bomb and libpng is in a\n    * position to protect against it.\n    */\n   png_XYZ XYZ;\n\n   switch (png_colorspace_check_xy(&XYZ, xy))\n   {\n      case 0: /* success */\n         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,\n             preferred);\n\n      case 1:\n         /* We can't invert the chromaticities so we can't produce value XYZ\n          * values.  Likely as not a color management system will fail too.\n          */\n         colorspace->flags |= PNG_COLORSPACE_INVALID;\n         png_benign_error(png_ptr, \"invalid chromaticities\");\n         break;\n\n      default:\n         /* libpng is broken; this should be a warning but if it happens we\n          * want error reports so for the moment it is an error.\n          */\n         colorspace->flags |= PNG_COLORSPACE_INVALID;\n         png_error(png_ptr, \"internal error checking chromaticities\");\n   }\n\n   return 0; /* failed */\n}\n\nint /* PRIVATE */\npng_colorspace_set_endpoints(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)\n{\n   png_XYZ XYZ = *XYZ_in;\n   png_xy xy;\n\n   switch (png_colorspace_check_XYZ(&xy, &XYZ))\n   {\n      case 0:\n         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,\n             preferred);\n\n      case 1:\n         /* End points are invalid. */\n         colorspace->flags |= PNG_COLORSPACE_INVALID;\n         png_benign_error(png_ptr, \"invalid end points\");\n         break;\n\n      default:\n         colorspace->flags |= PNG_COLORSPACE_INVALID;\n         png_error(png_ptr, \"internal error checking chromaticities\");\n   }\n\n   return 0; /* failed */\n}\n\n#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED)\n/* Error message generation */\nstatic char\npng_icc_tag_char(png_uint_32 byte)\n{\n   byte &= 0xff;\n   if (byte >= 32 && byte <= 126)\n      return (char)byte;\n   else\n      return '?';\n}\n\nstatic void\npng_icc_tag_name(char *name, png_uint_32 tag)\n{\n   name[0] = '\\'';\n   name[1] = png_icc_tag_char(tag >> 24);\n   name[2] = png_icc_tag_char(tag >> 16);\n   name[3] = png_icc_tag_char(tag >>  8);\n   name[4] = png_icc_tag_char(tag      );\n   name[5] = '\\'';\n}\n\nstatic int\nis_ICC_signature_char(png_alloc_size_t it)\n{\n   return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||\n      (it >= 97 && it <= 122);\n}\n\nstatic int\nis_ICC_signature(png_alloc_size_t it)\n{\n   return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&\n      is_ICC_signature_char((it >> 16) & 0xff) &&\n      is_ICC_signature_char((it >> 8) & 0xff) &&\n      is_ICC_signature_char(it & 0xff);\n}\n\nstatic int\npng_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_alloc_size_t value, png_const_charp reason)\n{\n   size_t pos;\n   char message[196]; /* see below for calculation */\n\n   if (colorspace != NULL)\n      colorspace->flags |= PNG_COLORSPACE_INVALID;\n\n   pos = png_safecat(message, (sizeof message), 0, \"profile '\"); /* 9 chars */\n   pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */\n   pos = png_safecat(message, (sizeof message), pos, \"': \"); /* +2 = 90 */\n   if (is_ICC_signature(value) != 0)\n   {\n      /* So 'value' is at most 4 bytes and the following cast is safe */\n      png_icc_tag_name(message+pos, (png_uint_32)value);\n      pos += 6; /* total +8; less than the else clause */\n      message[pos++] = ':';\n      message[pos++] = ' ';\n   }\n#  ifdef PNG_WARNINGS_SUPPORTED\n   else\n      {\n         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/\n\n         pos = png_safecat(message, (sizeof message), pos,\n             png_format_number(number, number+(sizeof number),\n             PNG_NUMBER_FORMAT_x, value));\n         pos = png_safecat(message, (sizeof message), pos, \"h: \"); /*+2 = 116*/\n      }\n#  endif\n   /* The 'reason' is an arbitrary message, allow +79 maximum 195 */\n   pos = png_safecat(message, (sizeof message), pos, reason);\n   PNG_UNUSED(pos)\n\n   /* This is recoverable, but make it unconditionally an app_error on write to\n    * avoid writing invalid ICC profiles into PNG files (i.e., we handle them\n    * on read, with a warning, but on write unless the app turns off\n    * application errors the PNG won't be written.)\n    */\n   png_chunk_report(png_ptr, message,\n       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);\n\n   return 0;\n}\n#endif /* sRGB || iCCP */\n\n#ifdef PNG_sRGB_SUPPORTED\nint /* PRIVATE */\npng_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    int intent)\n{\n   /* sRGB sets known gamma, end points and (from the chunk) intent. */\n   /* IMPORTANT: these are not necessarily the values found in an ICC profile\n    * because ICC profiles store values adapted to a D50 environment; it is\n    * expected that the ICC profile mediaWhitePointTag will be D50; see the\n    * checks and code elsewhere to understand this better.\n    *\n    * These XYZ values, which are accurate to 5dp, produce rgb to gray\n    * coefficients of (6968,23435,2366), which are reduced (because they add up\n    * to 32769 not 32768) to (6968,23434,2366).  These are the values that\n    * libpng has traditionally used (and are the best values given the 15bit\n    * algorithm used by the rgb to gray code.)\n    */\n   static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */\n   {\n      /* color      X      Y      Z */\n      /* red   */ 41239, 21264,  1933,\n      /* green */ 35758, 71517, 11919,\n      /* blue  */ 18048,  7219, 95053\n   };\n\n   /* Do nothing if the colorspace is already invalidated. */\n   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)\n      return 0;\n\n   /* Check the intent, then check for existing settings.  It is valid for the\n    * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must\n    * be consistent with the correct values.  If, however, this function is\n    * called below because an iCCP chunk matches sRGB then it is quite\n    * conceivable that an older app recorded incorrect gAMA and cHRM because of\n    * an incorrect calculation based on the values in the profile - this does\n    * *not* invalidate the profile (though it still produces an error, which can\n    * be ignored.)\n    */\n   if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)\n      return png_icc_profile_error(png_ptr, colorspace, \"sRGB\",\n          (png_alloc_size_t)intent, \"invalid sRGB rendering intent\");\n\n   if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&\n       colorspace->rendering_intent != intent)\n      return png_icc_profile_error(png_ptr, colorspace, \"sRGB\",\n         (png_alloc_size_t)intent, \"inconsistent rendering intents\");\n\n   if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)\n   {\n      png_benign_error(png_ptr, \"duplicate sRGB information ignored\");\n      return 0;\n   }\n\n   /* If the standard sRGB cHRM chunk does not match the one from the PNG file\n    * warn but overwrite the value with the correct one.\n    */\n   if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&\n       !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,\n       100))\n      png_chunk_report(png_ptr, \"cHRM chunk does not match sRGB\",\n         PNG_CHUNK_ERROR);\n\n   /* This check is just done for the error reporting - the routine always\n    * returns true when the 'from' argument corresponds to sRGB (2).\n    */\n   (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,\n       2/*from sRGB*/);\n\n   /* intent: bugs in GCC force 'int' to be used as the parameter type. */\n   colorspace->rendering_intent = (png_uint_16)intent;\n   colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;\n\n   /* endpoints */\n   colorspace->end_points_xy = sRGB_xy;\n   colorspace->end_points_XYZ = sRGB_XYZ;\n   colorspace->flags |=\n      (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);\n\n   /* gamma */\n   colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;\n   colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;\n\n   /* Finally record that we have an sRGB profile */\n   colorspace->flags |=\n      (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);\n\n   return 1; /* set */\n}\n#endif /* sRGB */\n\n#ifdef PNG_iCCP_SUPPORTED\n/* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value\n * is XYZ(0.9642,1.0,0.8249), which scales to:\n *\n *    (63189.8112, 65536, 54060.6464)\n */\nstatic const png_byte D50_nCIEXYZ[12] =\n   { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };\n\nstatic int /* bool */\nicc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_uint_32 profile_length)\n{\n   if (profile_length < 132)\n      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,\n          \"too short\");\n   return 1;\n}\n\n#ifdef PNG_READ_iCCP_SUPPORTED\nint /* PRIVATE */\npng_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_uint_32 profile_length)\n{\n   if (!icc_check_length(png_ptr, colorspace, name, profile_length))\n      return 0;\n\n   /* This needs to be here because the 'normal' check is in\n    * png_decompress_chunk, yet this happens after the attempt to\n    * png_malloc_base the required data.  We only need this on read; on write\n    * the caller supplies the profile buffer so libpng doesn't allocate it.  See\n    * the call to icc_check_length below (the write case).\n    */\n#  ifdef PNG_SET_USER_LIMITS_SUPPORTED\n      else if (png_ptr->user_chunk_malloc_max > 0 &&\n               png_ptr->user_chunk_malloc_max < profile_length)\n         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,\n             \"exceeds application limits\");\n#  elif PNG_USER_CHUNK_MALLOC_MAX > 0\n      else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)\n         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,\n             \"exceeds libpng limits\");\n#  else /* !SET_USER_LIMITS */\n      /* This will get compiled out on all 32-bit and better systems. */\n      else if (PNG_SIZE_MAX < profile_length)\n         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,\n             \"exceeds system limits\");\n#  endif /* !SET_USER_LIMITS */\n\n   return 1;\n}\n#endif /* READ_iCCP */\n\nint /* PRIVATE */\npng_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_uint_32 profile_length,\n    png_const_bytep profile/* first 132 bytes only */, int color_type)\n{\n   png_uint_32 temp;\n\n   /* Length check; this cannot be ignored in this code because profile_length\n    * is used later to check the tag table, so even if the profile seems over\n    * long profile_length from the caller must be correct.  The caller can fix\n    * this up on read or write by just passing in the profile header length.\n    */\n   temp = png_get_uint_32(profile);\n   if (temp != profile_length)\n      return png_icc_profile_error(png_ptr, colorspace, name, temp,\n          \"length does not match profile\");\n\n   temp = (png_uint_32) (*(profile+8));\n   if (temp > 3 && (profile_length & 3))\n      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,\n          \"invalid length\");\n\n   temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */\n   if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */\n      profile_length < 132+12*temp) /* truncated tag table */\n      return png_icc_profile_error(png_ptr, colorspace, name, temp,\n          \"tag count too large\");\n\n   /* The 'intent' must be valid or we can't store it, ICC limits the intent to\n    * 16 bits.\n    */\n   temp = png_get_uint_32(profile+64);\n   if (temp >= 0xffff) /* The ICC limit */\n      return png_icc_profile_error(png_ptr, colorspace, name, temp,\n          \"invalid rendering intent\");\n\n   /* This is just a warning because the profile may be valid in future\n    * versions.\n    */\n   if (temp >= PNG_sRGB_INTENT_LAST)\n      (void)png_icc_profile_error(png_ptr, NULL, name, temp,\n          \"intent outside defined range\");\n\n   /* At this point the tag table can't be checked because it hasn't necessarily\n    * been loaded; however, various header fields can be checked.  These checks\n    * are for values permitted by the PNG spec in an ICC profile; the PNG spec\n    * restricts the profiles that can be passed in an iCCP chunk (they must be\n    * appropriate to processing PNG data!)\n    */\n\n   /* Data checks (could be skipped).  These checks must be independent of the\n    * version number; however, the version number doesn't accommodate changes in\n    * the header fields (just the known tags and the interpretation of the\n    * data.)\n    */\n   temp = png_get_uint_32(profile+36); /* signature 'ascp' */\n   if (temp != 0x61637370)\n      return png_icc_profile_error(png_ptr, colorspace, name, temp,\n          \"invalid signature\");\n\n   /* Currently the PCS illuminant/adopted white point (the computational\n    * white point) are required to be D50,\n    * however the profile contains a record of the illuminant so perhaps ICC\n    * expects to be able to change this in the future (despite the rationale in\n    * the introduction for using a fixed PCS adopted white.)  Consequently the\n    * following is just a warning.\n    */\n   if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)\n      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,\n          \"PCS illuminant is not D50\");\n\n   /* The PNG spec requires this:\n    * \"If the iCCP chunk is present, the image samples conform to the colour\n    * space represented by the embedded ICC profile as defined by the\n    * International Color Consortium [ICC]. The colour space of the ICC profile\n    * shall be an RGB colour space for colour images (PNG colour types 2, 3, and\n    * 6), or a greyscale colour space for greyscale images (PNG colour types 0\n    * and 4).\"\n    *\n    * This checking code ensures the embedded profile (on either read or write)\n    * conforms to the specification requirements.  Notice that an ICC 'gray'\n    * color-space profile contains the information to transform the monochrome\n    * data to XYZ or L*a*b (according to which PCS the profile uses) and this\n    * should be used in preference to the standard libpng K channel replication\n    * into R, G and B channels.\n    *\n    * Previously it was suggested that an RGB profile on grayscale data could be\n    * handled.  However it it is clear that using an RGB profile in this context\n    * must be an error - there is no specification of what it means.  Thus it is\n    * almost certainly more correct to ignore the profile.\n    */\n   temp = png_get_uint_32(profile+16); /* data colour space field */\n   switch (temp)\n   {\n      case 0x52474220: /* 'RGB ' */\n         if ((color_type & PNG_COLOR_MASK_COLOR) == 0)\n            return png_icc_profile_error(png_ptr, colorspace, name, temp,\n                \"RGB color space not permitted on grayscale PNG\");\n         break;\n\n      case 0x47524159: /* 'GRAY' */\n         if ((color_type & PNG_COLOR_MASK_COLOR) != 0)\n            return png_icc_profile_error(png_ptr, colorspace, name, temp,\n                \"Gray color space not permitted on RGB PNG\");\n         break;\n\n      default:\n         return png_icc_profile_error(png_ptr, colorspace, name, temp,\n             \"invalid ICC profile color space\");\n   }\n\n   /* It is up to the application to check that the profile class matches the\n    * application requirements; the spec provides no guidance, but it's pretty\n    * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer\n    * ('prtr') or 'spac' (for generic color spaces).  Issue a warning in these\n    * cases.  Issue an error for device link or abstract profiles - these don't\n    * contain the records necessary to transform the color-space to anything\n    * other than the target device (and not even that for an abstract profile).\n    * Profiles of these classes may not be embedded in images.\n    */\n   temp = png_get_uint_32(profile+12); /* profile/device class */\n   switch (temp)\n   {\n      case 0x73636e72: /* 'scnr' */\n      case 0x6d6e7472: /* 'mntr' */\n      case 0x70727472: /* 'prtr' */\n      case 0x73706163: /* 'spac' */\n         /* All supported */\n         break;\n\n      case 0x61627374: /* 'abst' */\n         /* May not be embedded in an image */\n         return png_icc_profile_error(png_ptr, colorspace, name, temp,\n             \"invalid embedded Abstract ICC profile\");\n\n      case 0x6c696e6b: /* 'link' */\n         /* DeviceLink profiles cannot be interpreted in a non-device specific\n          * fashion, if an app uses the AToB0Tag in the profile the results are\n          * undefined unless the result is sent to the intended device,\n          * therefore a DeviceLink profile should not be found embedded in a\n          * PNG.\n          */\n         return png_icc_profile_error(png_ptr, colorspace, name, temp,\n             \"unexpected DeviceLink ICC profile class\");\n\n      case 0x6e6d636c: /* 'nmcl' */\n         /* A NamedColor profile is also device specific, however it doesn't\n          * contain an AToB0 tag that is open to misinterpretation.  Almost\n          * certainly it will fail the tests below.\n          */\n         (void)png_icc_profile_error(png_ptr, NULL, name, temp,\n             \"unexpected NamedColor ICC profile class\");\n         break;\n\n      default:\n         /* To allow for future enhancements to the profile accept unrecognized\n          * profile classes with a warning, these then hit the test below on the\n          * tag content to ensure they are backward compatible with one of the\n          * understood profiles.\n          */\n         (void)png_icc_profile_error(png_ptr, NULL, name, temp,\n             \"unrecognized ICC profile class\");\n         break;\n   }\n\n   /* For any profile other than a device link one the PCS must be encoded\n    * either in XYZ or Lab.\n    */\n   temp = png_get_uint_32(profile+20);\n   switch (temp)\n   {\n      case 0x58595a20: /* 'XYZ ' */\n      case 0x4c616220: /* 'Lab ' */\n         break;\n\n      default:\n         return png_icc_profile_error(png_ptr, colorspace, name, temp,\n             \"unexpected ICC PCS encoding\");\n   }\n\n   return 1;\n}\n\nint /* PRIVATE */\npng_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_uint_32 profile_length,\n    png_const_bytep profile /* header plus whole tag table */)\n{\n   png_uint_32 tag_count = png_get_uint_32(profile+128);\n   png_uint_32 itag;\n   png_const_bytep tag = profile+132; /* The first tag */\n\n   /* First scan all the tags in the table and add bits to the icc_info value\n    * (temporarily in 'tags').\n    */\n   for (itag=0; itag < tag_count; ++itag, tag += 12)\n   {\n      png_uint_32 tag_id = png_get_uint_32(tag+0);\n      png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */\n      png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */\n\n      /* The ICC specification does not exclude zero length tags, therefore the\n       * start might actually be anywhere if there is no data, but this would be\n       * a clear abuse of the intent of the standard so the start is checked for\n       * being in range.  All defined tag types have an 8 byte header - a 4 byte\n       * type signature then 0.\n       */\n\n      /* This is a hard error; potentially it can cause read outside the\n       * profile.\n       */\n      if (tag_start > profile_length || tag_length > profile_length - tag_start)\n         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,\n             \"ICC profile tag outside profile\");\n\n      if ((tag_start & 3) != 0)\n      {\n         /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is\n          * only a warning here because libpng does not care about the\n          * alignment.\n          */\n         (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,\n             \"ICC profile tag start not a multiple of 4\");\n      }\n   }\n\n   return 1; /* success, maybe with warnings */\n}\n\n#ifdef PNG_sRGB_SUPPORTED\n#if PNG_sRGB_PROFILE_CHECKS >= 0\n/* Information about the known ICC sRGB profiles */\nstatic const struct\n{\n   png_uint_32 adler, crc, length;\n   png_uint_32 md5[4];\n   png_byte    have_md5;\n   png_byte    is_broken;\n   png_uint_16 intent;\n\n#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)\n#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\\\n      { adler, crc, length, md5, broke, intent },\n\n} png_sRGB_checks[] =\n{\n   /* This data comes from contrib/tools/checksum-icc run on downloads of\n    * all four ICC sRGB profiles from www.color.org.\n    */\n   /* adler32, crc32, MD5[4], intent, date, length, file-name */\n   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,\n       PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,\n       \"2009/03/27 21:36:31\", 3048, \"sRGB_IEC61966-2-1_black_scaled.icc\")\n\n   /* ICC sRGB v2 perceptual no black-compensation: */\n   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,\n       PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,\n       \"2009/03/27 21:37:45\", 3052, \"sRGB_IEC61966-2-1_no_black_scaling.icc\")\n\n   PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,\n       PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,\n       \"2009/08/10 17:28:01\", 60988, \"sRGB_v4_ICC_preference_displayclass.icc\")\n\n   /* ICC sRGB v4 perceptual */\n   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,\n       PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,\n       \"2007/07/25 00:05:37\", 60960, \"sRGB_v4_ICC_preference.icc\")\n\n   /* The following profiles have no known MD5 checksum. If there is a match\n    * on the (empty) MD5 the other fields are used to attempt a match and\n    * a warning is produced.  The first two of these profiles have a 'cprt' tag\n    * which suggests that they were also made by Hewlett Packard.\n    */\n   PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,\n       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,\n       \"2004/07/21 18:57:42\", 3024, \"sRGB_IEC61966-2-1_noBPC.icc\")\n\n   /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not\n    * match the D50 PCS illuminant in the header (it is in fact the D65 values,\n    * so the white point is recorded as the un-adapted value.)  The profiles\n    * below only differ in one byte - the intent - and are basically the same as\n    * the previous profile except for the mediaWhitePointTag error and a missing\n    * chromaticAdaptationTag.\n    */\n   PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,\n       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,\n       \"1998/02/09 06:49:00\", 3144, \"HP-Microsoft sRGB v2 perceptual\")\n\n   PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,\n       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,\n       \"1998/02/09 06:49:00\", 3144, \"HP-Microsoft sRGB v2 media-relative\")\n};\n\nstatic int\npng_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,\n    png_const_bytep profile, uLong adler)\n{\n   /* The quick check is to verify just the MD5 signature and trust the\n    * rest of the data.  Because the profile has already been verified for\n    * correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'\n    * field too, so if the profile has been edited with an intent not defined\n    * by sRGB (but maybe defined by a later ICC specification) the read of\n    * the profile will fail at that point.\n    */\n\n   png_uint_32 length = 0;\n   png_uint_32 intent = 0x10000; /* invalid */\n#if PNG_sRGB_PROFILE_CHECKS > 1\n   uLong crc = 0; /* the value for 0 length data */\n#endif\n   unsigned int i;\n\n#ifdef PNG_SET_OPTION_SUPPORTED\n   /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to \"on\" */\n   if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==\n               PNG_OPTION_ON)\n      return 0;\n#endif\n\n   for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)\n   {\n      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&\n         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&\n         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&\n         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])\n      {\n         /* This may be one of the old HP profiles without an MD5, in that\n          * case we can only use the length and Adler32 (note that these\n          * are not used by default if there is an MD5!)\n          */\n#        if PNG_sRGB_PROFILE_CHECKS == 0\n            if (png_sRGB_checks[i].have_md5 != 0)\n               return 1+png_sRGB_checks[i].is_broken;\n#        endif\n\n         /* Profile is unsigned or more checks have been configured in. */\n         if (length == 0)\n         {\n            length = png_get_uint_32(profile);\n            intent = png_get_uint_32(profile+64);\n         }\n\n         /* Length *and* intent must match */\n         if (length == (png_uint_32) png_sRGB_checks[i].length &&\n            intent == (png_uint_32) png_sRGB_checks[i].intent)\n         {\n            /* Now calculate the adler32 if not done already. */\n            if (adler == 0)\n            {\n               adler = adler32(0, NULL, 0);\n               adler = adler32(adler, profile, length);\n            }\n\n            if (adler == png_sRGB_checks[i].adler)\n            {\n               /* These basic checks suggest that the data has not been\n                * modified, but if the check level is more than 1 perform\n                * our own crc32 checksum on the data.\n                */\n#              if PNG_sRGB_PROFILE_CHECKS > 1\n                  if (crc == 0)\n                  {\n                     crc = crc32(0, NULL, 0);\n                     crc = crc32(crc, profile, length);\n                  }\n\n                  /* So this check must pass for the 'return' below to happen.\n                   */\n                  if (crc == png_sRGB_checks[i].crc)\n#              endif\n               {\n                  if (png_sRGB_checks[i].is_broken != 0)\n                  {\n                     /* These profiles are known to have bad data that may cause\n                      * problems if they are used, therefore attempt to\n                      * discourage their use, skip the 'have_md5' warning below,\n                      * which is made irrelevant by this error.\n                      */\n                     png_chunk_report(png_ptr, \"known incorrect sRGB profile\",\n                         PNG_CHUNK_ERROR);\n                  }\n\n                  /* Warn that this being done; this isn't even an error since\n                   * the profile is perfectly valid, but it would be nice if\n                   * people used the up-to-date ones.\n                   */\n                  else if (png_sRGB_checks[i].have_md5 == 0)\n                  {\n                     png_chunk_report(png_ptr,\n                         \"out-of-date sRGB profile with no signature\",\n                         PNG_CHUNK_WARNING);\n                  }\n\n                  return 1+png_sRGB_checks[i].is_broken;\n               }\n            }\n\n# if PNG_sRGB_PROFILE_CHECKS > 0\n         /* The signature matched, but the profile had been changed in some\n          * way.  This probably indicates a data error or uninformed hacking.\n          * Fall through to \"no match\".\n          */\n         png_chunk_report(png_ptr,\n             \"Not recognizing known sRGB profile that has been edited\",\n             PNG_CHUNK_WARNING);\n         break;\n# endif\n         }\n      }\n   }\n\n   return 0; /* no match */\n}\n\nvoid /* PRIVATE */\npng_icc_set_sRGB(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, png_const_bytep profile, uLong adler)\n{\n   /* Is this profile one of the known ICC sRGB profiles?  If it is, just set\n    * the sRGB information.\n    */\n   if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0)\n      (void)png_colorspace_set_sRGB(png_ptr, colorspace,\n         (int)/*already checked*/png_get_uint_32(profile+64));\n}\n#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */\n#endif /* sRGB */\n\nint /* PRIVATE */\npng_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,\n    png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,\n    int color_type)\n{\n   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)\n      return 0;\n\n   if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&\n       png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,\n           color_type) != 0 &&\n       png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,\n           profile) != 0)\n   {\n#     if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0\n         /* If no sRGB support, don't try storing sRGB information */\n         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);\n#     endif\n      return 1;\n   }\n\n   /* Failure case */\n   return 0;\n}\n#endif /* iCCP */\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\nvoid /* PRIVATE */\npng_colorspace_set_rgb_coefficients(png_structrp png_ptr)\n{\n   /* Set the rgb_to_gray coefficients from the colorspace. */\n   if (png_ptr->rgb_to_gray_coefficients_set == 0 &&\n      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      /* png_set_background has not been called, get the coefficients from the Y\n       * values of the colorspace colorants.\n       */\n      png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;\n      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;\n      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;\n      png_fixed_point total = r+g+b;\n\n      if (total > 0 &&\n         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&\n         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&\n         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&\n         r+g+b <= 32769)\n      {\n         /* We allow 0 coefficients here.  r+g+b may be 32769 if two or\n          * all of the coefficients were rounded up.  Handle this by\n          * reducing the *largest* coefficient by 1; this matches the\n          * approach used for the default coefficients in pngrtran.c\n          */\n         int add = 0;\n\n         if (r+g+b > 32768)\n            add = -1;\n         else if (r+g+b < 32768)\n            add = 1;\n\n         if (add != 0)\n         {\n            if (g >= r && g >= b)\n               g += add;\n            else if (r >= g && r >= b)\n               r += add;\n            else\n               b += add;\n         }\n\n         /* Check for an internal error. */\n         if (r+g+b != 32768)\n            png_error(png_ptr,\n                \"internal error handling cHRM coefficients\");\n\n         else\n         {\n            png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;\n            png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;\n         }\n      }\n\n      /* This is a png_error at present even though it could be ignored -\n       * it should never happen, but it is important that if it does, the\n       * bug is fixed.\n       */\n      else\n         png_error(png_ptr, \"internal error handling cHRM->XYZ\");\n   }\n}\n#endif /* READ_RGB_TO_GRAY */\n\n#endif /* COLORSPACE */\n\n#ifdef __GNUC__\n/* This exists solely to work round a warning from GNU C. */\nstatic int /* PRIVATE */\npng_gt(size_t a, size_t b)\n{\n   return a > b;\n}\n#else\n#   define png_gt(a,b) ((a) > (b))\n#endif\n\nvoid /* PRIVATE */\npng_check_IHDR(png_const_structrp png_ptr,\n    png_uint_32 width, png_uint_32 height, int bit_depth,\n    int color_type, int interlace_type, int compression_type,\n    int filter_type)\n{\n   int error = 0;\n\n   /* Check for width and height valid values */\n   if (width == 0)\n   {\n      png_warning(png_ptr, \"Image width is zero in IHDR\");\n      error = 1;\n   }\n\n   if (width > PNG_UINT_31_MAX)\n   {\n      png_warning(png_ptr, \"Invalid image width in IHDR\");\n      error = 1;\n   }\n\n   if (png_gt(((width + 7) & (~7U)),\n       ((PNG_SIZE_MAX\n           - 48        /* big_row_buf hack */\n           - 1)        /* filter byte */\n           / 8)        /* 8-byte RGBA pixels */\n           - 1))       /* extra max_pixel_depth pad */\n   {\n      /* The size of the row must be within the limits of this architecture.\n       * Because the read code can perform arbitrary transformations the\n       * maximum size is checked here.  Because the code in png_read_start_row\n       * adds extra space \"for safety's sake\" in several places a conservative\n       * limit is used here.\n       *\n       * NOTE: it would be far better to check the size that is actually used,\n       * but the effect in the real world is minor and the changes are more\n       * extensive, therefore much more dangerous and much more difficult to\n       * write in a way that avoids compiler warnings.\n       */\n      png_warning(png_ptr, \"Image width is too large for this architecture\");\n      error = 1;\n   }\n\n#ifdef PNG_SET_USER_LIMITS_SUPPORTED\n   if (width > png_ptr->user_width_max)\n#else\n   if (width > PNG_USER_WIDTH_MAX)\n#endif\n   {\n      png_warning(png_ptr, \"Image width exceeds user limit in IHDR\");\n      error = 1;\n   }\n\n   if (height == 0)\n   {\n      png_warning(png_ptr, \"Image height is zero in IHDR\");\n      error = 1;\n   }\n\n   if (height > PNG_UINT_31_MAX)\n   {\n      png_warning(png_ptr, \"Invalid image height in IHDR\");\n      error = 1;\n   }\n\n#ifdef PNG_SET_USER_LIMITS_SUPPORTED\n   if (height > png_ptr->user_height_max)\n#else\n   if (height > PNG_USER_HEIGHT_MAX)\n#endif\n   {\n      png_warning(png_ptr, \"Image height exceeds user limit in IHDR\");\n      error = 1;\n   }\n\n   /* Check other values */\n   if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&\n       bit_depth != 8 && bit_depth != 16)\n   {\n      png_warning(png_ptr, \"Invalid bit depth in IHDR\");\n      error = 1;\n   }\n\n   if (color_type < 0 || color_type == 1 ||\n       color_type == 5 || color_type > 6)\n   {\n      png_warning(png_ptr, \"Invalid color type in IHDR\");\n      error = 1;\n   }\n\n   if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||\n       ((color_type == PNG_COLOR_TYPE_RGB ||\n         color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||\n         color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))\n   {\n      png_warning(png_ptr, \"Invalid color type/bit depth combination in IHDR\");\n      error = 1;\n   }\n\n   if (interlace_type >= PNG_INTERLACE_LAST)\n   {\n      png_warning(png_ptr, \"Unknown interlace method in IHDR\");\n      error = 1;\n   }\n\n   if (compression_type != PNG_COMPRESSION_TYPE_BASE)\n   {\n      png_warning(png_ptr, \"Unknown compression method in IHDR\");\n      error = 1;\n   }\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   /* Accept filter_method 64 (intrapixel differencing) only if\n    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and\n    * 2. Libpng did not read a PNG signature (this filter_method is only\n    *    used in PNG datastreams that are embedded in MNG datastreams) and\n    * 3. The application called png_permit_mng_features with a mask that\n    *    included PNG_FLAG_MNG_FILTER_64 and\n    * 4. The filter_method is 64 and\n    * 5. The color_type is RGB or RGBA\n    */\n   if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 &&\n       png_ptr->mng_features_permitted != 0)\n      png_warning(png_ptr, \"MNG features are not allowed in a PNG datastream\");\n\n   if (filter_type != PNG_FILTER_TYPE_BASE)\n   {\n      if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&\n          (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&\n          ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&\n          (color_type == PNG_COLOR_TYPE_RGB ||\n          color_type == PNG_COLOR_TYPE_RGB_ALPHA)))\n      {\n         png_warning(png_ptr, \"Unknown filter method in IHDR\");\n         error = 1;\n      }\n\n      if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0)\n      {\n         png_warning(png_ptr, \"Invalid filter method in IHDR\");\n         error = 1;\n      }\n   }\n\n#else\n   if (filter_type != PNG_FILTER_TYPE_BASE)\n   {\n      png_warning(png_ptr, \"Unknown filter method in IHDR\");\n      error = 1;\n   }\n#endif\n\n   if (error == 1)\n      png_error(png_ptr, \"Invalid IHDR data\");\n}\n\n#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)\n/* ASCII to fp functions */\n/* Check an ASCII formatted floating point value, see the more detailed\n * comments in pngpriv.h\n */\n/* The following is used internally to preserve the sticky flags */\n#define png_fp_add(state, flags) ((state) |= (flags))\n#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))\n\nint /* PRIVATE */\npng_check_fp_number(png_const_charp string, size_t size, int *statep,\n    png_size_tp whereami)\n{\n   int state = *statep;\n   size_t i = *whereami;\n\n   while (i < size)\n   {\n      int type;\n      /* First find the type of the next character */\n      switch (string[i])\n      {\n      case 43:  type = PNG_FP_SAW_SIGN;                   break;\n      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;\n      case 46:  type = PNG_FP_SAW_DOT;                    break;\n      case 48:  type = PNG_FP_SAW_DIGIT;                  break;\n      case 49: case 50: case 51: case 52:\n      case 53: case 54: case 55: case 56:\n      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;\n      case 69:\n      case 101: type = PNG_FP_SAW_E;                      break;\n      default:  goto PNG_FP_End;\n      }\n\n      /* Now deal with this type according to the current\n       * state, the type is arranged to not overlap the\n       * bits of the PNG_FP_STATE.\n       */\n      switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY))\n      {\n      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:\n         if ((state & PNG_FP_SAW_ANY) != 0)\n            goto PNG_FP_End; /* not a part of the number */\n\n         png_fp_add(state, type);\n         break;\n\n      case PNG_FP_INTEGER + PNG_FP_SAW_DOT:\n         /* Ok as trailer, ok as lead of fraction. */\n         if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */\n            goto PNG_FP_End;\n\n         else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */\n            png_fp_add(state, type);\n\n         else\n            png_fp_set(state, PNG_FP_FRACTION | type);\n\n         break;\n\n      case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT:\n         if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */\n            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);\n\n         png_fp_add(state, type | PNG_FP_WAS_VALID);\n\n         break;\n\n      case PNG_FP_INTEGER + PNG_FP_SAW_E:\n         if ((state & PNG_FP_SAW_DIGIT) == 0)\n            goto PNG_FP_End;\n\n         png_fp_set(state, PNG_FP_EXPONENT);\n\n         break;\n\n   /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN:\n         goto PNG_FP_End; ** no sign in fraction */\n\n   /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT:\n         goto PNG_FP_End; ** Because SAW_DOT is always set */\n\n      case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT:\n         png_fp_add(state, type | PNG_FP_WAS_VALID);\n         break;\n\n      case PNG_FP_FRACTION + PNG_FP_SAW_E:\n         /* This is correct because the trailing '.' on an\n          * integer is handled above - so we can only get here\n          * with the sequence \".E\" (with no preceding digits).\n          */\n         if ((state & PNG_FP_SAW_DIGIT) == 0)\n            goto PNG_FP_End;\n\n         png_fp_set(state, PNG_FP_EXPONENT);\n\n         break;\n\n      case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN:\n         if ((state & PNG_FP_SAW_ANY) != 0)\n            goto PNG_FP_End; /* not a part of the number */\n\n         png_fp_add(state, PNG_FP_SAW_SIGN);\n\n         break;\n\n   /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT:\n         goto PNG_FP_End; */\n\n      case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT:\n         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);\n\n         break;\n\n   /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E:\n         goto PNG_FP_End; */\n\n      default: goto PNG_FP_End; /* I.e. break 2 */\n      }\n\n      /* The character seems ok, continue. */\n      ++i;\n   }\n\nPNG_FP_End:\n   /* Here at the end, update the state and return the correct\n    * return code.\n    */\n   *statep = state;\n   *whereami = i;\n\n   return (state & PNG_FP_SAW_DIGIT) != 0;\n}\n\n\n/* The same but for a complete string. */\nint\npng_check_fp_string(png_const_charp string, size_t size)\n{\n   int        state=0;\n   size_t char_index=0;\n\n   if (png_check_fp_number(string, size, &state, &char_index) != 0 &&\n      (char_index == size || string[char_index] == 0))\n      return state /* must be non-zero - see above */;\n\n   return 0; /* i.e. fail */\n}\n#endif /* pCAL || sCAL */\n\n#ifdef PNG_sCAL_SUPPORTED\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\n/* Utility used below - a simple accurate power of ten from an integral\n * exponent.\n */\nstatic double\npng_pow10(int power)\n{\n   int recip = 0;\n   double d = 1;\n\n   /* Handle negative exponent with a reciprocal at the end because\n    * 10 is exact whereas .1 is inexact in base 2\n    */\n   if (power < 0)\n   {\n      if (power < DBL_MIN_10_EXP) return 0;\n      recip = 1; power = -power;\n   }\n\n   if (power > 0)\n   {\n      /* Decompose power bitwise. */\n      double mult = 10;\n      do\n      {\n         if (power & 1) d *= mult;\n         mult *= mult;\n         power >>= 1;\n      }\n      while (power > 0);\n\n      if (recip != 0) d = 1/d;\n   }\n   /* else power is 0 and d is 1 */\n\n   return d;\n}\n\n/* Function to format a floating point value in ASCII with a given\n * precision.\n */\n#if GCC_STRICT_OVERFLOW\n#pragma GCC diagnostic push\n/* The problem arises below with exp_b10, which can never overflow because it\n * comes, originally, from frexp and is therefore limited to a range which is\n * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)).\n */\n#pragma GCC diagnostic warning \"-Wstrict-overflow=2\"\n#endif /* GCC_STRICT_OVERFLOW */\nvoid /* PRIVATE */\npng_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,\n    double fp, unsigned int precision)\n{\n   /* We use standard functions from math.h, but not printf because\n    * that would require stdio.  The caller must supply a buffer of\n    * sufficient size or we will png_error.  The tests on size and\n    * the space in ascii[] consumed are indicated below.\n    */\n   if (precision < 1)\n      precision = DBL_DIG;\n\n   /* Enforce the limit of the implementation precision too. */\n   if (precision > DBL_DIG+1)\n      precision = DBL_DIG+1;\n\n   /* Basic sanity checks */\n   if (size >= precision+5) /* See the requirements below. */\n   {\n      if (fp < 0)\n      {\n         fp = -fp;\n         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */\n         --size;\n      }\n\n      if (fp >= DBL_MIN && fp <= DBL_MAX)\n      {\n         int exp_b10;   /* A base 10 exponent */\n         double base;   /* 10^exp_b10 */\n\n         /* First extract a base 10 exponent of the number,\n          * the calculation below rounds down when converting\n          * from base 2 to base 10 (multiply by log10(2) -\n          * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to\n          * be increased.  Note that the arithmetic shift\n          * performs a floor() unlike C arithmetic - using a\n          * C multiply would break the following for negative\n          * exponents.\n          */\n         (void)frexp(fp, &exp_b10); /* exponent to base 2 */\n\n         exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */\n\n         /* Avoid underflow here. */\n         base = png_pow10(exp_b10); /* May underflow */\n\n         while (base < DBL_MIN || base < fp)\n         {\n            /* And this may overflow. */\n            double test = png_pow10(exp_b10+1);\n\n            if (test <= DBL_MAX)\n            {\n               ++exp_b10; base = test;\n            }\n\n            else\n               break;\n         }\n\n         /* Normalize fp and correct exp_b10, after this fp is in the\n          * range [.1,1) and exp_b10 is both the exponent and the digit\n          * *before* which the decimal point should be inserted\n          * (starting with 0 for the first digit).  Note that this\n          * works even if 10^exp_b10 is out of range because of the\n          * test on DBL_MAX above.\n          */\n         fp /= base;\n         while (fp >= 1)\n         {\n            fp /= 10; ++exp_b10;\n         }\n\n         /* Because of the code above fp may, at this point, be\n          * less than .1, this is ok because the code below can\n          * handle the leading zeros this generates, so no attempt\n          * is made to correct that here.\n          */\n\n         {\n            unsigned int czero, clead, cdigits;\n            char exponent[10];\n\n            /* Allow up to two leading zeros - this will not lengthen\n             * the number compared to using E-n.\n             */\n            if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */\n            {\n               czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */\n               exp_b10 = 0;      /* Dot added below before first output. */\n            }\n            else\n               czero = 0;    /* No zeros to add */\n\n            /* Generate the digit list, stripping trailing zeros and\n             * inserting a '.' before a digit if the exponent is 0.\n             */\n            clead = czero; /* Count of leading zeros */\n            cdigits = 0;   /* Count of digits in list. */\n\n            do\n            {\n               double d;\n\n               fp *= 10;\n               /* Use modf here, not floor and subtract, so that\n                * the separation is done in one step.  At the end\n                * of the loop don't break the number into parts so\n                * that the final digit is rounded.\n                */\n               if (cdigits+czero+1 < precision+clead)\n                  fp = modf(fp, &d);\n\n               else\n               {\n                  d = floor(fp + .5);\n\n                  if (d > 9)\n                  {\n                     /* Rounding up to 10, handle that here. */\n                     if (czero > 0)\n                     {\n                        --czero; d = 1;\n                        if (cdigits == 0) --clead;\n                     }\n                     else\n                     {\n                        while (cdigits > 0 && d > 9)\n                        {\n                           int ch = *--ascii;\n\n                           if (exp_b10 != (-1))\n                              ++exp_b10;\n\n                           else if (ch == 46)\n                           {\n                              ch = *--ascii; ++size;\n                              /* Advance exp_b10 to '1', so that the\n                               * decimal point happens after the\n                               * previous digit.\n                               */\n                              exp_b10 = 1;\n                           }\n\n                           --cdigits;\n                           d = ch - 47;  /* I.e. 1+(ch-48) */\n                        }\n\n                        /* Did we reach the beginning? If so adjust the\n                         * exponent but take into account the leading\n                         * decimal point.\n                         */\n                        if (d > 9)  /* cdigits == 0 */\n                        {\n                           if (exp_b10 == (-1))\n                           {\n                              /* Leading decimal point (plus zeros?), if\n                               * we lose the decimal point here it must\n                               * be reentered below.\n                               */\n                              int ch = *--ascii;\n\n                              if (ch == 46)\n                              {\n                                 ++size; exp_b10 = 1;\n                              }\n\n                              /* Else lost a leading zero, so 'exp_b10' is\n                               * still ok at (-1)\n                               */\n                           }\n                           else\n                              ++exp_b10;\n\n                           /* In all cases we output a '1' */\n                           d = 1;\n                        }\n                     }\n                  }\n                  fp = 0; /* Guarantees termination below. */\n               }\n\n               if (d == 0)\n               {\n                  ++czero;\n                  if (cdigits == 0) ++clead;\n               }\n               else\n               {\n                  /* Included embedded zeros in the digit count. */\n                  cdigits += czero - clead;\n                  clead = 0;\n\n                  while (czero > 0)\n                  {\n                     /* exp_b10 == (-1) means we just output the decimal\n                      * place - after the DP don't adjust 'exp_b10' any\n                      * more!\n                      */\n                     if (exp_b10 != (-1))\n                     {\n                        if (exp_b10 == 0)\n                        {\n                           *ascii++ = 46; --size;\n                        }\n                        /* PLUS 1: TOTAL 4 */\n                        --exp_b10;\n                     }\n                     *ascii++ = 48; --czero;\n                  }\n\n                  if (exp_b10 != (-1))\n                  {\n                     if (exp_b10 == 0)\n                     {\n                        *ascii++ = 46; --size; /* counted above */\n                     }\n\n                     --exp_b10;\n                  }\n                  *ascii++ = (char)(48 + (int)d); ++cdigits;\n               }\n            }\n            while (cdigits+czero < precision+clead && fp > DBL_MIN);\n\n            /* The total output count (max) is now 4+precision */\n\n            /* Check for an exponent, if we don't need one we are\n             * done and just need to terminate the string.  At this\n             * point, exp_b10==(-1) is effectively a flag: it got\n             * to '-1' because of the decrement, after outputting\n             * the decimal point above. (The exponent required is\n             * *not* -1.)\n             */\n            if (exp_b10 >= (-1) && exp_b10 <= 2)\n            {\n               /* The following only happens if we didn't output the\n                * leading zeros above for negative exponent, so this\n                * doesn't add to the digit requirement.  Note that the\n                * two zeros here can only be output if the two leading\n                * zeros were *not* output, so this doesn't increase\n                * the output count.\n                */\n               while (exp_b10-- > 0) *ascii++ = 48;\n\n               *ascii = 0;\n\n               /* Total buffer requirement (including the '\\0') is\n                * 5+precision - see check at the start.\n                */\n               return;\n            }\n\n            /* Here if an exponent is required, adjust size for\n             * the digits we output but did not count.  The total\n             * digit output here so far is at most 1+precision - no\n             * decimal point and no leading or trailing zeros have\n             * been output.\n             */\n            size -= cdigits;\n\n            *ascii++ = 69; --size;    /* 'E': PLUS 1 TOTAL 2+precision */\n\n            /* The following use of an unsigned temporary avoids ambiguities in\n             * the signed arithmetic on exp_b10 and permits GCC at least to do\n             * better optimization.\n             */\n            {\n               unsigned int uexp_b10;\n\n               if (exp_b10 < 0)\n               {\n                  *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */\n                  uexp_b10 = 0U-exp_b10;\n               }\n\n               else\n                  uexp_b10 = 0U+exp_b10;\n\n               cdigits = 0;\n\n               while (uexp_b10 > 0)\n               {\n                  exponent[cdigits++] = (char)(48 + uexp_b10 % 10);\n                  uexp_b10 /= 10;\n               }\n            }\n\n            /* Need another size check here for the exponent digits, so\n             * this need not be considered above.\n             */\n            if (size > cdigits)\n            {\n               while (cdigits > 0) *ascii++ = exponent[--cdigits];\n\n               *ascii = 0;\n\n               return;\n            }\n         }\n      }\n      else if (!(fp >= DBL_MIN))\n      {\n         *ascii++ = 48; /* '0' */\n         *ascii = 0;\n         return;\n      }\n      else\n      {\n         *ascii++ = 105; /* 'i' */\n         *ascii++ = 110; /* 'n' */\n         *ascii++ = 102; /* 'f' */\n         *ascii = 0;\n         return;\n      }\n   }\n\n   /* Here on buffer too small. */\n   png_error(png_ptr, \"ASCII conversion buffer too small\");\n}\n#if GCC_STRICT_OVERFLOW\n#pragma GCC diagnostic pop\n#endif /* GCC_STRICT_OVERFLOW */\n\n#  endif /* FLOATING_POINT */\n\n#  ifdef PNG_FIXED_POINT_SUPPORTED\n/* Function to format a fixed point value in ASCII.\n */\nvoid /* PRIVATE */\npng_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,\n    size_t size, png_fixed_point fp)\n{\n   /* Require space for 10 decimal digits, a decimal point, a minus sign and a\n    * trailing \\0, 13 characters:\n    */\n   if (size > 12)\n   {\n      png_uint_32 num;\n\n      /* Avoid overflow here on the minimum integer. */\n      if (fp < 0)\n      {\n         *ascii++ = 45; num = (png_uint_32)(-fp);\n      }\n      else\n         num = (png_uint_32)fp;\n\n      if (num <= 0x80000000) /* else overflowed */\n      {\n         unsigned int ndigits = 0, first = 16 /* flag value */;\n         char digits[10];\n\n         while (num)\n         {\n            /* Split the low digit off num: */\n            unsigned int tmp = num/10;\n            num -= tmp*10;\n            digits[ndigits++] = (char)(48 + num);\n            /* Record the first non-zero digit, note that this is a number\n             * starting at 1, it's not actually the array index.\n             */\n            if (first == 16 && num > 0)\n               first = ndigits;\n            num = tmp;\n         }\n\n         if (ndigits > 0)\n         {\n            while (ndigits > 5) *ascii++ = digits[--ndigits];\n            /* The remaining digits are fractional digits, ndigits is '5' or\n             * smaller at this point.  It is certainly not zero.  Check for a\n             * non-zero fractional digit:\n             */\n            if (first <= 5)\n            {\n               unsigned int i;\n               *ascii++ = 46; /* decimal point */\n               /* ndigits may be <5 for small numbers, output leading zeros\n                * then ndigits digits to first:\n                */\n               i = 5;\n               while (ndigits < i)\n               {\n                  *ascii++ = 48; --i;\n               }\n               while (ndigits >= first) *ascii++ = digits[--ndigits];\n               /* Don't output the trailing zeros! */\n            }\n         }\n         else\n            *ascii++ = 48;\n\n         /* And null terminate the string: */\n         *ascii = 0;\n         return;\n      }\n   }\n\n   /* Here on buffer too small. */\n   png_error(png_ptr, \"ASCII conversion buffer too small\");\n}\n#   endif /* FIXED_POINT */\n#endif /* SCAL */\n\n#if defined(PNG_FLOATING_POINT_SUPPORTED) && \\\n   !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \\\n   (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \\\n   defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \\\n   (defined(PNG_sCAL_SUPPORTED) && \\\n   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))\npng_fixed_point\npng_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)\n{\n   double r = floor(100000 * fp + .5);\n\n   if (r > 2147483647. || r < -2147483648.)\n      png_fixed_error(png_ptr, text);\n\n#  ifndef PNG_ERROR_TEXT_SUPPORTED\n   PNG_UNUSED(text)\n#  endif\n\n   return (png_fixed_point)r;\n}\n#endif\n\n#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\\\n    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)\n/* muldiv functions */\n/* This API takes signed arguments and rounds the result to the nearest\n * integer (or, for a fixed point number - the standard argument - to\n * the nearest .00001).  Overflow and divide by zero are signalled in\n * the result, a boolean - true on success, false on overflow.\n */\n#if GCC_STRICT_OVERFLOW /* from above */\n/* It is not obvious which comparison below gets optimized in such a way that\n * signed overflow would change the result; looking through the code does not\n * reveal any tests which have the form GCC complains about, so presumably the\n * optimizer is moving an add or subtract into the 'if' somewhere.\n */\n#pragma GCC diagnostic push\n#pragma GCC diagnostic warning \"-Wstrict-overflow=2\"\n#endif /* GCC_STRICT_OVERFLOW */\nint\npng_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,\n    png_int_32 divisor)\n{\n   /* Return a * times / divisor, rounded. */\n   if (divisor != 0)\n   {\n      if (a == 0 || times == 0)\n      {\n         *res = 0;\n         return 1;\n      }\n      else\n      {\n#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n         double r = a;\n         r *= times;\n         r /= divisor;\n         r = floor(r+.5);\n\n         /* A png_fixed_point is a 32-bit integer. */\n         if (r <= 2147483647. && r >= -2147483648.)\n         {\n            *res = (png_fixed_point)r;\n            return 1;\n         }\n#else\n         int negative = 0;\n         png_uint_32 A, T, D;\n         png_uint_32 s16, s32, s00;\n\n         if (a < 0)\n            negative = 1, A = -a;\n         else\n            A = a;\n\n         if (times < 0)\n            negative = !negative, T = -times;\n         else\n            T = times;\n\n         if (divisor < 0)\n            negative = !negative, D = -divisor;\n         else\n            D = divisor;\n\n         /* Following can't overflow because the arguments only\n          * have 31 bits each, however the result may be 32 bits.\n          */\n         s16 = (A >> 16) * (T & 0xffff) +\n                           (A & 0xffff) * (T >> 16);\n         /* Can't overflow because the a*times bit is only 30\n          * bits at most.\n          */\n         s32 = (A >> 16) * (T >> 16) + (s16 >> 16);\n         s00 = (A & 0xffff) * (T & 0xffff);\n\n         s16 = (s16 & 0xffff) << 16;\n         s00 += s16;\n\n         if (s00 < s16)\n            ++s32; /* carry */\n\n         if (s32 < D) /* else overflow */\n         {\n            /* s32.s00 is now the 64-bit product, do a standard\n             * division, we know that s32 < D, so the maximum\n             * required shift is 31.\n             */\n            int bitshift = 32;\n            png_fixed_point result = 0; /* NOTE: signed */\n\n            while (--bitshift >= 0)\n            {\n               png_uint_32 d32, d00;\n\n               if (bitshift > 0)\n                  d32 = D >> (32-bitshift), d00 = D << bitshift;\n\n               else\n                  d32 = 0, d00 = D;\n\n               if (s32 > d32)\n               {\n                  if (s00 < d00) --s32; /* carry */\n                  s32 -= d32, s00 -= d00, result += 1<<bitshift;\n               }\n\n               else\n                  if (s32 == d32 && s00 >= d00)\n                     s32 = 0, s00 -= d00, result += 1<<bitshift;\n            }\n\n            /* Handle the rounding. */\n            if (s00 >= (D >> 1))\n               ++result;\n\n            if (negative != 0)\n               result = -result;\n\n            /* Check for overflow. */\n            if ((negative != 0 && result <= 0) ||\n                (negative == 0 && result >= 0))\n            {\n               *res = result;\n               return 1;\n            }\n         }\n#endif\n      }\n   }\n\n   return 0;\n}\n#if GCC_STRICT_OVERFLOW\n#pragma GCC diagnostic pop\n#endif /* GCC_STRICT_OVERFLOW */\n#endif /* READ_GAMMA || INCH_CONVERSIONS */\n\n#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)\n/* The following is for when the caller doesn't much care about the\n * result.\n */\npng_fixed_point\npng_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times,\n    png_int_32 divisor)\n{\n   png_fixed_point result;\n\n   if (png_muldiv(&result, a, times, divisor) != 0)\n      return result;\n\n   png_warning(png_ptr, \"fixed point overflow ignored\");\n   return 0;\n}\n#endif\n\n#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */\n/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */\npng_fixed_point\npng_reciprocal(png_fixed_point a)\n{\n#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n   double r = floor(1E10/a+.5);\n\n   if (r <= 2147483647. && r >= -2147483648.)\n      return (png_fixed_point)r;\n#else\n   png_fixed_point res;\n\n   if (png_muldiv(&res, 100000, 100000, a) != 0)\n      return res;\n#endif\n\n   return 0; /* error/overflow */\n}\n\n/* This is the shared test on whether a gamma value is 'significant' - whether\n * it is worth doing gamma correction.\n */\nint /* PRIVATE */\npng_gamma_significant(png_fixed_point gamma_val)\n{\n   return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||\n       gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;\n}\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n#ifdef PNG_16BIT_SUPPORTED\n/* A local convenience routine. */\nstatic png_fixed_point\npng_product2(png_fixed_point a, png_fixed_point b)\n{\n   /* The required result is 1/a * 1/b; the following preserves accuracy. */\n#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n   double r = a * 1E-5;\n   r *= b;\n   r = floor(r+.5);\n\n   if (r <= 2147483647. && r >= -2147483648.)\n      return (png_fixed_point)r;\n#else\n   png_fixed_point res;\n\n   if (png_muldiv(&res, a, b, 100000) != 0)\n      return res;\n#endif\n\n   return 0; /* overflow */\n}\n#endif /* 16BIT */\n\n/* The inverse of the above. */\npng_fixed_point\npng_reciprocal2(png_fixed_point a, png_fixed_point b)\n{\n   /* The required result is 1/a * 1/b; the following preserves accuracy. */\n#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n   if (a != 0 && b != 0)\n   {\n      double r = 1E15/a;\n      r /= b;\n      r = floor(r+.5);\n\n      if (r <= 2147483647. && r >= -2147483648.)\n         return (png_fixed_point)r;\n   }\n#else\n   /* This may overflow because the range of png_fixed_point isn't symmetric,\n    * but this API is only used for the product of file and screen gamma so it\n    * doesn't matter that the smallest number it can produce is 1/21474, not\n    * 1/100000\n    */\n   png_fixed_point res = png_product2(a, b);\n\n   if (res != 0)\n      return png_reciprocal(res);\n#endif\n\n   return 0; /* overflow */\n}\n#endif /* READ_GAMMA */\n\n#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */\n#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED\n/* Fixed point gamma.\n *\n * The code to calculate the tables used below can be found in the shell script\n * contrib/tools/intgamma.sh\n *\n * To calculate gamma this code implements fast log() and exp() calls using only\n * fixed point arithmetic.  This code has sufficient precision for either 8-bit\n * or 16-bit sample values.\n *\n * The tables used here were calculated using simple 'bc' programs, but C double\n * precision floating point arithmetic would work fine.\n *\n * 8-bit log table\n *   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to\n *   255, so it's the base 2 logarithm of a normalized 8-bit floating point\n *   mantissa.  The numbers are 32-bit fractions.\n */\nstatic const png_uint_32\npng_8bit_l2[128] =\n{\n   4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,\n   3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,\n   3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,\n   3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,\n   3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,\n   2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,\n   2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,\n   2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,\n   2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,\n   2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,\n   1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,\n   1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,\n   1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,\n   1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,\n   1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,\n   971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,\n   803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,\n   639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,\n   479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,\n   324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,\n   172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,\n   24347096U, 0U\n\n#if 0\n   /* The following are the values for 16-bit tables - these work fine for the\n    * 8-bit conversions but produce very slightly larger errors in the 16-bit\n    * log (about 1.2 as opposed to 0.7 absolute error in the final value).  To\n    * use these all the shifts below must be adjusted appropriately.\n    */\n   65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,\n   57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,\n   50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,\n   43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,\n   37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,\n   31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,\n   25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,\n   20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,\n   15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,\n   10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,\n   6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,\n   1119, 744, 372\n#endif\n};\n\nstatic png_int_32\npng_log8bit(unsigned int x)\n{\n   unsigned int lg2 = 0;\n   /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,\n    * because the log is actually negate that means adding 1.  The final\n    * returned value thus has the range 0 (for 255 input) to 7.994 (for 1\n    * input), return -1 for the overflow (log 0) case, - so the result is\n    * always at most 19 bits.\n    */\n   if ((x &= 0xff) == 0)\n      return -1;\n\n   if ((x & 0xf0) == 0)\n      lg2  = 4, x <<= 4;\n\n   if ((x & 0xc0) == 0)\n      lg2 += 2, x <<= 2;\n\n   if ((x & 0x80) == 0)\n      lg2 += 1, x <<= 1;\n\n   /* result is at most 19 bits, so this cast is safe: */\n   return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));\n}\n\n/* The above gives exact (to 16 binary places) log2 values for 8-bit images,\n * for 16-bit images we use the most significant 8 bits of the 16-bit value to\n * get an approximation then multiply the approximation by a correction factor\n * determined by the remaining up to 8 bits.  This requires an additional step\n * in the 16-bit case.\n *\n * We want log2(value/65535), we have log2(v'/255), where:\n *\n *    value = v' * 256 + v''\n *          = v' * f\n *\n * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128\n * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less\n * than 258.  The final factor also needs to correct for the fact that our 8-bit\n * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.\n *\n * This gives a final formula using a calculated value 'x' which is value/v' and\n * scaling by 65536 to match the above table:\n *\n *   log2(x/257) * 65536\n *\n * Since these numbers are so close to '1' we can use simple linear\n * interpolation between the two end values 256/257 (result -368.61) and 258/257\n * (result 367.179).  The values used below are scaled by a further 64 to give\n * 16-bit precision in the interpolation:\n *\n * Start (256): -23591\n * Zero  (257):      0\n * End   (258):  23499\n */\n#ifdef PNG_16BIT_SUPPORTED\nstatic png_int_32\npng_log16bit(png_uint_32 x)\n{\n   unsigned int lg2 = 0;\n\n   /* As above, but now the input has 16 bits. */\n   if ((x &= 0xffff) == 0)\n      return -1;\n\n   if ((x & 0xff00) == 0)\n      lg2  = 8, x <<= 8;\n\n   if ((x & 0xf000) == 0)\n      lg2 += 4, x <<= 4;\n\n   if ((x & 0xc000) == 0)\n      lg2 += 2, x <<= 2;\n\n   if ((x & 0x8000) == 0)\n      lg2 += 1, x <<= 1;\n\n   /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional\n    * value.\n    */\n   lg2 <<= 28;\n   lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;\n\n   /* Now we need to interpolate the factor, this requires a division by the top\n    * 8 bits.  Do this with maximum precision.\n    */\n   x = ((x << 16) + (x >> 9)) / (x >> 8);\n\n   /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,\n    * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly\n    * 16 bits to interpolate to get the low bits of the result.  Round the\n    * answer.  Note that the end point values are scaled by 64 to retain overall\n    * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust\n    * the overall scaling by 6-12.  Round at every step.\n    */\n   x -= 1U << 24;\n\n   if (x <= 65536U) /* <= '257' */\n      lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);\n\n   else\n      lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);\n\n   /* Safe, because the result can't have more than 20 bits: */\n   return (png_int_32)((lg2 + 2048) >> 12);\n}\n#endif /* 16BIT */\n\n/* The 'exp()' case must invert the above, taking a 20-bit fixed point\n * logarithmic value and returning a 16 or 8-bit number as appropriate.  In\n * each case only the low 16 bits are relevant - the fraction - since the\n * integer bits (the top 4) simply determine a shift.\n *\n * The worst case is the 16-bit distinction between 65535 and 65534. This\n * requires perhaps spurious accuracy in the decoding of the logarithm to\n * distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance\n * of getting this accuracy in practice.\n *\n * To deal with this the following exp() function works out the exponent of the\n * fractional part of the logarithm by using an accurate 32-bit value from the\n * top four fractional bits then multiplying in the remaining bits.\n */\nstatic const png_uint_32\npng_32bit_exp[16] =\n{\n   /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */\n   4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,\n   3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,\n   2553802834U, 2445529972U, 2341847524U, 2242560872U\n};\n\n/* Adjustment table; provided to explain the numbers in the code below. */\n#if 0\nfor (i=11;i>=0;--i){ print i, \" \", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), \"\\n\"}\n   11 44937.64284865548751208448\n   10 45180.98734845585101160448\n    9 45303.31936980687359311872\n    8 45364.65110595323018870784\n    7 45395.35850361789624614912\n    6 45410.72259715102037508096\n    5 45418.40724413220722311168\n    4 45422.25021786898173001728\n    3 45424.17186732298419044352\n    2 45425.13273269940811464704\n    1 45425.61317555035558641664\n    0 45425.85339951654943850496\n#endif\n\nstatic png_uint_32\npng_exp(png_fixed_point x)\n{\n   if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */\n   {\n      /* Obtain a 4-bit approximation */\n      png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f];\n\n      /* Incorporate the low 12 bits - these decrease the returned value by\n       * multiplying by a number less than 1 if the bit is set.  The multiplier\n       * is determined by the above table and the shift. Notice that the values\n       * converge on 45426 and this is used to allow linear interpolation of the\n       * low bits.\n       */\n      if (x & 0x800)\n         e -= (((e >> 16) * 44938U) +  16U) >> 5;\n\n      if (x & 0x400)\n         e -= (((e >> 16) * 45181U) +  32U) >> 6;\n\n      if (x & 0x200)\n         e -= (((e >> 16) * 45303U) +  64U) >> 7;\n\n      if (x & 0x100)\n         e -= (((e >> 16) * 45365U) + 128U) >> 8;\n\n      if (x & 0x080)\n         e -= (((e >> 16) * 45395U) + 256U) >> 9;\n\n      if (x & 0x040)\n         e -= (((e >> 16) * 45410U) + 512U) >> 10;\n\n      /* And handle the low 6 bits in a single block. */\n      e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;\n\n      /* Handle the upper bits of x. */\n      e >>= x >> 16;\n      return e;\n   }\n\n   /* Check for overflow */\n   if (x <= 0)\n      return png_32bit_exp[0];\n\n   /* Else underflow */\n   return 0;\n}\n\nstatic png_byte\npng_exp8bit(png_fixed_point lg2)\n{\n   /* Get a 32-bit value: */\n   png_uint_32 x = png_exp(lg2);\n\n   /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the\n    * second, rounding, step can't overflow because of the first, subtraction,\n    * step.\n    */\n   x -= x >> 8;\n   return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff);\n}\n\n#ifdef PNG_16BIT_SUPPORTED\nstatic png_uint_16\npng_exp16bit(png_fixed_point lg2)\n{\n   /* Get a 32-bit value: */\n   png_uint_32 x = png_exp(lg2);\n\n   /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */\n   x -= x >> 16;\n   return (png_uint_16)((x + 32767U) >> 16);\n}\n#endif /* 16BIT */\n#endif /* FLOATING_ARITHMETIC */\n\npng_byte\npng_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)\n{\n   if (value > 0 && value < 255)\n   {\n#     ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n         /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly\n          * convert this to a floating point value.  This includes values that\n          * would overflow if 'value' were to be converted to 'int'.\n          *\n          * Apparently GCC, however, does an intermediate conversion to (int)\n          * on some (ARM) but not all (x86) platforms, possibly because of\n          * hardware FP limitations.  (E.g. if the hardware conversion always\n          * assumes the integer register contains a signed value.)  This results\n          * in ANSI-C undefined behavior for large values.\n          *\n          * Other implementations on the same machine might actually be ANSI-C90\n          * conformant and therefore compile spurious extra code for the large\n          * values.\n          *\n          * We can be reasonably sure that an unsigned to float conversion\n          * won't be faster than an int to float one.  Therefore this code\n          * assumes responsibility for the undefined behavior, which it knows\n          * can't happen because of the check above.\n          *\n          * Note the argument to this routine is an (unsigned int) because, on\n          * 16-bit platforms, it is assigned a value which might be out of\n          * range for an (int); that would result in undefined behavior in the\n          * caller if the *argument* ('value') were to be declared (int).\n          */\n         double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5);\n         return (png_byte)r;\n#     else\n         png_int_32 lg2 = png_log8bit(value);\n         png_fixed_point res;\n\n         if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)\n            return png_exp8bit(res);\n\n         /* Overflow. */\n         value = 0;\n#     endif\n   }\n\n   return (png_byte)(value & 0xff);\n}\n\n#ifdef PNG_16BIT_SUPPORTED\npng_uint_16\npng_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)\n{\n   if (value > 0 && value < 65535)\n   {\n# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n      /* The same (unsigned int)->(double) constraints apply here as above,\n       * however in this case the (unsigned int) to (int) conversion can\n       * overflow on an ANSI-C90 compliant system so the cast needs to ensure\n       * that this is not possible.\n       */\n      double r = floor(65535*pow((png_int_32)value/65535.,\n          gamma_val*.00001)+.5);\n      return (png_uint_16)r;\n# else\n      png_int_32 lg2 = png_log16bit(value);\n      png_fixed_point res;\n\n      if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)\n         return png_exp16bit(res);\n\n      /* Overflow. */\n      value = 0;\n# endif\n   }\n\n   return (png_uint_16)value;\n}\n#endif /* 16BIT */\n\n/* This does the right thing based on the bit_depth field of the\n * png_struct, interpreting values as 8-bit or 16-bit.  While the result\n * is nominally a 16-bit value if bit depth is 8 then the result is\n * 8-bit (as are the arguments.)\n */\npng_uint_16 /* PRIVATE */\npng_gamma_correct(png_structrp png_ptr, unsigned int value,\n    png_fixed_point gamma_val)\n{\n   if (png_ptr->bit_depth == 8)\n      return png_gamma_8bit_correct(value, gamma_val);\n\n#ifdef PNG_16BIT_SUPPORTED\n   else\n      return png_gamma_16bit_correct(value, gamma_val);\n#else\n      /* should not reach this */\n      return 0;\n#endif /* 16BIT */\n}\n\n#ifdef PNG_16BIT_SUPPORTED\n/* Internal function to build a single 16-bit table - the table consists of\n * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount\n * to shift the input values right (or 16-number_of_signifiant_bits).\n *\n * The caller is responsible for ensuring that the table gets cleaned up on\n * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument\n * should be somewhere that will be cleaned.\n */\nstatic void\npng_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,\n    unsigned int shift, png_fixed_point gamma_val)\n{\n   /* Various values derived from 'shift': */\n   unsigned int num = 1U << (8U - shift);\n#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n   /* CSE the division and work round wacky GCC warnings (see the comments\n    * in png_gamma_8bit_correct for where these come from.)\n    */\n   double fmax = 1.0 / (((png_int_32)1 << (16U - shift)) - 1);\n#endif\n   unsigned int max = (1U << (16U - shift)) - 1U;\n   unsigned int max_by_2 = 1U << (15U - shift);\n   unsigned int i;\n\n   png_uint_16pp table = *ptable =\n       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));\n\n   for (i = 0; i < num; i++)\n   {\n      png_uint_16p sub_table = table[i] =\n          (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16)));\n\n      /* The 'threshold' test is repeated here because it can arise for one of\n       * the 16-bit tables even if the others don't hit it.\n       */\n      if (png_gamma_significant(gamma_val) != 0)\n      {\n         /* The old code would overflow at the end and this would cause the\n          * 'pow' function to return a result >1, resulting in an\n          * arithmetic error.  This code follows the spec exactly; ig is\n          * the recovered input sample, it always has 8-16 bits.\n          *\n          * We want input * 65535/max, rounded, the arithmetic fits in 32\n          * bits (unsigned) so long as max <= 32767.\n          */\n         unsigned int j;\n         for (j = 0; j < 256; j++)\n         {\n            png_uint_32 ig = (j << (8-shift)) + i;\n#           ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED\n               /* Inline the 'max' scaling operation: */\n               /* See png_gamma_8bit_correct for why the cast to (int) is\n                * required here.\n                */\n               double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5);\n               sub_table[j] = (png_uint_16)d;\n#           else\n               if (shift != 0)\n                  ig = (ig * 65535U + max_by_2)/max;\n\n               sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);\n#           endif\n         }\n      }\n      else\n      {\n         /* We must still build a table, but do it the fast way. */\n         unsigned int j;\n\n         for (j = 0; j < 256; j++)\n         {\n            png_uint_32 ig = (j << (8-shift)) + i;\n\n            if (shift != 0)\n               ig = (ig * 65535U + max_by_2)/max;\n\n            sub_table[j] = (png_uint_16)ig;\n         }\n      }\n   }\n}\n\n/* NOTE: this function expects the *inverse* of the overall gamma transformation\n * required.\n */\nstatic void\npng_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable,\n    unsigned int shift, png_fixed_point gamma_val)\n{\n   unsigned int num = 1U << (8U - shift);\n   unsigned int max = (1U << (16U - shift))-1U;\n   unsigned int i;\n   png_uint_32 last;\n\n   png_uint_16pp table = *ptable =\n       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));\n\n   /* 'num' is the number of tables and also the number of low bits of low\n    * bits of the input 16-bit value used to select a table.  Each table is\n    * itself indexed by the high 8 bits of the value.\n    */\n   for (i = 0; i < num; i++)\n      table[i] = (png_uint_16p)png_malloc(png_ptr,\n          256 * (sizeof (png_uint_16)));\n\n   /* 'gamma_val' is set to the reciprocal of the value calculated above, so\n    * pow(out,g) is an *input* value.  'last' is the last input value set.\n    *\n    * In the loop 'i' is used to find output values.  Since the output is\n    * 8-bit there are only 256 possible values.  The tables are set up to\n    * select the closest possible output value for each input by finding\n    * the input value at the boundary between each pair of output values\n    * and filling the table up to that boundary with the lower output\n    * value.\n    *\n    * The boundary values are 0.5,1.5..253.5,254.5.  Since these are 9-bit\n    * values the code below uses a 16-bit value in i; the values start at\n    * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last\n    * entries are filled with 255).  Start i at 128 and fill all 'last'\n    * table entries <= 'max'\n    */\n   last = 0;\n   for (i = 0; i < 255; ++i) /* 8-bit output value */\n   {\n      /* Find the corresponding maximum input value */\n      png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */\n\n      /* Find the boundary value in 16 bits: */\n      png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);\n\n      /* Adjust (round) to (16-shift) bits: */\n      bound = (bound * max + 32768U)/65535U + 1U;\n\n      while (last < bound)\n      {\n         table[last & (0xffU >> shift)][last >> (8U - shift)] = out;\n         last++;\n      }\n   }\n\n   /* And fill in the final entries. */\n   while (last < (num << 8))\n   {\n      table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;\n      last++;\n   }\n}\n#endif /* 16BIT */\n\n/* Build a single 8-bit table: same as the 16-bit case but much simpler (and\n * typically much faster).  Note that libpng currently does no sBIT processing\n * (apparently contrary to the spec) so a 256-entry table is always generated.\n */\nstatic void\npng_build_8bit_table(png_structrp png_ptr, png_bytepp ptable,\n    png_fixed_point gamma_val)\n{\n   unsigned int i;\n   png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);\n\n   if (png_gamma_significant(gamma_val) != 0)\n      for (i=0; i<256; i++)\n         table[i] = png_gamma_8bit_correct(i, gamma_val);\n\n   else\n      for (i=0; i<256; ++i)\n         table[i] = (png_byte)(i & 0xff);\n}\n\n/* Used from png_read_destroy and below to release the memory used by the gamma\n * tables.\n */\nvoid /* PRIVATE */\npng_destroy_gamma_table(png_structrp png_ptr)\n{\n   png_free(png_ptr, png_ptr->gamma_table);\n   png_ptr->gamma_table = NULL;\n\n#ifdef PNG_16BIT_SUPPORTED\n   if (png_ptr->gamma_16_table != NULL)\n   {\n      int i;\n      int istop = (1 << (8 - png_ptr->gamma_shift));\n      for (i = 0; i < istop; i++)\n      {\n         png_free(png_ptr, png_ptr->gamma_16_table[i]);\n      }\n   png_free(png_ptr, png_ptr->gamma_16_table);\n   png_ptr->gamma_16_table = NULL;\n   }\n#endif /* 16BIT */\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)\n   png_free(png_ptr, png_ptr->gamma_from_1);\n   png_ptr->gamma_from_1 = NULL;\n   png_free(png_ptr, png_ptr->gamma_to_1);\n   png_ptr->gamma_to_1 = NULL;\n\n#ifdef PNG_16BIT_SUPPORTED\n   if (png_ptr->gamma_16_from_1 != NULL)\n   {\n      int i;\n      int istop = (1 << (8 - png_ptr->gamma_shift));\n      for (i = 0; i < istop; i++)\n      {\n         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);\n      }\n   png_free(png_ptr, png_ptr->gamma_16_from_1);\n   png_ptr->gamma_16_from_1 = NULL;\n   }\n   if (png_ptr->gamma_16_to_1 != NULL)\n   {\n      int i;\n      int istop = (1 << (8 - png_ptr->gamma_shift));\n      for (i = 0; i < istop; i++)\n      {\n         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);\n      }\n   png_free(png_ptr, png_ptr->gamma_16_to_1);\n   png_ptr->gamma_16_to_1 = NULL;\n   }\n#endif /* 16BIT */\n#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */\n}\n\n/* We build the 8- or 16-bit gamma tables here.  Note that for 16-bit\n * tables, we don't make a full table if we are reducing to 8-bit in\n * the future.  Note also how the gamma_16 tables are segmented so that\n * we don't need to allocate > 64K chunks for a full 16-bit table.\n */\nvoid /* PRIVATE */\npng_build_gamma_table(png_structrp png_ptr, int bit_depth)\n{\n   png_debug(1, \"in png_build_gamma_table\");\n\n   /* Remove any existing table; this copes with multiple calls to\n    * png_read_update_info. The warning is because building the gamma tables\n    * multiple times is a performance hit - it's harmless but the ability to\n    * call png_read_update_info() multiple times is new in 1.5.6 so it seems\n    * sensible to warn if the app introduces such a hit.\n    */\n   if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL)\n   {\n      png_warning(png_ptr, \"gamma table being rebuilt\");\n      png_destroy_gamma_table(png_ptr);\n   }\n\n   if (bit_depth <= 8)\n   {\n      png_build_8bit_table(png_ptr, &png_ptr->gamma_table,\n          png_ptr->screen_gamma > 0 ?\n          png_reciprocal2(png_ptr->colorspace.gamma,\n          png_ptr->screen_gamma) : PNG_FP_1);\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)\n      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)\n      {\n         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,\n             png_reciprocal(png_ptr->colorspace.gamma));\n\n         png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,\n             png_ptr->screen_gamma > 0 ?\n             png_reciprocal(png_ptr->screen_gamma) :\n             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);\n      }\n#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */\n   }\n#ifdef PNG_16BIT_SUPPORTED\n   else\n   {\n      png_byte shift, sig_bit;\n\n      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      {\n         sig_bit = png_ptr->sig_bit.red;\n\n         if (png_ptr->sig_bit.green > sig_bit)\n            sig_bit = png_ptr->sig_bit.green;\n\n         if (png_ptr->sig_bit.blue > sig_bit)\n            sig_bit = png_ptr->sig_bit.blue;\n      }\n      else\n         sig_bit = png_ptr->sig_bit.gray;\n\n      /* 16-bit gamma code uses this equation:\n       *\n       *   ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]\n       *\n       * Where 'iv' is the input color value and 'ov' is the output value -\n       * pow(iv, gamma).\n       *\n       * Thus the gamma table consists of up to 256 256-entry tables.  The table\n       * is selected by the (8-gamma_shift) most significant of the low 8 bits\n       * of the color value then indexed by the upper 8 bits:\n       *\n       *   table[low bits][high 8 bits]\n       *\n       * So the table 'n' corresponds to all those 'iv' of:\n       *\n       *   <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>\n       *\n       */\n      if (sig_bit > 0 && sig_bit < 16U)\n         /* shift == insignificant bits */\n         shift = (png_byte)((16U - sig_bit) & 0xff);\n\n      else\n         shift = 0; /* keep all 16 bits */\n\n      if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)\n      {\n         /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively\n          * the significant bits in the *input* when the output will\n          * eventually be 8 bits.  By default it is 11.\n          */\n         if (shift < (16U - PNG_MAX_GAMMA_8))\n            shift = (16U - PNG_MAX_GAMMA_8);\n      }\n\n      if (shift > 8U)\n         shift = 8U; /* Guarantees at least one table! */\n\n      png_ptr->gamma_shift = shift;\n\n      /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now\n       * PNG_COMPOSE).  This effectively smashed the background calculation for\n       * 16-bit output because the 8-bit table assumes the result will be\n       * reduced to 8 bits.\n       */\n      if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)\n          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,\n          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,\n          png_ptr->screen_gamma) : PNG_FP_1);\n\n      else\n          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,\n          png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,\n          png_ptr->screen_gamma) : PNG_FP_1);\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)\n      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)\n      {\n         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,\n             png_reciprocal(png_ptr->colorspace.gamma));\n\n         /* Notice that the '16 from 1' table should be full precision, however\n          * the lookup on this table still uses gamma_shift, so it can't be.\n          * TODO: fix this.\n          */\n         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,\n             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :\n             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);\n      }\n#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */\n   }\n#endif /* 16BIT */\n}\n#endif /* READ_GAMMA */\n\n/* HARDWARE OR SOFTWARE OPTION SUPPORT */\n#ifdef PNG_SET_OPTION_SUPPORTED\nint PNGAPI\npng_set_option(png_structrp png_ptr, int option, int onoff)\n{\n   if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&\n      (option & 1) == 0)\n   {\n      png_uint_32 mask = 3U << option;\n      png_uint_32 setting = (2U + (onoff != 0)) << option;\n      png_uint_32 current = png_ptr->options;\n\n      png_ptr->options = (png_uint_32)((current & ~mask) | setting);\n\n      return (int)(current & mask) >> option;\n   }\n\n   return PNG_OPTION_INVALID;\n}\n#endif\n\n/* sRGB support */\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\\\n   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\n/* sRGB conversion tables; these are machine generated with the code in\n * contrib/tools/makesRGB.c.  The actual sRGB transfer curve defined in the\n * specification (see the article at https://en.wikipedia.org/wiki/SRGB)\n * is used, not the gamma=1/2.2 approximation use elsewhere in libpng.\n * The sRGB to linear table is exact (to the nearest 16-bit linear fraction).\n * The inverse (linear to sRGB) table has accuracies as follows:\n *\n * For all possible (255*65535+1) input values:\n *\n *    error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact\n *\n * For the input values corresponding to the 65536 16-bit values:\n *\n *    error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact\n *\n * In all cases the inexact readings are only off by one.\n */\n\n#ifdef PNG_SIMPLIFIED_READ_SUPPORTED\n/* The convert-to-sRGB table is only currently required for read. */\nconst png_uint_16 png_sRGB_table[256] =\n{\n   0,20,40,60,80,99,119,139,\n   159,179,199,219,241,264,288,313,\n   340,367,396,427,458,491,526,562,\n   599,637,677,718,761,805,851,898,\n   947,997,1048,1101,1156,1212,1270,1330,\n   1391,1453,1517,1583,1651,1720,1790,1863,\n   1937,2013,2090,2170,2250,2333,2418,2504,\n   2592,2681,2773,2866,2961,3058,3157,3258,\n   3360,3464,3570,3678,3788,3900,4014,4129,\n   4247,4366,4488,4611,4736,4864,4993,5124,\n   5257,5392,5530,5669,5810,5953,6099,6246,\n   6395,6547,6700,6856,7014,7174,7335,7500,\n   7666,7834,8004,8177,8352,8528,8708,8889,\n   9072,9258,9445,9635,9828,10022,10219,10417,\n   10619,10822,11028,11235,11446,11658,11873,12090,\n   12309,12530,12754,12980,13209,13440,13673,13909,\n   14146,14387,14629,14874,15122,15371,15623,15878,\n   16135,16394,16656,16920,17187,17456,17727,18001,\n   18277,18556,18837,19121,19407,19696,19987,20281,\n   20577,20876,21177,21481,21787,22096,22407,22721,\n   23038,23357,23678,24002,24329,24658,24990,25325,\n   25662,26001,26344,26688,27036,27386,27739,28094,\n   28452,28813,29176,29542,29911,30282,30656,31033,\n   31412,31794,32179,32567,32957,33350,33745,34143,\n   34544,34948,35355,35764,36176,36591,37008,37429,\n   37852,38278,38706,39138,39572,40009,40449,40891,\n   41337,41785,42236,42690,43147,43606,44069,44534,\n   45002,45473,45947,46423,46903,47385,47871,48359,\n   48850,49344,49841,50341,50844,51349,51858,52369,\n   52884,53401,53921,54445,54971,55500,56032,56567,\n   57105,57646,58190,58737,59287,59840,60396,60955,\n   61517,62082,62650,63221,63795,64372,64952,65535\n};\n#endif /* SIMPLIFIED_READ */\n\n/* The base/delta tables are required for both read and write (but currently\n * only the simplified versions.)\n */\nconst png_uint_16 png_sRGB_base[512] =\n{\n   128,1782,3383,4644,5675,6564,7357,8074,\n   8732,9346,9921,10463,10977,11466,11935,12384,\n   12816,13233,13634,14024,14402,14769,15125,15473,\n   15812,16142,16466,16781,17090,17393,17690,17981,\n   18266,18546,18822,19093,19359,19621,19879,20133,\n   20383,20630,20873,21113,21349,21583,21813,22041,\n   22265,22487,22707,22923,23138,23350,23559,23767,\n   23972,24175,24376,24575,24772,24967,25160,25352,\n   25542,25730,25916,26101,26284,26465,26645,26823,\n   27000,27176,27350,27523,27695,27865,28034,28201,\n   28368,28533,28697,28860,29021,29182,29341,29500,\n   29657,29813,29969,30123,30276,30429,30580,30730,\n   30880,31028,31176,31323,31469,31614,31758,31902,\n   32045,32186,32327,32468,32607,32746,32884,33021,\n   33158,33294,33429,33564,33697,33831,33963,34095,\n   34226,34357,34486,34616,34744,34873,35000,35127,\n   35253,35379,35504,35629,35753,35876,35999,36122,\n   36244,36365,36486,36606,36726,36845,36964,37083,\n   37201,37318,37435,37551,37668,37783,37898,38013,\n   38127,38241,38354,38467,38580,38692,38803,38915,\n   39026,39136,39246,39356,39465,39574,39682,39790,\n   39898,40005,40112,40219,40325,40431,40537,40642,\n   40747,40851,40955,41059,41163,41266,41369,41471,\n   41573,41675,41777,41878,41979,42079,42179,42279,\n   42379,42478,42577,42676,42775,42873,42971,43068,\n   43165,43262,43359,43456,43552,43648,43743,43839,\n   43934,44028,44123,44217,44311,44405,44499,44592,\n   44685,44778,44870,44962,45054,45146,45238,45329,\n   45420,45511,45601,45692,45782,45872,45961,46051,\n   46140,46229,46318,46406,46494,46583,46670,46758,\n   46846,46933,47020,47107,47193,47280,47366,47452,\n   47538,47623,47709,47794,47879,47964,48048,48133,\n   48217,48301,48385,48468,48552,48635,48718,48801,\n   48884,48966,49048,49131,49213,49294,49376,49458,\n   49539,49620,49701,49782,49862,49943,50023,50103,\n   50183,50263,50342,50422,50501,50580,50659,50738,\n   50816,50895,50973,51051,51129,51207,51285,51362,\n   51439,51517,51594,51671,51747,51824,51900,51977,\n   52053,52129,52205,52280,52356,52432,52507,52582,\n   52657,52732,52807,52881,52956,53030,53104,53178,\n   53252,53326,53400,53473,53546,53620,53693,53766,\n   53839,53911,53984,54056,54129,54201,54273,54345,\n   54417,54489,54560,54632,54703,54774,54845,54916,\n   54987,55058,55129,55199,55269,55340,55410,55480,\n   55550,55620,55689,55759,55828,55898,55967,56036,\n   56105,56174,56243,56311,56380,56448,56517,56585,\n   56653,56721,56789,56857,56924,56992,57059,57127,\n   57194,57261,57328,57395,57462,57529,57595,57662,\n   57728,57795,57861,57927,57993,58059,58125,58191,\n   58256,58322,58387,58453,58518,58583,58648,58713,\n   58778,58843,58908,58972,59037,59101,59165,59230,\n   59294,59358,59422,59486,59549,59613,59677,59740,\n   59804,59867,59930,59993,60056,60119,60182,60245,\n   60308,60370,60433,60495,60558,60620,60682,60744,\n   60806,60868,60930,60992,61054,61115,61177,61238,\n   61300,61361,61422,61483,61544,61605,61666,61727,\n   61788,61848,61909,61969,62030,62090,62150,62211,\n   62271,62331,62391,62450,62510,62570,62630,62689,\n   62749,62808,62867,62927,62986,63045,63104,63163,\n   63222,63281,63340,63398,63457,63515,63574,63632,\n   63691,63749,63807,63865,63923,63981,64039,64097,\n   64155,64212,64270,64328,64385,64443,64500,64557,\n   64614,64672,64729,64786,64843,64900,64956,65013,\n   65070,65126,65183,65239,65296,65352,65409,65465\n};\n\nconst png_byte png_sRGB_delta[512] =\n{\n   207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,\n   52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,\n   35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,\n   28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,\n   23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,\n   21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,\n   19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,\n   17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,\n   16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,\n   15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,\n   14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,\n   13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,\n   12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,\n   12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,\n   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\n   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,\n   11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\n   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\n   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,\n   10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7\n};\n#endif /* SIMPLIFIED READ/WRITE sRGB support */\n\n/* SIMPLIFIED READ/WRITE SUPPORT */\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\\\n   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\nstatic int\npng_image_free_function(png_voidp argument)\n{\n   png_imagep image = png_voidcast(png_imagep, argument);\n   png_controlp cp = image->opaque;\n   png_control c;\n\n   /* Double check that we have a png_ptr - it should be impossible to get here\n    * without one.\n    */\n   if (cp->png_ptr == NULL)\n      return 0;\n\n   /* First free any data held in the control structure. */\n#  ifdef PNG_STDIO_SUPPORTED\n      if (cp->owned_file != 0)\n      {\n         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);\n         cp->owned_file = 0;\n\n         /* Ignore errors here. */\n         if (fp != NULL)\n         {\n            cp->png_ptr->io_ptr = NULL;\n            (void)fclose(fp);\n         }\n      }\n#  endif\n\n   /* Copy the control structure so that the original, allocated, version can be\n    * safely freed.  Notice that a png_error here stops the remainder of the\n    * cleanup, but this is probably fine because that would indicate bad memory\n    * problems anyway.\n    */\n   c = *cp;\n   image->opaque = &c;\n   png_free(c.png_ptr, cp);\n\n   /* Then the structures, calling the correct API. */\n   if (c.for_write != 0)\n   {\n#     ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED\n         png_destroy_write_struct(&c.png_ptr, &c.info_ptr);\n#     else\n         png_error(c.png_ptr, \"simplified write not supported\");\n#     endif\n   }\n   else\n   {\n#     ifdef PNG_SIMPLIFIED_READ_SUPPORTED\n         png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);\n#     else\n         png_error(c.png_ptr, \"simplified read not supported\");\n#     endif\n   }\n\n   /* Success. */\n   return 1;\n}\n\nvoid PNGAPI\npng_image_free(png_imagep image)\n{\n   /* Safely call the real function, but only if doing so is safe at this point\n    * (if not inside an error handling context).  Otherwise assume\n    * png_safe_execute will call this API after the return.\n    */\n   if (image != NULL && image->opaque != NULL &&\n      image->opaque->error_buf == NULL)\n   {\n      png_image_free_function(image);\n      image->opaque = NULL;\n   }\n}\n\nint /* PRIVATE */\npng_image_error(png_imagep image, png_const_charp error_message)\n{\n   /* Utility to log an error. */\n   png_safecat(image->message, (sizeof image->message), 0, error_message);\n   image->warning_or_error |= PNG_IMAGE_ERROR;\n   png_image_free(image);\n   return 0;\n}\n\n#endif /* SIMPLIFIED READ/WRITE */\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/png.h",
    "content": "\n/* png.h - header file for PNG reference library\n *\n * libpng version 1.6.37 - April 14, 2019\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license. (See LICENSE, below.)\n *\n * Authors and maintainers:\n *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat\n *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger\n *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:\n *     Glenn Randers-Pehrson\n *   libpng versions 1.6.36, December 2018, through 1.6.37, April 2019:\n *     Cosmin Truta\n *   See also \"Contributing Authors\", below.\n */\n\n/*\n * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE\n * =========================================\n *\n * PNG Reference Library License version 2\n * ---------------------------------------\n *\n *  * Copyright (c) 1995-2019 The PNG Reference Library Authors.\n *  * Copyright (c) 2018-2019 Cosmin Truta.\n *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.\n *  * Copyright (c) 1996-1997 Andreas Dilger.\n *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * The software is supplied \"as is\", without warranty of any kind,\n * express or implied, including, without limitation, the warranties\n * of merchantability, fitness for a particular purpose, title, and\n * non-infringement.  In no event shall the Copyright owners, or\n * anyone distributing the software, be liable for any damages or\n * other liability, whether in contract, tort or otherwise, arising\n * from, out of, or in connection with the software, or the use or\n * other dealings in the software, even if advised of the possibility\n * of such damage.\n *\n * Permission is hereby granted to use, copy, modify, and distribute\n * this software, or portions hereof, for any purpose, without fee,\n * subject to the following restrictions:\n *\n *  1. The origin of this software must not be misrepresented; you\n *     must not claim that you wrote the original software.  If you\n *     use this software in a product, an acknowledgment in the product\n *     documentation would be appreciated, but is not required.\n *\n *  2. Altered source versions must be plainly marked as such, and must\n *     not be misrepresented as being the original software.\n *\n *  3. This Copyright notice may not be removed or altered from any\n *     source or altered source distribution.\n *\n *\n * PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35)\n * -----------------------------------------------------------------------\n *\n * libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are\n * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are\n * derived from libpng-1.0.6, and are distributed according to the same\n * disclaimer and license as libpng-1.0.6 with the following individuals\n * added to the list of Contributing Authors:\n *\n *     Simon-Pierre Cadieux\n *     Eric S. Raymond\n *     Mans Rullgard\n *     Cosmin Truta\n *     Gilles Vollant\n *     James Yu\n *     Mandar Sahastrabuddhe\n *     Google Inc.\n *     Vadim Barkov\n *\n * and with the following additions to the disclaimer:\n *\n *     There is no warranty against interference with your enjoyment of\n *     the library or against infringement.  There is no warranty that our\n *     efforts or the library will fulfill any of your particular purposes\n *     or needs.  This library is provided with all faults, and the entire\n *     risk of satisfactory quality, performance, accuracy, and effort is\n *     with the user.\n *\n * Some files in the \"contrib\" directory and some configure-generated\n * files that are distributed with libpng have other copyright owners, and\n * are released under other open source licenses.\n *\n * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are\n * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from\n * libpng-0.96, and are distributed according to the same disclaimer and\n * license as libpng-0.96, with the following individuals added to the\n * list of Contributing Authors:\n *\n *     Tom Lane\n *     Glenn Randers-Pehrson\n *     Willem van Schaik\n *\n * libpng versions 0.89, June 1996, through 0.96, May 1997, are\n * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,\n * and are distributed according to the same disclaimer and license as\n * libpng-0.88, with the following individuals added to the list of\n * Contributing Authors:\n *\n *     John Bowler\n *     Kevin Bracey\n *     Sam Bushell\n *     Magnus Holmgren\n *     Greg Roelofs\n *     Tom Tanner\n *\n * Some files in the \"scripts\" directory have other copyright owners,\n * but are released under this license.\n *\n * libpng versions 0.5, May 1995, through 0.88, January 1996, are\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * For the purposes of this copyright and license, \"Contributing Authors\"\n * is defined as the following set of individuals:\n *\n *     Andreas Dilger\n *     Dave Martindale\n *     Guy Eric Schalnat\n *     Paul Schmidt\n *     Tim Wegner\n *\n * The PNG Reference Library is supplied \"AS IS\".  The Contributing\n * Authors and Group 42, Inc. disclaim all warranties, expressed or\n * implied, including, without limitation, the warranties of\n * merchantability and of fitness for any purpose.  The Contributing\n * Authors and Group 42, Inc. assume no liability for direct, indirect,\n * incidental, special, exemplary, or consequential damages, which may\n * result from the use of the PNG Reference Library, even if advised of\n * the possibility of such damage.\n *\n * Permission is hereby granted to use, copy, modify, and distribute this\n * source code, or portions hereof, for any purpose, without fee, subject\n * to the following restrictions:\n *\n *  1. The origin of this source code must not be misrepresented.\n *\n *  2. Altered versions must be plainly marked as such and must not\n *     be misrepresented as being the original source.\n *\n *  3. This Copyright notice may not be removed or altered from any\n *     source or altered source distribution.\n *\n * The Contributing Authors and Group 42, Inc. specifically permit,\n * without fee, and encourage the use of this source code as a component\n * to supporting the PNG file format in commercial products.  If you use\n * this source code in a product, acknowledgment is not required but would\n * be appreciated.\n *\n * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.\n *\n * TRADEMARK\n * =========\n *\n * The name \"libpng\" has not been registered by the Copyright owners\n * as a trademark in any jurisdiction.  However, because libpng has\n * been distributed and maintained world-wide, continually since 1995,\n * the Copyright owners claim \"common-law trademark protection\" in any\n * jurisdiction where common-law trademark is recognized.\n */\n\n/*\n * A \"png_get_copyright\" function is available, for convenient use in \"about\"\n * boxes and the like:\n *\n *    printf(\"%s\", png_get_copyright(NULL));\n *\n * Also, the PNG logo (in PNG format, of course) is supplied in the\n * files \"pngbar.png\" and \"pngbar.jpg (88x31) and \"pngnow.png\" (98x31).\n */\n\n/*\n * The contributing authors would like to thank all those who helped\n * with testing, bug fixes, and patience.  This wouldn't have been\n * possible without all of you.\n *\n * Thanks to Frank J. T. Wojcik for helping with the documentation.\n */\n\n/* Note about libpng version numbers:\n *\n *    Due to various miscommunications, unforeseen code incompatibilities\n *    and occasional factors outside the authors' control, version numbering\n *    on the library has not always been consistent and straightforward.\n *    The following table summarizes matters since version 0.89c, which was\n *    the first widely used release:\n *\n *    source                 png.h  png.h  shared-lib\n *    version                string   int  version\n *    -------                ------ -----  ----------\n *    0.89c \"1.0 beta 3\"     0.89      89  1.0.89\n *    0.90  \"1.0 beta 4\"     0.90      90  0.90  [should have been 2.0.90]\n *    0.95  \"1.0 beta 5\"     0.95      95  0.95  [should have been 2.0.95]\n *    0.96  \"1.0 beta 6\"     0.96      96  0.96  [should have been 2.0.96]\n *    0.97b \"1.00.97 beta 7\" 1.00.97   97  1.0.1 [should have been 2.0.97]\n *    0.97c                  0.97      97  2.0.97\n *    0.98                   0.98      98  2.0.98\n *    0.99                   0.99      98  2.0.99\n *    0.99a-m                0.99      99  2.0.99\n *    1.00                   1.00     100  2.1.0 [100 should be 10000]\n *    1.0.0      (from here on, the   100  2.1.0 [100 should be 10000]\n *    1.0.1       png.h string is   10001  2.1.0\n *    1.0.1a-e    identical to the  10002  from here on, the shared library\n *    1.0.2       source version)   10002  is 2.V where V is the source code\n *    1.0.2a-b                      10003  version, except as noted.\n *    1.0.3                         10003\n *    1.0.3a-d                      10004\n *    1.0.4                         10004\n *    1.0.4a-f                      10005\n *    1.0.5 (+ 2 patches)           10005\n *    1.0.5a-d                      10006\n *    1.0.5e-r                      10100 (not source compatible)\n *    1.0.5s-v                      10006 (not binary compatible)\n *    1.0.6 (+ 3 patches)           10006 (still binary incompatible)\n *    1.0.6d-f                      10007 (still binary incompatible)\n *    1.0.6g                        10007\n *    1.0.6h                        10007  10.6h (testing xy.z so-numbering)\n *    1.0.6i                        10007  10.6i\n *    1.0.6j                        10007  2.1.0.6j (incompatible with 1.0.0)\n *    1.0.7beta11-14        DLLNUM  10007  2.1.0.7beta11-14 (binary compatible)\n *    1.0.7beta15-18           1    10007  2.1.0.7beta15-18 (binary compatible)\n *    1.0.7rc1-2               1    10007  2.1.0.7rc1-2 (binary compatible)\n *    1.0.7                    1    10007  (still compatible)\n *    ...\n *    1.0.69                  10    10069  10.so.0.69[.0]\n *    ...\n *    1.2.59                  13    10259  12.so.0.59[.0]\n *    ...\n *    1.4.20                  14    10420  14.so.0.20[.0]\n *    ...\n *    1.5.30                  15    10530  15.so.15.30[.0]\n *    ...\n *    1.6.37                  16    10637  16.so.16.37[.0]\n *\n *    Henceforth the source version will match the shared-library major and\n *    minor numbers; the shared-library major version number will be used for\n *    changes in backward compatibility, as it is intended.\n *    The PNG_LIBPNG_VER macro, which is not used within libpng but is\n *    available for applications, is an unsigned integer of the form XYYZZ\n *    corresponding to the source version X.Y.Z (leading zeros in Y and Z).\n *    Beta versions were given the previous public release number plus a\n *    letter, until version 1.0.6j; from then on they were given the upcoming\n *    public release number plus \"betaNN\" or \"rcNN\".\n *\n *    Binary incompatibility exists only when applications make direct access\n *    to the info_ptr or png_ptr members through png.h, and the compiled\n *    application is loaded with a different version of the library.\n *\n *    DLLNUM will change each time there are forward or backward changes\n *    in binary compatibility (e.g., when a new feature is added).\n *\n * See libpng.txt or libpng.3 for more information.  The PNG specification\n * is available as a W3C Recommendation and as an ISO/IEC Standard; see\n * <https://www.w3.org/TR/2003/REC-PNG-20031110/>\n */\n\n#ifndef PNG_H\n#define PNG_H\n\n/* This is not the place to learn how to use libpng. The file libpng-manual.txt\n * describes how to use libpng, and the file example.c summarizes it\n * with some code on which to build.  This file is useful for looking\n * at the actual function definitions and structure components.  If that\n * file has been stripped from your copy of libpng, you can find it at\n * <http://www.libpng.org/pub/png/libpng-manual.txt>\n *\n * If you just need to read a PNG file and don't want to read the documentation\n * skip to the end of this file and read the section entitled 'simplified API'.\n */\n\n/* Version information for png.h - this should match the version in png.c */\n#define PNG_LIBPNG_VER_STRING \"1.6.37\"\n#define PNG_HEADER_VERSION_STRING \" libpng version 1.6.37 - April 14, 2019\\n\"\n\n#define PNG_LIBPNG_VER_SONUM   16\n#define PNG_LIBPNG_VER_DLLNUM  16\n\n/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */\n#define PNG_LIBPNG_VER_MAJOR   1\n#define PNG_LIBPNG_VER_MINOR   6\n#define PNG_LIBPNG_VER_RELEASE 37\n\n/* This should be zero for a public release, or non-zero for a\n * development version.  [Deprecated]\n */\n#define PNG_LIBPNG_VER_BUILD  0\n\n/* Release Status */\n#define PNG_LIBPNG_BUILD_ALPHA    1\n#define PNG_LIBPNG_BUILD_BETA     2\n#define PNG_LIBPNG_BUILD_RC       3\n#define PNG_LIBPNG_BUILD_STABLE   4\n#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7\n\n/* Release-Specific Flags */\n#define PNG_LIBPNG_BUILD_PATCH    8 /* Can be OR'ed with\n                                       PNG_LIBPNG_BUILD_STABLE only */\n#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with\n                                       PNG_LIBPNG_BUILD_SPECIAL */\n#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with\n                                       PNG_LIBPNG_BUILD_PRIVATE */\n\n#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE\n\n/* Careful here.  At one time, Guy wanted to use 082, but that\n * would be octal.  We must not include leading zeros.\n * Versions 0.7 through 1.0.0 were in the range 0 to 100 here\n * (only version 1.0.0 was mis-numbered 100 instead of 10000).\n * From version 1.0.1 it is:\n * XXYYZZ, where XX=major, YY=minor, ZZ=release\n */\n#define PNG_LIBPNG_VER 10637 /* 1.6.37 */\n\n/* Library configuration: these options cannot be changed after\n * the library has been built.\n */\n#ifndef PNGLCONF_H\n/* If pnglibconf.h is missing, you can\n * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h\n */\n#   include \"pnglibconf.h\"\n#endif\n\n#ifndef PNG_VERSION_INFO_ONLY\n/* Machine specific configuration. */\n#  include \"pngconf.h\"\n#endif\n\n/*\n * Added at libpng-1.2.8\n *\n * Ref MSDN: Private as priority over Special\n * VS_FF_PRIVATEBUILD File *was not* built using standard release\n * procedures. If this value is given, the StringFileInfo block must\n * contain a PrivateBuild string.\n *\n * VS_FF_SPECIALBUILD File *was* built by the original company using\n * standard release procedures but is a variation of the standard\n * file of the same version number. If this value is given, the\n * StringFileInfo block must contain a SpecialBuild string.\n */\n\n#ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */\n#  define PNG_LIBPNG_BUILD_TYPE \\\n       (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE)\n#else\n#  ifdef PNG_LIBPNG_SPECIALBUILD\n#    define PNG_LIBPNG_BUILD_TYPE \\\n         (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL)\n#  else\n#    define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE)\n#  endif\n#endif\n\n#ifndef PNG_VERSION_INFO_ONLY\n\n/* Inhibit C++ name-mangling for libpng functions but not for system calls. */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n/* Version information for C files, stored in png.c.  This had better match\n * the version above.\n */\n#define png_libpng_ver png_get_header_ver(NULL)\n\n/* This file is arranged in several sections:\n *\n * 1. [omitted]\n * 2. Any configuration options that can be specified by for the application\n *    code when it is built.  (Build time configuration is in pnglibconf.h)\n * 3. Type definitions (base types are defined in pngconf.h), structure\n *    definitions.\n * 4. Exported library functions.\n * 5. Simplified API.\n * 6. Implementation options.\n *\n * The library source code has additional files (principally pngpriv.h) that\n * allow configuration of the library.\n */\n\n/* Section 1: [omitted] */\n\n/* Section 2: run time configuration\n * See pnglibconf.h for build time configuration\n *\n * Run time configuration allows the application to choose between\n * implementations of certain arithmetic APIs.  The default is set\n * at build time and recorded in pnglibconf.h, but it is safe to\n * override these (and only these) settings.  Note that this won't\n * change what the library does, only application code, and the\n * settings can (and probably should) be made on a per-file basis\n * by setting the #defines before including png.h\n *\n * Use macros to read integers from PNG data or use the exported\n * functions?\n *   PNG_USE_READ_MACROS: use the macros (see below)  Note that\n *     the macros evaluate their argument multiple times.\n *   PNG_NO_USE_READ_MACROS: call the relevant library function.\n *\n * Use the alternative algorithm for compositing alpha samples that\n * does not use division?\n *   PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division'\n *      algorithm.\n *   PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm.\n *\n * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is\n * false?\n *   PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error\n *      APIs to png_warning.\n * Otherwise the calls are mapped to png_error.\n */\n\n/* Section 3: type definitions, including structures and compile time\n * constants.\n * See pngconf.h for base types that vary by machine/system\n */\n\n/* This triggers a compiler error in png.c, if png.c and png.h\n * do not agree upon the version number.\n */\ntypedef char* png_libpng_version_1_6_37;\n\n/* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.\n *\n * png_struct is the cache of information used while reading or writing a single\n * PNG file.  One of these is always required, although the simplified API\n * (below) hides the creation and destruction of it.\n */\ntypedef struct png_struct_def png_struct;\ntypedef const png_struct * png_const_structp;\ntypedef png_struct * png_structp;\ntypedef png_struct * * png_structpp;\n\n/* png_info contains information read from or to be written to a PNG file.  One\n * or more of these must exist while reading or creating a PNG file.  The\n * information is not used by libpng during read but is used to control what\n * gets written when a PNG file is created.  \"png_get_\" function calls read\n * information during read and \"png_set_\" functions calls write information\n * when creating a PNG.\n * been moved into a separate header file that is not accessible to\n * applications.  Read libpng-manual.txt or libpng.3 for more info.\n */\ntypedef struct png_info_def png_info;\ntypedef png_info * png_infop;\ntypedef const png_info * png_const_infop;\ntypedef png_info * * png_infopp;\n\n/* Types with names ending 'p' are pointer types.  The corresponding types with\n * names ending 'rp' are identical pointer types except that the pointer is\n * marked 'restrict', which means that it is the only pointer to the object\n * passed to the function.  Applications should not use the 'restrict' types;\n * it is always valid to pass 'p' to a pointer with a function argument of the\n * corresponding 'rp' type.  Different compilers have different rules with\n * regard to type matching in the presence of 'restrict'.  For backward\n * compatibility libpng callbacks never have 'restrict' in their parameters and,\n * consequentially, writing portable application code is extremely difficult if\n * an attempt is made to use 'restrict'.\n */\ntypedef png_struct * PNG_RESTRICT png_structrp;\ntypedef const png_struct * PNG_RESTRICT png_const_structrp;\ntypedef png_info * PNG_RESTRICT png_inforp;\ntypedef const png_info * PNG_RESTRICT png_const_inforp;\n\n/* Three color definitions.  The order of the red, green, and blue, (and the\n * exact size) is not important, although the size of the fields need to\n * be png_byte or png_uint_16 (as defined below).\n */\ntypedef struct png_color_struct\n{\n   png_byte red;\n   png_byte green;\n   png_byte blue;\n} png_color;\ntypedef png_color * png_colorp;\ntypedef const png_color * png_const_colorp;\ntypedef png_color * * png_colorpp;\n\ntypedef struct png_color_16_struct\n{\n   png_byte index;    /* used for palette files */\n   png_uint_16 red;   /* for use in red green blue files */\n   png_uint_16 green;\n   png_uint_16 blue;\n   png_uint_16 gray;  /* for use in grayscale files */\n} png_color_16;\ntypedef png_color_16 * png_color_16p;\ntypedef const png_color_16 * png_const_color_16p;\ntypedef png_color_16 * * png_color_16pp;\n\ntypedef struct png_color_8_struct\n{\n   png_byte red;   /* for use in red green blue files */\n   png_byte green;\n   png_byte blue;\n   png_byte gray;  /* for use in grayscale files */\n   png_byte alpha; /* for alpha channel files */\n} png_color_8;\ntypedef png_color_8 * png_color_8p;\ntypedef const png_color_8 * png_const_color_8p;\ntypedef png_color_8 * * png_color_8pp;\n\n/*\n * The following two structures are used for the in-core representation\n * of sPLT chunks.\n */\ntypedef struct png_sPLT_entry_struct\n{\n   png_uint_16 red;\n   png_uint_16 green;\n   png_uint_16 blue;\n   png_uint_16 alpha;\n   png_uint_16 frequency;\n} png_sPLT_entry;\ntypedef png_sPLT_entry * png_sPLT_entryp;\ntypedef const png_sPLT_entry * png_const_sPLT_entryp;\ntypedef png_sPLT_entry * * png_sPLT_entrypp;\n\n/*  When the depth of the sPLT palette is 8 bits, the color and alpha samples\n *  occupy the LSB of their respective members, and the MSB of each member\n *  is zero-filled.  The frequency member always occupies the full 16 bits.\n */\n\ntypedef struct png_sPLT_struct\n{\n   png_charp name;           /* palette name */\n   png_byte depth;           /* depth of palette samples */\n   png_sPLT_entryp entries;  /* palette entries */\n   png_int_32 nentries;      /* number of palette entries */\n} png_sPLT_t;\ntypedef png_sPLT_t * png_sPLT_tp;\ntypedef const png_sPLT_t * png_const_sPLT_tp;\ntypedef png_sPLT_t * * png_sPLT_tpp;\n\n#ifdef PNG_TEXT_SUPPORTED\n/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file,\n * and whether that contents is compressed or not.  The \"key\" field\n * points to a regular zero-terminated C string.  The \"text\" fields can be a\n * regular C string, an empty string, or a NULL pointer.\n * However, the structure returned by png_get_text() will always contain\n * the \"text\" field as a regular zero-terminated C string (possibly\n * empty), never a NULL pointer, so it can be safely used in printf() and\n * other string-handling functions.  Note that the \"itxt_length\", \"lang\", and\n * \"lang_key\" members of the structure only exist when the library is built\n * with iTXt chunk support.  Prior to libpng-1.4.0 the library was built by\n * default without iTXt support. Also note that when iTXt *is* supported,\n * the \"lang\" and \"lang_key\" fields contain NULL pointers when the\n * \"compression\" field contains * PNG_TEXT_COMPRESSION_NONE or\n * PNG_TEXT_COMPRESSION_zTXt. Note that the \"compression value\" is not the\n * same as what appears in the PNG tEXt/zTXt/iTXt chunk's \"compression flag\"\n * which is always 0 or 1, or its \"compression method\" which is always 0.\n */\ntypedef struct png_text_struct\n{\n   int  compression;       /* compression value:\n                             -1: tEXt, none\n                              0: zTXt, deflate\n                              1: iTXt, none\n                              2: iTXt, deflate  */\n   png_charp key;          /* keyword, 1-79 character description of \"text\" */\n   png_charp text;         /* comment, may be an empty string (ie \"\")\n                              or a NULL pointer */\n   size_t text_length;     /* length of the text string */\n   size_t itxt_length;     /* length of the itxt string */\n   png_charp lang;         /* language code, 0-79 characters\n                              or a NULL pointer */\n   png_charp lang_key;     /* keyword translated UTF-8 string, 0 or more\n                              chars or a NULL pointer */\n} png_text;\ntypedef png_text * png_textp;\ntypedef const png_text * png_const_textp;\ntypedef png_text * * png_textpp;\n#endif\n\n/* Supported compression types for text in PNG files (tEXt, and zTXt).\n * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */\n#define PNG_TEXT_COMPRESSION_NONE_WR -3\n#define PNG_TEXT_COMPRESSION_zTXt_WR -2\n#define PNG_TEXT_COMPRESSION_NONE    -1\n#define PNG_TEXT_COMPRESSION_zTXt     0\n#define PNG_ITXT_COMPRESSION_NONE     1\n#define PNG_ITXT_COMPRESSION_zTXt     2\n#define PNG_TEXT_COMPRESSION_LAST     3  /* Not a valid value */\n\n/* png_time is a way to hold the time in an machine independent way.\n * Two conversions are provided, both from time_t and struct tm.  There\n * is no portable way to convert to either of these structures, as far\n * as I know.  If you know of a portable way, send it to me.  As a side\n * note - PNG has always been Year 2000 compliant!\n */\ntypedef struct png_time_struct\n{\n   png_uint_16 year; /* full year, as in, 1995 */\n   png_byte month;   /* month of year, 1 - 12 */\n   png_byte day;     /* day of month, 1 - 31 */\n   png_byte hour;    /* hour of day, 0 - 23 */\n   png_byte minute;  /* minute of hour, 0 - 59 */\n   png_byte second;  /* second of minute, 0 - 60 (for leap seconds) */\n} png_time;\ntypedef png_time * png_timep;\ntypedef const png_time * png_const_timep;\ntypedef png_time * * png_timepp;\n\n#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\\\n   defined(PNG_USER_CHUNKS_SUPPORTED)\n/* png_unknown_chunk is a structure to hold queued chunks for which there is\n * no specific support.  The idea is that we can use this to queue\n * up private chunks for output even though the library doesn't actually\n * know about their semantics.\n *\n * The data in the structure is set by libpng on read and used on write.\n */\ntypedef struct png_unknown_chunk_t\n{\n   png_byte name[5]; /* Textual chunk name with '\\0' terminator */\n   png_byte *data;   /* Data, should not be modified on read! */\n   size_t size;\n\n   /* On write 'location' must be set using the flag values listed below.\n    * Notice that on read it is set by libpng however the values stored have\n    * more bits set than are listed below.  Always treat the value as a\n    * bitmask.  On write set only one bit - setting multiple bits may cause the\n    * chunk to be written in multiple places.\n    */\n   png_byte location; /* mode of operation at read time */\n}\npng_unknown_chunk;\n\ntypedef png_unknown_chunk * png_unknown_chunkp;\ntypedef const png_unknown_chunk * png_const_unknown_chunkp;\ntypedef png_unknown_chunk * * png_unknown_chunkpp;\n#endif\n\n/* Flag values for the unknown chunk location byte. */\n#define PNG_HAVE_IHDR  0x01\n#define PNG_HAVE_PLTE  0x02\n#define PNG_AFTER_IDAT 0x08\n\n/* Maximum positive integer used in PNG is (2^31)-1 */\n#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL)\n#define PNG_UINT_32_MAX ((png_uint_32)(-1))\n#define PNG_SIZE_MAX ((size_t)(-1))\n\n/* These are constants for fixed point values encoded in the\n * PNG specification manner (x100000)\n */\n#define PNG_FP_1    100000\n#define PNG_FP_HALF  50000\n#define PNG_FP_MAX  ((png_fixed_point)0x7fffffffL)\n#define PNG_FP_MIN  (-PNG_FP_MAX)\n\n/* These describe the color_type field in png_info. */\n/* color type masks */\n#define PNG_COLOR_MASK_PALETTE    1\n#define PNG_COLOR_MASK_COLOR      2\n#define PNG_COLOR_MASK_ALPHA      4\n\n/* color types.  Note that not all combinations are legal */\n#define PNG_COLOR_TYPE_GRAY 0\n#define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)\n#define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR)\n#define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)\n#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)\n/* aliases */\n#define PNG_COLOR_TYPE_RGBA  PNG_COLOR_TYPE_RGB_ALPHA\n#define PNG_COLOR_TYPE_GA  PNG_COLOR_TYPE_GRAY_ALPHA\n\n/* This is for compression type. PNG 1.0-1.2 only define the single type. */\n#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */\n#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE\n\n/* This is for filter type. PNG 1.0-1.2 only define the single type. */\n#define PNG_FILTER_TYPE_BASE      0 /* Single row per-byte filtering */\n#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */\n#define PNG_FILTER_TYPE_DEFAULT   PNG_FILTER_TYPE_BASE\n\n/* These are for the interlacing type.  These values should NOT be changed. */\n#define PNG_INTERLACE_NONE        0 /* Non-interlaced image */\n#define PNG_INTERLACE_ADAM7       1 /* Adam7 interlacing */\n#define PNG_INTERLACE_LAST        2 /* Not a valid value */\n\n/* These are for the oFFs chunk.  These values should NOT be changed. */\n#define PNG_OFFSET_PIXEL          0 /* Offset in pixels */\n#define PNG_OFFSET_MICROMETER     1 /* Offset in micrometers (1/10^6 meter) */\n#define PNG_OFFSET_LAST           2 /* Not a valid value */\n\n/* These are for the pCAL chunk.  These values should NOT be changed. */\n#define PNG_EQUATION_LINEAR       0 /* Linear transformation */\n#define PNG_EQUATION_BASE_E       1 /* Exponential base e transform */\n#define PNG_EQUATION_ARBITRARY    2 /* Arbitrary base exponential transform */\n#define PNG_EQUATION_HYPERBOLIC   3 /* Hyperbolic sine transformation */\n#define PNG_EQUATION_LAST         4 /* Not a valid value */\n\n/* These are for the sCAL chunk.  These values should NOT be changed. */\n#define PNG_SCALE_UNKNOWN         0 /* unknown unit (image scale) */\n#define PNG_SCALE_METER           1 /* meters per pixel */\n#define PNG_SCALE_RADIAN          2 /* radians per pixel */\n#define PNG_SCALE_LAST            3 /* Not a valid value */\n\n/* These are for the pHYs chunk.  These values should NOT be changed. */\n#define PNG_RESOLUTION_UNKNOWN    0 /* pixels/unknown unit (aspect ratio) */\n#define PNG_RESOLUTION_METER      1 /* pixels/meter */\n#define PNG_RESOLUTION_LAST       2 /* Not a valid value */\n\n/* These are for the sRGB chunk.  These values should NOT be changed. */\n#define PNG_sRGB_INTENT_PERCEPTUAL 0\n#define PNG_sRGB_INTENT_RELATIVE   1\n#define PNG_sRGB_INTENT_SATURATION 2\n#define PNG_sRGB_INTENT_ABSOLUTE   3\n#define PNG_sRGB_INTENT_LAST       4 /* Not a valid value */\n\n/* This is for text chunks */\n#define PNG_KEYWORD_MAX_LENGTH     79\n\n/* Maximum number of entries in PLTE/sPLT/tRNS arrays */\n#define PNG_MAX_PALETTE_LENGTH    256\n\n/* These determine if an ancillary chunk's data has been successfully read\n * from the PNG header, or if the application has filled in the corresponding\n * data in the info_struct to be written into the output file.  The values\n * of the PNG_INFO_<chunk> defines should NOT be changed.\n */\n#define PNG_INFO_gAMA 0x0001U\n#define PNG_INFO_sBIT 0x0002U\n#define PNG_INFO_cHRM 0x0004U\n#define PNG_INFO_PLTE 0x0008U\n#define PNG_INFO_tRNS 0x0010U\n#define PNG_INFO_bKGD 0x0020U\n#define PNG_INFO_hIST 0x0040U\n#define PNG_INFO_pHYs 0x0080U\n#define PNG_INFO_oFFs 0x0100U\n#define PNG_INFO_tIME 0x0200U\n#define PNG_INFO_pCAL 0x0400U\n#define PNG_INFO_sRGB 0x0800U  /* GR-P, 0.96a */\n#define PNG_INFO_iCCP 0x1000U  /* ESR, 1.0.6 */\n#define PNG_INFO_sPLT 0x2000U  /* ESR, 1.0.6 */\n#define PNG_INFO_sCAL 0x4000U  /* ESR, 1.0.6 */\n#define PNG_INFO_IDAT 0x8000U  /* ESR, 1.0.6 */\n#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */\n\n/* This is used for the transformation routines, as some of them\n * change these values for the row.  It also should enable using\n * the routines for other purposes.\n */\ntypedef struct png_row_info_struct\n{\n   png_uint_32 width;    /* width of row */\n   size_t rowbytes;      /* number of bytes in row */\n   png_byte color_type;  /* color type of row */\n   png_byte bit_depth;   /* bit depth of row */\n   png_byte channels;    /* number of channels (1, 2, 3, or 4) */\n   png_byte pixel_depth; /* bits per pixel (depth * channels) */\n} png_row_info;\n\ntypedef png_row_info * png_row_infop;\ntypedef png_row_info * * png_row_infopp;\n\n/* These are the function types for the I/O functions and for the functions\n * that allow the user to override the default I/O functions with his or her\n * own.  The png_error_ptr type should match that of user-supplied warning\n * and error functions, while the png_rw_ptr type should match that of the\n * user read/write data functions.  Note that the 'write' function must not\n * modify the buffer it is passed. The 'read' function, on the other hand, is\n * expected to return the read data in the buffer.\n */\ntypedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp));\ntypedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, size_t));\ntypedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp));\ntypedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32,\n    int));\ntypedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32,\n    int));\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\ntypedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));\ntypedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));\n\n/* The following callback receives png_uint_32 row_number, int pass for the\n * png_bytep data of the row.  When transforming an interlaced image the\n * row number is the row number within the sub-image of the interlace pass, so\n * the value will increase to the height of the sub-image (not the full image)\n * then reset to 0 for the next pass.\n *\n * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to\n * find the output pixel (x,y) given an interlaced sub-image pixel\n * (row,col,pass).  (See below for these macros.)\n */\ntypedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep,\n    png_uint_32, int));\n#endif\n\n#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \\\n    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)\ntypedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop,\n    png_bytep));\n#endif\n\n#ifdef PNG_USER_CHUNKS_SUPPORTED\ntypedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp,\n    png_unknown_chunkp));\n#endif\n#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED\n/* not used anywhere */\n/* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */\n#endif\n\n#ifdef PNG_SETJMP_SUPPORTED\n/* This must match the function definition in <setjmp.h>, and the application\n * must include this before png.h to obtain the definition of jmp_buf.  The\n * function is required to be PNG_NORETURN, but this is not checked.  If the\n * function does return the application will crash via an abort() or similar\n * system level call.\n *\n * If you get a warning here while building the library you may need to make\n * changes to ensure that pnglibconf.h records the calling convention used by\n * your compiler.  This may be very difficult - try using a different compiler\n * to build the library!\n */\nPNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);\n#endif\n\n/* Transform masks for the high-level interface */\n#define PNG_TRANSFORM_IDENTITY       0x0000    /* read and write */\n#define PNG_TRANSFORM_STRIP_16       0x0001    /* read only */\n#define PNG_TRANSFORM_STRIP_ALPHA    0x0002    /* read only */\n#define PNG_TRANSFORM_PACKING        0x0004    /* read and write */\n#define PNG_TRANSFORM_PACKSWAP       0x0008    /* read and write */\n#define PNG_TRANSFORM_EXPAND         0x0010    /* read only */\n#define PNG_TRANSFORM_INVERT_MONO    0x0020    /* read and write */\n#define PNG_TRANSFORM_SHIFT          0x0040    /* read and write */\n#define PNG_TRANSFORM_BGR            0x0080    /* read and write */\n#define PNG_TRANSFORM_SWAP_ALPHA     0x0100    /* read and write */\n#define PNG_TRANSFORM_SWAP_ENDIAN    0x0200    /* read and write */\n#define PNG_TRANSFORM_INVERT_ALPHA   0x0400    /* read and write */\n#define PNG_TRANSFORM_STRIP_FILLER   0x0800    /* write only */\n/* Added to libpng-1.2.34 */\n#define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER\n#define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */\n/* Added to libpng-1.4.0 */\n#define PNG_TRANSFORM_GRAY_TO_RGB   0x2000      /* read only */\n/* Added to libpng-1.5.4 */\n#define PNG_TRANSFORM_EXPAND_16     0x4000      /* read only */\n#if INT_MAX >= 0x8000 /* else this might break */\n#define PNG_TRANSFORM_SCALE_16      0x8000      /* read only */\n#endif\n\n/* Flags for MNG supported features */\n#define PNG_FLAG_MNG_EMPTY_PLTE     0x01\n#define PNG_FLAG_MNG_FILTER_64      0x04\n#define PNG_ALL_MNG_FEATURES        0x05\n\n/* NOTE: prior to 1.5 these functions had no 'API' style declaration,\n * this allowed the zlib default functions to be used on Windows\n * platforms.  In 1.5 the zlib default malloc (which just calls malloc and\n * ignores the first argument) should be completely compatible with the\n * following.\n */\ntypedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp,\n    png_alloc_size_t));\ntypedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp));\n\n/* Section 4: exported functions\n * Here are the function definitions most commonly used.  This is not\n * the place to find out how to use libpng.  See libpng-manual.txt for the\n * full explanation, see example.c for the summary.  This just provides\n * a simple one line description of the use of each function.\n *\n * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in\n * pngconf.h and in the *.dfn files in the scripts directory.\n *\n *   PNG_EXPORT(ordinal, type, name, (args));\n *\n *       ordinal:    ordinal that is used while building\n *                   *.def files. The ordinal value is only\n *                   relevant when preprocessing png.h with\n *                   the *.dfn files for building symbol table\n *                   entries, and are removed by pngconf.h.\n *       type:       return type of the function\n *       name:       function name\n *       args:       function arguments, with types\n *\n * When we wish to append attributes to a function prototype we use\n * the PNG_EXPORTA() macro instead.\n *\n *   PNG_EXPORTA(ordinal, type, name, (args), attributes);\n *\n *       ordinal, type, name, and args: same as in PNG_EXPORT().\n *       attributes: function attributes\n */\n\n/* Returns the version number of the library */\nPNG_EXPORT(1, png_uint_32, png_access_version_number, (void));\n\n/* Tell lib we have already handled the first <num_bytes> magic bytes.\n * Handling more than 8 bytes from the beginning of the file is an error.\n */\nPNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));\n\n/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a\n * PNG file.  Returns zero if the supplied bytes match the 8-byte PNG\n * signature, and non-zero otherwise.  Having num_to_check == 0 or\n * start > 7 will always fail (ie return non-zero).\n */\nPNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,\n    size_t num_to_check));\n\n/* Simple signature checking function.  This is the same as calling\n * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).\n */\n#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n))\n\n/* Allocate and initialize png_ptr struct for reading, and any other memory. */\nPNG_EXPORTA(4, png_structp, png_create_read_struct,\n    (png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn),\n    PNG_ALLOCATED);\n\n/* Allocate and initialize png_ptr struct for writing, and any other memory */\nPNG_EXPORTA(5, png_structp, png_create_write_struct,\n    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,\n    png_error_ptr warn_fn),\n    PNG_ALLOCATED);\n\nPNG_EXPORT(6, size_t, png_get_compression_buffer_size,\n    (png_const_structrp png_ptr));\n\nPNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr,\n    size_t size));\n\n/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp\n * match up.\n */\n#ifdef PNG_SETJMP_SUPPORTED\n/* This function returns the jmp_buf built in to *png_ptr.  It must be\n * supplied with an appropriate 'longjmp' function to use on that jmp_buf\n * unless the default error function is overridden in which case NULL is\n * acceptable.  The size of the jmp_buf is checked against the actual size\n * allocated by the library - the call will return NULL on a mismatch\n * indicating an ABI mismatch.\n */\nPNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr,\n    png_longjmp_ptr longjmp_fn, size_t jmp_buf_size));\n#  define png_jmpbuf(png_ptr) \\\n      (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf))))\n#else\n#  define png_jmpbuf(png_ptr) \\\n      (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP)\n#endif\n/* This function should be used by libpng applications in place of\n * longjmp(png_ptr->jmpbuf, val).  If longjmp_fn() has been set, it\n * will use it; otherwise it will call PNG_ABORT().  This function was\n * added in libpng-1.5.0.\n */\nPNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val),\n    PNG_NORETURN);\n\n#ifdef PNG_READ_SUPPORTED\n/* Reset the compression stream */\nPNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED);\n#endif\n\n/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */\n#ifdef PNG_USER_MEM_SUPPORTED\nPNG_EXPORTA(11, png_structp, png_create_read_struct_2,\n    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,\n    png_error_ptr warn_fn,\n    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),\n    PNG_ALLOCATED);\nPNG_EXPORTA(12, png_structp, png_create_write_struct_2,\n    (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,\n    png_error_ptr warn_fn,\n    png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),\n    PNG_ALLOCATED);\n#endif\n\n/* Write the PNG file signature. */\nPNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr));\n\n/* Write a PNG chunk - size, type, (optional) data, CRC. */\nPNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep\n    chunk_name, png_const_bytep data, size_t length));\n\n/* Write the start of a PNG chunk - length and chunk name. */\nPNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr,\n    png_const_bytep chunk_name, png_uint_32 length));\n\n/* Write the data of a PNG chunk started with png_write_chunk_start(). */\nPNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr,\n    png_const_bytep data, size_t length));\n\n/* Finish a chunk started with png_write_chunk_start() (includes CRC). */\nPNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr));\n\n/* Allocate and initialize the info structure */\nPNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr),\n    PNG_ALLOCATED);\n\n/* DEPRECATED: this function allowed init structures to be created using the\n * default allocation method (typically malloc).  Use is deprecated in 1.6.0 and\n * the API will be removed in the future.\n */\nPNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr,\n    size_t png_info_struct_size), PNG_DEPRECATED);\n\n/* Writes all the PNG information before the image. */\nPNG_EXPORT(20, void, png_write_info_before_PLTE,\n    (png_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(21, void, png_write_info,\n    (png_structrp png_ptr, png_const_inforp info_ptr));\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the information before the actual image data. */\nPNG_EXPORT(22, void, png_read_info,\n    (png_structrp png_ptr, png_inforp info_ptr));\n#endif\n\n#ifdef PNG_TIME_RFC1123_SUPPORTED\n   /* Convert to a US string format: there is no localization support in this\n    * routine.  The original implementation used a 29 character buffer in\n    * png_struct, this will be removed in future versions.\n    */\n#if PNG_LIBPNG_VER < 10700\n/* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */\nPNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr,\n    png_const_timep ptime),PNG_DEPRECATED);\n#endif\nPNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29],\n    png_const_timep ptime));\n#endif\n\n#ifdef PNG_CONVERT_tIME_SUPPORTED\n/* Convert from a struct tm to png_time */\nPNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime,\n    const struct tm * ttime));\n\n/* Convert from time_t to png_time.  Uses gmtime() */\nPNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime));\n#endif /* CONVERT_tIME */\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */\nPNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr));\nPNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr));\nPNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr));\nPNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion\n * of a tRNS chunk if present.\n */\nPNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)\n/* Use blue, green, red order for pixels. */\nPNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n/* Expand the grayscale to 24-bit RGB if necessary. */\nPNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n/* Reduce RGB to grayscale. */\n#define PNG_ERROR_ACTION_NONE  1\n#define PNG_ERROR_ACTION_WARN  2\n#define PNG_ERROR_ACTION_ERROR 3\n#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/\n\nPNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr,\n    int error_action, double red, double green))\nPNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr,\n    int error_action, png_fixed_point red, png_fixed_point green))\n\nPNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp\n    png_ptr));\n#endif\n\n#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED\nPNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,\n    png_colorp palette));\n#endif\n\n#ifdef PNG_READ_ALPHA_MODE_SUPPORTED\n/* How the alpha channel is interpreted - this affects how the color channels\n * of a PNG file are returned to the calling application when an alpha channel,\n * or a tRNS chunk in a palette file, is present.\n *\n * This has no effect on the way pixels are written into a PNG output\n * datastream. The color samples in a PNG datastream are never premultiplied\n * with the alpha samples.\n *\n * The default is to return data according to the PNG specification: the alpha\n * channel is a linear measure of the contribution of the pixel to the\n * corresponding composited pixel, and the color channels are unassociated\n * (not premultiplied).  The gamma encoded color channels must be scaled\n * according to the contribution and to do this it is necessary to undo\n * the encoding, scale the color values, perform the composition and re-encode\n * the values.  This is the 'PNG' mode.\n *\n * The alternative is to 'associate' the alpha with the color information by\n * storing color channel values that have been scaled by the alpha.\n * image.  These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes\n * (the latter being the two common names for associated alpha color channels).\n *\n * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha\n * value is equal to the maximum value.\n *\n * The final choice is to gamma encode the alpha channel as well.  This is\n * broken because, in practice, no implementation that uses this choice\n * correctly undoes the encoding before handling alpha composition.  Use this\n * choice only if other serious errors in the software or hardware you use\n * mandate it; the typical serious error is for dark halos to appear around\n * opaque areas of the composited PNG image because of arithmetic overflow.\n *\n * The API function png_set_alpha_mode specifies which of these choices to use\n * with an enumerated 'mode' value and the gamma of the required output:\n */\n#define PNG_ALPHA_PNG           0 /* according to the PNG standard */\n#define PNG_ALPHA_STANDARD      1 /* according to Porter/Duff */\n#define PNG_ALPHA_ASSOCIATED    1 /* as above; this is the normal practice */\n#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */\n#define PNG_ALPHA_OPTIMIZED     2 /* 'PNG' for opaque pixels, else 'STANDARD' */\n#define PNG_ALPHA_BROKEN        3 /* the alpha channel is gamma encoded */\n\nPNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode,\n    double output_gamma))\nPNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr,\n    int mode, png_fixed_point output_gamma))\n#endif\n\n#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n/* The output_gamma value is a screen gamma in libpng terminology: it expresses\n * how to decode the output values, not how they are encoded.\n */\n#define PNG_DEFAULT_sRGB -1       /* sRGB gamma and color space */\n#define PNG_GAMMA_MAC_18 -2       /* Old Mac '1.8' gamma and color space */\n#define PNG_GAMMA_sRGB   220000   /* Television standards--matches sRGB gamma */\n#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */\n#endif\n\n/* The following are examples of calls to png_set_alpha_mode to achieve the\n * required overall gamma correction and, where necessary, alpha\n * premultiplication.\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);\n *    This is the default libpng handling of the alpha channel - it is not\n *    pre-multiplied into the color components.  In addition the call states\n *    that the output is for a sRGB system and causes all PNG files without gAMA\n *    chunks to be assumed to be encoded using sRGB.\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);\n *    In this case the output is assumed to be something like an sRGB conformant\n *    display preceded by a power-law lookup table of power 1.45.  This is how\n *    early Mac systems behaved.\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);\n *    This is the classic Jim Blinn approach and will work in academic\n *    environments where everything is done by the book.  It has the shortcoming\n *    of assuming that input PNG data with no gamma information is linear - this\n *    is unlikely to be correct unless the PNG files where generated locally.\n *    Most of the time the output precision will be so low as to show\n *    significant banding in dark areas of the image.\n *\n * png_set_expand_16(pp);\n * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);\n *    This is a somewhat more realistic Jim Blinn inspired approach.  PNG files\n *    are assumed to have the sRGB encoding if not marked with a gamma value and\n *    the output is always 16 bits per component.  This permits accurate scaling\n *    and processing of the data.  If you know that your input PNG files were\n *    generated locally you might need to replace PNG_DEFAULT_sRGB with the\n *    correct value for your system.\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);\n *    If you just need to composite the PNG image onto an existing background\n *    and if you control the code that does this you can use the optimization\n *    setting.  In this case you just copy completely opaque pixels to the\n *    output.  For pixels that are not completely transparent (you just skip\n *    those) you do the composition math using png_composite or png_composite_16\n *    below then encode the resultant 8-bit or 16-bit values to match the output\n *    encoding.\n *\n * Other cases\n *    If neither the PNG nor the standard linear encoding work for you because\n *    of the software or hardware you use then you have a big problem.  The PNG\n *    case will probably result in halos around the image.  The linear encoding\n *    will probably result in a washed out, too bright, image (it's actually too\n *    contrasty.)  Try the ALPHA_OPTIMIZED mode above - this will probably\n *    substantially reduce the halos.  Alternatively try:\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);\n *    This option will also reduce the halos, but there will be slight dark\n *    halos round the opaque parts of the image where the background is light.\n *    In the OPTIMIZED mode the halos will be light halos where the background\n *    is dark.  Take your pick - the halos are unavoidable unless you can get\n *    your hardware/software fixed!  (The OPTIMIZED approach is slightly\n *    faster.)\n *\n * When the default gamma of PNG files doesn't match the output gamma.\n *    If you have PNG files with no gamma information png_set_alpha_mode allows\n *    you to provide a default gamma, but it also sets the output gamma to the\n *    matching value.  If you know your PNG files have a gamma that doesn't\n *    match the output you can take advantage of the fact that\n *    png_set_alpha_mode always sets the output gamma but only sets the PNG\n *    default if it is not already set:\n *\n * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);\n * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);\n *    The first call sets both the default and the output gamma values, the\n *    second call overrides the output gamma without changing the default.  This\n *    is easier than achieving the same effect with png_set_gamma.  You must use\n *    PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will\n *    fire if more than one call to png_set_alpha_mode and png_set_background is\n *    made in the same read operation, however multiple calls with PNG_ALPHA_PNG\n *    are ignored.\n */\n\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\nPNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \\\n    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)\nPNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \\\n    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)\nPNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)\n/* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */\nPNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler,\n    int flags));\n/* The values of the PNG_FILLER_ defines should NOT be changed */\n#  define PNG_FILLER_BEFORE 0\n#  define PNG_FILLER_AFTER 1\n/* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */\nPNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr,\n    png_uint_32 filler, int flags));\n#endif /* READ_FILLER || WRITE_FILLER */\n\n#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)\n/* Swap bytes in 16-bit depth files. */\nPNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)\n/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */\nPNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \\\n    defined(PNG_WRITE_PACKSWAP_SUPPORTED)\n/* Swap packing order of pixels in bytes. */\nPNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)\n/* Converts files to legal bit depths. */\nPNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p\n    true_bits));\n#endif\n\n#if defined(PNG_READ_INTERLACING_SUPPORTED) || \\\n    defined(PNG_WRITE_INTERLACING_SUPPORTED)\n/* Have the code handle the interlacing.  Returns the number of passes.\n * MUST be called before png_read_update_info or png_start_read_image,\n * otherwise it will not have the desired effect.  Note that it is still\n * necessary to call png_read_row or png_read_rows png_get_image_height\n * times for each pass.\n*/\nPNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr));\n#endif\n\n#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)\n/* Invert monochrome files */\nPNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n/* Handle alpha and tRNS by replacing with a background color.  Prior to\n * libpng-1.5.4 this API must not be called before the PNG file header has been\n * read.  Doing so will result in unexpected behavior and possible warnings or\n * errors if the PNG file contains a bKGD chunk.\n */\nPNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr,\n    png_const_color_16p background_color, int background_gamma_code,\n    int need_expand, double background_gamma))\nPNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr,\n    png_const_color_16p background_color, int background_gamma_code,\n    int need_expand, png_fixed_point background_gamma))\n#endif\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n#  define PNG_BACKGROUND_GAMMA_UNKNOWN 0\n#  define PNG_BACKGROUND_GAMMA_SCREEN  1\n#  define PNG_BACKGROUND_GAMMA_FILE    2\n#  define PNG_BACKGROUND_GAMMA_UNIQUE  3\n#endif\n\n#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n/* Scale a 16-bit depth file down to 8-bit, accurately. */\nPNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n#define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */\n/* Strip the second byte of information from a 16-bit depth file. */\nPNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n/* Turn on quantizing, and reduce the palette to the number of colors\n * available.\n */\nPNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr,\n    png_colorp palette, int num_palette, int maximum_colors,\n    png_const_uint_16p histogram, int full_quantize));\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n/* The threshold on gamma processing is configurable but hard-wired into the\n * library.  The following is the floating point variant.\n */\n#define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001)\n\n/* Handle gamma correction. Screen_gamma=(display_exponent).\n * NOTE: this API simply sets the screen and file gamma values. It will\n * therefore override the value for gamma in a PNG file if it is called after\n * the file header has been read - use with care  - call before reading the PNG\n * file for best results!\n *\n * These routines accept the same gamma values as png_set_alpha_mode (described\n * above).  The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either\n * API (floating point or fixed.)  Notice, however, that the 'file_gamma' value\n * is the inverse of a 'screen gamma' value.\n */\nPNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr,\n    double screen_gamma, double override_file_gamma))\nPNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr,\n    png_fixed_point screen_gamma, png_fixed_point override_file_gamma))\n#endif\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n/* Set how many lines between output flushes - 0 for no flushing */\nPNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows));\n/* Flush the current PNG output buffer */\nPNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr));\n#endif\n\n/* Optional update palette with requested transformations */\nPNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr));\n\n/* Optional call to update the users info structure */\nPNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr,\n    png_inforp info_ptr));\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read one or more rows of image data. */\nPNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row,\n    png_bytepp display_row, png_uint_32 num_rows));\n#endif\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read a row of data. */\nPNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row,\n    png_bytep display_row));\n#endif\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the whole image into memory at once. */\nPNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image));\n#endif\n\n/* Write a row of image data */\nPNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr,\n    png_const_bytep row));\n\n/* Write a few rows of image data: (*row) is not written; however, the type\n * is declared as writeable to maintain compatibility with previous versions\n * of libpng and to allow the 'display_row' array from read_rows to be passed\n * unchanged to write_rows.\n */\nPNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row,\n    png_uint_32 num_rows));\n\n/* Write the image data */\nPNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image));\n\n/* Write the end of the PNG file. */\nPNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr,\n    png_inforp info_ptr));\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the end of the PNG file. */\nPNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr));\n#endif\n\n/* Free any memory associated with the png_info_struct */\nPNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr,\n    png_infopp info_ptr_ptr));\n\n/* Free any memory associated with the png_struct and the png_info_structs */\nPNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr,\n    png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));\n\n/* Free any memory associated with the png_struct and the png_info_structs */\nPNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr,\n    png_infopp info_ptr_ptr));\n\n/* Set the libpng method of handling chunk CRC errors */\nPNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,\n    int ancil_action));\n\n/* Values for png_set_crc_action() say how to handle CRC errors in\n * ancillary and critical chunks, and whether to use the data contained\n * therein.  Note that it is impossible to \"discard\" data in a critical\n * chunk.  For versions prior to 0.90, the action was always error/quit,\n * whereas in version 0.90 and later, the action for CRC errors in ancillary\n * chunks is warn/discard.  These values should NOT be changed.\n *\n *      value                       action:critical     action:ancillary\n */\n#define PNG_CRC_DEFAULT       0  /* error/quit          warn/discard data */\n#define PNG_CRC_ERROR_QUIT    1  /* error/quit          error/quit        */\n#define PNG_CRC_WARN_DISCARD  2  /* (INVALID)           warn/discard data */\n#define PNG_CRC_WARN_USE      3  /* warn/use data       warn/use data     */\n#define PNG_CRC_QUIET_USE     4  /* quiet/use data      quiet/use data    */\n#define PNG_CRC_NO_CHANGE     5  /* use current value   use current value */\n\n#ifdef PNG_WRITE_SUPPORTED\n/* These functions give the user control over the scan-line filtering in\n * libpng and the compression methods used by zlib.  These functions are\n * mainly useful for testing, as the defaults should work with most users.\n * Those users who are tight on memory or want faster performance at the\n * expense of compression can modify them.  See the compression library\n * header file (zlib.h) for an explination of the compression functions.\n */\n\n/* Set the filtering method(s) used by libpng.  Currently, the only valid\n * value for \"method\" is 0.\n */\nPNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,\n    int filters));\n#endif /* WRITE */\n\n/* Flags for png_set_filter() to say which filters to use.  The flags\n * are chosen so that they don't conflict with real filter types\n * below, in case they are supplied instead of the #defined constants.\n * These values should NOT be changed.\n */\n#define PNG_NO_FILTERS     0x00\n#define PNG_FILTER_NONE    0x08\n#define PNG_FILTER_SUB     0x10\n#define PNG_FILTER_UP      0x20\n#define PNG_FILTER_AVG     0x40\n#define PNG_FILTER_PAETH   0x80\n#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP)\n#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH)\n\n/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.\n * These defines should NOT be changed.\n */\n#define PNG_FILTER_VALUE_NONE  0\n#define PNG_FILTER_VALUE_SUB   1\n#define PNG_FILTER_VALUE_UP    2\n#define PNG_FILTER_VALUE_AVG   3\n#define PNG_FILTER_VALUE_PAETH 4\n#define PNG_FILTER_VALUE_LAST  5\n\n#ifdef PNG_WRITE_SUPPORTED\n#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */\nPNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr,\n    int heuristic_method, int num_weights, png_const_doublep filter_weights,\n    png_const_doublep filter_costs))\nPNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,\n    (png_structrp png_ptr, int heuristic_method, int num_weights,\n    png_const_fixed_point_p filter_weights,\n    png_const_fixed_point_p filter_costs))\n#endif /* WRITE_WEIGHTED_FILTER */\n\n/* The following are no longer used and will be removed from libpng-1.7: */\n#define PNG_FILTER_HEURISTIC_DEFAULT    0  /* Currently \"UNWEIGHTED\" */\n#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1  /* Used by libpng < 0.95 */\n#define PNG_FILTER_HEURISTIC_WEIGHTED   2  /* Experimental feature */\n#define PNG_FILTER_HEURISTIC_LAST       3  /* Not a valid value */\n\n/* Set the library compression level.  Currently, valid values range from\n * 0 - 9, corresponding directly to the zlib compression levels 0 - 9\n * (0 - no compression, 9 - \"maximal\" compression).  Note that tests have\n * shown that zlib compression levels 3-6 usually perform as well as level 9\n * for PNG images, and do considerably fewer caclulations.  In the future,\n * these values may not correspond directly to the zlib compression levels.\n */\n#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED\nPNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr,\n    int level));\n\nPNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr,\n    int mem_level));\n\nPNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr,\n    int strategy));\n\n/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a\n * smaller value of window_bits if it can do so safely.\n */\nPNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr,\n    int window_bits));\n\nPNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr,\n    int method));\n#endif /* WRITE_CUSTOMIZE_COMPRESSION */\n\n#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\n/* Also set zlib parameters for compressing non-IDAT chunks */\nPNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr,\n    int level));\n\nPNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr,\n    int mem_level));\n\nPNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr,\n    int strategy));\n\n/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a\n * smaller value of window_bits if it can do so safely.\n */\nPNG_EXPORT(225, void, png_set_text_compression_window_bits,\n    (png_structrp png_ptr, int window_bits));\n\nPNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr,\n    int method));\n#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */\n#endif /* WRITE */\n\n/* These next functions are called for input/output, memory, and error\n * handling.  They are in the file pngrio.c, pngwio.c, and pngerror.c,\n * and call standard C I/O routines such as fread(), fwrite(), and\n * fprintf().  These functions can be made to use other I/O routines\n * at run time for those applications that need to handle I/O in a\n * different manner by calling png_set_???_fn().  See libpng-manual.txt for\n * more information.\n */\n\n#ifdef PNG_STDIO_SUPPORTED\n/* Initialize the input/output for the PNG file to the default functions. */\nPNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp));\n#endif\n\n/* Replace the (error and abort), and warning functions with user\n * supplied functions.  If no messages are to be printed you must still\n * write and use replacement functions. The replacement error_fn should\n * still do a longjmp to the last setjmp location if you are using this\n * method of error handling.  If error_fn or warning_fn is NULL, the\n * default function will be used.\n */\n\nPNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr,\n    png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));\n\n/* Return the user pointer associated with the error functions */\nPNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr));\n\n/* Replace the default data output functions with a user supplied one(s).\n * If buffered output is not used, then output_flush_fn can be set to NULL.\n * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time\n * output_flush_fn will be ignored (and thus can be NULL).\n * It is probably a mistake to use NULL for output_flush_fn if\n * write_data_fn is not also NULL unless you have built libpng with\n * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's\n * default flush function, which uses the standard *FILE structure, will\n * be used.\n */\nPNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr,\n    png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));\n\n/* Replace the default data input function with a user supplied one. */\nPNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr,\n    png_rw_ptr read_data_fn));\n\n/* Return the user pointer associated with the I/O functions */\nPNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr));\n\nPNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr,\n    png_read_status_ptr read_row_fn));\n\nPNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr,\n    png_write_status_ptr write_row_fn));\n\n#ifdef PNG_USER_MEM_SUPPORTED\n/* Replace the default memory allocation functions with user supplied one(s). */\nPNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr,\n    png_malloc_ptr malloc_fn, png_free_ptr free_fn));\n/* Return the user pointer associated with the memory functions */\nPNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr));\n#endif\n\n#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED\nPNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr,\n    png_user_transform_ptr read_user_transform_fn));\n#endif\n\n#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED\nPNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr,\n    png_user_transform_ptr write_user_transform_fn));\n#endif\n\n#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED\nPNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr,\n    png_voidp user_transform_ptr, int user_transform_depth,\n    int user_transform_channels));\n/* Return the user pointer associated with the user transform functions */\nPNG_EXPORT(87, png_voidp, png_get_user_transform_ptr,\n    (png_const_structrp png_ptr));\n#endif\n\n#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED\n/* Return information about the row currently being processed.  Note that these\n * APIs do not fail but will return unexpected results if called outside a user\n * transform callback.  Also note that when transforming an interlaced image the\n * row number is the row number within the sub-image of the interlace pass, so\n * the value will increase to the height of the sub-image (not the full image)\n * then reset to 0 for the next pass.\n *\n * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to\n * find the output pixel (x,y) given an interlaced sub-image pixel\n * (row,col,pass).  (See below for these macros.)\n */\nPNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp));\nPNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp));\n#endif\n\n#ifdef PNG_READ_USER_CHUNKS_SUPPORTED\n/* This callback is called only for *unknown* chunks.  If\n * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known\n * chunks to be treated as unknown, however in this case the callback must do\n * any processing required by the chunk (e.g. by calling the appropriate\n * png_set_ APIs.)\n *\n * There is no write support - on write, by default, all the chunks in the\n * 'unknown' list are written in the specified position.\n *\n * The integer return from the callback function is interpreted thus:\n *\n * negative: An error occurred; png_chunk_error will be called.\n *     zero: The chunk was not handled, the chunk will be saved. A critical\n *           chunk will cause an error at this point unless it is to be saved.\n * positive: The chunk was handled, libpng will ignore/discard it.\n *\n * See \"INTERACTION WITH USER CHUNK CALLBACKS\" below for important notes about\n * how this behavior will change in libpng 1.7\n */\nPNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr,\n    png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));\n#endif\n\n#ifdef PNG_USER_CHUNKS_SUPPORTED\nPNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr));\n#endif\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\n/* Sets the function callbacks for the push reader, and a pointer to a\n * user-defined structure available to the callback functions.\n */\nPNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr,\n    png_voidp progressive_ptr, png_progressive_info_ptr info_fn,\n    png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn));\n\n/* Returns the user pointer associated with the push read functions */\nPNG_EXPORT(91, png_voidp, png_get_progressive_ptr,\n    (png_const_structrp png_ptr));\n\n/* Function to be called when data becomes available */\nPNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr,\n    png_inforp info_ptr, png_bytep buffer, size_t buffer_size));\n\n/* A function which may be called *only* within png_process_data to stop the\n * processing of any more data.  The function returns the number of bytes\n * remaining, excluding any that libpng has cached internally.  A subsequent\n * call to png_process_data must supply these bytes again.  If the argument\n * 'save' is set to true the routine will first save all the pending data and\n * will always return 0.\n */\nPNG_EXPORT(219, size_t, png_process_data_pause, (png_structrp, int save));\n\n/* A function which may be called *only* outside (after) a call to\n * png_process_data.  It returns the number of bytes of data to skip in the\n * input.  Normally it will return 0, but if it returns a non-zero value the\n * application must skip than number of bytes of input data and pass the\n * following data to the next call to png_process_data.\n */\nPNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp));\n\n/* Function that combines rows.  'new_row' is a flag that should come from\n * the callback and be non-NULL if anything needs to be done; the library\n * stores its own version of the new data internally and ignores the passed\n * in value.\n */\nPNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr,\n    png_bytep old_row, png_const_bytep new_row));\n#endif /* PROGRESSIVE_READ */\n\nPNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr,\n    png_alloc_size_t size), PNG_ALLOCATED);\n/* Added at libpng version 1.4.0 */\nPNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr,\n    png_alloc_size_t size), PNG_ALLOCATED);\n\n/* Added at libpng version 1.2.4 */\nPNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr,\n    png_alloc_size_t size), PNG_ALLOCATED);\n\n/* Frees a pointer allocated by png_malloc() */\nPNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));\n\n/* Free data that was allocated internally */\nPNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 free_me, int num));\n\n/* Reassign responsibility for freeing existing data, whether allocated\n * by libpng or by the application; this works on the png_info structure passed\n * in, it does not change the state for other png_info structures.\n *\n * It is unlikely that this function works correctly as of 1.6.0 and using it\n * may result either in memory leaks or double free of allocated data.\n */\nPNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int freer, png_uint_32 mask));\n\n/* Assignments for png_data_freer */\n#define PNG_DESTROY_WILL_FREE_DATA 1\n#define PNG_SET_WILL_FREE_DATA 1\n#define PNG_USER_WILL_FREE_DATA 2\n/* Flags for png_ptr->free_me and info_ptr->free_me */\n#define PNG_FREE_HIST 0x0008U\n#define PNG_FREE_ICCP 0x0010U\n#define PNG_FREE_SPLT 0x0020U\n#define PNG_FREE_ROWS 0x0040U\n#define PNG_FREE_PCAL 0x0080U\n#define PNG_FREE_SCAL 0x0100U\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n#  define PNG_FREE_UNKN 0x0200U\n#endif\n/*      PNG_FREE_LIST 0x0400U   removed in 1.6.0 because it is ignored */\n#define PNG_FREE_PLTE 0x1000U\n#define PNG_FREE_TRNS 0x2000U\n#define PNG_FREE_TEXT 0x4000U\n#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */\n#define PNG_FREE_ALL  0xffffU\n#define PNG_FREE_MUL  0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */\n\n#ifdef PNG_USER_MEM_SUPPORTED\nPNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr,\n    png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED);\nPNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr,\n    png_voidp ptr), PNG_DEPRECATED);\n#endif\n\n#ifdef PNG_ERROR_TEXT_SUPPORTED\n/* Fatal error in PNG image of libpng - can't continue */\nPNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr,\n    png_const_charp error_message), PNG_NORETURN);\n\n/* The same, but the chunk name is prepended to the error string. */\nPNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr,\n    png_const_charp error_message), PNG_NORETURN);\n\n#else\n/* Fatal error in PNG image of libpng - can't continue */\nPNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN);\n#  define png_error(s1,s2) png_err(s1)\n#  define png_chunk_error(s1,s2) png_err(s1)\n#endif\n\n#ifdef PNG_WARNINGS_SUPPORTED\n/* Non-fatal error in libpng.  Can continue, but may have a problem. */\nPNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr,\n    png_const_charp warning_message));\n\n/* Non-fatal error in libpng, chunk name is prepended to message. */\nPNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr,\n    png_const_charp warning_message));\n#else\n#  define png_warning(s1,s2) ((void)(s1))\n#  define png_chunk_warning(s1,s2) ((void)(s1))\n#endif\n\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\n/* Benign error in libpng.  Can continue, but may have a problem.\n * User can choose whether to handle as a fatal error or as a warning. */\nPNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr,\n    png_const_charp warning_message));\n\n#ifdef PNG_READ_SUPPORTED\n/* Same, chunk name is prepended to message (only during read) */\nPNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr,\n    png_const_charp warning_message));\n#endif\n\nPNG_EXPORT(109, void, png_set_benign_errors,\n    (png_structrp png_ptr, int allowed));\n#else\n#  ifdef PNG_ALLOW_BENIGN_ERRORS\n#    define png_benign_error png_warning\n#    define png_chunk_benign_error png_chunk_warning\n#  else\n#    define png_benign_error png_error\n#    define png_chunk_benign_error png_chunk_error\n#  endif\n#endif\n\n/* The png_set_<chunk> functions are for storing values in the png_info_struct.\n * Similarly, the png_get_<chunk> calls are used to read values from the\n * png_info_struct, either storing the parameters in the passed variables, or\n * setting pointers into the png_info_struct where the data is stored.  The\n * png_get_<chunk> functions return a non-zero value if the data was available\n * in info_ptr, or return zero and do not change any of the parameters if the\n * data was not available.\n *\n * These functions should be used instead of directly accessing png_info\n * to avoid problems with future changes in the size and internal layout of\n * png_info_struct.\n */\n/* Returns \"flag\" if chunk data is valid in info_ptr. */\nPNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, png_uint_32 flag));\n\n/* Returns number of bytes needed to hold a transformed row. */\nPNG_EXPORT(111, size_t, png_get_rowbytes, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\n/* Returns row_pointers, which is an array of pointers to scanlines that was\n * returned from png_read_png().\n */\nPNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Set row_pointers, which is an array of pointers to scanlines for use\n * by png_write_png().\n */\nPNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_bytepp row_pointers));\n#endif\n\n/* Returns number of color channels in image. */\nPNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n#ifdef PNG_EASY_ACCESS_SUPPORTED\n/* Returns image width in pixels. */\nPNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image height in pixels. */\nPNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image bit_depth. */\nPNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image color_type. */\nPNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image filter_type. */\nPNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image interlace_type. */\nPNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image compression_type. */\nPNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n\n/* Returns image resolution in pixels per meter, from pHYs chunk data. */\nPNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\n\n/* Returns pixel aspect ratio, computed from pHYs chunk data.  */\nPNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr))\nPNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr))\n\n/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */\nPNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(127, png_int_32, png_get_y_offset_pixels,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(128, png_int_32, png_get_x_offset_microns,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\nPNG_EXPORT(129, png_int_32, png_get_y_offset_microns,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\n\n#endif /* EASY_ACCESS */\n\n#ifdef PNG_READ_SUPPORTED\n/* Returns pointer to signature string read from PNG header */\nPNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr));\n#endif\n\n#ifdef PNG_bKGD_SUPPORTED\nPNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_color_16p *background));\n#endif\n\n#ifdef PNG_bKGD_SUPPORTED\nPNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_color_16p background));\n#endif\n\n#ifdef PNG_cHRM_SUPPORTED\nPNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x,\n    double *red_y, double *green_x, double *green_y, double *blue_x,\n    double *blue_y))\nPNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z,\n    double *green_X, double *green_Y, double *green_Z, double *blue_X,\n    double *blue_Y, double *blue_Z))\nPNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *int_white_x, png_fixed_point *int_white_y,\n    png_fixed_point *int_red_x, png_fixed_point *int_red_y,\n    png_fixed_point *int_green_x, png_fixed_point *int_green_y,\n    png_fixed_point *int_blue_x, png_fixed_point *int_blue_y))\nPNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *int_red_X, png_fixed_point *int_red_Y,\n    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,\n    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,\n    png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,\n    png_fixed_point *int_blue_Z))\n#endif\n\n#ifdef PNG_cHRM_SUPPORTED\nPNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr,\n    png_inforp info_ptr,\n    double white_x, double white_y, double red_x, double red_y, double green_x,\n    double green_y, double blue_x, double blue_y))\nPNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr,\n    png_inforp info_ptr, double red_X, double red_Y, double red_Z,\n    double green_X, double green_Y, double green_Z, double blue_X,\n    double blue_Y, double blue_Z))\nPNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_fixed_point int_white_x,\n    png_fixed_point int_white_y, png_fixed_point int_red_x,\n    png_fixed_point int_red_y, png_fixed_point int_green_x,\n    png_fixed_point int_green_y, png_fixed_point int_blue_x,\n    png_fixed_point int_blue_y))\nPNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,\n    png_fixed_point int_red_Z, png_fixed_point int_green_X,\n    png_fixed_point int_green_Y, png_fixed_point int_green_Z,\n    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,\n    png_fixed_point int_blue_Z))\n#endif\n\n#ifdef PNG_eXIf_SUPPORTED\nPNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_bytep *exif));\nPNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_bytep exif));\n\nPNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif));\nPNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 num_exif, png_bytep exif));\n#endif\n\n#ifdef PNG_gAMA_SUPPORTED\nPNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, double *file_gamma))\nPNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *int_file_gamma))\n#endif\n\n#ifdef PNG_gAMA_SUPPORTED\nPNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr,\n    png_inforp info_ptr, double file_gamma))\nPNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_fixed_point int_file_gamma))\n#endif\n\n#ifdef PNG_hIST_SUPPORTED\nPNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_uint_16p *hist));\nPNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_uint_16p hist));\n#endif\n\nPNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height,\n    int *bit_depth, int *color_type, int *interlace_method,\n    int *compression_method, int *filter_method));\n\nPNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,\n    int color_type, int interlace_method, int compression_method,\n    int filter_method));\n\n#ifdef PNG_oFFs_SUPPORTED\nPNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr,\n   png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,\n   int *unit_type));\n#endif\n\n#ifdef PNG_oFFs_SUPPORTED\nPNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y,\n    int unit_type));\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\nPNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_charp *purpose, png_int_32 *X0,\n    png_int_32 *X1, int *type, int *nparams, png_charp *units,\n    png_charpp *params));\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\nPNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1,\n    int type, int nparams, png_const_charp units, png_charpp params));\n#endif\n\n#ifdef PNG_pHYs_SUPPORTED\nPNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,\n    int *unit_type));\n#endif\n\n#ifdef PNG_pHYs_SUPPORTED\nPNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));\n#endif\n\nPNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr,\n   png_inforp info_ptr, png_colorp *palette, int *num_palette));\n\nPNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr,\n    png_inforp info_ptr, png_const_colorp palette, int num_palette));\n\n#ifdef PNG_sBIT_SUPPORTED\nPNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_color_8p *sig_bit));\n#endif\n\n#ifdef PNG_sBIT_SUPPORTED\nPNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_color_8p sig_bit));\n#endif\n\n#ifdef PNG_sRGB_SUPPORTED\nPNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, int *file_srgb_intent));\n#endif\n\n#ifdef PNG_sRGB_SUPPORTED\nPNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int srgb_intent));\nPNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int srgb_intent));\n#endif\n\n#ifdef PNG_iCCP_SUPPORTED\nPNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_charpp name, int *compression_type,\n    png_bytepp profile, png_uint_32 *proflen));\n#endif\n\n#ifdef PNG_iCCP_SUPPORTED\nPNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_charp name, int compression_type,\n    png_const_bytep profile, png_uint_32 proflen));\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\nPNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_sPLT_tpp entries));\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\nPNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries));\n#endif\n\n#ifdef PNG_TEXT_SUPPORTED\n/* png_get_text also returns the number of text chunks in *num_text */\nPNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_textp *text_ptr, int *num_text));\n#endif\n\n/* Note while png_set_text() will accept a structure whose text,\n * language, and  translated keywords are NULL pointers, the structure\n * returned by png_get_text will always contain regular\n * zero-terminated C strings.  They might be empty strings but\n * they will never be NULL pointers.\n */\n\n#ifdef PNG_TEXT_SUPPORTED\nPNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_textp text_ptr, int num_text));\n#endif\n\n#ifdef PNG_tIME_SUPPORTED\nPNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_timep *mod_time));\n#endif\n\n#ifdef PNG_tIME_SUPPORTED\nPNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_timep mod_time));\n#endif\n\n#ifdef PNG_tRNS_SUPPORTED\nPNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans,\n    png_color_16p *trans_color));\n#endif\n\n#ifdef PNG_tRNS_SUPPORTED\nPNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr,\n    png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans,\n    png_const_color_16p trans_color));\n#endif\n\n#ifdef PNG_sCAL_SUPPORTED\nPNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, int *unit, double *width, double *height))\n#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \\\n   defined(PNG_FLOATING_POINT_SUPPORTED)\n/* NOTE: this API is currently implemented using floating point arithmetic,\n * consequently it can only be used on systems with floating point support.\n * In any case the range of values supported by png_fixed_point is small and it\n * is highly recommended that png_get_sCAL_s be used instead.\n */\nPNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,\n    png_fixed_point *width, png_fixed_point *height))\n#endif\nPNG_EXPORT(169, png_uint_32, png_get_sCAL_s,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit,\n    png_charpp swidth, png_charpp sheight));\n\nPNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int unit, double width, double height))\nPNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr,\n   png_inforp info_ptr, int unit, png_fixed_point width,\n   png_fixed_point height))\nPNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int unit,\n    png_const_charp swidth, png_const_charp sheight));\n#endif /* sCAL */\n\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n/* Provide the default handling for all unknown chunks or, optionally, for\n * specific unknown chunks.\n *\n * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was\n * ignored and the default was used, the per-chunk setting only had an effect on\n * write.  If you wish to have chunk-specific handling on read in code that must\n * work on earlier versions you must use a user chunk callback to specify the\n * desired handling (keep or discard.)\n *\n * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below.  The\n * parameter is interpreted as follows:\n *\n * READ:\n *    PNG_HANDLE_CHUNK_AS_DEFAULT:\n *       Known chunks: do normal libpng processing, do not keep the chunk (but\n *          see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED)\n *       Unknown chunks: for a specific chunk use the global default, when used\n *          as the default discard the chunk data.\n *    PNG_HANDLE_CHUNK_NEVER:\n *       Discard the chunk data.\n *    PNG_HANDLE_CHUNK_IF_SAFE:\n *       Keep the chunk data if the chunk is not critical else raise a chunk\n *       error.\n *    PNG_HANDLE_CHUNK_ALWAYS:\n *       Keep the chunk data.\n *\n * If the chunk data is saved it can be retrieved using png_get_unknown_chunks,\n * below.  Notice that specifying \"AS_DEFAULT\" as a global default is equivalent\n * to specifying \"NEVER\", however when \"AS_DEFAULT\" is used for specific chunks\n * it simply resets the behavior to the libpng default.\n *\n * INTERACTION WITH USER CHUNK CALLBACKS:\n * The per-chunk handling is always used when there is a png_user_chunk_ptr\n * callback and the callback returns 0; the chunk is then always stored *unless*\n * it is critical and the per-chunk setting is other than ALWAYS.  Notice that\n * the global default is *not* used in this case.  (In effect the per-chunk\n * value is incremented to at least IF_SAFE.)\n *\n * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and\n * per-chunk defaults will be honored.  If you want to preserve the current\n * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE\n * as the default - if you don't do this libpng 1.6 will issue a warning.\n *\n * If you want unhandled unknown chunks to be discarded in libpng 1.6 and\n * earlier simply return '1' (handled).\n *\n * PNG_HANDLE_AS_UNKNOWN_SUPPORTED:\n *    If this is *not* set known chunks will always be handled by libpng and\n *    will never be stored in the unknown chunk list.  Known chunks listed to\n *    png_set_keep_unknown_chunks will have no effect.  If it is set then known\n *    chunks listed with a keep other than AS_DEFAULT will *never* be processed\n *    by libpng, in addition critical chunks must either be processed by the\n *    callback or saved.\n *\n *    The IHDR and IEND chunks must not be listed.  Because this turns off the\n *    default handling for chunks that would otherwise be recognized the\n *    behavior of libpng transformations may well become incorrect!\n *\n * WRITE:\n *    When writing chunks the options only apply to the chunks specified by\n *    png_set_unknown_chunks (below), libpng will *always* write known chunks\n *    required by png_set_ calls and will always write the core critical chunks\n *    (as required for PLTE).\n *\n *    Each chunk in the png_set_unknown_chunks list is looked up in the\n *    png_set_keep_unknown_chunks list to find the keep setting, this is then\n *    interpreted as follows:\n *\n *    PNG_HANDLE_CHUNK_AS_DEFAULT:\n *       Write safe-to-copy chunks and write other chunks if the global\n *       default is set to _ALWAYS, otherwise don't write this chunk.\n *    PNG_HANDLE_CHUNK_NEVER:\n *       Do not write the chunk.\n *    PNG_HANDLE_CHUNK_IF_SAFE:\n *       Write the chunk if it is safe-to-copy, otherwise do not write it.\n *    PNG_HANDLE_CHUNK_ALWAYS:\n *       Write the chunk.\n *\n * Note that the default behavior is effectively the opposite of the read case -\n * in read unknown chunks are not stored by default, in write they are written\n * by default.  Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different\n * - on write the safe-to-copy bit is checked, on read the critical bit is\n * checked and on read if the chunk is critical an error will be raised.\n *\n * num_chunks:\n * ===========\n *    If num_chunks is positive, then the \"keep\" parameter specifies the manner\n *    for handling only those chunks appearing in the chunk_list array,\n *    otherwise the chunk list array is ignored.\n *\n *    If num_chunks is 0 the \"keep\" parameter specifies the default behavior for\n *    unknown chunks, as described above.\n *\n *    If num_chunks is negative, then the \"keep\" parameter specifies the manner\n *    for handling all unknown chunks plus all chunks recognized by libpng\n *    except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to\n *    be processed by libpng.\n */\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\nPNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr,\n    int keep, png_const_bytep chunk_list, int num_chunks));\n#endif /* HANDLE_AS_UNKNOWN */\n\n/* The \"keep\" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned;\n * the result is therefore true (non-zero) if special handling is required,\n * false for the default handling.\n */\nPNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr,\n    png_const_bytep chunk_name));\n#endif /* SET_UNKNOWN_CHUNKS */\n\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\nPNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_unknown_chunkp unknowns,\n    int num_unknowns));\n   /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added\n    * unknowns to the location currently stored in the png_struct.  This is\n    * invariably the wrong value on write.  To fix this call the following API\n    * for each chunk in the list with the correct location.  If you know your\n    * code won't be compiled on earlier versions you can rely on\n    * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing\n    * the correct thing.\n    */\n\nPNG_EXPORT(175, void, png_set_unknown_chunk_location,\n    (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location));\n\nPNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr,\n    png_inforp info_ptr, png_unknown_chunkpp entries));\n#endif\n\n/* Png_free_data() will turn off the \"valid\" flag for anything it frees.\n * If you need to turn it off for a chunk that your application has freed,\n * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK);\n */\nPNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr,\n    png_inforp info_ptr, int mask));\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\n/* The \"params\" pointer is currently not used and is for future expansion. */\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\nPNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr,\n    int transforms, png_voidp params));\n#endif\n#ifdef PNG_WRITE_SUPPORTED\nPNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr,\n    int transforms, png_voidp params));\n#endif\n#endif\n\nPNG_EXPORT(180, png_const_charp, png_get_copyright,\n    (png_const_structrp png_ptr));\nPNG_EXPORT(181, png_const_charp, png_get_header_ver,\n    (png_const_structrp png_ptr));\nPNG_EXPORT(182, png_const_charp, png_get_header_version,\n    (png_const_structrp png_ptr));\nPNG_EXPORT(183, png_const_charp, png_get_libpng_ver,\n    (png_const_structrp png_ptr));\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\nPNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr,\n    png_uint_32 mng_features_permitted));\n#endif\n\n/* For use in png_set_keep_unknown, added to version 1.2.6 */\n#define PNG_HANDLE_CHUNK_AS_DEFAULT   0\n#define PNG_HANDLE_CHUNK_NEVER        1\n#define PNG_HANDLE_CHUNK_IF_SAFE      2\n#define PNG_HANDLE_CHUNK_ALWAYS       3\n#define PNG_HANDLE_CHUNK_LAST         4\n\n/* Strip the prepended error numbers (\"#nnn \") from error and warning\n * messages before passing them to the error or warning handler.\n */\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\nPNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr,\n    png_uint_32 strip_mode));\n#endif\n\n/* Added in libpng-1.2.6 */\n#ifdef PNG_SET_USER_LIMITS_SUPPORTED\nPNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr,\n    png_uint_32 user_width_max, png_uint_32 user_height_max));\nPNG_EXPORT(187, png_uint_32, png_get_user_width_max,\n    (png_const_structrp png_ptr));\nPNG_EXPORT(188, png_uint_32, png_get_user_height_max,\n    (png_const_structrp png_ptr));\n/* Added in libpng-1.4.0 */\nPNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr,\n    png_uint_32 user_chunk_cache_max));\nPNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max,\n    (png_const_structrp png_ptr));\n/* Added in libpng-1.4.1 */\nPNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr,\n    png_alloc_size_t user_chunk_cache_max));\nPNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max,\n    (png_const_structrp png_ptr));\n#endif\n\n#if defined(PNG_INCH_CONVERSIONS_SUPPORTED)\nPNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\n\nPNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\n\nPNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr));\n\nPNG_FP_EXPORT(196, float, png_get_x_offset_inches,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr))\n#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */\nPNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr))\n#endif\n\nPNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr))\n#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */\nPNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,\n    (png_const_structrp png_ptr, png_const_inforp info_ptr))\n#endif\n\n#  ifdef PNG_pHYs_SUPPORTED\nPNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr,\n    png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y,\n    int *unit_type));\n#  endif /* pHYs */\n#endif  /* INCH_CONVERSIONS */\n\n/* Added in libpng-1.4.0 */\n#ifdef PNG_IO_STATE_SUPPORTED\nPNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr));\n\n/* Removed from libpng 1.6; use png_get_io_chunk_type. */\nPNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr),\n    PNG_DEPRECATED)\n\nPNG_EXPORT(216, png_uint_32, png_get_io_chunk_type,\n    (png_const_structrp png_ptr));\n\n/* The flags returned by png_get_io_state() are the following: */\n#  define PNG_IO_NONE        0x0000   /* no I/O at this moment */\n#  define PNG_IO_READING     0x0001   /* currently reading */\n#  define PNG_IO_WRITING     0x0002   /* currently writing */\n#  define PNG_IO_SIGNATURE   0x0010   /* currently at the file signature */\n#  define PNG_IO_CHUNK_HDR   0x0020   /* currently at the chunk header */\n#  define PNG_IO_CHUNK_DATA  0x0040   /* currently at the chunk data */\n#  define PNG_IO_CHUNK_CRC   0x0080   /* currently at the chunk crc */\n#  define PNG_IO_MASK_OP     0x000f   /* current operation: reading/writing */\n#  define PNG_IO_MASK_LOC    0x00f0   /* current location: sig/hdr/data/crc */\n#endif /* IO_STATE */\n\n/* Interlace support.  The following macros are always defined so that if\n * libpng interlace handling is turned off the macros may be used to handle\n * interlaced images within the application.\n */\n#define PNG_INTERLACE_ADAM7_PASSES 7\n\n/* Two macros to return the first row and first column of the original,\n * full, image which appears in a given pass.  'pass' is in the range 0\n * to 6 and the result is in the range 0 to 7.\n */\n#define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7)\n#define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7)\n\n/* A macro to return the offset between pixels in the output row for a pair of\n * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that\n * follows.  Note that ROW_OFFSET is the offset from one row to the next whereas\n * COL_OFFSET is from one column to the next, within a row.\n */\n#define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8)\n#define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1))\n\n/* Two macros to help evaluate the number of rows or columns in each\n * pass.  This is expressed as a shift - effectively log2 of the number or\n * rows or columns in each 8x8 tile of the original image.\n */\n#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)\n#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)\n\n/* Hence two macros to determine the number of rows or columns in a given\n * pass of an image given its height or width.  In fact these macros may\n * return non-zero even though the sub-image is empty, because the other\n * dimension may be empty for a small image.\n */\n#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\\\n   -1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass))\n#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\\\n   -1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass))\n\n/* For the reader row callbacks (both progressive and sequential) it is\n * necessary to find the row in the output image given a row in an interlaced\n * image, so two more macros:\n */\n#define PNG_ROW_FROM_PASS_ROW(y_in, pass) \\\n   (((y_in)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass))\n#define PNG_COL_FROM_PASS_COL(x_in, pass) \\\n   (((x_in)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass))\n\n/* Two macros which return a boolean (0 or 1) saying whether the given row\n * or column is in a particular pass.  These use a common utility macro that\n * returns a mask for a given pass - the offset 'off' selects the row or\n * column version.  The mask has the appropriate bit set for each column in\n * the tile.\n */\n#define PNG_PASS_MASK(pass,off) ( \\\n   ((0x110145AF>>(((7-(off))-(pass))<<2)) & 0xF) | \\\n   ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0))\n\n#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \\\n   ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)\n#define PNG_COL_IN_INTERLACE_PASS(x, pass) \\\n   ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)\n\n#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED\n/* With these routines we avoid an integer divide, which will be slower on\n * most machines.  However, it does take more operations than the corresponding\n * divide method, so it may be slower on a few RISC systems.  There are two\n * shifts (by 8 or 16 bits) and an addition, versus a single integer divide.\n *\n * Note that the rounding factors are NOT supposed to be the same!  128 and\n * 32768 are correct for the NODIV code; 127 and 32767 are correct for the\n * standard method.\n *\n * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]\n */\n\n /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */\n\n#  define png_composite(composite, fg, alpha, bg)        \\\n   {                                                     \\\n      png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \\\n          * (png_uint_16)(alpha)                         \\\n          + (png_uint_16)(bg)*(png_uint_16)(255          \\\n          - (png_uint_16)(alpha)) + 128);                \\\n      (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); \\\n   }\n\n#  define png_composite_16(composite, fg, alpha, bg)     \\\n   {                                                     \\\n      png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \\\n          * (png_uint_32)(alpha)                         \\\n          + (png_uint_32)(bg)*(65535                     \\\n          - (png_uint_32)(alpha)) + 32768);              \\\n      (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); \\\n   }\n\n#else  /* Standard method using integer division */\n\n#  define png_composite(composite, fg, alpha, bg)                      \\\n   (composite) =                                                       \\\n       (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) +  \\\n       (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \\\n       127) / 255))\n\n#  define png_composite_16(composite, fg, alpha, bg)                       \\\n   (composite) =                                                           \\\n       (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \\\n       (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) +     \\\n       32767) / 65535))\n#endif /* READ_COMPOSITE_NODIV */\n\n#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED\nPNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf));\nPNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf));\nPNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf));\n#endif\n\nPNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr,\n    png_const_bytep buf));\n/* No png_get_int_16 -- may be added if there's a real need for it. */\n\n/* Place a 32-bit number into a buffer in PNG byte order (big-endian). */\n#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED\nPNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i));\n#endif\n#ifdef PNG_SAVE_INT_32_SUPPORTED\nPNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i));\n#endif\n\n/* Place a 16-bit number into a buffer in PNG byte order.\n * The parameter is declared unsigned int, not png_uint_16,\n * just to avoid potential problems on pre-ANSI C compilers.\n */\n#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED\nPNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));\n/* No png_save_int_16 -- may be added if there's a real need for it. */\n#endif\n\n#ifdef PNG_USE_READ_MACROS\n/* Inline macros to do direct reads of bytes from the input buffer.\n * The png_get_int_32() routine assumes we are using two's complement\n * format for negative values, which is almost certainly true.\n */\n#  define PNG_get_uint_32(buf) \\\n   (((png_uint_32)(*(buf)) << 24) + \\\n    ((png_uint_32)(*((buf) + 1)) << 16) + \\\n    ((png_uint_32)(*((buf) + 2)) << 8) + \\\n    ((png_uint_32)(*((buf) + 3))))\n\n   /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the\n    * function) incorrectly returned a value of type png_uint_32.\n    */\n#  define PNG_get_uint_16(buf) \\\n   ((png_uint_16) \\\n    (((unsigned int)(*(buf)) << 8) + \\\n    ((unsigned int)(*((buf) + 1)))))\n\n#  define PNG_get_int_32(buf) \\\n   ((png_int_32)((*(buf) & 0x80) \\\n    ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \\\n    : (png_int_32)png_get_uint_32(buf)))\n\n/* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h,\n * but defining a macro name prefixed with PNG_PREFIX.\n */\n#  ifndef PNG_PREFIX\n#    define png_get_uint_32(buf) PNG_get_uint_32(buf)\n#    define png_get_uint_16(buf) PNG_get_uint_16(buf)\n#    define png_get_int_32(buf)  PNG_get_int_32(buf)\n#  endif\n#else\n#  ifdef PNG_PREFIX\n   /* No macros; revert to the (redefined) function */\n#    define PNG_get_uint_32 (png_get_uint_32)\n#    define PNG_get_uint_16 (png_get_uint_16)\n#    define PNG_get_int_32  (png_get_int_32)\n#  endif\n#endif\n\n#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\nPNG_EXPORT(242, void, png_set_check_for_invalid_index,\n    (png_structrp png_ptr, int allowed));\n#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED\nPNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr,\n    png_const_infop info_ptr));\n#  endif\n#endif /* CHECK_FOR_INVALID_INDEX */\n\n/*******************************************************************************\n * Section 5: SIMPLIFIED API\n *******************************************************************************\n *\n * Please read the documentation in libpng-manual.txt (TODO: write said\n * documentation) if you don't understand what follows.\n *\n * The simplified API hides the details of both libpng and the PNG file format\n * itself.  It allows PNG files to be read into a very limited number of\n * in-memory bitmap formats or to be written from the same formats.  If these\n * formats do not accommodate your needs then you can, and should, use the more\n * sophisticated APIs above - these support a wide variety of in-memory formats\n * and a wide variety of sophisticated transformations to those formats as well\n * as a wide variety of APIs to manipulate ancillary information.\n *\n * To read a PNG file using the simplified API:\n *\n * 1) Declare a 'png_image' structure (see below) on the stack, set the\n *    version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL\n *    (this is REQUIRED, your program may crash if you don't do it.)\n * 2) Call the appropriate png_image_begin_read... function.\n * 3) Set the png_image 'format' member to the required sample format.\n * 4) Allocate a buffer for the image and, if required, the color-map.\n * 5) Call png_image_finish_read to read the image and, if required, the\n *    color-map into your buffers.\n *\n * There are no restrictions on the format of the PNG input itself; all valid\n * color types, bit depths, and interlace methods are acceptable, and the\n * input image is transformed as necessary to the requested in-memory format\n * during the png_image_finish_read() step.  The only caveat is that if you\n * request a color-mapped image from a PNG that is full-color or makes\n * complex use of an alpha channel the transformation is extremely lossy and the\n * result may look terrible.\n *\n * To write a PNG file using the simplified API:\n *\n * 1) Declare a 'png_image' structure on the stack and memset() it to all zero.\n * 2) Initialize the members of the structure that describe the image, setting\n *    the 'format' member to the format of the image samples.\n * 3) Call the appropriate png_image_write... function with a pointer to the\n *    image and, if necessary, the color-map to write the PNG data.\n *\n * png_image is a structure that describes the in-memory format of an image\n * when it is being read or defines the in-memory format of an image that you\n * need to write:\n */\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \\\n    defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\n\n#define PNG_IMAGE_VERSION 1\n\ntypedef struct png_control *png_controlp;\ntypedef struct\n{\n   png_controlp opaque;    /* Initialize to NULL, free with png_image_free */\n   png_uint_32  version;   /* Set to PNG_IMAGE_VERSION */\n   png_uint_32  width;     /* Image width in pixels (columns) */\n   png_uint_32  height;    /* Image height in pixels (rows) */\n   png_uint_32  format;    /* Image format as defined below */\n   png_uint_32  flags;     /* A bit mask containing informational flags */\n   png_uint_32  colormap_entries;\n                           /* Number of entries in the color-map */\n\n   /* In the event of an error or warning the following field will be set to a\n    * non-zero value and the 'message' field will contain a '\\0' terminated\n    * string with the libpng error or warning message.  If both warnings and\n    * an error were encountered, only the error is recorded.  If there\n    * are multiple warnings, only the first one is recorded.\n    *\n    * The upper 30 bits of this value are reserved, the low two bits contain\n    * a value as follows:\n    */\n#  define PNG_IMAGE_WARNING 1\n#  define PNG_IMAGE_ERROR 2\n   /*\n    * The result is a two-bit code such that a value more than 1 indicates\n    * a failure in the API just called:\n    *\n    *    0 - no warning or error\n    *    1 - warning\n    *    2 - error\n    *    3 - error preceded by warning\n    */\n#  define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1)\n\n   png_uint_32  warning_or_error;\n\n   char         message[64];\n} png_image, *png_imagep;\n\n/* The samples of the image have one to four channels whose components have\n * original values in the range 0 to 1.0:\n *\n * 1: A single gray or luminance channel (G).\n * 2: A gray/luminance channel and an alpha channel (GA).\n * 3: Three red, green, blue color channels (RGB).\n * 4: Three color channels and an alpha channel (RGBA).\n *\n * The components are encoded in one of two ways:\n *\n * a) As a small integer, value 0..255, contained in a single byte.  For the\n * alpha channel the original value is simply value/255.  For the color or\n * luminance channels the value is encoded according to the sRGB specification\n * and matches the 8-bit format expected by typical display devices.\n *\n * The color/gray channels are not scaled (pre-multiplied) by the alpha\n * channel and are suitable for passing to color management software.\n *\n * b) As a value in the range 0..65535, contained in a 2-byte integer.  All\n * channels can be converted to the original value by dividing by 65535; all\n * channels are linear.  Color channels use the RGB encoding (RGB end-points) of\n * the sRGB specification.  This encoding is identified by the\n * PNG_FORMAT_FLAG_LINEAR flag below.\n *\n * When the simplified API needs to convert between sRGB and linear colorspaces,\n * the actual sRGB transfer curve defined in the sRGB specification (see the\n * article at <https://en.wikipedia.org/wiki/SRGB>) is used, not the gamma=1/2.2\n * approximation used elsewhere in libpng.\n *\n * When an alpha channel is present it is expected to denote pixel coverage\n * of the color or luminance channels and is returned as an associated alpha\n * channel: the color/gray channels are scaled (pre-multiplied) by the alpha\n * value.\n *\n * The samples are either contained directly in the image data, between 1 and 8\n * bytes per pixel according to the encoding, or are held in a color-map indexed\n * by bytes in the image data.  In the case of a color-map the color-map entries\n * are individual samples, encoded as above, and the image data has one byte per\n * pixel to select the relevant sample from the color-map.\n */\n\n/* PNG_FORMAT_*\n *\n * #defines to be used in png_image::format.  Each #define identifies a\n * particular layout of sample data and, if present, alpha values.  There are\n * separate defines for each of the two component encodings.\n *\n * A format is built up using single bit flag values.  All combinations are\n * valid.  Formats can be built up from the flag values or you can use one of\n * the predefined values below.  When testing formats always use the FORMAT_FLAG\n * macros to test for individual features - future versions of the library may\n * add new flags.\n *\n * When reading or writing color-mapped images the format should be set to the\n * format of the entries in the color-map then png_image_{read,write}_colormap\n * called to read or write the color-map and set the format correctly for the\n * image data.  Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly!\n *\n * NOTE: libpng can be built with particular features disabled. If you see\n * compiler errors because the definition of one of the following flags has been\n * compiled out it is because libpng does not have the required support.  It is\n * possible, however, for the libpng configuration to enable the format on just\n * read or just write; in that case you may see an error at run time.  You can\n * guard against this by checking for the definition of the appropriate\n * \"_SUPPORTED\" macro, one of:\n *\n *    PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED\n */\n#define PNG_FORMAT_FLAG_ALPHA    0x01U /* format with an alpha channel */\n#define PNG_FORMAT_FLAG_COLOR    0x02U /* color format: otherwise grayscale */\n#define PNG_FORMAT_FLAG_LINEAR   0x04U /* 2-byte channels else 1-byte */\n#define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */\n\n#ifdef PNG_FORMAT_BGR_SUPPORTED\n#  define PNG_FORMAT_FLAG_BGR    0x10U /* BGR colors, else order is RGB */\n#endif\n\n#ifdef PNG_FORMAT_AFIRST_SUPPORTED\n#  define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */\n#endif\n\n#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */\n\n/* Commonly used formats have predefined macros.\n *\n * First the single byte (sRGB) formats:\n */\n#define PNG_FORMAT_GRAY 0\n#define PNG_FORMAT_GA   PNG_FORMAT_FLAG_ALPHA\n#define PNG_FORMAT_AG   (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST)\n#define PNG_FORMAT_RGB  PNG_FORMAT_FLAG_COLOR\n#define PNG_FORMAT_BGR  (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR)\n#define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA)\n#define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST)\n#define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA)\n#define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST)\n\n/* Then the linear 2-byte formats.  When naming these \"Y\" is used to\n * indicate a luminance (gray) channel.\n */\n#define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR\n#define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA)\n#define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR)\n#define PNG_FORMAT_LINEAR_RGB_ALPHA \\\n   (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA)\n\n/* With color-mapped formats the image data is one byte for each pixel, the byte\n * is an index into the color-map which is formatted as above.  To obtain a\n * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP\n * to one of the above definitions, or you can use one of the definitions below.\n */\n#define PNG_FORMAT_RGB_COLORMAP  (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP)\n#define PNG_FORMAT_BGR_COLORMAP  (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP)\n#define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP)\n#define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP)\n#define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP)\n#define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP)\n\n/* PNG_IMAGE macros\n *\n * These are convenience macros to derive information from a png_image\n * structure.  The PNG_IMAGE_SAMPLE_ macros return values appropriate to the\n * actual image sample values - either the entries in the color-map or the\n * pixels in the image.  The PNG_IMAGE_PIXEL_ macros return corresponding values\n * for the pixels and will always return 1 for color-mapped formats.  The\n * remaining macros return information about the rows in the image and the\n * complete image.\n *\n * NOTE: All the macros that take a png_image::format parameter are compile time\n * constants if the format parameter is, itself, a constant.  Therefore these\n * macros can be used in array declarations and case labels where required.\n * Similarly the macros are also pre-processor constants (sizeof is not used) so\n * they can be used in #if tests.\n *\n * First the information about the samples.\n */\n#define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\\\n   (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1)\n   /* Return the total number of channels in a given format: 1..4 */\n\n#define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\\\n   ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1)\n   /* Return the size in bytes of a single component of a pixel or color-map\n    * entry (as appropriate) in the image: 1 or 2.\n    */\n\n#define PNG_IMAGE_SAMPLE_SIZE(fmt)\\\n   (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt))\n   /* This is the size of the sample data for one sample.  If the image is\n    * color-mapped it is the size of one color-map entry (and image pixels are\n    * one byte in size), otherwise it is the size of one image pixel.\n    */\n\n#define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\\\n   (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256)\n   /* The maximum size of the color-map required by the format expressed in a\n    * count of components.  This can be used to compile-time allocate a\n    * color-map:\n    *\n    * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)];\n    *\n    * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)];\n    *\n    * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the\n    * information from one of the png_image_begin_read_ APIs and dynamically\n    * allocate the required memory.\n    */\n\n/* Corresponding information about the pixels */\n#define PNG_IMAGE_PIXEL_(test,fmt)\\\n   (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt))\n\n#define PNG_IMAGE_PIXEL_CHANNELS(fmt)\\\n   PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt)\n   /* The number of separate channels (components) in a pixel; 1 for a\n    * color-mapped image.\n    */\n\n#define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\\\n   PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt)\n   /* The size, in bytes, of each component in a pixel; 1 for a color-mapped\n    * image.\n    */\n\n#define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt)\n   /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */\n\n/* Information about the whole row, or whole image */\n#define PNG_IMAGE_ROW_STRIDE(image)\\\n   (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width)\n   /* Return the total number of components in a single row of the image; this\n    * is the minimum 'row stride', the minimum count of components between each\n    * row.  For a color-mapped image this is the minimum number of bytes in a\n    * row.\n    *\n    * WARNING: this macro overflows for some images with more than one component\n    * and very large image widths.  libpng will refuse to process an image where\n    * this macro would overflow.\n    */\n\n#define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\\\n   (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride))\n   /* Return the size, in bytes, of an image buffer given a png_image and a row\n    * stride - the number of components to leave space for in each row.\n    *\n    * WARNING: this macro overflows a 32-bit integer for some large PNG images,\n    * libpng will refuse to process an image where such an overflow would occur.\n    */\n\n#define PNG_IMAGE_SIZE(image)\\\n   PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image))\n   /* Return the size, in bytes, of the image in memory given just a png_image;\n    * the row stride is the minimum stride required for the image.\n    */\n\n#define PNG_IMAGE_COLORMAP_SIZE(image)\\\n   (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries)\n   /* Return the size, in bytes, of the color-map of this image.  If the image\n    * format is not a color-map format this will return a size sufficient for\n    * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if\n    * you don't want to allocate a color-map in this case.\n    */\n\n/* PNG_IMAGE_FLAG_*\n *\n * Flags containing additional information about the image are held in the\n * 'flags' field of png_image.\n */\n#define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01\n   /* This indicates that the RGB values of the in-memory bitmap do not\n    * correspond to the red, green and blue end-points defined by sRGB.\n    */\n\n#define PNG_IMAGE_FLAG_FAST 0x02\n   /* On write emphasise speed over compression; the resultant PNG file will be\n    * larger but will be produced significantly faster, particular for large\n    * images.  Do not use this option for images which will be distributed, only\n    * used it when producing intermediate files that will be read back in\n    * repeatedly.  For a typical 24-bit image the option will double the read\n    * speed at the cost of increasing the image size by 25%, however for many\n    * more compressible images the PNG file can be 10 times larger with only a\n    * slight speed gain.\n    */\n\n#define PNG_IMAGE_FLAG_16BIT_sRGB 0x04\n   /* On read if the image is a 16-bit per component image and there is no gAMA\n    * or sRGB chunk assume that the components are sRGB encoded.  Notice that\n    * images output by the simplified API always have gamma information; setting\n    * this flag only affects the interpretation of 16-bit images from an\n    * external source.  It is recommended that the application expose this flag\n    * to the user; the user can normally easily recognize the difference between\n    * linear and sRGB encoding.  This flag has no effect on write - the data\n    * passed to the write APIs must have the correct encoding (as defined\n    * above.)\n    *\n    * If the flag is not set (the default) input 16-bit per component data is\n    * assumed to be linear.\n    *\n    * NOTE: the flag can only be set after the png_image_begin_read_ call,\n    * because that call initializes the 'flags' field.\n    */\n\n#ifdef PNG_SIMPLIFIED_READ_SUPPORTED\n/* READ APIs\n * ---------\n *\n * The png_image passed to the read APIs must have been initialized by setting\n * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.)\n */\n#ifdef PNG_STDIO_SUPPORTED\nPNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image,\n   const char *file_name));\n   /* The named file is opened for read and the image header is filled in\n    * from the PNG header in the file.\n    */\n\nPNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image,\n   FILE* file));\n   /* The PNG header is read from the stdio FILE object. */\n#endif /* STDIO */\n\nPNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image,\n   png_const_voidp memory, size_t size));\n   /* The PNG header is read from the given memory buffer. */\n\nPNG_EXPORT(237, int, png_image_finish_read, (png_imagep image,\n   png_const_colorp background, void *buffer, png_int_32 row_stride,\n   void *colormap));\n   /* Finish reading the image into the supplied buffer and clean up the\n    * png_image structure.\n    *\n    * row_stride is the step, in byte or 2-byte units as appropriate,\n    * between adjacent rows.  A positive stride indicates that the top-most row\n    * is first in the buffer - the normal top-down arrangement.  A negative\n    * stride indicates that the bottom-most row is first in the buffer.\n    *\n    * background need only be supplied if an alpha channel must be removed from\n    * a png_byte format and the removal is to be done by compositing on a solid\n    * color; otherwise it may be NULL and any composition will be done directly\n    * onto the buffer.  The value is an sRGB color to use for the background,\n    * for grayscale output the green channel is used.\n    *\n    * background must be supplied when an alpha channel must be removed from a\n    * single byte color-mapped output format, in other words if:\n    *\n    * 1) The original format from png_image_begin_read_from_* had\n    *    PNG_FORMAT_FLAG_ALPHA set.\n    * 2) The format set by the application does not.\n    * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and\n    *    PNG_FORMAT_FLAG_LINEAR *not* set.\n    *\n    * For linear output removing the alpha channel is always done by compositing\n    * on black and background is ignored.\n    *\n    * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set.  It must\n    * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE.\n    * image->colormap_entries will be updated to the actual number of entries\n    * written to the colormap; this may be less than the original value.\n    */\n\nPNG_EXPORT(238, void, png_image_free, (png_imagep image));\n   /* Free any data allocated by libpng in image->opaque, setting the pointer to\n    * NULL.  May be called at any time after the structure is initialized.\n    */\n#endif /* SIMPLIFIED_READ */\n\n#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED\n/* WRITE APIS\n * ----------\n * For write you must initialize a png_image structure to describe the image to\n * be written.  To do this use memset to set the whole structure to 0 then\n * initialize fields describing your image.\n *\n * version: must be set to PNG_IMAGE_VERSION\n * opaque: must be initialized to NULL\n * width: image width in pixels\n * height: image height in rows\n * format: the format of the data (image and color-map) you wish to write\n * flags: set to 0 unless one of the defined flags applies; set\n *    PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB\n *    values do not correspond to the colors in sRGB.\n * colormap_entries: set to the number of entries in the color-map (0 to 256)\n */\n#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED\nPNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,\n   const char *file, int convert_to_8bit, const void *buffer,\n   png_int_32 row_stride, const void *colormap));\n   /* Write the image to the named file. */\n\nPNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,\n   int convert_to_8_bit, const void *buffer, png_int_32 row_stride,\n   const void *colormap));\n   /* Write the image to the given (FILE*). */\n#endif /* SIMPLIFIED_WRITE_STDIO */\n\n/* With all write APIs if image is in one of the linear formats with 16-bit\n * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG\n * gamma encoded according to the sRGB specification, otherwise a 16-bit linear\n * encoded PNG file is written.\n *\n * With color-mapped data formats the colormap parameter point to a color-map\n * with at least image->colormap_entries encoded in the specified format.  If\n * the format is linear the written PNG color-map will be converted to sRGB\n * regardless of the convert_to_8_bit flag.\n *\n * With all APIs row_stride is handled as in the read APIs - it is the spacing\n * from one row to the next in component sized units (1 or 2 bytes) and if\n * negative indicates a bottom-up row layout in the buffer.  If row_stride is\n * zero, libpng will calculate it for you from the image width and number of\n * channels.\n *\n * Note that the write API does not support interlacing, sub-8-bit pixels or\n * most ancillary chunks.  If you need to write text chunks (e.g. for copyright\n * notices) you need to use one of the other APIs.\n */\n\nPNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,\n   png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit,\n   const void *buffer, png_int_32 row_stride, const void *colormap));\n   /* Write the image to the given memory buffer.  The function both writes the\n    * whole PNG data stream to *memory and updates *memory_bytes with the count\n    * of bytes written.\n    *\n    * 'memory' may be NULL.  In this case *memory_bytes is not read however on\n    * success the number of bytes which would have been written will still be\n    * stored in *memory_bytes.  On failure *memory_bytes will contain 0.\n    *\n    * If 'memory' is not NULL it must point to memory[*memory_bytes] of\n    * writeable memory.\n    *\n    * If the function returns success memory[*memory_bytes] (if 'memory' is not\n    * NULL) contains the written PNG data.  *memory_bytes will always be less\n    * than or equal to the original value.\n    *\n    * If the function returns false and *memory_bytes was not changed an error\n    * occurred during write.  If *memory_bytes was changed, or is not 0 if\n    * 'memory' was NULL, the write would have succeeded but for the memory\n    * buffer being too small.  *memory_bytes contains the required number of\n    * bytes and will be bigger that the original value.\n    */\n\n#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\\\n   row_stride, colormap)\\\n   png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\\\n         row_stride, colormap)\n   /* Return the amount of memory in 'size' required to compress this image.\n    * The png_image structure 'image' must be filled in as in the above\n    * function and must not be changed before the actual write call, the buffer\n    * and all other parameters must also be identical to that in the final\n    * write call.  The 'size' variable need not be initialized.\n    *\n    * NOTE: the macro returns true/false, if false is returned 'size' will be\n    * set to zero and the write failed and probably will fail if tried again.\n    */\n\n/* You can pre-allocate the buffer by making sure it is of sufficient size\n * regardless of the amount of compression achieved.  The buffer size will\n * always be bigger than the original image and it will never be filled.  The\n * following macros are provided to assist in allocating the buffer.\n */\n#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height)\n   /* The number of uncompressed bytes in the PNG byte encoding of the image;\n    * uncompressing the PNG IDAT data will give this number of bytes.\n    *\n    * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this\n    * macro can because of the extra bytes used in the PNG byte encoding.  You\n    * need to avoid this macro if your image size approaches 2^30 in width or\n    * height.  The same goes for the remainder of these macros; they all produce\n    * bigger numbers than the actual in-memory image size.\n    */\n#ifndef PNG_ZLIB_MAX_SIZE\n#  define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U)\n   /* An upper bound on the number of compressed bytes given 'b' uncompressed\n    * bytes.  This is based on deflateBounds() in zlib; different\n    * implementations of zlib compression may conceivably produce more data so\n    * if your zlib implementation is not zlib itself redefine this macro\n    * appropriately.\n    */\n#endif\n\n#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\\\n   PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image))\n   /* An upper bound on the size of the data in the PNG IDAT chunks. */\n\n#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\\\n   ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\\\n    (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\\\n    12U+3U*(image).colormap_entries/*PLTE data*/+\\\n    (((image).format&PNG_FORMAT_FLAG_ALPHA)?\\\n    12U/*tRNS*/+(image).colormap_entries:0U):0U)+\\\n    12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size))\n   /* A helper for the following macro; if your compiler cannot handle the\n    * following macro use this one with the result of\n    * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most\n    * compilers should handle this just fine.)\n    */\n\n#define PNG_IMAGE_PNG_SIZE_MAX(image)\\\n   PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image))\n   /* An upper bound on the total length of the PNG data stream for 'image'.\n    * The result is of type png_alloc_size_t, on 32-bit systems this may\n    * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will\n    * run out of buffer space but return a corrected size which should work.\n    */\n#endif /* SIMPLIFIED_WRITE */\n/*******************************************************************************\n *  END OF SIMPLIFIED API\n ******************************************************************************/\n#endif /* SIMPLIFIED_{READ|WRITE} */\n\n/*******************************************************************************\n * Section 6: IMPLEMENTATION OPTIONS\n *******************************************************************************\n *\n * Support for arbitrary implementation-specific optimizations.  The API allows\n * particular options to be turned on or off.  'Option' is the number of the\n * option and 'onoff' is 0 (off) or non-0 (on).  The value returned is given\n * by the PNG_OPTION_ defines below.\n *\n * HARDWARE: normally hardware capabilities, such as the Intel SSE instructions,\n *           are detected at run time, however sometimes it may be impossible\n *           to do this in user mode, in which case it is necessary to discover\n *           the capabilities in an OS specific way.  Such capabilities are\n *           listed here when libpng has support for them and must be turned\n *           ON by the application if present.\n *\n * SOFTWARE: sometimes software optimizations actually result in performance\n *           decrease on some architectures or systems, or with some sets of\n *           PNG images.  'Software' options allow such optimizations to be\n *           selected at run time.\n */\n#ifdef PNG_SET_OPTION_SUPPORTED\n#ifdef PNG_ARM_NEON_API_SUPPORTED\n#  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */\n#endif\n#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */\n#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */\n#ifdef PNG_MIPS_MSA_API_SUPPORTED\n#  define PNG_MIPS_MSA   6 /* HARDWARE: MIPS Msa SIMD instructions supported */\n#endif\n#define PNG_IGNORE_ADLER32 8\n#ifdef PNG_POWERPC_VSX_API_SUPPORTED\n#  define PNG_POWERPC_VSX   10 /* HARDWARE: PowerPC VSX SIMD instructions supported */\n#endif\n#define PNG_OPTION_NEXT  12 /* Next option - numbers must be even */\n\n/* Return values: NOTE: there are four values and 'off' is *not* zero */\n#define PNG_OPTION_UNSET   0 /* Unset - defaults to off */\n#define PNG_OPTION_INVALID 1 /* Option number out of range */\n#define PNG_OPTION_OFF     2\n#define PNG_OPTION_ON      3\n\nPNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option,\n   int onoff));\n#endif /* SET_OPTION */\n\n/*******************************************************************************\n *  END OF HARDWARE AND SOFTWARE OPTIONS\n ******************************************************************************/\n\n/* Maintainer: Put new public prototypes here ^, in libpng.3, in project\n * defs, and in scripts/symbols.def.\n */\n\n/* The last ordinal number (this is the *last* one already used; the next\n * one to use is one more than this.)\n */\n#ifdef PNG_EXPORT_LAST_ORDINAL\n  PNG_EXPORT_LAST_ORDINAL(249);\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* PNG_VERSION_INFO_ONLY */\n/* Do not put anything past this line */\n#endif /* PNG_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngconf.h",
    "content": "\n/* pngconf.h - machine-configurable file for libpng\n *\n * libpng version 1.6.37\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * Any machine specific code is near the front of this file, so if you\n * are configuring libpng for a machine, you may want to read the section\n * starting here down to where it starts to typedef png_color, png_text,\n * and png_info.\n */\n\n#ifdef _MSC_VER\n// Disable the following warnings for Visual Studio\n// This is a warning you get from visual studio 2005 about things in the standard C++\n// library being \"deprecated.\"  I checked the C++ standard and it doesn't say jack \n// about any of them (I checked the searchable PDF).   So this warning is total Bunk.\n#pragma warning(disable : 4996)\n#endif\n\n\n#ifndef PNGCONF_H\n#define PNGCONF_H\n\n#ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */\n\n/* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 (\"ISOC90\") compliant C\n * compiler for correct compilation.  The following header files are required by\n * the standard.  If your compiler doesn't provide these header files, or they\n * do not match the standard, you will need to provide/improve them.\n */\n#include <limits.h>\n#include <stddef.h>\n\n/* Library header files.  These header files are all defined by ISOC90; libpng\n * expects conformant implementations, however, an ISOC90 conformant system need\n * not provide these header files if the functionality cannot be implemented.\n * In this case it will be necessary to disable the relevant parts of libpng in\n * the build of pnglibconf.h.\n *\n * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not\n * include this unnecessary header file.\n */\n\n#ifdef PNG_STDIO_SUPPORTED\n   /* Required for the definition of FILE: */\n#  include <stdio.h>\n#endif\n\n#ifdef PNG_SETJMP_SUPPORTED\n   /* Required for the definition of jmp_buf and the declaration of longjmp: */\n#  include <setjmp.h>\n#endif\n\n#ifdef PNG_CONVERT_tIME_SUPPORTED\n   /* Required for struct tm: */\n#  include <time.h>\n#endif\n\n#endif /* PNG_BUILDING_SYMBOL_TABLE */\n\n/* Prior to 1.6.0, it was possible to turn off 'const' in declarations,\n * using PNG_NO_CONST.  This is no longer supported.\n */\n#define PNG_CONST const /* backward compatibility only */\n\n/* This controls optimization of the reading of 16-bit and 32-bit\n * values from PNG files.  It can be set on a per-app-file basis: it\n * just changes whether a macro is used when the function is called.\n * The library builder sets the default; if read functions are not\n * built into the library the macro implementation is forced on.\n */\n#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED\n#  define PNG_USE_READ_MACROS\n#endif\n#if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS)\n#  if PNG_DEFAULT_READ_MACROS\n#    define PNG_USE_READ_MACROS\n#  endif\n#endif\n\n/* COMPILER SPECIFIC OPTIONS.\n *\n * These options are provided so that a variety of difficult compilers\n * can be used.  Some are fixed at build time (e.g. PNG_API_RULE\n * below) but still have compiler specific implementations, others\n * may be changed on a per-file basis when compiling against libpng.\n */\n\n/* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect\n * against legacy (pre ISOC90) compilers that did not understand function\n * prototypes.  It is not required for modern C compilers.\n */\n#ifndef PNGARG\n#  define PNGARG(arglist) arglist\n#endif\n\n/* Function calling conventions.\n * =============================\n * Normally it is not necessary to specify to the compiler how to call\n * a function - it just does it - however on x86 systems derived from\n * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems\n * and some others) there are multiple ways to call a function and the\n * default can be changed on the compiler command line.  For this reason\n * libpng specifies the calling convention of every exported function and\n * every function called via a user supplied function pointer.  This is\n * done in this file by defining the following macros:\n *\n * PNGAPI    Calling convention for exported functions.\n * PNGCBAPI  Calling convention for user provided (callback) functions.\n * PNGCAPI   Calling convention used by the ANSI-C library (required\n *           for longjmp callbacks and sometimes used internally to\n *           specify the calling convention for zlib).\n *\n * These macros should never be overridden.  If it is necessary to\n * change calling convention in a private build this can be done\n * by setting PNG_API_RULE (which defaults to 0) to one of the values\n * below to select the correct 'API' variants.\n *\n * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout.\n *                This is correct in every known environment.\n * PNG_API_RULE=1 Use the operating system convention for PNGAPI and\n *                the 'C' calling convention (from PNGCAPI) for\n *                callbacks (PNGCBAPI).  This is no longer required\n *                in any known environment - if it has to be used\n *                please post an explanation of the problem to the\n *                libpng mailing list.\n *\n * These cases only differ if the operating system does not use the C\n * calling convention, at present this just means the above cases\n * (x86 DOS/Windows systems) and, even then, this does not apply to\n * Cygwin running on those systems.\n *\n * Note that the value must be defined in pnglibconf.h so that what\n * the application uses to call the library matches the conventions\n * set when building the library.\n */\n\n/* Symbol export\n * =============\n * When building a shared library it is almost always necessary to tell\n * the compiler which symbols to export.  The png.h macro 'PNG_EXPORT'\n * is used to mark the symbols.  On some systems these symbols can be\n * extracted at link time and need no special processing by the compiler,\n * on other systems the symbols are flagged by the compiler and just\n * the declaration requires a special tag applied (unfortunately) in a\n * compiler dependent way.  Some systems can do either.\n *\n * A small number of older systems also require a symbol from a DLL to\n * be flagged to the program that calls it.  This is a problem because\n * we do not know in the header file included by application code that\n * the symbol will come from a shared library, as opposed to a statically\n * linked one.  For this reason the application must tell us by setting\n * the magic flag PNG_USE_DLL to turn on the special processing before\n * it includes png.h.\n *\n * Four additional macros are used to make this happen:\n *\n * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from\n *            the build or imported if PNG_USE_DLL is set - compiler\n *            and system specific.\n *\n * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to\n *                       'type', compiler specific.\n *\n * PNG_DLL_EXPORT Set to the magic to use during a libpng build to\n *                make a symbol exported from the DLL.  Not used in the\n *                public header files; see pngpriv.h for how it is used\n *                in the libpng build.\n *\n * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come\n *                from a DLL - used to define PNG_IMPEXP when\n *                PNG_USE_DLL is set.\n */\n\n/* System specific discovery.\n * ==========================\n * This code is used at build time to find PNG_IMPEXP, the API settings\n * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL\n * import processing is possible.  On Windows systems it also sets\n * compiler-specific macros to the values required to change the calling\n * conventions of the various functions.\n */\n#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\\\n    defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)\n  /* Windows system (DOS doesn't support DLLs).  Includes builds under Cygwin or\n   * MinGW on any architecture currently supported by Windows.  Also includes\n   * Watcom builds but these need special treatment because they are not\n   * compatible with GCC or Visual C because of different calling conventions.\n   */\n#  if PNG_API_RULE == 2\n   /* If this line results in an error, either because __watcall is not\n    * understood or because of a redefine just below you cannot use *this*\n    * build of the library with the compiler you are using.  *This* build was\n    * build using Watcom and applications must also be built using Watcom!\n    */\n#    define PNGCAPI __watcall\n#  endif\n\n#  if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800))\n#    define PNGCAPI __cdecl\n#    if PNG_API_RULE == 1\n   /* If this line results in an error __stdcall is not understood and\n    * PNG_API_RULE should not have been set to '1'.\n    */\n#      define PNGAPI __stdcall\n#    endif\n#  else\n   /* An older compiler, or one not detected (erroneously) above,\n    * if necessary override on the command line to get the correct\n    * variants for the compiler.\n    */\n#    ifndef PNGCAPI\n#      define PNGCAPI _cdecl\n#    endif\n#    if PNG_API_RULE == 1 && !defined(PNGAPI)\n#      define PNGAPI _stdcall\n#    endif\n#  endif /* compiler/api */\n\n  /* NOTE: PNGCBAPI always defaults to PNGCAPI. */\n\n#  if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD)\n#     error \"PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed\"\n#  endif\n\n#  if (defined(_MSC_VER) && _MSC_VER < 800) ||\\\n      (defined(__BORLANDC__) && __BORLANDC__ < 0x500)\n   /* older Borland and MSC\n    * compilers used '__export' and required this to be after\n    * the type.\n    */\n#    ifndef PNG_EXPORT_TYPE\n#      define PNG_EXPORT_TYPE(type) type PNG_IMPEXP\n#    endif\n#    define PNG_DLL_EXPORT __export\n#  else /* newer compiler */\n#    define PNG_DLL_EXPORT __declspec(dllexport)\n#    ifndef PNG_DLL_IMPORT\n#      define PNG_DLL_IMPORT __declspec(dllimport)\n#    endif\n#  endif /* compiler */\n\n#else /* !Windows */\n#  if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)\n#    define PNGAPI _System\n#  else /* !Windows/x86 && !OS/2 */\n   /* Use the defaults, or define PNG*API on the command line (but\n    * this will have to be done for every compile!)\n    */\n#  endif /* other system, !OS/2 */\n#endif /* !Windows/x86 */\n\n/* Now do all the defaulting . */\n#ifndef PNGCAPI\n#  define PNGCAPI\n#endif\n#ifndef PNGCBAPI\n#  define PNGCBAPI PNGCAPI\n#endif\n#ifndef PNGAPI\n#  define PNGAPI PNGCAPI\n#endif\n\n/* PNG_IMPEXP may be set on the compilation system command line or (if not set)\n * then in an internal header file when building the library, otherwise (when\n * using the library) it is set here.\n */\n#ifndef PNG_IMPEXP\n#  if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT)\n   /* This forces use of a DLL, disallowing static linking */\n#    define PNG_IMPEXP PNG_DLL_IMPORT\n#  endif\n\n#  ifndef PNG_IMPEXP\n#    define PNG_IMPEXP\n#  endif\n#endif\n\n/* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat\n * 'attributes' as a storage class - the attributes go at the start of the\n * function definition, and attributes are always appended regardless of the\n * compiler.  This considerably simplifies these macros but may cause problems\n * if any compilers both need function attributes and fail to handle them as\n * a storage class (this is unlikely.)\n */\n#ifndef PNG_FUNCTION\n#  define PNG_FUNCTION(type, name, args, attributes) attributes type name args\n#endif\n\n#ifndef PNG_EXPORT_TYPE\n#  define PNG_EXPORT_TYPE(type) PNG_IMPEXP type\n#endif\n\n   /* The ordinal value is only relevant when preprocessing png.h for symbol\n    * table entries, so we discard it here.  See the .dfn files in the\n    * scripts directory.\n    */\n\n#ifndef PNG_EXPORTA\n#  define PNG_EXPORTA(ordinal, type, name, args, attributes) \\\n      PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \\\n      PNG_LINKAGE_API attributes)\n#endif\n\n/* ANSI-C (C90) does not permit a macro to be invoked with an empty argument,\n * so make something non-empty to satisfy the requirement:\n */\n#define PNG_EMPTY /*empty list*/\n\n#define PNG_EXPORT(ordinal, type, name, args) \\\n   PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY)\n\n/* Use PNG_REMOVED to comment out a removed interface. */\n#ifndef PNG_REMOVED\n#  define PNG_REMOVED(ordinal, type, name, args, attributes)\n#endif\n\n#ifndef PNG_CALLBACK\n#  define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args)\n#endif\n\n/* Support for compiler specific function attributes.  These are used\n * so that where compiler support is available incorrect use of API\n * functions in png.h will generate compiler warnings.\n *\n * Added at libpng-1.2.41.\n */\n\n#ifndef PNG_NO_PEDANTIC_WARNINGS\n#  ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED\n#    define PNG_PEDANTIC_WARNINGS_SUPPORTED\n#  endif\n#endif\n\n#ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED\n  /* Support for compiler specific function attributes.  These are used\n   * so that where compiler support is available, incorrect use of API\n   * functions in png.h will generate compiler warnings.  Added at libpng\n   * version 1.2.41.  Disabling these removes the warnings but may also produce\n   * less efficient code.\n   */\n#  if defined(__clang__) && defined(__has_attribute)\n   /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */\n#    if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__)\n#      define PNG_USE_RESULT __attribute__((__warn_unused_result__))\n#    endif\n#    if !defined(PNG_NORETURN) && __has_attribute(__noreturn__)\n#      define PNG_NORETURN __attribute__((__noreturn__))\n#    endif\n#    if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__)\n#      define PNG_ALLOCATED __attribute__((__malloc__))\n#    endif\n#    if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__)\n#      define PNG_DEPRECATED __attribute__((__deprecated__))\n#    endif\n#    if !defined(PNG_PRIVATE)\n#      ifdef __has_extension\n#        if __has_extension(attribute_unavailable_with_message)\n#          define PNG_PRIVATE __attribute__((__unavailable__(\\\n             \"This function is not exported by libpng.\")))\n#        endif\n#      endif\n#    endif\n#    ifndef PNG_RESTRICT\n#      define PNG_RESTRICT __restrict\n#    endif\n\n#  elif defined(__GNUC__)\n#    ifndef PNG_USE_RESULT\n#      define PNG_USE_RESULT __attribute__((__warn_unused_result__))\n#    endif\n#    ifndef PNG_NORETURN\n#      define PNG_NORETURN   __attribute__((__noreturn__))\n#    endif\n#    if __GNUC__ >= 3\n#      ifndef PNG_ALLOCATED\n#        define PNG_ALLOCATED  __attribute__((__malloc__))\n#      endif\n#      ifndef PNG_DEPRECATED\n#        define PNG_DEPRECATED __attribute__((__deprecated__))\n#      endif\n#      ifndef PNG_PRIVATE\n#        if 0 /* Doesn't work so we use deprecated instead*/\n#          define PNG_PRIVATE \\\n            __attribute__((warning(\"This function is not exported by libpng.\")))\n#        else\n#          define PNG_PRIVATE \\\n            __attribute__((__deprecated__))\n#        endif\n#      endif\n#      if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1))\n#        ifndef PNG_RESTRICT\n#          define PNG_RESTRICT __restrict\n#        endif\n#      endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */\n#    endif /* __GNUC__ >= 3 */\n\n#  elif defined(_MSC_VER)  && (_MSC_VER >= 1300)\n#    ifndef PNG_USE_RESULT\n#      define PNG_USE_RESULT /* not supported */\n#    endif\n#    ifndef PNG_NORETURN\n#      define PNG_NORETURN   __declspec(noreturn)\n#    endif\n#    ifndef PNG_ALLOCATED\n#      if (_MSC_VER >= 1400)\n#        define PNG_ALLOCATED __declspec(restrict)\n#      endif\n#    endif\n#    ifndef PNG_DEPRECATED\n#      define PNG_DEPRECATED __declspec(deprecated)\n#    endif\n#    ifndef PNG_PRIVATE\n#      define PNG_PRIVATE __declspec(deprecated)\n#    endif\n#    ifndef PNG_RESTRICT\n#      if (_MSC_VER >= 1400)\n#        define PNG_RESTRICT __restrict\n#      endif\n#    endif\n\n#  elif defined(__WATCOMC__)\n#    ifndef PNG_RESTRICT\n#      define PNG_RESTRICT __restrict\n#    endif\n#  endif\n#endif /* PNG_PEDANTIC_WARNINGS */\n\n#ifndef PNG_DEPRECATED\n#  define PNG_DEPRECATED  /* Use of this function is deprecated */\n#endif\n#ifndef PNG_USE_RESULT\n#  define PNG_USE_RESULT  /* The result of this function must be checked */\n#endif\n#ifndef PNG_NORETURN\n#  define PNG_NORETURN    /* This function does not return */\n#endif\n#ifndef PNG_ALLOCATED\n#  define PNG_ALLOCATED   /* The result of the function is new memory */\n#endif\n#ifndef PNG_PRIVATE\n#  define PNG_PRIVATE     /* This is a private libpng function */\n#endif\n#ifndef PNG_RESTRICT\n#  define PNG_RESTRICT    /* The C99 \"restrict\" feature */\n#endif\n\n#ifndef PNG_FP_EXPORT     /* A floating point API. */\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\n#     define PNG_FP_EXPORT(ordinal, type, name, args)\\\n         PNG_EXPORT(ordinal, type, name, args);\n#  else                   /* No floating point APIs */\n#     define PNG_FP_EXPORT(ordinal, type, name, args)\n#  endif\n#endif\n#ifndef PNG_FIXED_EXPORT  /* A fixed point API. */\n#  ifdef PNG_FIXED_POINT_SUPPORTED\n#     define PNG_FIXED_EXPORT(ordinal, type, name, args)\\\n         PNG_EXPORT(ordinal, type, name, args);\n#  else                   /* No fixed point APIs */\n#     define PNG_FIXED_EXPORT(ordinal, type, name, args)\n#  endif\n#endif\n\n#ifndef PNG_BUILDING_SYMBOL_TABLE\n/* Some typedefs to get us started.  These should be safe on most of the common\n * platforms.\n *\n * png_uint_32 and png_int_32 may, currently, be larger than required to hold a\n * 32-bit value however this is not normally advisable.\n *\n * png_uint_16 and png_int_16 should always be two bytes in size - this is\n * verified at library build time.\n *\n * png_byte must always be one byte in size.\n *\n * The checks below use constants from limits.h, as defined by the ISOC90\n * standard.\n */\n#if CHAR_BIT == 8 && UCHAR_MAX == 255\n   typedef unsigned char png_byte;\n#else\n#  error \"libpng requires 8-bit bytes\"\n#endif\n\n#if INT_MIN == -32768 && INT_MAX == 32767\n   typedef int png_int_16;\n#elif SHRT_MIN == -32768 && SHRT_MAX == 32767\n   typedef short png_int_16;\n#else\n#  error \"libpng requires a signed 16-bit type\"\n#endif\n\n#if UINT_MAX == 65535\n   typedef unsigned int png_uint_16;\n#elif USHRT_MAX == 65535\n   typedef unsigned short png_uint_16;\n#else\n#  error \"libpng requires an unsigned 16-bit type\"\n#endif\n\n#if INT_MIN < -2147483646 && INT_MAX > 2147483646\n   typedef int png_int_32;\n#elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646\n   typedef long int png_int_32;\n#else\n#  error \"libpng requires a signed 32-bit (or more) type\"\n#endif\n\n#if UINT_MAX > 4294967294U\n   typedef unsigned int png_uint_32;\n#elif ULONG_MAX > 4294967294U\n   typedef unsigned long int png_uint_32;\n#else\n#  error \"libpng requires an unsigned 32-bit (or more) type\"\n#endif\n\n/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t.\n * From 1.6.0 onwards, an ISO C90 compiler, as well as a standard-compliant\n * behavior of sizeof and ptrdiff_t are required.\n * The legacy typedefs are provided here for backwards compatibility.\n */\ntypedef size_t png_size_t;\ntypedef ptrdiff_t png_ptrdiff_t;\n\n/* libpng needs to know the maximum value of 'size_t' and this controls the\n * definition of png_alloc_size_t, below.  This maximum value of size_t limits\n * but does not control the maximum allocations the library makes - there is\n * direct application control of this through png_set_user_limits().\n */\n#ifndef PNG_SMALL_SIZE_T\n   /* Compiler specific tests for systems where size_t is known to be less than\n    * 32 bits (some of these systems may no longer work because of the lack of\n    * 'far' support; see above.)\n    */\n#  if (defined(__TURBOC__) && !defined(__FLAT__)) ||\\\n   (defined(_MSC_VER) && defined(MAXSEG_64K))\n#     define PNG_SMALL_SIZE_T\n#  endif\n#endif\n\n/* png_alloc_size_t is guaranteed to be no smaller than size_t, and no smaller\n * than png_uint_32.  Casts from size_t or png_uint_32 to png_alloc_size_t are\n * not necessary; in fact, it is recommended not to use them at all, so that\n * the compiler can complain when something turns out to be problematic.\n *\n * Casts in the other direction (from png_alloc_size_t to size_t or\n * png_uint_32) should be explicitly applied; however, we do not expect to\n * encounter practical situations that require such conversions.\n *\n * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than\n * 4294967295 - i.e. less than the maximum value of png_uint_32.\n */\n#ifdef PNG_SMALL_SIZE_T\n   typedef png_uint_32 png_alloc_size_t;\n#else\n   typedef size_t png_alloc_size_t;\n#endif\n\n/* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler\n * implementations of Intel CPU specific support of user-mode segmented address\n * spaces, where 16-bit pointers address more than 65536 bytes of memory using\n * separate 'segment' registers.  The implementation requires two different\n * types of pointer (only one of which includes the segment value.)\n *\n * If required this support is available in version 1.2 of libpng and may be\n * available in versions through 1.5, although the correctness of the code has\n * not been verified recently.\n */\n\n/* Typedef for floating-point numbers that are converted to fixed-point with a\n * multiple of 100,000, e.g., gamma\n */\ntypedef png_int_32 png_fixed_point;\n\n/* Add typedefs for pointers */\ntypedef void                  * png_voidp;\ntypedef const void            * png_const_voidp;\ntypedef png_byte              * png_bytep;\ntypedef const png_byte        * png_const_bytep;\ntypedef png_uint_32           * png_uint_32p;\ntypedef const png_uint_32     * png_const_uint_32p;\ntypedef png_int_32            * png_int_32p;\ntypedef const png_int_32      * png_const_int_32p;\ntypedef png_uint_16           * png_uint_16p;\ntypedef const png_uint_16     * png_const_uint_16p;\ntypedef png_int_16            * png_int_16p;\ntypedef const png_int_16      * png_const_int_16p;\ntypedef char                  * png_charp;\ntypedef const char            * png_const_charp;\ntypedef png_fixed_point       * png_fixed_point_p;\ntypedef const png_fixed_point * png_const_fixed_point_p;\ntypedef size_t                * png_size_tp;\ntypedef const size_t          * png_const_size_tp;\n\n#ifdef PNG_STDIO_SUPPORTED\ntypedef FILE            * png_FILE_p;\n#endif\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\ntypedef double       * png_doublep;\ntypedef const double * png_const_doublep;\n#endif\n\n/* Pointers to pointers; i.e. arrays */\ntypedef png_byte        * * png_bytepp;\ntypedef png_uint_32     * * png_uint_32pp;\ntypedef png_int_32      * * png_int_32pp;\ntypedef png_uint_16     * * png_uint_16pp;\ntypedef png_int_16      * * png_int_16pp;\ntypedef const char      * * png_const_charpp;\ntypedef char            * * png_charpp;\ntypedef png_fixed_point * * png_fixed_point_pp;\n#ifdef PNG_FLOATING_POINT_SUPPORTED\ntypedef double          * * png_doublepp;\n#endif\n\n/* Pointers to pointers to pointers; i.e., pointer to array */\ntypedef char            * * * png_charppp;\n\n#endif /* PNG_BUILDING_SYMBOL_TABLE */\n\n#endif /* PNGCONF_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngdebug.h",
    "content": "\n/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n/* Define PNG_DEBUG at compile time for debugging information.  Higher\n * numbers for PNG_DEBUG mean more debugging information.  This has\n * only been added since version 0.95 so it is not implemented throughout\n * libpng yet, but more support will be added as needed.\n *\n * png_debug[1-2]?(level, message ,arg{0-2})\n *   Expands to a statement (either a simple expression or a compound\n *   do..while(0) statement) that outputs a message with parameter\n *   substitution if PNG_DEBUG is defined to 2 or more.  If PNG_DEBUG\n *   is undefined, 0 or 1 every png_debug expands to a simple expression\n *   (actually ((void)0)).\n *\n *   level: level of detail of message, starting at 0.  A level 'n'\n *          message is preceded by 'n' 3-space indentations (not implemented\n *          on Microsoft compilers unless PNG_DEBUG_FILE is also\n *          defined, to allow debug DLL compilation with no standard IO).\n *   message: a printf(3) style text string.  A trailing '\\n' is added\n *            to the message.\n *   arg: 0 to 2 arguments for printf(3) style substitution in message.\n */\n#ifndef PNGDEBUG_H\n#define PNGDEBUG_H\n/* These settings control the formatting of messages in png.c and pngerror.c */\n/* Moved to pngdebug.h at 1.5.0 */\n#  ifndef PNG_LITERAL_SHARP\n#    define PNG_LITERAL_SHARP 0x23\n#  endif\n#  ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET\n#    define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b\n#  endif\n#  ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET\n#    define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d\n#  endif\n#  ifndef PNG_STRING_NEWLINE\n#    define PNG_STRING_NEWLINE \"\\n\"\n#  endif\n\n#ifdef PNG_DEBUG\n#  if (PNG_DEBUG > 0)\n#    if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)\n#      include <crtdbg.h>\n#      if (PNG_DEBUG > 1)\n#        ifndef _DEBUG\n#          define _DEBUG\n#        endif\n#        ifndef png_debug\n#          define png_debug(l,m)  _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE)\n#        endif\n#        ifndef png_debug1\n#          define png_debug1(l,m,p1)  _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1)\n#        endif\n#        ifndef png_debug2\n#          define png_debug2(l,m,p1,p2) \\\n             _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2)\n#        endif\n#      endif\n#    else /* PNG_DEBUG_FILE || !_MSC_VER */\n#      ifndef PNG_STDIO_SUPPORTED\n#        include <stdio.h> /* not included yet */\n#      endif\n#      ifndef PNG_DEBUG_FILE\n#        define PNG_DEBUG_FILE stderr\n#      endif /* PNG_DEBUG_FILE */\n\n#      if (PNG_DEBUG > 1)\n#        ifdef __STDC__\n#          ifndef png_debug\n#            define png_debug(l,m) \\\n       do { \\\n       int num_tabs=l; \\\n       fprintf(PNG_DEBUG_FILE,\"%s\" m PNG_STRING_NEWLINE,(num_tabs==1 ? \"   \" : \\\n         (num_tabs==2 ? \"      \" : (num_tabs>2 ? \"         \" : \"\")))); \\\n       } while (0)\n#          endif\n#          ifndef png_debug1\n#            define png_debug1(l,m,p1) \\\n       do { \\\n       int num_tabs=l; \\\n       fprintf(PNG_DEBUG_FILE,\"%s\" m PNG_STRING_NEWLINE,(num_tabs==1 ? \"   \" : \\\n         (num_tabs==2 ? \"      \" : (num_tabs>2 ? \"         \" : \"\"))),p1); \\\n       } while (0)\n#          endif\n#          ifndef png_debug2\n#            define png_debug2(l,m,p1,p2) \\\n       do { \\\n       int num_tabs=l; \\\n       fprintf(PNG_DEBUG_FILE,\"%s\" m PNG_STRING_NEWLINE,(num_tabs==1 ? \"   \" : \\\n         (num_tabs==2 ? \"      \" : (num_tabs>2 ? \"         \" : \"\"))),p1,p2);\\\n       } while (0)\n#          endif\n#        else /* __STDC __ */\n#          ifndef png_debug\n#            define png_debug(l,m) \\\n       do { \\\n       int num_tabs=l; \\\n       char format[256]; \\\n       snprintf(format,256,\"%s%s%s\",(num_tabs==1 ? \"\\t\" : \\\n         (num_tabs==2 ? \"\\t\\t\":(num_tabs>2 ? \"\\t\\t\\t\":\"\"))), \\\n         m,PNG_STRING_NEWLINE); \\\n       fprintf(PNG_DEBUG_FILE,format); \\\n       } while (0)\n#          endif\n#          ifndef png_debug1\n#            define png_debug1(l,m,p1) \\\n       do { \\\n       int num_tabs=l; \\\n       char format[256]; \\\n       snprintf(format,256,\"%s%s%s\",(num_tabs==1 ? \"\\t\" : \\\n         (num_tabs==2 ? \"\\t\\t\":(num_tabs>2 ? \"\\t\\t\\t\":\"\"))), \\\n         m,PNG_STRING_NEWLINE); \\\n       fprintf(PNG_DEBUG_FILE,format,p1); \\\n       } while (0)\n#          endif\n#          ifndef png_debug2\n#            define png_debug2(l,m,p1,p2) \\\n       do { \\\n       int num_tabs=l; \\\n       char format[256]; \\\n       snprintf(format,256,\"%s%s%s\",(num_tabs==1 ? \"\\t\" : \\\n         (num_tabs==2 ? \"\\t\\t\":(num_tabs>2 ? \"\\t\\t\\t\":\"\"))), \\\n         m,PNG_STRING_NEWLINE); \\\n       fprintf(PNG_DEBUG_FILE,format,p1,p2); \\\n       } while (0)\n#          endif\n#        endif /* __STDC __ */\n#      endif /* (PNG_DEBUG > 1) */\n\n#    endif /* _MSC_VER */\n#  endif /* (PNG_DEBUG > 0) */\n#endif /* PNG_DEBUG */\n#ifndef png_debug\n#  define png_debug(l, m) ((void)0)\n#endif\n#ifndef png_debug1\n#  define png_debug1(l, m, p1) ((void)0)\n#endif\n#ifndef png_debug2\n#  define png_debug2(l, m, p1, p2) ((void)0)\n#endif\n#endif /* PNGDEBUG_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngerror.c",
    "content": "\n/* pngerror.c - stub functions for i/o and memory allocation\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file provides a location for all error handling.  Users who\n * need special error handling are expected to write replacement functions\n * and use png_set_error_fn() to use those functions.  See the instructions\n * at each function.\n */\n\n#include \"pngpriv.h\"\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n\nstatic PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,\n    png_const_charp error_message)),PNG_NORETURN);\n\n#ifdef PNG_WARNINGS_SUPPORTED\nstatic void /* PRIVATE */\npng_default_warning PNGARG((png_const_structrp png_ptr,\n    png_const_charp warning_message));\n#endif /* WARNINGS */\n\n/* This function is called whenever there is a fatal error.  This function\n * should not be changed.  If there is a need to handle errors differently,\n * you should supply a replacement error function and use png_set_error_fn()\n * to replace the error function at run-time.\n */\n#ifdef PNG_ERROR_TEXT_SUPPORTED\nPNG_FUNCTION(void,PNGAPI\npng_error,(png_const_structrp png_ptr, png_const_charp error_message),\n    PNG_NORETURN)\n{\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\n   char msg[16];\n   if (png_ptr != NULL)\n   {\n      if ((png_ptr->flags &\n         (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)\n      {\n         if (*error_message == PNG_LITERAL_SHARP)\n         {\n            /* Strip \"#nnnn \" from beginning of error message. */\n            int offset;\n            for (offset = 1; offset<15; offset++)\n               if (error_message[offset] == ' ')\n                  break;\n\n            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)\n            {\n               int i;\n               for (i = 0; i < offset - 1; i++)\n                  msg[i] = error_message[i + 1];\n               msg[i - 1] = '\\0';\n               error_message = msg;\n            }\n\n            else\n               error_message += offset;\n         }\n\n         else\n         {\n            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)\n            {\n               msg[0] = '0';\n               msg[1] = '\\0';\n               error_message = msg;\n            }\n         }\n      }\n   }\n#endif\n   if (png_ptr != NULL && png_ptr->error_fn != NULL)\n      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),\n          error_message);\n\n   /* If the custom handler doesn't exist, or if it returns,\n      use the default handler, which will not return. */\n   png_default_error(png_ptr, error_message);\n}\n#else\nPNG_FUNCTION(void,PNGAPI\npng_err,(png_const_structrp png_ptr),PNG_NORETURN)\n{\n   /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed\n    * erroneously as '\\0', instead of the empty string \"\".  This was\n    * apparently an error, introduced in libpng-1.2.20, and png_default_error\n    * will crash in this case.\n    */\n   if (png_ptr != NULL && png_ptr->error_fn != NULL)\n      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), \"\");\n\n   /* If the custom handler doesn't exist, or if it returns,\n      use the default handler, which will not return. */\n   png_default_error(png_ptr, \"\");\n}\n#endif /* ERROR_TEXT */\n\n/* Utility to safely appends strings to a buffer.  This never errors out so\n * error checking is not required in the caller.\n */\nsize_t\npng_safecat(png_charp buffer, size_t bufsize, size_t pos,\n    png_const_charp string)\n{\n   if (buffer != NULL && pos < bufsize)\n   {\n      if (string != NULL)\n         while (*string != '\\0' && pos < bufsize-1)\n           buffer[pos++] = *string++;\n\n      buffer[pos] = '\\0';\n   }\n\n   return pos;\n}\n\n#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)\n/* Utility to dump an unsigned value into a buffer, given a start pointer and\n * and end pointer (which should point just *beyond* the end of the buffer!)\n * Returns the pointer to the start of the formatted string.\n */\npng_charp\npng_format_number(png_const_charp start, png_charp end, int format,\n    png_alloc_size_t number)\n{\n   int count = 0;    /* number of digits output */\n   int mincount = 1; /* minimum number required */\n   int output = 0;   /* digit output (for the fixed point format) */\n\n   *--end = '\\0';\n\n   /* This is written so that the loop always runs at least once, even with\n    * number zero.\n    */\n   while (end > start && (number != 0 || count < mincount))\n   {\n\n      static const char digits[] = \"0123456789ABCDEF\";\n\n      switch (format)\n      {\n         case PNG_NUMBER_FORMAT_fixed:\n            /* Needs five digits (the fraction) */\n            mincount = 5;\n            if (output != 0 || number % 10 != 0)\n            {\n               *--end = digits[number % 10];\n               output = 1;\n            }\n            number /= 10;\n            break;\n\n         case PNG_NUMBER_FORMAT_02u:\n            /* Expects at least 2 digits. */\n            mincount = 2;\n            /* FALLTHROUGH */\n\n         case PNG_NUMBER_FORMAT_u:\n            *--end = digits[number % 10];\n            number /= 10;\n            break;\n\n         case PNG_NUMBER_FORMAT_02x:\n            /* This format expects at least two digits */\n            mincount = 2;\n            /* FALLTHROUGH */\n\n         case PNG_NUMBER_FORMAT_x:\n            *--end = digits[number & 0xf];\n            number >>= 4;\n            break;\n\n         default: /* an error */\n            number = 0;\n            break;\n      }\n\n      /* Keep track of the number of digits added */\n      ++count;\n\n      /* Float a fixed number here: */\n      if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start))\n      {\n         /* End of the fraction, but maybe nothing was output?  In that case\n          * drop the decimal point.  If the number is a true zero handle that\n          * here.\n          */\n         if (output != 0)\n            *--end = '.';\n         else if (number == 0) /* and !output */\n            *--end = '0';\n      }\n   }\n\n   return end;\n}\n#endif\n\n#ifdef PNG_WARNINGS_SUPPORTED\n/* This function is called whenever there is a non-fatal error.  This function\n * should not be changed.  If there is a need to handle warnings differently,\n * you should supply a replacement warning function and use\n * png_set_error_fn() to replace the warning function at run-time.\n */\nvoid PNGAPI\npng_warning(png_const_structrp png_ptr, png_const_charp warning_message)\n{\n   int offset = 0;\n   if (png_ptr != NULL)\n   {\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\n   if ((png_ptr->flags &\n       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)\n#endif\n      {\n         if (*warning_message == PNG_LITERAL_SHARP)\n         {\n            for (offset = 1; offset < 15; offset++)\n               if (warning_message[offset] == ' ')\n                  break;\n         }\n      }\n   }\n   if (png_ptr != NULL && png_ptr->warning_fn != NULL)\n      (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),\n          warning_message + offset);\n   else\n      png_default_warning(png_ptr, warning_message + offset);\n}\n\n/* These functions support 'formatted' warning messages with up to\n * PNG_WARNING_PARAMETER_COUNT parameters.  In the format string the parameter\n * is introduced by @<number>, where 'number' starts at 1.  This follows the\n * standard established by X/Open for internationalizable error messages.\n */\nvoid\npng_warning_parameter(png_warning_parameters p, int number,\n    png_const_charp string)\n{\n   if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)\n      (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);\n}\n\nvoid\npng_warning_parameter_unsigned(png_warning_parameters p, int number, int format,\n    png_alloc_size_t value)\n{\n   char buffer[PNG_NUMBER_BUFFER_SIZE];\n   png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));\n}\n\nvoid\npng_warning_parameter_signed(png_warning_parameters p, int number, int format,\n    png_int_32 value)\n{\n   png_alloc_size_t u;\n   png_charp str;\n   char buffer[PNG_NUMBER_BUFFER_SIZE];\n\n   /* Avoid overflow by doing the negate in a png_alloc_size_t: */\n   u = (png_alloc_size_t)value;\n   if (value < 0)\n      u = ~u + 1;\n\n   str = PNG_FORMAT_NUMBER(buffer, format, u);\n\n   if (value < 0 && str > buffer)\n      *--str = '-';\n\n   png_warning_parameter(p, number, str);\n}\n\nvoid\npng_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,\n    png_const_charp message)\n{\n   /* The internal buffer is just 192 bytes - enough for all our messages,\n    * overflow doesn't happen because this code checks!  If someone figures\n    * out how to send us a message longer than 192 bytes, all that will\n    * happen is that the message will be truncated appropriately.\n    */\n   size_t i = 0; /* Index in the msg[] buffer: */\n   char msg[192];\n\n   /* Each iteration through the following loop writes at most one character\n    * to msg[i++] then returns here to validate that there is still space for\n    * the trailing '\\0'.  It may (in the case of a parameter) read more than\n    * one character from message[]; it must check for '\\0' and continue to the\n    * test if it finds the end of string.\n    */\n   while (i<(sizeof msg)-1 && *message != '\\0')\n   {\n      /* '@' at end of string is now just printed (previously it was skipped);\n       * it is an error in the calling code to terminate the string with @.\n       */\n      if (p != NULL && *message == '@' && message[1] != '\\0')\n      {\n         int parameter_char = *++message; /* Consume the '@' */\n         static const char valid_parameters[] = \"123456789\";\n         int parameter = 0;\n\n         /* Search for the parameter digit, the index in the string is the\n          * parameter to use.\n          */\n         while (valid_parameters[parameter] != parameter_char &&\n            valid_parameters[parameter] != '\\0')\n            ++parameter;\n\n         /* If the parameter digit is out of range it will just get printed. */\n         if (parameter < PNG_WARNING_PARAMETER_COUNT)\n         {\n            /* Append this parameter */\n            png_const_charp parm = p[parameter];\n            png_const_charp pend = p[parameter] + (sizeof p[parameter]);\n\n            /* No need to copy the trailing '\\0' here, but there is no guarantee\n             * that parm[] has been initialized, so there is no guarantee of a\n             * trailing '\\0':\n             */\n            while (i<(sizeof msg)-1 && *parm != '\\0' && parm < pend)\n               msg[i++] = *parm++;\n\n            /* Consume the parameter digit too: */\n            ++message;\n            continue;\n         }\n\n         /* else not a parameter and there is a character after the @ sign; just\n          * copy that.  This is known not to be '\\0' because of the test above.\n          */\n      }\n\n      /* At this point *message can't be '\\0', even in the bad parameter case\n       * above where there is a lone '@' at the end of the message string.\n       */\n      msg[i++] = *message++;\n   }\n\n   /* i is always less than (sizeof msg), so: */\n   msg[i] = '\\0';\n\n   /* And this is the formatted message. It may be larger than\n    * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these\n    * are not (currently) formatted.\n    */\n   png_warning(png_ptr, msg);\n}\n#endif /* WARNINGS */\n\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\nvoid PNGAPI\npng_benign_error(png_const_structrp png_ptr, png_const_charp error_message)\n{\n   if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)\n   {\n#     ifdef PNG_READ_SUPPORTED\n         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&\n            png_ptr->chunk_name != 0)\n            png_chunk_warning(png_ptr, error_message);\n         else\n#     endif\n      png_warning(png_ptr, error_message);\n   }\n\n   else\n   {\n#     ifdef PNG_READ_SUPPORTED\n         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&\n            png_ptr->chunk_name != 0)\n            png_chunk_error(png_ptr, error_message);\n         else\n#     endif\n      png_error(png_ptr, error_message);\n   }\n\n#  ifndef PNG_ERROR_TEXT_SUPPORTED\n      PNG_UNUSED(error_message)\n#  endif\n}\n\nvoid /* PRIVATE */\npng_app_warning(png_const_structrp png_ptr, png_const_charp error_message)\n{\n   if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0)\n      png_warning(png_ptr, error_message);\n   else\n      png_error(png_ptr, error_message);\n\n#  ifndef PNG_ERROR_TEXT_SUPPORTED\n      PNG_UNUSED(error_message)\n#  endif\n}\n\nvoid /* PRIVATE */\npng_app_error(png_const_structrp png_ptr, png_const_charp error_message)\n{\n   if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0)\n      png_warning(png_ptr, error_message);\n   else\n      png_error(png_ptr, error_message);\n\n#  ifndef PNG_ERROR_TEXT_SUPPORTED\n      PNG_UNUSED(error_message)\n#  endif\n}\n#endif /* BENIGN_ERRORS */\n\n#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */\n#if defined(PNG_WARNINGS_SUPPORTED) || \\\n   (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED))\n/* These utilities are used internally to build an error message that relates\n * to the current chunk.  The chunk name comes from png_ptr->chunk_name,\n * which is used to prefix the message.  The message is limited in length\n * to 63 bytes. The name characters are output as hex digits wrapped in []\n * if the character is invalid.\n */\n#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))\nstatic const char png_digit[16] = {\n   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',\n   'A', 'B', 'C', 'D', 'E', 'F'\n};\n\nstatic void /* PRIVATE */\npng_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp\n    error_message)\n{\n   png_uint_32 chunk_name = png_ptr->chunk_name;\n   int iout = 0, ishift = 24;\n\n   while (ishift >= 0)\n   {\n      int c = (int)(chunk_name >> ishift) & 0xff;\n\n      ishift -= 8;\n      if (isnonalpha(c) != 0)\n      {\n         buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;\n         buffer[iout++] = png_digit[(c & 0xf0) >> 4];\n         buffer[iout++] = png_digit[c & 0x0f];\n         buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;\n      }\n\n      else\n      {\n         buffer[iout++] = (char)c;\n      }\n   }\n\n   if (error_message == NULL)\n      buffer[iout] = '\\0';\n\n   else\n   {\n      int iin = 0;\n\n      buffer[iout++] = ':';\n      buffer[iout++] = ' ';\n\n      while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\\0')\n         buffer[iout++] = error_message[iin++];\n\n      /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */\n      buffer[iout] = '\\0';\n   }\n}\n#endif /* WARNINGS || ERROR_TEXT */\n\n#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)\nPNG_FUNCTION(void,PNGAPI\npng_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),\n    PNG_NORETURN)\n{\n   char msg[18+PNG_MAX_ERROR_TEXT];\n   if (png_ptr == NULL)\n      png_error(png_ptr, error_message);\n\n   else\n   {\n      png_format_buffer(png_ptr, msg, error_message);\n      png_error(png_ptr, msg);\n   }\n}\n#endif /* READ && ERROR_TEXT */\n\n#ifdef PNG_WARNINGS_SUPPORTED\nvoid PNGAPI\npng_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)\n{\n   char msg[18+PNG_MAX_ERROR_TEXT];\n   if (png_ptr == NULL)\n      png_warning(png_ptr, warning_message);\n\n   else\n   {\n      png_format_buffer(png_ptr, msg, warning_message);\n      png_warning(png_ptr, msg);\n   }\n}\n#endif /* WARNINGS */\n\n#ifdef PNG_READ_SUPPORTED\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\nvoid PNGAPI\npng_chunk_benign_error(png_const_structrp png_ptr, png_const_charp\n    error_message)\n{\n   if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)\n      png_chunk_warning(png_ptr, error_message);\n\n   else\n      png_chunk_error(png_ptr, error_message);\n\n#  ifndef PNG_ERROR_TEXT_SUPPORTED\n      PNG_UNUSED(error_message)\n#  endif\n}\n#endif\n#endif /* READ */\n\nvoid /* PRIVATE */\npng_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)\n{\n#  ifndef PNG_WARNINGS_SUPPORTED\n      PNG_UNUSED(message)\n#  endif\n\n   /* This is always supported, but for just read or just write it\n    * unconditionally does the right thing.\n    */\n#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)\n      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)\n#  endif\n\n#  ifdef PNG_READ_SUPPORTED\n      {\n         if (error < PNG_CHUNK_ERROR)\n            png_chunk_warning(png_ptr, message);\n\n         else\n            png_chunk_benign_error(png_ptr, message);\n      }\n#  endif\n\n#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)\n      else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)\n#  endif\n\n#  ifdef PNG_WRITE_SUPPORTED\n      {\n         if (error < PNG_CHUNK_WRITE_ERROR)\n            png_app_warning(png_ptr, message);\n\n         else\n            png_app_error(png_ptr, message);\n      }\n#  endif\n}\n\n#ifdef PNG_ERROR_TEXT_SUPPORTED\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nPNG_FUNCTION(void,\npng_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)\n{\n#  define fixed_message \"fixed point overflow in \"\n#  define fixed_message_ln ((sizeof fixed_message)-1)\n   unsigned int  iin;\n   char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];\n   memcpy(msg, fixed_message, fixed_message_ln);\n   iin = 0;\n   if (name != NULL)\n      while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)\n      {\n         msg[fixed_message_ln + iin] = name[iin];\n         ++iin;\n      }\n   msg[fixed_message_ln + iin] = 0;\n   png_error(png_ptr, msg);\n}\n#endif\n#endif\n\n#ifdef PNG_SETJMP_SUPPORTED\n/* This API only exists if ANSI-C style error handling is used,\n * otherwise it is necessary for png_default_error to be overridden.\n */\njmp_buf* PNGAPI\npng_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,\n    size_t jmp_buf_size)\n{\n   /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value\n    * and it must not change after that.  Libpng doesn't care how big the\n    * buffer is, just that it doesn't change.\n    *\n    * If the buffer size is no *larger* than the size of jmp_buf when libpng is\n    * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0\n    * semantics that this call will not fail.  If the size is larger, however,\n    * the buffer is allocated and this may fail, causing the function to return\n    * NULL.\n    */\n   if (png_ptr == NULL)\n      return NULL;\n\n   if (png_ptr->jmp_buf_ptr == NULL)\n   {\n      png_ptr->jmp_buf_size = 0; /* not allocated */\n\n      if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))\n         png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;\n\n      else\n      {\n         png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,\n             png_malloc_warn(png_ptr, jmp_buf_size));\n\n         if (png_ptr->jmp_buf_ptr == NULL)\n            return NULL; /* new NULL return on OOM */\n\n         png_ptr->jmp_buf_size = jmp_buf_size;\n      }\n   }\n\n   else /* Already allocated: check the size */\n   {\n      size_t size = png_ptr->jmp_buf_size;\n\n      if (size == 0)\n      {\n         size = (sizeof png_ptr->jmp_buf_local);\n         if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)\n         {\n            /* This is an internal error in libpng: somehow we have been left\n             * with a stack allocated jmp_buf when the application regained\n             * control.  It's always possible to fix this up, but for the moment\n             * this is a png_error because that makes it easy to detect.\n             */\n            png_error(png_ptr, \"Libpng jmp_buf still allocated\");\n            /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */\n         }\n      }\n\n      if (size != jmp_buf_size)\n      {\n         png_warning(png_ptr, \"Application jmp_buf size changed\");\n         return NULL; /* caller will probably crash: no choice here */\n      }\n   }\n\n   /* Finally fill in the function, now we have a satisfactory buffer. It is\n    * valid to change the function on every call.\n    */\n   png_ptr->longjmp_fn = longjmp_fn;\n   return png_ptr->jmp_buf_ptr;\n}\n\nvoid /* PRIVATE */\npng_free_jmpbuf(png_structrp png_ptr)\n{\n   if (png_ptr != NULL)\n   {\n      jmp_buf *jb = png_ptr->jmp_buf_ptr;\n\n      /* A size of 0 is used to indicate a local, stack, allocation of the\n       * pointer; used here and in png.c\n       */\n      if (jb != NULL && png_ptr->jmp_buf_size > 0)\n      {\n\n         /* This stuff is so that a failure to free the error control structure\n          * does not leave libpng in a state with no valid error handling: the\n          * free always succeeds, if there is an error it gets ignored.\n          */\n         if (jb != &png_ptr->jmp_buf_local)\n         {\n            /* Make an internal, libpng, jmp_buf to return here */\n            jmp_buf free_jmp_buf;\n\n            if (!setjmp(free_jmp_buf))\n            {\n               png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */\n               png_ptr->jmp_buf_size = 0; /* stack allocation */\n               png_ptr->longjmp_fn = longjmp;\n               png_free(png_ptr, jb); /* Return to setjmp on error */\n            }\n         }\n      }\n\n      /* *Always* cancel everything out: */\n      png_ptr->jmp_buf_size = 0;\n      png_ptr->jmp_buf_ptr = NULL;\n      png_ptr->longjmp_fn = 0;\n   }\n}\n#endif\n\n/* This is the default error handling function.  Note that replacements for\n * this function MUST NOT RETURN, or the program will likely crash.  This\n * function is used by default, or if the program supplies NULL for the\n * error function pointer in png_set_error_fn().\n */\nstatic PNG_FUNCTION(void /* PRIVATE */,\npng_default_error,(png_const_structrp png_ptr, png_const_charp error_message),\n    PNG_NORETURN)\n{\n#ifdef PNG_CONSOLE_IO_SUPPORTED\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\n   /* Check on NULL only added in 1.5.4 */\n   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)\n   {\n      /* Strip \"#nnnn \" from beginning of error message. */\n      int offset;\n      char error_number[16];\n      for (offset = 0; offset<15; offset++)\n      {\n         error_number[offset] = error_message[offset + 1];\n         if (error_message[offset] == ' ')\n            break;\n      }\n\n      if ((offset > 1) && (offset < 15))\n      {\n         error_number[offset - 1] = '\\0';\n         fprintf(stderr, \"libpng error no. %s: %s\",\n             error_number, error_message + offset + 1);\n         fprintf(stderr, PNG_STRING_NEWLINE);\n      }\n\n      else\n      {\n         fprintf(stderr, \"libpng error: %s, offset=%d\",\n             error_message, offset);\n         fprintf(stderr, PNG_STRING_NEWLINE);\n      }\n   }\n   else\n#endif\n   {\n      fprintf(stderr, \"libpng error: %s\", error_message ? error_message :\n         \"undefined\");\n      fprintf(stderr, PNG_STRING_NEWLINE);\n   }\n#else\n   PNG_UNUSED(error_message) /* Make compiler happy */\n#endif\n   png_longjmp(png_ptr, 1);\n}\n\nPNG_FUNCTION(void,PNGAPI\npng_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)\n{\n#ifdef PNG_SETJMP_SUPPORTED\n   if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&\n       png_ptr->jmp_buf_ptr != NULL)\n      png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(val)\n#endif\n\n   /* If control reaches this point, png_longjmp() must not return. The only\n    * choice is to terminate the whole process (or maybe the thread); to do\n    * this the ANSI-C abort() function is used unless a different method is\n    * implemented by overriding the default configuration setting for\n    * PNG_ABORT().\n    */\n   PNG_ABORT();\n}\n\n#ifdef PNG_WARNINGS_SUPPORTED\n/* This function is called when there is a warning, but the library thinks\n * it can continue anyway.  Replacement functions don't have to do anything\n * here if you don't want them to.  In the default configuration, png_ptr is\n * not used, but it is passed in case it may be useful.\n */\nstatic void /* PRIVATE */\npng_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)\n{\n#ifdef PNG_CONSOLE_IO_SUPPORTED\n#  ifdef PNG_ERROR_NUMBERS_SUPPORTED\n   if (*warning_message == PNG_LITERAL_SHARP)\n   {\n      int offset;\n      char warning_number[16];\n      for (offset = 0; offset < 15; offset++)\n      {\n         warning_number[offset] = warning_message[offset + 1];\n         if (warning_message[offset] == ' ')\n            break;\n      }\n\n      if ((offset > 1) && (offset < 15))\n      {\n         warning_number[offset + 1] = '\\0';\n         fprintf(stderr, \"libpng warning no. %s: %s\",\n             warning_number, warning_message + offset);\n         fprintf(stderr, PNG_STRING_NEWLINE);\n      }\n\n      else\n      {\n         fprintf(stderr, \"libpng warning: %s\",\n             warning_message);\n         fprintf(stderr, PNG_STRING_NEWLINE);\n      }\n   }\n   else\n#  endif\n\n   {\n      fprintf(stderr, \"libpng warning: %s\", warning_message);\n      fprintf(stderr, PNG_STRING_NEWLINE);\n   }\n#else\n   PNG_UNUSED(warning_message) /* Make compiler happy */\n#endif\n   PNG_UNUSED(png_ptr) /* Make compiler happy */\n}\n#endif /* WARNINGS */\n\n/* This function is called when the application wants to use another method\n * of handling errors and warnings.  Note that the error function MUST NOT\n * return to the calling routine or serious problems will occur.  The return\n * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)\n */\nvoid PNGAPI\npng_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warning_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->error_ptr = error_ptr;\n   png_ptr->error_fn = error_fn;\n#ifdef PNG_WARNINGS_SUPPORTED\n   png_ptr->warning_fn = warning_fn;\n#else\n   PNG_UNUSED(warning_fn)\n#endif\n}\n\n\n/* This function returns a pointer to the error_ptr associated with the user\n * functions.  The application should free any memory associated with this\n * pointer before png_write_destroy and png_read_destroy are called.\n */\npng_voidp PNGAPI\npng_get_error_ptr(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return NULL;\n\n   return ((png_voidp)png_ptr->error_ptr);\n}\n\n\n#ifdef PNG_ERROR_NUMBERS_SUPPORTED\nvoid PNGAPI\npng_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)\n{\n   if (png_ptr != NULL)\n   {\n      png_ptr->flags &=\n         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |\n         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);\n   }\n}\n#endif\n\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\\\n   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\n   /* Currently the above both depend on SETJMP_SUPPORTED, however it would be\n    * possible to implement without setjmp support just so long as there is some\n    * way to handle the error return here:\n    */\nPNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI\npng_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message),\n    PNG_NORETURN)\n{\n   png_const_structrp png_ptr = png_nonconst_ptr;\n   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);\n\n   /* An error is always logged here, overwriting anything (typically a warning)\n    * that is already there:\n    */\n   if (image != NULL)\n   {\n      png_safecat(image->message, (sizeof image->message), 0, error_message);\n      image->warning_or_error |= PNG_IMAGE_ERROR;\n\n      /* Retrieve the jmp_buf from within the png_control, making this work for\n       * C++ compilation too is pretty tricky: C++ wants a pointer to the first\n       * element of a jmp_buf, but C doesn't tell us the type of that.\n       */\n      if (image->opaque != NULL && image->opaque->error_buf != NULL)\n         longjmp(png_control_jmp_buf(image->opaque), 1);\n\n      /* Missing longjmp buffer, the following is to help debugging: */\n      {\n         size_t pos = png_safecat(image->message, (sizeof image->message), 0,\n             \"bad longjmp: \");\n         png_safecat(image->message, (sizeof image->message), pos,\n             error_message);\n      }\n   }\n\n   /* Here on an internal programming error. */\n   abort();\n}\n\n#ifdef PNG_WARNINGS_SUPPORTED\nvoid /* PRIVATE */ PNGCBAPI\npng_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)\n{\n   png_const_structrp png_ptr = png_nonconst_ptr;\n   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);\n\n   /* A warning is only logged if there is no prior warning or error. */\n   if (image->warning_or_error == 0)\n   {\n      png_safecat(image->message, (sizeof image->message), 0, warning_message);\n      image->warning_or_error |= PNG_IMAGE_WARNING;\n   }\n}\n#endif\n\nint /* PRIVATE */\npng_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)\n{\n   volatile png_imagep image = image_in;\n   volatile int result;\n   volatile png_voidp saved_error_buf;\n   jmp_buf safe_jmpbuf;\n\n   /* Safely execute function(arg) with png_error returning to this function. */\n   saved_error_buf = image->opaque->error_buf;\n   result = setjmp(safe_jmpbuf) == 0;\n\n   if (result != 0)\n   {\n\n      image->opaque->error_buf = safe_jmpbuf;\n      result = function(arg);\n   }\n\n   image->opaque->error_buf = saved_error_buf;\n\n   /* And do the cleanup prior to any failure return. */\n   if (result == 0)\n      png_image_free(image);\n\n   return result;\n}\n#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngget.c",
    "content": "\n/* pngget.c - retrieval of values from info struct\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n */\n\n#include \"pngpriv.h\"\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n\npng_uint_32 PNGAPI\npng_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_uint_32 flag)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return(info_ptr->valid & flag);\n\n   return(0);\n}\n\nsize_t PNGAPI\npng_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return(info_ptr->rowbytes);\n\n   return(0);\n}\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\npng_bytepp PNGAPI\npng_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return(info_ptr->row_pointers);\n\n   return(0);\n}\n#endif\n\n#ifdef PNG_EASY_ACCESS_SUPPORTED\n/* Easy access to info, added in libpng-0.99 */\npng_uint_32 PNGAPI\npng_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->width;\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->height;\n\n   return (0);\n}\n\npng_byte PNGAPI\npng_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->bit_depth;\n\n   return (0);\n}\n\npng_byte PNGAPI\npng_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->color_type;\n\n   return (0);\n}\n\npng_byte PNGAPI\npng_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->filter_type;\n\n   return (0);\n}\n\npng_byte PNGAPI\npng_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->interlace_type;\n\n   return (0);\n}\n\npng_byte PNGAPI\npng_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return info_ptr->compression_type;\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp\n   info_ptr)\n{\n#ifdef PNG_pHYs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n      {\n         png_debug1(1, \"in %s retrieval function\",\n             \"png_get_x_pixels_per_meter\");\n\n         if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)\n            return (info_ptr->x_pixels_per_unit);\n      }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp\n    info_ptr)\n{\n#ifdef PNG_pHYs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\",\n          \"png_get_y_pixels_per_meter\");\n\n      if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)\n         return (info_ptr->y_pixels_per_unit);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n#ifdef PNG_pHYs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_pixels_per_meter\");\n\n      if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER &&\n          info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)\n         return (info_ptr->x_pixels_per_unit);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nfloat PNGAPI\npng_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp\n   info_ptr)\n{\n#ifdef PNG_READ_pHYs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_aspect_ratio\");\n\n      if (info_ptr->x_pixels_per_unit != 0)\n         return ((float)((float)info_ptr->y_pixels_per_unit\n             /(float)info_ptr->x_pixels_per_unit));\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return ((float)0.0);\n}\n#endif\n\n#ifdef PNG_FIXED_POINT_SUPPORTED\npng_fixed_point PNGAPI\npng_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,\n    png_const_inforp info_ptr)\n{\n#ifdef PNG_READ_pHYs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0 &&\n       info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 &&\n       info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX &&\n       info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX)\n   {\n      png_fixed_point res;\n\n      png_debug1(1, \"in %s retrieval function\", \"png_get_aspect_ratio_fixed\");\n\n      /* The following casts work because a PNG 4 byte integer only has a valid\n       * range of 0..2^31-1; otherwise the cast might overflow.\n       */\n      if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1,\n          (png_int_32)info_ptr->x_pixels_per_unit) != 0)\n         return res;\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return 0;\n}\n#endif\n\npng_int_32 PNGAPI\npng_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n#ifdef PNG_oFFs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_oFFs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_x_offset_microns\");\n\n      if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)\n         return (info_ptr->x_offset);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\npng_int_32 PNGAPI\npng_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n#ifdef PNG_oFFs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_oFFs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_y_offset_microns\");\n\n      if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)\n         return (info_ptr->y_offset);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\npng_int_32 PNGAPI\npng_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n#ifdef PNG_oFFs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_oFFs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_x_offset_pixels\");\n\n      if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)\n         return (info_ptr->x_offset);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\npng_int_32 PNGAPI\npng_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n#ifdef PNG_oFFs_SUPPORTED\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_oFFs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"png_get_y_offset_pixels\");\n\n      if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)\n         return (info_ptr->y_offset);\n   }\n#else\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(info_ptr)\n#endif\n\n   return (0);\n}\n\n#ifdef PNG_INCH_CONVERSIONS_SUPPORTED\nstatic png_uint_32\nppi_from_ppm(png_uint_32 ppm)\n{\n#if 0\n   /* The conversion is *(2.54/100), in binary (32 digits):\n    * .00000110100000001001110101001001\n    */\n   png_uint_32 t1001, t1101;\n   ppm >>= 1;                  /* .1 */\n   t1001 = ppm + (ppm >> 3);   /* .1001 */\n   t1101 = t1001 + (ppm >> 1); /* .1101 */\n   ppm >>= 20;                 /* .000000000000000000001 */\n   t1101 += t1101 >> 15;       /* .1101000000000001101 */\n   t1001 >>= 11;               /* .000000000001001 */\n   t1001 += t1001 >> 12;       /* .000000000001001000000001001 */\n   ppm += t1001;               /* .000000000001001000001001001 */\n   ppm += t1101;               /* .110100000001001110101001001 */\n   return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */\n#else\n   /* The argument is a PNG unsigned integer, so it is not permitted\n    * to be bigger than 2^31.\n    */\n   png_fixed_point result;\n   if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127,\n       5000) != 0)\n      return (png_uint_32)result;\n\n   /* Overflow. */\n   return 0;\n#endif\n}\n\npng_uint_32 PNGAPI\npng_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr));\n}\n\npng_uint_32 PNGAPI\npng_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr));\n}\n\npng_uint_32 PNGAPI\npng_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr));\n}\n\n#ifdef PNG_FIXED_POINT_SUPPORTED\nstatic png_fixed_point\npng_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns)\n{\n   /* Convert from meters * 1,000,000 to inches * 100,000, meters to\n    * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127.\n    * Notice that this can overflow - a warning is output and 0 is\n    * returned.\n    */\n   return png_muldiv_warn(png_ptr, microns, 500, 127);\n}\n\npng_fixed_point PNGAPI\npng_get_x_offset_inches_fixed(png_const_structrp png_ptr,\n    png_const_inforp info_ptr)\n{\n   return png_fixed_inches_from_microns(png_ptr,\n       png_get_x_offset_microns(png_ptr, info_ptr));\n}\n#endif\n\n#ifdef PNG_FIXED_POINT_SUPPORTED\npng_fixed_point PNGAPI\npng_get_y_offset_inches_fixed(png_const_structrp png_ptr,\n    png_const_inforp info_ptr)\n{\n   return png_fixed_inches_from_microns(png_ptr,\n       png_get_y_offset_microns(png_ptr, info_ptr));\n}\n#endif\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nfloat PNGAPI\npng_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   /* To avoid the overflow do the conversion directly in floating\n    * point.\n    */\n   return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937);\n}\n#endif\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nfloat PNGAPI\npng_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   /* To avoid the overflow do the conversion directly in floating\n    * point.\n    */\n   return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937);\n}\n#endif\n\n#ifdef PNG_pHYs_SUPPORTED\npng_uint_32 PNGAPI\npng_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)\n{\n   png_uint_32 retval = 0;\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"pHYs\");\n\n      if (res_x != NULL)\n      {\n         *res_x = info_ptr->x_pixels_per_unit;\n         retval |= PNG_INFO_pHYs;\n      }\n\n      if (res_y != NULL)\n      {\n         *res_y = info_ptr->y_pixels_per_unit;\n         retval |= PNG_INFO_pHYs;\n      }\n\n      if (unit_type != NULL)\n      {\n         *unit_type = (int)info_ptr->phys_unit_type;\n         retval |= PNG_INFO_pHYs;\n\n         if (*unit_type == 1)\n         {\n            if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);\n            if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);\n         }\n      }\n   }\n\n   return (retval);\n}\n#endif /* pHYs */\n#endif /* INCH_CONVERSIONS */\n\n/* png_get_channels really belongs in here, too, but it's been around longer */\n\n#endif /* EASY_ACCESS */\n\n\npng_byte PNGAPI\npng_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return(info_ptr->channels);\n\n   return (0);\n}\n\n#ifdef PNG_READ_SUPPORTED\npng_const_bytep PNGAPI\npng_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return(info_ptr->signature);\n\n   return (NULL);\n}\n#endif\n\n#ifdef PNG_bKGD_SUPPORTED\npng_uint_32 PNGAPI\npng_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_color_16p *background)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_bKGD) != 0 &&\n       background != NULL)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"bKGD\");\n\n      *background = &(info_ptr->background);\n      return (PNG_INFO_bKGD);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_cHRM_SUPPORTED\n/* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the\n * same time to correct the rgb grayscale coefficient defaults obtained from the\n * cHRM chunk in 1.5.4\n */\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    double *white_x, double *white_y, double *red_x, double *red_y,\n    double *green_x, double *green_y, double *blue_x, double *blue_y)\n{\n   /* Quiet API change: this code used to only return the end points if a cHRM\n    * chunk was present, but the end points can also come from iCCP or sRGB\n    * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and\n    * the png_set_ APIs merely check that set end points are mutually\n    * consistent.\n    */\n   if (png_ptr != NULL && info_ptr != NULL &&\n      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"cHRM\");\n\n      if (white_x != NULL)\n         *white_x = png_float(png_ptr,\n             info_ptr->colorspace.end_points_xy.whitex, \"cHRM white X\");\n      if (white_y != NULL)\n         *white_y = png_float(png_ptr,\n             info_ptr->colorspace.end_points_xy.whitey, \"cHRM white Y\");\n      if (red_x != NULL)\n         *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx,\n             \"cHRM red X\");\n      if (red_y != NULL)\n         *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy,\n             \"cHRM red Y\");\n      if (green_x != NULL)\n         *green_x = png_float(png_ptr,\n             info_ptr->colorspace.end_points_xy.greenx, \"cHRM green X\");\n      if (green_y != NULL)\n         *green_y = png_float(png_ptr,\n             info_ptr->colorspace.end_points_xy.greeny, \"cHRM green Y\");\n      if (blue_x != NULL)\n         *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex,\n             \"cHRM blue X\");\n      if (blue_y != NULL)\n         *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,\n             \"cHRM blue Y\");\n      return (PNG_INFO_cHRM);\n   }\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    double *red_X, double *red_Y, double *red_Z, double *green_X,\n    double *green_Y, double *green_Z, double *blue_X, double *blue_Y,\n    double *blue_Z)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"cHRM_XYZ(float)\");\n\n      if (red_X != NULL)\n         *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,\n             \"cHRM red X\");\n      if (red_Y != NULL)\n         *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y,\n             \"cHRM red Y\");\n      if (red_Z != NULL)\n         *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z,\n             \"cHRM red Z\");\n      if (green_X != NULL)\n         *green_X = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.green_X, \"cHRM green X\");\n      if (green_Y != NULL)\n         *green_Y = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.green_Y, \"cHRM green Y\");\n      if (green_Z != NULL)\n         *green_Z = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.green_Z, \"cHRM green Z\");\n      if (blue_X != NULL)\n         *blue_X = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.blue_X, \"cHRM blue X\");\n      if (blue_Y != NULL)\n         *blue_Y = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.blue_Y, \"cHRM blue Y\");\n      if (blue_Z != NULL)\n         *blue_Z = png_float(png_ptr,\n             info_ptr->colorspace.end_points_XYZ.blue_Z, \"cHRM blue Z\");\n      return (PNG_INFO_cHRM);\n   }\n\n   return (0);\n}\n#  endif\n\n#  ifdef PNG_FIXED_POINT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *int_red_X, png_fixed_point *int_red_Y,\n    png_fixed_point *int_red_Z, png_fixed_point *int_green_X,\n    png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,\n    png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,\n    png_fixed_point *int_blue_Z)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"cHRM_XYZ\");\n\n      if (int_red_X != NULL)\n         *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;\n      if (int_red_Y != NULL)\n         *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y;\n      if (int_red_Z != NULL)\n         *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z;\n      if (int_green_X != NULL)\n         *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X;\n      if (int_green_Y != NULL)\n         *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y;\n      if (int_green_Z != NULL)\n         *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z;\n      if (int_blue_X != NULL)\n         *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X;\n      if (int_blue_Y != NULL)\n         *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;\n      if (int_blue_Z != NULL)\n         *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;\n      return (PNG_INFO_cHRM);\n   }\n\n   return (0);\n}\n\npng_uint_32 PNGAPI\npng_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,\n    png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,\n    png_fixed_point *blue_x, png_fixed_point *blue_y)\n{\n   png_debug1(1, \"in %s retrieval function\", \"cHRM\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)\n   {\n      if (white_x != NULL)\n         *white_x = info_ptr->colorspace.end_points_xy.whitex;\n      if (white_y != NULL)\n         *white_y = info_ptr->colorspace.end_points_xy.whitey;\n      if (red_x != NULL)\n         *red_x = info_ptr->colorspace.end_points_xy.redx;\n      if (red_y != NULL)\n         *red_y = info_ptr->colorspace.end_points_xy.redy;\n      if (green_x != NULL)\n         *green_x = info_ptr->colorspace.end_points_xy.greenx;\n      if (green_y != NULL)\n         *green_y = info_ptr->colorspace.end_points_xy.greeny;\n      if (blue_x != NULL)\n         *blue_x = info_ptr->colorspace.end_points_xy.bluex;\n      if (blue_y != NULL)\n         *blue_y = info_ptr->colorspace.end_points_xy.bluey;\n      return (PNG_INFO_cHRM);\n   }\n\n   return (0);\n}\n#  endif\n#endif\n\n#ifdef PNG_gAMA_SUPPORTED\n#  ifdef PNG_FIXED_POINT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_fixed_point *file_gamma)\n{\n   png_debug1(1, \"in %s retrieval function\", \"gAMA\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&\n       file_gamma != NULL)\n   {\n      *file_gamma = info_ptr->colorspace.gamma;\n      return (PNG_INFO_gAMA);\n   }\n\n   return (0);\n}\n#  endif\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    double *file_gamma)\n{\n   png_debug1(1, \"in %s retrieval function\", \"gAMA(float)\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n      (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&\n      file_gamma != NULL)\n   {\n      *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,\n          \"png_get_gAMA\");\n      return (PNG_INFO_gAMA);\n   }\n\n   return (0);\n}\n#  endif\n#endif\n\n#ifdef PNG_sRGB_SUPPORTED\npng_uint_32 PNGAPI\npng_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    int *file_srgb_intent)\n{\n   png_debug1(1, \"in %s retrieval function\", \"sRGB\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n      (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL)\n   {\n      *file_srgb_intent = info_ptr->colorspace.rendering_intent;\n      return (PNG_INFO_sRGB);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_iCCP_SUPPORTED\npng_uint_32 PNGAPI\npng_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_charpp name, int *compression_type,\n    png_bytepp profile, png_uint_32 *proflen)\n{\n   png_debug1(1, \"in %s retrieval function\", \"iCCP\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_iCCP) != 0 &&\n       name != NULL && profile != NULL && proflen != NULL)\n   {\n      *name = info_ptr->iccp_name;\n      *profile = info_ptr->iccp_profile;\n      *proflen = png_get_uint_32(info_ptr->iccp_profile);\n      /* This is somewhat irrelevant since the profile data returned has\n       * actually been uncompressed.\n       */\n      if (compression_type != NULL)\n         *compression_type = PNG_COMPRESSION_TYPE_BASE;\n      return (PNG_INFO_iCCP);\n   }\n\n   return (0);\n\n}\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\nint PNGAPI\npng_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_sPLT_tpp spalettes)\n{\n   if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)\n   {\n      *spalettes = info_ptr->splt_palettes;\n      return info_ptr->splt_palettes_num;\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_eXIf_SUPPORTED\npng_uint_32 PNGAPI\npng_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_bytep *exif)\n{\n  png_warning(png_ptr, \"png_get_eXIf does not work; use png_get_eXIf_1\");\n  PNG_UNUSED(info_ptr)\n  PNG_UNUSED(exif)\n  return 0;\n}\n\npng_uint_32 PNGAPI\npng_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_uint_32 *num_exif, png_bytep *exif)\n{\n   png_debug1(1, \"in %s retrieval function\", \"eXIf\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL)\n   {\n      *num_exif = info_ptr->num_exif;\n      *exif = info_ptr->exif;\n      return (PNG_INFO_eXIf);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_hIST_SUPPORTED\npng_uint_32 PNGAPI\npng_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_uint_16p *hist)\n{\n   png_debug1(1, \"in %s retrieval function\", \"hIST\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL)\n   {\n      *hist = info_ptr->hist;\n      return (PNG_INFO_hIST);\n   }\n\n   return (0);\n}\n#endif\n\npng_uint_32 PNGAPI\npng_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_uint_32 *width, png_uint_32 *height, int *bit_depth,\n    int *color_type, int *interlace_type, int *compression_type,\n    int *filter_type)\n{\n   png_debug1(1, \"in %s retrieval function\", \"IHDR\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return (0);\n\n   if (width != NULL)\n       *width = info_ptr->width;\n\n   if (height != NULL)\n       *height = info_ptr->height;\n\n   if (bit_depth != NULL)\n       *bit_depth = info_ptr->bit_depth;\n\n   if (color_type != NULL)\n       *color_type = info_ptr->color_type;\n\n   if (compression_type != NULL)\n      *compression_type = info_ptr->compression_type;\n\n   if (filter_type != NULL)\n      *filter_type = info_ptr->filter_type;\n\n   if (interlace_type != NULL)\n      *interlace_type = info_ptr->interlace_type;\n\n   /* This is redundant if we can be sure that the info_ptr values were all\n    * assigned in png_set_IHDR().  We do the check anyhow in case an\n    * application has ignored our advice not to mess with the members\n    * of info_ptr directly.\n    */\n   png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height,\n       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,\n       info_ptr->compression_type, info_ptr->filter_type);\n\n   return (1);\n}\n\n#ifdef PNG_oFFs_SUPPORTED\npng_uint_32 PNGAPI\npng_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)\n{\n   png_debug1(1, \"in %s retrieval function\", \"oFFs\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_oFFs) != 0 &&\n       offset_x != NULL && offset_y != NULL && unit_type != NULL)\n   {\n      *offset_x = info_ptr->x_offset;\n      *offset_y = info_ptr->y_offset;\n      *unit_type = (int)info_ptr->offset_unit_type;\n      return (PNG_INFO_oFFs);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\npng_uint_32 PNGAPI\npng_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,\n    png_charp *units, png_charpp *params)\n{\n   png_debug1(1, \"in %s retrieval function\", \"pCAL\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pCAL) != 0 &&\n       purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&\n       nparams != NULL && units != NULL && params != NULL)\n   {\n      *purpose = info_ptr->pcal_purpose;\n      *X0 = info_ptr->pcal_X0;\n      *X1 = info_ptr->pcal_X1;\n      *type = (int)info_ptr->pcal_type;\n      *nparams = (int)info_ptr->pcal_nparams;\n      *units = info_ptr->pcal_units;\n      *params = info_ptr->pcal_params;\n      return (PNG_INFO_pCAL);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_sCAL_SUPPORTED\n#  ifdef PNG_FIXED_POINT_SUPPORTED\n#    if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \\\n         defined(PNG_FLOATING_POINT_SUPPORTED)\npng_uint_32 PNGAPI\npng_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    int *unit, png_fixed_point *width, png_fixed_point *height)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_sCAL) != 0)\n   {\n      *unit = info_ptr->scal_unit;\n      /*TODO: make this work without FP support; the API is currently eliminated\n       * if neither floating point APIs nor internal floating point arithmetic\n       * are enabled.\n       */\n      *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), \"sCAL width\");\n      *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height),\n          \"sCAL height\");\n      return (PNG_INFO_sCAL);\n   }\n\n   return(0);\n}\n#    endif /* FLOATING_ARITHMETIC */\n#  endif /* FIXED_POINT */\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    int *unit, double *width, double *height)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_sCAL) != 0)\n   {\n      *unit = info_ptr->scal_unit;\n      *width = atof(info_ptr->scal_s_width);\n      *height = atof(info_ptr->scal_s_height);\n      return (PNG_INFO_sCAL);\n   }\n\n   return(0);\n}\n#  endif /* FLOATING POINT */\npng_uint_32 PNGAPI\npng_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    int *unit, png_charpp width, png_charpp height)\n{\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_sCAL) != 0)\n   {\n      *unit = info_ptr->scal_unit;\n      *width = info_ptr->scal_s_width;\n      *height = info_ptr->scal_s_height;\n      return (PNG_INFO_sCAL);\n   }\n\n   return(0);\n}\n#endif /* sCAL */\n\n#ifdef PNG_pHYs_SUPPORTED\npng_uint_32 PNGAPI\npng_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr,\n    png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)\n{\n   png_uint_32 retval = 0;\n\n   png_debug1(1, \"in %s retrieval function\", \"pHYs\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      if (res_x != NULL)\n      {\n         *res_x = info_ptr->x_pixels_per_unit;\n         retval |= PNG_INFO_pHYs;\n      }\n\n      if (res_y != NULL)\n      {\n         *res_y = info_ptr->y_pixels_per_unit;\n         retval |= PNG_INFO_pHYs;\n      }\n\n      if (unit_type != NULL)\n      {\n         *unit_type = (int)info_ptr->phys_unit_type;\n         retval |= PNG_INFO_pHYs;\n      }\n   }\n\n   return (retval);\n}\n#endif /* pHYs */\n\npng_uint_32 PNGAPI\npng_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_colorp *palette, int *num_palette)\n{\n   png_debug1(1, \"in %s retrieval function\", \"PLTE\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL)\n   {\n      *palette = info_ptr->palette;\n      *num_palette = info_ptr->num_palette;\n      png_debug1(3, \"num_palette = %d\", *num_palette);\n      return (PNG_INFO_PLTE);\n   }\n\n   return (0);\n}\n\n#ifdef PNG_sBIT_SUPPORTED\npng_uint_32 PNGAPI\npng_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_color_8p *sig_bit)\n{\n   png_debug1(1, \"in %s retrieval function\", \"sBIT\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL)\n   {\n      *sig_bit = &(info_ptr->sig_bit);\n      return (PNG_INFO_sBIT);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_TEXT_SUPPORTED\nint PNGAPI\npng_get_text(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_textp *text_ptr, int *num_text)\n{\n   if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)\n   {\n      png_debug1(1, \"in 0x%lx retrieval function\",\n         (unsigned long)png_ptr->chunk_name);\n\n      if (text_ptr != NULL)\n         *text_ptr = info_ptr->text;\n\n      if (num_text != NULL)\n         *num_text = info_ptr->num_text;\n\n      return info_ptr->num_text;\n   }\n\n   if (num_text != NULL)\n      *num_text = 0;\n\n   return(0);\n}\n#endif\n\n#ifdef PNG_tIME_SUPPORTED\npng_uint_32 PNGAPI\npng_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_timep *mod_time)\n{\n   png_debug1(1, \"in %s retrieval function\", \"tIME\");\n\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL)\n   {\n      *mod_time = &(info_ptr->mod_time);\n      return (PNG_INFO_tIME);\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_tRNS_SUPPORTED\npng_uint_32 PNGAPI\npng_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)\n{\n   png_uint_32 retval = 0;\n   if (png_ptr != NULL && info_ptr != NULL &&\n       (info_ptr->valid & PNG_INFO_tRNS) != 0)\n   {\n      png_debug1(1, \"in %s retrieval function\", \"tRNS\");\n\n      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         if (trans_alpha != NULL)\n         {\n            *trans_alpha = info_ptr->trans_alpha;\n            retval |= PNG_INFO_tRNS;\n         }\n\n         if (trans_color != NULL)\n            *trans_color = &(info_ptr->trans_color);\n      }\n\n      else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */\n      {\n         if (trans_color != NULL)\n         {\n            *trans_color = &(info_ptr->trans_color);\n            retval |= PNG_INFO_tRNS;\n         }\n\n         if (trans_alpha != NULL)\n            *trans_alpha = NULL;\n      }\n\n      if (num_trans != NULL)\n      {\n         *num_trans = info_ptr->num_trans;\n         retval |= PNG_INFO_tRNS;\n      }\n   }\n\n   return (retval);\n}\n#endif\n\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\nint PNGAPI\npng_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_unknown_chunkpp unknowns)\n{\n   if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)\n   {\n      *unknowns = info_ptr->unknown_chunks;\n      return info_ptr->unknown_chunks_num;\n   }\n\n   return (0);\n}\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\npng_byte PNGAPI\npng_get_rgb_to_gray_status (png_const_structrp png_ptr)\n{\n   return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0);\n}\n#endif\n\n#ifdef PNG_USER_CHUNKS_SUPPORTED\npng_voidp PNGAPI\npng_get_user_chunk_ptr(png_const_structrp png_ptr)\n{\n   return (png_ptr ? png_ptr->user_chunk_ptr : NULL);\n}\n#endif\n\nsize_t PNGAPI\npng_get_compression_buffer_size(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return 0;\n\n#ifdef PNG_WRITE_SUPPORTED\n   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)\n#endif\n   {\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n      return png_ptr->IDAT_read_size;\n#else\n      return PNG_IDAT_READ_SIZE;\n#endif\n   }\n\n#ifdef PNG_WRITE_SUPPORTED\n   else\n      return png_ptr->zbuffer_size;\n#endif\n}\n\n#ifdef PNG_SET_USER_LIMITS_SUPPORTED\n/* These functions were added to libpng 1.2.6 and were enabled\n * by default in libpng-1.4.0 */\npng_uint_32 PNGAPI\npng_get_user_width_max (png_const_structrp png_ptr)\n{\n   return (png_ptr ? png_ptr->user_width_max : 0);\n}\n\npng_uint_32 PNGAPI\npng_get_user_height_max (png_const_structrp png_ptr)\n{\n   return (png_ptr ? png_ptr->user_height_max : 0);\n}\n\n/* This function was added to libpng 1.4.0 */\npng_uint_32 PNGAPI\npng_get_chunk_cache_max (png_const_structrp png_ptr)\n{\n   return (png_ptr ? png_ptr->user_chunk_cache_max : 0);\n}\n\n/* This function was added to libpng 1.4.1 */\npng_alloc_size_t PNGAPI\npng_get_chunk_malloc_max (png_const_structrp png_ptr)\n{\n   return (png_ptr ? png_ptr->user_chunk_malloc_max : 0);\n}\n#endif /* SET_USER_LIMITS */\n\n/* These functions were added to libpng 1.4.0 */\n#ifdef PNG_IO_STATE_SUPPORTED\npng_uint_32 PNGAPI\npng_get_io_state (png_const_structrp png_ptr)\n{\n   return png_ptr->io_state;\n}\n\npng_uint_32 PNGAPI\npng_get_io_chunk_type (png_const_structrp png_ptr)\n{\n   return png_ptr->chunk_name;\n}\n#endif /* IO_STATE */\n\n#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED\nint PNGAPI\npng_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      return png_ptr->num_palette_max;\n\n   return (-1);\n}\n#  endif\n#endif\n\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pnginfo.h",
    "content": "\n/* pnginfo.h - header file for PNG reference library\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n /* png_info is a structure that holds the information in a PNG file so\n * that the application can find out the characteristics of the image.\n * If you are reading the file, this structure will tell you what is\n * in the PNG file.  If you are writing the file, fill in the information\n * you want to put into the PNG file, using png_set_*() functions, then\n * call png_write_info().\n *\n * The names chosen should be very close to the PNG specification, so\n * consult that document for information about the meaning of each field.\n *\n * With libpng < 0.95, it was only possible to directly set and read the\n * the values in the png_info_struct, which meant that the contents and\n * order of the values had to remain fixed.  With libpng 0.95 and later,\n * however, there are now functions that abstract the contents of\n * png_info_struct from the application, so this makes it easier to use\n * libpng with dynamic libraries, and even makes it possible to use\n * libraries that don't have all of the libpng ancillary chunk-handing\n * functionality.  In libpng-1.5.0 this was moved into a separate private\n * file that is not visible to applications.\n *\n * The following members may have allocated storage attached that should be\n * cleaned up before the structure is discarded: palette, trans, text,\n * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,\n * splt_palettes, scal_unit, row_pointers, and unknowns.   By default, these\n * are automatically freed when the info structure is deallocated, if they were\n * allocated internally by libpng.  This behavior can be changed by means\n * of the png_data_freer() function.\n *\n * More allocation details: all the chunk-reading functions that\n * change these members go through the corresponding png_set_*\n * functions.  A function to clear these members is available: see\n * png_free_data().  The png_set_* functions do not depend on being\n * able to point info structure members to any of the storage they are\n * passed (they make their own copies), EXCEPT that the png_set_text\n * functions use the same storage passed to them in the text_ptr or\n * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns\n * functions do not make their own copies.\n */\n#ifndef PNGINFO_H\n#define PNGINFO_H\n\nstruct png_info_def\n{\n   /* The following are necessary for every PNG file */\n   png_uint_32 width;       /* width of image in pixels (from IHDR) */\n   png_uint_32 height;      /* height of image in pixels (from IHDR) */\n   png_uint_32 valid;       /* valid chunk data (see PNG_INFO_ below) */\n   size_t rowbytes;         /* bytes needed to hold an untransformed row */\n   png_colorp palette;      /* array of color values (valid & PNG_INFO_PLTE) */\n   png_uint_16 num_palette; /* number of color entries in \"palette\" (PLTE) */\n   png_uint_16 num_trans;   /* number of transparent palette color (tRNS) */\n   png_byte bit_depth;      /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */\n   png_byte color_type;     /* see PNG_COLOR_TYPE_ below (from IHDR) */\n   /* The following three should have been named *_method not *_type */\n   png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */\n   png_byte filter_type;    /* must be PNG_FILTER_TYPE_BASE (from IHDR) */\n   png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */\n\n   /* The following are set by png_set_IHDR, called from the application on\n    * write, but the are never actually used by the write code.\n    */\n   png_byte channels;       /* number of data channels per pixel (1, 2, 3, 4) */\n   png_byte pixel_depth;    /* number of bits per pixel */\n   png_byte spare_byte;     /* to align the data, and for future use */\n\n#ifdef PNG_READ_SUPPORTED\n   /* This is never set during write */\n   png_byte signature[8];   /* magic bytes read by libpng from start of file */\n#endif\n\n   /* The rest of the data is optional.  If you are reading, check the\n    * valid field to see if the information in these are valid.  If you\n    * are writing, set the valid field to those chunks you want written,\n    * and initialize the appropriate fields below.\n    */\n\n#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)\n   /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are\n    * defined.  When COLORSPACE is switched on all the colorspace-defining\n    * chunks should be enabled, when GAMMA is switched on all the gamma-defining\n    * chunks should be enabled.  If this is not done it becomes possible to read\n    * inconsistent PNG files and assign a probably incorrect interpretation to\n    * the information.  (In other words, by carefully choosing which chunks to\n    * recognize the system configuration can select an interpretation for PNG\n    * files containing ambiguous data and this will result in inconsistent\n    * behavior between different libpng builds!)\n    */\n   png_colorspace colorspace;\n#endif\n\n#ifdef PNG_iCCP_SUPPORTED\n   /* iCCP chunk data. */\n   png_charp iccp_name;     /* profile name */\n   png_bytep iccp_profile;  /* International Color Consortium profile data */\n   png_uint_32 iccp_proflen;  /* ICC profile data length */\n#endif\n\n#ifdef PNG_TEXT_SUPPORTED\n   /* The tEXt, and zTXt chunks contain human-readable textual data in\n    * uncompressed, compressed, and optionally compressed forms, respectively.\n    * The data in \"text\" is an array of pointers to uncompressed,\n    * null-terminated C strings. Each chunk has a keyword that describes the\n    * textual data contained in that chunk.  Keywords are not required to be\n    * unique, and the text string may be empty.  Any number of text chunks may\n    * be in an image.\n    */\n   int num_text; /* number of comments read or comments to write */\n   int max_text; /* current size of text array */\n   png_textp text; /* array of comments read or comments to write */\n#endif /* TEXT */\n\n#ifdef PNG_tIME_SUPPORTED\n   /* The tIME chunk holds the last time the displayed image data was\n    * modified.  See the png_time struct for the contents of this struct.\n    */\n   png_time mod_time;\n#endif\n\n#ifdef PNG_sBIT_SUPPORTED\n   /* The sBIT chunk specifies the number of significant high-order bits\n    * in the pixel data.  Values are in the range [1, bit_depth], and are\n    * only specified for the channels in the pixel data.  The contents of\n    * the low-order bits is not specified.  Data is valid if\n    * (valid & PNG_INFO_sBIT) is non-zero.\n    */\n   png_color_8 sig_bit; /* significant bits in color channels */\n#endif\n\n#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \\\ndefined(PNG_READ_BACKGROUND_SUPPORTED)\n   /* The tRNS chunk supplies transparency data for paletted images and\n    * other image types that don't need a full alpha channel.  There are\n    * \"num_trans\" transparency values for a paletted image, stored in the\n    * same order as the palette colors, starting from index 0.  Values\n    * for the data are in the range [0, 255], ranging from fully transparent\n    * to fully opaque, respectively.  For non-paletted images, there is a\n    * single color specified that should be treated as fully transparent.\n    * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.\n    */\n   png_bytep trans_alpha;    /* alpha values for paletted image */\n   png_color_16 trans_color; /* transparent color for non-palette image */\n#endif\n\n#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)\n   /* The bKGD chunk gives the suggested image background color if the\n    * display program does not have its own background color and the image\n    * is needs to composited onto a background before display.  The colors\n    * in \"background\" are normally in the same color space/depth as the\n    * pixel data.  Data is valid if (valid & PNG_INFO_bKGD) is non-zero.\n    */\n   png_color_16 background;\n#endif\n\n#ifdef PNG_oFFs_SUPPORTED\n   /* The oFFs chunk gives the offset in \"offset_unit_type\" units rightwards\n    * and downwards from the top-left corner of the display, page, or other\n    * application-specific co-ordinate space.  See the PNG_OFFSET_ defines\n    * below for the unit types.  Valid if (valid & PNG_INFO_oFFs) non-zero.\n    */\n   png_int_32 x_offset; /* x offset on page */\n   png_int_32 y_offset; /* y offset on page */\n   png_byte offset_unit_type; /* offset units type */\n#endif\n\n#ifdef PNG_pHYs_SUPPORTED\n   /* The pHYs chunk gives the physical pixel density of the image for\n    * display or printing in \"phys_unit_type\" units (see PNG_RESOLUTION_\n    * defines below).  Data is valid if (valid & PNG_INFO_pHYs) is non-zero.\n    */\n   png_uint_32 x_pixels_per_unit; /* horizontal pixel density */\n   png_uint_32 y_pixels_per_unit; /* vertical pixel density */\n   png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */\n#endif\n\n#ifdef PNG_eXIf_SUPPORTED\n   int num_exif;  /* Added at libpng-1.6.31 */\n   png_bytep exif;\n# ifdef PNG_READ_eXIf_SUPPORTED\n   png_bytep eXIf_buf;  /* Added at libpng-1.6.32 */\n# endif\n#endif\n\n#ifdef PNG_hIST_SUPPORTED\n   /* The hIST chunk contains the relative frequency or importance of the\n    * various palette entries, so that a viewer can intelligently select a\n    * reduced-color palette, if required.  Data is an array of \"num_palette\"\n    * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)\n    * is non-zero.\n    */\n   png_uint_16p hist;\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\n   /* The pCAL chunk describes a transformation between the stored pixel\n    * values and original physical data values used to create the image.\n    * The integer range [0, 2^bit_depth - 1] maps to the floating-point\n    * range given by [pcal_X0, pcal_X1], and are further transformed by a\n    * (possibly non-linear) transformation function given by \"pcal_type\"\n    * and \"pcal_params\" into \"pcal_units\".  Please see the PNG_EQUATION_\n    * defines below, and the PNG-Group's PNG extensions document for a\n    * complete description of the transformations and how they should be\n    * implemented, and for a description of the ASCII parameter strings.\n    * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.\n    */\n   png_charp pcal_purpose;  /* pCAL chunk description string */\n   png_int_32 pcal_X0;      /* minimum value */\n   png_int_32 pcal_X1;      /* maximum value */\n   png_charp pcal_units;    /* Latin-1 string giving physical units */\n   png_charpp pcal_params;  /* ASCII strings containing parameter values */\n   png_byte pcal_type;      /* equation type (see PNG_EQUATION_ below) */\n   png_byte pcal_nparams;   /* number of parameters given in pcal_params */\n#endif\n\n/* New members added in libpng-1.0.6 */\n   png_uint_32 free_me;     /* flags items libpng is responsible for freeing */\n\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n   /* Storage for unknown chunks that the library doesn't recognize. */\n   png_unknown_chunkp unknown_chunks;\n\n   /* The type of this field is limited by the type of\n    * png_struct::user_chunk_cache_max, else overflow can occur.\n    */\n   int                unknown_chunks_num;\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\n   /* Data on sPLT chunks (there may be more than one). */\n   png_sPLT_tp splt_palettes;\n   int         splt_palettes_num; /* Match type returned by png_get API */\n#endif\n\n#ifdef PNG_sCAL_SUPPORTED\n   /* The sCAL chunk describes the actual physical dimensions of the\n    * subject matter of the graphic.  The chunk contains a unit specification\n    * a byte value, and two ASCII strings representing floating-point\n    * values.  The values are width and height corresponding to one pixel\n    * in the image.  Data values are valid if (valid & PNG_INFO_sCAL) is\n    * non-zero.\n    */\n   png_byte scal_unit;         /* unit of physical scale */\n   png_charp scal_s_width;     /* string containing height */\n   png_charp scal_s_height;    /* string containing width */\n#endif\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\n   /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS)\n      non-zero */\n   /* Data valid if (valid & PNG_INFO_IDAT) non-zero */\n   png_bytepp row_pointers;        /* the image bits */\n#endif\n\n};\n#endif /* PNGINFO_H */\n"
  },
  {
    "path": "dlib/external/libpng/pnglibconf.h",
    "content": "/* pnglibconf.h - library build configuration */\n\n/* libpng version 1.6.37 */\n\n/* Copyright (c) 2018-2019 Cosmin Truta */\n/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */\n\n/* This code is released under the libpng license. */\n/* For conditions of distribution and use, see the disclaimer */\n/* and license in png.h */\n\n/* pnglibconf.h */\n/* Machine generated file: DO NOT EDIT */\n/* Derived from: scripts/pnglibconf.dfa */\n#ifndef PNGLCONF_H\n#define PNGLCONF_H\n/* options */\n#define PNG_16BIT_SUPPORTED\n#define PNG_ALIGNED_MEMORY_SUPPORTED\n/*#undef PNG_ARM_NEON_API_SUPPORTED*/\n/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/\n#define PNG_BENIGN_ERRORS_SUPPORTED\n#define PNG_BENIGN_READ_ERRORS_SUPPORTED\n/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/\n#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED\n#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_COLORSPACE_SUPPORTED\n#define PNG_CONSOLE_IO_SUPPORTED\n#define PNG_CONVERT_tIME_SUPPORTED\n#define PNG_EASY_ACCESS_SUPPORTED\n/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/\n#define PNG_ERROR_TEXT_SUPPORTED\n#define PNG_FIXED_POINT_SUPPORTED\n#define PNG_FLOATING_ARITHMETIC_SUPPORTED\n#define PNG_FLOATING_POINT_SUPPORTED\n#define PNG_FORMAT_AFIRST_SUPPORTED\n#define PNG_FORMAT_BGR_SUPPORTED\n#define PNG_GAMMA_SUPPORTED\n#define PNG_GET_PALETTE_MAX_SUPPORTED\n#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n#define PNG_INCH_CONVERSIONS_SUPPORTED\n#define PNG_INFO_IMAGE_SUPPORTED\n#define PNG_IO_STATE_SUPPORTED\n#define PNG_MNG_FEATURES_SUPPORTED\n#define PNG_POINTER_INDEXING_SUPPORTED\n/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/\n/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/\n#define PNG_PROGRESSIVE_READ_SUPPORTED\n#define PNG_READ_16BIT_SUPPORTED\n#define PNG_READ_ALPHA_MODE_SUPPORTED\n#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED\n#define PNG_READ_BACKGROUND_SUPPORTED\n#define PNG_READ_BGR_SUPPORTED\n#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_READ_COMPOSITE_NODIV_SUPPORTED\n#define PNG_READ_COMPRESSED_TEXT_SUPPORTED\n#define PNG_READ_EXPAND_16_SUPPORTED\n#define PNG_READ_EXPAND_SUPPORTED\n#define PNG_READ_FILLER_SUPPORTED\n#define PNG_READ_GAMMA_SUPPORTED\n#define PNG_READ_GET_PALETTE_MAX_SUPPORTED\n#define PNG_READ_GRAY_TO_RGB_SUPPORTED\n#define PNG_READ_INTERLACING_SUPPORTED\n#define PNG_READ_INT_FUNCTIONS_SUPPORTED\n#define PNG_READ_INVERT_ALPHA_SUPPORTED\n#define PNG_READ_INVERT_SUPPORTED\n#define PNG_READ_OPT_PLTE_SUPPORTED\n#define PNG_READ_PACKSWAP_SUPPORTED\n#define PNG_READ_PACK_SUPPORTED\n#define PNG_READ_QUANTIZE_SUPPORTED\n#define PNG_READ_RGB_TO_GRAY_SUPPORTED\n#define PNG_READ_SCALE_16_TO_8_SUPPORTED\n#define PNG_READ_SHIFT_SUPPORTED\n#define PNG_READ_STRIP_16_TO_8_SUPPORTED\n#define PNG_READ_STRIP_ALPHA_SUPPORTED\n#define PNG_READ_SUPPORTED\n#define PNG_READ_SWAP_ALPHA_SUPPORTED\n#define PNG_READ_SWAP_SUPPORTED\n#define PNG_READ_TEXT_SUPPORTED\n#define PNG_READ_TRANSFORMS_SUPPORTED\n#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_READ_USER_CHUNKS_SUPPORTED\n#define PNG_READ_USER_TRANSFORM_SUPPORTED\n#define PNG_READ_bKGD_SUPPORTED\n#define PNG_READ_cHRM_SUPPORTED\n#define PNG_READ_eXIf_SUPPORTED\n#define PNG_READ_gAMA_SUPPORTED\n#define PNG_READ_hIST_SUPPORTED\n#define PNG_READ_iCCP_SUPPORTED\n#define PNG_READ_iTXt_SUPPORTED\n#define PNG_READ_oFFs_SUPPORTED\n#define PNG_READ_pCAL_SUPPORTED\n#define PNG_READ_pHYs_SUPPORTED\n#define PNG_READ_sBIT_SUPPORTED\n#define PNG_READ_sCAL_SUPPORTED\n#define PNG_READ_sPLT_SUPPORTED\n#define PNG_READ_sRGB_SUPPORTED\n#define PNG_READ_tEXt_SUPPORTED\n#define PNG_READ_tIME_SUPPORTED\n#define PNG_READ_tRNS_SUPPORTED\n#define PNG_READ_zTXt_SUPPORTED\n#define PNG_SAVE_INT_32_SUPPORTED\n#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_SEQUENTIAL_READ_SUPPORTED\n#define PNG_SETJMP_SUPPORTED\n#define PNG_SET_OPTION_SUPPORTED\n#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_SET_USER_LIMITS_SUPPORTED\n#define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED\n#define PNG_SIMPLIFIED_READ_BGR_SUPPORTED\n#define PNG_SIMPLIFIED_READ_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED\n#define PNG_SIMPLIFIED_WRITE_SUPPORTED\n#define PNG_STDIO_SUPPORTED\n#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_TEXT_SUPPORTED\n#define PNG_TIME_RFC1123_SUPPORTED\n#define PNG_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_USER_CHUNKS_SUPPORTED\n#define PNG_USER_LIMITS_SUPPORTED\n#define PNG_USER_MEM_SUPPORTED\n#define PNG_USER_TRANSFORM_INFO_SUPPORTED\n#define PNG_USER_TRANSFORM_PTR_SUPPORTED\n#define PNG_WARNINGS_SUPPORTED\n#define PNG_WRITE_16BIT_SUPPORTED\n#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED\n#define PNG_WRITE_BGR_SUPPORTED\n#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED\n#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED\n#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED\n#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\n#define PNG_WRITE_FILLER_SUPPORTED\n#define PNG_WRITE_FILTER_SUPPORTED\n#define PNG_WRITE_FLUSH_SUPPORTED\n#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED\n#define PNG_WRITE_INTERLACING_SUPPORTED\n#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED\n#define PNG_WRITE_INVERT_ALPHA_SUPPORTED\n#define PNG_WRITE_INVERT_SUPPORTED\n#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n#define PNG_WRITE_PACKSWAP_SUPPORTED\n#define PNG_WRITE_PACK_SUPPORTED\n#define PNG_WRITE_SHIFT_SUPPORTED\n#define PNG_WRITE_SUPPORTED\n#define PNG_WRITE_SWAP_ALPHA_SUPPORTED\n#define PNG_WRITE_SWAP_SUPPORTED\n#define PNG_WRITE_TEXT_SUPPORTED\n#define PNG_WRITE_TRANSFORMS_SUPPORTED\n#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n#define PNG_WRITE_USER_TRANSFORM_SUPPORTED\n#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED\n#define PNG_WRITE_bKGD_SUPPORTED\n#define PNG_WRITE_cHRM_SUPPORTED\n#define PNG_WRITE_eXIf_SUPPORTED\n#define PNG_WRITE_gAMA_SUPPORTED\n#define PNG_WRITE_hIST_SUPPORTED\n#define PNG_WRITE_iCCP_SUPPORTED\n#define PNG_WRITE_iTXt_SUPPORTED\n#define PNG_WRITE_oFFs_SUPPORTED\n#define PNG_WRITE_pCAL_SUPPORTED\n#define PNG_WRITE_pHYs_SUPPORTED\n#define PNG_WRITE_sBIT_SUPPORTED\n#define PNG_WRITE_sCAL_SUPPORTED\n#define PNG_WRITE_sPLT_SUPPORTED\n#define PNG_WRITE_sRGB_SUPPORTED\n#define PNG_WRITE_tEXt_SUPPORTED\n#define PNG_WRITE_tIME_SUPPORTED\n#define PNG_WRITE_tRNS_SUPPORTED\n#define PNG_WRITE_zTXt_SUPPORTED\n#define PNG_bKGD_SUPPORTED\n#define PNG_cHRM_SUPPORTED\n#define PNG_eXIf_SUPPORTED\n#define PNG_gAMA_SUPPORTED\n#define PNG_hIST_SUPPORTED\n#define PNG_iCCP_SUPPORTED\n#define PNG_iTXt_SUPPORTED\n#define PNG_oFFs_SUPPORTED\n#define PNG_pCAL_SUPPORTED\n#define PNG_pHYs_SUPPORTED\n#define PNG_sBIT_SUPPORTED\n#define PNG_sCAL_SUPPORTED\n#define PNG_sPLT_SUPPORTED\n#define PNG_sRGB_SUPPORTED\n#define PNG_tEXt_SUPPORTED\n#define PNG_tIME_SUPPORTED\n#define PNG_tRNS_SUPPORTED\n#define PNG_zTXt_SUPPORTED\n/* end of options */\n/* settings */\n#define PNG_API_RULE 0\n#define PNG_DEFAULT_READ_MACROS 1\n#define PNG_GAMMA_THRESHOLD_FIXED 5000\n#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE\n#define PNG_INFLATE_BUF_SIZE 1024\n#define PNG_LINKAGE_API extern\n#define PNG_LINKAGE_CALLBACK extern\n#define PNG_LINKAGE_DATA extern\n#define PNG_LINKAGE_FUNCTION extern\n#define PNG_MAX_GAMMA_8 11\n#define PNG_QUANTIZE_BLUE_BITS 5\n#define PNG_QUANTIZE_GREEN_BITS 5\n#define PNG_QUANTIZE_RED_BITS 5\n#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)\n#define PNG_TEXT_Z_DEFAULT_STRATEGY 0\n#define PNG_USER_CHUNK_CACHE_MAX 1000\n#define PNG_USER_CHUNK_MALLOC_MAX 8000000\n#define PNG_USER_HEIGHT_MAX 1000000\n#define PNG_USER_WIDTH_MAX 1000000\n#define PNG_ZBUF_SIZE 8192\n#define PNG_ZLIB_VERNUM 0x12b0\n#define PNG_Z_DEFAULT_COMPRESSION (-1)\n#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0\n#define PNG_Z_DEFAULT_STRATEGY 1\n#define PNG_sCAL_PRECISION 5\n#define PNG_sRGB_PROFILE_CHECKS 2\n/* end of settings */\n#endif /* PNGLCONF_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngmem.c",
    "content": "\n/* pngmem.c - stub functions for memory allocation\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file provides a location for all memory allocation.  Users who\n * need special memory handling are expected to supply replacement\n * functions for png_malloc() and png_free(), and to use\n * png_create_read_struct_2() and png_create_write_struct_2() to\n * identify the replacement functions.\n */\n\n#include \"pngpriv.h\"\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n/* Free a png_struct */\nvoid /* PRIVATE */\npng_destroy_png_struct(png_structrp png_ptr)\n{\n   if (png_ptr != NULL)\n   {\n      /* png_free might call png_error and may certainly call\n       * png_get_mem_ptr, so fake a temporary png_struct to support this.\n       */\n      png_struct dummy_struct = *png_ptr;\n      memset(png_ptr, 0, (sizeof *png_ptr));\n      png_free(&dummy_struct, png_ptr);\n\n#     ifdef PNG_SETJMP_SUPPORTED\n         /* We may have a jmp_buf left to deallocate. */\n         png_free_jmpbuf(&dummy_struct);\n#     endif\n   }\n}\n\n/* Allocate memory.  For reasonable files, size should never exceed\n * 64K.  However, zlib may allocate more than 64K if you don't tell\n * it not to.  See zconf.h and png.h for more information.  zlib does\n * need to allocate exactly 64K, so whatever you call here must\n * have the ability to do that.\n */\nPNG_FUNCTION(png_voidp,PNGAPI\npng_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)\n{\n   png_voidp ret;\n\n   ret = png_malloc(png_ptr, size);\n\n   if (ret != NULL)\n      memset(ret, 0, size);\n\n   return ret;\n}\n\n/* png_malloc_base, an internal function added at libpng 1.6.0, does the work of\n * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED.\n * Checking and error handling must happen outside this routine; it returns NULL\n * if the allocation cannot be done (for any reason.)\n */\nPNG_FUNCTION(png_voidp /* PRIVATE */,\npng_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),\n    PNG_ALLOCATED)\n{\n   /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS\n    * allocators have also been removed in 1.6.0, so any 16-bit system now has\n    * to implement a user memory handler.  This checks to be sure it isn't\n    * called with big numbers.\n    */\n#ifndef PNG_USER_MEM_SUPPORTED\n   PNG_UNUSED(png_ptr)\n#endif\n\n   /* Some compilers complain that this is always true.  However, it\n    * can be false when integer overflow happens.\n    */\n   if (size > 0 && size <= PNG_SIZE_MAX\n#     ifdef PNG_MAX_MALLOC_64K\n         && size <= 65536U\n#     endif\n      )\n   {\n#ifdef PNG_USER_MEM_SUPPORTED\n      if (png_ptr != NULL && png_ptr->malloc_fn != NULL)\n         return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size);\n\n      else\n#endif\n         return malloc((size_t)size); /* checked for truncation above */\n   }\n\n   else\n      return NULL;\n}\n\n#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\\\n   defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)\n/* This is really here only to work round a spurious warning in GCC 4.6 and 4.7\n * that arises because of the checks in png_realloc_array that are repeated in\n * png_malloc_array.\n */\nstatic png_voidp\npng_malloc_array_checked(png_const_structrp png_ptr, int nelements,\n    size_t element_size)\n{\n   png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */\n\n   if (req <= PNG_SIZE_MAX/element_size)\n      return png_malloc_base(png_ptr, req * element_size);\n\n   /* The failure case when the request is too large */\n   return NULL;\n}\n\nPNG_FUNCTION(png_voidp /* PRIVATE */,\npng_malloc_array,(png_const_structrp png_ptr, int nelements,\n    size_t element_size),PNG_ALLOCATED)\n{\n   if (nelements <= 0 || element_size == 0)\n      png_error(png_ptr, \"internal error: array alloc\");\n\n   return png_malloc_array_checked(png_ptr, nelements, element_size);\n}\n\nPNG_FUNCTION(png_voidp /* PRIVATE */,\npng_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array,\n    int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED)\n{\n   /* These are internal errors: */\n   if (add_elements <= 0 || element_size == 0 || old_elements < 0 ||\n      (old_array == NULL && old_elements > 0))\n      png_error(png_ptr, \"internal error: array realloc\");\n\n   /* Check for overflow on the elements count (so the caller does not have to\n    * check.)\n    */\n   if (add_elements <= INT_MAX - old_elements)\n   {\n      png_voidp new_array = png_malloc_array_checked(png_ptr,\n          old_elements+add_elements, element_size);\n\n      if (new_array != NULL)\n      {\n         /* Because png_malloc_array worked the size calculations below cannot\n          * overflow.\n          */\n         if (old_elements > 0)\n            memcpy(new_array, old_array, element_size*(unsigned)old_elements);\n\n         memset((char*)new_array + element_size*(unsigned)old_elements, 0,\n             element_size*(unsigned)add_elements);\n\n         return new_array;\n      }\n   }\n\n   return NULL; /* error */\n}\n#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */\n\n/* Various functions that have different error handling are derived from this.\n * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate\n * function png_malloc_default is also provided.\n */\nPNG_FUNCTION(png_voidp,PNGAPI\npng_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED)\n{\n   png_voidp ret;\n\n   if (png_ptr == NULL)\n      return NULL;\n\n   ret = png_malloc_base(png_ptr, size);\n\n   if (ret == NULL)\n       png_error(png_ptr, \"Out of memory\"); /* 'm' means png_malloc */\n\n   return ret;\n}\n\n#ifdef PNG_USER_MEM_SUPPORTED\nPNG_FUNCTION(png_voidp,PNGAPI\npng_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size),\n    PNG_ALLOCATED PNG_DEPRECATED)\n{\n   png_voidp ret;\n\n   if (png_ptr == NULL)\n      return NULL;\n\n   /* Passing 'NULL' here bypasses the application provided memory handler. */\n   ret = png_malloc_base(NULL/*use malloc*/, size);\n\n   if (ret == NULL)\n      png_error(png_ptr, \"Out of Memory\"); /* 'M' means png_malloc_default */\n\n   return ret;\n}\n#endif /* USER_MEM */\n\n/* This function was added at libpng version 1.2.3.  The png_malloc_warn()\n * function will issue a png_warning and return NULL instead of issuing a\n * png_error, if it fails to allocate the requested memory.\n */\nPNG_FUNCTION(png_voidp,PNGAPI\npng_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size),\n    PNG_ALLOCATED)\n{\n   if (png_ptr != NULL)\n   {\n      png_voidp ret = png_malloc_base(png_ptr, size);\n\n      if (ret != NULL)\n         return ret;\n\n      png_warning(png_ptr, \"Out of memory\");\n   }\n\n   return NULL;\n}\n\n/* Free a pointer allocated by png_malloc().  If ptr is NULL, return\n * without taking any action.\n */\nvoid PNGAPI\npng_free(png_const_structrp png_ptr, png_voidp ptr)\n{\n   if (png_ptr == NULL || ptr == NULL)\n      return;\n\n#ifdef PNG_USER_MEM_SUPPORTED\n   if (png_ptr->free_fn != NULL)\n      png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr);\n\n   else\n      png_free_default(png_ptr, ptr);\n}\n\nPNG_FUNCTION(void,PNGAPI\npng_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED)\n{\n   if (png_ptr == NULL || ptr == NULL)\n      return;\n#endif /* USER_MEM */\n\n   free(ptr);\n}\n\n#ifdef PNG_USER_MEM_SUPPORTED\n/* This function is called when the application wants to use another method\n * of allocating and freeing memory.\n */\nvoid PNGAPI\npng_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr\n  malloc_fn, png_free_ptr free_fn)\n{\n   if (png_ptr != NULL)\n   {\n      png_ptr->mem_ptr = mem_ptr;\n      png_ptr->malloc_fn = malloc_fn;\n      png_ptr->free_fn = free_fn;\n   }\n}\n\n/* This function returns a pointer to the mem_ptr associated with the user\n * functions.  The application should free any memory associated with this\n * pointer before png_write_destroy and png_read_destroy are called.\n */\npng_voidp PNGAPI\npng_get_mem_ptr(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return NULL;\n\n   return png_ptr->mem_ptr;\n}\n#endif /* USER_MEM */\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngpread.c",
    "content": "\n/* pngpread.c - read a png file in push mode\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\n\n/* Push model modes */\n#define PNG_READ_SIG_MODE   0\n#define PNG_READ_CHUNK_MODE 1\n#define PNG_READ_IDAT_MODE  2\n#define PNG_READ_tEXt_MODE  4\n#define PNG_READ_zTXt_MODE  5\n#define PNG_READ_DONE_MODE  6\n#define PNG_READ_iTXt_MODE  7\n#define PNG_ERROR_MODE      8\n\n#define PNG_PUSH_SAVE_BUFFER_IF_FULL \\\nif (png_ptr->push_length + 4 > png_ptr->buffer_size) \\\n   { png_push_save_buffer(png_ptr); return; }\n#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \\\nif (png_ptr->buffer_size < N) \\\n   { png_push_save_buffer(png_ptr); return; }\n\nvoid PNGAPI\npng_process_data(png_structrp png_ptr, png_inforp info_ptr,\n    png_bytep buffer, size_t buffer_size)\n{\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   png_push_restore_buffer(png_ptr, buffer, buffer_size);\n\n   while (png_ptr->buffer_size)\n   {\n      png_process_some_data(png_ptr, info_ptr);\n   }\n}\n\nsize_t PNGAPI\npng_process_data_pause(png_structrp png_ptr, int save)\n{\n   if (png_ptr != NULL)\n   {\n      /* It's easiest for the caller if we do the save; then the caller doesn't\n       * have to supply the same data again:\n       */\n      if (save != 0)\n         png_push_save_buffer(png_ptr);\n      else\n      {\n         /* This includes any pending saved bytes: */\n         size_t remaining = png_ptr->buffer_size;\n         png_ptr->buffer_size = 0;\n\n         /* So subtract the saved buffer size, unless all the data\n          * is actually 'saved', in which case we just return 0\n          */\n         if (png_ptr->save_buffer_size < remaining)\n            return remaining - png_ptr->save_buffer_size;\n      }\n   }\n\n   return 0;\n}\n\npng_uint_32 PNGAPI\npng_process_data_skip(png_structrp png_ptr)\n{\n/* TODO: Deprecate and remove this API.\n * Somewhere the implementation of this seems to have been lost,\n * or abandoned.  It was only to support some internal back-door access\n * to png_struct) in libpng-1.4.x.\n */\n   png_app_warning(png_ptr,\n\"png_process_data_skip is not implemented in any current version of libpng\");\n   return 0;\n}\n\n/* What we do with the incoming data depends on what we were previously\n * doing before we ran out of data...\n */\nvoid /* PRIVATE */\npng_process_some_data(png_structrp png_ptr, png_inforp info_ptr)\n{\n   if (png_ptr == NULL)\n      return;\n\n   switch (png_ptr->process_mode)\n   {\n      case PNG_READ_SIG_MODE:\n      {\n         png_push_read_sig(png_ptr, info_ptr);\n         break;\n      }\n\n      case PNG_READ_CHUNK_MODE:\n      {\n         png_push_read_chunk(png_ptr, info_ptr);\n         break;\n      }\n\n      case PNG_READ_IDAT_MODE:\n      {\n         png_push_read_IDAT(png_ptr);\n         break;\n      }\n\n      default:\n      {\n         png_ptr->buffer_size = 0;\n         break;\n      }\n   }\n}\n\n/* Read any remaining signature bytes from the stream and compare them with\n * the correct PNG signature.  It is possible that this routine is called\n * with bytes already read from the signature, either because they have been\n * checked by the calling application, or because of multiple calls to this\n * routine.\n */\nvoid /* PRIVATE */\npng_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)\n{\n   size_t num_checked = png_ptr->sig_bytes; /* SAFE, does not exceed 8 */\n   size_t num_to_check = 8 - num_checked;\n\n   if (png_ptr->buffer_size < num_to_check)\n   {\n      num_to_check = png_ptr->buffer_size;\n   }\n\n   png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),\n       num_to_check);\n   png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);\n\n   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))\n   {\n      if (num_checked < 4 &&\n          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))\n         png_error(png_ptr, \"Not a PNG file\");\n\n      else\n         png_error(png_ptr, \"PNG file corrupted by ASCII conversion\");\n   }\n   else\n   {\n      if (png_ptr->sig_bytes >= 8)\n      {\n         png_ptr->process_mode = PNG_READ_CHUNK_MODE;\n      }\n   }\n}\n\nvoid /* PRIVATE */\npng_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)\n{\n   png_uint_32 chunk_name;\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n   int keep; /* unknown handling method */\n#endif\n\n   /* First we make sure we have enough data for the 4-byte chunk name\n    * and the 4-byte chunk length before proceeding with decoding the\n    * chunk data.  To fully decode each of these chunks, we also make\n    * sure we have enough data in the buffer for the 4-byte CRC at the\n    * end of every chunk (except IDAT, which is handled separately).\n    */\n   if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)\n   {\n      png_byte chunk_length[4];\n      png_byte chunk_tag[4];\n\n      PNG_PUSH_SAVE_BUFFER_IF_LT(8)\n      png_push_fill_buffer(png_ptr, chunk_length, 4);\n      png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);\n      png_reset_crc(png_ptr);\n      png_crc_read(png_ptr, chunk_tag, 4);\n      png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);\n      png_check_chunk_name(png_ptr, png_ptr->chunk_name);\n      png_check_chunk_length(png_ptr, png_ptr->push_length);\n      png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;\n   }\n\n   chunk_name = png_ptr->chunk_name;\n\n   if (chunk_name == png_IDAT)\n   {\n      if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)\n         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;\n\n      /* If we reach an IDAT chunk, this means we have read all of the\n       * header chunks, and we can start reading the image (or if this\n       * is called after the image has been read - we have an error).\n       */\n      if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n         png_error(png_ptr, \"Missing IHDR before IDAT\");\n\n      else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&\n          (png_ptr->mode & PNG_HAVE_PLTE) == 0)\n         png_error(png_ptr, \"Missing PLTE before IDAT\");\n\n      png_ptr->process_mode = PNG_READ_IDAT_MODE;\n\n      if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n         if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0)\n            if (png_ptr->push_length == 0)\n               return;\n\n      png_ptr->mode |= PNG_HAVE_IDAT;\n\n      if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)\n         png_benign_error(png_ptr, \"Too many IDATs found\");\n   }\n\n   if (chunk_name == png_IHDR)\n   {\n      if (png_ptr->push_length != 13)\n         png_error(png_ptr, \"Invalid IHDR length\");\n\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n   else if (chunk_name == png_IEND)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);\n\n      png_ptr->process_mode = PNG_READ_DONE_MODE;\n      png_push_have_end(png_ptr, info_ptr);\n   }\n\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n   else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep);\n\n      if (chunk_name == png_PLTE)\n         png_ptr->mode |= PNG_HAVE_PLTE;\n   }\n#endif\n\n   else if (chunk_name == png_PLTE)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n   else if (chunk_name == png_IDAT)\n   {\n      png_ptr->idat_size = png_ptr->push_length;\n      png_ptr->process_mode = PNG_READ_IDAT_MODE;\n      png_push_have_info(png_ptr, info_ptr);\n      png_ptr->zstream.avail_out =\n          (uInt) PNG_ROWBYTES(png_ptr->pixel_depth,\n          png_ptr->iwidth) + 1;\n      png_ptr->zstream.next_out = png_ptr->row_buf;\n      return;\n   }\n\n#ifdef PNG_READ_gAMA_SUPPORTED\n   else if (png_ptr->chunk_name == png_gAMA)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_sBIT_SUPPORTED\n   else if (png_ptr->chunk_name == png_sBIT)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_cHRM_SUPPORTED\n   else if (png_ptr->chunk_name == png_cHRM)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_sRGB_SUPPORTED\n   else if (chunk_name == png_sRGB)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_iCCP_SUPPORTED\n   else if (png_ptr->chunk_name == png_iCCP)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_sPLT_SUPPORTED\n   else if (chunk_name == png_sPLT)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_tRNS_SUPPORTED\n   else if (chunk_name == png_tRNS)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_bKGD_SUPPORTED\n   else if (chunk_name == png_bKGD)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_hIST_SUPPORTED\n   else if (chunk_name == png_hIST)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_pHYs_SUPPORTED\n   else if (chunk_name == png_pHYs)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_oFFs_SUPPORTED\n   else if (chunk_name == png_oFFs)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);\n   }\n#endif\n\n#ifdef PNG_READ_pCAL_SUPPORTED\n   else if (chunk_name == png_pCAL)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_sCAL_SUPPORTED\n   else if (chunk_name == png_sCAL)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_tIME_SUPPORTED\n   else if (chunk_name == png_tIME)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_tEXt_SUPPORTED\n   else if (chunk_name == png_tEXt)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_zTXt_SUPPORTED\n   else if (chunk_name == png_zTXt)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);\n   }\n\n#endif\n#ifdef PNG_READ_iTXt_SUPPORTED\n   else if (chunk_name == png_iTXt)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);\n   }\n#endif\n\n   else\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_FULL\n      png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length,\n          PNG_HANDLE_CHUNK_AS_DEFAULT);\n   }\n\n   png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;\n}\n\nvoid PNGCBAPI\npng_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length)\n{\n   png_bytep ptr;\n\n   if (png_ptr == NULL)\n      return;\n\n   ptr = buffer;\n   if (png_ptr->save_buffer_size != 0)\n   {\n      size_t save_size;\n\n      if (length < png_ptr->save_buffer_size)\n         save_size = length;\n\n      else\n         save_size = png_ptr->save_buffer_size;\n\n      memcpy(ptr, png_ptr->save_buffer_ptr, save_size);\n      length -= save_size;\n      ptr += save_size;\n      png_ptr->buffer_size -= save_size;\n      png_ptr->save_buffer_size -= save_size;\n      png_ptr->save_buffer_ptr += save_size;\n   }\n   if (length != 0 && png_ptr->current_buffer_size != 0)\n   {\n      size_t save_size;\n\n      if (length < png_ptr->current_buffer_size)\n         save_size = length;\n\n      else\n         save_size = png_ptr->current_buffer_size;\n\n      memcpy(ptr, png_ptr->current_buffer_ptr, save_size);\n      png_ptr->buffer_size -= save_size;\n      png_ptr->current_buffer_size -= save_size;\n      png_ptr->current_buffer_ptr += save_size;\n   }\n}\n\nvoid /* PRIVATE */\npng_push_save_buffer(png_structrp png_ptr)\n{\n   if (png_ptr->save_buffer_size != 0)\n   {\n      if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)\n      {\n         size_t i, istop;\n         png_bytep sp;\n         png_bytep dp;\n\n         istop = png_ptr->save_buffer_size;\n         for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;\n             i < istop; i++, sp++, dp++)\n         {\n            *dp = *sp;\n         }\n      }\n   }\n   if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >\n       png_ptr->save_buffer_max)\n   {\n      size_t new_max;\n      png_bytep old_buffer;\n\n      if (png_ptr->save_buffer_size > PNG_SIZE_MAX -\n          (png_ptr->current_buffer_size + 256))\n      {\n         png_error(png_ptr, \"Potential overflow of save_buffer\");\n      }\n\n      new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;\n      old_buffer = png_ptr->save_buffer;\n      png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,\n          (size_t)new_max);\n\n      if (png_ptr->save_buffer == NULL)\n      {\n         png_free(png_ptr, old_buffer);\n         png_error(png_ptr, \"Insufficient memory for save_buffer\");\n      }\n\n      if (old_buffer)\n         memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);\n      else if (png_ptr->save_buffer_size)\n         png_error(png_ptr, \"save_buffer error\");\n      png_free(png_ptr, old_buffer);\n      png_ptr->save_buffer_max = new_max;\n   }\n   if (png_ptr->current_buffer_size)\n   {\n      memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,\n         png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);\n      png_ptr->save_buffer_size += png_ptr->current_buffer_size;\n      png_ptr->current_buffer_size = 0;\n   }\n   png_ptr->save_buffer_ptr = png_ptr->save_buffer;\n   png_ptr->buffer_size = 0;\n}\n\nvoid /* PRIVATE */\npng_push_restore_buffer(png_structrp png_ptr, png_bytep buffer,\n    size_t buffer_length)\n{\n   png_ptr->current_buffer = buffer;\n   png_ptr->current_buffer_size = buffer_length;\n   png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;\n   png_ptr->current_buffer_ptr = png_ptr->current_buffer;\n}\n\nvoid /* PRIVATE */\npng_push_read_IDAT(png_structrp png_ptr)\n{\n   if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0)\n   {\n      png_byte chunk_length[4];\n      png_byte chunk_tag[4];\n\n      /* TODO: this code can be commoned up with the same code in push_read */\n      PNG_PUSH_SAVE_BUFFER_IF_LT(8)\n      png_push_fill_buffer(png_ptr, chunk_length, 4);\n      png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);\n      png_reset_crc(png_ptr);\n      png_crc_read(png_ptr, chunk_tag, 4);\n      png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);\n      png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;\n\n      if (png_ptr->chunk_name != png_IDAT)\n      {\n         png_ptr->process_mode = PNG_READ_CHUNK_MODE;\n\n         if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)\n            png_error(png_ptr, \"Not enough compressed data\");\n\n         return;\n      }\n\n      png_ptr->idat_size = png_ptr->push_length;\n   }\n\n   if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)\n   {\n      size_t save_size = png_ptr->save_buffer_size;\n      png_uint_32 idat_size = png_ptr->idat_size;\n\n      /* We want the smaller of 'idat_size' and 'current_buffer_size', but they\n       * are of different types and we don't know which variable has the fewest\n       * bits.  Carefully select the smaller and cast it to the type of the\n       * larger - this cannot overflow.  Do not cast in the following test - it\n       * will break on either 16-bit or 64-bit platforms.\n       */\n      if (idat_size < save_size)\n         save_size = (size_t)idat_size;\n\n      else\n         idat_size = (png_uint_32)save_size;\n\n      png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);\n\n      png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);\n\n      png_ptr->idat_size -= idat_size;\n      png_ptr->buffer_size -= save_size;\n      png_ptr->save_buffer_size -= save_size;\n      png_ptr->save_buffer_ptr += save_size;\n   }\n\n   if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0)\n   {\n      size_t save_size = png_ptr->current_buffer_size;\n      png_uint_32 idat_size = png_ptr->idat_size;\n\n      /* We want the smaller of 'idat_size' and 'current_buffer_size', but they\n       * are of different types and we don't know which variable has the fewest\n       * bits.  Carefully select the smaller and cast it to the type of the\n       * larger - this cannot overflow.\n       */\n      if (idat_size < save_size)\n         save_size = (size_t)idat_size;\n\n      else\n         idat_size = (png_uint_32)save_size;\n\n      png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);\n\n      png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);\n\n      png_ptr->idat_size -= idat_size;\n      png_ptr->buffer_size -= save_size;\n      png_ptr->current_buffer_size -= save_size;\n      png_ptr->current_buffer_ptr += save_size;\n   }\n\n   if (png_ptr->idat_size == 0)\n   {\n      PNG_PUSH_SAVE_BUFFER_IF_LT(4)\n      png_crc_finish(png_ptr, 0);\n      png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;\n      png_ptr->mode |= PNG_AFTER_IDAT;\n      png_ptr->zowner = 0;\n   }\n}\n\nvoid /* PRIVATE */\npng_process_IDAT_data(png_structrp png_ptr, png_bytep buffer,\n    size_t buffer_length)\n{\n   /* The caller checks for a non-zero buffer length. */\n   if (!(buffer_length > 0) || buffer == NULL)\n      png_error(png_ptr, \"No IDAT data (internal error)\");\n\n   /* This routine must process all the data it has been given\n    * before returning, calling the row callback as required to\n    * handle the uncompressed results.\n    */\n   png_ptr->zstream.next_in = buffer;\n   /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */\n   png_ptr->zstream.avail_in = (uInt)buffer_length;\n\n   /* Keep going until the decompressed data is all processed\n    * or the stream marked as finished.\n    */\n   while (png_ptr->zstream.avail_in > 0 &&\n      (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)\n   {\n      int ret;\n\n      /* We have data for zlib, but we must check that zlib\n       * has someplace to put the results.  It doesn't matter\n       * if we don't expect any results -- it may be the input\n       * data is just the LZ end code.\n       */\n      if (!(png_ptr->zstream.avail_out > 0))\n      {\n         /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */\n         png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth,\n             png_ptr->iwidth) + 1);\n\n         png_ptr->zstream.next_out = png_ptr->row_buf;\n      }\n\n      /* Using Z_SYNC_FLUSH here means that an unterminated\n       * LZ stream (a stream with a missing end code) can still\n       * be handled, otherwise (Z_NO_FLUSH) a future zlib\n       * implementation might defer output and therefore\n       * change the current behavior (see comments in inflate.c\n       * for why this doesn't happen at present with zlib 1.2.5).\n       */\n      ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH);\n\n      /* Check for any failure before proceeding. */\n      if (ret != Z_OK && ret != Z_STREAM_END)\n      {\n         /* Terminate the decompression. */\n         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\n         png_ptr->zowner = 0;\n\n         /* This may be a truncated stream (missing or\n          * damaged end code).  Treat that as a warning.\n          */\n         if (png_ptr->row_number >= png_ptr->num_rows ||\n             png_ptr->pass > 6)\n            png_warning(png_ptr, \"Truncated compressed data in IDAT\");\n\n         else\n         {\n            if (ret == Z_DATA_ERROR)\n               png_benign_error(png_ptr, \"IDAT: ADLER32 checksum mismatch\");\n            else\n               png_error(png_ptr, \"Decompression error in IDAT\");\n         }\n\n         /* Skip the check on unprocessed input */\n         return;\n      }\n\n      /* Did inflate output any data? */\n      if (png_ptr->zstream.next_out != png_ptr->row_buf)\n      {\n         /* Is this unexpected data after the last row?\n          * If it is, artificially terminate the LZ output\n          * here.\n          */\n         if (png_ptr->row_number >= png_ptr->num_rows ||\n             png_ptr->pass > 6)\n         {\n            /* Extra data. */\n            png_warning(png_ptr, \"Extra compressed data in IDAT\");\n            png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\n            png_ptr->zowner = 0;\n\n            /* Do no more processing; skip the unprocessed\n             * input check below.\n             */\n            return;\n         }\n\n         /* Do we have a complete row? */\n         if (png_ptr->zstream.avail_out == 0)\n            png_push_process_row(png_ptr);\n      }\n\n      /* And check for the end of the stream. */\n      if (ret == Z_STREAM_END)\n         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\n   }\n\n   /* All the data should have been processed, if anything\n    * is left at this point we have bytes of IDAT data\n    * after the zlib end code.\n    */\n   if (png_ptr->zstream.avail_in > 0)\n      png_warning(png_ptr, \"Extra compression data in IDAT\");\n}\n\nvoid /* PRIVATE */\npng_push_process_row(png_structrp png_ptr)\n{\n   /* 1.5.6: row_info moved out of png_struct to a local here. */\n   png_row_info row_info;\n\n   row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */\n   row_info.color_type = png_ptr->color_type;\n   row_info.bit_depth = png_ptr->bit_depth;\n   row_info.channels = png_ptr->channels;\n   row_info.pixel_depth = png_ptr->pixel_depth;\n   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);\n\n   if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)\n   {\n      if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)\n         png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,\n            png_ptr->prev_row + 1, png_ptr->row_buf[0]);\n      else\n         png_error(png_ptr, \"bad adaptive filter value\");\n   }\n\n   /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before\n    * 1.5.6, while the buffer really is this big in current versions of libpng\n    * it may not be in the future, so this was changed just to copy the\n    * interlaced row count:\n    */\n   memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n   if (png_ptr->transformations != 0)\n      png_do_read_transformations(png_ptr, &row_info);\n#endif\n\n   /* The transformed pixel depth should match the depth now in row_info. */\n   if (png_ptr->transformed_pixel_depth == 0)\n   {\n      png_ptr->transformed_pixel_depth = row_info.pixel_depth;\n      if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)\n         png_error(png_ptr, \"progressive row overflow\");\n   }\n\n   else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)\n      png_error(png_ptr, \"internal progressive row size calculation error\");\n\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   /* Expand interlaced rows to full size */\n   if (png_ptr->interlaced != 0 &&\n       (png_ptr->transformations & PNG_INTERLACE) != 0)\n   {\n      if (png_ptr->pass < 6)\n         png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,\n             png_ptr->transformations);\n\n      switch (png_ptr->pass)\n      {\n         case 0:\n         {\n            int i;\n            for (i = 0; i < 8 && png_ptr->pass == 0; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */\n            }\n\n            if (png_ptr->pass == 2) /* Pass 1 might be empty */\n            {\n               for (i = 0; i < 4 && png_ptr->pass == 2; i++)\n               {\n                  png_push_have_row(png_ptr, NULL);\n                  png_read_push_finish_row(png_ptr);\n               }\n            }\n\n            if (png_ptr->pass == 4 && png_ptr->height <= 4)\n            {\n               for (i = 0; i < 2 && png_ptr->pass == 4; i++)\n               {\n                  png_push_have_row(png_ptr, NULL);\n                  png_read_push_finish_row(png_ptr);\n               }\n            }\n\n            if (png_ptr->pass == 6 && png_ptr->height <= 4)\n            {\n                png_push_have_row(png_ptr, NULL);\n                png_read_push_finish_row(png_ptr);\n            }\n\n            break;\n         }\n\n         case 1:\n         {\n            int i;\n            for (i = 0; i < 8 && png_ptr->pass == 1; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            if (png_ptr->pass == 2) /* Skip top 4 generated rows */\n            {\n               for (i = 0; i < 4 && png_ptr->pass == 2; i++)\n               {\n                  png_push_have_row(png_ptr, NULL);\n                  png_read_push_finish_row(png_ptr);\n               }\n            }\n\n            break;\n         }\n\n         case 2:\n         {\n            int i;\n\n            for (i = 0; i < 4 && png_ptr->pass == 2; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            for (i = 0; i < 4 && png_ptr->pass == 2; i++)\n            {\n               png_push_have_row(png_ptr, NULL);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            if (png_ptr->pass == 4) /* Pass 3 might be empty */\n            {\n               for (i = 0; i < 2 && png_ptr->pass == 4; i++)\n               {\n                  png_push_have_row(png_ptr, NULL);\n                  png_read_push_finish_row(png_ptr);\n               }\n            }\n\n            break;\n         }\n\n         case 3:\n         {\n            int i;\n\n            for (i = 0; i < 4 && png_ptr->pass == 3; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            if (png_ptr->pass == 4) /* Skip top two generated rows */\n            {\n               for (i = 0; i < 2 && png_ptr->pass == 4; i++)\n               {\n                  png_push_have_row(png_ptr, NULL);\n                  png_read_push_finish_row(png_ptr);\n               }\n            }\n\n            break;\n         }\n\n         case 4:\n         {\n            int i;\n\n            for (i = 0; i < 2 && png_ptr->pass == 4; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            for (i = 0; i < 2 && png_ptr->pass == 4; i++)\n            {\n               png_push_have_row(png_ptr, NULL);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            if (png_ptr->pass == 6) /* Pass 5 might be empty */\n            {\n               png_push_have_row(png_ptr, NULL);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            break;\n         }\n\n         case 5:\n         {\n            int i;\n\n            for (i = 0; i < 2 && png_ptr->pass == 5; i++)\n            {\n               png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            if (png_ptr->pass == 6) /* Skip top generated row */\n            {\n               png_push_have_row(png_ptr, NULL);\n               png_read_push_finish_row(png_ptr);\n            }\n\n            break;\n         }\n\n         default:\n         case 6:\n         {\n            png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n            png_read_push_finish_row(png_ptr);\n\n            if (png_ptr->pass != 6)\n               break;\n\n            png_push_have_row(png_ptr, NULL);\n            png_read_push_finish_row(png_ptr);\n         }\n      }\n   }\n   else\n#endif\n   {\n      png_push_have_row(png_ptr, png_ptr->row_buf + 1);\n      png_read_push_finish_row(png_ptr);\n   }\n}\n\nvoid /* PRIVATE */\npng_read_push_finish_row(png_structrp png_ptr)\n{\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};\n\n   /* Start of interlace block in the y direction */\n   static const png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};\n\n   /* Offset to next interlace block in the y direction */\n   static const png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};\n\n   /* Height of interlace block.  This is not currently used - if you need\n    * it, uncomment it here and in png.h\n   static const png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};\n   */\n#endif\n\n   png_ptr->row_number++;\n   if (png_ptr->row_number < png_ptr->num_rows)\n      return;\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   if (png_ptr->interlaced != 0)\n   {\n      png_ptr->row_number = 0;\n      memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);\n\n      do\n      {\n         png_ptr->pass++;\n         if ((png_ptr->pass == 1 && png_ptr->width < 5) ||\n             (png_ptr->pass == 3 && png_ptr->width < 3) ||\n             (png_ptr->pass == 5 && png_ptr->width < 2))\n            png_ptr->pass++;\n\n         if (png_ptr->pass > 7)\n            png_ptr->pass--;\n\n         if (png_ptr->pass >= 7)\n            break;\n\n         png_ptr->iwidth = (png_ptr->width +\n             png_pass_inc[png_ptr->pass] - 1 -\n             png_pass_start[png_ptr->pass]) /\n             png_pass_inc[png_ptr->pass];\n\n         if ((png_ptr->transformations & PNG_INTERLACE) != 0)\n            break;\n\n         png_ptr->num_rows = (png_ptr->height +\n             png_pass_yinc[png_ptr->pass] - 1 -\n             png_pass_ystart[png_ptr->pass]) /\n             png_pass_yinc[png_ptr->pass];\n\n      } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);\n   }\n#endif /* READ_INTERLACING */\n}\n\nvoid /* PRIVATE */\npng_push_have_info(png_structrp png_ptr, png_inforp info_ptr)\n{\n   if (png_ptr->info_fn != NULL)\n      (*(png_ptr->info_fn))(png_ptr, info_ptr);\n}\n\nvoid /* PRIVATE */\npng_push_have_end(png_structrp png_ptr, png_inforp info_ptr)\n{\n   if (png_ptr->end_fn != NULL)\n      (*(png_ptr->end_fn))(png_ptr, info_ptr);\n}\n\nvoid /* PRIVATE */\npng_push_have_row(png_structrp png_ptr, png_bytep row)\n{\n   if (png_ptr->row_fn != NULL)\n      (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,\n          (int)png_ptr->pass);\n}\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\nvoid PNGAPI\npng_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row,\n    png_const_bytep new_row)\n{\n   if (png_ptr == NULL)\n      return;\n\n   /* new_row is a flag here - if it is NULL then the app callback was called\n    * from an empty row (see the calls to png_struct::row_fn below), otherwise\n    * it must be png_ptr->row_buf+1\n    */\n   if (new_row != NULL)\n      png_combine_row(png_ptr, old_row, 1/*blocky display*/);\n}\n#endif /* READ_INTERLACING */\n\nvoid PNGAPI\npng_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr,\n    png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,\n    png_progressive_end_ptr end_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->info_fn = info_fn;\n   png_ptr->row_fn = row_fn;\n   png_ptr->end_fn = end_fn;\n\n   png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);\n}\n\npng_voidp PNGAPI\npng_get_progressive_ptr(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return (NULL);\n\n   return png_ptr->io_ptr;\n}\n#endif /* PROGRESSIVE_READ */\n"
  },
  {
    "path": "dlib/external/libpng/pngpriv.h",
    "content": "\n/* pngpriv.h - private declarations for use inside libpng\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n/* The symbols declared in this file (including the functions declared\n * as extern) are PRIVATE.  They are not part of the libpng public\n * interface, and are not recommended for use by regular applications.\n * Some of them may become public in the future; others may stay private,\n * change in an incompatible way, or even disappear.\n * Although the libpng users are not forbidden to include this header,\n * they should be well aware of the issues that may arise from doing so.\n */\n\n#ifndef PNGPRIV_H\n#define PNGPRIV_H\n\n/* Feature Test Macros.  The following are defined here to ensure that correctly\n * implemented libraries reveal the APIs libpng needs to build and hide those\n * that are not needed and potentially damaging to the compilation.\n *\n * Feature Test Macros must be defined before any system header is included (see\n * POSIX 1003.1 2.8.2 \"POSIX Symbols.\"\n *\n * These macros only have an effect if the operating system supports either\n * POSIX 1003.1 or C99, or both.  On other operating systems (particularly\n * Windows/Visual Studio) there is no effect; the OS specific tests below are\n * still required (as of 2011-05-02.)\n */\n#ifndef _POSIX_SOURCE\n# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */\n#endif\n\n#ifndef PNG_VERSION_INFO_ONLY\n/* Standard library headers not required by png.h: */\n#  include <stdlib.h>\n#  include <string.h>\n#endif\n\n#define PNGLIB_BUILD /*libpng is being built, not used*/\n\n/* If HAVE_CONFIG_H is defined during the build then the build system must\n * provide an appropriate \"config.h\" file on the include path.  The header file\n * must provide definitions as required below (search for \"HAVE_CONFIG_H\");\n * see configure.ac for more details of the requirements.  The macro\n * \"PNG_NO_CONFIG_H\" is provided for maintainers to test for dependencies on\n * 'configure'; define this macro to prevent the configure build including the\n * configure generated config.h.  Libpng is expected to compile without *any*\n * special build system support on a reasonably ANSI-C compliant system.\n */\n#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)\n#  include <config.h>\n\n   /* Pick up the definition of 'restrict' from config.h if it was read: */\n#  define PNG_RESTRICT restrict\n#endif\n\n/* To support symbol prefixing it is necessary to know *before* including png.h\n * whether the fixed point (and maybe other) APIs are exported, because if they\n * are not internal definitions may be required.  This is handled below just\n * before png.h is included, but load the configuration now if it is available.\n */\n#ifndef PNGLCONF_H\n#  include \"pnglibconf.h\"\n#endif\n\n/* Local renames may change non-exported API functions from png.h */\n#if defined(PNG_PREFIX) && !defined(PNGPREFIX_H)\n#  include \"pngprefix.h\"\n#endif\n\n#ifdef PNG_USER_CONFIG\n#  include \"pngusr.h\"\n   /* These should have been defined in pngusr.h */\n#  ifndef PNG_USER_PRIVATEBUILD\n#    define PNG_USER_PRIVATEBUILD \"Custom libpng build\"\n#  endif\n#  ifndef PNG_USER_DLLFNAME_POSTFIX\n#    define PNG_USER_DLLFNAME_POSTFIX \"Cb\"\n#  endif\n#endif\n\n/* Compile time options.\n * =====================\n * In a multi-arch build the compiler may compile the code several times for the\n * same object module, producing different binaries for different architectures.\n * When this happens configure-time setting of the target host options cannot be\n * done and this interferes with the handling of the ARM NEON optimizations, and\n * possibly other similar optimizations.  Put additional tests here; in general\n * this is needed when the same option can be changed at both compile time and\n * run time depending on the target OS (i.e. iOS vs Android.)\n *\n * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because\n * this is not possible with certain compilers (Oracle SUN OS CC), as a result\n * it is necessary to ensure that all extern functions that *might* be used\n * regardless of $(CFLAGS) get declared in this file.  The test on __ARM_NEON__\n * below is one example of this behavior because it is controlled by the\n * presence or not of -mfpu=neon on the GCC command line, it is possible to do\n * this in $(CC), e.g. \"CC=gcc -mfpu=neon\", but people who build libpng rarely\n * do this.\n */\n#ifndef PNG_ARM_NEON_OPT\n   /* ARM NEON optimizations are being controlled by the compiler settings,\n    * typically the target FPU.  If the FPU has been set to NEON (-mfpu=neon\n    * with GCC) then the compiler will define __ARM_NEON__ and we can rely\n    * unconditionally on NEON instructions not crashing, otherwise we must\n    * disable use of NEON instructions.\n    *\n    * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they\n    * can only be turned on automatically if that is supported too.  If\n    * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail\n    * to compile with an appropriate #error if ALIGNED_MEMORY has been turned\n    * off.\n    *\n    * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated\n    * __ARM_NEON__, so we check both variants.\n    *\n    * To disable ARM_NEON optimizations entirely, and skip compiling the\n    * associated assembler code, pass --enable-arm-neon=no to configure\n    * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS.\n    */\n#  if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \\\n   defined(PNG_ALIGNED_MEMORY_SUPPORTED)\n#     define PNG_ARM_NEON_OPT 2\n#  else\n#     define PNG_ARM_NEON_OPT 0\n#  endif\n#endif\n\n#if PNG_ARM_NEON_OPT > 0\n   /* NEON optimizations are to be at least considered by libpng, so enable the\n    * callbacks to do this.\n    */\n#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon\n\n   /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used\n    * if possible - if __ARM_NEON__ is set and the compiler version is not known\n    * to be broken.  This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can\n    * be:\n    *\n    *    1  The intrinsics code (the default with __ARM_NEON__)\n    *    2  The hand coded assembler (the default without __ARM_NEON__)\n    *\n    * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however\n    * this is *NOT* supported and may cease to work even after a minor revision\n    * to libpng.  It *is* valid to do this for testing purposes, e.g. speed\n    * testing or a new compiler, but the results should be communicated to the\n    * libpng implementation list for incorporation in the next minor release.\n    */\n#  ifndef PNG_ARM_NEON_IMPLEMENTATION\n#     if defined(__ARM_NEON__) || defined(__ARM_NEON)\n#        if defined(__clang__)\n            /* At present it is unknown by the libpng developers which versions\n             * of clang support the intrinsics, however some or perhaps all\n             * versions do not work with the assembler so this may be\n             * irrelevant, so just use the default (do nothing here.)\n             */\n#        elif defined(__GNUC__)\n            /* GCC 4.5.4 NEON support is known to be broken.  4.6.3 is known to\n             * work, so if this *is* GCC, or G++, look for a version >4.5\n             */\n#           if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6)\n#              define PNG_ARM_NEON_IMPLEMENTATION 2\n#           endif /* no GNUC support */\n#        endif /* __GNUC__ */\n#     else /* !defined __ARM_NEON__ */\n         /* The 'intrinsics' code simply won't compile without this -mfpu=neon:\n          */\n#        if !defined(__aarch64__)\n            /* The assembler code currently does not work on ARM64 */\n#          define PNG_ARM_NEON_IMPLEMENTATION 2\n#        endif /* __aarch64__ */\n#     endif /* __ARM_NEON__ */\n#  endif /* !PNG_ARM_NEON_IMPLEMENTATION */\n\n#  ifndef PNG_ARM_NEON_IMPLEMENTATION\n      /* Use the intrinsics code by default. */\n#     define PNG_ARM_NEON_IMPLEMENTATION 1\n#  endif\n#endif /* PNG_ARM_NEON_OPT > 0 */\n\n#ifndef PNG_MIPS_MSA_OPT\n#  if defined(__mips_msa) && (__mips_isa_rev >= 5) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)\n#     define PNG_MIPS_MSA_OPT 2\n#  else\n#     define PNG_MIPS_MSA_OPT 0\n#  endif\n#endif\n\n#ifndef PNG_POWERPC_VSX_OPT\n#  if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)\n#     define PNG_POWERPC_VSX_OPT 2\n#  else\n#     define PNG_POWERPC_VSX_OPT 0\n#  endif\n#endif\n\n#ifndef PNG_INTEL_SSE_OPT\n#   ifdef PNG_INTEL_SSE\n      /* Only check for SSE if the build configuration has been modified to\n       * enable SSE optimizations.  This means that these optimizations will\n       * be off by default.  See contrib/intel for more details.\n       */\n#     if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \\\n       defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \\\n       (defined(_M_IX86_FP) && _M_IX86_FP >= 2)\n#         define PNG_INTEL_SSE_OPT 1\n#      else\n#         define PNG_INTEL_SSE_OPT 0\n#      endif\n#   else\n#      define PNG_INTEL_SSE_OPT 0\n#   endif\n#endif\n\n#if PNG_INTEL_SSE_OPT > 0\n#   ifndef PNG_INTEL_SSE_IMPLEMENTATION\n#      if defined(__SSE4_1__) || defined(__AVX__)\n          /* We are not actually using AVX, but checking for AVX is the best\n             way we can detect SSE4.1 and SSSE3 on MSVC.\n          */\n#         define PNG_INTEL_SSE_IMPLEMENTATION 3\n#      elif defined(__SSSE3__)\n#         define PNG_INTEL_SSE_IMPLEMENTATION 2\n#      elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \\\n       (defined(_M_IX86_FP) && _M_IX86_FP >= 2)\n#         define PNG_INTEL_SSE_IMPLEMENTATION 1\n#      else\n#         define PNG_INTEL_SSE_IMPLEMENTATION 0\n#      endif\n#   endif\n\n#   if PNG_INTEL_SSE_IMPLEMENTATION > 0\n#      define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2\n#   endif\n#else\n#   define PNG_INTEL_SSE_IMPLEMENTATION 0\n#endif\n\n#if PNG_MIPS_MSA_OPT > 0\n#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_msa\n#  ifndef PNG_MIPS_MSA_IMPLEMENTATION\n#     if defined(__mips_msa)\n#        if defined(__clang__)\n#        elif defined(__GNUC__)\n#           if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)\n#              define PNG_MIPS_MSA_IMPLEMENTATION 2\n#           endif /* no GNUC support */\n#        endif /* __GNUC__ */\n#     else /* !defined __mips_msa */\n#        define PNG_MIPS_MSA_IMPLEMENTATION 2\n#     endif /* __mips_msa */\n#  endif /* !PNG_MIPS_MSA_IMPLEMENTATION */\n\n#  ifndef PNG_MIPS_MSA_IMPLEMENTATION\n#     define PNG_MIPS_MSA_IMPLEMENTATION 1\n#  endif\n#endif /* PNG_MIPS_MSA_OPT > 0 */\n\n#if PNG_POWERPC_VSX_OPT > 0\n#  define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx\n#  define PNG_POWERPC_VSX_IMPLEMENTATION 1\n#endif\n\n\n/* Is this a build of a DLL where compilation of the object modules requires\n * different preprocessor settings to those required for a simple library?  If\n * so PNG_BUILD_DLL must be set.\n *\n * If libpng is used inside a DLL but that DLL does not export the libpng APIs\n * PNG_BUILD_DLL must not be set.  To avoid the code below kicking in build a\n * static library of libpng then link the DLL against that.\n */\n#ifndef PNG_BUILD_DLL\n#  ifdef DLL_EXPORT\n      /* This is set by libtool when files are compiled for a DLL; libtool\n       * always compiles twice, even on systems where it isn't necessary.  Set\n       * PNG_BUILD_DLL in case it is necessary:\n       */\n#     define PNG_BUILD_DLL\n#  else\n#     ifdef _WINDLL\n         /* This is set by the Microsoft Visual Studio IDE in projects that\n          * build a DLL.  It can't easily be removed from those projects (it\n          * isn't visible in the Visual Studio UI) so it is a fairly reliable\n          * indication that PNG_IMPEXP needs to be set to the DLL export\n          * attributes.\n          */\n#        define PNG_BUILD_DLL\n#     else\n#        ifdef __DLL__\n            /* This is set by the Borland C system when compiling for a DLL\n             * (as above.)\n             */\n#           define PNG_BUILD_DLL\n#        else\n            /* Add additional compiler cases here. */\n#        endif\n#     endif\n#  endif\n#endif /* Setting PNG_BUILD_DLL if required */\n\n/* See pngconf.h for more details: the builder of the library may set this on\n * the command line to the right thing for the specific compilation system or it\n * may be automagically set above (at present we know of no system where it does\n * need to be set on the command line.)\n *\n * PNG_IMPEXP must be set here when building the library to prevent pngconf.h\n * setting it to the \"import\" setting for a DLL build.\n */\n#ifndef PNG_IMPEXP\n#  ifdef PNG_BUILD_DLL\n#     define PNG_IMPEXP PNG_DLL_EXPORT\n#  else\n      /* Not building a DLL, or the DLL doesn't require specific export\n       * definitions.\n       */\n#     define PNG_IMPEXP\n#  endif\n#endif\n\n/* No warnings for private or deprecated functions in the build: */\n#ifndef PNG_DEPRECATED\n#  define PNG_DEPRECATED\n#endif\n#ifndef PNG_PRIVATE\n#  define PNG_PRIVATE\n#endif\n\n/* Symbol preprocessing support.\n *\n * To enable listing global, but internal, symbols the following macros should\n * always be used to declare an extern data or function object in this file.\n */\n#ifndef PNG_INTERNAL_DATA\n#  define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array\n#endif\n\n#ifndef PNG_INTERNAL_FUNCTION\n#  define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\\\n      PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes)\n#endif\n\n#ifndef PNG_INTERNAL_CALLBACK\n#  define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\\\n      PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\\\n         PNG_EMPTY attributes)\n#endif\n\n/* If floating or fixed point APIs are disabled they may still be compiled\n * internally.  To handle this make sure they are declared as the appropriate\n * internal extern function (otherwise the symbol prefixing stuff won't work and\n * the functions will be used without definitions.)\n *\n * NOTE: although all the API functions are declared here they are not all\n * actually built!  Because the declarations are still made it is necessary to\n * fake out types that they depend on.\n */\n#ifndef PNG_FP_EXPORT\n#  ifndef PNG_FLOATING_POINT_SUPPORTED\n#     define PNG_FP_EXPORT(ordinal, type, name, args)\\\n         PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);\n#     ifndef PNG_VERSION_INFO_ONLY\n         typedef struct png_incomplete png_double;\n         typedef png_double*           png_doublep;\n         typedef const png_double*     png_const_doublep;\n         typedef png_double**          png_doublepp;\n#     endif\n#  endif\n#endif\n#ifndef PNG_FIXED_EXPORT\n#  ifndef PNG_FIXED_POINT_SUPPORTED\n#     define PNG_FIXED_EXPORT(ordinal, type, name, args)\\\n         PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY);\n#  endif\n#endif\n\n#include \"png.h\"\n\n/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */\n#ifndef PNG_DLL_EXPORT\n#  define PNG_DLL_EXPORT\n#endif\n\n/* This is a global switch to set the compilation for an installed system\n * (a release build).  It can be set for testing debug builds to ensure that\n * they will compile when the build type is switched to RC or STABLE, the\n * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE.  Set this in CPPFLAGS\n * with either:\n *\n *   -DPNG_RELEASE_BUILD Turns on the release compile path\n *   -DPNG_RELEASE_BUILD=0 Turns it off\n * or in your pngusr.h with\n *   #define PNG_RELEASE_BUILD=1 Turns on the release compile path\n *   #define PNG_RELEASE_BUILD=0 Turns it off\n */\n#ifndef PNG_RELEASE_BUILD\n#  define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC)\n#endif\n\n/* SECURITY and SAFETY:\n *\n * libpng is built with support for internal limits on image dimensions and\n * memory usage.  These are documented in scripts/pnglibconf.dfa of the\n * source and recorded in the machine generated header file pnglibconf.h.\n */\n\n/* If you are running on a machine where you cannot allocate more\n * than 64K of memory at once, uncomment this.  While libpng will not\n * normally need that much memory in a chunk (unless you load up a very\n * large file), zlib needs to know how big of a chunk it can use, and\n * libpng thus makes sure to check any memory allocation to verify it\n * will fit into memory.\n *\n * zlib provides 'MAXSEG_64K' which, if defined, indicates the\n * same limit and pngconf.h (already included) sets the limit\n * if certain operating systems are detected.\n */\n#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)\n#  define PNG_MAX_MALLOC_64K\n#endif\n\n#ifndef PNG_UNUSED\n/* Unused formal parameter warnings are silenced using the following macro\n * which is expected to have no bad effects on performance (optimizing\n * compilers will probably remove it entirely).  Note that if you replace\n * it with something other than whitespace, you must include the terminating\n * semicolon.\n */\n#  define PNG_UNUSED(param) (void)param;\n#endif\n\n/* Just a little check that someone hasn't tried to define something\n * contradictory.\n */\n#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K)\n#  undef PNG_ZBUF_SIZE\n#  define PNG_ZBUF_SIZE 65536L\n#endif\n\n/* If warnings or errors are turned off the code is disabled or redirected here.\n * From 1.5.4 functions have been added to allow very limited formatting of\n * error and warning messages - this code will also be disabled here.\n */\n#ifdef PNG_WARNINGS_SUPPORTED\n#  define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;\n#else\n#  define png_warning_parameter(p,number,string) ((void)0)\n#  define png_warning_parameter_unsigned(p,number,format,value) ((void)0)\n#  define png_warning_parameter_signed(p,number,format,value) ((void)0)\n#  define png_formatted_warning(pp,p,message) ((void)(pp))\n#  define PNG_WARNING_PARAMETERS(p)\n#endif\n#ifndef PNG_ERROR_TEXT_SUPPORTED\n#  define png_fixed_error(s1,s2) png_err(s1)\n#endif\n\n/* Some fixed point APIs are still required even if not exported because\n * they get used by the corresponding floating point APIs.  This magic\n * deals with this:\n */\n#ifdef PNG_FIXED_POINT_SUPPORTED\n#  define PNGFAPI PNGAPI\n#else\n#  define PNGFAPI /* PRIVATE */\n#endif\n\n#ifndef PNG_VERSION_INFO_ONLY\n/* Other defines specific to compilers can go here.  Try to keep\n * them inside an appropriate ifdef/endif pair for portability.\n */\n\n/* C allows up-casts from (void*) to any pointer and (const void*) to any\n * pointer to a const object.  C++ regards this as a type error and requires an\n * explicit, static, cast and provides the static_cast<> rune to ensure that\n * const is not cast away.\n */\n#ifdef __cplusplus\n#  define png_voidcast(type, value) static_cast<type>(value)\n#  define png_constcast(type, value) const_cast<type>(value)\n#  define png_aligncast(type, value) \\\n   static_cast<type>(static_cast<void*>(value))\n#  define png_aligncastconst(type, value) \\\n   static_cast<type>(static_cast<const void*>(value))\n#else\n#  define png_voidcast(type, value) (value)\n#  ifdef _WIN64\n#     ifdef __GNUC__\n         typedef unsigned long long png_ptruint;\n#     else\n         typedef unsigned __int64 png_ptruint;\n#     endif\n#  else\n      typedef unsigned long png_ptruint;\n#  endif\n#  define png_constcast(type, value) ((type)(png_ptruint)(const void*)(value))\n#  define png_aligncast(type, value) ((void*)(value))\n#  define png_aligncastconst(type, value) ((const void*)(value))\n#endif /* __cplusplus */\n\n#if defined(PNG_FLOATING_POINT_SUPPORTED) ||\\\n    defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)\n   /* png.c requires the following ANSI-C constants if the conversion of\n    * floating point to ASCII is implemented therein:\n    *\n    *  DBL_DIG  Maximum number of decimal digits (can be set to any constant)\n    *  DBL_MIN  Smallest normalized fp number (can be set to an arbitrary value)\n    *  DBL_MAX  Maximum floating point number (can be set to an arbitrary value)\n    */\n#  include <float.h>\n\n#  if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \\\n    defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)\n   /* We need to check that <math.h> hasn't already been included earlier\n    * as it seems it doesn't agree with <fp.h>, yet we should really use\n    * <fp.h> if possible.\n    */\n#    if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)\n#      include <fp.h>\n#    endif\n#  else\n#    include <math.h>\n#  endif\n#  if defined(_AMIGA) && defined(__SASC) && defined(_M68881)\n   /* Amiga SAS/C: We must include builtin FPU functions when compiling using\n    * MATH=68881\n    */\n#    include <m68881.h>\n#  endif\n#endif\n\n/* This provides the non-ANSI (far) memory allocation routines. */\n#if defined(__TURBOC__) && defined(__MSDOS__)\n#  include <mem.h>\n#  include <alloc.h>\n#endif\n\n#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \\\n    defined(_WIN32) || defined(__WIN32__)\n#  include <windows.h>  /* defines _WINDOWS_ macro */\n#endif\n#endif /* PNG_VERSION_INFO_ONLY */\n\n/* Moved here around 1.5.0beta36 from pngconf.h */\n/* Users may want to use these so they are not private.  Any library\n * functions that are passed far data must be model-independent.\n */\n\n/* Memory model/platform independent fns */\n#ifndef PNG_ABORT\n#  ifdef _WINDOWS_\n#    define PNG_ABORT() ExitProcess(0)\n#  else\n#    define PNG_ABORT() abort()\n#  endif\n#endif\n\n/* These macros may need to be architecture dependent. */\n#define PNG_ALIGN_NONE   0 /* do not use data alignment */\n#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */\n#ifdef offsetof\n#  define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */\n#else\n#  define PNG_ALIGN_OFFSET -1 /* prevent the use of this */\n#endif\n#define PNG_ALIGN_SIZE   3 /* use sizeof to determine alignment */\n\n#ifndef PNG_ALIGN_TYPE\n   /* Default to using aligned access optimizations and requiring alignment to a\n    * multiple of the data type size.  Override in a compiler specific fashion\n    * if necessary by inserting tests here:\n    */\n#  define PNG_ALIGN_TYPE PNG_ALIGN_SIZE\n#endif\n\n#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE\n   /* This is used because in some compiler implementations non-aligned\n    * structure members are supported, so the offsetof approach below fails.\n    * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access\n    * is good for performance.  Do not do this unless you have tested the result\n    * and understand it.\n    */\n#  define png_alignof(type) (sizeof (type))\n#else\n#  if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET\n#     define png_alignof(type) offsetof(struct{char c; type t;}, t)\n#  else\n#     if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS\n#        define png_alignof(type) (1)\n#     endif\n      /* Else leave png_alignof undefined to prevent use thereof */\n#  endif\n#endif\n\n/* This implicitly assumes alignment is always to a power of 2. */\n#ifdef png_alignof\n#  define png_isaligned(ptr, type)\\\n   (((type)((const char*)ptr-(const char*)0) & \\\n   (type)(png_alignof(type)-1)) == 0)\n#else\n#  define png_isaligned(ptr, type) 0\n#endif\n\n/* End of memory model/platform independent support */\n/* End of 1.5.0beta36 move from pngconf.h */\n\n/* CONSTANTS and UTILITY MACROS\n * These are used internally by libpng and not exposed in the API\n */\n\n/* Various modes of operation.  Note that after an init, mode is set to\n * zero automatically when the structure is created.  Three of these\n * are defined in png.h because they need to be visible to applications\n * that call png_set_unknown_chunk().\n */\n/* #define PNG_HAVE_IHDR            0x01U (defined in png.h) */\n/* #define PNG_HAVE_PLTE            0x02U (defined in png.h) */\n#define PNG_HAVE_IDAT               0x04U\n/* #define PNG_AFTER_IDAT           0x08U (defined in png.h) */\n#define PNG_HAVE_IEND               0x10U\n                   /*               0x20U (unused) */\n                   /*               0x40U (unused) */\n                   /*               0x80U (unused) */\n#define PNG_HAVE_CHUNK_HEADER      0x100U\n#define PNG_WROTE_tIME             0x200U\n#define PNG_WROTE_INFO_BEFORE_PLTE 0x400U\n#define PNG_BACKGROUND_IS_GRAY     0x800U\n#define PNG_HAVE_PNG_SIGNATURE    0x1000U\n#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */\n                   /*             0x4000U (unused) */\n#define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */\n\n/* Flags for the transformations the PNG library does on the image data */\n#define PNG_BGR                 0x0001U\n#define PNG_INTERLACE           0x0002U\n#define PNG_PACK                0x0004U\n#define PNG_SHIFT               0x0008U\n#define PNG_SWAP_BYTES          0x0010U\n#define PNG_INVERT_MONO         0x0020U\n#define PNG_QUANTIZE            0x0040U\n#define PNG_COMPOSE             0x0080U    /* Was PNG_BACKGROUND */\n#define PNG_BACKGROUND_EXPAND   0x0100U\n#define PNG_EXPAND_16           0x0200U    /* Added to libpng 1.5.2 */\n#define PNG_16_TO_8             0x0400U    /* Becomes 'chop' in 1.5.4 */\n#define PNG_RGBA                0x0800U\n#define PNG_EXPAND              0x1000U\n#define PNG_GAMMA               0x2000U\n#define PNG_GRAY_TO_RGB         0x4000U\n#define PNG_FILLER              0x8000U\n#define PNG_PACKSWAP           0x10000U\n#define PNG_SWAP_ALPHA         0x20000U\n#define PNG_STRIP_ALPHA        0x40000U\n#define PNG_INVERT_ALPHA       0x80000U\n#define PNG_USER_TRANSFORM    0x100000U\n#define PNG_RGB_TO_GRAY_ERR   0x200000U\n#define PNG_RGB_TO_GRAY_WARN  0x400000U\n#define PNG_RGB_TO_GRAY       0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */\n#define PNG_ENCODE_ALPHA      0x800000U /* Added to libpng-1.5.4 */\n#define PNG_ADD_ALPHA        0x1000000U /* Added to libpng-1.2.7 */\n#define PNG_EXPAND_tRNS      0x2000000U /* Added to libpng-1.2.9 */\n#define PNG_SCALE_16_TO_8    0x4000000U /* Added to libpng-1.5.4 */\n                       /*    0x8000000U unused */\n                       /*   0x10000000U unused */\n                       /*   0x20000000U unused */\n                       /*   0x40000000U unused */\n/* Flags for png_create_struct */\n#define PNG_STRUCT_PNG   0x0001U\n#define PNG_STRUCT_INFO  0x0002U\n\n/* Flags for the png_ptr->flags rather than declaring a byte for each one */\n#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY     0x0001U\n#define PNG_FLAG_ZSTREAM_INITIALIZED      0x0002U /* Added to libpng-1.6.0 */\n                                  /*      0x0004U    unused */\n#define PNG_FLAG_ZSTREAM_ENDED            0x0008U /* Added to libpng-1.6.0 */\n                                  /*      0x0010U    unused */\n                                  /*      0x0020U    unused */\n#define PNG_FLAG_ROW_INIT                 0x0040U\n#define PNG_FLAG_FILLER_AFTER             0x0080U\n#define PNG_FLAG_CRC_ANCILLARY_USE        0x0100U\n#define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200U\n#define PNG_FLAG_CRC_CRITICAL_USE         0x0400U\n#define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800U\n#define PNG_FLAG_ASSUME_sRGB              0x1000U /* Added to libpng-1.5.4 */\n#define PNG_FLAG_OPTIMIZE_ALPHA           0x2000U /* Added to libpng-1.5.4 */\n#define PNG_FLAG_DETECT_UNINITIALIZED     0x4000U /* Added to libpng-1.5.4 */\n/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS      0x8000U */\n/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS      0x10000U */\n#define PNG_FLAG_LIBRARY_MISMATCH        0x20000U\n#define PNG_FLAG_STRIP_ERROR_NUMBERS     0x40000U\n#define PNG_FLAG_STRIP_ERROR_TEXT        0x80000U\n#define PNG_FLAG_BENIGN_ERRORS_WARN     0x100000U /* Added to libpng-1.4.0 */\n#define PNG_FLAG_APP_WARNINGS_WARN      0x200000U /* Added to libpng-1.6.0 */\n#define PNG_FLAG_APP_ERRORS_WARN        0x400000U /* Added to libpng-1.6.0 */\n                                  /*    0x800000U    unused */\n                                  /*   0x1000000U    unused */\n                                  /*   0x2000000U    unused */\n                                  /*   0x4000000U    unused */\n                                  /*   0x8000000U    unused */\n                                  /*  0x10000000U    unused */\n                                  /*  0x20000000U    unused */\n                                  /*  0x40000000U    unused */\n\n#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \\\n                                     PNG_FLAG_CRC_ANCILLARY_NOWARN)\n\n#define PNG_FLAG_CRC_CRITICAL_MASK  (PNG_FLAG_CRC_CRITICAL_USE | \\\n                                     PNG_FLAG_CRC_CRITICAL_IGNORE)\n\n#define PNG_FLAG_CRC_MASK           (PNG_FLAG_CRC_ANCILLARY_MASK | \\\n                                     PNG_FLAG_CRC_CRITICAL_MASK)\n\n/* Save typing and make code easier to understand */\n\n#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \\\n   abs((int)((c1).green) - (int)((c2).green)) + \\\n   abs((int)((c1).blue) - (int)((c2).blue)))\n\n/* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255\n * by dividing by 257 *with rounding*.  This macro is exact for the given range.\n * See the discourse in pngrtran.c png_do_scale_16_to_8.  The values in the\n * macro were established by experiment (modifying the added value).  The macro\n * has a second variant that takes a value already scaled by 255 and divides by\n * 65535 - this has a maximum error of .502.  Over the range 0..65535*65535 it\n * only gives off-by-one errors and only for 0.5% (1 in 200) of the values.\n */\n#define PNG_DIV65535(v24) (((v24) + 32895) >> 16)\n#define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255)\n\n/* Added to libpng-1.2.6 JB */\n#define PNG_ROWBYTES(pixel_bits, width) \\\n    ((pixel_bits) >= 8 ? \\\n    ((size_t)(width) * (((size_t)(pixel_bits)) >> 3)) : \\\n    (( ((size_t)(width) * ((size_t)(pixel_bits))) + 7) >> 3) )\n\n/* This returns the number of trailing bits in the last byte of a row, 0 if the\n * last byte is completely full of pixels.  It is, in principle, (pixel_bits x\n * width) % 8, but that would overflow for large 'width'.  The second macro is\n * the same except that it returns the number of unused bits in the last byte;\n * (8-TRAILBITS), but 0 when TRAILBITS is 0.\n *\n * NOTE: these macros are intended to be self-evidently correct and never\n * overflow on the assumption that pixel_bits is in the range 0..255.  The\n * arguments are evaluated only once and they can be signed (e.g. as a result of\n * the integral promotions).  The result of the expression always has type\n * (png_uint_32), however the compiler always knows it is in the range 0..7.\n */\n#define PNG_TRAILBITS(pixel_bits, width) \\\n    (((pixel_bits) * ((width) % (png_uint_32)8)) % 8)\n\n#define PNG_PADBITS(pixel_bits, width) \\\n    ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8)\n\n/* PNG_OUT_OF_RANGE returns true if value is outside the range\n * ideal-delta..ideal+delta.  Each argument is evaluated twice.\n * \"ideal\" and \"delta\" should be constants, normally simple\n * integers, \"value\" a variable. Added to libpng-1.2.6 JB\n */\n#define PNG_OUT_OF_RANGE(value, ideal, delta) \\\n   ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )\n\n/* Conversions between fixed and floating point, only defined if\n * required (to make sure the code doesn't accidentally use float\n * when it is supposedly disabled.)\n */\n#ifdef PNG_FLOATING_POINT_SUPPORTED\n/* The floating point conversion can't overflow, though it can and\n * does lose accuracy relative to the original fixed point value.\n * In practice this doesn't matter because png_fixed_point only\n * stores numbers with very low precision.  The png_ptr and s\n * arguments are unused by default but are there in case error\n * checking becomes a requirement.\n */\n#define png_float(png_ptr, fixed, s) (.00001 * (fixed))\n\n/* The fixed point conversion performs range checking and evaluates\n * its argument multiple times, so must be used with care.  The\n * range checking uses the PNG specification values for a signed\n * 32-bit fixed point value except that the values are deliberately\n * rounded-to-zero to an integral value - 21474 (21474.83 is roughly\n * (2^31-1) * 100000). 's' is a string that describes the value being\n * converted.\n *\n * NOTE: this macro will raise a png_error if the range check fails,\n * therefore it is normally only appropriate to use this on values\n * that come from API calls or other sources where an out of range\n * error indicates a programming error, not a data error!\n *\n * NOTE: by default this is off - the macro is not used - because the\n * function call saves a lot of code.\n */\n#ifdef PNG_FIXED_POINT_MACRO_SUPPORTED\n#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\\\n    ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))\n#endif\n/* else the corresponding function is defined below, inside the scope of the\n * cplusplus test.\n */\n#endif\n\n/* Constants for known chunk types.  If you need to add a chunk, define the name\n * here.  For historical reasons these constants have the form png_<name>; i.e.\n * the prefix is lower case.  Please use decimal values as the parameters to\n * match the ISO PNG specification and to avoid relying on the C locale\n * interpretation of character values.\n *\n * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values\n * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string\n * to be generated if required.\n *\n * PNG_32b correctly produces a value shifted by up to 24 bits, even on\n * architectures where (int) is only 16 bits.\n */\n#define PNG_32b(b,s) ((png_uint_32)(b) << (s))\n#define PNG_U32(b1,b2,b3,b4) \\\n   (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))\n\n/* Constants for known chunk types.\n *\n * MAINTAINERS: If you need to add a chunk, define the name here.\n * For historical reasons these constants have the form png_<name>; i.e.\n * the prefix is lower case.  Please use decimal values as the parameters to\n * match the ISO PNG specification and to avoid relying on the C locale\n * interpretation of character values.  Please keep the list sorted.\n *\n * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk\n * type.  In fact the specification does not express chunk types this way,\n * however using a 32-bit value means that the chunk type can be read from the\n * stream using exactly the same code as used for a 32-bit unsigned value and\n * can be examined far more efficiently (using one arithmetic compare).\n *\n * Prior to 1.5.6 the chunk type constants were expressed as C strings.  The\n * libpng API still uses strings for 'unknown' chunks and a macro,\n * PNG_STRING_FROM_CHUNK, allows a string to be generated if required.  Notice\n * that for portable code numeric values must still be used; the string \"IHDR\"\n * is not portable and neither is PNG_U32('I', 'H', 'D', 'R').\n *\n * In 1.7.0 the definitions will be made public in png.h to avoid having to\n * duplicate the same definitions in application code.\n */\n#define png_IDAT PNG_U32( 73,  68,  65,  84)\n#define png_IEND PNG_U32( 73,  69,  78,  68)\n#define png_IHDR PNG_U32( 73,  72,  68,  82)\n#define png_PLTE PNG_U32( 80,  76,  84,  69)\n#define png_bKGD PNG_U32( 98,  75,  71,  68)\n#define png_cHRM PNG_U32( 99,  72,  82,  77)\n#define png_eXIf PNG_U32(101,  88,  73, 102) /* registered July 2017 */\n#define png_fRAc PNG_U32(102,  82,  65,  99) /* registered, not defined */\n#define png_gAMA PNG_U32(103,  65,  77,  65)\n#define png_gIFg PNG_U32(103,  73,  70, 103)\n#define png_gIFt PNG_U32(103,  73,  70, 116) /* deprecated */\n#define png_gIFx PNG_U32(103,  73,  70, 120)\n#define png_hIST PNG_U32(104,  73,  83,  84)\n#define png_iCCP PNG_U32(105,  67,  67,  80)\n#define png_iTXt PNG_U32(105,  84,  88, 116)\n#define png_oFFs PNG_U32(111,  70,  70, 115)\n#define png_pCAL PNG_U32(112,  67,  65,  76)\n#define png_pHYs PNG_U32(112,  72,  89, 115)\n#define png_sBIT PNG_U32(115,  66,  73,  84)\n#define png_sCAL PNG_U32(115,  67,  65,  76)\n#define png_sPLT PNG_U32(115,  80,  76,  84)\n#define png_sRGB PNG_U32(115,  82,  71,  66)\n#define png_sTER PNG_U32(115,  84,  69,  82)\n#define png_tEXt PNG_U32(116,  69,  88, 116)\n#define png_tIME PNG_U32(116,  73,  77,  69)\n#define png_tRNS PNG_U32(116,  82,  78,  83)\n#define png_zTXt PNG_U32(122,  84,  88, 116)\n\n/* The following will work on (signed char*) strings, whereas the get_uint_32\n * macro will fail on top-bit-set values because of the sign extension.\n */\n#define PNG_CHUNK_FROM_STRING(s)\\\n   PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3])\n\n/* This uses (char), not (png_byte) to avoid warnings on systems where (char) is\n * signed and the argument is a (char[])  This macro will fail miserably on\n * systems where (char) is more than 8 bits.\n */\n#define PNG_STRING_FROM_CHUNK(s,c)\\\n   (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \\\n   ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\\\n   ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \\\n   ((char*)(s))[3]=(char)((c & 0xff)))\n\n/* Do the same but terminate with a null character. */\n#define PNG_CSTRING_FROM_CHUNK(s,c)\\\n   (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0)\n\n/* Test on flag values as defined in the spec (section 5.4): */\n#define PNG_CHUNK_ANCILLARY(c)   (1 & ((c) >> 29))\n#define PNG_CHUNK_CRITICAL(c)     (!PNG_CHUNK_ANCILLARY(c))\n#define PNG_CHUNK_PRIVATE(c)      (1 & ((c) >> 21))\n#define PNG_CHUNK_RESERVED(c)     (1 & ((c) >> 13))\n#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >>  5))\n\n/* Gamma values (new at libpng-1.5.4): */\n#define PNG_GAMMA_MAC_OLD 151724  /* Assume '1.8' is really 2.2/1.45! */\n#define PNG_GAMMA_MAC_INVERSE 65909\n#define PNG_GAMMA_sRGB_INVERSE 45455\n\n/* Almost everything below is C specific; the #defines above can be used in\n * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.\n */\n#ifndef PNG_VERSION_INFO_ONLY\n\n#include \"pngstruct.h\"\n#include \"pnginfo.h\"\n\n/* Validate the include paths - the include path used to generate pnglibconf.h\n * must match that used in the build, or we must be using pnglibconf.h.prebuilt:\n */\n#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM\n#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \\\n      \"-I (include path) error: see the notes in pngpriv.h\"\n   /* This means that when pnglibconf.h was built the copy of zlib.h that it\n    * used is not the same as the one being used here.  Because the build of\n    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the\n    * zlib version number and because this affects handling of certain broken\n    * PNG files the -I directives must match.\n    *\n    * The most likely explanation is that you passed a -I in CFLAGS. This will\n    * not work; all the preprocessor directives and in particular all the -I\n    * directives must be in CPPFLAGS.\n    */\n#endif\n\n/* This is used for 16-bit gamma tables -- only the top level pointers are\n * const; this could be changed:\n */\ntypedef const png_uint_16p * png_const_uint_16pp;\n\n/* Added to libpng-1.5.7: sRGB conversion tables */\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\\\n   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\n#ifdef PNG_SIMPLIFIED_READ_SUPPORTED\nPNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]);\n   /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value,\n    * 0..65535.  This table gives the closest 16-bit answers (no errors).\n    */\n#endif\n\nPNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]);\nPNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]);\n\n#define PNG_sRGB_FROM_LINEAR(linear) \\\n  ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \\\n   + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)))\n   /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB\n    * encoded value with maximum error 0.646365.  Note that the input is not a\n    * 16-bit value; it has been multiplied by 255! */\n#endif /* SIMPLIFIED_READ/WRITE */\n\n\n/* Inhibit C++ name-mangling for libpng functions but not for system calls. */\n#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n\n/* Internal functions; these are not exported from a DLL however because they\n * are used within several of the C source files they have to be C extern.\n *\n * All of these functions must be declared with PNG_INTERNAL_FUNCTION.\n */\n\n/* Zlib support */\n#define PNG_UNEXPECTED_ZLIB_RETURN (-7)\nPNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret),\n   PNG_EMPTY);\n   /* Used by the zlib handling functions to ensure that z_stream::msg is always\n    * set before they return.\n    */\n\n#ifdef PNG_WRITE_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,\n   png_compression_bufferp *list),PNG_EMPTY);\n   /* Free the buffer list used by the compressed write code. */\n#endif\n\n#if defined(PNG_FLOATING_POINT_SUPPORTED) && \\\n   !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \\\n   (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \\\n   defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \\\n   (defined(PNG_sCAL_SUPPORTED) && \\\n   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))\nPNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr,\n   double fp, png_const_charp text),PNG_EMPTY);\n#endif\n\n/* Check the user version string for compatibility, returns false if the version\n * numbers aren't compatible.\n */\nPNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr,\n   png_const_charp user_png_ver),PNG_EMPTY);\n\n/* Internal base allocator - no messages, NULL on failure to allocate.  This\n * does, however, call the application provided allocator and that could call\n * png_error (although that would be a bug in the application implementation.)\n */\nPNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr,\n   png_alloc_size_t size),PNG_ALLOCATED);\n\n#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\\\n   defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED)\n/* Internal array allocator, outputs no error or warning messages on failure,\n * just returns NULL.\n */\nPNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr,\n   int nelements, size_t element_size),PNG_ALLOCATED);\n\n/* The same but an existing array is extended by add_elements.  This function\n * also memsets the new elements to 0 and copies the old elements.  The old\n * array is not freed or altered.\n */\nPNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr,\n   png_const_voidp array, int old_elements, int add_elements,\n   size_t element_size),PNG_ALLOCATED);\n#endif /* text, sPLT or unknown chunks */\n\n/* Magic to create a struct when there is no struct to call the user supplied\n * memory allocators.  Because error handling has not been set up the memory\n * handlers can't safely call png_error, but this is an obscure and undocumented\n * restriction so libpng has to assume that the 'free' handler, at least, might\n * call png_error.\n */\nPNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct,\n   (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn,\n    png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn,\n    png_free_ptr free_fn),PNG_ALLOCATED);\n\n/* Free memory from internal libpng struct */\nPNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr),\n   PNG_EMPTY);\n\n/* Free an allocated jmp_buf (always succeeds) */\nPNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY);\n\n/* Function to allocate memory for zlib.  PNGAPI is disallowed. */\nPNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size),\n   PNG_ALLOCATED);\n\n/* Function to free memory for zlib.  PNGAPI is disallowed. */\nPNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY);\n\n/* Next four functions are used internally as callbacks.  PNGCBAPI is required\n * but not PNG_EXPORT.  PNGAPI added at libpng version 1.2.3, changed to\n * PNGCBAPI at 1.5.0\n */\n\nPNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr,\n    png_bytep data, size_t length),PNG_EMPTY);\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\nPNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr,\n    png_bytep buffer, size_t length),PNG_EMPTY);\n#endif\n\nPNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr,\n    png_bytep data, size_t length),PNG_EMPTY);\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n#  ifdef PNG_STDIO_SUPPORTED\nPNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr),\n   PNG_EMPTY);\n#  endif\n#endif\n\n/* Reset the CRC variable */\nPNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY);\n\n/* Write the \"data\" buffer to whatever output you are using */\nPNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr,\n    png_const_bytep data, size_t length),PNG_EMPTY);\n\n/* Read and check the PNG file signature */\nPNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr,\n   png_inforp info_ptr),PNG_EMPTY);\n\n/* Read the chunk header (length + type name) */\nPNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr),\n   PNG_EMPTY);\n\n/* Read data from whatever input you are using into the \"data\" buffer */\nPNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data,\n    size_t length),PNG_EMPTY);\n\n/* Read bytes into buf, and update png_ptr->crc */\nPNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,\n    png_uint_32 length),PNG_EMPTY);\n\n/* Read \"skip\" bytes, read the file crc, and (optionally) verify png_ptr->crc */\nPNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,\n   png_uint_32 skip),PNG_EMPTY);\n\n/* Read the CRC from the file and compare it to the libpng calculated CRC */\nPNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY);\n\n/* Calculate the CRC over a section of data.  Note that we are only\n * passing a maximum of 64K on systems that have this as a memory limit,\n * since this is the maximum buffer size we can specify.\n */\nPNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,\n   png_const_bytep ptr, size_t length),PNG_EMPTY);\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);\n#endif\n\n/* Write various chunks */\n\n/* Write the IHDR chunk, and update the png_struct with the necessary\n * information.\n */\nPNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr,\n   png_uint_32 width, png_uint_32 height, int bit_depth, int color_type,\n   int compression_method, int filter_method, int interlace_method),PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr,\n   png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr,\n   png_const_bytep row_data, png_alloc_size_t row_data_length, int flush),\n   PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY);\n\n#ifdef PNG_WRITE_gAMA_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr,\n    png_fixed_point file_gamma),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_sBIT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr,\n    png_const_color_8p sbit, int color_type),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_cHRM_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr,\n    const png_xy *xy), PNG_EMPTY);\n   /* The xy value must have been previously validated */\n#endif\n\n#ifdef PNG_WRITE_sRGB_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr,\n    int intent),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_eXIf_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr,\n    png_bytep exif, int num_exif),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_iCCP_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr,\n   png_const_charp name, png_const_bytep profile), PNG_EMPTY);\n   /* The profile must have been previously validated for correctness, the\n    * length comes from the first four bytes.  Only the base, deflate,\n    * compression is supported.\n    */\n#endif\n\n#ifdef PNG_WRITE_sPLT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr,\n    png_const_sPLT_tp palette),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_tRNS_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr,\n    png_const_bytep trans, png_const_color_16p values, int number,\n    int color_type),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_bKGD_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr,\n    png_const_color_16p values, int color_type),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_hIST_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr,\n    png_const_uint_16p hist, int num_hist),PNG_EMPTY);\n#endif\n\n/* Chunks that have keywords */\n#ifdef PNG_WRITE_tEXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr,\n   png_const_charp key, png_const_charp text, size_t text_len),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_zTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp\n    key, png_const_charp text, int compression),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_iTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr,\n    int compression, png_const_charp key, png_const_charp lang,\n    png_const_charp lang_key, png_const_charp text),PNG_EMPTY);\n#endif\n\n#ifdef PNG_TEXT_SUPPORTED  /* Added at version 1.0.14 and 1.2.4 */\nPNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_oFFs_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr,\n    png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_pCAL_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr,\n    png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,\n    png_const_charp units, png_charpp params),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_pHYs_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr,\n    png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,\n    int unit_type),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_tIME_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr,\n    png_const_timep mod_time),PNG_EMPTY);\n#endif\n\n#ifdef PNG_WRITE_sCAL_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,\n    int unit, png_const_charp width, png_const_charp height),PNG_EMPTY);\n#endif\n\n/* Called when finished processing a row of data */\nPNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr),\n    PNG_EMPTY);\n\n/* Internal use only.   Called before first row of data */\nPNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr),\n    PNG_EMPTY);\n\n/* Combine a row of data, dealing with alpha, etc. if requested.  'row' is an\n * array of png_ptr->width pixels.  If the image is not interlaced or this\n * is the final pass this just does a memcpy, otherwise the \"display\" flag\n * is used to determine whether to copy pixels that are not in the current pass.\n *\n * Because 'png_do_read_interlace' (below) replicates pixels this allows this\n * function to achieve the documented 'blocky' appearance during interlaced read\n * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row'\n * are not changed if they are not in the current pass, when display is 0.\n *\n * 'display' must be 0 or 1, otherwise the memcpy will be done regardless.\n *\n * The API always reads from the png_struct row buffer and always assumes that\n * it is full width (png_do_read_interlace has already been called.)\n *\n * This function is only ever used to write to row buffers provided by the\n * caller of the relevant libpng API and the row must have already been\n * transformed by the read transformations.\n *\n * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed\n * bitmasks for use within the code, otherwise runtime generated masks are used.\n * The default is compile time masks.\n */\n#ifndef PNG_USE_COMPILE_TIME_MASKS\n#  define PNG_USE_COMPILE_TIME_MASKS 1\n#endif\nPNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr,\n    png_bytep row, int display),PNG_EMPTY);\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n/* Expand an interlaced row: the 'row_info' describes the pass data that has\n * been read in and must correspond to the pixels in 'row', the pixels are\n * expanded (moved apart) in 'row' to match the final layout, when doing this\n * the pixels are *replicated* to the intervening space.  This is essential for\n * the correct operation of png_combine_row, above.\n */\nPNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info,\n    png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY);\n#endif\n\n/* GRR TO DO (2.0 or whenever):  simplify other internal calling interfaces */\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n/* Grab pixels out of a row for an interlaced pass */\nPNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info,\n    png_bytep row, int pass),PNG_EMPTY);\n#endif\n\n/* Unfilter a row: check the filter value before calling this, there is no point\n * calling it for PNG_FILTER_VALUE_NONE.\n */\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY);\n\n#if PNG_ARM_NEON_OPT > 0\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info,\n    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\n#endif\n\n#if PNG_MIPS_MSA_OPT > 0\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info,\n    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\n#endif\n\n#if PNG_POWERPC_VSX_OPT > 0\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info,\n    png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_vsx,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\n#endif\n\n#if PNG_INTEL_SSE_IMPLEMENTATION > 0\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop\n    row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);\n#endif\n\n/* Choose the best filter to use and filter the row data */\nPNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,\n    png_row_infop row_info),PNG_EMPTY);\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr,\n   png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY);\n   /* Read 'avail_out' bytes of data from the IDAT stream.  If the output buffer\n    * is NULL the function checks, instead, for the end of the stream.  In this\n    * case a benign error will be issued if the stream end is not found or if\n    * extra data has to be consumed.\n    */\nPNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr),\n   PNG_EMPTY);\n   /* This cleans up when the IDAT LZ stream does not end when the last image\n    * byte is read; there is still some pending input.\n    */\n\nPNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr),\n   PNG_EMPTY);\n   /* Finish a row while reading, dealing with interlacing passes, etc. */\n#endif /* SEQUENTIAL_READ */\n\n/* Initialize the row buffers, etc. */\nPNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY);\n\n#if ZLIB_VERNUM >= 0x1240\nPNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush),\n      PNG_EMPTY);\n#  define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush)\n#else /* Zlib < 1.2.4 */\n#  define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush)\n#endif /* Zlib < 1.2.4 */\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n/* Optional call to update the users info structure */\nPNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\n#endif\n\n/* Shared transform functions, defined in pngtran.c */\n#if defined(PNG_WRITE_FILLER_SUPPORTED) || \\\n    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info,\n    png_bytep row, int at_start),PNG_EMPTY);\n#endif\n\n#ifdef PNG_16BIT_SUPPORTED\n#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info,\n    png_bytep row),PNG_EMPTY);\n#endif\n#endif\n\n#if defined(PNG_READ_PACKSWAP_SUPPORTED) || \\\n    defined(PNG_WRITE_PACKSWAP_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info,\n    png_bytep row),PNG_EMPTY);\n#endif\n\n#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info,\n    png_bytep row),PNG_EMPTY);\n#endif\n\n#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info,\n    png_bytep row),PNG_EMPTY);\n#endif\n\n/* The following decodes the appropriate chunks, and does error correction,\n * then calls the appropriate callback for the chunk if it is valid.\n */\n\n/* Decode the IHDR chunk */\nPNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n\n#ifdef PNG_READ_bKGD_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_cHRM_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_eXIf_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_gAMA_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_hIST_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_iCCP_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif /* READ_iCCP */\n\n#ifdef PNG_READ_iTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_oFFs_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_pCAL_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_pHYs_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_sBIT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_sCAL_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_sPLT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif /* READ_sPLT */\n\n#ifdef PNG_READ_sRGB_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_tEXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_tIME_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_tRNS_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_zTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\n#endif\n\nPNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr,\n    png_uint_32 chunk_name),PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr,\n    png_uint_32 chunk_length),PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY);\n   /* This is the function that gets called for unknown chunks.  The 'keep'\n    * argument is either non-zero for a known chunk that has been set to be\n    * handled as unknown or zero for an unknown chunk.  By default the function\n    * just skips the chunk or errors out if it is critical.\n    */\n\n#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\\\n    defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)\nPNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling,\n    (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY);\n   /* Exactly as the API png_handle_as_unknown() except that the argument is a\n    * 32-bit chunk name, not a string.\n    */\n#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */\n\n/* Handle the transformations for reading and writing */\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr,\n   png_row_infop row_info),PNG_EMPTY);\n#endif\n#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr,\n   png_row_infop row_info),PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr),\n    PNG_EMPTY);\n#endif\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr),\n    PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr,\n    png_bytep buffer, size_t buffer_length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr,\n    png_bytep buffer, size_t buffer_length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr),\n    PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr,\n   png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr,\n   png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr,\n   png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr,\n    png_bytep row),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr),\n    PNG_EMPTY);\n#  ifdef PNG_READ_tEXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\n#  endif\n#  ifdef PNG_READ_zTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\n#  endif\n#  ifdef PNG_READ_iTXt_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr,\n    png_inforp info_ptr, png_uint_32 length),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr,\n    png_inforp info_ptr),PNG_EMPTY);\n#  endif\n\n#endif /* PROGRESSIVE_READ */\n\n/* Added at libpng version 1.6.0 */\n#ifdef PNG_GAMMA_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr,\n    png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY);\n   /* Set the colorspace gamma with a value provided by the application or by\n    * the gAMA chunk on read.  The value will override anything set by an ICC\n    * profile.\n    */\n\nPNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr,\n    png_inforp info_ptr), PNG_EMPTY);\n   /* Synchronize the info 'valid' flags with the colorspace */\n\nPNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr,\n    png_inforp info_ptr), PNG_EMPTY);\n   /* Copy the png_struct colorspace to the info_struct and call the above to\n    * synchronize the flags.  Checks for NULL info_ptr and does nothing.\n    */\n#endif\n\n/* Added at libpng version 1.4.0 */\n#ifdef PNG_COLORSPACE_SUPPORTED\n/* These internal functions are for maintaining the colorspace structure within\n * a png_info or png_struct (or, indeed, both).\n */\nPNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities,\n   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy,\n    int preferred), PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints,\n   (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ,\n    int preferred), PNG_EMPTY);\n\n#ifdef PNG_sRGB_SUPPORTED\nPNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr,\n   png_colorspacerp colorspace, int intent), PNG_EMPTY);\n   /* This does set the colorspace gAMA and cHRM values too, but doesn't set the\n    * flags to write them, if it returns false there was a problem and an error\n    * message has already been output (but the colorspace may still need to be\n    * synced to record the invalid flag).\n    */\n#endif /* sRGB */\n\n#ifdef PNG_iCCP_SUPPORTED\nPNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr,\n   png_colorspacerp colorspace, png_const_charp name,\n   png_uint_32 profile_length, png_const_bytep profile, int color_type),\n   PNG_EMPTY);\n   /* The 'name' is used for information only */\n\n/* Routines for checking parts of an ICC profile. */\n#ifdef PNG_READ_iCCP_SUPPORTED\nPNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr,\n   png_colorspacerp colorspace, png_const_charp name,\n   png_uint_32 profile_length), PNG_EMPTY);\n#endif /* READ_iCCP */\nPNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr,\n   png_colorspacerp colorspace, png_const_charp name,\n   png_uint_32 profile_length,\n   png_const_bytep profile /* first 132 bytes only */, int color_type),\n   PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr,\n   png_colorspacerp colorspace, png_const_charp name,\n   png_uint_32 profile_length,\n   png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);\n#ifdef PNG_sRGB_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,(\n   png_const_structrp png_ptr, png_colorspacerp colorspace,\n   png_const_bytep profile, uLong adler), PNG_EMPTY);\n   /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may\n    * be zero to indicate that it is not available.  It is used, if provided,\n    * as a fast check on the profile when checking to see if it is sRGB.\n    */\n#endif\n#endif /* iCCP */\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients,\n   (png_structrp png_ptr), PNG_EMPTY);\n   /* Set the rgb_to_gray coefficients from the colorspace Y values */\n#endif /* READ_RGB_TO_GRAY */\n#endif /* COLORSPACE */\n\n/* Added at libpng version 1.4.0 */\nPNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr,\n    png_uint_32 width, png_uint_32 height, int bit_depth,\n    int color_type, int interlace_type, int compression_type,\n    int filter_type),PNG_EMPTY);\n\n/* Added at libpng version 1.5.10 */\n#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \\\n    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes,\n   (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY);\n#endif\n\n#if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)\nPNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr,\n   png_const_charp name),PNG_NORETURN);\n#endif\n\n/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite\n * the end.  Always leaves the buffer nul terminated.  Never errors out (and\n * there is no error code.)\n */\nPNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize,\n   size_t pos, png_const_charp string),PNG_EMPTY);\n\n/* Various internal functions to handle formatted warning messages, currently\n * only implemented for warnings.\n */\n#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)\n/* Utility to dump an unsigned value into a buffer, given a start pointer and\n * and end pointer (which should point just *beyond* the end of the buffer!)\n * Returns the pointer to the start of the formatted string.  This utility only\n * does unsigned values.\n */\nPNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start,\n   png_charp end, int format, png_alloc_size_t number),PNG_EMPTY);\n\n/* Convenience macro that takes an array: */\n#define PNG_FORMAT_NUMBER(buffer,format,number) \\\n   png_format_number(buffer, buffer + (sizeof buffer), format, number)\n\n/* Suggested size for a number buffer (enough for 64 bits and a sign!) */\n#define PNG_NUMBER_BUFFER_SIZE 24\n\n/* These are the integer formats currently supported, the name is formed from\n * the standard printf(3) format string.\n */\n#define PNG_NUMBER_FORMAT_u     1 /* chose unsigned API! */\n#define PNG_NUMBER_FORMAT_02u   2\n#define PNG_NUMBER_FORMAT_d     1 /* chose signed API! */\n#define PNG_NUMBER_FORMAT_02d   2\n#define PNG_NUMBER_FORMAT_x     3\n#define PNG_NUMBER_FORMAT_02x   4\n#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */\n#endif\n\n#ifdef PNG_WARNINGS_SUPPORTED\n/* New defines and members adding in libpng-1.5.4 */\n#  define PNG_WARNING_PARAMETER_SIZE 32\n#  define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */\n\n/* An l-value of this type has to be passed to the APIs below to cache the\n * values of the parameters to a formatted warning message.\n */\ntypedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][\n   PNG_WARNING_PARAMETER_SIZE];\n\nPNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p,\n   int number, png_const_charp string),PNG_EMPTY);\n   /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters,\n    * including the trailing '\\0'.\n    */\nPNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned,\n   (png_warning_parameters p, int number, int format, png_alloc_size_t value),\n   PNG_EMPTY);\n   /* Use png_alloc_size_t because it is an unsigned type as big as any we\n    * need to output.  Use the following for a signed value.\n    */\nPNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed,\n   (png_warning_parameters p, int number, int format, png_int_32 value),\n   PNG_EMPTY);\n\nPNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr,\n   png_warning_parameters p, png_const_charp message),PNG_EMPTY);\n   /* 'message' follows the X/Open approach of using @1, @2 to insert\n    * parameters previously supplied using the above functions.  Errors in\n    * specifying the parameters will simply result in garbage substitutions.\n    */\n#endif\n\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\n/* Application errors (new in 1.6); use these functions (declared below) for\n * errors in the parameters or order of API function calls on read.  The\n * 'warning' should be used for an error that can be handled completely; the\n * 'error' for one which can be handled safely but which may lose application\n * information or settings.\n *\n * By default these both result in a png_error call prior to release, while in a\n * released version the 'warning' is just a warning.  However if the application\n * explicitly disables benign errors (explicitly permitting the code to lose\n * information) they both turn into warnings.\n *\n * If benign errors aren't supported they end up as the corresponding base call\n * (png_warning or png_error.)\n */\nPNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr,\n   png_const_charp message),PNG_EMPTY);\n   /* The application provided invalid parameters to an API function or called\n    * an API function at the wrong time, libpng can completely recover.\n    */\n\nPNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr,\n   png_const_charp message),PNG_EMPTY);\n   /* As above but libpng will ignore the call, or attempt some other partial\n    * recovery from the error.\n    */\n#else\n#  define png_app_warning(pp,s) png_warning(pp,s)\n#  define png_app_error(pp,s) png_error(pp,s)\n#endif\n\nPNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr,\n   png_const_charp message, int error),PNG_EMPTY);\n   /* Report a recoverable issue in chunk data.  On read this is used to report\n    * a problem found while reading a particular chunk and the\n    * png_chunk_benign_error or png_chunk_warning function is used as\n    * appropriate.  On write this is used to report an error that comes from\n    * data set via an application call to a png_set_ API and png_app_error or\n    * png_app_warning is used as appropriate.\n    *\n    * The 'error' parameter must have one of the following values:\n    */\n#define PNG_CHUNK_WARNING     0 /* never an error */\n#define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */\n#define PNG_CHUNK_ERROR       2 /* always an error */\n\n/* ASCII to FP interfaces, currently only implemented if sCAL\n * support is required.\n */\n#if defined(PNG_sCAL_SUPPORTED)\n/* MAX_DIGITS is actually the maximum number of characters in an sCAL\n * width or height, derived from the precision (number of significant\n * digits - a build time settable option) and assumptions about the\n * maximum ridiculous exponent.\n */\n#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr,\n   png_charp ascii, size_t size, double fp, unsigned int precision),\n   PNG_EMPTY);\n#endif /* FLOATING_POINT */\n\n#ifdef PNG_FIXED_POINT_SUPPORTED\nPNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,\n   png_charp ascii, size_t size, png_fixed_point fp),PNG_EMPTY);\n#endif /* FIXED_POINT */\n#endif /* sCAL */\n\n#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)\n/* An internal API to validate the format of a floating point number.\n * The result is the index of the next character.  If the number is\n * not valid it will be the index of a character in the supposed number.\n *\n * The format of a number is defined in the PNG extensions specification\n * and this API is strictly conformant to that spec, not anyone elses!\n *\n * The format as a regular expression is:\n *\n * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)?\n *\n * or:\n *\n * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)?\n *\n * The complexity is that either integer or fraction must be present and the\n * fraction is permitted to have no digits only if the integer is present.\n *\n * NOTE: The dangling E problem.\n *   There is a PNG valid floating point number in the following:\n *\n *       PNG floating point numbers are not greedy.\n *\n *   Working this out requires *TWO* character lookahead (because of the\n *   sign), the parser does not do this - it will fail at the 'r' - this\n *   doesn't matter for PNG sCAL chunk values, but it requires more care\n *   if the value were ever to be embedded in something more complex.  Use\n *   ANSI-C strtod if you need the lookahead.\n */\n/* State table for the parser. */\n#define PNG_FP_INTEGER    0  /* before or in integer */\n#define PNG_FP_FRACTION   1  /* before or in fraction */\n#define PNG_FP_EXPONENT   2  /* before or in exponent */\n#define PNG_FP_STATE      3  /* mask for the above */\n#define PNG_FP_SAW_SIGN   4  /* Saw +/- in current state */\n#define PNG_FP_SAW_DIGIT  8  /* Saw a digit in current state */\n#define PNG_FP_SAW_DOT   16  /* Saw a dot in current state */\n#define PNG_FP_SAW_E     32  /* Saw an E (or e) in current state */\n#define PNG_FP_SAW_ANY   60  /* Saw any of the above 4 */\n\n/* These three values don't affect the parser.  They are set but not used.\n */\n#define PNG_FP_WAS_VALID 64  /* Preceding substring is a valid fp number */\n#define PNG_FP_NEGATIVE 128  /* A negative number, including \"-0\" */\n#define PNG_FP_NONZERO  256  /* A non-zero value */\n#define PNG_FP_STICKY   448  /* The above three flags */\n\n/* This is available for the caller to store in 'state' if required.  Do not\n * call the parser after setting it (the parser sometimes clears it.)\n */\n#define PNG_FP_INVALID  512  /* Available for callers as a distinct value */\n\n/* Result codes for the parser (boolean - true meants ok, false means\n * not ok yet.)\n */\n#define PNG_FP_MAYBE      0  /* The number may be valid in the future */\n#define PNG_FP_OK         1  /* The number is valid */\n\n/* Tests on the sticky non-zero and negative flags.  To pass these checks\n * the state must also indicate that the whole number is valid - this is\n * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this\n * is equivalent to PNG_FP_OK above.)\n */\n#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO)\n   /* NZ_MASK: the string is valid and a non-zero negative value */\n#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO)\n   /* Z MASK: the string is valid and a non-zero value. */\n   /* PNG_FP_SAW_DIGIT: the string is valid. */\n#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)\n#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)\n#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)\n\n/* The actual parser.  This can be called repeatedly. It updates\n * the index into the string and the state variable (which must\n * be initialized to 0).  It returns a result code, as above.  There\n * is no point calling the parser any more if it fails to advance to\n * the end of the string - it is stuck on an invalid character (or\n * terminated by '\\0').\n *\n * Note that the pointer will consume an E or even an E+ and then leave\n * a 'maybe' state even though a preceding integer.fraction is valid.\n * The PNG_FP_WAS_VALID flag indicates that a preceding substring was\n * a valid number.  It's possible to recover from this by calling\n * the parser again (from the start, with state 0) but with a string\n * that omits the last character (i.e. set the size to the index of\n * the problem character.)  This has not been tested within libpng.\n */\nPNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string,\n   size_t size, int *statep, png_size_tp whereami),PNG_EMPTY);\n\n/* This is the same but it checks a complete string and returns true\n * only if it just contains a floating point number.  As of 1.5.4 this\n * function also returns the state at the end of parsing the number if\n * it was valid (otherwise it returns 0.)  This can be used for testing\n * for negative or zero values using the sticky flag.\n */\nPNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string,\n   size_t size),PNG_EMPTY);\n#endif /* pCAL || sCAL */\n\n#if defined(PNG_GAMMA_SUPPORTED) ||\\\n    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)\n/* Added at libpng version 1.5.0 */\n/* This is a utility to provide a*times/div (rounded) and indicate\n * if there is an overflow.  The result is a boolean - false (0)\n * for overflow, true (1) if no overflow, in which case *res\n * holds the result.\n */\nPNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a,\n   png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY);\n#endif\n\n#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)\n/* Same deal, but issue a warning on overflow and return 0. */\nPNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn,\n   (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by,\n   png_int_32 divided_by),PNG_EMPTY);\n#endif\n\n#ifdef PNG_GAMMA_SUPPORTED\n/* Calculate a reciprocal - used for gamma values.  This returns\n * 0 if the argument is 0 in order to maintain an undefined value;\n * there are no warnings.\n */\nPNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a),\n   PNG_EMPTY);\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n/* The same but gives a reciprocal of the product of two fixed point\n * values.  Accuracy is suitable for gamma calculations but this is\n * not exact - use png_muldiv for that.  Only required at present on read.\n */\nPNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a,\n   png_fixed_point b),PNG_EMPTY);\n#endif\n\n/* Return true if the gamma value is significantly different from 1.0 */\nPNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value),\n   PNG_EMPTY);\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n/* Internal fixed point gamma correction.  These APIs are called as\n * required to convert single values - they don't need to be fast,\n * they are not used when processing image pixel values.\n *\n * While the input is an 'unsigned' value it must actually be the\n * correct bit value - 0..255 or 0..65535 as required.\n */\nPNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr,\n   unsigned int value, png_fixed_point gamma_value),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value,\n   png_fixed_point gamma_value),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value,\n   png_fixed_point gamma_value),PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr),\n   PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr,\n   int bit_depth),PNG_EMPTY);\n#endif\n\n/* SIMPLIFIED READ/WRITE SUPPORT */\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\\\n   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)\n/* The internal structure that png_image::opaque points to. */\ntypedef struct png_control\n{\n   png_structp png_ptr;\n   png_infop   info_ptr;\n   png_voidp   error_buf;           /* Always a jmp_buf at present. */\n\n   png_const_bytep memory;          /* Memory buffer. */\n   size_t          size;            /* Size of the memory buffer. */\n\n   unsigned int for_write       :1; /* Otherwise it is a read structure */\n   unsigned int owned_file      :1; /* We own the file in io_ptr */\n} png_control;\n\n/* Return the pointer to the jmp_buf from a png_control: necessary because C\n * does not reveal the type of the elements of jmp_buf.\n */\n#ifdef __cplusplus\n#  define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0])\n#else\n#  define png_control_jmp_buf(pc) ((pc)->error_buf)\n#endif\n\n/* Utility to safely execute a piece of libpng code catching and logging any\n * errors that might occur.  Returns true on success, false on failure (either\n * of the function or as a result of a png_error.)\n */\nPNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr,\n   png_const_charp error_message),PNG_NORETURN);\n\n#ifdef PNG_WARNINGS_SUPPORTED\nPNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr,\n   png_const_charp warning_message),PNG_EMPTY);\n#else\n#  define png_safe_warning 0/*dummy argument*/\n#endif\n\nPNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image,\n   int (*function)(png_voidp), png_voidp arg),PNG_EMPTY);\n\n/* Utility to log an error; this also cleans up the png_image; the function\n * always returns 0 (false).\n */\nPNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image,\n   png_const_charp error_message),PNG_EMPTY);\n\n#ifndef PNG_SIMPLIFIED_READ_SUPPORTED\n/* png_image_free is used by the write code but not exported */\nPNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY);\n#endif /* !SIMPLIFIED_READ */\n\n#endif /* SIMPLIFIED READ/WRITE */\n\n/* These are initialization functions for hardware specific PNG filter\n * optimizations; list these here then select the appropriate one at compile\n * time using the macro PNG_FILTER_OPTIMIZATIONS.  If the macro is not defined\n * the generic code is used.\n */\n#ifdef PNG_FILTER_OPTIMIZATIONS\nPNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr,\n   unsigned int bpp), PNG_EMPTY);\n   /* Just declare the optimization that will be used */\n#else\n   /* List *all* the possible optimizations here - this branch is required if\n    * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in\n    * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing.\n    */\n#  if PNG_ARM_NEON_OPT > 0\nPNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,\n   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);\n#endif\n\n#if PNG_MIPS_MSA_OPT > 0\nPNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa,\n   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);\n#endif\n\n#  if PNG_INTEL_SSE_IMPLEMENTATION > 0\nPNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,\n   (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);\n#  endif\n#endif\n\nPNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,\n   png_const_charp key, png_bytep new_key), PNG_EMPTY);\n\n#if PNG_ARM_NEON_IMPLEMENTATION == 1\nPNG_INTERNAL_FUNCTION(void,\n                      png_riffle_palette_neon,\n                      (png_structrp),\n                      PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(int,\n                      png_do_expand_palette_rgba8_neon,\n                      (png_structrp,\n                       png_row_infop,\n                       png_const_bytep,\n                       const png_bytepp,\n                       const png_bytepp),\n                      PNG_EMPTY);\nPNG_INTERNAL_FUNCTION(int,\n                      png_do_expand_palette_rgb8_neon,\n                      (png_structrp,\n                       png_row_infop,\n                       png_const_bytep,\n                       const png_bytepp,\n                       const png_bytepp),\n                      PNG_EMPTY);\n#endif\n\n/* Maintainer: Put new private prototypes here ^ */\n\n#include \"pngdebug.h\"\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* PNG_VERSION_INFO_ONLY */\n#endif /* PNGPRIV_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngread.c",
    "content": "\n/* pngread.c - read a PNG file\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file contains routines that an application calls directly to\n * read a PNG file or stream.\n */\n\n#include \"pngpriv.h\"\n#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)\n#  include <errno.h>\n#endif\n\n#ifdef PNG_READ_SUPPORTED\n\n/* Create a PNG structure for reading, and allocate any memory needed. */\nPNG_FUNCTION(png_structp,PNGAPI\npng_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)\n{\n#ifndef PNG_USER_MEM_SUPPORTED\n   png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,\n        error_fn, warn_fn, NULL, NULL, NULL);\n#else\n   return png_create_read_struct_2(user_png_ver, error_ptr, error_fn,\n        warn_fn, NULL, NULL, NULL);\n}\n\n/* Alternate create PNG structure for reading, and allocate any memory\n * needed.\n */\nPNG_FUNCTION(png_structp,PNGAPI\npng_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,\n    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)\n{\n   png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,\n       error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);\n#endif /* USER_MEM */\n\n   if (png_ptr != NULL)\n   {\n      png_ptr->mode = PNG_IS_READ_STRUCT;\n\n      /* Added in libpng-1.6.0; this can be used to detect a read structure if\n       * required (it will be zero in a write structure.)\n       */\n#     ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n         png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE;\n#     endif\n\n#     ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED\n         png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;\n\n         /* In stable builds only warn if an application error can be completely\n          * handled.\n          */\n#        if PNG_RELEASE_BUILD\n            png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;\n#        endif\n#     endif\n\n      /* TODO: delay this, it can be done in png_init_io (if the app doesn't\n       * do it itself) avoiding setting the default function if it is not\n       * required.\n       */\n      png_set_read_fn(png_ptr, NULL, NULL);\n   }\n\n   return png_ptr;\n}\n\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the information before the actual image data.  This has been\n * changed in v0.90 to allow reading a file that already has the magic\n * bytes read from the stream.  You can tell libpng how many bytes have\n * been read from the beginning of the stream (up to the maximum of 8)\n * via png_set_sig_bytes(), and we will only check the remaining bytes\n * here.  The application can then have access to the signature bytes we\n * read if it is determined that this isn't a valid PNG file.\n */\nvoid PNGAPI\npng_read_info(png_structrp png_ptr, png_inforp info_ptr)\n{\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n   int keep;\n#endif\n\n   png_debug(1, \"in png_read_info\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   /* Read and check the PNG file signature. */\n   png_read_sig(png_ptr, info_ptr);\n\n   for (;;)\n   {\n      png_uint_32 length = png_read_chunk_header(png_ptr);\n      png_uint_32 chunk_name = png_ptr->chunk_name;\n\n      /* IDAT logic needs to happen here to simplify getting the two flags\n       * right.\n       */\n      if (chunk_name == png_IDAT)\n      {\n         if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n            png_chunk_error(png_ptr, \"Missing IHDR before IDAT\");\n\n         else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&\n             (png_ptr->mode & PNG_HAVE_PLTE) == 0)\n            png_chunk_error(png_ptr, \"Missing PLTE before IDAT\");\n\n         else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)\n            png_chunk_benign_error(png_ptr, \"Too many IDATs found\");\n\n         png_ptr->mode |= PNG_HAVE_IDAT;\n      }\n\n      else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n      {\n         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;\n         png_ptr->mode |= PNG_AFTER_IDAT;\n      }\n\n      /* This should be a binary subdivision search or a hash for\n       * matching the chunk name rather than a linear search.\n       */\n      if (chunk_name == png_IHDR)\n         png_handle_IHDR(png_ptr, info_ptr, length);\n\n      else if (chunk_name == png_IEND)\n         png_handle_IEND(png_ptr, info_ptr, length);\n\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n      else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)\n      {\n         png_handle_unknown(png_ptr, info_ptr, length, keep);\n\n         if (chunk_name == png_PLTE)\n            png_ptr->mode |= PNG_HAVE_PLTE;\n\n         else if (chunk_name == png_IDAT)\n         {\n            png_ptr->idat_size = 0; /* It has been consumed */\n            break;\n         }\n      }\n#endif\n      else if (chunk_name == png_PLTE)\n         png_handle_PLTE(png_ptr, info_ptr, length);\n\n      else if (chunk_name == png_IDAT)\n      {\n         png_ptr->idat_size = length;\n         break;\n      }\n\n#ifdef PNG_READ_bKGD_SUPPORTED\n      else if (chunk_name == png_bKGD)\n         png_handle_bKGD(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_cHRM_SUPPORTED\n      else if (chunk_name == png_cHRM)\n         png_handle_cHRM(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_eXIf_SUPPORTED\n      else if (chunk_name == png_eXIf)\n         png_handle_eXIf(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_gAMA_SUPPORTED\n      else if (chunk_name == png_gAMA)\n         png_handle_gAMA(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_hIST_SUPPORTED\n      else if (chunk_name == png_hIST)\n         png_handle_hIST(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_oFFs_SUPPORTED\n      else if (chunk_name == png_oFFs)\n         png_handle_oFFs(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_pCAL_SUPPORTED\n      else if (chunk_name == png_pCAL)\n         png_handle_pCAL(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sCAL_SUPPORTED\n      else if (chunk_name == png_sCAL)\n         png_handle_sCAL(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_pHYs_SUPPORTED\n      else if (chunk_name == png_pHYs)\n         png_handle_pHYs(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sBIT_SUPPORTED\n      else if (chunk_name == png_sBIT)\n         png_handle_sBIT(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sRGB_SUPPORTED\n      else if (chunk_name == png_sRGB)\n         png_handle_sRGB(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_iCCP_SUPPORTED\n      else if (chunk_name == png_iCCP)\n         png_handle_iCCP(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sPLT_SUPPORTED\n      else if (chunk_name == png_sPLT)\n         png_handle_sPLT(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tEXt_SUPPORTED\n      else if (chunk_name == png_tEXt)\n         png_handle_tEXt(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tIME_SUPPORTED\n      else if (chunk_name == png_tIME)\n         png_handle_tIME(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tRNS_SUPPORTED\n      else if (chunk_name == png_tRNS)\n         png_handle_tRNS(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_zTXt_SUPPORTED\n      else if (chunk_name == png_zTXt)\n         png_handle_zTXt(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_iTXt_SUPPORTED\n      else if (chunk_name == png_iTXt)\n         png_handle_iTXt(png_ptr, info_ptr, length);\n#endif\n\n      else\n         png_handle_unknown(png_ptr, info_ptr, length,\n             PNG_HANDLE_CHUNK_AS_DEFAULT);\n   }\n}\n#endif /* SEQUENTIAL_READ */\n\n/* Optional call to update the users info_ptr structure */\nvoid PNGAPI\npng_read_update_info(png_structrp png_ptr, png_inforp info_ptr)\n{\n   png_debug(1, \"in png_read_update_info\");\n\n   if (png_ptr != NULL)\n   {\n      if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)\n      {\n         png_read_start_row(png_ptr);\n\n#        ifdef PNG_READ_TRANSFORMS_SUPPORTED\n            png_read_transform_info(png_ptr, info_ptr);\n#        else\n            PNG_UNUSED(info_ptr)\n#        endif\n      }\n\n      /* New in 1.6.0 this avoids the bug of doing the initializations twice */\n      else\n         png_app_error(png_ptr,\n             \"png_read_update_info/png_start_read_image: duplicate call\");\n   }\n}\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Initialize palette, background, etc, after transformations\n * are set, but before any reading takes place.  This allows\n * the user to obtain a gamma-corrected palette, for example.\n * If the user doesn't call this, we will do it ourselves.\n */\nvoid PNGAPI\npng_start_read_image(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_start_read_image\");\n\n   if (png_ptr != NULL)\n   {\n      if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)\n         png_read_start_row(png_ptr);\n\n      /* New in 1.6.0 this avoids the bug of doing the initializations twice */\n      else\n         png_app_error(png_ptr,\n             \"png_start_read_image/png_read_update_info: duplicate call\");\n   }\n}\n#endif /* SEQUENTIAL_READ */\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n/* Undoes intrapixel differencing,\n * NOTE: this is apparently only supported in the 'sequential' reader.\n */\nstatic void\npng_do_read_intrapixel(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_read_intrapixel\");\n\n   if (\n       (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      int bytes_per_pixel;\n      png_uint_32 row_width = row_info->width;\n\n      if (row_info->bit_depth == 8)\n      {\n         png_bytep rp;\n         png_uint_32 i;\n\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n            bytes_per_pixel = 3;\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n            bytes_per_pixel = 4;\n\n         else\n            return;\n\n         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)\n         {\n            *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff);\n            *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff);\n         }\n      }\n      else if (row_info->bit_depth == 16)\n      {\n         png_bytep rp;\n         png_uint_32 i;\n\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n            bytes_per_pixel = 6;\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n            bytes_per_pixel = 8;\n\n         else\n            return;\n\n         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)\n         {\n            png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);\n            png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);\n            png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);\n            png_uint_32 red  = (s0 + s1 + 65536) & 0xffff;\n            png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;\n            *(rp    ) = (png_byte)((red >> 8) & 0xff);\n            *(rp + 1) = (png_byte)(red & 0xff);\n            *(rp + 4) = (png_byte)((blue >> 8) & 0xff);\n            *(rp + 5) = (png_byte)(blue & 0xff);\n         }\n      }\n   }\n}\n#endif /* MNG_FEATURES */\n\nvoid PNGAPI\npng_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)\n{\n   png_row_info row_info;\n\n   if (png_ptr == NULL)\n      return;\n\n   png_debug2(1, \"in png_read_row (row %lu, pass %d)\",\n       (unsigned long)png_ptr->row_number, png_ptr->pass);\n\n   /* png_read_start_row sets the information (in particular iwidth) for this\n    * interlace pass.\n    */\n   if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)\n      png_read_start_row(png_ptr);\n\n   /* 1.5.6: row_info moved out of png_struct to a local here. */\n   row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */\n   row_info.color_type = png_ptr->color_type;\n   row_info.bit_depth = png_ptr->bit_depth;\n   row_info.channels = png_ptr->channels;\n   row_info.pixel_depth = png_ptr->pixel_depth;\n   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);\n\n#ifdef PNG_WARNINGS_SUPPORTED\n   if (png_ptr->row_number == 0 && png_ptr->pass == 0)\n   {\n   /* Check for transforms that have been set but were defined out */\n#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)\n   if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)\n      png_warning(png_ptr, \"PNG_READ_INVERT_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)\n   if ((png_ptr->transformations & PNG_FILLER) != 0)\n      png_warning(png_ptr, \"PNG_READ_FILLER_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \\\n    !defined(PNG_READ_PACKSWAP_SUPPORTED)\n   if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n      png_warning(png_ptr, \"PNG_READ_PACKSWAP_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)\n   if ((png_ptr->transformations & PNG_PACK) != 0)\n      png_warning(png_ptr, \"PNG_READ_PACK_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)\n   if ((png_ptr->transformations & PNG_SHIFT) != 0)\n      png_warning(png_ptr, \"PNG_READ_SHIFT_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)\n   if ((png_ptr->transformations & PNG_BGR) != 0)\n      png_warning(png_ptr, \"PNG_READ_BGR_SUPPORTED is not defined\");\n#endif\n\n#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)\n   if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)\n      png_warning(png_ptr, \"PNG_READ_SWAP_SUPPORTED is not defined\");\n#endif\n   }\n#endif /* WARNINGS */\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   /* If interlaced and we do not need a new row, combine row and return.\n    * Notice that the pixels we have from previous rows have been transformed\n    * already; we can only combine like with like (transformed or\n    * untransformed) and, because of the libpng API for interlaced images, this\n    * means we must transform before de-interlacing.\n    */\n   if (png_ptr->interlaced != 0 &&\n       (png_ptr->transformations & PNG_INTERLACE) != 0)\n   {\n      switch (png_ptr->pass)\n      {\n         case 0:\n            if (png_ptr->row_number & 0x07)\n            {\n               if (dsp_row != NULL)\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 1:\n            if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)\n            {\n               if (dsp_row != NULL)\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 2:\n            if ((png_ptr->row_number & 0x07) != 4)\n            {\n               if (dsp_row != NULL && (png_ptr->row_number & 4))\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 3:\n            if ((png_ptr->row_number & 3) || png_ptr->width < 3)\n            {\n               if (dsp_row != NULL)\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 4:\n            if ((png_ptr->row_number & 3) != 2)\n            {\n               if (dsp_row != NULL && (png_ptr->row_number & 2))\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 5:\n            if ((png_ptr->row_number & 1) || png_ptr->width < 2)\n            {\n               if (dsp_row != NULL)\n                  png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         default:\n         case 6:\n            if ((png_ptr->row_number & 1) == 0)\n            {\n               png_read_finish_row(png_ptr);\n               return;\n            }\n            break;\n      }\n   }\n#endif\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)\n      png_error(png_ptr, \"Invalid attempt to read row data\");\n\n   /* Fill the row with IDAT data: */\n   png_ptr->row_buf[0]=255; /* to force error if no data was found */\n   png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1);\n\n   if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)\n   {\n      if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)\n         png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,\n             png_ptr->prev_row + 1, png_ptr->row_buf[0]);\n      else\n         png_error(png_ptr, \"bad adaptive filter value\");\n   }\n\n   /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before\n    * 1.5.6, while the buffer really is this big in current versions of libpng\n    * it may not be in the future, so this was changed just to copy the\n    * interlaced count:\n    */\n   memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&\n       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))\n   {\n      /* Intrapixel differencing */\n      png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1);\n   }\n#endif\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n   if (png_ptr->transformations)\n      png_do_read_transformations(png_ptr, &row_info);\n#endif\n\n   /* The transformed pixel depth should match the depth now in row_info. */\n   if (png_ptr->transformed_pixel_depth == 0)\n   {\n      png_ptr->transformed_pixel_depth = row_info.pixel_depth;\n      if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)\n         png_error(png_ptr, \"sequential row overflow\");\n   }\n\n   else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)\n      png_error(png_ptr, \"internal sequential row size calculation error\");\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   /* Expand interlaced rows to full size */\n   if (png_ptr->interlaced != 0 &&\n      (png_ptr->transformations & PNG_INTERLACE) != 0)\n   {\n      if (png_ptr->pass < 6)\n         png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,\n             png_ptr->transformations);\n\n      if (dsp_row != NULL)\n         png_combine_row(png_ptr, dsp_row, 1/*display*/);\n\n      if (row != NULL)\n         png_combine_row(png_ptr, row, 0/*row*/);\n   }\n\n   else\n#endif\n   {\n      if (row != NULL)\n         png_combine_row(png_ptr, row, -1/*ignored*/);\n\n      if (dsp_row != NULL)\n         png_combine_row(png_ptr, dsp_row, -1/*ignored*/);\n   }\n   png_read_finish_row(png_ptr);\n\n   if (png_ptr->read_row_fn != NULL)\n      (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);\n\n}\n#endif /* SEQUENTIAL_READ */\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read one or more rows of image data.  If the image is interlaced,\n * and png_set_interlace_handling() has been called, the rows need to\n * contain the contents of the rows from the previous pass.  If the\n * image has alpha or transparency, and png_handle_alpha()[*] has been\n * called, the rows contents must be initialized to the contents of the\n * screen.\n *\n * \"row\" holds the actual image, and pixels are placed in it\n * as they arrive.  If the image is displayed after each pass, it will\n * appear to \"sparkle\" in.  \"display_row\" can be used to display a\n * \"chunky\" progressive image, with finer detail added as it becomes\n * available.  If you do not want this \"chunky\" display, you may pass\n * NULL for display_row.  If you do not want the sparkle display, and\n * you have not called png_handle_alpha(), you may pass NULL for rows.\n * If you have called png_handle_alpha(), and the image has either an\n * alpha channel or a transparency chunk, you must provide a buffer for\n * rows.  In this case, you do not have to provide a display_row buffer\n * also, but you may.  If the image is not interlaced, or if you have\n * not called png_set_interlace_handling(), the display_row buffer will\n * be ignored, so pass NULL to it.\n *\n * [*] png_handle_alpha() does not exist yet, as of this version of libpng\n */\n\nvoid PNGAPI\npng_read_rows(png_structrp png_ptr, png_bytepp row,\n    png_bytepp display_row, png_uint_32 num_rows)\n{\n   png_uint_32 i;\n   png_bytepp rp;\n   png_bytepp dp;\n\n   png_debug(1, \"in png_read_rows\");\n\n   if (png_ptr == NULL)\n      return;\n\n   rp = row;\n   dp = display_row;\n   if (rp != NULL && dp != NULL)\n      for (i = 0; i < num_rows; i++)\n      {\n         png_bytep rptr = *rp++;\n         png_bytep dptr = *dp++;\n\n         png_read_row(png_ptr, rptr, dptr);\n      }\n\n   else if (rp != NULL)\n      for (i = 0; i < num_rows; i++)\n      {\n         png_bytep rptr = *rp;\n         png_read_row(png_ptr, rptr, NULL);\n         rp++;\n      }\n\n   else if (dp != NULL)\n      for (i = 0; i < num_rows; i++)\n      {\n         png_bytep dptr = *dp;\n         png_read_row(png_ptr, NULL, dptr);\n         dp++;\n      }\n}\n#endif /* SEQUENTIAL_READ */\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the entire image.  If the image has an alpha channel or a tRNS\n * chunk, and you have called png_handle_alpha()[*], you will need to\n * initialize the image to the current image that PNG will be overlaying.\n * We set the num_rows again here, in case it was incorrectly set in\n * png_read_start_row() by a call to png_read_update_info() or\n * png_start_read_image() if png_set_interlace_handling() wasn't called\n * prior to either of these functions like it should have been.  You can\n * only call this function once.  If you desire to have an image for\n * each pass of a interlaced image, use png_read_rows() instead.\n *\n * [*] png_handle_alpha() does not exist yet, as of this version of libpng\n */\nvoid PNGAPI\npng_read_image(png_structrp png_ptr, png_bytepp image)\n{\n   png_uint_32 i, image_height;\n   int pass, j;\n   png_bytepp rp;\n\n   png_debug(1, \"in png_read_image\");\n\n   if (png_ptr == NULL)\n      return;\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)\n   {\n      pass = png_set_interlace_handling(png_ptr);\n      /* And make sure transforms are initialized. */\n      png_start_read_image(png_ptr);\n   }\n   else\n   {\n      if (png_ptr->interlaced != 0 &&\n          (png_ptr->transformations & PNG_INTERLACE) == 0)\n      {\n         /* Caller called png_start_read_image or png_read_update_info without\n          * first turning on the PNG_INTERLACE transform.  We can fix this here,\n          * but the caller should do it!\n          */\n         png_warning(png_ptr, \"Interlace handling should be turned on when \"\n             \"using png_read_image\");\n         /* Make sure this is set correctly */\n         png_ptr->num_rows = png_ptr->height;\n      }\n\n      /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in\n       * the above error case.\n       */\n      pass = png_set_interlace_handling(png_ptr);\n   }\n#else\n   if (png_ptr->interlaced)\n      png_error(png_ptr,\n          \"Cannot read interlaced image -- interlace handler disabled\");\n\n   pass = 1;\n#endif\n\n   image_height=png_ptr->height;\n\n   for (j = 0; j < pass; j++)\n   {\n      rp = image;\n      for (i = 0; i < image_height; i++)\n      {\n         png_read_row(png_ptr, *rp, NULL);\n         rp++;\n      }\n   }\n}\n#endif /* SEQUENTIAL_READ */\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n/* Read the end of the PNG file.  Will not read past the end of the\n * file, will verify the end is accurate, and will read any comments\n * or time information at the end of the file, if info is not NULL.\n */\nvoid PNGAPI\npng_read_end(png_structrp png_ptr, png_inforp info_ptr)\n{\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n   int keep;\n#endif\n\n   png_debug(1, \"in png_read_end\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* If png_read_end is called in the middle of reading the rows there may\n    * still be pending IDAT data and an owned zstream.  Deal with this here.\n    */\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n   if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0)\n#endif\n      png_read_finish_IDAT(png_ptr);\n\n#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   /* Report invalid palette index; added at libng-1.5.10 */\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&\n       png_ptr->num_palette_max > png_ptr->num_palette)\n      png_benign_error(png_ptr, \"Read palette index exceeding num_palette\");\n#endif\n\n   do\n   {\n      png_uint_32 length = png_read_chunk_header(png_ptr);\n      png_uint_32 chunk_name = png_ptr->chunk_name;\n\n      if (chunk_name != png_IDAT)\n         png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;\n\n      if (chunk_name == png_IEND)\n         png_handle_IEND(png_ptr, info_ptr, length);\n\n      else if (chunk_name == png_IHDR)\n         png_handle_IHDR(png_ptr, info_ptr, length);\n\n      else if (info_ptr == NULL)\n         png_crc_finish(png_ptr, length);\n\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n      else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)\n      {\n         if (chunk_name == png_IDAT)\n         {\n            if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))\n                || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)\n               png_benign_error(png_ptr, \".Too many IDATs found\");\n         }\n         png_handle_unknown(png_ptr, info_ptr, length, keep);\n         if (chunk_name == png_PLTE)\n            png_ptr->mode |= PNG_HAVE_PLTE;\n      }\n#endif\n\n      else if (chunk_name == png_IDAT)\n      {\n         /* Zero length IDATs are legal after the last IDAT has been\n          * read, but not after other chunks have been read.  1.6 does not\n          * always read all the deflate data; specifically it cannot be relied\n          * upon to read the Adler32 at the end.  If it doesn't ignore IDAT\n          * chunks which are longer than zero as well:\n          */\n         if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))\n             || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)\n            png_benign_error(png_ptr, \"..Too many IDATs found\");\n\n         png_crc_finish(png_ptr, length);\n      }\n      else if (chunk_name == png_PLTE)\n         png_handle_PLTE(png_ptr, info_ptr, length);\n\n#ifdef PNG_READ_bKGD_SUPPORTED\n      else if (chunk_name == png_bKGD)\n         png_handle_bKGD(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_cHRM_SUPPORTED\n      else if (chunk_name == png_cHRM)\n         png_handle_cHRM(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_eXIf_SUPPORTED\n      else if (chunk_name == png_eXIf)\n         png_handle_eXIf(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_gAMA_SUPPORTED\n      else if (chunk_name == png_gAMA)\n         png_handle_gAMA(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_hIST_SUPPORTED\n      else if (chunk_name == png_hIST)\n         png_handle_hIST(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_oFFs_SUPPORTED\n      else if (chunk_name == png_oFFs)\n         png_handle_oFFs(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_pCAL_SUPPORTED\n      else if (chunk_name == png_pCAL)\n         png_handle_pCAL(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sCAL_SUPPORTED\n      else if (chunk_name == png_sCAL)\n         png_handle_sCAL(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_pHYs_SUPPORTED\n      else if (chunk_name == png_pHYs)\n         png_handle_pHYs(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sBIT_SUPPORTED\n      else if (chunk_name == png_sBIT)\n         png_handle_sBIT(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sRGB_SUPPORTED\n      else if (chunk_name == png_sRGB)\n         png_handle_sRGB(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_iCCP_SUPPORTED\n      else if (chunk_name == png_iCCP)\n         png_handle_iCCP(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_sPLT_SUPPORTED\n      else if (chunk_name == png_sPLT)\n         png_handle_sPLT(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tEXt_SUPPORTED\n      else if (chunk_name == png_tEXt)\n         png_handle_tEXt(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tIME_SUPPORTED\n      else if (chunk_name == png_tIME)\n         png_handle_tIME(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_tRNS_SUPPORTED\n      else if (chunk_name == png_tRNS)\n         png_handle_tRNS(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_zTXt_SUPPORTED\n      else if (chunk_name == png_zTXt)\n         png_handle_zTXt(png_ptr, info_ptr, length);\n#endif\n\n#ifdef PNG_READ_iTXt_SUPPORTED\n      else if (chunk_name == png_iTXt)\n         png_handle_iTXt(png_ptr, info_ptr, length);\n#endif\n\n      else\n         png_handle_unknown(png_ptr, info_ptr, length,\n             PNG_HANDLE_CHUNK_AS_DEFAULT);\n   } while ((png_ptr->mode & PNG_HAVE_IEND) == 0);\n}\n#endif /* SEQUENTIAL_READ */\n\n/* Free all memory used in the read struct */\nstatic void\npng_read_destroy(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_read_destroy\");\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   png_destroy_gamma_table(png_ptr);\n#endif\n\n   png_free(png_ptr, png_ptr->big_row_buf);\n   png_ptr->big_row_buf = NULL;\n   png_free(png_ptr, png_ptr->big_prev_row);\n   png_ptr->big_prev_row = NULL;\n   png_free(png_ptr, png_ptr->read_buffer);\n   png_ptr->read_buffer = NULL;\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n   png_free(png_ptr, png_ptr->palette_lookup);\n   png_ptr->palette_lookup = NULL;\n   png_free(png_ptr, png_ptr->quantize_index);\n   png_ptr->quantize_index = NULL;\n#endif\n\n   if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)\n   {\n      png_zfree(png_ptr, png_ptr->palette);\n      png_ptr->palette = NULL;\n   }\n   png_ptr->free_me &= ~PNG_FREE_PLTE;\n\n#if defined(PNG_tRNS_SUPPORTED) || \\\n    defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)\n   if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)\n   {\n      png_free(png_ptr, png_ptr->trans_alpha);\n      png_ptr->trans_alpha = NULL;\n   }\n   png_ptr->free_me &= ~PNG_FREE_TRNS;\n#endif\n\n   inflateEnd(&png_ptr->zstream);\n\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\n   png_free(png_ptr, png_ptr->save_buffer);\n   png_ptr->save_buffer = NULL;\n#endif\n\n#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \\\n   defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)\n   png_free(png_ptr, png_ptr->unknown_chunk.data);\n   png_ptr->unknown_chunk.data = NULL;\n#endif\n\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n   png_free(png_ptr, png_ptr->chunk_list);\n   png_ptr->chunk_list = NULL;\n#endif\n\n#if defined(PNG_READ_EXPAND_SUPPORTED) && \\\n    defined(PNG_ARM_NEON_IMPLEMENTATION)\n   png_free(png_ptr, png_ptr->riffled_palette);\n   png_ptr->riffled_palette = NULL;\n#endif\n\n   /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error\n    * callbacks are still set at this point.  They are required to complete the\n    * destruction of the png_struct itself.\n    */\n}\n\n/* Free all memory used by the read */\nvoid PNGAPI\npng_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,\n    png_infopp end_info_ptr_ptr)\n{\n   png_structrp png_ptr = NULL;\n\n   png_debug(1, \"in png_destroy_read_struct\");\n\n   if (png_ptr_ptr != NULL)\n      png_ptr = *png_ptr_ptr;\n\n   if (png_ptr == NULL)\n      return;\n\n   /* libpng 1.6.0: use the API to destroy info structs to ensure consistent\n    * behavior.  Prior to 1.6.0 libpng did extra 'info' destruction in this API.\n    * The extra was, apparently, unnecessary yet this hides memory leak bugs.\n    */\n   png_destroy_info_struct(png_ptr, end_info_ptr_ptr);\n   png_destroy_info_struct(png_ptr, info_ptr_ptr);\n\n   *png_ptr_ptr = NULL;\n   png_read_destroy(png_ptr);\n   png_destroy_png_struct(png_ptr);\n}\n\nvoid PNGAPI\npng_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->read_row_fn = read_row_fn;\n}\n\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n#ifdef PNG_INFO_IMAGE_SUPPORTED\nvoid PNGAPI\npng_read_png(png_structrp png_ptr, png_inforp info_ptr,\n    int transforms, voidp params)\n{\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   /* png_read_info() gives us all of the information from the\n    * PNG file before the first IDAT (image data chunk).\n    */\n   png_read_info(png_ptr, info_ptr);\n   if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep)))\n      png_error(png_ptr, \"Image is too high to process with png_read_png()\");\n\n   /* -------------- image transformations start here ------------------- */\n   /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM\n    * is not implemented.  This will only happen in de-configured (non-default)\n    * libpng builds.  The results can be unexpected - png_read_png may return\n    * short or mal-formed rows because the transform is skipped.\n    */\n\n   /* Tell libpng to strip 16-bit/color files down to 8 bits per color.\n    */\n   if ((transforms & PNG_TRANSFORM_SCALE_16) != 0)\n      /* Added at libpng-1.5.4. \"strip_16\" produces the same result that it\n       * did in earlier versions, while \"scale_16\" is now more accurate.\n       */\n#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n      png_set_scale_16(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SCALE_16 not supported\");\n#endif\n\n   /* If both SCALE and STRIP are required pngrtran will effectively cancel the\n    * latter by doing SCALE first.  This is ok and allows apps not to check for\n    * which is supported to get the right answer.\n    */\n   if ((transforms & PNG_TRANSFORM_STRIP_16) != 0)\n#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n      png_set_strip_16(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_STRIP_16 not supported\");\n#endif\n\n   /* Strip alpha bytes from the input data without combining with\n    * the background (not recommended).\n    */\n   if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0)\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\n      png_set_strip_alpha(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_STRIP_ALPHA not supported\");\n#endif\n\n   /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single\n    * byte into separate bytes (useful for paletted and grayscale images).\n    */\n   if ((transforms & PNG_TRANSFORM_PACKING) != 0)\n#ifdef PNG_READ_PACK_SUPPORTED\n      png_set_packing(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_PACKING not supported\");\n#endif\n\n   /* Change the order of packed pixels to least significant bit first\n    * (not useful if you are using png_set_packing).\n    */\n   if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)\n#ifdef PNG_READ_PACKSWAP_SUPPORTED\n      png_set_packswap(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_PACKSWAP not supported\");\n#endif\n\n   /* Expand paletted colors into true RGB triplets\n    * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel\n    * Expand paletted or RGB images with transparency to full alpha\n    * channels so the data will be available as RGBA quartets.\n    */\n   if ((transforms & PNG_TRANSFORM_EXPAND) != 0)\n#ifdef PNG_READ_EXPAND_SUPPORTED\n      png_set_expand(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_EXPAND not supported\");\n#endif\n\n   /* We don't handle background color or gamma transformation or quantizing.\n    */\n\n   /* Invert monochrome files to have 0 as white and 1 as black\n    */\n   if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)\n#ifdef PNG_READ_INVERT_SUPPORTED\n      png_set_invert_mono(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_INVERT_MONO not supported\");\n#endif\n\n   /* If you want to shift the pixel values from the range [0,255] or\n    * [0,65535] to the original [0,7] or [0,31], or whatever range the\n    * colors were originally in:\n    */\n   if ((transforms & PNG_TRANSFORM_SHIFT) != 0)\n#ifdef PNG_READ_SHIFT_SUPPORTED\n      if ((info_ptr->valid & PNG_INFO_sBIT) != 0)\n         png_set_shift(png_ptr, &info_ptr->sig_bit);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SHIFT not supported\");\n#endif\n\n   /* Flip the RGB pixels to BGR (or RGBA to BGRA) */\n   if ((transforms & PNG_TRANSFORM_BGR) != 0)\n#ifdef PNG_READ_BGR_SUPPORTED\n      png_set_bgr(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_BGR not supported\");\n#endif\n\n   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */\n   if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)\n#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED\n      png_set_swap_alpha(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SWAP_ALPHA not supported\");\n#endif\n\n   /* Swap bytes of 16-bit files to least significant byte first */\n   if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)\n#ifdef PNG_READ_SWAP_SUPPORTED\n      png_set_swap(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SWAP_ENDIAN not supported\");\n#endif\n\n/* Added at libpng-1.2.41 */\n   /* Invert the alpha channel from opacity to transparency */\n   if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)\n#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED\n      png_set_invert_alpha(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_INVERT_ALPHA not supported\");\n#endif\n\n/* Added at libpng-1.2.41 */\n   /* Expand grayscale image to RGB */\n   if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0)\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n      png_set_gray_to_rgb(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_GRAY_TO_RGB not supported\");\n#endif\n\n/* Added at libpng-1.5.4 */\n   if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0)\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n      png_set_expand_16(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_EXPAND_16 not supported\");\n#endif\n\n   /* We don't handle adding filler bytes */\n\n   /* We use png_read_image and rely on that for interlace handling, but we also\n    * call png_read_update_info therefore must turn on interlace handling now:\n    */\n   (void)png_set_interlace_handling(png_ptr);\n\n   /* Optional call to gamma correct and add the background to the palette\n    * and update info structure.  REQUIRED if you are expecting libpng to\n    * update the palette for you (i.e., you selected such a transform above).\n    */\n   png_read_update_info(png_ptr, info_ptr);\n\n   /* -------------- image transformations end here ------------------- */\n\n   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);\n   if (info_ptr->row_pointers == NULL)\n   {\n      png_uint_32 iptr;\n\n      info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr,\n          info_ptr->height * (sizeof (png_bytep))));\n\n      for (iptr=0; iptr<info_ptr->height; iptr++)\n         info_ptr->row_pointers[iptr] = NULL;\n\n      info_ptr->free_me |= PNG_FREE_ROWS;\n\n      for (iptr = 0; iptr < info_ptr->height; iptr++)\n         info_ptr->row_pointers[iptr] = png_voidcast(png_bytep,\n             png_malloc(png_ptr, info_ptr->rowbytes));\n   }\n\n   png_read_image(png_ptr, info_ptr->row_pointers);\n   info_ptr->valid |= PNG_INFO_IDAT;\n\n   /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */\n   png_read_end(png_ptr, info_ptr);\n\n   PNG_UNUSED(params)\n}\n#endif /* INFO_IMAGE */\n#endif /* SEQUENTIAL_READ */\n\n#ifdef PNG_SIMPLIFIED_READ_SUPPORTED\n/* SIMPLIFIED READ\n *\n * This code currently relies on the sequential reader, though it could easily\n * be made to work with the progressive one.\n */\n/* Arguments to png_image_finish_read: */\n\n/* Encoding of PNG data (used by the color-map code) */\n#  define P_NOTSET  0 /* File encoding not yet known */\n#  define P_sRGB    1 /* 8-bit encoded to sRGB gamma */\n#  define P_LINEAR  2 /* 16-bit linear: not encoded, NOT pre-multiplied! */\n#  define P_FILE    3 /* 8-bit encoded to file gamma, not sRGB or linear */\n#  define P_LINEAR8 4 /* 8-bit linear: only from a file value */\n\n/* Color-map processing: after libpng has run on the PNG image further\n * processing may be needed to convert the data to color-map indices.\n */\n#define PNG_CMAP_NONE      0\n#define PNG_CMAP_GA        1 /* Process GA data to a color-map with alpha */\n#define PNG_CMAP_TRANS     2 /* Process GA data to a background index */\n#define PNG_CMAP_RGB       3 /* Process RGB data */\n#define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */\n\n/* The following document where the background is for each processing case. */\n#define PNG_CMAP_NONE_BACKGROUND      256\n#define PNG_CMAP_GA_BACKGROUND        231\n#define PNG_CMAP_TRANS_BACKGROUND     254\n#define PNG_CMAP_RGB_BACKGROUND       256\n#define PNG_CMAP_RGB_ALPHA_BACKGROUND 216\n\ntypedef struct\n{\n   /* Arguments: */\n   png_imagep image;\n   png_voidp  buffer;\n   png_int_32 row_stride;\n   png_voidp  colormap;\n   png_const_colorp background;\n   /* Local variables: */\n   png_voidp       local_row;\n   png_voidp       first_row;\n   ptrdiff_t       row_bytes;           /* step between rows */\n   int             file_encoding;       /* E_ values above */\n   png_fixed_point gamma_to_linear;     /* For P_FILE, reciprocal of gamma */\n   int             colormap_processing; /* PNG_CMAP_ values above */\n} png_image_read_control;\n\n/* Do all the *safe* initialization - 'safe' means that png_error won't be\n * called, so setting up the jmp_buf is not required.  This means that anything\n * called from here must *not* call png_malloc - it has to call png_malloc_warn\n * instead so that control is returned safely back to this routine.\n */\nstatic int\npng_image_read_init(png_imagep image)\n{\n   if (image->opaque == NULL)\n   {\n      png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image,\n          png_safe_error, png_safe_warning);\n\n      /* And set the rest of the structure to NULL to ensure that the various\n       * fields are consistent.\n       */\n      memset(image, 0, (sizeof *image));\n      image->version = PNG_IMAGE_VERSION;\n\n      if (png_ptr != NULL)\n      {\n         png_infop info_ptr = png_create_info_struct(png_ptr);\n\n         if (info_ptr != NULL)\n         {\n            png_controlp control = png_voidcast(png_controlp,\n                png_malloc_warn(png_ptr, (sizeof *control)));\n\n            if (control != NULL)\n            {\n               memset(control, 0, (sizeof *control));\n\n               control->png_ptr = png_ptr;\n               control->info_ptr = info_ptr;\n               control->for_write = 0;\n\n               image->opaque = control;\n               return 1;\n            }\n\n            /* Error clean up */\n            png_destroy_info_struct(png_ptr, &info_ptr);\n         }\n\n         png_destroy_read_struct(&png_ptr, NULL, NULL);\n      }\n\n      return png_image_error(image, \"png_image_read: out of memory\");\n   }\n\n   return png_image_error(image, \"png_image_read: opaque pointer not NULL\");\n}\n\n/* Utility to find the base format of a PNG file from a png_struct. */\nstatic png_uint_32\npng_image_format(png_structrp png_ptr)\n{\n   png_uint_32 format = 0;\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      format |= PNG_FORMAT_FLAG_COLOR;\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      format |= PNG_FORMAT_FLAG_ALPHA;\n\n   /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS\n    * sets the png_struct fields; that's all we are interested in here.  The\n    * precise interaction with an app call to png_set_tRNS and PNG file reading\n    * is unclear.\n    */\n   else if (png_ptr->num_trans > 0)\n      format |= PNG_FORMAT_FLAG_ALPHA;\n\n   if (png_ptr->bit_depth == 16)\n      format |= PNG_FORMAT_FLAG_LINEAR;\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0)\n      format |= PNG_FORMAT_FLAG_COLORMAP;\n\n   return format;\n}\n\n/* Is the given gamma significantly different from sRGB?  The test is the same\n * one used in pngrtran.c when deciding whether to do gamma correction.  The\n * arithmetic optimizes the division by using the fact that the inverse of the\n * file sRGB gamma is 2.2\n */\nstatic int\npng_gamma_not_sRGB(png_fixed_point g)\n{\n   if (g < PNG_FP_1)\n   {\n      /* An uninitialized gamma is assumed to be sRGB for the simplified API. */\n      if (g == 0)\n         return 0;\n\n      return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);\n   }\n\n   return 1;\n}\n\n/* Do the main body of a 'png_image_begin_read' function; read the PNG file\n * header and fill in all the information.  This is executed in a safe context,\n * unlike the init routine above.\n */\nstatic int\npng_image_read_header(png_voidp argument)\n{\n   png_imagep image = png_voidcast(png_imagep, argument);\n   png_structrp png_ptr = image->opaque->png_ptr;\n   png_inforp info_ptr = image->opaque->info_ptr;\n\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\n   png_set_benign_errors(png_ptr, 1/*warn*/);\n#endif\n   png_read_info(png_ptr, info_ptr);\n\n   /* Do this the fast way; just read directly out of png_struct. */\n   image->width = png_ptr->width;\n   image->height = png_ptr->height;\n\n   {\n      png_uint_32 format = png_image_format(png_ptr);\n\n      image->format = format;\n\n#ifdef PNG_COLORSPACE_SUPPORTED\n      /* Does the colorspace match sRGB?  If there is no color endpoint\n       * (colorant) information assume yes, otherwise require the\n       * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set.  If the\n       * colorspace has been determined to be invalid ignore it.\n       */\n      if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags\n         & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|\n            PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))\n         image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;\n#endif\n   }\n\n   /* We need the maximum number of entries regardless of the format the\n    * application sets here.\n    */\n   {\n      png_uint_32 cmap_entries;\n\n      switch (png_ptr->color_type)\n      {\n         case PNG_COLOR_TYPE_GRAY:\n            cmap_entries = 1U << png_ptr->bit_depth;\n            break;\n\n         case PNG_COLOR_TYPE_PALETTE:\n            cmap_entries = (png_uint_32)png_ptr->num_palette;\n            break;\n\n         default:\n            cmap_entries = 256;\n            break;\n      }\n\n      if (cmap_entries > 256)\n         cmap_entries = 256;\n\n      image->colormap_entries = cmap_entries;\n   }\n\n   return 1;\n}\n\n#ifdef PNG_STDIO_SUPPORTED\nint PNGAPI\npng_image_begin_read_from_stdio(png_imagep image, FILE* file)\n{\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (file != NULL)\n      {\n         if (png_image_read_init(image) != 0)\n         {\n            /* This is slightly evil, but png_init_io doesn't do anything other\n             * than this and we haven't changed the standard IO functions so\n             * this saves a 'safe' function.\n             */\n            image->opaque->png_ptr->io_ptr = file;\n            return png_safe_execute(image, png_image_read_header, image);\n         }\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_begin_read_from_stdio: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION\");\n\n   return 0;\n}\n\nint PNGAPI\npng_image_begin_read_from_file(png_imagep image, const char *file_name)\n{\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (file_name != NULL)\n      {\n         FILE *fp = fopen(file_name, \"rb\");\n\n         if (fp != NULL)\n         {\n            if (png_image_read_init(image) != 0)\n            {\n               image->opaque->png_ptr->io_ptr = fp;\n               image->opaque->owned_file = 1;\n               return png_safe_execute(image, png_image_read_header, image);\n            }\n\n            /* Clean up: just the opened file. */\n            (void)fclose(fp);\n         }\n\n         else\n            return png_image_error(image, strerror(errno));\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_begin_read_from_file: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION\");\n\n   return 0;\n}\n#endif /* STDIO */\n\nstatic void PNGCBAPI\npng_image_memory_read(png_structp png_ptr, png_bytep out, size_t need)\n{\n   if (png_ptr != NULL)\n   {\n      png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr);\n      if (image != NULL)\n      {\n         png_controlp cp = image->opaque;\n         if (cp != NULL)\n         {\n            png_const_bytep memory = cp->memory;\n            size_t size = cp->size;\n\n            if (memory != NULL && size >= need)\n            {\n               memcpy(out, memory, need);\n               cp->memory = memory + need;\n               cp->size = size - need;\n               return;\n            }\n\n            png_error(png_ptr, \"read beyond end of data\");\n         }\n      }\n\n      png_error(png_ptr, \"invalid memory read\");\n   }\n}\n\nint PNGAPI png_image_begin_read_from_memory(png_imagep image,\n    png_const_voidp memory, size_t size)\n{\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (memory != NULL && size > 0)\n      {\n         if (png_image_read_init(image) != 0)\n         {\n            /* Now set the IO functions to read from the memory buffer and\n             * store it into io_ptr.  Again do this in-place to avoid calling a\n             * libpng function that requires error handling.\n             */\n            image->opaque->memory = png_voidcast(png_const_bytep, memory);\n            image->opaque->size = size;\n            image->opaque->png_ptr->io_ptr = image;\n            image->opaque->png_ptr->read_data_fn = png_image_memory_read;\n\n            return png_safe_execute(image, png_image_read_header, image);\n         }\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_begin_read_from_memory: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION\");\n\n   return 0;\n}\n\n/* Utility function to skip chunks that are not used by the simplified image\n * read functions and an appropriate macro to call it.\n */\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\nstatic void\npng_image_skip_unused_chunks(png_structrp png_ptr)\n{\n   /* Prepare the reader to ignore all recognized chunks whose data will not\n    * be used, i.e., all chunks recognized by libpng except for those\n    * involved in basic image reading:\n    *\n    *    IHDR, PLTE, IDAT, IEND\n    *\n    * Or image data handling:\n    *\n    *    tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT.\n    *\n    * This provides a small performance improvement and eliminates any\n    * potential vulnerability to security problems in the unused chunks.\n    *\n    * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored\n    * too.  This allows the simplified API to be compiled without iCCP support,\n    * however if the support is there the chunk is still checked to detect\n    * errors (which are unfortunately quite common.)\n    */\n   {\n         static const png_byte chunks_to_process[] = {\n            98,  75,  71,  68, '\\0',  /* bKGD */\n            99,  72,  82,  77, '\\0',  /* cHRM */\n           103,  65,  77,  65, '\\0',  /* gAMA */\n#        ifdef PNG_READ_iCCP_SUPPORTED\n           105,  67,  67,  80, '\\0',  /* iCCP */\n#        endif\n           115,  66,  73,  84, '\\0',  /* sBIT */\n           115,  82,  71,  66, '\\0',  /* sRGB */\n           };\n\n       /* Ignore unknown chunks and all other chunks except for the\n        * IHDR, PLTE, tRNS, IDAT, and IEND chunks.\n        */\n       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER,\n           NULL, -1);\n\n       /* But do not ignore image data handling chunks */\n       png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT,\n           chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5);\n   }\n}\n\n#  define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p)\n#else\n#  define PNG_SKIP_CHUNKS(p) ((void)0)\n#endif /* HANDLE_AS_UNKNOWN */\n\n/* The following macro gives the exact rounded answer for all values in the\n * range 0..255 (it actually divides by 51.2, but the rounding still generates\n * the correct numbers 0..5\n */\n#define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8)\n\n/* Utility functions to make particular color-maps */\nstatic void\nset_file_encoding(png_image_read_control *display)\n{\n   png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;\n   if (png_gamma_significant(g) != 0)\n   {\n      if (png_gamma_not_sRGB(g) != 0)\n      {\n         display->file_encoding = P_FILE;\n         display->gamma_to_linear = png_reciprocal(g);\n      }\n\n      else\n         display->file_encoding = P_sRGB;\n   }\n\n   else\n      display->file_encoding = P_LINEAR8;\n}\n\nstatic unsigned int\ndecode_gamma(png_image_read_control *display, png_uint_32 value, int encoding)\n{\n   if (encoding == P_FILE) /* double check */\n      encoding = display->file_encoding;\n\n   if (encoding == P_NOTSET) /* must be the file encoding */\n   {\n      set_file_encoding(display);\n      encoding = display->file_encoding;\n   }\n\n   switch (encoding)\n   {\n      case P_FILE:\n         value = png_gamma_16bit_correct(value*257, display->gamma_to_linear);\n         break;\n\n      case P_sRGB:\n         value = png_sRGB_table[value];\n         break;\n\n      case P_LINEAR:\n         break;\n\n      case P_LINEAR8:\n         value *= 257;\n         break;\n\n#ifdef __GNUC__\n      default:\n         png_error(display->image->opaque->png_ptr,\n             \"unexpected encoding (internal error)\");\n#endif\n   }\n\n   return value;\n}\n\nstatic png_uint_32\npng_colormap_compose(png_image_read_control *display,\n    png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha,\n    png_uint_32 background, int encoding)\n{\n   /* The file value is composed on the background, the background has the given\n    * encoding and so does the result, the file is encoded with P_FILE and the\n    * file and alpha are 8-bit values.  The (output) encoding will always be\n    * P_LINEAR or P_sRGB.\n    */\n   png_uint_32 f = decode_gamma(display, foreground, foreground_encoding);\n   png_uint_32 b = decode_gamma(display, background, encoding);\n\n   /* The alpha is always an 8-bit value (it comes from the palette), the value\n    * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires.\n    */\n   f = f * alpha + b * (255-alpha);\n\n   if (encoding == P_LINEAR)\n   {\n      /* Scale to 65535; divide by 255, approximately (in fact this is extremely\n       * accurate, it divides by 255.00000005937181414556, with no overflow.)\n       */\n      f *= 257; /* Now scaled by 65535 */\n      f += f >> 16;\n      f = (f+32768) >> 16;\n   }\n\n   else /* P_sRGB */\n      f = PNG_sRGB_FROM_LINEAR(f);\n\n   return f;\n}\n\n/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must\n * be 8-bit.\n */\nstatic void\npng_create_colormap_entry(png_image_read_control *display,\n    png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue,\n    png_uint_32 alpha, int encoding)\n{\n   png_imagep image = display->image;\n   int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ?\n       P_LINEAR : P_sRGB;\n   int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 &&\n       (red != green || green != blue);\n\n   if (ip > 255)\n      png_error(image->opaque->png_ptr, \"color-map index out of range\");\n\n   /* Update the cache with whether the file gamma is significantly different\n    * from sRGB.\n    */\n   if (encoding == P_FILE)\n   {\n      if (display->file_encoding == P_NOTSET)\n         set_file_encoding(display);\n\n      /* Note that the cached value may be P_FILE too, but if it is then the\n       * gamma_to_linear member has been set.\n       */\n      encoding = display->file_encoding;\n   }\n\n   if (encoding == P_FILE)\n   {\n      png_fixed_point g = display->gamma_to_linear;\n\n      red = png_gamma_16bit_correct(red*257, g);\n      green = png_gamma_16bit_correct(green*257, g);\n      blue = png_gamma_16bit_correct(blue*257, g);\n\n      if (convert_to_Y != 0 || output_encoding == P_LINEAR)\n      {\n         alpha *= 257;\n         encoding = P_LINEAR;\n      }\n\n      else\n      {\n         red = PNG_sRGB_FROM_LINEAR(red * 255);\n         green = PNG_sRGB_FROM_LINEAR(green * 255);\n         blue = PNG_sRGB_FROM_LINEAR(blue * 255);\n         encoding = P_sRGB;\n      }\n   }\n\n   else if (encoding == P_LINEAR8)\n   {\n      /* This encoding occurs quite frequently in test cases because PngSuite\n       * includes a gAMA 1.0 chunk with most images.\n       */\n      red *= 257;\n      green *= 257;\n      blue *= 257;\n      alpha *= 257;\n      encoding = P_LINEAR;\n   }\n\n   else if (encoding == P_sRGB &&\n       (convert_to_Y  != 0 || output_encoding == P_LINEAR))\n   {\n      /* The values are 8-bit sRGB values, but must be converted to 16-bit\n       * linear.\n       */\n      red = png_sRGB_table[red];\n      green = png_sRGB_table[green];\n      blue = png_sRGB_table[blue];\n      alpha *= 257;\n      encoding = P_LINEAR;\n   }\n\n   /* This is set if the color isn't gray but the output is. */\n   if (encoding == P_LINEAR)\n   {\n      if (convert_to_Y != 0)\n      {\n         /* NOTE: these values are copied from png_do_rgb_to_gray */\n         png_uint_32 y = (png_uint_32)6968 * red  + (png_uint_32)23434 * green +\n            (png_uint_32)2366 * blue;\n\n         if (output_encoding == P_LINEAR)\n            y = (y + 16384) >> 15;\n\n         else\n         {\n            /* y is scaled by 32768, we need it scaled by 255: */\n            y = (y + 128) >> 8;\n            y *= 255;\n            y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7);\n            alpha = PNG_DIV257(alpha);\n            encoding = P_sRGB;\n         }\n\n         blue = red = green = y;\n      }\n\n      else if (output_encoding == P_sRGB)\n      {\n         red = PNG_sRGB_FROM_LINEAR(red * 255);\n         green = PNG_sRGB_FROM_LINEAR(green * 255);\n         blue = PNG_sRGB_FROM_LINEAR(blue * 255);\n         alpha = PNG_DIV257(alpha);\n         encoding = P_sRGB;\n      }\n   }\n\n   if (encoding != output_encoding)\n      png_error(image->opaque->png_ptr, \"bad encoding (internal error)\");\n\n   /* Store the value. */\n   {\n#     ifdef PNG_FORMAT_AFIRST_SUPPORTED\n         int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 &&\n            (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;\n#     else\n#        define afirst 0\n#     endif\n#     ifdef PNG_FORMAT_BGR_SUPPORTED\n         int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;\n#     else\n#        define bgr 0\n#     endif\n\n      if (output_encoding == P_LINEAR)\n      {\n         png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap);\n\n         entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);\n\n         /* The linear 16-bit values must be pre-multiplied by the alpha channel\n          * value, if less than 65535 (this is, effectively, composite on black\n          * if the alpha channel is removed.)\n          */\n         switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))\n         {\n            case 4:\n               entry[afirst ? 0 : 3] = (png_uint_16)alpha;\n               /* FALLTHROUGH */\n\n            case 3:\n               if (alpha < 65535)\n               {\n                  if (alpha > 0)\n                  {\n                     blue = (blue * alpha + 32767U)/65535U;\n                     green = (green * alpha + 32767U)/65535U;\n                     red = (red * alpha + 32767U)/65535U;\n                  }\n\n                  else\n                     red = green = blue = 0;\n               }\n               entry[afirst + (2 ^ bgr)] = (png_uint_16)blue;\n               entry[afirst + 1] = (png_uint_16)green;\n               entry[afirst + bgr] = (png_uint_16)red;\n               break;\n\n            case 2:\n               entry[1 ^ afirst] = (png_uint_16)alpha;\n               /* FALLTHROUGH */\n\n            case 1:\n               if (alpha < 65535)\n               {\n                  if (alpha > 0)\n                     green = (green * alpha + 32767U)/65535U;\n\n                  else\n                     green = 0;\n               }\n               entry[afirst] = (png_uint_16)green;\n               break;\n\n            default:\n               break;\n         }\n      }\n\n      else /* output encoding is P_sRGB */\n      {\n         png_bytep entry = png_voidcast(png_bytep, display->colormap);\n\n         entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);\n\n         switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))\n         {\n            case 4:\n               entry[afirst ? 0 : 3] = (png_byte)alpha;\n               /* FALLTHROUGH */\n            case 3:\n               entry[afirst + (2 ^ bgr)] = (png_byte)blue;\n               entry[afirst + 1] = (png_byte)green;\n               entry[afirst + bgr] = (png_byte)red;\n               break;\n\n            case 2:\n               entry[1 ^ afirst] = (png_byte)alpha;\n               /* FALLTHROUGH */\n            case 1:\n               entry[afirst] = (png_byte)green;\n               break;\n\n            default:\n               break;\n         }\n      }\n\n#     ifdef afirst\n#        undef afirst\n#     endif\n#     ifdef bgr\n#        undef bgr\n#     endif\n   }\n}\n\nstatic int\nmake_gray_file_colormap(png_image_read_control *display)\n{\n   unsigned int i;\n\n   for (i=0; i<256; ++i)\n      png_create_colormap_entry(display, i, i, i, i, 255, P_FILE);\n\n   return (int)i;\n}\n\nstatic int\nmake_gray_colormap(png_image_read_control *display)\n{\n   unsigned int i;\n\n   for (i=0; i<256; ++i)\n      png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB);\n\n   return (int)i;\n}\n#define PNG_GRAY_COLORMAP_ENTRIES 256\n\nstatic int\nmake_ga_colormap(png_image_read_control *display)\n{\n   unsigned int i, a;\n\n   /* Alpha is retained, the output will be a color-map with entries\n    * selected by six levels of alpha.  One transparent entry, 6 gray\n    * levels for all the intermediate alpha values, leaving 230 entries\n    * for the opaque grays.  The color-map entries are the six values\n    * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the\n    * relevant entry.\n    *\n    * if (alpha > 229) // opaque\n    * {\n    *    // The 231 entries are selected to make the math below work:\n    *    base = 0;\n    *    entry = (231 * gray + 128) >> 8;\n    * }\n    * else if (alpha < 26) // transparent\n    * {\n    *    base = 231;\n    *    entry = 0;\n    * }\n    * else // partially opaque\n    * {\n    *    base = 226 + 6 * PNG_DIV51(alpha);\n    *    entry = PNG_DIV51(gray);\n    * }\n    */\n   i = 0;\n   while (i < 231)\n   {\n      unsigned int gray = (i * 256 + 115) / 231;\n      png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB);\n   }\n\n   /* 255 is used here for the component values for consistency with the code\n    * that undoes premultiplication in pngwrite.c.\n    */\n   png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB);\n\n   for (a=1; a<5; ++a)\n   {\n      unsigned int g;\n\n      for (g=0; g<6; ++g)\n         png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,\n             P_sRGB);\n   }\n\n   return (int)i;\n}\n\n#define PNG_GA_COLORMAP_ENTRIES 256\n\nstatic int\nmake_rgb_colormap(png_image_read_control *display)\n{\n   unsigned int i, r;\n\n   /* Build a 6x6x6 opaque RGB cube */\n   for (i=r=0; r<6; ++r)\n   {\n      unsigned int g;\n\n      for (g=0; g<6; ++g)\n      {\n         unsigned int b;\n\n         for (b=0; b<6; ++b)\n            png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,\n                P_sRGB);\n      }\n   }\n\n   return (int)i;\n}\n\n#define PNG_RGB_COLORMAP_ENTRIES 216\n\n/* Return a palette index to the above palette given three 8-bit sRGB values. */\n#define PNG_RGB_INDEX(r,g,b) \\\n   ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b)))\n\nstatic int\npng_image_read_colormap(png_voidp argument)\n{\n   png_image_read_control *display =\n      png_voidcast(png_image_read_control*, argument);\n   png_imagep image = display->image;\n\n   png_structrp png_ptr = image->opaque->png_ptr;\n   png_uint_32 output_format = image->format;\n   int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ?\n      P_LINEAR : P_sRGB;\n\n   unsigned int cmap_entries;\n   unsigned int output_processing;        /* Output processing option */\n   unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */\n\n   /* Background information; the background color and the index of this color\n    * in the color-map if it exists (else 256).\n    */\n   unsigned int background_index = 256;\n   png_uint_32 back_r, back_g, back_b;\n\n   /* Flags to accumulate things that need to be done to the input. */\n   int expand_tRNS = 0;\n\n   /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is\n    * very difficult to do, the results look awful, and it is difficult to see\n    * what possible use it is because the application can't control the\n    * color-map.\n    */\n   if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 ||\n         png_ptr->num_trans > 0) /* alpha in input */ &&\n      ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */)\n   {\n      if (output_encoding == P_LINEAR) /* compose on black */\n         back_b = back_g = back_r = 0;\n\n      else if (display->background == NULL /* no way to remove it */)\n         png_error(png_ptr,\n             \"background color must be supplied to remove alpha/transparency\");\n\n      /* Get a copy of the background color (this avoids repeating the checks\n       * below.)  The encoding is 8-bit sRGB or 16-bit linear, depending on the\n       * output format.\n       */\n      else\n      {\n         back_g = display->background->green;\n         if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0)\n         {\n            back_r = display->background->red;\n            back_b = display->background->blue;\n         }\n         else\n            back_b = back_r = back_g;\n      }\n   }\n\n   else if (output_encoding == P_LINEAR)\n      back_b = back_r = back_g = 65535;\n\n   else\n      back_b = back_r = back_g = 255;\n\n   /* Default the input file gamma if required - this is necessary because\n    * libpng assumes that if no gamma information is present the data is in the\n    * output format, but the simplified API deduces the gamma from the input\n    * format.\n    */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)\n   {\n      /* Do this directly, not using the png_colorspace functions, to ensure\n       * that it happens even if the colorspace is invalid (though probably if\n       * it is the setting will be ignored)  Note that the same thing can be\n       * achieved at the application interface with png_set_gAMA.\n       */\n      if (png_ptr->bit_depth == 16 &&\n         (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)\n         png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;\n\n      else\n         png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;\n\n      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;\n   }\n\n   /* Decide what to do based on the PNG color type of the input data.  The\n    * utility function png_create_colormap_entry deals with most aspects of the\n    * output transformations; this code works out how to produce bytes of\n    * color-map entries from the original format.\n    */\n   switch (png_ptr->color_type)\n   {\n      case PNG_COLOR_TYPE_GRAY:\n         if (png_ptr->bit_depth <= 8)\n         {\n            /* There at most 256 colors in the output, regardless of\n             * transparency.\n             */\n            unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0;\n\n            cmap_entries = 1U << png_ptr->bit_depth;\n            if (cmap_entries > image->colormap_entries)\n               png_error(png_ptr, \"gray[8] color-map: too few entries\");\n\n            step = 255 / (cmap_entries - 1);\n            output_processing = PNG_CMAP_NONE;\n\n            /* If there is a tRNS chunk then this either selects a transparent\n             * value or, if the output has no alpha, the background color.\n             */\n            if (png_ptr->num_trans > 0)\n            {\n               trans = png_ptr->trans_color.gray;\n\n               if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0)\n                  back_alpha = output_encoding == P_LINEAR ? 65535 : 255;\n            }\n\n            /* png_create_colormap_entry just takes an RGBA and writes the\n             * corresponding color-map entry using the format from 'image',\n             * including the required conversion to sRGB or linear as\n             * appropriate.  The input values are always either sRGB (if the\n             * gamma correction flag is 0) or 0..255 scaled file encoded values\n             * (if the function must gamma correct them).\n             */\n            for (i=val=0; i<cmap_entries; ++i, val += step)\n            {\n               /* 'i' is a file value.  While this will result in duplicated\n                * entries for 8-bit non-sRGB encoded files it is necessary to\n                * have non-gamma corrected values to do tRNS handling.\n                */\n               if (i != trans)\n                  png_create_colormap_entry(display, i, val, val, val, 255,\n                      P_FILE/*8-bit with file gamma*/);\n\n               /* Else this entry is transparent.  The colors don't matter if\n                * there is an alpha channel (back_alpha == 0), but it does no\n                * harm to pass them in; the values are not set above so this\n                * passes in white.\n                *\n                * NOTE: this preserves the full precision of the application\n                * supplied background color when it is used.\n                */\n               else\n                  png_create_colormap_entry(display, i, back_r, back_g, back_b,\n                      back_alpha, output_encoding);\n            }\n\n            /* We need libpng to preserve the original encoding. */\n            data_encoding = P_FILE;\n\n            /* The rows from libpng, while technically gray values, are now also\n             * color-map indices; however, they may need to be expanded to 1\n             * byte per pixel.  This is what png_set_packing does (i.e., it\n             * unpacks the bit values into bytes.)\n             */\n            if (png_ptr->bit_depth < 8)\n               png_set_packing(png_ptr);\n         }\n\n         else /* bit depth is 16 */\n         {\n            /* The 16-bit input values can be converted directly to 8-bit gamma\n             * encoded values; however, if a tRNS chunk is present 257 color-map\n             * entries are required.  This means that the extra entry requires\n             * special processing; add an alpha channel, sacrifice gray level\n             * 254 and convert transparent (alpha==0) entries to that.\n             *\n             * Use libpng to chop the data to 8 bits.  Convert it to sRGB at the\n             * same time to minimize quality loss.  If a tRNS chunk is present\n             * this means libpng must handle it too; otherwise it is impossible\n             * to do the exact match on the 16-bit value.\n             *\n             * If the output has no alpha channel *and* the background color is\n             * gray then it is possible to let libpng handle the substitution by\n             * ensuring that the corresponding gray level matches the background\n             * color exactly.\n             */\n            data_encoding = P_sRGB;\n\n            if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)\n               png_error(png_ptr, \"gray[16] color-map: too few entries\");\n\n            cmap_entries = (unsigned int)make_gray_colormap(display);\n\n            if (png_ptr->num_trans > 0)\n            {\n               unsigned int back_alpha;\n\n               if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n                  back_alpha = 0;\n\n               else\n               {\n                  if (back_r == back_g && back_g == back_b)\n                  {\n                     /* Background is gray; no special processing will be\n                      * required.\n                      */\n                     png_color_16 c;\n                     png_uint_32 gray = back_g;\n\n                     if (output_encoding == P_LINEAR)\n                     {\n                        gray = PNG_sRGB_FROM_LINEAR(gray * 255);\n\n                        /* And make sure the corresponding palette entry\n                         * matches.\n                         */\n                        png_create_colormap_entry(display, gray, back_g, back_g,\n                            back_g, 65535, P_LINEAR);\n                     }\n\n                     /* The background passed to libpng, however, must be the\n                      * sRGB value.\n                      */\n                     c.index = 0; /*unused*/\n                     c.gray = c.red = c.green = c.blue = (png_uint_16)gray;\n\n                     /* NOTE: does this work without expanding tRNS to alpha?\n                      * It should be the color->gray case below apparently\n                      * doesn't.\n                      */\n                     png_set_background_fixed(png_ptr, &c,\n                         PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,\n                         0/*gamma: not used*/);\n\n                     output_processing = PNG_CMAP_NONE;\n                     break;\n                  }\n#ifdef __COVERITY__\n                 /* Coverity claims that output_encoding cannot be 2 (P_LINEAR)\n                  * here.\n                  */\n                  back_alpha = 255;\n#else\n                  back_alpha = output_encoding == P_LINEAR ? 65535 : 255;\n#endif\n               }\n\n               /* output_processing means that the libpng-processed row will be\n                * 8-bit GA and it has to be processing to single byte color-map\n                * values.  Entry 254 is replaced by either a completely\n                * transparent entry or by the background color at full\n                * precision (and the background color is not a simple gray\n                * level in this case.)\n                */\n               expand_tRNS = 1;\n               output_processing = PNG_CMAP_TRANS;\n               background_index = 254;\n\n               /* And set (overwrite) color-map entry 254 to the actual\n                * background color at full precision.\n                */\n               png_create_colormap_entry(display, 254, back_r, back_g, back_b,\n                   back_alpha, output_encoding);\n            }\n\n            else\n               output_processing = PNG_CMAP_NONE;\n         }\n         break;\n\n      case PNG_COLOR_TYPE_GRAY_ALPHA:\n         /* 8-bit or 16-bit PNG with two channels - gray and alpha.  A minimum\n          * of 65536 combinations.  If, however, the alpha channel is to be\n          * removed there are only 256 possibilities if the background is gray.\n          * (Otherwise there is a subset of the 65536 possibilities defined by\n          * the triangle between black, white and the background color.)\n          *\n          * Reduce 16-bit files to 8-bit and sRGB encode the result.  No need to\n          * worry about tRNS matching - tRNS is ignored if there is an alpha\n          * channel.\n          */\n         data_encoding = P_sRGB;\n\n         if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n         {\n            if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)\n               png_error(png_ptr, \"gray+alpha color-map: too few entries\");\n\n            cmap_entries = (unsigned int)make_ga_colormap(display);\n\n            background_index = PNG_CMAP_GA_BACKGROUND;\n            output_processing = PNG_CMAP_GA;\n         }\n\n         else /* alpha is removed */\n         {\n            /* Alpha must be removed as the PNG data is processed when the\n             * background is a color because the G and A channels are\n             * independent and the vector addition (non-parallel vectors) is a\n             * 2-D problem.\n             *\n             * This can be reduced to the same algorithm as above by making a\n             * colormap containing gray levels (for the opaque grays), a\n             * background entry (for a transparent pixel) and a set of four six\n             * level color values, one set for each intermediate alpha value.\n             * See the comments in make_ga_colormap for how this works in the\n             * per-pixel processing.\n             *\n             * If the background is gray, however, we only need a 256 entry gray\n             * level color map.  It is sufficient to make the entry generated\n             * for the background color be exactly the color specified.\n             */\n            if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 ||\n               (back_r == back_g && back_g == back_b))\n            {\n               /* Background is gray; no special processing will be required. */\n               png_color_16 c;\n               png_uint_32 gray = back_g;\n\n               if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)\n                  png_error(png_ptr, \"gray-alpha color-map: too few entries\");\n\n               cmap_entries = (unsigned int)make_gray_colormap(display);\n\n               if (output_encoding == P_LINEAR)\n               {\n                  gray = PNG_sRGB_FROM_LINEAR(gray * 255);\n\n                  /* And make sure the corresponding palette entry matches. */\n                  png_create_colormap_entry(display, gray, back_g, back_g,\n                      back_g, 65535, P_LINEAR);\n               }\n\n               /* The background passed to libpng, however, must be the sRGB\n                * value.\n                */\n               c.index = 0; /*unused*/\n               c.gray = c.red = c.green = c.blue = (png_uint_16)gray;\n\n               png_set_background_fixed(png_ptr, &c,\n                   PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,\n                   0/*gamma: not used*/);\n\n               output_processing = PNG_CMAP_NONE;\n            }\n\n            else\n            {\n               png_uint_32 i, a;\n\n               /* This is the same as png_make_ga_colormap, above, except that\n                * the entries are all opaque.\n                */\n               if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)\n                  png_error(png_ptr, \"ga-alpha color-map: too few entries\");\n\n               i = 0;\n               while (i < 231)\n               {\n                  png_uint_32 gray = (i * 256 + 115) / 231;\n                  png_create_colormap_entry(display, i++, gray, gray, gray,\n                      255, P_sRGB);\n               }\n\n               /* NOTE: this preserves the full precision of the application\n                * background color.\n                */\n               background_index = i;\n               png_create_colormap_entry(display, i++, back_r, back_g, back_b,\n#ifdef __COVERITY__\n                   /* Coverity claims that output_encoding\n                    * cannot be 2 (P_LINEAR) here.\n                    */ 255U,\n#else\n                    output_encoding == P_LINEAR ? 65535U : 255U,\n#endif\n                    output_encoding);\n\n               /* For non-opaque input composite on the sRGB background - this\n                * requires inverting the encoding for each component.  The input\n                * is still converted to the sRGB encoding because this is a\n                * reasonable approximate to the logarithmic curve of human\n                * visual sensitivity, at least over the narrow range which PNG\n                * represents.  Consequently 'G' is always sRGB encoded, while\n                * 'A' is linear.  We need the linear background colors.\n                */\n               if (output_encoding == P_sRGB) /* else already linear */\n               {\n                  /* This may produce a value not exactly matching the\n                   * background, but that's ok because these numbers are only\n                   * used when alpha != 0\n                   */\n                  back_r = png_sRGB_table[back_r];\n                  back_g = png_sRGB_table[back_g];\n                  back_b = png_sRGB_table[back_b];\n               }\n\n               for (a=1; a<5; ++a)\n               {\n                  unsigned int g;\n\n                  /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled\n                   * by an 8-bit alpha value (0..255).\n                   */\n                  png_uint_32 alpha = 51 * a;\n                  png_uint_32 back_rx = (255-alpha) * back_r;\n                  png_uint_32 back_gx = (255-alpha) * back_g;\n                  png_uint_32 back_bx = (255-alpha) * back_b;\n\n                  for (g=0; g<6; ++g)\n                  {\n                     png_uint_32 gray = png_sRGB_table[g*51] * alpha;\n\n                     png_create_colormap_entry(display, i++,\n                         PNG_sRGB_FROM_LINEAR(gray + back_rx),\n                         PNG_sRGB_FROM_LINEAR(gray + back_gx),\n                         PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB);\n                  }\n               }\n\n               cmap_entries = i;\n               output_processing = PNG_CMAP_GA;\n            }\n         }\n         break;\n\n      case PNG_COLOR_TYPE_RGB:\n      case PNG_COLOR_TYPE_RGB_ALPHA:\n         /* Exclude the case where the output is gray; we can always handle this\n          * with the cases above.\n          */\n         if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)\n         {\n            /* The color-map will be grayscale, so we may as well convert the\n             * input RGB values to a simple grayscale and use the grayscale\n             * code above.\n             *\n             * NOTE: calling this apparently damages the recognition of the\n             * transparent color in background color handling; call\n             * png_set_tRNS_to_alpha before png_set_background_fixed.\n             */\n            png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,\n                -1);\n            data_encoding = P_sRGB;\n\n            /* The output will now be one or two 8-bit gray or gray+alpha\n             * channels.  The more complex case arises when the input has alpha.\n             */\n            if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n               png_ptr->num_trans > 0) &&\n               (output_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n            {\n               /* Both input and output have an alpha channel, so no background\n                * processing is required; just map the GA bytes to the right\n                * color-map entry.\n                */\n               expand_tRNS = 1;\n\n               if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)\n                  png_error(png_ptr, \"rgb[ga] color-map: too few entries\");\n\n               cmap_entries = (unsigned int)make_ga_colormap(display);\n               background_index = PNG_CMAP_GA_BACKGROUND;\n               output_processing = PNG_CMAP_GA;\n            }\n\n            else\n            {\n               /* Either the input or the output has no alpha channel, so there\n                * will be no non-opaque pixels in the color-map; it will just be\n                * grayscale.\n                */\n               if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)\n                  png_error(png_ptr, \"rgb[gray] color-map: too few entries\");\n\n               /* Ideally this code would use libpng to do the gamma correction,\n                * but if an input alpha channel is to be removed we will hit the\n                * libpng bug in gamma+compose+rgb-to-gray (the double gamma\n                * correction bug).  Fix this by dropping the gamma correction in\n                * this case and doing it in the palette; this will result in\n                * duplicate palette entries, but that's better than the\n                * alternative of double gamma correction.\n                */\n               if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n                  png_ptr->num_trans > 0) &&\n                  png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)\n               {\n                  cmap_entries = (unsigned int)make_gray_file_colormap(display);\n                  data_encoding = P_FILE;\n               }\n\n               else\n                  cmap_entries = (unsigned int)make_gray_colormap(display);\n\n               /* But if the input has alpha or transparency it must be removed\n                */\n               if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n                  png_ptr->num_trans > 0)\n               {\n                  png_color_16 c;\n                  png_uint_32 gray = back_g;\n\n                  /* We need to ensure that the application background exists in\n                   * the colormap and that completely transparent pixels map to\n                   * it.  Achieve this simply by ensuring that the entry\n                   * selected for the background really is the background color.\n                   */\n                  if (data_encoding == P_FILE) /* from the fixup above */\n                  {\n                     /* The app supplied a gray which is in output_encoding, we\n                      * need to convert it to a value of the input (P_FILE)\n                      * encoding then set this palette entry to the required\n                      * output encoding.\n                      */\n                     if (output_encoding == P_sRGB)\n                        gray = png_sRGB_table[gray]; /* now P_LINEAR */\n\n                     gray = PNG_DIV257(png_gamma_16bit_correct(gray,\n                         png_ptr->colorspace.gamma)); /* now P_FILE */\n\n                     /* And make sure the corresponding palette entry contains\n                      * exactly the required sRGB value.\n                      */\n                     png_create_colormap_entry(display, gray, back_g, back_g,\n                         back_g, 0/*unused*/, output_encoding);\n                  }\n\n                  else if (output_encoding == P_LINEAR)\n                  {\n                     gray = PNG_sRGB_FROM_LINEAR(gray * 255);\n\n                     /* And make sure the corresponding palette entry matches.\n                      */\n                     png_create_colormap_entry(display, gray, back_g, back_g,\n                        back_g, 0/*unused*/, P_LINEAR);\n                  }\n\n                  /* The background passed to libpng, however, must be the\n                   * output (normally sRGB) value.\n                   */\n                  c.index = 0; /*unused*/\n                  c.gray = c.red = c.green = c.blue = (png_uint_16)gray;\n\n                  /* NOTE: the following is apparently a bug in libpng. Without\n                   * it the transparent color recognition in\n                   * png_set_background_fixed seems to go wrong.\n                   */\n                  expand_tRNS = 1;\n                  png_set_background_fixed(png_ptr, &c,\n                      PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,\n                      0/*gamma: not used*/);\n               }\n\n               output_processing = PNG_CMAP_NONE;\n            }\n         }\n\n         else /* output is color */\n         {\n            /* We could use png_quantize here so long as there is no transparent\n             * color or alpha; png_quantize ignores alpha.  Easier overall just\n             * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube.\n             * Consequently we always want libpng to produce sRGB data.\n             */\n            data_encoding = P_sRGB;\n\n            /* Is there any transparency or alpha? */\n            if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n               png_ptr->num_trans > 0)\n            {\n               /* Is there alpha in the output too?  If so all four channels are\n                * processed into a special RGB cube with alpha support.\n                */\n               if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n               {\n                  png_uint_32 r;\n\n                  if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)\n                     png_error(png_ptr, \"rgb+alpha color-map: too few entries\");\n\n                  cmap_entries = (unsigned int)make_rgb_colormap(display);\n\n                  /* Add a transparent entry. */\n                  png_create_colormap_entry(display, cmap_entries, 255, 255,\n                      255, 0, P_sRGB);\n\n                  /* This is stored as the background index for the processing\n                   * algorithm.\n                   */\n                  background_index = cmap_entries++;\n\n                  /* Add 27 r,g,b entries each with alpha 0.5. */\n                  for (r=0; r<256; r = (r << 1) | 0x7f)\n                  {\n                     png_uint_32 g;\n\n                     for (g=0; g<256; g = (g << 1) | 0x7f)\n                     {\n                        png_uint_32 b;\n\n                        /* This generates components with the values 0, 127 and\n                         * 255\n                         */\n                        for (b=0; b<256; b = (b << 1) | 0x7f)\n                           png_create_colormap_entry(display, cmap_entries++,\n                               r, g, b, 128, P_sRGB);\n                     }\n                  }\n\n                  expand_tRNS = 1;\n                  output_processing = PNG_CMAP_RGB_ALPHA;\n               }\n\n               else\n               {\n                  /* Alpha/transparency must be removed.  The background must\n                   * exist in the color map (achieved by setting adding it after\n                   * the 666 color-map).  If the standard processing code will\n                   * pick up this entry automatically that's all that is\n                   * required; libpng can be called to do the background\n                   * processing.\n                   */\n                  unsigned int sample_size =\n                     PNG_IMAGE_SAMPLE_SIZE(output_format);\n                  png_uint_32 r, g, b; /* sRGB background */\n\n                  if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)\n                     png_error(png_ptr, \"rgb-alpha color-map: too few entries\");\n\n                  cmap_entries = (unsigned int)make_rgb_colormap(display);\n\n                  png_create_colormap_entry(display, cmap_entries, back_r,\n                      back_g, back_b, 0/*unused*/, output_encoding);\n\n                  if (output_encoding == P_LINEAR)\n                  {\n                     r = PNG_sRGB_FROM_LINEAR(back_r * 255);\n                     g = PNG_sRGB_FROM_LINEAR(back_g * 255);\n                     b = PNG_sRGB_FROM_LINEAR(back_b * 255);\n                  }\n\n                  else\n                  {\n                     r = back_r;\n                     g = back_g;\n                     b = back_g;\n                  }\n\n                  /* Compare the newly-created color-map entry with the one the\n                   * PNG_CMAP_RGB algorithm will use.  If the two entries don't\n                   * match, add the new one and set this as the background\n                   * index.\n                   */\n                  if (memcmp((png_const_bytep)display->colormap +\n                      sample_size * cmap_entries,\n                      (png_const_bytep)display->colormap +\n                          sample_size * PNG_RGB_INDEX(r,g,b),\n                     sample_size) != 0)\n                  {\n                     /* The background color must be added. */\n                     background_index = cmap_entries++;\n\n                     /* Add 27 r,g,b entries each with created by composing with\n                      * the background at alpha 0.5.\n                      */\n                     for (r=0; r<256; r = (r << 1) | 0x7f)\n                     {\n                        for (g=0; g<256; g = (g << 1) | 0x7f)\n                        {\n                           /* This generates components with the values 0, 127\n                            * and 255\n                            */\n                           for (b=0; b<256; b = (b << 1) | 0x7f)\n                              png_create_colormap_entry(display, cmap_entries++,\n                                  png_colormap_compose(display, r, P_sRGB, 128,\n                                      back_r, output_encoding),\n                                  png_colormap_compose(display, g, P_sRGB, 128,\n                                      back_g, output_encoding),\n                                  png_colormap_compose(display, b, P_sRGB, 128,\n                                      back_b, output_encoding),\n                                  0/*unused*/, output_encoding);\n                        }\n                     }\n\n                     expand_tRNS = 1;\n                     output_processing = PNG_CMAP_RGB_ALPHA;\n                  }\n\n                  else /* background color is in the standard color-map */\n                  {\n                     png_color_16 c;\n\n                     c.index = 0; /*unused*/\n                     c.red = (png_uint_16)back_r;\n                     c.gray = c.green = (png_uint_16)back_g;\n                     c.blue = (png_uint_16)back_b;\n\n                     png_set_background_fixed(png_ptr, &c,\n                         PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,\n                         0/*gamma: not used*/);\n\n                     output_processing = PNG_CMAP_RGB;\n                  }\n               }\n            }\n\n            else /* no alpha or transparency in the input */\n            {\n               /* Alpha in the output is irrelevant, simply map the opaque input\n                * pixels to the 6x6x6 color-map.\n                */\n               if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries)\n                  png_error(png_ptr, \"rgb color-map: too few entries\");\n\n               cmap_entries = (unsigned int)make_rgb_colormap(display);\n               output_processing = PNG_CMAP_RGB;\n            }\n         }\n         break;\n\n      case PNG_COLOR_TYPE_PALETTE:\n         /* It's already got a color-map.  It may be necessary to eliminate the\n          * tRNS entries though.\n          */\n         {\n            unsigned int num_trans = png_ptr->num_trans;\n            png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL;\n            png_const_colorp colormap = png_ptr->palette;\n            int do_background = trans != NULL &&\n               (output_format & PNG_FORMAT_FLAG_ALPHA) == 0;\n            unsigned int i;\n\n            /* Just in case: */\n            if (trans == NULL)\n               num_trans = 0;\n\n            output_processing = PNG_CMAP_NONE;\n            data_encoding = P_FILE; /* Don't change from color-map indices */\n            cmap_entries = (unsigned int)png_ptr->num_palette;\n            if (cmap_entries > 256)\n               cmap_entries = 256;\n\n            if (cmap_entries > (unsigned int)image->colormap_entries)\n               png_error(png_ptr, \"palette color-map: too few entries\");\n\n            for (i=0; i < cmap_entries; ++i)\n            {\n               if (do_background != 0 && i < num_trans && trans[i] < 255)\n               {\n                  if (trans[i] == 0)\n                     png_create_colormap_entry(display, i, back_r, back_g,\n                         back_b, 0, output_encoding);\n\n                  else\n                  {\n                     /* Must compose the PNG file color in the color-map entry\n                      * on the sRGB color in 'back'.\n                      */\n                     png_create_colormap_entry(display, i,\n                         png_colormap_compose(display, colormap[i].red,\n                             P_FILE, trans[i], back_r, output_encoding),\n                         png_colormap_compose(display, colormap[i].green,\n                             P_FILE, trans[i], back_g, output_encoding),\n                         png_colormap_compose(display, colormap[i].blue,\n                             P_FILE, trans[i], back_b, output_encoding),\n                         output_encoding == P_LINEAR ? trans[i] * 257U :\n                             trans[i],\n                         output_encoding);\n                  }\n               }\n\n               else\n                  png_create_colormap_entry(display, i, colormap[i].red,\n                      colormap[i].green, colormap[i].blue,\n                      i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/);\n            }\n\n            /* The PNG data may have indices packed in fewer than 8 bits, it\n             * must be expanded if so.\n             */\n            if (png_ptr->bit_depth < 8)\n               png_set_packing(png_ptr);\n         }\n         break;\n\n      default:\n         png_error(png_ptr, \"invalid PNG color type\");\n         /*NOT REACHED*/\n   }\n\n   /* Now deal with the output processing */\n   if (expand_tRNS != 0 && png_ptr->num_trans > 0 &&\n       (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0)\n      png_set_tRNS_to_alpha(png_ptr);\n\n   switch (data_encoding)\n   {\n      case P_sRGB:\n         /* Change to 8-bit sRGB */\n         png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB);\n         /* FALLTHROUGH */\n\n      case P_FILE:\n         if (png_ptr->bit_depth > 8)\n            png_set_scale_16(png_ptr);\n         break;\n\n#ifdef __GNUC__\n      default:\n         png_error(png_ptr, \"bad data option (internal error)\");\n#endif\n   }\n\n   if (cmap_entries > 256 || cmap_entries > image->colormap_entries)\n      png_error(png_ptr, \"color map overflow (BAD internal error)\");\n\n   image->colormap_entries = cmap_entries;\n\n   /* Double check using the recorded background index */\n   switch (output_processing)\n   {\n      case PNG_CMAP_NONE:\n         if (background_index != PNG_CMAP_NONE_BACKGROUND)\n            goto bad_background;\n         break;\n\n      case PNG_CMAP_GA:\n         if (background_index != PNG_CMAP_GA_BACKGROUND)\n            goto bad_background;\n         break;\n\n      case PNG_CMAP_TRANS:\n         if (background_index >= cmap_entries ||\n            background_index != PNG_CMAP_TRANS_BACKGROUND)\n            goto bad_background;\n         break;\n\n      case PNG_CMAP_RGB:\n         if (background_index != PNG_CMAP_RGB_BACKGROUND)\n            goto bad_background;\n         break;\n\n      case PNG_CMAP_RGB_ALPHA:\n         if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND)\n            goto bad_background;\n         break;\n\n      default:\n         png_error(png_ptr, \"bad processing option (internal error)\");\n\n      bad_background:\n         png_error(png_ptr, \"bad background index (internal error)\");\n   }\n\n   display->colormap_processing = (int)output_processing;\n\n   return 1/*ok*/;\n}\n\n/* The final part of the color-map read called from png_image_finish_read. */\nstatic int\npng_image_read_and_map(png_voidp argument)\n{\n   png_image_read_control *display = png_voidcast(png_image_read_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n   int passes;\n\n   /* Called when the libpng data must be transformed into the color-mapped\n    * form.  There is a local row buffer in display->local and this routine must\n    * do the interlace handling.\n    */\n   switch (png_ptr->interlaced)\n   {\n      case PNG_INTERLACE_NONE:\n         passes = 1;\n         break;\n\n      case PNG_INTERLACE_ADAM7:\n         passes = PNG_INTERLACE_ADAM7_PASSES;\n         break;\n\n      default:\n         png_error(png_ptr, \"unknown interlace type\");\n   }\n\n   {\n      png_uint_32  height = image->height;\n      png_uint_32  width = image->width;\n      int          proc = display->colormap_processing;\n      png_bytep    first_row = png_voidcast(png_bytep, display->first_row);\n      ptrdiff_t    step_row = display->row_bytes;\n      int pass;\n\n      for (pass = 0; pass < passes; ++pass)\n      {\n         unsigned int     startx, stepx, stepy;\n         png_uint_32      y;\n\n         if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)\n         {\n            /* The row may be empty for a short image: */\n            if (PNG_PASS_COLS(width, pass) == 0)\n               continue;\n\n            startx = PNG_PASS_START_COL(pass);\n            stepx = PNG_PASS_COL_OFFSET(pass);\n            y = PNG_PASS_START_ROW(pass);\n            stepy = PNG_PASS_ROW_OFFSET(pass);\n         }\n\n         else\n         {\n            y = 0;\n            startx = 0;\n            stepx = stepy = 1;\n         }\n\n         for (; y<height; y += stepy)\n         {\n            png_bytep inrow = png_voidcast(png_bytep, display->local_row);\n            png_bytep outrow = first_row + y * step_row;\n            png_const_bytep end_row = outrow + width;\n\n            /* Read read the libpng data into the temporary buffer. */\n            png_read_row(png_ptr, inrow, NULL);\n\n            /* Now process the row according to the processing option, note\n             * that the caller verifies that the format of the libpng output\n             * data is as required.\n             */\n            outrow += startx;\n            switch (proc)\n            {\n               case PNG_CMAP_GA:\n                  for (; outrow < end_row; outrow += stepx)\n                  {\n                     /* The data is always in the PNG order */\n                     unsigned int gray = *inrow++;\n                     unsigned int alpha = *inrow++;\n                     unsigned int entry;\n\n                     /* NOTE: this code is copied as a comment in\n                      * make_ga_colormap above.  Please update the\n                      * comment if you change this code!\n                      */\n                     if (alpha > 229) /* opaque */\n                     {\n                        entry = (231 * gray + 128) >> 8;\n                     }\n                     else if (alpha < 26) /* transparent */\n                     {\n                        entry = 231;\n                     }\n                     else /* partially opaque */\n                     {\n                        entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray);\n                     }\n\n                     *outrow = (png_byte)entry;\n                  }\n                  break;\n\n               case PNG_CMAP_TRANS:\n                  for (; outrow < end_row; outrow += stepx)\n                  {\n                     png_byte gray = *inrow++;\n                     png_byte alpha = *inrow++;\n\n                     if (alpha == 0)\n                        *outrow = PNG_CMAP_TRANS_BACKGROUND;\n\n                     else if (gray != PNG_CMAP_TRANS_BACKGROUND)\n                        *outrow = gray;\n\n                     else\n                        *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1);\n                  }\n                  break;\n\n               case PNG_CMAP_RGB:\n                  for (; outrow < end_row; outrow += stepx)\n                  {\n                     *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);\n                     inrow += 3;\n                  }\n                  break;\n\n               case PNG_CMAP_RGB_ALPHA:\n                  for (; outrow < end_row; outrow += stepx)\n                  {\n                     unsigned int alpha = inrow[3];\n\n                     /* Because the alpha entries only hold alpha==0.5 values\n                      * split the processing at alpha==0.25 (64) and 0.75\n                      * (196).\n                      */\n\n                     if (alpha >= 196)\n                        *outrow = PNG_RGB_INDEX(inrow[0], inrow[1],\n                            inrow[2]);\n\n                     else if (alpha < 64)\n                        *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND;\n\n                     else\n                     {\n                        /* Likewise there are three entries for each of r, g\n                         * and b.  We could select the entry by popcount on\n                         * the top two bits on those architectures that\n                         * support it, this is what the code below does,\n                         * crudely.\n                         */\n                        unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1;\n\n                        /* Here are how the values map:\n                         *\n                         * 0x00 .. 0x3f -> 0\n                         * 0x40 .. 0xbf -> 1\n                         * 0xc0 .. 0xff -> 2\n                         *\n                         * So, as above with the explicit alpha checks, the\n                         * breakpoints are at 64 and 196.\n                         */\n                        if (inrow[0] & 0x80) back_i += 9; /* red */\n                        if (inrow[0] & 0x40) back_i += 9;\n                        if (inrow[0] & 0x80) back_i += 3; /* green */\n                        if (inrow[0] & 0x40) back_i += 3;\n                        if (inrow[0] & 0x80) back_i += 1; /* blue */\n                        if (inrow[0] & 0x40) back_i += 1;\n\n                        *outrow = (png_byte)back_i;\n                     }\n\n                     inrow += 4;\n                  }\n                  break;\n\n               default:\n                  break;\n            }\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic int\npng_image_read_colormapped(png_voidp argument)\n{\n   png_image_read_control *display = png_voidcast(png_image_read_control*,\n       argument);\n   png_imagep image = display->image;\n   png_controlp control = image->opaque;\n   png_structrp png_ptr = control->png_ptr;\n   png_inforp info_ptr = control->info_ptr;\n\n   int passes = 0; /* As a flag */\n\n   PNG_SKIP_CHUNKS(png_ptr);\n\n   /* Update the 'info' structure and make sure the result is as required; first\n    * make sure to turn on the interlace handling if it will be required\n    * (because it can't be turned on *after* the call to png_read_update_info!)\n    */\n   if (display->colormap_processing == PNG_CMAP_NONE)\n      passes = png_set_interlace_handling(png_ptr);\n\n   png_read_update_info(png_ptr, info_ptr);\n\n   /* The expected output can be deduced from the colormap_processing option. */\n   switch (display->colormap_processing)\n   {\n      case PNG_CMAP_NONE:\n         /* Output must be one channel and one byte per pixel, the output\n          * encoding can be anything.\n          */\n         if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||\n            info_ptr->color_type == PNG_COLOR_TYPE_GRAY) &&\n            info_ptr->bit_depth == 8)\n            break;\n\n         goto bad_output;\n\n      case PNG_CMAP_TRANS:\n      case PNG_CMAP_GA:\n         /* Output must be two channels and the 'G' one must be sRGB, the latter\n          * can be checked with an exact number because it should have been set\n          * to this number above!\n          */\n         if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&\n            info_ptr->bit_depth == 8 &&\n            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&\n            image->colormap_entries == 256)\n            break;\n\n         goto bad_output;\n\n      case PNG_CMAP_RGB:\n         /* Output must be 8-bit sRGB encoded RGB */\n         if (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&\n            info_ptr->bit_depth == 8 &&\n            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&\n            image->colormap_entries == 216)\n            break;\n\n         goto bad_output;\n\n      case PNG_CMAP_RGB_ALPHA:\n         /* Output must be 8-bit sRGB encoded RGBA */\n         if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&\n            info_ptr->bit_depth == 8 &&\n            png_ptr->screen_gamma == PNG_GAMMA_sRGB &&\n            image->colormap_entries == 244 /* 216 + 1 + 27 */)\n            break;\n\n         goto bad_output;\n\n      default:\n      bad_output:\n         png_error(png_ptr, \"bad color-map processing (internal error)\");\n   }\n\n   /* Now read the rows.  Do this here if it is possible to read directly into\n    * the output buffer, otherwise allocate a local row buffer of the maximum\n    * size libpng requires and call the relevant processing routine safely.\n    */\n   {\n      png_voidp first_row = display->buffer;\n      ptrdiff_t row_bytes = display->row_stride;\n\n      /* The following expression is designed to work correctly whether it gives\n       * a signed or an unsigned result.\n       */\n      if (row_bytes < 0)\n      {\n         char *ptr = png_voidcast(char*, first_row);\n         ptr += (image->height-1) * (-row_bytes);\n         first_row = png_voidcast(png_voidp, ptr);\n      }\n\n      display->first_row = first_row;\n      display->row_bytes = row_bytes;\n   }\n\n   if (passes == 0)\n   {\n      int result;\n      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));\n\n      display->local_row = row;\n      result = png_safe_execute(image, png_image_read_and_map, display);\n      display->local_row = NULL;\n      png_free(png_ptr, row);\n\n      return result;\n   }\n\n   else\n   {\n      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;\n\n      while (--passes >= 0)\n      {\n         png_uint_32      y = image->height;\n         png_bytep        row = png_voidcast(png_bytep, display->first_row);\n\n         for (; y > 0; --y)\n         {\n            png_read_row(png_ptr, row, NULL);\n            row += row_bytes;\n         }\n      }\n\n      return 1;\n   }\n}\n\n/* Just the row reading part of png_image_read. */\nstatic int\npng_image_read_composite(png_voidp argument)\n{\n   png_image_read_control *display = png_voidcast(png_image_read_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n   int passes;\n\n   switch (png_ptr->interlaced)\n   {\n      case PNG_INTERLACE_NONE:\n         passes = 1;\n         break;\n\n      case PNG_INTERLACE_ADAM7:\n         passes = PNG_INTERLACE_ADAM7_PASSES;\n         break;\n\n      default:\n         png_error(png_ptr, \"unknown interlace type\");\n   }\n\n   {\n      png_uint_32  height = image->height;\n      png_uint_32  width = image->width;\n      ptrdiff_t    step_row = display->row_bytes;\n      unsigned int channels =\n          (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;\n      int pass;\n\n      for (pass = 0; pass < passes; ++pass)\n      {\n         unsigned int     startx, stepx, stepy;\n         png_uint_32      y;\n\n         if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)\n         {\n            /* The row may be empty for a short image: */\n            if (PNG_PASS_COLS(width, pass) == 0)\n               continue;\n\n            startx = PNG_PASS_START_COL(pass) * channels;\n            stepx = PNG_PASS_COL_OFFSET(pass) * channels;\n            y = PNG_PASS_START_ROW(pass);\n            stepy = PNG_PASS_ROW_OFFSET(pass);\n         }\n\n         else\n         {\n            y = 0;\n            startx = 0;\n            stepx = channels;\n            stepy = 1;\n         }\n\n         for (; y<height; y += stepy)\n         {\n            png_bytep inrow = png_voidcast(png_bytep, display->local_row);\n            png_bytep outrow;\n            png_const_bytep end_row;\n\n            /* Read the row, which is packed: */\n            png_read_row(png_ptr, inrow, NULL);\n\n            outrow = png_voidcast(png_bytep, display->first_row);\n            outrow += y * step_row;\n            end_row = outrow + width * channels;\n\n            /* Now do the composition on each pixel in this row. */\n            outrow += startx;\n            for (; outrow < end_row; outrow += stepx)\n            {\n               png_byte alpha = inrow[channels];\n\n               if (alpha > 0) /* else no change to the output */\n               {\n                  unsigned int c;\n\n                  for (c=0; c<channels; ++c)\n                  {\n                     png_uint_32 component = inrow[c];\n\n                     if (alpha < 255) /* else just use component */\n                     {\n                        /* This is PNG_OPTIMIZED_ALPHA, the component value\n                         * is a linear 8-bit value.  Combine this with the\n                         * current outrow[c] value which is sRGB encoded.\n                         * Arithmetic here is 16-bits to preserve the output\n                         * values correctly.\n                         */\n                        component *= 257*255; /* =65535 */\n                        component += (255-alpha)*png_sRGB_table[outrow[c]];\n\n                        /* So 'component' is scaled by 255*65535 and is\n                         * therefore appropriate for the sRGB to linear\n                         * conversion table.\n                         */\n                        component = PNG_sRGB_FROM_LINEAR(component);\n                     }\n\n                     outrow[c] = (png_byte)component;\n                  }\n               }\n\n               inrow += channels+1; /* components and alpha channel */\n            }\n         }\n      }\n   }\n\n   return 1;\n}\n\n/* The do_local_background case; called when all the following transforms are to\n * be done:\n *\n * PNG_RGB_TO_GRAY\n * PNG_COMPOSITE\n * PNG_GAMMA\n *\n * This is a work-around for the fact that both the PNG_RGB_TO_GRAY and\n * PNG_COMPOSITE code performs gamma correction, so we get double gamma\n * correction.  The fix-up is to prevent the PNG_COMPOSITE operation from\n * happening inside libpng, so this routine sees an 8 or 16-bit gray+alpha\n * row and handles the removal or pre-multiplication of the alpha channel.\n */\nstatic int\npng_image_read_background(png_voidp argument)\n{\n   png_image_read_control *display = png_voidcast(png_image_read_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n   png_inforp info_ptr = image->opaque->info_ptr;\n   png_uint_32 height = image->height;\n   png_uint_32 width = image->width;\n   int pass, passes;\n\n   /* Double check the convoluted logic below.  We expect to get here with\n    * libpng doing rgb to gray and gamma correction but background processing\n    * left to the png_image_read_background function.  The rows libpng produce\n    * might be 8 or 16-bit but should always have two channels; gray plus alpha.\n    */\n   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)\n      png_error(png_ptr, \"lost rgb to gray\");\n\n   if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n      png_error(png_ptr, \"unexpected compose\");\n\n   if (png_get_channels(png_ptr, info_ptr) != 2)\n      png_error(png_ptr, \"lost/gained channels\");\n\n   /* Expect the 8-bit case to always remove the alpha channel */\n   if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 &&\n      (image->format & PNG_FORMAT_FLAG_ALPHA) != 0)\n      png_error(png_ptr, \"unexpected 8-bit transformation\");\n\n   switch (png_ptr->interlaced)\n   {\n      case PNG_INTERLACE_NONE:\n         passes = 1;\n         break;\n\n      case PNG_INTERLACE_ADAM7:\n         passes = PNG_INTERLACE_ADAM7_PASSES;\n         break;\n\n      default:\n         png_error(png_ptr, \"unknown interlace type\");\n   }\n\n   /* Use direct access to info_ptr here because otherwise the simplified API\n    * would require PNG_EASY_ACCESS_SUPPORTED (just for this.)  Note this is\n    * checking the value after libpng expansions, not the original value in the\n    * PNG.\n    */\n   switch (info_ptr->bit_depth)\n   {\n      case 8:\n         /* 8-bit sRGB gray values with an alpha channel; the alpha channel is\n          * to be removed by composing on a background: either the row if\n          * display->background is NULL or display->background->green if not.\n          * Unlike the code above ALPHA_OPTIMIZED has *not* been done.\n          */\n         {\n            png_bytep first_row = png_voidcast(png_bytep, display->first_row);\n            ptrdiff_t step_row = display->row_bytes;\n\n            for (pass = 0; pass < passes; ++pass)\n            {\n               png_bytep row = png_voidcast(png_bytep, display->first_row);\n               unsigned int     startx, stepx, stepy;\n               png_uint_32      y;\n\n               if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)\n               {\n                  /* The row may be empty for a short image: */\n                  if (PNG_PASS_COLS(width, pass) == 0)\n                     continue;\n\n                  startx = PNG_PASS_START_COL(pass);\n                  stepx = PNG_PASS_COL_OFFSET(pass);\n                  y = PNG_PASS_START_ROW(pass);\n                  stepy = PNG_PASS_ROW_OFFSET(pass);\n               }\n\n               else\n               {\n                  y = 0;\n                  startx = 0;\n                  stepx = stepy = 1;\n               }\n\n               if (display->background == NULL)\n               {\n                  for (; y<height; y += stepy)\n                  {\n                     png_bytep inrow = png_voidcast(png_bytep,\n                         display->local_row);\n                     png_bytep outrow = first_row + y * step_row;\n                     png_const_bytep end_row = outrow + width;\n\n                     /* Read the row, which is packed: */\n                     png_read_row(png_ptr, inrow, NULL);\n\n                     /* Now do the composition on each pixel in this row. */\n                     outrow += startx;\n                     for (; outrow < end_row; outrow += stepx)\n                     {\n                        png_byte alpha = inrow[1];\n\n                        if (alpha > 0) /* else no change to the output */\n                        {\n                           png_uint_32 component = inrow[0];\n\n                           if (alpha < 255) /* else just use component */\n                           {\n                              /* Since PNG_OPTIMIZED_ALPHA was not set it is\n                               * necessary to invert the sRGB transfer\n                               * function and multiply the alpha out.\n                               */\n                              component = png_sRGB_table[component] * alpha;\n                              component += png_sRGB_table[outrow[0]] *\n                                 (255-alpha);\n                              component = PNG_sRGB_FROM_LINEAR(component);\n                           }\n\n                           outrow[0] = (png_byte)component;\n                        }\n\n                        inrow += 2; /* gray and alpha channel */\n                     }\n                  }\n               }\n\n               else /* constant background value */\n               {\n                  png_byte background8 = display->background->green;\n                  png_uint_16 background = png_sRGB_table[background8];\n\n                  for (; y<height; y += stepy)\n                  {\n                     png_bytep inrow = png_voidcast(png_bytep,\n                         display->local_row);\n                     png_bytep outrow = first_row + y * step_row;\n                     png_const_bytep end_row = outrow + width;\n\n                     /* Read the row, which is packed: */\n                     png_read_row(png_ptr, inrow, NULL);\n\n                     /* Now do the composition on each pixel in this row. */\n                     outrow += startx;\n                     for (; outrow < end_row; outrow += stepx)\n                     {\n                        png_byte alpha = inrow[1];\n\n                        if (alpha > 0) /* else use background */\n                        {\n                           png_uint_32 component = inrow[0];\n\n                           if (alpha < 255) /* else just use component */\n                           {\n                              component = png_sRGB_table[component] * alpha;\n                              component += background * (255-alpha);\n                              component = PNG_sRGB_FROM_LINEAR(component);\n                           }\n\n                           outrow[0] = (png_byte)component;\n                        }\n\n                        else\n                           outrow[0] = background8;\n\n                        inrow += 2; /* gray and alpha channel */\n                     }\n\n                     row += display->row_bytes;\n                  }\n               }\n            }\n         }\n         break;\n\n      case 16:\n         /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must\n          * still be done and, maybe, the alpha channel removed.  This code also\n          * handles the alpha-first option.\n          */\n         {\n            png_uint_16p first_row = png_voidcast(png_uint_16p,\n                display->first_row);\n            /* The division by two is safe because the caller passed in a\n             * stride which was multiplied by 2 (below) to get row_bytes.\n             */\n            ptrdiff_t    step_row = display->row_bytes / 2;\n            unsigned int preserve_alpha = (image->format &\n                PNG_FORMAT_FLAG_ALPHA) != 0;\n            unsigned int outchannels = 1U+preserve_alpha;\n            int swap_alpha = 0;\n\n#           ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED\n               if (preserve_alpha != 0 &&\n                   (image->format & PNG_FORMAT_FLAG_AFIRST) != 0)\n                  swap_alpha = 1;\n#           endif\n\n            for (pass = 0; pass < passes; ++pass)\n            {\n               unsigned int     startx, stepx, stepy;\n               png_uint_32      y;\n\n               /* The 'x' start and step are adjusted to output components here.\n                */\n               if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)\n               {\n                  /* The row may be empty for a short image: */\n                  if (PNG_PASS_COLS(width, pass) == 0)\n                     continue;\n\n                  startx = PNG_PASS_START_COL(pass) * outchannels;\n                  stepx = PNG_PASS_COL_OFFSET(pass) * outchannels;\n                  y = PNG_PASS_START_ROW(pass);\n                  stepy = PNG_PASS_ROW_OFFSET(pass);\n               }\n\n               else\n               {\n                  y = 0;\n                  startx = 0;\n                  stepx = outchannels;\n                  stepy = 1;\n               }\n\n               for (; y<height; y += stepy)\n               {\n                  png_const_uint_16p inrow;\n                  png_uint_16p outrow = first_row + y*step_row;\n                  png_uint_16p end_row = outrow + width * outchannels;\n\n                  /* Read the row, which is packed: */\n                  png_read_row(png_ptr, png_voidcast(png_bytep,\n                      display->local_row), NULL);\n                  inrow = png_voidcast(png_const_uint_16p, display->local_row);\n\n                  /* Now do the pre-multiplication on each pixel in this row.\n                   */\n                  outrow += startx;\n                  for (; outrow < end_row; outrow += stepx)\n                  {\n                     png_uint_32 component = inrow[0];\n                     png_uint_16 alpha = inrow[1];\n\n                     if (alpha > 0) /* else 0 */\n                     {\n                        if (alpha < 65535) /* else just use component */\n                        {\n                           component *= alpha;\n                           component += 32767;\n                           component /= 65535;\n                        }\n                     }\n\n                     else\n                        component = 0;\n\n                     outrow[swap_alpha] = (png_uint_16)component;\n                     if (preserve_alpha != 0)\n                        outrow[1 ^ swap_alpha] = alpha;\n\n                     inrow += 2; /* components and alpha channel */\n                  }\n               }\n            }\n         }\n         break;\n\n#ifdef __GNUC__\n      default:\n         png_error(png_ptr, \"unexpected bit depth\");\n#endif\n   }\n\n   return 1;\n}\n\n/* The guts of png_image_finish_read as a png_safe_execute callback. */\nstatic int\npng_image_read_direct(png_voidp argument)\n{\n   png_image_read_control *display = png_voidcast(png_image_read_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n   png_inforp info_ptr = image->opaque->info_ptr;\n\n   png_uint_32 format = image->format;\n   int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;\n   int do_local_compose = 0;\n   int do_local_background = 0; /* to avoid double gamma correction bug */\n   int passes = 0;\n\n   /* Add transforms to ensure the correct output format is produced then check\n    * that the required implementation support is there.  Always expand; always\n    * need 8 bits minimum, no palette and expanded tRNS.\n    */\n   png_set_expand(png_ptr);\n\n   /* Now check the format to see if it was modified. */\n   {\n      png_uint_32 base_format = png_image_format(png_ptr) &\n         ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */;\n      png_uint_32 change = format ^ base_format;\n      png_fixed_point output_gamma;\n      int mode; /* alpha mode */\n\n      /* Do this first so that we have a record if rgb to gray is happening. */\n      if ((change & PNG_FORMAT_FLAG_COLOR) != 0)\n      {\n         /* gray<->color transformation required. */\n         if ((format & PNG_FORMAT_FLAG_COLOR) != 0)\n            png_set_gray_to_rgb(png_ptr);\n\n         else\n         {\n            /* libpng can't do both rgb to gray and\n             * background/pre-multiplication if there is also significant gamma\n             * correction, because both operations require linear colors and\n             * the code only supports one transform doing the gamma correction.\n             * Handle this by doing the pre-multiplication or background\n             * operation in this code, if necessary.\n             *\n             * TODO: fix this by rewriting pngrtran.c (!)\n             *\n             * For the moment (given that fixing this in pngrtran.c is an\n             * enormous change) 'do_local_background' is used to indicate that\n             * the problem exists.\n             */\n            if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n               do_local_background = 1/*maybe*/;\n\n            png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE,\n                PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);\n         }\n\n         change &= ~PNG_FORMAT_FLAG_COLOR;\n      }\n\n      /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.\n       */\n      {\n         png_fixed_point input_gamma_default;\n\n         if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 &&\n             (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)\n            input_gamma_default = PNG_GAMMA_LINEAR;\n         else\n            input_gamma_default = PNG_DEFAULT_sRGB;\n\n         /* Call png_set_alpha_mode to set the default for the input gamma; the\n          * output gamma is set by a second call below.\n          */\n         png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default);\n      }\n\n      if (linear != 0)\n      {\n         /* If there *is* an alpha channel in the input it must be multiplied\n          * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG.\n          */\n         if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n            mode = PNG_ALPHA_STANDARD; /* associated alpha */\n\n         else\n            mode = PNG_ALPHA_PNG;\n\n         output_gamma = PNG_GAMMA_LINEAR;\n      }\n\n      else\n      {\n         mode = PNG_ALPHA_PNG;\n         output_gamma = PNG_DEFAULT_sRGB;\n      }\n      \n      if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)\n      {\n         mode = PNG_ALPHA_OPTIMIZED;\n         change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;\n      }\n      \n      /* If 'do_local_background' is set check for the presence of gamma\n       * correction; this is part of the work-round for the libpng bug\n       * described above.\n       *\n       * TODO: fix libpng and remove this.\n       */\n      if (do_local_background != 0)\n      {\n         png_fixed_point gtest;\n\n         /* This is 'png_gamma_threshold' from pngrtran.c; the test used for\n          * gamma correction, the screen gamma hasn't been set on png_struct\n          * yet; it's set below.  png_struct::gamma, however, is set to the\n          * final value.\n          */\n         if (png_muldiv(&gtest, output_gamma, png_ptr->colorspace.gamma,\n             PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)\n            do_local_background = 0;\n\n         else if (mode == PNG_ALPHA_STANDARD)\n         {\n            do_local_background = 2/*required*/;\n            mode = PNG_ALPHA_PNG; /* prevent libpng doing it */\n         }\n\n         /* else leave as 1 for the checks below */\n      }\n\n      /* If the bit-depth changes then handle that here. */\n      if ((change & PNG_FORMAT_FLAG_LINEAR) != 0)\n      {\n         if (linear != 0 /*16-bit output*/)\n            png_set_expand_16(png_ptr);\n\n         else /* 8-bit output */\n            png_set_scale_16(png_ptr);\n\n         change &= ~PNG_FORMAT_FLAG_LINEAR;\n      }\n\n      /* Now the background/alpha channel changes. */\n      if ((change & PNG_FORMAT_FLAG_ALPHA) != 0)\n      {\n         /* Removing an alpha channel requires composition for the 8-bit\n          * formats; for the 16-bit it is already done, above, by the\n          * pre-multiplication and the channel just needs to be stripped.\n          */\n         if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)\n         {\n            /* If RGB->gray is happening the alpha channel must be left and the\n             * operation completed locally.\n             *\n             * TODO: fix libpng and remove this.\n             */\n            if (do_local_background != 0)\n               do_local_background = 2/*required*/;\n\n            /* 16-bit output: just remove the channel */\n            else if (linear != 0) /* compose on black (well, pre-multiply) */\n               png_set_strip_alpha(png_ptr);\n\n            /* 8-bit output: do an appropriate compose */\n            else if (display->background != NULL)\n            {\n               png_color_16 c;\n\n               c.index = 0; /*unused*/\n               c.red = display->background->red;\n               c.green = display->background->green;\n               c.blue = display->background->blue;\n               c.gray = display->background->green;\n\n               /* This is always an 8-bit sRGB value, using the 'green' channel\n                * for gray is much better than calculating the luminance here;\n                * we can get off-by-one errors in that calculation relative to\n                * the app expectations and that will show up in transparent\n                * pixels.\n                */\n               png_set_background_fixed(png_ptr, &c,\n                   PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,\n                   0/*gamma: not used*/);\n            }\n\n            else /* compose on row: implemented below. */\n            {\n               do_local_compose = 1;\n               /* This leaves the alpha channel in the output, so it has to be\n                * removed by the code below.  Set the encoding to the 'OPTIMIZE'\n                * one so the code only has to hack on the pixels that require\n                * composition.\n                */\n               mode = PNG_ALPHA_OPTIMIZED;\n            }\n         }\n\n         else /* output needs an alpha channel */\n         {\n            /* This is tricky because it happens before the swap operation has\n             * been accomplished; however, the swap does *not* swap the added\n             * alpha channel (weird API), so it must be added in the correct\n             * place.\n             */\n            png_uint_32 filler; /* opaque filler */\n            int where;\n\n            if (linear != 0)\n               filler = 65535;\n\n            else\n               filler = 255;\n\n#ifdef PNG_FORMAT_AFIRST_SUPPORTED\n            if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)\n            {\n               where = PNG_FILLER_BEFORE;\n               change &= ~PNG_FORMAT_FLAG_AFIRST;\n            }\n\n            else\n#endif\n            where = PNG_FILLER_AFTER;\n\n            png_set_add_alpha(png_ptr, filler, where);\n         }\n\n         /* This stops the (irrelevant) call to swap_alpha below. */\n         change &= ~PNG_FORMAT_FLAG_ALPHA;\n      }\n\n      /* Now set the alpha mode correctly; this is always done, even if there is\n       * no alpha channel in either the input or the output because it correctly\n       * sets the output gamma.\n       */\n      png_set_alpha_mode_fixed(png_ptr, mode, output_gamma);\n\n#     ifdef PNG_FORMAT_BGR_SUPPORTED\n         if ((change & PNG_FORMAT_FLAG_BGR) != 0)\n         {\n            /* Check only the output format; PNG is never BGR; don't do this if\n             * the output is gray, but fix up the 'format' value in that case.\n             */\n            if ((format & PNG_FORMAT_FLAG_COLOR) != 0)\n               png_set_bgr(png_ptr);\n\n            else\n               format &= ~PNG_FORMAT_FLAG_BGR;\n\n            change &= ~PNG_FORMAT_FLAG_BGR;\n         }\n#     endif\n\n#     ifdef PNG_FORMAT_AFIRST_SUPPORTED\n         if ((change & PNG_FORMAT_FLAG_AFIRST) != 0)\n         {\n            /* Only relevant if there is an alpha channel - it's particularly\n             * important to handle this correctly because do_local_compose may\n             * be set above and then libpng will keep the alpha channel for this\n             * code to remove.\n             */\n            if ((format & PNG_FORMAT_FLAG_ALPHA) != 0)\n            {\n               /* Disable this if doing a local background,\n                * TODO: remove this when local background is no longer required.\n                */\n               if (do_local_background != 2)\n                  png_set_swap_alpha(png_ptr);\n            }\n\n            else\n               format &= ~PNG_FORMAT_FLAG_AFIRST;\n\n            change &= ~PNG_FORMAT_FLAG_AFIRST;\n         }\n#     endif\n\n      /* If the *output* is 16-bit then we need to check for a byte-swap on this\n       * architecture.\n       */\n      if (linear != 0)\n      {\n         png_uint_16 le = 0x0001;\n\n         if ((*(png_const_bytep) & le) != 0)\n            png_set_swap(png_ptr);\n      }\n\n      /* If change is not now 0 some transformation is missing - error out. */\n      if (change != 0)\n         png_error(png_ptr, \"png_read_image: unsupported transformation\");\n   }\n\n   PNG_SKIP_CHUNKS(png_ptr);\n\n   /* Update the 'info' structure and make sure the result is as required; first\n    * make sure to turn on the interlace handling if it will be required\n    * (because it can't be turned on *after* the call to png_read_update_info!)\n    *\n    * TODO: remove the do_local_background fixup below.\n    */\n   if (do_local_compose == 0 && do_local_background != 2)\n      passes = png_set_interlace_handling(png_ptr);\n\n   png_read_update_info(png_ptr, info_ptr);\n\n   {\n      png_uint_32 info_format = 0;\n\n      if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n         info_format |= PNG_FORMAT_FLAG_COLOR;\n\n      if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      {\n         /* do_local_compose removes this channel below. */\n         if (do_local_compose == 0)\n         {\n            /* do_local_background does the same if required. */\n            if (do_local_background != 2 ||\n               (format & PNG_FORMAT_FLAG_ALPHA) != 0)\n               info_format |= PNG_FORMAT_FLAG_ALPHA;\n         }\n      }\n\n      else if (do_local_compose != 0) /* internal error */\n         png_error(png_ptr, \"png_image_read: alpha channel lost\");\n\n      if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) {\n         info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;\n      }\n\n      if (info_ptr->bit_depth == 16)\n         info_format |= PNG_FORMAT_FLAG_LINEAR;\n\n#ifdef PNG_FORMAT_BGR_SUPPORTED\n      if ((png_ptr->transformations & PNG_BGR) != 0)\n         info_format |= PNG_FORMAT_FLAG_BGR;\n#endif\n\n#ifdef PNG_FORMAT_AFIRST_SUPPORTED\n         if (do_local_background == 2)\n         {\n            if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)\n               info_format |= PNG_FORMAT_FLAG_AFIRST;\n         }\n\n         if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 ||\n            ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 &&\n            (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0))\n         {\n            if (do_local_background == 2)\n               png_error(png_ptr, \"unexpected alpha swap transformation\");\n\n            info_format |= PNG_FORMAT_FLAG_AFIRST;\n         }\n#     endif\n\n      /* This is actually an internal error. */\n      if (info_format != format)\n         png_error(png_ptr, \"png_read_image: invalid transformations\");\n   }\n\n   /* Now read the rows.  If do_local_compose is set then it is necessary to use\n    * a local row buffer.  The output will be GA, RGBA or BGRA and must be\n    * converted to G, RGB or BGR as appropriate.  The 'local_row' member of the\n    * display acts as a flag.\n    */\n   {\n      png_voidp first_row = display->buffer;\n      ptrdiff_t row_bytes = display->row_stride;\n\n      if (linear != 0)\n         row_bytes *= 2;\n\n      /* The following expression is designed to work correctly whether it gives\n       * a signed or an unsigned result.\n       */\n      if (row_bytes < 0)\n      {\n         char *ptr = png_voidcast(char*, first_row);\n         ptr += (image->height-1) * (-row_bytes);\n         first_row = png_voidcast(png_voidp, ptr);\n      }\n\n      display->first_row = first_row;\n      display->row_bytes = row_bytes;\n   }\n\n   if (do_local_compose != 0)\n   {\n      int result;\n      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));\n\n      display->local_row = row;\n      result = png_safe_execute(image, png_image_read_composite, display);\n      display->local_row = NULL;\n      png_free(png_ptr, row);\n\n      return result;\n   }\n\n   else if (do_local_background == 2)\n   {\n      int result;\n      png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));\n\n      display->local_row = row;\n      result = png_safe_execute(image, png_image_read_background, display);\n      display->local_row = NULL;\n      png_free(png_ptr, row);\n\n      return result;\n   }\n\n   else\n   {\n      png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;\n\n      while (--passes >= 0)\n      {\n         png_uint_32      y = image->height;\n         png_bytep        row = png_voidcast(png_bytep, display->first_row);\n\n         for (; y > 0; --y)\n         {\n            png_read_row(png_ptr, row, NULL);\n            row += row_bytes;\n         }\n      }\n\n      return 1;\n   }\n}\n\nint PNGAPI\npng_image_finish_read(png_imagep image, png_const_colorp background,\n    void *buffer, png_int_32 row_stride, void *colormap)\n{\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      /* Check for row_stride overflow.  This check is not performed on the\n       * original PNG format because it may not occur in the output PNG format\n       * and libpng deals with the issues of reading the original.\n       */\n      unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);\n\n      /* The following checks just the 'row_stride' calculation to ensure it\n       * fits in a signed 32-bit value.  Because channels/components can be\n       * either 1 or 2 bytes in size the length of a row can still overflow 32\n       * bits; this is just to verify that the 'row_stride' argument can be\n       * represented.\n       */\n      if (image->width <= 0x7fffffffU/channels) /* no overflow */\n      {\n         png_uint_32 check;\n         png_uint_32 png_row_stride = image->width * channels;\n\n         if (row_stride == 0)\n            row_stride = (png_int_32)/*SAFE*/png_row_stride;\n\n         if (row_stride < 0)\n            check = (png_uint_32)(-row_stride);\n\n         else\n            check = (png_uint_32)row_stride;\n\n         /* This verifies 'check', the absolute value of the actual stride\n          * passed in and detects overflow in the application calculation (i.e.\n          * if the app did actually pass in a non-zero 'row_stride'.\n          */\n         if (image->opaque != NULL && buffer != NULL && check >= png_row_stride)\n         {\n            /* Now check for overflow of the image buffer calculation; this\n             * limits the whole image size to 32 bits for API compatibility with\n             * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.\n             *\n             * The PNG_IMAGE_BUFFER_SIZE macro is:\n             *\n             *    (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride))\n             *\n             * And the component size is always 1 or 2, so make sure that the\n             * number of *bytes* that the application is saying are available\n             * does actually fit into a 32-bit number.\n             *\n             * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE\n             * will be changed to use png_alloc_size_t; bigger images can be\n             * accommodated on 64-bit systems.\n             */\n            if (image->height <=\n                0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check)\n            {\n               if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||\n                  (image->colormap_entries > 0 && colormap != NULL))\n               {\n                  int result;\n                  png_image_read_control display;\n\n                  memset(&display, 0, (sizeof display));\n                  display.image = image;\n                  display.buffer = buffer;\n                  display.row_stride = row_stride;\n                  display.colormap = colormap;\n                  display.background = background;\n                  display.local_row = NULL;\n\n                  /* Choose the correct 'end' routine; for the color-map case\n                   * all the setup has already been done.\n                   */\n                  if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0)\n                     result =\n                         png_safe_execute(image,\n                             png_image_read_colormap, &display) &&\n                             png_safe_execute(image,\n                             png_image_read_colormapped, &display);\n\n                  else\n                     result =\n                        png_safe_execute(image,\n                            png_image_read_direct, &display);\n\n                  png_image_free(image);\n                  return result;\n               }\n\n               else\n                  return png_image_error(image,\n                      \"png_image_finish_read[color-map]: no color-map\");\n            }\n\n            else\n               return png_image_error(image,\n                   \"png_image_finish_read: image too large\");\n         }\n\n         else\n            return png_image_error(image,\n                \"png_image_finish_read: invalid argument\");\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_finish_read: row_stride too large\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_finish_read: damaged PNG_IMAGE_VERSION\");\n\n   return 0;\n}\n\n#endif /* SIMPLIFIED_READ */\n#endif /* READ */\n"
  },
  {
    "path": "dlib/external/libpng/pngrio.c",
    "content": "\n/* pngrio.c - functions for data input\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file provides a location for all input.  Users who need\n * special handling are expected to write a function that has the same\n * arguments as this and performs a similar function, but that possibly\n * has a different input method.  Note that you shouldn't change this\n * function, but rather write a replacement function and then make\n * libpng use it at run time with png_set_read_fn(...).\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_READ_SUPPORTED\n\n/* Read the data from whatever input you are using.  The default routine\n * reads from a file pointer.  Note that this routine sometimes gets called\n * with very small lengths, so you should implement some kind of simple\n * buffering if you are using unbuffered reads.  This should never be asked\n * to read more than 64K on a 16-bit machine.\n */\nvoid /* PRIVATE */\npng_read_data(png_structrp png_ptr, png_bytep data, size_t length)\n{\n   png_debug1(4, \"reading %d bytes\", (int)length);\n\n   if (png_ptr->read_data_fn != NULL)\n      (*(png_ptr->read_data_fn))(png_ptr, data, length);\n\n   else\n      png_error(png_ptr, \"Call to NULL read function\");\n}\n\n#ifdef PNG_STDIO_SUPPORTED\n/* This is the function that does the actual reading of data.  If you are\n * not reading from a standard C stream, you should create a replacement\n * read_data function and use it at run time with png_set_read_fn(), rather\n * than changing the library.\n */\nvoid PNGCBAPI\npng_default_read_data(png_structp png_ptr, png_bytep data, size_t length)\n{\n   size_t check;\n\n   if (png_ptr == NULL)\n      return;\n\n   /* fread() returns 0 on error, so it is OK to store this in a size_t\n    * instead of an int, which is what fread() actually returns.\n    */\n   check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr));\n\n   if (check != length)\n      png_error(png_ptr, \"Read Error\");\n}\n#endif\n\n/* This function allows the application to supply a new input function\n * for libpng if standard C streams aren't being used.\n *\n * This function takes as its arguments:\n *\n * png_ptr      - pointer to a png input data structure\n *\n * io_ptr       - pointer to user supplied structure containing info about\n *                the input functions.  May be NULL.\n *\n * read_data_fn - pointer to a new input function that takes as its\n *                arguments a pointer to a png_struct, a pointer to\n *                a location where input data can be stored, and a 32-bit\n *                unsigned int that is the number of bytes to be read.\n *                To exit and output any fatal error messages the new write\n *                function should call png_error(png_ptr, \"Error msg\").\n *                May be NULL, in which case libpng's default function will\n *                be used.\n */\nvoid PNGAPI\npng_set_read_fn(png_structrp png_ptr, png_voidp io_ptr,\n    png_rw_ptr read_data_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->io_ptr = io_ptr;\n\n#ifdef PNG_STDIO_SUPPORTED\n   if (read_data_fn != NULL)\n      png_ptr->read_data_fn = read_data_fn;\n\n   else\n      png_ptr->read_data_fn = png_default_read_data;\n#else\n   png_ptr->read_data_fn = read_data_fn;\n#endif\n\n#ifdef PNG_WRITE_SUPPORTED\n   /* It is an error to write to a read device */\n   if (png_ptr->write_data_fn != NULL)\n   {\n      png_ptr->write_data_fn = NULL;\n      png_warning(png_ptr,\n          \"Can't set both read_data_fn and write_data_fn in the\"\n          \" same structure\");\n   }\n#endif\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n   png_ptr->output_flush_fn = NULL;\n#endif\n}\n#endif /* READ */\n"
  },
  {
    "path": "dlib/external/libpng/pngrtran.c",
    "content": "\n/* pngrtran.c - transforms the data in a row for PNG readers\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file contains functions optionally called by an application\n * in order to tell libpng how to handle data when reading a PNG.\n * Transformations that are used in both reading and writing are\n * in pngtrans.c.\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_ARM_NEON_IMPLEMENTATION\n#  if PNG_ARM_NEON_IMPLEMENTATION == 1\n#    define PNG_ARM_NEON_INTRINSICS_AVAILABLE\n#    if defined(_MSC_VER) && defined(_M_ARM64)\n#      include <arm64_neon.h>\n#    else\n#      include <arm_neon.h>\n#    endif\n#  endif\n#endif\n\n#ifdef PNG_READ_SUPPORTED\n\n/* Set the action on getting a CRC error for an ancillary or critical chunk. */\nvoid PNGAPI\npng_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)\n{\n   png_debug(1, \"in png_set_crc_action\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* Tell libpng how we react to CRC errors in critical chunks */\n   switch (crit_action)\n   {\n      case PNG_CRC_NO_CHANGE:                        /* Leave setting as is */\n         break;\n\n      case PNG_CRC_WARN_USE:                               /* Warn/use data */\n         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;\n         png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;\n         break;\n\n      case PNG_CRC_QUIET_USE:                             /* Quiet/use data */\n         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;\n         png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |\n                           PNG_FLAG_CRC_CRITICAL_IGNORE;\n         break;\n\n      case PNG_CRC_WARN_DISCARD:    /* Not a valid action for critical data */\n         png_warning(png_ptr,\n             \"Can't discard critical data on CRC error\");\n         /* FALLTHROUGH */\n      case PNG_CRC_ERROR_QUIT:                                /* Error/quit */\n\n      case PNG_CRC_DEFAULT:\n      default:\n         png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;\n         break;\n   }\n\n   /* Tell libpng how we react to CRC errors in ancillary chunks */\n   switch (ancil_action)\n   {\n      case PNG_CRC_NO_CHANGE:                       /* Leave setting as is */\n         break;\n\n      case PNG_CRC_WARN_USE:                              /* Warn/use data */\n         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;\n         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;\n         break;\n\n      case PNG_CRC_QUIET_USE:                            /* Quiet/use data */\n         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;\n         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |\n                           PNG_FLAG_CRC_ANCILLARY_NOWARN;\n         break;\n\n      case PNG_CRC_ERROR_QUIT:                               /* Error/quit */\n         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;\n         png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;\n         break;\n\n      case PNG_CRC_WARN_DISCARD:                      /* Warn/discard data */\n\n      case PNG_CRC_DEFAULT:\n      default:\n         png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;\n         break;\n   }\n}\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n/* Is it OK to set a transformation now?  Only if png_start_read_image or\n * png_read_update_info have not been called.  It is not necessary for the IHDR\n * to have been read in all cases; the need_IHDR parameter allows for this\n * check too.\n */\nstatic int\npng_rtran_ok(png_structrp png_ptr, int need_IHDR)\n{\n   if (png_ptr != NULL)\n   {\n      if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)\n         png_app_error(png_ptr,\n             \"invalid after png_start_read_image or png_read_update_info\");\n\n      else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)\n         png_app_error(png_ptr, \"invalid before the PNG header has been read\");\n\n      else\n      {\n         /* Turn on failure to initialize correctly for all transforms. */\n         png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;\n\n         return 1; /* Ok */\n      }\n   }\n\n   return 0; /* no png_error possible! */\n}\n#endif\n\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n/* Handle alpha and tRNS via a background color */\nvoid PNGFAPI\npng_set_background_fixed(png_structrp png_ptr,\n    png_const_color_16p background_color, int background_gamma_code,\n    int need_expand, png_fixed_point background_gamma)\n{\n   png_debug(1, \"in png_set_background_fixed\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL)\n      return;\n\n   if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)\n   {\n      png_warning(png_ptr, \"Application must supply a known background gamma\");\n      return;\n   }\n\n   png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;\n   png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n   png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n\n   png_ptr->background = *background_color;\n   png_ptr->background_gamma = background_gamma;\n   png_ptr->background_gamma_type = (png_byte)(background_gamma_code);\n   if (need_expand != 0)\n      png_ptr->transformations |= PNG_BACKGROUND_EXPAND;\n   else\n      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_background(png_structrp png_ptr,\n    png_const_color_16p background_color, int background_gamma_code,\n    int need_expand, double background_gamma)\n{\n   png_set_background_fixed(png_ptr, background_color, background_gamma_code,\n      need_expand, png_fixed(png_ptr, background_gamma, \"png_set_background\"));\n}\n#  endif /* FLOATING_POINT */\n#endif /* READ_BACKGROUND */\n\n/* Scale 16-bit depth files to 8-bit depth.  If both of these are set then the\n * one that pngrtran does first (scale) happens.  This is necessary to allow the\n * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.\n */\n#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\nvoid PNGAPI\npng_set_scale_16(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_scale_16\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= PNG_SCALE_16_TO_8;\n}\n#endif\n\n#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n/* Chop 16-bit depth files to 8-bit depth */\nvoid PNGAPI\npng_set_strip_16(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_strip_16\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= PNG_16_TO_8;\n}\n#endif\n\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\nvoid PNGAPI\npng_set_strip_alpha(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_strip_alpha\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= PNG_STRIP_ALPHA;\n}\n#endif\n\n#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)\nstatic png_fixed_point\ntranslate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,\n    int is_screen)\n{\n   /* Check for flag values.  The main reason for having the old Mac value as a\n    * flag is that it is pretty near impossible to work out what the correct\n    * value is from Apple documentation - a working Mac system is needed to\n    * discover the value!\n    */\n   if (output_gamma == PNG_DEFAULT_sRGB ||\n      output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)\n   {\n      /* If there is no sRGB support this just sets the gamma to the standard\n       * sRGB value.  (This is a side effect of using this function!)\n       */\n#     ifdef PNG_READ_sRGB_SUPPORTED\n         png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;\n#     else\n         PNG_UNUSED(png_ptr)\n#     endif\n      if (is_screen != 0)\n         output_gamma = PNG_GAMMA_sRGB;\n      else\n         output_gamma = PNG_GAMMA_sRGB_INVERSE;\n   }\n\n   else if (output_gamma == PNG_GAMMA_MAC_18 ||\n      output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)\n   {\n      if (is_screen != 0)\n         output_gamma = PNG_GAMMA_MAC_OLD;\n      else\n         output_gamma = PNG_GAMMA_MAC_INVERSE;\n   }\n\n   return output_gamma;\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nstatic png_fixed_point\nconvert_gamma_value(png_structrp png_ptr, double output_gamma)\n{\n   /* The following silently ignores cases where fixed point (times 100,000)\n    * gamma values are passed to the floating point API.  This is safe and it\n    * means the fixed point constants work just fine with the floating point\n    * API.  The alternative would just lead to undetected errors and spurious\n    * bug reports.  Negative values fail inside the _fixed API unless they\n    * correspond to the flag values.\n    */\n   if (output_gamma > 0 && output_gamma < 128)\n      output_gamma *= PNG_FP_1;\n\n   /* This preserves -1 and -2 exactly: */\n   output_gamma = floor(output_gamma + .5);\n\n   if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)\n      png_fixed_error(png_ptr, \"gamma value\");\n\n   return (png_fixed_point)output_gamma;\n}\n#  endif\n#endif /* READ_ALPHA_MODE || READ_GAMMA */\n\n#ifdef PNG_READ_ALPHA_MODE_SUPPORTED\nvoid PNGFAPI\npng_set_alpha_mode_fixed(png_structrp png_ptr, int mode,\n    png_fixed_point output_gamma)\n{\n   int compose = 0;\n   png_fixed_point file_gamma;\n\n   png_debug(1, \"in png_set_alpha_mode\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);\n\n   /* Validate the value to ensure it is in a reasonable range. The value\n    * is expected to be 1 or greater, but this range test allows for some\n    * viewing correction values.  The intent is to weed out users of this API\n    * who use the inverse of the gamma value accidentally!  Since some of these\n    * values are reasonable this may have to be changed:\n    *\n    * 1.6.x: changed from 0.07..3 to 0.01..100 (to accommodate the optimal 16-bit\n    * gamma of 36, and its reciprocal.)\n    */\n   if (output_gamma < 1000 || output_gamma > 10000000)\n      png_error(png_ptr, \"output gamma out of expected range\");\n\n   /* The default file gamma is the inverse of the output gamma; the output\n    * gamma may be changed below so get the file value first:\n    */\n   file_gamma = png_reciprocal(output_gamma);\n\n   /* There are really 8 possibilities here, composed of any combination\n    * of:\n    *\n    *    premultiply the color channels\n    *    do not encode non-opaque pixels\n    *    encode the alpha as well as the color channels\n    *\n    * The differences disappear if the input/output ('screen') gamma is 1.0,\n    * because then the encoding is a no-op and there is only the choice of\n    * premultiplying the color channels or not.\n    *\n    * png_set_alpha_mode and png_set_background interact because both use\n    * png_compose to do the work.  Calling both is only useful when\n    * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along\n    * with a default gamma value.  Otherwise PNG_COMPOSE must not be set.\n    */\n   switch (mode)\n   {\n      case PNG_ALPHA_PNG:        /* default: png standard */\n         /* No compose, but it may be set by png_set_background! */\n         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n         break;\n\n      case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */\n         compose = 1;\n         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n         /* The output is linear: */\n         output_gamma = PNG_FP_1;\n         break;\n\n      case PNG_ALPHA_OPTIMIZED:  /* associated, non-opaque pixels linear */\n         compose = 1;\n         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n         png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;\n         /* output_gamma records the encoding of opaque pixels! */\n         break;\n\n      case PNG_ALPHA_BROKEN:     /* associated, non-linear, alpha encoded */\n         compose = 1;\n         png_ptr->transformations |= PNG_ENCODE_ALPHA;\n         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n         break;\n\n      default:\n         png_error(png_ptr, \"invalid alpha mode\");\n   }\n\n   /* Only set the default gamma if the file gamma has not been set (this has\n    * the side effect that the gamma in a second call to png_set_alpha_mode will\n    * be ignored.)\n    */\n   if (png_ptr->colorspace.gamma == 0)\n   {\n      png_ptr->colorspace.gamma = file_gamma;\n      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;\n   }\n\n   /* But always set the output gamma: */\n   png_ptr->screen_gamma = output_gamma;\n\n   /* Finally, if pre-multiplying, set the background fields to achieve the\n    * desired result.\n    */\n   if (compose != 0)\n   {\n      /* And obtain alpha pre-multiplication by composing on black: */\n      memset(&png_ptr->background, 0, (sizeof png_ptr->background));\n      png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */\n      png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;\n      png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;\n\n      if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n         png_error(png_ptr,\n             \"conflicting calls to set alpha mode and background\");\n\n      png_ptr->transformations |= PNG_COMPOSE;\n   }\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)\n{\n   png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,\n       output_gamma));\n}\n#  endif\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n/* Dither file to 8-bit.  Supply a palette, the current number\n * of elements in the palette, the maximum number of elements\n * allowed, and a histogram if possible.  If the current number\n * of colors is greater than the maximum number, the palette will be\n * modified to fit in the maximum number.  \"full_quantize\" indicates\n * whether we need a quantizing cube set up for RGB images, or if we\n * simply are reducing the number of colors in a paletted image.\n */\n\ntypedef struct png_dsort_struct\n{\n   struct png_dsort_struct * next;\n   png_byte left;\n   png_byte right;\n} png_dsort;\ntypedef png_dsort *   png_dsortp;\ntypedef png_dsort * * png_dsortpp;\n\nvoid PNGAPI\npng_set_quantize(png_structrp png_ptr, png_colorp palette,\n    int num_palette, int maximum_colors, png_const_uint_16p histogram,\n    int full_quantize)\n{\n   png_debug(1, \"in png_set_quantize\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= PNG_QUANTIZE;\n\n   if (full_quantize == 0)\n   {\n      int i;\n\n      png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,\n          (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));\n      for (i = 0; i < num_palette; i++)\n         png_ptr->quantize_index[i] = (png_byte)i;\n   }\n\n   if (num_palette > maximum_colors)\n   {\n      if (histogram != NULL)\n      {\n         /* This is easy enough, just throw out the least used colors.\n          * Perhaps not the best solution, but good enough.\n          */\n\n         int i;\n\n         /* Initialize an array to sort colors */\n         png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,\n             (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));\n\n         /* Initialize the quantize_sort array */\n         for (i = 0; i < num_palette; i++)\n            png_ptr->quantize_sort[i] = (png_byte)i;\n\n         /* Find the least used palette entries by starting a\n          * bubble sort, and running it until we have sorted\n          * out enough colors.  Note that we don't care about\n          * sorting all the colors, just finding which are\n          * least used.\n          */\n\n         for (i = num_palette - 1; i >= maximum_colors; i--)\n         {\n            int done; /* To stop early if the list is pre-sorted */\n            int j;\n\n            done = 1;\n            for (j = 0; j < i; j++)\n            {\n               if (histogram[png_ptr->quantize_sort[j]]\n                   < histogram[png_ptr->quantize_sort[j + 1]])\n               {\n                  png_byte t;\n\n                  t = png_ptr->quantize_sort[j];\n                  png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];\n                  png_ptr->quantize_sort[j + 1] = t;\n                  done = 0;\n               }\n            }\n\n            if (done != 0)\n               break;\n         }\n\n         /* Swap the palette around, and set up a table, if necessary */\n         if (full_quantize != 0)\n         {\n            int j = num_palette;\n\n            /* Put all the useful colors within the max, but don't\n             * move the others.\n             */\n            for (i = 0; i < maximum_colors; i++)\n            {\n               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)\n               {\n                  do\n                     j--;\n                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);\n\n                  palette[i] = palette[j];\n               }\n            }\n         }\n         else\n         {\n            int j = num_palette;\n\n            /* Move all the used colors inside the max limit, and\n             * develop a translation table.\n             */\n            for (i = 0; i < maximum_colors; i++)\n            {\n               /* Only move the colors we need to */\n               if ((int)png_ptr->quantize_sort[i] >= maximum_colors)\n               {\n                  png_color tmp_color;\n\n                  do\n                     j--;\n                  while ((int)png_ptr->quantize_sort[j] >= maximum_colors);\n\n                  tmp_color = palette[j];\n                  palette[j] = palette[i];\n                  palette[i] = tmp_color;\n                  /* Indicate where the color went */\n                  png_ptr->quantize_index[j] = (png_byte)i;\n                  png_ptr->quantize_index[i] = (png_byte)j;\n               }\n            }\n\n            /* Find closest color for those colors we are not using */\n            for (i = 0; i < num_palette; i++)\n            {\n               if ((int)png_ptr->quantize_index[i] >= maximum_colors)\n               {\n                  int min_d, k, min_k, d_index;\n\n                  /* Find the closest color to one we threw out */\n                  d_index = png_ptr->quantize_index[i];\n                  min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);\n                  for (k = 1, min_k = 0; k < maximum_colors; k++)\n                  {\n                     int d;\n\n                     d = PNG_COLOR_DIST(palette[d_index], palette[k]);\n\n                     if (d < min_d)\n                     {\n                        min_d = d;\n                        min_k = k;\n                     }\n                  }\n                  /* Point to closest color */\n                  png_ptr->quantize_index[i] = (png_byte)min_k;\n               }\n            }\n         }\n         png_free(png_ptr, png_ptr->quantize_sort);\n         png_ptr->quantize_sort = NULL;\n      }\n      else\n      {\n         /* This is much harder to do simply (and quickly).  Perhaps\n          * we need to go through a median cut routine, but those\n          * don't always behave themselves with only a few colors\n          * as input.  So we will just find the closest two colors,\n          * and throw out one of them (chosen somewhat randomly).\n          * [We don't understand this at all, so if someone wants to\n          *  work on improving it, be our guest - AED, GRP]\n          */\n         int i;\n         int max_d;\n         int num_new_palette;\n         png_dsortp t;\n         png_dsortpp hash;\n\n         t = NULL;\n\n         /* Initialize palette index arrays */\n         png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,\n             (png_alloc_size_t)((png_uint_32)num_palette *\n             (sizeof (png_byte))));\n         png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,\n             (png_alloc_size_t)((png_uint_32)num_palette *\n             (sizeof (png_byte))));\n\n         /* Initialize the sort array */\n         for (i = 0; i < num_palette; i++)\n         {\n            png_ptr->index_to_palette[i] = (png_byte)i;\n            png_ptr->palette_to_index[i] = (png_byte)i;\n         }\n\n         hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *\n             (sizeof (png_dsortp))));\n\n         num_new_palette = num_palette;\n\n         /* Initial wild guess at how far apart the farthest pixel\n          * pair we will be eliminating will be.  Larger\n          * numbers mean more areas will be allocated, Smaller\n          * numbers run the risk of not saving enough data, and\n          * having to do this all over again.\n          *\n          * I have not done extensive checking on this number.\n          */\n         max_d = 96;\n\n         while (num_new_palette > maximum_colors)\n         {\n            for (i = 0; i < num_new_palette - 1; i++)\n            {\n               int j;\n\n               for (j = i + 1; j < num_new_palette; j++)\n               {\n                  int d;\n\n                  d = PNG_COLOR_DIST(palette[i], palette[j]);\n\n                  if (d <= max_d)\n                  {\n\n                     t = (png_dsortp)png_malloc_warn(png_ptr,\n                         (png_alloc_size_t)(sizeof (png_dsort)));\n\n                     if (t == NULL)\n                         break;\n\n                     t->next = hash[d];\n                     t->left = (png_byte)i;\n                     t->right = (png_byte)j;\n                     hash[d] = t;\n                  }\n               }\n               if (t == NULL)\n                  break;\n            }\n\n            if (t != NULL)\n            for (i = 0; i <= max_d; i++)\n            {\n               if (hash[i] != NULL)\n               {\n                  png_dsortp p;\n\n                  for (p = hash[i]; p; p = p->next)\n                  {\n                     if ((int)png_ptr->index_to_palette[p->left]\n                         < num_new_palette &&\n                         (int)png_ptr->index_to_palette[p->right]\n                         < num_new_palette)\n                     {\n                        int j, next_j;\n\n                        if (num_new_palette & 0x01)\n                        {\n                           j = p->left;\n                           next_j = p->right;\n                        }\n                        else\n                        {\n                           j = p->right;\n                           next_j = p->left;\n                        }\n\n                        num_new_palette--;\n                        palette[png_ptr->index_to_palette[j]]\n                            = palette[num_new_palette];\n                        if (full_quantize == 0)\n                        {\n                           int k;\n\n                           for (k = 0; k < num_palette; k++)\n                           {\n                              if (png_ptr->quantize_index[k] ==\n                                  png_ptr->index_to_palette[j])\n                                 png_ptr->quantize_index[k] =\n                                     png_ptr->index_to_palette[next_j];\n\n                              if ((int)png_ptr->quantize_index[k] ==\n                                  num_new_palette)\n                                 png_ptr->quantize_index[k] =\n                                     png_ptr->index_to_palette[j];\n                           }\n                        }\n\n                        png_ptr->index_to_palette[png_ptr->palette_to_index\n                            [num_new_palette]] = png_ptr->index_to_palette[j];\n\n                        png_ptr->palette_to_index[png_ptr->index_to_palette[j]]\n                            = png_ptr->palette_to_index[num_new_palette];\n\n                        png_ptr->index_to_palette[j] =\n                            (png_byte)num_new_palette;\n\n                        png_ptr->palette_to_index[num_new_palette] =\n                            (png_byte)j;\n                     }\n                     if (num_new_palette <= maximum_colors)\n                        break;\n                  }\n                  if (num_new_palette <= maximum_colors)\n                     break;\n               }\n            }\n\n            for (i = 0; i < 769; i++)\n            {\n               if (hash[i] != NULL)\n               {\n                  png_dsortp p = hash[i];\n                  while (p)\n                  {\n                     t = p->next;\n                     png_free(png_ptr, p);\n                     p = t;\n                  }\n               }\n               hash[i] = 0;\n            }\n            max_d += 96;\n         }\n         png_free(png_ptr, hash);\n         png_free(png_ptr, png_ptr->palette_to_index);\n         png_free(png_ptr, png_ptr->index_to_palette);\n         png_ptr->palette_to_index = NULL;\n         png_ptr->index_to_palette = NULL;\n      }\n      num_palette = maximum_colors;\n   }\n   if (png_ptr->palette == NULL)\n   {\n      png_ptr->palette = palette;\n   }\n   png_ptr->num_palette = (png_uint_16)num_palette;\n\n   if (full_quantize != 0)\n   {\n      int i;\n      png_bytep distance;\n      int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +\n          PNG_QUANTIZE_BLUE_BITS;\n      int num_red = (1 << PNG_QUANTIZE_RED_BITS);\n      int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);\n      int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);\n      size_t num_entries = ((size_t)1 << total_bits);\n\n      png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,\n          (png_alloc_size_t)(num_entries * (sizeof (png_byte))));\n\n      distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *\n          (sizeof (png_byte))));\n\n      memset(distance, 0xff, num_entries * (sizeof (png_byte)));\n\n      for (i = 0; i < num_palette; i++)\n      {\n         int ir, ig, ib;\n         int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));\n         int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));\n         int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));\n\n         for (ir = 0; ir < num_red; ir++)\n         {\n            /* int dr = abs(ir - r); */\n            int dr = ((ir > r) ? ir - r : r - ir);\n            int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +\n                PNG_QUANTIZE_GREEN_BITS));\n\n            for (ig = 0; ig < num_green; ig++)\n            {\n               /* int dg = abs(ig - g); */\n               int dg = ((ig > g) ? ig - g : g - ig);\n               int dt = dr + dg;\n               int dm = ((dr > dg) ? dr : dg);\n               int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);\n\n               for (ib = 0; ib < num_blue; ib++)\n               {\n                  int d_index = index_g | ib;\n                  /* int db = abs(ib - b); */\n                  int db = ((ib > b) ? ib - b : b - ib);\n                  int dmax = ((dm > db) ? dm : db);\n                  int d = dmax + dt + db;\n\n                  if (d < (int)distance[d_index])\n                  {\n                     distance[d_index] = (png_byte)d;\n                     png_ptr->palette_lookup[d_index] = (png_byte)i;\n                  }\n               }\n            }\n         }\n      }\n\n      png_free(png_ptr, distance);\n   }\n}\n#endif /* READ_QUANTIZE */\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\nvoid PNGFAPI\npng_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,\n    png_fixed_point file_gamma)\n{\n   png_debug(1, \"in png_set_gamma_fixed\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   /* New in libpng-1.5.4 - reserve particular negative values as flags. */\n   scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);\n   file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);\n\n   /* Checking the gamma values for being >0 was added in 1.5.4 along with the\n    * premultiplied alpha support; this actually hides an undocumented feature\n    * of the previous implementation which allowed gamma processing to be\n    * disabled in background handling.  There is no evidence (so far) that this\n    * was being used; however, png_set_background itself accepted and must still\n    * accept '0' for the gamma value it takes, because it isn't always used.\n    *\n    * Since this is an API change (albeit a very minor one that removes an\n    * undocumented API feature) the following checks were only enabled in\n    * libpng-1.6.0.\n    */\n   if (file_gamma <= 0)\n      png_error(png_ptr, \"invalid file gamma in png_set_gamma\");\n\n   if (scrn_gamma <= 0)\n      png_error(png_ptr, \"invalid screen gamma in png_set_gamma\");\n\n   /* Set the gamma values unconditionally - this overrides the value in the PNG\n    * file if a gAMA chunk was present.  png_set_alpha_mode provides a\n    * different, easier, way to default the file gamma.\n    */\n   png_ptr->colorspace.gamma = file_gamma;\n   png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;\n   png_ptr->screen_gamma = scrn_gamma;\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)\n{\n   png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),\n       convert_gamma_value(png_ptr, file_gamma));\n}\n#  endif /* FLOATING_POINT */\n#endif /* READ_GAMMA */\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n/* Expand paletted images to RGB, expand grayscale images of\n * less than 8-bit depth to 8-bit depth, and expand tRNS chunks\n * to alpha channels.\n */\nvoid PNGAPI\npng_set_expand(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_expand\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);\n}\n\n/* GRR 19990627:  the following three functions currently are identical\n *  to png_set_expand().  However, it is entirely reasonable that someone\n *  might wish to expand an indexed image to RGB but *not* expand a single,\n *  fully transparent palette entry to a full alpha channel--perhaps instead\n *  convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace\n *  the transparent color with a particular RGB value, or drop tRNS entirely.\n *  IOW, a future version of the library may make the transformations flag\n *  a bit more fine-grained, with separate bits for each of these three\n *  functions.\n *\n *  More to the point, these functions make it obvious what libpng will be\n *  doing, whereas \"expand\" can (and does) mean any number of things.\n *\n *  GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified\n *  to expand only the sample depth but not to expand the tRNS to alpha\n *  and its name was changed to png_set_expand_gray_1_2_4_to_8().\n */\n\n/* Expand paletted images to RGB. */\nvoid PNGAPI\npng_set_palette_to_rgb(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_palette_to_rgb\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);\n}\n\n/* Expand grayscale images of less than 8-bit depth to 8 bits. */\nvoid PNGAPI\npng_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_expand_gray_1_2_4_to_8\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= PNG_EXPAND;\n}\n\n/* Expand tRNS chunks to alpha channels. */\nvoid PNGAPI\npng_set_tRNS_to_alpha(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_tRNS_to_alpha\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);\n}\n#endif /* READ_EXPAND */\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise\n * it may not work correctly.)\n */\nvoid PNGAPI\npng_set_expand_16(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_expand_16\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);\n}\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\nvoid PNGAPI\npng_set_gray_to_rgb(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_gray_to_rgb\");\n\n   if (png_rtran_ok(png_ptr, 0) == 0)\n      return;\n\n   /* Because rgb must be 8 bits or more: */\n   png_set_expand_gray_1_2_4_to_8(png_ptr);\n   png_ptr->transformations |= PNG_GRAY_TO_RGB;\n}\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\nvoid PNGFAPI\npng_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,\n    png_fixed_point red, png_fixed_point green)\n{\n   png_debug(1, \"in png_set_rgb_to_gray\");\n\n   /* Need the IHDR here because of the check on color_type below. */\n   /* TODO: fix this */\n   if (png_rtran_ok(png_ptr, 1) == 0)\n      return;\n\n   switch (error_action)\n   {\n      case PNG_ERROR_ACTION_NONE:\n         png_ptr->transformations |= PNG_RGB_TO_GRAY;\n         break;\n\n      case PNG_ERROR_ACTION_WARN:\n         png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;\n         break;\n\n      case PNG_ERROR_ACTION_ERROR:\n         png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;\n         break;\n\n      default:\n         png_error(png_ptr, \"invalid error action to rgb_to_gray\");\n   }\n\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n#ifdef PNG_READ_EXPAND_SUPPORTED\n      png_ptr->transformations |= PNG_EXPAND;\n#else\n   {\n      /* Make this an error in 1.6 because otherwise the application may assume\n       * that it just worked and get a memory overwrite.\n       */\n      png_error(png_ptr,\n          \"Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED\");\n\n      /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */\n   }\n#endif\n   {\n      if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)\n      {\n         png_uint_16 red_int, green_int;\n\n         /* NOTE: this calculation does not round, but this behavior is retained\n          * for consistency; the inaccuracy is very small.  The code here always\n          * overwrites the coefficients, regardless of whether they have been\n          * defaulted or set already.\n          */\n         red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);\n         green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);\n\n         png_ptr->rgb_to_gray_red_coeff   = red_int;\n         png_ptr->rgb_to_gray_green_coeff = green_int;\n         png_ptr->rgb_to_gray_coefficients_set = 1;\n      }\n\n      else\n      {\n         if (red >= 0 && green >= 0)\n            png_app_warning(png_ptr,\n                \"ignoring out of range rgb_to_gray coefficients\");\n\n         /* Use the defaults, from the cHRM chunk if set, else the historical\n          * values which are close to the sRGB/HDTV/ITU-Rec 709 values.  See\n          * png_do_rgb_to_gray for more discussion of the values.  In this case\n          * the coefficients are not marked as 'set' and are not overwritten if\n          * something has already provided a default.\n          */\n         if (png_ptr->rgb_to_gray_red_coeff == 0 &&\n             png_ptr->rgb_to_gray_green_coeff == 0)\n         {\n            png_ptr->rgb_to_gray_red_coeff   = 6968;\n            png_ptr->rgb_to_gray_green_coeff = 23434;\n            /* png_ptr->rgb_to_gray_blue_coeff  = 2366; */\n         }\n      }\n   }\n}\n\n#ifdef PNG_FLOATING_POINT_SUPPORTED\n/* Convert a RGB image to a grayscale of the same width.  This allows us,\n * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.\n */\n\nvoid PNGAPI\npng_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,\n    double green)\n{\n   png_set_rgb_to_gray_fixed(png_ptr, error_action,\n       png_fixed(png_ptr, red, \"rgb to gray red coefficient\"),\n      png_fixed(png_ptr, green, \"rgb to gray green coefficient\"));\n}\n#endif /* FLOATING POINT */\n\n#endif /* RGB_TO_GRAY */\n\n#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \\\n    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)\nvoid PNGAPI\npng_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr\n    read_user_transform_fn)\n{\n   png_debug(1, \"in png_set_read_user_transform_fn\");\n\n#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED\n   png_ptr->transformations |= PNG_USER_TRANSFORM;\n   png_ptr->read_user_transform_fn = read_user_transform_fn;\n#endif\n}\n#endif\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n#ifdef PNG_READ_GAMMA_SUPPORTED\n/* In the case of gamma transformations only do transformations on images where\n * the [file] gamma and screen_gamma are not close reciprocals, otherwise it\n * slows things down slightly, and also needlessly introduces small errors.\n */\nstatic int /* PRIVATE */\npng_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)\n{\n   /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma\n    * correction as a difference of the overall transform from 1.0\n    *\n    * We want to compare the threshold with s*f - 1, if we get\n    * overflow here it is because of wacky gamma values so we\n    * turn on processing anyway.\n    */\n   png_fixed_point gtest;\n   return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||\n       png_gamma_significant(gtest);\n}\n#endif\n\n/* Initialize everything needed for the read.  This includes modifying\n * the palette.\n */\n\n/* For the moment 'png_init_palette_transformations' and\n * 'png_init_rgb_transformations' only do some flag canceling optimizations.\n * The intent is that these two routines should have palette or rgb operations\n * extracted from 'png_init_read_transformations'.\n */\nstatic void /* PRIVATE */\npng_init_palette_transformations(png_structrp png_ptr)\n{\n   /* Called to handle the (input) palette case.  In png_do_read_transformations\n    * the first step is to expand the palette if requested, so this code must\n    * take care to only make changes that are invariant with respect to the\n    * palette expansion, or only do them if there is no expansion.\n    *\n    * STRIP_ALPHA has already been handled in the caller (by setting num_trans\n    * to 0.)\n    */\n   int input_has_alpha = 0;\n   int input_has_transparency = 0;\n\n   if (png_ptr->num_trans > 0)\n   {\n      int i;\n\n      /* Ignore if all the entries are opaque (unlikely!) */\n      for (i=0; i<png_ptr->num_trans; ++i)\n      {\n         if (png_ptr->trans_alpha[i] == 255)\n            continue;\n         else if (png_ptr->trans_alpha[i] == 0)\n            input_has_transparency = 1;\n         else\n         {\n            input_has_transparency = 1;\n            input_has_alpha = 1;\n            break;\n         }\n      }\n   }\n\n   /* If no alpha we can optimize. */\n   if (input_has_alpha == 0)\n   {\n      /* Any alpha means background and associative alpha processing is\n       * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA\n       * and ENCODE_ALPHA are irrelevant.\n       */\n      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n\n      if (input_has_transparency == 0)\n         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);\n   }\n\n#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)\n   /* png_set_background handling - deals with the complexity of whether the\n    * background color is in the file format or the screen format in the case\n    * where an 'expand' will happen.\n    */\n\n   /* The following code cannot be entered in the alpha pre-multiplication case\n    * because PNG_BACKGROUND_EXPAND is cancelled below.\n    */\n   if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&\n       (png_ptr->transformations & PNG_EXPAND) != 0)\n   {\n      {\n         png_ptr->background.red   =\n             png_ptr->palette[png_ptr->background.index].red;\n         png_ptr->background.green =\n             png_ptr->palette[png_ptr->background.index].green;\n         png_ptr->background.blue  =\n             png_ptr->palette[png_ptr->background.index].blue;\n\n#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED\n         if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)\n         {\n            if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)\n            {\n               /* Invert the alpha channel (in tRNS) unless the pixels are\n                * going to be expanded, in which case leave it for later\n                */\n               int i, istop = png_ptr->num_trans;\n\n               for (i = 0; i < istop; i++)\n                  png_ptr->trans_alpha[i] =\n                      (png_byte)(255 - png_ptr->trans_alpha[i]);\n            }\n         }\n#endif /* READ_INVERT_ALPHA */\n      }\n   } /* background expand and (therefore) no alpha association. */\n#endif /* READ_EXPAND && READ_BACKGROUND */\n}\n\nstatic void /* PRIVATE */\npng_init_rgb_transformations(png_structrp png_ptr)\n{\n   /* Added to libpng-1.5.4: check the color type to determine whether there\n    * is any alpha or transparency in the image and simply cancel the\n    * background and alpha mode stuff if there isn't.\n    */\n   int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;\n   int input_has_transparency = png_ptr->num_trans > 0;\n\n   /* If no alpha we can optimize. */\n   if (input_has_alpha == 0)\n   {\n      /* Any alpha means background and associative alpha processing is\n       * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA\n       * and ENCODE_ALPHA are irrelevant.\n       */\n#     ifdef PNG_READ_ALPHA_MODE_SUPPORTED\n         png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n         png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n#     endif\n\n      if (input_has_transparency == 0)\n         png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);\n   }\n\n#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)\n   /* png_set_background handling - deals with the complexity of whether the\n    * background color is in the file format or the screen format in the case\n    * where an 'expand' will happen.\n    */\n\n   /* The following code cannot be entered in the alpha pre-multiplication case\n    * because PNG_BACKGROUND_EXPAND is cancelled below.\n    */\n   if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&\n       (png_ptr->transformations & PNG_EXPAND) != 0 &&\n       (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)\n       /* i.e., GRAY or GRAY_ALPHA */\n   {\n      {\n         /* Expand background and tRNS chunks */\n         int gray = png_ptr->background.gray;\n         int trans_gray = png_ptr->trans_color.gray;\n\n         switch (png_ptr->bit_depth)\n         {\n            case 1:\n               gray *= 0xff;\n               trans_gray *= 0xff;\n               break;\n\n            case 2:\n               gray *= 0x55;\n               trans_gray *= 0x55;\n               break;\n\n            case 4:\n               gray *= 0x11;\n               trans_gray *= 0x11;\n               break;\n\n            default:\n\n            case 8:\n               /* FALLTHROUGH */ /*  (Already 8 bits) */\n\n            case 16:\n               /* Already a full 16 bits */\n               break;\n         }\n\n         png_ptr->background.red = png_ptr->background.green =\n            png_ptr->background.blue = (png_uint_16)gray;\n\n         if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)\n         {\n            png_ptr->trans_color.red = png_ptr->trans_color.green =\n               png_ptr->trans_color.blue = (png_uint_16)trans_gray;\n         }\n      }\n   } /* background expand and (therefore) no alpha association. */\n#endif /* READ_EXPAND && READ_BACKGROUND */\n}\n\nvoid /* PRIVATE */\npng_init_read_transformations(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_init_read_transformations\");\n\n   /* This internal function is called from png_read_start_row in pngrutil.c\n    * and it is called before the 'rowbytes' calculation is done, so the code\n    * in here can change or update the transformations flags.\n    *\n    * First do updates that do not depend on the details of the PNG image data\n    * being processed.\n    */\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds\n    * png_set_alpha_mode and this is another source for a default file gamma so\n    * the test needs to be performed later - here.  In addition prior to 1.5.4\n    * the tests were repeated for the PALETTE color type here - this is no\n    * longer necessary (and doesn't seem to have been necessary before.)\n    */\n   {\n      /* The following temporary indicates if overall gamma correction is\n       * required.\n       */\n      int gamma_correction = 0;\n\n      if (png_ptr->colorspace.gamma != 0) /* has been set */\n      {\n         if (png_ptr->screen_gamma != 0) /* screen set too */\n            gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,\n                png_ptr->screen_gamma);\n\n         else\n            /* Assume the output matches the input; a long time default behavior\n             * of libpng, although the standard has nothing to say about this.\n             */\n            png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);\n      }\n\n      else if (png_ptr->screen_gamma != 0)\n         /* The converse - assume the file matches the screen, note that this\n          * perhaps undesirable default can (from 1.5.4) be changed by calling\n          * png_set_alpha_mode (even if the alpha handling mode isn't required\n          * or isn't changed from the default.)\n          */\n         png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);\n\n      else /* neither are set */\n         /* Just in case the following prevents any processing - file and screen\n          * are both assumed to be linear and there is no way to introduce a\n          * third gamma value other than png_set_background with 'UNIQUE', and,\n          * prior to 1.5.4\n          */\n         png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;\n\n      /* We have a gamma value now. */\n      png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;\n\n      /* Now turn the gamma transformation on or off as appropriate.  Notice\n       * that PNG_GAMMA just refers to the file->screen correction.  Alpha\n       * composition may independently cause gamma correction because it needs\n       * linear data (e.g. if the file has a gAMA chunk but the screen gamma\n       * hasn't been specified.)  In any case this flag may get turned off in\n       * the code immediately below if the transform can be handled outside the\n       * row loop.\n       */\n      if (gamma_correction != 0)\n         png_ptr->transformations |= PNG_GAMMA;\n\n      else\n         png_ptr->transformations &= ~PNG_GAMMA;\n   }\n#endif\n\n   /* Certain transformations have the effect of preventing other\n    * transformations that happen afterward in png_do_read_transformations;\n    * resolve the interdependencies here.  From the code of\n    * png_do_read_transformations the order is:\n    *\n    *  1) PNG_EXPAND (including PNG_EXPAND_tRNS)\n    *  2) PNG_STRIP_ALPHA (if no compose)\n    *  3) PNG_RGB_TO_GRAY\n    *  4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY\n    *  5) PNG_COMPOSE\n    *  6) PNG_GAMMA\n    *  7) PNG_STRIP_ALPHA (if compose)\n    *  8) PNG_ENCODE_ALPHA\n    *  9) PNG_SCALE_16_TO_8\n    * 10) PNG_16_TO_8\n    * 11) PNG_QUANTIZE (converts to palette)\n    * 12) PNG_EXPAND_16\n    * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY\n    * 14) PNG_INVERT_MONO\n    * 15) PNG_INVERT_ALPHA\n    * 16) PNG_SHIFT\n    * 17) PNG_PACK\n    * 18) PNG_BGR\n    * 19) PNG_PACKSWAP\n    * 20) PNG_FILLER (includes PNG_ADD_ALPHA)\n    * 21) PNG_SWAP_ALPHA\n    * 22) PNG_SWAP_BYTES\n    * 23) PNG_USER_TRANSFORM [must be last]\n    */\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&\n       (png_ptr->transformations & PNG_COMPOSE) == 0)\n   {\n      /* Stripping the alpha channel happens immediately after the 'expand'\n       * transformations, before all other transformation, so it cancels out\n       * the alpha handling.  It has the side effect negating the effect of\n       * PNG_EXPAND_tRNS too:\n       */\n      png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |\n         PNG_EXPAND_tRNS);\n      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n\n      /* Kill the tRNS chunk itself too.  Prior to 1.5.4 this did not happen\n       * so transparency information would remain just so long as it wasn't\n       * expanded.  This produces unexpected API changes if the set of things\n       * that do PNG_EXPAND_tRNS changes (perfectly possible given the\n       * documentation - which says ask for what you want, accept what you\n       * get.)  This makes the behavior consistent from 1.5.4:\n       */\n      png_ptr->num_trans = 0;\n   }\n#endif /* STRIP_ALPHA supported, no COMPOSE */\n\n#ifdef PNG_READ_ALPHA_MODE_SUPPORTED\n   /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA\n    * settings will have no effect.\n    */\n   if (png_gamma_significant(png_ptr->screen_gamma) == 0)\n   {\n      png_ptr->transformations &= ~PNG_ENCODE_ALPHA;\n      png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;\n   }\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n   /* Make sure the coefficients for the rgb to gray conversion are set\n    * appropriately.\n    */\n   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)\n      png_colorspace_set_rgb_coefficients(png_ptr);\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)\n   /* Detect gray background and attempt to enable optimization for\n    * gray --> RGB case.\n    *\n    * Note:  if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or\n    * RGB_ALPHA (in which case need_expand is superfluous anyway), the\n    * background color might actually be gray yet not be flagged as such.\n    * This is not a problem for the current code, which uses\n    * PNG_BACKGROUND_IS_GRAY only to decide when to do the\n    * png_do_gray_to_rgb() transformation.\n    *\n    * TODO: this code needs to be revised to avoid the complexity and\n    * interdependencies.  The color type of the background should be recorded in\n    * png_set_background, along with the bit depth, then the code has a record\n    * of exactly what color space the background is currently in.\n    */\n   if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0)\n   {\n      /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if\n       * the file was grayscale the background value is gray.\n       */\n      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)\n         png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;\n   }\n\n   else if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n   {\n      /* PNG_COMPOSE: png_set_background was called with need_expand false,\n       * so the color is in the color space of the output or png_set_alpha_mode\n       * was called and the color is black.  Ignore RGB_TO_GRAY because that\n       * happens before GRAY_TO_RGB.\n       */\n      if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)\n      {\n         if (png_ptr->background.red == png_ptr->background.green &&\n             png_ptr->background.red == png_ptr->background.blue)\n         {\n            png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;\n            png_ptr->background.gray = png_ptr->background.red;\n         }\n      }\n   }\n#endif /* READ_EXPAND && READ_BACKGROUND */\n#endif /* READ_GRAY_TO_RGB */\n\n   /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations\n    * can be performed directly on the palette, and some (such as rgb to gray)\n    * can be optimized inside the palette.  This is particularly true of the\n    * composite (background and alpha) stuff, which can be pretty much all done\n    * in the palette even if the result is expanded to RGB or gray afterward.\n    *\n    * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and\n    * earlier and the palette stuff is actually handled on the first row.  This\n    * leads to the reported bug that the palette returned by png_get_PLTE is not\n    * updated.\n    */\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      png_init_palette_transformations(png_ptr);\n\n   else\n      png_init_rgb_transformations(png_ptr);\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \\\n   defined(PNG_READ_EXPAND_16_SUPPORTED)\n   if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&\n       (png_ptr->transformations & PNG_COMPOSE) != 0 &&\n       (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&\n       png_ptr->bit_depth != 16)\n   {\n      /* TODO: fix this.  Because the expand_16 operation is after the compose\n       * handling the background color must be 8, not 16, bits deep, but the\n       * application will supply a 16-bit value so reduce it here.\n       *\n       * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at\n       * present, so that case is ok (until do_expand_16 is moved.)\n       *\n       * NOTE: this discards the low 16 bits of the user supplied background\n       * color, but until expand_16 works properly there is no choice!\n       */\n#     define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))\n      CHOP(png_ptr->background.red);\n      CHOP(png_ptr->background.green);\n      CHOP(png_ptr->background.blue);\n      CHOP(png_ptr->background.gray);\n#     undef CHOP\n   }\n#endif /* READ_BACKGROUND && READ_EXPAND_16 */\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \\\n   (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \\\n   defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))\n   if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 &&\n       (png_ptr->transformations & PNG_COMPOSE) != 0 &&\n       (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&\n       png_ptr->bit_depth == 16)\n   {\n      /* On the other hand, if a 16-bit file is to be reduced to 8-bits per\n       * component this will also happen after PNG_COMPOSE and so the background\n       * color must be pre-expanded here.\n       *\n       * TODO: fix this too.\n       */\n      png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);\n      png_ptr->background.green =\n         (png_uint_16)(png_ptr->background.green * 257);\n      png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);\n      png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);\n   }\n#endif\n\n   /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the\n    * background support (see the comments in scripts/pnglibconf.dfa), this\n    * allows pre-multiplication of the alpha channel to be implemented as\n    * compositing on black.  This is probably sub-optimal and has been done in\n    * 1.5.4 betas simply to enable external critique and testing (i.e. to\n    * implement the new API quickly, without lots of internal changes.)\n    */\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n#  ifdef PNG_READ_BACKGROUND_SUPPORTED\n      /* Includes ALPHA_MODE */\n      png_ptr->background_1 = png_ptr->background;\n#  endif\n\n   /* This needs to change - in the palette image case a whole set of tables are\n    * built when it would be quicker to just calculate the correct value for\n    * each palette entry directly.  Also, the test is too tricky - why check\n    * PNG_RGB_TO_GRAY if PNG_GAMMA is not set?  The answer seems to be that\n    * PNG_GAMMA is cancelled even if the gamma is known?  The test excludes the\n    * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction\n    * the gamma tables will not be built even if composition is required on a\n    * gamma encoded value.\n    *\n    * In 1.5.4 this is addressed below by an additional check on the individual\n    * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the\n    * tables.\n    */\n   if ((png_ptr->transformations & PNG_GAMMA) != 0 ||\n       ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 &&\n        (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||\n         png_gamma_significant(png_ptr->screen_gamma) != 0)) ||\n        ((png_ptr->transformations & PNG_COMPOSE) != 0 &&\n         (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||\n          png_gamma_significant(png_ptr->screen_gamma) != 0\n#  ifdef PNG_READ_BACKGROUND_SUPPORTED\n         || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&\n           png_gamma_significant(png_ptr->background_gamma) != 0)\n#  endif\n        )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&\n       png_gamma_significant(png_ptr->screen_gamma) != 0))\n   {\n      png_build_gamma_table(png_ptr, png_ptr->bit_depth);\n\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n      if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n      {\n         /* Issue a warning about this combination: because RGB_TO_GRAY is\n          * optimized to do the gamma transform if present yet do_background has\n          * to do the same thing if both options are set a\n          * double-gamma-correction happens.  This is true in all versions of\n          * libpng to date.\n          */\n         if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)\n            png_warning(png_ptr,\n                \"libpng does not support gamma+background+rgb_to_gray\");\n\n         if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0)\n         {\n            /* We don't get to here unless there is a tRNS chunk with non-opaque\n             * entries - see the checking code at the start of this function.\n             */\n            png_color back, back_1;\n            png_colorp palette = png_ptr->palette;\n            int num_palette = png_ptr->num_palette;\n            int i;\n            if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)\n            {\n\n               back.red = png_ptr->gamma_table[png_ptr->background.red];\n               back.green = png_ptr->gamma_table[png_ptr->background.green];\n               back.blue = png_ptr->gamma_table[png_ptr->background.blue];\n\n               back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];\n               back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];\n               back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];\n            }\n            else\n            {\n               png_fixed_point g, gs;\n\n               switch (png_ptr->background_gamma_type)\n               {\n                  case PNG_BACKGROUND_GAMMA_SCREEN:\n                     g = (png_ptr->screen_gamma);\n                     gs = PNG_FP_1;\n                     break;\n\n                  case PNG_BACKGROUND_GAMMA_FILE:\n                     g = png_reciprocal(png_ptr->colorspace.gamma);\n                     gs = png_reciprocal2(png_ptr->colorspace.gamma,\n                         png_ptr->screen_gamma);\n                     break;\n\n                  case PNG_BACKGROUND_GAMMA_UNIQUE:\n                     g = png_reciprocal(png_ptr->background_gamma);\n                     gs = png_reciprocal2(png_ptr->background_gamma,\n                         png_ptr->screen_gamma);\n                     break;\n                  default:\n                     g = PNG_FP_1;    /* back_1 */\n                     gs = PNG_FP_1;   /* back */\n                     break;\n               }\n\n               if (png_gamma_significant(gs) != 0)\n               {\n                  back.red = png_gamma_8bit_correct(png_ptr->background.red,\n                      gs);\n                  back.green = png_gamma_8bit_correct(png_ptr->background.green,\n                      gs);\n                  back.blue = png_gamma_8bit_correct(png_ptr->background.blue,\n                      gs);\n               }\n\n               else\n               {\n                  back.red   = (png_byte)png_ptr->background.red;\n                  back.green = (png_byte)png_ptr->background.green;\n                  back.blue  = (png_byte)png_ptr->background.blue;\n               }\n\n               if (png_gamma_significant(g) != 0)\n               {\n                  back_1.red = png_gamma_8bit_correct(png_ptr->background.red,\n                      g);\n                  back_1.green = png_gamma_8bit_correct(\n                      png_ptr->background.green, g);\n                  back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,\n                      g);\n               }\n\n               else\n               {\n                  back_1.red   = (png_byte)png_ptr->background.red;\n                  back_1.green = (png_byte)png_ptr->background.green;\n                  back_1.blue  = (png_byte)png_ptr->background.blue;\n               }\n            }\n\n            for (i = 0; i < num_palette; i++)\n            {\n               if (i < (int)png_ptr->num_trans &&\n                   png_ptr->trans_alpha[i] != 0xff)\n               {\n                  if (png_ptr->trans_alpha[i] == 0)\n                  {\n                     palette[i] = back;\n                  }\n                  else /* if (png_ptr->trans_alpha[i] != 0xff) */\n                  {\n                     png_byte v, w;\n\n                     v = png_ptr->gamma_to_1[palette[i].red];\n                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);\n                     palette[i].red = png_ptr->gamma_from_1[w];\n\n                     v = png_ptr->gamma_to_1[palette[i].green];\n                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);\n                     palette[i].green = png_ptr->gamma_from_1[w];\n\n                     v = png_ptr->gamma_to_1[palette[i].blue];\n                     png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);\n                     palette[i].blue = png_ptr->gamma_from_1[w];\n                  }\n               }\n               else\n               {\n                  palette[i].red = png_ptr->gamma_table[palette[i].red];\n                  palette[i].green = png_ptr->gamma_table[palette[i].green];\n                  palette[i].blue = png_ptr->gamma_table[palette[i].blue];\n               }\n            }\n\n            /* Prevent the transformations being done again.\n             *\n             * NOTE: this is highly dubious; it removes the transformations in\n             * place.  This seems inconsistent with the general treatment of the\n             * transformations elsewhere.\n             */\n            png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);\n         } /* color_type == PNG_COLOR_TYPE_PALETTE */\n\n         /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */\n         else /* color_type != PNG_COLOR_TYPE_PALETTE */\n         {\n            int gs_sig, g_sig;\n            png_fixed_point g = PNG_FP_1;  /* Correction to linear */\n            png_fixed_point gs = PNG_FP_1; /* Correction to screen */\n\n            switch (png_ptr->background_gamma_type)\n            {\n               case PNG_BACKGROUND_GAMMA_SCREEN:\n                  g = png_ptr->screen_gamma;\n                  /* gs = PNG_FP_1; */\n                  break;\n\n               case PNG_BACKGROUND_GAMMA_FILE:\n                  g = png_reciprocal(png_ptr->colorspace.gamma);\n                  gs = png_reciprocal2(png_ptr->colorspace.gamma,\n                      png_ptr->screen_gamma);\n                  break;\n\n               case PNG_BACKGROUND_GAMMA_UNIQUE:\n                  g = png_reciprocal(png_ptr->background_gamma);\n                  gs = png_reciprocal2(png_ptr->background_gamma,\n                      png_ptr->screen_gamma);\n                  break;\n\n               default:\n                  png_error(png_ptr, \"invalid background gamma type\");\n            }\n\n            g_sig = png_gamma_significant(g);\n            gs_sig = png_gamma_significant(gs);\n\n            if (g_sig != 0)\n               png_ptr->background_1.gray = png_gamma_correct(png_ptr,\n                   png_ptr->background.gray, g);\n\n            if (gs_sig != 0)\n               png_ptr->background.gray = png_gamma_correct(png_ptr,\n                   png_ptr->background.gray, gs);\n\n            if ((png_ptr->background.red != png_ptr->background.green) ||\n                (png_ptr->background.red != png_ptr->background.blue) ||\n                (png_ptr->background.red != png_ptr->background.gray))\n            {\n               /* RGB or RGBA with color background */\n               if (g_sig != 0)\n               {\n                  png_ptr->background_1.red = png_gamma_correct(png_ptr,\n                      png_ptr->background.red, g);\n\n                  png_ptr->background_1.green = png_gamma_correct(png_ptr,\n                      png_ptr->background.green, g);\n\n                  png_ptr->background_1.blue = png_gamma_correct(png_ptr,\n                      png_ptr->background.blue, g);\n               }\n\n               if (gs_sig != 0)\n               {\n                  png_ptr->background.red = png_gamma_correct(png_ptr,\n                      png_ptr->background.red, gs);\n\n                  png_ptr->background.green = png_gamma_correct(png_ptr,\n                      png_ptr->background.green, gs);\n\n                  png_ptr->background.blue = png_gamma_correct(png_ptr,\n                      png_ptr->background.blue, gs);\n               }\n            }\n\n            else\n            {\n               /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */\n               png_ptr->background_1.red = png_ptr->background_1.green\n                   = png_ptr->background_1.blue = png_ptr->background_1.gray;\n\n               png_ptr->background.red = png_ptr->background.green\n                   = png_ptr->background.blue = png_ptr->background.gray;\n            }\n\n            /* The background is now in screen gamma: */\n            png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;\n         } /* color_type != PNG_COLOR_TYPE_PALETTE */\n      }/* png_ptr->transformations & PNG_BACKGROUND */\n\n      else\n      /* Transformation does not include PNG_BACKGROUND */\n#endif /* READ_BACKGROUND */\n      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n         /* RGB_TO_GRAY needs to have non-gamma-corrected values! */\n         && ((png_ptr->transformations & PNG_EXPAND) == 0 ||\n         (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)\n#endif\n         )\n      {\n         png_colorp palette = png_ptr->palette;\n         int num_palette = png_ptr->num_palette;\n         int i;\n\n         /* NOTE: there are other transformations that should probably be in\n          * here too.\n          */\n         for (i = 0; i < num_palette; i++)\n         {\n            palette[i].red = png_ptr->gamma_table[palette[i].red];\n            palette[i].green = png_ptr->gamma_table[palette[i].green];\n            palette[i].blue = png_ptr->gamma_table[palette[i].blue];\n         }\n\n         /* Done the gamma correction. */\n         png_ptr->transformations &= ~PNG_GAMMA;\n      } /* color_type == PALETTE && !PNG_BACKGROUND transformation */\n   }\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n   else\n#endif\n#endif /* READ_GAMMA */\n\n#ifdef PNG_READ_BACKGROUND_SUPPORTED\n   /* No GAMMA transformation (see the hanging else 4 lines above) */\n   if ((png_ptr->transformations & PNG_COMPOSE) != 0 &&\n       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))\n   {\n      int i;\n      int istop = (int)png_ptr->num_trans;\n      png_color back;\n      png_colorp palette = png_ptr->palette;\n\n      back.red   = (png_byte)png_ptr->background.red;\n      back.green = (png_byte)png_ptr->background.green;\n      back.blue  = (png_byte)png_ptr->background.blue;\n\n      for (i = 0; i < istop; i++)\n      {\n         if (png_ptr->trans_alpha[i] == 0)\n         {\n            palette[i] = back;\n         }\n\n         else if (png_ptr->trans_alpha[i] != 0xff)\n         {\n            /* The png_composite() macro is defined in png.h */\n            png_composite(palette[i].red, palette[i].red,\n                png_ptr->trans_alpha[i], back.red);\n\n            png_composite(palette[i].green, palette[i].green,\n                png_ptr->trans_alpha[i], back.green);\n\n            png_composite(palette[i].blue, palette[i].blue,\n                png_ptr->trans_alpha[i], back.blue);\n         }\n      }\n\n      png_ptr->transformations &= ~PNG_COMPOSE;\n   }\n#endif /* READ_BACKGROUND */\n\n#ifdef PNG_READ_SHIFT_SUPPORTED\n   if ((png_ptr->transformations & PNG_SHIFT) != 0 &&\n       (png_ptr->transformations & PNG_EXPAND) == 0 &&\n       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))\n   {\n      int i;\n      int istop = png_ptr->num_palette;\n      int shift = 8 - png_ptr->sig_bit.red;\n\n      png_ptr->transformations &= ~PNG_SHIFT;\n\n      /* significant bits can be in the range 1 to 7 for a meaningful result, if\n       * the number of significant bits is 0 then no shift is done (this is an\n       * error condition which is silently ignored.)\n       */\n      if (shift > 0 && shift < 8)\n         for (i=0; i<istop; ++i)\n         {\n            int component = png_ptr->palette[i].red;\n\n            component >>= shift;\n            png_ptr->palette[i].red = (png_byte)component;\n         }\n\n      shift = 8 - png_ptr->sig_bit.green;\n      if (shift > 0 && shift < 8)\n         for (i=0; i<istop; ++i)\n         {\n            int component = png_ptr->palette[i].green;\n\n            component >>= shift;\n            png_ptr->palette[i].green = (png_byte)component;\n         }\n\n      shift = 8 - png_ptr->sig_bit.blue;\n      if (shift > 0 && shift < 8)\n         for (i=0; i<istop; ++i)\n         {\n            int component = png_ptr->palette[i].blue;\n\n            component >>= shift;\n            png_ptr->palette[i].blue = (png_byte)component;\n         }\n   }\n#endif /* READ_SHIFT */\n}\n\n/* Modify the info structure to reflect the transformations.  The\n * info should be updated so a PNG file could be written with it,\n * assuming the transformations result in valid PNG data.\n */\nvoid /* PRIVATE */\npng_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)\n{\n   png_debug(1, \"in png_read_transform_info\");\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n   if ((png_ptr->transformations & PNG_EXPAND) != 0)\n   {\n      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         /* This check must match what actually happens in\n          * png_do_expand_palette; if it ever checks the tRNS chunk to see if\n          * it is all opaque we must do the same (at present it does not.)\n          */\n         if (png_ptr->num_trans > 0)\n            info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;\n\n         else\n            info_ptr->color_type = PNG_COLOR_TYPE_RGB;\n\n         info_ptr->bit_depth = 8;\n         info_ptr->num_trans = 0;\n\n         if (png_ptr->palette == NULL)\n            png_error (png_ptr, \"Palette is NULL in indexed image\");\n      }\n      else\n      {\n         if (png_ptr->num_trans != 0)\n         {\n            if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0)\n               info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;\n         }\n         if (info_ptr->bit_depth < 8)\n            info_ptr->bit_depth = 8;\n\n         info_ptr->num_trans = 0;\n      }\n   }\n#endif\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n   /* The following is almost certainly wrong unless the background value is in\n    * the screen space!\n    */\n   if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n      info_ptr->background = png_ptr->background;\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),\n    * however it seems that the code in png_init_read_transformations, which has\n    * been called before this from png_read_update_info->png_read_start_row\n    * sometimes does the gamma transform and cancels the flag.\n    *\n    * TODO: this looks wrong; the info_ptr should end up with a gamma equal to\n    * the screen_gamma value.  The following probably results in weirdness if\n    * the info_ptr is used by the app after the rows have been read.\n    */\n   info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;\n#endif\n\n   if (info_ptr->bit_depth == 16)\n   {\n#  ifdef PNG_READ_16BIT_SUPPORTED\n#     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n         if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)\n            info_ptr->bit_depth = 8;\n#     endif\n\n#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n         if ((png_ptr->transformations & PNG_16_TO_8) != 0)\n            info_ptr->bit_depth = 8;\n#     endif\n\n#  else\n      /* No 16-bit support: force chopping 16-bit input down to 8, in this case\n       * the app program can chose if both APIs are available by setting the\n       * correct scaling to use.\n       */\n#     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n         /* For compatibility with previous versions use the strip method by\n          * default.  This code works because if PNG_SCALE_16_TO_8 is already\n          * set the code below will do that in preference to the chop.\n          */\n         png_ptr->transformations |= PNG_16_TO_8;\n         info_ptr->bit_depth = 8;\n#     else\n\n#        ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n            png_ptr->transformations |= PNG_SCALE_16_TO_8;\n            info_ptr->bit_depth = 8;\n#        else\n\n            CONFIGURATION ERROR: you must enable at least one 16 to 8 method\n#        endif\n#    endif\n#endif /* !READ_16BIT */\n   }\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)\n      info_ptr->color_type = (png_byte)(info_ptr->color_type |\n         PNG_COLOR_MASK_COLOR);\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)\n      info_ptr->color_type = (png_byte)(info_ptr->color_type &\n         ~PNG_COLOR_MASK_COLOR);\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n   if ((png_ptr->transformations & PNG_QUANTIZE) != 0)\n   {\n      if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||\n          (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&\n          png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8)\n      {\n         info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;\n      }\n   }\n#endif\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n   if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&\n       info_ptr->bit_depth == 8 &&\n       info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)\n   {\n      info_ptr->bit_depth = 16;\n   }\n#endif\n\n#ifdef PNG_READ_PACK_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACK) != 0 &&\n       (info_ptr->bit_depth < 8))\n      info_ptr->bit_depth = 8;\n#endif\n\n   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      info_ptr->channels = 1;\n\n   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      info_ptr->channels = 3;\n\n   else\n      info_ptr->channels = 1;\n\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0)\n   {\n      info_ptr->color_type = (png_byte)(info_ptr->color_type &\n         ~PNG_COLOR_MASK_ALPHA);\n      info_ptr->num_trans = 0;\n   }\n#endif\n\n   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      info_ptr->channels++;\n\n#ifdef PNG_READ_FILLER_SUPPORTED\n   /* STRIP_ALPHA and FILLER allowed:  MASK_ALPHA bit stripped above */\n   if ((png_ptr->transformations & PNG_FILLER) != 0 &&\n       (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||\n       info_ptr->color_type == PNG_COLOR_TYPE_GRAY))\n   {\n      info_ptr->channels++;\n      /* If adding a true alpha channel not just filler */\n      if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0)\n         info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;\n   }\n#endif\n\n#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \\\ndefined(PNG_READ_USER_TRANSFORM_SUPPORTED)\n   if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)\n   {\n      if (png_ptr->user_transform_depth != 0)\n         info_ptr->bit_depth = png_ptr->user_transform_depth;\n\n      if (png_ptr->user_transform_channels != 0)\n         info_ptr->channels = png_ptr->user_transform_channels;\n   }\n#endif\n\n   info_ptr->pixel_depth = (png_byte)(info_ptr->channels *\n       info_ptr->bit_depth);\n\n   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);\n\n   /* Adding in 1.5.4: cache the above value in png_struct so that we can later\n    * check in png_rowbytes that the user buffer won't get overwritten.  Note\n    * that the field is not always set - if png_read_update_info isn't called\n    * the application has to either not do any transforms or get the calculation\n    * right itself.\n    */\n   png_ptr->info_rowbytes = info_ptr->rowbytes;\n\n#ifndef PNG_READ_EXPAND_SUPPORTED\n   if (png_ptr != NULL)\n      return;\n#endif\n}\n\n#ifdef PNG_READ_PACK_SUPPORTED\n/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,\n * without changing the actual values.  Thus, if you had a row with\n * a bit depth of 1, you would end up with bytes that only contained\n * the numbers 0 or 1.  If you would rather they contain 0 and 255, use\n * png_do_shift() after this.\n */\nstatic void\npng_do_unpack(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_unpack\");\n\n   if (row_info->bit_depth < 8)\n   {\n      png_uint_32 i;\n      png_uint_32 row_width=row_info->width;\n\n      switch (row_info->bit_depth)\n      {\n         case 1:\n         {\n            png_bytep sp = row + (size_t)((row_width - 1) >> 3);\n            png_bytep dp = row + (size_t)row_width - 1;\n            png_uint_32 shift = 7U - ((row_width + 7U) & 0x07);\n            for (i = 0; i < row_width; i++)\n            {\n               *dp = (png_byte)((*sp >> shift) & 0x01);\n\n               if (shift == 7)\n               {\n                  shift = 0;\n                  sp--;\n               }\n\n               else\n                  shift++;\n\n               dp--;\n            }\n            break;\n         }\n\n         case 2:\n         {\n\n            png_bytep sp = row + (size_t)((row_width - 1) >> 2);\n            png_bytep dp = row + (size_t)row_width - 1;\n            png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1);\n            for (i = 0; i < row_width; i++)\n            {\n               *dp = (png_byte)((*sp >> shift) & 0x03);\n\n               if (shift == 6)\n               {\n                  shift = 0;\n                  sp--;\n               }\n\n               else\n                  shift += 2;\n\n               dp--;\n            }\n            break;\n         }\n\n         case 4:\n         {\n            png_bytep sp = row + (size_t)((row_width - 1) >> 1);\n            png_bytep dp = row + (size_t)row_width - 1;\n            png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2);\n            for (i = 0; i < row_width; i++)\n            {\n               *dp = (png_byte)((*sp >> shift) & 0x0f);\n\n               if (shift == 4)\n               {\n                  shift = 0;\n                  sp--;\n               }\n\n               else\n                  shift = 4;\n\n               dp--;\n            }\n            break;\n         }\n\n         default:\n            break;\n      }\n      row_info->bit_depth = 8;\n      row_info->pixel_depth = (png_byte)(8 * row_info->channels);\n      row_info->rowbytes = row_width * row_info->channels;\n   }\n}\n#endif\n\n#ifdef PNG_READ_SHIFT_SUPPORTED\n/* Reverse the effects of png_do_shift.  This routine merely shifts the\n * pixels back to their significant bits values.  Thus, if you have\n * a row of bit depth 8, but only 5 are significant, this will shift\n * the values back to 0 through 31.\n */\nstatic void\npng_do_unshift(png_row_infop row_info, png_bytep row,\n    png_const_color_8p sig_bits)\n{\n   int color_type;\n\n   png_debug(1, \"in png_do_unshift\");\n\n   /* The palette case has already been handled in the _init routine. */\n   color_type = row_info->color_type;\n\n   if (color_type != PNG_COLOR_TYPE_PALETTE)\n   {\n      int shift[4];\n      int channels = 0;\n      int bit_depth = row_info->bit_depth;\n\n      if ((color_type & PNG_COLOR_MASK_COLOR) != 0)\n      {\n         shift[channels++] = bit_depth - sig_bits->red;\n         shift[channels++] = bit_depth - sig_bits->green;\n         shift[channels++] = bit_depth - sig_bits->blue;\n      }\n\n      else\n      {\n         shift[channels++] = bit_depth - sig_bits->gray;\n      }\n\n      if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      {\n         shift[channels++] = bit_depth - sig_bits->alpha;\n      }\n\n      {\n         int c, have_shift;\n\n         for (c = have_shift = 0; c < channels; ++c)\n         {\n            /* A shift of more than the bit depth is an error condition but it\n             * gets ignored here.\n             */\n            if (shift[c] <= 0 || shift[c] >= bit_depth)\n               shift[c] = 0;\n\n            else\n               have_shift = 1;\n         }\n\n         if (have_shift == 0)\n            return;\n      }\n\n      switch (bit_depth)\n      {\n         default:\n         /* Must be 1bpp gray: should not be here! */\n            /* NOTREACHED */\n            break;\n\n         case 2:\n         /* Must be 2bpp gray */\n         /* assert(channels == 1 && shift[0] == 1) */\n         {\n            png_bytep bp = row;\n            png_bytep bp_end = bp + row_info->rowbytes;\n\n            while (bp < bp_end)\n            {\n               int b = (*bp >> 1) & 0x55;\n               *bp++ = (png_byte)b;\n            }\n            break;\n         }\n\n         case 4:\n         /* Must be 4bpp gray */\n         /* assert(channels == 1) */\n         {\n            png_bytep bp = row;\n            png_bytep bp_end = bp + row_info->rowbytes;\n            int gray_shift = shift[0];\n            int mask =  0xf >> gray_shift;\n\n            mask |= mask << 4;\n\n            while (bp < bp_end)\n            {\n               int b = (*bp >> gray_shift) & mask;\n               *bp++ = (png_byte)b;\n            }\n            break;\n         }\n\n         case 8:\n         /* Single byte components, G, GA, RGB, RGBA */\n         {\n            png_bytep bp = row;\n            png_bytep bp_end = bp + row_info->rowbytes;\n            int channel = 0;\n\n            while (bp < bp_end)\n            {\n               int b = *bp >> shift[channel];\n               if (++channel >= channels)\n                  channel = 0;\n               *bp++ = (png_byte)b;\n            }\n            break;\n         }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n         case 16:\n         /* Double byte components, G, GA, RGB, RGBA */\n         {\n            png_bytep bp = row;\n            png_bytep bp_end = bp + row_info->rowbytes;\n            int channel = 0;\n\n            while (bp < bp_end)\n            {\n               int value = (bp[0] << 8) + bp[1];\n\n               value >>= shift[channel];\n               if (++channel >= channels)\n                  channel = 0;\n               *bp++ = (png_byte)(value >> 8);\n               *bp++ = (png_byte)value;\n            }\n            break;\n         }\n#endif\n      }\n   }\n}\n#endif\n\n#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n/* Scale rows of bit depth 16 down to 8 accurately */\nstatic void\npng_do_scale_16_to_8(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_scale_16_to_8\");\n\n   if (row_info->bit_depth == 16)\n   {\n      png_bytep sp = row; /* source */\n      png_bytep dp = row; /* destination */\n      png_bytep ep = sp + row_info->rowbytes; /* end+1 */\n\n      while (sp < ep)\n      {\n         /* The input is an array of 16-bit components, these must be scaled to\n          * 8 bits each.  For a 16-bit value V the required value (from the PNG\n          * specification) is:\n          *\n          *    (V * 255) / 65535\n          *\n          * This reduces to round(V / 257), or floor((V + 128.5)/257)\n          *\n          * Represent V as the two byte value vhi.vlo.  Make a guess that the\n          * result is the top byte of V, vhi, then the correction to this value\n          * is:\n          *\n          *    error = floor(((V-vhi.vhi) + 128.5) / 257)\n          *          = floor(((vlo-vhi) + 128.5) / 257)\n          *\n          * This can be approximated using integer arithmetic (and a signed\n          * shift):\n          *\n          *    error = (vlo-vhi+128) >> 8;\n          *\n          * The approximate differs from the exact answer only when (vlo-vhi) is\n          * 128; it then gives a correction of +1 when the exact correction is\n          * 0.  This gives 128 errors.  The exact answer (correct for all 16-bit\n          * input values) is:\n          *\n          *    error = (vlo-vhi+128)*65535 >> 24;\n          *\n          * An alternative arithmetic calculation which also gives no errors is:\n          *\n          *    (V * 255 + 32895) >> 16\n          */\n\n         png_int_32 tmp = *sp++; /* must be signed! */\n         tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;\n         *dp++ = (png_byte)tmp;\n      }\n\n      row_info->bit_depth = 8;\n      row_info->pixel_depth = (png_byte)(8 * row_info->channels);\n      row_info->rowbytes = row_info->width * row_info->channels;\n   }\n}\n#endif\n\n#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\nstatic void\n/* Simply discard the low byte.  This was the default behavior prior\n * to libpng-1.5.4.\n */\npng_do_chop(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_chop\");\n\n   if (row_info->bit_depth == 16)\n   {\n      png_bytep sp = row; /* source */\n      png_bytep dp = row; /* destination */\n      png_bytep ep = sp + row_info->rowbytes; /* end+1 */\n\n      while (sp < ep)\n      {\n         *dp++ = *sp;\n         sp += 2; /* skip low byte */\n      }\n\n      row_info->bit_depth = 8;\n      row_info->pixel_depth = (png_byte)(8 * row_info->channels);\n      row_info->rowbytes = row_info->width * row_info->channels;\n   }\n}\n#endif\n\n#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED\nstatic void\npng_do_read_swap_alpha(png_row_infop row_info, png_bytep row)\n{\n   png_uint_32 row_width = row_info->width;\n\n   png_debug(1, \"in png_do_read_swap_alpha\");\n\n   if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n   {\n      /* This converts from RGBA to ARGB */\n      if (row_info->bit_depth == 8)\n      {\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_byte save;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            save = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = save;\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      /* This converts from RRGGBBAA to AARRGGBB */\n      else\n      {\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_byte save[2];\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            save[0] = *(--sp);\n            save[1] = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = save[0];\n            *(--dp) = save[1];\n         }\n      }\n#endif\n   }\n\n   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n   {\n      /* This converts from GA to AG */\n      if (row_info->bit_depth == 8)\n      {\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_byte save;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            save = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = save;\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      /* This converts from GGAA to AAGG */\n      else\n      {\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_byte save[2];\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            save[0] = *(--sp);\n            save[1] = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = save[0];\n            *(--dp) = save[1];\n         }\n      }\n#endif\n   }\n}\n#endif\n\n#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED\nstatic void\npng_do_read_invert_alpha(png_row_infop row_info, png_bytep row)\n{\n   png_uint_32 row_width;\n   png_debug(1, \"in png_do_read_invert_alpha\");\n\n   row_width = row_info->width;\n   if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         /* This inverts the alpha channel in RGBA */\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            *(--dp) = (png_byte)(255 - *(--sp));\n\n/*          This does nothing:\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            We can replace it with:\n*/\n            sp-=3;\n            dp=sp;\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      /* This inverts the alpha channel in RRGGBBAA */\n      else\n      {\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            *(--dp) = (png_byte)(255 - *(--sp));\n            *(--dp) = (png_byte)(255 - *(--sp));\n\n/*          This does nothing:\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n            We can replace it with:\n*/\n            sp-=6;\n            dp=sp;\n         }\n      }\n#endif\n   }\n   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         /* This inverts the alpha channel in GA */\n         png_bytep sp = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            *(--dp) = (png_byte)(255 - *(--sp));\n            *(--dp) = *(--sp);\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      else\n      {\n         /* This inverts the alpha channel in GGAA */\n         png_bytep sp  = row + row_info->rowbytes;\n         png_bytep dp = sp;\n         png_uint_32 i;\n\n         for (i = 0; i < row_width; i++)\n         {\n            *(--dp) = (png_byte)(255 - *(--sp));\n            *(--dp) = (png_byte)(255 - *(--sp));\n/*\n            *(--dp) = *(--sp);\n            *(--dp) = *(--sp);\n*/\n            sp-=2;\n            dp=sp;\n         }\n      }\n#endif\n   }\n}\n#endif\n\n#ifdef PNG_READ_FILLER_SUPPORTED\n/* Add filler channel if we have RGB color */\nstatic void\npng_do_read_filler(png_row_infop row_info, png_bytep row,\n    png_uint_32 filler, png_uint_32 flags)\n{\n   png_uint_32 i;\n   png_uint_32 row_width = row_info->width;\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n   png_byte hi_filler = (png_byte)(filler>>8);\n#endif\n   png_byte lo_filler = (png_byte)filler;\n\n   png_debug(1, \"in png_do_read_filler\");\n\n   if (\n       row_info->color_type == PNG_COLOR_TYPE_GRAY)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         if ((flags & PNG_FLAG_FILLER_AFTER) != 0)\n         {\n            /* This changes the data from G to GX */\n            png_bytep sp = row + (size_t)row_width;\n            png_bytep dp =  sp + (size_t)row_width;\n            for (i = 1; i < row_width; i++)\n            {\n               *(--dp) = lo_filler;\n               *(--dp) = *(--sp);\n            }\n            *(--dp) = lo_filler;\n            row_info->channels = 2;\n            row_info->pixel_depth = 16;\n            row_info->rowbytes = row_width * 2;\n         }\n\n         else\n         {\n            /* This changes the data from G to XG */\n            png_bytep sp = row + (size_t)row_width;\n            png_bytep dp = sp  + (size_t)row_width;\n            for (i = 0; i < row_width; i++)\n            {\n               *(--dp) = *(--sp);\n               *(--dp) = lo_filler;\n            }\n            row_info->channels = 2;\n            row_info->pixel_depth = 16;\n            row_info->rowbytes = row_width * 2;\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      else if (row_info->bit_depth == 16)\n      {\n         if ((flags & PNG_FLAG_FILLER_AFTER) != 0)\n         {\n            /* This changes the data from GG to GGXX */\n            png_bytep sp = row + (size_t)row_width * 2;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 1; i < row_width; i++)\n            {\n               *(--dp) = lo_filler;\n               *(--dp) = hi_filler;\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n            }\n            *(--dp) = lo_filler;\n            *(--dp) = hi_filler;\n            row_info->channels = 2;\n            row_info->pixel_depth = 32;\n            row_info->rowbytes = row_width * 4;\n         }\n\n         else\n         {\n            /* This changes the data from GG to XXGG */\n            png_bytep sp = row + (size_t)row_width * 2;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 0; i < row_width; i++)\n            {\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = lo_filler;\n               *(--dp) = hi_filler;\n            }\n            row_info->channels = 2;\n            row_info->pixel_depth = 32;\n            row_info->rowbytes = row_width * 4;\n         }\n      }\n#endif\n   } /* COLOR_TYPE == GRAY */\n   else if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         if ((flags & PNG_FLAG_FILLER_AFTER) != 0)\n         {\n            /* This changes the data from RGB to RGBX */\n            png_bytep sp = row + (size_t)row_width * 3;\n            png_bytep dp = sp  + (size_t)row_width;\n            for (i = 1; i < row_width; i++)\n            {\n               *(--dp) = lo_filler;\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n            }\n            *(--dp) = lo_filler;\n            row_info->channels = 4;\n            row_info->pixel_depth = 32;\n            row_info->rowbytes = row_width * 4;\n         }\n\n         else\n         {\n            /* This changes the data from RGB to XRGB */\n            png_bytep sp = row + (size_t)row_width * 3;\n            png_bytep dp = sp + (size_t)row_width;\n            for (i = 0; i < row_width; i++)\n            {\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = lo_filler;\n            }\n            row_info->channels = 4;\n            row_info->pixel_depth = 32;\n            row_info->rowbytes = row_width * 4;\n         }\n      }\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n      else if (row_info->bit_depth == 16)\n      {\n         if ((flags & PNG_FLAG_FILLER_AFTER) != 0)\n         {\n            /* This changes the data from RRGGBB to RRGGBBXX */\n            png_bytep sp = row + (size_t)row_width * 6;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 1; i < row_width; i++)\n            {\n               *(--dp) = lo_filler;\n               *(--dp) = hi_filler;\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n            }\n            *(--dp) = lo_filler;\n            *(--dp) = hi_filler;\n            row_info->channels = 4;\n            row_info->pixel_depth = 64;\n            row_info->rowbytes = row_width * 8;\n         }\n\n         else\n         {\n            /* This changes the data from RRGGBB to XXRRGGBB */\n            png_bytep sp = row + (size_t)row_width * 6;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 0; i < row_width; i++)\n            {\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = *(--sp);\n               *(--dp) = lo_filler;\n               *(--dp) = hi_filler;\n            }\n\n            row_info->channels = 4;\n            row_info->pixel_depth = 64;\n            row_info->rowbytes = row_width * 8;\n         }\n      }\n#endif\n   } /* COLOR_TYPE == RGB */\n}\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n/* Expand grayscale files to RGB, with or without alpha */\nstatic void\npng_do_gray_to_rgb(png_row_infop row_info, png_bytep row)\n{\n   png_uint_32 i;\n   png_uint_32 row_width = row_info->width;\n\n   png_debug(1, \"in png_do_gray_to_rgb\");\n\n   if (row_info->bit_depth >= 8 &&\n       (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0)\n   {\n      if (row_info->color_type == PNG_COLOR_TYPE_GRAY)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This changes G to RGB */\n            png_bytep sp = row + (size_t)row_width - 1;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 0; i < row_width; i++)\n            {\n               *(dp--) = *sp;\n               *(dp--) = *sp;\n               *(dp--) = *(sp--);\n            }\n         }\n\n         else\n         {\n            /* This changes GG to RRGGBB */\n            png_bytep sp = row + (size_t)row_width * 2 - 1;\n            png_bytep dp = sp  + (size_t)row_width * 4;\n            for (i = 0; i < row_width; i++)\n            {\n               *(dp--) = *sp;\n               *(dp--) = *(sp - 1);\n               *(dp--) = *sp;\n               *(dp--) = *(sp - 1);\n               *(dp--) = *(sp--);\n               *(dp--) = *(sp--);\n            }\n         }\n      }\n\n      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This changes GA to RGBA */\n            png_bytep sp = row + (size_t)row_width * 2 - 1;\n            png_bytep dp = sp  + (size_t)row_width * 2;\n            for (i = 0; i < row_width; i++)\n            {\n               *(dp--) = *(sp--);\n               *(dp--) = *sp;\n               *(dp--) = *sp;\n               *(dp--) = *(sp--);\n            }\n         }\n\n         else\n         {\n            /* This changes GGAA to RRGGBBAA */\n            png_bytep sp = row + (size_t)row_width * 4 - 1;\n            png_bytep dp = sp  + (size_t)row_width * 4;\n            for (i = 0; i < row_width; i++)\n            {\n               *(dp--) = *(sp--);\n               *(dp--) = *(sp--);\n               *(dp--) = *sp;\n               *(dp--) = *(sp - 1);\n               *(dp--) = *sp;\n               *(dp--) = *(sp - 1);\n               *(dp--) = *(sp--);\n               *(dp--) = *(sp--);\n            }\n         }\n      }\n      row_info->channels = (png_byte)(row_info->channels + 2);\n      row_info->color_type |= PNG_COLOR_MASK_COLOR;\n      row_info->pixel_depth = (png_byte)(row_info->channels *\n          row_info->bit_depth);\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);\n   }\n}\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n/* Reduce RGB files to grayscale, with or without alpha\n * using the equation given in Poynton's ColorFAQ of 1998-01-04 at\n * <http://www.inforamp.net/~poynton/>  (THIS LINK IS DEAD June 2008 but\n * versions dated 1998 through November 2002 have been archived at\n * https://web.archive.org/web/20000816232553/www.inforamp.net/\n * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )\n * Charles Poynton poynton at poynton.com\n *\n *     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B\n *\n *  which can be expressed with integers as\n *\n *     Y = (6969 * R + 23434 * G + 2365 * B)/32768\n *\n * Poynton's current link (as of January 2003 through July 2011):\n * <http://www.poynton.com/notes/colour_and_gamma/>\n * has changed the numbers slightly:\n *\n *     Y = 0.2126*R + 0.7152*G + 0.0722*B\n *\n *  which can be expressed with integers as\n *\n *     Y = (6966 * R + 23436 * G + 2366 * B)/32768\n *\n *  Historically, however, libpng uses numbers derived from the ITU-R Rec 709\n *  end point chromaticities and the D65 white point.  Depending on the\n *  precision used for the D65 white point this produces a variety of different\n *  numbers, however if the four decimal place value used in ITU-R Rec 709 is\n *  used (0.3127,0.3290) the Y calculation would be:\n *\n *     Y = (6968 * R + 23435 * G + 2366 * B)/32768\n *\n *  While this is correct the rounding results in an overflow for white, because\n *  the sum of the rounded coefficients is 32769, not 32768.  Consequently\n *  libpng uses, instead, the closest non-overflowing approximation:\n *\n *     Y = (6968 * R + 23434 * G + 2366 * B)/32768\n *\n *  Starting with libpng-1.5.5, if the image being converted has a cHRM chunk\n *  (including an sRGB chunk) then the chromaticities are used to calculate the\n *  coefficients.  See the chunk handling in pngrutil.c for more information.\n *\n *  In all cases the calculation is to be done in a linear colorspace.  If no\n *  gamma information is available to correct the encoding of the original RGB\n *  values this results in an implicit assumption that the original PNG RGB\n *  values were linear.\n *\n *  Other integer coefficients can be used via png_set_rgb_to_gray().  Because\n *  the API takes just red and green coefficients the blue coefficient is\n *  calculated to make the sum 32768.  This will result in different rounding\n *  to that used above.\n */\nstatic int\npng_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)\n{\n   int rgb_error = 0;\n\n   png_debug(1, \"in png_do_rgb_to_gray\");\n\n   if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 &&\n       (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;\n      png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;\n      png_uint_32 bc = 32768 - rc - gc;\n      png_uint_32 row_width = row_info->width;\n      int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;\n\n      if (row_info->bit_depth == 8)\n      {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n         /* Notice that gamma to/from 1 are not necessarily inverses (if\n          * there is an overall gamma correction).  Prior to 1.5.5 this code\n          * checked the linearized values for equality; this doesn't match\n          * the documentation, the original values must be checked.\n          */\n         if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)\n         {\n            png_bytep sp = row;\n            png_bytep dp = row;\n            png_uint_32 i;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_byte red   = *(sp++);\n               png_byte green = *(sp++);\n               png_byte blue  = *(sp++);\n\n               if (red != green || red != blue)\n               {\n                  red = png_ptr->gamma_to_1[red];\n                  green = png_ptr->gamma_to_1[green];\n                  blue = png_ptr->gamma_to_1[blue];\n\n                  rgb_error |= 1;\n                  *(dp++) = png_ptr->gamma_from_1[\n                      (rc*red + gc*green + bc*blue + 16384)>>15];\n               }\n\n               else\n               {\n                  /* If there is no overall correction the table will not be\n                   * set.\n                   */\n                  if (png_ptr->gamma_table != NULL)\n                     red = png_ptr->gamma_table[red];\n\n                  *(dp++) = red;\n               }\n\n               if (have_alpha != 0)\n                  *(dp++) = *(sp++);\n            }\n         }\n         else\n#endif\n         {\n            png_bytep sp = row;\n            png_bytep dp = row;\n            png_uint_32 i;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_byte red   = *(sp++);\n               png_byte green = *(sp++);\n               png_byte blue  = *(sp++);\n\n               if (red != green || red != blue)\n               {\n                  rgb_error |= 1;\n                  /* NOTE: this is the historical approach which simply\n                   * truncates the results.\n                   */\n                  *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);\n               }\n\n               else\n                  *(dp++) = red;\n\n               if (have_alpha != 0)\n                  *(dp++) = *(sp++);\n            }\n         }\n      }\n\n      else /* RGB bit_depth == 16 */\n      {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n         if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)\n         {\n            png_bytep sp = row;\n            png_bytep dp = row;\n            png_uint_32 i;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_uint_16 red, green, blue, w;\n               png_byte hi,lo;\n\n               hi=*(sp)++; lo=*(sp)++; red   = (png_uint_16)((hi << 8) | (lo));\n               hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));\n               hi=*(sp)++; lo=*(sp)++; blue  = (png_uint_16)((hi << 8) | (lo));\n\n               if (red == green && red == blue)\n               {\n                  if (png_ptr->gamma_16_table != NULL)\n                     w = png_ptr->gamma_16_table[(red & 0xff)\n                         >> png_ptr->gamma_shift][red >> 8];\n\n                  else\n                     w = red;\n               }\n\n               else\n               {\n                  png_uint_16 red_1   = png_ptr->gamma_16_to_1[(red & 0xff)\n                      >> png_ptr->gamma_shift][red>>8];\n                  png_uint_16 green_1 =\n                      png_ptr->gamma_16_to_1[(green & 0xff) >>\n                      png_ptr->gamma_shift][green>>8];\n                  png_uint_16 blue_1  = png_ptr->gamma_16_to_1[(blue & 0xff)\n                      >> png_ptr->gamma_shift][blue>>8];\n                  png_uint_16 gray16  = (png_uint_16)((rc*red_1 + gc*green_1\n                      + bc*blue_1 + 16384)>>15);\n                  w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >>\n                      png_ptr->gamma_shift][gray16 >> 8];\n                  rgb_error |= 1;\n               }\n\n               *(dp++) = (png_byte)((w>>8) & 0xff);\n               *(dp++) = (png_byte)(w & 0xff);\n\n               if (have_alpha != 0)\n               {\n                  *(dp++) = *(sp++);\n                  *(dp++) = *(sp++);\n               }\n            }\n         }\n         else\n#endif\n         {\n            png_bytep sp = row;\n            png_bytep dp = row;\n            png_uint_32 i;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_uint_16 red, green, blue, gray16;\n               png_byte hi,lo;\n\n               hi=*(sp)++; lo=*(sp)++; red   = (png_uint_16)((hi << 8) | (lo));\n               hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));\n               hi=*(sp)++; lo=*(sp)++; blue  = (png_uint_16)((hi << 8) | (lo));\n\n               if (red != green || red != blue)\n                  rgb_error |= 1;\n\n               /* From 1.5.5 in the 16-bit case do the accurate conversion even\n                * in the 'fast' case - this is because this is where the code\n                * ends up when handling linear 16-bit data.\n                */\n               gray16  = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>\n                  15);\n               *(dp++) = (png_byte)((gray16 >> 8) & 0xff);\n               *(dp++) = (png_byte)(gray16 & 0xff);\n\n               if (have_alpha != 0)\n               {\n                  *(dp++) = *(sp++);\n                  *(dp++) = *(sp++);\n               }\n            }\n         }\n      }\n\n      row_info->channels = (png_byte)(row_info->channels - 2);\n      row_info->color_type = (png_byte)(row_info->color_type &\n          ~PNG_COLOR_MASK_COLOR);\n      row_info->pixel_depth = (png_byte)(row_info->channels *\n          row_info->bit_depth);\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);\n   }\n   return rgb_error;\n}\n#endif\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n/* Replace any alpha or transparency with the supplied background color.\n * \"background\" is already in the screen gamma, while \"background_1\" is\n * at a gamma of 1.0.  Paletted files have already been taken care of.\n */\nstatic void\npng_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)\n{\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   png_const_bytep gamma_table = png_ptr->gamma_table;\n   png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;\n   png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;\n   png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;\n   png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;\n   png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;\n   int gamma_shift = png_ptr->gamma_shift;\n   int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;\n#endif\n\n   png_bytep sp;\n   png_uint_32 i;\n   png_uint_32 row_width = row_info->width;\n   int shift;\n\n   png_debug(1, \"in png_do_compose\");\n\n   switch (row_info->color_type)\n   {\n      case PNG_COLOR_TYPE_GRAY:\n      {\n         switch (row_info->bit_depth)\n         {\n            case 1:\n            {\n               sp = row;\n               shift = 7;\n               for (i = 0; i < row_width; i++)\n               {\n                  if ((png_uint_16)((*sp >> shift) & 0x01)\n                     == png_ptr->trans_color.gray)\n                  {\n                     unsigned int tmp = *sp & (0x7f7f >> (7 - shift));\n                     tmp |=\n                         (unsigned int)(png_ptr->background.gray << shift);\n                     *sp = (png_byte)(tmp & 0xff);\n                  }\n\n                  if (shift == 0)\n                  {\n                     shift = 7;\n                     sp++;\n                  }\n\n                  else\n                     shift--;\n               }\n               break;\n            }\n\n            case 2:\n            {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n               if (gamma_table != NULL)\n               {\n                  sp = row;\n                  shift = 6;\n                  for (i = 0; i < row_width; i++)\n                  {\n                     if ((png_uint_16)((*sp >> shift) & 0x03)\n                         == png_ptr->trans_color.gray)\n                     {\n                        unsigned int tmp = *sp & (0x3f3f >> (6 - shift));\n                        tmp |=\n                           (unsigned int)png_ptr->background.gray << shift;\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     else\n                     {\n                        unsigned int p = (*sp >> shift) & 0x03;\n                        unsigned int g = (gamma_table [p | (p << 2) |\n                            (p << 4) | (p << 6)] >> 6) & 0x03;\n                        unsigned int tmp = *sp & (0x3f3f >> (6 - shift));\n                        tmp |= (unsigned int)(g << shift);\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     if (shift == 0)\n                     {\n                        shift = 6;\n                        sp++;\n                     }\n\n                     else\n                        shift -= 2;\n                  }\n               }\n\n               else\n#endif\n               {\n                  sp = row;\n                  shift = 6;\n                  for (i = 0; i < row_width; i++)\n                  {\n                     if ((png_uint_16)((*sp >> shift) & 0x03)\n                         == png_ptr->trans_color.gray)\n                     {\n                        unsigned int tmp = *sp & (0x3f3f >> (6 - shift));\n                        tmp |=\n                            (unsigned int)png_ptr->background.gray << shift;\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     if (shift == 0)\n                     {\n                        shift = 6;\n                        sp++;\n                     }\n\n                     else\n                        shift -= 2;\n                  }\n               }\n               break;\n            }\n\n            case 4:\n            {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n               if (gamma_table != NULL)\n               {\n                  sp = row;\n                  shift = 4;\n                  for (i = 0; i < row_width; i++)\n                  {\n                     if ((png_uint_16)((*sp >> shift) & 0x0f)\n                         == png_ptr->trans_color.gray)\n                     {\n                        unsigned int tmp = *sp & (0x0f0f >> (4 - shift));\n                        tmp |=\n                           (unsigned int)(png_ptr->background.gray << shift);\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     else\n                     {\n                        unsigned int p = (*sp >> shift) & 0x0f;\n                        unsigned int g = (gamma_table[p | (p << 4)] >> 4) &\n                           0x0f;\n                        unsigned int tmp = *sp & (0x0f0f >> (4 - shift));\n                        tmp |= (unsigned int)(g << shift);\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     if (shift == 0)\n                     {\n                        shift = 4;\n                        sp++;\n                     }\n\n                     else\n                        shift -= 4;\n                  }\n               }\n\n               else\n#endif\n               {\n                  sp = row;\n                  shift = 4;\n                  for (i = 0; i < row_width; i++)\n                  {\n                     if ((png_uint_16)((*sp >> shift) & 0x0f)\n                         == png_ptr->trans_color.gray)\n                     {\n                        unsigned int tmp = *sp & (0x0f0f >> (4 - shift));\n                        tmp |=\n                           (unsigned int)(png_ptr->background.gray << shift);\n                        *sp = (png_byte)(tmp & 0xff);\n                     }\n\n                     if (shift == 0)\n                     {\n                        shift = 4;\n                        sp++;\n                     }\n\n                     else\n                        shift -= 4;\n                  }\n               }\n               break;\n            }\n\n            case 8:\n            {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n               if (gamma_table != NULL)\n               {\n                  sp = row;\n                  for (i = 0; i < row_width; i++, sp++)\n                  {\n                     if (*sp == png_ptr->trans_color.gray)\n                        *sp = (png_byte)png_ptr->background.gray;\n\n                     else\n                        *sp = gamma_table[*sp];\n                  }\n               }\n               else\n#endif\n               {\n                  sp = row;\n                  for (i = 0; i < row_width; i++, sp++)\n                  {\n                     if (*sp == png_ptr->trans_color.gray)\n                        *sp = (png_byte)png_ptr->background.gray;\n                  }\n               }\n               break;\n            }\n\n            case 16:\n            {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n               if (gamma_16 != NULL)\n               {\n                  sp = row;\n                  for (i = 0; i < row_width; i++, sp += 2)\n                  {\n                     png_uint_16 v;\n\n                     v = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n\n                     if (v == png_ptr->trans_color.gray)\n                     {\n                        /* Background is already in screen gamma */\n                        *sp = (png_byte)((png_ptr->background.gray >> 8)\n                             & 0xff);\n                        *(sp + 1) = (png_byte)(png_ptr->background.gray\n                             & 0xff);\n                     }\n\n                     else\n                     {\n                        v = gamma_16[*(sp + 1) >> gamma_shift][*sp];\n                        *sp = (png_byte)((v >> 8) & 0xff);\n                        *(sp + 1) = (png_byte)(v & 0xff);\n                     }\n                  }\n               }\n               else\n#endif\n               {\n                  sp = row;\n                  for (i = 0; i < row_width; i++, sp += 2)\n                  {\n                     png_uint_16 v;\n\n                     v = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n\n                     if (v == png_ptr->trans_color.gray)\n                     {\n                        *sp = (png_byte)((png_ptr->background.gray >> 8)\n                             & 0xff);\n                        *(sp + 1) = (png_byte)(png_ptr->background.gray\n                             & 0xff);\n                     }\n                  }\n               }\n               break;\n            }\n\n            default:\n               break;\n         }\n         break;\n      }\n\n      case PNG_COLOR_TYPE_RGB:\n      {\n         if (row_info->bit_depth == 8)\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_table != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 3)\n               {\n                  if (*sp == png_ptr->trans_color.red &&\n                      *(sp + 1) == png_ptr->trans_color.green &&\n                      *(sp + 2) == png_ptr->trans_color.blue)\n                  {\n                     *sp = (png_byte)png_ptr->background.red;\n                     *(sp + 1) = (png_byte)png_ptr->background.green;\n                     *(sp + 2) = (png_byte)png_ptr->background.blue;\n                  }\n\n                  else\n                  {\n                     *sp = gamma_table[*sp];\n                     *(sp + 1) = gamma_table[*(sp + 1)];\n                     *(sp + 2) = gamma_table[*(sp + 2)];\n                  }\n               }\n            }\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 3)\n               {\n                  if (*sp == png_ptr->trans_color.red &&\n                      *(sp + 1) == png_ptr->trans_color.green &&\n                      *(sp + 2) == png_ptr->trans_color.blue)\n                  {\n                     *sp = (png_byte)png_ptr->background.red;\n                     *(sp + 1) = (png_byte)png_ptr->background.green;\n                     *(sp + 2) = (png_byte)png_ptr->background.blue;\n                  }\n               }\n            }\n         }\n         else /* if (row_info->bit_depth == 16) */\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_16 != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 6)\n               {\n                  png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n\n                  png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)\n                      + *(sp + 3));\n\n                  png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)\n                      + *(sp + 5));\n\n                  if (r == png_ptr->trans_color.red &&\n                      g == png_ptr->trans_color.green &&\n                      b == png_ptr->trans_color.blue)\n                  {\n                     /* Background is already in screen gamma */\n                     *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);\n                     *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)\n                             & 0xff);\n                     *(sp + 3) = (png_byte)(png_ptr->background.green\n                             & 0xff);\n                     *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)\n                             & 0xff);\n                     *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);\n                  }\n\n                  else\n                  {\n                     png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];\n                     *sp = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(v & 0xff);\n\n                     v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];\n                     *(sp + 2) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 3) = (png_byte)(v & 0xff);\n\n                     v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];\n                     *(sp + 4) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 5) = (png_byte)(v & 0xff);\n                  }\n               }\n            }\n\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 6)\n               {\n                  png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n\n                  png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)\n                      + *(sp + 3));\n\n                  png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)\n                      + *(sp + 5));\n\n                  if (r == png_ptr->trans_color.red &&\n                      g == png_ptr->trans_color.green &&\n                      b == png_ptr->trans_color.blue)\n                  {\n                     *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);\n                     *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)\n                             & 0xff);\n                     *(sp + 3) = (png_byte)(png_ptr->background.green\n                             & 0xff);\n                     *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)\n                             & 0xff);\n                     *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);\n                  }\n               }\n            }\n         }\n         break;\n      }\n\n      case PNG_COLOR_TYPE_GRAY_ALPHA:\n      {\n         if (row_info->bit_depth == 8)\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_to_1 != NULL && gamma_from_1 != NULL &&\n                gamma_table != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 2)\n               {\n                  png_uint_16 a = *(sp + 1);\n\n                  if (a == 0xff)\n                     *sp = gamma_table[*sp];\n\n                  else if (a == 0)\n                  {\n                     /* Background is already in screen gamma */\n                     *sp = (png_byte)png_ptr->background.gray;\n                  }\n\n                  else\n                  {\n                     png_byte v, w;\n\n                     v = gamma_to_1[*sp];\n                     png_composite(w, v, a, png_ptr->background_1.gray);\n                     if (optimize == 0)\n                        w = gamma_from_1[w];\n                     *sp = w;\n                  }\n               }\n            }\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 2)\n               {\n                  png_byte a = *(sp + 1);\n\n                  if (a == 0)\n                     *sp = (png_byte)png_ptr->background.gray;\n\n                  else if (a < 0xff)\n                     png_composite(*sp, *sp, a, png_ptr->background.gray);\n               }\n            }\n         }\n         else /* if (png_ptr->bit_depth == 16) */\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_16 != NULL && gamma_16_from_1 != NULL &&\n                gamma_16_to_1 != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 4)\n               {\n                  png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)\n                      + *(sp + 3));\n\n                  if (a == (png_uint_16)0xffff)\n                  {\n                     png_uint_16 v;\n\n                     v = gamma_16[*(sp + 1) >> gamma_shift][*sp];\n                     *sp = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(v & 0xff);\n                  }\n\n                  else if (a == 0)\n                  {\n                     /* Background is already in screen gamma */\n                     *sp = (png_byte)((png_ptr->background.gray >> 8)\n                             & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);\n                  }\n\n                  else\n                  {\n                     png_uint_16 g, v, w;\n\n                     g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];\n                     png_composite_16(v, g, a, png_ptr->background_1.gray);\n                     if (optimize != 0)\n                        w = v;\n                     else\n                        w = gamma_16_from_1[(v & 0xff) >>\n                            gamma_shift][v >> 8];\n                     *sp = (png_byte)((w >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(w & 0xff);\n                  }\n               }\n            }\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 4)\n               {\n                  png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)\n                      + *(sp + 3));\n\n                  if (a == 0)\n                  {\n                     *sp = (png_byte)((png_ptr->background.gray >> 8)\n                             & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);\n                  }\n\n                  else if (a < 0xffff)\n                  {\n                     png_uint_16 g, v;\n\n                     g = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n                     png_composite_16(v, g, a, png_ptr->background.gray);\n                     *sp = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(v & 0xff);\n                  }\n               }\n            }\n         }\n         break;\n      }\n\n      case PNG_COLOR_TYPE_RGB_ALPHA:\n      {\n         if (row_info->bit_depth == 8)\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_to_1 != NULL && gamma_from_1 != NULL &&\n                gamma_table != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 4)\n               {\n                  png_byte a = *(sp + 3);\n\n                  if (a == 0xff)\n                  {\n                     *sp = gamma_table[*sp];\n                     *(sp + 1) = gamma_table[*(sp + 1)];\n                     *(sp + 2) = gamma_table[*(sp + 2)];\n                  }\n\n                  else if (a == 0)\n                  {\n                     /* Background is already in screen gamma */\n                     *sp = (png_byte)png_ptr->background.red;\n                     *(sp + 1) = (png_byte)png_ptr->background.green;\n                     *(sp + 2) = (png_byte)png_ptr->background.blue;\n                  }\n\n                  else\n                  {\n                     png_byte v, w;\n\n                     v = gamma_to_1[*sp];\n                     png_composite(w, v, a, png_ptr->background_1.red);\n                     if (optimize == 0) w = gamma_from_1[w];\n                     *sp = w;\n\n                     v = gamma_to_1[*(sp + 1)];\n                     png_composite(w, v, a, png_ptr->background_1.green);\n                     if (optimize == 0) w = gamma_from_1[w];\n                     *(sp + 1) = w;\n\n                     v = gamma_to_1[*(sp + 2)];\n                     png_composite(w, v, a, png_ptr->background_1.blue);\n                     if (optimize == 0) w = gamma_from_1[w];\n                     *(sp + 2) = w;\n                  }\n               }\n            }\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 4)\n               {\n                  png_byte a = *(sp + 3);\n\n                  if (a == 0)\n                  {\n                     *sp = (png_byte)png_ptr->background.red;\n                     *(sp + 1) = (png_byte)png_ptr->background.green;\n                     *(sp + 2) = (png_byte)png_ptr->background.blue;\n                  }\n\n                  else if (a < 0xff)\n                  {\n                     png_composite(*sp, *sp, a, png_ptr->background.red);\n\n                     png_composite(*(sp + 1), *(sp + 1), a,\n                         png_ptr->background.green);\n\n                     png_composite(*(sp + 2), *(sp + 2), a,\n                         png_ptr->background.blue);\n                  }\n               }\n            }\n         }\n         else /* if (row_info->bit_depth == 16) */\n         {\n#ifdef PNG_READ_GAMMA_SUPPORTED\n            if (gamma_16 != NULL && gamma_16_from_1 != NULL &&\n                gamma_16_to_1 != NULL)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 8)\n               {\n                  png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))\n                      << 8) + (png_uint_16)(*(sp + 7)));\n\n                  if (a == (png_uint_16)0xffff)\n                  {\n                     png_uint_16 v;\n\n                     v = gamma_16[*(sp + 1) >> gamma_shift][*sp];\n                     *sp = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(v & 0xff);\n\n                     v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];\n                     *(sp + 2) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 3) = (png_byte)(v & 0xff);\n\n                     v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];\n                     *(sp + 4) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 5) = (png_byte)(v & 0xff);\n                  }\n\n                  else if (a == 0)\n                  {\n                     /* Background is already in screen gamma */\n                     *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);\n                     *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)\n                             & 0xff);\n                     *(sp + 3) = (png_byte)(png_ptr->background.green\n                             & 0xff);\n                     *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)\n                             & 0xff);\n                     *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);\n                  }\n\n                  else\n                  {\n                     png_uint_16 v, w;\n\n                     v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];\n                     png_composite_16(w, v, a, png_ptr->background_1.red);\n                     if (optimize == 0)\n                        w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>\n                             8];\n                     *sp = (png_byte)((w >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(w & 0xff);\n\n                     v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];\n                     png_composite_16(w, v, a, png_ptr->background_1.green);\n                     if (optimize == 0)\n                        w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>\n                             8];\n\n                     *(sp + 2) = (png_byte)((w >> 8) & 0xff);\n                     *(sp + 3) = (png_byte)(w & 0xff);\n\n                     v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];\n                     png_composite_16(w, v, a, png_ptr->background_1.blue);\n                     if (optimize == 0)\n                        w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>\n                             8];\n\n                     *(sp + 4) = (png_byte)((w >> 8) & 0xff);\n                     *(sp + 5) = (png_byte)(w & 0xff);\n                  }\n               }\n            }\n\n            else\n#endif\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++, sp += 8)\n               {\n                  png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))\n                      << 8) + (png_uint_16)(*(sp + 7)));\n\n                  if (a == 0)\n                  {\n                     *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);\n                     *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)\n                             & 0xff);\n                     *(sp + 3) = (png_byte)(png_ptr->background.green\n                             & 0xff);\n                     *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)\n                             & 0xff);\n                     *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);\n                  }\n\n                  else if (a < 0xffff)\n                  {\n                     png_uint_16 v;\n\n                     png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));\n                     png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)\n                         + *(sp + 3));\n                     png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)\n                         + *(sp + 5));\n\n                     png_composite_16(v, r, a, png_ptr->background.red);\n                     *sp = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 1) = (png_byte)(v & 0xff);\n\n                     png_composite_16(v, g, a, png_ptr->background.green);\n                     *(sp + 2) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 3) = (png_byte)(v & 0xff);\n\n                     png_composite_16(v, b, a, png_ptr->background.blue);\n                     *(sp + 4) = (png_byte)((v >> 8) & 0xff);\n                     *(sp + 5) = (png_byte)(v & 0xff);\n                  }\n               }\n            }\n         }\n         break;\n      }\n\n      default:\n         break;\n   }\n}\n#endif /* READ_BACKGROUND || READ_ALPHA_MODE */\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n/* Gamma correct the image, avoiding the alpha channel.  Make sure\n * you do this after you deal with the transparency issue on grayscale\n * or RGB images. If your bit depth is 8, use gamma_table, if it\n * is 16, use gamma_16_table and gamma_shift.  Build these with\n * build_gamma_table().\n */\nstatic void\npng_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)\n{\n   png_const_bytep gamma_table = png_ptr->gamma_table;\n   png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;\n   int gamma_shift = png_ptr->gamma_shift;\n\n   png_bytep sp;\n   png_uint_32 i;\n   png_uint_32 row_width=row_info->width;\n\n   png_debug(1, \"in png_do_gamma\");\n\n   if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||\n       (row_info->bit_depth == 16 && gamma_16_table != NULL)))\n   {\n      switch (row_info->color_type)\n      {\n         case PNG_COLOR_TYPE_RGB:\n         {\n            if (row_info->bit_depth == 8)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  *sp = gamma_table[*sp];\n                  sp++;\n                  *sp = gamma_table[*sp];\n                  sp++;\n                  *sp = gamma_table[*sp];\n                  sp++;\n               }\n            }\n\n            else /* if (row_info->bit_depth == 16) */\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  png_uint_16 v;\n\n                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n\n                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n\n                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n               }\n            }\n            break;\n         }\n\n         case PNG_COLOR_TYPE_RGB_ALPHA:\n         {\n            if (row_info->bit_depth == 8)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  *sp = gamma_table[*sp];\n                  sp++;\n\n                  *sp = gamma_table[*sp];\n                  sp++;\n\n                  *sp = gamma_table[*sp];\n                  sp++;\n\n                  sp++;\n               }\n            }\n\n            else /* if (row_info->bit_depth == 16) */\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n\n                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n\n                  v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 4;\n               }\n            }\n            break;\n         }\n\n         case PNG_COLOR_TYPE_GRAY_ALPHA:\n         {\n            if (row_info->bit_depth == 8)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  *sp = gamma_table[*sp];\n                  sp += 2;\n               }\n            }\n\n            else /* if (row_info->bit_depth == 16) */\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 4;\n               }\n            }\n            break;\n         }\n\n         case PNG_COLOR_TYPE_GRAY:\n         {\n            if (row_info->bit_depth == 2)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i += 4)\n               {\n                  int a = *sp & 0xc0;\n                  int b = *sp & 0x30;\n                  int c = *sp & 0x0c;\n                  int d = *sp & 0x03;\n\n                  *sp = (png_byte)(\n                      ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)])   ) & 0xc0)|\n                      ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|\n                      ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|\n                      ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));\n                  sp++;\n               }\n            }\n\n            if (row_info->bit_depth == 4)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i += 2)\n               {\n                  int msb = *sp & 0xf0;\n                  int lsb = *sp & 0x0f;\n\n                  *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)\n                      | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));\n                  sp++;\n               }\n            }\n\n            else if (row_info->bit_depth == 8)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  *sp = gamma_table[*sp];\n                  sp++;\n               }\n            }\n\n            else if (row_info->bit_depth == 16)\n            {\n               sp = row;\n               for (i = 0; i < row_width; i++)\n               {\n                  png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];\n                  *sp = (png_byte)((v >> 8) & 0xff);\n                  *(sp + 1) = (png_byte)(v & 0xff);\n                  sp += 2;\n               }\n            }\n            break;\n         }\n\n         default:\n            break;\n      }\n   }\n}\n#endif\n\n#ifdef PNG_READ_ALPHA_MODE_SUPPORTED\n/* Encode the alpha channel to the output gamma (the input channel is always\n * linear.)  Called only with color types that have an alpha channel.  Needs the\n * from_1 tables.\n */\nstatic void\npng_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)\n{\n   png_uint_32 row_width = row_info->width;\n\n   png_debug(1, \"in png_do_encode_alpha\");\n\n   if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         png_bytep table = png_ptr->gamma_from_1;\n\n         if (table != NULL)\n         {\n            int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;\n\n            /* The alpha channel is the last component: */\n            row += step - 1;\n\n            for (; row_width > 0; --row_width, row += step)\n               *row = table[*row];\n\n            return;\n         }\n      }\n\n      else if (row_info->bit_depth == 16)\n      {\n         png_uint_16pp table = png_ptr->gamma_16_from_1;\n         int gamma_shift = png_ptr->gamma_shift;\n\n         if (table != NULL)\n         {\n            int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;\n\n            /* The alpha channel is the last component: */\n            row += step - 2;\n\n            for (; row_width > 0; --row_width, row += step)\n            {\n               png_uint_16 v;\n\n               v = table[*(row + 1) >> gamma_shift][*row];\n               *row = (png_byte)((v >> 8) & 0xff);\n               *(row + 1) = (png_byte)(v & 0xff);\n            }\n\n            return;\n         }\n      }\n   }\n\n   /* Only get to here if called with a weird row_info; no harm has been done,\n    * so just issue a warning.\n    */\n   png_warning(png_ptr, \"png_do_encode_alpha: unexpected call\");\n}\n#endif\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n/* Expands a palette row to an RGB or RGBA row depending\n * upon whether you supply trans and num_trans.\n */\nstatic void\npng_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,\n    png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha,\n    int num_trans)\n{\n   int shift, value;\n   png_bytep sp, dp;\n   png_uint_32 i;\n   png_uint_32 row_width=row_info->width;\n\n   png_debug(1, \"in png_do_expand_palette\");\n\n   if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      if (row_info->bit_depth < 8)\n      {\n         switch (row_info->bit_depth)\n         {\n            case 1:\n            {\n               sp = row + (size_t)((row_width - 1) >> 3);\n               dp = row + (size_t)row_width - 1;\n               shift = 7 - (int)((row_width + 7) & 0x07);\n               for (i = 0; i < row_width; i++)\n               {\n                  if ((*sp >> shift) & 0x01)\n                     *dp = 1;\n\n                  else\n                     *dp = 0;\n\n                  if (shift == 7)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift++;\n\n                  dp--;\n               }\n               break;\n            }\n\n            case 2:\n            {\n               sp = row + (size_t)((row_width - 1) >> 2);\n               dp = row + (size_t)row_width - 1;\n               shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);\n               for (i = 0; i < row_width; i++)\n               {\n                  value = (*sp >> shift) & 0x03;\n                  *dp = (png_byte)value;\n                  if (shift == 6)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift += 2;\n\n                  dp--;\n               }\n               break;\n            }\n\n            case 4:\n            {\n               sp = row + (size_t)((row_width - 1) >> 1);\n               dp = row + (size_t)row_width - 1;\n               shift = (int)((row_width & 0x01) << 2);\n               for (i = 0; i < row_width; i++)\n               {\n                  value = (*sp >> shift) & 0x0f;\n                  *dp = (png_byte)value;\n                  if (shift == 4)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift += 4;\n\n                  dp--;\n               }\n               break;\n            }\n\n            default:\n               break;\n         }\n         row_info->bit_depth = 8;\n         row_info->pixel_depth = 8;\n         row_info->rowbytes = row_width;\n      }\n\n      if (row_info->bit_depth == 8)\n      {\n         {\n            if (num_trans > 0)\n            {\n               sp = row + (size_t)row_width - 1;\n               dp = row + ((size_t)row_width << 2) - 1;\n\n               i = 0;\n#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE\n               if (png_ptr->riffled_palette != NULL)\n               {\n                  /* The RGBA optimization works with png_ptr->bit_depth == 8\n                   * but sometimes row_info->bit_depth has been changed to 8.\n                   * In these cases, the palette hasn't been riffled.\n                   */\n                  i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row,\n                      &sp, &dp);\n               }\n#else\n               PNG_UNUSED(png_ptr)\n#endif\n\n               for (; i < row_width; i++)\n               {\n                  if ((int)(*sp) >= num_trans)\n                     *dp-- = 0xff;\n                  else\n                     *dp-- = trans_alpha[*sp];\n                  *dp-- = palette[*sp].blue;\n                  *dp-- = palette[*sp].green;\n                  *dp-- = palette[*sp].red;\n                  sp--;\n               }\n               row_info->bit_depth = 8;\n               row_info->pixel_depth = 32;\n               row_info->rowbytes = row_width * 4;\n               row_info->color_type = 6;\n               row_info->channels = 4;\n            }\n\n            else\n            {\n               sp = row + (size_t)row_width - 1;\n               dp = row + (size_t)(row_width * 3) - 1;\n               i = 0;\n#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE\n               i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,\n                   &sp, &dp);\n#else\n               PNG_UNUSED(png_ptr)\n#endif\n\n               for (; i < row_width; i++)\n               {\n                  *dp-- = palette[*sp].blue;\n                  *dp-- = palette[*sp].green;\n                  *dp-- = palette[*sp].red;\n                  sp--;\n               }\n\n               row_info->bit_depth = 8;\n               row_info->pixel_depth = 24;\n               row_info->rowbytes = row_width * 3;\n               row_info->color_type = 2;\n               row_info->channels = 3;\n            }\n         }\n      }\n   }\n}\n\n/* If the bit depth < 8, it is expanded to 8.  Also, if the already\n * expanded transparency value is supplied, an alpha channel is built.\n */\nstatic void\npng_do_expand(png_row_infop row_info, png_bytep row,\n    png_const_color_16p trans_color)\n{\n   int shift, value;\n   png_bytep sp, dp;\n   png_uint_32 i;\n   png_uint_32 row_width=row_info->width;\n\n   png_debug(1, \"in png_do_expand\");\n\n   if (row_info->color_type == PNG_COLOR_TYPE_GRAY)\n   {\n      unsigned int gray = trans_color != NULL ? trans_color->gray : 0;\n\n      if (row_info->bit_depth < 8)\n      {\n         switch (row_info->bit_depth)\n         {\n            case 1:\n            {\n               gray = (gray & 0x01) * 0xff;\n               sp = row + (size_t)((row_width - 1) >> 3);\n               dp = row + (size_t)row_width - 1;\n               shift = 7 - (int)((row_width + 7) & 0x07);\n               for (i = 0; i < row_width; i++)\n               {\n                  if ((*sp >> shift) & 0x01)\n                     *dp = 0xff;\n\n                  else\n                     *dp = 0;\n\n                  if (shift == 7)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift++;\n\n                  dp--;\n               }\n               break;\n            }\n\n            case 2:\n            {\n               gray = (gray & 0x03) * 0x55;\n               sp = row + (size_t)((row_width - 1) >> 2);\n               dp = row + (size_t)row_width - 1;\n               shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);\n               for (i = 0; i < row_width; i++)\n               {\n                  value = (*sp >> shift) & 0x03;\n                  *dp = (png_byte)(value | (value << 2) | (value << 4) |\n                     (value << 6));\n                  if (shift == 6)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift += 2;\n\n                  dp--;\n               }\n               break;\n            }\n\n            case 4:\n            {\n               gray = (gray & 0x0f) * 0x11;\n               sp = row + (size_t)((row_width - 1) >> 1);\n               dp = row + (size_t)row_width - 1;\n               shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);\n               for (i = 0; i < row_width; i++)\n               {\n                  value = (*sp >> shift) & 0x0f;\n                  *dp = (png_byte)(value | (value << 4));\n                  if (shift == 4)\n                  {\n                     shift = 0;\n                     sp--;\n                  }\n\n                  else\n                     shift = 4;\n\n                  dp--;\n               }\n               break;\n            }\n\n            default:\n               break;\n         }\n\n         row_info->bit_depth = 8;\n         row_info->pixel_depth = 8;\n         row_info->rowbytes = row_width;\n      }\n\n      if (trans_color != NULL)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            gray = gray & 0xff;\n            sp = row + (size_t)row_width - 1;\n            dp = row + ((size_t)row_width << 1) - 1;\n\n            for (i = 0; i < row_width; i++)\n            {\n               if ((*sp & 0xffU) == gray)\n                  *dp-- = 0;\n\n               else\n                  *dp-- = 0xff;\n\n               *dp-- = *sp--;\n            }\n         }\n\n         else if (row_info->bit_depth == 16)\n         {\n            unsigned int gray_high = (gray >> 8) & 0xff;\n            unsigned int gray_low = gray & 0xff;\n            sp = row + row_info->rowbytes - 1;\n            dp = row + (row_info->rowbytes << 1) - 1;\n            for (i = 0; i < row_width; i++)\n            {\n               if ((*(sp - 1) & 0xffU) == gray_high &&\n                   (*(sp) & 0xffU) == gray_low)\n               {\n                  *dp-- = 0;\n                  *dp-- = 0;\n               }\n\n               else\n               {\n                  *dp-- = 0xff;\n                  *dp-- = 0xff;\n               }\n\n               *dp-- = *sp--;\n               *dp-- = *sp--;\n            }\n         }\n\n         row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;\n         row_info->channels = 2;\n         row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);\n         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,\n             row_width);\n      }\n   }\n   else if (row_info->color_type == PNG_COLOR_TYPE_RGB &&\n       trans_color != NULL)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         png_byte red = (png_byte)(trans_color->red & 0xff);\n         png_byte green = (png_byte)(trans_color->green & 0xff);\n         png_byte blue = (png_byte)(trans_color->blue & 0xff);\n         sp = row + (size_t)row_info->rowbytes - 1;\n         dp = row + ((size_t)row_width << 2) - 1;\n         for (i = 0; i < row_width; i++)\n         {\n            if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)\n               *dp-- = 0;\n\n            else\n               *dp-- = 0xff;\n\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n         }\n      }\n      else if (row_info->bit_depth == 16)\n      {\n         png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);\n         png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);\n         png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);\n         png_byte red_low = (png_byte)(trans_color->red & 0xff);\n         png_byte green_low = (png_byte)(trans_color->green & 0xff);\n         png_byte blue_low = (png_byte)(trans_color->blue & 0xff);\n         sp = row + row_info->rowbytes - 1;\n         dp = row + ((size_t)row_width << 3) - 1;\n         for (i = 0; i < row_width; i++)\n         {\n            if (*(sp - 5) == red_high &&\n                *(sp - 4) == red_low &&\n                *(sp - 3) == green_high &&\n                *(sp - 2) == green_low &&\n                *(sp - 1) == blue_high &&\n                *(sp    ) == blue_low)\n            {\n               *dp-- = 0;\n               *dp-- = 0;\n            }\n\n            else\n            {\n               *dp-- = 0xff;\n               *dp-- = 0xff;\n            }\n\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n            *dp-- = *sp--;\n         }\n      }\n      row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;\n      row_info->channels = 4;\n      row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);\n   }\n}\n#endif\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n/* If the bit depth is 8 and the color type is not a palette type expand the\n * whole row to 16 bits.  Has no effect otherwise.\n */\nstatic void\npng_do_expand_16(png_row_infop row_info, png_bytep row)\n{\n   if (row_info->bit_depth == 8 &&\n      row_info->color_type != PNG_COLOR_TYPE_PALETTE)\n   {\n      /* The row have a sequence of bytes containing [0..255] and we need\n       * to turn it into another row containing [0..65535], to do this we\n       * calculate:\n       *\n       *  (input / 255) * 65535\n       *\n       *  Which happens to be exactly input * 257 and this can be achieved\n       *  simply by byte replication in place (copying backwards).\n       */\n      png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */\n      png_byte *dp = sp + row_info->rowbytes;  /* destination, end + 1 */\n      while (dp > sp)\n      {\n         dp[-2] = dp[-1] = *--sp; dp -= 2;\n      }\n\n      row_info->rowbytes *= 2;\n      row_info->bit_depth = 16;\n      row_info->pixel_depth = (png_byte)(row_info->channels * 16);\n   }\n}\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\nstatic void\npng_do_quantize(png_row_infop row_info, png_bytep row,\n    png_const_bytep palette_lookup, png_const_bytep quantize_lookup)\n{\n   png_bytep sp, dp;\n   png_uint_32 i;\n   png_uint_32 row_width=row_info->width;\n\n   png_debug(1, \"in png_do_quantize\");\n\n   if (row_info->bit_depth == 8)\n   {\n      if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)\n      {\n         int r, g, b, p;\n         sp = row;\n         dp = row;\n         for (i = 0; i < row_width; i++)\n         {\n            r = *sp++;\n            g = *sp++;\n            b = *sp++;\n\n            /* This looks real messy, but the compiler will reduce\n             * it down to a reasonable formula.  For example, with\n             * 5 bits per color, we get:\n             * p = (((r >> 3) & 0x1f) << 10) |\n             *    (((g >> 3) & 0x1f) << 5) |\n             *    ((b >> 3) & 0x1f);\n             */\n            p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &\n                ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<\n                (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |\n                (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &\n                ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<\n                (PNG_QUANTIZE_BLUE_BITS)) |\n                ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &\n                ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));\n\n            *dp++ = palette_lookup[p];\n         }\n\n         row_info->color_type = PNG_COLOR_TYPE_PALETTE;\n         row_info->channels = 1;\n         row_info->pixel_depth = row_info->bit_depth;\n         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);\n      }\n\n      else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&\n         palette_lookup != NULL)\n      {\n         int r, g, b, p;\n         sp = row;\n         dp = row;\n         for (i = 0; i < row_width; i++)\n         {\n            r = *sp++;\n            g = *sp++;\n            b = *sp++;\n            sp++;\n\n            p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &\n                ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<\n                (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |\n                (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &\n                ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<\n                (PNG_QUANTIZE_BLUE_BITS)) |\n                ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &\n                ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));\n\n            *dp++ = palette_lookup[p];\n         }\n\n         row_info->color_type = PNG_COLOR_TYPE_PALETTE;\n         row_info->channels = 1;\n         row_info->pixel_depth = row_info->bit_depth;\n         row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);\n      }\n\n      else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&\n         quantize_lookup)\n      {\n         sp = row;\n\n         for (i = 0; i < row_width; i++, sp++)\n         {\n            *sp = quantize_lookup[*sp];\n         }\n      }\n   }\n}\n#endif /* READ_QUANTIZE */\n\n/* Transform the row.  The order of transformations is significant,\n * and is very touchy.  If you add a transformation, take care to\n * decide how it fits in with the other transformations here.\n */\nvoid /* PRIVATE */\npng_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)\n{\n   png_debug(1, \"in png_do_read_transformations\");\n\n   if (png_ptr->row_buf == NULL)\n   {\n      /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this\n       * error is incredibly rare and incredibly easy to debug without this\n       * information.\n       */\n      png_error(png_ptr, \"NULL row buffer\");\n   }\n\n   /* The following is debugging; prior to 1.5.4 the code was never compiled in;\n    * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro\n    * PNG_WARN_UNINITIALIZED_ROW removed.  In 1.6 the new flag is set only for\n    * all transformations, however in practice the ROW_INIT always gets done on\n    * demand, if necessary.\n    */\n   if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&\n       (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)\n   {\n      /* Application has failed to call either png_read_start_image() or\n       * png_read_update_info() after setting transforms that expand pixels.\n       * This check added to libpng-1.2.19 (but not enabled until 1.5.4).\n       */\n      png_error(png_ptr, \"Uninitialized row\");\n   }\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n   if ((png_ptr->transformations & PNG_EXPAND) != 0)\n   {\n      if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE\n         if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8))\n         {\n            if (png_ptr->riffled_palette == NULL)\n            {\n               /* Initialize the accelerated palette expansion. */\n               png_ptr->riffled_palette =\n                   (png_bytep)png_malloc(png_ptr, 256 * 4);\n               png_riffle_palette_neon(png_ptr);\n            }\n         }\n#endif\n         png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1,\n             png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);\n      }\n\n      else\n      {\n         if (png_ptr->num_trans != 0 &&\n             (png_ptr->transformations & PNG_EXPAND_tRNS) != 0)\n            png_do_expand(row_info, png_ptr->row_buf + 1,\n                &(png_ptr->trans_color));\n\n         else\n            png_do_expand(row_info, png_ptr->row_buf + 1, NULL);\n      }\n   }\n#endif\n\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&\n       (png_ptr->transformations & PNG_COMPOSE) == 0 &&\n       (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n       row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))\n      png_do_strip_channel(row_info, png_ptr->row_buf + 1,\n          0 /* at_start == false, because SWAP_ALPHA happens later */);\n#endif\n\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n   if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)\n   {\n      int rgb_error =\n          png_do_rgb_to_gray(png_ptr, row_info,\n              png_ptr->row_buf + 1);\n\n      if (rgb_error != 0)\n      {\n         png_ptr->rgb_to_gray_status=1;\n         if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==\n             PNG_RGB_TO_GRAY_WARN)\n            png_warning(png_ptr, \"png_do_rgb_to_gray found nongray pixel\");\n\n         if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==\n             PNG_RGB_TO_GRAY_ERR)\n            png_error(png_ptr, \"png_do_rgb_to_gray found nongray pixel\");\n      }\n   }\n#endif\n\n/* From Andreas Dilger e-mail to png-implement, 26 March 1998:\n *\n *   In most cases, the \"simple transparency\" should be done prior to doing\n *   gray-to-RGB, or you will have to test 3x as many bytes to check if a\n *   pixel is transparent.  You would also need to make sure that the\n *   transparency information is upgraded to RGB.\n *\n *   To summarize, the current flow is:\n *   - Gray + simple transparency -> compare 1 or 2 gray bytes and composite\n *                                   with background \"in place\" if transparent,\n *                                   convert to RGB if necessary\n *   - Gray + alpha -> composite with gray background and remove alpha bytes,\n *                                   convert to RGB if necessary\n *\n *   To support RGB backgrounds for gray images we need:\n *   - Gray + simple transparency -> convert to RGB + simple transparency,\n *                                   compare 3 or 6 bytes and composite with\n *                                   background \"in place\" if transparent\n *                                   (3x compare/pixel compared to doing\n *                                   composite with gray bkgrnd)\n *   - Gray + alpha -> convert to RGB + alpha, composite with background and\n *                                   remove alpha bytes (3x float\n *                                   operations/pixel compared with composite\n *                                   on gray background)\n *\n *  Greg's change will do this.  The reason it wasn't done before is for\n *  performance, as this increases the per-pixel operations.  If we would check\n *  in advance if the background was gray or RGB, and position the gray-to-RGB\n *  transform appropriately, then it would save a lot of work/time.\n */\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n   /* If gray -> RGB, do so now only if background is non-gray; else do later\n    * for performance reasons\n    */\n   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&\n       (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0)\n      png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);\n#endif\n\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n   if ((png_ptr->transformations & PNG_COMPOSE) != 0)\n      png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   if ((png_ptr->transformations & PNG_GAMMA) != 0 &&\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n      /* Because RGB_TO_GRAY does the gamma transform. */\n      (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 &&\n#endif\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n      /* Because PNG_COMPOSE does the gamma transform if there is something to\n       * do (if there is an alpha channel or transparency.)\n       */\n       !((png_ptr->transformations & PNG_COMPOSE) != 0 &&\n       ((png_ptr->num_trans != 0) ||\n       (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) &&\n#endif\n      /* Because png_init_read_transformations transforms the palette, unless\n       * RGB_TO_GRAY will do the transform.\n       */\n       (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))\n      png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);\n#endif\n\n#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&\n       (png_ptr->transformations & PNG_COMPOSE) != 0 &&\n       (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||\n       row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))\n      png_do_strip_channel(row_info, png_ptr->row_buf + 1,\n          0 /* at_start == false, because SWAP_ALPHA happens later */);\n#endif\n\n#ifdef PNG_READ_ALPHA_MODE_SUPPORTED\n   if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&\n       (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);\n#endif\n\n#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED\n   if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)\n      png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED\n   /* There is no harm in doing both of these because only one has any effect,\n    * by putting the 'scale' option first if the app asks for scale (either by\n    * calling the API or in a TRANSFORM flag) this is what happens.\n    */\n   if ((png_ptr->transformations & PNG_16_TO_8) != 0)\n      png_do_chop(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n   if ((png_ptr->transformations & PNG_QUANTIZE) != 0)\n   {\n      png_do_quantize(row_info, png_ptr->row_buf + 1,\n          png_ptr->palette_lookup, png_ptr->quantize_index);\n\n      if (row_info->rowbytes == 0)\n         png_error(png_ptr, \"png_do_quantize returned rowbytes=0\");\n   }\n#endif /* READ_QUANTIZE */\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n   /* Do the expansion now, after all the arithmetic has been done.  Notice\n    * that previous transformations can handle the PNG_EXPAND_16 flag if this\n    * is efficient (particularly true in the case of gamma correction, where\n    * better accuracy results faster!)\n    */\n   if ((png_ptr->transformations & PNG_EXPAND_16) != 0)\n      png_do_expand_16(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n   /* NOTE: moved here in 1.5.4 (from much later in this list.) */\n   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&\n       (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0)\n      png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_INVERT_SUPPORTED\n   if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)\n      png_do_invert(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)\n      png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_SHIFT_SUPPORTED\n   if ((png_ptr->transformations & PNG_SHIFT) != 0)\n      png_do_unshift(row_info, png_ptr->row_buf + 1,\n          &(png_ptr->shift));\n#endif\n\n#ifdef PNG_READ_PACK_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACK) != 0)\n      png_do_unpack(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   /* Added at libpng-1.5.10 */\n   if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&\n       png_ptr->num_palette_max >= 0)\n      png_do_check_palette_indexes(png_ptr, row_info);\n#endif\n\n#ifdef PNG_READ_BGR_SUPPORTED\n   if ((png_ptr->transformations & PNG_BGR) != 0)\n      png_do_bgr(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_PACKSWAP_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n      png_do_packswap(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_FILLER_SUPPORTED\n   if ((png_ptr->transformations & PNG_FILLER) != 0)\n      png_do_read_filler(row_info, png_ptr->row_buf + 1,\n          (png_uint_32)png_ptr->filler, png_ptr->flags);\n#endif\n\n#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)\n      png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_READ_16BIT_SUPPORTED\n#ifdef PNG_READ_SWAP_SUPPORTED\n   if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)\n      png_do_swap(row_info, png_ptr->row_buf + 1);\n#endif\n#endif\n\n#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED\n   if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)\n   {\n      if (png_ptr->read_user_transform_fn != NULL)\n         (*(png_ptr->read_user_transform_fn)) /* User read transform function */\n             (png_ptr,     /* png_ptr */\n             row_info,     /* row_info: */\n                /*  png_uint_32 width;       width of row */\n                /*  size_t rowbytes;         number of bytes in row */\n                /*  png_byte color_type;     color type of pixels */\n                /*  png_byte bit_depth;      bit depth of samples */\n                /*  png_byte channels;       number of channels (1-4) */\n                /*  png_byte pixel_depth;    bits per pixel (depth*channels) */\n             png_ptr->row_buf + 1);    /* start of pixel data for row */\n#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED\n      if (png_ptr->user_transform_depth != 0)\n         row_info->bit_depth = png_ptr->user_transform_depth;\n\n      if (png_ptr->user_transform_channels != 0)\n         row_info->channels = png_ptr->user_transform_channels;\n#endif\n      row_info->pixel_depth = (png_byte)(row_info->bit_depth *\n          row_info->channels);\n\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);\n   }\n#endif\n}\n\n#endif /* READ_TRANSFORMS */\n#endif /* READ */\n"
  },
  {
    "path": "dlib/external/libpng/pngrutil.c",
    "content": "\n/* pngrutil.c - utilities to read a PNG file\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file contains routines that are only called from within\n * libpng itself during the course of reading an image.\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_READ_SUPPORTED\n\npng_uint_32 PNGAPI\npng_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)\n{\n   png_uint_32 uval = png_get_uint_32(buf);\n\n   if (uval > PNG_UINT_31_MAX)\n      png_error(png_ptr, \"PNG unsigned integer out of range\");\n\n   return (uval);\n}\n\n#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)\n/* The following is a variation on the above for use with the fixed\n * point values used for gAMA and cHRM.  Instead of png_error it\n * issues a warning and returns (-1) - an invalid value because both\n * gAMA and cHRM use *unsigned* integers for fixed point values.\n */\n#define PNG_FIXED_ERROR (-1)\n\nstatic png_fixed_point /* PRIVATE */\npng_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)\n{\n   png_uint_32 uval = png_get_uint_32(buf);\n\n   if (uval <= PNG_UINT_31_MAX)\n      return (png_fixed_point)uval; /* known to be in range */\n\n   /* The caller can turn off the warning by passing NULL. */\n   if (png_ptr != NULL)\n      png_warning(png_ptr, \"PNG fixed point integer out of range\");\n\n   return PNG_FIXED_ERROR;\n}\n#endif\n\n#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED\n/* NOTE: the read macros will obscure these definitions, so that if\n * PNG_USE_READ_MACROS is set the library will not use them internally,\n * but the APIs will still be available externally.\n *\n * The parentheses around \"PNGAPI function_name\" in the following three\n * functions are necessary because they allow the macros to co-exist with\n * these (unused but exported) functions.\n */\n\n/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */\npng_uint_32 (PNGAPI\npng_get_uint_32)(png_const_bytep buf)\n{\n   png_uint_32 uval =\n       ((png_uint_32)(*(buf    )) << 24) +\n       ((png_uint_32)(*(buf + 1)) << 16) +\n       ((png_uint_32)(*(buf + 2)) <<  8) +\n       ((png_uint_32)(*(buf + 3))      ) ;\n\n   return uval;\n}\n\n/* Grab a signed 32-bit integer from a buffer in big-endian format.  The\n * data is stored in the PNG file in two's complement format and there\n * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore\n * the following code does a two's complement to native conversion.\n */\npng_int_32 (PNGAPI\npng_get_int_32)(png_const_bytep buf)\n{\n   png_uint_32 uval = png_get_uint_32(buf);\n   if ((uval & 0x80000000) == 0) /* non-negative */\n      return (png_int_32)uval;\n\n   uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */\n   if ((uval & 0x80000000) == 0) /* no overflow */\n      return -(png_int_32)uval;\n   /* The following has to be safe; this function only gets called on PNG data\n    * and if we get here that data is invalid.  0 is the most safe value and\n    * if not then an attacker would surely just generate a PNG with 0 instead.\n    */\n   return 0;\n}\n\n/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */\npng_uint_16 (PNGAPI\npng_get_uint_16)(png_const_bytep buf)\n{\n   /* ANSI-C requires an int value to accommodate at least 16 bits so this\n    * works and allows the compiler not to worry about possible narrowing\n    * on 32-bit systems.  (Pre-ANSI systems did not make integers smaller\n    * than 16 bits either.)\n    */\n   unsigned int val =\n       ((unsigned int)(*buf) << 8) +\n       ((unsigned int)(*(buf + 1)));\n\n   return (png_uint_16)val;\n}\n\n#endif /* READ_INT_FUNCTIONS */\n\n/* Read and check the PNG file signature */\nvoid /* PRIVATE */\npng_read_sig(png_structrp png_ptr, png_inforp info_ptr)\n{\n   size_t num_checked, num_to_check;\n\n   /* Exit if the user application does not expect a signature. */\n   if (png_ptr->sig_bytes >= 8)\n      return;\n\n   num_checked = png_ptr->sig_bytes;\n   num_to_check = 8 - num_checked;\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;\n#endif\n\n   /* The signature must be serialized in a single I/O call. */\n   png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);\n   png_ptr->sig_bytes = 8;\n\n   if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)\n   {\n      if (num_checked < 4 &&\n          png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))\n         png_error(png_ptr, \"Not a PNG file\");\n      else\n         png_error(png_ptr, \"PNG file corrupted by ASCII conversion\");\n   }\n   if (num_checked < 3)\n      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;\n}\n\n/* Read the chunk header (length + type name).\n * Put the type name into png_ptr->chunk_name, and return the length.\n */\npng_uint_32 /* PRIVATE */\npng_read_chunk_header(png_structrp png_ptr)\n{\n   png_byte buf[8];\n   png_uint_32 length;\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;\n#endif\n\n   /* Read the length and the chunk name.\n    * This must be performed in a single I/O call.\n    */\n   png_read_data(png_ptr, buf, 8);\n   length = png_get_uint_31(png_ptr, buf);\n\n   /* Put the chunk name into png_ptr->chunk_name. */\n   png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);\n\n   png_debug2(0, \"Reading %lx chunk, length = %lu\",\n       (unsigned long)png_ptr->chunk_name, (unsigned long)length);\n\n   /* Reset the crc and run it over the chunk name. */\n   png_reset_crc(png_ptr);\n   png_calculate_crc(png_ptr, buf + 4, 4);\n\n   /* Check to see if chunk name is valid. */\n   png_check_chunk_name(png_ptr, png_ptr->chunk_name);\n\n   /* Check for too-large chunk length */\n   png_check_chunk_length(png_ptr, length);\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;\n#endif\n\n   return length;\n}\n\n/* Read data, and (optionally) run it through the CRC. */\nvoid /* PRIVATE */\npng_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_read_data(png_ptr, buf, length);\n   png_calculate_crc(png_ptr, buf, length);\n}\n\n/* Optionally skip data and then check the CRC.  Depending on whether we\n * are reading an ancillary or critical chunk, and how the program has set\n * things up, we may calculate the CRC on the data and print a message.\n * Returns '1' if there was a CRC error, '0' otherwise.\n */\nint /* PRIVATE */\npng_crc_finish(png_structrp png_ptr, png_uint_32 skip)\n{\n   /* The size of the local buffer for inflate is a good guess as to a\n    * reasonable size to use for buffering reads from the application.\n    */\n   while (skip > 0)\n   {\n      png_uint_32 len;\n      png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];\n\n      len = (sizeof tmpbuf);\n      if (len > skip)\n         len = skip;\n      skip -= len;\n\n      png_crc_read(png_ptr, tmpbuf, len);\n   }\n\n   if (png_crc_error(png_ptr) != 0)\n   {\n      if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?\n          (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 :\n          (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0)\n      {\n         png_chunk_warning(png_ptr, \"CRC error\");\n      }\n\n      else\n         png_chunk_error(png_ptr, \"CRC error\");\n\n      return (1);\n   }\n\n   return (0);\n}\n\n/* Compare the CRC stored in the PNG file with that calculated by libpng from\n * the data it has read thus far.\n */\nint /* PRIVATE */\npng_crc_error(png_structrp png_ptr)\n{\n   png_byte crc_bytes[4];\n   png_uint_32 crc;\n   int need_crc = 1;\n\n   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)\n   {\n      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==\n          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))\n         need_crc = 0;\n   }\n\n   else /* critical */\n   {\n      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)\n         need_crc = 0;\n   }\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;\n#endif\n\n   /* The chunk CRC must be serialized in a single I/O call. */\n   png_read_data(png_ptr, crc_bytes, 4);\n\n   if (need_crc != 0)\n   {\n      crc = png_get_uint_32(crc_bytes);\n      return ((int)(crc != png_ptr->crc));\n   }\n\n   else\n      return (0);\n}\n\n#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\\\n    defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\\\n    defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\\\n    defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED)\n/* Manage the read buffer; this simply reallocates the buffer if it is not small\n * enough (or if it is not allocated).  The routine returns a pointer to the\n * buffer; if an error occurs and 'warn' is set the routine returns NULL, else\n * it will call png_error (via png_malloc) on failure.  (warn == 2 means\n * 'silent').\n */\nstatic png_bytep\npng_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)\n{\n   png_bytep buffer = png_ptr->read_buffer;\n\n   if (buffer != NULL && new_size > png_ptr->read_buffer_size)\n   {\n      png_ptr->read_buffer = NULL;\n      png_ptr->read_buffer = NULL;\n      png_ptr->read_buffer_size = 0;\n      png_free(png_ptr, buffer);\n      buffer = NULL;\n   }\n\n   if (buffer == NULL)\n   {\n      buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size));\n\n      if (buffer != NULL)\n      {\n         memset(buffer, 0, new_size); /* just in case */\n         png_ptr->read_buffer = buffer;\n         png_ptr->read_buffer_size = new_size;\n      }\n\n      else if (warn < 2) /* else silent */\n      {\n         if (warn != 0)\n             png_chunk_warning(png_ptr, \"insufficient memory to read chunk\");\n\n         else\n             png_chunk_error(png_ptr, \"insufficient memory to read chunk\");\n      }\n   }\n\n   return buffer;\n}\n#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */\n\n/* png_inflate_claim: claim the zstream for some nefarious purpose that involves\n * decompression.  Returns Z_OK on success, else a zlib error code.  It checks\n * the owner but, in final release builds, just issues a warning if some other\n * chunk apparently owns the stream.  Prior to release it does a png_error.\n */\nstatic int\npng_inflate_claim(png_structrp png_ptr, png_uint_32 owner)\n{\n   if (png_ptr->zowner != 0)\n   {\n      char msg[64];\n\n      PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner);\n      /* So the message that results is \"<chunk> using zstream\"; this is an\n       * internal error, but is very useful for debugging.  i18n requirements\n       * are minimal.\n       */\n      (void)png_safecat(msg, (sizeof msg), 4, \" using zstream\");\n#if PNG_RELEASE_BUILD\n      png_chunk_warning(png_ptr, msg);\n      png_ptr->zowner = 0;\n#else\n      png_chunk_error(png_ptr, msg);\n#endif\n   }\n\n   /* Implementation note: unlike 'png_deflate_claim' this internal function\n    * does not take the size of the data as an argument.  Some efficiency could\n    * be gained by using this when it is known *if* the zlib stream itself does\n    * not record the number; however, this is an illusion: the original writer\n    * of the PNG may have selected a lower window size, and we really must\n    * follow that because, for systems with with limited capabilities, we\n    * would otherwise reject the application's attempts to use a smaller window\n    * size (zlib doesn't have an interface to say \"this or lower\"!).\n    *\n    * inflateReset2 was added to zlib 1.2.4; before this the window could not be\n    * reset, therefore it is necessary to always allocate the maximum window\n    * size with earlier zlibs just in case later compressed chunks need it.\n    */\n   {\n      int ret; /* zlib return code */\n#if ZLIB_VERNUM >= 0x1240\n      int window_bits = 0;\n\n# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW)\n      if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==\n          PNG_OPTION_ON)\n      {\n         window_bits = 15;\n         png_ptr->zstream_start = 0; /* fixed window size */\n      }\n\n      else\n      {\n         png_ptr->zstream_start = 1;\n      }\n# endif\n\n#endif /* ZLIB_VERNUM >= 0x1240 */\n\n      /* Set this for safety, just in case the previous owner left pointers to\n       * memory allocations.\n       */\n      png_ptr->zstream.next_in = NULL;\n      png_ptr->zstream.avail_in = 0;\n      png_ptr->zstream.next_out = NULL;\n      png_ptr->zstream.avail_out = 0;\n\n      if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)\n      {\n#if ZLIB_VERNUM >= 0x1240\n         ret = inflateReset2(&png_ptr->zstream, window_bits);\n#else\n         ret = inflateReset(&png_ptr->zstream);\n#endif\n      }\n\n      else\n      {\n#if ZLIB_VERNUM >= 0x1240\n         ret = inflateInit2(&png_ptr->zstream, window_bits);\n#else\n         ret = inflateInit(&png_ptr->zstream);\n#endif\n\n         if (ret == Z_OK)\n            png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;\n      }\n\n#if ZLIB_VERNUM >= 0x1290 && \\\n   defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_IGNORE_ADLER32)\n      if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON)\n         /* Turn off validation of the ADLER32 checksum in IDAT chunks */\n         ret = inflateValidate(&png_ptr->zstream, 0);\n#endif\n\n      if (ret == Z_OK)\n         png_ptr->zowner = owner;\n\n      else\n         png_zstream_error(png_ptr, ret);\n\n      return ret;\n   }\n\n#ifdef window_bits\n# undef window_bits\n#endif\n}\n\n#if ZLIB_VERNUM >= 0x1240\n/* Handle the start of the inflate stream if we called inflateInit2(strm,0);\n * in this case some zlib versions skip validation of the CINFO field and, in\n * certain circumstances, libpng may end up displaying an invalid image, in\n * contrast to implementations that call zlib in the normal way (e.g. libpng\n * 1.5).\n */\nint /* PRIVATE */\npng_zlib_inflate(png_structrp png_ptr, int flush)\n{\n   if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0)\n   {\n      if ((*png_ptr->zstream.next_in >> 4) > 7)\n      {\n         png_ptr->zstream.msg = \"invalid window size (libpng)\";\n         return Z_DATA_ERROR;\n      }\n\n      png_ptr->zstream_start = 0;\n   }\n\n   return inflate(&png_ptr->zstream, flush);\n}\n#endif /* Zlib >= 1.2.4 */\n\n#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED\n#if defined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_SUPPORTED)\n/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to\n * allow the caller to do multiple calls if required.  If the 'finish' flag is\n * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must\n * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and\n * Z_OK or Z_STREAM_END will be returned on success.\n *\n * The input and output sizes are updated to the actual amounts of data consumed\n * or written, not the amount available (as in a z_stream).  The data pointers\n * are not changed, so the next input is (data+input_size) and the next\n * available output is (output+output_size).\n */\nstatic int\npng_inflate(png_structrp png_ptr, png_uint_32 owner, int finish,\n    /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr,\n    /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr)\n{\n   if (png_ptr->zowner == owner) /* Else not claimed */\n   {\n      int ret;\n      png_alloc_size_t avail_out = *output_size_ptr;\n      png_uint_32 avail_in = *input_size_ptr;\n\n      /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it\n       * can't even necessarily handle 65536 bytes) because the type uInt is\n       * \"16 bits or more\".  Consequently it is necessary to chunk the input to\n       * zlib.  This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the\n       * maximum value that can be stored in a uInt.)  It is possible to set\n       * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have\n       * a performance advantage, because it reduces the amount of data accessed\n       * at each step and that may give the OS more time to page it in.\n       */\n      png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);\n      /* avail_in and avail_out are set below from 'size' */\n      png_ptr->zstream.avail_in = 0;\n      png_ptr->zstream.avail_out = 0;\n\n      /* Read directly into the output if it is available (this is set to\n       * a local buffer below if output is NULL).\n       */\n      if (output != NULL)\n         png_ptr->zstream.next_out = output;\n\n      do\n      {\n         uInt avail;\n         Byte local_buffer[PNG_INFLATE_BUF_SIZE];\n\n         /* zlib INPUT BUFFER */\n         /* The setting of 'avail_in' used to be outside the loop; by setting it\n          * inside it is possible to chunk the input to zlib and simply rely on\n          * zlib to advance the 'next_in' pointer.  This allows arbitrary\n          * amounts of data to be passed through zlib at the unavoidable cost of\n          * requiring a window save (memcpy of up to 32768 output bytes)\n          * every ZLIB_IO_MAX input bytes.\n          */\n         avail_in += png_ptr->zstream.avail_in; /* not consumed last time */\n\n         avail = ZLIB_IO_MAX;\n\n         if (avail_in < avail)\n            avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */\n\n         avail_in -= avail;\n         png_ptr->zstream.avail_in = avail;\n\n         /* zlib OUTPUT BUFFER */\n         avail_out += png_ptr->zstream.avail_out; /* not written last time */\n\n         avail = ZLIB_IO_MAX; /* maximum zlib can process */\n\n         if (output == NULL)\n         {\n            /* Reset the output buffer each time round if output is NULL and\n             * make available the full buffer, up to 'remaining_space'\n             */\n            png_ptr->zstream.next_out = local_buffer;\n            if ((sizeof local_buffer) < avail)\n               avail = (sizeof local_buffer);\n         }\n\n         if (avail_out < avail)\n            avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */\n\n         png_ptr->zstream.avail_out = avail;\n         avail_out -= avail;\n\n         /* zlib inflate call */\n         /* In fact 'avail_out' may be 0 at this point, that happens at the end\n          * of the read when the final LZ end code was not passed at the end of\n          * the previous chunk of input data.  Tell zlib if we have reached the\n          * end of the output buffer.\n          */\n         ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH :\n             (finish ? Z_FINISH : Z_SYNC_FLUSH));\n      } while (ret == Z_OK);\n\n      /* For safety kill the local buffer pointer now */\n      if (output == NULL)\n         png_ptr->zstream.next_out = NULL;\n\n      /* Claw back the 'size' and 'remaining_space' byte counts. */\n      avail_in += png_ptr->zstream.avail_in;\n      avail_out += png_ptr->zstream.avail_out;\n\n      /* Update the input and output sizes; the updated values are the amount\n       * consumed or written, effectively the inverse of what zlib uses.\n       */\n      if (avail_out > 0)\n         *output_size_ptr -= avail_out;\n\n      if (avail_in > 0)\n         *input_size_ptr -= avail_in;\n\n      /* Ensure png_ptr->zstream.msg is set (even in the success case!) */\n      png_zstream_error(png_ptr, ret);\n      return ret;\n   }\n\n   else\n   {\n      /* This is a bad internal error.  The recovery assigns to the zstream msg\n       * pointer, which is not owned by the caller, but this is safe; it's only\n       * used on errors!\n       */\n      png_ptr->zstream.msg = PNGZ_MSG_CAST(\"zstream unclaimed\");\n      return Z_STREAM_ERROR;\n   }\n}\n\n/*\n * Decompress trailing data in a chunk.  The assumption is that read_buffer\n * points at an allocated area holding the contents of a chunk with a\n * trailing compressed part.  What we get back is an allocated area\n * holding the original prefix part and an uncompressed version of the\n * trailing part (the malloc area passed in is freed).\n */\nstatic int\npng_decompress_chunk(png_structrp png_ptr,\n    png_uint_32 chunklength, png_uint_32 prefix_size,\n    png_alloc_size_t *newlength /* must be initialized to the maximum! */,\n    int terminate /*add a '\\0' to the end of the uncompressed data*/)\n{\n   /* TODO: implement different limits for different types of chunk.\n    *\n    * The caller supplies *newlength set to the maximum length of the\n    * uncompressed data, but this routine allocates space for the prefix and\n    * maybe a '\\0' terminator too.  We have to assume that 'prefix_size' is\n    * limited only by the maximum chunk size.\n    */\n   png_alloc_size_t limit = PNG_SIZE_MAX;\n\n# ifdef PNG_SET_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_malloc_max > 0 &&\n       png_ptr->user_chunk_malloc_max < limit)\n      limit = png_ptr->user_chunk_malloc_max;\n# elif PNG_USER_CHUNK_MALLOC_MAX > 0\n   if (PNG_USER_CHUNK_MALLOC_MAX < limit)\n      limit = PNG_USER_CHUNK_MALLOC_MAX;\n# endif\n\n   if (limit >= prefix_size + (terminate != 0))\n   {\n      int ret;\n\n      limit -= prefix_size + (terminate != 0);\n\n      if (limit < *newlength)\n         *newlength = limit;\n\n      /* Now try to claim the stream. */\n      ret = png_inflate_claim(png_ptr, png_ptr->chunk_name);\n\n      if (ret == Z_OK)\n      {\n         png_uint_32 lzsize = chunklength - prefix_size;\n\n         ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,\n             /* input: */ png_ptr->read_buffer + prefix_size, &lzsize,\n             /* output: */ NULL, newlength);\n\n         if (ret == Z_STREAM_END)\n         {\n            /* Use 'inflateReset' here, not 'inflateReset2' because this\n             * preserves the previously decided window size (otherwise it would\n             * be necessary to store the previous window size.)  In practice\n             * this doesn't matter anyway, because png_inflate will call inflate\n             * with Z_FINISH in almost all cases, so the window will not be\n             * maintained.\n             */\n            if (inflateReset(&png_ptr->zstream) == Z_OK)\n            {\n               /* Because of the limit checks above we know that the new,\n                * expanded, size will fit in a size_t (let alone an\n                * png_alloc_size_t).  Use png_malloc_base here to avoid an\n                * extra OOM message.\n                */\n               png_alloc_size_t new_size = *newlength;\n               png_alloc_size_t buffer_size = prefix_size + new_size +\n                   (terminate != 0);\n               png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr,\n                   buffer_size));\n\n               if (text != NULL)\n               {\n                  memset(text, 0, buffer_size);\n\n                  ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,\n                      png_ptr->read_buffer + prefix_size, &lzsize,\n                      text + prefix_size, newlength);\n\n                  if (ret == Z_STREAM_END)\n                  {\n                     if (new_size == *newlength)\n                     {\n                        if (terminate != 0)\n                           text[prefix_size + *newlength] = 0;\n\n                        if (prefix_size > 0)\n                           memcpy(text, png_ptr->read_buffer, prefix_size);\n\n                        {\n                           png_bytep old_ptr = png_ptr->read_buffer;\n\n                           png_ptr->read_buffer = text;\n                           png_ptr->read_buffer_size = buffer_size;\n                           text = old_ptr; /* freed below */\n                        }\n                     }\n\n                     else\n                     {\n                        /* The size changed on the second read, there can be no\n                         * guarantee that anything is correct at this point.\n                         * The 'msg' pointer has been set to \"unexpected end of\n                         * LZ stream\", which is fine, but return an error code\n                         * that the caller won't accept.\n                         */\n                        ret = PNG_UNEXPECTED_ZLIB_RETURN;\n                     }\n                  }\n\n                  else if (ret == Z_OK)\n                     ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */\n\n                  /* Free the text pointer (this is the old read_buffer on\n                   * success)\n                   */\n                  png_free(png_ptr, text);\n\n                  /* This really is very benign, but it's still an error because\n                   * the extra space may otherwise be used as a Trojan Horse.\n                   */\n                  if (ret == Z_STREAM_END &&\n                      chunklength - prefix_size != lzsize)\n                     png_chunk_benign_error(png_ptr, \"extra compressed data\");\n               }\n\n               else\n               {\n                  /* Out of memory allocating the buffer */\n                  ret = Z_MEM_ERROR;\n                  png_zstream_error(png_ptr, Z_MEM_ERROR);\n               }\n            }\n\n            else\n            {\n               /* inflateReset failed, store the error message */\n               png_zstream_error(png_ptr, ret);\n               ret = PNG_UNEXPECTED_ZLIB_RETURN;\n            }\n         }\n\n         else if (ret == Z_OK)\n            ret = PNG_UNEXPECTED_ZLIB_RETURN;\n\n         /* Release the claimed stream */\n         png_ptr->zowner = 0;\n      }\n\n      else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */\n         ret = PNG_UNEXPECTED_ZLIB_RETURN;\n\n      return ret;\n   }\n\n   else\n   {\n      /* Application/configuration limits exceeded */\n      png_zstream_error(png_ptr, Z_MEM_ERROR);\n      return Z_MEM_ERROR;\n   }\n}\n#endif /* READ_zTXt || READ_iTXt */\n#endif /* READ_COMPRESSED_TEXT */\n\n#ifdef PNG_READ_iCCP_SUPPORTED\n/* Perform a partial read and decompress, producing 'avail_out' bytes and\n * reading from the current chunk as required.\n */\nstatic int\npng_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,\n    png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size,\n    int finish)\n{\n   if (png_ptr->zowner == png_ptr->chunk_name)\n   {\n      int ret;\n\n      /* next_in and avail_in must have been initialized by the caller. */\n      png_ptr->zstream.next_out = next_out;\n      png_ptr->zstream.avail_out = 0; /* set in the loop */\n\n      do\n      {\n         if (png_ptr->zstream.avail_in == 0)\n         {\n            if (read_size > *chunk_bytes)\n               read_size = (uInt)*chunk_bytes;\n            *chunk_bytes -= read_size;\n\n            if (read_size > 0)\n               png_crc_read(png_ptr, read_buffer, read_size);\n\n            png_ptr->zstream.next_in = read_buffer;\n            png_ptr->zstream.avail_in = read_size;\n         }\n\n         if (png_ptr->zstream.avail_out == 0)\n         {\n            uInt avail = ZLIB_IO_MAX;\n            if (avail > *out_size)\n               avail = (uInt)*out_size;\n            *out_size -= avail;\n\n            png_ptr->zstream.avail_out = avail;\n         }\n\n         /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all\n          * the available output is produced; this allows reading of truncated\n          * streams.\n          */\n         ret = PNG_INFLATE(png_ptr, *chunk_bytes > 0 ?\n             Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH));\n      }\n      while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0));\n\n      *out_size += png_ptr->zstream.avail_out;\n      png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */\n\n      /* Ensure the error message pointer is always set: */\n      png_zstream_error(png_ptr, ret);\n      return ret;\n   }\n\n   else\n   {\n      png_ptr->zstream.msg = PNGZ_MSG_CAST(\"zstream unclaimed\");\n      return Z_STREAM_ERROR;\n   }\n}\n#endif /* READ_iCCP */\n\n/* Read and check the IDHR chunk */\n\nvoid /* PRIVATE */\npng_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte buf[13];\n   png_uint_32 width, height;\n   int bit_depth, color_type, compression_type, filter_type;\n   int interlace_type;\n\n   png_debug(1, \"in png_handle_IHDR\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)\n      png_chunk_error(png_ptr, \"out of place\");\n\n   /* Check the length */\n   if (length != 13)\n      png_chunk_error(png_ptr, \"invalid\");\n\n   png_ptr->mode |= PNG_HAVE_IHDR;\n\n   png_crc_read(png_ptr, buf, 13);\n   png_crc_finish(png_ptr, 0);\n\n   width = png_get_uint_31(png_ptr, buf);\n   height = png_get_uint_31(png_ptr, buf + 4);\n   bit_depth = buf[8];\n   color_type = buf[9];\n   compression_type = buf[10];\n   filter_type = buf[11];\n   interlace_type = buf[12];\n\n   /* Set internal variables */\n   png_ptr->width = width;\n   png_ptr->height = height;\n   png_ptr->bit_depth = (png_byte)bit_depth;\n   png_ptr->interlaced = (png_byte)interlace_type;\n   png_ptr->color_type = (png_byte)color_type;\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   png_ptr->filter_type = (png_byte)filter_type;\n#endif\n   png_ptr->compression_type = (png_byte)compression_type;\n\n   /* Find number of channels */\n   switch (png_ptr->color_type)\n   {\n      default: /* invalid, png_set_IHDR calls png_error */\n      case PNG_COLOR_TYPE_GRAY:\n      case PNG_COLOR_TYPE_PALETTE:\n         png_ptr->channels = 1;\n         break;\n\n      case PNG_COLOR_TYPE_RGB:\n         png_ptr->channels = 3;\n         break;\n\n      case PNG_COLOR_TYPE_GRAY_ALPHA:\n         png_ptr->channels = 2;\n         break;\n\n      case PNG_COLOR_TYPE_RGB_ALPHA:\n         png_ptr->channels = 4;\n         break;\n   }\n\n   /* Set up other useful info */\n   png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels);\n   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);\n   png_debug1(3, \"bit_depth = %d\", png_ptr->bit_depth);\n   png_debug1(3, \"channels = %d\", png_ptr->channels);\n   png_debug1(3, \"rowbytes = %lu\", (unsigned long)png_ptr->rowbytes);\n   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,\n       color_type, interlace_type, compression_type, filter_type);\n}\n\n/* Read and check the palette */\nvoid /* PRIVATE */\npng_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_color palette[PNG_MAX_PALETTE_LENGTH];\n   int max_palette_length, num, i;\n#ifdef PNG_POINTER_INDEXING_SUPPORTED\n   png_colorp pal_ptr;\n#endif\n\n   png_debug(1, \"in png_handle_PLTE\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   /* Moved to before the 'after IDAT' check below because otherwise duplicate\n    * PLTE chunks are potentially ignored (the spec says there shall not be more\n    * than one PLTE, the error is not treated as benign, so this check trumps\n    * the requirement that PLTE appears before IDAT.)\n    */\n   else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)\n      png_chunk_error(png_ptr, \"duplicate\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      /* This is benign because the non-benign error happened before, when an\n       * IDAT was encountered in a color-mapped image with no PLTE.\n       */\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   png_ptr->mode |= PNG_HAVE_PLTE;\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"ignored in grayscale PNG\");\n      return;\n   }\n\n#ifndef PNG_READ_OPT_PLTE_SUPPORTED\n   if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)\n   {\n      png_crc_finish(png_ptr, length);\n      return;\n   }\n#endif\n\n   if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)\n   {\n      png_crc_finish(png_ptr, length);\n\n      if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)\n         png_chunk_benign_error(png_ptr, \"invalid\");\n\n      else\n         png_chunk_error(png_ptr, \"invalid\");\n\n      return;\n   }\n\n   /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */\n   num = (int)length / 3;\n\n   /* If the palette has 256 or fewer entries but is too large for the bit\n    * depth, we don't issue an error, to preserve the behavior of previous\n    * libpng versions. We silently truncate the unused extra palette entries\n    * here.\n    */\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      max_palette_length = (1 << png_ptr->bit_depth);\n   else\n      max_palette_length = PNG_MAX_PALETTE_LENGTH;\n\n   if (num > max_palette_length)\n      num = max_palette_length;\n\n#ifdef PNG_POINTER_INDEXING_SUPPORTED\n   for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)\n   {\n      png_byte buf[3];\n\n      png_crc_read(png_ptr, buf, 3);\n      pal_ptr->red = buf[0];\n      pal_ptr->green = buf[1];\n      pal_ptr->blue = buf[2];\n   }\n#else\n   for (i = 0; i < num; i++)\n   {\n      png_byte buf[3];\n\n      png_crc_read(png_ptr, buf, 3);\n      /* Don't depend upon png_color being any order */\n      palette[i].red = buf[0];\n      palette[i].green = buf[1];\n      palette[i].blue = buf[2];\n   }\n#endif\n\n   /* If we actually need the PLTE chunk (ie for a paletted image), we do\n    * whatever the normal CRC configuration tells us.  However, if we\n    * have an RGB image, the PLTE can be considered ancillary, so\n    * we will act as though it is.\n    */\n#ifndef PNG_READ_OPT_PLTE_SUPPORTED\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n#endif\n   {\n      png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3));\n   }\n\n#ifndef PNG_READ_OPT_PLTE_SUPPORTED\n   else if (png_crc_error(png_ptr) != 0)  /* Only if we have a CRC error */\n   {\n      /* If we don't want to use the data from an ancillary chunk,\n       * we have two options: an error abort, or a warning and we\n       * ignore the data in this chunk (which should be OK, since\n       * it's considered ancillary for a RGB or RGBA image).\n       *\n       * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the\n       * chunk type to determine whether to check the ancillary or the critical\n       * flags.\n       */\n      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0)\n      {\n         if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0)\n            return;\n\n         else\n            png_chunk_error(png_ptr, \"CRC error\");\n      }\n\n      /* Otherwise, we (optionally) emit a warning and use the chunk. */\n      else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)\n         png_chunk_warning(png_ptr, \"CRC error\");\n   }\n#endif\n\n   /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its\n    * own copy of the palette.  This has the side effect that when png_start_row\n    * is called (this happens after any call to png_read_update_info) the\n    * info_ptr palette gets changed.  This is extremely unexpected and\n    * confusing.\n    *\n    * Fix this by not sharing the palette in this way.\n    */\n   png_set_PLTE(png_ptr, info_ptr, palette, num);\n\n   /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before\n    * IDAT.  Prior to 1.6.0 this was not checked; instead the code merely\n    * checked the apparent validity of a tRNS chunk inserted before PLTE on a\n    * palette PNG.  1.6.0 attempts to rigorously follow the standard and\n    * therefore does a benign error if the erroneous condition is detected *and*\n    * cancels the tRNS if the benign error returns.  The alternative is to\n    * amend the standard since it would be rather hypocritical of the standards\n    * maintainers to ignore it.\n    */\n#ifdef PNG_READ_tRNS_SUPPORTED\n   if (png_ptr->num_trans > 0 ||\n       (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))\n   {\n      /* Cancel this because otherwise it would be used if the transforms\n       * require it.  Don't cancel the 'valid' flag because this would prevent\n       * detection of duplicate chunks.\n       */\n      png_ptr->num_trans = 0;\n\n      if (info_ptr != NULL)\n         info_ptr->num_trans = 0;\n\n      png_chunk_benign_error(png_ptr, \"tRNS must be after\");\n   }\n#endif\n\n#ifdef PNG_READ_hIST_SUPPORTED\n   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)\n      png_chunk_benign_error(png_ptr, \"hIST must be after\");\n#endif\n\n#ifdef PNG_READ_bKGD_SUPPORTED\n   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)\n      png_chunk_benign_error(png_ptr, \"bKGD must be after\");\n#endif\n}\n\nvoid /* PRIVATE */\npng_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_debug(1, \"in png_handle_IEND\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 ||\n       (png_ptr->mode & PNG_HAVE_IDAT) == 0)\n      png_chunk_error(png_ptr, \"out of place\");\n\n   png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);\n\n   png_crc_finish(png_ptr, length);\n\n   if (length != 0)\n      png_chunk_benign_error(png_ptr, \"invalid\");\n\n   PNG_UNUSED(info_ptr)\n}\n\n#ifdef PNG_READ_gAMA_SUPPORTED\nvoid /* PRIVATE */\npng_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_fixed_point igamma;\n   png_byte buf[4];\n\n   png_debug(1, \"in png_handle_gAMA\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   if (length != 4)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, 4);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   igamma = png_get_fixed_point(NULL, buf);\n\n   png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);\n   png_colorspace_sync(png_ptr, info_ptr);\n}\n#endif\n\n#ifdef PNG_READ_sBIT_SUPPORTED\nvoid /* PRIVATE */\npng_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   unsigned int truelen, i;\n   png_byte sample_depth;\n   png_byte buf[4];\n\n   png_debug(1, \"in png_handle_sBIT\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      truelen = 3;\n      sample_depth = 8;\n   }\n\n   else\n   {\n      truelen = png_ptr->channels;\n      sample_depth = png_ptr->bit_depth;\n   }\n\n   if (length != truelen || length > 4)\n   {\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      png_crc_finish(png_ptr, length);\n      return;\n   }\n\n   buf[0] = buf[1] = buf[2] = buf[3] = sample_depth;\n   png_crc_read(png_ptr, buf, truelen);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   for (i=0; i<truelen; ++i)\n   {\n      if (buf[i] == 0 || buf[i] > sample_depth)\n      {\n         png_chunk_benign_error(png_ptr, \"invalid\");\n         return;\n      }\n   }\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      png_ptr->sig_bit.red = buf[0];\n      png_ptr->sig_bit.green = buf[1];\n      png_ptr->sig_bit.blue = buf[2];\n      png_ptr->sig_bit.alpha = buf[3];\n   }\n\n   else\n   {\n      png_ptr->sig_bit.gray = buf[0];\n      png_ptr->sig_bit.red = buf[0];\n      png_ptr->sig_bit.green = buf[0];\n      png_ptr->sig_bit.blue = buf[0];\n      png_ptr->sig_bit.alpha = buf[1];\n   }\n\n   png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));\n}\n#endif\n\n#ifdef PNG_READ_cHRM_SUPPORTED\nvoid /* PRIVATE */\npng_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte buf[32];\n   png_xy xy;\n\n   png_debug(1, \"in png_handle_cHRM\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   if (length != 32)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, 32);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   xy.whitex = png_get_fixed_point(NULL, buf);\n   xy.whitey = png_get_fixed_point(NULL, buf + 4);\n   xy.redx   = png_get_fixed_point(NULL, buf + 8);\n   xy.redy   = png_get_fixed_point(NULL, buf + 12);\n   xy.greenx = png_get_fixed_point(NULL, buf + 16);\n   xy.greeny = png_get_fixed_point(NULL, buf + 20);\n   xy.bluex  = png_get_fixed_point(NULL, buf + 24);\n   xy.bluey  = png_get_fixed_point(NULL, buf + 28);\n\n   if (xy.whitex == PNG_FIXED_ERROR ||\n       xy.whitey == PNG_FIXED_ERROR ||\n       xy.redx   == PNG_FIXED_ERROR ||\n       xy.redy   == PNG_FIXED_ERROR ||\n       xy.greenx == PNG_FIXED_ERROR ||\n       xy.greeny == PNG_FIXED_ERROR ||\n       xy.bluex  == PNG_FIXED_ERROR ||\n       xy.bluey  == PNG_FIXED_ERROR)\n   {\n      png_chunk_benign_error(png_ptr, \"invalid values\");\n      return;\n   }\n\n   /* If a colorspace error has already been output skip this chunk */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)\n      return;\n\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0)\n   {\n      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;\n      png_colorspace_sync(png_ptr, info_ptr);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;\n   (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy,\n       1/*prefer cHRM values*/);\n   png_colorspace_sync(png_ptr, info_ptr);\n}\n#endif\n\n#ifdef PNG_READ_sRGB_SUPPORTED\nvoid /* PRIVATE */\npng_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte intent;\n\n   png_debug(1, \"in png_handle_sRGB\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   if (length != 1)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, &intent, 1);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   /* If a colorspace error has already been output skip this chunk */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)\n      return;\n\n   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect\n    * this.\n    */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)\n   {\n      png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;\n      png_colorspace_sync(png_ptr, info_ptr);\n      png_chunk_benign_error(png_ptr, \"too many profiles\");\n      return;\n   }\n\n   (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);\n   png_colorspace_sync(png_ptr, info_ptr);\n}\n#endif /* READ_sRGB */\n\n#ifdef PNG_READ_iCCP_SUPPORTED\nvoid /* PRIVATE */\npng_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n/* Note: this does not properly handle profiles that are > 64K under DOS */\n{\n   png_const_charp errmsg = NULL; /* error message output, or no error */\n   int finished = 0; /* crc checked */\n\n   png_debug(1, \"in png_handle_iCCP\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   /* Consistent with all the above colorspace handling an obviously *invalid*\n    * chunk is just ignored, so does not invalidate the color space.  An\n    * alternative is to set the 'invalid' flags at the start of this routine\n    * and only clear them in they were not set before and all the tests pass.\n    */\n\n   /* The keyword must be at least one character and there is a\n    * terminator (0) byte and the compression method byte, and the\n    * 'zlib' datastream is at least 11 bytes.\n    */\n   if (length < 14)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"too short\");\n      return;\n   }\n\n   /* If a colorspace error has already been output skip this chunk */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      return;\n   }\n\n   /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect\n    * this.\n    */\n   if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)\n   {\n      uInt read_length, keyword_length;\n      char keyword[81];\n\n      /* Find the keyword; the keyword plus separator and compression method\n       * bytes can be at most 81 characters long.\n       */\n      read_length = 81; /* maximum */\n      if (read_length > length)\n         read_length = (uInt)length;\n\n      png_crc_read(png_ptr, (png_bytep)keyword, read_length);\n      length -= read_length;\n\n      /* The minimum 'zlib' stream is assumed to be just the 2 byte header,\n       * 5 bytes minimum 'deflate' stream, and the 4 byte checksum.\n       */\n      if (length < 11)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"too short\");\n         return;\n      }\n\n      keyword_length = 0;\n      while (keyword_length < 80 && keyword_length < read_length &&\n         keyword[keyword_length] != 0)\n         ++keyword_length;\n\n      /* TODO: make the keyword checking common */\n      if (keyword_length >= 1 && keyword_length <= 79)\n      {\n         /* We only understand '0' compression - deflate - so if we get a\n          * different value we can't safely decode the chunk.\n          */\n         if (keyword_length+1 < read_length &&\n            keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE)\n         {\n            read_length -= keyword_length+2;\n\n            if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)\n            {\n               Byte profile_header[132]={0};\n               Byte local_buffer[PNG_INFLATE_BUF_SIZE];\n               png_alloc_size_t size = (sizeof profile_header);\n\n               png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2);\n               png_ptr->zstream.avail_in = read_length;\n               (void)png_inflate_read(png_ptr, local_buffer,\n                   (sizeof local_buffer), &length, profile_header, &size,\n                   0/*finish: don't, because the output is too small*/);\n\n               if (size == 0)\n               {\n                  /* We have the ICC profile header; do the basic header checks.\n                   */\n                  png_uint_32 profile_length = png_get_uint_32(profile_header);\n\n                  if (png_icc_check_length(png_ptr, &png_ptr->colorspace,\n                      keyword, profile_length) != 0)\n                  {\n                     /* The length is apparently ok, so we can check the 132\n                      * byte header.\n                      */\n                     if (png_icc_check_header(png_ptr, &png_ptr->colorspace,\n                         keyword, profile_length, profile_header,\n                         png_ptr->color_type) != 0)\n                     {\n                        /* Now read the tag table; a variable size buffer is\n                         * needed at this point, allocate one for the whole\n                         * profile.  The header check has already validated\n                         * that none of this stuff will overflow.\n                         */\n                        png_uint_32 tag_count =\n                           png_get_uint_32(profile_header + 128);\n                        png_bytep profile = png_read_buffer(png_ptr,\n                            profile_length, 2/*silent*/);\n\n                        if (profile != NULL)\n                        {\n                           memcpy(profile, profile_header,\n                               (sizeof profile_header));\n\n                           size = 12 * tag_count;\n\n                           (void)png_inflate_read(png_ptr, local_buffer,\n                               (sizeof local_buffer), &length,\n                               profile + (sizeof profile_header), &size, 0);\n\n                           /* Still expect a buffer error because we expect\n                            * there to be some tag data!\n                            */\n                           if (size == 0)\n                           {\n                              if (png_icc_check_tag_table(png_ptr,\n                                  &png_ptr->colorspace, keyword, profile_length,\n                                  profile) != 0)\n                              {\n                                 /* The profile has been validated for basic\n                                  * security issues, so read the whole thing in.\n                                  */\n                                 size = profile_length - (sizeof profile_header)\n                                     - 12 * tag_count;\n\n                                 (void)png_inflate_read(png_ptr, local_buffer,\n                                     (sizeof local_buffer), &length,\n                                     profile + (sizeof profile_header) +\n                                     12 * tag_count, &size, 1/*finish*/);\n\n                                 if (length > 0 && !(png_ptr->flags &\n                                     PNG_FLAG_BENIGN_ERRORS_WARN))\n                                    errmsg = \"extra compressed data\";\n\n                                 /* But otherwise allow extra data: */\n                                 else if (size == 0)\n                                 {\n                                    if (length > 0)\n                                    {\n                                       /* This can be handled completely, so\n                                        * keep going.\n                                        */\n                                       png_chunk_warning(png_ptr,\n                                           \"extra compressed data\");\n                                    }\n\n                                    png_crc_finish(png_ptr, length);\n                                    finished = 1;\n\n# if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0\n                                    /* Check for a match against sRGB */\n                                    png_icc_set_sRGB(png_ptr,\n                                        &png_ptr->colorspace, profile,\n                                        png_ptr->zstream.adler);\n# endif\n\n                                    /* Steal the profile for info_ptr. */\n                                    if (info_ptr != NULL)\n                                    {\n                                       png_free_data(png_ptr, info_ptr,\n                                           PNG_FREE_ICCP, 0);\n\n                                       info_ptr->iccp_name = png_voidcast(char*,\n                                           png_malloc_base(png_ptr,\n                                           keyword_length+1));\n                                       if (info_ptr->iccp_name != NULL)\n                                       {\n                                          memcpy(info_ptr->iccp_name, keyword,\n                                              keyword_length+1);\n                                          info_ptr->iccp_proflen =\n                                              profile_length;\n                                          info_ptr->iccp_profile = profile;\n                                          png_ptr->read_buffer = NULL; /*steal*/\n                                          info_ptr->free_me |= PNG_FREE_ICCP;\n                                          info_ptr->valid |= PNG_INFO_iCCP;\n                                       }\n\n                                       else\n                                       {\n                                          png_ptr->colorspace.flags |=\n                                             PNG_COLORSPACE_INVALID;\n                                          errmsg = \"out of memory\";\n                                       }\n                                    }\n\n                                    /* else the profile remains in the read\n                                     * buffer which gets reused for subsequent\n                                     * chunks.\n                                     */\n\n                                    if (info_ptr != NULL)\n                                       png_colorspace_sync(png_ptr, info_ptr);\n\n                                    if (errmsg == NULL)\n                                    {\n                                       png_ptr->zowner = 0;\n                                       return;\n                                    }\n                                 }\n                                 if (errmsg == NULL)\n                                    errmsg = png_ptr->zstream.msg;\n                              }\n                              /* else png_icc_check_tag_table output an error */\n                           }\n                           else /* profile truncated */\n                              errmsg = png_ptr->zstream.msg;\n                        }\n\n                        else\n                           errmsg = \"out of memory\";\n                     }\n\n                     /* else png_icc_check_header output an error */\n                  }\n\n                  /* else png_icc_check_length output an error */\n               }\n\n               else /* profile truncated */\n                  errmsg = png_ptr->zstream.msg;\n\n               /* Release the stream */\n               png_ptr->zowner = 0;\n            }\n\n            else /* png_inflate_claim failed */\n               errmsg = png_ptr->zstream.msg;\n         }\n\n         else\n            errmsg = \"bad compression method\"; /* or missing */\n      }\n\n      else\n         errmsg = \"bad keyword\";\n   }\n\n   else\n      errmsg = \"too many profiles\";\n\n   /* Failure: the reason is in 'errmsg' */\n   if (finished == 0)\n      png_crc_finish(png_ptr, length);\n\n   png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;\n   png_colorspace_sync(png_ptr, info_ptr);\n   if (errmsg != NULL) /* else already output */\n      png_chunk_benign_error(png_ptr, errmsg);\n}\n#endif /* READ_iCCP */\n\n#ifdef PNG_READ_sPLT_SUPPORTED\nvoid /* PRIVATE */\npng_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n/* Note: this does not properly handle chunks that are > 64K under DOS */\n{\n   png_bytep entry_start, buffer;\n   png_sPLT_t new_palette;\n   png_sPLT_entryp pp;\n   png_uint_32 data_length;\n   int entry_size, i;\n   png_uint_32 skip = 0;\n   png_uint_32 dl;\n   size_t max_dl;\n\n   png_debug(1, \"in png_handle_sPLT\");\n\n#ifdef PNG_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_cache_max != 0)\n   {\n      if (png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         return;\n      }\n\n      if (--png_ptr->user_chunk_cache_max == 1)\n      {\n         png_warning(png_ptr, \"No space in chunk cache for sPLT\");\n         png_crc_finish(png_ptr, length);\n         return;\n      }\n   }\n#endif\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n#ifdef PNG_MAX_MALLOC_64K\n   if (length > 65535U)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"too large to fit in memory\");\n      return;\n   }\n#endif\n\n   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);\n   if (buffer == NULL)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n\n   /* WARNING: this may break if size_t is less than 32 bits; it is assumed\n    * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a\n    * potential breakage point if the types in pngconf.h aren't exactly right.\n    */\n   png_crc_read(png_ptr, buffer, length);\n\n   if (png_crc_finish(png_ptr, skip) != 0)\n      return;\n\n   buffer[length] = 0;\n\n   for (entry_start = buffer; *entry_start; entry_start++)\n      /* Empty loop to find end of name */ ;\n\n   ++entry_start;\n\n   /* A sample depth should follow the separator, and we should be on it  */\n   if (length < 2U || entry_start > buffer + (length - 2U))\n   {\n      png_warning(png_ptr, \"malformed sPLT chunk\");\n      return;\n   }\n\n   new_palette.depth = *entry_start++;\n   entry_size = (new_palette.depth == 8 ? 6 : 10);\n   /* This must fit in a png_uint_32 because it is derived from the original\n    * chunk data length.\n    */\n   data_length = length - (png_uint_32)(entry_start - buffer);\n\n   /* Integrity-check the data length */\n   if ((data_length % (unsigned int)entry_size) != 0)\n   {\n      png_warning(png_ptr, \"sPLT chunk has bad length\");\n      return;\n   }\n\n   dl = (png_uint_32)(data_length / (unsigned int)entry_size);\n   max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));\n\n   if (dl > max_dl)\n   {\n      png_warning(png_ptr, \"sPLT chunk too long\");\n      return;\n   }\n\n   new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size);\n\n   new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,\n       (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry)));\n\n   if (new_palette.entries == NULL)\n   {\n      png_warning(png_ptr, \"sPLT chunk requires too much memory\");\n      return;\n   }\n\n#ifdef PNG_POINTER_INDEXING_SUPPORTED\n   for (i = 0; i < new_palette.nentries; i++)\n   {\n      pp = new_palette.entries + i;\n\n      if (new_palette.depth == 8)\n      {\n         pp->red = *entry_start++;\n         pp->green = *entry_start++;\n         pp->blue = *entry_start++;\n         pp->alpha = *entry_start++;\n      }\n\n      else\n      {\n         pp->red   = png_get_uint_16(entry_start); entry_start += 2;\n         pp->green = png_get_uint_16(entry_start); entry_start += 2;\n         pp->blue  = png_get_uint_16(entry_start); entry_start += 2;\n         pp->alpha = png_get_uint_16(entry_start); entry_start += 2;\n      }\n\n      pp->frequency = png_get_uint_16(entry_start); entry_start += 2;\n   }\n#else\n   pp = new_palette.entries;\n\n   for (i = 0; i < new_palette.nentries; i++)\n   {\n\n      if (new_palette.depth == 8)\n      {\n         pp[i].red   = *entry_start++;\n         pp[i].green = *entry_start++;\n         pp[i].blue  = *entry_start++;\n         pp[i].alpha = *entry_start++;\n      }\n\n      else\n      {\n         pp[i].red   = png_get_uint_16(entry_start); entry_start += 2;\n         pp[i].green = png_get_uint_16(entry_start); entry_start += 2;\n         pp[i].blue  = png_get_uint_16(entry_start); entry_start += 2;\n         pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;\n      }\n\n      pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;\n   }\n#endif\n\n   /* Discard all chunk data except the name and stash that */\n   new_palette.name = (png_charp)buffer;\n\n   png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);\n\n   png_free(png_ptr, new_palette.entries);\n}\n#endif /* READ_sPLT */\n\n#ifdef PNG_READ_tRNS_SUPPORTED\nvoid /* PRIVATE */\npng_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte readbuf[PNG_MAX_PALETTE_LENGTH];\n\n   png_debug(1, \"in png_handle_tRNS\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)\n   {\n      png_byte buf[2];\n\n      if (length != 2)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"invalid\");\n         return;\n      }\n\n      png_crc_read(png_ptr, buf, 2);\n      png_ptr->num_trans = 1;\n      png_ptr->trans_color.gray = png_get_uint_16(buf);\n   }\n\n   else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)\n   {\n      png_byte buf[6];\n\n      if (length != 6)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"invalid\");\n         return;\n      }\n\n      png_crc_read(png_ptr, buf, length);\n      png_ptr->num_trans = 1;\n      png_ptr->trans_color.red = png_get_uint_16(buf);\n      png_ptr->trans_color.green = png_get_uint_16(buf + 2);\n      png_ptr->trans_color.blue = png_get_uint_16(buf + 4);\n   }\n\n   else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)\n      {\n         /* TODO: is this actually an error in the ISO spec? */\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"out of place\");\n         return;\n      }\n\n      if (length > (unsigned int) png_ptr->num_palette ||\n         length > (unsigned int) PNG_MAX_PALETTE_LENGTH ||\n         length == 0)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"invalid\");\n         return;\n      }\n\n      png_crc_read(png_ptr, readbuf, length);\n      png_ptr->num_trans = (png_uint_16)length;\n   }\n\n   else\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid with alpha channel\");\n      return;\n   }\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n   {\n      png_ptr->num_trans = 0;\n      return;\n   }\n\n   /* TODO: this is a horrible side effect in the palette case because the\n    * png_struct ends up with a pointer to the tRNS buffer owned by the\n    * png_info.  Fix this.\n    */\n   png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,\n       &(png_ptr->trans_color));\n}\n#endif\n\n#ifdef PNG_READ_bKGD_SUPPORTED\nvoid /* PRIVATE */\npng_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   unsigned int truelen;\n   png_byte buf[6];\n   png_color_16 background;\n\n   png_debug(1, \"in png_handle_bKGD\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||\n       (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&\n       (png_ptr->mode & PNG_HAVE_PLTE) == 0))\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      truelen = 1;\n\n   else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      truelen = 6;\n\n   else\n      truelen = 2;\n\n   if (length != truelen)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, truelen);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   /* We convert the index value into RGB components so that we can allow\n    * arbitrary RGB values for background when we have transparency, and\n    * so it is easy to determine the RGB values of the background color\n    * from the info_ptr struct.\n    */\n   if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      background.index = buf[0];\n\n      if (info_ptr != NULL && info_ptr->num_palette != 0)\n      {\n         if (buf[0] >= info_ptr->num_palette)\n         {\n            png_chunk_benign_error(png_ptr, \"invalid index\");\n            return;\n         }\n\n         background.red = (png_uint_16)png_ptr->palette[buf[0]].red;\n         background.green = (png_uint_16)png_ptr->palette[buf[0]].green;\n         background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;\n      }\n\n      else\n         background.red = background.green = background.blue = 0;\n\n      background.gray = 0;\n   }\n\n   else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */\n   {\n      if (png_ptr->bit_depth <= 8)\n      {\n         if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth))\n         {\n            png_chunk_benign_error(png_ptr, \"invalid gray level\");\n            return;\n         }\n      }\n\n      background.index = 0;\n      background.red =\n      background.green =\n      background.blue =\n      background.gray = png_get_uint_16(buf);\n   }\n\n   else\n   {\n      if (png_ptr->bit_depth <= 8)\n      {\n         if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0)\n         {\n            png_chunk_benign_error(png_ptr, \"invalid color\");\n            return;\n         }\n      }\n\n      background.index = 0;\n      background.red = png_get_uint_16(buf);\n      background.green = png_get_uint_16(buf + 2);\n      background.blue = png_get_uint_16(buf + 4);\n      background.gray = 0;\n   }\n\n   png_set_bKGD(png_ptr, info_ptr, &background);\n}\n#endif\n\n#ifdef PNG_READ_eXIf_SUPPORTED\nvoid /* PRIVATE */\npng_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   unsigned int i;\n\n   png_debug(1, \"in png_handle_eXIf\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   if (length < 2)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"too short\");\n      return;\n   }\n\n   else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   info_ptr->free_me |= PNG_FREE_EXIF;\n\n   info_ptr->eXIf_buf = png_voidcast(png_bytep,\n             png_malloc_warn(png_ptr, length));\n\n   if (info_ptr->eXIf_buf == NULL)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   for (i = 0; i < length; i++)\n   {\n      png_byte buf[1];\n      png_crc_read(png_ptr, buf, 1);\n      info_ptr->eXIf_buf[i] = buf[0];\n      if (i == 1 && buf[0] != 'M' && buf[0] != 'I'\n                 && info_ptr->eXIf_buf[0] != buf[0])\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"incorrect byte-order specifier\");\n         png_free(png_ptr, info_ptr->eXIf_buf);\n         info_ptr->eXIf_buf = NULL;\n         return;\n      }\n   }\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf);\n\n   png_free(png_ptr, info_ptr->eXIf_buf);\n   info_ptr->eXIf_buf = NULL;\n}\n#endif\n\n#ifdef PNG_READ_hIST_SUPPORTED\nvoid /* PRIVATE */\npng_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   unsigned int num, i;\n   png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];\n\n   png_debug(1, \"in png_handle_hIST\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||\n       (png_ptr->mode & PNG_HAVE_PLTE) == 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   num = length / 2 ;\n\n   if (num != (unsigned int) png_ptr->num_palette ||\n       num > (unsigned int) PNG_MAX_PALETTE_LENGTH)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   for (i = 0; i < num; i++)\n   {\n      png_byte buf[2];\n\n      png_crc_read(png_ptr, buf, 2);\n      readbuf[i] = png_get_uint_16(buf);\n   }\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   png_set_hIST(png_ptr, info_ptr, readbuf);\n}\n#endif\n\n#ifdef PNG_READ_pHYs_SUPPORTED\nvoid /* PRIVATE */\npng_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte buf[9];\n   png_uint_32 res_x, res_y;\n   int unit_type;\n\n   png_debug(1, \"in png_handle_pHYs\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if (length != 9)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, 9);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   res_x = png_get_uint_32(buf);\n   res_y = png_get_uint_32(buf + 4);\n   unit_type = buf[8];\n   png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);\n}\n#endif\n\n#ifdef PNG_READ_oFFs_SUPPORTED\nvoid /* PRIVATE */\npng_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte buf[9];\n   png_int_32 offset_x, offset_y;\n   int unit_type;\n\n   png_debug(1, \"in png_handle_oFFs\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if (length != 9)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, 9);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   offset_x = png_get_int_32(buf);\n   offset_y = png_get_int_32(buf + 4);\n   unit_type = buf[8];\n   png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);\n}\n#endif\n\n#ifdef PNG_READ_pCAL_SUPPORTED\n/* Read the pCAL chunk (described in the PNG Extensions document) */\nvoid /* PRIVATE */\npng_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_int_32 X0, X1;\n   png_byte type, nparams;\n   png_bytep buffer, buf, units, endptr;\n   png_charpp params;\n   int i;\n\n   png_debug(1, \"in png_handle_pCAL\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   png_debug1(2, \"Allocating and reading pCAL chunk data (%u bytes)\",\n       length + 1);\n\n   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);\n\n   if (buffer == NULL)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buffer, length);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   buffer[length] = 0; /* Null terminate the last string */\n\n   png_debug(3, \"Finding end of pCAL purpose string\");\n   for (buf = buffer; *buf; buf++)\n      /* Empty loop */ ;\n\n   endptr = buffer + length;\n\n   /* We need to have at least 12 bytes after the purpose string\n    * in order to get the parameter information.\n    */\n   if (endptr - buf <= 12)\n   {\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_debug(3, \"Reading pCAL X0, X1, type, nparams, and units\");\n   X0 = png_get_int_32((png_bytep)buf+1);\n   X1 = png_get_int_32((png_bytep)buf+5);\n   type = buf[9];\n   nparams = buf[10];\n   units = buf + 11;\n\n   png_debug(3, \"Checking pCAL equation type and number of parameters\");\n   /* Check that we have the right number of parameters for known\n    * equation types.\n    */\n   if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||\n       (type == PNG_EQUATION_BASE_E && nparams != 3) ||\n       (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||\n       (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))\n   {\n      png_chunk_benign_error(png_ptr, \"invalid parameter count\");\n      return;\n   }\n\n   else if (type >= PNG_EQUATION_LAST)\n   {\n      png_chunk_benign_error(png_ptr, \"unrecognized equation type\");\n   }\n\n   for (buf = units; *buf; buf++)\n      /* Empty loop to move past the units string. */ ;\n\n   png_debug(3, \"Allocating pCAL parameters array\");\n\n   params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,\n       nparams * (sizeof (png_charp))));\n\n   if (params == NULL)\n   {\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   /* Get pointers to the start of each parameter string. */\n   for (i = 0; i < nparams; i++)\n   {\n      buf++; /* Skip the null string terminator from previous parameter. */\n\n      png_debug1(3, \"Reading pCAL parameter %d\", i);\n\n      for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++)\n         /* Empty loop to move past each parameter string */ ;\n\n      /* Make sure we haven't run out of data yet */\n      if (buf > endptr)\n      {\n         png_free(png_ptr, params);\n         png_chunk_benign_error(png_ptr, \"invalid data\");\n         return;\n      }\n   }\n\n   png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,\n       (png_charp)units, params);\n\n   png_free(png_ptr, params);\n}\n#endif\n\n#ifdef PNG_READ_sCAL_SUPPORTED\n/* Read the sCAL chunk */\nvoid /* PRIVATE */\npng_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_bytep buffer;\n   size_t i;\n   int state;\n\n   png_debug(1, \"in png_handle_sCAL\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of place\");\n      return;\n   }\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   /* Need unit type, width, \\0, height: minimum 4 bytes */\n   else if (length < 4)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_debug1(2, \"Allocating and reading sCAL chunk data (%u bytes)\",\n       length + 1);\n\n   buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);\n\n   if (buffer == NULL)\n   {\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      png_crc_finish(png_ptr, length);\n      return;\n   }\n\n   png_crc_read(png_ptr, buffer, length);\n   buffer[length] = 0; /* Null terminate the last string */\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   /* Validate the unit. */\n   if (buffer[0] != 1 && buffer[0] != 2)\n   {\n      png_chunk_benign_error(png_ptr, \"invalid unit\");\n      return;\n   }\n\n   /* Validate the ASCII numbers, need two ASCII numbers separated by\n    * a '\\0' and they need to fit exactly in the chunk data.\n    */\n   i = 1;\n   state = 0;\n\n   if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 ||\n       i >= length || buffer[i++] != 0)\n      png_chunk_benign_error(png_ptr, \"bad width format\");\n\n   else if (PNG_FP_IS_POSITIVE(state) == 0)\n      png_chunk_benign_error(png_ptr, \"non-positive width\");\n\n   else\n   {\n      size_t heighti = i;\n\n      state = 0;\n      if (png_check_fp_number((png_const_charp)buffer, length,\n          &state, &i) == 0 || i != length)\n         png_chunk_benign_error(png_ptr, \"bad height format\");\n\n      else if (PNG_FP_IS_POSITIVE(state) == 0)\n         png_chunk_benign_error(png_ptr, \"non-positive height\");\n\n      else\n         /* This is the (only) success case. */\n         png_set_sCAL_s(png_ptr, info_ptr, buffer[0],\n             (png_charp)buffer+1, (png_charp)buffer+heighti);\n   }\n}\n#endif\n\n#ifdef PNG_READ_tIME_SUPPORTED\nvoid /* PRIVATE */\npng_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_byte buf[7];\n   png_time mod_time;\n\n   png_debug(1, \"in png_handle_tIME\");\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"duplicate\");\n      return;\n   }\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n      png_ptr->mode |= PNG_AFTER_IDAT;\n\n   if (length != 7)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"invalid\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buf, 7);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   mod_time.second = buf[6];\n   mod_time.minute = buf[5];\n   mod_time.hour = buf[4];\n   mod_time.day = buf[3];\n   mod_time.month = buf[2];\n   mod_time.year = png_get_uint_16(buf);\n\n   png_set_tIME(png_ptr, info_ptr, &mod_time);\n}\n#endif\n\n#ifdef PNG_READ_tEXt_SUPPORTED\n/* Note: this does not properly handle chunks that are > 64K under DOS */\nvoid /* PRIVATE */\npng_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_text  text_info;\n   png_bytep buffer;\n   png_charp key;\n   png_charp text;\n   png_uint_32 skip = 0;\n\n   png_debug(1, \"in png_handle_tEXt\");\n\n#ifdef PNG_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_cache_max != 0)\n   {\n      if (png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         return;\n      }\n\n      if (--png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"no space in chunk cache\");\n         return;\n      }\n   }\n#endif\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n      png_ptr->mode |= PNG_AFTER_IDAT;\n\n#ifdef PNG_MAX_MALLOC_64K\n   if (length > 65535U)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"too large to fit in memory\");\n      return;\n   }\n#endif\n\n   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);\n\n   if (buffer == NULL)\n   {\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buffer, length);\n\n   if (png_crc_finish(png_ptr, skip) != 0)\n      return;\n\n   key = (png_charp)buffer;\n   key[length] = 0;\n\n   for (text = key; *text; text++)\n      /* Empty loop to find end of key */ ;\n\n   if (text != key + length)\n      text++;\n\n   text_info.compression = PNG_TEXT_COMPRESSION_NONE;\n   text_info.key = key;\n   text_info.lang = NULL;\n   text_info.lang_key = NULL;\n   text_info.itxt_length = 0;\n   text_info.text = text;\n   text_info.text_length = strlen(text);\n\n   if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0)\n      png_warning(png_ptr, \"Insufficient memory to process text chunk\");\n}\n#endif\n\n#ifdef PNG_READ_zTXt_SUPPORTED\n/* Note: this does not correctly handle chunks that are > 64K under DOS */\nvoid /* PRIVATE */\npng_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_const_charp errmsg = NULL;\n   png_bytep       buffer;\n   png_uint_32     keyword_length;\n\n   png_debug(1, \"in png_handle_zTXt\");\n\n#ifdef PNG_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_cache_max != 0)\n   {\n      if (png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         return;\n      }\n\n      if (--png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"no space in chunk cache\");\n         return;\n      }\n   }\n#endif\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n      png_ptr->mode |= PNG_AFTER_IDAT;\n\n   /* Note, \"length\" is sufficient here; we won't be adding\n    * a null terminator later.\n    */\n   buffer = png_read_buffer(png_ptr, length, 2/*silent*/);\n\n   if (buffer == NULL)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buffer, length);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   /* TODO: also check that the keyword contents match the spec! */\n   for (keyword_length = 0;\n      keyword_length < length && buffer[keyword_length] != 0;\n      ++keyword_length)\n      /* Empty loop to find end of name */ ;\n\n   if (keyword_length > 79 || keyword_length < 1)\n      errmsg = \"bad keyword\";\n\n   /* zTXt must have some LZ data after the keyword, although it may expand to\n    * zero bytes; we need a '\\0' at the end of the keyword, the compression type\n    * then the LZ data:\n    */\n   else if (keyword_length + 3 > length)\n      errmsg = \"truncated\";\n\n   else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)\n      errmsg = \"unknown compression type\";\n\n   else\n   {\n      png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;\n\n      /* TODO: at present png_decompress_chunk imposes a single application\n       * level memory limit, this should be split to different values for iCCP\n       * and text chunks.\n       */\n      if (png_decompress_chunk(png_ptr, length, keyword_length+2,\n          &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)\n      {\n         png_text text;\n\n         if (png_ptr->read_buffer == NULL)\n           errmsg=\"Read failure in png_handle_zTXt\";\n         else\n         {\n            /* It worked; png_ptr->read_buffer now looks like a tEXt chunk\n             * except for the extra compression type byte and the fact that\n             * it isn't necessarily '\\0' terminated.\n             */\n            buffer = png_ptr->read_buffer;\n            buffer[uncompressed_length+(keyword_length+2)] = 0;\n\n            text.compression = PNG_TEXT_COMPRESSION_zTXt;\n            text.key = (png_charp)buffer;\n            text.text = (png_charp)(buffer + keyword_length+2);\n            text.text_length = uncompressed_length;\n            text.itxt_length = 0;\n            text.lang = NULL;\n            text.lang_key = NULL;\n\n            if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)\n               errmsg = \"insufficient memory\";\n         }\n      }\n\n      else\n         errmsg = png_ptr->zstream.msg;\n   }\n\n   if (errmsg != NULL)\n      png_chunk_benign_error(png_ptr, errmsg);\n}\n#endif\n\n#ifdef PNG_READ_iTXt_SUPPORTED\n/* Note: this does not correctly handle chunks that are > 64K under DOS */\nvoid /* PRIVATE */\npng_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)\n{\n   png_const_charp errmsg = NULL;\n   png_bytep buffer;\n   png_uint_32 prefix_length;\n\n   png_debug(1, \"in png_handle_iTXt\");\n\n#ifdef PNG_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_cache_max != 0)\n   {\n      if (png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         return;\n      }\n\n      if (--png_ptr->user_chunk_cache_max == 1)\n      {\n         png_crc_finish(png_ptr, length);\n         png_chunk_benign_error(png_ptr, \"no space in chunk cache\");\n         return;\n      }\n   }\n#endif\n\n   if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)\n      png_chunk_error(png_ptr, \"missing IHDR\");\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)\n      png_ptr->mode |= PNG_AFTER_IDAT;\n\n   buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);\n\n   if (buffer == NULL)\n   {\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"out of memory\");\n      return;\n   }\n\n   png_crc_read(png_ptr, buffer, length);\n\n   if (png_crc_finish(png_ptr, 0) != 0)\n      return;\n\n   /* First the keyword. */\n   for (prefix_length=0;\n      prefix_length < length && buffer[prefix_length] != 0;\n      ++prefix_length)\n      /* Empty loop */ ;\n\n   /* Perform a basic check on the keyword length here. */\n   if (prefix_length > 79 || prefix_length < 1)\n      errmsg = \"bad keyword\";\n\n   /* Expect keyword, compression flag, compression type, language, translated\n    * keyword (both may be empty but are 0 terminated) then the text, which may\n    * be empty.\n    */\n   else if (prefix_length + 5 > length)\n      errmsg = \"truncated\";\n\n   else if (buffer[prefix_length+1] == 0 ||\n      (buffer[prefix_length+1] == 1 &&\n      buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE))\n   {\n      int compressed = buffer[prefix_length+1] != 0;\n      png_uint_32 language_offset, translated_keyword_offset;\n      png_alloc_size_t uncompressed_length = 0;\n\n      /* Now the language tag */\n      prefix_length += 3;\n      language_offset = prefix_length;\n\n      for (; prefix_length < length && buffer[prefix_length] != 0;\n         ++prefix_length)\n         /* Empty loop */ ;\n\n      /* WARNING: the length may be invalid here, this is checked below. */\n      translated_keyword_offset = ++prefix_length;\n\n      for (; prefix_length < length && buffer[prefix_length] != 0;\n         ++prefix_length)\n         /* Empty loop */ ;\n\n      /* prefix_length should now be at the trailing '\\0' of the translated\n       * keyword, but it may already be over the end.  None of this arithmetic\n       * can overflow because chunks are at most 2^31 bytes long, but on 16-bit\n       * systems the available allocation may overflow.\n       */\n      ++prefix_length;\n\n      if (compressed == 0 && prefix_length <= length)\n         uncompressed_length = length - prefix_length;\n\n      else if (compressed != 0 && prefix_length < length)\n      {\n         uncompressed_length = PNG_SIZE_MAX;\n\n         /* TODO: at present png_decompress_chunk imposes a single application\n          * level memory limit, this should be split to different values for\n          * iCCP and text chunks.\n          */\n         if (png_decompress_chunk(png_ptr, length, prefix_length,\n             &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)\n            buffer = png_ptr->read_buffer;\n\n         else\n            errmsg = png_ptr->zstream.msg;\n      }\n\n      else\n         errmsg = \"truncated\";\n\n      if (errmsg == NULL)\n      {\n         png_text text;\n\n         buffer[uncompressed_length+prefix_length] = 0;\n\n         if (compressed == 0)\n            text.compression = PNG_ITXT_COMPRESSION_NONE;\n\n         else\n            text.compression = PNG_ITXT_COMPRESSION_zTXt;\n\n         text.key = (png_charp)buffer;\n         text.lang = (png_charp)buffer + language_offset;\n         text.lang_key = (png_charp)buffer + translated_keyword_offset;\n         text.text = (png_charp)buffer + prefix_length;\n         text.text_length = 0;\n         text.itxt_length = uncompressed_length;\n\n         if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)\n            errmsg = \"insufficient memory\";\n      }\n   }\n\n   else\n      errmsg = \"bad compression info\";\n\n   if (errmsg != NULL)\n      png_chunk_benign_error(png_ptr, errmsg);\n}\n#endif\n\n#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED\n/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */\nstatic int\npng_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)\n{\n   png_alloc_size_t limit = PNG_SIZE_MAX;\n\n   if (png_ptr->unknown_chunk.data != NULL)\n   {\n      png_free(png_ptr, png_ptr->unknown_chunk.data);\n      png_ptr->unknown_chunk.data = NULL;\n   }\n\n#  ifdef PNG_SET_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_malloc_max > 0 &&\n       png_ptr->user_chunk_malloc_max < limit)\n      limit = png_ptr->user_chunk_malloc_max;\n\n#  elif PNG_USER_CHUNK_MALLOC_MAX > 0\n   if (PNG_USER_CHUNK_MALLOC_MAX < limit)\n      limit = PNG_USER_CHUNK_MALLOC_MAX;\n#  endif\n\n   if (length <= limit)\n   {\n      PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);\n      /* The following is safe because of the PNG_SIZE_MAX init above */\n      png_ptr->unknown_chunk.size = (size_t)length/*SAFE*/;\n      /* 'mode' is a flag array, only the bottom four bits matter here */\n      png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/;\n\n      if (length == 0)\n         png_ptr->unknown_chunk.data = NULL;\n\n      else\n      {\n         /* Do a 'warn' here - it is handled below. */\n         png_ptr->unknown_chunk.data = png_voidcast(png_bytep,\n             png_malloc_warn(png_ptr, length));\n      }\n   }\n\n   if (png_ptr->unknown_chunk.data == NULL && length > 0)\n   {\n      /* This is benign because we clean up correctly */\n      png_crc_finish(png_ptr, length);\n      png_chunk_benign_error(png_ptr, \"unknown chunk exceeds memory limits\");\n      return 0;\n   }\n\n   else\n   {\n      if (length > 0)\n         png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);\n      png_crc_finish(png_ptr, 0);\n      return 1;\n   }\n}\n#endif /* READ_UNKNOWN_CHUNKS */\n\n/* Handle an unknown, or known but disabled, chunk */\nvoid /* PRIVATE */\npng_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,\n    png_uint_32 length, int keep)\n{\n   int handled = 0; /* the chunk was handled */\n\n   png_debug(1, \"in png_handle_unknown\");\n\n#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED\n   /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing\n    * the bug which meant that setting a non-default behavior for a specific\n    * chunk would be ignored (the default was always used unless a user\n    * callback was installed).\n    *\n    * 'keep' is the value from the png_chunk_unknown_handling, the setting for\n    * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it\n    * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here.\n    * This is just an optimization to avoid multiple calls to the lookup\n    * function.\n    */\n#  ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\n#     ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n   keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name);\n#     endif\n#  endif\n\n   /* One of the following methods will read the chunk or skip it (at least one\n    * of these is always defined because this is the only way to switch on\n    * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)\n    */\n#  ifdef PNG_READ_USER_CHUNKS_SUPPORTED\n   /* The user callback takes precedence over the chunk keep value, but the\n    * keep value is still required to validate a save of a critical chunk.\n    */\n   if (png_ptr->read_user_chunk_fn != NULL)\n   {\n      if (png_cache_unknown_chunk(png_ptr, length) != 0)\n      {\n         /* Callback to user unknown chunk handler */\n         int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr,\n             &png_ptr->unknown_chunk);\n\n         /* ret is:\n          * negative: An error occurred; png_chunk_error will be called.\n          *     zero: The chunk was not handled, the chunk will be discarded\n          *           unless png_set_keep_unknown_chunks has been used to set\n          *           a 'keep' behavior for this particular chunk, in which\n          *           case that will be used.  A critical chunk will cause an\n          *           error at this point unless it is to be saved.\n          * positive: The chunk was handled, libpng will ignore/discard it.\n          */\n         if (ret < 0)\n            png_chunk_error(png_ptr, \"error in user chunk\");\n\n         else if (ret == 0)\n         {\n            /* If the keep value is 'default' or 'never' override it, but\n             * still error out on critical chunks unless the keep value is\n             * 'always'  While this is weird it is the behavior in 1.4.12.\n             * A possible improvement would be to obey the value set for the\n             * chunk, but this would be an API change that would probably\n             * damage some applications.\n             *\n             * The png_app_warning below catches the case that matters, where\n             * the application has not set specific save or ignore for this\n             * chunk or global save or ignore.\n             */\n            if (keep < PNG_HANDLE_CHUNK_IF_SAFE)\n            {\n#              ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n               if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE)\n               {\n                  png_chunk_warning(png_ptr, \"Saving unknown chunk:\");\n                  png_app_warning(png_ptr,\n                      \"forcing save of an unhandled chunk;\"\n                      \" please call png_set_keep_unknown_chunks\");\n                      /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */\n               }\n#              endif\n               keep = PNG_HANDLE_CHUNK_IF_SAFE;\n            }\n         }\n\n         else /* chunk was handled */\n         {\n            handled = 1;\n            /* Critical chunks can be safely discarded at this point. */\n            keep = PNG_HANDLE_CHUNK_NEVER;\n         }\n      }\n\n      else\n         keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */\n   }\n\n   else\n   /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */\n#  endif /* READ_USER_CHUNKS */\n\n#  ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED\n   {\n      /* keep is currently just the per-chunk setting, if there was no\n       * setting change it to the global default now (not that this may\n       * still be AS_DEFAULT) then obtain the cache of the chunk if required,\n       * if not simply skip the chunk.\n       */\n      if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT)\n         keep = png_ptr->unknown_default;\n\n      if (keep == PNG_HANDLE_CHUNK_ALWAYS ||\n         (keep == PNG_HANDLE_CHUNK_IF_SAFE &&\n          PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))\n      {\n         if (png_cache_unknown_chunk(png_ptr, length) == 0)\n            keep = PNG_HANDLE_CHUNK_NEVER;\n      }\n\n      else\n         png_crc_finish(png_ptr, length);\n   }\n#  else\n#     ifndef PNG_READ_USER_CHUNKS_SUPPORTED\n#        error no method to support READ_UNKNOWN_CHUNKS\n#     endif\n\n   {\n      /* If here there is no read callback pointer set and no support is\n       * compiled in to just save the unknown chunks, so simply skip this\n       * chunk.  If 'keep' is something other than AS_DEFAULT or NEVER then\n       * the app has erroneously asked for unknown chunk saving when there\n       * is no support.\n       */\n      if (keep > PNG_HANDLE_CHUNK_NEVER)\n         png_app_error(png_ptr, \"no unknown chunk support available\");\n\n      png_crc_finish(png_ptr, length);\n   }\n#  endif\n\n#  ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\n   /* Now store the chunk in the chunk list if appropriate, and if the limits\n    * permit it.\n    */\n   if (keep == PNG_HANDLE_CHUNK_ALWAYS ||\n      (keep == PNG_HANDLE_CHUNK_IF_SAFE &&\n       PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))\n   {\n#     ifdef PNG_USER_LIMITS_SUPPORTED\n      switch (png_ptr->user_chunk_cache_max)\n      {\n         case 2:\n            png_ptr->user_chunk_cache_max = 1;\n            png_chunk_benign_error(png_ptr, \"no space in chunk cache\");\n            /* FALLTHROUGH */\n         case 1:\n            /* NOTE: prior to 1.6.0 this case resulted in an unknown critical\n             * chunk being skipped, now there will be a hard error below.\n             */\n            break;\n\n         default: /* not at limit */\n            --(png_ptr->user_chunk_cache_max);\n            /* FALLTHROUGH */\n         case 0: /* no limit */\n#  endif /* USER_LIMITS */\n            /* Here when the limit isn't reached or when limits are compiled\n             * out; store the chunk.\n             */\n            png_set_unknown_chunks(png_ptr, info_ptr,\n                &png_ptr->unknown_chunk, 1);\n            handled = 1;\n#  ifdef PNG_USER_LIMITS_SUPPORTED\n            break;\n      }\n#  endif\n   }\n#  else /* no store support: the chunk must be handled by the user callback */\n   PNG_UNUSED(info_ptr)\n#  endif\n\n   /* Regardless of the error handling below the cached data (if any) can be\n    * freed now.  Notice that the data is not freed if there is a png_error, but\n    * it will be freed by destroy_read_struct.\n    */\n   if (png_ptr->unknown_chunk.data != NULL)\n      png_free(png_ptr, png_ptr->unknown_chunk.data);\n   png_ptr->unknown_chunk.data = NULL;\n\n#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */\n   /* There is no support to read an unknown chunk, so just skip it. */\n   png_crc_finish(png_ptr, length);\n   PNG_UNUSED(info_ptr)\n   PNG_UNUSED(keep)\n#endif /* !READ_UNKNOWN_CHUNKS */\n\n   /* Check for unhandled critical chunks */\n   if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))\n      png_chunk_error(png_ptr, \"unhandled critical chunk\");\n}\n\n/* This function is called to verify that a chunk name is valid.\n * This function can't have the \"critical chunk check\" incorporated\n * into it, since in the future we will need to be able to call user\n * functions to handle unknown critical chunks after we check that\n * the chunk name itself is valid.\n */\n\n/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:\n *\n * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))\n */\n\nvoid /* PRIVATE */\npng_check_chunk_name(png_const_structrp png_ptr, png_uint_32 chunk_name)\n{\n   int i;\n   png_uint_32 cn=chunk_name;\n\n   png_debug(1, \"in png_check_chunk_name\");\n\n   for (i=1; i<=4; ++i)\n   {\n      int c = cn & 0xff;\n\n      if (c < 65 || c > 122 || (c > 90 && c < 97))\n         png_chunk_error(png_ptr, \"invalid chunk type\");\n\n      cn >>= 8;\n   }\n}\n\nvoid /* PRIVATE */\npng_check_chunk_length(png_const_structrp png_ptr, png_uint_32 length)\n{\n   png_alloc_size_t limit = PNG_UINT_31_MAX;\n\n# ifdef PNG_SET_USER_LIMITS_SUPPORTED\n   if (png_ptr->user_chunk_malloc_max > 0 &&\n       png_ptr->user_chunk_malloc_max < limit)\n      limit = png_ptr->user_chunk_malloc_max;\n# elif PNG_USER_CHUNK_MALLOC_MAX > 0\n   if (PNG_USER_CHUNK_MALLOC_MAX < limit)\n      limit = PNG_USER_CHUNK_MALLOC_MAX;\n# endif\n   if (png_ptr->chunk_name == png_IDAT)\n   {\n      png_alloc_size_t idat_limit = PNG_UINT_31_MAX;\n      size_t row_factor =\n         (size_t)png_ptr->width\n         * (size_t)png_ptr->channels\n         * (png_ptr->bit_depth > 8? 2: 1)\n         + 1\n         + (png_ptr->interlaced? 6: 0);\n      if (png_ptr->height > PNG_UINT_32_MAX/row_factor)\n         idat_limit = PNG_UINT_31_MAX;\n      else\n         idat_limit = png_ptr->height * row_factor;\n      row_factor = row_factor > 32566? 32566 : row_factor;\n      idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */\n      idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX;\n      limit = limit < idat_limit? idat_limit : limit;\n   }\n\n   if (length > limit)\n   {\n      png_debug2(0,\" length = %lu, limit = %lu\",\n         (unsigned long)length,(unsigned long)limit);\n      png_chunk_error(png_ptr, \"chunk data is too large\");\n   }\n}\n\n/* Combines the row recently read in with the existing pixels in the row.  This\n * routine takes care of alpha and transparency if requested.  This routine also\n * handles the two methods of progressive display of interlaced images,\n * depending on the 'display' value; if 'display' is true then the whole row\n * (dp) is filled from the start by replicating the available pixels.  If\n * 'display' is false only those pixels present in the pass are filled in.\n */\nvoid /* PRIVATE */\npng_combine_row(png_const_structrp png_ptr, png_bytep dp, int display)\n{\n   unsigned int pixel_depth = png_ptr->transformed_pixel_depth;\n   png_const_bytep sp = png_ptr->row_buf + 1;\n   png_alloc_size_t row_width = png_ptr->width;\n   unsigned int pass = png_ptr->pass;\n   png_bytep end_ptr = 0;\n   png_byte end_byte = 0;\n   unsigned int end_mask;\n\n   png_debug(1, \"in png_combine_row\");\n\n   /* Added in 1.5.6: it should not be possible to enter this routine until at\n    * least one row has been read from the PNG data and transformed.\n    */\n   if (pixel_depth == 0)\n      png_error(png_ptr, \"internal row logic error\");\n\n   /* Added in 1.5.4: the pixel depth should match the information returned by\n    * any call to png_read_update_info at this point.  Do not continue if we got\n    * this wrong.\n    */\n   if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=\n          PNG_ROWBYTES(pixel_depth, row_width))\n      png_error(png_ptr, \"internal row size calculation error\");\n\n   /* Don't expect this to ever happen: */\n   if (row_width == 0)\n      png_error(png_ptr, \"internal row width error\");\n\n   /* Preserve the last byte in cases where only part of it will be overwritten,\n    * the multiply below may overflow, we don't care because ANSI-C guarantees\n    * we get the low bits.\n    */\n   end_mask = (pixel_depth * row_width) & 7;\n   if (end_mask != 0)\n   {\n      /* end_ptr == NULL is a flag to say do nothing */\n      end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;\n      end_byte = *end_ptr;\n#     ifdef PNG_READ_PACKSWAP_SUPPORTED\n      if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n         /* little-endian byte */\n         end_mask = (unsigned int)(0xff << end_mask);\n\n      else /* big-endian byte */\n#     endif\n      end_mask = 0xff >> end_mask;\n      /* end_mask is now the bits to *keep* from the destination row */\n   }\n\n   /* For non-interlaced images this reduces to a memcpy(). A memcpy()\n    * will also happen if interlacing isn't supported or if the application\n    * does not call png_set_interlace_handling().  In the latter cases the\n    * caller just gets a sequence of the unexpanded rows from each interlace\n    * pass.\n    */\n#ifdef PNG_READ_INTERLACING_SUPPORTED\n   if (png_ptr->interlaced != 0 &&\n       (png_ptr->transformations & PNG_INTERLACE) != 0 &&\n       pass < 6 && (display == 0 ||\n       /* The following copies everything for 'display' on passes 0, 2 and 4. */\n       (display == 1 && (pass & 1) != 0)))\n   {\n      /* Narrow images may have no bits in a pass; the caller should handle\n       * this, but this test is cheap:\n       */\n      if (row_width <= PNG_PASS_START_COL(pass))\n         return;\n\n      if (pixel_depth < 8)\n      {\n         /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit\n          * into 32 bits, then a single loop over the bytes using the four byte\n          * values in the 32-bit mask can be used.  For the 'display' option the\n          * expanded mask may also not require any masking within a byte.  To\n          * make this work the PACKSWAP option must be taken into account - it\n          * simply requires the pixels to be reversed in each byte.\n          *\n          * The 'regular' case requires a mask for each of the first 6 passes,\n          * the 'display' case does a copy for the even passes in the range\n          * 0..6.  This has already been handled in the test above.\n          *\n          * The masks are arranged as four bytes with the first byte to use in\n          * the lowest bits (little-endian) regardless of the order (PACKSWAP or\n          * not) of the pixels in each byte.\n          *\n          * NOTE: the whole of this logic depends on the caller of this function\n          * only calling it on rows appropriate to the pass.  This function only\n          * understands the 'x' logic; the 'y' logic is handled by the caller.\n          *\n          * The following defines allow generation of compile time constant bit\n          * masks for each pixel depth and each possibility of swapped or not\n          * swapped bytes.  Pass 'p' is in the range 0..6; 'x', a pixel index,\n          * is in the range 0..7; and the result is 1 if the pixel is to be\n          * copied in the pass, 0 if not.  'S' is for the sparkle method, 'B'\n          * for the block method.\n          *\n          * With some compilers a compile time expression of the general form:\n          *\n          *    (shift >= 32) ? (a >> (shift-32)) : (b >> shift)\n          *\n          * Produces warnings with values of 'shift' in the range 33 to 63\n          * because the right hand side of the ?: expression is evaluated by\n          * the compiler even though it isn't used.  Microsoft Visual C (various\n          * versions) and the Intel C compiler are known to do this.  To avoid\n          * this the following macros are used in 1.5.6.  This is a temporary\n          * solution to avoid destabilizing the code during the release process.\n          */\n#        if PNG_USE_COMPILE_TIME_MASKS\n#           define PNG_LSR(x,s) ((x)>>((s) & 0x1f))\n#           define PNG_LSL(x,s) ((x)<<((s) & 0x1f))\n#        else\n#           define PNG_LSR(x,s) ((x)>>(s))\n#           define PNG_LSL(x,s) ((x)<<(s))\n#        endif\n#        define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\\\n           PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1)\n#        define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\\\n           PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1)\n\n         /* Return a mask for pass 'p' pixel 'x' at depth 'd'.  The mask is\n          * little endian - the first pixel is at bit 0 - however the extra\n          * parameter 's' can be set to cause the mask position to be swapped\n          * within each byte, to match the PNG format.  This is done by XOR of\n          * the shift with 7, 6 or 4 for bit depths 1, 2 and 4.\n          */\n#        define PIXEL_MASK(p,x,d,s) \\\n            (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0))))\n\n         /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask.\n          */\n#        define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)\n#        define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)\n\n         /* Combine 8 of these to get the full mask.  For the 1-bpp and 2-bpp\n          * cases the result needs replicating, for the 4-bpp case the above\n          * generates a full 32 bits.\n          */\n#        define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1)))\n\n#        define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\\\n            S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\\\n            S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d)\n\n#        define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\\\n            B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\\\n            B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d)\n\n#if PNG_USE_COMPILE_TIME_MASKS\n         /* Utility macros to construct all the masks for a depth/swap\n          * combination.  The 's' parameter says whether the format is PNG\n          * (big endian bytes) or not.  Only the three odd-numbered passes are\n          * required for the display/block algorithm.\n          */\n#        define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\\\n            S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }\n\n#        define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) }\n\n#        define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))\n\n         /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and\n          * then pass:\n          */\n         static const png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] =\n         {\n            /* Little-endian byte masks for PACKSWAP */\n            { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) },\n            /* Normal (big-endian byte) masks - PNG format */\n            { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) }\n         };\n\n         /* display_mask has only three entries for the odd passes, so index by\n          * pass>>1.\n          */\n         static const png_uint_32 display_mask[2][3][3] =\n         {\n            /* Little-endian byte masks for PACKSWAP */\n            { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) },\n            /* Normal (big-endian byte) masks - PNG format */\n            { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) }\n         };\n\n#        define MASK(pass,depth,display,png)\\\n            ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\\\n               row_mask[png][DEPTH_INDEX(depth)][pass])\n\n#else /* !PNG_USE_COMPILE_TIME_MASKS */\n         /* This is the runtime alternative: it seems unlikely that this will\n          * ever be either smaller or faster than the compile time approach.\n          */\n#        define MASK(pass,depth,display,png)\\\n            ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))\n#endif /* !USE_COMPILE_TIME_MASKS */\n\n         /* Use the appropriate mask to copy the required bits.  In some cases\n          * the byte mask will be 0 or 0xff; optimize these cases.  row_width is\n          * the number of pixels, but the code copies bytes, so it is necessary\n          * to special case the end.\n          */\n         png_uint_32 pixels_per_byte = 8 / pixel_depth;\n         png_uint_32 mask;\n\n#        ifdef PNG_READ_PACKSWAP_SUPPORTED\n         if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n            mask = MASK(pass, pixel_depth, display, 0);\n\n         else\n#        endif\n         mask = MASK(pass, pixel_depth, display, 1);\n\n         for (;;)\n         {\n            png_uint_32 m;\n\n            /* It doesn't matter in the following if png_uint_32 has more than\n             * 32 bits because the high bits always match those in m<<24; it is,\n             * however, essential to use OR here, not +, because of this.\n             */\n            m = mask;\n            mask = (m >> 8) | (m << 24); /* rotate right to good compilers */\n            m &= 0xff;\n\n            if (m != 0) /* something to copy */\n            {\n               if (m != 0xff)\n                  *dp = (png_byte)((*dp & ~m) | (*sp & m));\n               else\n                  *dp = *sp;\n            }\n\n            /* NOTE: this may overwrite the last byte with garbage if the image\n             * is not an exact number of bytes wide; libpng has always done\n             * this.\n             */\n            if (row_width <= pixels_per_byte)\n               break; /* May need to restore part of the last byte */\n\n            row_width -= pixels_per_byte;\n            ++dp;\n            ++sp;\n         }\n      }\n\n      else /* pixel_depth >= 8 */\n      {\n         unsigned int bytes_to_copy, bytes_to_jump;\n\n         /* Validate the depth - it must be a multiple of 8 */\n         if (pixel_depth & 7)\n            png_error(png_ptr, \"invalid user transform pixel depth\");\n\n         pixel_depth >>= 3; /* now in bytes */\n         row_width *= pixel_depth;\n\n         /* Regardless of pass number the Adam 7 interlace always results in a\n          * fixed number of pixels to copy then to skip.  There may be a\n          * different number of pixels to skip at the start though.\n          */\n         {\n            unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth;\n\n            row_width -= offset;\n            dp += offset;\n            sp += offset;\n         }\n\n         /* Work out the bytes to copy. */\n         if (display != 0)\n         {\n            /* When doing the 'block' algorithm the pixel in the pass gets\n             * replicated to adjacent pixels.  This is why the even (0,2,4,6)\n             * passes are skipped above - the entire expanded row is copied.\n             */\n            bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;\n\n            /* But don't allow this number to exceed the actual row width. */\n            if (bytes_to_copy > row_width)\n               bytes_to_copy = (unsigned int)/*SAFE*/row_width;\n         }\n\n         else /* normal row; Adam7 only ever gives us one pixel to copy. */\n            bytes_to_copy = pixel_depth;\n\n         /* In Adam7 there is a constant offset between where the pixels go. */\n         bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;\n\n         /* And simply copy these bytes.  Some optimization is possible here,\n          * depending on the value of 'bytes_to_copy'.  Special case the low\n          * byte counts, which we know to be frequent.\n          *\n          * Notice that these cases all 'return' rather than 'break' - this\n          * avoids an unnecessary test on whether to restore the last byte\n          * below.\n          */\n         switch (bytes_to_copy)\n         {\n            case 1:\n               for (;;)\n               {\n                  *dp = *sp;\n\n                  if (row_width <= bytes_to_jump)\n                     return;\n\n                  dp += bytes_to_jump;\n                  sp += bytes_to_jump;\n                  row_width -= bytes_to_jump;\n               }\n\n            case 2:\n               /* There is a possibility of a partial copy at the end here; this\n                * slows the code down somewhat.\n                */\n               do\n               {\n                  dp[0] = sp[0]; dp[1] = sp[1];\n\n                  if (row_width <= bytes_to_jump)\n                     return;\n\n                  sp += bytes_to_jump;\n                  dp += bytes_to_jump;\n                  row_width -= bytes_to_jump;\n               }\n               while (row_width > 1);\n\n               /* And there can only be one byte left at this point: */\n               *dp = *sp;\n               return;\n\n            case 3:\n               /* This can only be the RGB case, so each copy is exactly one\n                * pixel and it is not necessary to check for a partial copy.\n                */\n               for (;;)\n               {\n                  dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2];\n\n                  if (row_width <= bytes_to_jump)\n                     return;\n\n                  sp += bytes_to_jump;\n                  dp += bytes_to_jump;\n                  row_width -= bytes_to_jump;\n               }\n\n            default:\n#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE\n               /* Check for double byte alignment and, if possible, use a\n                * 16-bit copy.  Don't attempt this for narrow images - ones that\n                * are less than an interlace panel wide.  Don't attempt it for\n                * wide bytes_to_copy either - use the memcpy there.\n                */\n               if (bytes_to_copy < 16 /*else use memcpy*/ &&\n                   png_isaligned(dp, png_uint_16) &&\n                   png_isaligned(sp, png_uint_16) &&\n                   bytes_to_copy % (sizeof (png_uint_16)) == 0 &&\n                   bytes_to_jump % (sizeof (png_uint_16)) == 0)\n               {\n                  /* Everything is aligned for png_uint_16 copies, but try for\n                   * png_uint_32 first.\n                   */\n                  if (png_isaligned(dp, png_uint_32) &&\n                      png_isaligned(sp, png_uint_32) &&\n                      bytes_to_copy % (sizeof (png_uint_32)) == 0 &&\n                      bytes_to_jump % (sizeof (png_uint_32)) == 0)\n                  {\n                     png_uint_32p dp32 = png_aligncast(png_uint_32p,dp);\n                     png_const_uint_32p sp32 = png_aligncastconst(\n                         png_const_uint_32p, sp);\n                     size_t skip = (bytes_to_jump-bytes_to_copy) /\n                         (sizeof (png_uint_32));\n\n                     do\n                     {\n                        size_t c = bytes_to_copy;\n                        do\n                        {\n                           *dp32++ = *sp32++;\n                           c -= (sizeof (png_uint_32));\n                        }\n                        while (c > 0);\n\n                        if (row_width <= bytes_to_jump)\n                           return;\n\n                        dp32 += skip;\n                        sp32 += skip;\n                        row_width -= bytes_to_jump;\n                     }\n                     while (bytes_to_copy <= row_width);\n\n                     /* Get to here when the row_width truncates the final copy.\n                      * There will be 1-3 bytes left to copy, so don't try the\n                      * 16-bit loop below.\n                      */\n                     dp = (png_bytep)dp32;\n                     sp = (png_const_bytep)sp32;\n                     do\n                        *dp++ = *sp++;\n                     while (--row_width > 0);\n                     return;\n                  }\n\n                  /* Else do it in 16-bit quantities, but only if the size is\n                   * not too large.\n                   */\n                  else\n                  {\n                     png_uint_16p dp16 = png_aligncast(png_uint_16p, dp);\n                     png_const_uint_16p sp16 = png_aligncastconst(\n                        png_const_uint_16p, sp);\n                     size_t skip = (bytes_to_jump-bytes_to_copy) /\n                        (sizeof (png_uint_16));\n\n                     do\n                     {\n                        size_t c = bytes_to_copy;\n                        do\n                        {\n                           *dp16++ = *sp16++;\n                           c -= (sizeof (png_uint_16));\n                        }\n                        while (c > 0);\n\n                        if (row_width <= bytes_to_jump)\n                           return;\n\n                        dp16 += skip;\n                        sp16 += skip;\n                        row_width -= bytes_to_jump;\n                     }\n                     while (bytes_to_copy <= row_width);\n\n                     /* End of row - 1 byte left, bytes_to_copy > row_width: */\n                     dp = (png_bytep)dp16;\n                     sp = (png_const_bytep)sp16;\n                     do\n                        *dp++ = *sp++;\n                     while (--row_width > 0);\n                     return;\n                  }\n               }\n#endif /* ALIGN_TYPE code */\n\n               /* The true default - use a memcpy: */\n               for (;;)\n               {\n                  memcpy(dp, sp, bytes_to_copy);\n\n                  if (row_width <= bytes_to_jump)\n                     return;\n\n                  sp += bytes_to_jump;\n                  dp += bytes_to_jump;\n                  row_width -= bytes_to_jump;\n                  if (bytes_to_copy > row_width)\n                     bytes_to_copy = (unsigned int)/*SAFE*/row_width;\n               }\n         }\n\n         /* NOT REACHED*/\n      } /* pixel_depth >= 8 */\n\n      /* Here if pixel_depth < 8 to check 'end_ptr' below. */\n   }\n   else\n#endif /* READ_INTERLACING */\n\n   /* If here then the switch above wasn't used so just memcpy the whole row\n    * from the temporary row buffer (notice that this overwrites the end of the\n    * destination row if it is a partial byte.)\n    */\n   memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));\n\n   /* Restore the overwritten bits from the last byte if necessary. */\n   if (end_ptr != NULL)\n      *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask));\n}\n\n#ifdef PNG_READ_INTERLACING_SUPPORTED\nvoid /* PRIVATE */\npng_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,\n    png_uint_32 transformations /* Because these may affect the byte layout */)\n{\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n   /* Offset to next interlace block */\n   static const unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   png_debug(1, \"in png_do_read_interlace\");\n   if (row != NULL && row_info != NULL)\n   {\n      png_uint_32 final_width;\n\n      final_width = row_info->width * png_pass_inc[pass];\n\n      switch (row_info->pixel_depth)\n      {\n         case 1:\n         {\n            png_bytep sp = row + (size_t)((row_info->width - 1) >> 3);\n            png_bytep dp = row + (size_t)((final_width - 1) >> 3);\n            unsigned int sshift, dshift;\n            unsigned int s_start, s_end;\n            int s_inc;\n            int jstop = (int)png_pass_inc[pass];\n            png_byte v;\n            png_uint_32 i;\n            int j;\n\n#ifdef PNG_READ_PACKSWAP_SUPPORTED\n            if ((transformations & PNG_PACKSWAP) != 0)\n            {\n                sshift = ((row_info->width + 7) & 0x07);\n                dshift = ((final_width + 7) & 0x07);\n                s_start = 7;\n                s_end = 0;\n                s_inc = -1;\n            }\n\n            else\n#endif\n            {\n                sshift = 7 - ((row_info->width + 7) & 0x07);\n                dshift = 7 - ((final_width + 7) & 0x07);\n                s_start = 0;\n                s_end = 7;\n                s_inc = 1;\n            }\n\n            for (i = 0; i < row_info->width; i++)\n            {\n               v = (png_byte)((*sp >> sshift) & 0x01);\n               for (j = 0; j < jstop; j++)\n               {\n                  unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));\n                  tmp |= (unsigned int)(v << dshift);\n                  *dp = (png_byte)(tmp & 0xff);\n\n                  if (dshift == s_end)\n                  {\n                     dshift = s_start;\n                     dp--;\n                  }\n\n                  else\n                     dshift = (unsigned int)((int)dshift + s_inc);\n               }\n\n               if (sshift == s_end)\n               {\n                  sshift = s_start;\n                  sp--;\n               }\n\n               else\n                  sshift = (unsigned int)((int)sshift + s_inc);\n            }\n            break;\n         }\n\n         case 2:\n         {\n            png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);\n            png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);\n            unsigned int sshift, dshift;\n            unsigned int s_start, s_end;\n            int s_inc;\n            int jstop = (int)png_pass_inc[pass];\n            png_uint_32 i;\n\n#ifdef PNG_READ_PACKSWAP_SUPPORTED\n            if ((transformations & PNG_PACKSWAP) != 0)\n            {\n               sshift = (((row_info->width + 3) & 0x03) << 1);\n               dshift = (((final_width + 3) & 0x03) << 1);\n               s_start = 6;\n               s_end = 0;\n               s_inc = -2;\n            }\n\n            else\n#endif\n            {\n               sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1);\n               dshift = ((3 - ((final_width + 3) & 0x03)) << 1);\n               s_start = 0;\n               s_end = 6;\n               s_inc = 2;\n            }\n\n            for (i = 0; i < row_info->width; i++)\n            {\n               png_byte v;\n               int j;\n\n               v = (png_byte)((*sp >> sshift) & 0x03);\n               for (j = 0; j < jstop; j++)\n               {\n                  unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));\n                  tmp |= (unsigned int)(v << dshift);\n                  *dp = (png_byte)(tmp & 0xff);\n\n                  if (dshift == s_end)\n                  {\n                     dshift = s_start;\n                     dp--;\n                  }\n\n                  else\n                     dshift = (unsigned int)((int)dshift + s_inc);\n               }\n\n               if (sshift == s_end)\n               {\n                  sshift = s_start;\n                  sp--;\n               }\n\n               else\n                  sshift = (unsigned int)((int)sshift + s_inc);\n            }\n            break;\n         }\n\n         case 4:\n         {\n            png_bytep sp = row + (size_t)((row_info->width - 1) >> 1);\n            png_bytep dp = row + (size_t)((final_width - 1) >> 1);\n            unsigned int sshift, dshift;\n            unsigned int s_start, s_end;\n            int s_inc;\n            png_uint_32 i;\n            int jstop = (int)png_pass_inc[pass];\n\n#ifdef PNG_READ_PACKSWAP_SUPPORTED\n            if ((transformations & PNG_PACKSWAP) != 0)\n            {\n               sshift = (((row_info->width + 1) & 0x01) << 2);\n               dshift = (((final_width + 1) & 0x01) << 2);\n               s_start = 4;\n               s_end = 0;\n               s_inc = -4;\n            }\n\n            else\n#endif\n            {\n               sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2);\n               dshift = ((1 - ((final_width + 1) & 0x01)) << 2);\n               s_start = 0;\n               s_end = 4;\n               s_inc = 4;\n            }\n\n            for (i = 0; i < row_info->width; i++)\n            {\n               png_byte v = (png_byte)((*sp >> sshift) & 0x0f);\n               int j;\n\n               for (j = 0; j < jstop; j++)\n               {\n                  unsigned int tmp = *dp & (0xf0f >> (4 - dshift));\n                  tmp |= (unsigned int)(v << dshift);\n                  *dp = (png_byte)(tmp & 0xff);\n\n                  if (dshift == s_end)\n                  {\n                     dshift = s_start;\n                     dp--;\n                  }\n\n                  else\n                     dshift = (unsigned int)((int)dshift + s_inc);\n               }\n\n               if (sshift == s_end)\n               {\n                  sshift = s_start;\n                  sp--;\n               }\n\n               else\n                  sshift = (unsigned int)((int)sshift + s_inc);\n            }\n            break;\n         }\n\n         default:\n         {\n            size_t pixel_bytes = (row_info->pixel_depth >> 3);\n\n            png_bytep sp = row + (size_t)(row_info->width - 1)\n                * pixel_bytes;\n\n            png_bytep dp = row + (size_t)(final_width - 1) * pixel_bytes;\n\n            int jstop = (int)png_pass_inc[pass];\n            png_uint_32 i;\n\n            for (i = 0; i < row_info->width; i++)\n            {\n               png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */\n               int j;\n\n               memcpy(v, sp, pixel_bytes);\n\n               for (j = 0; j < jstop; j++)\n               {\n                  memcpy(dp, v, pixel_bytes);\n                  dp -= pixel_bytes;\n               }\n\n               sp -= pixel_bytes;\n            }\n            break;\n         }\n      }\n\n      row_info->width = final_width;\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);\n   }\n#ifndef PNG_READ_PACKSWAP_SUPPORTED\n   PNG_UNUSED(transformations)  /* Silence compiler warning */\n#endif\n}\n#endif /* READ_INTERLACING */\n\nstatic void\npng_read_filter_row_sub(png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row)\n{\n   size_t i;\n   size_t istop = row_info->rowbytes;\n   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;\n   png_bytep rp = row + bpp;\n\n   PNG_UNUSED(prev_row)\n\n   for (i = bpp; i < istop; i++)\n   {\n      *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);\n      rp++;\n   }\n}\n\nstatic void\npng_read_filter_row_up(png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row)\n{\n   size_t i;\n   size_t istop = row_info->rowbytes;\n   png_bytep rp = row;\n   png_const_bytep pp = prev_row;\n\n   for (i = 0; i < istop; i++)\n   {\n      *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);\n      rp++;\n   }\n}\n\nstatic void\npng_read_filter_row_avg(png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row)\n{\n   size_t i;\n   png_bytep rp = row;\n   png_const_bytep pp = prev_row;\n   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;\n   size_t istop = row_info->rowbytes - bpp;\n\n   for (i = 0; i < bpp; i++)\n   {\n      *rp = (png_byte)(((int)(*rp) +\n         ((int)(*pp++) / 2 )) & 0xff);\n\n      rp++;\n   }\n\n   for (i = 0; i < istop; i++)\n   {\n      *rp = (png_byte)(((int)(*rp) +\n         (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);\n\n      rp++;\n   }\n}\n\nstatic void\npng_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row)\n{\n   png_bytep rp_end = row + row_info->rowbytes;\n   int a, c;\n\n   /* First pixel/byte */\n   c = *prev_row++;\n   a = *row + c;\n   *row++ = (png_byte)a;\n\n   /* Remainder */\n   while (row < rp_end)\n   {\n      int b, pa, pb, pc, p;\n\n      a &= 0xff; /* From previous iteration or start */\n      b = *prev_row++;\n\n      p = b - c;\n      pc = a - c;\n\n#ifdef PNG_USE_ABS\n      pa = abs(p);\n      pb = abs(pc);\n      pc = abs(p + pc);\n#else\n      pa = p < 0 ? -p : p;\n      pb = pc < 0 ? -pc : pc;\n      pc = (p + pc) < 0 ? -(p + pc) : p + pc;\n#endif\n\n      /* Find the best predictor, the least of pa, pb, pc favoring the earlier\n       * ones in the case of a tie.\n       */\n      if (pb < pa)\n      {\n         pa = pb; a = b;\n      }\n      if (pc < pa) a = c;\n\n      /* Calculate the current pixel in a, and move the previous row pixel to c\n       * for the next time round the loop\n       */\n      c = b;\n      a += *row;\n      *row++ = (png_byte)a;\n   }\n}\n\nstatic void\npng_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row)\n{\n   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;\n   png_bytep rp_end = row + bpp;\n\n   /* Process the first pixel in the row completely (this is the same as 'up'\n    * because there is only one candidate predictor for the first row).\n    */\n   while (row < rp_end)\n   {\n      int a = *row + *prev_row++;\n      *row++ = (png_byte)a;\n   }\n\n   /* Remainder */\n   rp_end = rp_end + (row_info->rowbytes - bpp);\n\n   while (row < rp_end)\n   {\n      int a, b, c, pa, pb, pc, p;\n\n      c = *(prev_row - bpp);\n      a = *(row - bpp);\n      b = *prev_row++;\n\n      p = b - c;\n      pc = a - c;\n\n#ifdef PNG_USE_ABS\n      pa = abs(p);\n      pb = abs(pc);\n      pc = abs(p + pc);\n#else\n      pa = p < 0 ? -p : p;\n      pb = pc < 0 ? -pc : pc;\n      pc = (p + pc) < 0 ? -(p + pc) : p + pc;\n#endif\n\n      if (pb < pa)\n      {\n         pa = pb; a = b;\n      }\n      if (pc < pa) a = c;\n\n      a += *row;\n      *row++ = (png_byte)a;\n   }\n}\n\nstatic void\npng_init_filter_functions(png_structrp pp)\n   /* This function is called once for every PNG image (except for PNG images\n    * that only use PNG_FILTER_VALUE_NONE for all rows) to set the\n    * implementations required to reverse the filtering of PNG rows.  Reversing\n    * the filter is the first transformation performed on the row data.  It is\n    * performed in place, therefore an implementation can be selected based on\n    * the image pixel format.  If the implementation depends on image width then\n    * take care to ensure that it works correctly if the image is interlaced -\n    * interlacing causes the actual row width to vary.\n    */\n{\n   unsigned int bpp = (pp->pixel_depth + 7) >> 3;\n\n   pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub;\n   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up;\n   pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg;\n   if (bpp == 1)\n      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =\n         png_read_filter_row_paeth_1byte_pixel;\n   else\n      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =\n         png_read_filter_row_paeth_multibyte_pixel;\n\n#ifdef PNG_FILTER_OPTIMIZATIONS\n   /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to\n    * call to install hardware optimizations for the above functions; simply\n    * replace whatever elements of the pp->read_filter[] array with a hardware\n    * specific (or, for that matter, generic) optimization.\n    *\n    * To see an example of this examine what configure.ac does when\n    * --enable-arm-neon is specified on the command line.\n    */\n   PNG_FILTER_OPTIMIZATIONS(pp, bpp);\n#endif\n}\n\nvoid /* PRIVATE */\npng_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row,\n    png_const_bytep prev_row, int filter)\n{\n   /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define\n    * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic\n    * implementations.  See png_init_filter_functions above.\n    */\n   if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)\n   {\n      if (pp->read_filter[0] == NULL)\n         png_init_filter_functions(pp);\n\n      pp->read_filter[filter-1](row_info, row, prev_row);\n   }\n}\n\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\nvoid /* PRIVATE */\npng_read_IDAT_data(png_structrp png_ptr, png_bytep output,\n    png_alloc_size_t avail_out)\n{\n   /* Loop reading IDATs and decompressing the result into output[avail_out] */\n   png_ptr->zstream.next_out = output;\n   png_ptr->zstream.avail_out = 0; /* safety: set below */\n\n   if (output == NULL)\n      avail_out = 0;\n\n   do\n   {\n      int ret;\n      png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];\n\n      if (png_ptr->zstream.avail_in == 0)\n      {\n         uInt avail_in;\n         png_bytep buffer;\n\n         while (png_ptr->idat_size == 0)\n         {\n            png_crc_finish(png_ptr, 0);\n\n            png_ptr->idat_size = png_read_chunk_header(png_ptr);\n            /* This is an error even in the 'check' case because the code just\n             * consumed a non-IDAT header.\n             */\n            if (png_ptr->chunk_name != png_IDAT)\n               png_error(png_ptr, \"Not enough image data\");\n         }\n\n         avail_in = png_ptr->IDAT_read_size;\n\n         if (avail_in > png_ptr->idat_size)\n            avail_in = (uInt)png_ptr->idat_size;\n\n         /* A PNG with a gradually increasing IDAT size will defeat this attempt\n          * to minimize memory usage by causing lots of re-allocs, but\n          * realistically doing IDAT_read_size re-allocs is not likely to be a\n          * big problem.\n          */\n         buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);\n\n         png_crc_read(png_ptr, buffer, avail_in);\n         png_ptr->idat_size -= avail_in;\n\n         png_ptr->zstream.next_in = buffer;\n         png_ptr->zstream.avail_in = avail_in;\n      }\n\n      /* And set up the output side. */\n      if (output != NULL) /* standard read */\n      {\n         uInt out = ZLIB_IO_MAX;\n\n         if (out > avail_out)\n            out = (uInt)avail_out;\n\n         avail_out -= out;\n         png_ptr->zstream.avail_out = out;\n      }\n\n      else /* after last row, checking for end */\n      {\n         png_ptr->zstream.next_out = tmpbuf;\n         png_ptr->zstream.avail_out = (sizeof tmpbuf);\n      }\n\n      /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the\n       * process.  If the LZ stream is truncated the sequential reader will\n       * terminally damage the stream, above, by reading the chunk header of the\n       * following chunk (it then exits with png_error).\n       *\n       * TODO: deal more elegantly with truncated IDAT lists.\n       */\n      ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH);\n\n      /* Take the unconsumed output back. */\n      if (output != NULL)\n         avail_out += png_ptr->zstream.avail_out;\n\n      else /* avail_out counts the extra bytes */\n         avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out;\n\n      png_ptr->zstream.avail_out = 0;\n\n      if (ret == Z_STREAM_END)\n      {\n         /* Do this for safety; we won't read any more into this row. */\n         png_ptr->zstream.next_out = NULL;\n\n         png_ptr->mode |= PNG_AFTER_IDAT;\n         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\n\n         if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)\n            png_chunk_benign_error(png_ptr, \"Extra compressed data\");\n         break;\n      }\n\n      if (ret != Z_OK)\n      {\n         png_zstream_error(png_ptr, ret);\n\n         if (output != NULL)\n            png_chunk_error(png_ptr, png_ptr->zstream.msg);\n\n         else /* checking */\n         {\n            png_chunk_benign_error(png_ptr, png_ptr->zstream.msg);\n            return;\n         }\n      }\n   } while (avail_out > 0);\n\n   if (avail_out > 0)\n   {\n      /* The stream ended before the image; this is the same as too few IDATs so\n       * should be handled the same way.\n       */\n      if (output != NULL)\n         png_error(png_ptr, \"Not enough image data\");\n\n      else /* the deflate stream contained extra data */\n         png_chunk_benign_error(png_ptr, \"Too much image data\");\n   }\n}\n\nvoid /* PRIVATE */\npng_read_finish_IDAT(png_structrp png_ptr)\n{\n   /* We don't need any more data and the stream should have ended, however the\n    * LZ end code may actually not have been processed.  In this case we must\n    * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk\n    * may still remain to be consumed.\n    */\n   if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)\n   {\n      /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in\n       * the compressed stream, but the stream may be damaged too, so even after\n       * this call we may need to terminate the zstream ownership.\n       */\n      png_read_IDAT_data(png_ptr, NULL, 0);\n      png_ptr->zstream.next_out = NULL; /* safety */\n\n      /* Now clear everything out for safety; the following may not have been\n       * done.\n       */\n      if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)\n      {\n         png_ptr->mode |= PNG_AFTER_IDAT;\n         png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;\n      }\n   }\n\n   /* If the zstream has not been released do it now *and* terminate the reading\n    * of the final IDAT chunk.\n    */\n   if (png_ptr->zowner == png_IDAT)\n   {\n      /* Always do this; the pointers otherwise point into the read buffer. */\n      png_ptr->zstream.next_in = NULL;\n      png_ptr->zstream.avail_in = 0;\n\n      /* Now we no longer own the zstream. */\n      png_ptr->zowner = 0;\n\n      /* The slightly weird semantics of the sequential IDAT reading is that we\n       * are always in or at the end of an IDAT chunk, so we always need to do a\n       * crc_finish here.  If idat_size is non-zero we also need to read the\n       * spurious bytes at the end of the chunk now.\n       */\n      (void)png_crc_finish(png_ptr, png_ptr->idat_size);\n   }\n}\n\nvoid /* PRIVATE */\npng_read_finish_row(png_structrp png_ptr)\n{\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   /* Start of interlace block in the y direction */\n   static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};\n\n   /* Offset to next interlace block in the y direction */\n   static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};\n\n   png_debug(1, \"in png_read_finish_row\");\n   png_ptr->row_number++;\n   if (png_ptr->row_number < png_ptr->num_rows)\n      return;\n\n   if (png_ptr->interlaced != 0)\n   {\n      png_ptr->row_number = 0;\n\n      /* TO DO: don't do this if prev_row isn't needed (requires\n       * read-ahead of the next row's filter byte.\n       */\n      memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);\n\n      do\n      {\n         png_ptr->pass++;\n\n         if (png_ptr->pass >= 7)\n            break;\n\n         png_ptr->iwidth = (png_ptr->width +\n            png_pass_inc[png_ptr->pass] - 1 -\n            png_pass_start[png_ptr->pass]) /\n            png_pass_inc[png_ptr->pass];\n\n         if ((png_ptr->transformations & PNG_INTERLACE) == 0)\n         {\n            png_ptr->num_rows = (png_ptr->height +\n                png_pass_yinc[png_ptr->pass] - 1 -\n                png_pass_ystart[png_ptr->pass]) /\n                png_pass_yinc[png_ptr->pass];\n         }\n\n         else  /* if (png_ptr->transformations & PNG_INTERLACE) */\n            break; /* libpng deinterlacing sees every row */\n\n      } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0);\n\n      if (png_ptr->pass < 7)\n         return;\n   }\n\n   /* Here after at the end of the last row of the last pass. */\n   png_read_finish_IDAT(png_ptr);\n}\n#endif /* SEQUENTIAL_READ */\n\nvoid /* PRIVATE */\npng_read_start_row(png_structrp png_ptr)\n{\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   /* Start of interlace block in the y direction */\n   static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};\n\n   /* Offset to next interlace block in the y direction */\n   static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};\n\n   unsigned int max_pixel_depth;\n   size_t row_bytes;\n\n   png_debug(1, \"in png_read_start_row\");\n\n#ifdef PNG_READ_TRANSFORMS_SUPPORTED\n   png_init_read_transformations(png_ptr);\n#endif\n   if (png_ptr->interlaced != 0)\n   {\n      if ((png_ptr->transformations & PNG_INTERLACE) == 0)\n         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -\n             png_pass_ystart[0]) / png_pass_yinc[0];\n\n      else\n         png_ptr->num_rows = png_ptr->height;\n\n      png_ptr->iwidth = (png_ptr->width +\n          png_pass_inc[png_ptr->pass] - 1 -\n          png_pass_start[png_ptr->pass]) /\n          png_pass_inc[png_ptr->pass];\n   }\n\n   else\n   {\n      png_ptr->num_rows = png_ptr->height;\n      png_ptr->iwidth = png_ptr->width;\n   }\n\n   max_pixel_depth = (unsigned int)png_ptr->pixel_depth;\n\n   /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of\n    * calculations to calculate the final pixel depth, then\n    * png_do_read_transforms actually does the transforms.  This means that the\n    * code which effectively calculates this value is actually repeated in three\n    * separate places.  They must all match.  Innocent changes to the order of\n    * transformations can and will break libpng in a way that causes memory\n    * overwrites.\n    *\n    * TODO: fix this.\n    */\n#ifdef PNG_READ_PACK_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8)\n      max_pixel_depth = 8;\n#endif\n\n#ifdef PNG_READ_EXPAND_SUPPORTED\n   if ((png_ptr->transformations & PNG_EXPAND) != 0)\n   {\n      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         if (png_ptr->num_trans != 0)\n            max_pixel_depth = 32;\n\n         else\n            max_pixel_depth = 24;\n      }\n\n      else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)\n      {\n         if (max_pixel_depth < 8)\n            max_pixel_depth = 8;\n\n         if (png_ptr->num_trans != 0)\n            max_pixel_depth *= 2;\n      }\n\n      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)\n      {\n         if (png_ptr->num_trans != 0)\n         {\n            max_pixel_depth *= 4;\n            max_pixel_depth /= 3;\n         }\n      }\n   }\n#endif\n\n#ifdef PNG_READ_EXPAND_16_SUPPORTED\n   if ((png_ptr->transformations & PNG_EXPAND_16) != 0)\n   {\n#  ifdef PNG_READ_EXPAND_SUPPORTED\n      /* In fact it is an error if it isn't supported, but checking is\n       * the safe way.\n       */\n      if ((png_ptr->transformations & PNG_EXPAND) != 0)\n      {\n         if (png_ptr->bit_depth < 16)\n            max_pixel_depth *= 2;\n      }\n      else\n#  endif\n      png_ptr->transformations &= ~PNG_EXPAND_16;\n   }\n#endif\n\n#ifdef PNG_READ_FILLER_SUPPORTED\n   if ((png_ptr->transformations & (PNG_FILLER)) != 0)\n   {\n      if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)\n      {\n         if (max_pixel_depth <= 8)\n            max_pixel_depth = 16;\n\n         else\n            max_pixel_depth = 32;\n      }\n\n      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||\n         png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         if (max_pixel_depth <= 32)\n            max_pixel_depth = 32;\n\n         else\n            max_pixel_depth = 64;\n      }\n   }\n#endif\n\n#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED\n   if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)\n   {\n      if (\n#ifdef PNG_READ_EXPAND_SUPPORTED\n          (png_ptr->num_trans != 0 &&\n          (png_ptr->transformations & PNG_EXPAND) != 0) ||\n#endif\n#ifdef PNG_READ_FILLER_SUPPORTED\n          (png_ptr->transformations & (PNG_FILLER)) != 0 ||\n#endif\n          png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n      {\n         if (max_pixel_depth <= 16)\n            max_pixel_depth = 32;\n\n         else\n            max_pixel_depth = 64;\n      }\n\n      else\n      {\n         if (max_pixel_depth <= 8)\n         {\n            if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n               max_pixel_depth = 32;\n\n            else\n               max_pixel_depth = 24;\n         }\n\n         else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n            max_pixel_depth = 64;\n\n         else\n            max_pixel_depth = 48;\n      }\n   }\n#endif\n\n#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \\\ndefined(PNG_USER_TRANSFORM_PTR_SUPPORTED)\n   if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)\n   {\n      unsigned int user_pixel_depth = png_ptr->user_transform_depth *\n         png_ptr->user_transform_channels;\n\n      if (user_pixel_depth > max_pixel_depth)\n         max_pixel_depth = user_pixel_depth;\n   }\n#endif\n\n   /* This value is stored in png_struct and double checked in the row read\n    * code.\n    */\n   png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth;\n   png_ptr->transformed_pixel_depth = 0; /* calculated on demand */\n\n   /* Align the width on the next larger 8 pixels.  Mainly used\n    * for interlacing\n    */\n   row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));\n   /* Calculate the maximum bytes needed, adding a byte and a pixel\n    * for safety's sake\n    */\n   row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +\n       1 + ((max_pixel_depth + 7) >> 3U);\n\n#ifdef PNG_MAX_MALLOC_64K\n   if (row_bytes > (png_uint_32)65536L)\n      png_error(png_ptr, \"This image requires a row greater than 64KB\");\n#endif\n\n   if (row_bytes + 48 > png_ptr->old_big_row_buf_size)\n   {\n      png_free(png_ptr, png_ptr->big_row_buf);\n      png_free(png_ptr, png_ptr->big_prev_row);\n\n      if (png_ptr->interlaced != 0)\n         png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,\n             row_bytes + 48);\n\n      else\n         png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48);\n\n      png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48);\n\n#ifdef PNG_ALIGNED_MEMORY_SUPPORTED\n      /* Use 16-byte aligned memory for row_buf with at least 16 bytes\n       * of padding before and after row_buf; treat prev_row similarly.\n       * NOTE: the alignment is to the start of the pixels, one beyond the start\n       * of the buffer, because of the filter byte.  Prior to libpng 1.5.6 this\n       * was incorrect; the filter byte was aligned, which had the exact\n       * opposite effect of that intended.\n       */\n      {\n         png_bytep temp = png_ptr->big_row_buf + 32;\n         int extra = (int)((temp - (png_bytep)0) & 0x0f);\n         png_ptr->row_buf = temp - extra - 1/*filter byte*/;\n\n         temp = png_ptr->big_prev_row + 32;\n         extra = (int)((temp - (png_bytep)0) & 0x0f);\n         png_ptr->prev_row = temp - extra - 1/*filter byte*/;\n      }\n\n#else\n      /* Use 31 bytes of padding before and 17 bytes after row_buf. */\n      png_ptr->row_buf = png_ptr->big_row_buf + 31;\n      png_ptr->prev_row = png_ptr->big_prev_row + 31;\n#endif\n      png_ptr->old_big_row_buf_size = row_bytes + 48;\n   }\n\n#ifdef PNG_MAX_MALLOC_64K\n   if (png_ptr->rowbytes > 65535)\n      png_error(png_ptr, \"This image requires a row greater than 64KB\");\n\n#endif\n   if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))\n      png_error(png_ptr, \"Row has too many bytes to allocate in memory\");\n\n   memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);\n\n   png_debug1(3, \"width = %u,\", png_ptr->width);\n   png_debug1(3, \"height = %u,\", png_ptr->height);\n   png_debug1(3, \"iwidth = %u,\", png_ptr->iwidth);\n   png_debug1(3, \"num_rows = %u,\", png_ptr->num_rows);\n   png_debug1(3, \"rowbytes = %lu,\", (unsigned long)png_ptr->rowbytes);\n   png_debug1(3, \"irowbytes = %lu\",\n       (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);\n\n   /* The sequential reader needs a buffer for IDAT, but the progressive reader\n    * does not, so free the read buffer now regardless; the sequential reader\n    * reallocates it on demand.\n    */\n   if (png_ptr->read_buffer != NULL)\n   {\n      png_bytep buffer = png_ptr->read_buffer;\n\n      png_ptr->read_buffer_size = 0;\n      png_ptr->read_buffer = NULL;\n      png_free(png_ptr, buffer);\n   }\n\n   /* Finally claim the zstream for the inflate of the IDAT data, use the bits\n    * value from the stream (note that this will result in a fatal error if the\n    * IDAT stream has a bogus deflate header window_bits value, but this should\n    * not be happening any longer!)\n    */\n   if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK)\n      png_error(png_ptr, png_ptr->zstream.msg);\n\n   png_ptr->flags |= PNG_FLAG_ROW_INIT;\n}\n#endif /* READ */\n"
  },
  {
    "path": "dlib/external/libpng/pngset.c",
    "content": "\n/* pngset.c - storage of image information into info struct\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * The functions here are used during reads to store data from the file\n * into the info struct, and during writes to store application data\n * into the info struct for writing into the file.  This abstracts the\n * info struct and allows us to change the structure in the future.\n */\n\n#include \"pngpriv.h\"\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n\n#ifdef PNG_bKGD_SUPPORTED\nvoid PNGAPI\npng_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_color_16p background)\n{\n   png_debug1(1, \"in %s storage function\", \"bKGD\");\n\n   if (png_ptr == NULL || info_ptr == NULL || background == NULL)\n      return;\n\n   info_ptr->background = *background;\n   info_ptr->valid |= PNG_INFO_bKGD;\n}\n#endif\n\n#ifdef PNG_cHRM_SUPPORTED\nvoid PNGFAPI\npng_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,\n    png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,\n    png_fixed_point blue_x, png_fixed_point blue_y)\n{\n   png_xy xy;\n\n   png_debug1(1, \"in %s storage function\", \"cHRM fixed\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   xy.redx = red_x;\n   xy.redy = red_y;\n   xy.greenx = green_x;\n   xy.greeny = green_y;\n   xy.bluex = blue_x;\n   xy.bluey = blue_y;\n   xy.whitex = white_x;\n   xy.whitey = white_y;\n\n   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,\n       2/* override with app values*/) != 0)\n      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;\n\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n\nvoid PNGFAPI\npng_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_fixed_point int_red_X, png_fixed_point int_red_Y,\n    png_fixed_point int_red_Z, png_fixed_point int_green_X,\n    png_fixed_point int_green_Y, png_fixed_point int_green_Z,\n    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,\n    png_fixed_point int_blue_Z)\n{\n   png_XYZ XYZ;\n\n   png_debug1(1, \"in %s storage function\", \"cHRM XYZ fixed\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   XYZ.red_X = int_red_X;\n   XYZ.red_Y = int_red_Y;\n   XYZ.red_Z = int_red_Z;\n   XYZ.green_X = int_green_X;\n   XYZ.green_Y = int_green_Y;\n   XYZ.green_Z = int_green_Z;\n   XYZ.blue_X = int_blue_X;\n   XYZ.blue_Y = int_blue_Y;\n   XYZ.blue_Z = int_blue_Z;\n\n   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace,\n       &XYZ, 2) != 0)\n      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;\n\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,\n    double white_x, double white_y, double red_x, double red_y,\n    double green_x, double green_y, double blue_x, double blue_y)\n{\n   png_set_cHRM_fixed(png_ptr, info_ptr,\n       png_fixed(png_ptr, white_x, \"cHRM White X\"),\n       png_fixed(png_ptr, white_y, \"cHRM White Y\"),\n       png_fixed(png_ptr, red_x, \"cHRM Red X\"),\n       png_fixed(png_ptr, red_y, \"cHRM Red Y\"),\n       png_fixed(png_ptr, green_x, \"cHRM Green X\"),\n       png_fixed(png_ptr, green_y, \"cHRM Green Y\"),\n       png_fixed(png_ptr, blue_x, \"cHRM Blue X\"),\n       png_fixed(png_ptr, blue_y, \"cHRM Blue Y\"));\n}\n\nvoid PNGAPI\npng_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,\n    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,\n    double blue_X, double blue_Y, double blue_Z)\n{\n   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,\n       png_fixed(png_ptr, red_X, \"cHRM Red X\"),\n       png_fixed(png_ptr, red_Y, \"cHRM Red Y\"),\n       png_fixed(png_ptr, red_Z, \"cHRM Red Z\"),\n       png_fixed(png_ptr, green_X, \"cHRM Green X\"),\n       png_fixed(png_ptr, green_Y, \"cHRM Green Y\"),\n       png_fixed(png_ptr, green_Z, \"cHRM Green Z\"),\n       png_fixed(png_ptr, blue_X, \"cHRM Blue X\"),\n       png_fixed(png_ptr, blue_Y, \"cHRM Blue Y\"),\n       png_fixed(png_ptr, blue_Z, \"cHRM Blue Z\"));\n}\n#  endif /* FLOATING_POINT */\n\n#endif /* cHRM */\n\n#ifdef PNG_eXIf_SUPPORTED\nvoid PNGAPI\npng_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_bytep eXIf_buf)\n{\n  png_warning(png_ptr, \"png_set_eXIf does not work; use png_set_eXIf_1\");\n  PNG_UNUSED(info_ptr)\n  PNG_UNUSED(eXIf_buf)\n}\n\nvoid PNGAPI\npng_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_uint_32 num_exif, png_bytep eXIf_buf)\n{\n   int i;\n\n   png_debug1(1, \"in %s storage function\", \"eXIf\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if (info_ptr->exif)\n   {\n      png_free(png_ptr, info_ptr->exif);\n      info_ptr->exif = NULL;\n   }\n\n   info_ptr->num_exif = num_exif;\n\n   info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,\n       info_ptr->num_exif));\n\n   if (info_ptr->exif == NULL)\n   {\n      png_warning(png_ptr, \"Insufficient memory for eXIf chunk data\");\n      return;\n   }\n\n   info_ptr->free_me |= PNG_FREE_EXIF;\n\n   for (i = 0; i < (int) info_ptr->num_exif; i++)\n      info_ptr->exif[i] = eXIf_buf[i];\n\n   info_ptr->valid |= PNG_INFO_eXIf;\n}\n#endif /* eXIf */\n\n#ifdef PNG_gAMA_SUPPORTED\nvoid PNGFAPI\npng_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_fixed_point file_gamma)\n{\n   png_debug1(1, \"in %s storage function\", \"gAMA\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)\n{\n   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,\n       \"png_set_gAMA\"));\n}\n#  endif\n#endif\n\n#ifdef PNG_hIST_SUPPORTED\nvoid PNGAPI\npng_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_uint_16p hist)\n{\n   int i;\n\n   png_debug1(1, \"in %s storage function\", \"hIST\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if (info_ptr->num_palette == 0 || info_ptr->num_palette\n       > PNG_MAX_PALETTE_LENGTH)\n   {\n      png_warning(png_ptr,\n          \"Invalid palette size, hIST allocation skipped\");\n\n      return;\n   }\n\n   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);\n\n   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in\n    * version 1.2.1\n    */\n   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,\n       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));\n\n   if (info_ptr->hist == NULL)\n   {\n      png_warning(png_ptr, \"Insufficient memory for hIST chunk data\");\n\n      return;\n   }\n\n   info_ptr->free_me |= PNG_FREE_HIST;\n\n   for (i = 0; i < info_ptr->num_palette; i++)\n      info_ptr->hist[i] = hist[i];\n\n   info_ptr->valid |= PNG_INFO_hIST;\n}\n#endif\n\nvoid PNGAPI\npng_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_uint_32 width, png_uint_32 height, int bit_depth,\n    int color_type, int interlace_type, int compression_type,\n    int filter_type)\n{\n   png_debug1(1, \"in %s storage function\", \"IHDR\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   info_ptr->width = width;\n   info_ptr->height = height;\n   info_ptr->bit_depth = (png_byte)bit_depth;\n   info_ptr->color_type = (png_byte)color_type;\n   info_ptr->compression_type = (png_byte)compression_type;\n   info_ptr->filter_type = (png_byte)filter_type;\n   info_ptr->interlace_type = (png_byte)interlace_type;\n\n   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,\n       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,\n       info_ptr->compression_type, info_ptr->filter_type);\n\n   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      info_ptr->channels = 1;\n\n   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      info_ptr->channels = 3;\n\n   else\n      info_ptr->channels = 1;\n\n   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      info_ptr->channels++;\n\n   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);\n\n   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);\n}\n\n#ifdef PNG_oFFs_SUPPORTED\nvoid PNGAPI\npng_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_int_32 offset_x, png_int_32 offset_y, int unit_type)\n{\n   png_debug1(1, \"in %s storage function\", \"oFFs\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   info_ptr->x_offset = offset_x;\n   info_ptr->y_offset = offset_y;\n   info_ptr->offset_unit_type = (png_byte)unit_type;\n   info_ptr->valid |= PNG_INFO_oFFs;\n}\n#endif\n\n#ifdef PNG_pCAL_SUPPORTED\nvoid PNGAPI\npng_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,\n    int nparams, png_const_charp units, png_charpp params)\n{\n   size_t length;\n   int i;\n\n   png_debug1(1, \"in %s storage function\", \"pCAL\");\n\n   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL\n       || (nparams > 0 && params == NULL))\n      return;\n\n   length = strlen(purpose) + 1;\n   png_debug1(3, \"allocating purpose for info (%lu bytes)\",\n       (unsigned long)length);\n\n   /* TODO: validate format of calibration name and unit name */\n\n   /* Check that the type matches the specification. */\n   if (type < 0 || type > 3)\n   {\n      png_chunk_report(png_ptr, \"Invalid pCAL equation type\",\n            PNG_CHUNK_WRITE_ERROR);\n      return;\n   }\n\n   if (nparams < 0 || nparams > 255)\n   {\n      png_chunk_report(png_ptr, \"Invalid pCAL parameter count\",\n            PNG_CHUNK_WRITE_ERROR);\n      return;\n   }\n\n   /* Validate params[nparams] */\n   for (i=0; i<nparams; ++i)\n   {\n      if (params[i] == NULL ||\n          !png_check_fp_string(params[i], strlen(params[i])))\n      {\n         png_chunk_report(png_ptr, \"Invalid format for pCAL parameter\",\n               PNG_CHUNK_WRITE_ERROR);\n         return;\n      }\n   }\n\n   info_ptr->pcal_purpose = png_voidcast(png_charp,\n       png_malloc_warn(png_ptr, length));\n\n   if (info_ptr->pcal_purpose == NULL)\n   {\n      png_chunk_report(png_ptr, \"Insufficient memory for pCAL purpose\",\n            PNG_CHUNK_WRITE_ERROR);\n      return;\n   }\n\n   memcpy(info_ptr->pcal_purpose, purpose, length);\n\n   png_debug(3, \"storing X0, X1, type, and nparams in info\");\n   info_ptr->pcal_X0 = X0;\n   info_ptr->pcal_X1 = X1;\n   info_ptr->pcal_type = (png_byte)type;\n   info_ptr->pcal_nparams = (png_byte)nparams;\n\n   length = strlen(units) + 1;\n   png_debug1(3, \"allocating units for info (%lu bytes)\",\n       (unsigned long)length);\n\n   info_ptr->pcal_units = png_voidcast(png_charp,\n       png_malloc_warn(png_ptr, length));\n\n   if (info_ptr->pcal_units == NULL)\n   {\n      png_warning(png_ptr, \"Insufficient memory for pCAL units\");\n\n      return;\n   }\n\n   memcpy(info_ptr->pcal_units, units, length);\n\n   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,\n       (size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp)))));\n\n   if (info_ptr->pcal_params == NULL)\n   {\n      png_warning(png_ptr, \"Insufficient memory for pCAL params\");\n\n      return;\n   }\n\n   memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) *\n       (sizeof (png_charp)));\n\n   for (i = 0; i < nparams; i++)\n   {\n      length = strlen(params[i]) + 1;\n      png_debug2(3, \"allocating parameter %d for info (%lu bytes)\", i,\n          (unsigned long)length);\n\n      info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);\n\n      if (info_ptr->pcal_params[i] == NULL)\n      {\n         png_warning(png_ptr, \"Insufficient memory for pCAL parameter\");\n\n         return;\n      }\n\n      memcpy(info_ptr->pcal_params[i], params[i], length);\n   }\n\n   info_ptr->valid |= PNG_INFO_pCAL;\n   info_ptr->free_me |= PNG_FREE_PCAL;\n}\n#endif\n\n#ifdef PNG_sCAL_SUPPORTED\nvoid PNGAPI\npng_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,\n    int unit, png_const_charp swidth, png_const_charp sheight)\n{\n   size_t lengthw = 0, lengthh = 0;\n\n   png_debug1(1, \"in %s storage function\", \"sCAL\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   /* Double check the unit (should never get here with an invalid\n    * unit unless this is an API call.)\n    */\n   if (unit != 1 && unit != 2)\n      png_error(png_ptr, \"Invalid sCAL unit\");\n\n   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||\n       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))\n      png_error(png_ptr, \"Invalid sCAL width\");\n\n   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||\n       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))\n      png_error(png_ptr, \"Invalid sCAL height\");\n\n   info_ptr->scal_unit = (png_byte)unit;\n\n   ++lengthw;\n\n   png_debug1(3, \"allocating unit for info (%u bytes)\", (unsigned int)lengthw);\n\n   info_ptr->scal_s_width = png_voidcast(png_charp,\n       png_malloc_warn(png_ptr, lengthw));\n\n   if (info_ptr->scal_s_width == NULL)\n   {\n      png_warning(png_ptr, \"Memory allocation failed while processing sCAL\");\n\n      return;\n   }\n\n   memcpy(info_ptr->scal_s_width, swidth, lengthw);\n\n   ++lengthh;\n\n   png_debug1(3, \"allocating unit for info (%u bytes)\", (unsigned int)lengthh);\n\n   info_ptr->scal_s_height = png_voidcast(png_charp,\n       png_malloc_warn(png_ptr, lengthh));\n\n   if (info_ptr->scal_s_height == NULL)\n   {\n      png_free (png_ptr, info_ptr->scal_s_width);\n      info_ptr->scal_s_width = NULL;\n\n      png_warning(png_ptr, \"Memory allocation failed while processing sCAL\");\n\n      return;\n   }\n\n   memcpy(info_ptr->scal_s_height, sheight, lengthh);\n\n   info_ptr->valid |= PNG_INFO_sCAL;\n   info_ptr->free_me |= PNG_FREE_SCAL;\n}\n\n#  ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,\n    double width, double height)\n{\n   png_debug1(1, \"in %s storage function\", \"sCAL\");\n\n   /* Check the arguments. */\n   if (width <= 0)\n      png_warning(png_ptr, \"Invalid sCAL width ignored\");\n\n   else if (height <= 0)\n      png_warning(png_ptr, \"Invalid sCAL height ignored\");\n\n   else\n   {\n      /* Convert 'width' and 'height' to ASCII. */\n      char swidth[PNG_sCAL_MAX_DIGITS+1];\n      char sheight[PNG_sCAL_MAX_DIGITS+1];\n\n      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,\n          PNG_sCAL_PRECISION);\n      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,\n          PNG_sCAL_PRECISION);\n\n      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);\n   }\n}\n#  endif\n\n#  ifdef PNG_FIXED_POINT_SUPPORTED\nvoid PNGAPI\npng_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,\n    png_fixed_point width, png_fixed_point height)\n{\n   png_debug1(1, \"in %s storage function\", \"sCAL\");\n\n   /* Check the arguments. */\n   if (width <= 0)\n      png_warning(png_ptr, \"Invalid sCAL width ignored\");\n\n   else if (height <= 0)\n      png_warning(png_ptr, \"Invalid sCAL height ignored\");\n\n   else\n   {\n      /* Convert 'width' and 'height' to ASCII. */\n      char swidth[PNG_sCAL_MAX_DIGITS+1];\n      char sheight[PNG_sCAL_MAX_DIGITS+1];\n\n      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);\n      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);\n\n      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);\n   }\n}\n#  endif\n#endif\n\n#ifdef PNG_pHYs_SUPPORTED\nvoid PNGAPI\npng_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_uint_32 res_x, png_uint_32 res_y, int unit_type)\n{\n   png_debug1(1, \"in %s storage function\", \"pHYs\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   info_ptr->x_pixels_per_unit = res_x;\n   info_ptr->y_pixels_per_unit = res_y;\n   info_ptr->phys_unit_type = (png_byte)unit_type;\n   info_ptr->valid |= PNG_INFO_pHYs;\n}\n#endif\n\nvoid PNGAPI\npng_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,\n    png_const_colorp palette, int num_palette)\n{\n\n   png_uint_32 max_palette_length;\n\n   png_debug1(1, \"in %s storage function\", \"PLTE\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?\n      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;\n\n   if (num_palette < 0 || num_palette > (int) max_palette_length)\n   {\n      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n         png_error(png_ptr, \"Invalid palette length\");\n\n      else\n      {\n         png_warning(png_ptr, \"Invalid palette length\");\n\n         return;\n      }\n   }\n\n   if ((num_palette > 0 && palette == NULL) ||\n      (num_palette == 0\n#        ifdef PNG_MNG_FEATURES_SUPPORTED\n            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0\n#        endif\n      ))\n   {\n      png_error(png_ptr, \"Invalid palette\");\n   }\n\n   /* It may not actually be necessary to set png_ptr->palette here;\n    * we do it for backward compatibility with the way the png_handle_tRNS\n    * function used to do the allocation.\n    *\n    * 1.6.0: the above statement appears to be incorrect; something has to set\n    * the palette inside png_struct on read.\n    */\n   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);\n\n   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead\n    * of num_palette entries, in case of an invalid PNG file or incorrect\n    * call to png_set_PLTE() with too-large sample values.\n    */\n   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,\n       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));\n\n   if (num_palette > 0)\n      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *\n          (sizeof (png_color)));\n   info_ptr->palette = png_ptr->palette;\n   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;\n\n   info_ptr->free_me |= PNG_FREE_PLTE;\n\n   info_ptr->valid |= PNG_INFO_PLTE;\n}\n\n#ifdef PNG_sBIT_SUPPORTED\nvoid PNGAPI\npng_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_color_8p sig_bit)\n{\n   png_debug1(1, \"in %s storage function\", \"sBIT\");\n\n   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)\n      return;\n\n   info_ptr->sig_bit = *sig_bit;\n   info_ptr->valid |= PNG_INFO_sBIT;\n}\n#endif\n\n#ifdef PNG_sRGB_SUPPORTED\nvoid PNGAPI\npng_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)\n{\n   png_debug1(1, \"in %s storage function\", \"sRGB\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n\nvoid PNGAPI\npng_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,\n    int srgb_intent)\n{\n   png_debug1(1, \"in %s storage function\", \"sRGB_gAMA_and_cHRM\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,\n       srgb_intent) != 0)\n   {\n      /* This causes the gAMA and cHRM to be written too */\n      info_ptr->colorspace.flags |=\n         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;\n   }\n\n   png_colorspace_sync_info(png_ptr, info_ptr);\n}\n#endif /* sRGB */\n\n\n#ifdef PNG_iCCP_SUPPORTED\nvoid PNGAPI\npng_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_charp name, int compression_type,\n    png_const_bytep profile, png_uint_32 proflen)\n{\n   png_charp new_iccp_name;\n   png_bytep new_iccp_profile;\n   size_t length;\n\n   png_debug1(1, \"in %s storage function\", \"iCCP\");\n\n   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)\n      return;\n\n   if (compression_type != PNG_COMPRESSION_TYPE_BASE)\n      png_app_error(png_ptr, \"Invalid iCCP compression method\");\n\n   /* Set the colorspace first because this validates the profile; do not\n    * override previously set app cHRM or gAMA here (because likely as not the\n    * application knows better than libpng what the correct values are.)  Pass\n    * the info_ptr color_type field to png_colorspace_set_ICC because in the\n    * write case it has not yet been stored in png_ptr.\n    */\n   {\n      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,\n          proflen, profile, info_ptr->color_type);\n\n      png_colorspace_sync_info(png_ptr, info_ptr);\n\n      /* Don't do any of the copying if the profile was bad, or inconsistent. */\n      if (result == 0)\n         return;\n\n      /* But do write the gAMA and cHRM chunks from the profile. */\n      info_ptr->colorspace.flags |=\n         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;\n   }\n\n   length = strlen(name)+1;\n   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));\n\n   if (new_iccp_name == NULL)\n   {\n      png_benign_error(png_ptr, \"Insufficient memory to process iCCP chunk\");\n\n      return;\n   }\n\n   memcpy(new_iccp_name, name, length);\n   new_iccp_profile = png_voidcast(png_bytep,\n       png_malloc_warn(png_ptr, proflen));\n\n   if (new_iccp_profile == NULL)\n   {\n      png_free(png_ptr, new_iccp_name);\n      png_benign_error(png_ptr,\n          \"Insufficient memory to process iCCP profile\");\n\n      return;\n   }\n\n   memcpy(new_iccp_profile, profile, proflen);\n\n   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);\n\n   info_ptr->iccp_proflen = proflen;\n   info_ptr->iccp_name = new_iccp_name;\n   info_ptr->iccp_profile = new_iccp_profile;\n   info_ptr->free_me |= PNG_FREE_ICCP;\n   info_ptr->valid |= PNG_INFO_iCCP;\n}\n#endif\n\n#ifdef PNG_TEXT_SUPPORTED\nvoid PNGAPI\npng_set_text(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_textp text_ptr, int num_text)\n{\n   int ret;\n   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);\n\n   if (ret != 0)\n      png_error(png_ptr, \"Insufficient memory to store text\");\n}\n\nint /* PRIVATE */\npng_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_textp text_ptr, int num_text)\n{\n   int i;\n\n   png_debug1(1, \"in %lx storage function\", png_ptr == NULL ? 0xabadca11U :\n      (unsigned long)png_ptr->chunk_name);\n\n   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)\n      return(0);\n\n   /* Make sure we have enough space in the \"text\" array in info_struct\n    * to hold all of the incoming text_ptr objects.  This compare can't overflow\n    * because max_text >= num_text (anyway, subtract of two positive integers\n    * can't overflow in any case.)\n    */\n   if (num_text > info_ptr->max_text - info_ptr->num_text)\n   {\n      int old_num_text = info_ptr->num_text;\n      int max_text;\n      png_textp new_text = NULL;\n\n      /* Calculate an appropriate max_text, checking for overflow. */\n      max_text = old_num_text;\n      if (num_text <= INT_MAX - max_text)\n      {\n         max_text += num_text;\n\n         /* Round up to a multiple of 8 */\n         if (max_text < INT_MAX-8)\n            max_text = (max_text + 8) & ~0x7;\n\n         else\n            max_text = INT_MAX;\n\n         /* Now allocate a new array and copy the old members in; this does all\n          * the overflow checks.\n          */\n         new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,\n             info_ptr->text, old_num_text, max_text-old_num_text,\n             sizeof *new_text));\n      }\n\n      if (new_text == NULL)\n      {\n         png_chunk_report(png_ptr, \"too many text chunks\",\n             PNG_CHUNK_WRITE_ERROR);\n\n         return 1;\n      }\n\n      png_free(png_ptr, info_ptr->text);\n\n      info_ptr->text = new_text;\n      info_ptr->free_me |= PNG_FREE_TEXT;\n      info_ptr->max_text = max_text;\n      /* num_text is adjusted below as the entries are copied in */\n\n      png_debug1(3, \"allocated %d entries for info_ptr->text\", max_text);\n   }\n\n   for (i = 0; i < num_text; i++)\n   {\n      size_t text_length, key_len;\n      size_t lang_len, lang_key_len;\n      png_textp textp = &(info_ptr->text[info_ptr->num_text]);\n\n      if (text_ptr[i].key == NULL)\n          continue;\n\n      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||\n          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)\n      {\n         png_chunk_report(png_ptr, \"text compression mode is out of range\",\n             PNG_CHUNK_WRITE_ERROR);\n         continue;\n      }\n\n      key_len = strlen(text_ptr[i].key);\n\n      if (text_ptr[i].compression <= 0)\n      {\n         lang_len = 0;\n         lang_key_len = 0;\n      }\n\n      else\n#  ifdef PNG_iTXt_SUPPORTED\n      {\n         /* Set iTXt data */\n\n         if (text_ptr[i].lang != NULL)\n            lang_len = strlen(text_ptr[i].lang);\n\n         else\n            lang_len = 0;\n\n         if (text_ptr[i].lang_key != NULL)\n            lang_key_len = strlen(text_ptr[i].lang_key);\n\n         else\n            lang_key_len = 0;\n      }\n#  else /* iTXt */\n      {\n         png_chunk_report(png_ptr, \"iTXt chunk not supported\",\n             PNG_CHUNK_WRITE_ERROR);\n         continue;\n      }\n#  endif\n\n      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\\0')\n      {\n         text_length = 0;\n#  ifdef PNG_iTXt_SUPPORTED\n         if (text_ptr[i].compression > 0)\n            textp->compression = PNG_ITXT_COMPRESSION_NONE;\n\n         else\n#  endif\n            textp->compression = PNG_TEXT_COMPRESSION_NONE;\n      }\n\n      else\n      {\n         text_length = strlen(text_ptr[i].text);\n         textp->compression = text_ptr[i].compression;\n      }\n\n      textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,\n          key_len + text_length + lang_len + lang_key_len + 4));\n\n      if (textp->key == NULL)\n      {\n         png_chunk_report(png_ptr, \"text chunk: out of memory\",\n             PNG_CHUNK_WRITE_ERROR);\n\n         return 1;\n      }\n\n      png_debug2(2, \"Allocated %lu bytes at %p in png_set_text\",\n          (unsigned long)(png_uint_32)\n          (key_len + lang_len + lang_key_len + text_length + 4),\n          textp->key);\n\n      memcpy(textp->key, text_ptr[i].key, key_len);\n      *(textp->key + key_len) = '\\0';\n\n      if (text_ptr[i].compression > 0)\n      {\n         textp->lang = textp->key + key_len + 1;\n         memcpy(textp->lang, text_ptr[i].lang, lang_len);\n         *(textp->lang + lang_len) = '\\0';\n         textp->lang_key = textp->lang + lang_len + 1;\n         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);\n         *(textp->lang_key + lang_key_len) = '\\0';\n         textp->text = textp->lang_key + lang_key_len + 1;\n      }\n\n      else\n      {\n         textp->lang=NULL;\n         textp->lang_key=NULL;\n         textp->text = textp->key + key_len + 1;\n      }\n\n      if (text_length != 0)\n         memcpy(textp->text, text_ptr[i].text, text_length);\n\n      *(textp->text + text_length) = '\\0';\n\n#  ifdef PNG_iTXt_SUPPORTED\n      if (textp->compression > 0)\n      {\n         textp->text_length = 0;\n         textp->itxt_length = text_length;\n      }\n\n      else\n#  endif\n      {\n         textp->text_length = text_length;\n         textp->itxt_length = 0;\n      }\n\n      info_ptr->num_text++;\n      png_debug1(3, \"transferred text chunk %d\", info_ptr->num_text);\n   }\n\n   return(0);\n}\n#endif\n\n#ifdef PNG_tIME_SUPPORTED\nvoid PNGAPI\npng_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_const_timep mod_time)\n{\n   png_debug1(1, \"in %s storage function\", \"tIME\");\n\n   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||\n       (png_ptr->mode & PNG_WROTE_tIME) != 0)\n      return;\n\n   if (mod_time->month == 0   || mod_time->month > 12  ||\n       mod_time->day   == 0   || mod_time->day   > 31  ||\n       mod_time->hour  > 23   || mod_time->minute > 59 ||\n       mod_time->second > 60)\n   {\n      png_warning(png_ptr, \"Ignoring invalid time value\");\n\n      return;\n   }\n\n   info_ptr->mod_time = *mod_time;\n   info_ptr->valid |= PNG_INFO_tIME;\n}\n#endif\n\n#ifdef PNG_tRNS_SUPPORTED\nvoid PNGAPI\npng_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,\n    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)\n{\n   png_debug1(1, \"in %s storage function\", \"tRNS\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n\n      return;\n\n   if (trans_alpha != NULL)\n   {\n       /* It may not actually be necessary to set png_ptr->trans_alpha here;\n        * we do it for backward compatibility with the way the png_handle_tRNS\n        * function used to do the allocation.\n        *\n        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively\n        * relies on png_set_tRNS storing the information in png_struct\n        * (otherwise it won't be there for the code in pngrtran.c).\n        */\n\n       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);\n\n       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)\n       {\n         /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */\n          info_ptr->trans_alpha = png_voidcast(png_bytep,\n              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));\n          memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);\n       }\n       png_ptr->trans_alpha = info_ptr->trans_alpha;\n   }\n\n   if (trans_color != NULL)\n   {\n#ifdef PNG_WARNINGS_SUPPORTED\n      if (info_ptr->bit_depth < 16)\n      {\n         int sample_max = (1 << info_ptr->bit_depth) - 1;\n\n         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&\n             trans_color->gray > sample_max) ||\n             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&\n             (trans_color->red > sample_max ||\n             trans_color->green > sample_max ||\n             trans_color->blue > sample_max)))\n            png_warning(png_ptr,\n                \"tRNS chunk has out-of-range samples for bit_depth\");\n      }\n#endif\n\n      info_ptr->trans_color = *trans_color;\n\n      if (num_trans == 0)\n         num_trans = 1;\n   }\n\n   info_ptr->num_trans = (png_uint_16)num_trans;\n\n   if (num_trans != 0)\n   {\n      info_ptr->valid |= PNG_INFO_tRNS;\n      info_ptr->free_me |= PNG_FREE_TRNS;\n   }\n}\n#endif\n\n#ifdef PNG_sPLT_SUPPORTED\nvoid PNGAPI\npng_set_sPLT(png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)\n/*\n *  entries        - array of png_sPLT_t structures\n *                   to be added to the list of palettes\n *                   in the info structure.\n *\n *  nentries       - number of palette structures to be\n *                   added.\n */\n{\n   png_sPLT_tp np;\n\n   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)\n      return;\n\n   /* Use the internal realloc function, which checks for all the possible\n    * overflows.  Notice that the parameters are (int) and (size_t)\n    */\n   np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,\n       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,\n       sizeof *np));\n\n   if (np == NULL)\n   {\n      /* Out of memory or too many chunks */\n      png_chunk_report(png_ptr, \"too many sPLT chunks\", PNG_CHUNK_WRITE_ERROR);\n\n      return;\n   }\n\n   png_free(png_ptr, info_ptr->splt_palettes);\n   info_ptr->splt_palettes = np;\n   info_ptr->free_me |= PNG_FREE_SPLT;\n\n   np += info_ptr->splt_palettes_num;\n\n   do\n   {\n      size_t length;\n\n      /* Skip invalid input entries */\n      if (entries->name == NULL || entries->entries == NULL)\n      {\n         /* png_handle_sPLT doesn't do this, so this is an app error */\n         png_app_error(png_ptr, \"png_set_sPLT: invalid sPLT\");\n         /* Just skip the invalid entry */\n         continue;\n      }\n\n      np->depth = entries->depth;\n\n      /* In the event of out-of-memory just return - there's no point keeping\n       * on trying to add sPLT chunks.\n       */\n      length = strlen(entries->name) + 1;\n      np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));\n\n      if (np->name == NULL)\n         break;\n\n      memcpy(np->name, entries->name, length);\n\n      /* IMPORTANT: we have memory now that won't get freed if something else\n       * goes wrong; this code must free it.  png_malloc_array produces no\n       * warnings; use a png_chunk_report (below) if there is an error.\n       */\n      np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,\n          entries->nentries, sizeof (png_sPLT_entry)));\n\n      if (np->entries == NULL)\n      {\n         png_free(png_ptr, np->name);\n         np->name = NULL;\n         break;\n      }\n\n      np->nentries = entries->nentries;\n      /* This multiply can't overflow because png_malloc_array has already\n       * checked it when doing the allocation.\n       */\n      memcpy(np->entries, entries->entries,\n          (unsigned int)entries->nentries * sizeof (png_sPLT_entry));\n\n      /* Note that 'continue' skips the advance of the out pointer and out\n       * count, so an invalid entry is not added.\n       */\n      info_ptr->valid |= PNG_INFO_sPLT;\n      ++(info_ptr->splt_palettes_num);\n      ++np;\n      ++entries;\n   }\n   while (--nentries);\n\n   if (nentries > 0)\n      png_chunk_report(png_ptr, \"sPLT out of memory\", PNG_CHUNK_WRITE_ERROR);\n}\n#endif /* sPLT */\n\n#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED\nstatic png_byte\ncheck_location(png_const_structrp png_ptr, int location)\n{\n   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);\n\n   /* New in 1.6.0; copy the location and check it.  This is an API\n    * change; previously the app had to use the\n    * png_set_unknown_chunk_location API below for each chunk.\n    */\n   if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)\n   {\n      /* Write struct, so unknown chunks come from the app */\n      png_app_warning(png_ptr,\n          \"png_set_unknown_chunks now expects a valid location\");\n      /* Use the old behavior */\n      location = (png_byte)(png_ptr->mode &\n          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));\n   }\n\n   /* This need not be an internal error - if the app calls\n    * png_set_unknown_chunks on a read pointer it must get the location right.\n    */\n   if (location == 0)\n      png_error(png_ptr, \"invalid location in png_set_unknown_chunks\");\n\n   /* Now reduce the location to the top-most set bit by removing each least\n    * significant bit in turn.\n    */\n   while (location != (location & -location))\n      location &= ~(location & -location);\n\n   /* The cast is safe because 'location' is a bit mask and only the low four\n    * bits are significant.\n    */\n   return (png_byte)location;\n}\n\nvoid PNGAPI\npng_set_unknown_chunks(png_const_structrp png_ptr,\n    png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)\n{\n   png_unknown_chunkp np;\n\n   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||\n       unknowns == NULL)\n      return;\n\n   /* Check for the failure cases where support has been disabled at compile\n    * time.  This code is hardly ever compiled - it's here because\n    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this\n    * code) but may be meaningless if the read or write handling of unknown\n    * chunks is not compiled in.\n    */\n#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \\\n      defined(PNG_READ_SUPPORTED)\n      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)\n      {\n         png_app_error(png_ptr, \"no unknown chunk support on read\");\n\n         return;\n      }\n#  endif\n#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \\\n      defined(PNG_WRITE_SUPPORTED)\n      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)\n      {\n         png_app_error(png_ptr, \"no unknown chunk support on write\");\n\n         return;\n      }\n#  endif\n\n   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that\n    * unknown critical chunks could be lost with just a warning resulting in\n    * undefined behavior.  Now png_chunk_report is used to provide behavior\n    * appropriate to read or write.\n    */\n   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,\n       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,\n       sizeof *np));\n\n   if (np == NULL)\n   {\n      png_chunk_report(png_ptr, \"too many unknown chunks\",\n          PNG_CHUNK_WRITE_ERROR);\n\n      return;\n   }\n\n   png_free(png_ptr, info_ptr->unknown_chunks);\n   info_ptr->unknown_chunks = np; /* safe because it is initialized */\n   info_ptr->free_me |= PNG_FREE_UNKN;\n\n   np += info_ptr->unknown_chunks_num;\n\n   /* Increment unknown_chunks_num each time round the loop to protect the\n    * just-allocated chunk data.\n    */\n   for (; num_unknowns > 0; --num_unknowns, ++unknowns)\n   {\n      memcpy(np->name, unknowns->name, (sizeof np->name));\n      np->name[(sizeof np->name)-1] = '\\0';\n      np->location = check_location(png_ptr, unknowns->location);\n\n      if (unknowns->size == 0)\n      {\n         np->data = NULL;\n         np->size = 0;\n      }\n\n      else\n      {\n         np->data = png_voidcast(png_bytep,\n             png_malloc_base(png_ptr, unknowns->size));\n\n         if (np->data == NULL)\n         {\n            png_chunk_report(png_ptr, \"unknown chunk: out of memory\",\n                PNG_CHUNK_WRITE_ERROR);\n            /* But just skip storing the unknown chunk */\n            continue;\n         }\n\n         memcpy(np->data, unknowns->data, unknowns->size);\n         np->size = unknowns->size;\n      }\n\n      /* These increments are skipped on out-of-memory for the data - the\n       * unknown chunk entry gets overwritten if the png_chunk_report returns.\n       * This is correct in the read case (the chunk is just dropped.)\n       */\n      ++np;\n      ++(info_ptr->unknown_chunks_num);\n   }\n}\n\nvoid PNGAPI\npng_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,\n    int chunk, int location)\n{\n   /* This API is pretty pointless in 1.6.0 because the location can be set\n    * before the call to png_set_unknown_chunks.\n    *\n    * TODO: add a png_app_warning in 1.7\n    */\n   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&\n      chunk < info_ptr->unknown_chunks_num)\n   {\n      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)\n      {\n         png_app_error(png_ptr, \"invalid unknown chunk location\");\n         /* Fake out the pre 1.6.0 behavior: */\n         if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */\n            location = PNG_AFTER_IDAT;\n\n         else\n            location = PNG_HAVE_IHDR; /* also undocumented */\n      }\n\n      info_ptr->unknown_chunks[chunk].location =\n         check_location(png_ptr, location);\n   }\n}\n#endif /* STORE_UNKNOWN_CHUNKS */\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\npng_uint_32 PNGAPI\npng_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)\n{\n   png_debug(1, \"in png_permit_mng_features\");\n\n   if (png_ptr == NULL)\n      return 0;\n\n   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;\n\n   return png_ptr->mng_features_permitted;\n}\n#endif\n\n#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED\nstatic unsigned int\nadd_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)\n{\n   unsigned int i;\n\n   /* Utility function: update the 'keep' state of a chunk if it is already in\n    * the list, otherwise add it to the list.\n    */\n   for (i=0; i<count; ++i, list += 5)\n   {\n      if (memcmp(list, add, 4) == 0)\n      {\n         list[4] = (png_byte)keep;\n\n         return count;\n      }\n   }\n\n   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)\n   {\n      ++count;\n      memcpy(list, add, 4);\n      list[4] = (png_byte)keep;\n   }\n\n   return count;\n}\n\nvoid PNGAPI\npng_set_keep_unknown_chunks(png_structrp png_ptr, int keep,\n    png_const_bytep chunk_list, int num_chunks_in)\n{\n   png_bytep new_list;\n   unsigned int num_chunks, old_num_chunks;\n\n   if (png_ptr == NULL)\n      return;\n\n   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)\n   {\n      png_app_error(png_ptr, \"png_set_keep_unknown_chunks: invalid keep\");\n\n      return;\n   }\n\n   if (num_chunks_in <= 0)\n   {\n      png_ptr->unknown_default = keep;\n\n      /* '0' means just set the flags, so stop here */\n      if (num_chunks_in == 0)\n        return;\n   }\n\n   if (num_chunks_in < 0)\n   {\n      /* Ignore all unknown chunks and all chunks recognized by\n       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND\n       */\n      static const png_byte chunks_to_ignore[] = {\n         98,  75,  71,  68, '\\0',  /* bKGD */\n         99,  72,  82,  77, '\\0',  /* cHRM */\n        101,  88,  73, 102, '\\0',  /* eXIf */\n        103,  65,  77,  65, '\\0',  /* gAMA */\n        104,  73,  83,  84, '\\0',  /* hIST */\n        105,  67,  67,  80, '\\0',  /* iCCP */\n        105,  84,  88, 116, '\\0',  /* iTXt */\n        111,  70,  70, 115, '\\0',  /* oFFs */\n        112,  67,  65,  76, '\\0',  /* pCAL */\n        112,  72,  89, 115, '\\0',  /* pHYs */\n        115,  66,  73,  84, '\\0',  /* sBIT */\n        115,  67,  65,  76, '\\0',  /* sCAL */\n        115,  80,  76,  84, '\\0',  /* sPLT */\n        115,  84,  69,  82, '\\0',  /* sTER */\n        115,  82,  71,  66, '\\0',  /* sRGB */\n        116,  69,  88, 116, '\\0',  /* tEXt */\n        116,  73,  77,  69, '\\0',  /* tIME */\n        122,  84,  88, 116, '\\0'   /* zTXt */\n      };\n\n      chunk_list = chunks_to_ignore;\n      num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;\n   }\n\n   else /* num_chunks_in > 0 */\n   {\n      if (chunk_list == NULL)\n      {\n         /* Prior to 1.6.0 this was silently ignored, now it is an app_error\n          * which can be switched off.\n          */\n         png_app_error(png_ptr, \"png_set_keep_unknown_chunks: no chunk list\");\n\n         return;\n      }\n\n      num_chunks = (unsigned int)num_chunks_in;\n   }\n\n   old_num_chunks = png_ptr->num_chunk_list;\n   if (png_ptr->chunk_list == NULL)\n      old_num_chunks = 0;\n\n   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.\n    */\n   if (num_chunks + old_num_chunks > UINT_MAX/5)\n   {\n      png_app_error(png_ptr, \"png_set_keep_unknown_chunks: too many chunks\");\n\n      return;\n   }\n\n   /* If these chunks are being reset to the default then no more memory is\n    * required because add_one_chunk above doesn't extend the list if the 'keep'\n    * parameter is the default.\n    */\n   if (keep != 0)\n   {\n      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,\n          5 * (num_chunks + old_num_chunks)));\n\n      if (old_num_chunks > 0)\n         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);\n   }\n\n   else if (old_num_chunks > 0)\n      new_list = png_ptr->chunk_list;\n\n   else\n      new_list = NULL;\n\n   /* Add the new chunks together with each one's handling code.  If the chunk\n    * already exists the code is updated, otherwise the chunk is added to the\n    * end.  (In libpng 1.6.0 order no longer matters because this code enforces\n    * the earlier convention that the last setting is the one that is used.)\n    */\n   if (new_list != NULL)\n   {\n      png_const_bytep inlist;\n      png_bytep outlist;\n      unsigned int i;\n\n      for (i=0; i<num_chunks; ++i)\n      {\n         old_num_chunks = add_one_chunk(new_list, old_num_chunks,\n             chunk_list+5*i, keep);\n      }\n\n      /* Now remove any spurious 'default' entries. */\n      num_chunks = 0;\n      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)\n      {\n         if (inlist[4])\n         {\n            if (outlist != inlist)\n               memcpy(outlist, inlist, 5);\n            outlist += 5;\n            ++num_chunks;\n         }\n      }\n\n      /* This means the application has removed all the specialized handling. */\n      if (num_chunks == 0)\n      {\n         if (png_ptr->chunk_list != new_list)\n            png_free(png_ptr, new_list);\n\n         new_list = NULL;\n      }\n   }\n\n   else\n      num_chunks = 0;\n\n   png_ptr->num_chunk_list = num_chunks;\n\n   if (png_ptr->chunk_list != new_list)\n   {\n      if (png_ptr->chunk_list != NULL)\n         png_free(png_ptr, png_ptr->chunk_list);\n\n      png_ptr->chunk_list = new_list;\n   }\n}\n#endif\n\n#ifdef PNG_READ_USER_CHUNKS_SUPPORTED\nvoid PNGAPI\npng_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,\n    png_user_chunk_ptr read_user_chunk_fn)\n{\n   png_debug(1, \"in png_set_read_user_chunk_fn\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->read_user_chunk_fn = read_user_chunk_fn;\n   png_ptr->user_chunk_ptr = user_chunk_ptr;\n}\n#endif\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\nvoid PNGAPI\npng_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,\n    png_bytepp row_pointers)\n{\n   png_debug1(1, \"in %s storage function\", \"rows\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if (info_ptr->row_pointers != NULL &&\n       (info_ptr->row_pointers != row_pointers))\n      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);\n\n   info_ptr->row_pointers = row_pointers;\n\n   if (row_pointers != NULL)\n      info_ptr->valid |= PNG_INFO_IDAT;\n}\n#endif\n\nvoid PNGAPI\npng_set_compression_buffer_size(png_structrp png_ptr, size_t size)\n{\n   if (png_ptr == NULL)\n      return;\n\n   if (size == 0 || size > PNG_UINT_31_MAX)\n      png_error(png_ptr, \"invalid compression buffer size\");\n\n#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)\n   {\n      png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */\n      return;\n   }\n#  endif\n\n#  ifdef PNG_WRITE_SUPPORTED\n   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)\n   {\n      if (png_ptr->zowner != 0)\n      {\n         png_warning(png_ptr,\n             \"Compression buffer size cannot be changed because it is in use\");\n\n         return;\n      }\n\n#ifndef __COVERITY__\n      /* Some compilers complain that this is always false.  However, it\n       * can be true when integer overflow happens.\n       */\n      if (size > ZLIB_IO_MAX)\n      {\n         png_warning(png_ptr,\n             \"Compression buffer size limited to system maximum\");\n         size = ZLIB_IO_MAX; /* must fit */\n      }\n#endif\n\n      if (size < 6)\n      {\n         /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH\n          * if this is permitted.\n          */\n         png_warning(png_ptr,\n             \"Compression buffer size cannot be reduced below 6\");\n\n         return;\n      }\n\n      if (png_ptr->zbuffer_size != size)\n      {\n         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);\n         png_ptr->zbuffer_size = (uInt)size;\n      }\n   }\n#  endif\n}\n\nvoid PNGAPI\npng_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)\n{\n   if (png_ptr != NULL && info_ptr != NULL)\n      info_ptr->valid &= (unsigned int)(~mask);\n}\n\n\n#ifdef PNG_SET_USER_LIMITS_SUPPORTED\n/* This function was added to libpng 1.2.6 */\nvoid PNGAPI\npng_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,\n    png_uint_32 user_height_max)\n{\n   /* Images with dimensions larger than these limits will be\n    * rejected by png_set_IHDR().  To accept any PNG datastream\n    * regardless of dimensions, set both limits to 0x7fffffff.\n    */\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->user_width_max = user_width_max;\n   png_ptr->user_height_max = user_height_max;\n}\n\n/* This function was added to libpng 1.4.0 */\nvoid PNGAPI\npng_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)\n{\n   if (png_ptr != NULL)\n      png_ptr->user_chunk_cache_max = user_chunk_cache_max;\n}\n\n/* This function was added to libpng 1.4.1 */\nvoid PNGAPI\npng_set_chunk_malloc_max (png_structrp png_ptr,\n    png_alloc_size_t user_chunk_malloc_max)\n{\n   if (png_ptr != NULL)\n      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;\n}\n#endif /* ?SET_USER_LIMITS */\n\n\n#ifdef PNG_BENIGN_ERRORS_SUPPORTED\nvoid PNGAPI\npng_set_benign_errors(png_structrp png_ptr, int allowed)\n{\n   png_debug(1, \"in png_set_benign_errors\");\n\n   /* If allowed is 1, png_benign_error() is treated as a warning.\n    *\n    * If allowed is 0, png_benign_error() is treated as an error (which\n    * is the default behavior if png_set_benign_errors() is not called).\n    */\n\n   if (allowed != 0)\n      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |\n         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;\n\n   else\n      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |\n         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);\n}\n#endif /* BENIGN_ERRORS */\n\n#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   /* Whether to report invalid palette index; added at libng-1.5.10.\n    * It is possible for an indexed (color-type==3) PNG file to contain\n    * pixels with invalid (out-of-range) indexes if the PLTE chunk has\n    * fewer entries than the image's bit-depth would allow. We recover\n    * from this gracefully by filling any incomplete palette with zeros\n    * (opaque black).  By default, when this occurs libpng will issue\n    * a benign error.  This API can be used to override that behavior.\n    */\nvoid PNGAPI\npng_set_check_for_invalid_index(png_structrp png_ptr, int allowed)\n{\n   png_debug(1, \"in png_set_check_for_invalid_index\");\n\n   if (allowed > 0)\n      png_ptr->num_palette_max = 0;\n\n   else\n      png_ptr->num_palette_max = -1;\n}\n#endif\n\n#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \\\n    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)\n/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,\n * and if invalid, correct the keyword rather than discarding the entire\n * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in\n * length, forbids leading or trailing whitespace, multiple internal spaces,\n * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.\n *\n * The 'new_key' buffer must be 80 characters in size (for the keyword plus a\n * trailing '\\0').  If this routine returns 0 then there was no keyword, or a\n * valid one could not be generated, and the caller must png_error.\n */\npng_uint_32 /* PRIVATE */\npng_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)\n{\n#ifdef PNG_WARNINGS_SUPPORTED\n   png_const_charp orig_key = key;\n#endif\n   png_uint_32 key_len = 0;\n   int bad_character = 0;\n   int space = 1;\n\n   png_debug(1, \"in png_check_keyword\");\n\n   if (key == NULL)\n   {\n      *new_key = 0;\n      return 0;\n   }\n\n   while (*key && key_len < 79)\n   {\n      png_byte ch = (png_byte)*key++;\n\n      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))\n      {\n         *new_key++ = ch; ++key_len; space = 0;\n      }\n\n      else if (space == 0)\n      {\n         /* A space or an invalid character when one wasn't seen immediately\n          * before; output just a space.\n          */\n         *new_key++ = 32; ++key_len; space = 1;\n\n         /* If the character was not a space then it is invalid. */\n         if (ch != 32)\n            bad_character = ch;\n      }\n\n      else if (bad_character == 0)\n         bad_character = ch; /* just skip it, record the first error */\n   }\n\n   if (key_len > 0 && space != 0) /* trailing space */\n   {\n      --key_len; --new_key;\n      if (bad_character == 0)\n         bad_character = 32;\n   }\n\n   /* Terminate the keyword */\n   *new_key = 0;\n\n   if (key_len == 0)\n      return 0;\n\n#ifdef PNG_WARNINGS_SUPPORTED\n   /* Try to only output one warning per keyword: */\n   if (*key != 0) /* keyword too long */\n      png_warning(png_ptr, \"keyword truncated\");\n\n   else if (bad_character != 0)\n   {\n      PNG_WARNING_PARAMETERS(p)\n\n      png_warning_parameter(p, 1, orig_key);\n      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);\n\n      png_formatted_warning(png_ptr, p, \"keyword \\\"@1\\\": bad character '0x@2'\");\n   }\n#else /* !WARNINGS */\n   PNG_UNUSED(png_ptr)\n#endif /* !WARNINGS */\n\n   return key_len;\n}\n#endif /* TEXT || pCAL || iCCP || sPLT */\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngstruct.h",
    "content": "\n/* pngstruct.h - header file for PNG reference library\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n/* The structure that holds the information to read and write PNG files.\n * The only people who need to care about what is inside of this are the\n * people who will be modifying the library for their own special needs.\n * It should NOT be accessed directly by an application.\n */\n\n#ifndef PNGSTRUCT_H\n#define PNGSTRUCT_H\n/* zlib.h defines the structure z_stream, an instance of which is included\n * in this structure and is required for decompressing the LZ compressed\n * data in PNG files.\n */\n#ifndef ZLIB_CONST\n   /* We must ensure that zlib uses 'const' in declarations. */\n#  define ZLIB_CONST\n#endif\n#include \"zlib.h\"\n#ifdef const\n   /* zlib.h sometimes #defines const to nothing, undo this. */\n#  undef const\n#endif\n\n/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility\n * with older builds.\n */\n#if ZLIB_VERNUM < 0x1260\n#  define PNGZ_MSG_CAST(s) png_constcast(char*,s)\n#  define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)\n#else\n#  define PNGZ_MSG_CAST(s) (s)\n#  define PNGZ_INPUT_CAST(b) (b)\n#endif\n\n/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib\n * can handle at once.  This type need be no larger than 16 bits (so maximum of\n * 65535), this define allows us to discover how big it is, but limited by the\n * maximum for size_t.  The value can be overridden in a library build\n * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably\n * lower value (e.g. 255 works).  A lower value may help memory usage (slightly)\n * and may even improve performance on some systems (and degrade it on others.)\n */\n#ifndef ZLIB_IO_MAX\n#  define ZLIB_IO_MAX ((uInt)-1)\n#endif\n\n#ifdef PNG_WRITE_SUPPORTED\n/* The type of a compression buffer list used by the write code. */\ntypedef struct png_compression_buffer\n{\n   struct png_compression_buffer *next;\n   png_byte                       output[1]; /* actually zbuf_size */\n} png_compression_buffer, *png_compression_bufferp;\n\n#define PNG_COMPRESSION_BUFFER_SIZE(pp)\\\n   (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size)\n#endif\n\n/* Colorspace support; structures used in png_struct, png_info and in internal\n * functions to hold and communicate information about the color space.\n *\n * PNG_COLORSPACE_SUPPORTED is only required if the application will perform\n * colorspace corrections, otherwise all the colorspace information can be\n * skipped and the size of libpng can be reduced (significantly) by compiling\n * out the colorspace support.\n */\n#ifdef PNG_COLORSPACE_SUPPORTED\n/* The chromaticities of the red, green and blue colorants and the chromaticity\n * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)).\n */\ntypedef struct png_xy\n{\n   png_fixed_point redx, redy;\n   png_fixed_point greenx, greeny;\n   png_fixed_point bluex, bluey;\n   png_fixed_point whitex, whitey;\n} png_xy;\n\n/* The same data as above but encoded as CIE XYZ values.  When this data comes\n * from chromaticities the sum of the Y values is assumed to be 1.0\n */\ntypedef struct png_XYZ\n{\n   png_fixed_point red_X, red_Y, red_Z;\n   png_fixed_point green_X, green_Y, green_Z;\n   png_fixed_point blue_X, blue_Y, blue_Z;\n} png_XYZ;\n#endif /* COLORSPACE */\n\n#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)\n/* A colorspace is all the above plus, potentially, profile information;\n * however at present libpng does not use the profile internally so it is only\n * stored in the png_info struct (if iCCP is supported.)  The rendering intent\n * is retained here and is checked.\n *\n * The file gamma encoding information is also stored here and gamma correction\n * is done by libpng, whereas color correction must currently be done by the\n * application.\n */\ntypedef struct png_colorspace\n{\n#ifdef PNG_GAMMA_SUPPORTED\n   png_fixed_point gamma;        /* File gamma */\n#endif\n\n#ifdef PNG_COLORSPACE_SUPPORTED\n   png_xy      end_points_xy;    /* End points as chromaticities */\n   png_XYZ     end_points_XYZ;   /* End points as CIE XYZ colorant values */\n   png_uint_16 rendering_intent; /* Rendering intent of a profile */\n#endif\n\n   /* Flags are always defined to simplify the code. */\n   png_uint_16 flags;            /* As defined below */\n} png_colorspace, * PNG_RESTRICT png_colorspacerp;\n\ntypedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp;\n\n/* General flags for the 'flags' field */\n#define PNG_COLORSPACE_HAVE_GAMMA           0x0001\n#define PNG_COLORSPACE_HAVE_ENDPOINTS       0x0002\n#define PNG_COLORSPACE_HAVE_INTENT          0x0004\n#define PNG_COLORSPACE_FROM_gAMA            0x0008\n#define PNG_COLORSPACE_FROM_cHRM            0x0010\n#define PNG_COLORSPACE_FROM_sRGB            0x0020\n#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040\n#define PNG_COLORSPACE_MATCHES_sRGB         0x0080 /* exact match on profile */\n#define PNG_COLORSPACE_INVALID              0x8000\n#define PNG_COLORSPACE_CANCEL(flags)        (0xffff ^ (flags))\n#endif /* COLORSPACE || GAMMA */\n\nstruct png_struct_def\n{\n#ifdef PNG_SETJMP_SUPPORTED\n   jmp_buf jmp_buf_local;     /* New name in 1.6.0 for jmp_buf in png_struct */\n   png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */\n   jmp_buf *jmp_buf_ptr;      /* passed to longjmp_fn */\n   size_t jmp_buf_size;       /* size of the above, if allocated */\n#endif\n   png_error_ptr error_fn;    /* function for printing errors and aborting */\n#ifdef PNG_WARNINGS_SUPPORTED\n   png_error_ptr warning_fn;  /* function for printing warnings */\n#endif\n   png_voidp error_ptr;       /* user supplied struct for error functions */\n   png_rw_ptr write_data_fn;  /* function for writing output data */\n   png_rw_ptr read_data_fn;   /* function for reading input data */\n   png_voidp io_ptr;          /* ptr to application struct for I/O functions */\n\n#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED\n   png_user_transform_ptr read_user_transform_fn; /* user read transform */\n#endif\n\n#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED\n   png_user_transform_ptr write_user_transform_fn; /* user write transform */\n#endif\n\n/* These were added in libpng-1.0.2 */\n#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED\n#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \\\n    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)\n   png_voidp user_transform_ptr; /* user supplied struct for user transform */\n   png_byte user_transform_depth;    /* bit depth of user transformed pixels */\n   png_byte user_transform_channels; /* channels in user transformed pixels */\n#endif\n#endif\n\n   png_uint_32 mode;          /* tells us where we are in the PNG file */\n   png_uint_32 flags;         /* flags indicating various things to libpng */\n   png_uint_32 transformations; /* which transformations to perform */\n\n   png_uint_32 zowner;        /* ID (chunk type) of zstream owner, 0 if none */\n   z_stream    zstream;       /* decompression structure */\n\n#ifdef PNG_WRITE_SUPPORTED\n   png_compression_bufferp zbuffer_list; /* Created on demand during write */\n   uInt                    zbuffer_size; /* size of the actual buffer */\n\n   int zlib_level;            /* holds zlib compression level */\n   int zlib_method;           /* holds zlib compression method */\n   int zlib_window_bits;      /* holds zlib compression window bits */\n   int zlib_mem_level;        /* holds zlib compression memory level */\n   int zlib_strategy;         /* holds zlib compression strategy */\n#endif\n/* Added at libpng 1.5.4 */\n#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\n   int zlib_text_level;            /* holds zlib compression level */\n   int zlib_text_method;           /* holds zlib compression method */\n   int zlib_text_window_bits;      /* holds zlib compression window bits */\n   int zlib_text_mem_level;        /* holds zlib compression memory level */\n   int zlib_text_strategy;         /* holds zlib compression strategy */\n#endif\n/* End of material added at libpng 1.5.4 */\n/* Added at libpng 1.6.0 */\n#ifdef PNG_WRITE_SUPPORTED\n   int zlib_set_level;        /* Actual values set into the zstream on write */\n   int zlib_set_method;\n   int zlib_set_window_bits;\n   int zlib_set_mem_level;\n   int zlib_set_strategy;\n#endif\n\n   png_uint_32 width;         /* width of image in pixels */\n   png_uint_32 height;        /* height of image in pixels */\n   png_uint_32 num_rows;      /* number of rows in current pass */\n   png_uint_32 usr_width;     /* width of row at start of write */\n   size_t rowbytes;           /* size of row in bytes */\n   png_uint_32 iwidth;        /* width of current interlaced row in pixels */\n   png_uint_32 row_number;    /* current row in interlace pass */\n   png_uint_32 chunk_name;    /* PNG_CHUNK() id of current chunk */\n   png_bytep prev_row;        /* buffer to save previous (unfiltered) row.\n                               * While reading this is a pointer into\n                               * big_prev_row; while writing it is separately\n                               * allocated if needed.\n                               */\n   png_bytep row_buf;         /* buffer to save current (unfiltered) row.\n                               * While reading, this is a pointer into\n                               * big_row_buf; while writing it is separately\n                               * allocated.\n                               */\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n   png_bytep try_row;    /* buffer to save trial row when filtering */\n   png_bytep tst_row;    /* buffer to save best trial row when filtering */\n#endif\n   size_t info_rowbytes;      /* Added in 1.5.4: cache of updated row bytes */\n\n   png_uint_32 idat_size;     /* current IDAT size for read */\n   png_uint_32 crc;           /* current chunk CRC value */\n   png_colorp palette;        /* palette from the input file */\n   png_uint_16 num_palette;   /* number of color entries in palette */\n\n/* Added at libpng-1.5.10 */\n#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   int num_palette_max;       /* maximum palette index found in IDAT */\n#endif\n\n   png_uint_16 num_trans;     /* number of transparency values */\n   png_byte compression;      /* file compression type (always 0) */\n   png_byte filter;           /* file filter type (always 0) */\n   png_byte interlaced;       /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */\n   png_byte pass;             /* current interlace pass (0 - 6) */\n   png_byte do_filter;        /* row filter flags (see PNG_FILTER_ in png.h ) */\n   png_byte color_type;       /* color type of file */\n   png_byte bit_depth;        /* bit depth of file */\n   png_byte usr_bit_depth;    /* bit depth of users row: write only */\n   png_byte pixel_depth;      /* number of bits per pixel */\n   png_byte channels;         /* number of channels in file */\n#ifdef PNG_WRITE_SUPPORTED\n   png_byte usr_channels;     /* channels at start of write: write only */\n#endif\n   png_byte sig_bytes;        /* magic bytes read/written from start of file */\n   png_byte maximum_pixel_depth;\n                              /* pixel depth used for the row buffers */\n   png_byte transformed_pixel_depth;\n                              /* pixel depth after read/write transforms */\n#if ZLIB_VERNUM >= 0x1240\n   png_byte zstream_start;    /* at start of an input zlib stream */\n#endif /* Zlib >= 1.2.4 */\n#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)\n   png_uint_16 filler;           /* filler bytes for pixel expansion */\n#endif\n\n#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED)\n   png_byte background_gamma_type;\n   png_fixed_point background_gamma;\n   png_color_16 background;   /* background color in screen gamma space */\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   png_color_16 background_1; /* background normalized to gamma 1.0 */\n#endif\n#endif /* bKGD */\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n   png_flush_ptr output_flush_fn; /* Function for flushing output */\n   png_uint_32 flush_dist;    /* how many rows apart to flush, 0 - no flush */\n   png_uint_32 flush_rows;    /* number of rows written since last flush */\n#endif\n\n#ifdef PNG_READ_GAMMA_SUPPORTED\n   int gamma_shift;      /* number of \"insignificant\" bits in 16-bit gamma */\n   png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */\n\n   png_bytep gamma_table;     /* gamma table for 8-bit depth files */\n   png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */\n#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \\\n   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \\\n   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)\n   png_bytep gamma_from_1;    /* converts from 1.0 to screen */\n   png_bytep gamma_to_1;      /* converts from file to 1.0 */\n   png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */\n   png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */\n#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */\n#endif\n\n#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)\n   png_color_8 sig_bit;       /* significant bits in each available channel */\n#endif\n\n#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)\n   png_color_8 shift;         /* shift for significant bit transformation */\n#endif\n\n#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \\\n || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)\n   png_bytep trans_alpha;           /* alpha values for paletted files */\n   png_color_16 trans_color;  /* transparent color for non-paletted files */\n#endif\n\n   png_read_status_ptr read_row_fn;   /* called after each row is decoded */\n   png_write_status_ptr write_row_fn; /* called after each row is encoded */\n#ifdef PNG_PROGRESSIVE_READ_SUPPORTED\n   png_progressive_info_ptr info_fn; /* called after header data fully read */\n   png_progressive_row_ptr row_fn;   /* called after a prog. row is decoded */\n   png_progressive_end_ptr end_fn;   /* called after image is complete */\n   png_bytep save_buffer_ptr;        /* current location in save_buffer */\n   png_bytep save_buffer;            /* buffer for previously read data */\n   png_bytep current_buffer_ptr;     /* current location in current_buffer */\n   png_bytep current_buffer;         /* buffer for recently used data */\n   png_uint_32 push_length;          /* size of current input chunk */\n   png_uint_32 skip_length;          /* bytes to skip in input data */\n   size_t save_buffer_size;          /* amount of data now in save_buffer */\n   size_t save_buffer_max;           /* total size of save_buffer */\n   size_t buffer_size;               /* total amount of available input data */\n   size_t current_buffer_size;       /* amount of data now in current_buffer */\n   int process_mode;                 /* what push library is currently doing */\n   int cur_palette;                  /* current push library palette index */\n\n#endif /* PROGRESSIVE_READ */\n\n#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)\n/* For the Borland special 64K segment handler */\n   png_bytepp offset_table_ptr;\n   png_bytep offset_table;\n   png_uint_16 offset_table_number;\n   png_uint_16 offset_table_count;\n   png_uint_16 offset_table_count_free;\n#endif\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n   png_bytep palette_lookup; /* lookup table for quantizing */\n   png_bytep quantize_index; /* index translation for palette files */\n#endif\n\n/* Options */\n#ifdef PNG_SET_OPTION_SUPPORTED\n   png_uint_32 options;           /* On/off state (up to 16 options) */\n#endif\n\n#if PNG_LIBPNG_VER < 10700\n/* To do: remove this from libpng-1.7 */\n#ifdef PNG_TIME_RFC1123_SUPPORTED\n   char time_buffer[29]; /* String to hold RFC 1123 time text */\n#endif\n#endif\n\n/* New members added in libpng-1.0.6 */\n\n   png_uint_32 free_me;    /* flags items libpng is responsible for freeing */\n\n#ifdef PNG_USER_CHUNKS_SUPPORTED\n   png_voidp user_chunk_ptr;\n#ifdef PNG_READ_USER_CHUNKS_SUPPORTED\n   png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */\n#endif\n#endif\n\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n   int          unknown_default; /* As PNG_HANDLE_* */\n   unsigned int num_chunk_list;  /* Number of entries in the list */\n   png_bytep    chunk_list;      /* List of png_byte[5]; the textual chunk name\n                                  * followed by a PNG_HANDLE_* byte */\n#endif\n\n/* New members added in libpng-1.0.3 */\n#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED\n   png_byte rgb_to_gray_status;\n   /* Added in libpng 1.5.5 to record setting of coefficients: */\n   png_byte rgb_to_gray_coefficients_set;\n   /* These were changed from png_byte in libpng-1.0.6 */\n   png_uint_16 rgb_to_gray_red_coeff;\n   png_uint_16 rgb_to_gray_green_coeff;\n   /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */\n#endif\n\n/* New member added in libpng-1.6.36 */\n#if defined(PNG_READ_EXPAND_SUPPORTED) && \\\n    defined(PNG_ARM_NEON_IMPLEMENTATION)\n   png_bytep riffled_palette; /* buffer for accelerated palette expansion */\n#endif\n\n/* New member added in libpng-1.0.4 (renamed in 1.0.9) */\n#if defined(PNG_MNG_FEATURES_SUPPORTED)\n/* Changed from png_byte to png_uint_32 at version 1.2.0 */\n   png_uint_32 mng_features_permitted;\n#endif\n\n/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   png_byte filter_type;\n#endif\n\n/* New members added in libpng-1.2.0 */\n\n/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */\n#ifdef PNG_USER_MEM_SUPPORTED\n   png_voidp mem_ptr;             /* user supplied struct for mem functions */\n   png_malloc_ptr malloc_fn;      /* function for allocating memory */\n   png_free_ptr free_fn;          /* function for freeing memory */\n#endif\n\n/* New member added in libpng-1.0.13 and 1.2.0 */\n   png_bytep big_row_buf;         /* buffer to save current (unfiltered) row */\n\n#ifdef PNG_READ_QUANTIZE_SUPPORTED\n/* The following three members were added at version 1.0.14 and 1.2.4 */\n   png_bytep quantize_sort;          /* working sort array */\n   png_bytep index_to_palette;       /* where the original index currently is\n                                        in the palette */\n   png_bytep palette_to_index;       /* which original index points to this\n                                         palette color */\n#endif\n\n/* New members added in libpng-1.0.16 and 1.2.6 */\n   png_byte compression_type;\n\n#ifdef PNG_USER_LIMITS_SUPPORTED\n   png_uint_32 user_width_max;\n   png_uint_32 user_height_max;\n\n   /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown\n    * chunks that can be stored (0 means unlimited).\n    */\n   png_uint_32 user_chunk_cache_max;\n\n   /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk\n    * can occupy when decompressed.  0 means unlimited.\n    */\n   png_alloc_size_t user_chunk_malloc_max;\n#endif\n\n/* New member added in libpng-1.0.25 and 1.2.17 */\n#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED\n   /* Temporary storage for unknown chunk that the library doesn't recognize,\n    * used while reading the chunk.\n    */\n   png_unknown_chunk unknown_chunk;\n#endif\n\n/* New member added in libpng-1.2.26 */\n   size_t old_big_row_buf_size;\n\n#ifdef PNG_READ_SUPPORTED\n/* New member added in libpng-1.2.30 */\n  png_bytep        read_buffer;      /* buffer for reading chunk data */\n  png_alloc_size_t read_buffer_size; /* current size of the buffer */\n#endif\n#ifdef PNG_SEQUENTIAL_READ_SUPPORTED\n  uInt             IDAT_read_size;   /* limit on read buffer size for IDAT */\n#endif\n\n#ifdef PNG_IO_STATE_SUPPORTED\n/* New member added in libpng-1.4.0 */\n   png_uint_32 io_state;\n#endif\n\n/* New member added in libpng-1.5.6 */\n   png_bytep big_prev_row;\n\n/* New member added in libpng-1.5.7 */\n   void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,\n      png_bytep row, png_const_bytep prev_row);\n\n#ifdef PNG_READ_SUPPORTED\n#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)\n   png_colorspace   colorspace;\n#endif\n#endif\n};\n#endif /* PNGSTRUCT_H */\n"
  },
  {
    "path": "dlib/external/libpng/pngtrans.c",
    "content": "\n/* pngtrans.c - transforms the data in a row (used by both readers and writers)\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n\n#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)\n\n#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)\n/* Turn on BGR-to-RGB mapping */\nvoid PNGAPI\npng_set_bgr(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_bgr\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_BGR;\n}\n#endif\n\n#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)\n/* Turn on 16-bit byte swapping */\nvoid PNGAPI\npng_set_swap(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_swap\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (png_ptr->bit_depth == 16)\n      png_ptr->transformations |= PNG_SWAP_BYTES;\n}\n#endif\n\n#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)\n/* Turn on pixel packing */\nvoid PNGAPI\npng_set_packing(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_packing\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (png_ptr->bit_depth < 8)\n   {\n      png_ptr->transformations |= PNG_PACK;\n#     ifdef PNG_WRITE_SUPPORTED\n         png_ptr->usr_bit_depth = 8;\n#     endif\n   }\n}\n#endif\n\n#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)\n/* Turn on packed pixel swapping */\nvoid PNGAPI\npng_set_packswap(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_packswap\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (png_ptr->bit_depth < 8)\n      png_ptr->transformations |= PNG_PACKSWAP;\n}\n#endif\n\n#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)\nvoid PNGAPI\npng_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)\n{\n   png_debug(1, \"in png_set_shift\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_SHIFT;\n   png_ptr->shift = *true_bits;\n}\n#endif\n\n#if defined(PNG_READ_INTERLACING_SUPPORTED) || \\\n    defined(PNG_WRITE_INTERLACING_SUPPORTED)\nint PNGAPI\npng_set_interlace_handling(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_interlace handling\");\n\n   if (png_ptr != 0 && png_ptr->interlaced != 0)\n   {\n      png_ptr->transformations |= PNG_INTERLACE;\n      return (7);\n   }\n\n   return (1);\n}\n#endif\n\n#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)\n/* Add a filler byte on read, or remove a filler or alpha byte on write.\n * The filler type has changed in v0.95 to allow future 2-byte fillers\n * for 48-bit input data, as well as to avoid problems with some compilers\n * that don't like bytes as parameters.\n */\nvoid PNGAPI\npng_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc)\n{\n   png_debug(1, \"in png_set_filler\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* In libpng 1.6 it is possible to determine whether this is a read or write\n    * operation and therefore to do more checking here for a valid call.\n    */\n   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)\n   {\n#     ifdef PNG_READ_FILLER_SUPPORTED\n         /* On read png_set_filler is always valid, regardless of the base PNG\n          * format, because other transformations can give a format where the\n          * filler code can execute (basically an 8 or 16-bit component RGB or G\n          * format.)\n          *\n          * NOTE: usr_channels is not used by the read code!  (This has led to\n          * confusion in the past.)  The filler is only used in the read code.\n          */\n         png_ptr->filler = (png_uint_16)filler;\n#     else\n         png_app_error(png_ptr, \"png_set_filler not supported on read\");\n         PNG_UNUSED(filler) /* not used in the write case */\n         return;\n#     endif\n   }\n\n   else /* write */\n   {\n#     ifdef PNG_WRITE_FILLER_SUPPORTED\n         /* On write the usr_channels parameter must be set correctly at the\n          * start to record the number of channels in the app-supplied data.\n          */\n         switch (png_ptr->color_type)\n         {\n            case PNG_COLOR_TYPE_RGB:\n               png_ptr->usr_channels = 4;\n               break;\n\n            case PNG_COLOR_TYPE_GRAY:\n               if (png_ptr->bit_depth >= 8)\n               {\n                  png_ptr->usr_channels = 2;\n                  break;\n               }\n\n               else\n               {\n                  /* There simply isn't any code in libpng to strip out bits\n                   * from bytes when the components are less than a byte in\n                   * size!\n                   */\n                  png_app_error(png_ptr,\n                      \"png_set_filler is invalid for\"\n                      \" low bit depth gray output\");\n                  return;\n               }\n\n            default:\n               png_app_error(png_ptr,\n                   \"png_set_filler: inappropriate color type\");\n               return;\n         }\n#     else\n         png_app_error(png_ptr, \"png_set_filler not supported on write\");\n         return;\n#     endif\n   }\n\n   /* Here on success - libpng supports the operation, set the transformation\n    * and the flag to say where the filler channel is.\n    */\n   png_ptr->transformations |= PNG_FILLER;\n\n   if (filler_loc == PNG_FILLER_AFTER)\n      png_ptr->flags |= PNG_FLAG_FILLER_AFTER;\n\n   else\n      png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;\n}\n\n/* Added to libpng-1.2.7 */\nvoid PNGAPI\npng_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc)\n{\n   png_debug(1, \"in png_set_add_alpha\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_set_filler(png_ptr, filler, filler_loc);\n   /* The above may fail to do anything. */\n   if ((png_ptr->transformations & PNG_FILLER) != 0)\n      png_ptr->transformations |= PNG_ADD_ALPHA;\n}\n\n#endif\n\n#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \\\n    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)\nvoid PNGAPI\npng_set_swap_alpha(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_swap_alpha\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_SWAP_ALPHA;\n}\n#endif\n\n#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \\\n    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)\nvoid PNGAPI\npng_set_invert_alpha(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_invert_alpha\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_INVERT_ALPHA;\n}\n#endif\n\n#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)\nvoid PNGAPI\npng_set_invert_mono(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_set_invert_mono\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_INVERT_MONO;\n}\n\n/* Invert monochrome grayscale data */\nvoid /* PRIVATE */\npng_do_invert(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_invert\");\n\n  /* This test removed from libpng version 1.0.13 and 1.2.0:\n   *   if (row_info->bit_depth == 1 &&\n   */\n   if (row_info->color_type == PNG_COLOR_TYPE_GRAY)\n   {\n      png_bytep rp = row;\n      size_t i;\n      size_t istop = row_info->rowbytes;\n\n      for (i = 0; i < istop; i++)\n      {\n         *rp = (png_byte)(~(*rp));\n         rp++;\n      }\n   }\n\n   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&\n      row_info->bit_depth == 8)\n   {\n      png_bytep rp = row;\n      size_t i;\n      size_t istop = row_info->rowbytes;\n\n      for (i = 0; i < istop; i += 2)\n      {\n         *rp = (png_byte)(~(*rp));\n         rp += 2;\n      }\n   }\n\n#ifdef PNG_16BIT_SUPPORTED\n   else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&\n      row_info->bit_depth == 16)\n   {\n      png_bytep rp = row;\n      size_t i;\n      size_t istop = row_info->rowbytes;\n\n      for (i = 0; i < istop; i += 4)\n      {\n         *rp = (png_byte)(~(*rp));\n         *(rp + 1) = (png_byte)(~(*(rp + 1)));\n         rp += 4;\n      }\n   }\n#endif\n}\n#endif\n\n#ifdef PNG_16BIT_SUPPORTED\n#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)\n/* Swaps byte order on 16-bit depth images */\nvoid /* PRIVATE */\npng_do_swap(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_swap\");\n\n   if (row_info->bit_depth == 16)\n   {\n      png_bytep rp = row;\n      png_uint_32 i;\n      png_uint_32 istop= row_info->width * row_info->channels;\n\n      for (i = 0; i < istop; i++, rp += 2)\n      {\n#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED\n         /* Feature added to libpng-1.6.11 for testing purposes, not\n          * enabled by default.\n          */\n         *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp);\n#else\n         png_byte t = *rp;\n         *rp = *(rp + 1);\n         *(rp + 1) = t;\n#endif\n      }\n   }\n}\n#endif\n#endif\n\n#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)\nstatic const png_byte onebppswaptable[256] = {\n   0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,\n   0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,\n   0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,\n   0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,\n   0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,\n   0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,\n   0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,\n   0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,\n   0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,\n   0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,\n   0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,\n   0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,\n   0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,\n   0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,\n   0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,\n   0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,\n   0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,\n   0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,\n   0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,\n   0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,\n   0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,\n   0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,\n   0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,\n   0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,\n   0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,\n   0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,\n   0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,\n   0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,\n   0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,\n   0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,\n   0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,\n   0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF\n};\n\nstatic const png_byte twobppswaptable[256] = {\n   0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,\n   0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,\n   0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,\n   0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,\n   0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,\n   0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,\n   0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,\n   0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,\n   0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,\n   0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,\n   0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,\n   0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,\n   0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,\n   0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,\n   0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,\n   0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,\n   0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,\n   0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,\n   0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,\n   0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,\n   0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,\n   0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,\n   0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,\n   0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,\n   0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,\n   0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,\n   0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,\n   0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,\n   0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,\n   0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,\n   0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,\n   0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF\n};\n\nstatic const png_byte fourbppswaptable[256] = {\n   0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,\n   0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,\n   0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,\n   0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,\n   0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,\n   0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,\n   0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,\n   0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,\n   0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,\n   0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,\n   0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,\n   0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,\n   0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,\n   0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,\n   0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,\n   0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,\n   0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,\n   0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,\n   0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,\n   0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,\n   0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,\n   0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,\n   0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,\n   0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,\n   0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,\n   0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,\n   0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,\n   0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,\n   0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,\n   0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,\n   0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,\n   0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF\n};\n\n/* Swaps pixel packing order within bytes */\nvoid /* PRIVATE */\npng_do_packswap(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_packswap\");\n\n   if (row_info->bit_depth < 8)\n   {\n      png_bytep rp;\n      png_const_bytep end, table;\n\n      end = row + row_info->rowbytes;\n\n      if (row_info->bit_depth == 1)\n         table = onebppswaptable;\n\n      else if (row_info->bit_depth == 2)\n         table = twobppswaptable;\n\n      else if (row_info->bit_depth == 4)\n         table = fourbppswaptable;\n\n      else\n         return;\n\n      for (rp = row; rp < end; rp++)\n         *rp = table[*rp];\n   }\n}\n#endif /* PACKSWAP || WRITE_PACKSWAP */\n\n#if defined(PNG_WRITE_FILLER_SUPPORTED) || \\\n    defined(PNG_READ_STRIP_ALPHA_SUPPORTED)\n/* Remove a channel - this used to be 'png_do_strip_filler' but it used a\n * somewhat weird combination of flags to determine what to do.  All the calls\n * to png_do_strip_filler are changed in 1.5.2 to call this instead with the\n * correct arguments.\n *\n * The routine isn't general - the channel must be the channel at the start or\n * end (not in the middle) of each pixel.\n */\nvoid /* PRIVATE */\npng_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)\n{\n   png_bytep sp = row; /* source pointer */\n   png_bytep dp = row; /* destination pointer */\n   png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */\n\n   /* At the start sp will point to the first byte to copy and dp to where\n    * it is copied to.  ep always points just beyond the end of the row, so\n    * the loop simply copies (channels-1) channels until sp reaches ep.\n    *\n    * at_start:        0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc.\n    *            nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc.\n    */\n\n   /* GA, GX, XG cases */\n   if (row_info->channels == 2)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         if (at_start != 0) /* Skip initial filler */\n            ++sp;\n         else          /* Skip initial channel and, for sp, the filler */\n         {\n            sp += 2; ++dp;\n         }\n\n         /* For a 1 pixel wide image there is nothing to do */\n         while (sp < ep)\n         {\n            *dp++ = *sp; sp += 2;\n         }\n\n         row_info->pixel_depth = 8;\n      }\n\n      else if (row_info->bit_depth == 16)\n      {\n         if (at_start != 0) /* Skip initial filler */\n            sp += 2;\n         else          /* Skip initial channel and, for sp, the filler */\n         {\n            sp += 4; dp += 2;\n         }\n\n         while (sp < ep)\n         {\n            *dp++ = *sp++; *dp++ = *sp; sp += 3;\n         }\n\n         row_info->pixel_depth = 16;\n      }\n\n      else\n         return; /* bad bit depth */\n\n      row_info->channels = 1;\n\n      /* Finally fix the color type if it records an alpha channel */\n      if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n         row_info->color_type = PNG_COLOR_TYPE_GRAY;\n   }\n\n   /* RGBA, RGBX, XRGB cases */\n   else if (row_info->channels == 4)\n   {\n      if (row_info->bit_depth == 8)\n      {\n         if (at_start != 0) /* Skip initial filler */\n            ++sp;\n         else          /* Skip initial channels and, for sp, the filler */\n         {\n            sp += 4; dp += 3;\n         }\n\n         /* Note that the loop adds 3 to dp and 4 to sp each time. */\n         while (sp < ep)\n         {\n            *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 2;\n         }\n\n         row_info->pixel_depth = 24;\n      }\n\n      else if (row_info->bit_depth == 16)\n      {\n         if (at_start != 0) /* Skip initial filler */\n            sp += 2;\n         else          /* Skip initial channels and, for sp, the filler */\n         {\n            sp += 8; dp += 6;\n         }\n\n         while (sp < ep)\n         {\n            /* Copy 6 bytes, skip 2 */\n            *dp++ = *sp++; *dp++ = *sp++;\n            *dp++ = *sp++; *dp++ = *sp++;\n            *dp++ = *sp++; *dp++ = *sp; sp += 3;\n         }\n\n         row_info->pixel_depth = 48;\n      }\n\n      else\n         return; /* bad bit depth */\n\n      row_info->channels = 3;\n\n      /* Finally fix the color type if it records an alpha channel */\n      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n         row_info->color_type = PNG_COLOR_TYPE_RGB;\n   }\n\n   else\n      return; /* The filler channel has gone already */\n\n   /* Fix the rowbytes value. */\n   row_info->rowbytes = (size_t)(dp-row);\n}\n#endif\n\n#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)\n/* Swaps red and blue bytes within a pixel */\nvoid /* PRIVATE */\npng_do_bgr(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_bgr\");\n\n   if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      png_uint_32 row_width = row_info->width;\n      if (row_info->bit_depth == 8)\n      {\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n         {\n            png_bytep rp;\n            png_uint_32 i;\n\n            for (i = 0, rp = row; i < row_width; i++, rp += 3)\n            {\n               png_byte save = *rp;\n               *rp = *(rp + 2);\n               *(rp + 2) = save;\n            }\n         }\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n         {\n            png_bytep rp;\n            png_uint_32 i;\n\n            for (i = 0, rp = row; i < row_width; i++, rp += 4)\n            {\n               png_byte save = *rp;\n               *rp = *(rp + 2);\n               *(rp + 2) = save;\n            }\n         }\n      }\n\n#ifdef PNG_16BIT_SUPPORTED\n      else if (row_info->bit_depth == 16)\n      {\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n         {\n            png_bytep rp;\n            png_uint_32 i;\n\n            for (i = 0, rp = row; i < row_width; i++, rp += 6)\n            {\n               png_byte save = *rp;\n               *rp = *(rp + 4);\n               *(rp + 4) = save;\n               save = *(rp + 1);\n               *(rp + 1) = *(rp + 5);\n               *(rp + 5) = save;\n            }\n         }\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n         {\n            png_bytep rp;\n            png_uint_32 i;\n\n            for (i = 0, rp = row; i < row_width; i++, rp += 8)\n            {\n               png_byte save = *rp;\n               *rp = *(rp + 4);\n               *(rp + 4) = save;\n               save = *(rp + 1);\n               *(rp + 1) = *(rp + 5);\n               *(rp + 5) = save;\n            }\n         }\n      }\n#endif\n   }\n}\n#endif /* READ_BGR || WRITE_BGR */\n\n#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \\\n    defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)\n/* Added at libpng-1.5.10 */\nvoid /* PRIVATE */\npng_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)\n{\n   if (png_ptr->num_palette < (1 << row_info->bit_depth) &&\n      png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */\n   {\n      /* Calculations moved outside switch in an attempt to stop different\n       * compiler warnings.  'padding' is in *bits* within the last byte, it is\n       * an 'int' because pixel_depth becomes an 'int' in the expression below,\n       * and this calculation is used because it avoids warnings that other\n       * forms produced on either GCC or MSVC.\n       */\n      int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);\n      png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1;\n\n      switch (row_info->bit_depth)\n      {\n         case 1:\n         {\n            /* in this case, all bytes must be 0 so we don't need\n             * to unpack the pixels except for the rightmost one.\n             */\n            for (; rp > png_ptr->row_buf; rp--)\n            {\n              if ((*rp >> padding) != 0)\n                 png_ptr->num_palette_max = 1;\n              padding = 0;\n            }\n\n            break;\n         }\n\n         case 2:\n         {\n            for (; rp > png_ptr->row_buf; rp--)\n            {\n              int i = ((*rp >> padding) & 0x03);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              i = (((*rp >> padding) >> 2) & 0x03);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              i = (((*rp >> padding) >> 4) & 0x03);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              i = (((*rp >> padding) >> 6) & 0x03);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              padding = 0;\n            }\n\n            break;\n         }\n\n         case 4:\n         {\n            for (; rp > png_ptr->row_buf; rp--)\n            {\n              int i = ((*rp >> padding) & 0x0f);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              i = (((*rp >> padding) >> 4) & 0x0f);\n\n              if (i > png_ptr->num_palette_max)\n                 png_ptr->num_palette_max = i;\n\n              padding = 0;\n            }\n\n            break;\n         }\n\n         case 8:\n         {\n            for (; rp > png_ptr->row_buf; rp--)\n            {\n               if (*rp > png_ptr->num_palette_max)\n                  png_ptr->num_palette_max = (int) *rp;\n            }\n\n            break;\n         }\n\n         default:\n            break;\n      }\n   }\n}\n#endif /* CHECK_FOR_INVALID_INDEX */\n\n#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \\\n    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)\n#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED\nvoid PNGAPI\npng_set_user_transform_info(png_structrp png_ptr, png_voidp\n   user_transform_ptr, int user_transform_depth, int user_transform_channels)\n{\n   png_debug(1, \"in png_set_user_transform_info\");\n\n   if (png_ptr == NULL)\n      return;\n\n#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED\n   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&\n      (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)\n   {\n      png_app_error(png_ptr,\n          \"info change after png_start_read_image or png_read_update_info\");\n      return;\n   }\n#endif\n\n   png_ptr->user_transform_ptr = user_transform_ptr;\n   png_ptr->user_transform_depth = (png_byte)user_transform_depth;\n   png_ptr->user_transform_channels = (png_byte)user_transform_channels;\n}\n#endif\n\n/* This function returns a pointer to the user_transform_ptr associated with\n * the user transform functions.  The application should free any memory\n * associated with this pointer before png_write_destroy and png_read_destroy\n * are called.\n */\n#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED\npng_voidp PNGAPI\npng_get_user_transform_ptr(png_const_structrp png_ptr)\n{\n   if (png_ptr == NULL)\n      return (NULL);\n\n   return png_ptr->user_transform_ptr;\n}\n#endif\n\n#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED\npng_uint_32 PNGAPI\npng_get_current_row_number(png_const_structrp png_ptr)\n{\n   /* See the comments in png.h - this is the sub-image row when reading an\n    * interlaced image.\n    */\n   if (png_ptr != NULL)\n      return png_ptr->row_number;\n\n   return PNG_UINT_32_MAX; /* help the app not to fail silently */\n}\n\npng_byte PNGAPI\npng_get_current_pass_number(png_const_structrp png_ptr)\n{\n   if (png_ptr != NULL)\n      return png_ptr->pass;\n   return 8; /* invalid */\n}\n#endif /* USER_TRANSFORM_INFO */\n#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */\n#endif /* READ || WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngwio.c",
    "content": "\n/* pngwio.c - functions for data output\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2014,2016,2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n *\n * This file provides a location for all output.  Users who need\n * special handling are expected to write functions that have the same\n * arguments as these and perform similar functions, but that possibly\n * use different output methods.  Note that you shouldn't change these\n * functions, but rather write replacement functions and then change\n * them at run time with png_set_write_fn(...).\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_WRITE_SUPPORTED\n\n/* Write the data to whatever output you are using.  The default routine\n * writes to a file pointer.  Note that this routine sometimes gets called\n * with very small lengths, so you should implement some kind of simple\n * buffering if you are using unbuffered writes.  This should never be asked\n * to write more than 64K on a 16-bit machine.\n */\n\nvoid /* PRIVATE */\npng_write_data(png_structrp png_ptr, png_const_bytep data, size_t length)\n{\n   /* NOTE: write_data_fn must not change the buffer! */\n   if (png_ptr->write_data_fn != NULL )\n      (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data),\n          length);\n\n   else\n      png_error(png_ptr, \"Call to NULL write function\");\n}\n\n#ifdef PNG_STDIO_SUPPORTED\n/* This is the function that does the actual writing of data.  If you are\n * not writing to a standard C stream, you should create a replacement\n * write_data function and use it at run time with png_set_write_fn(), rather\n * than changing the library.\n */\nvoid PNGCBAPI\npng_default_write_data(png_structp png_ptr, png_bytep data, size_t length)\n{\n   size_t check;\n\n   if (png_ptr == NULL)\n      return;\n\n   check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));\n\n   if (check != length)\n      png_error(png_ptr, \"Write Error\");\n}\n#endif\n\n/* This function is called to output any data pending writing (normally\n * to disk).  After png_flush is called, there should be no data pending\n * writing in any buffers.\n */\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\nvoid /* PRIVATE */\npng_flush(png_structrp png_ptr)\n{\n   if (png_ptr->output_flush_fn != NULL)\n      (*(png_ptr->output_flush_fn))(png_ptr);\n}\n\n#  ifdef PNG_STDIO_SUPPORTED\nvoid PNGCBAPI\npng_default_flush(png_structp png_ptr)\n{\n   png_FILE_p io_ptr;\n\n   if (png_ptr == NULL)\n      return;\n\n   io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr));\n   fflush(io_ptr);\n}\n#  endif\n#endif\n\n/* This function allows the application to supply new output functions for\n * libpng if standard C streams aren't being used.\n *\n * This function takes as its arguments:\n * png_ptr       - pointer to a png output data structure\n * io_ptr        - pointer to user supplied structure containing info about\n *                 the output functions.  May be NULL.\n * write_data_fn - pointer to a new output function that takes as its\n *                 arguments a pointer to a png_struct, a pointer to\n *                 data to be written, and a 32-bit unsigned int that is\n *                 the number of bytes to be written.  The new write\n *                 function should call png_error(png_ptr, \"Error msg\")\n *                 to exit and output any fatal error messages.  May be\n *                 NULL, in which case libpng's default function will\n *                 be used.\n * flush_data_fn - pointer to a new flush function that takes as its\n *                 arguments a pointer to a png_struct.  After a call to\n *                 the flush function, there should be no data in any buffers\n *                 or pending transmission.  If the output method doesn't do\n *                 any buffering of output, a function prototype must still be\n *                 supplied although it doesn't have to do anything.  If\n *                 PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile\n *                 time, output_flush_fn will be ignored, although it must be\n *                 supplied for compatibility.  May be NULL, in which case\n *                 libpng's default function will be used, if\n *                 PNG_WRITE_FLUSH_SUPPORTED is defined.  This is not\n *                 a good idea if io_ptr does not point to a standard\n *                 *FILE structure.\n */\nvoid PNGAPI\npng_set_write_fn(png_structrp png_ptr, png_voidp io_ptr,\n    png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->io_ptr = io_ptr;\n\n#ifdef PNG_STDIO_SUPPORTED\n   if (write_data_fn != NULL)\n      png_ptr->write_data_fn = write_data_fn;\n\n   else\n      png_ptr->write_data_fn = png_default_write_data;\n#else\n   png_ptr->write_data_fn = write_data_fn;\n#endif\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n#  ifdef PNG_STDIO_SUPPORTED\n\n   if (output_flush_fn != NULL)\n      png_ptr->output_flush_fn = output_flush_fn;\n\n   else\n      png_ptr->output_flush_fn = png_default_flush;\n\n#  else\n   png_ptr->output_flush_fn = output_flush_fn;\n#  endif\n#else\n   PNG_UNUSED(output_flush_fn)\n#endif /* WRITE_FLUSH */\n\n#ifdef PNG_READ_SUPPORTED\n   /* It is an error to read while writing a png file */\n   if (png_ptr->read_data_fn != NULL)\n   {\n      png_ptr->read_data_fn = NULL;\n\n      png_warning(png_ptr,\n          \"Can't set both read_data_fn and write_data_fn in the\"\n          \" same structure\");\n   }\n#endif\n}\n#endif /* WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngwrite.c",
    "content": "\n/* pngwrite.c - general routines to write a PNG file\n *\n * Copyright (c) 2018-2019 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED\n#  include <errno.h>\n#endif /* SIMPLIFIED_WRITE_STDIO */\n\n#ifdef PNG_WRITE_SUPPORTED\n\n#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n/* Write out all the unknown chunks for the current given location */\nstatic void\nwrite_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,\n    unsigned int where)\n{\n   if (info_ptr->unknown_chunks_num != 0)\n   {\n      png_const_unknown_chunkp up;\n\n      png_debug(5, \"writing extra chunks\");\n\n      for (up = info_ptr->unknown_chunks;\n           up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;\n           ++up)\n         if ((up->location & where) != 0)\n      {\n         /* If per-chunk unknown chunk handling is enabled use it, otherwise\n          * just write the chunks the application has set.\n          */\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n         int keep = png_handle_as_unknown(png_ptr, up->name);\n\n         /* NOTE: this code is radically different from the read side in the\n          * matter of handling an ancillary unknown chunk.  In the read side\n          * the default behavior is to discard it, in the code below the default\n          * behavior is to write it.  Critical chunks are, however, only\n          * written if explicitly listed or if the default is set to write all\n          * unknown chunks.\n          *\n          * The default handling is also slightly weird - it is not possible to\n          * stop the writing of all unsafe-to-copy chunks!\n          *\n          * TODO: REVIEW: this would seem to be a bug.\n          */\n         if (keep != PNG_HANDLE_CHUNK_NEVER &&\n             ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||\n              keep == PNG_HANDLE_CHUNK_ALWAYS ||\n              (keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&\n               png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))\n#endif\n         {\n            /* TODO: review, what is wrong with a zero length unknown chunk? */\n            if (up->size == 0)\n               png_warning(png_ptr, \"Writing zero-length unknown chunk\");\n\n            png_write_chunk(png_ptr, up->name, up->data, up->size);\n         }\n      }\n   }\n}\n#endif /* WRITE_UNKNOWN_CHUNKS */\n\n/* Writes all the PNG information.  This is the suggested way to use the\n * library.  If you have a new chunk to add, make a function to write it,\n * and put it in the correct location here.  If you want the chunk written\n * after the image data, put it in png_write_end().  I strongly encourage\n * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing\n * the chunk, as that will keep the code from breaking if you want to just\n * write a plain PNG file.  If you have long comments, I suggest writing\n * them in png_write_end(), and compressing them.\n */\nvoid PNGAPI\npng_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)\n{\n   png_debug(1, \"in png_write_info_before_PLTE\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)\n   {\n      /* Write PNG signature */\n      png_write_sig(png_ptr);\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n      if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \\\n          png_ptr->mng_features_permitted != 0)\n      {\n         png_warning(png_ptr,\n             \"MNG features are not allowed in a PNG datastream\");\n         png_ptr->mng_features_permitted = 0;\n      }\n#endif\n\n      /* Write IHDR information. */\n      png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,\n          info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,\n          info_ptr->filter_type,\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n          info_ptr->interlace_type\n#else\n          0\n#endif\n         );\n\n      /* The rest of these check to see if the valid field has the appropriate\n       * flag set, and if it does, writes the chunk.\n       *\n       * 1.6.0: COLORSPACE support controls the writing of these chunks too, and\n       * the chunks will be written if the WRITE routine is there and\n       * information * is available in the COLORSPACE. (See\n       * png_colorspace_sync_info in png.c for where the valid flags get set.)\n       *\n       * Under certain circumstances the colorspace can be invalidated without\n       * syncing the info_struct 'valid' flags; this happens if libpng detects\n       * an error and calls png_error while the color space is being set, yet\n       * the application continues writing the PNG.  So check the 'invalid'\n       * flag here too.\n       */\n#ifdef PNG_GAMMA_SUPPORTED\n#  ifdef PNG_WRITE_gAMA_SUPPORTED\n      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&\n          (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&\n          (info_ptr->valid & PNG_INFO_gAMA) != 0)\n         png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);\n#  endif\n#endif\n\n#ifdef PNG_COLORSPACE_SUPPORTED\n      /* Write only one of sRGB or an ICC profile.  If a profile was supplied\n       * and it matches one of the known sRGB ones issue a warning.\n       */\n#  ifdef PNG_WRITE_iCCP_SUPPORTED\n         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&\n             (info_ptr->valid & PNG_INFO_iCCP) != 0)\n         {\n#    ifdef PNG_WRITE_sRGB_SUPPORTED\n               if ((info_ptr->valid & PNG_INFO_sRGB) != 0)\n                  png_app_warning(png_ptr,\n                      \"profile matches sRGB but writing iCCP instead\");\n#     endif\n\n            png_write_iCCP(png_ptr, info_ptr->iccp_name,\n                info_ptr->iccp_profile);\n         }\n#     ifdef PNG_WRITE_sRGB_SUPPORTED\n         else\n#     endif\n#  endif\n\n#  ifdef PNG_WRITE_sRGB_SUPPORTED\n         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&\n             (info_ptr->valid & PNG_INFO_sRGB) != 0)\n            png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);\n#  endif /* WRITE_sRGB */\n#endif /* COLORSPACE */\n\n#ifdef PNG_WRITE_sBIT_SUPPORTED\n         if ((info_ptr->valid & PNG_INFO_sBIT) != 0)\n            png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);\n#endif\n\n#ifdef PNG_COLORSPACE_SUPPORTED\n#  ifdef PNG_WRITE_cHRM_SUPPORTED\n         if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&\n             (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&\n             (info_ptr->valid & PNG_INFO_cHRM) != 0)\n            png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);\n#  endif\n#endif\n\n#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n         write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);\n#endif\n\n      png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;\n   }\n}\n\nvoid PNGAPI\npng_write_info(png_structrp png_ptr, png_const_inforp info_ptr)\n{\n#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)\n   int i;\n#endif\n\n   png_debug(1, \"in png_write_info\");\n\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   png_write_info_before_PLTE(png_ptr, info_ptr);\n\n   if ((info_ptr->valid & PNG_INFO_PLTE) != 0)\n      png_write_PLTE(png_ptr, info_ptr->palette,\n          (png_uint_32)info_ptr->num_palette);\n\n   else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      png_error(png_ptr, \"Valid palette required for paletted images\");\n\n#ifdef PNG_WRITE_tRNS_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_tRNS) !=0)\n   {\n#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED\n      /* Invert the alpha channel (in tRNS) */\n      if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 &&\n          info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         int j, jend;\n\n         jend = info_ptr->num_trans;\n         if (jend > PNG_MAX_PALETTE_LENGTH)\n            jend = PNG_MAX_PALETTE_LENGTH;\n\n         for (j = 0; j<jend; ++j)\n            info_ptr->trans_alpha[j] =\n               (png_byte)(255 - info_ptr->trans_alpha[j]);\n      }\n#endif\n      png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color),\n          info_ptr->num_trans, info_ptr->color_type);\n   }\n#endif\n#ifdef PNG_WRITE_bKGD_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_bKGD) != 0)\n      png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);\n#endif\n\n#ifdef PNG_WRITE_eXIf_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_eXIf) != 0)\n      png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);\n#endif\n\n#ifdef PNG_WRITE_hIST_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_hIST) != 0)\n      png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);\n#endif\n\n#ifdef PNG_WRITE_oFFs_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_oFFs) != 0)\n      png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,\n          info_ptr->offset_unit_type);\n#endif\n\n#ifdef PNG_WRITE_pCAL_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_pCAL) != 0)\n      png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,\n          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,\n          info_ptr->pcal_units, info_ptr->pcal_params);\n#endif\n\n#ifdef PNG_WRITE_sCAL_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_sCAL) != 0)\n      png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,\n          info_ptr->scal_s_width, info_ptr->scal_s_height);\n#endif /* sCAL */\n\n#ifdef PNG_WRITE_pHYs_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_pHYs) != 0)\n      png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,\n          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);\n#endif /* pHYs */\n\n#ifdef PNG_WRITE_tIME_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_tIME) != 0)\n   {\n      png_write_tIME(png_ptr, &(info_ptr->mod_time));\n      png_ptr->mode |= PNG_WROTE_tIME;\n   }\n#endif /* tIME */\n\n#ifdef PNG_WRITE_sPLT_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_sPLT) != 0)\n      for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)\n         png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);\n#endif /* sPLT */\n\n#ifdef PNG_WRITE_TEXT_SUPPORTED\n   /* Check to see if we need to write text chunks */\n   for (i = 0; i < info_ptr->num_text; i++)\n   {\n      png_debug2(2, \"Writing header text chunk %d, type %d\", i,\n          info_ptr->text[i].compression);\n      /* An internationalized chunk? */\n      if (info_ptr->text[i].compression > 0)\n      {\n#ifdef PNG_WRITE_iTXt_SUPPORTED\n         /* Write international chunk */\n         png_write_iTXt(png_ptr,\n             info_ptr->text[i].compression,\n             info_ptr->text[i].key,\n             info_ptr->text[i].lang,\n             info_ptr->text[i].lang_key,\n             info_ptr->text[i].text);\n         /* Mark this chunk as written */\n         if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)\n            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;\n         else\n            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;\n#else\n         png_warning(png_ptr, \"Unable to write international text\");\n#endif\n      }\n\n      /* If we want a compressed text chunk */\n      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)\n      {\n#ifdef PNG_WRITE_zTXt_SUPPORTED\n         /* Write compressed chunk */\n         png_write_zTXt(png_ptr, info_ptr->text[i].key,\n             info_ptr->text[i].text, info_ptr->text[i].compression);\n         /* Mark this chunk as written */\n         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;\n#else\n         png_warning(png_ptr, \"Unable to write compressed text\");\n#endif\n      }\n\n      else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)\n      {\n#ifdef PNG_WRITE_tEXt_SUPPORTED\n         /* Write uncompressed chunk */\n         png_write_tEXt(png_ptr, info_ptr->text[i].key,\n             info_ptr->text[i].text,\n             0);\n         /* Mark this chunk as written */\n         info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;\n#else\n         /* Can't get here */\n         png_warning(png_ptr, \"Unable to write uncompressed text\");\n#endif\n      }\n   }\n#endif /* tEXt */\n\n#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n   write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);\n#endif\n}\n\n/* Writes the end of the PNG file.  If you don't want to write comments or\n * time information, you can pass NULL for info.  If you already wrote these\n * in png_write_info(), do not write them again here.  If you have long\n * comments, I suggest writing them here, and compressing them.\n */\nvoid PNGAPI\npng_write_end(png_structrp png_ptr, png_inforp info_ptr)\n{\n   png_debug(1, \"in png_write_end\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)\n      png_error(png_ptr, \"No IDATs written into file\");\n\n#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   if (png_ptr->num_palette_max > png_ptr->num_palette)\n      png_benign_error(png_ptr, \"Wrote palette index exceeding num_palette\");\n#endif\n\n   /* See if user wants us to write information chunks */\n   if (info_ptr != NULL)\n   {\n#ifdef PNG_WRITE_TEXT_SUPPORTED\n      int i; /* local index variable */\n#endif\n#ifdef PNG_WRITE_tIME_SUPPORTED\n      /* Check to see if user has supplied a time chunk */\n      if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&\n          (png_ptr->mode & PNG_WROTE_tIME) == 0)\n         png_write_tIME(png_ptr, &(info_ptr->mod_time));\n\n#endif\n#ifdef PNG_WRITE_TEXT_SUPPORTED\n      /* Loop through comment chunks */\n      for (i = 0; i < info_ptr->num_text; i++)\n      {\n         png_debug2(2, \"Writing trailer text chunk %d, type %d\", i,\n             info_ptr->text[i].compression);\n         /* An internationalized chunk? */\n         if (info_ptr->text[i].compression > 0)\n         {\n#ifdef PNG_WRITE_iTXt_SUPPORTED\n            /* Write international chunk */\n            png_write_iTXt(png_ptr,\n                info_ptr->text[i].compression,\n                info_ptr->text[i].key,\n                info_ptr->text[i].lang,\n                info_ptr->text[i].lang_key,\n                info_ptr->text[i].text);\n            /* Mark this chunk as written */\n            if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)\n               info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;\n            else\n               info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;\n#else\n            png_warning(png_ptr, \"Unable to write international text\");\n#endif\n         }\n\n         else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)\n         {\n#ifdef PNG_WRITE_zTXt_SUPPORTED\n            /* Write compressed chunk */\n            png_write_zTXt(png_ptr, info_ptr->text[i].key,\n                info_ptr->text[i].text, info_ptr->text[i].compression);\n            /* Mark this chunk as written */\n            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;\n#else\n            png_warning(png_ptr, \"Unable to write compressed text\");\n#endif\n         }\n\n         else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)\n         {\n#ifdef PNG_WRITE_tEXt_SUPPORTED\n            /* Write uncompressed chunk */\n            png_write_tEXt(png_ptr, info_ptr->text[i].key,\n                info_ptr->text[i].text, 0);\n            /* Mark this chunk as written */\n            info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;\n#else\n            png_warning(png_ptr, \"Unable to write uncompressed text\");\n#endif\n         }\n      }\n#endif\n\n#ifdef PNG_WRITE_eXIf_SUPPORTED\n   if ((info_ptr->valid & PNG_INFO_eXIf) != 0)\n      png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);\n#endif\n\n#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED\n      write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);\n#endif\n   }\n\n   png_ptr->mode |= PNG_AFTER_IDAT;\n\n   /* Write end of PNG file */\n   png_write_IEND(png_ptr);\n\n   /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,\n    * and restored again in libpng-1.2.30, may cause some applications that\n    * do not set png_ptr->output_flush_fn to crash.  If your application\n    * experiences a problem, please try building libpng with\n    * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to\n    * png-mng-implement at lists.sf.net .\n    */\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n#  ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED\n   png_flush(png_ptr);\n#  endif\n#endif\n}\n\n#ifdef PNG_CONVERT_tIME_SUPPORTED\nvoid PNGAPI\npng_convert_from_struct_tm(png_timep ptime, const struct tm * ttime)\n{\n   png_debug(1, \"in png_convert_from_struct_tm\");\n\n   ptime->year = (png_uint_16)(1900 + ttime->tm_year);\n   ptime->month = (png_byte)(ttime->tm_mon + 1);\n   ptime->day = (png_byte)ttime->tm_mday;\n   ptime->hour = (png_byte)ttime->tm_hour;\n   ptime->minute = (png_byte)ttime->tm_min;\n   ptime->second = (png_byte)ttime->tm_sec;\n}\n\nvoid PNGAPI\npng_convert_from_time_t(png_timep ptime, time_t ttime)\n{\n   struct tm *tbuf;\n\n   png_debug(1, \"in png_convert_from_time_t\");\n\n   tbuf = gmtime(&ttime);\n   png_convert_from_struct_tm(ptime, tbuf);\n}\n#endif\n\n/* Initialize png_ptr structure, and allocate any memory needed */\nPNG_FUNCTION(png_structp,PNGAPI\npng_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)\n{\n#ifndef PNG_USER_MEM_SUPPORTED\n   png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,\n       error_fn, warn_fn, NULL, NULL, NULL);\n#else\n   return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,\n       warn_fn, NULL, NULL, NULL);\n}\n\n/* Alternate initialize png_ptr structure, and allocate any memory needed */\nPNG_FUNCTION(png_structp,PNGAPI\npng_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,\n    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,\n    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)\n{\n   png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,\n       error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);\n#endif /* USER_MEM */\n   if (png_ptr != NULL)\n   {\n      /* Set the zlib control values to defaults; they can be overridden by the\n       * application after the struct has been created.\n       */\n      png_ptr->zbuffer_size = PNG_ZBUF_SIZE;\n\n      /* The 'zlib_strategy' setting is irrelevant because png_default_claim in\n       * pngwutil.c defaults it according to whether or not filters will be\n       * used, and ignores this setting.\n       */\n      png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY;\n      png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION;\n      png_ptr->zlib_mem_level = 8;\n      png_ptr->zlib_window_bits = 15;\n      png_ptr->zlib_method = 8;\n\n#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED\n      png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY;\n      png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION;\n      png_ptr->zlib_text_mem_level = 8;\n      png_ptr->zlib_text_window_bits = 15;\n      png_ptr->zlib_text_method = 8;\n#endif /* WRITE_COMPRESSED_TEXT */\n\n      /* This is a highly dubious configuration option; by default it is off,\n       * but it may be appropriate for private builds that are testing\n       * extensions not conformant to the current specification, or of\n       * applications that must not fail to write at all costs!\n       */\n#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED\n      /* In stable builds only warn if an application error can be completely\n       * handled.\n       */\n      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;\n#endif\n\n      /* App warnings are warnings in release (or release candidate) builds but\n       * are errors during development.\n       */\n#if PNG_RELEASE_BUILD\n      png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;\n#endif\n\n      /* TODO: delay this, it can be done in png_init_io() (if the app doesn't\n       * do it itself) avoiding setting the default function if it is not\n       * required.\n       */\n      png_set_write_fn(png_ptr, NULL, NULL, NULL);\n   }\n\n   return png_ptr;\n}\n\n\n/* Write a few rows of image data.  If the image is interlaced,\n * either you will have to write the 7 sub images, or, if you\n * have called png_set_interlace_handling(), you will have to\n * \"write\" the image seven times.\n */\nvoid PNGAPI\npng_write_rows(png_structrp png_ptr, png_bytepp row,\n    png_uint_32 num_rows)\n{\n   png_uint_32 i; /* row counter */\n   png_bytepp rp; /* row pointer */\n\n   png_debug(1, \"in png_write_rows\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* Loop through the rows */\n   for (i = 0, rp = row; i < num_rows; i++, rp++)\n   {\n      png_write_row(png_ptr, *rp);\n   }\n}\n\n/* Write the image.  You only need to call this function once, even\n * if you are writing an interlaced image.\n */\nvoid PNGAPI\npng_write_image(png_structrp png_ptr, png_bytepp image)\n{\n   png_uint_32 i; /* row index */\n   int pass, num_pass; /* pass variables */\n   png_bytepp rp; /* points to current row */\n\n   if (png_ptr == NULL)\n      return;\n\n   png_debug(1, \"in png_write_image\");\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* Initialize interlace handling.  If image is not interlaced,\n    * this will set pass to 1\n    */\n   num_pass = png_set_interlace_handling(png_ptr);\n#else\n   num_pass = 1;\n#endif\n   /* Loop through passes */\n   for (pass = 0; pass < num_pass; pass++)\n   {\n      /* Loop through image */\n      for (i = 0, rp = image; i < png_ptr->height; i++, rp++)\n      {\n         png_write_row(png_ptr, *rp);\n      }\n   }\n}\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n/* Performs intrapixel differencing  */\nstatic void\npng_do_write_intrapixel(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_write_intrapixel\");\n\n   if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      int bytes_per_pixel;\n      png_uint_32 row_width = row_info->width;\n      if (row_info->bit_depth == 8)\n      {\n         png_bytep rp;\n         png_uint_32 i;\n\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n            bytes_per_pixel = 3;\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n            bytes_per_pixel = 4;\n\n         else\n            return;\n\n         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)\n         {\n            *(rp)     = (png_byte)(*rp       - *(rp + 1));\n            *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1));\n         }\n      }\n\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n      else if (row_info->bit_depth == 16)\n      {\n         png_bytep rp;\n         png_uint_32 i;\n\n         if (row_info->color_type == PNG_COLOR_TYPE_RGB)\n            bytes_per_pixel = 6;\n\n         else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n            bytes_per_pixel = 8;\n\n         else\n            return;\n\n         for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)\n         {\n            png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);\n            png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);\n            png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);\n            png_uint_32 red  = (png_uint_32)((s0 - s1) & 0xffffL);\n            png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL);\n            *(rp    ) = (png_byte)(red >> 8);\n            *(rp + 1) = (png_byte)red;\n            *(rp + 4) = (png_byte)(blue >> 8);\n            *(rp + 5) = (png_byte)blue;\n         }\n      }\n#endif /* WRITE_16BIT */\n   }\n}\n#endif /* MNG_FEATURES */\n\n/* Called by user to write a row of image data */\nvoid PNGAPI\npng_write_row(png_structrp png_ptr, png_const_bytep row)\n{\n   /* 1.5.6: moved from png_struct to be a local structure: */\n   png_row_info row_info;\n\n   if (png_ptr == NULL)\n      return;\n\n   png_debug2(1, \"in png_write_row (row %u, pass %d)\",\n       png_ptr->row_number, png_ptr->pass);\n\n   /* Initialize transformations and other stuff if first time */\n   if (png_ptr->row_number == 0 && png_ptr->pass == 0)\n   {\n      /* Make sure we wrote the header info */\n      if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0)\n         png_error(png_ptr,\n             \"png_write_info was never called before png_write_row\");\n\n      /* Check for transforms that have been set but were defined out */\n#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)\n      if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_INVERT_SUPPORTED is not defined\");\n#endif\n\n#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)\n      if ((png_ptr->transformations & PNG_FILLER) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_FILLER_SUPPORTED is not defined\");\n#endif\n#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \\\n    defined(PNG_READ_PACKSWAP_SUPPORTED)\n      if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n         png_warning(png_ptr,\n             \"PNG_WRITE_PACKSWAP_SUPPORTED is not defined\");\n#endif\n\n#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)\n      if ((png_ptr->transformations & PNG_PACK) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_PACK_SUPPORTED is not defined\");\n#endif\n\n#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)\n      if ((png_ptr->transformations & PNG_SHIFT) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_SHIFT_SUPPORTED is not defined\");\n#endif\n\n#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)\n      if ((png_ptr->transformations & PNG_BGR) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_BGR_SUPPORTED is not defined\");\n#endif\n\n#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)\n      if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)\n         png_warning(png_ptr, \"PNG_WRITE_SWAP_SUPPORTED is not defined\");\n#endif\n\n      png_write_start_row(png_ptr);\n   }\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* If interlaced and not interested in row, return */\n   if (png_ptr->interlaced != 0 &&\n       (png_ptr->transformations & PNG_INTERLACE) != 0)\n   {\n      switch (png_ptr->pass)\n      {\n         case 0:\n            if ((png_ptr->row_number & 0x07) != 0)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 1:\n            if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 2:\n            if ((png_ptr->row_number & 0x07) != 4)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 3:\n            if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 4:\n            if ((png_ptr->row_number & 0x03) != 2)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 5:\n            if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         case 6:\n            if ((png_ptr->row_number & 0x01) == 0)\n            {\n               png_write_finish_row(png_ptr);\n               return;\n            }\n            break;\n\n         default: /* error: ignore it */\n            break;\n      }\n   }\n#endif\n\n   /* Set up row info for transformations */\n   row_info.color_type = png_ptr->color_type;\n   row_info.width = png_ptr->usr_width;\n   row_info.channels = png_ptr->usr_channels;\n   row_info.bit_depth = png_ptr->usr_bit_depth;\n   row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels);\n   row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);\n\n   png_debug1(3, \"row_info->color_type = %d\", row_info.color_type);\n   png_debug1(3, \"row_info->width = %u\", row_info.width);\n   png_debug1(3, \"row_info->channels = %d\", row_info.channels);\n   png_debug1(3, \"row_info->bit_depth = %d\", row_info.bit_depth);\n   png_debug1(3, \"row_info->pixel_depth = %d\", row_info.pixel_depth);\n   png_debug1(3, \"row_info->rowbytes = %lu\", (unsigned long)row_info.rowbytes);\n\n   /* Copy user's row into buffer, leaving room for filter byte. */\n   memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes);\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* Handle interlacing */\n   if (png_ptr->interlaced && png_ptr->pass < 6 &&\n       (png_ptr->transformations & PNG_INTERLACE) != 0)\n   {\n      png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);\n      /* This should always get caught above, but still ... */\n      if (row_info.width == 0)\n      {\n         png_write_finish_row(png_ptr);\n         return;\n      }\n   }\n#endif\n\n#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED\n   /* Handle other transformations */\n   if (png_ptr->transformations != 0)\n      png_do_write_transformations(png_ptr, &row_info);\n#endif\n\n   /* At this point the row_info pixel depth must match the 'transformed' depth,\n    * which is also the output depth.\n    */\n   if (row_info.pixel_depth != png_ptr->pixel_depth ||\n       row_info.pixel_depth != png_ptr->transformed_pixel_depth)\n      png_error(png_ptr, \"internal write transform logic error\");\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   /* Write filter_method 64 (intrapixel differencing) only if\n    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and\n    * 2. Libpng did not write a PNG signature (this filter_method is only\n    *    used in PNG datastreams that are embedded in MNG datastreams) and\n    * 3. The application called png_permit_mng_features with a mask that\n    *    included PNG_FLAG_MNG_FILTER_64 and\n    * 4. The filter_method is 64 and\n    * 5. The color_type is RGB or RGBA\n    */\n   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&\n       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))\n   {\n      /* Intrapixel differencing */\n      png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1);\n   }\n#endif\n\n/* Added at libpng-1.5.10 */\n#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED\n   /* Check for out-of-range palette index */\n   if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&\n       png_ptr->num_palette_max >= 0)\n      png_do_check_palette_indexes(png_ptr, &row_info);\n#endif\n\n   /* Find a filter if necessary, filter the row and write it out. */\n   png_write_find_filter(png_ptr, &row_info);\n\n   if (png_ptr->write_row_fn != NULL)\n      (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);\n}\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n/* Set the automatic flush interval or 0 to turn flushing off */\nvoid PNGAPI\npng_set_flush(png_structrp png_ptr, int nrows)\n{\n   png_debug(1, \"in png_set_flush\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows);\n}\n\n/* Flush the current output buffers now */\nvoid PNGAPI\npng_write_flush(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_write_flush\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* We have already written out all of the data */\n   if (png_ptr->row_number >= png_ptr->num_rows)\n      return;\n\n   png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH);\n   png_ptr->flush_rows = 0;\n   png_flush(png_ptr);\n}\n#endif /* WRITE_FLUSH */\n\n/* Free any memory used in png_ptr struct without freeing the struct itself. */\nstatic void\npng_write_destroy(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_write_destroy\");\n\n   /* Free any memory zlib uses */\n   if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)\n      deflateEnd(&png_ptr->zstream);\n\n   /* Free our memory.  png_free checks NULL for us. */\n   png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);\n   png_free(png_ptr, png_ptr->row_buf);\n   png_ptr->row_buf = NULL;\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n   png_free(png_ptr, png_ptr->prev_row);\n   png_free(png_ptr, png_ptr->try_row);\n   png_free(png_ptr, png_ptr->tst_row);\n   png_ptr->prev_row = NULL;\n   png_ptr->try_row = NULL;\n   png_ptr->tst_row = NULL;\n#endif\n\n#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED\n   png_free(png_ptr, png_ptr->chunk_list);\n   png_ptr->chunk_list = NULL;\n#endif\n\n   /* The error handling and memory handling information is left intact at this\n    * point: the jmp_buf may still have to be freed.  See png_destroy_png_struct\n    * for how this happens.\n    */\n}\n\n/* Free all memory used by the write.\n * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for\n * *png_ptr_ptr.  Prior to 1.6.0 it would accept such a value and it would free\n * the passed in info_structs but it would quietly fail to free any of the data\n * inside them.  In 1.6.0 it quietly does nothing (it has to be quiet because it\n * has no png_ptr.)\n */\nvoid PNGAPI\npng_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)\n{\n   png_debug(1, \"in png_destroy_write_struct\");\n\n   if (png_ptr_ptr != NULL)\n   {\n      png_structrp png_ptr = *png_ptr_ptr;\n\n      if (png_ptr != NULL) /* added in libpng 1.6.0 */\n      {\n         png_destroy_info_struct(png_ptr, info_ptr_ptr);\n\n         *png_ptr_ptr = NULL;\n         png_write_destroy(png_ptr);\n         png_destroy_png_struct(png_ptr);\n      }\n   }\n}\n\n/* Allow the application to select one or more row filters to use. */\nvoid PNGAPI\npng_set_filter(png_structrp png_ptr, int method, int filters)\n{\n   png_debug(1, \"in png_set_filter\");\n\n   if (png_ptr == NULL)\n      return;\n\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&\n       (method == PNG_INTRAPIXEL_DIFFERENCING))\n      method = PNG_FILTER_TYPE_BASE;\n\n#endif\n   if (method == PNG_FILTER_TYPE_BASE)\n   {\n      switch (filters & (PNG_ALL_FILTERS | 0x07))\n      {\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n         case 5:\n         case 6:\n         case 7: png_app_error(png_ptr, \"Unknown row filter for method 0\");\n#endif /* WRITE_FILTER */\n            /* FALLTHROUGH */\n         case PNG_FILTER_VALUE_NONE:\n            png_ptr->do_filter = PNG_FILTER_NONE; break;\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n         case PNG_FILTER_VALUE_SUB:\n            png_ptr->do_filter = PNG_FILTER_SUB; break;\n\n         case PNG_FILTER_VALUE_UP:\n            png_ptr->do_filter = PNG_FILTER_UP; break;\n\n         case PNG_FILTER_VALUE_AVG:\n            png_ptr->do_filter = PNG_FILTER_AVG; break;\n\n         case PNG_FILTER_VALUE_PAETH:\n            png_ptr->do_filter = PNG_FILTER_PAETH; break;\n\n         default:\n            png_ptr->do_filter = (png_byte)filters; break;\n#else\n         default:\n            png_app_error(png_ptr, \"Unknown row filter for method 0\");\n#endif /* WRITE_FILTER */\n      }\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n      /* If we have allocated the row_buf, this means we have already started\n       * with the image and we should have allocated all of the filter buffers\n       * that have been selected.  If prev_row isn't already allocated, then\n       * it is too late to start using the filters that need it, since we\n       * will be missing the data in the previous row.  If an application\n       * wants to start and stop using particular filters during compression,\n       * it should start out with all of the filters, and then remove them\n       * or add them back after the start of compression.\n       *\n       * NOTE: this is a nasty constraint on the code, because it means that the\n       * prev_row buffer must be maintained even if there are currently no\n       * 'prev_row' requiring filters active.\n       */\n      if (png_ptr->row_buf != NULL)\n      {\n         int num_filters;\n         png_alloc_size_t buf_size;\n\n         /* Repeat the checks in png_write_start_row; 1 pixel high or wide\n          * images cannot benefit from certain filters.  If this isn't done here\n          * the check below will fire on 1 pixel high images.\n          */\n         if (png_ptr->height == 1)\n            filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);\n\n         if (png_ptr->width == 1)\n            filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);\n\n         if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0\n            && png_ptr->prev_row == NULL)\n         {\n            /* This is the error case, however it is benign - the previous row\n             * is not available so the filter can't be used.  Just warn here.\n             */\n            png_app_warning(png_ptr,\n                \"png_set_filter: UP/AVG/PAETH cannot be added after start\");\n            filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);\n         }\n\n         num_filters = 0;\n\n         if (filters & PNG_FILTER_SUB)\n            num_filters++;\n\n         if (filters & PNG_FILTER_UP)\n            num_filters++;\n\n         if (filters & PNG_FILTER_AVG)\n            num_filters++;\n\n         if (filters & PNG_FILTER_PAETH)\n            num_filters++;\n\n         /* Allocate needed row buffers if they have not already been\n          * allocated.\n          */\n         buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth,\n             png_ptr->width) + 1;\n\n         if (png_ptr->try_row == NULL)\n            png_ptr->try_row = png_voidcast(png_bytep,\n                png_malloc(png_ptr, buf_size));\n\n         if (num_filters > 1)\n         {\n            if (png_ptr->tst_row == NULL)\n               png_ptr->tst_row = png_voidcast(png_bytep,\n                   png_malloc(png_ptr, buf_size));\n         }\n      }\n      png_ptr->do_filter = (png_byte)filters;\n#endif\n   }\n   else\n      png_error(png_ptr, \"Unknown custom filter method\");\n}\n\n#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */\n/* Provide floating and fixed point APIs */\n#ifdef PNG_FLOATING_POINT_SUPPORTED\nvoid PNGAPI\npng_set_filter_heuristics(png_structrp png_ptr, int heuristic_method,\n    int num_weights, png_const_doublep filter_weights,\n    png_const_doublep filter_costs)\n{\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(heuristic_method)\n   PNG_UNUSED(num_weights)\n   PNG_UNUSED(filter_weights)\n   PNG_UNUSED(filter_costs)\n}\n#endif /* FLOATING_POINT */\n\n#ifdef PNG_FIXED_POINT_SUPPORTED\nvoid PNGAPI\npng_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method,\n    int num_weights, png_const_fixed_point_p filter_weights,\n    png_const_fixed_point_p filter_costs)\n{\n   PNG_UNUSED(png_ptr)\n   PNG_UNUSED(heuristic_method)\n   PNG_UNUSED(num_weights)\n   PNG_UNUSED(filter_weights)\n   PNG_UNUSED(filter_costs)\n}\n#endif /* FIXED_POINT */\n#endif /* WRITE_WEIGHTED_FILTER */\n\n#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED\nvoid PNGAPI\npng_set_compression_level(png_structrp png_ptr, int level)\n{\n   png_debug(1, \"in png_set_compression_level\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->zlib_level = level;\n}\n\nvoid PNGAPI\npng_set_compression_mem_level(png_structrp png_ptr, int mem_level)\n{\n   png_debug(1, \"in png_set_compression_mem_level\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->zlib_mem_level = mem_level;\n}\n\nvoid PNGAPI\npng_set_compression_strategy(png_structrp png_ptr, int strategy)\n{\n   png_debug(1, \"in png_set_compression_strategy\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* The flag setting here prevents the libpng dynamic selection of strategy.\n    */\n   png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;\n   png_ptr->zlib_strategy = strategy;\n}\n\n/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a\n * smaller value of window_bits if it can do so safely.\n */\nvoid PNGAPI\npng_set_compression_window_bits(png_structrp png_ptr, int window_bits)\n{\n   if (png_ptr == NULL)\n      return;\n\n   /* Prior to 1.6.0 this would warn but then set the window_bits value. This\n    * meant that negative window bits values could be selected that would cause\n    * libpng to write a non-standard PNG file with raw deflate or gzip\n    * compressed IDAT or ancillary chunks.  Such files can be read and there is\n    * no warning on read, so this seems like a very bad idea.\n    */\n   if (window_bits > 15)\n   {\n      png_warning(png_ptr, \"Only compression windows <= 32k supported by PNG\");\n      window_bits = 15;\n   }\n\n   else if (window_bits < 8)\n   {\n      png_warning(png_ptr, \"Only compression windows >= 256 supported by PNG\");\n      window_bits = 8;\n   }\n\n   png_ptr->zlib_window_bits = window_bits;\n}\n\nvoid PNGAPI\npng_set_compression_method(png_structrp png_ptr, int method)\n{\n   png_debug(1, \"in png_set_compression_method\");\n\n   if (png_ptr == NULL)\n      return;\n\n   /* This would produce an invalid PNG file if it worked, but it doesn't and\n    * deflate will fault it, so it is harmless to just warn here.\n    */\n   if (method != 8)\n      png_warning(png_ptr, \"Only compression method 8 is supported by PNG\");\n\n   png_ptr->zlib_method = method;\n}\n#endif /* WRITE_CUSTOMIZE_COMPRESSION */\n\n/* The following were added to libpng-1.5.4 */\n#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\nvoid PNGAPI\npng_set_text_compression_level(png_structrp png_ptr, int level)\n{\n   png_debug(1, \"in png_set_text_compression_level\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->zlib_text_level = level;\n}\n\nvoid PNGAPI\npng_set_text_compression_mem_level(png_structrp png_ptr, int mem_level)\n{\n   png_debug(1, \"in png_set_text_compression_mem_level\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->zlib_text_mem_level = mem_level;\n}\n\nvoid PNGAPI\npng_set_text_compression_strategy(png_structrp png_ptr, int strategy)\n{\n   png_debug(1, \"in png_set_text_compression_strategy\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->zlib_text_strategy = strategy;\n}\n\n/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a\n * smaller value of window_bits if it can do so safely.\n */\nvoid PNGAPI\npng_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)\n{\n   if (png_ptr == NULL)\n      return;\n\n   if (window_bits > 15)\n   {\n      png_warning(png_ptr, \"Only compression windows <= 32k supported by PNG\");\n      window_bits = 15;\n   }\n\n   else if (window_bits < 8)\n   {\n      png_warning(png_ptr, \"Only compression windows >= 256 supported by PNG\");\n      window_bits = 8;\n   }\n\n   png_ptr->zlib_text_window_bits = window_bits;\n}\n\nvoid PNGAPI\npng_set_text_compression_method(png_structrp png_ptr, int method)\n{\n   png_debug(1, \"in png_set_text_compression_method\");\n\n   if (png_ptr == NULL)\n      return;\n\n   if (method != 8)\n      png_warning(png_ptr, \"Only compression method 8 is supported by PNG\");\n\n   png_ptr->zlib_text_method = method;\n}\n#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */\n/* end of API added to libpng-1.5.4 */\n\nvoid PNGAPI\npng_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)\n{\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->write_row_fn = write_row_fn;\n}\n\n#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED\nvoid PNGAPI\npng_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr\n    write_user_transform_fn)\n{\n   png_debug(1, \"in png_set_write_user_transform_fn\");\n\n   if (png_ptr == NULL)\n      return;\n\n   png_ptr->transformations |= PNG_USER_TRANSFORM;\n   png_ptr->write_user_transform_fn = write_user_transform_fn;\n}\n#endif\n\n\n#ifdef PNG_INFO_IMAGE_SUPPORTED\nvoid PNGAPI\npng_write_png(png_structrp png_ptr, png_inforp info_ptr,\n    int transforms, voidp params)\n{\n   if (png_ptr == NULL || info_ptr == NULL)\n      return;\n\n   if ((info_ptr->valid & PNG_INFO_IDAT) == 0)\n   {\n      png_app_error(png_ptr, \"no rows for png_write_image to write\");\n      return;\n   }\n\n   /* Write the file header information. */\n   png_write_info(png_ptr, info_ptr);\n\n   /* ------ these transformations don't touch the info structure ------- */\n\n   /* Invert monochrome pixels */\n   if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)\n#ifdef PNG_WRITE_INVERT_SUPPORTED\n      png_set_invert_mono(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_INVERT_MONO not supported\");\n#endif\n\n   /* Shift the pixels up to a legal bit depth and fill in\n    * as appropriate to correctly scale the image.\n    */\n   if ((transforms & PNG_TRANSFORM_SHIFT) != 0)\n#ifdef PNG_WRITE_SHIFT_SUPPORTED\n      if ((info_ptr->valid & PNG_INFO_sBIT) != 0)\n         png_set_shift(png_ptr, &info_ptr->sig_bit);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SHIFT not supported\");\n#endif\n\n   /* Pack pixels into bytes */\n   if ((transforms & PNG_TRANSFORM_PACKING) != 0)\n#ifdef PNG_WRITE_PACK_SUPPORTED\n      png_set_packing(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_PACKING not supported\");\n#endif\n\n   /* Swap location of alpha bytes from ARGB to RGBA */\n   if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)\n#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED\n      png_set_swap_alpha(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SWAP_ALPHA not supported\");\n#endif\n\n   /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into\n    * RGB, note that the code expects the input color type to be G or RGB; no\n    * alpha channel.\n    */\n   if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|\n       PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)\n   {\n#ifdef PNG_WRITE_FILLER_SUPPORTED\n      if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)\n      {\n         if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)\n            png_app_error(png_ptr,\n                \"PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported\");\n\n         /* Continue if ignored - this is the pre-1.6.10 behavior */\n         png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);\n      }\n\n      else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)\n         png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_STRIP_FILLER not supported\");\n#endif\n   }\n\n   /* Flip BGR pixels to RGB */\n   if ((transforms & PNG_TRANSFORM_BGR) != 0)\n#ifdef PNG_WRITE_BGR_SUPPORTED\n      png_set_bgr(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_BGR not supported\");\n#endif\n\n   /* Swap bytes of 16-bit files to most significant byte first */\n   if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)\n#ifdef PNG_WRITE_SWAP_SUPPORTED\n      png_set_swap(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_SWAP_ENDIAN not supported\");\n#endif\n\n   /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */\n   if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)\n#ifdef PNG_WRITE_PACKSWAP_SUPPORTED\n      png_set_packswap(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_PACKSWAP not supported\");\n#endif\n\n   /* Invert the alpha channel from opacity to transparency */\n   if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)\n#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED\n      png_set_invert_alpha(png_ptr);\n#else\n      png_app_error(png_ptr, \"PNG_TRANSFORM_INVERT_ALPHA not supported\");\n#endif\n\n   /* ----------------------- end of transformations ------------------- */\n\n   /* Write the bits */\n   png_write_image(png_ptr, info_ptr->row_pointers);\n\n   /* It is REQUIRED to call this to finish writing the rest of the file */\n   png_write_end(png_ptr, info_ptr);\n\n   PNG_UNUSED(params)\n}\n#endif\n\n\n#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED\n/* Initialize the write structure - general purpose utility. */\nstatic int\npng_image_write_init(png_imagep image)\n{\n   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,\n       png_safe_error, png_safe_warning);\n\n   if (png_ptr != NULL)\n   {\n      png_infop info_ptr = png_create_info_struct(png_ptr);\n\n      if (info_ptr != NULL)\n      {\n         png_controlp control = png_voidcast(png_controlp,\n             png_malloc_warn(png_ptr, (sizeof *control)));\n\n         if (control != NULL)\n         {\n            memset(control, 0, (sizeof *control));\n\n            control->png_ptr = png_ptr;\n            control->info_ptr = info_ptr;\n            control->for_write = 1;\n\n            image->opaque = control;\n            return 1;\n         }\n\n         /* Error clean up */\n         png_destroy_info_struct(png_ptr, &info_ptr);\n      }\n\n      png_destroy_write_struct(&png_ptr, NULL);\n   }\n\n   return png_image_error(image, \"png_image_write_: out of memory\");\n}\n\n/* Arguments to png_image_write_main: */\ntypedef struct\n{\n   /* Arguments: */\n   png_imagep      image;\n   png_const_voidp buffer;\n   png_int_32      row_stride;\n   png_const_voidp colormap;\n   int             convert_to_8bit;\n   /* Local variables: */\n   png_const_voidp first_row;\n   ptrdiff_t       row_bytes;\n   png_voidp       local_row;\n   /* Byte count for memory writing */\n   png_bytep        memory;\n   png_alloc_size_t memory_bytes; /* not used for STDIO */\n   png_alloc_size_t output_bytes; /* running total */\n} png_image_write_control;\n\n/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to\n * do any necessary byte swapping.  The component order is defined by the\n * png_image format value.\n */\nstatic int\npng_write_image_16bit(png_voidp argument)\n{\n   png_image_write_control *display = png_voidcast(png_image_write_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n\n   png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,\n       display->first_row);\n   png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);\n   png_uint_16p row_end;\n   unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?\n       3 : 1;\n   int aindex = 0;\n   png_uint_32 y = image->height;\n\n   if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)\n   {\n#   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED\n      if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)\n      {\n         aindex = -1;\n         ++input_row; /* To point to the first component */\n         ++output_row;\n      }\n         else\n            aindex = (int)channels;\n#     else\n         aindex = (int)channels;\n#     endif\n   }\n\n   else\n      png_error(png_ptr, \"png_write_image: internal call error\");\n\n   /* Work out the output row end and count over this, note that the increment\n    * above to 'row' means that row_end can actually be beyond the end of the\n    * row; this is correct.\n    */\n   row_end = output_row + image->width * (channels+1);\n\n   for (; y > 0; --y)\n   {\n      png_const_uint_16p in_ptr = input_row;\n      png_uint_16p out_ptr = output_row;\n\n      while (out_ptr < row_end)\n      {\n         png_uint_16 alpha = in_ptr[aindex];\n         png_uint_32 reciprocal = 0;\n         int c;\n\n         out_ptr[aindex] = alpha;\n\n         /* Calculate a reciprocal.  The correct calculation is simply\n          * component/alpha*65535 << 15. (I.e. 15 bits of precision); this\n          * allows correct rounding by adding .5 before the shift.  'reciprocal'\n          * is only initialized when required.\n          */\n         if (alpha > 0 && alpha < 65535)\n            reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;\n\n         c = (int)channels;\n         do /* always at least one channel */\n         {\n            png_uint_16 component = *in_ptr++;\n\n            /* The following gives 65535 for an alpha of 0, which is fine,\n             * otherwise if 0/0 is represented as some other value there is more\n             * likely to be a discontinuity which will probably damage\n             * compression when moving from a fully transparent area to a\n             * nearly transparent one.  (The assumption here is that opaque\n             * areas tend not to be 0 intensity.)\n             */\n            if (component >= alpha)\n               component = 65535;\n\n            /* component<alpha, so component/alpha is less than one and\n             * component*reciprocal is less than 2^31.\n             */\n            else if (component > 0 && alpha < 65535)\n            {\n               png_uint_32 calc = component * reciprocal;\n               calc += 16384; /* round to nearest */\n               component = (png_uint_16)(calc >> 15);\n            }\n\n            *out_ptr++ = component;\n         }\n         while (--c > 0);\n\n         /* Skip to next component (skip the intervening alpha channel) */\n         ++in_ptr;\n         ++out_ptr;\n      }\n\n      png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));\n      input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));\n   }\n\n   return 1;\n}\n\n/* Given 16-bit input (1 to 4 channels) write 8-bit output.  If an alpha channel\n * is present it must be removed from the components, the components are then\n * written in sRGB encoding.  No components are added or removed.\n *\n * Calculate an alpha reciprocal to reverse pre-multiplication.  As above the\n * calculation can be done to 15 bits of accuracy; however, the output needs to\n * be scaled in the range 0..255*65535, so include that scaling here.\n */\n#   define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha))\n\nstatic png_byte\npng_unpremultiply(png_uint_32 component, png_uint_32 alpha,\n    png_uint_32 reciprocal/*from the above macro*/)\n{\n   /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0\n    * is represented as some other value there is more likely to be a\n    * discontinuity which will probably damage compression when moving from a\n    * fully transparent area to a nearly transparent one.  (The assumption here\n    * is that opaque areas tend not to be 0 intensity.)\n    *\n    * There is a rounding problem here; if alpha is less than 128 it will end up\n    * as 0 when scaled to 8 bits.  To avoid introducing spurious colors into the\n    * output change for this too.\n    */\n   if (component >= alpha || alpha < 128)\n      return 255;\n\n   /* component<alpha, so component/alpha is less than one and\n    * component*reciprocal is less than 2^31.\n    */\n   else if (component > 0)\n   {\n      /* The test is that alpha/257 (rounded) is less than 255, the first value\n       * that becomes 255 is 65407.\n       * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,\n       * be exact!)  [Could also test reciprocal != 0]\n       */\n      if (alpha < 65407)\n      {\n         component *= reciprocal;\n         component += 64; /* round to nearest */\n         component >>= 7;\n      }\n\n      else\n         component *= 255;\n\n      /* Convert the component to sRGB. */\n      return (png_byte)PNG_sRGB_FROM_LINEAR(component);\n   }\n\n   else\n      return 0;\n}\n\nstatic int\npng_write_image_8bit(png_voidp argument)\n{\n   png_image_write_control *display = png_voidcast(png_image_write_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n\n   png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,\n       display->first_row);\n   png_bytep output_row = png_voidcast(png_bytep, display->local_row);\n   png_uint_32 y = image->height;\n   unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ?\n       3 : 1;\n\n   if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)\n   {\n      png_bytep row_end;\n      int aindex;\n\n#   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED\n      if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)\n      {\n         aindex = -1;\n         ++input_row; /* To point to the first component */\n         ++output_row;\n      }\n\n      else\n#   endif\n      aindex = (int)channels;\n\n      /* Use row_end in place of a loop counter: */\n      row_end = output_row + image->width * (channels+1);\n\n      for (; y > 0; --y)\n      {\n         png_const_uint_16p in_ptr = input_row;\n         png_bytep out_ptr = output_row;\n\n         while (out_ptr < row_end)\n         {\n            png_uint_16 alpha = in_ptr[aindex];\n            png_byte alphabyte = (png_byte)PNG_DIV257(alpha);\n            png_uint_32 reciprocal = 0;\n            int c;\n\n            /* Scale and write the alpha channel. */\n            out_ptr[aindex] = alphabyte;\n\n            if (alphabyte > 0 && alphabyte < 255)\n               reciprocal = UNP_RECIPROCAL(alpha);\n\n            c = (int)channels;\n            do /* always at least one channel */\n               *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal);\n            while (--c > 0);\n\n            /* Skip to next component (skip the intervening alpha channel) */\n            ++in_ptr;\n            ++out_ptr;\n         } /* while out_ptr < row_end */\n\n         png_write_row(png_ptr, png_voidcast(png_const_bytep,\n             display->local_row));\n         input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));\n      } /* while y */\n   }\n\n   else\n   {\n      /* No alpha channel, so the row_end really is the end of the row and it\n       * is sufficient to loop over the components one by one.\n       */\n      png_bytep row_end = output_row + image->width * channels;\n\n      for (; y > 0; --y)\n      {\n         png_const_uint_16p in_ptr = input_row;\n         png_bytep out_ptr = output_row;\n\n         while (out_ptr < row_end)\n         {\n            png_uint_32 component = *in_ptr++;\n\n            component *= 255;\n            *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component);\n         }\n\n         png_write_row(png_ptr, output_row);\n         input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16));\n      }\n   }\n\n   return 1;\n}\n\nstatic void\npng_image_set_PLTE(png_image_write_control *display)\n{\n   png_imagep image = display->image;\n   const void *cmap = display->colormap;\n   int entries = image->colormap_entries > 256 ? 256 :\n       (int)image->colormap_entries;\n\n   /* NOTE: the caller must check for cmap != NULL and entries != 0 */\n   png_uint_32 format = image->format;\n   unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);\n\n#   if defined(PNG_FORMAT_BGR_SUPPORTED) &&\\\n      defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)\n      int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&\n          (format & PNG_FORMAT_FLAG_ALPHA) != 0;\n#   else\n#     define afirst 0\n#   endif\n\n#   ifdef PNG_FORMAT_BGR_SUPPORTED\n      int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;\n#   else\n#     define bgr 0\n#   endif\n\n   int i, num_trans;\n   png_color palette[256];\n   png_byte tRNS[256];\n\n   memset(tRNS, 255, (sizeof tRNS));\n   memset(palette, 0, (sizeof palette));\n\n   for (i=num_trans=0; i<entries; ++i)\n   {\n      /* This gets automatically converted to sRGB with reversal of the\n       * pre-multiplication if the color-map has an alpha channel.\n       */\n      if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)\n      {\n         png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);\n\n         entry += (unsigned int)i * channels;\n\n         if ((channels & 1) != 0) /* no alpha */\n         {\n            if (channels >= 3) /* RGB */\n            {\n               palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 *\n                   entry[(2 ^ bgr)]);\n               palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 *\n                   entry[1]);\n               palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 *\n                   entry[bgr]);\n            }\n\n            else /* Gray */\n               palette[i].blue = palette[i].red = palette[i].green =\n                  (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry);\n         }\n\n         else /* alpha */\n         {\n            png_uint_16 alpha = entry[afirst ? 0 : channels-1];\n            png_byte alphabyte = (png_byte)PNG_DIV257(alpha);\n            png_uint_32 reciprocal = 0;\n\n            /* Calculate a reciprocal, as in the png_write_image_8bit code above\n             * this is designed to produce a value scaled to 255*65535 when\n             * divided by 128 (i.e. asr 7).\n             */\n            if (alphabyte > 0 && alphabyte < 255)\n               reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;\n\n            tRNS[i] = alphabyte;\n            if (alphabyte < 255)\n               num_trans = i+1;\n\n            if (channels >= 3) /* RGB */\n            {\n               palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)],\n                   alpha, reciprocal);\n               palette[i].green = png_unpremultiply(entry[afirst + 1], alpha,\n                   reciprocal);\n               palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha,\n                   reciprocal);\n            }\n\n            else /* gray */\n               palette[i].blue = palette[i].red = palette[i].green =\n                   png_unpremultiply(entry[afirst], alpha, reciprocal);\n         }\n      }\n\n      else /* Color-map has sRGB values */\n      {\n         png_const_bytep entry = png_voidcast(png_const_bytep, cmap);\n\n         entry += (unsigned int)i * channels;\n\n         switch (channels)\n         {\n            case 4:\n               tRNS[i] = entry[afirst ? 0 : 3];\n               if (tRNS[i] < 255)\n                  num_trans = i+1;\n               /* FALLTHROUGH */\n            case 3:\n               palette[i].blue = entry[afirst + (2 ^ bgr)];\n               palette[i].green = entry[afirst + 1];\n               palette[i].red = entry[afirst + bgr];\n               break;\n\n            case 2:\n               tRNS[i] = entry[1 ^ afirst];\n               if (tRNS[i] < 255)\n                  num_trans = i+1;\n               /* FALLTHROUGH */\n            case 1:\n               palette[i].blue = palette[i].red = palette[i].green =\n                  entry[afirst];\n               break;\n\n            default:\n               break;\n         }\n      }\n   }\n\n#   ifdef afirst\n#     undef afirst\n#   endif\n#   ifdef bgr\n#     undef bgr\n#   endif\n\n   png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,\n       entries);\n\n   if (num_trans > 0)\n      png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,\n          num_trans, NULL);\n\n   image->colormap_entries = (png_uint_32)entries;\n}\n\nstatic int\npng_image_write_main(png_voidp argument)\n{\n   png_image_write_control *display = png_voidcast(png_image_write_control*,\n       argument);\n   png_imagep image = display->image;\n   png_structrp png_ptr = image->opaque->png_ptr;\n   png_inforp info_ptr = image->opaque->info_ptr;\n   png_uint_32 format = image->format;\n\n   /* The following four ints are actually booleans */\n   int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);\n   int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */\n   int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);\n   int write_16bit = linear && (display->convert_to_8bit == 0);\n\n#   ifdef PNG_BENIGN_ERRORS_SUPPORTED\n      /* Make sure we error out on any bad situation */\n      png_set_benign_errors(png_ptr, 0/*error*/);\n#   endif\n\n   /* Default the 'row_stride' parameter if required, also check the row stride\n    * and total image size to ensure that they are within the system limits.\n    */\n   {\n      unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);\n\n      if (image->width <= 0x7fffffffU/channels) /* no overflow */\n      {\n         png_uint_32 check;\n         png_uint_32 png_row_stride = image->width * channels;\n\n         if (display->row_stride == 0)\n            display->row_stride = (png_int_32)/*SAFE*/png_row_stride;\n\n         if (display->row_stride < 0)\n            check = (png_uint_32)(-display->row_stride);\n\n         else\n            check = (png_uint_32)display->row_stride;\n\n         if (check >= png_row_stride)\n         {\n            /* Now check for overflow of the image buffer calculation; this\n             * limits the whole image size to 32 bits for API compatibility with\n             * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.\n             */\n            if (image->height > 0xffffffffU/png_row_stride)\n               png_error(image->opaque->png_ptr, \"memory image too large\");\n         }\n\n         else\n            png_error(image->opaque->png_ptr, \"supplied row stride too small\");\n      }\n\n      else\n         png_error(image->opaque->png_ptr, \"image row stride too large\");\n   }\n\n   /* Set the required transforms then write the rows in the correct order. */\n   if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)\n   {\n      if (display->colormap != NULL && image->colormap_entries > 0)\n      {\n         png_uint_32 entries = image->colormap_entries;\n\n         png_set_IHDR(png_ptr, info_ptr, image->width, image->height,\n             entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),\n             PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,\n             PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\n\n         png_image_set_PLTE(display);\n      }\n\n      else\n         png_error(image->opaque->png_ptr,\n             \"no color-map for color-mapped image\");\n   }\n\n   else\n      png_set_IHDR(png_ptr, info_ptr, image->width, image->height,\n          write_16bit ? 16 : 8,\n          ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +\n          ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),\n          PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\n\n   /* Counter-intuitively the data transformations must be called *after*\n    * png_write_info, not before as in the read code, but the 'set' functions\n    * must still be called before.  Just set the color space information, never\n    * write an interlaced image.\n    */\n\n   if (write_16bit != 0)\n   {\n      /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */\n      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);\n\n      if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)\n         png_set_cHRM_fixed(png_ptr, info_ptr,\n             /* color      x       y */\n             /* white */ 31270, 32900,\n             /* red   */ 64000, 33000,\n             /* green */ 30000, 60000,\n             /* blue  */ 15000,  6000\n         );\n   }\n\n   else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)\n      png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);\n\n   /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit\n    * space must still be gamma encoded.\n    */\n   else\n      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);\n\n   /* Write the file header. */\n   png_write_info(png_ptr, info_ptr);\n\n   /* Now set up the data transformations (*after* the header is written),\n    * remove the handled transformations from the 'format' flags for checking.\n    *\n    * First check for a little endian system if writing 16-bit files.\n    */\n   if (write_16bit != 0)\n   {\n      png_uint_16 le = 0x0001;\n\n      if ((*(png_const_bytep) & le) != 0)\n         png_set_swap(png_ptr);\n   }\n\n#   ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED\n      if ((format & PNG_FORMAT_FLAG_BGR) != 0)\n      {\n         if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)\n            png_set_bgr(png_ptr);\n         format &= ~PNG_FORMAT_FLAG_BGR;\n      }\n#   endif\n\n#   ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED\n      if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)\n      {\n         if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)\n            png_set_swap_alpha(png_ptr);\n         format &= ~PNG_FORMAT_FLAG_AFIRST;\n      }\n#   endif\n\n   /* If there are 16 or fewer color-map entries we wrote a lower bit depth\n    * above, but the application data is still byte packed.\n    */\n   if (colormap != 0 && image->colormap_entries <= 16)\n      png_set_packing(png_ptr);\n\n   /* That should have handled all (both) the transforms. */\n   if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |\n         PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)\n      png_error(png_ptr, \"png_write_image: unsupported transformation\");\n\n   {\n      png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);\n      ptrdiff_t row_bytes = display->row_stride;\n\n      if (linear != 0)\n         row_bytes *= (sizeof (png_uint_16));\n\n      if (row_bytes < 0)\n         row += (image->height-1) * (-row_bytes);\n\n      display->first_row = row;\n      display->row_bytes = row_bytes;\n   }\n\n   /* Apply 'fast' options if the flag is set. */\n   if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0)\n   {\n      png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS);\n      /* NOTE: determined by experiment using pngstest, this reflects some\n       * balance between the time to write the image once and the time to read\n       * it about 50 times.  The speed-up in pngstest was about 10-20% of the\n       * total (user) time on a heavily loaded system.\n       */\n#   ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED\n      png_set_compression_level(png_ptr, 3);\n#   endif\n   }\n\n   /* Check for the cases that currently require a pre-transform on the row\n    * before it is written.  This only applies when the input is 16-bit and\n    * either there is an alpha channel or it is converted to 8-bit.\n    */\n   if ((linear != 0 && alpha != 0 ) ||\n       (colormap == 0 && display->convert_to_8bit != 0))\n   {\n      png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,\n          png_get_rowbytes(png_ptr, info_ptr)));\n      int result;\n\n      display->local_row = row;\n      if (write_16bit != 0)\n         result = png_safe_execute(image, png_write_image_16bit, display);\n      else\n         result = png_safe_execute(image, png_write_image_8bit, display);\n      display->local_row = NULL;\n\n      png_free(png_ptr, row);\n\n      /* Skip the 'write_end' on error: */\n      if (result == 0)\n         return 0;\n   }\n\n   /* Otherwise this is the case where the input is in a format currently\n    * supported by the rest of the libpng write code; call it directly.\n    */\n   else\n   {\n      png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);\n      ptrdiff_t row_bytes = display->row_bytes;\n      png_uint_32 y = image->height;\n\n      for (; y > 0; --y)\n      {\n         png_write_row(png_ptr, row);\n         row += row_bytes;\n      }\n   }\n\n   png_write_end(png_ptr, info_ptr);\n   return 1;\n}\n\n\nstatic void (PNGCBAPI\nimage_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size)\n{\n   png_image_write_control *display = png_voidcast(png_image_write_control*,\n       png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);\n   png_alloc_size_t ob = display->output_bytes;\n\n   /* Check for overflow; this should never happen: */\n   if (size <= ((png_alloc_size_t)-1) - ob)\n   {\n      /* I don't think libpng ever does this, but just in case: */\n      if (size > 0)\n      {\n         if (display->memory_bytes >= ob+size) /* writing */\n            memcpy(display->memory+ob, data, size);\n\n         /* Always update the size: */\n         display->output_bytes = ob+size;\n      }\n   }\n\n   else\n      png_error(png_ptr, \"png_image_write_to_memory: PNG too big\");\n}\n\nstatic void (PNGCBAPI\nimage_memory_flush)(png_structp png_ptr)\n{\n   PNG_UNUSED(png_ptr)\n}\n\nstatic int\npng_image_write_memory(png_voidp argument)\n{\n   png_image_write_control *display = png_voidcast(png_image_write_control*,\n       argument);\n\n   /* The rest of the memory-specific init and write_main in an error protected\n    * environment.  This case needs to use callbacks for the write operations\n    * since libpng has no built in support for writing to memory.\n    */\n   png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,\n       image_memory_write, image_memory_flush);\n\n   return png_image_write_main(display);\n}\n\nint PNGAPI\npng_image_write_to_memory(png_imagep image, void *memory,\n    png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,\n    const void *buffer, png_int_32 row_stride, const void *colormap)\n{\n   /* Write the image to the given buffer, or count the bytes if it is NULL */\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (memory_bytes != NULL && buffer != NULL)\n      {\n         /* This is to give the caller an easier error detection in the NULL\n          * case and guard against uninitialized variable problems:\n          */\n         if (memory == NULL)\n            *memory_bytes = 0;\n\n         if (png_image_write_init(image) != 0)\n         {\n            png_image_write_control display;\n            int result;\n\n            memset(&display, 0, (sizeof display));\n            display.image = image;\n            display.buffer = buffer;\n            display.row_stride = row_stride;\n            display.colormap = colormap;\n            display.convert_to_8bit = convert_to_8bit;\n            display.memory = png_voidcast(png_bytep, memory);\n            display.memory_bytes = *memory_bytes;\n            display.output_bytes = 0;\n\n            result = png_safe_execute(image, png_image_write_memory, &display);\n            png_image_free(image);\n\n            /* write_memory returns true even if we ran out of buffer. */\n            if (result)\n            {\n               /* On out-of-buffer this function returns '0' but still updates\n                * memory_bytes:\n                */\n               if (memory != NULL && display.output_bytes > *memory_bytes)\n                  result = 0;\n\n               *memory_bytes = display.output_bytes;\n            }\n\n            return result;\n         }\n\n         else\n            return 0;\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_write_to_memory: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_write_to_memory: incorrect PNG_IMAGE_VERSION\");\n\n   else\n      return 0;\n}\n\n#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED\nint PNGAPI\npng_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,\n    const void *buffer, png_int_32 row_stride, const void *colormap)\n{\n   /* Write the image to the given (FILE*). */\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (file != NULL && buffer != NULL)\n      {\n         if (png_image_write_init(image) != 0)\n         {\n            png_image_write_control display;\n            int result;\n\n            /* This is slightly evil, but png_init_io doesn't do anything other\n             * than this and we haven't changed the standard IO functions so\n             * this saves a 'safe' function.\n             */\n            image->opaque->png_ptr->io_ptr = file;\n\n            memset(&display, 0, (sizeof display));\n            display.image = image;\n            display.buffer = buffer;\n            display.row_stride = row_stride;\n            display.colormap = colormap;\n            display.convert_to_8bit = convert_to_8bit;\n\n            result = png_safe_execute(image, png_image_write_main, &display);\n            png_image_free(image);\n            return result;\n         }\n\n         else\n            return 0;\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_write_to_stdio: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION\");\n\n   else\n      return 0;\n}\n\nint PNGAPI\npng_image_write_to_file(png_imagep image, const char *file_name,\n    int convert_to_8bit, const void *buffer, png_int_32 row_stride,\n    const void *colormap)\n{\n   /* Write the image to the named file. */\n   if (image != NULL && image->version == PNG_IMAGE_VERSION)\n   {\n      if (file_name != NULL && buffer != NULL)\n      {\n         FILE *fp = fopen(file_name, \"wb\");\n\n         if (fp != NULL)\n         {\n            if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,\n                row_stride, colormap) != 0)\n            {\n               int error; /* from fflush/fclose */\n\n               /* Make sure the file is flushed correctly. */\n               if (fflush(fp) == 0 && ferror(fp) == 0)\n               {\n                  if (fclose(fp) == 0)\n                     return 1;\n\n                  error = errno; /* from fclose */\n               }\n\n               else\n               {\n                  error = errno; /* from fflush or ferror */\n                  (void)fclose(fp);\n               }\n\n               (void)remove(file_name);\n               /* The image has already been cleaned up; this is just used to\n                * set the error (because the original write succeeded).\n                */\n               return png_image_error(image, strerror(error));\n            }\n\n            else\n            {\n               /* Clean up: just the opened file. */\n               (void)fclose(fp);\n               (void)remove(file_name);\n               return 0;\n            }\n         }\n\n         else\n            return png_image_error(image, strerror(errno));\n      }\n\n      else\n         return png_image_error(image,\n             \"png_image_write_to_file: invalid argument\");\n   }\n\n   else if (image != NULL)\n      return png_image_error(image,\n          \"png_image_write_to_file: incorrect PNG_IMAGE_VERSION\");\n\n   else\n      return 0;\n}\n#endif /* SIMPLIFIED_WRITE_STDIO */\n#endif /* SIMPLIFIED_WRITE */\n#endif /* WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngwtran.c",
    "content": "\n/* pngwtran.c - transforms the data in a row for PNG writers\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_WRITE_SUPPORTED\n#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED\n\n#ifdef PNG_WRITE_PACK_SUPPORTED\n/* Pack pixels into bytes.  Pass the true bit depth in bit_depth.  The\n * row_info bit depth should be 8 (one pixel per byte).  The channels\n * should be 1 (this only happens on grayscale and paletted images).\n */\nstatic void\npng_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)\n{\n   png_debug(1, \"in png_do_pack\");\n\n   if (row_info->bit_depth == 8 &&\n      row_info->channels == 1)\n   {\n      switch ((int)bit_depth)\n      {\n         case 1:\n         {\n            png_bytep sp, dp;\n            int mask, v;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            sp = row;\n            dp = row;\n            mask = 0x80;\n            v = 0;\n\n            for (i = 0; i < row_width; i++)\n            {\n               if (*sp != 0)\n                  v |= mask;\n\n               sp++;\n\n               if (mask > 1)\n                  mask >>= 1;\n\n               else\n               {\n                  mask = 0x80;\n                  *dp = (png_byte)v;\n                  dp++;\n                  v = 0;\n               }\n            }\n\n            if (mask != 0x80)\n               *dp = (png_byte)v;\n\n            break;\n         }\n\n         case 2:\n         {\n            png_bytep sp, dp;\n            unsigned int shift;\n            int v;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            sp = row;\n            dp = row;\n            shift = 6;\n            v = 0;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_byte value;\n\n               value = (png_byte)(*sp & 0x03);\n               v |= (value << shift);\n\n               if (shift == 0)\n               {\n                  shift = 6;\n                  *dp = (png_byte)v;\n                  dp++;\n                  v = 0;\n               }\n\n               else\n                  shift -= 2;\n\n               sp++;\n            }\n\n            if (shift != 6)\n               *dp = (png_byte)v;\n\n            break;\n         }\n\n         case 4:\n         {\n            png_bytep sp, dp;\n            unsigned int shift;\n            int v;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            sp = row;\n            dp = row;\n            shift = 4;\n            v = 0;\n\n            for (i = 0; i < row_width; i++)\n            {\n               png_byte value;\n\n               value = (png_byte)(*sp & 0x0f);\n               v |= (value << shift);\n\n               if (shift == 0)\n               {\n                  shift = 4;\n                  *dp = (png_byte)v;\n                  dp++;\n                  v = 0;\n               }\n\n               else\n                  shift -= 4;\n\n               sp++;\n            }\n\n            if (shift != 4)\n               *dp = (png_byte)v;\n\n            break;\n         }\n\n         default:\n            break;\n      }\n\n      row_info->bit_depth = (png_byte)bit_depth;\n      row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,\n          row_info->width);\n   }\n}\n#endif\n\n#ifdef PNG_WRITE_SHIFT_SUPPORTED\n/* Shift pixel values to take advantage of whole range.  Pass the\n * true number of bits in bit_depth.  The row should be packed\n * according to row_info->bit_depth.  Thus, if you had a row of\n * bit depth 4, but the pixels only had values from 0 to 7, you\n * would pass 3 as bit_depth, and this routine would translate the\n * data to 0 to 15.\n */\nstatic void\npng_do_shift(png_row_infop row_info, png_bytep row,\n    png_const_color_8p bit_depth)\n{\n   png_debug(1, \"in png_do_shift\");\n\n   if (row_info->color_type != PNG_COLOR_TYPE_PALETTE)\n   {\n      int shift_start[4], shift_dec[4];\n      unsigned int channels = 0;\n\n      if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)\n      {\n         shift_start[channels] = row_info->bit_depth - bit_depth->red;\n         shift_dec[channels] = bit_depth->red;\n         channels++;\n\n         shift_start[channels] = row_info->bit_depth - bit_depth->green;\n         shift_dec[channels] = bit_depth->green;\n         channels++;\n\n         shift_start[channels] = row_info->bit_depth - bit_depth->blue;\n         shift_dec[channels] = bit_depth->blue;\n         channels++;\n      }\n\n      else\n      {\n         shift_start[channels] = row_info->bit_depth - bit_depth->gray;\n         shift_dec[channels] = bit_depth->gray;\n         channels++;\n      }\n\n      if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)\n      {\n         shift_start[channels] = row_info->bit_depth - bit_depth->alpha;\n         shift_dec[channels] = bit_depth->alpha;\n         channels++;\n      }\n\n      /* With low row depths, could only be grayscale, so one channel */\n      if (row_info->bit_depth < 8)\n      {\n         png_bytep bp = row;\n         size_t i;\n         unsigned int mask;\n         size_t row_bytes = row_info->rowbytes;\n\n         if (bit_depth->gray == 1 && row_info->bit_depth == 2)\n            mask = 0x55;\n\n         else if (row_info->bit_depth == 4 && bit_depth->gray == 3)\n            mask = 0x11;\n\n         else\n            mask = 0xff;\n\n         for (i = 0; i < row_bytes; i++, bp++)\n         {\n            int j;\n            unsigned int v, out;\n\n            v = *bp;\n            out = 0;\n\n            for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])\n            {\n               if (j > 0)\n                  out |= v << j;\n\n               else\n                  out |= (v >> (-j)) & mask;\n            }\n\n            *bp = (png_byte)(out & 0xff);\n         }\n      }\n\n      else if (row_info->bit_depth == 8)\n      {\n         png_bytep bp = row;\n         png_uint_32 i;\n         png_uint_32 istop = channels * row_info->width;\n\n         for (i = 0; i < istop; i++, bp++)\n         {\n            unsigned int c = i%channels;\n            int j;\n            unsigned int v, out;\n\n            v = *bp;\n            out = 0;\n\n            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])\n            {\n               if (j > 0)\n                  out |= v << j;\n\n               else\n                  out |= v >> (-j);\n            }\n\n            *bp = (png_byte)(out & 0xff);\n         }\n      }\n\n      else\n      {\n         png_bytep bp;\n         png_uint_32 i;\n         png_uint_32 istop = channels * row_info->width;\n\n         for (bp = row, i = 0; i < istop; i++)\n         {\n            unsigned int c = i%channels;\n            int j;\n            unsigned int value, v;\n\n            v = png_get_uint_16(bp);\n            value = 0;\n\n            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])\n            {\n               if (j > 0)\n                  value |= v << j;\n\n               else\n                  value |= v >> (-j);\n            }\n            *bp++ = (png_byte)((value >> 8) & 0xff);\n            *bp++ = (png_byte)(value & 0xff);\n         }\n      }\n   }\n}\n#endif\n\n#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED\nstatic void\npng_do_write_swap_alpha(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_write_swap_alpha\");\n\n   {\n      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This converts from ARGB to RGBA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               png_byte save = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = save;\n            }\n         }\n\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         else\n         {\n            /* This converts from AARRGGBB to RRGGBBAA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               png_byte save[2];\n               save[0] = *(sp++);\n               save[1] = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = save[0];\n               *(dp++) = save[1];\n            }\n         }\n#endif /* WRITE_16BIT */\n      }\n\n      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This converts from AG to GA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               png_byte save = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = save;\n            }\n         }\n\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         else\n         {\n            /* This converts from AAGG to GGAA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               png_byte save[2];\n               save[0] = *(sp++);\n               save[1] = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = save[0];\n               *(dp++) = save[1];\n            }\n         }\n#endif /* WRITE_16BIT */\n      }\n   }\n}\n#endif\n\n#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED\nstatic void\npng_do_write_invert_alpha(png_row_infop row_info, png_bytep row)\n{\n   png_debug(1, \"in png_do_write_invert_alpha\");\n\n   {\n      if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This inverts the alpha channel in RGBA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               /* Does nothing\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               */\n               sp+=3; dp = sp;\n               *dp = (png_byte)(255 - *(sp++));\n            }\n         }\n\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         else\n         {\n            /* This inverts the alpha channel in RRGGBBAA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               /* Does nothing\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               */\n               sp+=6; dp = sp;\n               *(dp++) = (png_byte)(255 - *(sp++));\n               *dp     = (png_byte)(255 - *(sp++));\n            }\n         }\n#endif /* WRITE_16BIT */\n      }\n\n      else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n      {\n         if (row_info->bit_depth == 8)\n         {\n            /* This inverts the alpha channel in GA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               *(dp++) = *(sp++);\n               *(dp++) = (png_byte)(255 - *(sp++));\n            }\n         }\n\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         else\n         {\n            /* This inverts the alpha channel in GGAA */\n            png_bytep sp, dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            for (i = 0, sp = dp = row; i < row_width; i++)\n            {\n               /* Does nothing\n               *(dp++) = *(sp++);\n               *(dp++) = *(sp++);\n               */\n               sp+=2; dp = sp;\n               *(dp++) = (png_byte)(255 - *(sp++));\n               *dp     = (png_byte)(255 - *(sp++));\n            }\n         }\n#endif /* WRITE_16BIT */\n      }\n   }\n}\n#endif\n\n/* Transform the data according to the user's wishes.  The order of\n * transformations is significant.\n */\nvoid /* PRIVATE */\npng_do_write_transformations(png_structrp png_ptr, png_row_infop row_info)\n{\n   png_debug(1, \"in png_do_write_transformations\");\n\n   if (png_ptr == NULL)\n      return;\n\n#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED\n   if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)\n      if (png_ptr->write_user_transform_fn != NULL)\n         (*(png_ptr->write_user_transform_fn)) /* User write transform\n                                                 function */\n             (png_ptr,  /* png_ptr */\n             row_info,  /* row_info: */\n                /*  png_uint_32 width;       width of row */\n                /*  size_t rowbytes;         number of bytes in row */\n                /*  png_byte color_type;     color type of pixels */\n                /*  png_byte bit_depth;      bit depth of samples */\n                /*  png_byte channels;       number of channels (1-4) */\n                /*  png_byte pixel_depth;    bits per pixel (depth*channels) */\n             png_ptr->row_buf + 1);      /* start of pixel data for row */\n#endif\n\n#ifdef PNG_WRITE_FILLER_SUPPORTED\n   if ((png_ptr->transformations & PNG_FILLER) != 0)\n      png_do_strip_channel(row_info, png_ptr->row_buf + 1,\n          !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));\n#endif\n\n#ifdef PNG_WRITE_PACKSWAP_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACKSWAP) != 0)\n      png_do_packswap(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_WRITE_PACK_SUPPORTED\n   if ((png_ptr->transformations & PNG_PACK) != 0)\n      png_do_pack(row_info, png_ptr->row_buf + 1,\n          (png_uint_32)png_ptr->bit_depth);\n#endif\n\n#ifdef PNG_WRITE_SWAP_SUPPORTED\n#  ifdef PNG_16BIT_SUPPORTED\n   if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)\n      png_do_swap(row_info, png_ptr->row_buf + 1);\n#  endif\n#endif\n\n#ifdef PNG_WRITE_SHIFT_SUPPORTED\n   if ((png_ptr->transformations & PNG_SHIFT) != 0)\n      png_do_shift(row_info, png_ptr->row_buf + 1,\n           &(png_ptr->shift));\n#endif\n\n#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)\n      png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED\n   if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)\n      png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_WRITE_BGR_SUPPORTED\n   if ((png_ptr->transformations & PNG_BGR) != 0)\n      png_do_bgr(row_info, png_ptr->row_buf + 1);\n#endif\n\n#ifdef PNG_WRITE_INVERT_SUPPORTED\n   if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)\n      png_do_invert(row_info, png_ptr->row_buf + 1);\n#endif\n}\n#endif /* WRITE_TRANSFORMS */\n#endif /* WRITE */\n"
  },
  {
    "path": "dlib/external/libpng/pngwutil.c",
    "content": "\n/* pngwutil.c - utilities to write a PNG file\n *\n * Copyright (c) 2018 Cosmin Truta\n * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson\n * Copyright (c) 1996-1997 Andreas Dilger\n * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n *\n * This code is released under the libpng license.\n * For conditions of distribution and use, see the disclaimer\n * and license in png.h\n */\n\n#include \"pngpriv.h\"\n\n#ifdef PNG_WRITE_SUPPORTED\n\n#ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED\n/* Place a 32-bit number into a buffer in PNG byte order.  We work\n * with unsigned numbers for convenience, although one supported\n * ancillary chunk uses signed (two's complement) numbers.\n */\nvoid PNGAPI\npng_save_uint_32(png_bytep buf, png_uint_32 i)\n{\n   buf[0] = (png_byte)((i >> 24) & 0xffU);\n   buf[1] = (png_byte)((i >> 16) & 0xffU);\n   buf[2] = (png_byte)((i >>  8) & 0xffU);\n   buf[3] = (png_byte)( i        & 0xffU);\n}\n\n/* Place a 16-bit number into a buffer in PNG byte order.\n * The parameter is declared unsigned int, not png_uint_16,\n * just to avoid potential problems on pre-ANSI C compilers.\n */\nvoid PNGAPI\npng_save_uint_16(png_bytep buf, unsigned int i)\n{\n   buf[0] = (png_byte)((i >> 8) & 0xffU);\n   buf[1] = (png_byte)( i       & 0xffU);\n}\n#endif\n\n/* Simple function to write the signature.  If we have already written\n * the magic bytes of the signature, or more likely, the PNG stream is\n * being embedded into another stream and doesn't need its own signature,\n * we should call png_set_sig_bytes() to tell libpng how many of the\n * bytes have already been written.\n */\nvoid PNGAPI\npng_write_sig(png_structrp png_ptr)\n{\n   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   /* Inform the I/O callback that the signature is being written */\n   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE;\n#endif\n\n   /* Write the rest of the 8 byte signature */\n   png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],\n       (size_t)(8 - png_ptr->sig_bytes));\n\n   if (png_ptr->sig_bytes < 3)\n      png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;\n}\n\n/* Write the start of a PNG chunk.  The type is the chunk type.\n * The total_length is the sum of the lengths of all the data you will be\n * passing in png_write_chunk_data().\n */\nstatic void\npng_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name,\n    png_uint_32 length)\n{\n   png_byte buf[8];\n\n#if defined(PNG_DEBUG) && (PNG_DEBUG > 0)\n   PNG_CSTRING_FROM_CHUNK(buf, chunk_name);\n   png_debug2(0, \"Writing %s chunk, length = %lu\", buf, (unsigned long)length);\n#endif\n\n   if (png_ptr == NULL)\n      return;\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   /* Inform the I/O callback that the chunk header is being written.\n    * PNG_IO_CHUNK_HDR requires a single I/O call.\n    */\n   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR;\n#endif\n\n   /* Write the length and the chunk name */\n   png_save_uint_32(buf, length);\n   png_save_uint_32(buf + 4, chunk_name);\n   png_write_data(png_ptr, buf, 8);\n\n   /* Put the chunk name into png_ptr->chunk_name */\n   png_ptr->chunk_name = chunk_name;\n\n   /* Reset the crc and run it over the chunk name */\n   png_reset_crc(png_ptr);\n\n   png_calculate_crc(png_ptr, buf + 4, 4);\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   /* Inform the I/O callback that chunk data will (possibly) be written.\n    * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.\n    */\n   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA;\n#endif\n}\n\nvoid PNGAPI\npng_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string,\n    png_uint_32 length)\n{\n   png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length);\n}\n\n/* Write the data of a PNG chunk started with png_write_chunk_header().\n * Note that multiple calls to this function are allowed, and that the\n * sum of the lengths from these calls *must* add up to the total_length\n * given to png_write_chunk_header().\n */\nvoid PNGAPI\npng_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length)\n{\n   /* Write the data, and run the CRC over it */\n   if (png_ptr == NULL)\n      return;\n\n   if (data != NULL && length > 0)\n   {\n      png_write_data(png_ptr, data, length);\n\n      /* Update the CRC after writing the data,\n       * in case the user I/O routine alters it.\n       */\n      png_calculate_crc(png_ptr, data, length);\n   }\n}\n\n/* Finish a chunk started with png_write_chunk_header(). */\nvoid PNGAPI\npng_write_chunk_end(png_structrp png_ptr)\n{\n   png_byte buf[4];\n\n   if (png_ptr == NULL) return;\n\n#ifdef PNG_IO_STATE_SUPPORTED\n   /* Inform the I/O callback that the chunk CRC is being written.\n    * PNG_IO_CHUNK_CRC requires a single I/O function call.\n    */\n   png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC;\n#endif\n\n   /* Write the crc in a single operation */\n   png_save_uint_32(buf, png_ptr->crc);\n\n   png_write_data(png_ptr, buf, 4);\n}\n\n/* Write a PNG chunk all at once.  The type is an array of ASCII characters\n * representing the chunk name.  The array must be at least 4 bytes in\n * length, and does not need to be null terminated.  To be safe, pass the\n * pre-defined chunk names here, and if you need a new one, define it\n * where the others are defined.  The length is the length of the data.\n * All the data must be present.  If that is not possible, use the\n * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()\n * functions instead.\n */\nstatic void\npng_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,\n    png_const_bytep data, size_t length)\n{\n   if (png_ptr == NULL)\n      return;\n\n   /* On 64-bit architectures 'length' may not fit in a png_uint_32. */\n   if (length > PNG_UINT_31_MAX)\n      png_error(png_ptr, \"length exceeds PNG maximum\");\n\n   png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length);\n   png_write_chunk_data(png_ptr, data, length);\n   png_write_chunk_end(png_ptr);\n}\n\n/* This is the API that calls the internal function above. */\nvoid PNGAPI\npng_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,\n    png_const_bytep data, size_t length)\n{\n   png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,\n       length);\n}\n\n/* This is used below to find the size of an image to pass to png_deflate_claim,\n * so it only needs to be accurate if the size is less than 16384 bytes (the\n * point at which a lower LZ window size can be used.)\n */\nstatic png_alloc_size_t\npng_image_size(png_structrp png_ptr)\n{\n   /* Only return sizes up to the maximum of a png_uint_32; do this by limiting\n    * the width and height used to 15 bits.\n    */\n   png_uint_32 h = png_ptr->height;\n\n   if (png_ptr->rowbytes < 32768 && h < 32768)\n   {\n      if (png_ptr->interlaced != 0)\n      {\n         /* Interlacing makes the image larger because of the replication of\n          * both the filter byte and the padding to a byte boundary.\n          */\n         png_uint_32 w = png_ptr->width;\n         unsigned int pd = png_ptr->pixel_depth;\n         png_alloc_size_t cb_base;\n         int pass;\n\n         for (cb_base=0, pass=0; pass<=6; ++pass)\n         {\n            png_uint_32 pw = PNG_PASS_COLS(w, pass);\n\n            if (pw > 0)\n               cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass);\n         }\n\n         return cb_base;\n      }\n\n      else\n         return (png_ptr->rowbytes+1) * h;\n   }\n\n   else\n      return 0xffffffffU;\n}\n\n#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n   /* This is the code to hack the first two bytes of the deflate stream (the\n    * deflate header) to correct the windowBits value to match the actual data\n    * size.  Note that the second argument is the *uncompressed* size but the\n    * first argument is the *compressed* data (and it must be deflate\n    * compressed.)\n    */\nstatic void\noptimize_cmf(png_bytep data, png_alloc_size_t data_size)\n{\n   /* Optimize the CMF field in the zlib stream.  The resultant zlib stream is\n    * still compliant to the stream specification.\n    */\n   if (data_size <= 16384) /* else windowBits must be 15 */\n   {\n      unsigned int z_cmf = data[0];  /* zlib compression method and flags */\n\n      if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)\n      {\n         unsigned int z_cinfo;\n         unsigned int half_z_window_size;\n\n         z_cinfo = z_cmf >> 4;\n         half_z_window_size = 1U << (z_cinfo + 7);\n\n         if (data_size <= half_z_window_size) /* else no change */\n         {\n            unsigned int tmp;\n\n            do\n            {\n               half_z_window_size >>= 1;\n               --z_cinfo;\n            }\n            while (z_cinfo > 0 && data_size <= half_z_window_size);\n\n            z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);\n\n            data[0] = (png_byte)z_cmf;\n            tmp = data[1] & 0xe0;\n            tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f;\n            data[1] = (png_byte)tmp;\n         }\n      }\n   }\n}\n#endif /* WRITE_OPTIMIZE_CMF */\n\n/* Initialize the compressor for the appropriate type of compression. */\nstatic int\npng_deflate_claim(png_structrp png_ptr, png_uint_32 owner,\n    png_alloc_size_t data_size)\n{\n   if (png_ptr->zowner != 0)\n   {\n#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)\n      char msg[64];\n\n      PNG_STRING_FROM_CHUNK(msg, owner);\n      msg[4] = ':';\n      msg[5] = ' ';\n      PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner);\n      /* So the message that results is \"<chunk> using zstream\"; this is an\n       * internal error, but is very useful for debugging.  i18n requirements\n       * are minimal.\n       */\n      (void)png_safecat(msg, (sizeof msg), 10, \" using zstream\");\n#endif\n#if PNG_RELEASE_BUILD\n         png_warning(png_ptr, msg);\n\n         /* Attempt sane error recovery */\n         if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */\n         {\n            png_ptr->zstream.msg = PNGZ_MSG_CAST(\"in use by IDAT\");\n            return Z_STREAM_ERROR;\n         }\n\n         png_ptr->zowner = 0;\n#else\n         png_error(png_ptr, msg);\n#endif\n   }\n\n   {\n      int level = png_ptr->zlib_level;\n      int method = png_ptr->zlib_method;\n      int windowBits = png_ptr->zlib_window_bits;\n      int memLevel = png_ptr->zlib_mem_level;\n      int strategy; /* set below */\n      int ret; /* zlib return code */\n\n      if (owner == png_IDAT)\n      {\n         if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0)\n            strategy = png_ptr->zlib_strategy;\n\n         else if (png_ptr->do_filter != PNG_FILTER_NONE)\n            strategy = PNG_Z_DEFAULT_STRATEGY;\n\n         else\n            strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY;\n      }\n\n      else\n      {\n#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED\n            level = png_ptr->zlib_text_level;\n            method = png_ptr->zlib_text_method;\n            windowBits = png_ptr->zlib_text_window_bits;\n            memLevel = png_ptr->zlib_text_mem_level;\n            strategy = png_ptr->zlib_text_strategy;\n#else\n            /* If customization is not supported the values all come from the\n             * IDAT values except for the strategy, which is fixed to the\n             * default.  (This is the pre-1.6.0 behavior too, although it was\n             * implemented in a very different way.)\n             */\n            strategy = Z_DEFAULT_STRATEGY;\n#endif\n      }\n\n      /* Adjust 'windowBits' down if larger than 'data_size'; to stop this\n       * happening just pass 32768 as the data_size parameter.  Notice that zlib\n       * requires an extra 262 bytes in the window in addition to the data to be\n       * able to see the whole of the data, so if data_size+262 takes us to the\n       * next windowBits size we need to fix up the value later.  (Because even\n       * though deflate needs the extra window, inflate does not!)\n       */\n      if (data_size <= 16384)\n      {\n         /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to\n          * work round a Microsoft Visual C misbehavior which, contrary to C-90,\n          * widens the result of the following shift to 64-bits if (and,\n          * apparently, only if) it is used in a test.\n          */\n         unsigned int half_window_size = 1U << (windowBits-1);\n\n         while (data_size + 262 <= half_window_size)\n         {\n            half_window_size >>= 1;\n            --windowBits;\n         }\n      }\n\n      /* Check against the previous initialized values, if any. */\n      if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 &&\n         (png_ptr->zlib_set_level != level ||\n         png_ptr->zlib_set_method != method ||\n         png_ptr->zlib_set_window_bits != windowBits ||\n         png_ptr->zlib_set_mem_level != memLevel ||\n         png_ptr->zlib_set_strategy != strategy))\n      {\n         if (deflateEnd(&png_ptr->zstream) != Z_OK)\n            png_warning(png_ptr, \"deflateEnd failed (ignored)\");\n\n         png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED;\n      }\n\n      /* For safety clear out the input and output pointers (currently zlib\n       * doesn't use them on Init, but it might in the future).\n       */\n      png_ptr->zstream.next_in = NULL;\n      png_ptr->zstream.avail_in = 0;\n      png_ptr->zstream.next_out = NULL;\n      png_ptr->zstream.avail_out = 0;\n\n      /* Now initialize if required, setting the new parameters, otherwise just\n       * do a simple reset to the previous parameters.\n       */\n      if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)\n         ret = deflateReset(&png_ptr->zstream);\n\n      else\n      {\n         ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,\n             memLevel, strategy);\n\n         if (ret == Z_OK)\n            png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;\n      }\n\n      /* The return code is from either deflateReset or deflateInit2; they have\n       * pretty much the same set of error codes.\n       */\n      if (ret == Z_OK)\n         png_ptr->zowner = owner;\n\n      else\n         png_zstream_error(png_ptr, ret);\n\n      return ret;\n   }\n}\n\n/* Clean up (or trim) a linked list of compression buffers. */\nvoid /* PRIVATE */\npng_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)\n{\n   png_compression_bufferp list = *listp;\n\n   if (list != NULL)\n   {\n      *listp = NULL;\n\n      do\n      {\n         png_compression_bufferp next = list->next;\n\n         png_free(png_ptr, list);\n         list = next;\n      }\n      while (list != NULL);\n   }\n}\n\n#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED\n/* This pair of functions encapsulates the operation of (a) compressing a\n * text string, and (b) issuing it later as a series of chunk data writes.\n * The compression_state structure is shared context for these functions\n * set up by the caller to allow access to the relevant local variables.\n *\n * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size\n * temporary buffers.  From 1.6.0 it is retained in png_struct so that it will\n * be correctly freed in the event of a write error (previous implementations\n * just leaked memory.)\n */\ntypedef struct\n{\n   png_const_bytep      input;        /* The uncompressed input data */\n   png_alloc_size_t     input_len;    /* Its length */\n   png_uint_32          output_len;   /* Final compressed length */\n   png_byte             output[1024]; /* First block of output */\n} compression_state;\n\nstatic void\npng_text_compress_init(compression_state *comp, png_const_bytep input,\n    png_alloc_size_t input_len)\n{\n   comp->input = input;\n   comp->input_len = input_len;\n   comp->output_len = 0;\n}\n\n/* Compress the data in the compression state input */\nstatic int\npng_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,\n    compression_state *comp, png_uint_32 prefix_len)\n{\n   int ret;\n\n   /* To find the length of the output it is necessary to first compress the\n    * input. The result is buffered rather than using the two-pass algorithm\n    * that is used on the inflate side; deflate is assumed to be slower and a\n    * PNG writer is assumed to have more memory available than a PNG reader.\n    *\n    * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an\n    * upper limit on the output size, but it is always bigger than the input\n    * size so it is likely to be more efficient to use this linked-list\n    * approach.\n    */\n   ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len);\n\n   if (ret != Z_OK)\n      return ret;\n\n   /* Set up the compression buffers, we need a loop here to avoid overflowing a\n    * uInt.  Use ZLIB_IO_MAX to limit the input.  The output is always limited\n    * by the output buffer size, so there is no need to check that.  Since this\n    * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits\n    * in size.\n    */\n   {\n      png_compression_bufferp *end = &png_ptr->zbuffer_list;\n      png_alloc_size_t input_len = comp->input_len; /* may be zero! */\n      png_uint_32 output_len;\n\n      /* zlib updates these for us: */\n      png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input);\n      png_ptr->zstream.avail_in = 0; /* Set below */\n      png_ptr->zstream.next_out = comp->output;\n      png_ptr->zstream.avail_out = (sizeof comp->output);\n\n      output_len = png_ptr->zstream.avail_out;\n\n      do\n      {\n         uInt avail_in = ZLIB_IO_MAX;\n\n         if (avail_in > input_len)\n            avail_in = (uInt)input_len;\n\n         input_len -= avail_in;\n\n         png_ptr->zstream.avail_in = avail_in;\n\n         if (png_ptr->zstream.avail_out == 0)\n         {\n            png_compression_buffer *next;\n\n            /* Chunk data is limited to 2^31 bytes in length, so the prefix\n             * length must be counted here.\n             */\n            if (output_len + prefix_len > PNG_UINT_31_MAX)\n            {\n               ret = Z_MEM_ERROR;\n               break;\n            }\n\n            /* Need a new (malloc'ed) buffer, but there may be one present\n             * already.\n             */\n            next = *end;\n            if (next == NULL)\n            {\n               next = png_voidcast(png_compression_bufferp, png_malloc_base\n                  (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));\n\n               if (next == NULL)\n               {\n                  ret = Z_MEM_ERROR;\n                  break;\n               }\n\n               /* Link in this buffer (so that it will be freed later) */\n               next->next = NULL;\n               *end = next;\n            }\n\n            png_ptr->zstream.next_out = next->output;\n            png_ptr->zstream.avail_out = png_ptr->zbuffer_size;\n            output_len += png_ptr->zstream.avail_out;\n\n            /* Move 'end' to the next buffer pointer. */\n            end = &next->next;\n         }\n\n         /* Compress the data */\n         ret = deflate(&png_ptr->zstream,\n             input_len > 0 ? Z_NO_FLUSH : Z_FINISH);\n\n         /* Claw back input data that was not consumed (because avail_in is\n          * reset above every time round the loop).\n          */\n         input_len += png_ptr->zstream.avail_in;\n         png_ptr->zstream.avail_in = 0; /* safety */\n      }\n      while (ret == Z_OK);\n\n      /* There may be some space left in the last output buffer. This needs to\n       * be subtracted from output_len.\n       */\n      output_len -= png_ptr->zstream.avail_out;\n      png_ptr->zstream.avail_out = 0; /* safety */\n      comp->output_len = output_len;\n\n      /* Now double check the output length, put in a custom message if it is\n       * too long.  Otherwise ensure the z_stream::msg pointer is set to\n       * something.\n       */\n      if (output_len + prefix_len >= PNG_UINT_31_MAX)\n      {\n         png_ptr->zstream.msg = PNGZ_MSG_CAST(\"compressed data too long\");\n         ret = Z_MEM_ERROR;\n      }\n\n      else\n         png_zstream_error(png_ptr, ret);\n\n      /* Reset zlib for another zTXt/iTXt or image data */\n      png_ptr->zowner = 0;\n\n      /* The only success case is Z_STREAM_END, input_len must be 0; if not this\n       * is an internal error.\n       */\n      if (ret == Z_STREAM_END && input_len == 0)\n      {\n#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n         /* Fix up the deflate header, if required */\n         optimize_cmf(comp->output, comp->input_len);\n#endif\n         /* But Z_OK is returned, not Z_STREAM_END; this allows the claim\n          * function above to return Z_STREAM_END on an error (though it never\n          * does in the current versions of zlib.)\n          */\n         return Z_OK;\n      }\n\n      else\n         return ret;\n   }\n}\n\n/* Ship the compressed text out via chunk writes */\nstatic void\npng_write_compressed_data_out(png_structrp png_ptr, compression_state *comp)\n{\n   png_uint_32 output_len = comp->output_len;\n   png_const_bytep output = comp->output;\n   png_uint_32 avail = (sizeof comp->output);\n   png_compression_buffer *next = png_ptr->zbuffer_list;\n\n   for (;;)\n   {\n      if (avail > output_len)\n         avail = output_len;\n\n      png_write_chunk_data(png_ptr, output, avail);\n\n      output_len -= avail;\n\n      if (output_len == 0 || next == NULL)\n         break;\n\n      avail = png_ptr->zbuffer_size;\n      output = next->output;\n      next = next->next;\n   }\n\n   /* This is an internal error; 'next' must have been NULL! */\n   if (output_len > 0)\n      png_error(png_ptr, \"error writing ancillary chunked compressed data\");\n}\n#endif /* WRITE_COMPRESSED_TEXT */\n\n/* Write the IHDR chunk, and update the png_struct with the necessary\n * information.  Note that the rest of this code depends upon this\n * information being correct.\n */\nvoid /* PRIVATE */\npng_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height,\n    int bit_depth, int color_type, int compression_type, int filter_type,\n    int interlace_type)\n{\n   png_byte buf[13]; /* Buffer to store the IHDR info */\n   int is_invalid_depth;\n\n   png_debug(1, \"in png_write_IHDR\");\n\n   /* Check that we have valid input data from the application info */\n   switch (color_type)\n   {\n      case PNG_COLOR_TYPE_GRAY:\n         switch (bit_depth)\n         {\n            case 1:\n            case 2:\n            case 4:\n            case 8:\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n            case 16:\n#endif\n               png_ptr->channels = 1; break;\n\n            default:\n               png_error(png_ptr,\n                   \"Invalid bit depth for grayscale image\");\n         }\n         break;\n\n      case PNG_COLOR_TYPE_RGB:\n         is_invalid_depth = (bit_depth != 8);\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         is_invalid_depth = (is_invalid_depth && bit_depth != 16);\n#endif\n         if (is_invalid_depth)\n            png_error(png_ptr, \"Invalid bit depth for RGB image\");\n\n         png_ptr->channels = 3;\n         break;\n\n      case PNG_COLOR_TYPE_PALETTE:\n         switch (bit_depth)\n         {\n            case 1:\n            case 2:\n            case 4:\n            case 8:\n               png_ptr->channels = 1;\n               break;\n\n            default:\n               png_error(png_ptr, \"Invalid bit depth for paletted image\");\n         }\n         break;\n\n      case PNG_COLOR_TYPE_GRAY_ALPHA:\n         is_invalid_depth = (bit_depth != 8);\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         is_invalid_depth = (is_invalid_depth && bit_depth != 16);\n#endif\n         if (is_invalid_depth)\n            png_error(png_ptr, \"Invalid bit depth for grayscale+alpha image\");\n\n         png_ptr->channels = 2;\n         break;\n\n      case PNG_COLOR_TYPE_RGB_ALPHA:\n         is_invalid_depth = (bit_depth != 8);\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n         is_invalid_depth = (is_invalid_depth && bit_depth != 16);\n#endif\n         if (is_invalid_depth)\n            png_error(png_ptr, \"Invalid bit depth for RGBA image\");\n\n         png_ptr->channels = 4;\n         break;\n\n      default:\n         png_error(png_ptr, \"Invalid image color type specified\");\n   }\n\n   if (compression_type != PNG_COMPRESSION_TYPE_BASE)\n   {\n      png_warning(png_ptr, \"Invalid compression type specified\");\n      compression_type = PNG_COMPRESSION_TYPE_BASE;\n   }\n\n   /* Write filter_method 64 (intrapixel differencing) only if\n    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and\n    * 2. Libpng did not write a PNG signature (this filter_method is only\n    *    used in PNG datastreams that are embedded in MNG datastreams) and\n    * 3. The application called png_permit_mng_features with a mask that\n    *    included PNG_FLAG_MNG_FILTER_64 and\n    * 4. The filter_method is 64 and\n    * 5. The color_type is RGB or RGBA\n    */\n   if (\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n       !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&\n       ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&\n       (color_type == PNG_COLOR_TYPE_RGB ||\n        color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&\n       (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&\n#endif\n       filter_type != PNG_FILTER_TYPE_BASE)\n   {\n      png_warning(png_ptr, \"Invalid filter type specified\");\n      filter_type = PNG_FILTER_TYPE_BASE;\n   }\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   if (interlace_type != PNG_INTERLACE_NONE &&\n       interlace_type != PNG_INTERLACE_ADAM7)\n   {\n      png_warning(png_ptr, \"Invalid interlace type specified\");\n      interlace_type = PNG_INTERLACE_ADAM7;\n   }\n#else\n   interlace_type=PNG_INTERLACE_NONE;\n#endif\n\n   /* Save the relevant information */\n   png_ptr->bit_depth = (png_byte)bit_depth;\n   png_ptr->color_type = (png_byte)color_type;\n   png_ptr->interlaced = (png_byte)interlace_type;\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n   png_ptr->filter_type = (png_byte)filter_type;\n#endif\n   png_ptr->compression_type = (png_byte)compression_type;\n   png_ptr->width = width;\n   png_ptr->height = height;\n\n   png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);\n   png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);\n   /* Set the usr info, so any transformations can modify it */\n   png_ptr->usr_width = png_ptr->width;\n   png_ptr->usr_bit_depth = png_ptr->bit_depth;\n   png_ptr->usr_channels = png_ptr->channels;\n\n   /* Pack the header information into the buffer */\n   png_save_uint_32(buf, width);\n   png_save_uint_32(buf + 4, height);\n   buf[8] = (png_byte)bit_depth;\n   buf[9] = (png_byte)color_type;\n   buf[10] = (png_byte)compression_type;\n   buf[11] = (png_byte)filter_type;\n   buf[12] = (png_byte)interlace_type;\n\n   /* Write the chunk */\n   png_write_complete_chunk(png_ptr, png_IHDR, buf, 13);\n\n   if ((png_ptr->do_filter) == PNG_NO_FILTERS)\n   {\n      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||\n          png_ptr->bit_depth < 8)\n         png_ptr->do_filter = PNG_FILTER_NONE;\n\n      else\n         png_ptr->do_filter = PNG_ALL_FILTERS;\n   }\n\n   png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */\n}\n\n/* Write the palette.  We are careful not to trust png_color to be in the\n * correct order for PNG, so people can redefine it to any convenient\n * structure.\n */\nvoid /* PRIVATE */\npng_write_PLTE(png_structrp png_ptr, png_const_colorp palette,\n    png_uint_32 num_pal)\n{\n   png_uint_32 max_palette_length, i;\n   png_const_colorp pal_ptr;\n   png_byte buf[3];\n\n   png_debug(1, \"in png_write_PLTE\");\n\n   max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?\n      (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;\n\n   if ((\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n       (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 &&\n#endif\n       num_pal == 0) || num_pal > max_palette_length)\n   {\n      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)\n      {\n         png_error(png_ptr, \"Invalid number of colors in palette\");\n      }\n\n      else\n      {\n         png_warning(png_ptr, \"Invalid number of colors in palette\");\n         return;\n      }\n   }\n\n   if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)\n   {\n      png_warning(png_ptr,\n          \"Ignoring request to write a PLTE chunk in grayscale PNG\");\n\n      return;\n   }\n\n   png_ptr->num_palette = (png_uint_16)num_pal;\n   png_debug1(3, \"num_palette = %d\", png_ptr->num_palette);\n\n   png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));\n#ifdef PNG_POINTER_INDEXING_SUPPORTED\n\n   for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)\n   {\n      buf[0] = pal_ptr->red;\n      buf[1] = pal_ptr->green;\n      buf[2] = pal_ptr->blue;\n      png_write_chunk_data(png_ptr, buf, 3);\n   }\n\n#else\n   /* This is a little slower but some buggy compilers need to do this\n    * instead\n    */\n   pal_ptr=palette;\n\n   for (i = 0; i < num_pal; i++)\n   {\n      buf[0] = pal_ptr[i].red;\n      buf[1] = pal_ptr[i].green;\n      buf[2] = pal_ptr[i].blue;\n      png_write_chunk_data(png_ptr, buf, 3);\n   }\n\n#endif\n   png_write_chunk_end(png_ptr);\n   png_ptr->mode |= PNG_HAVE_PLTE;\n}\n\n/* This is similar to png_text_compress, above, except that it does not require\n * all of the data at once and, instead of buffering the compressed result,\n * writes it as IDAT chunks.  Unlike png_text_compress it *can* png_error out\n * because it calls the write interface.  As a result it does its own error\n * reporting and does not return an error code.  In the event of error it will\n * just call png_error.  The input data length may exceed 32-bits.  The 'flush'\n * parameter is exactly the same as that to deflate, with the following\n * meanings:\n *\n * Z_NO_FLUSH: normal incremental output of compressed data\n * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush\n * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up\n *\n * The routine manages the acquire and release of the png_ptr->zstream by\n * checking and (at the end) clearing png_ptr->zowner; it does some sanity\n * checks on the 'mode' flags while doing this.\n */\nvoid /* PRIVATE */\npng_compress_IDAT(png_structrp png_ptr, png_const_bytep input,\n    png_alloc_size_t input_len, int flush)\n{\n   if (png_ptr->zowner != png_IDAT)\n   {\n      /* First time.   Ensure we have a temporary buffer for compression and\n       * trim the buffer list if it has more than one entry to free memory.\n       * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been\n       * created at this point, but the check here is quick and safe.\n       */\n      if (png_ptr->zbuffer_list == NULL)\n      {\n         png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,\n             png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));\n         png_ptr->zbuffer_list->next = NULL;\n      }\n\n      else\n         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next);\n\n      /* It is a terminal error if we can't claim the zstream. */\n      if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK)\n         png_error(png_ptr, png_ptr->zstream.msg);\n\n      /* The output state is maintained in png_ptr->zstream, so it must be\n       * initialized here after the claim.\n       */\n      png_ptr->zstream.next_out = png_ptr->zbuffer_list->output;\n      png_ptr->zstream.avail_out = png_ptr->zbuffer_size;\n   }\n\n   /* Now loop reading and writing until all the input is consumed or an error\n    * terminates the operation.  The _out values are maintained across calls to\n    * this function, but the input must be reset each time.\n    */\n   png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);\n   png_ptr->zstream.avail_in = 0; /* set below */\n   for (;;)\n   {\n      int ret;\n\n      /* INPUT: from the row data */\n      uInt avail = ZLIB_IO_MAX;\n\n      if (avail > input_len)\n         avail = (uInt)input_len; /* safe because of the check */\n\n      png_ptr->zstream.avail_in = avail;\n      input_len -= avail;\n\n      ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush);\n\n      /* Include as-yet unconsumed input */\n      input_len += png_ptr->zstream.avail_in;\n      png_ptr->zstream.avail_in = 0;\n\n      /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note\n       * that these two zstream fields are preserved across the calls, therefore\n       * there is no need to set these up on entry to the loop.\n       */\n      if (png_ptr->zstream.avail_out == 0)\n      {\n         png_bytep data = png_ptr->zbuffer_list->output;\n         uInt size = png_ptr->zbuffer_size;\n\n         /* Write an IDAT containing the data then reset the buffer.  The\n          * first IDAT may need deflate header optimization.\n          */\n#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n            if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&\n                png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)\n               optimize_cmf(data, png_image_size(png_ptr));\n#endif\n\n         if (size > 0)\n            png_write_complete_chunk(png_ptr, png_IDAT, data, size);\n         png_ptr->mode |= PNG_HAVE_IDAT;\n\n         png_ptr->zstream.next_out = data;\n         png_ptr->zstream.avail_out = size;\n\n         /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with\n          * the same flush parameter until it has finished output, for NO_FLUSH\n          * it doesn't matter.\n          */\n         if (ret == Z_OK && flush != Z_NO_FLUSH)\n            continue;\n      }\n\n      /* The order of these checks doesn't matter much; it just affects which\n       * possible error might be detected if multiple things go wrong at once.\n       */\n      if (ret == Z_OK) /* most likely return code! */\n      {\n         /* If all the input has been consumed then just return.  If Z_FINISH\n          * was used as the flush parameter something has gone wrong if we get\n          * here.\n          */\n         if (input_len == 0)\n         {\n            if (flush == Z_FINISH)\n               png_error(png_ptr, \"Z_OK on Z_FINISH with output space\");\n\n            return;\n         }\n      }\n\n      else if (ret == Z_STREAM_END && flush == Z_FINISH)\n      {\n         /* This is the end of the IDAT data; any pending output must be\n          * flushed.  For small PNG files we may still be at the beginning.\n          */\n         png_bytep data = png_ptr->zbuffer_list->output;\n         uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out;\n\n#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED\n         if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 &&\n             png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)\n            optimize_cmf(data, png_image_size(png_ptr));\n#endif\n\n         if (size > 0)\n            png_write_complete_chunk(png_ptr, png_IDAT, data, size);\n         png_ptr->zstream.avail_out = 0;\n         png_ptr->zstream.next_out = NULL;\n         png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;\n\n         png_ptr->zowner = 0; /* Release the stream */\n         return;\n      }\n\n      else\n      {\n         /* This is an error condition. */\n         png_zstream_error(png_ptr, ret);\n         png_error(png_ptr, png_ptr->zstream.msg);\n      }\n   }\n}\n\n/* Write an IEND chunk */\nvoid /* PRIVATE */\npng_write_IEND(png_structrp png_ptr)\n{\n   png_debug(1, \"in png_write_IEND\");\n\n   png_write_complete_chunk(png_ptr, png_IEND, NULL, 0);\n   png_ptr->mode |= PNG_HAVE_IEND;\n}\n\n#ifdef PNG_WRITE_gAMA_SUPPORTED\n/* Write a gAMA chunk */\nvoid /* PRIVATE */\npng_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma)\n{\n   png_byte buf[4];\n\n   png_debug(1, \"in png_write_gAMA\");\n\n   /* file_gamma is saved in 1/100,000ths */\n   png_save_uint_32(buf, (png_uint_32)file_gamma);\n   png_write_complete_chunk(png_ptr, png_gAMA, buf, 4);\n}\n#endif\n\n#ifdef PNG_WRITE_sRGB_SUPPORTED\n/* Write a sRGB chunk */\nvoid /* PRIVATE */\npng_write_sRGB(png_structrp png_ptr, int srgb_intent)\n{\n   png_byte buf[1];\n\n   png_debug(1, \"in png_write_sRGB\");\n\n   if (srgb_intent >= PNG_sRGB_INTENT_LAST)\n      png_warning(png_ptr,\n          \"Invalid sRGB rendering intent specified\");\n\n   buf[0]=(png_byte)srgb_intent;\n   png_write_complete_chunk(png_ptr, png_sRGB, buf, 1);\n}\n#endif\n\n#ifdef PNG_WRITE_iCCP_SUPPORTED\n/* Write an iCCP chunk */\nvoid /* PRIVATE */\npng_write_iCCP(png_structrp png_ptr, png_const_charp name,\n    png_const_bytep profile)\n{\n   png_uint_32 name_len;\n   png_uint_32 profile_len;\n   png_byte new_name[81]; /* 1 byte for the compression byte */\n   compression_state comp;\n   png_uint_32 temp;\n\n   png_debug(1, \"in png_write_iCCP\");\n\n   /* These are all internal problems: the profile should have been checked\n    * before when it was stored.\n    */\n   if (profile == NULL)\n      png_error(png_ptr, \"No profile for iCCP chunk\"); /* internal error */\n\n   profile_len = png_get_uint_32(profile);\n\n   if (profile_len < 132)\n      png_error(png_ptr, \"ICC profile too short\");\n\n   temp = (png_uint_32) (*(profile+8));\n   if (temp > 3 && (profile_len & 0x03))\n      png_error(png_ptr, \"ICC profile length invalid (not a multiple of 4)\");\n\n   {\n      png_uint_32 embedded_profile_len = png_get_uint_32(profile);\n\n      if (profile_len != embedded_profile_len)\n         png_error(png_ptr, \"Profile length does not match profile\");\n   }\n\n   name_len = png_check_keyword(png_ptr, name, new_name);\n\n   if (name_len == 0)\n      png_error(png_ptr, \"iCCP: invalid keyword\");\n\n   new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE;\n\n   /* Make sure we include the NULL after the name and the compression type */\n   ++name_len;\n\n   png_text_compress_init(&comp, profile, profile_len);\n\n   /* Allow for keyword terminator and compression byte */\n   if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK)\n      png_error(png_ptr, png_ptr->zstream.msg);\n\n   png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len);\n\n   png_write_chunk_data(png_ptr, new_name, name_len);\n\n   png_write_compressed_data_out(png_ptr, &comp);\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_sPLT_SUPPORTED\n/* Write a sPLT chunk */\nvoid /* PRIVATE */\npng_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)\n{\n   png_uint_32 name_len;\n   png_byte new_name[80];\n   png_byte entrybuf[10];\n   size_t entry_size = (spalette->depth == 8 ? 6 : 10);\n   size_t palette_size = entry_size * (size_t)spalette->nentries;\n   png_sPLT_entryp ep;\n#ifndef PNG_POINTER_INDEXING_SUPPORTED\n   int i;\n#endif\n\n   png_debug(1, \"in png_write_sPLT\");\n\n   name_len = png_check_keyword(png_ptr, spalette->name, new_name);\n\n   if (name_len == 0)\n      png_error(png_ptr, \"sPLT: invalid keyword\");\n\n   /* Make sure we include the NULL after the name */\n   png_write_chunk_header(png_ptr, png_sPLT,\n       (png_uint_32)(name_len + 2 + palette_size));\n\n   png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1));\n\n   png_write_chunk_data(png_ptr, &spalette->depth, 1);\n\n   /* Loop through each palette entry, writing appropriately */\n#ifdef PNG_POINTER_INDEXING_SUPPORTED\n   for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)\n   {\n      if (spalette->depth == 8)\n      {\n         entrybuf[0] = (png_byte)ep->red;\n         entrybuf[1] = (png_byte)ep->green;\n         entrybuf[2] = (png_byte)ep->blue;\n         entrybuf[3] = (png_byte)ep->alpha;\n         png_save_uint_16(entrybuf + 4, ep->frequency);\n      }\n\n      else\n      {\n         png_save_uint_16(entrybuf + 0, ep->red);\n         png_save_uint_16(entrybuf + 2, ep->green);\n         png_save_uint_16(entrybuf + 4, ep->blue);\n         png_save_uint_16(entrybuf + 6, ep->alpha);\n         png_save_uint_16(entrybuf + 8, ep->frequency);\n      }\n\n      png_write_chunk_data(png_ptr, entrybuf, entry_size);\n   }\n#else\n   ep=spalette->entries;\n   for (i = 0; i>spalette->nentries; i++)\n   {\n      if (spalette->depth == 8)\n      {\n         entrybuf[0] = (png_byte)ep[i].red;\n         entrybuf[1] = (png_byte)ep[i].green;\n         entrybuf[2] = (png_byte)ep[i].blue;\n         entrybuf[3] = (png_byte)ep[i].alpha;\n         png_save_uint_16(entrybuf + 4, ep[i].frequency);\n      }\n\n      else\n      {\n         png_save_uint_16(entrybuf + 0, ep[i].red);\n         png_save_uint_16(entrybuf + 2, ep[i].green);\n         png_save_uint_16(entrybuf + 4, ep[i].blue);\n         png_save_uint_16(entrybuf + 6, ep[i].alpha);\n         png_save_uint_16(entrybuf + 8, ep[i].frequency);\n      }\n\n      png_write_chunk_data(png_ptr, entrybuf, entry_size);\n   }\n#endif\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_sBIT_SUPPORTED\n/* Write the sBIT chunk */\nvoid /* PRIVATE */\npng_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type)\n{\n   png_byte buf[4];\n   size_t size;\n\n   png_debug(1, \"in png_write_sBIT\");\n\n   /* Make sure we don't depend upon the order of PNG_COLOR_8 */\n   if ((color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      png_byte maxbits;\n\n      maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :\n          png_ptr->usr_bit_depth);\n\n      if (sbit->red == 0 || sbit->red > maxbits ||\n          sbit->green == 0 || sbit->green > maxbits ||\n          sbit->blue == 0 || sbit->blue > maxbits)\n      {\n         png_warning(png_ptr, \"Invalid sBIT depth specified\");\n         return;\n      }\n\n      buf[0] = sbit->red;\n      buf[1] = sbit->green;\n      buf[2] = sbit->blue;\n      size = 3;\n   }\n\n   else\n   {\n      if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)\n      {\n         png_warning(png_ptr, \"Invalid sBIT depth specified\");\n         return;\n      }\n\n      buf[0] = sbit->gray;\n      size = 1;\n   }\n\n   if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)\n   {\n      if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)\n      {\n         png_warning(png_ptr, \"Invalid sBIT depth specified\");\n         return;\n      }\n\n      buf[size++] = sbit->alpha;\n   }\n\n   png_write_complete_chunk(png_ptr, png_sBIT, buf, size);\n}\n#endif\n\n#ifdef PNG_WRITE_cHRM_SUPPORTED\n/* Write the cHRM chunk */\nvoid /* PRIVATE */\npng_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy)\n{\n   png_byte buf[32];\n\n   png_debug(1, \"in png_write_cHRM\");\n\n   /* Each value is saved in 1/100,000ths */\n   png_save_int_32(buf,      xy->whitex);\n   png_save_int_32(buf +  4, xy->whitey);\n\n   png_save_int_32(buf +  8, xy->redx);\n   png_save_int_32(buf + 12, xy->redy);\n\n   png_save_int_32(buf + 16, xy->greenx);\n   png_save_int_32(buf + 20, xy->greeny);\n\n   png_save_int_32(buf + 24, xy->bluex);\n   png_save_int_32(buf + 28, xy->bluey);\n\n   png_write_complete_chunk(png_ptr, png_cHRM, buf, 32);\n}\n#endif\n\n#ifdef PNG_WRITE_tRNS_SUPPORTED\n/* Write the tRNS chunk */\nvoid /* PRIVATE */\npng_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha,\n    png_const_color_16p tran, int num_trans, int color_type)\n{\n   png_byte buf[6];\n\n   png_debug(1, \"in png_write_tRNS\");\n\n   if (color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)\n      {\n         png_app_warning(png_ptr,\n             \"Invalid number of transparent colors specified\");\n         return;\n      }\n\n      /* Write the chunk out as it is */\n      png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,\n          (size_t)num_trans);\n   }\n\n   else if (color_type == PNG_COLOR_TYPE_GRAY)\n   {\n      /* One 16-bit value */\n      if (tran->gray >= (1 << png_ptr->bit_depth))\n      {\n         png_app_warning(png_ptr,\n             \"Ignoring attempt to write tRNS chunk out-of-range for bit_depth\");\n\n         return;\n      }\n\n      png_save_uint_16(buf, tran->gray);\n      png_write_complete_chunk(png_ptr, png_tRNS, buf, 2);\n   }\n\n   else if (color_type == PNG_COLOR_TYPE_RGB)\n   {\n      /* Three 16-bit values */\n      png_save_uint_16(buf, tran->red);\n      png_save_uint_16(buf + 2, tran->green);\n      png_save_uint_16(buf + 4, tran->blue);\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)\n#else\n      if ((buf[0] | buf[2] | buf[4]) != 0)\n#endif\n      {\n         png_app_warning(png_ptr,\n             \"Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8\");\n         return;\n      }\n\n      png_write_complete_chunk(png_ptr, png_tRNS, buf, 6);\n   }\n\n   else\n   {\n      png_app_warning(png_ptr, \"Can't write tRNS with an alpha channel\");\n   }\n}\n#endif\n\n#ifdef PNG_WRITE_bKGD_SUPPORTED\n/* Write the background chunk */\nvoid /* PRIVATE */\npng_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type)\n{\n   png_byte buf[6];\n\n   png_debug(1, \"in png_write_bKGD\");\n\n   if (color_type == PNG_COLOR_TYPE_PALETTE)\n   {\n      if (\n#ifdef PNG_MNG_FEATURES_SUPPORTED\n          (png_ptr->num_palette != 0 ||\n          (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) &&\n#endif\n         back->index >= png_ptr->num_palette)\n      {\n         png_warning(png_ptr, \"Invalid background palette index\");\n         return;\n      }\n\n      buf[0] = back->index;\n      png_write_complete_chunk(png_ptr, png_bKGD, buf, 1);\n   }\n\n   else if ((color_type & PNG_COLOR_MASK_COLOR) != 0)\n   {\n      png_save_uint_16(buf, back->red);\n      png_save_uint_16(buf + 2, back->green);\n      png_save_uint_16(buf + 4, back->blue);\n#ifdef PNG_WRITE_16BIT_SUPPORTED\n      if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0)\n#else\n      if ((buf[0] | buf[2] | buf[4]) != 0)\n#endif\n      {\n         png_warning(png_ptr,\n             \"Ignoring attempt to write 16-bit bKGD chunk \"\n             \"when bit_depth is 8\");\n\n         return;\n      }\n\n      png_write_complete_chunk(png_ptr, png_bKGD, buf, 6);\n   }\n\n   else\n   {\n      if (back->gray >= (1 << png_ptr->bit_depth))\n      {\n         png_warning(png_ptr,\n             \"Ignoring attempt to write bKGD chunk out-of-range for bit_depth\");\n\n         return;\n      }\n\n      png_save_uint_16(buf, back->gray);\n      png_write_complete_chunk(png_ptr, png_bKGD, buf, 2);\n   }\n}\n#endif\n\n#ifdef PNG_WRITE_eXIf_SUPPORTED\n/* Write the Exif data */\nvoid /* PRIVATE */\npng_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif)\n{\n   int i;\n   png_byte buf[1];\n\n   png_debug(1, \"in png_write_eXIf\");\n\n   png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif));\n\n   for (i = 0; i < num_exif; i++)\n   {\n      buf[0] = exif[i];\n      png_write_chunk_data(png_ptr, buf, 1);\n   }\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_hIST_SUPPORTED\n/* Write the histogram */\nvoid /* PRIVATE */\npng_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist)\n{\n   int i;\n   png_byte buf[3];\n\n   png_debug(1, \"in png_write_hIST\");\n\n   if (num_hist > (int)png_ptr->num_palette)\n   {\n      png_debug2(3, \"num_hist = %d, num_palette = %d\", num_hist,\n          png_ptr->num_palette);\n\n      png_warning(png_ptr, \"Invalid number of histogram entries specified\");\n      return;\n   }\n\n   png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));\n\n   for (i = 0; i < num_hist; i++)\n   {\n      png_save_uint_16(buf, hist[i]);\n      png_write_chunk_data(png_ptr, buf, 2);\n   }\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_tEXt_SUPPORTED\n/* Write a tEXt chunk */\nvoid /* PRIVATE */\npng_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,\n    size_t text_len)\n{\n   png_uint_32 key_len;\n   png_byte new_key[80];\n\n   png_debug(1, \"in png_write_tEXt\");\n\n   key_len = png_check_keyword(png_ptr, key, new_key);\n\n   if (key_len == 0)\n      png_error(png_ptr, \"tEXt: invalid keyword\");\n\n   if (text == NULL || *text == '\\0')\n      text_len = 0;\n\n   else\n      text_len = strlen(text);\n\n   if (text_len > PNG_UINT_31_MAX - (key_len+1))\n      png_error(png_ptr, \"tEXt: text too long\");\n\n   /* Make sure we include the 0 after the key */\n   png_write_chunk_header(png_ptr, png_tEXt,\n       (png_uint_32)/*checked above*/(key_len + text_len + 1));\n   /*\n    * We leave it to the application to meet PNG-1.0 requirements on the\n    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of\n    * any non-Latin-1 characters except for NEWLINE.  ISO PNG will forbid them.\n    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.\n    */\n   png_write_chunk_data(png_ptr, new_key, key_len + 1);\n\n   if (text_len != 0)\n      png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len);\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_zTXt_SUPPORTED\n/* Write a compressed text chunk */\nvoid /* PRIVATE */\npng_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text,\n    int compression)\n{\n   png_uint_32 key_len;\n   png_byte new_key[81];\n   compression_state comp;\n\n   png_debug(1, \"in png_write_zTXt\");\n\n   if (compression == PNG_TEXT_COMPRESSION_NONE)\n   {\n      png_write_tEXt(png_ptr, key, text, 0);\n      return;\n   }\n\n   if (compression != PNG_TEXT_COMPRESSION_zTXt)\n      png_error(png_ptr, \"zTXt: invalid compression type\");\n\n   key_len = png_check_keyword(png_ptr, key, new_key);\n\n   if (key_len == 0)\n      png_error(png_ptr, \"zTXt: invalid keyword\");\n\n   /* Add the compression method and 1 for the keyword separator. */\n   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;\n   ++key_len;\n\n   /* Compute the compressed data; do it now for the length */\n   png_text_compress_init(&comp, (png_const_bytep)text,\n       text == NULL ? 0 : strlen(text));\n\n   if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)\n      png_error(png_ptr, png_ptr->zstream.msg);\n\n   /* Write start of chunk */\n   png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len);\n\n   /* Write key */\n   png_write_chunk_data(png_ptr, new_key, key_len);\n\n   /* Write the compressed data */\n   png_write_compressed_data_out(png_ptr, &comp);\n\n   /* Close the chunk */\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_iTXt_SUPPORTED\n/* Write an iTXt chunk */\nvoid /* PRIVATE */\npng_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,\n    png_const_charp lang, png_const_charp lang_key, png_const_charp text)\n{\n   png_uint_32 key_len, prefix_len;\n   size_t lang_len, lang_key_len;\n   png_byte new_key[82];\n   compression_state comp;\n\n   png_debug(1, \"in png_write_iTXt\");\n\n   key_len = png_check_keyword(png_ptr, key, new_key);\n\n   if (key_len == 0)\n      png_error(png_ptr, \"iTXt: invalid keyword\");\n\n   /* Set the compression flag */\n   switch (compression)\n   {\n      case PNG_ITXT_COMPRESSION_NONE:\n      case PNG_TEXT_COMPRESSION_NONE:\n         compression = new_key[++key_len] = 0; /* no compression */\n         break;\n\n      case PNG_TEXT_COMPRESSION_zTXt:\n      case PNG_ITXT_COMPRESSION_zTXt:\n         compression = new_key[++key_len] = 1; /* compressed */\n         break;\n\n      default:\n         png_error(png_ptr, \"iTXt: invalid compression\");\n   }\n\n   new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;\n   ++key_len; /* for the keywod separator */\n\n   /* We leave it to the application to meet PNG-1.0 requirements on the\n    * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of\n    * any non-Latin-1 characters except for NEWLINE.  ISO PNG, however,\n    * specifies that the text is UTF-8 and this really doesn't require any\n    * checking.\n    *\n    * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.\n    *\n    * TODO: validate the language tag correctly (see the spec.)\n    */\n   if (lang == NULL) lang = \"\"; /* empty language is valid */\n   lang_len = strlen(lang)+1;\n   if (lang_key == NULL) lang_key = \"\"; /* may be empty */\n   lang_key_len = strlen(lang_key)+1;\n   if (text == NULL) text = \"\"; /* may be empty */\n\n   prefix_len = key_len;\n   if (lang_len > PNG_UINT_31_MAX-prefix_len)\n      prefix_len = PNG_UINT_31_MAX;\n   else\n      prefix_len = (png_uint_32)(prefix_len + lang_len);\n\n   if (lang_key_len > PNG_UINT_31_MAX-prefix_len)\n      prefix_len = PNG_UINT_31_MAX;\n   else\n      prefix_len = (png_uint_32)(prefix_len + lang_key_len);\n\n   png_text_compress_init(&comp, (png_const_bytep)text, strlen(text));\n\n   if (compression != 0)\n   {\n      if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK)\n         png_error(png_ptr, png_ptr->zstream.msg);\n   }\n\n   else\n   {\n      if (comp.input_len > PNG_UINT_31_MAX-prefix_len)\n         png_error(png_ptr, \"iTXt: uncompressed text too long\");\n\n      /* So the string will fit in a chunk: */\n      comp.output_len = (png_uint_32)/*SAFE*/comp.input_len;\n   }\n\n   png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len);\n\n   png_write_chunk_data(png_ptr, new_key, key_len);\n\n   png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len);\n\n   png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len);\n\n   if (compression != 0)\n      png_write_compressed_data_out(png_ptr, &comp);\n\n   else\n      png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len);\n\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_oFFs_SUPPORTED\n/* Write the oFFs chunk */\nvoid /* PRIVATE */\npng_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset,\n    int unit_type)\n{\n   png_byte buf[9];\n\n   png_debug(1, \"in png_write_oFFs\");\n\n   if (unit_type >= PNG_OFFSET_LAST)\n      png_warning(png_ptr, \"Unrecognized unit type for oFFs chunk\");\n\n   png_save_int_32(buf, x_offset);\n   png_save_int_32(buf + 4, y_offset);\n   buf[8] = (png_byte)unit_type;\n\n   png_write_complete_chunk(png_ptr, png_oFFs, buf, 9);\n}\n#endif\n#ifdef PNG_WRITE_pCAL_SUPPORTED\n/* Write the pCAL chunk (described in the PNG extensions document) */\nvoid /* PRIVATE */\npng_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0,\n    png_int_32 X1, int type, int nparams, png_const_charp units,\n    png_charpp params)\n{\n   png_uint_32 purpose_len;\n   size_t units_len, total_len;\n   png_size_tp params_len;\n   png_byte buf[10];\n   png_byte new_purpose[80];\n   int i;\n\n   png_debug1(1, \"in png_write_pCAL (%d parameters)\", nparams);\n\n   if (type >= PNG_EQUATION_LAST)\n      png_error(png_ptr, \"Unrecognized equation type for pCAL chunk\");\n\n   purpose_len = png_check_keyword(png_ptr, purpose, new_purpose);\n\n   if (purpose_len == 0)\n      png_error(png_ptr, \"pCAL: invalid keyword\");\n\n   ++purpose_len; /* terminator */\n\n   png_debug1(3, \"pCAL purpose length = %d\", (int)purpose_len);\n   units_len = strlen(units) + (nparams == 0 ? 0 : 1);\n   png_debug1(3, \"pCAL units length = %d\", (int)units_len);\n   total_len = purpose_len + units_len + 10;\n\n   params_len = (png_size_tp)png_malloc(png_ptr,\n       (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t))));\n\n   /* Find the length of each parameter, making sure we don't count the\n    * null terminator for the last parameter.\n    */\n   for (i = 0; i < nparams; i++)\n   {\n      params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1);\n      png_debug2(3, \"pCAL parameter %d length = %lu\", i,\n          (unsigned long)params_len[i]);\n      total_len += params_len[i];\n   }\n\n   png_debug1(3, \"pCAL total length = %d\", (int)total_len);\n   png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);\n   png_write_chunk_data(png_ptr, new_purpose, purpose_len);\n   png_save_int_32(buf, X0);\n   png_save_int_32(buf + 4, X1);\n   buf[8] = (png_byte)type;\n   buf[9] = (png_byte)nparams;\n   png_write_chunk_data(png_ptr, buf, 10);\n   png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len);\n\n   for (i = 0; i < nparams; i++)\n   {\n      png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);\n   }\n\n   png_free(png_ptr, params_len);\n   png_write_chunk_end(png_ptr);\n}\n#endif\n\n#ifdef PNG_WRITE_sCAL_SUPPORTED\n/* Write the sCAL chunk */\nvoid /* PRIVATE */\npng_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width,\n    png_const_charp height)\n{\n   png_byte buf[64];\n   size_t wlen, hlen, total_len;\n\n   png_debug(1, \"in png_write_sCAL_s\");\n\n   wlen = strlen(width);\n   hlen = strlen(height);\n   total_len = wlen + hlen + 2;\n\n   if (total_len > 64)\n   {\n      png_warning(png_ptr, \"Can't write sCAL (buffer too small)\");\n      return;\n   }\n\n   buf[0] = (png_byte)unit;\n   memcpy(buf + 1, width, wlen + 1);      /* Append the '\\0' here */\n   memcpy(buf + wlen + 2, height, hlen);  /* Do NOT append the '\\0' here */\n\n   png_debug1(3, \"sCAL total length = %u\", (unsigned int)total_len);\n   png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len);\n}\n#endif\n\n#ifdef PNG_WRITE_pHYs_SUPPORTED\n/* Write the pHYs chunk */\nvoid /* PRIVATE */\npng_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit,\n    png_uint_32 y_pixels_per_unit,\n    int unit_type)\n{\n   png_byte buf[9];\n\n   png_debug(1, \"in png_write_pHYs\");\n\n   if (unit_type >= PNG_RESOLUTION_LAST)\n      png_warning(png_ptr, \"Unrecognized unit type for pHYs chunk\");\n\n   png_save_uint_32(buf, x_pixels_per_unit);\n   png_save_uint_32(buf + 4, y_pixels_per_unit);\n   buf[8] = (png_byte)unit_type;\n\n   png_write_complete_chunk(png_ptr, png_pHYs, buf, 9);\n}\n#endif\n\n#ifdef PNG_WRITE_tIME_SUPPORTED\n/* Write the tIME chunk.  Use either png_convert_from_struct_tm()\n * or png_convert_from_time_t(), or fill in the structure yourself.\n */\nvoid /* PRIVATE */\npng_write_tIME(png_structrp png_ptr, png_const_timep mod_time)\n{\n   png_byte buf[7];\n\n   png_debug(1, \"in png_write_tIME\");\n\n   if (mod_time->month  > 12 || mod_time->month  < 1 ||\n       mod_time->day    > 31 || mod_time->day    < 1 ||\n       mod_time->hour   > 23 || mod_time->second > 60)\n   {\n      png_warning(png_ptr, \"Invalid time specified for tIME chunk\");\n      return;\n   }\n\n   png_save_uint_16(buf, mod_time->year);\n   buf[2] = mod_time->month;\n   buf[3] = mod_time->day;\n   buf[4] = mod_time->hour;\n   buf[5] = mod_time->minute;\n   buf[6] = mod_time->second;\n\n   png_write_complete_chunk(png_ptr, png_tIME, buf, 7);\n}\n#endif\n\n/* Initializes the row writing capability of libpng */\nvoid /* PRIVATE */\npng_write_start_row(png_structrp png_ptr)\n{\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   /* Start of interlace block in the y direction */\n   static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};\n\n   /* Offset to next interlace block in the y direction */\n   static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};\n#endif\n\n   png_alloc_size_t buf_size;\n   int usr_pixel_depth;\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n   png_byte filters;\n#endif\n\n   png_debug(1, \"in png_write_start_row\");\n\n   usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;\n   buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1;\n\n   /* 1.5.6: added to allow checking in the row write code. */\n   png_ptr->transformed_pixel_depth = png_ptr->pixel_depth;\n   png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;\n\n   /* Set up row buffer */\n   png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));\n\n   png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n   filters = png_ptr->do_filter;\n\n   if (png_ptr->height == 1)\n      filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);\n\n   if (png_ptr->width == 1)\n      filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);\n\n   if (filters == 0)\n      filters = PNG_FILTER_NONE;\n\n   png_ptr->do_filter = filters;\n\n   if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG |\n       PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL)\n   {\n      int num_filters = 0;\n\n      png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));\n\n      if (filters & PNG_FILTER_SUB)\n         num_filters++;\n\n      if (filters & PNG_FILTER_UP)\n         num_filters++;\n\n      if (filters & PNG_FILTER_AVG)\n         num_filters++;\n\n      if (filters & PNG_FILTER_PAETH)\n         num_filters++;\n\n      if (num_filters > 1)\n         png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,\n             buf_size));\n   }\n\n   /* We only need to keep the previous row if we are using one of the following\n    * filters.\n    */\n   if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)\n      png_ptr->prev_row = png_voidcast(png_bytep,\n          png_calloc(png_ptr, buf_size));\n#endif /* WRITE_FILTER */\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* If interlaced, we need to set up width and height of pass */\n   if (png_ptr->interlaced != 0)\n   {\n      if ((png_ptr->transformations & PNG_INTERLACE) == 0)\n      {\n         png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -\n             png_pass_ystart[0]) / png_pass_yinc[0];\n\n         png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -\n             png_pass_start[0]) / png_pass_inc[0];\n      }\n\n      else\n      {\n         png_ptr->num_rows = png_ptr->height;\n         png_ptr->usr_width = png_ptr->width;\n      }\n   }\n\n   else\n#endif\n   {\n      png_ptr->num_rows = png_ptr->height;\n      png_ptr->usr_width = png_ptr->width;\n   }\n}\n\n/* Internal use only.  Called when finished processing a row of data. */\nvoid /* PRIVATE */\npng_write_finish_row(png_structrp png_ptr)\n{\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   /* Start of interlace block in the y direction */\n   static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};\n\n   /* Offset to next interlace block in the y direction */\n   static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};\n#endif\n\n   png_debug(1, \"in png_write_finish_row\");\n\n   /* Next row */\n   png_ptr->row_number++;\n\n   /* See if we are done */\n   if (png_ptr->row_number < png_ptr->num_rows)\n      return;\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n   /* If interlaced, go to next pass */\n   if (png_ptr->interlaced != 0)\n   {\n      png_ptr->row_number = 0;\n      if ((png_ptr->transformations & PNG_INTERLACE) != 0)\n      {\n         png_ptr->pass++;\n      }\n\n      else\n      {\n         /* Loop until we find a non-zero width or height pass */\n         do\n         {\n            png_ptr->pass++;\n\n            if (png_ptr->pass >= 7)\n               break;\n\n            png_ptr->usr_width = (png_ptr->width +\n                png_pass_inc[png_ptr->pass] - 1 -\n                png_pass_start[png_ptr->pass]) /\n                png_pass_inc[png_ptr->pass];\n\n            png_ptr->num_rows = (png_ptr->height +\n                png_pass_yinc[png_ptr->pass] - 1 -\n                png_pass_ystart[png_ptr->pass]) /\n                png_pass_yinc[png_ptr->pass];\n\n            if ((png_ptr->transformations & PNG_INTERLACE) != 0)\n               break;\n\n         } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);\n\n      }\n\n      /* Reset the row above the image for the next pass */\n      if (png_ptr->pass < 7)\n      {\n         if (png_ptr->prev_row != NULL)\n            memset(png_ptr->prev_row, 0,\n                PNG_ROWBYTES(png_ptr->usr_channels *\n                png_ptr->usr_bit_depth, png_ptr->width) + 1);\n\n         return;\n      }\n   }\n#endif\n\n   /* If we get here, we've just written the last row, so we need\n      to flush the compressor */\n   png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH);\n}\n\n#ifdef PNG_WRITE_INTERLACING_SUPPORTED\n/* Pick out the correct pixels for the interlace pass.\n * The basic idea here is to go through the row with a source\n * pointer and a destination pointer (sp and dp), and copy the\n * correct pixels for the pass.  As the row gets compacted,\n * sp will always be >= dp, so we should never overwrite anything.\n * See the default: case for the easiest code to understand.\n */\nvoid /* PRIVATE */\npng_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)\n{\n   /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */\n\n   /* Start of interlace block */\n   static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};\n\n   /* Offset to next interlace block */\n   static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};\n\n   png_debug(1, \"in png_do_write_interlace\");\n\n   /* We don't have to do anything on the last pass (6) */\n   if (pass < 6)\n   {\n      /* Each pixel depth is handled separately */\n      switch (row_info->pixel_depth)\n      {\n         case 1:\n         {\n            png_bytep sp;\n            png_bytep dp;\n            unsigned int shift;\n            int d;\n            int value;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            dp = row;\n            d = 0;\n            shift = 7;\n\n            for (i = png_pass_start[pass]; i < row_width;\n               i += png_pass_inc[pass])\n            {\n               sp = row + (size_t)(i >> 3);\n               value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;\n               d |= (value << shift);\n\n               if (shift == 0)\n               {\n                  shift = 7;\n                  *dp++ = (png_byte)d;\n                  d = 0;\n               }\n\n               else\n                  shift--;\n\n            }\n            if (shift != 7)\n               *dp = (png_byte)d;\n\n            break;\n         }\n\n         case 2:\n         {\n            png_bytep sp;\n            png_bytep dp;\n            unsigned int shift;\n            int d;\n            int value;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            dp = row;\n            shift = 6;\n            d = 0;\n\n            for (i = png_pass_start[pass]; i < row_width;\n               i += png_pass_inc[pass])\n            {\n               sp = row + (size_t)(i >> 2);\n               value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;\n               d |= (value << shift);\n\n               if (shift == 0)\n               {\n                  shift = 6;\n                  *dp++ = (png_byte)d;\n                  d = 0;\n               }\n\n               else\n                  shift -= 2;\n            }\n            if (shift != 6)\n               *dp = (png_byte)d;\n\n            break;\n         }\n\n         case 4:\n         {\n            png_bytep sp;\n            png_bytep dp;\n            unsigned int shift;\n            int d;\n            int value;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n\n            dp = row;\n            shift = 4;\n            d = 0;\n            for (i = png_pass_start[pass]; i < row_width;\n                i += png_pass_inc[pass])\n            {\n               sp = row + (size_t)(i >> 1);\n               value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;\n               d |= (value << shift);\n\n               if (shift == 0)\n               {\n                  shift = 4;\n                  *dp++ = (png_byte)d;\n                  d = 0;\n               }\n\n               else\n                  shift -= 4;\n            }\n            if (shift != 4)\n               *dp = (png_byte)d;\n\n            break;\n         }\n\n         default:\n         {\n            png_bytep sp;\n            png_bytep dp;\n            png_uint_32 i;\n            png_uint_32 row_width = row_info->width;\n            size_t pixel_bytes;\n\n            /* Start at the beginning */\n            dp = row;\n\n            /* Find out how many bytes each pixel takes up */\n            pixel_bytes = (row_info->pixel_depth >> 3);\n\n            /* Loop through the row, only looking at the pixels that matter */\n            for (i = png_pass_start[pass]; i < row_width;\n               i += png_pass_inc[pass])\n            {\n               /* Find out where the original pixel is */\n               sp = row + (size_t)i * pixel_bytes;\n\n               /* Move the pixel */\n               if (dp != sp)\n                  memcpy(dp, sp, pixel_bytes);\n\n               /* Next pixel */\n               dp += pixel_bytes;\n            }\n            break;\n         }\n      }\n      /* Set new row width */\n      row_info->width = (row_info->width +\n          png_pass_inc[pass] - 1 -\n          png_pass_start[pass]) /\n          png_pass_inc[pass];\n\n      row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,\n          row_info->width);\n   }\n}\n#endif\n\n\n/* This filters the row, chooses which filter to use, if it has not already\n * been specified by the application, and then writes the row out with the\n * chosen filter.\n */\nstatic void /* PRIVATE */\npng_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,\n    size_t row_bytes);\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\nstatic size_t /* PRIVATE */\npng_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes, size_t lmins)\n{\n   png_bytep rp, dp, lp;\n   size_t i;\n   size_t sum = 0;\n   unsigned int v;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;\n        i++, rp++, dp++)\n   {\n      v = *dp = *rp;\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n   }\n\n   for (lp = png_ptr->row_buf + 1; i < row_bytes;\n      i++, rp++, lp++, dp++)\n   {\n      v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n\n      if (sum > lmins)  /* We are already worse, don't continue. */\n        break;\n   }\n\n   return (sum);\n}\n\nstatic void /* PRIVATE */\npng_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes)\n{\n   png_bytep rp, dp, lp;\n   size_t i;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;\n        i++, rp++, dp++)\n   {\n      *dp = *rp;\n   }\n\n   for (lp = png_ptr->row_buf + 1; i < row_bytes;\n      i++, rp++, lp++, dp++)\n   {\n      *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);\n   }\n}\n\nstatic size_t /* PRIVATE */\npng_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins)\n{\n   png_bytep rp, dp, pp;\n   size_t i;\n   size_t sum = 0;\n   unsigned int v;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < row_bytes;\n       i++, rp++, pp++, dp++)\n   {\n      v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n\n      if (sum > lmins)  /* We are already worse, don't continue. */\n        break;\n   }\n\n   return (sum);\n}\nstatic void /* PRIVATE */\npng_setup_up_row_only(png_structrp png_ptr, size_t row_bytes)\n{\n   png_bytep rp, dp, pp;\n   size_t i;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < row_bytes;\n       i++, rp++, pp++, dp++)\n   {\n      *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);\n   }\n}\n\nstatic size_t /* PRIVATE */\npng_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes, size_t lmins)\n{\n   png_bytep rp, dp, pp, lp;\n   png_uint_32 i;\n   size_t sum = 0;\n   unsigned int v;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < bpp; i++)\n   {\n      v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);\n\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n   }\n\n   for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)\n   {\n      v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))\n          & 0xff);\n\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n\n      if (sum > lmins)  /* We are already worse, don't continue. */\n        break;\n   }\n\n   return (sum);\n}\nstatic void /* PRIVATE */\npng_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes)\n{\n   png_bytep rp, dp, pp, lp;\n   png_uint_32 i;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < bpp; i++)\n   {\n      *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);\n   }\n\n   for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)\n   {\n      *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))\n          & 0xff);\n   }\n}\n\nstatic size_t /* PRIVATE */\npng_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes, size_t lmins)\n{\n   png_bytep rp, dp, pp, cp, lp;\n   size_t i;\n   size_t sum = 0;\n   unsigned int v;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < bpp; i++)\n   {\n      v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);\n\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n   }\n\n   for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;\n        i++)\n   {\n      int a, b, c, pa, pb, pc, p;\n\n      b = *pp++;\n      c = *cp++;\n      a = *lp++;\n\n      p = b - c;\n      pc = a - c;\n\n#ifdef PNG_USE_ABS\n      pa = abs(p);\n      pb = abs(pc);\n      pc = abs(p + pc);\n#else\n      pa = p < 0 ? -p : p;\n      pb = pc < 0 ? -pc : pc;\n      pc = (p + pc) < 0 ? -(p + pc) : p + pc;\n#endif\n\n      p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;\n\n      v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);\n\n#ifdef PNG_USE_ABS\n      sum += 128 - abs((int)v - 128);\n#else\n      sum += (v < 128) ? v : 256 - v;\n#endif\n\n      if (sum > lmins)  /* We are already worse, don't continue. */\n        break;\n   }\n\n   return (sum);\n}\nstatic void /* PRIVATE */\npng_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp,\n    size_t row_bytes)\n{\n   png_bytep rp, dp, pp, cp, lp;\n   size_t i;\n\n   png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;\n\n   for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,\n       pp = png_ptr->prev_row + 1; i < bpp; i++)\n   {\n      *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);\n   }\n\n   for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;\n        i++)\n   {\n      int a, b, c, pa, pb, pc, p;\n\n      b = *pp++;\n      c = *cp++;\n      a = *lp++;\n\n      p = b - c;\n      pc = a - c;\n\n#ifdef PNG_USE_ABS\n      pa = abs(p);\n      pb = abs(pc);\n      pc = abs(p + pc);\n#else\n      pa = p < 0 ? -p : p;\n      pb = pc < 0 ? -pc : pc;\n      pc = (p + pc) < 0 ? -(p + pc) : p + pc;\n#endif\n\n      p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;\n\n      *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);\n   }\n}\n#endif /* WRITE_FILTER */\n\nvoid /* PRIVATE */\npng_write_find_filter(png_structrp png_ptr, png_row_infop row_info)\n{\n#ifndef PNG_WRITE_FILTER_SUPPORTED\n   png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1);\n#else\n   unsigned int filter_to_do = png_ptr->do_filter;\n   png_bytep row_buf;\n   png_bytep best_row;\n   png_uint_32 bpp;\n   size_t mins;\n   size_t row_bytes = row_info->rowbytes;\n\n   png_debug(1, \"in png_write_find_filter\");\n\n   /* Find out how many bytes offset each pixel is */\n   bpp = (row_info->pixel_depth + 7) >> 3;\n\n   row_buf = png_ptr->row_buf;\n   mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the\n                               running sum */;\n\n   /* The prediction method we use is to find which method provides the\n    * smallest value when summing the absolute values of the distances\n    * from zero, using anything >= 128 as negative numbers.  This is known\n    * as the \"minimum sum of absolute differences\" heuristic.  Other\n    * heuristics are the \"weighted minimum sum of absolute differences\"\n    * (experimental and can in theory improve compression), and the \"zlib\n    * predictive\" method (not implemented yet), which does test compressions\n    * of lines using different filter methods, and then chooses the\n    * (series of) filter(s) that give minimum compressed data size (VERY\n    * computationally expensive).\n    *\n    * GRR 980525:  consider also\n    *\n    *   (1) minimum sum of absolute differences from running average (i.e.,\n    *       keep running sum of non-absolute differences & count of bytes)\n    *       [track dispersion, too?  restart average if dispersion too large?]\n    *\n    *  (1b) minimum sum of absolute differences from sliding average, probably\n    *       with window size <= deflate window (usually 32K)\n    *\n    *   (2) minimum sum of squared differences from zero or running average\n    *       (i.e., ~ root-mean-square approach)\n    */\n\n\n   /* We don't need to test the 'no filter' case if this is the only filter\n    * that has been chosen, as it doesn't actually do anything to the data.\n    */\n   best_row = png_ptr->row_buf;\n\n   if (PNG_SIZE_MAX/128 <= row_bytes)\n   {\n      /* Overflow can occur in the calculation, just select the lowest set\n       * filter.\n       */\n      filter_to_do &= 0U-filter_to_do;\n   }\n   else if ((filter_to_do & PNG_FILTER_NONE) != 0 &&\n         filter_to_do != PNG_FILTER_NONE)\n   {\n      /* Overflow not possible and multiple filters in the list, including the\n       * 'none' filter.\n       */\n      png_bytep rp;\n      size_t sum = 0;\n      size_t i;\n      unsigned int v;\n\n      {\n         for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)\n         {\n            v = *rp;\n#ifdef PNG_USE_ABS\n            sum += 128 - abs((int)v - 128);\n#else\n            sum += (v < 128) ? v : 256 - v;\n#endif\n         }\n      }\n\n      mins = sum;\n   }\n\n   /* Sub filter */\n   if (filter_to_do == PNG_FILTER_SUB)\n   /* It's the only filter so no testing is needed */\n   {\n      png_setup_sub_row_only(png_ptr, bpp, row_bytes);\n      best_row = png_ptr->try_row;\n   }\n\n   else if ((filter_to_do & PNG_FILTER_SUB) != 0)\n   {\n      size_t sum;\n      size_t lmins = mins;\n\n      sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);\n\n      if (sum < mins)\n      {\n         mins = sum;\n         best_row = png_ptr->try_row;\n         if (png_ptr->tst_row != NULL)\n         {\n            png_ptr->try_row = png_ptr->tst_row;\n            png_ptr->tst_row = best_row;\n         }\n      }\n   }\n\n   /* Up filter */\n   if (filter_to_do == PNG_FILTER_UP)\n   {\n      png_setup_up_row_only(png_ptr, row_bytes);\n      best_row = png_ptr->try_row;\n   }\n\n   else if ((filter_to_do & PNG_FILTER_UP) != 0)\n   {\n      size_t sum;\n      size_t lmins = mins;\n\n      sum = png_setup_up_row(png_ptr, row_bytes, lmins);\n\n      if (sum < mins)\n      {\n         mins = sum;\n         best_row = png_ptr->try_row;\n         if (png_ptr->tst_row != NULL)\n         {\n            png_ptr->try_row = png_ptr->tst_row;\n            png_ptr->tst_row = best_row;\n         }\n      }\n   }\n\n   /* Avg filter */\n   if (filter_to_do == PNG_FILTER_AVG)\n   {\n      png_setup_avg_row_only(png_ptr, bpp, row_bytes);\n      best_row = png_ptr->try_row;\n   }\n\n   else if ((filter_to_do & PNG_FILTER_AVG) != 0)\n   {\n      size_t sum;\n      size_t lmins = mins;\n\n      sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);\n\n      if (sum < mins)\n      {\n         mins = sum;\n         best_row = png_ptr->try_row;\n         if (png_ptr->tst_row != NULL)\n         {\n            png_ptr->try_row = png_ptr->tst_row;\n            png_ptr->tst_row = best_row;\n         }\n      }\n   }\n\n   /* Paeth filter */\n   if (filter_to_do == PNG_FILTER_PAETH)\n   {\n      png_setup_paeth_row_only(png_ptr, bpp, row_bytes);\n      best_row = png_ptr->try_row;\n   }\n\n   else if ((filter_to_do & PNG_FILTER_PAETH) != 0)\n   {\n      size_t sum;\n      size_t lmins = mins;\n\n      sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);\n\n      if (sum < mins)\n      {\n         best_row = png_ptr->try_row;\n         if (png_ptr->tst_row != NULL)\n         {\n            png_ptr->try_row = png_ptr->tst_row;\n            png_ptr->tst_row = best_row;\n         }\n      }\n   }\n\n   /* Do the actual writing of the filtered row data from the chosen filter. */\n   png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);\n\n#endif /* WRITE_FILTER */\n}\n\n\n/* Do the actual writing of a previously filtered row. */\nstatic void\npng_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,\n    size_t full_row_length/*includes filter byte*/)\n{\n   png_debug(1, \"in png_write_filtered_row\");\n\n   png_debug1(2, \"filter = %d\", filtered_row[0]);\n\n   png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH);\n\n#ifdef PNG_WRITE_FILTER_SUPPORTED\n   /* Swap the current and previous rows */\n   if (png_ptr->prev_row != NULL)\n   {\n      png_bytep tptr;\n\n      tptr = png_ptr->prev_row;\n      png_ptr->prev_row = png_ptr->row_buf;\n      png_ptr->row_buf = tptr;\n   }\n#endif /* WRITE_FILTER */\n\n   /* Finish row - updates counters and flushes zlib if last row */\n   png_write_finish_row(png_ptr);\n\n#ifdef PNG_WRITE_FLUSH_SUPPORTED\n   png_ptr->flush_rows++;\n\n   if (png_ptr->flush_dist > 0 &&\n       png_ptr->flush_rows >= png_ptr->flush_dist)\n   {\n      png_write_flush(png_ptr);\n   }\n#endif /* WRITE_FLUSH */\n}\n#endif /* WRITE */\n"
  },
  {
    "path": "dlib/external/pybind11/CMakeLists.txt",
    "content": "# CMakeLists.txt -- Build system for the pybind11 modules\n#\n# Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>\n#\n# All rights reserved. Use of this source code is governed by a\n# BSD-style license that can be found in the LICENSE file.\n\n# Propagate this policy (FindPythonInterp removal) so it can be detected later\nif(NOT CMAKE_VERSION VERSION_LESS \"3.27\")\n  cmake_policy(GET CMP0148 _pybind11_cmp0148)\nendif()\n\ncmake_minimum_required(VERSION 3.5)\n\n# The `cmake_minimum_required(VERSION 3.5...3.27)` syntax does not work with\n# some versions of VS that have a patched CMake 3.11. This forces us to emulate\n# the behavior using the following workaround:\nif(${CMAKE_VERSION} VERSION_LESS 3.27)\n  cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})\nelse()\n  cmake_policy(VERSION 3.27)\nendif()\n\nif(_pybind11_cmp0148)\n  cmake_policy(SET CMP0148 ${_pybind11_cmp0148})\n  unset(_pybind11_cmp0148)\nendif()\n\n# Avoid infinite recursion if tests include this as a subdirectory\nif(DEFINED PYBIND11_MASTER_PROJECT)\n  return()\nendif()\n\n# Extract project version from source\nfile(STRINGS \"${CMAKE_CURRENT_SOURCE_DIR}/include/pybind11/detail/common.h\"\n     pybind11_version_defines REGEX \"#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) \")\n\nforeach(ver ${pybind11_version_defines})\n  if(ver MATCHES [[#define PYBIND11_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$]])\n    set(PYBIND11_VERSION_${CMAKE_MATCH_1} \"${CMAKE_MATCH_2}\")\n  endif()\nendforeach()\n\nif(PYBIND11_VERSION_PATCH MATCHES [[\\.([a-zA-Z0-9]+)$]])\n  set(pybind11_VERSION_TYPE \"${CMAKE_MATCH_1}\")\nendif()\nstring(REGEX MATCH \"^[0-9]+\" PYBIND11_VERSION_PATCH \"${PYBIND11_VERSION_PATCH}\")\n\nproject(\n  pybind11\n  LANGUAGES CXX\n  VERSION \"${PYBIND11_VERSION_MAJOR}.${PYBIND11_VERSION_MINOR}.${PYBIND11_VERSION_PATCH}\")\n\n# Standard includes\ninclude(GNUInstallDirs)\ninclude(CMakePackageConfigHelpers)\ninclude(CMakeDependentOption)\n\nif(NOT pybind11_FIND_QUIETLY)\n  message(STATUS \"pybind11 v${pybind11_VERSION} ${pybind11_VERSION_TYPE}\")\nendif()\n\n# Check if pybind11 is being used directly or via add_subdirectory\nif(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)\n  ### Warn if not an out-of-source builds\n  if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)\n    set(lines\n        \"You are building in-place. If that is not what you intended to \"\n        \"do, you can clean the source directory with:\\n\"\n        \"rm -r CMakeCache.txt CMakeFiles/ cmake_uninstall.cmake pybind11Config.cmake \"\n        \"pybind11ConfigVersion.cmake tests/CMakeFiles/\\n\")\n    message(AUTHOR_WARNING ${lines})\n  endif()\n\n  set(PYBIND11_MASTER_PROJECT ON)\n\n  if(OSX AND CMAKE_VERSION VERSION_LESS 3.7)\n    # Bug in macOS CMake < 3.7 is unable to download catch\n    message(WARNING \"CMAKE 3.7+ needed on macOS to download catch, and newer HIGHLY recommended\")\n  elseif(WINDOWS AND CMAKE_VERSION VERSION_LESS 3.8)\n    # Only tested with 3.8+ in CI.\n    message(WARNING \"CMAKE 3.8+ tested on Windows, previous versions untested\")\n  endif()\n\n  message(STATUS \"CMake ${CMAKE_VERSION}\")\n\n  if(CMAKE_CXX_STANDARD)\n    set(CMAKE_CXX_EXTENSIONS OFF)\n    set(CMAKE_CXX_STANDARD_REQUIRED ON)\n  endif()\n\n  set(pybind11_system \"\")\n\n  set_property(GLOBAL PROPERTY USE_FOLDERS ON)\n  if(CMAKE_VERSION VERSION_LESS \"3.18\")\n    set(_pybind11_findpython_default OFF)\n  else()\n    set(_pybind11_findpython_default ON)\n  endif()\nelse()\n  set(PYBIND11_MASTER_PROJECT OFF)\n  set(pybind11_system SYSTEM)\n  set(_pybind11_findpython_default OFF)\nendif()\n\n# Options\noption(PYBIND11_INSTALL \"Install pybind11 header files?\" ${PYBIND11_MASTER_PROJECT})\noption(PYBIND11_TEST \"Build pybind11 test suite?\" ${PYBIND11_MASTER_PROJECT})\noption(PYBIND11_NOPYTHON \"Disable search for Python\" OFF)\noption(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION\n       \"To enforce that a handle_type_name<> specialization exists\" OFF)\noption(PYBIND11_SIMPLE_GIL_MANAGEMENT\n       \"Use simpler GIL management logic that does not support disassociation\" OFF)\noption(PYBIND11_NUMPY_1_ONLY\n       \"Disable NumPy 2 support to avoid changes to previous pybind11 versions.\" OFF)\nset(PYBIND11_INTERNALS_VERSION\n    \"\"\n    CACHE STRING \"Override the ABI version, may be used to enable the unstable ABI.\")\n\nif(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)\n  add_compile_definitions(PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION)\nendif()\nif(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n  add_compile_definitions(PYBIND11_SIMPLE_GIL_MANAGEMENT)\nendif()\nif(PYBIND11_NUMPY_1_ONLY)\n  add_compile_definitions(PYBIND11_NUMPY_1_ONLY)\nendif()\n\ncmake_dependent_option(\n  USE_PYTHON_INCLUDE_DIR\n  \"Install pybind11 headers in Python include directory instead of default installation prefix\"\n  OFF \"PYBIND11_INSTALL\" OFF)\n\ncmake_dependent_option(PYBIND11_FINDPYTHON \"Force new FindPython\" ${_pybind11_findpython_default}\n                       \"NOT CMAKE_VERSION VERSION_LESS 3.12\" OFF)\n\n# Allow PYTHON_EXECUTABLE if in FINDPYTHON mode and building pybind11's tests\n# (makes transition easier while we support both modes).\nif(PYBIND11_MASTER_PROJECT\n   AND PYBIND11_FINDPYTHON\n   AND DEFINED PYTHON_EXECUTABLE\n   AND NOT DEFINED Python_EXECUTABLE)\n  set(Python_EXECUTABLE \"${PYTHON_EXECUTABLE}\")\nendif()\n\n# NB: when adding a header don't forget to also add it to setup.py\nset(PYBIND11_HEADERS\n    include/pybind11/detail/class.h\n    include/pybind11/detail/common.h\n    include/pybind11/detail/descr.h\n    include/pybind11/detail/init.h\n    include/pybind11/detail/internals.h\n    include/pybind11/detail/type_caster_base.h\n    include/pybind11/detail/typeid.h\n    include/pybind11/attr.h\n    include/pybind11/buffer_info.h\n    include/pybind11/cast.h\n    include/pybind11/chrono.h\n    include/pybind11/common.h\n    include/pybind11/complex.h\n    include/pybind11/options.h\n    include/pybind11/eigen.h\n    include/pybind11/eigen/common.h\n    include/pybind11/eigen/matrix.h\n    include/pybind11/eigen/tensor.h\n    include/pybind11/embed.h\n    include/pybind11/eval.h\n    include/pybind11/gil.h\n    include/pybind11/gil_safe_call_once.h\n    include/pybind11/iostream.h\n    include/pybind11/functional.h\n    include/pybind11/numpy.h\n    include/pybind11/operators.h\n    include/pybind11/pybind11.h\n    include/pybind11/pytypes.h\n    include/pybind11/stl.h\n    include/pybind11/stl_bind.h\n    include/pybind11/stl/filesystem.h\n    include/pybind11/type_caster_pyobject_ptr.h\n    include/pybind11/typing.h)\n\n# Compare with grep and warn if mismatched\nif(PYBIND11_MASTER_PROJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)\n  file(\n    GLOB_RECURSE _pybind11_header_check\n    LIST_DIRECTORIES false\n    RELATIVE \"${CMAKE_CURRENT_SOURCE_DIR}\"\n    CONFIGURE_DEPENDS \"include/pybind11/*.h\")\n  set(_pybind11_here_only ${PYBIND11_HEADERS})\n  set(_pybind11_disk_only ${_pybind11_header_check})\n  list(REMOVE_ITEM _pybind11_here_only ${_pybind11_header_check})\n  list(REMOVE_ITEM _pybind11_disk_only ${PYBIND11_HEADERS})\n  if(_pybind11_here_only)\n    message(AUTHOR_WARNING \"PYBIND11_HEADERS has extra files:\" ${_pybind11_here_only})\n  endif()\n  if(_pybind11_disk_only)\n    message(AUTHOR_WARNING \"PYBIND11_HEADERS is missing files:\" ${_pybind11_disk_only})\n  endif()\nendif()\n\n# CMake 3.12 added list(TRANSFORM <list> PREPEND\n# But we can't use it yet\nstring(REPLACE \"include/\" \"${CMAKE_CURRENT_SOURCE_DIR}/include/\" PYBIND11_HEADERS\n               \"${PYBIND11_HEADERS}\")\n\n# Cache variable so this can be used in parent projects\nset(pybind11_INCLUDE_DIR\n    \"${CMAKE_CURRENT_LIST_DIR}/include\"\n    CACHE INTERNAL \"Directory where pybind11 headers are located\")\n\n# Backward compatible variable for add_subdirectory mode\nif(NOT PYBIND11_MASTER_PROJECT)\n  set(PYBIND11_INCLUDE_DIR\n      \"${pybind11_INCLUDE_DIR}\"\n      CACHE INTERNAL \"\")\nendif()\n\n# Note: when creating targets, you cannot use if statements at configure time -\n# you need generator expressions, because those will be placed in the target file.\n# You can also place ifs *in* the Config.in, but not here.\n\n# This section builds targets, but does *not* touch Python\n# Non-IMPORT targets cannot be defined twice\nif(NOT TARGET pybind11_headers)\n  # Build the headers-only target (no Python included):\n  # (long name used here to keep this from clashing in subdirectory mode)\n  add_library(pybind11_headers INTERFACE)\n  add_library(pybind11::pybind11_headers ALIAS pybind11_headers) # to match exported target\n  add_library(pybind11::headers ALIAS pybind11_headers) # easier to use/remember\n\n  target_include_directories(\n    pybind11_headers ${pybind11_system} INTERFACE $<BUILD_INTERFACE:${pybind11_INCLUDE_DIR}>\n                                                  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)\n\n  target_compile_features(pybind11_headers INTERFACE cxx_inheriting_constructors cxx_user_literals\n                                                     cxx_right_angle_brackets)\n  if(NOT \"${PYBIND11_INTERNALS_VERSION}\" STREQUAL \"\")\n    target_compile_definitions(\n      pybind11_headers INTERFACE \"PYBIND11_INTERNALS_VERSION=${PYBIND11_INTERNALS_VERSION}\")\n  endif()\nelse()\n  # It is invalid to install a target twice, too.\n  set(PYBIND11_INSTALL OFF)\nendif()\n\ninclude(\"${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11Common.cmake\")\n# https://github.com/jtojnar/cmake-snips/#concatenating-paths-when-building-pkg-config-files\n# TODO: cmake 3.20 adds the cmake_path() function, which obsoletes this snippet\ninclude(\"${CMAKE_CURRENT_SOURCE_DIR}/tools/JoinPaths.cmake\")\n\n# Relative directory setting\nif(USE_PYTHON_INCLUDE_DIR AND DEFINED Python_INCLUDE_DIRS)\n  file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${Python_INCLUDE_DIRS})\nelseif(USE_PYTHON_INCLUDE_DIR AND DEFINED PYTHON_INCLUDE_DIR)\n  file(RELATIVE_PATH CMAKE_INSTALL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${PYTHON_INCLUDE_DIRS})\nendif()\n\nif(PYBIND11_INSTALL)\n  install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})\n  set(PYBIND11_CMAKECONFIG_INSTALL_DIR\n      \"${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}\"\n      CACHE STRING \"install path for pybind11Config.cmake\")\n\n  if(IS_ABSOLUTE \"${CMAKE_INSTALL_INCLUDEDIR}\")\n    set(pybind11_INCLUDEDIR \"${CMAKE_INSTALL_FULL_INCLUDEDIR}\")\n  else()\n    set(pybind11_INCLUDEDIR \"\\$\\{PACKAGE_PREFIX_DIR\\}/${CMAKE_INSTALL_INCLUDEDIR}\")\n  endif()\n\n  configure_package_config_file(\n    tools/${PROJECT_NAME}Config.cmake.in \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\"\n    INSTALL_DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})\n\n  if(CMAKE_VERSION VERSION_LESS 3.14)\n    # Remove CMAKE_SIZEOF_VOID_P from ConfigVersion.cmake since the library does\n    # not depend on architecture specific settings or libraries.\n    set(_PYBIND11_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})\n    unset(CMAKE_SIZEOF_VOID_P)\n\n    write_basic_package_version_file(\n      ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\n      VERSION ${PROJECT_VERSION}\n      COMPATIBILITY AnyNewerVersion)\n\n    set(CMAKE_SIZEOF_VOID_P ${_PYBIND11_CMAKE_SIZEOF_VOID_P})\n  else()\n    # CMake 3.14+ natively supports header-only libraries\n    write_basic_package_version_file(\n      ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\n      VERSION ${PROJECT_VERSION}\n      COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT)\n  endif()\n\n  install(\n    FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake\n          ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake\n          tools/FindPythonLibsNew.cmake\n          tools/pybind11Common.cmake\n          tools/pybind11Tools.cmake\n          tools/pybind11NewTools.cmake\n    DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})\n\n  if(NOT PYBIND11_EXPORT_NAME)\n    set(PYBIND11_EXPORT_NAME \"${PROJECT_NAME}Targets\")\n  endif()\n\n  install(TARGETS pybind11_headers EXPORT \"${PYBIND11_EXPORT_NAME}\")\n\n  install(\n    EXPORT \"${PYBIND11_EXPORT_NAME}\"\n    NAMESPACE \"pybind11::\"\n    DESTINATION ${PYBIND11_CMAKECONFIG_INSTALL_DIR})\n\n  # pkg-config support\n  if(NOT prefix_for_pc_file)\n    if(IS_ABSOLUTE \"${CMAKE_INSTALL_DATAROOTDIR}\")\n      set(prefix_for_pc_file \"${CMAKE_INSTALL_PREFIX}\")\n    else()\n      set(pc_datarootdir \"${CMAKE_INSTALL_DATAROOTDIR}\")\n      if(CMAKE_VERSION VERSION_LESS 3.20)\n        set(prefix_for_pc_file \"\\${pcfiledir}/..\")\n        while(pc_datarootdir)\n          get_filename_component(pc_datarootdir \"${pc_datarootdir}\" DIRECTORY)\n          string(APPEND prefix_for_pc_file \"/..\")\n        endwhile()\n      else()\n        cmake_path(RELATIVE_PATH CMAKE_INSTALL_PREFIX BASE_DIRECTORY CMAKE_INSTALL_DATAROOTDIR\n                   OUTPUT_VARIABLE prefix_for_pc_file)\n      endif()\n    endif()\n  endif()\n  join_paths(includedir_for_pc_file \"\\${prefix}\" \"${CMAKE_INSTALL_INCLUDEDIR}\")\n  configure_file(\"${CMAKE_CURRENT_SOURCE_DIR}/tools/pybind11.pc.in\"\n                 \"${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc\" @ONLY)\n  install(FILES \"${CMAKE_CURRENT_BINARY_DIR}/pybind11.pc\"\n          DESTINATION \"${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig/\")\n\n  # Uninstall target\n  if(PYBIND11_MASTER_PROJECT)\n    configure_file(\"${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake_uninstall.cmake.in\"\n                   \"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake\" IMMEDIATE @ONLY)\n\n    add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P\n                                        ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)\n  endif()\nendif()\n\n# BUILD_TESTING takes priority, but only if this is the master project\nif(PYBIND11_MASTER_PROJECT AND DEFINED BUILD_TESTING)\n  if(BUILD_TESTING)\n    if(_pybind11_nopython)\n      message(FATAL_ERROR \"Cannot activate tests in NOPYTHON mode\")\n    else()\n      add_subdirectory(tests)\n    endif()\n  endif()\nelse()\n  if(PYBIND11_TEST)\n    if(_pybind11_nopython)\n      message(FATAL_ERROR \"Cannot activate tests in NOPYTHON mode\")\n    else()\n      add_subdirectory(tests)\n    endif()\n  endif()\nendif()\n\n# Better symmetry with find_package(pybind11 CONFIG) mode.\nif(NOT PYBIND11_MASTER_PROJECT)\n  set(pybind11_FOUND\n      TRUE\n      CACHE INTERNAL \"True if pybind11 and all required components found on the system\")\nendif()\n"
  },
  {
    "path": "dlib/external/pybind11/LICENSE",
    "content": "Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>, All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors\n   may be used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nPlease also refer to the file .github/CONTRIBUTING.md, which clarifies licensing of\nexternal contributions to this project including patches, pull requests, etc.\n"
  },
  {
    "path": "dlib/external/pybind11/README.rst",
    "content": ".. figure:: https://github.com/pybind/pybind11/raw/master/docs/pybind11-logo.png\n   :alt: pybind11 logo\n\n**pybind11 — Seamless operability between C++11 and Python**\n\n|Latest Documentation Status| |Stable Documentation Status| |Gitter chat| |GitHub Discussions| |CI| |Build status|\n\n|Repology| |PyPI package| |Conda-forge| |Python Versions|\n\n`Setuptools example <https://github.com/pybind/python_example>`_\n• `Scikit-build example <https://github.com/pybind/scikit_build_example>`_\n• `CMake example <https://github.com/pybind/cmake_example>`_\n\n.. start\n\n\n**pybind11** is a lightweight header-only library that exposes C++ types\nin Python and vice versa, mainly to create Python bindings of existing\nC++ code. Its goals and syntax are similar to the excellent\n`Boost.Python <http://www.boost.org/doc/libs/1_58_0/libs/python/doc/>`_\nlibrary by David Abrahams: to minimize boilerplate code in traditional\nextension modules by inferring type information using compile-time\nintrospection.\n\nThe main issue with Boost.Python—and the reason for creating such a\nsimilar project—is Boost. Boost is an enormously large and complex suite\nof utility libraries that works with almost every C++ compiler in\nexistence. This compatibility has its cost: arcane template tricks and\nworkarounds are necessary to support the oldest and buggiest of compiler\nspecimens. Now that C++11-compatible compilers are widely available,\nthis heavy machinery has become an excessively large and unnecessary\ndependency.\n\nThink of this library as a tiny self-contained version of Boost.Python\nwith everything stripped away that isn't relevant for binding\ngeneration. Without comments, the core header files only require ~4K\nlines of code and depend on Python (3.6+, or PyPy) and the C++\nstandard library. This compact implementation was possible thanks to\nsome C++11 language features (specifically: tuples, lambda functions and\nvariadic templates). Since its creation, this library has grown beyond\nBoost.Python in many ways, leading to dramatically simpler binding code in many\ncommon situations.\n\nTutorial and reference documentation is provided at\n`pybind11.readthedocs.io <https://pybind11.readthedocs.io/en/latest>`_.\nA PDF version of the manual is available\n`here <https://pybind11.readthedocs.io/_/downloads/en/latest/pdf/>`_.\nAnd the source code is always available at\n`github.com/pybind/pybind11 <https://github.com/pybind/pybind11>`_.\n\n\nCore features\n-------------\n\n\npybind11 can map the following core C++ features to Python:\n\n- Functions accepting and returning custom data structures per value,\n  reference, or pointer\n- Instance methods and static methods\n- Overloaded functions\n- Instance attributes and static attributes\n- Arbitrary exception types\n- Enumerations\n- Callbacks\n- Iterators and ranges\n- Custom operators\n- Single and multiple inheritance\n- STL data structures\n- Smart pointers with reference counting like ``std::shared_ptr``\n- Internal references with correct reference counting\n- C++ classes with virtual (and pure virtual) methods can be extended\n  in Python\n- Integrated NumPy support (NumPy 2 requires pybind11 2.12+)\n\nGoodies\n-------\n\nIn addition to the core functionality, pybind11 provides some extra\ngoodies:\n\n- Python 3.6+, and PyPy3 7.3 are supported with an implementation-agnostic\n  interface (pybind11 2.9 was the last version to support Python 2 and 3.5).\n\n- It is possible to bind C++11 lambda functions with captured\n  variables. The lambda capture data is stored inside the resulting\n  Python function object.\n\n- pybind11 uses C++11 move constructors and move assignment operators\n  whenever possible to efficiently transfer custom data types.\n\n- It's easy to expose the internal storage of custom data types through\n  Pythons' buffer protocols. This is handy e.g. for fast conversion\n  between C++ matrix classes like Eigen and NumPy without expensive\n  copy operations.\n\n- pybind11 can automatically vectorize functions so that they are\n  transparently applied to all entries of one or more NumPy array\n  arguments.\n\n- Python's slice-based access and assignment operations can be\n  supported with just a few lines of code.\n\n- Everything is contained in just a few header files; there is no need\n  to link against any additional libraries.\n\n- Binaries are generally smaller by a factor of at least 2 compared to\n  equivalent bindings generated by Boost.Python. A recent pybind11\n  conversion of PyRosetta, an enormous Boost.Python binding project,\n  `reported <https://graylab.jhu.edu/Sergey/2016.RosettaCon/PyRosetta-4.pdf>`_\n  a binary size reduction of **5.4x** and compile time reduction by\n  **5.8x**.\n\n- Function signatures are precomputed at compile time (using\n  ``constexpr``), leading to smaller binaries.\n\n- With little extra effort, C++ types can be pickled and unpickled\n  similar to regular Python objects.\n\nSupported compilers\n-------------------\n\n1. Clang/LLVM 3.3 or newer (for Apple Xcode's clang, this is 5.0.0 or\n   newer)\n2. GCC 4.8 or newer\n3. Microsoft Visual Studio 2017 or newer\n4. Intel classic C++ compiler 18 or newer (ICC 20.2 tested in CI)\n5. Cygwin/GCC (previously tested on 2.5.1)\n6. NVCC (CUDA 11.0 tested in CI)\n7. NVIDIA PGI (20.9 tested in CI)\n\nAbout\n-----\n\nThis project was created by `Wenzel\nJakob <http://rgl.epfl.ch/people/wjakob>`_. Significant features and/or\nimprovements to the code were contributed by Jonas Adler, Lori A. Burns,\nSylvain Corlay, Eric Cousineau, Aaron Gokaslan, Ralf Grosse-Kunstleve, Trent Houliston, Axel\nHuebl, @hulucc, Yannick Jadoul, Sergey Lyskov, Johan Mabille, Tomasz Miąsko,\nDean Moldovan, Ben Pritchard, Jason Rhinelander, Boris Schäling, Pim\nSchellart, Henry Schreiner, Ivan Smirnov, Boris Staletic, and Patrick Stewart.\n\nWe thank Google for a generous financial contribution to the continuous\nintegration infrastructure used by this project.\n\n\nContributing\n~~~~~~~~~~~~\n\nSee the `contributing\nguide <https://github.com/pybind/pybind11/blob/master/.github/CONTRIBUTING.md>`_\nfor information on building and contributing to pybind11.\n\nLicense\n~~~~~~~\n\npybind11 is provided under a BSD-style license that can be found in the\n`LICENSE <https://github.com/pybind/pybind11/blob/master/LICENSE>`_\nfile. By using, distributing, or contributing to this project, you agree\nto the terms and conditions of this license.\n\n.. |Latest Documentation Status| image:: https://readthedocs.org/projects/pybind11/badge?version=latest\n   :target: http://pybind11.readthedocs.org/en/latest\n.. |Stable Documentation Status| image:: https://img.shields.io/badge/docs-stable-blue.svg\n   :target: http://pybind11.readthedocs.org/en/stable\n.. |Gitter chat| image:: https://img.shields.io/gitter/room/gitterHQ/gitter.svg\n   :target: https://gitter.im/pybind/Lobby\n.. |CI| image:: https://github.com/pybind/pybind11/workflows/CI/badge.svg\n   :target: https://github.com/pybind/pybind11/actions\n.. |Build status| image:: https://ci.appveyor.com/api/projects/status/riaj54pn4h08xy40?svg=true\n   :target: https://ci.appveyor.com/project/wjakob/pybind11\n.. |PyPI package| image:: https://img.shields.io/pypi/v/pybind11.svg\n   :target: https://pypi.org/project/pybind11/\n.. |Conda-forge| image:: https://img.shields.io/conda/vn/conda-forge/pybind11.svg\n   :target: https://github.com/conda-forge/pybind11-feedstock\n.. |Repology| image:: https://repology.org/badge/latest-versions/python:pybind11.svg\n   :target: https://repology.org/project/python:pybind11/versions\n.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pybind11.svg\n   :target: https://pypi.org/project/pybind11/\n.. |GitHub Discussions| image:: https://img.shields.io/static/v1?label=Discussions&message=Ask&color=blue&logo=github\n   :target: https://github.com/pybind/pybind11/discussions\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/attr.h",
    "content": "/*\n    pybind11/attr.h: Infrastructure for processing custom\n    type and function attributes\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"cast.h\"\n\n#include <functional>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\n/// \\addtogroup annotations\n/// @{\n\n/// Annotation for methods\nstruct is_method {\n    handle class_;\n    explicit is_method(const handle &c) : class_(c) {}\n};\n\n/// Annotation for setters\nstruct is_setter {};\n\n/// Annotation for operators\nstruct is_operator {};\n\n/// Annotation for classes that cannot be subclassed\nstruct is_final {};\n\n/// Annotation for parent scope\nstruct scope {\n    handle value;\n    explicit scope(const handle &s) : value(s) {}\n};\n\n/// Annotation for documentation\nstruct doc {\n    const char *value;\n    explicit doc(const char *value) : value(value) {}\n};\n\n/// Annotation for function names\nstruct name {\n    const char *value;\n    explicit name(const char *value) : value(value) {}\n};\n\n/// Annotation indicating that a function is an overload associated with a given \"sibling\"\nstruct sibling {\n    handle value;\n    explicit sibling(const handle &value) : value(value.ptr()) {}\n};\n\n/// Annotation indicating that a class derives from another given type\ntemplate <typename T>\nstruct base {\n\n    PYBIND11_DEPRECATED(\n        \"base<T>() was deprecated in favor of specifying 'T' as a template argument to class_\")\n    base() = default;\n};\n\n/// Keep patient alive while nurse lives\ntemplate <size_t Nurse, size_t Patient>\nstruct keep_alive {};\n\n/// Annotation indicating that a class is involved in a multiple inheritance relationship\nstruct multiple_inheritance {};\n\n/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class\nstruct dynamic_attr {};\n\n/// Annotation which enables the buffer protocol for a type\nstruct buffer_protocol {};\n\n/// Annotation which requests that a special metaclass is created for a type\nstruct metaclass {\n    handle value;\n\n    PYBIND11_DEPRECATED(\"py::metaclass() is no longer required. It's turned on by default now.\")\n    metaclass() = default;\n\n    /// Override pybind11's default metaclass\n    explicit metaclass(handle value) : value(value) {}\n};\n\n/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that\n/// may be used to customize the Python type.\n///\n/// The callback is invoked immediately before `PyType_Ready`.\n///\n/// Note: This is an advanced interface, and uses of it may require changes to\n/// work with later versions of pybind11.  You may wish to consult the\n/// implementation of `make_new_python_type` in `detail/classes.h` to understand\n/// the context in which the callback will be run.\nstruct custom_type_setup {\n    using callback = std::function<void(PyHeapTypeObject *heap_type)>;\n\n    explicit custom_type_setup(callback value) : value(std::move(value)) {}\n\n    callback value;\n};\n\n/// Annotation that marks a class as local to the module:\nstruct module_local {\n    const bool value;\n    constexpr explicit module_local(bool v = true) : value(v) {}\n};\n\n/// Annotation to mark enums as an arithmetic type\nstruct arithmetic {};\n\n/// Mark a function for addition at the beginning of the existing overload chain instead of the end\nstruct prepend {};\n\n/** \\rst\n    A call policy which places one or more guard variables (``Ts...``) around the function call.\n\n    For example, this definition:\n\n    .. code-block:: cpp\n\n        m.def(\"foo\", foo, py::call_guard<T>());\n\n    is equivalent to the following pseudocode:\n\n    .. code-block:: cpp\n\n        m.def(\"foo\", [](args...) {\n            T scope_guard;\n            return foo(args...); // forwarded arguments\n        });\n \\endrst */\ntemplate <typename... Ts>\nstruct call_guard;\n\ntemplate <>\nstruct call_guard<> {\n    using type = detail::void_type;\n};\n\ntemplate <typename T>\nstruct call_guard<T> {\n    static_assert(std::is_default_constructible<T>::value,\n                  \"The guard type must be default constructible\");\n\n    using type = T;\n};\n\ntemplate <typename T, typename... Ts>\nstruct call_guard<T, Ts...> {\n    struct type {\n        T guard{}; // Compose multiple guard types with left-to-right default-constructor order\n        typename call_guard<Ts...>::type next{};\n    };\n};\n\n/// @} annotations\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n/* Forward declarations */\nenum op_id : int;\nenum op_type : int;\nstruct undefined_t;\ntemplate <op_id id, op_type ot, typename L = undefined_t, typename R = undefined_t>\nstruct op_;\nvoid keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret);\n\n/// Internal data structure which holds metadata about a keyword argument\nstruct argument_record {\n    const char *name;  ///< Argument name\n    const char *descr; ///< Human-readable version of the argument value\n    handle value;      ///< Associated Python object\n    bool convert : 1;  ///< True if the argument is allowed to convert when loading\n    bool none : 1;     ///< True if None is allowed when loading\n\n    argument_record(const char *name, const char *descr, handle value, bool convert, bool none)\n        : name(name), descr(descr), value(value), convert(convert), none(none) {}\n};\n\n/// Internal data structure which holds metadata about a bound function (signature, overloads,\n/// etc.)\nstruct function_record {\n    function_record()\n        : is_constructor(false), is_new_style_constructor(false), is_stateless(false),\n          is_operator(false), is_method(false), is_setter(false), has_args(false),\n          has_kwargs(false), prepend(false) {}\n\n    /// Function name\n    char *name = nullptr; /* why no C++ strings? They generate heavier code.. */\n\n    // User-specified documentation string\n    char *doc = nullptr;\n\n    /// Human-readable version of the function signature\n    char *signature = nullptr;\n\n    /// List of registered keyword arguments\n    std::vector<argument_record> args;\n\n    /// Pointer to lambda function which converts arguments and performs the actual call\n    handle (*impl)(function_call &) = nullptr;\n\n    /// Storage for the wrapped function pointer and captured data, if any\n    void *data[3] = {};\n\n    /// Pointer to custom destructor for 'data' (if needed)\n    void (*free_data)(function_record *ptr) = nullptr;\n\n    /// Return value policy associated with this function\n    return_value_policy policy = return_value_policy::automatic;\n\n    /// True if name == '__init__'\n    bool is_constructor : 1;\n\n    /// True if this is a new-style `__init__` defined in `detail/init.h`\n    bool is_new_style_constructor : 1;\n\n    /// True if this is a stateless function pointer\n    bool is_stateless : 1;\n\n    /// True if this is an operator (__add__), etc.\n    bool is_operator : 1;\n\n    /// True if this is a method\n    bool is_method : 1;\n\n    /// True if this is a setter\n    bool is_setter : 1;\n\n    /// True if the function has a '*args' argument\n    bool has_args : 1;\n\n    /// True if the function has a '**kwargs' argument\n    bool has_kwargs : 1;\n\n    /// True if this function is to be inserted at the beginning of the overload resolution chain\n    bool prepend : 1;\n\n    /// Number of arguments (including py::args and/or py::kwargs, if present)\n    std::uint16_t nargs;\n\n    /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs\n    /// argument or by a py::kw_only annotation.\n    std::uint16_t nargs_pos = 0;\n\n    /// Number of leading arguments (counted in `nargs`) that are positional-only\n    std::uint16_t nargs_pos_only = 0;\n\n    /// Python method object\n    PyMethodDef *def = nullptr;\n\n    /// Python handle to the parent scope (a class or a module)\n    handle scope;\n\n    /// Python handle to the sibling function representing an overload chain\n    handle sibling;\n\n    /// Pointer to next overload\n    function_record *next = nullptr;\n};\n\n/// Special data structure which (temporarily) holds metadata about a bound class\nstruct type_record {\n    PYBIND11_NOINLINE type_record()\n        : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false),\n          default_holder(true), module_local(false), is_final(false) {}\n\n    /// Handle to the parent scope\n    handle scope;\n\n    /// Name of the class\n    const char *name = nullptr;\n\n    // Pointer to RTTI type_info data structure\n    const std::type_info *type = nullptr;\n\n    /// How large is the underlying C++ type?\n    size_t type_size = 0;\n\n    /// What is the alignment of the underlying C++ type?\n    size_t type_align = 0;\n\n    /// How large is the type's holder?\n    size_t holder_size = 0;\n\n    /// The global operator new can be overridden with a class-specific variant\n    void *(*operator_new)(size_t) = nullptr;\n\n    /// Function pointer to class_<..>::init_instance\n    void (*init_instance)(instance *, const void *) = nullptr;\n\n    /// Function pointer to class_<..>::dealloc\n    void (*dealloc)(detail::value_and_holder &) = nullptr;\n\n    /// List of base classes of the newly created type\n    list bases;\n\n    /// Optional docstring\n    const char *doc = nullptr;\n\n    /// Custom metaclass (optional)\n    handle metaclass;\n\n    /// Custom type setup.\n    custom_type_setup::callback custom_type_setup_callback;\n\n    /// Multiple inheritance marker\n    bool multiple_inheritance : 1;\n\n    /// Does the class manage a __dict__?\n    bool dynamic_attr : 1;\n\n    /// Does the class implement the buffer protocol?\n    bool buffer_protocol : 1;\n\n    /// Is the default (unique_ptr) holder type used?\n    bool default_holder : 1;\n\n    /// Is the class definition local to the module shared object?\n    bool module_local : 1;\n\n    /// Is the class inheritable from python classes?\n    bool is_final : 1;\n\n    PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) {\n        auto *base_info = detail::get_type_info(base, false);\n        if (!base_info) {\n            std::string tname(base.name());\n            detail::clean_type_id(tname);\n            pybind11_fail(\"generic_type: type \\\"\" + std::string(name)\n                          + \"\\\" referenced unknown base type \\\"\" + tname + \"\\\"\");\n        }\n\n        if (default_holder != base_info->default_holder) {\n            std::string tname(base.name());\n            detail::clean_type_id(tname);\n            pybind11_fail(\"generic_type: type \\\"\" + std::string(name) + \"\\\" \"\n                          + (default_holder ? \"does not have\" : \"has\")\n                          + \" a non-default holder type while its base \\\"\" + tname + \"\\\" \"\n                          + (base_info->default_holder ? \"does not\" : \"does\"));\n        }\n\n        bases.append((PyObject *) base_info->type);\n\n#if PY_VERSION_HEX < 0x030B0000\n        dynamic_attr |= base_info->type->tp_dictoffset != 0;\n#else\n        dynamic_attr |= (base_info->type->tp_flags & Py_TPFLAGS_MANAGED_DICT) != 0;\n#endif\n\n        if (caster) {\n            base_info->implicit_casts.emplace_back(type, caster);\n        }\n    }\n};\n\ninline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) {\n    args.reserve(f.nargs);\n    args_convert.reserve(f.nargs);\n}\n\n/// Tag for a new-style `__init__` defined in `detail/init.h`\nstruct is_new_style_constructor {};\n\n/**\n * Partial template specializations to process custom attributes provided to\n * cpp_function_ and class_. These are either used to initialize the respective\n * fields in the type_record and function_record data structures or executed at\n * runtime to deal with custom call policies (e.g. keep_alive).\n */\ntemplate <typename T, typename SFINAE = void>\nstruct process_attribute;\n\ntemplate <typename T>\nstruct process_attribute_default {\n    /// Default implementation: do nothing\n    static void init(const T &, function_record *) {}\n    static void init(const T &, type_record *) {}\n    static void precall(function_call &) {}\n    static void postcall(function_call &, handle) {}\n};\n\n/// Process an attribute specifying the function's name\ntemplate <>\nstruct process_attribute<name> : process_attribute_default<name> {\n    static void init(const name &n, function_record *r) { r->name = const_cast<char *>(n.value); }\n};\n\n/// Process an attribute specifying the function's docstring\ntemplate <>\nstruct process_attribute<doc> : process_attribute_default<doc> {\n    static void init(const doc &n, function_record *r) { r->doc = const_cast<char *>(n.value); }\n};\n\n/// Process an attribute specifying the function's docstring (provided as a C-style string)\ntemplate <>\nstruct process_attribute<const char *> : process_attribute_default<const char *> {\n    static void init(const char *d, function_record *r) { r->doc = const_cast<char *>(d); }\n    static void init(const char *d, type_record *r) { r->doc = d; }\n};\ntemplate <>\nstruct process_attribute<char *> : process_attribute<const char *> {};\n\n/// Process an attribute indicating the function's return value policy\ntemplate <>\nstruct process_attribute<return_value_policy> : process_attribute_default<return_value_policy> {\n    static void init(const return_value_policy &p, function_record *r) { r->policy = p; }\n};\n\n/// Process an attribute which indicates that this is an overloaded function associated with a\n/// given sibling\ntemplate <>\nstruct process_attribute<sibling> : process_attribute_default<sibling> {\n    static void init(const sibling &s, function_record *r) { r->sibling = s.value; }\n};\n\n/// Process an attribute which indicates that this function is a method\ntemplate <>\nstruct process_attribute<is_method> : process_attribute_default<is_method> {\n    static void init(const is_method &s, function_record *r) {\n        r->is_method = true;\n        r->scope = s.class_;\n    }\n};\n\n/// Process an attribute which indicates that this function is a setter\ntemplate <>\nstruct process_attribute<is_setter> : process_attribute_default<is_setter> {\n    static void init(const is_setter &, function_record *r) { r->is_setter = true; }\n};\n\n/// Process an attribute which indicates the parent scope of a method\ntemplate <>\nstruct process_attribute<scope> : process_attribute_default<scope> {\n    static void init(const scope &s, function_record *r) { r->scope = s.value; }\n};\n\n/// Process an attribute which indicates that this function is an operator\ntemplate <>\nstruct process_attribute<is_operator> : process_attribute_default<is_operator> {\n    static void init(const is_operator &, function_record *r) { r->is_operator = true; }\n};\n\ntemplate <>\nstruct process_attribute<is_new_style_constructor>\n    : process_attribute_default<is_new_style_constructor> {\n    static void init(const is_new_style_constructor &, function_record *r) {\n        r->is_new_style_constructor = true;\n    }\n};\n\ninline void check_kw_only_arg(const arg &a, function_record *r) {\n    if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\\0')) {\n        pybind11_fail(\"arg(): cannot specify an unnamed argument after a kw_only() annotation or \"\n                      \"args() argument\");\n    }\n}\n\ninline void append_self_arg_if_needed(function_record *r) {\n    if (r->is_method && r->args.empty()) {\n        r->args.emplace_back(\"self\", nullptr, handle(), /*convert=*/true, /*none=*/false);\n    }\n}\n\n/// Process a keyword argument attribute (*without* a default value)\ntemplate <>\nstruct process_attribute<arg> : process_attribute_default<arg> {\n    static void init(const arg &a, function_record *r) {\n        append_self_arg_if_needed(r);\n        r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none);\n\n        check_kw_only_arg(a, r);\n    }\n};\n\n/// Process a keyword argument attribute (*with* a default value)\ntemplate <>\nstruct process_attribute<arg_v> : process_attribute_default<arg_v> {\n    static void init(const arg_v &a, function_record *r) {\n        if (r->is_method && r->args.empty()) {\n            r->args.emplace_back(\n                \"self\", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false);\n        }\n\n        if (!a.value) {\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            std::string descr(\"'\");\n            if (a.name) {\n                descr += std::string(a.name) + \": \";\n            }\n            descr += a.type + \"'\";\n            if (r->is_method) {\n                if (r->name) {\n                    descr += \" in method '\" + (std::string) str(r->scope) + \".\"\n                             + (std::string) r->name + \"'\";\n                } else {\n                    descr += \" in method of '\" + (std::string) str(r->scope) + \"'\";\n                }\n            } else if (r->name) {\n                descr += \" in function '\" + (std::string) r->name + \"'\";\n            }\n            pybind11_fail(\"arg(): could not convert default argument \" + descr\n                          + \" into a Python object (type not registered yet?)\");\n#else\n            pybind11_fail(\"arg(): could not convert default argument \"\n                          \"into a Python object (type not registered yet?). \"\n                          \"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for \"\n                          \"more information.\");\n#endif\n        }\n        r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none);\n\n        check_kw_only_arg(a, r);\n    }\n};\n\n/// Process a keyword-only-arguments-follow pseudo argument\ntemplate <>\nstruct process_attribute<kw_only> : process_attribute_default<kw_only> {\n    static void init(const kw_only &, function_record *r) {\n        append_self_arg_if_needed(r);\n        if (r->has_args && r->nargs_pos != static_cast<std::uint16_t>(r->args.size())) {\n            pybind11_fail(\"Mismatched args() and kw_only(): they must occur at the same relative \"\n                          \"argument location (or omit kw_only() entirely)\");\n        }\n        r->nargs_pos = static_cast<std::uint16_t>(r->args.size());\n    }\n};\n\n/// Process a positional-only-argument maker\ntemplate <>\nstruct process_attribute<pos_only> : process_attribute_default<pos_only> {\n    static void init(const pos_only &, function_record *r) {\n        append_self_arg_if_needed(r);\n        r->nargs_pos_only = static_cast<std::uint16_t>(r->args.size());\n        if (r->nargs_pos_only > r->nargs_pos) {\n            pybind11_fail(\"pos_only(): cannot follow a py::args() argument\");\n        }\n        // It also can't follow a kw_only, but a static_assert in pybind11.h checks that\n    }\n};\n\n/// Process a parent class attribute.  Single inheritance only (class_ itself already guarantees\n/// that)\ntemplate <typename T>\nstruct process_attribute<T, enable_if_t<is_pyobject<T>::value>>\n    : process_attribute_default<handle> {\n    static void init(const handle &h, type_record *r) { r->bases.append(h); }\n};\n\n/// Process a parent class attribute (deprecated, does not support multiple inheritance)\ntemplate <typename T>\nstruct process_attribute<base<T>> : process_attribute_default<base<T>> {\n    static void init(const base<T> &, type_record *r) { r->add_base(typeid(T), nullptr); }\n};\n\n/// Process a multiple inheritance attribute\ntemplate <>\nstruct process_attribute<multiple_inheritance> : process_attribute_default<multiple_inheritance> {\n    static void init(const multiple_inheritance &, type_record *r) {\n        r->multiple_inheritance = true;\n    }\n};\n\ntemplate <>\nstruct process_attribute<dynamic_attr> : process_attribute_default<dynamic_attr> {\n    static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; }\n};\n\ntemplate <>\nstruct process_attribute<custom_type_setup> {\n    static void init(const custom_type_setup &value, type_record *r) {\n        r->custom_type_setup_callback = value.value;\n    }\n};\n\ntemplate <>\nstruct process_attribute<is_final> : process_attribute_default<is_final> {\n    static void init(const is_final &, type_record *r) { r->is_final = true; }\n};\n\ntemplate <>\nstruct process_attribute<buffer_protocol> : process_attribute_default<buffer_protocol> {\n    static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; }\n};\n\ntemplate <>\nstruct process_attribute<metaclass> : process_attribute_default<metaclass> {\n    static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; }\n};\n\ntemplate <>\nstruct process_attribute<module_local> : process_attribute_default<module_local> {\n    static void init(const module_local &l, type_record *r) { r->module_local = l.value; }\n};\n\n/// Process a 'prepend' attribute, putting this at the beginning of the overload chain\ntemplate <>\nstruct process_attribute<prepend> : process_attribute_default<prepend> {\n    static void init(const prepend &, function_record *r) { r->prepend = true; }\n};\n\n/// Process an 'arithmetic' attribute for enums (does nothing here)\ntemplate <>\nstruct process_attribute<arithmetic> : process_attribute_default<arithmetic> {};\n\ntemplate <typename... Ts>\nstruct process_attribute<call_guard<Ts...>> : process_attribute_default<call_guard<Ts...>> {};\n\n/**\n * Process a keep_alive call policy -- invokes keep_alive_impl during the\n * pre-call handler if both Nurse, Patient != 0 and use the post-call handler\n * otherwise\n */\ntemplate <size_t Nurse, size_t Patient>\nstruct process_attribute<keep_alive<Nurse, Patient>>\n    : public process_attribute_default<keep_alive<Nurse, Patient>> {\n    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>\n    static void precall(function_call &call) {\n        keep_alive_impl(Nurse, Patient, call, handle());\n    }\n    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N != 0 && P != 0, int> = 0>\n    static void postcall(function_call &, handle) {}\n    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>\n    static void precall(function_call &) {}\n    template <size_t N = Nurse, size_t P = Patient, enable_if_t<N == 0 || P == 0, int> = 0>\n    static void postcall(function_call &call, handle ret) {\n        keep_alive_impl(Nurse, Patient, call, ret);\n    }\n};\n\n/// Recursively iterate over variadic template arguments\ntemplate <typename... Args>\nstruct process_attributes {\n    static void init(const Args &...args, function_record *r) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);\n        PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);\n        using expander = int[];\n        (void) expander{\n            0, ((void) process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};\n    }\n    static void init(const Args &...args, type_record *r) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r);\n        PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r);\n        using expander = int[];\n        (void) expander{0,\n                        (process_attribute<typename std::decay<Args>::type>::init(args, r), 0)...};\n    }\n    static void precall(function_call &call) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call);\n        using expander = int[];\n        (void) expander{0,\n                        (process_attribute<typename std::decay<Args>::type>::precall(call), 0)...};\n    }\n    static void postcall(function_call &call, handle fn_ret) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret);\n        PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret);\n        using expander = int[];\n        (void) expander{\n            0, (process_attribute<typename std::decay<Args>::type>::postcall(call, fn_ret), 0)...};\n    }\n};\n\ntemplate <typename T>\nusing is_call_guard = is_instantiation<call_guard, T>;\n\n/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found)\ntemplate <typename... Extra>\nusing extract_guard_t = typename exactly_one_t<is_call_guard, call_guard<>, Extra...>::type;\n\n/// Check the number of named arguments at compile time\ntemplate <typename... Extra,\n          size_t named = constexpr_sum(std::is_base_of<arg, Extra>::value...),\n          size_t self = constexpr_sum(std::is_same<is_method, Extra>::value...)>\nconstexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) {\n    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs);\n    return named == 0 || (self + named + size_t(has_args) + size_t(has_kwargs)) == nargs;\n}\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/buffer_info.h",
    "content": "/*\n    pybind11/buffer_info.h: Python buffer object interface\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Default, C-style strides\ninline std::vector<ssize_t> c_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {\n    auto ndim = shape.size();\n    std::vector<ssize_t> strides(ndim, itemsize);\n    if (ndim > 0) {\n        for (size_t i = ndim - 1; i > 0; --i) {\n            strides[i - 1] = strides[i] * shape[i];\n        }\n    }\n    return strides;\n}\n\n// F-style strides; default when constructing an array_t with `ExtraFlags & f_style`\ninline std::vector<ssize_t> f_strides(const std::vector<ssize_t> &shape, ssize_t itemsize) {\n    auto ndim = shape.size();\n    std::vector<ssize_t> strides(ndim, itemsize);\n    for (size_t i = 1; i < ndim; ++i) {\n        strides[i] = strides[i - 1] * shape[i - 1];\n    }\n    return strides;\n}\n\ntemplate <typename T, typename SFINAE = void>\nstruct compare_buffer_info;\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Information record describing a Python buffer object\nstruct buffer_info {\n    void *ptr = nullptr;          // Pointer to the underlying storage\n    ssize_t itemsize = 0;         // Size of individual items in bytes\n    ssize_t size = 0;             // Total number of entries\n    std::string format;           // For homogeneous buffers, this should be set to\n                                  // format_descriptor<T>::format()\n    ssize_t ndim = 0;             // Number of dimensions\n    std::vector<ssize_t> shape;   // Shape of the tensor (1 entry per dimension)\n    std::vector<ssize_t> strides; // Number of bytes between adjacent entries\n                                  // (for each per dimension)\n    bool readonly = false;        // flag to indicate if the underlying storage may be written to\n\n    buffer_info() = default;\n\n    buffer_info(void *ptr,\n                ssize_t itemsize,\n                const std::string &format,\n                ssize_t ndim,\n                detail::any_container<ssize_t> shape_in,\n                detail::any_container<ssize_t> strides_in,\n                bool readonly = false)\n        : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim),\n          shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) {\n        if (ndim != (ssize_t) shape.size() || ndim != (ssize_t) strides.size()) {\n            pybind11_fail(\"buffer_info: ndim doesn't match shape and/or strides length\");\n        }\n        for (size_t i = 0; i < (size_t) ndim; ++i) {\n            size *= shape[i];\n        }\n    }\n\n    template <typename T>\n    buffer_info(T *ptr,\n                detail::any_container<ssize_t> shape_in,\n                detail::any_container<ssize_t> strides_in,\n                bool readonly = false)\n        : buffer_info(private_ctr_tag(),\n                      ptr,\n                      sizeof(T),\n                      format_descriptor<T>::format(),\n                      static_cast<ssize_t>(shape_in->size()),\n                      std::move(shape_in),\n                      std::move(strides_in),\n                      readonly) {}\n\n    buffer_info(void *ptr,\n                ssize_t itemsize,\n                const std::string &format,\n                ssize_t size,\n                bool readonly = false)\n        : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {}\n\n    template <typename T>\n    buffer_info(T *ptr, ssize_t size, bool readonly = false)\n        : buffer_info(ptr, sizeof(T), format_descriptor<T>::format(), size, readonly) {}\n\n    template <typename T>\n    buffer_info(const T *ptr, ssize_t size, bool readonly = true)\n        : buffer_info(\n            const_cast<T *>(ptr), sizeof(T), format_descriptor<T>::format(), size, readonly) {}\n\n    explicit buffer_info(Py_buffer *view, bool ownview = true)\n        : buffer_info(\n            view->buf,\n            view->itemsize,\n            view->format,\n            view->ndim,\n            {view->shape, view->shape + view->ndim},\n            /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects\n             * ignore this flag and return a view with NULL strides.\n             * When strides are NULL, build them manually.  */\n            view->strides\n                ? std::vector<ssize_t>(view->strides, view->strides + view->ndim)\n                : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize),\n            (view->readonly != 0)) {\n        // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)\n        this->m_view = view;\n        // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)\n        this->ownview = ownview;\n    }\n\n    buffer_info(const buffer_info &) = delete;\n    buffer_info &operator=(const buffer_info &) = delete;\n\n    buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); }\n\n    buffer_info &operator=(buffer_info &&rhs) noexcept {\n        ptr = rhs.ptr;\n        itemsize = rhs.itemsize;\n        size = rhs.size;\n        format = std::move(rhs.format);\n        ndim = rhs.ndim;\n        shape = std::move(rhs.shape);\n        strides = std::move(rhs.strides);\n        std::swap(m_view, rhs.m_view);\n        std::swap(ownview, rhs.ownview);\n        readonly = rhs.readonly;\n        return *this;\n    }\n\n    ~buffer_info() {\n        if (m_view && ownview) {\n            PyBuffer_Release(m_view);\n            delete m_view;\n        }\n    }\n\n    Py_buffer *view() const { return m_view; }\n    Py_buffer *&view() { return m_view; }\n\n    /* True if the buffer item type is equivalent to `T`. */\n    // To define \"equivalent\" by example:\n    // `buffer_info::item_type_is_equivalent_to<int>(b)` and\n    // `buffer_info::item_type_is_equivalent_to<long>(b)` may both be true\n    // on some platforms, but `int` and `unsigned` will never be equivalent.\n    // For the ground truth, please inspect `detail::compare_buffer_info<>`.\n    template <typename T>\n    bool item_type_is_equivalent_to() const {\n        return detail::compare_buffer_info<T>::compare(*this);\n    }\n\nprivate:\n    struct private_ctr_tag {};\n\n    buffer_info(private_ctr_tag,\n                void *ptr,\n                ssize_t itemsize,\n                const std::string &format,\n                ssize_t ndim,\n                detail::any_container<ssize_t> &&shape_in,\n                detail::any_container<ssize_t> &&strides_in,\n                bool readonly)\n        : buffer_info(\n            ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {}\n\n    Py_buffer *m_view = nullptr;\n    bool ownview = false;\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename T, typename SFINAE>\nstruct compare_buffer_info {\n    static bool compare(const buffer_info &b) {\n        // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *`\n        return b.format == format_descriptor<T>::format() && b.itemsize == (ssize_t) sizeof(T);\n    }\n};\n\ntemplate <typename T>\nstruct compare_buffer_info<T, detail::enable_if_t<std::is_integral<T>::value>> {\n    static bool compare(const buffer_info &b) {\n        return (size_t) b.itemsize == sizeof(T)\n               && (b.format == format_descriptor<T>::value\n                   || ((sizeof(T) == sizeof(long))\n                       && b.format == (std::is_unsigned<T>::value ? \"L\" : \"l\"))\n                   || ((sizeof(T) == sizeof(size_t))\n                       && b.format == (std::is_unsigned<T>::value ? \"N\" : \"n\")));\n    }\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/cast.h",
    "content": "/*\n    pybind11/cast.h: Partial template specializations to cast between\n    C++ and Python types\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"detail/descr.h\"\n#include \"detail/type_caster_base.h\"\n#include \"detail/typeid.h\"\n#include \"pytypes.h\"\n\n#include <array>\n#include <cstring>\n#include <functional>\n#include <iosfwd>\n#include <iterator>\n#include <memory>\n#include <string>\n#include <tuple>\n#include <type_traits>\n#include <utility>\n#include <vector>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename type, typename SFINAE = void>\nclass type_caster : public type_caster_base<type> {};\ntemplate <typename type>\nusing make_caster = type_caster<intrinsic_t<type>>;\n\n// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T\ntemplate <typename T>\ntypename make_caster<T>::template cast_op_type<T> cast_op(make_caster<T> &caster) {\n    using result_t = typename make_caster<T>::template cast_op_type<T>; // See PR #4893\n    return caster.operator result_t();\n}\ntemplate <typename T>\ntypename make_caster<T>::template cast_op_type<typename std::add_rvalue_reference<T>::type>\ncast_op(make_caster<T> &&caster) {\n    using result_t = typename make_caster<T>::template cast_op_type<\n        typename std::add_rvalue_reference<T>::type>; // See PR #4893\n    return std::move(caster).operator result_t();\n}\n\ntemplate <typename type>\nclass type_caster<std::reference_wrapper<type>> {\nprivate:\n    using caster_t = make_caster<type>;\n    caster_t subcaster;\n    using reference_t = type &;\n    using subcaster_cast_op_type = typename caster_t::template cast_op_type<reference_t>;\n\n    static_assert(\n        std::is_same<typename std::remove_const<type>::type &, subcaster_cast_op_type>::value\n            || std::is_same<reference_t, subcaster_cast_op_type>::value,\n        \"std::reference_wrapper<T> caster requires T to have a caster with an \"\n        \"`operator T &()` or `operator const T &()`\");\n\npublic:\n    bool load(handle src, bool convert) { return subcaster.load(src, convert); }\n    static constexpr auto name = caster_t::name;\n    static handle\n    cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {\n        // It is definitely wrong to take ownership of this pointer, so mask that rvp\n        if (policy == return_value_policy::take_ownership\n            || policy == return_value_policy::automatic) {\n            policy = return_value_policy::automatic_reference;\n        }\n        return caster_t::cast(&src.get(), policy, parent);\n    }\n    template <typename T>\n    using cast_op_type = std::reference_wrapper<type>;\n    explicit operator std::reference_wrapper<type>() { return cast_op<type &>(subcaster); }\n};\n\n#define PYBIND11_TYPE_CASTER(type, py_name)                                                       \\\nprotected:                                                                                        \\\n    type value;                                                                                   \\\n                                                                                                  \\\npublic:                                                                                           \\\n    static constexpr auto name = py_name;                                                         \\\n    template <typename T_,                                                                        \\\n              ::pybind11::detail::enable_if_t<                                                    \\\n                  std::is_same<type, ::pybind11::detail::remove_cv_t<T_>>::value,                 \\\n                  int>                                                                            \\\n              = 0>                                                                                \\\n    static ::pybind11::handle cast(                                                               \\\n        T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) {             \\\n        if (!src)                                                                                 \\\n            return ::pybind11::none().release();                                                  \\\n        if (policy == ::pybind11::return_value_policy::take_ownership) {                          \\\n            auto h = cast(std::move(*src), policy, parent);                                       \\\n            delete src;                                                                           \\\n            return h;                                                                             \\\n        }                                                                                         \\\n        return cast(*src, policy, parent);                                                        \\\n    }                                                                                             \\\n    operator type *() { return &value; }               /* NOLINT(bugprone-macro-parentheses) */   \\\n    operator type &() { return value; }                /* NOLINT(bugprone-macro-parentheses) */   \\\n    operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */   \\\n    template <typename T_>                                                                        \\\n    using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>\n\ntemplate <typename CharT>\nusing is_std_char_type = any_of<std::is_same<CharT, char>, /* std::string */\n#if defined(PYBIND11_HAS_U8STRING)\n                                std::is_same<CharT, char8_t>, /* std::u8string */\n#endif\n                                std::is_same<CharT, char16_t>, /* std::u16string */\n                                std::is_same<CharT, char32_t>, /* std::u32string */\n                                std::is_same<CharT, wchar_t>   /* std::wstring */\n                                >;\n\ntemplate <typename T>\nstruct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_type<T>::value>> {\n    using _py_type_0 = conditional_t<sizeof(T) <= sizeof(long), long, long long>;\n    using _py_type_1 = conditional_t<std::is_signed<T>::value,\n                                     _py_type_0,\n                                     typename std::make_unsigned<_py_type_0>::type>;\n    using py_type = conditional_t<std::is_floating_point<T>::value, double, _py_type_1>;\n\npublic:\n    bool load(handle src, bool convert) {\n        py_type py_value;\n\n        if (!src) {\n            return false;\n        }\n\n#if !defined(PYPY_VERSION)\n        auto index_check = [](PyObject *o) { return PyIndex_Check(o); };\n#else\n        // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`,\n        // while CPython only considers the existence of `nb_index`/`__index__`.\n        auto index_check = [](PyObject *o) { return hasattr(o, \"__index__\"); };\n#endif\n\n        if (std::is_floating_point<T>::value) {\n            if (convert || PyFloat_Check(src.ptr())) {\n                py_value = (py_type) PyFloat_AsDouble(src.ptr());\n            } else {\n                return false;\n            }\n        } else if (PyFloat_Check(src.ptr())\n                   || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {\n            return false;\n        } else {\n            handle src_or_index = src;\n            // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.\n#if PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)\n            object index;\n            if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())\n                index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));\n                if (!index) {\n                    PyErr_Clear();\n                    if (!convert)\n                        return false;\n                } else {\n                    src_or_index = index;\n                }\n            }\n#endif\n            if (std::is_unsigned<py_type>::value) {\n                py_value = as_unsigned<py_type>(src_or_index.ptr());\n            } else { // signed integer:\n                py_value = sizeof(T) <= sizeof(long)\n                               ? (py_type) PyLong_AsLong(src_or_index.ptr())\n                               : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr());\n            }\n        }\n\n        // Python API reported an error\n        bool py_err = py_value == (py_type) -1 && PyErr_Occurred();\n\n        // Check to see if the conversion is valid (integers should match exactly)\n        // Signed/unsigned checks happen elsewhere\n        if (py_err\n            || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T)\n                && py_value != (py_type) (T) py_value)) {\n            PyErr_Clear();\n            if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) {\n                auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value\n                                                         ? PyNumber_Float(src.ptr())\n                                                         : PyNumber_Long(src.ptr()));\n                PyErr_Clear();\n                return load(tmp, false);\n            }\n            return false;\n        }\n\n        value = (T) py_value;\n        return true;\n    }\n\n    template <typename U = T>\n    static typename std::enable_if<std::is_floating_point<U>::value, handle>::type\n    cast(U src, return_value_policy /* policy */, handle /* parent */) {\n        return PyFloat_FromDouble((double) src);\n    }\n\n    template <typename U = T>\n    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value\n                                       && (sizeof(U) <= sizeof(long)),\n                                   handle>::type\n    cast(U src, return_value_policy /* policy */, handle /* parent */) {\n        return PYBIND11_LONG_FROM_SIGNED((long) src);\n    }\n\n    template <typename U = T>\n    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value\n                                       && (sizeof(U) <= sizeof(unsigned long)),\n                                   handle>::type\n    cast(U src, return_value_policy /* policy */, handle /* parent */) {\n        return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src);\n    }\n\n    template <typename U = T>\n    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value\n                                       && (sizeof(U) > sizeof(long)),\n                                   handle>::type\n    cast(U src, return_value_policy /* policy */, handle /* parent */) {\n        return PyLong_FromLongLong((long long) src);\n    }\n\n    template <typename U = T>\n    static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value\n                                       && (sizeof(U) > sizeof(unsigned long)),\n                                   handle>::type\n    cast(U src, return_value_policy /* policy */, handle /* parent */) {\n        return PyLong_FromUnsignedLongLong((unsigned long long) src);\n    }\n\n    PYBIND11_TYPE_CASTER(T, const_name<std::is_integral<T>::value>(\"int\", \"float\"));\n};\n\ntemplate <typename T>\nstruct void_caster {\npublic:\n    bool load(handle src, bool) {\n        if (src && src.is_none()) {\n            return true;\n        }\n        return false;\n    }\n    static handle cast(T, return_value_policy /* policy */, handle /* parent */) {\n        return none().release();\n    }\n    PYBIND11_TYPE_CASTER(T, const_name(\"None\"));\n};\n\ntemplate <>\nclass type_caster<void_type> : public void_caster<void_type> {};\n\ntemplate <>\nclass type_caster<void> : public type_caster<void_type> {\npublic:\n    using type_caster<void_type>::cast;\n\n    bool load(handle h, bool) {\n        if (!h) {\n            return false;\n        }\n        if (h.is_none()) {\n            value = nullptr;\n            return true;\n        }\n\n        /* Check if this is a capsule */\n        if (isinstance<capsule>(h)) {\n            value = reinterpret_borrow<capsule>(h);\n            return true;\n        }\n\n        /* Check if this is a C++ type */\n        const auto &bases = all_type_info((PyTypeObject *) type::handle_of(h).ptr());\n        if (bases.size() == 1) { // Only allowing loading from a single-value type\n            value = values_and_holders(reinterpret_cast<instance *>(h.ptr())).begin()->value_ptr();\n            return true;\n        }\n\n        /* Fail */\n        return false;\n    }\n\n    static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) {\n        if (ptr) {\n            return capsule(ptr).release();\n        }\n        return none().release();\n    }\n\n    template <typename T>\n    using cast_op_type = void *&;\n    explicit operator void *&() { return value; }\n    static constexpr auto name = const_name(\"capsule\");\n\nprivate:\n    void *value = nullptr;\n};\n\ntemplate <>\nclass type_caster<std::nullptr_t> : public void_caster<std::nullptr_t> {};\n\ntemplate <>\nclass type_caster<bool> {\npublic:\n    bool load(handle src, bool convert) {\n        if (!src) {\n            return false;\n        }\n        if (src.ptr() == Py_True) {\n            value = true;\n            return true;\n        }\n        if (src.ptr() == Py_False) {\n            value = false;\n            return true;\n        }\n        if (convert || is_numpy_bool(src)) {\n            // (allow non-implicit conversion for numpy booleans), use strncmp\n            // since NumPy 1.x had an additional trailing underscore.\n\n            Py_ssize_t res = -1;\n            if (src.is_none()) {\n                res = 0; // None is implicitly converted to False\n            }\n#if defined(PYPY_VERSION)\n            // On PyPy, check that \"__bool__\" attr exists\n            else if (hasattr(src, PYBIND11_BOOL_ATTR)) {\n                res = PyObject_IsTrue(src.ptr());\n            }\n#else\n            // Alternate approach for CPython: this does the same as the above, but optimized\n            // using the CPython API so as to avoid an unneeded attribute lookup.\n            else if (auto *tp_as_number = src.ptr()->ob_type->tp_as_number) {\n                if (PYBIND11_NB_BOOL(tp_as_number)) {\n                    res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr());\n                }\n            }\n#endif\n            if (res == 0 || res == 1) {\n                value = (res != 0);\n                return true;\n            }\n            PyErr_Clear();\n        }\n        return false;\n    }\n    static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) {\n        return handle(src ? Py_True : Py_False).inc_ref();\n    }\n    PYBIND11_TYPE_CASTER(bool, const_name(\"bool\"));\n\nprivate:\n    // Test if an object is a NumPy boolean (without fetching the type).\n    static inline bool is_numpy_bool(handle object) {\n        const char *type_name = Py_TYPE(object.ptr())->tp_name;\n        // Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support\n        return std::strcmp(\"numpy.bool\", type_name) == 0\n               || std::strcmp(\"numpy.bool_\", type_name) == 0;\n    }\n};\n\n// Helper class for UTF-{8,16,32} C++ stl strings:\ntemplate <typename StringType, bool IsView = false>\nstruct string_caster {\n    using CharT = typename StringType::value_type;\n\n    // Simplify life by being able to assume standard char sizes (the standard only guarantees\n    // minimums, but Python requires exact sizes)\n    static_assert(!std::is_same<CharT, char>::value || sizeof(CharT) == 1,\n                  \"Unsupported char size != 1\");\n#if defined(PYBIND11_HAS_U8STRING)\n    static_assert(!std::is_same<CharT, char8_t>::value || sizeof(CharT) == 1,\n                  \"Unsupported char8_t size != 1\");\n#endif\n    static_assert(!std::is_same<CharT, char16_t>::value || sizeof(CharT) == 2,\n                  \"Unsupported char16_t size != 2\");\n    static_assert(!std::is_same<CharT, char32_t>::value || sizeof(CharT) == 4,\n                  \"Unsupported char32_t size != 4\");\n    // wchar_t can be either 16 bits (Windows) or 32 (everywhere else)\n    static_assert(!std::is_same<CharT, wchar_t>::value || sizeof(CharT) == 2 || sizeof(CharT) == 4,\n                  \"Unsupported wchar_t size != 2/4\");\n    static constexpr size_t UTF_N = 8 * sizeof(CharT);\n\n    bool load(handle src, bool) {\n        handle load_src = src;\n        if (!src) {\n            return false;\n        }\n        if (!PyUnicode_Check(load_src.ptr())) {\n            return load_raw(load_src);\n        }\n\n        // For UTF-8 we avoid the need for a temporary `bytes` object by using\n        // `PyUnicode_AsUTF8AndSize`.\n        if (UTF_N == 8) {\n            Py_ssize_t size = -1;\n            const auto *buffer\n                = reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size));\n            if (!buffer) {\n                PyErr_Clear();\n                return false;\n            }\n            value = StringType(buffer, static_cast<size_t>(size));\n            return true;\n        }\n\n        auto utfNbytes\n            = reinterpret_steal<object>(PyUnicode_AsEncodedString(load_src.ptr(),\n                                                                  UTF_N == 8    ? \"utf-8\"\n                                                                  : UTF_N == 16 ? \"utf-16\"\n                                                                                : \"utf-32\",\n                                                                  nullptr));\n        if (!utfNbytes) {\n            PyErr_Clear();\n            return false;\n        }\n\n        const auto *buffer\n            = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));\n        size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);\n        // Skip BOM for UTF-16/32\n        if (UTF_N > 8) {\n            buffer++;\n            length--;\n        }\n        value = StringType(buffer, length);\n\n        // If we're loading a string_view we need to keep the encoded Python object alive:\n        if (IsView) {\n            loader_life_support::add_patient(utfNbytes);\n        }\n\n        return true;\n    }\n\n    static handle\n    cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) {\n        const char *buffer = reinterpret_cast<const char *>(src.data());\n        auto nbytes = ssize_t(src.size() * sizeof(CharT));\n        handle s = decode_utfN(buffer, nbytes);\n        if (!s) {\n            throw error_already_set();\n        }\n        return s;\n    }\n\n    PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME));\n\nprivate:\n    static handle decode_utfN(const char *buffer, ssize_t nbytes) {\n#if !defined(PYPY_VERSION)\n        return UTF_N == 8    ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr)\n               : UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr)\n                             : PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr);\n#else\n        // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as\n        // well), so bypass the whole thing by just passing the encoding as a string value, which\n        // works properly:\n        return PyUnicode_Decode(buffer,\n                                nbytes,\n                                UTF_N == 8    ? \"utf-8\"\n                                : UTF_N == 16 ? \"utf-16\"\n                                              : \"utf-32\",\n                                nullptr);\n#endif\n    }\n\n    // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e.\n    // without any encoding/decoding attempt).  For other C++ char sizes this is a no-op.\n    // which supports loading a unicode from a str, doesn't take this path.\n    template <typename C = CharT>\n    bool load_raw(enable_if_t<std::is_same<C, char>::value, handle> src) {\n        if (PYBIND11_BYTES_CHECK(src.ptr())) {\n            // We were passed raw bytes; accept it into a std::string or char*\n            // without any encoding attempt.\n            const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr());\n            if (!bytes) {\n                pybind11_fail(\"Unexpected PYBIND11_BYTES_AS_STRING() failure.\");\n            }\n            value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr()));\n            return true;\n        }\n        if (PyByteArray_Check(src.ptr())) {\n            // We were passed a bytearray; accept it into a std::string or char*\n            // without any encoding attempt.\n            const char *bytearray = PyByteArray_AsString(src.ptr());\n            if (!bytearray) {\n                pybind11_fail(\"Unexpected PyByteArray_AsString() failure.\");\n            }\n            value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr()));\n            return true;\n        }\n\n        return false;\n    }\n\n    template <typename C = CharT>\n    bool load_raw(enable_if_t<!std::is_same<C, char>::value, handle>) {\n        return false;\n    }\n};\n\ntemplate <typename CharT, class Traits, class Allocator>\nstruct type_caster<std::basic_string<CharT, Traits, Allocator>,\n                   enable_if_t<is_std_char_type<CharT>::value>>\n    : string_caster<std::basic_string<CharT, Traits, Allocator>> {};\n\n#ifdef PYBIND11_HAS_STRING_VIEW\ntemplate <typename CharT, class Traits>\nstruct type_caster<std::basic_string_view<CharT, Traits>,\n                   enable_if_t<is_std_char_type<CharT>::value>>\n    : string_caster<std::basic_string_view<CharT, Traits>, true> {};\n#endif\n\n// Type caster for C-style strings.  We basically use a std::string type caster, but also add the\n// ability to use None as a nullptr char* (which the string caster doesn't allow).\ntemplate <typename CharT>\nstruct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {\n    using StringType = std::basic_string<CharT>;\n    using StringCaster = make_caster<StringType>;\n    StringCaster str_caster;\n    bool none = false;\n    CharT one_char = 0;\n\npublic:\n    bool load(handle src, bool convert) {\n        if (!src) {\n            return false;\n        }\n        if (src.is_none()) {\n            // Defer accepting None to other overloads (if we aren't in convert mode):\n            if (!convert) {\n                return false;\n            }\n            none = true;\n            return true;\n        }\n        return str_caster.load(src, convert);\n    }\n\n    static handle cast(const CharT *src, return_value_policy policy, handle parent) {\n        if (src == nullptr) {\n            return pybind11::none().release();\n        }\n        return StringCaster::cast(StringType(src), policy, parent);\n    }\n\n    static handle cast(CharT src, return_value_policy policy, handle parent) {\n        if (std::is_same<char, CharT>::value) {\n            handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);\n            if (!s) {\n                throw error_already_set();\n            }\n            return s;\n        }\n        return StringCaster::cast(StringType(1, src), policy, parent);\n    }\n\n    explicit operator CharT *() {\n        return none ? nullptr : const_cast<CharT *>(static_cast<StringType &>(str_caster).c_str());\n    }\n    explicit operator CharT &() {\n        if (none) {\n            throw value_error(\"Cannot convert None to a character\");\n        }\n\n        auto &value = static_cast<StringType &>(str_caster);\n        size_t str_len = value.size();\n        if (str_len == 0) {\n            throw value_error(\"Cannot convert empty string to a character\");\n        }\n\n        // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that\n        // is too high, and one for multiple unicode characters (caught later), so we need to\n        // figure out how long the first encoded character is in bytes to distinguish between these\n        // two errors.  We also allow want to allow unicode characters U+0080 through U+00FF, as\n        // those can fit into a single char value.\n        if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {\n            auto v0 = static_cast<unsigned char>(value[0]);\n            // low bits only: 0-127\n            // 0b110xxxxx - start of 2-byte sequence\n            // 0b1110xxxx - start of 3-byte sequence\n            // 0b11110xxx - start of 4-byte sequence\n            size_t char0_bytes = (v0 & 0x80) == 0      ? 1\n                                 : (v0 & 0xE0) == 0xC0 ? 2\n                                 : (v0 & 0xF0) == 0xE0 ? 3\n                                                       : 4;\n\n            if (char0_bytes == str_len) {\n                // If we have a 128-255 value, we can decode it into a single char:\n                if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx\n                    one_char = static_cast<CharT>(((v0 & 3) << 6)\n                                                  + (static_cast<unsigned char>(value[1]) & 0x3F));\n                    return one_char;\n                }\n                // Otherwise we have a single character, but it's > U+00FF\n                throw value_error(\"Character code point not in range(0x100)\");\n            }\n        }\n\n        // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a\n        // surrogate pair with total length 2 instantly indicates a range error (but not a \"your\n        // string was too long\" error).\n        else if (StringCaster::UTF_N == 16 && str_len == 2) {\n            one_char = static_cast<CharT>(value[0]);\n            if (one_char >= 0xD800 && one_char < 0xE000) {\n                throw value_error(\"Character code point not in range(0x10000)\");\n            }\n        }\n\n        if (str_len != 1) {\n            throw value_error(\"Expected a character, but multi-character string found\");\n        }\n\n        one_char = value[0];\n        return one_char;\n    }\n\n    static constexpr auto name = const_name(PYBIND11_STRING_NAME);\n    template <typename _T>\n    using cast_op_type = pybind11::detail::cast_op_type<_T>;\n};\n\n// Base implementation for std::tuple and std::pair\ntemplate <template <typename...> class Tuple, typename... Ts>\nclass tuple_caster {\n    using type = Tuple<Ts...>;\n    static constexpr auto size = sizeof...(Ts);\n    using indices = make_index_sequence<size>;\n\npublic:\n    bool load(handle src, bool convert) {\n        if (!isinstance<sequence>(src)) {\n            return false;\n        }\n        const auto seq = reinterpret_borrow<sequence>(src);\n        if (seq.size() != size) {\n            return false;\n        }\n        return load_impl(seq, convert, indices{});\n    }\n\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        return cast_impl(std::forward<T>(src), policy, parent, indices{});\n    }\n\n    // copied from the PYBIND11_TYPE_CASTER macro\n    template <typename T>\n    static handle cast(T *src, return_value_policy policy, handle parent) {\n        if (!src) {\n            return none().release();\n        }\n        if (policy == return_value_policy::take_ownership) {\n            auto h = cast(std::move(*src), policy, parent);\n            delete src;\n            return h;\n        }\n        return cast(*src, policy, parent);\n    }\n\n    static constexpr auto name = const_name(\"tuple[\")\n                                 + ::pybind11::detail::concat(make_caster<Ts>::name...)\n                                 + const_name(\"]\");\n\n    template <typename T>\n    using cast_op_type = type;\n\n    explicit operator type() & { return implicit_cast(indices{}); }\n    explicit operator type() && { return std::move(*this).implicit_cast(indices{}); }\n\nprotected:\n    template <size_t... Is>\n    type implicit_cast(index_sequence<Is...>) & {\n        return type(cast_op<Ts>(std::get<Is>(subcasters))...);\n    }\n    template <size_t... Is>\n    type implicit_cast(index_sequence<Is...>) && {\n        return type(cast_op<Ts>(std::move(std::get<Is>(subcasters)))...);\n    }\n\n    static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }\n\n    template <size_t... Is>\n    bool load_impl(const sequence &seq, bool convert, index_sequence<Is...>) {\n#ifdef __cpp_fold_expressions\n        if ((... || !std::get<Is>(subcasters).load(seq[Is], convert))) {\n            return false;\n        }\n#else\n        for (bool r : {std::get<Is>(subcasters).load(seq[Is], convert)...}) {\n            if (!r) {\n                return false;\n            }\n        }\n#endif\n        return true;\n    }\n\n    /* Implementation: Convert a C++ tuple into a Python tuple */\n    template <typename T, size_t... Is>\n    static handle\n    cast_impl(T &&src, return_value_policy policy, handle parent, index_sequence<Is...>) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(src, policy, parent);\n        PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(policy, parent);\n        std::array<object, size> entries{{reinterpret_steal<object>(\n            make_caster<Ts>::cast(std::get<Is>(std::forward<T>(src)), policy, parent))...}};\n        for (const auto &entry : entries) {\n            if (!entry) {\n                return handle();\n            }\n        }\n        tuple result(size);\n        int counter = 0;\n        for (auto &entry : entries) {\n            PyTuple_SET_ITEM(result.ptr(), counter++, entry.release().ptr());\n        }\n        return result.release();\n    }\n\n    Tuple<make_caster<Ts>...> subcasters;\n};\n\ntemplate <typename T1, typename T2>\nclass type_caster<std::pair<T1, T2>> : public tuple_caster<std::pair, T1, T2> {};\n\ntemplate <typename... Ts>\nclass type_caster<std::tuple<Ts...>> : public tuple_caster<std::tuple, Ts...> {};\n\n/// Helper class which abstracts away certain actions. Users can provide specializations for\n/// custom holders, but it's only necessary if the type has a non-standard interface.\ntemplate <typename T>\nstruct holder_helper {\n    static auto get(const T &p) -> decltype(p.get()) { return p.get(); }\n};\n\n/// Type caster for holder types like std::shared_ptr, etc.\n/// The SFINAE hook is provided to help work around the current lack of support\n/// for smart-pointer interoperability. Please consider it an implementation\n/// detail that may change in the future, as formal support for smart-pointer\n/// interoperability is added into pybind11.\ntemplate <typename type, typename holder_type, typename SFINAE = void>\nstruct copyable_holder_caster : public type_caster_base<type> {\npublic:\n    using base = type_caster_base<type>;\n    static_assert(std::is_base_of<base, type_caster<type>>::value,\n                  \"Holder classes are only supported for custom types\");\n    using base::base;\n    using base::cast;\n    using base::typeinfo;\n    using base::value;\n\n    bool load(handle src, bool convert) {\n        return base::template load_impl<copyable_holder_caster<type, holder_type>>(src, convert);\n    }\n\n    explicit operator type *() { return this->value; }\n    // static_cast works around compiler error with MSVC 17 and CUDA 10.2\n    // see issue #2180\n    explicit operator type &() { return *(static_cast<type *>(this->value)); }\n    explicit operator holder_type *() { return std::addressof(holder); }\n    explicit operator holder_type &() { return holder; }\n\n    static handle cast(const holder_type &src, return_value_policy, handle) {\n        const auto *ptr = holder_helper<holder_type>::get(src);\n        return type_caster_base<type>::cast_holder(ptr, &src);\n    }\n\nprotected:\n    friend class type_caster_generic;\n    void check_holder_compat() {\n        if (typeinfo->default_holder) {\n            throw cast_error(\"Unable to load a custom holder type from a default-holder instance\");\n        }\n    }\n\n    bool load_value(value_and_holder &&v_h) {\n        if (v_h.holder_constructed()) {\n            value = v_h.value_ptr();\n            holder = v_h.template holder<holder_type>();\n            return true;\n        }\n        throw cast_error(\"Unable to cast from non-held to held instance (T& to Holder<T>) \"\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                         \"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for \"\n                         \"type information)\");\n#else\n                         \"of type '\"\n                         + type_id<holder_type>() + \"''\");\n#endif\n    }\n\n    template <typename T = holder_type,\n              detail::enable_if_t<!std::is_constructible<T, const T &, type *>::value, int> = 0>\n    bool try_implicit_casts(handle, bool) {\n        return false;\n    }\n\n    template <typename T = holder_type,\n              detail::enable_if_t<std::is_constructible<T, const T &, type *>::value, int> = 0>\n    bool try_implicit_casts(handle src, bool convert) {\n        for (auto &cast : typeinfo->implicit_casts) {\n            copyable_holder_caster sub_caster(*cast.first);\n            if (sub_caster.load(src, convert)) {\n                value = cast.second(sub_caster.value);\n                holder = holder_type(sub_caster.holder, (type *) value);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    static bool try_direct_conversions(handle) { return false; }\n\n    holder_type holder;\n};\n\n/// Specialize for the common std::shared_ptr, so users don't need to\ntemplate <typename T>\nclass type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};\n\n/// Type caster for holder types like std::unique_ptr.\n/// Please consider the SFINAE hook an implementation detail, as explained\n/// in the comment for the copyable_holder_caster.\ntemplate <typename type, typename holder_type, typename SFINAE = void>\nstruct move_only_holder_caster {\n    static_assert(std::is_base_of<type_caster_base<type>, type_caster<type>>::value,\n                  \"Holder classes are only supported for custom types\");\n\n    static handle cast(holder_type &&src, return_value_policy, handle) {\n        auto *ptr = holder_helper<holder_type>::get(src);\n        return type_caster_base<type>::cast_holder(ptr, std::addressof(src));\n    }\n    static constexpr auto name = type_caster_base<type>::name;\n};\n\ntemplate <typename type, typename deleter>\nclass type_caster<std::unique_ptr<type, deleter>>\n    : public move_only_holder_caster<type, std::unique_ptr<type, deleter>> {};\n\ntemplate <typename type, typename holder_type>\nusing type_caster_holder = conditional_t<is_copy_constructible<holder_type>::value,\n                                         copyable_holder_caster<type, holder_type>,\n                                         move_only_holder_caster<type, holder_type>>;\n\ntemplate <typename T, bool Value = false>\nstruct always_construct_holder {\n    static constexpr bool value = Value;\n};\n\n/// Create a specialization for custom holder types (silently ignores std::shared_ptr)\n#define PYBIND11_DECLARE_HOLDER_TYPE(type, holder_type, ...)                                      \\\n    PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)                                                  \\\n    namespace detail {                                                                            \\\n    template <typename type>                                                                      \\\n    struct always_construct_holder<holder_type> : always_construct_holder<void, ##__VA_ARGS__> {  \\\n    };                                                                                            \\\n    template <typename type>                                                                      \\\n    class type_caster<holder_type, enable_if_t<!is_shared_ptr<holder_type>::value>>               \\\n        : public type_caster_holder<type, holder_type> {};                                        \\\n    }                                                                                             \\\n    PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n\n// PYBIND11_DECLARE_HOLDER_TYPE holder types:\ntemplate <typename base, typename holder>\nstruct is_holder_type\n    : std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};\n// Specialization for always-supported unique_ptr holders:\ntemplate <typename base, typename deleter>\nstruct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};\n\n#ifdef PYBIND11_DISABLE_HANDLE_TYPE_NAME_DEFAULT_IMPLEMENTATION // See PR #4888\n\n// This leads to compilation errors if a specialization is missing.\ntemplate <typename T>\nstruct handle_type_name;\n\n#else\n\ntemplate <typename T>\nstruct handle_type_name {\n    static constexpr auto name = const_name<T>();\n};\n\n#endif\n\ntemplate <>\nstruct handle_type_name<object> {\n    static constexpr auto name = const_name(\"object\");\n};\ntemplate <>\nstruct handle_type_name<list> {\n    static constexpr auto name = const_name(\"list\");\n};\ntemplate <>\nstruct handle_type_name<dict> {\n    static constexpr auto name = const_name(\"dict\");\n};\ntemplate <>\nstruct handle_type_name<anyset> {\n    static constexpr auto name = const_name(\"Union[set, frozenset]\");\n};\ntemplate <>\nstruct handle_type_name<set> {\n    static constexpr auto name = const_name(\"set\");\n};\ntemplate <>\nstruct handle_type_name<frozenset> {\n    static constexpr auto name = const_name(\"frozenset\");\n};\ntemplate <>\nstruct handle_type_name<str> {\n    static constexpr auto name = const_name(\"str\");\n};\ntemplate <>\nstruct handle_type_name<tuple> {\n    static constexpr auto name = const_name(\"tuple\");\n};\ntemplate <>\nstruct handle_type_name<bool_> {\n    static constexpr auto name = const_name(\"bool\");\n};\ntemplate <>\nstruct handle_type_name<bytes> {\n    static constexpr auto name = const_name(PYBIND11_BYTES_NAME);\n};\ntemplate <>\nstruct handle_type_name<buffer> {\n    static constexpr auto name = const_name(\"Buffer\");\n};\ntemplate <>\nstruct handle_type_name<int_> {\n    static constexpr auto name = const_name(\"int\");\n};\ntemplate <>\nstruct handle_type_name<iterable> {\n    static constexpr auto name = const_name(\"Iterable\");\n};\ntemplate <>\nstruct handle_type_name<iterator> {\n    static constexpr auto name = const_name(\"Iterator\");\n};\ntemplate <>\nstruct handle_type_name<float_> {\n    static constexpr auto name = const_name(\"float\");\n};\ntemplate <>\nstruct handle_type_name<function> {\n    static constexpr auto name = const_name(\"Callable\");\n};\ntemplate <>\nstruct handle_type_name<handle> {\n    static constexpr auto name = handle_type_name<object>::name;\n};\ntemplate <>\nstruct handle_type_name<none> {\n    static constexpr auto name = const_name(\"None\");\n};\ntemplate <>\nstruct handle_type_name<sequence> {\n    static constexpr auto name = const_name(\"Sequence\");\n};\ntemplate <>\nstruct handle_type_name<bytearray> {\n    static constexpr auto name = const_name(\"bytearray\");\n};\ntemplate <>\nstruct handle_type_name<memoryview> {\n    static constexpr auto name = const_name(\"memoryview\");\n};\ntemplate <>\nstruct handle_type_name<slice> {\n    static constexpr auto name = const_name(\"slice\");\n};\ntemplate <>\nstruct handle_type_name<type> {\n    static constexpr auto name = const_name(\"type\");\n};\ntemplate <>\nstruct handle_type_name<capsule> {\n    static constexpr auto name = const_name(\"capsule\");\n};\ntemplate <>\nstruct handle_type_name<ellipsis> {\n    static constexpr auto name = const_name(\"ellipsis\");\n};\ntemplate <>\nstruct handle_type_name<weakref> {\n    static constexpr auto name = const_name(\"weakref\");\n};\ntemplate <>\nstruct handle_type_name<args> {\n    static constexpr auto name = const_name(\"*args\");\n};\ntemplate <>\nstruct handle_type_name<kwargs> {\n    static constexpr auto name = const_name(\"**kwargs\");\n};\ntemplate <>\nstruct handle_type_name<obj_attr_accessor> {\n    static constexpr auto name = const_name<obj_attr_accessor>();\n};\ntemplate <>\nstruct handle_type_name<str_attr_accessor> {\n    static constexpr auto name = const_name<str_attr_accessor>();\n};\ntemplate <>\nstruct handle_type_name<item_accessor> {\n    static constexpr auto name = const_name<item_accessor>();\n};\ntemplate <>\nstruct handle_type_name<sequence_accessor> {\n    static constexpr auto name = const_name<sequence_accessor>();\n};\ntemplate <>\nstruct handle_type_name<list_accessor> {\n    static constexpr auto name = const_name<list_accessor>();\n};\ntemplate <>\nstruct handle_type_name<tuple_accessor> {\n    static constexpr auto name = const_name<tuple_accessor>();\n};\n\ntemplate <typename type>\nstruct pyobject_caster {\n    template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>\n    pyobject_caster() : value() {}\n\n    // `type` may not be default constructible (e.g. frozenset, anyset).  Initializing `value`\n    // to a nil handle is safe since it will only be accessed if `load` succeeds.\n    template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>\n    pyobject_caster() : value(reinterpret_steal<type>(handle())) {}\n\n    template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>\n    bool load(handle src, bool /* convert */) {\n        value = src;\n        return static_cast<bool>(value);\n    }\n\n    template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>\n    bool load(handle src, bool /* convert */) {\n        if (!isinstance<type>(src)) {\n            return false;\n        }\n        value = reinterpret_borrow<type>(src);\n        return true;\n    }\n\n    static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {\n        return src.inc_ref();\n    }\n    PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);\n};\n\ntemplate <typename T>\nclass type_caster<T, enable_if_t<is_pyobject<T>::value>> : public pyobject_caster<T> {};\n\n// Our conditions for enabling moving are quite restrictive:\n// At compile time:\n// - T needs to be a non-const, non-pointer, non-reference type\n// - type_caster<T>::operator T&() must exist\n// - the type must be move constructible (obviously)\n// At run-time:\n// - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it\n//   must have ref_count() == 1)h\n// If any of the above are not satisfied, we fall back to copying.\ntemplate <typename T>\nusing move_is_plain_type\n    = satisfies_none_of<T, std::is_void, std::is_pointer, std::is_reference, std::is_const>;\ntemplate <typename T, typename SFINAE = void>\nstruct move_always : std::false_type {};\ntemplate <typename T>\nstruct move_always<\n    T,\n    enable_if_t<\n        all_of<move_is_plain_type<T>,\n               negation<is_copy_constructible<T>>,\n               is_move_constructible<T>,\n               std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>\n    : std::true_type {};\ntemplate <typename T, typename SFINAE = void>\nstruct move_if_unreferenced : std::false_type {};\ntemplate <typename T>\nstruct move_if_unreferenced<\n    T,\n    enable_if_t<\n        all_of<move_is_plain_type<T>,\n               negation<move_always<T>>,\n               is_move_constructible<T>,\n               std::is_same<decltype(std::declval<make_caster<T>>().operator T &()), T &>>::value>>\n    : std::true_type {};\ntemplate <typename T>\nusing move_never = none_of<move_always<T>, move_if_unreferenced<T>>;\n\n// Detect whether returning a `type` from a cast on type's type_caster is going to result in a\n// reference or pointer to a local variable of the type_caster.  Basically, only\n// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;\n// everything else returns a reference/pointer to a local variable.\ntemplate <typename type>\nusing cast_is_temporary_value_reference\n    = bool_constant<(std::is_reference<type>::value || std::is_pointer<type>::value)\n                    && !std::is_base_of<type_caster_generic, make_caster<type>>::value\n                    && !std::is_same<intrinsic_t<type>, void>::value>;\n\n// When a value returned from a C++ function is being cast back to Python, we almost always want to\n// force `policy = move`, regardless of the return value policy the function/method was declared\n// with.\ntemplate <typename Return, typename SFINAE = void>\nstruct return_value_policy_override {\n    static return_value_policy policy(return_value_policy p) { return p; }\n};\n\ntemplate <typename Return>\nstruct return_value_policy_override<\n    Return,\n    detail::enable_if_t<std::is_base_of<type_caster_generic, make_caster<Return>>::value, void>> {\n    static return_value_policy policy(return_value_policy p) {\n        return !std::is_lvalue_reference<Return>::value && !std::is_pointer<Return>::value\n                   ? return_value_policy::move\n                   : p;\n    }\n};\n\n// Basic python -> C++ casting; throws if casting fails\ntemplate <typename T, typename SFINAE>\ntype_caster<T, SFINAE> &load_type(type_caster<T, SFINAE> &conv, const handle &handle) {\n    static_assert(!detail::is_pyobject<T>::value,\n                  \"Internal error: type_caster should only be used for C++ types\");\n    if (!conv.load(handle, true)) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n        throw cast_error(\n            \"Unable to cast Python instance of type \"\n            + str(type::handle_of(handle)).cast<std::string>()\n            + \" to C++ type '?' (#define \"\n              \"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)\");\n#else\n        throw cast_error(\"Unable to cast Python instance of type \"\n                         + str(type::handle_of(handle)).cast<std::string>() + \" to C++ type '\"\n                         + type_id<T>() + \"'\");\n#endif\n    }\n    return conv;\n}\n// Wrapper around the above that also constructs and returns a type_caster\ntemplate <typename T>\nmake_caster<T> load_type(const handle &handle) {\n    make_caster<T> conv;\n    load_type(conv, handle);\n    return conv;\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n// pytype -> C++ type\ntemplate <typename T,\n          detail::enable_if_t<!detail::is_pyobject<T>::value\n                                  && !detail::is_same_ignoring_cvref<T, PyObject *>::value,\n                              int>\n          = 0>\nT cast(const handle &handle) {\n    using namespace detail;\n    static_assert(!cast_is_temporary_value_reference<T>::value,\n                  \"Unable to cast type to reference: value is local to type caster\");\n    return cast_op<T>(load_type<T>(handle));\n}\n\n// pytype -> pytype (calls converting constructor)\ntemplate <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>\nT cast(const handle &handle) {\n    return T(reinterpret_borrow<object>(handle));\n}\n\n// Note that `cast<PyObject *>(obj)` increments the reference count of `obj`.\n// This is necessary for the case that `obj` is a temporary, and could\n// not possibly be different, given\n// 1. the established convention that the passed `handle` is borrowed, and\n// 2. we don't want to force all generic code using `cast<T>()` to special-case\n//    handling of `T` = `PyObject *` (to increment the reference count there).\n// It is the responsibility of the caller to ensure that the reference count\n// is decremented.\ntemplate <typename T,\n          typename Handle,\n          detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value\n                                  && detail::is_same_ignoring_cvref<Handle, handle>::value,\n                              int>\n          = 0>\nT cast(Handle &&handle) {\n    return handle.inc_ref().ptr();\n}\n// To optimize way an inc_ref/dec_ref cycle:\ntemplate <typename T,\n          typename Object,\n          detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value\n                                  && detail::is_same_ignoring_cvref<Object, object>::value,\n                              int>\n          = 0>\nT cast(Object &&obj) {\n    return obj.release().ptr();\n}\n\n// C++ type -> py::object\ntemplate <typename T, detail::enable_if_t<!detail::is_pyobject<T>::value, int> = 0>\nobject cast(T &&value,\n            return_value_policy policy = return_value_policy::automatic_reference,\n            handle parent = handle()) {\n    using no_ref_T = typename std::remove_reference<T>::type;\n    if (policy == return_value_policy::automatic) {\n        policy = std::is_pointer<no_ref_T>::value     ? return_value_policy::take_ownership\n                 : std::is_lvalue_reference<T>::value ? return_value_policy::copy\n                                                      : return_value_policy::move;\n    } else if (policy == return_value_policy::automatic_reference) {\n        policy = std::is_pointer<no_ref_T>::value     ? return_value_policy::reference\n                 : std::is_lvalue_reference<T>::value ? return_value_policy::copy\n                                                      : return_value_policy::move;\n    }\n    return reinterpret_steal<object>(\n        detail::make_caster<T>::cast(std::forward<T>(value), policy, parent));\n}\n\ntemplate <typename T>\nT handle::cast() const {\n    return pybind11::cast<T>(*this);\n}\ntemplate <>\ninline void handle::cast() const {\n    return;\n}\n\ntemplate <typename T>\ndetail::enable_if_t<!detail::move_never<T>::value, T> move(object &&obj) {\n    if (obj.ref_count() > 1) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n        throw cast_error(\n            \"Unable to cast Python \" + str(type::handle_of(obj)).cast<std::string>()\n            + \" instance to C++ rvalue: instance has multiple references\"\n              \" (#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)\");\n#else\n        throw cast_error(\"Unable to move from Python \"\n                         + str(type::handle_of(obj)).cast<std::string>() + \" instance to C++ \"\n                         + type_id<T>() + \" instance: instance has multiple references\");\n#endif\n    }\n\n    // Move into a temporary and return that, because the reference may be a local value of `conv`\n    T ret = std::move(detail::load_type<T>(obj).operator T &());\n    return ret;\n}\n\n// Calling cast() on an rvalue calls pybind11::cast with the object rvalue, which does:\n// - If we have to move (because T has no copy constructor), do it.  This will fail if the moved\n//   object has multiple references, but trying to copy will fail to compile.\n// - If both movable and copyable, check ref count: if 1, move; otherwise copy\n// - Otherwise (not movable), copy.\ntemplate <typename T>\ndetail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_always<T>::value, T>\ncast(object &&object) {\n    return move<T>(std::move(object));\n}\ntemplate <typename T>\ndetail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_if_unreferenced<T>::value, T>\ncast(object &&object) {\n    if (object.ref_count() > 1) {\n        return cast<T>(object);\n    }\n    return move<T>(std::move(object));\n}\ntemplate <typename T>\ndetail::enable_if_t<!detail::is_pyobject<T>::value && detail::move_never<T>::value, T>\ncast(object &&object) {\n    return cast<T>(object);\n}\n\n// pytype rvalue -> pytype (calls converting constructor)\ntemplate <typename T>\ndetail::enable_if_t<detail::is_pyobject<T>::value, T> cast(object &&object) {\n    return T(std::move(object));\n}\n\ntemplate <typename T>\nT object::cast() const & {\n    return pybind11::cast<T>(*this);\n}\ntemplate <typename T>\nT object::cast() && {\n    return pybind11::cast<T>(std::move(*this));\n}\ntemplate <>\ninline void object::cast() const & {\n    return;\n}\ntemplate <>\ninline void object::cast() && {\n    return;\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Declared in pytypes.h:\ntemplate <typename T, enable_if_t<!is_pyobject<T>::value, int>>\nobject object_or_cast(T &&o) {\n    return pybind11::cast(std::forward<T>(o));\n}\n\n// Placeholder type for the unneeded (and dead code) static variable in the\n// PYBIND11_OVERRIDE_OVERRIDE macro\nstruct override_unused {};\ntemplate <typename ret_type>\nusing override_caster_t = conditional_t<cast_is_temporary_value_reference<ret_type>::value,\n                                        make_caster<ret_type>,\n                                        override_unused>;\n\n// Trampoline use: for reference/pointer types to value-converted values, we do a value cast, then\n// store the result in the given variable.  For other types, this is a no-op.\ntemplate <typename T>\nenable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&o,\n                                                                     make_caster<T> &caster) {\n    return cast_op<T>(load_type(caster, o));\n}\ntemplate <typename T>\nenable_if_t<!cast_is_temporary_value_reference<T>::value, T> cast_ref(object &&,\n                                                                      override_unused &) {\n    pybind11_fail(\"Internal error: cast_ref fallback invoked\");\n}\n\n// Trampoline use: Having a pybind11::cast with an invalid reference type is going to\n// static_assert, even though if it's in dead code, so we provide a \"trampoline\" to pybind11::cast\n// that only does anything in cases where pybind11::cast is valid.\ntemplate <typename T>\nenable_if_t<cast_is_temporary_value_reference<T>::value, T> cast_safe(object &&) {\n    pybind11_fail(\"Internal error: cast_safe fallback invoked\");\n}\ntemplate <typename T>\nenable_if_t<std::is_void<T>::value, void> cast_safe(object &&) {}\ntemplate <typename T>\nenable_if_t<detail::none_of<cast_is_temporary_value_reference<T>, std::is_void<T>>::value, T>\ncast_safe(object &&o) {\n    return pybind11::cast<T>(std::move(o));\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n// The overloads could coexist, i.e. the #if is not strictly speaking needed,\n// but it is an easy minor optimization.\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\ninline cast_error cast_error_unable_to_convert_call_arg(const std::string &name) {\n    return cast_error(\"Unable to convert call argument '\" + name\n                      + \"' to Python object (#define \"\n                        \"PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)\");\n}\n#else\ninline cast_error cast_error_unable_to_convert_call_arg(const std::string &name,\n                                                        const std::string &type) {\n    return cast_error(\"Unable to convert call argument '\" + name + \"' of type '\" + type\n                      + \"' to Python object\");\n}\n#endif\n\ntemplate <return_value_policy policy = return_value_policy::automatic_reference>\ntuple make_tuple() {\n    return tuple(0);\n}\n\ntemplate <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>\ntuple make_tuple(Args &&...args_) {\n    constexpr size_t size = sizeof...(Args);\n    std::array<object, size> args{{reinterpret_steal<object>(\n        detail::make_caster<Args>::cast(std::forward<Args>(args_), policy, nullptr))...}};\n    for (size_t i = 0; i < args.size(); i++) {\n        if (!args[i]) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            throw cast_error_unable_to_convert_call_arg(std::to_string(i));\n#else\n            std::array<std::string, size> argtypes{{type_id<Args>()...}};\n            throw cast_error_unable_to_convert_call_arg(std::to_string(i), argtypes[i]);\n#endif\n        }\n    }\n    tuple result(size);\n    int counter = 0;\n    for (auto &arg_value : args) {\n        PyTuple_SET_ITEM(result.ptr(), counter++, arg_value.release().ptr());\n    }\n    return result;\n}\n\n/// \\ingroup annotations\n/// Annotation for arguments\nstruct arg {\n    /// Constructs an argument with the name of the argument; if null or omitted, this is a\n    /// positional argument.\n    constexpr explicit arg(const char *name = nullptr)\n        : name(name), flag_noconvert(false), flag_none(true) {}\n    /// Assign a value to this argument\n    template <typename T>\n    arg_v operator=(T &&value) const;\n    /// Indicate that the type should not be converted in the type caster\n    arg &noconvert(bool flag = true) {\n        flag_noconvert = flag;\n        return *this;\n    }\n    /// Indicates that the argument should/shouldn't allow None (e.g. for nullable pointer args)\n    arg &none(bool flag = true) {\n        flag_none = flag;\n        return *this;\n    }\n\n    const char *name;        ///< If non-null, this is a named kwargs argument\n    bool flag_noconvert : 1; ///< If set, do not allow conversion (requires a supporting type\n                             ///< caster!)\n    bool flag_none : 1;      ///< If set (the default), allow None to be passed to this argument\n};\n\n/// \\ingroup annotations\n/// Annotation for arguments with values\nstruct arg_v : arg {\nprivate:\n    template <typename T>\n    arg_v(arg &&base, T &&x, const char *descr = nullptr)\n        : arg(base), value(reinterpret_steal<object>(detail::make_caster<T>::cast(\n                         std::forward<T>(x), return_value_policy::automatic, {}))),\n          descr(descr)\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n          ,\n          type(type_id<T>())\n#endif\n    {\n        // Workaround! See:\n        // https://github.com/pybind/pybind11/issues/2336\n        // https://github.com/pybind/pybind11/pull/2685#issuecomment-731286700\n        if (PyErr_Occurred()) {\n            PyErr_Clear();\n        }\n    }\n\npublic:\n    /// Direct construction with name, default, and description\n    template <typename T>\n    arg_v(const char *name, T &&x, const char *descr = nullptr)\n        : arg_v(arg(name), std::forward<T>(x), descr) {}\n\n    /// Called internally when invoking `py::arg(\"a\") = value`\n    template <typename T>\n    arg_v(const arg &base, T &&x, const char *descr = nullptr)\n        : arg_v(arg(base), std::forward<T>(x), descr) {}\n\n    /// Same as `arg::noconvert()`, but returns *this as arg_v&, not arg&\n    arg_v &noconvert(bool flag = true) {\n        arg::noconvert(flag);\n        return *this;\n    }\n\n    /// Same as `arg::nonone()`, but returns *this as arg_v&, not arg&\n    arg_v &none(bool flag = true) {\n        arg::none(flag);\n        return *this;\n    }\n\n    /// The default value\n    object value;\n    /// The (optional) description of the default value\n    const char *descr;\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n    /// The C++ type name of the default value (only available when compiled in debug mode)\n    std::string type;\n#endif\n};\n\n/// \\ingroup annotations\n/// Annotation indicating that all following arguments are keyword-only; the is the equivalent of\n/// an unnamed '*' argument\nstruct kw_only {};\n\n/// \\ingroup annotations\n/// Annotation indicating that all previous arguments are positional-only; the is the equivalent of\n/// an unnamed '/' argument (in Python 3.8)\nstruct pos_only {};\n\ntemplate <typename T>\narg_v arg::operator=(T &&value) const {\n    return {*this, std::forward<T>(value)};\n}\n\n/// Alias for backward compatibility -- to be removed in version 2.0\ntemplate <typename /*unused*/>\nusing arg_t = arg_v;\n\ninline namespace literals {\n/** \\rst\n    String literal version of `arg`\n \\endrst */\nconstexpr arg\n#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5\noperator\"\" _a // gcc 4.8.5 insists on having a space (hard error).\n#else\noperator\"\"_a // clang 17 generates a deprecation warning if there is a space.\n#endif\n    (const char *name, size_t) {\n    return arg(name);\n}\n} // namespace literals\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename T>\nusing is_kw_only = std::is_same<intrinsic_t<T>, kw_only>;\ntemplate <typename T>\nusing is_pos_only = std::is_same<intrinsic_t<T>, pos_only>;\n\n// forward declaration (definition in attr.h)\nstruct function_record;\n\n/// Internal data associated with a single function call\nstruct function_call {\n    function_call(const function_record &f, handle p); // Implementation in attr.h\n\n    /// The function data:\n    const function_record &func;\n\n    /// Arguments passed to the function:\n    std::vector<handle> args;\n\n    /// The `convert` value the arguments should be loaded with\n    std::vector<bool> args_convert;\n\n    /// Extra references for the optional `py::args` and/or `py::kwargs` arguments (which, if\n    /// present, are also in `args` but without a reference).\n    object args_ref, kwargs_ref;\n\n    /// The parent, if any\n    handle parent;\n\n    /// If this is a call to an initializer, this argument contains `self`\n    handle init_self;\n};\n\n/// Helper class which loads arguments for C++ functions called from Python\ntemplate <typename... Args>\nclass argument_loader {\n    using indices = make_index_sequence<sizeof...(Args)>;\n\n    template <typename Arg>\n    using argument_is_args = std::is_same<intrinsic_t<Arg>, args>;\n    template <typename Arg>\n    using argument_is_kwargs = std::is_same<intrinsic_t<Arg>, kwargs>;\n    // Get kwargs argument position, or -1 if not present:\n    static constexpr auto kwargs_pos = constexpr_last<argument_is_kwargs, Args...>();\n\n    static_assert(kwargs_pos == -1 || kwargs_pos == (int) sizeof...(Args) - 1,\n                  \"py::kwargs is only permitted as the last argument of a function\");\n\npublic:\n    static constexpr bool has_kwargs = kwargs_pos != -1;\n\n    // py::args argument position; -1 if not present.\n    static constexpr int args_pos = constexpr_last<argument_is_args, Args...>();\n\n    static_assert(args_pos == -1 || args_pos == constexpr_first<argument_is_args, Args...>(),\n                  \"py::args cannot be specified more than once\");\n\n    static constexpr auto arg_names\n        = ::pybind11::detail::concat(type_descr(make_caster<Args>::name)...);\n\n    bool load_args(function_call &call) { return load_impl_sequence(call, indices{}); }\n\n    template <typename Return, typename Guard, typename Func>\n    // NOLINTNEXTLINE(readability-const-return-type)\n    enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {\n        return std::move(*this).template call_impl<remove_cv_t<Return>>(\n            std::forward<Func>(f), indices{}, Guard{});\n    }\n\n    template <typename Return, typename Guard, typename Func>\n    enable_if_t<std::is_void<Return>::value, void_type> call(Func &&f) && {\n        std::move(*this).template call_impl<remove_cv_t<Return>>(\n            std::forward<Func>(f), indices{}, Guard{});\n        return void_type();\n    }\n\nprivate:\n    static bool load_impl_sequence(function_call &, index_sequence<>) { return true; }\n\n    template <size_t... Is>\n    bool load_impl_sequence(function_call &call, index_sequence<Is...>) {\n#ifdef __cpp_fold_expressions\n        if ((... || !std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is]))) {\n            return false;\n        }\n#else\n        for (bool r : {std::get<Is>(argcasters).load(call.args[Is], call.args_convert[Is])...}) {\n            if (!r) {\n                return false;\n            }\n        }\n#endif\n        return true;\n    }\n\n    template <typename Return, typename Func, size_t... Is, typename Guard>\n    Return call_impl(Func &&f, index_sequence<Is...>, Guard &&) && {\n        return std::forward<Func>(f)(cast_op<Args>(std::move(std::get<Is>(argcasters)))...);\n    }\n\n    std::tuple<make_caster<Args>...> argcasters;\n};\n\n/// Helper class which collects only positional arguments for a Python function call.\n/// A fancier version below can collect any argument, but this one is optimal for simple calls.\ntemplate <return_value_policy policy>\nclass simple_collector {\npublic:\n    template <typename... Ts>\n    explicit simple_collector(Ts &&...values)\n        : m_args(pybind11::make_tuple<policy>(std::forward<Ts>(values)...)) {}\n\n    const tuple &args() const & { return m_args; }\n    dict kwargs() const { return {}; }\n\n    tuple args() && { return std::move(m_args); }\n\n    /// Call a Python function and pass the collected arguments\n    object call(PyObject *ptr) const {\n        PyObject *result = PyObject_CallObject(ptr, m_args.ptr());\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<object>(result);\n    }\n\nprivate:\n    tuple m_args;\n};\n\n/// Helper class which collects positional, keyword, * and ** arguments for a Python function call\ntemplate <return_value_policy policy>\nclass unpacking_collector {\npublic:\n    template <typename... Ts>\n    explicit unpacking_collector(Ts &&...values) {\n        // Tuples aren't (easily) resizable so a list is needed for collection,\n        // but the actual function call strictly requires a tuple.\n        auto args_list = list();\n        using expander = int[];\n        (void) expander{0, (process(args_list, std::forward<Ts>(values)), 0)...};\n\n        m_args = std::move(args_list);\n    }\n\n    const tuple &args() const & { return m_args; }\n    const dict &kwargs() const & { return m_kwargs; }\n\n    tuple args() && { return std::move(m_args); }\n    dict kwargs() && { return std::move(m_kwargs); }\n\n    /// Call a Python function and pass the collected arguments\n    object call(PyObject *ptr) const {\n        PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr());\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<object>(result);\n    }\n\nprivate:\n    template <typename T>\n    void process(list &args_list, T &&x) {\n        auto o = reinterpret_steal<object>(\n            detail::make_caster<T>::cast(std::forward<T>(x), policy, {}));\n        if (!o) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()));\n#else\n            throw cast_error_unable_to_convert_call_arg(std::to_string(args_list.size()),\n                                                        type_id<T>());\n#endif\n        }\n        args_list.append(std::move(o));\n    }\n\n    void process(list &args_list, detail::args_proxy ap) {\n        for (auto a : ap) {\n            args_list.append(a);\n        }\n    }\n\n    void process(list & /*args_list*/, arg_v a) {\n        if (!a.name) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            nameless_argument_error();\n#else\n            nameless_argument_error(a.type);\n#endif\n        }\n        if (m_kwargs.contains(a.name)) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            multiple_values_error();\n#else\n            multiple_values_error(a.name);\n#endif\n        }\n        if (!a.value) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            throw cast_error_unable_to_convert_call_arg(a.name);\n#else\n            throw cast_error_unable_to_convert_call_arg(a.name, a.type);\n#endif\n        }\n        m_kwargs[a.name] = std::move(a.value);\n    }\n\n    void process(list & /*args_list*/, detail::kwargs_proxy kp) {\n        if (!kp) {\n            return;\n        }\n        for (auto k : reinterpret_borrow<dict>(kp)) {\n            if (m_kwargs.contains(k.first)) {\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                multiple_values_error();\n#else\n                multiple_values_error(str(k.first));\n#endif\n            }\n            m_kwargs[k.first] = k.second;\n        }\n    }\n\n    [[noreturn]] static void nameless_argument_error() {\n        throw type_error(\n            \"Got kwargs without a name; only named arguments \"\n            \"may be passed via py::arg() to a python function call. \"\n            \"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)\");\n    }\n    [[noreturn]] static void nameless_argument_error(const std::string &type) {\n        throw type_error(\"Got kwargs without a name of type '\" + type\n                         + \"'; only named \"\n                           \"arguments may be passed via py::arg() to a python function call. \");\n    }\n    [[noreturn]] static void multiple_values_error() {\n        throw type_error(\n            \"Got multiple values for keyword argument \"\n            \"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for details)\");\n    }\n\n    [[noreturn]] static void multiple_values_error(const std::string &name) {\n        throw type_error(\"Got multiple values for keyword argument '\" + name + \"'\");\n    }\n\nprivate:\n    tuple m_args;\n    dict m_kwargs;\n};\n\n// [workaround(intel)] Separate function required here\n// We need to put this into a separate function because the Intel compiler\n// fails to compile enable_if_t<!all_of<is_positional<Args>...>::value>\n// (tested with ICC 2021.1 Beta 20200827).\ntemplate <typename... Args>\nconstexpr bool args_are_all_positional() {\n    return all_of<is_positional<Args>...>::value;\n}\n\n/// Collect only positional arguments for a Python function call\ntemplate <return_value_policy policy,\n          typename... Args,\n          typename = enable_if_t<args_are_all_positional<Args...>()>>\nsimple_collector<policy> collect_arguments(Args &&...args) {\n    return simple_collector<policy>(std::forward<Args>(args)...);\n}\n\n/// Collect all arguments, including keywords and unpacking (only instantiated when needed)\ntemplate <return_value_policy policy,\n          typename... Args,\n          typename = enable_if_t<!args_are_all_positional<Args...>()>>\nunpacking_collector<policy> collect_arguments(Args &&...args) {\n    // Following argument order rules for generalized unpacking according to PEP 448\n    static_assert(constexpr_last<is_positional, Args...>()\n                          < constexpr_first<is_keyword_or_ds, Args...>()\n                      && constexpr_last<is_s_unpacking, Args...>()\n                             < constexpr_first<is_ds_unpacking, Args...>(),\n                  \"Invalid function call: positional args must precede keywords and ** unpacking; \"\n                  \"* unpacking must precede ** unpacking\");\n    return unpacking_collector<policy>(std::forward<Args>(args)...);\n}\n\ntemplate <typename Derived>\ntemplate <return_value_policy policy, typename... Args>\nobject object_api<Derived>::operator()(Args &&...args) const {\n#ifndef NDEBUG\n    if (!PyGILState_Check()) {\n        pybind11_fail(\"pybind11::object_api<>::operator() PyGILState_Check() failure.\");\n    }\n#endif\n    return detail::collect_arguments<policy>(std::forward<Args>(args)...).call(derived().ptr());\n}\n\ntemplate <typename Derived>\ntemplate <return_value_policy policy, typename... Args>\nobject object_api<Derived>::call(Args &&...args) const {\n    return operator()<policy>(std::forward<Args>(args)...);\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\ntemplate <typename T>\nhandle type::handle_of() {\n    static_assert(std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,\n                  \"py::type::of<T> only supports the case where T is a registered C++ types.\");\n\n    return detail::get_type_handle(typeid(T), true);\n}\n\n#define PYBIND11_MAKE_OPAQUE(...)                                                                 \\\n    PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)                                                  \\\n    namespace detail {                                                                            \\\n    template <>                                                                                   \\\n    class type_caster<__VA_ARGS__> : public type_caster_base<__VA_ARGS__> {};                     \\\n    }                                                                                             \\\n    PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n\n/// Lets you pass a type containing a `,` through a macro parameter without needing a separate\n/// typedef, e.g.:\n/// `PYBIND11_OVERRIDE(PYBIND11_TYPE(ReturnType<A, B>), PYBIND11_TYPE(Parent<C, D>), f, arg)`\n#define PYBIND11_TYPE(...) __VA_ARGS__\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/chrono.h",
    "content": "/*\n    pybind11/chrono.h: Transparent conversion between std::chrono and python's datetime\n\n    Copyright (c) 2016 Trent Houliston <trent@houliston.me> and\n                       Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\n#include <chrono>\n#include <cmath>\n#include <ctime>\n#include <datetime.h>\n#include <mutex>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename type>\nclass duration_caster {\npublic:\n    using rep = typename type::rep;\n    using period = typename type::period;\n\n    // signed 25 bits required by the standard.\n    using days = std::chrono::duration<int_least32_t, std::ratio<86400>>;\n\n    bool load(handle src, bool) {\n        using namespace std::chrono;\n\n        // Lazy initialise the PyDateTime import\n        if (!PyDateTimeAPI) {\n            PyDateTime_IMPORT;\n        }\n\n        if (!src) {\n            return false;\n        }\n        // If invoked with datetime.delta object\n        if (PyDelta_Check(src.ptr())) {\n            value = type(duration_cast<duration<rep, period>>(\n                days(PyDateTime_DELTA_GET_DAYS(src.ptr()))\n                + seconds(PyDateTime_DELTA_GET_SECONDS(src.ptr()))\n                + microseconds(PyDateTime_DELTA_GET_MICROSECONDS(src.ptr()))));\n            return true;\n        }\n        // If invoked with a float we assume it is seconds and convert\n        if (PyFloat_Check(src.ptr())) {\n            value = type(duration_cast<duration<rep, period>>(\n                duration<double>(PyFloat_AsDouble(src.ptr()))));\n            return true;\n        }\n        return false;\n    }\n\n    // If this is a duration just return it back\n    static const std::chrono::duration<rep, period> &\n    get_duration(const std::chrono::duration<rep, period> &src) {\n        return src;\n    }\n\n    // If this is a time_point get the time_since_epoch\n    template <typename Clock>\n    static std::chrono::duration<rep, period>\n    get_duration(const std::chrono::time_point<Clock, std::chrono::duration<rep, period>> &src) {\n        return src.time_since_epoch();\n    }\n\n    static handle cast(const type &src, return_value_policy /* policy */, handle /* parent */) {\n        using namespace std::chrono;\n\n        // Use overloaded function to get our duration from our source\n        // Works out if it is a duration or time_point and get the duration\n        auto d = get_duration(src);\n\n        // Lazy initialise the PyDateTime import\n        if (!PyDateTimeAPI) {\n            PyDateTime_IMPORT;\n        }\n\n        // Declare these special duration types so the conversions happen with the correct\n        // primitive types (int)\n        using dd_t = duration<int, std::ratio<86400>>;\n        using ss_t = duration<int, std::ratio<1>>;\n        using us_t = duration<int, std::micro>;\n\n        auto dd = duration_cast<dd_t>(d);\n        auto subd = d - dd;\n        auto ss = duration_cast<ss_t>(subd);\n        auto us = duration_cast<us_t>(subd - ss);\n        return PyDelta_FromDSU(dd.count(), ss.count(), us.count());\n    }\n\n    PYBIND11_TYPE_CASTER(type, const_name(\"datetime.timedelta\"));\n};\n\ninline std::tm *localtime_thread_safe(const std::time_t *time, std::tm *buf) {\n#if (defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__)) || defined(_MSC_VER)\n    if (localtime_s(buf, time))\n        return nullptr;\n    return buf;\n#else\n    static std::mutex mtx;\n    std::lock_guard<std::mutex> lock(mtx);\n    std::tm *tm_ptr = std::localtime(time);\n    if (tm_ptr != nullptr) {\n        *buf = *tm_ptr;\n    }\n    return tm_ptr;\n#endif\n}\n\n// This is for casting times on the system clock into datetime.datetime instances\ntemplate <typename Duration>\nclass type_caster<std::chrono::time_point<std::chrono::system_clock, Duration>> {\npublic:\n    using type = std::chrono::time_point<std::chrono::system_clock, Duration>;\n    bool load(handle src, bool) {\n        using namespace std::chrono;\n\n        // Lazy initialise the PyDateTime import\n        if (!PyDateTimeAPI) {\n            PyDateTime_IMPORT;\n        }\n\n        if (!src) {\n            return false;\n        }\n\n        std::tm cal;\n        microseconds msecs;\n\n        if (PyDateTime_Check(src.ptr())) {\n            cal.tm_sec = PyDateTime_DATE_GET_SECOND(src.ptr());\n            cal.tm_min = PyDateTime_DATE_GET_MINUTE(src.ptr());\n            cal.tm_hour = PyDateTime_DATE_GET_HOUR(src.ptr());\n            cal.tm_mday = PyDateTime_GET_DAY(src.ptr());\n            cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;\n            cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;\n            cal.tm_isdst = -1;\n            msecs = microseconds(PyDateTime_DATE_GET_MICROSECOND(src.ptr()));\n        } else if (PyDate_Check(src.ptr())) {\n            cal.tm_sec = 0;\n            cal.tm_min = 0;\n            cal.tm_hour = 0;\n            cal.tm_mday = PyDateTime_GET_DAY(src.ptr());\n            cal.tm_mon = PyDateTime_GET_MONTH(src.ptr()) - 1;\n            cal.tm_year = PyDateTime_GET_YEAR(src.ptr()) - 1900;\n            cal.tm_isdst = -1;\n            msecs = microseconds(0);\n        } else if (PyTime_Check(src.ptr())) {\n            cal.tm_sec = PyDateTime_TIME_GET_SECOND(src.ptr());\n            cal.tm_min = PyDateTime_TIME_GET_MINUTE(src.ptr());\n            cal.tm_hour = PyDateTime_TIME_GET_HOUR(src.ptr());\n            cal.tm_mday = 1;  // This date (day, month, year) = (1, 0, 70)\n            cal.tm_mon = 0;   // represents 1-Jan-1970, which is the first\n            cal.tm_year = 70; // earliest available date for Python's datetime\n            cal.tm_isdst = -1;\n            msecs = microseconds(PyDateTime_TIME_GET_MICROSECOND(src.ptr()));\n        } else {\n            return false;\n        }\n\n        value = time_point_cast<Duration>(system_clock::from_time_t(std::mktime(&cal)) + msecs);\n        return true;\n    }\n\n    static handle cast(const std::chrono::time_point<std::chrono::system_clock, Duration> &src,\n                       return_value_policy /* policy */,\n                       handle /* parent */) {\n        using namespace std::chrono;\n\n        // Lazy initialise the PyDateTime import\n        if (!PyDateTimeAPI) {\n            PyDateTime_IMPORT;\n        }\n\n        // Get out microseconds, and make sure they are positive, to avoid bug in eastern\n        // hemisphere time zones (cfr. https://github.com/pybind/pybind11/issues/2417)\n        using us_t = duration<int, std::micro>;\n        auto us = duration_cast<us_t>(src.time_since_epoch() % seconds(1));\n        if (us.count() < 0) {\n            us += seconds(1);\n        }\n\n        // Subtract microseconds BEFORE `system_clock::to_time_t`, because:\n        // > If std::time_t has lower precision, it is implementation-defined whether the value is\n        // rounded or truncated. (https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t)\n        std::time_t tt\n            = system_clock::to_time_t(time_point_cast<system_clock::duration>(src - us));\n\n        std::tm localtime;\n        std::tm *localtime_ptr = localtime_thread_safe(&tt, &localtime);\n        if (!localtime_ptr) {\n            throw cast_error(\"Unable to represent system_clock in local time\");\n        }\n        return PyDateTime_FromDateAndTime(localtime.tm_year + 1900,\n                                          localtime.tm_mon + 1,\n                                          localtime.tm_mday,\n                                          localtime.tm_hour,\n                                          localtime.tm_min,\n                                          localtime.tm_sec,\n                                          us.count());\n    }\n    PYBIND11_TYPE_CASTER(type, const_name(\"datetime.datetime\"));\n};\n\n// Other clocks that are not the system clock are not measured as datetime.datetime objects\n// since they are not measured on calendar time. So instead we just make them timedeltas\n// Or if they have passed us a time as a float we convert that\ntemplate <typename Clock, typename Duration>\nclass type_caster<std::chrono::time_point<Clock, Duration>>\n    : public duration_caster<std::chrono::time_point<Clock, Duration>> {};\n\ntemplate <typename Rep, typename Period>\nclass type_caster<std::chrono::duration<Rep, Period>>\n    : public duration_caster<std::chrono::duration<Rep, Period>> {};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/common.h",
    "content": "#include \"detail/common.h\"\n#warning \"Including 'common.h' is deprecated. It will be removed in v3.0. Use 'pybind11.h'.\"\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/complex.h",
    "content": "/*\n    pybind11/complex.h: Complex number support\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\n#include <complex>\n\n/// glibc defines I as a macro which breaks things, e.g., boost template names\n#ifdef I\n#    undef I\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\ntemplate <typename T>\nstruct format_descriptor<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {\n    static constexpr const char c = format_descriptor<T>::c;\n    static constexpr const char value[3] = {'Z', c, '\\0'};\n    static std::string format() { return std::string(value); }\n};\n\n#ifndef PYBIND11_CPP17\n\ntemplate <typename T>\nconstexpr const char\n    format_descriptor<std::complex<T>,\n                      detail::enable_if_t<std::is_floating_point<T>::value>>::value[3];\n\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename T>\nstruct is_fmt_numeric<std::complex<T>, detail::enable_if_t<std::is_floating_point<T>::value>> {\n    static constexpr bool value = true;\n    static constexpr int index = is_fmt_numeric<T>::index + 3;\n};\n\ntemplate <typename T>\nclass type_caster<std::complex<T>> {\npublic:\n    bool load(handle src, bool convert) {\n        if (!src) {\n            return false;\n        }\n        if (!convert && !PyComplex_Check(src.ptr())) {\n            return false;\n        }\n        Py_complex result = PyComplex_AsCComplex(src.ptr());\n        if (result.real == -1.0 && PyErr_Occurred()) {\n            PyErr_Clear();\n            return false;\n        }\n        value = std::complex<T>((T) result.real, (T) result.imag);\n        return true;\n    }\n\n    static handle\n    cast(const std::complex<T> &src, return_value_policy /* policy */, handle /* parent */) {\n        return PyComplex_FromDoubles((double) src.real(), (double) src.imag());\n    }\n\n    PYBIND11_TYPE_CASTER(std::complex<T>, const_name(\"complex\"));\n};\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/class.h",
    "content": "/*\n    pybind11/detail/class.h: Python C API implementation details for py::class_\n\n    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"../attr.h\"\n#include \"../options.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n#if !defined(PYPY_VERSION)\n#    define PYBIND11_BUILTIN_QUALNAME\n#    define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)\n#else\n// In PyPy, we still set __qualname__ so that we can produce reliable function type\n// signatures; in CPython this macro expands to nothing:\n#    define PYBIND11_SET_OLDPY_QUALNAME(obj, nameobj)                                             \\\n        setattr((PyObject *) obj, \"__qualname__\", nameobj)\n#endif\n\ninline std::string get_fully_qualified_tp_name(PyTypeObject *type) {\n#if !defined(PYPY_VERSION)\n    return type->tp_name;\n#else\n    auto module_name = handle((PyObject *) type).attr(\"__module__\").cast<std::string>();\n    if (module_name == PYBIND11_BUILTINS_MODULE)\n        return type->tp_name;\n    else\n        return std::move(module_name) + \".\" + type->tp_name;\n#endif\n}\n\ninline PyTypeObject *type_incref(PyTypeObject *type) {\n    Py_INCREF(type);\n    return type;\n}\n\n#if !defined(PYPY_VERSION)\n\n/// `pybind11_static_property.__get__()`: Always pass the class instead of the instance.\nextern \"C\" inline PyObject *pybind11_static_get(PyObject *self, PyObject * /*ob*/, PyObject *cls) {\n    return PyProperty_Type.tp_descr_get(self, cls, cls);\n}\n\n/// `pybind11_static_property.__set__()`: Just like the above `__get__()`.\nextern \"C\" inline int pybind11_static_set(PyObject *self, PyObject *obj, PyObject *value) {\n    PyObject *cls = PyType_Check(obj) ? obj : (PyObject *) Py_TYPE(obj);\n    return PyProperty_Type.tp_descr_set(self, cls, value);\n}\n\n// Forward declaration to use in `make_static_property_type()`\ninline void enable_dynamic_attributes(PyHeapTypeObject *heap_type);\n\n/** A `static_property` is the same as a `property` but the `__get__()` and `__set__()`\n    methods are modified to always use the object type instead of a concrete instance.\n    Return value: New reference. */\ninline PyTypeObject *make_static_property_type() {\n    constexpr auto *name = \"pybind11_static_property\";\n    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));\n\n    /* Danger zone: from now (and until PyType_Ready), make sure to\n       issue no Python C API calls which could potentially invoke the\n       garbage collector (the GC will call type_traverse(), which will in\n       turn find the newly constructed type in an invalid state) */\n    auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);\n    if (!heap_type) {\n        pybind11_fail(\"make_static_property_type(): error allocating type!\");\n    }\n\n    heap_type->ht_name = name_obj.inc_ref().ptr();\n#    ifdef PYBIND11_BUILTIN_QUALNAME\n    heap_type->ht_qualname = name_obj.inc_ref().ptr();\n#    endif\n\n    auto *type = &heap_type->ht_type;\n    type->tp_name = name;\n    type->tp_base = type_incref(&PyProperty_Type);\n    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;\n    type->tp_descr_get = pybind11_static_get;\n    type->tp_descr_set = pybind11_static_set;\n\n#    if PY_VERSION_HEX >= 0x030C0000\n    // Since Python-3.12 property-derived types are required to\n    // have dynamic attributes (to set `__doc__`)\n    enable_dynamic_attributes(heap_type);\n#    endif\n\n    if (PyType_Ready(type) < 0) {\n        pybind11_fail(\"make_static_property_type(): failure in PyType_Ready()!\");\n    }\n\n    setattr((PyObject *) type, \"__module__\", str(\"pybind11_builtins\"));\n    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);\n\n    return type;\n}\n\n#else // PYPY\n\n/** PyPy has some issues with the above C API, so we evaluate Python code instead.\n    This function will only be called once so performance isn't really a concern.\n    Return value: New reference. */\ninline PyTypeObject *make_static_property_type() {\n    auto d = dict();\n    PyObject *result = PyRun_String(R\"(\\\nclass pybind11_static_property(property):\n    def __get__(self, obj, cls):\n        return property.__get__(self, cls, cls)\n\n    def __set__(self, obj, value):\n        cls = obj if isinstance(obj, type) else type(obj)\n        property.__set__(self, cls, value)\n)\",\n                                    Py_file_input,\n                                    d.ptr(),\n                                    d.ptr());\n    if (result == nullptr)\n        throw error_already_set();\n    Py_DECREF(result);\n    return (PyTypeObject *) d[\"pybind11_static_property\"].cast<object>().release().ptr();\n}\n\n#endif // PYPY\n\n/** Types with static properties need to handle `Type.static_prop = x` in a specific way.\n    By default, Python replaces the `static_property` itself, but for wrapped C++ types\n    we need to call `static_property.__set__()` in order to propagate the new value to\n    the underlying C++ data structure. */\nextern \"C\" inline int pybind11_meta_setattro(PyObject *obj, PyObject *name, PyObject *value) {\n    // Use `_PyType_Lookup()` instead of `PyObject_GetAttr()` in order to get the raw\n    // descriptor (`property`) instead of calling `tp_descr_get` (`property.__get__()`).\n    PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);\n\n    // The following assignment combinations are possible:\n    //   1. `Type.static_prop = value`             --> descr_set: `Type.static_prop.__set__(value)`\n    //   2. `Type.static_prop = other_static_prop` --> setattro:  replace existing `static_prop`\n    //   3. `Type.regular_attribute = value`       --> setattro:  regular attribute assignment\n    auto *const static_prop = (PyObject *) get_internals().static_property_type;\n    const auto call_descr_set = (descr != nullptr) && (value != nullptr)\n                                && (PyObject_IsInstance(descr, static_prop) != 0)\n                                && (PyObject_IsInstance(value, static_prop) == 0);\n    if (call_descr_set) {\n        // Call `static_property.__set__()` instead of replacing the `static_property`.\n#if !defined(PYPY_VERSION)\n        return Py_TYPE(descr)->tp_descr_set(descr, obj, value);\n#else\n        if (PyObject *result = PyObject_CallMethod(descr, \"__set__\", \"OO\", obj, value)) {\n            Py_DECREF(result);\n            return 0;\n        } else {\n            return -1;\n        }\n#endif\n    } else {\n        // Replace existing attribute.\n        return PyType_Type.tp_setattro(obj, name, value);\n    }\n}\n\n/**\n * Python 3's PyInstanceMethod_Type hides itself via its tp_descr_get, which prevents aliasing\n * methods via cls.attr(\"m2\") = cls.attr(\"m1\"): instead the tp_descr_get returns a plain function,\n * when called on a class, or a PyMethod, when called on an instance.  Override that behaviour here\n * to do a special case bypass for PyInstanceMethod_Types.\n */\nextern \"C\" inline PyObject *pybind11_meta_getattro(PyObject *obj, PyObject *name) {\n    PyObject *descr = _PyType_Lookup((PyTypeObject *) obj, name);\n    if (descr && PyInstanceMethod_Check(descr)) {\n        Py_INCREF(descr);\n        return descr;\n    }\n    return PyType_Type.tp_getattro(obj, name);\n}\n\n/// metaclass `__call__` function that is used to create all pybind11 objects.\nextern \"C\" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, PyObject *kwargs) {\n\n    // use the default metaclass call to create/initialize the object\n    PyObject *self = PyType_Type.tp_call(type, args, kwargs);\n    if (self == nullptr) {\n        return nullptr;\n    }\n\n    // Ensure that the base __init__ function(s) were called\n    values_and_holders vhs(self);\n    for (const auto &vh : vhs) {\n        if (!vh.holder_constructed() && !vhs.is_redundant_value_and_holder(vh)) {\n            PyErr_Format(PyExc_TypeError,\n                         \"%.200s.__init__() must be called when overriding __init__\",\n                         get_fully_qualified_tp_name(vh.type->type).c_str());\n            Py_DECREF(self);\n            return nullptr;\n        }\n    }\n\n    return self;\n}\n\n/// Cleanup the type-info for a pybind11-registered type.\nextern \"C\" inline void pybind11_meta_dealloc(PyObject *obj) {\n    auto *type = (PyTypeObject *) obj;\n    auto &internals = get_internals();\n\n    // A pybind11-registered type will:\n    // 1) be found in internals.registered_types_py\n    // 2) have exactly one associated `detail::type_info`\n    auto found_type = internals.registered_types_py.find(type);\n    if (found_type != internals.registered_types_py.end() && found_type->second.size() == 1\n        && found_type->second[0]->type == type) {\n\n        auto *tinfo = found_type->second[0];\n        auto tindex = std::type_index(*tinfo->cpptype);\n        internals.direct_conversions.erase(tindex);\n\n        if (tinfo->module_local) {\n            get_local_internals().registered_types_cpp.erase(tindex);\n        } else {\n            internals.registered_types_cpp.erase(tindex);\n        }\n        internals.registered_types_py.erase(tinfo->type);\n\n        // Actually just `std::erase_if`, but that's only available in C++20\n        auto &cache = internals.inactive_override_cache;\n        for (auto it = cache.begin(), last = cache.end(); it != last;) {\n            if (it->first == (PyObject *) tinfo->type) {\n                it = cache.erase(it);\n            } else {\n                ++it;\n            }\n        }\n\n        delete tinfo;\n    }\n\n    PyType_Type.tp_dealloc(obj);\n}\n\n/** This metaclass is assigned by default to all pybind11 types and is required in order\n    for static properties to function correctly. Users may override this using `py::metaclass`.\n    Return value: New reference. */\ninline PyTypeObject *make_default_metaclass() {\n    constexpr auto *name = \"pybind11_type\";\n    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));\n\n    /* Danger zone: from now (and until PyType_Ready), make sure to\n       issue no Python C API calls which could potentially invoke the\n       garbage collector (the GC will call type_traverse(), which will in\n       turn find the newly constructed type in an invalid state) */\n    auto *heap_type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 0);\n    if (!heap_type) {\n        pybind11_fail(\"make_default_metaclass(): error allocating metaclass!\");\n    }\n\n    heap_type->ht_name = name_obj.inc_ref().ptr();\n#ifdef PYBIND11_BUILTIN_QUALNAME\n    heap_type->ht_qualname = name_obj.inc_ref().ptr();\n#endif\n\n    auto *type = &heap_type->ht_type;\n    type->tp_name = name;\n    type->tp_base = type_incref(&PyType_Type);\n    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;\n\n    type->tp_call = pybind11_meta_call;\n\n    type->tp_setattro = pybind11_meta_setattro;\n    type->tp_getattro = pybind11_meta_getattro;\n\n    type->tp_dealloc = pybind11_meta_dealloc;\n\n    if (PyType_Ready(type) < 0) {\n        pybind11_fail(\"make_default_metaclass(): failure in PyType_Ready()!\");\n    }\n\n    setattr((PyObject *) type, \"__module__\", str(\"pybind11_builtins\"));\n    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);\n\n    return type;\n}\n\n/// For multiple inheritance types we need to recursively register/deregister base pointers for any\n/// base classes with pointers that are difference from the instance value pointer so that we can\n/// correctly recognize an offset base class pointer. This calls a function with any offset base\n/// ptrs.\ninline void traverse_offset_bases(void *valueptr,\n                                  const detail::type_info *tinfo,\n                                  instance *self,\n                                  bool (*f)(void * /*parentptr*/, instance * /*self*/)) {\n    for (handle h : reinterpret_borrow<tuple>(tinfo->type->tp_bases)) {\n        if (auto *parent_tinfo = get_type_info((PyTypeObject *) h.ptr())) {\n            for (auto &c : parent_tinfo->implicit_casts) {\n                if (c.first == tinfo->cpptype) {\n                    auto *parentptr = c.second(valueptr);\n                    if (parentptr != valueptr) {\n                        f(parentptr, self);\n                    }\n                    traverse_offset_bases(parentptr, parent_tinfo, self, f);\n                    break;\n                }\n            }\n        }\n    }\n}\n\ninline bool register_instance_impl(void *ptr, instance *self) {\n    get_internals().registered_instances.emplace(ptr, self);\n    return true; // unused, but gives the same signature as the deregister func\n}\ninline bool deregister_instance_impl(void *ptr, instance *self) {\n    auto &registered_instances = get_internals().registered_instances;\n    auto range = registered_instances.equal_range(ptr);\n    for (auto it = range.first; it != range.second; ++it) {\n        if (self == it->second) {\n            registered_instances.erase(it);\n            return true;\n        }\n    }\n    return false;\n}\n\ninline void register_instance(instance *self, void *valptr, const type_info *tinfo) {\n    register_instance_impl(valptr, self);\n    if (!tinfo->simple_ancestors) {\n        traverse_offset_bases(valptr, tinfo, self, register_instance_impl);\n    }\n}\n\ninline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo) {\n    bool ret = deregister_instance_impl(valptr, self);\n    if (!tinfo->simple_ancestors) {\n        traverse_offset_bases(valptr, tinfo, self, deregister_instance_impl);\n    }\n    return ret;\n}\n\n/// Instance creation function for all pybind11 types. It allocates the internal instance layout\n/// for holding C++ objects and holders.  Allocation is done lazily (the first time the instance is\n/// cast to a reference or pointer), and initialization is done by an `__init__` function.\ninline PyObject *make_new_instance(PyTypeObject *type) {\n#if defined(PYPY_VERSION)\n    // PyPy gets tp_basicsize wrong (issue 2482) under multiple inheritance when the first\n    // inherited object is a plain Python type (i.e. not derived from an extension type).  Fix it.\n    ssize_t instance_size = static_cast<ssize_t>(sizeof(instance));\n    if (type->tp_basicsize < instance_size) {\n        type->tp_basicsize = instance_size;\n    }\n#endif\n    PyObject *self = type->tp_alloc(type, 0);\n    auto *inst = reinterpret_cast<instance *>(self);\n    // Allocate the value/holder internals:\n    inst->allocate_layout();\n\n    return self;\n}\n\n/// Instance creation function for all pybind11 types. It only allocates space for the\n/// C++ object, but doesn't call the constructor -- an `__init__` function must do that.\nextern \"C\" inline PyObject *pybind11_object_new(PyTypeObject *type, PyObject *, PyObject *) {\n    return make_new_instance(type);\n}\n\n/// An `__init__` function constructs the C++ object. Users should provide at least one\n/// of these using `py::init` or directly with `.def(__init__, ...)`. Otherwise, the\n/// following default function will be used which simply throws an exception.\nextern \"C\" inline int pybind11_object_init(PyObject *self, PyObject *, PyObject *) {\n    PyTypeObject *type = Py_TYPE(self);\n    std::string msg = get_fully_qualified_tp_name(type) + \": No constructor defined!\";\n    set_error(PyExc_TypeError, msg.c_str());\n    return -1;\n}\n\ninline void add_patient(PyObject *nurse, PyObject *patient) {\n    auto &internals = get_internals();\n    auto *instance = reinterpret_cast<detail::instance *>(nurse);\n    instance->has_patients = true;\n    Py_INCREF(patient);\n    internals.patients[nurse].push_back(patient);\n}\n\ninline void clear_patients(PyObject *self) {\n    auto *instance = reinterpret_cast<detail::instance *>(self);\n    auto &internals = get_internals();\n    auto pos = internals.patients.find(self);\n    assert(pos != internals.patients.end());\n    // Clearing the patients can cause more Python code to run, which\n    // can invalidate the iterator. Extract the vector of patients\n    // from the unordered_map first.\n    auto patients = std::move(pos->second);\n    internals.patients.erase(pos);\n    instance->has_patients = false;\n    for (PyObject *&patient : patients) {\n        Py_CLEAR(patient);\n    }\n}\n\n/// Clears all internal data from the instance and removes it from registered instances in\n/// preparation for deallocation.\ninline void clear_instance(PyObject *self) {\n    auto *instance = reinterpret_cast<detail::instance *>(self);\n\n    // Deallocate any values/holders, if present:\n    for (auto &v_h : values_and_holders(instance)) {\n        if (v_h) {\n\n            // We have to deregister before we call dealloc because, for virtual MI types, we still\n            // need to be able to get the parent pointers.\n            if (v_h.instance_registered()\n                && !deregister_instance(instance, v_h.value_ptr(), v_h.type)) {\n                pybind11_fail(\n                    \"pybind11_object_dealloc(): Tried to deallocate unregistered instance!\");\n            }\n\n            if (instance->owned || v_h.holder_constructed()) {\n                v_h.type->dealloc(v_h);\n            }\n        }\n    }\n    // Deallocate the value/holder layout internals:\n    instance->deallocate_layout();\n\n    if (instance->weakrefs) {\n        PyObject_ClearWeakRefs(self);\n    }\n\n    PyObject **dict_ptr = _PyObject_GetDictPtr(self);\n    if (dict_ptr) {\n        Py_CLEAR(*dict_ptr);\n    }\n\n    if (instance->has_patients) {\n        clear_patients(self);\n    }\n}\n\n/// Instance destructor function for all pybind11 types. It calls `type_info.dealloc`\n/// to destroy the C++ object itself, while the rest is Python bookkeeping.\nextern \"C\" inline void pybind11_object_dealloc(PyObject *self) {\n    auto *type = Py_TYPE(self);\n\n    // If this is a GC tracked object, untrack it first\n    // Note that the track call is implicitly done by the\n    // default tp_alloc, which we never override.\n    if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC) != 0) {\n        PyObject_GC_UnTrack(self);\n    }\n\n    clear_instance(self);\n\n    type->tp_free(self);\n\n#if PY_VERSION_HEX < 0x03080000\n    // `type->tp_dealloc != pybind11_object_dealloc` means that we're being called\n    // as part of a derived type's dealloc, in which case we're not allowed to decref\n    // the type here. For cross-module compatibility, we shouldn't compare directly\n    // with `pybind11_object_dealloc`, but with the common one stashed in internals.\n    auto pybind11_object_type = (PyTypeObject *) get_internals().instance_base;\n    if (type->tp_dealloc == pybind11_object_type->tp_dealloc)\n        Py_DECREF(type);\n#else\n    // This was not needed before Python 3.8 (Python issue 35810)\n    // https://github.com/pybind/pybind11/issues/1946\n    Py_DECREF(type);\n#endif\n}\n\nstd::string error_string();\n\n/** Create the type which can be used as a common base for all classes.  This is\n    needed in order to satisfy Python's requirements for multiple inheritance.\n    Return value: New reference. */\ninline PyObject *make_object_base_type(PyTypeObject *metaclass) {\n    constexpr auto *name = \"pybind11_object\";\n    auto name_obj = reinterpret_steal<object>(PYBIND11_FROM_STRING(name));\n\n    /* Danger zone: from now (and until PyType_Ready), make sure to\n       issue no Python C API calls which could potentially invoke the\n       garbage collector (the GC will call type_traverse(), which will in\n       turn find the newly constructed type in an invalid state) */\n    auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);\n    if (!heap_type) {\n        pybind11_fail(\"make_object_base_type(): error allocating type!\");\n    }\n\n    heap_type->ht_name = name_obj.inc_ref().ptr();\n#ifdef PYBIND11_BUILTIN_QUALNAME\n    heap_type->ht_qualname = name_obj.inc_ref().ptr();\n#endif\n\n    auto *type = &heap_type->ht_type;\n    type->tp_name = name;\n    type->tp_base = type_incref(&PyBaseObject_Type);\n    type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));\n    type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE;\n\n    type->tp_new = pybind11_object_new;\n    type->tp_init = pybind11_object_init;\n    type->tp_dealloc = pybind11_object_dealloc;\n\n    /* Support weak references (needed for the keep_alive feature) */\n    type->tp_weaklistoffset = offsetof(instance, weakrefs);\n\n    if (PyType_Ready(type) < 0) {\n        pybind11_fail(\"PyType_Ready failed in make_object_base_type(): \" + error_string());\n    }\n\n    setattr((PyObject *) type, \"__module__\", str(\"pybind11_builtins\"));\n    PYBIND11_SET_OLDPY_QUALNAME(type, name_obj);\n\n    assert(!PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));\n    return (PyObject *) heap_type;\n}\n\n/// dynamic_attr: Allow the garbage collector to traverse the internal instance `__dict__`.\nextern \"C\" inline int pybind11_traverse(PyObject *self, visitproc visit, void *arg) {\n#if PY_VERSION_HEX >= 0x030D0000\n    PyObject_VisitManagedDict(self, visit, arg);\n#else\n    PyObject *&dict = *_PyObject_GetDictPtr(self);\n    Py_VISIT(dict);\n#endif\n// https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_traverse\n#if PY_VERSION_HEX >= 0x03090000\n    Py_VISIT(Py_TYPE(self));\n#endif\n    return 0;\n}\n\n/// dynamic_attr: Allow the GC to clear the dictionary.\nextern \"C\" inline int pybind11_clear(PyObject *self) {\n#if PY_VERSION_HEX >= 0x030D0000\n    PyObject_ClearManagedDict(self);\n#else\n    PyObject *&dict = *_PyObject_GetDictPtr(self);\n    Py_CLEAR(dict);\n#endif\n    return 0;\n}\n\n/// Give instances of this type a `__dict__` and opt into garbage collection.\ninline void enable_dynamic_attributes(PyHeapTypeObject *heap_type) {\n    auto *type = &heap_type->ht_type;\n    type->tp_flags |= Py_TPFLAGS_HAVE_GC;\n#if PY_VERSION_HEX < 0x030B0000\n    type->tp_dictoffset = type->tp_basicsize;           // place dict at the end\n    type->tp_basicsize += (ssize_t) sizeof(PyObject *); // and allocate enough space for it\n#else\n    type->tp_flags |= Py_TPFLAGS_MANAGED_DICT;\n#endif\n    type->tp_traverse = pybind11_traverse;\n    type->tp_clear = pybind11_clear;\n\n    static PyGetSetDef getset[] = {{\n#if PY_VERSION_HEX < 0x03070000\n                                       const_cast<char *>(\"__dict__\"),\n#else\n                                       \"__dict__\",\n#endif\n                                       PyObject_GenericGetDict,\n                                       PyObject_GenericSetDict,\n                                       nullptr,\n                                       nullptr},\n                                   {nullptr, nullptr, nullptr, nullptr, nullptr}};\n    type->tp_getset = getset;\n}\n\n/// buffer_protocol: Fill in the view as specified by flags.\nextern \"C\" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int flags) {\n    // Look for a `get_buffer` implementation in this type's info or any bases (following MRO).\n    type_info *tinfo = nullptr;\n    for (auto type : reinterpret_borrow<tuple>(Py_TYPE(obj)->tp_mro)) {\n        tinfo = get_type_info((PyTypeObject *) type.ptr());\n        if (tinfo && tinfo->get_buffer) {\n            break;\n        }\n    }\n    if (view == nullptr || !tinfo || !tinfo->get_buffer) {\n        if (view) {\n            view->obj = nullptr;\n        }\n        set_error(PyExc_BufferError, \"pybind11_getbuffer(): Internal error\");\n        return -1;\n    }\n    std::memset(view, 0, sizeof(Py_buffer));\n    buffer_info *info = tinfo->get_buffer(obj, tinfo->get_buffer_data);\n    if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE && info->readonly) {\n        delete info;\n        // view->obj = nullptr;  // Was just memset to 0, so not necessary\n        set_error(PyExc_BufferError, \"Writable buffer requested for readonly storage\");\n        return -1;\n    }\n    view->obj = obj;\n    view->ndim = 1;\n    view->internal = info;\n    view->buf = info->ptr;\n    view->itemsize = info->itemsize;\n    view->len = view->itemsize;\n    for (auto s : info->shape) {\n        view->len *= s;\n    }\n    view->readonly = static_cast<int>(info->readonly);\n    if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {\n        view->format = const_cast<char *>(info->format.c_str());\n    }\n    if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {\n        view->ndim = (int) info->ndim;\n        view->strides = info->strides.data();\n        view->shape = info->shape.data();\n    }\n    Py_INCREF(view->obj);\n    return 0;\n}\n\n/// buffer_protocol: Release the resources of the buffer.\nextern \"C\" inline void pybind11_releasebuffer(PyObject *, Py_buffer *view) {\n    delete (buffer_info *) view->internal;\n}\n\n/// Give this type a buffer interface.\ninline void enable_buffer_protocol(PyHeapTypeObject *heap_type) {\n    heap_type->ht_type.tp_as_buffer = &heap_type->as_buffer;\n\n    heap_type->as_buffer.bf_getbuffer = pybind11_getbuffer;\n    heap_type->as_buffer.bf_releasebuffer = pybind11_releasebuffer;\n}\n\n/** Create a brand new Python type according to the `type_record` specification.\n    Return value: New reference. */\ninline PyObject *make_new_python_type(const type_record &rec) {\n    auto name = reinterpret_steal<object>(PYBIND11_FROM_STRING(rec.name));\n\n    auto qualname = name;\n    if (rec.scope && !PyModule_Check(rec.scope.ptr()) && hasattr(rec.scope, \"__qualname__\")) {\n        qualname = reinterpret_steal<object>(\n            PyUnicode_FromFormat(\"%U.%U\", rec.scope.attr(\"__qualname__\").ptr(), name.ptr()));\n    }\n\n    object module_;\n    if (rec.scope) {\n        if (hasattr(rec.scope, \"__module__\")) {\n            module_ = rec.scope.attr(\"__module__\");\n        } else if (hasattr(rec.scope, \"__name__\")) {\n            module_ = rec.scope.attr(\"__name__\");\n        }\n    }\n\n    const auto *full_name = c_str(\n#if !defined(PYPY_VERSION)\n        module_ ? str(module_).cast<std::string>() + \".\" + rec.name :\n#endif\n                rec.name);\n\n    char *tp_doc = nullptr;\n    if (rec.doc && options::show_user_defined_docstrings()) {\n        /* Allocate memory for docstring (using PyObject_MALLOC, since\n           Python will free this later on) */\n        size_t size = std::strlen(rec.doc) + 1;\n        tp_doc = (char *) PyObject_MALLOC(size);\n        std::memcpy((void *) tp_doc, rec.doc, size);\n    }\n\n    auto &internals = get_internals();\n    auto bases = tuple(rec.bases);\n    auto *base = (bases.empty()) ? internals.instance_base : bases[0].ptr();\n\n    /* Danger zone: from now (and until PyType_Ready), make sure to\n       issue no Python C API calls which could potentially invoke the\n       garbage collector (the GC will call type_traverse(), which will in\n       turn find the newly constructed type in an invalid state) */\n    auto *metaclass\n        = rec.metaclass.ptr() ? (PyTypeObject *) rec.metaclass.ptr() : internals.default_metaclass;\n\n    auto *heap_type = (PyHeapTypeObject *) metaclass->tp_alloc(metaclass, 0);\n    if (!heap_type) {\n        pybind11_fail(std::string(rec.name) + \": Unable to create type object!\");\n    }\n\n    heap_type->ht_name = name.release().ptr();\n#ifdef PYBIND11_BUILTIN_QUALNAME\n    heap_type->ht_qualname = qualname.inc_ref().ptr();\n#endif\n\n    auto *type = &heap_type->ht_type;\n    type->tp_name = full_name;\n    type->tp_doc = tp_doc;\n    type->tp_base = type_incref((PyTypeObject *) base);\n    type->tp_basicsize = static_cast<ssize_t>(sizeof(instance));\n    if (!bases.empty()) {\n        type->tp_bases = bases.release().ptr();\n    }\n\n    /* Don't inherit base __init__ */\n    type->tp_init = pybind11_object_init;\n\n    /* Supported protocols */\n    type->tp_as_number = &heap_type->as_number;\n    type->tp_as_sequence = &heap_type->as_sequence;\n    type->tp_as_mapping = &heap_type->as_mapping;\n    type->tp_as_async = &heap_type->as_async;\n\n    /* Flags */\n    type->tp_flags |= Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;\n    if (!rec.is_final) {\n        type->tp_flags |= Py_TPFLAGS_BASETYPE;\n    }\n\n    if (rec.dynamic_attr) {\n        enable_dynamic_attributes(heap_type);\n    }\n\n    if (rec.buffer_protocol) {\n        enable_buffer_protocol(heap_type);\n    }\n\n    if (rec.custom_type_setup_callback) {\n        rec.custom_type_setup_callback(heap_type);\n    }\n\n    if (PyType_Ready(type) < 0) {\n        pybind11_fail(std::string(rec.name) + \": PyType_Ready failed: \" + error_string());\n    }\n\n    assert(!rec.dynamic_attr || PyType_HasFeature(type, Py_TPFLAGS_HAVE_GC));\n\n    /* Register type with the parent scope */\n    if (rec.scope) {\n        setattr(rec.scope, rec.name, (PyObject *) type);\n    } else {\n        Py_INCREF(type); // Keep it alive forever (reference leak)\n    }\n\n    if (module_) { // Needed by pydoc\n        setattr((PyObject *) type, \"__module__\", module_);\n    }\n\n    PYBIND11_SET_OLDPY_QUALNAME(type, qualname);\n\n    return (PyObject *) type;\n}\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/common.h",
    "content": "/*\n    pybind11/detail/common.h -- Basic macros\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#define PYBIND11_VERSION_MAJOR 2\n#define PYBIND11_VERSION_MINOR 12\n#define PYBIND11_VERSION_PATCH 0\n\n// Similar to Python's convention: https://docs.python.org/3/c-api/apiabiversion.html\n// Additional convention: 0xD = dev\n#define PYBIND11_VERSION_HEX 0x020C0000\n\n// Define some generic pybind11 helper macros for warning management.\n//\n// Note that compiler-specific push/pop pairs are baked into the\n// PYBIND11_NAMESPACE_BEGIN/PYBIND11_NAMESPACE_END pair of macros. Therefore manual\n// PYBIND11_WARNING_PUSH/PYBIND11_WARNING_POP are usually only needed in `#include` sections.\n//\n// If you find you need to suppress a warning, please try to make the suppression as local as\n// possible using these macros. Please also be sure to push/pop with the pybind11 macros. Please\n// only use compiler specifics if you need to check specific versions, e.g. Apple Clang vs. vanilla\n// Clang.\n#if defined(_MSC_VER)\n#    define PYBIND11_COMPILER_MSVC\n#    define PYBIND11_PRAGMA(...) __pragma(__VA_ARGS__)\n#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning(push))\n#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning(pop))\n#elif defined(__INTEL_COMPILER)\n#    define PYBIND11_COMPILER_INTEL\n#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)\n#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(warning push)\n#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(warning pop)\n#elif defined(__clang__)\n#    define PYBIND11_COMPILER_CLANG\n#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)\n#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(clang diagnostic push)\n#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(clang diagnostic push)\n#elif defined(__GNUC__)\n#    define PYBIND11_COMPILER_GCC\n#    define PYBIND11_PRAGMA(...) _Pragma(#__VA_ARGS__)\n#    define PYBIND11_WARNING_PUSH PYBIND11_PRAGMA(GCC diagnostic push)\n#    define PYBIND11_WARNING_POP PYBIND11_PRAGMA(GCC diagnostic pop)\n#endif\n\n#ifdef PYBIND11_COMPILER_MSVC\n#    define PYBIND11_WARNING_DISABLE_MSVC(name) PYBIND11_PRAGMA(warning(disable : name))\n#else\n#    define PYBIND11_WARNING_DISABLE_MSVC(name)\n#endif\n\n#ifdef PYBIND11_COMPILER_CLANG\n#    define PYBIND11_WARNING_DISABLE_CLANG(name) PYBIND11_PRAGMA(clang diagnostic ignored name)\n#else\n#    define PYBIND11_WARNING_DISABLE_CLANG(name)\n#endif\n\n#ifdef PYBIND11_COMPILER_GCC\n#    define PYBIND11_WARNING_DISABLE_GCC(name) PYBIND11_PRAGMA(GCC diagnostic ignored name)\n#else\n#    define PYBIND11_WARNING_DISABLE_GCC(name)\n#endif\n\n#ifdef PYBIND11_COMPILER_INTEL\n#    define PYBIND11_WARNING_DISABLE_INTEL(name) PYBIND11_PRAGMA(warning disable name)\n#else\n#    define PYBIND11_WARNING_DISABLE_INTEL(name)\n#endif\n\n#define PYBIND11_NAMESPACE_BEGIN(name)                                                            \\\n    namespace name {                                                                              \\\n    PYBIND11_WARNING_PUSH\n\n#define PYBIND11_NAMESPACE_END(name)                                                              \\\n    PYBIND11_WARNING_POP                                                                          \\\n    }\n\n// Robust support for some features and loading modules compiled against different pybind versions\n// requires forcing hidden visibility on pybind code, so we enforce this by setting the attribute\n// on the main `pybind11` namespace.\n#if !defined(PYBIND11_NAMESPACE)\n#    ifdef __GNUG__\n#        define PYBIND11_NAMESPACE pybind11 __attribute__((visibility(\"hidden\")))\n#    else\n#        define PYBIND11_NAMESPACE pybind11\n#    endif\n#endif\n\n#if !(defined(_MSC_VER) && __cplusplus == 199711L)\n#    if __cplusplus >= 201402L\n#        define PYBIND11_CPP14\n#        if __cplusplus >= 201703L\n#            define PYBIND11_CPP17\n#            if __cplusplus >= 202002L\n#                define PYBIND11_CPP20\n// Please update tests/pybind11_tests.cpp `cpp_std()` when adding a macro here.\n#            endif\n#        endif\n#    endif\n#elif defined(_MSC_VER) && __cplusplus == 199711L\n// MSVC sets _MSVC_LANG rather than __cplusplus (supposedly until the standard is fully\n// implemented). Unless you use the /Zc:__cplusplus flag on Visual Studio 2017 15.7 Preview 3\n// or newer.\n#    if _MSVC_LANG >= 201402L\n#        define PYBIND11_CPP14\n#        if _MSVC_LANG > 201402L\n#            define PYBIND11_CPP17\n#            if _MSVC_LANG >= 202002L\n#                define PYBIND11_CPP20\n#            endif\n#        endif\n#    endif\n#endif\n\n#if defined(PYBIND11_CPP20)\n#    define PYBIND11_CONSTINIT constinit\n#    define PYBIND11_DTOR_CONSTEXPR constexpr\n#else\n#    define PYBIND11_CONSTINIT\n#    define PYBIND11_DTOR_CONSTEXPR\n#endif\n\n// Compiler version assertions\n#if defined(__INTEL_COMPILER)\n#    if __INTEL_COMPILER < 1800\n#        error pybind11 requires Intel C++ compiler v18 or newer\n#    elif __INTEL_COMPILER < 1900 && defined(PYBIND11_CPP14)\n#        error pybind11 supports only C++11 with Intel C++ compiler v18. Use v19 or newer for C++14.\n#    endif\n/* The following pragma cannot be pop'ed:\n   https://community.intel.com/t5/Intel-C-Compiler/Inline-and-no-inline-warning/td-p/1216764 */\n#    pragma warning disable 2196 // warning #2196: routine is both \"inline\" and \"noinline\"\n#elif defined(__clang__) && !defined(__apple_build_version__)\n#    if __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 3)\n#        error pybind11 requires clang 3.3 or newer\n#    endif\n#elif defined(__clang__)\n// Apple changes clang version macros to its Xcode version; the first Xcode release based on\n// (upstream) clang 3.3 was Xcode 5:\n#    if __clang_major__ < 5\n#        error pybind11 requires Xcode/clang 5.0 or newer\n#    endif\n#elif defined(__GNUG__)\n#    if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)\n#        error pybind11 requires gcc 4.8 or newer\n#    endif\n#elif defined(_MSC_VER)\n#    if _MSC_VER < 1910\n#        error pybind11 2.10+ requires MSVC 2017 or newer\n#    endif\n#endif\n\n#if !defined(PYBIND11_EXPORT)\n#    if defined(WIN32) || defined(_WIN32)\n#        define PYBIND11_EXPORT __declspec(dllexport)\n#    else\n#        define PYBIND11_EXPORT __attribute__((visibility(\"default\")))\n#    endif\n#endif\n\n#if !defined(PYBIND11_EXPORT_EXCEPTION)\n#    if defined(__apple_build_version__)\n#        define PYBIND11_EXPORT_EXCEPTION PYBIND11_EXPORT\n#    else\n#        define PYBIND11_EXPORT_EXCEPTION\n#    endif\n#endif\n\n// For CUDA, GCC7, GCC8:\n// PYBIND11_NOINLINE_FORCED is incompatible with `-Wattributes -Werror`.\n// When defining PYBIND11_NOINLINE_FORCED, it is best to also use `-Wno-attributes`.\n// However, the measured shared-library size saving when using noinline are only\n// 1.7% for CUDA, -0.2% for GCC7, and 0.0% for GCC8 (using -DCMAKE_BUILD_TYPE=MinSizeRel,\n// the default under pybind11/tests).\n#if !defined(PYBIND11_NOINLINE_FORCED)                                                            \\\n    && (defined(__CUDACC__) || (defined(__GNUC__) && (__GNUC__ == 7 || __GNUC__ == 8)))\n#    define PYBIND11_NOINLINE_DISABLED\n#endif\n\n// The PYBIND11_NOINLINE macro is for function DEFINITIONS.\n// In contrast, FORWARD DECLARATIONS should never use this macro:\n// https://stackoverflow.com/questions/9317473/forward-declaration-of-inline-functions\n#if defined(PYBIND11_NOINLINE_DISABLED) // Option for maximum portability and experimentation.\n#    define PYBIND11_NOINLINE inline\n#elif defined(_MSC_VER)\n#    define PYBIND11_NOINLINE __declspec(noinline) inline\n#else\n#    define PYBIND11_NOINLINE __attribute__((noinline)) inline\n#endif\n\n#if defined(__MINGW32__)\n// For unknown reasons all PYBIND11_DEPRECATED member trigger a warning when declared\n// whether it is used or not\n#    define PYBIND11_DEPRECATED(reason)\n#elif defined(PYBIND11_CPP14)\n#    define PYBIND11_DEPRECATED(reason) [[deprecated(reason)]]\n#else\n#    define PYBIND11_DEPRECATED(reason) __attribute__((deprecated(reason)))\n#endif\n\n#if defined(PYBIND11_CPP17)\n#    define PYBIND11_MAYBE_UNUSED [[maybe_unused]]\n#elif defined(_MSC_VER) && !defined(__clang__)\n#    define PYBIND11_MAYBE_UNUSED\n#else\n#    define PYBIND11_MAYBE_UNUSED __attribute__((__unused__))\n#endif\n\n/* Don't let Python.h #define (v)snprintf as macro because they are implemented\n   properly in Visual Studio since 2015. */\n#if defined(_MSC_VER)\n#    define HAVE_SNPRINTF 1\n#endif\n\n/// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode\n#if defined(_MSC_VER)\nPYBIND11_WARNING_PUSH\nPYBIND11_WARNING_DISABLE_MSVC(4505)\n// C4505: 'PySlice_GetIndicesEx': unreferenced local function has been removed (PyPy only)\n#    if defined(_DEBUG) && !defined(Py_DEBUG)\n// Workaround for a VS 2022 issue.\n// NOTE: This workaround knowingly violates the Python.h include order requirement:\n// https://docs.python.org/3/c-api/intro.html#include-files\n// See https://github.com/pybind/pybind11/pull/3497 for full context.\n#        include <yvals.h>\n#        if _MSVC_STL_VERSION >= 143\n#            include <crtdefs.h>\n#        endif\n#        define PYBIND11_DEBUG_MARKER\n#        undef _DEBUG\n#    endif\n#endif\n\n// https://en.cppreference.com/w/c/chrono/localtime\n#if defined(__STDC_LIB_EXT1__) && !defined(__STDC_WANT_LIB_EXT1__)\n#    define __STDC_WANT_LIB_EXT1__\n#endif\n\n#ifdef __has_include\n// std::optional (but including it in c++14 mode isn't allowed)\n#    if defined(PYBIND11_CPP17) && __has_include(<optional>)\n#        define PYBIND11_HAS_OPTIONAL 1\n#    endif\n// std::experimental::optional (but not allowed in c++11 mode)\n#    if defined(PYBIND11_CPP14) && (__has_include(<experimental/optional>) && \\\n                                 !__has_include(<optional>))\n#        define PYBIND11_HAS_EXP_OPTIONAL 1\n#    endif\n// std::variant\n#    if defined(PYBIND11_CPP17) && __has_include(<variant>)\n#        define PYBIND11_HAS_VARIANT 1\n#    endif\n#elif defined(_MSC_VER) && defined(PYBIND11_CPP17)\n#    define PYBIND11_HAS_OPTIONAL 1\n#    define PYBIND11_HAS_VARIANT 1\n#endif\n\n#if defined(PYBIND11_CPP17)\n#    if defined(__has_include)\n#        if __has_include(<string_view>)\n#            define PYBIND11_HAS_STRING_VIEW\n#        endif\n#    elif defined(_MSC_VER)\n#        define PYBIND11_HAS_STRING_VIEW\n#    endif\n#endif\n\n#include <Python.h>\n// Reminder: WITH_THREAD is always defined if PY_VERSION_HEX >= 0x03070000\n#if PY_VERSION_HEX < 0x03060000\n#    error \"PYTHON < 3.6 IS UNSUPPORTED. pybind11 v2.9 was the last to support Python 2 and 3.5.\"\n#endif\n#include <frameobject.h>\n#include <pythread.h>\n\n/* Python #defines overrides on all sorts of core functions, which\n   tends to weak havok in C++ codebases that expect these to work\n   like regular functions (potentially with several overloads) */\n#if defined(isalnum)\n#    undef isalnum\n#    undef isalpha\n#    undef islower\n#    undef isspace\n#    undef isupper\n#    undef tolower\n#    undef toupper\n#endif\n\n#if defined(copysign)\n#    undef copysign\n#endif\n\n#if defined(PYBIND11_NUMPY_1_ONLY)\n#    define PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED\n#endif\n\n#if defined(PYPY_VERSION) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n#    define PYBIND11_SIMPLE_GIL_MANAGEMENT\n#endif\n\n#if defined(_MSC_VER)\n#    if defined(PYBIND11_DEBUG_MARKER)\n#        define _DEBUG\n#        undef PYBIND11_DEBUG_MARKER\n#    endif\nPYBIND11_WARNING_POP\n#endif\n\n#include <cstddef>\n#include <cstring>\n#include <exception>\n#include <forward_list>\n#include <memory>\n#include <stdexcept>\n#include <string>\n#include <type_traits>\n#include <typeindex>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n#if defined(__has_include)\n#    if __has_include(<version>)\n#        include <version>\n#    endif\n#endif\n\n// Must be after including <version> or one of the other headers specified by the standard\n#if defined(__cpp_lib_char8_t) && __cpp_lib_char8_t >= 201811L\n#    define PYBIND11_HAS_U8STRING\n#endif\n\n// See description of PR #4246:\n#if !defined(PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF) && !defined(NDEBUG)                       \\\n    && !defined(PYPY_VERSION) && !defined(PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF)\n#    define PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF\n#endif\n\n// #define PYBIND11_STR_LEGACY_PERMISSIVE\n// If DEFINED, pybind11::str can hold PyUnicodeObject or PyBytesObject\n//             (probably surprising and never documented, but this was the\n//             legacy behavior until and including v2.6.x). As a side-effect,\n//             pybind11::isinstance<str>() is true for both pybind11::str and\n//             pybind11::bytes.\n// If UNDEFINED, pybind11::str can only hold PyUnicodeObject, and\n//               pybind11::isinstance<str>() is true only for pybind11::str.\n//               However, for Python 2 only (!), the pybind11::str caster\n//               implicitly decoded bytes to PyUnicodeObject. This was to ease\n//               the transition from the legacy behavior to the non-permissive\n//               behavior.\n\n/// Compatibility macros for Python 2 / Python 3 versions TODO: remove\n#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)\n#define PYBIND11_INSTANCE_METHOD_CHECK PyInstanceMethod_Check\n#define PYBIND11_INSTANCE_METHOD_GET_FUNCTION PyInstanceMethod_GET_FUNCTION\n#define PYBIND11_BYTES_CHECK PyBytes_Check\n#define PYBIND11_BYTES_FROM_STRING PyBytes_FromString\n#define PYBIND11_BYTES_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize\n#define PYBIND11_BYTES_AS_STRING_AND_SIZE PyBytes_AsStringAndSize\n#define PYBIND11_BYTES_AS_STRING PyBytes_AsString\n#define PYBIND11_BYTES_SIZE PyBytes_Size\n#define PYBIND11_LONG_CHECK(o) PyLong_Check(o)\n#define PYBIND11_LONG_AS_LONGLONG(o) PyLong_AsLongLong(o)\n#define PYBIND11_LONG_FROM_SIGNED(o) PyLong_FromSsize_t((ssize_t) (o))\n#define PYBIND11_LONG_FROM_UNSIGNED(o) PyLong_FromSize_t((size_t) (o))\n#define PYBIND11_BYTES_NAME \"bytes\"\n#define PYBIND11_STRING_NAME \"str\"\n#define PYBIND11_SLICE_OBJECT PyObject\n#define PYBIND11_FROM_STRING PyUnicode_FromString\n#define PYBIND11_STR_TYPE ::pybind11::str\n#define PYBIND11_BOOL_ATTR \"__bool__\"\n#define PYBIND11_NB_BOOL(ptr) ((ptr)->nb_bool)\n#define PYBIND11_BUILTINS_MODULE \"builtins\"\n// Providing a separate declaration to make Clang's -Wmissing-prototypes happy.\n// See comment for PYBIND11_MODULE below for why this is marked \"maybe unused\".\n#define PYBIND11_PLUGIN_IMPL(name)                                                                \\\n    extern \"C\" PYBIND11_MAYBE_UNUSED PYBIND11_EXPORT PyObject *PyInit_##name();                   \\\n    extern \"C\" PYBIND11_EXPORT PyObject *PyInit_##name()\n\n#define PYBIND11_TRY_NEXT_OVERLOAD ((PyObject *) 1) // special failure return code\n#define PYBIND11_STRINGIFY(x) #x\n#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)\n#define PYBIND11_CONCAT(first, second) first##second\n#define PYBIND11_ENSURE_INTERNALS_READY pybind11::detail::get_internals();\n\n#define PYBIND11_CHECK_PYTHON_VERSION                                                             \\\n    {                                                                                             \\\n        const char *compiled_ver                                                                  \\\n            = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \".\" PYBIND11_TOSTRING(PY_MINOR_VERSION);        \\\n        const char *runtime_ver = Py_GetVersion();                                                \\\n        size_t len = std::strlen(compiled_ver);                                                   \\\n        if (std::strncmp(runtime_ver, compiled_ver, len) != 0                                     \\\n            || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {                            \\\n            PyErr_Format(PyExc_ImportError,                                                       \\\n                         \"Python version mismatch: module was compiled for Python %s, \"           \\\n                         \"but the interpreter version is incompatible: %s.\",                      \\\n                         compiled_ver,                                                            \\\n                         runtime_ver);                                                            \\\n            return nullptr;                                                                       \\\n        }                                                                                         \\\n    }\n\n#define PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \\\n    catch (pybind11::error_already_set & e) {                                                     \\\n        pybind11::raise_from(e, PyExc_ImportError, \"initialization failed\");                      \\\n        return nullptr;                                                                           \\\n    }                                                                                             \\\n    catch (const std::exception &e) {                                                             \\\n        ::pybind11::set_error(PyExc_ImportError, e.what());                                       \\\n        return nullptr;                                                                           \\\n    }\n\n/** \\rst\n    ***Deprecated in favor of PYBIND11_MODULE***\n\n    This macro creates the entry point that will be invoked when the Python interpreter\n    imports a plugin library. Please create a `module_` in the function body and return\n    the pointer to its underlying Python object at the end.\n\n    .. code-block:: cpp\n\n        PYBIND11_PLUGIN(example) {\n            pybind11::module_ m(\"example\", \"pybind11 example plugin\");\n            /// Set up bindings here\n            return m.ptr();\n        }\n\\endrst */\n#define PYBIND11_PLUGIN(name)                                                                     \\\n    PYBIND11_DEPRECATED(\"PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE\")                     \\\n    static PyObject *pybind11_init();                                                             \\\n    PYBIND11_PLUGIN_IMPL(name) {                                                                  \\\n        PYBIND11_CHECK_PYTHON_VERSION                                                             \\\n        PYBIND11_ENSURE_INTERNALS_READY                                                           \\\n        try {                                                                                     \\\n            return pybind11_init();                                                               \\\n        }                                                                                         \\\n        PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \\\n    }                                                                                             \\\n    PyObject *pybind11_init()\n\n/** \\rst\n    This macro creates the entry point that will be invoked when the Python interpreter\n    imports an extension module. The module name is given as the first argument and it\n    should not be in quotes. The second macro argument defines a variable of type\n    `py::module_` which can be used to initialize the module.\n\n    The entry point is marked as \"maybe unused\" to aid dead-code detection analysis:\n    since the entry point is typically only looked up at runtime and not referenced\n    during translation, it would otherwise appear as unused (\"dead\") code.\n\n    .. code-block:: cpp\n\n        PYBIND11_MODULE(example, m) {\n            m.doc() = \"pybind11 example module\";\n\n            // Add bindings here\n            m.def(\"foo\", []() {\n                return \"Hello, World!\";\n            });\n        }\n\\endrst */\n#define PYBIND11_MODULE(name, variable)                                                           \\\n    static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name)            \\\n        PYBIND11_MAYBE_UNUSED;                                                                    \\\n    PYBIND11_MAYBE_UNUSED                                                                         \\\n    static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &);                     \\\n    PYBIND11_PLUGIN_IMPL(name) {                                                                  \\\n        PYBIND11_CHECK_PYTHON_VERSION                                                             \\\n        PYBIND11_ENSURE_INTERNALS_READY                                                           \\\n        auto m = ::pybind11::module_::create_extension_module(                                    \\\n            PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name));      \\\n        try {                                                                                     \\\n            PYBIND11_CONCAT(pybind11_init_, name)(m);                                             \\\n            return m.ptr();                                                                       \\\n        }                                                                                         \\\n        PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \\\n    }                                                                                             \\\n    void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nusing ssize_t = Py_ssize_t;\nusing size_t = std::size_t;\n\ntemplate <typename IntType>\ninline ssize_t ssize_t_cast(const IntType &val) {\n    static_assert(sizeof(IntType) <= sizeof(ssize_t), \"Implicit narrowing is not permitted.\");\n    return static_cast<ssize_t>(val);\n}\n\n/// Approach used to cast a previously unknown C++ instance into a Python object\nenum class return_value_policy : uint8_t {\n    /** This is the default return value policy, which falls back to the policy\n        return_value_policy::take_ownership when the return value is a pointer.\n        Otherwise, it uses return_value::move or return_value::copy for rvalue\n        and lvalue references, respectively. See below for a description of what\n        all of these different policies do. */\n    automatic = 0,\n\n    /** As above, but use policy return_value_policy::reference when the return\n        value is a pointer. This is the default conversion policy for function\n        arguments when calling Python functions manually from C++ code (i.e. via\n        handle::operator()). You probably won't need to use this. */\n    automatic_reference,\n\n    /** Reference an existing object (i.e. do not create a new copy) and take\n        ownership. Python will call the destructor and delete operator when the\n        object's reference count reaches zero. Undefined behavior ensues when\n        the C++ side does the same.. */\n    take_ownership,\n\n    /** Create a new copy of the returned object, which will be owned by\n        Python. This policy is comparably safe because the lifetimes of the two\n        instances are decoupled. */\n    copy,\n\n    /** Use std::move to move the return value contents into a new instance\n        that will be owned by Python. This policy is comparably safe because the\n        lifetimes of the two instances (move source and destination) are\n        decoupled. */\n    move,\n\n    /** Reference an existing object, but do not take ownership. The C++ side\n        is responsible for managing the object's lifetime and deallocating it\n        when it is no longer used. Warning: undefined behavior will ensue when\n        the C++ side deletes an object that is still referenced and used by\n        Python. */\n    reference,\n\n    /** This policy only applies to methods and properties. It references the\n        object without taking ownership similar to the above\n        return_value_policy::reference policy. In contrast to that policy, the\n        function or property's implicit this argument (called the parent) is\n        considered to be the the owner of the return value (the child).\n        pybind11 then couples the lifetime of the parent to the child via a\n        reference relationship that ensures that the parent cannot be garbage\n        collected while Python is still using the child. More advanced\n        variations of this scheme are also possible using combinations of\n        return_value_policy::reference and the keep_alive call policy */\n    reference_internal\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline static constexpr int log2(size_t n, int k = 0) {\n    return (n <= 1) ? k : log2(n >> 1, k + 1);\n}\n\n// Returns the size as a multiple of sizeof(void *), rounded up.\ninline static constexpr size_t size_in_ptrs(size_t s) {\n    return 1 + ((s - 1) >> log2(sizeof(void *)));\n}\n\n/**\n * The space to allocate for simple layout instance holders (see below) in multiple of the size of\n * a pointer (e.g.  2 means 16 bytes on 64-bit architectures).  The default is the minimum required\n * to holder either a std::unique_ptr or std::shared_ptr (which is almost always\n * sizeof(std::shared_ptr<T>)).\n */\nconstexpr size_t instance_simple_holder_in_ptrs() {\n    static_assert(sizeof(std::shared_ptr<int>) >= sizeof(std::unique_ptr<int>),\n                  \"pybind assumes std::shared_ptrs are at least as big as std::unique_ptrs\");\n    return size_in_ptrs(sizeof(std::shared_ptr<int>));\n}\n\n// Forward declarations\nstruct type_info;\nstruct value_and_holder;\n\nstruct nonsimple_values_and_holders {\n    void **values_and_holders;\n    uint8_t *status;\n};\n\n/// The 'instance' type which needs to be standard layout (need to be able to use 'offsetof')\nstruct instance {\n    PyObject_HEAD\n    /// Storage for pointers and holder; see simple_layout, below, for a description\n    union {\n        void *simple_value_holder[1 + instance_simple_holder_in_ptrs()];\n        nonsimple_values_and_holders nonsimple;\n    };\n    /// Weak references\n    PyObject *weakrefs;\n    /// If true, the pointer is owned which means we're free to manage it with a holder.\n    bool owned : 1;\n    /**\n     * An instance has two possible value/holder layouts.\n     *\n     * Simple layout (when this flag is true), means the `simple_value_holder` is set with a\n     * pointer and the holder object governing that pointer, i.e. [val1*][holder].  This layout is\n     * applied whenever there is no python-side multiple inheritance of bound C++ types *and* the\n     * type's holder will fit in the default space (which is large enough to hold either a\n     * std::unique_ptr or std::shared_ptr).\n     *\n     * Non-simple layout applies when using custom holders that require more space than\n     * `shared_ptr` (which is typically the size of two pointers), or when multiple inheritance is\n     * used on the python side.  Non-simple layout allocates the required amount of memory to have\n     * multiple bound C++ classes as parents.  Under this layout, `nonsimple.values_and_holders` is\n     * set to a pointer to allocated space of the required space to hold a sequence of value\n     * pointers and holders followed `status`, a set of bit flags (1 byte each), i.e.\n     * [val1*][holder1][val2*][holder2]...[bb...]  where each [block] is rounded up to a multiple\n     * of `sizeof(void *)`.  `nonsimple.status` is, for convenience, a pointer to the beginning of\n     * the [bb...] block (but not independently allocated).\n     *\n     * Status bits indicate whether the associated holder is constructed (&\n     * status_holder_constructed) and whether the value pointer is registered (&\n     * status_instance_registered) in `registered_instances`.\n     */\n    bool simple_layout : 1;\n    /// For simple layout, tracks whether the holder has been constructed\n    bool simple_holder_constructed : 1;\n    /// For simple layout, tracks whether the instance is registered in `registered_instances`\n    bool simple_instance_registered : 1;\n    /// If true, get_internals().patients has an entry for this object\n    bool has_patients : 1;\n\n    /// Initializes all of the above type/values/holders data (but not the instance values\n    /// themselves)\n    void allocate_layout();\n\n    /// Destroys/deallocates all of the above\n    void deallocate_layout();\n\n    /// Returns the value_and_holder wrapper for the given type (or the first, if `find_type`\n    /// omitted).  Returns a default-constructed (with `.inst = nullptr`) object on failure if\n    /// `throw_if_missing` is false.\n    value_and_holder get_value_and_holder(const type_info *find_type = nullptr,\n                                          bool throw_if_missing = true);\n\n    /// Bit values for the non-simple status flags\n    static constexpr uint8_t status_holder_constructed = 1;\n    static constexpr uint8_t status_instance_registered = 2;\n};\n\nstatic_assert(std::is_standard_layout<instance>::value,\n              \"Internal error: `pybind11::detail::instance` is not standard layout!\");\n\n/// from __cpp_future__ import (convenient aliases from C++14/17)\n#if defined(PYBIND11_CPP14)\nusing std::conditional_t;\nusing std::enable_if_t;\nusing std::remove_cv_t;\nusing std::remove_reference_t;\n#else\ntemplate <bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\ntemplate <bool B, typename T, typename F>\nusing conditional_t = typename std::conditional<B, T, F>::type;\ntemplate <typename T>\nusing remove_cv_t = typename std::remove_cv<T>::type;\ntemplate <typename T>\nusing remove_reference_t = typename std::remove_reference<T>::type;\n#endif\n\n#if defined(PYBIND11_CPP20)\nusing std::remove_cvref;\nusing std::remove_cvref_t;\n#else\ntemplate <class T>\nstruct remove_cvref {\n    using type = remove_cv_t<remove_reference_t<T>>;\n};\ntemplate <class T>\nusing remove_cvref_t = typename remove_cvref<T>::type;\n#endif\n\n/// Example usage: is_same_ignoring_cvref<T, PyObject *>::value\ntemplate <typename T, typename U>\nusing is_same_ignoring_cvref = std::is_same<detail::remove_cvref_t<T>, U>;\n\n/// Index sequences\n#if defined(PYBIND11_CPP14)\nusing std::index_sequence;\nusing std::make_index_sequence;\n#else\ntemplate <size_t...>\nstruct index_sequence {};\ntemplate <size_t N, size_t... S>\nstruct make_index_sequence_impl : make_index_sequence_impl<N - 1, N - 1, S...> {};\ntemplate <size_t... S>\nstruct make_index_sequence_impl<0, S...> {\n    using type = index_sequence<S...>;\n};\ntemplate <size_t N>\nusing make_index_sequence = typename make_index_sequence_impl<N>::type;\n#endif\n\n/// Make an index sequence of the indices of true arguments\ntemplate <typename ISeq, size_t, bool...>\nstruct select_indices_impl {\n    using type = ISeq;\n};\ntemplate <size_t... IPrev, size_t I, bool B, bool... Bs>\nstruct select_indices_impl<index_sequence<IPrev...>, I, B, Bs...>\n    : select_indices_impl<conditional_t<B, index_sequence<IPrev..., I>, index_sequence<IPrev...>>,\n                          I + 1,\n                          Bs...> {};\ntemplate <bool... Bs>\nusing select_indices = typename select_indices_impl<index_sequence<>, 0, Bs...>::type;\n\n/// Backports of std::bool_constant and std::negation to accommodate older compilers\ntemplate <bool B>\nusing bool_constant = std::integral_constant<bool, B>;\ntemplate <typename T>\nstruct negation : bool_constant<!T::value> {};\n\n// PGI/Intel cannot detect operator delete with the \"compatible\" void_t impl, so\n// using the new one (C++14 defect, so generally works on newer compilers, even\n// if not in C++17 mode)\n#if defined(__PGIC__) || defined(__INTEL_COMPILER)\ntemplate <typename...>\nusing void_t = void;\n#else\ntemplate <typename...>\nstruct void_t_impl {\n    using type = void;\n};\ntemplate <typename... Ts>\nusing void_t = typename void_t_impl<Ts...>::type;\n#endif\n\n/// Compile-time all/any/none of that check the boolean value of all template types\n#if defined(__cpp_fold_expressions) && !(defined(_MSC_VER) && (_MSC_VER < 1916))\ntemplate <class... Ts>\nusing all_of = bool_constant<(Ts::value && ...)>;\ntemplate <class... Ts>\nusing any_of = bool_constant<(Ts::value || ...)>;\n#elif !defined(_MSC_VER)\ntemplate <bool...>\nstruct bools {};\ntemplate <class... Ts>\nusing all_of = std::is_same<bools<Ts::value..., true>, bools<true, Ts::value...>>;\ntemplate <class... Ts>\nusing any_of = negation<all_of<negation<Ts>...>>;\n#else\n// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit\n// at a slight loss of compilation efficiency).\ntemplate <class... Ts>\nusing all_of = std::conjunction<Ts...>;\ntemplate <class... Ts>\nusing any_of = std::disjunction<Ts...>;\n#endif\ntemplate <class... Ts>\nusing none_of = negation<any_of<Ts...>>;\n\ntemplate <class T, template <class> class... Predicates>\nusing satisfies_all_of = all_of<Predicates<T>...>;\ntemplate <class T, template <class> class... Predicates>\nusing satisfies_any_of = any_of<Predicates<T>...>;\ntemplate <class T, template <class> class... Predicates>\nusing satisfies_none_of = none_of<Predicates<T>...>;\n\n/// Strip the class from a method type\ntemplate <typename T>\nstruct remove_class {};\ntemplate <typename C, typename R, typename... A>\nstruct remove_class<R (C::*)(A...)> {\n    using type = R(A...);\n};\ntemplate <typename C, typename R, typename... A>\nstruct remove_class<R (C::*)(A...) const> {\n    using type = R(A...);\n};\n#ifdef __cpp_noexcept_function_type\ntemplate <typename C, typename R, typename... A>\nstruct remove_class<R (C::*)(A...) noexcept> {\n    using type = R(A...);\n};\ntemplate <typename C, typename R, typename... A>\nstruct remove_class<R (C::*)(A...) const noexcept> {\n    using type = R(A...);\n};\n#endif\n/// Helper template to strip away type modifiers\ntemplate <typename T>\nstruct intrinsic_type {\n    using type = T;\n};\ntemplate <typename T>\nstruct intrinsic_type<const T> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T>\nstruct intrinsic_type<T *> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T>\nstruct intrinsic_type<T &> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T>\nstruct intrinsic_type<T &&> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T, size_t N>\nstruct intrinsic_type<const T[N]> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T, size_t N>\nstruct intrinsic_type<T[N]> {\n    using type = typename intrinsic_type<T>::type;\n};\ntemplate <typename T>\nusing intrinsic_t = typename intrinsic_type<T>::type;\n\n/// Helper type to replace 'void' in some expressions\nstruct void_type {};\n\n/// Helper template which holds a list of types\ntemplate <typename...>\nstruct type_list {};\n\n/// Compile-time integer sum\n#ifdef __cpp_fold_expressions\ntemplate <typename... Ts>\nconstexpr size_t constexpr_sum(Ts... ns) {\n    return (0 + ... + size_t{ns});\n}\n#else\nconstexpr size_t constexpr_sum() { return 0; }\ntemplate <typename T, typename... Ts>\nconstexpr size_t constexpr_sum(T n, Ts... ns) {\n    return size_t{n} + constexpr_sum(ns...);\n}\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(constexpr_impl)\n/// Implementation details for constexpr functions\nconstexpr int first(int i) { return i; }\ntemplate <typename T, typename... Ts>\nconstexpr int first(int i, T v, Ts... vs) {\n    return v ? i : first(i + 1, vs...);\n}\n\nconstexpr int last(int /*i*/, int result) { return result; }\ntemplate <typename T, typename... Ts>\nconstexpr int last(int i, int result, T v, Ts... vs) {\n    return last(i + 1, v ? i : result, vs...);\n}\nPYBIND11_NAMESPACE_END(constexpr_impl)\n\n/// Return the index of the first type in Ts which satisfies Predicate<T>.\n/// Returns sizeof...(Ts) if none match.\ntemplate <template <typename> class Predicate, typename... Ts>\nconstexpr int constexpr_first() {\n    return constexpr_impl::first(0, Predicate<Ts>::value...);\n}\n\n/// Return the index of the last type in Ts which satisfies Predicate<T>, or -1 if none match.\ntemplate <template <typename> class Predicate, typename... Ts>\nconstexpr int constexpr_last() {\n    return constexpr_impl::last(0, -1, Predicate<Ts>::value...);\n}\n\n/// Return the Nth element from the parameter pack\ntemplate <size_t N, typename T, typename... Ts>\nstruct pack_element {\n    using type = typename pack_element<N - 1, Ts...>::type;\n};\ntemplate <typename T, typename... Ts>\nstruct pack_element<0, T, Ts...> {\n    using type = T;\n};\n\n/// Return the one and only type which matches the predicate, or Default if none match.\n/// If more than one type matches the predicate, fail at compile-time.\ntemplate <template <typename> class Predicate, typename Default, typename... Ts>\nstruct exactly_one {\n    static constexpr auto found = constexpr_sum(Predicate<Ts>::value...);\n    static_assert(found <= 1, \"Found more than one type matching the predicate\");\n\n    static constexpr auto index = found ? constexpr_first<Predicate, Ts...>() : 0;\n    using type = conditional_t<found, typename pack_element<index, Ts...>::type, Default>;\n};\ntemplate <template <typename> class P, typename Default>\nstruct exactly_one<P, Default> {\n    using type = Default;\n};\n\ntemplate <template <typename> class Predicate, typename Default, typename... Ts>\nusing exactly_one_t = typename exactly_one<Predicate, Default, Ts...>::type;\n\n/// Defer the evaluation of type T until types Us are instantiated\ntemplate <typename T, typename... /*Us*/>\nstruct deferred_type {\n    using type = T;\n};\ntemplate <typename T, typename... Us>\nusing deferred_t = typename deferred_type<T, Us...>::type;\n\n/// Like is_base_of, but requires a strict base (i.e. `is_strict_base_of<T, T>::value == false`,\n/// unlike `std::is_base_of`)\ntemplate <typename Base, typename Derived>\nusing is_strict_base_of\n    = bool_constant<std::is_base_of<Base, Derived>::value && !std::is_same<Base, Derived>::value>;\n\n/// Like is_base_of, but also requires that the base type is accessible (i.e. that a Derived\n/// pointer can be converted to a Base pointer) For unions, `is_base_of<T, T>::value` is False, so\n/// we need to check `is_same` as well.\ntemplate <typename Base, typename Derived>\nusing is_accessible_base_of\n    = bool_constant<(std::is_same<Base, Derived>::value || std::is_base_of<Base, Derived>::value)\n                    && std::is_convertible<Derived *, Base *>::value>;\n\ntemplate <template <typename...> class Base>\nstruct is_template_base_of_impl {\n    template <typename... Us>\n    static std::true_type check(Base<Us...> *);\n    static std::false_type check(...);\n};\n\n/// Check if a template is the base of a type. For example:\n/// `is_template_base_of<Base, T>` is true if `struct T : Base<U> {}` where U can be anything\ntemplate <template <typename...> class Base, typename T>\n// Sadly, all MSVC versions incl. 2022 need the workaround, even in C++20 mode.\n// See also: https://github.com/pybind/pybind11/pull/3741\n#if !defined(_MSC_VER)\nusing is_template_base_of\n    = decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr));\n#else\nstruct is_template_base_of\n    : decltype(is_template_base_of_impl<Base>::check((intrinsic_t<T> *) nullptr)) {\n};\n#endif\n\n/// Check if T is an instantiation of the template `Class`. For example:\n/// `is_instantiation<shared_ptr, T>` is true if `T == shared_ptr<U>` where U can be anything.\ntemplate <template <typename...> class Class, typename T>\nstruct is_instantiation : std::false_type {};\ntemplate <template <typename...> class Class, typename... Us>\nstruct is_instantiation<Class, Class<Us...>> : std::true_type {};\n\n/// Check if T is std::shared_ptr<U> where U can be anything\ntemplate <typename T>\nusing is_shared_ptr = is_instantiation<std::shared_ptr, T>;\n\n/// Check if T looks like an input iterator\ntemplate <typename T, typename = void>\nstruct is_input_iterator : std::false_type {};\ntemplate <typename T>\nstruct is_input_iterator<T,\n                         void_t<decltype(*std::declval<T &>()), decltype(++std::declval<T &>())>>\n    : std::true_type {};\n\ntemplate <typename T>\nusing is_function_pointer\n    = bool_constant<std::is_pointer<T>::value\n                    && std::is_function<typename std::remove_pointer<T>::type>::value>;\n\ntemplate <typename F>\nstruct strip_function_object {\n    // If you are encountering an\n    // 'error: name followed by \"::\" must be a class or namespace name'\n    // with the Intel compiler and a noexcept function here,\n    // try to use noexcept(true) instead of plain noexcept.\n    using type = typename remove_class<decltype(&F::operator())>::type;\n};\n\n// Extracts the function signature from a function, function pointer or lambda.\ntemplate <typename Function, typename F = remove_reference_t<Function>>\nusing function_signature_t = conditional_t<\n    std::is_function<F>::value,\n    F,\n    typename conditional_t<std::is_pointer<F>::value || std::is_member_pointer<F>::value,\n                           std::remove_pointer<F>,\n                           strip_function_object<F>>::type>;\n\n/// Returns true if the type looks like a lambda: that is, isn't a function, pointer or member\n/// pointer.  Note that this can catch all sorts of other things, too; this is intended to be used\n/// in a place where passing a lambda makes sense.\ntemplate <typename T>\nusing is_lambda = satisfies_none_of<remove_reference_t<T>,\n                                    std::is_function,\n                                    std::is_pointer,\n                                    std::is_member_pointer>;\n\n// [workaround(intel)] Internal error on fold expression\n/// Apply a function over each element of a parameter pack\n#if defined(__cpp_fold_expressions) && !defined(__INTEL_COMPILER)\n// Intel compiler produces an internal error on this fold expression (tested with ICC 19.0.2)\n#    define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN) (((PATTERN), void()), ...)\n#else\nusing expand_side_effects = bool[];\n#    define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN)                                                 \\\n        (void) pybind11::detail::expand_side_effects { ((PATTERN), void(), false)..., false }\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// C++ bindings of builtin Python exceptions\nclass PYBIND11_EXPORT_EXCEPTION builtin_exception : public std::runtime_error {\npublic:\n    using std::runtime_error::runtime_error;\n    /// Set the error using the Python C API\n    virtual void set_error() const = 0;\n};\n\n#define PYBIND11_RUNTIME_EXCEPTION(name, type)                                                    \\\n    class PYBIND11_EXPORT_EXCEPTION name : public builtin_exception {                             \\\n    public:                                                                                       \\\n        using builtin_exception::builtin_exception;                                               \\\n        name() : name(\"\") {}                                                                      \\\n        void set_error() const override { PyErr_SetString(type, what()); }                        \\\n    };\n\nPYBIND11_RUNTIME_EXCEPTION(stop_iteration, PyExc_StopIteration)\nPYBIND11_RUNTIME_EXCEPTION(index_error, PyExc_IndexError)\nPYBIND11_RUNTIME_EXCEPTION(key_error, PyExc_KeyError)\nPYBIND11_RUNTIME_EXCEPTION(value_error, PyExc_ValueError)\nPYBIND11_RUNTIME_EXCEPTION(type_error, PyExc_TypeError)\nPYBIND11_RUNTIME_EXCEPTION(buffer_error, PyExc_BufferError)\nPYBIND11_RUNTIME_EXCEPTION(import_error, PyExc_ImportError)\nPYBIND11_RUNTIME_EXCEPTION(attribute_error, PyExc_AttributeError)\nPYBIND11_RUNTIME_EXCEPTION(cast_error, PyExc_RuntimeError) /// Thrown when pybind11::cast or\n                                                           /// handle::call fail due to a type\n                                                           /// casting error\nPYBIND11_RUNTIME_EXCEPTION(reference_cast_error, PyExc_RuntimeError) /// Used internally\n\n[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const char *reason) {\n    assert(!PyErr_Occurred());\n    throw std::runtime_error(reason);\n}\n[[noreturn]] PYBIND11_NOINLINE void pybind11_fail(const std::string &reason) {\n    assert(!PyErr_Occurred());\n    throw std::runtime_error(reason);\n}\n\ntemplate <typename T, typename SFINAE = void>\nstruct format_descriptor {};\n\ntemplate <typename T>\nstruct format_descriptor<\n    T,\n    detail::enable_if_t<detail::is_same_ignoring_cvref<T, PyObject *>::value>> {\n    static constexpr const char c = 'O';\n    static constexpr const char value[2] = {c, '\\0'};\n    static std::string format() { return std::string(1, c); }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n// Returns the index of the given type in the type char array below, and in the list in numpy.h\n// The order here is: bool; 8 ints ((signed,unsigned)x(8,16,32,64)bits); float,double,long double;\n// complex float,double,long double.  Note that the long double types only participate when long\n// double is actually longer than double (it isn't under MSVC).\n// NB: not only the string below but also complex.h and numpy.h rely on this order.\ntemplate <typename T, typename SFINAE = void>\nstruct is_fmt_numeric {\n    static constexpr bool value = false;\n};\ntemplate <typename T>\nstruct is_fmt_numeric<T, enable_if_t<std::is_arithmetic<T>::value>> {\n    static constexpr bool value = true;\n    static constexpr int index\n        = std::is_same<T, bool>::value\n              ? 0\n              : 1\n                    + (std::is_integral<T>::value\n                           ? detail::log2(sizeof(T)) * 2 + std::is_unsigned<T>::value\n                           : 8\n                                 + (std::is_same<T, double>::value        ? 1\n                                    : std::is_same<T, long double>::value ? 2\n                                                                          : 0));\n};\nPYBIND11_NAMESPACE_END(detail)\n\ntemplate <typename T>\nstruct format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>> {\n    static constexpr const char c = \"?bBhHiIqQfdg\"[detail::is_fmt_numeric<T>::index];\n    static constexpr const char value[2] = {c, '\\0'};\n    static std::string format() { return std::string(1, c); }\n};\n\n#if !defined(PYBIND11_CPP17)\n\ntemplate <typename T>\nconstexpr const char\n    format_descriptor<T, detail::enable_if_t<std::is_arithmetic<T>::value>>::value[2];\n\n#endif\n\n/// RAII wrapper that temporarily clears any Python error state\nstruct error_scope {\n    PyObject *type, *value, *trace;\n    error_scope() { PyErr_Fetch(&type, &value, &trace); }\n    error_scope(const error_scope &) = delete;\n    error_scope &operator=(const error_scope &) = delete;\n    ~error_scope() { PyErr_Restore(type, value, trace); }\n};\n\n/// Dummy destructor wrapper that can be used to expose classes with a private destructor\nstruct nodelete {\n    template <typename T>\n    void operator()(T *) {}\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\ntemplate <typename... Args>\nstruct overload_cast_impl {\n    template <typename Return>\n    constexpr auto operator()(Return (*pf)(Args...)) const noexcept -> decltype(pf) {\n        return pf;\n    }\n\n    template <typename Return, typename Class>\n    constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept\n        -> decltype(pmf) {\n        return pmf;\n    }\n\n    template <typename Return, typename Class>\n    constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept\n        -> decltype(pmf) {\n        return pmf;\n    }\n};\nPYBIND11_NAMESPACE_END(detail)\n\n// overload_cast requires variable templates: C++14\n#if defined(PYBIND11_CPP14)\n#    define PYBIND11_OVERLOAD_CAST 1\n/// Syntax sugar for resolving overloaded function pointers:\n///  - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)\n///  - sweet:   overload_cast<Arg0, Arg1, Arg2>(&Class::func)\ntemplate <typename... Args>\nstatic constexpr detail::overload_cast_impl<Args...> overload_cast{};\n#endif\n\n/// Const member function selector for overload_cast\n///  - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)\n///  - sweet:   overload_cast<Arg>(&Class::func, const_)\nstatic constexpr auto const_ = std::true_type{};\n\n#if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails:\ntemplate <typename... Args>\nstruct overload_cast {\n    static_assert(detail::deferred_t<std::false_type, Args...>::value,\n                  \"pybind11::overload_cast<...> requires compiling in C++14 mode\");\n};\n#endif // overload_cast\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Adaptor for converting arbitrary container arguments into a vector; implicitly convertible from\n// any standard container (or C-style array) supporting std::begin/std::end, any singleton\n// arithmetic type (if T is arithmetic), or explicitly constructible from an iterator pair.\ntemplate <typename T>\nclass any_container {\n    std::vector<T> v;\n\npublic:\n    any_container() = default;\n\n    // Can construct from a pair of iterators\n    template <typename It, typename = enable_if_t<is_input_iterator<It>::value>>\n    any_container(It first, It last) : v(first, last) {}\n\n    // Implicit conversion constructor from any arbitrary container type\n    // with values convertible to T\n    template <typename Container,\n              typename = enable_if_t<\n                  std::is_convertible<decltype(*std::begin(std::declval<const Container &>())),\n                                      T>::value>>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    any_container(const Container &c) : any_container(std::begin(c), std::end(c)) {}\n\n    // initializer_list's aren't deducible, so don't get matched by the above template;\n    // we need this to explicitly allow implicit conversion from one:\n    template <typename TIn, typename = enable_if_t<std::is_convertible<TIn, T>::value>>\n    any_container(const std::initializer_list<TIn> &c) : any_container(c.begin(), c.end()) {}\n\n    // Avoid copying if given an rvalue vector of the correct type.\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    any_container(std::vector<T> &&v) : v(std::move(v)) {}\n\n    // Moves the vector out of an rvalue any_container\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator std::vector<T> &&() && { return std::move(v); }\n\n    // Dereferencing obtains a reference to the underlying vector\n    std::vector<T> &operator*() { return v; }\n    const std::vector<T> &operator*() const { return v; }\n\n    // -> lets you call methods on the underlying vector\n    std::vector<T> *operator->() { return &v; }\n    const std::vector<T> *operator->() const { return &v; }\n};\n\n// Forward-declaration; see detail/class.h\nstd::string get_fully_qualified_tp_name(PyTypeObject *);\n\ntemplate <typename T>\ninline static std::shared_ptr<T>\ntry_get_shared_from_this(std::enable_shared_from_this<T> *holder_value_ptr) {\n// Pre C++17, this code path exploits undefined behavior, but is known to work on many platforms.\n// Use at your own risk!\n// See also https://en.cppreference.com/w/cpp/memory/enable_shared_from_this, and in particular\n// the `std::shared_ptr<Good> gp1 = not_so_good.getptr();` and `try`-`catch` parts of the example.\n#if defined(__cpp_lib_enable_shared_from_this) && (!defined(_MSC_VER) || _MSC_VER >= 1912)\n    return holder_value_ptr->weak_from_this().lock();\n#else\n    try {\n        return holder_value_ptr->shared_from_this();\n    } catch (const std::bad_weak_ptr &) {\n        return nullptr;\n    }\n#endif\n}\n\n// For silencing \"unused\" compiler warnings in special situations.\ntemplate <typename... Args>\n#if defined(_MSC_VER) && _MSC_VER < 1920 // MSVC 2017\nconstexpr\n#endif\n    inline void\n    silence_unused_warnings(Args &&...) {\n}\n\n// MSVC warning C4100: Unreferenced formal parameter\n#if defined(_MSC_VER) && _MSC_VER <= 1916\n#    define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...)                                         \\\n        detail::silence_unused_warnings(__VA_ARGS__)\n#else\n#    define PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(...)\n#endif\n\n// GCC -Wunused-but-set-parameter  All GCC versions (as of July 2021).\n#if defined(__GNUG__) && !defined(__clang__) && !defined(__INTEL_COMPILER)\n#    define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...)                       \\\n        detail::silence_unused_warnings(__VA_ARGS__)\n#else\n#    define PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(...)\n#endif\n\n#if defined(__clang__)                                                                            \\\n    && (defined(__apple_build_version__) /* AppleClang 13.0.0.13000029 was the only data point    \\\n                                            available. */                                         \\\n        || (__clang_major__ >= 7                                                                  \\\n            && __clang_major__ <= 12) /* Clang 3, 5, 13, 14, 15 do not generate the warning. */   \\\n    )\n#    define PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING\n// Example:\n// tests/test_kwargs_and_defaults.cpp:46:68: error: local variable 'args' will be copied despite\n// being returned by name [-Werror,-Wreturn-std-move]\n//     m.def(\"args_function\", [](py::args args) -> py::tuple { return args; });\n//                                                                    ^~~~\n// test_kwargs_and_defaults.cpp:46:68: note: call 'std::move' explicitly to avoid copying\n//     m.def(\"args_function\", [](py::args args) -> py::tuple { return args; });\n//                                                                    ^~~~\n//                                                                    std::move(args)\n#endif\n\n// Pybind offers detailed error messages by default for all builts that are debug (through the\n// negation of NDEBUG). This can also be manually enabled by users, for any builds, through\n// defining PYBIND11_DETAILED_ERROR_MESSAGES. This information is primarily useful for those\n// who are writing (as opposed to merely using) libraries that use pybind11.\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(NDEBUG)\n#    define PYBIND11_DETAILED_ERROR_MESSAGES\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/descr.h",
    "content": "/*\n    pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"common.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n#if !defined(_MSC_VER)\n#    define PYBIND11_DESCR_CONSTEXPR static constexpr\n#else\n#    define PYBIND11_DESCR_CONSTEXPR const\n#endif\n\n/* Concatenate type signatures at compile time */\ntemplate <size_t N, typename... Ts>\nstruct descr {\n    char text[N + 1]{'\\0'};\n\n    constexpr descr() = default;\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    constexpr descr(char const (&s)[N + 1]) : descr(s, make_index_sequence<N>()) {}\n\n    template <size_t... Is>\n    constexpr descr(char const (&s)[N + 1], index_sequence<Is...>) : text{s[Is]..., '\\0'} {}\n\n    template <typename... Chars>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    constexpr descr(char c, Chars... cs) : text{c, static_cast<char>(cs)..., '\\0'} {}\n\n    static constexpr std::array<const std::type_info *, sizeof...(Ts) + 1> types() {\n        return {{&typeid(Ts)..., nullptr}};\n    }\n};\n\ntemplate <size_t N1, size_t N2, typename... Ts1, typename... Ts2, size_t... Is1, size_t... Is2>\nconstexpr descr<N1 + N2, Ts1..., Ts2...> plus_impl(const descr<N1, Ts1...> &a,\n                                                   const descr<N2, Ts2...> &b,\n                                                   index_sequence<Is1...>,\n                                                   index_sequence<Is2...>) {\n    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(b);\n    return {a.text[Is1]..., b.text[Is2]...};\n}\n\ntemplate <size_t N1, size_t N2, typename... Ts1, typename... Ts2>\nconstexpr descr<N1 + N2, Ts1..., Ts2...> operator+(const descr<N1, Ts1...> &a,\n                                                   const descr<N2, Ts2...> &b) {\n    return plus_impl(a, b, make_index_sequence<N1>(), make_index_sequence<N2>());\n}\n\ntemplate <size_t N>\nconstexpr descr<N - 1> const_name(char const (&text)[N]) {\n    return descr<N - 1>(text);\n}\nconstexpr descr<0> const_name(char const (&)[1]) { return {}; }\n\ntemplate <size_t Rem, size_t... Digits>\nstruct int_to_str : int_to_str<Rem / 10, Rem % 10, Digits...> {};\ntemplate <size_t... Digits>\nstruct int_to_str<0, Digits...> {\n    // WARNING: This only works with C++17 or higher.\n    static constexpr auto digits = descr<sizeof...(Digits)>(('0' + Digits)...);\n};\n\n// Ternary description (like std::conditional)\ntemplate <bool B, size_t N1, size_t N2>\nconstexpr enable_if_t<B, descr<N1 - 1>> const_name(char const (&text1)[N1], char const (&)[N2]) {\n    return const_name(text1);\n}\ntemplate <bool B, size_t N1, size_t N2>\nconstexpr enable_if_t<!B, descr<N2 - 1>> const_name(char const (&)[N1], char const (&text2)[N2]) {\n    return const_name(text2);\n}\n\ntemplate <bool B, typename T1, typename T2>\nconstexpr enable_if_t<B, T1> const_name(const T1 &d, const T2 &) {\n    return d;\n}\ntemplate <bool B, typename T1, typename T2>\nconstexpr enable_if_t<!B, T2> const_name(const T1 &, const T2 &d) {\n    return d;\n}\n\ntemplate <size_t Size>\nauto constexpr const_name() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {\n    return int_to_str<Size / 10, Size % 10>::digits;\n}\n\ntemplate <typename Type>\nconstexpr descr<1, Type> const_name() {\n    return {'%'};\n}\n\n// If \"_\" is defined as a macro, py::detail::_ cannot be provided.\n// It is therefore best to use py::detail::const_name universally.\n// This block is for backward compatibility only.\n// (The const_name code is repeated to avoid introducing a \"_\" #define ourselves.)\n#ifndef _\n#    define PYBIND11_DETAIL_UNDERSCORE_BACKWARD_COMPATIBILITY\ntemplate <size_t N>\nconstexpr descr<N - 1> _(char const (&text)[N]) {\n    return const_name<N>(text);\n}\ntemplate <bool B, size_t N1, size_t N2>\nconstexpr enable_if_t<B, descr<N1 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {\n    return const_name<B, N1, N2>(text1, text2);\n}\ntemplate <bool B, size_t N1, size_t N2>\nconstexpr enable_if_t<!B, descr<N2 - 1>> _(char const (&text1)[N1], char const (&text2)[N2]) {\n    return const_name<B, N1, N2>(text1, text2);\n}\ntemplate <bool B, typename T1, typename T2>\nconstexpr enable_if_t<B, T1> _(const T1 &d1, const T2 &d2) {\n    return const_name<B, T1, T2>(d1, d2);\n}\ntemplate <bool B, typename T1, typename T2>\nconstexpr enable_if_t<!B, T2> _(const T1 &d1, const T2 &d2) {\n    return const_name<B, T1, T2>(d1, d2);\n}\n\ntemplate <size_t Size>\nauto constexpr _() -> remove_cv_t<decltype(int_to_str<Size / 10, Size % 10>::digits)> {\n    return const_name<Size>();\n}\ntemplate <typename Type>\nconstexpr descr<1, Type> _() {\n    return const_name<Type>();\n}\n#endif // #ifndef _\n\nconstexpr descr<0> concat() { return {}; }\n\ntemplate <size_t N, typename... Ts>\nconstexpr descr<N, Ts...> concat(const descr<N, Ts...> &descr) {\n    return descr;\n}\n\n#ifdef __cpp_fold_expressions\ntemplate <size_t N1, size_t N2, typename... Ts1, typename... Ts2>\nconstexpr descr<N1 + N2 + 2, Ts1..., Ts2...> operator,(const descr<N1, Ts1...> &a,\n                                                       const descr<N2, Ts2...> &b) {\n    return a + const_name(\", \") + b;\n}\n\ntemplate <size_t N, typename... Ts, typename... Args>\nconstexpr auto concat(const descr<N, Ts...> &d, const Args &...args) {\n    return (d, ..., args);\n}\n#else\ntemplate <size_t N, typename... Ts, typename... Args>\nconstexpr auto concat(const descr<N, Ts...> &d, const Args &...args)\n    -> decltype(std::declval<descr<N + 2, Ts...>>() + concat(args...)) {\n    return d + const_name(\", \") + concat(args...);\n}\n#endif\n\ntemplate <size_t N, typename... Ts>\nconstexpr descr<N + 2, Ts...> type_descr(const descr<N, Ts...> &descr) {\n    return const_name(\"{\") + descr + const_name(\"}\");\n}\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/init.h",
    "content": "/*\n    pybind11/detail/init.h: init factory function implementation and support code.\n\n    Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"class.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nclass type_caster<value_and_holder> {\npublic:\n    bool load(handle h, bool) {\n        value = reinterpret_cast<value_and_holder *>(h.ptr());\n        return true;\n    }\n\n    template <typename>\n    using cast_op_type = value_and_holder &;\n    explicit operator value_and_holder &() { return *value; }\n    static constexpr auto name = const_name<value_and_holder>();\n\nprivate:\n    value_and_holder *value = nullptr;\n};\n\nPYBIND11_NAMESPACE_BEGIN(initimpl)\n\ninline void no_nullptr(void *ptr) {\n    if (!ptr) {\n        throw type_error(\"pybind11::init(): factory function returned nullptr\");\n    }\n}\n\n// Implementing functions for all forms of py::init<...> and py::init(...)\ntemplate <typename Class>\nusing Cpp = typename Class::type;\ntemplate <typename Class>\nusing Alias = typename Class::type_alias;\ntemplate <typename Class>\nusing Holder = typename Class::holder_type;\n\ntemplate <typename Class>\nusing is_alias_constructible = std::is_constructible<Alias<Class>, Cpp<Class> &&>;\n\n// Takes a Cpp pointer and returns true if it actually is a polymorphic Alias instance.\ntemplate <typename Class, enable_if_t<Class::has_alias, int> = 0>\nbool is_alias(Cpp<Class> *ptr) {\n    return dynamic_cast<Alias<Class> *>(ptr) != nullptr;\n}\n// Failing fallback version of the above for a no-alias class (always returns false)\ntemplate <typename /*Class*/>\nconstexpr bool is_alias(void *) {\n    return false;\n}\n\n// Constructs and returns a new object; if the given arguments don't map to a constructor, we fall\n// back to brace aggregate initialization so that for aggregate initialization can be used with\n// py::init, e.g.  `py::init<int, int>` to initialize a `struct T { int a; int b; }`.  For\n// non-aggregate types, we need to use an ordinary T(...) constructor (invoking as `T{...}` usually\n// works, but will not do the expected thing when `T` has an `initializer_list<T>` constructor).\ntemplate <typename Class,\n          typename... Args,\n          detail::enable_if_t<std::is_constructible<Class, Args...>::value, int> = 0>\ninline Class *construct_or_initialize(Args &&...args) {\n    return new Class(std::forward<Args>(args)...);\n}\ntemplate <typename Class,\n          typename... Args,\n          detail::enable_if_t<!std::is_constructible<Class, Args...>::value, int> = 0>\ninline Class *construct_or_initialize(Args &&...args) {\n    return new Class{std::forward<Args>(args)...};\n}\n\n// Attempts to constructs an alias using a `Alias(Cpp &&)` constructor.  This allows types with\n// an alias to provide only a single Cpp factory function as long as the Alias can be\n// constructed from an rvalue reference of the base Cpp type.  This means that Alias classes\n// can, when appropriate, simply define a `Alias(Cpp &&)` constructor rather than needing to\n// inherit all the base class constructors.\ntemplate <typename Class>\nvoid construct_alias_from_cpp(std::true_type /*is_alias_constructible*/,\n                              value_and_holder &v_h,\n                              Cpp<Class> &&base) {\n    v_h.value_ptr() = new Alias<Class>(std::move(base));\n}\ntemplate <typename Class>\n[[noreturn]] void construct_alias_from_cpp(std::false_type /*!is_alias_constructible*/,\n                                           value_and_holder &,\n                                           Cpp<Class> &&) {\n    throw type_error(\"pybind11::init(): unable to convert returned instance to required \"\n                     \"alias class: no `Alias<Class>(Class &&)` constructor available\");\n}\n\n// Error-generating fallback for factories that don't match one of the below construction\n// mechanisms.\ntemplate <typename Class>\nvoid construct(...) {\n    static_assert(!std::is_same<Class, Class>::value /* always false */,\n                  \"pybind11::init(): init function must return a compatible pointer, \"\n                  \"holder, or value\");\n}\n\n// Pointer return v1: the factory function returns a class pointer for a registered class.\n// If we don't need an alias (because this class doesn't have one, or because the final type is\n// inherited on the Python side) we can simply take over ownership.  Otherwise we need to try to\n// construct an Alias from the returned base instance.\ntemplate <typename Class>\nvoid construct(value_and_holder &v_h, Cpp<Class> *ptr, bool need_alias) {\n    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);\n    no_nullptr(ptr);\n    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {\n        // We're going to try to construct an alias by moving the cpp type.  Whether or not\n        // that succeeds, we still need to destroy the original cpp pointer (either the\n        // moved away leftover, if the alias construction works, or the value itself if we\n        // throw an error), but we can't just call `delete ptr`: it might have a special\n        // deleter, or might be shared_from_this.  So we construct a holder around it as if\n        // it was a normal instance, then steal the holder away into a local variable; thus\n        // the holder and destruction happens when we leave the C++ scope, and the holder\n        // class gets to handle the destruction however it likes.\n        v_h.value_ptr() = ptr;\n        v_h.set_instance_registered(true);          // To prevent init_instance from registering it\n        v_h.type->init_instance(v_h.inst, nullptr); // Set up the holder\n        Holder<Class> temp_holder(std::move(v_h.holder<Holder<Class>>())); // Steal the holder\n        v_h.type->dealloc(v_h); // Destroys the moved-out holder remains, resets value ptr to null\n        v_h.set_instance_registered(false);\n\n        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(*ptr));\n    } else {\n        // Otherwise the type isn't inherited, so we don't need an Alias\n        v_h.value_ptr() = ptr;\n    }\n}\n\n// Pointer return v2: a factory that always returns an alias instance ptr.  We simply take over\n// ownership of the pointer.\ntemplate <typename Class, enable_if_t<Class::has_alias, int> = 0>\nvoid construct(value_and_holder &v_h, Alias<Class> *alias_ptr, bool) {\n    no_nullptr(alias_ptr);\n    v_h.value_ptr() = static_cast<Cpp<Class> *>(alias_ptr);\n}\n\n// Holder return: copy its pointer, and move or copy the returned holder into the new instance's\n// holder.  This also handles types like std::shared_ptr<T> and std::unique_ptr<T> where T is a\n// derived type (through those holder's implicit conversion from derived class holder\n// constructors).\ntemplate <typename Class>\nvoid construct(value_and_holder &v_h, Holder<Class> holder, bool need_alias) {\n    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);\n    auto *ptr = holder_helper<Holder<Class>>::get(holder);\n    no_nullptr(ptr);\n    // If we need an alias, check that the held pointer is actually an alias instance\n    if (Class::has_alias && need_alias && !is_alias<Class>(ptr)) {\n        throw type_error(\"pybind11::init(): construction failed: returned holder-wrapped instance \"\n                         \"is not an alias instance\");\n    }\n\n    v_h.value_ptr() = ptr;\n    v_h.type->init_instance(v_h.inst, &holder);\n}\n\n// return-by-value version 1: returning a cpp class by value.  If the class has an alias and an\n// alias is required the alias must have an `Alias(Cpp &&)` constructor so that we can construct\n// the alias from the base when needed (i.e. because of Python-side inheritance).  When we don't\n// need it, we simply move-construct the cpp value into a new instance.\ntemplate <typename Class>\nvoid construct(value_and_holder &v_h, Cpp<Class> &&result, bool need_alias) {\n    PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(need_alias);\n    static_assert(is_move_constructible<Cpp<Class>>::value,\n                  \"pybind11::init() return-by-value factory function requires a movable class\");\n    if (Class::has_alias && need_alias) {\n        construct_alias_from_cpp<Class>(is_alias_constructible<Class>{}, v_h, std::move(result));\n    } else {\n        v_h.value_ptr() = new Cpp<Class>(std::move(result));\n    }\n}\n\n// return-by-value version 2: returning a value of the alias type itself.  We move-construct an\n// Alias instance (even if no the python-side inheritance is involved).  The is intended for\n// cases where Alias initialization is always desired.\ntemplate <typename Class>\nvoid construct(value_and_holder &v_h, Alias<Class> &&result, bool) {\n    static_assert(\n        is_move_constructible<Alias<Class>>::value,\n        \"pybind11::init() return-by-alias-value factory function requires a movable alias class\");\n    v_h.value_ptr() = new Alias<Class>(std::move(result));\n}\n\n// Implementing class for py::init<...>()\ntemplate <typename... Args>\nstruct constructor {\n    template <typename Class, typename... Extra, enable_if_t<!Class::has_alias, int> = 0>\n    static void execute(Class &cl, const Extra &...extra) {\n        cl.def(\n            \"__init__\",\n            [](value_and_holder &v_h, Args... args) {\n                v_h.value_ptr() = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n\n    template <\n        typename Class,\n        typename... Extra,\n        enable_if_t<Class::has_alias && std::is_constructible<Cpp<Class>, Args...>::value, int>\n        = 0>\n    static void execute(Class &cl, const Extra &...extra) {\n        cl.def(\n            \"__init__\",\n            [](value_and_holder &v_h, Args... args) {\n                if (Py_TYPE(v_h.inst) == v_h.type->type) {\n                    v_h.value_ptr()\n                        = construct_or_initialize<Cpp<Class>>(std::forward<Args>(args)...);\n                } else {\n                    v_h.value_ptr()\n                        = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);\n                }\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n\n    template <\n        typename Class,\n        typename... Extra,\n        enable_if_t<Class::has_alias && !std::is_constructible<Cpp<Class>, Args...>::value, int>\n        = 0>\n    static void execute(Class &cl, const Extra &...extra) {\n        cl.def(\n            \"__init__\",\n            [](value_and_holder &v_h, Args... args) {\n                v_h.value_ptr()\n                    = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n};\n\n// Implementing class for py::init_alias<...>()\ntemplate <typename... Args>\nstruct alias_constructor {\n    template <\n        typename Class,\n        typename... Extra,\n        enable_if_t<Class::has_alias && std::is_constructible<Alias<Class>, Args...>::value, int>\n        = 0>\n    static void execute(Class &cl, const Extra &...extra) {\n        cl.def(\n            \"__init__\",\n            [](value_and_holder &v_h, Args... args) {\n                v_h.value_ptr()\n                    = construct_or_initialize<Alias<Class>>(std::forward<Args>(args)...);\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n};\n\n// Implementation class for py::init(Func) and py::init(Func, AliasFunc)\ntemplate <typename CFunc,\n          typename AFunc = void_type (*)(),\n          typename = function_signature_t<CFunc>,\n          typename = function_signature_t<AFunc>>\nstruct factory;\n\n// Specialization for py::init(Func)\ntemplate <typename Func, typename Return, typename... Args>\nstruct factory<Func, void_type (*)(), Return(Args...)> {\n    remove_reference_t<Func> class_factory;\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    factory(Func &&f) : class_factory(std::forward<Func>(f)) {}\n\n    // The given class either has no alias or has no separate alias factory;\n    // this always constructs the class itself.  If the class is registered with an alias\n    // type and an alias instance is needed (i.e. because the final type is a Python class\n    // inheriting from the C++ type) the returned value needs to either already be an alias\n    // instance, or the alias needs to be constructible from a `Class &&` argument.\n    template <typename Class, typename... Extra>\n    void execute(Class &cl, const Extra &...extra) && {\n#if defined(PYBIND11_CPP14)\n        cl.def(\n            \"__init__\",\n            [func = std::move(class_factory)]\n#else\n        auto &func = class_factory;\n        cl.def(\n            \"__init__\",\n            [func]\n#endif\n            (value_and_holder &v_h, Args... args) {\n                construct<Class>(\n                    v_h, func(std::forward<Args>(args)...), Py_TYPE(v_h.inst) != v_h.type->type);\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n};\n\n// Specialization for py::init(Func, AliasFunc)\ntemplate <typename CFunc,\n          typename AFunc,\n          typename CReturn,\n          typename... CArgs,\n          typename AReturn,\n          typename... AArgs>\nstruct factory<CFunc, AFunc, CReturn(CArgs...), AReturn(AArgs...)> {\n    static_assert(sizeof...(CArgs) == sizeof...(AArgs),\n                  \"pybind11::init(class_factory, alias_factory): class and alias factories \"\n                  \"must have identical argument signatures\");\n    static_assert(all_of<std::is_same<CArgs, AArgs>...>::value,\n                  \"pybind11::init(class_factory, alias_factory): class and alias factories \"\n                  \"must have identical argument signatures\");\n\n    remove_reference_t<CFunc> class_factory;\n    remove_reference_t<AFunc> alias_factory;\n\n    factory(CFunc &&c, AFunc &&a)\n        : class_factory(std::forward<CFunc>(c)), alias_factory(std::forward<AFunc>(a)) {}\n\n    // The class factory is called when the `self` type passed to `__init__` is the direct\n    // class (i.e. not inherited), the alias factory when `self` is a Python-side subtype.\n    template <typename Class, typename... Extra>\n    void execute(Class &cl, const Extra &...extra) && {\n        static_assert(Class::has_alias,\n                      \"The two-argument version of `py::init()` can \"\n                      \"only be used if the class has an alias\");\n#if defined(PYBIND11_CPP14)\n        cl.def(\n            \"__init__\",\n            [class_func = std::move(class_factory), alias_func = std::move(alias_factory)]\n#else\n        auto &class_func = class_factory;\n        auto &alias_func = alias_factory;\n        cl.def(\n            \"__init__\",\n            [class_func, alias_func]\n#endif\n            (value_and_holder &v_h, CArgs... args) {\n                if (Py_TYPE(v_h.inst) == v_h.type->type) {\n                    // If the instance type equals the registered type we don't have inheritance,\n                    // so don't need the alias and can construct using the class function:\n                    construct<Class>(v_h, class_func(std::forward<CArgs>(args)...), false);\n                } else {\n                    construct<Class>(v_h, alias_func(std::forward<CArgs>(args)...), true);\n                }\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n};\n\n/// Set just the C++ state. Same as `__init__`.\ntemplate <typename Class, typename T>\nvoid setstate(value_and_holder &v_h, T &&result, bool need_alias) {\n    construct<Class>(v_h, std::forward<T>(result), need_alias);\n}\n\n/// Set both the C++ and Python states\ntemplate <typename Class,\n          typename T,\n          typename O,\n          enable_if_t<std::is_convertible<O, handle>::value, int> = 0>\nvoid setstate(value_and_holder &v_h, std::pair<T, O> &&result, bool need_alias) {\n    construct<Class>(v_h, std::move(result.first), need_alias);\n    auto d = handle(result.second);\n    if (PyDict_Check(d.ptr()) && PyDict_Size(d.ptr()) == 0) {\n        // Skipping setattr below, to not force use of py::dynamic_attr() for Class unnecessarily.\n        // See PR #2972 for details.\n        return;\n    }\n    setattr((PyObject *) v_h.inst, \"__dict__\", d);\n}\n\n/// Implementation for py::pickle(GetState, SetState)\ntemplate <typename Get,\n          typename Set,\n          typename = function_signature_t<Get>,\n          typename = function_signature_t<Set>>\nstruct pickle_factory;\n\ntemplate <typename Get,\n          typename Set,\n          typename RetState,\n          typename Self,\n          typename NewInstance,\n          typename ArgState>\nstruct pickle_factory<Get, Set, RetState(Self), NewInstance(ArgState)> {\n    static_assert(std::is_same<intrinsic_t<RetState>, intrinsic_t<ArgState>>::value,\n                  \"The type returned by `__getstate__` must be the same \"\n                  \"as the argument accepted by `__setstate__`\");\n\n    remove_reference_t<Get> get;\n    remove_reference_t<Set> set;\n\n    pickle_factory(Get get, Set set) : get(std::forward<Get>(get)), set(std::forward<Set>(set)) {}\n\n    template <typename Class, typename... Extra>\n    void execute(Class &cl, const Extra &...extra) && {\n        cl.def(\"__getstate__\", std::move(get));\n\n#if defined(PYBIND11_CPP14)\n        cl.def(\n            \"__setstate__\",\n            [func = std::move(set)]\n#else\n        auto &func = set;\n        cl.def(\n            \"__setstate__\",\n            [func]\n#endif\n            (value_and_holder &v_h, ArgState state) {\n                setstate<Class>(\n                    v_h, func(std::forward<ArgState>(state)), Py_TYPE(v_h.inst) != v_h.type->type);\n            },\n            is_new_style_constructor(),\n            extra...);\n    }\n};\n\nPYBIND11_NAMESPACE_END(initimpl)\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/internals.h",
    "content": "/*\n    pybind11/detail/internals.h: Internal data structure and related functions\n\n    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"common.h\"\n\n#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n#    include \"../gil.h\"\n#endif\n\n#include \"../pytypes.h\"\n\n#include <exception>\n\n/// Tracks the `internals` and `type_info` ABI version independent of the main library version.\n///\n/// Some portions of the code use an ABI that is conditional depending on this\n/// version number.  That allows ABI-breaking changes to be \"pre-implemented\".\n/// Once the default version number is incremented, the conditional logic that\n/// no longer applies can be removed.  Additionally, users that need not\n/// maintain ABI compatibility can increase the version number in order to take\n/// advantage of any functionality/efficiency improvements that depend on the\n/// newer ABI.\n///\n/// WARNING: If you choose to manually increase the ABI version, note that\n/// pybind11 may not be tested as thoroughly with a non-default ABI version, and\n/// further ABI-incompatible changes may be made before the ABI is officially\n/// changed to the new version.\n#ifndef PYBIND11_INTERNALS_VERSION\n#    if PY_VERSION_HEX >= 0x030C0000 || defined(_MSC_VER)\n// Version bump for Python 3.12+, before first 3.12 beta release.\n// Version bump for MSVC piggy-backed on PR #4779. See comments there.\n#        define PYBIND11_INTERNALS_VERSION 5\n#    else\n#        define PYBIND11_INTERNALS_VERSION 4\n#    endif\n#endif\n\n// This requirement is mainly to reduce the support burden (see PR #4570).\nstatic_assert(PY_VERSION_HEX < 0x030C0000 || PYBIND11_INTERNALS_VERSION >= 5,\n              \"pybind11 ABI version 5 is the minimum for Python 3.12+\");\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nusing ExceptionTranslator = void (*)(std::exception_ptr);\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\nconstexpr const char *internals_function_record_capsule_name = \"pybind11_function_record_capsule\";\n\n// Forward declarations\ninline PyTypeObject *make_static_property_type();\ninline PyTypeObject *make_default_metaclass();\ninline PyObject *make_object_base_type(PyTypeObject *metaclass);\n\n// The old Python Thread Local Storage (TLS) API is deprecated in Python 3.7 in favor of the new\n// Thread Specific Storage (TSS) API.\n#if PY_VERSION_HEX >= 0x03070000\n// Avoid unnecessary allocation of `Py_tss_t`, since we cannot use\n// `Py_LIMITED_API` anyway.\n#    if PYBIND11_INTERNALS_VERSION > 4\n#        define PYBIND11_TLS_KEY_REF Py_tss_t &\n#        if defined(__clang__)\n#            define PYBIND11_TLS_KEY_INIT(var)                                                    \\\n                _Pragma(\"clang diagnostic push\")                                         /**/     \\\n                    _Pragma(\"clang diagnostic ignored \\\"-Wmissing-field-initializers\\\"\") /**/     \\\n                    Py_tss_t var                                                                  \\\n                    = Py_tss_NEEDS_INIT;                                                          \\\n                _Pragma(\"clang diagnostic pop\")\n#        elif defined(__GNUC__) && !defined(__INTEL_COMPILER)\n#            define PYBIND11_TLS_KEY_INIT(var)                                                    \\\n                _Pragma(\"GCC diagnostic push\")                                         /**/       \\\n                    _Pragma(\"GCC diagnostic ignored \\\"-Wmissing-field-initializers\\\"\") /**/       \\\n                    Py_tss_t var                                                                  \\\n                    = Py_tss_NEEDS_INIT;                                                          \\\n                _Pragma(\"GCC diagnostic pop\")\n#        else\n#            define PYBIND11_TLS_KEY_INIT(var) Py_tss_t var = Py_tss_NEEDS_INIT;\n#        endif\n#        define PYBIND11_TLS_KEY_CREATE(var) (PyThread_tss_create(&(var)) == 0)\n#        define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get(&(key))\n#        define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set(&(key), (value))\n#        define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set(&(key), nullptr)\n#        define PYBIND11_TLS_FREE(key) PyThread_tss_delete(&(key))\n#    else\n#        define PYBIND11_TLS_KEY_REF Py_tss_t *\n#        define PYBIND11_TLS_KEY_INIT(var) Py_tss_t *var = nullptr;\n#        define PYBIND11_TLS_KEY_CREATE(var)                                                      \\\n            (((var) = PyThread_tss_alloc()) != nullptr && (PyThread_tss_create((var)) == 0))\n#        define PYBIND11_TLS_GET_VALUE(key) PyThread_tss_get((key))\n#        define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_tss_set((key), (value))\n#        define PYBIND11_TLS_DELETE_VALUE(key) PyThread_tss_set((key), nullptr)\n#        define PYBIND11_TLS_FREE(key) PyThread_tss_free(key)\n#    endif\n#else\n// Usually an int but a long on Cygwin64 with Python 3.x\n#    define PYBIND11_TLS_KEY_REF decltype(PyThread_create_key())\n#    define PYBIND11_TLS_KEY_INIT(var) PYBIND11_TLS_KEY_REF var = 0;\n#    define PYBIND11_TLS_KEY_CREATE(var) (((var) = PyThread_create_key()) != -1)\n#    define PYBIND11_TLS_GET_VALUE(key) PyThread_get_key_value((key))\n#    if defined(PYPY_VERSION)\n// On CPython < 3.4 and on PyPy, `PyThread_set_key_value` strangely does not set\n// the value if it has already been set.  Instead, it must first be deleted and\n// then set again.\ninline void tls_replace_value(PYBIND11_TLS_KEY_REF key, void *value) {\n    PyThread_delete_key_value(key);\n    PyThread_set_key_value(key, value);\n}\n#        define PYBIND11_TLS_DELETE_VALUE(key) PyThread_delete_key_value(key)\n#        define PYBIND11_TLS_REPLACE_VALUE(key, value)                                            \\\n            ::pybind11::detail::tls_replace_value((key), (value))\n#    else\n#        define PYBIND11_TLS_DELETE_VALUE(key) PyThread_set_key_value((key), nullptr)\n#        define PYBIND11_TLS_REPLACE_VALUE(key, value) PyThread_set_key_value((key), (value))\n#    endif\n#    define PYBIND11_TLS_FREE(key) (void) key\n#endif\n\n// Python loads modules by default with dlopen with the RTLD_LOCAL flag; under libc++ and possibly\n// other STLs, this means `typeid(A)` from one module won't equal `typeid(A)` from another module\n// even when `A` is the same, non-hidden-visibility type (e.g. from a common include).  Under\n// libstdc++, this doesn't happen: equality and the type_index hash are based on the type name,\n// which works.  If not under a known-good stl, provide our own name-based hash and equality\n// functions that use the type name.\n#if (PYBIND11_INTERNALS_VERSION <= 4 && defined(__GLIBCXX__))                                     \\\n    || (PYBIND11_INTERNALS_VERSION >= 5 && !defined(_LIBCPP_VERSION))\ninline bool same_type(const std::type_info &lhs, const std::type_info &rhs) { return lhs == rhs; }\nusing type_hash = std::hash<std::type_index>;\nusing type_equal_to = std::equal_to<std::type_index>;\n#else\ninline bool same_type(const std::type_info &lhs, const std::type_info &rhs) {\n    return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;\n}\n\nstruct type_hash {\n    size_t operator()(const std::type_index &t) const {\n        size_t hash = 5381;\n        const char *ptr = t.name();\n        while (auto c = static_cast<unsigned char>(*ptr++)) {\n            hash = (hash * 33) ^ c;\n        }\n        return hash;\n    }\n};\n\nstruct type_equal_to {\n    bool operator()(const std::type_index &lhs, const std::type_index &rhs) const {\n        return lhs.name() == rhs.name() || std::strcmp(lhs.name(), rhs.name()) == 0;\n    }\n};\n#endif\n\ntemplate <typename value_type>\nusing type_map = std::unordered_map<std::type_index, value_type, type_hash, type_equal_to>;\n\nstruct override_hash {\n    inline size_t operator()(const std::pair<const PyObject *, const char *> &v) const {\n        size_t value = std::hash<const void *>()(v.first);\n        value ^= std::hash<const void *>()(v.second) + 0x9e3779b9 + (value << 6) + (value >> 2);\n        return value;\n    }\n};\n\n/// Internal data structure used to track registered instances and types.\n/// Whenever binary incompatible changes are made to this structure,\n/// `PYBIND11_INTERNALS_VERSION` must be incremented.\nstruct internals {\n    // std::type_index -> pybind11's type information\n    type_map<type_info *> registered_types_cpp;\n    // PyTypeObject* -> base type_info(s)\n    std::unordered_map<PyTypeObject *, std::vector<type_info *>> registered_types_py;\n    std::unordered_multimap<const void *, instance *> registered_instances; // void * -> instance*\n    std::unordered_set<std::pair<const PyObject *, const char *>, override_hash>\n        inactive_override_cache;\n    type_map<std::vector<bool (*)(PyObject *, void *&)>> direct_conversions;\n    std::unordered_map<const PyObject *, std::vector<PyObject *>> patients;\n    std::forward_list<ExceptionTranslator> registered_exception_translators;\n    std::unordered_map<std::string, void *> shared_data; // Custom data to be shared across\n                                                         // extensions\n#if PYBIND11_INTERNALS_VERSION == 4\n    std::vector<PyObject *> unused_loader_patient_stack_remove_at_v5;\n#endif\n    std::forward_list<std::string> static_strings; // Stores the std::strings backing\n                                                   // detail::c_str()\n    PyTypeObject *static_property_type;\n    PyTypeObject *default_metaclass;\n    PyObject *instance_base;\n#if defined(WITH_THREAD)\n    // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:\n    PYBIND11_TLS_KEY_INIT(tstate)\n#    if PYBIND11_INTERNALS_VERSION > 4\n    PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)\n#    endif // PYBIND11_INTERNALS_VERSION > 4\n    // Unused if PYBIND11_SIMPLE_GIL_MANAGEMENT is defined:\n    PyInterpreterState *istate = nullptr;\n\n#    if PYBIND11_INTERNALS_VERSION > 4\n    // Note that we have to use a std::string to allocate memory to ensure a unique address\n    // We want unique addresses since we use pointer equality to compare function records\n    std::string function_record_capsule_name = internals_function_record_capsule_name;\n#    endif\n\n    internals() = default;\n    internals(const internals &other) = delete;\n    internals &operator=(const internals &other) = delete;\n    ~internals() {\n#    if PYBIND11_INTERNALS_VERSION > 4\n        PYBIND11_TLS_FREE(loader_life_support_tls_key);\n#    endif // PYBIND11_INTERNALS_VERSION > 4\n\n        // This destructor is called *after* Py_Finalize() in finalize_interpreter().\n        // That *SHOULD BE* fine. The following details what happens when PyThread_tss_free is\n        // called. PYBIND11_TLS_FREE is PyThread_tss_free on python 3.7+. On older python, it does\n        // nothing. PyThread_tss_free calls PyThread_tss_delete and PyMem_RawFree.\n        // PyThread_tss_delete just calls TlsFree (on Windows) or pthread_key_delete (on *NIX).\n        // Neither of those have anything to do with CPython internals. PyMem_RawFree *requires*\n        // that the `tstate` be allocated with the CPython allocator.\n        PYBIND11_TLS_FREE(tstate);\n    }\n#endif\n};\n\n/// Additional type information which does not fit into the PyTypeObject.\n/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.\nstruct type_info {\n    PyTypeObject *type;\n    const std::type_info *cpptype;\n    size_t type_size, type_align, holder_size_in_ptrs;\n    void *(*operator_new)(size_t);\n    void (*init_instance)(instance *, const void *);\n    void (*dealloc)(value_and_holder &v_h);\n    std::vector<PyObject *(*) (PyObject *, PyTypeObject *)> implicit_conversions;\n    std::vector<std::pair<const std::type_info *, void *(*) (void *)>> implicit_casts;\n    std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;\n    buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;\n    void *get_buffer_data = nullptr;\n    void *(*module_local_load)(PyObject *, const type_info *) = nullptr;\n    /* A simple type never occurs as a (direct or indirect) parent\n     * of a class that makes use of multiple inheritance.\n     * A type can be simple even if it has non-simple ancestors as long as it has no descendants.\n     */\n    bool simple_type : 1;\n    /* True if there is no multiple inheritance in this type's inheritance tree */\n    bool simple_ancestors : 1;\n    /* for base vs derived holder_type checks */\n    bool default_holder : 1;\n    /* true if this is a type registered with py::module_local */\n    bool module_local : 1;\n};\n\n/// On MSVC, debug and release builds are not ABI-compatible!\n#if defined(_MSC_VER) && defined(_DEBUG)\n#    define PYBIND11_BUILD_TYPE \"_debug\"\n#else\n#    define PYBIND11_BUILD_TYPE \"\"\n#endif\n\n/// Let's assume that different compilers are ABI-incompatible.\n/// A user can manually set this string if they know their\n/// compiler is compatible.\n#ifndef PYBIND11_COMPILER_TYPE\n#    if defined(_MSC_VER)\n#        define PYBIND11_COMPILER_TYPE \"_msvc\"\n#    elif defined(__INTEL_COMPILER)\n#        define PYBIND11_COMPILER_TYPE \"_icc\"\n#    elif defined(__clang__)\n#        define PYBIND11_COMPILER_TYPE \"_clang\"\n#    elif defined(__PGI)\n#        define PYBIND11_COMPILER_TYPE \"_pgi\"\n#    elif defined(__MINGW32__)\n#        define PYBIND11_COMPILER_TYPE \"_mingw\"\n#    elif defined(__CYGWIN__)\n#        define PYBIND11_COMPILER_TYPE \"_gcc_cygwin\"\n#    elif defined(__GNUC__)\n#        define PYBIND11_COMPILER_TYPE \"_gcc\"\n#    else\n#        define PYBIND11_COMPILER_TYPE \"_unknown\"\n#    endif\n#endif\n\n/// Also standard libs\n#ifndef PYBIND11_STDLIB\n#    if defined(_LIBCPP_VERSION)\n#        define PYBIND11_STDLIB \"_libcpp\"\n#    elif defined(__GLIBCXX__) || defined(__GLIBCPP__)\n#        define PYBIND11_STDLIB \"_libstdcpp\"\n#    else\n#        define PYBIND11_STDLIB \"\"\n#    endif\n#endif\n\n/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.\n/// On MSVC, changes in _MSC_VER may indicate ABI incompatibility (#2898).\n#ifndef PYBIND11_BUILD_ABI\n#    if defined(__GXX_ABI_VERSION)\n#        define PYBIND11_BUILD_ABI \"_cxxabi\" PYBIND11_TOSTRING(__GXX_ABI_VERSION)\n#    elif defined(_MSC_VER)\n#        define PYBIND11_BUILD_ABI \"_mscver\" PYBIND11_TOSTRING(_MSC_VER)\n#    else\n#        define PYBIND11_BUILD_ABI \"\"\n#    endif\n#endif\n\n#ifndef PYBIND11_INTERNALS_KIND\n#    if defined(WITH_THREAD)\n#        define PYBIND11_INTERNALS_KIND \"\"\n#    else\n#        define PYBIND11_INTERNALS_KIND \"_without_thread\"\n#    endif\n#endif\n\n#define PYBIND11_INTERNALS_ID                                                                     \\\n    \"__pybind11_internals_v\" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION)                        \\\n        PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI         \\\n            PYBIND11_BUILD_TYPE \"__\"\n\n#define PYBIND11_MODULE_LOCAL_ID                                                                  \\\n    \"__pybind11_module_local_v\" PYBIND11_TOSTRING(PYBIND11_INTERNALS_VERSION)                     \\\n        PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI         \\\n            PYBIND11_BUILD_TYPE \"__\"\n\n/// Each module locally stores a pointer to the `internals` data. The data\n/// itself is shared among modules with the same `PYBIND11_INTERNALS_ID`.\ninline internals **&get_internals_pp() {\n    static internals **internals_pp = nullptr;\n    return internals_pp;\n}\n\n// forward decl\ninline void translate_exception(std::exception_ptr);\n\ntemplate <class T,\n          enable_if_t<std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>\nbool handle_nested_exception(const T &exc, const std::exception_ptr &p) {\n    std::exception_ptr nested = exc.nested_ptr();\n    if (nested != nullptr && nested != p) {\n        translate_exception(nested);\n        return true;\n    }\n    return false;\n}\n\ntemplate <class T,\n          enable_if_t<!std::is_same<std::nested_exception, remove_cvref_t<T>>::value, int> = 0>\nbool handle_nested_exception(const T &exc, const std::exception_ptr &p) {\n    if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(exc))) {\n        return handle_nested_exception(*nep, p);\n    }\n    return false;\n}\n\ninline bool raise_err(PyObject *exc_type, const char *msg) {\n    if (PyErr_Occurred()) {\n        raise_from(exc_type, msg);\n        return true;\n    }\n    set_error(exc_type, msg);\n    return false;\n}\n\ninline void translate_exception(std::exception_ptr p) {\n    if (!p) {\n        return;\n    }\n    try {\n        std::rethrow_exception(p);\n    } catch (error_already_set &e) {\n        handle_nested_exception(e, p);\n        e.restore();\n        return;\n    } catch (const builtin_exception &e) {\n        // Could not use template since it's an abstract class.\n        if (const auto *nep = dynamic_cast<const std::nested_exception *>(std::addressof(e))) {\n            handle_nested_exception(*nep, p);\n        }\n        e.set_error();\n        return;\n    } catch (const std::bad_alloc &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_MemoryError, e.what());\n        return;\n    } catch (const std::domain_error &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_ValueError, e.what());\n        return;\n    } catch (const std::invalid_argument &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_ValueError, e.what());\n        return;\n    } catch (const std::length_error &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_ValueError, e.what());\n        return;\n    } catch (const std::out_of_range &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_IndexError, e.what());\n        return;\n    } catch (const std::range_error &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_ValueError, e.what());\n        return;\n    } catch (const std::overflow_error &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_OverflowError, e.what());\n        return;\n    } catch (const std::exception &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_RuntimeError, e.what());\n        return;\n    } catch (const std::nested_exception &e) {\n        handle_nested_exception(e, p);\n        raise_err(PyExc_RuntimeError, \"Caught an unknown nested exception!\");\n        return;\n    } catch (...) {\n        raise_err(PyExc_RuntimeError, \"Caught an unknown exception!\");\n        return;\n    }\n}\n\n#if !defined(__GLIBCXX__)\ninline void translate_local_exception(std::exception_ptr p) {\n    try {\n        if (p) {\n            std::rethrow_exception(p);\n        }\n    } catch (error_already_set &e) {\n        e.restore();\n        return;\n    } catch (const builtin_exception &e) {\n        e.set_error();\n        return;\n    }\n}\n#endif\n\ninline object get_python_state_dict() {\n    object state_dict;\n#if PYBIND11_INTERNALS_VERSION <= 4 || PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)\n    state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());\n#else\n#    if PY_VERSION_HEX < 0x03090000\n    PyInterpreterState *istate = _PyInterpreterState_Get();\n#    else\n    PyInterpreterState *istate = PyInterpreterState_Get();\n#    endif\n    if (istate) {\n        state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));\n    }\n#endif\n    if (!state_dict) {\n        raise_from(PyExc_SystemError, \"pybind11::detail::get_python_state_dict() FAILED\");\n        throw error_already_set();\n    }\n    return state_dict;\n}\n\ninline object get_internals_obj_from_state_dict(handle state_dict) {\n    return reinterpret_borrow<object>(dict_getitemstring(state_dict.ptr(), PYBIND11_INTERNALS_ID));\n}\n\ninline internals **get_internals_pp_from_capsule(handle obj) {\n    void *raw_ptr = PyCapsule_GetPointer(obj.ptr(), /*name=*/nullptr);\n    if (raw_ptr == nullptr) {\n        raise_from(PyExc_SystemError, \"pybind11::detail::get_internals_pp_from_capsule() FAILED\");\n        throw error_already_set();\n    }\n    return static_cast<internals **>(raw_ptr);\n}\n\n/// Return a reference to the current `internals` data\nPYBIND11_NOINLINE internals &get_internals() {\n    auto **&internals_pp = get_internals_pp();\n    if (internals_pp && *internals_pp) {\n        return **internals_pp;\n    }\n\n#if defined(WITH_THREAD)\n#    if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n    gil_scoped_acquire gil;\n#    else\n    // Ensure that the GIL is held since we will need to make Python calls.\n    // Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.\n    struct gil_scoped_acquire_local {\n        gil_scoped_acquire_local() : state(PyGILState_Ensure()) {}\n        gil_scoped_acquire_local(const gil_scoped_acquire_local &) = delete;\n        gil_scoped_acquire_local &operator=(const gil_scoped_acquire_local &) = delete;\n        ~gil_scoped_acquire_local() { PyGILState_Release(state); }\n        const PyGILState_STATE state;\n    } gil;\n#    endif\n#endif\n    error_scope err_scope;\n\n    dict state_dict = get_python_state_dict();\n    if (object internals_obj = get_internals_obj_from_state_dict(state_dict)) {\n        internals_pp = get_internals_pp_from_capsule(internals_obj);\n    }\n    if (internals_pp && *internals_pp) {\n        // We loaded the internals through `state_dict`, which means that our `error_already_set`\n        // and `builtin_exception` may be different local classes than the ones set up in the\n        // initial exception translator, below, so add another for our local exception classes.\n        //\n        // libstdc++ doesn't require this (types there are identified only by name)\n        // libc++ with CPython doesn't require this (types are explicitly exported)\n        // libc++ with PyPy still need it, awaiting further investigation\n#if !defined(__GLIBCXX__)\n        (*internals_pp)->registered_exception_translators.push_front(&translate_local_exception);\n#endif\n    } else {\n        if (!internals_pp) {\n            internals_pp = new internals *();\n        }\n        auto *&internals_ptr = *internals_pp;\n        internals_ptr = new internals();\n#if defined(WITH_THREAD)\n\n        PyThreadState *tstate = PyThreadState_Get();\n        // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)\n        if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->tstate)) {\n            pybind11_fail(\"get_internals: could not successfully initialize the tstate TSS key!\");\n        }\n        PYBIND11_TLS_REPLACE_VALUE(internals_ptr->tstate, tstate);\n\n#    if PYBIND11_INTERNALS_VERSION > 4\n        // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)\n        if (!PYBIND11_TLS_KEY_CREATE(internals_ptr->loader_life_support_tls_key)) {\n            pybind11_fail(\"get_internals: could not successfully initialize the \"\n                          \"loader_life_support TSS key!\");\n        }\n#    endif\n        internals_ptr->istate = tstate->interp;\n#endif\n        state_dict[PYBIND11_INTERNALS_ID] = capsule(internals_pp);\n        internals_ptr->registered_exception_translators.push_front(&translate_exception);\n        internals_ptr->static_property_type = make_static_property_type();\n        internals_ptr->default_metaclass = make_default_metaclass();\n        internals_ptr->instance_base = make_object_base_type(internals_ptr->default_metaclass);\n    }\n    return **internals_pp;\n}\n\n// the internals struct (above) is shared between all the modules. local_internals are only\n// for a single module. Any changes made to internals may require an update to\n// PYBIND11_INTERNALS_VERSION, breaking backwards compatibility. local_internals is, by design,\n// restricted to a single module. Whether a module has local internals or not should not\n// impact any other modules, because the only things accessing the local internals is the\n// module that contains them.\nstruct local_internals {\n    type_map<type_info *> registered_types_cpp;\n    std::forward_list<ExceptionTranslator> registered_exception_translators;\n#if defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4\n\n    // For ABI compatibility, we can't store the loader_life_support TLS key in\n    // the `internals` struct directly.  Instead, we store it in `shared_data` and\n    // cache a copy in `local_internals`.  If we allocated a separate TLS key for\n    // each instance of `local_internals`, we could end up allocating hundreds of\n    // TLS keys if hundreds of different pybind11 modules are loaded (which is a\n    // plausible number).\n    PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)\n\n    // Holds the shared TLS key for the loader_life_support stack.\n    struct shared_loader_life_support_data {\n        PYBIND11_TLS_KEY_INIT(loader_life_support_tls_key)\n        shared_loader_life_support_data() {\n            // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)\n            if (!PYBIND11_TLS_KEY_CREATE(loader_life_support_tls_key)) {\n                pybind11_fail(\"local_internals: could not successfully initialize the \"\n                              \"loader_life_support TLS key!\");\n            }\n        }\n        // We can't help but leak the TLS key, because Python never unloads extension modules.\n    };\n\n    local_internals() {\n        auto &internals = get_internals();\n        // Get or create the `loader_life_support_stack_key`.\n        auto &ptr = internals.shared_data[\"_life_support\"];\n        if (!ptr) {\n            ptr = new shared_loader_life_support_data;\n        }\n        loader_life_support_tls_key\n            = static_cast<shared_loader_life_support_data *>(ptr)->loader_life_support_tls_key;\n    }\n#endif //  defined(WITH_THREAD) && PYBIND11_INTERNALS_VERSION == 4\n};\n\n/// Works like `get_internals`, but for things which are locally registered.\ninline local_internals &get_local_internals() {\n    // Current static can be created in the interpreter finalization routine. If the later will be\n    // destroyed in another static variable destructor, creation of this static there will cause\n    // static deinitialization fiasco. In order to avoid it we avoid destruction of the\n    // local_internals static. One can read more about the problem and current solution here:\n    // https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables\n    static auto *locals = new local_internals();\n    return *locals;\n}\n\n/// Constructs a std::string with the given arguments, stores it in `internals`, and returns its\n/// `c_str()`.  Such strings objects have a long storage duration -- the internal strings are only\n/// cleared when the program exits or after interpreter shutdown (when embedding), and so are\n/// suitable for c-style strings needed by Python internals (such as PyTypeObject's tp_name).\ntemplate <typename... Args>\nconst char *c_str(Args &&...args) {\n    auto &strings = get_internals().static_strings;\n    strings.emplace_front(std::forward<Args>(args)...);\n    return strings.front().c_str();\n}\n\ninline const char *get_function_record_capsule_name() {\n#if PYBIND11_INTERNALS_VERSION > 4\n    return get_internals().function_record_capsule_name.c_str();\n#else\n    return nullptr;\n#endif\n}\n\n// Determine whether or not the following capsule contains a pybind11 function record.\n// Note that we use `internals` to make sure that only ABI compatible records are touched.\n//\n// This check is currently used in two places:\n// - An important optimization in functional.h to avoid overhead in C++ -> Python -> C++\n// - The sibling feature of cpp_function to allow overloads\ninline bool is_function_record_capsule(const capsule &cap) {\n    // Pointer equality as we rely on internals() to ensure unique pointers\n    return cap.name() == get_function_record_capsule_name();\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Returns a named pointer that is shared among all extension modules (using the same\n/// pybind11 version) running in the current interpreter. Names starting with underscores\n/// are reserved for internal usage. Returns `nullptr` if no matching entry was found.\nPYBIND11_NOINLINE void *get_shared_data(const std::string &name) {\n    auto &internals = detail::get_internals();\n    auto it = internals.shared_data.find(name);\n    return it != internals.shared_data.end() ? it->second : nullptr;\n}\n\n/// Set the shared data that can be later recovered by `get_shared_data()`.\nPYBIND11_NOINLINE void *set_shared_data(const std::string &name, void *data) {\n    detail::get_internals().shared_data[name] = data;\n    return data;\n}\n\n/// Returns a typed reference to a shared data entry (by using `get_shared_data()`) if\n/// such entry exists. Otherwise, a new object of default-constructible type `T` is\n/// added to the shared data under the given name and a reference to it is returned.\ntemplate <typename T>\nT &get_or_create_shared_data(const std::string &name) {\n    auto &internals = detail::get_internals();\n    auto it = internals.shared_data.find(name);\n    T *ptr = (T *) (it != internals.shared_data.end() ? it->second : nullptr);\n    if (!ptr) {\n        ptr = new T();\n        internals.shared_data[name] = ptr;\n    }\n    return *ptr;\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/type_caster_base.h",
    "content": "/*\n    pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h)\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"../pytypes.h\"\n#include \"common.h\"\n#include \"descr.h\"\n#include \"internals.h\"\n#include \"typeid.h\"\n\n#include <cstdint>\n#include <iterator>\n#include <new>\n#include <string>\n#include <type_traits>\n#include <typeindex>\n#include <typeinfo>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// A life support system for temporary objects created by `type_caster::load()`.\n/// Adding a patient will keep it alive up until the enclosing function returns.\nclass loader_life_support {\nprivate:\n    loader_life_support *parent = nullptr;\n    std::unordered_set<PyObject *> keep_alive;\n\n#if defined(WITH_THREAD)\n    // Store stack pointer in thread-local storage.\n    static PYBIND11_TLS_KEY_REF get_stack_tls_key() {\n#    if PYBIND11_INTERNALS_VERSION == 4\n        return get_local_internals().loader_life_support_tls_key;\n#    else\n        return get_internals().loader_life_support_tls_key;\n#    endif\n    }\n    static loader_life_support *get_stack_top() {\n        return static_cast<loader_life_support *>(PYBIND11_TLS_GET_VALUE(get_stack_tls_key()));\n    }\n    static void set_stack_top(loader_life_support *value) {\n        PYBIND11_TLS_REPLACE_VALUE(get_stack_tls_key(), value);\n    }\n#else\n    // Use single global variable for stack.\n    static loader_life_support **get_stack_pp() {\n        static loader_life_support *global_stack = nullptr;\n        return global_stack;\n    }\n    static loader_life_support *get_stack_top() { return *get_stack_pp(); }\n    static void set_stack_top(loader_life_support *value) { *get_stack_pp() = value; }\n#endif\n\npublic:\n    /// A new patient frame is created when a function is entered\n    loader_life_support() : parent{get_stack_top()} { set_stack_top(this); }\n\n    /// ... and destroyed after it returns\n    ~loader_life_support() {\n        if (get_stack_top() != this) {\n            pybind11_fail(\"loader_life_support: internal error\");\n        }\n        set_stack_top(parent);\n        for (auto *item : keep_alive) {\n            Py_DECREF(item);\n        }\n    }\n\n    /// This can only be used inside a pybind11-bound function, either by `argument_loader`\n    /// at argument preparation time or by `py::cast()` at execution time.\n    PYBIND11_NOINLINE static void add_patient(handle h) {\n        loader_life_support *frame = get_stack_top();\n        if (!frame) {\n            // NOTE: It would be nice to include the stack frames here, as this indicates\n            // use of pybind11::cast<> outside the normal call framework, finding such\n            // a location is challenging. Developers could consider printing out\n            // stack frame addresses here using something like __builtin_frame_address(0)\n            throw cast_error(\"When called outside a bound function, py::cast() cannot \"\n                             \"do Python -> C++ conversions which require the creation \"\n                             \"of temporary values\");\n        }\n\n        if (frame->keep_alive.insert(h.ptr()).second) {\n            Py_INCREF(h.ptr());\n        }\n    }\n};\n\n// Gets the cache entry for the given type, creating it if necessary.  The return value is the pair\n// returned by emplace, i.e. an iterator for the entry and a bool set to `true` if the entry was\n// just created.\ninline std::pair<decltype(internals::registered_types_py)::iterator, bool>\nall_type_info_get_cache(PyTypeObject *type);\n\n// Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.\ninline void all_type_info_add_base_most_derived_first(std::vector<type_info *> &bases,\n                                                      type_info *addl_base) {\n    for (auto it = bases.begin(); it != bases.end(); it++) {\n        type_info *existing_base = *it;\n        if (PyType_IsSubtype(addl_base->type, existing_base->type) != 0) {\n            bases.insert(it, addl_base);\n            return;\n        }\n    }\n    bases.push_back(addl_base);\n}\n\n// Populates a just-created cache entry.\nPYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_info *> &bases) {\n    assert(bases.empty());\n    std::vector<PyTypeObject *> check;\n    for (handle parent : reinterpret_borrow<tuple>(t->tp_bases)) {\n        check.push_back((PyTypeObject *) parent.ptr());\n    }\n\n    auto const &type_dict = get_internals().registered_types_py;\n    for (size_t i = 0; i < check.size(); i++) {\n        auto *type = check[i];\n        // Ignore Python2 old-style class super type:\n        if (!PyType_Check((PyObject *) type)) {\n            continue;\n        }\n\n        // Check `type` in the current set of registered python types:\n        auto it = type_dict.find(type);\n        if (it != type_dict.end()) {\n            // We found a cache entry for it, so it's either pybind-registered or has pre-computed\n            // pybind bases, but we have to make sure we haven't already seen the type(s) before:\n            // we want to follow Python/virtual C++ rules that there should only be one instance of\n            // a common base.\n            for (auto *tinfo : it->second) {\n                // NB: Could use a second set here, rather than doing a linear search, but since\n                // having a large number of immediate pybind11-registered types seems fairly\n                // unlikely, that probably isn't worthwhile.\n                bool found = false;\n                for (auto *known : bases) {\n                    if (known == tinfo) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    all_type_info_add_base_most_derived_first(bases, tinfo);\n                }\n            }\n        } else if (type->tp_bases) {\n            // It's some python type, so keep follow its bases classes to look for one or more\n            // registered types\n            if (i + 1 == check.size()) {\n                // When we're at the end, we can pop off the current element to avoid growing\n                // `check` when adding just one base (which is typical--i.e. when there is no\n                // multiple inheritance)\n                check.pop_back();\n                i--;\n            }\n            for (handle parent : reinterpret_borrow<tuple>(type->tp_bases)) {\n                check.push_back((PyTypeObject *) parent.ptr());\n            }\n        }\n    }\n}\n\n/**\n * Extracts vector of type_info pointers of pybind-registered roots of the given Python type.  Will\n * be just 1 pybind type for the Python type of a pybind-registered class, or for any Python-side\n * derived class that uses single inheritance.  Will contain as many types as required for a Python\n * class that uses multiple inheritance to inherit (directly or indirectly) from multiple\n * pybind-registered classes.  Will be empty if neither the type nor any base classes are\n * pybind-registered.\n *\n * The value is cached for the lifetime of the Python type.\n */\ninline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {\n    auto ins = all_type_info_get_cache(type);\n    if (ins.second) {\n        // New cache entry: populate it\n        all_type_info_populate(type, ins.first->second);\n    }\n\n    return ins.first->second;\n}\n\n/**\n * Gets a single pybind11 type info for a python type.  Returns nullptr if neither the type nor any\n * ancestors are pybind11-registered.  Throws an exception if there are multiple bases--use\n * `all_type_info` instead if you want to support multiple bases.\n */\nPYBIND11_NOINLINE detail::type_info *get_type_info(PyTypeObject *type) {\n    const auto &bases = all_type_info(type);\n    if (bases.empty()) {\n        return nullptr;\n    }\n    if (bases.size() > 1) {\n        pybind11_fail(\n            \"pybind11::detail::get_type_info: type has multiple pybind11-registered bases\");\n    }\n    return bases.front();\n}\n\ninline detail::type_info *get_local_type_info(const std::type_index &tp) {\n    auto &locals = get_local_internals().registered_types_cpp;\n    auto it = locals.find(tp);\n    if (it != locals.end()) {\n        return it->second;\n    }\n    return nullptr;\n}\n\ninline detail::type_info *get_global_type_info(const std::type_index &tp) {\n    auto &types = get_internals().registered_types_cpp;\n    auto it = types.find(tp);\n    if (it != types.end()) {\n        return it->second;\n    }\n    return nullptr;\n}\n\n/// Return the type info for a given C++ type; on lookup failure can either throw or return\n/// nullptr.\nPYBIND11_NOINLINE detail::type_info *get_type_info(const std::type_index &tp,\n                                                   bool throw_if_missing = false) {\n    if (auto *ltype = get_local_type_info(tp)) {\n        return ltype;\n    }\n    if (auto *gtype = get_global_type_info(tp)) {\n        return gtype;\n    }\n\n    if (throw_if_missing) {\n        std::string tname = tp.name();\n        detail::clean_type_id(tname);\n        pybind11_fail(\"pybind11::detail::get_type_info: unable to find type info for \\\"\"\n                      + std::move(tname) + '\"');\n    }\n    return nullptr;\n}\n\nPYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if_missing) {\n    detail::type_info *type_info = get_type_info(tp, throw_if_missing);\n    return handle(type_info ? ((PyObject *) type_info->type) : nullptr);\n}\n\n// Searches the inheritance graph for a registered Python instance, using all_type_info().\nPYBIND11_NOINLINE handle find_registered_python_instance(void *src,\n                                                         const detail::type_info *tinfo) {\n    auto it_instances = get_internals().registered_instances.equal_range(src);\n    for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {\n        for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {\n            if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {\n                return handle((PyObject *) it_i->second).inc_ref();\n            }\n        }\n    }\n    return handle();\n}\n\nstruct value_and_holder {\n    instance *inst = nullptr;\n    size_t index = 0u;\n    const detail::type_info *type = nullptr;\n    void **vh = nullptr;\n\n    // Main constructor for a found value/holder:\n    value_and_holder(instance *i, const detail::type_info *type, size_t vpos, size_t index)\n        : inst{i}, index{index}, type{type},\n          vh{inst->simple_layout ? inst->simple_value_holder\n                                 : &inst->nonsimple.values_and_holders[vpos]} {}\n\n    // Default constructor (used to signal a value-and-holder not found by get_value_and_holder())\n    value_and_holder() = default;\n\n    // Used for past-the-end iterator\n    explicit value_and_holder(size_t index) : index{index} {}\n\n    template <typename V = void>\n    V *&value_ptr() const {\n        return reinterpret_cast<V *&>(vh[0]);\n    }\n    // True if this `value_and_holder` has a non-null value pointer\n    explicit operator bool() const { return value_ptr() != nullptr; }\n\n    template <typename H>\n    H &holder() const {\n        return reinterpret_cast<H &>(vh[1]);\n    }\n    bool holder_constructed() const {\n        return inst->simple_layout\n                   ? inst->simple_holder_constructed\n                   : (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;\n    }\n    // NOLINTNEXTLINE(readability-make-member-function-const)\n    void set_holder_constructed(bool v = true) {\n        if (inst->simple_layout) {\n            inst->simple_holder_constructed = v;\n        } else if (v) {\n            inst->nonsimple.status[index] |= instance::status_holder_constructed;\n        } else {\n            inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_holder_constructed;\n        }\n    }\n    bool instance_registered() const {\n        return inst->simple_layout\n                   ? inst->simple_instance_registered\n                   : ((inst->nonsimple.status[index] & instance::status_instance_registered) != 0);\n    }\n    // NOLINTNEXTLINE(readability-make-member-function-const)\n    void set_instance_registered(bool v = true) {\n        if (inst->simple_layout) {\n            inst->simple_instance_registered = v;\n        } else if (v) {\n            inst->nonsimple.status[index] |= instance::status_instance_registered;\n        } else {\n            inst->nonsimple.status[index] &= (std::uint8_t) ~instance::status_instance_registered;\n        }\n    }\n};\n\n// Container for accessing and iterating over an instance's values/holders\nstruct values_and_holders {\nprivate:\n    instance *inst;\n    using type_vec = std::vector<detail::type_info *>;\n    const type_vec &tinfo;\n\npublic:\n    explicit values_and_holders(instance *inst)\n        : inst{inst}, tinfo(all_type_info(Py_TYPE(inst))) {}\n\n    explicit values_and_holders(PyObject *obj)\n        : inst{nullptr}, tinfo(all_type_info(Py_TYPE(obj))) {\n        if (!tinfo.empty()) {\n            inst = reinterpret_cast<instance *>(obj);\n        }\n    }\n\n    struct iterator {\n    private:\n        instance *inst = nullptr;\n        const type_vec *types = nullptr;\n        value_and_holder curr;\n        friend struct values_and_holders;\n        iterator(instance *inst, const type_vec *tinfo) : inst{inst}, types{tinfo} {\n            if (inst != nullptr) {\n                assert(!types->empty());\n                curr = value_and_holder(\n                    inst /* instance */,\n                    (*types)[0] /* type info */,\n                    0, /* vpos: (non-simple types only): the first vptr comes first */\n                    0 /* index */);\n            }\n        }\n        // Past-the-end iterator:\n        explicit iterator(size_t end) : curr(end) {}\n\n    public:\n        bool operator==(const iterator &other) const { return curr.index == other.curr.index; }\n        bool operator!=(const iterator &other) const { return curr.index != other.curr.index; }\n        iterator &operator++() {\n            if (!inst->simple_layout) {\n                curr.vh += 1 + (*types)[curr.index]->holder_size_in_ptrs;\n            }\n            ++curr.index;\n            curr.type = curr.index < types->size() ? (*types)[curr.index] : nullptr;\n            return *this;\n        }\n        value_and_holder &operator*() { return curr; }\n        value_and_holder *operator->() { return &curr; }\n    };\n\n    iterator begin() { return iterator(inst, &tinfo); }\n    iterator end() { return iterator(tinfo.size()); }\n\n    iterator find(const type_info *find_type) {\n        auto it = begin(), endit = end();\n        while (it != endit && it->type != find_type) {\n            ++it;\n        }\n        return it;\n    }\n\n    size_t size() { return tinfo.size(); }\n\n    // Band-aid workaround to fix a subtle but serious bug in a minimalistic fashion. See PR #4762.\n    bool is_redundant_value_and_holder(const value_and_holder &vh) {\n        for (size_t i = 0; i < vh.index; i++) {\n            if (PyType_IsSubtype(tinfo[i]->type, tinfo[vh.index]->type) != 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n};\n\n/**\n * Extracts C++ value and holder pointer references from an instance (which may contain multiple\n * values/holders for python-side multiple inheritance) that match the given type.  Throws an error\n * if the given type (or ValueType, if omitted) is not a pybind11 base of the given instance.  If\n * `find_type` is omitted (or explicitly specified as nullptr) the first value/holder are returned,\n * regardless of type (and the resulting .type will be nullptr).\n *\n * The returned object should be short-lived: in particular, it must not outlive the called-upon\n * instance.\n */\nPYBIND11_NOINLINE value_and_holder\ninstance::get_value_and_holder(const type_info *find_type /*= nullptr default in common.h*/,\n                               bool throw_if_missing /*= true in common.h*/) {\n    // Optimize common case:\n    if (!find_type || Py_TYPE(this) == find_type->type) {\n        return value_and_holder(this, find_type, 0, 0);\n    }\n\n    detail::values_and_holders vhs(this);\n    auto it = vhs.find(find_type);\n    if (it != vhs.end()) {\n        return *it;\n    }\n\n    if (!throw_if_missing) {\n        return value_and_holder();\n    }\n\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n    pybind11_fail(\"pybind11::detail::instance::get_value_and_holder: `\"\n                  + get_fully_qualified_tp_name(find_type->type)\n                  + \"' is not a pybind11 base of the given `\"\n                  + get_fully_qualified_tp_name(Py_TYPE(this)) + \"' instance\");\n#else\n    pybind11_fail(\n        \"pybind11::detail::instance::get_value_and_holder: \"\n        \"type is not a pybind11 base of the given instance \"\n        \"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for type details)\");\n#endif\n}\n\nPYBIND11_NOINLINE void instance::allocate_layout() {\n    const auto &tinfo = all_type_info(Py_TYPE(this));\n\n    const size_t n_types = tinfo.size();\n\n    if (n_types == 0) {\n        pybind11_fail(\n            \"instance allocation failed: new instance has no pybind11-registered base types\");\n    }\n\n    simple_layout\n        = n_types == 1 && tinfo.front()->holder_size_in_ptrs <= instance_simple_holder_in_ptrs();\n\n    // Simple path: no python-side multiple inheritance, and a small-enough holder\n    if (simple_layout) {\n        simple_value_holder[0] = nullptr;\n        simple_holder_constructed = false;\n        simple_instance_registered = false;\n    } else { // multiple base types or a too-large holder\n        // Allocate space to hold: [v1*][h1][v2*][h2]...[bb...] where [vN*] is a value pointer,\n        // [hN] is the (uninitialized) holder instance for value N, and [bb...] is a set of bool\n        // values that tracks whether each associated holder has been initialized.  Each [block] is\n        // padded, if necessary, to an integer multiple of sizeof(void *).\n        size_t space = 0;\n        for (auto *t : tinfo) {\n            space += 1;                      // value pointer\n            space += t->holder_size_in_ptrs; // holder instance\n        }\n        size_t flags_at = space;\n        space += size_in_ptrs(n_types); // status bytes (holder_constructed and\n                                        // instance_registered)\n\n        // Allocate space for flags, values, and holders, and initialize it to 0 (flags and values,\n        // in particular, need to be 0).  Use Python's memory allocation\n        // functions: Python is using pymalloc, which is designed to be\n        // efficient for small allocations like the one we're doing here;\n        // for larger allocations they are just wrappers around malloc.\n        // TODO: is this still true for pure Python 3.6?\n        nonsimple.values_and_holders = (void **) PyMem_Calloc(space, sizeof(void *));\n        if (!nonsimple.values_and_holders) {\n            throw std::bad_alloc();\n        }\n        nonsimple.status\n            = reinterpret_cast<std::uint8_t *>(&nonsimple.values_and_holders[flags_at]);\n    }\n    owned = true;\n}\n\n// NOLINTNEXTLINE(readability-make-member-function-const)\nPYBIND11_NOINLINE void instance::deallocate_layout() {\n    if (!simple_layout) {\n        PyMem_Free(nonsimple.values_and_holders);\n    }\n}\n\nPYBIND11_NOINLINE bool isinstance_generic(handle obj, const std::type_info &tp) {\n    handle type = detail::get_type_handle(tp, false);\n    if (!type) {\n        return false;\n    }\n    return isinstance(obj, type);\n}\n\nPYBIND11_NOINLINE handle get_object_handle(const void *ptr, const detail::type_info *type) {\n    auto &instances = get_internals().registered_instances;\n    auto range = instances.equal_range(ptr);\n    for (auto it = range.first; it != range.second; ++it) {\n        for (const auto &vh : values_and_holders(it->second)) {\n            if (vh.type == type) {\n                return handle((PyObject *) it->second);\n            }\n        }\n    }\n    return handle();\n}\n\ninline PyThreadState *get_thread_state_unchecked() {\n#if defined(PYPY_VERSION)\n    return PyThreadState_GET();\n#elif PY_VERSION_HEX < 0x030D0000\n    return _PyThreadState_UncheckedGet();\n#else\n    return PyThreadState_GetUnchecked();\n#endif\n}\n\n// Forward declarations\nvoid keep_alive_impl(handle nurse, handle patient);\ninline PyObject *make_new_instance(PyTypeObject *type);\n\nclass type_caster_generic {\npublic:\n    PYBIND11_NOINLINE explicit type_caster_generic(const std::type_info &type_info)\n        : typeinfo(get_type_info(type_info)), cpptype(&type_info) {}\n\n    explicit type_caster_generic(const type_info *typeinfo)\n        : typeinfo(typeinfo), cpptype(typeinfo ? typeinfo->cpptype : nullptr) {}\n\n    bool load(handle src, bool convert) { return load_impl<type_caster_generic>(src, convert); }\n\n    PYBIND11_NOINLINE static handle cast(const void *_src,\n                                         return_value_policy policy,\n                                         handle parent,\n                                         const detail::type_info *tinfo,\n                                         void *(*copy_constructor)(const void *),\n                                         void *(*move_constructor)(const void *),\n                                         const void *existing_holder = nullptr) {\n        if (!tinfo) { // no type info: error will be set already\n            return handle();\n        }\n\n        void *src = const_cast<void *>(_src);\n        if (src == nullptr) {\n            return none().release();\n        }\n\n        if (handle registered_inst = find_registered_python_instance(src, tinfo)) {\n            return registered_inst;\n        }\n\n        auto inst = reinterpret_steal<object>(make_new_instance(tinfo->type));\n        auto *wrapper = reinterpret_cast<instance *>(inst.ptr());\n        wrapper->owned = false;\n        void *&valueptr = values_and_holders(wrapper).begin()->value_ptr();\n\n        switch (policy) {\n            case return_value_policy::automatic:\n            case return_value_policy::take_ownership:\n                valueptr = src;\n                wrapper->owned = true;\n                break;\n\n            case return_value_policy::automatic_reference:\n            case return_value_policy::reference:\n                valueptr = src;\n                wrapper->owned = false;\n                break;\n\n            case return_value_policy::copy:\n                if (copy_constructor) {\n                    valueptr = copy_constructor(src);\n                } else {\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                    std::string type_name(tinfo->cpptype->name());\n                    detail::clean_type_id(type_name);\n                    throw cast_error(\"return_value_policy = copy, but type \" + type_name\n                                     + \" is non-copyable!\");\n#else\n                    throw cast_error(\"return_value_policy = copy, but type is \"\n                                     \"non-copyable! (#define PYBIND11_DETAILED_ERROR_MESSAGES or \"\n                                     \"compile in debug mode for details)\");\n#endif\n                }\n                wrapper->owned = true;\n                break;\n\n            case return_value_policy::move:\n                if (move_constructor) {\n                    valueptr = move_constructor(src);\n                } else if (copy_constructor) {\n                    valueptr = copy_constructor(src);\n                } else {\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                    std::string type_name(tinfo->cpptype->name());\n                    detail::clean_type_id(type_name);\n                    throw cast_error(\"return_value_policy = move, but type \" + type_name\n                                     + \" is neither movable nor copyable!\");\n#else\n                    throw cast_error(\"return_value_policy = move, but type is neither \"\n                                     \"movable nor copyable! \"\n                                     \"(#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in \"\n                                     \"debug mode for details)\");\n#endif\n                }\n                wrapper->owned = true;\n                break;\n\n            case return_value_policy::reference_internal:\n                valueptr = src;\n                wrapper->owned = false;\n                keep_alive_impl(inst, parent);\n                break;\n\n            default:\n                throw cast_error(\"unhandled return_value_policy: should not happen!\");\n        }\n\n        tinfo->init_instance(wrapper, existing_holder);\n\n        return inst.release();\n    }\n\n    // Base methods for generic caster; there are overridden in copyable_holder_caster\n    void load_value(value_and_holder &&v_h) {\n        auto *&vptr = v_h.value_ptr();\n        // Lazy allocation for unallocated values:\n        if (vptr == nullptr) {\n            const auto *type = v_h.type ? v_h.type : typeinfo;\n            if (type->operator_new) {\n                vptr = type->operator_new(type->type_size);\n            } else {\n#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)\n                if (type->type_align > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {\n                    vptr = ::operator new(type->type_size, std::align_val_t(type->type_align));\n                } else {\n                    vptr = ::operator new(type->type_size);\n                }\n#else\n                vptr = ::operator new(type->type_size);\n#endif\n            }\n        }\n        value = vptr;\n    }\n    bool try_implicit_casts(handle src, bool convert) {\n        for (const auto &cast : typeinfo->implicit_casts) {\n            type_caster_generic sub_caster(*cast.first);\n            if (sub_caster.load(src, convert)) {\n                value = cast.second(sub_caster.value);\n                return true;\n            }\n        }\n        return false;\n    }\n    bool try_direct_conversions(handle src) {\n        for (auto &converter : *typeinfo->direct_conversions) {\n            if (converter(src.ptr(), value)) {\n                return true;\n            }\n        }\n        return false;\n    }\n    void check_holder_compat() {}\n\n    PYBIND11_NOINLINE static void *local_load(PyObject *src, const type_info *ti) {\n        auto caster = type_caster_generic(ti);\n        if (caster.load(src, false)) {\n            return caster.value;\n        }\n        return nullptr;\n    }\n\n    /// Try to load with foreign typeinfo, if available. Used when there is no\n    /// native typeinfo, or when the native one wasn't able to produce a value.\n    PYBIND11_NOINLINE bool try_load_foreign_module_local(handle src) {\n        constexpr auto *local_key = PYBIND11_MODULE_LOCAL_ID;\n        const auto pytype = type::handle_of(src);\n        if (!hasattr(pytype, local_key)) {\n            return false;\n        }\n\n        type_info *foreign_typeinfo = reinterpret_borrow<capsule>(getattr(pytype, local_key));\n        // Only consider this foreign loader if actually foreign and is a loader of the correct cpp\n        // type\n        if (foreign_typeinfo->module_local_load == &local_load\n            || (cpptype && !same_type(*cpptype, *foreign_typeinfo->cpptype))) {\n            return false;\n        }\n\n        if (auto *result = foreign_typeinfo->module_local_load(src.ptr(), foreign_typeinfo)) {\n            value = result;\n            return true;\n        }\n        return false;\n    }\n\n    // Implementation of `load`; this takes the type of `this` so that it can dispatch the relevant\n    // bits of code between here and copyable_holder_caster where the two classes need different\n    // logic (without having to resort to virtual inheritance).\n    template <typename ThisT>\n    PYBIND11_NOINLINE bool load_impl(handle src, bool convert) {\n        if (!src) {\n            return false;\n        }\n        if (!typeinfo) {\n            return try_load_foreign_module_local(src);\n        }\n\n        auto &this_ = static_cast<ThisT &>(*this);\n        this_.check_holder_compat();\n\n        PyTypeObject *srctype = Py_TYPE(src.ptr());\n\n        // Case 1: If src is an exact type match for the target type then we can reinterpret_cast\n        // the instance's value pointer to the target type:\n        if (srctype == typeinfo->type) {\n            this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());\n            return true;\n        }\n        // Case 2: We have a derived class\n        if (PyType_IsSubtype(srctype, typeinfo->type)) {\n            const auto &bases = all_type_info(srctype);\n            bool no_cpp_mi = typeinfo->simple_type;\n\n            // Case 2a: the python type is a Python-inherited derived class that inherits from just\n            // one simple (no MI) pybind11 class, or is an exact match, so the C++ instance is of\n            // the right type and we can use reinterpret_cast.\n            // (This is essentially the same as case 2b, but because not using multiple inheritance\n            // is extremely common, we handle it specially to avoid the loop iterator and type\n            // pointer lookup overhead)\n            if (bases.size() == 1 && (no_cpp_mi || bases.front()->type == typeinfo->type)) {\n                this_.load_value(reinterpret_cast<instance *>(src.ptr())->get_value_and_holder());\n                return true;\n            }\n            // Case 2b: the python type inherits from multiple C++ bases.  Check the bases to see\n            // if we can find an exact match (or, for a simple C++ type, an inherited match); if\n            // so, we can safely reinterpret_cast to the relevant pointer.\n            if (bases.size() > 1) {\n                for (auto *base : bases) {\n                    if (no_cpp_mi ? PyType_IsSubtype(base->type, typeinfo->type)\n                                  : base->type == typeinfo->type) {\n                        this_.load_value(\n                            reinterpret_cast<instance *>(src.ptr())->get_value_and_holder(base));\n                        return true;\n                    }\n                }\n            }\n\n            // Case 2c: C++ multiple inheritance is involved and we couldn't find an exact type\n            // match in the registered bases, above, so try implicit casting (needed for proper C++\n            // casting when MI is involved).\n            if (this_.try_implicit_casts(src, convert)) {\n                return true;\n            }\n        }\n\n        // Perform an implicit conversion\n        if (convert) {\n            for (const auto &converter : typeinfo->implicit_conversions) {\n                auto temp = reinterpret_steal<object>(converter(src.ptr(), typeinfo->type));\n                if (load_impl<ThisT>(temp, false)) {\n                    loader_life_support::add_patient(temp);\n                    return true;\n                }\n            }\n            if (this_.try_direct_conversions(src)) {\n                return true;\n            }\n        }\n\n        // Failed to match local typeinfo. Try again with global.\n        if (typeinfo->module_local) {\n            if (auto *gtype = get_global_type_info(*typeinfo->cpptype)) {\n                typeinfo = gtype;\n                return load(src, false);\n            }\n        }\n\n        // Global typeinfo has precedence over foreign module_local\n        if (try_load_foreign_module_local(src)) {\n            return true;\n        }\n\n        // Custom converters didn't take None, now we convert None to nullptr.\n        if (src.is_none()) {\n            // Defer accepting None to other overloads (if we aren't in convert mode):\n            if (!convert) {\n                return false;\n            }\n            value = nullptr;\n            return true;\n        }\n\n        return false;\n    }\n\n    // Called to do type lookup and wrap the pointer and type in a pair when a dynamic_cast\n    // isn't needed or can't be used.  If the type is unknown, sets the error and returns a pair\n    // with .second = nullptr.  (p.first = nullptr is not an error: it becomes None).\n    PYBIND11_NOINLINE static std::pair<const void *, const type_info *>\n    src_and_type(const void *src,\n                 const std::type_info &cast_type,\n                 const std::type_info *rtti_type = nullptr) {\n        if (auto *tpi = get_type_info(cast_type)) {\n            return {src, const_cast<const type_info *>(tpi)};\n        }\n\n        // Not found, set error:\n        std::string tname = rtti_type ? rtti_type->name() : cast_type.name();\n        detail::clean_type_id(tname);\n        std::string msg = \"Unregistered type : \" + tname;\n        set_error(PyExc_TypeError, msg.c_str());\n        return {nullptr, nullptr};\n    }\n\n    const type_info *typeinfo = nullptr;\n    const std::type_info *cpptype = nullptr;\n    void *value = nullptr;\n};\n\n/**\n * Determine suitable casting operator for pointer-or-lvalue-casting type casters.  The type caster\n * needs to provide `operator T*()` and `operator T&()` operators.\n *\n * If the type supports moving the value away via an `operator T&&() &&` method, it should use\n * `movable_cast_op_type` instead.\n */\ntemplate <typename T>\nusing cast_op_type = conditional_t<std::is_pointer<remove_reference_t<T>>::value,\n                                   typename std::add_pointer<intrinsic_t<T>>::type,\n                                   typename std::add_lvalue_reference<intrinsic_t<T>>::type>;\n\n/**\n * Determine suitable casting operator for a type caster with a movable value.  Such a type caster\n * needs to provide `operator T*()`, `operator T&()`, and `operator T&&() &&`.  The latter will be\n * called in appropriate contexts where the value can be moved rather than copied.\n *\n * These operator are automatically provided when using the PYBIND11_TYPE_CASTER macro.\n */\ntemplate <typename T>\nusing movable_cast_op_type\n    = conditional_t<std::is_pointer<typename std::remove_reference<T>::type>::value,\n                    typename std::add_pointer<intrinsic_t<T>>::type,\n                    conditional_t<std::is_rvalue_reference<T>::value,\n                                  typename std::add_rvalue_reference<intrinsic_t<T>>::type,\n                                  typename std::add_lvalue_reference<intrinsic_t<T>>::type>>;\n\n// Does the container have a mapped type and is it recursive?\n// Implemented by specializations below.\ntemplate <typename Container, typename SFINAE = void>\nstruct container_mapped_type_traits {\n    static constexpr bool has_mapped_type = false;\n    static constexpr bool has_recursive_mapped_type = false;\n};\n\ntemplate <typename Container>\nstruct container_mapped_type_traits<\n    Container,\n    typename std::enable_if<\n        std::is_same<typename Container::mapped_type, Container>::value>::type> {\n    static constexpr bool has_mapped_type = true;\n    static constexpr bool has_recursive_mapped_type = true;\n};\n\ntemplate <typename Container>\nstruct container_mapped_type_traits<\n    Container,\n    typename std::enable_if<\n        negation<std::is_same<typename Container::mapped_type, Container>>::value>::type> {\n    static constexpr bool has_mapped_type = true;\n    static constexpr bool has_recursive_mapped_type = false;\n};\n\n// Does the container have a value type and is it recursive?\n// Implemented by specializations below.\ntemplate <typename Container, typename SFINAE = void>\nstruct container_value_type_traits : std::false_type {\n    static constexpr bool has_value_type = false;\n    static constexpr bool has_recursive_value_type = false;\n};\n\ntemplate <typename Container>\nstruct container_value_type_traits<\n    Container,\n    typename std::enable_if<\n        std::is_same<typename Container::value_type, Container>::value>::type> {\n    static constexpr bool has_value_type = true;\n    static constexpr bool has_recursive_value_type = true;\n};\n\ntemplate <typename Container>\nstruct container_value_type_traits<\n    Container,\n    typename std::enable_if<\n        negation<std::is_same<typename Container::value_type, Container>>::value>::type> {\n    static constexpr bool has_value_type = true;\n    static constexpr bool has_recursive_value_type = false;\n};\n\n/*\n * Tag to be used for representing the bottom of recursively defined types.\n * Define this tag so we don't have to use void.\n */\nstruct recursive_bottom {};\n\n/*\n * Implementation detail of `recursive_container_traits` below.\n * `T` is the `value_type` of the container, which might need to be modified to\n * avoid recursive types and const types.\n */\ntemplate <typename T, bool is_this_a_map>\nstruct impl_type_to_check_recursively {\n    /*\n     * If the container is recursive, then no further recursion should be done.\n     */\n    using if_recursive = recursive_bottom;\n    /*\n     * Otherwise yield `T` unchanged.\n     */\n    using if_not_recursive = T;\n};\n\n/*\n * For pairs - only as value type of a map -, the first type should remove the `const`.\n * Also, if the map is recursive, then the recursive checking should consider\n * the first type only.\n */\ntemplate <typename A, typename B>\nstruct impl_type_to_check_recursively<std::pair<A, B>, /* is_this_a_map = */ true> {\n    using if_recursive = typename std::remove_const<A>::type;\n    using if_not_recursive = std::pair<typename std::remove_const<A>::type, B>;\n};\n\n/*\n * Implementation of `recursive_container_traits` below.\n */\ntemplate <typename Container, typename SFINAE = void>\nstruct impl_recursive_container_traits {\n    using type_to_check_recursively = recursive_bottom;\n};\n\ntemplate <typename Container>\nstruct impl_recursive_container_traits<\n    Container,\n    typename std::enable_if<container_value_type_traits<Container>::has_value_type>::type> {\n    static constexpr bool is_recursive\n        = container_mapped_type_traits<Container>::has_recursive_mapped_type\n          || container_value_type_traits<Container>::has_recursive_value_type;\n    /*\n     * This member dictates which type Pybind11 should check recursively in traits\n     * such as `is_move_constructible`, `is_copy_constructible`, `is_move_assignable`, ...\n     * Direct access to `value_type` should be avoided:\n     * 1. `value_type` might recursively contain the type again\n     * 2. `value_type` of STL map types is `std::pair<A const, B>`, the `const`\n     *    should be removed.\n     *\n     */\n    using type_to_check_recursively = typename std::conditional<\n        is_recursive,\n        typename impl_type_to_check_recursively<\n            typename Container::value_type,\n            container_mapped_type_traits<Container>::has_mapped_type>::if_recursive,\n        typename impl_type_to_check_recursively<\n            typename Container::value_type,\n            container_mapped_type_traits<Container>::has_mapped_type>::if_not_recursive>::type;\n};\n\n/*\n * This trait defines the `type_to_check_recursively` which is needed to properly\n * handle recursively defined traits such as `is_move_constructible` without going\n * into an infinite recursion.\n * Should be used instead of directly accessing the `value_type`.\n * It cancels the recursion by returning the `recursive_bottom` tag.\n *\n * The default definition of `type_to_check_recursively` is as follows:\n *\n * 1. By default, it is `recursive_bottom`, so that the recursion is canceled.\n * 2. If the type is non-recursive and defines a `value_type`, then the `value_type` is used.\n *    If the `value_type` is a pair and a `mapped_type` is defined,\n *    then the `const` is removed from the first type.\n * 3. If the type is recursive and `value_type` is not a pair, then `recursive_bottom` is returned.\n * 4. If the type is recursive and `value_type` is a pair and a `mapped_type` is defined,\n *    then `const` is removed from the first type and the first type is returned.\n *\n * This behavior can be extended by the user as seen in test_stl_binders.cpp.\n *\n * This struct is exactly the same as impl_recursive_container_traits.\n * The duplication achieves that user-defined specializations don't compete\n * with internal specializations, but take precedence.\n */\ntemplate <typename Container, typename SFINAE = void>\nstruct recursive_container_traits : impl_recursive_container_traits<Container> {};\n\ntemplate <typename T>\nstruct is_move_constructible\n    : all_of<std::is_move_constructible<T>,\n             is_move_constructible<\n                 typename recursive_container_traits<T>::type_to_check_recursively>> {};\n\ntemplate <>\nstruct is_move_constructible<recursive_bottom> : std::true_type {};\n\n// Likewise for std::pair\n// (after C++17 it is mandatory that the move constructor not exist when the two types aren't\n// themselves move constructible, but this can not be relied upon when T1 or T2 are themselves\n// containers).\ntemplate <typename T1, typename T2>\nstruct is_move_constructible<std::pair<T1, T2>>\n    : all_of<is_move_constructible<T1>, is_move_constructible<T2>> {};\n\n// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when\n// T is non-copyable, but code containing such a copy constructor fails to actually compile.\ntemplate <typename T>\nstruct is_copy_constructible\n    : all_of<std::is_copy_constructible<T>,\n             is_copy_constructible<\n                 typename recursive_container_traits<T>::type_to_check_recursively>> {};\n\ntemplate <>\nstruct is_copy_constructible<recursive_bottom> : std::true_type {};\n\n// Likewise for std::pair\n// (after C++17 it is mandatory that the copy constructor not exist when the two types aren't\n// themselves copy constructible, but this can not be relied upon when T1 or T2 are themselves\n// containers).\ntemplate <typename T1, typename T2>\nstruct is_copy_constructible<std::pair<T1, T2>>\n    : all_of<is_copy_constructible<T1>, is_copy_constructible<T2>> {};\n\n// The same problems arise with std::is_copy_assignable, so we use the same workaround.\ntemplate <typename T>\nstruct is_copy_assignable\n    : all_of<\n          std::is_copy_assignable<T>,\n          is_copy_assignable<typename recursive_container_traits<T>::type_to_check_recursively>> {\n};\n\ntemplate <>\nstruct is_copy_assignable<recursive_bottom> : std::true_type {};\n\ntemplate <typename T1, typename T2>\nstruct is_copy_assignable<std::pair<T1, T2>>\n    : all_of<is_copy_assignable<T1>, is_copy_assignable<T2>> {};\n\nPYBIND11_NAMESPACE_END(detail)\n\n// polymorphic_type_hook<itype>::get(src, tinfo) determines whether the object pointed\n// to by `src` actually is an instance of some class derived from `itype`.\n// If so, it sets `tinfo` to point to the std::type_info representing that derived\n// type, and returns a pointer to the start of the most-derived object of that type\n// (in which `src` is a subobject; this will be the same address as `src` in most\n// single inheritance cases). If not, or if `src` is nullptr, it simply returns `src`\n// and leaves `tinfo` at its default value of nullptr.\n//\n// The default polymorphic_type_hook just returns src. A specialization for polymorphic\n// types determines the runtime type of the passed object and adjusts the this-pointer\n// appropriately via dynamic_cast<void*>. This is what enables a C++ Animal* to appear\n// to Python as a Dog (if Dog inherits from Animal, Animal is polymorphic, Dog is\n// registered with pybind11, and this Animal is in fact a Dog).\n//\n// You may specialize polymorphic_type_hook yourself for types that want to appear\n// polymorphic to Python but do not use C++ RTTI. (This is a not uncommon pattern\n// in performance-sensitive applications, used most notably in LLVM.)\n//\n// polymorphic_type_hook_base allows users to specialize polymorphic_type_hook with\n// std::enable_if. User provided specializations will always have higher priority than\n// the default implementation and specialization provided in polymorphic_type_hook_base.\ntemplate <typename itype, typename SFINAE = void>\nstruct polymorphic_type_hook_base {\n    static const void *get(const itype *src, const std::type_info *&) { return src; }\n};\ntemplate <typename itype>\nstruct polymorphic_type_hook_base<itype, detail::enable_if_t<std::is_polymorphic<itype>::value>> {\n    static const void *get(const itype *src, const std::type_info *&type) {\n        type = src ? &typeid(*src) : nullptr;\n        return dynamic_cast<const void *>(src);\n    }\n};\ntemplate <typename itype, typename SFINAE = void>\nstruct polymorphic_type_hook : public polymorphic_type_hook_base<itype> {};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// Generic type caster for objects stored on the heap\ntemplate <typename type>\nclass type_caster_base : public type_caster_generic {\n    using itype = intrinsic_t<type>;\n\npublic:\n    static constexpr auto name = const_name<type>();\n\n    type_caster_base() : type_caster_base(typeid(type)) {}\n    explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) {}\n\n    static handle cast(const itype &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast(&src, policy, parent);\n    }\n\n    static handle cast(itype &&src, return_value_policy, handle parent) {\n        return cast(&src, return_value_policy::move, parent);\n    }\n\n    // Returns a (pointer, type_info) pair taking care of necessary type lookup for a\n    // polymorphic type (using RTTI by default, but can be overridden by specializing\n    // polymorphic_type_hook). If the instance isn't derived, returns the base version.\n    static std::pair<const void *, const type_info *> src_and_type(const itype *src) {\n        const auto &cast_type = typeid(itype);\n        const std::type_info *instance_type = nullptr;\n        const void *vsrc = polymorphic_type_hook<itype>::get(src, instance_type);\n        if (instance_type && !same_type(cast_type, *instance_type)) {\n            // This is a base pointer to a derived type. If the derived type is registered\n            // with pybind11, we want to make the full derived object available.\n            // In the typical case where itype is polymorphic, we get the correct\n            // derived pointer (which may be != base pointer) by a dynamic_cast to\n            // most derived type. If itype is not polymorphic, we won't get here\n            // except via a user-provided specialization of polymorphic_type_hook,\n            // and the user has promised that no this-pointer adjustment is\n            // required in that case, so it's OK to use static_cast.\n            if (const auto *tpi = get_type_info(*instance_type)) {\n                return {vsrc, tpi};\n            }\n        }\n        // Otherwise we have either a nullptr, an `itype` pointer, or an unknown derived pointer,\n        // so don't do a cast\n        return type_caster_generic::src_and_type(src, cast_type, instance_type);\n    }\n\n    static handle cast(const itype *src, return_value_policy policy, handle parent) {\n        auto st = src_and_type(src);\n        return type_caster_generic::cast(st.first,\n                                         policy,\n                                         parent,\n                                         st.second,\n                                         make_copy_constructor(src),\n                                         make_move_constructor(src));\n    }\n\n    static handle cast_holder(const itype *src, const void *holder) {\n        auto st = src_and_type(src);\n        return type_caster_generic::cast(st.first,\n                                         return_value_policy::take_ownership,\n                                         {},\n                                         st.second,\n                                         nullptr,\n                                         nullptr,\n                                         holder);\n    }\n\n    template <typename T>\n    using cast_op_type = detail::cast_op_type<T>;\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator itype *() { return (type *) value; }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator itype &() {\n        if (!value) {\n            throw reference_cast_error();\n        }\n        return *((itype *) value);\n    }\n\nprotected:\n    using Constructor = void *(*) (const void *);\n\n    /* Only enabled when the types are {copy,move}-constructible *and* when the type\n       does not have a private operator new implementation. A comma operator is used in the\n       decltype argument to apply SFINAE to the public copy/move constructors.*/\n    template <typename T, typename = enable_if_t<is_copy_constructible<T>::value>>\n    static auto make_copy_constructor(const T *)\n        -> decltype(new T(std::declval<const T>()), Constructor{}) {\n        return [](const void *arg) -> void * { return new T(*reinterpret_cast<const T *>(arg)); };\n    }\n\n    template <typename T, typename = enable_if_t<is_move_constructible<T>::value>>\n    static auto make_move_constructor(const T *)\n        -> decltype(new T(std::declval<T &&>()), Constructor{}) {\n        return [](const void *arg) -> void * {\n            return new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg))));\n        };\n    }\n\n    static Constructor make_copy_constructor(...) { return nullptr; }\n    static Constructor make_move_constructor(...) { return nullptr; }\n};\n\ninline std::string quote_cpp_type_name(const std::string &cpp_type_name) {\n    return cpp_type_name; // No-op for now. See PR #4888\n}\n\nPYBIND11_NOINLINE std::string type_info_description(const std::type_info &ti) {\n    if (auto *type_data = get_type_info(ti)) {\n        handle th((PyObject *) type_data->type);\n        return th.attr(\"__module__\").cast<std::string>() + '.'\n               + th.attr(\"__qualname__\").cast<std::string>();\n    }\n    return quote_cpp_type_name(clean_type_id(ti.name()));\n}\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/detail/typeid.h",
    "content": "/*\n    pybind11/detail/typeid.h: Compiler-independent access to type identifiers\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include <cstdio>\n#include <cstdlib>\n\n#if defined(__GNUG__)\n#    include <cxxabi.h>\n#endif\n\n#include \"common.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// Erase all occurrences of a substring\ninline void erase_all(std::string &string, const std::string &search) {\n    for (size_t pos = 0;;) {\n        pos = string.find(search, pos);\n        if (pos == std::string::npos) {\n            break;\n        }\n        string.erase(pos, search.length());\n    }\n}\n\nPYBIND11_NOINLINE void clean_type_id(std::string &name) {\n#if defined(__GNUG__)\n    int status = 0;\n    std::unique_ptr<char, void (*)(void *)> res{\n        abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free};\n    if (status == 0) {\n        name = res.get();\n    }\n#else\n    detail::erase_all(name, \"class \");\n    detail::erase_all(name, \"struct \");\n    detail::erase_all(name, \"enum \");\n#endif\n    detail::erase_all(name, \"pybind11::\");\n}\n\ninline std::string clean_type_id(const char *typeid_name) {\n    std::string name(typeid_name);\n    detail::clean_type_id(name);\n    return name;\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Return a string representation of a C++ type\ntemplate <typename T>\nstatic std::string type_id() {\n    return detail::clean_type_id(typeid(T).name());\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/eigen/common.h",
    "content": "// Copyright (c) 2023 The pybind Community.\n\n#pragma once\n\n// Common message for `static_assert()`s, which are useful to easily\n// preempt much less obvious errors.\n#define PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED                                    \\\n    \"Pointer types (in particular `PyObject *`) are not supported as scalar types for Eigen \"     \\\n    \"types.\"\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/eigen/matrix.h",
    "content": "/*\n    pybind11/eigen/matrix.h: Transparent conversion for dense and sparse Eigen matrices\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"../numpy.h\"\n#include \"common.h\"\n\n/* HINT: To suppress warnings originating from the Eigen headers, use -isystem.\n   See also:\n       https://stackoverflow.com/questions/2579576/i-dir-vs-isystem-dir\n       https://stackoverflow.com/questions/1741816/isystem-for-ms-visual-studio-c-compiler\n*/\nPYBIND11_WARNING_PUSH\nPYBIND11_WARNING_DISABLE_MSVC(5054) // https://github.com/pybind/pybind11/pull/3741\n//       C5054: operator '&': deprecated between enumerations of different types\n#if defined(__MINGW32__)\nPYBIND11_WARNING_DISABLE_GCC(\"-Wmaybe-uninitialized\")\n#endif\n\n#include <Eigen/Core>\n#include <Eigen/SparseCore>\n\nPYBIND11_WARNING_POP\n\n// Eigen prior to 3.2.7 doesn't have proper move constructors--but worse, some classes get implicit\n// move constructors that break things.  We could detect this an explicitly copy, but an extra copy\n// of matrices seems highly undesirable.\nstatic_assert(EIGEN_VERSION_AT_LEAST(3, 2, 7),\n              \"Eigen matrix support in pybind11 requires Eigen >= 3.2.7\");\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\n// Provide a convenience alias for easier pass-by-ref usage with fully dynamic strides:\nusing EigenDStride = Eigen::Stride<Eigen::Dynamic, Eigen::Dynamic>;\ntemplate <typename MatrixType>\nusing EigenDRef = Eigen::Ref<MatrixType, 0, EigenDStride>;\ntemplate <typename MatrixType>\nusing EigenDMap = Eigen::Map<MatrixType, 0, EigenDStride>;\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n#if EIGEN_VERSION_AT_LEAST(3, 3, 0)\nusing EigenIndex = Eigen::Index;\ntemplate <typename Scalar, int Flags, typename StorageIndex>\nusing EigenMapSparseMatrix = Eigen::Map<Eigen::SparseMatrix<Scalar, Flags, StorageIndex>>;\n#else\nusing EigenIndex = EIGEN_DEFAULT_DENSE_INDEX_TYPE;\ntemplate <typename Scalar, int Flags, typename StorageIndex>\nusing EigenMapSparseMatrix = Eigen::MappedSparseMatrix<Scalar, Flags, StorageIndex>;\n#endif\n\n// Matches Eigen::Map, Eigen::Ref, blocks, etc:\ntemplate <typename T>\nusing is_eigen_dense_map = all_of<is_template_base_of<Eigen::DenseBase, T>,\n                                  std::is_base_of<Eigen::MapBase<T, Eigen::ReadOnlyAccessors>, T>>;\ntemplate <typename T>\nusing is_eigen_mutable_map = std::is_base_of<Eigen::MapBase<T, Eigen::WriteAccessors>, T>;\ntemplate <typename T>\nusing is_eigen_dense_plain\n    = all_of<negation<is_eigen_dense_map<T>>, is_template_base_of<Eigen::PlainObjectBase, T>>;\ntemplate <typename T>\nusing is_eigen_sparse = is_template_base_of<Eigen::SparseMatrixBase, T>;\n// Test for objects inheriting from EigenBase<Derived> that aren't captured by the above.  This\n// basically covers anything that can be assigned to a dense matrix but that don't have a typical\n// matrix data layout that can be copied from their .data().  For example, DiagonalMatrix and\n// SelfAdjointView fall into this category.\ntemplate <typename T>\nusing is_eigen_other\n    = all_of<is_template_base_of<Eigen::EigenBase, T>,\n             negation<any_of<is_eigen_dense_map<T>, is_eigen_dense_plain<T>, is_eigen_sparse<T>>>>;\n\n// Captures numpy/eigen conformability status (returned by EigenProps::conformable()):\ntemplate <bool EigenRowMajor>\nstruct EigenConformable {\n    bool conformable = false;\n    EigenIndex rows = 0, cols = 0;\n    EigenDStride stride{0, 0};    // Only valid if negativestrides is false!\n    bool negativestrides = false; // If true, do not use stride!\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    EigenConformable(bool fits = false) : conformable{fits} {}\n    // Matrix type:\n    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex rstride, EigenIndex cstride)\n        : conformable{true}, rows{r}, cols{c},\n          // TODO: when Eigen bug #747 is fixed, remove the tests for non-negativity.\n          // http://eigen.tuxfamily.org/bz/show_bug.cgi?id=747\n          stride{EigenRowMajor ? (rstride > 0 ? rstride : 0)\n                               : (cstride > 0 ? cstride : 0) /* outer stride */,\n                 EigenRowMajor ? (cstride > 0 ? cstride : 0)\n                               : (rstride > 0 ? rstride : 0) /* inner stride */},\n          negativestrides{rstride < 0 || cstride < 0} {}\n    // Vector type:\n    EigenConformable(EigenIndex r, EigenIndex c, EigenIndex stride)\n        : EigenConformable(r, c, r == 1 ? c * stride : stride, c == 1 ? r : r * stride) {}\n\n    template <typename props>\n    bool stride_compatible() const {\n        // To have compatible strides, we need (on both dimensions) one of fully dynamic strides,\n        // matching strides, or a dimension size of 1 (in which case the stride value is\n        // irrelevant). Alternatively, if any dimension size is 0, the strides are not relevant\n        // (and numpy ≥ 1.23 sets the strides to 0 in that case, so we need to check explicitly).\n        if (negativestrides) {\n            return false;\n        }\n        if (rows == 0 || cols == 0) {\n            return true;\n        }\n        return (props::inner_stride == Eigen::Dynamic || props::inner_stride == stride.inner()\n                || (EigenRowMajor ? cols : rows) == 1)\n               && (props::outer_stride == Eigen::Dynamic || props::outer_stride == stride.outer()\n                   || (EigenRowMajor ? rows : cols) == 1);\n    }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator bool() const { return conformable; }\n};\n\ntemplate <typename Type>\nstruct eigen_extract_stride {\n    using type = Type;\n};\ntemplate <typename PlainObjectType, int MapOptions, typename StrideType>\nstruct eigen_extract_stride<Eigen::Map<PlainObjectType, MapOptions, StrideType>> {\n    using type = StrideType;\n};\ntemplate <typename PlainObjectType, int Options, typename StrideType>\nstruct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> {\n    using type = StrideType;\n};\n\n// Helper struct for extracting information from an Eigen type\ntemplate <typename Type_>\nstruct EigenProps {\n    using Type = Type_;\n    using Scalar = typename Type::Scalar;\n    using StrideType = typename eigen_extract_stride<Type>::type;\n    static constexpr EigenIndex rows = Type::RowsAtCompileTime, cols = Type::ColsAtCompileTime,\n                                size = Type::SizeAtCompileTime;\n    static constexpr bool row_major = Type::IsRowMajor,\n                          vector\n                          = Type::IsVectorAtCompileTime, // At least one dimension has fixed size 1\n        fixed_rows = rows != Eigen::Dynamic, fixed_cols = cols != Eigen::Dynamic,\n                          fixed = size != Eigen::Dynamic, // Fully-fixed size\n        dynamic = !fixed_rows && !fixed_cols;             // Fully-dynamic size\n\n    template <EigenIndex i, EigenIndex ifzero>\n    using if_zero = std::integral_constant<EigenIndex, i == 0 ? ifzero : i>;\n    static constexpr EigenIndex inner_stride\n        = if_zero<StrideType::InnerStrideAtCompileTime, 1>::value,\n        outer_stride = if_zero < StrideType::OuterStrideAtCompileTime,\n        vector      ? size\n        : row_major ? cols\n                    : rows > ::value;\n    static constexpr bool dynamic_stride\n        = inner_stride == Eigen::Dynamic && outer_stride == Eigen::Dynamic;\n    static constexpr bool requires_row_major\n        = !dynamic_stride && !vector && (row_major ? inner_stride : outer_stride) == 1;\n    static constexpr bool requires_col_major\n        = !dynamic_stride && !vector && (row_major ? outer_stride : inner_stride) == 1;\n\n    // Takes an input array and determines whether we can make it fit into the Eigen type.  If\n    // the array is a vector, we attempt to fit it into either an Eigen 1xN or Nx1 vector\n    // (preferring the latter if it will fit in either, i.e. for a fully dynamic matrix type).\n    static EigenConformable<row_major> conformable(const array &a) {\n        const auto dims = a.ndim();\n        if (dims < 1 || dims > 2) {\n            return false;\n        }\n\n        if (dims == 2) { // Matrix type: require exact match (or dynamic)\n\n            EigenIndex np_rows = a.shape(0), np_cols = a.shape(1),\n                       np_rstride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar)),\n                       np_cstride = a.strides(1) / static_cast<ssize_t>(sizeof(Scalar));\n            if ((fixed_rows && np_rows != rows) || (fixed_cols && np_cols != cols)) {\n                return false;\n            }\n\n            return {np_rows, np_cols, np_rstride, np_cstride};\n        }\n\n        // Otherwise we're storing an n-vector.  Only one of the strides will be used, but\n        // whichever is used, we want the (single) numpy stride value.\n        const EigenIndex n = a.shape(0),\n                         stride = a.strides(0) / static_cast<ssize_t>(sizeof(Scalar));\n\n        if (vector) { // Eigen type is a compile-time vector\n            if (fixed && size != n) {\n                return false; // Vector size mismatch\n            }\n            return {rows == 1 ? 1 : n, cols == 1 ? 1 : n, stride};\n        }\n        if (fixed) {\n            // The type has a fixed size, but is not a vector: abort\n            return false;\n        }\n        if (fixed_cols) {\n            // Since this isn't a vector, cols must be != 1.  We allow this only if it exactly\n            // equals the number of elements (rows is Dynamic, and so 1 row is allowed).\n            if (cols != n) {\n                return false;\n            }\n            return {1, n, stride};\n        } // Otherwise it's either fully dynamic, or column dynamic; both become a column vector\n        if (fixed_rows && rows != n) {\n            return false;\n        }\n        return {n, 1, stride};\n    }\n\n    static constexpr bool show_writeable\n        = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;\n    static constexpr bool show_order = is_eigen_dense_map<Type>::value;\n    static constexpr bool show_c_contiguous = show_order && requires_row_major;\n    static constexpr bool show_f_contiguous\n        = !show_c_contiguous && show_order && requires_col_major;\n\n    static constexpr auto descriptor\n        = const_name(\"numpy.ndarray[\") + npy_format_descriptor<Scalar>::name + const_name(\"[\")\n          + const_name<fixed_rows>(const_name<(size_t) rows>(), const_name(\"m\")) + const_name(\", \")\n          + const_name<fixed_cols>(const_name<(size_t) cols>(), const_name(\"n\")) + const_name(\"]\")\n          +\n          // For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to\n          // be satisfied: writeable=True (for a mutable reference), and, depending on the map's\n          // stride options, possibly f_contiguous or c_contiguous.  We include them in the\n          // descriptor output to provide some hint as to why a TypeError is occurring (otherwise\n          // it can be confusing to see that a function accepts a 'numpy.ndarray[float64[3,2]]' and\n          // an error message that you *gave* a numpy.ndarray of the right type and dimensions.\n          const_name<show_writeable>(\", flags.writeable\", \"\")\n          + const_name<show_c_contiguous>(\", flags.c_contiguous\", \"\")\n          + const_name<show_f_contiguous>(\", flags.f_contiguous\", \"\") + const_name(\"]\");\n};\n\n// Casts an Eigen type to numpy array.  If given a base, the numpy array references the src data,\n// otherwise it'll make a copy.  writeable lets you turn off the writeable flag for the array.\ntemplate <typename props>\nhandle\neigen_array_cast(typename props::Type const &src, handle base = handle(), bool writeable = true) {\n    constexpr ssize_t elem_size = sizeof(typename props::Scalar);\n    array a;\n    if (props::vector) {\n        a = array({src.size()}, {elem_size * src.innerStride()}, src.data(), base);\n    } else {\n        a = array({src.rows(), src.cols()},\n                  {elem_size * src.rowStride(), elem_size * src.colStride()},\n                  src.data(),\n                  base);\n    }\n\n    if (!writeable) {\n        array_proxy(a.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;\n    }\n\n    return a.release();\n}\n\n// Takes an lvalue ref to some Eigen type and a (python) base object, creating a numpy array that\n// reference the Eigen object's data with `base` as the python-registered base class (if omitted,\n// the base will be set to None, and lifetime management is up to the caller).  The numpy array is\n// non-writeable if the given type is const.\ntemplate <typename props, typename Type>\nhandle eigen_ref_array(Type &src, handle parent = none()) {\n    // none here is to get past array's should-we-copy detection, which currently always\n    // copies when there is no base.  Setting the base to None should be harmless.\n    return eigen_array_cast<props>(src, parent, !std::is_const<Type>::value);\n}\n\n// Takes a pointer to some dense, plain Eigen type, builds a capsule around it, then returns a\n// numpy array that references the encapsulated data with a python-side reference to the capsule to\n// tie its destruction to that of any dependent python objects.  Const-ness is determined by\n// whether or not the Type of the pointer given is const.\ntemplate <typename props, typename Type, typename = enable_if_t<is_eigen_dense_plain<Type>::value>>\nhandle eigen_encapsulate(Type *src) {\n    capsule base(src, [](void *o) { delete static_cast<Type *>(o); });\n    return eigen_ref_array<props>(*src, base);\n}\n\n// Type caster for regular, dense matrix types (e.g. MatrixXd), but not maps/refs/etc. of dense\n// types.\ntemplate <typename Type>\nstruct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {\n    using Scalar = typename Type::Scalar;\n    static_assert(!std::is_pointer<Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n    using props = EigenProps<Type>;\n\n    bool load(handle src, bool convert) {\n        // If we're in no-convert mode, only load if given an array of the correct type\n        if (!convert && !isinstance<array_t<Scalar>>(src)) {\n            return false;\n        }\n\n        // Coerce into an array, but don't do type conversion yet; the copy below handles it.\n        auto buf = array::ensure(src);\n\n        if (!buf) {\n            return false;\n        }\n\n        auto dims = buf.ndim();\n        if (dims < 1 || dims > 2) {\n            return false;\n        }\n\n        auto fits = props::conformable(buf);\n        if (!fits) {\n            return false;\n        }\n\n        // Allocate the new type, then build a numpy reference into it\n        value = Type(fits.rows, fits.cols);\n        auto ref = reinterpret_steal<array>(eigen_ref_array<props>(value));\n        if (dims == 1) {\n            ref = ref.squeeze();\n        } else if (ref.ndim() == 1) {\n            buf = buf.squeeze();\n        }\n\n        int result = detail::npy_api::get().PyArray_CopyInto_(ref.ptr(), buf.ptr());\n\n        if (result < 0) { // Copy failed!\n            PyErr_Clear();\n            return false;\n        }\n\n        return true;\n    }\n\nprivate:\n    // Cast implementation\n    template <typename CType>\n    static handle cast_impl(CType *src, return_value_policy policy, handle parent) {\n        switch (policy) {\n            case return_value_policy::take_ownership:\n            case return_value_policy::automatic:\n                return eigen_encapsulate<props>(src);\n            case return_value_policy::move:\n                return eigen_encapsulate<props>(new CType(std::move(*src)));\n            case return_value_policy::copy:\n                return eigen_array_cast<props>(*src);\n            case return_value_policy::reference:\n            case return_value_policy::automatic_reference:\n                return eigen_ref_array<props>(*src);\n            case return_value_policy::reference_internal:\n                return eigen_ref_array<props>(*src, parent);\n            default:\n                throw cast_error(\"unhandled return_value_policy: should not happen!\");\n        };\n    }\n\npublic:\n    // Normal returned non-reference, non-const value:\n    static handle cast(Type &&src, return_value_policy /* policy */, handle parent) {\n        return cast_impl(&src, return_value_policy::move, parent);\n    }\n    // If you return a non-reference const, we mark the numpy array readonly:\n    static handle cast(const Type &&src, return_value_policy /* policy */, handle parent) {\n        return cast_impl(&src, return_value_policy::move, parent);\n    }\n    // lvalue reference return; default (automatic) becomes copy\n    static handle cast(Type &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast_impl(&src, policy, parent);\n    }\n    // const lvalue reference return; default (automatic) becomes copy\n    static handle cast(const Type &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast(&src, policy, parent);\n    }\n    // non-const pointer return\n    static handle cast(Type *src, return_value_policy policy, handle parent) {\n        return cast_impl(src, policy, parent);\n    }\n    // const pointer return\n    static handle cast(const Type *src, return_value_policy policy, handle parent) {\n        return cast_impl(src, policy, parent);\n    }\n\n    static constexpr auto name = props::descriptor;\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator Type *() { return &value; }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator Type &() { return value; }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator Type &&() && { return std::move(value); }\n    template <typename T>\n    using cast_op_type = movable_cast_op_type<T>;\n\nprivate:\n    Type value;\n};\n\n// Base class for casting reference/map/block/etc. objects back to python.\ntemplate <typename MapType>\nstruct eigen_map_caster {\n    static_assert(!std::is_pointer<typename MapType::Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n\nprivate:\n    using props = EigenProps<MapType>;\n\npublic:\n    // Directly referencing a ref/map's data is a bit dangerous (whatever the map/ref points to has\n    // to stay around), but we'll allow it under the assumption that you know what you're doing\n    // (and have an appropriate keep_alive in place).  We return a numpy array pointing directly at\n    // the ref's data (The numpy array ends up read-only if the ref was to a const matrix type.)\n    // Note that this means you need to ensure you don't destroy the object in some other way (e.g.\n    // with an appropriate keep_alive, or with a reference to a statically allocated matrix).\n    static handle cast(const MapType &src, return_value_policy policy, handle parent) {\n        switch (policy) {\n            case return_value_policy::copy:\n                return eigen_array_cast<props>(src);\n            case return_value_policy::reference_internal:\n                return eigen_array_cast<props>(src, parent, is_eigen_mutable_map<MapType>::value);\n            case return_value_policy::reference:\n            case return_value_policy::automatic:\n            case return_value_policy::automatic_reference:\n                return eigen_array_cast<props>(src, none(), is_eigen_mutable_map<MapType>::value);\n            default:\n                // move, take_ownership don't make any sense for a ref/map:\n                pybind11_fail(\"Invalid return_value_policy for Eigen Map/Ref/Block type\");\n        }\n    }\n\n    static constexpr auto name = props::descriptor;\n\n    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return\n    // types but not bound arguments).  We still provide them (with an explicitly delete) so that\n    // you end up here if you try anyway.\n    bool load(handle, bool) = delete;\n    operator MapType() = delete;\n    template <typename>\n    using cast_op_type = MapType;\n};\n\n// We can return any map-like object (but can only load Refs, specialized next):\ntemplate <typename Type>\nstruct type_caster<Type, enable_if_t<is_eigen_dense_map<Type>::value>> : eigen_map_caster<Type> {};\n\n// Loader for Ref<...> arguments.  See the documentation for info on how to make this work without\n// copying (it requires some extra effort in many cases).\ntemplate <typename PlainObjectType, typename StrideType>\nstruct type_caster<\n    Eigen::Ref<PlainObjectType, 0, StrideType>,\n    enable_if_t<is_eigen_dense_map<Eigen::Ref<PlainObjectType, 0, StrideType>>::value>>\n    : public eigen_map_caster<Eigen::Ref<PlainObjectType, 0, StrideType>> {\nprivate:\n    using Type = Eigen::Ref<PlainObjectType, 0, StrideType>;\n    using props = EigenProps<Type>;\n    using Scalar = typename props::Scalar;\n    static_assert(!std::is_pointer<Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n    using MapType = Eigen::Map<PlainObjectType, 0, StrideType>;\n    using Array\n        = array_t<Scalar,\n                  array::forcecast\n                      | ((props::row_major ? props::inner_stride : props::outer_stride) == 1\n                             ? array::c_style\n                         : (props::row_major ? props::outer_stride : props::inner_stride) == 1\n                             ? array::f_style\n                             : 0)>;\n    static constexpr bool need_writeable = is_eigen_mutable_map<Type>::value;\n    // Delay construction (these have no default constructor)\n    std::unique_ptr<MapType> map;\n    std::unique_ptr<Type> ref;\n    // Our array.  When possible, this is just a numpy array pointing to the source data, but\n    // sometimes we can't avoid copying (e.g. input is not a numpy array at all, has an\n    // incompatible layout, or is an array of a type that needs to be converted).  Using a numpy\n    // temporary (rather than an Eigen temporary) saves an extra copy when we need both type\n    // conversion and storage order conversion.  (Note that we refuse to use this temporary copy\n    // when loading an argument for a Ref<M> with M non-const, i.e. a read-write reference).\n    Array copy_or_ref;\n\npublic:\n    bool load(handle src, bool convert) {\n        // First check whether what we have is already an array of the right type.  If not, we\n        // can't avoid a copy (because the copy is also going to do type conversion).\n        bool need_copy = !isinstance<Array>(src);\n\n        EigenConformable<props::row_major> fits;\n        if (!need_copy) {\n            // We don't need a converting copy, but we also need to check whether the strides are\n            // compatible with the Ref's stride requirements\n            auto aref = reinterpret_borrow<Array>(src);\n\n            if (aref && (!need_writeable || aref.writeable())) {\n                fits = props::conformable(aref);\n                if (!fits) {\n                    return false; // Incompatible dimensions\n                }\n                if (!fits.template stride_compatible<props>()) {\n                    need_copy = true;\n                } else {\n                    copy_or_ref = std::move(aref);\n                }\n            } else {\n                need_copy = true;\n            }\n        }\n\n        if (need_copy) {\n            // We need to copy: If we need a mutable reference, or we're not supposed to convert\n            // (either because we're in the no-convert overload pass, or because we're explicitly\n            // instructed not to copy (via `py::arg().noconvert()`) we have to fail loading.\n            if (!convert || need_writeable) {\n                return false;\n            }\n\n            Array copy = Array::ensure(src);\n            if (!copy) {\n                return false;\n            }\n            fits = props::conformable(copy);\n            if (!fits || !fits.template stride_compatible<props>()) {\n                return false;\n            }\n            copy_or_ref = std::move(copy);\n            loader_life_support::add_patient(copy_or_ref);\n        }\n\n        ref.reset();\n        map.reset(new MapType(data(copy_or_ref),\n                              fits.rows,\n                              fits.cols,\n                              make_stride(fits.stride.outer(), fits.stride.inner())));\n        ref.reset(new Type(*map));\n\n        return true;\n    }\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator Type *() { return ref.get(); }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator Type &() { return *ref; }\n    template <typename _T>\n    using cast_op_type = pybind11::detail::cast_op_type<_T>;\n\nprivate:\n    template <typename T = Type, enable_if_t<is_eigen_mutable_map<T>::value, int> = 0>\n    Scalar *data(Array &a) {\n        return a.mutable_data();\n    }\n\n    template <typename T = Type, enable_if_t<!is_eigen_mutable_map<T>::value, int> = 0>\n    const Scalar *data(Array &a) {\n        return a.data();\n    }\n\n    // Attempt to figure out a constructor of `Stride` that will work.\n    // If both strides are fixed, use a default constructor:\n    template <typename S>\n    using stride_ctor_default = bool_constant<S::InnerStrideAtCompileTime != Eigen::Dynamic\n                                              && S::OuterStrideAtCompileTime != Eigen::Dynamic\n                                              && std::is_default_constructible<S>::value>;\n    // Otherwise, if there is a two-index constructor, assume it is (outer,inner) like\n    // Eigen::Stride, and use it:\n    template <typename S>\n    using stride_ctor_dual\n        = bool_constant<!stride_ctor_default<S>::value\n                        && std::is_constructible<S, EigenIndex, EigenIndex>::value>;\n    // Otherwise, if there is a one-index constructor, and just one of the strides is dynamic, use\n    // it (passing whichever stride is dynamic).\n    template <typename S>\n    using stride_ctor_outer\n        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value\n                        && S::OuterStrideAtCompileTime == Eigen::Dynamic\n                        && S::InnerStrideAtCompileTime != Eigen::Dynamic\n                        && std::is_constructible<S, EigenIndex>::value>;\n    template <typename S>\n    using stride_ctor_inner\n        = bool_constant<!any_of<stride_ctor_default<S>, stride_ctor_dual<S>>::value\n                        && S::InnerStrideAtCompileTime == Eigen::Dynamic\n                        && S::OuterStrideAtCompileTime != Eigen::Dynamic\n                        && std::is_constructible<S, EigenIndex>::value>;\n\n    template <typename S = StrideType, enable_if_t<stride_ctor_default<S>::value, int> = 0>\n    static S make_stride(EigenIndex, EigenIndex) {\n        return S();\n    }\n    template <typename S = StrideType, enable_if_t<stride_ctor_dual<S>::value, int> = 0>\n    static S make_stride(EigenIndex outer, EigenIndex inner) {\n        return S(outer, inner);\n    }\n    template <typename S = StrideType, enable_if_t<stride_ctor_outer<S>::value, int> = 0>\n    static S make_stride(EigenIndex outer, EigenIndex) {\n        return S(outer);\n    }\n    template <typename S = StrideType, enable_if_t<stride_ctor_inner<S>::value, int> = 0>\n    static S make_stride(EigenIndex, EigenIndex inner) {\n        return S(inner);\n    }\n};\n\n// type_caster for special matrix types (e.g. DiagonalMatrix), which are EigenBase, but not\n// EigenDense (i.e. they don't have a data(), at least not with the usual matrix layout).\n// load() is not supported, but we can cast them into the python domain by first copying to a\n// regular Eigen::Matrix, then casting that.\ntemplate <typename Type>\nstruct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {\n    static_assert(!std::is_pointer<typename Type::Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n\nprotected:\n    using Matrix\n        = Eigen::Matrix<typename Type::Scalar, Type::RowsAtCompileTime, Type::ColsAtCompileTime>;\n    using props = EigenProps<Matrix>;\n\npublic:\n    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {\n        handle h = eigen_encapsulate<props>(new Matrix(src));\n        return h;\n    }\n    static handle cast(const Type *src, return_value_policy policy, handle parent) {\n        return cast(*src, policy, parent);\n    }\n\n    static constexpr auto name = props::descriptor;\n\n    // Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return\n    // types but not bound arguments).  We still provide them (with an explicitly delete) so that\n    // you end up here if you try anyway.\n    bool load(handle, bool) = delete;\n    operator Type() = delete;\n    template <typename>\n    using cast_op_type = Type;\n};\n\ntemplate <typename Type>\nstruct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {\n    using Scalar = typename Type::Scalar;\n    static_assert(!std::is_pointer<Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n    using StorageIndex = remove_reference_t<decltype(*std::declval<Type>().outerIndexPtr())>;\n    using Index = typename Type::Index;\n    static constexpr bool rowMajor = Type::IsRowMajor;\n\n    bool load(handle src, bool) {\n        if (!src) {\n            return false;\n        }\n\n        auto obj = reinterpret_borrow<object>(src);\n        object sparse_module = module_::import(\"scipy.sparse\");\n        object matrix_type = sparse_module.attr(rowMajor ? \"csr_matrix\" : \"csc_matrix\");\n\n        if (!type::handle_of(obj).is(matrix_type)) {\n            try {\n                obj = matrix_type(obj);\n            } catch (const error_already_set &) {\n                return false;\n            }\n        }\n\n        auto values = array_t<Scalar>((object) obj.attr(\"data\"));\n        auto innerIndices = array_t<StorageIndex>((object) obj.attr(\"indices\"));\n        auto outerIndices = array_t<StorageIndex>((object) obj.attr(\"indptr\"));\n        auto shape = pybind11::tuple((pybind11::object) obj.attr(\"shape\"));\n        auto nnz = obj.attr(\"nnz\").cast<Index>();\n\n        if (!values || !innerIndices || !outerIndices) {\n            return false;\n        }\n\n        value = EigenMapSparseMatrix<Scalar,\n                                     Type::Flags &(Eigen::RowMajor | Eigen::ColMajor),\n                                     StorageIndex>(shape[0].cast<Index>(),\n                                                   shape[1].cast<Index>(),\n                                                   std::move(nnz),\n                                                   outerIndices.mutable_data(),\n                                                   innerIndices.mutable_data(),\n                                                   values.mutable_data());\n\n        return true;\n    }\n\n    static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {\n        const_cast<Type &>(src).makeCompressed();\n\n        object matrix_type\n            = module_::import(\"scipy.sparse\").attr(rowMajor ? \"csr_matrix\" : \"csc_matrix\");\n\n        array data(src.nonZeros(), src.valuePtr());\n        array outerIndices((rowMajor ? src.rows() : src.cols()) + 1, src.outerIndexPtr());\n        array innerIndices(src.nonZeros(), src.innerIndexPtr());\n\n        return matrix_type(pybind11::make_tuple(\n                               std::move(data), std::move(innerIndices), std::move(outerIndices)),\n                           pybind11::make_tuple(src.rows(), src.cols()))\n            .release();\n    }\n\n    PYBIND11_TYPE_CASTER(Type,\n                         const_name<(Type::IsRowMajor) != 0>(\"scipy.sparse.csr_matrix[\",\n                                                             \"scipy.sparse.csc_matrix[\")\n                             + npy_format_descriptor<Scalar>::name + const_name(\"]\"));\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/eigen/tensor.h",
    "content": "/*\n    pybind11/eigen/tensor.h: Transparent conversion for Eigen tensors\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"../numpy.h\"\n#include \"common.h\"\n\n#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)\nstatic_assert(__GNUC__ > 5, \"Eigen Tensor support in pybind11 requires GCC > 5.0\");\n#endif\n\n// Disable warnings for Eigen\nPYBIND11_WARNING_PUSH\nPYBIND11_WARNING_DISABLE_MSVC(4554)\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n#if defined(__MINGW32__)\nPYBIND11_WARNING_DISABLE_GCC(\"-Wmaybe-uninitialized\")\n#endif\n\n#include <unsupported/Eigen/CXX11/Tensor>\n\nPYBIND11_WARNING_POP\n\nstatic_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),\n              \"Eigen Tensor support in pybind11 requires Eigen >= 3.3.0\");\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline bool is_tensor_aligned(const void *data) {\n    return (reinterpret_cast<std::size_t>(data) % EIGEN_DEFAULT_ALIGN_BYTES) == 0;\n}\n\ntemplate <typename T>\nconstexpr int compute_array_flag_from_tensor() {\n    static_assert((static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor))\n                      || (static_cast<int>(T::Layout) == static_cast<int>(Eigen::ColMajor)),\n                  \"Layout must be row or column major\");\n    return (static_cast<int>(T::Layout) == static_cast<int>(Eigen::RowMajor)) ? array::c_style\n                                                                              : array::f_style;\n}\n\ntemplate <typename T>\nstruct eigen_tensor_helper {};\n\ntemplate <typename Scalar_, int NumIndices_, int Options_, typename IndexType>\nstruct eigen_tensor_helper<Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>> {\n    using Type = Eigen::Tensor<Scalar_, NumIndices_, Options_, IndexType>;\n    using ValidType = void;\n\n    static Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape(const Type &f) {\n        return f.dimensions();\n    }\n\n    static constexpr bool\n    is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> & /*shape*/) {\n        return true;\n    }\n\n    template <typename T>\n    struct helper {};\n\n    template <size_t... Is>\n    struct helper<index_sequence<Is...>> {\n        static constexpr auto value = ::pybind11::detail::concat(const_name(((void) Is, \"?\"))...);\n    };\n\n    static constexpr auto dimensions_descriptor\n        = helper<decltype(make_index_sequence<Type::NumIndices>())>::value;\n\n    template <typename... Args>\n    static Type *alloc(Args &&...args) {\n        return new Type(std::forward<Args>(args)...);\n    }\n\n    static void free(Type *tensor) { delete tensor; }\n};\n\ntemplate <typename Scalar_, typename std::ptrdiff_t... Indices, int Options_, typename IndexType>\nstruct eigen_tensor_helper<\n    Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>> {\n    using Type = Eigen::TensorFixedSize<Scalar_, Eigen::Sizes<Indices...>, Options_, IndexType>;\n    using ValidType = void;\n\n    static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices>\n    get_shape(const Type & /*f*/) {\n        return get_shape();\n    }\n\n    static constexpr Eigen::DSizes<typename Type::Index, Type::NumIndices> get_shape() {\n        return Eigen::DSizes<typename Type::Index, Type::NumIndices>(Indices...);\n    }\n\n    static bool\n    is_correct_shape(const Eigen::DSizes<typename Type::Index, Type::NumIndices> &shape) {\n        return get_shape() == shape;\n    }\n\n    static constexpr auto dimensions_descriptor\n        = ::pybind11::detail::concat(const_name<Indices>()...);\n\n    template <typename... Args>\n    static Type *alloc(Args &&...args) {\n        Eigen::aligned_allocator<Type> allocator;\n        return ::new (allocator.allocate(1)) Type(std::forward<Args>(args)...);\n    }\n\n    static void free(Type *tensor) {\n        Eigen::aligned_allocator<Type> allocator;\n        tensor->~Type();\n        allocator.deallocate(tensor, 1);\n    }\n};\n\ntemplate <typename Type, bool ShowDetails, bool NeedsWriteable = false>\nstruct get_tensor_descriptor {\n    static constexpr auto details\n        = const_name<NeedsWriteable>(\", flags.writeable\", \"\")\n          + const_name<static_cast<int>(Type::Layout) == static_cast<int>(Eigen::RowMajor)>(\n              \", flags.c_contiguous\", \", flags.f_contiguous\");\n    static constexpr auto value\n        = const_name(\"numpy.ndarray[\") + npy_format_descriptor<typename Type::Scalar>::name\n          + const_name(\"[\") + eigen_tensor_helper<remove_cv_t<Type>>::dimensions_descriptor\n          + const_name(\"]\") + const_name<ShowDetails>(details, const_name(\"\")) + const_name(\"]\");\n};\n\n// When EIGEN_AVOID_STL_ARRAY is defined, Eigen::DSizes<T, 0> does not have the begin() member\n// function. Falling back to a simple loop works around this issue.\n//\n// We need to disable the type-limits warning for the inner loop when size = 0.\n\nPYBIND11_WARNING_PUSH\nPYBIND11_WARNING_DISABLE_GCC(\"-Wtype-limits\")\n\ntemplate <typename T, int size>\nstd::vector<T> convert_dsizes_to_vector(const Eigen::DSizes<T, size> &arr) {\n    std::vector<T> result(size);\n\n    for (size_t i = 0; i < size; i++) {\n        result[i] = arr[i];\n    }\n\n    return result;\n}\n\ntemplate <typename T, int size>\nEigen::DSizes<T, size> get_shape_for_array(const array &arr) {\n    Eigen::DSizes<T, size> result;\n    const T *shape = arr.shape();\n    for (size_t i = 0; i < size; i++) {\n        result[i] = shape[i];\n    }\n\n    return result;\n}\n\nPYBIND11_WARNING_POP\n\ntemplate <typename Type>\nstruct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {\n    static_assert(!std::is_pointer<typename Type::Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n    using Helper = eigen_tensor_helper<Type>;\n    static constexpr auto temp_name = get_tensor_descriptor<Type, false>::value;\n    PYBIND11_TYPE_CASTER(Type, temp_name);\n\n    bool load(handle src, bool convert) {\n        if (!convert) {\n            if (!isinstance<array>(src)) {\n                return false;\n            }\n            array temp = array::ensure(src);\n            if (!temp) {\n                return false;\n            }\n\n            if (!temp.dtype().is(dtype::of<typename Type::Scalar>())) {\n                return false;\n            }\n        }\n\n        array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()> arr(\n            reinterpret_borrow<object>(src));\n\n        if (arr.ndim() != Type::NumIndices) {\n            return false;\n        }\n        auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);\n\n        if (!Helper::is_correct_shape(shape)) {\n            return false;\n        }\n\n#if EIGEN_VERSION_AT_LEAST(3, 4, 0)\n        auto data_pointer = arr.data();\n#else\n        // Handle Eigen bug\n        auto data_pointer = const_cast<typename Type::Scalar *>(arr.data());\n#endif\n\n        if (is_tensor_aligned(arr.data())) {\n            value = Eigen::TensorMap<const Type, Eigen::Aligned>(data_pointer, shape);\n        } else {\n            value = Eigen::TensorMap<const Type>(data_pointer, shape);\n        }\n\n        return true;\n    }\n\n    static handle cast(Type &&src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::reference\n            || policy == return_value_policy::reference_internal) {\n            pybind11_fail(\"Cannot use a reference return value policy for an rvalue\");\n        }\n        return cast_impl(&src, return_value_policy::move, parent);\n    }\n\n    static handle cast(const Type &&src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::reference\n            || policy == return_value_policy::reference_internal) {\n            pybind11_fail(\"Cannot use a reference return value policy for an rvalue\");\n        }\n        return cast_impl(&src, return_value_policy::move, parent);\n    }\n\n    static handle cast(Type &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast_impl(&src, policy, parent);\n    }\n\n    static handle cast(const Type &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast(&src, policy, parent);\n    }\n\n    static handle cast(Type *src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic) {\n            policy = return_value_policy::take_ownership;\n        } else if (policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::reference;\n        }\n        return cast_impl(src, policy, parent);\n    }\n\n    static handle cast(const Type *src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic) {\n            policy = return_value_policy::take_ownership;\n        } else if (policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::reference;\n        }\n        return cast_impl(src, policy, parent);\n    }\n\n    template <typename C>\n    static handle cast_impl(C *src, return_value_policy policy, handle parent) {\n        object parent_object;\n        bool writeable = false;\n        switch (policy) {\n            case return_value_policy::move:\n                if (std::is_const<C>::value) {\n                    pybind11_fail(\"Cannot move from a constant reference\");\n                }\n\n                src = Helper::alloc(std::move(*src));\n\n                parent_object\n                    = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });\n                writeable = true;\n                break;\n\n            case return_value_policy::take_ownership:\n                if (std::is_const<C>::value) {\n                    // This cast is ugly, and might be UB in some cases, but we don't have an\n                    // alternative here as we must free that memory\n                    Helper::free(const_cast<Type *>(src));\n                    pybind11_fail(\"Cannot take ownership of a const reference\");\n                }\n\n                parent_object\n                    = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });\n                writeable = true;\n                break;\n\n            case return_value_policy::copy:\n                writeable = true;\n                break;\n\n            case return_value_policy::reference:\n                parent_object = none();\n                writeable = !std::is_const<C>::value;\n                break;\n\n            case return_value_policy::reference_internal:\n                // Default should do the right thing\n                if (!parent) {\n                    pybind11_fail(\"Cannot use reference internal when there is no parent\");\n                }\n                parent_object = reinterpret_borrow<object>(parent);\n                writeable = !std::is_const<C>::value;\n                break;\n\n            default:\n                pybind11_fail(\"pybind11 bug in eigen.h, please file a bug report\");\n        }\n\n        auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(\n            convert_dsizes_to_vector(Helper::get_shape(*src)), src->data(), parent_object);\n\n        if (!writeable) {\n            array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;\n        }\n\n        return result.release();\n    }\n};\n\ntemplate <typename StoragePointerType,\n          bool needs_writeable,\n          enable_if_t<!needs_writeable, bool> = true>\nStoragePointerType get_array_data_for_type(array &arr) {\n#if EIGEN_VERSION_AT_LEAST(3, 4, 0)\n    return reinterpret_cast<StoragePointerType>(arr.data());\n#else\n    // Handle Eigen bug\n    return reinterpret_cast<StoragePointerType>(const_cast<void *>(arr.data()));\n#endif\n}\n\ntemplate <typename StoragePointerType,\n          bool needs_writeable,\n          enable_if_t<needs_writeable, bool> = true>\nStoragePointerType get_array_data_for_type(array &arr) {\n    return reinterpret_cast<StoragePointerType>(arr.mutable_data());\n}\n\ntemplate <typename T, typename = void>\nstruct get_storage_pointer_type;\n\ntemplate <typename MapType>\nstruct get_storage_pointer_type<MapType, void_t<typename MapType::StoragePointerType>> {\n    using SPT = typename MapType::StoragePointerType;\n};\n\ntemplate <typename MapType>\nstruct get_storage_pointer_type<MapType, void_t<typename MapType::PointerArgType>> {\n    using SPT = typename MapType::PointerArgType;\n};\n\ntemplate <typename Type, int Options>\nstruct type_caster<Eigen::TensorMap<Type, Options>,\n                   typename eigen_tensor_helper<remove_cv_t<Type>>::ValidType> {\n    static_assert(!std::is_pointer<typename Type::Scalar>::value,\n                  PYBIND11_EIGEN_MESSAGE_POINTER_TYPES_ARE_NOT_SUPPORTED);\n    using MapType = Eigen::TensorMap<Type, Options>;\n    using Helper = eigen_tensor_helper<remove_cv_t<Type>>;\n\n    bool load(handle src, bool /*convert*/) {\n        // Note that we have a lot more checks here as we want to make sure to avoid copies\n        if (!isinstance<array>(src)) {\n            return false;\n        }\n        auto arr = reinterpret_borrow<array>(src);\n        if ((arr.flags() & compute_array_flag_from_tensor<Type>()) == 0) {\n            return false;\n        }\n\n        if (!arr.dtype().is(dtype::of<typename Type::Scalar>())) {\n            return false;\n        }\n\n        if (arr.ndim() != Type::NumIndices) {\n            return false;\n        }\n\n        constexpr bool is_aligned = (Options & Eigen::Aligned) != 0;\n\n        if (is_aligned && !is_tensor_aligned(arr.data())) {\n            return false;\n        }\n\n        auto shape = get_shape_for_array<typename Type::Index, Type::NumIndices>(arr);\n\n        if (!Helper::is_correct_shape(shape)) {\n            return false;\n        }\n\n        if (needs_writeable && !arr.writeable()) {\n            return false;\n        }\n\n        auto result = get_array_data_for_type<typename get_storage_pointer_type<MapType>::SPT,\n                                              needs_writeable>(arr);\n\n        value.reset(new MapType(std::move(result), std::move(shape)));\n\n        return true;\n    }\n\n    static handle cast(MapType &&src, return_value_policy policy, handle parent) {\n        return cast_impl(&src, policy, parent);\n    }\n\n    static handle cast(const MapType &&src, return_value_policy policy, handle parent) {\n        return cast_impl(&src, policy, parent);\n    }\n\n    static handle cast(MapType &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast_impl(&src, policy, parent);\n    }\n\n    static handle cast(const MapType &src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic\n            || policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::copy;\n        }\n        return cast(&src, policy, parent);\n    }\n\n    static handle cast(MapType *src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic) {\n            policy = return_value_policy::take_ownership;\n        } else if (policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::reference;\n        }\n        return cast_impl(src, policy, parent);\n    }\n\n    static handle cast(const MapType *src, return_value_policy policy, handle parent) {\n        if (policy == return_value_policy::automatic) {\n            policy = return_value_policy::take_ownership;\n        } else if (policy == return_value_policy::automatic_reference) {\n            policy = return_value_policy::reference;\n        }\n        return cast_impl(src, policy, parent);\n    }\n\n    template <typename C>\n    static handle cast_impl(C *src, return_value_policy policy, handle parent) {\n        object parent_object;\n        constexpr bool writeable = !std::is_const<C>::value;\n        switch (policy) {\n            case return_value_policy::reference:\n                parent_object = none();\n                break;\n\n            case return_value_policy::reference_internal:\n                // Default should do the right thing\n                if (!parent) {\n                    pybind11_fail(\"Cannot use reference internal when there is no parent\");\n                }\n                parent_object = reinterpret_borrow<object>(parent);\n                break;\n\n            case return_value_policy::take_ownership:\n                delete src;\n                // fallthrough\n            default:\n                // move, take_ownership don't make any sense for a ref/map:\n                pybind11_fail(\"Invalid return_value_policy for Eigen Map type, must be either \"\n                              \"reference or reference_internal\");\n        }\n\n        auto result = array_t<typename Type::Scalar, compute_array_flag_from_tensor<Type>()>(\n            convert_dsizes_to_vector(Helper::get_shape(*src)),\n            src->data(),\n            std::move(parent_object));\n\n        if (!writeable) {\n            array_proxy(result.ptr())->flags &= ~detail::npy_api::NPY_ARRAY_WRITEABLE_;\n        }\n\n        return result.release();\n    }\n\n#if EIGEN_VERSION_AT_LEAST(3, 4, 0)\n\n    static constexpr bool needs_writeable = !std::is_const<typename std::remove_pointer<\n        typename get_storage_pointer_type<MapType>::SPT>::type>::value;\n#else\n    // Handle Eigen bug\n    static constexpr bool needs_writeable = !std::is_const<Type>::value;\n#endif\n\nprotected:\n    // TODO: Move to std::optional once std::optional has more support\n    std::unique_ptr<MapType> value;\n\npublic:\n    static constexpr auto name = get_tensor_descriptor<Type, true, needs_writeable>::value;\n    explicit operator MapType *() { return value.get(); }\n    explicit operator MapType &() { return *value; }\n    explicit operator MapType &&() && { return std::move(*value); }\n\n    template <typename T_>\n    using cast_op_type = ::pybind11::detail::movable_cast_op_type<T_>;\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/eigen.h",
    "content": "/*\n    pybind11/eigen.h: Transparent conversion for dense and sparse Eigen matrices\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"eigen/matrix.h\"\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/embed.h",
    "content": "/*\n    pybind11/embed.h: Support for embedding the interpreter\n\n    Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n#include \"eval.h\"\n\n#include <memory>\n#include <vector>\n\n#if defined(PYPY_VERSION)\n#    error Embedding the interpreter is not supported with PyPy\n#endif\n\n#define PYBIND11_EMBEDDED_MODULE_IMPL(name)                                                       \\\n    extern \"C\" PyObject *pybind11_init_impl_##name();                                             \\\n    extern \"C\" PyObject *pybind11_init_impl_##name() { return pybind11_init_wrapper_##name(); }\n\n/** \\rst\n    Add a new module to the table of builtins for the interpreter. Must be\n    defined in global scope. The first macro parameter is the name of the\n    module (without quotes). The second parameter is the variable which will\n    be used as the interface to add functions and classes to the module.\n\n    .. code-block:: cpp\n\n        PYBIND11_EMBEDDED_MODULE(example, m) {\n            // ... initialize functions and classes here\n            m.def(\"foo\", []() {\n                return \"Hello, World!\";\n            });\n        }\n \\endrst */\n#define PYBIND11_EMBEDDED_MODULE(name, variable)                                                  \\\n    static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name);           \\\n    static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &);                     \\\n    static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() {                            \\\n        auto m = ::pybind11::module_::create_extension_module(                                    \\\n            PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name));      \\\n        try {                                                                                     \\\n            PYBIND11_CONCAT(pybind11_init_, name)(m);                                             \\\n            return m.ptr();                                                                       \\\n        }                                                                                         \\\n        PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \\\n    }                                                                                             \\\n    PYBIND11_EMBEDDED_MODULE_IMPL(name)                                                           \\\n    ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name)(                  \\\n        PYBIND11_TOSTRING(name), PYBIND11_CONCAT(pybind11_init_impl_, name));                     \\\n    void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_                                \\\n                                               & variable) // NOLINT(bugprone-macro-parentheses)\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// Python 2.7/3.x compatible version of `PyImport_AppendInittab` and error checks.\nstruct embedded_module {\n    using init_t = PyObject *(*) ();\n    embedded_module(const char *name, init_t init) {\n        if (Py_IsInitialized() != 0) {\n            pybind11_fail(\"Can't add new modules after the interpreter has been initialized\");\n        }\n\n        auto result = PyImport_AppendInittab(name, init);\n        if (result == -1) {\n            pybind11_fail(\"Insufficient memory to add a new module\");\n        }\n    }\n};\n\nstruct wide_char_arg_deleter {\n    void operator()(wchar_t *ptr) const {\n        // API docs: https://docs.python.org/3/c-api/sys.html#c.Py_DecodeLocale\n        PyMem_RawFree(ptr);\n    }\n};\n\ninline wchar_t *widen_chars(const char *safe_arg) {\n    wchar_t *widened_arg = Py_DecodeLocale(safe_arg, nullptr);\n    return widened_arg;\n}\n\ninline void precheck_interpreter() {\n    if (Py_IsInitialized() != 0) {\n        pybind11_fail(\"The interpreter is already running\");\n    }\n}\n\n#if !defined(PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX)\n#    define PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX (0x03080000)\n#endif\n\n#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX\ninline void initialize_interpreter_pre_pyconfig(bool init_signal_handlers,\n                                                int argc,\n                                                const char *const *argv,\n                                                bool add_program_dir_to_path) {\n    detail::precheck_interpreter();\n    Py_InitializeEx(init_signal_handlers ? 1 : 0);\n#    if defined(WITH_THREAD) && PY_VERSION_HEX < 0x03070000\n    PyEval_InitThreads();\n#    endif\n\n    // Before it was special-cased in python 3.8, passing an empty or null argv\n    // caused a segfault, so we have to reimplement the special case ourselves.\n    bool special_case = (argv == nullptr || argc <= 0);\n\n    const char *const empty_argv[]{\"\\0\"};\n    const char *const *safe_argv = special_case ? empty_argv : argv;\n    if (special_case) {\n        argc = 1;\n    }\n\n    auto argv_size = static_cast<size_t>(argc);\n    // SetArgv* on python 3 takes wchar_t, so we have to convert.\n    std::unique_ptr<wchar_t *[]> widened_argv(new wchar_t *[argv_size]);\n    std::vector<std::unique_ptr<wchar_t[], detail::wide_char_arg_deleter>> widened_argv_entries;\n    widened_argv_entries.reserve(argv_size);\n    for (size_t ii = 0; ii < argv_size; ++ii) {\n        widened_argv_entries.emplace_back(detail::widen_chars(safe_argv[ii]));\n        if (!widened_argv_entries.back()) {\n            // A null here indicates a character-encoding failure or the python\n            // interpreter out of memory. Give up.\n            return;\n        }\n        widened_argv[ii] = widened_argv_entries.back().get();\n    }\n\n    auto *pysys_argv = widened_argv.get();\n\n    PySys_SetArgvEx(argc, pysys_argv, static_cast<int>(add_program_dir_to_path));\n}\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\n\n#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX\ninline void initialize_interpreter(PyConfig *config,\n                                   int argc = 0,\n                                   const char *const *argv = nullptr,\n                                   bool add_program_dir_to_path = true) {\n    detail::precheck_interpreter();\n    PyStatus status = PyConfig_SetBytesArgv(config, argc, const_cast<char *const *>(argv));\n    if (PyStatus_Exception(status) != 0) {\n        // A failure here indicates a character-encoding failure or the python\n        // interpreter out of memory. Give up.\n        PyConfig_Clear(config);\n        throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg\n                                                               : \"Failed to prepare CPython\");\n    }\n    status = Py_InitializeFromConfig(config);\n    if (PyStatus_Exception(status) != 0) {\n        PyConfig_Clear(config);\n        throw std::runtime_error(PyStatus_IsError(status) != 0 ? status.err_msg\n                                                               : \"Failed to init CPython\");\n    }\n    if (add_program_dir_to_path) {\n        PyRun_SimpleString(\"import sys, os.path; \"\n                           \"sys.path.insert(0, \"\n                           \"os.path.abspath(os.path.dirname(sys.argv[0])) \"\n                           \"if sys.argv and os.path.exists(sys.argv[0]) else '')\");\n    }\n    PyConfig_Clear(config);\n}\n#endif\n\n/** \\rst\n    Initialize the Python interpreter. No other pybind11 or CPython API functions can be\n    called before this is done; with the exception of `PYBIND11_EMBEDDED_MODULE`. The\n    optional `init_signal_handlers` parameter can be used to skip the registration of\n    signal handlers (see the `Python documentation`_ for details). Calling this function\n    again after the interpreter has already been initialized is a fatal error.\n\n    If initializing the Python interpreter fails, then the program is terminated.  (This\n    is controlled by the CPython runtime and is an exception to pybind11's normal behavior\n    of throwing exceptions on errors.)\n\n    The remaining optional parameters, `argc`, `argv`, and `add_program_dir_to_path` are\n    used to populate ``sys.argv`` and ``sys.path``.\n    See the |PySys_SetArgvEx documentation|_ for details.\n\n    .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx\n    .. |PySys_SetArgvEx documentation| replace:: ``PySys_SetArgvEx`` documentation\n    .. _PySys_SetArgvEx documentation: https://docs.python.org/3/c-api/init.html#c.PySys_SetArgvEx\n \\endrst */\ninline void initialize_interpreter(bool init_signal_handlers = true,\n                                   int argc = 0,\n                                   const char *const *argv = nullptr,\n                                   bool add_program_dir_to_path = true) {\n#if PY_VERSION_HEX < PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX\n    detail::initialize_interpreter_pre_pyconfig(\n        init_signal_handlers, argc, argv, add_program_dir_to_path);\n#else\n    PyConfig config;\n    PyConfig_InitPythonConfig(&config);\n    // See PR #4473 for background\n    config.parse_argv = 0;\n\n    config.install_signal_handlers = init_signal_handlers ? 1 : 0;\n    initialize_interpreter(&config, argc, argv, add_program_dir_to_path);\n#endif\n}\n\n/** \\rst\n    Shut down the Python interpreter. No pybind11 or CPython API functions can be called\n    after this. In addition, pybind11 objects must not outlive the interpreter:\n\n    .. code-block:: cpp\n\n        { // BAD\n            py::initialize_interpreter();\n            auto hello = py::str(\"Hello, World!\");\n            py::finalize_interpreter();\n        } // <-- BOOM, hello's destructor is called after interpreter shutdown\n\n        { // GOOD\n            py::initialize_interpreter();\n            { // scoped\n                auto hello = py::str(\"Hello, World!\");\n            } // <-- OK, hello is cleaned up properly\n            py::finalize_interpreter();\n        }\n\n        { // BETTER\n            py::scoped_interpreter guard{};\n            auto hello = py::str(\"Hello, World!\");\n        }\n\n    .. warning::\n\n        The interpreter can be restarted by calling `initialize_interpreter` again.\n        Modules created using pybind11 can be safely re-initialized. However, Python\n        itself cannot completely unload binary extension modules and there are several\n        caveats with regard to interpreter restarting. All the details can be found\n        in the CPython documentation. In short, not all interpreter memory may be\n        freed, either due to reference cycles or user-created global data.\n\n \\endrst */\ninline void finalize_interpreter() {\n    // Get the internals pointer (without creating it if it doesn't exist).  It's possible for the\n    // internals to be created during Py_Finalize() (e.g. if a py::capsule calls `get_internals()`\n    // during destruction), so we get the pointer-pointer here and check it after Py_Finalize().\n    detail::internals **internals_ptr_ptr = detail::get_internals_pp();\n    // It could also be stashed in state_dict, so look there too:\n    if (object internals_obj\n        = get_internals_obj_from_state_dict(detail::get_python_state_dict())) {\n        internals_ptr_ptr = detail::get_internals_pp_from_capsule(internals_obj);\n    }\n    // Local internals contains data managed by the current interpreter, so we must clear them to\n    // avoid undefined behaviors when initializing another interpreter\n    detail::get_local_internals().registered_types_cpp.clear();\n    detail::get_local_internals().registered_exception_translators.clear();\n\n    Py_Finalize();\n\n    if (internals_ptr_ptr) {\n        delete *internals_ptr_ptr;\n        *internals_ptr_ptr = nullptr;\n    }\n}\n\n/** \\rst\n    Scope guard version of `initialize_interpreter` and `finalize_interpreter`.\n    This a move-only guard and only a single instance can exist.\n\n    See `initialize_interpreter` for a discussion of its constructor arguments.\n\n    .. code-block:: cpp\n\n        #include <pybind11/embed.h>\n\n        int main() {\n            py::scoped_interpreter guard{};\n            py::print(Hello, World!);\n        } // <-- interpreter shutdown\n \\endrst */\nclass scoped_interpreter {\npublic:\n    explicit scoped_interpreter(bool init_signal_handlers = true,\n                                int argc = 0,\n                                const char *const *argv = nullptr,\n                                bool add_program_dir_to_path = true) {\n        initialize_interpreter(init_signal_handlers, argc, argv, add_program_dir_to_path);\n    }\n\n#if PY_VERSION_HEX >= PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX\n    explicit scoped_interpreter(PyConfig *config,\n                                int argc = 0,\n                                const char *const *argv = nullptr,\n                                bool add_program_dir_to_path = true) {\n        initialize_interpreter(config, argc, argv, add_program_dir_to_path);\n    }\n#endif\n\n    scoped_interpreter(const scoped_interpreter &) = delete;\n    scoped_interpreter(scoped_interpreter &&other) noexcept { other.is_valid = false; }\n    scoped_interpreter &operator=(const scoped_interpreter &) = delete;\n    scoped_interpreter &operator=(scoped_interpreter &&) = delete;\n\n    ~scoped_interpreter() {\n        if (is_valid) {\n            finalize_interpreter();\n        }\n    }\n\nprivate:\n    bool is_valid = true;\n};\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/eval.h",
    "content": "/*\n    pybind11/eval.h: Support for evaluating Python expressions and statements\n    from strings and files\n\n    Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and\n                       Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\n#include <utility>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline void ensure_builtins_in_globals(object &global) {\n#if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000\n    // Running exec and eval adds `builtins` module under `__builtins__` key to\n    // globals if not yet present.  Python 3.8 made PyRun_String behave\n    // similarly. Let's also do that for older versions, for consistency. This\n    // was missing from PyPy3.8 7.3.7.\n    if (!global.contains(\"__builtins__\"))\n        global[\"__builtins__\"] = module_::import(PYBIND11_BUILTINS_MODULE);\n#else\n    (void) global;\n#endif\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\nenum eval_mode {\n    /// Evaluate a string containing an isolated expression\n    eval_expr,\n\n    /// Evaluate a string containing a single statement. Returns \\c none\n    eval_single_statement,\n\n    /// Evaluate a string containing a sequence of statement. Returns \\c none\n    eval_statements\n};\n\ntemplate <eval_mode mode = eval_expr>\nobject eval(const str &expr, object global = globals(), object local = object()) {\n    if (!local) {\n        local = global;\n    }\n\n    detail::ensure_builtins_in_globals(global);\n\n    /* PyRun_String does not accept a PyObject / encoding specifier,\n       this seems to be the only alternative */\n    std::string buffer = \"# -*- coding: utf-8 -*-\\n\" + (std::string) expr;\n\n    int start = 0;\n    switch (mode) {\n        case eval_expr:\n            start = Py_eval_input;\n            break;\n        case eval_single_statement:\n            start = Py_single_input;\n            break;\n        case eval_statements:\n            start = Py_file_input;\n            break;\n        default:\n            pybind11_fail(\"invalid evaluation mode\");\n    }\n\n    PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());\n    if (!result) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<object>(result);\n}\n\ntemplate <eval_mode mode = eval_expr, size_t N>\nobject eval(const char (&s)[N], object global = globals(), object local = object()) {\n    /* Support raw string literals by removing common leading whitespace */\n    auto expr = (s[0] == '\\n') ? str(module_::import(\"textwrap\").attr(\"dedent\")(s)) : str(s);\n    return eval<mode>(expr, std::move(global), std::move(local));\n}\n\ninline void exec(const str &expr, object global = globals(), object local = object()) {\n    eval<eval_statements>(expr, std::move(global), std::move(local));\n}\n\ntemplate <size_t N>\nvoid exec(const char (&s)[N], object global = globals(), object local = object()) {\n    eval<eval_statements>(s, std::move(global), std::move(local));\n}\n\n#if defined(PYPY_VERSION)\ntemplate <eval_mode mode = eval_statements>\nobject eval_file(str, object, object) {\n    pybind11_fail(\"eval_file not supported in PyPy3. Use eval\");\n}\ntemplate <eval_mode mode = eval_statements>\nobject eval_file(str, object) {\n    pybind11_fail(\"eval_file not supported in PyPy3. Use eval\");\n}\ntemplate <eval_mode mode = eval_statements>\nobject eval_file(str) {\n    pybind11_fail(\"eval_file not supported in PyPy3. Use eval\");\n}\n#else\ntemplate <eval_mode mode = eval_statements>\nobject eval_file(str fname, object global = globals(), object local = object()) {\n    if (!local) {\n        local = global;\n    }\n\n    detail::ensure_builtins_in_globals(global);\n\n    int start = 0;\n    switch (mode) {\n        case eval_expr:\n            start = Py_eval_input;\n            break;\n        case eval_single_statement:\n            start = Py_single_input;\n            break;\n        case eval_statements:\n            start = Py_file_input;\n            break;\n        default:\n            pybind11_fail(\"invalid evaluation mode\");\n    }\n\n    int closeFile = 1;\n    std::string fname_str = (std::string) fname;\n    FILE *f = _Py_fopen_obj(fname.ptr(), \"r\");\n    if (!f) {\n        PyErr_Clear();\n        pybind11_fail(\"File \\\"\" + fname_str + \"\\\" could not be opened!\");\n    }\n\n    if (!global.contains(\"__file__\")) {\n        global[\"__file__\"] = std::move(fname);\n    }\n\n    PyObject *result\n        = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(), local.ptr(), closeFile);\n\n    if (!result) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<object>(result);\n}\n#endif\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/functional.h",
    "content": "/*\n    pybind11/functional.h: std::function<> support\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\n#include <functional>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename Return, typename... Args>\nstruct type_caster<std::function<Return(Args...)>> {\n    using type = std::function<Return(Args...)>;\n    using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;\n    using function_type = Return (*)(Args...);\n\npublic:\n    bool load(handle src, bool convert) {\n        if (src.is_none()) {\n            // Defer accepting None to other overloads (if we aren't in convert mode):\n            if (!convert) {\n                return false;\n            }\n            return true;\n        }\n\n        if (!isinstance<function>(src)) {\n            return false;\n        }\n\n        auto func = reinterpret_borrow<function>(src);\n\n        /*\n           When passing a C++ function as an argument to another C++\n           function via Python, every function call would normally involve\n           a full C++ -> Python -> C++ roundtrip, which can be prohibitive.\n           Here, we try to at least detect the case where the function is\n           stateless (i.e. function pointer or lambda function without\n           captured variables), in which case the roundtrip can be avoided.\n         */\n        if (auto cfunc = func.cpp_function()) {\n            auto *cfunc_self = PyCFunction_GET_SELF(cfunc.ptr());\n            if (cfunc_self == nullptr) {\n                PyErr_Clear();\n            } else if (isinstance<capsule>(cfunc_self)) {\n                auto c = reinterpret_borrow<capsule>(cfunc_self);\n\n                function_record *rec = nullptr;\n                // Check that we can safely reinterpret the capsule into a function_record\n                if (detail::is_function_record_capsule(c)) {\n                    rec = c.get_pointer<function_record>();\n                }\n\n                while (rec != nullptr) {\n                    if (rec->is_stateless\n                        && same_type(typeid(function_type),\n                                     *reinterpret_cast<const std::type_info *>(rec->data[1]))) {\n                        struct capture {\n                            function_type f;\n                        };\n                        value = ((capture *) &rec->data)->f;\n                        return true;\n                    }\n                    rec = rec->next;\n                }\n            }\n            // PYPY segfaults here when passing builtin function like sum.\n            // Raising an fail exception here works to prevent the segfault, but only on gcc.\n            // See PR #1413 for full details\n        }\n\n        // ensure GIL is held during functor destruction\n        struct func_handle {\n            function f;\n#if !(defined(_MSC_VER) && _MSC_VER == 1916 && defined(PYBIND11_CPP17))\n            // This triggers a syntax error under very special conditions (very weird indeed).\n            explicit\n#endif\n                func_handle(function &&f_) noexcept\n                : f(std::move(f_)) {\n            }\n            func_handle(const func_handle &f_) { operator=(f_); }\n            func_handle &operator=(const func_handle &f_) {\n                gil_scoped_acquire acq;\n                f = f_.f;\n                return *this;\n            }\n            ~func_handle() {\n                gil_scoped_acquire acq;\n                function kill_f(std::move(f));\n            }\n        };\n\n        // to emulate 'move initialization capture' in C++11\n        struct func_wrapper {\n            func_handle hfunc;\n            explicit func_wrapper(func_handle &&hf) noexcept : hfunc(std::move(hf)) {}\n            Return operator()(Args... args) const {\n                gil_scoped_acquire acq;\n                // casts the returned object as a rvalue to the return type\n                return hfunc.f(std::forward<Args>(args)...).template cast<Return>();\n            }\n        };\n\n        value = func_wrapper(func_handle(std::move(func)));\n        return true;\n    }\n\n    template <typename Func>\n    static handle cast(Func &&f_, return_value_policy policy, handle /* parent */) {\n        if (!f_) {\n            return none().release();\n        }\n\n        auto result = f_.template target<function_type>();\n        if (result) {\n            return cpp_function(*result, policy).release();\n        }\n        return cpp_function(std::forward<Func>(f_), policy).release();\n    }\n\n    PYBIND11_TYPE_CASTER(type,\n                         const_name(\"Callable[[\")\n                             + ::pybind11::detail::concat(make_caster<Args>::name...)\n                             + const_name(\"], \") + make_caster<retval_type>::name\n                             + const_name(\"]\"));\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/gil.h",
    "content": "/*\n    pybind11/gil.h: RAII helpers for managing the GIL\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n\n#include <cassert>\n\n#if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n#    include \"detail/internals.h\"\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// forward declarations\nPyThreadState *get_thread_state_unchecked();\n\nPYBIND11_NAMESPACE_END(detail)\n\n#if defined(WITH_THREAD)\n\n#    if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)\n\n/* The functions below essentially reproduce the PyGILState_* API using a RAII\n * pattern, but there are a few important differences:\n *\n * 1. When acquiring the GIL from an non-main thread during the finalization\n *    phase, the GILState API blindly terminates the calling thread, which\n *    is often not what is wanted. This API does not do this.\n *\n * 2. The gil_scoped_release function can optionally cut the relationship\n *    of a PyThreadState and its associated thread, which allows moving it to\n *    another thread (this is a fairly rare/advanced use case).\n *\n * 3. The reference count of an acquired thread state can be controlled. This\n *    can be handy to prevent cases where callbacks issued from an external\n *    thread would otherwise constantly construct and destroy thread state data\n *    structures.\n *\n * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an\n * example which uses features 2 and 3 to migrate the Python thread of\n * execution to another thread (to run the event loop on the original thread,\n * in this case).\n */\n\nclass gil_scoped_acquire {\npublic:\n    PYBIND11_NOINLINE gil_scoped_acquire() {\n        auto &internals = detail::get_internals();\n        tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);\n\n        if (!tstate) {\n            /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if\n               calling from a Python thread). Since we use a different key, this ensures\n               we don't create a new thread state and deadlock in PyEval_AcquireThread\n               below. Note we don't save this state with internals.tstate, since we don't\n               create it we would fail to clear it (its reference count should be > 0). */\n            tstate = PyGILState_GetThisThreadState();\n        }\n\n        if (!tstate) {\n            tstate = PyThreadState_New(internals.istate);\n#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            if (!tstate) {\n                pybind11_fail(\"scoped_acquire: could not create thread state!\");\n            }\n#        endif\n            tstate->gilstate_counter = 0;\n            PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);\n        } else {\n            release = detail::get_thread_state_unchecked() != tstate;\n        }\n\n        if (release) {\n            PyEval_AcquireThread(tstate);\n        }\n\n        inc_ref();\n    }\n\n    gil_scoped_acquire(const gil_scoped_acquire &) = delete;\n    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;\n\n    void inc_ref() { ++tstate->gilstate_counter; }\n\n    PYBIND11_NOINLINE void dec_ref() {\n        --tstate->gilstate_counter;\n#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n        if (detail::get_thread_state_unchecked() != tstate) {\n            pybind11_fail(\"scoped_acquire::dec_ref(): thread state must be current!\");\n        }\n        if (tstate->gilstate_counter < 0) {\n            pybind11_fail(\"scoped_acquire::dec_ref(): reference count underflow!\");\n        }\n#        endif\n        if (tstate->gilstate_counter == 0) {\n#        if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n            if (!release) {\n                pybind11_fail(\"scoped_acquire::dec_ref(): internal error!\");\n            }\n#        endif\n            PyThreadState_Clear(tstate);\n            if (active) {\n                PyThreadState_DeleteCurrent();\n            }\n            PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);\n            release = false;\n        }\n    }\n\n    /// This method will disable the PyThreadState_DeleteCurrent call and the\n    /// GIL won't be acquired. This method should be used if the interpreter\n    /// could be shutting down when this is called, as thread deletion is not\n    /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and\n    /// protect subsequent code.\n    PYBIND11_NOINLINE void disarm() { active = false; }\n\n    PYBIND11_NOINLINE ~gil_scoped_acquire() {\n        dec_ref();\n        if (release) {\n            PyEval_SaveThread();\n        }\n    }\n\nprivate:\n    PyThreadState *tstate = nullptr;\n    bool release = true;\n    bool active = true;\n};\n\nclass gil_scoped_release {\npublic:\n    // PRECONDITION: The GIL must be held when this constructor is called.\n    explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {\n        assert(PyGILState_Check());\n        // `get_internals()` must be called here unconditionally in order to initialize\n        // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an\n        // initialization race could occur as multiple threads try `gil_scoped_acquire`.\n        auto &internals = detail::get_internals();\n        // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)\n        tstate = PyEval_SaveThread();\n        if (disassoc) {\n            // Python >= 3.7 can remove this, it's an int before 3.7\n            // NOLINTNEXTLINE(readability-qualified-auto)\n            auto key = internals.tstate;\n            PYBIND11_TLS_DELETE_VALUE(key);\n        }\n    }\n\n    gil_scoped_release(const gil_scoped_release &) = delete;\n    gil_scoped_release &operator=(const gil_scoped_release &) = delete;\n\n    /// This method will disable the PyThreadState_DeleteCurrent call and the\n    /// GIL won't be acquired. This method should be used if the interpreter\n    /// could be shutting down when this is called, as thread deletion is not\n    /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and\n    /// protect subsequent code.\n    PYBIND11_NOINLINE void disarm() { active = false; }\n\n    ~gil_scoped_release() {\n        if (!tstate) {\n            return;\n        }\n        // `PyEval_RestoreThread()` should not be called if runtime is finalizing\n        if (active) {\n            PyEval_RestoreThread(tstate);\n        }\n        if (disassoc) {\n            // Python >= 3.7 can remove this, it's an int before 3.7\n            // NOLINTNEXTLINE(readability-qualified-auto)\n            auto key = detail::get_internals().tstate;\n            PYBIND11_TLS_REPLACE_VALUE(key, tstate);\n        }\n    }\n\nprivate:\n    PyThreadState *tstate;\n    bool disassoc;\n    bool active = true;\n};\n\n#    else // PYBIND11_SIMPLE_GIL_MANAGEMENT\n\nclass gil_scoped_acquire {\n    PyGILState_STATE state;\n\npublic:\n    gil_scoped_acquire() : state{PyGILState_Ensure()} {}\n    gil_scoped_acquire(const gil_scoped_acquire &) = delete;\n    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;\n    ~gil_scoped_acquire() { PyGILState_Release(state); }\n    void disarm() {}\n};\n\nclass gil_scoped_release {\n    PyThreadState *state;\n\npublic:\n    // PRECONDITION: The GIL must be held when this constructor is called.\n    gil_scoped_release() {\n        assert(PyGILState_Check());\n        state = PyEval_SaveThread();\n    }\n    gil_scoped_release(const gil_scoped_release &) = delete;\n    gil_scoped_release &operator=(const gil_scoped_release &) = delete;\n    ~gil_scoped_release() { PyEval_RestoreThread(state); }\n    void disarm() {}\n};\n\n#    endif // PYBIND11_SIMPLE_GIL_MANAGEMENT\n\n#else // WITH_THREAD\n\nclass gil_scoped_acquire {\npublic:\n    gil_scoped_acquire() {\n        // Trick to suppress `unused variable` error messages (at call sites).\n        (void) (this != (this + 1));\n    }\n    gil_scoped_acquire(const gil_scoped_acquire &) = delete;\n    gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;\n    void disarm() {}\n};\n\nclass gil_scoped_release {\npublic:\n    gil_scoped_release() {\n        // Trick to suppress `unused variable` error messages (at call sites).\n        (void) (this != (this + 1));\n    }\n    gil_scoped_release(const gil_scoped_release &) = delete;\n    gil_scoped_release &operator=(const gil_scoped_release &) = delete;\n    void disarm() {}\n};\n\n#endif // WITH_THREAD\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/gil_safe_call_once.h",
    "content": "// Copyright (c) 2023 The pybind Community.\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"gil.h\"\n\n#include <cassert>\n#include <mutex>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\n// Use the `gil_safe_call_once_and_store` class below instead of the naive\n//\n//   static auto imported_obj = py::module_::import(\"module_name\"); // BAD, DO NOT USE!\n//\n// which has two serious issues:\n//\n//     1. Py_DECREF() calls potentially after the Python interpreter was finalized already, and\n//     2. deadlocks in multi-threaded processes (because of missing lock ordering).\n//\n// The following alternative avoids both problems:\n//\n//   PYBIND11_CONSTINIT static py::gil_safe_call_once_and_store<py::object> storage;\n//   auto &imported_obj = storage // Do NOT make this `static`!\n//       .call_once_and_store_result([]() {\n//           return py::module_::import(\"module_name\");\n//       })\n//       .get_stored();\n//\n// The parameter of `call_once_and_store_result()` must be callable. It can make\n// CPython API calls, and in particular, it can temporarily release the GIL.\n//\n// `T` can be any C++ type, it does not have to involve CPython API types.\n//\n// The behavior with regard to signals, e.g. `SIGINT` (`KeyboardInterrupt`),\n// is not ideal. If the main thread is the one to actually run the `Callable`,\n// then a `KeyboardInterrupt` will interrupt it if it is running normal Python\n// code. The situation is different if a non-main thread runs the\n// `Callable`, and then the main thread starts waiting for it to complete:\n// a `KeyboardInterrupt` will not interrupt the non-main thread, but it will\n// get processed only when it is the main thread's turn again and it is running\n// normal Python code. However, this will be unnoticeable for quick call-once\n// functions, which is usually the case.\ntemplate <typename T>\nclass gil_safe_call_once_and_store {\npublic:\n    // PRECONDITION: The GIL must be held when `call_once_and_store_result()` is called.\n    template <typename Callable>\n    gil_safe_call_once_and_store &call_once_and_store_result(Callable &&fn) {\n        if (!is_initialized_) { // This read is guarded by the GIL.\n            // Multiple threads may enter here, because the GIL is released in the next line and\n            // CPython API calls in the `fn()` call below may release and reacquire the GIL.\n            gil_scoped_release gil_rel; // Needed to establish lock ordering.\n            std::call_once(once_flag_, [&] {\n                // Only one thread will ever enter here.\n                gil_scoped_acquire gil_acq;\n                ::new (storage_) T(fn()); // fn may release, but will reacquire, the GIL.\n                is_initialized_ = true;   // This write is guarded by the GIL.\n            });\n            // All threads will observe `is_initialized_` as true here.\n        }\n        // Intentionally not returning `T &` to ensure the calling code is self-documenting.\n        return *this;\n    }\n\n    // This must only be called after `call_once_and_store_result()` was called.\n    T &get_stored() {\n        assert(is_initialized_);\n        PYBIND11_WARNING_PUSH\n#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5\n        // Needed for gcc 4.8.5\n        PYBIND11_WARNING_DISABLE_GCC(\"-Wstrict-aliasing\")\n#endif\n        return *reinterpret_cast<T *>(storage_);\n        PYBIND11_WARNING_POP\n    }\n\n    constexpr gil_safe_call_once_and_store() = default;\n    PYBIND11_DTOR_CONSTEXPR ~gil_safe_call_once_and_store() = default;\n\nprivate:\n    alignas(T) char storage_[sizeof(T)] = {};\n    std::once_flag once_flag_ = {};\n    bool is_initialized_ = false;\n    // The `is_initialized_`-`storage_` pair is very similar to `std::optional`,\n    // but the latter does not have the triviality properties of former,\n    // therefore `std::optional` is not a viable alternative here.\n};\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/iostream.h",
    "content": "/*\n    pybind11/iostream.h -- Tools to assist with redirecting cout and cerr to Python\n\n    Copyright (c) 2017 Henry F. Schreiner\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n\n    WARNING: The implementation in this file is NOT thread safe. Multiple\n    threads writing to a redirected ostream concurrently cause data races\n    and potentially buffer overflows. Therefore it is currently a requirement\n    that all (possibly) concurrent redirected ostream writes are protected by\n    a mutex.\n    #HelpAppreciated: Work on iostream.h thread safety.\n    For more background see the discussions under\n    https://github.com/pybind/pybind11/pull/2982 and\n    https://github.com/pybind/pybind11/pull/2995.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\n#include <algorithm>\n#include <cstring>\n#include <iostream>\n#include <iterator>\n#include <memory>\n#include <ostream>\n#include <streambuf>\n#include <string>\n#include <utility>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Buffer that writes to Python instead of C++\nclass pythonbuf : public std::streambuf {\nprivate:\n    using traits_type = std::streambuf::traits_type;\n\n    const size_t buf_size;\n    std::unique_ptr<char[]> d_buffer;\n    object pywrite;\n    object pyflush;\n\n    int overflow(int c) override {\n        if (!traits_type::eq_int_type(c, traits_type::eof())) {\n            *pptr() = traits_type::to_char_type(c);\n            pbump(1);\n        }\n        return sync() == 0 ? traits_type::not_eof(c) : traits_type::eof();\n    }\n\n    // Computes how many bytes at the end of the buffer are part of an\n    // incomplete sequence of UTF-8 bytes.\n    // Precondition: pbase() < pptr()\n    size_t utf8_remainder() const {\n        const auto rbase = std::reverse_iterator<char *>(pbase());\n        const auto rpptr = std::reverse_iterator<char *>(pptr());\n        auto is_ascii = [](char c) { return (static_cast<unsigned char>(c) & 0x80) == 0x00; };\n        auto is_leading = [](char c) { return (static_cast<unsigned char>(c) & 0xC0) == 0xC0; };\n        auto is_leading_2b = [](char c) { return static_cast<unsigned char>(c) <= 0xDF; };\n        auto is_leading_3b = [](char c) { return static_cast<unsigned char>(c) <= 0xEF; };\n        // If the last character is ASCII, there are no incomplete code points\n        if (is_ascii(*rpptr)) {\n            return 0;\n        }\n        // Otherwise, work back from the end of the buffer and find the first\n        // UTF-8 leading byte\n        const auto rpend = rbase - rpptr >= 3 ? rpptr + 3 : rbase;\n        const auto leading = std::find_if(rpptr, rpend, is_leading);\n        if (leading == rbase) {\n            return 0;\n        }\n        const auto dist = static_cast<size_t>(leading - rpptr);\n        size_t remainder = 0;\n\n        if (dist == 0) {\n            remainder = 1; // 1-byte code point is impossible\n        } else if (dist == 1) {\n            remainder = is_leading_2b(*leading) ? 0 : dist + 1;\n        } else if (dist == 2) {\n            remainder = is_leading_3b(*leading) ? 0 : dist + 1;\n        }\n        // else if (dist >= 3), at least 4 bytes before encountering an UTF-8\n        // leading byte, either no remainder or invalid UTF-8.\n        // Invalid UTF-8 will cause an exception later when converting\n        // to a Python string, so that's not handled here.\n        return remainder;\n    }\n\n    // This function must be non-virtual to be called in a destructor.\n    int _sync() {\n        if (pbase() != pptr()) { // If buffer is not empty\n            gil_scoped_acquire tmp;\n            // This subtraction cannot be negative, so dropping the sign.\n            auto size = static_cast<size_t>(pptr() - pbase());\n            size_t remainder = utf8_remainder();\n\n            if (size > remainder) {\n                str line(pbase(), size - remainder);\n                pywrite(std::move(line));\n                pyflush();\n            }\n\n            // Copy the remainder at the end of the buffer to the beginning:\n            if (remainder > 0) {\n                std::memmove(pbase(), pptr() - remainder, remainder);\n            }\n            setp(pbase(), epptr());\n            pbump(static_cast<int>(remainder));\n        }\n        return 0;\n    }\n\n    int sync() override { return _sync(); }\n\npublic:\n    explicit pythonbuf(const object &pyostream, size_t buffer_size = 1024)\n        : buf_size(buffer_size), d_buffer(new char[buf_size]), pywrite(pyostream.attr(\"write\")),\n          pyflush(pyostream.attr(\"flush\")) {\n        setp(d_buffer.get(), d_buffer.get() + buf_size - 1);\n    }\n\n    pythonbuf(pythonbuf &&) = default;\n\n    /// Sync before destroy\n    ~pythonbuf() override { _sync(); }\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\n/** \\rst\n    This a move-only guard that redirects output.\n\n    .. code-block:: cpp\n\n        #include <pybind11/iostream.h>\n\n        ...\n\n        {\n            py::scoped_ostream_redirect output;\n            std::cout << \"Hello, World!\"; // Python stdout\n        } // <-- return std::cout to normal\n\n    You can explicitly pass the c++ stream and the python object,\n    for example to guard stderr instead.\n\n    .. code-block:: cpp\n\n        {\n            py::scoped_ostream_redirect output{\n                std::cerr, py::module::import(\"sys\").attr(\"stderr\")};\n            std::cout << \"Hello, World!\";\n        }\n \\endrst */\nclass scoped_ostream_redirect {\nprotected:\n    std::streambuf *old;\n    std::ostream &costream;\n    detail::pythonbuf buffer;\n\npublic:\n    explicit scoped_ostream_redirect(std::ostream &costream = std::cout,\n                                     const object &pyostream\n                                     = module_::import(\"sys\").attr(\"stdout\"))\n        : costream(costream), buffer(pyostream) {\n        old = costream.rdbuf(&buffer);\n    }\n\n    ~scoped_ostream_redirect() { costream.rdbuf(old); }\n\n    scoped_ostream_redirect(const scoped_ostream_redirect &) = delete;\n    scoped_ostream_redirect(scoped_ostream_redirect &&other) = default;\n    scoped_ostream_redirect &operator=(const scoped_ostream_redirect &) = delete;\n    scoped_ostream_redirect &operator=(scoped_ostream_redirect &&) = delete;\n};\n\n/** \\rst\n    Like `scoped_ostream_redirect`, but redirects cerr by default. This class\n    is provided primary to make ``py::call_guard`` easier to make.\n\n    .. code-block:: cpp\n\n     m.def(\"noisy_func\", &noisy_func,\n           py::call_guard<scoped_ostream_redirect,\n                          scoped_estream_redirect>());\n\n\\endrst */\nclass scoped_estream_redirect : public scoped_ostream_redirect {\npublic:\n    explicit scoped_estream_redirect(std::ostream &costream = std::cerr,\n                                     const object &pyostream\n                                     = module_::import(\"sys\").attr(\"stderr\"))\n        : scoped_ostream_redirect(costream, pyostream) {}\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Class to redirect output as a context manager. C++ backend.\nclass OstreamRedirect {\n    bool do_stdout_;\n    bool do_stderr_;\n    std::unique_ptr<scoped_ostream_redirect> redirect_stdout;\n    std::unique_ptr<scoped_estream_redirect> redirect_stderr;\n\npublic:\n    explicit OstreamRedirect(bool do_stdout = true, bool do_stderr = true)\n        : do_stdout_(do_stdout), do_stderr_(do_stderr) {}\n\n    void enter() {\n        if (do_stdout_) {\n            redirect_stdout.reset(new scoped_ostream_redirect());\n        }\n        if (do_stderr_) {\n            redirect_stderr.reset(new scoped_estream_redirect());\n        }\n    }\n\n    void exit() {\n        redirect_stdout.reset();\n        redirect_stderr.reset();\n    }\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\n/** \\rst\n    This is a helper function to add a C++ redirect context manager to Python\n    instead of using a C++ guard. To use it, add the following to your binding code:\n\n    .. code-block:: cpp\n\n        #include <pybind11/iostream.h>\n\n        ...\n\n        py::add_ostream_redirect(m, \"ostream_redirect\");\n\n    You now have a Python context manager that redirects your output:\n\n    .. code-block:: python\n\n        with m.ostream_redirect():\n            m.print_to_cout_function()\n\n    This manager can optionally be told which streams to operate on:\n\n    .. code-block:: python\n\n        with m.ostream_redirect(stdout=true, stderr=true):\n            m.noisy_function_with_error_printing()\n\n \\endrst */\ninline class_<detail::OstreamRedirect>\nadd_ostream_redirect(module_ m, const std::string &name = \"ostream_redirect\") {\n    return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())\n        .def(init<bool, bool>(), arg(\"stdout\") = true, arg(\"stderr\") = true)\n        .def(\"__enter__\", &detail::OstreamRedirect::enter)\n        .def(\"__exit__\", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/numpy.h",
    "content": "/*\n    pybind11/numpy.h: Basic NumPy support, vectorize() wrapper\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n#include \"detail/common.h\"\n#include \"complex.h\"\n#include \"gil_safe_call_once.h\"\n#include \"pytypes.h\"\n\n#include <algorithm>\n#include <array>\n#include <cstdint>\n#include <cstdlib>\n#include <cstring>\n#include <functional>\n#include <numeric>\n#include <sstream>\n#include <string>\n#include <type_traits>\n#include <typeindex>\n#include <utility>\n#include <vector>\n\n#if defined(PYBIND11_NUMPY_1_ONLY) && !defined(PYBIND11_INTERNAL_NUMPY_1_ONLY_DETECTED)\n#    error PYBIND11_NUMPY_1_ONLY must be defined before any pybind11 header is included.\n#endif\n\n/* This will be true on all flat address space platforms and allows us to reduce the\n   whole npy_intp / ssize_t / Py_intptr_t business down to just ssize_t for all size\n   and dimension types (e.g. shape, strides, indexing), instead of inflicting this\n   upon the library user.\n   Note that NumPy 2 now uses ssize_t for `npy_intp` to simplify this. */\nstatic_assert(sizeof(::pybind11::ssize_t) == sizeof(Py_intptr_t), \"ssize_t != Py_intptr_t\");\nstatic_assert(std::is_signed<Py_intptr_t>::value, \"Py_intptr_t must be signed\");\n// We now can reinterpret_cast between py::ssize_t and Py_intptr_t (MSVC + PyPy cares)\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\nclass dtype; // Forward declaration\nclass array; // Forward declaration\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nstruct handle_type_name<dtype> {\n    static constexpr auto name = const_name(\"numpy.dtype\");\n};\n\ntemplate <>\nstruct handle_type_name<array> {\n    static constexpr auto name = const_name(\"numpy.ndarray\");\n};\n\ntemplate <typename type, typename SFINAE = void>\nstruct npy_format_descriptor;\n\n/* NumPy 1 proxy (always includes legacy fields) */\nstruct PyArrayDescr1_Proxy {\n    PyObject_HEAD\n    PyObject *typeobj;\n    char kind;\n    char type;\n    char byteorder;\n    char flags;\n    int type_num;\n    int elsize;\n    int alignment;\n    char *subarray;\n    PyObject *fields;\n    PyObject *names;\n};\n\n#ifndef PYBIND11_NUMPY_1_ONLY\nstruct PyArrayDescr_Proxy {\n    PyObject_HEAD\n    PyObject *typeobj;\n    char kind;\n    char type;\n    char byteorder;\n    char _former_flags;\n    int type_num;\n    /* Additional fields are NumPy version specific. */\n};\n#else\n/* NumPy 1.x only, we can expose all fields */\nusing PyArrayDescr_Proxy = PyArrayDescr1_Proxy;\n#endif\n\n/* NumPy 2 proxy, including legacy fields */\nstruct PyArrayDescr2_Proxy {\n    PyObject_HEAD\n    PyObject *typeobj;\n    char kind;\n    char type;\n    char byteorder;\n    char _former_flags;\n    int type_num;\n    std::uint64_t flags;\n    ssize_t elsize;\n    ssize_t alignment;\n    PyObject *metadata;\n    Py_hash_t hash;\n    void *reserved_null[2];\n    /* The following fields only exist if 0 <= type_num < 2056 */\n    char *subarray;\n    PyObject *fields;\n    PyObject *names;\n};\n\nstruct PyArray_Proxy {\n    PyObject_HEAD\n    char *data;\n    int nd;\n    ssize_t *dimensions;\n    ssize_t *strides;\n    PyObject *base;\n    PyObject *descr;\n    int flags;\n};\n\nstruct PyVoidScalarObject_Proxy {\n    PyObject_VAR_HEAD char *obval;\n    PyArrayDescr_Proxy *descr;\n    int flags;\n    PyObject *base;\n};\n\nstruct numpy_type_info {\n    PyObject *dtype_ptr;\n    std::string format_str;\n};\n\nstruct numpy_internals {\n    std::unordered_map<std::type_index, numpy_type_info> registered_dtypes;\n\n    numpy_type_info *get_type_info(const std::type_info &tinfo, bool throw_if_missing = true) {\n        auto it = registered_dtypes.find(std::type_index(tinfo));\n        if (it != registered_dtypes.end()) {\n            return &(it->second);\n        }\n        if (throw_if_missing) {\n            pybind11_fail(std::string(\"NumPy type info missing for \") + tinfo.name());\n        }\n        return nullptr;\n    }\n\n    template <typename T>\n    numpy_type_info *get_type_info(bool throw_if_missing = true) {\n        return get_type_info(typeid(typename std::remove_cv<T>::type), throw_if_missing);\n    }\n};\n\nPYBIND11_NOINLINE void load_numpy_internals(numpy_internals *&ptr) {\n    ptr = &get_or_create_shared_data<numpy_internals>(\"_numpy_internals\");\n}\n\ninline numpy_internals &get_numpy_internals() {\n    static numpy_internals *ptr = nullptr;\n    if (!ptr) {\n        load_numpy_internals(ptr);\n    }\n    return *ptr;\n}\n\nPYBIND11_NOINLINE module_ import_numpy_core_submodule(const char *submodule_name) {\n    module_ numpy = module_::import(\"numpy\");\n    str version_string = numpy.attr(\"__version__\");\n\n    module_ numpy_lib = module_::import(\"numpy.lib\");\n    object numpy_version = numpy_lib.attr(\"NumpyVersion\")(version_string);\n    int major_version = numpy_version.attr(\"major\").cast<int>();\n\n#ifdef PYBIND11_NUMPY_1_ONLY\n    if (major_version >= 2) {\n        throw std::runtime_error(\n            \"This extension was built with PYBIND11_NUMPY_1_ONLY defined, \"\n            \"but NumPy 2 is used in this process. For NumPy2 compatibility, \"\n            \"this extension needs to be rebuilt without the PYBIND11_NUMPY_1_ONLY define.\");\n    }\n#endif\n    /* `numpy.core` was renamed to `numpy._core` in NumPy 2.0 as it officially\n        became a private module. */\n    std::string numpy_core_path = major_version >= 2 ? \"numpy._core\" : \"numpy.core\";\n    return module_::import((numpy_core_path + \".\" + submodule_name).c_str());\n}\n\ntemplate <typename T>\nstruct same_size {\n    template <typename U>\n    using as = bool_constant<sizeof(T) == sizeof(U)>;\n};\n\ntemplate <typename Concrete>\nconstexpr int platform_lookup() {\n    return -1;\n}\n\n// Lookup a type according to its size, and return a value corresponding to the NumPy typenum.\ntemplate <typename Concrete, typename T, typename... Ts, typename... Ints>\nconstexpr int platform_lookup(int I, Ints... Is) {\n    return sizeof(Concrete) == sizeof(T) ? I : platform_lookup<Concrete, Ts...>(Is...);\n}\n\nstruct npy_api {\n    enum constants {\n        NPY_ARRAY_C_CONTIGUOUS_ = 0x0001,\n        NPY_ARRAY_F_CONTIGUOUS_ = 0x0002,\n        NPY_ARRAY_OWNDATA_ = 0x0004,\n        NPY_ARRAY_FORCECAST_ = 0x0010,\n        NPY_ARRAY_ENSUREARRAY_ = 0x0040,\n        NPY_ARRAY_ALIGNED_ = 0x0100,\n        NPY_ARRAY_WRITEABLE_ = 0x0400,\n        NPY_BOOL_ = 0,\n        NPY_BYTE_,\n        NPY_UBYTE_,\n        NPY_SHORT_,\n        NPY_USHORT_,\n        NPY_INT_,\n        NPY_UINT_,\n        NPY_LONG_,\n        NPY_ULONG_,\n        NPY_LONGLONG_,\n        NPY_ULONGLONG_,\n        NPY_FLOAT_,\n        NPY_DOUBLE_,\n        NPY_LONGDOUBLE_,\n        NPY_CFLOAT_,\n        NPY_CDOUBLE_,\n        NPY_CLONGDOUBLE_,\n        NPY_OBJECT_ = 17,\n        NPY_STRING_,\n        NPY_UNICODE_,\n        NPY_VOID_,\n        // Platform-dependent normalization\n        NPY_INT8_ = NPY_BYTE_,\n        NPY_UINT8_ = NPY_UBYTE_,\n        NPY_INT16_ = NPY_SHORT_,\n        NPY_UINT16_ = NPY_USHORT_,\n        // `npy_common.h` defines the integer aliases. In order, it checks:\n        // NPY_BITSOF_LONG, NPY_BITSOF_LONGLONG, NPY_BITSOF_INT, NPY_BITSOF_SHORT, NPY_BITSOF_CHAR\n        // and assigns the alias to the first matching size, so we should check in this order.\n        NPY_INT32_\n        = platform_lookup<std::int32_t, long, int, short>(NPY_LONG_, NPY_INT_, NPY_SHORT_),\n        NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>(\n            NPY_ULONG_, NPY_UINT_, NPY_USHORT_),\n        NPY_INT64_\n        = platform_lookup<std::int64_t, long, long long, int>(NPY_LONG_, NPY_LONGLONG_, NPY_INT_),\n        NPY_UINT64_\n        = platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(\n            NPY_ULONG_, NPY_ULONGLONG_, NPY_UINT_),\n    };\n\n    unsigned int PyArray_RUNTIME_VERSION_;\n\n    struct PyArray_Dims {\n        Py_intptr_t *ptr;\n        int len;\n    };\n\n    static npy_api &get() {\n        PYBIND11_CONSTINIT static gil_safe_call_once_and_store<npy_api> storage;\n        return storage.call_once_and_store_result(lookup).get_stored();\n    }\n\n    bool PyArray_Check_(PyObject *obj) const {\n        return PyObject_TypeCheck(obj, PyArray_Type_) != 0;\n    }\n    bool PyArrayDescr_Check_(PyObject *obj) const {\n        return PyObject_TypeCheck(obj, PyArrayDescr_Type_) != 0;\n    }\n\n    unsigned int (*PyArray_GetNDArrayCFeatureVersion_)();\n    PyObject *(*PyArray_DescrFromType_)(int);\n    PyObject *(*PyArray_NewFromDescr_)(PyTypeObject *,\n                                       PyObject *,\n                                       int,\n                                       Py_intptr_t const *,\n                                       Py_intptr_t const *,\n                                       void *,\n                                       int,\n                                       PyObject *);\n    // Unused. Not removed because that affects ABI of the class.\n    PyObject *(*PyArray_DescrNewFromType_)(int);\n    int (*PyArray_CopyInto_)(PyObject *, PyObject *);\n    PyObject *(*PyArray_NewCopy_)(PyObject *, int);\n    PyTypeObject *PyArray_Type_;\n    PyTypeObject *PyVoidArrType_Type_;\n    PyTypeObject *PyArrayDescr_Type_;\n    PyObject *(*PyArray_DescrFromScalar_)(PyObject *);\n    PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);\n    int (*PyArray_DescrConverter_)(PyObject *, PyObject **);\n    bool (*PyArray_EquivTypes_)(PyObject *, PyObject *);\n#ifdef PYBIND11_NUMPY_1_ONLY\n    int (*PyArray_GetArrayParamsFromObject_)(PyObject *,\n                                             PyObject *,\n                                             unsigned char,\n                                             PyObject **,\n                                             int *,\n                                             Py_intptr_t *,\n                                             PyObject **,\n                                             PyObject *);\n#endif\n    PyObject *(*PyArray_Squeeze_)(PyObject *);\n    // Unused. Not removed because that affects ABI of the class.\n    int (*PyArray_SetBaseObject_)(PyObject *, PyObject *);\n    PyObject *(*PyArray_Resize_)(PyObject *, PyArray_Dims *, int, int);\n    PyObject *(*PyArray_Newshape_)(PyObject *, PyArray_Dims *, int);\n    PyObject *(*PyArray_View_)(PyObject *, PyObject *, PyObject *);\n\nprivate:\n    enum functions {\n        API_PyArray_GetNDArrayCFeatureVersion = 211,\n        API_PyArray_Type = 2,\n        API_PyArrayDescr_Type = 3,\n        API_PyVoidArrType_Type = 39,\n        API_PyArray_DescrFromType = 45,\n        API_PyArray_DescrFromScalar = 57,\n        API_PyArray_FromAny = 69,\n        API_PyArray_Resize = 80,\n        // CopyInto was slot 82 and 50 was effectively an alias. NumPy 2 removed 82.\n        API_PyArray_CopyInto = 50,\n        API_PyArray_NewCopy = 85,\n        API_PyArray_NewFromDescr = 94,\n        API_PyArray_DescrNewFromType = 96,\n        API_PyArray_Newshape = 135,\n        API_PyArray_Squeeze = 136,\n        API_PyArray_View = 137,\n        API_PyArray_DescrConverter = 174,\n        API_PyArray_EquivTypes = 182,\n#ifdef PYBIND11_NUMPY_1_ONLY\n        API_PyArray_GetArrayParamsFromObject = 278,\n#endif\n        API_PyArray_SetBaseObject = 282\n    };\n\n    static npy_api lookup() {\n        module_ m = detail::import_numpy_core_submodule(\"multiarray\");\n        auto c = m.attr(\"_ARRAY_API\");\n        void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), nullptr);\n        if (api_ptr == nullptr) {\n            raise_from(PyExc_SystemError, \"FAILURE obtaining numpy _ARRAY_API pointer.\");\n            throw error_already_set();\n        }\n        npy_api api;\n#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];\n        DECL_NPY_API(PyArray_GetNDArrayCFeatureVersion);\n        api.PyArray_RUNTIME_VERSION_ = api.PyArray_GetNDArrayCFeatureVersion_();\n        if (api.PyArray_RUNTIME_VERSION_ < 0x7) {\n            pybind11_fail(\"pybind11 numpy support requires numpy >= 1.7.0\");\n        }\n        DECL_NPY_API(PyArray_Type);\n        DECL_NPY_API(PyVoidArrType_Type);\n        DECL_NPY_API(PyArrayDescr_Type);\n        DECL_NPY_API(PyArray_DescrFromType);\n        DECL_NPY_API(PyArray_DescrFromScalar);\n        DECL_NPY_API(PyArray_FromAny);\n        DECL_NPY_API(PyArray_Resize);\n        DECL_NPY_API(PyArray_CopyInto);\n        DECL_NPY_API(PyArray_NewCopy);\n        DECL_NPY_API(PyArray_NewFromDescr);\n        DECL_NPY_API(PyArray_DescrNewFromType);\n        DECL_NPY_API(PyArray_Newshape);\n        DECL_NPY_API(PyArray_Squeeze);\n        DECL_NPY_API(PyArray_View);\n        DECL_NPY_API(PyArray_DescrConverter);\n        DECL_NPY_API(PyArray_EquivTypes);\n#ifdef PYBIND11_NUMPY_1_ONLY\n        DECL_NPY_API(PyArray_GetArrayParamsFromObject);\n#endif\n        DECL_NPY_API(PyArray_SetBaseObject);\n\n#undef DECL_NPY_API\n        return api;\n    }\n};\n\ninline PyArray_Proxy *array_proxy(void *ptr) { return reinterpret_cast<PyArray_Proxy *>(ptr); }\n\ninline const PyArray_Proxy *array_proxy(const void *ptr) {\n    return reinterpret_cast<const PyArray_Proxy *>(ptr);\n}\n\ninline PyArrayDescr_Proxy *array_descriptor_proxy(PyObject *ptr) {\n    return reinterpret_cast<PyArrayDescr_Proxy *>(ptr);\n}\n\ninline const PyArrayDescr_Proxy *array_descriptor_proxy(const PyObject *ptr) {\n    return reinterpret_cast<const PyArrayDescr_Proxy *>(ptr);\n}\n\ninline const PyArrayDescr1_Proxy *array_descriptor1_proxy(const PyObject *ptr) {\n    return reinterpret_cast<const PyArrayDescr1_Proxy *>(ptr);\n}\n\ninline const PyArrayDescr2_Proxy *array_descriptor2_proxy(const PyObject *ptr) {\n    return reinterpret_cast<const PyArrayDescr2_Proxy *>(ptr);\n}\n\ninline bool check_flags(const void *ptr, int flag) {\n    return (flag == (array_proxy(ptr)->flags & flag));\n}\n\ntemplate <typename T>\nstruct is_std_array : std::false_type {};\ntemplate <typename T, size_t N>\nstruct is_std_array<std::array<T, N>> : std::true_type {};\ntemplate <typename T>\nstruct is_complex : std::false_type {};\ntemplate <typename T>\nstruct is_complex<std::complex<T>> : std::true_type {};\n\ntemplate <typename T>\nstruct array_info_scalar {\n    using type = T;\n    static constexpr bool is_array = false;\n    static constexpr bool is_empty = false;\n    static constexpr auto extents = const_name(\"\");\n    static void append_extents(list & /* shape */) {}\n};\n// Computes underlying type and a comma-separated list of extents for array\n// types (any mix of std::array and built-in arrays). An array of char is\n// treated as scalar because it gets special handling.\ntemplate <typename T>\nstruct array_info : array_info_scalar<T> {};\ntemplate <typename T, size_t N>\nstruct array_info<std::array<T, N>> {\n    using type = typename array_info<T>::type;\n    static constexpr bool is_array = true;\n    static constexpr bool is_empty = (N == 0) || array_info<T>::is_empty;\n    static constexpr size_t extent = N;\n\n    // appends the extents to shape\n    static void append_extents(list &shape) {\n        shape.append(N);\n        array_info<T>::append_extents(shape);\n    }\n\n    static constexpr auto extents = const_name<array_info<T>::is_array>(\n        ::pybind11::detail::concat(const_name<N>(), array_info<T>::extents), const_name<N>());\n};\n// For numpy we have special handling for arrays of characters, so we don't include\n// the size in the array extents.\ntemplate <size_t N>\nstruct array_info<char[N]> : array_info_scalar<char[N]> {};\ntemplate <size_t N>\nstruct array_info<std::array<char, N>> : array_info_scalar<std::array<char, N>> {};\ntemplate <typename T, size_t N>\nstruct array_info<T[N]> : array_info<std::array<T, N>> {};\ntemplate <typename T>\nusing remove_all_extents_t = typename array_info<T>::type;\n\ntemplate <typename T>\nusing is_pod_struct\n    = all_of<std::is_standard_layout<T>, // since we're accessing directly in memory\n                                         // we need a standard layout type\n#if defined(__GLIBCXX__)                                                                          \\\n    && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623              \\\n        || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)\n             // libstdc++ < 5 (including versions 4.8.5, 4.9.3 and 4.9.4 which were released after\n             // 5) don't implement is_trivially_copyable, so approximate it\n             std::is_trivially_destructible<T>,\n             satisfies_any_of<T, std::has_trivial_copy_constructor, std::has_trivial_copy_assign>,\n#else\n             std::is_trivially_copyable<T>,\n#endif\n             satisfies_none_of<T,\n                               std::is_reference,\n                               std::is_array,\n                               is_std_array,\n                               std::is_arithmetic,\n                               is_complex,\n                               std::is_enum>>;\n\n// Replacement for std::is_pod (deprecated in C++20)\ntemplate <typename T>\nusing is_pod = all_of<std::is_standard_layout<T>, std::is_trivial<T>>;\n\ntemplate <ssize_t Dim = 0, typename Strides>\nssize_t byte_offset_unsafe(const Strides &) {\n    return 0;\n}\ntemplate <ssize_t Dim = 0, typename Strides, typename... Ix>\nssize_t byte_offset_unsafe(const Strides &strides, ssize_t i, Ix... index) {\n    return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);\n}\n\n/**\n * Proxy class providing unsafe, unchecked const access to array data.  This is constructed through\n * the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims`\n * will be -1 for dimensions determined at runtime.\n */\ntemplate <typename T, ssize_t Dims>\nclass unchecked_reference {\nprotected:\n    static constexpr bool Dynamic = Dims < 0;\n    const unsigned char *data_;\n    // Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to\n    // make large performance gains on big, nested loops, but requires compile-time dimensions\n    conditional_t<Dynamic, const ssize_t *, std::array<ssize_t, (size_t) Dims>> shape_, strides_;\n    const ssize_t dims_;\n\n    friend class pybind11::array;\n    // Constructor for compile-time dimensions:\n    template <bool Dyn = Dynamic>\n    unchecked_reference(const void *data,\n                        const ssize_t *shape,\n                        const ssize_t *strides,\n                        enable_if_t<!Dyn, ssize_t>)\n        : data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {\n        for (size_t i = 0; i < (size_t) dims_; i++) {\n            shape_[i] = shape[i];\n            strides_[i] = strides[i];\n        }\n    }\n    // Constructor for runtime dimensions:\n    template <bool Dyn = Dynamic>\n    unchecked_reference(const void *data,\n                        const ssize_t *shape,\n                        const ssize_t *strides,\n                        enable_if_t<Dyn, ssize_t> dims)\n        : data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides},\n          dims_{dims} {}\n\npublic:\n    /**\n     * Unchecked const reference access to data at the given indices.  For a compile-time known\n     * number of dimensions, this requires the correct number of arguments; for run-time\n     * dimensionality, this is not checked (and so is up to the caller to use safely).\n     */\n    template <typename... Ix>\n    const T &operator()(Ix... index) const {\n        static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,\n                      \"Invalid number of indices for unchecked array reference\");\n        return *reinterpret_cast<const T *>(data_\n                                            + byte_offset_unsafe(strides_, ssize_t(index)...));\n    }\n    /**\n     * Unchecked const reference access to data; this operator only participates if the reference\n     * is to a 1-dimensional array.  When present, this is exactly equivalent to `obj(index)`.\n     */\n    template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>\n    const T &operator[](ssize_t index) const {\n        return operator()(index);\n    }\n\n    /// Pointer access to the data at the given indices.\n    template <typename... Ix>\n    const T *data(Ix... ix) const {\n        return &operator()(ssize_t(ix)...);\n    }\n\n    /// Returns the item size, i.e. sizeof(T)\n    constexpr static ssize_t itemsize() { return sizeof(T); }\n\n    /// Returns the shape (i.e. size) of dimension `dim`\n    ssize_t shape(ssize_t dim) const { return shape_[(size_t) dim]; }\n\n    /// Returns the number of dimensions of the array\n    ssize_t ndim() const { return dims_; }\n\n    /// Returns the total number of elements in the referenced array, i.e. the product of the\n    /// shapes\n    template <bool Dyn = Dynamic>\n    enable_if_t<!Dyn, ssize_t> size() const {\n        return std::accumulate(\n            shape_.begin(), shape_.end(), (ssize_t) 1, std::multiplies<ssize_t>());\n    }\n    template <bool Dyn = Dynamic>\n    enable_if_t<Dyn, ssize_t> size() const {\n        return std::accumulate(shape_, shape_ + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());\n    }\n\n    /// Returns the total number of bytes used by the referenced data.  Note that the actual span\n    /// in memory may be larger if the referenced array has non-contiguous strides (e.g. for a\n    /// slice).\n    ssize_t nbytes() const { return size() * itemsize(); }\n};\n\ntemplate <typename T, ssize_t Dims>\nclass unchecked_mutable_reference : public unchecked_reference<T, Dims> {\n    friend class pybind11::array;\n    using ConstBase = unchecked_reference<T, Dims>;\n    using ConstBase::ConstBase;\n    using ConstBase::Dynamic;\n\npublic:\n    // Bring in const-qualified versions from base class\n    using ConstBase::operator();\n    using ConstBase::operator[];\n\n    /// Mutable, unchecked access to data at the given indices.\n    template <typename... Ix>\n    T &operator()(Ix... index) {\n        static_assert(ssize_t{sizeof...(Ix)} == Dims || Dynamic,\n                      \"Invalid number of indices for unchecked array reference\");\n        return const_cast<T &>(ConstBase::operator()(index...));\n    }\n    /**\n     * Mutable, unchecked access data at the given index; this operator only participates if the\n     * reference is to a 1-dimensional array (or has runtime dimensions).  When present, this is\n     * exactly equivalent to `obj(index)`.\n     */\n    template <ssize_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>\n    T &operator[](ssize_t index) {\n        return operator()(index);\n    }\n\n    /// Mutable pointer access to the data at the given indices.\n    template <typename... Ix>\n    T *mutable_data(Ix... ix) {\n        return &operator()(ssize_t(ix)...);\n    }\n};\n\ntemplate <typename T, ssize_t Dim>\nstruct type_caster<unchecked_reference<T, Dim>> {\n    static_assert(Dim == 0 && Dim > 0 /* always fail */,\n                  \"unchecked array proxy object is not castable\");\n};\ntemplate <typename T, ssize_t Dim>\nstruct type_caster<unchecked_mutable_reference<T, Dim>>\n    : type_caster<unchecked_reference<T, Dim>> {};\n\nPYBIND11_NAMESPACE_END(detail)\n\nclass dtype : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(dtype, object, detail::npy_api::get().PyArrayDescr_Check_)\n\n    explicit dtype(const buffer_info &info) {\n        dtype descr(_dtype_from_pep3118()(pybind11::str(info.format)));\n        // If info.itemsize == 0, use the value calculated from the format string\n        m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())\n                    .release()\n                    .ptr();\n    }\n\n    explicit dtype(const pybind11::str &format) : dtype(from_args(format)) {}\n\n    explicit dtype(const std::string &format) : dtype(pybind11::str(format)) {}\n\n    explicit dtype(const char *format) : dtype(pybind11::str(format)) {}\n\n    dtype(list names, list formats, list offsets, ssize_t itemsize) {\n        dict args;\n        args[\"names\"] = std::move(names);\n        args[\"formats\"] = std::move(formats);\n        args[\"offsets\"] = std::move(offsets);\n        args[\"itemsize\"] = pybind11::int_(itemsize);\n        m_ptr = from_args(args).release().ptr();\n    }\n\n    /// Return dtype for the given typenum (one of the NPY_TYPES).\n    /// https://numpy.org/devdocs/reference/c-api/array.html#c.PyArray_DescrFromType\n    explicit dtype(int typenum)\n        : object(detail::npy_api::get().PyArray_DescrFromType_(typenum), stolen_t{}) {\n        if (m_ptr == nullptr) {\n            throw error_already_set();\n        }\n    }\n\n    /// This is essentially the same as calling numpy.dtype(args) in Python.\n    static dtype from_args(const object &args) {\n        PyObject *ptr = nullptr;\n        if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<dtype>(ptr);\n    }\n\n    /// Return dtype associated with a C++ type.\n    template <typename T>\n    static dtype of() {\n        return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::dtype();\n    }\n\n    /// Size of the data type in bytes.\n#ifdef PYBIND11_NUMPY_1_ONLY\n    ssize_t itemsize() const { return detail::array_descriptor_proxy(m_ptr)->elsize; }\n#else\n    ssize_t itemsize() const {\n        if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {\n            return detail::array_descriptor1_proxy(m_ptr)->elsize;\n        }\n        return detail::array_descriptor2_proxy(m_ptr)->elsize;\n    }\n#endif\n\n    /// Returns true for structured data types.\n#ifdef PYBIND11_NUMPY_1_ONLY\n    bool has_fields() const { return detail::array_descriptor_proxy(m_ptr)->names != nullptr; }\n#else\n    bool has_fields() const {\n        if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {\n            return detail::array_descriptor1_proxy(m_ptr)->names != nullptr;\n        }\n        const auto *proxy = detail::array_descriptor2_proxy(m_ptr);\n        if (proxy->type_num < 0 || proxy->type_num >= 2056) {\n            return false;\n        }\n        return proxy->names != nullptr;\n    }\n#endif\n\n    /// Single-character code for dtype's kind.\n    /// For example, floating point types are 'f' and integral types are 'i'.\n    char kind() const { return detail::array_descriptor_proxy(m_ptr)->kind; }\n\n    /// Single-character for dtype's type.\n    /// For example, ``float`` is 'f', ``double`` 'd', ``int`` 'i', and ``long`` 'l'.\n    char char_() const {\n        // Note: The signature, `dtype::char_` follows the naming of NumPy's\n        // public Python API (i.e., ``dtype.char``), rather than its internal\n        // C API (``PyArray_Descr::type``).\n        return detail::array_descriptor_proxy(m_ptr)->type;\n    }\n\n    /// type number of dtype.\n    int num() const {\n        // Note: The signature, `dtype::num` follows the naming of NumPy's public\n        // Python API (i.e., ``dtype.num``), rather than its internal\n        // C API (``PyArray_Descr::type_num``).\n        return detail::array_descriptor_proxy(m_ptr)->type_num;\n    }\n\n    /// Single character for byteorder\n    char byteorder() const { return detail::array_descriptor_proxy(m_ptr)->byteorder; }\n\n/// Alignment of the data type\n#ifdef PYBIND11_NUMPY_1_ONLY\n    int alignment() const { return detail::array_descriptor_proxy(m_ptr)->alignment; }\n#else\n    ssize_t alignment() const {\n        if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {\n            return detail::array_descriptor1_proxy(m_ptr)->alignment;\n        }\n        return detail::array_descriptor2_proxy(m_ptr)->alignment;\n    }\n#endif\n\n/// Flags for the array descriptor\n#ifdef PYBIND11_NUMPY_1_ONLY\n    char flags() const { return detail::array_descriptor_proxy(m_ptr)->flags; }\n#else\n    std::uint64_t flags() const {\n        if (detail::npy_api::get().PyArray_RUNTIME_VERSION_ < 0x12) {\n            return (unsigned char) detail::array_descriptor1_proxy(m_ptr)->flags;\n        }\n        return detail::array_descriptor2_proxy(m_ptr)->flags;\n    }\n#endif\n\nprivate:\n    static object &_dtype_from_pep3118() {\n        PYBIND11_CONSTINIT static gil_safe_call_once_and_store<object> storage;\n        return storage\n            .call_once_and_store_result([]() {\n                return detail::import_numpy_core_submodule(\"_internal\")\n                    .attr(\"_dtype_from_pep3118\");\n            })\n            .get_stored();\n    }\n\n    dtype strip_padding(ssize_t itemsize) {\n        // Recursively strip all void fields with empty names that are generated for\n        // padding fields (as of NumPy v1.11).\n        if (!has_fields()) {\n            return *this;\n        }\n\n        struct field_descr {\n            pybind11::str name;\n            object format;\n            pybind11::int_ offset;\n            field_descr(pybind11::str &&name, object &&format, pybind11::int_ &&offset)\n                : name{std::move(name)}, format{std::move(format)}, offset{std::move(offset)} {};\n        };\n        auto field_dict = attr(\"fields\").cast<dict>();\n        std::vector<field_descr> field_descriptors;\n        field_descriptors.reserve(field_dict.size());\n\n        for (auto field : field_dict.attr(\"items\")()) {\n            auto spec = field.cast<tuple>();\n            auto name = spec[0].cast<pybind11::str>();\n            auto spec_fo = spec[1].cast<tuple>();\n            auto format = spec_fo[0].cast<dtype>();\n            auto offset = spec_fo[1].cast<pybind11::int_>();\n            if ((len(name) == 0u) && format.kind() == 'V') {\n                continue;\n            }\n            field_descriptors.emplace_back(\n                std::move(name), format.strip_padding(format.itemsize()), std::move(offset));\n        }\n\n        std::sort(field_descriptors.begin(),\n                  field_descriptors.end(),\n                  [](const field_descr &a, const field_descr &b) {\n                      return a.offset.cast<int>() < b.offset.cast<int>();\n                  });\n\n        list names, formats, offsets;\n        for (auto &descr : field_descriptors) {\n            names.append(std::move(descr.name));\n            formats.append(std::move(descr.format));\n            offsets.append(std::move(descr.offset));\n        }\n        return dtype(std::move(names), std::move(formats), std::move(offsets), itemsize);\n    }\n};\n\nclass array : public buffer {\npublic:\n    PYBIND11_OBJECT_CVT(array, buffer, detail::npy_api::get().PyArray_Check_, raw_array)\n\n    enum {\n        c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,\n        f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,\n        forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_\n    };\n\n    array() : array(0, static_cast<const double *>(nullptr)) {}\n\n    using ShapeContainer = detail::any_container<ssize_t>;\n    using StridesContainer = detail::any_container<ssize_t>;\n\n    // Constructs an array taking shape/strides from arbitrary container types\n    array(const pybind11::dtype &dt,\n          ShapeContainer shape,\n          StridesContainer strides,\n          const void *ptr = nullptr,\n          handle base = handle()) {\n\n        if (strides->empty()) {\n            *strides = detail::c_strides(*shape, dt.itemsize());\n        }\n\n        auto ndim = shape->size();\n        if (ndim != strides->size()) {\n            pybind11_fail(\"NumPy: shape ndim doesn't match strides ndim\");\n        }\n        auto descr = dt;\n\n        int flags = 0;\n        if (base && ptr) {\n            if (isinstance<array>(base)) {\n                /* Copy flags from base (except ownership bit) */\n                flags = reinterpret_borrow<array>(base).flags()\n                        & ~detail::npy_api::NPY_ARRAY_OWNDATA_;\n            } else {\n                /* Writable by default, easy to downgrade later on if needed */\n                flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;\n            }\n        }\n\n        auto &api = detail::npy_api::get();\n        auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(\n            api.PyArray_Type_,\n            descr.release().ptr(),\n            (int) ndim,\n            // Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)\n            reinterpret_cast<Py_intptr_t *>(shape->data()),\n            reinterpret_cast<Py_intptr_t *>(strides->data()),\n            const_cast<void *>(ptr),\n            flags,\n            nullptr));\n        if (!tmp) {\n            throw error_already_set();\n        }\n        if (ptr) {\n            if (base) {\n                api.PyArray_SetBaseObject_(tmp.ptr(), base.inc_ref().ptr());\n            } else {\n                tmp = reinterpret_steal<object>(\n                    api.PyArray_NewCopy_(tmp.ptr(), -1 /* any order */));\n            }\n        }\n        m_ptr = tmp.release().ptr();\n    }\n\n    array(const pybind11::dtype &dt,\n          ShapeContainer shape,\n          const void *ptr = nullptr,\n          handle base = handle())\n        : array(dt, std::move(shape), {}, ptr, base) {}\n\n    template <typename T,\n              typename\n              = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>\n    array(const pybind11::dtype &dt, T count, const void *ptr = nullptr, handle base = handle())\n        : array(dt, {{count}}, ptr, base) {}\n\n    template <typename T>\n    array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base = handle())\n        : array(pybind11::dtype::of<T>(), std::move(shape), std::move(strides), ptr, base) {}\n\n    template <typename T>\n    array(ShapeContainer shape, const T *ptr, handle base = handle())\n        : array(std::move(shape), {}, ptr, base) {}\n\n    template <typename T>\n    explicit array(ssize_t count, const T *ptr, handle base = handle())\n        : array({count}, {}, ptr, base) {}\n\n    explicit array(const buffer_info &info, handle base = handle())\n        : array(pybind11::dtype(info), info.shape, info.strides, info.ptr, base) {}\n\n    /// Array descriptor (dtype)\n    pybind11::dtype dtype() const {\n        return reinterpret_borrow<pybind11::dtype>(detail::array_proxy(m_ptr)->descr);\n    }\n\n    /// Total number of elements\n    ssize_t size() const {\n        return std::accumulate(shape(), shape() + ndim(), (ssize_t) 1, std::multiplies<ssize_t>());\n    }\n\n    /// Byte size of a single element\n    ssize_t itemsize() const { return dtype().itemsize(); }\n\n    /// Total number of bytes\n    ssize_t nbytes() const { return size() * itemsize(); }\n\n    /// Number of dimensions\n    ssize_t ndim() const { return detail::array_proxy(m_ptr)->nd; }\n\n    /// Base object\n    object base() const { return reinterpret_borrow<object>(detail::array_proxy(m_ptr)->base); }\n\n    /// Dimensions of the array\n    const ssize_t *shape() const { return detail::array_proxy(m_ptr)->dimensions; }\n\n    /// Dimension along a given axis\n    ssize_t shape(ssize_t dim) const {\n        if (dim >= ndim()) {\n            fail_dim_check(dim, \"invalid axis\");\n        }\n        return shape()[dim];\n    }\n\n    /// Strides of the array\n    const ssize_t *strides() const { return detail::array_proxy(m_ptr)->strides; }\n\n    /// Stride along a given axis\n    ssize_t strides(ssize_t dim) const {\n        if (dim >= ndim()) {\n            fail_dim_check(dim, \"invalid axis\");\n        }\n        return strides()[dim];\n    }\n\n    /// Return the NumPy array flags\n    int flags() const { return detail::array_proxy(m_ptr)->flags; }\n\n    /// If set, the array is writeable (otherwise the buffer is read-only)\n    bool writeable() const {\n        return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);\n    }\n\n    /// If set, the array owns the data (will be freed when the array is deleted)\n    bool owndata() const {\n        return detail::check_flags(m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_);\n    }\n\n    /// Pointer to the contained data. If index is not provided, points to the\n    /// beginning of the buffer. May throw if the index would lead to out of bounds access.\n    template <typename... Ix>\n    const void *data(Ix... index) const {\n        return static_cast<const void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));\n    }\n\n    /// Mutable pointer to the contained data. If index is not provided, points to the\n    /// beginning of the buffer. May throw if the index would lead to out of bounds access.\n    /// May throw if the array is not writeable.\n    template <typename... Ix>\n    void *mutable_data(Ix... index) {\n        check_writeable();\n        return static_cast<void *>(detail::array_proxy(m_ptr)->data + offset_at(index...));\n    }\n\n    /// Byte offset from beginning of the array to a given index (full or partial).\n    /// May throw if the index would lead to out of bounds access.\n    template <typename... Ix>\n    ssize_t offset_at(Ix... index) const {\n        if ((ssize_t) sizeof...(index) > ndim()) {\n            fail_dim_check(sizeof...(index), \"too many indices for an array\");\n        }\n        return byte_offset(ssize_t(index)...);\n    }\n\n    ssize_t offset_at() const { return 0; }\n\n    /// Item count from beginning of the array to a given index (full or partial).\n    /// May throw if the index would lead to out of bounds access.\n    template <typename... Ix>\n    ssize_t index_at(Ix... index) const {\n        return offset_at(index...) / itemsize();\n    }\n\n    /**\n     * Returns a proxy object that provides access to the array's data without bounds or\n     * dimensionality checking.  Will throw if the array is missing the `writeable` flag.  Use with\n     * care: the array must not be destroyed or reshaped for the duration of the returned object,\n     * and the caller must take care not to access invalid dimensions or dimension indices.\n     */\n    template <typename T, ssize_t Dims = -1>\n    detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {\n        if (Dims >= 0 && ndim() != Dims) {\n            throw std::domain_error(\"array has incorrect number of dimensions: \"\n                                    + std::to_string(ndim()) + \"; expected \"\n                                    + std::to_string(Dims));\n        }\n        return detail::unchecked_mutable_reference<T, Dims>(\n            mutable_data(), shape(), strides(), ndim());\n    }\n\n    /**\n     * Returns a proxy object that provides const access to the array's data without bounds or\n     * dimensionality checking.  Unlike `mutable_unchecked()`, this does not require that the\n     * underlying array have the `writable` flag.  Use with care: the array must not be destroyed\n     * or reshaped for the duration of the returned object, and the caller must take care not to\n     * access invalid dimensions or dimension indices.\n     */\n    template <typename T, ssize_t Dims = -1>\n    detail::unchecked_reference<T, Dims> unchecked() const & {\n        if (Dims >= 0 && ndim() != Dims) {\n            throw std::domain_error(\"array has incorrect number of dimensions: \"\n                                    + std::to_string(ndim()) + \"; expected \"\n                                    + std::to_string(Dims));\n        }\n        return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());\n    }\n\n    /// Return a new view with all of the dimensions of length 1 removed\n    array squeeze() {\n        auto &api = detail::npy_api::get();\n        return reinterpret_steal<array>(api.PyArray_Squeeze_(m_ptr));\n    }\n\n    /// Resize array to given shape\n    /// If refcheck is true and more that one reference exist to this array\n    /// then resize will succeed only if it makes a reshape, i.e. original size doesn't change\n    void resize(ShapeContainer new_shape, bool refcheck = true) {\n        detail::npy_api::PyArray_Dims d\n            = {// Use reinterpret_cast for PyPy on Windows (remove if fixed, checked on 7.3.1)\n               reinterpret_cast<Py_intptr_t *>(new_shape->data()),\n               int(new_shape->size())};\n        // try to resize, set ordering param to -1 cause it's not used anyway\n        auto new_array = reinterpret_steal<object>(\n            detail::npy_api::get().PyArray_Resize_(m_ptr, &d, int(refcheck), -1));\n        if (!new_array) {\n            throw error_already_set();\n        }\n        if (isinstance<array>(new_array)) {\n            *this = std::move(new_array);\n        }\n    }\n\n    /// Optional `order` parameter omitted, to be added as needed.\n    array reshape(ShapeContainer new_shape) {\n        detail::npy_api::PyArray_Dims d\n            = {reinterpret_cast<Py_intptr_t *>(new_shape->data()), int(new_shape->size())};\n        auto new_array\n            = reinterpret_steal<array>(detail::npy_api::get().PyArray_Newshape_(m_ptr, &d, 0));\n        if (!new_array) {\n            throw error_already_set();\n        }\n        return new_array;\n    }\n\n    /// Create a view of an array in a different data type.\n    /// This function may fundamentally reinterpret the data in the array.\n    /// It is the responsibility of the caller to ensure that this is safe.\n    /// Only supports the `dtype` argument, the `type` argument is omitted,\n    /// to be added as needed.\n    array view(const std::string &dtype) {\n        auto &api = detail::npy_api::get();\n        auto new_view = reinterpret_steal<array>(api.PyArray_View_(\n            m_ptr, dtype::from_args(pybind11::str(dtype)).release().ptr(), nullptr));\n        if (!new_view) {\n            throw error_already_set();\n        }\n        return new_view;\n    }\n\n    /// Ensure that the argument is a NumPy array\n    /// In case of an error, nullptr is returned and the Python error is cleared.\n    static array ensure(handle h, int ExtraFlags = 0) {\n        auto result = reinterpret_steal<array>(raw_array(h.ptr(), ExtraFlags));\n        if (!result) {\n            PyErr_Clear();\n        }\n        return result;\n    }\n\nprotected:\n    template <typename, typename>\n    friend struct detail::npy_format_descriptor;\n\n    void fail_dim_check(ssize_t dim, const std::string &msg) const {\n        throw index_error(msg + \": \" + std::to_string(dim) + \" (ndim = \" + std::to_string(ndim())\n                          + ')');\n    }\n\n    template <typename... Ix>\n    ssize_t byte_offset(Ix... index) const {\n        check_dimensions(index...);\n        return detail::byte_offset_unsafe(strides(), ssize_t(index)...);\n    }\n\n    void check_writeable() const {\n        if (!writeable()) {\n            throw std::domain_error(\"array is not writeable\");\n        }\n    }\n\n    template <typename... Ix>\n    void check_dimensions(Ix... index) const {\n        check_dimensions_impl(ssize_t(0), shape(), ssize_t(index)...);\n    }\n\n    void check_dimensions_impl(ssize_t, const ssize_t *) const {}\n\n    template <typename... Ix>\n    void check_dimensions_impl(ssize_t axis, const ssize_t *shape, ssize_t i, Ix... index) const {\n        if (i >= *shape) {\n            throw index_error(std::string(\"index \") + std::to_string(i)\n                              + \" is out of bounds for axis \" + std::to_string(axis)\n                              + \" with size \" + std::to_string(*shape));\n        }\n        check_dimensions_impl(axis + 1, shape + 1, index...);\n    }\n\n    /// Create array from any object -- always returns a new reference\n    static PyObject *raw_array(PyObject *ptr, int ExtraFlags = 0) {\n        if (ptr == nullptr) {\n            set_error(PyExc_ValueError, \"cannot create a pybind11::array from a nullptr\");\n            return nullptr;\n        }\n        return detail::npy_api::get().PyArray_FromAny_(\n            ptr, nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags, nullptr);\n    }\n};\n\ntemplate <typename T, int ExtraFlags = array::forcecast>\nclass array_t : public array {\nprivate:\n    struct private_ctor {};\n    // Delegating constructor needed when both moving and accessing in the same constructor\n    array_t(private_ctor,\n            ShapeContainer &&shape,\n            StridesContainer &&strides,\n            const T *ptr,\n            handle base)\n        : array(std::move(shape), std::move(strides), ptr, base) {}\n\npublic:\n    static_assert(!detail::array_info<T>::is_array, \"Array types cannot be used with array_t\");\n\n    using value_type = T;\n\n    array_t() : array(0, static_cast<const T *>(nullptr)) {}\n    array_t(handle h, borrowed_t) : array(h, borrowed_t{}) {}\n    array_t(handle h, stolen_t) : array(h, stolen_t{}) {}\n\n    PYBIND11_DEPRECATED(\"Use array_t<T>::ensure() instead\")\n    array_t(handle h, bool is_borrowed) : array(raw_array_t(h.ptr()), stolen_t{}) {\n        if (!m_ptr) {\n            PyErr_Clear();\n        }\n        if (!is_borrowed) {\n            Py_XDECREF(h.ptr());\n        }\n    }\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    array_t(const object &o) : array(raw_array_t(o.ptr()), stolen_t{}) {\n        if (!m_ptr) {\n            throw error_already_set();\n        }\n    }\n\n    explicit array_t(const buffer_info &info, handle base = handle()) : array(info, base) {}\n\n    array_t(ShapeContainer shape,\n            StridesContainer strides,\n            const T *ptr = nullptr,\n            handle base = handle())\n        : array(std::move(shape), std::move(strides), ptr, base) {}\n\n    explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())\n        : array_t(private_ctor{},\n                  std::move(shape),\n                  (ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())\n                                              : detail::c_strides(*shape, itemsize()),\n                  ptr,\n                  base) {}\n\n    explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())\n        : array({count}, {}, ptr, base) {}\n\n    constexpr ssize_t itemsize() const { return sizeof(T); }\n\n    template <typename... Ix>\n    ssize_t index_at(Ix... index) const {\n        return offset_at(index...) / itemsize();\n    }\n\n    template <typename... Ix>\n    const T *data(Ix... index) const {\n        return static_cast<const T *>(array::data(index...));\n    }\n\n    template <typename... Ix>\n    T *mutable_data(Ix... index) {\n        return static_cast<T *>(array::mutable_data(index...));\n    }\n\n    // Reference to element at a given index\n    template <typename... Ix>\n    const T &at(Ix... index) const {\n        if ((ssize_t) sizeof...(index) != ndim()) {\n            fail_dim_check(sizeof...(index), \"index dimension mismatch\");\n        }\n        return *(static_cast<const T *>(array::data())\n                 + byte_offset(ssize_t(index)...) / itemsize());\n    }\n\n    // Mutable reference to element at a given index\n    template <typename... Ix>\n    T &mutable_at(Ix... index) {\n        if ((ssize_t) sizeof...(index) != ndim()) {\n            fail_dim_check(sizeof...(index), \"index dimension mismatch\");\n        }\n        return *(static_cast<T *>(array::mutable_data())\n                 + byte_offset(ssize_t(index)...) / itemsize());\n    }\n\n    /**\n     * Returns a proxy object that provides access to the array's data without bounds or\n     * dimensionality checking.  Will throw if the array is missing the `writeable` flag.  Use with\n     * care: the array must not be destroyed or reshaped for the duration of the returned object,\n     * and the caller must take care not to access invalid dimensions or dimension indices.\n     */\n    template <ssize_t Dims = -1>\n    detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() & {\n        return array::mutable_unchecked<T, Dims>();\n    }\n\n    /**\n     * Returns a proxy object that provides const access to the array's data without bounds or\n     * dimensionality checking.  Unlike `mutable_unchecked()`, this does not require that the\n     * underlying array have the `writable` flag.  Use with care: the array must not be destroyed\n     * or reshaped for the duration of the returned object, and the caller must take care not to\n     * access invalid dimensions or dimension indices.\n     */\n    template <ssize_t Dims = -1>\n    detail::unchecked_reference<T, Dims> unchecked() const & {\n        return array::unchecked<T, Dims>();\n    }\n\n    /// Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert\n    /// it).  In case of an error, nullptr is returned and the Python error is cleared.\n    static array_t ensure(handle h) {\n        auto result = reinterpret_steal<array_t>(raw_array_t(h.ptr()));\n        if (!result) {\n            PyErr_Clear();\n        }\n        return result;\n    }\n\n    static bool check_(handle h) {\n        const auto &api = detail::npy_api::get();\n        return api.PyArray_Check_(h.ptr())\n               && api.PyArray_EquivTypes_(detail::array_proxy(h.ptr())->descr,\n                                          dtype::of<T>().ptr())\n               && detail::check_flags(h.ptr(), ExtraFlags & (array::c_style | array::f_style));\n    }\n\nprotected:\n    /// Create array from any object -- always returns a new reference\n    static PyObject *raw_array_t(PyObject *ptr) {\n        if (ptr == nullptr) {\n            set_error(PyExc_ValueError, \"cannot create a pybind11::array_t from a nullptr\");\n            return nullptr;\n        }\n        return detail::npy_api::get().PyArray_FromAny_(ptr,\n                                                       dtype::of<T>().release().ptr(),\n                                                       0,\n                                                       0,\n                                                       detail::npy_api::NPY_ARRAY_ENSUREARRAY_\n                                                           | ExtraFlags,\n                                                       nullptr);\n    }\n};\n\ntemplate <typename T>\nstruct format_descriptor<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {\n    static std::string format() {\n        return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();\n    }\n};\n\ntemplate <size_t N>\nstruct format_descriptor<char[N]> {\n    static std::string format() { return std::to_string(N) + 's'; }\n};\ntemplate <size_t N>\nstruct format_descriptor<std::array<char, N>> {\n    static std::string format() { return std::to_string(N) + 's'; }\n};\n\ntemplate <typename T>\nstruct format_descriptor<T, detail::enable_if_t<std::is_enum<T>::value>> {\n    static std::string format() {\n        return format_descriptor<\n            typename std::remove_cv<typename std::underlying_type<T>::type>::type>::format();\n    }\n};\n\ntemplate <typename T>\nstruct format_descriptor<T, detail::enable_if_t<detail::array_info<T>::is_array>> {\n    static std::string format() {\n        using namespace detail;\n        static constexpr auto extents = const_name(\"(\") + array_info<T>::extents + const_name(\")\");\n        return extents.text + format_descriptor<remove_all_extents_t<T>>::format();\n    }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\ntemplate <typename T, int ExtraFlags>\nstruct pyobject_caster<array_t<T, ExtraFlags>> {\n    using type = array_t<T, ExtraFlags>;\n\n    bool load(handle src, bool convert) {\n        if (!convert && !type::check_(src)) {\n            return false;\n        }\n        value = type::ensure(src);\n        return static_cast<bool>(value);\n    }\n\n    static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {\n        return src.inc_ref();\n    }\n    PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);\n};\n\ntemplate <typename T>\nstruct compare_buffer_info<T, detail::enable_if_t<detail::is_pod_struct<T>::value>> {\n    static bool compare(const buffer_info &b) {\n        return npy_api::get().PyArray_EquivTypes_(dtype::of<T>().ptr(), dtype(b).ptr());\n    }\n};\n\ntemplate <typename T, typename = void>\nstruct npy_format_descriptor_name;\n\ntemplate <typename T>\nstruct npy_format_descriptor_name<T, enable_if_t<std::is_integral<T>::value>> {\n    static constexpr auto name = const_name<std::is_same<T, bool>::value>(\n        const_name(\"bool\"),\n        const_name<std::is_signed<T>::value>(\"numpy.int\", \"numpy.uint\")\n            + const_name<sizeof(T) * 8>());\n};\n\ntemplate <typename T>\nstruct npy_format_descriptor_name<T, enable_if_t<std::is_floating_point<T>::value>> {\n    static constexpr auto name = const_name < std::is_same<T, float>::value\n                                 || std::is_same<T, const float>::value\n                                 || std::is_same<T, double>::value\n                                 || std::is_same<T, const double>::value\n                                        > (const_name(\"numpy.float\") + const_name<sizeof(T) * 8>(),\n                                           const_name(\"numpy.longdouble\"));\n};\n\ntemplate <typename T>\nstruct npy_format_descriptor_name<T, enable_if_t<is_complex<T>::value>> {\n    static constexpr auto name = const_name < std::is_same<typename T::value_type, float>::value\n                                 || std::is_same<typename T::value_type, const float>::value\n                                 || std::is_same<typename T::value_type, double>::value\n                                 || std::is_same<typename T::value_type, const double>::value\n                                        > (const_name(\"numpy.complex\")\n                                               + const_name<sizeof(typename T::value_type) * 16>(),\n                                           const_name(\"numpy.longcomplex\"));\n};\n\ntemplate <typename T>\nstruct npy_format_descriptor<\n    T,\n    enable_if_t<satisfies_any_of<T, std::is_arithmetic, is_complex>::value>>\n    : npy_format_descriptor_name<T> {\nprivate:\n    // NB: the order here must match the one in common.h\n    constexpr static const int values[15] = {npy_api::NPY_BOOL_,\n                                             npy_api::NPY_BYTE_,\n                                             npy_api::NPY_UBYTE_,\n                                             npy_api::NPY_INT16_,\n                                             npy_api::NPY_UINT16_,\n                                             npy_api::NPY_INT32_,\n                                             npy_api::NPY_UINT32_,\n                                             npy_api::NPY_INT64_,\n                                             npy_api::NPY_UINT64_,\n                                             npy_api::NPY_FLOAT_,\n                                             npy_api::NPY_DOUBLE_,\n                                             npy_api::NPY_LONGDOUBLE_,\n                                             npy_api::NPY_CFLOAT_,\n                                             npy_api::NPY_CDOUBLE_,\n                                             npy_api::NPY_CLONGDOUBLE_};\n\npublic:\n    static constexpr int value = values[detail::is_fmt_numeric<T>::index];\n\n    static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); }\n};\n\ntemplate <typename T>\nstruct npy_format_descriptor<T, enable_if_t<is_same_ignoring_cvref<T, PyObject *>::value>> {\n    static constexpr auto name = const_name(\"object\");\n\n    static constexpr int value = npy_api::NPY_OBJECT_;\n\n    static pybind11::dtype dtype() { return pybind11::dtype(/*typenum*/ value); }\n};\n\n#define PYBIND11_DECL_CHAR_FMT                                                                    \\\n    static constexpr auto name = const_name(\"S\") + const_name<N>();                               \\\n    static pybind11::dtype dtype() {                                                              \\\n        return pybind11::dtype(std::string(\"S\") + std::to_string(N));                             \\\n    }\ntemplate <size_t N>\nstruct npy_format_descriptor<char[N]> {\n    PYBIND11_DECL_CHAR_FMT\n};\ntemplate <size_t N>\nstruct npy_format_descriptor<std::array<char, N>> {\n    PYBIND11_DECL_CHAR_FMT\n};\n#undef PYBIND11_DECL_CHAR_FMT\n\ntemplate <typename T>\nstruct npy_format_descriptor<T, enable_if_t<array_info<T>::is_array>> {\nprivate:\n    using base_descr = npy_format_descriptor<typename array_info<T>::type>;\n\npublic:\n    static_assert(!array_info<T>::is_empty, \"Zero-sized arrays are not supported\");\n\n    static constexpr auto name\n        = const_name(\"(\") + array_info<T>::extents + const_name(\")\") + base_descr::name;\n    static pybind11::dtype dtype() {\n        list shape;\n        array_info<T>::append_extents(shape);\n        return pybind11::dtype::from_args(\n            pybind11::make_tuple(base_descr::dtype(), std::move(shape)));\n    }\n};\n\ntemplate <typename T>\nstruct npy_format_descriptor<T, enable_if_t<std::is_enum<T>::value>> {\nprivate:\n    using base_descr = npy_format_descriptor<typename std::underlying_type<T>::type>;\n\npublic:\n    static constexpr auto name = base_descr::name;\n    static pybind11::dtype dtype() { return base_descr::dtype(); }\n};\n\nstruct field_descriptor {\n    const char *name;\n    ssize_t offset;\n    ssize_t size;\n    std::string format;\n    dtype descr;\n};\n\nPYBIND11_NOINLINE void register_structured_dtype(any_container<field_descriptor> fields,\n                                                 const std::type_info &tinfo,\n                                                 ssize_t itemsize,\n                                                 bool (*direct_converter)(PyObject *, void *&)) {\n\n    auto &numpy_internals = get_numpy_internals();\n    if (numpy_internals.get_type_info(tinfo, false)) {\n        pybind11_fail(\"NumPy: dtype is already registered\");\n    }\n\n    // Use ordered fields because order matters as of NumPy 1.14:\n    // https://docs.scipy.org/doc/numpy/release.html#multiple-field-indexing-assignment-of-structured-arrays\n    std::vector<field_descriptor> ordered_fields(std::move(fields));\n    std::sort(\n        ordered_fields.begin(),\n        ordered_fields.end(),\n        [](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });\n\n    list names, formats, offsets;\n    for (auto &field : ordered_fields) {\n        if (!field.descr) {\n            pybind11_fail(std::string(\"NumPy: unsupported field dtype: `\") + field.name + \"` @ \"\n                          + tinfo.name());\n        }\n        names.append(pybind11::str(field.name));\n        formats.append(field.descr);\n        offsets.append(pybind11::int_(field.offset));\n    }\n    auto *dtype_ptr\n        = pybind11::dtype(std::move(names), std::move(formats), std::move(offsets), itemsize)\n              .release()\n              .ptr();\n\n    // There is an existing bug in NumPy (as of v1.11): trailing bytes are\n    // not encoded explicitly into the format string. This will supposedly\n    // get fixed in v1.12; for further details, see these:\n    // - https://github.com/numpy/numpy/issues/7797\n    // - https://github.com/numpy/numpy/pull/7798\n    // Because of this, we won't use numpy's logic to generate buffer format\n    // strings and will just do it ourselves.\n    ssize_t offset = 0;\n    std::ostringstream oss;\n    // mark the structure as unaligned with '^', because numpy and C++ don't\n    // always agree about alignment (particularly for complex), and we're\n    // explicitly listing all our padding. This depends on none of the fields\n    // overriding the endianness. Putting the ^ in front of individual fields\n    // isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049\n    oss << \"^T{\";\n    for (auto &field : ordered_fields) {\n        if (field.offset > offset) {\n            oss << (field.offset - offset) << 'x';\n        }\n        oss << field.format << ':' << field.name << ':';\n        offset = field.offset + field.size;\n    }\n    if (itemsize > offset) {\n        oss << (itemsize - offset) << 'x';\n    }\n    oss << '}';\n    auto format_str = oss.str();\n\n    // Smoke test: verify that NumPy properly parses our buffer format string\n    auto &api = npy_api::get();\n    auto arr = array(buffer_info(nullptr, itemsize, format_str, 1));\n    if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) {\n        pybind11_fail(\"NumPy: invalid buffer descriptor!\");\n    }\n\n    auto tindex = std::type_index(tinfo);\n    numpy_internals.registered_dtypes[tindex] = {dtype_ptr, std::move(format_str)};\n    get_internals().direct_conversions[tindex].push_back(direct_converter);\n}\n\ntemplate <typename T, typename SFINAE>\nstruct npy_format_descriptor {\n    static_assert(is_pod_struct<T>::value,\n                  \"Attempt to use a non-POD or unimplemented POD type as a numpy dtype\");\n\n    static constexpr auto name = make_caster<T>::name;\n\n    static pybind11::dtype dtype() { return reinterpret_borrow<pybind11::dtype>(dtype_ptr()); }\n\n    static std::string format() {\n        static auto format_str = get_numpy_internals().get_type_info<T>(true)->format_str;\n        return format_str;\n    }\n\n    static void register_dtype(any_container<field_descriptor> fields) {\n        register_structured_dtype(std::move(fields),\n                                  typeid(typename std::remove_cv<T>::type),\n                                  sizeof(T),\n                                  &direct_converter);\n    }\n\nprivate:\n    static PyObject *dtype_ptr() {\n        static PyObject *ptr = get_numpy_internals().get_type_info<T>(true)->dtype_ptr;\n        return ptr;\n    }\n\n    static bool direct_converter(PyObject *obj, void *&value) {\n        auto &api = npy_api::get();\n        if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) {\n            return false;\n        }\n        if (auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {\n            if (api.PyArray_EquivTypes_(dtype_ptr(), descr.ptr())) {\n                value = ((PyVoidScalarObject_Proxy *) obj)->obval;\n                return true;\n            }\n        }\n        return false;\n    }\n};\n\n#ifdef __CLION_IDE__ // replace heavy macro with dummy code for the IDE (doesn't affect code)\n#    define PYBIND11_NUMPY_DTYPE(Type, ...) ((void) 0)\n#    define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void) 0)\n#else\n\n#    define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name)                                          \\\n        ::pybind11::detail::field_descriptor {                                                    \\\n            Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)),                  \\\n                ::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(),       \\\n                ::pybind11::detail::npy_format_descriptor<                                        \\\n                    decltype(std::declval<T>().Field)>::dtype()                                   \\\n        }\n\n// Extract name, offset and format descriptor for a struct field\n#    define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)\n\n// The main idea of this macro is borrowed from https://github.com/swansontec/map-macro\n// (C) William Swanson, Paul Fultz\n#    define PYBIND11_EVAL0(...) __VA_ARGS__\n#    define PYBIND11_EVAL1(...) PYBIND11_EVAL0(PYBIND11_EVAL0(PYBIND11_EVAL0(__VA_ARGS__)))\n#    define PYBIND11_EVAL2(...) PYBIND11_EVAL1(PYBIND11_EVAL1(PYBIND11_EVAL1(__VA_ARGS__)))\n#    define PYBIND11_EVAL3(...) PYBIND11_EVAL2(PYBIND11_EVAL2(PYBIND11_EVAL2(__VA_ARGS__)))\n#    define PYBIND11_EVAL4(...) PYBIND11_EVAL3(PYBIND11_EVAL3(PYBIND11_EVAL3(__VA_ARGS__)))\n#    define PYBIND11_EVAL(...) PYBIND11_EVAL4(PYBIND11_EVAL4(PYBIND11_EVAL4(__VA_ARGS__)))\n#    define PYBIND11_MAP_END(...)\n#    define PYBIND11_MAP_OUT\n#    define PYBIND11_MAP_COMMA ,\n#    define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END\n#    define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT\n#    define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0(test, next, 0)\n#    define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1(PYBIND11_MAP_GET_END test, next)\n#    if defined(_MSC_VER)                                                                         \\\n        && !defined(__clang__) // MSVC is not as eager to expand macros, hence this workaround\n#        define PYBIND11_MAP_LIST_NEXT1(test, next)                                               \\\n            PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))\n#    else\n#        define PYBIND11_MAP_LIST_NEXT1(test, next)                                               \\\n            PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)\n#    endif\n#    define PYBIND11_MAP_LIST_NEXT(test, next)                                                    \\\n        PYBIND11_MAP_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)\n#    define PYBIND11_MAP_LIST0(f, t, x, peek, ...)                                                \\\n        f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST1)(f, t, peek, __VA_ARGS__)\n#    define PYBIND11_MAP_LIST1(f, t, x, peek, ...)                                                \\\n        f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST0)(f, t, peek, __VA_ARGS__)\n// PYBIND11_MAP_LIST(f, t, a1, a2, ...) expands to f(t, a1), f(t, a2), ...\n#    define PYBIND11_MAP_LIST(f, t, ...)                                                          \\\n        PYBIND11_EVAL(PYBIND11_MAP_LIST1(f, t, __VA_ARGS__, (), 0))\n\n#    define PYBIND11_NUMPY_DTYPE(Type, ...)                                                       \\\n        ::pybind11::detail::npy_format_descriptor<Type>::register_dtype(                          \\\n            ::std::vector<::pybind11::detail::field_descriptor>{                                  \\\n                PYBIND11_MAP_LIST(PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})\n\n#    if defined(_MSC_VER) && !defined(__clang__)\n#        define PYBIND11_MAP2_LIST_NEXT1(test, next)                                              \\\n            PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))\n#    else\n#        define PYBIND11_MAP2_LIST_NEXT1(test, next)                                              \\\n            PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)\n#    endif\n#    define PYBIND11_MAP2_LIST_NEXT(test, next)                                                   \\\n        PYBIND11_MAP2_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)\n#    define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...)                                          \\\n        f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST1)(f, t, peek, __VA_ARGS__)\n#    define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...)                                          \\\n        f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST0)(f, t, peek, __VA_ARGS__)\n// PYBIND11_MAP2_LIST(f, t, a1, a2, ...) expands to f(t, a1, a2), f(t, a3, a4), ...\n#    define PYBIND11_MAP2_LIST(f, t, ...)                                                         \\\n        PYBIND11_EVAL(PYBIND11_MAP2_LIST1(f, t, __VA_ARGS__, (), 0))\n\n#    define PYBIND11_NUMPY_DTYPE_EX(Type, ...)                                                    \\\n        ::pybind11::detail::npy_format_descriptor<Type>::register_dtype(                          \\\n            ::std::vector<::pybind11::detail::field_descriptor>{                                  \\\n                PYBIND11_MAP2_LIST(PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})\n\n#endif // __CLION_IDE__\n\nclass common_iterator {\npublic:\n    using container_type = std::vector<ssize_t>;\n    using value_type = container_type::value_type;\n    using size_type = container_type::size_type;\n\n    common_iterator() : m_strides() {}\n\n    common_iterator(void *ptr, const container_type &strides, const container_type &shape)\n        : p_ptr(reinterpret_cast<char *>(ptr)), m_strides(strides.size()) {\n        m_strides.back() = static_cast<value_type>(strides.back());\n        for (size_type i = m_strides.size() - 1; i != 0; --i) {\n            size_type j = i - 1;\n            auto s = static_cast<value_type>(shape[i]);\n            m_strides[j] = strides[j] + m_strides[i] - strides[i] * s;\n        }\n    }\n\n    void increment(size_type dim) { p_ptr += m_strides[dim]; }\n\n    void *data() const { return p_ptr; }\n\nprivate:\n    char *p_ptr{nullptr};\n    container_type m_strides;\n};\n\ntemplate <size_t N>\nclass multi_array_iterator {\npublic:\n    using container_type = std::vector<ssize_t>;\n\n    multi_array_iterator(const std::array<buffer_info, N> &buffers, const container_type &shape)\n        : m_shape(shape.size()), m_index(shape.size(), 0), m_common_iterator() {\n\n        // Manual copy to avoid conversion warning if using std::copy\n        for (size_t i = 0; i < shape.size(); ++i) {\n            m_shape[i] = shape[i];\n        }\n\n        container_type strides(shape.size());\n        for (size_t i = 0; i < N; ++i) {\n            init_common_iterator(buffers[i], shape, m_common_iterator[i], strides);\n        }\n    }\n\n    multi_array_iterator &operator++() {\n        for (size_t j = m_index.size(); j != 0; --j) {\n            size_t i = j - 1;\n            if (++m_index[i] != m_shape[i]) {\n                increment_common_iterator(i);\n                break;\n            }\n            m_index[i] = 0;\n        }\n        return *this;\n    }\n\n    template <size_t K, class T = void>\n    T *data() const {\n        return reinterpret_cast<T *>(m_common_iterator[K].data());\n    }\n\nprivate:\n    using common_iter = common_iterator;\n\n    void init_common_iterator(const buffer_info &buffer,\n                              const container_type &shape,\n                              common_iter &iterator,\n                              container_type &strides) {\n        auto buffer_shape_iter = buffer.shape.rbegin();\n        auto buffer_strides_iter = buffer.strides.rbegin();\n        auto shape_iter = shape.rbegin();\n        auto strides_iter = strides.rbegin();\n\n        while (buffer_shape_iter != buffer.shape.rend()) {\n            if (*shape_iter == *buffer_shape_iter) {\n                *strides_iter = *buffer_strides_iter;\n            } else {\n                *strides_iter = 0;\n            }\n\n            ++buffer_shape_iter;\n            ++buffer_strides_iter;\n            ++shape_iter;\n            ++strides_iter;\n        }\n\n        std::fill(strides_iter, strides.rend(), 0);\n        iterator = common_iter(buffer.ptr, strides, shape);\n    }\n\n    void increment_common_iterator(size_t dim) {\n        for (auto &iter : m_common_iterator) {\n            iter.increment(dim);\n        }\n    }\n\n    container_type m_shape;\n    container_type m_index;\n    std::array<common_iter, N> m_common_iterator;\n};\n\nenum class broadcast_trivial { non_trivial, c_trivial, f_trivial };\n\n// Populates the shape and number of dimensions for the set of buffers.  Returns a\n// broadcast_trivial enum value indicating whether the broadcast is \"trivial\"--that is, has each\n// buffer being either a singleton or a full-size, C-contiguous (`c_trivial`) or Fortran-contiguous\n// (`f_trivial`) storage buffer; returns `non_trivial` otherwise.\ntemplate <size_t N>\nbroadcast_trivial\nbroadcast(const std::array<buffer_info, N> &buffers, ssize_t &ndim, std::vector<ssize_t> &shape) {\n    ndim = std::accumulate(\n        buffers.begin(), buffers.end(), ssize_t(0), [](ssize_t res, const buffer_info &buf) {\n            return std::max(res, buf.ndim);\n        });\n\n    shape.clear();\n    shape.resize((size_t) ndim, 1);\n\n    // Figure out the output size, and make sure all input arrays conform (i.e. are either size 1\n    // or the full size).\n    for (size_t i = 0; i < N; ++i) {\n        auto res_iter = shape.rbegin();\n        auto end = buffers[i].shape.rend();\n        for (auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end;\n             ++shape_iter, ++res_iter) {\n            const auto &dim_size_in = *shape_iter;\n            auto &dim_size_out = *res_iter;\n\n            // Each input dimension can either be 1 or `n`, but `n` values must match across\n            // buffers\n            if (dim_size_out == 1) {\n                dim_size_out = dim_size_in;\n            } else if (dim_size_in != 1 && dim_size_in != dim_size_out) {\n                pybind11_fail(\"pybind11::vectorize: incompatible size/dimension of inputs!\");\n            }\n        }\n    }\n\n    bool trivial_broadcast_c = true;\n    bool trivial_broadcast_f = true;\n    for (size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {\n        if (buffers[i].size == 1) {\n            continue;\n        }\n\n        // Require the same number of dimensions:\n        if (buffers[i].ndim != ndim) {\n            return broadcast_trivial::non_trivial;\n        }\n\n        // Require all dimensions be full-size:\n        if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) {\n            return broadcast_trivial::non_trivial;\n        }\n\n        // Check for C contiguity (but only if previous inputs were also C contiguous)\n        if (trivial_broadcast_c) {\n            ssize_t expect_stride = buffers[i].itemsize;\n            auto end = buffers[i].shape.crend();\n            for (auto shape_iter = buffers[i].shape.crbegin(),\n                      stride_iter = buffers[i].strides.crbegin();\n                 trivial_broadcast_c && shape_iter != end;\n                 ++shape_iter, ++stride_iter) {\n                if (expect_stride == *stride_iter) {\n                    expect_stride *= *shape_iter;\n                } else {\n                    trivial_broadcast_c = false;\n                }\n            }\n        }\n\n        // Check for Fortran contiguity (if previous inputs were also F contiguous)\n        if (trivial_broadcast_f) {\n            ssize_t expect_stride = buffers[i].itemsize;\n            auto end = buffers[i].shape.cend();\n            for (auto shape_iter = buffers[i].shape.cbegin(),\n                      stride_iter = buffers[i].strides.cbegin();\n                 trivial_broadcast_f && shape_iter != end;\n                 ++shape_iter, ++stride_iter) {\n                if (expect_stride == *stride_iter) {\n                    expect_stride *= *shape_iter;\n                } else {\n                    trivial_broadcast_f = false;\n                }\n            }\n        }\n    }\n\n    return trivial_broadcast_c   ? broadcast_trivial::c_trivial\n           : trivial_broadcast_f ? broadcast_trivial::f_trivial\n                                 : broadcast_trivial::non_trivial;\n}\n\ntemplate <typename T>\nstruct vectorize_arg {\n    static_assert(!std::is_rvalue_reference<T>::value,\n                  \"Functions with rvalue reference arguments cannot be vectorized\");\n    // The wrapped function gets called with this type:\n    using call_type = remove_reference_t<T>;\n    // Is this a vectorized argument?\n    static constexpr bool vectorize\n        = satisfies_any_of<call_type, std::is_arithmetic, is_complex, is_pod>::value\n          && satisfies_none_of<call_type,\n                               std::is_pointer,\n                               std::is_array,\n                               is_std_array,\n                               std::is_enum>::value\n          && (!std::is_reference<T>::value\n              || (std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));\n    // Accept this type: an array for vectorized types, otherwise the type as-is:\n    using type = conditional_t<vectorize, array_t<remove_cv_t<call_type>, array::forcecast>, T>;\n};\n\n// py::vectorize when a return type is present\ntemplate <typename Func, typename Return, typename... Args>\nstruct vectorize_returned_array {\n    using Type = array_t<Return>;\n\n    static Type create(broadcast_trivial trivial, const std::vector<ssize_t> &shape) {\n        if (trivial == broadcast_trivial::f_trivial) {\n            return array_t<Return, array::f_style>(shape);\n        }\n        return array_t<Return>(shape);\n    }\n\n    static Return *mutable_data(Type &array) { return array.mutable_data(); }\n\n    static Return call(Func &f, Args &...args) { return f(args...); }\n\n    static void call(Return *out, size_t i, Func &f, Args &...args) { out[i] = f(args...); }\n};\n\n// py::vectorize when a return type is not present\ntemplate <typename Func, typename... Args>\nstruct vectorize_returned_array<Func, void, Args...> {\n    using Type = none;\n\n    static Type create(broadcast_trivial, const std::vector<ssize_t> &) { return none(); }\n\n    static void *mutable_data(Type &) { return nullptr; }\n\n    static detail::void_type call(Func &f, Args &...args) {\n        f(args...);\n        return {};\n    }\n\n    static void call(void *, size_t, Func &f, Args &...args) { f(args...); }\n};\n\ntemplate <typename Func, typename Return, typename... Args>\nstruct vectorize_helper {\n\n// NVCC for some reason breaks if NVectorized is private\n#ifdef __CUDACC__\npublic:\n#else\nprivate:\n#endif\n\n    static constexpr size_t N = sizeof...(Args);\n    static constexpr size_t NVectorized = constexpr_sum(vectorize_arg<Args>::vectorize...);\n    static_assert(\n        NVectorized >= 1,\n        \"pybind11::vectorize(...) requires a function with at least one vectorizable argument\");\n\npublic:\n    template <typename T,\n              // SFINAE to prevent shadowing the copy constructor.\n              typename = detail::enable_if_t<\n                  !std::is_same<vectorize_helper, typename std::decay<T>::type>::value>>\n    explicit vectorize_helper(T &&f) : f(std::forward<T>(f)) {}\n\n    object operator()(typename vectorize_arg<Args>::type... args) {\n        return run(args...,\n                   make_index_sequence<N>(),\n                   select_indices<vectorize_arg<Args>::vectorize...>(),\n                   make_index_sequence<NVectorized>());\n    }\n\nprivate:\n    remove_reference_t<Func> f;\n\n    // Internal compiler error in MSVC 19.16.27025.1 (Visual Studio 2017 15.9.4), when compiling\n    // with \"/permissive-\" flag when arg_call_types is manually inlined.\n    using arg_call_types = std::tuple<typename vectorize_arg<Args>::call_type...>;\n    template <size_t Index>\n    using param_n_t = typename std::tuple_element<Index, arg_call_types>::type;\n\n    using returned_array = vectorize_returned_array<Func, Return, Args...>;\n\n    // Runs a vectorized function given arguments tuple and three index sequences:\n    //     - Index is the full set of 0 ... (N-1) argument indices;\n    //     - VIndex is the subset of argument indices with vectorized parameters, letting us access\n    //       vectorized arguments (anything not in this sequence is passed through)\n    //     - BIndex is a incremental sequence (beginning at 0) of the same size as VIndex, so that\n    //       we can store vectorized buffer_infos in an array (argument VIndex has its buffer at\n    //       index BIndex in the array).\n    template <size_t... Index, size_t... VIndex, size_t... BIndex>\n    object run(typename vectorize_arg<Args>::type &...args,\n               index_sequence<Index...> i_seq,\n               index_sequence<VIndex...> vi_seq,\n               index_sequence<BIndex...> bi_seq) {\n\n        // Pointers to values the function was called with; the vectorized ones set here will start\n        // out as array_t<T> pointers, but they will be changed them to T pointers before we make\n        // call the wrapped function.  Non-vectorized pointers are left as-is.\n        std::array<void *, N> params{{&args...}};\n\n        // The array of `buffer_info`s of vectorized arguments:\n        std::array<buffer_info, NVectorized> buffers{\n            {reinterpret_cast<array *>(params[VIndex])->request()...}};\n\n        /* Determine dimensions parameters of output array */\n        ssize_t nd = 0;\n        std::vector<ssize_t> shape(0);\n        auto trivial = broadcast(buffers, nd, shape);\n        auto ndim = (size_t) nd;\n\n        size_t size\n            = std::accumulate(shape.begin(), shape.end(), (size_t) 1, std::multiplies<size_t>());\n\n        // If all arguments are 0-dimension arrays (i.e. single values) return a plain value (i.e.\n        // not wrapped in an array).\n        if (size == 1 && ndim == 0) {\n            PYBIND11_EXPAND_SIDE_EFFECTS(params[VIndex] = buffers[BIndex].ptr);\n            return cast(\n                returned_array::call(f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...));\n        }\n\n        auto result = returned_array::create(trivial, shape);\n\n        PYBIND11_WARNING_PUSH\n#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING\n        PYBIND11_WARNING_DISABLE_CLANG(\"-Wreturn-std-move\")\n#endif\n\n        if (size == 0) {\n            return result;\n        }\n\n        /* Call the function */\n        auto *mutable_data = returned_array::mutable_data(result);\n        if (trivial == broadcast_trivial::non_trivial) {\n            apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq);\n        } else {\n            apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);\n        }\n\n        return result;\n        PYBIND11_WARNING_POP\n    }\n\n    template <size_t... Index, size_t... VIndex, size_t... BIndex>\n    void apply_trivial(std::array<buffer_info, NVectorized> &buffers,\n                       std::array<void *, N> &params,\n                       Return *out,\n                       size_t size,\n                       index_sequence<Index...>,\n                       index_sequence<VIndex...>,\n                       index_sequence<BIndex...>) {\n\n        // Initialize an array of mutable byte references and sizes with references set to the\n        // appropriate pointer in `params`; as we iterate, we'll increment each pointer by its size\n        // (except for singletons, which get an increment of 0).\n        std::array<std::pair<unsigned char *&, const size_t>, NVectorized> vecparams{\n            {std::pair<unsigned char *&, const size_t>(\n                reinterpret_cast<unsigned char *&>(params[VIndex] = buffers[BIndex].ptr),\n                buffers[BIndex].size == 1 ? 0 : sizeof(param_n_t<VIndex>))...}};\n\n        for (size_t i = 0; i < size; ++i) {\n            returned_array::call(\n                out, i, f, *reinterpret_cast<param_n_t<Index> *>(params[Index])...);\n            for (auto &x : vecparams) {\n                x.first += x.second;\n            }\n        }\n    }\n\n    template <size_t... Index, size_t... VIndex, size_t... BIndex>\n    void apply_broadcast(std::array<buffer_info, NVectorized> &buffers,\n                         std::array<void *, N> &params,\n                         Return *out,\n                         size_t size,\n                         const std::vector<ssize_t> &output_shape,\n                         index_sequence<Index...>,\n                         index_sequence<VIndex...>,\n                         index_sequence<BIndex...>) {\n\n        multi_array_iterator<NVectorized> input_iter(buffers, output_shape);\n\n        for (size_t i = 0; i < size; ++i, ++input_iter) {\n            PYBIND11_EXPAND_SIDE_EFFECTS((params[VIndex] = input_iter.template data<BIndex>()));\n            returned_array::call(\n                out, i, f, *reinterpret_cast<param_n_t<Index> *>(std::get<Index>(params))...);\n        }\n    }\n};\n\ntemplate <typename Func, typename Return, typename... Args>\nvectorize_helper<Func, Return, Args...> vectorize_extractor(const Func &f, Return (*)(Args...)) {\n    return detail::vectorize_helper<Func, Return, Args...>(f);\n}\n\ntemplate <typename T, int Flags>\nstruct handle_type_name<array_t<T, Flags>> {\n    static constexpr auto name\n        = const_name(\"numpy.ndarray[\") + npy_format_descriptor<T>::name + const_name(\"]\");\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\n// Vanilla pointer vectorizer:\ntemplate <typename Return, typename... Args>\ndetail::vectorize_helper<Return (*)(Args...), Return, Args...> vectorize(Return (*f)(Args...)) {\n    return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);\n}\n\n// lambda vectorizer:\ntemplate <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value, int> = 0>\nauto vectorize(Func &&f)\n    -> decltype(detail::vectorize_extractor(std::forward<Func>(f),\n                                            (detail::function_signature_t<Func> *) nullptr)) {\n    return detail::vectorize_extractor(std::forward<Func>(f),\n                                       (detail::function_signature_t<Func> *) nullptr);\n}\n\n// Vectorize a class method (non-const):\ntemplate <typename Return,\n          typename Class,\n          typename... Args,\n          typename Helper = detail::vectorize_helper<\n              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())),\n              Return,\n              Class *,\n              Args...>>\nHelper vectorize(Return (Class::*f)(Args...)) {\n    return Helper(std::mem_fn(f));\n}\n\n// Vectorize a class method (const):\ntemplate <typename Return,\n          typename Class,\n          typename... Args,\n          typename Helper = detail::vectorize_helper<\n              decltype(std::mem_fn(std::declval<Return (Class::*)(Args...) const>())),\n              Return,\n              const Class *,\n              Args...>>\nHelper vectorize(Return (Class::*f)(Args...) const) {\n    return Helper(std::mem_fn(f));\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/operators.h",
    "content": "/*\n    pybind11/operator.h: Metatemplates for operator overloading\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// Enumeration with all supported operator types\nenum op_id : int {\n    op_add,\n    op_sub,\n    op_mul,\n    op_div,\n    op_mod,\n    op_divmod,\n    op_pow,\n    op_lshift,\n    op_rshift,\n    op_and,\n    op_xor,\n    op_or,\n    op_neg,\n    op_pos,\n    op_abs,\n    op_invert,\n    op_int,\n    op_long,\n    op_float,\n    op_str,\n    op_cmp,\n    op_gt,\n    op_ge,\n    op_lt,\n    op_le,\n    op_eq,\n    op_ne,\n    op_iadd,\n    op_isub,\n    op_imul,\n    op_idiv,\n    op_imod,\n    op_ilshift,\n    op_irshift,\n    op_iand,\n    op_ixor,\n    op_ior,\n    op_complex,\n    op_bool,\n    op_nonzero,\n    op_repr,\n    op_truediv,\n    op_itruediv,\n    op_hash\n};\n\nenum op_type : int {\n    op_l, /* base type on left */\n    op_r, /* base type on right */\n    op_u  /* unary operator */\n};\n\nstruct self_t {};\nstatic const self_t self = self_t();\n\n/// Type for an unused type slot\nstruct undefined_t {};\n\n/// Don't warn about an unused variable\ninline self_t __self() { return self; }\n\n/// base template of operator implementations\ntemplate <op_id, op_type, typename B, typename L, typename R>\nstruct op_impl {};\n\n/// Operator implementation generator\ntemplate <op_id id, op_type ot, typename L, typename R>\nstruct op_ {\n    static constexpr bool op_enable_if_hook = true;\n    template <typename Class, typename... Extra>\n    void execute(Class &cl, const Extra &...extra) const {\n        using Base = typename Class::type;\n        using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;\n        using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;\n        using op = op_impl<id, ot, Base, L_type, R_type>;\n        cl.def(op::name(), &op::execute, is_operator(), extra...);\n    }\n    template <typename Class, typename... Extra>\n    void execute_cast(Class &cl, const Extra &...extra) const {\n        using Base = typename Class::type;\n        using L_type = conditional_t<std::is_same<L, self_t>::value, Base, L>;\n        using R_type = conditional_t<std::is_same<R, self_t>::value, Base, R>;\n        using op = op_impl<id, ot, Base, L_type, R_type>;\n        cl.def(op::name(), &op::execute_cast, is_operator(), extra...);\n    }\n};\n\n#define PYBIND11_BINARY_OPERATOR(id, rid, op, expr)                                               \\\n    template <typename B, typename L, typename R>                                                 \\\n    struct op_impl<op_##id, op_l, B, L, R> {                                                      \\\n        static char const *name() { return \"__\" #id \"__\"; }                                       \\\n        static auto execute(const L &l, const R &r) -> decltype(expr) { return (expr); }          \\\n        static B execute_cast(const L &l, const R &r) { return B(expr); }                         \\\n    };                                                                                            \\\n    template <typename B, typename L, typename R>                                                 \\\n    struct op_impl<op_##id, op_r, B, L, R> {                                                      \\\n        static char const *name() { return \"__\" #rid \"__\"; }                                      \\\n        static auto execute(const R &r, const L &l) -> decltype(expr) { return (expr); }          \\\n        static B execute_cast(const R &r, const L &l) { return B(expr); }                         \\\n    };                                                                                            \\\n    inline op_<op_##id, op_l, self_t, self_t> op(const self_t &, const self_t &) {                \\\n        return op_<op_##id, op_l, self_t, self_t>();                                              \\\n    }                                                                                             \\\n    template <typename T>                                                                         \\\n    op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) {                                 \\\n        return op_<op_##id, op_l, self_t, T>();                                                   \\\n    }                                                                                             \\\n    template <typename T>                                                                         \\\n    op_<op_##id, op_r, T, self_t> op(const T &, const self_t &) {                                 \\\n        return op_<op_##id, op_r, T, self_t>();                                                   \\\n    }\n\n#define PYBIND11_INPLACE_OPERATOR(id, op, expr)                                                   \\\n    template <typename B, typename L, typename R>                                                 \\\n    struct op_impl<op_##id, op_l, B, L, R> {                                                      \\\n        static char const *name() { return \"__\" #id \"__\"; }                                       \\\n        static auto execute(L &l, const R &r) -> decltype(expr) { return expr; }                  \\\n        static B execute_cast(L &l, const R &r) { return B(expr); }                               \\\n    };                                                                                            \\\n    template <typename T>                                                                         \\\n    op_<op_##id, op_l, self_t, T> op(const self_t &, const T &) {                                 \\\n        return op_<op_##id, op_l, self_t, T>();                                                   \\\n    }\n\n#define PYBIND11_UNARY_OPERATOR(id, op, expr)                                                     \\\n    template <typename B, typename L>                                                             \\\n    struct op_impl<op_##id, op_u, B, L, undefined_t> {                                            \\\n        static char const *name() { return \"__\" #id \"__\"; }                                       \\\n        static auto execute(const L &l) -> decltype(expr) { return expr; }                        \\\n        static B execute_cast(const L &l) { return B(expr); }                                     \\\n    };                                                                                            \\\n    inline op_<op_##id, op_u, self_t, undefined_t> op(const self_t &) {                           \\\n        return op_<op_##id, op_u, self_t, undefined_t>();                                         \\\n    }\n\nPYBIND11_BINARY_OPERATOR(sub, rsub, operator-, l - r)\nPYBIND11_BINARY_OPERATOR(add, radd, operator+, l + r)\nPYBIND11_BINARY_OPERATOR(mul, rmul, operator*, l *r)\nPYBIND11_BINARY_OPERATOR(truediv, rtruediv, operator/, l / r)\nPYBIND11_BINARY_OPERATOR(mod, rmod, operator%, l % r)\nPYBIND11_BINARY_OPERATOR(lshift, rlshift, operator<<, l << r)\nPYBIND11_BINARY_OPERATOR(rshift, rrshift, operator>>, l >> r)\nPYBIND11_BINARY_OPERATOR(and, rand, operator&, l &r)\nPYBIND11_BINARY_OPERATOR(xor, rxor, operator^, l ^ r)\nPYBIND11_BINARY_OPERATOR(eq, eq, operator==, l == r)\nPYBIND11_BINARY_OPERATOR(ne, ne, operator!=, l != r)\nPYBIND11_BINARY_OPERATOR(or, ror, operator|, l | r)\nPYBIND11_BINARY_OPERATOR(gt, lt, operator>, l > r)\nPYBIND11_BINARY_OPERATOR(ge, le, operator>=, l >= r)\nPYBIND11_BINARY_OPERATOR(lt, gt, operator<, l < r)\nPYBIND11_BINARY_OPERATOR(le, ge, operator<=, l <= r)\n// PYBIND11_BINARY_OPERATOR(pow,       rpow,         pow,          std::pow(l,  r))\nPYBIND11_INPLACE_OPERATOR(iadd, operator+=, l += r)\nPYBIND11_INPLACE_OPERATOR(isub, operator-=, l -= r)\nPYBIND11_INPLACE_OPERATOR(imul, operator*=, l *= r)\nPYBIND11_INPLACE_OPERATOR(itruediv, operator/=, l /= r)\nPYBIND11_INPLACE_OPERATOR(imod, operator%=, l %= r)\nPYBIND11_INPLACE_OPERATOR(ilshift, operator<<=, l <<= r)\nPYBIND11_INPLACE_OPERATOR(irshift, operator>>=, l >>= r)\nPYBIND11_INPLACE_OPERATOR(iand, operator&=, l &= r)\nPYBIND11_INPLACE_OPERATOR(ixor, operator^=, l ^= r)\nPYBIND11_INPLACE_OPERATOR(ior, operator|=, l |= r)\nPYBIND11_UNARY_OPERATOR(neg, operator-, -l)\nPYBIND11_UNARY_OPERATOR(pos, operator+, +l)\n// WARNING: This usage of `abs` should only be done for existing STL overloads.\n// Adding overloads directly in to the `std::` namespace is advised against:\n// https://en.cppreference.com/w/cpp/language/extending_std\nPYBIND11_UNARY_OPERATOR(abs, abs, std::abs(l))\nPYBIND11_UNARY_OPERATOR(hash, hash, std::hash<L>()(l))\nPYBIND11_UNARY_OPERATOR(invert, operator~, (~l))\nPYBIND11_UNARY_OPERATOR(bool, operator!, !!l)\nPYBIND11_UNARY_OPERATOR(int, int_, (int) l)\nPYBIND11_UNARY_OPERATOR(float, float_, (double) l)\n\n#undef PYBIND11_BINARY_OPERATOR\n#undef PYBIND11_INPLACE_OPERATOR\n#undef PYBIND11_UNARY_OPERATOR\nPYBIND11_NAMESPACE_END(detail)\n\nusing detail::self;\n// Add named operators so that they are accessible via `py::`.\nusing detail::hash;\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/options.h",
    "content": "/*\n    pybind11/options.h: global settings that are configurable at runtime.\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nclass options {\npublic:\n    // Default RAII constructor, which leaves settings as they currently are.\n    options() : previous_state(global_state()) {}\n\n    // Class is non-copyable.\n    options(const options &) = delete;\n    options &operator=(const options &) = delete;\n\n    // Destructor, which restores settings that were in effect before.\n    ~options() { global_state() = previous_state; }\n\n    // Setter methods (affect the global state):\n\n    options &disable_user_defined_docstrings() & {\n        global_state().show_user_defined_docstrings = false;\n        return *this;\n    }\n\n    options &enable_user_defined_docstrings() & {\n        global_state().show_user_defined_docstrings = true;\n        return *this;\n    }\n\n    options &disable_function_signatures() & {\n        global_state().show_function_signatures = false;\n        return *this;\n    }\n\n    options &enable_function_signatures() & {\n        global_state().show_function_signatures = true;\n        return *this;\n    }\n\n    options &disable_enum_members_docstring() & {\n        global_state().show_enum_members_docstring = false;\n        return *this;\n    }\n\n    options &enable_enum_members_docstring() & {\n        global_state().show_enum_members_docstring = true;\n        return *this;\n    }\n\n    // Getter methods (return the global state):\n\n    static bool show_user_defined_docstrings() {\n        return global_state().show_user_defined_docstrings;\n    }\n\n    static bool show_function_signatures() { return global_state().show_function_signatures; }\n\n    static bool show_enum_members_docstring() {\n        return global_state().show_enum_members_docstring;\n    }\n\n    // This type is not meant to be allocated on the heap.\n    void *operator new(size_t) = delete;\n\nprivate:\n    struct state {\n        bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.\n        bool show_function_signatures = true;     //< Include auto-generated function signatures\n                                                  //  in docstrings.\n        bool show_enum_members_docstring = true;  //< Include auto-generated member list in enum\n                                                  //  docstrings.\n    };\n\n    static state &global_state() {\n        static state instance;\n        return instance;\n    }\n\n    state previous_state;\n};\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/pybind11.h",
    "content": "/*\n    pybind11/pybind11.h: Main header file of the C++11 python\n    binding generator library\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/class.h\"\n#include \"detail/init.h\"\n#include \"attr.h\"\n#include \"gil.h\"\n#include \"gil_safe_call_once.h\"\n#include \"options.h\"\n#include \"typing.h\"\n\n#include <cstdlib>\n#include <cstring>\n#include <memory>\n#include <new>\n#include <string>\n#include <utility>\n#include <vector>\n\n#if defined(__cpp_lib_launder) && !(defined(_MSC_VER) && (_MSC_VER < 1914))\n#    define PYBIND11_STD_LAUNDER std::launder\n#    define PYBIND11_HAS_STD_LAUNDER 1\n#else\n#    define PYBIND11_STD_LAUNDER\n#    define PYBIND11_HAS_STD_LAUNDER 0\n#endif\n#if defined(__GNUG__) && !defined(__clang__)\n#    include <cxxabi.h>\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\n/* https://stackoverflow.com/questions/46798456/handling-gccs-noexcept-type-warning\n   This warning is about ABI compatibility, not code health.\n   It is only actually needed in a couple places, but apparently GCC 7 \"generates this warning if\n   and only if the first template instantiation ... involves noexcept\" [stackoverflow], therefore\n   it could get triggered from seemingly random places, depending on user code.\n   No other GCC version generates this warning.\n */\n#if defined(__GNUC__) && __GNUC__ == 7\nPYBIND11_WARNING_DISABLE_GCC(\"-Wnoexcept-type\")\n#endif\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline std::string replace_newlines_and_squash(const char *text) {\n    const char *whitespaces = \" \\t\\n\\r\\f\\v\";\n    std::string result(text);\n    bool previous_is_whitespace = false;\n\n    if (result.size() >= 2) {\n        // Do not modify string representations\n        char first_char = result[0];\n        char last_char = result[result.size() - 1];\n        if (first_char == last_char && first_char == '\\'') {\n            return result;\n        }\n    }\n    result.clear();\n\n    // Replace characters in whitespaces array with spaces and squash consecutive spaces\n    while (*text != '\\0') {\n        if (std::strchr(whitespaces, *text)) {\n            if (!previous_is_whitespace) {\n                result += ' ';\n                previous_is_whitespace = true;\n            }\n        } else {\n            result += *text;\n            previous_is_whitespace = false;\n        }\n        ++text;\n    }\n\n    // Strip leading and trailing whitespaces\n    const size_t str_begin = result.find_first_not_of(whitespaces);\n    if (str_begin == std::string::npos) {\n        return \"\";\n    }\n\n    const size_t str_end = result.find_last_not_of(whitespaces);\n    const size_t str_range = str_end - str_begin + 1;\n\n    return result.substr(str_begin, str_range);\n}\n\n// Apply all the extensions translators from a list\n// Return true if one of the translators completed without raising an exception\n// itself. Return of false indicates that if there are other translators\n// available, they should be tried.\ninline bool apply_exception_translators(std::forward_list<ExceptionTranslator> &translators) {\n    auto last_exception = std::current_exception();\n\n    for (auto &translator : translators) {\n        try {\n            translator(last_exception);\n            return true;\n        } catch (...) {\n            last_exception = std::current_exception();\n        }\n    }\n    return false;\n}\n\n#if defined(_MSC_VER)\n#    define PYBIND11_COMPAT_STRDUP _strdup\n#else\n#    define PYBIND11_COMPAT_STRDUP strdup\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Wraps an arbitrary C++ function/method/lambda function/.. into a callable Python object\nclass cpp_function : public function {\npublic:\n    cpp_function() = default;\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(std::nullptr_t) {}\n    cpp_function(std::nullptr_t, const is_setter &) {}\n\n    /// Construct a cpp_function from a vanilla function pointer\n    template <typename Return, typename... Args, typename... Extra>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Return (*f)(Args...), const Extra &...extra) {\n        initialize(f, f, extra...);\n    }\n\n    /// Construct a cpp_function from a lambda function (possibly with internal state)\n    template <typename Func,\n              typename... Extra,\n              typename = detail::enable_if_t<detail::is_lambda<Func>::value>>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Func &&f, const Extra &...extra) {\n        initialize(\n            std::forward<Func>(f), (detail::function_signature_t<Func> *) nullptr, extra...);\n    }\n\n    /// Construct a cpp_function from a class method (non-const, no ref-qualifier)\n    template <typename Return, typename Class, typename... Arg, typename... Extra>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Return (Class::*f)(Arg...), const Extra &...extra) {\n        initialize(\n            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },\n            (Return(*)(Class *, Arg...)) nullptr,\n            extra...);\n    }\n\n    /// Construct a cpp_function from a class method (non-const, lvalue ref-qualifier)\n    /// A copy of the overload for non-const functions without explicit ref-qualifier\n    /// but with an added `&`.\n    template <typename Return, typename Class, typename... Arg, typename... Extra>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Return (Class::*f)(Arg...) &, const Extra &...extra) {\n        initialize(\n            [f](Class *c, Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },\n            (Return(*)(Class *, Arg...)) nullptr,\n            extra...);\n    }\n\n    /// Construct a cpp_function from a class method (const, no ref-qualifier)\n    template <typename Return, typename Class, typename... Arg, typename... Extra>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Return (Class::*f)(Arg...) const, const Extra &...extra) {\n        initialize([f](const Class *c,\n                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },\n                   (Return(*)(const Class *, Arg...)) nullptr,\n                   extra...);\n    }\n\n    /// Construct a cpp_function from a class method (const, lvalue ref-qualifier)\n    /// A copy of the overload for const functions without explicit ref-qualifier\n    /// but with an added `&`.\n    template <typename Return, typename Class, typename... Arg, typename... Extra>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    cpp_function(Return (Class::*f)(Arg...) const &, const Extra &...extra) {\n        initialize([f](const Class *c,\n                       Arg... args) -> Return { return (c->*f)(std::forward<Arg>(args)...); },\n                   (Return(*)(const Class *, Arg...)) nullptr,\n                   extra...);\n    }\n\n    /// Return the function name\n    object name() const { return attr(\"__name__\"); }\n\nprotected:\n    struct InitializingFunctionRecordDeleter {\n        // `destruct(function_record, false)`: `initialize_generic` copies strings and\n        // takes care of cleaning up in case of exceptions. So pass `false` to `free_strings`.\n        void operator()(detail::function_record *rec) { destruct(rec, false); }\n    };\n    using unique_function_record\n        = std::unique_ptr<detail::function_record, InitializingFunctionRecordDeleter>;\n\n    /// Space optimization: don't inline this frequently instantiated fragment\n    PYBIND11_NOINLINE unique_function_record make_function_record() {\n        return unique_function_record(new detail::function_record());\n    }\n\n    /// Special internal constructor for functors, lambda functions, etc.\n    template <typename Func, typename Return, typename... Args, typename... Extra>\n    void initialize(Func &&f, Return (*)(Args...), const Extra &...extra) {\n        using namespace detail;\n        struct capture {\n            remove_reference_t<Func> f;\n        };\n\n        /* Store the function including any extra state it might have (e.g. a lambda capture\n         * object) */\n        // The unique_ptr makes sure nothing is leaked in case of an exception.\n        auto unique_rec = make_function_record();\n        auto *rec = unique_rec.get();\n\n        /* Store the capture object directly in the function record if there is enough space */\n        if (sizeof(capture) <= sizeof(rec->data)) {\n            /* Without these pragmas, GCC warns that there might not be\n               enough space to use the placement new operator. However, the\n               'if' statement above ensures that this is the case. */\n            PYBIND11_WARNING_PUSH\n\n#if defined(__GNUG__) && __GNUC__ >= 6\n            PYBIND11_WARNING_DISABLE_GCC(\"-Wplacement-new\")\n#endif\n\n            new ((capture *) &rec->data) capture{std::forward<Func>(f)};\n\n#if !PYBIND11_HAS_STD_LAUNDER\n            PYBIND11_WARNING_DISABLE_GCC(\"-Wstrict-aliasing\")\n#endif\n\n            // UB without std::launder, but without breaking ABI and/or\n            // a significant refactoring it's \"impossible\" to solve.\n            if (!std::is_trivially_destructible<capture>::value) {\n                rec->free_data = [](function_record *r) {\n                    auto data = PYBIND11_STD_LAUNDER((capture *) &r->data);\n                    (void) data;\n                    data->~capture();\n                };\n            }\n            PYBIND11_WARNING_POP\n        } else {\n            rec->data[0] = new capture{std::forward<Func>(f)};\n            rec->free_data = [](function_record *r) { delete ((capture *) r->data[0]); };\n        }\n\n        /* Type casters for the function arguments and return value */\n        using cast_in = argument_loader<Args...>;\n        using cast_out\n            = make_caster<conditional_t<std::is_void<Return>::value, void_type, Return>>;\n\n        static_assert(\n            expected_num_args<Extra...>(\n                sizeof...(Args), cast_in::args_pos >= 0, cast_in::has_kwargs),\n            \"The number of argument annotations does not match the number of function arguments\");\n\n        /* Dispatch code which converts function arguments and performs the actual function call */\n        rec->impl = [](function_call &call) -> handle {\n            cast_in args_converter;\n\n            /* Try to cast the function arguments into the C++ domain */\n            if (!args_converter.load_args(call)) {\n                return PYBIND11_TRY_NEXT_OVERLOAD;\n            }\n\n            /* Invoke call policy pre-call hook */\n            process_attributes<Extra...>::precall(call);\n\n            /* Get a pointer to the capture object */\n            const auto *data = (sizeof(capture) <= sizeof(call.func.data) ? &call.func.data\n                                                                          : call.func.data[0]);\n            auto *cap = const_cast<capture *>(reinterpret_cast<const capture *>(data));\n\n            /* Override policy for rvalues -- usually to enforce rvp::move on an rvalue */\n            return_value_policy policy\n                = return_value_policy_override<Return>::policy(call.func.policy);\n\n            /* Function scope guard -- defaults to the compile-to-nothing `void_type` */\n            using Guard = extract_guard_t<Extra...>;\n\n            /* Perform the function call */\n            handle result;\n            if (call.func.is_setter) {\n                (void) std::move(args_converter).template call<Return, Guard>(cap->f);\n                result = none().release();\n            } else {\n                result = cast_out::cast(\n                    std::move(args_converter).template call<Return, Guard>(cap->f),\n                    policy,\n                    call.parent);\n            }\n\n            /* Invoke call policy post-call hook */\n            process_attributes<Extra...>::postcall(call, result);\n\n            return result;\n        };\n\n        rec->nargs_pos = cast_in::args_pos >= 0\n                             ? static_cast<std::uint16_t>(cast_in::args_pos)\n                             : sizeof...(Args) - cast_in::has_kwargs; // Will get reduced more if\n                                                                      // we have a kw_only\n        rec->has_args = cast_in::args_pos >= 0;\n        rec->has_kwargs = cast_in::has_kwargs;\n\n        /* Process any user-provided function attributes */\n        process_attributes<Extra...>::init(extra..., rec);\n\n        {\n            constexpr bool has_kw_only_args = any_of<std::is_same<kw_only, Extra>...>::value,\n                           has_pos_only_args = any_of<std::is_same<pos_only, Extra>...>::value,\n                           has_arg_annotations = any_of<is_keyword<Extra>...>::value;\n            static_assert(has_arg_annotations || !has_kw_only_args,\n                          \"py::kw_only requires the use of argument annotations\");\n            static_assert(has_arg_annotations || !has_pos_only_args,\n                          \"py::pos_only requires the use of argument annotations (for docstrings \"\n                          \"and aligning the annotations to the argument)\");\n\n            static_assert(constexpr_sum(is_kw_only<Extra>::value...) <= 1,\n                          \"py::kw_only may be specified only once\");\n            static_assert(constexpr_sum(is_pos_only<Extra>::value...) <= 1,\n                          \"py::pos_only may be specified only once\");\n            constexpr auto kw_only_pos = constexpr_first<is_kw_only, Extra...>();\n            constexpr auto pos_only_pos = constexpr_first<is_pos_only, Extra...>();\n            static_assert(!(has_kw_only_args && has_pos_only_args) || pos_only_pos < kw_only_pos,\n                          \"py::pos_only must come before py::kw_only\");\n        }\n\n        /* Generate a readable signature describing the function's arguments and return\n           value types */\n        static constexpr auto signature\n            = const_name(\"(\") + cast_in::arg_names + const_name(\") -> \") + cast_out::name;\n        PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();\n\n        /* Register the function with Python from generic (non-templated) code */\n        // Pass on the ownership over the `unique_rec` to `initialize_generic`. `rec` stays valid.\n        initialize_generic(std::move(unique_rec), signature.text, types.data(), sizeof...(Args));\n\n        /* Stash some additional information used by an important optimization in 'functional.h' */\n        using FunctionType = Return (*)(Args...);\n        constexpr bool is_function_ptr\n            = std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);\n        if (is_function_ptr) {\n            rec->is_stateless = true;\n            rec->data[1]\n                = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));\n        }\n    }\n\n    // Utility class that keeps track of all duplicated strings, and cleans them up in its\n    // destructor, unless they are released. Basically a RAII-solution to deal with exceptions\n    // along the way.\n    class strdup_guard {\n    public:\n        strdup_guard() = default;\n        strdup_guard(const strdup_guard &) = delete;\n        strdup_guard &operator=(const strdup_guard &) = delete;\n\n        ~strdup_guard() {\n            for (auto *s : strings) {\n                std::free(s);\n            }\n        }\n        char *operator()(const char *s) {\n            auto *t = PYBIND11_COMPAT_STRDUP(s);\n            strings.push_back(t);\n            return t;\n        }\n        void release() { strings.clear(); }\n\n    private:\n        std::vector<char *> strings;\n    };\n\n    /// Register a function call with Python (generic non-templated code goes here)\n    void initialize_generic(unique_function_record &&unique_rec,\n                            const char *text,\n                            const std::type_info *const *types,\n                            size_t args) {\n        // Do NOT receive `unique_rec` by value. If this function fails to move out the unique_ptr,\n        // we do not want this to destruct the pointer. `initialize` (the caller) still relies on\n        // the pointee being alive after this call. Only move out if a `capsule` is going to keep\n        // it alive.\n        auto *rec = unique_rec.get();\n\n        // Keep track of strdup'ed strings, and clean them up as long as the function's capsule\n        // has not taken ownership yet (when `unique_rec.release()` is called).\n        // Note: This cannot easily be fixed by a `unique_ptr` with custom deleter, because the\n        // strings are only referenced before strdup'ing. So only *after* the following block could\n        // `destruct` safely be called, but even then, `repr` could still throw in the middle of\n        // copying all strings.\n        strdup_guard guarded_strdup;\n\n        /* Create copies of all referenced C-style strings */\n        rec->name = guarded_strdup(rec->name ? rec->name : \"\");\n        if (rec->doc) {\n            rec->doc = guarded_strdup(rec->doc);\n        }\n        for (auto &a : rec->args) {\n            if (a.name) {\n                a.name = guarded_strdup(a.name);\n            }\n            if (a.descr) {\n                a.descr = guarded_strdup(a.descr);\n            } else if (a.value) {\n                a.descr = guarded_strdup(repr(a.value).cast<std::string>().c_str());\n            }\n        }\n\n        rec->is_constructor = (std::strcmp(rec->name, \"__init__\") == 0)\n                              || (std::strcmp(rec->name, \"__setstate__\") == 0);\n\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)\n        if (rec->is_constructor && !rec->is_new_style_constructor) {\n            const auto class_name\n                = detail::get_fully_qualified_tp_name((PyTypeObject *) rec->scope.ptr());\n            const auto func_name = std::string(rec->name);\n            PyErr_WarnEx(PyExc_FutureWarning,\n                         (\"pybind11-bound class '\" + class_name\n                          + \"' is using an old-style \"\n                            \"placement-new '\"\n                          + func_name\n                          + \"' which has been deprecated. See \"\n                            \"the upgrade guide in pybind11's docs. This message is only visible \"\n                            \"when compiled in debug mode.\")\n                             .c_str(),\n                         0);\n        }\n#endif\n\n        /* Generate a proper function signature */\n        std::string signature;\n        size_t type_index = 0, arg_index = 0;\n        bool is_starred = false;\n        for (const auto *pc = text; *pc != '\\0'; ++pc) {\n            const auto c = *pc;\n\n            if (c == '{') {\n                // Write arg name for everything except *args and **kwargs.\n                is_starred = *(pc + 1) == '*';\n                if (is_starred) {\n                    continue;\n                }\n                // Separator for keyword-only arguments, placed before the kw\n                // arguments start (unless we are already putting an *args)\n                if (!rec->has_args && arg_index == rec->nargs_pos) {\n                    signature += \"*, \";\n                }\n                if (arg_index < rec->args.size() && rec->args[arg_index].name) {\n                    signature += rec->args[arg_index].name;\n                } else if (arg_index == 0 && rec->is_method) {\n                    signature += \"self\";\n                } else {\n                    signature += \"arg\" + std::to_string(arg_index - (rec->is_method ? 1 : 0));\n                }\n                signature += \": \";\n            } else if (c == '}') {\n                // Write default value if available.\n                if (!is_starred && arg_index < rec->args.size() && rec->args[arg_index].descr) {\n                    signature += \" = \";\n                    signature += detail::replace_newlines_and_squash(rec->args[arg_index].descr);\n                }\n                // Separator for positional-only arguments (placed after the\n                // argument, rather than before like *\n                if (rec->nargs_pos_only > 0 && (arg_index + 1) == rec->nargs_pos_only) {\n                    signature += \", /\";\n                }\n                if (!is_starred) {\n                    arg_index++;\n                }\n            } else if (c == '%') {\n                const std::type_info *t = types[type_index++];\n                if (!t) {\n                    pybind11_fail(\"Internal error while parsing type signature (1)\");\n                }\n                if (auto *tinfo = detail::get_type_info(*t)) {\n                    handle th((PyObject *) tinfo->type);\n                    signature += th.attr(\"__module__\").cast<std::string>() + \".\"\n                                 + th.attr(\"__qualname__\").cast<std::string>();\n                } else if (rec->is_new_style_constructor && arg_index == 0) {\n                    // A new-style `__init__` takes `self` as `value_and_holder`.\n                    // Rewrite it to the proper class type.\n                    signature += rec->scope.attr(\"__module__\").cast<std::string>() + \".\"\n                                 + rec->scope.attr(\"__qualname__\").cast<std::string>();\n                } else {\n                    signature += detail::quote_cpp_type_name(detail::clean_type_id(t->name()));\n                }\n            } else {\n                signature += c;\n            }\n        }\n\n        if (arg_index != args - rec->has_args - rec->has_kwargs || types[type_index] != nullptr) {\n            pybind11_fail(\"Internal error while parsing type signature (2)\");\n        }\n\n        rec->signature = guarded_strdup(signature.c_str());\n        rec->args.shrink_to_fit();\n        rec->nargs = (std::uint16_t) args;\n\n        if (rec->sibling && PYBIND11_INSTANCE_METHOD_CHECK(rec->sibling.ptr())) {\n            rec->sibling = PYBIND11_INSTANCE_METHOD_GET_FUNCTION(rec->sibling.ptr());\n        }\n\n        detail::function_record *chain = nullptr, *chain_start = rec;\n        if (rec->sibling) {\n            if (PyCFunction_Check(rec->sibling.ptr())) {\n                auto *self = PyCFunction_GET_SELF(rec->sibling.ptr());\n                if (!isinstance<capsule>(self)) {\n                    chain = nullptr;\n                } else {\n                    auto rec_capsule = reinterpret_borrow<capsule>(self);\n                    if (detail::is_function_record_capsule(rec_capsule)) {\n                        chain = rec_capsule.get_pointer<detail::function_record>();\n                        /* Never append a method to an overload chain of a parent class;\n                           instead, hide the parent's overloads in this case */\n                        if (!chain->scope.is(rec->scope)) {\n                            chain = nullptr;\n                        }\n                    } else {\n                        chain = nullptr;\n                    }\n                }\n            }\n            // Don't trigger for things like the default __init__, which are wrapper_descriptors\n            // that we are intentionally replacing\n            else if (!rec->sibling.is_none() && rec->name[0] != '_') {\n                pybind11_fail(\"Cannot overload existing non-function object \\\"\"\n                              + std::string(rec->name) + \"\\\" with a function of the same name\");\n            }\n        }\n\n        if (!chain) {\n            /* No existing overload was found, create a new function object */\n            rec->def = new PyMethodDef();\n            std::memset(rec->def, 0, sizeof(PyMethodDef));\n            rec->def->ml_name = rec->name;\n            rec->def->ml_meth\n                = reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(dispatcher));\n            rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;\n\n            capsule rec_capsule(unique_rec.release(),\n                                detail::get_function_record_capsule_name(),\n                                [](void *ptr) { destruct((detail::function_record *) ptr); });\n            guarded_strdup.release();\n\n            object scope_module;\n            if (rec->scope) {\n                if (hasattr(rec->scope, \"__module__\")) {\n                    scope_module = rec->scope.attr(\"__module__\");\n                } else if (hasattr(rec->scope, \"__name__\")) {\n                    scope_module = rec->scope.attr(\"__name__\");\n                }\n            }\n\n            m_ptr = PyCFunction_NewEx(rec->def, rec_capsule.ptr(), scope_module.ptr());\n            if (!m_ptr) {\n                pybind11_fail(\"cpp_function::cpp_function(): Could not allocate function object\");\n            }\n        } else {\n            /* Append at the beginning or end of the overload chain */\n            m_ptr = rec->sibling.ptr();\n            inc_ref();\n            if (chain->is_method != rec->is_method) {\n                pybind11_fail(\n                    \"overloading a method with both static and instance methods is not supported; \"\n#if !defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                    \"#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for more \"\n                    \"details\"\n#else\n                    \"error while attempting to bind \"\n                    + std::string(rec->is_method ? \"instance\" : \"static\") + \" method \"\n                    + std::string(pybind11::str(rec->scope.attr(\"__name__\"))) + \".\"\n                    + std::string(rec->name) + signature\n#endif\n                );\n            }\n\n            if (rec->prepend) {\n                // Beginning of chain; we need to replace the capsule's current head-of-the-chain\n                // pointer with this one, then make this one point to the previous head of the\n                // chain.\n                chain_start = rec;\n                rec->next = chain;\n                auto rec_capsule\n                    = reinterpret_borrow<capsule>(((PyCFunctionObject *) m_ptr)->m_self);\n                rec_capsule.set_pointer(unique_rec.release());\n                guarded_strdup.release();\n            } else {\n                // Or end of chain (normal behavior)\n                chain_start = chain;\n                while (chain->next) {\n                    chain = chain->next;\n                }\n                chain->next = unique_rec.release();\n                guarded_strdup.release();\n            }\n        }\n\n        std::string signatures;\n        int index = 0;\n        /* Create a nice pydoc rec including all signatures and\n           docstrings of the functions in the overload chain */\n        if (chain && options::show_function_signatures()) {\n            // First a generic signature\n            signatures += rec->name;\n            signatures += \"(*args, **kwargs)\\n\";\n            signatures += \"Overloaded function.\\n\\n\";\n        }\n        // Then specific overload signatures\n        bool first_user_def = true;\n        for (auto *it = chain_start; it != nullptr; it = it->next) {\n            if (options::show_function_signatures()) {\n                if (index > 0) {\n                    signatures += '\\n';\n                }\n                if (chain) {\n                    signatures += std::to_string(++index) + \". \";\n                }\n                signatures += rec->name;\n                signatures += it->signature;\n                signatures += '\\n';\n            }\n            if (it->doc && it->doc[0] != '\\0' && options::show_user_defined_docstrings()) {\n                // If we're appending another docstring, and aren't printing function signatures,\n                // we need to append a newline first:\n                if (!options::show_function_signatures()) {\n                    if (first_user_def) {\n                        first_user_def = false;\n                    } else {\n                        signatures += '\\n';\n                    }\n                }\n                if (options::show_function_signatures()) {\n                    signatures += '\\n';\n                }\n                signatures += it->doc;\n                if (options::show_function_signatures()) {\n                    signatures += '\\n';\n                }\n            }\n        }\n\n        /* Install docstring */\n        auto *func = (PyCFunctionObject *) m_ptr;\n        std::free(const_cast<char *>(func->m_ml->ml_doc));\n        // Install docstring if it's non-empty (when at least one option is enabled)\n        func->m_ml->ml_doc\n            = signatures.empty() ? nullptr : PYBIND11_COMPAT_STRDUP(signatures.c_str());\n\n        if (rec->is_method) {\n            m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr());\n            if (!m_ptr) {\n                pybind11_fail(\n                    \"cpp_function::cpp_function(): Could not allocate instance method object\");\n            }\n            Py_DECREF(func);\n        }\n    }\n\n    /// When a cpp_function is GCed, release any memory allocated by pybind11\n    static void destruct(detail::function_record *rec, bool free_strings = true) {\n// If on Python 3.9, check the interpreter \"MICRO\" (patch) version.\n// If this is running on 3.9.0, we have to work around a bug.\n#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9\n        static bool is_zero = Py_GetVersion()[4] == '0';\n#endif\n\n        while (rec) {\n            detail::function_record *next = rec->next;\n            if (rec->free_data) {\n                rec->free_data(rec);\n            }\n            // During initialization, these strings might not have been copied yet,\n            // so they cannot be freed. Once the function has been created, they can.\n            // Check `make_function_record` for more details.\n            if (free_strings) {\n                std::free((char *) rec->name);\n                std::free((char *) rec->doc);\n                std::free((char *) rec->signature);\n                for (auto &arg : rec->args) {\n                    std::free(const_cast<char *>(arg.name));\n                    std::free(const_cast<char *>(arg.descr));\n                }\n            }\n            for (auto &arg : rec->args) {\n                arg.value.dec_ref();\n            }\n            if (rec->def) {\n                std::free(const_cast<char *>(rec->def->ml_doc));\n// Python 3.9.0 decref's these in the wrong order; rec->def\n// If loaded on 3.9.0, let these leak (use Python 3.9.1 at runtime to fix)\n// See https://github.com/python/cpython/pull/22670\n#if !defined(PYPY_VERSION) && PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 9\n                if (!is_zero) {\n                    delete rec->def;\n                }\n#else\n                delete rec->def;\n#endif\n            }\n            delete rec;\n            rec = next;\n        }\n    }\n\n    /// Main dispatch logic for calls to functions bound using pybind11\n    static PyObject *dispatcher(PyObject *self, PyObject *args_in, PyObject *kwargs_in) {\n        using namespace detail;\n        assert(isinstance<capsule>(self));\n\n        /* Iterator over the list of potentially admissible overloads */\n        const function_record *overloads = reinterpret_cast<function_record *>(\n                                  PyCapsule_GetPointer(self, get_function_record_capsule_name())),\n                              *current_overload = overloads;\n        assert(overloads != nullptr);\n\n        /* Need to know how many arguments + keyword arguments there are to pick the right\n           overload */\n        const auto n_args_in = (size_t) PyTuple_GET_SIZE(args_in);\n\n        handle parent = n_args_in > 0 ? PyTuple_GET_ITEM(args_in, 0) : nullptr,\n               result = PYBIND11_TRY_NEXT_OVERLOAD;\n\n        auto self_value_and_holder = value_and_holder();\n        if (overloads->is_constructor) {\n            if (!parent\n                || !PyObject_TypeCheck(parent.ptr(), (PyTypeObject *) overloads->scope.ptr())) {\n                set_error(PyExc_TypeError,\n                          \"__init__(self, ...) called with invalid or missing `self` argument\");\n                return nullptr;\n            }\n\n            auto *const tinfo = get_type_info((PyTypeObject *) overloads->scope.ptr());\n            auto *const pi = reinterpret_cast<instance *>(parent.ptr());\n            self_value_and_holder = pi->get_value_and_holder(tinfo, true);\n\n            // If this value is already registered it must mean __init__ is invoked multiple times;\n            // we really can't support that in C++, so just ignore the second __init__.\n            if (self_value_and_holder.instance_registered()) {\n                return none().release().ptr();\n            }\n        }\n\n        try {\n            // We do this in two passes: in the first pass, we load arguments with `convert=false`;\n            // in the second, we allow conversion (except for arguments with an explicit\n            // py::arg().noconvert()).  This lets us prefer calls without conversion, with\n            // conversion as a fallback.\n            std::vector<function_call> second_pass;\n\n            // However, if there are no overloads, we can just skip the no-convert pass entirely\n            const bool overloaded\n                = current_overload != nullptr && current_overload->next != nullptr;\n\n            for (; current_overload != nullptr; current_overload = current_overload->next) {\n\n                /* For each overload:\n                   1. Copy all positional arguments we were given, also checking to make sure that\n                      named positional arguments weren't *also* specified via kwarg.\n                   2. If we weren't given enough, try to make up the omitted ones by checking\n                      whether they were provided by a kwarg matching the `py::arg(\"name\")` name. If\n                      so, use it (and remove it from kwargs); if not, see if the function binding\n                      provided a default that we can use.\n                   3. Ensure that either all keyword arguments were \"consumed\", or that the\n                   function takes a kwargs argument to accept unconsumed kwargs.\n                   4. Any positional arguments still left get put into a tuple (for args), and any\n                      leftover kwargs get put into a dict.\n                   5. Pack everything into a vector; if we have py::args or py::kwargs, they are an\n                      extra tuple or dict at the end of the positional arguments.\n                   6. Call the function call dispatcher (function_record::impl)\n\n                   If one of these fail, move on to the next overload and keep trying until we get\n                   a result other than PYBIND11_TRY_NEXT_OVERLOAD.\n                 */\n\n                const function_record &func = *current_overload;\n                size_t num_args = func.nargs; // Number of positional arguments that we need\n                if (func.has_args) {\n                    --num_args; // (but don't count py::args\n                }\n                if (func.has_kwargs) {\n                    --num_args; //  or py::kwargs)\n                }\n                size_t pos_args = func.nargs_pos;\n\n                if (!func.has_args && n_args_in > pos_args) {\n                    continue; // Too many positional arguments for this overload\n                }\n\n                if (n_args_in < pos_args && func.args.size() < pos_args) {\n                    continue; // Not enough positional arguments given, and not enough defaults to\n                              // fill in the blanks\n                }\n\n                function_call call(func, parent);\n\n                // Protect std::min with parentheses\n                size_t args_to_copy = (std::min)(pos_args, n_args_in);\n                size_t args_copied = 0;\n\n                // 0. Inject new-style `self` argument\n                if (func.is_new_style_constructor) {\n                    // The `value` may have been preallocated by an old-style `__init__`\n                    // if it was a preceding candidate for overload resolution.\n                    if (self_value_and_holder) {\n                        self_value_and_holder.type->dealloc(self_value_and_holder);\n                    }\n\n                    call.init_self = PyTuple_GET_ITEM(args_in, 0);\n                    call.args.emplace_back(reinterpret_cast<PyObject *>(&self_value_and_holder));\n                    call.args_convert.push_back(false);\n                    ++args_copied;\n                }\n\n                // 1. Copy any position arguments given.\n                bool bad_arg = false;\n                for (; args_copied < args_to_copy; ++args_copied) {\n                    const argument_record *arg_rec\n                        = args_copied < func.args.size() ? &func.args[args_copied] : nullptr;\n                    if (kwargs_in && arg_rec && arg_rec->name\n                        && dict_getitemstring(kwargs_in, arg_rec->name)) {\n                        bad_arg = true;\n                        break;\n                    }\n\n                    handle arg(PyTuple_GET_ITEM(args_in, args_copied));\n                    if (arg_rec && !arg_rec->none && arg.is_none()) {\n                        bad_arg = true;\n                        break;\n                    }\n                    call.args.push_back(arg);\n                    call.args_convert.push_back(arg_rec ? arg_rec->convert : true);\n                }\n                if (bad_arg) {\n                    continue; // Maybe it was meant for another overload (issue #688)\n                }\n\n                // Keep track of how many position args we copied out in case we need to come back\n                // to copy the rest into a py::args argument.\n                size_t positional_args_copied = args_copied;\n\n                // We'll need to copy this if we steal some kwargs for defaults\n                dict kwargs = reinterpret_borrow<dict>(kwargs_in);\n\n                // 1.5. Fill in any missing pos_only args from defaults if they exist\n                if (args_copied < func.nargs_pos_only) {\n                    for (; args_copied < func.nargs_pos_only; ++args_copied) {\n                        const auto &arg_rec = func.args[args_copied];\n                        handle value;\n\n                        if (arg_rec.value) {\n                            value = arg_rec.value;\n                        }\n                        if (value) {\n                            call.args.push_back(value);\n                            call.args_convert.push_back(arg_rec.convert);\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if (args_copied < func.nargs_pos_only) {\n                        continue; // Not enough defaults to fill the positional arguments\n                    }\n                }\n\n                // 2. Check kwargs and, failing that, defaults that may help complete the list\n                if (args_copied < num_args) {\n                    bool copied_kwargs = false;\n\n                    for (; args_copied < num_args; ++args_copied) {\n                        const auto &arg_rec = func.args[args_copied];\n\n                        handle value;\n                        if (kwargs_in && arg_rec.name) {\n                            value = dict_getitemstring(kwargs.ptr(), arg_rec.name);\n                        }\n\n                        if (value) {\n                            // Consume a kwargs value\n                            if (!copied_kwargs) {\n                                kwargs = reinterpret_steal<dict>(PyDict_Copy(kwargs.ptr()));\n                                copied_kwargs = true;\n                            }\n                            if (PyDict_DelItemString(kwargs.ptr(), arg_rec.name) == -1) {\n                                throw error_already_set();\n                            }\n                        } else if (arg_rec.value) {\n                            value = arg_rec.value;\n                        }\n\n                        if (!arg_rec.none && value.is_none()) {\n                            break;\n                        }\n\n                        if (value) {\n                            // If we're at the py::args index then first insert a stub for it to be\n                            // replaced later\n                            if (func.has_args && call.args.size() == func.nargs_pos) {\n                                call.args.push_back(none());\n                            }\n\n                            call.args.push_back(value);\n                            call.args_convert.push_back(arg_rec.convert);\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if (args_copied < num_args) {\n                        continue; // Not enough arguments, defaults, or kwargs to fill the\n                                  // positional arguments\n                    }\n                }\n\n                // 3. Check everything was consumed (unless we have a kwargs arg)\n                if (kwargs && !kwargs.empty() && !func.has_kwargs) {\n                    continue; // Unconsumed kwargs, but no py::kwargs argument to accept them\n                }\n\n                // 4a. If we have a py::args argument, create a new tuple with leftovers\n                if (func.has_args) {\n                    tuple extra_args;\n                    if (args_to_copy == 0) {\n                        // We didn't copy out any position arguments from the args_in tuple, so we\n                        // can reuse it directly without copying:\n                        extra_args = reinterpret_borrow<tuple>(args_in);\n                    } else if (positional_args_copied >= n_args_in) {\n                        extra_args = tuple(0);\n                    } else {\n                        size_t args_size = n_args_in - positional_args_copied;\n                        extra_args = tuple(args_size);\n                        for (size_t i = 0; i < args_size; ++i) {\n                            extra_args[i] = PyTuple_GET_ITEM(args_in, positional_args_copied + i);\n                        }\n                    }\n                    if (call.args.size() <= func.nargs_pos) {\n                        call.args.push_back(extra_args);\n                    } else {\n                        call.args[func.nargs_pos] = extra_args;\n                    }\n                    call.args_convert.push_back(false);\n                    call.args_ref = std::move(extra_args);\n                }\n\n                // 4b. If we have a py::kwargs, pass on any remaining kwargs\n                if (func.has_kwargs) {\n                    if (!kwargs.ptr()) {\n                        kwargs = dict(); // If we didn't get one, send an empty one\n                    }\n                    call.args.push_back(kwargs);\n                    call.args_convert.push_back(false);\n                    call.kwargs_ref = std::move(kwargs);\n                }\n\n// 5. Put everything in a vector.  Not technically step 5, we've been building it\n// in `call.args` all along.\n#if defined(PYBIND11_DETAILED_ERROR_MESSAGES)\n                if (call.args.size() != func.nargs || call.args_convert.size() != func.nargs) {\n                    pybind11_fail(\"Internal error: function call dispatcher inserted wrong number \"\n                                  \"of arguments!\");\n                }\n#endif\n\n                std::vector<bool> second_pass_convert;\n                if (overloaded) {\n                    // We're in the first no-convert pass, so swap out the conversion flags for a\n                    // set of all-false flags.  If the call fails, we'll swap the flags back in for\n                    // the conversion-allowed call below.\n                    second_pass_convert.resize(func.nargs, false);\n                    call.args_convert.swap(second_pass_convert);\n                }\n\n                // 6. Call the function.\n                try {\n                    loader_life_support guard{};\n                    result = func.impl(call);\n                } catch (reference_cast_error &) {\n                    result = PYBIND11_TRY_NEXT_OVERLOAD;\n                }\n\n                if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {\n                    break;\n                }\n\n                if (overloaded) {\n                    // The (overloaded) call failed; if the call has at least one argument that\n                    // permits conversion (i.e. it hasn't been explicitly specified `.noconvert()`)\n                    // then add this call to the list of second pass overloads to try.\n                    for (size_t i = func.is_method ? 1 : 0; i < pos_args; i++) {\n                        if (second_pass_convert[i]) {\n                            // Found one: swap the converting flags back in and store the call for\n                            // the second pass.\n                            call.args_convert.swap(second_pass_convert);\n                            second_pass.push_back(std::move(call));\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if (overloaded && !second_pass.empty() && result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {\n                // The no-conversion pass finished without success, try again with conversion\n                // allowed\n                for (auto &call : second_pass) {\n                    try {\n                        loader_life_support guard{};\n                        result = call.func.impl(call);\n                    } catch (reference_cast_error &) {\n                        result = PYBIND11_TRY_NEXT_OVERLOAD;\n                    }\n\n                    if (result.ptr() != PYBIND11_TRY_NEXT_OVERLOAD) {\n                        // The error reporting logic below expects 'current_overload' to be valid,\n                        // as it would be if we'd encountered this failure in the first-pass loop.\n                        if (!result) {\n                            current_overload = &call.func;\n                        }\n                        break;\n                    }\n                }\n            }\n        } catch (error_already_set &e) {\n            e.restore();\n            return nullptr;\n#ifdef __GLIBCXX__\n        } catch (abi::__forced_unwind &) {\n            throw;\n#endif\n        } catch (...) {\n            /* When an exception is caught, give each registered exception\n               translator a chance to translate it to a Python exception. First\n               all module-local translators will be tried in reverse order of\n               registration. If none of the module-locale translators handle\n               the exception (or there are no module-locale translators) then\n               the global translators will be tried, also in reverse order of\n               registration.\n\n               A translator may choose to do one of the following:\n\n                - catch the exception and call py::set_error()\n                  to set a standard (or custom) Python exception, or\n                - do nothing and let the exception fall through to the next translator, or\n                - delegate translation to the next translator by throwing a new type of exception.\n             */\n\n            auto &local_exception_translators\n                = get_local_internals().registered_exception_translators;\n            if (detail::apply_exception_translators(local_exception_translators)) {\n                return nullptr;\n            }\n            auto &exception_translators = get_internals().registered_exception_translators;\n            if (detail::apply_exception_translators(exception_translators)) {\n                return nullptr;\n            }\n\n            set_error(PyExc_SystemError, \"Exception escaped from default exception translator!\");\n            return nullptr;\n        }\n\n        auto append_note_if_missing_header_is_suspected = [](std::string &msg) {\n            if (msg.find(\"std::\") != std::string::npos) {\n                msg += \"\\n\\n\"\n                       \"Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,\\n\"\n                       \"<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic\\n\"\n                       \"conversions are optional and require extra headers to be included\\n\"\n                       \"when compiling your pybind11 module.\";\n            }\n        };\n\n        if (result.ptr() == PYBIND11_TRY_NEXT_OVERLOAD) {\n            if (overloads->is_operator) {\n                return handle(Py_NotImplemented).inc_ref().ptr();\n            }\n\n            std::string msg = std::string(overloads->name) + \"(): incompatible \"\n                              + std::string(overloads->is_constructor ? \"constructor\" : \"function\")\n                              + \" arguments. The following argument types are supported:\\n\";\n\n            int ctr = 0;\n            for (const function_record *it2 = overloads; it2 != nullptr; it2 = it2->next) {\n                msg += \"    \" + std::to_string(++ctr) + \". \";\n\n                bool wrote_sig = false;\n                if (overloads->is_constructor) {\n                    // For a constructor, rewrite `(self: Object, arg0, ...) -> NoneType` as\n                    // `Object(arg0, ...)`\n                    std::string sig = it2->signature;\n                    size_t start = sig.find('(') + 7; // skip \"(self: \"\n                    if (start < sig.size()) {\n                        // End at the , for the next argument\n                        size_t end = sig.find(\", \"), next = end + 2;\n                        size_t ret = sig.rfind(\" -> \");\n                        // Or the ), if there is no comma:\n                        if (end >= sig.size()) {\n                            next = end = sig.find(')');\n                        }\n                        if (start < end && next < sig.size()) {\n                            msg.append(sig, start, end - start);\n                            msg += '(';\n                            msg.append(sig, next, ret - next);\n                            wrote_sig = true;\n                        }\n                    }\n                }\n                if (!wrote_sig) {\n                    msg += it2->signature;\n                }\n\n                msg += '\\n';\n            }\n            msg += \"\\nInvoked with: \";\n            auto args_ = reinterpret_borrow<tuple>(args_in);\n            bool some_args = false;\n            for (size_t ti = overloads->is_constructor ? 1 : 0; ti < args_.size(); ++ti) {\n                if (!some_args) {\n                    some_args = true;\n                } else {\n                    msg += \", \";\n                }\n                try {\n                    msg += pybind11::repr(args_[ti]);\n                } catch (const error_already_set &) {\n                    msg += \"<repr raised Error>\";\n                }\n            }\n            if (kwargs_in) {\n                auto kwargs = reinterpret_borrow<dict>(kwargs_in);\n                if (!kwargs.empty()) {\n                    if (some_args) {\n                        msg += \"; \";\n                    }\n                    msg += \"kwargs: \";\n                    bool first = true;\n                    for (const auto &kwarg : kwargs) {\n                        if (first) {\n                            first = false;\n                        } else {\n                            msg += \", \";\n                        }\n                        msg += pybind11::str(\"{}=\").format(kwarg.first);\n                        try {\n                            msg += pybind11::repr(kwarg.second);\n                        } catch (const error_already_set &) {\n                            msg += \"<repr raised Error>\";\n                        }\n                    }\n                }\n            }\n\n            append_note_if_missing_header_is_suspected(msg);\n            // Attach additional error info to the exception if supported\n            if (PyErr_Occurred()) {\n                // #HelpAppreciated: unit test coverage for this branch.\n                raise_from(PyExc_TypeError, msg.c_str());\n                return nullptr;\n            }\n            set_error(PyExc_TypeError, msg.c_str());\n            return nullptr;\n        }\n        if (!result) {\n            std::string msg = \"Unable to convert function return value to a \"\n                              \"Python type! The signature was\\n\\t\";\n            assert(current_overload != nullptr);\n            msg += current_overload->signature;\n            append_note_if_missing_header_is_suspected(msg);\n            // Attach additional error info to the exception if supported\n            if (PyErr_Occurred()) {\n                raise_from(PyExc_TypeError, msg.c_str());\n                return nullptr;\n            }\n            set_error(PyExc_TypeError, msg.c_str());\n            return nullptr;\n        }\n        if (overloads->is_constructor && !self_value_and_holder.holder_constructed()) {\n            auto *pi = reinterpret_cast<instance *>(parent.ptr());\n            self_value_and_holder.type->init_instance(pi, nullptr);\n        }\n        return result.ptr();\n    }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nstruct handle_type_name<cpp_function> {\n    static constexpr auto name = const_name(\"Callable\");\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Wrapper for Python extension modules\nclass module_ : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)\n\n    /// Create a new top-level Python module with the given name and docstring\n    PYBIND11_DEPRECATED(\"Use PYBIND11_MODULE or module_::create_extension_module instead\")\n    explicit module_(const char *name, const char *doc = nullptr) {\n        *this = create_extension_module(name, doc, new PyModuleDef());\n    }\n\n    /** \\rst\n        Create Python binding for a new function within the module scope. ``Func``\n        can be a plain C++ function, a function pointer, or a lambda function. For\n        details on the ``Extra&& ... extra`` argument, see section :ref:`extras`.\n    \\endrst */\n    template <typename Func, typename... Extra>\n    module_ &def(const char *name_, Func &&f, const Extra &...extra) {\n        cpp_function func(std::forward<Func>(f),\n                          name(name_),\n                          scope(*this),\n                          sibling(getattr(*this, name_, none())),\n                          extra...);\n        // NB: allow overwriting here because cpp_function sets up a chain with the intention of\n        // overwriting (and has already checked internally that it isn't overwriting\n        // non-functions).\n        add_object(name_, func, true /* overwrite */);\n        return *this;\n    }\n\n    /** \\rst\n        Create and return a new Python submodule with the given name and docstring.\n        This also works recursively, i.e.\n\n        .. code-block:: cpp\n\n            py::module_ m(\"example\", \"pybind11 example plugin\");\n            py::module_ m2 = m.def_submodule(\"sub\", \"A submodule of 'example'\");\n            py::module_ m3 = m2.def_submodule(\"subsub\", \"A submodule of 'example.sub'\");\n    \\endrst */\n    module_ def_submodule(const char *name, const char *doc = nullptr) {\n        const char *this_name = PyModule_GetName(m_ptr);\n        if (this_name == nullptr) {\n            throw error_already_set();\n        }\n        std::string full_name = std::string(this_name) + '.' + name;\n        handle submodule = PyImport_AddModule(full_name.c_str());\n        if (!submodule) {\n            throw error_already_set();\n        }\n        auto result = reinterpret_borrow<module_>(submodule);\n        if (doc && options::show_user_defined_docstrings()) {\n            result.attr(\"__doc__\") = pybind11::str(doc);\n        }\n        attr(name) = result;\n        return result;\n    }\n\n    /// Import and return a module or throws `error_already_set`.\n    static module_ import(const char *name) {\n        PyObject *obj = PyImport_ImportModule(name);\n        if (!obj) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<module_>(obj);\n    }\n\n    /// Reload the module or throws `error_already_set`.\n    void reload() {\n        PyObject *obj = PyImport_ReloadModule(ptr());\n        if (!obj) {\n            throw error_already_set();\n        }\n        *this = reinterpret_steal<module_>(obj);\n    }\n\n    /** \\rst\n        Adds an object to the module using the given name.  Throws if an object with the given name\n        already exists.\n\n        ``overwrite`` should almost always be false: attempting to overwrite objects that pybind11\n        has established will, in most cases, break things.\n    \\endrst */\n    PYBIND11_NOINLINE void add_object(const char *name, handle obj, bool overwrite = false) {\n        if (!overwrite && hasattr(*this, name)) {\n            pybind11_fail(\n                \"Error during initialization: multiple incompatible definitions with name \\\"\"\n                + std::string(name) + \"\\\"\");\n        }\n\n        PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);\n    }\n\n    using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)?\n\n    /** \\rst\n        Create a new top-level module that can be used as the main module of a C extension.\n\n        ``def`` should point to a statically allocated module_def.\n    \\endrst */\n    static module_ create_extension_module(const char *name, const char *doc, module_def *def) {\n        // module_def is PyModuleDef\n        // Placement new (not an allocation).\n        def = new (def)\n            PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,\n                        /* m_name */ name,\n                        /* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,\n                        /* m_size */ -1,\n                        /* m_methods */ nullptr,\n                        /* m_slots */ nullptr,\n                        /* m_traverse */ nullptr,\n                        /* m_clear */ nullptr,\n                        /* m_free */ nullptr};\n        auto *m = PyModule_Create(def);\n        if (m == nullptr) {\n            if (PyErr_Occurred()) {\n                throw error_already_set();\n            }\n            pybind11_fail(\"Internal error in module_::create_extension_module()\");\n        }\n        // TODO: Should be reinterpret_steal for Python 3, but Python also steals it again when\n        //       returned from PyInit_...\n        //       For Python 2, reinterpret_borrow was correct.\n        return reinterpret_borrow<module_>(m);\n    }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nstruct handle_type_name<module_> {\n    static constexpr auto name = const_name(\"module\");\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\n// When inside a namespace (or anywhere as long as it's not the first item on a line),\n// C++20 allows \"module\" to be used. This is provided for backward compatibility, and for\n// simplicity, if someone wants to use py::module for example, that is perfectly safe.\nusing module = module_;\n\n/// \\ingroup python_builtins\n/// Return a dictionary representing the global variables in the current execution frame,\n/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).\ninline dict globals() {\n    PyObject *p = PyEval_GetGlobals();\n    return reinterpret_borrow<dict>(p ? p : module_::import(\"__main__\").attr(\"__dict__\").ptr());\n}\n\ntemplate <typename... Args, typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>\nPYBIND11_DEPRECATED(\"make_simple_namespace should be replaced with \"\n                    \"py::module_::import(\\\"types\\\").attr(\\\"SimpleNamespace\\\") \")\nobject make_simple_namespace(Args &&...args_) {\n    return module_::import(\"types\").attr(\"SimpleNamespace\")(std::forward<Args>(args_)...);\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n/// Generic support for creating new Python heap types\nclass generic_type : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(generic_type, object, PyType_Check)\nprotected:\n    void initialize(const type_record &rec) {\n        if (rec.scope && hasattr(rec.scope, \"__dict__\")\n            && rec.scope.attr(\"__dict__\").contains(rec.name)) {\n            pybind11_fail(\"generic_type: cannot initialize type \\\"\" + std::string(rec.name)\n                          + \"\\\": an object with that name is already defined\");\n        }\n\n        if ((rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type))\n            != nullptr) {\n            pybind11_fail(\"generic_type: type \\\"\" + std::string(rec.name)\n                          + \"\\\" is already registered!\");\n        }\n\n        m_ptr = make_new_python_type(rec);\n\n        /* Register supplemental type information in C++ dict */\n        auto *tinfo = new detail::type_info();\n        tinfo->type = (PyTypeObject *) m_ptr;\n        tinfo->cpptype = rec.type;\n        tinfo->type_size = rec.type_size;\n        tinfo->type_align = rec.type_align;\n        tinfo->operator_new = rec.operator_new;\n        tinfo->holder_size_in_ptrs = size_in_ptrs(rec.holder_size);\n        tinfo->init_instance = rec.init_instance;\n        tinfo->dealloc = rec.dealloc;\n        tinfo->simple_type = true;\n        tinfo->simple_ancestors = true;\n        tinfo->default_holder = rec.default_holder;\n        tinfo->module_local = rec.module_local;\n\n        auto &internals = get_internals();\n        auto tindex = std::type_index(*rec.type);\n        tinfo->direct_conversions = &internals.direct_conversions[tindex];\n        if (rec.module_local) {\n            get_local_internals().registered_types_cpp[tindex] = tinfo;\n        } else {\n            internals.registered_types_cpp[tindex] = tinfo;\n        }\n        internals.registered_types_py[(PyTypeObject *) m_ptr] = {tinfo};\n\n        if (rec.bases.size() > 1 || rec.multiple_inheritance) {\n            mark_parents_nonsimple(tinfo->type);\n            tinfo->simple_ancestors = false;\n        } else if (rec.bases.size() == 1) {\n            auto *parent_tinfo = get_type_info((PyTypeObject *) rec.bases[0].ptr());\n            assert(parent_tinfo != nullptr);\n            bool parent_simple_ancestors = parent_tinfo->simple_ancestors;\n            tinfo->simple_ancestors = parent_simple_ancestors;\n            // The parent can no longer be a simple type if it has MI and has a child\n            parent_tinfo->simple_type = parent_tinfo->simple_type && parent_simple_ancestors;\n        }\n\n        if (rec.module_local) {\n            // Stash the local typeinfo and loader so that external modules can access it.\n            tinfo->module_local_load = &type_caster_generic::local_load;\n            setattr(m_ptr, PYBIND11_MODULE_LOCAL_ID, capsule(tinfo));\n        }\n    }\n\n    /// Helper function which tags all parents of a type using mult. inheritance\n    void mark_parents_nonsimple(PyTypeObject *value) {\n        auto t = reinterpret_borrow<tuple>(value->tp_bases);\n        for (handle h : t) {\n            auto *tinfo2 = get_type_info((PyTypeObject *) h.ptr());\n            if (tinfo2) {\n                tinfo2->simple_type = false;\n            }\n            mark_parents_nonsimple((PyTypeObject *) h.ptr());\n        }\n    }\n\n    void install_buffer_funcs(buffer_info *(*get_buffer)(PyObject *, void *),\n                              void *get_buffer_data) {\n        auto *type = (PyHeapTypeObject *) m_ptr;\n        auto *tinfo = detail::get_type_info(&type->ht_type);\n\n        if (!type->ht_type.tp_as_buffer) {\n            pybind11_fail(\"To be able to register buffer protocol support for the type '\"\n                          + get_fully_qualified_tp_name(tinfo->type)\n                          + \"' the associated class<>(..) invocation must \"\n                            \"include the pybind11::buffer_protocol() annotation!\");\n        }\n\n        tinfo->get_buffer = get_buffer;\n        tinfo->get_buffer_data = get_buffer_data;\n    }\n\n    // rec_func must be set for either fget or fset.\n    void def_property_static_impl(const char *name,\n                                  handle fget,\n                                  handle fset,\n                                  detail::function_record *rec_func) {\n        const auto is_static = (rec_func != nullptr) && !(rec_func->is_method && rec_func->scope);\n        const auto has_doc = (rec_func != nullptr) && (rec_func->doc != nullptr)\n                             && pybind11::options::show_user_defined_docstrings();\n        auto property = handle(\n            (PyObject *) (is_static ? get_internals().static_property_type : &PyProperty_Type));\n        attr(name) = property(fget.ptr() ? fget : none(),\n                              fset.ptr() ? fset : none(),\n                              /*deleter*/ none(),\n                              pybind11::str(has_doc ? rec_func->doc : \"\"));\n    }\n};\n\n/// Set the pointer to operator new if it exists. The cast is needed because it can be overloaded.\ntemplate <typename T,\n          typename = void_t<decltype(static_cast<void *(*) (size_t)>(T::operator new))>>\nvoid set_operator_new(type_record *r) {\n    r->operator_new = &T::operator new;\n}\n\ntemplate <typename>\nvoid set_operator_new(...) {}\n\ntemplate <typename T, typename SFINAE = void>\nstruct has_operator_delete : std::false_type {};\ntemplate <typename T>\nstruct has_operator_delete<T, void_t<decltype(static_cast<void (*)(void *)>(T::operator delete))>>\n    : std::true_type {};\ntemplate <typename T, typename SFINAE = void>\nstruct has_operator_delete_size : std::false_type {};\ntemplate <typename T>\nstruct has_operator_delete_size<\n    T,\n    void_t<decltype(static_cast<void (*)(void *, size_t)>(T::operator delete))>> : std::true_type {\n};\n/// Call class-specific delete if it exists or global otherwise. Can also be an overload set.\ntemplate <typename T, enable_if_t<has_operator_delete<T>::value, int> = 0>\nvoid call_operator_delete(T *p, size_t, size_t) {\n    T::operator delete(p);\n}\ntemplate <typename T,\n          enable_if_t<!has_operator_delete<T>::value && has_operator_delete_size<T>::value, int>\n          = 0>\nvoid call_operator_delete(T *p, size_t s, size_t) {\n    T::operator delete(p, s);\n}\n\ninline void call_operator_delete(void *p, size_t s, size_t a) {\n    (void) s;\n    (void) a;\n#if defined(__cpp_aligned_new) && (!defined(_MSC_VER) || _MSC_VER >= 1912)\n    if (a > __STDCPP_DEFAULT_NEW_ALIGNMENT__) {\n#    ifdef __cpp_sized_deallocation\n        ::operator delete(p, s, std::align_val_t(a));\n#    else\n        ::operator delete(p, std::align_val_t(a));\n#    endif\n        return;\n    }\n#endif\n#ifdef __cpp_sized_deallocation\n    ::operator delete(p, s);\n#else\n    ::operator delete(p);\n#endif\n}\n\ninline void add_class_method(object &cls, const char *name_, const cpp_function &cf) {\n    cls.attr(cf.name()) = cf;\n    if (std::strcmp(name_, \"__eq__\") == 0 && !cls.attr(\"__dict__\").contains(\"__hash__\")) {\n        cls.attr(\"__hash__\") = none();\n    }\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Given a pointer to a member function, cast it to its `Derived` version.\n/// Forward everything else unchanged.\ntemplate <typename /*Derived*/, typename F>\nauto method_adaptor(F &&f) -> decltype(std::forward<F>(f)) {\n    return std::forward<F>(f);\n}\n\ntemplate <typename Derived, typename Return, typename Class, typename... Args>\nauto method_adaptor(Return (Class::*pmf)(Args...)) -> Return (Derived::*)(Args...) {\n    static_assert(\n        detail::is_accessible_base_of<Class, Derived>::value,\n        \"Cannot bind an inaccessible base class method; use a lambda definition instead\");\n    return pmf;\n}\n\ntemplate <typename Derived, typename Return, typename Class, typename... Args>\nauto method_adaptor(Return (Class::*pmf)(Args...) const) -> Return (Derived::*)(Args...) const {\n    static_assert(\n        detail::is_accessible_base_of<Class, Derived>::value,\n        \"Cannot bind an inaccessible base class method; use a lambda definition instead\");\n    return pmf;\n}\n\ntemplate <typename type_, typename... options>\nclass class_ : public detail::generic_type {\n    template <typename T>\n    using is_holder = detail::is_holder_type<type_, T>;\n    template <typename T>\n    using is_subtype = detail::is_strict_base_of<type_, T>;\n    template <typename T>\n    using is_base = detail::is_strict_base_of<T, type_>;\n    // struct instead of using here to help MSVC:\n    template <typename T>\n    struct is_valid_class_option : detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};\n\npublic:\n    using type = type_;\n    using type_alias = detail::exactly_one_t<is_subtype, void, options...>;\n    constexpr static bool has_alias = !std::is_void<type_alias>::value;\n    using holder_type = detail::exactly_one_t<is_holder, std::unique_ptr<type>, options...>;\n\n    static_assert(detail::all_of<is_valid_class_option<options>...>::value,\n                  \"Unknown/invalid class_ template parameters provided\");\n\n    static_assert(!has_alias || std::is_polymorphic<type>::value,\n                  \"Cannot use an alias class with a non-polymorphic type\");\n\n    PYBIND11_OBJECT(class_, generic_type, PyType_Check)\n\n    template <typename... Extra>\n    class_(handle scope, const char *name, const Extra &...extra) {\n        using namespace detail;\n\n        // MI can only be specified via class_ template options, not constructor parameters\n        static_assert(\n            none_of<is_pyobject<Extra>...>::value || // no base class arguments, or:\n                (constexpr_sum(is_pyobject<Extra>::value...) == 1 && // Exactly one base\n                 constexpr_sum(is_base<options>::value...) == 0 &&   // no template option bases\n                 // no multiple_inheritance attr\n                 none_of<std::is_same<multiple_inheritance, Extra>...>::value),\n            \"Error: multiple inheritance bases must be specified via class_ template options\");\n\n        type_record record;\n        record.scope = scope;\n        record.name = name;\n        record.type = &typeid(type);\n        record.type_size = sizeof(conditional_t<has_alias, type_alias, type>);\n        record.type_align = alignof(conditional_t<has_alias, type_alias, type> &);\n        record.holder_size = sizeof(holder_type);\n        record.init_instance = init_instance;\n        record.dealloc = dealloc;\n        record.default_holder = detail::is_instantiation<std::unique_ptr, holder_type>::value;\n\n        set_operator_new<type>(&record);\n\n        /* Register base classes specified via template arguments to class_, if any */\n        PYBIND11_EXPAND_SIDE_EFFECTS(add_base<options>(record));\n\n        /* Process optional arguments, if any */\n        process_attributes<Extra...>::init(extra..., &record);\n\n        generic_type::initialize(record);\n\n        if (has_alias) {\n            auto &instances = record.module_local ? get_local_internals().registered_types_cpp\n                                                  : get_internals().registered_types_cpp;\n            instances[std::type_index(typeid(type_alias))]\n                = instances[std::type_index(typeid(type))];\n        }\n    }\n\n    template <typename Base, detail::enable_if_t<is_base<Base>::value, int> = 0>\n    static void add_base(detail::type_record &rec) {\n        rec.add_base(typeid(Base), [](void *src) -> void * {\n            return static_cast<Base *>(reinterpret_cast<type *>(src));\n        });\n    }\n\n    template <typename Base, detail::enable_if_t<!is_base<Base>::value, int> = 0>\n    static void add_base(detail::type_record &) {}\n\n    template <typename Func, typename... Extra>\n    class_ &def(const char *name_, Func &&f, const Extra &...extra) {\n        cpp_function cf(method_adaptor<type>(std::forward<Func>(f)),\n                        name(name_),\n                        is_method(*this),\n                        sibling(getattr(*this, name_, none())),\n                        extra...);\n        add_class_method(*this, name_, cf);\n        return *this;\n    }\n\n    template <typename Func, typename... Extra>\n    class_ &def_static(const char *name_, Func &&f, const Extra &...extra) {\n        static_assert(!std::is_member_function_pointer<Func>::value,\n                      \"def_static(...) called with a non-static member function pointer\");\n        cpp_function cf(std::forward<Func>(f),\n                        name(name_),\n                        scope(*this),\n                        sibling(getattr(*this, name_, none())),\n                        extra...);\n        auto cf_name = cf.name();\n        attr(std::move(cf_name)) = staticmethod(std::move(cf));\n        return *this;\n    }\n\n    template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>\n    class_ &def(const T &op, const Extra &...extra) {\n        op.execute(*this, extra...);\n        return *this;\n    }\n\n    template <typename T, typename... Extra, detail::enable_if_t<T::op_enable_if_hook, int> = 0>\n    class_ &def_cast(const T &op, const Extra &...extra) {\n        op.execute_cast(*this, extra...);\n        return *this;\n    }\n\n    template <typename... Args, typename... Extra>\n    class_ &def(const detail::initimpl::constructor<Args...> &init, const Extra &...extra) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(init);\n        init.execute(*this, extra...);\n        return *this;\n    }\n\n    template <typename... Args, typename... Extra>\n    class_ &def(const detail::initimpl::alias_constructor<Args...> &init, const Extra &...extra) {\n        PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(init);\n        init.execute(*this, extra...);\n        return *this;\n    }\n\n    template <typename... Args, typename... Extra>\n    class_ &def(detail::initimpl::factory<Args...> &&init, const Extra &...extra) {\n        std::move(init).execute(*this, extra...);\n        return *this;\n    }\n\n    template <typename... Args, typename... Extra>\n    class_ &def(detail::initimpl::pickle_factory<Args...> &&pf, const Extra &...extra) {\n        std::move(pf).execute(*this, extra...);\n        return *this;\n    }\n\n    template <typename Func>\n    class_ &def_buffer(Func &&func) {\n        struct capture {\n            Func func;\n        };\n        auto *ptr = new capture{std::forward<Func>(func)};\n        install_buffer_funcs(\n            [](PyObject *obj, void *ptr) -> buffer_info * {\n                detail::make_caster<type> caster;\n                if (!caster.load(obj, false)) {\n                    return nullptr;\n                }\n                return new buffer_info(((capture *) ptr)->func(std::move(caster)));\n            },\n            ptr);\n        weakref(m_ptr, cpp_function([ptr](handle wr) {\n                    delete ptr;\n                    wr.dec_ref();\n                }))\n            .release();\n        return *this;\n    }\n\n    template <typename Return, typename Class, typename... Args>\n    class_ &def_buffer(Return (Class::*func)(Args...)) {\n        return def_buffer([func](type &obj) { return (obj.*func)(); });\n    }\n\n    template <typename Return, typename Class, typename... Args>\n    class_ &def_buffer(Return (Class::*func)(Args...) const) {\n        return def_buffer([func](const type &obj) { return (obj.*func)(); });\n    }\n\n    template <typename C, typename D, typename... Extra>\n    class_ &def_readwrite(const char *name, D C::*pm, const Extra &...extra) {\n        static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,\n                      \"def_readwrite() requires a class member (or base class member)\");\n        cpp_function fget([pm](const type &c) -> const D & { return c.*pm; }, is_method(*this)),\n            fset([pm](type &c, const D &value) { c.*pm = value; }, is_method(*this));\n        def_property(name, fget, fset, return_value_policy::reference_internal, extra...);\n        return *this;\n    }\n\n    template <typename C, typename D, typename... Extra>\n    class_ &def_readonly(const char *name, const D C::*pm, const Extra &...extra) {\n        static_assert(std::is_same<C, type>::value || std::is_base_of<C, type>::value,\n                      \"def_readonly() requires a class member (or base class member)\");\n        cpp_function fget([pm](const type &c) -> const D & { return c.*pm; }, is_method(*this));\n        def_property_readonly(name, fget, return_value_policy::reference_internal, extra...);\n        return *this;\n    }\n\n    template <typename D, typename... Extra>\n    class_ &def_readwrite_static(const char *name, D *pm, const Extra &...extra) {\n        cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this)),\n            fset([pm](const object &, const D &value) { *pm = value; }, scope(*this));\n        def_property_static(name, fget, fset, return_value_policy::reference, extra...);\n        return *this;\n    }\n\n    template <typename D, typename... Extra>\n    class_ &def_readonly_static(const char *name, const D *pm, const Extra &...extra) {\n        cpp_function fget([pm](const object &) -> const D & { return *pm; }, scope(*this));\n        def_property_readonly_static(name, fget, return_value_policy::reference, extra...);\n        return *this;\n    }\n\n    /// Uses return_value_policy::reference_internal by default\n    template <typename Getter, typename... Extra>\n    class_ &def_property_readonly(const char *name, const Getter &fget, const Extra &...extra) {\n        return def_property_readonly(name,\n                                     cpp_function(method_adaptor<type>(fget)),\n                                     return_value_policy::reference_internal,\n                                     extra...);\n    }\n\n    /// Uses cpp_function's return_value_policy by default\n    template <typename... Extra>\n    class_ &\n    def_property_readonly(const char *name, const cpp_function &fget, const Extra &...extra) {\n        return def_property(name, fget, nullptr, extra...);\n    }\n\n    /// Uses return_value_policy::reference by default\n    template <typename Getter, typename... Extra>\n    class_ &\n    def_property_readonly_static(const char *name, const Getter &fget, const Extra &...extra) {\n        return def_property_readonly_static(\n            name, cpp_function(fget), return_value_policy::reference, extra...);\n    }\n\n    /// Uses cpp_function's return_value_policy by default\n    template <typename... Extra>\n    class_ &def_property_readonly_static(const char *name,\n                                         const cpp_function &fget,\n                                         const Extra &...extra) {\n        return def_property_static(name, fget, nullptr, extra...);\n    }\n\n    /// Uses return_value_policy::reference_internal by default\n    template <typename Getter, typename Setter, typename... Extra>\n    class_ &\n    def_property(const char *name, const Getter &fget, const Setter &fset, const Extra &...extra) {\n        return def_property(\n            name, fget, cpp_function(method_adaptor<type>(fset), is_setter()), extra...);\n    }\n    template <typename Getter, typename... Extra>\n    class_ &def_property(const char *name,\n                         const Getter &fget,\n                         const cpp_function &fset,\n                         const Extra &...extra) {\n        return def_property(name,\n                            cpp_function(method_adaptor<type>(fget)),\n                            fset,\n                            return_value_policy::reference_internal,\n                            extra...);\n    }\n\n    /// Uses cpp_function's return_value_policy by default\n    template <typename... Extra>\n    class_ &def_property(const char *name,\n                         const cpp_function &fget,\n                         const cpp_function &fset,\n                         const Extra &...extra) {\n        return def_property_static(name, fget, fset, is_method(*this), extra...);\n    }\n\n    /// Uses return_value_policy::reference by default\n    template <typename Getter, typename... Extra>\n    class_ &def_property_static(const char *name,\n                                const Getter &fget,\n                                const cpp_function &fset,\n                                const Extra &...extra) {\n        return def_property_static(\n            name, cpp_function(fget), fset, return_value_policy::reference, extra...);\n    }\n\n    /// Uses cpp_function's return_value_policy by default\n    template <typename... Extra>\n    class_ &def_property_static(const char *name,\n                                const cpp_function &fget,\n                                const cpp_function &fset,\n                                const Extra &...extra) {\n        static_assert(0 == detail::constexpr_sum(std::is_base_of<arg, Extra>::value...),\n                      \"Argument annotations are not allowed for properties\");\n        auto rec_fget = get_function_record(fget), rec_fset = get_function_record(fset);\n        auto *rec_active = rec_fget;\n        if (rec_fget) {\n            char *doc_prev = rec_fget->doc; /* 'extra' field may include a property-specific\n                                               documentation string */\n            detail::process_attributes<Extra...>::init(extra..., rec_fget);\n            if (rec_fget->doc && rec_fget->doc != doc_prev) {\n                std::free(doc_prev);\n                rec_fget->doc = PYBIND11_COMPAT_STRDUP(rec_fget->doc);\n            }\n        }\n        if (rec_fset) {\n            char *doc_prev = rec_fset->doc;\n            detail::process_attributes<Extra...>::init(extra..., rec_fset);\n            if (rec_fset->doc && rec_fset->doc != doc_prev) {\n                std::free(doc_prev);\n                rec_fset->doc = PYBIND11_COMPAT_STRDUP(rec_fset->doc);\n            }\n            if (!rec_active) {\n                rec_active = rec_fset;\n            }\n        }\n        def_property_static_impl(name, fget, fset, rec_active);\n        return *this;\n    }\n\nprivate:\n    /// Initialize holder object, variant 1: object derives from enable_shared_from_this\n    template <typename T>\n    static void init_holder(detail::instance *inst,\n                            detail::value_and_holder &v_h,\n                            const holder_type * /* unused */,\n                            const std::enable_shared_from_this<T> * /* dummy */) {\n\n        auto sh = std::dynamic_pointer_cast<typename holder_type::element_type>(\n            detail::try_get_shared_from_this(v_h.value_ptr<type>()));\n        if (sh) {\n            new (std::addressof(v_h.holder<holder_type>())) holder_type(std::move(sh));\n            v_h.set_holder_constructed();\n        }\n\n        if (!v_h.holder_constructed() && inst->owned) {\n            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());\n            v_h.set_holder_constructed();\n        }\n    }\n\n    static void init_holder_from_existing(const detail::value_and_holder &v_h,\n                                          const holder_type *holder_ptr,\n                                          std::true_type /*is_copy_constructible*/) {\n        new (std::addressof(v_h.holder<holder_type>()))\n            holder_type(*reinterpret_cast<const holder_type *>(holder_ptr));\n    }\n\n    static void init_holder_from_existing(const detail::value_and_holder &v_h,\n                                          const holder_type *holder_ptr,\n                                          std::false_type /*is_copy_constructible*/) {\n        new (std::addressof(v_h.holder<holder_type>()))\n            holder_type(std::move(*const_cast<holder_type *>(holder_ptr)));\n    }\n\n    /// Initialize holder object, variant 2: try to construct from existing holder object, if\n    /// possible\n    static void init_holder(detail::instance *inst,\n                            detail::value_and_holder &v_h,\n                            const holder_type *holder_ptr,\n                            const void * /* dummy -- not enable_shared_from_this<T>) */) {\n        if (holder_ptr) {\n            init_holder_from_existing(v_h, holder_ptr, std::is_copy_constructible<holder_type>());\n            v_h.set_holder_constructed();\n        } else if (detail::always_construct_holder<holder_type>::value || inst->owned) {\n            new (std::addressof(v_h.holder<holder_type>())) holder_type(v_h.value_ptr<type>());\n            v_h.set_holder_constructed();\n        }\n    }\n\n    /// Performs instance initialization including constructing a holder and registering the known\n    /// instance.  Should be called as soon as the `type` value_ptr is set for an instance.  Takes\n    /// an optional pointer to an existing holder to use; if not specified and the instance is\n    /// `.owned`, a new holder will be constructed to manage the value pointer.\n    static void init_instance(detail::instance *inst, const void *holder_ptr) {\n        auto v_h = inst->get_value_and_holder(detail::get_type_info(typeid(type)));\n        if (!v_h.instance_registered()) {\n            register_instance(inst, v_h.value_ptr(), v_h.type);\n            v_h.set_instance_registered();\n        }\n        init_holder(inst, v_h, (const holder_type *) holder_ptr, v_h.value_ptr<type>());\n    }\n\n    /// Deallocates an instance; via holder, if constructed; otherwise via operator delete.\n    static void dealloc(detail::value_and_holder &v_h) {\n        // We could be deallocating because we are cleaning up after a Python exception.\n        // If so, the Python error indicator will be set. We need to clear that before\n        // running the destructor, in case the destructor code calls more Python.\n        // If we don't, the Python API will exit with an exception, and pybind11 will\n        // throw error_already_set from the C++ destructor which is forbidden and triggers\n        // std::terminate().\n        error_scope scope;\n        if (v_h.holder_constructed()) {\n            v_h.holder<holder_type>().~holder_type();\n            v_h.set_holder_constructed(false);\n        } else {\n            detail::call_operator_delete(\n                v_h.value_ptr<type>(), v_h.type->type_size, v_h.type->type_align);\n        }\n        v_h.value_ptr() = nullptr;\n    }\n\n    static detail::function_record *get_function_record(handle h) {\n        h = detail::get_function(h);\n        if (!h) {\n            return nullptr;\n        }\n\n        handle func_self = PyCFunction_GET_SELF(h.ptr());\n        if (!func_self) {\n            throw error_already_set();\n        }\n        if (!isinstance<capsule>(func_self)) {\n            return nullptr;\n        }\n        auto cap = reinterpret_borrow<capsule>(func_self);\n        if (!detail::is_function_record_capsule(cap)) {\n            return nullptr;\n        }\n        return cap.get_pointer<detail::function_record>();\n    }\n};\n\n/// Binds an existing constructor taking arguments Args...\ntemplate <typename... Args>\ndetail::initimpl::constructor<Args...> init() {\n    return {};\n}\n/// Like `init<Args...>()`, but the instance is always constructed through the alias class (even\n/// when not inheriting on the Python side).\ntemplate <typename... Args>\ndetail::initimpl::alias_constructor<Args...> init_alias() {\n    return {};\n}\n\n/// Binds a factory function as a constructor\ntemplate <typename Func, typename Ret = detail::initimpl::factory<Func>>\nRet init(Func &&f) {\n    return {std::forward<Func>(f)};\n}\n\n/// Dual-argument factory function: the first function is called when no alias is needed, the\n/// second when an alias is needed (i.e. due to python-side inheritance).  Arguments must be\n/// identical.\ntemplate <typename CFunc, typename AFunc, typename Ret = detail::initimpl::factory<CFunc, AFunc>>\nRet init(CFunc &&c, AFunc &&a) {\n    return {std::forward<CFunc>(c), std::forward<AFunc>(a)};\n}\n\n/// Binds pickling functions `__getstate__` and `__setstate__` and ensures that the type\n/// returned by `__getstate__` is the same as the argument accepted by `__setstate__`.\ntemplate <typename GetState, typename SetState>\ndetail::initimpl::pickle_factory<GetState, SetState> pickle(GetState &&g, SetState &&s) {\n    return {std::forward<GetState>(g), std::forward<SetState>(s)};\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline str enum_name(handle arg) {\n    dict entries = arg.get_type().attr(\"__entries\");\n    for (auto kv : entries) {\n        if (handle(kv.second[int_(0)]).equal(arg)) {\n            return pybind11::str(kv.first);\n        }\n    }\n    return \"???\";\n}\n\nstruct enum_base {\n    enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) {}\n\n    PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) {\n        m_base.attr(\"__entries\") = dict();\n        auto property = handle((PyObject *) &PyProperty_Type);\n        auto static_property = handle((PyObject *) get_internals().static_property_type);\n\n        m_base.attr(\"__repr__\") = cpp_function(\n            [](const object &arg) -> str {\n                handle type = type::handle_of(arg);\n                object type_name = type.attr(\"__name__\");\n                return pybind11::str(\"<{}.{}: {}>\")\n                    .format(std::move(type_name), enum_name(arg), int_(arg));\n            },\n            name(\"__repr__\"),\n            is_method(m_base));\n\n        m_base.attr(\"name\") = property(cpp_function(&enum_name, name(\"name\"), is_method(m_base)));\n\n        m_base.attr(\"__str__\") = cpp_function(\n            [](handle arg) -> str {\n                object type_name = type::handle_of(arg).attr(\"__name__\");\n                return pybind11::str(\"{}.{}\").format(std::move(type_name), enum_name(arg));\n            },\n            name(\"__str__\"),\n            is_method(m_base));\n\n        if (options::show_enum_members_docstring()) {\n            m_base.attr(\"__doc__\") = static_property(\n                cpp_function(\n                    [](handle arg) -> std::string {\n                        std::string docstring;\n                        dict entries = arg.attr(\"__entries\");\n                        if (((PyTypeObject *) arg.ptr())->tp_doc) {\n                            docstring += std::string(\n                                reinterpret_cast<PyTypeObject *>(arg.ptr())->tp_doc);\n                            docstring += \"\\n\\n\";\n                        }\n                        docstring += \"Members:\";\n                        for (auto kv : entries) {\n                            auto key = std::string(pybind11::str(kv.first));\n                            auto comment = kv.second[int_(1)];\n                            docstring += \"\\n\\n  \";\n                            docstring += key;\n                            if (!comment.is_none()) {\n                                docstring += \" : \";\n                                docstring += pybind11::str(comment).cast<std::string>();\n                            }\n                        }\n                        return docstring;\n                    },\n                    name(\"__doc__\")),\n                none(),\n                none(),\n                \"\");\n        }\n\n        m_base.attr(\"__members__\") = static_property(cpp_function(\n                                                         [](handle arg) -> dict {\n                                                             dict entries = arg.attr(\"__entries\"),\n                                                                  m;\n                                                             for (auto kv : entries) {\n                                                                 m[kv.first] = kv.second[int_(0)];\n                                                             }\n                                                             return m;\n                                                         },\n                                                         name(\"__members__\")),\n                                                     none(),\n                                                     none(),\n                                                     \"\");\n\n#define PYBIND11_ENUM_OP_STRICT(op, expr, strict_behavior)                                        \\\n    m_base.attr(op) = cpp_function(                                                               \\\n        [](const object &a, const object &b) {                                                    \\\n            if (!type::handle_of(a).is(type::handle_of(b)))                                       \\\n                strict_behavior; /* NOLINT(bugprone-macro-parentheses) */                         \\\n            return expr;                                                                          \\\n        },                                                                                        \\\n        name(op),                                                                                 \\\n        is_method(m_base),                                                                        \\\n        arg(\"other\"))\n\n#define PYBIND11_ENUM_OP_CONV(op, expr)                                                           \\\n    m_base.attr(op) = cpp_function(                                                               \\\n        [](const object &a_, const object &b_) {                                                  \\\n            int_ a(a_), b(b_);                                                                    \\\n            return expr;                                                                          \\\n        },                                                                                        \\\n        name(op),                                                                                 \\\n        is_method(m_base),                                                                        \\\n        arg(\"other\"))\n\n#define PYBIND11_ENUM_OP_CONV_LHS(op, expr)                                                       \\\n    m_base.attr(op) = cpp_function(                                                               \\\n        [](const object &a_, const object &b) {                                                   \\\n            int_ a(a_);                                                                           \\\n            return expr;                                                                          \\\n        },                                                                                        \\\n        name(op),                                                                                 \\\n        is_method(m_base),                                                                        \\\n        arg(\"other\"))\n\n        if (is_convertible) {\n            PYBIND11_ENUM_OP_CONV_LHS(\"__eq__\", !b.is_none() && a.equal(b));\n            PYBIND11_ENUM_OP_CONV_LHS(\"__ne__\", b.is_none() || !a.equal(b));\n\n            if (is_arithmetic) {\n                PYBIND11_ENUM_OP_CONV(\"__lt__\", a < b);\n                PYBIND11_ENUM_OP_CONV(\"__gt__\", a > b);\n                PYBIND11_ENUM_OP_CONV(\"__le__\", a <= b);\n                PYBIND11_ENUM_OP_CONV(\"__ge__\", a >= b);\n                PYBIND11_ENUM_OP_CONV(\"__and__\", a & b);\n                PYBIND11_ENUM_OP_CONV(\"__rand__\", a & b);\n                PYBIND11_ENUM_OP_CONV(\"__or__\", a | b);\n                PYBIND11_ENUM_OP_CONV(\"__ror__\", a | b);\n                PYBIND11_ENUM_OP_CONV(\"__xor__\", a ^ b);\n                PYBIND11_ENUM_OP_CONV(\"__rxor__\", a ^ b);\n                m_base.attr(\"__invert__\")\n                    = cpp_function([](const object &arg) { return ~(int_(arg)); },\n                                   name(\"__invert__\"),\n                                   is_method(m_base));\n            }\n        } else {\n            PYBIND11_ENUM_OP_STRICT(\"__eq__\", int_(a).equal(int_(b)), return false);\n            PYBIND11_ENUM_OP_STRICT(\"__ne__\", !int_(a).equal(int_(b)), return true);\n\n            if (is_arithmetic) {\n#define PYBIND11_THROW throw type_error(\"Expected an enumeration of matching type!\");\n                PYBIND11_ENUM_OP_STRICT(\"__lt__\", int_(a) < int_(b), PYBIND11_THROW);\n                PYBIND11_ENUM_OP_STRICT(\"__gt__\", int_(a) > int_(b), PYBIND11_THROW);\n                PYBIND11_ENUM_OP_STRICT(\"__le__\", int_(a) <= int_(b), PYBIND11_THROW);\n                PYBIND11_ENUM_OP_STRICT(\"__ge__\", int_(a) >= int_(b), PYBIND11_THROW);\n#undef PYBIND11_THROW\n            }\n        }\n\n#undef PYBIND11_ENUM_OP_CONV_LHS\n#undef PYBIND11_ENUM_OP_CONV\n#undef PYBIND11_ENUM_OP_STRICT\n\n        m_base.attr(\"__getstate__\") = cpp_function(\n            [](const object &arg) { return int_(arg); }, name(\"__getstate__\"), is_method(m_base));\n\n        m_base.attr(\"__hash__\") = cpp_function(\n            [](const object &arg) { return int_(arg); }, name(\"__hash__\"), is_method(m_base));\n    }\n\n    PYBIND11_NOINLINE void value(char const *name_, object value, const char *doc = nullptr) {\n        dict entries = m_base.attr(\"__entries\");\n        str name(name_);\n        if (entries.contains(name)) {\n            std::string type_name = (std::string) str(m_base.attr(\"__name__\"));\n            throw value_error(std::move(type_name) + \": element \\\"\" + std::string(name_)\n                              + \"\\\" already exists!\");\n        }\n\n        entries[name] = pybind11::make_tuple(value, doc);\n        m_base.attr(std::move(name)) = std::move(value);\n    }\n\n    PYBIND11_NOINLINE void export_values() {\n        dict entries = m_base.attr(\"__entries\");\n        for (auto kv : entries) {\n            m_parent.attr(kv.first) = kv.second[int_(0)];\n        }\n    }\n\n    handle m_base;\n    handle m_parent;\n};\n\ntemplate <bool is_signed, size_t length>\nstruct equivalent_integer {};\ntemplate <>\nstruct equivalent_integer<true, 1> {\n    using type = int8_t;\n};\ntemplate <>\nstruct equivalent_integer<false, 1> {\n    using type = uint8_t;\n};\ntemplate <>\nstruct equivalent_integer<true, 2> {\n    using type = int16_t;\n};\ntemplate <>\nstruct equivalent_integer<false, 2> {\n    using type = uint16_t;\n};\ntemplate <>\nstruct equivalent_integer<true, 4> {\n    using type = int32_t;\n};\ntemplate <>\nstruct equivalent_integer<false, 4> {\n    using type = uint32_t;\n};\ntemplate <>\nstruct equivalent_integer<true, 8> {\n    using type = int64_t;\n};\ntemplate <>\nstruct equivalent_integer<false, 8> {\n    using type = uint64_t;\n};\n\ntemplate <typename IntLike>\nusing equivalent_integer_t =\n    typename equivalent_integer<std::is_signed<IntLike>::value, sizeof(IntLike)>::type;\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Binds C++ enumerations and enumeration classes to Python\ntemplate <typename Type>\nclass enum_ : public class_<Type> {\npublic:\n    using Base = class_<Type>;\n    using Base::attr;\n    using Base::def;\n    using Base::def_property_readonly;\n    using Base::def_property_readonly_static;\n    using Underlying = typename std::underlying_type<Type>::type;\n    // Scalar is the integer representation of underlying type\n    using Scalar = detail::conditional_t<detail::any_of<detail::is_std_char_type<Underlying>,\n                                                        std::is_same<Underlying, bool>>::value,\n                                         detail::equivalent_integer_t<Underlying>,\n                                         Underlying>;\n\n    template <typename... Extra>\n    enum_(const handle &scope, const char *name, const Extra &...extra)\n        : class_<Type>(scope, name, extra...), m_base(*this, scope) {\n        constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;\n        constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value;\n        m_base.init(is_arithmetic, is_convertible);\n\n        def(init([](Scalar i) { return static_cast<Type>(i); }), arg(\"value\"));\n        def_property_readonly(\"value\", [](Type value) { return (Scalar) value; });\n        def(\"__int__\", [](Type value) { return (Scalar) value; });\n        def(\"__index__\", [](Type value) { return (Scalar) value; });\n        attr(\"__setstate__\") = cpp_function(\n            [](detail::value_and_holder &v_h, Scalar arg) {\n                detail::initimpl::setstate<Base>(\n                    v_h, static_cast<Type>(arg), Py_TYPE(v_h.inst) != v_h.type->type);\n            },\n            detail::is_new_style_constructor(),\n            pybind11::name(\"__setstate__\"),\n            is_method(*this),\n            arg(\"state\"));\n    }\n\n    /// Export enumeration entries into the parent scope\n    enum_ &export_values() {\n        m_base.export_values();\n        return *this;\n    }\n\n    /// Add an enumeration entry\n    enum_ &value(char const *name, Type value, const char *doc = nullptr) {\n        m_base.value(name, pybind11::cast(value, return_value_policy::copy), doc);\n        return *this;\n    }\n\nprivate:\n    detail::enum_base m_base;\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\nPYBIND11_NOINLINE void keep_alive_impl(handle nurse, handle patient) {\n    if (!nurse || !patient) {\n        pybind11_fail(\"Could not activate keep_alive!\");\n    }\n\n    if (patient.is_none() || nurse.is_none()) {\n        return; /* Nothing to keep alive or nothing to be kept alive by */\n    }\n\n    auto tinfo = all_type_info(Py_TYPE(nurse.ptr()));\n    if (!tinfo.empty()) {\n        /* It's a pybind-registered type, so we can store the patient in the\n         * internal list. */\n        add_patient(nurse.ptr(), patient.ptr());\n    } else {\n        /* Fall back to clever approach based on weak references taken from\n         * Boost.Python. This is not used for pybind-registered types because\n         * the objects can be destroyed out-of-order in a GC pass. */\n        cpp_function disable_lifesupport([patient](handle weakref) {\n            patient.dec_ref();\n            weakref.dec_ref();\n        });\n\n        weakref wr(nurse, disable_lifesupport);\n\n        patient.inc_ref(); /* reference patient and leak the weak reference */\n        (void) wr.release();\n    }\n}\n\nPYBIND11_NOINLINE void\nkeep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret) {\n    auto get_arg = [&](size_t n) {\n        if (n == 0) {\n            return ret;\n        }\n        if (n == 1 && call.init_self) {\n            return call.init_self;\n        }\n        if (n <= call.args.size()) {\n            return call.args[n - 1];\n        }\n        return handle();\n    };\n\n    keep_alive_impl(get_arg(Nurse), get_arg(Patient));\n}\n\ninline std::pair<decltype(internals::registered_types_py)::iterator, bool>\nall_type_info_get_cache(PyTypeObject *type) {\n    auto res = get_internals()\n                   .registered_types_py\n#ifdef __cpp_lib_unordered_map_try_emplace\n                   .try_emplace(type);\n#else\n                   .emplace(type, std::vector<detail::type_info *>());\n#endif\n    if (res.second) {\n        // New cache entry created; set up a weak reference to automatically remove it if the type\n        // gets destroyed:\n        weakref((PyObject *) type, cpp_function([type](handle wr) {\n                    get_internals().registered_types_py.erase(type);\n\n                    // TODO consolidate the erasure code in pybind11_meta_dealloc() in class.h\n                    auto &cache = get_internals().inactive_override_cache;\n                    for (auto it = cache.begin(), last = cache.end(); it != last;) {\n                        if (it->first == reinterpret_cast<PyObject *>(type)) {\n                            it = cache.erase(it);\n                        } else {\n                            ++it;\n                        }\n                    }\n\n                    wr.dec_ref();\n                }))\n            .release();\n    }\n\n    return res;\n}\n\n/* There are a large number of apparently unused template arguments because\n * each combination requires a separate py::class_ registration.\n */\ntemplate <typename Access,\n          return_value_policy Policy,\n          typename Iterator,\n          typename Sentinel,\n          typename ValueType,\n          typename... Extra>\nstruct iterator_state {\n    Iterator it;\n    Sentinel end;\n    bool first_or_done;\n};\n\n// Note: these helpers take the iterator by non-const reference because some\n// iterators in the wild can't be dereferenced when const. The & after Iterator\n// is required for MSVC < 16.9. SFINAE cannot be reused for result_type due to\n// bugs in ICC, NVCC, and PGI compilers. See PR #3293.\ntemplate <typename Iterator, typename SFINAE = decltype(*std::declval<Iterator &>())>\nstruct iterator_access {\n    using result_type = decltype(*std::declval<Iterator &>());\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    result_type operator()(Iterator &it) const { return *it; }\n};\n\ntemplate <typename Iterator, typename SFINAE = decltype((*std::declval<Iterator &>()).first)>\nclass iterator_key_access {\nprivate:\n    using pair_type = decltype(*std::declval<Iterator &>());\n\npublic:\n    /* If either the pair itself or the element of the pair is a reference, we\n     * want to return a reference, otherwise a value. When the decltype\n     * expression is parenthesized it is based on the value category of the\n     * expression; otherwise it is the declared type of the pair member.\n     * The use of declval<pair_type> in the second branch rather than directly\n     * using *std::declval<Iterator &>() is a workaround for nvcc\n     * (it's not used in the first branch because going via decltype and back\n     * through declval does not perfectly preserve references).\n     */\n    using result_type\n        = conditional_t<std::is_reference<decltype(*std::declval<Iterator &>())>::value,\n                        decltype(((*std::declval<Iterator &>()).first)),\n                        decltype(std::declval<pair_type>().first)>;\n    result_type operator()(Iterator &it) const { return (*it).first; }\n};\n\ntemplate <typename Iterator, typename SFINAE = decltype((*std::declval<Iterator &>()).second)>\nclass iterator_value_access {\nprivate:\n    using pair_type = decltype(*std::declval<Iterator &>());\n\npublic:\n    using result_type\n        = conditional_t<std::is_reference<decltype(*std::declval<Iterator &>())>::value,\n                        decltype(((*std::declval<Iterator &>()).second)),\n                        decltype(std::declval<pair_type>().second)>;\n    result_type operator()(Iterator &it) const { return (*it).second; }\n};\n\ntemplate <typename Access,\n          return_value_policy Policy,\n          typename Iterator,\n          typename Sentinel,\n          typename ValueType,\n          typename... Extra>\niterator make_iterator_impl(Iterator first, Sentinel last, Extra &&...extra) {\n    using state = detail::iterator_state<Access, Policy, Iterator, Sentinel, ValueType, Extra...>;\n    // TODO: state captures only the types of Extra, not the values\n\n    if (!detail::get_type_info(typeid(state), false)) {\n        class_<state>(handle(), \"iterator\", pybind11::module_local())\n            .def(\"__iter__\", [](state &s) -> state & { return s; })\n            .def(\n                \"__next__\",\n                [](state &s) -> ValueType {\n                    if (!s.first_or_done) {\n                        ++s.it;\n                    } else {\n                        s.first_or_done = false;\n                    }\n                    if (s.it == s.end) {\n                        s.first_or_done = true;\n                        throw stop_iteration();\n                    }\n                    return Access()(s.it);\n                    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n                },\n                std::forward<Extra>(extra)...,\n                Policy);\n    }\n\n    return cast(state{std::forward<Iterator>(first), std::forward<Sentinel>(last), true});\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Makes a python iterator from a first and past-the-end C++ InputIterator.\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Iterator,\n          typename Sentinel,\n          typename ValueType = typename detail::iterator_access<Iterator>::result_type,\n          typename... Extra>\ntyping::Iterator<ValueType> make_iterator(Iterator first, Sentinel last, Extra &&...extra) {\n    return detail::make_iterator_impl<detail::iterator_access<Iterator>,\n                                      Policy,\n                                      Iterator,\n                                      Sentinel,\n                                      ValueType,\n                                      Extra...>(std::forward<Iterator>(first),\n                                                std::forward<Sentinel>(last),\n                                                std::forward<Extra>(extra)...);\n}\n\n/// Makes a python iterator over the keys (`.first`) of a iterator over pairs from a\n/// first and past-the-end InputIterator.\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Iterator,\n          typename Sentinel,\n          typename KeyType = typename detail::iterator_key_access<Iterator>::result_type,\n          typename... Extra>\ntyping::Iterator<KeyType> make_key_iterator(Iterator first, Sentinel last, Extra &&...extra) {\n    return detail::make_iterator_impl<detail::iterator_key_access<Iterator>,\n                                      Policy,\n                                      Iterator,\n                                      Sentinel,\n                                      KeyType,\n                                      Extra...>(std::forward<Iterator>(first),\n                                                std::forward<Sentinel>(last),\n                                                std::forward<Extra>(extra)...);\n}\n\n/// Makes a python iterator over the values (`.second`) of a iterator over pairs from a\n/// first and past-the-end InputIterator.\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Iterator,\n          typename Sentinel,\n          typename ValueType = typename detail::iterator_value_access<Iterator>::result_type,\n          typename... Extra>\ntyping::Iterator<ValueType> make_value_iterator(Iterator first, Sentinel last, Extra &&...extra) {\n    return detail::make_iterator_impl<detail::iterator_value_access<Iterator>,\n                                      Policy,\n                                      Iterator,\n                                      Sentinel,\n                                      ValueType,\n                                      Extra...>(std::forward<Iterator>(first),\n                                                std::forward<Sentinel>(last),\n                                                std::forward<Extra>(extra)...);\n}\n\n/// Makes an iterator over values of an stl container or other container supporting\n/// `std::begin()`/`std::end()`\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Type,\n          typename ValueType = typename detail::iterator_access<\n              decltype(std::begin(std::declval<Type &>()))>::result_type,\n          typename... Extra>\ntyping::Iterator<ValueType> make_iterator(Type &value, Extra &&...extra) {\n    return make_iterator<Policy>(\n        std::begin(value), std::end(value), std::forward<Extra>(extra)...);\n}\n\n/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting\n/// `std::begin()`/`std::end()`\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Type,\n          typename KeyType = typename detail::iterator_key_access<\n              decltype(std::begin(std::declval<Type &>()))>::result_type,\n          typename... Extra>\ntyping::Iterator<KeyType> make_key_iterator(Type &value, Extra &&...extra) {\n    return make_key_iterator<Policy>(\n        std::begin(value), std::end(value), std::forward<Extra>(extra)...);\n}\n\n/// Makes an iterator over the values (`.second`) of a stl map-like container supporting\n/// `std::begin()`/`std::end()`\ntemplate <return_value_policy Policy = return_value_policy::reference_internal,\n          typename Type,\n          typename ValueType = typename detail::iterator_value_access<\n              decltype(std::begin(std::declval<Type &>()))>::result_type,\n          typename... Extra>\ntyping::Iterator<ValueType> make_value_iterator(Type &value, Extra &&...extra) {\n    return make_value_iterator<Policy>(\n        std::begin(value), std::end(value), std::forward<Extra>(extra)...);\n}\n\ntemplate <typename InputType, typename OutputType>\nvoid implicitly_convertible() {\n    struct set_flag {\n        bool &flag;\n        explicit set_flag(bool &flag_) : flag(flag_) { flag_ = true; }\n        ~set_flag() { flag = false; }\n    };\n    auto implicit_caster = [](PyObject *obj, PyTypeObject *type) -> PyObject * {\n        static bool currently_used = false;\n        if (currently_used) { // implicit conversions are non-reentrant\n            return nullptr;\n        }\n        set_flag flag_helper(currently_used);\n        if (!detail::make_caster<InputType>().load(obj, false)) {\n            return nullptr;\n        }\n        tuple args(1);\n        args[0] = obj;\n        PyObject *result = PyObject_Call((PyObject *) type, args.ptr(), nullptr);\n        if (result == nullptr) {\n            PyErr_Clear();\n        }\n        return result;\n    };\n\n    if (auto *tinfo = detail::get_type_info(typeid(OutputType))) {\n        tinfo->implicit_conversions.emplace_back(std::move(implicit_caster));\n    } else {\n        pybind11_fail(\"implicitly_convertible: Unable to find type \" + type_id<OutputType>());\n    }\n}\n\ninline void register_exception_translator(ExceptionTranslator &&translator) {\n    detail::get_internals().registered_exception_translators.push_front(\n        std::forward<ExceptionTranslator>(translator));\n}\n\n/**\n * Add a new module-local exception translator. Locally registered functions\n * will be tried before any globally registered exception translators, which\n * will only be invoked if the module-local handlers do not deal with\n * the exception.\n */\ninline void register_local_exception_translator(ExceptionTranslator &&translator) {\n    detail::get_local_internals().registered_exception_translators.push_front(\n        std::forward<ExceptionTranslator>(translator));\n}\n\n/**\n * Wrapper to generate a new Python exception type.\n *\n * This should only be used with py::set_error() for now.\n * It is not (yet) possible to use as a py::base.\n * Template type argument is reserved for future use.\n */\ntemplate <typename type>\nclass exception : public object {\npublic:\n    exception() = default;\n    exception(handle scope, const char *name, handle base = PyExc_Exception) {\n        std::string full_name\n            = scope.attr(\"__name__\").cast<std::string>() + std::string(\".\") + name;\n        m_ptr = PyErr_NewException(const_cast<char *>(full_name.c_str()), base.ptr(), nullptr);\n        if (hasattr(scope, \"__dict__\") && scope.attr(\"__dict__\").contains(name)) {\n            pybind11_fail(\"Error during initialization: multiple incompatible \"\n                          \"definitions with name \\\"\"\n                          + std::string(name) + \"\\\"\");\n        }\n        scope.attr(name) = *this;\n    }\n\n    // Sets the current python exception to this exception object with the given message\n    PYBIND11_DEPRECATED(\"Please use py::set_error() instead \"\n                        \"(https://github.com/pybind/pybind11/pull/4772)\")\n    void operator()(const char *message) const { set_error(*this, message); }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nstruct handle_type_name<exception<void>> {\n    static constexpr auto name = const_name(\"Exception\");\n};\n\n// Helper function for register_exception and register_local_exception\ntemplate <typename CppException>\nexception<CppException> &\nregister_exception_impl(handle scope, const char *name, handle base, bool isLocal) {\n    PYBIND11_CONSTINIT static gil_safe_call_once_and_store<exception<CppException>> exc_storage;\n    exc_storage.call_once_and_store_result(\n        [&]() { return exception<CppException>(scope, name, base); });\n\n    auto register_func\n        = isLocal ? &register_local_exception_translator : &register_exception_translator;\n\n    register_func([](std::exception_ptr p) {\n        if (!p) {\n            return;\n        }\n        try {\n            std::rethrow_exception(p);\n        } catch (const CppException &e) {\n            set_error(exc_storage.get_stored(), e.what());\n        }\n    });\n    return exc_storage.get_stored();\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/**\n * Registers a Python exception in `m` of the given `name` and installs a translator to\n * translate the C++ exception to the created Python exception using the what() method.\n * This is intended for simple exception translations; for more complex translation, register the\n * exception object and translator directly.\n */\ntemplate <typename CppException>\nexception<CppException> &\nregister_exception(handle scope, const char *name, handle base = PyExc_Exception) {\n    return detail::register_exception_impl<CppException>(scope, name, base, false /* isLocal */);\n}\n\n/**\n * Registers a Python exception in `m` of the given `name` and installs a translator to\n * translate the C++ exception to the created Python exception using the what() method.\n * This translator will only be used for exceptions that are thrown in this module and will be\n * tried before global exception translators, including those registered with register_exception.\n * This is intended for simple exception translations; for more complex translation, register the\n * exception object and translator directly.\n */\ntemplate <typename CppException>\nexception<CppException> &\nregister_local_exception(handle scope, const char *name, handle base = PyExc_Exception) {\n    return detail::register_exception_impl<CppException>(scope, name, base, true /* isLocal */);\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\nPYBIND11_NOINLINE void print(const tuple &args, const dict &kwargs) {\n    auto strings = tuple(args.size());\n    for (size_t i = 0; i < args.size(); ++i) {\n        strings[i] = str(args[i]);\n    }\n    auto sep = kwargs.contains(\"sep\") ? kwargs[\"sep\"] : str(\" \");\n    auto line = sep.attr(\"join\")(std::move(strings));\n\n    object file;\n    if (kwargs.contains(\"file\")) {\n        file = kwargs[\"file\"].cast<object>();\n    } else {\n        try {\n            file = module_::import(\"sys\").attr(\"stdout\");\n        } catch (const error_already_set &) {\n            /* If print() is called from code that is executed as\n               part of garbage collection during interpreter shutdown,\n               importing 'sys' can fail. Give up rather than crashing the\n               interpreter in this case. */\n            return;\n        }\n    }\n\n    auto write = file.attr(\"write\");\n    write(std::move(line));\n    write(kwargs.contains(\"end\") ? kwargs[\"end\"] : str(\"\\n\"));\n\n    if (kwargs.contains(\"flush\") && kwargs[\"flush\"].cast<bool>()) {\n        file.attr(\"flush\")();\n    }\n}\nPYBIND11_NAMESPACE_END(detail)\n\ntemplate <return_value_policy policy = return_value_policy::automatic_reference, typename... Args>\nvoid print(Args &&...args) {\n    auto c = detail::collect_arguments<policy>(std::forward<Args>(args)...);\n    detail::print(c.args(), c.kwargs());\n}\n\ninline void\nerror_already_set::m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr) {\n    gil_scoped_acquire gil;\n    error_scope scope;\n    delete raw_ptr;\n}\n\ninline const char *error_already_set::what() const noexcept {\n    gil_scoped_acquire gil;\n    error_scope scope;\n    return m_fetched_error->error_string().c_str();\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ninline function\nget_type_override(const void *this_ptr, const type_info *this_type, const char *name) {\n    handle self = get_object_handle(this_ptr, this_type);\n    if (!self) {\n        return function();\n    }\n    handle type = type::handle_of(self);\n    auto key = std::make_pair(type.ptr(), name);\n\n    /* Cache functions that aren't overridden in Python to avoid\n       many costly Python dictionary lookups below */\n    auto &cache = get_internals().inactive_override_cache;\n    if (cache.find(key) != cache.end()) {\n        return function();\n    }\n\n    function override = getattr(self, name, function());\n    if (override.is_cpp_function()) {\n        cache.insert(std::move(key));\n        return function();\n    }\n\n    /* Don't call dispatch code if invoked from overridden function.\n       Unfortunately this doesn't work on PyPy. */\n#if !defined(PYPY_VERSION)\n#    if PY_VERSION_HEX >= 0x03090000\n    PyFrameObject *frame = PyThreadState_GetFrame(PyThreadState_Get());\n    if (frame != nullptr) {\n        PyCodeObject *f_code = PyFrame_GetCode(frame);\n        // f_code is guaranteed to not be NULL\n        if ((std::string) str(f_code->co_name) == name && f_code->co_argcount > 0) {\n            PyObject *locals = PyEval_GetLocals();\n            if (locals != nullptr) {\n#        if PY_VERSION_HEX >= 0x030b0000\n                PyObject *co_varnames = PyCode_GetVarnames(f_code);\n#        else\n                PyObject *co_varnames = PyObject_GetAttrString((PyObject *) f_code, \"co_varnames\");\n#        endif\n                PyObject *self_arg = PyTuple_GET_ITEM(co_varnames, 0);\n                Py_DECREF(co_varnames);\n                PyObject *self_caller = dict_getitem(locals, self_arg);\n                if (self_caller == self.ptr()) {\n                    Py_DECREF(f_code);\n                    Py_DECREF(frame);\n                    return function();\n                }\n            }\n        }\n        Py_DECREF(f_code);\n        Py_DECREF(frame);\n    }\n#    else\n    PyFrameObject *frame = PyThreadState_Get()->frame;\n    if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name\n        && frame->f_code->co_argcount > 0) {\n        PyFrame_FastToLocals(frame);\n        PyObject *self_caller\n            = dict_getitem(frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));\n        if (self_caller == self.ptr()) {\n            return function();\n        }\n    }\n#    endif\n\n#else\n    /* PyPy currently doesn't provide a detailed cpyext emulation of\n       frame objects, so we have to emulate this using Python. This\n       is going to be slow..*/\n    dict d;\n    d[\"self\"] = self;\n    d[\"name\"] = pybind11::str(name);\n    PyObject *result\n        = PyRun_String(\"import inspect\\n\"\n                       \"frame = inspect.currentframe()\\n\"\n                       \"if frame is not None:\\n\"\n                       \"    frame = frame.f_back\\n\"\n                       \"    if frame is not None and str(frame.f_code.co_name) == name and \"\n                       \"frame.f_code.co_argcount > 0:\\n\"\n                       \"        self_caller = frame.f_locals[frame.f_code.co_varnames[0]]\\n\"\n                       \"        if self_caller == self:\\n\"\n                       \"            self = None\\n\",\n                       Py_file_input,\n                       d.ptr(),\n                       d.ptr());\n    if (result == nullptr)\n        throw error_already_set();\n    Py_DECREF(result);\n    if (d[\"self\"].is_none())\n        return function();\n#endif\n\n    return override;\n}\nPYBIND11_NAMESPACE_END(detail)\n\n/** \\rst\n  Try to retrieve a python method by the provided name from the instance pointed to by the\n  this_ptr.\n\n  :this_ptr: The pointer to the object the overridden method should be retrieved for. This should\n             be the first non-trampoline class encountered in the inheritance chain.\n  :name: The name of the overridden Python method to retrieve.\n  :return: The Python method by this name from the object or an empty function wrapper.\n \\endrst */\ntemplate <class T>\nfunction get_override(const T *this_ptr, const char *name) {\n    auto *tinfo = detail::get_type_info(typeid(T));\n    return tinfo ? detail::get_type_override(this_ptr, tinfo, name) : function();\n}\n\n#define PYBIND11_OVERRIDE_IMPL(ret_type, cname, name, ...)                                        \\\n    do {                                                                                          \\\n        pybind11::gil_scoped_acquire gil;                                                         \\\n        pybind11::function override                                                               \\\n            = pybind11::get_override(static_cast<const cname *>(this), name);                     \\\n        if (override) {                                                                           \\\n            auto o = override(__VA_ARGS__);                                                       \\\n            if (pybind11::detail::cast_is_temporary_value_reference<ret_type>::value) {           \\\n                static pybind11::detail::override_caster_t<ret_type> caster;                      \\\n                return pybind11::detail::cast_ref<ret_type>(std::move(o), caster);                \\\n            }                                                                                     \\\n            return pybind11::detail::cast_safe<ret_type>(std::move(o));                           \\\n        }                                                                                         \\\n    } while (false)\n\n/** \\rst\n    Macro to populate the virtual method in the trampoline class. This macro tries to look up a\n    method named 'fn' from the Python side, deals with the :ref:`gil` and necessary argument\n    conversions to call this method and return the appropriate type.\n    See :ref:`overriding_virtuals` for more information. This macro should be used when the method\n    name in C is not the same as the method name in Python. For example with `__str__`.\n\n    .. code-block:: cpp\n\n      std::string toString() override {\n        PYBIND11_OVERRIDE_NAME(\n            std::string, // Return type (ret_type)\n            Animal,      // Parent class (cname)\n            \"__str__\",   // Name of method in Python (name)\n            toString,    // Name of function in C++ (fn)\n        );\n      }\n\\endrst */\n#define PYBIND11_OVERRIDE_NAME(ret_type, cname, name, fn, ...)                                    \\\n    do {                                                                                          \\\n        PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \\\n        return cname::fn(__VA_ARGS__);                                                            \\\n    } while (false)\n\n/** \\rst\n    Macro for pure virtual functions, this function is identical to\n    :c:macro:`PYBIND11_OVERRIDE_NAME`, except that it throws if no override can be found.\n\\endrst */\n#define PYBIND11_OVERRIDE_PURE_NAME(ret_type, cname, name, fn, ...)                               \\\n    do {                                                                                          \\\n        PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \\\n        pybind11::pybind11_fail(                                                                  \\\n            \"Tried to call pure virtual function \\\"\" PYBIND11_STRINGIFY(cname) \"::\" name \"\\\"\");   \\\n    } while (false)\n\n/** \\rst\n    Macro to populate the virtual method in the trampoline class. This macro tries to look up the\n    method from the Python side, deals with the :ref:`gil` and necessary argument conversions to\n    call this method and return the appropriate type. This macro should be used if the method name\n    in C and in Python are identical.\n    See :ref:`overriding_virtuals` for more information.\n\n    .. code-block:: cpp\n\n      class PyAnimal : public Animal {\n      public:\n          // Inherit the constructors\n          using Animal::Animal;\n\n          // Trampoline (need one for each virtual function)\n          std::string go(int n_times) override {\n              PYBIND11_OVERRIDE_PURE(\n                  std::string, // Return type (ret_type)\n                  Animal,      // Parent class (cname)\n                  go,          // Name of function in C++ (must match Python name) (fn)\n                  n_times      // Argument(s) (...)\n              );\n          }\n      };\n\\endrst */\n#define PYBIND11_OVERRIDE(ret_type, cname, fn, ...)                                               \\\n    PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)\n\n/** \\rst\n    Macro for pure virtual functions, this function is identical to :c:macro:`PYBIND11_OVERRIDE`,\n    except that it throws if no override can be found.\n\\endrst */\n#define PYBIND11_OVERRIDE_PURE(ret_type, cname, fn, ...)                                          \\\n    PYBIND11_OVERRIDE_PURE_NAME(                                                                  \\\n        PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__)\n\n// Deprecated versions\n\nPYBIND11_DEPRECATED(\"get_type_overload has been deprecated\")\ninline function\nget_type_overload(const void *this_ptr, const detail::type_info *this_type, const char *name) {\n    return detail::get_type_override(this_ptr, this_type, name);\n}\n\ntemplate <class T>\ninline function get_overload(const T *this_ptr, const char *name) {\n    return get_override(this_ptr, name);\n}\n\n#define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...)                                         \\\n    PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__)\n#define PYBIND11_OVERLOAD_NAME(ret_type, cname, name, fn, ...)                                    \\\n    PYBIND11_OVERRIDE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__)\n#define PYBIND11_OVERLOAD_PURE_NAME(ret_type, cname, name, fn, ...)                               \\\n    PYBIND11_OVERRIDE_PURE_NAME(                                                                  \\\n        PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, fn, __VA_ARGS__);\n#define PYBIND11_OVERLOAD(ret_type, cname, fn, ...)                                               \\\n    PYBIND11_OVERRIDE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__)\n#define PYBIND11_OVERLOAD_PURE(ret_type, cname, fn, ...)                                          \\\n    PYBIND11_OVERRIDE_PURE(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), fn, __VA_ARGS__);\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/pytypes.h",
    "content": "/*\n    pybind11/pytypes.h: Convenience wrapper classes for basic Python types\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"buffer_info.h\"\n\n#include <assert.h>\n#include <cstddef>\n#include <exception>\n#include <frameobject.h>\n#include <iterator>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <typeinfo>\n#include <utility>\n\n#if defined(PYBIND11_HAS_OPTIONAL)\n#    include <optional>\n#endif\n\n#ifdef PYBIND11_HAS_STRING_VIEW\n#    include <string_view>\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\n\nPYBIND11_WARNING_DISABLE_MSVC(4127)\n\n/* A few forward declarations */\nclass handle;\nclass object;\nclass str;\nclass iterator;\nclass type;\nstruct arg;\nstruct arg_v;\n\nPYBIND11_NAMESPACE_BEGIN(detail)\nclass args_proxy;\nbool isinstance_generic(handle obj, const std::type_info &tp);\n\n// Accessor forward declarations\ntemplate <typename Policy>\nclass accessor;\nnamespace accessor_policies {\nstruct obj_attr;\nstruct str_attr;\nstruct generic_item;\nstruct sequence_item;\nstruct list_item;\nstruct tuple_item;\n} // namespace accessor_policies\n// PLEASE KEEP handle_type_name SPECIALIZATIONS IN SYNC.\nusing obj_attr_accessor = accessor<accessor_policies::obj_attr>;\nusing str_attr_accessor = accessor<accessor_policies::str_attr>;\nusing item_accessor = accessor<accessor_policies::generic_item>;\nusing sequence_accessor = accessor<accessor_policies::sequence_item>;\nusing list_accessor = accessor<accessor_policies::list_item>;\nusing tuple_accessor = accessor<accessor_policies::tuple_item>;\n\n/// Tag and check to identify a class which implements the Python object API\nclass pyobject_tag {};\ntemplate <typename T>\nusing is_pyobject = std::is_base_of<pyobject_tag, remove_reference_t<T>>;\n\n/** \\rst\n    A mixin class which adds common functions to `handle`, `object` and various accessors.\n    The only requirement for `Derived` is to implement ``PyObject *Derived::ptr() const``.\n\\endrst */\ntemplate <typename Derived>\nclass object_api : public pyobject_tag {\n    const Derived &derived() const { return static_cast<const Derived &>(*this); }\n\npublic:\n    /** \\rst\n        Return an iterator equivalent to calling ``iter()`` in Python. The object\n        must be a collection which supports the iteration protocol.\n    \\endrst */\n    iterator begin() const;\n    /// Return a sentinel which ends iteration.\n    iterator end() const;\n\n    /** \\rst\n        Return an internal functor to invoke the object's sequence protocol. Casting\n        the returned ``detail::item_accessor`` instance to a `handle` or `object`\n        subclass causes a corresponding call to ``__getitem__``. Assigning a `handle`\n        or `object` subclass causes a call to ``__setitem__``.\n    \\endrst */\n    item_accessor operator[](handle key) const;\n    /// See above (the only difference is that the key's reference is stolen)\n    item_accessor operator[](object &&key) const;\n    /// See above (the only difference is that the key is provided as a string literal)\n    item_accessor operator[](const char *key) const;\n\n    /** \\rst\n        Return an internal functor to access the object's attributes. Casting the\n        returned ``detail::obj_attr_accessor`` instance to a `handle` or `object`\n        subclass causes a corresponding call to ``getattr``. Assigning a `handle`\n        or `object` subclass causes a call to ``setattr``.\n    \\endrst */\n    obj_attr_accessor attr(handle key) const;\n    /// See above (the only difference is that the key's reference is stolen)\n    obj_attr_accessor attr(object &&key) const;\n    /// See above (the only difference is that the key is provided as a string literal)\n    str_attr_accessor attr(const char *key) const;\n\n    /** \\rst\n        Matches * unpacking in Python, e.g. to unpack arguments out of a ``tuple``\n        or ``list`` for a function call. Applying another * to the result yields\n        ** unpacking, e.g. to unpack a dict as function keyword arguments.\n        See :ref:`calling_python_functions`.\n    \\endrst */\n    args_proxy operator*() const;\n\n    /// Check if the given item is contained within this object, i.e. ``item in obj``.\n    template <typename T>\n    bool contains(T &&item) const;\n\n    /** \\rst\n        Assuming the Python object is a function or implements the ``__call__``\n        protocol, ``operator()`` invokes the underlying function, passing an\n        arbitrary set of parameters. The result is returned as a `object` and\n        may need to be converted back into a Python object using `handle::cast()`.\n\n        When some of the arguments cannot be converted to Python objects, the\n        function will throw a `cast_error` exception. When the Python function\n        call fails, a `error_already_set` exception is thrown.\n    \\endrst */\n    template <return_value_policy policy = return_value_policy::automatic_reference,\n              typename... Args>\n    object operator()(Args &&...args) const;\n    template <return_value_policy policy = return_value_policy::automatic_reference,\n              typename... Args>\n    PYBIND11_DEPRECATED(\"call(...) was deprecated in favor of operator()(...)\")\n    object call(Args &&...args) const;\n\n    /// Equivalent to ``obj is other`` in Python.\n    bool is(object_api const &other) const { return derived().ptr() == other.derived().ptr(); }\n    /// Equivalent to ``obj is None`` in Python.\n    bool is_none() const { return derived().ptr() == Py_None; }\n    /// Equivalent to obj == other in Python\n    bool equal(object_api const &other) const { return rich_compare(other, Py_EQ); }\n    bool not_equal(object_api const &other) const { return rich_compare(other, Py_NE); }\n    bool operator<(object_api const &other) const { return rich_compare(other, Py_LT); }\n    bool operator<=(object_api const &other) const { return rich_compare(other, Py_LE); }\n    bool operator>(object_api const &other) const { return rich_compare(other, Py_GT); }\n    bool operator>=(object_api const &other) const { return rich_compare(other, Py_GE); }\n\n    object operator-() const;\n    object operator~() const;\n    object operator+(object_api const &other) const;\n    object operator+=(object_api const &other);\n    object operator-(object_api const &other) const;\n    object operator-=(object_api const &other);\n    object operator*(object_api const &other) const;\n    object operator*=(object_api const &other);\n    object operator/(object_api const &other) const;\n    object operator/=(object_api const &other);\n    object operator|(object_api const &other) const;\n    object operator|=(object_api const &other);\n    object operator&(object_api const &other) const;\n    object operator&=(object_api const &other);\n    object operator^(object_api const &other) const;\n    object operator^=(object_api const &other);\n    object operator<<(object_api const &other) const;\n    object operator<<=(object_api const &other);\n    object operator>>(object_api const &other) const;\n    object operator>>=(object_api const &other);\n\n    PYBIND11_DEPRECATED(\"Use py::str(obj) instead\")\n    pybind11::str str() const;\n\n    /// Get or set the object's docstring, i.e. ``obj.__doc__``.\n    str_attr_accessor doc() const;\n\n    /// Return the object's current reference count\n    int ref_count() const { return static_cast<int>(Py_REFCNT(derived().ptr())); }\n\n    // TODO PYBIND11_DEPRECATED(\n    //     \"Call py::type::handle_of(h) or py::type::of(h) instead of h.get_type()\")\n    handle get_type() const;\n\nprivate:\n    bool rich_compare(object_api const &other, int value) const;\n};\n\ntemplate <typename T>\nusing is_pyobj_ptr_or_nullptr_t = detail::any_of<std::is_same<T, PyObject *>,\n                                                 std::is_same<T, PyObject *const>,\n                                                 std::is_same<T, std::nullptr_t>>;\n\nPYBIND11_NAMESPACE_END(detail)\n\n#if !defined(PYBIND11_HANDLE_REF_DEBUG) && !defined(NDEBUG)\n#    define PYBIND11_HANDLE_REF_DEBUG\n#endif\n\n/** \\rst\n    Holds a reference to a Python object (no reference counting)\n\n    The `handle` class is a thin wrapper around an arbitrary Python object (i.e. a\n    ``PyObject *`` in Python's C API). It does not perform any automatic reference\n    counting and merely provides a basic C++ interface to various Python API functions.\n\n    .. seealso::\n        The `object` class inherits from `handle` and adds automatic reference\n        counting features.\n\\endrst */\nclass handle : public detail::object_api<handle> {\npublic:\n    /// The default constructor creates a handle with a ``nullptr``-valued pointer\n    handle() = default;\n\n    /// Enable implicit conversion from ``PyObject *`` and ``nullptr``.\n    /// Not using ``handle(PyObject *ptr)`` to avoid implicit conversion from ``0``.\n    template <typename T,\n              detail::enable_if_t<detail::is_pyobj_ptr_or_nullptr_t<T>::value, int> = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    handle(T ptr) : m_ptr(ptr) {}\n\n    /// Enable implicit conversion through ``T::operator PyObject *()``.\n    template <\n        typename T,\n        detail::enable_if_t<detail::all_of<detail::none_of<std::is_base_of<handle, T>,\n                                                           detail::is_pyobj_ptr_or_nullptr_t<T>>,\n                                           std::is_convertible<T, PyObject *>>::value,\n                            int>\n        = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    handle(T &obj) : m_ptr(obj) {}\n\n    /// Return the underlying ``PyObject *`` pointer\n    PyObject *ptr() const { return m_ptr; }\n    PyObject *&ptr() { return m_ptr; }\n\n    /** \\rst\n        Manually increase the reference count of the Python object. Usually, it is\n        preferable to use the `object` class which derives from `handle` and calls\n        this function automatically. Returns a reference to itself.\n    \\endrst */\n    const handle &inc_ref() const & {\n#ifdef PYBIND11_HANDLE_REF_DEBUG\n        inc_ref_counter(1);\n#endif\n#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF\n        if (m_ptr != nullptr && !PyGILState_Check()) {\n            throw_gilstate_error(\"pybind11::handle::inc_ref()\");\n        }\n#endif\n        Py_XINCREF(m_ptr);\n        return *this;\n    }\n\n    /** \\rst\n        Manually decrease the reference count of the Python object. Usually, it is\n        preferable to use the `object` class which derives from `handle` and calls\n        this function automatically. Returns a reference to itself.\n    \\endrst */\n    const handle &dec_ref() const & {\n#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF\n        if (m_ptr != nullptr && !PyGILState_Check()) {\n            throw_gilstate_error(\"pybind11::handle::dec_ref()\");\n        }\n#endif\n        Py_XDECREF(m_ptr);\n        return *this;\n    }\n\n    /** \\rst\n        Attempt to cast the Python object into the given C++ type. A `cast_error`\n        will be throw upon failure.\n    \\endrst */\n    template <typename T>\n    T cast() const;\n    /// Return ``true`` when the `handle` wraps a valid Python object\n    explicit operator bool() const { return m_ptr != nullptr; }\n    /** \\rst\n        Deprecated: Check that the underlying pointers are the same.\n        Equivalent to ``obj1 is obj2`` in Python.\n    \\endrst */\n    PYBIND11_DEPRECATED(\"Use obj1.is(obj2) instead\")\n    bool operator==(const handle &h) const { return m_ptr == h.m_ptr; }\n    PYBIND11_DEPRECATED(\"Use !obj1.is(obj2) instead\")\n    bool operator!=(const handle &h) const { return m_ptr != h.m_ptr; }\n    PYBIND11_DEPRECATED(\"Use handle::operator bool() instead\")\n    bool check() const { return m_ptr != nullptr; }\n\nprotected:\n    PyObject *m_ptr = nullptr;\n\nprivate:\n#ifdef PYBIND11_ASSERT_GIL_HELD_INCREF_DECREF\n    void throw_gilstate_error(const std::string &function_name) const {\n        fprintf(\n            stderr,\n            \"%s is being called while the GIL is either not held or invalid. Please see \"\n            \"https://pybind11.readthedocs.io/en/stable/advanced/\"\n            \"misc.html#common-sources-of-global-interpreter-lock-errors for debugging advice.\\n\"\n            \"If you are convinced there is no bug in your code, you can #define \"\n            \"PYBIND11_NO_ASSERT_GIL_HELD_INCREF_DECREF \"\n            \"to disable this check. In that case you have to ensure this #define is consistently \"\n            \"used for all translation units linked into a given pybind11 extension, otherwise \"\n            \"there will be ODR violations.\",\n            function_name.c_str());\n        if (Py_TYPE(m_ptr)->tp_name != nullptr) {\n            fprintf(stderr,\n                    \" The failing %s call was triggered on a %s object.\",\n                    function_name.c_str(),\n                    Py_TYPE(m_ptr)->tp_name);\n        }\n        fprintf(stderr, \"\\n\");\n        fflush(stderr);\n        throw std::runtime_error(function_name + \" PyGILState_Check() failure.\");\n    }\n#endif\n\n#ifdef PYBIND11_HANDLE_REF_DEBUG\n    static std::size_t inc_ref_counter(std::size_t add) {\n        thread_local std::size_t counter = 0;\n        counter += add;\n        return counter;\n    }\n\npublic:\n    static std::size_t inc_ref_counter() { return inc_ref_counter(0); }\n#endif\n};\n\ninline void set_error(const handle &type, const char *message) {\n    PyErr_SetString(type.ptr(), message);\n}\n\ninline void set_error(const handle &type, const handle &value) {\n    PyErr_SetObject(type.ptr(), value.ptr());\n}\n\n/** \\rst\n    Holds a reference to a Python object (with reference counting)\n\n    Like `handle`, the `object` class is a thin wrapper around an arbitrary Python\n    object (i.e. a ``PyObject *`` in Python's C API). In contrast to `handle`, it\n    optionally increases the object's reference count upon construction, and it\n    *always* decreases the reference count when the `object` instance goes out of\n    scope and is destructed. When using `object` instances consistently, it is much\n    easier to get reference counting right at the first attempt.\n\\endrst */\nclass object : public handle {\npublic:\n    object() = default;\n    PYBIND11_DEPRECATED(\"Use reinterpret_borrow<object>() or reinterpret_steal<object>()\")\n    object(handle h, bool is_borrowed) : handle(h) {\n        if (is_borrowed) {\n            inc_ref();\n        }\n    }\n    /// Copy constructor; always increases the reference count\n    object(const object &o) : handle(o) { inc_ref(); }\n    /// Move constructor; steals the object from ``other`` and preserves its reference count\n    object(object &&other) noexcept : handle(other) { other.m_ptr = nullptr; }\n    /// Destructor; automatically calls `handle::dec_ref()`\n    ~object() { dec_ref(); }\n\n    /** \\rst\n        Resets the internal pointer to ``nullptr`` without decreasing the\n        object's reference count. The function returns a raw handle to the original\n        Python object.\n    \\endrst */\n    handle release() {\n        PyObject *tmp = m_ptr;\n        m_ptr = nullptr;\n        return handle(tmp);\n    }\n\n    object &operator=(const object &other) {\n        // Skip inc_ref and dec_ref if both objects are the same\n        if (!this->is(other)) {\n            other.inc_ref();\n            // Use temporary variable to ensure `*this` remains valid while\n            // `Py_XDECREF` executes, in case `*this` is accessible from Python.\n            handle temp(m_ptr);\n            m_ptr = other.m_ptr;\n            temp.dec_ref();\n        }\n        return *this;\n    }\n\n    object &operator=(object &&other) noexcept {\n        if (this != &other) {\n            handle temp(m_ptr);\n            m_ptr = other.m_ptr;\n            other.m_ptr = nullptr;\n            temp.dec_ref();\n        }\n        return *this;\n    }\n\n#define PYBIND11_INPLACE_OP(iop)                                                                  \\\n    object iop(object_api const &other) { return operator=(handle::iop(other)); }\n\n    PYBIND11_INPLACE_OP(operator+=)\n    PYBIND11_INPLACE_OP(operator-=)\n    PYBIND11_INPLACE_OP(operator*=)\n    PYBIND11_INPLACE_OP(operator/=)\n    PYBIND11_INPLACE_OP(operator|=)\n    PYBIND11_INPLACE_OP(operator&=)\n    PYBIND11_INPLACE_OP(operator^=)\n    PYBIND11_INPLACE_OP(operator<<=)\n    PYBIND11_INPLACE_OP(operator>>=)\n#undef PYBIND11_INPLACE_OP\n\n    // Calling cast() on an object lvalue just copies (via handle::cast)\n    template <typename T>\n    T cast() const &;\n    // Calling on an object rvalue does a move, if needed and/or possible\n    template <typename T>\n    T cast() &&;\n\nprotected:\n    // Tags for choosing constructors from raw PyObject *\n    struct borrowed_t {};\n    struct stolen_t {};\n\n    /// @cond BROKEN\n    template <typename T>\n    friend T reinterpret_borrow(handle);\n    template <typename T>\n    friend T reinterpret_steal(handle);\n    /// @endcond\n\npublic:\n    // Only accessible from derived classes and the reinterpret_* functions\n    object(handle h, borrowed_t) : handle(h) { inc_ref(); }\n    object(handle h, stolen_t) : handle(h) {}\n};\n\n/** \\rst\n    Declare that a `handle` or ``PyObject *`` is a certain type and borrow the reference.\n    The target type ``T`` must be `object` or one of its derived classes. The function\n    doesn't do any conversions or checks. It's up to the user to make sure that the\n    target type is correct.\n\n    .. code-block:: cpp\n\n        PyObject *p = PyList_GetItem(obj, index);\n        py::object o = reinterpret_borrow<py::object>(p);\n        // or\n        py::tuple t = reinterpret_borrow<py::tuple>(p); // <-- `p` must be already be a `tuple`\n\\endrst */\ntemplate <typename T>\nT reinterpret_borrow(handle h) {\n    return {h, object::borrowed_t{}};\n}\n\n/** \\rst\n    Like `reinterpret_borrow`, but steals the reference.\n\n     .. code-block:: cpp\n\n        PyObject *p = PyObject_Str(obj);\n        py::str s = reinterpret_steal<py::str>(p); // <-- `p` must be already be a `str`\n\\endrst */\ntemplate <typename T>\nT reinterpret_steal(handle h) {\n    return {h, object::stolen_t{}};\n}\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).\ninline const char *obj_class_name(PyObject *obj) {\n    if (PyType_Check(obj)) {\n        return reinterpret_cast<PyTypeObject *>(obj)->tp_name;\n    }\n    return Py_TYPE(obj)->tp_name;\n}\n\nstd::string error_string();\n\n// The code in this struct is very unusual, to minimize the chances of\n// masking bugs (elsewhere) by errors during the error handling (here).\n// This is meant to be a lifeline for troubleshooting long-running processes\n// that crash under conditions that are virtually impossible to reproduce.\n// Low-level implementation alternatives are preferred to higher-level ones\n// that might raise cascading exceptions. Last-ditch-kind-of attempts are made\n// to report as much of the original error as possible, even if there are\n// secondary issues obtaining some of the details.\nstruct error_fetch_and_normalize {\n    // This comment only applies to Python <= 3.11:\n    //     Immediate normalization is long-established behavior (starting with\n    //     https://github.com/pybind/pybind11/commit/135ba8deafb8bf64a15b24d1513899eb600e2011\n    //     from Sep 2016) and safest. Normalization could be deferred, but this could mask\n    //     errors elsewhere, the performance gain is very minor in typical situations\n    //     (usually the dominant bottleneck is EH unwinding), and the implementation here\n    //     would be more complex.\n    // Starting with Python 3.12, PyErr_Fetch() normalizes exceptions immediately.\n    // Any errors during normalization are tracked under __notes__.\n    explicit error_fetch_and_normalize(const char *called) {\n        PyErr_Fetch(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());\n        if (!m_type) {\n            pybind11_fail(\"Internal error: \" + std::string(called)\n                          + \" called while \"\n                            \"Python error indicator not set.\");\n        }\n        const char *exc_type_name_orig = detail::obj_class_name(m_type.ptr());\n        if (exc_type_name_orig == nullptr) {\n            pybind11_fail(\"Internal error: \" + std::string(called)\n                          + \" failed to obtain the name \"\n                            \"of the original active exception type.\");\n        }\n        m_lazy_error_string = exc_type_name_orig;\n#if PY_VERSION_HEX >= 0x030C0000\n        // The presence of __notes__ is likely due to exception normalization\n        // errors, although that is not necessarily true, therefore insert a\n        // hint only:\n        if (PyObject_HasAttrString(m_value.ptr(), \"__notes__\")) {\n            m_lazy_error_string += \"[WITH __notes__]\";\n        }\n#else\n        // PyErr_NormalizeException() may change the exception type if there are cascading\n        // failures. This can potentially be extremely confusing.\n        PyErr_NormalizeException(&m_type.ptr(), &m_value.ptr(), &m_trace.ptr());\n        if (m_type.ptr() == nullptr) {\n            pybind11_fail(\"Internal error: \" + std::string(called)\n                          + \" failed to normalize the \"\n                            \"active exception.\");\n        }\n        const char *exc_type_name_norm = detail::obj_class_name(m_type.ptr());\n        if (exc_type_name_norm == nullptr) {\n            pybind11_fail(\"Internal error: \" + std::string(called)\n                          + \" failed to obtain the name \"\n                            \"of the normalized active exception type.\");\n        }\n#    if defined(PYPY_VERSION_NUM) && PYPY_VERSION_NUM < 0x07030a00\n        // This behavior runs the risk of masking errors in the error handling, but avoids a\n        // conflict with PyPy, which relies on the normalization here to change OSError to\n        // FileNotFoundError (https://github.com/pybind/pybind11/issues/4075).\n        m_lazy_error_string = exc_type_name_norm;\n#    else\n        if (exc_type_name_norm != m_lazy_error_string) {\n            std::string msg = std::string(called)\n                              + \": MISMATCH of original and normalized \"\n                                \"active exception types: \";\n            msg += \"ORIGINAL \";\n            msg += m_lazy_error_string;\n            msg += \" REPLACED BY \";\n            msg += exc_type_name_norm;\n            msg += \": \" + format_value_and_trace();\n            pybind11_fail(msg);\n        }\n#    endif\n#endif\n    }\n\n    error_fetch_and_normalize(const error_fetch_and_normalize &) = delete;\n    error_fetch_and_normalize(error_fetch_and_normalize &&) = delete;\n\n    std::string format_value_and_trace() const {\n        std::string result;\n        std::string message_error_string;\n        if (m_value) {\n            auto value_str = reinterpret_steal<object>(PyObject_Str(m_value.ptr()));\n            constexpr const char *message_unavailable_exc\n                = \"<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>\";\n            if (!value_str) {\n                message_error_string = detail::error_string();\n                result = message_unavailable_exc;\n            } else {\n                // Not using `value_str.cast<std::string>()`, to not potentially throw a secondary\n                // error_already_set that will then result in process termination (#4288).\n                auto value_bytes = reinterpret_steal<object>(\n                    PyUnicode_AsEncodedString(value_str.ptr(), \"utf-8\", \"backslashreplace\"));\n                if (!value_bytes) {\n                    message_error_string = detail::error_string();\n                    result = message_unavailable_exc;\n                } else {\n                    char *buffer = nullptr;\n                    Py_ssize_t length = 0;\n                    if (PyBytes_AsStringAndSize(value_bytes.ptr(), &buffer, &length) == -1) {\n                        message_error_string = detail::error_string();\n                        result = message_unavailable_exc;\n                    } else {\n                        result = std::string(buffer, static_cast<std::size_t>(length));\n                    }\n                }\n            }\n#if PY_VERSION_HEX >= 0x030B0000\n            auto notes\n                = reinterpret_steal<object>(PyObject_GetAttrString(m_value.ptr(), \"__notes__\"));\n            if (!notes) {\n                PyErr_Clear(); // No notes is good news.\n            } else {\n                auto len_notes = PyList_Size(notes.ptr());\n                if (len_notes < 0) {\n                    result += \"\\nFAILURE obtaining len(__notes__): \" + detail::error_string();\n                } else {\n                    result += \"\\n__notes__ (len=\" + std::to_string(len_notes) + \"):\";\n                    for (ssize_t i = 0; i < len_notes; i++) {\n                        PyObject *note = PyList_GET_ITEM(notes.ptr(), i);\n                        auto note_bytes = reinterpret_steal<object>(\n                            PyUnicode_AsEncodedString(note, \"utf-8\", \"backslashreplace\"));\n                        if (!note_bytes) {\n                            result += \"\\nFAILURE obtaining __notes__[\" + std::to_string(i)\n                                      + \"]: \" + detail::error_string();\n                        } else {\n                            char *buffer = nullptr;\n                            Py_ssize_t length = 0;\n                            if (PyBytes_AsStringAndSize(note_bytes.ptr(), &buffer, &length)\n                                == -1) {\n                                result += \"\\nFAILURE formatting __notes__[\" + std::to_string(i)\n                                          + \"]: \" + detail::error_string();\n                            } else {\n                                result += '\\n';\n                                result += std::string(buffer, static_cast<std::size_t>(length));\n                            }\n                        }\n                    }\n                }\n            }\n#endif\n        } else {\n            result = \"<MESSAGE UNAVAILABLE>\";\n        }\n        if (result.empty()) {\n            result = \"<EMPTY MESSAGE>\";\n        }\n\n        bool have_trace = false;\n        if (m_trace) {\n#if !defined(PYPY_VERSION)\n            auto *tb = reinterpret_cast<PyTracebackObject *>(m_trace.ptr());\n\n            // Get the deepest trace possible.\n            while (tb->tb_next) {\n                tb = tb->tb_next;\n            }\n\n            PyFrameObject *frame = tb->tb_frame;\n            Py_XINCREF(frame);\n            result += \"\\n\\nAt:\\n\";\n            while (frame) {\n#    if PY_VERSION_HEX >= 0x030900B1\n                PyCodeObject *f_code = PyFrame_GetCode(frame);\n#    else\n                PyCodeObject *f_code = frame->f_code;\n                Py_INCREF(f_code);\n#    endif\n                int lineno = PyFrame_GetLineNumber(frame);\n                result += \"  \";\n                result += handle(f_code->co_filename).cast<std::string>();\n                result += '(';\n                result += std::to_string(lineno);\n                result += \"): \";\n                result += handle(f_code->co_name).cast<std::string>();\n                result += '\\n';\n                Py_DECREF(f_code);\n#    if PY_VERSION_HEX >= 0x030900B1\n                auto *b_frame = PyFrame_GetBack(frame);\n#    else\n                auto *b_frame = frame->f_back;\n                Py_XINCREF(b_frame);\n#    endif\n                Py_DECREF(frame);\n                frame = b_frame;\n            }\n\n            have_trace = true;\n#endif //! defined(PYPY_VERSION)\n        }\n\n        if (!message_error_string.empty()) {\n            if (!have_trace) {\n                result += '\\n';\n            }\n            result += \"\\nMESSAGE UNAVAILABLE DUE TO EXCEPTION: \" + message_error_string;\n        }\n\n        return result;\n    }\n\n    std::string const &error_string() const {\n        if (!m_lazy_error_string_completed) {\n            m_lazy_error_string += \": \" + format_value_and_trace();\n            m_lazy_error_string_completed = true;\n        }\n        return m_lazy_error_string;\n    }\n\n    void restore() {\n        if (m_restore_called) {\n            pybind11_fail(\"Internal error: pybind11::detail::error_fetch_and_normalize::restore() \"\n                          \"called a second time. ORIGINAL ERROR: \"\n                          + error_string());\n        }\n        PyErr_Restore(m_type.inc_ref().ptr(), m_value.inc_ref().ptr(), m_trace.inc_ref().ptr());\n        m_restore_called = true;\n    }\n\n    bool matches(handle exc) const {\n        return (PyErr_GivenExceptionMatches(m_type.ptr(), exc.ptr()) != 0);\n    }\n\n    // Not protecting these for simplicity.\n    object m_type, m_value, m_trace;\n\nprivate:\n    // Only protecting invariants.\n    mutable std::string m_lazy_error_string;\n    mutable bool m_lazy_error_string_completed = false;\n    mutable bool m_restore_called = false;\n};\n\ninline std::string error_string() {\n    return error_fetch_and_normalize(\"pybind11::detail::error_string\").error_string();\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n/// Fetch and hold an error which was already set in Python.  An instance of this is typically\n/// thrown to propagate python-side errors back through C++ which can either be caught manually or\n/// else falls back to the function dispatcher (which then raises the captured error back to\n/// python).\nclass PYBIND11_EXPORT_EXCEPTION error_already_set : public std::exception {\npublic:\n    /// Fetches the current Python exception (using PyErr_Fetch()), which will clear the\n    /// current Python error indicator.\n    error_already_set()\n        : m_fetched_error{new detail::error_fetch_and_normalize(\"pybind11::error_already_set\"),\n                          m_fetched_error_deleter} {}\n\n    /// The what() result is built lazily on demand.\n    /// WARNING: This member function needs to acquire the Python GIL. This can lead to\n    ///          crashes (undefined behavior) if the Python interpreter is finalizing.\n    const char *what() const noexcept override;\n\n    /// Restores the currently-held Python error (which will clear the Python error indicator first\n    /// if already set).\n    /// NOTE: This member function will always restore the normalized exception, which may or may\n    ///       not be the original Python exception.\n    /// WARNING: The GIL must be held when this member function is called!\n    void restore() { m_fetched_error->restore(); }\n\n    /// If it is impossible to raise the currently-held error, such as in a destructor, we can\n    /// write it out using Python's unraisable hook (`sys.unraisablehook`). The error context\n    /// should be some object whose `repr()` helps identify the location of the error. Python\n    /// already knows the type and value of the error, so there is no need to repeat that.\n    void discard_as_unraisable(object err_context) {\n        restore();\n        PyErr_WriteUnraisable(err_context.ptr());\n    }\n    /// An alternate version of `discard_as_unraisable()`, where a string provides information on\n    /// the location of the error. For example, `__func__` could be helpful.\n    /// WARNING: The GIL must be held when this member function is called!\n    void discard_as_unraisable(const char *err_context) {\n        discard_as_unraisable(reinterpret_steal<object>(PYBIND11_FROM_STRING(err_context)));\n    }\n\n    // Does nothing; provided for backwards compatibility.\n    PYBIND11_DEPRECATED(\"Use of error_already_set.clear() is deprecated\")\n    void clear() {}\n\n    /// Check if the currently trapped error type matches the given Python exception class (or a\n    /// subclass thereof).  May also be passed a tuple to search for any exception class matches in\n    /// the given tuple.\n    bool matches(handle exc) const { return m_fetched_error->matches(exc); }\n\n    const object &type() const { return m_fetched_error->m_type; }\n    const object &value() const { return m_fetched_error->m_value; }\n    const object &trace() const { return m_fetched_error->m_trace; }\n\nprivate:\n    std::shared_ptr<detail::error_fetch_and_normalize> m_fetched_error;\n\n    /// WARNING: This custom deleter needs to acquire the Python GIL. This can lead to\n    ///          crashes (undefined behavior) if the Python interpreter is finalizing.\n    static void m_fetched_error_deleter(detail::error_fetch_and_normalize *raw_ptr);\n};\n\n/// Replaces the current Python error indicator with the chosen error, performing a\n/// 'raise from' to indicate that the chosen error was caused by the original error.\ninline void raise_from(PyObject *type, const char *message) {\n    // Based on _PyErr_FormatVFromCause:\n    // https://github.com/python/cpython/blob/467ab194fc6189d9f7310c89937c51abeac56839/Python/errors.c#L405\n    // See https://github.com/pybind/pybind11/pull/2112 for details.\n    PyObject *exc = nullptr, *val = nullptr, *val2 = nullptr, *tb = nullptr;\n\n    assert(PyErr_Occurred());\n    PyErr_Fetch(&exc, &val, &tb);\n    PyErr_NormalizeException(&exc, &val, &tb);\n    if (tb != nullptr) {\n        PyException_SetTraceback(val, tb);\n        Py_DECREF(tb);\n    }\n    Py_DECREF(exc);\n    assert(!PyErr_Occurred());\n\n    PyErr_SetString(type, message);\n\n    PyErr_Fetch(&exc, &val2, &tb);\n    PyErr_NormalizeException(&exc, &val2, &tb);\n    Py_INCREF(val);\n    PyException_SetCause(val2, val);\n    PyException_SetContext(val2, val);\n    PyErr_Restore(exc, val2, tb);\n}\n\n/// Sets the current Python error indicator with the chosen error, performing a 'raise from'\n/// from the error contained in error_already_set to indicate that the chosen error was\n/// caused by the original error.\ninline void raise_from(error_already_set &err, PyObject *type, const char *message) {\n    err.restore();\n    raise_from(type, message);\n}\n\n/** \\defgroup python_builtins const_name\n    Unless stated otherwise, the following C++ functions behave the same\n    as their Python counterparts.\n */\n\n/** \\ingroup python_builtins\n    \\rst\n    Return true if ``obj`` is an instance of ``T``. Type ``T`` must be a subclass of\n    `object` or a class which was exposed to Python as ``py::class_<T>``.\n\\endrst */\ntemplate <typename T, detail::enable_if_t<std::is_base_of<object, T>::value, int> = 0>\nbool isinstance(handle obj) {\n    return T::check_(obj);\n}\n\ntemplate <typename T, detail::enable_if_t<!std::is_base_of<object, T>::value, int> = 0>\nbool isinstance(handle obj) {\n    return detail::isinstance_generic(obj, typeid(T));\n}\n\ntemplate <>\ninline bool isinstance<handle>(handle) = delete;\ntemplate <>\ninline bool isinstance<object>(handle obj) {\n    return obj.ptr() != nullptr;\n}\n\n/// \\ingroup python_builtins\n/// Return true if ``obj`` is an instance of the ``type``.\ninline bool isinstance(handle obj, handle type) {\n    const auto result = PyObject_IsInstance(obj.ptr(), type.ptr());\n    if (result == -1) {\n        throw error_already_set();\n    }\n    return result != 0;\n}\n\n/// \\addtogroup python_builtins\n/// @{\ninline bool hasattr(handle obj, handle name) {\n    return PyObject_HasAttr(obj.ptr(), name.ptr()) == 1;\n}\n\ninline bool hasattr(handle obj, const char *name) {\n    return PyObject_HasAttrString(obj.ptr(), name) == 1;\n}\n\ninline void delattr(handle obj, handle name) {\n    if (PyObject_DelAttr(obj.ptr(), name.ptr()) != 0) {\n        throw error_already_set();\n    }\n}\n\ninline void delattr(handle obj, const char *name) {\n    if (PyObject_DelAttrString(obj.ptr(), name) != 0) {\n        throw error_already_set();\n    }\n}\n\ninline object getattr(handle obj, handle name) {\n    PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr());\n    if (!result) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<object>(result);\n}\n\ninline object getattr(handle obj, const char *name) {\n    PyObject *result = PyObject_GetAttrString(obj.ptr(), name);\n    if (!result) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<object>(result);\n}\n\ninline object getattr(handle obj, handle name, handle default_) {\n    if (PyObject *result = PyObject_GetAttr(obj.ptr(), name.ptr())) {\n        return reinterpret_steal<object>(result);\n    }\n    PyErr_Clear();\n    return reinterpret_borrow<object>(default_);\n}\n\ninline object getattr(handle obj, const char *name, handle default_) {\n    if (PyObject *result = PyObject_GetAttrString(obj.ptr(), name)) {\n        return reinterpret_steal<object>(result);\n    }\n    PyErr_Clear();\n    return reinterpret_borrow<object>(default_);\n}\n\ninline void setattr(handle obj, handle name, handle value) {\n    if (PyObject_SetAttr(obj.ptr(), name.ptr(), value.ptr()) != 0) {\n        throw error_already_set();\n    }\n}\n\ninline void setattr(handle obj, const char *name, handle value) {\n    if (PyObject_SetAttrString(obj.ptr(), name, value.ptr()) != 0) {\n        throw error_already_set();\n    }\n}\n\ninline ssize_t hash(handle obj) {\n    auto h = PyObject_Hash(obj.ptr());\n    if (h == -1) {\n        throw error_already_set();\n    }\n    return h;\n}\n\n/// @} python_builtins\n\nPYBIND11_NAMESPACE_BEGIN(detail)\ninline handle get_function(handle value) {\n    if (value) {\n        if (PyInstanceMethod_Check(value.ptr())) {\n            value = PyInstanceMethod_GET_FUNCTION(value.ptr());\n        } else if (PyMethod_Check(value.ptr())) {\n            value = PyMethod_GET_FUNCTION(value.ptr());\n        }\n    }\n    return value;\n}\n\n// Reimplementation of python's dict helper functions to ensure that exceptions\n// aren't swallowed (see #2862)\n\n// copied from cpython _PyDict_GetItemStringWithError\ninline PyObject *dict_getitemstring(PyObject *v, const char *key) {\n    PyObject *kv = nullptr, *rv = nullptr;\n    kv = PyUnicode_FromString(key);\n    if (kv == nullptr) {\n        throw error_already_set();\n    }\n\n    rv = PyDict_GetItemWithError(v, kv);\n    Py_DECREF(kv);\n    if (rv == nullptr && PyErr_Occurred()) {\n        throw error_already_set();\n    }\n    return rv;\n}\n\ninline PyObject *dict_getitem(PyObject *v, PyObject *key) {\n    PyObject *rv = PyDict_GetItemWithError(v, key);\n    if (rv == nullptr && PyErr_Occurred()) {\n        throw error_already_set();\n    }\n    return rv;\n}\n\n// Helper aliases/functions to support implicit casting of values given to python\n// accessors/methods. When given a pyobject, this simply returns the pyobject as-is; for other C++\n// type, the value goes through pybind11::cast(obj) to convert it to an `object`.\ntemplate <typename T, enable_if_t<is_pyobject<T>::value, int> = 0>\nauto object_or_cast(T &&o) -> decltype(std::forward<T>(o)) {\n    return std::forward<T>(o);\n}\n// The following casting version is implemented in cast.h:\ntemplate <typename T, enable_if_t<!is_pyobject<T>::value, int> = 0>\nobject object_or_cast(T &&o);\n// Match a PyObject*, which we want to convert directly to handle via its converting constructor\ninline handle object_or_cast(PyObject *ptr) { return ptr; }\n\nPYBIND11_WARNING_PUSH\nPYBIND11_WARNING_DISABLE_MSVC(4522) // warning C4522: multiple assignment operators specified\ntemplate <typename Policy>\nclass accessor : public object_api<accessor<Policy>> {\n    using key_type = typename Policy::key_type;\n\npublic:\n    accessor(handle obj, key_type key) : obj(obj), key(std::move(key)) {}\n    accessor(const accessor &) = default;\n    accessor(accessor &&) noexcept = default;\n\n    // accessor overload required to override default assignment operator (templates are not\n    // allowed to replace default compiler-generated assignments).\n    void operator=(const accessor &a) && { std::move(*this).operator=(handle(a)); }\n    void operator=(const accessor &a) & { operator=(handle(a)); }\n\n    template <typename T>\n    void operator=(T &&value) && {\n        Policy::set(obj, key, object_or_cast(std::forward<T>(value)));\n    }\n    template <typename T>\n    void operator=(T &&value) & {\n        get_cache() = ensure_object(object_or_cast(std::forward<T>(value)));\n    }\n\n    template <typename T = Policy>\n    PYBIND11_DEPRECATED(\n        \"Use of obj.attr(...) as bool is deprecated in favor of pybind11::hasattr(obj, ...)\")\n    explicit\n    operator enable_if_t<std::is_same<T, accessor_policies::str_attr>::value\n                             || std::is_same<T, accessor_policies::obj_attr>::value,\n                         bool>() const {\n        return hasattr(obj, key);\n    }\n    template <typename T = Policy>\n    PYBIND11_DEPRECATED(\"Use of obj[key] as bool is deprecated in favor of obj.contains(key)\")\n    explicit\n    operator enable_if_t<std::is_same<T, accessor_policies::generic_item>::value, bool>() const {\n        return obj.contains(key);\n    }\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator object() const { return get_cache(); }\n    PyObject *ptr() const { return get_cache().ptr(); }\n    template <typename T>\n    T cast() const {\n        return get_cache().template cast<T>();\n    }\n\nprivate:\n    static object ensure_object(object &&o) { return std::move(o); }\n    static object ensure_object(handle h) { return reinterpret_borrow<object>(h); }\n\n    object &get_cache() const {\n        if (!cache) {\n            cache = Policy::get(obj, key);\n        }\n        return cache;\n    }\n\nprivate:\n    handle obj;\n    key_type key;\n    mutable object cache;\n};\nPYBIND11_WARNING_POP\n\nPYBIND11_NAMESPACE_BEGIN(accessor_policies)\nstruct obj_attr {\n    using key_type = object;\n    static object get(handle obj, handle key) { return getattr(obj, key); }\n    static void set(handle obj, handle key, handle val) { setattr(obj, key, val); }\n};\n\nstruct str_attr {\n    using key_type = const char *;\n    static object get(handle obj, const char *key) { return getattr(obj, key); }\n    static void set(handle obj, const char *key, handle val) { setattr(obj, key, val); }\n};\n\nstruct generic_item {\n    using key_type = object;\n\n    static object get(handle obj, handle key) {\n        PyObject *result = PyObject_GetItem(obj.ptr(), key.ptr());\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<object>(result);\n    }\n\n    static void set(handle obj, handle key, handle val) {\n        if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) {\n            throw error_already_set();\n        }\n    }\n};\n\nstruct sequence_item {\n    using key_type = size_t;\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static object get(handle obj, const IdxType &index) {\n        PyObject *result = PySequence_GetItem(obj.ptr(), ssize_t_cast(index));\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_steal<object>(result);\n    }\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static void set(handle obj, const IdxType &index, handle val) {\n        // PySequence_SetItem does not steal a reference to 'val'\n        if (PySequence_SetItem(obj.ptr(), ssize_t_cast(index), val.ptr()) != 0) {\n            throw error_already_set();\n        }\n    }\n};\n\nstruct list_item {\n    using key_type = size_t;\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static object get(handle obj, const IdxType &index) {\n        PyObject *result = PyList_GetItem(obj.ptr(), ssize_t_cast(index));\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_borrow<object>(result);\n    }\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static void set(handle obj, const IdxType &index, handle val) {\n        // PyList_SetItem steals a reference to 'val'\n        if (PyList_SetItem(obj.ptr(), ssize_t_cast(index), val.inc_ref().ptr()) != 0) {\n            throw error_already_set();\n        }\n    }\n};\n\nstruct tuple_item {\n    using key_type = size_t;\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static object get(handle obj, const IdxType &index) {\n        PyObject *result = PyTuple_GetItem(obj.ptr(), ssize_t_cast(index));\n        if (!result) {\n            throw error_already_set();\n        }\n        return reinterpret_borrow<object>(result);\n    }\n\n    template <typename IdxType, detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    static void set(handle obj, const IdxType &index, handle val) {\n        // PyTuple_SetItem steals a reference to 'val'\n        if (PyTuple_SetItem(obj.ptr(), ssize_t_cast(index), val.inc_ref().ptr()) != 0) {\n            throw error_already_set();\n        }\n    }\n};\nPYBIND11_NAMESPACE_END(accessor_policies)\n\n/// STL iterator template used for tuple, list, sequence and dict\ntemplate <typename Policy>\nclass generic_iterator : public Policy {\n    using It = generic_iterator;\n\npublic:\n    using difference_type = ssize_t;\n    using iterator_category = typename Policy::iterator_category;\n    using value_type = typename Policy::value_type;\n    using reference = typename Policy::reference;\n    using pointer = typename Policy::pointer;\n\n    generic_iterator() = default;\n    generic_iterator(handle seq, ssize_t index) : Policy(seq, index) {}\n\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    reference operator*() const { return Policy::dereference(); }\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    reference operator[](difference_type n) const { return *(*this + n); }\n    pointer operator->() const { return **this; }\n\n    It &operator++() {\n        Policy::increment();\n        return *this;\n    }\n    It operator++(int) {\n        auto copy = *this;\n        Policy::increment();\n        return copy;\n    }\n    It &operator--() {\n        Policy::decrement();\n        return *this;\n    }\n    It operator--(int) {\n        auto copy = *this;\n        Policy::decrement();\n        return copy;\n    }\n    It &operator+=(difference_type n) {\n        Policy::advance(n);\n        return *this;\n    }\n    It &operator-=(difference_type n) {\n        Policy::advance(-n);\n        return *this;\n    }\n\n    friend It operator+(const It &a, difference_type n) {\n        auto copy = a;\n        return copy += n;\n    }\n    friend It operator+(difference_type n, const It &b) { return b + n; }\n    friend It operator-(const It &a, difference_type n) {\n        auto copy = a;\n        return copy -= n;\n    }\n    friend difference_type operator-(const It &a, const It &b) { return a.distance_to(b); }\n\n    friend bool operator==(const It &a, const It &b) { return a.equal(b); }\n    friend bool operator!=(const It &a, const It &b) { return !(a == b); }\n    friend bool operator<(const It &a, const It &b) { return b - a > 0; }\n    friend bool operator>(const It &a, const It &b) { return b < a; }\n    friend bool operator>=(const It &a, const It &b) { return !(a < b); }\n    friend bool operator<=(const It &a, const It &b) { return !(a > b); }\n};\n\nPYBIND11_NAMESPACE_BEGIN(iterator_policies)\n/// Quick proxy class needed to implement ``operator->`` for iterators which can't return pointers\ntemplate <typename T>\nstruct arrow_proxy {\n    T value;\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    arrow_proxy(T &&value) noexcept : value(std::move(value)) {}\n    T *operator->() const { return &value; }\n};\n\n/// Lightweight iterator policy using just a simple pointer: see ``PySequence_Fast_ITEMS``\nclass sequence_fast_readonly {\nprotected:\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = handle;\n    using reference = const handle; // PR #3263\n    using pointer = arrow_proxy<const handle>;\n\n    sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}\n\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    reference dereference() const { return *ptr; }\n    void increment() { ++ptr; }\n    void decrement() { --ptr; }\n    void advance(ssize_t n) { ptr += n; }\n    bool equal(const sequence_fast_readonly &b) const { return ptr == b.ptr; }\n    ssize_t distance_to(const sequence_fast_readonly &b) const { return ptr - b.ptr; }\n\nprivate:\n    PyObject **ptr;\n};\n\n/// Full read and write access using the sequence protocol: see ``detail::sequence_accessor``\nclass sequence_slow_readwrite {\nprotected:\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = object;\n    using reference = sequence_accessor;\n    using pointer = arrow_proxy<const sequence_accessor>;\n\n    sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}\n\n    reference dereference() const { return {obj, static_cast<size_t>(index)}; }\n    void increment() { ++index; }\n    void decrement() { --index; }\n    void advance(ssize_t n) { index += n; }\n    bool equal(const sequence_slow_readwrite &b) const { return index == b.index; }\n    ssize_t distance_to(const sequence_slow_readwrite &b) const { return index - b.index; }\n\nprivate:\n    handle obj;\n    ssize_t index;\n};\n\n/// Python's dictionary protocol permits this to be a forward iterator\nclass dict_readonly {\nprotected:\n    using iterator_category = std::forward_iterator_tag;\n    using value_type = std::pair<handle, handle>;\n    using reference = const value_type; // PR #3263\n    using pointer = arrow_proxy<const value_type>;\n\n    dict_readonly() = default;\n    dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }\n\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    reference dereference() const { return {key, value}; }\n    void increment() {\n        if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {\n            pos = -1;\n        }\n    }\n    bool equal(const dict_readonly &b) const { return pos == b.pos; }\n\nprivate:\n    handle obj;\n    PyObject *key = nullptr, *value = nullptr;\n    ssize_t pos = -1;\n};\nPYBIND11_NAMESPACE_END(iterator_policies)\n\n#if !defined(PYPY_VERSION)\nusing tuple_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;\nusing list_iterator = generic_iterator<iterator_policies::sequence_fast_readonly>;\n#else\nusing tuple_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;\nusing list_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;\n#endif\n\nusing sequence_iterator = generic_iterator<iterator_policies::sequence_slow_readwrite>;\nusing dict_iterator = generic_iterator<iterator_policies::dict_readonly>;\n\ninline bool PyIterable_Check(PyObject *obj) {\n    PyObject *iter = PyObject_GetIter(obj);\n    if (iter) {\n        Py_DECREF(iter);\n        return true;\n    }\n    PyErr_Clear();\n    return false;\n}\n\ninline bool PyNone_Check(PyObject *o) { return o == Py_None; }\ninline bool PyEllipsis_Check(PyObject *o) { return o == Py_Ellipsis; }\n\n#ifdef PYBIND11_STR_LEGACY_PERMISSIVE\ninline bool PyUnicode_Check_Permissive(PyObject *o) {\n    return PyUnicode_Check(o) || PYBIND11_BYTES_CHECK(o);\n}\n#    define PYBIND11_STR_CHECK_FUN detail::PyUnicode_Check_Permissive\n#else\n#    define PYBIND11_STR_CHECK_FUN PyUnicode_Check\n#endif\n\ninline bool PyStaticMethod_Check(PyObject *o) { return o->ob_type == &PyStaticMethod_Type; }\n\nclass kwargs_proxy : public handle {\npublic:\n    explicit kwargs_proxy(handle h) : handle(h) {}\n};\n\nclass args_proxy : public handle {\npublic:\n    explicit args_proxy(handle h) : handle(h) {}\n    kwargs_proxy operator*() const { return kwargs_proxy(*this); }\n};\n\n/// Python argument categories (using PEP 448 terms)\ntemplate <typename T>\nusing is_keyword = std::is_base_of<arg, T>;\ntemplate <typename T>\nusing is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking\ntemplate <typename T>\nusing is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking\ntemplate <typename T>\nusing is_positional = satisfies_none_of<T, is_keyword, is_s_unpacking, is_ds_unpacking>;\ntemplate <typename T>\nusing is_keyword_or_ds = satisfies_any_of<T, is_keyword, is_ds_unpacking>;\n\n// Call argument collector forward declarations\ntemplate <return_value_policy policy = return_value_policy::automatic_reference>\nclass simple_collector;\ntemplate <return_value_policy policy = return_value_policy::automatic_reference>\nclass unpacking_collector;\n\nPYBIND11_NAMESPACE_END(detail)\n\n// TODO: After the deprecated constructors are removed, this macro can be simplified by\n//       inheriting ctors: `using Parent::Parent`. It's not an option right now because\n//       the `using` statement triggers the parent deprecation warning even if the ctor\n//       isn't even used.\n#define PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun)                                            \\\npublic:                                                                                           \\\n    PYBIND11_DEPRECATED(\"Use reinterpret_borrow<\" #Name \">() or reinterpret_steal<\" #Name \">()\")  \\\n    Name(handle h, bool is_borrowed)                                                              \\\n        : Parent(is_borrowed ? Parent(h, borrowed_t{}) : Parent(h, stolen_t{})) {}                \\\n    Name(handle h, borrowed_t) : Parent(h, borrowed_t{}) {}                                       \\\n    Name(handle h, stolen_t) : Parent(h, stolen_t{}) {}                                           \\\n    PYBIND11_DEPRECATED(\"Use py::isinstance<py::python_type>(obj) instead\")                       \\\n    bool check() const { return m_ptr != nullptr && (CheckFun(m_ptr) != 0); }                     \\\n    static bool check_(handle h) { return h.ptr() != nullptr && CheckFun(h.ptr()); }              \\\n    template <typename Policy_> /* NOLINTNEXTLINE(google-explicit-constructor) */                 \\\n    Name(const ::pybind11::detail::accessor<Policy_> &a) : Name(object(a)) {}\n\n#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun)                                   \\\n    PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun)                                                \\\n    /* This is deliberately not 'explicit' to allow implicit conversion from object: */           \\\n    /* NOLINTNEXTLINE(google-explicit-constructor) */                                             \\\n    Name(const object &o)                                                                         \\\n        : Parent(check_(o) ? o.inc_ref().ptr() : ConvertFun(o.ptr()), stolen_t{}) {               \\\n        if (!m_ptr)                                                                               \\\n            throw ::pybind11::error_already_set();                                                \\\n    }                                                                                             \\\n    /* NOLINTNEXTLINE(google-explicit-constructor) */                                             \\\n    Name(object &&o) : Parent(check_(o) ? o.release().ptr() : ConvertFun(o.ptr()), stolen_t{}) {  \\\n        if (!m_ptr)                                                                               \\\n            throw ::pybind11::error_already_set();                                                \\\n    }\n\n#define PYBIND11_OBJECT_CVT_DEFAULT(Name, Parent, CheckFun, ConvertFun)                           \\\n    PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun)                                       \\\n    Name() = default;\n\n#define PYBIND11_OBJECT_CHECK_FAILED(Name, o_ptr)                                                 \\\n    ::pybind11::type_error(\"Object of type '\"                                                     \\\n                           + ::pybind11::detail::get_fully_qualified_tp_name(Py_TYPE(o_ptr))      \\\n                           + \"' is not an instance of '\" #Name \"'\")\n\n#define PYBIND11_OBJECT(Name, Parent, CheckFun)                                                   \\\n    PYBIND11_OBJECT_COMMON(Name, Parent, CheckFun)                                                \\\n    /* This is deliberately not 'explicit' to allow implicit conversion from object: */           \\\n    /* NOLINTNEXTLINE(google-explicit-constructor) */                                             \\\n    Name(const object &o) : Parent(o) {                                                           \\\n        if (m_ptr && !check_(m_ptr))                                                              \\\n            throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr);                                      \\\n    }                                                                                             \\\n    /* NOLINTNEXTLINE(google-explicit-constructor) */                                             \\\n    Name(object &&o) : Parent(std::move(o)) {                                                     \\\n        if (m_ptr && !check_(m_ptr))                                                              \\\n            throw PYBIND11_OBJECT_CHECK_FAILED(Name, m_ptr);                                      \\\n    }\n\n#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun)                                           \\\n    PYBIND11_OBJECT(Name, Parent, CheckFun)                                                       \\\n    Name() = default;\n\n/// \\addtogroup pytypes\n/// @{\n\n/** \\rst\n    Wraps a Python iterator so that it can also be used as a C++ input iterator\n\n    Caveat: copying an iterator does not (and cannot) clone the internal\n    state of the Python iterable. This also applies to the post-increment\n    operator. This iterator should only be used to retrieve the current\n    value using ``operator*()``.\n\\endrst */\nclass iterator : public object {\npublic:\n    using iterator_category = std::input_iterator_tag;\n    using difference_type = ssize_t;\n    using value_type = handle;\n    using reference = const handle; // PR #3263\n    using pointer = const handle *;\n\n    PYBIND11_OBJECT_DEFAULT(iterator, object, PyIter_Check)\n\n    iterator &operator++() {\n        advance();\n        return *this;\n    }\n\n    iterator operator++(int) {\n        auto rv = *this;\n        advance();\n        return rv;\n    }\n\n    // NOLINTNEXTLINE(readability-const-return-type) // PR #3263\n    reference operator*() const {\n        if (m_ptr && !value.ptr()) {\n            auto &self = const_cast<iterator &>(*this);\n            self.advance();\n        }\n        return value;\n    }\n\n    pointer operator->() const {\n        operator*();\n        return &value;\n    }\n\n    /** \\rst\n         The value which marks the end of the iteration. ``it == iterator::sentinel()``\n         is equivalent to catching ``StopIteration`` in Python.\n\n         .. code-block:: cpp\n\n             void foo(py::iterator it) {\n                 while (it != py::iterator::sentinel()) {\n                    // use `*it`\n                    ++it;\n                 }\n             }\n    \\endrst */\n    static iterator sentinel() { return {}; }\n\n    friend bool operator==(const iterator &a, const iterator &b) { return a->ptr() == b->ptr(); }\n    friend bool operator!=(const iterator &a, const iterator &b) { return a->ptr() != b->ptr(); }\n\nprivate:\n    void advance() {\n        value = reinterpret_steal<object>(PyIter_Next(m_ptr));\n        if (value.ptr() == nullptr && PyErr_Occurred()) {\n            throw error_already_set();\n        }\n    }\n\nprivate:\n    object value = {};\n};\n\nclass type : public object {\npublic:\n    PYBIND11_OBJECT(type, object, PyType_Check)\n\n    /// Return a type handle from a handle or an object\n    static handle handle_of(handle h) { return handle((PyObject *) Py_TYPE(h.ptr())); }\n\n    /// Return a type object from a handle or an object\n    static type of(handle h) { return type(type::handle_of(h), borrowed_t{}); }\n\n    // Defined in pybind11/cast.h\n    /// Convert C++ type to handle if previously registered. Does not convert\n    /// standard types, like int, float. etc. yet.\n    /// See https://github.com/pybind/pybind11/issues/2486\n    template <typename T>\n    static handle handle_of();\n\n    /// Convert C++ type to type if previously registered. Does not convert\n    /// standard types, like int, float. etc. yet.\n    /// See https://github.com/pybind/pybind11/issues/2486\n    template <typename T>\n    static type of() {\n        return type(type::handle_of<T>(), borrowed_t{});\n    }\n};\n\nclass iterable : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(iterable, object, detail::PyIterable_Check)\n};\n\nclass bytes;\n\nclass str : public object {\npublic:\n    PYBIND11_OBJECT_CVT(str, object, PYBIND11_STR_CHECK_FUN, raw_str)\n\n    template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>\n    str(const char *c, const SzType &n)\n        : object(PyUnicode_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {\n        if (!m_ptr) {\n            if (PyErr_Occurred()) {\n                throw error_already_set();\n            }\n            pybind11_fail(\"Could not allocate string object!\");\n        }\n    }\n\n    // 'explicit' is explicitly omitted from the following constructors to allow implicit\n    // conversion to py::str from C++ string-like objects\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    str(const char *c = \"\") : object(PyUnicode_FromString(c), stolen_t{}) {\n        if (!m_ptr) {\n            if (PyErr_Occurred()) {\n                throw error_already_set();\n            }\n            pybind11_fail(\"Could not allocate string object!\");\n        }\n    }\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    str(const std::string &s) : str(s.data(), s.size()) {}\n\n#ifdef PYBIND11_HAS_STRING_VIEW\n    // enable_if is needed to avoid \"ambiguous conversion\" errors (see PR #3521).\n    template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    str(T s) : str(s.data(), s.size()) {}\n\n#    ifdef PYBIND11_HAS_U8STRING\n    // reinterpret_cast here is safe (C++20 guarantees char8_t has the same size/alignment as char)\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    str(std::u8string_view s) : str(reinterpret_cast<const char *>(s.data()), s.size()) {}\n#    endif\n\n#endif\n\n    explicit str(const bytes &b);\n\n    /** \\rst\n        Return a string representation of the object. This is analogous to\n        the ``str()`` function in Python.\n    \\endrst */\n    explicit str(handle h) : object(raw_str(h.ptr()), stolen_t{}) {\n        if (!m_ptr) {\n            throw error_already_set();\n        }\n    }\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator std::string() const {\n        object temp = *this;\n        if (PyUnicode_Check(m_ptr)) {\n            temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(m_ptr));\n            if (!temp) {\n                throw error_already_set();\n            }\n        }\n        char *buffer = nullptr;\n        ssize_t length = 0;\n        if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {\n            throw error_already_set();\n        }\n        return std::string(buffer, (size_t) length);\n    }\n\n    template <typename... Args>\n    str format(Args &&...args) const {\n        return attr(\"format\")(std::forward<Args>(args)...);\n    }\n\nprivate:\n    /// Return string representation -- always returns a new reference, even if already a str\n    static PyObject *raw_str(PyObject *op) {\n        PyObject *str_value = PyObject_Str(op);\n        return str_value;\n    }\n};\n/// @} pytypes\n\ninline namespace literals {\n/** \\rst\n    String literal version of `str`\n \\endrst */\ninline str\n#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ < 5\noperator\"\" _s // gcc 4.8.5 insists on having a space (hard error).\n#else\noperator\"\"_s // clang 17 generates a deprecation warning if there is a space.\n#endif\n    (const char *s, size_t size) {\n    return {s, size};\n}\n} // namespace literals\n\n/// \\addtogroup pytypes\n/// @{\nclass bytes : public object {\npublic:\n    PYBIND11_OBJECT(bytes, object, PYBIND11_BYTES_CHECK)\n\n    // Allow implicit conversion:\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    bytes(const char *c = \"\") : object(PYBIND11_BYTES_FROM_STRING(c), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate bytes object!\");\n        }\n    }\n\n    template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>\n    bytes(const char *c, const SzType &n)\n        : object(PYBIND11_BYTES_FROM_STRING_AND_SIZE(c, ssize_t_cast(n)), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate bytes object!\");\n        }\n    }\n\n    // Allow implicit conversion:\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    bytes(const std::string &s) : bytes(s.data(), s.size()) {}\n\n    explicit bytes(const pybind11::str &s);\n\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator std::string() const { return string_op<std::string>(); }\n\n#ifdef PYBIND11_HAS_STRING_VIEW\n    // enable_if is needed to avoid \"ambiguous conversion\" errors (see PR #3521).\n    template <typename T, detail::enable_if_t<std::is_same<T, std::string_view>::value, int> = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    bytes(T s) : bytes(s.data(), s.size()) {}\n\n    // Obtain a string view that views the current `bytes` buffer value.  Note that this is only\n    // valid so long as the `bytes` instance remains alive and so generally should not outlive the\n    // lifetime of the `bytes` instance.\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator std::string_view() const { return string_op<std::string_view>(); }\n#endif\nprivate:\n    template <typename T>\n    T string_op() const {\n        char *buffer = nullptr;\n        ssize_t length = 0;\n        if (PyBytes_AsStringAndSize(m_ptr, &buffer, &length) != 0) {\n            throw error_already_set();\n        }\n        return {buffer, static_cast<size_t>(length)};\n    }\n};\n// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors\n// are included in the doxygen group; close here and reopen after as a workaround\n/// @} pytypes\n\ninline bytes::bytes(const pybind11::str &s) {\n    object temp = s;\n    if (PyUnicode_Check(s.ptr())) {\n        temp = reinterpret_steal<object>(PyUnicode_AsUTF8String(s.ptr()));\n        if (!temp) {\n            throw error_already_set();\n        }\n    }\n    char *buffer = nullptr;\n    ssize_t length = 0;\n    if (PyBytes_AsStringAndSize(temp.ptr(), &buffer, &length) != 0) {\n        throw error_already_set();\n    }\n    auto obj = reinterpret_steal<object>(PYBIND11_BYTES_FROM_STRING_AND_SIZE(buffer, length));\n    if (!obj) {\n        pybind11_fail(\"Could not allocate bytes object!\");\n    }\n    m_ptr = obj.release().ptr();\n}\n\ninline str::str(const bytes &b) {\n    char *buffer = nullptr;\n    ssize_t length = 0;\n    if (PyBytes_AsStringAndSize(b.ptr(), &buffer, &length) != 0) {\n        throw error_already_set();\n    }\n    auto obj = reinterpret_steal<object>(PyUnicode_FromStringAndSize(buffer, length));\n    if (!obj) {\n        if (PyErr_Occurred()) {\n            throw error_already_set();\n        }\n        pybind11_fail(\"Could not allocate string object!\");\n    }\n    m_ptr = obj.release().ptr();\n}\n\n/// \\addtogroup pytypes\n/// @{\nclass bytearray : public object {\npublic:\n    PYBIND11_OBJECT_CVT(bytearray, object, PyByteArray_Check, PyByteArray_FromObject)\n\n    template <typename SzType, detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>\n    bytearray(const char *c, const SzType &n)\n        : object(PyByteArray_FromStringAndSize(c, ssize_t_cast(n)), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate bytearray object!\");\n        }\n    }\n\n    bytearray() : bytearray(\"\", 0) {}\n\n    explicit bytearray(const std::string &s) : bytearray(s.data(), s.size()) {}\n\n    size_t size() const { return static_cast<size_t>(PyByteArray_Size(m_ptr)); }\n\n    explicit operator std::string() const {\n        char *buffer = PyByteArray_AS_STRING(m_ptr);\n        ssize_t size = PyByteArray_GET_SIZE(m_ptr);\n        return std::string(buffer, static_cast<size_t>(size));\n    }\n};\n// Note: breathe >= 4.17.0 will fail to build docs if the below two constructors\n// are included in the doxygen group; close here and reopen after as a workaround\n/// @} pytypes\n\n/// \\addtogroup pytypes\n/// @{\nclass none : public object {\npublic:\n    PYBIND11_OBJECT(none, object, detail::PyNone_Check)\n    none() : object(Py_None, borrowed_t{}) {}\n};\n\nclass ellipsis : public object {\npublic:\n    PYBIND11_OBJECT(ellipsis, object, detail::PyEllipsis_Check)\n    ellipsis() : object(Py_Ellipsis, borrowed_t{}) {}\n};\n\nclass bool_ : public object {\npublic:\n    PYBIND11_OBJECT_CVT(bool_, object, PyBool_Check, raw_bool)\n    bool_() : object(Py_False, borrowed_t{}) {}\n    // Allow implicit conversion from and to `bool`:\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) {}\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }\n\nprivate:\n    /// Return the truth value of an object -- always returns a new reference\n    static PyObject *raw_bool(PyObject *op) {\n        const auto value = PyObject_IsTrue(op);\n        if (value == -1) {\n            return nullptr;\n        }\n        return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();\n    }\n};\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n// Converts a value to the given unsigned type.  If an error occurs, you get back (Unsigned) -1;\n// otherwise you get back the unsigned long or unsigned long long value cast to (Unsigned).\n// (The distinction is critically important when casting a returned -1 error value to some other\n// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).\ntemplate <typename Unsigned>\nUnsigned as_unsigned(PyObject *o) {\n    if (sizeof(Unsigned) <= sizeof(unsigned long)) {\n        unsigned long v = PyLong_AsUnsignedLong(o);\n        return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;\n    }\n    unsigned long long v = PyLong_AsUnsignedLongLong(o);\n    return v == (unsigned long long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;\n}\nPYBIND11_NAMESPACE_END(detail)\n\nclass int_ : public object {\npublic:\n    PYBIND11_OBJECT_CVT(int_, object, PYBIND11_LONG_CHECK, PyNumber_Long)\n    int_() : object(PyLong_FromLong(0), stolen_t{}) {}\n    // Allow implicit conversion from C++ integral types:\n    template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    int_(T value) {\n        if (sizeof(T) <= sizeof(long)) {\n            if (std::is_signed<T>::value) {\n                m_ptr = PyLong_FromLong((long) value);\n            } else {\n                m_ptr = PyLong_FromUnsignedLong((unsigned long) value);\n            }\n        } else {\n            if (std::is_signed<T>::value) {\n                m_ptr = PyLong_FromLongLong((long long) value);\n            } else {\n                m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);\n            }\n        }\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate int object!\");\n        }\n    }\n\n    template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator T() const {\n        return std::is_unsigned<T>::value  ? detail::as_unsigned<T>(m_ptr)\n               : sizeof(T) <= sizeof(long) ? (T) PyLong_AsLong(m_ptr)\n                                           : (T) PYBIND11_LONG_AS_LONGLONG(m_ptr);\n    }\n};\n\nclass float_ : public object {\npublic:\n    PYBIND11_OBJECT_CVT(float_, object, PyFloat_Check, PyNumber_Float)\n    // Allow implicit conversion from float/double:\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    float_(float value) : object(PyFloat_FromDouble((double) value), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate float object!\");\n        }\n    }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    float_(double value = .0) : object(PyFloat_FromDouble((double) value), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate float object!\");\n        }\n    }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator float() const { return (float) PyFloat_AsDouble(m_ptr); }\n    // NOLINTNEXTLINE(google-explicit-constructor)\n    operator double() const { return (double) PyFloat_AsDouble(m_ptr); }\n};\n\nclass weakref : public object {\npublic:\n    PYBIND11_OBJECT_CVT_DEFAULT(weakref, object, PyWeakref_Check, raw_weakref)\n    explicit weakref(handle obj, handle callback = {})\n        : object(PyWeakref_NewRef(obj.ptr(), callback.ptr()), stolen_t{}) {\n        if (!m_ptr) {\n            if (PyErr_Occurred()) {\n                throw error_already_set();\n            }\n            pybind11_fail(\"Could not allocate weak reference!\");\n        }\n    }\n\nprivate:\n    static PyObject *raw_weakref(PyObject *o) { return PyWeakref_NewRef(o, nullptr); }\n};\n\nclass slice : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(slice, object, PySlice_Check)\n    slice(handle start, handle stop, handle step)\n        : object(PySlice_New(start.ptr(), stop.ptr(), step.ptr()), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate slice object!\");\n        }\n    }\n\n#ifdef PYBIND11_HAS_OPTIONAL\n    slice(std::optional<ssize_t> start, std::optional<ssize_t> stop, std::optional<ssize_t> step)\n        : slice(index_to_object(start), index_to_object(stop), index_to_object(step)) {}\n#else\n    slice(ssize_t start_, ssize_t stop_, ssize_t step_)\n        : slice(int_(start_), int_(stop_), int_(step_)) {}\n#endif\n\n    bool\n    compute(size_t length, size_t *start, size_t *stop, size_t *step, size_t *slicelength) const {\n        return PySlice_GetIndicesEx((PYBIND11_SLICE_OBJECT *) m_ptr,\n                                    (ssize_t) length,\n                                    (ssize_t *) start,\n                                    (ssize_t *) stop,\n                                    (ssize_t *) step,\n                                    (ssize_t *) slicelength)\n               == 0;\n    }\n    bool compute(\n        ssize_t length, ssize_t *start, ssize_t *stop, ssize_t *step, ssize_t *slicelength) const {\n        return PySlice_GetIndicesEx(\n                   (PYBIND11_SLICE_OBJECT *) m_ptr, length, start, stop, step, slicelength)\n               == 0;\n    }\n\nprivate:\n    template <typename T>\n    static object index_to_object(T index) {\n        return index ? object(int_(*index)) : object(none());\n    }\n};\n\nclass capsule : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)\n    PYBIND11_DEPRECATED(\"Use reinterpret_borrow<capsule>() or reinterpret_steal<capsule>()\")\n    capsule(PyObject *ptr, bool is_borrowed)\n        : object(is_borrowed ? object(ptr, borrowed_t{}) : object(ptr, stolen_t{})) {}\n\n    explicit capsule(const void *value,\n                     const char *name = nullptr,\n                     PyCapsule_Destructor destructor = nullptr)\n        : object(PyCapsule_New(const_cast<void *>(value), name, destructor), stolen_t{}) {\n        if (!m_ptr) {\n            throw error_already_set();\n        }\n    }\n\n    PYBIND11_DEPRECATED(\"Please use the ctor with value, name, destructor args\")\n    capsule(const void *value, PyCapsule_Destructor destructor)\n        : object(PyCapsule_New(const_cast<void *>(value), nullptr, destructor), stolen_t{}) {\n        if (!m_ptr) {\n            throw error_already_set();\n        }\n    }\n\n    /// Capsule name is nullptr.\n    capsule(const void *value, void (*destructor)(void *)) {\n        initialize_with_void_ptr_destructor(value, nullptr, destructor);\n    }\n\n    capsule(const void *value, const char *name, void (*destructor)(void *)) {\n        initialize_with_void_ptr_destructor(value, name, destructor);\n    }\n\n    explicit capsule(void (*destructor)()) {\n        m_ptr = PyCapsule_New(reinterpret_cast<void *>(destructor), nullptr, [](PyObject *o) {\n            const char *name = get_name_in_error_scope(o);\n            auto destructor = reinterpret_cast<void (*)()>(PyCapsule_GetPointer(o, name));\n            if (destructor == nullptr) {\n                throw error_already_set();\n            }\n            destructor();\n        });\n\n        if (!m_ptr) {\n            throw error_already_set();\n        }\n    }\n\n    template <typename T>\n    operator T *() const { // NOLINT(google-explicit-constructor)\n        return get_pointer<T>();\n    }\n\n    /// Get the pointer the capsule holds.\n    template <typename T = void>\n    T *get_pointer() const {\n        const auto *name = this->name();\n        T *result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, name));\n        if (!result) {\n            throw error_already_set();\n        }\n        return result;\n    }\n\n    /// Replaces a capsule's pointer *without* calling the destructor on the existing one.\n    void set_pointer(const void *value) {\n        if (PyCapsule_SetPointer(m_ptr, const_cast<void *>(value)) != 0) {\n            throw error_already_set();\n        }\n    }\n\n    const char *name() const {\n        const char *name = PyCapsule_GetName(m_ptr);\n        if ((name == nullptr) && PyErr_Occurred()) {\n            throw error_already_set();\n        }\n        return name;\n    }\n\n    /// Replaces a capsule's name *without* calling the destructor on the existing one.\n    void set_name(const char *new_name) {\n        if (PyCapsule_SetName(m_ptr, new_name) != 0) {\n            throw error_already_set();\n        }\n    }\n\nprivate:\n    static const char *get_name_in_error_scope(PyObject *o) {\n        error_scope error_guard;\n\n        const char *name = PyCapsule_GetName(o);\n        if ((name == nullptr) && PyErr_Occurred()) {\n            // write out and consume error raised by call to PyCapsule_GetName\n            PyErr_WriteUnraisable(o);\n        }\n\n        return name;\n    }\n\n    void initialize_with_void_ptr_destructor(const void *value,\n                                             const char *name,\n                                             void (*destructor)(void *)) {\n        m_ptr = PyCapsule_New(const_cast<void *>(value), name, [](PyObject *o) {\n            // guard if destructor called while err indicator is set\n            error_scope error_guard;\n            auto destructor = reinterpret_cast<void (*)(void *)>(PyCapsule_GetContext(o));\n            if (destructor == nullptr && PyErr_Occurred()) {\n                throw error_already_set();\n            }\n            const char *name = get_name_in_error_scope(o);\n            void *ptr = PyCapsule_GetPointer(o, name);\n            if (ptr == nullptr) {\n                throw error_already_set();\n            }\n\n            if (destructor != nullptr) {\n                destructor(ptr);\n            }\n        });\n\n        if (!m_ptr || PyCapsule_SetContext(m_ptr, reinterpret_cast<void *>(destructor)) != 0) {\n            throw error_already_set();\n        }\n    }\n};\n\nclass tuple : public object {\npublic:\n    PYBIND11_OBJECT_CVT(tuple, object, PyTuple_Check, PySequence_Tuple)\n    template <typename SzType = ssize_t,\n              detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>\n    // Some compilers generate link errors when using `const SzType &` here:\n    explicit tuple(SzType size = 0) : object(PyTuple_New(ssize_t_cast(size)), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate tuple object!\");\n        }\n    }\n    size_t size() const { return (size_t) PyTuple_Size(m_ptr); }\n    bool empty() const { return size() == 0; }\n    detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }\n    template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>\n    detail::item_accessor operator[](T &&o) const {\n        return object::operator[](std::forward<T>(o));\n    }\n    detail::tuple_iterator begin() const { return {*this, 0}; }\n    detail::tuple_iterator end() const { return {*this, PyTuple_GET_SIZE(m_ptr)}; }\n};\n\n// We need to put this into a separate function because the Intel compiler\n// fails to compile enable_if_t<all_of<is_keyword_or_ds<Args>...>::value> part below\n// (tested with ICC 2021.1 Beta 20200827).\ntemplate <typename... Args>\nconstexpr bool args_are_all_keyword_or_ds() {\n    return detail::all_of<detail::is_keyword_or_ds<Args>...>::value;\n}\n\nclass dict : public object {\npublic:\n    PYBIND11_OBJECT_CVT(dict, object, PyDict_Check, raw_dict)\n    dict() : object(PyDict_New(), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate dict object!\");\n        }\n    }\n    template <typename... Args,\n              typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>,\n              // MSVC workaround: it can't compile an out-of-line definition, so defer the\n              // collector\n              typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>\n    explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) {}\n\n    size_t size() const { return (size_t) PyDict_Size(m_ptr); }\n    bool empty() const { return size() == 0; }\n    detail::dict_iterator begin() const { return {*this, 0}; }\n    detail::dict_iterator end() const { return {}; }\n    void clear() /* py-non-const */ { PyDict_Clear(ptr()); }\n    template <typename T>\n    bool contains(T &&key) const {\n        auto result = PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr());\n        if (result == -1) {\n            throw error_already_set();\n        }\n        return result == 1;\n    }\n\nprivate:\n    /// Call the `dict` Python type -- always returns a new reference\n    static PyObject *raw_dict(PyObject *op) {\n        if (PyDict_Check(op)) {\n            return handle(op).inc_ref().ptr();\n        }\n        return PyObject_CallFunctionObjArgs((PyObject *) &PyDict_Type, op, nullptr);\n    }\n};\n\nclass sequence : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(sequence, object, PySequence_Check)\n    size_t size() const {\n        ssize_t result = PySequence_Size(m_ptr);\n        if (result == -1) {\n            throw error_already_set();\n        }\n        return (size_t) result;\n    }\n    bool empty() const { return size() == 0; }\n    detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }\n    template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>\n    detail::item_accessor operator[](T &&o) const {\n        return object::operator[](std::forward<T>(o));\n    }\n    detail::sequence_iterator begin() const { return {*this, 0}; }\n    detail::sequence_iterator end() const { return {*this, PySequence_Size(m_ptr)}; }\n};\n\nclass list : public object {\npublic:\n    PYBIND11_OBJECT_CVT(list, object, PyList_Check, PySequence_List)\n    template <typename SzType = ssize_t,\n              detail::enable_if_t<std::is_integral<SzType>::value, int> = 0>\n    // Some compilers generate link errors when using `const SzType &` here:\n    explicit list(SzType size = 0) : object(PyList_New(ssize_t_cast(size)), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate list object!\");\n        }\n    }\n    size_t size() const { return (size_t) PyList_Size(m_ptr); }\n    bool empty() const { return size() == 0; }\n    detail::list_accessor operator[](size_t index) const { return {*this, index}; }\n    template <typename T, detail::enable_if_t<detail::is_pyobject<T>::value, int> = 0>\n    detail::item_accessor operator[](T &&o) const {\n        return object::operator[](std::forward<T>(o));\n    }\n    detail::list_iterator begin() const { return {*this, 0}; }\n    detail::list_iterator end() const { return {*this, PyList_GET_SIZE(m_ptr)}; }\n    template <typename T>\n    void append(T &&val) /* py-non-const */ {\n        if (PyList_Append(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) != 0) {\n            throw error_already_set();\n        }\n    }\n    template <typename IdxType,\n              typename ValType,\n              detail::enable_if_t<std::is_integral<IdxType>::value, int> = 0>\n    void insert(const IdxType &index, ValType &&val) /* py-non-const */ {\n        if (PyList_Insert(m_ptr,\n                          ssize_t_cast(index),\n                          detail::object_or_cast(std::forward<ValType>(val)).ptr())\n            != 0) {\n            throw error_already_set();\n        }\n    }\n};\n\nclass args : public tuple {\n    PYBIND11_OBJECT_DEFAULT(args, tuple, PyTuple_Check)\n};\nclass kwargs : public dict {\n    PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)\n};\n\nclass anyset : public object {\npublic:\n    PYBIND11_OBJECT(anyset, object, PyAnySet_Check)\n    size_t size() const { return static_cast<size_t>(PySet_Size(m_ptr)); }\n    bool empty() const { return size() == 0; }\n    template <typename T>\n    bool contains(T &&val) const {\n        auto result = PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr());\n        if (result == -1) {\n            throw error_already_set();\n        }\n        return result == 1;\n    }\n};\n\nclass set : public anyset {\npublic:\n    PYBIND11_OBJECT_CVT(set, anyset, PySet_Check, PySet_New)\n    set() : anyset(PySet_New(nullptr), stolen_t{}) {\n        if (!m_ptr) {\n            pybind11_fail(\"Could not allocate set object!\");\n        }\n    }\n    template <typename T>\n    bool add(T &&val) /* py-non-const */ {\n        return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;\n    }\n    void clear() /* py-non-const */ { PySet_Clear(m_ptr); }\n};\n\nclass frozenset : public anyset {\npublic:\n    PYBIND11_OBJECT_CVT(frozenset, anyset, PyFrozenSet_Check, PyFrozenSet_New)\n};\n\nclass function : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(function, object, PyCallable_Check)\n    handle cpp_function() const {\n        handle fun = detail::get_function(m_ptr);\n        if (fun && PyCFunction_Check(fun.ptr())) {\n            return fun;\n        }\n        return handle();\n    }\n    bool is_cpp_function() const { return (bool) cpp_function(); }\n};\n\nclass staticmethod : public object {\npublic:\n    PYBIND11_OBJECT_CVT(staticmethod, object, detail::PyStaticMethod_Check, PyStaticMethod_New)\n};\n\nclass buffer : public object {\npublic:\n    PYBIND11_OBJECT_DEFAULT(buffer, object, PyObject_CheckBuffer)\n\n    buffer_info request(bool writable = false) const {\n        int flags = PyBUF_STRIDES | PyBUF_FORMAT;\n        if (writable) {\n            flags |= PyBUF_WRITABLE;\n        }\n        auto *view = new Py_buffer();\n        if (PyObject_GetBuffer(m_ptr, view, flags) != 0) {\n            delete view;\n            throw error_already_set();\n        }\n        return buffer_info(view);\n    }\n};\n\nclass memoryview : public object {\npublic:\n    PYBIND11_OBJECT_CVT(memoryview, object, PyMemoryView_Check, PyMemoryView_FromObject)\n\n    /** \\rst\n        Creates ``memoryview`` from ``buffer_info``.\n\n        ``buffer_info`` must be created from ``buffer::request()``. Otherwise\n        throws an exception.\n\n        For creating a ``memoryview`` from objects that support buffer protocol,\n        use ``memoryview(const object& obj)`` instead of this constructor.\n     \\endrst */\n    explicit memoryview(const buffer_info &info) {\n        if (!info.view()) {\n            pybind11_fail(\"Prohibited to create memoryview without Py_buffer\");\n        }\n        // Note: PyMemoryView_FromBuffer never increments obj reference.\n        m_ptr = (info.view()->obj) ? PyMemoryView_FromObject(info.view()->obj)\n                                   : PyMemoryView_FromBuffer(info.view());\n        if (!m_ptr) {\n            pybind11_fail(\"Unable to create memoryview from buffer descriptor\");\n        }\n    }\n\n    /** \\rst\n        Creates ``memoryview`` from static buffer.\n\n        This method is meant for providing a ``memoryview`` for C/C++ buffer not\n        managed by Python. The caller is responsible for managing the lifetime\n        of ``ptr`` and ``format``, which MUST outlive the memoryview constructed\n        here.\n\n        See also: Python C API documentation for `PyMemoryView_FromBuffer`_.\n\n        .. _PyMemoryView_FromBuffer:\n           https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromBuffer\n\n        :param ptr: Pointer to the buffer.\n        :param itemsize: Byte size of an element.\n        :param format: Pointer to the null-terminated format string. For\n            homogeneous Buffers, this should be set to\n            ``format_descriptor<T>::value``.\n        :param shape: Shape of the tensor (1 entry per dimension).\n        :param strides: Number of bytes between adjacent entries (for each\n            per dimension).\n        :param readonly: Flag to indicate if the underlying storage may be\n            written to.\n     \\endrst */\n    static memoryview from_buffer(void *ptr,\n                                  ssize_t itemsize,\n                                  const char *format,\n                                  detail::any_container<ssize_t> shape,\n                                  detail::any_container<ssize_t> strides,\n                                  bool readonly = false);\n\n    static memoryview from_buffer(const void *ptr,\n                                  ssize_t itemsize,\n                                  const char *format,\n                                  detail::any_container<ssize_t> shape,\n                                  detail::any_container<ssize_t> strides) {\n        return memoryview::from_buffer(\n            const_cast<void *>(ptr), itemsize, format, std::move(shape), std::move(strides), true);\n    }\n\n    template <typename T>\n    static memoryview from_buffer(T *ptr,\n                                  detail::any_container<ssize_t> shape,\n                                  detail::any_container<ssize_t> strides,\n                                  bool readonly = false) {\n        return memoryview::from_buffer(reinterpret_cast<void *>(ptr),\n                                       sizeof(T),\n                                       format_descriptor<T>::value,\n                                       std::move(shape),\n                                       std::move(strides),\n                                       readonly);\n    }\n\n    template <typename T>\n    static memoryview from_buffer(const T *ptr,\n                                  detail::any_container<ssize_t> shape,\n                                  detail::any_container<ssize_t> strides) {\n        return memoryview::from_buffer(\n            const_cast<T *>(ptr), std::move(shape), std::move(strides), true);\n    }\n\n    /** \\rst\n        Creates ``memoryview`` from static memory.\n\n        This method is meant for providing a ``memoryview`` for C/C++ buffer not\n        managed by Python. The caller is responsible for managing the lifetime\n        of ``mem``, which MUST outlive the memoryview constructed here.\n\n        See also: Python C API documentation for `PyMemoryView_FromBuffer`_.\n\n        .. _PyMemoryView_FromMemory:\n           https://docs.python.org/c-api/memoryview.html#c.PyMemoryView_FromMemory\n     \\endrst */\n    static memoryview from_memory(void *mem, ssize_t size, bool readonly = false) {\n        PyObject *ptr = PyMemoryView_FromMemory(\n            reinterpret_cast<char *>(mem), size, (readonly) ? PyBUF_READ : PyBUF_WRITE);\n        if (!ptr) {\n            pybind11_fail(\"Could not allocate memoryview object!\");\n        }\n        return memoryview(object(ptr, stolen_t{}));\n    }\n\n    static memoryview from_memory(const void *mem, ssize_t size) {\n        return memoryview::from_memory(const_cast<void *>(mem), size, true);\n    }\n\n#ifdef PYBIND11_HAS_STRING_VIEW\n    static memoryview from_memory(std::string_view mem) {\n        return from_memory(const_cast<char *>(mem.data()), static_cast<ssize_t>(mem.size()), true);\n    }\n#endif\n};\n\n/// @cond DUPLICATE\ninline memoryview memoryview::from_buffer(void *ptr,\n                                          ssize_t itemsize,\n                                          const char *format,\n                                          detail::any_container<ssize_t> shape,\n                                          detail::any_container<ssize_t> strides,\n                                          bool readonly) {\n    size_t ndim = shape->size();\n    if (ndim != strides->size()) {\n        pybind11_fail(\"memoryview: shape length doesn't match strides length\");\n    }\n    ssize_t size = ndim != 0u ? 1 : 0;\n    for (size_t i = 0; i < ndim; ++i) {\n        size *= (*shape)[i];\n    }\n    Py_buffer view;\n    view.buf = ptr;\n    view.obj = nullptr;\n    view.len = size * itemsize;\n    view.readonly = static_cast<int>(readonly);\n    view.itemsize = itemsize;\n    view.format = const_cast<char *>(format);\n    view.ndim = static_cast<int>(ndim);\n    view.shape = shape->data();\n    view.strides = strides->data();\n    view.suboffsets = nullptr;\n    view.internal = nullptr;\n    PyObject *obj = PyMemoryView_FromBuffer(&view);\n    if (!obj) {\n        throw error_already_set();\n    }\n    return memoryview(object(obj, stolen_t{}));\n}\n/// @endcond\n/// @} pytypes\n\n/// \\addtogroup python_builtins\n/// @{\n\n/// Get the length of a Python object.\ninline size_t len(handle h) {\n    ssize_t result = PyObject_Length(h.ptr());\n    if (result < 0) {\n        throw error_already_set();\n    }\n    return (size_t) result;\n}\n\n/// Get the length hint of a Python object.\n/// Returns 0 when this cannot be determined.\ninline size_t len_hint(handle h) {\n    ssize_t result = PyObject_LengthHint(h.ptr(), 0);\n    if (result < 0) {\n        // Sometimes a length can't be determined at all (eg generators)\n        // In which case simply return 0\n        PyErr_Clear();\n        return 0;\n    }\n    return (size_t) result;\n}\n\ninline str repr(handle h) {\n    PyObject *str_value = PyObject_Repr(h.ptr());\n    if (!str_value) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<str>(str_value);\n}\n\ninline iterator iter(handle obj) {\n    PyObject *result = PyObject_GetIter(obj.ptr());\n    if (!result) {\n        throw error_already_set();\n    }\n    return reinterpret_steal<iterator>(result);\n}\n/// @} python_builtins\n\nPYBIND11_NAMESPACE_BEGIN(detail)\ntemplate <typename D>\niterator object_api<D>::begin() const {\n    return iter(derived());\n}\ntemplate <typename D>\niterator object_api<D>::end() const {\n    return iterator::sentinel();\n}\ntemplate <typename D>\nitem_accessor object_api<D>::operator[](handle key) const {\n    return {derived(), reinterpret_borrow<object>(key)};\n}\ntemplate <typename D>\nitem_accessor object_api<D>::operator[](object &&key) const {\n    return {derived(), std::move(key)};\n}\ntemplate <typename D>\nitem_accessor object_api<D>::operator[](const char *key) const {\n    return {derived(), pybind11::str(key)};\n}\ntemplate <typename D>\nobj_attr_accessor object_api<D>::attr(handle key) const {\n    return {derived(), reinterpret_borrow<object>(key)};\n}\ntemplate <typename D>\nobj_attr_accessor object_api<D>::attr(object &&key) const {\n    return {derived(), std::move(key)};\n}\ntemplate <typename D>\nstr_attr_accessor object_api<D>::attr(const char *key) const {\n    return {derived(), key};\n}\ntemplate <typename D>\nargs_proxy object_api<D>::operator*() const {\n    return args_proxy(derived().ptr());\n}\ntemplate <typename D>\ntemplate <typename T>\nbool object_api<D>::contains(T &&item) const {\n    return attr(\"__contains__\")(std::forward<T>(item)).template cast<bool>();\n}\n\ntemplate <typename D>\npybind11::str object_api<D>::str() const {\n    return pybind11::str(derived());\n}\n\ntemplate <typename D>\nstr_attr_accessor object_api<D>::doc() const {\n    return attr(\"__doc__\");\n}\n\ntemplate <typename D>\nhandle object_api<D>::get_type() const {\n    return type::handle_of(derived());\n}\n\ntemplate <typename D>\nbool object_api<D>::rich_compare(object_api const &other, int value) const {\n    int rv = PyObject_RichCompareBool(derived().ptr(), other.derived().ptr(), value);\n    if (rv == -1) {\n        throw error_already_set();\n    }\n    return rv == 1;\n}\n\n#define PYBIND11_MATH_OPERATOR_UNARY(op, fn)                                                      \\\n    template <typename D>                                                                         \\\n    object object_api<D>::op() const {                                                            \\\n        object result = reinterpret_steal<object>(fn(derived().ptr()));                           \\\n        if (!result.ptr())                                                                        \\\n            throw error_already_set();                                                            \\\n        return result;                                                                            \\\n    }\n\n#define PYBIND11_MATH_OPERATOR_BINARY(op, fn)                                                     \\\n    template <typename D>                                                                         \\\n    object object_api<D>::op(object_api const &other) const {                                     \\\n        object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr()));    \\\n        if (!result.ptr())                                                                        \\\n            throw error_already_set();                                                            \\\n        return result;                                                                            \\\n    }\n\n#define PYBIND11_MATH_OPERATOR_BINARY_INPLACE(iop, fn)                                            \\\n    template <typename D>                                                                         \\\n    object object_api<D>::iop(object_api const &other) {                                          \\\n        object result = reinterpret_steal<object>(fn(derived().ptr(), other.derived().ptr()));    \\\n        if (!result.ptr())                                                                        \\\n            throw error_already_set();                                                            \\\n        return result;                                                                            \\\n    }\n\nPYBIND11_MATH_OPERATOR_UNARY(operator~, PyNumber_Invert)\nPYBIND11_MATH_OPERATOR_UNARY(operator-, PyNumber_Negative)\nPYBIND11_MATH_OPERATOR_BINARY(operator+, PyNumber_Add)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator+=, PyNumber_InPlaceAdd)\nPYBIND11_MATH_OPERATOR_BINARY(operator-, PyNumber_Subtract)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator-=, PyNumber_InPlaceSubtract)\nPYBIND11_MATH_OPERATOR_BINARY(operator*, PyNumber_Multiply)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator*=, PyNumber_InPlaceMultiply)\nPYBIND11_MATH_OPERATOR_BINARY(operator/, PyNumber_TrueDivide)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator/=, PyNumber_InPlaceTrueDivide)\nPYBIND11_MATH_OPERATOR_BINARY(operator|, PyNumber_Or)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator|=, PyNumber_InPlaceOr)\nPYBIND11_MATH_OPERATOR_BINARY(operator&, PyNumber_And)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator&=, PyNumber_InPlaceAnd)\nPYBIND11_MATH_OPERATOR_BINARY(operator^, PyNumber_Xor)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator^=, PyNumber_InPlaceXor)\nPYBIND11_MATH_OPERATOR_BINARY(operator<<, PyNumber_Lshift)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator<<=, PyNumber_InPlaceLshift)\nPYBIND11_MATH_OPERATOR_BINARY(operator>>, PyNumber_Rshift)\nPYBIND11_MATH_OPERATOR_BINARY_INPLACE(operator>>=, PyNumber_InPlaceRshift)\n\n#undef PYBIND11_MATH_OPERATOR_UNARY\n#undef PYBIND11_MATH_OPERATOR_BINARY\n#undef PYBIND11_MATH_OPERATOR_BINARY_INPLACE\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/stl/filesystem.h",
    "content": "// Copyright (c) 2021 The Pybind Development Team.\n// All rights reserved. Use of this source code is governed by a\n// BSD-style license that can be found in the LICENSE file.\n\n#pragma once\n\n#include \"../pybind11.h\"\n#include \"../detail/common.h\"\n#include \"../detail/descr.h\"\n#include \"../cast.h\"\n#include \"../pytypes.h\"\n\n#include <string>\n\n#ifdef __has_include\n#    if defined(PYBIND11_CPP17)\n#        if __has_include(<filesystem>) && \\\n          PY_VERSION_HEX >= 0x03060000\n#            include <filesystem>\n#            define PYBIND11_HAS_FILESYSTEM 1\n#        elif __has_include(<experimental/filesystem>)\n#            include <experimental/filesystem>\n#            define PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM 1\n#        endif\n#    endif\n#endif\n\n#if !defined(PYBIND11_HAS_FILESYSTEM) && !defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)           \\\n    && !defined(PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL)\n#    error                                                                                        \\\n        \"Neither #include <filesystem> nor #include <experimental/filesystem is available. (Use -DPYBIND11_HAS_FILESYSTEM_IS_OPTIONAL to ignore.)\"\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n#if defined(PYBIND11_HAS_FILESYSTEM) || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)\ntemplate <typename T>\nstruct path_caster {\n\nprivate:\n    static PyObject *unicode_from_fs_native(const std::string &w) {\n#    if !defined(PYPY_VERSION)\n        return PyUnicode_DecodeFSDefaultAndSize(w.c_str(), ssize_t(w.size()));\n#    else\n        // PyPy mistakenly declares the first parameter as non-const.\n        return PyUnicode_DecodeFSDefaultAndSize(const_cast<char *>(w.c_str()), ssize_t(w.size()));\n#    endif\n    }\n\n    static PyObject *unicode_from_fs_native(const std::wstring &w) {\n        return PyUnicode_FromWideChar(w.c_str(), ssize_t(w.size()));\n    }\n\npublic:\n    static handle cast(const T &path, return_value_policy, handle) {\n        if (auto py_str = unicode_from_fs_native(path.native())) {\n            return module_::import(\"pathlib\")\n                .attr(\"Path\")(reinterpret_steal<object>(py_str))\n                .release();\n        }\n        return nullptr;\n    }\n\n    bool load(handle handle, bool) {\n        // PyUnicode_FSConverter and PyUnicode_FSDecoder normally take care of\n        // calling PyOS_FSPath themselves, but that's broken on PyPy (PyPy\n        // issue #3168) so we do it ourselves instead.\n        PyObject *buf = PyOS_FSPath(handle.ptr());\n        if (!buf) {\n            PyErr_Clear();\n            return false;\n        }\n        PyObject *native = nullptr;\n        if constexpr (std::is_same_v<typename T::value_type, char>) {\n            if (PyUnicode_FSConverter(buf, &native) != 0) {\n                if (auto *c_str = PyBytes_AsString(native)) {\n                    // AsString returns a pointer to the internal buffer, which\n                    // must not be free'd.\n                    value = c_str;\n                }\n            }\n        } else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {\n            if (PyUnicode_FSDecoder(buf, &native) != 0) {\n                if (auto *c_str = PyUnicode_AsWideCharString(native, nullptr)) {\n                    // AsWideCharString returns a new string that must be free'd.\n                    value = c_str; // Copies the string.\n                    PyMem_Free(c_str);\n                }\n            }\n        }\n        Py_XDECREF(native);\n        Py_DECREF(buf);\n        if (PyErr_Occurred()) {\n            PyErr_Clear();\n            return false;\n        }\n        return true;\n    }\n\n    PYBIND11_TYPE_CASTER(T, const_name(\"os.PathLike\"));\n};\n\n#endif // PYBIND11_HAS_FILESYSTEM || defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)\n\n#if defined(PYBIND11_HAS_FILESYSTEM)\ntemplate <>\nstruct type_caster<std::filesystem::path> : public path_caster<std::filesystem::path> {};\n#elif defined(PYBIND11_HAS_EXPERIMENTAL_FILESYSTEM)\ntemplate <>\nstruct type_caster<std::experimental::filesystem::path>\n    : public path_caster<std::experimental::filesystem::path> {};\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/stl.h",
    "content": "/*\n    pybind11/stl.h: Transparent conversion for STL data types\n\n    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"pybind11.h\"\n#include \"detail/common.h\"\n\n#include <deque>\n#include <list>\n#include <map>\n#include <ostream>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <valarray>\n\n// See `detail/common.h` for implementation of these guards.\n#if defined(PYBIND11_HAS_OPTIONAL)\n#    include <optional>\n#elif defined(PYBIND11_HAS_EXP_OPTIONAL)\n#    include <experimental/optional>\n#endif\n\n#if defined(PYBIND11_HAS_VARIANT)\n#    include <variant>\n#endif\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/// Extracts an const lvalue reference or rvalue reference for U based on the type of T (e.g. for\n/// forwarding a container element).  Typically used indirect via forwarded_type(), below.\ntemplate <typename T, typename U>\nusing forwarded_type = conditional_t<std::is_lvalue_reference<T>::value,\n                                     remove_reference_t<U> &,\n                                     remove_reference_t<U> &&>;\n\n/// Forwards a value U as rvalue or lvalue according to whether T is rvalue or lvalue; typically\n/// used for forwarding a container's elements.\ntemplate <typename T, typename U>\nconstexpr forwarded_type<T, U> forward_like(U &&u) {\n    return std::forward<detail::forwarded_type<T, U>>(std::forward<U>(u));\n}\n\n// Checks if a container has a STL style reserve method.\n// This will only return true for a `reserve()` with a `void` return.\ntemplate <typename C>\nusing has_reserve_method = std::is_same<decltype(std::declval<C>().reserve(0)), void>;\n\ntemplate <typename Type, typename Key>\nstruct set_caster {\n    using type = Type;\n    using key_conv = make_caster<Key>;\n\nprivate:\n    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>\n    void reserve_maybe(const anyset &s, Type *) {\n        value.reserve(s.size());\n    }\n    void reserve_maybe(const anyset &, void *) {}\n\npublic:\n    bool load(handle src, bool convert) {\n        if (!isinstance<anyset>(src)) {\n            return false;\n        }\n        auto s = reinterpret_borrow<anyset>(src);\n        value.clear();\n        reserve_maybe(s, &value);\n        for (auto entry : s) {\n            key_conv conv;\n            if (!conv.load(entry, convert)) {\n                return false;\n            }\n            value.insert(cast_op<Key &&>(std::move(conv)));\n        }\n        return true;\n    }\n\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        if (!std::is_lvalue_reference<T>::value) {\n            policy = return_value_policy_override<Key>::policy(policy);\n        }\n        pybind11::set s;\n        for (auto &&value : src) {\n            auto value_ = reinterpret_steal<object>(\n                key_conv::cast(detail::forward_like<T>(value), policy, parent));\n            if (!value_ || !s.add(std::move(value_))) {\n                return handle();\n            }\n        }\n        return s.release();\n    }\n\n    PYBIND11_TYPE_CASTER(type, const_name(\"set[\") + key_conv::name + const_name(\"]\"));\n};\n\ntemplate <typename Type, typename Key, typename Value>\nstruct map_caster {\n    using key_conv = make_caster<Key>;\n    using value_conv = make_caster<Value>;\n\nprivate:\n    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>\n    void reserve_maybe(const dict &d, Type *) {\n        value.reserve(d.size());\n    }\n    void reserve_maybe(const dict &, void *) {}\n\npublic:\n    bool load(handle src, bool convert) {\n        if (!isinstance<dict>(src)) {\n            return false;\n        }\n        auto d = reinterpret_borrow<dict>(src);\n        value.clear();\n        reserve_maybe(d, &value);\n        for (auto it : d) {\n            key_conv kconv;\n            value_conv vconv;\n            if (!kconv.load(it.first.ptr(), convert) || !vconv.load(it.second.ptr(), convert)) {\n                return false;\n            }\n            value.emplace(cast_op<Key &&>(std::move(kconv)), cast_op<Value &&>(std::move(vconv)));\n        }\n        return true;\n    }\n\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        dict d;\n        return_value_policy policy_key = policy;\n        return_value_policy policy_value = policy;\n        if (!std::is_lvalue_reference<T>::value) {\n            policy_key = return_value_policy_override<Key>::policy(policy_key);\n            policy_value = return_value_policy_override<Value>::policy(policy_value);\n        }\n        for (auto &&kv : src) {\n            auto key = reinterpret_steal<object>(\n                key_conv::cast(detail::forward_like<T>(kv.first), policy_key, parent));\n            auto value = reinterpret_steal<object>(\n                value_conv::cast(detail::forward_like<T>(kv.second), policy_value, parent));\n            if (!key || !value) {\n                return handle();\n            }\n            d[std::move(key)] = std::move(value);\n        }\n        return d.release();\n    }\n\n    PYBIND11_TYPE_CASTER(Type,\n                         const_name(\"dict[\") + key_conv::name + const_name(\", \") + value_conv::name\n                             + const_name(\"]\"));\n};\n\ntemplate <typename Type, typename Value>\nstruct list_caster {\n    using value_conv = make_caster<Value>;\n\n    bool load(handle src, bool convert) {\n        if (!isinstance<sequence>(src) || isinstance<bytes>(src) || isinstance<str>(src)) {\n            return false;\n        }\n        auto s = reinterpret_borrow<sequence>(src);\n        value.clear();\n        reserve_maybe(s, &value);\n        for (const auto &it : s) {\n            value_conv conv;\n            if (!conv.load(it, convert)) {\n                return false;\n            }\n            value.push_back(cast_op<Value &&>(std::move(conv)));\n        }\n        return true;\n    }\n\nprivate:\n    template <typename T = Type, enable_if_t<has_reserve_method<T>::value, int> = 0>\n    void reserve_maybe(const sequence &s, Type *) {\n        value.reserve(s.size());\n    }\n    void reserve_maybe(const sequence &, void *) {}\n\npublic:\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        if (!std::is_lvalue_reference<T>::value) {\n            policy = return_value_policy_override<Value>::policy(policy);\n        }\n        list l(src.size());\n        ssize_t index = 0;\n        for (auto &&value : src) {\n            auto value_ = reinterpret_steal<object>(\n                value_conv::cast(detail::forward_like<T>(value), policy, parent));\n            if (!value_) {\n                return handle();\n            }\n            PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference\n        }\n        return l.release();\n    }\n\n    PYBIND11_TYPE_CASTER(Type, const_name(\"list[\") + value_conv::name + const_name(\"]\"));\n};\n\ntemplate <typename Type, typename Alloc>\nstruct type_caster<std::vector<Type, Alloc>> : list_caster<std::vector<Type, Alloc>, Type> {};\n\ntemplate <typename Type, typename Alloc>\nstruct type_caster<std::deque<Type, Alloc>> : list_caster<std::deque<Type, Alloc>, Type> {};\n\ntemplate <typename Type, typename Alloc>\nstruct type_caster<std::list<Type, Alloc>> : list_caster<std::list<Type, Alloc>, Type> {};\n\ntemplate <typename ArrayType, typename Value, bool Resizable, size_t Size = 0>\nstruct array_caster {\n    using value_conv = make_caster<Value>;\n\nprivate:\n    template <bool R = Resizable>\n    bool require_size(enable_if_t<R, size_t> size) {\n        if (value.size() != size) {\n            value.resize(size);\n        }\n        return true;\n    }\n    template <bool R = Resizable>\n    bool require_size(enable_if_t<!R, size_t> size) {\n        return size == Size;\n    }\n\npublic:\n    bool load(handle src, bool convert) {\n        if (!isinstance<sequence>(src)) {\n            return false;\n        }\n        auto l = reinterpret_borrow<sequence>(src);\n        if (!require_size(l.size())) {\n            return false;\n        }\n        size_t ctr = 0;\n        for (const auto &it : l) {\n            value_conv conv;\n            if (!conv.load(it, convert)) {\n                return false;\n            }\n            value[ctr++] = cast_op<Value &&>(std::move(conv));\n        }\n        return true;\n    }\n\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        list l(src.size());\n        ssize_t index = 0;\n        for (auto &&value : src) {\n            auto value_ = reinterpret_steal<object>(\n                value_conv::cast(detail::forward_like<T>(value), policy, parent));\n            if (!value_) {\n                return handle();\n            }\n            PyList_SET_ITEM(l.ptr(), index++, value_.release().ptr()); // steals a reference\n        }\n        return l.release();\n    }\n\n    PYBIND11_TYPE_CASTER(ArrayType,\n                         const_name<Resizable>(const_name(\"\"), const_name(\"Annotated[\"))\n                             + const_name(\"list[\") + value_conv::name + const_name(\"]\")\n                             + const_name<Resizable>(const_name(\"\"),\n                                                     const_name(\", FixedSize(\")\n                                                         + const_name<Size>() + const_name(\")]\")));\n};\n\ntemplate <typename Type, size_t Size>\nstruct type_caster<std::array<Type, Size>>\n    : array_caster<std::array<Type, Size>, Type, false, Size> {};\n\ntemplate <typename Type>\nstruct type_caster<std::valarray<Type>> : array_caster<std::valarray<Type>, Type, true> {};\n\ntemplate <typename Key, typename Compare, typename Alloc>\nstruct type_caster<std::set<Key, Compare, Alloc>>\n    : set_caster<std::set<Key, Compare, Alloc>, Key> {};\n\ntemplate <typename Key, typename Hash, typename Equal, typename Alloc>\nstruct type_caster<std::unordered_set<Key, Hash, Equal, Alloc>>\n    : set_caster<std::unordered_set<Key, Hash, Equal, Alloc>, Key> {};\n\ntemplate <typename Key, typename Value, typename Compare, typename Alloc>\nstruct type_caster<std::map<Key, Value, Compare, Alloc>>\n    : map_caster<std::map<Key, Value, Compare, Alloc>, Key, Value> {};\n\ntemplate <typename Key, typename Value, typename Hash, typename Equal, typename Alloc>\nstruct type_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>>\n    : map_caster<std::unordered_map<Key, Value, Hash, Equal, Alloc>, Key, Value> {};\n\n// This type caster is intended to be used for std::optional and std::experimental::optional\ntemplate <typename Type, typename Value = typename Type::value_type>\nstruct optional_caster {\n    using value_conv = make_caster<Value>;\n\n    template <typename T>\n    static handle cast(T &&src, return_value_policy policy, handle parent) {\n        if (!src) {\n            return none().release();\n        }\n        if (!std::is_lvalue_reference<T>::value) {\n            policy = return_value_policy_override<Value>::policy(policy);\n        }\n        // NOLINTNEXTLINE(bugprone-unchecked-optional-access)\n        return value_conv::cast(*std::forward<T>(src), policy, parent);\n    }\n\n    bool load(handle src, bool convert) {\n        if (!src) {\n            return false;\n        }\n        if (src.is_none()) {\n            return true; // default-constructed value is already empty\n        }\n        value_conv inner_caster;\n        if (!inner_caster.load(src, convert)) {\n            return false;\n        }\n\n        value.emplace(cast_op<Value &&>(std::move(inner_caster)));\n        return true;\n    }\n\n    PYBIND11_TYPE_CASTER(Type, const_name(\"Optional[\") + value_conv::name + const_name(\"]\"));\n};\n\n#if defined(PYBIND11_HAS_OPTIONAL)\ntemplate <typename T>\nstruct type_caster<std::optional<T>> : public optional_caster<std::optional<T>> {};\n\ntemplate <>\nstruct type_caster<std::nullopt_t> : public void_caster<std::nullopt_t> {};\n#endif\n\n#if defined(PYBIND11_HAS_EXP_OPTIONAL)\ntemplate <typename T>\nstruct type_caster<std::experimental::optional<T>>\n    : public optional_caster<std::experimental::optional<T>> {};\n\ntemplate <>\nstruct type_caster<std::experimental::nullopt_t>\n    : public void_caster<std::experimental::nullopt_t> {};\n#endif\n\n/// Visit a variant and cast any found type to Python\nstruct variant_caster_visitor {\n    return_value_policy policy;\n    handle parent;\n\n    using result_type = handle; // required by boost::variant in C++11\n\n    template <typename T>\n    result_type operator()(T &&src) const {\n        return make_caster<T>::cast(std::forward<T>(src), policy, parent);\n    }\n};\n\n/// Helper class which abstracts away variant's `visit` function. `std::variant` and similar\n/// `namespace::variant` types which provide a `namespace::visit()` function are handled here\n/// automatically using argument-dependent lookup. Users can provide specializations for other\n/// variant-like classes, e.g. `boost::variant` and `boost::apply_visitor`.\ntemplate <template <typename...> class Variant>\nstruct visit_helper {\n    template <typename... Args>\n    static auto call(Args &&...args) -> decltype(visit(std::forward<Args>(args)...)) {\n        return visit(std::forward<Args>(args)...);\n    }\n};\n\n/// Generic variant caster\ntemplate <typename Variant>\nstruct variant_caster;\n\ntemplate <template <typename...> class V, typename... Ts>\nstruct variant_caster<V<Ts...>> {\n    static_assert(sizeof...(Ts) > 0, \"Variant must consist of at least one alternative.\");\n\n    template <typename U, typename... Us>\n    bool load_alternative(handle src, bool convert, type_list<U, Us...>) {\n        auto caster = make_caster<U>();\n        if (caster.load(src, convert)) {\n            value = cast_op<U>(std::move(caster));\n            return true;\n        }\n        return load_alternative(src, convert, type_list<Us...>{});\n    }\n\n    bool load_alternative(handle, bool, type_list<>) { return false; }\n\n    bool load(handle src, bool convert) {\n        // Do a first pass without conversions to improve constructor resolution.\n        // E.g. `py::int_(1).cast<variant<double, int>>()` needs to fill the `int`\n        // slot of the variant. Without two-pass loading `double` would be filled\n        // because it appears first and a conversion is possible.\n        if (convert && load_alternative(src, false, type_list<Ts...>{})) {\n            return true;\n        }\n        return load_alternative(src, convert, type_list<Ts...>{});\n    }\n\n    template <typename Variant>\n    static handle cast(Variant &&src, return_value_policy policy, handle parent) {\n        return visit_helper<V>::call(variant_caster_visitor{policy, parent},\n                                     std::forward<Variant>(src));\n    }\n\n    using Type = V<Ts...>;\n    PYBIND11_TYPE_CASTER(Type,\n                         const_name(\"Union[\")\n                             + ::pybind11::detail::concat(make_caster<Ts>::name...)\n                             + const_name(\"]\"));\n};\n\n#if defined(PYBIND11_HAS_VARIANT)\ntemplate <typename... Ts>\nstruct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> {};\n\ntemplate <>\nstruct type_caster<std::monostate> : public void_caster<std::monostate> {};\n#endif\n\nPYBIND11_NAMESPACE_END(detail)\n\ninline std::ostream &operator<<(std::ostream &os, const handle &obj) {\n#ifdef PYBIND11_HAS_STRING_VIEW\n    os << str(obj).cast<std::string_view>();\n#else\n    os << (std::string) str(obj);\n#endif\n    return os;\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/stl_bind.h",
    "content": "/*\n    pybind11/std_bind.h: Binding generators for STL data types\n\n    Copyright (c) 2016 Sergey Lyskov and Wenzel Jakob\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"detail/type_caster_base.h\"\n#include \"cast.h\"\n#include \"operators.h\"\n\n#include <algorithm>\n#include <sstream>\n#include <type_traits>\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/* SFINAE helper class used by 'is_comparable */\ntemplate <typename T>\nstruct container_traits {\n    template <typename T2>\n    static std::true_type\n    test_comparable(decltype(std::declval<const T2 &>() == std::declval<const T2 &>()) *);\n    template <typename T2>\n    static std::false_type test_comparable(...);\n    template <typename T2>\n    static std::true_type test_value(typename T2::value_type *);\n    template <typename T2>\n    static std::false_type test_value(...);\n    template <typename T2>\n    static std::true_type test_pair(typename T2::first_type *, typename T2::second_type *);\n    template <typename T2>\n    static std::false_type test_pair(...);\n\n    static constexpr const bool is_comparable\n        = std::is_same<std::true_type, decltype(test_comparable<T>(nullptr))>::value;\n    static constexpr const bool is_pair\n        = std::is_same<std::true_type, decltype(test_pair<T>(nullptr, nullptr))>::value;\n    static constexpr const bool is_vector\n        = std::is_same<std::true_type, decltype(test_value<T>(nullptr))>::value;\n    static constexpr const bool is_element = !is_pair && !is_vector;\n};\n\n/* Default: is_comparable -> std::false_type */\ntemplate <typename T, typename SFINAE = void>\nstruct is_comparable : std::false_type {};\n\n/* For non-map data structures, check whether operator== can be instantiated */\ntemplate <typename T>\nstruct is_comparable<\n    T,\n    enable_if_t<container_traits<T>::is_element && container_traits<T>::is_comparable>>\n    : std::true_type {};\n\n/* For a vector/map data structure, recursively check the value type\n   (which is std::pair for maps) */\ntemplate <typename T>\nstruct is_comparable<T, enable_if_t<container_traits<T>::is_vector>>\n    : is_comparable<typename recursive_container_traits<T>::type_to_check_recursively> {};\n\ntemplate <>\nstruct is_comparable<recursive_bottom> : std::true_type {};\n\n/* For pairs, recursively check the two data types */\ntemplate <typename T>\nstruct is_comparable<T, enable_if_t<container_traits<T>::is_pair>> {\n    static constexpr const bool value = is_comparable<typename T::first_type>::value\n                                        && is_comparable<typename T::second_type>::value;\n};\n\n/* Fallback functions */\ntemplate <typename, typename, typename... Args>\nvoid vector_if_copy_constructible(const Args &...) {}\ntemplate <typename, typename, typename... Args>\nvoid vector_if_equal_operator(const Args &...) {}\ntemplate <typename, typename, typename... Args>\nvoid vector_if_insertion_operator(const Args &...) {}\ntemplate <typename, typename, typename... Args>\nvoid vector_modifiers(const Args &...) {}\n\ntemplate <typename Vector, typename Class_>\nvoid vector_if_copy_constructible(enable_if_t<is_copy_constructible<Vector>::value, Class_> &cl) {\n    cl.def(init<const Vector &>(), \"Copy constructor\");\n}\n\ntemplate <typename Vector, typename Class_>\nvoid vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_> &cl) {\n    using T = typename Vector::value_type;\n\n    cl.def(self == self);\n    cl.def(self != self);\n\n    cl.def(\n        \"count\",\n        [](const Vector &v, const T &x) { return std::count(v.begin(), v.end(), x); },\n        arg(\"x\"),\n        \"Return the number of times ``x`` appears in the list\");\n\n    cl.def(\n        \"remove\",\n        [](Vector &v, const T &x) {\n            auto p = std::find(v.begin(), v.end(), x);\n            if (p != v.end()) {\n                v.erase(p);\n            } else {\n                throw value_error();\n            }\n        },\n        arg(\"x\"),\n        \"Remove the first item from the list whose value is x. \"\n        \"It is an error if there is no such item.\");\n\n    cl.def(\n        \"__contains__\",\n        [](const Vector &v, const T &x) { return std::find(v.begin(), v.end(), x) != v.end(); },\n        arg(\"x\"),\n        \"Return true the container contains ``x``\");\n}\n\n// Vector modifiers -- requires a copyable vector_type:\n// (Technically, some of these (pop and __delitem__) don't actually require copyability, but it\n// seems silly to allow deletion but not insertion, so include them here too.)\ntemplate <typename Vector, typename Class_>\nvoid vector_modifiers(\n    enable_if_t<is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {\n    using T = typename Vector::value_type;\n    using SizeType = typename Vector::size_type;\n    using DiffType = typename Vector::difference_type;\n\n    auto wrap_i = [](DiffType i, SizeType n) {\n        if (i < 0) {\n            i += n;\n        }\n        if (i < 0 || (SizeType) i >= n) {\n            throw index_error();\n        }\n        return i;\n    };\n\n    cl.def(\n        \"append\",\n        [](Vector &v, const T &value) { v.push_back(value); },\n        arg(\"x\"),\n        \"Add an item to the end of the list\");\n\n    cl.def(init([](const iterable &it) {\n        auto v = std::unique_ptr<Vector>(new Vector());\n        v->reserve(len_hint(it));\n        for (handle h : it) {\n            v->push_back(h.cast<T>());\n        }\n        return v.release();\n    }));\n\n    cl.def(\n        \"clear\", [](Vector &v) { v.clear(); }, \"Clear the contents\");\n\n    cl.def(\n        \"extend\",\n        [](Vector &v, const Vector &src) { v.insert(v.end(), src.begin(), src.end()); },\n        arg(\"L\"),\n        \"Extend the list by appending all the items in the given list\");\n\n    cl.def(\n        \"extend\",\n        [](Vector &v, const iterable &it) {\n            const size_t old_size = v.size();\n            v.reserve(old_size + len_hint(it));\n            try {\n                for (handle h : it) {\n                    v.push_back(h.cast<T>());\n                }\n            } catch (const cast_error &) {\n                v.erase(v.begin() + static_cast<typename Vector::difference_type>(old_size),\n                        v.end());\n                try {\n                    v.shrink_to_fit();\n                } catch (const std::exception &) {\n                    // Do nothing\n                }\n                throw;\n            }\n        },\n        arg(\"L\"),\n        \"Extend the list by appending all the items in the given list\");\n\n    cl.def(\n        \"insert\",\n        [](Vector &v, DiffType i, const T &x) {\n            // Can't use wrap_i; i == v.size() is OK\n            if (i < 0) {\n                i += v.size();\n            }\n            if (i < 0 || (SizeType) i > v.size()) {\n                throw index_error();\n            }\n            v.insert(v.begin() + i, x);\n        },\n        arg(\"i\"),\n        arg(\"x\"),\n        \"Insert an item at a given position.\");\n\n    cl.def(\n        \"pop\",\n        [](Vector &v) {\n            if (v.empty()) {\n                throw index_error();\n            }\n            T t = std::move(v.back());\n            v.pop_back();\n            return t;\n        },\n        \"Remove and return the last item\");\n\n    cl.def(\n        \"pop\",\n        [wrap_i](Vector &v, DiffType i) {\n            i = wrap_i(i, v.size());\n            T t = std::move(v[(SizeType) i]);\n            v.erase(std::next(v.begin(), i));\n            return t;\n        },\n        arg(\"i\"),\n        \"Remove and return the item at index ``i``\");\n\n    cl.def(\"__setitem__\", [wrap_i](Vector &v, DiffType i, const T &t) {\n        i = wrap_i(i, v.size());\n        v[(SizeType) i] = t;\n    });\n\n    /// Slicing protocol\n    cl.def(\n        \"__getitem__\",\n        [](const Vector &v, const slice &slice) -> Vector * {\n            size_t start = 0, stop = 0, step = 0, slicelength = 0;\n\n            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {\n                throw error_already_set();\n            }\n\n            auto *seq = new Vector();\n            seq->reserve((size_t) slicelength);\n\n            for (size_t i = 0; i < slicelength; ++i) {\n                seq->push_back(v[start]);\n                start += step;\n            }\n            return seq;\n        },\n        arg(\"s\"),\n        \"Retrieve list elements using a slice object\");\n\n    cl.def(\n        \"__setitem__\",\n        [](Vector &v, const slice &slice, const Vector &value) {\n            size_t start = 0, stop = 0, step = 0, slicelength = 0;\n            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {\n                throw error_already_set();\n            }\n\n            if (slicelength != value.size()) {\n                throw std::runtime_error(\n                    \"Left and right hand size of slice assignment have different sizes!\");\n            }\n\n            for (size_t i = 0; i < slicelength; ++i) {\n                v[start] = value[i];\n                start += step;\n            }\n        },\n        \"Assign list elements using a slice object\");\n\n    cl.def(\n        \"__delitem__\",\n        [wrap_i](Vector &v, DiffType i) {\n            i = wrap_i(i, v.size());\n            v.erase(v.begin() + i);\n        },\n        \"Delete the list elements at index ``i``\");\n\n    cl.def(\n        \"__delitem__\",\n        [](Vector &v, const slice &slice) {\n            size_t start = 0, stop = 0, step = 0, slicelength = 0;\n\n            if (!slice.compute(v.size(), &start, &stop, &step, &slicelength)) {\n                throw error_already_set();\n            }\n\n            if (step == 1 && false) {\n                v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));\n            } else {\n                for (size_t i = 0; i < slicelength; ++i) {\n                    v.erase(v.begin() + DiffType(start));\n                    start += step - 1;\n                }\n            }\n        },\n        \"Delete list elements using a slice object\");\n}\n\n// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),\n// we have to access by copying; otherwise we return by reference.\ntemplate <typename Vector>\nusing vector_needs_copy\n    = negation<std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]),\n                            typename Vector::value_type &>>;\n\n// The usual case: access and iterate by reference\ntemplate <typename Vector, typename Class_>\nvoid vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl) {\n    using T = typename Vector::value_type;\n    using SizeType = typename Vector::size_type;\n    using DiffType = typename Vector::difference_type;\n    using ItType = typename Vector::iterator;\n\n    auto wrap_i = [](DiffType i, SizeType n) {\n        if (i < 0) {\n            i += n;\n        }\n        if (i < 0 || (SizeType) i >= n) {\n            throw index_error();\n        }\n        return i;\n    };\n\n    cl.def(\n        \"__getitem__\",\n        [wrap_i](Vector &v, DiffType i) -> T & {\n            i = wrap_i(i, v.size());\n            return v[(SizeType) i];\n        },\n        return_value_policy::reference_internal // ref + keepalive\n    );\n\n    cl.def(\n        \"__iter__\",\n        [](Vector &v) {\n            return make_iterator<return_value_policy::reference_internal, ItType, ItType, T &>(\n                v.begin(), v.end());\n        },\n        keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */\n    );\n}\n\n// The case for special objects, like std::vector<bool>, that have to be returned-by-copy:\ntemplate <typename Vector, typename Class_>\nvoid vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl) {\n    using T = typename Vector::value_type;\n    using SizeType = typename Vector::size_type;\n    using DiffType = typename Vector::difference_type;\n    using ItType = typename Vector::iterator;\n    cl.def(\"__getitem__\", [](const Vector &v, DiffType i) -> T {\n        if (i < 0) {\n            i += v.size();\n            if (i < 0) {\n                throw index_error();\n            }\n        }\n        auto i_st = static_cast<SizeType>(i);\n        if (i_st >= v.size()) {\n            throw index_error();\n        }\n        return v[i_st];\n    });\n\n    cl.def(\n        \"__iter__\",\n        [](Vector &v) {\n            return make_iterator<return_value_policy::copy, ItType, ItType, T>(v.begin(), v.end());\n        },\n        keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */\n    );\n}\n\ntemplate <typename Vector, typename Class_>\nauto vector_if_insertion_operator(Class_ &cl, std::string const &name)\n    -> decltype(std::declval<std::ostream &>() << std::declval<typename Vector::value_type>(),\n                void()) {\n    using size_type = typename Vector::size_type;\n\n    cl.def(\n        \"__repr__\",\n        [name](Vector &v) {\n            std::ostringstream s;\n            s << name << '[';\n            for (size_type i = 0; i < v.size(); ++i) {\n                s << v[i];\n                if (i != v.size() - 1) {\n                    s << \", \";\n                }\n            }\n            s << ']';\n            return s.str();\n        },\n        \"Return the canonical string representation of this list.\");\n}\n\n// Provide the buffer interface for vectors if we have data() and we have a format for it\n// GCC seems to have \"void std::vector<bool>::data()\" - doing SFINAE on the existence of data()\n// is insufficient, we need to check it returns an appropriate pointer\ntemplate <typename Vector, typename = void>\nstruct vector_has_data_and_format : std::false_type {};\ntemplate <typename Vector>\nstruct vector_has_data_and_format<\n    Vector,\n    enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(),\n                                      std::declval<Vector>().data()),\n                             typename Vector::value_type *>::value>> : std::true_type {};\n\n// [workaround(intel)] Separate function required here\n// Workaround as the Intel compiler does not compile the enable_if_t part below\n// (tested with icc (ICC) 2021.1 Beta 20200827)\ntemplate <typename... Args>\nconstexpr bool args_any_are_buffer() {\n    return detail::any_of<std::is_same<Args, buffer_protocol>...>::value;\n}\n\n// [workaround(intel)] Separate function required here\n// [workaround(msvc)] Can't use constexpr bool in return type\n\n// Add the buffer interface to a vector\ntemplate <typename Vector, typename Class_, typename... Args>\nvoid vector_buffer_impl(Class_ &cl, std::true_type) {\n    using T = typename Vector::value_type;\n\n    static_assert(vector_has_data_and_format<Vector>::value,\n                  \"There is not an appropriate format descriptor for this vector\");\n\n    // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard\n    // at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here\n    format_descriptor<T>::format();\n\n    cl.def_buffer([](Vector &v) -> buffer_info {\n        return buffer_info(v.data(),\n                           static_cast<ssize_t>(sizeof(T)),\n                           format_descriptor<T>::format(),\n                           1,\n                           {v.size()},\n                           {sizeof(T)});\n    });\n\n    cl.def(init([](const buffer &buf) {\n        auto info = buf.request();\n        if (info.ndim != 1 || info.strides[0] % static_cast<ssize_t>(sizeof(T))) {\n            throw type_error(\"Only valid 1D buffers can be copied to a vector\");\n        }\n        if (!detail::compare_buffer_info<T>::compare(info)\n            || (ssize_t) sizeof(T) != info.itemsize) {\n            throw type_error(\"Format mismatch (Python: \" + info.format\n                             + \" C++: \" + format_descriptor<T>::format() + \")\");\n        }\n\n        T *p = static_cast<T *>(info.ptr);\n        ssize_t step = info.strides[0] / static_cast<ssize_t>(sizeof(T));\n        T *end = p + info.shape[0] * step;\n        if (step == 1) {\n            return Vector(p, end);\n        }\n        Vector vec;\n        vec.reserve((size_t) info.shape[0]);\n        for (; p != end; p += step) {\n            vec.push_back(*p);\n        }\n        return vec;\n    }));\n\n    return;\n}\n\ntemplate <typename Vector, typename Class_, typename... Args>\nvoid vector_buffer_impl(Class_ &, std::false_type) {}\n\ntemplate <typename Vector, typename Class_, typename... Args>\nvoid vector_buffer(Class_ &cl) {\n    vector_buffer_impl<Vector, Class_, Args...>(\n        cl, detail::any_of<std::is_same<Args, buffer_protocol>...>{});\n}\n\nPYBIND11_NAMESPACE_END(detail)\n\n//\n// std::vector\n//\ntemplate <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>\nclass_<Vector, holder_type> bind_vector(handle scope, std::string const &name, Args &&...args) {\n    using Class_ = class_<Vector, holder_type>;\n\n    // If the value_type is unregistered (e.g. a converting type) or is itself registered\n    // module-local then make the vector binding module-local as well:\n    using vtype = typename Vector::value_type;\n    auto *vtype_info = detail::get_type_info(typeid(vtype));\n    bool local = !vtype_info || vtype_info->module_local;\n\n    Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);\n\n    // Declare the buffer interface if a buffer_protocol() is passed in\n    detail::vector_buffer<Vector, Class_, Args...>(cl);\n\n    cl.def(init<>());\n\n    // Register copy constructor (if possible)\n    detail::vector_if_copy_constructible<Vector, Class_>(cl);\n\n    // Register comparison-related operators and functions (if possible)\n    detail::vector_if_equal_operator<Vector, Class_>(cl);\n\n    // Register stream insertion operator (if possible)\n    detail::vector_if_insertion_operator<Vector, Class_>(cl, name);\n\n    // Modifiers require copyable vector value type\n    detail::vector_modifiers<Vector, Class_>(cl);\n\n    // Accessor and iterator; return by value if copyable, otherwise we return by ref + keep-alive\n    detail::vector_accessor<Vector, Class_>(cl);\n\n    cl.def(\n        \"__bool__\",\n        [](const Vector &v) -> bool { return !v.empty(); },\n        \"Check whether the list is nonempty\");\n\n    cl.def(\"__len__\", [](const Vector &vec) { return vec.size(); });\n\n#if 0\n    // C++ style functions deprecated, leaving it here as an example\n    cl.def(init<size_type>());\n\n    cl.def(\"resize\",\n         (void (Vector::*) (size_type count)) & Vector::resize,\n         \"changes the number of elements stored\");\n\n    cl.def(\"erase\",\n        [](Vector &v, SizeType i) {\n        if (i >= v.size())\n            throw index_error();\n        v.erase(v.begin() + i);\n    }, \"erases element at index ``i``\");\n\n    cl.def(\"empty\",         &Vector::empty,         \"checks whether the container is empty\");\n    cl.def(\"size\",          &Vector::size,          \"returns the number of elements\");\n    cl.def(\"push_back\", (void (Vector::*)(const T&)) &Vector::push_back, \"adds an element to the end\");\n    cl.def(\"pop_back\",                               &Vector::pop_back, \"removes the last element\");\n\n    cl.def(\"max_size\",      &Vector::max_size,      \"returns the maximum possible number of elements\");\n    cl.def(\"reserve\",       &Vector::reserve,       \"reserves storage\");\n    cl.def(\"capacity\",      &Vector::capacity,      \"returns the number of elements that can be held in currently allocated storage\");\n    cl.def(\"shrink_to_fit\", &Vector::shrink_to_fit, \"reduces memory usage by freeing unused memory\");\n\n    cl.def(\"clear\", &Vector::clear, \"clears the contents\");\n    cl.def(\"swap\",   &Vector::swap, \"swaps the contents\");\n\n    cl.def(\"front\", [](Vector &v) {\n        if (v.size()) return v.front();\n        else throw index_error();\n    }, \"access the first element\");\n\n    cl.def(\"back\", [](Vector &v) {\n        if (v.size()) return v.back();\n        else throw index_error();\n    }, \"access the last element \");\n\n#endif\n\n    return cl;\n}\n\n//\n// std::map, std::unordered_map\n//\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\n/* Fallback functions */\ntemplate <typename, typename, typename... Args>\nvoid map_if_insertion_operator(const Args &...) {}\ntemplate <typename, typename, typename... Args>\nvoid map_assignment(const Args &...) {}\n\n// Map assignment when copy-assignable: just copy the value\ntemplate <typename Map, typename Class_>\nvoid map_assignment(\n    enable_if_t<is_copy_assignable<typename Map::mapped_type>::value, Class_> &cl) {\n    using KeyType = typename Map::key_type;\n    using MappedType = typename Map::mapped_type;\n\n    cl.def(\"__setitem__\", [](Map &m, const KeyType &k, const MappedType &v) {\n        auto it = m.find(k);\n        if (it != m.end()) {\n            it->second = v;\n        } else {\n            m.emplace(k, v);\n        }\n    });\n}\n\n// Not copy-assignable, but still copy-constructible: we can update the value by erasing and\n// reinserting\ntemplate <typename Map, typename Class_>\nvoid map_assignment(enable_if_t<!is_copy_assignable<typename Map::mapped_type>::value\n                                    && is_copy_constructible<typename Map::mapped_type>::value,\n                                Class_> &cl) {\n    using KeyType = typename Map::key_type;\n    using MappedType = typename Map::mapped_type;\n\n    cl.def(\"__setitem__\", [](Map &m, const KeyType &k, const MappedType &v) {\n        // We can't use m[k] = v; because value type might not be default constructable\n        auto r = m.emplace(k, v);\n        if (!r.second) {\n            // value type is not copy assignable so the only way to insert it is to erase it\n            // first...\n            m.erase(r.first);\n            m.emplace(k, v);\n        }\n    });\n}\n\ntemplate <typename Map, typename Class_>\nauto map_if_insertion_operator(Class_ &cl, std::string const &name)\n    -> decltype(std::declval<std::ostream &>() << std::declval<typename Map::key_type>()\n                                               << std::declval<typename Map::mapped_type>(),\n                void()) {\n\n    cl.def(\n        \"__repr__\",\n        [name](Map &m) {\n            std::ostringstream s;\n            s << name << '{';\n            bool f = false;\n            for (auto const &kv : m) {\n                if (f) {\n                    s << \", \";\n                }\n                s << kv.first << \": \" << kv.second;\n                f = true;\n            }\n            s << '}';\n            return s.str();\n        },\n        \"Return the canonical string representation of this map.\");\n}\n\nstruct keys_view {\n    virtual size_t len() = 0;\n    virtual iterator iter() = 0;\n    virtual bool contains(const handle &k) = 0;\n    virtual ~keys_view() = default;\n};\n\nstruct values_view {\n    virtual size_t len() = 0;\n    virtual iterator iter() = 0;\n    virtual ~values_view() = default;\n};\n\nstruct items_view {\n    virtual size_t len() = 0;\n    virtual iterator iter() = 0;\n    virtual ~items_view() = default;\n};\n\ntemplate <typename Map>\nstruct KeysViewImpl : public detail::keys_view {\n    explicit KeysViewImpl(Map &map) : map(map) {}\n    size_t len() override { return map.size(); }\n    iterator iter() override { return make_key_iterator(map.begin(), map.end()); }\n    bool contains(const handle &k) override {\n        try {\n            return map.find(k.template cast<typename Map::key_type>()) != map.end();\n        } catch (const cast_error &) {\n            return false;\n        }\n    }\n    Map &map;\n};\n\ntemplate <typename Map>\nstruct ValuesViewImpl : public detail::values_view {\n    explicit ValuesViewImpl(Map &map) : map(map) {}\n    size_t len() override { return map.size(); }\n    iterator iter() override { return make_value_iterator(map.begin(), map.end()); }\n    Map &map;\n};\n\ntemplate <typename Map>\nstruct ItemsViewImpl : public detail::items_view {\n    explicit ItemsViewImpl(Map &map) : map(map) {}\n    size_t len() override { return map.size(); }\n    iterator iter() override { return make_iterator(map.begin(), map.end()); }\n    Map &map;\n};\n\nPYBIND11_NAMESPACE_END(detail)\n\ntemplate <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>\nclass_<Map, holder_type> bind_map(handle scope, const std::string &name, Args &&...args) {\n    using KeyType = typename Map::key_type;\n    using MappedType = typename Map::mapped_type;\n    using KeysView = detail::keys_view;\n    using ValuesView = detail::values_view;\n    using ItemsView = detail::items_view;\n    using Class_ = class_<Map, holder_type>;\n\n    // If either type is a non-module-local bound type then make the map binding non-local as well;\n    // otherwise (e.g. both types are either module-local or converting) the map will be\n    // module-local.\n    auto *tinfo = detail::get_type_info(typeid(MappedType));\n    bool local = !tinfo || tinfo->module_local;\n    if (local) {\n        tinfo = detail::get_type_info(typeid(KeyType));\n        local = !tinfo || tinfo->module_local;\n    }\n\n    Class_ cl(scope, name.c_str(), pybind11::module_local(local), std::forward<Args>(args)...);\n\n    // Wrap KeysView if it wasn't already wrapped\n    if (!detail::get_type_info(typeid(KeysView))) {\n        class_<KeysView> keys_view(scope, \"KeysView\", pybind11::module_local(local));\n        keys_view.def(\"__len__\", &KeysView::len);\n        keys_view.def(\"__iter__\",\n                      &KeysView::iter,\n                      keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */\n        );\n        keys_view.def(\"__contains__\", &KeysView::contains);\n    }\n    // Similarly for ValuesView:\n    if (!detail::get_type_info(typeid(ValuesView))) {\n        class_<ValuesView> values_view(scope, \"ValuesView\", pybind11::module_local(local));\n        values_view.def(\"__len__\", &ValuesView::len);\n        values_view.def(\"__iter__\",\n                        &ValuesView::iter,\n                        keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */\n        );\n    }\n    // Similarly for ItemsView:\n    if (!detail::get_type_info(typeid(ItemsView))) {\n        class_<ItemsView> items_view(scope, \"ItemsView\", pybind11::module_local(local));\n        items_view.def(\"__len__\", &ItemsView::len);\n        items_view.def(\"__iter__\",\n                       &ItemsView::iter,\n                       keep_alive<0, 1>() /* Essential: keep view alive while iterator exists */\n        );\n    }\n\n    cl.def(init<>());\n\n    // Register stream insertion operator (if possible)\n    detail::map_if_insertion_operator<Map, Class_>(cl, name);\n\n    cl.def(\n        \"__bool__\",\n        [](const Map &m) -> bool { return !m.empty(); },\n        \"Check whether the map is nonempty\");\n\n    cl.def(\n        \"__iter__\",\n        [](Map &m) { return make_key_iterator(m.begin(), m.end()); },\n        keep_alive<0, 1>() /* Essential: keep map alive while iterator exists */\n    );\n\n    cl.def(\n        \"keys\",\n        [](Map &m) { return std::unique_ptr<KeysView>(new detail::KeysViewImpl<Map>(m)); },\n        keep_alive<0, 1>() /* Essential: keep map alive while view exists */\n    );\n\n    cl.def(\n        \"values\",\n        [](Map &m) { return std::unique_ptr<ValuesView>(new detail::ValuesViewImpl<Map>(m)); },\n        keep_alive<0, 1>() /* Essential: keep map alive while view exists */\n    );\n\n    cl.def(\n        \"items\",\n        [](Map &m) { return std::unique_ptr<ItemsView>(new detail::ItemsViewImpl<Map>(m)); },\n        keep_alive<0, 1>() /* Essential: keep map alive while view exists */\n    );\n\n    cl.def(\n        \"__getitem__\",\n        [](Map &m, const KeyType &k) -> MappedType & {\n            auto it = m.find(k);\n            if (it == m.end()) {\n                throw key_error();\n            }\n            return it->second;\n        },\n        return_value_policy::reference_internal // ref + keepalive\n    );\n\n    cl.def(\"__contains__\", [](Map &m, const KeyType &k) -> bool {\n        auto it = m.find(k);\n        if (it == m.end()) {\n            return false;\n        }\n        return true;\n    });\n    // Fallback for when the object is not of the key type\n    cl.def(\"__contains__\", [](Map &, const object &) -> bool { return false; });\n\n    // Assignment provided only if the type is copyable\n    detail::map_assignment<Map, Class_>(cl);\n\n    cl.def(\"__delitem__\", [](Map &m, const KeyType &k) {\n        auto it = m.find(k);\n        if (it == m.end()) {\n            throw key_error();\n        }\n        m.erase(it);\n    });\n\n    // Always use a lambda in case of `using` declaration\n    cl.def(\"__len__\", [](const Map &m) { return m.size(); });\n\n    return cl;\n}\n\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/type_caster_pyobject_ptr.h",
    "content": "// Copyright (c) 2023 The pybind Community.\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"detail/descr.h\"\n#include \"cast.h\"\n#include \"pytypes.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <>\nclass type_caster<PyObject> {\npublic:\n    static constexpr auto name = const_name(\"object\"); // See discussion under PR #4601.\n\n    // This overload is purely to guard against accidents.\n    template <typename T,\n              detail::enable_if_t<!is_same_ignoring_cvref<T, PyObject *>::value, int> = 0>\n    static handle cast(T &&, return_value_policy, handle /*parent*/) {\n        static_assert(is_same_ignoring_cvref<T, PyObject *>::value,\n                      \"Invalid C++ type T for to-Python conversion (type_caster<PyObject>).\");\n        return nullptr; // Unreachable.\n    }\n\n    static handle cast(PyObject *src, return_value_policy policy, handle /*parent*/) {\n        if (src == nullptr) {\n            throw error_already_set();\n        }\n        if (PyErr_Occurred()) {\n            raise_from(PyExc_SystemError, \"src != nullptr but PyErr_Occurred()\");\n            throw error_already_set();\n        }\n        if (policy == return_value_policy::take_ownership) {\n            return src;\n        }\n        if (policy == return_value_policy::reference\n            || policy == return_value_policy::automatic_reference) {\n            return handle(src).inc_ref();\n        }\n        pybind11_fail(\"type_caster<PyObject>::cast(): unsupported return_value_policy: \"\n                      + std::to_string(static_cast<int>(policy)));\n    }\n\n    bool load(handle src, bool) {\n        value = reinterpret_borrow<object>(src);\n        return true;\n    }\n\n    template <typename T>\n    using cast_op_type = PyObject *;\n\n    explicit operator PyObject *() { return value.ptr(); }\n\nprivate:\n    object value;\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/include/pybind11/typing.h",
    "content": "/*\n    pybind11/typing.h: Convenience wrapper classes for basic Python types\n    with more explicit annotations.\n\n    Copyright (c) 2023 Dustin Spicuzza <dustin@virtualroadside.com>\n\n    All rights reserved. Use of this source code is governed by a\n    BSD-style license that can be found in the LICENSE file.\n*/\n\n#pragma once\n\n#include \"detail/common.h\"\n#include \"cast.h\"\n#include \"pytypes.h\"\n\nPYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)\nPYBIND11_NAMESPACE_BEGIN(typing)\n\n/*\n    The following types can be used to direct pybind11-generated docstrings\n    to have have more explicit types (e.g., `list[str]` instead of `list`).\n    Just use these in place of existing types.\n\n    There is no additional enforcement of types at runtime.\n*/\n\ntemplate <typename... Types>\nclass Tuple : public tuple {\n    using tuple::tuple;\n};\n\ntemplate <typename K, typename V>\nclass Dict : public dict {\n    using dict::dict;\n};\n\ntemplate <typename T>\nclass List : public list {\n    using list::list;\n};\n\ntemplate <typename T>\nclass Set : public set {\n    using set::set;\n};\n\ntemplate <typename T>\nclass Iterable : public iterable {\n    using iterable::iterable;\n};\n\ntemplate <typename T>\nclass Iterator : public iterator {\n    using iterator::iterator;\n};\n\ntemplate <typename Signature>\nclass Callable;\n\ntemplate <typename Return, typename... Args>\nclass Callable<Return(Args...)> : public function {\n    using function::function;\n};\n\nPYBIND11_NAMESPACE_END(typing)\n\nPYBIND11_NAMESPACE_BEGIN(detail)\n\ntemplate <typename... Types>\nstruct handle_type_name<typing::Tuple<Types...>> {\n    static constexpr auto name = const_name(\"tuple[\")\n                                 + ::pybind11::detail::concat(make_caster<Types>::name...)\n                                 + const_name(\"]\");\n};\n\ntemplate <>\nstruct handle_type_name<typing::Tuple<>> {\n    // PEP 484 specifies this syntax for an empty tuple\n    static constexpr auto name = const_name(\"tuple[()]\");\n};\n\ntemplate <typename T>\nstruct handle_type_name<typing::Tuple<T, ellipsis>> {\n    // PEP 484 specifies this syntax for a variable-length tuple\n    static constexpr auto name\n        = const_name(\"tuple[\") + make_caster<T>::name + const_name(\", ...]\");\n};\n\ntemplate <typename K, typename V>\nstruct handle_type_name<typing::Dict<K, V>> {\n    static constexpr auto name = const_name(\"dict[\") + make_caster<K>::name + const_name(\", \")\n                                 + make_caster<V>::name + const_name(\"]\");\n};\n\ntemplate <typename T>\nstruct handle_type_name<typing::List<T>> {\n    static constexpr auto name = const_name(\"list[\") + make_caster<T>::name + const_name(\"]\");\n};\n\ntemplate <typename T>\nstruct handle_type_name<typing::Set<T>> {\n    static constexpr auto name = const_name(\"set[\") + make_caster<T>::name + const_name(\"]\");\n};\n\ntemplate <typename T>\nstruct handle_type_name<typing::Iterable<T>> {\n    static constexpr auto name = const_name(\"Iterable[\") + make_caster<T>::name + const_name(\"]\");\n};\n\ntemplate <typename T>\nstruct handle_type_name<typing::Iterator<T>> {\n    static constexpr auto name = const_name(\"Iterator[\") + make_caster<T>::name + const_name(\"]\");\n};\n\ntemplate <typename Return, typename... Args>\nstruct handle_type_name<typing::Callable<Return(Args...)>> {\n    using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;\n    static constexpr auto name\n        = const_name(\"Callable[[\") + ::pybind11::detail::concat(make_caster<Args>::name...)\n          + const_name(\"], \") + make_caster<retval_type>::name + const_name(\"]\");\n};\n\nPYBIND11_NAMESPACE_END(detail)\nPYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)\n"
  },
  {
    "path": "dlib/external/pybind11/tools/FindCatch.cmake",
    "content": "# - Find the Catch test framework or download it (single header)\n#\n# This is a quick module for internal use. It assumes that Catch is\n# REQUIRED and that a minimum version is provided (not EXACT). If\n# a suitable version isn't found locally, the single header file\n# will be downloaded and placed in the build dir: PROJECT_BINARY_DIR.\n#\n# This code sets the following variables:\n#  CATCH_INCLUDE_DIR      - path to catch.hpp\n#  CATCH_VERSION          - version number\n\noption(DOWNLOAD_CATCH \"Download catch2 if not found\")\n\nif(NOT Catch_FIND_VERSION)\n  message(FATAL_ERROR \"A version number must be specified.\")\nelseif(Catch_FIND_REQUIRED)\n  message(FATAL_ERROR \"This module assumes Catch is not required.\")\nelseif(Catch_FIND_VERSION_EXACT)\n  message(FATAL_ERROR \"Exact version numbers are not supported, only minimum.\")\nendif()\n\n# Extract the version number from catch.hpp\nfunction(_get_catch_version)\n  file(\n    STRINGS \"${CATCH_INCLUDE_DIR}/catch.hpp\" version_line\n    REGEX \"Catch v.*\"\n    LIMIT_COUNT 1)\n  if(version_line MATCHES \"Catch v([0-9]+)\\\\.([0-9]+)\\\\.([0-9]+)\")\n    set(CATCH_VERSION\n        \"${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}\"\n        PARENT_SCOPE)\n  endif()\nendfunction()\n\n# Download the single-header version of Catch\nfunction(_download_catch version destination_dir)\n  message(STATUS \"Downloading catch v${version}...\")\n  set(url https://github.com/philsquared/Catch/releases/download/v${version}/catch.hpp)\n  file(\n    DOWNLOAD ${url} \"${destination_dir}/catch.hpp\"\n    STATUS status\n    LOG log)\n  list(GET status 0 error)\n  if(error)\n    string(REPLACE \"\\n\" \"\\n  \" log \"  ${log}\")\n    message(FATAL_ERROR \"Could not download URL:\\n\" \"  ${url}\\n\" \"Log:\\n\" \"${log}\")\n  endif()\n  set(CATCH_INCLUDE_DIR\n      \"${destination_dir}\"\n      CACHE INTERNAL \"\")\nendfunction()\n\n# Look for catch locally\nfind_path(\n  CATCH_INCLUDE_DIR\n  NAMES catch.hpp\n  PATH_SUFFIXES catch2)\nif(CATCH_INCLUDE_DIR)\n  _get_catch_version()\nendif()\n\n# Download the header if it wasn't found or if it's outdated\nif(NOT CATCH_VERSION OR CATCH_VERSION VERSION_LESS ${Catch_FIND_VERSION})\n  if(DOWNLOAD_CATCH)\n    _download_catch(${Catch_FIND_VERSION} \"${PROJECT_BINARY_DIR}/catch/\")\n    _get_catch_version()\n  else()\n    set(CATCH_FOUND FALSE)\n    return()\n  endif()\nendif()\n\nadd_library(Catch2::Catch2 IMPORTED INTERFACE)\nset_property(TARGET Catch2::Catch2 PROPERTY INTERFACE_INCLUDE_DIRECTORIES \"${CATCH_INCLUDE_DIR}\")\n\nset(CATCH_FOUND TRUE)\n"
  },
  {
    "path": "dlib/external/pybind11/tools/FindEigen3.cmake",
    "content": "# - Try to find Eigen3 lib\n#\n# This module supports requiring a minimum version, e.g. you can do\n#   find_package(Eigen3 3.1.2)\n# to require version 3.1.2 or newer of Eigen3.\n#\n# Once done this will define\n#\n#  EIGEN3_FOUND - system has eigen lib with correct version\n#  EIGEN3_INCLUDE_DIR - the eigen include directory\n#  EIGEN3_VERSION - eigen version\n\n# Copyright (c) 2006, 2007 Montel Laurent, <montel@kde.org>\n# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael@free.fr>\n# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>\n# Redistribution and use is allowed according to the terms of the 2-clause BSD license.\n\nif(NOT Eigen3_FIND_VERSION)\n  if(NOT Eigen3_FIND_VERSION_MAJOR)\n    set(Eigen3_FIND_VERSION_MAJOR 2)\n  endif(NOT Eigen3_FIND_VERSION_MAJOR)\n  if(NOT Eigen3_FIND_VERSION_MINOR)\n    set(Eigen3_FIND_VERSION_MINOR 91)\n  endif(NOT Eigen3_FIND_VERSION_MINOR)\n  if(NOT Eigen3_FIND_VERSION_PATCH)\n    set(Eigen3_FIND_VERSION_PATCH 0)\n  endif(NOT Eigen3_FIND_VERSION_PATCH)\n\n  set(Eigen3_FIND_VERSION\n      \"${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}\")\nendif(NOT Eigen3_FIND_VERSION)\n\nmacro(_eigen3_check_version)\n  file(READ \"${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h\" _eigen3_version_header)\n\n  string(REGEX MATCH \"define[ \\t]+EIGEN_WORLD_VERSION[ \\t]+([0-9]+)\" _eigen3_world_version_match\n               \"${_eigen3_version_header}\")\n  set(EIGEN3_WORLD_VERSION \"${CMAKE_MATCH_1}\")\n  string(REGEX MATCH \"define[ \\t]+EIGEN_MAJOR_VERSION[ \\t]+([0-9]+)\" _eigen3_major_version_match\n               \"${_eigen3_version_header}\")\n  set(EIGEN3_MAJOR_VERSION \"${CMAKE_MATCH_1}\")\n  string(REGEX MATCH \"define[ \\t]+EIGEN_MINOR_VERSION[ \\t]+([0-9]+)\" _eigen3_minor_version_match\n               \"${_eigen3_version_header}\")\n  set(EIGEN3_MINOR_VERSION \"${CMAKE_MATCH_1}\")\n\n  set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})\n  if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})\n    set(EIGEN3_VERSION_OK FALSE)\n  else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})\n    set(EIGEN3_VERSION_OK TRUE)\n  endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})\n\n  if(NOT EIGEN3_VERSION_OK)\n\n    message(STATUS \"Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, \"\n                   \"but at least version ${Eigen3_FIND_VERSION} is required\")\n  endif(NOT EIGEN3_VERSION_OK)\nendmacro(_eigen3_check_version)\n\nif(EIGEN3_INCLUDE_DIR)\n\n  # in cache already\n  _eigen3_check_version()\n  set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})\n\nelse(EIGEN3_INCLUDE_DIR)\n  if(NOT DEFINED KDE4_INCLUDE_DIR)\n    set(KDE4_INCLUDE_DIR \"\")\n  endif()\n\n  find_path(\n    EIGEN3_INCLUDE_DIR\n    NAMES signature_of_eigen3_matrix_library\n    PATHS ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR}\n    PATH_SUFFIXES eigen3 eigen)\n\n  if(EIGEN3_INCLUDE_DIR)\n    _eigen3_check_version()\n  endif(EIGEN3_INCLUDE_DIR)\n\n  include(FindPackageHandleStandardArgs)\n  find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)\n\n  mark_as_advanced(EIGEN3_INCLUDE_DIR)\n\nendif(EIGEN3_INCLUDE_DIR)\n"
  },
  {
    "path": "dlib/external/pybind11/tools/FindPythonLibsNew.cmake",
    "content": "# - Find python libraries\n# This module finds the libraries corresponding to the Python interpreter\n# FindPythonInterp provides.\n# This code sets the following variables:\n#\n#  PYTHONLIBS_FOUND           - have the Python libs been found\n#  PYTHON_PREFIX              - path to the Python installation\n#  PYTHON_LIBRARIES           - path to the python library\n#  PYTHON_INCLUDE_DIRS        - path to where Python.h is found\n#  PYTHON_MODULE_EXTENSION    - lib extension, e.g. '.so' or '.pyd'\n#  PYTHON_MODULE_PREFIX       - lib name prefix: usually an empty string\n#  PYTHON_SITE_PACKAGES       - path to installation site-packages\n#  PYTHON_IS_DEBUG            - whether the Python interpreter is a debug build\n#\n# Thanks to talljimbo for the patch adding the 'LDVERSION' config\n# variable usage.\n\n#=============================================================================\n# Copyright 2001-2009 Kitware, Inc.\n# Copyright 2012 Continuum Analytics, Inc.\n#\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions\n# are met:\n#\n# * Redistributions of source code must retain the above copyright\n# notice, this list of conditions and the following disclaimer.\n#\n# * Redistributions in binary form must reproduce the above copyright\n# notice, this list of conditions and the following disclaimer in the\n# documentation and/or other materials provided with the distribution.\n#\n# * Neither the names of Kitware, Inc., the Insight Software Consortium,\n# nor the names of their contributors may be used to endorse or promote\n# products derived from this software without specific prior written\n# permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n# # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n#=============================================================================\n\n# Checking for the extension makes sure that `LibsNew` was found and not just `Libs`.\nif(PYTHONLIBS_FOUND AND PYTHON_MODULE_EXTENSION)\n  return()\nendif()\n\nif(PythonLibsNew_FIND_QUIETLY)\n  set(_pythonlibs_quiet QUIET)\nelse()\n  set(_pythonlibs_quiet \"\")\nendif()\n\nif(PythonLibsNew_FIND_REQUIRED)\n  set(_pythonlibs_required REQUIRED)\nendif()\n\n# Check to see if the `python` command is present and from a virtual\n# environment, conda, or GHA activation - if it is, try to use that.\n\nif(NOT DEFINED PYTHON_EXECUTABLE)\n  if(DEFINED ENV{VIRTUAL_ENV})\n    find_program(\n      PYTHON_EXECUTABLE python\n      PATHS \"$ENV{VIRTUAL_ENV}\" \"$ENV{VIRTUAL_ENV}/bin\"\n      NO_DEFAULT_PATH)\n  elseif(DEFINED ENV{CONDA_PREFIX})\n    find_program(\n      PYTHON_EXECUTABLE python\n      PATHS \"$ENV{CONDA_PREFIX}\" \"$ENV{CONDA_PREFIX}/bin\"\n      NO_DEFAULT_PATH)\n  elseif(DEFINED ENV{pythonLocation})\n    find_program(\n      PYTHON_EXECUTABLE python\n      PATHS \"$ENV{pythonLocation}\" \"$ENV{pythonLocation}/bin\"\n      NO_DEFAULT_PATH)\n  endif()\n  if(NOT PYTHON_EXECUTABLE)\n    unset(PYTHON_EXECUTABLE)\n  endif()\nendif()\n\n# Use the Python interpreter to find the libs.\nif(NOT PythonLibsNew_FIND_VERSION)\n  set(PythonLibsNew_FIND_VERSION \"3.6\")\nendif()\n\nif(NOT CMAKE_VERSION VERSION_LESS \"3.27\")\n  cmake_policy(GET CMP0148 _pybind11_cmp0148)\n  if(NOT _pybind11_cmp0148)\n    message(\n      AUTHOR_WARNING\n        \"Policy CMP0148 is not set: The FindPythonInterp and FindPythonLibs \"\n        \"modules are removed.  Run \\\"cmake --help-policy CMP0148\\\" for policy \"\n        \"details.  Use the cmake_policy command to set the policy and suppress \"\n        \"this warning, or preferably upgrade to using FindPython, either by \"\n        \"calling it explicitly before pybind11, or by setting \"\n        \"PYBIND11_FINDPYTHON ON before pybind11.\")\n  endif()\n  cmake_policy(SET CMP0148 OLD)\n  unset(_pybind11_cmp0148)\nendif()\n\nfind_package(PythonInterp ${PythonLibsNew_FIND_VERSION} ${_pythonlibs_required}\n             ${_pythonlibs_quiet})\n\nif(NOT PYTHONINTERP_FOUND)\n  set(PYTHONLIBS_FOUND FALSE)\n  set(PythonLibsNew_FOUND FALSE)\n  return()\nendif()\n\n# According to https://stackoverflow.com/questions/646518/python-how-to-detect-debug-interpreter\n# testing whether sys has the gettotalrefcount function is a reliable, cross-platform\n# way to detect a CPython debug interpreter.\n#\n# The library suffix is from the config var LDVERSION sometimes, otherwise\n# VERSION. VERSION will typically be like \"2.7\" on unix, and \"27\" on windows.\nexecute_process(\n  COMMAND\n    \"${PYTHON_EXECUTABLE}\" \"-c\" \"\nimport sys;import struct;\nimport sysconfig as s\nUSE_SYSCONFIG = sys.version_info >= (3, 10)\nif not USE_SYSCONFIG:\n    from distutils import sysconfig as ds\nprint('.'.join(str(v) for v in sys.version_info));\nprint(sys.prefix);\nif USE_SYSCONFIG:\n    scheme = s.get_default_scheme()\n    if scheme == 'posix_local':\n        # Debian's default scheme installs to /usr/local/ but we want to find headers in /usr/\n        scheme = 'posix_prefix'\n    print(s.get_path('platinclude', scheme))\n    print(s.get_path('platlib'))\n    print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))\nelse:\n    print(ds.get_python_inc(plat_specific=True));\n    print(ds.get_python_lib(plat_specific=True));\n    print(ds.get_config_var('EXT_SUFFIX') or ds.get_config_var('SO'));\nprint(hasattr(sys, 'gettotalrefcount')+0);\nprint(struct.calcsize('@P'));\nprint(s.get_config_var('LDVERSION') or s.get_config_var('VERSION'));\nprint(s.get_config_var('LIBDIR') or '');\nprint(s.get_config_var('MULTIARCH') or '');\n\"\n  RESULT_VARIABLE _PYTHON_SUCCESS\n  OUTPUT_VARIABLE _PYTHON_VALUES\n  ERROR_VARIABLE _PYTHON_ERROR_VALUE)\n\nif(NOT _PYTHON_SUCCESS MATCHES 0)\n  if(PythonLibsNew_FIND_REQUIRED)\n    message(FATAL_ERROR \"Python config failure:\\n${_PYTHON_ERROR_VALUE}\")\n  endif()\n  set(PYTHONLIBS_FOUND FALSE)\n  set(PythonLibsNew_FOUND FALSE)\n  return()\nendif()\n\noption(\n  PYBIND11_PYTHONLIBS_OVERWRITE\n  \"Overwrite cached values read from Python library (classic search). Turn off if cross-compiling and manually setting these values.\"\n  ON)\n# Can manually set values when cross-compiling\nmacro(_PYBIND11_GET_IF_UNDEF lst index name)\n  if(PYBIND11_PYTHONLIBS_OVERWRITE OR NOT DEFINED \"${name}\")\n    list(GET \"${lst}\" \"${index}\" \"${name}\")\n  endif()\nendmacro()\n\n# Convert the process output into a list\nif(WIN32)\n  string(REGEX REPLACE \"\\\\\\\\\" \"/\" _PYTHON_VALUES ${_PYTHON_VALUES})\nendif()\nstring(REGEX REPLACE \";\" \"\\\\\\\\;\" _PYTHON_VALUES ${_PYTHON_VALUES})\nstring(REGEX REPLACE \"\\n\" \";\" _PYTHON_VALUES ${_PYTHON_VALUES})\n_pybind11_get_if_undef(_PYTHON_VALUES 0 _PYTHON_VERSION_LIST)\n_pybind11_get_if_undef(_PYTHON_VALUES 1 PYTHON_PREFIX)\n_pybind11_get_if_undef(_PYTHON_VALUES 2 PYTHON_INCLUDE_DIR)\n_pybind11_get_if_undef(_PYTHON_VALUES 3 PYTHON_SITE_PACKAGES)\n_pybind11_get_if_undef(_PYTHON_VALUES 5 PYTHON_IS_DEBUG)\n_pybind11_get_if_undef(_PYTHON_VALUES 6 PYTHON_SIZEOF_VOID_P)\n_pybind11_get_if_undef(_PYTHON_VALUES 7 PYTHON_LIBRARY_SUFFIX)\n_pybind11_get_if_undef(_PYTHON_VALUES 8 PYTHON_LIBDIR)\n_pybind11_get_if_undef(_PYTHON_VALUES 9 PYTHON_MULTIARCH)\n\nlist(GET _PYTHON_VALUES 4 _PYTHON_MODULE_EXT_SUFFIX)\nif(PYBIND11_PYTHONLIBS_OVERWRITE OR NOT DEFINED PYTHON_MODULE_DEBUG_POSTFIX)\n  get_filename_component(PYTHON_MODULE_DEBUG_POSTFIX \"${_PYTHON_MODULE_EXT_SUFFIX}\" NAME_WE)\nendif()\nif(PYBIND11_PYTHONLIBS_OVERWRITE OR NOT DEFINED PYTHON_MODULE_EXTENSION)\n  get_filename_component(PYTHON_MODULE_EXTENSION \"${_PYTHON_MODULE_EXT_SUFFIX}\" EXT)\nendif()\n\n# Make sure the Python has the same pointer-size as the chosen compiler\n# Skip if CMAKE_SIZEOF_VOID_P is not defined\n# This should be skipped for (non-Apple) cross-compiles (like EMSCRIPTEN)\nif(NOT CMAKE_CROSSCOMPILING\n   AND CMAKE_SIZEOF_VOID_P\n   AND (NOT \"${PYTHON_SIZEOF_VOID_P}\" STREQUAL \"${CMAKE_SIZEOF_VOID_P}\"))\n  if(PythonLibsNew_FIND_REQUIRED)\n    math(EXPR _PYTHON_BITS \"${PYTHON_SIZEOF_VOID_P} * 8\")\n    math(EXPR _CMAKE_BITS \"${CMAKE_SIZEOF_VOID_P} * 8\")\n    message(FATAL_ERROR \"Python config failure: Python is ${_PYTHON_BITS}-bit, \"\n                        \"chosen compiler is  ${_CMAKE_BITS}-bit\")\n  endif()\n  set(PYTHONLIBS_FOUND FALSE)\n  set(PythonLibsNew_FOUND FALSE)\n  return()\nendif()\n\n# The built-in FindPython didn't always give the version numbers\nstring(REGEX REPLACE \"\\\\.\" \";\" _PYTHON_VERSION_LIST ${_PYTHON_VERSION_LIST})\nlist(GET _PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)\nlist(GET _PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)\nlist(GET _PYTHON_VERSION_LIST 2 PYTHON_VERSION_PATCH)\nset(PYTHON_VERSION \"${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}.${PYTHON_VERSION_PATCH}\")\n\n# Make sure all directory separators are '/'\nstring(REGEX REPLACE \"\\\\\\\\\" \"/\" PYTHON_PREFIX \"${PYTHON_PREFIX}\")\nstring(REGEX REPLACE \"\\\\\\\\\" \"/\" PYTHON_INCLUDE_DIR \"${PYTHON_INCLUDE_DIR}\")\nstring(REGEX REPLACE \"\\\\\\\\\" \"/\" PYTHON_SITE_PACKAGES \"${PYTHON_SITE_PACKAGES}\")\n\nif(DEFINED PYTHON_LIBRARY)\n  # Don't write to PYTHON_LIBRARY if it's already set\nelseif(CMAKE_HOST_WIN32)\n  set(PYTHON_LIBRARY \"${PYTHON_PREFIX}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib\")\n\n  # when run in a venv, PYTHON_PREFIX points to it. But the libraries remain in the\n  # original python installation. They may be found relative to PYTHON_INCLUDE_DIR.\n  if(NOT EXISTS \"${PYTHON_LIBRARY}\")\n    get_filename_component(_PYTHON_ROOT ${PYTHON_INCLUDE_DIR} DIRECTORY)\n    set(PYTHON_LIBRARY \"${_PYTHON_ROOT}/libs/python${PYTHON_LIBRARY_SUFFIX}.lib\")\n  endif()\n\n  # if we are in MSYS & MINGW, and we didn't find windows python lib, look for system python lib\n  if(DEFINED ENV{MSYSTEM}\n     AND MINGW\n     AND NOT EXISTS \"${PYTHON_LIBRARY}\")\n    if(PYTHON_MULTIARCH)\n      set(_PYTHON_LIBS_SEARCH \"${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}\" \"${PYTHON_LIBDIR}\")\n    else()\n      set(_PYTHON_LIBS_SEARCH \"${PYTHON_LIBDIR}\")\n    endif()\n    unset(PYTHON_LIBRARY)\n    find_library(\n      PYTHON_LIBRARY\n      NAMES \"python${PYTHON_LIBRARY_SUFFIX}\"\n      PATHS ${_PYTHON_LIBS_SEARCH}\n      NO_DEFAULT_PATH)\n  endif()\n\n  # raise an error if the python libs are still not found.\n  if(NOT EXISTS \"${PYTHON_LIBRARY}\")\n    message(FATAL_ERROR \"Python libraries not found\")\n  endif()\n\nelse()\n  if(PYTHON_MULTIARCH)\n    set(_PYTHON_LIBS_SEARCH \"${PYTHON_LIBDIR}/${PYTHON_MULTIARCH}\" \"${PYTHON_LIBDIR}\")\n  else()\n    set(_PYTHON_LIBS_SEARCH \"${PYTHON_LIBDIR}\")\n  endif()\n  #message(STATUS \"Searching for Python libs in ${_PYTHON_LIBS_SEARCH}\")\n  # Probably this needs to be more involved. It would be nice if the config\n  # information the python interpreter itself gave us were more complete.\n  find_library(\n    PYTHON_LIBRARY\n    NAMES \"python${PYTHON_LIBRARY_SUFFIX}\"\n    PATHS ${_PYTHON_LIBS_SEARCH}\n    NO_DEFAULT_PATH)\n\n  # If all else fails, just set the name/version and let the linker figure out the path.\n  if(NOT PYTHON_LIBRARY)\n    set(PYTHON_LIBRARY python${PYTHON_LIBRARY_SUFFIX})\n  endif()\nendif()\n\nmark_as_advanced(PYTHON_LIBRARY PYTHON_INCLUDE_DIR)\n\n# We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the\n# cache entries because they are meant to specify the location of a single\n# library. We now set the variables listed by the documentation for this\n# module.\nset(PYTHON_INCLUDE_DIRS \"${PYTHON_INCLUDE_DIR}\")\nset(PYTHON_LIBRARIES \"${PYTHON_LIBRARY}\")\nif(NOT PYTHON_DEBUG_LIBRARY)\n  set(PYTHON_DEBUG_LIBRARY \"\")\nendif()\nset(PYTHON_DEBUG_LIBRARIES \"${PYTHON_DEBUG_LIBRARY}\")\n\nfind_package_message(PYTHON \"Found PythonLibs: ${PYTHON_LIBRARIES}\"\n                     \"${PYTHON_EXECUTABLE}${PYTHON_VERSION_STRING}\")\n\nset(PYTHONLIBS_FOUND TRUE)\nset(PythonLibsNew_FOUND TRUE)\n\nif(NOT PYTHON_MODULE_PREFIX)\n  set(PYTHON_MODULE_PREFIX \"\")\nendif()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/JoinPaths.cmake",
    "content": "# This module provides function for joining paths\n# known from most languages\n#\n# SPDX-License-Identifier: (MIT OR CC0-1.0)\n# Copyright 2020 Jan Tojnar\n# https://github.com/jtojnar/cmake-snips\n#\n# Modelled after Python’s os.path.join\n# https://docs.python.org/3.7/library/os.path.html#os.path.join\n# Windows not supported\nfunction(join_paths joined_path first_path_segment)\n    set(temp_path \"${first_path_segment}\")\n    foreach(current_segment IN LISTS ARGN)\n        if(NOT (\"${current_segment}\" STREQUAL \"\"))\n            if(IS_ABSOLUTE \"${current_segment}\")\n                set(temp_path \"${current_segment}\")\n            else()\n                set(temp_path \"${temp_path}/${current_segment}\")\n            endif()\n        endif()\n    endforeach()\n    set(${joined_path} \"${temp_path}\" PARENT_SCOPE)\nendfunction()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/check-style.sh",
    "content": "#!/bin/bash\n#\n# Script to check include/test code for common pybind11 code style errors.\n#\n# This script currently checks for\n#\n# 1. missing space between keyword and parenthesis, e.g.: for(, if(, while(\n# 2. Missing space between right parenthesis and brace, e.g. 'for (...){'\n# 3. opening brace on its own line. It should always be on the same line as the\n#    if/while/for/do statement.\n#\n# Invoke as: tools/check-style.sh <filenames>\n#\n\ncheck_style_errors=0\nIFS=$'\\n'\n\n\nfound=\"$(grep '\\<\\(if\\|for\\|while\\|catch\\)(\\|){' \"$@\" -rn --color=always)\"\nif [ -n \"$found\" ]; then\n    echo -e '\\033[31;01mError: found the following coding style problems:\\033[0m'\n    check_style_errors=1\n    echo \"${found//^/    /}\"\nfi\n\nfound=\"$(awk '\nfunction prefix(filename, lineno) {\n    return \"    \\033[35m\" filename \"\\033[36m:\\033[32m\" lineno \"\\033[36m:\\033[0m\"\n}\nfunction mark(pattern, string) { sub(pattern, \"\\033[01;31m&\\033[0m\", string); return string }\nlast && /^\\s*{/ {\n    print prefix(FILENAME, FNR-1) mark(\"\\\\)\\\\s*$\", last)\n    print prefix(FILENAME, FNR)   mark(\"^\\\\s*{\", $0)\n    last=\"\"\n}\n{ last = /(if|for|while|catch|switch)\\s*\\(.*\\)\\s*$/ ? $0 : \"\" }\n' \"$(find include -type f)\" \"$@\")\"\nif [ -n \"$found\" ]; then\n    check_style_errors=1\n    echo -e '\\033[31;01mError: braces should occur on the same line as the if/while/.. statement. Found issues in the following files:\\033[0m'\n    echo \"$found\"\nfi\n\nexit $check_style_errors\n"
  },
  {
    "path": "dlib/external/pybind11/tools/cmake_uninstall.cmake.in",
    "content": "# Source: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#can-i-do-make-uninstall-with-cmake\n\nif(NOT EXISTS \"@CMAKE_BINARY_DIR@/install_manifest.txt\")\n  message(FATAL_ERROR \"Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt\")\nendif()\n\nfile(READ \"@CMAKE_BINARY_DIR@/install_manifest.txt\" files)\nstring(REGEX REPLACE \"\\n\" \";\" files \"${files}\")\nforeach(file ${files})\n  message(STATUS \"Uninstalling $ENV{DESTDIR}${file}\")\n  if(IS_SYMLINK \"$ENV{DESTDIR}${file}\" OR EXISTS \"$ENV{DESTDIR}${file}\")\n    exec_program(\n      \"@CMAKE_COMMAND@\" ARGS\n      \"-E remove \\\"$ENV{DESTDIR}${file}\\\"\"\n      OUTPUT_VARIABLE rm_out\n      RETURN_VALUE rm_retval)\n    if(NOT \"${rm_retval}\" STREQUAL 0)\n      message(FATAL_ERROR \"Problem when removing $ENV{DESTDIR}${file}\")\n    endif()\n  else(IS_SYMLINK \"$ENV{DESTDIR}${file}\" OR EXISTS \"$ENV{DESTDIR}${file}\")\n    message(STATUS \"File $ENV{DESTDIR}${file} does not exist.\")\n  endif()\nendforeach()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/codespell_ignore_lines_from_errors.py",
    "content": "\"\"\"Simple script for rebuilding .codespell-ignore-lines\n\nUsage:\n\ncat < /dev/null > .codespell-ignore-lines\npre-commit run --all-files codespell >& /tmp/codespell_errors.txt\npython3 tools/codespell_ignore_lines_from_errors.py /tmp/codespell_errors.txt > .codespell-ignore-lines\n\ngit diff to review changes, then commit, push.\n\"\"\"\n\nimport sys\nfrom typing import List\n\n\ndef run(args: List[str]) -> None:\n    assert len(args) == 1, \"codespell_errors.txt\"\n    cache = {}\n    done = set()\n    with open(args[0]) as f:\n        lines = f.read().splitlines()\n\n    for line in sorted(lines):\n        i = line.find(\" ==> \")\n        if i > 0:\n            flds = line[:i].split(\":\")\n            if len(flds) >= 2:\n                filename, line_num = flds[:2]\n                if filename not in cache:\n                    with open(filename) as f:\n                        cache[filename] = f.read().splitlines()\n                supp = cache[filename][int(line_num) - 1]\n                if supp not in done:\n                    print(supp)\n                    done.add(supp)\n\n\nif __name__ == \"__main__\":\n    run(args=sys.argv[1:])\n"
  },
  {
    "path": "dlib/external/pybind11/tools/libsize.py",
    "content": "import os\nimport sys\n\n# Internal build script for generating debugging test .so size.\n# Usage:\n#     python libsize.py file.so save.txt -- displays the size of file.so and, if save.txt exists, compares it to the\n#                                           size in it, then overwrites save.txt with the new size for future runs.\n\nif len(sys.argv) != 3:\n    sys.exit(\"Invalid arguments: usage: python libsize.py file.so save.txt\")\n\nlib = sys.argv[1]\nsave = sys.argv[2]\n\nif not os.path.exists(lib):\n    sys.exit(f\"Error: requested file ({lib}) does not exist\")\n\nlibsize = os.path.getsize(lib)\n\nprint(\"------\", os.path.basename(lib), \"file size:\", libsize, end=\"\")\n\nif os.path.exists(save):\n    with open(save) as sf:\n        oldsize = int(sf.readline())\n\n    if oldsize > 0:\n        change = libsize - oldsize\n        if change == 0:\n            print(\" (no change)\")\n        else:\n            print(f\" (change of {change:+} bytes = {change / oldsize:+.2%})\")\nelse:\n    print()\n\nwith open(save, \"w\") as sf:\n    sf.write(str(libsize))\n"
  },
  {
    "path": "dlib/external/pybind11/tools/make_changelog.py",
    "content": "#!/usr/bin/env python3\nfrom __future__ import annotations\n\nimport re\n\nimport ghapi.all\nfrom rich import print\nfrom rich.syntax import Syntax\n\nENTRY = re.compile(\n    r\"\"\"\n    Suggested \\s changelog \\s entry:\n    .*\n    ```rst\n    \\s*\n    (.*?)\n    \\s*\n    ```\n\"\"\",\n    re.DOTALL | re.VERBOSE,\n)\n\nprint()\n\n\napi = ghapi.all.GhApi(owner=\"pybind\", repo=\"pybind11\")\n\nissues_pages = ghapi.page.paged(\n    api.issues.list_for_repo, labels=\"needs changelog\", state=\"closed\"\n)\nissues = (issue for page in issues_pages for issue in page)\nmissing = []\ncats_descr = {\n    \"feat\": \"New Features\",\n    \"fix\": \"Bug fixes\",\n    \"fix(types)\": \"\",\n    \"fix(cmake)\": \"\",\n    \"docs\": \"Documentation\",\n    \"tests\": \"Tests\",\n    \"ci\": \"CI\",\n    \"chore\": \"Other\",\n    \"unknown\": \"Uncategorised\",\n}\ncats: dict[str, list[str]] = {c: [] for c in cats_descr}\n\nfor issue in issues:\n    changelog = ENTRY.findall(issue.body or \"\")\n    if not changelog or not changelog[0]:\n        missing.append(issue)\n    else:\n        (msg,) = changelog\n        if msg.startswith(\"- \"):\n            msg = msg[2:]\n        if not msg.startswith(\"* \"):\n            msg = \"* \" + msg\n        if not msg.endswith(\".\"):\n            msg += \".\"\n\n        msg += f\"\\n  `#{issue.number} <{issue.html_url}>`_\"\n        for cat in cats:\n            if issue.title.lower().startswith(f\"{cat}:\"):\n                cats[cat].append(msg)\n                break\n        else:\n            cats[\"unknown\"].append(msg)\n\nfor cat, msgs in cats.items():\n    if msgs:\n        desc = cats_descr[cat]\n        print(f\"[bold]{desc}:\" if desc else f\".. {cat}\")\n        print()\n        for msg in msgs:\n            print(Syntax(msg, \"rst\", theme=\"ansi_light\", word_wrap=True))\n            print()\n        print()\n\nif missing:\n    print()\n    print(\"[blue]\" + \"-\" * 30)\n    print()\n\n    for issue in missing:\n        print(f\"[red bold]Missing:[/red bold][red] {issue.title}\")\n        print(f\"[red]  {issue.html_url}\\n\")\n\n    print(\"[bold]Template:\\n\")\n    msg = \"## Suggested changelog entry:\\n\\n```rst\\n\\n```\"\n    print(Syntax(msg, \"md\", theme=\"ansi_light\"))\n\nprint()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pybind11.pc.in",
    "content": "prefix=@prefix_for_pc_file@\nincludedir=@includedir_for_pc_file@\n\nName: @PROJECT_NAME@\nDescription: Seamless operability between C++11 and Python\nVersion: @PROJECT_VERSION@\nCflags: -I${includedir}\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pybind11Common.cmake",
    "content": "#[======================================================[.rst\n\nAdds the following targets::\n\n    pybind11::pybind11 - link to headers and pybind11\n    pybind11::module - Adds module links\n    pybind11::embed - Adds embed links\n    pybind11::lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set)\n    pybind11::thin_lto - Link time optimizations (only if CMAKE_INTERPROCEDURAL_OPTIMIZATION is not set)\n    pybind11::python_link_helper - Adds link to Python libraries\n    pybind11::windows_extras - MSVC bigobj and mp for building multithreaded\n    pybind11::opt_size - avoid optimizations that increase code size\n\nAdds the following functions::\n\n    pybind11_strip(target) - strip target after building on linux/macOS\n    pybind11_find_import(module) - See if a module is installed.\n\n#]======================================================]\n\n# CMake 3.10 has an include_guard command, but we can't use that yet\n# include_guard(global) (pre-CMake 3.10)\nif(TARGET pybind11::pybind11)\n  return()\nendif()\n\n# If we are in subdirectory mode, all IMPORTED targets must be GLOBAL. If we\n# are in CONFIG mode, they should be \"normal\" targets instead.\n# In CMake 3.11+ you can promote a target to global after you create it,\n# which might be simpler than this check.\nget_property(\n  is_config\n  TARGET pybind11::headers\n  PROPERTY IMPORTED)\nif(NOT is_config)\n  set(optional_global GLOBAL)\nendif()\n\n# If not run in Python mode, we still would like this to at least\n# include pybind11's include directory:\nset(pybind11_INCLUDE_DIRS\n    \"${pybind11_INCLUDE_DIR}\"\n    CACHE INTERNAL \"Include directory for pybind11 (Python not requested)\")\n\n# --------------------- Shared targets ----------------------------\n\n# Build an interface library target:\nadd_library(pybind11::pybind11 IMPORTED INTERFACE ${optional_global})\nset_property(\n  TARGET pybind11::pybind11\n  APPEND\n  PROPERTY INTERFACE_LINK_LIBRARIES pybind11::headers)\n\n# Build a module target:\nadd_library(pybind11::module IMPORTED INTERFACE ${optional_global})\nset_property(\n  TARGET pybind11::module\n  APPEND\n  PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)\n\n# Build an embed library target:\nadd_library(pybind11::embed IMPORTED INTERFACE ${optional_global})\nset_property(\n  TARGET pybind11::embed\n  APPEND\n  PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11)\n\n# --------------------------- link helper ---------------------------\n\nadd_library(pybind11::python_link_helper IMPORTED INTERFACE ${optional_global})\n\nif(CMAKE_VERSION VERSION_LESS 3.13)\n  # In CMake 3.11+, you can set INTERFACE properties via the normal methods, and\n  # this would be simpler.\n  set_property(\n    TARGET pybind11::python_link_helper\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES \"$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>\")\nelse()\n  # link_options was added in 3.13+\n  # This is safer, because you are ensured the deduplication pass in CMake will not consider\n  # these separate and remove one but not the other.\n  set_property(\n    TARGET pybind11::python_link_helper\n    APPEND\n    PROPERTY INTERFACE_LINK_OPTIONS \"$<$<PLATFORM_ID:Darwin>:LINKER:-undefined,dynamic_lookup>\")\nendif()\n\n# ------------------------ Windows extras -------------------------\n\nadd_library(pybind11::windows_extras IMPORTED INTERFACE ${optional_global})\n\nif(MSVC) # That's also clang-cl\n  # /bigobj is needed for bigger binding projects due to the limit to 64k\n  # addressable sections\n  set_property(\n    TARGET pybind11::windows_extras\n    APPEND\n    PROPERTY INTERFACE_COMPILE_OPTIONS $<$<COMPILE_LANGUAGE:CXX>:/bigobj>)\n\n  # /MP enables multithreaded builds (relevant when there are many files) for MSVC\n  if(\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\") # no Clang no Intel\n    if(CMAKE_VERSION VERSION_LESS 3.11)\n      set_property(\n        TARGET pybind11::windows_extras\n        APPEND\n        PROPERTY INTERFACE_COMPILE_OPTIONS $<$<NOT:$<CONFIG:Debug>>:/MP>)\n    else()\n      # Only set these options for C++ files.  This is important so that, for\n      # instance, projects that include other types of source files like CUDA\n      # .cu files don't get these options propagated to nvcc since that would\n      # cause the build to fail.\n      set_property(\n        TARGET pybind11::windows_extras\n        APPEND\n        PROPERTY INTERFACE_COMPILE_OPTIONS\n                 $<$<NOT:$<CONFIG:Debug>>:$<$<COMPILE_LANGUAGE:CXX>:/MP>>)\n    endif()\n  endif()\nendif()\n\n# ----------------------- Optimize binary size --------------------------\n\nadd_library(pybind11::opt_size IMPORTED INTERFACE ${optional_global})\n\nif(MSVC)\n  set(PYBIND11_OPT_SIZE /Os)\nelse()\n  set(PYBIND11_OPT_SIZE -Os)\nendif()\n\nset_property(\n  TARGET pybind11::opt_size\n  APPEND\n  PROPERTY INTERFACE_COMPILE_OPTIONS $<$<CONFIG:Release>:${PYBIND11_OPT_SIZE}>\n           $<$<CONFIG:MinSizeRel>:${PYBIND11_OPT_SIZE}>\n           $<$<CONFIG:RelWithDebInfo>:${PYBIND11_OPT_SIZE}>)\n\n# ----------------------- Legacy option --------------------------\n\n# Warn or error if old variable name used\nif(PYBIND11_CPP_STANDARD)\n  string(REGEX MATCH [[..$]] VAL \"${PYBIND11_CPP_STANDARD}\")\n  if(CMAKE_CXX_STANDARD)\n    if(NOT CMAKE_CXX_STANDARD STREQUAL VAL)\n      message(WARNING \"CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} does not match \"\n                      \"PYBIND11_CPP_STANDARD=${PYBIND11_CPP_STANDARD}, \"\n                      \"please remove PYBIND11_CPP_STANDARD from your cache\")\n    endif()\n  else()\n    set(supported_standards 11 14 17 20)\n    if(\"${VAL}\" IN_LIST supported_standards)\n      message(WARNING \"USE -DCMAKE_CXX_STANDARD=${VAL} instead of PYBIND11_CPP_STANDARD\")\n      set(CMAKE_CXX_STANDARD\n          ${VAL}\n          CACHE STRING \"From PYBIND11_CPP_STANDARD\")\n    else()\n      message(FATAL_ERROR \"PYBIND11_CPP_STANDARD should be replaced with CMAKE_CXX_STANDARD \"\n                          \"(last two chars: ${VAL} not understood as a valid CXX std)\")\n    endif()\n  endif()\nendif()\n\n# --------------------- Python specifics -------------------------\n\n# CMake 3.27 removes the classic FindPythonInterp if CMP0148 is NEW\nif(CMAKE_VERSION VERSION_LESS \"3.27\")\n  set(_pybind11_missing_old_python \"OLD\")\nelse()\n  cmake_policy(GET CMP0148 _pybind11_missing_old_python)\nendif()\n\n# Check to see which Python mode we are in, new, old, or no python\nif(PYBIND11_NOPYTHON)\n  set(_pybind11_nopython ON)\n  # We won't use new FindPython if PYBIND11_FINDPYTHON is defined and falselike\n  # Otherwise, we use if FindPythonLibs is missing or if FindPython was already used\nelseif(\n  (NOT DEFINED PYBIND11_FINDPYTHON OR PYBIND11_FINDPYTHON)\n  AND (_pybind11_missing_old_python STREQUAL \"NEW\"\n       OR PYBIND11_FINDPYTHON\n       OR Python_FOUND\n       OR Python3_FOUND\n      ))\n\n  # New mode\n  include(\"${CMAKE_CURRENT_LIST_DIR}/pybind11NewTools.cmake\")\n\nelse()\n\n  # Classic mode\n  include(\"${CMAKE_CURRENT_LIST_DIR}/pybind11Tools.cmake\")\n\nendif()\n\n# --------------------- pybind11_find_import -------------------------------\n\nif(NOT _pybind11_nopython)\n  # Check to see if modules are importable. Use REQUIRED to force an error if\n  # one of the modules is not found. <package_name>_FOUND will be set if the\n  # package was found (underscores replace dashes if present). QUIET will hide\n  # the found message, and VERSION will require a minimum version. A successful\n  # find will cache the result.\n  function(pybind11_find_import PYPI_NAME)\n    # CMake variables need underscores (PyPI doesn't care)\n    string(REPLACE \"-\" \"_\" NORM_PYPI_NAME \"${PYPI_NAME}\")\n\n    # Return if found previously\n    if(${NORM_PYPI_NAME}_FOUND)\n      return()\n    endif()\n\n    set(options \"REQUIRED;QUIET\")\n    set(oneValueArgs \"VERSION\")\n    cmake_parse_arguments(ARG \"${options}\" \"${oneValueArgs}\" \"\" ${ARGN})\n\n    if(ARG_REQUIRED)\n      set(status_level FATAL_ERROR)\n    else()\n      set(status_level WARNING)\n    endif()\n\n    execute_process(\n      COMMAND\n        ${${_Python}_EXECUTABLE} -c \"\ntry:\n    from importlib.metadata import version\nexcept ImportError:\n    from pkg_resources import get_distribution\n    def version(s):\n        return get_distribution(s).version\nprint(version('${PYPI_NAME}'))\n        \"\n      RESULT_VARIABLE RESULT_PRESENT\n      OUTPUT_VARIABLE PKG_VERSION\n      ERROR_QUIET)\n\n    string(STRIP \"${PKG_VERSION}\" PKG_VERSION)\n\n    # If a result is present, this failed\n    if(RESULT_PRESENT)\n      set(${NORM_PYPI_NAME}_FOUND\n          ${NORM_PYPI_NAME}-NOTFOUND\n          CACHE INTERNAL \"\")\n      # Always warn or error\n      message(\n        ${status_level}\n        \"Missing: ${PYPI_NAME} ${ARG_VERSION}\\nTry: ${${_Python}_EXECUTABLE} -m pip install ${PYPI_NAME}\"\n      )\n    else()\n      if(ARG_VERSION AND PKG_VERSION VERSION_LESS ARG_VERSION)\n        message(\n          ${status_level}\n          \"Version incorrect: ${PYPI_NAME} ${PKG_VERSION} found, ${ARG_VERSION} required - try upgrading\"\n        )\n      else()\n        set(${NORM_PYPI_NAME}_FOUND\n            YES\n            CACHE INTERNAL \"\")\n        set(${NORM_PYPI_NAME}_VERSION\n            ${PKG_VERSION}\n            CACHE INTERNAL \"\")\n      endif()\n      if(NOT ARG_QUIET)\n        message(STATUS \"Found ${PYPI_NAME} ${PKG_VERSION}\")\n      endif()\n    endif()\n    if(NOT ARG_VERSION OR (NOT PKG_VERSION VERSION_LESS ARG_VERSION))\n      # We have successfully found a good version, cache to avoid calling again.\n    endif()\n  endfunction()\nendif()\n\n# --------------------- LTO -------------------------------\n\ninclude(CheckCXXCompilerFlag)\n\n# Checks whether the given CXX/linker flags can compile and link a cxx file.\n# cxxflags and linkerflags are lists of flags to use.  The result variable is a\n# unique variable name for each set of flags: the compilation result will be\n# cached base on the result variable.  If the flags work, sets them in\n# cxxflags_out/linkerflags_out internal cache variables (in addition to\n# ${result}).\nfunction(_pybind11_return_if_cxx_and_linker_flags_work result cxxflags linkerflags cxxflags_out\n         linkerflags_out)\n  set(CMAKE_REQUIRED_LIBRARIES ${linkerflags})\n  check_cxx_compiler_flag(\"${cxxflags}\" ${result})\n  if(${result})\n    set(${cxxflags_out}\n        \"${cxxflags}\"\n        PARENT_SCOPE)\n    set(${linkerflags_out}\n        \"${linkerflags}\"\n        PARENT_SCOPE)\n  endif()\nendfunction()\n\nfunction(_pybind11_generate_lto target prefer_thin_lto)\n  if(MINGW)\n    message(STATUS \"${target} disabled (problems with undefined symbols for MinGW for now)\")\n    return()\n  endif()\n\n  if(CMAKE_CXX_COMPILER_ID MATCHES \"GNU|Clang\")\n    set(cxx_append \"\")\n    set(linker_append \"\")\n    if(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\" AND NOT APPLE)\n      # Clang Gold plugin does not support -Os; append -O3 to MinSizeRel builds to override it\n      set(linker_append \";$<$<CONFIG:MinSizeRel>:-O3>\")\n    elseif(CMAKE_CXX_COMPILER_ID MATCHES \"GNU\" AND NOT MINGW)\n      set(cxx_append \";-fno-fat-lto-objects\")\n    endif()\n\n    if(prefer_thin_lto)\n      set(thin \"=thin\")\n    else()\n      set(thin \"\")\n    endif()\n\n    if(CMAKE_SYSTEM_PROCESSOR MATCHES \"ppc64le\" OR CMAKE_SYSTEM_PROCESSOR MATCHES \"mips64\")\n      # Do nothing\n    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES emscripten)\n      # This compile is very costly when cross-compiling, so set this without checking\n      set(PYBIND11_LTO_CXX_FLAGS \"-flto${thin}${cxx_append}\")\n      set(PYBIND11_LTO_LINKER_FLAGS \"-flto${thin}${linker_append}\")\n    elseif(CMAKE_CXX_COMPILER_ID MATCHES \"Clang\")\n      _pybind11_return_if_cxx_and_linker_flags_work(\n        HAS_FLTO_THIN \"-flto${thin}${cxx_append}\" \"-flto=${thin}${linker_append}\"\n        PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)\n    endif()\n    if(NOT HAS_FLTO_THIN)\n      _pybind11_return_if_cxx_and_linker_flags_work(\n        HAS_FLTO \"-flto${cxx_append}\" \"-flto${linker_append}\" PYBIND11_LTO_CXX_FLAGS\n        PYBIND11_LTO_LINKER_FLAGS)\n    endif()\n  elseif(CMAKE_CXX_COMPILER_ID MATCHES \"IntelLLVM\")\n    # IntelLLVM equivalent to LTO is called IPO; also IntelLLVM is WIN32/UNIX\n    # WARNING/HELP WANTED: This block of code is currently not covered by pybind11 GitHub Actions!\n    if(WIN32)\n      _pybind11_return_if_cxx_and_linker_flags_work(\n        HAS_INTEL_IPO \"-Qipo\" \"-Qipo\" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)\n    else()\n      _pybind11_return_if_cxx_and_linker_flags_work(\n        HAS_INTEL_IPO \"-ipo\" \"-ipo\" PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)\n    endif()\n  elseif(CMAKE_CXX_COMPILER_ID MATCHES \"Intel\")\n    # Intel equivalent to LTO is called IPO\n    _pybind11_return_if_cxx_and_linker_flags_work(HAS_INTEL_IPO \"-ipo\" \"-ipo\"\n                                                  PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)\n  elseif(MSVC)\n    # cmake only interprets libraries as linker flags when they start with a - (otherwise it\n    # converts /LTCG to \\LTCG as if it was a Windows path).  Luckily MSVC supports passing flags\n    # with - instead of /, even if it is a bit non-standard:\n    _pybind11_return_if_cxx_and_linker_flags_work(HAS_MSVC_GL_LTCG \"/GL\" \"-LTCG\"\n                                                  PYBIND11_LTO_CXX_FLAGS PYBIND11_LTO_LINKER_FLAGS)\n  endif()\n\n  # Enable LTO flags if found, except for Debug builds\n  if(PYBIND11_LTO_CXX_FLAGS)\n    # CONFIG takes multiple values in CMake 3.19+, until then we have to use OR\n    set(is_debug \"$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>\")\n    set(not_debug \"$<NOT:${is_debug}>\")\n    set(cxx_lang \"$<COMPILE_LANGUAGE:CXX>\")\n    if(MSVC AND CMAKE_VERSION VERSION_LESS 3.11)\n      set(genex \"${not_debug}\")\n    else()\n      set(genex \"$<AND:${not_debug},${cxx_lang}>\")\n    endif()\n    set_property(\n      TARGET ${target}\n      APPEND\n      PROPERTY INTERFACE_COMPILE_OPTIONS \"$<${genex}:${PYBIND11_LTO_CXX_FLAGS}>\")\n    if(CMAKE_PROJECT_NAME STREQUAL \"pybind11\")\n      message(STATUS \"${target} enabled\")\n    endif()\n  else()\n    if(CMAKE_PROJECT_NAME STREQUAL \"pybind11\")\n      message(STATUS \"${target} disabled (not supported by the compiler and/or linker)\")\n    endif()\n  endif()\n\n  if(PYBIND11_LTO_LINKER_FLAGS)\n    if(CMAKE_VERSION VERSION_LESS 3.11)\n      set_property(\n        TARGET ${target}\n        APPEND\n        PROPERTY INTERFACE_LINK_LIBRARIES \"$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>\")\n    else()\n      set_property(\n        TARGET ${target}\n        APPEND\n        PROPERTY INTERFACE_LINK_OPTIONS \"$<${not_debug}:${PYBIND11_LTO_LINKER_FLAGS}>\")\n    endif()\n  endif()\nendfunction()\n\nif(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)\n  add_library(pybind11::lto IMPORTED INTERFACE ${optional_global})\n  _pybind11_generate_lto(pybind11::lto FALSE)\n\n  add_library(pybind11::thin_lto IMPORTED INTERFACE ${optional_global})\n  _pybind11_generate_lto(pybind11::thin_lto TRUE)\nendif()\n\n# ---------------------- pybind11_strip -----------------------------\n\nfunction(pybind11_strip target_name)\n  # Strip unnecessary sections of the binary on Linux/macOS\n  if(CMAKE_STRIP)\n    if(APPLE)\n      set(x_opt -x)\n    endif()\n\n    add_custom_command(\n      TARGET ${target_name}\n      POST_BUILD\n      COMMAND ${CMAKE_STRIP} ${x_opt} $<TARGET_FILE:${target_name}>)\n  endif()\nendfunction()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pybind11Config.cmake.in",
    "content": "#[=============================================================================[.rst:\n\npybind11Config.cmake\n####################\n\nExported variables\n==================\n\nThis module sets the following variables in your project:\n\n``pybind11_FOUND``\n  true if pybind11 and all required components found on the system\n``pybind11_VERSION``\n  pybind11 version in format Major.Minor.Release\n``pybind11_VERSION_TYPE``\n  pybind11 version type (``dev*`` or empty for a release)\n``pybind11_INCLUDE_DIRS``\n  Directories where pybind11 and python headers are located.\n``pybind11_INCLUDE_DIR``\n  Directory where pybind11 headers are located.\n``pybind11_DEFINITIONS``\n  Definitions necessary to use pybind11, namely USING_pybind11.\n``pybind11_LIBRARIES``\n  Compile flags and python libraries (as needed) to link against.\n``pybind11_LIBRARY``\n  Empty.\n\nAvailable components: None\n\n\nExported targets\n================\n\nIf pybind11 is found, this module defines the following ``IMPORTED``\ninterface library targets:\n\n``pybind11::module``\n  for extension modules.\n``pybind11::embed``\n  for embedding the Python interpreter.\n\nPython headers, libraries (as needed by platform), and the C++ standard\nare attached to the target.\n\nAdvanced targets are also supplied - these are primary for users building\ncomplex applications, and they are available in all modes:\n\n``pybind11::headers``\n  Just the pybind11 headers and minimum compile requirements.\n``pybind11::pybind11``\n  Python headers too.\n``pybind11::python_link_helper``\n  Just the \"linking\" part of ``pybind11:module``, for CMake < 3.15.\n``pybind11::thin_lto``\n  An alternative to ``INTERPROCEDURAL_OPTIMIZATION``.\n``pybind11::lto``\n  An alternative to ``INTERPROCEDURAL_OPTIMIZATION`` (also avoids thin LTO on clang).\n``pybind11::windows_extras``\n  Adds bigobj and mp for MSVC.\n\nModes\n=====\n\nThere are two modes provided; classic, which is built on the old Python\ndiscovery packages in CMake, or the new FindPython mode, which uses FindPython\nfrom 3.12+ forward (3.15+ _highly_ recommended). If you set the minimum or\nmaximum version of CMake to 3.27+, then FindPython is the default (since\nFindPythonInterp/FindPythonLibs has been removed via policy `CMP0148`).\n\nNew FindPython mode\n^^^^^^^^^^^^^^^^^^^\n\nTo activate this mode, either call ``find_package(Python COMPONENTS Interpreter Development)``\nbefore finding this package, or set the ``PYBIND11_FINDPYTHON`` variable to ON. In this mode,\nyou can either use the basic targets, or use the FindPython tools:\n\n.. code-block:: cmake\n\n  find_package(Python COMPONENTS Interpreter Development)\n  find_package(pybind11 CONFIG)\n\n  # pybind11 method:\n  pybind11_add_module(MyModule1 src1.cpp)\n\n  # Python method:\n  Python_add_library(MyModule2 src2.cpp)\n  target_link_libraries(MyModule2 pybind11::headers)\n  set_target_properties(MyModule2 PROPERTIES\n                                  INTERPROCEDURAL_OPTIMIZATION ON\n                                  CXX_VISIBILITY_PRESET ON\n                                  VISIBILITY_INLINES_HIDDEN ON)\n\nIf you build targets yourself, you may be interested in stripping the output\nfor reduced size; this is the one other feature that the helper function gives you.\n\nClassic mode\n^^^^^^^^^^^^\n\nSet PythonLibsNew variables to influence python detection and\nCMAKE_CXX_STANDARD to influence standard setting.\n\n.. code-block:: cmake\n\n  find_package(pybind11 CONFIG REQUIRED)\n\n  # Create an extension module\n  add_library(mylib MODULE main.cpp)\n  target_link_libraries(mylib PUBLIC pybind11::module)\n\n  # Or embed the Python interpreter into an executable\n  add_executable(myexe main.cpp)\n  target_link_libraries(myexe PUBLIC pybind11::embed)\n\n\nHints\n=====\n\nThe following variables can be set to guide the search for this package:\n\n``pybind11_DIR``\n  CMake variable, set to directory containing this Config file.\n``CMAKE_PREFIX_PATH``\n  CMake variable, set to root directory of this package.\n``PATH``\n  Environment variable, set to bin directory of this package.\n``CMAKE_DISABLE_FIND_PACKAGE_pybind11``\n  CMake variable, disables ``find_package(pybind11)`` when not ``REQUIRED``,\n  perhaps to force internal build.\n\nCommands\n========\n\npybind11_add_module\n^^^^^^^^^^^^^^^^^^^\n\nThis module defines the following commands to assist with creating Python modules:\n\n.. code-block:: cmake\n\n  pybind11_add_module(<target>\n    [STATIC|SHARED|MODULE]\n    [THIN_LTO] [OPT_SIZE] [NO_EXTRAS] [WITHOUT_SOABI]\n    <files>...\n    )\n\nAdd a module and setup all helpers. You can select the type of the library; the\ndefault is ``MODULE``. There are several options:\n\n``OPT_SIZE``\n  Optimize for size, even if the ``CMAKE_BUILD_TYPE`` is not ``MinSizeRel``.\n``THIN_LTO``\n  Use thin LTO instead of regular if there's a choice (pybind11's selection\n  is disabled if ``CMAKE_INTERPROCEDURAL_OPTIMIZATIONS`` is set).\n``WITHOUT_SOABI``\n  Disable the SOABI component (``PYBIND11_NEWPYTHON`` mode only).\n``NO_EXTRAS``\n  Disable all extras, exit immediately after making the module.\n\npybind11_strip\n^^^^^^^^^^^^^^\n\n.. code-block:: cmake\n\n  pybind11_strip(<target>)\n\nStrip a target after building it (linux/macOS), called by ``pybind11_add_module``.\n\npybind11_extension\n^^^^^^^^^^^^^^^^^^\n\n.. code-block:: cmake\n\n    pybind11_extension(<target>)\n\nSets the Python extension name correctly for Python on your platform, called by\n``pybind11_add_module``.\n\npybind11_find_import(module)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: cmake\n\n    pybind11_find_import(<module> [VERSION <number>] [REQUIRED] [QUIET])\n\nSee if a module is installed. Use the registered name (the one on PyPI). You\ncan specify a ``VERSION``, and you can specify ``REQUIRED`` or ``QUIET``. Only available if\n``NOPYTHON`` mode is not active.  Sets ``module_VERSION`` and ``module_FOUND``. Caches the\nresult once a valid install is found.\n\nSuggested usage\n===============\n\nUsing ``find_package`` with version info is not recommended except for release versions.\n\n.. code-block:: cmake\n\n  find_package(pybind11 CONFIG)\n  find_package(pybind11 2.9 EXACT CONFIG REQUIRED)\n\n#]=============================================================================]\n@PACKAGE_INIT@\n\n# Location of pybind11/pybind11.h\n# This will be relative unless explicitly set as absolute\nset(pybind11_INCLUDE_DIR \"@pybind11_INCLUDEDIR@\")\n\nset(pybind11_LIBRARY \"\")\nset(pybind11_DEFINITIONS USING_pybind11)\nset(pybind11_VERSION_TYPE \"@pybind11_VERSION_TYPE@\")\n\ncheck_required_components(pybind11)\n\nif(TARGET pybind11::python_link_helper)\n  # This has already been setup elsewhere, such as with a previous call or\n  # add_subdirectory\n  return()\nendif()\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/pybind11Targets.cmake\")\n\n# Easier to use / remember\nadd_library(pybind11::headers IMPORTED INTERFACE)\nset_target_properties(pybind11::headers PROPERTIES INTERFACE_LINK_LIBRARIES\n                                                   pybind11::pybind11_headers)\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/pybind11Common.cmake\")\n\nif(NOT pybind11_FIND_QUIETLY)\n  message(\n    STATUS\n      \"Found pybind11: ${pybind11_INCLUDE_DIR} (found version \\\"${pybind11_VERSION}${pybind11_VERSION_TYPE}\\\")\"\n  )\nendif()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pybind11NewTools.cmake",
    "content": "# tools/pybind11NewTools.cmake -- Build system for the pybind11 modules\n#\n# Copyright (c) 2020 Wenzel Jakob <wenzel@inf.ethz.ch> and Henry Schreiner\n#\n# All rights reserved. Use of this source code is governed by a\n# BSD-style license that can be found in the LICENSE file.\n\nif(CMAKE_VERSION VERSION_LESS 3.12)\n  message(FATAL_ERROR \"You cannot use the new FindPython module with CMake < 3.12\")\nendif()\n\ninclude_guard(DIRECTORY)\n\nget_property(\n  is_config\n  TARGET pybind11::headers\n  PROPERTY IMPORTED)\n\nif(pybind11_FIND_QUIETLY)\n  set(_pybind11_quiet QUIET)\nelse()\n  set(_pybind11_quiet \"\")\nendif()\n\nif(NOT Python_FOUND AND NOT Python3_FOUND)\n  if(NOT DEFINED Python_FIND_IMPLEMENTATIONS)\n    set(Python_FIND_IMPLEMENTATIONS CPython PyPy)\n  endif()\n\n  # GitHub Actions like activation\n  if(NOT DEFINED Python_ROOT_DIR AND DEFINED ENV{pythonLocation})\n    set(Python_ROOT_DIR \"$ENV{pythonLocation}\")\n  endif()\n\n  # Development.Module support (required for manylinux) started in 3.18\n  if(CMAKE_VERSION VERSION_LESS 3.18)\n    set(_pybind11_dev_component Development)\n  else()\n    set(_pybind11_dev_component Development.Module OPTIONAL_COMPONENTS Development.Embed)\n  endif()\n\n  # Callers need to be able to access Python_EXECUTABLE\n  set(_pybind11_global_keyword \"\")\n  if(NOT is_config AND NOT DEFINED Python_ARTIFACTS_INTERACTIVE)\n    set(Python_ARTIFACTS_INTERACTIVE TRUE)\n    if(NOT CMAKE_VERSION VERSION_LESS 3.24)\n      set(_pybind11_global_keyword \"GLOBAL\")\n    endif()\n  endif()\n\n  find_package(Python 3.6 REQUIRED COMPONENTS Interpreter ${_pybind11_dev_component}\n                                              ${_pybind11_quiet} ${_pybind11_global_keyword})\n\n  # If we are in submodule mode, export the Python targets to global targets.\n  # If this behavior is not desired, FindPython _before_ pybind11.\n  if(NOT is_config\n     AND Python_ARTIFACTS_INTERACTIVE\n     AND _pybind11_global_keyword STREQUAL \"\")\n    if(TARGET Python::Python)\n      set_property(TARGET Python::Python PROPERTY IMPORTED_GLOBAL TRUE)\n    endif()\n    set_property(TARGET Python::Interpreter PROPERTY IMPORTED_GLOBAL TRUE)\n    if(TARGET Python::Module)\n      set_property(TARGET Python::Module PROPERTY IMPORTED_GLOBAL TRUE)\n    endif()\n  endif()\n\n  # Explicitly export version for callers (including our own functions)\n  if(NOT is_config AND Python_ARTIFACTS_INTERACTIVE)\n    set(Python_VERSION\n        \"${Python_VERSION}\"\n        CACHE INTERNAL \"\")\n    set(Python_VERSION_MAJOR\n        \"${Python_VERSION_MAJOR}\"\n        CACHE INTERNAL \"\")\n    set(Python_VERSION_MINOR\n        \"${Python_VERSION_MINOR}\"\n        CACHE INTERNAL \"\")\n    set(Python_VERSION_PATCH\n        \"${Python_VERSION_PATCH}\"\n        CACHE INTERNAL \"\")\n  endif()\nendif()\n\nif(Python_FOUND)\n  set(_Python\n      Python\n      CACHE INTERNAL \"\" FORCE)\nelseif(Python3_FOUND)\n  set(_Python\n      Python3\n      CACHE INTERNAL \"\" FORCE)\nendif()\n\nif(PYBIND11_MASTER_PROJECT)\n  if(${_Python}_INTERPRETER_ID MATCHES \"PyPy\")\n    message(STATUS \"PyPy ${${_Python}_PyPy_VERSION} (Py ${${_Python}_VERSION})\")\n  else()\n    message(STATUS \"${_Python} ${${_Python}_VERSION}\")\n  endif()\nendif()\n\n# If a user finds Python, they may forget to include the Interpreter component\n# and the following two steps require it. It is highly recommended by CMake\n# when finding development libraries anyway, so we will require it.\nif(NOT DEFINED ${_Python}_EXECUTABLE)\n  message(\n    FATAL_ERROR\n      \"${_Python} was found without the Interpreter component. Pybind11 requires this component.\")\n\nendif()\n\nif(DEFINED PYBIND11_PYTHON_EXECUTABLE_LAST AND NOT ${_Python}_EXECUTABLE STREQUAL\n                                               PYBIND11_PYTHON_EXECUTABLE_LAST)\n  # Detect changes to the Python version/binary in subsequent CMake runs, and refresh config if needed\n  unset(PYTHON_IS_DEBUG CACHE)\n  unset(PYTHON_MODULE_EXTENSION CACHE)\nendif()\n\nset(PYBIND11_PYTHON_EXECUTABLE_LAST\n    \"${${_Python}_EXECUTABLE}\"\n    CACHE INTERNAL \"Python executable during the last CMake run\")\n\nif(NOT DEFINED PYTHON_IS_DEBUG)\n  # Debug check - see https://stackoverflow.com/questions/646518/python-how-to-detect-debug-Interpreter\n  execute_process(\n    COMMAND \"${${_Python}_EXECUTABLE}\" \"-c\"\n            \"import sys; sys.exit(hasattr(sys, 'gettotalrefcount'))\"\n    RESULT_VARIABLE _PYTHON_IS_DEBUG)\n  set(PYTHON_IS_DEBUG\n      \"${_PYTHON_IS_DEBUG}\"\n      CACHE INTERNAL \"Python debug status\")\nendif()\n\n# Get the suffix - SO is deprecated, should use EXT_SUFFIX, but this is\n# required for PyPy3 (as of 7.3.1)\nif(NOT DEFINED PYTHON_MODULE_EXTENSION OR NOT DEFINED PYTHON_MODULE_DEBUG_POSTFIX)\n  execute_process(\n    COMMAND\n      \"${${_Python}_EXECUTABLE}\" \"-c\"\n      \"import sys, importlib; s = importlib.import_module('distutils.sysconfig' if sys.version_info < (3, 10) else 'sysconfig'); print(s.get_config_var('EXT_SUFFIX') or s.get_config_var('SO'))\"\n    OUTPUT_VARIABLE _PYTHON_MODULE_EXT_SUFFIX\n    ERROR_VARIABLE _PYTHON_MODULE_EXT_SUFFIX_ERR\n    OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n  if(_PYTHON_MODULE_EXT_SUFFIX STREQUAL \"\")\n    message(\n      FATAL_ERROR \"pybind11 could not query the module file extension, likely the 'distutils'\"\n                  \"package is not installed. Full error message:\\n${_PYTHON_MODULE_EXT_SUFFIX_ERR}\"\n    )\n  endif()\n\n  # This needs to be available for the pybind11_extension function\n  if(NOT DEFINED PYTHON_MODULE_DEBUG_POSTFIX)\n    get_filename_component(_PYTHON_MODULE_DEBUG_POSTFIX \"${_PYTHON_MODULE_EXT_SUFFIX}\" NAME_WE)\n    set(PYTHON_MODULE_DEBUG_POSTFIX\n        \"${_PYTHON_MODULE_DEBUG_POSTFIX}\"\n        CACHE INTERNAL \"\")\n  endif()\n\n  if(NOT DEFINED PYTHON_MODULE_EXTENSION)\n    get_filename_component(_PYTHON_MODULE_EXTENSION \"${_PYTHON_MODULE_EXT_SUFFIX}\" EXT)\n    set(PYTHON_MODULE_EXTENSION\n        \"${_PYTHON_MODULE_EXTENSION}\"\n        CACHE INTERNAL \"\")\n  endif()\nendif()\n\n# Python debug libraries expose slightly different objects before 3.8\n# https://docs.python.org/3.6/c-api/intro.html#debugging-builds\n# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib\nif(PYTHON_IS_DEBUG)\n  set_property(\n    TARGET pybind11::pybind11\n    APPEND\n    PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)\nendif()\n\n# Check on every access - since Python can change - do nothing in that case.\n\nif(DEFINED ${_Python}_INCLUDE_DIRS)\n  # Only add Python for build - must be added during the import for config\n  # since it has to be re-discovered.\n  #\n  # This needs to be a target to be included after the local pybind11\n  # directory, just in case there there is an installed pybind11 sitting\n  # next to Python's includes. It also ensures Python is a SYSTEM library.\n  add_library(pybind11::python_headers INTERFACE IMPORTED)\n  set_property(\n    TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES\n                                             \"$<BUILD_INTERFACE:${${_Python}_INCLUDE_DIRS}>\")\n  set_property(\n    TARGET pybind11::pybind11\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers)\n  set(pybind11_INCLUDE_DIRS\n      \"${pybind11_INCLUDE_DIR}\" \"${${_Python}_INCLUDE_DIRS}\"\n      CACHE INTERNAL \"Directories where pybind11 and possibly Python headers are located\")\nendif()\n\n# In CMake 3.18+, you can find these separately, so include an if\nif(TARGET ${_Python}::Python)\n  set_property(\n    TARGET pybind11::embed\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Python)\nendif()\n\n# CMake 3.15+ has this\nif(TARGET ${_Python}::Module)\n  set_property(\n    TARGET pybind11::module\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES ${_Python}::Module)\nelse()\n  set_property(\n    TARGET pybind11::module\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_link_helper)\nendif()\n\n# WITHOUT_SOABI and WITH_SOABI will disable the custom extension handling used by pybind11.\n# WITH_SOABI is passed on to python_add_library.\nfunction(pybind11_add_module target_name)\n  cmake_parse_arguments(PARSE_ARGV 1 ARG\n                        \"STATIC;SHARED;MODULE;THIN_LTO;OPT_SIZE;NO_EXTRAS;WITHOUT_SOABI\" \"\" \"\")\n\n  if(ARG_STATIC)\n    set(lib_type STATIC)\n  elseif(ARG_SHARED)\n    set(lib_type SHARED)\n  else()\n    set(lib_type MODULE)\n  endif()\n\n  if(\"${_Python}\" STREQUAL \"Python\")\n    python_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})\n  elseif(\"${_Python}\" STREQUAL \"Python3\")\n    python3_add_library(${target_name} ${lib_type} ${ARG_UNPARSED_ARGUMENTS})\n  else()\n    message(FATAL_ERROR \"Cannot detect FindPython version: ${_Python}\")\n  endif()\n\n  target_link_libraries(${target_name} PRIVATE pybind11::headers)\n\n  if(lib_type STREQUAL \"MODULE\")\n    target_link_libraries(${target_name} PRIVATE pybind11::module)\n  else()\n    target_link_libraries(${target_name} PRIVATE pybind11::embed)\n  endif()\n\n  if(MSVC)\n    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)\n  endif()\n\n  # -fvisibility=hidden is required to allow multiple modules compiled against\n  # different pybind versions to work properly, and for some features (e.g.\n  # py::module_local).  We force it on everything inside the `pybind11`\n  # namespace; also turning it on for a pybind module compilation here avoids\n  # potential warnings or issues from having mixed hidden/non-hidden types.\n  if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)\n    set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET \"hidden\")\n  endif()\n\n  if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET)\n    set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET \"hidden\")\n  endif()\n\n  # If we don't pass a WITH_SOABI or WITHOUT_SOABI, use our own default handling of extensions\n  if(NOT ARG_WITHOUT_SOABI AND NOT \"WITH_SOABI\" IN_LIST ARG_UNPARSED_ARGUMENTS)\n    pybind11_extension(${target_name})\n  endif()\n\n  if(ARG_NO_EXTRAS)\n    return()\n  endif()\n\n  if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)\n    if(ARG_THIN_LTO)\n      target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)\n    else()\n      target_link_libraries(${target_name} PRIVATE pybind11::lto)\n    endif()\n  endif()\n\n  if(DEFINED CMAKE_BUILD_TYPE) # see https://github.com/pybind/pybind11/issues/4454\n    # Use case-insensitive comparison to match the result of $<CONFIG:cfgs>\n    string(TOUPPER \"${CMAKE_BUILD_TYPE}\" uppercase_CMAKE_BUILD_TYPE)\n    if(NOT MSVC AND NOT \"${uppercase_CMAKE_BUILD_TYPE}\" MATCHES DEBUG|RELWITHDEBINFO)\n      # Strip unnecessary sections of the binary on Linux/macOS\n      pybind11_strip(${target_name})\n    endif()\n  endif()\n\n  if(MSVC)\n    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)\n  endif()\n\n  if(ARG_OPT_SIZE)\n    target_link_libraries(${target_name} PRIVATE pybind11::opt_size)\n  endif()\nendfunction()\n\nfunction(pybind11_extension name)\n  # The extension is precomputed\n  set_target_properties(\n    ${name}\n    PROPERTIES PREFIX \"\"\n               DEBUG_POSTFIX \"${PYTHON_MODULE_DEBUG_POSTFIX}\"\n               SUFFIX \"${PYTHON_MODULE_EXTENSION}\")\nendfunction()\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pybind11Tools.cmake",
    "content": "# tools/pybind11Tools.cmake -- Build system for the pybind11 modules\n#\n# Copyright (c) 2020 Wenzel Jakob <wenzel.jakob@epfl.ch>\n#\n# All rights reserved. Use of this source code is governed by a\n# BSD-style license that can be found in the LICENSE file.\n\n# include_guard(global) (pre-CMake 3.10)\nif(TARGET pybind11::python_headers)\n  return()\nendif()\n\n# Built-in in CMake 3.5+\ninclude(CMakeParseArguments)\n\nif(pybind11_FIND_QUIETLY)\n  set(_pybind11_quiet QUIET)\nelse()\n  set(_pybind11_quiet \"\")\nendif()\n\n# If this is the first run, PYTHON_VERSION can stand in for PYBIND11_PYTHON_VERSION\nif(NOT DEFINED PYBIND11_PYTHON_VERSION AND DEFINED PYTHON_VERSION)\n  message(WARNING \"Set PYBIND11_PYTHON_VERSION to search for a specific version, not \"\n                  \"PYTHON_VERSION (which is an output). Assuming that is what you \"\n                  \"meant to do and continuing anyway.\")\n  set(PYBIND11_PYTHON_VERSION\n      \"${PYTHON_VERSION}\"\n      CACHE STRING \"Python version to use for compiling modules\")\n  unset(PYTHON_VERSION)\n  unset(PYTHON_VERSION CACHE)\nelseif(DEFINED PYBIND11_PYTHON_VERSION)\n  # If this is set as a normal variable, promote it\n  set(PYBIND11_PYTHON_VERSION\n      \"${PYBIND11_PYTHON_VERSION}\"\n      CACHE STRING \"Python version to use for compiling modules\")\nelse()\n  # Make an empty cache variable.\n  set(PYBIND11_PYTHON_VERSION\n      \"\"\n      CACHE STRING \"Python version to use for compiling modules\")\nendif()\n\n# A user can set versions manually too\nset(Python_ADDITIONAL_VERSIONS\n    \"3.12;3.11;3.10;3.9;3.8;3.7;3.6\"\n    CACHE INTERNAL \"\")\n\nlist(APPEND CMAKE_MODULE_PATH \"${CMAKE_CURRENT_LIST_DIR}\")\nfind_package(PythonLibsNew ${PYBIND11_PYTHON_VERSION} MODULE REQUIRED ${_pybind11_quiet})\nlist(REMOVE_AT CMAKE_MODULE_PATH -1)\n\n# Makes a normal variable a cached variable\nmacro(_PYBIND11_PROMOTE_TO_CACHE NAME)\n  set(_tmp_ptc \"${${NAME}}\")\n  # CMake 3.21 complains if a cached variable is shadowed by a normal one\n  unset(${NAME})\n  set(${NAME}\n      \"${_tmp_ptc}\"\n      CACHE INTERNAL \"\")\nendmacro()\n\n# Cache variables so pybind11_add_module can be used in parent projects\n_pybind11_promote_to_cache(PYTHON_INCLUDE_DIRS)\n_pybind11_promote_to_cache(PYTHON_LIBRARIES)\n_pybind11_promote_to_cache(PYTHON_MODULE_PREFIX)\n_pybind11_promote_to_cache(PYTHON_MODULE_EXTENSION)\n_pybind11_promote_to_cache(PYTHON_MODULE_DEBUG_POSTFIX)\n_pybind11_promote_to_cache(PYTHON_VERSION_MAJOR)\n_pybind11_promote_to_cache(PYTHON_VERSION_MINOR)\n_pybind11_promote_to_cache(PYTHON_VERSION)\n_pybind11_promote_to_cache(PYTHON_IS_DEBUG)\n\nif(PYBIND11_MASTER_PROJECT)\n  if(PYTHON_MODULE_EXTENSION MATCHES \"pypy\")\n    if(NOT DEFINED PYPY_VERSION)\n      execute_process(\n        COMMAND ${PYTHON_EXECUTABLE} -c\n                [=[import sys; sys.stdout.write(\".\".join(map(str, sys.pypy_version_info[:3])))]=]\n        OUTPUT_VARIABLE pypy_version)\n      set(PYPY_VERSION\n          ${pypy_version}\n          CACHE INTERNAL \"\")\n    endif()\n    message(STATUS \"PYPY ${PYPY_VERSION} (Py ${PYTHON_VERSION})\")\n  else()\n    message(STATUS \"PYTHON ${PYTHON_VERSION}\")\n  endif()\nendif()\n\n# Only add Python for build - must be added during the import for config since\n# it has to be re-discovered.\n#\n# This needs to be an target to it is included after the local pybind11\n# directory, just in case there are multiple versions of pybind11, we want the\n# one we expect.\nadd_library(pybind11::python_headers INTERFACE IMPORTED)\nset_property(TARGET pybind11::python_headers PROPERTY INTERFACE_INCLUDE_DIRECTORIES\n                                                      \"$<BUILD_INTERFACE:${PYTHON_INCLUDE_DIRS}>\")\nset_property(\n  TARGET pybind11::pybind11\n  APPEND\n  PROPERTY INTERFACE_LINK_LIBRARIES pybind11::python_headers)\n\nset(pybind11_INCLUDE_DIRS\n    \"${pybind11_INCLUDE_DIR}\" \"${PYTHON_INCLUDE_DIRS}\"\n    CACHE INTERNAL \"Directories where pybind11 and possibly Python headers are located\")\n\n# Python debug libraries expose slightly different objects before 3.8\n# https://docs.python.org/3.6/c-api/intro.html#debugging-builds\n# https://stackoverflow.com/questions/39161202/how-to-work-around-missing-pymodule-create2-in-amd64-win-python35-d-lib\nif(PYTHON_IS_DEBUG)\n  set_property(\n    TARGET pybind11::pybind11\n    APPEND\n    PROPERTY INTERFACE_COMPILE_DEFINITIONS Py_DEBUG)\nendif()\n\n# The <3.11 code here does not support release/debug builds at the same time, like on vcpkg\nif(CMAKE_VERSION VERSION_LESS 3.11)\n  set_property(\n    TARGET pybind11::module\n    APPEND\n    PROPERTY\n      INTERFACE_LINK_LIBRARIES\n      pybind11::python_link_helper\n      \"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:$<BUILD_INTERFACE:${PYTHON_LIBRARIES}>>\"\n  )\n\n  set_property(\n    TARGET pybind11::embed\n    APPEND\n    PROPERTY INTERFACE_LINK_LIBRARIES pybind11::pybind11 $<BUILD_INTERFACE:${PYTHON_LIBRARIES}>)\nelse()\n  # The IMPORTED INTERFACE library here is to ensure that \"debug\" and \"release\" get processed outside\n  # of a generator expression - https://gitlab.kitware.com/cmake/cmake/-/issues/18424, as they are\n  # target_link_library keywords rather than real libraries.\n  add_library(pybind11::_ClassicPythonLibraries IMPORTED INTERFACE)\n  target_link_libraries(pybind11::_ClassicPythonLibraries INTERFACE ${PYTHON_LIBRARIES})\n  target_link_libraries(\n    pybind11::module\n    INTERFACE\n      pybind11::python_link_helper\n      \"$<$<OR:$<PLATFORM_ID:Windows>,$<PLATFORM_ID:Cygwin>>:pybind11::_ClassicPythonLibraries>\")\n\n  target_link_libraries(pybind11::embed INTERFACE pybind11::pybind11\n                                                  pybind11::_ClassicPythonLibraries)\nendif()\n\nfunction(pybind11_extension name)\n  # The prefix and extension are provided by FindPythonLibsNew.cmake\n  set_target_properties(\n    ${name}\n    PROPERTIES PREFIX \"${PYTHON_MODULE_PREFIX}\"\n               DEBUG_POSTFIX \"${PYTHON_MODULE_DEBUG_POSTFIX}\"\n               SUFFIX \"${PYTHON_MODULE_EXTENSION}\")\nendfunction()\n\n# Build a Python extension module:\n# pybind11_add_module(<name> [MODULE | SHARED] [EXCLUDE_FROM_ALL]\n#                     [NO_EXTRAS] [THIN_LTO] [OPT_SIZE] source1 [source2 ...])\n#\nfunction(pybind11_add_module target_name)\n  set(options \"MODULE;SHARED;EXCLUDE_FROM_ALL;NO_EXTRAS;SYSTEM;THIN_LTO;OPT_SIZE\")\n  cmake_parse_arguments(ARG \"${options}\" \"\" \"\" ${ARGN})\n\n  if(ARG_MODULE AND ARG_SHARED)\n    message(FATAL_ERROR \"Can't be both MODULE and SHARED\")\n  elseif(ARG_SHARED)\n    set(lib_type SHARED)\n  else()\n    set(lib_type MODULE)\n  endif()\n\n  if(ARG_EXCLUDE_FROM_ALL)\n    set(exclude_from_all EXCLUDE_FROM_ALL)\n  else()\n    set(exclude_from_all \"\")\n  endif()\n\n  add_library(${target_name} ${lib_type} ${exclude_from_all} ${ARG_UNPARSED_ARGUMENTS})\n\n  target_link_libraries(${target_name} PRIVATE pybind11::module)\n\n  if(ARG_SYSTEM)\n    message(\n      STATUS\n        \"Warning: this does not have an effect - use NO_SYSTEM_FROM_IMPORTED if using imported targets\"\n    )\n  endif()\n\n  pybind11_extension(${target_name})\n\n  # -fvisibility=hidden is required to allow multiple modules compiled against\n  # different pybind versions to work properly, and for some features (e.g.\n  # py::module_local).  We force it on everything inside the `pybind11`\n  # namespace; also turning it on for a pybind module compilation here avoids\n  # potential warnings or issues from having mixed hidden/non-hidden types.\n  if(NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)\n    set_target_properties(${target_name} PROPERTIES CXX_VISIBILITY_PRESET \"hidden\")\n  endif()\n\n  if(NOT DEFINED CMAKE_CUDA_VISIBILITY_PRESET)\n    set_target_properties(${target_name} PROPERTIES CUDA_VISIBILITY_PRESET \"hidden\")\n  endif()\n\n  if(ARG_NO_EXTRAS)\n    return()\n  endif()\n\n  if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)\n    if(ARG_THIN_LTO)\n      target_link_libraries(${target_name} PRIVATE pybind11::thin_lto)\n    else()\n      target_link_libraries(${target_name} PRIVATE pybind11::lto)\n    endif()\n  endif()\n\n  if(DEFINED CMAKE_BUILD_TYPE) # see https://github.com/pybind/pybind11/issues/4454\n    # Use case-insensitive comparison to match the result of $<CONFIG:cfgs>\n    string(TOUPPER \"${CMAKE_BUILD_TYPE}\" uppercase_CMAKE_BUILD_TYPE)\n    if(NOT MSVC AND NOT \"${uppercase_CMAKE_BUILD_TYPE}\" MATCHES DEBUG|RELWITHDEBINFO)\n      pybind11_strip(${target_name})\n    endif()\n  endif()\n\n  if(MSVC)\n    target_link_libraries(${target_name} PRIVATE pybind11::windows_extras)\n  endif()\n\n  if(ARG_OPT_SIZE)\n    target_link_libraries(${target_name} PRIVATE pybind11::opt_size)\n  endif()\nendfunction()\n\n# Provide general way to call common Python commands in \"common\" file.\nset(_Python\n    PYTHON\n    CACHE INTERNAL \"\" FORCE)\n"
  },
  {
    "path": "dlib/external/pybind11/tools/pyproject.toml",
    "content": "[build-system]\nrequires = [\"setuptools>=42\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\"\n"
  },
  {
    "path": "dlib/external/pybind11/tools/setup_global.py.in",
    "content": "#!/usr/bin/env python3\n\n# Setup script for pybind11-global (in the sdist or in tools/setup_global.py in the repository)\n# This package is targeted for easy use from CMake.\n\nimport glob\nimport os\nimport re\n\n# Setuptools has to be before distutils\nfrom setuptools import setup\n\nfrom distutils.command.install_headers import install_headers\n\nclass InstallHeadersNested(install_headers):\n    def run(self):\n        headers = self.distribution.headers or []\n        for header in headers:\n            # Remove pybind11/include/\n            short_header = header.split(\"/\", 2)[-1]\n\n            dst = os.path.join(self.install_dir, os.path.dirname(short_header))\n            self.mkpath(dst)\n            (out, _) = self.copy_file(header, dst)\n            self.outfiles.append(out)\n\n\nmain_headers = glob.glob(\"pybind11/include/pybind11/*.h\")\ndetail_headers = glob.glob(\"pybind11/include/pybind11/detail/*.h\")\neigen_headers = glob.glob(\"pybind11/include/pybind11/eigen/*.h\")\nstl_headers = glob.glob(\"pybind11/include/pybind11/stl/*.h\")\ncmake_files = glob.glob(\"pybind11/share/cmake/pybind11/*.cmake\")\npkgconfig_files = glob.glob(\"pybind11/share/pkgconfig/*.pc\")\nheaders = main_headers + detail_headers + stl_headers + eigen_headers\n\ncmdclass = {\"install_headers\": InstallHeadersNested}\n$extra_cmd\n\n# This will _not_ affect installing from wheels,\n# only building wheels or installing from SDist.\n# Primarily intended on Windows, where this is sometimes\n# customized (for example, conda-forge uses Library/)\nbase = os.environ.get(\"PYBIND11_GLOBAL_PREFIX\", \"\")\n\n# Must have a separator\nif base and not base.endswith(\"/\"):\n    base += \"/\"\n\nsetup(\n    name=\"pybind11_global\",\n    version=\"$version\",\n    packages=[],\n    headers=headers,\n    data_files=[\n        (base + \"share/cmake/pybind11\", cmake_files),\n        (base + \"share/pkgconfig\", pkgconfig_files),\n        (base + \"include/pybind11\", main_headers),\n        (base + \"include/pybind11/detail\", detail_headers),\n        (base + \"include/pybind11/eigen\", eigen_headers),\n        (base + \"include/pybind11/stl\", stl_headers),\n    ],\n    cmdclass=cmdclass,\n)\n"
  },
  {
    "path": "dlib/external/pybind11/tools/setup_main.py.in",
    "content": "#!/usr/bin/env python3\n\n# Setup script (in the sdist or in tools/setup_main.py in the repository)\n\nfrom setuptools import setup\n\ncmdclass = {}\n$extra_cmd\n\nsetup(\n    name=\"pybind11\",\n    version=\"$version\",\n    download_url='https://github.com/pybind/pybind11/tarball/v$version',\n    packages=[\n        \"pybind11\",\n        \"pybind11.include.pybind11\",\n        \"pybind11.include.pybind11.detail\",\n        \"pybind11.include.pybind11.eigen\",\n        \"pybind11.include.pybind11.stl\",\n        \"pybind11.share.cmake.pybind11\",\n        \"pybind11.share.pkgconfig\",\n    ],\n    package_data={\n        \"pybind11\": [\"py.typed\"],\n        \"pybind11.include.pybind11\": [\"*.h\"],\n        \"pybind11.include.pybind11.detail\": [\"*.h\"],\n        \"pybind11.include.pybind11.eigen\": [\"*.h\"],\n        \"pybind11.include.pybind11.stl\": [\"*.h\"],\n        \"pybind11.share.cmake.pybind11\": [\"*.cmake\"],\n        \"pybind11.share.pkgconfig\": [\"*.pc\"],\n    },\n    extras_require={\n        \"global\": [\"pybind11_global==$version\"]\n        },\n    entry_points={\n        \"console_scripts\": [\n             \"pybind11-config = pybind11.__main__:main\",\n        ],\n        \"pipx.run\": [\n             \"pybind11 = pybind11.__main__:main\",\n        ]\n    },\n    cmdclass=cmdclass\n)\n"
  },
  {
    "path": "dlib/external/zlib/README",
    "content": "ZLIB DATA COMPRESSION LIBRARY\n\nzlib 1.2.11 is a general purpose data compression library.  All the code is\nthread safe.  The data format used by the zlib library is described by RFCs\n(Request for Comments) 1950 to 1952 in the files\nhttp://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and\nrfc1952 (gzip format).\n\nAll functions of the compression library are documented in the file zlib.h\n(volunteer to write man pages welcome, contact zlib@gzip.org).  A usage example\nof the library is given in the file test/example.c which also tests that\nthe library is working correctly.  Another example is given in the file\ntest/minigzip.c.  The compression library itself is composed of all source\nfiles in the root directory.\n\nTo compile all files and run the test program, follow the instructions given at\nthe top of Makefile.in.  In short \"./configure; make test\", and if that goes\nwell, \"make install\" should work for most flavors of Unix.  For Windows, use\none of the special makefiles in win32/ or contrib/vstudio/ .  For VMS, use\nmake_vms.com.\n\nQuestions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant\n<info@winimage.com> for the Windows DLL version.  The zlib home page is\nhttp://zlib.net/ .  Before reporting a problem, please check this site to\nverify that you have the latest version of zlib; otherwise get the latest\nversion and check whether the problem still exists or not.\n\nPLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.\n\nMark Nelson <markn@ieee.org> wrote an article about zlib for the Jan.  1997\nissue of Dr.  Dobb's Journal; a copy of the article is available at\nhttp://marknelson.us/1997/01/01/zlib-engine/ .\n\nThe changes made in version 1.2.11 are documented in the file ChangeLog.\n\nUnsupported third party contributions are provided in directory contrib/ .\n\nzlib is available in Java using the java.util.zip package, documented at\nhttp://java.sun.com/developer/technicalArticles/Programming/compression/ .\n\nA Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available\nat CPAN (Comprehensive Perl Archive Network) sites, including\nhttp://search.cpan.org/~pmqs/IO-Compress-Zlib/ .\n\nA Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is\navailable in Python 1.5 and later versions, see\nhttp://docs.python.org/library/zlib.html .\n\nzlib is built into tcl: http://wiki.tcl.tk/4610 .\n\nAn experimental package to read and write files in .zip format, written on top\nof zlib by Gilles Vollant <info@winimage.com>, is available in the\ncontrib/minizip directory of zlib.\n\n\nNotes for some targets:\n\n- For Windows DLL versions, please see win32/DLL_FAQ.txt\n\n- For 64-bit Irix, deflate.c must be compiled without any optimization. With\n  -O, one libpng test fails. The test works in 32 bit mode (with the -n32\n  compiler flag). The compiler bug has been reported to SGI.\n\n- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works\n  when compiled with cc.\n\n- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is\n  necessary to get gzprintf working correctly. This is done by configure.\n\n- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with\n  other compilers. Use \"make test\" to check your compiler.\n\n- gzdopen is not supported on RISCOS or BEOS.\n\n- For PalmOs, see http://palmzlib.sourceforge.net/\n\n\nAcknowledgments:\n\n  The deflate format used by zlib was defined by Phil Katz.  The deflate and\n  zlib specifications were written by L.  Peter Deutsch.  Thanks to all the\n  people who reported problems and suggested various improvements in zlib; they\n  are too numerous to cite here.\n\nCopyright notice:\n\n (C) 1995-2017 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\nIf you use the zlib library in a product, we would appreciate *not* receiving\nlengthy legal documents to sign.  The sources are provided for free but without\nwarranty of any kind.  The library has been entirely written by Jean-loup\nGailly and Mark Adler; it does not include third-party code.\n\nIf you redistribute modified sources, we would appreciate that you include in\nthe file ChangeLog history information documenting your changes.  Please read\nthe FAQ for more information on the distribution of modified source versions.\n"
  },
  {
    "path": "dlib/external/zlib/adler32.c",
    "content": "/* adler32.c -- compute the Adler-32 checksum of a data stream\n * Copyright (C) 1995-2011, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n\nlocal uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));\n\n#define BASE 65521U     /* largest prime smaller than 65536 */\n#define NMAX 5552\n/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */\n\n#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}\n#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);\n#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);\n#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);\n#define DO16(buf)   DO8(buf,0); DO8(buf,8);\n\n/* use NO_DIVIDE if your processor does not do division in hardware --\n   try it both ways to see which is faster */\n#ifdef NO_DIVIDE\n/* note that this assumes BASE is 65521, where 65536 % 65521 == 15\n   (thank you to John Reiser for pointing this out) */\n#  define CHOP(a) \\\n    do { \\\n        unsigned long tmp = a >> 16; \\\n        a &= 0xffffUL; \\\n        a += (tmp << 4) - tmp; \\\n    } while (0)\n#  define MOD28(a) \\\n    do { \\\n        CHOP(a); \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#  define MOD(a) \\\n    do { \\\n        CHOP(a); \\\n        MOD28(a); \\\n    } while (0)\n#  define MOD63(a) \\\n    do { /* this assumes a is not negative */ \\\n        z_off64_t tmp = a >> 32; \\\n        a &= 0xffffffffL; \\\n        a += (tmp << 8) - (tmp << 5) + tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        tmp = a >> 16; \\\n        a &= 0xffffL; \\\n        a += (tmp << 4) - tmp; \\\n        if (a >= BASE) a -= BASE; \\\n    } while (0)\n#else\n#  define MOD(a) a %= BASE\n#  define MOD28(a) a %= BASE\n#  define MOD63(a) a %= BASE\n#endif\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_z(adler, buf, len)\n    uLong adler;\n    const Bytef *buf;\n    z_size_t len;\n{\n    unsigned long sum2;\n    unsigned n;\n\n    /* split Adler-32 into component sums */\n    sum2 = (adler >> 16) & 0xffff;\n    adler &= 0xffff;\n\n    /* in case user likes doing a byte at a time, keep it fast */\n    if (len == 1) {\n        adler += buf[0];\n        if (adler >= BASE)\n            adler -= BASE;\n        sum2 += adler;\n        if (sum2 >= BASE)\n            sum2 -= BASE;\n        return adler | (sum2 << 16);\n    }\n\n    /* initial Adler-32 value (deferred check for len == 1 speed) */\n    if (buf == Z_NULL)\n        return 1L;\n\n    /* in case short lengths are provided, keep it somewhat fast */\n    if (len < 16) {\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        if (adler >= BASE)\n            adler -= BASE;\n        MOD28(sum2);            /* only added so many BASE's */\n        return adler | (sum2 << 16);\n    }\n\n    /* do length NMAX blocks -- requires just one modulo operation */\n    while (len >= NMAX) {\n        len -= NMAX;\n        n = NMAX / 16;          /* NMAX is divisible by 16 */\n        do {\n            DO16(buf);          /* 16 sums unrolled */\n            buf += 16;\n        } while (--n);\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* do remaining bytes (less than NMAX, still just one modulo) */\n    if (len) {                  /* avoid modulos if none remaining */\n        while (len >= 16) {\n            len -= 16;\n            DO16(buf);\n            buf += 16;\n        }\n        while (len--) {\n            adler += *buf++;\n            sum2 += adler;\n        }\n        MOD(adler);\n        MOD(sum2);\n    }\n\n    /* return recombined sums */\n    return adler | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32(adler, buf, len)\n    uLong adler;\n    const Bytef *buf;\n    uInt len;\n{\n    return adler32_z(adler, buf, len);\n}\n\n/* ========================================================================= */\nlocal uLong adler32_combine_(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off64_t len2;\n{\n    unsigned long sum1;\n    unsigned long sum2;\n    unsigned rem;\n\n    /* for negative len, return invalid adler32 as a clue for debugging */\n    if (len2 < 0)\n        return 0xffffffffUL;\n\n    /* the derivation of this formula is left as an exercise for the reader */\n    MOD63(len2);                /* assumes len2 >= 0 */\n    rem = (unsigned)len2;\n    sum1 = adler1 & 0xffff;\n    sum2 = rem * sum1;\n    MOD(sum2);\n    sum1 += (adler2 & 0xffff) + BASE - 1;\n    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum1 >= BASE) sum1 -= BASE;\n    if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);\n    if (sum2 >= BASE) sum2 -= BASE;\n    return sum1 | (sum2 << 16);\n}\n\n/* ========================================================================= */\nuLong ZEXPORT adler32_combine(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off_t len2;\n{\n    return adler32_combine_(adler1, adler2, len2);\n}\n\nuLong ZEXPORT adler32_combine64(adler1, adler2, len2)\n    uLong adler1;\n    uLong adler2;\n    z_off64_t len2;\n{\n    return adler32_combine_(adler1, adler2, len2);\n}\n"
  },
  {
    "path": "dlib/external/zlib/compress.c",
    "content": "/* compress.c -- compress a memory buffer\n * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#define ZLIB_INTERNAL\n#include \"zlib.h\"\n\n/* ===========================================================================\n     Compresses the source buffer into the destination buffer. The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer. Upon entry, destLen is the total size of the\n   destination buffer, which must be at least 0.1% larger than sourceLen plus\n   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\nint ZEXPORT compress2 (dest, destLen, source, sourceLen, level)\n    Bytef *dest;\n    uLongf *destLen;\n    const Bytef *source;\n    uLong sourceLen;\n    int level;\n{\n    z_stream stream;\n    int err;\n    const uInt max = (uInt)-1;\n    uLong left;\n\n    left = *destLen;\n    *destLen = 0;\n\n    stream.zalloc = (alloc_func)0;\n    stream.zfree = (free_func)0;\n    stream.opaque = (voidpf)0;\n\n    err = deflateInit(&stream, level);\n    if (err != Z_OK) return err;\n\n    stream.next_out = dest;\n    stream.avail_out = 0;\n    stream.next_in = (z_const Bytef *)source;\n    stream.avail_in = 0;\n\n    do {\n        if (stream.avail_out == 0) {\n            stream.avail_out = left > (uLong)max ? max : (uInt)left;\n            left -= stream.avail_out;\n        }\n        if (stream.avail_in == 0) {\n            stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;\n            sourceLen -= stream.avail_in;\n        }\n        err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);\n    } while (err == Z_OK);\n\n    *destLen = stream.total_out;\n    deflateEnd(&stream);\n    return err == Z_STREAM_END ? Z_OK : err;\n}\n\n/* ===========================================================================\n */\nint ZEXPORT compress (dest, destLen, source, sourceLen)\n    Bytef *dest;\n    uLongf *destLen;\n    const Bytef *source;\n    uLong sourceLen;\n{\n    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);\n}\n\n/* ===========================================================================\n     If the default memLevel or windowBits for deflateInit() is changed, then\n   this function needs to be updated.\n */\nuLong ZEXPORT compressBound (sourceLen)\n    uLong sourceLen;\n{\n    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +\n           (sourceLen >> 25) + 13;\n}\n"
  },
  {
    "path": "dlib/external/zlib/crc32.c",
    "content": "/* crc32.c -- compute the CRC-32 of a data stream\n * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n *\n * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster\n * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing\n * tables for updating the shift register in one step with three exclusive-ors\n * instead of four steps with four exclusive-ors.  This results in about a\n * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.\n */\n\n/* @(#) $Id$ */\n\n/*\n  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore\n  protection on the static variables used to control the first-use generation\n  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should\n  first call get_crc_table() to initialize the tables before allowing more than\n  one thread to use crc32().\n\n  DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.\n */\n\n#ifdef MAKECRCH\n#  include <stdio.h>\n#  ifndef DYNAMIC_CRC_TABLE\n#    define DYNAMIC_CRC_TABLE\n#  endif /* !DYNAMIC_CRC_TABLE */\n#endif /* MAKECRCH */\n\n#include \"zutil.h\"      /* for STDC and FAR definitions */\n\n/* Definitions for doing the crc four data bytes at a time. */\n#if !defined(NOBYFOUR) && defined(Z_U4)\n#  define BYFOUR\n#endif\n#ifdef BYFOUR\n   local unsigned long crc32_little OF((unsigned long,\n                        const unsigned char FAR *, z_size_t));\n   local unsigned long crc32_big OF((unsigned long,\n                        const unsigned char FAR *, z_size_t));\n#  define TBLS 8\n#else\n#  define TBLS 1\n#endif /* BYFOUR */\n\n/* Local functions for crc concatenation */\nlocal unsigned long gf2_matrix_times OF((unsigned long *mat,\n                                         unsigned long vec));\nlocal void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));\nlocal uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));\n\n\n#ifdef DYNAMIC_CRC_TABLE\n\nlocal volatile int crc_table_empty = 1;\nlocal z_crc_t FAR crc_table[TBLS][256];\nlocal void make_crc_table OF((void));\n#ifdef MAKECRCH\n   local void write_table OF((FILE *, const z_crc_t FAR *));\n#endif /* MAKECRCH */\n/*\n  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:\n  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.\n\n  Polynomials over GF(2) are represented in binary, one bit per coefficient,\n  with the lowest powers in the most significant bit.  Then adding polynomials\n  is just exclusive-or, and multiplying a polynomial by x is a right shift by\n  one.  If we call the above polynomial p, and represent a byte as the\n  polynomial q, also with the lowest power in the most significant bit (so the\n  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,\n  where a mod b means the remainder after dividing a by b.\n\n  This calculation is done using the shift-register method of multiplying and\n  taking the remainder.  The register is initialized to zero, and for each\n  incoming bit, x^32 is added mod p to the register if the bit is a one (where\n  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by\n  x (which is shifting right by one and adding x^32 mod p if the bit shifted\n  out is a one).  We start with the highest power (least significant bit) of\n  q and repeat for all eight bits of q.\n\n  The first table is simply the CRC of all possible eight bit values.  This is\n  all the information needed to generate CRCs on data a byte at a time for all\n  combinations of CRC register values and incoming bytes.  The remaining tables\n  allow for word-at-a-time CRC calculation for both big-endian and little-\n  endian machines, where a word is four bytes.\n*/\nlocal void make_crc_table()\n{\n    z_crc_t c;\n    int n, k;\n    z_crc_t poly;                       /* polynomial exclusive-or pattern */\n    /* terms of polynomial defining this crc (except x^32): */\n    static volatile int first = 1;      /* flag to limit concurrent making */\n    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};\n\n    /* See if another task is already doing this (not thread-safe, but better\n       than nothing -- significantly reduces duration of vulnerability in\n       case the advice about DYNAMIC_CRC_TABLE is ignored) */\n    if (first) {\n        first = 0;\n\n        /* make exclusive-or pattern from polynomial (0xedb88320UL) */\n        poly = 0;\n        for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)\n            poly |= (z_crc_t)1 << (31 - p[n]);\n\n        /* generate a crc for every 8-bit value */\n        for (n = 0; n < 256; n++) {\n            c = (z_crc_t)n;\n            for (k = 0; k < 8; k++)\n                c = c & 1 ? poly ^ (c >> 1) : c >> 1;\n            crc_table[0][n] = c;\n        }\n\n#ifdef BYFOUR\n        /* generate crc for each value followed by one, two, and three zeros,\n           and then the byte reversal of those as well as the first table */\n        for (n = 0; n < 256; n++) {\n            c = crc_table[0][n];\n            crc_table[4][n] = ZSWAP32(c);\n            for (k = 1; k < 4; k++) {\n                c = crc_table[0][c & 0xff] ^ (c >> 8);\n                crc_table[k][n] = c;\n                crc_table[k + 4][n] = ZSWAP32(c);\n            }\n        }\n#endif /* BYFOUR */\n\n        crc_table_empty = 0;\n    }\n    else {      /* not first */\n        /* wait for the other guy to finish (not efficient, but rare) */\n        while (crc_table_empty)\n            ;\n    }\n\n#ifdef MAKECRCH\n    /* write out CRC tables to crc32.h */\n    {\n        FILE *out;\n\n        out = fopen(\"crc32.h\", \"w\");\n        if (out == NULL) return;\n        fprintf(out, \"/* crc32.h -- tables for rapid CRC calculation\\n\");\n        fprintf(out, \" * Generated automatically by crc32.c\\n */\\n\\n\");\n        fprintf(out, \"local const z_crc_t FAR \");\n        fprintf(out, \"crc_table[TBLS][256] =\\n{\\n  {\\n\");\n        write_table(out, crc_table[0]);\n#  ifdef BYFOUR\n        fprintf(out, \"#ifdef BYFOUR\\n\");\n        for (k = 1; k < 8; k++) {\n            fprintf(out, \"  },\\n  {\\n\");\n            write_table(out, crc_table[k]);\n        }\n        fprintf(out, \"#endif\\n\");\n#  endif /* BYFOUR */\n        fprintf(out, \"  }\\n};\\n\");\n        fclose(out);\n    }\n#endif /* MAKECRCH */\n}\n\n#ifdef MAKECRCH\nlocal void write_table(out, table)\n    FILE *out;\n    const z_crc_t FAR *table;\n{\n    int n;\n\n    for (n = 0; n < 256; n++)\n        fprintf(out, \"%s0x%08lxUL%s\", n % 5 ? \"\" : \"    \",\n                (unsigned long)(table[n]),\n                n == 255 ? \"\\n\" : (n % 5 == 4 ? \",\\n\" : \", \"));\n}\n#endif /* MAKECRCH */\n\n#else /* !DYNAMIC_CRC_TABLE */\n/* ========================================================================\n * Tables of CRC-32s of all single-byte values, made by make_crc_table().\n */\n#include \"crc32.h\"\n#endif /* DYNAMIC_CRC_TABLE */\n\n/* =========================================================================\n * This function can be used by asm versions of crc32()\n */\nconst z_crc_t FAR * ZEXPORT get_crc_table()\n{\n#ifdef DYNAMIC_CRC_TABLE\n    if (crc_table_empty)\n        make_crc_table();\n#endif /* DYNAMIC_CRC_TABLE */\n    return (const z_crc_t FAR *)crc_table;\n}\n\n/* ========================================================================= */\n#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)\n#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32_z(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    if (buf == Z_NULL) return 0UL;\n\n#ifdef DYNAMIC_CRC_TABLE\n    if (crc_table_empty)\n        make_crc_table();\n#endif /* DYNAMIC_CRC_TABLE */\n\n#ifdef BYFOUR\n    if (sizeof(void *) == sizeof(ptrdiff_t)) {\n        z_crc_t endian;\n\n        endian = 1;\n        if (*((unsigned char *)(&endian)))\n            return crc32_little(crc, buf, len);\n        else\n            return crc32_big(crc, buf, len);\n    }\n#endif /* BYFOUR */\n    crc = crc ^ 0xffffffffUL;\n    while (len >= 8) {\n        DO8;\n        len -= 8;\n    }\n    if (len) do {\n        DO1;\n    } while (--len);\n    return crc ^ 0xffffffffUL;\n}\n\n/* ========================================================================= */\nunsigned long ZEXPORT crc32(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    uInt len;\n{\n    return crc32_z(crc, buf, len);\n}\n\n#ifdef BYFOUR\n\n/*\n   This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit\n   integer pointer type. This violates the strict aliasing rule, where a\n   compiler can assume, for optimization purposes, that two pointers to\n   fundamentally different types won't ever point to the same memory. This can\n   manifest as a problem only if one of the pointers is written to. This code\n   only reads from those pointers. So long as this code remains isolated in\n   this compilation unit, there won't be a problem. For this reason, this code\n   should not be copied and pasted into a compilation unit in which other code\n   writes to the buffer that is passed to these routines.\n */\n\n/* ========================================================================= */\n#define DOLIT4 c ^= *buf4++; \\\n        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \\\n            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]\n#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4\n\n/* ========================================================================= */\nlocal unsigned long crc32_little(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    register z_crc_t c;\n    register const z_crc_t FAR *buf4;\n\n    c = (z_crc_t)crc;\n    c = ~c;\n    while (len && ((ptrdiff_t)buf & 3)) {\n        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);\n        len--;\n    }\n\n    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;\n    while (len >= 32) {\n        DOLIT32;\n        len -= 32;\n    }\n    while (len >= 4) {\n        DOLIT4;\n        len -= 4;\n    }\n    buf = (const unsigned char FAR *)buf4;\n\n    if (len) do {\n        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);\n    } while (--len);\n    c = ~c;\n    return (unsigned long)c;\n}\n\n/* ========================================================================= */\n#define DOBIG4 c ^= *buf4++; \\\n        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \\\n            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]\n#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4\n\n/* ========================================================================= */\nlocal unsigned long crc32_big(crc, buf, len)\n    unsigned long crc;\n    const unsigned char FAR *buf;\n    z_size_t len;\n{\n    register z_crc_t c;\n    register const z_crc_t FAR *buf4;\n\n    c = ZSWAP32((z_crc_t)crc);\n    c = ~c;\n    while (len && ((ptrdiff_t)buf & 3)) {\n        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);\n        len--;\n    }\n\n    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;\n    while (len >= 32) {\n        DOBIG32;\n        len -= 32;\n    }\n    while (len >= 4) {\n        DOBIG4;\n        len -= 4;\n    }\n    buf = (const unsigned char FAR *)buf4;\n\n    if (len) do {\n        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);\n    } while (--len);\n    c = ~c;\n    return (unsigned long)(ZSWAP32(c));\n}\n\n#endif /* BYFOUR */\n\n#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */\n\n/* ========================================================================= */\nlocal unsigned long gf2_matrix_times(mat, vec)\n    unsigned long *mat;\n    unsigned long vec;\n{\n    unsigned long sum;\n\n    sum = 0;\n    while (vec) {\n        if (vec & 1)\n            sum ^= *mat;\n        vec >>= 1;\n        mat++;\n    }\n    return sum;\n}\n\n/* ========================================================================= */\nlocal void gf2_matrix_square(square, mat)\n    unsigned long *square;\n    unsigned long *mat;\n{\n    int n;\n\n    for (n = 0; n < GF2_DIM; n++)\n        square[n] = gf2_matrix_times(mat, mat[n]);\n}\n\n/* ========================================================================= */\nlocal uLong crc32_combine_(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off64_t len2;\n{\n    int n;\n    unsigned long row;\n    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */\n    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */\n\n    /* degenerate case (also disallow negative lengths) */\n    if (len2 <= 0)\n        return crc1;\n\n    /* put operator for one zero bit in odd */\n    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */\n    row = 1;\n    for (n = 1; n < GF2_DIM; n++) {\n        odd[n] = row;\n        row <<= 1;\n    }\n\n    /* put operator for two zero bits in even */\n    gf2_matrix_square(even, odd);\n\n    /* put operator for four zero bits in odd */\n    gf2_matrix_square(odd, even);\n\n    /* apply len2 zeros to crc1 (first square will put the operator for one\n       zero byte, eight zero bits, in even) */\n    do {\n        /* apply zeros operator for this bit of len2 */\n        gf2_matrix_square(even, odd);\n        if (len2 & 1)\n            crc1 = gf2_matrix_times(even, crc1);\n        len2 >>= 1;\n\n        /* if no more bits set, then done */\n        if (len2 == 0)\n            break;\n\n        /* another iteration of the loop with odd and even swapped */\n        gf2_matrix_square(odd, even);\n        if (len2 & 1)\n            crc1 = gf2_matrix_times(odd, crc1);\n        len2 >>= 1;\n\n        /* if no more bits set, then done */\n    } while (len2 != 0);\n\n    /* return combined crc */\n    crc1 ^= crc2;\n    return crc1;\n}\n\n/* ========================================================================= */\nuLong ZEXPORT crc32_combine(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off_t len2;\n{\n    return crc32_combine_(crc1, crc2, len2);\n}\n\nuLong ZEXPORT crc32_combine64(crc1, crc2, len2)\n    uLong crc1;\n    uLong crc2;\n    z_off64_t len2;\n{\n    return crc32_combine_(crc1, crc2, len2);\n}\n"
  },
  {
    "path": "dlib/external/zlib/crc32.h",
    "content": "/* crc32.h -- tables for rapid CRC calculation\n * Generated automatically by crc32.c\n */\n\nlocal const z_crc_t FAR crc_table[TBLS][256] =\n{\n  {\n    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,\n    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,\n    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,\n    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,\n    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,\n    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,\n    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,\n    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,\n    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,\n    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,\n    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,\n    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,\n    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,\n    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,\n    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,\n    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,\n    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,\n    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,\n    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,\n    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,\n    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,\n    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,\n    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,\n    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,\n    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,\n    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,\n    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,\n    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,\n    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,\n    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,\n    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,\n    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,\n    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,\n    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,\n    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,\n    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,\n    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,\n    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,\n    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,\n    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,\n    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,\n    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,\n    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,\n    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,\n    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,\n    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,\n    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,\n    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,\n    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,\n    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,\n    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,\n    0x2d02ef8dUL\n#ifdef BYFOUR\n  },\n  {\n    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,\n    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,\n    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,\n    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,\n    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,\n    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,\n    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,\n    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,\n    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,\n    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,\n    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,\n    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,\n    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,\n    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,\n    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,\n    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,\n    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,\n    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,\n    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,\n    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,\n    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,\n    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,\n    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,\n    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,\n    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,\n    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,\n    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,\n    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,\n    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,\n    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,\n    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,\n    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,\n    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,\n    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,\n    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,\n    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,\n    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,\n    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,\n    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,\n    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,\n    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,\n    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,\n    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,\n    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,\n    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,\n    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,\n    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,\n    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,\n    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,\n    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,\n    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,\n    0x9324fd72UL\n  },\n  {\n    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,\n    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,\n    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,\n    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,\n    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,\n    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,\n    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,\n    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,\n    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,\n    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,\n    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,\n    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,\n    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,\n    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,\n    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,\n    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,\n    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,\n    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,\n    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,\n    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,\n    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,\n    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,\n    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,\n    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,\n    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,\n    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,\n    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,\n    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,\n    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,\n    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,\n    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,\n    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,\n    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,\n    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,\n    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,\n    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,\n    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,\n    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,\n    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,\n    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,\n    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,\n    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,\n    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,\n    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,\n    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,\n    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,\n    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,\n    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,\n    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,\n    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,\n    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,\n    0xbe9834edUL\n  },\n  {\n    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,\n    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,\n    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,\n    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,\n    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,\n    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,\n    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,\n    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,\n    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,\n    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,\n    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,\n    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,\n    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,\n    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,\n    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,\n    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,\n    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,\n    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,\n    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,\n    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,\n    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,\n    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,\n    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,\n    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,\n    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,\n    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,\n    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,\n    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,\n    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,\n    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,\n    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,\n    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,\n    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,\n    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,\n    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,\n    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,\n    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,\n    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,\n    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,\n    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,\n    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,\n    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,\n    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,\n    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,\n    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,\n    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,\n    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,\n    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,\n    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,\n    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,\n    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,\n    0xde0506f1UL\n  },\n  {\n    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,\n    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,\n    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,\n    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,\n    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,\n    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,\n    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,\n    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,\n    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,\n    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,\n    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,\n    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,\n    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,\n    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,\n    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,\n    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,\n    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,\n    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,\n    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,\n    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,\n    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,\n    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,\n    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,\n    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,\n    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,\n    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,\n    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,\n    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,\n    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,\n    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,\n    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,\n    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,\n    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,\n    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,\n    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,\n    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,\n    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,\n    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,\n    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,\n    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,\n    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,\n    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,\n    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,\n    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,\n    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,\n    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,\n    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,\n    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,\n    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,\n    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,\n    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,\n    0x8def022dUL\n  },\n  {\n    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,\n    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,\n    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,\n    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,\n    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,\n    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,\n    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,\n    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,\n    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,\n    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,\n    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,\n    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,\n    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,\n    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,\n    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,\n    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,\n    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,\n    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,\n    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,\n    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,\n    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,\n    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,\n    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,\n    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,\n    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,\n    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,\n    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,\n    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,\n    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,\n    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,\n    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,\n    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,\n    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,\n    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,\n    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,\n    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,\n    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,\n    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,\n    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,\n    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,\n    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,\n    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,\n    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,\n    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,\n    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,\n    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,\n    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,\n    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,\n    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,\n    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,\n    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,\n    0x72fd2493UL\n  },\n  {\n    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,\n    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,\n    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,\n    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,\n    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,\n    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,\n    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,\n    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,\n    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,\n    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,\n    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,\n    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,\n    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,\n    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,\n    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,\n    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,\n    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,\n    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,\n    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,\n    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,\n    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,\n    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,\n    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,\n    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,\n    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,\n    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,\n    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,\n    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,\n    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,\n    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,\n    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,\n    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,\n    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,\n    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,\n    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,\n    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,\n    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,\n    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,\n    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,\n    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,\n    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,\n    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,\n    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,\n    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,\n    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,\n    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,\n    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,\n    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,\n    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,\n    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,\n    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,\n    0xed3498beUL\n  },\n  {\n    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,\n    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,\n    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,\n    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,\n    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,\n    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,\n    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,\n    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,\n    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,\n    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,\n    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,\n    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,\n    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,\n    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,\n    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,\n    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,\n    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,\n    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,\n    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,\n    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,\n    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,\n    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,\n    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,\n    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,\n    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,\n    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,\n    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,\n    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,\n    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,\n    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,\n    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,\n    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,\n    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,\n    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,\n    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,\n    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,\n    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,\n    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,\n    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,\n    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,\n    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,\n    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,\n    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,\n    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,\n    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,\n    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,\n    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,\n    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,\n    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,\n    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,\n    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,\n    0xf10605deUL\n#endif\n  }\n};\n"
  },
  {
    "path": "dlib/external/zlib/deflate.c",
    "content": "/* deflate.c -- compress data using the deflation algorithm\n * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process depends on being able to identify portions\n *      of the input text which are identical to earlier input (within a\n *      sliding window trailing behind the input currently being processed).\n *\n *      The most straightforward technique turns out to be the fastest for\n *      most input files: try all possible matches and select the longest.\n *      The key feature of this algorithm is that insertions into the string\n *      dictionary are very simple and thus fast, and deletions are avoided\n *      completely. Insertions are performed at each input character, whereas\n *      string matches are performed only when the previous match ends. So it\n *      is preferable to spend more time in matches to allow very fast string\n *      insertions and avoid deletions. The matching algorithm for small\n *      strings is inspired from that of Rabin & Karp. A brute force approach\n *      is used to find longer strings when a small match has been found.\n *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze\n *      (by Leonid Broukhis).\n *         A previous version of this file used a more sophisticated algorithm\n *      (by Fiala and Greene) which is guaranteed to run in linear amortized\n *      time, but has a larger average cost, uses more memory and is patented.\n *      However the F&G algorithm may be faster for some highly redundant\n *      files if the parameter max_chain_length (described below) is too large.\n *\n *  ACKNOWLEDGEMENTS\n *\n *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and\n *      I found it in 'freeze' written by Leonid Broukhis.\n *      Thanks to many people for bug reports and testing.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"DEFLATE Compressed Data Format Specification\".\n *      Available in http://tools.ietf.org/html/rfc1951\n *\n *      A description of the Rabin and Karp algorithm is given in the book\n *         \"Algorithms\" by R. Sedgewick, Addison-Wesley, p252.\n *\n *      Fiala,E.R., and Greene,D.H.\n *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595\n *\n */\n\n/* @(#) $Id$ */\n\n#include \"deflate.h\"\n\nconst char deflate_copyright[] =\n   \" deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\n/* ===========================================================================\n *  Function prototypes.\n */\ntypedef enum {\n    need_more,      /* block not completed, need more input or more output */\n    block_done,     /* block flush performed */\n    finish_started, /* finish started, need only more output at next deflate */\n    finish_done     /* finish done, accept no more input or output */\n} block_state;\n\ntypedef block_state (*compress_func) OF((deflate_state *s, int flush));\n/* Compression function. Returns the block state after the call. */\n\nlocal int deflateStateCheck      OF((z_streamp strm));\nlocal void slide_hash     OF((deflate_state *s));\nlocal void fill_window    OF((deflate_state *s));\nlocal block_state deflate_stored OF((deflate_state *s, int flush));\nlocal block_state deflate_fast   OF((deflate_state *s, int flush));\n#ifndef FASTEST\nlocal block_state deflate_slow   OF((deflate_state *s, int flush));\n#endif\nlocal block_state deflate_rle    OF((deflate_state *s, int flush));\nlocal block_state deflate_huff   OF((deflate_state *s, int flush));\nlocal void lm_init        OF((deflate_state *s));\nlocal void putShortMSB    OF((deflate_state *s, uInt b));\nlocal void flush_pending  OF((z_streamp strm));\nlocal unsigned read_buf   OF((z_streamp strm, Bytef *buf, unsigned size));\n#ifdef ASMV\n#  pragma message(\"Assembler code may have bugs -- use at your own risk\")\n      void match_init OF((void)); /* asm code initialization */\n      uInt longest_match  OF((deflate_state *s, IPos cur_match));\n#else\nlocal uInt longest_match  OF((deflate_state *s, IPos cur_match));\n#endif\n\n#ifdef ZLIB_DEBUG\nlocal  void check_match OF((deflate_state *s, IPos start, IPos match,\n                            int length));\n#endif\n\n/* ===========================================================================\n * Local data\n */\n\n#define NIL 0\n/* Tail of hash chains */\n\n#ifndef TOO_FAR\n#  define TOO_FAR 4096\n#endif\n/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */\n\n/* Values for max_lazy_match, good_match and max_chain_length, depending on\n * the desired pack level (0..9). The values given below have been tuned to\n * exclude worst case performance for pathological files. Better values may be\n * found for specific files.\n */\ntypedef struct config_s {\n   ush good_length; /* reduce lazy search above this match length */\n   ush max_lazy;    /* do not perform lazy search above this match length */\n   ush nice_length; /* quit search above this match length */\n   ush max_chain;\n   compress_func func;\n} config;\n\n#ifdef FASTEST\nlocal const config configuration_table[2] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */\n#else\nlocal const config configuration_table[10] = {\n/*      good lazy nice chain */\n/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */\n/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */\n/* 2 */ {4,    5, 16,    8, deflate_fast},\n/* 3 */ {4,    6, 32,   32, deflate_fast},\n\n/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */\n/* 5 */ {8,   16, 32,   32, deflate_slow},\n/* 6 */ {8,   16, 128, 128, deflate_slow},\n/* 7 */ {8,   32, 128, 256, deflate_slow},\n/* 8 */ {32, 128, 258, 1024, deflate_slow},\n/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */\n#endif\n\n/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4\n * For deflate_fast() (levels <= 3) good is ignored and lazy has a different\n * meaning.\n */\n\n/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */\n#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))\n\n/* ===========================================================================\n * Update a hash value with the given input byte\n * IN  assertion: all calls to UPDATE_HASH are made with consecutive input\n *    characters, so that a running hash key can be computed from the previous\n *    key instead of complete recalculation each time.\n */\n#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)\n\n\n/* ===========================================================================\n * Insert string str in the dictionary and set match_head to the previous head\n * of the hash chain (the most recent string with same hash key). Return\n * the previous length of the hash chain.\n * If this file is compiled with -DFASTEST, the compression level is forced\n * to 1, and no hash chains are maintained.\n * IN  assertion: all calls to INSERT_STRING are made with consecutive input\n *    characters and the first MIN_MATCH bytes of str are valid (except for\n *    the last MIN_MATCH-1 bytes of the input file).\n */\n#ifdef FASTEST\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#else\n#define INSERT_STRING(s, str, match_head) \\\n   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \\\n    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \\\n    s->head[s->ins_h] = (Pos)(str))\n#endif\n\n/* ===========================================================================\n * Initialize the hash table (avoiding 64K overflow for 16 bit systems).\n * prev[] will be initialized on the fly.\n */\n#define CLEAR_HASH(s) \\\n    s->head[s->hash_size-1] = NIL; \\\n    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));\n\n/* ===========================================================================\n * Slide the hash table when sliding the window down (could be avoided with 32\n * bit values at the expense of memory usage). We slide even when level == 0 to\n * keep the hash table consistent if we switch back to level > 0 later.\n */\nlocal void slide_hash(s)\n    deflate_state *s;\n{\n    unsigned n, m;\n    Posf *p;\n    uInt wsize = s->w_size;\n\n    n = s->hash_size;\n    p = &s->head[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n    } while (--n);\n    n = wsize;\n#ifndef FASTEST\n    p = &s->prev[n];\n    do {\n        m = *--p;\n        *p = (Pos)(m >= wsize ? m - wsize : NIL);\n        /* If n is not on any hash chain, prev[n] is garbage but\n         * its value will never be used.\n         */\n    } while (--n);\n#endif\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit_(strm, level, version, stream_size)\n    z_streamp strm;\n    int level;\n    const char *version;\n    int stream_size;\n{\n    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,\n                         Z_DEFAULT_STRATEGY, version, stream_size);\n    /* To do: ignore strm->next_in if we use it as window */\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,\n                  version, stream_size)\n    z_streamp strm;\n    int  level;\n    int  method;\n    int  windowBits;\n    int  memLevel;\n    int  strategy;\n    const char *version;\n    int stream_size;\n{\n    deflate_state *s;\n    int wrap = 1;\n    static const char my_version[] = ZLIB_VERSION;\n\n    ushf *overlay;\n    /* We overlay pending_buf and d_buf+l_buf. This works since the average\n     * output size for (length,distance) codes is <= 24 bits.\n     */\n\n    if (version == Z_NULL || version[0] != my_version[0] ||\n        stream_size != sizeof(z_stream)) {\n        return Z_VERSION_ERROR;\n    }\n    if (strm == Z_NULL) return Z_STREAM_ERROR;\n\n    strm->msg = Z_NULL;\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zfree = zcfree;\n#endif\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n\n    if (windowBits < 0) { /* suppress zlib wrapper */\n        wrap = 0;\n        windowBits = -windowBits;\n    }\n#ifdef GZIP\n    else if (windowBits > 15) {\n        wrap = 2;       /* write gzip wrapper instead */\n        windowBits -= 16;\n    }\n#endif\n    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||\n        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||\n        strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {\n        return Z_STREAM_ERROR;\n    }\n    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */\n    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));\n    if (s == Z_NULL) return Z_MEM_ERROR;\n    strm->state = (struct internal_state FAR *)s;\n    s->strm = strm;\n    s->status = INIT_STATE;     /* to pass state test in deflateReset() */\n\n    s->wrap = wrap;\n    s->gzhead = Z_NULL;\n    s->w_bits = (uInt)windowBits;\n    s->w_size = 1 << s->w_bits;\n    s->w_mask = s->w_size - 1;\n\n    s->hash_bits = (uInt)memLevel + 7;\n    s->hash_size = 1 << s->hash_bits;\n    s->hash_mask = s->hash_size - 1;\n    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);\n\n    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));\n    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));\n    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));\n\n    s->high_water = 0;      /* nothing written to s->window yet */\n\n    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */\n\n    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);\n    s->pending_buf = (uchf *) overlay;\n    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);\n\n    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||\n        s->pending_buf == Z_NULL) {\n        s->status = FINISH_STATE;\n        strm->msg = ERR_MSG(Z_MEM_ERROR);\n        deflateEnd (strm);\n        return Z_MEM_ERROR;\n    }\n    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);\n    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;\n\n    s->level = level;\n    s->strategy = strategy;\n    s->method = (Byte)method;\n\n    return deflateReset(strm);\n}\n\n/* =========================================================================\n * Check for a valid deflate stream state. Return 0 if ok, 1 if not.\n */\nlocal int deflateStateCheck (strm)\n    z_streamp strm;\n{\n    deflate_state *s;\n    if (strm == Z_NULL ||\n        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)\n        return 1;\n    s = strm->state;\n    if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&\n#ifdef GZIP\n                                           s->status != GZIP_STATE &&\n#endif\n                                           s->status != EXTRA_STATE &&\n                                           s->status != NAME_STATE &&\n                                           s->status != COMMENT_STATE &&\n                                           s->status != HCRC_STATE &&\n                                           s->status != BUSY_STATE &&\n                                           s->status != FINISH_STATE))\n        return 1;\n    return 0;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)\n    z_streamp strm;\n    const Bytef *dictionary;\n    uInt  dictLength;\n{\n    deflate_state *s;\n    uInt str, n;\n    int wrap;\n    unsigned avail;\n    z_const unsigned char *next;\n\n    if (deflateStateCheck(strm) || dictionary == Z_NULL)\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    wrap = s->wrap;\n    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)\n        return Z_STREAM_ERROR;\n\n    /* when using zlib wrappers, compute Adler-32 for provided dictionary */\n    if (wrap == 1)\n        strm->adler = adler32(strm->adler, dictionary, dictLength);\n    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */\n\n    /* if dictionary would fill window, just replace the history */\n    if (dictLength >= s->w_size) {\n        if (wrap == 0) {            /* already empty otherwise */\n            CLEAR_HASH(s);\n            s->strstart = 0;\n            s->block_start = 0L;\n            s->insert = 0;\n        }\n        dictionary += dictLength - s->w_size;  /* use the tail */\n        dictLength = s->w_size;\n    }\n\n    /* insert dictionary into window and hash */\n    avail = strm->avail_in;\n    next = strm->next_in;\n    strm->avail_in = dictLength;\n    strm->next_in = (z_const Bytef *)dictionary;\n    fill_window(s);\n    while (s->lookahead >= MIN_MATCH) {\n        str = s->strstart;\n        n = s->lookahead - (MIN_MATCH-1);\n        do {\n            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n            s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n            s->head[s->ins_h] = (Pos)str;\n            str++;\n        } while (--n);\n        s->strstart = str;\n        s->lookahead = MIN_MATCH-1;\n        fill_window(s);\n    }\n    s->strstart += s->lookahead;\n    s->block_start = (long)s->strstart;\n    s->insert = s->lookahead;\n    s->lookahead = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    strm->next_in = next;\n    strm->avail_in = avail;\n    s->wrap = wrap;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)\n    z_streamp strm;\n    Bytef *dictionary;\n    uInt  *dictLength;\n{\n    deflate_state *s;\n    uInt len;\n\n    if (deflateStateCheck(strm))\n        return Z_STREAM_ERROR;\n    s = strm->state;\n    len = s->strstart + s->lookahead;\n    if (len > s->w_size)\n        len = s->w_size;\n    if (dictionary != Z_NULL && len)\n        zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);\n    if (dictLength != Z_NULL)\n        *dictLength = len;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateResetKeep (strm)\n    z_streamp strm;\n{\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) {\n        return Z_STREAM_ERROR;\n    }\n\n    strm->total_in = strm->total_out = 0;\n    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */\n    strm->data_type = Z_UNKNOWN;\n\n    s = (deflate_state *)strm->state;\n    s->pending = 0;\n    s->pending_out = s->pending_buf;\n\n    if (s->wrap < 0) {\n        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */\n    }\n    s->status =\n#ifdef GZIP\n        s->wrap == 2 ? GZIP_STATE :\n#endif\n        s->wrap ? INIT_STATE : BUSY_STATE;\n    strm->adler =\n#ifdef GZIP\n        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :\n#endif\n        adler32(0L, Z_NULL, 0);\n    s->last_flush = Z_NO_FLUSH;\n\n    _tr_init(s);\n\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateReset (strm)\n    z_streamp strm;\n{\n    int ret;\n\n    ret = deflateResetKeep(strm);\n    if (ret == Z_OK)\n        lm_init(strm->state);\n    return ret;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateSetHeader (strm, head)\n    z_streamp strm;\n    gz_headerp head;\n{\n    if (deflateStateCheck(strm) || strm->state->wrap != 2)\n        return Z_STREAM_ERROR;\n    strm->state->gzhead = head;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePending (strm, pending, bits)\n    unsigned *pending;\n    int *bits;\n    z_streamp strm;\n{\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    if (pending != Z_NULL)\n        *pending = strm->state->pending;\n    if (bits != Z_NULL)\n        *bits = strm->state->bi_valid;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflatePrime (strm, bits, value)\n    z_streamp strm;\n    int bits;\n    int value;\n{\n    deflate_state *s;\n    int put;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))\n        return Z_BUF_ERROR;\n    do {\n        put = Buf_size - s->bi_valid;\n        if (put > bits)\n            put = bits;\n        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);\n        s->bi_valid += put;\n        _tr_flush_bits(s);\n        value >>= put;\n        bits -= put;\n    } while (bits);\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateParams(strm, level, strategy)\n    z_streamp strm;\n    int level;\n    int strategy;\n{\n    deflate_state *s;\n    compress_func func;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n\n#ifdef FASTEST\n    if (level != 0) level = 1;\n#else\n    if (level == Z_DEFAULT_COMPRESSION) level = 6;\n#endif\n    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {\n        return Z_STREAM_ERROR;\n    }\n    func = configuration_table[s->level].func;\n\n    if ((strategy != s->strategy || func != configuration_table[level].func) &&\n        s->high_water) {\n        /* Flush the last buffer: */\n        int err = deflate(strm, Z_BLOCK);\n        if (err == Z_STREAM_ERROR)\n            return err;\n        if (strm->avail_out == 0)\n            return Z_BUF_ERROR;\n    }\n    if (s->level != level) {\n        if (s->level == 0 && s->matches != 0) {\n            if (s->matches == 1)\n                slide_hash(s);\n            else\n                CLEAR_HASH(s);\n            s->matches = 0;\n        }\n        s->level = level;\n        s->max_lazy_match   = configuration_table[level].max_lazy;\n        s->good_match       = configuration_table[level].good_length;\n        s->nice_match       = configuration_table[level].nice_length;\n        s->max_chain_length = configuration_table[level].max_chain;\n    }\n    s->strategy = strategy;\n    return Z_OK;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)\n    z_streamp strm;\n    int good_length;\n    int max_lazy;\n    int nice_length;\n    int max_chain;\n{\n    deflate_state *s;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n    s = strm->state;\n    s->good_match = (uInt)good_length;\n    s->max_lazy_match = (uInt)max_lazy;\n    s->nice_match = nice_length;\n    s->max_chain_length = (uInt)max_chain;\n    return Z_OK;\n}\n\n/* =========================================================================\n * For the default windowBits of 15 and memLevel of 8, this function returns\n * a close to exact, as well as small, upper bound on the compressed size.\n * They are coded as constants here for a reason--if the #define's are\n * changed, then this function needs to be changed as well.  The return\n * value for 15 and 8 only works for those exact settings.\n *\n * For any setting other than those defaults for windowBits and memLevel,\n * the value returned is a conservative worst case for the maximum expansion\n * resulting from using fixed blocks instead of stored blocks, which deflate\n * can emit on compressed data for some combinations of the parameters.\n *\n * This function could be more sophisticated to provide closer upper bounds for\n * every combination of windowBits and memLevel.  But even the conservative\n * upper bound of about 14% expansion does not seem onerous for output buffer\n * allocation.\n */\nuLong ZEXPORT deflateBound(strm, sourceLen)\n    z_streamp strm;\n    uLong sourceLen;\n{\n    deflate_state *s;\n    uLong complen, wraplen;\n\n    /* conservative upper bound for compressed data */\n    complen = sourceLen +\n              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;\n\n    /* if can't get parameters, return conservative bound plus zlib wrapper */\n    if (deflateStateCheck(strm))\n        return complen + 6;\n\n    /* compute wrapper length */\n    s = strm->state;\n    switch (s->wrap) {\n    case 0:                                 /* raw deflate */\n        wraplen = 0;\n        break;\n    case 1:                                 /* zlib wrapper */\n        wraplen = 6 + (s->strstart ? 4 : 0);\n        break;\n#ifdef GZIP\n    case 2:                                 /* gzip wrapper */\n        wraplen = 18;\n        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */\n            Bytef *str;\n            if (s->gzhead->extra != Z_NULL)\n                wraplen += 2 + s->gzhead->extra_len;\n            str = s->gzhead->name;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            str = s->gzhead->comment;\n            if (str != Z_NULL)\n                do {\n                    wraplen++;\n                } while (*str++);\n            if (s->gzhead->hcrc)\n                wraplen += 2;\n        }\n        break;\n#endif\n    default:                                /* for compiler happiness */\n        wraplen = 6;\n    }\n\n    /* if not default parameters, return conservative bound */\n    if (s->w_bits != 15 || s->hash_bits != 8 + 7)\n        return complen + wraplen;\n\n    /* default settings: return tight bound for that case */\n    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +\n           (sourceLen >> 25) + 13 - 6 + wraplen;\n}\n\n/* =========================================================================\n * Put a short in the pending buffer. The 16-bit value is put in MSB order.\n * IN assertion: the stream state is correct and there is enough room in\n * pending_buf.\n */\nlocal void putShortMSB (s, b)\n    deflate_state *s;\n    uInt b;\n{\n    put_byte(s, (Byte)(b >> 8));\n    put_byte(s, (Byte)(b & 0xff));\n}\n\n/* =========================================================================\n * Flush as much pending output as possible. All deflate() output, except for\n * some deflate_stored() output, goes through this function so some\n * applications may wish to modify it to avoid allocating a large\n * strm->next_out buffer and copying into it. (See also read_buf()).\n */\nlocal void flush_pending(strm)\n    z_streamp strm;\n{\n    unsigned len;\n    deflate_state *s = strm->state;\n\n    _tr_flush_bits(s);\n    len = s->pending;\n    if (len > strm->avail_out) len = strm->avail_out;\n    if (len == 0) return;\n\n    zmemcpy(strm->next_out, s->pending_out, len);\n    strm->next_out  += len;\n    s->pending_out  += len;\n    strm->total_out += len;\n    strm->avail_out -= len;\n    s->pending      -= len;\n    if (s->pending == 0) {\n        s->pending_out = s->pending_buf;\n    }\n}\n\n/* ===========================================================================\n * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].\n */\n#define HCRC_UPDATE(beg) \\\n    do { \\\n        if (s->gzhead->hcrc && s->pending > (beg)) \\\n            strm->adler = crc32(strm->adler, s->pending_buf + (beg), \\\n                                s->pending - (beg)); \\\n    } while (0)\n\n/* ========================================================================= */\nint ZEXPORT deflate (strm, flush)\n    z_streamp strm;\n    int flush;\n{\n    int old_flush; /* value of flush param for previous deflate call */\n    deflate_state *s;\n\n    if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {\n        return Z_STREAM_ERROR;\n    }\n    s = strm->state;\n\n    if (strm->next_out == Z_NULL ||\n        (strm->avail_in != 0 && strm->next_in == Z_NULL) ||\n        (s->status == FINISH_STATE && flush != Z_FINISH)) {\n        ERR_RETURN(strm, Z_STREAM_ERROR);\n    }\n    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);\n\n    old_flush = s->last_flush;\n    s->last_flush = flush;\n\n    /* Flush as much pending output as possible */\n    if (s->pending != 0) {\n        flush_pending(strm);\n        if (strm->avail_out == 0) {\n            /* Since avail_out is 0, deflate will be called again with\n             * more output space, but possibly with both pending and\n             * avail_in equal to zero. There won't be anything to do,\n             * but this is not an error situation so make sure we\n             * return OK instead of BUF_ERROR at next call of deflate:\n             */\n            s->last_flush = -1;\n            return Z_OK;\n        }\n\n    /* Make sure there is something to do and avoid duplicate consecutive\n     * flushes. For repeated and useless calls with Z_FINISH, we keep\n     * returning Z_STREAM_END instead of Z_BUF_ERROR.\n     */\n    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&\n               flush != Z_FINISH) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* User must not provide more input after the first FINISH: */\n    if (s->status == FINISH_STATE && strm->avail_in != 0) {\n        ERR_RETURN(strm, Z_BUF_ERROR);\n    }\n\n    /* Write the header */\n    if (s->status == INIT_STATE) {\n        /* zlib header */\n        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;\n        uInt level_flags;\n\n        if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)\n            level_flags = 0;\n        else if (s->level < 6)\n            level_flags = 1;\n        else if (s->level == 6)\n            level_flags = 2;\n        else\n            level_flags = 3;\n        header |= (level_flags << 6);\n        if (s->strstart != 0) header |= PRESET_DICT;\n        header += 31 - (header % 31);\n\n        putShortMSB(s, header);\n\n        /* Save the adler32 of the preset dictionary: */\n        if (s->strstart != 0) {\n            putShortMSB(s, (uInt)(strm->adler >> 16));\n            putShortMSB(s, (uInt)(strm->adler & 0xffff));\n        }\n        strm->adler = adler32(0L, Z_NULL, 0);\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#ifdef GZIP\n    if (s->status == GZIP_STATE) {\n        /* gzip header */\n        strm->adler = crc32(0L, Z_NULL, 0);\n        put_byte(s, 31);\n        put_byte(s, 139);\n        put_byte(s, 8);\n        if (s->gzhead == Z_NULL) {\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, 0);\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, OS_CODE);\n            s->status = BUSY_STATE;\n\n            /* Compression must start with an empty pending buffer */\n            flush_pending(strm);\n            if (s->pending != 0) {\n                s->last_flush = -1;\n                return Z_OK;\n            }\n        }\n        else {\n            put_byte(s, (s->gzhead->text ? 1 : 0) +\n                     (s->gzhead->hcrc ? 2 : 0) +\n                     (s->gzhead->extra == Z_NULL ? 0 : 4) +\n                     (s->gzhead->name == Z_NULL ? 0 : 8) +\n                     (s->gzhead->comment == Z_NULL ? 0 : 16)\n                     );\n            put_byte(s, (Byte)(s->gzhead->time & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));\n            put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));\n            put_byte(s, s->level == 9 ? 2 :\n                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?\n                      4 : 0));\n            put_byte(s, s->gzhead->os & 0xff);\n            if (s->gzhead->extra != Z_NULL) {\n                put_byte(s, s->gzhead->extra_len & 0xff);\n                put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);\n            }\n            if (s->gzhead->hcrc)\n                strm->adler = crc32(strm->adler, s->pending_buf,\n                                    s->pending);\n            s->gzindex = 0;\n            s->status = EXTRA_STATE;\n        }\n    }\n    if (s->status == EXTRA_STATE) {\n        if (s->gzhead->extra != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;\n            while (s->pending + left > s->pending_buf_size) {\n                uInt copy = s->pending_buf_size - s->pending;\n                zmemcpy(s->pending_buf + s->pending,\n                        s->gzhead->extra + s->gzindex, copy);\n                s->pending = s->pending_buf_size;\n                HCRC_UPDATE(beg);\n                s->gzindex += copy;\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n                beg = 0;\n                left -= copy;\n            }\n            zmemcpy(s->pending_buf + s->pending,\n                    s->gzhead->extra + s->gzindex, left);\n            s->pending += left;\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = NAME_STATE;\n    }\n    if (s->status == NAME_STATE) {\n        if (s->gzhead->name != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->name[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n            s->gzindex = 0;\n        }\n        s->status = COMMENT_STATE;\n    }\n    if (s->status == COMMENT_STATE) {\n        if (s->gzhead->comment != Z_NULL) {\n            ulg beg = s->pending;   /* start of bytes to update crc */\n            int val;\n            do {\n                if (s->pending == s->pending_buf_size) {\n                    HCRC_UPDATE(beg);\n                    flush_pending(strm);\n                    if (s->pending != 0) {\n                        s->last_flush = -1;\n                        return Z_OK;\n                    }\n                    beg = 0;\n                }\n                val = s->gzhead->comment[s->gzindex++];\n                put_byte(s, val);\n            } while (val != 0);\n            HCRC_UPDATE(beg);\n        }\n        s->status = HCRC_STATE;\n    }\n    if (s->status == HCRC_STATE) {\n        if (s->gzhead->hcrc) {\n            if (s->pending + 2 > s->pending_buf_size) {\n                flush_pending(strm);\n                if (s->pending != 0) {\n                    s->last_flush = -1;\n                    return Z_OK;\n                }\n            }\n            put_byte(s, (Byte)(strm->adler & 0xff));\n            put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n            strm->adler = crc32(0L, Z_NULL, 0);\n        }\n        s->status = BUSY_STATE;\n\n        /* Compression must start with an empty pending buffer */\n        flush_pending(strm);\n        if (s->pending != 0) {\n            s->last_flush = -1;\n            return Z_OK;\n        }\n    }\n#endif\n\n    /* Start a new block or continue the current one.\n     */\n    if (strm->avail_in != 0 || s->lookahead != 0 ||\n        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {\n        block_state bstate;\n\n        bstate = s->level == 0 ? deflate_stored(s, flush) :\n                 s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :\n                 s->strategy == Z_RLE ? deflate_rle(s, flush) :\n                 (*(configuration_table[s->level].func))(s, flush);\n\n        if (bstate == finish_started || bstate == finish_done) {\n            s->status = FINISH_STATE;\n        }\n        if (bstate == need_more || bstate == finish_started) {\n            if (strm->avail_out == 0) {\n                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */\n            }\n            return Z_OK;\n            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call\n             * of deflate should use the same flush parameter to make sure\n             * that the flush is complete. So we don't have to output an\n             * empty block here, this will be done at next call. This also\n             * ensures that for a very small output buffer, we emit at most\n             * one empty block.\n             */\n        }\n        if (bstate == block_done) {\n            if (flush == Z_PARTIAL_FLUSH) {\n                _tr_align(s);\n            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */\n                _tr_stored_block(s, (char*)0, 0L, 0);\n                /* For a full flush, this empty block will be recognized\n                 * as a special marker by inflate_sync().\n                 */\n                if (flush == Z_FULL_FLUSH) {\n                    CLEAR_HASH(s);             /* forget history */\n                    if (s->lookahead == 0) {\n                        s->strstart = 0;\n                        s->block_start = 0L;\n                        s->insert = 0;\n                    }\n                }\n            }\n            flush_pending(strm);\n            if (strm->avail_out == 0) {\n              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */\n              return Z_OK;\n            }\n        }\n    }\n\n    if (flush != Z_FINISH) return Z_OK;\n    if (s->wrap <= 0) return Z_STREAM_END;\n\n    /* Write the trailer */\n#ifdef GZIP\n    if (s->wrap == 2) {\n        put_byte(s, (Byte)(strm->adler & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));\n        put_byte(s, (Byte)(strm->total_in & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));\n        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));\n    }\n    else\n#endif\n    {\n        putShortMSB(s, (uInt)(strm->adler >> 16));\n        putShortMSB(s, (uInt)(strm->adler & 0xffff));\n    }\n    flush_pending(strm);\n    /* If avail_out is zero, the application will call deflate again\n     * to flush the rest.\n     */\n    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */\n    return s->pending != 0 ? Z_OK : Z_STREAM_END;\n}\n\n/* ========================================================================= */\nint ZEXPORT deflateEnd (strm)\n    z_streamp strm;\n{\n    int status;\n\n    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;\n\n    status = strm->state->status;\n\n    /* Deallocate in reverse order of allocations: */\n    TRY_FREE(strm, strm->state->pending_buf);\n    TRY_FREE(strm, strm->state->head);\n    TRY_FREE(strm, strm->state->prev);\n    TRY_FREE(strm, strm->state->window);\n\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n\n    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;\n}\n\n/* =========================================================================\n * Copy the source state to the destination state.\n * To simplify the source, this is not supported for 16-bit MSDOS (which\n * doesn't have enough memory anyway to duplicate compression states).\n */\nint ZEXPORT deflateCopy (dest, source)\n    z_streamp dest;\n    z_streamp source;\n{\n#ifdef MAXSEG_64K\n    return Z_STREAM_ERROR;\n#else\n    deflate_state *ds;\n    deflate_state *ss;\n    ushf *overlay;\n\n\n    if (deflateStateCheck(source) || dest == Z_NULL) {\n        return Z_STREAM_ERROR;\n    }\n\n    ss = source->state;\n\n    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));\n\n    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));\n    if (ds == Z_NULL) return Z_MEM_ERROR;\n    dest->state = (struct internal_state FAR *) ds;\n    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));\n    ds->strm = dest;\n\n    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));\n    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));\n    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));\n    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);\n    ds->pending_buf = (uchf *) overlay;\n\n    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||\n        ds->pending_buf == Z_NULL) {\n        deflateEnd (dest);\n        return Z_MEM_ERROR;\n    }\n    /* following zmemcpy do not work for 16-bit MSDOS */\n    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));\n    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));\n    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));\n    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);\n\n    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);\n    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);\n    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;\n\n    ds->l_desc.dyn_tree = ds->dyn_ltree;\n    ds->d_desc.dyn_tree = ds->dyn_dtree;\n    ds->bl_desc.dyn_tree = ds->bl_tree;\n\n    return Z_OK;\n#endif /* MAXSEG_64K */\n}\n\n/* ===========================================================================\n * Read a new buffer from the current input stream, update the adler32\n * and total number of bytes read.  All deflate() input goes through\n * this function so some applications may wish to modify it to avoid\n * allocating a large strm->next_in buffer and copying from it.\n * (See also flush_pending()).\n */\nlocal unsigned read_buf(strm, buf, size)\n    z_streamp strm;\n    Bytef *buf;\n    unsigned size;\n{\n    unsigned len = strm->avail_in;\n\n    if (len > size) len = size;\n    if (len == 0) return 0;\n\n    strm->avail_in  -= len;\n\n    zmemcpy(buf, strm->next_in, len);\n    if (strm->state->wrap == 1) {\n        strm->adler = adler32(strm->adler, buf, len);\n    }\n#ifdef GZIP\n    else if (strm->state->wrap == 2) {\n        strm->adler = crc32(strm->adler, buf, len);\n    }\n#endif\n    strm->next_in  += len;\n    strm->total_in += len;\n\n    return len;\n}\n\n/* ===========================================================================\n * Initialize the \"longest match\" routines for a new zlib stream\n */\nlocal void lm_init (s)\n    deflate_state *s;\n{\n    s->window_size = (ulg)2L*s->w_size;\n\n    CLEAR_HASH(s);\n\n    /* Set the default configuration parameters:\n     */\n    s->max_lazy_match   = configuration_table[s->level].max_lazy;\n    s->good_match       = configuration_table[s->level].good_length;\n    s->nice_match       = configuration_table[s->level].nice_length;\n    s->max_chain_length = configuration_table[s->level].max_chain;\n\n    s->strstart = 0;\n    s->block_start = 0L;\n    s->lookahead = 0;\n    s->insert = 0;\n    s->match_length = s->prev_length = MIN_MATCH-1;\n    s->match_available = 0;\n    s->ins_h = 0;\n#ifndef FASTEST\n#ifdef ASMV\n    match_init(); /* initialize the asm code */\n#endif\n#endif\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Set match_start to the longest match starting at the given string and\n * return its length. Matches shorter or equal to prev_length are discarded,\n * in which case the result is equal to prev_length and match_start is\n * garbage.\n * IN assertions: cur_match is the head of the hash chain for the current\n *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1\n * OUT assertion: the match length is not greater than s->lookahead.\n */\n#ifndef ASMV\n/* For 80x86 and 680x0, an optimized version will be provided in match.asm or\n * match.S. The code will be functionally equivalent.\n */\nlocal uInt longest_match(s, cur_match)\n    deflate_state *s;\n    IPos cur_match;                             /* current match */\n{\n    unsigned chain_length = s->max_chain_length;/* max hash chain length */\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                      /* matched string */\n    register int len;                           /* length of current match */\n    int best_len = (int)s->prev_length;         /* best match length so far */\n    int nice_match = s->nice_match;             /* stop if match long enough */\n    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?\n        s->strstart - (IPos)MAX_DIST(s) : NIL;\n    /* Stop when cur_match becomes <= limit. To simplify the code,\n     * we prevent matches with the string of window index 0.\n     */\n    Posf *prev = s->prev;\n    uInt wmask = s->w_mask;\n\n#ifdef UNALIGNED_OK\n    /* Compare two bytes at a time. Note: this is not always beneficial.\n     * Try with and without -DUNALIGNED_OK to check.\n     */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;\n    register ush scan_start = *(ushf*)scan;\n    register ush scan_end   = *(ushf*)(scan+best_len-1);\n#else\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n    register Byte scan_end1  = scan[best_len-1];\n    register Byte scan_end   = scan[best_len];\n#endif\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    /* Do not waste too much time if we already have a good match: */\n    if (s->prev_length >= s->good_match) {\n        chain_length >>= 2;\n    }\n    /* Do not look for matches beyond the end of the input. This is necessary\n     * to make deflate deterministic.\n     */\n    if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;\n\n    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n    do {\n        Assert(cur_match < s->strstart, \"no future\");\n        match = s->window + cur_match;\n\n        /* Skip to next match if the match length cannot increase\n         * or if the match length is less than 2.  Note that the checks below\n         * for insufficient lookahead only occur occasionally for performance\n         * reasons.  Therefore uninitialized memory will be accessed, and\n         * conditional jumps will be made that depend on those values.\n         * However the length of the match is limited to the lookahead, so\n         * the output of deflate is not affected by the uninitialized values.\n         */\n#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)\n        /* This code assumes sizeof(unsigned short) == 2. Do not use\n         * UNALIGNED_OK if your compiler uses a different size.\n         */\n        if (*(ushf*)(match+best_len-1) != scan_end ||\n            *(ushf*)match != scan_start) continue;\n\n        /* It is not necessary to compare scan[2] and match[2] since they are\n         * always equal when the other bytes match, given that the hash keys\n         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at\n         * strstart+3, +5, ... up to strstart+257. We check for insufficient\n         * lookahead only every 4th comparison; the 128th check will be made\n         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is\n         * necessary to put more guard bytes at the end of the window, or\n         * to check more often for insufficient lookahead.\n         */\n        Assert(scan[2] == match[2], \"scan[2]?\");\n        scan++, match++;\n        do {\n        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&\n                 scan < strend);\n        /* The funny \"do {}\" generates better code on most compilers */\n\n        /* Here, scan <= window+strstart+257 */\n        Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n        if (*scan == *match) scan++;\n\n        len = (MAX_MATCH - 1) - (int)(strend-scan);\n        scan = strend - (MAX_MATCH-1);\n\n#else /* UNALIGNED_OK */\n\n        if (match[best_len]   != scan_end  ||\n            match[best_len-1] != scan_end1 ||\n            *match            != *scan     ||\n            *++match          != scan[1])      continue;\n\n        /* The check at best_len-1 can be removed because it will be made\n         * again later. (This heuristic is not always a win.)\n         * It is not necessary to compare scan[2] and match[2] since they\n         * are always equal when the other bytes match, given that\n         * the hash keys are equal and that HASH_BITS >= 8.\n         */\n        scan += 2, match++;\n        Assert(*scan == *match, \"match[2]?\");\n\n        /* We check for insufficient lookahead only every 8th comparison;\n         * the 256th check will be made at strstart+258.\n         */\n        do {\n        } while (*++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 *++scan == *++match && *++scan == *++match &&\n                 scan < strend);\n\n        Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n        len = MAX_MATCH - (int)(strend - scan);\n        scan = strend - MAX_MATCH;\n\n#endif /* UNALIGNED_OK */\n\n        if (len > best_len) {\n            s->match_start = cur_match;\n            best_len = len;\n            if (len >= nice_match) break;\n#ifdef UNALIGNED_OK\n            scan_end = *(ushf*)(scan+best_len-1);\n#else\n            scan_end1  = scan[best_len-1];\n            scan_end   = scan[best_len];\n#endif\n        }\n    } while ((cur_match = prev[cur_match & wmask]) > limit\n             && --chain_length != 0);\n\n    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;\n    return s->lookahead;\n}\n#endif /* ASMV */\n\n#else /* FASTEST */\n\n/* ---------------------------------------------------------------------------\n * Optimized version for FASTEST only\n */\nlocal uInt longest_match(s, cur_match)\n    deflate_state *s;\n    IPos cur_match;                             /* current match */\n{\n    register Bytef *scan = s->window + s->strstart; /* current string */\n    register Bytef *match;                       /* matched string */\n    register int len;                           /* length of current match */\n    register Bytef *strend = s->window + s->strstart + MAX_MATCH;\n\n    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.\n     * It is easy to get rid of this optimization if necessary.\n     */\n    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, \"Code too clever\");\n\n    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, \"need lookahead\");\n\n    Assert(cur_match < s->strstart, \"no future\");\n\n    match = s->window + cur_match;\n\n    /* Return failure if the match length is less than 2:\n     */\n    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;\n\n    /* The check at best_len-1 can be removed because it will be made\n     * again later. (This heuristic is not always a win.)\n     * It is not necessary to compare scan[2] and match[2] since they\n     * are always equal when the other bytes match, given that\n     * the hash keys are equal and that HASH_BITS >= 8.\n     */\n    scan += 2, match += 2;\n    Assert(*scan == *match, \"match[2]?\");\n\n    /* We check for insufficient lookahead only every 8th comparison;\n     * the 256th check will be made at strstart+258.\n     */\n    do {\n    } while (*++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             *++scan == *++match && *++scan == *++match &&\n             scan < strend);\n\n    Assert(scan <= s->window+(unsigned)(s->window_size-1), \"wild scan\");\n\n    len = MAX_MATCH - (int)(strend - scan);\n\n    if (len < MIN_MATCH) return MIN_MATCH - 1;\n\n    s->match_start = cur_match;\n    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;\n}\n\n#endif /* FASTEST */\n\n#ifdef ZLIB_DEBUG\n\n#define EQUAL 0\n/* result of memcmp for equal strings */\n\n/* ===========================================================================\n * Check that the match at match_start is indeed a match.\n */\nlocal void check_match(s, start, match, length)\n    deflate_state *s;\n    IPos start, match;\n    int length;\n{\n    /* check that the match is indeed a match */\n    if (zmemcmp(s->window + match,\n                s->window + start, length) != EQUAL) {\n        fprintf(stderr, \" start %u, match %u, length %d\\n\",\n                start, match, length);\n        do {\n            fprintf(stderr, \"%c%c\", s->window[match++], s->window[start++]);\n        } while (--length != 0);\n        z_error(\"invalid match\");\n    }\n    if (z_verbose > 1) {\n        fprintf(stderr,\"\\\\[%d,%d]\", start-match, length);\n        do { putc(s->window[start++], stderr); } while (--length != 0);\n    }\n}\n#else\n#  define check_match(s, start, match, length)\n#endif /* ZLIB_DEBUG */\n\n/* ===========================================================================\n * Fill the window when the lookahead becomes insufficient.\n * Updates strstart and lookahead.\n *\n * IN assertion: lookahead < MIN_LOOKAHEAD\n * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD\n *    At least one byte has been read, or avail_in == 0; reads are\n *    performed for at least two bytes (required for the zip translate_eol\n *    option -- not supported here).\n */\nlocal void fill_window(s)\n    deflate_state *s;\n{\n    unsigned n;\n    unsigned more;    /* Amount of free space at the end of the window. */\n    uInt wsize = s->w_size;\n\n    Assert(s->lookahead < MIN_LOOKAHEAD, \"already enough lookahead\");\n\n    do {\n        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);\n\n        /* Deal with !@#$% 64K limit: */\n        if (sizeof(int) <= 2) {\n            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {\n                more = wsize;\n\n            } else if (more == (unsigned)(-1)) {\n                /* Very unlikely, but possible on 16 bit machine if\n                 * strstart == 0 && lookahead == 1 (input done a byte at time)\n                 */\n                more--;\n            }\n        }\n\n        /* If the window is almost full and there is insufficient lookahead,\n         * move the upper half to the lower one to make room in the upper half.\n         */\n        if (s->strstart >= wsize+MAX_DIST(s)) {\n\n            zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);\n            s->match_start -= wsize;\n            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */\n            s->block_start -= (long) wsize;\n            slide_hash(s);\n            more += wsize;\n        }\n        if (s->strm->avail_in == 0) break;\n\n        /* If there was no sliding:\n         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&\n         *    more == window_size - lookahead - strstart\n         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)\n         * => more >= window_size - 2*WSIZE + 2\n         * In the BIG_MEM or MMAP case (not yet supported),\n         *   window_size == input_size + MIN_LOOKAHEAD  &&\n         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.\n         * Otherwise, window_size == 2*WSIZE so more >= 2.\n         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.\n         */\n        Assert(more >= 2, \"more < 2\");\n\n        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);\n        s->lookahead += n;\n\n        /* Initialize the hash value now that we have some input: */\n        if (s->lookahead + s->insert >= MIN_MATCH) {\n            uInt str = s->strstart - s->insert;\n            s->ins_h = s->window[str];\n            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);\n#if MIN_MATCH != 3\n            Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n            while (s->insert) {\n                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);\n#ifndef FASTEST\n                s->prev[str & s->w_mask] = s->head[s->ins_h];\n#endif\n                s->head[s->ins_h] = (Pos)str;\n                str++;\n                s->insert--;\n                if (s->lookahead + s->insert < MIN_MATCH)\n                    break;\n            }\n        }\n        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,\n         * but this is not important since only literal bytes will be emitted.\n         */\n\n    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);\n\n    /* If the WIN_INIT bytes after the end of the current data have never been\n     * written, then zero those bytes in order to avoid memory check reports of\n     * the use of uninitialized (or uninitialised as Julian writes) bytes by\n     * the longest match routines.  Update the high water mark for the next\n     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match\n     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.\n     */\n    if (s->high_water < s->window_size) {\n        ulg curr = s->strstart + (ulg)(s->lookahead);\n        ulg init;\n\n        if (s->high_water < curr) {\n            /* Previous high water mark below current data -- zero WIN_INIT\n             * bytes or up to end of window, whichever is less.\n             */\n            init = s->window_size - curr;\n            if (init > WIN_INIT)\n                init = WIN_INIT;\n            zmemzero(s->window + curr, (unsigned)init);\n            s->high_water = curr + init;\n        }\n        else if (s->high_water < (ulg)curr + WIN_INIT) {\n            /* High water mark at or above current data, but below current data\n             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up\n             * to end of window, whichever is less.\n             */\n            init = (ulg)curr + WIN_INIT - s->high_water;\n            if (init > s->window_size - s->high_water)\n                init = s->window_size - s->high_water;\n            zmemzero(s->window + s->high_water, (unsigned)init);\n            s->high_water += init;\n        }\n    }\n\n    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,\n           \"not enough room for search\");\n}\n\n/* ===========================================================================\n * Flush the current block, with given end-of-file flag.\n * IN assertion: strstart is set to the end of the current match.\n */\n#define FLUSH_BLOCK_ONLY(s, last) { \\\n   _tr_flush_block(s, (s->block_start >= 0L ? \\\n                   (charf *)&s->window[(unsigned)s->block_start] : \\\n                   (charf *)Z_NULL), \\\n                (ulg)((long)s->strstart - s->block_start), \\\n                (last)); \\\n   s->block_start = s->strstart; \\\n   flush_pending(s->strm); \\\n   Tracev((stderr,\"[FLUSH]\")); \\\n}\n\n/* Same but force premature exit if necessary. */\n#define FLUSH_BLOCK(s, last) { \\\n   FLUSH_BLOCK_ONLY(s, last); \\\n   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \\\n}\n\n/* Maximum stored block length in deflate format (not including header). */\n#define MAX_STORED 65535\n\n/* Minimum of a and b. */\n#define MIN(a, b) ((a) > (b) ? (b) : (a))\n\n/* ===========================================================================\n * Copy without compression as much as possible from the input stream, return\n * the current block state.\n *\n * In case deflateParams() is used to later switch to a non-zero compression\n * level, s->matches (otherwise unused when storing) keeps track of the number\n * of hash table slides to perform. If s->matches is 1, then one hash table\n * slide will be done when switching. If s->matches is 2, the maximum value\n * allowed here, then the hash table will be cleared, since two or more slides\n * is the same as a clear.\n *\n * deflate_stored() is written to minimize the number of times an input byte is\n * copied. It is most efficient with large input and output buffers, which\n * maximizes the opportunites to have a single copy from next_in to next_out.\n */\nlocal block_state deflate_stored(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    /* Smallest worthy block size when not flushing or finishing. By default\n     * this is 32K. This can be as small as 507 bytes for memLevel == 1. For\n     * large input and output buffers, the stored block size will be larger.\n     */\n    unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);\n\n    /* Copy as many min_block or larger stored blocks directly to next_out as\n     * possible. If flushing, copy the remaining available input to next_out as\n     * stored blocks, if there is enough space.\n     */\n    unsigned len, left, have, last = 0;\n    unsigned used = s->strm->avail_in;\n    do {\n        /* Set len to the maximum size block that we can copy directly with the\n         * available input data and output space. Set left to how much of that\n         * would be copied from what's left in the window.\n         */\n        len = MAX_STORED;       /* maximum deflate stored block length */\n        have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        if (s->strm->avail_out < have)          /* need room for header */\n            break;\n            /* maximum stored block length that will fit in avail_out: */\n        have = s->strm->avail_out - have;\n        left = s->strstart - s->block_start;    /* bytes left in window */\n        if (len > (ulg)left + s->strm->avail_in)\n            len = left + s->strm->avail_in;     /* limit len to the input */\n        if (len > have)\n            len = have;                         /* limit len to the output */\n\n        /* If the stored block would be less than min_block in length, or if\n         * unable to copy all of the available input when flushing, then try\n         * copying to the window and the pending buffer instead. Also don't\n         * write an empty block when flushing -- deflate() does that.\n         */\n        if (len < min_block && ((len == 0 && flush != Z_FINISH) ||\n                                flush == Z_NO_FLUSH ||\n                                len != left + s->strm->avail_in))\n            break;\n\n        /* Make a dummy stored block in pending to get the header bytes,\n         * including any pending bits. This also updates the debugging counts.\n         */\n        last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;\n        _tr_stored_block(s, (char *)0, 0L, last);\n\n        /* Replace the lengths in the dummy stored block with len. */\n        s->pending_buf[s->pending - 4] = len;\n        s->pending_buf[s->pending - 3] = len >> 8;\n        s->pending_buf[s->pending - 2] = ~len;\n        s->pending_buf[s->pending - 1] = ~len >> 8;\n\n        /* Write the stored block header bytes. */\n        flush_pending(s->strm);\n\n#ifdef ZLIB_DEBUG\n        /* Update debugging counts for the data about to be copied. */\n        s->compressed_len += len << 3;\n        s->bits_sent += len << 3;\n#endif\n\n        /* Copy uncompressed bytes from the window to next_out. */\n        if (left) {\n            if (left > len)\n                left = len;\n            zmemcpy(s->strm->next_out, s->window + s->block_start, left);\n            s->strm->next_out += left;\n            s->strm->avail_out -= left;\n            s->strm->total_out += left;\n            s->block_start += left;\n            len -= left;\n        }\n\n        /* Copy uncompressed bytes directly from next_in to next_out, updating\n         * the check value.\n         */\n        if (len) {\n            read_buf(s->strm, s->strm->next_out, len);\n            s->strm->next_out += len;\n            s->strm->avail_out -= len;\n            s->strm->total_out += len;\n        }\n    } while (last == 0);\n\n    /* Update the sliding window with the last s->w_size bytes of the copied\n     * data, or append all of the copied data to the existing window if less\n     * than s->w_size bytes were copied. Also update the number of bytes to\n     * insert in the hash tables, in the event that deflateParams() switches to\n     * a non-zero compression level.\n     */\n    used -= s->strm->avail_in;      /* number of input bytes directly copied */\n    if (used) {\n        /* If any input was used, then no unused input remains in the window,\n         * therefore s->block_start == s->strstart.\n         */\n        if (used >= s->w_size) {    /* supplant the previous history */\n            s->matches = 2;         /* clear hash */\n            zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);\n            s->strstart = s->w_size;\n        }\n        else {\n            if (s->window_size - s->strstart <= used) {\n                /* Slide the window down. */\n                s->strstart -= s->w_size;\n                zmemcpy(s->window, s->window + s->w_size, s->strstart);\n                if (s->matches < 2)\n                    s->matches++;   /* add a pending slide_hash() */\n            }\n            zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);\n            s->strstart += used;\n        }\n        s->block_start = s->strstart;\n        s->insert += MIN(used, s->w_size - s->insert);\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* If the last block was written to next_out, then done. */\n    if (last)\n        return finish_done;\n\n    /* If flushing and all input has been consumed, then done. */\n    if (flush != Z_NO_FLUSH && flush != Z_FINISH &&\n        s->strm->avail_in == 0 && (long)s->strstart == s->block_start)\n        return block_done;\n\n    /* Fill the window with any remaining input. */\n    have = s->window_size - s->strstart - 1;\n    if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {\n        /* Slide the window down. */\n        s->block_start -= s->w_size;\n        s->strstart -= s->w_size;\n        zmemcpy(s->window, s->window + s->w_size, s->strstart);\n        if (s->matches < 2)\n            s->matches++;           /* add a pending slide_hash() */\n        have += s->w_size;          /* more space now */\n    }\n    if (have > s->strm->avail_in)\n        have = s->strm->avail_in;\n    if (have) {\n        read_buf(s->strm, s->window + s->strstart, have);\n        s->strstart += have;\n    }\n    if (s->high_water < s->strstart)\n        s->high_water = s->strstart;\n\n    /* There was not enough avail_out to write a complete worthy or flushed\n     * stored block to next_out. Write a stored block to pending instead, if we\n     * have enough input for a worthy block, or if flushing and there is enough\n     * room for the remaining input as a stored block in the pending buffer.\n     */\n    have = (s->bi_valid + 42) >> 3;         /* number of header bytes */\n        /* maximum stored block length that will fit in pending: */\n    have = MIN(s->pending_buf_size - have, MAX_STORED);\n    min_block = MIN(have, s->w_size);\n    left = s->strstart - s->block_start;\n    if (left >= min_block ||\n        ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&\n         s->strm->avail_in == 0 && left <= have)) {\n        len = MIN(left, have);\n        last = flush == Z_FINISH && s->strm->avail_in == 0 &&\n               len == left ? 1 : 0;\n        _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);\n        s->block_start += len;\n        flush_pending(s->strm);\n    }\n\n    /* We've done all we can with the available input and output. */\n    return last ? finish_started : need_more;\n}\n\n/* ===========================================================================\n * Compress as much as possible from the input stream, return the current\n * block state.\n * This function does not perform lazy evaluation of matches and inserts\n * new strings in the dictionary only for unmatched strings or for short\n * matches. It is used only for the fast compression options.\n */\nlocal block_state deflate_fast(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    IPos hash_head;       /* head of the hash chain */\n    int bflush;           /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart+2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         * At this point we have always match_length < MIN_MATCH\n         */\n        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n        }\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->match_start, s->match_length);\n\n            _tr_tally_dist(s, s->strstart - s->match_start,\n                           s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n\n            /* Insert new strings in the hash table only if the match length\n             * is not too large. This saves time but degrades compression.\n             */\n#ifndef FASTEST\n            if (s->match_length <= s->max_insert_length &&\n                s->lookahead >= MIN_MATCH) {\n                s->match_length--; /* string at strstart already in table */\n                do {\n                    s->strstart++;\n                    INSERT_STRING(s, s->strstart, hash_head);\n                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are\n                     * always MIN_MATCH bytes ahead.\n                     */\n                } while (--s->match_length != 0);\n                s->strstart++;\n            } else\n#endif\n            {\n                s->strstart += s->match_length;\n                s->match_length = 0;\n                s->ins_h = s->window[s->strstart];\n                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);\n#if MIN_MATCH != 3\n                Call UPDATE_HASH() MIN_MATCH-3 more times\n#endif\n                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not\n                 * matter since it will be recomputed at next deflate call.\n                 */\n            }\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit (s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n#ifndef FASTEST\n/* ===========================================================================\n * Same as above, but achieves better compression. We use a lazy\n * evaluation for matches: a match is finally adopted only if there is\n * no better match at the next window position.\n */\nlocal block_state deflate_slow(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    IPos hash_head;          /* head of hash chain */\n    int bflush;              /* set if current block must be flushed */\n\n    /* Process the input block. */\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the next match, plus MIN_MATCH bytes to insert the\n         * string following the next match.\n         */\n        if (s->lookahead < MIN_LOOKAHEAD) {\n            fill_window(s);\n            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* Insert the string window[strstart .. strstart+2] in the\n         * dictionary, and set hash_head to the head of the hash chain:\n         */\n        hash_head = NIL;\n        if (s->lookahead >= MIN_MATCH) {\n            INSERT_STRING(s, s->strstart, hash_head);\n        }\n\n        /* Find the longest match, discarding those <= prev_length.\n         */\n        s->prev_length = s->match_length, s->prev_match = s->match_start;\n        s->match_length = MIN_MATCH-1;\n\n        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&\n            s->strstart - hash_head <= MAX_DIST(s)) {\n            /* To simplify the code, we prevent matches with the string\n             * of window index 0 (in particular we have to avoid a match\n             * of the string with itself at the start of the input file).\n             */\n            s->match_length = longest_match (s, hash_head);\n            /* longest_match() sets match_start */\n\n            if (s->match_length <= 5 && (s->strategy == Z_FILTERED\n#if TOO_FAR <= 32767\n                || (s->match_length == MIN_MATCH &&\n                    s->strstart - s->match_start > TOO_FAR)\n#endif\n                )) {\n\n                /* If prev_match is also MIN_MATCH, match_start is garbage\n                 * but we will ignore the current match anyway.\n                 */\n                s->match_length = MIN_MATCH-1;\n            }\n        }\n        /* If there was a match at the previous step and the current\n         * match is not better, output the previous match:\n         */\n        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {\n            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;\n            /* Do not insert strings in hash table beyond this. */\n\n            check_match(s, s->strstart-1, s->prev_match, s->prev_length);\n\n            _tr_tally_dist(s, s->strstart -1 - s->prev_match,\n                           s->prev_length - MIN_MATCH, bflush);\n\n            /* Insert in hash table all strings up to the end of the match.\n             * strstart-1 and strstart are already inserted. If there is not\n             * enough lookahead, the last two strings are not inserted in\n             * the hash table.\n             */\n            s->lookahead -= s->prev_length-1;\n            s->prev_length -= 2;\n            do {\n                if (++s->strstart <= max_insert) {\n                    INSERT_STRING(s, s->strstart, hash_head);\n                }\n            } while (--s->prev_length != 0);\n            s->match_available = 0;\n            s->match_length = MIN_MATCH-1;\n            s->strstart++;\n\n            if (bflush) FLUSH_BLOCK(s, 0);\n\n        } else if (s->match_available) {\n            /* If there was no match at the previous position, output a\n             * single literal. If there was a match but the current match\n             * is longer, truncate the previous match to a single literal.\n             */\n            Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n            _tr_tally_lit(s, s->window[s->strstart-1], bflush);\n            if (bflush) {\n                FLUSH_BLOCK_ONLY(s, 0);\n            }\n            s->strstart++;\n            s->lookahead--;\n            if (s->strm->avail_out == 0) return need_more;\n        } else {\n            /* There is no previous match to compare with, wait for\n             * the next step to decide.\n             */\n            s->match_available = 1;\n            s->strstart++;\n            s->lookahead--;\n        }\n    }\n    Assert (flush != Z_NO_FLUSH, \"no flush?\");\n    if (s->match_available) {\n        Tracevv((stderr,\"%c\", s->window[s->strstart-1]));\n        _tr_tally_lit(s, s->window[s->strstart-1], bflush);\n        s->match_available = 0;\n    }\n    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n#endif /* FASTEST */\n\n/* ===========================================================================\n * For Z_RLE, simply look for runs of bytes, generate matches only of distance\n * one.  Do not maintain a hash table.  (It will be regenerated if this run of\n * deflate switches away from Z_RLE.)\n */\nlocal block_state deflate_rle(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    int bflush;             /* set if current block must be flushed */\n    uInt prev;              /* byte at distance one to match */\n    Bytef *scan, *strend;   /* scan goes up to strend for length of run */\n\n    for (;;) {\n        /* Make sure that we always have enough lookahead, except\n         * at the end of the input file. We need MAX_MATCH bytes\n         * for the longest run, plus one for the unrolled loop.\n         */\n        if (s->lookahead <= MAX_MATCH) {\n            fill_window(s);\n            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {\n                return need_more;\n            }\n            if (s->lookahead == 0) break; /* flush the current block */\n        }\n\n        /* See how many times the previous byte repeats */\n        s->match_length = 0;\n        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {\n            scan = s->window + s->strstart - 1;\n            prev = *scan;\n            if (prev == *++scan && prev == *++scan && prev == *++scan) {\n                strend = s->window + s->strstart + MAX_MATCH;\n                do {\n                } while (prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         prev == *++scan && prev == *++scan &&\n                         scan < strend);\n                s->match_length = MAX_MATCH - (uInt)(strend - scan);\n                if (s->match_length > s->lookahead)\n                    s->match_length = s->lookahead;\n            }\n            Assert(scan <= s->window+(uInt)(s->window_size-1), \"wild scan\");\n        }\n\n        /* Emit match if have run of MIN_MATCH or longer, else emit literal */\n        if (s->match_length >= MIN_MATCH) {\n            check_match(s, s->strstart, s->strstart - 1, s->match_length);\n\n            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);\n\n            s->lookahead -= s->match_length;\n            s->strstart += s->match_length;\n            s->match_length = 0;\n        } else {\n            /* No match, output a literal byte */\n            Tracevv((stderr,\"%c\", s->window[s->strstart]));\n            _tr_tally_lit (s, s->window[s->strstart], bflush);\n            s->lookahead--;\n            s->strstart++;\n        }\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n\n/* ===========================================================================\n * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.\n * (It will be regenerated if this run of deflate switches away from Huffman.)\n */\nlocal block_state deflate_huff(s, flush)\n    deflate_state *s;\n    int flush;\n{\n    int bflush;             /* set if current block must be flushed */\n\n    for (;;) {\n        /* Make sure that we have a literal to write. */\n        if (s->lookahead == 0) {\n            fill_window(s);\n            if (s->lookahead == 0) {\n                if (flush == Z_NO_FLUSH)\n                    return need_more;\n                break;      /* flush the current block */\n            }\n        }\n\n        /* Output a literal byte */\n        s->match_length = 0;\n        Tracevv((stderr,\"%c\", s->window[s->strstart]));\n        _tr_tally_lit (s, s->window[s->strstart], bflush);\n        s->lookahead--;\n        s->strstart++;\n        if (bflush) FLUSH_BLOCK(s, 0);\n    }\n    s->insert = 0;\n    if (flush == Z_FINISH) {\n        FLUSH_BLOCK(s, 1);\n        return finish_done;\n    }\n    if (s->last_lit)\n        FLUSH_BLOCK(s, 0);\n    return block_done;\n}\n"
  },
  {
    "path": "dlib/external/zlib/deflate.h",
    "content": "/* deflate.h -- internal compression state\n * Copyright (C) 1995-2016 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef DEFLATE_H\n#define DEFLATE_H\n\n#include \"zutil.h\"\n\n/* define NO_GZIP when compiling if you want to disable gzip header and\n   trailer creation by deflate().  NO_GZIP would be used to avoid linking in\n   the crc code when it is not needed.  For shared libraries, gzip encoding\n   should be left enabled. */\n#ifndef NO_GZIP\n#  define GZIP\n#endif\n\n/* ===========================================================================\n * Internal compression state.\n */\n\n#define LENGTH_CODES 29\n/* number of length codes, not counting the special END_BLOCK code */\n\n#define LITERALS  256\n/* number of literal bytes 0..255 */\n\n#define L_CODES (LITERALS+1+LENGTH_CODES)\n/* number of Literal or Length codes, including the END_BLOCK code */\n\n#define D_CODES   30\n/* number of distance codes */\n\n#define BL_CODES  19\n/* number of codes used to transfer the bit lengths */\n\n#define HEAP_SIZE (2*L_CODES+1)\n/* maximum heap size */\n\n#define MAX_BITS 15\n/* All codes must not exceed MAX_BITS bits */\n\n#define Buf_size 16\n/* size of bit buffer in bi_buf */\n\n#define INIT_STATE    42    /* zlib header -> BUSY_STATE */\n#ifdef GZIP\n#  define GZIP_STATE  57    /* gzip header -> BUSY_STATE | EXTRA_STATE */\n#endif\n#define EXTRA_STATE   69    /* gzip extra block -> NAME_STATE */\n#define NAME_STATE    73    /* gzip file name -> COMMENT_STATE */\n#define COMMENT_STATE 91    /* gzip comment -> HCRC_STATE */\n#define HCRC_STATE   103    /* gzip header CRC -> BUSY_STATE */\n#define BUSY_STATE   113    /* deflate -> FINISH_STATE */\n#define FINISH_STATE 666    /* stream complete */\n/* Stream status */\n\n\n/* Data structure describing a single value and its code string. */\ntypedef struct ct_data_s {\n    union {\n        ush  freq;       /* frequency count */\n        ush  code;       /* bit string */\n    } fc;\n    union {\n        ush  dad;        /* father node in Huffman tree */\n        ush  len;        /* length of bit string */\n    } dl;\n} FAR ct_data;\n\n#define Freq fc.freq\n#define Code fc.code\n#define Dad  dl.dad\n#define Len  dl.len\n\ntypedef struct static_tree_desc_s  static_tree_desc;\n\ntypedef struct tree_desc_s {\n    ct_data *dyn_tree;           /* the dynamic tree */\n    int     max_code;            /* largest code with non zero frequency */\n    const static_tree_desc *stat_desc;  /* the corresponding static tree */\n} FAR tree_desc;\n\ntypedef ush Pos;\ntypedef Pos FAR Posf;\ntypedef unsigned IPos;\n\n/* A Pos is an index in the character window. We use short instead of int to\n * save space in the various tables. IPos is used only for parameter passing.\n */\n\ntypedef struct internal_state {\n    z_streamp strm;      /* pointer back to this zlib stream */\n    int   status;        /* as the name implies */\n    Bytef *pending_buf;  /* output still pending */\n    ulg   pending_buf_size; /* size of pending_buf */\n    Bytef *pending_out;  /* next pending byte to output to the stream */\n    ulg   pending;       /* nb of bytes in the pending buffer */\n    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */\n    gz_headerp  gzhead;  /* gzip header information to write */\n    ulg   gzindex;       /* where in extra, name, or comment */\n    Byte  method;        /* can only be DEFLATED */\n    int   last_flush;    /* value of flush param for previous deflate call */\n\n                /* used by deflate.c: */\n\n    uInt  w_size;        /* LZ77 window size (32K by default) */\n    uInt  w_bits;        /* log2(w_size)  (8..16) */\n    uInt  w_mask;        /* w_size - 1 */\n\n    Bytef *window;\n    /* Sliding window. Input bytes are read into the second half of the window,\n     * and move to the first half later to keep a dictionary of at least wSize\n     * bytes. With this organization, matches are limited to a distance of\n     * wSize-MAX_MATCH bytes, but this ensures that IO is always\n     * performed with a length multiple of the block size. Also, it limits\n     * the window size to 64K, which is quite useful on MSDOS.\n     * To do: use the user input buffer as sliding window.\n     */\n\n    ulg window_size;\n    /* Actual size of window: 2*wSize, except when the user input buffer\n     * is directly used as sliding window.\n     */\n\n    Posf *prev;\n    /* Link to older string with same hash index. To limit the size of this\n     * array to 64K, this link is maintained only for the last 32K strings.\n     * An index in this array is thus a window index modulo 32K.\n     */\n\n    Posf *head; /* Heads of the hash chains or NIL. */\n\n    uInt  ins_h;          /* hash index of string to be inserted */\n    uInt  hash_size;      /* number of elements in hash table */\n    uInt  hash_bits;      /* log2(hash_size) */\n    uInt  hash_mask;      /* hash_size-1 */\n\n    uInt  hash_shift;\n    /* Number of bits by which ins_h must be shifted at each input\n     * step. It must be such that after MIN_MATCH steps, the oldest\n     * byte no longer takes part in the hash key, that is:\n     *   hash_shift * MIN_MATCH >= hash_bits\n     */\n\n    long block_start;\n    /* Window position at the beginning of the current output block. Gets\n     * negative when the window is moved backwards.\n     */\n\n    uInt match_length;           /* length of best match */\n    IPos prev_match;             /* previous match */\n    int match_available;         /* set if previous match exists */\n    uInt strstart;               /* start of string to insert */\n    uInt match_start;            /* start of matching string */\n    uInt lookahead;              /* number of valid bytes ahead in window */\n\n    uInt prev_length;\n    /* Length of the best match at previous step. Matches not greater than this\n     * are discarded. This is used in the lazy match evaluation.\n     */\n\n    uInt max_chain_length;\n    /* To speed up deflation, hash chains are never searched beyond this\n     * length.  A higher limit improves compression ratio but degrades the\n     * speed.\n     */\n\n    uInt max_lazy_match;\n    /* Attempt to find a better match only when the current match is strictly\n     * smaller than this value. This mechanism is used only for compression\n     * levels >= 4.\n     */\n#   define max_insert_length  max_lazy_match\n    /* Insert new strings in the hash table only if the match length is not\n     * greater than this length. This saves time but degrades compression.\n     * max_insert_length is used only for compression levels <= 3.\n     */\n\n    int level;    /* compression level (1..9) */\n    int strategy; /* favor or force Huffman coding*/\n\n    uInt good_match;\n    /* Use a faster search when the previous match is longer than this */\n\n    int nice_match; /* Stop searching when current match exceeds this */\n\n                /* used by trees.c: */\n    /* Didn't use ct_data typedef below to suppress compiler warning */\n    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */\n    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */\n    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */\n\n    struct tree_desc_s l_desc;               /* desc. for literal tree */\n    struct tree_desc_s d_desc;               /* desc. for distance tree */\n    struct tree_desc_s bl_desc;              /* desc. for bit length tree */\n\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */\n    int heap_len;               /* number of elements in the heap */\n    int heap_max;               /* element of largest frequency */\n    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.\n     * The same heap array is used to build all trees.\n     */\n\n    uch depth[2*L_CODES+1];\n    /* Depth of each subtree used as tie breaker for trees of equal frequency\n     */\n\n    uchf *l_buf;          /* buffer for literals or lengths */\n\n    uInt  lit_bufsize;\n    /* Size of match buffer for literals/lengths.  There are 4 reasons for\n     * limiting lit_bufsize to 64K:\n     *   - frequencies can be kept in 16 bit counters\n     *   - if compression is not successful for the first block, all input\n     *     data is still in the window so we can still emit a stored block even\n     *     when input comes from standard input.  (This can also be done for\n     *     all blocks if lit_bufsize is not greater than 32K.)\n     *   - if compression is not successful for a file smaller than 64K, we can\n     *     even emit a stored file instead of a stored block (saving 5 bytes).\n     *     This is applicable only for zip (not gzip or zlib).\n     *   - creating new Huffman trees less frequently may not provide fast\n     *     adaptation to changes in the input data statistics. (Take for\n     *     example a binary file with poorly compressible code followed by\n     *     a highly compressible string table.) Smaller buffer sizes give\n     *     fast adaptation but have of course the overhead of transmitting\n     *     trees more frequently.\n     *   - I can't count above 4\n     */\n\n    uInt last_lit;      /* running index in l_buf */\n\n    ushf *d_buf;\n    /* Buffer for distances. To simplify the code, d_buf and l_buf have\n     * the same number of elements. To use different lengths, an extra flag\n     * array would be necessary.\n     */\n\n    ulg opt_len;        /* bit length of current block with optimal trees */\n    ulg static_len;     /* bit length of current block with static trees */\n    uInt matches;       /* number of string matches in current block */\n    uInt insert;        /* bytes at end of window left to insert */\n\n#ifdef ZLIB_DEBUG\n    ulg compressed_len; /* total bit length of compressed file mod 2^32 */\n    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */\n#endif\n\n    ush bi_buf;\n    /* Output buffer. bits are inserted starting at the bottom (least\n     * significant bits).\n     */\n    int bi_valid;\n    /* Number of valid bits in bi_buf.  All bits above the last valid bit\n     * are always zero.\n     */\n\n    ulg high_water;\n    /* High water mark offset in window for initialized bytes -- bytes above\n     * this are set to zero in order to avoid memory check warnings when\n     * longest match routines access bytes past the input.  This is then\n     * updated to the new high water mark.\n     */\n\n} FAR deflate_state;\n\n/* Output a byte on the stream.\n * IN assertion: there is enough room in pending_buf.\n */\n#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}\n\n\n#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)\n/* Minimum amount of lookahead, except at the end of the input file.\n * See deflate.c for comments about the MIN_MATCH+1.\n */\n\n#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)\n/* In order to simplify the code, particularly on 16 bit machines, match\n * distances are limited to MAX_DIST instead of WSIZE.\n */\n\n#define WIN_INIT MAX_MATCH\n/* Number of bytes after end of data in window to initialize in order to avoid\n   memory checker errors from longest match routines */\n\n        /* in trees.c */\nvoid ZLIB_INTERNAL _tr_init OF((deflate_state *s));\nint ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));\nvoid ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,\n                        ulg stored_len, int last));\nvoid ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));\nvoid ZLIB_INTERNAL _tr_align OF((deflate_state *s));\nvoid ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,\n                        ulg stored_len, int last));\n\n#define d_code(dist) \\\n   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])\n/* Mapping from a distance to a distance code. dist is the distance - 1 and\n * must not have side effects. _dist_code[256] and _dist_code[257] are never\n * used.\n */\n\n#ifndef ZLIB_DEBUG\n/* Inline versions of _tr_tally for speed: */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n  extern uch ZLIB_INTERNAL _length_code[];\n  extern uch ZLIB_INTERNAL _dist_code[];\n#else\n  extern const uch ZLIB_INTERNAL _length_code[];\n  extern const uch ZLIB_INTERNAL _dist_code[];\n#endif\n\n# define _tr_tally_lit(s, c, flush) \\\n  { uch cc = (c); \\\n    s->d_buf[s->last_lit] = 0; \\\n    s->l_buf[s->last_lit++] = cc; \\\n    s->dyn_ltree[cc].Freq++; \\\n    flush = (s->last_lit == s->lit_bufsize-1); \\\n   }\n# define _tr_tally_dist(s, distance, length, flush) \\\n  { uch len = (uch)(length); \\\n    ush dist = (ush)(distance); \\\n    s->d_buf[s->last_lit] = dist; \\\n    s->l_buf[s->last_lit++] = len; \\\n    dist--; \\\n    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \\\n    s->dyn_dtree[d_code(dist)].Freq++; \\\n    flush = (s->last_lit == s->lit_bufsize-1); \\\n  }\n#else\n# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)\n# define _tr_tally_dist(s, distance, length, flush) \\\n              flush = _tr_tally(s, distance, length)\n#endif\n\n#endif /* DEFLATE_H */\n"
  },
  {
    "path": "dlib/external/zlib/gzclose.c",
    "content": "/* gzclose.c -- zlib gzclose() function\n * Copyright (C) 2004, 2010 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n/* gzclose() is in a separate file so that it is linked in only if it is used.\n   That way the other gzclose functions can be used instead to avoid linking in\n   unneeded compression or decompression routines. */\nint ZEXPORT gzclose(file)\n    gzFile file;\n{\n#ifndef NO_GZCOMPRESS\n    gz_statep state;\n\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);\n#else\n    return gzclose_r(file);\n#endif\n}\n"
  },
  {
    "path": "dlib/external/zlib/gzguts.h",
    "content": "/* gzguts.h -- zlib internal header definitions for gz* operations\n * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#ifdef _MSC_VER\n// Disable the following warnings for Visual Studio\n// This is a warning you get from visual studio 2005 about things in the standard C++\n// library being \"deprecated.\"  I checked the C++ standard and it doesn't say jack \n// about any of them (I checked the searchable PDF).   So this warning is total Bunk.\n#pragma warning(disable : 4996)\n#endif\n\n#ifdef _LARGEFILE64_SOURCE\n#  ifndef _LARGEFILE_SOURCE\n#    define _LARGEFILE_SOURCE 1\n#  endif\n#  ifdef _FILE_OFFSET_BITS\n#    undef _FILE_OFFSET_BITS\n#  endif\n#endif\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include <stdio.h>\n#include \"zlib.h\"\n#ifdef STDC\n#  include <string.h>\n#  include <stdlib.h>\n#  include <limits.h>\n#endif\n\n#ifndef _POSIX_SOURCE\n#  define _POSIX_SOURCE\n#endif\n#include <fcntl.h>\n\n#ifdef _WIN32\n#  include <stddef.h>\n#endif\n\n#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)\n#  include <io.h>\n#else\n#  include <unistd.h>\n#endif\n\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define WIDECHAR\n#endif\n\n#ifdef WINAPI_FAMILY\n#  define open _open\n#  define read _read\n#  define write _write\n#  define close _close\n#endif\n\n#ifdef NO_DEFLATE       /* for compatibility with old definition */\n#  define NO_GZCOMPRESS\n#endif\n\n#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(__CYGWIN__)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)\n#  ifndef HAVE_VSNPRINTF\n#    define HAVE_VSNPRINTF\n#  endif\n#endif\n\n#ifndef HAVE_VSNPRINTF\n#  ifdef MSDOS\n/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),\n   but for now we just assume it doesn't. */\n#    define NO_vsnprintf\n#  endif\n#  ifdef __TURBOC__\n#    define NO_vsnprintf\n#  endif\n#  ifdef WIN32\n/* In Win32, vsnprintf is available as the \"non-ANSI\" _vsnprintf. */\n#    if !defined(vsnprintf) && !defined(NO_vsnprintf)\n#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )\n#         define vsnprintf _vsnprintf\n#      endif\n#    endif\n#  endif\n#  ifdef __SASC\n#    define NO_vsnprintf\n#  endif\n#  ifdef VMS\n#    define NO_vsnprintf\n#  endif\n#  ifdef __OS400__\n#    define NO_vsnprintf\n#  endif\n#  ifdef __MVS__\n#    define NO_vsnprintf\n#  endif\n#endif\n\n/* unlike snprintf (which is required in C99), _snprintf does not guarantee\n   null termination of the result -- however this is only used in gzlib.c where\n   the result is assured to fit in the space provided */\n#if defined(_MSC_VER) && _MSC_VER < 1900\n#  define snprintf _snprintf\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\n/* gz* functions always use library allocation functions */\n#ifndef STDC\n  extern voidp  malloc OF((uInt size));\n  extern void   free   OF((voidpf ptr));\n#endif\n\n/* get errno and strerror definition */\n#if defined UNDER_CE\n#  include <windows.h>\n#  define zstrerror() gz_strwinerror((DWORD)GetLastError())\n#else\n#  ifndef NO_STRERROR\n#    include <errno.h>\n#    define zstrerror() strerror(errno)\n#  else\n#    define zstrerror() \"stdio error (consult errno)\"\n#  endif\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0\n    ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n    ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));\n    ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));\n    ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));\n#endif\n\n/* default memLevel */\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n\n/* default i/o buffer size -- double this for output when reading (this and\n   twice this must be able to fit in an unsigned type) */\n#define GZBUFSIZE 8192\n\n/* gzip modes, also provide a little integrity check on the passed structure */\n#define GZ_NONE 0\n#define GZ_READ 7247\n#define GZ_WRITE 31153\n#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */\n\n/* values for gz_state how */\n#define LOOK 0      /* look for a gzip header */\n#define COPY 1      /* copy input directly */\n#define GZIP 2      /* decompress a gzip stream */\n\n/* internal gzip file state data structure */\ntypedef struct {\n        /* exposed contents for gzgetc() macro */\n    struct gzFile_s x;      /* \"x\" for exposed */\n                            /* x.have: number of bytes available at x.next */\n                            /* x.next: next output data to deliver or write */\n                            /* x.pos: current position in uncompressed data */\n        /* used for both reading and writing */\n    int mode;               /* see gzip modes above */\n    int fd;                 /* file descriptor */\n    char *path;             /* path or fd for error messages */\n    unsigned size;          /* buffer size, zero if not allocated yet */\n    unsigned want;          /* requested buffer size, default is GZBUFSIZE */\n    unsigned char *in;      /* input buffer (double-sized when writing) */\n    unsigned char *out;     /* output buffer (double-sized when reading) */\n    int direct;             /* 0 if processing gzip, 1 if transparent */\n        /* just for reading */\n    int how;                /* 0: get header, 1: copy, 2: decompress */\n    z_off64_t start;        /* where the gzip data started, for rewinding */\n    int eof;                /* true if end of input file reached */\n    int past;               /* true if read requested past end */\n        /* just for writing */\n    int level;              /* compression level */\n    int strategy;           /* compression strategy */\n        /* seek request */\n    z_off64_t skip;         /* amount to skip (already rewound if backwards) */\n    int seek;               /* true if seek request pending */\n        /* error information */\n    int err;                /* error code */\n    char *msg;              /* error message */\n        /* zlib inflate or deflate stream */\n    z_stream strm;          /* stream structure in-place (not a pointer) */\n} gz_state;\ntypedef gz_state FAR *gz_statep;\n\n/* shared functions */\nvoid ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));\n#if defined UNDER_CE\nchar ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));\n#endif\n\n/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t\n   value -- needed when comparing unsigned to z_off64_t, which is signed\n   (possible z_off64_t types off_t, off64_t, and long are all signed) */\n#ifdef INT_MAX\n#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)\n#else\nunsigned ZLIB_INTERNAL gz_intmax OF((void));\n#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())\n#endif\n"
  },
  {
    "path": "dlib/external/zlib/gzlib.c",
    "content": "/* gzlib.c -- zlib functions common to reading and writing gzip files\n * Copyright (C) 2004-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)\n#  define LSEEK _lseeki64\n#else\n#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0\n#  define LSEEK lseek64\n#else\n#  define LSEEK lseek\n#endif\n#endif\n\n/* Local functions */\nlocal void gz_reset OF((gz_statep));\nlocal gzFile gz_open OF((const void *, int, const char *));\n\n#if defined UNDER_CE\n\n/* Map the Windows error number in ERROR to a locale-dependent error message\n   string and return a pointer to it.  Typically, the values for ERROR come\n   from GetLastError.\n\n   The string pointed to shall not be modified by the application, but may be\n   overwritten by a subsequent call to gz_strwinerror\n\n   The gz_strwinerror function does not change the current setting of\n   GetLastError. */\nchar ZLIB_INTERNAL *gz_strwinerror (error)\n     DWORD error;\n{\n    static char buf[1024];\n\n    wchar_t *msgbuf;\n    DWORD lasterr = GetLastError();\n    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM\n        | FORMAT_MESSAGE_ALLOCATE_BUFFER,\n        NULL,\n        error,\n        0, /* Default language */\n        (LPVOID)&msgbuf,\n        0,\n        NULL);\n    if (chars != 0) {\n        /* If there is an \\r\\n appended, zap it.  */\n        if (chars >= 2\n            && msgbuf[chars - 2] == '\\r' && msgbuf[chars - 1] == '\\n') {\n            chars -= 2;\n            msgbuf[chars] = 0;\n        }\n\n        if (chars > sizeof (buf) - 1) {\n            chars = sizeof (buf) - 1;\n            msgbuf[chars] = 0;\n        }\n\n        wcstombs(buf, msgbuf, chars + 1);\n        LocalFree(msgbuf);\n    }\n    else {\n        sprintf(buf, \"unknown win32 error (%ld)\", error);\n    }\n\n    SetLastError(lasterr);\n    return buf;\n}\n\n#endif /* UNDER_CE */\n\n/* Reset gzip file state */\nlocal void gz_reset(state)\n    gz_statep state;\n{\n    state->x.have = 0;              /* no output data available */\n    if (state->mode == GZ_READ) {   /* for reading ... */\n        state->eof = 0;             /* not at end of file */\n        state->past = 0;            /* have not read past end yet */\n        state->how = LOOK;          /* look for gzip header */\n    }\n    state->seek = 0;                /* no seek request pending */\n    gz_error(state, Z_OK, NULL);    /* clear error */\n    state->x.pos = 0;               /* no uncompressed data yet */\n    state->strm.avail_in = 0;       /* no input data yet */\n}\n\n/* Open a gzip file either by name or file descriptor. */\nlocal gzFile gz_open(path, fd, mode)\n    const void *path;\n    int fd;\n    const char *mode;\n{\n    gz_statep state;\n    z_size_t len;\n    int oflag;\n#ifdef O_CLOEXEC\n    int cloexec = 0;\n#endif\n#ifdef O_EXCL\n    int exclusive = 0;\n#endif\n\n    /* check input */\n    if (path == NULL)\n        return NULL;\n\n    /* allocate gzFile structure to return */\n    state = (gz_statep)malloc(sizeof(gz_state));\n    if (state == NULL)\n        return NULL;\n    state->size = 0;            /* no buffers allocated yet */\n    state->want = GZBUFSIZE;    /* requested buffer size */\n    state->msg = NULL;          /* no error message yet */\n\n    /* interpret mode */\n    state->mode = GZ_NONE;\n    state->level = Z_DEFAULT_COMPRESSION;\n    state->strategy = Z_DEFAULT_STRATEGY;\n    state->direct = 0;\n    while (*mode) {\n        if (*mode >= '0' && *mode <= '9')\n            state->level = *mode - '0';\n        else\n            switch (*mode) {\n            case 'r':\n                state->mode = GZ_READ;\n                break;\n#ifndef NO_GZCOMPRESS\n            case 'w':\n                state->mode = GZ_WRITE;\n                break;\n            case 'a':\n                state->mode = GZ_APPEND;\n                break;\n#endif\n            case '+':       /* can't read and write at the same time */\n                free(state);\n                return NULL;\n            case 'b':       /* ignore -- will request binary anyway */\n                break;\n#ifdef O_CLOEXEC\n            case 'e':\n                cloexec = 1;\n                break;\n#endif\n#ifdef O_EXCL\n            case 'x':\n                exclusive = 1;\n                break;\n#endif\n            case 'f':\n                state->strategy = Z_FILTERED;\n                break;\n            case 'h':\n                state->strategy = Z_HUFFMAN_ONLY;\n                break;\n            case 'R':\n                state->strategy = Z_RLE;\n                break;\n            case 'F':\n                state->strategy = Z_FIXED;\n                break;\n            case 'T':\n                state->direct = 1;\n                break;\n            default:        /* could consider as an error, but just ignore */\n                ;\n            }\n        mode++;\n    }\n\n    /* must provide an \"r\", \"w\", or \"a\" */\n    if (state->mode == GZ_NONE) {\n        free(state);\n        return NULL;\n    }\n\n    /* can't force transparent read */\n    if (state->mode == GZ_READ) {\n        if (state->direct) {\n            free(state);\n            return NULL;\n        }\n        state->direct = 1;      /* for empty file */\n    }\n\n    /* save the path name for error messages */\n#ifdef WIDECHAR\n    if (fd == -2) {\n        len = wcstombs(NULL, path, 0);\n        if (len == (z_size_t)-1)\n            len = 0;\n    }\n    else\n#endif\n        len = strlen((const char *)path);\n    state->path = (char *)malloc(len + 1);\n    if (state->path == NULL) {\n        free(state);\n        return NULL;\n    }\n#ifdef WIDECHAR\n    if (fd == -2)\n        if (len)\n            wcstombs(state->path, path, len + 1);\n        else\n            *(state->path) = 0;\n    else\n#endif\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n        (void)snprintf(state->path, len + 1, \"%s\", (const char *)path);\n#else\n        strcpy(state->path, path);\n#endif\n\n    /* compute the flags for open() */\n    oflag =\n#ifdef O_LARGEFILE\n        O_LARGEFILE |\n#endif\n#ifdef O_BINARY\n        O_BINARY |\n#endif\n#ifdef O_CLOEXEC\n        (cloexec ? O_CLOEXEC : 0) |\n#endif\n        (state->mode == GZ_READ ?\n         O_RDONLY :\n         (O_WRONLY | O_CREAT |\n#ifdef O_EXCL\n          (exclusive ? O_EXCL : 0) |\n#endif\n          (state->mode == GZ_WRITE ?\n           O_TRUNC :\n           O_APPEND)));\n\n    /* open the file with the appropriate flags (or just use fd) */\n    state->fd = fd > -1 ? fd : (\n#ifdef WIDECHAR\n        fd == -2 ? _wopen(path, oflag, 0666) :\n#endif\n        open((const char *)path, oflag, 0666));\n    if (state->fd == -1) {\n        free(state->path);\n        free(state);\n        return NULL;\n    }\n    if (state->mode == GZ_APPEND) {\n        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */\n        state->mode = GZ_WRITE;         /* simplify later checks */\n    }\n\n    /* save the current position for rewinding (only if reading) */\n    if (state->mode == GZ_READ) {\n        state->start = LSEEK(state->fd, 0, SEEK_CUR);\n        if (state->start == -1) state->start = 0;\n    }\n\n    /* initialize stream */\n    gz_reset(state);\n\n    /* return stream */\n    return (gzFile)state;\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzopen(path, mode)\n    const char *path;\n    const char *mode;\n{\n    return gz_open(path, -1, mode);\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzopen64(path, mode)\n    const char *path;\n    const char *mode;\n{\n    return gz_open(path, -1, mode);\n}\n\n/* -- see zlib.h -- */\ngzFile ZEXPORT gzdopen(fd, mode)\n    int fd;\n    const char *mode;\n{\n    char *path;         /* identifier for error messages */\n    gzFile gz;\n\n    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)\n        return NULL;\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n    (void)snprintf(path, 7 + 3 * sizeof(int), \"<fd:%d>\", fd);\n#else\n    sprintf(path, \"<fd:%d>\", fd);   /* for debugging */\n#endif\n    gz = gz_open(path, fd, mode);\n    free(path);\n    return gz;\n}\n\n/* -- see zlib.h -- */\n#ifdef WIDECHAR\ngzFile ZEXPORT gzopen_w(path, mode)\n    const wchar_t *path;\n    const char *mode;\n{\n    return gz_open(path, -2, mode);\n}\n#endif\n\n/* -- see zlib.h -- */\nint ZEXPORT gzbuffer(file, size)\n    gzFile file;\n    unsigned size;\n{\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* make sure we haven't already allocated memory */\n    if (state->size != 0)\n        return -1;\n\n    /* check and set requested size */\n    if ((size << 1) < size)\n        return -1;              /* need to be able to double it */\n    if (size < 2)\n        size = 2;               /* need two bytes to check magic header */\n    state->want = size;\n    return 0;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzrewind(file)\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no error */\n    if (state->mode != GZ_READ ||\n            (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return -1;\n\n    /* back up and start over */\n    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)\n        return -1;\n    gz_reset(state);\n    return 0;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gzseek64(file, offset, whence)\n    gzFile file;\n    z_off64_t offset;\n    int whence;\n{\n    unsigned n;\n    z_off64_t ret;\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* check that there's no error */\n    if (state->err != Z_OK && state->err != Z_BUF_ERROR)\n        return -1;\n\n    /* can only seek from start or relative to current position */\n    if (whence != SEEK_SET && whence != SEEK_CUR)\n        return -1;\n\n    /* normalize offset to a SEEK_CUR specification */\n    if (whence == SEEK_SET)\n        offset -= state->x.pos;\n    else if (state->seek)\n        offset += state->skip;\n    state->seek = 0;\n\n    /* if within raw area while reading, just go there */\n    if (state->mode == GZ_READ && state->how == COPY &&\n            state->x.pos + offset >= 0) {\n        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);\n        if (ret == -1)\n            return -1;\n        state->x.have = 0;\n        state->eof = 0;\n        state->past = 0;\n        state->seek = 0;\n        gz_error(state, Z_OK, NULL);\n        state->strm.avail_in = 0;\n        state->x.pos += offset;\n        return state->x.pos;\n    }\n\n    /* calculate skip amount, rewinding if needed for back seek when reading */\n    if (offset < 0) {\n        if (state->mode != GZ_READ)         /* writing -- can't go backwards */\n            return -1;\n        offset += state->x.pos;\n        if (offset < 0)                     /* before start of file! */\n            return -1;\n        if (gzrewind(file) == -1)           /* rewind, then skip to offset */\n            return -1;\n    }\n\n    /* if reading, skip what's in output buffer (one less gzgetc() check) */\n    if (state->mode == GZ_READ) {\n        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?\n            (unsigned)offset : state->x.have;\n        state->x.have -= n;\n        state->x.next += n;\n        state->x.pos += n;\n        offset -= n;\n    }\n\n    /* request skip (if not zero) */\n    if (offset) {\n        state->seek = 1;\n        state->skip = offset;\n    }\n    return state->x.pos + offset;\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gzseek(file, offset, whence)\n    gzFile file;\n    z_off_t offset;\n    int whence;\n{\n    z_off64_t ret;\n\n    ret = gzseek64(file, (z_off64_t)offset, whence);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gztell64(file)\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* return position */\n    return state->x.pos + (state->seek ? state->skip : 0);\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gztell(file)\n    gzFile file;\n{\n    z_off64_t ret;\n\n    ret = gztell64(file);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nz_off64_t ZEXPORT gzoffset64(file)\n    gzFile file;\n{\n    z_off64_t offset;\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return -1;\n\n    /* compute and return effective offset in file */\n    offset = LSEEK(state->fd, 0, SEEK_CUR);\n    if (offset == -1)\n        return -1;\n    if (state->mode == GZ_READ)             /* reading */\n        offset -= state->strm.avail_in;     /* don't count buffered input */\n    return offset;\n}\n\n/* -- see zlib.h -- */\nz_off_t ZEXPORT gzoffset(file)\n    gzFile file;\n{\n    z_off64_t ret;\n\n    ret = gzoffset64(file);\n    return ret == (z_off_t)ret ? (z_off_t)ret : -1;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzeof(file)\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return 0;\n\n    /* return end-of-file state */\n    return state->mode == GZ_READ ? state->past : 0;\n}\n\n/* -- see zlib.h -- */\nconst char * ZEXPORT gzerror(file, errnum)\n    gzFile file;\n    int *errnum;\n{\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return NULL;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return NULL;\n\n    /* return error information */\n    if (errnum != NULL)\n        *errnum = state->err;\n    return state->err == Z_MEM_ERROR ? \"out of memory\" :\n                                       (state->msg == NULL ? \"\" : state->msg);\n}\n\n/* -- see zlib.h -- */\nvoid ZEXPORT gzclearerr(file)\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure and check integrity */\n    if (file == NULL)\n        return;\n    state = (gz_statep)file;\n    if (state->mode != GZ_READ && state->mode != GZ_WRITE)\n        return;\n\n    /* clear error and end-of-file */\n    if (state->mode == GZ_READ) {\n        state->eof = 0;\n        state->past = 0;\n    }\n    gz_error(state, Z_OK, NULL);\n}\n\n/* Create an error message in allocated memory and set state->err and\n   state->msg accordingly.  Free any previous error message already there.  Do\n   not try to free or allocate space if the error is Z_MEM_ERROR (out of\n   memory).  Simply save the error message as a static string.  If there is an\n   allocation failure constructing the error message, then convert the error to\n   out of memory. */\nvoid ZLIB_INTERNAL gz_error(state, err, msg)\n    gz_statep state;\n    int err;\n    const char *msg;\n{\n    /* free previously allocated message and clear */\n    if (state->msg != NULL) {\n        if (state->err != Z_MEM_ERROR)\n            free(state->msg);\n        state->msg = NULL;\n    }\n\n    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */\n    if (err != Z_OK && err != Z_BUF_ERROR)\n        state->x.have = 0;\n\n    /* set error code, and if no message, then done */\n    state->err = err;\n    if (msg == NULL)\n        return;\n\n    /* for an out of memory error, return literal string when requested */\n    if (err == Z_MEM_ERROR)\n        return;\n\n    /* construct error message with path */\n    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==\n            NULL) {\n        state->err = Z_MEM_ERROR;\n        return;\n    }\n#if !defined(NO_snprintf) && !defined(NO_vsnprintf)\n    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,\n                   \"%s%s%s\", state->path, \": \", msg);\n#else\n    strcpy(state->msg, state->path);\n    strcat(state->msg, \": \");\n    strcat(state->msg, msg);\n#endif\n}\n\n#ifndef INT_MAX\n/* portably return maximum value for an int (when limits.h presumed not\n   available) -- we need to do this to cover cases where 2's complement not\n   used, since C standard permits 1's complement and sign-bit representations,\n   otherwise we could just use ((unsigned)-1) >> 1 */\nunsigned ZLIB_INTERNAL gz_intmax()\n{\n    unsigned p, q;\n\n    p = 1;\n    do {\n        q = p;\n        p <<= 1;\n        p++;\n    } while (p > q);\n    return q >> 1;\n}\n#endif\n"
  },
  {
    "path": "dlib/external/zlib/gzread.c",
    "content": "/* gzread.c -- zlib functions for reading gzip files\n * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n/* Local functions */\nlocal int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));\nlocal int gz_avail OF((gz_statep));\nlocal int gz_look OF((gz_statep));\nlocal int gz_decomp OF((gz_statep));\nlocal int gz_fetch OF((gz_statep));\nlocal int gz_skip OF((gz_statep, z_off64_t));\nlocal z_size_t gz_read OF((gz_statep, voidp, z_size_t));\n\n/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from\n   state->fd, and update state->eof, state->err, and state->msg as appropriate.\n   This function needs to loop on read(), since read() is not guaranteed to\n   read the number of bytes requested, depending on the type of descriptor. */\nlocal int gz_load(state, buf, len, have)\n    gz_statep state;\n    unsigned char *buf;\n    unsigned len;\n    unsigned *have;\n{\n    int ret;\n    unsigned get, max = ((unsigned)-1 >> 2) + 1;\n\n    *have = 0;\n    do {\n        get = len - *have;\n        if (get > max)\n            get = max;\n        ret = read(state->fd, buf + *have, get);\n        if (ret <= 0)\n            break;\n        *have += (unsigned)ret;\n    } while (*have < len);\n    if (ret < 0) {\n        gz_error(state, Z_ERRNO, zstrerror());\n        return -1;\n    }\n    if (ret == 0)\n        state->eof = 1;\n    return 0;\n}\n\n/* Load up input buffer and set eof flag if last data loaded -- return -1 on\n   error, 0 otherwise.  Note that the eof flag is set when the end of the input\n   file is reached, even though there may be unused data in the buffer.  Once\n   that data has been used, no more attempts will be made to read the file.\n   If strm->avail_in != 0, then the current data is moved to the beginning of\n   the input buffer, and then the remainder of the buffer is loaded with the\n   available data from the input file. */\nlocal int gz_avail(state)\n    gz_statep state;\n{\n    unsigned got;\n    z_streamp strm = &(state->strm);\n\n    if (state->err != Z_OK && state->err != Z_BUF_ERROR)\n        return -1;\n    if (state->eof == 0) {\n        if (strm->avail_in) {       /* copy what's there to the start */\n            unsigned char *p = state->in;\n            unsigned const char *q = strm->next_in;\n            unsigned n = strm->avail_in;\n            do {\n                *p++ = *q++;\n            } while (--n);\n        }\n        if (gz_load(state, state->in + strm->avail_in,\n                    state->size - strm->avail_in, &got) == -1)\n            return -1;\n        strm->avail_in += got;\n        strm->next_in = state->in;\n    }\n    return 0;\n}\n\n/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.\n   If this is the first time in, allocate required memory.  state->how will be\n   left unchanged if there is no more input data available, will be set to COPY\n   if there is no gzip header and direct copying will be performed, or it will\n   be set to GZIP for decompression.  If direct copying, then leftover input\n   data from the input buffer will be copied to the output buffer.  In that\n   case, all further file reads will be directly to either the output buffer or\n   a user buffer.  If decompressing, the inflate state will be initialized.\n   gz_look() will return 0 on success or -1 on failure. */\nlocal int gz_look(state)\n    gz_statep state;\n{\n    z_streamp strm = &(state->strm);\n\n    /* allocate read buffers and inflate memory */\n    if (state->size == 0) {\n        /* allocate buffers */\n        state->in = (unsigned char *)malloc(state->want);\n        state->out = (unsigned char *)malloc(state->want << 1);\n        if (state->in == NULL || state->out == NULL) {\n            free(state->out);\n            free(state->in);\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n        state->size = state->want;\n\n        /* allocate inflate memory */\n        state->strm.zalloc = Z_NULL;\n        state->strm.zfree = Z_NULL;\n        state->strm.opaque = Z_NULL;\n        state->strm.avail_in = 0;\n        state->strm.next_in = Z_NULL;\n        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */\n            free(state->out);\n            free(state->in);\n            state->size = 0;\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n    }\n\n    /* get at least the magic bytes in the input buffer */\n    if (strm->avail_in < 2) {\n        if (gz_avail(state) == -1)\n            return -1;\n        if (strm->avail_in == 0)\n            return 0;\n    }\n\n    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is\n       a logical dilemma here when considering the case of a partially written\n       gzip file, to wit, if a single 31 byte is written, then we cannot tell\n       whether this is a single-byte file, or just a partially written gzip\n       file -- for here we assume that if a gzip file is being written, then\n       the header will be written in a single operation, so that reading a\n       single byte is sufficient indication that it is not a gzip file) */\n    if (strm->avail_in > 1 &&\n            strm->next_in[0] == 31 && strm->next_in[1] == 139) {\n        inflateReset(strm);\n        state->how = GZIP;\n        state->direct = 0;\n        return 0;\n    }\n\n    /* no gzip header -- if we were decoding gzip before, then this is trailing\n       garbage.  Ignore the trailing garbage and finish. */\n    if (state->direct == 0) {\n        strm->avail_in = 0;\n        state->eof = 1;\n        state->x.have = 0;\n        return 0;\n    }\n\n    /* doing raw i/o, copy any leftover input to output -- this assumes that\n       the output buffer is larger than the input buffer, which also assures\n       space for gzungetc() */\n    state->x.next = state->out;\n    if (strm->avail_in) {\n        memcpy(state->x.next, strm->next_in, strm->avail_in);\n        state->x.have = strm->avail_in;\n        strm->avail_in = 0;\n    }\n    state->how = COPY;\n    state->direct = 1;\n    return 0;\n}\n\n/* Decompress from input to the provided next_out and avail_out in the state.\n   On return, state->x.have and state->x.next point to the just decompressed\n   data.  If the gzip stream completes, state->how is reset to LOOK to look for\n   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0\n   on success, -1 on failure. */\nlocal int gz_decomp(state)\n    gz_statep state;\n{\n    int ret = Z_OK;\n    unsigned had;\n    z_streamp strm = &(state->strm);\n\n    /* fill output buffer up to end of deflate stream */\n    had = strm->avail_out;\n    do {\n        /* get more input for inflate() */\n        if (strm->avail_in == 0 && gz_avail(state) == -1)\n            return -1;\n        if (strm->avail_in == 0) {\n            gz_error(state, Z_BUF_ERROR, \"unexpected end of file\");\n            break;\n        }\n\n        /* decompress and handle errors */\n        ret = inflate(strm, Z_NO_FLUSH);\n        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {\n            gz_error(state, Z_STREAM_ERROR,\n                     \"internal error: inflate stream corrupt\");\n            return -1;\n        }\n        if (ret == Z_MEM_ERROR) {\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */\n            gz_error(state, Z_DATA_ERROR,\n                     strm->msg == NULL ? \"compressed data error\" : strm->msg);\n            return -1;\n        }\n    } while (strm->avail_out && ret != Z_STREAM_END);\n\n    /* update available output */\n    state->x.have = had - strm->avail_out;\n    state->x.next = strm->next_out - state->x.have;\n\n    /* if the gzip stream completed successfully, look for another */\n    if (ret == Z_STREAM_END)\n        state->how = LOOK;\n\n    /* good decompression */\n    return 0;\n}\n\n/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.\n   Data is either copied from the input file or decompressed from the input\n   file depending on state->how.  If state->how is LOOK, then a gzip header is\n   looked for to determine whether to copy or decompress.  Returns -1 on error,\n   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the\n   end of the input file has been reached and all data has been processed.  */\nlocal int gz_fetch(state)\n    gz_statep state;\n{\n    z_streamp strm = &(state->strm);\n\n    do {\n        switch(state->how) {\n        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */\n            if (gz_look(state) == -1)\n                return -1;\n            if (state->how == LOOK)\n                return 0;\n            break;\n        case COPY:      /* -> COPY */\n            if (gz_load(state, state->out, state->size << 1, &(state->x.have))\n                    == -1)\n                return -1;\n            state->x.next = state->out;\n            return 0;\n        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */\n            strm->avail_out = state->size << 1;\n            strm->next_out = state->out;\n            if (gz_decomp(state) == -1)\n                return -1;\n        }\n    } while (state->x.have == 0 && (!state->eof || strm->avail_in));\n    return 0;\n}\n\n/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */\nlocal int gz_skip(state, len)\n    gz_statep state;\n    z_off64_t len;\n{\n    unsigned n;\n\n    /* skip over len bytes or reach end-of-file, whichever comes first */\n    while (len)\n        /* skip over whatever is in output buffer */\n        if (state->x.have) {\n            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?\n                (unsigned)len : state->x.have;\n            state->x.have -= n;\n            state->x.next += n;\n            state->x.pos += n;\n            len -= n;\n        }\n\n        /* output buffer empty -- return if we're at the end of the input */\n        else if (state->eof && state->strm.avail_in == 0)\n            break;\n\n        /* need more data to skip -- load up output buffer */\n        else {\n            /* get more output, looking for header if required */\n            if (gz_fetch(state) == -1)\n                return -1;\n        }\n    return 0;\n}\n\n/* Read len bytes into buf from file, or less than len up to the end of the\n   input.  Return the number of bytes read.  If zero is returned, either the\n   end of file was reached, or there was an error.  state->err must be\n   consulted in that case to determine which. */\nlocal z_size_t gz_read(state, buf, len)\n    gz_statep state;\n    voidp buf;\n    z_size_t len;\n{\n    z_size_t got;\n    unsigned n;\n\n    /* if len is zero, avoid unnecessary operations */\n    if (len == 0)\n        return 0;\n\n    /* process a skip request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_skip(state, state->skip) == -1)\n            return 0;\n    }\n\n    /* get len bytes to buf, or less than len if at the end */\n    got = 0;\n    do {\n        /* set n to the maximum amount of len that fits in an unsigned int */\n        n = -1;\n        if (n > len)\n            n = len;\n\n        /* first just try copying data from the output buffer */\n        if (state->x.have) {\n            if (state->x.have < n)\n                n = state->x.have;\n            memcpy(buf, state->x.next, n);\n            state->x.next += n;\n            state->x.have -= n;\n        }\n\n        /* output buffer empty -- return if we're at the end of the input */\n        else if (state->eof && state->strm.avail_in == 0) {\n            state->past = 1;        /* tried to read past end */\n            break;\n        }\n\n        /* need output data -- for small len or new stream load up our output\n           buffer */\n        else if (state->how == LOOK || n < (state->size << 1)) {\n            /* get more output, looking for header if required */\n            if (gz_fetch(state) == -1)\n                return 0;\n            continue;       /* no progress yet -- go back to copy above */\n            /* the copy above assures that we will leave with space in the\n               output buffer, allowing at least one gzungetc() to succeed */\n        }\n\n        /* large len -- read directly into user buffer */\n        else if (state->how == COPY) {      /* read directly */\n            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)\n                return 0;\n        }\n\n        /* large len -- decompress directly into user buffer */\n        else {  /* state->how == GZIP */\n            state->strm.avail_out = n;\n            state->strm.next_out = (unsigned char *)buf;\n            if (gz_decomp(state) == -1)\n                return 0;\n            n = state->x.have;\n            state->x.have = 0;\n        }\n\n        /* update progress */\n        len -= n;\n        buf = (char *)buf + n;\n        got += n;\n        state->x.pos += n;\n    } while (len);\n\n    /* return number of bytes read into user buffer */\n    return got;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzread(file, buf, len)\n    gzFile file;\n    voidp buf;\n    unsigned len;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no (serious) error */\n    if (state->mode != GZ_READ ||\n            (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return -1;\n\n    /* since an int is returned, make sure len fits in one, otherwise return\n       with an error (this avoids a flaw in the interface) */\n    if ((int)len < 0) {\n        gz_error(state, Z_STREAM_ERROR, \"request does not fit in an int\");\n        return -1;\n    }\n\n    /* read len or fewer bytes to buf */\n    len = gz_read(state, buf, len);\n\n    /* check for an error */\n    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)\n        return -1;\n\n    /* return the number of bytes read (this is assured to fit in an int) */\n    return (int)len;\n}\n\n/* -- see zlib.h -- */\nz_size_t ZEXPORT gzfread(buf, size, nitems, file)\n    voidp buf;\n    z_size_t size;\n    z_size_t nitems;\n    gzFile file;\n{\n    z_size_t len;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no (serious) error */\n    if (state->mode != GZ_READ ||\n            (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return 0;\n\n    /* compute bytes to read -- error on overflow */\n    len = nitems * size;\n    if (size && len / size != nitems) {\n        gz_error(state, Z_STREAM_ERROR, \"request does not fit in a size_t\");\n        return 0;\n    }\n\n    /* read len or fewer bytes to buf, return the number of full items read */\n    return len ? gz_read(state, buf, len) / size : 0;\n}\n\n/* -- see zlib.h -- */\n#ifdef Z_PREFIX_SET\n#  undef z_gzgetc\n#else\n#  undef gzgetc\n#endif\nint ZEXPORT gzgetc(file)\n    gzFile file;\n{\n    int ret;\n    unsigned char buf[1];\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no (serious) error */\n    if (state->mode != GZ_READ ||\n        (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return -1;\n\n    /* try output buffer (no need to check for skip request) */\n    if (state->x.have) {\n        state->x.have--;\n        state->x.pos++;\n        return *(state->x.next)++;\n    }\n\n    /* nothing there -- try gz_read() */\n    ret = gz_read(state, buf, 1);\n    return ret < 1 ? -1 : buf[0];\n}\n\nint ZEXPORT gzgetc_(file)\ngzFile file;\n{\n    return gzgetc(file);\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzungetc(c, file)\n    int c;\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no (serious) error */\n    if (state->mode != GZ_READ ||\n        (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return -1;\n\n    /* process a skip request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_skip(state, state->skip) == -1)\n            return -1;\n    }\n\n    /* can't push EOF */\n    if (c < 0)\n        return -1;\n\n    /* if output buffer empty, put byte at end (allows more pushing) */\n    if (state->x.have == 0) {\n        state->x.have = 1;\n        state->x.next = state->out + (state->size << 1) - 1;\n        state->x.next[0] = (unsigned char)c;\n        state->x.pos--;\n        state->past = 0;\n        return c;\n    }\n\n    /* if no room, give up (must have already done a gzungetc()) */\n    if (state->x.have == (state->size << 1)) {\n        gz_error(state, Z_DATA_ERROR, \"out of room to push characters\");\n        return -1;\n    }\n\n    /* slide output data if needed and insert byte before existing data */\n    if (state->x.next == state->out) {\n        unsigned char *src = state->out + state->x.have;\n        unsigned char *dest = state->out + (state->size << 1);\n        while (src > state->out)\n            *--dest = *--src;\n        state->x.next = dest;\n    }\n    state->x.have++;\n    state->x.next--;\n    state->x.next[0] = (unsigned char)c;\n    state->x.pos--;\n    state->past = 0;\n    return c;\n}\n\n/* -- see zlib.h -- */\nchar * ZEXPORT gzgets(file, buf, len)\n    gzFile file;\n    char *buf;\n    int len;\n{\n    unsigned left, n;\n    char *str;\n    unsigned char *eol;\n    gz_statep state;\n\n    /* check parameters and get internal structure */\n    if (file == NULL || buf == NULL || len < 1)\n        return NULL;\n    state = (gz_statep)file;\n\n    /* check that we're reading and that there's no (serious) error */\n    if (state->mode != GZ_READ ||\n        (state->err != Z_OK && state->err != Z_BUF_ERROR))\n        return NULL;\n\n    /* process a skip request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_skip(state, state->skip) == -1)\n            return NULL;\n    }\n\n    /* copy output bytes up to new line or len - 1, whichever comes first --\n       append a terminating zero to the string (we don't check for a zero in\n       the contents, let the user worry about that) */\n    str = buf;\n    left = (unsigned)len - 1;\n    if (left) do {\n        /* assure that something is in the output buffer */\n        if (state->x.have == 0 && gz_fetch(state) == -1)\n            return NULL;                /* error */\n        if (state->x.have == 0) {       /* end of file */\n            state->past = 1;            /* read past end */\n            break;                      /* return what we have */\n        }\n\n        /* look for end-of-line in current output buffer */\n        n = state->x.have > left ? left : state->x.have;\n        eol = (unsigned char *)memchr(state->x.next, '\\n', n);\n        if (eol != NULL)\n            n = (unsigned)(eol - state->x.next) + 1;\n\n        /* copy through end-of-line, or remainder if not found */\n        memcpy(buf, state->x.next, n);\n        state->x.have -= n;\n        state->x.next += n;\n        state->x.pos += n;\n        left -= n;\n        buf += n;\n    } while (left && eol == NULL);\n\n    /* return terminated string, or if nothing, end of file */\n    if (buf == str)\n        return NULL;\n    buf[0] = 0;\n    return str;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzdirect(file)\n    gzFile file;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* if the state is not known, but we can find out, then do so (this is\n       mainly for right after a gzopen() or gzdopen()) */\n    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)\n        (void)gz_look(state);\n\n    /* return 1 if transparent, 0 if processing a gzip stream */\n    return state->direct;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzclose_r(file)\n    gzFile file;\n{\n    int ret, err;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    /* check that we're reading */\n    if (state->mode != GZ_READ)\n        return Z_STREAM_ERROR;\n\n    /* free memory and close file */\n    if (state->size) {\n        inflateEnd(&(state->strm));\n        free(state->out);\n        free(state->in);\n    }\n    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;\n    gz_error(state, Z_OK, NULL);\n    free(state->path);\n    ret = close(state->fd);\n    free(state);\n    return ret ? Z_ERRNO : err;\n}\n"
  },
  {
    "path": "dlib/external/zlib/gzwrite.c",
    "content": "/* gzwrite.c -- zlib functions for writing gzip files\n * Copyright (C) 2004-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"gzguts.h\"\n\n/* Local functions */\nlocal int gz_init OF((gz_statep));\nlocal int gz_comp OF((gz_statep, int));\nlocal int gz_zero OF((gz_statep, z_off64_t));\nlocal z_size_t gz_write OF((gz_statep, voidpc, z_size_t));\n\n/* Initialize state for writing a gzip file.  Mark initialization by setting\n   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on\n   success. */\nlocal int gz_init(state)\n    gz_statep state;\n{\n    int ret;\n    z_streamp strm = &(state->strm);\n\n    /* allocate input buffer (double size for gzprintf) */\n    state->in = (unsigned char *)malloc(state->want << 1);\n    if (state->in == NULL) {\n        gz_error(state, Z_MEM_ERROR, \"out of memory\");\n        return -1;\n    }\n\n    /* only need output buffer and deflate state if compressing */\n    if (!state->direct) {\n        /* allocate output buffer */\n        state->out = (unsigned char *)malloc(state->want);\n        if (state->out == NULL) {\n            free(state->in);\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n\n        /* allocate deflate memory, set up for gzip compression */\n        strm->zalloc = Z_NULL;\n        strm->zfree = Z_NULL;\n        strm->opaque = Z_NULL;\n        ret = deflateInit2(strm, state->level, Z_DEFLATED,\n                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);\n        if (ret != Z_OK) {\n            free(state->out);\n            free(state->in);\n            gz_error(state, Z_MEM_ERROR, \"out of memory\");\n            return -1;\n        }\n        strm->next_in = NULL;\n    }\n\n    /* mark state as initialized */\n    state->size = state->want;\n\n    /* initialize write buffer if compressing */\n    if (!state->direct) {\n        strm->avail_out = state->size;\n        strm->next_out = state->out;\n        state->x.next = strm->next_out;\n    }\n    return 0;\n}\n\n/* Compress whatever is at avail_in and next_in and write to the output file.\n   Return -1 if there is an error writing to the output file or if gz_init()\n   fails to allocate memory, otherwise 0.  flush is assumed to be a valid\n   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is\n   reset to start a new gzip stream.  If gz->direct is true, then simply write\n   to the output file without compressing, and ignore flush. */\nlocal int gz_comp(state, flush)\n    gz_statep state;\n    int flush;\n{\n    int ret, writ;\n    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;\n    z_streamp strm = &(state->strm);\n\n    /* allocate memory if this is the first time through */\n    if (state->size == 0 && gz_init(state) == -1)\n        return -1;\n\n    /* write directly if requested */\n    if (state->direct) {\n        while (strm->avail_in) {\n            put = strm->avail_in > max ? max : strm->avail_in;\n            writ = write(state->fd, strm->next_in, put);\n            if (writ < 0) {\n                gz_error(state, Z_ERRNO, zstrerror());\n                return -1;\n            }\n            strm->avail_in -= (unsigned)writ;\n            strm->next_in += writ;\n        }\n        return 0;\n    }\n\n    /* run deflate() on provided input until it produces no more output */\n    ret = Z_OK;\n    do {\n        /* write out current buffer contents if full, or if flushing, but if\n           doing Z_FINISH then don't write until we get to Z_STREAM_END */\n        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&\n            (flush != Z_FINISH || ret == Z_STREAM_END))) {\n            while (strm->next_out > state->x.next) {\n                put = strm->next_out - state->x.next > (int)max ? max :\n                      (unsigned)(strm->next_out - state->x.next);\n                writ = write(state->fd, state->x.next, put);\n                if (writ < 0) {\n                    gz_error(state, Z_ERRNO, zstrerror());\n                    return -1;\n                }\n                state->x.next += writ;\n            }\n            if (strm->avail_out == 0) {\n                strm->avail_out = state->size;\n                strm->next_out = state->out;\n                state->x.next = state->out;\n            }\n        }\n\n        /* compress */\n        have = strm->avail_out;\n        ret = deflate(strm, flush);\n        if (ret == Z_STREAM_ERROR) {\n            gz_error(state, Z_STREAM_ERROR,\n                      \"internal error: deflate stream corrupt\");\n            return -1;\n        }\n        have -= strm->avail_out;\n    } while (have);\n\n    /* if that completed a deflate stream, allow another to start */\n    if (flush == Z_FINISH)\n        deflateReset(strm);\n\n    /* all done, no errors */\n    return 0;\n}\n\n/* Compress len zeros to output.  Return -1 on a write error or memory\n   allocation failure by gz_comp(), or 0 on success. */\nlocal int gz_zero(state, len)\n    gz_statep state;\n    z_off64_t len;\n{\n    int first;\n    unsigned n;\n    z_streamp strm = &(state->strm);\n\n    /* consume whatever's left in the input buffer */\n    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)\n        return -1;\n\n    /* compress len zeros (len guaranteed > 0) */\n    first = 1;\n    while (len) {\n        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?\n            (unsigned)len : state->size;\n        if (first) {\n            memset(state->in, 0, n);\n            first = 0;\n        }\n        strm->avail_in = n;\n        strm->next_in = state->in;\n        state->x.pos += n;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return -1;\n        len -= n;\n    }\n    return 0;\n}\n\n/* Write len bytes from buf to file.  Return the number of bytes written.  If\n   the returned value is less than len, then there was an error. */\nlocal z_size_t gz_write(state, buf, len)\n    gz_statep state;\n    voidpc buf;\n    z_size_t len;\n{\n    z_size_t put = len;\n\n    /* if len is zero, avoid unnecessary operations */\n    if (len == 0)\n        return 0;\n\n    /* allocate memory if this is the first time through */\n    if (state->size == 0 && gz_init(state) == -1)\n        return 0;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return 0;\n    }\n\n    /* for small len, copy to input buffer, otherwise compress directly */\n    if (len < state->size) {\n        /* copy to input buffer, compress when full */\n        do {\n            unsigned have, copy;\n\n            if (state->strm.avail_in == 0)\n                state->strm.next_in = state->in;\n            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -\n                              state->in);\n            copy = state->size - have;\n            if (copy > len)\n                copy = len;\n            memcpy(state->in + have, buf, copy);\n            state->strm.avail_in += copy;\n            state->x.pos += copy;\n            buf = (const char *)buf + copy;\n            len -= copy;\n            if (len && gz_comp(state, Z_NO_FLUSH) == -1)\n                return 0;\n        } while (len);\n    }\n    else {\n        /* consume whatever's left in the input buffer */\n        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)\n            return 0;\n\n        /* directly compress user buffer to file */\n        state->strm.next_in = (z_const Bytef *)buf;\n        do {\n            unsigned n = (unsigned)-1;\n            if (n > len)\n                n = len;\n            state->strm.avail_in = n;\n            state->x.pos += n;\n            if (gz_comp(state, Z_NO_FLUSH) == -1)\n                return 0;\n            len -= n;\n        } while (len);\n    }\n\n    /* input was all buffered or compressed */\n    return put;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzwrite(file, buf, len)\n    gzFile file;\n    voidpc buf;\n    unsigned len;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return 0;\n\n    /* since an int is returned, make sure len fits in one, otherwise return\n       with an error (this avoids a flaw in the interface) */\n    if ((int)len < 0) {\n        gz_error(state, Z_DATA_ERROR, \"requested length does not fit in int\");\n        return 0;\n    }\n\n    /* write len bytes from buf (the return value will fit in an int) */\n    return (int)gz_write(state, buf, len);\n}\n\n/* -- see zlib.h -- */\nz_size_t ZEXPORT gzfwrite(buf, size, nitems, file)\n    voidpc buf;\n    z_size_t size;\n    z_size_t nitems;\n    gzFile file;\n{\n    z_size_t len;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return 0;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return 0;\n\n    /* compute bytes to read -- error on overflow */\n    len = nitems * size;\n    if (size && len / size != nitems) {\n        gz_error(state, Z_STREAM_ERROR, \"request does not fit in a size_t\");\n        return 0;\n    }\n\n    /* write len bytes to buf, return the number of full items written */\n    return len ? gz_write(state, buf, len) / size : 0;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzputc(file, c)\n    gzFile file;\n    int c;\n{\n    unsigned have;\n    unsigned char buf[1];\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return -1;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return -1;\n    }\n\n    /* try writing to input buffer for speed (state->size == 0 if buffer not\n       initialized) */\n    if (state->size) {\n        if (strm->avail_in == 0)\n            strm->next_in = state->in;\n        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);\n        if (have < state->size) {\n            state->in[have] = (unsigned char)c;\n            strm->avail_in++;\n            state->x.pos++;\n            return c & 0xff;\n        }\n    }\n\n    /* no room in buffer or not initialized, use gz_write() */\n    buf[0] = (unsigned char)c;\n    if (gz_write(state, buf, 1) != 1)\n        return -1;\n    return c & 0xff;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzputs(file, str)\n    gzFile file;\n    const char *str;\n{\n    int ret;\n    z_size_t len;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return -1;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return -1;\n\n    /* write string */\n    len = strlen(str);\n    ret = gz_write(state, str, len);\n    return ret == 0 && len != 0 ? -1 : ret;\n}\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#include <stdarg.h>\n\n/* -- see zlib.h -- */\nint ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)\n{\n    int len;\n    unsigned left;\n    char *next;\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* make sure we have some buffer space */\n    if (state->size == 0 && gz_init(state) == -1)\n        return state->err;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* do the printf() into the input buffer, put length in len -- the input\n       buffer is double-sized just for this function, so there is guaranteed to\n       be state->size bytes available after the current contents */\n    if (strm->avail_in == 0)\n        strm->next_in = state->in;\n    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);\n    next[state->size - 1] = 0;\n#ifdef NO_vsnprintf\n#  ifdef HAS_vsprintf_void\n    (void)vsprintf(next, format, va);\n    for (len = 0; len < state->size; len++)\n        if (next[len] == 0) break;\n#  else\n    len = vsprintf(next, format, va);\n#  endif\n#else\n#  ifdef HAS_vsnprintf_void\n    (void)vsnprintf(next, state->size, format, va);\n    len = strlen(next);\n#  else\n    len = vsnprintf(next, state->size, format, va);\n#  endif\n#endif\n\n    /* check that printf() results fit in buffer */\n    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)\n        return 0;\n\n    /* update buffer and position, compress first half if past that */\n    strm->avail_in += (unsigned)len;\n    state->x.pos += len;\n    if (strm->avail_in >= state->size) {\n        left = strm->avail_in - state->size;\n        strm->avail_in = state->size;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return state->err;\n        memcpy(state->in, state->in + state->size, left);\n        strm->next_in = state->in;\n        strm->avail_in = left;\n    }\n    return len;\n}\n\nint ZEXPORTVA gzprintf(gzFile file, const char *format, ...)\n{\n    va_list va;\n    int ret;\n\n    va_start(va, format);\n    ret = gzvprintf(file, format, va);\n    va_end(va);\n    return ret;\n}\n\n#else /* !STDC && !Z_HAVE_STDARG_H */\n\n/* -- see zlib.h -- */\nint ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,\n                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)\n    gzFile file;\n    const char *format;\n    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,\n        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;\n{\n    unsigned len, left;\n    char *next;\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that can really pass pointer in ints */\n    if (sizeof(int) != sizeof(void *))\n        return Z_STREAM_ERROR;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* make sure we have some buffer space */\n    if (state->size == 0 && gz_init(state) == -1)\n        return state->error;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->error;\n    }\n\n    /* do the printf() into the input buffer, put length in len -- the input\n       buffer is double-sized just for this function, so there is guaranteed to\n       be state->size bytes available after the current contents */\n    if (strm->avail_in == 0)\n        strm->next_in = state->in;\n    next = (char *)(strm->next_in + strm->avail_in);\n    next[state->size - 1] = 0;\n#ifdef NO_snprintf\n#  ifdef HAS_sprintf_void\n    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,\n            a13, a14, a15, a16, a17, a18, a19, a20);\n    for (len = 0; len < size; len++)\n        if (next[len] == 0)\n            break;\n#  else\n    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,\n                  a12, a13, a14, a15, a16, a17, a18, a19, a20);\n#  endif\n#else\n#  ifdef HAS_snprintf_void\n    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,\n             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);\n    len = strlen(next);\n#  else\n    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,\n                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);\n#  endif\n#endif\n\n    /* check that printf() results fit in buffer */\n    if (len == 0 || len >= state->size || next[state->size - 1] != 0)\n        return 0;\n\n    /* update buffer and position, compress first half if past that */\n    strm->avail_in += len;\n    state->x.pos += len;\n    if (strm->avail_in >= state->size) {\n        left = strm->avail_in - state->size;\n        strm->avail_in = state->size;\n        if (gz_comp(state, Z_NO_FLUSH) == -1)\n            return state->err;\n        memcpy(state->in, state->in + state->size, left);\n        strm->next_in = state->in;\n        strm->avail_in = left;\n    }\n    return (int)len;\n}\n\n#endif\n\n/* -- see zlib.h -- */\nint ZEXPORT gzflush(file, flush)\n    gzFile file;\n    int flush;\n{\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* check flush parameter */\n    if (flush < 0 || flush > Z_FINISH)\n        return Z_STREAM_ERROR;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* compress remaining data with requested flush */\n    (void)gz_comp(state, flush);\n    return state->err;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzsetparams(file, level, strategy)\n    gzFile file;\n    int level;\n    int strategy;\n{\n    gz_statep state;\n    z_streamp strm;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n    strm = &(state->strm);\n\n    /* check that we're writing and that there's no error */\n    if (state->mode != GZ_WRITE || state->err != Z_OK)\n        return Z_STREAM_ERROR;\n\n    /* if no change is requested, then do nothing */\n    if (level == state->level && strategy == state->strategy)\n        return Z_OK;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            return state->err;\n    }\n\n    /* change compression parameters for subsequent input */\n    if (state->size) {\n        /* flush previous input with previous parameters before changing */\n        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)\n            return state->err;\n        deflateParams(strm, level, strategy);\n    }\n    state->level = level;\n    state->strategy = strategy;\n    return Z_OK;\n}\n\n/* -- see zlib.h -- */\nint ZEXPORT gzclose_w(file)\n    gzFile file;\n{\n    int ret = Z_OK;\n    gz_statep state;\n\n    /* get internal structure */\n    if (file == NULL)\n        return Z_STREAM_ERROR;\n    state = (gz_statep)file;\n\n    /* check that we're writing */\n    if (state->mode != GZ_WRITE)\n        return Z_STREAM_ERROR;\n\n    /* check for seek request */\n    if (state->seek) {\n        state->seek = 0;\n        if (gz_zero(state, state->skip) == -1)\n            ret = state->err;\n    }\n\n    /* flush, free memory, and close file */\n    if (gz_comp(state, Z_FINISH) == -1)\n        ret = state->err;\n    if (state->size) {\n        if (!state->direct) {\n            (void)deflateEnd(&(state->strm));\n            free(state->out);\n        }\n        free(state->in);\n    }\n    gz_error(state, Z_OK, NULL);\n    free(state->path);\n    if (close(state->fd) == -1)\n        ret = Z_ERRNO;\n    free(state);\n    return ret;\n}\n"
  },
  {
    "path": "dlib/external/zlib/infback.c",
    "content": "/* infback.c -- inflate using a call-back interface\n * Copyright (C) 1995-2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n   This code is largely copied from inflate.c.  Normally either infback.o or\n   inflate.o would be linked into an application--not both.  The interface\n   with inffast.c is retained so that optimized assembler-coded versions of\n   inflate_fast() can be used with either inflate.c or infback.c.\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n#include \"inflate.h\"\n#include \"inffast.h\"\n\n/* function prototypes */\nlocal void fixedtables OF((struct inflate_state FAR *state));\n\n/*\n   strm provides memory allocation functions in zalloc and zfree, or\n   Z_NULL to use the library memory allocation functions.\n\n   windowBits is in the range 8..15, and window is a user-supplied\n   window and output buffer that is 2**windowBits bytes.\n */\nint ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)\nz_streamp strm;\nint windowBits;\nunsigned char FAR *window;\nconst char *version;\nint stream_size;\n{\n    struct inflate_state FAR *state;\n\n    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||\n        stream_size != (int)(sizeof(z_stream)))\n        return Z_VERSION_ERROR;\n    if (strm == Z_NULL || window == Z_NULL ||\n        windowBits < 8 || windowBits > 15)\n        return Z_STREAM_ERROR;\n    strm->msg = Z_NULL;                 /* in case we return an error */\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n    strm->zfree = zcfree;\n#endif\n    state = (struct inflate_state FAR *)ZALLOC(strm, 1,\n                                               sizeof(struct inflate_state));\n    if (state == Z_NULL) return Z_MEM_ERROR;\n    Tracev((stderr, \"inflate: allocated\\n\"));\n    strm->state = (struct internal_state FAR *)state;\n    state->dmax = 32768U;\n    state->wbits = (uInt)windowBits;\n    state->wsize = 1U << windowBits;\n    state->window = window;\n    state->wnext = 0;\n    state->whave = 0;\n    return Z_OK;\n}\n\n/*\n   Return state with length and distance decoding tables and index sizes set to\n   fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n   If BUILDFIXED is defined, then instead this routine builds the tables the\n   first time it's called, and returns those tables the first time and\n   thereafter.  This reduces the size of the code by about 2K bytes, in\n   exchange for a little execution time.  However, BUILDFIXED should not be\n   used for threaded applications, since the rewriting of the tables and virgin\n   may not be thread-safe.\n */\nlocal void fixedtables(state)\nstruct inflate_state FAR *state;\n{\n#ifdef BUILDFIXED\n    static int virgin = 1;\n    static code *lenfix, *distfix;\n    static code fixed[544];\n\n    /* build fixed huffman tables if first call (may not be thread safe) */\n    if (virgin) {\n        unsigned sym, bits;\n        static code *next;\n\n        /* literal/length table */\n        sym = 0;\n        while (sym < 144) state->lens[sym++] = 8;\n        while (sym < 256) state->lens[sym++] = 9;\n        while (sym < 280) state->lens[sym++] = 7;\n        while (sym < 288) state->lens[sym++] = 8;\n        next = fixed;\n        lenfix = next;\n        bits = 9;\n        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);\n\n        /* distance table */\n        sym = 0;\n        while (sym < 32) state->lens[sym++] = 5;\n        distfix = next;\n        bits = 5;\n        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);\n\n        /* do this just once */\n        virgin = 0;\n    }\n#else /* !BUILDFIXED */\n#   include \"inffixed.h\"\n#endif /* BUILDFIXED */\n    state->lencode = lenfix;\n    state->lenbits = 9;\n    state->distcode = distfix;\n    state->distbits = 5;\n}\n\n/* Macros for inflateBack(): */\n\n/* Load returned state from inflate_fast() */\n#define LOAD() \\\n    do { \\\n        put = strm->next_out; \\\n        left = strm->avail_out; \\\n        next = strm->next_in; \\\n        have = strm->avail_in; \\\n        hold = state->hold; \\\n        bits = state->bits; \\\n    } while (0)\n\n/* Set state from registers for inflate_fast() */\n#define RESTORE() \\\n    do { \\\n        strm->next_out = put; \\\n        strm->avail_out = left; \\\n        strm->next_in = next; \\\n        strm->avail_in = have; \\\n        state->hold = hold; \\\n        state->bits = bits; \\\n    } while (0)\n\n/* Clear the input bit accumulator */\n#define INITBITS() \\\n    do { \\\n        hold = 0; \\\n        bits = 0; \\\n    } while (0)\n\n/* Assure that some input is available.  If input is requested, but denied,\n   then return a Z_BUF_ERROR from inflateBack(). */\n#define PULL() \\\n    do { \\\n        if (have == 0) { \\\n            have = in(in_desc, &next); \\\n            if (have == 0) { \\\n                next = Z_NULL; \\\n                ret = Z_BUF_ERROR; \\\n                goto inf_leave; \\\n            } \\\n        } \\\n    } while (0)\n\n/* Get a byte of input into the bit accumulator, or return from inflateBack()\n   with an error if there is no input available. */\n#define PULLBYTE() \\\n    do { \\\n        PULL(); \\\n        have--; \\\n        hold += (unsigned long)(*next++) << bits; \\\n        bits += 8; \\\n    } while (0)\n\n/* Assure that there are at least n bits in the bit accumulator.  If there is\n   not enough available input to do that, then return from inflateBack() with\n   an error. */\n#define NEEDBITS(n) \\\n    do { \\\n        while (bits < (unsigned)(n)) \\\n            PULLBYTE(); \\\n    } while (0)\n\n/* Return the low n bits of the bit accumulator (n < 16) */\n#define BITS(n) \\\n    ((unsigned)hold & ((1U << (n)) - 1))\n\n/* Remove n bits from the bit accumulator */\n#define DROPBITS(n) \\\n    do { \\\n        hold >>= (n); \\\n        bits -= (unsigned)(n); \\\n    } while (0)\n\n/* Remove zero to seven bits as needed to go to a byte boundary */\n#define BYTEBITS() \\\n    do { \\\n        hold >>= bits & 7; \\\n        bits -= bits & 7; \\\n    } while (0)\n\n/* Assure that some output space is available, by writing out the window\n   if it's full.  If the write fails, return from inflateBack() with a\n   Z_BUF_ERROR. */\n#define ROOM() \\\n    do { \\\n        if (left == 0) { \\\n            put = state->window; \\\n            left = state->wsize; \\\n            state->whave = left; \\\n            if (out(out_desc, put, left)) { \\\n                ret = Z_BUF_ERROR; \\\n                goto inf_leave; \\\n            } \\\n        } \\\n    } while (0)\n\n/*\n   strm provides the memory allocation functions and window buffer on input,\n   and provides information on the unused input on return.  For Z_DATA_ERROR\n   returns, strm will also provide an error message.\n\n   in() and out() are the call-back input and output functions.  When\n   inflateBack() needs more input, it calls in().  When inflateBack() has\n   filled the window with output, or when it completes with data in the\n   window, it calls out() to write out the data.  The application must not\n   change the provided input until in() is called again or inflateBack()\n   returns.  The application must not change the window/output buffer until\n   inflateBack() returns.\n\n   in() and out() are called with a descriptor parameter provided in the\n   inflateBack() call.  This parameter can be a structure that provides the\n   information required to do the read or write, as well as accumulated\n   information on the input and output such as totals and check values.\n\n   in() should return zero on failure.  out() should return non-zero on\n   failure.  If either in() or out() fails, than inflateBack() returns a\n   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it\n   was in() or out() that caused in the error.  Otherwise,  inflateBack()\n   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format\n   error, or Z_MEM_ERROR if it could not allocate memory for the state.\n   inflateBack() can also return Z_STREAM_ERROR if the input parameters\n   are not correct, i.e. strm is Z_NULL or the state was not initialized.\n */\nint ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)\nz_streamp strm;\nin_func in;\nvoid FAR *in_desc;\nout_func out;\nvoid FAR *out_desc;\n{\n    struct inflate_state FAR *state;\n    z_const unsigned char FAR *next;    /* next input */\n    unsigned char FAR *put;     /* next output */\n    unsigned have, left;        /* available input and output */\n    unsigned long hold;         /* bit buffer */\n    unsigned bits;              /* bits in bit buffer */\n    unsigned copy;              /* number of stored or match bytes to copy */\n    unsigned char FAR *from;    /* where to copy match bytes from */\n    code here;                  /* current decoding table entry */\n    code last;                  /* parent table entry */\n    unsigned len;               /* length to copy for repeats, bits to drop */\n    int ret;                    /* return code */\n    static const unsigned short order[19] = /* permutation of code lengths */\n        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n    /* Check that the strm exists and that the state was initialized */\n    if (strm == Z_NULL || strm->state == Z_NULL)\n        return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* Reset the state */\n    strm->msg = Z_NULL;\n    state->mode = TYPE;\n    state->last = 0;\n    state->whave = 0;\n    next = strm->next_in;\n    have = next != Z_NULL ? strm->avail_in : 0;\n    hold = 0;\n    bits = 0;\n    put = state->window;\n    left = state->wsize;\n\n    /* Inflate until end of block marked as last */\n    for (;;)\n        switch (state->mode) {\n        case TYPE:\n            /* determine and dispatch block type */\n            if (state->last) {\n                BYTEBITS();\n                state->mode = DONE;\n                break;\n            }\n            NEEDBITS(3);\n            state->last = BITS(1);\n            DROPBITS(1);\n            switch (BITS(2)) {\n            case 0:                             /* stored block */\n                Tracev((stderr, \"inflate:     stored block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = STORED;\n                break;\n            case 1:                             /* fixed block */\n                fixedtables(state);\n                Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = LEN;              /* decode codes */\n                break;\n            case 2:                             /* dynamic block */\n                Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = TABLE;\n                break;\n            case 3:\n                strm->msg = (char *)\"invalid block type\";\n                state->mode = BAD;\n            }\n            DROPBITS(2);\n            break;\n\n        case STORED:\n            /* get and verify stored block length */\n            BYTEBITS();                         /* go to byte boundary */\n            NEEDBITS(32);\n            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {\n                strm->msg = (char *)\"invalid stored block lengths\";\n                state->mode = BAD;\n                break;\n            }\n            state->length = (unsigned)hold & 0xffff;\n            Tracev((stderr, \"inflate:       stored length %u\\n\",\n                    state->length));\n            INITBITS();\n\n            /* copy stored block from input to output */\n            while (state->length != 0) {\n                copy = state->length;\n                PULL();\n                ROOM();\n                if (copy > have) copy = have;\n                if (copy > left) copy = left;\n                zmemcpy(put, next, copy);\n                have -= copy;\n                next += copy;\n                left -= copy;\n                put += copy;\n                state->length -= copy;\n            }\n            Tracev((stderr, \"inflate:       stored end\\n\"));\n            state->mode = TYPE;\n            break;\n\n        case TABLE:\n            /* get dynamic table entries descriptor */\n            NEEDBITS(14);\n            state->nlen = BITS(5) + 257;\n            DROPBITS(5);\n            state->ndist = BITS(5) + 1;\n            DROPBITS(5);\n            state->ncode = BITS(4) + 4;\n            DROPBITS(4);\n#ifndef PKZIP_BUG_WORKAROUND\n            if (state->nlen > 286 || state->ndist > 30) {\n                strm->msg = (char *)\"too many length or distance symbols\";\n                state->mode = BAD;\n                break;\n            }\n#endif\n            Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n\n            /* get code length code lengths (not a typo) */\n            state->have = 0;\n            while (state->have < state->ncode) {\n                NEEDBITS(3);\n                state->lens[order[state->have++]] = (unsigned short)BITS(3);\n                DROPBITS(3);\n            }\n            while (state->have < 19)\n                state->lens[order[state->have++]] = 0;\n            state->next = state->codes;\n            state->lencode = (code const FAR *)(state->next);\n            state->lenbits = 7;\n            ret = inflate_table(CODES, state->lens, 19, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid code lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n\n            /* get length and distance code code lengths */\n            state->have = 0;\n            while (state->have < state->nlen + state->ndist) {\n                for (;;) {\n                    here = state->lencode[BITS(state->lenbits)];\n                    if ((unsigned)(here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                if (here.val < 16) {\n                    DROPBITS(here.bits);\n                    state->lens[state->have++] = here.val;\n                }\n                else {\n                    if (here.val == 16) {\n                        NEEDBITS(here.bits + 2);\n                        DROPBITS(here.bits);\n                        if (state->have == 0) {\n                            strm->msg = (char *)\"invalid bit length repeat\";\n                            state->mode = BAD;\n                            break;\n                        }\n                        len = (unsigned)(state->lens[state->have - 1]);\n                        copy = 3 + BITS(2);\n                        DROPBITS(2);\n                    }\n                    else if (here.val == 17) {\n                        NEEDBITS(here.bits + 3);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 3 + BITS(3);\n                        DROPBITS(3);\n                    }\n                    else {\n                        NEEDBITS(here.bits + 7);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 11 + BITS(7);\n                        DROPBITS(7);\n                    }\n                    if (state->have + copy > state->nlen + state->ndist) {\n                        strm->msg = (char *)\"invalid bit length repeat\";\n                        state->mode = BAD;\n                        break;\n                    }\n                    while (copy--)\n                        state->lens[state->have++] = (unsigned short)len;\n                }\n            }\n\n            /* handle error breaks in while */\n            if (state->mode == BAD) break;\n\n            /* check for end-of-block code (better have one) */\n            if (state->lens[256] == 0) {\n                strm->msg = (char *)\"invalid code -- missing end-of-block\";\n                state->mode = BAD;\n                break;\n            }\n\n            /* build code tables -- note: do not change the lenbits or distbits\n               values here (9 and 6) without reading the comments in inftrees.h\n               concerning the ENOUGH constants, which depend on those values */\n            state->next = state->codes;\n            state->lencode = (code const FAR *)(state->next);\n            state->lenbits = 9;\n            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid literal/lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            state->distcode = (code const FAR *)(state->next);\n            state->distbits = 6;\n            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,\n                            &(state->next), &(state->distbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid distances set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       codes ok\\n\"));\n            state->mode = LEN;\n\n        case LEN:\n            /* use inflate_fast() if we have enough input and output */\n            if (have >= 6 && left >= 258) {\n                RESTORE();\n                if (state->whave < state->wsize)\n                    state->whave = state->wsize - left;\n                inflate_fast(strm, state->wsize);\n                LOAD();\n                break;\n            }\n\n            /* get a literal, length, or end-of-block code */\n            for (;;) {\n                here = state->lencode[BITS(state->lenbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if (here.op && (here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->lencode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n            }\n            DROPBITS(here.bits);\n            state->length = (unsigned)here.val;\n\n            /* process literal */\n            if (here.op == 0) {\n                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n                        \"inflate:         literal '%c'\\n\" :\n                        \"inflate:         literal 0x%02x\\n\", here.val));\n                ROOM();\n                *put++ = (unsigned char)(state->length);\n                left--;\n                state->mode = LEN;\n                break;\n            }\n\n            /* process end of block */\n            if (here.op & 32) {\n                Tracevv((stderr, \"inflate:         end of block\\n\"));\n                state->mode = TYPE;\n                break;\n            }\n\n            /* invalid code */\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid literal/length code\";\n                state->mode = BAD;\n                break;\n            }\n\n            /* length code -- get extra bits, if any */\n            state->extra = (unsigned)(here.op) & 15;\n            if (state->extra != 0) {\n                NEEDBITS(state->extra);\n                state->length += BITS(state->extra);\n                DROPBITS(state->extra);\n            }\n            Tracevv((stderr, \"inflate:         length %u\\n\", state->length));\n\n            /* get distance code */\n            for (;;) {\n                here = state->distcode[BITS(state->distbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if ((here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->distcode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n            }\n            DROPBITS(here.bits);\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid distance code\";\n                state->mode = BAD;\n                break;\n            }\n            state->offset = (unsigned)here.val;\n\n            /* get distance extra bits, if any */\n            state->extra = (unsigned)(here.op) & 15;\n            if (state->extra != 0) {\n                NEEDBITS(state->extra);\n                state->offset += BITS(state->extra);\n                DROPBITS(state->extra);\n            }\n            if (state->offset > state->wsize - (state->whave < state->wsize ?\n                                                left : 0)) {\n                strm->msg = (char *)\"invalid distance too far back\";\n                state->mode = BAD;\n                break;\n            }\n            Tracevv((stderr, \"inflate:         distance %u\\n\", state->offset));\n\n            /* copy match from window to output */\n            do {\n                ROOM();\n                copy = state->wsize - state->offset;\n                if (copy < left) {\n                    from = put + copy;\n                    copy = left - copy;\n                }\n                else {\n                    from = put - state->offset;\n                    copy = left;\n                }\n                if (copy > state->length) copy = state->length;\n                state->length -= copy;\n                left -= copy;\n                do {\n                    *put++ = *from++;\n                } while (--copy);\n            } while (state->length != 0);\n            break;\n\n        case DONE:\n            /* inflate stream terminated properly -- write leftover output */\n            ret = Z_STREAM_END;\n            if (left < state->wsize) {\n                if (out(out_desc, state->window, state->wsize - left))\n                    ret = Z_BUF_ERROR;\n            }\n            goto inf_leave;\n\n        case BAD:\n            ret = Z_DATA_ERROR;\n            goto inf_leave;\n\n        default:                /* can't happen, but makes compilers happy */\n            ret = Z_STREAM_ERROR;\n            goto inf_leave;\n        }\n\n    /* Return unused input */\n  inf_leave:\n    strm->next_in = next;\n    strm->avail_in = have;\n    return ret;\n}\n\nint ZEXPORT inflateBackEnd(strm)\nz_streamp strm;\n{\n    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)\n        return Z_STREAM_ERROR;\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n    Tracev((stderr, \"inflate: end\\n\"));\n    return Z_OK;\n}\n"
  },
  {
    "path": "dlib/external/zlib/inffast.c",
    "content": "/* inffast.c -- fast decoding\n * Copyright (C) 1995-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n#include \"inflate.h\"\n#include \"inffast.h\"\n\n#ifdef ASMINF\n#  pragma message(\"Assembler code may have bugs -- use at your own risk\")\n#else\n\n/*\n   Decode literal, length, and distance codes and write out the resulting\n   literal and match bytes until either not enough input or output is\n   available, an end-of-block is encountered, or a data error is encountered.\n   When large enough input and output buffers are supplied to inflate(), for\n   example, a 16K input buffer and a 64K output buffer, more than 95% of the\n   inflate execution time is spent in this routine.\n\n   Entry assumptions:\n\n        state->mode == LEN\n        strm->avail_in >= 6\n        strm->avail_out >= 258\n        start >= strm->avail_out\n        state->bits < 8\n\n   On return, state->mode is one of:\n\n        LEN -- ran out of enough output space or enough available input\n        TYPE -- reached end of block code, inflate() to interpret next block\n        BAD -- error in block data\n\n   Notes:\n\n    - The maximum input bits used by a length/distance pair is 15 bits for the\n      length code, 5 bits for the length extra, 15 bits for the distance code,\n      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.\n      Therefore if strm->avail_in >= 6, then there is enough input to avoid\n      checking for available input while decoding.\n\n    - The maximum bytes that a single length/distance pair can output is 258\n      bytes, which is the maximum length that can be coded.  inflate_fast()\n      requires strm->avail_out >= 258 for each loop to avoid checking for\n      output space.\n */\nvoid ZLIB_INTERNAL inflate_fast(strm, start)\nz_streamp strm;\nunsigned start;         /* inflate()'s starting value for strm->avail_out */\n{\n    struct inflate_state FAR *state;\n    z_const unsigned char FAR *in;      /* local strm->next_in */\n    z_const unsigned char FAR *last;    /* have enough input while in < last */\n    unsigned char FAR *out;     /* local strm->next_out */\n    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */\n    unsigned char FAR *end;     /* while out < end, enough space available */\n#ifdef INFLATE_STRICT\n    unsigned dmax;              /* maximum distance from zlib header */\n#endif\n    unsigned wsize;             /* window size or zero if not using window */\n    unsigned whave;             /* valid bytes in the window */\n    unsigned wnext;             /* window write index */\n    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */\n    unsigned long hold;         /* local strm->hold */\n    unsigned bits;              /* local strm->bits */\n    code const FAR *lcode;      /* local strm->lencode */\n    code const FAR *dcode;      /* local strm->distcode */\n    unsigned lmask;             /* mask for first level of length codes */\n    unsigned dmask;             /* mask for first level of distance codes */\n    code here;                  /* retrieved table entry */\n    unsigned op;                /* code bits, operation, extra bits, or */\n                                /*  window position, window bytes to copy */\n    unsigned len;               /* match length, unused bytes */\n    unsigned dist;              /* match distance */\n    unsigned char FAR *from;    /* where to copy match from */\n\n    /* copy state to local variables */\n    state = (struct inflate_state FAR *)strm->state;\n    in = strm->next_in;\n    last = in + (strm->avail_in - 5);\n    out = strm->next_out;\n    beg = out - (start - strm->avail_out);\n    end = out + (strm->avail_out - 257);\n#ifdef INFLATE_STRICT\n    dmax = state->dmax;\n#endif\n    wsize = state->wsize;\n    whave = state->whave;\n    wnext = state->wnext;\n    window = state->window;\n    hold = state->hold;\n    bits = state->bits;\n    lcode = state->lencode;\n    dcode = state->distcode;\n    lmask = (1U << state->lenbits) - 1;\n    dmask = (1U << state->distbits) - 1;\n\n    /* decode literals and length/distances until end-of-block or not enough\n       input data or output space */\n    do {\n        if (bits < 15) {\n            hold += (unsigned long)(*in++) << bits;\n            bits += 8;\n            hold += (unsigned long)(*in++) << bits;\n            bits += 8;\n        }\n        here = lcode[hold & lmask];\n      dolen:\n        op = (unsigned)(here.bits);\n        hold >>= op;\n        bits -= op;\n        op = (unsigned)(here.op);\n        if (op == 0) {                          /* literal */\n            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n                    \"inflate:         literal '%c'\\n\" :\n                    \"inflate:         literal 0x%02x\\n\", here.val));\n            *out++ = (unsigned char)(here.val);\n        }\n        else if (op & 16) {                     /* length base */\n            len = (unsigned)(here.val);\n            op &= 15;                           /* number of extra bits */\n            if (op) {\n                if (bits < op) {\n                    hold += (unsigned long)(*in++) << bits;\n                    bits += 8;\n                }\n                len += (unsigned)hold & ((1U << op) - 1);\n                hold >>= op;\n                bits -= op;\n            }\n            Tracevv((stderr, \"inflate:         length %u\\n\", len));\n            if (bits < 15) {\n                hold += (unsigned long)(*in++) << bits;\n                bits += 8;\n                hold += (unsigned long)(*in++) << bits;\n                bits += 8;\n            }\n            here = dcode[hold & dmask];\n          dodist:\n            op = (unsigned)(here.bits);\n            hold >>= op;\n            bits -= op;\n            op = (unsigned)(here.op);\n            if (op & 16) {                      /* distance base */\n                dist = (unsigned)(here.val);\n                op &= 15;                       /* number of extra bits */\n                if (bits < op) {\n                    hold += (unsigned long)(*in++) << bits;\n                    bits += 8;\n                    if (bits < op) {\n                        hold += (unsigned long)(*in++) << bits;\n                        bits += 8;\n                    }\n                }\n                dist += (unsigned)hold & ((1U << op) - 1);\n#ifdef INFLATE_STRICT\n                if (dist > dmax) {\n                    strm->msg = (char *)\"invalid distance too far back\";\n                    state->mode = BAD;\n                    break;\n                }\n#endif\n                hold >>= op;\n                bits -= op;\n                Tracevv((stderr, \"inflate:         distance %u\\n\", dist));\n                op = (unsigned)(out - beg);     /* max distance in output */\n                if (dist > op) {                /* see if copy from window */\n                    op = dist - op;             /* distance back in window */\n                    if (op > whave) {\n                        if (state->sane) {\n                            strm->msg =\n                                (char *)\"invalid distance too far back\";\n                            state->mode = BAD;\n                            break;\n                        }\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n                        if (len <= op - whave) {\n                            do {\n                                *out++ = 0;\n                            } while (--len);\n                            continue;\n                        }\n                        len -= op - whave;\n                        do {\n                            *out++ = 0;\n                        } while (--op > whave);\n                        if (op == 0) {\n                            from = out - dist;\n                            do {\n                                *out++ = *from++;\n                            } while (--len);\n                            continue;\n                        }\n#endif\n                    }\n                    from = window;\n                    if (wnext == 0) {           /* very common case */\n                        from += wsize - op;\n                        if (op < len) {         /* some from window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = out - dist;  /* rest from output */\n                        }\n                    }\n                    else if (wnext < op) {      /* wrap around window */\n                        from += wsize + wnext - op;\n                        op -= wnext;\n                        if (op < len) {         /* some from end of window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = window;\n                            if (wnext < len) {  /* some from start of window */\n                                op = wnext;\n                                len -= op;\n                                do {\n                                    *out++ = *from++;\n                                } while (--op);\n                                from = out - dist;      /* rest from output */\n                            }\n                        }\n                    }\n                    else {                      /* contiguous in window */\n                        from += wnext - op;\n                        if (op < len) {         /* some from window */\n                            len -= op;\n                            do {\n                                *out++ = *from++;\n                            } while (--op);\n                            from = out - dist;  /* rest from output */\n                        }\n                    }\n                    while (len > 2) {\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        len -= 3;\n                    }\n                    if (len) {\n                        *out++ = *from++;\n                        if (len > 1)\n                            *out++ = *from++;\n                    }\n                }\n                else {\n                    from = out - dist;          /* copy direct from output */\n                    do {                        /* minimum length is three */\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        *out++ = *from++;\n                        len -= 3;\n                    } while (len > 2);\n                    if (len) {\n                        *out++ = *from++;\n                        if (len > 1)\n                            *out++ = *from++;\n                    }\n                }\n            }\n            else if ((op & 64) == 0) {          /* 2nd level distance code */\n                here = dcode[here.val + (hold & ((1U << op) - 1))];\n                goto dodist;\n            }\n            else {\n                strm->msg = (char *)\"invalid distance code\";\n                state->mode = BAD;\n                break;\n            }\n        }\n        else if ((op & 64) == 0) {              /* 2nd level length code */\n            here = lcode[here.val + (hold & ((1U << op) - 1))];\n            goto dolen;\n        }\n        else if (op & 32) {                     /* end-of-block */\n            Tracevv((stderr, \"inflate:         end of block\\n\"));\n            state->mode = TYPE;\n            break;\n        }\n        else {\n            strm->msg = (char *)\"invalid literal/length code\";\n            state->mode = BAD;\n            break;\n        }\n    } while (in < last && out < end);\n\n    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */\n    len = bits >> 3;\n    in -= len;\n    bits -= len << 3;\n    hold &= (1U << bits) - 1;\n\n    /* update state and return */\n    strm->next_in = in;\n    strm->next_out = out;\n    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));\n    strm->avail_out = (unsigned)(out < end ?\n                                 257 + (end - out) : 257 - (out - end));\n    state->hold = hold;\n    state->bits = bits;\n    return;\n}\n\n/*\n   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):\n   - Using bit fields for code structure\n   - Different op definition to avoid & for extra bits (do & for table bits)\n   - Three separate decoding do-loops for direct, window, and wnext == 0\n   - Special case for distance > 1 copies to do overlapped load and store copy\n   - Explicit branch predictions (based on measured branch probabilities)\n   - Deferring match copy and interspersed it with decoding subsequent codes\n   - Swapping literal/length else\n   - Swapping window/direct else\n   - Larger unrolled copy loops (three is about right)\n   - Moving len -= 3 statement into middle of loop\n */\n\n#endif /* !ASMINF */\n"
  },
  {
    "path": "dlib/external/zlib/inffast.h",
    "content": "/* inffast.h -- header to use inffast.c\n * Copyright (C) 1995-2003, 2010 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\nvoid ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));\n"
  },
  {
    "path": "dlib/external/zlib/inffixed.h",
    "content": "    /* inffixed.h -- table for decoding fixed codes\n     * Generated automatically by makefixed().\n     */\n\n    /* WARNING: this file should *not* be used by applications.\n       It is part of the implementation of this library and is\n       subject to change. Applications should only use zlib.h.\n     */\n\n    static const code lenfix[512] = {\n        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},\n        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},\n        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},\n        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},\n        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},\n        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},\n        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},\n        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},\n        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},\n        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},\n        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},\n        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},\n        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},\n        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},\n        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},\n        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},\n        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},\n        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},\n        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},\n        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},\n        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},\n        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},\n        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},\n        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},\n        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},\n        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},\n        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},\n        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},\n        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},\n        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},\n        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},\n        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},\n        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},\n        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},\n        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},\n        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},\n        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},\n        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},\n        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},\n        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},\n        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},\n        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},\n        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},\n        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},\n        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},\n        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},\n        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},\n        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},\n        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},\n        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},\n        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},\n        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},\n        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},\n        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},\n        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},\n        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},\n        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},\n        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},\n        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},\n        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},\n        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},\n        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},\n        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},\n        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},\n        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},\n        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},\n        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},\n        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},\n        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},\n        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},\n        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},\n        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},\n        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},\n        {0,9,255}\n    };\n\n    static const code distfix[32] = {\n        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},\n        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},\n        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},\n        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},\n        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},\n        {22,5,193},{64,5,0}\n    };\n"
  },
  {
    "path": "dlib/external/zlib/inflate.c",
    "content": "/* inflate.c -- zlib decompression\n * Copyright (C) 1995-2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n * Change history:\n *\n * 1.2.beta0    24 Nov 2002\n * - First version -- complete rewrite of inflate to simplify code, avoid\n *   creation of window when not needed, minimize use of window when it is\n *   needed, make inffast.c even faster, implement gzip decoding, and to\n *   improve code readability and style over the previous zlib inflate code\n *\n * 1.2.beta1    25 Nov 2002\n * - Use pointers for available input and output checking in inffast.c\n * - Remove input and output counters in inffast.c\n * - Change inffast.c entry and loop from avail_in >= 7 to >= 6\n * - Remove unnecessary second byte pull from length extra in inffast.c\n * - Unroll direct copy to three copies per loop in inffast.c\n *\n * 1.2.beta2    4 Dec 2002\n * - Change external routine names to reduce potential conflicts\n * - Correct filename to inffixed.h for fixed tables in inflate.c\n * - Make hbuf[] unsigned char to match parameter type in inflate.c\n * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)\n *   to avoid negation problem on Alphas (64 bit) in inflate.c\n *\n * 1.2.beta3    22 Dec 2002\n * - Add comments on state->bits assertion in inffast.c\n * - Add comments on op field in inftrees.h\n * - Fix bug in reuse of allocated window after inflateReset()\n * - Remove bit fields--back to byte structure for speed\n * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths\n * - Change post-increments to pre-increments in inflate_fast(), PPC biased?\n * - Add compile time option, POSTINC, to use post-increments instead (Intel?)\n * - Make MATCH copy in inflate() much faster for when inflate_fast() not used\n * - Use local copies of stream next and avail values, as well as local bit\n *   buffer and bit count in inflate()--for speed when inflate_fast() not used\n *\n * 1.2.beta4    1 Jan 2003\n * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings\n * - Move a comment on output buffer sizes from inffast.c to inflate.c\n * - Add comments in inffast.c to introduce the inflate_fast() routine\n * - Rearrange window copies in inflate_fast() for speed and simplification\n * - Unroll last copy for window match in inflate_fast()\n * - Use local copies of window variables in inflate_fast() for speed\n * - Pull out common wnext == 0 case for speed in inflate_fast()\n * - Make op and len in inflate_fast() unsigned for consistency\n * - Add FAR to lcode and dcode declarations in inflate_fast()\n * - Simplified bad distance check in inflate_fast()\n * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new\n *   source file infback.c to provide a call-back interface to inflate for\n *   programs like gzip and unzip -- uses window as output buffer to avoid\n *   window copying\n *\n * 1.2.beta5    1 Jan 2003\n * - Improved inflateBack() interface to allow the caller to provide initial\n *   input in strm.\n * - Fixed stored blocks bug in inflateBack()\n *\n * 1.2.beta6    4 Jan 2003\n * - Added comments in inffast.c on effectiveness of POSTINC\n * - Typecasting all around to reduce compiler warnings\n * - Changed loops from while (1) or do {} while (1) to for (;;), again to\n *   make compilers happy\n * - Changed type of window in inflateBackInit() to unsigned char *\n *\n * 1.2.beta7    27 Jan 2003\n * - Changed many types to unsigned or unsigned short to avoid warnings\n * - Added inflateCopy() function\n *\n * 1.2.0        9 Mar 2003\n * - Changed inflateBack() interface to provide separate opaque descriptors\n *   for the in() and out() functions\n * - Changed inflateBack() argument and in_func typedef to swap the length\n *   and buffer address return values for the input function\n * - Check next_in and next_out for Z_NULL on entry to inflate()\n *\n * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n#include \"inflate.h\"\n#include \"inffast.h\"\n\n#ifdef MAKEFIXED\n#  ifndef BUILDFIXED\n#    define BUILDFIXED\n#  endif\n#endif\n\n/* function prototypes */\nlocal int inflateStateCheck OF((z_streamp strm));\nlocal void fixedtables OF((struct inflate_state FAR *state));\nlocal int updatewindow OF((z_streamp strm, const unsigned char FAR *end,\n                           unsigned copy));\n#ifdef BUILDFIXED\n   void makefixed OF((void));\n#endif\nlocal unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,\n                              unsigned len));\n\nlocal int inflateStateCheck(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (strm == Z_NULL ||\n        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)\n        return 1;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state == Z_NULL || state->strm != strm ||\n        state->mode < HEAD || state->mode > SYNC)\n        return 1;\n    return 0;\n}\n\nint ZEXPORT inflateResetKeep(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    strm->total_in = strm->total_out = state->total = 0;\n    strm->msg = Z_NULL;\n    if (state->wrap)        /* to support ill-conceived Java test suite */\n        strm->adler = state->wrap & 1;\n    state->mode = HEAD;\n    state->last = 0;\n    state->havedict = 0;\n    state->dmax = 32768U;\n    state->head = Z_NULL;\n    state->hold = 0;\n    state->bits = 0;\n    state->lencode = state->distcode = state->next = state->codes;\n    state->sane = 1;\n    state->back = -1;\n    Tracev((stderr, \"inflate: reset\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateReset(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    state->wsize = 0;\n    state->whave = 0;\n    state->wnext = 0;\n    return inflateResetKeep(strm);\n}\n\nint ZEXPORT inflateReset2(strm, windowBits)\nz_streamp strm;\nint windowBits;\n{\n    int wrap;\n    struct inflate_state FAR *state;\n\n    /* get the state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* extract wrap request from windowBits parameter */\n    if (windowBits < 0) {\n        wrap = 0;\n        windowBits = -windowBits;\n    }\n    else {\n        wrap = (windowBits >> 4) + 5;\n#ifdef GUNZIP\n        if (windowBits < 48)\n            windowBits &= 15;\n#endif\n    }\n\n    /* set number of window bits, free window if different */\n    if (windowBits && (windowBits < 8 || windowBits > 15))\n        return Z_STREAM_ERROR;\n    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {\n        ZFREE(strm, state->window);\n        state->window = Z_NULL;\n    }\n\n    /* update state and reset the rest of it */\n    state->wrap = wrap;\n    state->wbits = (unsigned)windowBits;\n    return inflateReset(strm);\n}\n\nint ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)\nz_streamp strm;\nint windowBits;\nconst char *version;\nint stream_size;\n{\n    int ret;\n    struct inflate_state FAR *state;\n\n    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||\n        stream_size != (int)(sizeof(z_stream)))\n        return Z_VERSION_ERROR;\n    if (strm == Z_NULL) return Z_STREAM_ERROR;\n    strm->msg = Z_NULL;                 /* in case we return an error */\n    if (strm->zalloc == (alloc_func)0) {\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zalloc = zcalloc;\n        strm->opaque = (voidpf)0;\n#endif\n    }\n    if (strm->zfree == (free_func)0)\n#ifdef Z_SOLO\n        return Z_STREAM_ERROR;\n#else\n        strm->zfree = zcfree;\n#endif\n    state = (struct inflate_state FAR *)\n            ZALLOC(strm, 1, sizeof(struct inflate_state));\n    if (state == Z_NULL) return Z_MEM_ERROR;\n    Tracev((stderr, \"inflate: allocated\\n\"));\n    strm->state = (struct internal_state FAR *)state;\n    state->strm = strm;\n    state->window = Z_NULL;\n    state->mode = HEAD;     /* to pass state test in inflateReset2() */\n    ret = inflateReset2(strm, windowBits);\n    if (ret != Z_OK) {\n        ZFREE(strm, state);\n        strm->state = Z_NULL;\n    }\n    return ret;\n}\n\nint ZEXPORT inflateInit_(strm, version, stream_size)\nz_streamp strm;\nconst char *version;\nint stream_size;\n{\n    return inflateInit2_(strm, DEF_WBITS, version, stream_size);\n}\n\nint ZEXPORT inflatePrime(strm, bits, value)\nz_streamp strm;\nint bits;\nint value;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (bits < 0) {\n        state->hold = 0;\n        state->bits = 0;\n        return Z_OK;\n    }\n    if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;\n    value &= (1L << bits) - 1;\n    state->hold += (unsigned)value << state->bits;\n    state->bits += (uInt)bits;\n    return Z_OK;\n}\n\n/*\n   Return state with length and distance decoding tables and index sizes set to\n   fixed code decoding.  Normally this returns fixed tables from inffixed.h.\n   If BUILDFIXED is defined, then instead this routine builds the tables the\n   first time it's called, and returns those tables the first time and\n   thereafter.  This reduces the size of the code by about 2K bytes, in\n   exchange for a little execution time.  However, BUILDFIXED should not be\n   used for threaded applications, since the rewriting of the tables and virgin\n   may not be thread-safe.\n */\nlocal void fixedtables(state)\nstruct inflate_state FAR *state;\n{\n#ifdef BUILDFIXED\n    static int virgin = 1;\n    static code *lenfix, *distfix;\n    static code fixed[544];\n\n    /* build fixed huffman tables if first call (may not be thread safe) */\n    if (virgin) {\n        unsigned sym, bits;\n        static code *next;\n\n        /* literal/length table */\n        sym = 0;\n        while (sym < 144) state->lens[sym++] = 8;\n        while (sym < 256) state->lens[sym++] = 9;\n        while (sym < 280) state->lens[sym++] = 7;\n        while (sym < 288) state->lens[sym++] = 8;\n        next = fixed;\n        lenfix = next;\n        bits = 9;\n        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);\n\n        /* distance table */\n        sym = 0;\n        while (sym < 32) state->lens[sym++] = 5;\n        distfix = next;\n        bits = 5;\n        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);\n\n        /* do this just once */\n        virgin = 0;\n    }\n#else /* !BUILDFIXED */\n#   include \"inffixed.h\"\n#endif /* BUILDFIXED */\n    state->lencode = lenfix;\n    state->lenbits = 9;\n    state->distcode = distfix;\n    state->distbits = 5;\n}\n\n#ifdef MAKEFIXED\n#include <stdio.h>\n\n/*\n   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also\n   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes\n   those tables to stdout, which would be piped to inffixed.h.  A small program\n   can simply call makefixed to do this:\n\n    void makefixed(void);\n\n    int main(void)\n    {\n        makefixed();\n        return 0;\n    }\n\n   Then that can be linked with zlib built with MAKEFIXED defined and run:\n\n    a.out > inffixed.h\n */\nvoid makefixed()\n{\n    unsigned low, size;\n    struct inflate_state state;\n\n    fixedtables(&state);\n    puts(\"    /* inffixed.h -- table for decoding fixed codes\");\n    puts(\"     * Generated automatically by makefixed().\");\n    puts(\"     */\");\n    puts(\"\");\n    puts(\"    /* WARNING: this file should *not* be used by applications.\");\n    puts(\"       It is part of the implementation of this library and is\");\n    puts(\"       subject to change. Applications should only use zlib.h.\");\n    puts(\"     */\");\n    puts(\"\");\n    size = 1U << 9;\n    printf(\"    static const code lenfix[%u] = {\", size);\n    low = 0;\n    for (;;) {\n        if ((low % 7) == 0) printf(\"\\n        \");\n        printf(\"{%u,%u,%d}\", (low & 127) == 99 ? 64 : state.lencode[low].op,\n               state.lencode[low].bits, state.lencode[low].val);\n        if (++low == size) break;\n        putchar(',');\n    }\n    puts(\"\\n    };\");\n    size = 1U << 5;\n    printf(\"\\n    static const code distfix[%u] = {\", size);\n    low = 0;\n    for (;;) {\n        if ((low % 6) == 0) printf(\"\\n        \");\n        printf(\"{%u,%u,%d}\", state.distcode[low].op, state.distcode[low].bits,\n               state.distcode[low].val);\n        if (++low == size) break;\n        putchar(',');\n    }\n    puts(\"\\n    };\");\n}\n#endif /* MAKEFIXED */\n\n/*\n   Update the window with the last wsize (normally 32K) bytes written before\n   returning.  If window does not exist yet, create it.  This is only called\n   when a window is already in use, or when output has been written during this\n   inflate call, but the end of the deflate stream has not been reached yet.\n   It is also called to create a window for dictionary data when a dictionary\n   is loaded.\n\n   Providing output buffers larger than 32K to inflate() should provide a speed\n   advantage, since only the last 32K of output is copied to the sliding window\n   upon return from inflate(), and since all distances after the first 32K of\n   output will fall in the output data, making match copies simpler and faster.\n   The advantage may be dependent on the size of the processor's data caches.\n */\nlocal int updatewindow(strm, end, copy)\nz_streamp strm;\nconst Bytef *end;\nunsigned copy;\n{\n    struct inflate_state FAR *state;\n    unsigned dist;\n\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* if it hasn't been done already, allocate space for the window */\n    if (state->window == Z_NULL) {\n        state->window = (unsigned char FAR *)\n                        ZALLOC(strm, 1U << state->wbits,\n                               sizeof(unsigned char));\n        if (state->window == Z_NULL) return 1;\n    }\n\n    /* if window not in use yet, initialize */\n    if (state->wsize == 0) {\n        state->wsize = 1U << state->wbits;\n        state->wnext = 0;\n        state->whave = 0;\n    }\n\n    /* copy state->wsize or less output bytes into the circular window */\n    if (copy >= state->wsize) {\n        zmemcpy(state->window, end - state->wsize, state->wsize);\n        state->wnext = 0;\n        state->whave = state->wsize;\n    }\n    else {\n        dist = state->wsize - state->wnext;\n        if (dist > copy) dist = copy;\n        zmemcpy(state->window + state->wnext, end - copy, dist);\n        copy -= dist;\n        if (copy) {\n            zmemcpy(state->window, end - copy, copy);\n            state->wnext = copy;\n            state->whave = state->wsize;\n        }\n        else {\n            state->wnext += dist;\n            if (state->wnext == state->wsize) state->wnext = 0;\n            if (state->whave < state->wsize) state->whave += dist;\n        }\n    }\n    return 0;\n}\n\n/* Macros for inflate(): */\n\n/* check function to use adler32() for zlib or crc32() for gzip */\n#ifdef GUNZIP\n#  define UPDATE(check, buf, len) \\\n    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))\n#else\n#  define UPDATE(check, buf, len) adler32(check, buf, len)\n#endif\n\n/* check macros for header crc */\n#ifdef GUNZIP\n#  define CRC2(check, word) \\\n    do { \\\n        hbuf[0] = (unsigned char)(word); \\\n        hbuf[1] = (unsigned char)((word) >> 8); \\\n        check = crc32(check, hbuf, 2); \\\n    } while (0)\n\n#  define CRC4(check, word) \\\n    do { \\\n        hbuf[0] = (unsigned char)(word); \\\n        hbuf[1] = (unsigned char)((word) >> 8); \\\n        hbuf[2] = (unsigned char)((word) >> 16); \\\n        hbuf[3] = (unsigned char)((word) >> 24); \\\n        check = crc32(check, hbuf, 4); \\\n    } while (0)\n#endif\n\n/* Load registers with state in inflate() for speed */\n#define LOAD() \\\n    do { \\\n        put = strm->next_out; \\\n        left = strm->avail_out; \\\n        next = strm->next_in; \\\n        have = strm->avail_in; \\\n        hold = state->hold; \\\n        bits = state->bits; \\\n    } while (0)\n\n/* Restore state from registers in inflate() */\n#define RESTORE() \\\n    do { \\\n        strm->next_out = put; \\\n        strm->avail_out = left; \\\n        strm->next_in = next; \\\n        strm->avail_in = have; \\\n        state->hold = hold; \\\n        state->bits = bits; \\\n    } while (0)\n\n/* Clear the input bit accumulator */\n#define INITBITS() \\\n    do { \\\n        hold = 0; \\\n        bits = 0; \\\n    } while (0)\n\n/* Get a byte of input into the bit accumulator, or return from inflate()\n   if there is no input available. */\n#define PULLBYTE() \\\n    do { \\\n        if (have == 0) goto inf_leave; \\\n        have--; \\\n        hold += (unsigned long)(*next++) << bits; \\\n        bits += 8; \\\n    } while (0)\n\n/* Assure that there are at least n bits in the bit accumulator.  If there is\n   not enough available input to do that, then return from inflate(). */\n#define NEEDBITS(n) \\\n    do { \\\n        while (bits < (unsigned)(n)) \\\n            PULLBYTE(); \\\n    } while (0)\n\n/* Return the low n bits of the bit accumulator (n < 16) */\n#define BITS(n) \\\n    ((unsigned)hold & ((1U << (n)) - 1))\n\n/* Remove n bits from the bit accumulator */\n#define DROPBITS(n) \\\n    do { \\\n        hold >>= (n); \\\n        bits -= (unsigned)(n); \\\n    } while (0)\n\n/* Remove zero to seven bits as needed to go to a byte boundary */\n#define BYTEBITS() \\\n    do { \\\n        hold >>= bits & 7; \\\n        bits -= bits & 7; \\\n    } while (0)\n\n/*\n   inflate() uses a state machine to process as much input data and generate as\n   much output data as possible before returning.  The state machine is\n   structured roughly as follows:\n\n    for (;;) switch (state) {\n    ...\n    case STATEn:\n        if (not enough input data or output space to make progress)\n            return;\n        ... make progress ...\n        state = STATEm;\n        break;\n    ...\n    }\n\n   so when inflate() is called again, the same case is attempted again, and\n   if the appropriate resources are provided, the machine proceeds to the\n   next state.  The NEEDBITS() macro is usually the way the state evaluates\n   whether it can proceed or should return.  NEEDBITS() does the return if\n   the requested bits are not available.  The typical use of the BITS macros\n   is:\n\n        NEEDBITS(n);\n        ... do something with BITS(n) ...\n        DROPBITS(n);\n\n   where NEEDBITS(n) either returns from inflate() if there isn't enough\n   input left to load n bits into the accumulator, or it continues.  BITS(n)\n   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops\n   the low n bits off the accumulator.  INITBITS() clears the accumulator\n   and sets the number of available bits to zero.  BYTEBITS() discards just\n   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()\n   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.\n\n   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return\n   if there is no input available.  The decoding of variable length codes uses\n   PULLBYTE() directly in order to pull just enough bytes to decode the next\n   code, and no more.\n\n   Some states loop until they get enough input, making sure that enough\n   state information is maintained to continue the loop where it left off\n   if NEEDBITS() returns in the loop.  For example, want, need, and keep\n   would all have to actually be part of the saved state in case NEEDBITS()\n   returns:\n\n    case STATEw:\n        while (want < need) {\n            NEEDBITS(n);\n            keep[want++] = BITS(n);\n            DROPBITS(n);\n        }\n        state = STATEx;\n    case STATEx:\n\n   As shown above, if the next state is also the next case, then the break\n   is omitted.\n\n   A state may also return if there is not enough output space available to\n   complete that state.  Those states are copying stored data, writing a\n   literal byte, and copying a matching string.\n\n   When returning, a \"goto inf_leave\" is used to update the total counters,\n   update the check value, and determine whether any progress has been made\n   during that inflate() call in order to return the proper return code.\n   Progress is defined as a change in either strm->avail_in or strm->avail_out.\n   When there is a window, goto inf_leave will update the window with the last\n   output written.  If a goto inf_leave occurs in the middle of decompression\n   and there is no window currently, goto inf_leave will create one and copy\n   output to the window for the next call of inflate().\n\n   In this implementation, the flush parameter of inflate() only affects the\n   return code (per zlib.h).  inflate() always writes as much as possible to\n   strm->next_out, given the space available and the provided input--the effect\n   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers\n   the allocation of and copying into a sliding window until necessary, which\n   provides the effect documented in zlib.h for Z_FINISH when the entire input\n   stream available.  So the only thing the flush parameter actually does is:\n   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it\n   will return Z_BUF_ERROR if it has not reached the end of the stream.\n */\n\nint ZEXPORT inflate(strm, flush)\nz_streamp strm;\nint flush;\n{\n    struct inflate_state FAR *state;\n    z_const unsigned char FAR *next;    /* next input */\n    unsigned char FAR *put;     /* next output */\n    unsigned have, left;        /* available input and output */\n    unsigned long hold;         /* bit buffer */\n    unsigned bits;              /* bits in bit buffer */\n    unsigned in, out;           /* save starting available input and output */\n    unsigned copy;              /* number of stored or match bytes to copy */\n    unsigned char FAR *from;    /* where to copy match bytes from */\n    code here;                  /* current decoding table entry */\n    code last;                  /* parent table entry */\n    unsigned len;               /* length to copy for repeats, bits to drop */\n    int ret;                    /* return code */\n#ifdef GUNZIP\n    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */\n#endif\n    static const unsigned short order[19] = /* permutation of code lengths */\n        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};\n\n    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||\n        (strm->next_in == Z_NULL && strm->avail_in != 0))\n        return Z_STREAM_ERROR;\n\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */\n    LOAD();\n    in = have;\n    out = left;\n    ret = Z_OK;\n    for (;;)\n        switch (state->mode) {\n        case HEAD:\n            if (state->wrap == 0) {\n                state->mode = TYPEDO;\n                break;\n            }\n            NEEDBITS(16);\n#ifdef GUNZIP\n            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */\n                if (state->wbits == 0)\n                    state->wbits = 15;\n                state->check = crc32(0L, Z_NULL, 0);\n                CRC2(state->check, hold);\n                INITBITS();\n                state->mode = FLAGS;\n                break;\n            }\n            state->flags = 0;           /* expect zlib header */\n            if (state->head != Z_NULL)\n                state->head->done = -1;\n            if (!(state->wrap & 1) ||   /* check if zlib header allowed */\n#else\n            if (\n#endif\n                ((BITS(8) << 8) + (hold >> 8)) % 31) {\n                strm->msg = (char *)\"incorrect header check\";\n                state->mode = BAD;\n                break;\n            }\n            if (BITS(4) != Z_DEFLATED) {\n                strm->msg = (char *)\"unknown compression method\";\n                state->mode = BAD;\n                break;\n            }\n            DROPBITS(4);\n            len = BITS(4) + 8;\n            if (state->wbits == 0)\n                state->wbits = len;\n            if (len > 15 || len > state->wbits) {\n                strm->msg = (char *)\"invalid window size\";\n                state->mode = BAD;\n                break;\n            }\n            state->dmax = 1U << len;\n            Tracev((stderr, \"inflate:   zlib header ok\\n\"));\n            strm->adler = state->check = adler32(0L, Z_NULL, 0);\n            state->mode = hold & 0x200 ? DICTID : TYPE;\n            INITBITS();\n            break;\n#ifdef GUNZIP\n        case FLAGS:\n            NEEDBITS(16);\n            state->flags = (int)(hold);\n            if ((state->flags & 0xff) != Z_DEFLATED) {\n                strm->msg = (char *)\"unknown compression method\";\n                state->mode = BAD;\n                break;\n            }\n            if (state->flags & 0xe000) {\n                strm->msg = (char *)\"unknown header flags set\";\n                state->mode = BAD;\n                break;\n            }\n            if (state->head != Z_NULL)\n                state->head->text = (int)((hold >> 8) & 1);\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC2(state->check, hold);\n            INITBITS();\n            state->mode = TIME;\n        case TIME:\n            NEEDBITS(32);\n            if (state->head != Z_NULL)\n                state->head->time = hold;\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC4(state->check, hold);\n            INITBITS();\n            state->mode = OS;\n        case OS:\n            NEEDBITS(16);\n            if (state->head != Z_NULL) {\n                state->head->xflags = (int)(hold & 0xff);\n                state->head->os = (int)(hold >> 8);\n            }\n            if ((state->flags & 0x0200) && (state->wrap & 4))\n                CRC2(state->check, hold);\n            INITBITS();\n            state->mode = EXLEN;\n        case EXLEN:\n            if (state->flags & 0x0400) {\n                NEEDBITS(16);\n                state->length = (unsigned)(hold);\n                if (state->head != Z_NULL)\n                    state->head->extra_len = (unsigned)hold;\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    CRC2(state->check, hold);\n                INITBITS();\n            }\n            else if (state->head != Z_NULL)\n                state->head->extra = Z_NULL;\n            state->mode = EXTRA;\n        case EXTRA:\n            if (state->flags & 0x0400) {\n                copy = state->length;\n                if (copy > have) copy = have;\n                if (copy) {\n                    len = state->head->extra_len - state->length;\n                    if (state->head != Z_NULL &&\n                        state->head->extra != Z_NULL &&\n                        len < state->head->extra_max) {\n                        zmemcpy(state->head->extra + len, next,\n                                len + copy > state->head->extra_max ?\n                                state->head->extra_max - len : copy);\n                    }\n                    if ((state->flags & 0x0200) && (state->wrap & 4))\n                        state->check = crc32(state->check, next, copy);\n                    have -= copy;\n                    next += copy;\n                    state->length -= copy;\n                }\n                if (state->length) goto inf_leave;\n            }\n            state->length = 0;\n            state->mode = NAME;\n        case NAME:\n            if (state->flags & 0x0800) {\n                if (have == 0) goto inf_leave;\n                copy = 0;\n                do {\n                    len = (unsigned)(next[copy++]);\n                    if (state->head != Z_NULL &&\n                            state->head->name != Z_NULL &&\n                            state->length < state->head->name_max)\n                        state->head->name[state->length++] = (Bytef)len;\n                } while (len && copy < have);\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    state->check = crc32(state->check, next, copy);\n                have -= copy;\n                next += copy;\n                if (len) goto inf_leave;\n            }\n            else if (state->head != Z_NULL)\n                state->head->name = Z_NULL;\n            state->length = 0;\n            state->mode = COMMENT;\n        case COMMENT:\n            if (state->flags & 0x1000) {\n                if (have == 0) goto inf_leave;\n                copy = 0;\n                do {\n                    len = (unsigned)(next[copy++]);\n                    if (state->head != Z_NULL &&\n                            state->head->comment != Z_NULL &&\n                            state->length < state->head->comm_max)\n                        state->head->comment[state->length++] = (Bytef)len;\n                } while (len && copy < have);\n                if ((state->flags & 0x0200) && (state->wrap & 4))\n                    state->check = crc32(state->check, next, copy);\n                have -= copy;\n                next += copy;\n                if (len) goto inf_leave;\n            }\n            else if (state->head != Z_NULL)\n                state->head->comment = Z_NULL;\n            state->mode = HCRC;\n        case HCRC:\n            if (state->flags & 0x0200) {\n                NEEDBITS(16);\n                if ((state->wrap & 4) && hold != (state->check & 0xffff)) {\n                    strm->msg = (char *)\"header crc mismatch\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n            }\n            if (state->head != Z_NULL) {\n                state->head->hcrc = (int)((state->flags >> 9) & 1);\n                state->head->done = 1;\n            }\n            strm->adler = state->check = crc32(0L, Z_NULL, 0);\n            state->mode = TYPE;\n            break;\n#endif\n        case DICTID:\n            NEEDBITS(32);\n            strm->adler = state->check = ZSWAP32(hold);\n            INITBITS();\n            state->mode = DICT;\n        case DICT:\n            if (state->havedict == 0) {\n                RESTORE();\n                return Z_NEED_DICT;\n            }\n            strm->adler = state->check = adler32(0L, Z_NULL, 0);\n            state->mode = TYPE;\n        case TYPE:\n            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;\n        case TYPEDO:\n            if (state->last) {\n                BYTEBITS();\n                state->mode = CHECK;\n                break;\n            }\n            NEEDBITS(3);\n            state->last = BITS(1);\n            DROPBITS(1);\n            switch (BITS(2)) {\n            case 0:                             /* stored block */\n                Tracev((stderr, \"inflate:     stored block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = STORED;\n                break;\n            case 1:                             /* fixed block */\n                fixedtables(state);\n                Tracev((stderr, \"inflate:     fixed codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = LEN_;             /* decode codes */\n                if (flush == Z_TREES) {\n                    DROPBITS(2);\n                    goto inf_leave;\n                }\n                break;\n            case 2:                             /* dynamic block */\n                Tracev((stderr, \"inflate:     dynamic codes block%s\\n\",\n                        state->last ? \" (last)\" : \"\"));\n                state->mode = TABLE;\n                break;\n            case 3:\n                strm->msg = (char *)\"invalid block type\";\n                state->mode = BAD;\n            }\n            DROPBITS(2);\n            break;\n        case STORED:\n            BYTEBITS();                         /* go to byte boundary */\n            NEEDBITS(32);\n            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {\n                strm->msg = (char *)\"invalid stored block lengths\";\n                state->mode = BAD;\n                break;\n            }\n            state->length = (unsigned)hold & 0xffff;\n            Tracev((stderr, \"inflate:       stored length %u\\n\",\n                    state->length));\n            INITBITS();\n            state->mode = COPY_;\n            if (flush == Z_TREES) goto inf_leave;\n        case COPY_:\n            state->mode = COPY;\n        case COPY:\n            copy = state->length;\n            if (copy) {\n                if (copy > have) copy = have;\n                if (copy > left) copy = left;\n                if (copy == 0) goto inf_leave;\n                zmemcpy(put, next, copy);\n                have -= copy;\n                next += copy;\n                left -= copy;\n                put += copy;\n                state->length -= copy;\n                break;\n            }\n            Tracev((stderr, \"inflate:       stored end\\n\"));\n            state->mode = TYPE;\n            break;\n        case TABLE:\n            NEEDBITS(14);\n            state->nlen = BITS(5) + 257;\n            DROPBITS(5);\n            state->ndist = BITS(5) + 1;\n            DROPBITS(5);\n            state->ncode = BITS(4) + 4;\n            DROPBITS(4);\n#ifndef PKZIP_BUG_WORKAROUND\n            if (state->nlen > 286 || state->ndist > 30) {\n                strm->msg = (char *)\"too many length or distance symbols\";\n                state->mode = BAD;\n                break;\n            }\n#endif\n            Tracev((stderr, \"inflate:       table sizes ok\\n\"));\n            state->have = 0;\n            state->mode = LENLENS;\n        case LENLENS:\n            while (state->have < state->ncode) {\n                NEEDBITS(3);\n                state->lens[order[state->have++]] = (unsigned short)BITS(3);\n                DROPBITS(3);\n            }\n            while (state->have < 19)\n                state->lens[order[state->have++]] = 0;\n            state->next = state->codes;\n            state->lencode = (const code FAR *)(state->next);\n            state->lenbits = 7;\n            ret = inflate_table(CODES, state->lens, 19, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid code lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       code lengths ok\\n\"));\n            state->have = 0;\n            state->mode = CODELENS;\n        case CODELENS:\n            while (state->have < state->nlen + state->ndist) {\n                for (;;) {\n                    here = state->lencode[BITS(state->lenbits)];\n                    if ((unsigned)(here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                if (here.val < 16) {\n                    DROPBITS(here.bits);\n                    state->lens[state->have++] = here.val;\n                }\n                else {\n                    if (here.val == 16) {\n                        NEEDBITS(here.bits + 2);\n                        DROPBITS(here.bits);\n                        if (state->have == 0) {\n                            strm->msg = (char *)\"invalid bit length repeat\";\n                            state->mode = BAD;\n                            break;\n                        }\n                        len = state->lens[state->have - 1];\n                        copy = 3 + BITS(2);\n                        DROPBITS(2);\n                    }\n                    else if (here.val == 17) {\n                        NEEDBITS(here.bits + 3);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 3 + BITS(3);\n                        DROPBITS(3);\n                    }\n                    else {\n                        NEEDBITS(here.bits + 7);\n                        DROPBITS(here.bits);\n                        len = 0;\n                        copy = 11 + BITS(7);\n                        DROPBITS(7);\n                    }\n                    if (state->have + copy > state->nlen + state->ndist) {\n                        strm->msg = (char *)\"invalid bit length repeat\";\n                        state->mode = BAD;\n                        break;\n                    }\n                    while (copy--)\n                        state->lens[state->have++] = (unsigned short)len;\n                }\n            }\n\n            /* handle error breaks in while */\n            if (state->mode == BAD) break;\n\n            /* check for end-of-block code (better have one) */\n            if (state->lens[256] == 0) {\n                strm->msg = (char *)\"invalid code -- missing end-of-block\";\n                state->mode = BAD;\n                break;\n            }\n\n            /* build code tables -- note: do not change the lenbits or distbits\n               values here (9 and 6) without reading the comments in inftrees.h\n               concerning the ENOUGH constants, which depend on those values */\n            state->next = state->codes;\n            state->lencode = (const code FAR *)(state->next);\n            state->lenbits = 9;\n            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),\n                                &(state->lenbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid literal/lengths set\";\n                state->mode = BAD;\n                break;\n            }\n            state->distcode = (const code FAR *)(state->next);\n            state->distbits = 6;\n            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,\n                            &(state->next), &(state->distbits), state->work);\n            if (ret) {\n                strm->msg = (char *)\"invalid distances set\";\n                state->mode = BAD;\n                break;\n            }\n            Tracev((stderr, \"inflate:       codes ok\\n\"));\n            state->mode = LEN_;\n            if (flush == Z_TREES) goto inf_leave;\n        case LEN_:\n            state->mode = LEN;\n        case LEN:\n            if (have >= 6 && left >= 258) {\n                RESTORE();\n                inflate_fast(strm, out);\n                LOAD();\n                if (state->mode == TYPE)\n                    state->back = -1;\n                break;\n            }\n            state->back = 0;\n            for (;;) {\n                here = state->lencode[BITS(state->lenbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if (here.op && (here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->lencode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n                state->back += last.bits;\n            }\n            DROPBITS(here.bits);\n            state->back += here.bits;\n            state->length = (unsigned)here.val;\n            if ((int)(here.op) == 0) {\n                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?\n                        \"inflate:         literal '%c'\\n\" :\n                        \"inflate:         literal 0x%02x\\n\", here.val));\n                state->mode = LIT;\n                break;\n            }\n            if (here.op & 32) {\n                Tracevv((stderr, \"inflate:         end of block\\n\"));\n                state->back = -1;\n                state->mode = TYPE;\n                break;\n            }\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid literal/length code\";\n                state->mode = BAD;\n                break;\n            }\n            state->extra = (unsigned)(here.op) & 15;\n            state->mode = LENEXT;\n        case LENEXT:\n            if (state->extra) {\n                NEEDBITS(state->extra);\n                state->length += BITS(state->extra);\n                DROPBITS(state->extra);\n                state->back += state->extra;\n            }\n            Tracevv((stderr, \"inflate:         length %u\\n\", state->length));\n            state->was = state->length;\n            state->mode = DIST;\n        case DIST:\n            for (;;) {\n                here = state->distcode[BITS(state->distbits)];\n                if ((unsigned)(here.bits) <= bits) break;\n                PULLBYTE();\n            }\n            if ((here.op & 0xf0) == 0) {\n                last = here;\n                for (;;) {\n                    here = state->distcode[last.val +\n                            (BITS(last.bits + last.op) >> last.bits)];\n                    if ((unsigned)(last.bits + here.bits) <= bits) break;\n                    PULLBYTE();\n                }\n                DROPBITS(last.bits);\n                state->back += last.bits;\n            }\n            DROPBITS(here.bits);\n            state->back += here.bits;\n            if (here.op & 64) {\n                strm->msg = (char *)\"invalid distance code\";\n                state->mode = BAD;\n                break;\n            }\n            state->offset = (unsigned)here.val;\n            state->extra = (unsigned)(here.op) & 15;\n            state->mode = DISTEXT;\n        case DISTEXT:\n            if (state->extra) {\n                NEEDBITS(state->extra);\n                state->offset += BITS(state->extra);\n                DROPBITS(state->extra);\n                state->back += state->extra;\n            }\n#ifdef INFLATE_STRICT\n            if (state->offset > state->dmax) {\n                strm->msg = (char *)\"invalid distance too far back\";\n                state->mode = BAD;\n                break;\n            }\n#endif\n            Tracevv((stderr, \"inflate:         distance %u\\n\", state->offset));\n            state->mode = MATCH;\n        case MATCH:\n            if (left == 0) goto inf_leave;\n            copy = out - left;\n            if (state->offset > copy) {         /* copy from window */\n                copy = state->offset - copy;\n                if (copy > state->whave) {\n                    if (state->sane) {\n                        strm->msg = (char *)\"invalid distance too far back\";\n                        state->mode = BAD;\n                        break;\n                    }\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n                    Trace((stderr, \"inflate.c too far\\n\"));\n                    copy -= state->whave;\n                    if (copy > state->length) copy = state->length;\n                    if (copy > left) copy = left;\n                    left -= copy;\n                    state->length -= copy;\n                    do {\n                        *put++ = 0;\n                    } while (--copy);\n                    if (state->length == 0) state->mode = LEN;\n                    break;\n#endif\n                }\n                if (copy > state->wnext) {\n                    copy -= state->wnext;\n                    from = state->window + (state->wsize - copy);\n                }\n                else\n                    from = state->window + (state->wnext - copy);\n                if (copy > state->length) copy = state->length;\n            }\n            else {                              /* copy from output */\n                from = put - state->offset;\n                copy = state->length;\n            }\n            if (copy > left) copy = left;\n            left -= copy;\n            state->length -= copy;\n            do {\n                *put++ = *from++;\n            } while (--copy);\n            if (state->length == 0) state->mode = LEN;\n            break;\n        case LIT:\n            if (left == 0) goto inf_leave;\n            *put++ = (unsigned char)(state->length);\n            left--;\n            state->mode = LEN;\n            break;\n        case CHECK:\n            if (state->wrap) {\n                NEEDBITS(32);\n                out -= left;\n                strm->total_out += out;\n                state->total += out;\n                if ((state->wrap & 4) && out)\n                    strm->adler = state->check =\n                        UPDATE(state->check, put - out, out);\n                out = left;\n                if ((state->wrap & 4) && (\n#ifdef GUNZIP\n                     state->flags ? hold :\n#endif\n                     ZSWAP32(hold)) != state->check) {\n                    strm->msg = (char *)\"incorrect data check\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n                Tracev((stderr, \"inflate:   check matches trailer\\n\"));\n            }\n#ifdef GUNZIP\n            state->mode = LENGTH;\n        case LENGTH:\n            if (state->wrap && state->flags) {\n                NEEDBITS(32);\n                if (hold != (state->total & 0xffffffffUL)) {\n                    strm->msg = (char *)\"incorrect length check\";\n                    state->mode = BAD;\n                    break;\n                }\n                INITBITS();\n                Tracev((stderr, \"inflate:   length matches trailer\\n\"));\n            }\n#endif\n            state->mode = DONE;\n        case DONE:\n            ret = Z_STREAM_END;\n            goto inf_leave;\n        case BAD:\n            ret = Z_DATA_ERROR;\n            goto inf_leave;\n        case MEM:\n            return Z_MEM_ERROR;\n        case SYNC:\n        default:\n            return Z_STREAM_ERROR;\n        }\n\n    /*\n       Return from inflate(), updating the total counts and the check value.\n       If there was no progress during the inflate() call, return a buffer\n       error.  Call updatewindow() to create and/or update the window state.\n       Note: a memory error from inflate() is non-recoverable.\n     */\n  inf_leave:\n    RESTORE();\n    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&\n            (state->mode < CHECK || flush != Z_FINISH)))\n        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {\n            state->mode = MEM;\n            return Z_MEM_ERROR;\n        }\n    in -= strm->avail_in;\n    out -= strm->avail_out;\n    strm->total_in += in;\n    strm->total_out += out;\n    state->total += out;\n    if ((state->wrap & 4) && out)\n        strm->adler = state->check =\n            UPDATE(state->check, strm->next_out - out, out);\n    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +\n                      (state->mode == TYPE ? 128 : 0) +\n                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);\n    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)\n        ret = Z_BUF_ERROR;\n    return ret;\n}\n\nint ZEXPORT inflateEnd(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (inflateStateCheck(strm))\n        return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->window != Z_NULL) ZFREE(strm, state->window);\n    ZFREE(strm, strm->state);\n    strm->state = Z_NULL;\n    Tracev((stderr, \"inflate: end\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)\nz_streamp strm;\nBytef *dictionary;\nuInt *dictLength;\n{\n    struct inflate_state FAR *state;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n\n    /* copy dictionary */\n    if (state->whave && dictionary != Z_NULL) {\n        zmemcpy(dictionary, state->window + state->wnext,\n                state->whave - state->wnext);\n        zmemcpy(dictionary + state->whave - state->wnext,\n                state->window, state->wnext);\n    }\n    if (dictLength != Z_NULL)\n        *dictLength = state->whave;\n    return Z_OK;\n}\n\nint ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)\nz_streamp strm;\nconst Bytef *dictionary;\nuInt dictLength;\n{\n    struct inflate_state FAR *state;\n    unsigned long dictid;\n    int ret;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (state->wrap != 0 && state->mode != DICT)\n        return Z_STREAM_ERROR;\n\n    /* check for correct dictionary identifier */\n    if (state->mode == DICT) {\n        dictid = adler32(0L, Z_NULL, 0);\n        dictid = adler32(dictid, dictionary, dictLength);\n        if (dictid != state->check)\n            return Z_DATA_ERROR;\n    }\n\n    /* copy dictionary to window using updatewindow(), which will amend the\n       existing dictionary if appropriate */\n    ret = updatewindow(strm, dictionary + dictLength, dictLength);\n    if (ret) {\n        state->mode = MEM;\n        return Z_MEM_ERROR;\n    }\n    state->havedict = 1;\n    Tracev((stderr, \"inflate:   dictionary set\\n\"));\n    return Z_OK;\n}\n\nint ZEXPORT inflateGetHeader(strm, head)\nz_streamp strm;\ngz_headerp head;\n{\n    struct inflate_state FAR *state;\n\n    /* check state */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;\n\n    /* save header structure */\n    state->head = head;\n    head->done = 0;\n    return Z_OK;\n}\n\n/*\n   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found\n   or when out of input.  When called, *have is the number of pattern bytes\n   found in order so far, in 0..3.  On return *have is updated to the new\n   state.  If on return *have equals four, then the pattern was found and the\n   return value is how many bytes were read including the last byte of the\n   pattern.  If *have is less than four, then the pattern has not been found\n   yet and the return value is len.  In the latter case, syncsearch() can be\n   called again with more data and the *have state.  *have is initialized to\n   zero for the first call.\n */\nlocal unsigned syncsearch(have, buf, len)\nunsigned FAR *have;\nconst unsigned char FAR *buf;\nunsigned len;\n{\n    unsigned got;\n    unsigned next;\n\n    got = *have;\n    next = 0;\n    while (next < len && got < 4) {\n        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))\n            got++;\n        else if (buf[next])\n            got = 0;\n        else\n            got = 4 - got;\n        next++;\n    }\n    *have = got;\n    return next;\n}\n\nint ZEXPORT inflateSync(strm)\nz_streamp strm;\n{\n    unsigned len;               /* number of bytes to look at or looked at */\n    unsigned long in, out;      /* temporary to save total_in and total_out */\n    unsigned char buf[4];       /* to restore bit buffer to byte string */\n    struct inflate_state FAR *state;\n\n    /* check parameters */\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;\n\n    /* if first time, start search in bit buffer */\n    if (state->mode != SYNC) {\n        state->mode = SYNC;\n        state->hold <<= state->bits & 7;\n        state->bits -= state->bits & 7;\n        len = 0;\n        while (state->bits >= 8) {\n            buf[len++] = (unsigned char)(state->hold);\n            state->hold >>= 8;\n            state->bits -= 8;\n        }\n        state->have = 0;\n        syncsearch(&(state->have), buf, len);\n    }\n\n    /* search available input */\n    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);\n    strm->avail_in -= len;\n    strm->next_in += len;\n    strm->total_in += len;\n\n    /* return no joy or set up to restart inflate() on a new block */\n    if (state->have != 4) return Z_DATA_ERROR;\n    in = strm->total_in;  out = strm->total_out;\n    inflateReset(strm);\n    strm->total_in = in;  strm->total_out = out;\n    state->mode = TYPE;\n    return Z_OK;\n}\n\n/*\n   Returns true if inflate is currently at the end of a block generated by\n   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP\n   implementation to provide an additional safety check. PPP uses\n   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored\n   block. When decompressing, PPP checks that at the end of input packet,\n   inflate is waiting for these length bytes.\n */\nint ZEXPORT inflateSyncPoint(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    return state->mode == STORED && state->bits == 0;\n}\n\nint ZEXPORT inflateCopy(dest, source)\nz_streamp dest;\nz_streamp source;\n{\n    struct inflate_state FAR *state;\n    struct inflate_state FAR *copy;\n    unsigned char FAR *window;\n    unsigned wsize;\n\n    /* check input */\n    if (inflateStateCheck(source) || dest == Z_NULL)\n        return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)source->state;\n\n    /* allocate space */\n    copy = (struct inflate_state FAR *)\n           ZALLOC(source, 1, sizeof(struct inflate_state));\n    if (copy == Z_NULL) return Z_MEM_ERROR;\n    window = Z_NULL;\n    if (state->window != Z_NULL) {\n        window = (unsigned char FAR *)\n                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));\n        if (window == Z_NULL) {\n            ZFREE(source, copy);\n            return Z_MEM_ERROR;\n        }\n    }\n\n    /* copy state */\n    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));\n    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));\n    copy->strm = dest;\n    if (state->lencode >= state->codes &&\n        state->lencode <= state->codes + ENOUGH - 1) {\n        copy->lencode = copy->codes + (state->lencode - state->codes);\n        copy->distcode = copy->codes + (state->distcode - state->codes);\n    }\n    copy->next = copy->codes + (state->next - state->codes);\n    if (window != Z_NULL) {\n        wsize = 1U << state->wbits;\n        zmemcpy(window, state->window, wsize);\n    }\n    copy->window = window;\n    dest->state = (struct internal_state FAR *)copy;\n    return Z_OK;\n}\n\nint ZEXPORT inflateUndermine(strm, subvert)\nz_streamp strm;\nint subvert;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR\n    state->sane = !subvert;\n    return Z_OK;\n#else\n    (void)subvert;\n    state->sane = 1;\n    return Z_DATA_ERROR;\n#endif\n}\n\nint ZEXPORT inflateValidate(strm, check)\nz_streamp strm;\nint check;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;\n    state = (struct inflate_state FAR *)strm->state;\n    if (check)\n        state->wrap |= 4;\n    else\n        state->wrap &= ~4;\n    return Z_OK;\n}\n\nlong ZEXPORT inflateMark(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n\n    if (inflateStateCheck(strm))\n        return -(1L << 16);\n    state = (struct inflate_state FAR *)strm->state;\n    return (long)(((unsigned long)((long)state->back)) << 16) +\n        (state->mode == COPY ? state->length :\n            (state->mode == MATCH ? state->was - state->length : 0));\n}\n\nunsigned long ZEXPORT inflateCodesUsed(strm)\nz_streamp strm;\n{\n    struct inflate_state FAR *state;\n    if (inflateStateCheck(strm)) return (unsigned long)-1;\n    state = (struct inflate_state FAR *)strm->state;\n    return (unsigned long)(state->next - state->codes);\n}\n"
  },
  {
    "path": "dlib/external/zlib/inflate.h",
    "content": "/* inflate.h -- internal inflate state definition\n * Copyright (C) 1995-2016 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* define NO_GZIP when compiling if you want to disable gzip header and\n   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in\n   the crc code when it is not needed.  For shared libraries, gzip decoding\n   should be left enabled. */\n#ifndef NO_GZIP\n#  define GUNZIP\n#endif\n\n/* Possible inflate modes between inflate() calls */\ntypedef enum {\n    HEAD = 16180,   /* i: waiting for magic header */\n    FLAGS,      /* i: waiting for method and flags (gzip) */\n    TIME,       /* i: waiting for modification time (gzip) */\n    OS,         /* i: waiting for extra flags and operating system (gzip) */\n    EXLEN,      /* i: waiting for extra length (gzip) */\n    EXTRA,      /* i: waiting for extra bytes (gzip) */\n    NAME,       /* i: waiting for end of file name (gzip) */\n    COMMENT,    /* i: waiting for end of comment (gzip) */\n    HCRC,       /* i: waiting for header crc (gzip) */\n    DICTID,     /* i: waiting for dictionary check value */\n    DICT,       /* waiting for inflateSetDictionary() call */\n        TYPE,       /* i: waiting for type bits, including last-flag bit */\n        TYPEDO,     /* i: same, but skip check to exit inflate on new block */\n        STORED,     /* i: waiting for stored size (length and complement) */\n        COPY_,      /* i/o: same as COPY below, but only first time in */\n        COPY,       /* i/o: waiting for input or output to copy stored block */\n        TABLE,      /* i: waiting for dynamic block table lengths */\n        LENLENS,    /* i: waiting for code length code lengths */\n        CODELENS,   /* i: waiting for length/lit and distance code lengths */\n            LEN_,       /* i: same as LEN below, but only first time in */\n            LEN,        /* i: waiting for length/lit/eob code */\n            LENEXT,     /* i: waiting for length extra bits */\n            DIST,       /* i: waiting for distance code */\n            DISTEXT,    /* i: waiting for distance extra bits */\n            MATCH,      /* o: waiting for output space to copy string */\n            LIT,        /* o: waiting for output space to write literal */\n    CHECK,      /* i: waiting for 32-bit check value */\n    LENGTH,     /* i: waiting for 32-bit length (gzip) */\n    DONE,       /* finished check, done -- remain here until reset */\n    BAD,        /* got a data error -- remain here until reset */\n    MEM,        /* got an inflate() memory error -- remain here until reset */\n    SYNC        /* looking for synchronization bytes to restart inflate() */\n} inflate_mode;\n\n/*\n    State transitions between above modes -\n\n    (most modes can go to BAD or MEM on error -- not shown for clarity)\n\n    Process header:\n        HEAD -> (gzip) or (zlib) or (raw)\n        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->\n                  HCRC -> TYPE\n        (zlib) -> DICTID or TYPE\n        DICTID -> DICT -> TYPE\n        (raw) -> TYPEDO\n    Read deflate blocks:\n            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK\n            STORED -> COPY_ -> COPY -> TYPE\n            TABLE -> LENLENS -> CODELENS -> LEN_\n            LEN_ -> LEN\n    Read deflate codes in fixed or dynamic block:\n                LEN -> LENEXT or LIT or TYPE\n                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN\n                LIT -> LEN\n    Process trailer:\n        CHECK -> LENGTH -> DONE\n */\n\n/* State maintained between inflate() calls -- approximately 7K bytes, not\n   including the allocated sliding window, which is up to 32K bytes. */\nstruct inflate_state {\n    z_streamp strm;             /* pointer back to this zlib stream */\n    inflate_mode mode;          /* current inflate mode */\n    int last;                   /* true if processing last block */\n    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip,\n                                   bit 2 true to validate check value */\n    int havedict;               /* true if dictionary provided */\n    int flags;                  /* gzip header method and flags (0 if zlib) */\n    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */\n    unsigned long check;        /* protected copy of check value */\n    unsigned long total;        /* protected copy of output count */\n    gz_headerp head;            /* where to save gzip header information */\n        /* sliding window */\n    unsigned wbits;             /* log base 2 of requested window size */\n    unsigned wsize;             /* window size or zero if not using window */\n    unsigned whave;             /* valid bytes in the window */\n    unsigned wnext;             /* window write index */\n    unsigned char FAR *window;  /* allocated sliding window, if needed */\n        /* bit accumulator */\n    unsigned long hold;         /* input bit accumulator */\n    unsigned bits;              /* number of bits in \"in\" */\n        /* for string and stored block copying */\n    unsigned length;            /* literal or length of data to copy */\n    unsigned offset;            /* distance back to copy string from */\n        /* for table and code decoding */\n    unsigned extra;             /* extra bits needed */\n        /* fixed and dynamic code tables */\n    code const FAR *lencode;    /* starting table for length/literal codes */\n    code const FAR *distcode;   /* starting table for distance codes */\n    unsigned lenbits;           /* index bits for lencode */\n    unsigned distbits;          /* index bits for distcode */\n        /* dynamic table building */\n    unsigned ncode;             /* number of code length code lengths */\n    unsigned nlen;              /* number of length code lengths */\n    unsigned ndist;             /* number of distance code lengths */\n    unsigned have;              /* number of code lengths in lens[] */\n    code FAR *next;             /* next available space in codes[] */\n    unsigned short lens[320];   /* temporary storage for code lengths */\n    unsigned short work[288];   /* work area for code table building */\n    code codes[ENOUGH];         /* space for code tables */\n    int sane;                   /* if false, allow invalid distance too far */\n    int back;                   /* bits back of last unprocessed length/lit */\n    unsigned was;               /* initial length of match */\n};\n"
  },
  {
    "path": "dlib/external/zlib/inftrees.c",
    "content": "/* inftrees.c -- generate Huffman trees for efficient decoding\n * Copyright (C) 1995-2017 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n#include \"zutil.h\"\n#include \"inftrees.h\"\n\n#define MAXBITS 15\n\nconst char inflate_copyright[] =\n   \" inflate 1.2.11 Copyright 1995-2017 Mark Adler \";\n/*\n  If you use the zlib library in a product, an acknowledgment is welcome\n  in the documentation of your product. If for some reason you cannot\n  include such an acknowledgment, I would appreciate that you keep this\n  copyright string in the executable of your product.\n */\n\n/*\n   Build a set of tables to decode the provided canonical Huffman code.\n   The code lengths are lens[0..codes-1].  The result starts at *table,\n   whose indices are 0..2^bits-1.  work is a writable array of at least\n   lens shorts, which is used as a work area.  type is the type of code\n   to be generated, CODES, LENS, or DISTS.  On return, zero is success,\n   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table\n   on return points to the next available entry's address.  bits is the\n   requested root table index bits, and on return it is the actual root\n   table index bits.  It will differ if the request is greater than the\n   longest code or if it is less than the shortest code.\n */\nint ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)\ncodetype type;\nunsigned short FAR *lens;\nunsigned codes;\ncode FAR * FAR *table;\nunsigned FAR *bits;\nunsigned short FAR *work;\n{\n    unsigned len;               /* a code's length in bits */\n    unsigned sym;               /* index of code symbols */\n    unsigned min, max;          /* minimum and maximum code lengths */\n    unsigned root;              /* number of index bits for root table */\n    unsigned curr;              /* number of index bits for current table */\n    unsigned drop;              /* code bits to drop for sub-table */\n    int left;                   /* number of prefix codes available */\n    unsigned used;              /* code entries in table used */\n    unsigned huff;              /* Huffman code */\n    unsigned incr;              /* for incrementing code, index */\n    unsigned fill;              /* index for replicating entries */\n    unsigned low;               /* low bits for current root entry */\n    unsigned mask;              /* mask for low root bits */\n    code here;                  /* table entry for duplication */\n    code FAR *next;             /* next available space in table */\n    const unsigned short FAR *base;     /* base value table to use */\n    const unsigned short FAR *extra;    /* extra bits table to use */\n    unsigned match;             /* use base and extra for symbol >= match */\n    unsigned short count[MAXBITS+1];    /* number of codes of each length */\n    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */\n    static const unsigned short lbase[31] = { /* Length codes 257..285 base */\n        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,\n        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};\n    static const unsigned short lext[31] = { /* Length codes 257..285 extra */\n        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,\n        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};\n    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */\n        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,\n        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,\n        8193, 12289, 16385, 24577, 0, 0};\n    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */\n        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,\n        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,\n        28, 28, 29, 29, 64, 64};\n\n    /*\n       Process a set of code lengths to create a canonical Huffman code.  The\n       code lengths are lens[0..codes-1].  Each length corresponds to the\n       symbols 0..codes-1.  The Huffman code is generated by first sorting the\n       symbols by length from short to long, and retaining the symbol order\n       for codes with equal lengths.  Then the code starts with all zero bits\n       for the first code of the shortest length, and the codes are integer\n       increments for the same length, and zeros are appended as the length\n       increases.  For the deflate format, these bits are stored backwards\n       from their more natural integer increment ordering, and so when the\n       decoding tables are built in the large loop below, the integer codes\n       are incremented backwards.\n\n       This routine assumes, but does not check, that all of the entries in\n       lens[] are in the range 0..MAXBITS.  The caller must assure this.\n       1..MAXBITS is interpreted as that code length.  zero means that that\n       symbol does not occur in this code.\n\n       The codes are sorted by computing a count of codes for each length,\n       creating from that a table of starting indices for each length in the\n       sorted table, and then entering the symbols in order in the sorted\n       table.  The sorted table is work[], with that space being provided by\n       the caller.\n\n       The length counts are used for other purposes as well, i.e. finding\n       the minimum and maximum length codes, determining if there are any\n       codes at all, checking for a valid set of lengths, and looking ahead\n       at length counts to determine sub-table sizes when building the\n       decoding tables.\n     */\n\n    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */\n    for (len = 0; len <= MAXBITS; len++)\n        count[len] = 0;\n    for (sym = 0; sym < codes; sym++)\n        count[lens[sym]]++;\n\n    /* bound code lengths, force root to be within code lengths */\n    root = *bits;\n    for (max = MAXBITS; max >= 1; max--)\n        if (count[max] != 0) break;\n    if (root > max) root = max;\n    if (max == 0) {                     /* no symbols to code at all */\n        here.op = (unsigned char)64;    /* invalid code marker */\n        here.bits = (unsigned char)1;\n        here.val = (unsigned short)0;\n        *(*table)++ = here;             /* make a table to force an error */\n        *(*table)++ = here;\n        *bits = 1;\n        return 0;     /* no symbols, but wait for decoding to report error */\n    }\n    for (min = 1; min < max; min++)\n        if (count[min] != 0) break;\n    if (root < min) root = min;\n\n    /* check for an over-subscribed or incomplete set of lengths */\n    left = 1;\n    for (len = 1; len <= MAXBITS; len++) {\n        left <<= 1;\n        left -= count[len];\n        if (left < 0) return -1;        /* over-subscribed */\n    }\n    if (left > 0 && (type == CODES || max != 1))\n        return -1;                      /* incomplete set */\n\n    /* generate offsets into symbol table for each length for sorting */\n    offs[1] = 0;\n    for (len = 1; len < MAXBITS; len++)\n        offs[len + 1] = offs[len] + count[len];\n\n    /* sort symbols by length, by symbol order within each length */\n    for (sym = 0; sym < codes; sym++)\n        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;\n\n    /*\n       Create and fill in decoding tables.  In this loop, the table being\n       filled is at next and has curr index bits.  The code being used is huff\n       with length len.  That code is converted to an index by dropping drop\n       bits off of the bottom.  For codes where len is less than drop + curr,\n       those top drop + curr - len bits are incremented through all values to\n       fill the table with replicated entries.\n\n       root is the number of index bits for the root table.  When len exceeds\n       root, sub-tables are created pointed to by the root entry with an index\n       of the low root bits of huff.  This is saved in low to check for when a\n       new sub-table should be started.  drop is zero when the root table is\n       being filled, and drop is root when sub-tables are being filled.\n\n       When a new sub-table is needed, it is necessary to look ahead in the\n       code lengths to determine what size sub-table is needed.  The length\n       counts are used for this, and so count[] is decremented as codes are\n       entered in the tables.\n\n       used keeps track of how many table entries have been allocated from the\n       provided *table space.  It is checked for LENS and DIST tables against\n       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in\n       the initial root table size constants.  See the comments in inftrees.h\n       for more information.\n\n       sym increments through all symbols, and the loop terminates when\n       all codes of length max, i.e. all codes, have been processed.  This\n       routine permits incomplete codes, so another loop after this one fills\n       in the rest of the decoding tables with invalid code markers.\n     */\n\n    /* set up for code type */\n    switch (type) {\n    case CODES:\n        base = extra = work;    /* dummy value--not used */\n        match = 20;\n        break;\n    case LENS:\n        base = lbase;\n        extra = lext;\n        match = 257;\n        break;\n    default:    /* DISTS */\n        base = dbase;\n        extra = dext;\n        match = 0;\n    }\n\n    /* initialize state for loop */\n    huff = 0;                   /* starting code */\n    sym = 0;                    /* starting code symbol */\n    len = min;                  /* starting code length */\n    next = *table;              /* current table to fill in */\n    curr = root;                /* current table index bits */\n    drop = 0;                   /* current bits to drop from code for index */\n    low = (unsigned)(-1);       /* trigger new sub-table when len > root */\n    used = 1U << root;          /* use root table entries */\n    mask = used - 1;            /* mask for comparing low */\n\n    /* check available table space */\n    if ((type == LENS && used > ENOUGH_LENS) ||\n        (type == DISTS && used > ENOUGH_DISTS))\n        return 1;\n\n    /* process all codes and make table entries */\n    for (;;) {\n        /* create table entry */\n        here.bits = (unsigned char)(len - drop);\n        if (work[sym] + 1U < match) {\n            here.op = (unsigned char)0;\n            here.val = work[sym];\n        }\n        else if (work[sym] >= match) {\n            here.op = (unsigned char)(extra[work[sym] - match]);\n            here.val = base[work[sym] - match];\n        }\n        else {\n            here.op = (unsigned char)(32 + 64);         /* end of block */\n            here.val = 0;\n        }\n\n        /* replicate for those indices with low len bits equal to huff */\n        incr = 1U << (len - drop);\n        fill = 1U << curr;\n        min = fill;                 /* save offset to next table */\n        do {\n            fill -= incr;\n            next[(huff >> drop) + fill] = here;\n        } while (fill != 0);\n\n        /* backwards increment the len-bit code huff */\n        incr = 1U << (len - 1);\n        while (huff & incr)\n            incr >>= 1;\n        if (incr != 0) {\n            huff &= incr - 1;\n            huff += incr;\n        }\n        else\n            huff = 0;\n\n        /* go to next symbol, update count, len */\n        sym++;\n        if (--(count[len]) == 0) {\n            if (len == max) break;\n            len = lens[work[sym]];\n        }\n\n        /* create new sub-table if needed */\n        if (len > root && (huff & mask) != low) {\n            /* if first time, transition to sub-tables */\n            if (drop == 0)\n                drop = root;\n\n            /* increment past last table */\n            next += min;            /* here min is 1 << curr */\n\n            /* determine length of next table */\n            curr = len - drop;\n            left = (int)(1 << curr);\n            while (curr + drop < max) {\n                left -= count[curr + drop];\n                if (left <= 0) break;\n                curr++;\n                left <<= 1;\n            }\n\n            /* check for enough space */\n            used += 1U << curr;\n            if ((type == LENS && used > ENOUGH_LENS) ||\n                (type == DISTS && used > ENOUGH_DISTS))\n                return 1;\n\n            /* point entry in root table to sub-table */\n            low = huff & mask;\n            (*table)[low].op = (unsigned char)curr;\n            (*table)[low].bits = (unsigned char)root;\n            (*table)[low].val = (unsigned short)(next - *table);\n        }\n    }\n\n    /* fill in remaining table entry if code is incomplete (guaranteed to have\n       at most one remaining entry, since if the code is incomplete, the\n       maximum code length that was allowed to get this far is one bit) */\n    if (huff != 0) {\n        here.op = (unsigned char)64;            /* invalid code marker */\n        here.bits = (unsigned char)(len - drop);\n        here.val = (unsigned short)0;\n        next[huff] = here;\n    }\n\n    /* set return parameters */\n    *table += used;\n    *bits = root;\n    return 0;\n}\n"
  },
  {
    "path": "dlib/external/zlib/inftrees.h",
    "content": "/* inftrees.h -- header to use inftrees.c\n * Copyright (C) 1995-2005, 2010 Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* Structure for decoding tables.  Each entry provides either the\n   information needed to do the operation requested by the code that\n   indexed that table entry, or it provides a pointer to another\n   table that indexes more bits of the code.  op indicates whether\n   the entry is a pointer to another table, a literal, a length or\n   distance, an end-of-block, or an invalid code.  For a table\n   pointer, the low four bits of op is the number of index bits of\n   that table.  For a length or distance, the low four bits of op\n   is the number of extra bits to get after the code.  bits is\n   the number of bits in this code or part of the code to drop off\n   of the bit buffer.  val is the actual byte to output in the case\n   of a literal, the base length or distance, or the offset from\n   the current table to the next table.  Each entry is four bytes. */\ntypedef struct {\n    unsigned char op;           /* operation, extra bits, table bits */\n    unsigned char bits;         /* bits in this part of the code */\n    unsigned short val;         /* offset in table or code value */\n} code;\n\n/* op values as set by inflate_table():\n    00000000 - literal\n    0000tttt - table link, tttt != 0 is the number of table index bits\n    0001eeee - length or distance, eeee is the number of extra bits\n    01100000 - end of block\n    01000000 - invalid code\n */\n\n/* Maximum size of the dynamic table.  The maximum number of code structures is\n   1444, which is the sum of 852 for literal/length codes and 592 for distance\n   codes.  These values were found by exhaustive searches using the program\n   examples/enough.c found in the zlib distribtution.  The arguments to that\n   program are the number of symbols, the initial root table size, and the\n   maximum bit length of a code.  \"enough 286 9 15\" for literal/length codes\n   returns returns 852, and \"enough 30 6 15\" for distance codes returns 592.\n   The initial root table size (9 or 6) is found in the fifth argument of the\n   inflate_table() calls in inflate.c and infback.c.  If the root table size is\n   changed, then these maximum sizes would be need to be recalculated and\n   updated. */\n#define ENOUGH_LENS 852\n#define ENOUGH_DISTS 592\n#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)\n\n/* Type of code to build for inflate_table() */\ntypedef enum {\n    CODES,\n    LENS,\n    DISTS\n} codetype;\n\nint ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,\n                             unsigned codes, code FAR * FAR *table,\n                             unsigned FAR *bits, unsigned short FAR *work));\n"
  },
  {
    "path": "dlib/external/zlib/trees.c",
    "content": "/* trees.c -- output deflated data using Huffman coding\n * Copyright (C) 1995-2017 Jean-loup Gailly\n * detect_data_type() function provided freely by Cosmin Truta, 2006\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/*\n *  ALGORITHM\n *\n *      The \"deflation\" process uses several Huffman trees. The more\n *      common source values are represented by shorter bit sequences.\n *\n *      Each code tree is stored in a compressed form which is itself\n * a Huffman encoding of the lengths of all the code strings (in\n * ascending order by source values).  The actual code strings are\n * reconstructed from the lengths in the inflate process, as described\n * in the deflate specification.\n *\n *  REFERENCES\n *\n *      Deutsch, L.P.,\"'Deflate' Compressed Data Format Specification\".\n *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc\n *\n *      Storer, James A.\n *          Data Compression:  Methods and Theory, pp. 49-50.\n *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.\n *\n *      Sedgewick, R.\n *          Algorithms, p290.\n *          Addison-Wesley, 1983. ISBN 0-201-06672-6.\n */\n\n/* @(#) $Id$ */\n\n/* #define GEN_TREES_H */\n\n#include \"deflate.h\"\n\n#ifdef ZLIB_DEBUG\n#  include <ctype.h>\n#endif\n\n/* ===========================================================================\n * Constants\n */\n\n#define MAX_BL_BITS 7\n/* Bit length codes must not exceed MAX_BL_BITS bits */\n\n#define END_BLOCK 256\n/* end of block literal code */\n\n#define REP_3_6      16\n/* repeat previous bit length 3-6 times (2 bits of repeat count) */\n\n#define REPZ_3_10    17\n/* repeat a zero length 3-10 times  (3 bits of repeat count) */\n\n#define REPZ_11_138  18\n/* repeat a zero length 11-138 times  (7 bits of repeat count) */\n\nlocal const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */\n   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};\n\nlocal const int extra_dbits[D_CODES] /* extra bits for each distance code */\n   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nlocal const int extra_blbits[BL_CODES]/* extra bits for each bit length code */\n   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};\n\nlocal const uch bl_order[BL_CODES]\n   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};\n/* The lengths of the bit length codes are sent in order of decreasing\n * probability, to avoid transmitting the lengths for unused bit length codes.\n */\n\n/* ===========================================================================\n * Local data. These are initialized only once.\n */\n\n#define DIST_CODE_LEN  512 /* see definition of array dist_code below */\n\n#if defined(GEN_TREES_H) || !defined(STDC)\n/* non ANSI compilers may not accept trees.h */\n\nlocal ct_data static_ltree[L_CODES+2];\n/* The static literal tree. Since the bit lengths are imposed, there is no\n * need for the L_CODES extra codes used during heap construction. However\n * The codes 286 and 287 are needed to build a canonical tree (see _tr_init\n * below).\n */\n\nlocal ct_data static_dtree[D_CODES];\n/* The static distance tree. (Actually a trivial tree since all codes use\n * 5 bits.)\n */\n\nuch _dist_code[DIST_CODE_LEN];\n/* Distance codes. The first 256 values correspond to the distances\n * 3 .. 258, the last 256 values correspond to the top 8 bits of\n * the 15 bit distances.\n */\n\nuch _length_code[MAX_MATCH-MIN_MATCH+1];\n/* length code for each normalized match length (0 == MIN_MATCH) */\n\nlocal int base_length[LENGTH_CODES];\n/* First normalized length for each code (0 = MIN_MATCH) */\n\nlocal int base_dist[D_CODES];\n/* First normalized distance for each code (0 = distance of 1) */\n\n#else\n#  include \"trees.h\"\n#endif /* GEN_TREES_H */\n\nstruct static_tree_desc_s {\n    const ct_data *static_tree;  /* static tree or NULL */\n    const intf *extra_bits;      /* extra bits for each code or NULL */\n    int     extra_base;          /* base index for extra_bits */\n    int     elems;               /* max number of elements in the tree */\n    int     max_length;          /* max bit length for the codes */\n};\n\nlocal const static_tree_desc  static_l_desc =\n{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};\n\nlocal const static_tree_desc  static_d_desc =\n{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};\n\nlocal const static_tree_desc  static_bl_desc =\n{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};\n\n/* ===========================================================================\n * Local (static) routines in this file.\n */\n\nlocal void tr_static_init OF((void));\nlocal void init_block     OF((deflate_state *s));\nlocal void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));\nlocal void gen_bitlen     OF((deflate_state *s, tree_desc *desc));\nlocal void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));\nlocal void build_tree     OF((deflate_state *s, tree_desc *desc));\nlocal void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));\nlocal void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));\nlocal int  build_bl_tree  OF((deflate_state *s));\nlocal void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,\n                              int blcodes));\nlocal void compress_block OF((deflate_state *s, const ct_data *ltree,\n                              const ct_data *dtree));\nlocal int  detect_data_type OF((deflate_state *s));\nlocal unsigned bi_reverse OF((unsigned value, int length));\nlocal void bi_windup      OF((deflate_state *s));\nlocal void bi_flush       OF((deflate_state *s));\n\n#ifdef GEN_TREES_H\nlocal void gen_trees_header OF((void));\n#endif\n\n#ifndef ZLIB_DEBUG\n#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)\n   /* Send a code of the given tree. c and tree must not have side effects */\n\n#else /* !ZLIB_DEBUG */\n#  define send_code(s, c, tree) \\\n     { if (z_verbose>2) fprintf(stderr,\"\\ncd %3d \",(c)); \\\n       send_bits(s, tree[c].Code, tree[c].Len); }\n#endif\n\n/* ===========================================================================\n * Output a short LSB first on the stream.\n * IN assertion: there is enough room in pendingBuf.\n */\n#define put_short(s, w) { \\\n    put_byte(s, (uch)((w) & 0xff)); \\\n    put_byte(s, (uch)((ush)(w) >> 8)); \\\n}\n\n/* ===========================================================================\n * Send a value on a given number of bits.\n * IN assertion: length <= 16 and value fits in length bits.\n */\n#ifdef ZLIB_DEBUG\nlocal void send_bits      OF((deflate_state *s, int value, int length));\n\nlocal void send_bits(s, value, length)\n    deflate_state *s;\n    int value;  /* value to send */\n    int length; /* number of bits */\n{\n    Tracevv((stderr,\" l %2d v %4x \", length, value));\n    Assert(length > 0 && length <= 15, \"invalid length\");\n    s->bits_sent += (ulg)length;\n\n    /* If not enough room in bi_buf, use (valid) bits from bi_buf and\n     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))\n     * unused bits in value.\n     */\n    if (s->bi_valid > (int)Buf_size - length) {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        put_short(s, s->bi_buf);\n        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);\n        s->bi_valid += length - Buf_size;\n    } else {\n        s->bi_buf |= (ush)value << s->bi_valid;\n        s->bi_valid += length;\n    }\n}\n#else /* !ZLIB_DEBUG */\n\n#define send_bits(s, value, length) \\\n{ int len = length;\\\n  if (s->bi_valid > (int)Buf_size - len) {\\\n    int val = (int)value;\\\n    s->bi_buf |= (ush)val << s->bi_valid;\\\n    put_short(s, s->bi_buf);\\\n    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\\\n    s->bi_valid += len - Buf_size;\\\n  } else {\\\n    s->bi_buf |= (ush)(value) << s->bi_valid;\\\n    s->bi_valid += len;\\\n  }\\\n}\n#endif /* ZLIB_DEBUG */\n\n\n/* the arguments must not have side effects */\n\n/* ===========================================================================\n * Initialize the various 'constant' tables.\n */\nlocal void tr_static_init()\n{\n#if defined(GEN_TREES_H) || !defined(STDC)\n    static int static_init_done = 0;\n    int n;        /* iterates over tree elements */\n    int bits;     /* bit counter */\n    int length;   /* length value */\n    int code;     /* code value */\n    int dist;     /* distance index */\n    ush bl_count[MAX_BITS+1];\n    /* number of codes at each bit length for an optimal tree */\n\n    if (static_init_done) return;\n\n    /* For some embedded targets, global variables are not initialized: */\n#ifdef NO_INIT_GLOBAL_POINTERS\n    static_l_desc.static_tree = static_ltree;\n    static_l_desc.extra_bits = extra_lbits;\n    static_d_desc.static_tree = static_dtree;\n    static_d_desc.extra_bits = extra_dbits;\n    static_bl_desc.extra_bits = extra_blbits;\n#endif\n\n    /* Initialize the mapping length (0..255) -> length code (0..28) */\n    length = 0;\n    for (code = 0; code < LENGTH_CODES-1; code++) {\n        base_length[code] = length;\n        for (n = 0; n < (1<<extra_lbits[code]); n++) {\n            _length_code[length++] = (uch)code;\n        }\n    }\n    Assert (length == 256, \"tr_static_init: length != 256\");\n    /* Note that the length 255 (match length 258) can be represented\n     * in two different ways: code 284 + 5 bits or code 285, so we\n     * overwrite length_code[255] to use the best encoding:\n     */\n    _length_code[length-1] = (uch)code;\n\n    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */\n    dist = 0;\n    for (code = 0 ; code < 16; code++) {\n        base_dist[code] = dist;\n        for (n = 0; n < (1<<extra_dbits[code]); n++) {\n            _dist_code[dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: dist != 256\");\n    dist >>= 7; /* from now on, all distances are divided by 128 */\n    for ( ; code < D_CODES; code++) {\n        base_dist[code] = dist << 7;\n        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {\n            _dist_code[256 + dist++] = (uch)code;\n        }\n    }\n    Assert (dist == 256, \"tr_static_init: 256+dist != 512\");\n\n    /* Construct the codes of the static literal tree */\n    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;\n    n = 0;\n    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;\n    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;\n    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;\n    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;\n    /* Codes 286 and 287 do not exist, but we must include them in the\n     * tree construction to get a canonical Huffman tree (longest code\n     * all ones)\n     */\n    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);\n\n    /* The static distance tree is trivial: */\n    for (n = 0; n < D_CODES; n++) {\n        static_dtree[n].Len = 5;\n        static_dtree[n].Code = bi_reverse((unsigned)n, 5);\n    }\n    static_init_done = 1;\n\n#  ifdef GEN_TREES_H\n    gen_trees_header();\n#  endif\n#endif /* defined(GEN_TREES_H) || !defined(STDC) */\n}\n\n/* ===========================================================================\n * Genererate the file trees.h describing the static trees.\n */\n#ifdef GEN_TREES_H\n#  ifndef ZLIB_DEBUG\n#    include <stdio.h>\n#  endif\n\n#  define SEPARATOR(i, last, width) \\\n      ((i) == (last)? \"\\n};\\n\\n\" :    \\\n       ((i) % (width) == (width)-1 ? \",\\n\" : \", \"))\n\nvoid gen_trees_header()\n{\n    FILE *header = fopen(\"trees.h\", \"w\");\n    int i;\n\n    Assert (header != NULL, \"Can't open trees.h\");\n    fprintf(header,\n            \"/* header created automatically with -DGEN_TREES_H */\\n\\n\");\n\n    fprintf(header, \"local const ct_data static_ltree[L_CODES+2] = {\\n\");\n    for (i = 0; i < L_CODES+2; i++) {\n        fprintf(header, \"{{%3u},{%3u}}%s\", static_ltree[i].Code,\n                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));\n    }\n\n    fprintf(header, \"local const ct_data static_dtree[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"{{%2u},{%2u}}%s\", static_dtree[i].Code,\n                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));\n    }\n\n    fprintf(header, \"const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\\n\");\n    for (i = 0; i < DIST_CODE_LEN; i++) {\n        fprintf(header, \"%2u%s\", _dist_code[i],\n                SEPARATOR(i, DIST_CODE_LEN-1, 20));\n    }\n\n    fprintf(header,\n        \"const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\\n\");\n    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {\n        fprintf(header, \"%2u%s\", _length_code[i],\n                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));\n    }\n\n    fprintf(header, \"local const int base_length[LENGTH_CODES] = {\\n\");\n    for (i = 0; i < LENGTH_CODES; i++) {\n        fprintf(header, \"%1u%s\", base_length[i],\n                SEPARATOR(i, LENGTH_CODES-1, 20));\n    }\n\n    fprintf(header, \"local const int base_dist[D_CODES] = {\\n\");\n    for (i = 0; i < D_CODES; i++) {\n        fprintf(header, \"%5u%s\", base_dist[i],\n                SEPARATOR(i, D_CODES-1, 10));\n    }\n\n    fclose(header);\n}\n#endif /* GEN_TREES_H */\n\n/* ===========================================================================\n * Initialize the tree data structures for a new zlib stream.\n */\nvoid ZLIB_INTERNAL _tr_init(s)\n    deflate_state *s;\n{\n    tr_static_init();\n\n    s->l_desc.dyn_tree = s->dyn_ltree;\n    s->l_desc.stat_desc = &static_l_desc;\n\n    s->d_desc.dyn_tree = s->dyn_dtree;\n    s->d_desc.stat_desc = &static_d_desc;\n\n    s->bl_desc.dyn_tree = s->bl_tree;\n    s->bl_desc.stat_desc = &static_bl_desc;\n\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = 0L;\n    s->bits_sent = 0L;\n#endif\n\n    /* Initialize the first block of the first file: */\n    init_block(s);\n}\n\n/* ===========================================================================\n * Initialize a new block.\n */\nlocal void init_block(s)\n    deflate_state *s;\n{\n    int n; /* iterates over tree elements */\n\n    /* Initialize the trees. */\n    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;\n    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;\n    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;\n\n    s->dyn_ltree[END_BLOCK].Freq = 1;\n    s->opt_len = s->static_len = 0L;\n    s->last_lit = s->matches = 0;\n}\n\n#define SMALLEST 1\n/* Index within the heap array of least frequent node in the Huffman tree */\n\n\n/* ===========================================================================\n * Remove the smallest element from the heap and recreate the heap with\n * one less element. Updates heap and heap_len.\n */\n#define pqremove(s, tree, top) \\\n{\\\n    top = s->heap[SMALLEST]; \\\n    s->heap[SMALLEST] = s->heap[s->heap_len--]; \\\n    pqdownheap(s, tree, SMALLEST); \\\n}\n\n/* ===========================================================================\n * Compares to subtrees, using the tree depth as tie breaker when\n * the subtrees have equal frequency. This minimizes the worst case length.\n */\n#define smaller(tree, n, m, depth) \\\n   (tree[n].Freq < tree[m].Freq || \\\n   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))\n\n/* ===========================================================================\n * Restore the heap property by moving down the tree starting at node k,\n * exchanging a node with the smallest of its two sons if necessary, stopping\n * when the heap property is re-established (each father smaller than its\n * two sons).\n */\nlocal void pqdownheap(s, tree, k)\n    deflate_state *s;\n    ct_data *tree;  /* the tree to restore */\n    int k;               /* node to move down */\n{\n    int v = s->heap[k];\n    int j = k << 1;  /* left son of k */\n    while (j <= s->heap_len) {\n        /* Set j to the smallest of the two sons: */\n        if (j < s->heap_len &&\n            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {\n            j++;\n        }\n        /* Exit if v is smaller than both sons */\n        if (smaller(tree, v, s->heap[j], s->depth)) break;\n\n        /* Exchange v with the smallest son */\n        s->heap[k] = s->heap[j];  k = j;\n\n        /* And continue down the tree, setting j to the left son of k */\n        j <<= 1;\n    }\n    s->heap[k] = v;\n}\n\n/* ===========================================================================\n * Compute the optimal bit lengths for a tree and update the total bit length\n * for the current block.\n * IN assertion: the fields freq and dad are set, heap[heap_max] and\n *    above are the tree nodes sorted by increasing frequency.\n * OUT assertions: the field len is set to the optimal bit length, the\n *     array bl_count contains the frequencies for each bit length.\n *     The length opt_len is updated; static_len is also updated if stree is\n *     not null.\n */\nlocal void gen_bitlen(s, desc)\n    deflate_state *s;\n    tree_desc *desc;    /* the tree descriptor */\n{\n    ct_data *tree        = desc->dyn_tree;\n    int max_code         = desc->max_code;\n    const ct_data *stree = desc->stat_desc->static_tree;\n    const intf *extra    = desc->stat_desc->extra_bits;\n    int base             = desc->stat_desc->extra_base;\n    int max_length       = desc->stat_desc->max_length;\n    int h;              /* heap index */\n    int n, m;           /* iterate over the tree elements */\n    int bits;           /* bit length */\n    int xbits;          /* extra bits */\n    ush f;              /* frequency */\n    int overflow = 0;   /* number of elements with bit length too large */\n\n    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;\n\n    /* In a first pass, compute the optimal bit lengths (which may\n     * overflow in the case of the bit length tree).\n     */\n    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */\n\n    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {\n        n = s->heap[h];\n        bits = tree[tree[n].Dad].Len + 1;\n        if (bits > max_length) bits = max_length, overflow++;\n        tree[n].Len = (ush)bits;\n        /* We overwrite tree[n].Dad which is no longer needed */\n\n        if (n > max_code) continue; /* not a leaf node */\n\n        s->bl_count[bits]++;\n        xbits = 0;\n        if (n >= base) xbits = extra[n-base];\n        f = tree[n].Freq;\n        s->opt_len += (ulg)f * (unsigned)(bits + xbits);\n        if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);\n    }\n    if (overflow == 0) return;\n\n    Tracev((stderr,\"\\nbit length overflow\\n\"));\n    /* This happens for example on obj2 and pic of the Calgary corpus */\n\n    /* Find the first bit length which could increase: */\n    do {\n        bits = max_length-1;\n        while (s->bl_count[bits] == 0) bits--;\n        s->bl_count[bits]--;      /* move one leaf down the tree */\n        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */\n        s->bl_count[max_length]--;\n        /* The brother of the overflow item also moves one step up,\n         * but this does not affect bl_count[max_length]\n         */\n        overflow -= 2;\n    } while (overflow > 0);\n\n    /* Now recompute all bit lengths, scanning in increasing frequency.\n     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all\n     * lengths instead of fixing only the wrong ones. This idea is taken\n     * from 'ar' written by Haruhiko Okumura.)\n     */\n    for (bits = max_length; bits != 0; bits--) {\n        n = s->bl_count[bits];\n        while (n != 0) {\n            m = s->heap[--h];\n            if (m > max_code) continue;\n            if ((unsigned) tree[m].Len != (unsigned) bits) {\n                Tracev((stderr,\"code %d bits %d->%d\\n\", m, tree[m].Len, bits));\n                s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;\n                tree[m].Len = (ush)bits;\n            }\n            n--;\n        }\n    }\n}\n\n/* ===========================================================================\n * Generate the codes for a given tree and bit counts (which need not be\n * optimal).\n * IN assertion: the array bl_count contains the bit length statistics for\n * the given tree and the field len is set for all tree elements.\n * OUT assertion: the field code is set for all tree elements of non\n *     zero code length.\n */\nlocal void gen_codes (tree, max_code, bl_count)\n    ct_data *tree;             /* the tree to decorate */\n    int max_code;              /* largest code with non zero frequency */\n    ushf *bl_count;            /* number of codes at each bit length */\n{\n    ush next_code[MAX_BITS+1]; /* next code value for each bit length */\n    unsigned code = 0;         /* running code value */\n    int bits;                  /* bit index */\n    int n;                     /* code index */\n\n    /* The distribution counts are first used to generate the code values\n     * without bit reversal.\n     */\n    for (bits = 1; bits <= MAX_BITS; bits++) {\n        code = (code + bl_count[bits-1]) << 1;\n        next_code[bits] = (ush)code;\n    }\n    /* Check that the bit counts in bl_count are consistent. The last code\n     * must be all ones.\n     */\n    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,\n            \"inconsistent bit counts\");\n    Tracev((stderr,\"\\ngen_codes: max_code %d \", max_code));\n\n    for (n = 0;  n <= max_code; n++) {\n        int len = tree[n].Len;\n        if (len == 0) continue;\n        /* Now reverse the bits */\n        tree[n].Code = (ush)bi_reverse(next_code[len]++, len);\n\n        Tracecv(tree != static_ltree, (stderr,\"\\nn %3d %c l %2d c %4x (%x) \",\n             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));\n    }\n}\n\n/* ===========================================================================\n * Construct one Huffman tree and assigns the code bit strings and lengths.\n * Update the total bit length for the current block.\n * IN assertion: the field freq is set for all tree elements.\n * OUT assertions: the fields len and code are set to the optimal bit length\n *     and corresponding code. The length opt_len is updated; static_len is\n *     also updated if stree is not null. The field max_code is set.\n */\nlocal void build_tree(s, desc)\n    deflate_state *s;\n    tree_desc *desc; /* the tree descriptor */\n{\n    ct_data *tree         = desc->dyn_tree;\n    const ct_data *stree  = desc->stat_desc->static_tree;\n    int elems             = desc->stat_desc->elems;\n    int n, m;          /* iterate over heap elements */\n    int max_code = -1; /* largest code with non zero frequency */\n    int node;          /* new node being created */\n\n    /* Construct the initial heap, with least frequent element in\n     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].\n     * heap[0] is not used.\n     */\n    s->heap_len = 0, s->heap_max = HEAP_SIZE;\n\n    for (n = 0; n < elems; n++) {\n        if (tree[n].Freq != 0) {\n            s->heap[++(s->heap_len)] = max_code = n;\n            s->depth[n] = 0;\n        } else {\n            tree[n].Len = 0;\n        }\n    }\n\n    /* The pkzip format requires that at least one distance code exists,\n     * and that at least one bit should be sent even if there is only one\n     * possible code. So to avoid special checks later on we force at least\n     * two codes of non zero frequency.\n     */\n    while (s->heap_len < 2) {\n        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);\n        tree[node].Freq = 1;\n        s->depth[node] = 0;\n        s->opt_len--; if (stree) s->static_len -= stree[node].Len;\n        /* node is 0 or 1 so it does not have extra bits */\n    }\n    desc->max_code = max_code;\n\n    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,\n     * establish sub-heaps of increasing lengths:\n     */\n    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);\n\n    /* Construct the Huffman tree by repeatedly combining the least two\n     * frequent nodes.\n     */\n    node = elems;              /* next internal node of the tree */\n    do {\n        pqremove(s, tree, n);  /* n = node of least frequency */\n        m = s->heap[SMALLEST]; /* m = node of next least frequency */\n\n        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */\n        s->heap[--(s->heap_max)] = m;\n\n        /* Create a new node father of n and m */\n        tree[node].Freq = tree[n].Freq + tree[m].Freq;\n        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?\n                                s->depth[n] : s->depth[m]) + 1);\n        tree[n].Dad = tree[m].Dad = (ush)node;\n#ifdef DUMP_BL_TREE\n        if (tree == s->bl_tree) {\n            fprintf(stderr,\"\\nnode %d(%d), sons %d(%d) %d(%d)\",\n                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);\n        }\n#endif\n        /* and insert the new node in the heap */\n        s->heap[SMALLEST] = node++;\n        pqdownheap(s, tree, SMALLEST);\n\n    } while (s->heap_len >= 2);\n\n    s->heap[--(s->heap_max)] = s->heap[SMALLEST];\n\n    /* At this point, the fields freq and dad are set. We can now\n     * generate the bit lengths.\n     */\n    gen_bitlen(s, (tree_desc *)desc);\n\n    /* The field len is now set, we can generate the bit codes */\n    gen_codes ((ct_data *)tree, max_code, s->bl_count);\n}\n\n/* ===========================================================================\n * Scan a literal or distance tree to determine the frequencies of the codes\n * in the bit length tree.\n */\nlocal void scan_tree (s, tree, max_code)\n    deflate_state *s;\n    ct_data *tree;   /* the tree to be scanned */\n    int max_code;    /* and its largest code of non zero frequency */\n{\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    if (nextlen == 0) max_count = 138, min_count = 3;\n    tree[max_code+1].Len = (ush)0xffff; /* guard */\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n+1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            s->bl_tree[curlen].Freq += count;\n        } else if (curlen != 0) {\n            if (curlen != prevlen) s->bl_tree[curlen].Freq++;\n            s->bl_tree[REP_3_6].Freq++;\n        } else if (count <= 10) {\n            s->bl_tree[REPZ_3_10].Freq++;\n        } else {\n            s->bl_tree[REPZ_11_138].Freq++;\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Send a literal or distance tree in compressed form, using the codes in\n * bl_tree.\n */\nlocal void send_tree (s, tree, max_code)\n    deflate_state *s;\n    ct_data *tree; /* the tree to be scanned */\n    int max_code;       /* and its largest code of non zero frequency */\n{\n    int n;                     /* iterates over all tree elements */\n    int prevlen = -1;          /* last emitted length */\n    int curlen;                /* length of current code */\n    int nextlen = tree[0].Len; /* length of next code */\n    int count = 0;             /* repeat count of the current code */\n    int max_count = 7;         /* max repeat count */\n    int min_count = 4;         /* min repeat count */\n\n    /* tree[max_code+1].Len = -1; */  /* guard already set */\n    if (nextlen == 0) max_count = 138, min_count = 3;\n\n    for (n = 0; n <= max_code; n++) {\n        curlen = nextlen; nextlen = tree[n+1].Len;\n        if (++count < max_count && curlen == nextlen) {\n            continue;\n        } else if (count < min_count) {\n            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);\n\n        } else if (curlen != 0) {\n            if (curlen != prevlen) {\n                send_code(s, curlen, s->bl_tree); count--;\n            }\n            Assert(count >= 3 && count <= 6, \" 3_6?\");\n            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);\n\n        } else if (count <= 10) {\n            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);\n\n        } else {\n            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);\n        }\n        count = 0; prevlen = curlen;\n        if (nextlen == 0) {\n            max_count = 138, min_count = 3;\n        } else if (curlen == nextlen) {\n            max_count = 6, min_count = 3;\n        } else {\n            max_count = 7, min_count = 4;\n        }\n    }\n}\n\n/* ===========================================================================\n * Construct the Huffman tree for the bit lengths and return the index in\n * bl_order of the last bit length code to send.\n */\nlocal int build_bl_tree(s)\n    deflate_state *s;\n{\n    int max_blindex;  /* index of last bit length code of non zero freq */\n\n    /* Determine the bit length frequencies for literal and distance trees */\n    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);\n    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);\n\n    /* Build the bit length tree: */\n    build_tree(s, (tree_desc *)(&(s->bl_desc)));\n    /* opt_len now includes the length of the tree representations, except\n     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.\n     */\n\n    /* Determine the number of bit length codes to send. The pkzip format\n     * requires that at least 4 bit length codes be sent. (appnote.txt says\n     * 3 but the actual value used is 4.)\n     */\n    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {\n        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;\n    }\n    /* Update opt_len to include the bit length tree and counts */\n    s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;\n    Tracev((stderr, \"\\ndyn trees: dyn %ld, stat %ld\",\n            s->opt_len, s->static_len));\n\n    return max_blindex;\n}\n\n/* ===========================================================================\n * Send the header for a block using dynamic Huffman trees: the counts, the\n * lengths of the bit length codes, the literal tree and the distance tree.\n * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.\n */\nlocal void send_all_trees(s, lcodes, dcodes, blcodes)\n    deflate_state *s;\n    int lcodes, dcodes, blcodes; /* number of codes for each tree */\n{\n    int rank;                    /* index in bl_order */\n\n    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, \"not enough codes\");\n    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,\n            \"too many codes\");\n    Tracev((stderr, \"\\nbl counts: \"));\n    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */\n    send_bits(s, dcodes-1,   5);\n    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */\n    for (rank = 0; rank < blcodes; rank++) {\n        Tracev((stderr, \"\\nbl code %2d \", bl_order[rank]));\n        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);\n    }\n    Tracev((stderr, \"\\nbl tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */\n    Tracev((stderr, \"\\nlit tree: sent %ld\", s->bits_sent));\n\n    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */\n    Tracev((stderr, \"\\ndist tree: sent %ld\", s->bits_sent));\n}\n\n/* ===========================================================================\n * Send a stored block\n */\nvoid ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)\n    deflate_state *s;\n    charf *buf;       /* input block */\n    ulg stored_len;   /* length of input block */\n    int last;         /* one if this is the last block for a file */\n{\n    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */\n    bi_windup(s);        /* align on byte boundary */\n    put_short(s, (ush)stored_len);\n    put_short(s, (ush)~stored_len);\n    zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);\n    s->pending += stored_len;\n#ifdef ZLIB_DEBUG\n    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;\n    s->compressed_len += (stored_len + 4) << 3;\n    s->bits_sent += 2*16;\n    s->bits_sent += stored_len<<3;\n#endif\n}\n\n/* ===========================================================================\n * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)\n */\nvoid ZLIB_INTERNAL _tr_flush_bits(s)\n    deflate_state *s;\n{\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Send one empty static block to give enough lookahead for inflate.\n * This takes 10 bits, of which 7 may remain in the bit buffer.\n */\nvoid ZLIB_INTERNAL _tr_align(s)\n    deflate_state *s;\n{\n    send_bits(s, STATIC_TREES<<1, 3);\n    send_code(s, END_BLOCK, static_ltree);\n#ifdef ZLIB_DEBUG\n    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */\n#endif\n    bi_flush(s);\n}\n\n/* ===========================================================================\n * Determine the best encoding for the current block: dynamic trees, static\n * trees or store, and write out the encoded block.\n */\nvoid ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)\n    deflate_state *s;\n    charf *buf;       /* input block, or NULL if too old */\n    ulg stored_len;   /* length of input block */\n    int last;         /* one if this is the last block for a file */\n{\n    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */\n    int max_blindex = 0;  /* index of last bit length code of non zero freq */\n\n    /* Build the Huffman trees unless a stored block is forced */\n    if (s->level > 0) {\n\n        /* Check if the file is binary or text */\n        if (s->strm->data_type == Z_UNKNOWN)\n            s->strm->data_type = detect_data_type(s);\n\n        /* Construct the literal and distance trees */\n        build_tree(s, (tree_desc *)(&(s->l_desc)));\n        Tracev((stderr, \"\\nlit data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n\n        build_tree(s, (tree_desc *)(&(s->d_desc)));\n        Tracev((stderr, \"\\ndist data: dyn %ld, stat %ld\", s->opt_len,\n                s->static_len));\n        /* At this point, opt_len and static_len are the total bit lengths of\n         * the compressed block data, excluding the tree representations.\n         */\n\n        /* Build the bit length tree for the above two trees, and get the index\n         * in bl_order of the last bit length code to send.\n         */\n        max_blindex = build_bl_tree(s);\n\n        /* Determine the best encoding. Compute the block lengths in bytes. */\n        opt_lenb = (s->opt_len+3+7)>>3;\n        static_lenb = (s->static_len+3+7)>>3;\n\n        Tracev((stderr, \"\\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u \",\n                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,\n                s->last_lit));\n\n        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;\n\n    } else {\n        Assert(buf != (char*)0, \"lost buf\");\n        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */\n    }\n\n#ifdef FORCE_STORED\n    if (buf != (char*)0) { /* force stored block */\n#else\n    if (stored_len+4 <= opt_lenb && buf != (char*)0) {\n                       /* 4: two words for the lengths */\n#endif\n        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.\n         * Otherwise we can't have processed more than WSIZE input bytes since\n         * the last block flush, because compression would have been\n         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to\n         * transform a block into a stored block.\n         */\n        _tr_stored_block(s, buf, stored_len, last);\n\n#ifdef FORCE_STATIC\n    } else if (static_lenb >= 0) { /* force static trees */\n#else\n    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {\n#endif\n        send_bits(s, (STATIC_TREES<<1)+last, 3);\n        compress_block(s, (const ct_data *)static_ltree,\n                       (const ct_data *)static_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->static_len;\n#endif\n    } else {\n        send_bits(s, (DYN_TREES<<1)+last, 3);\n        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,\n                       max_blindex+1);\n        compress_block(s, (const ct_data *)s->dyn_ltree,\n                       (const ct_data *)s->dyn_dtree);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 3 + s->opt_len;\n#endif\n    }\n    Assert (s->compressed_len == s->bits_sent, \"bad compressed size\");\n    /* The above check is made mod 2^32, for files larger than 512 MB\n     * and uLong implemented on 32 bits.\n     */\n    init_block(s);\n\n    if (last) {\n        bi_windup(s);\n#ifdef ZLIB_DEBUG\n        s->compressed_len += 7;  /* align on byte boundary */\n#endif\n    }\n    Tracev((stderr,\"\\ncomprlen %lu(%lu) \", s->compressed_len>>3,\n           s->compressed_len-7*last));\n}\n\n/* ===========================================================================\n * Save the match info and tally the frequency counts. Return true if\n * the current block must be flushed.\n */\nint ZLIB_INTERNAL _tr_tally (s, dist, lc)\n    deflate_state *s;\n    unsigned dist;  /* distance of matched string */\n    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */\n{\n    s->d_buf[s->last_lit] = (ush)dist;\n    s->l_buf[s->last_lit++] = (uch)lc;\n    if (dist == 0) {\n        /* lc is the unmatched char */\n        s->dyn_ltree[lc].Freq++;\n    } else {\n        s->matches++;\n        /* Here, lc is the match length - MIN_MATCH */\n        dist--;             /* dist = match distance - 1 */\n        Assert((ush)dist < (ush)MAX_DIST(s) &&\n               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&\n               (ush)d_code(dist) < (ush)D_CODES,  \"_tr_tally: bad match\");\n\n        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;\n        s->dyn_dtree[d_code(dist)].Freq++;\n    }\n\n#ifdef TRUNCATE_BLOCK\n    /* Try to guess if it is profitable to stop the current block here */\n    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {\n        /* Compute an upper bound for the compressed length */\n        ulg out_length = (ulg)s->last_lit*8L;\n        ulg in_length = (ulg)((long)s->strstart - s->block_start);\n        int dcode;\n        for (dcode = 0; dcode < D_CODES; dcode++) {\n            out_length += (ulg)s->dyn_dtree[dcode].Freq *\n                (5L+extra_dbits[dcode]);\n        }\n        out_length >>= 3;\n        Tracev((stderr,\"\\nlast_lit %u, in %ld, out ~%ld(%ld%%) \",\n               s->last_lit, in_length, out_length,\n               100L - out_length*100L/in_length));\n        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;\n    }\n#endif\n    return (s->last_lit == s->lit_bufsize-1);\n    /* We avoid equality with lit_bufsize because of wraparound at 64K\n     * on 16 bit machines and because stored blocks are restricted to\n     * 64K-1 bytes.\n     */\n}\n\n/* ===========================================================================\n * Send the block data compressed using the given Huffman trees\n */\nlocal void compress_block(s, ltree, dtree)\n    deflate_state *s;\n    const ct_data *ltree; /* literal tree */\n    const ct_data *dtree; /* distance tree */\n{\n    unsigned dist;      /* distance of matched string */\n    int lc;             /* match length or unmatched char (if dist == 0) */\n    unsigned lx = 0;    /* running index in l_buf */\n    unsigned code;      /* the code to send */\n    int extra;          /* number of extra bits to send */\n\n    if (s->last_lit != 0) do {\n        dist = s->d_buf[lx];\n        lc = s->l_buf[lx++];\n        if (dist == 0) {\n            send_code(s, lc, ltree); /* send a literal byte */\n            Tracecv(isgraph(lc), (stderr,\" '%c' \", lc));\n        } else {\n            /* Here, lc is the match length - MIN_MATCH */\n            code = _length_code[lc];\n            send_code(s, code+LITERALS+1, ltree); /* send the length code */\n            extra = extra_lbits[code];\n            if (extra != 0) {\n                lc -= base_length[code];\n                send_bits(s, lc, extra);       /* send the extra length bits */\n            }\n            dist--; /* dist is now the match distance - 1 */\n            code = d_code(dist);\n            Assert (code < D_CODES, \"bad d_code\");\n\n            send_code(s, code, dtree);       /* send the distance code */\n            extra = extra_dbits[code];\n            if (extra != 0) {\n                dist -= (unsigned)base_dist[code];\n                send_bits(s, dist, extra);   /* send the extra distance bits */\n            }\n        } /* literal or match pair ? */\n\n        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */\n        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,\n               \"pendingBuf overflow\");\n\n    } while (lx < s->last_lit);\n\n    send_code(s, END_BLOCK, ltree);\n}\n\n/* ===========================================================================\n * Check if the data type is TEXT or BINARY, using the following algorithm:\n * - TEXT if the two conditions below are satisfied:\n *    a) There are no non-portable control characters belonging to the\n *       \"black list\" (0..6, 14..25, 28..31).\n *    b) There is at least one printable character belonging to the\n *       \"white list\" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).\n * - BINARY otherwise.\n * - The following partially-portable control characters form a\n *   \"gray list\" that is ignored in this detection algorithm:\n *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).\n * IN assertion: the fields Freq of dyn_ltree are set.\n */\nlocal int detect_data_type(s)\n    deflate_state *s;\n{\n    /* black_mask is the bit mask of black-listed bytes\n     * set bits 0..6, 14..25, and 28..31\n     * 0xf3ffc07f = binary 11110011111111111100000001111111\n     */\n    unsigned long black_mask = 0xf3ffc07fUL;\n    int n;\n\n    /* Check for non-textual (\"black-listed\") bytes. */\n    for (n = 0; n <= 31; n++, black_mask >>= 1)\n        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))\n            return Z_BINARY;\n\n    /* Check for textual (\"white-listed\") bytes. */\n    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0\n            || s->dyn_ltree[13].Freq != 0)\n        return Z_TEXT;\n    for (n = 32; n < LITERALS; n++)\n        if (s->dyn_ltree[n].Freq != 0)\n            return Z_TEXT;\n\n    /* There are no \"black-listed\" or \"white-listed\" bytes:\n     * this stream either is empty or has tolerated (\"gray-listed\") bytes only.\n     */\n    return Z_BINARY;\n}\n\n/* ===========================================================================\n * Reverse the first len bits of a code, using straightforward code (a faster\n * method would use a table)\n * IN assertion: 1 <= len <= 15\n */\nlocal unsigned bi_reverse(code, len)\n    unsigned code; /* the value to invert */\n    int len;       /* its bit length */\n{\n    register unsigned res = 0;\n    do {\n        res |= code & 1;\n        code >>= 1, res <<= 1;\n    } while (--len > 0);\n    return res >> 1;\n}\n\n/* ===========================================================================\n * Flush the bit buffer, keeping at most 7 bits in it.\n */\nlocal void bi_flush(s)\n    deflate_state *s;\n{\n    if (s->bi_valid == 16) {\n        put_short(s, s->bi_buf);\n        s->bi_buf = 0;\n        s->bi_valid = 0;\n    } else if (s->bi_valid >= 8) {\n        put_byte(s, (Byte)s->bi_buf);\n        s->bi_buf >>= 8;\n        s->bi_valid -= 8;\n    }\n}\n\n/* ===========================================================================\n * Flush the bit buffer and align the output on a byte boundary\n */\nlocal void bi_windup(s)\n    deflate_state *s;\n{\n    if (s->bi_valid > 8) {\n        put_short(s, s->bi_buf);\n    } else if (s->bi_valid > 0) {\n        put_byte(s, (Byte)s->bi_buf);\n    }\n    s->bi_buf = 0;\n    s->bi_valid = 0;\n#ifdef ZLIB_DEBUG\n    s->bits_sent = (s->bits_sent+7) & ~7;\n#endif\n}\n"
  },
  {
    "path": "dlib/external/zlib/trees.h",
    "content": "/* header created automatically with -DGEN_TREES_H */\n\nlocal const ct_data static_ltree[L_CODES+2] = {\n{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},\n{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},\n{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},\n{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},\n{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},\n{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},\n{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},\n{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},\n{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},\n{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},\n{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},\n{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},\n{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},\n{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},\n{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},\n{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},\n{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},\n{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},\n{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},\n{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},\n{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},\n{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},\n{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},\n{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},\n{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},\n{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},\n{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},\n{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},\n{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},\n{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},\n{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},\n{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},\n{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},\n{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},\n{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},\n{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},\n{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},\n{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},\n{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},\n{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},\n{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},\n{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},\n{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},\n{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},\n{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},\n{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},\n{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},\n{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},\n{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},\n{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},\n{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},\n{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},\n{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},\n{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},\n{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},\n{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},\n{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},\n{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}\n};\n\nlocal const ct_data static_dtree[D_CODES] = {\n{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},\n{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},\n{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},\n{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},\n{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},\n{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}\n};\n\nconst uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,\n 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,\n10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,\n11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,\n12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,\n13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,\n14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,\n15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,\n18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,\n28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,\n29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29\n};\n\nconst uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,\n13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,\n17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,\n19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,\n21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,\n22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,\n23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,\n25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,\n26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,\n27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28\n};\n\nlocal const int base_length[LENGTH_CODES] = {\n0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,\n64, 80, 96, 112, 128, 160, 192, 224, 0\n};\n\nlocal const int base_dist[D_CODES] = {\n    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,\n   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,\n 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576\n};\n\n"
  },
  {
    "path": "dlib/external/zlib/uncompr.c",
    "content": "/* uncompr.c -- decompress a memory buffer\n * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#define ZLIB_INTERNAL\n#include \"zlib.h\"\n\n/* ===========================================================================\n     Decompresses the source buffer into the destination buffer.  *sourceLen is\n   the byte length of the source buffer. Upon entry, *destLen is the total size\n   of the destination buffer, which must be large enough to hold the entire\n   uncompressed data. (The size of the uncompressed data must have been saved\n   previously by the compressor and transmitted to the decompressor by some\n   mechanism outside the scope of this compression library.) Upon exit,\n   *destLen is the size of the decompressed data and *sourceLen is the number\n   of source bytes consumed. Upon return, source + *sourceLen points to the\n   first unused input byte.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer, or\n   Z_DATA_ERROR if the input data was corrupted, including if the input data is\n   an incomplete zlib stream.\n*/\nint ZEXPORT uncompress2 (dest, destLen, source, sourceLen)\n    Bytef *dest;\n    uLongf *destLen;\n    const Bytef *source;\n    uLong *sourceLen;\n{\n    z_stream stream;\n    int err;\n    const uInt max = (uInt)-1;\n    uLong len, left;\n    Byte buf[1];    /* for detection of incomplete stream when *destLen == 0 */\n\n    len = *sourceLen;\n    if (*destLen) {\n        left = *destLen;\n        *destLen = 0;\n    }\n    else {\n        left = 1;\n        dest = buf;\n    }\n\n    stream.next_in = (z_const Bytef *)source;\n    stream.avail_in = 0;\n    stream.zalloc = (alloc_func)0;\n    stream.zfree = (free_func)0;\n    stream.opaque = (voidpf)0;\n\n    err = inflateInit(&stream);\n    if (err != Z_OK) return err;\n\n    stream.next_out = dest;\n    stream.avail_out = 0;\n\n    do {\n        if (stream.avail_out == 0) {\n            stream.avail_out = left > (uLong)max ? max : (uInt)left;\n            left -= stream.avail_out;\n        }\n        if (stream.avail_in == 0) {\n            stream.avail_in = len > (uLong)max ? max : (uInt)len;\n            len -= stream.avail_in;\n        }\n        err = inflate(&stream, Z_NO_FLUSH);\n    } while (err == Z_OK);\n\n    *sourceLen -= len + stream.avail_in;\n    if (dest != buf)\n        *destLen = stream.total_out;\n    else if (stream.total_out && err == Z_BUF_ERROR)\n        left = 1;\n\n    inflateEnd(&stream);\n    return err == Z_STREAM_END ? Z_OK :\n           err == Z_NEED_DICT ? Z_DATA_ERROR  :\n           err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :\n           err;\n}\n\nint ZEXPORT uncompress (dest, destLen, source, sourceLen)\n    Bytef *dest;\n    uLongf *destLen;\n    const Bytef *source;\n    uLong sourceLen;\n{\n    return uncompress2(dest, destLen, source, &sourceLen);\n}\n"
  },
  {
    "path": "dlib/external/zlib/zconf.h",
    "content": "/* zconf.h -- configuration of the zlib compression library\n * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZCONF_H\n#define ZCONF_H\n\n/*\n * If you *really* need a unique prefix for all types and library functions,\n * compile with -DZ_PREFIX. The \"standard\" zlib should be compiled without it.\n * Even better than compiling with -DZ_PREFIX would be to use configure to set\n * this permanently in zconf.h using \"./configure --zprefix\".\n */\n#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */\n#  define Z_PREFIX_SET\n\n/* all linked symbols and init macros */\n#  define _dist_code            z__dist_code\n#  define _length_code          z__length_code\n#  define _tr_align             z__tr_align\n#  define _tr_flush_bits        z__tr_flush_bits\n#  define _tr_flush_block       z__tr_flush_block\n#  define _tr_init              z__tr_init\n#  define _tr_stored_block      z__tr_stored_block\n#  define _tr_tally             z__tr_tally\n#  define adler32               z_adler32\n#  define adler32_combine       z_adler32_combine\n#  define adler32_combine64     z_adler32_combine64\n#  define adler32_z             z_adler32_z\n#  ifndef Z_SOLO\n#    define compress              z_compress\n#    define compress2             z_compress2\n#    define compressBound         z_compressBound\n#  endif\n#  define crc32                 z_crc32\n#  define crc32_combine         z_crc32_combine\n#  define crc32_combine64       z_crc32_combine64\n#  define crc32_z               z_crc32_z\n#  define deflate               z_deflate\n#  define deflateBound          z_deflateBound\n#  define deflateCopy           z_deflateCopy\n#  define deflateEnd            z_deflateEnd\n#  define deflateGetDictionary  z_deflateGetDictionary\n#  define deflateInit           z_deflateInit\n#  define deflateInit2          z_deflateInit2\n#  define deflateInit2_         z_deflateInit2_\n#  define deflateInit_          z_deflateInit_\n#  define deflateParams         z_deflateParams\n#  define deflatePending        z_deflatePending\n#  define deflatePrime          z_deflatePrime\n#  define deflateReset          z_deflateReset\n#  define deflateResetKeep      z_deflateResetKeep\n#  define deflateSetDictionary  z_deflateSetDictionary\n#  define deflateSetHeader      z_deflateSetHeader\n#  define deflateTune           z_deflateTune\n#  define deflate_copyright     z_deflate_copyright\n#  define get_crc_table         z_get_crc_table\n#  ifndef Z_SOLO\n#    define gz_error              z_gz_error\n#    define gz_intmax             z_gz_intmax\n#    define gz_strwinerror        z_gz_strwinerror\n#    define gzbuffer              z_gzbuffer\n#    define gzclearerr            z_gzclearerr\n#    define gzclose               z_gzclose\n#    define gzclose_r             z_gzclose_r\n#    define gzclose_w             z_gzclose_w\n#    define gzdirect              z_gzdirect\n#    define gzdopen               z_gzdopen\n#    define gzeof                 z_gzeof\n#    define gzerror               z_gzerror\n#    define gzflush               z_gzflush\n#    define gzfread               z_gzfread\n#    define gzfwrite              z_gzfwrite\n#    define gzgetc                z_gzgetc\n#    define gzgetc_               z_gzgetc_\n#    define gzgets                z_gzgets\n#    define gzoffset              z_gzoffset\n#    define gzoffset64            z_gzoffset64\n#    define gzopen                z_gzopen\n#    define gzopen64              z_gzopen64\n#    ifdef _WIN32\n#      define gzopen_w              z_gzopen_w\n#    endif\n#    define gzprintf              z_gzprintf\n#    define gzputc                z_gzputc\n#    define gzputs                z_gzputs\n#    define gzread                z_gzread\n#    define gzrewind              z_gzrewind\n#    define gzseek                z_gzseek\n#    define gzseek64              z_gzseek64\n#    define gzsetparams           z_gzsetparams\n#    define gztell                z_gztell\n#    define gztell64              z_gztell64\n#    define gzungetc              z_gzungetc\n#    define gzvprintf             z_gzvprintf\n#    define gzwrite               z_gzwrite\n#  endif\n#  define inflate               z_inflate\n#  define inflateBack           z_inflateBack\n#  define inflateBackEnd        z_inflateBackEnd\n#  define inflateBackInit       z_inflateBackInit\n#  define inflateBackInit_      z_inflateBackInit_\n#  define inflateCodesUsed      z_inflateCodesUsed\n#  define inflateCopy           z_inflateCopy\n#  define inflateEnd            z_inflateEnd\n#  define inflateGetDictionary  z_inflateGetDictionary\n#  define inflateGetHeader      z_inflateGetHeader\n#  define inflateInit           z_inflateInit\n#  define inflateInit2          z_inflateInit2\n#  define inflateInit2_         z_inflateInit2_\n#  define inflateInit_          z_inflateInit_\n#  define inflateMark           z_inflateMark\n#  define inflatePrime          z_inflatePrime\n#  define inflateReset          z_inflateReset\n#  define inflateReset2         z_inflateReset2\n#  define inflateResetKeep      z_inflateResetKeep\n#  define inflateSetDictionary  z_inflateSetDictionary\n#  define inflateSync           z_inflateSync\n#  define inflateSyncPoint      z_inflateSyncPoint\n#  define inflateUndermine      z_inflateUndermine\n#  define inflateValidate       z_inflateValidate\n#  define inflate_copyright     z_inflate_copyright\n#  define inflate_fast          z_inflate_fast\n#  define inflate_table         z_inflate_table\n#  ifndef Z_SOLO\n#    define uncompress            z_uncompress\n#    define uncompress2           z_uncompress2\n#  endif\n#  define zError                z_zError\n#  ifndef Z_SOLO\n#    define zcalloc               z_zcalloc\n#    define zcfree                z_zcfree\n#  endif\n#  define zlibCompileFlags      z_zlibCompileFlags\n#  define zlibVersion           z_zlibVersion\n\n/* all zlib typedefs in zlib.h and zconf.h */\n#  define Byte                  z_Byte\n#  define Bytef                 z_Bytef\n#  define alloc_func            z_alloc_func\n#  define charf                 z_charf\n#  define free_func             z_free_func\n#  ifndef Z_SOLO\n#    define gzFile                z_gzFile\n#  endif\n#  define gz_header             z_gz_header\n#  define gz_headerp            z_gz_headerp\n#  define in_func               z_in_func\n#  define intf                  z_intf\n#  define out_func              z_out_func\n#  define uInt                  z_uInt\n#  define uIntf                 z_uIntf\n#  define uLong                 z_uLong\n#  define uLongf                z_uLongf\n#  define voidp                 z_voidp\n#  define voidpc                z_voidpc\n#  define voidpf                z_voidpf\n\n/* all zlib structs in zlib.h and zconf.h */\n#  define gz_header_s           z_gz_header_s\n#  define internal_state        z_internal_state\n\n#endif\n\n#if defined(__MSDOS__) && !defined(MSDOS)\n#  define MSDOS\n#endif\n#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)\n#  define OS2\n#endif\n#if defined(_WINDOWS) && !defined(WINDOWS)\n#  define WINDOWS\n#endif\n#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)\n#  ifndef WIN32\n#    define WIN32\n#  endif\n#endif\n#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)\n#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)\n#    ifndef SYS16BIT\n#      define SYS16BIT\n#    endif\n#  endif\n#endif\n\n/*\n * Compile with -DMAXSEG_64K if the alloc function cannot allocate more\n * than 64k bytes at a time (needed on systems with 16-bit int).\n */\n#ifdef SYS16BIT\n#  define MAXSEG_64K\n#endif\n#ifdef MSDOS\n#  define UNALIGNED_OK\n#endif\n\n#ifdef __STDC_VERSION__\n#  ifndef STDC\n#    define STDC\n#  endif\n#  if __STDC_VERSION__ >= 199901L\n#    ifndef STDC99\n#      define STDC99\n#    endif\n#  endif\n#endif\n#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))\n#  define STDC\n#endif\n#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))\n#  define STDC\n#endif\n\n#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */\n#  define STDC\n#endif\n\n#ifndef STDC\n#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */\n#    define const       /* note: need a more gentle solution here */\n#  endif\n#endif\n\n#if defined(ZLIB_CONST) && !defined(z_const)\n#  define z_const const\n#else\n#  define z_const\n#endif\n\n#ifdef Z_SOLO\n   typedef unsigned long z_size_t;\n#else\n#  define z_longlong long long\n#  if defined(NO_SIZE_T)\n     typedef unsigned NO_SIZE_T z_size_t;\n#  elif defined(STDC)\n#    include <stddef.h>\n     typedef size_t z_size_t;\n#  else\n     typedef unsigned long z_size_t;\n#  endif\n#  undef z_longlong\n#endif\n\n/* Maximum value for memLevel in deflateInit2 */\n#ifndef MAX_MEM_LEVEL\n#  ifdef MAXSEG_64K\n#    define MAX_MEM_LEVEL 8\n#  else\n#    define MAX_MEM_LEVEL 9\n#  endif\n#endif\n\n/* Maximum value for windowBits in deflateInit2 and inflateInit2.\n * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files\n * created by gzip. (Files created by minigzip can still be extracted by\n * gzip.)\n */\n#ifndef MAX_WBITS\n#  define MAX_WBITS   15 /* 32K LZ77 window */\n#endif\n\n/* The memory requirements for deflate are (in bytes):\n            (1 << (windowBits+2)) +  (1 << (memLevel+9))\n that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)\n plus a few kilobytes for small objects. For example, if you want to reduce\n the default memory requirements from 256K to 128K, compile with\n     make CFLAGS=\"-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7\"\n Of course this will generally degrade compression (there's no free lunch).\n\n   The memory requirements for inflate are (in bytes) 1 << windowBits\n that is, 32K for windowBits=15 (default value) plus about 7 kilobytes\n for small objects.\n*/\n\n                        /* Type declarations */\n\n#ifndef OF /* function prototypes */\n#  ifdef STDC\n#    define OF(args)  args\n#  else\n#    define OF(args)  ()\n#  endif\n#endif\n\n#ifndef Z_ARG /* function prototypes for stdarg */\n#  if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#    define Z_ARG(args)  args\n#  else\n#    define Z_ARG(args)  ()\n#  endif\n#endif\n\n/* The following definitions for FAR are needed only for MSDOS mixed\n * model programming (small or medium model with some far allocations).\n * This was tested only with MSC; for other MSDOS compilers you may have\n * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,\n * just define FAR to be empty.\n */\n#ifdef SYS16BIT\n#  if defined(M_I86SM) || defined(M_I86MM)\n     /* MSC small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef _MSC_VER\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#  if (defined(__SMALL__) || defined(__MEDIUM__))\n     /* Turbo C small or medium model */\n#    define SMALL_MEDIUM\n#    ifdef __BORLANDC__\n#      define FAR _far\n#    else\n#      define FAR far\n#    endif\n#  endif\n#endif\n\n#if defined(WINDOWS) || defined(WIN32)\n   /* If building or using zlib as a DLL, define ZLIB_DLL.\n    * This is not mandatory, but it offers a little performance increase.\n    */\n#  ifdef ZLIB_DLL\n#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))\n#      ifdef ZLIB_INTERNAL\n#        define ZEXTERN extern __declspec(dllexport)\n#      else\n#        define ZEXTERN extern __declspec(dllimport)\n#      endif\n#    endif\n#  endif  /* ZLIB_DLL */\n   /* If building or using zlib with the WINAPI/WINAPIV calling convention,\n    * define ZLIB_WINAPI.\n    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.\n    */\n#  ifdef ZLIB_WINAPI\n#    ifdef FAR\n#      undef FAR\n#    endif\n#    include <windows.h>\n     /* No need for _export, use ZLIB.DEF instead. */\n     /* For complete Windows compatibility, use WINAPI, not __stdcall. */\n#    define ZEXPORT WINAPI\n#    ifdef WIN32\n#      define ZEXPORTVA WINAPIV\n#    else\n#      define ZEXPORTVA FAR CDECL\n#    endif\n#  endif\n#endif\n\n#if defined (__BEOS__)\n#  ifdef ZLIB_DLL\n#    ifdef ZLIB_INTERNAL\n#      define ZEXPORT   __declspec(dllexport)\n#      define ZEXPORTVA __declspec(dllexport)\n#    else\n#      define ZEXPORT   __declspec(dllimport)\n#      define ZEXPORTVA __declspec(dllimport)\n#    endif\n#  endif\n#endif\n\n#ifndef ZEXTERN\n#  define ZEXTERN extern\n#endif\n#ifndef ZEXPORT\n#  define ZEXPORT\n#endif\n#ifndef ZEXPORTVA\n#  define ZEXPORTVA\n#endif\n\n#ifndef FAR\n#  define FAR\n#endif\n\n#if !defined(__MACTYPES__)\ntypedef unsigned char  Byte;  /* 8 bits */\n#endif\ntypedef unsigned int   uInt;  /* 16 bits or more */\ntypedef unsigned long  uLong; /* 32 bits or more */\n\n#ifdef SMALL_MEDIUM\n   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */\n#  define Bytef Byte FAR\n#else\n   typedef Byte  FAR Bytef;\n#endif\ntypedef char  FAR charf;\ntypedef int   FAR intf;\ntypedef uInt  FAR uIntf;\ntypedef uLong FAR uLongf;\n\n#ifdef STDC\n   typedef void const *voidpc;\n   typedef void FAR   *voidpf;\n   typedef void       *voidp;\n#else\n   typedef Byte const *voidpc;\n   typedef Byte FAR   *voidpf;\n   typedef Byte       *voidp;\n#endif\n\n#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)\n#  include <limits.h>\n#  if (UINT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned\n#  elif (ULONG_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned long\n#  elif (USHRT_MAX == 0xffffffffUL)\n#    define Z_U4 unsigned short\n#  endif\n#endif\n\n#ifdef Z_U4\n   typedef Z_U4 z_crc_t;\n#else\n   typedef unsigned long z_crc_t;\n#endif\n\n#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_UNISTD_H\n#endif\n\n#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */\n#  define Z_HAVE_STDARG_H\n#endif\n\n#ifdef STDC\n#  ifndef Z_SOLO\n#    include <sys/types.h>      /* for off_t */\n#  endif\n#endif\n\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\n#    include <stdarg.h>         /* for va_list */\n#  endif\n#endif\n\n#ifdef _WIN32\n#  ifndef Z_SOLO\n#    include <stddef.h>         /* for wchar_t */\n#  endif\n#endif\n\n/* a little trick to accommodate both \"#define _LARGEFILE64_SOURCE\" and\n * \"#define _LARGEFILE64_SOURCE 1\" as requesting 64-bit operations, (even\n * though the former does not conform to the LFS document), but considering\n * both \"#undef _LARGEFILE64_SOURCE\" and \"#define _LARGEFILE64_SOURCE 0\" as\n * equivalently requesting no 64-bit operations\n */\n#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1\n#  undef _LARGEFILE64_SOURCE\n#endif\n\n#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)\n#  define Z_HAVE_UNISTD_H\n#endif\n#ifndef Z_SOLO\n#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)\n#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */\n#    ifdef VMS\n#      include <unixio.h>       /* for off_t */\n#    endif\n#    ifndef z_off_t\n#      define z_off_t off_t\n#    endif\n#  endif\n#endif\n\n#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0\n#  define Z_LFS64\n#endif\n\n#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)\n#  define Z_LARGE64\n#endif\n\n#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)\n#  define Z_WANT64\n#endif\n\n#if !defined(SEEK_SET) && !defined(Z_SOLO)\n#  define SEEK_SET        0       /* Seek from beginning of file.  */\n#  define SEEK_CUR        1       /* Seek from current position.  */\n#  define SEEK_END        2       /* Set file pointer to EOF plus \"offset\" */\n#endif\n\n#ifndef z_off_t\n#  define z_off_t long\n#endif\n\n#if !defined(_WIN32) && defined(Z_LARGE64)\n#  define z_off64_t off64_t\n#else\n#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)\n#    define z_off64_t __int64\n#  else\n#    define z_off64_t z_off_t\n#  endif\n#endif\n\n/* MVS linker does not support external names larger than 8 bytes */\n#if defined(__MVS__)\n  #pragma map(deflateInit_,\"DEIN\")\n  #pragma map(deflateInit2_,\"DEIN2\")\n  #pragma map(deflateEnd,\"DEEND\")\n  #pragma map(deflateBound,\"DEBND\")\n  #pragma map(inflateInit_,\"ININ\")\n  #pragma map(inflateInit2_,\"ININ2\")\n  #pragma map(inflateEnd,\"INEND\")\n  #pragma map(inflateSync,\"INSY\")\n  #pragma map(inflateSetDictionary,\"INSEDI\")\n  #pragma map(compressBound,\"CMBND\")\n  #pragma map(inflate_table,\"INTABL\")\n  #pragma map(inflate_fast,\"INFA\")\n  #pragma map(inflate_copyright,\"INCOPY\")\n#endif\n\n#endif /* ZCONF_H */\n"
  },
  {
    "path": "dlib/external/zlib/zlib.h",
    "content": "/* zlib.h -- interface of the 'zlib' general purpose compression library\n  version 1.2.11, January 15th, 2017\n\n  Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Jean-loup Gailly        Mark Adler\n  jloup@gzip.org          madler@alumni.caltech.edu\n\n\n  The data format used by the zlib library is described by RFCs (Request for\n  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950\n  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).\n*/\n\n#ifndef ZLIB_H\n#define ZLIB_H\n\n#include \"zconf.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define ZLIB_VERSION \"1.2.11\"\n#define ZLIB_VERNUM 0x12b0\n#define ZLIB_VER_MAJOR 1\n#define ZLIB_VER_MINOR 2\n#define ZLIB_VER_REVISION 11\n#define ZLIB_VER_SUBREVISION 0\n\n/*\n    The 'zlib' compression library provides in-memory compression and\n  decompression functions, including integrity checks of the uncompressed data.\n  This version of the library supports only one compression method (deflation)\n  but other algorithms will be added later and will have the same stream\n  interface.\n\n    Compression can be done in a single step if the buffers are large enough,\n  or can be done by repeated calls of the compression function.  In the latter\n  case, the application must provide more input and/or consume the output\n  (providing more output space) before each call.\n\n    The compressed data format used by default by the in-memory functions is\n  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped\n  around a deflate stream, which is itself documented in RFC 1951.\n\n    The library also supports reading and writing files in gzip (.gz) format\n  with an interface similar to that of stdio using the functions that start\n  with \"gz\".  The gzip format is different from the zlib format.  gzip is a\n  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.\n\n    This library can optionally read and write gzip and raw deflate streams in\n  memory as well.\n\n    The zlib format was designed to be compact and fast for use in memory\n  and on communications channels.  The gzip format was designed for single-\n  file compression on file systems, has a larger header than zlib to maintain\n  directory information, and uses a different, slower check method than zlib.\n\n    The library does not install any signal handler.  The decoder checks\n  the consistency of the compressed data, so the library should never crash\n  even in the case of corrupted input.\n*/\n\ntypedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));\ntypedef void   (*free_func)  OF((voidpf opaque, voidpf address));\n\nstruct internal_state;\n\ntypedef struct z_stream_s {\n    z_const Bytef *next_in;     /* next input byte */\n    uInt     avail_in;  /* number of bytes available at next_in */\n    uLong    total_in;  /* total number of input bytes read so far */\n\n    Bytef    *next_out; /* next output byte will go here */\n    uInt     avail_out; /* remaining free space at next_out */\n    uLong    total_out; /* total number of bytes output so far */\n\n    z_const char *msg;  /* last error message, NULL if no error */\n    struct internal_state FAR *state; /* not visible by applications */\n\n    alloc_func zalloc;  /* used to allocate the internal state */\n    free_func  zfree;   /* used to free the internal state */\n    voidpf     opaque;  /* private data object passed to zalloc and zfree */\n\n    int     data_type;  /* best guess about the data type: binary or text\n                           for deflate, or the decoding state for inflate */\n    uLong   adler;      /* Adler-32 or CRC-32 value of the uncompressed data */\n    uLong   reserved;   /* reserved for future use */\n} z_stream;\n\ntypedef z_stream FAR *z_streamp;\n\n/*\n     gzip header information passed to and from zlib routines.  See RFC 1952\n  for more details on the meanings of these fields.\n*/\ntypedef struct gz_header_s {\n    int     text;       /* true if compressed data believed to be text */\n    uLong   time;       /* modification time */\n    int     xflags;     /* extra flags (not used when writing a gzip file) */\n    int     os;         /* operating system */\n    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */\n    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */\n    uInt    extra_max;  /* space at extra (only when reading header) */\n    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */\n    uInt    name_max;   /* space at name (only when reading header) */\n    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */\n    uInt    comm_max;   /* space at comment (only when reading header) */\n    int     hcrc;       /* true if there was or will be a header crc */\n    int     done;       /* true when done reading gzip header (not used\n                           when writing a gzip file) */\n} gz_header;\n\ntypedef gz_header FAR *gz_headerp;\n\n/*\n     The application must update next_in and avail_in when avail_in has dropped\n   to zero.  It must update next_out and avail_out when avail_out has dropped\n   to zero.  The application must initialize zalloc, zfree and opaque before\n   calling the init function.  All other fields are set by the compression\n   library and must not be updated by the application.\n\n     The opaque value provided by the application will be passed as the first\n   parameter for calls of zalloc and zfree.  This can be useful for custom\n   memory management.  The compression library attaches no meaning to the\n   opaque value.\n\n     zalloc must return Z_NULL if there is not enough memory for the object.\n   If zlib is used in a multi-threaded application, zalloc and zfree must be\n   thread safe.  In that case, zlib is thread-safe.  When zalloc and zfree are\n   Z_NULL on entry to the initialization function, they are set to internal\n   routines that use the standard library functions malloc() and free().\n\n     On 16-bit systems, the functions zalloc and zfree must be able to allocate\n   exactly 65536 bytes, but will not be required to allocate more than this if\n   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers\n   returned by zalloc for objects of exactly 65536 bytes *must* have their\n   offset normalized to zero.  The default allocation function provided by this\n   library ensures this (see zutil.c).  To reduce memory requirements and avoid\n   any allocation of 64K objects, at the expense of compression ratio, compile\n   the library with -DMAX_WBITS=14 (see zconf.h).\n\n     The fields total_in and total_out can be used for statistics or progress\n   reports.  After compression, total_in holds the total size of the\n   uncompressed data and may be saved for use by the decompressor (particularly\n   if the decompressor wants to decompress everything in a single step).\n*/\n\n                        /* constants */\n\n#define Z_NO_FLUSH      0\n#define Z_PARTIAL_FLUSH 1\n#define Z_SYNC_FLUSH    2\n#define Z_FULL_FLUSH    3\n#define Z_FINISH        4\n#define Z_BLOCK         5\n#define Z_TREES         6\n/* Allowed flush values; see deflate() and inflate() below for details */\n\n#define Z_OK            0\n#define Z_STREAM_END    1\n#define Z_NEED_DICT     2\n#define Z_ERRNO        (-1)\n#define Z_STREAM_ERROR (-2)\n#define Z_DATA_ERROR   (-3)\n#define Z_MEM_ERROR    (-4)\n#define Z_BUF_ERROR    (-5)\n#define Z_VERSION_ERROR (-6)\n/* Return codes for the compression/decompression functions. Negative values\n * are errors, positive values are used for special but normal events.\n */\n\n#define Z_NO_COMPRESSION         0\n#define Z_BEST_SPEED             1\n#define Z_BEST_COMPRESSION       9\n#define Z_DEFAULT_COMPRESSION  (-1)\n/* compression levels */\n\n#define Z_FILTERED            1\n#define Z_HUFFMAN_ONLY        2\n#define Z_RLE                 3\n#define Z_FIXED               4\n#define Z_DEFAULT_STRATEGY    0\n/* compression strategy; see deflateInit2() below for details */\n\n#define Z_BINARY   0\n#define Z_TEXT     1\n#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */\n#define Z_UNKNOWN  2\n/* Possible values of the data_type field for deflate() */\n\n#define Z_DEFLATED   8\n/* The deflate compression method (the only one supported in this version) */\n\n#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */\n\n#define zlib_version zlibVersion()\n/* for compatibility with versions < 1.0.2 */\n\n\n                        /* basic functions */\n\nZEXTERN const char * ZEXPORT zlibVersion OF((void));\n/* The application can compare zlibVersion and ZLIB_VERSION for consistency.\n   If the first character differs, the library code actually used is not\n   compatible with the zlib.h header file used by the application.  This check\n   is automatically made by deflateInit and inflateInit.\n */\n\n/*\nZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));\n\n     Initializes the internal stream state for compression.  The fields\n   zalloc, zfree and opaque must be initialized before by the caller.  If\n   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default\n   allocation functions.\n\n     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:\n   1 gives best speed, 9 gives best compression, 0 gives no compression at all\n   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION\n   requests a default compromise between speed and compression (currently\n   equivalent to level 6).\n\n     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if level is not a valid compression level, or\n   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible\n   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null\n   if there is no error message.  deflateInit does not perform any compression:\n   this will be done by deflate().\n*/\n\n\nZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));\n/*\n    deflate compresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n    The detailed semantics are as follows.  deflate performs one or both of the\n  following actions:\n\n  - Compress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), next_in and avail_in are updated and\n    processing will resume at this point for the next call of deflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  This action is forced if the parameter flush is non zero.\n    Forcing flush frequently degrades the compression ratio, so this parameter\n    should be set only when necessary.  Some output may be provided even if\n    flush is zero.\n\n    Before the call of deflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating avail_in or avail_out accordingly; avail_out should\n  never be zero before the call.  The application can consume the compressed\n  output when it wants, for example when the output buffer is full (avail_out\n  == 0), or after each call of deflate().  If deflate returns Z_OK and with\n  zero avail_out, it must be called again after making room in the output\n  buffer because there might be more output pending. See deflatePending(),\n  which can be used if desired to determine whether or not there is more ouput\n  in that case.\n\n    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to\n  decide how much data to accumulate before producing output, in order to\n  maximize compression.\n\n    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is\n  flushed to the output buffer and the output is aligned on a byte boundary, so\n  that the decompressor can get all input data available so far.  (In\n  particular avail_in is zero after the call if enough output space has been\n  provided before the call.) Flushing may degrade compression for some\n  compression algorithms and so it should be used only when necessary.  This\n  completes the current deflate block and follows it with an empty stored block\n  that is three bits plus filler bits to the next byte, followed by four bytes\n  (00 00 ff ff).\n\n    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the\n  output buffer, but the output is not aligned to a byte boundary.  All of the\n  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.\n  This completes the current deflate block and follows it with an empty fixed\n  codes block that is 10 bits long.  This assures that enough bytes are output\n  in order for the decompressor to finish the block before the empty fixed\n  codes block.\n\n    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as\n  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to\n  seven bits of the current block are held to be written as the next byte after\n  the next deflate block is completed.  In this case, the decompressor may not\n  be provided enough bits at this point in order to complete decompression of\n  the data provided so far to the compressor.  It may need to wait for the next\n  block to be emitted.  This is for advanced applications that need to control\n  the emission of deflate blocks.\n\n    If flush is set to Z_FULL_FLUSH, all output is flushed as with\n  Z_SYNC_FLUSH, and the compression state is reset so that decompression can\n  restart from this point if previous compressed data has been damaged or if\n  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade\n  compression.\n\n    If deflate returns with avail_out == 0, this function must be called again\n  with the same value of the flush parameter and more output space (updated\n  avail_out), until the flush is complete (deflate returns with non-zero\n  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that\n  avail_out is greater than six to avoid repeated flush markers due to\n  avail_out == 0 on return.\n\n    If the parameter flush is set to Z_FINISH, pending input is processed,\n  pending output is flushed and deflate returns with Z_STREAM_END if there was\n  enough output space.  If deflate returns with Z_OK or Z_BUF_ERROR, this\n  function must be called again with Z_FINISH and more output space (updated\n  avail_out) but no more input data, until it returns with Z_STREAM_END or an\n  error.  After deflate has returned Z_STREAM_END, the only possible operations\n  on the stream are deflateReset or deflateEnd.\n\n    Z_FINISH can be used in the first deflate call after deflateInit if all the\n  compression is to be done in a single step.  In order to complete in one\n  call, avail_out must be at least the value returned by deflateBound (see\n  below).  Then deflate is guaranteed to return Z_STREAM_END.  If not enough\n  output space is provided, deflate will not return Z_STREAM_END, and it must\n  be called again as described above.\n\n    deflate() sets strm->adler to the Adler-32 checksum of all input read\n  so far (that is, total_in bytes).  If a gzip stream is being generated, then\n  strm->adler will be the CRC-32 checksum of the input read so far.  (See\n  deflateInit2 below.)\n\n    deflate() may update strm->data_type if it can make a good guess about\n  the input data type (Z_BINARY or Z_TEXT).  If in doubt, the data is\n  considered binary.  This field is only for information purposes and does not\n  affect the compression algorithm in any manner.\n\n    deflate() returns Z_OK if some progress has been made (more input\n  processed or more output produced), Z_STREAM_END if all input has been\n  consumed and all output has been produced (only when flush is set to\n  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example\n  if next_in or next_out was Z_NULL or the state was inadvertently written over\n  by the application), or Z_BUF_ERROR if no progress is possible (for example\n  avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not fatal, and\n  deflate() can be called again with more input and more output space to\n  continue compressing.\n*/\n\n\nZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the\n   stream state was inconsistent, Z_DATA_ERROR if the stream was freed\n   prematurely (some input or output was discarded).  In the error case, msg\n   may be set but then points to a static string (which must not be\n   deallocated).\n*/\n\n\n/*\nZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));\n\n     Initializes the internal stream state for decompression.  The fields\n   next_in, avail_in, zalloc, zfree and opaque must be initialized before by\n   the caller.  In the current version of inflate, the provided input is not\n   read or consumed.  The allocation of a sliding window will be deferred to\n   the first call of inflate (if the decompression does not complete on the\n   first call).  If zalloc and zfree are set to Z_NULL, inflateInit updates\n   them to use default allocation functions.\n\n     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit does not perform any decompression.\n   Actual decompression will be done by inflate().  So next_in, and avail_in,\n   next_out, and avail_out are unused and unchanged.  The current\n   implementation of inflateInit() does not process any header information --\n   that is deferred until inflate() is called.\n*/\n\n\nZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));\n/*\n    inflate decompresses as much data as possible, and stops when the input\n  buffer becomes empty or the output buffer becomes full.  It may introduce\n  some output latency (reading input without producing any output) except when\n  forced to flush.\n\n  The detailed semantics are as follows.  inflate performs one or both of the\n  following actions:\n\n  - Decompress more input starting at next_in and update next_in and avail_in\n    accordingly.  If not all input can be processed (because there is not\n    enough room in the output buffer), then next_in and avail_in are updated\n    accordingly, and processing will resume at this point for the next call of\n    inflate().\n\n  - Generate more output starting at next_out and update next_out and avail_out\n    accordingly.  inflate() provides as much output as possible, until there is\n    no more input data or no more space in the output buffer (see below about\n    the flush parameter).\n\n    Before the call of inflate(), the application should ensure that at least\n  one of the actions is possible, by providing more input and/or consuming more\n  output, and updating the next_* and avail_* values accordingly.  If the\n  caller of inflate() does not provide both available input and available\n  output space, it is possible that there will be no progress made.  The\n  application can consume the uncompressed output when it wants, for example\n  when the output buffer is full (avail_out == 0), or after each call of\n  inflate().  If inflate returns Z_OK and with zero avail_out, it must be\n  called again after making room in the output buffer because there might be\n  more output pending.\n\n    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,\n  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much\n  output as possible to the output buffer.  Z_BLOCK requests that inflate()\n  stop if and when it gets to the next deflate block boundary.  When decoding\n  the zlib or gzip format, this will cause inflate() to return immediately\n  after the header and before the first block.  When doing a raw inflate,\n  inflate() will go ahead and process the first block, and will return when it\n  gets to the end of that block, or when it runs out of data.\n\n    The Z_BLOCK option assists in appending to or combining deflate streams.\n  To assist in this, on return inflate() always sets strm->data_type to the\n  number of unused bits in the last byte taken from strm->next_in, plus 64 if\n  inflate() is currently decoding the last block in the deflate stream, plus\n  128 if inflate() returned immediately after decoding an end-of-block code or\n  decoding the complete header up to just before the first byte of the deflate\n  stream.  The end-of-block will not be indicated until all of the uncompressed\n  data from that block has been written to strm->next_out.  The number of\n  unused bits may in general be greater than seven, except when bit 7 of\n  data_type is set, in which case the number of unused bits will be less than\n  eight.  data_type is set as noted here every time inflate() returns for all\n  flush options, and so can be used to determine the amount of currently\n  consumed input in bits.\n\n    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the\n  end of each deflate block header is reached, before any actual data in that\n  block is decoded.  This allows the caller to determine the length of the\n  deflate block header for later use in random access within a deflate block.\n  256 is added to the value of strm->data_type when inflate() returns\n  immediately after reaching the end of the deflate block header.\n\n    inflate() should normally be called until it returns Z_STREAM_END or an\n  error.  However if all decompression is to be performed in a single step (a\n  single call of inflate), the parameter flush should be set to Z_FINISH.  In\n  this case all pending input is processed and all pending output is flushed;\n  avail_out must be large enough to hold all of the uncompressed data for the\n  operation to complete.  (The size of the uncompressed data may have been\n  saved by the compressor for this purpose.)  The use of Z_FINISH is not\n  required to perform an inflation in one step.  However it may be used to\n  inform inflate that a faster approach can be used for the single inflate()\n  call.  Z_FINISH also informs inflate to not maintain a sliding window if the\n  stream completes, which reduces inflate's memory footprint.  If the stream\n  does not complete, either because not all of the stream is provided or not\n  enough output space is provided, then a sliding window will be allocated and\n  inflate() can be called again to continue the operation as if Z_NO_FLUSH had\n  been used.\n\n     In this implementation, inflate() always flushes as much output as\n  possible to the output buffer, and always uses the faster approach on the\n  first call.  So the effects of the flush parameter in this implementation are\n  on the return value of inflate() as noted below, when inflate() returns early\n  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of\n  memory for a sliding window when Z_FINISH is used.\n\n     If a preset dictionary is needed after this call (see inflateSetDictionary\n  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary\n  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets\n  strm->adler to the Adler-32 checksum of all output produced so far (that is,\n  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described\n  below.  At the end of the stream, inflate() checks that its computed Adler-32\n  checksum is equal to that saved by the compressor and returns Z_STREAM_END\n  only if the checksum is correct.\n\n    inflate() can decompress and check either zlib-wrapped or gzip-wrapped\n  deflate data.  The header type is detected automatically, if requested when\n  initializing with inflateInit2().  Any information contained in the gzip\n  header is not retained unless inflateGetHeader() is used.  When processing\n  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output\n  produced so far.  The CRC-32 is checked against the gzip trailer, as is the\n  uncompressed length, modulo 2^32.\n\n    inflate() returns Z_OK if some progress has been made (more input processed\n  or more output produced), Z_STREAM_END if the end of the compressed data has\n  been reached and all uncompressed output has been produced, Z_NEED_DICT if a\n  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was\n  corrupted (input stream not conforming to the zlib format or incorrect check\n  value, in which case strm->msg points to a string with a more specific\n  error), Z_STREAM_ERROR if the stream structure was inconsistent (for example\n  next_in or next_out was Z_NULL, or the state was inadvertently written over\n  by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR\n  if no progress was possible or if there was not enough room in the output\n  buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and\n  inflate() can be called again with more input and more output space to\n  continue decompressing.  If Z_DATA_ERROR is returned, the application may\n  then call inflateSync() to look for a good compression block if a partial\n  recovery of the data is to be attempted.\n*/\n\n\nZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));\n/*\n     All dynamically allocated data structures for this stream are freed.\n   This function discards any unprocessed input and does not flush any pending\n   output.\n\n     inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state\n   was inconsistent.\n*/\n\n\n                        /* Advanced functions */\n\n/*\n    The following functions are needed only in some special applications.\n*/\n\n/*\nZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,\n                                     int  level,\n                                     int  method,\n                                     int  windowBits,\n                                     int  memLevel,\n                                     int  strategy));\n\n     This is another version of deflateInit with more compression options.  The\n   fields next_in, zalloc, zfree and opaque must be initialized before by the\n   caller.\n\n     The method parameter is the compression method.  It must be Z_DEFLATED in\n   this version of the library.\n\n     The windowBits parameter is the base two logarithm of the window size\n   (the size of the history buffer).  It should be in the range 8..15 for this\n   version of the library.  Larger values of this parameter result in better\n   compression at the expense of memory usage.  The default value is 15 if\n   deflateInit is used instead.\n\n     For the current implementation of deflate(), a windowBits value of 8 (a\n   window size of 256 bytes) is not supported.  As a result, a request for 8\n   will result in 9 (a 512-byte window).  In that case, providing 8 to\n   inflateInit2() will result in an error when the zlib header with 9 is\n   checked against the initialization of inflate().  The remedy is to not use 8\n   with deflateInit2() with this initialization, or at least in that case use 9\n   with inflateInit2().\n\n     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits\n   determines the window size.  deflate() will then generate raw deflate data\n   with no zlib header or trailer, and will not compute a check value.\n\n     windowBits can also be greater than 15 for optional gzip encoding.  Add\n   16 to windowBits to write a simple gzip header and trailer around the\n   compressed data instead of a zlib wrapper.  The gzip header will have no\n   file name, no extra data, no comment, no modification time (set to zero), no\n   header crc, and the operating system will be set to the appropriate value,\n   if the operating system was determined at compile time.  If a gzip stream is\n   being written, strm->adler is a CRC-32 instead of an Adler-32.\n\n     For raw deflate or gzip encoding, a request for a 256-byte window is\n   rejected as invalid, since only the zlib header provides a means of\n   transmitting the window size to the decompressor.\n\n     The memLevel parameter specifies how much memory should be allocated\n   for the internal compression state.  memLevel=1 uses minimum memory but is\n   slow and reduces compression ratio; memLevel=9 uses maximum memory for\n   optimal speed.  The default value is 8.  See zconf.h for total memory usage\n   as a function of windowBits and memLevel.\n\n     The strategy parameter is used to tune the compression algorithm.  Use the\n   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a\n   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no\n   string match), or Z_RLE to limit match distances to one (run-length\n   encoding).  Filtered data consists mostly of small values with a somewhat\n   random distribution.  In this case, the compression algorithm is tuned to\n   compress them better.  The effect of Z_FILTERED is to force more Huffman\n   coding and less string matching; it is somewhat intermediate between\n   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as\n   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The\n   strategy parameter only affects the compression ratio but not the\n   correctness of the compressed output even if it is not set appropriately.\n   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler\n   decoder for special applications.\n\n     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid\n   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is\n   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is\n   set to null if there is no error message.  deflateInit2 does not perform any\n   compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength));\n/*\n     Initializes the compression dictionary from the given byte sequence\n   without producing any compressed output.  When using the zlib format, this\n   function must be called immediately after deflateInit, deflateInit2 or\n   deflateReset, and before any call of deflate.  When doing raw deflate, this\n   function must be called either before any call of deflate, or immediately\n   after the completion of a deflate block, i.e. after all input has been\n   consumed and all output has been delivered when using any of the flush\n   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The\n   compressor and decompressor must use exactly the same dictionary (see\n   inflateSetDictionary).\n\n     The dictionary should consist of strings (byte sequences) that are likely\n   to be encountered later in the data to be compressed, with the most commonly\n   used strings preferably put towards the end of the dictionary.  Using a\n   dictionary is most useful when the data to be compressed is short and can be\n   predicted with good accuracy; the data can then be compressed better than\n   with the default empty dictionary.\n\n     Depending on the size of the compression data structures selected by\n   deflateInit or deflateInit2, a part of the dictionary may in effect be\n   discarded, for example if the dictionary is larger than the window size\n   provided in deflateInit or deflateInit2.  Thus the strings most likely to be\n   useful should be put at the end of the dictionary, not at the front.  In\n   addition, the current implementation of deflate will use at most the window\n   size minus 262 bytes of the provided dictionary.\n\n     Upon return of this function, strm->adler is set to the Adler-32 value\n   of the dictionary; the decompressor may later use this value to determine\n   which dictionary has been used by the compressor.  (The Adler-32 value\n   applies to the whole dictionary even if only a subset of the dictionary is\n   actually used by the compressor.) If a raw deflate was requested, then the\n   Adler-32 value is not computed and strm->adler is not set.\n\n     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent (for example if deflate has already been called for this stream\n   or if not at a block boundary for raw deflate).  deflateSetDictionary does\n   not perform any compression: this will be done by deflate().\n*/\n\nZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,\n                                             Bytef *dictionary,\n                                             uInt  *dictLength));\n/*\n     Returns the sliding dictionary being maintained by deflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If deflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similary, if dictLength is Z_NULL, then it is not set.\n\n     deflateGetDictionary() may return a length less than the window size, even\n   when more than the window size in input has been provided. It may return up\n   to 258 bytes less in that case, due to how zlib's implementation of deflate\n   manages the sliding window and lookahead for matches, where matches can be\n   up to 258 bytes long. If the application needs the last window-size bytes of\n   input, then that would need to be saved by the application outside of zlib.\n\n     deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,\n                                    z_streamp source));\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when several compression strategies will be\n   tried, for example when there are several ways of pre-processing the input\n   data with a filter.  The streams that will be discarded should then be freed\n   by calling deflateEnd.  Note that deflateCopy duplicates the internal\n   compression state which can be quite large, so this strategy is slow and can\n   consume lots of memory.\n\n     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to deflateEnd followed by deflateInit, but\n   does not free and reallocate the internal compression state.  The stream\n   will leave the compression level and any other attributes that may have been\n   set unchanged.\n\n     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,\n                                      int level,\n                                      int strategy));\n/*\n     Dynamically update the compression level and compression strategy.  The\n   interpretation of level and strategy is as in deflateInit2().  This can be\n   used to switch between compression and straight copy of the input data, or\n   to switch to a different kind of input data requiring a different strategy.\n   If the compression approach (which is a function of the level) or the\n   strategy is changed, and if any input has been consumed in a previous\n   deflate() call, then the input available so far is compressed with the old\n   level and strategy using deflate(strm, Z_BLOCK).  There are three approaches\n   for the compression levels 0, 1..3, and 4..9 respectively.  The new level\n   and strategy will take effect at the next call of deflate().\n\n     If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does\n   not have enough output space to complete, then the parameter change will not\n   take effect.  In this case, deflateParams() can be called again with the\n   same parameters and more output space to try again.\n\n     In order to assure a change in the parameters on the first try, the\n   deflate stream should be flushed using deflate() with Z_BLOCK or other flush\n   request until strm.avail_out is not zero, before calling deflateParams().\n   Then no more input data should be provided before the deflateParams() call.\n   If this is done, the old level and strategy will be applied to the data\n   compressed before deflateParams(), and the new level and strategy will be\n   applied to the the data compressed after deflateParams().\n\n     deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream\n   state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if\n   there was not enough output space to complete the compression of the\n   available input data before a change in the strategy or approach.  Note that\n   in the case of a Z_BUF_ERROR, the parameters are not changed.  A return\n   value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be\n   retried with more output space.\n*/\n\nZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,\n                                    int good_length,\n                                    int max_lazy,\n                                    int nice_length,\n                                    int max_chain));\n/*\n     Fine tune deflate's internal compression parameters.  This should only be\n   used by someone who understands the algorithm used by zlib's deflate for\n   searching for the best matching string, and even then only by the most\n   fanatic optimizer trying to squeeze out the last compressed bit for their\n   specific input data.  Read the deflate.c source code for the meaning of the\n   max_lazy, good_length, nice_length, and max_chain parameters.\n\n     deflateTune() can be called after deflateInit() or deflateInit2(), and\n   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.\n */\n\nZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,\n                                       uLong sourceLen));\n/*\n     deflateBound() returns an upper bound on the compressed size after\n   deflation of sourceLen bytes.  It must be called after deflateInit() or\n   deflateInit2(), and after deflateSetHeader(), if used.  This would be used\n   to allocate an output buffer for deflation in a single pass, and so would be\n   called before deflate().  If that first deflate() call is provided the\n   sourceLen input bytes, an output buffer allocated to the size returned by\n   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed\n   to return Z_STREAM_END.  Note that it is possible for the compressed size to\n   be larger than the value returned by deflateBound() if flush options other\n   than Z_FINISH or Z_NO_FLUSH are used.\n*/\n\nZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,\n                                       unsigned *pending,\n                                       int *bits));\n/*\n     deflatePending() returns the number of bytes and bits of output that have\n   been generated, but not yet provided in the available output.  The bytes not\n   provided would be due to the available output space having being consumed.\n   The number of bits of output not provided are between 0 and 7, where they\n   await more bits to join them in order to fill out a full byte.  If pending\n   or bits are Z_NULL, then those values are not set.\n\n     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n */\n\nZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,\n                                     int bits,\n                                     int value));\n/*\n     deflatePrime() inserts bits in the deflate output stream.  The intent\n   is that this function is used to start off the deflate output with the bits\n   leftover from a previous deflate stream when appending to it.  As such, this\n   function can only be used for raw deflate, and must be used before the first\n   deflate() call after a deflateInit2() or deflateReset().  bits must be less\n   than or equal to 16, and that many of the least significant bits of value\n   will be inserted in the output.\n\n     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough\n   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,\n                                         gz_headerp head));\n/*\n     deflateSetHeader() provides gzip header information for when a gzip\n   stream is requested by deflateInit2().  deflateSetHeader() may be called\n   after deflateInit2() or deflateReset() and before the first call of\n   deflate().  The text, time, os, extra field, name, and comment information\n   in the provided gz_header structure are written to the gzip header (xflag is\n   ignored -- the extra flags are set according to the compression level).  The\n   caller must assure that, if not Z_NULL, name and comment are terminated with\n   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are\n   available there.  If hcrc is true, a gzip header crc is included.  Note that\n   the current versions of the command-line version of gzip (up through version\n   1.3.x) do not support header crc's, and will report that it is a \"multi-part\n   gzip file\" and give up.\n\n     If deflateSetHeader is not used, the default gzip header has text false,\n   the time set to zero, and os set to 255, with no extra, name, or comment\n   fields.  The gzip header is returned to the default state by deflateReset().\n\n     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,\n                                     int  windowBits));\n\n     This is another version of inflateInit with an extra parameter.  The\n   fields next_in, avail_in, zalloc, zfree and opaque must be initialized\n   before by the caller.\n\n     The windowBits parameter is the base two logarithm of the maximum window\n   size (the size of the history buffer).  It should be in the range 8..15 for\n   this version of the library.  The default value is 15 if inflateInit is used\n   instead.  windowBits must be greater than or equal to the windowBits value\n   provided to deflateInit2() while compressing, or it must be equal to 15 if\n   deflateInit2() was not used.  If a compressed stream with a larger window\n   size is given as input, inflate() will return with the error code\n   Z_DATA_ERROR instead of trying to allocate a larger window.\n\n     windowBits can also be zero to request that inflate use the window size in\n   the zlib header of the compressed stream.\n\n     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits\n   determines the window size.  inflate() will then process raw deflate data,\n   not looking for a zlib or gzip header, not generating a check value, and not\n   looking for any check values for comparison at the end of the stream.  This\n   is for use with other formats that use the deflate compressed data format\n   such as zip.  Those formats provide their own check values.  If a custom\n   format is developed using the raw deflate format for compressed data, it is\n   recommended that a check value such as an Adler-32 or a CRC-32 be applied to\n   the uncompressed data as is done in the zlib, gzip, and zip formats.  For\n   most applications, the zlib format should be used as is.  Note that comments\n   above on the use in deflateInit2() applies to the magnitude of windowBits.\n\n     windowBits can also be greater than 15 for optional gzip decoding.  Add\n   32 to windowBits to enable zlib and gzip decoding with automatic header\n   detection, or add 16 to decode only the gzip format (the zlib format will\n   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a\n   CRC-32 instead of an Adler-32.  Unlike the gunzip utility and gzread() (see\n   below), inflate() will not automatically decode concatenated gzip streams.\n   inflate() will return Z_STREAM_END at the end of the gzip stream.  The state\n   would need to be reset to continue decoding a subsequent gzip stream.\n\n     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the\n   version assumed by the caller, or Z_STREAM_ERROR if the parameters are\n   invalid, such as a null pointer to the structure.  msg is set to null if\n   there is no error message.  inflateInit2 does not perform any decompression\n   apart from possibly reading the zlib header if present: actual decompression\n   will be done by inflate().  (So next_in and avail_in may be modified, but\n   next_out and avail_out are unused and unchanged.) The current implementation\n   of inflateInit2() does not process any header information -- that is\n   deferred until inflate() is called.\n*/\n\nZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,\n                                             const Bytef *dictionary,\n                                             uInt  dictLength));\n/*\n     Initializes the decompression dictionary from the given uncompressed byte\n   sequence.  This function must be called immediately after a call of inflate,\n   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor\n   can be determined from the Adler-32 value returned by that call of inflate.\n   The compressor and decompressor must use exactly the same dictionary (see\n   deflateSetDictionary).  For raw inflate, this function can be called at any\n   time to set the dictionary.  If the provided dictionary is smaller than the\n   window and there is already data in the window, then the provided dictionary\n   will amend what's there.  The application must insure that the dictionary\n   that was used for compression is provided.\n\n     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a\n   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is\n   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the\n   expected one (incorrect Adler-32 value).  inflateSetDictionary does not\n   perform any decompression: this will be done by subsequent calls of\n   inflate().\n*/\n\nZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,\n                                             Bytef *dictionary,\n                                             uInt  *dictLength));\n/*\n     Returns the sliding dictionary being maintained by inflate.  dictLength is\n   set to the number of bytes in the dictionary, and that many bytes are copied\n   to dictionary.  dictionary must have enough space, where 32768 bytes is\n   always enough.  If inflateGetDictionary() is called with dictionary equal to\n   Z_NULL, then only the dictionary length is returned, and nothing is copied.\n   Similary, if dictLength is Z_NULL, then it is not set.\n\n     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the\n   stream state is inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));\n/*\n     Skips invalid compressed data until a possible full flush point (see above\n   for the description of deflate with Z_FULL_FLUSH) can be found, or until all\n   available input is skipped.  No output is provided.\n\n     inflateSync searches for a 00 00 FF FF pattern in the compressed data.\n   All full flush points have this pattern, but not all occurrences of this\n   pattern are full flush points.\n\n     inflateSync returns Z_OK if a possible full flush point has been found,\n   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point\n   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.\n   In the success case, the application may save the current current value of\n   total_in which indicates where valid compressed data was found.  In the\n   error case, the application may repeatedly call inflateSync, providing more\n   input each time, until success or end of the input data.\n*/\n\nZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,\n                                    z_streamp source));\n/*\n     Sets the destination stream as a complete copy of the source stream.\n\n     This function can be useful when randomly accessing a large stream.  The\n   first pass through the stream can periodically record the inflate state,\n   allowing restarting inflate at those points when randomly accessing the\n   stream.\n\n     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent\n   (such as zalloc being Z_NULL).  msg is left unchanged in both source and\n   destination.\n*/\n\nZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));\n/*\n     This function is equivalent to inflateEnd followed by inflateInit,\n   but does not free and reallocate the internal decompression state.  The\n   stream will keep attributes that may have been set by inflateInit2.\n\n     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL).\n*/\n\nZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,\n                                      int windowBits));\n/*\n     This function is the same as inflateReset, but it also permits changing\n   the wrap and window size requests.  The windowBits parameter is interpreted\n   the same as it is for inflateInit2.  If the window size is changed, then the\n   memory allocated for the window is freed, and the window will be reallocated\n   by inflate() if needed.\n\n     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent (such as zalloc or state being Z_NULL), or if\n   the windowBits parameter is invalid.\n*/\n\nZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,\n                                     int bits,\n                                     int value));\n/*\n     This function inserts bits in the inflate input stream.  The intent is\n   that this function is used to start inflating at a bit position in the\n   middle of a byte.  The provided bits will be used before any bytes are used\n   from next_in.  This function should only be used with raw inflate, and\n   should be used before the first inflate() call after inflateInit2() or\n   inflateReset().  bits must be less than or equal to 16, and that many of the\n   least significant bits of value will be inserted in the input.\n\n     If bits is negative, then the input stream bit buffer is emptied.  Then\n   inflatePrime() can be called again to put bits in the buffer.  This is used\n   to clear out bits leftover after feeding inflate a block description prior\n   to feeding inflate codes.\n\n     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\nZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));\n/*\n     This function returns two values, one in the lower 16 bits of the return\n   value, and the other in the remaining upper bits, obtained by shifting the\n   return value down 16 bits.  If the upper value is -1 and the lower value is\n   zero, then inflate() is currently decoding information outside of a block.\n   If the upper value is -1 and the lower value is non-zero, then inflate is in\n   the middle of a stored block, with the lower value equaling the number of\n   bytes from the input remaining to copy.  If the upper value is not -1, then\n   it is the number of bits back from the current bit position in the input of\n   the code (literal or length/distance pair) currently being processed.  In\n   that case the lower value is the number of bytes already emitted for that\n   code.\n\n     A code is being processed if inflate is waiting for more input to complete\n   decoding of the code, or if it has completed decoding but is waiting for\n   more output space to write the literal or match data.\n\n     inflateMark() is used to mark locations in the input data for random\n   access, which may be at bit positions, and to note those cases where the\n   output of a code may span boundaries of random access blocks.  The current\n   location in the input stream can be determined from avail_in and data_type\n   as noted in the description for the Z_BLOCK flush parameter for inflate.\n\n     inflateMark returns the value noted above, or -65536 if the provided\n   source stream state was inconsistent.\n*/\n\nZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,\n                                         gz_headerp head));\n/*\n     inflateGetHeader() requests that gzip header information be stored in the\n   provided gz_header structure.  inflateGetHeader() may be called after\n   inflateInit2() or inflateReset(), and before the first call of inflate().\n   As inflate() processes the gzip stream, head->done is zero until the header\n   is completed, at which time head->done is set to one.  If a zlib stream is\n   being decoded, then head->done is set to -1 to indicate that there will be\n   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be\n   used to force inflate() to return immediately after header processing is\n   complete and before any actual data is decompressed.\n\n     The text, time, xflags, and os fields are filled in with the gzip header\n   contents.  hcrc is set to true if there is a header CRC.  (The header CRC\n   was valid if done is set to one.) If extra is not Z_NULL, then extra_max\n   contains the maximum number of bytes to write to extra.  Once done is true,\n   extra_len contains the actual extra field length, and extra contains the\n   extra field, or that field truncated if extra_max is less than extra_len.\n   If name is not Z_NULL, then up to name_max characters are written there,\n   terminated with a zero unless the length is greater than name_max.  If\n   comment is not Z_NULL, then up to comm_max characters are written there,\n   terminated with a zero unless the length is greater than comm_max.  When any\n   of extra, name, or comment are not Z_NULL and the respective field is not\n   present in the header, then that field is set to Z_NULL to signal its\n   absence.  This allows the use of deflateSetHeader() with the returned\n   structure to duplicate the header.  However if those fields are set to\n   allocated memory, then the application will need to save those pointers\n   elsewhere so that they can be eventually freed.\n\n     If inflateGetHeader is not used, then the header information is simply\n   discarded.  The header is always checked for validity, including the header\n   CRC if present.  inflateReset() will reset the process to discard the header\n   information.  The application would need to call inflateGetHeader() again to\n   retrieve the header from the next gzip stream.\n\n     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source\n   stream state was inconsistent.\n*/\n\n/*\nZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,\n                                        unsigned char FAR *window));\n\n     Initialize the internal stream state for decompression using inflateBack()\n   calls.  The fields zalloc, zfree and opaque in strm must be initialized\n   before the call.  If zalloc and zfree are Z_NULL, then the default library-\n   derived memory allocation routines are used.  windowBits is the base two\n   logarithm of the window size, in the range 8..15.  window is a caller\n   supplied buffer of that size.  Except for special applications where it is\n   assured that deflate was used with small window sizes, windowBits must be 15\n   and a 32K byte window must be supplied to be able to decompress general\n   deflate streams.\n\n     See inflateBack() for the usage of these routines.\n\n     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of\n   the parameters are invalid, Z_MEM_ERROR if the internal state could not be\n   allocated, or Z_VERSION_ERROR if the version of the library does not match\n   the version of the header file.\n*/\n\ntypedef unsigned (*in_func) OF((void FAR *,\n                                z_const unsigned char FAR * FAR *));\ntypedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));\n\nZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,\n                                    in_func in, void FAR *in_desc,\n                                    out_func out, void FAR *out_desc));\n/*\n     inflateBack() does a raw inflate with a single call using a call-back\n   interface for input and output.  This is potentially more efficient than\n   inflate() for file i/o applications, in that it avoids copying between the\n   output and the sliding window by simply making the window itself the output\n   buffer.  inflate() can be faster on modern CPUs when used with large\n   buffers.  inflateBack() trusts the application to not change the output\n   buffer passed by the output function, at least until inflateBack() returns.\n\n     inflateBackInit() must be called first to allocate the internal state\n   and to initialize the state with the user-provided window buffer.\n   inflateBack() may then be used multiple times to inflate a complete, raw\n   deflate stream with each call.  inflateBackEnd() is then called to free the\n   allocated state.\n\n     A raw deflate stream is one with no zlib or gzip header or trailer.\n   This routine would normally be used in a utility that reads zip or gzip\n   files and writes out uncompressed files.  The utility would decode the\n   header and process the trailer on its own, hence this routine expects only\n   the raw deflate stream to decompress.  This is different from the default\n   behavior of inflate(), which expects a zlib header and trailer around the\n   deflate stream.\n\n     inflateBack() uses two subroutines supplied by the caller that are then\n   called by inflateBack() for input and output.  inflateBack() calls those\n   routines until it reads a complete deflate stream and writes out all of the\n   uncompressed data, or until it encounters an error.  The function's\n   parameters and return types are defined above in the in_func and out_func\n   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the\n   number of bytes of provided input, and a pointer to that input in buf.  If\n   there is no input available, in() must return zero -- buf is ignored in that\n   case -- and inflateBack() will return a buffer error.  inflateBack() will\n   call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].\n   out() should return zero on success, or non-zero on failure.  If out()\n   returns non-zero, inflateBack() will return with an error.  Neither in() nor\n   out() are permitted to change the contents of the window provided to\n   inflateBackInit(), which is also the buffer that out() uses to write from.\n   The length written by out() will be at most the window size.  Any non-zero\n   amount of input may be provided by in().\n\n     For convenience, inflateBack() can be provided input on the first call by\n   setting strm->next_in and strm->avail_in.  If that input is exhausted, then\n   in() will be called.  Therefore strm->next_in must be initialized before\n   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called\n   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in\n   must also be initialized, and then if strm->avail_in is not zero, input will\n   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].\n\n     The in_desc and out_desc parameters of inflateBack() is passed as the\n   first parameter of in() and out() respectively when they are called.  These\n   descriptors can be optionally used to pass any information that the caller-\n   supplied in() and out() functions need to do their job.\n\n     On return, inflateBack() will set strm->next_in and strm->avail_in to\n   pass back any unused input that was provided by the last in() call.  The\n   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR\n   if in() or out() returned an error, Z_DATA_ERROR if there was a format error\n   in the deflate stream (in which case strm->msg is set to indicate the nature\n   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.\n   In the case of Z_BUF_ERROR, an input or output error can be distinguished\n   using strm->next_in which will be Z_NULL only if in() returned an error.  If\n   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning\n   non-zero.  (in() will always be called before out(), so strm->next_in is\n   assured to be defined if out() returns non-zero.)  Note that inflateBack()\n   cannot return Z_OK.\n*/\n\nZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));\n/*\n     All memory allocated by inflateBackInit() is freed.\n\n     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream\n   state was inconsistent.\n*/\n\nZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));\n/* Return flags indicating compile-time options.\n\n    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:\n     1.0: size of uInt\n     3.2: size of uLong\n     5.4: size of voidpf (pointer)\n     7.6: size of z_off_t\n\n    Compiler, assembler, and debug options:\n     8: ZLIB_DEBUG\n     9: ASMV or ASMINF -- use ASM code\n     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention\n     11: 0 (reserved)\n\n    One-time table building (smaller code, but not thread-safe if true):\n     12: BUILDFIXED -- build static block decoding tables when needed\n     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed\n     14,15: 0 (reserved)\n\n    Library content (indicates missing functionality):\n     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking\n                          deflate code when not needed)\n     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect\n                    and decode gzip streams (to avoid linking crc code)\n     18-19: 0 (reserved)\n\n    Operation variations (changes in library functionality):\n     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate\n     21: FASTEST -- deflate algorithm with only one, lowest compression level\n     22,23: 0 (reserved)\n\n    The sprintf variant used by gzprintf (zero is best):\n     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format\n     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!\n     26: 0 = returns value, 1 = void -- 1 means inferred string length returned\n\n    Remainder:\n     27-31: 0 (reserved)\n */\n\n#ifndef Z_SOLO\n\n                        /* utility functions */\n\n/*\n     The following utility functions are implemented on top of the basic\n   stream-oriented functions.  To simplify the interface, some default options\n   are assumed (compression level and memory usage, standard memory allocation\n   functions).  The source code of these utility functions can be modified if\n   you need special options.\n*/\n\nZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,\n                                 const Bytef *source, uLong sourceLen));\n/*\n     Compresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.  compress() is equivalent to compress2() with a level\n   parameter of Z_DEFAULT_COMPRESSION.\n\n     compress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer.\n*/\n\nZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,\n                                  const Bytef *source, uLong sourceLen,\n                                  int level));\n/*\n     Compresses the source buffer into the destination buffer.  The level\n   parameter has the same meaning as in deflateInit.  sourceLen is the byte\n   length of the source buffer.  Upon entry, destLen is the total size of the\n   destination buffer, which must be at least the value returned by\n   compressBound(sourceLen).  Upon exit, destLen is the actual size of the\n   compressed data.\n\n     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough\n   memory, Z_BUF_ERROR if there was not enough room in the output buffer,\n   Z_STREAM_ERROR if the level parameter is invalid.\n*/\n\nZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));\n/*\n     compressBound() returns an upper bound on the compressed size after\n   compress() or compress2() on sourceLen bytes.  It would be used before a\n   compress() or compress2() call to allocate the destination buffer.\n*/\n\nZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,\n                                   const Bytef *source, uLong sourceLen));\n/*\n     Decompresses the source buffer into the destination buffer.  sourceLen is\n   the byte length of the source buffer.  Upon entry, destLen is the total size\n   of the destination buffer, which must be large enough to hold the entire\n   uncompressed data.  (The size of the uncompressed data must have been saved\n   previously by the compressor and transmitted to the decompressor by some\n   mechanism outside the scope of this compression library.) Upon exit, destLen\n   is the actual size of the uncompressed data.\n\n     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not\n   enough memory, Z_BUF_ERROR if there was not enough room in the output\n   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In\n   the case where there is not enough room, uncompress() will fill the output\n   buffer with the uncompressed data up to that point.\n*/\n\nZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest,   uLongf *destLen,\n                                    const Bytef *source, uLong *sourceLen));\n/*\n     Same as uncompress, except that sourceLen is a pointer, where the\n   length of the source is *sourceLen.  On return, *sourceLen is the number of\n   source bytes consumed.\n*/\n\n                        /* gzip file access functions */\n\n/*\n     This library supports reading and writing files in gzip (.gz) format with\n   an interface similar to that of stdio, using the functions that start with\n   \"gz\".  The gzip format is different from the zlib format.  gzip is a gzip\n   wrapper, documented in RFC 1952, wrapped around a deflate stream.\n*/\n\ntypedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */\n\n/*\nZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));\n\n     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as\n   in fopen (\"rb\" or \"wb\") but can also include a compression level (\"wb9\") or\n   a strategy: 'f' for filtered data as in \"wb6f\", 'h' for Huffman-only\n   compression as in \"wb1h\", 'R' for run-length encoding as in \"wb1R\", or 'F'\n   for fixed code compression as in \"wb9F\".  (See the description of\n   deflateInit2 for more information about the strategy parameter.)  'T' will\n   request transparent writing or appending with no compression and not using\n   the gzip format.\n\n     \"a\" can be used instead of \"w\" to request that the gzip stream that will\n   be written be appended to the file.  \"+\" will result in an error, since\n   reading and writing to the same gzip file is not supported.  The addition of\n   \"x\" when writing will create the file exclusively, which fails if the file\n   already exists.  On systems that support it, the addition of \"e\" when\n   reading or writing will set the flag to close the file on an execve() call.\n\n     These functions, as well as gzip, will read and decode a sequence of gzip\n   streams in a file.  The append function of gzopen() can be used to create\n   such a file.  (Also see gzflush() for another way to do this.)  When\n   appending, gzopen does not test whether the file begins with a gzip stream,\n   nor does it look for the end of the gzip streams to begin appending.  gzopen\n   will simply append a gzip stream to the existing file.\n\n     gzopen can be used to read a file which is not in gzip format; in this\n   case gzread will directly read from the file without decompression.  When\n   reading, this will be detected automatically by looking for the magic two-\n   byte gzip header.\n\n     gzopen returns NULL if the file could not be opened, if there was\n   insufficient memory to allocate the gzFile state, or if an invalid mode was\n   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).\n   errno can be checked to determine if the reason gzopen failed was that the\n   file could not be opened.\n*/\n\nZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));\n/*\n     gzdopen associates a gzFile with the file descriptor fd.  File descriptors\n   are obtained from calls like open, dup, creat, pipe or fileno (if the file\n   has been previously opened with fopen).  The mode parameter is as in gzopen.\n\n     The next call of gzclose on the returned gzFile will also close the file\n   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor\n   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,\n   mode);.  The duplicated descriptor should be saved to avoid a leak, since\n   gzdopen does not close fd if it fails.  If you are using fileno() to get the\n   file descriptor from a FILE *, then you will have to use dup() to avoid\n   double-close()ing the file descriptor.  Both gzclose() and fclose() will\n   close the associated file descriptor, so they need to have different file\n   descriptors.\n\n     gzdopen returns NULL if there was insufficient memory to allocate the\n   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not\n   provided, or '+' was provided), or if fd is -1.  The file descriptor is not\n   used until the next gz* read, write, seek, or close operation, so gzdopen\n   will not detect if fd is invalid (unless fd is -1).\n*/\n\nZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));\n/*\n     Set the internal buffer size used by this library's functions.  The\n   default buffer size is 8192 bytes.  This function must be called after\n   gzopen() or gzdopen(), and before any other calls that read or write the\n   file.  The buffer memory allocation is always deferred to the first read or\n   write.  Three times that size in buffer space is allocated.  A larger buffer\n   size of, for example, 64K or 128K bytes will noticeably increase the speed\n   of decompression (reading).\n\n     The new buffer size also affects the maximum length for gzprintf().\n\n     gzbuffer() returns 0 on success, or -1 on failure, such as being called\n   too late.\n*/\n\nZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));\n/*\n     Dynamically update the compression level or strategy.  See the description\n   of deflateInit2 for the meaning of these parameters.  Previously provided\n   data is flushed before the parameter change.\n\n     gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not\n   opened for writing, Z_ERRNO if there is an error writing the flushed data,\n   or Z_MEM_ERROR if there is a memory allocation error.\n*/\n\nZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));\n/*\n     Reads the given number of uncompressed bytes from the compressed file.  If\n   the input file is not in gzip format, gzread copies the given number of\n   bytes into the buffer directly from the file.\n\n     After reaching the end of a gzip stream in the input, gzread will continue\n   to read, looking for another gzip stream.  Any number of gzip streams may be\n   concatenated in the input file, and will all be decompressed by gzread().\n   If something other than a gzip stream is encountered after a gzip stream,\n   that remaining trailing garbage is ignored (and no error is returned).\n\n     gzread can be used to read a gzip file that is being concurrently written.\n   Upon reaching the end of the input, gzread will return with the available\n   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then\n   gzclearerr can be used to clear the end of file indicator in order to permit\n   gzread to be tried again.  Z_OK indicates that a gzip stream was completed\n   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the\n   middle of a gzip stream.  Note that gzread does not return -1 in the event\n   of an incomplete gzip stream.  This error is deferred until gzclose(), which\n   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip\n   stream.  Alternatively, gzerror can be used before gzclose to detect this\n   case.\n\n     gzread returns the number of uncompressed bytes actually read, less than\n   len for end of file, or -1 for error.  If len is too large to fit in an int,\n   then nothing is read, -1 is returned, and the error state is set to\n   Z_STREAM_ERROR.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,\n                                     gzFile file));\n/*\n     Read up to nitems items of size size from file to buf, otherwise operating\n   as gzread() does.  This duplicates the interface of stdio's fread(), with\n   size_t request and return types.  If the library defines size_t, then\n   z_size_t is identical to size_t.  If not, then z_size_t is an unsigned\n   integer type that can contain a pointer.\n\n     gzfread() returns the number of full items read of size size, or zero if\n   the end of the file was reached and a full item could not be read, or if\n   there was an error.  gzerror() must be consulted if zero is returned in\n   order to determine if there was an error.  If the multiplication of size and\n   nitems overflows, i.e. the product does not fit in a z_size_t, then nothing\n   is read, zero is returned, and the error state is set to Z_STREAM_ERROR.\n\n     In the event that the end of file is reached and only a partial item is\n   available at the end, i.e. the remaining uncompressed data length is not a\n   multiple of size, then the final partial item is nevetheless read into buf\n   and the end-of-file flag is set.  The length of the partial item read is not\n   provided, but could be inferred from the result of gztell().  This behavior\n   is the same as the behavior of fread() implementations in common libraries,\n   but it prevents the direct use of gzfread() to read a concurrently written\n   file, reseting and retrying on end-of-file, when size is not 1.\n*/\n\nZEXTERN int ZEXPORT gzwrite OF((gzFile file,\n                                voidpc buf, unsigned len));\n/*\n     Writes the given number of uncompressed bytes into the compressed file.\n   gzwrite returns the number of uncompressed bytes written or 0 in case of\n   error.\n*/\n\nZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,\n                                      z_size_t nitems, gzFile file));\n/*\n     gzfwrite() writes nitems items of size size from buf to file, duplicating\n   the interface of stdio's fwrite(), with size_t request and return types.  If\n   the library defines size_t, then z_size_t is identical to size_t.  If not,\n   then z_size_t is an unsigned integer type that can contain a pointer.\n\n     gzfwrite() returns the number of full items written of size size, or zero\n   if there was an error.  If the multiplication of size and nitems overflows,\n   i.e. the product does not fit in a z_size_t, then nothing is written, zero\n   is returned, and the error state is set to Z_STREAM_ERROR.\n*/\n\nZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));\n/*\n     Converts, formats, and writes the arguments to the compressed file under\n   control of the format string, as in fprintf.  gzprintf returns the number of\n   uncompressed bytes actually written, or a negative zlib error code in case\n   of error.  The number of uncompressed bytes written is limited to 8191, or\n   one less than the buffer size given to gzbuffer().  The caller should assure\n   that this limit is not exceeded.  If it is exceeded, then gzprintf() will\n   return an error (0) with nothing written.  In this case, there may also be a\n   buffer overflow with unpredictable consequences, which is possible only if\n   zlib was compiled with the insecure functions sprintf() or vsprintf()\n   because the secure snprintf() or vsnprintf() functions were not available.\n   This can be determined using zlibCompileFlags().\n*/\n\nZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));\n/*\n     Writes the given null-terminated string to the compressed file, excluding\n   the terminating null character.\n\n     gzputs returns the number of characters written, or -1 in case of error.\n*/\n\nZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));\n/*\n     Reads bytes from the compressed file until len-1 characters are read, or a\n   newline character is read and transferred to buf, or an end-of-file\n   condition is encountered.  If any characters are read or if len == 1, the\n   string is terminated with a null character.  If no characters are read due\n   to an end-of-file or len < 1, then the buffer is left untouched.\n\n     gzgets returns buf which is a null-terminated string, or it returns NULL\n   for end-of-file or in case of error.  If there was an error, the contents at\n   buf are indeterminate.\n*/\n\nZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));\n/*\n     Writes c, converted to an unsigned char, into the compressed file.  gzputc\n   returns the value that was written, or -1 in case of error.\n*/\n\nZEXTERN int ZEXPORT gzgetc OF((gzFile file));\n/*\n     Reads one byte from the compressed file.  gzgetc returns this byte or -1\n   in case of end of file or error.  This is implemented as a macro for speed.\n   As such, it does not do all of the checking the other functions do.  I.e.\n   it does not check to see if file is NULL, nor whether the structure file\n   points to has been clobbered or not.\n*/\n\nZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));\n/*\n     Push one character back onto the stream to be read as the first character\n   on the next read.  At least one character of push-back is allowed.\n   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will\n   fail if c is -1, and may fail if a character has been pushed but not read\n   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the\n   output buffer size of pushed characters is allowed.  (See gzbuffer above.)\n   The pushed character will be discarded if the stream is repositioned with\n   gzseek() or gzrewind().\n*/\n\nZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));\n/*\n     Flushes all pending output into the compressed file.  The parameter flush\n   is as in the deflate() function.  The return value is the zlib error number\n   (see function gzerror below).  gzflush is only permitted when writing.\n\n     If the flush parameter is Z_FINISH, the remaining data is written and the\n   gzip stream is completed in the output.  If gzwrite() is called again, a new\n   gzip stream will be started in the output.  gzread() is able to read such\n   concatenated gzip streams.\n\n     gzflush should be called only when strictly necessary because it will\n   degrade compression if called too often.\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,\n                                   z_off_t offset, int whence));\n\n     Sets the starting position for the next gzread or gzwrite on the given\n   compressed file.  The offset represents a number of bytes in the\n   uncompressed data stream.  The whence parameter is defined as in lseek(2);\n   the value SEEK_END is not supported.\n\n     If the file is opened for reading, this function is emulated but can be\n   extremely slow.  If the file is opened for writing, only forward seeks are\n   supported; gzseek then compresses a sequence of zeroes up to the new\n   starting position.\n\n     gzseek returns the resulting offset location as measured in bytes from\n   the beginning of the uncompressed stream, or -1 in case of error, in\n   particular if the file is opened for writing and the new starting position\n   would be before the current position.\n*/\n\nZEXTERN int ZEXPORT    gzrewind OF((gzFile file));\n/*\n     Rewinds the given file. This function is supported only for reading.\n\n     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));\n\n     Returns the starting position for the next gzread or gzwrite on the given\n   compressed file.  This position represents a number of bytes in the\n   uncompressed data stream, and is zero when starting, even if appending or\n   reading a gzip stream from the middle of a file using gzdopen().\n\n     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)\n*/\n\n/*\nZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));\n\n     Returns the current offset in the file being read or written.  This offset\n   includes the count of bytes that precede the gzip stream, for example when\n   appending or when using gzdopen() for reading.  When reading, the offset\n   does not include as yet unused buffered input.  This information can be used\n   for a progress indicator.  On error, gzoffset() returns -1.\n*/\n\nZEXTERN int ZEXPORT gzeof OF((gzFile file));\n/*\n     Returns true (1) if the end-of-file indicator has been set while reading,\n   false (0) otherwise.  Note that the end-of-file indicator is set only if the\n   read tried to go past the end of the input, but came up short.  Therefore,\n   just like feof(), gzeof() may return false even if there is no more data to\n   read, in the event that the last read request was for the exact number of\n   bytes remaining in the input file.  This will happen if the input file size\n   is an exact multiple of the buffer size.\n\n     If gzeof() returns true, then the read functions will return no more data,\n   unless the end-of-file indicator is reset by gzclearerr() and the input file\n   has grown since the previous end of file was detected.\n*/\n\nZEXTERN int ZEXPORT gzdirect OF((gzFile file));\n/*\n     Returns true (1) if file is being copied directly while reading, or false\n   (0) if file is a gzip stream being decompressed.\n\n     If the input file is empty, gzdirect() will return true, since the input\n   does not contain a gzip stream.\n\n     If gzdirect() is used immediately after gzopen() or gzdopen() it will\n   cause buffers to be allocated to allow reading the file to determine if it\n   is a gzip file.  Therefore if gzbuffer() is used, it should be called before\n   gzdirect().\n\n     When writing, gzdirect() returns true (1) if transparent writing was\n   requested (\"wT\" for the gzopen() mode), or false (0) otherwise.  (Note:\n   gzdirect() is not needed when writing.  Transparent writing must be\n   explicitly requested, so the application already knows the answer.  When\n   linking statically, using gzdirect() will include all of the zlib code for\n   gzip file reading and decompression, which may not be desired.)\n*/\n\nZEXTERN int ZEXPORT    gzclose OF((gzFile file));\n/*\n     Flushes all pending output if necessary, closes the compressed file and\n   deallocates the (de)compression state.  Note that once file is closed, you\n   cannot call gzerror with file, since its structures have been deallocated.\n   gzclose must not be called more than once on the same file, just as free\n   must not be called more than once on the same allocation.\n\n     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a\n   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the\n   last read ended in the middle of a gzip stream, or Z_OK on success.\n*/\n\nZEXTERN int ZEXPORT gzclose_r OF((gzFile file));\nZEXTERN int ZEXPORT gzclose_w OF((gzFile file));\n/*\n     Same as gzclose(), but gzclose_r() is only for use when reading, and\n   gzclose_w() is only for use when writing or appending.  The advantage to\n   using these instead of gzclose() is that they avoid linking in zlib\n   compression or decompression code that is not used when only reading or only\n   writing respectively.  If gzclose() is used, then both compression and\n   decompression code will be included the application when linking to a static\n   zlib library.\n*/\n\nZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));\n/*\n     Returns the error message for the last error which occurred on the given\n   compressed file.  errnum is set to zlib error number.  If an error occurred\n   in the file system and not in the compression library, errnum is set to\n   Z_ERRNO and the application may consult errno to get the exact error code.\n\n     The application must not modify the returned string.  Future calls to\n   this function may invalidate the previously returned string.  If file is\n   closed, then the string previously returned by gzerror will no longer be\n   available.\n\n     gzerror() should be used to distinguish errors from end-of-file for those\n   functions above that do not distinguish those cases in their return values.\n*/\n\nZEXTERN void ZEXPORT gzclearerr OF((gzFile file));\n/*\n     Clears the error and end-of-file flags for file.  This is analogous to the\n   clearerr() function in stdio.  This is useful for continuing to read a gzip\n   file that is being written concurrently.\n*/\n\n#endif /* !Z_SOLO */\n\n                        /* checksum functions */\n\n/*\n     These functions are not related to compression but are exported\n   anyway because they might be useful in applications using the compression\n   library.\n*/\n\nZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));\n/*\n     Update a running Adler-32 checksum with the bytes buf[0..len-1] and\n   return the updated checksum.  If buf is Z_NULL, this function returns the\n   required initial value for the checksum.\n\n     An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed\n   much faster.\n\n   Usage example:\n\n     uLong adler = adler32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       adler = adler32(adler, buffer, length);\n     }\n     if (adler != original_adler) error();\n*/\n\nZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,\n                                    z_size_t len));\n/*\n     Same as adler32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,\n                                          z_off_t len2));\n\n     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1\n   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for\n   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of\n   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note\n   that the z_off_t type (like off_t) is a signed integer.  If len2 is\n   negative, the result has no meaning or utility.\n*/\n\nZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));\n/*\n     Update a running CRC-32 with the bytes buf[0..len-1] and return the\n   updated CRC-32.  If buf is Z_NULL, this function returns the required\n   initial value for the crc.  Pre- and post-conditioning (one's complement) is\n   performed within this function so it shouldn't be done by the application.\n\n   Usage example:\n\n     uLong crc = crc32(0L, Z_NULL, 0);\n\n     while (read_buffer(buffer, length) != EOF) {\n       crc = crc32(crc, buffer, length);\n     }\n     if (crc != original_crc) error();\n*/\n\nZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,\n                                  z_size_t len));\n/*\n     Same as crc32(), but with a size_t length.\n*/\n\n/*\nZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));\n\n     Combine two CRC-32 check values into one.  For two sequences of bytes,\n   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were\n   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32\n   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and\n   len2.\n*/\n\n\n                        /* various hacks, don't look :) */\n\n/* deflateInit and inflateInit are macros to allow checking the zlib version\n * and the compiler's view of z_stream:\n */\nZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,\n                                     const char *version, int stream_size));\nZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,\n                                     const char *version, int stream_size));\nZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,\n                                      int windowBits, int memLevel,\n                                      int strategy, const char *version,\n                                      int stream_size));\nZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,\n                                      const char *version, int stream_size));\nZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,\n                                         unsigned char FAR *window,\n                                         const char *version,\n                                         int stream_size));\n#ifdef Z_PREFIX_SET\n#  define z_deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define z_inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define z_inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#else\n#  define deflateInit(strm, level) \\\n          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit(strm) \\\n          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \\\n          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\\\n                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))\n#  define inflateInit2(strm, windowBits) \\\n          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \\\n                        (int)sizeof(z_stream))\n#  define inflateBackInit(strm, windowBits, window) \\\n          inflateBackInit_((strm), (windowBits), (window), \\\n                           ZLIB_VERSION, (int)sizeof(z_stream))\n#endif\n\n#ifndef Z_SOLO\n\n/* gzgetc() macro and its supporting function and exposed data structure.  Note\n * that the real internal state is much larger than the exposed structure.\n * This abbreviated structure exposes just enough for the gzgetc() macro.  The\n * user should not mess with these exposed elements, since their names or\n * behavior could change in the future, perhaps even capriciously.  They can\n * only be used by the gzgetc() macro.  You have been warned.\n */\nstruct gzFile_s {\n    unsigned have;\n    unsigned char *next;\n    z_off64_t pos;\n};\nZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */\n#ifdef Z_PREFIX_SET\n#  undef z_gzgetc\n#  define z_gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#else\n#  define gzgetc(g) \\\n          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))\n#endif\n\n/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or\n * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if\n * both are true, the application gets the *64 functions, and the regular\n * functions are changed to 64 bits) -- in case these are set on systems\n * without large file support, _LFS64_LARGEFILE must also be true\n */\n#ifdef Z_LARGE64\n   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));\n   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));\n   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));\n   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));\n   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));\n#endif\n\n#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)\n#  ifdef Z_PREFIX_SET\n#    define z_gzopen z_gzopen64\n#    define z_gzseek z_gzseek64\n#    define z_gztell z_gztell64\n#    define z_gzoffset z_gzoffset64\n#    define z_adler32_combine z_adler32_combine64\n#    define z_crc32_combine z_crc32_combine64\n#  else\n#    define gzopen gzopen64\n#    define gzseek gzseek64\n#    define gztell gztell64\n#    define gzoffset gzoffset64\n#    define adler32_combine adler32_combine64\n#    define crc32_combine crc32_combine64\n#  endif\n#  ifndef Z_LARGE64\n     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));\n     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));\n     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));\n     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));\n     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));\n     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));\n#  endif\n#else\n   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));\n   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));\n   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));\n   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));\n   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));\n   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));\n#endif\n\n#else /* Z_SOLO */\n\n   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));\n   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));\n\n#endif /* !Z_SOLO */\n\n/* undocumented functions */\nZEXTERN const char   * ZEXPORT zError           OF((int));\nZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));\nZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));\nZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));\nZEXTERN int            ZEXPORT inflateValidate OF((z_streamp, int));\nZEXTERN unsigned long  ZEXPORT inflateCodesUsed OF ((z_streamp));\nZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));\nZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));\n#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)\nZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,\n                                            const char *mode));\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifndef Z_SOLO\nZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,\n                                                  const char *format,\n                                                  va_list va));\n#  endif\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* ZLIB_H */\n"
  },
  {
    "path": "dlib/external/zlib/zutil.c",
    "content": "/* zutil.c -- target dependent utility functions for the compression library\n * Copyright (C) 1995-2017 Jean-loup Gailly\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* @(#) $Id$ */\n\n#include \"zutil.h\"\n#ifndef Z_SOLO\n#  include \"gzguts.h\"\n#endif\n\nz_const char * const z_errmsg[10] = {\n    (z_const char *)\"need dictionary\",     /* Z_NEED_DICT       2  */\n    (z_const char *)\"stream end\",          /* Z_STREAM_END      1  */\n    (z_const char *)\"\",                    /* Z_OK              0  */\n    (z_const char *)\"file error\",          /* Z_ERRNO         (-1) */\n    (z_const char *)\"stream error\",        /* Z_STREAM_ERROR  (-2) */\n    (z_const char *)\"data error\",          /* Z_DATA_ERROR    (-3) */\n    (z_const char *)\"insufficient memory\", /* Z_MEM_ERROR     (-4) */\n    (z_const char *)\"buffer error\",        /* Z_BUF_ERROR     (-5) */\n    (z_const char *)\"incompatible version\",/* Z_VERSION_ERROR (-6) */\n    (z_const char *)\"\"\n};\n\n\nconst char * ZEXPORT zlibVersion()\n{\n    return ZLIB_VERSION;\n}\n\nuLong ZEXPORT zlibCompileFlags()\n{\n    uLong flags;\n\n    flags = 0;\n    switch ((int)(sizeof(uInt))) {\n    case 2:     break;\n    case 4:     flags += 1;     break;\n    case 8:     flags += 2;     break;\n    default:    flags += 3;\n    }\n    switch ((int)(sizeof(uLong))) {\n    case 2:     break;\n    case 4:     flags += 1 << 2;        break;\n    case 8:     flags += 2 << 2;        break;\n    default:    flags += 3 << 2;\n    }\n    switch ((int)(sizeof(voidpf))) {\n    case 2:     break;\n    case 4:     flags += 1 << 4;        break;\n    case 8:     flags += 2 << 4;        break;\n    default:    flags += 3 << 4;\n    }\n    switch ((int)(sizeof(z_off_t))) {\n    case 2:     break;\n    case 4:     flags += 1 << 6;        break;\n    case 8:     flags += 2 << 6;        break;\n    default:    flags += 3 << 6;\n    }\n#ifdef ZLIB_DEBUG\n    flags += 1 << 8;\n#endif\n#if defined(ASMV) || defined(ASMINF)\n    flags += 1 << 9;\n#endif\n#ifdef ZLIB_WINAPI\n    flags += 1 << 10;\n#endif\n#ifdef BUILDFIXED\n    flags += 1 << 12;\n#endif\n#ifdef DYNAMIC_CRC_TABLE\n    flags += 1 << 13;\n#endif\n#ifdef NO_GZCOMPRESS\n    flags += 1L << 16;\n#endif\n#ifdef NO_GZIP\n    flags += 1L << 17;\n#endif\n#ifdef PKZIP_BUG_WORKAROUND\n    flags += 1L << 20;\n#endif\n#ifdef FASTEST\n    flags += 1L << 21;\n#endif\n#if defined(STDC) || defined(Z_HAVE_STDARG_H)\n#  ifdef NO_vsnprintf\n    flags += 1L << 25;\n#    ifdef HAS_vsprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_vsnprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#else\n    flags += 1L << 24;\n#  ifdef NO_snprintf\n    flags += 1L << 25;\n#    ifdef HAS_sprintf_void\n    flags += 1L << 26;\n#    endif\n#  else\n#    ifdef HAS_snprintf_void\n    flags += 1L << 26;\n#    endif\n#  endif\n#endif\n    return flags;\n}\n\n#ifdef ZLIB_DEBUG\n#include <stdlib.h>\n#  ifndef verbose\n#    define verbose 0\n#  endif\nint ZLIB_INTERNAL z_verbose = verbose;\n\nvoid ZLIB_INTERNAL z_error (m)\n    char *m;\n{\n    fprintf(stderr, \"%s\\n\", m);\n    exit(1);\n}\n#endif\n\n/* exported to allow conversion of error code to string for compress() and\n * uncompress()\n */\nconst char * ZEXPORT zError(err)\n    int err;\n{\n    return ERR_MSG(err);\n}\n\n#if defined(_WIN32_WCE)\n    /* The Microsoft C Run-Time Library for Windows CE doesn't have\n     * errno.  We define it as a global variable to simplify porting.\n     * Its value is always 0 and should not be used.\n     */\n    int errno = 0;\n#endif\n\n#ifndef HAVE_MEMCPY\n\nvoid ZLIB_INTERNAL zmemcpy(dest, source, len)\n    Bytef* dest;\n    const Bytef* source;\n    uInt  len;\n{\n    if (len == 0) return;\n    do {\n        *dest++ = *source++; /* ??? to be unrolled */\n    } while (--len != 0);\n}\n\nint ZLIB_INTERNAL zmemcmp(s1, s2, len)\n    const Bytef* s1;\n    const Bytef* s2;\n    uInt  len;\n{\n    uInt j;\n\n    for (j = 0; j < len; j++) {\n        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;\n    }\n    return 0;\n}\n\nvoid ZLIB_INTERNAL zmemzero(dest, len)\n    Bytef* dest;\n    uInt  len;\n{\n    if (len == 0) return;\n    do {\n        *dest++ = 0;  /* ??? to be unrolled */\n    } while (--len != 0);\n}\n#endif\n\n#ifndef Z_SOLO\n\n#ifdef SYS16BIT\n\n#ifdef __TURBOC__\n/* Turbo C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n/* Turbo C malloc() does not allow dynamic allocation of 64K bytes\n * and farmalloc(64K) returns a pointer with an offset of 8, so we\n * must fix the pointer. Warning: the pointer must be put back to its\n * original form in order to free it, use zcfree().\n */\n\n#define MAX_PTR 10\n/* 10*64K = 640K */\n\nlocal int next_ptr = 0;\n\ntypedef struct ptr_table_s {\n    voidpf org_ptr;\n    voidpf new_ptr;\n} ptr_table;\n\nlocal ptr_table table[MAX_PTR];\n/* This table is used to remember the original form of pointers\n * to large buffers (64K). Such pointers are normalized with a zero offset.\n * Since MSDOS is not a preemptive multitasking OS, this table is not\n * protected from concurrent access. This hack doesn't work anyway on\n * a protected system like OS/2. Use Microsoft C instead.\n */\n\nvoidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)\n{\n    voidpf buf;\n    ulg bsize = (ulg)items*size;\n\n    (void)opaque;\n\n    /* If we allocate less than 65520 bytes, we assume that farmalloc\n     * will return a usable pointer which doesn't have to be normalized.\n     */\n    if (bsize < 65520L) {\n        buf = farmalloc(bsize);\n        if (*(ush*)&buf != 0) return buf;\n    } else {\n        buf = farmalloc(bsize + 16L);\n    }\n    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;\n    table[next_ptr].org_ptr = buf;\n\n    /* Normalize the pointer to seg:0 */\n    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;\n    *(ush*)&buf = 0;\n    table[next_ptr++].new_ptr = buf;\n    return buf;\n}\n\nvoid ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)\n{\n    int n;\n\n    (void)opaque;\n\n    if (*(ush*)&ptr != 0) { /* object < 64K */\n        farfree(ptr);\n        return;\n    }\n    /* Find the original pointer */\n    for (n = 0; n < next_ptr; n++) {\n        if (ptr != table[n].new_ptr) continue;\n\n        farfree(table[n].org_ptr);\n        while (++n < next_ptr) {\n            table[n-1] = table[n];\n        }\n        next_ptr--;\n        return;\n    }\n    Assert(0, \"zcfree: ptr not found\");\n}\n\n#endif /* __TURBOC__ */\n\n\n#ifdef M_I86\n/* Microsoft C in 16-bit mode */\n\n#  define MY_ZCALLOC\n\n#if (!defined(_MSC_VER) || (_MSC_VER <= 600))\n#  define _halloc  halloc\n#  define _hfree   hfree\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)\n{\n    (void)opaque;\n    return _halloc((long)items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)\n{\n    (void)opaque;\n    _hfree(ptr);\n}\n\n#endif /* M_I86 */\n\n#endif /* SYS16BIT */\n\n\n#ifndef MY_ZCALLOC /* Any system without a special alloc function */\n\n#ifndef STDC\nextern voidp  malloc OF((uInt size));\nextern voidp  calloc OF((uInt items, uInt size));\nextern void   free   OF((voidpf ptr));\n#endif\n\nvoidpf ZLIB_INTERNAL zcalloc (opaque, items, size)\n    voidpf opaque;\n    unsigned items;\n    unsigned size;\n{\n    (void)opaque;\n    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :\n                              (voidpf)calloc(items, size);\n}\n\nvoid ZLIB_INTERNAL zcfree (opaque, ptr)\n    voidpf opaque;\n    voidpf ptr;\n{\n    (void)opaque;\n    free(ptr);\n}\n\n#endif /* MY_ZCALLOC */\n\n#endif /* !Z_SOLO */\n"
  },
  {
    "path": "dlib/external/zlib/zutil.h",
    "content": "/* zutil.h -- internal interface and configuration of the compression library\n * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler\n * For conditions of distribution and use, see copyright notice in zlib.h\n */\n\n/* WARNING: this file should *not* be used by applications. It is\n   part of the implementation of the compression library and is\n   subject to change. Applications should only use zlib.h.\n */\n\n/* @(#) $Id$ */\n\n#ifndef ZUTIL_H\n#define ZUTIL_H\n\n#ifdef HAVE_HIDDEN\n#  define ZLIB_INTERNAL __attribute__((visibility (\"hidden\")))\n#else\n#  define ZLIB_INTERNAL\n#endif\n\n#include \"zlib.h\"\n\n#if defined(STDC) && !defined(Z_SOLO)\n#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))\n#    include <stddef.h>\n#  endif\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n\n#ifdef Z_SOLO\n   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */\n#endif\n\n#ifndef local\n#  define local static\n#endif\n/* since \"static\" is used to mean two completely different things in C, we\n   define \"local\" for the non-static meaning of \"static\", for readability\n   (compile with -Dlocal if your debugger can't find static symbols) */\n\ntypedef unsigned char  uch;\ntypedef uch FAR uchf;\ntypedef unsigned short ush;\ntypedef ush FAR ushf;\ntypedef unsigned long  ulg;\n\nextern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */\n/* (size given to avoid silly warnings with Visual C++) */\n\n#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]\n\n#define ERR_RETURN(strm,err) \\\n  return (strm->msg = ERR_MSG(err), (err))\n/* To be used only when the state is known to be valid */\n\n        /* common constants */\n\n#ifndef DEF_WBITS\n#  define DEF_WBITS MAX_WBITS\n#endif\n/* default windowBits for decompression. MAX_WBITS is for compression only */\n\n#if MAX_MEM_LEVEL >= 8\n#  define DEF_MEM_LEVEL 8\n#else\n#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL\n#endif\n/* default memLevel */\n\n#define STORED_BLOCK 0\n#define STATIC_TREES 1\n#define DYN_TREES    2\n/* The three kinds of block type */\n\n#define MIN_MATCH  3\n#define MAX_MATCH  258\n/* The minimum and maximum match lengths */\n\n#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */\n\n        /* target dependencies */\n\n#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))\n#  define OS_CODE  0x00\n#  ifndef Z_SOLO\n#    if defined(__TURBOC__) || defined(__BORLANDC__)\n#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))\n         /* Allow compilation with ANSI keywords only enabled */\n         void _Cdecl farfree( void *block );\n         void *_Cdecl farmalloc( unsigned long nbytes );\n#      else\n#        include <alloc.h>\n#      endif\n#    else /* MSC or DJGPP */\n#      include <malloc.h>\n#    endif\n#  endif\n#endif\n\n#ifdef AMIGA\n#  define OS_CODE  1\n#endif\n\n#if defined(VAXC) || defined(VMS)\n#  define OS_CODE  2\n#  define F_OPEN(name, mode) \\\n     fopen((name), (mode), \"mbc=60\", \"ctx=stm\", \"rfm=fix\", \"mrs=512\")\n#endif\n\n#ifdef __370__\n#  if __TARGET_LIB__ < 0x20000000\n#    define OS_CODE 4\n#  elif __TARGET_LIB__ < 0x40000000\n#    define OS_CODE 11\n#  else\n#    define OS_CODE 8\n#  endif\n#endif\n\n#if defined(ATARI) || defined(atarist)\n#  define OS_CODE  5\n#endif\n\n#ifdef OS2\n#  define OS_CODE  6\n#  if defined(M_I86) && !defined(Z_SOLO)\n#    include <malloc.h>\n#  endif\n#endif\n\n#if defined(MACOS) || defined(TARGET_OS_MAC)\n#  define OS_CODE  7\n#  ifndef Z_SOLO\n#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os\n#      include <unix.h> /* for fdopen */\n#    else\n#      ifndef fdopen\n#        define fdopen(fd,mode) NULL /* No fdopen() */\n#      endif\n#    endif\n#  endif\n#endif\n\n#ifdef __acorn\n#  define OS_CODE 13\n#endif\n\n#if defined(WIN32) && !defined(__CYGWIN__)\n#  define OS_CODE  10\n#endif\n\n#ifdef _BEOS_\n#  define OS_CODE  16\n#endif\n\n#ifdef __TOS_OS400__\n#  define OS_CODE 18\n#endif\n\n#ifdef __APPLE__\n#  define OS_CODE 19\n#endif\n\n#if defined(_BEOS_) || defined(RISCOS)\n#  define fdopen(fd,mode) NULL /* No fdopen() */\n#endif\n\n#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX\n#  if defined(_WIN32_WCE)\n#    define fdopen(fd,mode) NULL /* No fdopen() */\n#    ifndef _PTRDIFF_T_DEFINED\n       typedef int ptrdiff_t;\n#      define _PTRDIFF_T_DEFINED\n#    endif\n#  else\n#    define fdopen(fd,type)  _fdopen(fd,type)\n#  endif\n#endif\n\n#if defined(__BORLANDC__) && !defined(MSDOS)\n  #pragma warn -8004\n  #pragma warn -8008\n  #pragma warn -8066\n#endif\n\n/* provide prototypes for these when building zlib without LFS */\n#if !defined(_WIN32) && \\\n    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)\n    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));\n    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));\n#endif\n\n        /* common defaults */\n\n#ifndef OS_CODE\n#  define OS_CODE  3     /* assume Unix */\n#endif\n\n#ifndef F_OPEN\n#  define F_OPEN(name, mode) fopen((name), (mode))\n#endif\n\n         /* functions */\n\n#if defined(pyr) || defined(Z_SOLO)\n#  define NO_MEMCPY\n#endif\n#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)\n /* Use our own functions for small and medium model with MSC <= 5.0.\n  * You may have to use the same strategy for Borland C (untested).\n  * The __SC__ check is for Symantec.\n  */\n#  define NO_MEMCPY\n#endif\n#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)\n#  define HAVE_MEMCPY\n#endif\n#ifdef HAVE_MEMCPY\n#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */\n#    define zmemcpy _fmemcpy\n#    define zmemcmp _fmemcmp\n#    define zmemzero(dest, len) _fmemset(dest, 0, len)\n#  else\n#    define zmemcpy memcpy\n#    define zmemcmp memcmp\n#    define zmemzero(dest, len) memset(dest, 0, len)\n#  endif\n#else\n   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));\n   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));\n   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));\n#endif\n\n/* Diagnostic functions */\n#ifdef ZLIB_DEBUG\n#  include <stdio.h>\n   extern int ZLIB_INTERNAL z_verbose;\n   extern void ZLIB_INTERNAL z_error OF((char *m));\n#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}\n#  define Trace(x) {if (z_verbose>=0) fprintf x ;}\n#  define Tracev(x) {if (z_verbose>0) fprintf x ;}\n#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}\n#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}\n#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}\n#else\n#  define Assert(cond,msg)\n#  define Trace(x)\n#  define Tracev(x)\n#  define Tracevv(x)\n#  define Tracec(c,x)\n#  define Tracecv(c,x)\n#endif\n\n#ifndef Z_SOLO\n   voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,\n                                    unsigned size));\n   void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));\n#endif\n\n#define ZALLOC(strm, items, size) \\\n           (*((strm)->zalloc))((strm)->opaque, (items), (size))\n#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))\n#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}\n\n/* Reverse the bytes in a 32-bit value */\n#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \\\n                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))\n\n#endif /* ZUTIL_H */\n"
  },
  {
    "path": "dlib/fft/fft.cpp",
    "content": "#include \"fft.h\"\n\n#ifdef DLIB_USE_MKL_FFT\n#include \"mkl_fft.h\"\n#else\n#include \"kiss_fft.h\"\n#endif\n\nnamespace dlib\n{\n    template<typename T>\n    void fft(const fft_size& dims, const std::complex<T>* in, std::complex<T>* out, bool is_inverse)\n    {\n#ifdef DLIB_USE_MKL_FFT\n        mkl_fft(dims, in, out, is_inverse);\n#else\n        kiss_fft(dims, in, out, is_inverse);\n#endif\n    }\n\n    template<typename T>\n    void fftr(const fft_size& dims, const T* in, std::complex<T>* out)\n    {\n#ifdef DLIB_USE_MKL_FFT\n        mkl_fftr(dims, in, out);\n#else\n        kiss_fftr(dims, in, out);\n#endif\n    }\n\n    template<typename T>\n    void ifftr(const fft_size& dims, const std::complex<T>* in, T* out)\n    {\n#ifdef DLIB_USE_MKL_FFT\n        mkl_ifftr(dims, in, out);\n#else\n        kiss_ifftr(dims, in, out);\n#endif\n    }\n\n    template void fft<float>(const fft_size& dims, const std::complex<float>* in, std::complex<float>* out, bool is_inverse);\n    template void fft<double>(const fft_size& dims, const std::complex<double>* in, std::complex<double>* out, bool is_inverse);\n\n    template void fftr<float>(const fft_size& dims, const float* in, std::complex<float>* out);\n    template void fftr<double>(const fft_size& dims, const double* in, std::complex<double>* out);\n\n    template void ifftr<float>(const fft_size& dims, const std::complex<float>* in, float* out);\n    template void ifftr<double>(const fft_size& dims, const std::complex<double>* in, double* out);\n}"
  },
  {
    "path": "dlib/fft/fft.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FFT_DETAILS_Hh_\n#define DLIB_FFT_DETAILS_Hh_\n\n#include <complex>\n#include \"fft_size.h\"\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    constexpr bool is_power_of_two (\n        const unsigned long n\n    )\n    /*!\n        ensures\n            - returns true if value contains a power of two and false otherwise.  As a\n              special case, we also consider 0 to be a power of two.\n    !*/\n    {\n        return n == 0 ? true : (n & (n - 1)) == 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n   \n    constexpr long fftr_nc_size(\n        long nc\n    )\n    /*!\n        ensures\n            - returns the output dimension of a 1D real FFT\n    !*/\n    {\n        return nc == 0 ? 0 : nc/2+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    constexpr long ifftr_nc_size(\n        long nc\n    )\n    /*!\n        ensures\n            - returns the output dimension of an inverse 1D real FFT\n    !*/\n    {\n        return nc == 0 ? 0 : 2*(nc-1);\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    void fft(const fft_size& dims, const std::complex<T>* in, std::complex<T>* out, bool is_inverse);\n    /*!\n        requires\n            - T must be either float or double\n            - dims represents the dimensions of both `in` and `out`\n            - dims.num_dims() > 0\n        ensures\n            - performs an FFT on `in` and stores the result in `out`.\n            - if `is_inverse` is true, a backward FFT is performed, \n              otherwise a forward FFT is performed.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    void fftr(const fft_size& dims, const T* in, std::complex<T>* out);\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `in`\n            - `in`  has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]}\n            - `out` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - dims.num_dims() > 0\n            - dims.back() must be even\n        ensures\n            - performs a real FFT on `in` and stores the result in `out`.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    void ifftr(const fft_size& dims, const std::complex<T>* in, T* out);\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `out`\n            - `in`  has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - `out` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]}\n            - dims.num_dims() > 0\n            - dims.back() must be even\n        ensures\n            - performs an inverse real FFT on `in` and stores the result in `out`.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif //DLIB_FFT_DETAILS_Hh_"
  },
  {
    "path": "dlib/fft/fft_size.h",
    "content": "#ifndef DLIB_FFT_SIZE_H\n#define DLIB_FFT_SIZE_H\n\n#include <array>\n#include <algorithm>\n#include <numeric>\n#include \"../assert.h\"\n#include \"../hash.h\"\n\nnamespace dlib\n{\n    class fft_size\n    {   \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a container used to store the dimensions of an FFT \n                operation. It is implemented as a stack-based container with an \n                upper bound of 5 dimensions (batch,channels,height,width,depth).\n                All dimensions must be strictly positive.\n         \n                The object is either default constructed, constructed with an \n                initialiser list or with a pair of iterators\n\n                If default-constructed, the object is empty and in an invalid state.\n                That is, FFT functions will throw if attempted to be used with such \n                an object.\n\n                If constructed with an initialiser list L, the object is properly\n                initialised provided:\n                    - L.size() > 0 and L.size() <= 5\n                    - L contains strictly positive values\n         \n                If constructed with a pair of iterators, the behaviour of the \n                constructor is exactly the same as if constructed with an \n                initializer list spanned by those iterators.\n\n                Once the object is constructed, it is immutable.\n        !*/\n    public:\n        using container_type    = std::array<long,5>;\n        using const_reference   = container_type::const_reference;\n        using iterator          = container_type::iterator;\n        using const_iterator    = container_type::const_iterator;\n        \n        fft_size() = default;\n        /*!\n            ensures\n                - *this is properly initialised\n                - num_dims() == 0\n        !*/\n        \n        template<typename ConstIterator>\n        fft_size(ConstIterator dims_begin, ConstIterator dims_end)\n        /*!\n            requires\n                - ConstIterator is const iterator type that points to a long object\n                - std::distance(dims_begin, dims_end) > 0\n                - std::distance(dims_begin, dims_end) <= 5\n                - range contains strictly positive values\n            ensures\n                - *this is properly initialised\n                - num_dims() == std::distance(dims_begin, dims_end)\n                - num_elements() == product of all values in range\n        !*/\n        {\n            const size_t ndims = std::distance(dims_begin, dims_end);\n            DLIB_ASSERT(ndims > 0, \"fft_size objects must be non-empty\");\n            DLIB_ASSERT(ndims <= _dims.size(), \"fft_size objects must have size less than 6\");\n            DLIB_ASSERT(std::find_if(dims_begin, dims_end, [](long dim) {return dim <= 0;}) == dims_end, \"fft_size objects must contain strictly positive values\");\n            \n            std::copy(dims_begin, dims_end, _dims.begin());\n            _size = ndims;\n            _num_elements = std::accumulate(dims_begin, dims_end, 1, std::multiplies<long>());\n        }\n        \n        fft_size(std::initializer_list<long> dims)\n        : fft_size(dims.begin(), dims.end())\n        /*!\n            requires\n                - dims.size() > 0 and dims.size() <= 5\n                - dims contains strictly positive values\n            ensures\n                - *this is properly initialised\n                - num_dims() == dims.size()\n                - num_elements() == product of all values in dims\n        !*/\n        {\n        }\n        \n        size_t num_dims() const\n        /*!\n            ensures\n                - returns the number of dimensions\n        !*/\n        {\n            return _size;\n        }\n        \n        long num_elements() const\n        /*!\n            ensures\n                - if num_dims() > 0, returns the product of all dimensions, i.e. the total number\n                  of elements\n                - if num_dims() == 0, returns 0\n        !*/\n        {\n            return _num_elements;\n        }\n\n        const_reference operator[](size_t index) const\n        /*!\n            requires\n                - index < num_dims()\n            ensures\n                - returns a const reference to the dimension at position index\n        !*/\n        {\n            DLIB_ASSERT(index < _size, \"index \" << index << \" out of range [0,\" << _size << \")\");\n            return _dims[index];\n        }\n        \n        const_reference back() const\n        /*!\n            requires\n                - num_dims() > 0\n            ensures\n                - returns a const reference to (*this)[num_dims()-1]\n        !*/\n        {\n            DLIB_ASSERT(_size > 0, \"object is empty\");\n            return _dims[_size-1];\n        }\n                \n        const_iterator begin() const\n        /*!\n            ensures\n                - returns a const iterator that points to the first dimension \n                  in this container or end() if the array is empty.\n        !*/\n        {\n            return _dims.begin();\n        }\n        \n        const_iterator end() const\n        /*!\n            ensures\n                - returns a const iterator that points to one past the end of \n                  the container.\n        !*/\n        {\n            return _dims.begin() + _size;\n        }\n        \n        bool operator==(const fft_size& other) const\n        /*!\n            ensures\n                - returns true if two fft_size objects have same size and same dimensions, i.e. if they have identical states\n        !*/\n        {\n            return this->_size == other._size && std::equal(begin(), end(), other.begin());\n        }\n        \n    private:        \n        size_t _size = 0;\n        size_t _num_elements = 0;\n        container_type _dims{};\n    };\n    \n    inline dlib::uint32 hash(\n        const fft_size& item,\n        dlib::uint32 seed = 0)\n    {\n        seed = dlib::hash((dlib::uint64)item.num_dims(), seed);\n        seed = std::accumulate(item.begin(), item.end(), seed, [](dlib::uint32 seed, long next) {\n            return dlib::hash((dlib::uint64)next, seed);\n        });\n        return seed;\n    }\n    /*!\n        ensures\n            - returns a 32bit hash of the data stored in item.\n    !*/\n\n    inline fft_size pop_back(const fft_size& size)\n    {\n        DLIB_ASSERT(size.num_dims() > 0);\n        return fft_size(size.begin(), size.end() - 1);\n    }\n    /*!\n        requires\n            - num_dims.size() > 0\n        ensures\n            - returns a copy of size with the last dimension removed.\n    !*/\n    \n    inline fft_size squeeze_ones(const fft_size size)\n    {\n        DLIB_ASSERT(size.num_dims() > 0);\n        fft_size newsize;\n        if (size.num_elements() == 1)\n        {\n            newsize = {1};\n        }\n        else\n        {\n            fft_size::container_type tmp;\n            auto end = std::copy_if(size.begin(), size.end(), tmp.begin(), [](long dim){return dim != 1;});\n            newsize = fft_size(tmp.begin(), end);\n        }\n        return newsize;\n    }\n    /*!\n        requires\n            - num_dims.size() > 0\n        ensures\n            - removes dimensions with values equal to 1, yielding a new fft_size object with the same num_elements() but fewer dimensions\n    !*/\n}\n\n#endif //DLIB_FFT_SIZE_H\n"
  },
  {
    "path": "dlib/fft/fft_stl.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FFT_STL_Hh_\n#define DLIB_FFT_STL_Hh_\n\n#include <vector>\n#include \"fft.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, typename Alloc >\n    void fft_inplace (std::vector<std::complex<T>, Alloc>& data)\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - This function is identical to fft() except that it does the FFT in-place.\n              That is, after this function executes we will have:\n                - #data == fft(data)\n    !*/\n    {\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        if (data.size() != 0)\n            fft({(long)data.size()}, &data[0], &data[0], false);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template < typename T, typename Alloc >\n    void ifft_inplace (std::vector<std::complex<T>, Alloc>& data)\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - This function is identical to ifft() except that it does the inverse FFT\n              in-place.  That is, after this function executes we will have:\n                - #data == ifft(data)*data.size()\n                - Note that the output needs to be divided by data.size() to complete the \n                  inverse transformation.  \n    !*/\n    {\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        if (data.size() != 0)\n            fft({(long)data.size()}, &data[0], &data[0], true);\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif //DLIB_FFT_STL_Hh_"
  },
  {
    "path": "dlib/fft/kiss_fft.h",
    "content": "/*\n *  Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.\n *  This file is part of KISS FFT - https://github.com/mborgerding/kissfft\n *\n *  SPDX-License-Identifier: BSD-3-Clause\n *  See COPYING file for more information.\n */\n\n#ifndef DLIB_KISS_FFT_H\n#define DLIB_KISS_FFT_H\n\n#include <complex>\n#include <vector>\n#include <cmath>\n#include <stdexcept>\n#include <algorithm>\n#include <unordered_map>\n#include <mutex>\n#include <numeric>\n#include \"fft_size.h\"\n#include \"../hash.h\"\n#include \"../assert.h\"\n\n#define C_FIXDIV(x,y) /*noop*/\n\nnamespace dlib\n{    \n    namespace kiss_details\n    {\n        struct plan_key\n        {\n            fft_size dims;\n            bool is_inverse;\n\n            plan_key(const fft_size& dims_, bool is_inverse_)\n            :   dims(dims_), is_inverse(is_inverse_) \n            {}\n            \n            bool operator==(const plan_key& other) const\n            {\n                return std::tie(dims, is_inverse) == std::tie(other.dims, other.is_inverse);\n            }\n\n            uint32 hash() const\n            {\n                using dlib::hash;\n                uint32 ret = 0;\n                ret = hash(dims, ret);\n                ret = hash((uint32)is_inverse, ret);\n                return ret;\n            }\n        };\n\n        template<typename T>\n        struct kiss_fft_state\n        {\n            long nfft;\n            bool inverse;\n            std::vector<int> factors;\n            std::vector<std::complex<T>> twiddles;\n            \n            kiss_fft_state() = default;\n            kiss_fft_state(const plan_key& key);\n        };\n\n        template<typename T>\n        struct kiss_fftnd_state\n        {\n            fft_size dims;\n            std::vector<kiss_fft_state<T>> plans;\n            \n            kiss_fftnd_state() = default;\n            kiss_fftnd_state(const plan_key& key);\n        };\n\n        template<typename T>\n        struct kiss_fftr_state\n        {\n            kiss_fft_state<T> substate;\n            std::vector<std::complex<T>> super_twiddles;\n            \n            kiss_fftr_state() = default;\n            kiss_fftr_state(const plan_key& key);\n        };\n\n        template<typename T>\n        struct kiss_fftndr_state\n        {\n            kiss_fftr_state<T> cfg_r;\n            kiss_fftnd_state<T> cfg_nd;\n            \n            kiss_fftndr_state() = default;\n            kiss_fftndr_state(const plan_key& key);\n        };\n\n        template<typename T>\n        inline void kf_bfly2(\n            std::complex<T> * Fout,\n            const size_t fstride,\n            const kiss_fft_state<T>& cfg,\n            const int m\n        )\n        {\n            const std::complex<T> * tw1 = &cfg.twiddles[0];\n            std::complex<T> t;\n            std::complex<T> * Fout2 = Fout + m;\n\n            for (int i = 0 ; i < m ; i++)\n            {\n                t = Fout2[i] * tw1[i*fstride];\n                Fout2[i] = Fout[i] - t;\n                Fout[i] += t;\n            }\n        }\n\n        template<typename T>\n        inline std::complex<T> rot_PI_2(std::complex<T> z)\n        {\n            return std::complex<T>(z.imag(), -z.real());\n        }\n\n        template<typename T>\n        inline void kf_bfly3 (\n            std::complex<T> * Fout,\n            const size_t fstride,\n            const kiss_fft_state<T>& cfg,\n            const size_t m\n        )\n        {\n            const size_t m2 = 2*m;\n            const std::complex<T> *tw1,*tw2;\n            std::complex<T> scratch[5];\n            const std::complex<T> epi3 = cfg.twiddles[fstride*m];\n\n            tw1=tw2=&cfg.twiddles[0];\n\n            constexpr T half = 0.5;\n            \n            for (size_t k = 0 ; k < m ; k++)\n            {\n                C_FIXDIV(Fout[k],3); C_FIXDIV(Fout[k+m],3); C_FIXDIV(Fout[m2+k],3); //noop for float and double\n\n                scratch[1] = Fout[k+m]  * tw1[k*fstride];\n                scratch[2] = Fout[k+m2] * tw2[k*fstride*2];\n\n                scratch[3] = scratch[1] + scratch[2];\n                scratch[0] = scratch[1] - scratch[2];\n\n                Fout[m+k] = Fout[k] - half * scratch[3];\n\n                scratch[0] *= epi3.imag();\n\n                Fout[k] += scratch[3];\n\n                Fout[k+m2] = Fout[k+m] + rot_PI_2(scratch[0]);\n                Fout[k+m] -= rot_PI_2(scratch[0]);\n            }\n        }\n\n        template<typename T>\n        inline void kf_bfly4(\n            std::complex<T> * Fout,\n            const size_t fstride,\n            const kiss_fft_state<T>& cfg,\n            const size_t m\n        )\n        {\n            const std::complex<T> *tw1,*tw2,*tw3;\n            std::complex<T> scratch[6];\n            const size_t m2=2*m;\n            const size_t m3=3*m;\n\n            tw3 = tw2 = tw1 = &cfg.twiddles[0];\n\n            for (size_t k = 0 ; k < m ; k++)\n            {\n                C_FIXDIV(Fout[k],4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2+k],4); C_FIXDIV(Fout[m3+k],4);\n\n                scratch[0] = Fout[m+k]  * tw1[k*fstride];\n                scratch[1] = Fout[m2+k] * tw2[k*fstride*2];\n                scratch[2] = Fout[m3+k] * tw3[k*fstride*3];\n\n                scratch[5] = Fout[k] - scratch[1];\n                Fout[k]  += scratch[1];\n                scratch[3] = scratch[0] + scratch[2];\n                scratch[4] = scratch[0] - scratch[2];\n                Fout[m2+k] = Fout[k] - scratch[3];\n\n                Fout[k] += scratch[3];\n\n                if(cfg.inverse) {\n                    Fout[m+k]  = scratch[5] - rot_PI_2(scratch[4]);\n                    Fout[m3+k] = scratch[5] + rot_PI_2(scratch[4]);\n                }else {\n                    Fout[m+k] =  scratch[5] + rot_PI_2(scratch[4]);\n                    Fout[m3+k] = scratch[5] - rot_PI_2(scratch[4]);\n                }\n            }\n        }\n\n        template<typename T>\n        inline void kf_bfly5(\n            std::complex<T> * Fout,\n            const size_t fstride,\n            const kiss_fft_state<T>& cfg,\n            const int m\n        )\n        {\n            std::complex<T> scratch[13];\n            const std::complex<T> * twiddles = &cfg.twiddles[0];\n            const std::complex<T> ya = twiddles[fstride*m];\n            const std::complex<T> yb = twiddles[fstride*2*m];\n\n            std::complex<T> *Fout0=Fout;\n            std::complex<T> *Fout1=Fout0+m;\n            std::complex<T> *Fout2=Fout0+2*m;\n            std::complex<T> *Fout3=Fout0+3*m;\n            std::complex<T> *Fout4=Fout0+4*m;\n\n            const std::complex<T> *tw = &cfg.twiddles[0];\n            \n            for (int u=0; u<m; ++u ) \n            {\n                scratch[0] = Fout0[u];\n\n                scratch[1] = Fout1[u] * tw[u*fstride]; //C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);\n                scratch[2] = Fout2[u] * tw[2*u*fstride]; //C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);\n                scratch[3] = Fout3[u] * tw[3*u*fstride]; //C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);\n                scratch[4] = Fout4[u] * tw[4*u*fstride]; //C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);\n\n                scratch[7]  = scratch[1] + scratch[4]; //C_ADD( scratch[7],scratch[1],scratch[4]);\n                scratch[10] = scratch[1] - scratch[4]; //C_SUB( scratch[10],scratch[1],scratch[4]);\n                scratch[8]  = scratch[2] + scratch[3]; //C_ADD( scratch[8],scratch[2],scratch[3]);\n                scratch[9]  = scratch[2] - scratch[3]; //C_SUB( scratch[9],scratch[2],scratch[3]);\n\n                Fout0[u] += scratch[7] + scratch[8];\n\n                scratch[5].real(scratch[0].real() + scratch[7].real() * ya.real() + scratch[8].real() * yb.real());\n                scratch[5].imag(scratch[0].imag() + scratch[7].imag() * ya.real() + scratch[8].imag() * yb.real());\n\n                scratch[6].real(scratch[10].imag() * ya.imag() + scratch[9].imag() * yb.imag());\n                scratch[6].imag(-scratch[10].real() * ya.imag() - scratch[9].real() * yb.imag());\n\n                Fout1[u] = scratch[5] - scratch[6]; //C_SUB(*Fout1,scratch[5],scratch[6]);\n                Fout4[u] = scratch[5] + scratch[6]; //C_ADD(*Fout4,scratch[5],scratch[6]);\n\n                scratch[11].real(scratch[0].real() + scratch[7].real()*yb.real() + scratch[8].real()*ya.real());\n                scratch[11].imag(scratch[0].imag() + scratch[7].imag()*yb.real() + scratch[8].imag()*ya.real());\n                scratch[12].real(- scratch[10].imag()*yb.imag() + scratch[9].imag()*ya.imag());\n                scratch[12].imag(scratch[10].real()*yb.imag() - scratch[9].real()*ya.imag());\n\n                Fout2[u] = scratch[11] + scratch[12];\n                Fout3[u] = scratch[11] - scratch[12];\n            }\n        }\n\n        /* perform the butterfly for one stage of a mixed radix FFT */\n        template<typename T> \n        inline void kf_bfly_generic(\n            std::complex<T> * Fout,\n            const size_t fstride,\n            const kiss_fft_state<T>& cfg,\n            const int m,\n            const int p\n        )\n        {\n            int u,k,q1,q;\n            const std::complex<T> * twiddles = &cfg.twiddles[0];\n            std::complex<T> t;\n            const int Norig = cfg.nfft;\n\n            std::vector<std::complex<T>> scratch(p);\n\n            for ( u=0; u<m; ++u ) {\n                k=u;\n                for ( q1=0 ; q1<p ; ++q1 ) {\n                    scratch[q1] = Fout[ k  ];\n                    C_FIXDIV(scratch[q1],p);\n                    k += m;\n                }\n\n                k=u;\n                for ( q1=0 ; q1<p ; ++q1 ) {\n                    int twidx=0;\n                    Fout[ k ] = scratch[0];\n                    for (q=1;q<p;++q ) {\n                        twidx += fstride * k;\n                        if (twidx>=Norig) twidx-=Norig;\n                        t = scratch[q] * twiddles[twidx];\n                        Fout[ k ] += t;\n                    }\n                    k += m;\n                }\n            }\n        }\n\n        template<typename T>\n        inline void kf_work(\n            const kiss_fft_state<T>& cfg,\n            const int* factors,\n            std::complex<T>* Fout,\n            const std::complex<T>* f,\n            const size_t fstride,\n            const int in_stride\n        )\n        {\n            std::complex<T> * Fout_beg = Fout;\n            const int p=*factors++; /* the radix  */\n            const int m=*factors++; /* stage's fft length/p */\n            const std::complex<T> * Fout_end = Fout + p*m;\n\n            if (m==1) {\n                do{\n                    *Fout = *f;\n                    f += fstride*in_stride;\n                }while(++Fout != Fout_end );\n            }else{\n                do{\n                    // recursive call:\n                    // DFT of size m*p performed by doing\n                    // p instances of smaller DFTs of size m,\n                    // each one takes a decimated version of the input\n                    kf_work(cfg, factors, Fout , f, fstride*p, in_stride);\n                    f += fstride*in_stride;\n                }while( (Fout += m) != Fout_end );\n            }\n\n            Fout=Fout_beg;\n\n            // recombine the p smaller DFTs\n            switch (p) {\n                case 2: kf_bfly2(Fout,fstride,cfg,m); break;\n                case 3: kf_bfly3(Fout,fstride,cfg,m); break;\n                case 4: kf_bfly4(Fout,fstride,cfg,m); break;\n                case 5: kf_bfly5(Fout,fstride,cfg,m); break;\n                default: kf_bfly_generic(Fout,fstride,cfg,m,p); break;\n            }\n        }\n\n        /*  facbuf is populated by p1,m1,p2,m2, ...\n            where\n            p[i] * m[i] = m[i-1]\n            m0 = n                  */\n        inline void kf_factor(int n, std::vector<int>& facbuf)\n        {\n            int p=4;\n            const double floor_sqrt = std::floor( std::sqrt((double)n) );\n\n            /*factor out powers of 4, powers of 2, then any remaining primes */\n            do {\n                while (n % p) {\n                    switch (p) {\n                        case 4: p = 2; break;\n                        case 2: p = 3; break;\n                        default: p += 2; break;\n                    }\n                    if (p > floor_sqrt)\n                        p = n;          /* no more factors, skip to end */\n                }\n                n /= p;\n                facbuf.push_back(p);\n                facbuf.push_back(n);\n            } while (n > 1);\n        }\n\n        template<typename T>\n        inline kiss_fft_state<T>::kiss_fft_state(const plan_key& key)\n        {\n            constexpr double twopi = 6.283185307179586476925286766559005768394338798;\n            nfft       = key.dims[0];\n            inverse    = key.is_inverse;\n            twiddles.resize(nfft);\n\n            for (int i = 0 ; i < nfft ; ++i) \n            {\n                double phase = -twopi*i / nfft;\n                if (inverse)\n                    phase *= -1;\n                twiddles[i] = std::polar(1.0, phase);\n            }\n\n            kf_factor(nfft,factors);\n        }\n\n        template<typename T>\n        void kiss_fft_stride(const kiss_fft_state<T>& cfg, const std::complex<T>* in, std::complex<T>* out,int fin_stride)\n        {\n            if (in == out) \n            {\n                DLIB_ASSERT(out != nullptr, \"out buffer is NULL!\");\n                std::vector<std::complex<T>> tmpbuf(cfg.nfft);\n                kiss_fft_stride(cfg, in, &tmpbuf[0], fin_stride);\n                std::copy(tmpbuf.begin(), tmpbuf.end(), out);\n            }\n            else\n            {\n                kf_work(cfg, &cfg.factors[0], out, in, 1, fin_stride);\n            }\n        }\n\n        template<typename T>\n        inline kiss_fftnd_state<T>::kiss_fftnd_state(const plan_key& key)\n        {\n            dims = key.dims;\n            for (size_t i = 0 ; i < dims.num_dims() ; i++)\n                plans.push_back(std::move(kiss_fft_state<T>(plan_key({dims[i]}, key.is_inverse))));\n        }\n\n        template<typename T>\n        void kiss_fftnd(const kiss_fftnd_state<T>& cfg, const std::complex<T>* in, std::complex<T>* out)\n        {\n            const std::complex<T>* bufin=in;\n            std::complex<T>* bufout;\n            std::vector<std::complex<T>> tmpbuf(cfg.dims.num_elements());\n\n            /*arrange it so the last bufout == out*/\n            if ( cfg.dims.num_dims() & 1 )\n            {\n                bufout = out;\n                if (in==out) {\n                    std::copy(in, in + cfg.dims.num_elements(), tmpbuf.begin());\n                    bufin = &tmpbuf[0];\n                }\n            }\n            else\n                bufout = &tmpbuf[0];\n\n            for (size_t k=0; k < cfg.dims.num_dims(); ++k) \n            {\n                int curdim = cfg.dims[k];\n                int stride = cfg.dims.num_elements() / curdim;\n\n                for (int i=0 ; i<stride ; ++i ) \n                    kiss_fft_stride(cfg.plans[k], bufin+i , bufout+i*curdim, stride );\n\n                /*toggle back and forth between the two buffers*/\n                if (bufout == &tmpbuf[0])\n                {\n                    bufout = out;\n                    bufin = &tmpbuf[0];\n                }\n                else\n                {\n                    bufout = &tmpbuf[0];\n                    bufin = out;\n                }\n            }\n        }\n\n        template<typename T>\n        inline kiss_fftr_state<T>::kiss_fftr_state(const plan_key& key)\n        {\n            DLIB_ASSERT((key.dims[0] & 1) == 0, \"real FFT must have even dimension\");\n            \n            const int nfft = key.dims[0] / 2;\n            substate = kiss_fft_state<T>(plan_key({nfft}, key.is_inverse));\n            super_twiddles.resize(nfft/2);\n\n            for (size_t i = 0 ; i < super_twiddles.size() ; ++i) \n            {\n                double phase = -3.141592653589793238462643383279502884197169399 * ((double) (i+1) / nfft + .5);\n                if (key.is_inverse)\n                    phase *= -1;\n                super_twiddles[i] = std::polar(1.0, phase);\n            }\n        }\n\n        template<typename T>\n        void kiss_fftr(const kiss_fftr_state<T>& plan, const T* timedata, std::complex<T>* freqdata)\n        {\n            DLIB_ASSERT(!plan.substate.inverse, \"bad fftr plan : need a forward plan. This is an inverse plan\");\n\n            const int nfft_h = plan.substate.nfft; //recall that the FFT size is actually half the original requested FFT size, i.e. the size of timedata\n\n            /*perform the parallel fft of two real signals packed in real,imag*/\n            std::vector<std::complex<T>> tmpbuf(nfft_h);\n            kiss_fft_stride(plan.substate, reinterpret_cast<const std::complex<T>*>(timedata), &tmpbuf[0], 1);\n            /* The real part of the DC element of the frequency spectrum in st->tmpbuf\n             * contains the sum of the even-numbered elements of the input time sequence\n             * The imag part is the sum of the odd-numbered elements\n             *\n             * The sum of tdc.r and tdc.i is the sum of the input time sequence.\n             *      yielding DC of input time sequence\n             * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...\n             *      yielding Nyquist bin of input time sequence\n             */\n\n            freqdata[0]         = std::complex<T>(tmpbuf[0].real() + tmpbuf[0].imag(), 0);\n            freqdata[nfft_h]    = std::complex<T>(tmpbuf[0].real() - tmpbuf[0].imag(), 0);\n\n            constexpr T half = 0.5;\n            \n            for (int k = 1 ; k <= nfft_h / 2 ; ++k)\n            {\n                const auto fpk  = tmpbuf[k];\n                const auto fpnk = std::conj(tmpbuf[nfft_h-k]);\n                const auto f1k = fpk + fpnk;\n                const auto f2k = fpk - fpnk;\n                const auto tw  = f2k * plan.super_twiddles[k-1];\n                freqdata[k]         = half * (f1k + tw);\n                freqdata[nfft_h-k]  = half * std::conj(f1k - tw);\n            }\n        }\n\n        template<typename T>\n        void kiss_ifftr(const kiss_fftr_state<T>& plan, const std::complex<T>* freqdata, T* timedata)\n        {\n            DLIB_ASSERT(plan.substate.inverse, \"bad Ifftr plan : need an inverse plan. This is a forward plan\")\n\n            const int nfft_h = plan.substate.nfft; //recall that the FFT size is actually half the original requested FFT size, i.e. the size of timedata\n\n            std::vector<std::complex<T>> tmpbuf(nfft_h);\n\n            tmpbuf[0] = std::complex<T>(freqdata[0].real() + freqdata[nfft_h].real(),\n                                        freqdata[0].real() - freqdata[nfft_h].real());\n\n            for (int k = 1; k <= nfft_h / 2; ++k)\n            {\n                std::complex<T> fk   = freqdata[k];\n                std::complex<T> fnkc = std::conj(freqdata[nfft_h - k]);\n                auto fek = fk + fnkc;\n                auto tmp = fk - fnkc;\n                auto fok = tmp * plan.super_twiddles[k-1];\n                tmpbuf[k] = fek + fok;\n                tmpbuf[nfft_h - k] = std::conj(fek - fok);\n            }\n\n            kiss_fft_stride (plan.substate, &tmpbuf[0], (std::complex<T>*)timedata, 1);\n        }\n\n        template<typename T>\n        inline kiss_fftndr_state<T>::kiss_fftndr_state(const plan_key& key)\n        {\n            const long realdim = key.dims.back();\n            const fft_size otherdims = pop_back(key.dims);\n            cfg_r  = kiss_fftr_state<T>(plan_key({realdim}, key.is_inverse));\n            cfg_nd = kiss_fftnd_state<T>(plan_key(otherdims, key.is_inverse));\n        }\n\n        template<typename T>\n        void kiss_fftndr(const kiss_fftndr_state<T>& plan, const T* timedata, std::complex<T>* freqdata)\n        {\n            const int dimReal  = plan.cfg_r.substate.nfft*2; //recall the real fft size is half the length of the input\n            const int dimOther = plan.cfg_nd.dims.num_elements();\n            const int nrbins   = dimReal/2+1;\n\n            std::vector<std::complex<T>> tmp1(std::max<int>(nrbins, dimOther));\n            std::vector<std::complex<T>> tmp2(plan.cfg_nd.dims.num_elements()*dimReal);\n\n            // take a real chunk of data, fft it and place the output at correct intervals\n            for (int k1 = 0; k1 < dimOther; ++k1) \n            {\n                kiss_fftr(plan.cfg_r, timedata + k1*dimReal , &tmp1[0]); // tmp1 now holds nrbins complex points\n                for (int k2 = 0; k2 < nrbins; ++k2)\n                   tmp2[k2*dimOther+k1] = tmp1[k2];\n            }\n\n            for (int k2 = 0; k2 < nrbins; ++k2) \n            {\n                kiss_fftnd(plan.cfg_nd, &tmp2[k2*dimOther], &tmp1[0]);  // tmp1 now holds dimOther complex points\n                for (int k1 = 0; k1 < dimOther; ++k1) \n                    freqdata[ k1*(nrbins) + k2] = tmp1[k1];\n            }\n        }\n\n        template<typename T>\n        void kiss_ifftndr(const kiss_fftndr_state<T>& plan, const std::complex<T>* freqdata, T* timedata)\n        {\n            const int dimReal  = plan.cfg_r.substate.nfft*2; //recall the real fft size is half the length of the input\n            const int dimOther = plan.cfg_nd.dims.num_elements();\n            const int nrbins   = dimReal/2+1;\n\n            std::vector<std::complex<T>> tmp1(std::max<int>(nrbins, dimOther));\n            std::vector<std::complex<T>> tmp2(plan.cfg_nd.dims.num_elements()*dimReal);\n\n            for (int k2 = 0; k2 < nrbins; ++k2) \n            {\n                for (int k1 = 0; k1 < dimOther; ++k1) \n                    tmp1[k1] = freqdata[ k1*(nrbins) + k2 ];\n                kiss_fftnd(plan.cfg_nd, &tmp1[0], &tmp2[k2*dimOther]);\n            }\n\n            for (int k1 = 0; k1 < dimOther; ++k1) \n            {\n                for (int k2 = 0; k2 < nrbins; ++k2)\n                    tmp1[k2] = tmp2[ k2*dimOther+k1 ];\n                kiss_ifftr(plan.cfg_r, &tmp1[0], timedata + k1*dimReal);\n            }\n        }\n\n        struct hasher\n        {\n            size_t operator()(const plan_key& key) const {return key.hash();}\n        };\n\n        template<typename plan_type>\n        const plan_type& get_plan(const plan_key& key)\n        {\n            static std::mutex m;\n            static std::unordered_map<plan_key, plan_type, hasher> plans;\n            \n            std::lock_guard<std::mutex> l(m);\n            auto it = plans.find(key);\n            if (it != plans.end())\n            {\n                return it->second;\n            }\n            else\n            {\n                plans[key] = plan_type(key);\n                return plans[key];\n            }\n        }\n    }\n\n    template<typename T>\n    void kiss_fft(const fft_size& dims, const std::complex<T>* in, std::complex<T>* out, bool is_inverse)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represents the dimensions of both `in` and `out`\n            - dims.num_dims() > 0\n        ensures\n            - performs an FFT on `in` and stores the result in `out`.\n            - if `is_inverse` is true, a backward FFT is performed, \n              otherwise a forward FFT is performed.\n    !*/\n    {\n        using namespace kiss_details;\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floating point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        \n        const fft_size squeezed_dims = squeeze_ones(dims);\n        \n        if (squeezed_dims.num_elements() == 1)\n        {\n            if (in != out)\n            {\n                out[0] = in[0];\n            }\n        }\n        else if (squeezed_dims.num_dims() == 1)\n        {\n            const auto& plan = get_plan<kiss_fft_state<T>>({squeezed_dims, is_inverse});\n            kiss_fft_stride(plan, in, out, 1);\n        }\n        else\n        {\n            const auto& plan = get_plan<kiss_fftnd_state<T>>({squeezed_dims,is_inverse});\n            kiss_fftnd(plan, in, out);\n        }\n    }\n\n    /*\n     *  in  has dims[0] * dims[1] * ... * dims[-2] * dims[-1] points\n     *  out has dims[0] * dims[1] * ... * dims[-2] * (dims[-1]/2+1) points\n     */\n    template<typename T>\n    void kiss_fftr(const fft_size& dims, const T* in, std::complex<T>* out)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `in`\n            - `out` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - dims.num_dims() > 0\n            - dims.back() must be even\n        ensures\n            - performs a real FFT on `in` and stores the result in `out`.\n    !*/\n    {\n        using namespace kiss_details;\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floating point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        DLIB_ASSERT(dims.back() % 2 == 0, \"last dimension needs to be even\");\n\n        const fft_size squeezed_dims = squeeze_ones(dims);\n        \n        if (squeezed_dims.num_dims() == 1)\n        {\n            const auto& plan = get_plan<kiss_fftr_state<T>>({squeezed_dims,false});\n            kiss_fftr(plan, in, out);\n        }\n        else\n        {\n            const auto& plan = get_plan<kiss_fftndr_state<T>>({squeezed_dims,false});\n            kiss_fftndr(plan, in, out);\n        }\n    }\n\n    /*\n     *  in  has dims[0] * dims[1] * ... * dims[-2] * (dims[-1]/2+1) points\n     *  out has dims[0] * dims[1] * ... * dims[-2] * dims[-1] points\n     */\n    template<typename T>\n    void kiss_ifftr(const fft_size& dims, const std::complex<T>* in, T* out)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `out`\n            - `in` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - dims.num_dims() > 0\n            - dims.back() must be even\n        ensures\n            - performs an inverse real FFT on `in` and stores the result in `out`.\n    !*/\n    {\n        using namespace kiss_details;\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floating point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        DLIB_ASSERT(dims.back() % 2 == 0, \"last dimension needs to be even\");\n\n        const fft_size squeezed_dims = squeeze_ones(dims);\n        \n        if (squeezed_dims.num_dims() == 1)\n        {\n            const auto& plan = get_plan<kiss_fftr_state<T>>({squeezed_dims,true});\n            kiss_ifftr(plan, in, out);\n        }\n        else\n        {\n            const auto& plan = get_plan<kiss_fftndr_state<T>>({squeezed_dims,true});\n            kiss_ifftndr(plan, in, out);\n        }\n    }\n\n    inline int kiss_fft_next_fast_size(int n)\n    {\n        while(1) {\n            int m=n;\n            while ( (m%2) == 0 ) m/=2;\n            while ( (m%3) == 0 ) m/=3;\n            while ( (m%5) == 0 ) m/=5;\n            if (m<=1)\n                break; /* n is completely factorable by twos, threes, and fives */\n            n++;\n        }\n        return n;\n    }\n\n    inline int kiss_fftr_next_fast_size_real(int n)\n    {\n        return kiss_fft_next_fast_size((n+1)>>1) << 1;\n    }\n}\n\n#endif // DLIB_KISS_FFT_H\n"
  },
  {
    "path": "dlib/fft/mkl_fft.h",
    "content": "#ifndef DLIB_MKL_FFT_H\n#define DLIB_MKL_FFT_H\n\n#include <type_traits>\n#include <mkl_dfti.h>\n#include \"fft_size.h\"\n\n#define DLIB_DFTI_CHECK_STATUS(s) \\\n    if((s) != 0 && !DftiErrorClass((s), DFTI_NO_ERROR)) \\\n    { \\\n        throw dlib::error(DftiErrorMessage((s))); \\\n    }\n\nnamespace dlib\n{\n    template<typename T>\n    void mkl_fft(const fft_size& dims, const std::complex<T>* in, std::complex<T>* out, bool is_inverse)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represents the dimensions of both `in` and `out`\n            - dims.num_dims() > 0\n            - dims.num_dims() < 3\n        ensures\n            - performs an FFT on `in` and stores the result in `out`.\n            - if `is_inverse` is true, a backward FFT is performed, \n              otherwise a forward FFT is performed.\n    !*/\n    {\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floatint point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        DLIB_ASSERT(dims.num_dims() < 3, \"we currently only support up to 2D FFT. Please submit an issue on github if 3D or above is required.\");\n\n        constexpr DFTI_CONFIG_VALUE dfti_type = std::is_same<T,float>::value ? DFTI_SINGLE : DFTI_DOUBLE;\n\n        DFTI_DESCRIPTOR_HANDLE h;\n        MKL_LONG status;\n\n        if (dims.num_dims() == 1)\n        {\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_COMPLEX, 1, dims[0]);\n            DLIB_DFTI_CHECK_STATUS(status);\n        }\n        else\n        {\n            MKL_LONG size[] = {dims[0], dims[1]};\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_COMPLEX, 2, size);\n            DLIB_DFTI_CHECK_STATUS(status);\n\n            MKL_LONG strides[3];\n            strides[0] = 0;\n            strides[1] = size[1];\n            strides[2] = 1;\n\n            status = DftiSetValue(h, DFTI_INPUT_STRIDES, strides);\n            DLIB_DFTI_CHECK_STATUS(status);\n            status = DftiSetValue(h, DFTI_OUTPUT_STRIDES, strides);\n            DLIB_DFTI_CHECK_STATUS(status);\n        }\n\n        const DFTI_CONFIG_VALUE inplacefft = in == out ? DFTI_INPLACE : DFTI_NOT_INPLACE;\n        status = DftiSetValue(h, DFTI_PLACEMENT, inplacefft);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        // Unless we use sequential mode, the fft results are not correct.\n        status = DftiSetValue(h, DFTI_THREAD_LIMIT, 1);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiCommitDescriptor(h);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        if (is_inverse)\n            status = DftiComputeBackward(h, (void*)in, (void*)out);\n        else\n            status = DftiComputeForward(h, (void*)in, (void*)out);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiFreeDescriptor(&h);\n        DLIB_DFTI_CHECK_STATUS(status);\n    }\n\n    /*\n     *  in  has dims[0] * dims[1] * ... * dims[-2] * dims[-1] points\n     *  out has dims[0] * dims[1] * ... * dims[-2] * (dims[-1]/2+1) points\n     */\n    template<typename T>\n    void mkl_fftr(const fft_size& dims, const T* in, std::complex<T>* out)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `in`\n            - `out` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - dims.num_dims() > 0\n            - dims.num_dims() <= 3\n            - dims.back() must be even\n        ensures\n            - performs a real FFT on `in` and stores the result in `out`.\n    !*/\n    {\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floatint point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        DLIB_ASSERT(dims.num_dims() < 3, \"we currently only support up to 2D FFT. Please submit an issue on github if 3D or above is required.\");\n        DLIB_ASSERT(dims.back() % 2 == 0, \"last dimension needs to be even\");\n        \n        constexpr DFTI_CONFIG_VALUE dfti_type = std::is_same<T,float>::value ? DFTI_SINGLE : DFTI_DOUBLE;\n\n        DFTI_DESCRIPTOR_HANDLE h;\n        MKL_LONG status;\n\n        if (dims.num_dims() == 1)\n        {\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_REAL, 1, dims[0]);\n            DLIB_DFTI_CHECK_STATUS(status);\n        }\n        else\n        {\n            const long lastdim  = dims[1]/2+1;\n            MKL_LONG size[] = {dims[0], dims[1]};\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_REAL, 2, size);\n            DLIB_DFTI_CHECK_STATUS(status);\n\n            {\n                MKL_LONG strides[3];\n                strides[0] = 0;\n                strides[1] = size[1];\n                strides[2] = 1;\n\n                status = DftiSetValue(h, DFTI_INPUT_STRIDES, strides);\n                DLIB_DFTI_CHECK_STATUS(status);\n            }\n            {\n                MKL_LONG strides[3];\n                strides[0] = 0;\n                strides[1] = lastdim;\n                strides[2] = 1;\n                status = DftiSetValue(h, DFTI_OUTPUT_STRIDES, strides);\n                DLIB_DFTI_CHECK_STATUS(status);\n            }   \n        }\n\n        const DFTI_CONFIG_VALUE inplacefft = (void*)in == (void*)out ? DFTI_INPLACE : DFTI_NOT_INPLACE;\n        status = DftiSetValue(h, DFTI_PLACEMENT, inplacefft);\n        DLIB_DFTI_CHECK_STATUS(status);\n        \n        status = DftiSetValue(h, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        // Unless we use sequential mode, the fft results are not correct.\n        status = DftiSetValue(h, DFTI_THREAD_LIMIT, 1);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiCommitDescriptor(h);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiComputeForward(h, (void*)in, (void*)out);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiFreeDescriptor(&h);\n        DLIB_DFTI_CHECK_STATUS(status);\n    }\n\n    /*\n     *  in  has dims[0] * dims[1] * ... * dims[-2] * (dims[-1]/2+1) points\n     *  out has dims[0] * dims[1] * ... * dims[-2] * dims[-1] points\n     */\n    template<typename T>\n    void mkl_ifftr(const fft_size& dims, const std::complex<T>* in, T* out)\n    /*!\n        requires\n            - T must be either float or double\n            - dims represent the dimensions of `out`\n            - `in` has dimensions {dims[0], dims[1], ..., dims[-2], dims[-1]/2+1}\n            - dims.num_dims() > 0\n            - dims.num_dims() <= 3\n            - dims.back() must be even\n        ensures\n            - performs an inverse real FFT on `in` and stores the result in `out`.\n    !*/\n    {\n        static_assert(std::is_floating_point<T>::value, \"template parameter needs to be a floatint point type\");\n        DLIB_ASSERT(dims.num_dims() > 0, \"dims can't be empty\");\n        DLIB_ASSERT(dims.num_dims() < 3, \"we currently only support up to 2D FFT. Please submit an issue on github if 3D or above is required.\");\n        DLIB_ASSERT(dims.back() % 2 == 0, \"last dimension needs to be even\");\n\n        constexpr DFTI_CONFIG_VALUE dfti_type = std::is_same<T,float>::value ? DFTI_SINGLE : DFTI_DOUBLE;\n\n        DFTI_DESCRIPTOR_HANDLE h;\n        MKL_LONG status;\n\n        if (dims.num_dims() == 1)\n        {\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_REAL, 1, dims[0]);\n            DLIB_DFTI_CHECK_STATUS(status);\n        }\n        else\n        {\n            const long lastdim  = dims[1]/2+1;\n            MKL_LONG size[] = {dims[0], dims[1]};\n            status = DftiCreateDescriptor(&h, dfti_type, DFTI_REAL, 2, size);\n            DLIB_DFTI_CHECK_STATUS(status);\n\n            {\n                MKL_LONG strides[3];\n                strides[0] = 0;\n                strides[1] = lastdim;\n                strides[2] = 1;\n\n                status = DftiSetValue(h, DFTI_INPUT_STRIDES, strides);\n                DLIB_DFTI_CHECK_STATUS(status);\n            }\n            {\n                MKL_LONG strides[3];\n                strides[0] = 0;\n                strides[1] = dims[1];\n                strides[2] = 1;\n                status = DftiSetValue(h, DFTI_OUTPUT_STRIDES, strides);\n                DLIB_DFTI_CHECK_STATUS(status);\n            }   \n        }\n\n        const DFTI_CONFIG_VALUE inplacefft = (void*)in == (void*)out ? DFTI_INPLACE : DFTI_NOT_INPLACE;\n        status = DftiSetValue(h, DFTI_PLACEMENT, inplacefft);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiSetValue(h, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX);\n        DLIB_DFTI_CHECK_STATUS(status);\n        \n        // Unless we use sequential mode, the fft results are not correct.\n        status = DftiSetValue(h, DFTI_THREAD_LIMIT, 1);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiCommitDescriptor(h);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiComputeBackward(h, (void*)in, (void*)out);\n        DLIB_DFTI_CHECK_STATUS(status);\n\n        status = DftiFreeDescriptor(&h);\n        DLIB_DFTI_CHECK_STATUS(status);\n    }\n}\n\n#endif // DLIB_MKL_FFT_H\n"
  },
  {
    "path": "dlib/filtering/kalman_filter.cpp",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_KALMAN_FiLTER_CPp_\n#define DLIB_KALMAN_FiLTER_CPp_\n\n#include \"kalman_filter.h\"\n#include \"../global_optimization.h\"\n#include \"../statistics.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<std::vector<double>>& sequences,\n        const double smoothness \n    )\n    {\n        DLIB_CASSERT(sequences.size() != 0);\n        for (auto& vals : sequences)\n            DLIB_CASSERT(vals.size() > 4);\n        DLIB_CASSERT(smoothness >= 0);\n\n        // define the objective function we optimize to find the best filter\n        auto obj = [&](double measurement_noise, double typical_acceleration, double max_measurement_deviation)\n        {\n            running_stats<double> rs;\n            for (auto& vals : sequences)\n            {\n                momentum_filter filt(measurement_noise, typical_acceleration, max_measurement_deviation);\n                double prev_filt = 0;\n                for (size_t i = 0; i < vals.size(); ++i)\n                {\n                    // we care about smoothness and fitting the data.\n                    if (i > 0)\n                    {\n                        // the filter should fit the data\n                        rs.add(std::abs(vals[i]-filt.get_predicted_next_position()));\n                    }\n                    double next_filt = filt(vals[i]);\n                    if (i > 0)\n                    {\n                        // the filter should also output a smooth trajectory\n                        rs.add(smoothness*std::abs(next_filt-prev_filt));\n                    }\n                    prev_filt = next_filt;\n                }\n            }\n            return rs.mean();\n        };\n\n        running_stats<double> avgdiff;\n        for (auto& vals : sequences)\n        {\n            for (size_t i = 1; i < vals.size(); ++i)\n                avgdiff.add(vals[i]-vals[i-1]);\n        }\n        const double scale = avgdiff.stddev();\n\n        function_evaluation opt = find_min_global(obj, {scale*0.01, scale*0.0001, 0.00001}, {scale*10, scale*10, 10}, max_function_calls(400));\n\n        momentum_filter filt(opt.x(0), opt.x(1), opt.x(2));\n\n        return filt;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<double>& sequence,\n        const double smoothness \n    )\n    {\n        return find_optimal_momentum_filter({1,sequence}, smoothness);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rect_filter find_optimal_rect_filter (\n        const std::vector<rectangle>& rects,\n        const double smoothness\n    )\n    {\n        DLIB_CASSERT(rects.size() > 4);\n        DLIB_CASSERT(smoothness >= 0);\n\n        std::vector<std::vector<double>> vals(4);\n        for (auto& r : rects)\n        {\n            vals[0].push_back(r.left());\n            vals[1].push_back(r.top());\n            vals[2].push_back(r.right());\n            vals[3].push_back(r.bottom());\n        }\n        return rect_filter(find_optimal_momentum_filter(vals, smoothness));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_KALMAN_FiLTER_CPp_\n\n"
  },
  {
    "path": "dlib/filtering/kalman_filter.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_KALMAN_FiLTER_Hh_\n#define DLIB_KALMAN_FiLTER_Hh_\n\n#include \"kalman_filter_abstract.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long states,\n        long measurements\n        >\n    class kalman_filter\n    {\n    public:\n\n        kalman_filter()\n        {\n            H = 0;\n            A = 0;\n            Q = 0;\n            R = 0;\n            x = 0;\n            xb = 0;\n            P = identity_matrix<double>(states);\n            got_first_meas = false;\n        }\n\n        void set_observation_model ( const matrix<double,measurements,states>& H_) { H = H_; }\n        void set_transition_model  ( const matrix<double,states,states>& A_) { A = A_; }\n        void set_process_noise     ( const matrix<double,states,states>& Q_) { Q = Q_; }\n        void set_measurement_noise ( const matrix<double,measurements,measurements>& R_) { R = R_; }\n        void set_estimation_error_covariance( const matrix<double,states,states>& P_) { P = P_; }\n        void set_state             ( const matrix<double,states,1>& xb_) \n        {\n            xb = xb_;\n            if (!got_first_meas) \n            {\n                x = xb_;\n                got_first_meas = true;\n            }\n        }\n\n        const matrix<double,measurements,states>& get_observation_model (\n        ) const { return H; }\n\n        const matrix<double,states,states>& get_transition_model (\n        ) const { return A; }\n\n        const matrix<double,states,states>& get_process_noise (\n        ) const { return Q; }\n\n        const matrix<double,measurements,measurements>& get_measurement_noise (\n        ) const { return R; }\n\n        void update (\n        )\n        {\n            // propagate estimation error covariance forward\n            P = A*P*trans(A) + Q;\n\n            // propagate state forward\n            x = xb;\n            xb = A*x;\n        }\n\n        void update (const matrix<double,measurements,1>& z)\n        {\n            // propagate estimation error covariance forward\n            P = A*P*trans(A) + Q;\n\n            // compute Kalman gain matrix\n            const matrix<double,states,measurements> K = P*trans(H)*pinv(H*P*trans(H) + R);\n\n            if (got_first_meas)\n            {\n                const matrix<double,measurements,1> res = z - H*xb;\n                // correct the current state estimate\n                x = xb + K*res;\n            }\n            else\n            {\n                // Since we don't have a previous state estimate at the start of filtering,\n                // we will just set the current state to whatever is indicated by the measurement\n                x = pinv(H)*z; \n                got_first_meas = true;\n            }\n\n            // propagate state forward in time\n            xb = A*x;\n\n            // update estimation error covariance since we got a measurement.\n            P = (identity_matrix<double,states>() - K*H)*P;\n        }\n\n        const matrix<double,states,1>& get_current_state(\n        ) const\n        {\n            return x;\n        }\n\n        const matrix<double,states,1>& get_predicted_next_state(\n        ) const\n        {\n            return xb;\n        }\n\n        const matrix<double,states,states>& get_current_estimation_error_covariance(\n        ) const\n        {\n            return P;\n        }\n\n        friend inline void serialize(const kalman_filter& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.got_first_meas, out);\n            serialize(item.x, out);\n            serialize(item.xb, out);\n            serialize(item.P, out);\n            serialize(item.H, out);\n            serialize(item.A, out);\n            serialize(item.Q, out);\n            serialize(item.R, out);\n        }\n\n        friend inline void deserialize(kalman_filter& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw dlib::serialization_error(\"Unknown version number found while deserializing kalman_filter object.\");\n\n            deserialize(item.got_first_meas, in);\n            deserialize(item.x, in);\n            deserialize(item.xb, in);\n            deserialize(item.P, in);\n            deserialize(item.H, in);\n            deserialize(item.A, in);\n            deserialize(item.Q, in);\n            deserialize(item.R, in);\n        }\n\n    private:\n\n        bool got_first_meas;\n        matrix<double,states,1> x, xb;\n        matrix<double,states,states> P;\n\n        matrix<double,measurements,states> H;\n        matrix<double,states,states> A;\n        matrix<double,states,states> Q;\n        matrix<double,measurements,measurements> R;\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class momentum_filter\n    {\n    public:\n\n        momentum_filter(\n            double meas_noise,\n            double acc,\n            double max_meas_dev\n        ) : \n            measurement_noise(meas_noise),\n            typical_acceleration(acc),\n            max_measurement_deviation(max_meas_dev)\n        {\n            DLIB_CASSERT(meas_noise >= 0);\n            DLIB_CASSERT(acc >= 0);\n            DLIB_CASSERT(max_meas_dev >= 0);\n\n            kal.set_observation_model({1, 0});\n            kal.set_transition_model( {1, 1,\n                0, 1});\n            kal.set_process_noise({0, 0,\n                0, typical_acceleration*typical_acceleration});\n\n            kal.set_measurement_noise({measurement_noise*measurement_noise});\n        }\n\n        momentum_filter() = default; \n\n        double get_measurement_noise (\n        ) const { return measurement_noise; }\n\n        double get_typical_acceleration (\n        ) const { return typical_acceleration; }\n\n        double get_max_measurement_deviation (\n        ) const { return max_measurement_deviation; }\n\n        void reset()\n        {\n            *this = momentum_filter(measurement_noise, typical_acceleration, max_measurement_deviation);\n        }\n\n        double get_predicted_next_position(\n        ) const\n        {\n            return kal.get_predicted_next_state()(0);\n        }\n\n        double operator()(\n            const double measured_position\n        )\n        {\n            auto x = kal.get_predicted_next_state();\n            const auto max_deviation = max_measurement_deviation*measurement_noise;\n            // Check if measured_position has suddenly jumped in value by a whole lot. This\n            // could happen if the velocity term experiences a much larger than normal\n            // acceleration, e.g.  because the underlying object is doing a maneuver.  If\n            // this happens then we clamp the state so that the predicted next value is no\n            // more than max_deviation away from measured_position at all times.\n            if (x(0) > measured_position + max_deviation)\n            {\n                x(0) = measured_position + max_deviation;\n                kal.set_state(x);\n            }\n            else if (x(0) < measured_position - max_deviation)\n            {\n                x(0) = measured_position - max_deviation;\n                kal.set_state(x);\n            }\n\n            kal.update({measured_position});\n\n            return kal.get_current_state()(0);\n        }\n\n        friend std::ostream& operator << (std::ostream& out, const momentum_filter& item)\n        {\n            out << \"measurement_noise:         \" << item.measurement_noise << \"\\n\";\n            out << \"typical_acceleration:      \" << item.typical_acceleration << \"\\n\";\n            out << \"max_measurement_deviation: \" << item.max_measurement_deviation;\n            return out;\n        }\n\n        friend void serialize(const momentum_filter& item, std::ostream& out)\n        {\n            int version = 15;\n            serialize(version, out);\n            serialize(item.measurement_noise, out);\n            serialize(item.typical_acceleration, out);\n            serialize(item.max_measurement_deviation, out);\n            serialize(item.kal, out);\n        }\n\n        friend void deserialize(momentum_filter& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 15)\n                throw serialization_error(\"Unexpected version found while deserializing momentum_filter.\");\n            deserialize(item.measurement_noise, in);\n            deserialize(item.typical_acceleration, in);\n            deserialize(item.max_measurement_deviation, in);\n            deserialize(item.kal, in);\n        }\n\n    private:\n\n        double measurement_noise = 2;\n        double typical_acceleration = 0.1;\n        double max_measurement_deviation = 3; // nominally number of standard deviations\n\n        kalman_filter<2,1> kal;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<std::vector<double>>& sequences,\n        const double smoothness = 1\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<double>& sequence,\n        const double smoothness = 1\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class rect_filter\n    {\n    public:\n        rect_filter() = default;\n\n        rect_filter(\n            double meas_noise,\n            double acc,\n            double max_meas_dev\n        ) : rect_filter(momentum_filter(meas_noise, acc, max_meas_dev)) {}\n\n        rect_filter(\n            const momentum_filter& filt\n        ) : \n            left(filt),\n            top(filt),\n            right(filt),\n            bottom(filt)\n        {\n        }\n\n        drectangle operator()(const drectangle& r) \n        {\n            return drectangle(left(r.left()),\n                            top(r.top()),\n                            right(r.right()),\n                            bottom(r.bottom()));\n        }\n\n        drectangle operator()(const rectangle& r) \n        {\n            return drectangle(left(r.left()),\n                            top(r.top()),\n                            right(r.right()),\n                            bottom(r.bottom()));\n        }\n\n        const momentum_filter& get_left   () const { return left; }\n        momentum_filter&       get_left   ()       { return left; }\n        const momentum_filter& get_top    () const { return top; }\n        momentum_filter&       get_top    ()       { return top; }\n        const momentum_filter& get_right  () const { return right; }\n        momentum_filter&       get_right  ()       { return right; }\n        const momentum_filter& get_bottom () const { return bottom; }\n        momentum_filter&       get_bottom ()       { return bottom; }\n\n        friend void serialize(const rect_filter& item, std::ostream& out)\n        {\n            int version = 123;\n            serialize(version, out);\n            serialize(item.left, out);\n            serialize(item.top, out);\n            serialize(item.right, out);\n            serialize(item.bottom, out);\n        }\n\n        friend void deserialize(rect_filter& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 123)\n                throw dlib::serialization_error(\"Unknown version number found while deserializing rect_filter object.\");\n            deserialize(item.left, in);\n            deserialize(item.top, in);\n            deserialize(item.right, in);\n            deserialize(item.bottom, in);\n        }\n\n    private:\n\n        momentum_filter left, top, right, bottom;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    rect_filter find_optimal_rect_filter (\n        const std::vector<rectangle>& rects,\n        const double smoothness = 1\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_KALMAN_FiLTER_Hh_\n\n"
  },
  {
    "path": "dlib/filtering/kalman_filter_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_KALMAN_FiLTER_ABSTRACT_Hh_\n#ifdef DLIB_KALMAN_FiLTER_ABSTRACT_Hh_\n\n#include \"../serialize.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long states,\n        long measurements\n        >\n    class kalman_filter\n    {\n        /*!\n            REQUIREMENTS ON states\n                states > 0\n\n            REQUIREMENTS ON measurements \n                measurements > 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object implements the Kalman filter, which is a tool for \n                recursively estimating the state of a process given measurements\n                related to that process.  To use this tool you will have to \n                be familiar with the workings of the Kalman filter.  An excellent\n                introduction can be found in the paper:\n                    An Introduction to the Kalman Filter\n                    by Greg Welch and Gary Bishop\n\n        !*/\n\n    public:\n\n        kalman_filter(\n        );\n        /*!\n            - #get_observation_model()    == 0\n            - #get_transition_model()     == 0\n            - #get_process_noise()        == 0\n            - #get_measurement_noise()    == 0\n            - #get_current_state()        == 0\n            - #get_predicted_next_state() == 0\n            - #get_current_estimation_error_covariance() == the identity matrix\n        !*/\n\n        void set_observation_model ( \n            const matrix<double,measurements,states>& H\n        );\n        /*!\n            ensures\n                - #get_observation_model() == H\n        !*/\n\n        void set_transition_model  ( \n            const matrix<double,states,states>& A\n        );\n        /*!\n            ensures\n                - #get_transition_model() == A\n        !*/\n\n        void set_process_noise     ( \n            const matrix<double,states,states>& Q\n        );\n        /*!\n            ensures\n                - #get_process_noise() == Q\n        !*/\n\n        void set_measurement_noise ( \n            const matrix<double,measurements,measurements>& R\n        );\n        /*!\n            ensures\n                - #get_measurement_noise() == R\n        !*/\n\n        void set_estimation_error_covariance ( \n            const matrix<double,states,states>& P\n        ); \n        /*!\n            ensures\n                - #get_current_estimation_error_covariance() == P\n                  (Note that you should only set this before you start filtering\n                  since the Kalman filter will maintain the value of P on its own.\n                  So only set this during initialization unless you are sure you\n                  understand what you are doing.)\n        !*/\n\n        void set_state ( \n            const matrix<double,states,1>& xb\n        ); \n        /*!\n            ensures\n                - This function can be used when the initial state is known, or if the\n                  state needs to be corrected before the next update().\n                - #get_predicted_next_state() == xb\n                - If (update() hasn't been called yet) then \n                    - #get_current_state() == xb \n        !*/\n\n        const matrix<double,measurements,states>& get_observation_model (\n        ) const;\n        /*!\n            ensures\n                - Returns the matrix \"H\" which relates process states x to measurements z.\n                  The relation is linear, therefore, z = H*x.  That is, multiplying a\n                  state by H gives the measurement you expect to observe for that state.\n        !*/\n\n        const matrix<double,states,states>& get_transition_model (\n        ) const;\n        /*!\n            ensures\n                - Returns the matrix \"A\" which determines how process states change over time.\n                  The relation is linear, therefore, given a state vector x, the value you\n                  expect it to have at the next time step is A*x.\n        !*/\n\n        const matrix<double,states,states>& get_process_noise (\n        ) const;\n        /*!\n            ensures\n                - returns the process noise covariance matrix.  You can think of this\n                  covariance matrix as a measure of how wrong the assumption of\n                  linear state transitions is. \n        !*/\n\n        const matrix<double,measurements,measurements>& get_measurement_noise (\n        ) const;\n        /*!\n            ensures\n                - returns the measurement noise covariance matrix.  That is, when we\n                  measure a state x we only obtain H*x corrupted by Gaussian noise.\n                  The measurement noise is the covariance matrix of this Gaussian\n                  noise which corrupts our measurements.\n        !*/\n\n        void update (\n        );\n        /*!\n            ensures\n                - propagates the current state estimate forward in time one\n                  time step.  In particular:\n                    - #get_current_state() == get_predicted_next_state()\n                    - #get_predicted_next_state() == get_transition_model()*get_current_state()\n                    - #get_current_estimation_error_covariance() == the propagated value of this covariance matrix\n        !*/\n\n        void update (\n            const matrix<double,measurements,1>& z\n        );\n        /*!\n            ensures\n                - propagates the current state estimate forward in time one time step.  \n                  Also applies a correction based on the given measurement z.  In particular:\n                    - #get_current_state(), #get_predicted_next_state(), and\n                      #get_current_estimation_error_covariance() are updated using the\n                      Kalman filter method based on the new measurement in z.\n        !*/\n\n        const matrix<double,states,1>& get_current_state(\n        ) const;\n        /*!\n            ensures\n                - returns the current estimate of the state of the process.  This\n                  estimate is based on all the measurements supplied to the update()\n                  method.\n        !*/\n\n        const matrix<double,states,1>& get_predicted_next_state(\n        ) const;\n        /*!\n            ensures\n                - returns the next expected value of the process state.  \n                - Specifically, returns get_transition_model()*get_current_state()\n                  \n        !*/\n\n        const matrix<double,states,states>& get_current_estimation_error_covariance(\n        ) const;\n        /*!\n            ensures\n                - returns the current state error estimation covariance matrix.  \n                  This matrix captures our uncertainty about the value of get_current_state().\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const kalman_filter& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        kalman_filter& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class momentum_filter\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple tool for filtering a single scalar value that\n                measures the location of a moving object that has some non-trivial\n                momentum.  Importantly, the measurements are noisy and the object can\n                experience sudden unpredictable accelerations.  To accomplish this\n                filtering we use a simple Kalman filter with a state transition model of:\n\n                    position_{i+1} = position_{i} + velocity_{i} \n                    velocity_{i+1} = velocity_{i} + some_unpredictable_acceleration\n\n                and a measurement model of:\n                    \n                    measured_position_{i} = position_{i} + measurement_noise\n\n                Where some_unpredictable_acceleration and measurement_noise are 0 mean Gaussian \n                noise sources with standard deviations of get_typical_acceleration() and\n                get_measurement_noise() respectively.\n\n                To allow for really sudden and large but infrequent accelerations, at each\n                step we check if the current measured position deviates from the predicted\n                filtered position by more than get_max_measurement_deviation()*get_measurement_noise() \n                and if so we adjust the filter's state to keep it within these bounds.\n                This allows the moving object to undergo large unmodeled accelerations, far\n                in excess of what would be suggested by get_typical_acceleration(), without\n                then experiencing a long lag time where the Kalman filter has to \"catch\n                up\" to the new position.\n        !*/\n\n    public:\n\n        momentum_filter(\n        ) = default; \n        /*!\n            ensures\n                - #get_measurement_noise() == 2\n                - #get_typical_acceleration() == 0.1\n                - #get_max_measurement_deviation() == 3\n        !*/\n\n        momentum_filter(\n            double meas_noise,\n            double acc,\n            double max_meas_dev\n        ); \n        /*!\n            requires\n                - meas_noise >= 0\n                - acc >= 0\n                - max_meas_dev >= 0\n            ensures\n                - #get_measurement_noise() == meas_noise\n                - #get_typical_acceleration() == acc\n                - #get_max_measurement_deviation() == max_meas_dev\n        !*/\n\n\n        double get_measurement_noise (\n        ) const; \n        /*!\n            ensures\n                - Returns the standard deviation of the 0 mean Gaussian noise that corrupts\n                  measurements of the moving object.\n        !*/\n\n        double get_typical_acceleration (\n        ) const;\n        /*!\n            ensures\n                - We assume that the moving object experiences random accelerations that\n                  are distributed by 0 mean Gaussian noise with get_typical_acceleration()\n                  standard deviation.\n        !*/\n\n        double get_max_measurement_deviation (\n        ) const;\n        /*!\n            ensures\n                - This object will never let the filtered location of the object deviate\n                  from the measured location by much more than\n                  get_max_measurement_deviation()*get_measurement_noise().\n        !*/\n\n        void reset(\n        );\n        /*!\n            ensures\n                - Returns this object to the state immediately after construction. To be precise, we do:\n                   *this = momentum_filter(get_measurement_noise(), get_typical_acceleration(), get_max_measurement_deviation());\n        !*/\n\n        double operator()(\n            const double measured_position\n        );\n        /*!\n            ensures\n                - Updates the Kalman filter with the new measured position of the object\n                  and returns the new filtered estimate of the object's position, now that\n                  we have seen the latest measured position.\n                - #get_predicted_next_position() == the prediction for the *next* place we\n                  will see the object. That is, where we think it will be in the future\n                  rather than where it is now.\n        !*/\n\n        double get_predicted_next_position (\n        ) const;\n        /*!\n            ensures\n                - Returns the Kalman filter's estimate of the next position we will see the object. \n        !*/\n    };\n\n    std::ostream& operator << (std::ostream& out, const momentum_filter& item);\n    void serialize(const momentum_filter& item, std::ostream& out);\n    void deserialize(momentum_filter& item, std::istream& in);\n    /*!\n        Provide printing and serialization support.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<std::vector<double>>& sequences,\n        const double smoothness = 1\n    );\n    /*!\n        requires\n            - sequences.size() != 0\n            - for all valid i: sequences[i].size() > 4\n            - smoothness >= 0\n        ensures\n            - This function finds the \"optimal\" settings of a momentum_filter based on\n              recorded measurement data stored in sequences.  Here we assume that each\n              vector in sequences is a complete track history of some object's measured\n              positions.  What we do is find the momentum_filter that minimizes the\n              following objective function:\n                 sum of abs(predicted_location[i] - measured_location[i]) + smoothness*abs(filtered_location[i]-filtered_location[i-1])\n                 Where i is a time index.\n              The sum runs over all the data in sequences.  So what we do is find the\n              filter settings that produce smooth filtered trajectories but also produce\n              filtered outputs that are as close to the measured positions as possible.\n              The larger the value of smoothness the less jittery the filter outputs will\n              be, but they might become biased or laggy if smoothness is set really high. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    momentum_filter find_optimal_momentum_filter (\n        const std::vector<double>& sequence,\n        const double smoothness = 1\n    );\n    /*!\n        requires\n            - sequence.size() > 4\n            - smoothness >= 0\n        ensures\n            - performs: find_optimal_momentum_filter({1,sequence}, smoothness);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class rect_filter\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object simply contains four momentum_filters and applies them to the\n                4 components of a dlib::rectangle's position.  It therefore allows you to\n                easily filter a sequence of rectangles.  For instance, it can be used to\n                smooth the output of an object detector running on a video.\n        !*/\n\n    public:\n        rect_filter(\n        ) = default;\n        /*!\n            ensures\n                - The four momentum_filters in this object are default initialized.\n        !*/\n\n        rect_filter(\n            const momentum_filter& filt\n        );\n        /*!\n            ensures\n                - #get_left() == filt\n                - #get_top() == filt\n                - #get_right() == filt\n                - #get_bottom() == filt\n        !*/\n\n        rect_filter(\n            double meas_noise,\n            double acc,\n            double max_meas_dev\n        ) : rect_filter(momentum_filter(meas_noise, acc, max_meas_dev)) {}\n        /*!\n            requires\n                - meas_noise >= 0\n                - acc >= 0\n                - max_meas_dev >= 0\n            ensures\n                - Initializes this object with momentum_filter(meas_noise, acc, max_meas_dev)\n        !*/\n\n        drectangle operator()(\n            const drectangle& r\n        );\n        /*!\n            ensures\n                - Runs the given rectangle through the momentum_filters and returns the\n                  filtered rectangle location.  That is, performs:\n                  return drectangle(get_left()(r.left()),\n                                    get_top()(r.top()),\n                                    get_right()(r.right()),\n                                    get_bottom()(r.bottom()));\n        !*/\n\n        drectangle operator()(\n            const rectangle& r\n        ); \n        /*!\n            ensures\n                - Runs the given rectangle through the momentum_filters and returns the\n                  filtered rectangle location.  That is, performs:\n                  return drectangle(get_left()(r.left()),\n                                    get_top()(r.top()),\n                                    get_right()(r.right()),\n                                    get_bottom()(r.bottom()));\n        !*/\n\n        const momentum_filter& get_left() const; \n        momentum_filter&       get_left();\n        const momentum_filter& get_top() const; \n        momentum_filter&       get_top();\n        const momentum_filter& get_right() const; \n        momentum_filter&       get_right();\n        const momentum_filter& get_bottom() const;\n        momentum_filter&       get_bottom(); \n        /*!\n            Provides access to the 4 momentum_filters used to filter the 4 coordinates that define a rectangle.\n        !*/\n    };\n\n    void serialize(const rect_filter& item, std::ostream& out);\n    void deserialize(rect_filter& item, std::istream& in);\n    /*!\n        Provide serialization support.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    rect_filter find_optimal_rect_filter (\n        const std::vector<rectangle>& rects,\n        const double smoothness = 1\n    );\n    /*!\n        requires\n            - rects.size() > 4\n            - smoothness >= 0\n        ensures\n            - This routine simply invokes find_optimal_momentum_filter() to find the\n              momentum_filter that works best on the provided sequence of rectangles.  It\n              then constructs a rect_filter using that momentum_filter and returns it.\n              Therefore, this routine finds the rect_filter that is \"optimal\" for filtering\n              the given sequence of rectangles.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_KALMAN_FiLTER_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/filtering/rls_filter.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RLS_FiLTER_Hh_\n#define DLIB_RLS_FiLTER_Hh_\n\n#include \"rls_filter_abstract.h\"\n#include \"../svm/rls.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include \"../sliding_buffer.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class rls_filter\n    {\n        /*!\n            CONVENTION\n                - data.size() == the number of variables in a measurement \n                - data[i].size() == data[j].size() for all i and j.  \n                - data[i].size() == get_window_size() \n                - data[i][0] == most recent measurement of i-th variable given to update.\n                - data[i].back() == oldest measurement of i-th variable given to update \n                  (or zero if we haven't seen this much data yet).\n\n                - if (count <= 2) then\n                    - count == number of times update(z) has been called\n        !*/\n    public:\n\n        rls_filter()\n        {\n            size = 5;\n            count = 0;\n            filter = rls(0.8, 100);\n        }\n\n        explicit rls_filter (\n            unsigned long size_,\n            double forget_factor = 0.8,\n            double C = 100\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(0 < forget_factor && forget_factor <= 1 &&\n                        0 < C && size_ >= 2,\n                \"\\t rls_filter::rls_filter()\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t forget_factor: \" << forget_factor \n                << \"\\n\\t C:     \" << C \n                << \"\\n\\t size_: \" << size_\n                << \"\\n\\t this: \" << this\n                );\n\n            size = size_;\n            count = 0;\n            filter = rls(forget_factor, C);\n        }\n\n        double get_c(\n        ) const\n        {\n            return filter.get_c();\n        }\n\n        double get_forget_factor(\n        ) const\n        {\n            return filter.get_forget_factor();\n        }\n\n        unsigned long get_window_size (\n        ) const\n        {\n            return size;\n        }\n\n        void update (\n        )\n        {\n            if (filter.get_w().size() == 0)\n                return;\n\n            for (unsigned long i = 0; i < data.size(); ++i)\n            {\n                // Put old predicted value into the circular buffer as if it was \n                // the measurement we just observed.  But don't update the rls filter.\n                data[i].push_front(next(i));\n            }\n\n            // predict next state\n            for (long i = 0; i < next.size(); ++i)\n                next(i) = filter(mat(data[i]));\n        }\n\n        template <typename EXP>\n        void update (\n            const matrix_exp<EXP>& z\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_col_vector(z) == true &&\n                        z.size() != 0 &&\n                        (get_predicted_next_state().size()==0 || z.size()==get_predicted_next_state().size()),\n                \"\\t void rls_filter::update(z)\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t is_col_vector(z): \" << is_col_vector(z) \n                << \"\\n\\t z.size():         \" << z.size()\n                << \"\\n\\t get_predicted_next_state().size(): \" << get_predicted_next_state().size()\n                << \"\\n\\t this: \" << this\n                );\n\n            // initialize data if necessary \n            if (data.size() == 0)\n            {\n                data.resize(z.size());\n                for (long i = 0; i < z.size(); ++i)\n                    data[i].assign(size, 0);\n            }\n\n\n            for (unsigned long i = 0; i < data.size(); ++i)\n            {\n                // Once there is some stuff in the circular buffer, start\n                // showing it to the rls filter so it can do its thing.\n                if (count >= 2)\n                {\n                    filter.train(mat(data[i]), z(i));\n                }\n\n                // keep track of the measurements in our circular buffer\n                data[i].push_front(z(i));\n            }\n\n            // Don't bother with the filter until we have seen two samples\n            if (count >= 2)\n            {\n                // predict next state\n                for (long i = 0; i < z.size(); ++i)\n                    next(i) = filter(mat(data[i]));\n            }\n            else\n            {\n                // Use current measurement as the next state prediction\n                // since we don't know any better at this point.\n                ++count;\n                next = matrix_cast<double>(z);\n            }\n        }\n\n        const matrix<double,0,1>& get_predicted_next_state(\n        ) const\n        {\n            return next;\n        }\n\n        friend inline void serialize(const rls_filter& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.count, out);\n            serialize(item.size, out);\n            serialize(item.filter, out);\n            serialize(item.next, out);\n            serialize(item.data, out);\n        }\n\n        friend inline void deserialize(rls_filter& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw dlib::serialization_error(\"Unknown version number found while deserializing rls_filter object.\");\n\n            deserialize(item.count, in);\n            deserialize(item.size, in);\n            deserialize(item.filter, in);\n            deserialize(item.next, in);\n            deserialize(item.data, in);\n        }\n\n    private:\n\n        unsigned long count;\n        unsigned long size;\n        rls filter;\n        matrix<double,0,1> next;\n        std::vector<circular_buffer<double> > data;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RLS_FiLTER_Hh_\n\n"
  },
  {
    "path": "dlib/filtering/rls_filter_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RLS_FiLTER_ABSTRACT_Hh_\n#ifdef DLIB_RLS_FiLTER_ABSTRACT_Hh_\n\n#include \"../svm/rls_abstract.h\"\n#include \"../matrix/matrix_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class rls_filter\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for doing time series prediction using linear \n                recursive least squares.  In particular, this object takes a sequence \n                of points from the user and, at each step, attempts to predict the \n                value of the next point.  \n\n                To accomplish this, this object maintains a fixed size buffer of recent \n                points.  Each prediction is a linear combination of the points in this \n                history buffer.  It uses the recursive least squares algorithm to \n                determine how to best combine the contents of the history buffer to\n                predict each point.  Therefore, each time update() is called with\n                a point, recursive least squares updates the linear combination weights,\n                and then it inserts the point into the history buffer.  After that, the \n                next prediction is based on these updated weights and the current history \n                buffer.\n        !*/\n\n    public:\n\n        rls_filter(\n        );\n        /*!\n            ensures\n                - #get_window_size() == 5\n                - #get_forget_factor() == 0.8\n                - #get_c() == 100\n                - #get_predicted_next_state().size() == 0\n        !*/\n\n        explicit rls_filter (\n            unsigned long size,\n            double forget_factor = 0.8,\n            double C = 100\n        );\n        /*!\n            requires\n                - 0 < forget_factor <= 1\n                - 0 < C\n                - size >= 2\n            ensures\n                - #get_window_size() == size\n                - #get_forget_factor() == forget_factor\n                - #get_c() == C\n                - #get_predicted_next_state().size() == 0\n        !*/\n\n        double get_c(\n        ) const;\n        /*!\n            ensures\n                - returns the regularization parameter.  It is the parameter that determines \n                  the trade-off between trying to fit the data points given to update() or \n                  allowing more errors but hopefully improving the generalization of the \n                  predictions.  Larger values encourage exact fitting while smaller values \n                  of C may encourage better generalization. \n        !*/\n\n        double get_forget_factor(\n        ) const;\n        /*!\n            ensures\n                - This object uses exponential forgetting in its implementation of recursive \n                  least squares.  Therefore, this function returns the \"forget factor\". \n                - if (get_forget_factor() == 1) then\n                    - In this case, exponential forgetting is disabled.\n                    - The recursive least squares algorithm will implicitly take all previous\n                      calls to update(z) into account when estimating the optimal weights for\n                      linearly combining the history buffer into a prediction of the next point.\n                - else\n                    - Old calls to update(z) are eventually forgotten.  That is, the smaller\n                      the forget factor, the less recursive least squares will care about \n                      attempting to find linear combination weights which would have make \n                      good predictions on old points.  It will care more about fitting recent \n                      points.  This is appropriate if the statistical properties of the time \n                      series we are modeling are not constant.\n        !*/\n\n        unsigned long get_window_size (\n        ) const;\n        /*!\n            ensures\n                - returns the size of the history buffer.  This is the number of points which are\n                  linearly combined to make the predictions returned by get_predicted_next_state().\n        !*/\n\n        void update (\n        );\n        /*!\n            ensures\n                - Propagates the prediction forward in time.\n                - In particular, the value in get_predicted_next_state() is inserted\n                  into the history buffer and then the next prediction is estimated \n                  based on this updated history buffer.\n                - #get_predicted_next_state() == the prediction for the next point\n                  in the time series.\n        !*/\n\n        template <typename EXP>\n        void update (\n            const matrix_exp<EXP>& z\n        );\n        /*!\n            requires\n                - is_col_vector(z) == true\n                - z.size() != 0\n                - if (get_predicted_next_state().size() != 0) then\n                    - z.size() == get_predicted_next_state().size()\n                      (i.e. z must be the same size as all the previous z values given\n                      to this function)\n            ensures\n                - Updates the state of this filter based on the current measurement in z. \n                - In particular, the filter weights are updated and z is inserted into\n                  the history buffer.  Then the next prediction is estimated based on \n                  these updated weights and history buffer.\n                - #get_predicted_next_state() == the prediction for the next point\n                  in the time series.\n                - #get_predicted_next_state().size() == z.size()\n        !*/\n\n        const matrix<double,0,1>& get_predicted_next_state(\n        ) const;\n        /*!\n            ensures\n                - returns the estimate of the next point we will observe in the\n                  time series data.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const rls_filter& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        rls_filter& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n\n}\n\n#endif // DLIB_RLS_FiLTER_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/filtering.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FILTERiNG_HEADER\n#define DLIB_FILTERiNG_HEADER\n\n#include \"filtering/kalman_filter.h\"\n#include \"filtering/rls_filter.h\"\n\n#endif // DLIB_FILTERiNG_HEADER\n\n\n\n"
  },
  {
    "path": "dlib/float_details.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FLOAT_DEtAILS_Hh_\n#define DLIB_FLOAT_DEtAILS_Hh_\n\n#include <cmath>\n#include \"algs.h\"\n#include <limits> \n\nnamespace dlib\n{\n    struct float_details\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for converting floating point numbers into an\n                explicit integer representation and then also converting back.  In\n                particular, a float_details object represents a floating point number with\n                a 64 bit mantissa and 16 bit exponent.  These are stored in the public\n                fields of the same names.\n\n                The main use of this object is to convert floating point values into a\n                known uniform representation so they can be serialized to an output stream.\n                This allows dlib serialization code to work on any system, regardless of\n                the floating point representation used by the hardware.  It also means\n                that, for example, a double can be serialized and then deserialized into a\n                float and it will perform the appropriate conversion.\n\n\n                In more detail, this object represents a floating point value equal to\n                mantissa*pow(2,exponent), except when exponent takes on any of the\n                following special values: \n                    - is_inf\n                    - is_ninf\n                    - is_nan\n                These values are used to indicate that the floating point value should be\n                either infinity, negative infinity, or not-a-number respectively.\n        !*/\n\n        float_details(\n            int64 man,\n            int16 exp\n        ) : mantissa(man), exponent(exp) {}\n        /*!\n            ensures\n                - #mantissa == man\n                - #exponent == exp\n        !*/\n\n        float_details() :\n            mantissa(0), exponent(0)\n        {}\n        /*!\n            ensures\n                - this object represents a floating point value of 0\n        !*/\n\n        float_details ( const double&      val) { *this = val; }\n        float_details ( const float&       val) { *this = val; }\n        float_details ( const long double& val) { *this = val; }\n        /*!\n            ensures\n                - converts the given value into a float_details representation.  This \n                  means that converting #*this back into a floating point number should\n                  recover the input val.\n        !*/\n\n        float_details& operator= ( const double&      val) { convert_from_T(val); return *this; }\n        float_details& operator= ( const float&       val) { convert_from_T(val); return *this; }\n        float_details& operator= ( const long double& val) { convert_from_T(val); return *this; }\n        /*!\n            ensures\n                - converts the given value into a float_details representation.  This \n                  means that converting #*this back into a floating point number should\n                  recover the input val.\n        !*/\n\n        operator double      () const { return convert_to_T<double>(); }\n        operator float       () const { return convert_to_T<float>(); }\n        operator long double () const { return convert_to_T<long double>(); }\n        /*!\n            ensures\n                - converts the contents of this float_details object into a floating point number.\n        !*/\n\n        const static int16 is_inf  = 32000;\n        const static int16 is_ninf = 32001;\n        const static int16 is_nan  = 32002;\n\n        int64 mantissa;\n        int16 exponent;\n\n\n    private:\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                  IMPLEMENTATION DETAILS \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        void convert_from_T (\n            const T& val\n        )\n        {\n            mantissa = 0;\n\n            const int digits = dlib::tmin<std::numeric_limits<T>::digits, 63>::value;\n\n            if (val == std::numeric_limits<T>::infinity())\n            {\n                exponent = is_inf;\n            }\n            else if (val == -std::numeric_limits<T>::infinity())\n            {\n                exponent = is_ninf;\n            }\n            else if (val < std::numeric_limits<T>::infinity())\n            {\n                int exp;\n                mantissa = static_cast<int64>(std::frexp(val, &exp)*(((uint64)1)<<digits));\n                exponent = exp - digits;\n\n                // Compact the representation a bit by shifting off any low order bytes \n                // which are zero in the mantissa.  This makes the numbers in mantissa and\n                // exponent generally smaller which can make serialization and other things\n                // more efficient in some cases.\n                for (int i = 0; i < 8 && ((mantissa&0xFF)==0); ++i)\n                {\n                    mantissa >>= 8;\n                    exponent += 8;\n                }\n            }\n            else\n            {\n                exponent = is_nan;\n            }\n        }\n\n        template <typename T>\n        T convert_to_T (\n        ) const\n        {\n            if (exponent < is_inf)\n                return std::ldexp((T)mantissa, exponent);\n            else if (exponent == is_inf)\n                return std::numeric_limits<T>::infinity();\n            else if (exponent == is_ninf)\n                return -std::numeric_limits<T>::infinity();\n            else\n                return std::numeric_limits<T>::quiet_NaN();\n        }\n\n    };\n\n}\n\n#endif // DLIB_FLOAT_DEtAILS_Hh_\n\n"
  },
  {
    "path": "dlib/fstream",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/functional.h",
    "content": "// Copyright (C) 2021  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FUNCTIONAL_Hh_\n#define DLIB_FUNCTIONAL_Hh_\n\n#include <functional>\n#include \"type_traits.h\"\n#include \"utility.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail \n    {\n        template< typename T >\n        struct is_reference_wrapper : std::false_type {};\n        template< typename U >\n        struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};\n\n        template <\n            typename Base,\n            typename T,\n            typename Derived,\n            typename... Args\n        >\n        constexpr auto invoke_(\n            T Base::*pmf, //pointer to member function\n            Derived&& ref,\n            Args&&... args\n        )\n        noexcept(noexcept((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...)))\n        -> typename std::enable_if<\n                std::is_function<T>::value &&\n                std::is_base_of<Base, typename std::decay<Derived>::type>::value,\n                decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))\n           >::type\n        {\n            return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...);\n        }\n\n        template<\n            typename Base,\n            typename T,\n            typename RefWrap,\n            typename... Args\n        >\n        constexpr auto invoke_(\n            T Base::*pmf, //pointer to member function\n            RefWrap&& ref,\n            Args&&... args\n        )\n        noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...)))\n        -> typename std::enable_if<\n                std::is_function<T>::value &&\n                is_reference_wrapper<typename std::decay<RefWrap>::type>::value,\n                decltype((ref.get().*pmf)(std::forward<Args>(args)...))>::type\n        {\n            return (ref.get().*pmf)(std::forward<Args>(args)...);\n        }\n\n        template<\n            typename Base,\n            typename T,\n            typename Ptr,\n            typename... Args\n        >\n        constexpr auto invoke_(\n            T Base::*pmf, //pointer to member function\n            Ptr&& ptr,\n            Args&&... args\n        )\n        noexcept(noexcept(((*std::forward<Ptr>(ptr)).*pmf)( std::forward<Args>( args )...)))\n        -> typename std::enable_if<\n                std::is_function<T>::value &&\n                !is_reference_wrapper<typename std::decay<Ptr>::type>::value &&\n                !std::is_base_of<Base, typename std::decay<Ptr>::type>::value,\n                decltype(((*std::forward<Ptr>(ptr)).*pmf)(std::forward<Args>(args)...))>::type\n        {\n            return ((*std::forward<Ptr>(ptr)).*pmf)( std::forward<Args>( args )...);\n        }\n\n        template<\n            typename Base,\n            typename T,\n            typename Derived\n        >\n        constexpr auto invoke_(\n            T Base::*pmd, //pointer to member data\n            Derived&& ref\n        )\n        noexcept(noexcept(std::forward<Derived>(ref).*pmd))\n        -> typename std::enable_if<\n                std::is_object<T>::value &&\n                std::is_base_of<Base, typename std::decay<Derived>::type>::value,\n                decltype(std::forward<Derived>(ref).*pmd)>::type\n        {\n            return std::forward<Derived>(ref).*pmd;\n        }\n\n        template<\n            typename Base,\n            typename T,\n            typename RefWrap\n        >\n        constexpr auto invoke_(\n            T Base::*pmd, //pointer to member data\n            RefWrap&& ref\n        )\n        noexcept(noexcept(ref.get().*pmd))\n        -> typename std::enable_if<\n                std::is_object<T>::value &&\n                is_reference_wrapper<typename std::decay<RefWrap>::type>::value,\n                decltype(ref.get().*pmd)>::type\n        {\n            return ref.get().*pmd;\n        }\n\n        template<\n            typename Base,\n            typename T,\n            typename Ptr\n        >\n        constexpr auto invoke_(\n            T Base::*pmd, //pointer to member data\n            Ptr&& ptr\n        )\n        noexcept(noexcept((*std::forward<Ptr>(ptr)).*pmd))\n        -> typename std::enable_if<\n                std::is_object<T>::value &&\n                !is_reference_wrapper<typename std::decay<Ptr>::type>::value &&\n                !std::is_base_of<Base, typename std::decay<Ptr>::type>::value,\n                decltype((*std::forward<Ptr>(ptr)).*pmd)>::type\n        {\n            return (*std::forward<Ptr>(ptr)).*pmd;\n        }\n\n        template<\n            typename F,\n            typename... Args\n        >\n        constexpr auto invoke_(\n            F && f,\n            Args&&... args\n        )\n        noexcept(noexcept(std::forward<F>( f )( std::forward<Args>( args )...)))\n        -> typename std::enable_if<\n                !std::is_member_pointer<typename std::decay<F>::type>::value,\n                decltype(std::forward<F>(f)(std::forward<Args>(args)...))>::type\n        {\n            return std::forward<F>( f )( std::forward<Args>( args )...);\n        }\n    } // end namespace detail\n\n// ----------------------------------------------------------------------------------------\n    \n    template< typename F, typename... Args>\n    constexpr auto invoke(F && f, Args &&... args)\n    /*!\n        ensures\n            - identical to std::invoke(std::forward<F>(f), std::forward<Args>(args)...)\n            - works with C++11 onwards\n    !*/\n    noexcept(noexcept(detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...)))\n    -> decltype(detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...))\n    {\n        return detail::invoke_(std::forward<F>( f ), std::forward<Args>( args )...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n        template<class AlwaysVoid, class F, class... Args>\n        struct invoke_traits\n        {\n            static constexpr bool value{false};\n\n            template<class R>\n            using is_convertible = std::false_type;\n        };\n\n        template<class F, class... Args>\n        struct invoke_traits<void_t<decltype(dlib::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...>\n        {\n            static constexpr bool value{true};\n            using type = decltype(dlib::invoke(std::declval<F>(), std::declval<Args>()...));\n\n            template<class R>\n            using is_convertible = std::is_convertible<type, R>;\n        };\n    } // end namespace detail\n\n// ----------------------------------------------------------------------------------------\n\n    template< typename F, typename... Args >\n    struct invoke_result : detail::invoke_traits< void, F, Args...> {};\n    /*!\n        ensures\n            - identical to std::invoke_result<F, Args..>\n            - works with C++11 onwards\n    !*/\n\n    template< typename F, typename... Args >\n    using invoke_result_t = typename invoke_result<F, Args...>::type;\n    /*!\n        ensures\n            - identical to std::invoke_result_t<F, Args..>\n            - works with C++11 onwards\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template< typename F, typename... Args >\n    struct is_invocable : std::integral_constant<bool, detail::invoke_traits< void, F, Args...>::value> {};\n    /*!\n        ensures\n            - identical to std::is_invocable<F, Args..>\n            - works with C++11 onwards\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename R, typename F, typename... Args>\n    struct is_invocable_r : std::integral_constant<bool, detail::invoke_traits< void, F, Args...>::template is_convertible<R>::value> {};\n    /*!\n        ensures\n            - identical to std::is_invocable_r<R, F, Args..>\n            - works with C++11 onwards\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template< typename R, typename F, typename... Args>\n    constexpr typename std::enable_if<dlib::is_invocable_r<R, F, Args...>::value, R>::type\n    invoke_r(F && f, Args &&... args)\n    /*!\n        ensures\n            - identical to std::invoke_r<R>(std::forward<F>(f), std::forward<Args>(args)...)\n            - works with C++11 onwards\n    !*/\n    noexcept(noexcept(dlib::invoke(std::forward<F>( f ), std::forward<Args>( args )...)))\n    {\n        return dlib::invoke(std::forward<F>( f ), std::forward<Args>( args )...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n        template<typename F, typename Tuple, std::size_t... I>\n        constexpr auto apply_impl(F&& fn, Tuple&& tpl, index_sequence<I...>)\n        noexcept(noexcept(dlib::invoke(std::forward<F>(fn),\n                                       std::get<I>(std::forward<Tuple>(tpl))...)))\n        -> decltype(dlib::invoke(std::forward<F>(fn),\n                                 std::get<I>(std::forward<Tuple>(tpl))...))\n        {\n            return dlib::invoke(std::forward<F>(fn),\n                                std::get<I>(std::forward<Tuple>(tpl))...);\n        }\n    } // end namespace detail\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename F, typename Tuple>\n    constexpr auto apply(F&& fn, Tuple&& tpl)\n    /*!\n        ensures\n            - identical to std::apply(std::forward<F>(f), std::forward<Tuple>(tpl))\n            - works with C++11 onwards\n    !*/\n    noexcept(noexcept(detail::apply_impl(std::forward<F>(fn),\n                                         std::forward<Tuple>(tpl),\n                                         make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{})))\n    -> decltype(detail::apply_impl(std::forward<F>(fn),\n                                   std::forward<Tuple>(tpl),\n                                   make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{}))\n    {\n        return detail::apply_impl(std::forward<F>(fn),\n                                  std::forward<Tuple>(tpl),\n                                  make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{});\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n        template <class T, class Tuple, std::size_t... I>\n        constexpr T make_from_tuple_impl( Tuple&& t, index_sequence<I...> )\n        {\n            return T(std::get<I>(std::forward<Tuple>(t))...);\n        }\n    } // end namespace detail\n\n// ----------------------------------------------------------------------------------------\n\n    template <class T, class Tuple>\n    constexpr T make_from_tuple( Tuple&& t )\n    /*!\n        ensures\n            - identical to std::make_from_tuple<T>(std::forward<Tuple>(t))\n            - works with C++11 onwards\n    !*/\n    {\n        return detail::make_from_tuple_impl<T>(std::forward<Tuple>(t),\n                                               make_index_sequence<std::tuple_size<typename std::remove_reference<Tuple>::type >::value>{});\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace detail\n    {\n\n        template<class Binder, std::size_t ...I, class ...Rest>\n        constexpr static auto binder_run(\n            Binder&& self,\n            std::integral_constant<bool, false>,\n            index_sequence<I...>, \n            Rest&&... rest\n        ) noexcept(noexcept(dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...)))\n                -> decltype(dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...))\n        {\n            return dlib::invoke(std::forward<Binder>(self).func, std::get<I>(std::forward<Binder>(self).args)..., std::forward<Rest>(rest)...);\n        }\n\n        template<class Binder, std::size_t ...I, class ...Rest>\n        constexpr static auto binder_run(\n            Binder&& self,\n            std::integral_constant<bool, true>,\n            index_sequence<I...>, \n            Rest&&... rest\n        ) noexcept(noexcept(dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...)))\n                -> decltype(dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...))\n        {\n            return dlib::invoke(std::forward<Binder>(self).func, std::forward<Rest>(rest)..., std::get<I>(std::forward<Binder>(self).args)...);\n        }\n\n        template<bool Back, class F, class ...Args>\n        struct binder_wrapper\n        {\n            F                   func;\n            std::tuple<Args...> args;\n\n            template<class ...Rest>\n            constexpr auto operator()(Rest&&... rest) \n                noexcept(noexcept(binder_run(std::declval<binder_wrapper&>(), std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...)))\n                      -> decltype(binder_run(std::declval<binder_wrapper&>(), std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...))\n            {\n                return binder_run(*this, std::integral_constant<bool, Back>{}, index_sequence_for<Args...>{}, std::forward<Rest>(rest)...);\n            }\n        };\n\n        template<bool Back, class F, class... Args>\n        constexpr auto make_binder(\n            F&& func, \n            Args&&... args\n        )\n        {\n            return binder_wrapper<Back, std::decay_t<F>, std::decay_t<Args>...>{std::forward<F>(func), std::make_tuple(std::forward<Args>(args)...)};\n        }\n    }\n    \n    template<class F, class ...Args>\n    constexpr auto bind_front(\n        F&& func,\n        Args&&... args\n    ) noexcept(noexcept(detail::make_binder<false>(std::forward<F>(func), std::forward<Args>(args)...)))\n    /*!\n        ensures\n            - identical to std::bind_front()\n            - works with C++11 onwards\n    !*/\n    {\n        return detail::make_binder<false>(std::forward<F>(func), std::forward<Args>(args)...);\n    }\n\n    template<class F, class ...Args>\n    constexpr auto bind_back(\n        F&& func,\n        Args&&... args\n    ) noexcept(noexcept(detail::make_binder<true>(std::forward<F>(func), std::forward<Args>(args)...)))\n    /*!\n        ensures\n            - identical to std::bind_back()\n            - works with C++11 onwards\n    !*/\n    {\n        return detail::make_binder<true>(std::forward<F>(func), std::forward<Args>(args)...);\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif //DLIB_FUNCTIONAL_Hh_\n"
  },
  {
    "path": "dlib/general_hash/count_bits.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_COUNT_BiTS_Hh_\n#define DLIB_COUNT_BiTS_Hh_\n\n#include \"../algs.h\"\n#include <climits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    T count_bits (\n        T v\n    )\n    /*!\n        requires\n            - T is an unsigned integral type\n        ensures\n            - returns the number of bits in v which are set to 1.\n    !*/\n    {\n        COMPILE_TIME_ASSERT(is_unsigned_type<T>::value && sizeof(T) <= 8);\n\n        // This bit of bit trickery is from:\n        // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSet64\n\n        v = v - ((v >> 1) & (T)~(T)0/3);                           \n        v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      \n        v = (v + (v >> 4)) & (T)~(T)0/255*15;                      \n        return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    T hamming_distance (\n        const T& a,\n        const T& b\n    )\n    /*!\n        requires\n            - T is an unsigned integral type\n        ensures\n            - returns the number of bits which differ between a and b.\n    !*/\n    {\n        return count_bits(a^b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    T hamming_distance (\n        const std::pair<T,T>& a,\n        const std::pair<T,T>& b\n    )\n    /*!\n        requires\n            - T is an unsigned integral type or a std::pair that, recursively, eventually\n              contains unsigned integral types.\n        ensures\n            - returns the number of bits which differ between a and b.\n    !*/\n    {\n        return hamming_distance(a.first,b.first) + hamming_distance(a.second, b.second);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_COUNT_BiTS_Hh_\n\n"
  },
  {
    "path": "dlib/general_hash/count_bits_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_COUNT_BiTS_ABSTRACT_Hh_\n#ifdef DLIB_COUNT_BiTS_ABSTRACT_Hh_\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    T count_bits (\n        T v\n    );\n    /*!\n        requires\n            - T is an unsigned integral type\n        ensures\n            - returns the number of bits in v which are set to 1.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    T hamming_distance (\n        const T& a,\n        const T& b\n    );\n    /*!\n        requires\n            - T is an unsigned integral type\n        ensures\n            - returns the number of bits which differ between a and b.  (I.e. returns\n              count_bits(a^b).)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_COUNT_BiTS_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/general_hash/general_hash.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GENERAL_HASh_\n#define DLIB_GENERAL_HASh_\n\n\n#include <string>\n#include \"hash.h\"\n\nnamespace dlib \n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------- provide a general hashing function object ----------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class general_hash\n    {\n    public:\n        inline unsigned long operator() (\n            const T& item\n        ) const;\n    };\n    /*!\n        Note that the default behavior of general hash is to attempt to cast\n        an object of type T to an unsigned long and use that as the hash.\n\n        REQUIREMENTS ON general_hash\n            - must have a default constructor\n            - must be a function object which overloads operator() as follows:\n              unsigned long operator()(const T& item)             \n            - must take item, compute a hash number and return it \n            - must not throw\n            - must define the hash in such a way that all equivalent objects have \n              the same hash.  where equivalent means the following:\n                  definition of equivalent:\n                  a is equivalent to b if\n                  a < b == false and\n                  b < a == false\n    !*/\n\n// ---------------\n\n    template <\n        typename T\n        >\n    unsigned long general_hash<T>:: \n    operator() (\n        const T& item\n    ) const\n    {\n        // hash any types that have a conversion to uint64 \n        return hash(static_cast<uint64>(item));\n    }\n\n\n// ---------------\n\n    // std::string hash\n    template <>\n    inline unsigned long general_hash<std::string>:: \n    operator() (\n        const std::string& item\n    ) const\n    {\n        return hash(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GENERAL_HASh_\n\n"
  },
  {
    "path": "dlib/general_hash/hash.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HAsH_Hh_ \n#define DLIB_HAsH_Hh_ \n\n#include \"hash_abstract.h\"\n#include <vector>\n#include <string>\n#include <map>\n#include \"murmur_hash3.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        const std::string& item,\n        uint32 seed = 0\n    )\n    {\n        if (item.size() == 0)\n            return 0;\n        else\n            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        const std::wstring& item,\n        uint32 seed = 0\n    )\n    {\n        if (item.size() == 0)\n            return 0;\n        else\n            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc>\n    uint32 hash (\n        const std::vector<T,alloc>& item,\n        uint32 seed = 0\n    )\n    {\n        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);\n\n        if (item.size() == 0)\n            return 0;\n        else\n            return murmur_hash3(&item[0], sizeof(T)*item.size(), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename alloc>\n    uint32 hash (\n        const std::vector<std::pair<T,U>,alloc>& item,\n        uint32 seed = 0\n    )\n    {\n        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);\n        DLIB_ASSERT_HAS_STANDARD_LAYOUT(U);\n\n        if (item.size() == 0)\n            return 0;\n        else\n            return murmur_hash3(&item[0], sizeof(item[0])*item.size(), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename comp, typename alloc>\n    uint32 hash (\n        const std::map<T,U,comp,alloc>& item,\n        uint32 seed = 0\n    )\n    {\n        return hash(std::vector<std::pair<T,U> >(item.begin(), item.end()), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        uint32 val,\n        uint32 seed = 0\n    )\n    {\n        return murmur_hash3_2(val,seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        uint64 val,\n        uint32 seed = 0\n    )\n    {\n        return static_cast<uint32>(murmur_hash3_128bit_3(val,seed,0).first);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        const std::pair<uint64,uint64>& item,\n        uint32 seed = 0\n    )\n    {\n        return static_cast<uint32>(murmur_hash3_128bit_3(item.first,item.second,seed).first);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        const std::pair<uint32,uint32>& item,\n        uint32 seed = 0\n    )\n    {\n        return murmur_hash3_3(item.first,item.second,seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    uint32 hash (\n        const std::pair<T,U>& item,\n        uint32 seed = 0\n    )\n    {\n        return hash(item.first, seed) ^ hash(item.second, seed+1); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HAsH_Hh_\n\n"
  },
  {
    "path": "dlib/general_hash/hash_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HAsH_ABSTRACT_Hh_\n#ifdef DLIB_HAsH_ABSTRACT_Hh_ \n\n#include \"murmur_hash3_abstract.h\"\n#include <vector>\n#include <string>\n#include <map>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    uint32 hash (\n        const std::string& item,\n        uint32 seed = 0\n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - This routine will always give the same hash value when presented\n              with the same input string.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    uint32 hash (\n        const std::wstring& item,\n        uint32 seed = 0\n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - Note that if the memory layout of the elements in item change between\n              hardware platforms then hash() will give different outputs.  If you want\n              hash() to always give the same output for the same input then you must \n              ensure that elements of item always have the same layout in memory.\n              Typically this means using fixed width types and performing byte swapping\n              to account for endianness before passing item to hash().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc>\n    uint32 hash (\n        const std::vector<T,alloc>& item,\n        uint32 seed = 0\n    );\n    /*!\n        requires\n            - T is a standard layout type (e.g. a POD type like int, float, \n              or a simple struct).\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - Note that if the memory layout of the elements in item change between\n              hardware platforms then hash() will give different outputs.  If you want\n              hash() to always give the same output for the same input then you must \n              ensure that elements of item always have the same layout in memory.\n              Typically this means using fixed width types and performing byte swapping\n              to account for endianness before passing item to hash().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename alloc>\n    uint32 hash (\n        const std::vector<std::pair<T,U>,alloc>& item,\n        uint32 seed = 0\n    );\n    /*!\n        requires\n            - T and U are standard layout types (e.g. POD types like int, float, \n              or simple structs).\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - Note that if the memory layout of the elements in item change between\n              hardware platforms then hash() will give different outputs.  If you want\n              hash() to always give the same output for the same input then you must \n              ensure that elements of item always have the same layout in memory.\n              Typically this means using fixed width types and performing byte swapping\n              to account for endianness before passing item to hash().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename comp, typename alloc>\n    uint32 hash (\n        const std::map<T,U,comp,alloc>& item,\n        uint32 seed = 0\n    );\n    /*!\n        requires\n            - T and U are standard layout types (e.g. POD types like int, float, \n              or simple structs).\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - Note that if the memory layout of the elements in item change between\n              hardware platforms then hash() will give different outputs.  If you want\n              hash() to always give the same output for the same input then you must \n              ensure that elements of item always have the same layout in memory.\n              Typically this means using fixed width types and performing byte swapping\n              to account for endianness before passing item to hash().  However, since\n              you can't modify the keys in a map you may have to copy it into a \n              std::vector and then work from there.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        uint32 item,\n        uint32 seed = 0\n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3_2() routine to compute the actual hash.\n            - This routine will always give the same hash value when presented\n              with the same input.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 hash (\n        uint64 item,\n        uint32 seed = 0\n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3_128bit_3() routine to compute the actual hash.\n            - This routine will always give the same hash value when presented\n              with the same input.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    uint32 hash (\n        const std::pair<T,U>& item,\n        uint32 seed = 0\n    );\n    /*!\n        requires\n            - hash() is defined for objects of type T and U\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - if (calling hash() on items of type T and U is always guaranteed to give the\n              same hash values when presented with the same input) then\n                - This routine will always give the same hash value when presented\n                  with the same input.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HAsH_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/general_hash/murmur_hash3.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MURMUR_HAsH_3_Hh_ \n#define DLIB_MURMUR_HAsH_3_Hh_ \n\n#include \"murmur_hash3_abstract.h\"\n#include \"../uintn.h\"\n#include <utility>\n#include <string.h>\n\nnamespace dlib\n{\n    //-----------------------------------------------------------------------------\n    // The original MurmurHash3 code was written by Austin Appleby, and is placed \n    // in the public domain. The author hereby disclaims copyright to this source code.\n    // The code in this particular file was modified by Davis E. King.  In\n    // particular, endian-swapping was added along with some other minor code\n    // changes like avoiding strict aliasing violations.\n\n\n    //-----------------------------------------------------------------------------\n    // Platform-specific functions and macros\n\n    // Microsoft Visual Studio\n\n\n#if ((defined(__GNUC__) && __GNUC__ >= 7) || defined(__clang__))\n#define DLIB_FALLTHROUGH [[fallthrough]]\n#else\n#define DLIB_FALLTHROUGH \n#endif\n\n#if defined(_MSC_VER)\n\n#define DLIB_FORCE_INLINE\t__forceinline\n\n#include <stdlib.h>\n\n#define DLIB_ROTL32(x,y)\t_rotl(x,y)\n#define DLIB_ROTL64(x,y)\t_rotl64(x,y)\n\n#define DLIB_BIG_CONSTANT(x) (x)\n\n    // Other compilers\n\n#else\t// defined(_MSC_VER)\n\n#define\tDLIB_FORCE_INLINE __attribute__((always_inline)) inline \n\n    inline uint32 murmur_rotl32 ( uint32 x, int8 r )\n    {\n        return (x << r) | (x >> (32 - r));\n    }\n\n    inline uint64 murmur_rotl64 ( uint64 x, int8 r )\n    {\n        return (x << r) | (x >> (64 - r));\n    }\n\n#define\tDLIB_ROTL32(x,y)\tdlib::murmur_rotl32(x,y)\n#define DLIB_ROTL64(x,y)\tdlib::murmur_rotl64(x,y)\n\n#define DLIB_BIG_CONSTANT(x) (x##LLU)\n\n#endif // !defined(_MSC_VER)\n\n// ----------------------------------------------------------------------------------------\n    // Block read - if your platform needs to do endian-swapping or can only\n    // handle aligned reads, do the conversion here\n\n    DLIB_FORCE_INLINE uint32 murmur_getblock ( const uint32 * p, int i )\n    {\n        // The reason we do a memcpy() here instead of simply returning p[i] is because\n        // doing it this way avoids violations of the strict aliasing rule when all these\n        // functions are inlined into the user's code.\n        uint32 temp;\n        memcpy(&temp, p+i, 4);\n        return temp;\n    }\n\n    DLIB_FORCE_INLINE uint32 murmur_getblock_byte_swap ( const uint32 * p, int i )\n    {\n        union \n        {\n            uint8 bytes[4];\n            uint32 val;\n        } temp;\n\n        const uint8* pp = reinterpret_cast<const uint8*>(p + i);\n        temp.bytes[0] = pp[3];\n        temp.bytes[1] = pp[2];\n        temp.bytes[2] = pp[1];\n        temp.bytes[3] = pp[0];\n\n        return temp.val;\n    }\n\n    DLIB_FORCE_INLINE uint64 murmur_getblock ( const uint64 * p, int i )\n    {\n        // The reason we do a memcpy() here instead of simply returning p[i] is because\n        // doing it this way avoids violations of the strict aliasing rule when all these\n        // functions are inlined into the user's code.\n        uint64 temp;\n        memcpy(&temp, p+i, 8);\n        return temp;\n    }\n\n    DLIB_FORCE_INLINE uint64 murmur_getblock_byte_swap ( const uint64 * p, int i )\n    {\n        union \n        {\n            uint8 bytes[8];\n            uint64 val;\n        } temp;\n\n        const uint8* pp = reinterpret_cast<const uint8*>(p + i);\n        temp.bytes[0] = pp[7];\n        temp.bytes[1] = pp[6];\n        temp.bytes[2] = pp[5];\n        temp.bytes[3] = pp[4];\n        temp.bytes[4] = pp[3];\n        temp.bytes[5] = pp[2];\n        temp.bytes[6] = pp[1];\n        temp.bytes[7] = pp[0];\n\n        return temp.val;\n    }\n\n// ----------------------------------------------------------------------------------------\n    // Finalization mix - force all bits of a hash block to avalanche\n\n    DLIB_FORCE_INLINE uint32 murmur_fmix ( uint32 h )\n    {\n        h ^= h >> 16;\n        h *= 0x85ebca6b;\n        h ^= h >> 13;\n        h *= 0xc2b2ae35;\n        h ^= h >> 16;\n\n        return h;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    DLIB_FORCE_INLINE uint64 murmur_fmix ( uint64 k )\n    {\n        k ^= k >> 33;\n        k *= DLIB_BIG_CONSTANT(0xff51afd7ed558ccd);\n        k ^= k >> 33;\n        k *= DLIB_BIG_CONSTANT(0xc4ceb9fe1a85ec53);\n        k ^= k >> 33;\n\n        return k;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 murmur_hash3 ( \n        const void * key, \n        const int len, \n        const uint32 seed = 0\n    )\n    {\n        const uint8 * data = (const uint8*)key;\n        const int nblocks = len / 4;\n\n        uint32 h1 = seed;\n\n        uint32 c1 = 0xcc9e2d51;\n        uint32 c2 = 0x1b873593;\n\n        //----------\n        // body\n\n        const uint32 * blocks = (const uint32 *)(data + nblocks*4);\n\n        bool is_little_endian = true;\n        uint32 endian_test = 1;\n        if (*reinterpret_cast<unsigned char*>(&endian_test) != 1)\n            is_little_endian = false;\n\n\n        if (is_little_endian)\n        {\n            for(int i = -nblocks; i; i++)\n            {\n                uint32 k1 = murmur_getblock(blocks,i);\n\n                k1 *= c1;\n                k1 = DLIB_ROTL32(k1,15);\n                k1 *= c2;\n\n                h1 ^= k1;\n                h1 = DLIB_ROTL32(h1,13); \n                h1 = h1*5+0xe6546b64;\n            }\n        }\n        else\n        {\n            for(int i = -nblocks; i; i++)\n            {\n                uint32 k1 = murmur_getblock_byte_swap(blocks,i);\n\n                k1 *= c1;\n                k1 = DLIB_ROTL32(k1,15);\n                k1 *= c2;\n\n                h1 ^= k1;\n                h1 = DLIB_ROTL32(h1,13); \n                h1 = h1*5+0xe6546b64;\n            }\n        }\n\n        //----------\n        // tail\n\n        const uint8 * tail = (const uint8*)(data + nblocks*4);\n\n        uint32 k1 = 0;\n\n        switch(len & 3)\n        {\n            case 3: k1 ^= tail[2] << 16;\n                    DLIB_FALLTHROUGH; // fall through\n            case 2: k1 ^= tail[1] << 8;\n                    DLIB_FALLTHROUGH; // fall through\n            case 1: k1 ^= tail[0];\n                    k1 *= c1; k1 = DLIB_ROTL32(k1,15); k1 *= c2; h1 ^= k1;\n        };\n\n        //----------\n        // finalization\n\n        h1 ^= len;\n\n        h1 = murmur_fmix(h1);\n\n        return h1;\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 murmur_hash3_2 ( \n        const uint32 v1,\n        const uint32 v2 \n    )\n    {\n        uint32 h1 = v2;\n\n        uint32 c1 = 0xcc9e2d51;\n        uint32 c2 = 0x1b873593;\n\n        //----------\n        // body\n\n\n        uint32 k1 = v1;\n\n        k1 *= c1;\n        k1 = DLIB_ROTL32(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = DLIB_ROTL32(h1,13); \n        h1 = h1*5+0xe6546b64;\n\n\n        //----------\n        // finalization\n\n        h1 ^= 4; // =^ by length in bytes\n\n        h1 = murmur_fmix(h1);\n\n        return h1;\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 murmur_hash3_3 ( \n        const uint32 v1,\n        const uint32 v2, \n        const uint32 v3 \n    )\n    {\n\n        uint32 h1 = v3;\n\n        uint32 c1 = 0xcc9e2d51;\n        uint32 c2 = 0x1b873593;\n\n        //----------\n        // body\n\n\n        uint32 k1 = v1;\n\n        k1 *= c1;\n        k1 = DLIB_ROTL32(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = DLIB_ROTL32(h1,13); \n        h1 = h1*5+0xe6546b64;\n\n        k1 = v2;\n        k1 *= c1;\n        k1 = DLIB_ROTL32(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = DLIB_ROTL32(h1,13); \n        h1 = h1*5+0xe6546b64;\n\n        //----------\n        // finalization\n\n        h1 ^= 8; // =^ by length in bytes\n\n        h1 = murmur_fmix(h1);\n\n        return h1;\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    inline std::pair<uint64,uint64> murmur_hash3_128bit ( \n        const void* key, \n        const int len,\n        const uint64 seed = 0\n    )\n    {\n        const uint8 * data = (const uint8*)key;\n        const int nblocks = len / 16;\n\n        uint64 h1 = seed;\n        uint64 h2 = seed;\n\n        uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);\n        uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);\n\n        //----------\n        // body\n\n        const uint64 * blocks = (const uint64 *)(data);\n\n        bool is_little_endian = true;\n        uint32 endian_test = 1;\n        if (*reinterpret_cast<unsigned char*>(&endian_test) != 1)\n            is_little_endian = false;\n\n\n        if (is_little_endian)\n        {\n            for(int i = 0; i < nblocks; i++)\n            {\n                uint64 k1 = murmur_getblock(blocks,i*2+0);\n                uint64 k2 = murmur_getblock(blocks,i*2+1);\n\n                k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;\n\n                h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;\n\n                k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;\n\n                h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;\n            }\n        }\n        else\n        {\n            for(int i = 0; i < nblocks; i++)\n            {\n                uint64 k1 = murmur_getblock_byte_swap(blocks,i*2+0);\n                uint64 k2 = murmur_getblock_byte_swap(blocks,i*2+1);\n\n                k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;\n\n                h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;\n\n                k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;\n\n                h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;\n            }\n        }\n\n        //----------\n        // tail\n\n        const uint8 * tail = (const uint8*)(data + nblocks*16);\n\n        uint64 k1 = 0;\n        uint64 k2 = 0;\n\n        switch(len & 15)\n        {\n            case 15: k2 ^= uint64(tail[14]) << 48; DLIB_FALLTHROUGH; // fall through\n            case 14: k2 ^= uint64(tail[13]) << 40; DLIB_FALLTHROUGH; // fall through\n            case 13: k2 ^= uint64(tail[12]) << 32; DLIB_FALLTHROUGH; // fall through\n            case 12: k2 ^= uint64(tail[11]) << 24; DLIB_FALLTHROUGH; // fall through\n            case 11: k2 ^= uint64(tail[10]) << 16; DLIB_FALLTHROUGH; // fall through\n            case 10: k2 ^= uint64(tail[ 9]) << 8; DLIB_FALLTHROUGH; // fall through\n            case  9: k2 ^= uint64(tail[ 8]) << 0;\n                     k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2; DLIB_FALLTHROUGH; // fall through\n\n            case  8: k1 ^= uint64(tail[ 7]) << 56; DLIB_FALLTHROUGH; // fall through\n            case  7: k1 ^= uint64(tail[ 6]) << 48; DLIB_FALLTHROUGH; // fall through\n            case  6: k1 ^= uint64(tail[ 5]) << 40; DLIB_FALLTHROUGH; // fall through\n            case  5: k1 ^= uint64(tail[ 4]) << 32; DLIB_FALLTHROUGH; // fall through\n            case  4: k1 ^= uint64(tail[ 3]) << 24; DLIB_FALLTHROUGH; // fall through\n            case  3: k1 ^= uint64(tail[ 2]) << 16; DLIB_FALLTHROUGH; // fall through\n            case  2: k1 ^= uint64(tail[ 1]) << 8; DLIB_FALLTHROUGH; // fall through\n            case  1: k1 ^= uint64(tail[ 0]) << 0;\n                     k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1; \n        };\n\n        //----------\n        // finalization\n\n        h1 ^= len; h2 ^= len;\n\n        h1 += h2;\n        h2 += h1;\n\n        h1 = murmur_fmix(h1);\n        h2 = murmur_fmix(h2);\n\n        h1 += h2;\n        h2 += h1;\n\n        return std::make_pair(h1,h2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::pair<uint64,uint64> murmur_hash3_128bit ( \n        const uint32& v1, \n        const uint32& v2, \n        const uint32& v3, \n        const uint32& v4 \n    )\n    {\n        uint64 h1 = 0;\n        uint64 h2 = 0;\n\n        const uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);\n        const uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);\n\n        //----------\n        // body\n\n        uint64 k1 = (static_cast<uint64>(v2)<<32)|v1; \n        uint64 k2 = (static_cast<uint64>(v4)<<32)|v3; \n\n        k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2;\n\n        h1 = DLIB_ROTL64(k1,27); h1 = h1*5+0x52dce729;\n\n        k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; \n\n        h2 = DLIB_ROTL64(k2,31); h2 += h1; h2 = h2*5+0x38495ab5;\n\n        //----------\n        // finalization\n\n        h1 ^= 16; h2 ^= 16;\n\n        h1 += h2;\n        h2 += h1;\n\n        h1 = murmur_fmix(h1);\n        h2 = murmur_fmix(h2);\n\n        h1 += h2;\n        h2 += h1;\n\n        return std::make_pair(h1,h2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::pair<uint64,uint64> murmur_hash3_128bit_3 ( \n        uint64 k1, \n        uint64 k2,\n        uint64 k3 \n    )\n    {\n        uint64 h1 = k3;\n        uint64 h2 = k3;\n\n        const uint64 c1 = DLIB_BIG_CONSTANT(0x87c37b91114253d5);\n        const uint64 c2 = DLIB_BIG_CONSTANT(0x4cf5ad432745937f);\n\n        //----------\n        // body\n\n        k1 *= c1; k1  = DLIB_ROTL64(k1,31); k1 *= c2; h1 ^= k1;\n\n        h1 = DLIB_ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;\n\n        k2 *= c2; k2  = DLIB_ROTL64(k2,33); k2 *= c1; h2 ^= k2;\n\n        h2 = DLIB_ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;\n\n        //----------\n        // finalization\n\n        h1 ^= 16; h2 ^= 16;\n\n        h1 += h2;\n        h2 += h1;\n\n        h1 = murmur_fmix(h1);\n        h2 = murmur_fmix(h2);\n\n        h1 += h2;\n        h2 += h1;\n\n        return std::make_pair(h1,h2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MURMUR_HAsH_3_Hh_\n\n"
  },
  {
    "path": "dlib/general_hash/murmur_hash3_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_ \n#ifdef DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_ \n\n#include \"../uintn.h\"\n#include <utility>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    uint32 murmur_hash3 ( \n        const void* key, \n        const int len, \n        const uint32 seed = 0\n    );\n    /*!\n        requires\n            - key == a pointer to a block of memory len bytes long\n        ensures\n            - returns a 32bit hash of the len bytes pointed to by key.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. murmur_hash3(key,len,0) should generally not be equal to murmur_hash3(key,len,1))\n            - This function is machine architecture agnostic and should always give the same\n              hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 murmur_hash3_2 ( \n        const uint32 v1,\n        const uint32 v2 \n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the two integers given to this function.  \n            - This function is machine architecture agnostic and should always give the same\n              hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline uint32 murmur_hash3_3 ( \n        const uint32 v1,\n        const uint32 v2,\n        const uint32 v3 \n    );\n    /*!\n        ensures\n            - returns a 32bit hash of the three integers given to this function.  \n            - This function is machine architecture agnostic and should always give the same\n              hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x86_32.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::pair<uint64,uint64> murmur_hash3_128bit ( \n        const void* key, \n        const int len,\n        const uint64 seed = 0\n    );\n    /*!\n        requires\n            - key == a pointer to a block of memory len bytes long\n        ensures\n            - returns a 128bit hash (as two 64bit numbers) of the len bytes pointed to by key.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. murmur_hash3_128bit(key,len,0) should generally not be equal to \n              murmur_hash3_128bit(key,len,1))\n            - This function is machine architecture agnostic and should always give the same\n              hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::pair<uint64,uint64> murmur_hash3_128bit ( \n        const uint32& v1, \n        const uint32& v2, \n        const uint32& v3, \n        const uint32& v4 \n    );\n    /*!\n        ensures\n            - returns a 128bit hash (as two 64bit numbers) of the 4 integers given to this\n              function. \n            - This function is machine architecture agnostic and should always give the\n              same hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::pair<uint64,uint64> murmur_hash3_128bit_3 ( \n        uint64 k1, \n        uint64 k2,\n        uint64 k3 \n    );\n    /*!\n        ensures\n            - returns a 128bit hash (as two 64bit numbers) of the 3 integers given to this\n              function. \n            - This function is machine architecture agnostic and should always give the\n              same hash value when presented with the same inputs.\n            - This hashing algorithm is Austin Appleby's excellent MurmurHash3_x64_128.  \n              See: http://code.google.com/p/smhasher/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MURMUR_HAsH_3_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/general_hash/random_hashing.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANDOM_HAsHING_Hh_ \n#define DLIB_RANDOM_HAsHING_Hh_ \n\n#include \"random_hashing_abstract.h\"\n#include \"murmur_hash3.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline double uniform_random_hash (\n        const uint64& k1,\n        const uint64& k2,\n        const uint64& k3\n    )\n    {\n        const std::pair<uint64,uint64> h = murmur_hash3_128bit_3(k1,k2,k3);\n        const uint64 mask = DLIB_BIG_CONSTANT(0xFFFFFFFFFF); \n        const double max = mask+1;\n        return static_cast<double>(h.first&mask)/max;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double gaussian_random_hash (\n        const uint64& k1,\n        const uint64& k2,\n        const uint64& k3\n    )\n    {\n        const std::pair<uint64,uint64> h = murmur_hash3_128bit_3(k1,k2,k3);\n\n        const static unsigned int max = 4096;\n\n        const static double logvals[max] = { \n        4.079, 3.905, 3.8, 3.723, 3.663, 3.613, 3.57, 3.532, 3.499, 3.468, \n        3.441, 3.416, 3.392, 3.37, 3.35, 3.33, 3.312, 3.295, 3.278, 3.263, \n        3.248, 3.233, 3.219, 3.206, 3.193, 3.181, 3.169, 3.158, 3.147, 3.136, \n        3.125, 3.115, 3.105, 3.096, 3.086, 3.077, 3.068, 3.059, 3.051, 3.043, \n        3.035, 3.027, 3.019, 3.011, 3.004, 2.996, 2.989, 2.982, 2.975, 2.968, \n        2.962, 2.955, 2.949, 2.942, 2.936, 2.93, 2.924, 2.918, 2.912, 2.906, \n        2.901, 2.895, 2.89, 2.884, 2.879, 2.873, 2.868, 2.863, 2.858, 2.853, \n        2.848, 2.843, 2.838, 2.833, 2.829, 2.824, 2.819, 2.815, 2.81, 2.806, \n        2.801, 2.797, 2.792, 2.788, 2.784, 2.78, 2.776, 2.771, 2.767, 2.763, \n        2.759, 2.755, 2.751, 2.748, 2.744, 2.74, 2.736, 2.732, 2.729, 2.725, \n        2.721, 2.718, 2.714, 2.71, 2.707, 2.703, 2.7, 2.697, 2.693, 2.69, \n        2.686, 2.683, 2.68, 2.676, 2.673, 2.67, 2.667, 2.663, 2.66, 2.657, \n        2.654, 2.651, 2.648, 2.645, 2.642, 2.639, 2.636, 2.633, 2.63, 2.627, \n        2.624, 2.621, 2.618, 2.615, 2.612, 2.61, 2.607, 2.604, 2.601, 2.599, \n        2.596, 2.593, 2.59, 2.588, 2.585, 2.582, 2.58, 2.577, 2.574, 2.572, \n        2.569, 2.567, 2.564, 2.562, 2.559, 2.557, 2.554, 2.552, 2.549, 2.547, \n        2.544, 2.542, 2.539, 2.537, 2.534, 2.532, 2.53, 2.527, 2.525, 2.523, \n        2.52, 2.518, 2.516, 2.513, 2.511, 2.509, 2.507, 2.504, 2.502, 2.5, \n        2.498, 2.495, 2.493, 2.491, 2.489, 2.487, 2.485, 2.482, 2.48, 2.478, \n        2.476, 2.474, 2.472, 2.47, 2.468, 2.466, 2.464, 2.462, 2.459, 2.457, \n        2.455, 2.453, 2.451, 2.449, 2.447, 2.445, 2.443, 2.441, 2.439, 2.437, \n        2.436, 2.434, 2.432, 2.43, 2.428, 2.426, 2.424, 2.422, 2.42, 2.418, \n        2.416, 2.415, 2.413, 2.411, 2.409, 2.407, 2.405, 2.404, 2.402, 2.4, \n        2.398, 2.396, 2.394, 2.393, 2.391, 2.389, 2.387, 2.386, 2.384, 2.382, \n        2.38, 2.379, 2.377, 2.375, 2.373, 2.372, 2.37, 2.368, 2.367, 2.365, \n        2.363, 2.361, 2.36, 2.358, 2.356, 2.355, 2.353, 2.352, 2.35, 2.348, \n        2.347, 2.345, 2.343, 2.342, 2.34, 2.338, 2.337, 2.335, 2.334, 2.332, \n        2.331, 2.329, 2.327, 2.326, 2.324, 2.323, 2.321, 2.32, 2.318, 2.316, \n        2.315, 2.313, 2.312, 2.31, 2.309, 2.307, 2.306, 2.304, 2.303, 2.301, \n        2.3, 2.298, 2.297, 2.295, 2.294, 2.292, 2.291, 2.289, 2.288, 2.286, \n        2.285, 2.284, 2.282, 2.281, 2.279, 2.278, 2.276, 2.275, 2.274, 2.272, \n        2.271, 2.269, 2.268, 2.266, 2.265, 2.264, 2.262, 2.261, 2.259, 2.258, \n        2.257, 2.255, 2.254, 2.253, 2.251, 2.25, 2.248, 2.247, 2.246, 2.244, \n        2.243, 2.242, 2.24, 2.239, 2.238, 2.236, 2.235, 2.234, 2.232, 2.231, \n        2.23, 2.228, 2.227, 2.226, 2.225, 2.223, 2.222, 2.221, 2.219, 2.218, \n        2.217, 2.215, 2.214, 2.213, 2.212, 2.21, 2.209, 2.208, 2.207, 2.205, \n        2.204, 2.203, 2.202, 2.2, 2.199, 2.198, 2.197, 2.195, 2.194, 2.193, \n        2.192, 2.19, 2.189, 2.188, 2.187, 2.185, 2.184, 2.183, 2.182, 2.181, \n        2.179, 2.178, 2.177, 2.176, 2.175, 2.173, 2.172, 2.171, 2.17, 2.169, \n        2.168, 2.166, 2.165, 2.164, 2.163, 2.162, 2.16, 2.159, 2.158, 2.157, \n        2.156, 2.155, 2.154, 2.152, 2.151, 2.15, 2.149, 2.148, 2.147, 2.146, \n        2.144, 2.143, 2.142, 2.141, 2.14, 2.139, 2.138, 2.136, 2.135, 2.134, \n        2.133, 2.132, 2.131, 2.13, 2.129, 2.128, 2.126, 2.125, 2.124, 2.123, \n        2.122, 2.121, 2.12, 2.119, 2.118, 2.117, 2.116, 2.114, 2.113, 2.112, \n        2.111, 2.11, 2.109, 2.108, 2.107, 2.106, 2.105, 2.104, 2.103, 2.102, \n        2.101, 2.1, 2.099, 2.097, 2.096, 2.095, 2.094, 2.093, 2.092, 2.091, \n        2.09, 2.089, 2.088, 2.087, 2.086, 2.085, 2.084, 2.083, 2.082, 2.081, \n        2.08, 2.079, 2.078, 2.077, 2.076, 2.075, 2.074, 2.073, 2.072, 2.071, \n        2.07, 2.069, 2.068, 2.067, 2.066, 2.065, 2.064, 2.063, 2.062, 2.061, \n        2.06, 2.059, 2.058, 2.057, 2.056, 2.055, 2.054, 2.053, 2.052, 2.051, \n        2.05, 2.049, 2.048, 2.047, 2.046, 2.045, 2.044, 2.043, 2.042, 2.041, \n        2.04, 2.039, 2.038, 2.037, 2.036, 2.036, 2.035, 2.034, 2.033, 2.032, \n        2.031, 2.03, 2.029, 2.028, 2.027, 2.026, 2.025, 2.024, 2.023, 2.022, \n        2.021, 2.02, 2.02, 2.019, 2.018, 2.017, 2.016, 2.015, 2.014, 2.013, \n        2.012, 2.011, 2.01, 2.009, 2.008, 2.008, 2.007, 2.006, 2.005, 2.004, \n        2.003, 2.002, 2.001, 2, 1.999, 1.998, 1.998, 1.997, 1.996, 1.995, \n        1.994, 1.993, 1.992, 1.991, 1.99, 1.99, 1.989, 1.988, 1.987, 1.986, \n        1.985, 1.984, 1.983, 1.982, 1.982, 1.981, 1.98, 1.979, 1.978, 1.977, \n        1.976, 1.975, 1.975, 1.974, 1.973, 1.972, 1.971, 1.97, 1.969, 1.969, \n        1.968, 1.967, 1.966, 1.965, 1.964, 1.963, 1.963, 1.962, 1.961, 1.96, \n        1.959, 1.958, 1.957, 1.957, 1.956, 1.955, 1.954, 1.953, 1.952, 1.952, \n        1.951, 1.95, 1.949, 1.948, 1.947, 1.947, 1.946, 1.945, 1.944, 1.943, \n        1.942, 1.942, 1.941, 1.94, 1.939, 1.938, 1.937, 1.937, 1.936, 1.935, \n        1.934, 1.933, 1.933, 1.932, 1.931, 1.93, 1.929, 1.928, 1.928, 1.927, \n        1.926, 1.925, 1.924, 1.924, 1.923, 1.922, 1.921, 1.92, 1.92, 1.919, \n        1.918, 1.917, 1.916, 1.916, 1.915, 1.914, 1.913, 1.912, 1.912, 1.911, \n        1.91, 1.909, 1.908, 1.908, 1.907, 1.906, 1.905, 1.904, 1.904, 1.903, \n        1.902, 1.901, 1.901, 1.9, 1.899, 1.898, 1.897, 1.897, 1.896, 1.895, \n        1.894, 1.894, 1.893, 1.892, 1.891, 1.89, 1.89, 1.889, 1.888, 1.887, \n        1.887, 1.886, 1.885, 1.884, 1.884, 1.883, 1.882, 1.881, 1.88, 1.88, \n        1.879, 1.878, 1.877, 1.877, 1.876, 1.875, 1.874, 1.874, 1.873, 1.872, \n        1.871, 1.871, 1.87, 1.869, 1.868, 1.868, 1.867, 1.866, 1.865, 1.865, \n        1.864, 1.863, 1.862, 1.862, 1.861, 1.86, 1.859, 1.859, 1.858, 1.857, \n        1.857, 1.856, 1.855, 1.854, 1.854, 1.853, 1.852, 1.851, 1.851, 1.85, \n        1.849, 1.848, 1.848, 1.847, 1.846, 1.846, 1.845, 1.844, 1.843, 1.843, \n        1.842, 1.841, 1.84, 1.84, 1.839, 1.838, 1.838, 1.837, 1.836, 1.835, \n        1.835, 1.834, 1.833, 1.833, 1.832, 1.831, 1.83, 1.83, 1.829, 1.828, \n        1.828, 1.827, 1.826, 1.825, 1.825, 1.824, 1.823, 1.823, 1.822, 1.821, \n        1.821, 1.82, 1.819, 1.818, 1.818, 1.817, 1.816, 1.816, 1.815, 1.814, \n        1.814, 1.813, 1.812, 1.811, 1.811, 1.81, 1.809, 1.809, 1.808, 1.807, \n        1.807, 1.806, 1.805, 1.805, 1.804, 1.803, 1.802, 1.802, 1.801, 1.8, \n        1.8, 1.799, 1.798, 1.798, 1.797, 1.796, 1.796, 1.795, 1.794, 1.794, \n        1.793, 1.792, 1.792, 1.791, 1.79, 1.79, 1.789, 1.788, 1.787, 1.787, \n        1.786, 1.785, 1.785, 1.784, 1.783, 1.783, 1.782, 1.781, 1.781, 1.78, \n        1.779, 1.779, 1.778, 1.777, 1.777, 1.776, 1.775, 1.775, 1.774, 1.773, \n        1.773, 1.772, 1.771, 1.771, 1.77, 1.769, 1.769, 1.768, 1.767, 1.767, \n        1.766, 1.766, 1.765, 1.764, 1.764, 1.763, 1.762, 1.762, 1.761, 1.76, \n        1.76, 1.759, 1.758, 1.758, 1.757, 1.756, 1.756, 1.755, 1.754, 1.754, \n        1.753, 1.752, 1.752, 1.751, 1.751, 1.75, 1.749, 1.749, 1.748, 1.747, \n        1.747, 1.746, 1.745, 1.745, 1.744, 1.743, 1.743, 1.742, 1.742, 1.741, \n        1.74, 1.74, 1.739, 1.738, 1.738, 1.737, 1.736, 1.736, 1.735, 1.735, \n        1.734, 1.733, 1.733, 1.732, 1.731, 1.731, 1.73, 1.729, 1.729, 1.728, \n        1.728, 1.727, 1.726, 1.726, 1.725, 1.724, 1.724, 1.723, 1.723, 1.722, \n        1.721, 1.721, 1.72, 1.719, 1.719, 1.718, 1.718, 1.717, 1.716, 1.716, \n        1.715, 1.715, 1.714, 1.713, 1.713, 1.712, 1.711, 1.711, 1.71, 1.71, \n        1.709, 1.708, 1.708, 1.707, 1.706, 1.706, 1.705, 1.705, 1.704, 1.703, \n        1.703, 1.702, 1.702, 1.701, 1.7, 1.7, 1.699, 1.699, 1.698, 1.697, \n        1.697, 1.696, 1.696, 1.695, 1.694, 1.694, 1.693, 1.692, 1.692, 1.691, \n        1.691, 1.69, 1.689, 1.689, 1.688, 1.688, 1.687, 1.686, 1.686, 1.685, \n        1.685, 1.684, 1.683, 1.683, 1.682, 1.682, 1.681, 1.68, 1.68, 1.679, \n        1.679, 1.678, 1.678, 1.677, 1.676, 1.676, 1.675, 1.675, 1.674, 1.673, \n        1.673, 1.672, 1.672, 1.671, 1.67, 1.67, 1.669, 1.669, 1.668, 1.667, \n        1.667, 1.666, 1.666, 1.665, 1.665, 1.664, 1.663, 1.663, 1.662, 1.662, \n        1.661, 1.66, 1.66, 1.659, 1.659, 1.658, 1.658, 1.657, 1.656, 1.656, \n        1.655, 1.655, 1.654, 1.653, 1.653, 1.652, 1.652, 1.651, 1.651, 1.65, \n        1.649, 1.649, 1.648, 1.648, 1.647, 1.647, 1.646, 1.645, 1.645, 1.644, \n        1.644, 1.643, 1.643, 1.642, 1.641, 1.641, 1.64, 1.64, 1.639, 1.639, \n        1.638, 1.637, 1.637, 1.636, 1.636, 1.635, 1.635, 1.634, 1.633, 1.633, \n        1.632, 1.632, 1.631, 1.631, 1.63, 1.629, 1.629, 1.628, 1.628, 1.627, \n        1.627, 1.626, 1.625, 1.625, 1.624, 1.624, 1.623, 1.623, 1.622, 1.622, \n        1.621, 1.62, 1.62, 1.619, 1.619, 1.618, 1.618, 1.617, 1.617, 1.616, \n        1.615, 1.615, 1.614, 1.614, 1.613, 1.613, 1.612, 1.612, 1.611, 1.61, \n        1.61, 1.609, 1.609, 1.608, 1.608, 1.607, 1.607, 1.606, 1.605, 1.605, \n        1.604, 1.604, 1.603, 1.603, 1.602, 1.602, 1.601, 1.6, 1.6, 1.599, \n        1.599, 1.598, 1.598, 1.597, 1.597, 1.596, 1.596, 1.595, 1.594, 1.594, \n        1.593, 1.593, 1.592, 1.592, 1.591, 1.591, 1.59, 1.59, 1.589, 1.588, \n        1.588, 1.587, 1.587, 1.586, 1.586, 1.585, 1.585, 1.584, 1.584, 1.583, \n        1.582, 1.582, 1.581, 1.581, 1.58, 1.58, 1.579, 1.579, 1.578, 1.578, \n        1.577, 1.577, 1.576, 1.576, 1.575, 1.574, 1.574, 1.573, 1.573, 1.572, \n        1.572, 1.571, 1.571, 1.57, 1.57, 1.569, 1.569, 1.568, 1.567, 1.567, \n        1.566, 1.566, 1.565, 1.565, 1.564, 1.564, 1.563, 1.563, 1.562, 1.562, \n        1.561, 1.561, 1.56, 1.56, 1.559, 1.558, 1.558, 1.557, 1.557, 1.556, \n        1.556, 1.555, 1.555, 1.554, 1.554, 1.553, 1.553, 1.552, 1.552, 1.551, \n        1.551, 1.55, 1.55, 1.549, 1.549, 1.548, 1.547, 1.547, 1.546, 1.546, \n        1.545, 1.545, 1.544, 1.544, 1.543, 1.543, 1.542, 1.542, 1.541, 1.541, \n        1.54, 1.54, 1.539, 1.539, 1.538, 1.538, 1.537, 1.537, 1.536, 1.536, \n        1.535, 1.534, 1.534, 1.533, 1.533, 1.532, 1.532, 1.531, 1.531, 1.53, \n        1.53, 1.529, 1.529, 1.528, 1.528, 1.527, 1.527, 1.526, 1.526, 1.525, \n        1.525, 1.524, 1.524, 1.523, 1.523, 1.522, 1.522, 1.521, 1.521, 1.52, \n        1.52, 1.519, 1.519, 1.518, 1.518, 1.517, 1.517, 1.516, 1.516, 1.515, \n        1.515, 1.514, 1.514, 1.513, 1.512, 1.512, 1.511, 1.511, 1.51, 1.51, \n        1.509, 1.509, 1.508, 1.508, 1.507, 1.507, 1.506, 1.506, 1.505, 1.505, \n        1.504, 1.504, 1.503, 1.503, 1.502, 1.502, 1.501, 1.501, 1.5, 1.5, \n        1.499, 1.499, 1.498, 1.498, 1.497, 1.497, 1.496, 1.496, 1.495, 1.495, \n        1.494, 1.494, 1.493, 1.493, 1.492, 1.492, 1.491, 1.491, 1.49, 1.49, \n        1.489, 1.489, 1.488, 1.488, 1.487, 1.487, 1.486, 1.486, 1.485, 1.485, \n        1.484, 1.484, 1.483, 1.483, 1.482, 1.482, 1.481, 1.481, 1.48, 1.48, \n        1.48, 1.479, 1.479, 1.478, 1.478, 1.477, 1.477, 1.476, 1.476, 1.475, \n        1.475, 1.474, 1.474, 1.473, 1.473, 1.472, 1.472, 1.471, 1.471, 1.47, \n        1.47, 1.469, 1.469, 1.468, 1.468, 1.467, 1.467, 1.466, 1.466, 1.465, \n        1.465, 1.464, 1.464, 1.463, 1.463, 1.462, 1.462, 1.461, 1.461, 1.46, \n        1.46, 1.459, 1.459, 1.458, 1.458, 1.458, 1.457, 1.457, 1.456, 1.456, \n        1.455, 1.455, 1.454, 1.454, 1.453, 1.453, 1.452, 1.452, 1.451, 1.451, \n        1.45, 1.45, 1.449, 1.449, 1.448, 1.448, 1.447, 1.447, 1.446, 1.446, \n        1.445, 1.445, 1.444, 1.444, 1.444, 1.443, 1.443, 1.442, 1.442, 1.441, \n        1.441, 1.44, 1.44, 1.439, 1.439, 1.438, 1.438, 1.437, 1.437, 1.436, \n        1.436, 1.435, 1.435, 1.434, 1.434, 1.434, 1.433, 1.433, 1.432, 1.432, \n        1.431, 1.431, 1.43, 1.43, 1.429, 1.429, 1.428, 1.428, 1.427, 1.427, \n        1.426, 1.426, 1.425, 1.425, 1.424, 1.424, 1.424, 1.423, 1.423, 1.422, \n        1.422, 1.421, 1.421, 1.42, 1.42, 1.419, 1.419, 1.418, 1.418, 1.417, \n        1.417, 1.416, 1.416, 1.416, 1.415, 1.415, 1.414, 1.414, 1.413, 1.413, \n        1.412, 1.412, 1.411, 1.411, 1.41, 1.41, 1.409, 1.409, 1.409, 1.408, \n        1.408, 1.407, 1.407, 1.406, 1.406, 1.405, 1.405, 1.404, 1.404, 1.403, \n        1.403, 1.402, 1.402, 1.402, 1.401, 1.401, 1.4, 1.4, 1.399, 1.399, \n        1.398, 1.398, 1.397, 1.397, 1.396, 1.396, 1.395, 1.395, 1.395, 1.394, \n        1.394, 1.393, 1.393, 1.392, 1.392, 1.391, 1.391, 1.39, 1.39, 1.389, \n        1.389, 1.389, 1.388, 1.388, 1.387, 1.387, 1.386, 1.386, 1.385, 1.385, \n        1.384, 1.384, 1.383, 1.383, 1.383, 1.382, 1.382, 1.381, 1.381, 1.38, \n        1.38, 1.379, 1.379, 1.378, 1.378, 1.378, 1.377, 1.377, 1.376, 1.376, \n        1.375, 1.375, 1.374, 1.374, 1.373, 1.373, 1.373, 1.372, 1.372, 1.371, \n        1.371, 1.37, 1.37, 1.369, 1.369, 1.368, 1.368, 1.367, 1.367, 1.367, \n        1.366, 1.366, 1.365, 1.365, 1.364, 1.364, 1.363, 1.363, 1.362, 1.362, \n        1.362, 1.361, 1.361, 1.36, 1.36, 1.359, 1.359, 1.358, 1.358, 1.358, \n        1.357, 1.357, 1.356, 1.356, 1.355, 1.355, 1.354, 1.354, 1.353, 1.353, \n        1.353, 1.352, 1.352, 1.351, 1.351, 1.35, 1.35, 1.349, 1.349, 1.349, \n        1.348, 1.348, 1.347, 1.347, 1.346, 1.346, 1.345, 1.345, 1.344, 1.344, \n        1.344, 1.343, 1.343, 1.342, 1.342, 1.341, 1.341, 1.34, 1.34, 1.34, \n        1.339, 1.339, 1.338, 1.338, 1.337, 1.337, 1.336, 1.336, 1.336, 1.335, \n        1.335, 1.334, 1.334, 1.333, 1.333, 1.332, 1.332, 1.332, 1.331, 1.331, \n        1.33, 1.33, 1.329, 1.329, 1.328, 1.328, 1.328, 1.327, 1.327, 1.326, \n        1.326, 1.325, 1.325, 1.324, 1.324, 1.324, 1.323, 1.323, 1.322, 1.322, \n        1.321, 1.321, 1.32, 1.32, 1.32, 1.319, 1.319, 1.318, 1.318, 1.317, \n        1.317, 1.316, 1.316, 1.316, 1.315, 1.315, 1.314, 1.314, 1.313, 1.313, \n        1.312, 1.312, 1.312, 1.311, 1.311, 1.31, 1.31, 1.309, 1.309, 1.309, \n        1.308, 1.308, 1.307, 1.307, 1.306, 1.306, 1.305, 1.305, 1.305, 1.304, \n        1.304, 1.303, 1.303, 1.302, 1.302, 1.302, 1.301, 1.301, 1.3, 1.3, \n        1.299, 1.299, 1.298, 1.298, 1.298, 1.297, 1.297, 1.296, 1.296, 1.295, \n        1.295, 1.295, 1.294, 1.294, 1.293, 1.293, 1.292, 1.292, 1.291, 1.291, \n        1.291, 1.29, 1.29, 1.289, 1.289, 1.288, 1.288, 1.288, 1.287, 1.287, \n        1.286, 1.286, 1.285, 1.285, 1.285, 1.284, 1.284, 1.283, 1.283, 1.282, \n        1.282, 1.281, 1.281, 1.281, 1.28, 1.28, 1.279, 1.279, 1.278, 1.278, \n        1.278, 1.277, 1.277, 1.276, 1.276, 1.275, 1.275, 1.275, 1.274, 1.274, \n        1.273, 1.273, 1.272, 1.272, 1.272, 1.271, 1.271, 1.27, 1.27, 1.269, \n        1.269, 1.269, 1.268, 1.268, 1.267, 1.267, 1.266, 1.266, 1.266, 1.265, \n        1.265, 1.264, 1.264, 1.263, 1.263, 1.263, 1.262, 1.262, 1.261, 1.261, \n        1.26, 1.26, 1.26, 1.259, 1.259, 1.258, 1.258, 1.257, 1.257, 1.257, \n        1.256, 1.256, 1.255, 1.255, 1.254, 1.254, 1.254, 1.253, 1.253, 1.252, \n        1.252, 1.251, 1.251, 1.251, 1.25, 1.25, 1.249, 1.249, 1.248, 1.248, \n        1.248, 1.247, 1.247, 1.246, 1.246, 1.245, 1.245, 1.245, 1.244, 1.244, \n        1.243, 1.243, 1.242, 1.242, 1.242, 1.241, 1.241, 1.24, 1.24, 1.239, \n        1.239, 1.239, 1.238, 1.238, 1.237, 1.237, 1.237, 1.236, 1.236, 1.235, \n        1.235, 1.234, 1.234, 1.234, 1.233, 1.233, 1.232, 1.232, 1.231, 1.231, \n        1.231, 1.23, 1.23, 1.229, 1.229, 1.228, 1.228, 1.228, 1.227, 1.227, \n        1.226, 1.226, 1.226, 1.225, 1.225, 1.224, 1.224, 1.223, 1.223, 1.223, \n        1.222, 1.222, 1.221, 1.221, 1.22, 1.22, 1.22, 1.219, 1.219, 1.218, \n        1.218, 1.218, 1.217, 1.217, 1.216, 1.216, 1.215, 1.215, 1.215, 1.214, \n        1.214, 1.213, 1.213, 1.212, 1.212, 1.212, 1.211, 1.211, 1.21, 1.21, \n        1.21, 1.209, 1.209, 1.208, 1.208, 1.207, 1.207, 1.207, 1.206, 1.206, \n        1.205, 1.205, 1.204, 1.204, 1.204, 1.203, 1.203, 1.202, 1.202, 1.202, \n        1.201, 1.201, 1.2, 1.2, 1.199, 1.199, 1.199, 1.198, 1.198, 1.197, \n        1.197, 1.197, 1.196, 1.196, 1.195, 1.195, 1.194, 1.194, 1.194, 1.193, \n        1.193, 1.192, 1.192, 1.192, 1.191, 1.191, 1.19, 1.19, 1.189, 1.189, \n        1.189, 1.188, 1.188, 1.187, 1.187, 1.187, 1.186, 1.186, 1.185, 1.185, \n        1.184, 1.184, 1.184, 1.183, 1.183, 1.182, 1.182, 1.182, 1.181, 1.181, \n        1.18, 1.18, 1.179, 1.179, 1.179, 1.178, 1.178, 1.177, 1.177, 1.177, \n        1.176, 1.176, 1.175, 1.175, 1.175, 1.174, 1.174, 1.173, 1.173, 1.172, \n        1.172, 1.172, 1.171, 1.171, 1.17, 1.17, 1.17, 1.169, 1.169, 1.168, \n        1.168, 1.167, 1.167, 1.167, 1.166, 1.166, 1.165, 1.165, 1.165, 1.164, \n        1.164, 1.163, 1.163, 1.163, 1.162, 1.162, 1.161, 1.161, 1.16, 1.16, \n        1.16, 1.159, 1.159, 1.158, 1.158, 1.158, 1.157, 1.157, 1.156, 1.156, \n        1.156, 1.155, 1.155, 1.154, 1.154, 1.153, 1.153, 1.153, 1.152, 1.152, \n        1.151, 1.151, 1.151, 1.15, 1.15, 1.149, 1.149, 1.149, 1.148, 1.148, \n        1.147, 1.147, 1.146, 1.146, 1.146, 1.145, 1.145, 1.144, 1.144, 1.144, \n        1.143, 1.143, 1.142, 1.142, 1.142, 1.141, 1.141, 1.14, 1.14, 1.139, \n        1.139, 1.139, 1.138, 1.138, 1.137, 1.137, 1.137, 1.136, 1.136, 1.135, \n        1.135, 1.135, 1.134, 1.134, 1.133, 1.133, 1.133, 1.132, 1.132, 1.131, \n        1.131, 1.13, 1.13, 1.13, 1.129, 1.129, 1.128, 1.128, 1.128, 1.127, \n        1.127, 1.126, 1.126, 1.126, 1.125, 1.125, 1.124, 1.124, 1.124, 1.123, \n        1.123, 1.122, 1.122, 1.121, 1.121, 1.121, 1.12, 1.12, 1.119, 1.119, \n        1.119, 1.118, 1.118, 1.117, 1.117, 1.117, 1.116, 1.116, 1.115, 1.115, \n        1.115, 1.114, 1.114, 1.113, 1.113, 1.113, 1.112, 1.112, 1.111, 1.111, \n        1.11, 1.11, 1.11, 1.109, 1.109, 1.108, 1.108, 1.108, 1.107, 1.107, \n        1.106, 1.106, 1.106, 1.105, 1.105, 1.104, 1.104, 1.104, 1.103, 1.103, \n        1.102, 1.102, 1.102, 1.101, 1.101, 1.1, 1.1, 1.099, 1.099, 1.099, \n        1.098, 1.098, 1.097, 1.097, 1.097, 1.096, 1.096, 1.095, 1.095, 1.095, \n        1.094, 1.094, 1.093, 1.093, 1.093, 1.092, 1.092, 1.091, 1.091, 1.091, \n        1.09, 1.09, 1.089, 1.089, 1.089, 1.088, 1.088, 1.087, 1.087, 1.086, \n        1.086, 1.086, 1.085, 1.085, 1.084, 1.084, 1.084, 1.083, 1.083, 1.082, \n        1.082, 1.082, 1.081, 1.081, 1.08, 1.08, 1.08, 1.079, 1.079, 1.078, \n        1.078, 1.078, 1.077, 1.077, 1.076, 1.076, 1.076, 1.075, 1.075, 1.074, \n        1.074, 1.074, 1.073, 1.073, 1.072, 1.072, 1.072, 1.071, 1.071, 1.07, \n        1.07, 1.069, 1.069, 1.069, 1.068, 1.068, 1.067, 1.067, 1.067, 1.066, \n        1.066, 1.065, 1.065, 1.065, 1.064, 1.064, 1.063, 1.063, 1.063, 1.062, \n        1.062, 1.061, 1.061, 1.061, 1.06, 1.06, 1.059, 1.059, 1.059, 1.058, \n        1.058, 1.057, 1.057, 1.057, 1.056, 1.056, 1.055, 1.055, 1.055, 1.054, \n        1.054, 1.053, 1.053, 1.053, 1.052, 1.052, 1.051, 1.051, 1.05, 1.05, \n        1.05, 1.049, 1.049, 1.048, 1.048, 1.048, 1.047, 1.047, 1.046, 1.046, \n        1.046, 1.045, 1.045, 1.044, 1.044, 1.044, 1.043, 1.043, 1.042, 1.042, \n        1.042, 1.041, 1.041, 1.04, 1.04, 1.04, 1.039, 1.039, 1.038, 1.038, \n        1.038, 1.037, 1.037, 1.036, 1.036, 1.036, 1.035, 1.035, 1.034, 1.034, \n        1.034, 1.033, 1.033, 1.032, 1.032, 1.032, 1.031, 1.031, 1.03, 1.03, \n        1.03, 1.029, 1.029, 1.028, 1.028, 1.028, 1.027, 1.027, 1.026, 1.026, \n        1.026, 1.025, 1.025, 1.024, 1.024, 1.023, 1.023, 1.023, 1.022, 1.022, \n        1.021, 1.021, 1.021, 1.02, 1.02, 1.019, 1.019, 1.019, 1.018, 1.018, \n        1.017, 1.017, 1.017, 1.016, 1.016, 1.015, 1.015, 1.015, 1.014, 1.014, \n        1.013, 1.013, 1.013, 1.012, 1.012, 1.011, 1.011, 1.011, 1.01, 1.01, \n        1.009, 1.009, 1.009, 1.008, 1.008, 1.007, 1.007, 1.007, 1.006, 1.006, \n        1.005, 1.005, 1.005, 1.004, 1.004, 1.003, 1.003, 1.003, 1.002, 1.002, \n        1.001, 1.001, 1.001, 1, 0.9997, 0.9993, 0.9989, 0.9985, 0.9981, 0.9977, \n        0.9973, 0.9969, 0.9965, 0.9961, 0.9957, 0.9953, 0.9949, 0.9945, 0.9941, 0.9937, \n        0.9933, 0.9929, 0.9925, 0.9921, 0.9917, 0.9913, 0.9909, 0.9905, 0.9901, 0.9897, \n        0.9893, 0.9889, 0.9885, 0.9881, 0.9877, 0.9873, 0.9869, 0.9865, 0.9861, 0.9856, \n        0.9852, 0.9848, 0.9844, 0.984, 0.9836, 0.9832, 0.9828, 0.9824, 0.982, 0.9816, \n        0.9812, 0.9808, 0.9804, 0.98, 0.9796, 0.9792, 0.9788, 0.9784, 0.978, 0.9776, \n        0.9772, 0.9768, 0.9764, 0.976, 0.9756, 0.9752, 0.9748, 0.9744, 0.974, 0.9736, \n        0.9732, 0.9728, 0.9724, 0.972, 0.9716, 0.9712, 0.9707, 0.9703, 0.9699, 0.9695, \n        0.9691, 0.9687, 0.9683, 0.9679, 0.9675, 0.9671, 0.9667, 0.9663, 0.9659, 0.9655, \n        0.9651, 0.9647, 0.9643, 0.9639, 0.9635, 0.9631, 0.9627, 0.9623, 0.9619, 0.9615, \n        0.9611, 0.9607, 0.9603, 0.9599, 0.9595, 0.9591, 0.9587, 0.9583, 0.9579, 0.9574, \n        0.957, 0.9566, 0.9562, 0.9558, 0.9554, 0.955, 0.9546, 0.9542, 0.9538, 0.9534, \n        0.953, 0.9526, 0.9522, 0.9518, 0.9514, 0.951, 0.9506, 0.9502, 0.9498, 0.9494, \n        0.949, 0.9486, 0.9482, 0.9478, 0.9474, 0.947, 0.9466, 0.9462, 0.9457, 0.9453, \n        0.9449, 0.9445, 0.9441, 0.9437, 0.9433, 0.9429, 0.9425, 0.9421, 0.9417, 0.9413, \n        0.9409, 0.9405, 0.9401, 0.9397, 0.9393, 0.9389, 0.9385, 0.9381, 0.9377, 0.9373, \n        0.9369, 0.9365, 0.9361, 0.9356, 0.9352, 0.9348, 0.9344, 0.934, 0.9336, 0.9332, \n        0.9328, 0.9324, 0.932, 0.9316, 0.9312, 0.9308, 0.9304, 0.93, 0.9296, 0.9292, \n        0.9288, 0.9284, 0.928, 0.9276, 0.9272, 0.9267, 0.9263, 0.9259, 0.9255, 0.9251, \n        0.9247, 0.9243, 0.9239, 0.9235, 0.9231, 0.9227, 0.9223, 0.9219, 0.9215, 0.9211, \n        0.9207, 0.9203, 0.9199, 0.9195, 0.9191, 0.9186, 0.9182, 0.9178, 0.9174, 0.917, \n        0.9166, 0.9162, 0.9158, 0.9154, 0.915, 0.9146, 0.9142, 0.9138, 0.9134, 0.913, \n        0.9126, 0.9122, 0.9118, 0.9113, 0.9109, 0.9105, 0.9101, 0.9097, 0.9093, 0.9089, \n        0.9085, 0.9081, 0.9077, 0.9073, 0.9069, 0.9065, 0.9061, 0.9057, 0.9053, 0.9049, \n        0.9044, 0.904, 0.9036, 0.9032, 0.9028, 0.9024, 0.902, 0.9016, 0.9012, 0.9008, \n        0.9004, 0.9, 0.8996, 0.8992, 0.8988, 0.8983, 0.8979, 0.8975, 0.8971, 0.8967, \n        0.8963, 0.8959, 0.8955, 0.8951, 0.8947, 0.8943, 0.8939, 0.8935, 0.8931, 0.8926, \n        0.8922, 0.8918, 0.8914, 0.891, 0.8906, 0.8902, 0.8898, 0.8894, 0.889, 0.8886, \n        0.8882, 0.8878, 0.8873, 0.8869, 0.8865, 0.8861, 0.8857, 0.8853, 0.8849, 0.8845, \n        0.8841, 0.8837, 0.8833, 0.8829, 0.8825, 0.882, 0.8816, 0.8812, 0.8808, 0.8804, \n        0.88, 0.8796, 0.8792, 0.8788, 0.8784, 0.878, 0.8775, 0.8771, 0.8767, 0.8763, \n        0.8759, 0.8755, 0.8751, 0.8747, 0.8743, 0.8739, 0.8735, 0.873, 0.8726, 0.8722, \n        0.8718, 0.8714, 0.871, 0.8706, 0.8702, 0.8698, 0.8694, 0.869, 0.8685, 0.8681, \n        0.8677, 0.8673, 0.8669, 0.8665, 0.8661, 0.8657, 0.8653, 0.8649, 0.8644, 0.864, \n        0.8636, 0.8632, 0.8628, 0.8624, 0.862, 0.8616, 0.8612, 0.8607, 0.8603, 0.8599, \n        0.8595, 0.8591, 0.8587, 0.8583, 0.8579, 0.8575, 0.857, 0.8566, 0.8562, 0.8558, \n        0.8554, 0.855, 0.8546, 0.8542, 0.8538, 0.8533, 0.8529, 0.8525, 0.8521, 0.8517, \n        0.8513, 0.8509, 0.8505, 0.85, 0.8496, 0.8492, 0.8488, 0.8484, 0.848, 0.8476, \n        0.8472, 0.8467, 0.8463, 0.8459, 0.8455, 0.8451, 0.8447, 0.8443, 0.8439, 0.8434, \n        0.843, 0.8426, 0.8422, 0.8418, 0.8414, 0.841, 0.8406, 0.8401, 0.8397, 0.8393, \n        0.8389, 0.8385, 0.8381, 0.8377, 0.8372, 0.8368, 0.8364, 0.836, 0.8356, 0.8352, \n        0.8348, 0.8343, 0.8339, 0.8335, 0.8331, 0.8327, 0.8323, 0.8319, 0.8314, 0.831, \n        0.8306, 0.8302, 0.8298, 0.8294, 0.8289, 0.8285, 0.8281, 0.8277, 0.8273, 0.8269, \n        0.8265, 0.826, 0.8256, 0.8252, 0.8248, 0.8244, 0.824, 0.8235, 0.8231, 0.8227, \n        0.8223, 0.8219, 0.8215, 0.821, 0.8206, 0.8202, 0.8198, 0.8194, 0.819, 0.8185, \n        0.8181, 0.8177, 0.8173, 0.8169, 0.8165, 0.816, 0.8156, 0.8152, 0.8148, 0.8144, \n        0.814, 0.8135, 0.8131, 0.8127, 0.8123, 0.8119, 0.8114, 0.811, 0.8106, 0.8102, \n        0.8098, 0.8094, 0.8089, 0.8085, 0.8081, 0.8077, 0.8073, 0.8068, 0.8064, 0.806, \n        0.8056, 0.8052, 0.8047, 0.8043, 0.8039, 0.8035, 0.8031, 0.8026, 0.8022, 0.8018, \n        0.8014, 0.801, 0.8005, 0.8001, 0.7997, 0.7993, 0.7989, 0.7984, 0.798, 0.7976, \n        0.7972, 0.7968, 0.7963, 0.7959, 0.7955, 0.7951, 0.7947, 0.7942, 0.7938, 0.7934, \n        0.793, 0.7926, 0.7921, 0.7917, 0.7913, 0.7909, 0.7904, 0.79, 0.7896, 0.7892, \n        0.7888, 0.7883, 0.7879, 0.7875, 0.7871, 0.7866, 0.7862, 0.7858, 0.7854, 0.7849, \n        0.7845, 0.7841, 0.7837, 0.7833, 0.7828, 0.7824, 0.782, 0.7816, 0.7811, 0.7807, \n        0.7803, 0.7799, 0.7794, 0.779, 0.7786, 0.7782, 0.7777, 0.7773, 0.7769, 0.7765, \n        0.776, 0.7756, 0.7752, 0.7748, 0.7743, 0.7739, 0.7735, 0.7731, 0.7726, 0.7722, \n        0.7718, 0.7714, 0.7709, 0.7705, 0.7701, 0.7697, 0.7692, 0.7688, 0.7684, 0.7679, \n        0.7675, 0.7671, 0.7667, 0.7662, 0.7658, 0.7654, 0.765, 0.7645, 0.7641, 0.7637, \n        0.7632, 0.7628, 0.7624, 0.762, 0.7615, 0.7611, 0.7607, 0.7602, 0.7598, 0.7594, \n        0.759, 0.7585, 0.7581, 0.7577, 0.7572, 0.7568, 0.7564, 0.756, 0.7555, 0.7551, \n        0.7547, 0.7542, 0.7538, 0.7534, 0.7529, 0.7525, 0.7521, 0.7516, 0.7512, 0.7508, \n        0.7504, 0.7499, 0.7495, 0.7491, 0.7486, 0.7482, 0.7478, 0.7473, 0.7469, 0.7465, \n        0.746, 0.7456, 0.7452, 0.7447, 0.7443, 0.7439, 0.7434, 0.743, 0.7426, 0.7421, \n        0.7417, 0.7413, 0.7408, 0.7404, 0.74, 0.7395, 0.7391, 0.7387, 0.7382, 0.7378, \n        0.7374, 0.7369, 0.7365, 0.7361, 0.7356, 0.7352, 0.7348, 0.7343, 0.7339, 0.7335, \n        0.733, 0.7326, 0.7321, 0.7317, 0.7313, 0.7308, 0.7304, 0.73, 0.7295, 0.7291, \n        0.7287, 0.7282, 0.7278, 0.7273, 0.7269, 0.7265, 0.726, 0.7256, 0.7252, 0.7247, \n        0.7243, 0.7238, 0.7234, 0.723, 0.7225, 0.7221, 0.7216, 0.7212, 0.7208, 0.7203, \n        0.7199, 0.7195, 0.719, 0.7186, 0.7181, 0.7177, 0.7173, 0.7168, 0.7164, 0.7159, \n        0.7155, 0.7151, 0.7146, 0.7142, 0.7137, 0.7133, 0.7128, 0.7124, 0.712, 0.7115, \n        0.7111, 0.7106, 0.7102, 0.7098, 0.7093, 0.7089, 0.7084, 0.708, 0.7075, 0.7071, \n        0.7066, 0.7062, 0.7058, 0.7053, 0.7049, 0.7044, 0.704, 0.7035, 0.7031, 0.7027, \n        0.7022, 0.7018, 0.7013, 0.7009, 0.7004, 0.7, 0.6995, 0.6991, 0.6986, 0.6982, \n        0.6978, 0.6973, 0.6969, 0.6964, 0.696, 0.6955, 0.6951, 0.6946, 0.6942, 0.6937, \n        0.6933, 0.6928, 0.6924, 0.6919, 0.6915, 0.691, 0.6906, 0.6901, 0.6897, 0.6892, \n        0.6888, 0.6883, 0.6879, 0.6874, 0.687, 0.6865, 0.6861, 0.6856, 0.6852, 0.6847, \n        0.6843, 0.6838, 0.6834, 0.6829, 0.6825, 0.682, 0.6816, 0.6811, 0.6807, 0.6802, \n        0.6798, 0.6793, 0.6789, 0.6784, 0.678, 0.6775, 0.6771, 0.6766, 0.6762, 0.6757, \n        0.6752, 0.6748, 0.6743, 0.6739, 0.6734, 0.673, 0.6725, 0.6721, 0.6716, 0.6711, \n        0.6707, 0.6702, 0.6698, 0.6693, 0.6689, 0.6684, 0.668, 0.6675, 0.667, 0.6666, \n        0.6661, 0.6657, 0.6652, 0.6648, 0.6643, 0.6638, 0.6634, 0.6629, 0.6625, 0.662, \n        0.6615, 0.6611, 0.6606, 0.6602, 0.6597, 0.6592, 0.6588, 0.6583, 0.6579, 0.6574, \n        0.6569, 0.6565, 0.656, 0.6556, 0.6551, 0.6546, 0.6542, 0.6537, 0.6532, 0.6528, \n        0.6523, 0.6519, 0.6514, 0.6509, 0.6505, 0.65, 0.6495, 0.6491, 0.6486, 0.6481, \n        0.6477, 0.6472, 0.6468, 0.6463, 0.6458, 0.6454, 0.6449, 0.6444, 0.644, 0.6435, \n        0.643, 0.6426, 0.6421, 0.6416, 0.6412, 0.6407, 0.6402, 0.6397, 0.6393, 0.6388, \n        0.6383, 0.6379, 0.6374, 0.6369, 0.6365, 0.636, 0.6355, 0.6351, 0.6346, 0.6341, \n        0.6336, 0.6332, 0.6327, 0.6322, 0.6318, 0.6313, 0.6308, 0.6303, 0.6299, 0.6294, \n        0.6289, 0.6285, 0.628, 0.6275, 0.627, 0.6266, 0.6261, 0.6256, 0.6251, 0.6247, \n        0.6242, 0.6237, 0.6232, 0.6228, 0.6223, 0.6218, 0.6213, 0.6208, 0.6204, 0.6199, \n        0.6194, 0.6189, 0.6185, 0.618, 0.6175, 0.617, 0.6165, 0.6161, 0.6156, 0.6151, \n        0.6146, 0.6142, 0.6137, 0.6132, 0.6127, 0.6122, 0.6117, 0.6113, 0.6108, 0.6103, \n        0.6098, 0.6093, 0.6089, 0.6084, 0.6079, 0.6074, 0.6069, 0.6064, 0.606, 0.6055, \n        0.605, 0.6045, 0.604, 0.6035, 0.603, 0.6026, 0.6021, 0.6016, 0.6011, 0.6006, \n        0.6001, 0.5996, 0.5992, 0.5987, 0.5982, 0.5977, 0.5972, 0.5967, 0.5962, 0.5957, \n        0.5952, 0.5948, 0.5943, 0.5938, 0.5933, 0.5928, 0.5923, 0.5918, 0.5913, 0.5908, \n        0.5903, 0.5898, 0.5894, 0.5889, 0.5884, 0.5879, 0.5874, 0.5869, 0.5864, 0.5859, \n        0.5854, 0.5849, 0.5844, 0.5839, 0.5834, 0.5829, 0.5824, 0.5819, 0.5814, 0.5809, \n        0.5804, 0.5799, 0.5794, 0.5789, 0.5784, 0.5779, 0.5774, 0.5769, 0.5764, 0.5759, \n        0.5754, 0.5749, 0.5744, 0.5739, 0.5734, 0.5729, 0.5724, 0.5719, 0.5714, 0.5709, \n        0.5704, 0.5699, 0.5694, 0.5689, 0.5684, 0.5679, 0.5674, 0.5669, 0.5664, 0.5659, \n        0.5654, 0.5649, 0.5644, 0.5639, 0.5633, 0.5628, 0.5623, 0.5618, 0.5613, 0.5608, \n        0.5603, 0.5598, 0.5593, 0.5588, 0.5582, 0.5577, 0.5572, 0.5567, 0.5562, 0.5557, \n        0.5552, 0.5547, 0.5541, 0.5536, 0.5531, 0.5526, 0.5521, 0.5516, 0.5511, 0.5505, \n        0.55, 0.5495, 0.549, 0.5485, 0.548, 0.5474, 0.5469, 0.5464, 0.5459, 0.5454, \n        0.5448, 0.5443, 0.5438, 0.5433, 0.5428, 0.5422, 0.5417, 0.5412, 0.5407, 0.5402, \n        0.5396, 0.5391, 0.5386, 0.5381, 0.5375, 0.537, 0.5365, 0.536, 0.5354, 0.5349, \n        0.5344, 0.5339, 0.5333, 0.5328, 0.5323, 0.5317, 0.5312, 0.5307, 0.5302, 0.5296, \n        0.5291, 0.5286, 0.528, 0.5275, 0.527, 0.5264, 0.5259, 0.5254, 0.5248, 0.5243, \n        0.5238, 0.5232, 0.5227, 0.5222, 0.5216, 0.5211, 0.5206, 0.52, 0.5195, 0.5189, \n        0.5184, 0.5179, 0.5173, 0.5168, 0.5162, 0.5157, 0.5152, 0.5146, 0.5141, 0.5135, \n        0.513, 0.5124, 0.5119, 0.5114, 0.5108, 0.5103, 0.5097, 0.5092, 0.5086, 0.5081, \n        0.5075, 0.507, 0.5064, 0.5059, 0.5053, 0.5048, 0.5043, 0.5037, 0.5032, 0.5026, \n        0.502, 0.5015, 0.5009, 0.5004, 0.4998, 0.4993, 0.4987, 0.4982, 0.4976, 0.4971, \n        0.4965, 0.496, 0.4954, 0.4948, 0.4943, 0.4937, 0.4932, 0.4926, 0.492, 0.4915, \n        0.4909, 0.4904, 0.4898, 0.4892, 0.4887, 0.4881, 0.4875, 0.487, 0.4864, 0.4859, \n        0.4853, 0.4847, 0.4842, 0.4836, 0.483, 0.4825, 0.4819, 0.4813, 0.4807, 0.4802, \n        0.4796, 0.479, 0.4785, 0.4779, 0.4773, 0.4767, 0.4762, 0.4756, 0.475, 0.4744, \n        0.4739, 0.4733, 0.4727, 0.4721, 0.4716, 0.471, 0.4704, 0.4698, 0.4692, 0.4687, \n        0.4681, 0.4675, 0.4669, 0.4663, 0.4657, 0.4652, 0.4646, 0.464, 0.4634, 0.4628, \n        0.4622, 0.4616, 0.461, 0.4605, 0.4599, 0.4593, 0.4587, 0.4581, 0.4575, 0.4569, \n        0.4563, 0.4557, 0.4551, 0.4545, 0.4539, 0.4533, 0.4527, 0.4521, 0.4515, 0.451, \n        0.4504, 0.4498, 0.4491, 0.4485, 0.4479, 0.4473, 0.4467, 0.4461, 0.4455, 0.4449, \n        0.4443, 0.4437, 0.4431, 0.4425, 0.4419, 0.4413, 0.4407, 0.4401, 0.4394, 0.4388, \n        0.4382, 0.4376, 0.437, 0.4364, 0.4358, 0.4351, 0.4345, 0.4339, 0.4333, 0.4327, \n        0.4321, 0.4314, 0.4308, 0.4302, 0.4296, 0.4289, 0.4283, 0.4277, 0.4271, 0.4264, \n        0.4258, 0.4252, 0.4246, 0.4239, 0.4233, 0.4227, 0.422, 0.4214, 0.4208, 0.4201, \n        0.4195, 0.4189, 0.4182, 0.4176, 0.4169, 0.4163, 0.4157, 0.415, 0.4144, 0.4137, \n        0.4131, 0.4125, 0.4118, 0.4112, 0.4105, 0.4099, 0.4092, 0.4086, 0.4079, 0.4073, \n        0.4066, 0.406, 0.4053, 0.4047, 0.404, 0.4034, 0.4027, 0.402, 0.4014, 0.4007, \n        0.4001, 0.3994, 0.3987, 0.3981, 0.3974, 0.3967, 0.3961, 0.3954, 0.3947, 0.3941, \n        0.3934, 0.3927, 0.3921, 0.3914, 0.3907, 0.39, 0.3894, 0.3887, 0.388, 0.3873, \n        0.3866, 0.386, 0.3853, 0.3846, 0.3839, 0.3832, 0.3825, 0.3819, 0.3812, 0.3805, \n        0.3798, 0.3791, 0.3784, 0.3777, 0.377, 0.3763, 0.3756, 0.3749, 0.3742, 0.3735, \n        0.3728, 0.3721, 0.3714, 0.3707, 0.37, 0.3693, 0.3686, 0.3679, 0.3672, 0.3665, \n        0.3657, 0.365, 0.3643, 0.3636, 0.3629, 0.3622, 0.3614, 0.3607, 0.36, 0.3593, \n        0.3585, 0.3578, 0.3571, 0.3564, 0.3556, 0.3549, 0.3542, 0.3534, 0.3527, 0.352, \n        0.3512, 0.3505, 0.3497, 0.349, 0.3483, 0.3475, 0.3468, 0.346, 0.3453, 0.3445, \n        0.3438, 0.343, 0.3422, 0.3415, 0.3407, 0.34, 0.3392, 0.3384, 0.3377, 0.3369, \n        0.3361, 0.3354, 0.3346, 0.3338, 0.3331, 0.3323, 0.3315, 0.3307, 0.3299, 0.3292, \n        0.3284, 0.3276, 0.3268, 0.326, 0.3252, 0.3244, 0.3236, 0.3228, 0.3221, 0.3213, \n        0.3205, 0.3196, 0.3188, 0.318, 0.3172, 0.3164, 0.3156, 0.3148, 0.314, 0.3132, \n        0.3123, 0.3115, 0.3107, 0.3099, 0.309, 0.3082, 0.3074, 0.3065, 0.3057, 0.3049, \n        0.304, 0.3032, 0.3023, 0.3015, 0.3007, 0.2998, 0.2989, 0.2981, 0.2972, 0.2964, \n        0.2955, 0.2946, 0.2938, 0.2929, 0.292, 0.2912, 0.2903, 0.2894, 0.2885, 0.2877, \n        0.2868, 0.2859, 0.285, 0.2841, 0.2832, 0.2823, 0.2814, 0.2805, 0.2796, 0.2787, \n        0.2778, 0.2768, 0.2759, 0.275, 0.2741, 0.2732, 0.2722, 0.2713, 0.2704, 0.2694, \n        0.2685, 0.2675, 0.2666, 0.2656, 0.2647, 0.2637, 0.2628, 0.2618, 0.2608, 0.2599, \n        0.2589, 0.2579, 0.2569, 0.256, 0.255, 0.254, 0.253, 0.252, 0.251, 0.25, \n        0.249, 0.248, 0.2469, 0.2459, 0.2449, 0.2439, 0.2428, 0.2418, 0.2408, 0.2397, \n        0.2387, 0.2376, 0.2365, 0.2355, 0.2344, 0.2333, 0.2323, 0.2312, 0.2301, 0.229, \n        0.2279, 0.2268, 0.2257, 0.2246, 0.2235, 0.2223, 0.2212, 0.2201, 0.2189, 0.2178, \n        0.2166, 0.2155, 0.2143, 0.2132, 0.212, 0.2108, 0.2096, 0.2084, 0.2072, 0.206, \n        0.2048, 0.2036, 0.2023, 0.2011, 0.1999, 0.1986, 0.1974, 0.1961, 0.1948, 0.1935, \n        0.1923, 0.191, 0.1896, 0.1883, 0.187, 0.1857, 0.1843, 0.183, 0.1816, 0.1802, \n        0.1789, 0.1775, 0.1761, 0.1747, 0.1732, 0.1718, 0.1703, 0.1689, 0.1674, 0.1659, \n        0.1644, 0.1629, 0.1614, 0.1599, 0.1583, 0.1567, 0.1551, 0.1535, 0.1519, 0.1503, \n        0.1486, 0.147, 0.1453, 0.1436, 0.1418, 0.1401, 0.1383, 0.1365, 0.1347, 0.1329, \n        0.131, 0.1291, 0.1272, 0.1252, 0.1233, 0.1213, 0.1192, 0.1171, 0.115, 0.1129, \n        0.1107, 0.1084, 0.1061, 0.1038, 0.1014, 0.09894, 0.09643, 0.09385, 0.0912, 0.08847, \n        0.08566, 0.08275, 0.07974, 0.0766, 0.07334, 0.06992, 0.06633, 0.06253, 0.05849, 0.05415, \n        0.04943, 0.0442, 0.03828, 0.03125, 0.0221, -0};\n\n        const static double cosvals[max] = { \n        1, 1, 1, 1, 1, 1, 0.9999, 0.9999, 0.9999, 0.9999, \n        0.9999, 0.9998, 0.9998, 0.9998, 0.9997, 0.9997, 0.9997, 0.9996, 0.9996, 0.9995, \n        0.9995, 0.9994, 0.9994, 0.9993, 0.9993, 0.9992, 0.9991, 0.9991, 0.999, 0.9989, \n        0.9989, 0.9988, 0.9987, 0.9986, 0.9986, 0.9985, 0.9984, 0.9983, 0.9982, 0.9981, \n        0.998, 0.9979, 0.9978, 0.9977, 0.9976, 0.9975, 0.9974, 0.9973, 0.9972, 0.9971, \n        0.9969, 0.9968, 0.9967, 0.9966, 0.9964, 0.9963, 0.9962, 0.996, 0.9959, 0.9958, \n        0.9956, 0.9955, 0.9953, 0.9952, 0.995, 0.9949, 0.9947, 0.9946, 0.9944, 0.9942, \n        0.9941, 0.9939, 0.9937, 0.9936, 0.9934, 0.9932, 0.993, 0.9929, 0.9927, 0.9925, \n        0.9923, 0.9921, 0.9919, 0.9917, 0.9915, 0.9913, 0.9911, 0.9909, 0.9907, 0.9905, \n        0.9903, 0.9901, 0.9898, 0.9896, 0.9894, 0.9892, 0.989, 0.9887, 0.9885, 0.9883, \n        0.988, 0.9878, 0.9875, 0.9873, 0.9871, 0.9868, 0.9866, 0.9863, 0.9861, 0.9858, \n        0.9855, 0.9853, 0.985, 0.9847, 0.9845, 0.9842, 0.9839, 0.9837, 0.9834, 0.9831, \n        0.9828, 0.9825, 0.9823, 0.982, 0.9817, 0.9814, 0.9811, 0.9808, 0.9805, 0.9802, \n        0.9799, 0.9796, 0.9793, 0.9789, 0.9786, 0.9783, 0.978, 0.9777, 0.9774, 0.977, \n        0.9767, 0.9764, 0.976, 0.9757, 0.9754, 0.975, 0.9747, 0.9743, 0.974, 0.9736, \n        0.9733, 0.9729, 0.9726, 0.9722, 0.9719, 0.9715, 0.9711, 0.9708, 0.9704, 0.97, \n        0.9697, 0.9693, 0.9689, 0.9685, 0.9681, 0.9678, 0.9674, 0.967, 0.9666, 0.9662, \n        0.9658, 0.9654, 0.965, 0.9646, 0.9642, 0.9638, 0.9634, 0.963, 0.9625, 0.9621, \n        0.9617, 0.9613, 0.9609, 0.9604, 0.96, 0.9596, 0.9591, 0.9587, 0.9583, 0.9578, \n        0.9574, 0.9569, 0.9565, 0.956, 0.9556, 0.9551, 0.9547, 0.9542, 0.9538, 0.9533, \n        0.9528, 0.9524, 0.9519, 0.9514, 0.951, 0.9505, 0.95, 0.9495, 0.949, 0.9486, \n        0.9481, 0.9476, 0.9471, 0.9466, 0.9461, 0.9456, 0.9451, 0.9446, 0.9441, 0.9436, \n        0.9431, 0.9426, 0.9421, 0.9415, 0.941, 0.9405, 0.94, 0.9395, 0.9389, 0.9384, \n        0.9379, 0.9373, 0.9368, 0.9363, 0.9357, 0.9352, 0.9346, 0.9341, 0.9335, 0.933, \n        0.9324, 0.9319, 0.9313, 0.9308, 0.9302, 0.9296, 0.9291, 0.9285, 0.9279, 0.9274, \n        0.9268, 0.9262, 0.9256, 0.925, 0.9245, 0.9239, 0.9233, 0.9227, 0.9221, 0.9215, \n        0.9209, 0.9203, 0.9197, 0.9191, 0.9185, 0.9179, 0.9173, 0.9167, 0.9161, 0.9154, \n        0.9148, 0.9142, 0.9136, 0.913, 0.9123, 0.9117, 0.9111, 0.9104, 0.9098, 0.9092, \n        0.9085, 0.9079, 0.9072, 0.9066, 0.9059, 0.9053, 0.9046, 0.904, 0.9033, 0.9027, \n        0.902, 0.9013, 0.9007, 0.9, 0.8993, 0.8987, 0.898, 0.8973, 0.8966, 0.896, \n        0.8953, 0.8946, 0.8939, 0.8932, 0.8925, 0.8918, 0.8911, 0.8904, 0.8897, 0.889, \n        0.8883, 0.8876, 0.8869, 0.8862, 0.8855, 0.8848, 0.8841, 0.8834, 0.8826, 0.8819, \n        0.8812, 0.8805, 0.8797, 0.879, 0.8783, 0.8775, 0.8768, 0.8761, 0.8753, 0.8746, \n        0.8738, 0.8731, 0.8723, 0.8716, 0.8708, 0.8701, 0.8693, 0.8686, 0.8678, 0.867, \n        0.8663, 0.8655, 0.8647, 0.864, 0.8632, 0.8624, 0.8616, 0.8609, 0.8601, 0.8593, \n        0.8585, 0.8577, 0.8569, 0.8561, 0.8554, 0.8546, 0.8538, 0.853, 0.8522, 0.8514, \n        0.8505, 0.8497, 0.8489, 0.8481, 0.8473, 0.8465, 0.8457, 0.8449, 0.844, 0.8432, \n        0.8424, 0.8416, 0.8407, 0.8399, 0.8391, 0.8382, 0.8374, 0.8365, 0.8357, 0.8349, \n        0.834, 0.8332, 0.8323, 0.8315, 0.8306, 0.8298, 0.8289, 0.828, 0.8272, 0.8263, \n        0.8255, 0.8246, 0.8237, 0.8228, 0.822, 0.8211, 0.8202, 0.8193, 0.8185, 0.8176, \n        0.8167, 0.8158, 0.8149, 0.814, 0.8131, 0.8123, 0.8114, 0.8105, 0.8096, 0.8087, \n        0.8078, 0.8068, 0.8059, 0.805, 0.8041, 0.8032, 0.8023, 0.8014, 0.8005, 0.7995, \n        0.7986, 0.7977, 0.7968, 0.7958, 0.7949, 0.794, 0.793, 0.7921, 0.7912, 0.7902, \n        0.7893, 0.7883, 0.7874, 0.7865, 0.7855, 0.7846, 0.7836, 0.7827, 0.7817, 0.7807, \n        0.7798, 0.7788, 0.7779, 0.7769, 0.7759, 0.775, 0.774, 0.773, 0.772, 0.7711, \n        0.7701, 0.7691, 0.7681, 0.7671, 0.7662, 0.7652, 0.7642, 0.7632, 0.7622, 0.7612, \n        0.7602, 0.7592, 0.7582, 0.7572, 0.7562, 0.7552, 0.7542, 0.7532, 0.7522, 0.7512, \n        0.7502, 0.7491, 0.7481, 0.7471, 0.7461, 0.7451, 0.744, 0.743, 0.742, 0.741, \n        0.7399, 0.7389, 0.7379, 0.7368, 0.7358, 0.7347, 0.7337, 0.7327, 0.7316, 0.7306, \n        0.7295, 0.7285, 0.7274, 0.7264, 0.7253, 0.7242, 0.7232, 0.7221, 0.7211, 0.72, \n        0.7189, 0.7179, 0.7168, 0.7157, 0.7147, 0.7136, 0.7125, 0.7114, 0.7104, 0.7093, \n        0.7082, 0.7071, 0.706, 0.7049, 0.7038, 0.7028, 0.7017, 0.7006, 0.6995, 0.6984, \n        0.6973, 0.6962, 0.6951, 0.694, 0.6929, 0.6918, 0.6907, 0.6895, 0.6884, 0.6873, \n        0.6862, 0.6851, 0.684, 0.6828, 0.6817, 0.6806, 0.6795, 0.6784, 0.6772, 0.6761, \n        0.675, 0.6738, 0.6727, 0.6716, 0.6704, 0.6693, 0.6681, 0.667, 0.6659, 0.6647, \n        0.6636, 0.6624, 0.6613, 0.6601, 0.659, 0.6578, 0.6567, 0.6555, 0.6543, 0.6532, \n        0.652, 0.6508, 0.6497, 0.6485, 0.6473, 0.6462, 0.645, 0.6438, 0.6427, 0.6415, \n        0.6403, 0.6391, 0.6379, 0.6368, 0.6356, 0.6344, 0.6332, 0.632, 0.6308, 0.6296, \n        0.6284, 0.6273, 0.6261, 0.6249, 0.6237, 0.6225, 0.6213, 0.6201, 0.6189, 0.6176, \n        0.6164, 0.6152, 0.614, 0.6128, 0.6116, 0.6104, 0.6092, 0.6079, 0.6067, 0.6055, \n        0.6043, 0.6031, 0.6018, 0.6006, 0.5994, 0.5982, 0.5969, 0.5957, 0.5945, 0.5932, \n        0.592, 0.5908, 0.5895, 0.5883, 0.587, 0.5858, 0.5846, 0.5833, 0.5821, 0.5808, \n        0.5796, 0.5783, 0.5771, 0.5758, 0.5746, 0.5733, 0.572, 0.5708, 0.5695, 0.5683, \n        0.567, 0.5657, 0.5645, 0.5632, 0.5619, 0.5607, 0.5594, 0.5581, 0.5568, 0.5556, \n        0.5543, 0.553, 0.5517, 0.5505, 0.5492, 0.5479, 0.5466, 0.5453, 0.544, 0.5428, \n        0.5415, 0.5402, 0.5389, 0.5376, 0.5363, 0.535, 0.5337, 0.5324, 0.5311, 0.5298, \n        0.5285, 0.5272, 0.5259, 0.5246, 0.5233, 0.522, 0.5207, 0.5194, 0.518, 0.5167, \n        0.5154, 0.5141, 0.5128, 0.5115, 0.5102, 0.5088, 0.5075, 0.5062, 0.5049, 0.5035, \n        0.5022, 0.5009, 0.4996, 0.4982, 0.4969, 0.4956, 0.4942, 0.4929, 0.4916, 0.4902, \n        0.4889, 0.4876, 0.4862, 0.4849, 0.4835, 0.4822, 0.4808, 0.4795, 0.4781, 0.4768, \n        0.4755, 0.4741, 0.4727, 0.4714, 0.47, 0.4687, 0.4673, 0.466, 0.4646, 0.4633, \n        0.4619, 0.4605, 0.4592, 0.4578, 0.4564, 0.4551, 0.4537, 0.4523, 0.451, 0.4496, \n        0.4482, 0.4469, 0.4455, 0.4441, 0.4427, 0.4414, 0.44, 0.4386, 0.4372, 0.4359, \n        0.4345, 0.4331, 0.4317, 0.4303, 0.4289, 0.4276, 0.4262, 0.4248, 0.4234, 0.422, \n        0.4206, 0.4192, 0.4178, 0.4164, 0.415, 0.4136, 0.4122, 0.4108, 0.4094, 0.408, \n        0.4066, 0.4052, 0.4038, 0.4024, 0.401, 0.3996, 0.3982, 0.3968, 0.3954, 0.394, \n        0.3926, 0.3912, 0.3898, 0.3883, 0.3869, 0.3855, 0.3841, 0.3827, 0.3813, 0.3798, \n        0.3784, 0.377, 0.3756, 0.3742, 0.3727, 0.3713, 0.3699, 0.3685, 0.367, 0.3656, \n        0.3642, 0.3628, 0.3613, 0.3599, 0.3585, 0.357, 0.3556, 0.3542, 0.3527, 0.3513, \n        0.3499, 0.3484, 0.347, 0.3455, 0.3441, 0.3427, 0.3412, 0.3398, 0.3383, 0.3369, \n        0.3354, 0.334, 0.3326, 0.3311, 0.3297, 0.3282, 0.3268, 0.3253, 0.3239, 0.3224, \n        0.321, 0.3195, 0.318, 0.3166, 0.3151, 0.3137, 0.3122, 0.3108, 0.3093, 0.3078, \n        0.3064, 0.3049, 0.3035, 0.302, 0.3005, 0.2991, 0.2976, 0.2962, 0.2947, 0.2932, \n        0.2918, 0.2903, 0.2888, 0.2873, 0.2859, 0.2844, 0.2829, 0.2815, 0.28, 0.2785, \n        0.277, 0.2756, 0.2741, 0.2726, 0.2711, 0.2697, 0.2682, 0.2667, 0.2652, 0.2638, \n        0.2623, 0.2608, 0.2593, 0.2578, 0.2563, 0.2549, 0.2534, 0.2519, 0.2504, 0.2489, \n        0.2474, 0.246, 0.2445, 0.243, 0.2415, 0.24, 0.2385, 0.237, 0.2355, 0.234, \n        0.2326, 0.2311, 0.2296, 0.2281, 0.2266, 0.2251, 0.2236, 0.2221, 0.2206, 0.2191, \n        0.2176, 0.2161, 0.2146, 0.2131, 0.2116, 0.2101, 0.2086, 0.2071, 0.2056, 0.2041, \n        0.2026, 0.2011, 0.1996, 0.1981, 0.1966, 0.1951, 0.1936, 0.1921, 0.1906, 0.1891, \n        0.1876, 0.1861, 0.1845, 0.183, 0.1815, 0.18, 0.1785, 0.177, 0.1755, 0.174, \n        0.1725, 0.171, 0.1695, 0.1679, 0.1664, 0.1649, 0.1634, 0.1619, 0.1604, 0.1589, \n        0.1573, 0.1558, 0.1543, 0.1528, 0.1513, 0.1498, 0.1482, 0.1467, 0.1452, 0.1437, \n        0.1422, 0.1407, 0.1391, 0.1376, 0.1361, 0.1346, 0.1331, 0.1315, 0.13, 0.1285, \n        0.127, 0.1255, 0.1239, 0.1224, 0.1209, 0.1194, 0.1178, 0.1163, 0.1148, 0.1133, \n        0.1117, 0.1102, 0.1087, 0.1072, 0.1056, 0.1041, 0.1026, 0.1011, 0.09954, 0.09802, \n        0.09649, 0.09496, 0.09344, 0.09191, 0.09038, 0.08885, 0.08733, 0.0858, 0.08427, 0.08274, \n        0.08121, 0.07968, 0.07815, 0.07662, 0.07509, 0.07356, 0.07203, 0.0705, 0.06897, 0.06744, \n        0.06591, 0.06438, 0.06285, 0.06132, 0.05979, 0.05826, 0.05673, 0.0552, 0.05366, 0.05213, \n        0.0506, 0.04907, 0.04754, 0.046, 0.04447, 0.04294, 0.04141, 0.03987, 0.03834, 0.03681, \n        0.03527, 0.03374, 0.03221, 0.03067, 0.02914, 0.02761, 0.02607, 0.02454, 0.02301, 0.02147, \n        0.01994, 0.01841, 0.01687, 0.01534, 0.01381, 0.01227, 0.01074, 0.009204, 0.00767, 0.006136, \n        0.004602, 0.003068, 0.001534, 6.123e-17, -0.001534, -0.003068, -0.004602, -0.006136, -0.00767, -0.009204, \n        -0.01074, -0.01227, -0.01381, -0.01534, -0.01687, -0.01841, -0.01994, -0.02147, -0.02301, -0.02454, \n        -0.02607, -0.02761, -0.02914, -0.03067, -0.03221, -0.03374, -0.03527, -0.03681, -0.03834, -0.03987, \n        -0.04141, -0.04294, -0.04447, -0.046, -0.04754, -0.04907, -0.0506, -0.05213, -0.05366, -0.0552, \n        -0.05673, -0.05826, -0.05979, -0.06132, -0.06285, -0.06438, -0.06591, -0.06744, -0.06897, -0.0705, \n        -0.07203, -0.07356, -0.07509, -0.07662, -0.07815, -0.07968, -0.08121, -0.08274, -0.08427, -0.0858, \n        -0.08733, -0.08885, -0.09038, -0.09191, -0.09344, -0.09496, -0.09649, -0.09802, -0.09954, -0.1011, \n        -0.1026, -0.1041, -0.1056, -0.1072, -0.1087, -0.1102, -0.1117, -0.1133, -0.1148, -0.1163, \n        -0.1178, -0.1194, -0.1209, -0.1224, -0.1239, -0.1255, -0.127, -0.1285, -0.13, -0.1315, \n        -0.1331, -0.1346, -0.1361, -0.1376, -0.1391, -0.1407, -0.1422, -0.1437, -0.1452, -0.1467, \n        -0.1482, -0.1498, -0.1513, -0.1528, -0.1543, -0.1558, -0.1573, -0.1589, -0.1604, -0.1619, \n        -0.1634, -0.1649, -0.1664, -0.1679, -0.1695, -0.171, -0.1725, -0.174, -0.1755, -0.177, \n        -0.1785, -0.18, -0.1815, -0.183, -0.1845, -0.1861, -0.1876, -0.1891, -0.1906, -0.1921, \n        -0.1936, -0.1951, -0.1966, -0.1981, -0.1996, -0.2011, -0.2026, -0.2041, -0.2056, -0.2071, \n        -0.2086, -0.2101, -0.2116, -0.2131, -0.2146, -0.2161, -0.2176, -0.2191, -0.2206, -0.2221, \n        -0.2236, -0.2251, -0.2266, -0.2281, -0.2296, -0.2311, -0.2326, -0.234, -0.2355, -0.237, \n        -0.2385, -0.24, -0.2415, -0.243, -0.2445, -0.246, -0.2474, -0.2489, -0.2504, -0.2519, \n        -0.2534, -0.2549, -0.2563, -0.2578, -0.2593, -0.2608, -0.2623, -0.2638, -0.2652, -0.2667, \n        -0.2682, -0.2697, -0.2711, -0.2726, -0.2741, -0.2756, -0.277, -0.2785, -0.28, -0.2815, \n        -0.2829, -0.2844, -0.2859, -0.2873, -0.2888, -0.2903, -0.2918, -0.2932, -0.2947, -0.2962, \n        -0.2976, -0.2991, -0.3005, -0.302, -0.3035, -0.3049, -0.3064, -0.3078, -0.3093, -0.3108, \n        -0.3122, -0.3137, -0.3151, -0.3166, -0.318, -0.3195, -0.321, -0.3224, -0.3239, -0.3253, \n        -0.3268, -0.3282, -0.3297, -0.3311, -0.3326, -0.334, -0.3354, -0.3369, -0.3383, -0.3398, \n        -0.3412, -0.3427, -0.3441, -0.3455, -0.347, -0.3484, -0.3499, -0.3513, -0.3527, -0.3542, \n        -0.3556, -0.357, -0.3585, -0.3599, -0.3613, -0.3628, -0.3642, -0.3656, -0.367, -0.3685, \n        -0.3699, -0.3713, -0.3727, -0.3742, -0.3756, -0.377, -0.3784, -0.3798, -0.3813, -0.3827, \n        -0.3841, -0.3855, -0.3869, -0.3883, -0.3898, -0.3912, -0.3926, -0.394, -0.3954, -0.3968, \n        -0.3982, -0.3996, -0.401, -0.4024, -0.4038, -0.4052, -0.4066, -0.408, -0.4094, -0.4108, \n        -0.4122, -0.4136, -0.415, -0.4164, -0.4178, -0.4192, -0.4206, -0.422, -0.4234, -0.4248, \n        -0.4262, -0.4276, -0.4289, -0.4303, -0.4317, -0.4331, -0.4345, -0.4359, -0.4372, -0.4386, \n        -0.44, -0.4414, -0.4427, -0.4441, -0.4455, -0.4469, -0.4482, -0.4496, -0.451, -0.4523, \n        -0.4537, -0.4551, -0.4564, -0.4578, -0.4592, -0.4605, -0.4619, -0.4633, -0.4646, -0.466, \n        -0.4673, -0.4687, -0.47, -0.4714, -0.4727, -0.4741, -0.4755, -0.4768, -0.4781, -0.4795, \n        -0.4808, -0.4822, -0.4835, -0.4849, -0.4862, -0.4876, -0.4889, -0.4902, -0.4916, -0.4929, \n        -0.4942, -0.4956, -0.4969, -0.4982, -0.4996, -0.5009, -0.5022, -0.5035, -0.5049, -0.5062, \n        -0.5075, -0.5088, -0.5102, -0.5115, -0.5128, -0.5141, -0.5154, -0.5167, -0.518, -0.5194, \n        -0.5207, -0.522, -0.5233, -0.5246, -0.5259, -0.5272, -0.5285, -0.5298, -0.5311, -0.5324, \n        -0.5337, -0.535, -0.5363, -0.5376, -0.5389, -0.5402, -0.5415, -0.5428, -0.544, -0.5453, \n        -0.5466, -0.5479, -0.5492, -0.5505, -0.5517, -0.553, -0.5543, -0.5556, -0.5568, -0.5581, \n        -0.5594, -0.5607, -0.5619, -0.5632, -0.5645, -0.5657, -0.567, -0.5683, -0.5695, -0.5708, \n        -0.572, -0.5733, -0.5746, -0.5758, -0.5771, -0.5783, -0.5796, -0.5808, -0.5821, -0.5833, \n        -0.5846, -0.5858, -0.587, -0.5883, -0.5895, -0.5908, -0.592, -0.5932, -0.5945, -0.5957, \n        -0.5969, -0.5982, -0.5994, -0.6006, -0.6018, -0.6031, -0.6043, -0.6055, -0.6067, -0.6079, \n        -0.6092, -0.6104, -0.6116, -0.6128, -0.614, -0.6152, -0.6164, -0.6176, -0.6189, -0.6201, \n        -0.6213, -0.6225, -0.6237, -0.6249, -0.6261, -0.6273, -0.6284, -0.6296, -0.6308, -0.632, \n        -0.6332, -0.6344, -0.6356, -0.6368, -0.6379, -0.6391, -0.6403, -0.6415, -0.6427, -0.6438, \n        -0.645, -0.6462, -0.6473, -0.6485, -0.6497, -0.6508, -0.652, -0.6532, -0.6543, -0.6555, \n        -0.6567, -0.6578, -0.659, -0.6601, -0.6613, -0.6624, -0.6636, -0.6647, -0.6659, -0.667, \n        -0.6681, -0.6693, -0.6704, -0.6716, -0.6727, -0.6738, -0.675, -0.6761, -0.6772, -0.6784, \n        -0.6795, -0.6806, -0.6817, -0.6828, -0.684, -0.6851, -0.6862, -0.6873, -0.6884, -0.6895, \n        -0.6907, -0.6918, -0.6929, -0.694, -0.6951, -0.6962, -0.6973, -0.6984, -0.6995, -0.7006, \n        -0.7017, -0.7028, -0.7038, -0.7049, -0.706, -0.7071, -0.7082, -0.7093, -0.7104, -0.7114, \n        -0.7125, -0.7136, -0.7147, -0.7157, -0.7168, -0.7179, -0.7189, -0.72, -0.7211, -0.7221, \n        -0.7232, -0.7242, -0.7253, -0.7264, -0.7274, -0.7285, -0.7295, -0.7306, -0.7316, -0.7327, \n        -0.7337, -0.7347, -0.7358, -0.7368, -0.7379, -0.7389, -0.7399, -0.741, -0.742, -0.743, \n        -0.744, -0.7451, -0.7461, -0.7471, -0.7481, -0.7491, -0.7502, -0.7512, -0.7522, -0.7532, \n        -0.7542, -0.7552, -0.7562, -0.7572, -0.7582, -0.7592, -0.7602, -0.7612, -0.7622, -0.7632, \n        -0.7642, -0.7652, -0.7662, -0.7671, -0.7681, -0.7691, -0.7701, -0.7711, -0.772, -0.773, \n        -0.774, -0.775, -0.7759, -0.7769, -0.7779, -0.7788, -0.7798, -0.7807, -0.7817, -0.7827, \n        -0.7836, -0.7846, -0.7855, -0.7865, -0.7874, -0.7883, -0.7893, -0.7902, -0.7912, -0.7921, \n        -0.793, -0.794, -0.7949, -0.7958, -0.7968, -0.7977, -0.7986, -0.7995, -0.8005, -0.8014, \n        -0.8023, -0.8032, -0.8041, -0.805, -0.8059, -0.8068, -0.8078, -0.8087, -0.8096, -0.8105, \n        -0.8114, -0.8123, -0.8131, -0.814, -0.8149, -0.8158, -0.8167, -0.8176, -0.8185, -0.8193, \n        -0.8202, -0.8211, -0.822, -0.8228, -0.8237, -0.8246, -0.8255, -0.8263, -0.8272, -0.828, \n        -0.8289, -0.8298, -0.8306, -0.8315, -0.8323, -0.8332, -0.834, -0.8349, -0.8357, -0.8365, \n        -0.8374, -0.8382, -0.8391, -0.8399, -0.8407, -0.8416, -0.8424, -0.8432, -0.844, -0.8449, \n        -0.8457, -0.8465, -0.8473, -0.8481, -0.8489, -0.8497, -0.8505, -0.8514, -0.8522, -0.853, \n        -0.8538, -0.8546, -0.8554, -0.8561, -0.8569, -0.8577, -0.8585, -0.8593, -0.8601, -0.8609, \n        -0.8616, -0.8624, -0.8632, -0.864, -0.8647, -0.8655, -0.8663, -0.867, -0.8678, -0.8686, \n        -0.8693, -0.8701, -0.8708, -0.8716, -0.8723, -0.8731, -0.8738, -0.8746, -0.8753, -0.8761, \n        -0.8768, -0.8775, -0.8783, -0.879, -0.8797, -0.8805, -0.8812, -0.8819, -0.8826, -0.8834, \n        -0.8841, -0.8848, -0.8855, -0.8862, -0.8869, -0.8876, -0.8883, -0.889, -0.8897, -0.8904, \n        -0.8911, -0.8918, -0.8925, -0.8932, -0.8939, -0.8946, -0.8953, -0.896, -0.8966, -0.8973, \n        -0.898, -0.8987, -0.8993, -0.9, -0.9007, -0.9013, -0.902, -0.9027, -0.9033, -0.904, \n        -0.9046, -0.9053, -0.9059, -0.9066, -0.9072, -0.9079, -0.9085, -0.9092, -0.9098, -0.9104, \n        -0.9111, -0.9117, -0.9123, -0.913, -0.9136, -0.9142, -0.9148, -0.9154, -0.9161, -0.9167, \n        -0.9173, -0.9179, -0.9185, -0.9191, -0.9197, -0.9203, -0.9209, -0.9215, -0.9221, -0.9227, \n        -0.9233, -0.9239, -0.9245, -0.925, -0.9256, -0.9262, -0.9268, -0.9274, -0.9279, -0.9285, \n        -0.9291, -0.9296, -0.9302, -0.9308, -0.9313, -0.9319, -0.9324, -0.933, -0.9335, -0.9341, \n        -0.9346, -0.9352, -0.9357, -0.9363, -0.9368, -0.9373, -0.9379, -0.9384, -0.9389, -0.9395, \n        -0.94, -0.9405, -0.941, -0.9415, -0.9421, -0.9426, -0.9431, -0.9436, -0.9441, -0.9446, \n        -0.9451, -0.9456, -0.9461, -0.9466, -0.9471, -0.9476, -0.9481, -0.9486, -0.949, -0.9495, \n        -0.95, -0.9505, -0.951, -0.9514, -0.9519, -0.9524, -0.9528, -0.9533, -0.9538, -0.9542, \n        -0.9547, -0.9551, -0.9556, -0.956, -0.9565, -0.9569, -0.9574, -0.9578, -0.9583, -0.9587, \n        -0.9591, -0.9596, -0.96, -0.9604, -0.9609, -0.9613, -0.9617, -0.9621, -0.9625, -0.963, \n        -0.9634, -0.9638, -0.9642, -0.9646, -0.965, -0.9654, -0.9658, -0.9662, -0.9666, -0.967, \n        -0.9674, -0.9678, -0.9681, -0.9685, -0.9689, -0.9693, -0.9697, -0.97, -0.9704, -0.9708, \n        -0.9711, -0.9715, -0.9719, -0.9722, -0.9726, -0.9729, -0.9733, -0.9736, -0.974, -0.9743, \n        -0.9747, -0.975, -0.9754, -0.9757, -0.976, -0.9764, -0.9767, -0.977, -0.9774, -0.9777, \n        -0.978, -0.9783, -0.9786, -0.9789, -0.9793, -0.9796, -0.9799, -0.9802, -0.9805, -0.9808, \n        -0.9811, -0.9814, -0.9817, -0.982, -0.9823, -0.9825, -0.9828, -0.9831, -0.9834, -0.9837, \n        -0.9839, -0.9842, -0.9845, -0.9847, -0.985, -0.9853, -0.9855, -0.9858, -0.9861, -0.9863, \n        -0.9866, -0.9868, -0.9871, -0.9873, -0.9875, -0.9878, -0.988, -0.9883, -0.9885, -0.9887, \n        -0.989, -0.9892, -0.9894, -0.9896, -0.9898, -0.9901, -0.9903, -0.9905, -0.9907, -0.9909, \n        -0.9911, -0.9913, -0.9915, -0.9917, -0.9919, -0.9921, -0.9923, -0.9925, -0.9927, -0.9929, \n        -0.993, -0.9932, -0.9934, -0.9936, -0.9937, -0.9939, -0.9941, -0.9942, -0.9944, -0.9946, \n        -0.9947, -0.9949, -0.995, -0.9952, -0.9953, -0.9955, -0.9956, -0.9958, -0.9959, -0.996, \n        -0.9962, -0.9963, -0.9964, -0.9966, -0.9967, -0.9968, -0.9969, -0.9971, -0.9972, -0.9973, \n        -0.9974, -0.9975, -0.9976, -0.9977, -0.9978, -0.9979, -0.998, -0.9981, -0.9982, -0.9983, \n        -0.9984, -0.9985, -0.9986, -0.9986, -0.9987, -0.9988, -0.9989, -0.9989, -0.999, -0.9991, \n        -0.9991, -0.9992, -0.9993, -0.9993, -0.9994, -0.9994, -0.9995, -0.9995, -0.9996, -0.9996, \n        -0.9997, -0.9997, -0.9997, -0.9998, -0.9998, -0.9998, -0.9999, -0.9999, -0.9999, -0.9999, \n        -0.9999, -1, -1, -1, -1, -1, -1, -1, -1, -1, \n        -1, -1, -1, -1, -0.9999, -0.9999, -0.9999, -0.9999, -0.9999, -0.9998, \n        -0.9998, -0.9998, -0.9997, -0.9997, -0.9997, -0.9996, -0.9996, -0.9995, -0.9995, -0.9994, \n        -0.9994, -0.9993, -0.9993, -0.9992, -0.9991, -0.9991, -0.999, -0.9989, -0.9989, -0.9988, \n        -0.9987, -0.9986, -0.9986, -0.9985, -0.9984, -0.9983, -0.9982, -0.9981, -0.998, -0.9979, \n        -0.9978, -0.9977, -0.9976, -0.9975, -0.9974, -0.9973, -0.9972, -0.9971, -0.9969, -0.9968, \n        -0.9967, -0.9966, -0.9964, -0.9963, -0.9962, -0.996, -0.9959, -0.9958, -0.9956, -0.9955, \n        -0.9953, -0.9952, -0.995, -0.9949, -0.9947, -0.9946, -0.9944, -0.9942, -0.9941, -0.9939, \n        -0.9937, -0.9936, -0.9934, -0.9932, -0.993, -0.9929, -0.9927, -0.9925, -0.9923, -0.9921, \n        -0.9919, -0.9917, -0.9915, -0.9913, -0.9911, -0.9909, -0.9907, -0.9905, -0.9903, -0.9901, \n        -0.9898, -0.9896, -0.9894, -0.9892, -0.989, -0.9887, -0.9885, -0.9883, -0.988, -0.9878, \n        -0.9875, -0.9873, -0.9871, -0.9868, -0.9866, -0.9863, -0.9861, -0.9858, -0.9855, -0.9853, \n        -0.985, -0.9847, -0.9845, -0.9842, -0.9839, -0.9837, -0.9834, -0.9831, -0.9828, -0.9825, \n        -0.9823, -0.982, -0.9817, -0.9814, -0.9811, -0.9808, -0.9805, -0.9802, -0.9799, -0.9796, \n        -0.9793, -0.9789, -0.9786, -0.9783, -0.978, -0.9777, -0.9774, -0.977, -0.9767, -0.9764, \n        -0.976, -0.9757, -0.9754, -0.975, -0.9747, -0.9743, -0.974, -0.9736, -0.9733, -0.9729, \n        -0.9726, -0.9722, -0.9719, -0.9715, -0.9711, -0.9708, -0.9704, -0.97, -0.9697, -0.9693, \n        -0.9689, -0.9685, -0.9681, -0.9678, -0.9674, -0.967, -0.9666, -0.9662, -0.9658, -0.9654, \n        -0.965, -0.9646, -0.9642, -0.9638, -0.9634, -0.963, -0.9625, -0.9621, -0.9617, -0.9613, \n        -0.9609, -0.9604, -0.96, -0.9596, -0.9591, -0.9587, -0.9583, -0.9578, -0.9574, -0.9569, \n        -0.9565, -0.956, -0.9556, -0.9551, -0.9547, -0.9542, -0.9538, -0.9533, -0.9528, -0.9524, \n        -0.9519, -0.9514, -0.951, -0.9505, -0.95, -0.9495, -0.949, -0.9486, -0.9481, -0.9476, \n        -0.9471, -0.9466, -0.9461, -0.9456, -0.9451, -0.9446, -0.9441, -0.9436, -0.9431, -0.9426, \n        -0.9421, -0.9415, -0.941, -0.9405, -0.94, -0.9395, -0.9389, -0.9384, -0.9379, -0.9373, \n        -0.9368, -0.9363, -0.9357, -0.9352, -0.9346, -0.9341, -0.9335, -0.933, -0.9324, -0.9319, \n        -0.9313, -0.9308, -0.9302, -0.9296, -0.9291, -0.9285, -0.9279, -0.9274, -0.9268, -0.9262, \n        -0.9256, -0.925, -0.9245, -0.9239, -0.9233, -0.9227, -0.9221, -0.9215, -0.9209, -0.9203, \n        -0.9197, -0.9191, -0.9185, -0.9179, -0.9173, -0.9167, -0.9161, -0.9154, -0.9148, -0.9142, \n        -0.9136, -0.913, -0.9123, -0.9117, -0.9111, -0.9104, -0.9098, -0.9092, -0.9085, -0.9079, \n        -0.9072, -0.9066, -0.9059, -0.9053, -0.9046, -0.904, -0.9033, -0.9027, -0.902, -0.9013, \n        -0.9007, -0.9, -0.8993, -0.8987, -0.898, -0.8973, -0.8966, -0.896, -0.8953, -0.8946, \n        -0.8939, -0.8932, -0.8925, -0.8918, -0.8911, -0.8904, -0.8897, -0.889, -0.8883, -0.8876, \n        -0.8869, -0.8862, -0.8855, -0.8848, -0.8841, -0.8834, -0.8826, -0.8819, -0.8812, -0.8805, \n        -0.8797, -0.879, -0.8783, -0.8775, -0.8768, -0.8761, -0.8753, -0.8746, -0.8738, -0.8731, \n        -0.8723, -0.8716, -0.8708, -0.8701, -0.8693, -0.8686, -0.8678, -0.867, -0.8663, -0.8655, \n        -0.8647, -0.864, -0.8632, -0.8624, -0.8616, -0.8609, -0.8601, -0.8593, -0.8585, -0.8577, \n        -0.8569, -0.8561, -0.8554, -0.8546, -0.8538, -0.853, -0.8522, -0.8514, -0.8505, -0.8497, \n        -0.8489, -0.8481, -0.8473, -0.8465, -0.8457, -0.8449, -0.844, -0.8432, -0.8424, -0.8416, \n        -0.8407, -0.8399, -0.8391, -0.8382, -0.8374, -0.8365, -0.8357, -0.8349, -0.834, -0.8332, \n        -0.8323, -0.8315, -0.8306, -0.8298, -0.8289, -0.828, -0.8272, -0.8263, -0.8255, -0.8246, \n        -0.8237, -0.8228, -0.822, -0.8211, -0.8202, -0.8193, -0.8185, -0.8176, -0.8167, -0.8158, \n        -0.8149, -0.814, -0.8131, -0.8123, -0.8114, -0.8105, -0.8096, -0.8087, -0.8078, -0.8068, \n        -0.8059, -0.805, -0.8041, -0.8032, -0.8023, -0.8014, -0.8005, -0.7995, -0.7986, -0.7977, \n        -0.7968, -0.7958, -0.7949, -0.794, -0.793, -0.7921, -0.7912, -0.7902, -0.7893, -0.7883, \n        -0.7874, -0.7865, -0.7855, -0.7846, -0.7836, -0.7827, -0.7817, -0.7807, -0.7798, -0.7788, \n        -0.7779, -0.7769, -0.7759, -0.775, -0.774, -0.773, -0.772, -0.7711, -0.7701, -0.7691, \n        -0.7681, -0.7671, -0.7662, -0.7652, -0.7642, -0.7632, -0.7622, -0.7612, -0.7602, -0.7592, \n        -0.7582, -0.7572, -0.7562, -0.7552, -0.7542, -0.7532, -0.7522, -0.7512, -0.7502, -0.7491, \n        -0.7481, -0.7471, -0.7461, -0.7451, -0.744, -0.743, -0.742, -0.741, -0.7399, -0.7389, \n        -0.7379, -0.7368, -0.7358, -0.7347, -0.7337, -0.7327, -0.7316, -0.7306, -0.7295, -0.7285, \n        -0.7274, -0.7264, -0.7253, -0.7242, -0.7232, -0.7221, -0.7211, -0.72, -0.7189, -0.7179, \n        -0.7168, -0.7157, -0.7147, -0.7136, -0.7125, -0.7114, -0.7104, -0.7093, -0.7082, -0.7071, \n        -0.706, -0.7049, -0.7038, -0.7028, -0.7017, -0.7006, -0.6995, -0.6984, -0.6973, -0.6962, \n        -0.6951, -0.694, -0.6929, -0.6918, -0.6907, -0.6895, -0.6884, -0.6873, -0.6862, -0.6851, \n        -0.684, -0.6828, -0.6817, -0.6806, -0.6795, -0.6784, -0.6772, -0.6761, -0.675, -0.6738, \n        -0.6727, -0.6716, -0.6704, -0.6693, -0.6681, -0.667, -0.6659, -0.6647, -0.6636, -0.6624, \n        -0.6613, -0.6601, -0.659, -0.6578, -0.6567, -0.6555, -0.6543, -0.6532, -0.652, -0.6508, \n        -0.6497, -0.6485, -0.6473, -0.6462, -0.645, -0.6438, -0.6427, -0.6415, -0.6403, -0.6391, \n        -0.6379, -0.6368, -0.6356, -0.6344, -0.6332, -0.632, -0.6308, -0.6296, -0.6284, -0.6273, \n        -0.6261, -0.6249, -0.6237, -0.6225, -0.6213, -0.6201, -0.6189, -0.6176, -0.6164, -0.6152, \n        -0.614, -0.6128, -0.6116, -0.6104, -0.6092, -0.6079, -0.6067, -0.6055, -0.6043, -0.6031, \n        -0.6018, -0.6006, -0.5994, -0.5982, -0.5969, -0.5957, -0.5945, -0.5932, -0.592, -0.5908, \n        -0.5895, -0.5883, -0.587, -0.5858, -0.5846, -0.5833, -0.5821, -0.5808, -0.5796, -0.5783, \n        -0.5771, -0.5758, -0.5746, -0.5733, -0.572, -0.5708, -0.5695, -0.5683, -0.567, -0.5657, \n        -0.5645, -0.5632, -0.5619, -0.5607, -0.5594, -0.5581, -0.5568, -0.5556, -0.5543, -0.553, \n        -0.5517, -0.5505, -0.5492, -0.5479, -0.5466, -0.5453, -0.544, -0.5428, -0.5415, -0.5402, \n        -0.5389, -0.5376, -0.5363, -0.535, -0.5337, -0.5324, -0.5311, -0.5298, -0.5285, -0.5272, \n        -0.5259, -0.5246, -0.5233, -0.522, -0.5207, -0.5194, -0.518, -0.5167, -0.5154, -0.5141, \n        -0.5128, -0.5115, -0.5102, -0.5088, -0.5075, -0.5062, -0.5049, -0.5035, -0.5022, -0.5009, \n        -0.4996, -0.4982, -0.4969, -0.4956, -0.4942, -0.4929, -0.4916, -0.4902, -0.4889, -0.4876, \n        -0.4862, -0.4849, -0.4835, -0.4822, -0.4808, -0.4795, -0.4781, -0.4768, -0.4755, -0.4741, \n        -0.4727, -0.4714, -0.47, -0.4687, -0.4673, -0.466, -0.4646, -0.4633, -0.4619, -0.4605, \n        -0.4592, -0.4578, -0.4564, -0.4551, -0.4537, -0.4523, -0.451, -0.4496, -0.4482, -0.4469, \n        -0.4455, -0.4441, -0.4427, -0.4414, -0.44, -0.4386, -0.4372, -0.4359, -0.4345, -0.4331, \n        -0.4317, -0.4303, -0.4289, -0.4276, -0.4262, -0.4248, -0.4234, -0.422, -0.4206, -0.4192, \n        -0.4178, -0.4164, -0.415, -0.4136, -0.4122, -0.4108, -0.4094, -0.408, -0.4066, -0.4052, \n        -0.4038, -0.4024, -0.401, -0.3996, -0.3982, -0.3968, -0.3954, -0.394, -0.3926, -0.3912, \n        -0.3898, -0.3883, -0.3869, -0.3855, -0.3841, -0.3827, -0.3813, -0.3798, -0.3784, -0.377, \n        -0.3756, -0.3742, -0.3727, -0.3713, -0.3699, -0.3685, -0.367, -0.3656, -0.3642, -0.3628, \n        -0.3613, -0.3599, -0.3585, -0.357, -0.3556, -0.3542, -0.3527, -0.3513, -0.3499, -0.3484, \n        -0.347, -0.3455, -0.3441, -0.3427, -0.3412, -0.3398, -0.3383, -0.3369, -0.3354, -0.334, \n        -0.3326, -0.3311, -0.3297, -0.3282, -0.3268, -0.3253, -0.3239, -0.3224, -0.321, -0.3195, \n        -0.318, -0.3166, -0.3151, -0.3137, -0.3122, -0.3108, -0.3093, -0.3078, -0.3064, -0.3049, \n        -0.3035, -0.302, -0.3005, -0.2991, -0.2976, -0.2962, -0.2947, -0.2932, -0.2918, -0.2903, \n        -0.2888, -0.2873, -0.2859, -0.2844, -0.2829, -0.2815, -0.28, -0.2785, -0.277, -0.2756, \n        -0.2741, -0.2726, -0.2711, -0.2697, -0.2682, -0.2667, -0.2652, -0.2638, -0.2623, -0.2608, \n        -0.2593, -0.2578, -0.2563, -0.2549, -0.2534, -0.2519, -0.2504, -0.2489, -0.2474, -0.246, \n        -0.2445, -0.243, -0.2415, -0.24, -0.2385, -0.237, -0.2355, -0.234, -0.2326, -0.2311, \n        -0.2296, -0.2281, -0.2266, -0.2251, -0.2236, -0.2221, -0.2206, -0.2191, -0.2176, -0.2161, \n        -0.2146, -0.2131, -0.2116, -0.2101, -0.2086, -0.2071, -0.2056, -0.2041, -0.2026, -0.2011, \n        -0.1996, -0.1981, -0.1966, -0.1951, -0.1936, -0.1921, -0.1906, -0.1891, -0.1876, -0.1861, \n        -0.1845, -0.183, -0.1815, -0.18, -0.1785, -0.177, -0.1755, -0.174, -0.1725, -0.171, \n        -0.1695, -0.1679, -0.1664, -0.1649, -0.1634, -0.1619, -0.1604, -0.1589, -0.1573, -0.1558, \n        -0.1543, -0.1528, -0.1513, -0.1498, -0.1482, -0.1467, -0.1452, -0.1437, -0.1422, -0.1407, \n        -0.1391, -0.1376, -0.1361, -0.1346, -0.1331, -0.1315, -0.13, -0.1285, -0.127, -0.1255, \n        -0.1239, -0.1224, -0.1209, -0.1194, -0.1178, -0.1163, -0.1148, -0.1133, -0.1117, -0.1102, \n        -0.1087, -0.1072, -0.1056, -0.1041, -0.1026, -0.1011, -0.09954, -0.09802, -0.09649, -0.09496, \n        -0.09344, -0.09191, -0.09038, -0.08885, -0.08733, -0.0858, -0.08427, -0.08274, -0.08121, -0.07968, \n        -0.07815, -0.07662, -0.07509, -0.07356, -0.07203, -0.0705, -0.06897, -0.06744, -0.06591, -0.06438, \n        -0.06285, -0.06132, -0.05979, -0.05826, -0.05673, -0.0552, -0.05366, -0.05213, -0.0506, -0.04907, \n        -0.04754, -0.046, -0.04447, -0.04294, -0.04141, -0.03987, -0.03834, -0.03681, -0.03527, -0.03374, \n        -0.03221, -0.03067, -0.02914, -0.02761, -0.02607, -0.02454, -0.02301, -0.02147, -0.01994, -0.01841, \n        -0.01687, -0.01534, -0.01381, -0.01227, -0.01074, -0.009204, -0.00767, -0.006136, -0.004602, -0.003068, \n        -0.001534, -1.837e-16, 0.001534, 0.003068, 0.004602, 0.006136, 0.00767, 0.009204, 0.01074, 0.01227, \n        0.01381, 0.01534, 0.01687, 0.01841, 0.01994, 0.02147, 0.02301, 0.02454, 0.02607, 0.02761, \n        0.02914, 0.03067, 0.03221, 0.03374, 0.03527, 0.03681, 0.03834, 0.03987, 0.04141, 0.04294, \n        0.04447, 0.046, 0.04754, 0.04907, 0.0506, 0.05213, 0.05366, 0.0552, 0.05673, 0.05826, \n        0.05979, 0.06132, 0.06285, 0.06438, 0.06591, 0.06744, 0.06897, 0.0705, 0.07203, 0.07356, \n        0.07509, 0.07662, 0.07815, 0.07968, 0.08121, 0.08274, 0.08427, 0.0858, 0.08733, 0.08885, \n        0.09038, 0.09191, 0.09344, 0.09496, 0.09649, 0.09802, 0.09954, 0.1011, 0.1026, 0.1041, \n        0.1056, 0.1072, 0.1087, 0.1102, 0.1117, 0.1133, 0.1148, 0.1163, 0.1178, 0.1194, \n        0.1209, 0.1224, 0.1239, 0.1255, 0.127, 0.1285, 0.13, 0.1315, 0.1331, 0.1346, \n        0.1361, 0.1376, 0.1391, 0.1407, 0.1422, 0.1437, 0.1452, 0.1467, 0.1482, 0.1498, \n        0.1513, 0.1528, 0.1543, 0.1558, 0.1573, 0.1589, 0.1604, 0.1619, 0.1634, 0.1649, \n        0.1664, 0.1679, 0.1695, 0.171, 0.1725, 0.174, 0.1755, 0.177, 0.1785, 0.18, \n        0.1815, 0.183, 0.1845, 0.1861, 0.1876, 0.1891, 0.1906, 0.1921, 0.1936, 0.1951, \n        0.1966, 0.1981, 0.1996, 0.2011, 0.2026, 0.2041, 0.2056, 0.2071, 0.2086, 0.2101, \n        0.2116, 0.2131, 0.2146, 0.2161, 0.2176, 0.2191, 0.2206, 0.2221, 0.2236, 0.2251, \n        0.2266, 0.2281, 0.2296, 0.2311, 0.2326, 0.234, 0.2355, 0.237, 0.2385, 0.24, \n        0.2415, 0.243, 0.2445, 0.246, 0.2474, 0.2489, 0.2504, 0.2519, 0.2534, 0.2549, \n        0.2563, 0.2578, 0.2593, 0.2608, 0.2623, 0.2638, 0.2652, 0.2667, 0.2682, 0.2697, \n        0.2711, 0.2726, 0.2741, 0.2756, 0.277, 0.2785, 0.28, 0.2815, 0.2829, 0.2844, \n        0.2859, 0.2873, 0.2888, 0.2903, 0.2918, 0.2932, 0.2947, 0.2962, 0.2976, 0.2991, \n        0.3005, 0.302, 0.3035, 0.3049, 0.3064, 0.3078, 0.3093, 0.3108, 0.3122, 0.3137, \n        0.3151, 0.3166, 0.318, 0.3195, 0.321, 0.3224, 0.3239, 0.3253, 0.3268, 0.3282, \n        0.3297, 0.3311, 0.3326, 0.334, 0.3354, 0.3369, 0.3383, 0.3398, 0.3412, 0.3427, \n        0.3441, 0.3455, 0.347, 0.3484, 0.3499, 0.3513, 0.3527, 0.3542, 0.3556, 0.357, \n        0.3585, 0.3599, 0.3613, 0.3628, 0.3642, 0.3656, 0.367, 0.3685, 0.3699, 0.3713, \n        0.3727, 0.3742, 0.3756, 0.377, 0.3784, 0.3798, 0.3813, 0.3827, 0.3841, 0.3855, \n        0.3869, 0.3883, 0.3898, 0.3912, 0.3926, 0.394, 0.3954, 0.3968, 0.3982, 0.3996, \n        0.401, 0.4024, 0.4038, 0.4052, 0.4066, 0.408, 0.4094, 0.4108, 0.4122, 0.4136, \n        0.415, 0.4164, 0.4178, 0.4192, 0.4206, 0.422, 0.4234, 0.4248, 0.4262, 0.4276, \n        0.4289, 0.4303, 0.4317, 0.4331, 0.4345, 0.4359, 0.4372, 0.4386, 0.44, 0.4414, \n        0.4427, 0.4441, 0.4455, 0.4469, 0.4482, 0.4496, 0.451, 0.4523, 0.4537, 0.4551, \n        0.4564, 0.4578, 0.4592, 0.4605, 0.4619, 0.4633, 0.4646, 0.466, 0.4673, 0.4687, \n        0.47, 0.4714, 0.4727, 0.4741, 0.4755, 0.4768, 0.4781, 0.4795, 0.4808, 0.4822, \n        0.4835, 0.4849, 0.4862, 0.4876, 0.4889, 0.4902, 0.4916, 0.4929, 0.4942, 0.4956, \n        0.4969, 0.4982, 0.4996, 0.5009, 0.5022, 0.5035, 0.5049, 0.5062, 0.5075, 0.5088, \n        0.5102, 0.5115, 0.5128, 0.5141, 0.5154, 0.5167, 0.518, 0.5194, 0.5207, 0.522, \n        0.5233, 0.5246, 0.5259, 0.5272, 0.5285, 0.5298, 0.5311, 0.5324, 0.5337, 0.535, \n        0.5363, 0.5376, 0.5389, 0.5402, 0.5415, 0.5428, 0.544, 0.5453, 0.5466, 0.5479, \n        0.5492, 0.5505, 0.5517, 0.553, 0.5543, 0.5556, 0.5568, 0.5581, 0.5594, 0.5607, \n        0.5619, 0.5632, 0.5645, 0.5657, 0.567, 0.5683, 0.5695, 0.5708, 0.572, 0.5733, \n        0.5746, 0.5758, 0.5771, 0.5783, 0.5796, 0.5808, 0.5821, 0.5833, 0.5846, 0.5858, \n        0.587, 0.5883, 0.5895, 0.5908, 0.592, 0.5932, 0.5945, 0.5957, 0.5969, 0.5982, \n        0.5994, 0.6006, 0.6018, 0.6031, 0.6043, 0.6055, 0.6067, 0.6079, 0.6092, 0.6104, \n        0.6116, 0.6128, 0.614, 0.6152, 0.6164, 0.6176, 0.6189, 0.6201, 0.6213, 0.6225, \n        0.6237, 0.6249, 0.6261, 0.6273, 0.6284, 0.6296, 0.6308, 0.632, 0.6332, 0.6344, \n        0.6356, 0.6368, 0.6379, 0.6391, 0.6403, 0.6415, 0.6427, 0.6438, 0.645, 0.6462, \n        0.6473, 0.6485, 0.6497, 0.6508, 0.652, 0.6532, 0.6543, 0.6555, 0.6567, 0.6578, \n        0.659, 0.6601, 0.6613, 0.6624, 0.6636, 0.6647, 0.6659, 0.667, 0.6681, 0.6693, \n        0.6704, 0.6716, 0.6727, 0.6738, 0.675, 0.6761, 0.6772, 0.6784, 0.6795, 0.6806, \n        0.6817, 0.6828, 0.684, 0.6851, 0.6862, 0.6873, 0.6884, 0.6895, 0.6907, 0.6918, \n        0.6929, 0.694, 0.6951, 0.6962, 0.6973, 0.6984, 0.6995, 0.7006, 0.7017, 0.7028, \n        0.7038, 0.7049, 0.706, 0.7071, 0.7082, 0.7093, 0.7104, 0.7114, 0.7125, 0.7136, \n        0.7147, 0.7157, 0.7168, 0.7179, 0.7189, 0.72, 0.7211, 0.7221, 0.7232, 0.7242, \n        0.7253, 0.7264, 0.7274, 0.7285, 0.7295, 0.7306, 0.7316, 0.7327, 0.7337, 0.7347, \n        0.7358, 0.7368, 0.7379, 0.7389, 0.7399, 0.741, 0.742, 0.743, 0.744, 0.7451, \n        0.7461, 0.7471, 0.7481, 0.7491, 0.7502, 0.7512, 0.7522, 0.7532, 0.7542, 0.7552, \n        0.7562, 0.7572, 0.7582, 0.7592, 0.7602, 0.7612, 0.7622, 0.7632, 0.7642, 0.7652, \n        0.7662, 0.7671, 0.7681, 0.7691, 0.7701, 0.7711, 0.772, 0.773, 0.774, 0.775, \n        0.7759, 0.7769, 0.7779, 0.7788, 0.7798, 0.7807, 0.7817, 0.7827, 0.7836, 0.7846, \n        0.7855, 0.7865, 0.7874, 0.7883, 0.7893, 0.7902, 0.7912, 0.7921, 0.793, 0.794, \n        0.7949, 0.7958, 0.7968, 0.7977, 0.7986, 0.7995, 0.8005, 0.8014, 0.8023, 0.8032, \n        0.8041, 0.805, 0.8059, 0.8068, 0.8078, 0.8087, 0.8096, 0.8105, 0.8114, 0.8123, \n        0.8131, 0.814, 0.8149, 0.8158, 0.8167, 0.8176, 0.8185, 0.8193, 0.8202, 0.8211, \n        0.822, 0.8228, 0.8237, 0.8246, 0.8255, 0.8263, 0.8272, 0.828, 0.8289, 0.8298, \n        0.8306, 0.8315, 0.8323, 0.8332, 0.834, 0.8349, 0.8357, 0.8365, 0.8374, 0.8382, \n        0.8391, 0.8399, 0.8407, 0.8416, 0.8424, 0.8432, 0.844, 0.8449, 0.8457, 0.8465, \n        0.8473, 0.8481, 0.8489, 0.8497, 0.8505, 0.8514, 0.8522, 0.853, 0.8538, 0.8546, \n        0.8554, 0.8561, 0.8569, 0.8577, 0.8585, 0.8593, 0.8601, 0.8609, 0.8616, 0.8624, \n        0.8632, 0.864, 0.8647, 0.8655, 0.8663, 0.867, 0.8678, 0.8686, 0.8693, 0.8701, \n        0.8708, 0.8716, 0.8723, 0.8731, 0.8738, 0.8746, 0.8753, 0.8761, 0.8768, 0.8775, \n        0.8783, 0.879, 0.8797, 0.8805, 0.8812, 0.8819, 0.8826, 0.8834, 0.8841, 0.8848, \n        0.8855, 0.8862, 0.8869, 0.8876, 0.8883, 0.889, 0.8897, 0.8904, 0.8911, 0.8918, \n        0.8925, 0.8932, 0.8939, 0.8946, 0.8953, 0.896, 0.8966, 0.8973, 0.898, 0.8987, \n        0.8993, 0.9, 0.9007, 0.9013, 0.902, 0.9027, 0.9033, 0.904, 0.9046, 0.9053, \n        0.9059, 0.9066, 0.9072, 0.9079, 0.9085, 0.9092, 0.9098, 0.9104, 0.9111, 0.9117, \n        0.9123, 0.913, 0.9136, 0.9142, 0.9148, 0.9154, 0.9161, 0.9167, 0.9173, 0.9179, \n        0.9185, 0.9191, 0.9197, 0.9203, 0.9209, 0.9215, 0.9221, 0.9227, 0.9233, 0.9239, \n        0.9245, 0.925, 0.9256, 0.9262, 0.9268, 0.9274, 0.9279, 0.9285, 0.9291, 0.9296, \n        0.9302, 0.9308, 0.9313, 0.9319, 0.9324, 0.933, 0.9335, 0.9341, 0.9346, 0.9352, \n        0.9357, 0.9363, 0.9368, 0.9373, 0.9379, 0.9384, 0.9389, 0.9395, 0.94, 0.9405, \n        0.941, 0.9415, 0.9421, 0.9426, 0.9431, 0.9436, 0.9441, 0.9446, 0.9451, 0.9456, \n        0.9461, 0.9466, 0.9471, 0.9476, 0.9481, 0.9486, 0.949, 0.9495, 0.95, 0.9505, \n        0.951, 0.9514, 0.9519, 0.9524, 0.9528, 0.9533, 0.9538, 0.9542, 0.9547, 0.9551, \n        0.9556, 0.956, 0.9565, 0.9569, 0.9574, 0.9578, 0.9583, 0.9587, 0.9591, 0.9596, \n        0.96, 0.9604, 0.9609, 0.9613, 0.9617, 0.9621, 0.9625, 0.963, 0.9634, 0.9638, \n        0.9642, 0.9646, 0.965, 0.9654, 0.9658, 0.9662, 0.9666, 0.967, 0.9674, 0.9678, \n        0.9681, 0.9685, 0.9689, 0.9693, 0.9697, 0.97, 0.9704, 0.9708, 0.9711, 0.9715, \n        0.9719, 0.9722, 0.9726, 0.9729, 0.9733, 0.9736, 0.974, 0.9743, 0.9747, 0.975, \n        0.9754, 0.9757, 0.976, 0.9764, 0.9767, 0.977, 0.9774, 0.9777, 0.978, 0.9783, \n        0.9786, 0.9789, 0.9793, 0.9796, 0.9799, 0.9802, 0.9805, 0.9808, 0.9811, 0.9814, \n        0.9817, 0.982, 0.9823, 0.9825, 0.9828, 0.9831, 0.9834, 0.9837, 0.9839, 0.9842, \n        0.9845, 0.9847, 0.985, 0.9853, 0.9855, 0.9858, 0.9861, 0.9863, 0.9866, 0.9868, \n        0.9871, 0.9873, 0.9875, 0.9878, 0.988, 0.9883, 0.9885, 0.9887, 0.989, 0.9892, \n        0.9894, 0.9896, 0.9898, 0.9901, 0.9903, 0.9905, 0.9907, 0.9909, 0.9911, 0.9913, \n        0.9915, 0.9917, 0.9919, 0.9921, 0.9923, 0.9925, 0.9927, 0.9929, 0.993, 0.9932, \n        0.9934, 0.9936, 0.9937, 0.9939, 0.9941, 0.9942, 0.9944, 0.9946, 0.9947, 0.9949, \n        0.995, 0.9952, 0.9953, 0.9955, 0.9956, 0.9958, 0.9959, 0.996, 0.9962, 0.9963, \n        0.9964, 0.9966, 0.9967, 0.9968, 0.9969, 0.9971, 0.9972, 0.9973, 0.9974, 0.9975, \n        0.9976, 0.9977, 0.9978, 0.9979, 0.998, 0.9981, 0.9982, 0.9983, 0.9984, 0.9985, \n        0.9986, 0.9986, 0.9987, 0.9988, 0.9989, 0.9989, 0.999, 0.9991, 0.9991, 0.9992, \n        0.9993, 0.9993, 0.9994, 0.9994, 0.9995, 0.9995, 0.9996, 0.9996, 0.9997, 0.9997, \n        0.9997, 0.9998, 0.9998, 0.9998, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 1, \n        1, 1, 1, 1, 1, 1};\n\n        const static uint64 mask = max-1; \n        return logvals[h.first&mask]*cosvals[h.second&mask];\n\n        // Note that we are just using the Box-Muller transform to compute the result.  In\n        // particular, we are doing this (where u1 and u2 are uniform random variables in\n        // the range [0,1]): \n        //    return sqrt(-2*log(u1)) * cos(2*PI*u2);\n        // It is just that we use table lookups to avoid calling sqrt(), log() and cos().\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANDOM_HAsHING_Hh_\n\n"
  },
  {
    "path": "dlib/general_hash/random_hashing_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RANDOM_HAsHING_ABSTRACT_Hh_ \n#ifdef DLIB_RANDOM_HAsHING_ABSTRACT_Hh_ \n\n#include \"random_hashing_abstract.h\"\n#include \"murmur_hash3.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    double uniform_random_hash (\n        const uint64& k1,\n        const uint64& k2,\n        const uint64& k3\n    );\n    /*!\n        ensures\n            - This function uses hashing to generate uniform random values in the range [0,1).\n            - To define this function precisely, assume we have an arbitrary sequence of\n              input triplets.  Then calling uniform_random_hash() on each of them should\n              result in a sequence of double values that look like numbers sampled\n              independently and uniformly at random from the interval [0,1).  This is true\n              even if there is some simple pattern in the inputs.  For example, (0,0,0),\n              (1,0,0), (2,0,0), (3,0,0), etc.\n            - This function is deterministic.  That is, the same output is always returned\n              when given the same input.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    double gaussian_random_hash (\n        const uint64& k1,\n        const uint64& k2,\n        const uint64& k3\n    );\n    /*!\n        ensures\n            - This function uses hashing to generate Gaussian distributed random values\n              with mean 0 and variance 1.  \n            - To define this function precisely, assume we have an arbitrary sequence of\n              input triplets.  Then calling gaussian_random_hash() on each of them should\n              result in a sequence of double values that look like numbers sampled\n              independently from a standard normal distribution.  This is true even if\n              there is some simple pattern in the inputs.  For example, (0,0,0), (1,0,0),\n              (2,0,0), (3,0,0), etc.\n            - This function is deterministic.  That is, the same output is always returned\n              when given the same input.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANDOM_HAsHING_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/geometry/border_enumerator.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BORDER_EnUMERATOR_H_\n#define DLIB_BORDER_EnUMERATOR_H_\n\n#include \"border_enumerator_abstract.h\"\n#include \"rectangle.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class border_enumerator\n    {\n    public:\n        border_enumerator(\n        ) \n        {\n            reset();\n        }\n\n        border_enumerator(\n            const rectangle& rect_,\n            unsigned long border_size\n        ) : \n            rect(rect_),\n            inner_rect(shrink_rect(rect_, border_size))\n        {\n            reset();\n        }\n\n        border_enumerator(\n            const rectangle& rect_,\n            const rectangle& non_border_region\n        ) : \n            rect(rect_),\n            inner_rect(non_border_region.intersect(rect))\n        {\n            reset();\n        }\n\n        void reset (\n        ) \n        {\n            // make the four rectangles that surround inner_rect and intersect them\n            // with rect.\n            bleft   = rect.intersect(rectangle(std::numeric_limits<long>::min(),\n                                               std::numeric_limits<long>::min(),\n                                               inner_rect.left()-1,\n                                               std::numeric_limits<long>::max()));\n\n            bright  = rect.intersect(rectangle(inner_rect.right()+1,\n                                               std::numeric_limits<long>::min(),\n                                               std::numeric_limits<long>::max(),\n                                               std::numeric_limits<long>::max()));\n\n            btop    = rect.intersect(rectangle(inner_rect.left(),\n                                               std::numeric_limits<long>::min(),\n                                               inner_rect.right(),\n                                               inner_rect.top()-1));\n\n            bbottom = rect.intersect(rectangle(inner_rect.left(),\n                                               inner_rect.bottom()+1,\n                                               inner_rect.right(),\n                                               std::numeric_limits<long>::max()));\n\n            p = bleft.tl_corner();\n            p.x() -= 1;\n\n            mode = atleft;\n        }\n\n        bool at_start (\n        ) const\n        {\n            point temp = bleft.tl_corner();\n            temp.x() -=1;\n            return temp == p;\n        }\n\n        bool current_element_valid(\n        ) const\n        {\n            return rect.contains(p);\n        }\n\n        bool move_next()\n        {\n            if (mode == atleft)\n            {\n                if (advance_point(bleft, p))\n                    return true;\n                    \n                mode = attop;\n                p = btop.tl_corner();\n                p.x() -= 1;\n            }\n            if (mode == attop)\n            {\n                if (advance_point(btop, p))\n                    return true;\n                    \n                mode = atright;\n                p = bright.tl_corner();\n                p.x() -= 1;\n            }\n            if (mode == atright)\n            {\n                if (advance_point(bright, p))\n                    return true;\n                    \n                mode = atbottom;\n                p = bbottom.tl_corner();\n                p.x() -= 1;\n            }\n\n            if (advance_point(bbottom, p))\n                return true;\n\n            // put p outside rect since there are no more points to enumerate\n            p = rect.br_corner();\n            p.x() += 1;\n                    \n            return false;\n        }\n\n        size_t size (\n        ) const\n        {\n            return rect.area() - inner_rect.area();\n        }\n\n        const point& element (\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(current_element_valid(),\n                \"\\t point border_enumerator::element()\"\n                << \"\\n\\t This function can't be called unless the element is valid.\"\n                << \"\\n\\t this: \" << this\n                );\n\n            return p;\n        }\n\n    private:\n\n        bool advance_point (\n            const rectangle& r,\n            point& p\n        ) const\n        {\n            p.x() += 1;\n            if (p.x() > r.right())\n            {\n                p.x() = r.left();\n                p.y() += 1;\n            }\n\n            return r.contains(p);\n        }\n\n        point p;\n        rectangle rect;\n        rectangle inner_rect;  // the non-border regions of rect\n\n        enum emode\n        {\n            atleft,\n            atright,\n            atbottom,\n            attop\n        };\n\n        emode mode;\n\n        rectangle btop, bleft, bright, bbottom;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BORDER_EnUMERATOR_H_\n\n"
  },
  {
    "path": "dlib/geometry/border_enumerator_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_\n#ifdef DLIB_BORDER_EnUMERATOR_ABSTRACT_H_\n\n#include \"rectangle_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class border_enumerator\n    {\n        /*!\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                All operations on this object other than calling element() invalidate\n                pointers and references to internal data.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is an enumerator over the border points of a rectangle.\n        !*/\n    public:\n\n        border_enumerator(\n        ); \n        /*!\n            ensures\n                - #move_next() == false\n                  (i.e. this object is \"empty\" and won't enumerate anything)\n                - current_element_valid() == false \n                - at_start() == true\n                - size() == 0\n        !*/\n\n        border_enumerator(\n            const rectangle& rect,\n            unsigned long border_size\n        );\n        /*!\n            ensures\n                - This object will enumerate over the border points which are inside rect\n                  but within border_size of the edge.  For example, if border_size == 1\n                  then it enumerates over the single point wide strip of points all around\n                  the interior edge of rect.\n                - current_element_valid() == false \n                - at_start() == true\n                - size() == rect.area() - shrink_rect(rect,border_size).area()\n                  (i.e. the number of points in the border area of rect)\n        !*/\n\n        border_enumerator(\n            const rectangle& rect,\n            const rectangle& non_border_region\n        );\n        /*!\n            ensures\n                - This object will enumerate over all points which are in rect but\n                  not in non_border_region.  \n                - current_element_valid() == false \n                - at_start() == true\n                - size() == rect.area() - rect.intersect(non_border_region).area() \n        !*/\n\n        bool at_start (\n        ) const;\n        /*!\n            ensures\n                - returns true if *this represents one position before the first point \n                  (this would also make the current element invalid) else returns false                \n        !*/\n\n        void reset (\n        ); \n        /*!\n            ensures\n                - #current_element_valid() == false \n                - #at_start() == true\n        !*/\n\n        bool current_element_valid(\n        ) const;\n        /*!\n            ensures\n                - returns true if we are currently at a valid element else\n                  returns false \n        !*/\n\n        bool move_next(\n        );\n        /*!\n            ensures\n                - moves to the next element.  i.e. #element() will now \n                  return the next border point. \n                - the return value will be equal to #current_element_valid() \n                - #at_start() == false \n\n                - returns true if there is another element \n                - returns false if there are no more elements in the container\n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of border points\n        !*/\n\n        const point& element (\n        ) const;\n        /*!\n            requires\n                - current_element_valid() == true\n            ensures\n                - returns the current border point\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BORDER_EnUMERATOR_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/geometry/drectangle.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DRECTANGLe_\n#define DLIB_DRECTANGLe_\n\n#include \"drectangle_abstract.h\"\n#include \"rectangle.h\"\n\nnamespace dlib\n{\n    class drectangle;\n    drectangle operator* (\n        const drectangle& rect,\n        const double& scale \n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class drectangle\n    {\n    public:\n\n        drectangle (\n        ) : l(0), t(0), r(-1), b(-1) {}\n\n        drectangle (\n            double l_,\n            double t_,\n            double r_,\n            double b_\n        ) :\n            l(l_),\n            t(t_),\n            r(r_),\n            b(b_)\n        {}\n\n        drectangle (\n            const dlib::vector<double,2>& p\n        ) :\n            l(p.x()),\n            t(p.y()),\n            r(p.x()),\n            b(p.y())\n        {\n        }\n\n        template <typename T, typename U>\n        drectangle (\n            const vector<T,2>& p1,\n            const vector<U,2>& p2\n        )\n        {\n            *this = drectangle(p1) + drectangle(p2);\n        }\n\n        drectangle (\n            const rectangle& rect\n        ) : l(rect.left()), \n            t(rect.top()),\n            r(rect.right()),\n            b(rect.bottom()) {}\n\n        operator rectangle (\n        ) const\n        {\n            return rectangle(std::lround(l),\n                             std::lround(t),\n                             std::lround(r),\n                             std::lround(b));\n        }\n\n        double left()   const { return l; }\n        double top()    const { return t; }\n        double right()  const { return r; }\n        double bottom() const { return b; }\n\n        double& left()   { return l; }\n        double& top()    { return t; }\n        double& right()  { return r; }\n        double& bottom() { return b; }\n\n        const dlib::vector<double,2> tl_corner (\n        ) const { return dlib::vector<double,2>(left(), top()); }\n\n        const dlib::vector<double,2> bl_corner (\n        ) const { return dlib::vector<double,2>(left(), bottom()); } \n\n        const dlib::vector<double,2> tr_corner (\n        ) const { return dlib::vector<double,2>(right(), top()); }\n\n        const dlib::vector<double,2> br_corner (\n        ) const { return dlib::vector<double,2>(right(), bottom()); }\n\n        double width (\n        ) const \n        { \n            if (is_empty())\n                return 0;\n            else\n                return r - l + 1; \n        }\n\n        double height (\n        ) const \n        { \n            if (is_empty())\n                return 0;\n            else\n                return b - t + 1; \n        }\n\n        double area (\n        ) const\n        {\n            return width()*height();\n        }\n\n        bool is_empty (\n        ) const { return (t > b || l > r); }\n\n        drectangle operator + (\n            const drectangle& rhs\n        ) const\n        {\n            if (rhs.is_empty())\n                return *this;\n            else if (is_empty())\n                return rhs;\n\n            return drectangle (\n                std::min(l,rhs.l),\n                std::min(t,rhs.t),\n                std::max(r,rhs.r),\n                std::max(b,rhs.b)\n                );\n        }\n\n        drectangle intersect (\n            const drectangle& rhs\n        ) const\n        {\n            return drectangle (\n                std::max(l,rhs.l),\n                std::max(t,rhs.t),\n                std::min(r,rhs.r),\n                std::min(b,rhs.b)\n                );\n        }\n\n        bool contains (\n            const dlib::vector<double,2>& p\n        ) const\n        {\n            if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)\n                return false;\n            return true;\n        }\n\n        bool contains (\n            const drectangle& rect\n        ) const\n        {\n            if (rect.is_empty())\n                return true;\n            if (l <= rect.left() &&\n                r >= rect.right() &&\n                t <= rect.top() &&\n                b >= rect.bottom())\n                return true;\n            return false;\n        }\n\n        drectangle& operator *= (\n            const double& scale\n        )\n        {\n            *this = *this*scale;\n            return *this;\n        }\n\n        drectangle& operator /= (\n            const double& scale\n        )\n        {\n            *this = *this*(1.0/scale);\n            return *this;\n        }\n\n        drectangle& operator += (\n            const dlib::vector<double,2>& p\n        )\n        {\n            *this = *this + drectangle(p);\n            return *this;\n        }\n\n        bool operator== (\n            const drectangle& rect\n        ) const\n        {\n            return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b);\n        }\n\n        bool operator!= (\n            const drectangle& rect\n        ) const\n        {\n            return !(*this == rect);\n        }\n\n    private:\n        double l;\n        double t;\n        double r;\n        double b;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const drectangle& item, \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.left(),out); \n            serialize(item.top(),out); \n            serialize(item.right(),out); \n            serialize(item.bottom(),out); \n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing an object of type drectangle\");\n        }\n    }\n\n    inline void deserialize (\n        drectangle& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            deserialize(item.left(),in); \n            deserialize(item.top(),in); \n            deserialize(item.right(),in); \n            deserialize(item.bottom(),in); \n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing an object of type drectangle\");\n        }\n    }\n\n    inline std::ostream& operator<< (\n        std::ostream& out, \n        const drectangle& item \n    )   \n    {\n        out << \"[(\" << item.left() << \", \" << item.top() << \") (\" << item.right() << \", \" << item.bottom() << \")]\";\n        return out;\n    }\n\n    inline std::istream& operator>>(\n        std::istream& in, \n        drectangle& item \n    )\n    {\n        // ignore any whitespace\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n        // now eat the leading '[' character\n        if (in.get() != '[')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n        dlib::vector<double,2> p1, p2;\n        in >> p1;\n        in >> p2;\n        item = drectangle(p1) + drectangle(p2);\n\n        // ignore any whitespace\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n        // now eat the trailing ']' character\n        if (in.get() != ']')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n        }\n        return in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline dlib::vector<double,2> center (\n        const drectangle& rect\n    )\n    {\n        dlib::vector<double,2> temp(rect.left() + rect.right(),\n                                    rect.top() + rect.bottom());\n\n        return temp/2.0;\n    }\n\n    inline dlib::vector<double,2> dcenter (\n        const drectangle& rect\n    )\n    {\n        return center(rect);\n    }\n\n    inline drectangle operator* (\n        const drectangle& rect,\n        const double& scale \n    )\n    {\n        if (!rect.is_empty())\n        {\n            const double width = (rect.right()-rect.left())*scale;\n            const double height = (rect.bottom()-rect.top())*scale;\n            const dlib::vector<double,2> p = center(rect);\n            return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);\n        }\n        else\n        {\n            return rect;\n        }\n    }\n\n    inline drectangle operator* (\n        const double& scale,\n        const drectangle& rect\n    )\n    {\n        return rect*scale;\n    }\n\n    inline drectangle operator/ (\n        const drectangle& rect,\n        const double& scale\n    )\n    {\n        return rect*(1.0/scale);\n    }\n\n    inline drectangle operator+ (\n        const drectangle& r,\n        const dlib::vector<double,2>& p\n    )\n    {\n        return r + drectangle(p);\n    }\n\n    inline drectangle operator+ (\n        const dlib::vector<double,2>& p,\n        const drectangle& r\n    )\n    {\n        return r + drectangle(p);\n    }\n\n    template <typename T>\n    inline drectangle translate_rect (\n        const drectangle& rect,\n        const dlib::vector<T,2>& p\n    )\n    {\n        drectangle result;\n        result.top    () = rect.top()    + p.y();\n        result.bottom () = rect.bottom() + p.y();\n        result.left   () = rect.left()   + p.x();\n        result.right  () = rect.right()  + p.x();\n        return result;\n    }\n\n    inline drectangle intersect (\n        const drectangle& a,\n        const drectangle& b\n    ) { return a.intersect(b); }\n\n    inline double area (\n        const drectangle& a\n    ) { return a.area(); }\n\n    inline drectangle centered_drect (\n        const dlib::vector<double,2>& p,\n        double width,\n        double height\n    )\n    {\n        width--;\n        height--;\n\n        return drectangle(p.x()-width/2, p.y()-height/2, p.x()+width/2, p.y()+height/2);\n    }\n\n    inline drectangle centered_drect (\n        const drectangle& rect,\n        double width,\n        double height\n    )\n    {\n        return centered_drect(dcenter(rect), width, height);\n    }\n\n    inline const drectangle shrink_rect (\n        const drectangle& rect,\n        double num \n    )\n    {\n        return drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);\n    }\n\n    inline const drectangle grow_rect (\n        const drectangle& rect,\n        double num \n    )\n    {\n        return shrink_rect(rect, -num);\n    }\n\n    inline const drectangle shrink_rect (\n        const drectangle& rect,\n        double width,\n        double height\n    )\n    {\n        return drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);\n    }\n\n    inline const drectangle grow_rect (\n        const drectangle& rect,\n        double width,\n        double height\n    )\n    {\n        return shrink_rect(rect, -width, -height);\n    }\n\n    inline const drectangle scale_rect (\n        const drectangle& rect,\n        double scale\n    )\n    {\n        DLIB_ASSERT(scale > 0, \"scale factor must be > 0\");\n\n        double l = rect.left() * scale;\n        double t = rect.top() * scale;\n        double r = rect.right() * scale;\n        double b = rect.bottom() * scale;\n        return drectangle(l, t, r, b);\n    }\n\n    inline drectangle set_rect_area (\n        const drectangle& rect,\n        double area\n    )\n    {\n        DLIB_ASSERT(area >= 0, \"drectangle can't have a negative area.\");\n\n        if (area == 0)\n            return drectangle(dcenter(rect));\n\n        if (rect.area() == 0)\n        {\n            // In this case we will make the output rectangle a square with the requested\n            // area.\n            double scale = std::sqrt(area);\n            return centered_drect(rect, scale, scale);\n        }\n        else\n        {\n            double scale = std::sqrt(area/rect.area());\n            return centered_drect(rect, rect.width()*scale, rect.height()*scale);\n        }\n    }\n\n    inline drectangle set_aspect_ratio (\n        const drectangle& rect,\n        double ratio\n    )\n    {\n        DLIB_ASSERT(ratio > 0,\n            \"\\t drectangle set_aspect_ratio()\"\n            << \"\\n\\t ratio: \" << ratio \n            );\n\n        const double h = std::sqrt(rect.area()/ratio);\n        const double w = h*ratio;\n        return centered_drect(rect, w, h);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRECTANGLe_\n\n"
  },
  {
    "path": "dlib/geometry/drectangle_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DRECTANGLe_ABSTRACT_H_\n#ifdef DLIB_DRECTANGLe_ABSTRACT_H_\n\n#include \"rectangle_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class drectangle\n    {\n        /*!\n            INITIAL VALUE\n                The initial value of this object is defined by its constructor.                \n\n            WHAT THIS OBJECT REPRESENTS\n                This object is just like dlib::rectangle except that it stores the\n                coordinates of the rectangle using double rather than long variables.  As\n                such, this object represents a rectangular region inside an image.  The\n                region is the rectangle with its top left corner at position (left(),top())\n                and its bottom right corner at (right(),bottom()).\n\n                Note that the origin of the coordinate system, i.e. (0,0), is located at\n                the upper left corner.  That is, points such as (1,1) or (3,5) represent\n                locations that are below and to the right of the origin.\n\n                Also note that rectangles where top() > bottom() or left() > right()\n                represent empty rectangles.\n        !*/\n    public:\n\n        drectangle (\n        );\n        /*!\n            ensures\n                - #left() == 0\n                - #top() == 0\n                - #right() == -1 \n                - #bottom() == -1 \n                - #is_empty() == true\n        !*/\n\n        drectangle (\n            double left_,\n            double top_,\n            double right_,\n            double bottom_\n        );\n        /*!\n            ensures\n                - #left() == left_\n                - #top() == top_\n                - #right() == right_\n                - #bottom() == bottom_\n        !*/\n\n        drectangle (\n            const vector<double,2>& p\n        );\n        /*!\n            ensures\n                - #left()   == p.x()\n                - #top()    == p.y()\n                - #right()  == p.x()\n                - #bottom() == p.y()\n        !*/\n\n        template <typename T, typename U>\n        drectangle (\n            const vector<T,2>& p1,\n            const vector<U,2>& p2\n        );\n        /*!\n            ensures\n                - #*this == drectangle(p1) + drectangle(p2)\n        !*/\n\n        drectangle (\n            const drectangle& rect\n        );\n        /*!\n            ensures\n                - #*this represents the same rectangle as rect\n        !*/\n\n        drectangle (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - left()   == rect.left()\n                - top()    == rect.top()\n                - right()  == rect.right()\n                - bottom() == rect.bottom()\n                - dcenter(*this) == dcenter(rect)\n                - width() == rect.width()\n                - height() == rect.height()\n        !*/\n\n        operator rectangle (\n        ) const;\n        /*!\n            ensures\n                - returns a rectangle where left(), top(), right(), and bottom() have been\n                  rounded to the nearest integer values.\n        !*/\n\n        double left (\n        ) const;\n        /*!\n            ensures\n                - returns the x coordinate for the left side of this rectangle\n        !*/\n\n        double& left (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the x coordinate for the left side \n                  of this rectangle\n        !*/\n\n        double top (\n        ) const;\n        /*!\n            ensures\n                - returns the y coordinate for the top of this rectangle\n        !*/\n\n        double& top (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the y coordinate for the \n                  top of this rectangle\n        !*/\n\n        double right (\n        ) const;\n        /*!\n            ensures\n                - returns the x coordinate for the right side of this rectangle\n        !*/\n\n        double& right (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the x coordinate for the right \n                  side of this rectangle\n        !*/\n\n        double bottom (\n        ) const;\n        /*!\n            ensures\n                - returns the y coordinate for the bottom of this rectangle\n        !*/\n       \n        double& bottom (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the y coordinate for the bottom \n                  of this rectangle\n        !*/\n       \n        const vector<double,2> tl_corner (\n        ) const;\n        /*!\n            ensures\n                - returns vector<double,2>(left(), top()) \n                  (i.e. returns the top left corner point for this rectangle)\n        !*/\n\n        const vector<double,2> bl_corner (\n        ) const;\n        /*!\n            ensures\n                - returns vector<double,2>(left(), bottom()) \n                  (i.e. returns the bottom left corner point for this rectangle)\n        !*/\n\n        const vector<double,2> tr_corner (\n        ) const;\n        /*!\n            ensures\n                - returns vector<double,2>(right(), top()) \n                  (i.e. returns the top right corner point for this rectangle)\n        !*/\n\n        const vector<double,2> br_corner (\n        ) const;\n        /*!\n            ensures\n                - returns vector<double,2>(right(), bottom()) \n                  (i.e. returns the bottom right corner point for this rectangle)\n        !*/\n\n        double width (\n        ) const;\n        /*!\n            ensures\n                - if (is_empty()) then\n                    - returns 0\n                - else\n                    - returns the width of this rectangle.\n                      (i.e. right() - left() + 1)\n        !*/\n\n        double height (\n        ) const;\n        /*!\n            ensures\n                - if (is_empty()) then\n                    - returns 0\n                - else\n                    - returns the height of this rectangle.\n                      (i.e. bottom() - top() + 1)\n        !*/\n\n        double area (\n        ) const;\n        /*!\n            ensures\n                - returns width()*height()\n        !*/\n\n        bool is_empty (\n        ) const;\n        /*!\n            ensures\n                - if (top() > bottom() || left() > right()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        drectangle operator + (\n            const drectangle& rhs\n        ) const;\n        /*!\n            ensures\n                - if (rhs.is_empty() == false && this->is_empty() == false) then\n                    - returns the smallest rectangle that contains both *this and \n                      rhs.\n                - if (rhs.is_empty() == true && this->is_empty() == false) then\n                    - returns *this\n                - if (rhs.is_empty() == false && this->is_empty() == true) then\n                    - returns rhs\n                - if (rhs.is_empty() == true && this->is_empty() == true) then\n                    - returns a rectangle that has is_empty() == true\n        !*/\n\n        drectangle intersect (\n            const drectangle& rhs\n        ) const;\n        /*!\n            ensures\n                - if (there is a region of intersection between *this and rhs) then\n                    - returns a rectangle that represents the intersection of *this \n                      and rhs.\n                - else\n                    - returns a rectangle where is_empty() == true\n        !*/\n\n        bool contains (\n            const vector<double,2>& p\n        ) const;\n        /*!\n            ensures\n                - if (the point (p.x(),p.y()) is contained in this rectangle) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool contains (\n            const drectangle& rect\n        ) const\n        /*!\n            ensures\n                - if (rect + *this == *this) then\n                    - returns true\n                      (i.e. returns true if *this contains the given rectangle)\n                - else\n                    - returns false\n        !*/\n\n        drectangle& operator *= (\n            const double& scale\n        );\n        /*!\n            ensures\n                - performs: *this = *this*scale;\n                - returns #*this\n        !*/\n\n        drectangle& operator /= (\n            const double& scale\n        );\n        /*!\n            requires\n                - scale != 0\n            ensures\n                - performs: *this = *this*(1.0/scale);\n                - returns #*this\n        !*/\n\n        drectangle& operator += (\n            const dlib::vector<double,2>& p\n        );\n        /*!\n            ensures\n                - performs: *this = *this + drectangle(p)\n                - returns #*this\n        !*/\n\n        bool operator== (\n            const drectangle& rect\n        ) const;\n        /*!\n            ensures\n                - if (top() == rect.top() && left() == rect.left() &&\n                      right() == rect.right() && bottom() == rect.bottom()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool operator!= (\n            const drectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns !(*this == rect)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const drectangle& item, \n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        drectangle& item, \n        std::istream& in\n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& operator<< (\n        std::ostream& out, \n        const drectangle& item \n    );\n    /*!\n        ensures\n            - writes item to out in the form \"[(left, top) (right, bottom)]\"\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::istream& operator>>(\n        std::istream& in, \n        drectangle& item \n    );\n    /*!\n        ensures\n            - reads a drectangle from the input stream in and stores it in #item.  The data\n              in the input stream should be of the form [(left, top) (right, bottom)]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    vector<double,2> center (\n        const drectangle& rect\n    );\n    /*!\n        ensures\n            - returns the center of the given rectangle\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    vector<double,2> dcenter (\n        const drectangle& rect\n    );\n    /*!\n        ensures\n            - returns the center of the given rectangle.  (Both center() and dcenter() are\n              identical when applied to drectangle objects)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle operator* (\n        const drectangle& rect,\n        const double& scale \n    );\n    /*!\n        ensures\n            - This function returns a rectangle that has the same center as rect but with\n              dimensions that are scale times larger.  That is, we return a new rectangle R\n              such that:\n                - center(R) == center(rect)\n                - R.right()-R.left() == (rect.right()-rect.left())*scale\n                - R.bottom()-R.top() == (rect.bottom()-rect.top())*scale\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle operator* (\n        const double& scale,\n        const drectangle& rect\n    );\n    /*!\n        ensures\n            - returns rect*scale\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle operator/ (\n        const drectangle& rect,\n        const double& scale\n    );\n    /*!\n        ensures\n            - returns rect*(1.0/scale)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle operator+ (\n        const drectangle& r,\n        const vector<double,2>& p\n    );\n    /*!\n        ensures\n            - returns r + drectangle(p)\n              (i.e. returns the rectangle that contains both r and p)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle operator+ (\n        const vector<double,2>& p,\n        const drectangle& r\n    );\n    /*!\n        ensures\n            - returns r + drectangle(p)\n              (i.e. returns the rectangle that contains both r and p)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    drectangle translate_rect (\n        const drectangle& rect,\n        const vector<T,2>& p\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.left()   == rect.left()   + p.x()\n                - R.right()  == rect.right()  + p.x()\n                - R.top()    == rect.top()    + p.y()\n                - R.bottom() == rect.bottom() + p.y()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle intersect (\n        const drectangle& a,\n        const drectangle& b\n    ); \n    /*!\n        ensures\n            - returns a.intersect(b)\n              (i.e. returns a rectangle representing the intersection of a and b)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    double area (\n        const drectangle& a\n    );\n    /*!\n        ensures\n            - returns a.area()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle centered_drect (\n        const vector<double,2>& p,\n        double width,\n        double height\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - center(R) == p\n                - if (width < 1 || height < 1)\n                    - R.width() == 0 \n                    - R.height() == 0 \n                    - R.is_empty() == true\n                - else\n                    - R.width() == width\n                    - R.height() == height \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle centered_drect (\n        const drectangle& rect,\n        double width,\n        double height\n    );\n    /*!\n        ensures\n            - returns centered_drect(center(rect), width, height)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const drectangle shrink_rect (\n        const drectangle& rect,\n        double num \n    );\n    /*!\n        ensures\n            - returns drectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num)\n              (i.e. shrinks the given drectangle by shrinking its border by num)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const drectangle grow_rect (\n        const drectangle& rect,\n        double num \n    );\n    /*!\n        ensures\n            - return shrink_rect(rect, -num)\n              (i.e. grows the given drectangle by expanding its border by num)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const drectangle shrink_rect (\n        const drectangle& rect,\n        double width,\n        double height\n    );\n    /*!\n        ensures\n            - returns drectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height)\n              (i.e. shrinks the given drectangle by shrinking its left and right borders by width\n              and its top and bottom borders by height. )\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const drectangle grow_rect (\n        const drectangle& rect,\n        double width,\n        double height\n    );\n    /*!\n        ensures\n            - return shrink_rect(rect, -width, -height)\n              (i.e. grows the given drectangle by expanding its border)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const drectangle scale_rect (\n        const drectangle& rect,\n        double scale\n    );\n    /*!\n        requires\n            - scale > 0\n        ensures\n            - return drectangle(rect.left() * scale, rect.top() * scale, rect.right() * scale, rect.bottom() * scale)\n              (i.e. resizes the given rectangle by multiplying all side coordinates with a scale factor)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle set_rect_area (\n        const drectangle& rect,\n        double area\n    );\n    /*!\n        requires\n            - area >= 0\n        ensures\n            - Returns a rectangle R such that:\n                - center(R) == center(rect)\n                - R has the same aspect ratio as rect.  If rect.area() == 0 then the\n                  returned rect has a 1:1 aspect ratio.\n                - R.area() == area\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    drectangle set_aspect_ratio (\n        const drectangle& rect,\n        double ratio\n    );\n    /*!\n        requires\n            - ratio > 0\n        ensures\n            - This function reshapes the given rectangle so that it has the given aspect\n              ratio.  In particular, this means we return a rectangle R such that the\n              following equations are true:\n                - R.width()/R.height() == ratio\n                - R.area() == rect.area()\n                - dcenter(rect) == dcenter(R)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRECTANGLe_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/geometry/line.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LInE_H_\n#define DLIB_LInE_H_\n\n#include \"line_abstract.h\"\n#include \"vector.h\"\n#include <utility>\n#include \"../numeric_constants.h\"\n#include <array>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class line\n    {\n    public:\n\n        line() = default;\n\n        line(const dpoint& a, const dpoint& b) : end1(a), end2(b)\n        {\n            normal_vector = (end1-end2).cross(dlib::vector<double,3>(0,0,1)).normalize();\n        }\n\n        template <typename T>\n        line(const std::pair<vector<T,2>,vector<T,2>>& l) : line(l.first, l.second) {}\n\n        const dpoint& p1() const { return end1; }\n        const dpoint& p2() const { return end2; }\n\n        const dpoint& normal() const { return normal_vector; }\n\n    private:\n\n        dpoint end1;\n        dpoint end2;\n\n        dpoint normal_vector;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename U>\n    double signed_distance_to_line (\n        const line& l,\n        const vector<U,2>& p\n    )\n    {\n        return dot(p-l.p1(), l.normal());\n    }\n\n    template <typename T, typename U>\n    double signed_distance_to_line (\n        const std::pair<vector<T,2>,vector<T,2> >& l,\n        const vector<U,2>& p\n    )\n    {\n        return signed_distance_to_line(line(l),p);\n    }\n\n    template <typename T, typename U>\n    double distance_to_line (\n        const std::pair<vector<T,2>,vector<T,2> >& l,\n        const vector<U,2>& p\n    )\n    {\n        return std::abs(signed_distance_to_line(l,p));\n    }\n\n    template <typename U>\n    double distance_to_line (\n        const line& l,\n        const vector<U,2>& p\n    )\n    {\n        return std::abs(signed_distance_to_line(l,p));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline line reverse(const line& l)\n    {\n        return line(l.p2(), l.p1());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline dpoint intersect(\n        const std::pair<vector<T,2>,vector<T,2>>& a,\n        const std::pair<vector<T,2>,vector<T,2>>& b\n    )\n    {\n        // convert to homogeneous coordinates\n        dlib::vector<double,3> a1 = a.first;\n        dlib::vector<double,3> a2 = a.second;\n        dlib::vector<double,3> b1 = b.first;\n        dlib::vector<double,3> b2 = b.second;\n        a1.z() = 1;\n        a2.z() = 1;\n        b1.z() = 1;\n        b2.z() = 1;\n\n        // find lines between pairs of points.\n        auto l1 = a1.cross(a2);\n        auto l2 = b1.cross(b2);\n\n        // find intersection of the lines.\n        auto p = l1.cross(l2);\n\n        if (p.z() != 0)\n            return p/p.z();\n        else\n            return dpoint(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline dpoint intersect(\n        const line& a,\n        const line& b\n    )\n    {\n        return intersect(std::make_pair(a.p1(),a.p2()), std::make_pair(b.p1(), b.p2()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline size_t count_points_on_side_of_line(\n        line l,\n        const dpoint& reference_point,\n        const std::vector<vector<T,2>>& pts,\n        const double& dist_thresh_min = 0,\n        const double& dist_thresh_max = std::numeric_limits<double>::infinity()\n    )\n    {\n        if (signed_distance_to_line(l,reference_point) < 0)\n            l = reverse(l);\n\n        size_t cnt = 0;\n        for (auto& p : pts)\n        {\n            double dist = signed_distance_to_line(l,p);\n            if (dist_thresh_min <= dist && dist <= dist_thresh_max)\n                ++cnt;\n        }\n        return cnt;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline double count_points_between_lines(\n        line l1,\n        line l2,\n        const dpoint& reference_point,\n        const std::vector<vector<T,2>>& pts\n    )\n    {\n        if (signed_distance_to_line(l1,reference_point) < 0)\n            l1 = reverse(l1);\n        if (signed_distance_to_line(l2,reference_point) < 0)\n            l2 = reverse(l2);\n\n        size_t cnt = 0;\n        for (auto& p : pts)\n        {\n            if (signed_distance_to_line(l1,p) > 0 && signed_distance_to_line(l2,p) > 0)\n                ++cnt;\n        }\n        return cnt;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double angle_between_lines (\n        const line& a,\n        const line& b\n    )\n    {\n        auto tmp = put_in_range(0.0, 1.0, std::abs(dot(a.normal(),b.normal()))); \n        return std::acos(tmp)*180/pi;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct no_convex_quadrilateral : dlib::error\n    {\n        no_convex_quadrilateral() : dlib::error(\"Lines given to find_convex_quadrilateral() don't form any convex quadrilateral.\") {}\n    };\n\n    inline std::array<dpoint,4> find_convex_quadrilateral (\n        const std::array<line,4>& lines\n    )\n    {\n        const dpoint v01 = intersect(lines[0],lines[1]);\n        const dpoint v02 = intersect(lines[0],lines[2]);\n        const dpoint v03 = intersect(lines[0],lines[3]);\n        const dpoint v12 = intersect(lines[1],lines[2]);\n        const dpoint v13 = intersect(lines[1],lines[3]);\n        const dpoint v23 = intersect(lines[2],lines[3]);\n        const auto& v10 = v01;\n        const auto& v20 = v02;\n        const auto& v30 = v03;\n        const auto& v21 = v12;\n        const auto& v31 = v13;\n        const auto& v32 = v23;\n\n        if (is_convex_quadrilateral({{v01, v12, v23, v30}}))\n                             return {{v01, v12, v23, v30}};\n        if (is_convex_quadrilateral({{v01, v13, v32, v20}}))\n                             return {{v01, v13, v32, v20}};\n\n        if (is_convex_quadrilateral({{v02, v23, v31, v10}}))\n                             return {{v02, v23, v31, v10}};\n        if (is_convex_quadrilateral({{v02, v21, v13, v30}}))\n                             return {{v02, v21, v13, v30}};\n\n        if (is_convex_quadrilateral({{v03, v32, v21, v10}}))\n                             return {{v03, v32, v21, v10}};\n        if (is_convex_quadrilateral({{v03, v31, v12, v20}}))\n                             return {{v03, v31, v12, v20}};\n\n        throw no_convex_quadrilateral();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LInE_H_\n\n"
  },
  {
    "path": "dlib/geometry/line_abstract.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LInE_ABSTRACT_H_\n#ifdef DLIB_LInE_ABSTRACT_H_\n\n#include \"../vector_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class line\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a line in the 2D plane.  The line is defined by two\n                points running through it, p1() and p2().  This object also includes a\n                unit normal vector that is perpendicular to the line.\n        !*/\n\n    public:\n\n        line(\n        );\n        /*!\n            ensures\n                - p1(), p2(), and normal() are all the 0 vector.\n        !*/\n\n        line(\n            const dpoint& a, \n            const dpoint& b\n        );\n        /*!\n            ensures\n                - #p1() == a\n                - #p2() == b\n                - #normal() == A vector normal to the line passing through points a and b.\n                  In particular, it is given by: (a-b).cross(dlib::vector<double,3>(0,0,1)).normalize().\n                  Therefore, the normal vector is the vector (a-b) but unit normalized and rotated clockwise 90 degrees.\n        !*/\n\n        template <typename T>\n        line(\n            const std::pair<vector<T,2>,vector<T,2>>& l\n        );\n        /*!\n            ensures\n                - #*this == line(l.first, l.second)\n        !*/\n\n        const dpoint& p1(\n        ) const; \n        /*!\n            ensures\n                - returns the first endpoint of the line.\n        !*/\n\n        const dpoint& p2(\n        ) const;\n        /*!\n            ensures\n                - returns the second endpoint of the line.\n        !*/\n\n        const dpoint& normal(\n        ) const; \n        /*!\n            ensures\n                - returns a unit vector that is normal to the line passing through p1() and p2().\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename U>\n    double signed_distance_to_line (\n        const line& l,\n        const vector<U,2>& p\n    );\n    /*!\n        ensures\n            - returns how far p is from the line l.  This is a signed distance.  The sign\n              indicates which side of the line the point is on and the magnitude is the\n              distance. Moreover, the direction of positive sign is pointed to by the\n              vector l.normal().\n            - To be specific, this routine returns dot(p-l.p1(), l.normal())\n    !*/\n\n    template <typename T, typename U>\n    double signed_distance_to_line (\n        const std::pair<vector<T,2>,vector<T,2> >& l,\n        const vector<U,2>& p\n    );\n    /*!\n        ensures\n            - returns signed_distance_to_line(line(l),p);\n    !*/\n\n    template <typename T, typename U>\n    double distance_to_line (\n        const std::pair<vector<T,2>,vector<T,2> >& l,\n        const vector<U,2>& p\n    );\n    /*!\n        ensures\n            - returns abs(signed_distance_to_line(l,p))\n    !*/\n\n    template <typename U>\n    double distance_to_line (\n        const line& l,\n        const vector<U,2>& p\n    );\n    /*!\n        ensures\n            - returns abs(signed_distance_to_line(l,p))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    line reverse(\n        const line& l\n    );\n    /*!\n        ensures\n            - returns line(l.p2(), l.p1())\n              (i.e. returns a line object that represents the same line as l but with the\n              endpoints, and therefore, the normal vector flipped.  This means that the\n              signed distance of operator() is also flipped).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    dpoint intersect(\n        const line& a,\n        const line& b\n    );\n    /*!\n        ensures\n            - returns the point of intersection between lines a and b.  If no such point\n              exists then this function returns a point with Inf values in it.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    double angle_between_lines (\n        const line& a,\n        const line& b\n    );\n    /*!\n        ensures\n            - returns the angle, in degrees, between the given lines.  This is a number in\n              the range [0 90].\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    dpoint intersect(\n        const std::pair<vector<T,2>,vector<T,2>>& a,\n        const std::pair<vector<T,2>,vector<T,2>>& b\n    );\n    /*!\n        ensures\n            - returns intersect(line(a), line(b))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    size_t count_points_on_side_of_line(\n        const line& l,\n        const dpoint& reference_point,\n        const std::vector<vector<T,2>>& pts,\n        const double& dist_thresh_min = 0,\n        const double& dist_thresh_max = std::numeric_limits<double>::infinity()\n    );\n    /*!\n        ensures\n            - Returns a count of how many points in pts have a distance from the line l\n              that is in the range [dist_thresh_min, dist_thresh_max].  This distance is a\n              signed value that indicates how far a point is from the line. Moreover, if\n              the point is on the same side as reference_point then the distance is\n              positive, otherwise it is negative.  So for example, If this range is [0,\n              infinity] then this function counts how many points are on the same side of l\n              as reference_point.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    double count_points_between_lines(\n        const line& l1,\n        const line& l2,\n        const dpoint& reference_point,\n        const std::vector<vector<T,2>>& pts\n    );\n    /*!\n        ensures\n            - Counts and returns the number of points in pts that are between lines l1 and\n              l2.  Since a pair of lines will, in the general case, divide the plane into 4\n              regions, we identify the region of interest as the one that contains the\n              reference_point.  Therefore, this function counts the number of points in pts\n              that appear in the same region as reference_point.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct no_convex_quadrilateral : dlib::error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown by find_convex_quadrilateral() if the inputs\n                can't form a convex quadrilateral.\n        !*/\n        no_convex_quadrilateral(\n        ) : dlib::error(\"Lines given to find_convex_quadrilateral() don't form any convex quadrilateral.\") \n        {}\n    };\n\n    std::array<dpoint,4> find_convex_quadrilateral (\n        const std::array<line,4>& lines\n    );\n    /*!\n        ensures\n            - Is there a set of 4 points, made up of the intersections of the given lines,\n              that forms a convex quadrilateral?  If yes then this routine returns those 4\n              points and if not throws no_convex_quadrilateral.\n        throws\n            - no_convex_quadrilateral\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LInE_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/geometry/point_transforms.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_POINT_TrANSFORMS_H_\n#define DLIB_POINT_TrANSFORMS_H_\n\n#include \"point_transforms_abstract.h\"\n#include \"../algs.h\"\n#include \"vector.h\"\n#include \"../matrix.h\"\n#include \"../matrix/matrix_la.h\"\n#include \"../optimization/optimization.h\"\n#include \"rectangle.h\"\n#include \"drectangle.h\"\n#include <vector>\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class point_rotator\n    {\n    public:\n        point_rotator (\n        )\n        {\n            sin_angle = 0;\n            cos_angle = 1;\n        }\n\n        point_rotator (\n            const double& angle\n        )\n        {\n            sin_angle = std::sin(angle);\n            cos_angle = std::cos(angle);\n        }\n\n        template <typename T>\n        const dlib::vector<T,2> operator() (\n            const dlib::vector<T,2>& p\n        ) const\n        {\n            double x = cos_angle*p.x() - sin_angle*p.y();\n            double y = sin_angle*p.x() + cos_angle*p.y();\n\n            return dlib::vector<double,2>(x,y);\n        }\n\n        const matrix<double,2,2> get_m(\n        ) const \n        { \n            matrix<double,2,2> temp;\n            temp = cos_angle, -sin_angle,\n                   sin_angle, cos_angle;\n            return temp; \n        }\n\n        inline friend void serialize (const point_rotator& item, std::ostream& out)\n        {\n            serialize(item.sin_angle, out);\n            serialize(item.cos_angle, out);\n        }\n\n        inline friend void deserialize (point_rotator& item, std::istream& in)\n        {\n            deserialize(item.sin_angle, in);\n            deserialize(item.cos_angle, in);\n        }\n\n    private:\n        double sin_angle;\n        double cos_angle;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform\n    {\n    public:\n\n        point_transform (\n        )\n        {\n            sin_angle = 0;\n            cos_angle = 1;\n            translate.x() = 0;\n            translate.y() = 0;\n        }\n\n        point_transform (\n            const double& angle,\n            const dlib::vector<double,2>& translate_\n        )\n        {\n            sin_angle = std::sin(angle);\n            cos_angle = std::cos(angle);\n            translate = translate_;\n        }\n\n        template <typename T>\n        const dlib::vector<T,2> operator() (\n            const dlib::vector<T,2>& p\n        ) const\n        {\n            double x = cos_angle*p.x() - sin_angle*p.y();\n            double y = sin_angle*p.x() + cos_angle*p.y();\n\n            return dlib::vector<double,2>(x,y) + translate;\n        }\n\n        const matrix<double,2,2> get_m(\n        ) const \n        { \n            matrix<double,2,2> temp;\n            temp = cos_angle, -sin_angle,\n                   sin_angle, cos_angle;\n            return temp; \n        }\n\n        const dlib::vector<double,2> get_b(\n        ) const { return translate; }\n\n        inline friend void serialize (const point_transform& item, std::ostream& out)\n        {\n            serialize(item.sin_angle, out);\n            serialize(item.cos_angle, out);\n            serialize(item.translate, out);\n        }\n\n        inline friend void deserialize (point_transform& item, std::istream& in)\n        {\n            deserialize(item.sin_angle, in);\n            deserialize(item.cos_angle, in);\n            deserialize(item.translate, in);\n        }\n\n    private:\n        double sin_angle;\n        double cos_angle;\n        dlib::vector<double,2> translate;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_affine\n    {\n    public:\n\n        point_transform_affine (\n        )\n        {\n            m = identity_matrix<double>(2);\n            b.x() = 0;\n            b.y() = 0;\n        }\n\n        point_transform_affine (\n            const matrix<double,2,2>& m_,\n            const dlib::vector<double,2>& b_\n        ) :m(m_), b(b_)\n        {\n        }\n\n        const dlib::vector<double,2> operator() (\n            const dlib::vector<double,2>& p\n        ) const\n        {\n            return m*p + b;\n        }\n\n        const matrix<double,2,2>& get_m(\n        ) const { return m; }\n\n        const dlib::vector<double,2>& get_b(\n        ) const { return b; }\n\n        inline friend void serialize (const point_transform_affine& item, std::ostream& out)\n        {\n            serialize(item.m, out);\n            serialize(item.b, out);\n        }\n\n        inline friend void deserialize (point_transform_affine& item, std::istream& in)\n        {\n            deserialize(item.m, in);\n            deserialize(item.b, in);\n        }\n\n    private:\n        matrix<double,2,2> m;\n        dlib::vector<double,2> b;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class rectangle_transform\n    {\n    public:\n\n        rectangle_transform (\n        )\n        {\n        }\n\n        rectangle_transform (\n            const point_transform_affine& tform_\n        ) :tform(tform_)\n        {\n        }\n\n        drectangle operator() (\n            const drectangle& r\n        ) const\n        {\n            dpoint tl = r.tl_corner();\n            dpoint tr = r.tr_corner();\n            dpoint bl = r.bl_corner();\n            dpoint br = r.br_corner();\n            // The new rectangle would ideally have this area if we could actually rotate\n            // the box.  Note the 1+ is because that's how the rectangles calculate their\n            // width and height.\n            double new_area = (1+length(tform(tl)-tform(tr)))*(1+length(tform(tl)-tform(bl)));\n\n            // But if we rotate the corners of the rectangle and then find the rectangle\n            // that contains them we get this, which might have a much larger area than we\n            // want.\n            drectangle temp;\n            temp += tform(tl);\n            temp += tform(tr);\n            temp += tform(bl);\n            temp += tform(br);\n            // so we adjust the area to match the target area and have the same center as\n            // the above box.\n            double scale = std::sqrt(new_area/temp.area());\n\n            return centered_drect(dcenter(temp), temp.width()*scale, temp.height()*scale);\n        }\n\n        rectangle operator() (\n            const rectangle& r\n        ) const\n        {\n            const auto temp = (*this)(drectangle(r));\n            return centered_rect(center(temp), std::round(temp.width()), std::round(temp.height()));\n        }\n\n        const point_transform_affine& get_tform(\n        ) const { return tform; }\n\n        inline friend void serialize (const rectangle_transform& item, std::ostream& out)\n        {\n            serialize(item.tform, out);\n        }\n\n        inline friend void deserialize (rectangle_transform& item, std::istream& in)\n        {\n            deserialize(item.tform, in);\n        }\n\n    private:\n        point_transform_affine tform;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine operator* (\n        const point_transform_affine& lhs,\n        const point_transform_affine& rhs\n    )\n    {\n        return point_transform_affine(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine inv (\n        const point_transform_affine& trans\n    )\n    {\n        matrix<double,2,2> im = inv(trans.get_m());\n        return point_transform_affine(im, -im*trans.get_b());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    point_transform_affine find_affine_transform (\n        const std::vector<dlib::vector<T,2> >& from_points,\n        const std::vector<dlib::vector<T,2> >& to_points\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(from_points.size() == to_points.size() &&\n                    from_points.size() >= 3,\n            \"\\t point_transform_affine find_affine_transform(from_points, to_points)\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t from_points.size(): \" << from_points.size()\n            << \"\\n\\t to_points.size():   \" << to_points.size()\n            );\n\n        matrix<double,3,0> P(3, from_points.size());\n        matrix<double,2,0> Q(2, from_points.size());\n\n        for (unsigned long i = 0; i < from_points.size(); ++i)\n        {\n            P(0,i) = from_points[i].x();\n            P(1,i) = from_points[i].y();\n            P(2,i) = 1;\n\n            Q(0,i) = to_points[i].x();\n            Q(1,i) = to_points[i].y();\n        }\n\n        const matrix<double,2,3> m = Q*pinv(P);\n        return point_transform_affine(subm(m,0,0,2,2), colm(m,2));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    point_transform_affine find_similarity_transform (\n        const std::vector<dlib::vector<T,2> >& from_points,\n        const std::vector<dlib::vector<T,2> >& to_points\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(from_points.size() == to_points.size() &&\n                    from_points.size() >= 2,\n            \"\\t point_transform_affine find_similarity_transform(from_points, to_points)\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t from_points.size(): \" << from_points.size()\n            << \"\\n\\t to_points.size():   \" << to_points.size()\n            );\n\n        // We use the formulas from the paper: Least-squares estimation of transformation\n        // parameters between two point patterns by Umeyama.  They are equations 34 through\n        // 43.\n\n        dlib::vector<double,2> mean_from, mean_to;\n        double sigma_from = 0, sigma_to = 0;\n        matrix<double,2,2> cov;\n        cov = 0;\n\n        for (unsigned long i = 0; i < from_points.size(); ++i)\n        {\n            mean_from += from_points[i];\n            mean_to += to_points[i];\n        }\n        mean_from /= from_points.size();\n        mean_to   /= from_points.size();\n\n        for (unsigned long i = 0; i < from_points.size(); ++i)\n        {\n            sigma_from += length_squared(from_points[i] - mean_from);\n            sigma_to += length_squared(to_points[i] - mean_to);\n            cov += (to_points[i] - mean_to)*trans(from_points[i] - mean_from);\n        }\n\n        sigma_from /= from_points.size();\n        sigma_to   /= from_points.size();\n        cov        /= from_points.size();\n\n        matrix<double,2,2> u, v, s, d;\n        svd(cov, u,d,v);\n        s = identity_matrix(cov);\n        if (det(cov) < 0 || (det(cov) == 0 && det(u)*det(v)<0))\n        {\n            if (d(1,1) < d(0,0))\n                s(1,1) = -1;\n            else\n                s(0,0) = -1;\n        }\n\n        matrix<double,2,2> r = u*s*trans(v);\n        double c = 1; \n        if (sigma_from != 0)\n            c = 1.0/sigma_from * trace(d*s);\n        vector<double,2> t = mean_to - c*r*mean_from;\n\n        return point_transform_affine(c*r, t);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_projective\n    {\n    public:\n\n        point_transform_projective (\n        )\n        {\n            m = identity_matrix<double>(3);\n        }\n\n        point_transform_projective (\n            const matrix<double,3,3>& m_\n        ) :m(m_)\n        {\n        }\n        \n        point_transform_projective (\n            const point_transform_affine& tran\n        ) \n        {\n            set_subm(m, 0,0, 2,2) = tran.get_m();\n            set_subm(m, 0,2, 2,1) = tran.get_b();\n            m(2,0) = 0;\n            m(2,1) = 0;\n            m(2,2) = 1;\n        }\n        \n\n        const dlib::vector<double,2> operator() (\n            const dlib::vector<double,2>& p\n        ) const\n        {\n            dlib::vector<double,3> temp(p);\n            temp.z() = 1;\n            temp = m*temp;\n            if (temp.z() != 0)\n                temp = temp/temp.z();\n            return temp;\n        }\n\n        const matrix<double,3,3>& get_m(\n        ) const { return m; }\n\n        inline friend void serialize (const point_transform_projective& item, std::ostream& out)\n        {\n            serialize(item.m, out);\n        }\n\n        inline friend void deserialize (point_transform_projective& item, std::istream& in)\n        {\n            deserialize(item.m, in);\n        }\n\n    private:\n        matrix<double,3,3> m;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_projective operator* (\n        const point_transform_projective& lhs,\n        const point_transform_projective& rhs\n    )\n    {\n        return point_transform_projective(lhs.get_m()*rhs.get_m());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_projective inv (\n        const point_transform_projective& trans\n    )\n    {\n        return point_transform_projective(inv(trans.get_m()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl_proj\n    {\n\n        inline point_transform_projective find_projective_transform_basic (\n            const std::vector<dlib::vector<double,2> >& from_points,\n            const std::vector<dlib::vector<double,2> >& to_points\n        )\n        /*!\n            ensures\n                - Uses the system of equations approach to finding a projective transform.\n                  This is \"Method 3\" from Estimating Projective Transformation Matrix by\n                  Zhengyou Zhang. \n                - It should be emphasized that the find_projective_transform_basic()\n                  routine, which uses the most popular method for finding projective\n                  transformations, doesn't really work well when the minimum error solution\n                  doesn't have zero error.  In this case, it can deviate by a large amount\n                  from the proper minimum mean squared error transformation.  Therefore,\n                  our overall strategy will be to use the solution from\n                  find_projective_transform_basic() as a starting point for a BFGS based\n                  non-linear optimizer which will optimize the correct mean squared error\n                  criterion.\n\n                  A great essay on this subject is Homography Estimation by Elan Dubrofsky.\n        !*/\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(from_points.size() == to_points.size() &&\n                from_points.size() >= 4,\n                \"\\t point_transform_projective find_projective_transform_basic(from_points, to_points)\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t from_points.size(): \" << from_points.size()\n                << \"\\n\\t to_points.size():   \" << to_points.size()\n            );\n\n            matrix<double,9,9> accum, u, v;\n            matrix<double,9,1> w;\n            matrix<double,2,9> B;\n            accum = 0;\n            B = 0;\n            for (unsigned long i = 0; i < from_points.size(); ++i)\n            {\n                dlib::vector<double,3> f = from_points[i];\n                f.z() = 1;\n                dlib::vector<double,3> t = to_points[i];\n                t.z() = 1;\n\n                set_subm(B,0,0,1,3) = t.y()*trans(f);\n                set_subm(B,1,0,1,3) =       trans(f);\n\n                set_subm(B,0,3,1,3) = -t.x()*trans(f);\n                set_subm(B,1,6,1,3) = -t.x()*trans(f);\n\n                accum += trans(B)*B;\n            }\n\n            svd2(true, false, accum, u, w, v);\n            long j = index_of_min(w);\n\n            return point_transform_projective(reshape(colm(u,j),3,3)); \n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        struct obj\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is the objective function we really want to minimize when looking\n                    for a transformation matrix.  That is, we would like the transformed\n                    points to be as close as possible to their \"to\" points.  Here,\n                    closeness is measured using Euclidean distance.\n\n            !*/\n            obj(\n                const std::vector<dlib::vector<double,2> >& from_points_,\n                const std::vector<dlib::vector<double,2> >& to_points_\n            ) : \n                from_points(from_points_) ,\n                to_points(to_points_)\n            {}\n            const std::vector<dlib::vector<double,2> >& from_points;\n            const std::vector<dlib::vector<double,2> >& to_points;\n\n            double operator() (\n                const matrix<double,9,1>& p\n            ) const\n            {\n                point_transform_projective tran(reshape(p,3,3));\n\n                double sum = 0;\n                for (unsigned long i = 0; i < from_points.size(); ++i)\n                {\n                    sum += length_squared(tran(from_points[i]) - to_points[i]);\n                }\n                return sum;\n            }\n        };\n\n        struct obj_der\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is the derivative of obj.\n            !*/\n\n            obj_der(\n                const std::vector<dlib::vector<double,2> >& from_points_,\n                const std::vector<dlib::vector<double,2> >& to_points_\n            ) : \n                from_points(from_points_) ,\n                to_points(to_points_)\n            {}\n            const std::vector<dlib::vector<double,2> >& from_points;\n            const std::vector<dlib::vector<double,2> >& to_points;\n\n            matrix<double,9,1> operator() (\n                const matrix<double,9,1>& p\n            ) const\n            {\n                const matrix<double,3,3> H = reshape(p,3,3);\n\n                matrix<double,3,3> grad;\n                grad = 0;\n                for (unsigned long i = 0; i < from_points.size(); ++i)\n                {\n                    dlib::vector<double,3> from, to;\n                    from = from_points[i];\n                    from.z() = 1;\n                    to = to_points[i];\n                    to.z() = 1;\n\n                    matrix<double,3,1> w = H*from;\n                    const double scale = (w(2) != 0) ? (1.0/w(2)) : (1);\n                    w *= scale;\n                    matrix<double,3,1> residual = (w-to)*2*scale;\n\n                    grad(0,0) += from.x()*residual(0);\n                    grad(0,1) += from.y()*residual(0);\n                    grad(0,2) +=          residual(0);\n\n                    grad(1,0) += from.x()*residual(1);\n                    grad(1,1) += from.y()*residual(1);\n                    grad(1,2) +=          residual(1);\n\n                    grad(2,0) += -(from.x()*w(0)*residual(0) + from.x()*w(1)*residual(1));\n                    grad(2,1) += -(from.y()*w(0)*residual(0) + from.y()*w(1)*residual(1));\n                    grad(2,2) += -(         w(0)*residual(0) +          w(1)*residual(1));\n\n                }\n                return reshape_to_column_vector(grad);\n            }\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_projective find_projective_transform (\n        const std::vector<dlib::vector<double,2> >& from_points,\n        const std::vector<dlib::vector<double,2> >& to_points\n    )\n    {\n        using namespace impl_proj;\n        // make sure requires clause is not broken\n        DLIB_ASSERT(from_points.size() == to_points.size() &&\n                    from_points.size() >= 4,\n            \"\\t point_transform_projective find_projective_transform(from_points, to_points)\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t from_points.size(): \" << from_points.size()\n            << \"\\n\\t to_points.size():   \" << to_points.size()\n            );\n\n\n        // Find a candidate projective transformation.  Also, find the best affine\n        // transform and then compare it with the projective transform estimated using the\n        // direct SVD method.  Use whichever one works better as the starting point for a\n        // BFGS based optimizer.  If the best solution has large mean squared error and is\n        // also close to affine then find_projective_transform_basic() might give a very\n        // bad initial guess.  So also checking for a good affine transformation can\n        // produce a much better final result in many cases.\n        point_transform_projective tran1 = find_projective_transform_basic(from_points, to_points);\n        point_transform_affine tran2 = find_affine_transform(from_points, to_points);\n\n        // check which is best\n        double error1 = 0;\n        double error2 = 0;\n        for (unsigned long i = 0; i < from_points.size(); ++i)\n        {\n            error1 += length_squared(tran1(from_points[i])-to_points[i]);\n            error2 += length_squared(tran2(from_points[i])-to_points[i]);\n        }\n        matrix<double,9,1> params; \n        // Pick the minimum error solution among the two so far.\n        if (error1 < error2)\n            params = reshape_to_column_vector(tran1.get_m());\n        else\n            params = reshape_to_column_vector(point_transform_projective(tran2).get_m());\n\n\n        // Now refine the transformation matrix so that we can be sure we have\n        // at least a local minimizer.\n        obj o(from_points, to_points);\n        obj_der der(from_points, to_points);\n        find_min(bfgs_search_strategy(),\n                objective_delta_stop_strategy(1e-6,100),\n                o,\n                der,\n                params,\n                0);\n\n        return point_transform_projective(reshape(params,3,3)); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const dlib::vector<T,2> rotate_point (\n        const dlib::vector<T,2>& center,\n        const dlib::vector<T,2>& p,\n        double angle\n    )\n    {\n        point_rotator rot(angle);\n        return rot(p-center)+center;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline matrix<double,2,2> rotation_matrix (\n         double angle\n    )\n    {\n        const double ca = std::cos(angle);\n        const double sa = std::sin(angle);\n\n        matrix<double,2,2> m;\n        m = ca, -sa,\n            sa, ca;\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_affine3d\n    {\n    public:\n\n        point_transform_affine3d (\n        )\n        {\n            m = identity_matrix<double>(3);\n            b.x() = 0;\n            b.y() = 0;\n        }\n\n        point_transform_affine3d (\n            const matrix<double,3,3>& m_,\n            const dlib::vector<double,3>& b_\n        ) :m(m_), b(b_)\n        {\n        }\n\n        const dlib::vector<double,3> operator() (\n            const dlib::vector<double,3>& p\n        ) const\n        {\n            return m*p + b;\n        }\n\n        const matrix<double,3,3>& get_m(\n        ) const { return m; }\n\n        const dlib::vector<double,3>& get_b(\n        ) const { return b; }\n\n        inline friend void serialize (const point_transform_affine3d& item, std::ostream& out)\n        {\n            serialize(item.m, out);\n            serialize(item.b, out);\n        }\n\n        inline friend void deserialize (point_transform_affine3d& item, std::istream& in)\n        {\n            deserialize(item.m, in);\n            deserialize(item.b, in);\n        }\n\n    private:\n        matrix<double,3,3> m;\n        dlib::vector<double,3> b;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d operator* (\n        const point_transform_affine3d& lhs,\n        const point_transform_affine& rhs\n    )\n    {\n        matrix<double,3,3> m;\n        m = 0;\n        set_subm(m, get_rect(rhs.get_m())) = rhs.get_m();\n        vector<double,3> b = rhs.get_b();\n\n        return point_transform_affine3d(lhs.get_m()*m, lhs.get_m()*b+lhs.get_b());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d operator* (\n        const point_transform_affine3d& lhs,\n        const point_transform_affine3d& rhs\n    )\n    {\n        return point_transform_affine3d(lhs.get_m()*rhs.get_m(), lhs.get_m()*rhs.get_b()+lhs.get_b());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d inv (\n        const point_transform_affine3d& trans\n    )\n    {\n        matrix<double,3,3> im = inv(trans.get_m());\n        return point_transform_affine3d(im, -im*trans.get_b());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d rotate_around_x (\n        double angle\n    )\n    {\n        const double ca = std::cos(angle);\n        const double sa = std::sin(angle);\n\n        matrix<double,3,3> m;\n        m = 1,  0,  0,\n            0, ca, -sa,\n            0, sa, ca;\n\n        vector<double,3> b;\n\n        return point_transform_affine3d(m,b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d rotate_around_y (\n        double angle\n    )\n    {\n        const double ca = std::cos(angle);\n        const double sa = std::sin(angle);\n\n        matrix<double,3,3> m;\n        m = ca,  0, sa,\n             0,  1, 0,\n            -sa, 0, ca;\n\n        vector<double,3> b;\n\n        return point_transform_affine3d(m,b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d rotate_around_z (\n        double angle\n    )\n    {\n        const double ca = std::cos(angle);\n        const double sa = std::sin(angle);\n\n        matrix<double,3,3> m;\n        m = ca, -sa, 0,\n            sa, ca,  0,\n            0,   0,  1;\n\n        vector<double,3> b;\n\n        return point_transform_affine3d(m,b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine3d translate_point (\n        const vector<double,3>& delta\n    )\n    {\n        return point_transform_affine3d(identity_matrix<double>(3),delta);\n    }\n\n    inline point_transform_affine3d translate_point (\n        double x,\n        double y,\n        double z\n    )\n    {\n        return translate_point(vector<double>(x,y,z));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class camera_transform\n    {\n\n    public:\n\n        camera_transform  (\n        )\n        {\n            *this = camera_transform(vector<double>(1,1,1), \n                                     vector<double>(0,0,0),\n                                     vector<double>(0,0,1),\n                                     90,\n                                     1);\n        }\n\n        camera_transform (\n            const vector<double>& camera_pos_,\n            const vector<double>& camera_looking_at_,\n            const vector<double>& camera_up_direction_,\n            const double camera_field_of_view_, \n            const unsigned long num_pixels_\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(0 < camera_field_of_view_ && camera_field_of_view_ < 180,\n                \"\\t camera_transform::camera_transform()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t camera_field_of_view_: \" << camera_field_of_view_\n                );\n\n            camera_pos = camera_pos_;\n            camera_looking_at = camera_looking_at_;\n            camera_up_direction = camera_up_direction_;\n            camera_field_of_view = camera_field_of_view_;\n            num_pixels = num_pixels_;\n\n            dlib::vector<double> X,Y,Z;\n            Z = (camera_looking_at - camera_pos).normalize();\n            Y = camera_up_direction - dot(camera_up_direction,Z)*Z; \n            Y = Y.normalize();\n            X = Z.cross(Y);\n\n            set_rowm(proj,0) = trans(X);\n            // 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.\n            set_rowm(proj,1) = -trans(Y); \n            set_rowm(proj,2) = trans(Z);\n\n            width = num_pixels/2.0;\n            dist_scale = width/std::tan(pi/180*camera_field_of_view/2);\n        }\n\n        vector<double> get_camera_pos()         const { return camera_pos; }\n        vector<double> get_camera_looking_at()  const { return camera_looking_at; }\n        vector<double> get_camera_up_direction()const { return camera_up_direction; }\n        double get_camera_field_of_view()       const { return camera_field_of_view; }\n        unsigned long get_num_pixels()                   const { return num_pixels; }\n\n        inline dpoint operator() (\n            const vector<double>& p,\n            double& scale,\n            double& distance\n        ) const\n        {\n            vector<double> temp = p-camera_pos;\n            temp = proj*temp;\n            distance = temp.z();\n            scale = dist_scale/(temp.z()>0 ? temp.z() : 1e-9);\n            temp.x() = temp.x()*scale + width;\n            temp.y() = temp.y()*scale + width;\n            return temp;\n        }\n\n        dpoint operator() (\n            const vector<double>& p\n        ) const\n        {\n            double scale, distance;\n            return (*this)(p,scale,distance);\n        }\n\n        inline friend void serialize (const camera_transform& item, std::ostream& out)\n        {\n            serialize(item.camera_pos, out);\n            serialize(item.camera_looking_at, out);\n            serialize(item.camera_up_direction, out);\n            serialize(item.camera_field_of_view, out); \n            serialize(item.num_pixels, out);\n            serialize(item.proj, out);\n            serialize(item.dist_scale, out);\n            serialize(item.width, out);\n        }\n\n        inline friend void deserialize (camera_transform& item, std::istream& in)\n        {\n            deserialize(item.camera_pos, in);\n            deserialize(item.camera_looking_at, in);\n            deserialize(item.camera_up_direction, in);\n            deserialize(item.camera_field_of_view, in); \n            deserialize(item.num_pixels, in);\n            deserialize(item.proj, in);\n            deserialize(item.dist_scale, in);\n            deserialize(item.width, in);\n        }\n\n    private:\n\n        vector<double> camera_pos;\n        vector<double> camera_looking_at;\n        vector<double> camera_up_direction;\n        double camera_field_of_view; \n        unsigned long num_pixels;\n        matrix<double,3,3> proj;\n        double dist_scale;\n        double width;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_POINT_TrANSFORMS_H_\n\n"
  },
  {
    "path": "dlib/geometry/point_transforms_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_\n#ifdef DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_\n\n#include \"../matrix/matrix_abstract.h\"\n#include \"vector_abstract.h\"\n#include \"rectangle_abstract.h\"\n#include \"drectangle_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_affine\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an object that takes 2D points or vectors and \n                applies an affine transformation to them.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n    public:\n\n        point_transform_affine (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a point\n                  as input it will return the same point as output.\n        !*/\n\n        point_transform_affine (\n            const matrix<double,2,2>& m,\n            const dlib::vector<double,2>& b\n        );\n        /*!\n            ensures\n                - #get_m() == m\n                - #get_b() == b\n                - When (*this)(p) is invoked it will return a point P such that:\n                    - P == m*p + b\n        !*/\n\n        const dlib::vector<double,2> operator() (\n            const dlib::vector<double,2>& p\n        ) const;\n        /*!\n            ensures\n                - applies the affine transformation defined by this object's constructor\n                  to p and returns the result.\n        !*/\n\n        const matrix<double,2,2>& get_m(\n        ) const;\n        /*!\n            ensures\n                - returns the transformation matrix used by this object.\n        !*/\n\n        const dlib::vector<double,2>& get_b(\n        ) const;\n        /*!\n            ensures\n                - returns the offset vector used by this object.\n        !*/\n\n    };\n\n    void serialize   (const point_transform_affine& item, std::ostream& out);\n    void deserialize (point_transform_affine& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine operator* (\n        const point_transform_affine& lhs,\n        const point_transform_affine& rhs\n    );\n    /*!\n        ensures\n            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That\n              is, for all valid x: TFORM(x) == lhs(rhs(x)).\n    !*/\n\n    // ----------------------------------------------------------------------------------------\n\n    point_transform_affine inv (\n        const point_transform_affine& trans\n    );\n    /*!\n        ensures\n            - If trans is an invertible transformation then this function returns a new\n              transformation that is the inverse of trans. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    point_transform_affine find_affine_transform (\n        const std::vector<dlib::vector<T,2> >& from_points,\n        const std::vector<dlib::vector<T,2> >& to_points\n    );\n    /*!\n        requires\n            - from_points.size() == to_points.size()\n            - from_points.size() >= 3\n        ensures\n            - returns a point_transform_affine object, T, such that for all valid i:\n                length(T(from_points[i]) - to_points[i])\n              is minimized as often as possible.  That is, this function finds the affine\n              transform that maps points in from_points to points in to_points.  If no\n              affine transform exists which performs this mapping exactly then the one\n              which minimizes the mean squared error is selected.  Additionally, if many\n              equally good transformations exist, then the transformation with the smallest\n              squared parameters is selected (i.e. if you wrote the transformation as a\n              matrix then we say we select the transform with minimum Frobenius norm among\n              all possible solutions).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    point_transform_affine find_similarity_transform (\n        const std::vector<dlib::vector<T,2> >& from_points,\n        const std::vector<dlib::vector<T,2> >& to_points\n    );\n    /*!\n        requires\n            - from_points.size() == to_points.size()\n            - from_points.size() >= 2\n        ensures\n            - This function is just like find_affine_transform() except it finds the best\n              similarity transform instead of a full affine transform.  This means that it\n              optimizes over only the space of rotations, scale changes, and translations.\n              So for example, if you mapped the 3 vertices of a triangle through a\n              similarity transform then the output would still be the same triangle.\n              However, the triangle itself may be larger or smaller, rotated, or at a\n              different location in the coordinate system.  This is not the case for a\n              general affine transform which can stretch points in ways that cause, for\n              example, an equilateral triangle to turn into an isosceles triangle.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class rectangle_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is just a point_transform_affine wrapped up so that it can\n                transform rectangle objects.  It will take a rectangle and transform it\n                according to an affine transformation.  \n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n    public:\n\n        rectangle_transform (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a rectangle \n                  as input it will return the same rectangle as output.\n        !*/\n\n        rectangle_transform (\n            const point_transform_affine& tform\n        );\n        /*!\n            ensures\n                - #get_tform() == tform\n        !*/\n\n        drectangle operator() (\n            const drectangle& r\n        ) const;\n        /*!\n            ensures\n                - Applies the transformation get_tform() to r and returns the resulting\n                  rectangle.  If the transformation doesn't have any rotation then the\n                  transformation simply maps the corners of the rectangle according to\n                  get_tform() and returns the exact result.  However, since\n                  dlib::drectangle can't represent rotated rectangles, if there is any\n                  rotation in the affine transform we will attempt to produce the most\n                  faithful possible outputs by ensuring the output rectangle has the\n                  correct center point and that its area and aspect ratio match the correct\n                  rotated rectangle's as much as possible.\n        !*/\n\n        rectangle operator() (\n            const rectangle& r\n        ) const;\n        /*!\n            ensures\n                - returns (*this)(drectangle(r))\n        !*/\n\n        const point_transform_affine& get_tform(\n        ) const; \n        /*!\n            ensures\n                - returns the affine transformation this object uses to transform rectangles.\n        !*/\n\n    };\n\n    void serialize   (const rectangle_transform& item, std::ostream& out);\n    void deserialize (rectangle_transform& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_projective\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an object that takes 2D points or vectors and \n                applies a projective transformation to them.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n\n    public:\n\n        point_transform_projective (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a point\n                  as input it will return the same point as output.\n        !*/\n\n        point_transform_projective (\n            const matrix<double,3,3>& m\n        );\n        /*!\n            ensures\n                - #get_m() == m\n        !*/\n\n        point_transform_projective (\n            const point_transform_affine& tran\n        );\n        /*!\n            ensures\n                - This object will perform exactly the same transformation as the given\n                  affine transform.\n        !*/\n\n        const dlib::vector<double,2> operator() (\n            const dlib::vector<double,2>& p\n        ) const;\n        /*!\n            ensures\n                - Applies the projective transformation defined by this object's constructor\n                  to p and returns the result.  To define this precisely:\n                    - let p_h == the point p in homogeneous coordinates.  That is:\n                        - p_h.x() == p.x()\n                        - p_h.y() == p.y()\n                        - p_h.z() == 1 \n                    - let x == get_m()*p_h \n                    - Then this function returns the value x/x.z()\n        !*/\n\n        const matrix<double,3,3>& get_m(\n        ) const;\n        /*!\n            ensures\n                - returns the transformation matrix used by this object.\n        !*/\n\n    };\n\n    void serialize   (const point_transform_projective& item, std::ostream& out);\n    void deserialize (point_transform_projective& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_projective operator* (\n        const point_transform_projective& lhs,\n        const point_transform_projective& rhs\n    );\n    /*!\n        ensures\n            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That\n              is, for all valid x: TFORM(x) == lhs(rhs(x)).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_projective inv (\n        const point_transform_projective& trans\n    );\n    /*!\n        ensures\n            - If trans is an invertible transformation then this function returns a new\n              transformation that is the inverse of trans. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_projective find_projective_transform (\n        const std::vector<dlib::vector<double,2> >& from_points,\n        const std::vector<dlib::vector<double,2> >& to_points\n    );\n    /*!\n        requires\n            - from_points.size() == to_points.size()\n            - from_points.size() >= 4\n        ensures\n            - returns a point_transform_projective object, T, such that for all valid i:\n                length(T(from_points[i]) - to_points[i])\n              is minimized as often as possible.  That is, this function finds the projective\n              transform that maps points in from_points to points in to_points.  If no\n              projective transform exists which performs this mapping exactly then the one\n              which minimizes the mean squared error is selected. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an object that takes 2D points or vectors and \n                rotates them around the origin by a given angle and then\n                translates them.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n    public:\n\n        point_transform (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a point\n                  as input it will return the same point as output.\n        !*/\n\n        point_transform (\n            const double& angle,\n            const dlib::vector<double,2>& translate\n        )\n        /*!\n            ensures\n                - When (*this)(p) is invoked it will return a point P such that:\n                    - P is the point p rotated counter-clockwise around the origin \n                      angle radians and then shifted by having translate added to it.\n                      (Note that this is counter clockwise with respect to the normal\n                      coordinate system with positive y going up and positive x going\n                      to the right)\n        !*/\n\n        template <typename T>\n        const dlib::vector<T,2> operator() (\n            const dlib::vector<T,2>& p\n        ) const;\n        /*!\n            ensures\n                - rotates p, then translates it and returns the result.  The output\n                  of this function is therefore equal to get_m()*p + get_b().\n        !*/\n\n        const matrix<double,2,2> get_m(\n        ) const;\n        /*!\n            ensures\n                - returns the transformation matrix used by this object.\n        !*/\n\n        const dlib::vector<double,2> get_b(\n        ) const;\n        /*!\n            ensures\n                - returns the offset vector used by this object.\n        !*/\n\n    };\n\n    void serialize   (const point_transform& item, std::ostream& out);\n    void deserialize (point_transform& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class point_rotator\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an object that takes 2D points or vectors and \n                rotates them around the origin by a given angle.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n    public:\n\n        point_rotator (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a point\n                  as input it will return the same point as output.\n        !*/\n\n        point_rotator (\n            const double& angle\n        );\n        /*!\n            ensures\n                - When (*this)(p) is invoked it will return a point P such that:\n                    - P is the point p rotated counter-clockwise around the origin \n                      angle radians.\n                      (Note that this is counter clockwise with respect to the normal\n                      coordinate system with positive y going up and positive x going\n                      to the right)\n        !*/\n\n        template <typename T>\n        const dlib::vector<T,2> operator() (\n            const dlib::vector<T,2>& p\n        ) const;\n        /*!\n            ensures\n                - rotates p and returns the result. The output of this function is\n                  therefore equal to get_m()*p.\n        !*/\n\n        const matrix<double,2,2> get_m(\n        ) const;\n        /*!\n            ensures\n                - returns the transformation matrix used by this object.\n        !*/\n    };\n\n    void serialize   (const point_rotator& item, std::ostream& out);\n    void deserialize (point_rotator& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const dlib::vector<T,2> rotate_point (\n        const dlib::vector<T,2> center,\n        const dlib::vector<T,2> p,\n        double angle\n    );\n    /*!\n        ensures\n            - returns a point P such that:\n                - P is the point p rotated counter-clockwise around the given\n                  center point by angle radians.\n                  (Note that this is counter clockwise with respect to the normal\n                  coordinate system with positive y going up and positive x going\n                  to the right)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    matrix<double,2,2> rotation_matrix (\n         double angle\n    );\n    /*!\n        ensures\n            - returns a rotation matrix which rotates points around the origin in a\n              counter-clockwise direction by angle radians.\n              (Note that this is counter clockwise with respect to the normal\n              coordinate system with positive y going up and positive x going\n              to the right)\n              Or in other words, this function returns a matrix M such that, given a\n              point P, M*P gives a point which is P rotated by angle radians around\n              the origin in a counter-clockwise direction.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class point_transform_affine3d\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an object that takes 3D points or vectors and \n                applies an affine transformation to them.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n    public:\n\n        point_transform_affine3d (\n        );\n        /*!\n            ensures\n                - This object will perform the identity transform.  That is, given a point\n                  as input it will return the same point as output.\n        !*/\n\n        point_transform_affine3d (\n            const matrix<double,3,3>& m,\n            const dlib::vector<double,3>& b\n        );\n        /*!\n            ensures\n                - #get_m() == m\n                - #get_b() == b\n                - When (*this)(p) is invoked it will return a point P such that:\n                    - P == m*p + b\n        !*/\n\n        const dlib::vector<double,3> operator() (\n            const dlib::vector<double,3>& p\n        ) const;\n        /*!\n            ensures\n                - applies the affine transformation defined by this object's constructor\n                  to p and returns the result.\n        !*/\n\n        const matrix<double,3,3>& get_m(\n        ) const;\n        /*!\n            ensures\n                - returns the transformation matrix used by this object.\n        !*/\n\n        const dlib::vector<double,3>& get_b(\n        ) const;\n        /*!\n            ensures\n                - returns the offset vector used by this object.\n        !*/\n\n    };\n\n    void serialize   (const point_transform_affine3d& item, std::ostream& out);\n    void deserialize (point_transform_affine3d& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d operator* (\n        const point_transform_affine3d& lhs,\n        const point_transform_affine3d& rhs\n    );\n    /*!\n        ensures\n            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That\n              is, for all valid x: TFORM(x) == lhs(rhs(x)).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d operator* (\n        const point_transform_affine3d& lhs,\n        const point_transform_affine& rhs\n    );\n    /*!\n        ensures\n            - returns a transformation TFORM(x) that is equivalent to lhs(rhs(x)).  That\n              is, for all valid x: TFORM(x) == lhs(rhs(x)).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d inv (\n        const point_transform_affine3d& trans\n    );\n    /*!\n        ensures\n            - If trans is an invertible transformation then this function returns a new\n              transformation that is the inverse of trans. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d rotate_around_x (\n        double angle\n    );\n    /*!\n        ensures\n            - Returns a transformation that rotates a point around the x axis in a\n              counter-clockwise direction by angle radians.  That is, the rotation appears\n              counter-clockwise when the x axis points toward the observer, the coordinate\n              system is right-handed, and the angle is positive.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d rotate_around_y (\n        double angle\n    );\n    /*!\n        ensures\n            - Returns a transformation that rotates a point around the y axis in a\n              counter-clockwise direction by angle radians.  That is, the rotation appears\n              counter-clockwise when the y axis points toward the observer, the coordinate\n              system is right-handed, and the angle is positive.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d rotate_around_z (\n        double angle\n    );\n    /*!\n        ensures\n            - Returns a transformation that rotates a point around the z axis in a\n              counter-clockwise direction by angle radians.  That is, the rotation appears\n              counter-clockwise when the z axis points toward the observer, the coordinate\n              system is right-handed, and the angle is positive.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine3d translate_point (\n        const vector<double,3>& delta\n    );\n    /*!\n        ensures\n            - returns a transformation that simply translates points by adding delta to\n              them.  That is, this function returns:\n                point_transform_affine3d(identity_matrix<double>(3),delta);\n    !*/\n\n    point_transform_affine3d translate_point (\n        double x,\n        double y,\n        double z\n    );\n    /*!\n        ensures\n            - returns translate_point(vector<double>(x,y,z))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class camera_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object maps 3D points into the image plane of a camera.  Therefore,\n                you can use it to compute 2D representations of 3D data from the point of\n                view of some camera in 3D space.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n\n    public:\n\n        camera_transform  (\n        );\n        /*!\n            ensures\n                - #get_camera_pos()           == vector<double>(1,1,1) \n                - #get_camera_looking_at()    == vector<double>(0,0,0) \n                - #get_camera_up_direction()  == vector<double>(0,0,1) \n                - #get_camera_field_of_view() == 90\n                - #get_num_pixels()           == 1 \n        !*/\n\n        camera_transform (\n            const vector<double>& camera_pos,\n            const vector<double>& camera_looking_at,\n            const vector<double>& camera_up_direction,\n            const double camera_field_of_view, \n            const unsigned long num_pixels\n        );\n        /*!\n            requires\n                - 0 < camera_field_of_view < 180\n            ensures\n                - #get_camera_pos() == camera_pos\n                - #get_camera_looking_at() == camera_looking_at\n                - #get_camera_up_direction() == camera_up_direction\n                - #get_camera_field_of_view() == camera_field_of_view\n                - #get_num_pixels() == num_pixels\n        !*/\n\n        dpoint operator() (\n            const vector<double>& p\n        ) const;\n        /*!\n            ensures\n                - Maps the given 3D point p into the 2D image plane defined by the camera\n                  parameters given to this object's constructor.  The 2D point in the image\n                  plane is returned.\n        !*/\n\n        dpoint operator() (\n            const vector<double>& p,\n            double& scale,\n            double& distance\n        ) const;\n        /*!\n            ensures\n                - Maps the given 3D point p into the 2D image plane defined by the camera\n                  parameters given to this object's constructor.  The 2D point in the image\n                  plane is returned.\n                - #scale == a number that tells you how large things are at the point p.\n                  Objects further from the camera appear smaller, in particular, they\n                  appear #scale times their normal size.\n                - #distance == how far away the point is from the image plane.  Objects in\n                  front of the camera will have a positive distance and those behind a\n                  negative distance.\n        !*/\n\n        vector<double> get_camera_pos(\n        ) const;\n        /*!\n            ensures\n                - returns the position, in 3D space, of the camera.  When operator() is\n                  invoked it maps 3D points into the image plane of this camera.\n        !*/\n\n        vector<double> get_camera_looking_at(\n        ) const;\n        /*!\n            ensures\n                - returns the point in 3D space the camera is pointed at.  \n        !*/\n\n        vector<double> get_camera_up_direction(\n        ) const;\n        /*!\n            ensures\n                - returns a vector that defines what direction is \"up\" for the camera.\n                  This means that as you travel from the bottom of the image plane to the\n                  top you will be traveling in the direction of this vector.  Note that\n                  get_camera_up_direction() doesn't need to be orthogonal to the camera's\n                  line of sight (i.e. get_camera_looking_at()-get_camera_pos()), it just\n                  needs to not be an exact multiple of the line of sight.  Any necessary\n                  orthogonalization will be taken care of internally.\n        !*/\n\n        double get_camera_field_of_view(\n        ) const;\n        /*!\n            ensures\n                - returns the field of view of the camera in degrees.\n        !*/\n\n        unsigned long get_num_pixels(\n        ) const;\n        /*!\n            ensures\n                - 3D points that fall within the field of view of the camera are mapped by\n                  operator() into the pixel coordinates of a get_num_pixels() by\n                  get_num_pixels() image.  Therefore, you can use the output of operator()\n                  to index into an image.  However, you still need to perform bounds\n                  checking as there might be 3D points outside the field of view of the\n                  camera and those will be mapped to 2D points outside the image.\n        !*/\n\n    };\n\n    void serialize   (const camera_transform& item, std::ostream& out);\n    void deserialize (camera_transform& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_POINT_TrANSFORMS_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/geometry/polygon.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_POLYGOn_\n#define DLIB_POLYGOn_\n\n#include \"polygon_abstract.h\"\n#include \"rectangle.h\"\n#include \"vector.h\"\n\nnamespace dlib\n{\n    class polygon\n    {\n    public:\n        using size_type = std::vector<point>::size_type;\n\n        polygon(std::vector<point> points) : points(std::move(points)) {}\n\n        size_type size() const { return points.size(); }\n\n        point& operator[](const size_type idx) { return points[idx]; }\n        const point& operator[](const size_type idx) const { return points[idx]; }\n        const point& at(const size_type idx) const { return points.at(idx); }\n\n        std::vector<point>::iterator begin() { return points.begin(); }\n        std::vector<point>::iterator end() { return points.end(); }\n        const std::vector<point>::const_iterator begin() const { return points.begin(); }\n        const std::vector<point>::const_iterator end() const { return points.end(); }\n\n        rectangle get_rect() const\n        {\n            rectangle rect;\n            for (const auto& p : points)\n                rect += p;\n            return rect;\n        }\n\n        double area() const { return polygon_area(points); }\n\n        template <typename alloc>\n        void get_left_and_right_bounds (\n            const long top,\n            const long bottom,\n            std::vector<double, alloc>& left_boundary,\n            std::vector<double, alloc>& right_boundary\n        ) const\n        {\n            using std::min;\n            using std::max;\n\n            left_boundary.assign(bottom-top+1, std::numeric_limits<double>::infinity());\n            right_boundary.assign(bottom-top+1, -std::numeric_limits<double>::infinity());\n\n            // trace out the points along the edge of the polynomial and record them\n            for (unsigned long i = 0; i < points.size(); ++i)\n            {\n                const point p1 = points[i];\n                const point p2 = points[(i+1)%points.size()];\n\n                if (p1.y() == p2.y())\n                {\n                    if (top <= p1.y() && p1.y() <= bottom)\n                    {\n                        const long y = p1.y() - top;\n                        const double xmin = min(p1.x(), p2.x());\n                        const double xmax = min(p1.x(), p2.x());\n                        left_boundary[y]  = min(left_boundary[y], xmin);\n                        right_boundary[y] = max(right_boundary[y], xmax);\n                    }\n                }\n                else\n                {\n                    // Here we trace out the line from p1 to p2 and record where it hits.  \n\n                    // x = m*y + b\n                    const double m = (p2.x() - p1.x())/(double)(p2.y()-p1.y());\n                    const double b = p1.x() - m*p1.y(); // because: x1 = m*y1 + b\n\n                    const long ymin = max(top,min(p1.y(), p2.y()));\n                    const long ymax = min(bottom,max(p1.y(), p2.y()));\n                    for (long y = ymin; y <= ymax; ++y)\n                    {\n                        const double x = m*y + b;\n                        const unsigned long idx = y-top;\n                        left_boundary[idx]  = min(left_boundary[idx], x);\n                        right_boundary[idx] = max(right_boundary[idx], x);\n                    }\n                }\n            }\n        }\n\n    private:\n        std::vector<point> points;\n    };\n}\n\n#endif  // polygon_h_INCLUDED\n"
  },
  {
    "path": "dlib/geometry/polygon_abstract.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_POLYGOn_ABSTRACT_H_\n#ifdef DLIB_POLYGOn_ABSTRACT_H_\n\n#include \"rectangle.h\"\n#include \"vector.h\"\n\nnamespace dlib\n{\n    class polygon\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a polygon inside a Cartesian coordinate system.\n                It is just a wrapper class for a std::vector<point> with some added\n                methods.\n\n                Note that the origin of the coordinate system, i.e. (0,0), is located\n                at the upper left corner.  That is, points such as (1,1) or (3,5)\n                represent locations that are below and to the right of the origin.\n\n                Moreover, the polygon is the area enclosed by the lines defined by all\n                pairwise lines between adjacent points in this object.  That is, if\n                you drew lines between all pairs of points polygon[i] and polygon[(i+1)%polygon.size()]\n                for all valid i, then the area enclosed by those lines is the polygon in \n                question.\n        !*/\n\n    public:\n        using size_type = std::vector<point>::size_type;\n\n        polygon(std::vector<point> points);\n        /*!\n            ensures\n                - #*this represents a polygon defined by points.\n        !*/\n\n        size_type size() const;\n        /*!\n            ensures\n                - returns the number of points in the polygon.\n        !*/\n\n        point& operator[](const size_type idx);\n        /*!\n            requires\n                - idx < size()\n            ensures\n                - returns the point of the polygon at index idx.\n        !*/\n\n        const point& operator[](const size_type idx) const;\n        /*!\n            requires\n                - idx < size()\n            ensures\n                - returns the point of the polygon at index idx.\n        !*/\n\n        const point& at(const size_type idx) const;\n        /*!\n            ensures\n                - returns the point of the polygon at index idx.\n            throws\n                - std::out_of_range if idx >= size()\n        !*/\n\n        rectangle get_rect() const;\n        /*!\n            ensures\n                - returns smallest rectangle that contains all points in the polygon.\n        !*/\n\n        double area() const;\n        /*!\n            ensures\n                - If you walk the points of #*this in order to make a closed polygon, what is its\n                  area?  This function returns that area.  It uses the shoelace formula to\n                  compute the result and so works for general non-self-intersecting polygons.\n        !*/\n\n        template <typename alloc>\n        void get_left_and_right_bounds (\n            const long top,\n            const long bottom,\n            std::vector<double, alloc>& left_boundary,\n            std::vector<double, alloc>& right_boundary\n        ) const;\n        /*!                                                                                \n            requires                                                                       \n                - 0 <= top <= bottom                                                       \n            ensures                                                                        \n                - Finds the left and right edges of the polygon for all y coordinate values in the\n                  range [top, bottom].\n                - #left_boundary.size() == bottom-top+1                                    \n                - #right_boundary.size() == bottom-top+1                                   \n                - for all top <= y <= bottom:                                              \n                    - #left_boundary[y-top] == the x coordinate for the left most side of  \n                      the polygon at coordinate y.                                         \n                    - #right_boundary[y-top] == the x coordinate for the right most side of\n                      the polygon at coordinate y.                                         \n        !*/\n\n    private:\n        std::vector<point> points;\n    };\n}\n\n#endif  // DLIB_POLYGOn_ABSTRACT_H_\n"
  },
  {
    "path": "dlib/geometry/rectangle.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RECTANGLe_\n#define DLIB_RECTANGLe_\n\n#include \"rectangle_abstract.h\"\n#include \"../algs.h\"\n#include <algorithm>\n#include <iostream>\n#include \"../serialize.h\"\n#include \"vector.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    class rectangle\n    {\n        /*!\n            INITIAL VALUE\n                The initial value of this object is defined by its constructor.\n\n            CONVENTION\n                left() == l\n                top() == t\n                right() == r\n                bottom() == b\n        !*/\n\n    public:\n\n        rectangle (\n            long l_,\n            long t_,\n            long r_,\n            long b_\n        ) :\n            l(l_),\n            t(t_),\n            r(r_),\n            b(b_)\n        {}\n\n        rectangle (\n            unsigned long w,\n            unsigned long h\n        ) :\n            l(0),\n            t(0),\n            r(static_cast<long>(w)-1),\n            b(static_cast<long>(h)-1)\n        {\n            DLIB_ASSERT((w > 0 && h > 0) || (w == 0 && h == 0),\n                \"\\trectangle(width,height)\"\n                << \"\\n\\twidth and height must be > 0 or both == 0\"\n                << \"\\n\\twidth:  \" << w \n                << \"\\n\\theight: \" << h \n                << \"\\n\\tthis: \" << this\n                );\n        }\n\n        rectangle (\n            const point& p\n        ) :\n            l(p.x()),\n            t(p.y()),\n            r(p.x()),\n            b(p.y())\n        {\n        }\n\n        rectangle (\n            const point& p1,\n            const point& p2\n        )\n        {\n            *this = rectangle(p1) + rectangle(p2);\n        }\n\n        template <typename T>\n        rectangle (\n            const vector<T,2>& p1,\n            const vector<T,2>& p2\n        )\n        {\n            *this = rectangle(p1) + rectangle(p2);\n        }\n\n        rectangle (\n        ) :\n            l(0),\n            t(0),\n            r(-1),\n            b(-1)\n        {}\n\n        long top (\n        ) const { return t; }\n\n        long& top (\n        ) { return t; }\n\n        void set_top (\n            long top_\n        ) { t = top_; }\n\n        long left (\n        ) const { return l; }\n\n        long& left (\n        ) { return l; }\n\n        void set_left (\n            long left_\n        ) { l = left_; }\n\n        long right (\n        ) const { return r; }\n\n        long& right (\n        ) { return r; }\n\n        void set_right (\n            long right_\n        ) { r = right_; }\n\n        long bottom (\n        ) const { return b; }\n\n        long& bottom (\n        ) { return b; }\n\n        void set_bottom (\n            long bottom_\n        ) { b = bottom_; }\n\n        const point tl_corner (\n        ) const { return point(left(), top()); }\n\n        const point bl_corner (\n        ) const { return point(left(), bottom()); } \n\n        const point tr_corner (\n        ) const { return point(right(), top()); }\n\n        const point br_corner (\n        ) const { return point(right(), bottom()); }\n       \n        unsigned long width (\n        ) const \n        { \n            if (is_empty())\n                return 0;\n            else\n                return r - l + 1; \n        }\n\n        unsigned long height (\n        ) const \n        { \n            if (is_empty())\n                return 0;\n            else\n                return b - t + 1; \n        }\n\n        unsigned long area (\n        ) const\n        {\n            return width()*height();\n        }\n\n        bool is_empty (\n        ) const { return (t > b || l > r); }\n\n        rectangle operator + (\n            const rectangle& rhs\n        ) const\n        {\n            if (rhs.is_empty())\n                return *this;\n            else if (is_empty())\n                return rhs;\n\n            return rectangle (\n                std::min(l,rhs.l),\n                std::min(t,rhs.t),\n                std::max(r,rhs.r),\n                std::max(b,rhs.b)\n                );\n        }\n\n        rectangle intersect (\n            const rectangle& rhs\n        ) const\n        {\n            return rectangle (\n                std::max(l,rhs.l),\n                std::max(t,rhs.t),\n                std::min(r,rhs.r),\n                std::min(b,rhs.b)\n                );\n        }\n\n        bool contains (\n            const point& p\n        ) const\n        {\n            if (p.x() < l || p.x() > r || p.y() < t || p.y() > b)\n                return false;\n            return true;\n        }\n\n        bool contains (\n            long x,\n            long y\n        ) const\n        {\n            if (x < l || x > r || y < t || y > b)\n                return false;\n            return true;\n        }\n\n        bool contains (\n            const rectangle& rect\n        ) const\n        {\n            return (rect + *this == *this);\n        }\n\n        rectangle& operator+= (\n            const point& p \n        )\n        {\n            *this = *this + rectangle(p);\n            return *this;\n        }\n\n        rectangle& operator+= (\n            const rectangle& rect\n        )\n        {\n            *this = *this + rect;\n            return *this;\n        }\n\n        bool operator== (\n            const rectangle& rect \n        ) const \n        {\n            return (l == rect.l) && (t == rect.t) && (r == rect.r) && (b == rect.b);\n        }\n\n        bool operator!= (\n            const rectangle& rect \n        ) const \n        {\n            return !(*this == rect);\n        }\n\n        inline bool operator< (const dlib::rectangle& b) const\n        { \n            if      (left() < b.left()) return true;\n            else if (left() > b.left()) return false;\n            else if (top() < b.top()) return true;\n            else if (top() > b.top()) return false;\n            else if (right() < b.right()) return true;\n            else if (right() > b.right()) return false;\n            else if (bottom() < b.bottom()) return true;\n            else if (bottom() > b.bottom()) return false;\n            else                    return false;\n        }\n\n    private:\n        long l;\n        long t;\n        long r;\n        long b;   \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const rectangle& item, \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.left(),out); \n            serialize(item.top(),out); \n            serialize(item.right(),out); \n            serialize(item.bottom(),out); \n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing an object of type rectangle\");\n        }\n    }\n\n    inline void deserialize (\n        rectangle& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            deserialize(item.left(),in); \n            deserialize(item.top(),in); \n            deserialize(item.right(),in); \n            deserialize(item.bottom(),in); \n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing an object of type rectangle\");\n        }\n    }\n\n    inline std::ostream& operator<< (\n        std::ostream& out, \n        const rectangle& item \n    )   \n    {\n        out << \"[(\" << item.left() << \", \" << item.top() << \") (\" << item.right() << \", \" << item.bottom() << \")]\";\n        return out;\n    }\n\n    inline std::istream& operator>>(\n        std::istream& in, \n        rectangle& item \n    )\n    {\n        // ignore any whitespace\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n        // now eat the leading '[' character\n        if (in.get() != '[')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n        point p1, p2;\n        in >> p1;\n        in >> p2;\n        item = rectangle(p1) + rectangle(p2);\n\n        // ignore any whitespace\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n        // now eat the trailing ']' character\n        if (in.get() != ']')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n        }\n        return in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle centered_rect (\n        long x,\n        long y,\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        rectangle result;\n        result.set_left ( x - static_cast<long>(width) / 2 );\n        result.set_top ( y - static_cast<long>(height) / 2 );\n        result.set_right ( result.left() + width - 1 );\n        result.set_bottom ( result.top() + height - 1 );\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle intersect (\n        const rectangle& a,\n        const rectangle& b\n    ) { return a.intersect(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long area (\n        const rectangle& a\n    ) { return a.area(); }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point center (\n        const dlib::rectangle& rect\n    )\n    {\n        point temp(rect.left() + rect.right() + 1,\n                   rect.top() + rect.bottom() + 1);\n\n        if (temp.x() < 0)\n            temp.x() -= 1;\n\n        if (temp.y() < 0)\n            temp.y() -= 1;\n\n        return temp/2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline dlib::vector<double,2> dcenter (\n        const dlib::rectangle& rect\n    )\n    {\n        dlib::vector<double,2> temp(rect.left() + rect.right(),\n                                    rect.top() + rect.bottom());\n\n        return temp/2.0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline long distance_to_rect_edge (\n        const rectangle& rect,\n        const point& p\n    )\n    {\n        using std::max;\n        using std::min;\n        using std::abs;\n\n        const long dist_x = min(abs(p.x()-rect.left()), abs(p.x()-rect.right()));\n        const long dist_y = min(abs(p.y()-rect.top()),  abs(p.y()-rect.bottom()));\n\n        if (rect.contains(p))\n            return min(dist_x,dist_y);\n        else if (rect.left() <= p.x() && p.x() <= rect.right())\n            return dist_y;\n        else if (rect.top() <= p.y() && p.y() <= rect.bottom())\n            return dist_x;\n        else\n            return dist_x + dist_y;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline const dlib::vector<T,2> nearest_point (\n        const rectangle& rect,\n        const dlib::vector<T,2>& p\n    )\n    {\n        dlib::vector<T,2> temp(p);\n        if (temp.x() < rect.left())\n            temp.x() = rect.left();\n        else if (temp.x() > rect.right())\n            temp.x() = rect.right();\n\n        if (temp.y() < rect.top())\n            temp.y() = rect.top();\n        else if (temp.y() > rect.bottom())\n            temp.y() = rect.bottom();\n\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline size_t nearest_rect (\n        const std::vector<rectangle>& rects,\n        const point& p\n    )\n    {\n        DLIB_ASSERT(rects.size() > 0);\n        size_t idx = 0;\n        double best_dist = std::numeric_limits<double>::infinity();\n\n        for (size_t i = 0; i < rects.size(); ++i)\n        {\n            if (rects[i].contains(p))\n            {\n                return i;\n            }\n            else\n            {\n                double dist = (nearest_point(rects[i],p)-p).length();\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    idx = i;\n                }\n            }\n        }\n        return idx;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline void clip_line_to_rectangle (\n        const rectangle& box,\n        dlib::vector<T,2>& p1,\n        dlib::vector<T,2>& p2\n    )\n    {\n        // Now clip the line segment so it is contained inside box.\n        if (p1.x() == p2.x())\n        {\n            if (!box.contains(p1))\n                p1.y() = box.top();\n            if (!box.contains(p2))\n                p2.y() = box.bottom();\n        }\n        else if (p1.y() == p2.y())\n        {\n            if (!box.contains(p1))\n                p1.x() = box.left();\n            if (!box.contains(p2))\n                p2.x() = box.right();\n        }\n        else\n        {\n            // We use these relations to find alpha values.  These values tell us\n            // how to generate points intersecting the rectangle boundaries.  We then\n            // test the resulting points for ones that are inside the rectangle and output\n            // those.\n            //box.left()  == alpha1*(p1.x()-p2.x()) + p2.x();\n            //box.right() == alpha2*(p1.x()-p2.x()) + p2.x();\n\n            const dlib::vector<T,2> d = p1-p2;\n            double alpha1 = (box.left()  -p2.x())/(double)d.x();\n            double alpha2 = (box.right() -p2.x())/(double)d.x();\n            double alpha3 = (box.top()   -p2.y())/(double)d.y();\n            double alpha4 = (box.bottom()-p2.y())/(double)d.y();\n\n            const dlib::vector<T,2> c1 = alpha1*d + p2;\n            const dlib::vector<T,2> c2 = alpha2*d + p2;\n            const dlib::vector<T,2> c3 = alpha3*d + p2;\n            const dlib::vector<T,2> c4 = alpha4*d + p2;\n\n            if (!box.contains(p1))\n                p1 = c1;\n            if (!box.contains(p2))\n                p2 = c2;\n            if (box.contains(c3))\n            {\n                if (!box.contains(p2))\n                    p2 = c3;\n                else if (!box.contains(p1))\n                    p1 = c3;\n            }\n            if (box.contains(c4))\n            {\n                if (!box.contains(p2))\n                    p2 = c4;\n                else if (!box.contains(p1))\n                    p1 = c4;\n            }\n        }\n\n        p1 = nearest_point(box, p1);\n        p2 = nearest_point(box, p2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle centered_rect (\n        const point& p,\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        return centered_rect(p.x(),p.y(),width,height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<rectangle> centered_rects (\n        const std::vector<point>& pts,\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        std::vector<rectangle> tmp;\n        tmp.reserve(pts.size());\n        for (auto& p : pts)\n            tmp.emplace_back(centered_rect(p, width, height));\n        return tmp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle centered_rect (\n        const rectangle& rect,\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        return centered_rect((rect.left()+rect.right())/2,  (rect.top()+rect.bottom())/2, width, height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle shrink_rect (\n        const rectangle& rect,\n        long num \n    )\n    {\n        return rectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle grow_rect (\n        const rectangle& rect,\n        long num \n    )\n    {\n        return shrink_rect(rect, -num);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle shrink_rect (\n        const rectangle& rect,\n        long width,\n        long height\n    )\n    {\n        return rectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle grow_rect (\n        const rectangle& rect,\n        long width,\n        long height\n    )\n    {\n        return shrink_rect(rect, -width, -height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle scale_rect (\n        const rectangle& rect,\n        double scale\n    )\n    {\n        DLIB_ASSERT(scale > 0, \"scale factor must be > 0\");\n\n        const long l = std::lround(rect.left()*scale);\n        const long t = std::lround(rect.top()*scale);\n        const long r = std::lround(rect.right()*scale);\n        const long b = std::lround(rect.bottom()*scale);\n        return rectangle(l, t, r, b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle translate_rect (\n        const rectangle& rect,\n        const point& p\n    )\n    {\n        rectangle result;\n        result.set_top ( rect.top() + p.y() );\n        result.set_bottom ( rect.bottom() + p.y() );\n        result.set_left ( rect.left() + p.x() );\n        result.set_right ( rect.right() + p.x() );\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle translate_rect (\n        const rectangle& rect,\n        long x,\n        long y\n    )\n    {\n        rectangle result;\n        result.set_top ( rect.top() + y );\n        result.set_bottom ( rect.bottom() + y );\n        result.set_left ( rect.left() + x );\n        result.set_right ( rect.right() + x );\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle resize_rect (\n        const rectangle& rect,\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        return rectangle(rect.left(),rect.top(), \n                         rect.left()+width-1,\n                         rect.top()+height-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle resize_rect_width (\n        const rectangle& rect,\n        unsigned long width\n    )\n    {\n        return rectangle(rect.left(),rect.top(), \n                         rect.left()+width-1,\n                         rect.bottom());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle resize_rect_height (\n        const rectangle& rect,\n        unsigned long height \n    )\n    {\n        return rectangle(rect.left(),rect.top(), \n                         rect.right(),\n                         rect.top()+height-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle move_rect (\n        const rectangle& rect,\n        const point& p\n    )\n    {\n        return rectangle(p.x(), p.y(), p.x()+rect.width()-1, p.y()+rect.height()-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle move_rect (\n        const rectangle& rect,\n        long x,\n        long y \n    )\n    {\n        return rectangle(x, y, x+rect.width()-1, y+rect.height()-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    // Circumvent what appears to be a bug in Visual Studio 2019's optimizer\n    // (see: https://forum.juce.com/t/warning-in-the-lastest-vs2019/38267)\n#if defined (_MSC_VER)\n#pragma warning ( push )\n#pragma warning ( disable: 4723 )\n#endif\n    inline rectangle set_rect_area (\n        const rectangle& rect,\n        unsigned long area\n    )\n    {\n        DLIB_ASSERT(area > 0);\n\n        if (rect.area() == 0)\n        {\n            // In this case we will make the output rectangle a square with the requested\n            // area.\n            unsigned long scale = std::round(std::sqrt(area));\n            return centered_rect(rect, scale, scale);\n        }\n        else\n        {\n            const double scale = std::sqrt(area/static_cast<double>(rect.area()));\n            return centered_rect(rect, std::lround(rect.width()*scale), std::lround(rect.height()*scale));\n        }\n    }\n#if defined (_MSC_VER)\n#pragma warning ( pop )\n#endif\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle set_aspect_ratio (\n        const rectangle& rect,\n        double ratio\n    )\n    {\n        DLIB_ASSERT(ratio > 0,\n            \"\\t rectangle set_aspect_ratio()\"\n            << \"\\n\\t ratio: \" << ratio \n            );\n\n        // aspect ratio is w/h\n\n        // we need to find the rectangle that is nearest to rect in area but\n        // with an aspect ratio of ratio.\n\n        // w/h == ratio\n        // w*h == rect.area()\n\n        if (ratio >= 1)\n        {\n            const long h = static_cast<long>(std::sqrt(rect.area()/ratio) + 0.5);\n            const long w = static_cast<long>(h*ratio + 0.5);\n            return centered_rect(rect, w, h);\n        }\n        else\n        {\n            const long w = static_cast<long>(std::sqrt(rect.area()*ratio) + 0.5);\n            const long h = static_cast<long>(w/ratio + 0.5);\n            return centered_rect(rect, w, h);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    inline const rectangle get_rect (\n        const T& m\n    )\n    {\n        return rectangle(0, 0, num_columns(m)-1, num_rows(m)-1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle operator+ (\n        const rectangle& r,\n        const point& p\n    )\n    {\n        return r + rectangle(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle operator+ (\n        const point& p,\n        const rectangle& r\n    )\n    {\n        return r + rectangle(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RECTANGLe_\n\n\n"
  },
  {
    "path": "dlib/geometry/rectangle_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RECTANGLe_ABSTRACT_\n#ifdef DLIB_RECTANGLe_ABSTRACT_\n\n#include \"vector_abstract.h\"\n#include <iostream>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    class rectangle\n    {\n        /*!\n            INITIAL VALUE\n                The initial value of this object is defined by its constructor.                \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a rectangular region inside a Cartesian \n                coordinate system.  The region is the rectangle with its top \n                left corner at position (left(),top()) and its bottom right corner \n                at (right(),bottom()).\n\n                Note that the origin of the coordinate system, i.e. (0,0), is located\n                at the upper left corner.  That is, points such as (1,1) or (3,5) \n                represent locations that are below and to the right of the origin.\n\n                Also note that rectangles where top() > bottom() or left() > right() \n                represent empty rectangles.\n        !*/\n\n    public:\n\n        rectangle (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - #*this represents the same rectangle as rect\n        !*/\n\n        rectangle (\n        );\n        /*!\n            ensures\n                - #left() == 0\n                - #top() == 0\n                - #right() == -1 \n                - #bottom() == -1 \n                - #is_empty() == true\n        !*/\n\n        rectangle (\n            long left_,\n            long top_,\n            long right_,\n            long bottom_\n        );\n        /*!\n            ensures\n                - #left() == left_\n                - #top() == top_\n                - #right() == right_\n                - #bottom() == bottom_\n        !*/\n\n        rectangle (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*!\n            requires\n                - (width_ > 0 && height_ > 0) || (width_ == 0 && height_ == 0)\n            ensures\n                - #left() == 0  \n                - #top() == 0\n                - #width() == width_\n                - #height() == height_\n        !*/\n\n        rectangle (\n            const point& p\n        );\n        /*!\n            ensures\n                - #left()   == p.x()\n                - #top()    == p.y()\n                - #right()  == p.x()\n                - #bottom() == p.y()\n        !*/\n\n        template <typename T>\n        rectangle (\n            const vector<T,2>& p1,\n            const vector<T,2>& p2\n        );\n        /*!\n            ensures\n                - #*this == rectangle(p1) + rectangle(p2)\n        !*/\n\n        long left (\n        ) const;\n        /*!\n            ensures\n                - returns the x coordinate for the left side of this rectangle\n        !*/\n\n        long& left (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the x coordinate for the left side \n                  of this rectangle\n        !*/\n\n        void set_left (\n            long left_\n        );\n        /*!\n            ensures\n                - #left() == left_\n        !*/\n\n        long top (\n        ) const;\n        /*!\n            ensures\n                - returns the y coordinate for the top of this rectangle\n        !*/\n\n        long& top (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the y coordinate for the \n                  top of this rectangle\n        !*/\n\n        void set_top (\n            long top_\n        );\n        /*!\n            ensures\n                - #top() == top_\n        !*/\n\n        long right (\n        ) const;\n        /*!\n            ensures\n                - returns the x coordinate for the right side of this rectangle\n        !*/\n\n        long& right (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the x coordinate for the right \n                  side of this rectangle\n        !*/\n\n        void set_right (\n            long right_\n        );\n        /*!\n            ensures\n                - #right() == right_\n        !*/\n\n        long bottom (\n        ) const;\n        /*!\n            ensures\n                - returns the y coordinate for the bottom of this rectangle\n        !*/\n       \n        long& bottom (\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the y coordinate for the bottom \n                  of this rectangle\n        !*/\n       \n        void set_bottom (\n            long bottom_\n        );\n        /*!\n            ensures\n                - #bottom() == bottom_\n        !*/\n\n        const point tl_corner (\n        ) const;\n        /*!\n            ensures\n                - returns point(left(), top()) \n                  (i.e. returns the top left corner point for this rectangle)\n        !*/\n\n        const point bl_corner (\n        ) const;\n        /*!\n            ensures\n                - returns point(left(), bottom()) \n                  (i.e. returns the bottom left corner point for this rectangle)\n        !*/\n\n        const point tr_corner (\n        ) const;\n        /*!\n            ensures\n                - returns point(right(), top()) \n                  (i.e. returns the top right corner point for this rectangle)\n        !*/\n\n        const point br_corner (\n        ) const;\n        /*!\n            ensures\n                - returns point(right(), bottom()) \n                  (i.e. returns the bottom right corner point for this rectangle)\n        !*/\n\n        bool is_empty (\n        ) const;\n        /*!\n            ensures\n                - if (top() > bottom() || left() > right()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        unsigned long width (\n        ) const;\n        /*!\n            ensures\n                - if (is_empty()) then\n                    - returns 0\n                - else\n                    - returns the width of this rectangle.\n                      (i.e. right() - left() + 1)\n        !*/\n\n        unsigned long height (\n        ) const;\n        /*!\n            ensures\n                - if (is_empty()) then\n                    - returns 0\n                - else\n                    - returns the height of this rectangle.\n                      (i.e. bottom() - top() + 1)\n        !*/\n\n        unsigned long area (\n        ) const;\n        /*!\n            ensures\n                - returns width()*height()\n        !*/\n\n        rectangle operator + (\n            const rectangle& rhs\n        ) const;\n        /*!\n            ensures\n                - if (rhs.is_empty() == false && this->is_empty() == false) then\n                    - returns the smallest rectangle that contains both *this and \n                      rhs.\n                - if (rhs.is_empty() == true && this->is_empty() == false) then\n                    - returns *this\n                - if (rhs.is_empty() == false && this->is_empty() == true) then\n                    - returns rhs\n                - if (rhs.is_empty() == true && this->is_empty() == true) then\n                    - returns a rectangle that has is_empty() == true\n        !*/\n\n        rectangle intersect (\n            const rectangle& rhs\n        ) const;\n        /*!\n            ensures\n                - if (there is a region of intersection between *this and rhs) then\n                    - returns a rectangle that represents the intersection of *this \n                      and rhs.\n                - else\n                    - returns a rectangle where is_empty() == true\n        !*/\n\n        bool contains (\n            long x,\n            long y\n        ) const;\n        /*!\n            ensures\n                - if (the point (x,y) is contained in this rectangle) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool contains (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - if (the point (p.x(),p.y()) is contained in this rectangle) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool contains (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - if (rect + *this == *this) then\n                    - returns true\n                      (i.e. returns true if *this contains the given rectangle)\n                - else\n                    - returns false\n        !*/\n\n        rectangle& operator= (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - #*this represents the same rectangle as rect\n                - returns #*this\n        !*/\n\n        rectangle& operator+= (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - #*this == *this + rect \n                - returns #*this\n        !*/\n\n        bool operator== (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - if (top() == rect.top() && left() == rect.left() &&\n                      right() == rect.right() && bottom() == rect.bottom()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool operator!= (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns !(*this == rect)\n        !*/\n\n        bool operator< (\n            const dlib::rectangle& a,\n            const dlib::rectangle& b\n        ) const;\n        /*!\n            ensures\n                - Defines a total ordering over rectangles so they can be used in\n                  associative containers.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const rectangle& item, \n        std::ostream& out\n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        rectangle& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n    std::ostream& operator<< (\n        std::ostream& out, \n        const rectangle& item \n    );   \n    /*!\n        ensures\n            - writes item to out in the form \"[(left, top) (right, bottom)]\"\n    !*/\n\n    std::istream& operator>>(\n        std::istream& in, \n        rectangle& item \n    );   \n    /*!\n        ensures\n            - reads a rectangle from the input stream in and stores it in #item.\n              The data in the input stream should be of the form [(left, top) (right, bottom)]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point center (\n        const dlib::rectangle& rect\n    );\n    /*!\n        ensures\n            - returns the center of the given rectangle\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    dlib::vector<double,2> dcenter (\n        const dlib::rectangle& rect\n    );\n    /*!\n        ensures\n            - returns the center of the given rectangle using a real valued vector.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle centered_rect (\n        const point& p,\n        unsigned long width,\n        unsigned long height\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - center(R) == p\n                - if (width == 0 || height == 0)\n                    - R.width() == 0 \n                    - R.height() == 0 \n                - else\n                    - R.width() == width\n                    - R.height() == height \n                - R.tl_corner() == point(p.x()-width/2, p.y()-height/2)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<rectangle> centered_rects (\n        const std::vector<point>& pts,\n        unsigned long width,\n        unsigned long height\n    );\n    /*!\n        ensures\n            - returns an array ARR where:\n                - #ARR.size() == pts.size()\n                - #ARR[i] == centered_rect(pts[i], width, height)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle centered_rect (\n        long x,\n        long y,\n        unsigned long width,\n        unsigned long height\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - center(R) == p\n                - if (width == 0 || height == 0)\n                    - R.width() == 0 \n                    - R.height() == 0 \n                - else\n                    - R.width() == width\n                    - R.height() == height \n                - R.tl_corner() == point(x-width/2, y-height/2)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle centered_rect (\n        const rectangle& rect,\n        unsigned long width,\n        unsigned long height\n    );\n    /*!\n        ensures\n            - returns centered_rect( (rect.tl_corner() + rect.br_corner())/2, width, height)\n              (i.e. returns a rectangle centered on rect but with the given width\n              and height)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle set_rect_area (\n        const rectangle& rect,\n        unsigned long area\n    );\n    /*!\n        requires\n            - area > 0\n        ensures\n            - Returns a rectangle R such that:\n                - center(R) == center(rect)\n                - R has the same aspect ratio as rect.  If rect.area() == 0 then the\n                  returned rect has a 1:1 aspect ratio.\n                - R.area() == area\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle set_aspect_ratio (\n        const rectangle& rect,\n        double ratio\n    );\n    /*!\n        requires\n            - ratio > 0\n        ensures\n            - This function reshapes the given rectangle so that it has the given aspect\n              ratio.  In particular, this means we return a rectangle R such that the\n              following equations are as true as possible:\n                - R.width()/R.height() == ratio\n                - R.area() == rect.area()\n                - center(rect) == center(R)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle intersect (\n        const rectangle& a,\n        const rectangle& b\n    );\n    /*!\n        ensures\n            - returns a.intersect(b)\n              (i.e. returns a rectangle representing the intersection of a and b)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline unsigned long area (\n        const rectangle& a\n    );\n    /*!\n        ensures\n            - returns a.area()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle shrink_rect (\n        const rectangle& rect,\n        long num \n    );\n    /*!\n        ensures\n            - returns rectangle(rect.left()+num, rect.top()+num, rect.right()-num, rect.bottom()-num)\n              (i.e. shrinks the given rectangle by shrinking its border by num)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle grow_rect (\n        const rectangle& rect,\n        long num \n    );\n    /*!\n        ensures\n            - return shrink_rect(rect, -num)\n              (i.e. grows the given rectangle by expanding its border by num)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle shrink_rect (\n        const rectangle& rect,\n        long width,\n        long height\n    );\n    /*!\n        ensures\n            - returns rectangle(rect.left()+width, rect.top()+height, rect.right()-width, rect.bottom()-height)\n              (i.e. shrinks the given rectangle by shrinking its left and right borders by width\n              and its top and bottom borders by height. )\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const rectangle grow_rect (\n        const rectangle& rect,\n        long width,\n        long height\n    );\n    /*!\n        ensures\n            - return shrink_rect(rect, -width, -height)\n              (i.e. grows the given rectangle by expanding its border)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle scale_rect (\n        const rectangle& rect,\n        double scale\n    );\n    /*!\n        requires\n            - scale > 0\n        ensures\n            - return rectangle(rect.left() * scale, rect.top() * scale, rect.right() * scale, rect.bottom() * scale)\n              (i.e. resizes the given rectangle by multiplying all side coordinates with a scale factor)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle translate_rect (\n        const rectangle& rect,\n        const point& p\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.left()   == rect.left()   + p.x()\n                - R.right()  == rect.right()  + p.x()\n                - R.top()    == rect.top()    + p.y()\n                - R.bottom() == rect.bottom() + p.y()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle translate_rect (\n        const rectangle& rect,\n        long x,\n        long y\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.left()   == rect.left()   + x\n                - R.right()  == rect.right()  + x\n                - R.top()    == rect.top()    + y\n                - R.bottom() == rect.bottom() + y\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle resize_rect (\n        const rectangle& rect,\n        unsigned long width,\n        unsigned long height\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - if (width == 0 || height == 0)\n                    - R.width() == 0 \n                    - R.height() == 0 \n                - else\n                    - R.width() == width\n                    - R.height() == height \n                - R.left() == rect.left() \n                - R.top() == rect.top() \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle resize_rect_width (\n        const rectangle& rect,\n        unsigned long width\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.width() == width\n                - R.left() == rect.left() \n                - R.top() == rect.top() \n                - R.bottom() == rect.bottom() \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle resize_rect_height (\n        const rectangle& rect,\n        unsigned long height \n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.height() == height \n                - R.left() == rect.left() \n                - R.top() == rect.top() \n                - R.right() == rect.right() \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle move_rect (\n        const rectangle& rect,\n        const point& p\n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.width() == rect.width() \n                - R.height() == rect.height() \n                - R.left() == p.x()\n                - R.top() == p.y() \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle move_rect (\n        const rectangle& rect,\n        long x,\n        long y \n    );\n    /*!\n        ensures\n            - returns a rectangle R such that:\n                - R.width() == rect.width() \n                - R.height() == rect.height() \n                - R.left() == x \n                - R.top() == y \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline const dlib::vector<T,2> nearest_point (\n        const rectangle& rect,\n        const dlib::vector<T,2>& p\n    );\n    /*!\n        ensures\n            - if (rect.contains(p)) then\n                - returns p\n            - else\n                - returns the point in rect that is closest to p\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline size_t nearest_rect (\n        const std::vector<rectangle>& rects,\n        const point& p\n    );\n    /*!\n        requires\n            - rects.size() > 0\n        ensures\n            - returns the index of the rectangle that is closest to the point p.  In\n              particular, this function returns an IDX such that:\n                length(nearest_point(rects[IDX],p) - p)\n              is minimized.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline long distance_to_rect_edge (\n        const rectangle& rect,\n        const point& p\n    );\n    /*!\n        ensures\n            - returns the Manhattan distance between the edge of rect and p.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void clip_line_to_rectangle (\n        const rectangle& box,\n        dlib::vector<T,2>& p1,\n        dlib::vector<T,2>& p2\n    );\n    /*!\n        ensures\n            - clips the line segment that goes from points p1 to p2 so that it is entirely\n              within the given box.  In particular, we will have:\n                - box.contains(#p1) == true\n                - box.contains(#p2) == true\n                - The line segment #p1 to #p2 is entirely contained within the line segment\n                  p1 to p2.  Moreover, #p1 to #p2 is the largest such line segment that\n                  fits within the given box.\n            - If the line segment does not intersect the box then the result is some\n              arbitrary line segment inside the box.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    const rectangle get_rect (\n        const T& m\n    );\n    /*!\n        requires\n            - It must be possible to determine the number of \"rows\" and \"columns\" in m.\n              Either by calling num_rows(m) and num_columns(m) or by calling m.nr() and\n              m.nc() to obtain the number of rows and columns respectively.  Moreover,\n              these routines should return longs.\n        ensures\n            - returns rectangle(0, 0, num_columns(m)-1, num_rows(m)-1)\n              (i.e. assuming T represents some kind of rectangular grid, such as\n              the dlib::matrix or dlib::array2d objects, this function returns the\n              bounding rectangle for that gridded object.)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle operator+ (\n        const rectangle& r,\n        const point& p\n    );\n    /*!\n        ensures\n            - returns r + rectangle(p)\n              (i.e. returns the rectangle that contains both r and p)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle operator+ (\n        const point& p,\n        const rectangle& r\n    );\n    /*!\n        ensures\n            - returns r + rectangle(p)\n              (i.e. returns the rectangle that contains both r and p)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RECTANGLe_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/geometry/vector.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_VECTOr_H_\n#define DLIB_VECTOr_H_\n\n#include <cmath>\n#include \"vector_abstract.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include <functional>\n#include <iostream>\n#include \"../matrix/matrix.h\"\n#include <limits>\n#include <array>\n\n#if defined(_MSC_VER) && _MSC_VER < 1400\n#pragma warning(push)\n\n// Despite my efforts to disabuse visual studio of its usual nonsense I can't find a \n// way to make this warning go away without just disabling it.   This is the warning:\n//   dlib\\geometry\\vector.h(129) : warning C4805: '==' : unsafe mix of type 'std::numeric_limits<_Ty>::is_integer' and type 'bool' in operation\n// \n#pragma warning(disable:4805)\n#endif\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        long NR = 3\n        >\n    class vector;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename enabled = void> \n    struct vect_promote;\n\n    template <typename T, typename U, bool res = (sizeof(T) <= sizeof(U))>\n    struct largest_type\n    {\n        typedef T type;\n    };\n    template <typename T, typename U>\n    struct largest_type<T,U,true>\n    {\n        typedef U type;\n    };\n\n    template <typename T, typename U> \n    struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == std::numeric_limits<U>::is_integer>::type> \n    { \n        // If both T and U are both either integral or non-integral then just\n        // use the biggest one\n        typedef typename largest_type<T,U>::type type;\n    };\n\n    template <typename T, typename U> \n    struct vect_promote<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer != std::numeric_limits<U>::is_integer>::type> \n    { \n        typedef double type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    // This insanity here is to work around a bug in visual studio 8.   These two rebind\n    // structures are actually declared at a few points in this file because just having the\n    // one declaration here isn't enough for visual studio.  It takes the three spread around\n    // to avoid all its bugs. \n    template <typename T, long N>\n    struct vc_rebind\n    {\n        typedef vector<T,N> type;\n    };\n    template <typename T, typename U, long N>\n    struct vc_rebind_promote\n    {\n        typedef vector<typename vect_promote<T,U>::type,N> type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename enabled = void>\n    struct vector_assign_helper\n    {\n        template <long NR>\n        static void assign (\n            vector<T,2>& dest,\n            const vector<U,NR>& src\n        )\n        {\n            dest.x() = static_cast<T>(src.x());\n            dest.y() = static_cast<T>(src.y());\n        }\n\n        template <long NR>\n        static void assign (\n            vector<T,3>& dest,\n            const vector<U,NR>& src\n        )\n        {\n            dest.x() = static_cast<T>(src.x());\n            dest.y() = static_cast<T>(src.y());\n            dest.z() = static_cast<T>(src.z());\n        }\n\n        template <typename EXP>\n        static void assign (\n            vector<T,2>& dest,\n            const matrix_exp<EXP>& m\n        )\n        {\n            T x = static_cast<T>(m(0));\n            T y = static_cast<T>(m(1));\n            dest.x() = x;\n            dest.y() = y;\n        }\n\n        template <typename EXP>\n        static void assign (\n            vector<T,3>& dest,\n            const matrix_exp<EXP>& m\n        )\n        {\n            T x = static_cast<T>(m(0));\n            T y = static_cast<T>(m(1));\n            T z = static_cast<T>(m(2));\n\n            dest.x() = x;\n            dest.y() = y;\n            dest.z() = z;\n        }\n    };\n\n    // This is an overload for the case where you are converting from a floating point\n    // type to an integral type.  These overloads make sure values are rounded to \n    // the nearest integral value.\n    template <typename T, typename U>\n    struct vector_assign_helper<T,U, typename enable_if_c<std::numeric_limits<T>::is_integer == true && \n                                                          std::numeric_limits<U>::is_integer == false>::type>\n    {\n        template <long NR>\n        static void assign (\n            vector<T,2>& dest,\n            const vector<U,NR>& src\n        )\n        {\n            dest.x() = static_cast<T>(std::floor(src.x() + 0.5));\n            dest.y() = static_cast<T>(std::floor(src.y() + 0.5));\n        }\n\n        template <long NR>\n        static void assign (\n            vector<T,3>& dest,\n            const vector<U,NR>& src\n        )\n        {\n            dest.x() = static_cast<T>(std::floor(src.x() + 0.5));\n            dest.y() = static_cast<T>(std::floor(src.y() + 0.5));\n            dest.z() = static_cast<T>(std::floor(src.z() + 0.5));\n        }\n\n        template <typename EXP>\n        static void assign (\n            vector<T,3>& dest,\n            const matrix_exp<EXP>& m\n        )\n        {\n            dest.x() = static_cast<T>(std::floor(m(0) + 0.5));\n            dest.y() = static_cast<T>(std::floor(m(1) + 0.5));\n            dest.z() = static_cast<T>(std::floor(m(2) + 0.5));\n        }\n\n        template <typename EXP>\n        static void assign (\n            vector<T,2>& dest,\n            const matrix_exp<EXP>& m\n        )\n        {\n            dest.x() = static_cast<T>(std::floor(m(0) + 0.5));\n            dest.y() = static_cast<T>(std::floor(m(1) + 0.5));\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class vector<T,3> : public matrix<T,3,1>\n    {\n        /*!\n            INITIAL VALUE\n                - x() == 0\n                - y() == 0\n                - z() == 0\n\n            CONVENTION\n                - (*this)(0) == x() \n                - (*this)(1) == y() \n                - (*this)(2) == z() \n\n        !*/\n\n        // This insanity here is to work around a bug in visual studio 8.  \n        template <typename V, long N>\n        struct vc_rebind\n        {\n            typedef vector<V,N> type;\n        };\n            template <typename V, typename U, long N>\n        struct vc_rebind_promote\n        {\n            typedef vector<typename vect_promote<V,U>::type,N> type;\n        };\n\n    public:\n\n        typedef T type;\n        \n        vector (\n        ) \n        {\n            x() = 0;\n            y() = 0;\n            z() = 0;\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const T _x,\n            const T _y,\n            const T _z\n        ) \n        {\n            x() = _x;\n            y() = _y;\n            z() = _z;\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const vector& item\n        ) : matrix<T,3,1>(item)\n        {\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        vector (\n            const vector<U,2>& item\n        )\n        {\n            // Do this so that we get the appropriate rounding depending on the relative\n            // type of T and U.\n            vector<T,2> temp(item);\n            x() = temp.x();\n            y() = temp.y();\n            z() = 0;\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const vector<T,2>& item\n        )\n        {\n            x() = item.x();\n            y() = item.y();\n            z() = 0;\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        vector (\n            const vector<U,3>& item\n        )\n        {\n            (*this) = item;\n        }\n\n        // ---------------------------------------\n\n        template <typename EXP>\n        vector ( const matrix_exp<EXP>& m)\n        {\n            (*this) = m;\n        }\n\n        // ---------------------------------------\n\n        template <typename EXP>\n        vector& operator = (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // you can only assign vectors with 3 elements to a dlib::vector<T,3> object\n            COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 3 || EXP::NR*EXP::NC == 0);\n\n            // make sure requires clause is not broken\n            DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 3),\n                \"\\t vector(const matrix_exp& m)\"\n                << \"\\n\\t the given matrix is of the wrong size\"\n                << \"\\n\\t m.nr():   \" << m.nr() \n                << \"\\n\\t m.nc():   \" << m.nc() \n                << \"\\n\\t m.size(): \" << m.size() \n                << \"\\n\\t this: \" << this\n                );\n\n            vector_assign_helper<T, typename EXP::type>::assign(*this, m);\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        vector& operator = (\n            const vector<U,N>& item\n        )\n        {\n            vector_assign_helper<T,U>::assign(*this, item);\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator= (\n            const vector& item\n        )\n        {\n            x() = item.x();\n            y() = item.y();\n            z() = item.z();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        double length(\n        ) const \n        { \n            return std::sqrt((double)(x()*x() + y()*y() + z()*z())); \n        }\n\n        // ---------------------------------------\n\n        double length_squared(\n        ) const \n        { \n            return (double)(x()*x() + y()*y() + z()*z()); \n        }\n\n        // ---------------------------------------\n\n        typename vc_rebind<double,3>::type normalize (\n        ) const \n        {\n            const double tmp = std::sqrt((double)(x()*x() + y()*y() + z()*z()));\n            return vector<double,3> ( x()/tmp,\n                                      y()/tmp,\n                                      z()/tmp\n            );\n        }\n\n        // ---------------------------------------\n\n        T& x (\n        ) \n        { \n            return (*this)(0);\n        }\n\n        // ---------------------------------------\n\n        T& y (\n        ) \n        { \n            return (*this)(1);\n        }\n\n        // ---------------------------------------\n\n        T& z (\n        ) \n        { \n            return (*this)(2);\n        }\n\n        // ---------------------------------------\n\n        const T& x (\n        ) const\n        { \n            return (*this)(0);\n        }\n\n        // ---------------------------------------\n\n        const T& y (\n        ) const \n        { \n            return (*this)(1);\n        }\n\n        // ---------------------------------------\n\n        const T& z (\n        ) const\n        { \n            return (*this)(2);\n        }\n\n        // ---------------------------------------\n\n        T dot (\n            const vector& rhs\n        ) const \n        { \n            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        typename vect_promote<T,U>::type dot (\n            const vector<U,N>& rhs\n        ) const \n        { \n            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        typename vc_rebind_promote<T,U,3>::type cross (\n            const vector<U,N>& rhs\n        ) const\n        {\n            typedef vector<typename vect_promote<T,U>::type,3> ret_type;\n\n            return ret_type (\n                y()*rhs.z() - z()*rhs.y(),\n                z()*rhs.x() - x()*rhs.z(),\n                x()*rhs.y() - y()*rhs.x()\n                );\n        }\n\n        // ---------------------------------------\n\n        vector& operator += (\n            const vector& rhs\n        )\n        {\n            x() += rhs.x();\n            y() += rhs.y();\n            z() += rhs.z();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator -= (\n            const vector& rhs\n        )\n        {\n            x() -= rhs.x();\n            y() -= rhs.y();\n            z() -= rhs.z();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator /= (\n            const T& rhs\n        )\n        {\n            x() /= rhs;\n            y() /= rhs;\n            z() /= rhs;\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator *= (\n            const T& rhs\n        )\n        {\n            x() *= rhs;\n            y() *= rhs;\n            z() *= rhs;\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector operator - (\n        ) const\n        {\n            return vector(-x(), -y(), -z());\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        typename vc_rebind_promote<T,U,3>::type operator / (\n            const U& val\n        ) const\n        {\n            typedef vector<typename vect_promote<T,U>::type,3> ret_type;\n            return ret_type(x()/val, y()/val, z()/val);\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long NR2>\n        bool operator== (\n            const vector<U,NR2>& rhs\n        ) const\n        {\n            return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long NR2>\n        bool operator!= (\n            const vector<U,NR2>& rhs\n        ) const\n        {\n            return !(*this == rhs);\n        }\n\n        // ---------------------------------------\n\n        void swap (\n            vector& item\n        )\n        {\n            dlib::exchange(x(), item.x());\n            dlib::exchange(y(), item.y());\n            dlib::exchange(z(), item.z());\n        }\n\n        // ---------------------------------------\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class vector<T,2> : public matrix<T,2,1>\n    {\n        /*!\n            INITIAL VALUE\n                - x() == 0\n                - y() == 0\n\n            CONVENTION\n                - (*this)(0) == x() \n                - (*this)(1) == y() \n                - z() == 0\n        !*/\n\n        // This insanity here is to work around a bug in visual studio 8.  \n        template <typename V, long N>\n        struct vc_rebind\n        {\n            typedef vector<V,N> type;\n        };\n            template <typename V, typename U, long N>\n        struct vc_rebind_promote\n        {\n            typedef vector<typename vect_promote<V,U>::type,N> type;\n        };\n\n\n    public:\n\n        typedef T type;\n        \n        vector (\n        ) \n        {\n            x() = 0;\n            y() = 0;\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const T _x,\n            const T _y\n        ) \n        {\n            x() = _x;\n            y() = _y;\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        vector (\n            const vector<U,3>& item\n        )\n        {\n            // Do this so that we get the appropriate rounding depending on the relative\n            // type of T and U.\n            vector<T,3> temp(item);\n            x() = temp.x();\n            y() = temp.y();\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const vector& item\n        ) : matrix<T,2,1>(item)\n        {\n        }\n\n        // ---------------------------------------\n\n        vector (\n            const vector<T,3>& item\n        )\n        {\n            x() = item.x();\n            y() = item.y();\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        vector (\n            const vector<U,2>& item\n        )\n        {\n            (*this) = item;\n        }\n\n        // ---------------------------------------\n\n        template <typename EXP>\n        vector ( const matrix_exp<EXP>& m)\n        {\n            (*this) = m;\n        }\n\n        // ---------------------------------------\n\n        template <typename EXP>\n        vector& operator = (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // you can only assign vectors with 2 elements to a dlib::vector<T,2> object\n            COMPILE_TIME_ASSERT(EXP::NR*EXP::NC == 2 || EXP::NR*EXP::NC == 0);\n\n            // make sure requires clause is not broken\n            DLIB_ASSERT((m.nr() == 1 || m.nc() == 1) && (m.size() == 2),\n                \"\\t vector(const matrix_exp& m)\"\n                << \"\\n\\t the given matrix is of the wrong size\"\n                << \"\\n\\t m.nr():   \" << m.nr() \n                << \"\\n\\t m.nc():   \" << m.nc() \n                << \"\\n\\t m.size(): \" << m.size() \n                << \"\\n\\t this: \" << this\n                );\n\n            vector_assign_helper<T, typename EXP::type>::assign(*this, m);\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        vector& operator = (\n            const vector<U,N>& item\n        )\n        {\n            vector_assign_helper<T,U>::assign(*this, item);\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator= (\n            const vector& item\n        )\n        {\n            x() = item.x();\n            y() = item.y();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        double length(\n        ) const \n        { \n            return std::sqrt((double)(x()*x() + y()*y())); \n        }\n\n        // ---------------------------------------\n\n        double length_squared(\n        ) const \n        { \n            return (double)(x()*x() + y()*y()); \n        }\n\n        // ---------------------------------------\n\n        typename vc_rebind<double,2>::type normalize (\n        ) const \n        {\n            const double tmp = std::sqrt((double)(x()*x() + y()*y()));\n            return vector<double,2> ( x()/tmp,\n                         y()/tmp\n            );\n        }\n\n        // ---------------------------------------\n\n        T& x (\n        ) \n        { \n            return (*this)(0);\n        }\n\n        // ---------------------------------------\n\n        T& y (\n        ) \n        { \n            return (*this)(1);\n        }\n\n        // ---------------------------------------\n\n        const T& x (\n        ) const\n        { \n            return (*this)(0);\n        }\n\n        // ---------------------------------------\n\n        const T& y (\n        ) const \n        { \n            return (*this)(1);\n        }\n\n        // ---------------------------------------\n\n        const T z (\n        ) const\n        {\n            return 0;\n        }\n\n        // ---------------------------------------\n\n        T dot (\n            const vector& rhs\n        ) const \n        { \n            return x()*rhs.x() + y()*rhs.y();\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        typename vect_promote<T,U>::type dot (\n            const vector<U,N>& rhs\n        ) const \n        { \n            return x()*rhs.x() + y()*rhs.y() + z()*rhs.z();\n        }\n\n        // ---------------------------------------\n\n        vector& operator += (\n            const vector& rhs\n        )\n        {\n            x() += rhs.x();\n            y() += rhs.y();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator -= (\n            const vector& rhs\n        )\n        {\n            x() -= rhs.x();\n            y() -= rhs.y();\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator /= (\n            const T& rhs\n        )\n        {\n            x() /= rhs;\n            y() /= rhs;\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector& operator *= (\n            const T& rhs\n        )\n        {\n            x() *= rhs;\n            y() *= rhs;\n            return *this;\n        }\n\n        // ---------------------------------------\n\n        vector operator - (\n        ) const\n        {\n            return vector(-x(), -y());\n        }\n\n        // ---------------------------------------\n\n        template <typename U>\n        typename vc_rebind_promote<T,U,2>::type operator / (\n            const U& val\n        ) const\n        {\n            typedef vector<typename vect_promote<T,U>::type,2> ret_type;\n            return ret_type(x()/val, y()/val);\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long NR2>\n        bool operator== (\n            const vector<U,NR2>& rhs\n        ) const\n        {\n            return x()==rhs.x() && y()==rhs.y() && z()==rhs.z();\n        }\n\n        // ---------------------------------------\n\n        bool operator== (\n            const vector& rhs\n        ) const\n        {\n            return x()==rhs.x() && y()==rhs.y();\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long NR2>\n        bool operator!= (\n            const vector<U,NR2>& rhs\n        ) const\n        {\n            return !(*this == rhs);\n        }\n\n        // ---------------------------------------\n\n        bool operator!= (\n            const vector& rhs\n        ) const\n        {\n            return !(*this == rhs);\n        }\n\n        // ---------------------------------------\n\n        void swap (\n            vector& item\n        )\n        {\n            dlib::exchange(x(), item.x());\n            dlib::exchange(y(), item.y());\n        }\n\n        // ---------------------------------------\n\n        template <typename U, long N>\n        typename vc_rebind_promote<T,U,3>::type cross (\n            const vector<U,N>& rhs\n        ) const\n        {\n            typedef vector<typename vect_promote<T,U>::type,3> ret_type;\n            return ret_type (\n                y()*rhs.z(),\n                - x()*rhs.z(),\n                x()*rhs.y() - y()*rhs.x()\n                );\n        }\n\n        // ---------------------------------------\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,2>::type operator+ (\n        const vector<T,2>& lhs,\n        const vector<U,2>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,2>::type ret_type;\n        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator+ (\n        const vector<T,3>& lhs,\n        const vector<U,3>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z()+rhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator+ (\n        const vector<T,2>& lhs,\n        const vector<U,3>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), rhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator+ (\n        const vector<T,3>& lhs,\n        const vector<U,2>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()+rhs.x(), lhs.y()+rhs.y(), lhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,2>::type operator- (\n        const vector<T,2>& lhs,\n        const vector<U,2>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,2>::type ret_type;\n        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator- (\n        const vector<T,3>& lhs,\n        const vector<U,3>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z()-rhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator- (\n        const vector<T,2>& lhs,\n        const vector<U,3>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), -rhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline const typename vc_rebind_promote<T,U,3>::type operator- (\n        const vector<T,3>& lhs,\n        const vector<U,2>& rhs \n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(lhs.x()-rhs.x(), lhs.y()-rhs.y(), lhs.z());\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (\n        const vector<T,2>& v,\n        const U& s\n    )\n    {\n        typedef typename vc_rebind_promote<T,U,2>::type ret_type;\n        return ret_type(v.x()*s, v.y()*s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,2>::type >::type operator* (\n        const U& s,\n        const vector<T,2>& v\n    )\n    {\n        typedef typename vc_rebind_promote<T,U,2>::type ret_type;\n        return ret_type(v.x()*s, v.y()*s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (\n        const vector<T,3>& v,\n        const U& s\n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(v.x()*s, v.y()*s, v.z()*s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    inline typename disable_if<is_matrix<U>, const typename vc_rebind_promote<T,U,3>::type >::type operator* (\n        const U& s,\n        const vector<T,3>& v\n    )\n    {\n        typedef typename vc_rebind_promote<T,U,3>::type ret_type;\n        return ret_type(v.x()*s, v.y()*s, v.z()*s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T, long NR>\n    inline void swap (\n        vector<T,NR> & a, \n        vector<T,NR> & b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    inline void serialize (\n        const vector<T,3>& item,  \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.x(),out);\n            serialize(item.y(),out);\n            serialize(item.z(),out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type vector\"); \n        }\n    }\n\n    template<typename T>\n    inline void deserialize (\n        vector<T,3>& item,  \n        std::istream& in\n    )\n    {\n        try\n        {\n            deserialize(item.x(),in);\n            deserialize(item.y(),in);\n            deserialize(item.z(),in);\n        }\n        catch (serialization_error& e)\n        { \n            item.x() = 0;\n            item.y() = 0;\n            item.z() = 0;\n            throw serialization_error(e.info + \"\\n   while deserializing object of type vector\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    inline void serialize (\n        const vector<T,2>& item,  \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.x(),out);\n            serialize(item.y(),out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type vector\"); \n        }\n    }\n\n    template<typename T>\n    inline void deserialize (\n        vector<T,2>& item,  \n        std::istream& in\n    )\n    {\n        try\n        {\n            deserialize(item.x(),in);\n            deserialize(item.y(),in);\n        }\n        catch (serialization_error& e)\n        { \n            item.x() = 0;\n            item.y() = 0;\n            throw serialization_error(e.info + \"\\n   while deserializing object of type vector\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T>\n    std::ostream& operator<< (\n        std::ostream& out, \n        const vector<T,3>& item \n    )\n    {\n        out << \"(\" << item.x() << \", \" << item.y() << \", \" << item.z() << \")\";\n        return out;\n    }\n\n    template<typename T>\n    std::istream& operator>>(\n        std::istream& in, \n        vector<T,3>& item \n    )   \n    {\n\n        // eat all the crap up to the '(' \n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n\n        // there should be a '(' if not then this is an error\n        if (in.get() != '(')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n        // eat all the crap up to the first number \n        while (in.peek() == ' ' || in.peek() == '\\t')\n            in.get();\n        in >> item.x();\n\n        if (!in.good())\n            return in;\n              \n        // eat all the crap up to the next number\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == ',')\n            in.get();\n        in >> item.y();\n\n        if (!in.good())\n            return in;\n              \n        // eat all the crap up to the next number\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == ',')\n            in.get();\n        in >> item.z();\n\n        if (!in.good())\n            return in;\n              \n        // eat all the crap up to the ')'\n        while (in.peek() == ' ' || in.peek() == '\\t')\n            in.get();\n\n        // there should be a ')' if not then this is an error\n        if (in.get() != ')')\n            in.setstate(in.rdstate() | std::ios::failbit);\n        return in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n    template<typename T>\n    std::ostream& operator<< (\n        std::ostream& out, \n        const vector<T,2>& item \n    )\n    {\n        out << \"(\" << item.x() << \", \" << item.y() << \")\";\n        return out;\n    }\n\n    template<typename T>\n    std::istream& operator>>(\n        std::istream& in, \n        vector<T,2>& item \n    )   \n    {\n\n        // eat all the crap up to the '(' \n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == '\\r' || in.peek() == '\\n')\n            in.get();\n\n        // there should be a '(' if not then this is an error\n        if (in.get() != '(')\n        {\n            in.setstate(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n        // eat all the crap up to the first number \n        while (in.peek() == ' ' || in.peek() == '\\t')\n            in.get();\n        in >> item.x();\n\n        if (!in.good())\n            return in;\n              \n        // eat all the crap up to the next number\n        while (in.peek() == ' ' || in.peek() == '\\t' || in.peek() == ',')\n            in.get();\n        in >> item.y();\n\n        if (!in.good())\n            return in;\n              \n        // eat all the crap up to the ')'\n        while (in.peek() == ' ' || in.peek() == '\\t')\n            in.get();\n\n        // there should be a ')' if not then this is an error\n        if (in.get() != ')')\n            in.setstate(in.rdstate() | std::ios::failbit);\n        return in;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    typedef vector<long,2> point;\n    typedef vector<double,2> dpoint;\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool is_convex_quadrilateral (\n        const std::array<dpoint,4>& pts\n    )\n    {\n        auto orientation = [&](size_t i)\n        {\n            size_t a = (i+1)%4;\n            size_t b = (i+3)%4;\n            return (pts[a]-pts[i]).cross(pts[b]-pts[i]).z();\n        };\n\n        // If pts has any infinite points then this isn't a valid quadrilateral.\n        for (auto& p : pts)\n        {\n            if (p.x() == std::numeric_limits<double>::infinity())\n                return false;\n            if (p.y() == std::numeric_limits<double>::infinity())\n                return false;\n        }\n\n        double s0 = orientation(0); \n        double s1 = orientation(1); \n        double s2 = orientation(2); \n        double s3 = orientation(3); \n\n        // if all these things have the same sign then it's convex.\n        return (s0>0&&s1>0&&s2>0&&s3>0) || (s0<0&&s1<0&&s2<0&&s3<0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        enum class points_orientation\n        {\n            collinear,\n            clockwise,\n            couter_clockwise,\n        };\n\n        template <typename T>\n        std::enable_if_t<std::is_same<T, point>::value || std::is_same<T, dpoint>::value, points_orientation>\n        find_points_orientation(const T& a, const T& b, const T& c)\n        {\n            const auto v = a.x() * (b.y() - c.y()) + b.x() * (c.y() - a.y()) + c.x() * (a.y() - b.y());\n            if (v < 0) return points_orientation::clockwise;\n            if (v > 0) return points_orientation::couter_clockwise;\n            return points_orientation::collinear;\n        }\n    }\n\n    template <typename T>\n    std::vector<T> find_convex_hull(std::vector<T>& points)\n    {\n        static_assert(std::is_same<T, point>::value || std::is_same<T, dpoint>::value, \"find_convex_hull() only works for 2D dlib::vector types.\");\n        if (points.size() < 3)\n            return {};\n\n        // find the point with the lowest y coordinate, and the left-most in case of ties.\n        const auto p0 = *std::min_element(points.begin(), points.end(), [](const auto& a, const auto& b){\n            return std::make_pair(a.y(), a.x()) < std::make_pair(b.y(), b.x());\n        });\n\n        // sort the points by polar angle in clockwise order\n        std::sort(points.begin(), points.end(), [&p0](const auto& a, const auto& b){\n            switch (impl::find_points_orientation(p0, a, b))\n            {\n                case impl::points_orientation::clockwise:\n                    return true;\n                case impl::points_orientation::couter_clockwise:\n                    return false;\n                case impl::points_orientation::collinear:\n                    return length_squared(p0-a) < length_squared(p0-b);\n                default:\n                    DLIB_CASSERT(false, \"this should be impossible\");\n            }\n        });\n\n        std::vector<T> hull;\n        for (const auto& p : points)\n        {\n            while (hull.size() > 1 &&\n                impl::find_points_orientation(hull.at(hull.size() - 2), hull.back(), p) != impl::points_orientation::clockwise\n            )\n            {\n                hull.pop_back();\n            }\n            hull.push_back(p);\n        }\n        // If all the points were collinear, we'll have only two points in the hull, so we need to clear it.\n        if (hull.size() < 3)\n            hull.clear();\n        return hull;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_of_dpoints\n        >\n    inline double polygon_area (\n        const array_of_dpoints& pts\n    )\n    {\n        if (pts.size() <= 2)\n            return 0;\n\n        double val = 0;\n\n\n        for (size_t i = 1; i < pts.size(); ++i)\n            val += (double)pts[i].x()*pts[i-1].y() - pts[i].y()*pts[i-1].x();\n\n        const size_t end = pts.size()-1;\n        val += (double)pts[0].x()*pts[end].y() - pts[0].y()*pts[end].x();\n\n        return std::abs(val)/2.0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\nnamespace std\n{\n    /*!\n        Define std::less<vector<T,3> > so that you can use vectors in the associative containers.\n    !*/\n    template<typename T>\n    struct less<dlib::vector<T,3> >\n    {\n        typedef dlib::vector<T, 3> first_argument_type;\n        typedef dlib::vector<T, 3> second_argument_type;\n        typedef bool result_type;\n        inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const\n        { \n            if      (a.x() < b.x()) return true;\n            else if (a.x() > b.x()) return false;\n            else if (a.y() < b.y()) return true;\n            else if (a.y() > b.y()) return false;\n            else if (a.z() < b.z()) return true;\n            else if (a.z() > b.z()) return false;\n            else                    return false;\n        }\n    };\n\n    /*!\n        Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.\n    !*/\n    template<typename T>\n    struct less<dlib::vector<T,2> >\n    {\n        typedef dlib::vector<T, 2> first_argument_type;\n        typedef dlib::vector<T, 2> second_argument_type;\n        typedef bool result_type;\n        inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const\n        { \n            if      (a.x() < b.x()) return true;\n            else if (a.x() > b.x()) return false;\n            else if (a.y() < b.y()) return true;\n            else if (a.y() > b.y()) return false;\n            else                    return false;\n        }\n    };\n}\n\n#if defined(_MSC_VER) && _MSC_VER < 1400\n// restore warnings back to their previous settings\n#pragma warning(pop)\n#endif\n\n#endif // DLIB_VECTOr_H_\n\n"
  },
  {
    "path": "dlib/geometry/vector_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_VECTOR_ABSTRACT_\n#ifdef DLIB_VECTOR_ABSTRACT_\n\n#include \"../serialize.h\"\n#include <functional>\n#include <iostream>\n#include \"../matrix/matrix_abstract.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        long NR = 3\n        >\n    class vector : public matrix<T,NR,1>\n    {\n        /*!\n            REQUIREMENTS ON T\n                T should be some object that provides an interface that is \n                compatible with double, float, int, long and the like.\n\n            REQUIREMENTS ON NR\n                NR == 3 || NR == 2\n\n            INITIAL VALUE\n                x() == 0 \n                y() == 0 \n                z() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a three dimensional vector.  If NR == 2 then\n                this object is limited to representing points on the XY plane where\n                Z is set to 0.\n\n                Also note that this object performs the appropriate integer and \n                floating point conversions and promotions when vectors of mixed\n                type are used together.  For example:\n                    vector<int,3> vi;\n                    vector<double,2> vd;\n                    vd + vi == a vector<double,3> object type since that is what\n                               is needed to contain the result of vi+vd without\n                               any loss of information.\n        !*/\n\n    public:\n\n        typedef T type;\n        \n        vector (\n        );\n        /*!\n            ensures\n               - #*this has been properly initialized\n        !*/\n\n        vector (\n            const T _x,\n            const T _y,\n            const T _z\n        );\n        /*!\n            requires\n                - NR == 3\n            ensures\n                - #x() == _x \n                - #y() == _y \n                - #z() == _z \n        !*/\n\n        vector (\n            const T _x,\n            const T _y\n        );\n        /*!\n            requires\n                - NR == 2\n            ensures\n                - #x() == _x \n                - #y() == _y \n                - #z() == 0\n        !*/\n\n        template <typename U, long NRv>\n        vector (\n            const vector<U,NRv>& v\n        );\n        /*!\n            ensures\n                - Initializes *this with the contents of v and does any rounding if necessary and also \n                  takes care of converting between 2 and 3 dimensional vectors.\n                - if (U is a real valued type like float or double and T is an integral type like long) then\n                    - if (NR == 3) then\n                        - #x() == floor(v.x() + 0.5)\n                        - #y() == floor(v.y() + 0.5)\n                        - #z() == floor(v.z() + 0.5)\n                    - else // NR == 2\n                        - #x() == floor(v.x() + 0.5)\n                        - #y() == floor(v.y() + 0.5)\n                        - #z() == 0\n                - else\n                    - if (NR == 3) then\n                        - #x() == v.x() \n                        - #y() == v.y() \n                        - #z() == v.z() \n                    - else // NR == 2\n                        - #x() == v.x() \n                        - #y() == v.y() \n                        - #z() == 0\n        !*/\n\n        template <typename EXP>\n        vector ( \n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - m.size() == NR\n                - m.nr() == 1 || m.nc() == 1 (i.e. m must be a row or column matrix)\n            ensures\n                - Initializes *this with the contents of m and does any rounding if necessary and also \n                  takes care of converting between 2 and 3 dimensional vectors.\n                - if (m contains real valued values like float or double and T is an integral type like long) then\n                    - #x() == floor(m(0) + 0.5)\n                    - #y() == floor(m(1) + 0.5)\n                    - if (NR == 3) then\n                        - #z() == floor(m(2) + 0.5)\n                    - else\n                        - #z() == 0\n                - else\n                    - #x() == m(0)\n                    - #y() == m(1)\n                    - if (NR == 3) then\n                        - #z() == m(2)\n                    - else\n                        - #z() == 0\n        !*/\n\n        ~vector (\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n\n        double length(\n        ) const;\n        /*!\n            ensures\n                - returns the length of the vector\n        !*/\n\n        double length_squared(\n        ) const;\n        /*!\n            ensures\n                - returns length()*length() \n        !*/\n\n        T& x (\n        );\n        /*!\n            ensures\n                - returns a reference to the x component of the vector\n        !*/\n\n        T& y (\n        );\n        /*!\n            ensures\n                - returns a reference to the y component of the vector\n        !*/\n\n        T& z (\n        );\n        /*!\n            requires\n                - NR == 3 (this function actually doesn't exist when NR != 3)\n            ensures\n                - returns a reference to the z component of the vector\n        !*/\n\n        const T& x (\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the x component of the vector\n        !*/\n\n        const T& y (\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the y component of the vector\n        !*/\n\n        const T& z (\n        ) const;\n        /*!\n            ensures\n                - if (NR == 3) then\n                    - returns a const reference to the z component of the vector\n                - else\n                    - return 0\n                      (there isn't really a z in this case so we just return 0)\n        !*/\n\n        T dot (\n            const vector& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of the dot product between *this and rhs\n        !*/\n\n        vector<T,3> cross (\n            const vector& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of the cross product between *this and rhs\n        !*/\n\n        vector<double,NR> normalize (\n        ) const;\n        /*!\n            ensures\n                - returns a vector with length() == 1 and in the same direction as *this\n        !*/\n\n        vector operator+ (\n            const vector& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of adding *this to rhs\n        !*/\n\n        vector operator- (\n            const vector& rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of subtracting rhs from *this\n        !*/\n\n        vector operator- (\n        ) const;\n        /*!\n            ensures\n                - returns -1*(*this) \n        !*/\n\n        vector operator/ (\n            const T rhs\n        ) const;\n        /*!\n            ensures\n                - returns the result of dividing *this by rhs \n        !*/\n\n        vector& operator= (\n            const vector& rhs\n        );\n        /*!\n            ensures\n                - #x() == rhs.x() \n                - #y() == rhs.y() \n                - #z() == rhs.z()\n                - returns #*this\n        !*/\n\n        vector& operator += (\n            const vector& rhs\n        );\n        /*!\n            ensures\n                - #*this == *this + rhs\n                - returns #*this\n        !*/\n\n        vector& operator -= (\n            const vector& rhs\n        );\n        /*!\n            ensures\n                - #*this == *this - rhs\n                - returns #*this\n        !*/\n\n        vector& operator *= (\n            const T rhs\n        );\n        /*!\n            ensures\n                - #*this == *this * rhs\n                - returns #*this\n        !*/\n\n        vector& operator /= (\n            const T rhs\n        );\n        /*!\n            ensures\n                - #*this == *this / rhs\n                - returns #*this\n        !*/\n\n        template <typename U, long NR2>\n        bool operator== (\n            const vector<U,NR2>& rhs\n        ) const;\n        /*!\n            ensures\n                - if (x() == rhs.x() && y() == rhs.y() && z() == rhs.z()) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        template <typename U, long NR2>\n        bool operator!= (\n            const vector<U,NR2>& rhs\n        ) const;\n        /*!\n            ensures\n                - returns !((*this) == rhs)\n        !*/\n\n        void swap (\n            vector& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename T, typename U, long NR>\n    vector operator* (\n        const vector<T,NR> & lhs,\n        const U rhs\n    );\n    /*!\n        ensures\n            - returns the result of multiplying the scalar rhs by lhs\n    !*/\n    \n    template<typename T, typename U, long NR>\n    vector operator* (\n        const U lhs,\n        const vector<T,NR> & rhs   \n    );\n    /*! \n        ensures\n            - returns the result of multiplying the scalar lhs by rhs\n    !*/\n\n    template<typename T, long NR>\n    inline void swap (\n        vector<T,NR> & a, \n        vector<T,NR> & b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template<typename T, long NR>\n    void serialize (\n        const vector<T,NR>& item, \n        std::ostream& out\n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    template<typename T, long NR>\n    void deserialize (\n        vector<T,NR>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n    template<typename T>\n    std::ostream& operator<< (\n        std::ostream& out, \n        const vector<T,3>& item \n    );   \n    /*!\n        ensures\n            - writes item to out in the form \"(x, y, z)\"\n    !*/\n\n    template<typename T>\n    std::istream& operator>>(\n        std::istream& in, \n        vector<T,3>& item \n    );   \n    /*!\n        ensures\n            - reads a vector from the input stream in and stores it in #item.\n              The data in the input stream should be of the form (x, y, z)\n    !*/\n\n    template<typename T>\n    std::ostream& operator<< (\n        std::ostream& out, \n        const vector<T,2>& item \n    );   \n    /*!\n        ensures\n            - writes item to out in the form \"(x, y)\"\n    !*/\n\n    template<typename T>\n    std::istream& operator>>(\n        std::istream& in, \n        vector<T,2>& item \n    );   \n    /*!\n        ensures\n            - reads a vector from the input stream in and stores it in #item.\n              The data in the input stream should be of the form (x, y)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A point\n        This is just a typedef of the vector object. \n    !*/\n\n    typedef vector<long,2> point;\n\n    /*!A dpoint\n        This is just a typedef of the vector object. \n    !*/\n\n    typedef vector<double,2> dpoint;\n\n// ----------------------------------------------------------------------------------------\n\n    bool is_convex_quadrilateral (\n        const std::array<dpoint,4>& pts\n    );\n    /*!\n        ensures\n            - If you walk the points in pts in order pts[0], pts[1], pts[2], pts[3], pts[0]\n              does it draw a convex quadrilateral?  This routine returns true if yes and\n              false if not.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    std::vector<T> find_convex_hull(\n        std::vector<T>& points\n    );\n    /*!\n        requires\n            - T == dlib::point or dlib::dpoint\n        ensures\n            - If points.size() < 3: it returns an empty vector.\n            - Else: Finds the convex hull of points using the Graham scan algorithm.  That is,\n              the smallest convex shape that contains all points.  Moreover, in case all points\n              are collinear, that is, along the same line, it will also return an empty vector.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_of_dpoints\n        >\n    double polygon_area (\n        const array_of_dpoints& pts\n    );\n    /*!\n        requires\n            - array_of_dpoints is something with an interface compatible with\n              std::vector<dpoint> or std::array<dpoint,N>.\n        ensures\n            - If you walk the points pts in order to make a closed polygon, what is its\n              area?  This function returns that area.  It uses the shoelace formula to\n              compute the result and so works for general non-self-intersecting polygons.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\nnamespace std\n{\n    /*!\n        Define std::less<vector<T,3> > so that you can use vectors in the associative containers.\n    !*/\n    template<typename T>\n    struct less<dlib::vector<T,3> > : public binary_function<dlib::vector<T,3> ,dlib::vector<T,3> ,bool>\n    {\n        inline bool operator() (const dlib::vector<T,3> & a, const dlib::vector<T,3> & b) const\n        { \n            if      (a.x() < b.x()) return true;\n            else if (a.x() > b.x()) return false;\n            else if (a.y() < b.y()) return true;\n            else if (a.y() > b.y()) return false;\n            else if (a.z() < b.z()) return true;\n            else if (a.z() > b.z()) return false;\n            else                    return false;\n        }\n    };\n\n    /*!\n        Define std::less<vector<T,2> > so that you can use vector<T,2>s in the associative containers.\n    !*/\n    template<typename T>\n    struct less<dlib::vector<T,2> > : public binary_function<dlib::vector<T,2> ,dlib::vector<T,2> ,bool>\n    {\n        inline bool operator() (const dlib::vector<T,2> & a, const dlib::vector<T,2> & b) const\n        { \n            if      (a.x() < b.x()) return true;\n            else if (a.x() > b.x()) return false;\n            else if (a.y() < b.y()) return true;\n            else if (a.y() > b.y()) return false;\n            else                    return false;\n        }\n    };\n}\n\n#endif // DLIB_VECTOR_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/geometry.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GEOMETRy_HEADER\n#define DLIB_GEOMETRy_HEADER\n\n#include \"geometry/rectangle.h\"\n#include \"geometry/drectangle.h\"\n#include \"geometry/vector.h\"\n#include \"geometry/border_enumerator.h\"\n#include \"geometry/point_transforms.h\"\n#include \"geometry/line.h\"\n#include \"geometry/polygon.h\"\n\n#endif // DLIB_GEOMETRy_HEADER\n\n\n"
  },
  {
    "path": "dlib/global_optimization/find_max_global.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FiND_GLOBAL_MAXIMUM_hH_\n#define DLIB_FiND_GLOBAL_MAXIMUM_hH_\n\n#include \"find_max_global_abstract.h\"\n#include \"global_function_search.h\"\n#include \"../metaprogramming.h\"\n#include <utility>\n#include <chrono>\n#include <memory>\n#include <thread>\n#include <functional>\n#include \"../threads/thread_pool_extension.h\"\n#include \"../statistics/statistics.h\"\n#include \"../enable_if.h\"\n\nnamespace dlib\n{\n    namespace gopt_impl\n    {\n\n    // ----------------------------------------------------------------------------------------\n\n        class disable_decay_to_scalar \n        {\n            const matrix<double,0,1>& a;\n        public:\n            disable_decay_to_scalar(const matrix<double,0,1>& a) : a(a){}\n            operator const matrix<double,0,1>&() const { return a;}\n        };\n\n\n        template <typename T, size_t... indices> \n        auto _cwv (\n            T&& f, \n            const matrix<double,0,1>& a, \n            std::index_sequence<indices...>\n        ) -> decltype(f(a(indices)...)) \n        {\n            DLIB_CASSERT(a.size() == sizeof...(indices), \n                \"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'. \"\n                << \"Expected \" << sizeof...(indices) << \" arguments but got \" << a.size() << \".\"\n            );  \n            return f(a(indices)...); \n        }\n\n        // Visual studio, as of November 2017, doesn't support C++11 and can't compile this code.  \n        // 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.\n#ifndef _MSC_VER \n        template <size_t max_unpack>\n        struct call_function_and_expand_args\n        {\n            template <typename T>\n            static auto go(T&& f, const matrix<double,0,1>& a) -> decltype(_cwv(std::forward<T>(f),a,std::make_index_sequence<max_unpack>{}))\n            {\n                return _cwv(std::forward<T>(f),a, std::make_index_sequence<max_unpack>{});\n            }\n\n            template <typename T>\n            static auto go(T&& f, const matrix<double,0,1>& a) -> decltype(call_function_and_expand_args<max_unpack-1>::template go<T>(std::forward<T>(f),a))\n            {\n                return call_function_and_expand_args<max_unpack-1>::go(std::forward<T>(f),a);\n            }\n        };\n\n        template <>\n        struct call_function_and_expand_args<0>\n        {\n            template <typename T>\n            static auto go(T&& f, const matrix<double,0,1>& a) -> decltype(f(disable_decay_to_scalar(a)))\n            {\n                return f(disable_decay_to_scalar(a));\n            }\n        };\n#else\n        template <size_t max_unpack>\n        struct call_function_and_expand_args\n        {         \ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& a) -> decltype(f(disable_decay_to_scalar(a)))  {return f(disable_decay_to_scalar(a));   }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& a) -> decltype(f(a(0))) { DLIB_CASSERT(a.size() == 1); return f(a(0)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& a) -> decltype(f(a(0),a(1))) { DLIB_CASSERT(a.size() == 2); return f(a(0),a(1)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& a) -> decltype(f(a(0), a(1), a(2))) { DLIB_CASSERT(a.size() == 3); return f(a(0), a(1),a(2)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& 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)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& 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)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& 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)); }\ntemplate <typename T> static auto go(T&& f, const matrix<double, 0, 1>& 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)); }\n        };\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T> \n    auto call_function_and_expand_args(\n        T&& f, \n        const matrix<double,0,1>& a\n    ) -> decltype(gopt_impl::call_function_and_expand_args<40>::go(f,a))\n    {\n        // unpack up to 40 parameters when calling f()\n        return gopt_impl::call_function_and_expand_args<40>::go(std::forward<T>(f),a);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct max_function_calls\n    {\n        max_function_calls() = default;\n        explicit max_function_calls(size_t max_calls) : max_calls(max_calls) {}\n        size_t max_calls = std::numeric_limits<size_t>::max();\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const auto FOREVER = std::chrono::hours(24*365*200); // 200 years\n    using stop_condition = std::function<bool(double)>;\n    const stop_condition never_stop_early = [](double) { return false; };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename funct\n            >\n        std::pair<size_t,function_evaluation> find_max_global (\n            double ymult,\n            thread_pool& tp,\n            std::vector<funct>& functions,\n            std::vector<function_spec> specs,\n            const max_function_calls num,\n            const std::chrono::nanoseconds max_runtime = FOREVER,\n            double solver_epsilon = 0,\n            std::vector<std::vector<function_evaluation>> initial_function_evals = {},\n            stop_condition should_stop = never_stop_early\n        ) \n        {\n            // Decide which parameters should be searched on a log scale.  Basically, it's\n            // common for machine learning models to have parameters that should be searched on\n            // a log scale (e.g. SVM C).  These parameters are usually identifiable because\n            // they have bounds like [1e-5 1e10], that is, they span a very large range of\n            // magnitudes from really small to really big.  So there we are going to check for\n            // that and if we find parameters with that kind of bound constraints we will\n            // transform them to a log scale automatically.\n            std::vector<std::vector<bool>> log_scale(specs.size());\n            for (size_t i = 0; i < specs.size(); ++i)\n            {\n                for (long j = 0; j < specs[i].lower.size(); ++j)\n                {\n                    if (!specs[i].is_integer_variable[j] && specs[i].lower(j) > 0 && specs[i].upper(j)/specs[i].lower(j) >= 1000)\n                    {\n                        log_scale[i].push_back(true);\n                        specs[i].lower(j) = std::log(specs[i].lower(j));\n                        specs[i].upper(j) = std::log(specs[i].upper(j));\n                    }\n                    else\n                    {\n                        log_scale[i].push_back(false);\n                    }\n                }\n            }\n\n            if (initial_function_evals.empty()) \n            {\n                initial_function_evals.resize(specs.size());\n            }\n            for (auto& evals : initial_function_evals) {\n                for (auto& eval : evals) {\n                    eval.y *= ymult;\n                }\n            }\n\n            global_function_search opt(specs, {initial_function_evals});\n            opt.set_solver_epsilon(solver_epsilon);\n\n            running_stats_decayed<double> objective_funct_eval_time(functions.size()*5);\n            std::mutex eval_time_mutex;\n\n            using std::chrono::steady_clock;\n            using std::chrono::duration_cast;\n            using std::chrono::nanoseconds;\n            const auto time_to_stop = steady_clock::now() + max_runtime;\n            //atomic<bool> doesn't support .fetch_or, use std::atomic<int> instead\n            std::atomic<int> this_should_stop{false};\n\n            double max_solver_overhead_time = 0;\n\n            // Now run the main solver loop.\n            for (size_t i = 0; i < num.max_calls && steady_clock::now() < time_to_stop && !this_should_stop.load(); ++i)\n            {\n                const auto get_next_x_start_time = steady_clock::now();\n                auto next = std::make_shared<function_evaluation_request>(opt.get_next_x());\n                const auto get_next_x_runtime = steady_clock::now() - get_next_x_start_time;\n\n                auto execute_call = [&functions,&ymult,&log_scale,&eval_time_mutex,&objective_funct_eval_time,next,&should_stop,&this_should_stop]() {\n                    matrix<double,0,1> x = next->x();\n                    // Undo any log-scaling that was applied to the variables before we pass them\n                    // to the functions being optimized.\n                    for (long j = 0; j < x.size(); ++j)\n                    {\n                        if (log_scale[next->function_idx()][j])\n                            x(j) = std::exp(x(j));\n                    }\n                    const auto funct_eval_start = steady_clock::now();\n                    double y = ymult*call_function_and_expand_args(functions[next->function_idx()], x);\n                    const double funct_eval_runtime = duration_cast<nanoseconds>(steady_clock::now() - funct_eval_start).count();\n                    this_should_stop.fetch_or(should_stop(y*ymult));\n                    next->set(y);\n                    \n                    std::lock_guard<std::mutex> lock(eval_time_mutex);\n                    objective_funct_eval_time.add(funct_eval_runtime);\n                };\n\n                tp.add_task_by_value(execute_call);\n\n                std::lock_guard<std::mutex> lock(eval_time_mutex);\n                const double obj_funct_time = objective_funct_eval_time.mean()/std::max(1ul,tp.num_threads_in_pool());\n                const double solver_overhead_time = duration_cast<nanoseconds>(get_next_x_runtime).count();\n                max_solver_overhead_time = std::max(max_solver_overhead_time, solver_overhead_time);\n                // Don't start thinking about the logic below until we have at least 5 objective\n                // function samples for each objective function.  This way we have a decent idea how\n                // fast these things are.  The solver overhead is really small initially so none of\n                // the stuff below really matters in the beginning anyway.\n                if (objective_funct_eval_time.current_n() > functions.size()*5) \n                {\n                    // If calling opt.get_next_x() is taking a long time relative to how long it takes\n                    // to evaluate the objective function then we should spend less time grinding on the\n                    // internal details of the optimizer and more time running the actual objective\n                    // function.  E.g. if we could just run 2x more objective function calls in the same\n                    // amount of time then we should just do that.  The main slowness in the solver is\n                    // from the Monte Carlo sampling, which we can turn down if the objective function\n                    // is really fast to evaluate.  This is because the point of the Monte Carlo part is\n                    // to try really hard to avoid calls to really expensive objective functions.  But\n                    // if the objective function is not expensive then we should just call it.\n                    if (obj_funct_time < solver_overhead_time) \n                    {\n                        // Reduce the amount of Monte Carlo sampling we do.  If it goes low enough\n                        // we will disable it altogether.\n                        const size_t new_val = static_cast<size_t>(std::floor(opt.get_monte_carlo_upper_bound_sample_num()*0.8));\n                        opt.set_monte_carlo_upper_bound_sample_num(std::max<size_t>(1, new_val));\n                        // At this point just disable the upper bounding Monte Carlo search stuff and\n                        // use only pure random search since the objective function is super cheap to\n                        // evaluate, making this more fancy search a waste of time.\n                        if (opt.get_monte_carlo_upper_bound_sample_num() == 1) \n                        {\n                            opt.set_pure_random_search_probability(1);\n                        }\n                    } else if (obj_funct_time > 1.5*max_solver_overhead_time) // Consider reenabling\n                    {\n                        // The Monte Carlo overhead grows over time as the solver accumulates more\n                        // information about the objective function.  So we only want to reenable it\n                        // or make it bigger if the objective function really is more expensive.  So\n                        // we compare to the max solver runtime we have seen so far. If the\n                        // objective function has suddenly gotten more expensive then we start to\n                        // turn the Monte Carlo modeling back on.\n                        const size_t new_val = static_cast<size_t>(std::ceil(opt.get_monte_carlo_upper_bound_sample_num()*1.28));\n                        opt.set_monte_carlo_upper_bound_sample_num(std::min<size_t>(5000, new_val));\n                        // Set this back to its default value.\n                        opt.set_pure_random_search_probability(0.02);\n                    }\n                }\n            }\n            tp.wait_for_all_tasks();\n\n\n            matrix<double,0,1> x;\n            double y;\n            size_t function_idx;\n            opt.get_best_function_eval(x,y,function_idx);\n            // Undo any log-scaling that was applied to the variables before we output them. \n            for (long j = 0; j < x.size(); ++j)\n            {\n                if (log_scale[function_idx][j])\n                    x(j) = std::exp(x(j));\n            }\n            return std::make_pair(function_idx, function_evaluation(x,y/ymult));\n        }\n\n        // This overload allows the order of max_runtime and num to be reversed.\n        template <\n            typename funct,\n            typename ...Args\n            >\n        std::pair<size_t,function_evaluation> find_max_global (\n            double ymult,\n            thread_pool& tp,\n            std::vector<funct>& functions,\n            std::vector<function_spec> specs,\n            const std::chrono::nanoseconds max_runtime,\n            const max_function_calls num,\n            double solver_epsilon = 0,\n            Args&& ...args\n        ) \n        {\n            return find_max_global(ymult, tp, functions, std::move(specs), num, max_runtime, solver_epsilon, std::forward<Args>(args)...);\n        }\n\n        // This overload allows the num argument to be skipped.\n        template <\n            typename funct,\n            typename ...Args\n            >\n        std::pair<size_t,function_evaluation> find_max_global (\n            double ymult,\n            thread_pool& tp,\n            std::vector<funct>& functions,\n            std::vector<function_spec> specs,\n            const std::chrono::nanoseconds max_runtime,\n            double solver_epsilon = 0,\n            Args&& ...args\n        ) \n        {\n            return find_max_global(ymult, tp, functions, std::move(specs), max_function_calls(), max_runtime, solver_epsilon, std::forward<Args>(args)...);\n        }\n\n        // This overload allows the max_runtime argument to be skipped.\n        template <\n            typename funct,\n            typename ...Args\n            >\n        std::pair<size_t,function_evaluation> find_max_global (\n            double ymult,\n            thread_pool& tp,\n            std::vector<funct>& functions,\n            std::vector<function_spec> specs,\n            const max_function_calls num,\n            double solver_epsilon,\n            Args&& ...args\n        ) \n        {\n            return find_max_global(ymult, tp, functions, std::move(specs), num, FOREVER, solver_epsilon, std::forward<Args>(args)...);\n        }\n\n        // This overload makes the thread_pool argument optional.\n        template <\n            typename funct,\n            typename ...Args\n            >\n        std::pair<size_t,function_evaluation> find_max_global (\n            double ymult,\n            std::vector<funct>& functions,\n            Args&& ...args\n        ) \n        {\n            // disabled, don't use any threads\n            thread_pool tp(0);\n\n            return find_max_global(ymult, tp, functions, std::forward<Args>(args)...);\n        }\n\n        // The point of normalize() is to handle some of the overloaded argument types in\n        // find_max_global() instances below and turn them into the argument types expected by\n        // find_max_global() above.\n        template <typename T>\n        const T& normalize(const T& item) \n        {\n            return item;\n        }\n\n        inline std::vector<std::vector<function_evaluation>> normalize(\n            const std::vector<function_evaluation>& initial_function_evals\n        )\n        {\n            return {initial_function_evals};\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    std::pair<size_t,function_evaluation> find_max_global (\n        std::vector<funct>& functions,\n        std::vector<function_spec> specs,\n        Args&& ...args\n    ) \n    {\n        return impl::find_max_global(+1, functions, std::move(specs), std::forward<Args>(args)...);\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    std::pair<size_t,function_evaluation> find_min_global (\n        std::vector<funct>& functions,\n        std::vector<function_spec> specs,\n        Args&& ...args\n    ) \n    {\n        return impl::find_max_global(-1, functions, std::move(specs), std::forward<Args>(args)...);\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    std::pair<size_t,function_evaluation> find_max_global (\n        thread_pool& tp,\n        std::vector<funct>& functions,\n        std::vector<function_spec> specs,\n        Args&& ...args\n    ) \n    {\n        return impl::find_max_global(+1, tp, functions, std::move(specs), std::forward<Args>(args)...);\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    std::pair<size_t,function_evaluation> find_min_global (\n        thread_pool& tp,\n        std::vector<funct>& functions,\n        std::vector<function_spec> specs,\n        Args&& ...args\n    ) \n    {\n        return impl::find_max_global(-1, tp, functions, std::move(specs), std::forward<Args>(args)...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// Overloads that take function objects and simple matrix bounds instead of function_specs.\n    template <\n        typename funct,\n        typename ...Args\n        >\n    function_evaluation find_max_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        Args&& ...args\n    ) \n    {\n        std::vector<funct> functions(1,std::move(f));\n        std::vector<function_spec> specs(1, function_spec(bound1, bound2, is_integer_variable));\n        return find_max_global(functions, std::move(specs), impl::normalize(args)...).second;\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    function_evaluation find_min_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        Args&& ...args\n    ) \n    {\n        std::vector<funct> functions(1,std::move(f));\n        std::vector<function_spec> specs(1, function_spec(bound1, bound2, is_integer_variable));\n        return find_min_global(functions, std::move(specs), impl::normalize(args)...).second;\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    function_evaluation find_max_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        Args&& ...args\n    ) \n    {\n        std::vector<funct> functions(1,std::move(f));\n        std::vector<function_spec> specs(1, function_spec(bound1, bound2, is_integer_variable));\n        return find_max_global(tp, functions, std::move(specs), impl::normalize(args)...).second;\n    }\n\n    template <\n        typename funct,\n        typename ...Args\n        >\n    function_evaluation find_min_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        Args&& ...args\n    ) \n    {\n        std::vector<funct> functions(1,std::move(f));\n        std::vector<function_spec> specs(1, function_spec(bound1, bound2, is_integer_variable));\n        return find_min_global(tp, functions, std::move(specs), impl::normalize(args)...).second;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// overloads that are the same as above, but is_integer_variable defaulted to false for all parameters.\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    typename disable_if<std::is_same<T,std::vector<bool>>, function_evaluation>::type \n    find_max_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        const std::vector<bool> is_integer_variable(bound1.size(),false);\n        return find_max_global(std::move(f), bound1, bound2, is_integer_variable, arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    typename disable_if<std::is_same<T,std::vector<bool>>, function_evaluation>::type \n    find_min_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        const std::vector<bool> is_integer_variable(bound1.size(),false);\n        return find_min_global(std::move(f), bound1, bound2, is_integer_variable, arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    typename disable_if<std::is_same<T,std::vector<bool>>, function_evaluation>::type \n    find_max_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        const std::vector<bool> is_integer_variable(bound1.size(),false);\n        return find_max_global(tp, std::move(f), bound1, bound2, is_integer_variable, arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    typename disable_if<std::is_same<T,std::vector<bool>>, function_evaluation>::type \n    find_min_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        const std::vector<bool> is_integer_variable(bound1.size(),false);\n        return find_min_global(tp, std::move(f), bound1, bound2, is_integer_variable, arg, impl::normalize(args)...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// overloads for a function taking a single scalar.\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    function_evaluation find_max_global (\n        funct f,\n        const double bound1,\n        const double bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        return find_max_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    function_evaluation find_min_global (\n        funct f,\n        const double bound1,\n        const double bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        return find_min_global(std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    function_evaluation find_max_global (\n        thread_pool& tp,\n        funct f,\n        const double bound1,\n        const double bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        return find_max_global(tp, std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), arg, impl::normalize(args)...);\n    }\n\n    template <\n        typename funct,\n        typename T,\n        typename ...Args\n        >\n    function_evaluation find_min_global (\n        thread_pool& tp,\n        funct f,\n        const double bound1,\n        const double bound2,\n        const T& arg,\n        Args&& ...args\n    ) \n    {\n        return find_min_global(tp, std::move(f), matrix<double,0,1>({bound1}), matrix<double,0,1>({bound2}), arg, impl::normalize(args)...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FiND_GLOBAL_MAXIMUM_hH_\n\n"
  },
  {
    "path": "dlib/global_optimization/find_max_global_abstract.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_\n#ifdef DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_\n\n#include \"upper_bound_function_abstract.h\"\n#include \"global_function_search_abstract.h\"\n#include \"../metaprogramming.h\"\n#include \"../matrix.h\"\n#include \"../threads/thread_pool_extension_abstract.h\"\n#include <utility>\n#include <chrono>\n#include <functional>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        > \n    auto call_function_and_expand_args(\n        T&& f, \n        const matrix<double,0,1>& args\n    ) -> decltype(f(args or args expanded out as discussed below));\n    /*!\n        requires\n            - f is a function object with one of the following signatures:\n                auto f(matrix<double,0,1>)\n                auto f(double)\n                auto f(double,double)\n                auto f(double,double,double)\n                ...\n                auto f(double,double,...,double)  // up to 40 double arguments\n            - if (f() explicitly expands its arguments) then \n                - args.size() == the number of arguments taken by f.\n        ensures\n            - This function invokes f() with the given arguments and returns the result.\n              However, the signature of f() is allowed to vary.  In particular, if f()\n              takes a matrix<double,0,1> as a single argument then this function simply\n              calls f(args).  However, if f() takes double arguments then args is expanded\n              appropriately, i.e. it calls one of the following as appropriate: \n                f(args(0))\n                f(args(0),args(1))\n                ...\n                f(args(0),args(1),...,args(N))\n              and the result of f() is returned.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct max_function_calls\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple typed integer class used to strongly type the \"max number\n                of function calls\" argument to find_max_global() and find_min_global().\n\n        !*/\n\n        max_function_calls() = default;\n\n        explicit max_function_calls(size_t max_calls) : max_calls(max_calls) {}\n\n        size_t max_calls = std::numeric_limits<size_t>::max();\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const auto FOREVER = std::chrono::hours(24*356*200); // 200 years, basically forever\n\n    /*!\n       WHAT THIS OBJECT REPRESENTS\n          A call-back that returns true when the search should stop.\n\n          It is useful when the user either wants to terminate the search based on special knowledge\n          of the function, the user's preferences regarding what is a \"good-enough\" solution, or\n          based on the results of some external process which may have found a solution and this search\n          is no longer required.\n     !*/\n    using stop_condition = std::function<bool(double)>;\n    // The default condition.\n    const stop_condition never_stop_early = [](double) { return false; };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    std::pair<size_t,function_evaluation> find_max_global (\n        thread_pool& tp,\n        std::vector<funct>& functions,\n        const std::vector<function_spec>& specs,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<std::vector<function_evaluation>>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        requires\n            - functions.size() != 0\n            - functions.size() == specs.size()\n            - solver_epsilon >= 0\n            - for all valid i:\n                - functions[i] is a real valued multi-variate function object.  Moreover,\n                  it must be callable via an expression of the form:\n                  call_function_and_expand_args(functions[i], specs.lower).  This means\n                  function[i] should have a signature like one of the following:\n                    double f(matrix<double,0,1>)\n                    double f(double)\n                    double f(double,double)\n                    etc.\n                - The range of inputs defined by specs[i] must be valid inputs to\n                  functions[i].\n            - if (tp.num_threads_in_pool() != 0) then\n                - it must be safe to call the given functions concurrently from multiple\n                  threads.\n            - initial_function_evals.empty() || initial_function_evals.size() == functions.size()\n            - for all valid i:\n                - for (item : initial_function_evals[i]):\n                    - functions[i](item.x) == item.y\n                      i.e. initial_function_evals contains a record of evaluations of the given\n                      functions.\n        ensures\n            - This function performs global optimization on the set of given functions.\n              The goal is to maximize the following objective function:\n                 max_{i,x_i}: functions[i](x_i)\n                 subject to the constraints on x_i defined by specs[i].\n              Once found, the return value of find_max_global() is:\n                make_pair(i, function_evaluation(x_i,functions[i](x_i))). \n              That is, we search for the settings of i and x that return the largest output\n              and return those settings.\n            - The search is performed using the global_function_search object.  See its\n              documentation for details of the algorithm.\n            - We set the global_function_search::get_solver_epsilon() parameter to\n              solver_epsilon.  Therefore, the search will only attempt to find a global\n              maximizer to at most solver_epsilon accuracy.  Once a local maximizer is\n              found to that accuracy the search will focus entirely on finding other maxima\n              elsewhere rather than on further improving the current local optima found so\n              far.  That is, once a local maxima is identified to about solver_epsilon\n              accuracy, the algorithm will spend all its time exploring the functions to\n              find other local maxima to investigate.  An epsilon of 0 means it will keep\n              solving until it reaches full floating point precision.  Larger values will\n              cause it to switch to pure global exploration sooner and therefore might be\n              more effective if your objective function has many local maxima and you don't\n              care about a super high precision solution.\n            - find_max_global() runs until one of the following is true:\n                - The total number of calls to the provided functions is == num.max_calls\n                - More than max_runtime time has elapsed since the start of this function.\n                - should_stop(f(x)) returns true\n            - Any variables that satisfy the following conditions are optimized on a log-scale:\n                - The lower bound on the variable is > 0\n                - The ratio of the upper bound to lower bound is >= 1000\n                - The variable is not an integer variable\n              We do this because it's common to optimize machine learning models that have\n              parameters with bounds in a range such as [1e-5 to 1e10] (e.g. the SVM C\n              parameter) and it's much more appropriate to optimize these kinds of\n              variables on a log scale.  So we transform them by applying std::log() to\n              them and then undo the transform via std::exp() before invoking the function\n              being optimized.  Therefore, this transformation is invisible to the user\n              supplied functions.  In most cases, it improves the efficiency of the\n              optimizer.\n            - The evaluations in initial_function_evals are incorporated into the solver state at\n              startup.  This is useful if you have information from a previous optimization attempt\n              or just know some good initial x values that should be attempted as a baseline.\n              Giving initial_function_evals allows you to tell the solver to explicitly include\n              those x values in its search.\n            - if (tp.num_threads_in_pool() != 0) then\n                - This function will make concurrent calls to the given functions.  In\n                  particular, it will submit the calls to the functions as jobs to the\n                  given thread_pool tp.\n    !*/\n\n    template <\n        typename funct\n        >\n    std::pair<size_t,function_evaluation> find_max_global (\n        std::vector<funct>& functions,\n        const std::vector<function_spec>& specs,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<std::vector<function_evaluation>>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        this function is identical to the find_max_global() defined immediately above,\n        except that no threading is used.\n    !*/\n\n    template <\n        typename funct\n        >\n    std::pair<size_t,function_evaluation> find_min_global (\n        std::vector<funct>& functions,\n        const std::vector<function_spec>& specs,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<std::vector<function_evaluation>>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        This function is identical to the find_max_global() defined immediately above,\n        except that we perform minimization rather than maximization.\n    !*/\n\n    template <\n        typename funct\n        >\n    std::pair<size_t,function_evaluation> find_min_global (\n        thread_pool& tp,\n        std::vector<funct>& functions,\n        const std::vector<function_spec>& specs,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<std::vector<function_evaluation>>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        This function is identical to the find_max_global() defined immediately above,\n        except that we perform minimization rather than maximization.  We also allow you to\n        give a thread_pool so we can make concurrent calls to the given functions during\n        optimization.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    function_evaluation find_max_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<function_evaluation>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        requires\n            - bound1.size() == bound2.size() == is_integer_variable.size()\n            - for all valid i: bound1(i) != bound2(i)\n            - solver_epsilon >= 0\n            - f() is a real valued multi-variate function object.  Moreover, it must be\n              callable via an expression of the form: call_function_and_expand_args(f,\n              bound1).  This means f() should have a signature like one of the following:\n                double f(matrix<double,0,1>)\n                double f(double)\n                double f(double,double)\n                etc.\n            - The range of inputs defined by function_spec(bound1,bound2,is_integer_variable) \n              must be valid inputs to f().\n            - if (tp.num_threads_in_pool() != 0) then\n                - it must be safe to call the given function f() concurrently from multiple\n                  threads.\n            - for (item : initial_function_evals):\n                - f(item.x) == item.y\n                  i.e. initial_function_evals contains a record of evaluations of f().\n        ensures\n            - This function performs global optimization on the given f() function.\n              The goal is to maximize the following objective function:\n                 f(x)\n                 subject to the constraints on x defined by function_spec(bound1,bound2,is_integer_variable).\n              Once found, the return value of find_max_global() is:\n                function_evaluation(x,f(x))). \n              That is, we search for the setting of x that returns the largest output and\n              return that setting.\n            - The search is performed using the global_function_search object.  See its\n              documentation for details of the algorithm.\n            - We set the global_function_search::get_solver_epsilon() parameter to\n              solver_epsilon.  Therefore, the search will only attempt to find a global\n              maximizer to at most solver_epsilon accuracy.  Once a local maximizer is\n              found to that accuracy the search will focus entirely on finding other maxima\n              elsewhere rather than on further improving the current local optima found so\n              far.  That is, once a local maxima is identified to about solver_epsilon\n              accuracy, the algorithm will spend all its time exploring the function to\n              find other local maxima to investigate.  An epsilon of 0 means it will keep\n              solving until it reaches full floating point precision.  Larger values will\n              cause it to switch to pure global exploration sooner and therefore might be\n              more effective if your objective function has many local maxima and you don't\n              care about a super high precision solution.\n            - find_max_global() runs until one of the following is true:\n                - The total number of calls to f() is == num.max_calls\n                - More than max_runtime time has elapsed since the start of this function.\n                - should_stop(f(x)) returns true\n            - Any variables that satisfy the following conditions are optimized on a log-scale:\n                - The lower bound on the variable is > 0\n                - The ratio of the upper bound to lower bound is >= 1000\n                - The variable is not an integer variable\n              We do this because it's common to optimize machine learning models that have\n              parameters with bounds in a range such as [1e-5 to 1e10] (e.g. the SVM C\n              parameter) and it's much more appropriate to optimize these kinds of\n              variables on a log scale.  So we transform them by applying std::log() to\n              them and then undo the transform via std::exp() before invoking the function\n              being optimized.  Therefore, this transformation is invisible to the user\n              supplied functions.  In most cases, it improves the efficiency of the\n              optimizer.\n            - The evaluations in initial_function_evals are incorporated into the solver state at\n              startup.  This is useful if you have information from a previous optimization attempt\n              of f(x) or just know some good initial x values that should be attempted as a\n              baseline.  Giving initial_function_evals allows you to tell the solver to explicitly\n              include those x values in its search.\n            - if (tp.num_threads_in_pool() != 0) then\n                - This function will make concurrent calls to the given function f().  In\n                  particular, it will submit the calls to f() as jobs to the given\n                  thread_pool tp.\n    !*/\n\n    template <\n        typename funct\n        >\n    function_evaluation find_min_global (\n        thread_pool& tp,\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<function_evaluation>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        This function is identical to the find_max_global() defined immediately above,\n        except that we perform minimization rather than maximization.\n    !*/\n\n    template <\n        typename funct\n        >\n    function_evaluation find_max_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<function_evaluation>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        This function is identical to the find_max_global() defined immediately above,\n        except that we don't take a thread_pool and therefore don't make concurrent calls\n        to f().\n    !*/\n\n    template <\n        typename funct\n        >\n    function_evaluation find_min_global (\n        funct f,\n        const matrix<double,0,1>& bound1,\n        const matrix<double,0,1>& bound2,\n        const std::vector<bool>& is_integer_variable,\n        const max_function_calls num,\n        const std::chrono::nanoseconds max_runtime = FOREVER,\n        double solver_epsilon = 0,\n        const std::vector<function_evaluation>& initial_function_evals = {},\n        stop_condition should_stop = never_stop_early\n    );\n    /*!\n        This function is identical to the find_min_global() defined immediately above,\n        except that we don't take a thread_pool and therefore don't make concurrent calls\n        to f().\n    !*/\n\n// Finally, there are a bunch of overloads of find_min_global() and find_max_global() that make do\n// the following for you:\n//   - They make is_integer_variable optional.  If you don't provide it then we assume no parameters\n//     are integers.\n//   - The order of num and max_runtime can be exchanged.  You can also leave one of these arguments\n//     out so long as you provide the other.\n//   - If f() takes just a single double then bound1 and bound2 can also just be doubles.\n\n}\n\n#endif // DLIB_FiND_GLOBAL_MAXIMUM_ABSTRACT_hH_\n\n\n"
  },
  {
    "path": "dlib/global_optimization/global_function_search.cpp",
    "content": "\n#include \"global_function_search.h\"\n#include \"upper_bound_function.h\"\n#include \"../optimization.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace qopt_impl\n    {\n        void fit_quadratic_to_points_mse(\n            const matrix<double>& X,\n            const matrix<double,0,1>& Y,\n            matrix<double>& H,\n            matrix<double,0,1>& g,\n            double& c\n        )\n        {\n            DLIB_CASSERT(X.size() > 0);\n            DLIB_CASSERT(X.nc() == Y.size());\n            DLIB_CASSERT(X.nc() >= (X.nr()+1)*(X.nr()+2)/2);\n\n            const long dims = X.nr();\n            const long M = X.nc();\n\n            matrix<double> W((X.nr()+1)*(X.nr()+2)/2, M);\n\n            set_subm(W, 0,0, dims, M) = X;\n            set_subm(W, dims,0, 1, M) = 1;\n            for (long c = 0; c < X.nc(); ++c)\n            {\n                long wr = dims+1;\n                for (long r = 0; r < X.nr(); ++r)\n                {\n                    for (long r2 = r; r2 < X.nr(); ++r2)\n                    {\n                        W(wr,c) = X(r,c)*X(r2,c);\n                        if (r2 == r)\n                            W(wr,c) *= 0.5;\n                        ++wr;\n                    }\n                }\n            }\n\n            matrix<double,0,1> z = pinv(trans(W))*Y;\n\n            c = z(dims);\n            g = rowm(z, range(0,dims-1));\n\n            H.set_size(dims,dims);\n\n            long wr = dims+1;\n            for (long r = 0; r < X.nr(); ++r)\n            {\n                for (long r2 = r; r2 < X.nr(); ++r2)\n                {\n                    H(r,r2) = H(r2,r) = z(wr++);\n                }\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void fit_quadratic_to_points(\n            const matrix<double>& X,\n            const matrix<double,0,1>& Y,\n            matrix<double>& H,\n            matrix<double,0,1>& g,\n            double& c\n        )\n        /*!\n            requires\n                - X.size() > 0\n                - X.nc() == Y.size()\n                - X.nr()+1 <= X.nc()      \n            ensures\n                - This function finds a quadratic function, Q(x), that interpolates the\n                  given set of points.  If there aren't enough points to uniquely define\n                  Q(x) then the Q(x) that fits the given points with the minimum Frobenius\n                  norm hessian matrix is selected. \n                - To be precise:\n                    - Let: Q(x) == 0.5*trans(x)*H*x + trans(x)*g + c\n                    - Then this function finds H, g, and c that minimizes the following:\n                        sum(squared(H))\n                      such that:\n                        Q(colm(X,i)) == Y(i),  for all valid i\n                    - If there are more points than necessary to constrain Q then the Q\n                      that best interpolates the function in the mean squared sense is\n                      found.\n        !*/\n        {\n            DLIB_CASSERT(X.size() > 0);\n            DLIB_CASSERT(X.nc() == Y.size());\n            DLIB_CASSERT(X.nr()+1 <= X.nc());\n\n\n            if (X.nc() >= (X.nr()+1)*(X.nr()+2)/2)\n            {\n                fit_quadratic_to_points_mse(X,Y,H,g,c);\n                return;\n            }\n\n\n            const long dims = X.nr();\n            const long M = X.nc();\n\n            /*\n                Our implementation uses the equations 3.9 - 3.12 from the paper:\n                The NEWUOA software for unconstrained optimization without derivatives\n                By M.J.D. Powell, 40th Workshop on Large Scale Nonlinear Optimization (Erice, Italy, 2004)\n            */\n\n            matrix<double> W(M + dims + 1, M + dims + 1);\n\n            set_subm(W, 0, 0, M, M) = 0.5*squared(tmp(trans(X)*X));\n            set_subm(W, 0, M, M, 1) = 1;\n            set_subm(W, M, 0, 1, M) = 1;\n            set_subm(W, M, M, dims+1, dims+1) = 0;\n            set_subm(W, 0, M+1, X.nc(), X.nr()) = trans(X);\n            set_subm(W, M+1, 0, X.nr(), X.nc()) = X;\n\n\n            const matrix<double,0,1> r = join_cols(Y, zeros_matrix<double>(dims+1,1));\n\n            //matrix<double,0,1> z = pinv(W)*r;\n            lu_decomposition<decltype(W)> lu(W);\n            matrix<double,0,1> z = lu.solve(r);\n            //if (lu.is_singular()) std::cout << \"WARNING, THE W MATRIX IS SINGULAR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\" << std::endl;\n\n            matrix<double,0,1> lambda = rowm(z, range(0,M-1));\n\n            c = z(M);\n            g = rowm(z, range(M+1,z.size()-1));\n            H = X*diagm(lambda)*trans(X);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        struct quad_interp_result\n        {\n            quad_interp_result() = default;\n\n            template <typename EXP>\n            quad_interp_result(\n                const matrix_exp<EXP>& best_x,\n                double predicted_improvement\n            ) : best_x(best_x), predicted_improvement(predicted_improvement)  {}\n\n            matrix<double,0,1> best_x;\n            double predicted_improvement = std::numeric_limits<double>::quiet_NaN();\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        quad_interp_result find_max_quadraticly_interpolated_vector (\n            const matrix<double,0,1>& anchor,\n            const double radius,\n            const std::vector<matrix<double,0,1>>& x,\n            const std::vector<double>& y,\n            const matrix<double,0,1>& lower,\n            const matrix<double,0,1>& upper\n        )\n        {\n            DLIB_CASSERT(x.size() == y.size());\n            DLIB_CASSERT(x.size() > 0);\n            for (size_t i = 0; i < x.size(); ++i)\n                DLIB_CASSERT(anchor.size() == x[i].size());\n\n            const long x_size = static_cast<long>(x.size());\n            DLIB_CASSERT(anchor.size()+1 <= x_size && x_size <= (anchor.size()+1)*(anchor.size()+2)/2);\n\n\n            matrix<double> X(anchor.size(), x.size());\n            matrix<double,0,1> Y(x.size());\n            for (size_t i = 0; i < x.size(); ++i)\n            {\n                set_colm(X,i) = x[i] - anchor;\n                Y(i) = y[i];\n            }\n\n            matrix<double> H;\n            matrix<double,0,1> g;\n            double c;\n\n            fit_quadratic_to_points(X, Y, H, g, c);\n\n            matrix<double,0,1> p;\n\n            solve_trust_region_subproblem_bounded(-H,-g, radius, p,  0.001, 500, lower-anchor, upper-anchor);\n\n            // ensure we never move more than radius from the anchor.  This might happen if the\n            // trust region subproblem isn't solved accurately enough.\n            if (length(p) >= radius)\n                p *= radius/length(p);\n\n\n            double predicted_improvement = 0.5*trans(p)*H*p + trans(p)*g;\n            return quad_interp_result{clamp(anchor+p,lower,upper), predicted_improvement};\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        quad_interp_result pick_next_sample_using_trust_region (\n            const std::vector<function_evaluation>& samples,\n            double& radius,\n            const matrix<double,0,1>& lower,\n            const matrix<double,0,1>& upper,\n            const std::vector<bool>& is_integer_variable\n        )\n        {\n            DLIB_CASSERT(samples.size() > 0);\n            // We don't use the QP to optimize integer variables.  Instead, we just fix them at\n            // their best observed value and use the QP to optimize the real variables.  So the\n            // number of dimensions, as far as the QP is concerned, is the number of non-integer\n            // variables.\n            size_t dims = 0;\n            for (auto is_int : is_integer_variable)\n            {\n                if (!is_int)\n                    ++dims;\n            }\n\n            DLIB_CASSERT(samples.size() >= dims+1);\n\n            // Use enough points to fill out a quadratic model or the max available if we don't\n            // have quite enough.\n            const long N = std::min(samples.size(), (dims+1)*(dims+2)/2); \n\n\n            // first find the best sample;\n            double best_val = -1e300;\n            matrix<double,0,1> best_x;\n            for (auto& v : samples)\n            {\n                if (v.y > best_val)\n                {\n                    best_val = v.y;\n                    best_x = v.x;\n                }\n            }\n\n            // if there are only integer variables then there isn't really anything to do.  So just\n            // return the best_x and say there is no improvement.\n            if (dims == 0)\n                return quad_interp_result(best_x, 0);\n\n            matrix<long,0,1> active_dims(dims);\n            long j = 0;\n            for (size_t i = 0; i < is_integer_variable.size(); ++i)\n            {\n                if (!is_integer_variable[i])\n                    active_dims(j++) = i;\n            }\n\n            // now find the N-1 nearest neighbors of best_x\n            std::vector<std::pair<double,size_t>> distances;\n            for (size_t i = 0; i < samples.size(); ++i)\n                distances.emplace_back(length(best_x-samples[i].x), i);\n            std::sort(distances.begin(), distances.end());\n            distances.resize(N);\n\n            std::vector<matrix<double,0,1>> x;\n            std::vector<double> y;\n            for (auto& idx : distances)\n            {\n                x.emplace_back(rowm(samples[idx.second].x, active_dims));\n                y.emplace_back(samples[idx.second].y);\n            }\n\n            if (radius == 0)\n            {\n                for (auto& idx : distances)\n                    radius = std::max(radius, length(rowm(best_x-samples[idx.second].x, active_dims)) );\n                // Shrink the radius a little so we are always going to be making the sampling of\n                // points near the best current point smaller.\n                radius *= 0.95;\n            }\n\n\n            auto tmp = find_max_quadraticly_interpolated_vector(rowm(best_x,active_dims), radius, x, y, rowm(lower,active_dims), rowm(upper,active_dims));\n\n            // stick the integer variables back into the solution\n            for (long i = 0; i < active_dims.size(); ++i)\n                best_x(active_dims(i)) = tmp.best_x(i);\n\n            tmp.best_x = best_x;\n            return tmp;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        matrix<double,0,1> make_random_vector(\n            dlib::rand& rnd,\n            const matrix<double,0,1>& lower,\n            const matrix<double,0,1>& upper,\n            const std::vector<bool>& is_integer_variable\n        )\n        {\n            matrix<double,0,1> temp(lower.size());\n            for (long i = 0; i < temp.size(); ++i)\n            {\n                temp(i) = rnd.get_double_in_range(lower(i), upper(i));\n                if (is_integer_variable[i])\n                    temp(i) = std::round(temp(i));\n            }\n            return temp;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        struct max_upper_bound_function \n        {\n            max_upper_bound_function() = default;\n\n            template <typename EXP>\n            max_upper_bound_function(\n                const matrix_exp<EXP>& x,\n                double predicted_improvement,\n                double upper_bound \n            ) : x(x), predicted_improvement(predicted_improvement), upper_bound(upper_bound)  {}\n\n            matrix<double,0,1> x;\n            double predicted_improvement = 0;\n            double upper_bound = 0;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        max_upper_bound_function pick_next_sample_as_max_upper_bound (\n            dlib::rand& rnd,\n            const upper_bound_function& ub,\n            const matrix<double,0,1>& lower,\n            const matrix<double,0,1>& upper,\n            const std::vector<bool>& is_integer_variable,\n            const size_t num_random_samples \n        )\n        {\n            DLIB_CASSERT(ub.num_points() > 0);\n\n\n\n            // now do a simple random search to find the maximum upper bound\n            double best_ub_so_far = -std::numeric_limits<double>::infinity();\n            matrix<double,0,1> vtemp(lower.size()), v;\n            for (size_t rounds = 0; rounds < num_random_samples; ++rounds)\n            {\n                vtemp = make_random_vector(rnd, lower, upper, is_integer_variable);\n\n                double bound = ub(vtemp);\n                if (bound > best_ub_so_far)\n                {\n                    best_ub_so_far = bound;\n                    v = vtemp;\n                }\n            }\n\n            double max_value = -std::numeric_limits<double>::infinity();\n            for (auto& v : ub.get_points())\n                max_value = std::max(max_value, v.y);\n\n            return max_upper_bound_function(v, best_ub_so_far - max_value, best_ub_so_far);\n        }\n\n    } // end of namespace qopt_impl;\n\n    using namespace qopt_impl;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    function_spec::function_spec(\n        matrix<double,0,1> bound1, \n        matrix<double,0,1> bound2\n    ) : \n        lower(std::move(bound1)), upper(std::move(bound2))\n    {\n        DLIB_CASSERT(lower.size() == upper.size());\n        for (long i = 0; i < lower.size(); ++i)\n        {\n            if (upper(i) < lower(i))\n                std::swap(lower(i), upper(i));\n            DLIB_CASSERT(upper(i) != lower(i), \"The upper and lower bounds can't be equal.\");\n        }\n        is_integer_variable.assign(lower.size(), false);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    function_spec::function_spec(\n        matrix<double,0,1> bound1,\n        matrix<double,0,1> bound2, \n        std::vector<bool> is_integer\n    ) : \n        function_spec(std::move(bound1),std::move(bound2))\n    {\n        is_integer_variable = std::move(is_integer);\n        DLIB_CASSERT(lower.size() == (long)is_integer_variable.size());\n\n\n        // Make sure any integer variables have integer bounds. \n        for (size_t i = 0; i < is_integer_variable.size(); ++i)\n        {\n            if (is_integer_variable[i])\n            {\n                DLIB_CASSERT(std::round(lower(i)) == lower(i), \"If you say a variable is an integer variable then it must have an integer lower bound. \\n\"\n                    << \"lower[i] = \" << lower(i));\n                DLIB_CASSERT(std::round(upper(i)) == upper(i), \"If you say a variable is an integer variable then it must have an integer upper bound. \\n\"\n                    << \"upper[i] = \" << upper(i));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gopt_impl \n    {\n        upper_bound_function funct_info::build_upper_bound_with_all_function_evals (\n        ) const\n        {\n            upper_bound_function tmp(ub);\n\n            // we are going to add the outstanding evals into this and assume the\n            // outstanding evals are going to take y values equal to their nearest\n            // neighbor complete evals.\n            for (auto& eval : outstanding_evals)\n            {\n                function_evaluation e;\n                e.x = eval.x;\n                e.y = find_nn(ub.get_points(), eval.x);\n                tmp.add(e);\n            }\n\n            return tmp;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        double funct_info::find_nn (\n            const std::vector<function_evaluation>& evals,\n            const matrix<double,0,1>& x\n        )\n        {\n            double best_y = 0;\n            double best_dist = std::numeric_limits<double>::infinity();\n            for (auto& v : evals)\n            {\n                double dist = length_squared(v.x-x);\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_y = v.y;\n                }\n            }\n            return best_y;\n        }\n\n    } // end namespace gopt_impl \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    function_evaluation_request::function_evaluation_request(\n        function_evaluation_request&& item\n    )\n    {\n        m_has_been_evaluated = item.m_has_been_evaluated;\n        req = item.req;\n        info = item.info;\n        item.info.reset();\n\n        item.m_has_been_evaluated = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    function_evaluation_request& function_evaluation_request::\n    operator=(\n        function_evaluation_request&& item\n    )\n    {\n        function_evaluation_request(std::move(item)).swap(*this);\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void function_evaluation_request::\n    swap(\n        function_evaluation_request& item\n    )\n    {\n        std::swap(m_has_been_evaluated, item.m_has_been_evaluated);\n        std::swap(req, item.req);\n        std::swap(info, item.info);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    size_t function_evaluation_request::\n    function_idx (\n    ) const\n    {\n        return info->function_idx;\n    }\n\n    const matrix<double,0,1>& function_evaluation_request::\n    x (\n    ) const\n    {\n        return req.x;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool function_evaluation_request::\n    has_been_evaluated (\n    ) const\n    {\n        return m_has_been_evaluated;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    function_evaluation_request::\n    ~function_evaluation_request()\n    {\n        if (!m_has_been_evaluated)\n        {\n            std::lock_guard<std::mutex> lock(*info->m);\n\n            // remove the evaluation request from the outstanding list.\n            auto i = std::find(info->outstanding_evals.begin(), info->outstanding_evals.end(), req);\n            info->outstanding_evals.erase(i);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void function_evaluation_request::\n    set (\n        double y\n    )\n    {\n        DLIB_CASSERT(has_been_evaluated() == false);\n        std::lock_guard<std::mutex> lock(*info->m);\n\n        m_has_been_evaluated = true;\n\n\n        // move the evaluation from outstanding to complete\n        auto i = std::find(info->outstanding_evals.begin(), info->outstanding_evals.end(), req);\n        DLIB_CASSERT(i != info->outstanding_evals.end());\n        info->outstanding_evals.erase(i);\n        info->ub.add(function_evaluation(req.x,y));\n\n\n        // Now do trust region radius maintenance and keep track of the best objective\n        // values and all that.\n        if (req.was_trust_region_generated_request)\n        {\n            // Adjust trust region radius based on how good this evaluation\n            // was.\n            double measured_improvement = y-req.anchor_objective_value;\n            double rho = measured_improvement/std::abs(req.predicted_improvement);\n            //std::cout << \"rho: \"<< rho << std::endl;\n            //std::cout << \"radius: \"<< info->radius << std::endl;\n            if (rho < 0.25)\n                info->radius *= 0.5;\n            else if (rho > 0.75)\n                info->radius *= 2;\n        }\n\n        if (y > info->best_objective_value)\n        {\n            if (!req.was_trust_region_generated_request && length(req.x - info->best_x) > info->radius*1.001)\n            {\n                //std::cout << \"reset radius because of big move, \" << length(req.x - info->best_x) << \"  radius was \" << info->radius << std::endl;\n                // reset trust region radius since we made a big move.  Doing this will\n                // cause the radius to be reset to the size of the local region.\n                info->radius = 0;\n            }\n            info->best_objective_value = y;\n            info->best_x = req.x;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    global_function_search::\n    global_function_search(\n        const function_spec& function\n    ) : global_function_search(std::vector<function_spec>(1,function)) {}\n\n// ----------------------------------------------------------------------------------------\n\n    global_function_search::\n    global_function_search(\n        const std::vector<function_spec>& functions_\n    )\n    {\n        DLIB_CASSERT(functions_.size() > 0);\n        m = std::make_shared<std::mutex>();\n        functions.reserve(functions_.size());\n        for (size_t i = 0; i < functions_.size(); ++i)\n            functions.emplace_back(std::make_shared<gopt_impl::funct_info>(functions_[i],i,m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    global_function_search::\n    global_function_search(\n        const std::vector<function_spec>& functions_,\n        const std::vector<std::vector<function_evaluation>>& initial_function_evals,\n        const double relative_noise_magnitude_\n    ) : \n        global_function_search(functions_) \n    {\n        DLIB_CASSERT(functions_.size() > 0);\n        DLIB_CASSERT(functions_.size() == initial_function_evals.size());\n        DLIB_CASSERT(relative_noise_magnitude_ >= 0);\n        relative_noise_magnitude = relative_noise_magnitude_;\n        for (size_t i = 0; i < initial_function_evals.size(); ++i)\n        {\n            functions[i]->ub = upper_bound_function(initial_function_evals[i], relative_noise_magnitude);\n\n            if (initial_function_evals[i].size() != 0)\n            {\n                auto best = max_scoring_element(initial_function_evals[i], [](const function_evaluation& e) { return e.y; }).first;\n                functions[i]->best_objective_value = best.y;\n                functions[i]->best_x = best.x;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    size_t global_function_search::\n    num_functions(\n    ) const \n    { \n        return functions.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    set_seed (\n        time_t seed\n    )\n    {\n        rnd = dlib::rand(seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    get_function_evaluations (\n        std::vector<function_spec>& specs,\n        std::vector<std::vector<function_evaluation>>& function_evals\n    ) const\n    {\n        std::lock_guard<std::mutex> lock(*m);\n        specs.clear();\n        function_evals.clear();\n        for (size_t i = 0; i < functions.size(); ++i)\n        {\n            specs.emplace_back(functions[i]->spec);\n            function_evals.emplace_back(functions[i]->ub.get_points());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    get_best_function_eval (\n        matrix<double,0,1>& x,\n        double& y,\n        size_t& function_idx\n    ) const\n    {\n        DLIB_CASSERT(num_functions() != 0);\n\n        std::lock_guard<std::mutex> lock(*m);\n\n        // find the largest value\n        auto& info = *best_function(function_idx);\n        y = info.best_objective_value;\n        x = info.best_x;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    function_evaluation_request global_function_search::\n    get_next_x (\n    ) \n    {\n        DLIB_CASSERT(num_functions() != 0);\n\n        using namespace gopt_impl;\n\n        std::lock_guard<std::mutex> lock(*m);\n\n\n        // the first thing we do is make sure each function has at least max(3,dimensionality of function) evaluations\n        for (auto& info : functions)\n        {\n            const long dims = info->spec.lower.size();\n            // If this is the very beginning of the optimization process\n            if (info->ub.num_points()+info->outstanding_evals.size() < 1)\n            {\n                outstanding_function_eval_request new_req;\n                new_req.request_id = next_request_id++;\n                // Pick the point right in the center of the bounds to evaluate first since\n                // people will commonly center the bound on a location they think is good.\n                // So might as well try there first.\n                new_req.x = (info->spec.lower + info->spec.upper)/2.0;\n                for (long i = 0; i < new_req.x.size(); ++i)\n                {\n                    if (info->spec.is_integer_variable[i])\n                        new_req.x(i) = std::round(new_req.x(i));\n                }\n                info->outstanding_evals.emplace_back(new_req);\n                return function_evaluation_request(new_req,info);\n            }\n            else if (info->ub.num_points() < std::max<long>(3,dims))\n            {\n                outstanding_function_eval_request new_req;\n                new_req.request_id = next_request_id++;\n                new_req.x = make_random_vector(rnd, info->spec.lower, info->spec.upper, info->spec.is_integer_variable);\n                info->outstanding_evals.emplace_back(new_req);\n                return function_evaluation_request(new_req,info);\n            }\n        }\n\n\n        if (do_trust_region_step && !has_outstanding_trust_region_request())\n        {\n            // find the currently best performing function, we will do a trust region\n            // step on it.\n            auto info = best_function();\n            const long dims = info->spec.lower.size();\n            // if we have enough points to do a trust region step\n            if (info->ub.num_points() > dims+1)\n            {\n                auto tmp = pick_next_sample_using_trust_region(info->ub.get_points(),\n                    info->radius, info->spec.lower, info->spec.upper, info->spec.is_integer_variable);\n                //std::cout << \"QP predicted improvement: \"<< tmp.predicted_improvement << std::endl;\n                if (tmp.predicted_improvement > min_trust_region_epsilon)\n                {\n                    do_trust_region_step = false;\n                    outstanding_function_eval_request new_req;\n                    new_req.request_id = next_request_id++;\n                    new_req.x = tmp.best_x;\n                    new_req.was_trust_region_generated_request = true;\n                    new_req.anchor_objective_value = info->best_objective_value;\n                    new_req.predicted_improvement = tmp.predicted_improvement;\n                    info->outstanding_evals.emplace_back(new_req);\n                    return function_evaluation_request(new_req, info);\n                }\n            }\n        }\n\n        // make it so we alternate between upper bounded and trust region steps.\n        do_trust_region_step = true;\n\n        if (rnd.get_random_double() >= pure_random_search_probability)\n        {\n            // pick a point at random to sample according to the upper bound\n            double best_upper_bound = -std::numeric_limits<double>::infinity();\n            std::shared_ptr<funct_info> best_funct;\n            matrix<double,0,1> next_sample;\n            // so figure out if any function has a good upper bound and if so pick the\n            // function with the largest upper bound for evaluation.\n            for (auto& info : functions)\n            {\n                auto tmp = pick_next_sample_as_max_upper_bound(rnd,\n                    info->build_upper_bound_with_all_function_evals(), info->spec.lower, info->spec.upper,\n                    info->spec.is_integer_variable,  num_random_samples);\n                if (tmp.predicted_improvement > 0 && tmp.upper_bound > best_upper_bound) \n                {\n                    best_upper_bound = tmp.upper_bound;\n                    next_sample = std::move(tmp.x);\n                    best_funct = info;\n                }\n            }\n\n            // if we found a good function to evaluate then return that. \n            if (best_funct)\n            {\n                outstanding_function_eval_request new_req;\n                new_req.request_id = next_request_id++;\n                new_req.x = std::move(next_sample);\n                best_funct->outstanding_evals.emplace_back(new_req);\n                return function_evaluation_request(new_req, best_funct);\n            }\n        }\n\n\n        // pick entirely at random\n        size_t function_idx = rnd.get_integer(functions.size());\n        auto info = functions[function_idx];\n        outstanding_function_eval_request new_req;\n        new_req.request_id = next_request_id++;\n        new_req.x = make_random_vector(rnd, info->spec.lower, info->spec.upper, info->spec.is_integer_variable);\n        info->outstanding_evals.emplace_back(new_req);\n        return function_evaluation_request(new_req, info);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double global_function_search::\n    get_pure_random_search_probability (\n    ) const \n    { \n        return pure_random_search_probability; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    set_pure_random_search_probability (\n        double prob\n    ) \n    {\n        DLIB_CASSERT(0 <= prob && prob <= 1);\n        pure_random_search_probability = prob;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double global_function_search::\n    get_solver_epsilon (\n    ) const \n    { \n        return min_trust_region_epsilon; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    set_solver_epsilon (\n        double eps\n    )\n    {\n        DLIB_CASSERT(0 <= eps);\n        min_trust_region_epsilon = eps;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double global_function_search::\n    get_relative_noise_magnitude (\n    ) const \n    { \n        return relative_noise_magnitude; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    set_relative_noise_magnitude (\n        double value\n    )\n    {\n        DLIB_CASSERT(0 <= value);\n        relative_noise_magnitude = value;\n        if (m)\n        {\n            std::lock_guard<std::mutex> lock(*m);\n            // recreate all the upper bound functions with the new relative noise magnitude\n            for (auto& f : functions)\n                f->ub = upper_bound_function(f->ub.get_points(), relative_noise_magnitude);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    size_t global_function_search::\n    get_monte_carlo_upper_bound_sample_num (\n    ) const \n    { \n        return num_random_samples; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void global_function_search::\n    set_monte_carlo_upper_bound_sample_num (\n        size_t num\n    )\n    {\n        num_random_samples = num;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::shared_ptr<gopt_impl::funct_info> global_function_search::\n    best_function(\n    ) const\n    {\n        size_t idx = 0;\n        return best_function(idx);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::shared_ptr<gopt_impl::funct_info> global_function_search::\n    best_function(\n        size_t& idx\n    ) const\n    {\n        auto compare = [](const std::shared_ptr<gopt_impl::funct_info>& a, const std::shared_ptr<gopt_impl::funct_info>& b) \n            { return a->best_objective_value < b->best_objective_value; };\n\n        auto i = std::max_element(functions.begin(), functions.end(), compare);\n\n        idx = std::distance(functions.begin(),i);\n        return *i;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool global_function_search::\n    has_outstanding_trust_region_request (\n    ) const \n    {\n        for (auto& f : functions)\n        {\n            for (auto& i : f->outstanding_evals)\n            {\n                if (i.was_trust_region_generated_request)\n                    return true;\n            }\n        }\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n"
  },
  {
    "path": "dlib/global_optimization/global_function_search.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GLOBAL_FuNCTION_SEARCH_Hh_\n#define DLIB_GLOBAL_FuNCTION_SEARCH_Hh_\n\n#include \"global_function_search_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include <mutex>\n#include \"../rand.h\"\n#include \"upper_bound_function.h\"\n#include \"../test_for_odr_violations.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct function_spec\n    {\n        function_spec(\n            matrix<double,0,1> bound1, \n            matrix<double,0,1> bound2\n        );\n\n        function_spec(\n            matrix<double,0,1> bound1, \n            matrix<double,0,1> bound2, \n            std::vector<bool> is_integer\n        );\n\n        matrix<double,0,1> lower;\n        matrix<double,0,1> upper;\n        std::vector<bool> is_integer_variable;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gopt_impl \n    {\n        struct outstanding_function_eval_request\n        {\n            size_t request_id = 0;   // unique id for this eval request\n            matrix<double,0,1> x;   // function x to evaluate \n\n            // trust region specific stuff\n            bool was_trust_region_generated_request = false;\n            double predicted_improvement = std::numeric_limits<double>::quiet_NaN();\n            double anchor_objective_value = std::numeric_limits<double>::quiet_NaN(); // objective value at center of TR step\n\n            bool operator==(const outstanding_function_eval_request& item) const { return request_id == item.request_id; }\n        };\n\n        struct funct_info\n        {\n            funct_info() = delete;\n            funct_info(const funct_info&) = delete;\n            funct_info& operator=(const funct_info&) = delete;\n\n            funct_info(\n                const function_spec& spec,\n                size_t function_idx, \n                const std::shared_ptr<std::mutex>& m\n            ) : \n                spec(spec), function_idx(function_idx), m(m)\n            {\n                best_x = zeros_matrix(spec.lower);\n            }\n\n            upper_bound_function build_upper_bound_with_all_function_evals (\n            ) const;\n\n            static double find_nn (\n                const std::vector<function_evaluation>& evals,\n                const matrix<double,0,1>& x\n            );\n\n\n            function_spec spec;\n            size_t function_idx = 0;\n            std::shared_ptr<std::mutex> m;\n            upper_bound_function ub;\n            std::vector<outstanding_function_eval_request> outstanding_evals;\n            matrix<double,0,1> best_x; \n            double best_objective_value = -std::numeric_limits<double>::infinity(); \n            double radius = 0;\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class function_evaluation_request\n    {\n    public:\n\n        function_evaluation_request() = delete;\n        function_evaluation_request(const function_evaluation_request&) = delete;\n        function_evaluation_request& operator=(const function_evaluation_request&) = delete;\n\n\n        function_evaluation_request(function_evaluation_request&& item);\n        function_evaluation_request& operator=(function_evaluation_request&& item);\n\n        ~function_evaluation_request();\n\n        size_t function_idx (\n        ) const;\n\n        const matrix<double,0,1>& x (\n        ) const;\n\n        bool has_been_evaluated (\n        ) const;\n\n        void set (\n            double y\n        );\n\n        void swap(function_evaluation_request& item);\n\n    private:\n\n        friend class global_function_search;\n\n        explicit function_evaluation_request(\n            const gopt_impl::outstanding_function_eval_request& req,\n            const std::shared_ptr<gopt_impl::funct_info>& info\n        ) : req(req), info(info) {}\n\n        bool m_has_been_evaluated = false;\n        gopt_impl::outstanding_function_eval_request req;\n        std::shared_ptr<gopt_impl::funct_info> info;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class global_function_search\n    {\n    public:\n\n        global_function_search() = default;\n\n        explicit global_function_search(\n            const function_spec& function\n        ); \n\n        explicit global_function_search(\n            const std::vector<function_spec>& functions_\n        );\n\n        global_function_search(\n            const std::vector<function_spec>& functions_,\n            const std::vector<std::vector<function_evaluation>>& initial_function_evals,\n            const double relative_noise_magnitude = 0.001\n        ); \n\n        global_function_search(const global_function_search&) = delete;\n        global_function_search& operator=(const global_function_search& item) = delete;\n\n        global_function_search(global_function_search&& item) = default;\n        global_function_search& operator=(global_function_search&& item) = default;\n\n        size_t num_functions(\n        ) const;\n\n        void set_seed (\n            time_t seed\n        );\n\n        void get_function_evaluations (\n            std::vector<function_spec>& specs,\n            std::vector<std::vector<function_evaluation>>& function_evals\n        ) const;\n\n        void get_best_function_eval (\n            matrix<double,0,1>& x,\n            double& y,\n            size_t& function_idx\n        ) const;\n\n        function_evaluation_request get_next_x (\n        ); \n\n        double get_pure_random_search_probability (\n        ) const; \n\n        void set_pure_random_search_probability (\n            double prob\n        );\n\n        double get_solver_epsilon (\n        ) const; \n\n        void set_solver_epsilon (\n            double eps\n        );\n\n        double get_relative_noise_magnitude (\n        ) const; \n\n        void set_relative_noise_magnitude (\n            double value\n        );\n\n        size_t get_monte_carlo_upper_bound_sample_num (\n        ) const; \n\n        void set_monte_carlo_upper_bound_sample_num (\n            size_t num\n        );\n\n    private:\n\n        std::shared_ptr<gopt_impl::funct_info> best_function(\n        ) const;\n\n        std::shared_ptr<gopt_impl::funct_info> best_function(\n            size_t& idx\n        ) const;\n\n        bool has_outstanding_trust_region_request (\n        ) const;\n\n\n        dlib::rand rnd;\n        double pure_random_search_probability = 0.02;\n        double min_trust_region_epsilon = 0;\n        double relative_noise_magnitude = 0.001;\n        size_t num_random_samples = 5000;\n        bool do_trust_region_step = true;\n\n        size_t next_request_id = 1;\n\n        std::vector<std::shared_ptr<gopt_impl::funct_info>> functions;\n        std::shared_ptr<std::mutex> m;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GLOBAL_FuNCTION_SEARCH_Hh_\n\n"
  },
  {
    "path": "dlib/global_optimization/global_function_search_abstract.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_\n#ifdef DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../matrix.h\"\n#include \"upper_bound_function_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct function_spec\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple struct that lets you define the valid inputs to a\n                multivariate function.  It lets you define bound constraints for each\n                variable as well as say if a variable is integer valued or not.  Therefore,\n                an instance of this struct says that a function takes upper.size() input\n                variables, where the ith variable must be in the range [lower(i) upper(i)]\n                and be an integer if is_integer_variable[i]==true.\n        !*/\n\n        function_spec(\n            matrix<double,0,1> bound1, \n            matrix<double,0,1> bound2\n        );\n        /*!\n            requires\n                - bound1.size() == bound2.size()\n                - for all valid i: bound1(i) != bound2(i)\n            ensures\n                - #is_integer_variable.size() == bound1.size()\n                - #lower.size() == bound1.size()\n                - #upper.size() == bound1.size()\n                - for all valid i:\n                    - #is_integer_variable[i] == false\n                    - #lower(i) == min(bound1(i), bound2(i))\n                    - #upper(i) == max(bound1(i), bound2(i))\n        !*/\n\n        function_spec(\n            matrix<double,0,1> lower, \n            matrix<double,0,1> upper, \n            std::vector<bool> is_integer\n        );\n        /*!\n            requires\n                - bound1.size() == bound2.size() == is_integer.size()\n                - for all valid i: bound1(i) != bound2(i)\n            ensures\n                - #is_integer_variable.size() == bound1.size()\n                - #lower.size() == bound1.size()\n                - #upper.size() == bound1.size()\n                - for all valid i:\n                    - #is_integer_variable[i] == is_integer[i] \n                    - #lower(i) == min(bound1(i), bound2(i))\n                    - #upper(i) == max(bound1(i), bound2(i))\n        !*/\n\n        matrix<double,0,1> lower;\n        matrix<double,0,1> upper;\n        std::vector<bool> is_integer_variable;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class function_evaluation_request\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a request, by the global_function_search object, to\n                evaluate a real-valued function and report back the results.  \n\n            THREAD SAFETY\n                You shouldn't let more than one thread touch a function_evaluation_request\n                at the same time.  However, it is safe to send instances of this class to\n                other threads for processing.  This lets you evaluate multiple\n                function_evaluation_requests in parallel.  Any appropriate synchronization\n                with regard to the originating global_function_search instance is handled\n                automatically.\n        !*/\n\n    public:\n\n        // You can't make or copy this object, the only way to get one is from the\n        // global_function_search class via get_next_x().\n        function_evaluation_request() = delete;\n        function_evaluation_request(const function_evaluation_request&) = delete;\n        function_evaluation_request& operator=(const function_evaluation_request&) = delete;\n\n        // You can however move and swap this object.\n        function_evaluation_request(function_evaluation_request&& item);\n        function_evaluation_request& operator=(function_evaluation_request&& item);\n        /*!\n            ensures\n                - *this takes the state of item.  \n                - #item.has_been_evaluated() == true\n        !*/\n\n        ~function_evaluation_request(\n        );\n        /*!\n            ensures\n                - frees all resources associated with this object.  \n                - It's fine to destruct function_evaluation_requests even if they haven't\n                  been evaluated yet. If this happens it will simply be as if the request\n                  was never issued.\n        !*/\n\n        size_t function_idx (\n        ) const;\n        /*!\n            ensures\n                - Returns the function index that identifies which function is to be\n                  evaluated.  \n        !*/\n\n        const matrix<double,0,1>& x (\n        ) const;\n        /*!\n            ensures\n                - returns the input parameters to the function to be evaluated.\n        !*/\n\n        bool has_been_evaluated (\n        ) const;\n        /*!\n            ensures\n                - If this evaluation request is still outstanding then returns false,\n                  otherwise returns true.  That is, if the global_function_search is still\n                  waiting for you report back by calling set() then\n                  has_been_evaluated()==false.\n        !*/\n\n        void set (\n            double y\n        );\n        /*!\n            requires\n                - has_been_evaluated() == false\n            ensures\n                - #has_been_evaluated() == true\n                - Notifies the global_function_search instance that created this object\n                  that when the function_idx()th function is evaluated with x() as input\n                  then the output is y.\n        !*/\n\n        void swap(\n            function_evaluation_request& item\n        );\n        /*!\n            ensures\n                - swaps the state of *this and item\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class global_function_search\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object performs global optimization of a set of user supplied\n                functions.  The goal is to maximize the following objective function:\n                    max_{function_i,x_i}: function_i(x_i)\n                subject to bound constraints on each element of x_i.  Moreover, each\n                element of x_i can be either real valued or integer valued.  Each of the\n                functions can also take a different number of variables.  Therefore, the\n                final result of the optimization tells you which function produced the\n                largest output and what input (i.e. the x value) to that function is\n                necessary to obtain that maximal value.\n\n                Importantly, the global_function_search object does not require the user to\n                supply derivatives.  Moreover, the functions may contain discontinuities,\n                behave stochastically, and have many local maxima.  The global_function_search \n                object will attempt to find the global optima in the face of these challenges.  \n                It is also designed to use as few function evaluations as possible, making\n                it suitable for optimizing functions that are very expensive to evaluate.  \n\n                It does this by alternating between two modes.  A global exploration mode\n                and a local optima refinement mode.  This is accomplished by building and\n                maintaining two models of the objective function:\n                    1. A global model that upper bounds our objective function.  This is a\n                       non-parametric piecewise linear model based on all function\n                       evaluations ever seen by the global_function_search object.  \n                    2. A local quadratic model fit around the best point seen so far.   \n                \n                The optimization procedure therefore looks like this:\n\n                    while(not done) \n                    {\n                        DO GLOBAL EXPLORE STEP:\n                           Find the point that maximizes the upper bounding model since\n                           that is the point with the largest possible improvement in the\n                           objective function.\n\n                           Evaluate the new point and incorporate it into our models.\n\n                        DO LOCAL REFINEMENT STEP:\n                           Find the optimal solution to the local quadratic model.  \n                           \n                           If this point looks like it will improve on the \"best point seen\n                           so far\" by at least get_solver_epsilon() then we evaluate that\n                           point and incorporate it into our models, otherwise we ignore\n                           it.\n                    }\n\n                You can see that we alternate between global search and local refinement,\n                except in the case where the local model seems to have converged to within\n                get_solver_epsilon() accuracy.  In that case only global search steps are\n                used.  We do this in the hope that the global search will find a new and\n                better local optima to explore, which would then reactivate local\n                refinement when it has something productive to do. \n\n                \n                Now let's turn our attention to the specific API defined by the\n                global_function_search object.  We will begin by showing a short example of\n                its use:\n\n                    // Suppose we want to find which of these functions, F() and G(), have\n                    // the largest output and what input is necessary to produce the\n                    // maximal output.\n                    auto F = [](double a, double b) { return  -std::pow(a-2,2.0) - std::pow(b-4,2.0); };\n                    auto G = [](double x)           { return 2-std::pow(x-5,2.0); };\n\n                    // We first define function_spec objects that specify bounds on the\n                    // inputs to each function.  The search process will only search within\n                    // these bounds.\n                    function_spec spec_F({-10,-10}, {10,10});\n                    function_spec spec_G({-2}, {6});\n                    // Then we create a global_function_search object with those function specifications.\n                    global_function_search opt({spec_F, spec_G});\n\n                    // Here we run 15 iterations of the search process.  Note that the user\n                    // of global_function_search writes the main solver loop, which is\n                    // somewhat unusual.  We will discuss why that is in a moment, but for\n                    // now let's look at this example.\n                    for (int i = 0; i < 15; ++i)\n                    {\n                        // All we do here is ask the global_function_search object what to\n                        // evaluate next, then do what it asked, and then report the\n                        // results back by calling function_evaluation_request's set()\n                        // method.  \n                        function_evaluation_request next = opt.get_next_x();\n                        // next.function_idx() tells you which of the functions you should\n                        // evaluate.  We have 2 functions here (F and G) so function_idx()\n                        // can take only the values 0 and 1.  If, for example, we had 10\n                        // functions it would take the values 0 through 9.\n                        if (next.function_idx() == 0)\n                        {\n                            // Call F with the inputs requested by the\n                            // global_function_search and report them back.\n                            double a = next.x()(0);\n                            double b = next.x()(1);\n                            next.set(F(a,b));  // Tell the solver what happened.\n                        }\n                        else\n                        {\n                            double x = next.x()(0);\n                            next.set(G(x));\n                        }\n                    }\n\n                    // Find out what point gave the largest outputs:\n                    matrix<double,0,1> x;\n                    double y;\n                    size_t function_idx;\n                    opt.get_best_function_eval(x,y,function_idx);\n\n                    cout << \"function_idx: \"<< function_idx << endl; \n                    cout << \"y: \" << y << endl; \n                    cout << \"x: \" << x << endl; \n\n                The above cout statements will print this:\n\n                    function_idx: 1\n                    y: 2\n                    x: 5 \n                \n                Which is the correct result since G(5) gives the largest possible output in\n                our example.\n\n                So why does the user write the main loop?  Why isn't it embedded inside\n                dlib?  Well, there are two answers to this.  The first is that it is.  Most\n                users should just call dlib::find_max_global() which does exactly that, it\n                runs the loop for you.  However, the API shown above gives you the\n                opportunity to run multiple function evaluations in parallel.  For\n                instance, it is perfectly valid to call get_next_x() multiple times and\n                send the resulting function_evaluation_request objects to separate threads\n                for processing.  Those separate threads can run the functions being\n                optimized (e.g. F and G or whatever) and report back by calling\n                function_evaluation_request::set().  You could even spread the work across\n                a compute cluster if you have one.  Note that find_max_global() optionally\n                supports this type of parallel execution, however you get more flexibility\n                with the global_function_search's API.  As another example, it's possible\n                to save the state of the solver to disk so you can restart the optimization\n                from that point at a later date when using global_function_search, but not\n                with find_max_global().\n\n                So what happens if you have N outstanding function evaluation requests?\n                Or in other words, what happens if you called get_next_x() N times and\n                haven't yet called their set() methods?  Well, 1 of the N requests will be\n                a local refinement step while the N-1 other requests will be global\n                exploration steps generated from the current upper bounding model.  This\n                should give you an idea of the usefulness of this kind of parallelism.  If\n                for example, your functions being optimized were simple convex functions\n                this kind of parallelism wouldn't help since essentially all the\n                interesting work in the solver is going to be done by the local optimizer.\n                However, if your function has a lot of local optima, running many global\n                exploration steps in parallel might significantly reduce the time it takes\n                to find a good solution.\n                \n                It should also be noted that our upper bounding model is implemented by the\n                dlib::upper_bound_function object, which is a tool that allows us to create\n                a tight upper bound on our objective function.  This upper bound is\n                non-parametric and gets progressively more accurate as the optimization\n                progresses, but also more and more expensive to maintain.  It causes the\n                runtime of the entire optimization procedure to be O(N^2) where N is the\n                number of objective function evaluations. So problems that require millions\n                of function evaluations to find a good solution are not appropriate for the\n                global_function_search tool.  However, if your objective function is very\n                expensive to evaluate then this relatively expensive upper bounding model\n                is well worth its computational cost.\n                \n                Finally, let's introduce some background literature on this algorithm.  The\n                two most relevant papers in the optimization literature are:\n                    Global optimization of Lipschitz functions Malherbe, Cédric and Vayatis,\n                    Nicolas International Conference on Machine Learning - 2017\n                and\n                    The NEWUOA software for unconstrained optimization without derivatives By\n                    M.J.D. Powell, 40th Workshop on Large Scale Nonlinear Optimization (Erice,\n                    Italy, 2004)\n\n                Our upper bounding model is an extension of the AdaLIPO method in the\n                Malherbe.  See the documentation of dlib::upper_bound_function for more\n                details on that, as we make a number of important extensions.  The other\n                part of our method, our local refinement model, is essentially the same\n                type of trust region model proposed by Powell in the above paper.  That is,\n                each time we do a local refinement step we identify the best point seen so\n                far, fit a quadratic function around it using the function evaluations we\n                have collected so far, and then use a simple trust region procedure to\n                decide the next best point to evaluate based on our quadratic model.  \n\n                The method proposed by Malherbe gives excellent global search performance\n                but has terrible convergence properties in the area around a maxima.\n                Powell's method on the other hand has excellent convergence in the area\n                around a local maxima, as expected by a quadratic trust region method, but\n                is aggressively local maxima seeking.  It will simply get stuck in the\n                nearest local optima.  Combining the two together as we do here gives us\n                excellent performance in both global search and final convergence speed\n                near a local optima.  Causing the global_function_search to perform well\n                for functions with many local optima while still giving high precision\n                solutions.  For instance, on typical tests problems, like the Holder table\n                function, the global_function_search object can reliably find the globally\n                optimal solution to full floating point precision in under a few hundred\n                steps.\n\n\n            THREAD SAFETY\n                You shouldn't let more than one thread touch a global_function_search\n                instance at the same time.  \n        !*/\n\n    public:\n\n        global_function_search(\n        );\n        /*!\n            ensures\n                - #num_functions() == 0\n                - #get_relative_noise_magnitude() == 0.001\n                - #get_solver_epsilon() == 0\n                - #get_monte_carlo_upper_bound_sample_num() == 5000\n                - #get_pure_random_search_probability() == 0.02\n        !*/\n\n        explicit global_function_search(\n            const function_spec& function\n        ); \n        /*!\n            ensures\n                - #num_functions() == 1\n                - #get_function_evaluations() will indicate that there are no function evaluations yet.\n                - #get_relative_noise_magnitude() == 0.001\n                - #get_solver_epsilon() == 0\n                - #get_monte_carlo_upper_bound_sample_num() == 5000\n                - #get_pure_random_search_probability() == 0.02\n        !*/\n\n        explicit global_function_search(\n            const std::vector<function_spec>& functions\n        );\n        /*!\n            ensures\n                - #num_functions() == functions.size()\n                - #get_function_evaluations() will indicate that there are no function evaluations yet.\n                - #get_relative_noise_magnitude() == 0.001\n                - #get_solver_epsilon() == 0\n                - #get_monte_carlo_upper_bound_sample_num() == 5000\n                - #get_pure_random_search_probability() == 0.02\n        !*/\n\n        global_function_search(\n            const std::vector<function_spec>& functions,\n            const std::vector<std::vector<function_evaluation>>& initial_function_evals,\n            const double relative_noise_magnitude = 0.001\n        ); \n        /*!\n            requires\n                - functions.size() == initial_function_evals.size()\n                - relative_noise_magnitude >= 0\n            ensures\n                - #num_functions() == functions.size()\n                - #get_function_evaluations() will return the provided initial_function_evals.\n                - #get_relative_noise_magnitude() == relative_noise_magnitude\n                - #get_solver_epsilon() == 0\n                - #get_monte_carlo_upper_bound_sample_num() == 5000\n                - #get_pure_random_search_probability() == 0.02\n        !*/\n\n        // This object can't be copied.\n        global_function_search(const global_function_search&) = delete;\n        global_function_search& operator=(const global_function_search& item) = delete;\n        // But it can be moved\n        global_function_search(global_function_search&& item) = default;\n        global_function_search& operator=(global_function_search&& item) = default;\n        /*!\n            ensures\n                - moves the state of item into *this\n                - #item.num_functions() == 0\n        !*/\n\n        void set_seed (\n            time_t seed\n        );\n        /*!\n            ensures\n                - Part of this object's algorithm uses random sampling to decide what\n                  points to evaluate next.  Calling set_seed() lets you set the seed used\n                  by the random number generator.   Note that if you don't call set_seed()\n                  you will always get the same deterministic behavior.\n        !*/\n\n        size_t num_functions(\n        ) const;\n        /*!\n            ensures\n                - returns the number of functions being optimized.\n        !*/\n\n        void get_function_evaluations (\n            std::vector<function_spec>& specs,\n            std::vector<std::vector<function_evaluation>>& function_evals\n        ) const;\n        /*!\n            ensures\n                - #specs.size() == num_functions()\n                - #function_evals.size() == num_functions()\n                - This function allows you to query the state of the solver.  In\n                  particular, you can find the function_specs for each function being\n                  optimized and their recorded evaluations.  \n                - for all valid i:\n                    - function_evals[i] == all the function evaluations that have been\n                      recorded for the ith function (i.e. the function with the\n                      function_spec #specs[i]).  That is, this is the record of all the x\n                      and y values reported back by function_evaluation_request::set()\n                      calls.\n        !*/\n\n        void get_best_function_eval (\n            matrix<double,0,1>& x,\n            double& y,\n            size_t& function_idx\n        ) const;\n        /*!\n            requires\n                - num_functions() != 0\n            ensures\n                - if (no function evaluations have been recorded yet) then\n                    - The outputs of this function are in a valid but undefined state.\n                - else\n                    - This function tells you which function has produced the largest\n                      output seen so far.  It also tells you the inputs to that function\n                      that leads to those outputs (x) as well as the output value itself (y).\n                    - 0 <= #function_idx < num_functions()\n                    - #function_idx == the index of the function that produced the largest output seen so far.\n                    - #x == the input parameters to the function that produced the largest outputs seen so far.\n                    - #y == the largest output seen so far.\n        !*/\n\n        function_evaluation_request get_next_x (\n        ); \n        /*!\n            requires\n                - num_functions() != 0\n            ensures\n                - Generates and returns a function evaluation request.  See the discussion\n                  in the WHAT THIS OBJECT REPRESENTS section above for details.\n        !*/\n\n        double get_pure_random_search_probability (\n        ) const; \n        /*!\n            ensures\n                - When we decide to do a global explore step we will, with probability\n                  get_pure_random_search_probability(), sample a point completely at random\n                  rather than using the upper bounding model.  Therefore, if you set this\n                  probability to 0 then we will depend entirely on the upper bounding\n                  model.  Alternatively, if you set get_pure_random_search_probability() to\n                  1 then we won't use the upper bounding model at all and instead use pure\n                  random search to do global exploration.  Pure random search is much\n                  faster than using the upper bounding model, so if you know that your\n                  objective function is especially simple it can be faster to use pure\n                  random search.  However, if you really know your function that well you\n                  should probably use a gradient based optimizer :)\n        !*/\n\n        void set_pure_random_search_probability (\n            double prob\n        );\n        /*!\n            requires\n                - prob >= 0\n            ensures\n                - #get_pure_random_search_probability() == prob\n        !*/\n\n        double get_solver_epsilon (\n        ) const; \n        /*!\n            ensures\n                - As discussed in the WHAT THIS OBJECT REPRESENTS section, we only do a\n                  local refinement step if we haven't already found the peak of the current\n                  local optima.  get_solver_epsilon() sets the tolerance for deciding if\n                  the local search method has found the local optima.  Therefore, when the\n                  local trust region model runs we check if its predicted improvement in\n                  the objective function is greater than get_solver_epsilon().  If it isn't\n                  then we assume it has converged and we should focus entirely on global\n                  search.\n\n                  This means that, for instance, setting get_solver_epsilon() to 0\n                  essentially instructs the solver to find each local optima to full\n                  floating point precision and only then to focus on pure global search.\n        !*/\n\n        void set_solver_epsilon (\n            double eps\n        );\n        /*!\n            requires\n                - eps >= 0\n            ensures\n                - #get_solver_epsilon() == eps \n        !*/\n\n        double get_relative_noise_magnitude (\n        ) const; \n        /*!\n            ensures\n                - Returns the value of the relative noise magnitude parameter to the\n                  dlib::upper_bound_function's used by this object.  See the\n                  upper_bound_function's documentation for a detailed discussion of this\n                  parameter's meaning.  Most users should leave this value as its default\n                  setting.\n        !*/\n\n        void set_relative_noise_magnitude (\n            double value\n        );\n        /*!\n            requires\n                - value >= 0\n            ensures\n                - #get_relative_noise_magnitude() == value \n        !*/\n\n        size_t get_monte_carlo_upper_bound_sample_num (\n        ) const; \n        /*!\n            ensures\n                - To find the point that maximizes the upper bounding model we use\n                  get_monte_carlo_upper_bound_sample_num() random evaluations and select\n                  the largest upper bound from that set.   So this parameter influences how\n                  well we estimate the maximum point on the upper bounding model. \n        !*/\n\n        void set_monte_carlo_upper_bound_sample_num (\n            size_t num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_monte_carlo_upper_bound_sample_num() == num \n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GLOBAL_FuNCTION_SEARCH_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/global_optimization/upper_bound_function.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_UPPER_bOUND_FUNCTION_Hh_\n#define DLIB_UPPER_bOUND_FUNCTION_Hh_\n\n#include \"upper_bound_function_abstract.h\"\n#include \"../svm/svm_c_linear_dcd_trainer.h\"\n#include \"../statistics.h\"\n#include <limits>\n#include <utility>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct function_evaluation\n    {\n        function_evaluation() = default;\n        function_evaluation(const matrix<double,0,1>& x, double y) :x(x), y(y) {}\n\n        matrix<double,0,1> x;\n        double y = std::numeric_limits<double>::quiet_NaN();\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class upper_bound_function\n    {\n\n    public:\n\n        upper_bound_function(\n        ) = default;\n\n        upper_bound_function(\n            const double relative_noise_magnitude,\n            const double solver_eps \n        ) : relative_noise_magnitude(relative_noise_magnitude), solver_eps(solver_eps)\n        {\n            DLIB_CASSERT(relative_noise_magnitude >= 0);\n            DLIB_CASSERT(solver_eps > 0);\n        }\n\n        explicit upper_bound_function(\n            const std::vector<function_evaluation>& _points,\n            const double relative_noise_magnitude = 0.001,\n            const double solver_eps = 0.0001\n        ) : relative_noise_magnitude(relative_noise_magnitude), solver_eps(solver_eps), points(_points)\n        {\n            DLIB_CASSERT(relative_noise_magnitude >= 0);\n            DLIB_CASSERT(solver_eps > 0);\n\n            if (points.size() > 1)\n            {\n                DLIB_CASSERT(points[0].x.size() > 0, \"The vectors can't be empty.\");\n\n                const long dims = points[0].x.size();\n                for (auto& p : points)\n                    DLIB_CASSERT(p.x.size() == dims, \"All the vectors given to upper_bound_function must have the same dimensionality.\");\n\n                learn_params();\n            }\n\n        }\n\n        void add (\n            const function_evaluation& point\n        )\n        {\n            DLIB_CASSERT(point.x.size() != 0, \"The vectors can't be empty.\");\n            if (points.size() == 0)\n            {\n                points.push_back(point);\n                return;\n            }\n\n            DLIB_CASSERT(point.x.size() == dimensionality(), \"All the vectors given to upper_bound_function must have the same dimensionality.\");\n\n            if (points.size() < 4)\n            {\n                points.push_back(point);\n                *this = upper_bound_function(points, relative_noise_magnitude, solver_eps);\n                return;\n            }\n\n            points.push_back(point);\n            // add constraints between the new point and the old points\n            for (size_t i = 0; i < points.size()-1; ++i)\n                active_constraints.push_back(std::make_pair(i,points.size()-1));\n\n            learn_params();\n        }\n\n        long num_points(\n        ) const \n        { \n            return points.size(); \n        }\n\n        long dimensionality(\n        ) const\n        { \n            if (points.size() == 0)\n                return 0;\n            else\n                return points[0].x.size();\n        }\n\n        const std::vector<function_evaluation>& get_points(\n        ) const \n        { \n            return points; \n        }\n\n        double operator() (\n            const matrix<double,0,1>& x\n        ) const\n        {\n            DLIB_CASSERT(num_points() > 0);\n            DLIB_CASSERT(x.size() == dimensionality());\n\n\n\n            double upper_bound = std::numeric_limits<double>::infinity();\n\n            for (size_t i = 0; i < points.size(); ++i)\n            {\n                const double local_bound = points[i].y + std::sqrt(offsets[i] + dot(slopes, squared(x-points[i].x)));\n                upper_bound = std::min(upper_bound, local_bound);\n            }\n\n            return upper_bound;\n        }\n\n    private:\n\n        void learn_params (\n        )\n        {\n            const long dims = points[0].x.size();\n\n            using sample_type = std::vector<std::pair<size_t,double>>;\n            using kernel_type = sparse_linear_kernel<sample_type>;\n            std::vector<sample_type> x;\n            std::vector<double> y;\n\n            // We are going to normalize the data so the values aren't extreme.  First, we\n            // collect statistics on our data.\n            std::vector<running_stats<double>> x_rs(dims);\n            running_stats<double> y_rs;\n            for (auto& v : points)\n            {\n                for (long i = 0; i < v.x.size(); ++i)\n                    x_rs[i].add(v.x(i));\n                y_rs.add(v.y);\n            }\n\n\n            // compute normalization vectors for the data.  The only reason we do this is\n            // to make the optimization well conditioned.  In particular, scaling the y\n            // values will prevent numerical errors in the 1-diff*diff computation below that\n            // would otherwise result when diff is really big.  Also, scaling the xvalues\n            // to be about 1 will similarly make the optimization more stable and it also\n            // has the added benefit of keeping the relative_noise_magnitude's scale\n            // constant regardless of the size of x values.\n            const double yscale = 1.0/y_rs.stddev();\n            std::vector<double> xscale(dims);\n            for (size_t i = 0; i < xscale.size(); ++i)\n                xscale[i] = 1.0/(x_rs[i].stddev()*yscale); // make it so that xscale[i]*yscale ==  1/x_rs[i].stddev()\n\n            sample_type samp;\n            auto add_constraint = [&](long i, long j) {\n                samp.clear();\n                for (long k = 0; k < dims; ++k)\n                {\n                    double temp = (points[i].x(k) - points[j].x(k))*xscale[k]*yscale;\n                    samp.push_back(std::make_pair(k, temp*temp));\n                }\n\n                if (points[i].y > points[j].y)\n                    samp.push_back(std::make_pair(dims + j, relative_noise_magnitude));\n                else\n                    samp.push_back(std::make_pair(dims + i, relative_noise_magnitude));\n\n                const double diff = (points[i].y - points[j].y)*yscale;\n                samp.push_back(std::make_pair(dims + points.size(), 1-diff*diff));\n\n                x.push_back(samp);\n                y.push_back(1);\n            };\n\n            if (active_constraints.size() == 0)\n            {\n                x.reserve(points.size()*(points.size()-1)/2);\n                y.reserve(points.size()*(points.size()-1)/2);\n                for (size_t i = 0; i < points.size(); ++i)\n                {\n                    for (size_t j = i+1; j < points.size(); ++j)\n                    {\n                        add_constraint(i,j);\n                    }\n                }\n            }\n            else\n            {\n                for (auto& p : active_constraints)\n                    add_constraint(p.first, p.second);\n            }\n\n\n\n\n            svm_c_linear_dcd_trainer<kernel_type> trainer;\n            trainer.set_c(std::numeric_limits<double>::infinity());\n            //trainer.be_verbose();\n            trainer.force_last_weight_to_1(true);\n            trainer.set_epsilon(solver_eps);\n\n            svm_c_linear_dcd_trainer<kernel_type>::optimizer_state state;\n            auto df = trainer.train(x,y, state);\n\n            // save the active constraints for later so we can use them inside add() to add\n            // new points efficiently.\n            if (active_constraints.size() == 0)\n            {\n                long k = 0;\n                for (size_t i = 0; i < points.size(); ++i)\n                {\n                    for (size_t j = i+1; j < points.size(); ++j)\n                    {\n                        if (state.get_alpha()[k++] != 0)\n                            active_constraints.push_back(std::make_pair(i,j));\n                    }\n                }\n            }\n            else\n            {\n                DLIB_CASSERT(state.get_alpha().size() == active_constraints.size());\n                new_active_constraints.clear();\n                for (size_t i = 0; i < state.get_alpha().size(); ++i)\n                {\n                    if (state.get_alpha()[i] != 0)\n                        new_active_constraints.push_back(active_constraints[i]);\n                }\n                active_constraints.swap(new_active_constraints);\n            }\n\n            //std::cout << \"points.size(): \" << points.size() << std::endl;\n            //std::cout << \"active_constraints.size(): \" << active_constraints.size() << std::endl;\n\n\n            const auto& bv = df.basis_vectors(0);\n            slopes.set_size(dims);\n            for (long i = 0; i < dims; ++i)\n                slopes(i) = bv[i].second*xscale[i]*xscale[i];\n\n            //std::cout << \"slopes:\" << trans(slopes);\n\n            offsets.assign(points.size(),0);\n\n\n            for (size_t i = 0; i < points.size(); ++i)\n            {\n                offsets[i] += bv[slopes.size()+i].second*relative_noise_magnitude;\n            }\n        }\n\n\n\n        double relative_noise_magnitude = 0.001;\n        double solver_eps = 0.0001; \n        std::vector<std::pair<size_t,size_t>> active_constraints, new_active_constraints;\n\n        std::vector<function_evaluation> points;\n        std::vector<double> offsets; // offsets.size() == points.size()\n        matrix<double,0,1> slopes; // slopes.size() == points[0].first.size()\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_UPPER_bOUND_FUNCTION_Hh_\n\n\n"
  },
  {
    "path": "dlib/global_optimization/upper_bound_function_abstract.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_\n#ifdef DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include <limits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct function_evaluation\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object records the output of a real valued function in response to\n                some input. \n\n                In particular, if you have a function F(x) then the function_evaluation is\n                simply a struct that records x and the scalar value F(x).\n        !*/\n\n        function_evaluation() = default;\n        function_evaluation(const matrix<double,0,1>& x, double y) :x(x), y(y) {}\n\n        matrix<double,0,1> x;\n        double y = std::numeric_limits<double>::quiet_NaN();\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class upper_bound_function\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a piecewise linear non-parametric function that can\n                be used to define an upper bound on some more complex and unknown function.\n                To describe this precisely, lets assume there is a function F(x) which you\n                are capable of sampling from but otherwise know nothing about, and that you\n                would like to find an upper bounding function U(x) such that U(x) >= F(x)\n                for any x.  It would also be good if U(x)-F(x) was minimal.  I.e. we would\n                like U(x) to be a tight upper bound, not something vacuous like U(x) =\n                infinity.\n\n                The upper_bound_function class is a tool for creating this kind of upper\n                bounding function from a set of function_evaluations of F(x).  We do this\n                by considering only U(x) of the form:\n                    U = [](matrix<double,0,1> x) {\n                       double min_ub = infinity;\n                       for (size_t i = 0; i < POINTS.size(); ++i) {\n                            function_evaluation p = POINTS[i]\n                            double local_bound = p.y + sqrt(noise_terms[i] + trans(p.x-x)*M*(p.x-x))\n                            min_ub = min(min_ub, local_bound)\n                        }\n                        return min_ub;\n                    }\n                Where POINTS is an array of function_evaluation instances drawn from F(x),\n                M is a diagonal matrix, and noise_terms is an array of scalars.\n\n                To create an upper bound U(x), the upper_bound_function takes a POINTS array\n                containing evaluations of F(x) as input and solves the following quadratic\n                program to find the parameters of U(x):\n                    \n                    min_{M,noise_terms}:  sum(squared(M)) + sum(squared(noise_terms/relative_noise_magnitude))\n                    s.t.   U(POINTS[i].x) >= POINTS[i].y,  for all i \n                           noise_terms[i] >= 0\n                           min(M) >= 0\n                           M is a diagonal matrix \n               \n                Therefore, the quadratic program finds the U(x) that always upper bounds\n                F(x) on the supplied POINTS, but is otherwise as small as possible.\n\n\n\n                The inspiration for the upper_bound_function object came from the AdaLIPO\n                algorithm from this excellent paper:\n                    Global optimization of Lipschitz functions \n                    Malherbe, Cédric and Vayatis, Nicolas \n                    International Conference on Machine Learning - 2017\n                In that paper, they propose to use a simpler U(x) where noise_terms is\n                always 0 and M is a diagonal matrix where each diagonal element is the same\n                value.  Therefore, there is only a single scalar parameter for U(x) in\n                their formulation of the problem.  This causes difficulties if F(x) is\n                stochastic or has discontinuities since, without the noise term, M will\n                become really huge and the upper bound becomes vacuously large.  It is also\n                problematic if the gradient of F(x) with respect to x contains elements of\n                widely varying magnitude since the simpler formulation of U(x) assumes a\n                uniform rate of change regardless of which dimension is varying. \n        !*/\n\n    public:\n\n        upper_bound_function(\n        );\n        /*!\n            ensures\n                - #num_points() == 0\n                - #dimensionality() == 0\n        !*/\n\n        explicit upper_bound_function(\n            const std::vector<function_evaluation>& points,\n            const double relative_noise_magnitude = 0.001,\n            const double solver_eps = 0.0001\n        );\n        /*!\n            requires\n                - all the x vectors in points must have the same non-zero dimensionality.\n                - relative_noise_magnitude >= 0\n                - solver_eps > 0\n            ensures\n                - Creates an upper bounding function U(x), as described above, assuming that\n                  the given points are drawn from F(x).\n                - Uses the provided relative_noise_magnitude when solving the QP, as\n                  described above.  Note that relative_noise_magnitude can be set to 0.  If\n                  you do this then all the noise terms are constrained to 0.  You should\n                  only do this if you know F(x) is non-stochastic and continuous\n                  everywhere.\n                - When solving the QP used to find the parameters of U(x), the upper\n                  bounding function, we solve the QP to solver_eps accuracy.   It's\n                  possible that large enough solver_eps can lead to upper bounds that don't\n                  upper bound all the supplied points.  But for reasonable epsilon values\n                  this shouldn't be a problem. \n                - #num_points() == points.size()\n                - #dimensionality() == points[0].x.size()\n        !*/\n\n        upper_bound_function(\n            const double relative_noise_magnitude,\n            const double solver_eps \n        );\n        /*!\n            requires\n                - relative_noise_magnitude >= 0\n                - solver_eps > 0\n            ensures\n                - #num_points() == 0\n                - #dimensionality() == 0\n                - This destructor is the same as calling the above constructor with points.size()==0\n        !*/\n\n\n        void add (\n            const function_evaluation& point\n        );\n        /*!\n            requires\n                - num_points() == 0 || point.x.size() == dimensionality()\n                - point.x.size() != 0\n            ensures\n                - Adds point to get_points().\n                - Incrementally updates the upper bounding function with the given function\n                  evaluation.  That is, we assume that F(point.x)==point.y and solve the QP\n                  described above to find the new U(x) that upper bounds all the points\n                  this object knows about (i.e. all the points in get_points() and the new point).\n                - Calling add() is much faster than recreating the upper_bound_function\n                  from scratch with all the points.  This is because we warm start with the\n                  previous solution to the QP.  This is done by discarding any non-active\n                  constraints and solving the QP again with only the previously active\n                  constraints and the new constraints formed by all the pairs of the new\n                  point and the old points.  This means the QP solved by add() is much\n                  smaller than the QP that would be solved by a fresh call to the\n                  upper_bound_function constructor.\n        !*/\n\n        const std::vector<function_evaluation>& get_points(\n        ) const;\n        /*!\n            ensures\n                - returns the points from F(x) used to define this upper bounding function.\n                  These are all the function_evaluation objects given to this object via\n                  its constructor and add().\n        !*/\n\n        long num_points(\n        ) const;\n        /*!\n            ensures\n                - returns the number of points used to define the upper bounding function.\n                  (i.e. returns get_points().size())\n        !*/\n\n        long dimensionality(\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the input vectors to the upper bounding function. \n        !*/\n\n        double operator() (\n            const matrix<double,0,1>& x\n        ) const;\n        /*!\n            requires\n                - num_points() > 0\n                - x.size() == dimensionality()\n            ensures\n                - return U(x)\n                  (i.e. returns the upper bound on F(x) at x given by our upper bounding function)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_UPPER_bOUND_FUNCTION_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/global_optimization.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GLOBAL_OPTIMIZATIOn_HEADER\n#define DLIB_GLOBAL_OPTIMIZATIOn_HEADER\n\n#include \"global_optimization/upper_bound_function.h\"\n#include \"global_optimization/global_function_search.h\"\n#include \"global_optimization/find_max_global.h\"\n\n#endif // DLIB_GLOBAL_OPTIMIZATIOn_HEADER\n\n\n\n\n"
  },
  {
    "path": "dlib/graph/graph_kernel_1.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_KERNEl_1_\n#define DLIB_GRAPH_KERNEl_1_\n\n#include <memory>\n#include <vector>\n\n#include \"../serialize.h\"\n#include \"../noncopyable.h\"\n#include \"../std_allocator.h\"\n#include \"../algs.h\"\n#include \"graph_kernel_abstract.h\"\n#include \"../is_kind.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename node_type, typename graph, bool is_checked>\n    struct graph_checker_helper \n    { \n        /*!\n            This object is used to check preconditions based on the value of is_checked\n        !*/\n\n        static void check_neighbor (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_neighbors(),\n                         \"\\tnode_type& graph::node_type::neighbor(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:            \" << edge_index \n                         << \"\\n\\tnumber_of_neighbors(): \" << self.number_of_neighbors() \n                         << \"\\n\\tthis:                  \" << &self\n            );\n        }\n\n        static void check_edge (\n            unsigned long edge_index,\n            const node_type& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(edge_index < self.number_of_neighbors(),\n                         \"\\tE& graph::node_type::edge(edge_index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tedge_index:            \" << edge_index \n                         << \"\\n\\tnumber_of_neighbors(): \" << self.number_of_neighbors() \n                         << \"\\n\\tthis:                  \" << &self\n            );\n        }\n\n        static void check_node (\n            unsigned long index,\n            const graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(index < self.number_of_nodes(),\n                         \"\\tnode_type& graph::node(index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tindex:             \" << index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_has_edge (\n            unsigned long node_index1,\n            unsigned long node_index2,\n            const graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&\n                         node_index2 < self.number_of_nodes(),\n                         \"\\tvoid graph::has_edge(node_index1, node_index2)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tnode_index1:       \" << node_index1 \n                         << \"\\n\\tnode_index2:       \" << node_index2 \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n\n        static void check_add_edge (\n            unsigned long node_index1,\n            unsigned long node_index2,\n            const graph& self\n        )\n        {\n            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&\n                         node_index2 < self.number_of_nodes(),\n                         \"\\tvoid graph::add_edge(node_index1, node_index2)\" \n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tnode_index1:       \" << node_index1 \n                         << \"\\n\\tnode_index2:       \" << node_index2 \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n\n            DLIB_CASSERT( self.has_edge(node_index1, node_index2) == false,\n                          \"\\tvoid graph::add_edge(node_index1, node_index2)\"\n                          << \"\\n\\tYou can't add an edge if it already exists in the graph\"\n                          << \"\\n\\tnode_index1:       \" << node_index1 \n                          << \"\\n\\tnode_index2:       \" << node_index2 \n                          << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                          << \"\\n\\tthis:              \" << &self\n            );\n\n        }\n\n        static void check_remove_edge (\n            unsigned long node_index1,\n            unsigned long node_index2,\n            const graph& self\n        )\n        {\n            DLIB_CASSERT(node_index1 < self.number_of_nodes() &&\n                         node_index2 < self.number_of_nodes(),\n                         \"\\tvoid graph::remove_edge(node_index1, node_index2)\" \n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tnode_index1:       \" << node_index1 \n                         << \"\\n\\tnode_index2:       \" << node_index2 \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                         << \"\\n\\tthis:              \" << &self\n            );\n\n            DLIB_CASSERT( self.has_edge(node_index1, node_index2) == true,\n                          \"\\tvoid graph::remove_edge(node_index1, node_index2)\"\n                          << \"\\n\\tYou can't remove an edge if it isn't in the graph\"\n                          << \"\\n\\tnode_index1:       \" << node_index1 \n                          << \"\\n\\tnode_index2:       \" << node_index2 \n                          << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes()\n                          << \"\\n\\tthis:              \" << &self\n            );\n\n        }\n\n        static void check_remove_node (\n            unsigned long index,\n            const graph& self\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(index < self.number_of_nodes(),\n                         \"\\tvoid graph::remove_node(index)\"\n                         << \"\\n\\tYou have specified an invalid index\"\n                         << \"\\n\\tindex:             \" << index \n                         << \"\\n\\tnumber_of_nodes(): \" << self.number_of_nodes() \n                         << \"\\n\\tthis:              \" << &self\n            );\n        }\n    };\n\n    template <typename node_type, typename graph>\n    struct graph_checker_helper <node_type, graph, false>\n    { \n        static inline void check_edge ( unsigned long , const node_type& ) { }\n        static inline void check_neighbor ( unsigned long , const node_type& ) { }\n        static inline void check_node ( unsigned long , const graph& ) { }\n        static inline void check_has_edge ( unsigned long , unsigned long , const graph& ) { }\n        static inline void check_add_edge ( unsigned long , unsigned long , const graph& ) { }\n        static inline void check_remove_edge ( unsigned long , unsigned long , const graph& ) { }\n        static inline void check_remove_node ( unsigned long , const graph& ) { }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager,\n        bool is_checked = true \n        >\n    class graph_kernel_1 : noncopyable\n    {\n\n        /*!\n            INITIAL VALUE\n                - nodes.size() == 0\n\n            CONVENTION\n                - nodes.size() == number_of_nodes()\n                - for all valid i:\n                    - *nodes[i] == node(i)\n                    - nodes[i]->neighbors.size() == nodes[i]->number_of_neighbors(i)\n                    - nodes[i]->idx == i == nodes[i]->index()\n                    - for all valid n:\n                        - nodes[i]->neighbors[n] == pointer to the n'th parent node of i\n                        - *nodes[i]->neighbors[n] == node(i).neighbor(n)\n                        - *nodes[i]->edges[n] == node(i).edge(n)\n        !*/\n\n    public:\n        struct node_type;\n\n    private:\n        typedef graph_checker_helper<node_type, graph_kernel_1, is_checked> checker;\n\n\n    public:\n\n        typedef T type;\n        typedef E edge_type;\n        typedef mem_manager mem_manager_type;\n\n        graph_kernel_1(\n        ) {}\n\n        virtual ~graph_kernel_1(\n        ) {}\n\n        void clear(\n        ) { nodes.clear(); }\n\n        void set_number_of_nodes (\n            unsigned long new_size\n        );\n\n        unsigned long number_of_nodes (\n        ) const { return nodes.size(); }\n\n        node_type& node (\n            unsigned long index\n        ) { checker::check_node(index,*this); return *nodes[index]; }\n\n        const node_type& node (\n            unsigned long index\n        ) const { checker::check_node(index,*this); return *nodes[index]; }\n\n        bool has_edge (\n            unsigned long node_index1,\n            unsigned long node_index2\n        ) const;\n\n        void add_edge (\n            unsigned long node_index1,\n            unsigned long node_index2\n        );\n\n        void remove_edge (\n            unsigned long node_index1,\n            unsigned long node_index2\n        );\n\n        unsigned long add_node (\n        );\n\n        void remove_node (\n            unsigned long index\n        );\n\n        void swap (\n            graph_kernel_1& item\n        ) { nodes.swap(item.nodes); }\n\n    public:\n\n        struct node_type\n        {\n            T data;\n            typedef graph_kernel_1 graph_type;\n\n            unsigned long index(\n            ) const { return idx; }\n\n            unsigned long number_of_neighbors (\n            ) const { return neighbors.size(); }\n\n            const node_type& neighbor (\n                unsigned long edge_index\n            ) const { checker::check_neighbor(edge_index,*this);  return *neighbors[edge_index]; }\n\n            node_type& neighbor (\n                unsigned long edge_index\n            ) { checker::check_neighbor(edge_index,*this);  return *neighbors[edge_index]; }\n\n            const E& edge (\n                unsigned long edge_index\n            ) const { checker::check_edge(edge_index,*this);  return *edges[edge_index]; }\n\n            E& edge (\n                unsigned long edge_index\n            ) { checker::check_edge(edge_index,*this);  return *edges[edge_index]; }\n\n        private:\n            friend class graph_kernel_1;\n            typedef std_allocator<node_type*,mem_manager> alloc_type;\n            typedef std_allocator<std::shared_ptr<E>,mem_manager> alloc_edge_type;\n            std::vector<node_type*,alloc_type> neighbors;\n            std::vector<std::shared_ptr<E>,alloc_edge_type> edges;\n            unsigned long idx;\n        };\n\n    private:\n\n        typedef std_allocator<std::shared_ptr<node_type>,mem_manager> alloc_type;\n        typedef std::vector<std::shared_ptr<node_type>, alloc_type> vector_type;\n        vector_type nodes;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename E, \n        typename mem_manager,\n        bool is_checked\n        >\n    inline void swap (\n        graph_kernel_1<T,E,mem_manager,is_checked>& a, \n        graph_kernel_1<T,E,mem_manager,is_checked>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename E, \n        typename mem_manager,\n        bool is_checked\n        >\n    struct is_graph<graph_kernel_1<T,E,mem_manager, is_checked> >\n    {\n        static const bool value = true; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void serialize (\n        const graph_kernel_1<T,E,mem_manager,is_checked>& item,\n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.number_of_nodes(), out);\n\n            // serialize each node\n            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)\n            {\n                serialize(item.node(i).data, out);\n\n                // serialize all the edges\n                for (unsigned long n = 0; n < item.node(i).number_of_neighbors(); ++n)\n                {\n                    // only serialize edges that we haven't already serialized \n                    if (item.node(i).neighbor(n).index() >= i)\n                    {\n                        serialize(item.node(i).neighbor(n).index(), out);\n                        serialize(item.node(i).edge(n), out);\n                    }\n                }\n                const unsigned long stop_mark = 0xFFFFFFFF;\n                serialize(stop_mark, out);\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type graph_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void deserialize (\n        graph_kernel_1<T,E,mem_manager,is_checked>& item,\n        std::istream& in\n    )   \n    {\n        try\n        {\n            unsigned long size;\n            deserialize(size, in);\n\n            item.clear();\n            item.set_number_of_nodes(size);\n\n            // deserialize each node\n            for (unsigned long i = 0; i < item.number_of_nodes(); ++i)\n            {\n                deserialize(item.node(i).data, in);\n\n                const unsigned long stop_mark = 0xFFFFFFFF;\n                // Add all the edges going to this node's neighbors\n                unsigned long index;\n                deserialize(index, in);\n                while (index != stop_mark)\n                {\n                    item.add_edge(i, index);\n                    // find the edge\n                    unsigned long j = 0;\n                    for (j = 0; j < item.node(i).number_of_neighbors(); ++j)\n                        if (item.node(i).neighbor(j).index() == index)\n                            break;\n\n                    deserialize(item.node(i).edge(j), in);\n                    deserialize(index, in);\n                }\n\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type graph_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                             member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void graph_kernel_1<T,E,mem_manager,is_checked>::\n    set_number_of_nodes (\n        unsigned long new_size\n    )\n    {\n        try\n        {\n            nodes.resize(new_size);\n            for (unsigned long i = 0; i < nodes.size(); ++i)\n            {\n                nodes[i].reset(new node_type);\n                nodes[i]->idx = i;\n            }\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    bool graph_kernel_1<T,E,mem_manager,is_checked>::\n    has_edge (\n        unsigned long node_index1,\n        unsigned long node_index2\n    ) const\n    {\n        checker::check_has_edge(node_index1, node_index2, *this);\n\n        node_type& n = *nodes[node_index1];\n\n        // search all the child nodes to see if there is a link to the right node\n        for (unsigned long i = 0; i < n.neighbors.size(); ++i)\n        {\n            if (n.neighbors[i]->idx == node_index2)\n                return true;\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void graph_kernel_1<T,E,mem_manager,is_checked>::\n    add_edge (\n        unsigned long node_index1,\n        unsigned long node_index2\n    )\n    {\n        checker::check_add_edge(node_index1, node_index2, *this);\n        try\n        {\n            node_type& n1 = *nodes[node_index1];\n            node_type& n2 = *nodes[node_index2];\n\n            n1.neighbors.push_back(&n2);\n\n            std::shared_ptr<E> e(new E);\n            n1.edges.push_back(e);\n\n            // don't add this twice if this is an edge from node_index1 back to itself\n            if (node_index1 != node_index2)\n            {\n                n2.neighbors.push_back(&n1);\n                n2.edges.push_back(e);\n            }\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void graph_kernel_1<T,E,mem_manager,is_checked>::\n    remove_edge (\n        unsigned long node_index1,\n        unsigned long node_index2\n    )\n    {\n        checker::check_remove_edge(node_index1, node_index2, *this);\n\n        node_type& n1 = *nodes[node_index1];\n        node_type& n2 = *nodes[node_index2];\n\n        // remove the record of the link from n1 \n        unsigned long pos = static_cast<unsigned long>(find(n1.neighbors.begin(), n1.neighbors.end(), &n2) - n1.neighbors.begin());\n        n1.neighbors.erase(n1.neighbors.begin() + pos); \n        n1.edges.erase(n1.edges.begin() + pos); \n\n        // check if this is an edge that goes from node_index1 back to itself\n        if (node_index1 != node_index2)\n        {\n            // remove the record of the link from n2 \n            unsigned long pos = static_cast<unsigned long>(find(n2.neighbors.begin(), n2.neighbors.end(), &n1) - n2.neighbors.begin());\n            n2.neighbors.erase(n2.neighbors.begin() + pos); \n            n2.edges.erase(n2.edges.begin() + pos); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    unsigned long graph_kernel_1<T,E,mem_manager,is_checked>::\n    add_node (\n    )\n    {\n        try\n        {\n            std::shared_ptr<node_type> n(new node_type);\n            n->idx = nodes.size();\n            nodes.push_back(n);\n            return n->idx;\n        }\n        catch (...)\n        {\n            clear();\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager,\n        bool is_checked\n        >\n    void graph_kernel_1<T,E,mem_manager,is_checked>::\n    remove_node (\n        unsigned long index\n    )\n    {\n        checker::check_remove_node(index,*this);\n\n        node_type& n = *nodes[index];\n\n        // remove all edges pointing to this node from its neighbors \n        for (unsigned long i = 0; i < n.neighbors.size(); ++i)\n        {\n            // remove the edge from this specific parent\n            unsigned long pos = static_cast<unsigned long>(find(n.neighbors[i]->neighbors.begin(), n.neighbors[i]->neighbors.end(), &n) - \n                                n.neighbors[i]->neighbors.begin());\n            n.neighbors[i]->neighbors.erase(n.neighbors[i]->neighbors.begin() + pos); \n            n.neighbors[i]->edges.erase(n.neighbors[i]->edges.begin() + pos); \n        }\n\n        // now remove this node by replacing it with the last node in the nodes vector\n        nodes[index] = nodes[nodes.size()-1];\n\n        // update the index for the node we just moved\n        nodes[index]->idx = index;\n\n        // now remove the duplicated node at the end of the vector\n        nodes.pop_back();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GRAPH_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/graph/graph_kernel_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GRAPH_KERNEl_ABSTRACT_\n#ifdef DLIB_GRAPH_KERNEl_ABSTRACT_\n\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include \"../noncopyable.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager \n        >\n    class graph : noncopyable\n    {\n\n        /*!\n            REQUIREMENTS ON T \n                T must be swappable by a global swap() and\n                T must have a default constructor\n\n            REQUIREMENTS ON E \n                E must be swappable by a global swap() and\n                E must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                The only time pointers or references to nodes or edges become invalid is when\n                they reference nodes or edges that have been removed from a graph.\n\n            INITIAL VALUE\n                number_of_nodes() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an undirected graph which is a set of nodes with undirected\n                edges connecting various nodes.  \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n        !*/\n\n    public:\n\n        typedef T type;\n        typedef E edge_type;\n        typedef mem_manager mem_manager_type;\n\n        graph(\n        );\n        /*!\n            ensures \n                - #*this is properly initialized\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n        !*/\n\n        virtual ~graph(\n        ); \n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then *this is unusable \n                  until clear() is called and succeeds\n        !*/\n\n        void set_number_of_nodes (\n            unsigned long new_size\n        );\n        /*!\n            ensures\n                - #number_of_nodes() == new_size\n                - for all i < new_size:\n                    - number_of_neighbors(i) == 0\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in this graph\n        !*/\n\n        struct node_type\n        {\n            T data;\n            typedef graph graph_type;\n\n            unsigned long index(\n            ) const;\n            /*!\n                ensures\n                    - let G be the graph that contains the node *this\n                    - returns a number N such that G.node(N) == *this\n                      (i.e. returns the index of this node in the graph)\n            !*/\n\n            unsigned long number_of_neighbors (\n            ) const;\n            /*!\n                ensures\n                    - returns the number of nodes in this graph that are\n                      adjacent to this node.  I.e. the number of nodes\n                      that are directly connected to this node via an edge. \n            !*/\n\n            const node_type& neighbor (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_neighbors()\n                ensures\n                    - returns a const reference to the edge_index'th neighbor of *this\n            !*/\n\n            node_type& neighbor (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_neighbors()\n                ensures\n                    - returns a non-const reference to the edge_index'th neighbor of *this\n            !*/\n\n            const E& edge (\n                unsigned long edge_index\n            ) const;\n            /*!\n                requires\n                    - edge_index < number_of_neighbors()\n                ensures\n                    - returns a const reference to the edge_index'th edge data for the\n                      edge connecting to neighbor this->neighbor(edge_index)\n            !*/\n\n            E& edge (\n                unsigned long edge_index\n            );\n            /*!\n                requires\n                    - edge_index < number_of_neighbors()\n                ensures\n                    - returns a non-const reference to the edge_index'th edge data for the\n                      edge connecting to neighbor this->neighbor(edge_index)\n            !*/\n\n        };\n\n        node_type& node (\n            unsigned long index\n        );\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - returns a non-const reference to the node with the given index\n        !*/\n\n        const node_type& node (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - returns a const reference to the node with the given index\n        !*/\n\n        bool has_edge (\n            unsigned long node_index1,\n            unsigned long node_index2 \n        ) const;\n        /*!\n            requires\n                - node_index1 < number_of_nodes()\n                - node_index2 < number_of_nodes()\n            ensures\n                - if (there is an edge connecting node(node_index1) and node(node_index2)) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void add_edge (\n            unsigned long node_index1,\n            unsigned long node_index2\n        );\n        /*!\n            requires\n                - node_index1 < number_of_nodes()\n                - node_index2 < number_of_nodes()\n                - has_edge(node_index1, node_index2) == false\n            ensures\n                - #has_edge(node_index1, node_index2) == true \n            throws\n                - std::bad_alloc \n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void remove_edge (\n            unsigned long node_index1,\n            unsigned long node_index2\n        );\n        /*!\n            requires\n                - node_index1 < number_of_nodes()\n                - node_index2 < number_of_nodes()\n                - has_edge(node_index1, node_index2) == true \n            ensures\n                - #has_edge(node_index1, node_index2) == false \n            throws\n                - std::bad_alloc \n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        unsigned long add_node (\n        );\n        /*!\n            ensures\n                - does not change the index number of existing nodes\n                - adds a node with index N == number_of_nodes() such that:\n                    - #node(N).number_of_neighbors() == 0 \n                    - #number_of_nodes() == number_of_nodes() + 1\n                    - returns N  \n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void remove_node (\n            unsigned long index\n        );\n        /*!\n            requires\n                - index < number_of_nodes()\n            ensures\n                - removes the node with the given index from the graph. \n                - removes all edges linking the removed node to the rest\n                  of the graph.\n                - the remaining node indexes are remapped so that they remain\n                  contiguous.  (This means that for all valid N, node(N) doesn't\n                  necessarily reference the same node as #node(N))\n                - #number_of_nodes() == number_of_nodes() - 1\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor.\n                  If this exception is thrown then this object reverts back \n                  to its initial state.\n        !*/\n\n        void swap (\n            graph& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };\n\n    template <\n        typename T, \n        typename E, \n        typename mem_manager\n        >\n    inline void swap (\n        graph<T,E,mem_manager>& a, \n        graph<T,E,mem_manager>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager\n        >\n    void serialize (\n        const graph<T,E,mem_manager>& item,\n        std::ostream& out \n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n    template <\n        typename T,\n        typename E,\n        typename mem_manager\n        >\n    void deserialize (\n        graph<T,E,mem_manager>& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n}\n\n#endif // DLIB_GRAPH_KERNEl_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/graph.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPh_\n#define DLIB_GRAPh_\n\n#include \"graph/graph_kernel_1.h\"\n\n#include \"algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename E = char,\n        typename mem_manager = default_memory_manager \n        >\n    class graph \n    {\n        graph() {}\n    public:\n                \n\n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     graph_kernel_1<T,E,mem_manager,false>    \n                    kernel_1a;\n        typedef     graph_kernel_1<T,E,mem_manager,true>    \n                    kernel_1a_c;\n \n    };\n}\n\n#endif // DLIB_GRAPh_ \n\n\n"
  },
  {
    "path": "dlib/graph_cuts/find_max_factor_graph_potts.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_Hh_\n#define DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_Hh_\n\n#include \"find_max_factor_graph_potts_abstract.h\"\n#include \"../matrix.h\"\n#include \"min_cut.h\"\n#include \"general_potts_problem.h\"\n#include \"../algs.h\"\n#include \"../graph_utils.h\"\n#include \"../array2d.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n        template <\n            typename potts_problem,\n            typename T = void\n            >\n        class flows_container\n        {\n            /*\n                This object notionally represents a matrix of flow values.  It's\n                overloaded to represent this matrix efficiently though.  In this case\n                it represents the matrix using a sparse representation.\n            */\n\n            typedef typename potts_problem::value_type edge_type;\n            std::vector<std::vector<edge_type> > flows;\n        public:\n\n            void setup(\n                const potts_problem& p\n            )\n            {\n                flows.resize(p.number_of_nodes());\n                for (unsigned long i = 0; i < flows.size(); ++i)\n                {\n                    flows[i].resize(p.number_of_neighbors(i));\n                }\n            }\n\n            edge_type& operator() (\n                const long r,\n                const long c\n            ) { return flows[r][c]; }\n\n            const edge_type& operator() (\n                const long r,\n                const long c\n            ) const { return flows[r][c]; }\n        };\n\n// ----------------------------------------------------------------------------------------\n\n        template <\n            typename potts_problem\n            >\n        class flows_container<potts_problem, \n                              typename enable_if_c<potts_problem::max_number_of_neighbors!=0>::type>\n        {\n            /*\n                This object notionally represents a matrix of flow values.  It's\n                overloaded to represent this matrix efficiently though.  In this case\n                it represents the matrix using a dense representation.\n\n            */\n            typedef typename potts_problem::value_type edge_type;\n            const static unsigned long max_number_of_neighbors = potts_problem::max_number_of_neighbors;\n            matrix<edge_type,0,max_number_of_neighbors> flows;\n        public:\n\n            void setup(\n                const potts_problem& p\n            )\n            {\n                flows.set_size(p.number_of_nodes(), max_number_of_neighbors);\n            }\n\n            edge_type& operator() (\n                const long r,\n                const long c\n            ) { return flows(r,c); }\n\n            const edge_type& operator() (\n                const long r,\n                const long c\n            ) const { return flows(r,c); }\n        };\n\n// ----------------------------------------------------------------------------------------\n\n        template <\n            typename potts_problem \n            >\n        class potts_flow_graph \n        {\n        public:\n            typedef typename potts_problem::value_type edge_type;\n        private:\n            /*!\n                This is a utility class used by dlib::min_cut to convert a potts_problem \n                into the kind of flow graph expected by the min_cut object's main block\n                of code.\n\n                Within this object, we will use the convention that one past \n                potts_problem::number_of_nodes() is the source node and two past is \n                the sink node.\n            !*/\n\n            potts_problem& g;\n\n            // flows(i,j) == the flow from node id i to it's jth neighbor\n            flows_container<potts_problem> flows;\n            // source_flows(i,0) == flow from source to node i, \n            // source_flows(i,1) == flow from node i to source\n            matrix<edge_type,0,2> source_flows;\n\n            // sink_flows(i,0) == flow from sink to node i, \n            // sink_flows(i,1) == flow from node i to sink\n            matrix<edge_type,0,2> sink_flows;\n\n            node_label source_label, sink_label;\n        public:\n\n            potts_flow_graph(\n                potts_problem& g_\n            ) : g(g_)\n            {\n                flows.setup(g);\n\n                source_flows.set_size(g.number_of_nodes(), 2);\n                sink_flows.set_size(g.number_of_nodes(), 2);\n                source_flows = 0;\n                sink_flows = 0;\n\n                source_label = FREE_NODE;\n                sink_label = FREE_NODE;\n\n                // setup flows based on factor potentials\n                for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n                {\n                    const edge_type temp = g.factor_value(i);\n                    if (temp < 0)\n                        source_flows(i,0) = -temp;\n                    else\n                        sink_flows(i,1) = temp;\n\n                    for (unsigned long j = 0; j < g.number_of_neighbors(i); ++j)\n                    {\n                        flows(i,j) = g.factor_value_disagreement(i, g.get_neighbor(i,j));\n                    }\n                }\n            }\n\n            class out_edge_iterator\n            {\n                friend class potts_flow_graph;\n                unsigned long idx; // base node idx\n                unsigned long cnt; // count over the neighbors of idx\n            public:\n\n                out_edge_iterator(\n                ):idx(0),cnt(0){}\n\n                out_edge_iterator(\n                    unsigned long idx_,\n                    unsigned long cnt_\n                ):idx(idx_),cnt(cnt_)\n                {}\n\n                bool operator!= (\n                    const out_edge_iterator& item\n                ) const { return cnt != item.cnt; }\n\n                out_edge_iterator& operator++(\n                )\n                {\n                    ++cnt;\n                    return *this;\n                }\n            };\n\n            class in_edge_iterator\n            {\n                friend class potts_flow_graph;\n                unsigned long idx; // base node idx\n                unsigned long cnt; // count over the neighbors of idx\n            public:\n\n                in_edge_iterator(\n                ):idx(0),cnt(0)  \n                {}\n\n\n                in_edge_iterator(\n                    unsigned long idx_,\n                    unsigned long cnt_\n                ):idx(idx_),cnt(cnt_)\n                {}\n\n                bool operator!= (\n                    const in_edge_iterator& item\n                ) const { return cnt != item.cnt; }\n\n                in_edge_iterator& operator++(\n                )\n                {\n                    ++cnt;\n                    return *this;\n                }\n            };\n\n            unsigned long number_of_nodes (\n            ) const { return g.number_of_nodes() + 2; }\n\n            out_edge_iterator out_begin(\n                const unsigned long& it\n            ) const { return out_edge_iterator(it, 0); }\n\n            in_edge_iterator in_begin(\n                const unsigned long& it\n            ) const { return in_edge_iterator(it, 0); }\n\n            out_edge_iterator out_end(\n                const unsigned long& it\n            ) const \n            { \n                if (it >= g.number_of_nodes())\n                    return out_edge_iterator(it, g.number_of_nodes()); \n                else\n                    return out_edge_iterator(it, g.number_of_neighbors(it)+2); \n            }\n\n            in_edge_iterator in_end(\n                const unsigned long& it\n            ) const \n            { \n                if (it >= g.number_of_nodes())\n                    return in_edge_iterator(it, g.number_of_nodes()); \n                else\n                    return in_edge_iterator(it, g.number_of_neighbors(it)+2); \n            }\n\n\n            template <typename iterator_type>\n            unsigned long node_id (\n                const iterator_type& it\n            ) const \n            { \n                // if this isn't an iterator over the source or sink nodes\n                if (it.idx < g.number_of_nodes())\n                {\n                    const unsigned long num = g.number_of_neighbors(it.idx);\n                    if (it.cnt < num)\n                        return g.get_neighbor(it.idx, it.cnt); \n                    else if (it.cnt == num)\n                        return g.number_of_nodes();\n                    else\n                        return g.number_of_nodes()+1;\n                }\n                else\n                {\n                    return it.cnt;\n                }\n            }\n\n\n            edge_type get_flow (\n                const unsigned long& it1,     \n                const unsigned long& it2\n            ) const\n            {\n                if (it1 >= g.number_of_nodes())\n                {\n                    // if it1 is the source\n                    if (it1 == g.number_of_nodes())\n                    {\n                        return source_flows(it2,0);\n                    }\n                    else // if it1 is the sink\n                    {\n                        return sink_flows(it2,0);\n                    }\n                }\n                else if (it2 >= g.number_of_nodes())\n                {\n                    // if it2 is the source\n                    if (it2 == g.number_of_nodes())\n                    {\n                        return source_flows(it1,1);\n                    }\n                    else // if it2 is the sink\n                    {\n                        return sink_flows(it1,1);\n                    }\n                }\n                else\n                {\n                    return flows(it1, g.get_neighbor_idx(it1, it2));\n                }\n\n            }\n\n            edge_type get_flow (\n                const out_edge_iterator& it\n            ) const\n            {\n                if (it.idx < g.number_of_nodes())\n                {\n                    const unsigned long num = g.number_of_neighbors(it.idx);\n                    if (it.cnt < num)\n                        return flows(it.idx, it.cnt);\n                    else if (it.cnt == num)\n                        return source_flows(it.idx,1);\n                    else\n                        return sink_flows(it.idx,1);\n                }\n                else\n                {\n                    // if it.idx is the source\n                    if (it.idx == g.number_of_nodes())\n                    {\n                        return source_flows(it.cnt,0);\n                    }\n                    else // if it.idx is the sink\n                    {\n                        return sink_flows(it.cnt,0);\n                    }\n                }\n            }\n\n            edge_type get_flow (\n                const in_edge_iterator& it\n            ) const\n            {\n                return get_flow(node_id(it), it.idx); \n            }\n\n            void adjust_flow (\n                const unsigned long& it1,     \n                const unsigned long& it2,     \n                const edge_type& value\n            )\n            {\n                if (it1 >= g.number_of_nodes())\n                {\n                    // if it1 is the source\n                    if (it1 == g.number_of_nodes())\n                    {\n                        source_flows(it2,0) += value;\n                        source_flows(it2,1) -= value;\n                    }\n                    else // if it1 is the sink\n                    {\n                        sink_flows(it2,0) += value;\n                        sink_flows(it2,1) -= value;\n                    }\n                }\n                else if (it2 >= g.number_of_nodes())\n                {\n                    // if it2 is the source\n                    if (it2 == g.number_of_nodes())\n                    {\n                        source_flows(it1,1) += value;\n                        source_flows(it1,0) -= value;\n                    }\n                    else // if it2 is the sink\n                    {\n                        sink_flows(it1,1) += value;\n                        sink_flows(it1,0) -= value;\n                    }\n                }\n                else\n                {\n                    flows(it1, g.get_neighbor_idx(it1, it2)) += value;\n                    flows(it2, g.get_neighbor_idx(it2, it1)) -= value;\n                }\n\n            }\n\n            void set_label (\n                const unsigned long& it,\n                node_label value\n            )\n            {\n                if (it < g.number_of_nodes())\n                    g.set_label(it, value);\n                else if (it == g.number_of_nodes())\n                    source_label = value;\n                else \n                    sink_label = value;\n            }\n\n            node_label get_label (\n                const unsigned long& it\n            ) const\n            {\n                if (it < g.number_of_nodes())\n                    return g.get_label(it);\n                if (it == g.number_of_nodes())\n                    return source_label;\n                else\n                    return sink_label;\n            }\n\n        };\n\n// ----------------------------------------------------------------------------------------\n\n        template <\n            typename label_image_type,\n            typename image_potts_model\n            >\n        class potts_grid_problem \n        {\n            label_image_type& label_img;\n            long nc;\n            long num_nodes;\n            unsigned char* labels;\n            const image_potts_model& model;\n\n        public:\n            const static unsigned long max_number_of_neighbors = 4;\n\n            potts_grid_problem (\n                label_image_type& label_img_,\n                const image_potts_model& image_potts_model_\n            ) : \n                label_img(label_img_),\n                model(image_potts_model_)\n            {\n                num_nodes = model.nr()*model.nc();\n                nc = model.nc();\n                labels = &label_img[0][0];\n            }\n\n            unsigned long number_of_nodes (\n            ) const { return num_nodes; }\n\n            unsigned long number_of_neighbors (\n                unsigned long \n            ) const \n            { \n                return 4;\n            }\n\n            unsigned long get_neighbor_idx (\n                long node_id1,\n                long node_id2\n            ) const\n            {\n                long diff = node_id2-node_id1;\n                if (diff > nc)\n                    diff -= (long)number_of_nodes();\n                else if (diff < -nc)\n                    diff += (long)number_of_nodes();\n\n                if (diff == 1) \n                    return 0;\n                else if (diff == -1)\n                    return 1;\n                else if (diff == nc)\n                    return 2;\n                else\n                    return 3;\n            }\n\n            unsigned long get_neighbor (\n                long node_id,\n                long idx\n            ) const\n            {\n                switch(idx)\n                {\n                    case 0: \n                        {\n                            long temp = node_id+1;\n                            if (temp < (long)number_of_nodes())\n                                return temp;\n                            else\n                                return temp - (long)number_of_nodes();\n                        }\n                    case 1: \n                        {\n                            long temp = node_id-1;\n                            if (node_id >= 1)\n                                return temp;\n                            else\n                                return temp + (long)number_of_nodes();\n                        }\n                    case 2: \n                        {\n                            long temp = node_id+nc;\n                            if (temp < (long)number_of_nodes())\n                                return temp;\n                            else\n                                return temp - (long)number_of_nodes();\n                        }\n                    case 3: \n                        {\n                            long temp = node_id-nc;\n                            if (node_id >= nc)\n                                return temp;\n                            else\n                                return temp + (long)number_of_nodes();\n                        }\n                }\n                return 0;\n            }\n\n            void set_label (\n                const unsigned long& idx,\n                node_label value\n            )\n            {\n                *(labels+idx) = value;\n            }\n\n            node_label get_label (\n                const unsigned long& idx\n            ) const\n            {\n                return *(labels+idx);\n            }\n\n            typedef typename image_potts_model::value_type value_type;\n\n            value_type factor_value (unsigned long idx) const\n            {\n                return model.factor_value(idx);\n            }\n\n            value_type factor_value_disagreement (unsigned long idx1, unsigned long idx2) const\n            {\n                return model.factor_value_disagreement(idx1,idx2);\n            }\n\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_model\n        >\n    typename potts_model::value_type potts_model_score (\n        const potts_model& prob\n    )\n    {\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < prob.number_of_nodes(); ++i)\n        {\n            for (unsigned long jj = 0; jj < prob.number_of_neighbors(i); ++jj)\n            {\n                unsigned long j = prob.get_neighbor(i,jj);\n                DLIB_ASSERT(prob.factor_value_disagreement(i,j) >= 0,\n                    \"\\t value_type potts_model_score(prob)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t i: \" << i \n                    << \"\\n\\t j: \" << j \n                    << \"\\n\\t prob.factor_value_disagreement(i,j): \" << prob.factor_value_disagreement(i,j)\n                    );\n                DLIB_ASSERT(prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i),\n                    \"\\t value_type potts_model_score(prob)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t i: \" << i \n                    << \"\\n\\t j: \" << j \n                    << \"\\n\\t prob.factor_value_disagreement(i,j): \" << prob.factor_value_disagreement(i,j)\n                    << \"\\n\\t prob.factor_value_disagreement(j,i): \" << prob.factor_value_disagreement(j,i)\n                    );\n            }\n        }\n#endif \n\n        typename potts_model::value_type score = 0;\n        for (unsigned long i = 0; i < prob.number_of_nodes(); ++i)\n        {\n            const bool label = (prob.get_label(i)!=0);\n            if (label)\n                score += prob.factor_value(i);\n        }\n\n        for (unsigned long i = 0; i < prob.number_of_nodes(); ++i)\n        {\n            for (unsigned long n = 0; n < prob.number_of_neighbors(i); ++n)\n            {\n                const unsigned long idx2 = prob.get_neighbor(i,n);\n                const bool label_i = (prob.get_label(i)!=0);\n                const bool label_idx2 = (prob.get_label(idx2)!=0);\n                if (label_i != label_idx2 && i < idx2)\n                    score -= prob.factor_value_disagreement(i, idx2);\n            }\n        }\n\n        return score;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type \n        >\n    typename graph_type::edge_type potts_model_score (\n        const graph_type& g,\n        const std::vector<node_label>& labels\n    )\n    {\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n                    \"\\t edge_type potts_model_score(g,labels)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    );\n        typedef typename graph_type::edge_type edge_type;\n        typedef typename graph_type::type type;\n\n        // The edges and node's have to use the same type to represent factor weights!\n        COMPILE_TIME_ASSERT((is_same_type<edge_type, type>::value == true));\n\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            for (unsigned long jj = 0; jj < g.node(i).number_of_neighbors(); ++jj)\n            {\n                unsigned long j = g.node(i).neighbor(jj).index();\n                DLIB_ASSERT(edge(g,i,j) >= 0,\n                    \"\\t edge_type potts_model_score(g,labels)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t i: \" << i \n                    << \"\\n\\t j: \" << j \n                    << \"\\n\\t edge(g,i,j): \" << edge(g,i,j)\n                    );\n            }\n        }\n#endif \n\n        typename graph_type::edge_type score = 0;\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            const bool label = (labels[i]!=0);\n            if (label)\n                score += g.node(i).data;\n        }\n\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            for (unsigned long n = 0; n < g.node(i).number_of_neighbors(); ++n)\n            {\n                const unsigned long idx2 = g.node(i).neighbor(n).index();\n                const bool label_i = (labels[i]!=0);\n                const bool label_idx2 = (labels[idx2]!=0);\n                if (label_i != label_idx2 && i < idx2)\n                    score -= g.node(i).edge(n);\n            }\n        }\n\n        return score;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_grid_problem,\n        typename mem_manager\n        >\n    typename potts_grid_problem::value_type potts_model_score (\n        const potts_grid_problem& prob,\n        const array2d<node_label,mem_manager>& labels\n    )\n    {\n        DLIB_ASSERT(prob.nr() == labels.nr() && prob.nc() == labels.nc(),\n            \"\\t value_type potts_model_score(prob,labels)\"\n            << \"\\n\\t Invalid inputs were given to this function.\" \n            << \"\\n\\t prob.nr(): \" << labels.nr()\n            << \"\\n\\t prob.nc(): \" << labels.nc()\n            );\n        typedef array2d<node_label,mem_manager> image_type;\n        // This const_cast is ok because the model object won't actually modify labels\n        dlib::impl::potts_grid_problem<image_type,potts_grid_problem> model(const_cast<image_type&>(labels),prob);\n        return potts_model_score(model);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_model\n        >\n    void find_max_factor_graph_potts (\n        potts_model& prob\n    )\n    {\n#ifdef ENABLE_ASSERTS\n        for (unsigned long node_i = 0; node_i < prob.number_of_nodes(); ++node_i)\n        {\n            for (unsigned long jj = 0; jj < prob.number_of_neighbors(node_i); ++jj)\n            {\n                unsigned long node_j = prob.get_neighbor(node_i,jj);\n                DLIB_ASSERT(prob.get_neighbor_idx(node_j,node_i) < prob.number_of_neighbors(node_j),\n                    \"\\t void find_max_factor_graph_potts(prob)\"\n                    << \"\\n\\t The supplied potts problem defines an invalid graph.\" \n                    << \"\\n\\t node_i: \" << node_i \n                    << \"\\n\\t node_j: \" << node_j \n                    << \"\\n\\t prob.get_neighbor_idx(node_j,node_i): \" << prob.get_neighbor_idx(node_j,node_i)\n                    << \"\\n\\t prob.number_of_neighbors(node_j):     \" << prob.number_of_neighbors(node_j)\n                            );\n\n                DLIB_ASSERT(prob.get_neighbor_idx(node_i,prob.get_neighbor(node_i,jj)) == jj,\n                    \"\\t void find_max_factor_graph_potts(prob)\"\n                    << \"\\n\\t The get_neighbor_idx() and get_neighbor() functions must be inverses of each other.\" \n                    << \"\\n\\t node_i: \" << node_i \n                    << \"\\n\\t jj:     \" << jj\n                    << \"\\n\\t prob.get_neighbor(node_i,jj): \" << prob.get_neighbor(node_i,jj)\n                    << \"\\n\\t prob.get_neighbor_idx(node_i,prob.get_neighbor(node_i,jj)): \" << prob.get_neighbor_idx(node_i,node_j)\n                            );\n\n                DLIB_ASSERT(prob.get_neighbor(node_j,prob.get_neighbor_idx(node_j,node_i))==node_i,\n                    \"\\t void find_max_factor_graph_potts(prob)\"\n                    << \"\\n\\t The get_neighbor_idx() and get_neighbor() functions must be inverses of each other.\" \n                    << \"\\n\\t node_i: \" << node_i \n                    << \"\\n\\t node_j: \" << node_j \n                    << \"\\n\\t prob.get_neighbor_idx(node_j,node_i): \" << prob.get_neighbor_idx(node_j,node_i)\n                    << \"\\n\\t prob.get_neighbor(node_j,prob.get_neighbor_idx(node_j,node_i)): \" << prob.get_neighbor(node_j,prob.get_neighbor_idx(node_j,node_i))\n                            );\n\n                DLIB_ASSERT(prob.factor_value_disagreement(node_i,node_j) >= 0,\n                    \"\\t void find_max_factor_graph_potts(prob)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t node_i: \" << node_i \n                    << \"\\n\\t node_j: \" << node_j \n                    << \"\\n\\t prob.factor_value_disagreement(node_i,node_j): \" << prob.factor_value_disagreement(node_i,node_j)\n                    );\n                DLIB_ASSERT(prob.factor_value_disagreement(node_i,node_j) == prob.factor_value_disagreement(node_j,node_i),\n                    \"\\t void find_max_factor_graph_potts(prob)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t node_i: \" << node_i \n                    << \"\\n\\t node_j: \" << node_j \n                    << \"\\n\\t prob.factor_value_disagreement(node_i,node_j): \" << prob.factor_value_disagreement(node_i,node_j)\n                    << \"\\n\\t prob.factor_value_disagreement(node_j,node_i): \" << prob.factor_value_disagreement(node_j,node_i)\n                    );\n            }\n        }\n#endif \n        COMPILE_TIME_ASSERT(is_signed_type<typename potts_model::value_type>::value);\n        min_cut mc;\n        dlib::impl::potts_flow_graph<potts_model> pfg(prob);\n        mc(pfg, prob.number_of_nodes(), prob.number_of_nodes()+1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type \n        >\n    void find_max_factor_graph_potts (\n        const graph_type& g,\n        std::vector<node_label>& labels\n    )\n    {\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n                    \"\\t void find_max_factor_graph_potts(g,labels)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    );\n        typedef typename graph_type::edge_type edge_type;\n        typedef typename graph_type::type type;\n\n        // The edges and node's have to use the same type to represent factor weights!\n        COMPILE_TIME_ASSERT((is_same_type<edge_type, type>::value == true));\n        COMPILE_TIME_ASSERT(is_signed_type<edge_type>::value);\n\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            for (unsigned long jj = 0; jj < g.node(i).number_of_neighbors(); ++jj)\n            {\n                unsigned long j = g.node(i).neighbor(jj).index();\n                DLIB_ASSERT(edge(g,i,j) >= 0,\n                    \"\\t void find_max_factor_graph_potts(g,labels)\"\n                    << \"\\n\\t Invalid inputs were given to this function.\" \n                    << \"\\n\\t i: \" << i \n                    << \"\\n\\t j: \" << j \n                    << \"\\n\\t edge(g,i,j): \" << edge(g,i,j)\n                    );\n            }\n        }\n#endif \n\n        dlib::impl::general_potts_problem<graph_type> gg(g, labels);\n        find_max_factor_graph_potts(gg);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_grid_problem,\n        typename mem_manager\n        >\n    void find_max_factor_graph_potts (\n        const potts_grid_problem& prob,\n        array2d<node_label,mem_manager>& labels\n    )\n    {\n        typedef array2d<node_label,mem_manager> image_type;\n        labels.set_size(prob.nr(), prob.nc());\n        dlib::impl::potts_grid_problem<image_type,potts_grid_problem> model(labels,prob);\n        find_max_factor_graph_potts(model);\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    namespace impl\n    {\n        template <\n            typename pixel_type1,\n            typename pixel_type2,\n            typename model_type\n            >\n        struct potts_grid_image_pair_model\n        {\n            const pixel_type1* data1;\n            const pixel_type2* data2;\n            const model_type& model;\n            const long nr_;\n            const long nc_;\n            template <typename image_type1, typename image_type2>\n            potts_grid_image_pair_model(\n                const model_type& model_,\n                const image_type1& img1,\n                const image_type2& img2\n            ) :\n                model(model_),\n                nr_(img1.nr()),\n                nc_(img1.nc())\n            {\n                data1 = &img1[0][0];\n                data2 = &img2[0][0];\n            }\n\n            typedef typename model_type::value_type value_type;\n\n            long nr() const { return nr_; }\n            long nc() const { return nc_; }\n\n            value_type factor_value (\n                unsigned long idx\n            ) const \n            {\n                return model.factor_value(*(data1 + idx), *(data2 + idx));\n            }\n\n            value_type factor_value_disagreement (\n                unsigned long idx1,\n                unsigned long idx2\n            ) const \n            {\n                return model.factor_value_disagreement(*(data1 + idx1), *(data1 + idx2));\n            }\n        };\n\n    // ---------------------------------------------------------------------------------------- \n\n        template <\n            typename image_type,\n            typename model_type\n            >\n        struct potts_grid_image_single_model\n        {\n            const typename image_type::type* data1;\n            const model_type& model;\n            const long nr_;\n            const long nc_;\n            potts_grid_image_single_model(\n                const model_type& model_,\n                const image_type& img1\n            ) :\n                model(model_),\n                nr_(img1.nr()),\n                nc_(img1.nc())\n            {\n                data1 = &img1[0][0];\n            }\n\n            typedef typename model_type::value_type value_type;\n\n            long nr() const { return nr_; }\n            long nc() const { return nc_; }\n\n            value_type factor_value (\n                unsigned long idx\n            ) const \n            {\n                return model.factor_value(*(data1 + idx));\n            }\n\n            value_type factor_value_disagreement (\n                unsigned long idx1,\n                unsigned long idx2\n            ) const \n            {\n                return model.factor_value_disagreement(*(data1 + idx1), *(data1 + idx2));\n            }\n        };\n\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    template <\n        typename pair_image_model,\n        typename pixel_type1,\n        typename pixel_type2,\n        typename mem_manager\n        >\n    impl::potts_grid_image_pair_model<pixel_type1, pixel_type2, pair_image_model> make_potts_grid_problem (\n        const pair_image_model& model,\n        const array2d<pixel_type1,mem_manager>& img1,\n        const array2d<pixel_type2,mem_manager>& img2\n    )\n    {\n        DLIB_ASSERT(get_rect(img1) == get_rect(img2),\n            \"\\t potts_grid_problem make_potts_grid_problem()\"\n            << \"\\n\\t Invalid inputs were given to this function.\" \n            << \"\\n\\t get_rect(img1): \" << get_rect(img1)\n            << \"\\n\\t get_rect(img2): \" << get_rect(img2)\n            );\n        typedef impl::potts_grid_image_pair_model<pixel_type1, pixel_type2, pair_image_model> potts_type;\n        return potts_type(model,img1,img2);\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    template <\n        typename single_image_model,\n        typename pixel_type,\n        typename mem_manager\n        >\n    impl::potts_grid_image_single_model<array2d<pixel_type,mem_manager>, single_image_model> make_potts_grid_problem (\n        const single_image_model& model,\n        const array2d<pixel_type,mem_manager>& img\n    )\n    {\n        typedef impl::potts_grid_image_single_model<array2d<pixel_type,mem_manager>, single_image_model> potts_type;\n        return potts_type(model,img);\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_Hh_\n\n"
  },
  {
    "path": "dlib/graph_cuts/find_max_factor_graph_potts_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_\n#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include \"min_cut_abstract.h\"\n#include \"../graph_utils.h\"\n#include \"../array2d/array2d_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class potts_problem \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a boolean valued factor graph or graphical model \n                that can be efficiently operated on using graph cuts.  In particular, this \n                object defines the interface a MAP problem on a factor graph must \n                implement if it is to be solved using the find_max_factor_graph_potts() \n                routine defined at the bottom of this file.  \n\n                Note that there is no dlib::potts_problem object.  What you are looking \n                at here is simply the interface definition for a Potts problem.  You must \n                implement your own version of this object for the problem you wish to \n                solve and then pass it to the find_max_factor_graph_potts() routine.\n\n                Note also that a factor graph should not have any nodes which are \n                neighbors with themselves.  Additionally, the graph is undirected. This\n                mean that if A is a neighbor of B then B must be a neighbor of A for\n                the MAP problem to be valid.\n        !*/\n\n    public:\n\n        unsigned long number_of_nodes (\n        ) const; \n        /*!\n            ensures\n                - returns the number of nodes in the factor graph.  Or in other words, \n                  returns the number of variables in the MAP problem/Potts model.\n        !*/\n\n        unsigned long number_of_neighbors (\n            unsigned long idx\n        ) const; \n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns the number of neighbors of node idx.\n        !*/\n\n        // This is an optional variable which specifies a number that is always\n        // greater than or equal to number_of_neighbors(idx).  If you don't know\n        // the value at compile time then either don't include max_number_of_neighbors \n        // in your potts_problem object or set it to 0.\n        const static unsigned long max_number_of_neighbors = 0; \n\n        unsigned long get_neighbor (\n            unsigned long idx,\n            unsigned long n \n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n                - n < number_of_neighbors(idx)\n            ensures\n                - returns the node index value of the n-th neighbor of \n                  the node with index value idx.\n                - The neighbor relationship is reciprocal.  That is, if \n                  get_neighbor(A,i)==B then there is a value of j such \n                  that get_neighbor(B,j)==A.\n                - A node is never its own neighbor.  That is, there is\n                  no i such that get_neighbor(idx,i)==idx.\n        !*/\n\n        unsigned long get_neighbor_idx (\n            unsigned long idx1,\n            unsigned long idx2\n        ) const;\n        /*!\n            requires\n                - idx1 < number_of_nodes()\n                - idx2 < number_of_nodes()\n            ensures\n                - This function is basically the inverse of get_neighbor().\n                - returns a number IDX such that:\n                    - get_neighbor(idx1,IDX) == idx2\n                    - IDX < number_of_neighbors(idx1)\n        !*/\n\n        void set_label (\n            const unsigned long& idx,\n            node_label value\n        );\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - #get_label(idx) == value\n        !*/\n\n        node_label get_label (\n            const unsigned long& idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns the current label for the idx-th node.  This is a value which is\n                  0 if the node's label is false and is any other value if it is true.  \n\n                  Note that this value is not used by factor_value() or factor_value_disagreement().\n                  It is simply here to provide a mechanism for find_max_factor_graph_potts()\n                  to return its labeled result.  Additionally, the reason it returns a \n                  node_label rather than a bool is because doing it this way facilitates \n                  use of a graph cut algorithm for the solution of the MAP problem.  For \n                  more of an explanation you should read the paper referenced by the min_cut\n                  object.\n        !*/\n\n        // This typedef should be for a type like int or double.  It\n        // must also be capable of representing signed values.\n        typedef an_integer_or_real_type value_type;\n\n        value_type factor_value (\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns a value which indicates how \"good\" it is to assign the idx-th\n                  node the label of true.  The larger the value, the more desirable it is \n                  to give it this label.  Similarly, a negative value indicates that it is\n                  better to give the node a label of false.\n                - It is valid for the returned value to be positive or negative infinity.  \n                  A value of positive infinity indicates that the idx-th node must be labeled\n                  true while negative infinity means it must be labeled false.\n        !*/\n\n        value_type factor_value_disagreement (\n            unsigned long idx1, \n            unsigned long idx2\n        ) const;\n        /*!\n            requires\n                - idx1 < number_of_nodes()\n                - idx2 < number_of_nodes()\n                - idx1 != idx2\n                - the idx1-th node and idx2-th node are neighbors in the graph.  That is, \n                  get_neighbor(idx1,i)==idx2 for some value of i.\n            ensures\n                - returns a number >= 0.  This is the penalty for giving node idx1 and idx2\n                  different labels.  Larger values indicate a larger penalty.\n                - this function is symmetric.  That is, it is true that: \n                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)\n                - It is valid for the returned value to be positive infinity.  Returning\n                  infinity indicates that the idx1-th and idx2-th nodes must share the same \n                  label.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class potts_grid_problem \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a specialization of a potts_problem to the case where\n                the graph is a regular grid where each node is connected to its four\n                neighbors.  An example of this is an image where each pixel is a node\n                and is connected to its four immediate neighboring pixels.  Therefore,\n                this object defines the interface this special kind of MAP problem\n                must implement if it is to be solved by the find_max_factor_graph_potts(potts_grid_problem,array2d)\n                routine defined at the end of this file.\n\n\n                Note that all nodes always have four neighbors, even nodes on the edge\n                of the graph.  This is because these border nodes are connected to\n                the border nodes on the other side of the graph.  That is, the graph\n                \"wraps\" around at the borders.  \n        !*/\n\n    public:\n\n        // This typedef should be for a type like int or double.  It\n        // must also be capable of representing signed values.\n        typedef an_integer_or_real_type value_type;\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in the grid\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in the grid\n        !*/\n\n        value_type factor_value (\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < nr()*nc()\n            ensures\n                - The grid is represented in row-major-order format.  Therefore, idx\n                  identifies a node according to its position in the row-major-order \n                  representation of the grid graph.  Or in other words, idx corresponds\n                  to the following row and column location in the graph:\n                    - row == idx/nc()\n                    - col == idx%nc()\n                - returns a value which indicates how \"good\" it is to assign the idx-th \n                  node the label of true.  The larger the value, the more desirable it is \n                  to give it this label.  Similarly, a negative value indicates that it is\n                  better to give the node a label of false.\n                - It is valid for the returned value to be positive or negative infinity.  \n                  A value of positive infinity indicates that the idx-th node must be labeled\n                  true while negative infinity means it must be labeled false.\n        !*/\n\n        value_type factor_value_disagreement (\n            unsigned long idx1,\n            unsigned long idx2\n        ) const;\n        /*!\n            requires\n                - idx1 < nr()*nc()\n                - idx2 < nr()*nc()\n                - idx1 != idx2\n                - the idx1-th node and idx2-th node are neighbors in the grid graph.  \n            ensures\n                - The grid is represented in row-major-order format.  Therefore, idx1 and \n                  idx2 identify nodes according to their positions in the row-major-order \n                  representation of the grid graph.  For example, idx1 corresponds\n                  to the following row and column location in the graph:\n                    - row == idx1/nc()\n                    - col == idx1%nc()\n                - returns a number >= 0.  This is the penalty for giving node idx1 and idx2\n                  different labels.  Larger values indicate a larger penalty.\n                - this function is symmetric.  That is, it is true that: \n                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)\n                - It is valid for the returned value to be positive infinity.  Returning\n                  infinity indicates that the idx1-th and idx2-th nodes must share the same \n                  label.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_problem\n        >\n    typename potts_problem::value_type potts_model_score (\n        const potts_problem& prob \n    );\n    /*!\n        requires\n            - potts_problem == an object with an interface compatible with the potts_problem \n              object defined at the top of this file.\n            - for all valid i and j:\n                - prob.factor_value_disagreement(i,j) >= 0\n                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)\n        ensures\n            - computes the model score for the given potts_problem.  We define this\n              precisely below:\n                - let L(i) == the boolean label of the i-th variable in prob.  Or in other \n                  words, L(i) == (prob.get_label(i) != 0).\n                - let F == the sum of values of prob.factor_value(i) for only i values\n                  where L(i) == true.\n                - Let D == the sum of values of prob.factor_value_disagreement(i,j) \n                  for only i and j values which meet the following conditions:\n                    - i and j are neighbors in the graph defined by prob, that is,\n                      it is valid to call prob.factor_value_disagreement(i,j).\n                    - L(i) != L(j)\n                    - i < j\n                      (i.e. We want to make sure to only count the edge between i and j once)\n\n                - Then this function returns F - D\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type \n        >\n    typename graph_type::edge_type potts_model_score (\n        const graph_type& g,\n        const std::vector<node_label>& labels\n    );\n    /*!\n        requires\n            - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h\n            - graph_type::edge_type is some signed type such as int or double\n            - graph_type::type must be the same type as graph_type::edge_type \n            - graph_contains_length_one_cycle(g) == false\n            - for all valid i and j:\n                - edge(g,i,j) >= 0\n        ensures\n            - This function does the same thing as the version of potts_model_score()\n              defined above, except that this version operates on a dlib::graph\n              instead of a potts_problem object.\n            - computes the model score for the given graph and labeling.  We define this\n              precisely below:\n                - let L(i) == the boolean label of the i-th variable in g.  Or in other \n                  words, L(i) == (labels[i] != 0).\n                - let F == the sum of values of g.node(i).data for only i values\n                  where L(i) == true.\n                - Let D == the sum of values of edge(g,i,j) for only i and j \n                  values which meet the following conditions:\n                    - i and j are neighbors in the graph defined by g, that is,\n                      it is valid to call edge(g,i,j).\n                    - L(i) != L(j)\n                    - i < j\n                      (i.e. We want to make sure to only count the edge between i and j once)\n\n                - Then this function returns F - D\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_grid_problem,\n        typename mem_manager\n        >\n    typename potts_grid_problem::value_type potts_model_score (\n        const potts_grid_problem& prob,\n        const array2d<node_label,mem_manager>& labels\n    );\n    /*!\n        requires\n            - prob.nr() == labels.nr()\n            - prob.nc() == labels.nc()\n            - potts_grid_problem == an object with an interface compatible with the \n              potts_grid_problem object defined above.\n            - for all valid i and j:\n                - prob.factor_value_disagreement(i,j) >= 0\n                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)\n        ensures\n            - computes the model score for the given potts_grid_problem.  We define this\n              precisely below:\n                - let L(i) == the boolean label of the i-th variable in prob.  Or in other \n                  words, L(i) == (labels[i/labels.nc()][i%labels.nc()] != 0).\n                - let F == the sum of values of prob.factor_value(i) for only i values\n                  where L(i) == true.\n                - Let D == the sum of values of prob.factor_value_disagreement(i,j) \n                  for only i and j values which meet the following conditions:\n                    - i and j are neighbors in the graph defined by prob, that is,\n                      it is valid to call prob.factor_value_disagreement(i,j).\n                    - L(i) != L(j)\n                    - i < j\n                      (i.e. We want to make sure to only count the edge between i and j once)\n\n                - Then this function returns F - D\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_problem\n        >\n    void find_max_factor_graph_potts (\n        potts_problem& prob \n    );\n    /*!\n        requires\n            - potts_problem == an object with an interface compatible with the potts_problem \n              object defined at the top of this file.\n            - for all valid i and j:\n                - prob.factor_value_disagreement(i,j) >= 0\n                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)\n        ensures\n            - This function is a tool for exactly solving the MAP problem in a Potts\n              model.  In particular, this means that this function finds the assignments \n              to all the labels in prob which maximizes potts_model_score(#prob).\n            - The optimal labels are stored in #prob.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type \n        >\n    void find_max_factor_graph_potts (\n        const graph_type& g,\n        std::vector<node_label>& labels\n    );\n    /*!\n        requires\n            - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h\n            - graph_type::edge_type is some signed type such as int or double\n            - graph_type::type must be the same type as graph_type::edge_type \n            - graph_contains_length_one_cycle(g) == false\n            - for all valid i and j:\n                - edge(g,i,j) >= 0\n        ensures\n            - This routine simply converts g into a potts_problem and calls the\n              version of find_max_factor_graph_potts() defined above on it.  Therefore,\n              this routine is just a convenience wrapper that lets you use a dlib::graph\n              to represent a potts problem.  This means that this function maximizes \n              the value of potts_model_score(g, #labels).\n            - #labels.size() == g.number_of_nodes() \n            - for all valid i:  \n                - #labels[i] == the optimal label for g.node(i)\n            - The correspondence between g and a potts_problem is the following:\n                - the factor_value() for a node is stored in g.node(i).data.\n                - the factor_value_disagreement(i,j) is stored in edge(g,i,j).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename potts_grid_problem,\n        typename mem_manager\n        >\n    void find_max_factor_graph_potts (\n        const potts_grid_problem& prob,\n        array2d<node_label,mem_manager>& labels\n    );\n    /*!\n        requires\n            - potts_grid_problem == an object with an interface compatible with the \n              potts_grid_problem object defined above.\n            - for all valid i and j:\n                - prob.factor_value_disagreement(i,j) >= 0\n                - prob.factor_value_disagreement(i,j) == prob.factor_value_disagreement(j,i)\n        ensures\n            - This routine solves a version of a potts problem where the graph is a\n              regular grid where each node is connected to its four immediate neighbors.\n              In particular, this means that this function finds the assignments \n              to all the labels in prob which maximizes potts_model_score(prob,#labels).\n            - The optimal labels are stored in #labels.\n            - #labels.nr() == prob.nr()\n            - #labels.nc() == prob.nc()\n    !*/\n\n// ---------------------------------------------------------------------------------------- \n// ---------------------------------------------------------------------------------------- \n//    The following functions and interface definitions are convenience routines for use \n//    with the potts grid problem version of find_max_factor_graph_potts() defined above.\n// ---------------------------------------------------------------------------------------- \n// ---------------------------------------------------------------------------------------- \n\n    struct single_image_model \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines a slightly more convenient interface for creating\n                potts_grid_problems which operate on an image.  In this case, the goal \n                is to assign a binary label to each pixel in an image.  In particular, \n                this object defines the interface used by the make_potts_grid_problem() \n                routine defined below. \n\n                In the following comments, we will refer to the image supplied to \n                make_potts_grid_problem() as IMG.\n        !*/\n\n        // This typedef should be for a type like int or double.  It\n        // must also be capable of representing signed values.\n        typedef an_integer_or_real_type value_type;\n\n        template <typename pixel_type>\n        value_type factor_value (\n            const pixel_type& v\n        ) const;\n        /*!\n            requires\n                - v is a pixel value from IMG.\n            ensures\n                - returns a value which indicates how \"good\" it is to assign the location\n                  in IMG corresponding to v with the label of true.  The larger the value, \n                  the more desirable it is to give it this label.  Similarly, a negative \n                  value indicates that it is better to give the node a label of false.\n                - It is valid for the returned value to be positive or negative infinity.  \n                  A value of positive infinity indicates that the pixel must be labeled\n                  true while negative infinity means it must be labeled false.\n        !*/\n\n        template <typename pixel_type>\n        value_type factor_value_disagreement (\n            const pixel_type& v1,\n            const pixel_type& v2 \n        ) const;\n        /*!\n            requires\n                - v1 and v2 are pixel values from neighboring pixels in the IMG image.\n            ensures\n                - returns a number >= 0.  This is the penalty for giving neighboring pixels \n                  with values v1 and v2 different labels.  Larger values indicate a larger \n                  penalty.\n                - this function is symmetric.  That is, it is true that: \n                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)\n                - It is valid for the returned value to be positive infinity.  Returning\n                  infinity indicates that the idx1-th and idx2-th nodes must share the same \n                  label.\n        !*/\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n    struct pair_image_model \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines a slightly more convenient interface for creating\n                potts_grid_problems which operate on a pair of identically sized images.\n                In this case, the goal is to assign a label to each pixel in the first\n                image of the pair.  In particular, this object defines the interface\n                used by the make_potts_grid_problem() routine defined below. \n\n                In the following comments, we will refer to the two images supplied to \n                make_potts_grid_problem() as IMG1 and IMG2.  The goal of the potts\n                problem will be to assign labels to each pixel in IMG1 (IMG2 is\n                not labeled, it is simply used as a place to keep auxiliary data).\n        !*/\n\n        // This typedef should be for a type like int or double.  It\n        // must also be capable of representing signed values.\n        typedef an_integer_or_real_type value_type;\n\n        template <typename pixel_type1, typename pixel_type2>\n        value_type factor_value (\n            const pixel_type1& v1,\n            const pixel_type2& v2 \n        ) const;\n        /*!\n            requires\n                - v1 and v2 are corresponding pixels from IMG1 and IMG2 respectively.\n                  That is, both pixel values have the same coordinates in the images.\n                  So for example, if v1 is the value of IMG1[4][5] then v2 is the value\n                  of IMG2[4][5].\n            ensures\n                - returns a value which indicates how \"good\" it is to assign the location\n                  in IMG1 corresponding to v1 with the label of true.  The larger the value, \n                  the more desirable it is to give it this label.  Similarly, a negative \n                  value indicates that it is better to give the node a label of false.\n                - It is valid for the returned value to be positive or negative infinity.  \n                  A value of positive infinity indicates that the pixel must be labeled\n                  true while negative infinity means it must be labeled false.\n        !*/\n\n        template <typename pixel_type>\n        value_type factor_value_disagreement (\n            const pixel_type& v1,\n            const pixel_type& v2 \n        ) const;\n        /*!\n            requires\n                - v1 and v2 are pixel values from neighboring pixels in the IMG1 image.\n            ensures\n                - returns a number >= 0.  This is the penalty for giving neighboring pixels \n                  with values v1 and v2 different labels.  Larger values indicate a larger \n                  penalty.\n                - this function is symmetric.  That is, it is true that: \n                  factor_value_disagreement(i,j) == factor_value_disagreement(j,i)\n                - It is valid for the returned value to be positive infinity.  Returning\n                  infinity indicates that the idx1-th and idx2-th nodes must share the same \n                  label.\n        !*/\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n    template <\n        typename single_image_model,\n        typename pixel_type,\n        typename mem_manager\n        >\n    potts_grid_problem make_potts_grid_problem (\n        const single_image_model& model,\n        const array2d<pixel_type,mem_manager>& img\n    );\n    /*!\n        requires\n            - single_image_model == an object with an interface compatible with the \n              single_image_model object defined above.\n            - for all valid i and j:\n                - model.factor_value_disagreement(i,j) >= 0\n                - model.factor_value_disagreement(i,j) == model.factor_value_disagreement(j,i)\n        ensures\n            - returns a potts_grid_problem which can be solved using the \n              find_max_factor_graph_potts(prob,array2d) routine defined above.  That is,\n              given an image to store the labels, the following statement would solve the \n              potts problem defined by the given model and image:\n                find_max_factor_graph_potts(make_potts_grid_problem(model,img),labels);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pair_image_model,\n        typename pixel_type1,\n        typename pixel_type2,\n        typename mem_manager\n        >\n    potts_grid_problem make_potts_grid_problem (\n        const pair_image_model& model,\n        const array2d<pixel_type1,mem_manager>& img1,\n        const array2d<pixel_type2,mem_manager>& img2\n    );\n    /*!\n        requires\n            - get_rect(img1) == get_rect(img2)\n              (i.e. img1 and img2 have the same dimensions)\n            - pair_image_model == an object with an interface compatible with the \n              pair_image_model object defined above.\n            - for all valid i and j:\n                - model.factor_value_disagreement(i,j) >= 0\n                - model.factor_value_disagreement(i,j) == model.factor_value_disagreement(j,i)\n        ensures\n            - returns a potts_grid_problem which can be solved using the \n              find_max_factor_graph_potts(prob,array2d) routine defined above.  That is,\n              given an image to store the labels, the following statement would solve the \n              potts problem defined by the given model and pair of images:\n                find_max_factor_graph_potts(make_potts_grid_problem(model,img1,img2),labels);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_PoTTS_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_cuts/general_flow_graph.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GENERAL_FLOW_GRaPH_Hh_\n#define DLIB_GENERAL_FLOW_GRaPH_Hh_\n\n#include \"../graph_utils.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n        template <\n            typename directed_graph_type\n            >\n        class general_flow_graph \n        {\n            /*!\n                this is a utility class used by dlib::min_cut to convert a directed_graph\n                into the kind of flow graph expected by the min_cut object's main block\n                of code.\n            !*/\n\n            directed_graph_type& g;\n\n            typedef typename directed_graph_type::node_type node_type;\n            typedef typename directed_graph_type::type node_label;\n\n        public:\n\n            general_flow_graph(\n                directed_graph_type& g_\n            ) : g(g_)\n            {\n            }\n\n            class out_edge_iterator\n            {\n                friend class general_flow_graph;\n                unsigned long idx; // base node idx\n                unsigned long cnt; // count over the neighbors of idx\n            public:\n\n                out_edge_iterator(\n                ):idx(0),cnt(0) {}\n\n                out_edge_iterator(\n                    unsigned long idx_,\n                    unsigned long cnt_\n                ):idx(idx_),cnt(cnt_)\n                {}\n\n                bool operator!= (\n                    const out_edge_iterator& item\n                ) const { return cnt != item.cnt; }\n\n                out_edge_iterator& operator++(\n                )\n                {\n                    ++cnt;\n                    return *this;\n                }\n            };\n\n            class in_edge_iterator\n            {\n\n                friend class general_flow_graph;\n                unsigned long idx; // base node idx\n                unsigned long cnt; // count over the neighbors of idx\n            public:\n\n                in_edge_iterator(\n                ):idx(0),cnt(0) {}\n\n                in_edge_iterator(\n                    unsigned long idx_,\n                    unsigned long cnt_\n                ):idx(idx_),cnt(cnt_)\n                {}\n\n                bool operator!= (\n                    const in_edge_iterator& item\n                ) const { return cnt != item.cnt; }\n\n                in_edge_iterator& operator++(\n                )\n                {\n                    ++cnt;\n                    return *this;\n                }\n            };\n\n            unsigned long number_of_nodes (\n            ) const { return g.number_of_nodes(); }\n\n            out_edge_iterator out_begin(\n                const unsigned long& it\n            ) const { return out_edge_iterator(it, 0); }\n\n            in_edge_iterator in_begin(\n                const unsigned long& it\n            ) const { return in_edge_iterator(it, 0); }\n\n            out_edge_iterator out_end(\n                const unsigned long& it\n            ) const { return out_edge_iterator(it, g.node(it).number_of_children()); }\n\n            in_edge_iterator in_end(\n                const unsigned long& it\n            ) const { return in_edge_iterator(it, g.node(it).number_of_parents()); }\n\n            unsigned long node_id (\n                const out_edge_iterator& it\n            ) const { return g.node(it.idx).child(it.cnt).index(); }\n            unsigned long node_id (\n                const in_edge_iterator& it\n            ) const { return g.node(it.idx).parent(it.cnt).index(); }\n\n            typedef typename directed_graph_type::edge_type edge_type;\n\n            edge_type get_flow (const unsigned long& it1,     const unsigned long& it2) const\n            {\n                return edge(g, it1, it2);\n            }\n            edge_type get_flow (const out_edge_iterator& it) const\n            {\n                return g.node(it.idx).child_edge(it.cnt);\n            }\n            edge_type get_flow (const in_edge_iterator& it) const\n            {\n                return g.node(it.idx).parent_edge(it.cnt);\n            }\n\n            void adjust_flow (\n                const unsigned long& it1,\n                const unsigned long& it2,\n                const edge_type& value\n            )\n            {\n                edge(g, it1, it2) += value;\n                edge(g, it2, it1) -= value;\n            }\n\n            void set_label (\n                const unsigned long& it,\n                node_label value\n            )\n            {\n                g.node(it).data = value;\n            }\n\n            node_label get_label (\n                const unsigned long& it\n            ) const\n            {\n                return g.node(it).data;\n            }\n\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GENERAL_FLOW_GRaPH_Hh_\n\n"
  },
  {
    "path": "dlib/graph_cuts/general_potts_problem.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GENERAL_POTTS_PRoBLEM_Hh_\n#define DLIB_GENERAL_POTTS_PRoBLEM_Hh_\n\n#include \"../graph_utils.h\"\n#include \"min_cut.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename graph_type\n            >\n        class general_potts_problem \n        {\n\n            const graph_type& g;\n            std::vector<node_label>& labels;\n        public:\n            general_potts_problem (\n                const graph_type& g_,\n                std::vector<node_label>& labels_\n            ) : g(g_), labels(labels_)\n            {\n                labels.resize(g.number_of_nodes());\n            }\n\n            unsigned long number_of_nodes (\n            ) const { return g.number_of_nodes(); }\n\n            unsigned long number_of_neighbors (\n                unsigned long idx\n            ) const { return g.node(idx).number_of_neighbors(); }\n\n            unsigned long get_neighbor (\n                unsigned long idx,\n                unsigned long n \n            ) const { return g.node(idx).neighbor(n).index(); }\n\n            unsigned long get_neighbor_idx (\n                unsigned long idx1,\n                unsigned long idx2\n            ) const\n            {\n                for (unsigned long i = 0; i < g.node(idx1).number_of_neighbors(); ++i)\n                {\n                    if (g.node(idx1).neighbor(i).index() == idx2)\n                        return i;\n                }\n\n                // This should never ever execute\n                return 0;\n            }\n\n            void set_label (\n                const unsigned long& idx,\n                node_label value\n            )\n            {\n                labels[idx] = value;\n            }\n\n            node_label get_label (\n                const unsigned long& idx\n            ) const { return labels[idx]; }\n\n            typedef typename graph_type::edge_type value_type;\n\n            value_type factor_value (\n                unsigned long idx\n            ) const\n            {\n                return g.node(idx).data;\n            }\n\n            value_type factor_value_disagreement (\n                unsigned long idx1, \n                unsigned long idx2\n            ) const\n            {\n                return edge(g, idx1, idx2);\n            }\n\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GENERAL_POTTS_PRoBLEM_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_cuts/graph_labeler.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_LaBELER_Hh_\n#define DLIB_GRAPH_LaBELER_Hh_\n\n#include \"graph_labeler_abstract.h\"\n#include \"../matrix.h\"\n#include \"../string.h\"\n#include <vector>\n#include \"find_max_factor_graph_potts.h\"\n#include \"../svm/sparse_vector.h\"\n#include \"../graph.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    class graph_labeler \n    {\n\n    public:\n\n        typedef std::vector<bool> label_type;\n        typedef label_type result_type;\n\n        graph_labeler()\n        {\n        }\n\n        graph_labeler(\n            const vector_type& edge_weights_,\n            const vector_type& node_weights_\n        ) : \n            edge_weights(edge_weights_),\n            node_weights(node_weights_)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(edge_weights.size() == 0 || min(edge_weights) >= 0,\n                    \"\\t graph_labeler::graph_labeler()\"\n                    << \"\\n\\t Invalid inputs were given to this function.\"\n                    << \"\\n\\t min(edge_weights): \" << min(edge_weights)\n                    << \"\\n\\t this:              \" << this\n                    );\n        }\n\n        const vector_type& get_edge_weights (\n        ) const { return edge_weights; }\n\n        const vector_type& get_node_weights (\n        ) const { return node_weights; }\n\n        template <typename graph_type>\n        void operator() (\n            const graph_type& sample,\n            std::vector<bool>& labels \n        ) const\n        {\n            // make sure requires clause is not broken\n#ifdef ENABLE_ASSERTS\n            DLIB_ASSERT(graph_contains_length_one_cycle(sample) == false,\n                        \"\\t void graph_labeler::operator()\"\n                        << \"\\n\\t Invalid inputs were given to this function.\"\n                        << \"\\n\\t get_edge_weights().size(): \" << get_edge_weights().size()\n                        << \"\\n\\t get_node_weights().size(): \" << get_node_weights().size()\n                        << \"\\n\\t graph_contains_length_one_cycle(sample): \" << graph_contains_length_one_cycle(sample)\n                        << \"\\n\\t this:                      \" << this\n                    );\n            for (unsigned long i = 0; i < sample.number_of_nodes(); ++i)\n            {\n                if (is_matrix<vector_type>::value &&\n                    is_matrix<typename graph_type::type>::value)\n                {\n                    // check that dot() is legal.\n                    DLIB_ASSERT((unsigned long)get_node_weights().size() == (unsigned long)sample.node(i).data.size(),\n                                \"\\t void graph_labeler::operator()\"\n                                << \"\\n\\t The size of the node weight vector must match the one in the node.\"\n                                << \"\\n\\t get_node_weights().size():  \" << get_node_weights().size()\n                                << \"\\n\\t sample.node(i).data.size(): \" << sample.node(i).data.size()\n                                << \"\\n\\t i: \" << i \n                                << \"\\n\\t this:              \" << this\n                            );\n                }\n\n                for (unsigned long n = 0; n < sample.node(i).number_of_neighbors(); ++n)\n                {\n                    if (is_matrix<vector_type>::value &&\n                        is_matrix<typename graph_type::edge_type>::value)\n                    {\n                        // check that dot() is legal.\n                        DLIB_ASSERT((unsigned long)get_edge_weights().size() == (unsigned long)sample.node(i).edge(n).size(),\n                                    \"\\t void graph_labeler::operator()\"\n                                    << \"\\n\\t The size of the edge weight vector must match the one in graph's edge.\"\n                                    << \"\\n\\t get_edge_weights().size():  \" << get_edge_weights().size()\n                                    << \"\\n\\t sample.node(i).edge(n).size(): \" << sample.node(i).edge(n).size()\n                                    << \"\\n\\t i: \" << i \n                                    << \"\\n\\t this:              \" << this\n                        );\n                    }\n\n                    DLIB_ASSERT(sample.node(i).edge(n).size() == 0 || min(sample.node(i).edge(n)) >= 0,\n                                \"\\t void graph_labeler::operator()\"\n                                << \"\\n\\t No edge vectors are allowed to have negative elements.\"\n                                << \"\\n\\t min(sample.node(i).edge(n)): \" << min(sample.node(i).edge(n))\n                                << \"\\n\\t i:    \" << i \n                                << \"\\n\\t n:    \" << n \n                                << \"\\n\\t this: \" << this\n                    );\n                }\n            }\n#endif\n\n\n            graph<double,double>::kernel_1a g; \n            copy_graph_structure(sample, g);\n            for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n            {\n                g.node(i).data = dot(node_weights, sample.node(i).data);\n\n                for (unsigned long n = 0; n < g.node(i).number_of_neighbors(); ++n)\n                {\n                    const unsigned long j = g.node(i).neighbor(n).index();\n                    // Don't compute an edge weight more than once. \n                    if (i < j)\n                    {\n                        g.node(i).edge(n) = dot(edge_weights, sample.node(i).edge(n));\n                    }\n                }\n\n            }\n\n            labels.clear();\n            std::vector<node_label> temp;\n            find_max_factor_graph_potts(g, temp);\n            for (unsigned long i = 0; i < temp.size(); ++i)\n            {\n                if (temp[i] != 0)\n                    labels.push_back(true);\n                else\n                    labels.push_back(false);\n            }\n        }\n\n        template <typename graph_type>\n        std::vector<bool> operator() (\n            const graph_type& sample \n        ) const\n        {\n            std::vector<bool> temp;\n            (*this)(sample, temp);\n            return temp;\n        }\n\n    private:\n\n        vector_type edge_weights;\n        vector_type node_weights;\n    };\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    void serialize (\n        const graph_labeler<vector_type>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.get_edge_weights(), out);\n        serialize(item.get_node_weights(), out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    void deserialize (\n        graph_labeler<vector_type>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n        {\n            throw dlib::serialization_error(\"While deserializing graph_labeler, found unexpected version number of \" + \n                                            cast_to_string(version) + \".\");\n        }\n\n        vector_type edge_weights, node_weights;\n        deserialize(edge_weights, in);\n        deserialize(node_weights, in);\n\n        item = graph_labeler<vector_type>(edge_weights, node_weights);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GRAPH_LaBELER_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_cuts/graph_labeler_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GRAPH_LaBELER_ABSTRACT_Hh_\n#ifdef DLIB_GRAPH_LaBELER_ABSTRACT_Hh_\n\n#include \"find_max_factor_graph_potts_abstract.h\"\n#include \"../graph/graph_kernel_abstract.h\"\n#include \"../matrix/matrix_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    class graph_labeler \n    {\n        /*!\n            REQUIREMENTS ON vector_type\n                - vector_type is a dlib::matrix capable of representing column \n                  vectors or it is a sparse vector type as defined in dlib/svm/sparse_vector_abstract.h.  \n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for labeling each node in a graph with a value \n                of true or false, subject to a labeling consistency constraint between \n                nodes that share an edge.  In particular, this object is useful for \n                representing a graph labeling model learned via some machine learning \n                method.\n                \n                To elaborate, suppose we have a graph we want to label.  Moreover, \n                suppose we can assign a score to each node which represents how much \n                we want to label the node as true, and we also have scores for each \n                edge which represent how much we wanted the nodes sharing the edge to \n                have the same label.  If we could do this then we could find the optimal \n                labeling using the find_max_factor_graph_potts() routine.  Therefore, \n                the graph_labeler is just an object which contains the necessary data \n                to compute these score functions and then call find_max_factor_graph_potts().  \n                Additionally, this object uses linear functions to represent these score \n                functions.    \n\n            THREAD SAFETY\n                It is always safe to use distinct instances of this object in different\n                threads.  However, when a single instance is shared between threads then\n                the following rules apply:\n                    It is safe to call the const members of this object from multiple\n                    threads.  This is because the const members are purely read-only\n                    operations.  However, any operation that modifies a graph_labeler is\n                    not threadsafe.\n        !*/\n\n    public:\n\n        typedef std::vector<bool> label_type;\n        typedef label_type result_type;\n\n        graph_labeler(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n                - #get_node_weights() == an initial value of type vector_type.\n                - #get_edge_weights() == an initial value of type vector_type.\n        !*/\n\n        graph_labeler(\n            const vector_type& edge_weights,\n            const vector_type& node_weights\n        );\n        /*!\n            requires\n                - min(edge_weights) >= 0\n            ensures\n                - #get_edge_weights() == edge_weights\n                - #get_node_weights() == node_weights\n        !*/\n\n        const vector_type& get_edge_weights (\n        ) const; \n        /*!\n            ensures\n                - Recall that the score function for an edge is a linear function of\n                  the vector stored at that edge.  This means there is some vector, E,\n                  which we dot product with the vector in the graph to compute the \n                  score.  Therefore, this function returns that E vector which defines \n                  the edge score function.\n        !*/\n\n        const vector_type& get_node_weights (\n        ) const; \n        /*!\n            ensures\n                - Recall that the score function for a node is a linear function of\n                  the vector stored in that node.  This means there is some vector, W, \n                  which we dot product with the vector in the graph to compute the score.  \n                  Therefore, this function returns that W vector which defines the node \n                  score function.\n        !*/\n\n        template <typename graph_type>\n        void operator() (\n            const graph_type& sample,\n            std::vector<bool>& labels \n        ) const;\n        /*!\n            requires\n                - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h\n                - graph_type::type and graph_type::edge_type must be either matrix objects\n                  capable of representing column vectors or some kind of sparse vector\n                  type as defined in dlib/svm/sparse_vector_abstract.h.\n                - graph_contains_length_one_cycle(sample) == false\n                - for all valid i and j:\n                    - min(edge(sample,i,j)) >= 0\n                    - it must be legal to call dot(edge(sample,i,j), get_edge_weights())\n                    - it must be legal to call dot(sample.node(i).data, get_node_weights())\n            ensures\n                - Computes a labeling for each node in the given graph and stores the result\n                  in #labels.  \n                - #labels.size() == sample.number_of_nodes()\n                - for all valid i:\n                    - #labels[i] == the label of the node sample.node(i).\n                - The labels are computed by creating a graph, G, with scalar values on each node \n                  and edge.  The scalar values are calculated according to the following:\n                    - for all valid i:\n                        - G.node(i).data == dot(get_node_weights(), sample.node(i).data)\n                    - for all valid i and j:\n                        - edge(G,i,j) == dot(get_edge_weights(), edge(sample,i,j))\n                  Then the labels are computed by calling find_max_factor_graph_potts(G,#labels).\n        !*/\n\n        template <typename graph_type>\n        std::vector<bool> operator() (\n            const graph_type& sample \n        ) const;\n        /*!\n            requires\n                - graph_type is an implementation of dlib/graph/graph_kernel_abstract.h\n                - graph_contains_length_one_cycle(sample) == false\n                - for all valid i and j:\n                    - min(edge(sample,i,j)) >= 0\n                    - it must be legal to call dot(edge(sample,i,j), get_edge_weights())\n                    - it must be legal to call dot(sample.node(i).data, get_node_weights())\n            ensures\n                - Performs (*this)(sample, labels); return labels;\n                  (i.e. This is just another version of the above operator() routine\n                  but instead of returning the labels via the second argument, it\n                  returns them as the normal return value).\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    void serialize (\n        const graph_labeler<vector_type>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    void deserialize (\n        graph_labeler<vector_type>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GRAPH_LaBELER_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/graph_cuts/min_cut.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MIN_CuT_Hh_\n#define DLIB_MIN_CuT_Hh_\n\n#include \"min_cut_abstract.h\"\n#include \"../matrix.h\"\n#include \"general_flow_graph.h\"\n#include \"../is_kind.h\"\n\n#include <iostream>\n#include <fstream>\n#include <deque>\n\n\n// ----------------------------------------------------------------------------------------\n\n\nnamespace dlib\n{\n\n    typedef unsigned char node_label;\n\n// ----------------------------------------------------------------------------------------\n\n    const node_label SOURCE_CUT = 0;\n    const node_label SINK_CUT = 254;\n    const node_label FREE_NODE = 255;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename flow_graph>\n    typename disable_if<is_directed_graph<flow_graph>,typename flow_graph::edge_type>::type \n    graph_cut_score (\n        const flow_graph& g\n    )\n    {\n        typedef typename flow_graph::edge_type edge_weight_type;\n        edge_weight_type score = 0;\n        typedef typename flow_graph::out_edge_iterator out_edge_iterator;\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            if (g.get_label(i) != SOURCE_CUT)\n                continue;\n\n            for (out_edge_iterator n = g.out_begin(i); n != g.out_end(i); ++n)\n            {\n                if (g.get_label(g.node_id(n)) != SOURCE_CUT)\n                {\n                    score += g.get_flow(n);\n                }\n            }\n        }\n\n        return score;\n    }\n\n    template <typename directed_graph>\n    typename enable_if<is_directed_graph<directed_graph>,typename directed_graph::edge_type>::type \n    graph_cut_score (\n        const directed_graph& g\n    )\n    {\n        return graph_cut_score(dlib::impl::general_flow_graph<const directed_graph>(g));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class min_cut\n    {\n\n    public:\n\n        min_cut()\n        {\n        }\n\n        min_cut( const min_cut& )\n        {\n            // Intentionally left empty since all the member variables\n            // don't logically contribute to the state of this object.\n            // This copy constructor is here to explicitly avoid the overhead\n            // of copying these transient variables.  \n        }\n\n        template <\n            typename directed_graph\n            >\n        typename enable_if<is_directed_graph<directed_graph> >::type operator() (\n            directed_graph& g,\n            const unsigned long source_node,\n            const unsigned long sink_node\n        ) const\n        {\n            DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n                        \"\\t void min_cut::operator()\"\n                        << \"\\n\\t Invalid arguments were given to this function.\"\n                        );\n            DLIB_ASSERT(graph_has_symmetric_edges(g) == true,\n                        \"\\t void min_cut::operator()\"\n                        << \"\\n\\t Invalid arguments were given to this function.\"\n                        );\n\n            dlib::impl::general_flow_graph<directed_graph> temp(g);\n            (*this)(temp, source_node, sink_node);\n        }\n\n        template <\n            typename flow_graph\n            >\n        typename disable_if<is_directed_graph<flow_graph> >::type operator() (\n            flow_graph& g,\n            const unsigned long source_node,\n            const unsigned long sink_node\n        ) const\n        {\n#ifdef ENABLE_ASSERTS\n            DLIB_ASSERT(source_node != sink_node &&\n                        source_node < g.number_of_nodes() &&\n                        sink_node < g.number_of_nodes(),\n                    \"\\t void min_cut::operator()\"\n                    << \"\\n\\t Invalid arguments were given to this function.\"\n                    << \"\\n\\t g.number_of_nodes(): \" << g.number_of_nodes() \n                    << \"\\n\\t source_node: \" << source_node \n                    << \"\\n\\t sink_node:   \" << sink_node \n                    << \"\\n\\t this:   \" << this\n            );\n\n            for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n            {\n                typename flow_graph::out_edge_iterator j, end = g.out_end(i);\n                for (j = g.out_begin(i); j != end; ++j)\n                {\n                    const unsigned long jj = g.node_id(j);\n                    DLIB_ASSERT(g.get_flow(i,jj) >= 0,\n                                \"\\t void min_cut::operator()\"\n                                << \"\\n\\t Invalid inputs were given to this function.\" \n                                << \"\\n\\t i: \"<< i \n                                << \"\\n\\t jj: \"<< jj\n                                << \"\\n\\t g.get_flow(i,jj): \"<< g.get_flow(i,jj)\n                                << \"\\n\\t this: \"<< this\n                                );\n\n                }\n            }\n#endif\n            parent.clear();\n            active.clear();\n            orphans.clear();\n\n            typedef typename flow_graph::edge_type edge_type;\n            COMPILE_TIME_ASSERT(is_signed_type<edge_type>::value);\n\n            typedef typename flow_graph::out_edge_iterator out_edge_iterator;\n            typedef typename flow_graph::in_edge_iterator in_edge_iterator;\n\n            // initialize labels\n            for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n                g.set_label(i, FREE_NODE);\n\n            g.set_label(source_node, SOURCE_CUT);\n            g.set_label(sink_node, SINK_CUT);\n\n            // used to indicate \"no parent\"\n            const unsigned long no_parent = g.number_of_nodes();\n\n            parent.assign(g.number_of_nodes(), no_parent);\n\n            time = 1;\n            dist.assign(g.number_of_nodes(), 0);\n            ts.assign(g.number_of_nodes(), time);\n\n            active.push_back(source_node);\n            active.push_back(sink_node);\n\n\n            in_edge_iterator in_begin = g.in_begin(active[0]);\n            out_edge_iterator out_begin = g.out_begin(active[0]);\n\n            unsigned long source_side, sink_side;\n            while (grow(g,source_side,sink_side, in_begin, out_begin))\n            {\n                ++time;\n                ts[source_node] = time;\n                ts[sink_node] = time;\n\n                augment(g, source_node, sink_node, source_side, sink_side);\n                adopt(g, source_node, sink_node);\n            }\n\n        }\n\n\n    private:\n\n        unsigned long distance_to_origin (\n            const unsigned long no_parent,\n            unsigned long p,\n            unsigned long \n        ) const\n        {\n            unsigned long start = p;\n            unsigned long count = 0;\n            while (p != no_parent)\n            {\n                if (ts[p] == time)\n                {\n                    count += dist[p];\n\n                    unsigned long count_down = count;\n                    // adjust the dist and ts for the nodes on this path.\n                    while (start != p)\n                    {\n                        ts[start] = time;\n                        dist[start] = count_down;\n                        --count_down;\n                        start = parent[start];\n                    }\n\n                    return count;\n                }\n                p = parent[p];\n                ++count;\n            }\n\n            return std::numeric_limits<unsigned long>::max();\n        }\n\n        template <typename flow_graph>\n        void adopt (\n            flow_graph& g,\n            const unsigned long source,\n            const unsigned long sink\n        ) const\n        {\n            typedef typename flow_graph::out_edge_iterator out_edge_iterator;\n            typedef typename flow_graph::in_edge_iterator in_edge_iterator;\n\n            // used to indicate \"no parent\"\n            const unsigned long no_parent = g.number_of_nodes();\n\n            while (orphans.size() > 0)\n            {\n                const unsigned long p = orphans.back();\n                orphans.pop_back();\n\n                const unsigned char label_p = g.get_label(p);\n\n                // Try to find a valid parent for p.\n                if (label_p == SOURCE_CUT)\n                {\n                    const in_edge_iterator begin(g.in_begin(p));\n                    const in_edge_iterator end(g.in_end(p));\n                    unsigned long best_dist = std::numeric_limits<unsigned long>::max();\n                    unsigned long best_node = 0;\n                    for(in_edge_iterator q = begin; q != end; ++q)\n                    {\n                        const unsigned long id = g.node_id(q);\n\n                        if (g.get_label(id) != label_p || g.get_flow(q) <= 0 )\n                            continue;\n\n                        unsigned long temp = distance_to_origin(no_parent, id,source);\n                        if (temp < best_dist)\n                        {\n                            best_dist = temp;\n                            best_node = id;\n                        }\n\n                    }\n                    if (best_dist != std::numeric_limits<unsigned long>::max())\n                    {\n                        parent[p] = best_node;\n                        dist[p] = dist[best_node] + 1;\n                        ts[p] = time;\n                    }\n\n                    // if we didn't find a parent for p\n                    if (parent[p] == no_parent)\n                    {\n                        for(in_edge_iterator q = begin; q != end; ++q)\n                        {\n                            const unsigned long id = g.node_id(q);\n\n                            if (g.get_label(id) != SOURCE_CUT)\n                                continue;\n\n                            if (g.get_flow(q) > 0)\n                                active.push_back(id);\n\n                            if (parent[id] == p)\n                            {\n                                parent[id] = no_parent;\n                                orphans.push_back(id);\n                            }\n                        }\n                        g.set_label(p, FREE_NODE);\n                    }\n                }\n                else\n                {\n                    unsigned long best_node = 0;\n                    unsigned long best_dist = std::numeric_limits<unsigned long>::max();\n                    const out_edge_iterator begin(g.out_begin(p));\n                    const out_edge_iterator end(g.out_end(p));\n                    for(out_edge_iterator q = begin; q != end; ++q)\n                    {\n                        const unsigned long id = g.node_id(q);\n                        if (g.get_label(id) != label_p || g.get_flow(q) <= 0)\n                            continue;\n\n                        unsigned long temp = distance_to_origin(no_parent, id,sink);\n\n                        if (temp < best_dist)\n                        {\n                            best_dist = temp;\n                            best_node = id;\n                        }\n                    }\n\n                    if (best_dist != std::numeric_limits<unsigned long>::max())\n                    {\n                        parent[p] = best_node;\n                        dist[p] = dist[best_node] + 1;\n                        ts[p] = time;\n                    }\n\n                    // if we didn't find a parent for p\n                    if (parent[p] == no_parent)\n                    {\n                        for(out_edge_iterator q = begin; q != end; ++q)\n                        {\n                            const unsigned long id = g.node_id(q);\n\n                            if (g.get_label(id) != SINK_CUT)\n                                continue;\n\n                            if (g.get_flow(q) > 0)\n                                active.push_back(id);\n\n                            if (parent[id] == p)\n                            {\n                                parent[id] = no_parent;\n                                orphans.push_back(id);\n                            }\n                        }\n\n                        g.set_label(p, FREE_NODE);\n                    }\n                }\n\n                \n            }\n\n        }\n\n        template <typename flow_graph>\n        void augment (\n            flow_graph& g,\n            const unsigned long& source,\n            const unsigned long& sink,\n            const unsigned long& source_side, \n            const unsigned long& sink_side\n        ) const\n        {\n            typedef typename flow_graph::edge_type edge_type;\n\n            // used to indicate \"no parent\"\n            const unsigned long no_parent = g.number_of_nodes();\n\n            unsigned long s = source_side;\n            unsigned long t = sink_side;\n            edge_type min_cap = g.get_flow(s,t);\n\n            // find the bottleneck capacity on the current path.\n\n            // check from source_side back to the source for the min capacity link.\n            t = s;\n            while (t != source)\n            {\n                s = parent[t];\n                const edge_type temp = g.get_flow(s, t);\n                if (temp < min_cap)\n                {\n                    min_cap = temp;\n                }\n                t = s;\n            }\n\n            // check from sink_side back to the sink for the min capacity link\n            s = sink_side;\n            while (s != sink)\n            {\n                t = parent[s];\n                const edge_type temp = g.get_flow(s, t);\n                if (temp < min_cap)\n                {\n                    min_cap = temp;\n                }\n                s = t;\n            }\n\n\n            // now push the max possible amount of flow though the path\n            s = source_side;\n            t = sink_side;\n            g.adjust_flow(t,s, min_cap);\n\n            // trace back towards the source\n            t = s;\n            while (t != source)\n            {\n                s = parent[t];\n                g.adjust_flow(t,s, min_cap);\n                if (g.get_flow(s,t) <= 0)\n                {\n                    parent[t] = no_parent;\n                    orphans.push_back(t);\n                }\n\n                t = s;\n            }\n\n            // trace back towards the sink \n            s = sink_side;\n            while (s != sink)\n            {\n                t = parent[s];\n                g.adjust_flow(t,s, min_cap);\n                if (g.get_flow(s,t) <= 0)\n                {\n                    parent[s] = no_parent;\n                    orphans.push_back(s);\n                }\n                s = t;\n            }\n        }\n\n        template <typename flow_graph>\n        bool grow (\n            flow_graph& g,\n            unsigned long& source_side, \n            unsigned long& sink_side,\n            typename flow_graph::in_edge_iterator& in_begin,\n            typename flow_graph::out_edge_iterator& out_begin\n        ) const\n        /*!\n            ensures\n                - if (an augmenting path was found) then \n                    - returns true\n                    - (#source_side, #sink_side) == the point where the two trees meet.\n                      #source_side is part of the source tree and #sink_side is part of\n                      the sink tree.\n                - else\n                    - returns false\n        !*/\n        {\n            typedef typename flow_graph::out_edge_iterator out_edge_iterator;\n            typedef typename flow_graph::in_edge_iterator in_edge_iterator;\n\n\n            while (active.size() != 0)\n            {\n                // pick an active node\n                const unsigned long A = active[0];\n\n                const unsigned char label_A = g.get_label(A);\n\n                // process its neighbors\n                if (label_A == SOURCE_CUT)\n                {\n                    const out_edge_iterator out_end = g.out_end(A);\n                    for(out_edge_iterator& i = out_begin; i != out_end; ++i)\n                    {\n                        if (g.get_flow(i) > 0)\n                        {\n                            const unsigned long id = g.node_id(i);\n                            const unsigned char label_i = g.get_label(id); \n                            if (label_i == FREE_NODE)\n                            {\n                                active.push_back(id);\n                                g.set_label(id,SOURCE_CUT);\n                                parent[id] = A;\n                                ts[id] = ts[A];\n                                dist[id] = dist[A] + 1;\n                            }\n                            else if (label_A != label_i)\n                            {\n                                source_side = A;\n                                sink_side = id;\n                                return true;\n                            }\n                            else if (is_closer(A, id))\n                            {\n                                parent[id] = A;\n                                ts[id] = ts[A];\n                                dist[id] = dist[A] + 1;\n                            }\n                        }\n                    }\n                }\n                else if (label_A == SINK_CUT)\n                {\n                    const in_edge_iterator in_end = g.in_end(A);\n                    for(in_edge_iterator& i = in_begin; i != in_end; ++i)\n                    {\n                        if (g.get_flow(i) > 0)\n                        {\n                            const unsigned long id = g.node_id(i);\n                            const unsigned char label_i = g.get_label(id); \n                            if (label_i == FREE_NODE)\n                            {\n                                active.push_back(id);\n                                g.set_label(id,SINK_CUT);\n                                parent[id] = A;\n                                ts[id] = ts[A];\n                                dist[id] = dist[A] + 1;\n                            }\n                            else if (label_A != label_i)\n                            {\n                                sink_side = A;\n                                source_side = id;\n                                return true;\n                            }\n                            else if (is_closer(A, id))\n                            {\n                                parent[id] = A;\n                                ts[id] = ts[A];\n                                dist[id] = dist[A] + 1;\n                            }\n                        }\n                    }\n                }\n\n                active.pop_front();\n                if (active.size() != 0)\n                {\n                    in_begin = g.in_begin(active[0]);\n                    out_begin = g.out_begin(active[0]);\n                }\n            }\n\n            return false;\n        }\n\n        inline bool is_closer (\n            unsigned long p,\n            unsigned long q\n        ) const\n        {\n            // return true if p is closer to a terminal than q\n            return ts[q] <= ts[p] && dist[q] > dist[p];\n        }\n\n        mutable std::vector<uint32> dist;\n        mutable std::vector<uint32> ts;\n        mutable uint32 time;\n        mutable std::vector<unsigned long> parent;\n\n        mutable std::deque<unsigned long> active;\n        mutable std::vector<unsigned long> orphans;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_MIN_CuT_Hh_\n\n"
  },
  {
    "path": "dlib/graph_cuts/min_cut_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MIN_CuT_ABSTRACT_Hh_\n#ifdef DLIB_MIN_CuT_ABSTRACT_Hh_\n\n#include \"../graph_utils.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    /*!A node_label\n        The node_label type is the type used to label which part of a graph cut\n        a node is on.  It is used by all the graph cut tools.  The three possible\n        values of a node label are SOURCE_CUT, SINK_CUT, or FREE_NODE.\n    !*/\n\n    typedef unsigned char node_label;\n    const node_label SOURCE_CUT = 0;\n    const node_label SINK_CUT = 254;\n    const node_label FREE_NODE = 255;\n\n// ----------------------------------------------------------------------------------------\n\n    class flow_graph \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a flow capacity graph for use with the\n                min_cut algorithm defined below.  In particular, this object\n                is a kind of directed graph where the edge weights specify the\n                flow capacities.\n\n                Note that there is no dlib::flow_graph object.  What you are\n                looking at here is simply the interface definition for a graph \n                which can be used with the min_cut algorithm.  You must implement \n                your own version of this object for the graph you wish to work with \n                and then pass it to the min_cut::operator() routine.\n\n                It's also worth pointing out that this graph has symmetric edge \n                connections.  That is, if there is an edge from node A to node B\n                then there must also be an edge from node B to node A.\n        !*/\n\n    public:\n\n        class out_edge_iterator\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a simple forward iterator for iterating over the neighbors\n                    of a node in the graph.  It also represents the fact that the neighbors \n                    are on the end of an outgoing edge.  That is, the edge represents\n                    the amount of flow which can flow towards the neighbor.\n            !*/\n\n        public:\n            out_edge_iterator(\n            );\n            /*!\n                ensures\n                    - constructs an iterator in an undefined state.  It can't\n                      be used until assigned with a valid iterator.\n            !*/\n\n            out_edge_iterator(\n                const out_edge_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n            !*/\n\n            out_edge_iterator& operator=(\n                const out_edge_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n                    - returns #*this\n            !*/\n\n            bool operator!= (\n                const out_edge_iterator& item\n            ) const;\n            /*!\n                requires\n                    - *this and item are iterators over the neighbors for the\n                      same node.  \n                ensures\n                    - returns false if *this and item both reference the same\n                      node in the graph and true otherwise.\n            !*/\n\n            out_edge_iterator& operator++(\n            );\n            /*!\n                ensures\n                    - advances *this to the next neighbor node.\n                    - returns a reference to the updated *this\n                      (i.e. this is the ++object form of the increment operator) \n            !*/\n        };\n\n        class in_edge_iterator\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a simple forward iterator for iterating over the neighbors\n                    of a node in the graph.  It also represents the fact that the neighbors \n                    are on the end of an incoming edge.  That is, the edge represents\n                    the amount of flow which can flow out of the neighbor node.\n            !*/\n\n        public:\n\n            in_edge_iterator(\n            );\n            /*!\n                ensures\n                    - constructs an iterator in an undefined state.  It can't\n                      be used until assigned with a valid iterator.\n            !*/\n\n            in_edge_iterator(\n                const in_edge_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n            !*/\n\n            in_edge_iterator& operator=(\n                const in_edge_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n                    - returns #*this\n            !*/\n\n            bool operator!= (\n                const in_edge_iterator& item\n            ) const;\n            /*!\n                requires\n                    - *this and item are iterators over the neighbors for the\n                      same node.  \n                ensures\n                    - returns false if *this and item both reference the same\n                      node in the graph and true otherwise.\n            !*/\n\n            in_edge_iterator& operator++(\n            );\n            /*!\n                ensures\n                    - advances *this to the next neighbor node.\n                    - returns a reference to the updated *this\n                      (i.e. this is the ++object form of the increment operator) \n            !*/\n        };\n\n\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the graph.  \n        !*/\n\n        out_edge_iterator out_begin(\n            const unsigned long& idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns an iterator pointing to the first neighboring node of\n                  the idx-th node.  If no such node exists then returns out_end(idx).\n                - The returned iterator also represents the directed edge going from \n                  node idx to the neighbor.\n        !*/\n\n        in_edge_iterator in_begin(\n            const unsigned long& idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns an iterator pointing to the first neighboring node of\n                  the idx-th node.  If no such node exists then returns in_end(idx).\n                - The returned iterator also represents the directed edge going from \n                  the neighbor to node idx.\n        !*/\n\n        out_edge_iterator out_end(\n            const unsigned long& idx \n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns an iterator to one past the last neighboring node of\n                  the idx-th node.\n        !*/\n\n        in_edge_iterator in_end(\n            const unsigned long& idx \n        ) const; \n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns an iterator to one past the last neighboring node of\n                  the idx-th node.\n        !*/\n\n\n        unsigned long node_id (\n            const out_edge_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [out_begin(idx), out_end(idx))\n                  for some valid idx)\n            ensures\n                - returns a number IDX such that:\n                    - 0 <= IDX < number_of_nodes()\n                    - IDX == The index which uniquely identifies the node pointed to by the\n                      iterator it.  This number can be used with any member function in this\n                      object which expect a node index.  (e.g. get_label(IDX) == the label for the\n                      node pointed to by it)\n        !*/\n\n        unsigned long node_id (\n            const in_edge_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [in_begin(idx), in_end(idx))\n                  for some valid idx)\n            ensures\n                - returns a number IDX such that:\n                    - 0 <= IDX < number_of_nodes()\n                    - IDX == The index which uniquely identifies the node pointed to by the\n                      iterator it.  This number can be used with any member function in this\n                      object which expect a node index.  (e.g. get_label(IDX) == the label for the\n                      node pointed to by it)\n        !*/\n\n        // This typedef should be for a type like int or double.  It\n        // must also be capable of representing signed values.\n        typedef an_integer_or_real_type edge_type;\n\n        edge_type get_flow (\n            const unsigned long& idx1,     \n            const unsigned long& idx2 \n        ) const;\n        /*!\n            requires\n                - idx1 < number_of_nodes()\n                - idx2 < number_of_nodes()\n                - idx1 and idx2 are neighbors in the graph\n            ensures\n                - returns the residual flow capacity from the idx1-th node to the idx2-th node.\n                - It is valid for this function to return a floating point value of infinity.\n                  This value means this edge has an unlimited capacity.\n        !*/\n\n        edge_type get_flow (\n            const out_edge_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [out_begin(idx), out_end(idx))\n                  for some valid idx)\n            ensures\n                - let IDX = node_id(it)\n                - it represents the directed edge from a node, call it H, to the node IDX. Therefore,\n                  this function returns get_flow(H,IDX)\n                - It is valid for this function to return a floating point value of infinity.\n                  This value means this edge has an unlimited capacity.\n        !*/\n\n        edge_type get_flow (\n            const in_edge_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [in_begin(idx), in_end(idx))\n                  for some valid idx)\n            ensures\n                - let IDX = node_id(it)\n                - it represents the directed edge from node IDX to another node, call it H. Therefore,\n                  this function returns get_flow(IDX,H)\n                - It is valid for this function to return a floating point value of infinity.\n                  This value means this edge has an unlimited capacity.\n        !*/\n\n        void adjust_flow (\n            const unsigned long& idx1,\n            const unsigned long& idx2,\n            const edge_type& value\n        );\n        /*!\n            requires\n                - idx1 < number_of_nodes()\n                - idx2 < number_of_nodes()\n                - idx1 and idx2 are neighbors in the graph\n            ensures\n                - #get_flow(idx1,idx2) == get_flow(idx1,idx2) + value\n                - #get_flow(idx2,idx1) == get_flow(idx2,idx1) - value\n        !*/\n\n        void set_label (\n            const unsigned long& idx,\n            node_label value\n        );\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - #get_label(idx) == value\n        !*/\n\n        node_label get_label (\n            const unsigned long& idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_nodes()\n            ensures\n                - returns the label for the idx-th node in the graph.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename flow_graph\n        >\n    typename flow_graph::edge_type graph_cut_score (\n        const flow_graph& g\n    );\n    /*!\n        requires\n            - flow_graph == an object with an interface compatible with the flow_graph\n              object defined at the top of this file, or, an implementation of \n              dlib/directed_graph/directed_graph_kernel_abstract.h.\n        ensures\n            - returns the sum of the outgoing flows from nodes with a label of SOURCE_CUT \n              to nodes with a label != SOURCE_CUT.  Note that for a directed_graph object,\n              the labels are stored in the node's data field.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class min_cut\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object which can be used to find the min cut\n                on a graph.\n\n                The implementation is based on the method described in the following\n                paper:\n                    An Experimental Comparison of Min-Cut/Max-Flow Algorithms for\n                    Energy Minimization in Vision, by Yuri Boykov and Vladimir Kolmogorov, \n                    in PAMI 2004.\n\n        !*/\n\n    public:\n\n        min_cut(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename flow_graph\n            >\n        void operator() (\n            flow_graph& g,\n            const unsigned long source_node,\n            const unsigned long sink_node\n        ) const;\n        /*!\n            requires\n                - flow_graph == an object with an interface compatible with the flow_graph\n                  object defined at the top of this file.\n                - source_node != sink_node\n                - source_node < g.number_of_nodes()\n                - sink_node < g.number_of_nodes()\n                - for all valid i and j:\n                    - g.get_flow(i,j) >= 0\n                      (i.e. all the flow capacities/edge weights are non-negative)\n                - g does not contain any self loops.  That is, no nodes are neighbors with\n                  themselves.\n            ensures\n                - Finds the minimum cut on the given graph.  That is, this function finds\n                  a labeling of nodes in g such that graph_cut_score(g) would be minimized.  Note \n                  that the flow values in #g are modified by this algorithm so if you want \n                  to obtain the min cut score you must call min_cut::operator(), then copy \n                  the flow values back into #g, and then call graph_cut_score(#g).  But in most \n                  cases you don't care about the value of the min cut score, rather, you \n                  just want the labels in #g.\n                - #g.get_label(source_node) == SOURCE_CUT \n                - #g.get_label(sink_node) == SINK_CUT \n                - for all valid i:\n                    - #g.get_label(i) == SOURCE_CUT, SINK_CUT, or FREE_NODE\n                    - if (#g.get_label(i) == SOURCE_CUT) then\n                        - The minimum cut of g places node i into the source side of the cut.\n                    - if (#g.get_label(i) == SINK_CUT) then\n                        - The minimum cut of g places node i into the sink side of the cut.\n                    - if (#g.get_label(i) == FREE_NODE) then\n                        - Node i can be labeled SOURCE_CUT or SINK_CUT.  Both labelings\n                          result in the same cut score.  \n                - When interpreting g as a graph of flow capacities from the source_node \n                  to the sink_node we can say that the min cut problem is equivalent to\n                  the max flow problem.  This equivalent problem is to find out how to push \n                  as much \"flow\" from the source node to the sink node as possible.  \n                  Upon termination, #g will contain the final flow residuals in addition to \n                  the graph cut labels.  That is, for all valid i and j:\n                    - #g.get_flow(i,j) == the residual flow capacity left after the max \n                      possible amount of flow is passing from the source node to the sink\n                      node.  For example, this means that #g.get_flow(i,j) == 0 whenever \n                      node i is in the SOURCE_CUT and j is in the SINK_CUT. \n                    - #g.get_flow(i,j) >= 0\n        !*/\n\n        template <\n            typename directed_graph\n            >\n        void operator() (\n            directed_graph& g,\n            const unsigned long source_node,\n            const unsigned long sink_node\n        ) const;\n        /*!\n            requires\n                - directed_graph == an implementation of dlib/directed_graph/directed_graph_kernel_abstract.h \n                - directed_graph::type == node_label\n                - directed_graph::edge_type == and integer or double type\n                - source_node != sink_node\n                - source_node < g.number_of_nodes()\n                - sink_node < g.number_of_nodes()\n                - for all valid i and j:\n                    - edge(g,i,j) >= 0\n                      (i.e. all the flow capacities/edge weights are positive)\n                - graph_contains_length_one_cycle(g) == false \n                - graph_has_symmetric_edges(g) == true\n            ensures\n                - This routine simply converts g into a flow graph and calls the version\n                  of operator() defined above.  Note that the conversion is done in O(1)\n                  time, it's just an interface adaptor. \n                - edge weights in g correspond to network flows while the .data field of\n                  each node in g corresponds to the graph node labels.  \n                - upon termination, the flows and labels in g will have been modified\n                  as described in the above operator() routine.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MIN_CuT_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_cuts.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_CUTs_HEADER_\n#define DLIB_GRAPH_CUTs_HEADER_\n\n#include \"graph_cuts/min_cut.h\"\n#include \"graph_cuts/general_flow_graph.h\"\n#include \"graph_cuts/find_max_factor_graph_potts.h\"\n#include \"graph_cuts/graph_labeler.h\"\n\n#endif // DLIB_GRAPH_CUTs_HEADER_\n\n\n\n"
  },
  {
    "path": "dlib/graph_utils/edge_list_graphs.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_EDGE_LIST_GrAPHS_Hh_\n#define DLIB_EDGE_LIST_GrAPHS_Hh_\n\n#include \"edge_list_graphs_abstract.h\"\n#include <limits>\n#include <vector>\n#include \"../string.h\"\n#include \"../rand.h\"\n#include <algorithm>\n#include \"sample_pair.h\"\n#include \"ordered_sample_pair.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_duplicate_edges (\n        vector_type& pairs\n    )\n    {\n        typedef typename vector_type::value_type T;\n        if (pairs.size() > 0)\n        {\n            // sort pairs so that we can avoid duplicates in the loop below\n            std::sort(pairs.begin(), pairs.end(), &order_by_index<T>);\n\n            // now put edges into temp while avoiding duplicates\n            vector_type temp;\n            temp.reserve(pairs.size());\n            temp.push_back(pairs[0]);\n            for (unsigned long i = 1; i < pairs.size(); ++i)\n            {\n                if (pairs[i] != pairs[i-1])\n                {\n                    temp.push_back(pairs[i]);\n                }\n            }\n\n            temp.swap(pairs);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename iterator>\n        iterator iterator_of_worst (\n            iterator begin,\n            const iterator& end\n        ) \n        /*!\n            ensures\n                - returns an iterator that points to the element in the given range \n                  that has the biggest distance \n        !*/\n        {\n            double dist = begin->distance();\n            iterator worst = begin;\n            for (; begin != end; ++begin)\n            {\n                if (begin->distance() > dist)\n                {\n                    dist = begin->distance();\n                    worst = begin;\n                }\n            }\n\n            return worst;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc,\n        typename T\n        >\n    void find_percent_shortest_edges_randomly (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const double percent,\n        const unsigned long num,\n        const T& random_seed,\n        std::vector<sample_pair, alloc>& out\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( 0 < percent && percent <= 1 &&\n                    num > 0,\n            \"\\t void find_percent_shortest_edges_randomly()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t percent:        \" << percent \n            << \"\\n\\t num:            \" << num \n            );\n\n        out.clear();\n\n        if (samples.size() <= 1)\n        {\n            return;\n        }\n\n        std::vector<sample_pair, alloc> edges;\n        edges.reserve(num);\n\n        dlib::rand rnd;\n        rnd.set_seed(cast_to_string(random_seed));\n\n        // randomly sample a bunch of edges\n        for (unsigned long i = 0; i < num; ++i)\n        {\n            const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();\n            const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();\n            if (idx1 != idx2)\n            {\n                const double dist = dist_funct(samples[idx1], samples[idx2]);\n                if (dist < std::numeric_limits<double>::infinity())\n                {\n                    edges.push_back(sample_pair(idx1, idx2, dist));\n                }\n            }\n        }\n\n\n        // now put edges into out while avoiding duplicates\n        if (edges.size() > 0)\n        {\n            remove_duplicate_edges(edges);\n\n            // now sort all the edges by distance and take the percent with the smallest distance\n            std::sort(edges.begin(), edges.end(), &order_by_distance<sample_pair>);\n\n            const unsigned long out_size = std::min<unsigned long>((unsigned long)(num*percent), edges.size());\n            out.assign(edges.begin(), edges.begin() + out_size);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc,\n        typename T\n        >\n    void find_approximate_k_nearest_neighbors (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const unsigned long k,\n        unsigned long num,\n        const T& random_seed,\n        std::vector<sample_pair, alloc>& out\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( num > 0 && k > 0,\n            \"\\t void find_approximate_k_nearest_neighbors()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t k:              \" << k  \n            << \"\\n\\t num:            \" << num \n            );\n\n        out.clear();\n\n        if (samples.size() <= 1)\n        {\n            return;\n        }\n\n        // we add each edge twice in the following loop.  So multiply num by 2 to account for that.\n        num *= 2;\n\n        std::vector<ordered_sample_pair> edges;\n        edges.reserve(num);\n        std::vector<sample_pair, alloc> temp;\n        temp.reserve(num);\n\n        dlib::rand rnd;\n        rnd.set_seed(cast_to_string(random_seed));\n\n        // randomly sample a bunch of edges\n        for (unsigned long i = 0; i < num; ++i)\n        {\n            const unsigned long idx1 = rnd.get_random_32bit_number()%samples.size();\n            const unsigned long idx2 = rnd.get_random_32bit_number()%samples.size();\n            if (idx1 != idx2)\n            {\n                const double dist = dist_funct(samples[idx1], samples[idx2]);\n                if (dist < std::numeric_limits<double>::infinity())\n                {\n                    edges.push_back(ordered_sample_pair(idx1, idx2, dist));\n                    edges.push_back(ordered_sample_pair(idx2, idx1, dist));\n                }\n            }\n        }\n\n        std::sort(edges.begin(), edges.end(), &order_by_index<ordered_sample_pair>);\n\n        std::vector<ordered_sample_pair>::iterator beg, itr;\n        // now copy edges into temp when they aren't duplicates and also only move in the k shortest for\n        // each index.\n        itr = edges.begin();\n        while (itr != edges.end())\n        {\n            // first find the bounding range for all the edges connected to node itr->index1()\n            beg = itr; \n            while (itr != edges.end() && itr->index1() == beg->index1())\n                ++itr;\n\n            // If the node has more than k edges then sort them by distance so that\n            // we will end up with the k best.\n            if (static_cast<unsigned long>(itr - beg) > k)\n            {\n                std::sort(beg, itr, &order_by_distance_and_index<ordered_sample_pair>);\n            }\n\n            // take the k best unique edges from the range [beg,itr)\n            temp.push_back(sample_pair(beg->index1(), beg->index2(), beg->distance()));\n            unsigned long prev_index2 = beg->index2();\n            ++beg;\n            unsigned long count = 1;\n            for (; beg != itr && count < k; ++beg)\n            {\n                if (beg->index2() != prev_index2)\n                {\n                    temp.push_back(sample_pair(beg->index1(), beg->index2(), beg->distance()));\n                    ++count;\n                }\n                prev_index2 = beg->index2();\n            }\n        }\n\n\n        remove_duplicate_edges(temp);\n        temp.swap(out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc\n        >\n    void find_k_nearest_neighbors (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const unsigned long k,\n        std::vector<sample_pair, alloc>& out\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(k > 0,\n            \"\\t void find_k_nearest_neighbors()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t k:              \" << k \n            );\n\n        out.clear();\n\n        if (samples.size() <= 1)\n        {\n            return;\n        }\n\n        using namespace impl;\n        std::vector<sample_pair> edges;\n\n        // Initialize all the edges to an edge with an invalid index\n        edges.resize(samples.size()*k, \n                     sample_pair(samples.size(),samples.size(),std::numeric_limits<double>::infinity()));\n\n        // Hold the length for the longest edge for each node.  Initially they are all infinity.\n        std::vector<double> worst_dists(samples.size(), std::numeric_limits<double>::infinity());\n\n        std::vector<sample_pair>::iterator begin_i, end_i, begin_j, end_j;\n        begin_i = edges.begin();\n        end_i = begin_i + k;\n\n        // Loop over all combinations of samples.   We will maintain the iterator ranges so that\n        // within the inner for loop we have:\n        //   [begin_i, end_i) == the range in edges that contains neighbors of samples[i]\n        //   [begin_j, end_j) == the range in edges that contains neighbors of samples[j]\n        for (unsigned long i = 0; i+1 < samples.size(); ++i)\n        {\n            begin_j = begin_i;\n            end_j = end_i;\n\n            for (unsigned long j = i+1; j < samples.size(); ++j)\n            {\n                begin_j += k;\n                end_j += k;\n\n                const double dist = dist_funct(samples[i], samples[j]);\n\n                if (dist < worst_dists[i])\n                {\n                    *iterator_of_worst(begin_i, end_i) = sample_pair(i, j, dist);\n                    worst_dists[i] = iterator_of_worst(begin_i, end_i)->distance();\n                }\n\n                if (dist < worst_dists[j])\n                {\n                    *iterator_of_worst(begin_j, end_j) = sample_pair(i, j, dist);\n                    worst_dists[j] = iterator_of_worst(begin_j, end_j)->distance();\n                }\n            }\n\n            begin_i += k;\n            end_i += k;\n        }\n\n        // sort the edges so that duplicate edges will be adjacent\n        std::sort(edges.begin(), edges.end(), &order_by_index<sample_pair>);\n\n        // if the first edge is valid \n        if (edges[0].index1() < samples.size())\n        {\n            // now put edges into out while avoiding duplicates and any remaining invalid edges.\n            out.reserve(edges.size());\n            out.push_back(edges[0]);\n            for (unsigned long i = 1; i < edges.size(); ++i)\n            {\n                // if we hit an invalid edge then we can stop\n                if (edges[i].index1() >= samples.size())\n                    break;\n\n                // if this isn't a duplicate edge\n                if (edges[i] != edges[i-1])\n                {\n                    out.push_back(edges[i]);\n                }\n            }\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    bool contains_duplicate_pairs (\n        const vector_type& pairs\n    )\n    {\n        typedef typename vector_type::value_type T;\n        vector_type temp(pairs);\n        std::sort(temp.begin(), temp.end(), &order_by_index<T>);\n\n        for (unsigned long i = 1; i < temp.size(); ++i)\n        {\n            // if we found a duplicate\n            if (temp[i-1] == temp[i])\n                return true;\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    typename enable_if_c<(is_same_type<sample_pair, typename vector_type::value_type>::value ||\n                          is_same_type<ordered_sample_pair, typename vector_type::value_type>::value),\n                          unsigned long>::type\n    max_index_plus_one (\n        const vector_type& pairs\n    )\n    {\n        if (pairs.size() == 0)\n        {\n            return 0;\n        }\n        else\n        {\n            unsigned long max_idx = 0;\n            for (unsigned long i = 0; i < pairs.size(); ++i)\n            {\n                if (pairs[i].index1() > max_idx)\n                    max_idx = pairs[i].index1();\n                if (pairs[i].index2() > max_idx)\n                    max_idx = pairs[i].index2();\n            }\n\n            return max_idx + 1;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_long_edges (\n        vector_type& pairs,\n        double distance_threshold\n    )\n    {\n        vector_type temp;\n        temp.reserve(pairs.size());\n\n        // add all the pairs shorter than the given threshold into temp\n        for (unsigned long i = 0; i < pairs.size(); ++i)\n        {\n            if (pairs[i].distance() <= distance_threshold)\n                temp.push_back(pairs[i]);\n        }\n\n        // move temp into the output vector\n        temp.swap(pairs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_short_edges (\n        vector_type& pairs,\n        double distance_threshold\n    )\n    {\n        vector_type temp;\n        temp.reserve(pairs.size());\n\n        // add all the pairs longer than the given threshold into temp\n        for (unsigned long i = 0; i < pairs.size(); ++i)\n        {\n            if (pairs[i].distance() >= distance_threshold)\n                temp.push_back(pairs[i]);\n        }\n\n        // move temp into the output vector\n        temp.swap(pairs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_percent_longest_edges (\n        vector_type& pairs,\n        double percent \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( 0 <= percent && percent < 1,\n            \"\\t void remove_percent_longest_edges()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t percent:        \" << percent \n            );\n\n        typedef typename vector_type::value_type T;\n        std::sort(pairs.begin(), pairs.end(), &order_by_distance<T>);\n\n        const unsigned long num = static_cast<unsigned long>((1.0-percent)*pairs.size());\n\n        // pick out the num shortest pairs\n        vector_type temp(pairs.begin(), pairs.begin() + num);\n\n        // move temp into the output vector\n        temp.swap(pairs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_percent_shortest_edges (\n        vector_type& pairs,\n        double percent \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( 0 <= percent && percent < 1,\n            \"\\t void remove_percent_shortest_edges()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t percent:        \" << percent \n            );\n\n        typedef typename vector_type::value_type T;\n        std::sort(pairs.rbegin(), pairs.rend(), &order_by_distance<T>);\n\n        const unsigned long num = static_cast<unsigned long>((1.0-percent)*pairs.size());\n\n        // pick out the num shortest pairs\n        vector_type temp(pairs.begin(), pairs.begin() + num);\n\n        // move temp into the output vector\n        temp.swap(pairs);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    bool is_ordered_by_index (\n        const vector_type& edges\n    )\n    {\n        for (unsigned long i = 1; i < edges.size(); ++i)\n        {\n            if (order_by_index(edges[i], edges[i-1]))\n                return false;\n        }\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename alloc1, \n        typename alloc2\n        >\n    void find_neighbor_ranges (\n        const std::vector<ordered_sample_pair,alloc1>& edges,\n        std::vector<std::pair<unsigned long, unsigned long>,alloc2>& neighbors\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_ordered_by_index(edges),\n                    \"\\t void find_neighbor_ranges()\"\n                    << \"\\n\\t Invalid inputs were given to this function\"\n        );\n\n\n        // setup neighbors so that [neighbors[i].first, neighbors[i].second) is the range\n        // within edges that contains all node i's edges.\n        const unsigned long num_nodes = max_index_plus_one(edges);\n        neighbors.assign(num_nodes, std::make_pair(0,0));\n        unsigned long cur_node = 0;\n        unsigned long start_idx = 0;\n        for (unsigned long i = 0; i < edges.size(); ++i)\n        {\n            if (edges[i].index1() != cur_node)\n            {\n                neighbors[cur_node] = std::make_pair(start_idx, i);\n                start_idx = i;\n                cur_node = edges[i].index1();\n            }\n        }\n        if (neighbors.size() != 0)\n            neighbors[cur_node] = std::make_pair(start_idx, (unsigned long)edges.size());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename alloc1, \n        typename alloc2\n        >\n    void convert_unordered_to_ordered (\n        const std::vector<sample_pair,alloc1>& edges,\n        std::vector<ordered_sample_pair,alloc2>& out_edges\n    )\n    {\n        out_edges.clear();\n        out_edges.reserve(edges.size()*2);\n        for (unsigned long i = 0; i < edges.size(); ++i)\n        {\n            out_edges.push_back(ordered_sample_pair(edges[i].index1(), edges[i].index2(), edges[i].distance()));\n            if (edges[i].index1() != edges[i].index2())\n                out_edges.push_back(ordered_sample_pair(edges[i].index2(), edges[i].index1(), edges[i].distance()));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EDGE_LIST_GrAPHS_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_utils/edge_list_graphs_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_\n#ifdef DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../string.h\"\n#include \"sample_pair_abstract.h\"\n#include \"ordered_sample_pair_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc,\n        typename T\n        >\n    void find_percent_shortest_edges_randomly (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const double percent,\n        const unsigned long num,\n        const T& random_seed,\n        std::vector<sample_pair, alloc>& out\n    );\n    /*!\n        requires\n            - 0 < percent <= 1\n            - num > 0\n            - random_seed must be convertible to a string by dlib::cast_to_string()\n            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates\n              to a floating point number \n        ensures\n            - This function randomly samples the space of pairs of integers between\n              0 and samples.size()-1 inclusive.  For each of these pairs, (i,j), a\n              sample_pair is created as follows:    \n                sample_pair(i, j, dist_funct(samples[i], samples[j]))\n              num such sample_pair objects are generated, duplicates and pairs with distance\n              values == infinity are removed, and then the top percent of them with the \n              smallest distance are stored into out.  \n            - #out.size() <= num*percent \n            - contains_duplicate_pairs(#out) == false\n            - for all valid i:\n                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])\n                - #out[i].distance() < std::numeric_limits<double>::infinity()\n            - random_seed is used to seed the random number generator used by this \n              function.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc,\n        typename T\n        >\n    void find_approximate_k_nearest_neighbors (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const unsigned long k,\n        const unsigned long num,\n        const T& random_seed,\n        std::vector<sample_pair, alloc>& out\n    );\n    /*!\n        requires\n            - k > 0\n            - num > 0\n            - random_seed must be convertible to a string by dlib::cast_to_string()\n            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates\n              to a floating point number \n        ensures\n            - This function computes an approximate form of k nearest neighbors. As num grows \n              larger the output of this function converges to the output of the \n              find_k_nearest_neighbors() function defined below.\n            - Specifically, this function randomly samples the space of pairs of integers between\n              0 and samples.size()-1 inclusive.  For each of these pairs, (i,j), a\n              sample_pair is created as follows:    \n                sample_pair(i, j, dist_funct(samples[i], samples[j]))\n              num such sample_pair objects are generated and then exact k-nearest-neighbors\n              is performed amongst these sample_pairs and the results are stored into #out.\n              Note that samples with an infinite distance between them are considered to \n              be not connected at all.\n            - contains_duplicate_pairs(#out) == false\n            - for all valid i:\n                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])\n                - #out[i].distance() < std::numeric_limits<double>::infinity()\n            - random_seed is used to seed the random number generator used by this \n              function.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename alloc\n        >\n    void find_k_nearest_neighbors (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const unsigned long k,\n        std::vector<sample_pair, alloc>& out\n    );\n    /*!\n        requires\n            - k > 0\n            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates\n              to a floating point number \n        ensures\n            - #out == a set of sample_pair objects that represent all the k nearest \n              neighbors in samples according to the given distance function dist_funct.  \n              Note that samples with an infinite distance between them are considered to \n              be not connected at all.\n            - for all valid i:\n                - #out[i].distance() == dist_funct(samples[#out[i].index1()], samples[#out[i].index2()])\n                - #out[i].distance() < std::numeric_limits<double>::infinity()\n            - contains_duplicate_pairs(#out) == false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    bool contains_duplicate_pairs (\n        const vector_type& pairs\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - if (pairs contains any elements that are equal according to operator==) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type \n        >\n    unsigned long max_index_plus_one (\n        const vector_type& pairs\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - if (pairs.size() == 0) then\n                - returns 0\n            - else\n                - returns a number N such that: \n                    - for all i:  pairs[i].index1()   <  N && pairs[i].index2()   <  N\n                    - for some j: pairs[j].index1()+1 == N || pairs[j].index2()+1 == N\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_long_edges (\n        vector_type& pairs,\n        double distance_threshold\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - Removes all elements of pairs that have a distance value greater than the\n              given threshold.\n            - #pairs.size() <= pairs.size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_short_edges (\n        vector_type& pairs,\n        double distance_threshold\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - Removes all elements of pairs that have a distance value less than the\n              given threshold.\n            - #pairs.size() <= pairs.size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_percent_longest_edges (\n        vector_type& pairs,\n        double percent \n    );\n    /*!\n        requires\n            - 0 <= percent < 1\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - Removes the given upper percentage of the longest edges in pairs.  I.e.\n              this function removes the long edges from pairs.\n            - #pairs.size() == (1-percent)*pairs.size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_percent_shortest_edges (\n        vector_type& pairs,\n        double percent \n    );\n    /*!\n        requires\n            - 0 <= percent < 1\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - Removes the given upper percentage of the shortest edges in pairs.  I.e.\n              this function removes the short edges from pairs.\n            - #pairs.size() == (1-percent)*pairs.size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    void remove_duplicate_edges (\n        vector_type& pairs\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - Removes any duplicate edges from pairs.  That is, for all elements of pairs,\n              A and B, such that A == B, only one of A or B will be in pairs after this\n              function terminates.\n            - #pairs.size() <= pairs.size()\n            - is_ordered_by_index(#pairs) == true\n            - contains_duplicate_pairs(#pairs) == false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    bool is_ordered_by_index (\n        const vector_type& edges\n    );\n    /*!\n        requires\n            - vector_type == a type with an interface compatible with std::vector and it\n              must in turn contain objects with an interface compatible with\n              dlib::sample_pair or dlib::ordered_sample_pair.\n        ensures\n            - returns true if and only if the contents of edges are in sorted order\n              according to order_by_index().  That is, we return true if calling\n              std::stable_sort(edges.begin(), edges.end(), &order_by_index<T>) would not\n              change the ordering of elements of edges.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename alloc1, \n        typename alloc2\n        >\n    void find_neighbor_ranges (\n        const std::vector<ordered_sample_pair,alloc1>& edges,\n        std::vector<std::pair<unsigned long, unsigned long>,alloc2>& neighbors\n    );\n    /*!\n        requires\n            - is_ordered_by_index(edges) == true\n              (i.e. edges is sorted so that all the edges for a particular node are grouped\n              together)\n        ensures\n            - This function takes a graph, represented by its list of edges, and finds the\n              ranges that contain the edges for each node in the graph.  In particular,\n              #neighbors[i] will tell you which edges correspond to the ith node in the\n              graph.\n            - #neighbors.size() == max_index_plus_one(edges)\n              (i.e. neighbors will have an entry for each node in the graph defined by the\n              list of edges)\n            - for all valid i:\n                - all elements of edges such that their index1() value == i are in the\n                  range [neighbors[i].first, neighbors[i].second).  That is, for all k such\n                  that neighbors[i].first <= k < neighbors[i].second:\n                    - edges[k].index1() == i.\n                    - all edges outside this range have an index1() value != i\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename alloc1, \n        typename alloc2\n        >\n    void convert_unordered_to_ordered (\n        const std::vector<sample_pair,alloc1>& edges,\n        std::vector<ordered_sample_pair,alloc2>& out_edges\n    );\n    /*!\n        ensures\n            - interprets edges a defining an undirected graph. \n            - This function populates out_edges with a directed graph that represents the\n              same graph as the one in edges.  In particular, this means that for all valid\n              i we have the following:\n                - if (edges[i].index1() != edges[i].index2()) then\n                    - #out_edges contains two edges corresponding to edges[i].  They\n                      represent the two directions of this edge.  The distance value from\n                      edges[i] is also copied into the output edges.\n                - else\n                    - #out_edges contains one edge corresponding to edges[i] since this is\n                      a self edge.  The distance value from edges[i] is also copied into\n                      the output edge.\n            - max_index_plus_one(edges) == max_index_plus_one(#out_edges) \n              (i.e. both graphs have the same number of nodes)\n            - In all but the most trivial cases, we will have is_ordered_by_index(#out_edges) == false\n            - contains_duplicate_pairs(#out_edges) == contains_duplicate_pairs(edges)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EDGE_LIST_GrAPHS_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/graph_utils/find_k_nearest_neighbors_lsh.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_Hh_\n#define DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_Hh_\n\n#include \"find_k_nearest_neighbors_lsh_abstract.h\"\n#include \"../threads.h\"\n#include \"../lsh/hashes.h\"\n#include <vector>\n#include <queue>\n#include \"sample_pair.h\"\n#include \"edge_list_graphs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        struct compare_sample_pair_with_distance \n        {\n            inline bool operator() (const sample_pair& a, const sample_pair& b) const\n            { \n                return a.distance() < b.distance();\n            }\n        };\n\n        template <\n            typename vector_type,\n            typename hash_function_type\n            >\n        class hash_block\n        {\n        public:\n            hash_block(\n                const vector_type& samples_,\n                const hash_function_type& hash_funct_,\n                std::vector<typename hash_function_type::result_type>& hashes_\n            ) : \n                samples(samples_),\n                hash_funct(hash_funct_),\n                hashes(hashes_)\n            {}\n\n            void operator() (long i) const\n            {\n                hashes[i] = hash_funct(samples[i]);\n            }\n\n            const vector_type& samples;\n            const hash_function_type& hash_funct;\n            std::vector<typename hash_function_type::result_type>& hashes;\n        };\n\n        template <\n            typename vector_type,\n            typename distance_function_type,\n            typename hash_function_type,\n            typename alloc\n            >\n        class scan_find_k_nearest_neighbors_lsh\n        {\n        public:\n            scan_find_k_nearest_neighbors_lsh (\n                const vector_type& samples_,\n                const distance_function_type& dist_funct_,\n                const hash_function_type& hash_funct_,\n                const unsigned long k_,\n                std::vector<sample_pair, alloc>& edges_,\n                const unsigned long k_oversample_,\n                const std::vector<typename hash_function_type::result_type>& hashes_\n            ) :\n                samples(samples_),\n                dist_funct(dist_funct_),\n                hash_funct(hash_funct_),\n                k(k_),\n                edges(edges_),\n                k_oversample(k_oversample_),\n                hashes(hashes_)\n            {\n                edges.clear();\n                edges.reserve(samples.size()*k/2);\n            }\n\n            mutex m;\n            const vector_type& samples;\n            const distance_function_type& dist_funct;\n            const hash_function_type& hash_funct;\n            const unsigned long k;\n            std::vector<sample_pair, alloc>& edges;\n            const unsigned long k_oversample;\n            const std::vector<typename hash_function_type::result_type>& hashes;\n\n            void operator() (unsigned long i) const\n            {\n                const unsigned long k_hash = k*k_oversample;\n\n                std::priority_queue<std::pair<unsigned long, unsigned long> > best_hashes;\n                std::priority_queue<sample_pair, std::vector<sample_pair>, dlib::impl::compare_sample_pair_with_distance> best_samples;\n                unsigned long worst_distance = std::numeric_limits<unsigned long>::max();\n                // scan over the hashes and find the best matches for hashes[i]\n                for (unsigned long j = 0; j < hashes.size(); ++j)\n                {\n                    if (i == j) \n                        continue;\n\n                    const unsigned long dist = hash_funct.distance(hashes[i], hashes[j]);\n                    if (dist < worst_distance || best_hashes.size() < k_hash)\n                    {\n                        if (best_hashes.size() >= k_hash)\n                            best_hashes.pop();\n                        best_hashes.push(std::make_pair(dist, j));\n                        worst_distance = best_hashes.top().first;\n                    }\n                }\n\n                // Now figure out which of the best_hashes are actually the k best matches\n                // according to dist_funct()\n                while (best_hashes.size() != 0)\n                {\n                    const unsigned long j = best_hashes.top().second;\n                    best_hashes.pop();\n\n                    const double dist = dist_funct(samples[i], samples[j]);\n                    if (dist < std::numeric_limits<double>::infinity())\n                    {\n                        if (best_samples.size() >= k)\n                            best_samples.pop();\n                        best_samples.push(sample_pair(i,j,dist));\n                    }\n                }\n\n                // Finally, now put the k best matches according to dist_funct() into edges\n                auto_mutex lock(m);\n                while (best_samples.size() != 0)\n                {\n                    edges.push_back(best_samples.top());\n                    best_samples.pop();\n                }\n            }\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename hash_function_type\n        >\n    void hash_samples (\n        const vector_type& samples,\n        const hash_function_type& hash_funct,\n        const unsigned long num_threads,\n        std::vector<typename hash_function_type::result_type>& hashes\n    )\n    {\n        hashes.resize(samples.size());\n\n        typedef impl::hash_block<vector_type,hash_function_type> block_type;\n        block_type temp(samples, hash_funct, hashes);\n        parallel_for(num_threads, 0, samples.size(), temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename hash_function_type,\n        typename alloc\n        >\n    void find_k_nearest_neighbors_lsh (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const hash_function_type& hash_funct,\n        const unsigned long k,\n        const unsigned long num_threads,\n        std::vector<sample_pair, alloc>& edges,\n        const unsigned long k_oversample = 20 \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(k > 0 && k_oversample > 0,\n            \"\\t void find_k_nearest_neighbors_lsh()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t samples.size(): \" << samples.size()\n            << \"\\n\\t k:              \" << k \n            << \"\\n\\t k_oversample:   \" << k_oversample \n            );\n\n        edges.clear();\n\n        if (samples.size() <= 1)\n        {\n            return;\n        }\n\n        typedef typename hash_function_type::result_type hash_type;\n        std::vector<hash_type> hashes;\n        hash_samples(samples, hash_funct, num_threads, hashes);\n\n        typedef impl::scan_find_k_nearest_neighbors_lsh<vector_type, distance_function_type,hash_function_type,alloc> scan_type;\n        scan_type temp(samples, dist_funct, hash_funct, k, edges, k_oversample, hashes);\n        parallel_for(num_threads, 0, hashes.size(), temp);\n\n        remove_duplicate_edges(edges);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_utils/find_k_nearest_neighbors_lsh_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_\n#ifdef DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_\n\n#include \"../lsh/hashes_abstract.h\"\n#include \"sample_pair_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename hash_function_type\n        >\n    void hash_samples (\n        const vector_type& samples,\n        const hash_function_type& hash_funct,\n        const unsigned long num_threads,\n        std::vector<typename hash_function_type::result_type>& hashes\n    );\n    /*!\n        requires\n            - hash_funct() is threadsafe.  This means that it must be safe for multiple\n              threads to invoke the member functions of hash_funct() at the same time.\n            - vector_type is any container that looks like a std::vector or dlib::array.\n            - hash_funct must be a function object with an interface compatible with the\n              objects defined in dlib/lsh/hashes_abstract.h.  In particular, hash_funct\n              must be capable of hashing the elements in the samples vector.\n        ensures\n            - This function hashes all the elements in samples and stores the results in\n              hashes.  It will also use num_threads concurrent threads to do this.  You\n              should set this value equal to the number of processing cores on your\n              computer for maximum speed.\n            - #hashes.size() == 0\n            - for all valid i:\n                - #hashes[i] = hash_funct(samples[i])\n                  (i.e. #hashes[i] will contain the hash of samples[i])\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type,\n        typename distance_function_type,\n        typename hash_function_type,\n        typename alloc\n        >\n    void find_k_nearest_neighbors_lsh (\n        const vector_type& samples,\n        const distance_function_type& dist_funct,\n        const hash_function_type& hash_funct,\n        const unsigned long k,\n        const unsigned long num_threads,\n        std::vector<sample_pair, alloc>& edges,\n        const unsigned long k_oversample = 20 \n    );\n    /*!\n        requires\n            - hash_funct and dist_funct are threadsafe.  This means that it must be safe\n              for multiple threads to invoke the member functions of these objects at the\n              same time.\n            - k > 0\n            - k_oversample > 0\n            - dist_funct(samples[i], samples[j]) must be a valid expression that evaluates\n              to a floating point number \n            - vector_type is any container that looks like a std::vector or dlib::array.\n            - hash_funct must be a function object with an interface compatible with the\n              objects defined in dlib/lsh/hashes_abstract.h.  In particular, hash_funct\n              must be capable of hashing the elements in the samples vector.\n        ensures\n            - This function computes an approximate form of a k nearest neighbors graph of\n              the elements in samples.  In particular, the way it works is that it first\n              hashes all elements in samples using the provided locality sensitive hash\n              function hash_funct().  Then it performs an exact k nearest neighbors on the\n              hashes which can be done very quickly.  For each of these neighbors we\n              compute the true distance using dist_funct() and the k nearest neighbors for\n              each sample are stored into #edges.  \n            - Note that samples with an infinite distance between them are considered to be\n              not connected at all. Therefore, we exclude edges with such distances from\n              being output.\n            - for all valid i:\n                - #edges[i].distance() == dist_funct(samples[#edges[i].index1()], samples[#edges[i].index2()])\n                - #edges[i].distance() < std::numeric_limits<double>::infinity()\n            - contains_duplicate_pairs(#edges) == false\n            - This function will use num_threads concurrent threads of processing.  You\n              should set this value equal to the number of processing cores on your\n              computer for maximum speed.\n            - The hash based k nearest neighbor step is approximate, however, you can\n              improve the output accuracy by using a larger k value for this first step.\n              Therefore, this function finds k*k_oversample nearest neighbors during the\n              first hashing based step. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_K_NEAREST_NEIGHBOrS_LSH_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/graph_utils/function_objects.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MR_FUNCTION_ObJECTS_Hh_\n#define DLIB_MR_FUNCTION_ObJECTS_Hh_\n\n#include \"function_objects_abstract.h\"\n#include \"../matrix.h\"\n#include \"../svm/sparse_vector.h\"\n#include <cmath>\n#include <limits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct squared_euclidean_distance\n    {\n        squared_euclidean_distance (\n        ) : \n            lower(0),\n            upper(std::numeric_limits<double>::infinity())\n        {}\n\n        squared_euclidean_distance (\n            const double l,\n            const double u\n        ) :\n            lower(l),\n            upper(u)\n        {}\n\n        const double lower;\n        const double upper;\n\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const\n        { \n            const double len = length_squared(a-b);\n            if (lower <= len && len <= upper)\n                return len;\n            else\n                return std::numeric_limits<double>::infinity();\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct cosine_distance \n    {\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const\n        { \n            const double temp = length(a)*length(b);\n            if (temp == 0)\n                return 0;\n            else\n                return 1-dot(a,b)/temp;\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct negative_dot_product_distance \n    {\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const\n        { \n            return -dot(a,b);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct use_weights_of_one \n    {\n        template <typename edge_type>\n        double operator() (\n            const edge_type&\n        ) const\n        { \n            return 1;\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct use_gaussian_weights \n    {\n        use_gaussian_weights (\n        ) \n        {\n            gamma = 0.1;\n        }\n\n        use_gaussian_weights (\n            double g\n        )\n        {\n            gamma = g;\n        }\n\n        double gamma;\n\n        template <typename edge_type>\n        double operator() (\n            const edge_type& e\n        ) const\n        { \n            return std::exp(-gamma*e.distance());\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MR_FUNCTION_ObJECTS_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_utils/function_objects_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_\n#ifdef DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include <cmath>\n#include \"../svm/sparse_vector_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct squared_euclidean_distance\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that computes squared euclidean distance\n                between two dlib::matrix objects. \n\n            THREAD SAFETY\n                This object has no mutable members.  Therefore, it is safe to call\n                operator() on a single instance of this object simultaneously from multiple\n                threads.\n        !*/\n\n        squared_euclidean_distance (\n        );\n        /*!\n            ensures\n                - #lower == 0\n                - #upper == std::numeric_limits<double>::infinity()\n        !*/\n\n        squared_euclidean_distance (\n            const double l,\n            const double u\n        );\n        /*!\n            ensures\n                - #lower == l\n                - #upper == u  \n        !*/\n\n        const double lower;\n        const double upper;\n\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const;\n        /*!\n            requires\n                - sample_type should be a kind of dlib::matrix \n            ensures\n                - let LEN = length_squared(a-b)\n                - if (lower <= LEN <= upper) then\n                    - returns LEN\n                - else\n                    - returns std::numeric_limits<double>::infinity()\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct cosine_distance \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that computes the cosine of the angle\n                between two vectors and returns 1 - this quantity.   Moreover, this object\n                works for both sparse and dense vectors.\n\n            THREAD SAFETY\n                This object has no mutable members.  Therefore, it is safe to call\n                operator() on a single instance of this object simultaneously from multiple\n                threads.\n        !*/\n\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const;\n        /*!\n            requires\n                - sample_type is a dense vector (e.g. a dlib::matrix) or a sparse\n                  vector as defined at the top of dlib/svm/sparse_vector_abstract.h\n            ensures\n                - let theta = the angle between a and b.  \n                - returns 1 - cos(theta)\n                  (e.g. this function returns 0 when a and b have an angle of 0 between\n                  each other, 1 if they have a 90 degree angle, and a maximum of 2 if the\n                  vectors have a 180 degree angle between each other).\n                - zero length vectors are considered to have angles of 0 between all other\n                  vectors.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct negative_dot_product_distance \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that computes the dot product between two\n                vectors and returns the negation of this value.  Moreover, this object\n                works for both sparse and dense vectors.\n\n            THREAD SAFETY\n                This object has no mutable members.  Therefore, it is safe to call\n                operator() on a single instance of this object simultaneously from multiple\n                threads.\n        !*/\n\n        template <typename sample_type>\n        double operator() (\n            const sample_type& a,\n            const sample_type& b\n        ) const;\n        /*!\n            requires\n                - sample_type is a dense vector (e.g. a dlib::matrix) or a sparse\n                  vector as defined at the top of dlib/svm/sparse_vector_abstract.h\n            ensures\n                - returns -dot(a,b)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct use_weights_of_one \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that takes a single argument\n                and always returns 1 \n\n            THREAD SAFETY\n                This object has no mutable members.  Therefore, it is safe to call\n                operator() on a single instance of this object simultaneously from multiple\n                threads.\n        !*/\n\n        template <typename edge_type>\n        double operator() (\n            const edge_type&\n        ) const;\n        /*!\n            ensures\n                - returns 1\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct use_gaussian_weights \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple function object that takes a single argument\n                which should be an object similar to dlib::sample_pair.  \n\n            THREAD SAFETY\n                This object has no mutable members.  Therefore, it is safe to call\n                operator() on a single instance of this object simultaneously from multiple\n                threads.\n        !*/\n\n        use_gaussian_weights (\n        );\n        /*!\n            ensures\n                - #gamma == 0.1\n        !*/\n\n        use_gaussian_weights (\n            double g\n        );\n        /*!\n            ensures\n                - #gamma == g\n        !*/\n\n        double gamma;\n\n        template <typename edge_type>\n        double operator() (\n            const edge_type& e\n        ) const;\n        /*!\n            requires\n                - e.distance() must be a valid expression that returns a number\n                  (e.g. edge_type might be dlib::sample_pair)\n            ensures\n                - returns std::exp(-gamma*e.distance());\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MR_FUNCTION_ObJECTS_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/graph_utils/graph_utils.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_UTILs_\n#define DLIB_GRAPH_UTILs_\n\n#include \"../algs.h\"\n#include <vector>\n#include \"graph_utils_abstract.h\"\n#include \"../is_kind.h\"\n#include \"../enable_if.h\"\n#include <algorithm>\n#include \"../set.h\"\n#include \"../memory_manager.h\"\n#include \"../set_utils.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    typename enable_if<is_graph<T>,typename T::edge_type>::type& edge(\n        T& g, \n        unsigned long idx_i, \n        unsigned long idx_j\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(g.has_edge(idx_i,idx_j) == true,\n            \"\\tT::edge_type& edge(g, idx_i, idx_j)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t idx_i: \" << idx_i\n            << \"\\n\\t idx_j: \" << idx_j \n            );\n\n        for (unsigned long i = 0; i < g.node(idx_i).number_of_neighbors(); ++i)\n        {\n            if (g.node(idx_i).neighbor(i).index() == idx_j)\n                return g.node(idx_i).edge(i);\n        }\n\n        // put this here just so compilers don't complain about a lack of\n        // a return here\n        DLIB_CASSERT(false,\n            \"\\tT::edge_type& edge(g, idx_i, idx_j)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t idx_i: \" << idx_i\n            << \"\\n\\t idx_j: \" << idx_j \n            );\n    }\n\n    template <typename T>\n    const typename enable_if<is_graph<T>,typename T::edge_type>::type& edge(\n        const T& g,  \n        unsigned long idx_i,\n        unsigned long idx_j\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(g.has_edge(idx_i,idx_j) == true,\n            \"\\tT::edge_type& edge(g, idx_i, idx_j)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t idx_i: \" << idx_i\n            << \"\\n\\t idx_j: \" << idx_j \n            );\n\n        for (unsigned long i = 0; i < g.node(idx_i).number_of_neighbors(); ++i)\n        {\n            if (g.node(idx_i).neighbor(i).index() == idx_j)\n                return g.node(idx_i).edge(i);\n        }\n\n        // put this here just so compilers don't complain about a lack of\n        // a return here\n        DLIB_CASSERT(false,\n            \"\\tT::edge_type& edge(g, idx_i, idx_j)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t idx_i: \" << idx_i\n            << \"\\n\\t idx_j: \" << idx_j \n            );\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <typename T>\n    typename enable_if<is_directed_graph<T>,typename T::edge_type>::type& edge(\n        T& g, \n        unsigned long parent_idx, \n        unsigned long child_idx \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(g.has_edge(parent_idx,child_idx) == true,\n            \"\\t T::edge_type& edge(g, parent_idx, child_idx)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t parent_idx: \" << parent_idx\n            << \"\\n\\t child_idx: \" << child_idx \n            );\n\n        for (unsigned long i = 0; i < g.node(parent_idx).number_of_children(); ++i)\n        {\n            if (g.node(parent_idx).child(i).index() == child_idx)\n                return g.node(parent_idx).child_edge(i);\n        }\n\n        // put this here just so compilers don't complain about a lack of\n        // a return here\n        DLIB_CASSERT(false,\n            \"\\t T::edge_type& edge(g, parent_idx, child_idx)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t parent_idx: \" << parent_idx\n            << \"\\n\\t child_idx: \" << child_idx \n            );\n    }\n\n    template <typename T>\n    const typename enable_if<is_directed_graph<T>,typename T::edge_type>::type& edge(\n        const T& g,  \n        unsigned long parent_idx, \n        unsigned long child_idx \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(g.has_edge(parent_idx,child_idx) == true,\n            \"\\t T::edge_type& edge(g, parent_idx, child_idx)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t parent_idx: \" << parent_idx\n            << \"\\n\\t child_idx: \" << child_idx \n            );\n\n        for (unsigned long i = 0; i < g.node(parent_idx).number_of_children(); ++i)\n        {\n            if (g.node(parent_idx).child(i).index() == child_idx)\n                return g.node(parent_idx).child_edge(i);\n        }\n\n        // put this here just so compilers don't complain about a lack of\n        // a return here\n        DLIB_ASSERT(false,\n            \"\\t T::edge_type& edge(g, parent_idx, child_idx)\"\n            << \"\\n\\t you have requested an invalid edge\"\n            << \"\\n\\t parent_idx: \" << parent_idx\n            << \"\\n\\t child_idx: \" << child_idx \n            );\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    namespace graph_helpers \n    {\n        template <typename T, typename U>\n        inline bool is_same_object (\n            const T& a,\n            const U& b\n        )\n        {\n            if (is_same_type<const T,const U>::value == false)\n                return false;\n            if ((void*)&a == (void*)&b)\n                return true;\n            else\n                return false;\n        }\n\n        template <\n            typename T\n            >\n        bool search_for_directed_cycles (\n            const T& node,\n            std::vector<bool>& visited,\n            std::vector<bool>& temp\n        )\n        /*!\n            requires\n                - visited.size() >= number of nodes in the graph that contains the given node \n                - temp.size() >= number of nodes in the graph that contains the given node \n                - for all i in temp: \n                    - temp[i] == false\n            ensures\n                - checks the connected subgraph containing the given node for directed cycles\n                  and returns true if any are found and false otherwise.\n                - for all nodes N in the connected subgraph containing the given node:\n                    - #visited[N.index()] == true\n                - for all i in temp: \n                    - #temp[i] == false\n        !*/\n        {\n            if (temp[node.index()] == true)\n                return true;\n\n            visited[node.index()] = true;\n            temp[node.index()] = true;\n\n            for (unsigned long i = 0; i < node.number_of_children(); ++i)\n            {\n                if (search_for_directed_cycles(node.child(i), visited, temp))\n                    return true;\n            }\n                \n            temp[node.index()] = false;\n\n            return false;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        typename enable_if<is_directed_graph<typename T::graph_type>,bool>::type search_for_undirected_cycles (\n            const T& node,\n            std::vector<bool>& visited,\n            unsigned long prev = std::numeric_limits<unsigned long>::max()\n        )\n        /*!\n            requires\n                - visited.size() >= number of nodes in the graph that contains the given node \n                - for all nodes N in the connected subgraph containing the given node:\n                    - visited[N.index] == false\n            ensures\n                - checks the connected subgraph containing the given node for directed cycles\n                  and returns true if any are found and false otherwise.\n                - for all nodes N in the connected subgraph containing the given node:\n                    - #visited[N.index()] == true\n        !*/\n        {\n            if (visited[node.index()] == true)\n                return true;\n\n            visited[node.index()] = true;\n\n            for (unsigned long i = 0; i < node.number_of_children(); ++i)\n            {\n                if (node.child(i).index() != prev && \n                    search_for_undirected_cycles(node.child(i), visited, node.index()))\n                    return true;\n            }\n                \n            for (unsigned long i = 0; i < node.number_of_parents(); ++i)\n            {\n                if (node.parent(i).index() != prev && \n                    search_for_undirected_cycles(node.parent(i), visited, node.index()))\n                    return true;\n            }\n\n            return false;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        typename enable_if<is_graph<typename T::graph_type>,bool>::type search_for_undirected_cycles (\n            const T& node,\n            std::vector<bool>& visited,\n            unsigned long prev = std::numeric_limits<unsigned long>::max()\n        )\n        /*!\n            requires\n                - visited.size() >= number of nodes in the graph that contains the given node \n                - for all nodes N in the connected subgraph containing the given node:\n                    - visited[N.index] == false\n            ensures\n                - checks the connected subgraph containing the given node for directed cycles\n                  and returns true if any are found and false otherwise.\n                - for all nodes N in the connected subgraph containing the given node:\n                    - #visited[N.index()] == true\n        !*/\n        {\n            if (visited[node.index()] == true)\n                return true;\n\n            visited[node.index()] = true;\n\n            for (unsigned long i = 0; i < node.number_of_neighbors(); ++i)\n            {\n                if (node.neighbor(i).index() != prev && \n                    search_for_undirected_cycles(node.neighbor(i), visited, node.index()))\n                    return true;\n            }\n                \n            return false;\n        }\n\n    }\n\n// ------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type1,\n        typename graph_type2\n        >\n    typename enable_if<is_graph<graph_type1> >::type copy_graph_structure (\n        const graph_type1& src,\n        graph_type2& dest\n    )\n    {\n        COMPILE_TIME_ASSERT(is_graph<graph_type1>::value);\n        COMPILE_TIME_ASSERT(is_graph<graph_type2>::value);\n        if (graph_helpers::is_same_object(src,dest))\n            return;\n\n        dest.clear();\n        dest.set_number_of_nodes(src.number_of_nodes());\n\n        // copy all the edges from src into dest \n        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)\n        {\n            for (unsigned long j = 0; j < src.node(i).number_of_neighbors(); ++j)\n            {\n                const unsigned long nidx = src.node(i).neighbor(j).index();\n                if (nidx >= i)\n                {\n                    dest.add_edge(i,nidx);\n                }\n            }\n        }\n    }\n\n    template <\n        typename graph_type1,\n        typename graph_type2\n        >\n    typename enable_if<is_directed_graph<graph_type1> >::type copy_graph_structure (\n        const graph_type1& src,\n        graph_type2& dest\n    )\n    {\n        COMPILE_TIME_ASSERT(is_directed_graph<graph_type1>::value);\n        COMPILE_TIME_ASSERT(is_directed_graph<graph_type2>::value || is_graph<graph_type2>::value );\n        if (graph_helpers::is_same_object(src,dest))\n            return;\n\n        dest.clear();\n        dest.set_number_of_nodes(src.number_of_nodes());\n\n        // copy all the edges from src into dest \n        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)\n        {\n            for (unsigned long j = 0; j < src.node(i).number_of_children(); ++j)\n            {\n                const unsigned long nidx = src.node(i).child(j).index();\n                if (dest.has_edge(i,nidx) == false)\n                {\n                    dest.add_edge(i,nidx);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type1,\n        typename graph_type2\n        >\n    typename enable_if<is_graph<graph_type1> >::type copy_graph (\n        const graph_type1& src,\n        graph_type2& dest\n    )\n    {\n        COMPILE_TIME_ASSERT(is_graph<graph_type1>::value);\n        COMPILE_TIME_ASSERT(is_graph<graph_type2>::value);\n        if (graph_helpers::is_same_object(src,dest))\n            return;\n\n        copy_graph_structure(src,dest);\n\n        // copy all the node and edge content \n        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)\n        {\n            dest.node(i).data = src.node(i).data;\n\n            for (unsigned long j = 0; j < src.node(i).number_of_neighbors(); ++j)\n            {\n                const unsigned long nidx = src.node(i).neighbor(j).index();\n                if (nidx >= i)\n                {\n                    dest.node(i).edge(j) = src.node(i).edge(j);\n                }\n            }\n        }\n    }\n\n    template <\n        typename graph_type1,\n        typename graph_type2\n        >\n    typename enable_if<is_directed_graph<graph_type1> >::type copy_graph (\n        const graph_type1& src,\n        graph_type2& dest\n    )\n    {\n        COMPILE_TIME_ASSERT(is_directed_graph<graph_type1>::value);\n        COMPILE_TIME_ASSERT(is_directed_graph<graph_type2>::value);\n        if (graph_helpers::is_same_object(src,dest))\n            return;\n\n        copy_graph_structure(src,dest);\n\n        // copy all the node and edge content \n        for (unsigned long i = 0; i < src.number_of_nodes(); ++i)\n        {\n            dest.node(i).data = src.node(i).data;\n            for (unsigned long j = 0; j < src.node(i).number_of_children(); ++j)\n            {\n                dest.node(i).child_edge(j) = src.node(i).child_edge(j);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename S\n        >\n    typename enable_if<is_graph<typename T::graph_type> >::type find_connected_nodes (\n    const T& n,\n    S& visited\n    )\n    {\n        if (visited.is_member(n.index()) == false)\n        {\n            unsigned long temp = n.index();\n            visited.add(temp);\n\n            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)\n                find_connected_nodes(n.neighbor(i), visited);\n        }\n    }\n\n    template <\n        typename T,\n        typename S\n        >\n    typename enable_if<is_directed_graph<typename T::graph_type> >::type find_connected_nodes (\n    const T& n,\n    S& visited\n    )\n    {\n        if (visited.is_member(n.index()) == false)\n        {\n            unsigned long temp = n.index();\n            visited.add(temp);\n\n            for (unsigned long i = 0; i < n.number_of_parents(); ++i)\n                find_connected_nodes(n.parent(i), visited);\n            for (unsigned long i = 0; i < n.number_of_children(); ++i)\n                find_connected_nodes(n.child(i), visited);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    bool graph_is_connected (\n        const T& g\n    )\n    {\n        if (g.number_of_nodes() == 0)\n            return true;\n\n        set<unsigned long>::kernel_1b_c visited;\n        find_connected_nodes(g.node(0), visited);\n        return (visited.size() == g.number_of_nodes());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_has_symmetric_edges (\n        const T& graph\n    )\n    {\n        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)\n        {\n            for (unsigned long j = 0; j < graph.node(i).number_of_children(); ++j)\n            {\n                const unsigned long jj = graph.node(i).child(j).index();\n                // make sure every edge from a parent to a child has an edge linking back\n                if (graph.has_edge(jj,i) == false)\n                    return false;\n            }\n\n            for (unsigned long j = 0; j < graph.node(i).number_of_parents(); ++j)\n            {\n                const unsigned long jj = graph.node(i).parent(j).index();\n                // make sure every edge from a child to a parent has an edge linking back\n                if (graph.has_edge(i,jj) == false)\n                    return false;\n            }\n        }\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename T\n        >\n    bool graph_contains_directed_cycle (\n        const T& graph\n    )\n    {\n        using namespace graph_helpers;\n        std::vector<bool> visited(graph.number_of_nodes(), false);\n        std::vector<bool> temp(graph.number_of_nodes(), false);\n\n        while (true)\n        {\n            // find the first node that hasn't been visited yet\n            unsigned long i;\n            for (i = 0; i < visited.size(); ++i)\n            {\n                if (visited[i] == false)\n                    break;\n            }\n\n            // if we didn't find any non-visited nodes then we are done\n            if (i == visited.size())\n                return false;\n\n            if (search_for_directed_cycles(graph.node(i), visited, temp))\n                return true;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_contains_undirected_cycle (\n        const T& graph\n    )\n    {\n        using namespace graph_helpers;\n        std::vector<bool> visited(graph.number_of_nodes(), false);\n\n        while (true)\n        {\n            // find the first node that hasn't been visited yet\n            unsigned long i;\n            for (i = 0; i < visited.size(); ++i)\n            {\n                if (visited[i] == false)\n                    break;\n            }\n\n            // if we didn't find any non-visited nodes then we are done\n            if (i == visited.size())\n                return false;\n\n            if (search_for_undirected_cycles(graph.node(i), visited))\n                return true;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename directed_graph_type,\n        typename graph_type\n        >\n    void create_moral_graph (\n        const directed_graph_type& g,\n        graph_type& moral_graph\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_directed_cycle(g) == false,\n            \"\\tvoid create_moral_graph(g, moral_graph)\"\n            << \"\\n\\tYou can only make moral graphs if g doesn't have directed cycles\"\n            );\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);\n        COMPILE_TIME_ASSERT(is_directed_graph<directed_graph_type>::value);\n\n        copy_graph_structure(g, moral_graph);\n\n        // now marry all the parents (i.e. add edges between parent nodes)\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            // loop over all combinations of parents of g.node(i)\n            for (unsigned long j = 0; j < g.node(i).number_of_parents(); ++j)\n            {\n                for (unsigned long k = 0; k < g.node(i).number_of_parents(); ++k)\n                {\n                    const unsigned long p1 = g.node(i).parent(j).index();\n                    const unsigned long p2 = g.node(i).parent(k).index();\n                    if (p1 == p2)\n                        continue;\n\n                    if (moral_graph.has_edge(p1,p2) == false)\n                        moral_graph.add_edge(p1,p2);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename sets_of_int\n        >\n    bool is_clique (\n        const graph_type& g,\n        const sets_of_int& clique\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n            \"\\tvoid is_clique(g, clique)\"\n            << \"\\n\\tinvalid graph\"\n            );\n#ifdef ENABLE_ASSERTS\n        clique.reset();\n        while (clique.move_next())\n        {\n            const unsigned long x = clique.element();\n            DLIB_ASSERT( x < g.number_of_nodes(), \n                \"\\tvoid is_clique(g, clique)\"\n                << \"\\n\\tthe clique set contained an invalid node index\"\n                << \"\\n\\tx:                   \" << x \n                << \"\\n\\tg.number_of_nodes(): \" << g.number_of_nodes()\n                );\n        }\n#endif\n\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);\n\n        std::vector<unsigned long> v;\n        v.reserve(clique.size());\n        clique.reset();\n        while (clique.move_next())\n        {\n            v.push_back(clique.element());\n        }\n\n        for (unsigned long i = 0; i < v.size(); ++i)\n        {\n            for (unsigned long j = 0; j < v.size(); ++j)\n            {\n                if (v[i] == v[j])\n                    continue;\n                if (g.has_edge(v[i], v[j]) == false)\n                    return false;\n            }\n        }\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename sets_of_int\n        >\n    bool is_maximal_clique (\n        const graph_type& g,\n        const sets_of_int& clique\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n            \"\\tvoid is_maximal_clique(g, clique)\"\n            << \"\\n\\tinvalid graph\"\n            );\n        DLIB_ASSERT(is_clique(g,clique) == true,\n            \"\\tvoid is_maximal_clique(g, clique)\"\n            << \"\\n\\tinvalid graph\"\n            );\n#ifdef ENABLE_ASSERTS\n        clique.reset();\n        while (clique.move_next())\n        {\n            const unsigned long x = clique.element();\n            DLIB_ASSERT( x < g.number_of_nodes(), \n                \"\\tvoid is_maximal_clique(g, clique)\"\n                << \"\\n\\tthe clique set contained an invalid node index\"\n                << \"\\n\\tx:                   \" << x \n                << \"\\n\\tg.number_of_nodes(): \" << g.number_of_nodes()\n                );\n        }\n#endif\n\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);\n\n        if (clique.size() == 0)\n            return true;\n\n        // get an element in the clique and make sure that\n        // none of its neighbors that aren't in the clique are connected \n        // to all the elements of the clique.\n        clique.reset();\n        clique.move_next();\n        const unsigned long idx = clique.element();\n\n        for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i)\n        {\n            const unsigned long n = g.node(idx).neighbor(i).index();\n            if (clique.is_member(n))\n                continue;\n\n            // now loop over all the clique members and make sure they don't all\n            // share an edge with node n\n            bool all_share_edge = true;\n            clique.reset();\n            while (clique.move_next())\n            {\n                if (g.has_edge(clique.element(), n) == false)\n                {\n                    all_share_edge = false;\n                    break;\n                }\n            }\n\n            if (all_share_edge == true)\n                return false;\n        }\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename enable_if<is_directed_graph<T>,bool>::type graph_contains_length_one_cycle (\n        const T& graph\n    )\n    {\n        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)\n        {\n            // make sure none of this guys children are actually itself\n            for (unsigned long n = 0; n < graph.node(i).number_of_children(); ++n)\n            {\n                if (graph.node(i).child(n).index() == i)\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename enable_if<is_graph<T>,bool>::type graph_contains_length_one_cycle (\n        const T& graph\n    )\n    {\n        for (unsigned long i = 0; i < graph.number_of_nodes(); ++i)\n        {\n            // make sure none of this guys neighbors are actually itself\n            for (unsigned long n = 0; n < graph.node(i).number_of_neighbors(); ++n)\n            {\n                if (graph.node(i).neighbor(n).index() == i)\n                    return true;\n            }\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace graph_helpers\n    {\n        struct pair\n        {\n            unsigned long index;\n            unsigned long num_neighbors;\n\n            bool operator< (const pair& p) const { return num_neighbors < p.num_neighbors; }\n        };\n\n        template <\n            typename T,\n            typename S,\n            typename V\n            >\n        void search_graph_for_triangulate (\n            const T& n,\n            S& visited,\n            V& order_visited\n        )\n        {\n            // base case of recursion.  stop when we hit a node we have\n            // already visited.\n            if (visited.is_member(n.index()))\n                return;\n\n            // record that we have visited this node\n            order_visited.push_back(n.index());\n            unsigned long temp = n.index();\n            visited.add(temp);\n\n            // we want to visit all the neighbors of this node but do\n            // so by visiting the nodes with the most neighbors first.  So\n            // lets make a vector that lists the nodes in the order we \n            // want to visit them\n            std::vector<pair> neighbors;\n            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)\n            {\n                pair p;\n                p.index = i;\n                p.num_neighbors = n.neighbor(i).number_of_neighbors();\n                neighbors.push_back(p);\n            }\n\n            // now sort the neighbors array so that the neighbors with the\n            // most neighbors come first.\n            std::sort(neighbors.rbegin(), neighbors.rend());\n\n            // now visit all the nodes\n            for (unsigned long i = 0; i < neighbors.size(); ++i)\n            {\n                search_graph_for_triangulate(n.neighbor(neighbors[i].index), visited, order_visited);\n            }\n        }\n    } // end namespace graph_helpers\n\n    template <\n        typename graph_type,\n        typename set_of_sets_of_int\n        >\n    void triangulate_graph_and_find_cliques (\n        graph_type& g,\n        set_of_sets_of_int& cliques\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n            \"\\tvoid triangulate_graph_and_find_cliques(g, cliques)\"\n            << \"\\n\\tInvalid graph\"\n            );\n        DLIB_ASSERT(graph_is_connected(g) == true,\n            \"\\tvoid triangulate_graph_and_find_cliques(g, cliques)\"\n            << \"\\n\\tInvalid graph\"\n            );\n\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);\n\n\n        using namespace graph_helpers;\n        typedef typename set_of_sets_of_int::type set_of_int;\n\n        cliques.clear();\n\n        // first we find the node with the most neighbors\n        unsigned long max_index = 0;\n        unsigned long num_neighbors = 0;\n        for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n        {\n            if (g.node(i).number_of_neighbors() > num_neighbors)\n            {\n                max_index = i;\n                num_neighbors = g.node(i).number_of_neighbors();\n            }\n        }\n\n        // now we do a depth first search of the entire graph starting\n        // with the node we just found.  We record the order in which\n        // we visit each node in the vector order_visited.\n        std::vector<unsigned long> order_visited;\n        set_of_int visited;\n        search_graph_for_triangulate(g.node(max_index), visited, order_visited);\n\n        set_of_int clique;\n\n        // now add edges to the graph to make it triangulated  \n        while (visited.size() > 0)\n        {\n            // we are going to enumerate over the nodes in the reverse of the\n            // order in which they were visited.  So get the last node out.\n            const unsigned long idx = order_visited.back();\n            order_visited.pop_back();\n            visited.destroy(idx);\n\n            // as a start add this node to our current clique\n            unsigned long temp = idx;\n            clique.clear();\n            clique.add(temp);\n\n            // now we want to make a clique that contains node g.node(idx) and\n            // all of its neighbors that are still recorded in the visited set \n            // (except for neighbors that have only one edge).\n            for (unsigned long i = 0; i < g.node(idx).number_of_neighbors(); ++i)\n            {\n                // get the index of the i'th neighbor\n                unsigned long nidx = g.node(idx).neighbor(i).index();\n\n                // add it to the clique if it is still in visited and it isn't\n                // a node with only one neighbor\n                if (visited.is_member(nidx) == true && \n                    g.node(nidx).number_of_neighbors() != 1)\n                {\n                    // add edges between this new node and all the nodes \n                    // that are already in the clique\n                    clique.reset();\n                    while (clique.move_next())\n                    {\n                        if (g.has_edge(nidx, clique.element()) == false)\n                            g.add_edge(nidx, clique.element());\n                    }\n\n                    // now also record that we added this node to the clique\n                    clique.add(nidx);\n                }\n            }\n\n            if (cliques.is_member(clique) == false && is_maximal_clique(g,clique) )\n            {\n                cliques.add(clique);\n            }\n\n            // now it is possible that we are missing some cliques of size 2 since\n            // above we didn't add nodes with only one edge to any of our cliques.\n            // Now lets make sure all these nodes are accounted for\n            for (unsigned long i = 0; i < g.number_of_nodes(); ++i)\n            {\n                clique.clear();\n                if (g.node(i).number_of_neighbors() == 1)\n                {\n                    unsigned long temp = i;\n                    clique.add(temp);\n                    temp = g.node(i).neighbor(0).index();\n                    clique.add(temp);\n\n                    if (cliques.is_member(clique) == false)\n                        cliques.add(clique);\n                }\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename join_tree_type\n        >\n    void create_join_tree (\n        const graph_type& g,\n        join_tree_type& join_tree\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n            \"\\tvoid create_join_tree(g, join_tree)\"\n            << \"\\n\\tInvalid graph\"\n            );\n        DLIB_ASSERT(graph_is_connected(g) == true,\n            \"\\tvoid create_join_tree(g, join_tree)\"\n            << \"\\n\\tInvalid graph\"\n            );\n\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value);\n        COMPILE_TIME_ASSERT(is_graph<join_tree_type>::value);\n\n\n\n        typedef typename join_tree_type::type set_of_int;\n        typedef typename join_tree_type::edge_type set_of_int_edge;\n        typedef typename set<set_of_int>::kernel_1b_c set_of_sets_of_int;\n\n        copy_graph_structure(g, join_tree);\n\n        // don't even bother in this case\n        if (g.number_of_nodes() == 0)\n            return;\n\n        set_of_sets_of_int cliques;\n        set_of_int s;\n\n        triangulate_graph_and_find_cliques(join_tree, cliques);\n\n        join_tree.set_number_of_nodes(cliques.size());\n\n        // copy the cliques into each of the nodes of tree\n        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)\n        {\n            cliques.remove_any(s);\n            s.swap(join_tree.node(i).data);\n        }\n\n        set_of_int_edge e;\n\n        // add all possible edges to the join_tree\n        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)\n        {\n            for (unsigned long j = i+1; j < join_tree.number_of_nodes(); ++j)\n            {\n                set_intersection(\n                    join_tree.node(i).data,\n                    join_tree.node(j).data,\n                    e);\n\n                if (e.size() > 0)\n                {\n                    join_tree.add_edge(i,j);\n                    edge(join_tree,i,j).swap(e);\n                }\n            }\n        }\n\n        // now we just need to remove the unnecessary edges so that we get a \n        // proper join tree\n        s.clear();\n        set_of_int& good = s; // rename s to something slightly more meaningful\n        // good will contain nodes that have been \"approved\"\n        unsigned long n = 0;\n        good.add(n);\n\n        std::vector<unsigned long> vtemp;\n\n        while (good.size() < join_tree.number_of_nodes())\n        {\n            // figure out which of the neighbors of nodes in good has the best edge\n            unsigned long best_bad_idx = 0;\n            unsigned long best_good_idx = 0;\n            unsigned long best_overlap = 0;\n            good.reset();\n            while (good.move_next())\n            {\n                // loop over all the neighbors of the current node in good\n                for (unsigned long i = 0; i < join_tree.node(good.element()).number_of_neighbors(); ++i)\n                {\n                    const unsigned long idx = join_tree.node(good.element()).neighbor(i).index();\n                    if (!good.is_member(idx))\n                    {\n                        const unsigned long overlap = join_tree.node(good.element()).edge(i).size();\n\n                        if (overlap > best_overlap)\n                        {\n                            best_overlap = overlap;\n                            best_bad_idx = idx;\n                            best_good_idx = good.element();\n                        }\n                    }\n                }\n            }\n\n            // now remove all the edges from best_bad_idx to the nodes in good except for the\n            // edge to best_good_idx.\n            for (unsigned long i = 0; i < join_tree.node(best_bad_idx).number_of_neighbors(); ++i)\n            {\n                const unsigned long idx = join_tree.node(best_bad_idx).neighbor(i).index();\n                if (idx != best_good_idx && good.is_member(idx))\n                {\n                    vtemp.push_back(idx);\n                }\n            }\n\n            for (unsigned long i = 0; i < vtemp.size(); ++i)\n                join_tree.remove_edge(vtemp[i], best_bad_idx);\n\n            vtemp.clear();\n\n\n            // and finally add this bad index into the good set\n            good.add(best_bad_idx);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace graph_helpers\n    {\n        template <\n            typename T,\n            typename U\n            >\n        bool validate_join_tree (\n            const T& n,\n            U& deads,\n            unsigned long parent = 0xffffffff\n        )\n        /*!\n            this function makes sure that a join tree satisfies the following criterion for paths starting at the given node:\n                - for all valid i and j such that i and j are both < #join_tree.number_of_nodes()\n                    - let X be the set of numbers that is contained in both #join_tree.node(i).data\n                      and #join_tree.node(j).data\n                    - It is the case that all nodes on the unique path between #join_tree.node(i)\n                      and #join_tree.node(j) contain the numbers from X in their sets.\n\n            returns true if validation passed and false if there is a problem with the tree\n        !*/\n        {\n            n.data.reset();\n            while (n.data.move_next())\n            {\n                if (deads.is_member(n.data.element()))\n                    return false;\n            }\n\n\n            for (unsigned long i = 0; i < n.number_of_neighbors(); ++i)\n            {\n                if (n.neighbor(i).index() == parent)\n                    continue;\n\n                // add anything to dead stuff\n                n.data.reset();\n                while (n.data.move_next())\n                {\n                    if (n.neighbor(i).data.is_member(n.data.element()) == false)\n                    {\n                        unsigned long temp = n.data.element();\n                        deads.add(temp);\n                    }\n                }\n\n                if (validate_join_tree(n.neighbor(i), deads, n.index()) == false)\n                    return false;\n\n                // remove this nodes stuff from dead stuff\n                n.data.reset();\n                while (n.data.move_next())\n                {\n                    if (n.neighbor(i).data.is_member(n.data.element()) == false)\n                    {\n                        unsigned long temp = n.data.element();\n                        deads.destroy(temp);\n                    }\n                }\n            }\n\n            return true;\n        }\n    }\n\n    template <\n        typename graph_type,\n        typename join_tree_type\n        >\n    bool is_join_tree (\n        const graph_type& g,\n        const join_tree_type& join_tree\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(graph_contains_length_one_cycle(g) == false,\n            \"\\tvoid create_join_tree(g, join_tree)\"\n            << \"\\n\\tInvalid graph\"\n            );\n        DLIB_ASSERT(graph_is_connected(g) == true,\n            \"\\tvoid create_join_tree(g, join_tree)\"\n            << \"\\n\\tInvalid graph\"\n            );\n\n        COMPILE_TIME_ASSERT(is_graph<graph_type>::value || is_directed_graph<graph_type>::value);\n        COMPILE_TIME_ASSERT(is_graph<join_tree_type>::value);\n\n\n        if (graph_contains_undirected_cycle(join_tree))\n            return false;\n\n        if (graph_is_connected(join_tree) == false)\n            return false;\n\n        // verify that the path condition of the join tree is valid\n        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)\n        {\n            typename join_tree_type::type deads;\n            if (graph_helpers::validate_join_tree(join_tree.node(i), deads) == false)\n                return false;\n        }\n\n        typename join_tree_type::edge_type e;\n        typename join_tree_type::edge_type all;\n        // now make sure that the edges contain correct intersections\n        for (unsigned long i = 0; i < join_tree.number_of_nodes(); ++i)\n        {\n            set_union(all,join_tree.node(i).data, all);\n            for (unsigned long j = 0; j < join_tree.node(i).number_of_neighbors(); ++j)\n            {\n                set_intersection(join_tree.node(i).data,\n                                 join_tree.node(i).neighbor(j).data,\n                                 e);\n\n                if (!(e == join_tree.node(i).edge(j)))\n                    return false;\n            }\n        }\n\n        // and finally check that all the nodes in g show up in the join tree \n        if (all.size() != g.number_of_nodes())\n            return false;\n        all.reset();\n        while (all.move_next())\n        {\n            if (all.element() >= g.number_of_nodes())\n                return false;\n        }\n\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GRAPH_UTILs_\n\n\n"
  },
  {
    "path": "dlib/graph_utils/graph_utils_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GRAPH_UTILs_ABSTRACT_\n#ifdef DLIB_GRAPH_UTILs_ABSTRACT_\n\n#include \"../directed_graph.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename T::edge_type& edge(\n        T& g,  \n        unsigned long i, \n        unsigned long j\n    );\n    /*!\n        requires\n            - T is an implementation of graph/graph_kernel_abstract.h \n            - g.has_edge(i,j)\n        ensures\n            - returns a reference to the edge data for the edge connecting nodes i and j\n              (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j)\n    !*/\n\n    template <\n        typename T\n        >\n    typename const T::edge_type& edge(\n        const T& g,  \n        unsigned long i, \n        unsigned long j\n    );\n    /*!\n        requires\n            - T is an implementation of graph/graph_kernel_abstract.h \n            - g.has_edge(i,j)\n        ensures\n            - returns a const reference to the edge data for the edge connecting nodes i and j\n              (i.e. returns g.node(i).edge(x) such that g.node(i).neighbor(x).index() == j)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename T::edge_type& edge(\n        T& g,  \n        unsigned long parent_idx, \n        unsigned long child_idx \n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h \n            - g.has_edge(parent_idx,child_idx)\n        ensures\n            - returns a reference to the edge data for the directed edge connecting parent\n              node g.node(parent_idx) to child node g.node(child_idx).\n    !*/\n\n    template <\n        typename T\n        >\n    typename const T::edge_type& edge(\n        const T& g,  \n        unsigned long parent_idx, \n        unsigned long child_idx \n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h \n            - g.has_edge(parent_idx,child_idx)\n        ensures\n            - returns a const reference to the edge data for the directed edge connecting \n              parent node g.node(parent_idx) to child node g.node(child_idx).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_has_symmetric_edges (\n        const T& graph\n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h \n        ensures\n            - if (All nodes have either 0 edges between them or 2 edges between them.  \n              That is, if there is an edge pointing from node A to node B then there is\n              also an edge from B to A) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_contains_directed_cycle (\n        const T& graph\n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h \n        ensures\n            - if (there is a directed cycle in the given graph) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_contains_undirected_cycle (\n        const T& graph\n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              T is an implementation of graph/graph_kernel_abstract.h\n        ensures\n            - if (there is an undirected cycle in the given graph) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool graph_contains_length_one_cycle (\n        const T& graph\n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              T is an implementation of graph/graph_kernel_abstract.h\n        ensures\n            - if (it is the case that graph.has_edge(i,i) == true for some i) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename src_type,\n        typename dest_type \n        >\n    void copy_graph_structure (\n        const src_type& src,\n        dest_type& dest\n    );\n    /*!\n        requires\n            - src_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              src_type is an implementation of graph/graph_kernel_abstract.h\n            - dest_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              dest_type is an implementation of graph/graph_kernel_abstract.h\n            - dest_type is not a directed_graph when src_type is a graph\n        ensures\n            - this function copies the graph structure from src into dest\n            - #dest.number_of_nodes() == src.number_of_nodes()\n            - for all valid i: #dest.node(i).item has an initial value for its type\n            - for all valid i and j:\n                - if (src.has_edge(i,j) == true) then\n                    - #dest.has_edge(i,j) == true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename src_type,\n        typename dest_type \n        >\n    void copy_graph (\n        const src_type& src,\n        dest_type& dest\n    );\n    /*!\n        requires\n            - src_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              src_type is an implementation of graph/graph_kernel_abstract.h\n            - dest_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              dest_type is an implementation of graph/graph_kernel_abstract.h\n            - src_type and dest_type are both the same kind of graph.  That is, they\n              are either both directed or both undirected.\n            - the node and edge data in the graphs are copyable via operator=().\n        ensures\n            - #dest is a complete duplicate of src.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename directed_graph_type,\n        typename graph_type\n        >\n    void create_moral_graph (\n        const directed_graph_type& g,\n        graph_type& moral_graph\n    );\n    /*!\n        requires\n            - directed_graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h\n            - graph_type is an implementation of graph/graph_kernel_abstract.h\n            - graph_contains_directed_cycle(g) == false\n        ensures\n            - #moral_graph == the moralized version of the directed graph g\n            - #moral_graph.number_of_nodes() == g.number_of_nodes()\n            - for all valid i and j:\n                - if (g.has_edge(i,j) == true) then\n                    - #moral_graph.has_edge(i,j) == true\n                      (i.e. all the edges that are in g are also in moral_graph)\n            - for all valid i:\n                - for all pairs p1 and p2 such that p1 != p2 and g.node(p1) and g.node(p2) are both\n                  parents of node g.node(i):\n                    - #moral_graph.has_edge(p1,p2) == true\n                      (i.e. all the parents of a node are connected in the moral graph)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename S\n        >\n    void find_connected_nodes (\n        const T& n,\n        S& visited\n    );\n    /*!\n        requires\n            - T is a node_type from an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              T is a node_type from an implementation of graph/graph_kernel_abstract.h\n            - S is an implementation of set/set_kernel_abstract.h\n        ensures\n            - let G be the graph that contains node n\n            - #visited.is_member(n.index()) == true\n            - for all i such that there is an undirected path from n to G.node(i):\n                - #visited.is_member(i) == true\n            - for all i such that visited.is_member(i):\n                - #visited.is_member(i) == true\n                  (i.e. this function doesn't remove anything from visited.  So if\n                  it contains stuff when you call this function then it will still\n                  contain those things once the function ends)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    bool graph_is_connected (\n        const T& g\n    );\n    /*!\n        requires\n            - T is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              T is an implementation of graph/graph_kernel_abstract.h\n        ensures\n            - every node in g has an undirected path to every other node in g.  \n              I.e. g is a connected graph\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename sets_of_int\n        >\n    bool is_clique (\n        const graph_type& g,\n        const sets_of_int& clique\n    );\n    /*!\n        requires\n            - graph_type is an implementation of graph/graph_kernel_abstract.h\n            - sets_of_int is an implementation of set/set_kernel_abstract.h\n              and it contains unsigned long objects. \n            - graph_contains_length_one_cycle(g) == false\n            - for all x such that clique.is_member(x):\n                - x < g.number_of_nodes()\n        ensures\n            - if (it is true that for all i and j such that clique.is_member(i) and \n              clique.is_member(j) then g.has_edge(i,j) == true) then\n                - returns true\n            - else\n                - returns false\n            - if (clique.size() == 0) then\n                - returns true\n                  (this is just a special case of the above condition)\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename sets_of_int\n        >\n    bool is_maximal_clique (\n        const graph_type& g,\n        const sets_of_int& clique\n    );\n    /*!\n        requires\n            - graph_type is an implementation of graph/graph_kernel_abstract.h\n            - sets_of_int is an implementation of set/set_kernel_abstract.h\n              and it contains unsigned long objects. \n            - graph_contains_length_one_cycle(g) == false\n            - for all x such that clique.is_member(x):\n                - x < g.number_of_nodes()\n            - is_clique(g,clique) == true\n        ensures\n            - if (there is no x such that clique.is_member(x) == false \n              and g.has_edge(i,x) for all i such that cliques.is_member(i)) then\n                - returns true\n            - else\n                - returns false\n            - if (clique.size() == 0) then\n                - returns true\n                  (this is just a special case of the above condition)\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename set_of_sets_of_int\n        >\n    void triangulate_graph_and_find_cliques (\n        graph_type& g,\n        set_of_sets_of_int& cliques\n    );\n    /*!\n        requires\n            - graph_type is an implementation of graph/graph_kernel_abstract.h\n            - set_of_sets_of_int is an implementation of set/set_kernel_abstract.h\n              and it contains another set object which is comparable by operator< and\n              itself contains unsigned long objects.  \n              (e.g. set<set<unsigned long>::compare_1a>::kernel_1a)\n            - graph_contains_length_one_cycle(g) == false\n            - graph_is_connected(g) == true\n        ensures\n            - #g.number_of_nodes() == g.number_of_nodes()\n            - all this function does to g is add edges to it until g becomes a \n              chordal graph where a chordal graph is a graph where each cycle\n              in the graph of 4 or more nodes has an edge joining two nodes\n              that are not adjacent in the cycle. \n            - #cliques.size() == the number of maximal cliques in the graph #g\n            - for all valid sets S such that #cliques.is_member(S):\n                - for all valid integers i and j such that S.is_member(i) == true\n                  and S.is_member(j) == true and i != j:\n                    - #g.has_edge(i,j) == true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename join_tree_type\n        >\n    bool is_join_tree (\n        const graph_type& g,\n        const join_tree_type& join_tree\n    );\n    /*!\n        requires\n            - graph_type is an implementation of directed_graph/directed_graph_kernel_abstract.h or\n              graph_type is an implementation of graph/graph_kernel_abstract.h\n            - join_tree_type is an implementation of graph/graph_kernel_abstract.h\n            - join_tree_type::type is an implementation of set/set_compare_abstract.h and\n              this set type contains unsigned long objects. \n            - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and\n              this set type contains unsigned long objects. \n            - graph_contains_length_one_cycle(g) == false\n            - graph_is_connected(g) == true\n        ensures\n            - if (join_tree is a valid join tree of graph g.  That is, join_tree is a \n              tree decomposition of g) then\n                - returns true\n            - else\n                - returns false\n\n            - a join tree of graph g is defined as follows: \n                - graph_contains_undirected_cycle(join_tree) == false\n                - graph_is_connected(join_tree) == true\n                - for all valid i:\n                    - join_tree.node(i).item == a non-empty set containing node indexes \n                      from g.  That is, this set contains all the nodes from g that are\n                      in this cluster in the join tree\n                - for all valid i and j such that i and j are both < join_tree.number_of_nodes()\n                    - let X be the set of numbers that is contained in both join_tree.node(i).item\n                      and join_tree.node(j).item\n                    - It is the case that all nodes on the unique path between join_tree.node(i)\n                      and join_tree.node(j) contain the numbers from X in their sets.\n                    - edge(join_tree,i,j) == a set containing the intersection of \n                      join_tree.node(i).item and join_tree.node(j).item\n                - the node index for every node in g appears in some node in join_tree at \n                  least once.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type,\n        typename join_tree_type\n        >\n    void create_join_tree (\n        const graph_type& g,\n        join_tree_type& join_tree\n    );\n    /*!\n        requires\n            - graph_type is an implementation of graph/graph_kernel_abstract.h\n            - join_tree_type is an implementation of graph/graph_kernel_abstract.h\n            - join_tree_type::type is an implementation of set/set_compare_abstract.h and\n              this set type contains unsigned long objects. \n            - join_tree_type::edge_type is an implementation of set/set_compare_abstract.h and\n              this set type contains unsigned long objects. \n            - graph_contains_length_one_cycle(g) == false\n            - graph_is_connected(g) == true\n        ensures\n            - #is_join_tree(g, join_tree) == true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GRAPH_UTILs_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/graph_utils/ordered_sample_pair.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ORDERED_SAMPLE_PaIR_Hh_\n#define DLIB_ORDERED_SAMPLE_PaIR_Hh_\n\n#include \"ordered_sample_pair_abstract.h\"\n#include <limits>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class ordered_sample_pair \n    {\n    public:\n        ordered_sample_pair(\n        ) : \n            _index1(0),\n            _index2(0)\n        {\n            _distance = 1;\n        }\n\n        ordered_sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2\n        )\n        {\n            _distance = 1;\n            _index1 = idx1;\n            _index2 = idx2;\n        }\n\n        ordered_sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2,\n            const double dist\n        )\n        {\n            _distance = dist;\n            _index1 = idx1;\n            _index2 = idx2;\n        }\n\n        const unsigned long& index1 (\n        ) const { return _index1; }\n\n        const unsigned long& index2 (\n        ) const { return _index2; }\n\n        const double& distance (\n        ) const { return _distance; }\n\n    private:\n        unsigned long _index1;\n        unsigned long _index2;\n        double _distance;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool operator == (\n        const ordered_sample_pair& a,\n        const ordered_sample_pair& b\n    ) \n    {\n        return a.index1() == b.index1() && a.index2() == b.index2();\n    }\n\n    inline bool operator != (\n        const ordered_sample_pair& a,\n        const ordered_sample_pair& b\n    ) \n    {\n        return !(a == b); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const ordered_sample_pair& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.index1(),out);\n            serialize(item.index2(),out);\n            serialize(item.distance(),out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type ordered_sample_pair\"); \n        }\n    }\n\n    inline void deserialize (\n        ordered_sample_pair& item,\n        std::istream& in \n    )\n    {\n        try\n        {\n            unsigned long idx1, idx2;\n            double dist;\n\n            deserialize(idx1,in);\n            deserialize(idx2,in);\n            deserialize(dist,in);\n            item = ordered_sample_pair(idx1, idx2, dist);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while deserializing object of type ordered_sample_pair\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ORDERED_SAMPLE_PaIR_Hh_\n\n"
  },
  {
    "path": "dlib/graph_utils/ordered_sample_pair_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_\n#ifdef DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_\n\n#include <limits>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class ordered_sample_pair \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is intended to represent an edge in a directed graph which has\n                data samples at its vertices.  So it contains two integers (index1 and\n                index2) which represent the identifying indices of the samples at the ends\n                of an edge.  \n\n                This object also contains a double which can be used for any purpose.\n        !*/\n\n    public:\n        ordered_sample_pair(\n        );\n        /*!\n            ensures\n                - #index1() == 0\n                - #index2() == 0\n                - #distance() == 1 \n        !*/\n\n        ordered_sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2\n        );\n        /*!\n            ensures\n                - #index1() == idx1\n                - #index2() == idx2\n                - #distance() == 1 \n        !*/\n\n        ordered_sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2,\n            const double dist\n        );\n        /*!\n            ensures\n                - #index1() == idx1\n                - #index2() == idx2\n                - #distance() == dist\n        !*/\n\n        const unsigned long& index1 (\n        ) const; \n        /*!\n            ensures\n                - returns the first index value stored in this object \n        !*/\n\n        const unsigned long& index2 (\n        ) const; \n        /*!\n            ensures\n                - returns the second index value stored in this object \n        !*/\n\n        const double& distance (\n        ) const;\n        /*!\n            ensures\n                - returns the floating point number stored in this object\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool operator == (\n        const ordered_sample_pair& a,\n        const ordered_sample_pair& b\n    );\n    /*!\n        ensures\n            - returns a.index1() == b.index1() && a.index2() == b.index2();\n              I.e. returns true if a and b both represent the same pair and false otherwise.  \n              Note that the distance field is not involved in this comparison.\n    !*/\n\n    inline bool operator != (\n        const ordered_sample_pair& a,\n        const ordered_sample_pair& b\n    );\n    /*!\n        ensures\n            - returns !(a == b)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const ordered_sample_pair& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    inline void deserialize (\n        ordered_sample_pair& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ORDERED_SAMPLE_PaIR_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_utils/sample_pair.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAMPLE_PaIR_Hh_\n#define DLIB_SAMPLE_PaIR_Hh_\n\n#include \"sample_pair_abstract.h\"\n#include <limits>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class sample_pair \n    {\n    public:\n        sample_pair(\n        ) : \n            _index1(0),\n            _index2(0)\n        {\n            _distance = 1;\n        }\n\n        sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2\n        )\n        {\n            _distance = 1;\n            if (idx1 < idx2)\n            {\n                _index1 = idx1;\n                _index2 = idx2;\n            }\n            else\n            {\n                _index1 = idx2;\n                _index2 = idx1;\n            }\n        }\n\n        sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2,\n            const double dist\n        )\n        {\n            _distance = dist;\n            if (idx1 < idx2)\n            {\n                _index1 = idx1;\n                _index2 = idx2;\n            }\n            else\n            {\n                _index1 = idx2;\n                _index2 = idx1;\n            }\n        }\n\n        const unsigned long& index1 (\n        ) const { return _index1; }\n\n        const unsigned long& index2 (\n        ) const { return _index2; }\n\n        const double& distance (\n        ) const { return _distance; }\n\n    private:\n        unsigned long _index1;\n        unsigned long _index2;\n        double _distance;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline bool order_by_index (\n        const T& a,\n        const T& b\n    )\n    {\n        return a.index1() < b.index1() || (a.index1() == b.index1() && a.index2() < b.index2());\n    }\n\n    template <typename T>\n    inline bool order_by_distance (\n        const T& a,\n        const T& b\n    )\n    {\n        return a.distance() < b.distance();\n    }\n\n    template <typename T>\n    inline bool order_by_descending_distance (\n        const T& a,\n        const T& b\n    )\n    {\n        return a.distance() > b.distance();\n    }\n\n    template <typename T>\n    bool order_by_distance_and_index (\n        const T& a,\n        const T& b\n    )\n    { \n        return a.distance() < b.distance() || (a.distance() == b.distance() && order_by_index(a,b)); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool operator == (\n        const sample_pair& a,\n        const sample_pair& b\n    ) \n    {\n        return a.index1() == b.index1() && a.index2() == b.index2();\n    }\n\n    inline bool operator != (\n        const sample_pair& a,\n        const sample_pair& b\n    ) \n    {\n        return !(a == b); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const sample_pair& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.index1(),out);\n            serialize(item.index2(),out);\n            serialize(item.distance(),out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type sample_pair\"); \n        }\n    }\n\n    inline void deserialize (\n        sample_pair& item,\n        std::istream& in \n    )\n    {\n        try\n        {\n            unsigned long idx1, idx2;\n            double dist;\n\n            deserialize(idx1,in);\n            deserialize(idx2,in);\n            deserialize(dist,in);\n            item = sample_pair(idx1, idx2, dist);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while deserializing object of type sample_pair\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAMPLE_PaIR_Hh_\n\n"
  },
  {
    "path": "dlib/graph_utils/sample_pair_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SAMPLE_PaIR_ABSTRACT_Hh_\n#ifdef DLIB_SAMPLE_PaIR_ABSTRACT_Hh_\n\n#include <limits>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class sample_pair \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is intended to represent an edge in an undirected graph \n                which has data samples at its vertices.  So it contains two integers\n                (index1 and index2) which represent the identifying indices of \n                the samples at the ends of an edge.  Note that this object enforces\n                the constraint that index1 <= index2.  This has the effect of \n                making the edges undirected since a sample_pair is incapable\n                of representing a single edge in more than one way.  That is,\n                sample_pair(i,j) == sample_pair(j,i) for any value of i and j.\n\n                This object also contains a double which can be used for any purpose.\n        !*/\n\n    public:\n        sample_pair(\n        );\n        /*!\n            ensures\n                - #index1() == 0\n                - #index2() == 0\n                - #distance() == 1 \n        !*/\n\n        sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2\n        );\n        /*!\n            ensures\n                - #index1() == min(idx1,idx2)\n                - #index2() == max(idx1,idx2)\n                - #distance() == 1 \n        !*/\n\n        sample_pair (\n            const unsigned long idx1,\n            const unsigned long idx2,\n            const double dist\n        );\n        /*!\n            ensures\n                - #index1() == min(idx1,idx2)\n                - #index2() == max(idx1,idx2)\n                - #distance() == dist\n        !*/\n\n        const unsigned long& index1 (\n        ) const; \n        /*!\n            ensures\n                - returns the first index value stored in this object \n        !*/\n\n        const unsigned long& index2 (\n        ) const; \n        /*!\n            ensures\n                - returns the second index value stored in this object \n        !*/\n\n        const double& distance (\n        ) const;\n        /*!\n            ensures\n                - returns the floating point number stored in this object\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    bool order_by_index (\n        const T& a,\n        const T& b\n    ) { return a.index1() < b.index1() || (a.index1() == b.index1() && a.index2() < b.index2()); }\n    /*!\n        requires\n            - T is a type with an interface compatible with sample_pair.\n        ensures\n            - provides a total ordering of sample_pair objects that will cause pairs that are \n              equal to be adjacent when sorted.  So for example, this function can be used\n              with std::sort() to first sort a sequence of sample_pair objects and then\n              find duplicate edges.\n    !*/\n\n    template <typename T>\n    bool order_by_distance (\n        const T& a,\n        const T& b\n    ) { return a.distance() < b.distance(); }\n    /*!\n        requires\n            - T is a type with an interface compatible with sample_pair.\n        ensures\n            - provides a total ordering of sample_pair objects that causes pairs with \n              smallest distance to be the first in a sorted list.  This function can be\n              used with std::sort().\n    !*/\n\n    template <typename T>\n    bool order_by_descending_distance (\n        const T& a,\n        const T& b\n    ) { return a.distance() > b.distance(); }\n    /*!\n        requires\n            - T is a type with an interface compatible with sample_pair.\n        ensures\n            - provides a total ordering of sample_pair objects that causes pairs with \n              largest distance to be the first in a sorted list.  This function can be\n              used with std::sort().\n    !*/\n\n    template <typename T>\n    bool order_by_distance_and_index (\n        const T& a,\n        const T& b\n    ) { return a.distance() < b.distance() || (a.distance() == b.distance() && order_by_index(a,b)); }\n    /*!\n        requires\n            - T is a type with an interface compatible with sample_pair.\n        ensures\n            - provides a total ordering of sample_pair objects that causes pairs with\n              smallest distance to be the first in a sorted list but also orders samples\n              with equal distances according to order_by_index().  This function can be\n              used with std::sort().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool operator == (\n        const sample_pair& a,\n        const sample_pair& b\n    );\n    /*!\n        ensures\n            - returns a.index1() == b.index1() && a.index2() == b.index2();\n              I.e. returns true if a and b both represent the same pair and false otherwise.  \n              Note that the distance field is not involved in this comparison.\n    !*/\n\n    inline bool operator != (\n        const sample_pair& a,\n        const sample_pair& b\n    );\n    /*!\n        ensures\n            - returns !(a == b)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const sample_pair& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    inline void deserialize (\n        sample_pair& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAMPLE_PaIR_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/graph_utils.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_UTILs_H_\n#define DLIB_GRAPH_UTILs_H_ \n\n#include \"graph_utils/graph_utils.h\"\n#include \"graph_utils/edge_list_graphs.h\"\n#include \"graph_utils/function_objects.h\"\n\n#endif // DLIB_GRAPH_UTILs_H_ \n\n\n"
  },
  {
    "path": "dlib/graph_utils_threaded.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GRAPH_UTILs_THREADED_H_\n#define DLIB_GRAPH_UTILs_THREADED_H_ \n\n#include \"graph_utils.h\"\n#include \"graph_utils/find_k_nearest_neighbors_lsh.h\"\n\n#endif // DLIB_GRAPH_UTILs_THREADED_H_ \n\n\n\n"
  },
  {
    "path": "dlib/gui_core/gui_core_kernel_1.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEL_1_CPp_\n#define DLIB_GUI_CORE_KERNEL_1_CPp_\n#include \"../platform.h\"\n\n#ifdef WIN32\n\n#include \"gui_core_kernel_1.h\"\n\n// tell visual studio to link to the libraries we need if we are\n// in fact using visual studio\n#ifdef _MSC_VER\n#pragma comment (lib, \"gdi32.lib\")\n#pragma comment (lib, \"comctl32.lib\")\n#pragma comment (lib, \"user32.lib\")\n#pragma comment (lib, \"imm32.lib\")\n#endif\n\n#include <cmath>\n#include <memory>\n#include <sstream>\n#include <vector>\n\n#include \"../threads.h\"\n#include \"../assert.h\"\n#include \"../queue.h\"\n#include \"../sync_extension.h\"\n#include \"../queue.h\"\n#include \"../logger.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gui_core_kernel_1_globals\n    {\n\n\n        struct user_event_type\n        {\n            HWND w;\n            void* p;\n            int i;\n        };\n\n        typedef sync_extension<binary_search_tree<HWND,base_window*>::kernel_1a>::kernel_1a window_table_type;\n        typedef sync_extension<queue<user_event_type,memory_manager<char>::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events;\n\n\n        enum USER_OFFSETS\n        {\n            CREATE_WINDOW,\n            DESTROY_WINDOW,\n            SET_ACTIVE_WINDOW,\n            QUIT_EVENT_HANDLER_THREAD,\n            USER_EVENTS_READY,\n            CALL_MOVE_WINDOW,\n            SHOW_WINDOW_SHOW,\n            SHOW_WINDOW_HIDE,\n            CALL_SET_WINDOW_TITLE\n        };\n\n    // ----------------------------------------------------------------------------------------\n\n        const std::shared_ptr<dlib::mutex>& global_mutex()\n        {\n            static std::shared_ptr<dlib::mutex> m(new dlib::mutex);\n            return m;\n        }\n\n        class event_handler_thread : public threaded_object\n        {\n        public:\n\n            enum et_state\n            {\n                uninitialized,\n                initialized,\n                failure_to_init \n            };\n            \n            et_state status;\n\n            queue_of_user_events user_events;\n            queue_of_user_events user_events_temp;\n            logger dlog;\n\n            HINSTANCE hInstance;\n            HWND helper_window;    \n            const TCHAR* window_class_name;\n\n            bool quit_windows_loop;\n            bool set_window_title_done;\n            std::wstring window_title;\n            bool move_window_done;\n            HWND move_window_hwnd;\n            int move_window_width;\n            int move_window_height;\n            int move_window_x;\n            int move_window_y;\n            bool request_new_window;\n            DWORD dwStyle;\n            HWND new_window;\n            bool in_ime_composition;\n            bool event_thread_started;\n            // the window_table.get_mutex() mutex locks the above 11 variables\n\n\n            // this variable holds a mapping from window handles to the base_window\n            // objects which represent them.  Note that this objects mutex is always locked\n            // when inside the event loop.\n            window_table_type window_table;\n            rsignaler window_close_signaler;\n            rsignaler et_signaler;\n\n            // note that this is the thread that will perform all the event\n            // processing.\n            thread_id_type event_thread_id;\n\n            std::shared_ptr<dlib::mutex> reference_to_global_mutex;\n\n            event_handler_thread(\n            ) :\n                dlog(\"dlib.gui_core\"),\n                hInstance(0),\n                helper_window(0),\n                window_class_name(TEXT (\"w3049u6qc2d94thw9m34f4we0gvwa3-tgkser0-b9gm 05\")),\n                quit_windows_loop(false),\n                set_window_title_done(true),\n                move_window_done(true),\n                move_window_hwnd(0),\n                move_window_width(0),\n                move_window_height(0),\n                move_window_x(0),\n                move_window_y(0),\n                request_new_window(false),\n                dwStyle(0),\n                new_window(0),\n                in_ime_composition(false),\n                event_thread_started(false),\n                window_close_signaler(window_table.get_mutex()),\n                et_signaler(window_table.get_mutex()),\n                reference_to_global_mutex(global_mutex())\n            {\n                status = uninitialized;\n            }\n\n            void start_event_thread (\n            )\n            /*!\n                we can't call this function from this objects constructor because \n                starting the event thread in windows involves sending messages to the\n                WndProc() and that requires this object to be fully constructed.\n            !*/\n            {\n\n                if (event_thread_started == false)\n                {\n                    auto_mutex M(window_table.get_mutex());\n                    if (event_thread_started == false)\n                    {\n                        event_thread_started = true;\n                        // start up the event handler thread\n                        start();\n\n                        // wait for the event thread to get up and running\n                        while (status == uninitialized)\n                            et_signaler.wait();\n\n                        if (status == failure_to_init)\n                            throw gui_error(\"Failed to start event thread\");\n                    }\n                }\n            }\n\n            ~event_handler_thread ()\n            {\n                using namespace gui_core_kernel_1_globals;\n                \n                if (is_alive())\n                {\n                    if (PostMessage(helper_window,WM_USER+QUIT_EVENT_HANDLER_THREAD,0,0)==0)\n                    {\n                        dlog << LWARN << \"Unable to schedule function for execution in event handling thread.\";\n                        // No point calling wait() here since the thread isn't going to\n                        // terminate gracefully in this case.  So we just let the program\n                        // end as it will and hope for the best.\n                    } \n                    else\n                    {\n                        // wait for the event handler thread to terminate.\n                        wait();\n                    }\n                }\n\n            }\n\n        private:\n\n            void thread (\n            )\n            {\n                event_thread_id = get_thread_id();\n\n                hInstance = GetModuleHandle(NULL);\n                if (hInstance == NULL)\n                {\n                    dlog << LFATAL << \"Error gathering needed resources\";\n\n                    // signal that an error has occurred\n                    window_table.get_mutex().lock();\n                    status = failure_to_init;\n                    et_signaler.broadcast();\n                    window_table.get_mutex().unlock();\n                    return;\n                }\n\n                // register the main window class\n                WNDCLASS     wndclass ;\n\n                wndclass.style         = CS_DBLCLKS;\n                wndclass.lpfnWndProc   = dlib::gui_core_kernel_1_globals::WndProc ;\n                wndclass.cbClsExtra    = 0 ;\n                wndclass.cbWndExtra    = 0 ;\n                wndclass.hInstance     = hInstance ;\n                wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;\n                wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;\n                wndclass.hbrBackground = 0;\n                wndclass.lpszMenuName  = NULL ;\n                wndclass.lpszClassName = window_class_name ;\n\n                if (!RegisterClass (&wndclass))  \n                {\n                    dlog << LFATAL << \"Error registering window class\";\n\n                    // signal that an error has occurred\n                    window_table.get_mutex().lock();\n                    status = failure_to_init;\n                    et_signaler.broadcast();\n                    window_table.get_mutex().unlock();\n                    return;\n                }\n\n\n                // make the helper window that is used to trigger events in the\n                // event handler loop from other threads\n                TCHAR nothing[] = TEXT(\"\");\n                helper_window = CreateWindow(window_class_name,nothing,WS_DISABLED,0,0,0,0,HWND_MESSAGE,NULL,hInstance,NULL);\n                if (helper_window == NULL)\n                {\n                    dlog << LFATAL << \"Error gathering needed resources\";\n\n                    // signal that an error has occurred\n                    window_table.get_mutex().lock();\n                    status = failure_to_init;\n                    et_signaler.broadcast();\n                    window_table.get_mutex().unlock();\n                    return;\n                }\n\n                // signal that the event thread is now up and running\n                window_table.get_mutex().lock();\n                status = initialized;\n                et_signaler.broadcast();\n                window_table.get_mutex().unlock();\n\n                // start the event handler loop.   \n                /*\n                    A note about this quit_windows_loop thing.  If the user is holding \n                    the mouse button down on the title bar of a window it will cause\n                    the PostQuitMessage() function to be ignored!!  This extra bool \n                    is a work around to prevent that from happening.\n                */\n                MSG msg;\n                while (GetMessage (&msg, NULL, 0, 0) && \n                       quit_windows_loop == false)\n                {\n                    TranslateMessage (&msg) ;\n                    DispatchMessage (&msg) ;\n                } \n            }\n        };\n\n        // Do all this just to make sure global_mutex() is initialized at program start\n        // and thus hopefully before any threads have the chance to startup and call\n        // global_data() concurrently.\n        struct call_global_mutex { call_global_mutex() { global_mutex(); } };\n        static call_global_mutex call_global_mutex_instance;\n\n        // Note that we need to use dlib::shared_ptr_thread_safe here rather than\n        // std::shared_ptr.  This is because the destructor of event_handler_thread\n        // triggers an event in the main event loop telling it to stop and that event loop\n        // holds a shared pointer to the event_handler_thread.  So what can happen is\n        // global_data()'s shared pointer gets destructed because the program is\n        // terminating, which causes the event_handler_thread destructor to run, which\n        // eventually causes the event loop to ask global_data() for a handle to the event\n        // thread.  This is bad for std::shared_ptr since (at least as of 2017) most\n        // implementations of std::shared_ptr decrement the reference count to 0 before\n        // invoking the event_handler_thread's destructor and then when the event thread\n        // calls global_data() it increments the counter again, then decrements it back to\n        // 0, triggering a double deletion, when the event handler routine finally\n        // finishes.  \n        // \n        // dlib::shared_ptr_thread_safe doesn't have this problem.  An alternative would be\n        // to somehow avoid this kind of self reference.  But it's not obvious how to do\n        // that given the limitations of the Win32 event WndProc() structure imposed by\n        // windows.  So in any case, we just use the old dlib::shared_ptr_thread_safe to\n        // avoid this problem.\n        const shared_ptr_thread_safe<event_handler_thread>& global_data()\n        {\n            auto_mutex M(*global_mutex());\n            static shared_ptr_thread_safe<event_handler_thread> p;\n            if (p.get() == 0)\n            {\n                p.reset(new event_handler_thread());\n                M.unlock();\n                p->start_event_thread();\n            }\n            return p;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        struct ebh_param\n        {\n            std::string text;\n            std::string title;\n        };\n\n        static void error_box_helper(void* param)\n        {\n            ebh_param& p = *static_cast<ebh_param*>(param);\n#ifdef UNICODE\n            MessageBox (NULL,  convert_mbstring_to_wstring(p.text).c_str(), \n                        convert_mbstring_to_wstring(p.title).c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL \n                        ); \n#else\n            MessageBox (NULL,  p.text.c_str(), \n                        p.title.c_str(), MB_OK|MB_ICONERROR|MB_SYSTEMMODAL \n                        ); \n#endif\n            delete &p;\n        }\n\n        static void error_box (\n            const char* title,\n            const char* text,\n            bool nonblocking = false\n        )\n        {\n            try\n            {\n                if (nonblocking)\n                {\n                    ebh_param* param = new ebh_param;\n                    param->text = text;\n                    param->title = title;\n                    dlib::create_new_thread(error_box_helper,param);\n                }\n                else\n                {\n#ifdef UNICODE\n                    MessageBox (NULL, convert_mbstring_to_wstring(text).c_str(), \n                                convert_mbstring_to_wstring(title).c_str(), \n                                MB_OK|MB_ICONERROR|MB_SYSTEMMODAL \n                                ); \n#else\n                    MessageBox (NULL,  text, \n                                title, MB_OK|MB_ICONERROR|MB_SYSTEMMODAL \n                                ); \n#endif\n                }\n            }\n            catch (...)\n            {\n                // we are totally screwed if this happens so just quit\n                exit(0);\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        static bool map_keys (\n            unsigned long keycode,\n            bool shift,\n            bool caps,\n            unsigned long& result,\n            bool& is_printable\n        )\n        /*!\n            requires\n                - if (shift was down for this key) then\n                    - shift == true\n                - if (caps lock was on for this key) then\n                    - caps == true\n                - keycode == the keycode from windows that we are to process\n                - keycode < keyboard_keys_size\n            ensures\n                - if (this key should be ignored) then\n                    - returns false\n                - else\n                    - returns true\n                    - #is_printable == true if result is a printable ascii character\n                    - #result == the keycode converted into the proper number to tbe \n                      returned by the event handler.\n        !*/\n        {\n            is_printable = true;\n\n            if (keycode <= '9' && keycode >= '0')\n            {\n                result = keycode;\n                if (shift)\n                {\n                    switch (result)\n                    {\n                    case '0': result = ')'; break;\n                    case '1': result = '!'; break;\n                    case '2': result = '@'; break;\n                    case '3': result = '#'; break;\n                    case '4': result = '$'; break;\n                    case '5': result = '%'; break;\n                    case '6': result = '^'; break;\n                    case '7': result = '&'; break;\n                    case '8': result = '*'; break;\n                    case '9': result = '('; break;\n                    }\n                }\n            }\n            else if (keycode <= 'Z' && keycode >= 'A')\n            {\n                result = keycode;\n\n                // make the result lower case if we need to.\n                if ((shift && caps) || (!caps && !shift))\n                    result = result - 'A' + 'a';               \n            }\n            else\n            {\n                switch (keycode)\n                {\n                case VK_BACK:   \n                    is_printable = false;\n                    result = base_window::KEY_BACKSPACE; \n                    break;\n\n                case VK_SHIFT:\n                    is_printable = false;\n                    result = base_window::KEY_SHIFT;\n                    break;\n\n                case VK_CONTROL:\n                    is_printable = false;\n                    result = base_window::KEY_CTRL;\n                    break;\n\n                case VK_MENU:\n                    is_printable = false;\n                    result = base_window::KEY_ALT;\n                    break;\n\n                case VK_PAUSE:\n                    is_printable = false;\n                    result = base_window::KEY_PAUSE;\n                    break;\n\n                case VK_CAPITAL:\n                    is_printable = false;\n                    result = base_window::KEY_CAPS_LOCK;\n                    break;\n\n                case VK_ESCAPE:\n                    is_printable = false;\n                    result = base_window::KEY_ESC;\n                    break;\n\n                case VK_PRIOR:\n                    is_printable = false;\n                    result = base_window::KEY_PAGE_UP;\n                    break;\n\n                case VK_NEXT:\n                    is_printable = false;\n                    result = base_window::KEY_PAGE_DOWN;\n                    break;\n\n                case VK_END:\n                    is_printable = false;\n                    result = base_window::KEY_END;\n                    break;\n\n                case VK_HOME:\n                    is_printable = false;\n                    result = base_window::KEY_HOME;\n                    break;\n\n                case VK_LEFT:\n                    is_printable = false;\n                    result = base_window::KEY_LEFT;\n                    break;\n\n                case VK_RIGHT:\n                    is_printable = false;\n                    result = base_window::KEY_RIGHT;\n                    break;\n\n                case VK_UP:\n                    is_printable = false;\n                    result = base_window::KEY_UP;\n                    break;\n\n                case VK_DOWN:\n                    is_printable = false;\n                    result = base_window::KEY_DOWN;\n                    break;\n\n                case VK_INSERT:\n                    is_printable = false;\n                    result = base_window::KEY_INSERT;\n                    break;\n\n                case VK_DELETE:\n                    is_printable = false;\n                    result = base_window::KEY_DELETE;\n                    break;\n\n                case 0x91:\n                    is_printable = false;\n                    result = base_window::KEY_SCROLL_LOCK;\n                    break;\n\n                case VK_F1:\n                    is_printable = false;\n                    result = base_window::KEY_F1;\n                    break;\n\n                case VK_F2:\n                    is_printable = false;\n                    result = base_window::KEY_F2;\n                    break;\n\n                case VK_F3:\n                    is_printable = false;\n                    result = base_window::KEY_F3;\n                    break;\n\n                case VK_F4:\n                    is_printable = false;\n                    result = base_window::KEY_F4;\n                    break;\n\n                case VK_F5:\n                    is_printable = false;\n                    result = base_window::KEY_F5;\n                    break;\n\n                case VK_F6:\n                    is_printable = false;\n                    result = base_window::KEY_F6;\n                    break;\n\n                case VK_F7:\n                    is_printable = false;\n                    result = base_window::KEY_F7;\n                    break;\n\n                case VK_F8:\n                    is_printable = false;\n                    result = base_window::KEY_F8;\n                    break;\n\n                case VK_F9:\n                    is_printable = false;\n                    result = base_window::KEY_F9;\n                    break;\n\n                case VK_F10:\n                    is_printable = false;\n                    result = base_window::KEY_F10;\n                    break;\n\n                case VK_F11:\n                    is_printable = false;\n                    result = base_window::KEY_F11;\n                    break;\n\n                case VK_F12:\n                    is_printable = false;\n                    result = base_window::KEY_F12;\n                    break;\n      \n\n                case VK_SPACE:  result = ' ';  break;                \n                case VK_TAB:    result = '\\t'; break;\n                case VK_RETURN: result = '\\n'; break;\n                case VK_NUMPAD0:  result = '0';  break;\n                case VK_NUMPAD1:  result = '1';  break;\n                case VK_NUMPAD2:  result = '2';  break;\n                case VK_NUMPAD3:  result = '3';  break;\n                case VK_NUMPAD4:  result = '4';  break;\n                case VK_NUMPAD5:  result = '5';  break;\n                case VK_NUMPAD6:  result = '6';  break;\n                case VK_NUMPAD7:  result = '7';  break;\n                case VK_NUMPAD8:  result = '8';  break;\n                case VK_NUMPAD9:  result = '9';  break;\n\n                case VK_MULTIPLY:   result = '*';  break;\n                case VK_ADD:        result = '+';  break;\n                case VK_SUBTRACT:   result = '-';  break;\n                case VK_DECIMAL:    result = '.';  break;\n                case VK_DIVIDE:     result = '/';  break;\n\n                case VK_OEM_1:\n                    if (shift)  result = ':';\n                    else        result = ';';\n                    break;\n\n                case VK_OEM_PLUS:\n                    if (shift)  result = '+';\n                    else        result = '=';\n                    break;\n\n                case VK_OEM_COMMA:\n                    if (shift)  result = '<';\n                    else        result = ',';\n                    break;\n\n                case VK_OEM_MINUS:\n                    if (shift)  result = '_';\n                    else        result = '-';\n                    break;\n\n                case VK_OEM_PERIOD:\n                    if (shift)  result = '>';\n                    else        result = '.';\n                    break;\n\n                case VK_OEM_2:\n                    if (shift)  result = '?';\n                    else        result = '/';\n                    break;\n\n                case VK_OEM_3:\n                    if (shift)  result = '~';\n                    else        result = '`';\n                    break;\n\n                case VK_OEM_4:\n                    if (shift)  result = '{';\n                    else        result = '[';\n                    break;\n\n                case VK_OEM_5:\n                    if (shift)  result = '|';\n                    else        result = '\\\\';\n                    break;\n\n                case VK_OEM_6:\n                    if (shift)  result = '}';\n                    else        result = ']';\n                    break;\n\n                case VK_OEM_7:\n                    if (shift)  result = '\"';\n                    else        result = '\\'';\n                    break;\n\n                default:\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        LRESULT CALLBACK WndProc (  \n            HWND hwnd, \n            UINT message, \n            WPARAM wParam, \n            LPARAM lParam\n        )\n        {        \n            using namespace gui_core_kernel_1_globals;\n            // Make the event processing thread have a priority slightly above normal.\n            // This makes the GUI smother if you do heavy processing in other threads.\n            HANDLE hand = OpenThread(THREAD_ALL_ACCESS,FALSE,GetCurrentThreadId());\n            SetThreadPriority(hand,THREAD_PRIORITY_ABOVE_NORMAL);\n            CloseHandle(hand);\n\n            auto globals = global_data();\n\n            window_table_type& window_table = globals->window_table;\n            HWND& helper_window = globals->helper_window;\n\n            auto_mutex M(window_table.get_mutex());\n\n            try\n            {\n                std::vector<unsigned char> bitmap_buffer;\n\n                bool is_double = false;\n                unsigned long btn = base_window::NONE;\n\n                switch (message)\n                {\n                    case WM_USER+QUIT_EVENT_HANDLER_THREAD:\n                        if (hwnd == helper_window)\n                        {                            \n                            globals->quit_windows_loop = true;\n                            PostQuitMessage(0); \n                        }\n                        return 0;\n\n                    case WM_USER+DESTROY_WINDOW:\n                        if (hwnd == helper_window)\n                        {                            \n                            DestroyWindow((HWND)wParam);\n                        }\n                        return 0;\n\n                    case WM_USER+CALL_MOVE_WINDOW:\n                        if (hwnd == helper_window)\n                        {\n                            MoveWindow(\n                                globals->move_window_hwnd,\n                                globals->move_window_x,\n                                globals->move_window_y,\n                                globals->move_window_width,\n                                globals->move_window_height,\n                                TRUE);\n                            globals->move_window_done = true;\n                            globals->et_signaler.broadcast();\n                        }\n                        return 0;\n\n                    case WM_USER+USER_EVENTS_READY:\n                        if (hwnd == helper_window)\n                        {\n                            // this is the signal to look in the user_events queue \n                            globals->user_events.lock();\n                            globals->user_events.swap(globals->user_events_temp);\n                            globals->user_events.unlock();\n                            globals->user_events_temp.reset();\n                            // now dispatch all these user events\n                            while (globals->user_events_temp.move_next())\n                            {\n                                base_window** win_ = window_table[globals->user_events_temp.element().w];\n                                base_window* win;\n                                // if this window exists in the window table then dispatch\n                                // its event.\n                                if (win_)\n                                {\n                                    win = *win_;\n                                    win->on_user_event(\n                                        globals->user_events_temp.element().p,\n                                        globals->user_events_temp.element().i\n                                    );\n                                }\n                            }\n                            globals->user_events_temp.clear();\n                        }\n                        return 0;\n\n                    case WM_USER+SET_ACTIVE_WINDOW:\n                        if (hwnd == helper_window)\n                        {                            \n                            SetActiveWindow((HWND)wParam);\n                        }\n                        return 0;\n\n                    case WM_USER+SHOW_WINDOW_SHOW:\n                        if (hwnd == helper_window)\n                        {                            \n                            ShowWindow((HWND)wParam,SW_SHOW);\n                            BringWindowToTop((HWND)wParam);\n                        }\n                        return 0;\n\n                    case WM_USER+SHOW_WINDOW_HIDE:\n                        if (hwnd == helper_window)\n                        {                            \n                            ShowWindow((HWND)wParam,SW_HIDE);\n                        }\n                        return 0;\n\n                    case WM_USER+CALL_SET_WINDOW_TITLE:\n                        if (hwnd == helper_window)\n                        {                            \n                            SetWindowTextW((HWND)wParam,globals->window_title.c_str());\n                            globals->set_window_title_done = true;\n                            globals->et_signaler.broadcast();\n                        }\n                        return 0;\n\n\n                    case WM_USER+CREATE_WINDOW:\n                        if (hwnd == helper_window)\n                        {                 \n\n                            // if this is stupposed to be a popup window then do the popup window thing\n                            if (globals->dwStyle == WS_CHILD)\n                            {\n                                TCHAR nothing[] = TEXT(\"\");\n                                globals->new_window = CreateWindowEx (WS_EX_TOOLWINDOW,globals->window_class_name, nothing,\n                                    globals->dwStyle,\n                                    CW_USEDEFAULT, CW_USEDEFAULT,\n                                    CW_USEDEFAULT, CW_USEDEFAULT,\n                                    helper_window, NULL, globals->hInstance, NULL);\n                                SetParent(globals->new_window,NULL);\n                            }\n                            else\n                            {\n                                TCHAR nothing[] = TEXT(\"\");\n                                globals->new_window = CreateWindow (globals->window_class_name, nothing,\n                                    globals->dwStyle,\n                                    CW_USEDEFAULT, CW_USEDEFAULT,\n                                    CW_USEDEFAULT, CW_USEDEFAULT,\n                                    NULL, NULL, globals->hInstance, NULL);\n                            }\n                            // use the helper_window to indicate that CreateWindow failed\n                            if (globals->new_window == NULL)\n                                globals->new_window = helper_window;\n                            globals->et_signaler.broadcast();\n                        }\n                        return 0;\n\n                    case WM_SYSKEYDOWN:\n                    case WM_KEYDOWN:\n                        {\n                            if (globals->in_ime_composition) break;\n\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n                            unsigned long state = 0;\n\n                            bool shift = ((GetKeyState(VK_SHIFT)&0x8000)!=0);\n                            bool ctrl = ((GetKeyState(VK_CONTROL)&0x8000)!=0);\n                            bool caps = ((GetKeyState(VK_CAPITAL)&0x0001)!=0);\n                            if(shift)\n                                state = base_window::KBD_MOD_SHIFT;\n                            if(ctrl)\n                                state |= base_window::KBD_MOD_CONTROL;\n                            if(caps)\n                                state |= base_window::KBD_MOD_CAPS_LOCK;\n                            if((GetKeyState(VK_MENU)&0x8000)!=0)\n                                state |= base_window::KBD_MOD_ALT;\n                            if((GetKeyState(VK_NUMLOCK)&0x0001)!=0)\n                                state |= base_window::KBD_MOD_NUM_LOCK;\n                            if((GetKeyState(VK_SCROLL)&0x0001)!=0)\n                                state |= base_window::KBD_MOD_SCROLL_LOCK;\n\n\n                            bool is_printable;\n                            unsigned long result;\n\n                            if (map_keys(wParam,shift,caps,result,is_printable))\n                            {\n                                // signal the keyboard event\n                                win->on_keydown(result,is_printable,state);\n                            }\n                           \n                        }\n                        break;\n\n                        // treat the user releasing the mouse button on the non client area (e.g. the title bar)\n                        // like focus being lost since that is what X11 does\n                    case WM_NCLBUTTONUP:\n                    case WM_NCMBUTTONUP:\n                    case WM_NCRBUTTONUP:\n                    case WM_SETFOCUS:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n                            // signal that the window is gaining focus \n                            win->on_focus_gained();\n                        }\n                        break;\n\n                        // treat the user clicking on the non client area (e.g. the title bar)\n                        // like focus being lost since that is what X11 does\n                    case WM_NCLBUTTONDBLCLK:\n                    case WM_NCMBUTTONDBLCLK:\n                    case WM_NCRBUTTONDBLCLK:\n                    case WM_NCLBUTTONDOWN:\n                    case WM_NCMBUTTONDOWN:\n                    case WM_NCRBUTTONDOWN:\n                    case WM_KILLFOCUS:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n                            // signal that the window is gaining focus \n                            win->on_focus_lost();\n                        }\n                        break;\n\n                    case WM_SIZE:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n\n                            // signal that the window has been resized\n                            win->on_window_resized();\n                           \n                        }\n                        return 0;\n\n                    case WM_MOVE:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n\n                            // signal that the window has moved \n                            win->on_window_moved();\n                           \n                        }\n                        return 0;\n\n                    case WM_MOUSELEAVE:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n\n                            // signal that the mouse has left the window\n                            if (win->mouse_in)\n                            {\n                                win->on_mouse_leave();\n                                win->mouse_in = false;\n                            }\n                           \n                        }\n                        return 0;\n\n                    case WM_MOUSEWHEEL:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n                            unsigned long state = 0;\n                            if (wParam & MK_CONTROL)\n                                state |= base_window::CONTROL;\n                            if (wParam & MK_LBUTTON)\n                                state |= base_window::LEFT;\n                            if (wParam & MK_MBUTTON)\n                                state |= base_window::MIDDLE;\n                            if (wParam & MK_RBUTTON)\n                                state |= base_window::RIGHT;\n                            if (wParam & MK_SHIFT)\n                                state |= base_window::SHIFT;\n\n                            // signal the mouse wheel event\n                            if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)\n                            {\n                                win->on_wheel_up(state);                                \n                            }\n                            else\n                            {\n                                win->on_wheel_down(state);\n                            }\n                           \n                        }\n                        return 0;\n\n                    case WM_LBUTTONUP:\n                        btn = base_window::LEFT;\n                    case WM_MBUTTONUP:\n                        if (btn == base_window::NONE)\n                            btn = base_window::MIDDLE;\n                    case WM_RBUTTONUP:\n                        if (btn == base_window::NONE)\n                            btn = base_window::RIGHT;\n                        {        \n                            // release the mouse capture if the user isn't holding any\n                            // other mouse buttons\n                            if (!((wParam & MK_LBUTTON) | (wParam & MK_MBUTTON) | (wParam & MK_RBUTTON)))\n                                ReleaseCapture();\n\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n\n                            unsigned long state = 0;\n                            if (wParam & MK_CONTROL)\n                                state |= base_window::CONTROL;\n                            if (wParam & MK_LBUTTON)\n                                state |= base_window::LEFT;\n                            if (wParam & MK_MBUTTON)\n                                state |= base_window::MIDDLE;\n                            if (wParam & MK_RBUTTON)\n                                state |= base_window::RIGHT;\n                            if (wParam & MK_SHIFT)\n                                state |= base_window::SHIFT;\n                            \n                            // remove the clicked button from the state\n                            state &= (~btn);\n\n                            // signal the mouse click\n                            win->on_mouse_up(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));\n                           \n                        }\n                        return 0;\n\n\n\n                    case WM_LBUTTONDBLCLK:\n                        if (btn == base_window::NONE)\n                            btn = base_window::LEFT;\n                    case WM_MBUTTONDBLCLK:\n                        if (btn == base_window::NONE)\n                            btn = base_window::MIDDLE;\n                    case WM_RBUTTONDBLCLK:\n                        if (btn == base_window::NONE)\n                            btn = base_window::RIGHT;\n                        is_double = true;\n                    case WM_LBUTTONDOWN:\n                        if (btn == base_window::NONE)\n                            btn = base_window::LEFT;\n                    case WM_MBUTTONDOWN:\n                        if (btn == base_window::NONE)\n                            btn = base_window::MIDDLE;\n                    case WM_RBUTTONDOWN:\n                        if (btn == base_window::NONE)\n                            btn = base_window::RIGHT;\n                        {\n                            SetCapture(hwnd);\n\n\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n                            \n                            unsigned long state = 0;\n                            if (wParam & MK_CONTROL)\n                                state |= base_window::CONTROL;\n                            if (wParam & MK_LBUTTON)\n                                state |= base_window::LEFT;\n                            if (wParam & MK_MBUTTON)\n                                state |= base_window::MIDDLE;\n                            if (wParam & MK_RBUTTON)\n                                state |= base_window::RIGHT;\n                            if (wParam & MK_SHIFT)\n                                state |= base_window::SHIFT;\n\n                            // remove the clicked button from the state\n                            state &= (~btn);\n\n                            // signal the mouse click\n                            win->on_mouse_down(btn,state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),is_double);\n                           \n                        }\n                        return 0;\n\n                    case WM_MOUSEMOVE:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n                            \n                            unsigned long state = 0;\n                            bool mouse_button_down = false;\n                            if (wParam & MK_CONTROL)\n                                state |= base_window::CONTROL;\n                            if (wParam & MK_LBUTTON)\n                            {\n                                state |= base_window::LEFT;\n                                mouse_button_down = true;\n                            }\n                            if (wParam & MK_MBUTTON)\n                            {\n                                mouse_button_down = true;\n                                state |= base_window::MIDDLE;\n                            }\n                            if (wParam & MK_RBUTTON)\n                            {\n                                state |= base_window::RIGHT;\n                                mouse_button_down = true;\n                            }\n                            if (wParam & MK_SHIFT)\n                                state |= base_window::SHIFT;\n\n                            // signal the mouse movement if this mouse event isn't identical to the\n                            // last one we got\n                            if ( GET_X_LPARAM(lParam) != win->prevx || \n                                 GET_Y_LPARAM(lParam) != win->prevy || \n                                 state != win->prev_state)\n                            {\n                                win->on_mouse_move(state,GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));\n                            }\n                           \n                            // save the event data into the prev* member variables\n                            win->prevx = GET_X_LPARAM(lParam);\n                            win->prevy = GET_Y_LPARAM(lParam);\n                            win->prev_state = state;\n\n                            // The following block of code checks if the mouse is moving\n                            // into or out of the window.\n                            if (mouse_button_down == false)\n                            {\n                                // if there isn't any mouse button down then the fact that\n                                // we are getting a mouse move message means it is in the\n                                // window\n                                if (win->mouse_in == false)\n                                {\n                                    win->on_mouse_enter();\n                                    win->mouse_in = true;\n\n                                    // set the tracker for the mouse\n                                    TRACKMOUSEEVENT tm;\n                                    tm.hwndTrack = hwnd;\n                                    tm.cbSize = sizeof(tm);\n                                    tm.dwFlags = TME_LEAVE;\n                                    _TrackMouseEvent(&tm);\n                                }\n                            }\n                            else if (win->mouse_in)\n                            {\n                                // check if the mouse is currently outside the window\n                                const long mouse_x = GET_X_LPARAM(lParam);\n                                const long mouse_y = GET_Y_LPARAM(lParam);\n                                if (mouse_x < 0 || mouse_y < 0)\n                                {\n                                    // the mouse is not in the window\n                                    win->mouse_in = false;\n                                    win->on_mouse_leave();\n                                }\n                                else\n                                {\n                                    unsigned long width, height;\n                                    win->get_size(width,height);  \n                                    if (mouse_x >= static_cast<long>(width) || \n                                        mouse_y >= static_cast<long>(height))\n                                    {\n                                        // the mouse is not in the window\n                                        win->mouse_in = false;\n                                        win->on_mouse_leave();\n                                    }\n                                }\n                            }\n                            else if (win->mouse_in == false)\n                            {\n                                // at this point we know that the mouse is moving around\n                                // with some of its buttons down.  So it might be outside the window.\n                                // get the window size and see if the mouse is outside\n                                // it.\n                                const long mouse_x = GET_X_LPARAM(lParam);\n                                const long mouse_y = GET_Y_LPARAM(lParam);\n                                unsigned long width, height;\n                                win->get_size(width,height);  \n                                if (mouse_x < static_cast<long>(width) && \n                                    mouse_y < static_cast<long>(height) &&\n                                    mouse_x >= 0 &&\n                                    mouse_y >= 0)\n                                {\n                                    // The mouse has gone inside the window\n                                    win->mouse_in = true;\n                                    win->on_mouse_enter();\n\n                                    // set the tracker for the mouse\n                                    TRACKMOUSEEVENT tm;\n                                    tm.hwndTrack = hwnd;\n                                    tm.cbSize = sizeof(tm);\n                                    tm.dwFlags = TME_LEAVE;\n                                    _TrackMouseEvent(&tm);\n                                }\n                               \n                            }\n\n\n                        }\n                        return 0;\n\n                    case WM_PAINT :\n                        {     \n\n                            PAINTSTRUCT ps;\n                            HDC   hdc = NULL;\n\n                            hdc = BeginPaint (hwnd, &ps) ;\n\n                            try\n                            {\n                                base_window** win_ = window_table[hwnd];\n                                base_window* win;\n                                if (win_)\n                                    win = *win_;\n                                else\n                                    break;\n\n\n\n\n                                LONG x = ps.rcPaint.left;\n                                LONG y = ps.rcPaint.top;\n                                LONG width = ps.rcPaint.right - x;\n                                LONG height = ps.rcPaint.bottom - y;\n                        \n                                if (width != 0 && height != 0)\n                                {\n\n                                    BITMAPINFO bmap_info;\n                                    bmap_info.bmiColors[0].rgbBlue = 0;\n                                    bmap_info.bmiColors[0].rgbGreen = 0;\n                                    bmap_info.bmiColors[0].rgbRed = 0;\n                                    bmap_info.bmiColors[0].rgbReserved = 0;\n                                    bmap_info.bmiHeader.biSize = sizeof(bmap_info.bmiHeader);\n                                    bmap_info.bmiHeader.biWidth = width;\n                                    bmap_info.bmiHeader.biHeight = -1*height;\n                                    bmap_info.bmiHeader.biPlanes = 1;\n                                    bmap_info.bmiHeader.biBitCount = 24;\n                                    bmap_info.bmiHeader.biCompression = BI_RGB;\n                                    bmap_info.bmiHeader.biSizeImage = 0;\n                                    bmap_info.bmiHeader.biXPelsPerMeter = 0;\n                                    bmap_info.bmiHeader.biYPelsPerMeter = 0;\n                                    bmap_info.bmiHeader.biClrUsed = 0;\n                                    bmap_info.bmiHeader.biClrImportant = 0;\n\n\n\n                                    unsigned char* bitmap ;\n                                    unsigned long size;\n                                    unsigned long padding = 0;\n                                    if ((width*3)%sizeof(LONG) != 0)\n                                    {\n                                        padding = sizeof(LONG) - (width*3)%sizeof(LONG);\n                                        size = (width*3+padding)*height;\n                                    }\n                                    else\n                                    {\n                                        size = width*height*3;\n                                    }\n\n                                    if (bitmap_buffer.size() < size)\n                                        bitmap_buffer.resize(size);\n                                    bitmap = &bitmap_buffer[0];                         \n\n                                    canvas bits(bitmap,padding,x,y,x+width-1,y+height-1);\n\n\n\n                                    win->paint(bits);\n\n\n                                    \n                                    SetDIBitsToDevice (\n                                        hdc,\n                                        ps.rcPaint.left,\n                                        ps.rcPaint.top,\n                                        width,\n                                        height,\n                                        0,\n                                        0,\n                                        0,\n                                        height,\n                                        bitmap,\n                                        &bmap_info,\n                                        DIB_RGB_COLORS\n                                        );\n                                }\n\n                                EndPaint (hwnd, &ps) ;    \n\n                            }\n                            catch (...)\n                            {\n                                // make sure EndPaint is called even if an exception\n                                // is thrown.\n                                if (hdc != NULL)\n                                    EndPaint (hwnd, &ps);    \n                                throw;\n                            }\n                        }   \n                        return 0 ;\n\n                    case  WM_ERASEBKGND:\n                        return 1;\n\n\n\n\n                    case WM_CLOSE:\n                        {\n                            base_window** win_ = window_table[hwnd];\n                            base_window* win;\n                            if (win_)\n                                win = *win_;\n                            else\n                                break;\n                            \n  \n                            // signal that the window is being closed                                \n                            if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW)\n                            {\n                                DLIB_ASSERT(win->has_been_destroyed == false,\n                                    \"\\tYou called close_window() inside the on_window_close() event but\" \n                                    << \"\\n\\tthen returned DO_NOT_CLOSE_WINDOW.  You can do one or the other but not both.\"\n                                    << \"\\n\\tthis:     \" << win \n                                    );\n                                // this happens if the on_window_close() callback\n                                // tells us to ignore the close event.  \n                                return 0;\n                            }\n                            else\n                            {\n                                if (window_table[hwnd])\n                                {\n                                    window_table.destroy(hwnd);\n                                    win->has_been_destroyed = true;\n                                    win->hwnd = 0;\n                                    globals->window_close_signaler.broadcast();\n                                }\n                                else\n                                {\n                                    // in this case the window must have self destructed by\n                                    // calling delete this;\n                                    return 0;\n                                }\n                            }\n                          \n                        }\n                        return DefWindowProc (hwnd, message, wParam, lParam);\n\n                    case WM_IME_STARTCOMPOSITION:\n                        globals->in_ime_composition = true;\n                        break;\n\n                    case WM_IME_COMPOSITION:\n                        {\n                        globals->in_ime_composition = false;\n                        base_window** win_ = window_table[hwnd];\n                        base_window* win;\n                        if (win_)\n                            win = *win_;\n                        else\n                            break;\n                        HIMC hImc = ImmGetContext(hwnd);\n                        if (lParam & GCS_RESULTSTR){\n                            WCHAR wc;\n                            LONG bufbyte = ImmGetCompositionStringW(hImc, GCS_RESULTSTR, &wc, 0);\n                            if (bufbyte != IMM_ERROR_NODATA && bufbyte != IMM_ERROR_GENERAL){\n                                bufbyte += sizeof(WCHAR);\n\n\n                                WCHAR *buf = new WCHAR[bufbyte / sizeof(WCHAR)];\n                                ImmGetCompositionStringW(hImc, GCS_RESULTSTR, buf, bufbyte);\n                                buf[bufbyte / sizeof(WCHAR) - 1] = L'\\0';\n\n                                // signal the putstring event\n                                win->on_string_put(std::wstring(buf));\n                                delete [] buf;\n                            }\n                        }\n                        ImmReleaseContext(hwnd, hImc);\n                        }\n                        break;\n\n                    default:\n                        break;\n\n                } // switch (message)\n\n            \n            }\n            catch (std::exception& e)\n            {\n                error_box(\"Exception thrown in event handler\",e.what());\n                globals->quit_windows_loop = true; \n            }\n            catch (...)\n            {\n                error_box(\"Exception thrown in event handler\",\"Unknown Exception type.\");\n                globals->quit_windows_loop = true; \n            }\n\n            return DefWindowProc (hwnd, message, wParam, lParam) ;\n\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void show_window (\n            HWND hwnd\n        )\n        {\n            using namespace gui_core_kernel_1_globals;\n            PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_SHOW,(WPARAM)hwnd,0);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void hide_window (\n            HWND hwnd\n        )\n        {\n            using namespace gui_core_kernel_1_globals;\n            PostMessage(global_data()->helper_window,WM_USER+SHOW_WINDOW_HIDE,(WPARAM)hwnd,0);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void give_window_focus (\n            HWND hwnd\n        )\n        /*!\n            ensures\n                - calls SetActiveWindow(hwnd) from the event handling thread.\n        !*/\n        {\n            using namespace gui_core_kernel_1_globals;\n            PostMessage(global_data()->helper_window,WM_USER+SET_ACTIVE_WINDOW,(WPARAM)hwnd,0);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void destroy_window (\n            HWND hwnd\n        )\n        /*!\n            ensures\n                - calls DestroyWindow(hwnd) from the event handling thread.  \n        !*/\n        {\n            using namespace gui_core_kernel_1_globals;\n            PostMessage(global_data()->helper_window,WM_USER+DESTROY_WINDOW,(WPARAM)hwnd,0);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        HWND make_window (\n            DWORD dwStyle_\n        )\n        /*!\n            ensures\n                - creates a window by calling CreateWindow and passes on the \n                  dwStyle argument.  \n                - returns the HWND that is returned by CreateWindow\n                - ensures that CreateWindow is called from the event handler thread\n                - if (it was unable to create a window) then\n                    - returns NULL or helper_window\n        !*/\n        {   \n            using namespace gui_core_kernel_1_globals;\n            auto globals = global_data();\n            // if we are running in the event handling thread then just call\n            // CreateWindow directly\n            if (get_thread_id() == globals->event_thread_id)\n            {\n                // if this is stupposed to be a popup window then do the popup window thing\n                if (dwStyle_ == WS_CHILD)\n                {\n                    TCHAR nothing[] = TEXT(\"\");\n                    HWND tmp = CreateWindowEx (WS_EX_TOOLWINDOW|WS_EX_TOPMOST, globals->window_class_name, nothing,\n                            dwStyle_,\n                            CW_USEDEFAULT, CW_USEDEFAULT,\n                            CW_USEDEFAULT, CW_USEDEFAULT,\n                            globals->helper_window, NULL, globals->hInstance, NULL);\n                    SetParent(tmp,NULL);\n                    return tmp;\n                }\n                else\n                {\n                    TCHAR nothing[] = TEXT(\"\");\n                    return CreateWindow (globals->window_class_name, nothing,\n                            dwStyle_,\n                            CW_USEDEFAULT, CW_USEDEFAULT,\n                            CW_USEDEFAULT, CW_USEDEFAULT,\n                            NULL, NULL, globals->hInstance, NULL);\n                }\n            }\n            else\n            {\n                auto_mutex M(globals->window_table.get_mutex());\n                // wait for our chance to make a new window request\n                while (globals->request_new_window)\n                    globals->et_signaler.wait();\n\n\n                globals->dwStyle = dwStyle_;\n                if (PostMessage(globals->helper_window,WM_USER+CREATE_WINDOW,0,0)==0)\n                {\n                    throw gui_error(\"Unable to schedule function for execution in event handling thread.\");\n                } \n\n                // wait for our request to be serviced\n                while (globals->new_window == NULL)\n                    globals->et_signaler.wait();\n\n                HWND temp = globals->new_window;\n                globals->new_window = NULL;\n                globals->request_new_window = false;\n                globals->et_signaler.broadcast();\n\n                // if make_window() returns the helper_window then it means it failed\n                // to make a new window\n                if (temp == globals->helper_window)\n                    temp = NULL;\n\n                return temp;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n\n    } // end namespace gui_core_kernel_1_globals\n\n// ----------------------------------------------------------------------------------------\n\n    void canvas::\n    fill (\n        unsigned char red_,\n        unsigned char green_,\n        unsigned char blue_\n    ) const\n    {\n        const unsigned long red = red_;\n        const unsigned long green = green_;\n        const unsigned long blue = blue_;\n\n        const LONG block1 = (blue<<24) | (red<<16) | (green<<8) | blue;\n        const LONG block2 = (green<<24) | (blue<<16) | (red<<8) | green;\n        const LONG block3 = (red<<24) | (green<<16) | (blue<<8) | red;\n\n        // remember that row_width is a multiple of 4 because windows\n        // requires that all bitmaps have row widths that are multiples of 4.\n        unsigned long size = row_width/4;\n        for (unsigned long i = 0; i < height_; ++i)\n        {\n            unsigned long padding = size%3;                \n            LONG* start = reinterpret_cast<LONG*>(bits+row_width*i);\n            LONG* end = reinterpret_cast<LONG*>(start) + size - padding;\n            while (start != end)\n            {\n                *start = block1;\n                ++start;\n                *start = block2;\n                ++start;\n                *start = block3;\n                ++start;\n            }\n            if (padding)\n            {\n                *start = block1;\n                ++start;\n                --padding;\n            }\n            if (padding)\n            {\n                *start = block2;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    trigger_user_event (\n        void* p,\n        int i\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n\n        user_event_type e;\n        e.w = hwnd;\n        e.p = p;\n        e.i = i;\n        {\n            auto_mutex M(globals->user_events.get_mutex());\n            globals->user_events.enqueue(e);\n        }\n        \n        if (PostMessage(globals->helper_window,WM_USER+USER_EVENTS_READY,0,0)==0)\n        {\n            throw gui_error(\"Unable to schedule function for execution in event handling thread.\");\n        } \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base_window::\n    base_window (\n        bool resizable,\n        bool undecorated \n    ) :\n        globals(gui_core_kernel_1_globals::global_data()),\n        has_been_destroyed(false),\n        prevx(-1),\n        prevy(-1),\n        prev_state(0),\n        wm(globals->window_table.get_mutex())\n    {\n        using namespace gui_core_kernel_1_globals;\n        DLIB_ASSERT(!(undecorated == true && resizable == true),\n            \"\\tbase_window::base_window()\"\n            << \"\\n\\tThere is no such thing as an undecorated window that is resizable by the user.\"\n            << \"\\n\\tthis:     \" << this\n            );\n\n        if (resizable)   \n            style = WS_OVERLAPPEDWINDOW;                \n        else if (undecorated)\n            style = WS_CHILD;\n        else\n            style = WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX;\n\n        hwnd = gui_core_kernel_1_globals::make_window(style);                \n\n        if (hwnd == NULL)\n            throw gui_error(\"unable to create base_window\");\n\n        auto_mutex M(wm);\n\n        mouse_in = false;\n\n        HWND temp = hwnd;\n        base_window* ttemp = this;\n        globals->window_table.add(temp,ttemp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base_window::\n    ~base_window (\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        close_window();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    close_window (\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == false)\n        {\n            // do this just to make sure no one tries to call this window's\n            // calbacks.\n            globals->window_table.destroy(hwnd);\n            gui_core_kernel_1_globals::destroy_window(hwnd);\n            hwnd = 0;\n            has_been_destroyed = true;\n            globals->window_close_signaler.broadcast();\n        }  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    wait_until_closed (\n    ) const\n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        while (has_been_destroyed == false)\n            globals->window_close_signaler.wait();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool base_window::\n    is_closed (\n    ) const\n    {\n        auto_mutex M(wm);\n        return has_been_destroyed;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_title (\n        const std::string &title\n    )\n    {\n        set_title(convert_mbstring_to_wstring(title));\n    }\n\n    void base_window::\n    set_title (\n        const ustring &title\n    )\n    {\n        set_title(convert_utf32_to_wstring(title));\n    }\n\n    void base_window::\n    set_title (\n        const std::wstring& title\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        \n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n\n        // call the SetWindowText function with our arguments but make sure it is from \n        // the event thread.  We have to do this because the SetWindowText() apparently blocks\n        // until something happens in the event thread so we have to \n        // do this to avoid possible deadlocks.\n        if (get_thread_id() == globals->event_thread_id)\n        {\n            SetWindowTextW(hwnd,title.c_str());\n        }\n        else\n        {\n            globals->window_title = title;\n            globals->set_window_title_done = false;\n\n            if (PostMessage(globals->helper_window,WM_USER+CALL_SET_WINDOW_TITLE,(WPARAM)hwnd,0)==0)\n            {\n                throw gui_error(\"Unable to schedule SetWindowText function for execution in event handling thread.\");\n            } \n\n            // wait for any SetWindowText() calls to finish\n            while (globals->set_window_title_done == false)\n                globals->et_signaler.wait();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    show (\n    )    \n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        show_window(hwnd);\n        if (style != WS_CHILD)\n            give_window_focus(hwnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    hide(\n    )    \n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        hide_window(hwnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_size (\n        int width_,\n        int height_\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        if (get_thread_id() == globals->event_thread_id)\n        {\n            RECT info;\n            GetWindowRect(hwnd,&info);\n\n            int x = info.left;\n            int y = info.top;\n            int width;\n            int height;\n\n            RECT rect;\n            rect.top = 0;\n            rect.left = 0;\n            rect.bottom = height_;\n            rect.right = width_;\n            AdjustWindowRectEx(&rect,style,FALSE,0);\n\n            width = std::abs(rect.right - rect.left);\n            height = std::abs(rect.bottom - rect.top);\n\n            MoveWindow(\n                hwnd,\n                x,\n                y,\n                width,\n                height,\n                TRUE);\n        }\n        else\n        {\n            RECT info;\n            GetWindowRect(hwnd,&info);\n\n            int x = info.left;\n            int y = info.top;\n            int width;\n            int height;\n\n            RECT rect;\n            rect.top = 0;\n            rect.left = 0;\n            rect.bottom = height_;\n            rect.right = width_;\n            AdjustWindowRectEx(&rect,style,FALSE,0);\n\n            width = std::abs(rect.right - rect.left);\n            height = std::abs(rect.bottom - rect.top);\n\n            // call the MoveWindow function with our arguments.  We \n            // have to do this because the MoveWindow() apparently blocks\n            // until something happens in the event thread so we have to \n            // do this to avoid possible deadlocks.\n            globals->move_window_hwnd = hwnd;\n            globals->move_window_x = x;\n            globals->move_window_y = y;\n            globals->move_window_width = width;\n            globals->move_window_height = height;\n            globals->move_window_done = false;\n\n            if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0)\n            {\n                throw gui_error(\"Unable to schedule MoveWindow function for execution in event handling thread.\");\n            } \n\n            // wait for any MoveWindow calls to finish\n            while (globals->move_window_done == false)\n                globals->et_signaler.wait();\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_pos (\n        long x_,\n        long y_\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        if (get_thread_id() == globals->event_thread_id)\n        {\n            RECT info;\n            GetWindowRect(hwnd,&info);\n            int width = info.right - info.left;\n            int height = info.bottom - info.top;\n\n            MoveWindow(\n                hwnd,\n                x_,\n                y_,\n                width,\n                height,\n                TRUE);\n\n        }\n        else\n        {\n            RECT info;\n            GetWindowRect(hwnd,&info);\n            int width = info.right - info.left;\n            int height = info.bottom - info.top;\n\n\n\n            // call the MoveWindow function with our arguments.  We \n            // have to do this because the MoveWindow() apparently blocks\n            // until something happens in the event thread so we have to \n            // do this to avoid possible deadlocks.\n            globals->move_window_hwnd = hwnd;\n            globals->move_window_x = x_;\n            globals->move_window_y = y_;\n            globals->move_window_width = width;\n            globals->move_window_height = height;\n            globals->move_window_done = false;\n\n            if (PostMessage(globals->helper_window,WM_USER+CALL_MOVE_WINDOW,0,0)==0)\n            {\n                throw gui_error(\"Unable to schedule MoveWindow function for execution in event handling thread.\");\n            } \n\n            // wait for any MoveWindow calls to finish\n            while (globals->move_window_done == false)\n                globals->et_signaler.wait();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_pos (\n        long& x_,\n        long& y_\n    )\n    {\n        auto_mutex M(wm);\n        x_ = 0;\n        y_ = 0;\n        if (has_been_destroyed == true)\n            return;\n\n        POINT p;\n        p.x = 0;\n        p.y = 0;\n        ClientToScreen(hwnd,&p);\n\n        x_ = p.x;\n        y_ = p.y;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_display_size (\n        unsigned long& width,\n        unsigned long& height\n    ) const\n    {\n        auto_mutex M(wm);\n        width = 0;\n        height = 0;\n        if (has_been_destroyed == true)\n            return;\n\n\n        RECT rc;\n        GetWindowRect(hwnd, &rc);\n\n        HMONITOR hMonitor;\n        MONITORINFO mi;\n        //\n        // get the nearest monitor to the passed rect.\n        //\n        hMonitor = MonitorFromRect(&rc, MONITOR_DEFAULTTONEAREST);\n\n        //\n        // get the work area or entire monitor rect.\n        //\n        mi.cbSize = sizeof(mi);\n        GetMonitorInfo(hMonitor, &mi);\n\n        rc = mi.rcMonitor;\n\n        width = static_cast<unsigned long>(rc.right - rc.left);\n        height = static_cast<unsigned long>(rc.bottom - rc.top);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_size (\n        unsigned long& width,\n        unsigned long& height\n    ) const\n    {\n        auto_mutex M(wm);\n        width = 0;\n        height = 0;\n        if (has_been_destroyed == true)\n            return;\n\n\n        RECT r;\n        GetClientRect(hwnd,&r);\n\n        width = r.right - r.left;\n        height = r.bottom - r.top;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    invalidate_rectangle (\n        const rectangle& rect\n    )\n    {\n        auto_mutex M(wm);\n        if (rect.is_empty() == false && !has_been_destroyed)\n        {\n            RECT info;\n            info.top = rect.top();\n            info.left = rect.left();\n            info.right = rect.right()+1;\n            info.bottom = rect.bottom()+1;\n\n            InvalidateRect(hwnd,&info,FALSE);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_im_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        HIMC hImc = ImmGetContext(hwnd);\n\n        COMPOSITIONFORM cf;\n        cf.dwStyle = CFS_POINT;\n        cf.ptCurrentPos.x = x;\n        cf.ptCurrentPos.y = y;\n        ImmSetCompositionWindow(hImc, &cf);\n        ImmReleaseContext(hwnd, hImc);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void put_on_clipboard (\n        const std::string& str\n    )\n    {\n        put_on_clipboard(convert_mbstring_to_wstring(str));\n    }\n\n    void put_on_clipboard (\n        const dlib::ustring& str\n    )\n    {\n        put_on_clipboard(convert_utf32_to_wstring(str));\n    }\n\n    void put_on_clipboard (\n        const std::wstring& str\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        using namespace std;\n\n        auto globals = global_data();\n\n        if (OpenClipboard(globals->helper_window))\n        {\n            EmptyClipboard();\n            auto_mutex M(globals->window_table.get_mutex());\n\n            const unsigned long newlines = count(str.begin(),str.end(),L'\\n');\n\n            HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE,(str.size()+newlines+1)*sizeof(wchar_t));\n            if (mem != NULL)\n            {\n                wchar_t* buf = reinterpret_cast<wchar_t*>(GlobalLock(mem));\n\n                if (buf != NULL)\n                {\n                    // copy str into buf while also replacing all the \\n with \\r\\n\n                    for (wstring::size_type i = 0; i < str.size(); ++i)\n                    {\n                        if (str[i] != L'\\n')\n                        {\n                            *buf = str[i];\n                            ++buf;\n                        }\n                        else\n                        {\n                            *buf = L'\\r';\n                            ++buf;\n                            *buf = L'\\n';\n                            ++buf;\n                        }\n                    }\n                    *buf = L'\\0';\n                    GlobalUnlock(mem);\n                    SetClipboardData(CF_UNICODETEXT,mem);\n                }\n            }\n            CloseClipboard();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void get_from_clipboard (\n        std::string& str\n    )\n    {\n        std::wstring wstr;\n        get_from_clipboard(wstr);\n        str = convert_wstring_to_mbstring(wstr);\n    }\n\n    void get_from_clipboard (\n        dlib::ustring& str\n    )\n    {\n        std::wstring wstr;\n        get_from_clipboard(wstr);\n        str = convert_to_utf32(wstr);\n    }\n\n    void get_from_clipboard (\n        std::wstring& str\n    )\n    {\n        using namespace gui_core_kernel_1_globals;\n        using namespace std;\n        auto globals = global_data();\n\n        auto_mutex M(globals->window_table.get_mutex());\n        if (OpenClipboard(globals->helper_window))\n        {\n\n            HANDLE data = GetClipboardData(CF_UNICODETEXT);\n            if (data != NULL)\n            {\n                wchar_t* buf = reinterpret_cast<wchar_t*>(GlobalLock(data));\n                if (buf != 0)\n                {\n                    str.clear();\n\n                    // copy the data from buf into str while also removing any '\\r' \n                    // characters.\n                    while (*buf != L'\\0')\n                    {\n                        if (*buf != L'\\r')\n                            str += *buf;\n                        ++buf;\n                    }\n\n                    GlobalUnlock(data);\n                }\n                else\n                {\n                    Beep(500,500);\n                }\n            }\n\n            CloseClipboard();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // WIN32\n\n#endif // DLIB_GUI_CORE_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/gui_core/gui_core_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki \n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEl_1_\n#define DLIB_GUI_CORE_KERNEl_1_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n#ifdef DLIB_NO_GUI_SUPPORT\n#error \"DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code.  Turn DLIB_NO_GUI_SUPPORT off if you want to use it.\"\n#endif\n\n#include <string>\n\n#include \"../windows_magic.h\"\n\n\n#include <windows.h>\n#include <winuser.h>\n#include <windowsx.h>\n#include <commctrl.h>\n\n#include \"gui_core_kernel_abstract.h\"\n\n#ifdef _MSC_VER\n// Disable the following warnings for Visual Studio\n//\n// These two warnings have to do with converting points to and from the LONG\n// type.  But both these types are 32 bits in windows so it is fine.\n#pragma warning(disable: 4244; disable: 4312)\n#endif \n\n#include \"../algs.h\"\n#include \"../sync_extension.h\"\n#include \"../binary_search_tree.h\"\n#include \"../threads.h\"\n#include \"../geometry/rectangle.h\"\n#include \"../assert.h\"\n#include \"../queue.h\"\n#include \"../pixel.h\"\n#include \"../unicode.h\"\n#include \"../smart_pointers/shared_ptr_thread_safe.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class base_window;\n    namespace gui_core_kernel_1_globals\n    {\n\n        LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);\n        class event_handler_thread;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class canvas : public rectangle\n    {\n    public:\n        struct pixel\n        {\n            unsigned char blue;\n            unsigned char green;\n            unsigned char red;\n        };\n\n        ~canvas() { }\n\n        inline pixel* operator[] (\n            unsigned long row\n        ) const\n        {\n            DLIB_ASSERT(row < height(),\n                \"\\tpixel* canvas::operator[]\"\n                << \"\\n\\tyou have to give a row that is less than the height()\"\n                << \"\\n\\tthis:     \" << this\n                << \"\\n\\trow:      \" << row \n                << \"\\n\\theight(): \" << height() \n                );\n            unsigned char* temp = bits + row_width*row;\n            return reinterpret_cast<pixel*>(temp);\n        }\n\n        void fill (\n            unsigned char red_,\n            unsigned char green_,\n            unsigned char blue_\n        ) const;\n\n    private:\n\n        friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM);\n\n        canvas (\n            unsigned char* bits_,\n            unsigned long padding_,\n            unsigned long left_,\n            unsigned long top_,            \n            unsigned long right_,            \n            unsigned long bottom_\n        ) : \n            rectangle(left_,top_,right_,bottom_),\n            bits(bits_),\n            width_(width()),\n            height_(height()),\n            row_width(width_*3+padding_)\n        {}\n\n        // restricted functions\n        canvas();        // normal constructor\n        canvas(canvas&);        // copy constructor\n        canvas& operator=(canvas&);    // assignment operator    \n\n        unsigned char* const bits;\n        const unsigned long width_;\n        const unsigned long height_;\n        const unsigned long row_width;\n    };\n\n    template <>\n    struct pixel_traits<canvas::pixel>\n    {\n        constexpr static bool rgb  = true;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void put_on_clipboard (\n        const std::string& str\n    );\n\n    void put_on_clipboard (\n        const std::wstring& str\n    );\n\n    void put_on_clipboard (\n        const dlib::ustring& str\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void get_from_clipboard (\n        std::string& str\n    );\n\n    void get_from_clipboard (\n        std::wstring& str\n    );\n\n    void get_from_clipboard (\n        dlib::ustring& str\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class base_window\n    {\n        friend LRESULT CALLBACK gui_core_kernel_1_globals::WndProc (HWND, UINT, WPARAM, LPARAM);\n        dlib::shared_ptr_thread_safe<gui_core_kernel_1_globals::event_handler_thread> globals;\n\n        HWND hwnd;\n        DWORD style;\n        bool has_been_destroyed;\n\n        // This is true if the mouse is in this window.  false otherwise.\n        // also note that this variable is only accessed from the event handling thread\n        // (except for being initialized below in the constructor, but that is inside\n        // the window_table mutex so it doesn't matter).\n        bool mouse_in;\n\n        // this is a copy of the last inputs we sent to the on_mouse_move() event.\n        long prevx;\n        long prevy;\n        unsigned long prev_state;\n\n    protected:\n        const rmutex& wm;\n\n    public:\n\n        base_window (\n            bool resizable = true,\n            bool undecorated = false\n        );\n\n        virtual ~base_window (\n        );\n\n        void close_window (\n        );\n\n        bool is_closed (\n        ) const;\n\n        void set_title (\n            const std::string& title\n        );\n\n        void set_title (\n            const std::wstring& title\n        );\n\n        void set_title (\n            const ustring& title\n        );\n\n        virtual void show (\n        );    \n\n        virtual void hide(\n        );    \n\n        void set_size (\n            int width_,\n            int height_\n        );\n\n        void set_pos (\n            long x_,\n            long y_\n        );\n\n        void get_pos (\n            long& x_,\n            long& y_\n        );\n\n        void get_size (\n            unsigned long& width,\n            unsigned long& height\n        ) const;\n\n        void get_display_size (\n            unsigned long& width,\n            unsigned long& height\n        ) const;\n\n        void invalidate_rectangle (\n            const rectangle& rect\n        );\n\n        void trigger_user_event (\n            void* p,\n            int i\n        );\n\n        void wait_until_closed (\n        ) const;\n\n        void set_im_pos (\n            long x_,\n            long y_\n        );\n\n        enum on_close_return_code\n        {\n            DO_NOT_CLOSE_WINDOW,\n            CLOSE_WINDOW\n        };\n\n        enum mouse_state_masks\n        {\n            NONE = 0,\n            LEFT = 1,\n            RIGHT = 2,\n            MIDDLE = 4,\n            SHIFT = 8,\n            CONTROL = 16\n        };\n\n        enum keyboard_state_masks\n        {\n            KBD_MOD_NONE = 0,\n            KBD_MOD_SHIFT = 1,\n            KBD_MOD_CONTROL = 2,\n            KBD_MOD_ALT = 4,\n            KBD_MOD_META = 8,\n            KBD_MOD_CAPS_LOCK = 16,\n            KBD_MOD_NUM_LOCK = 32,\n            KBD_MOD_SCROLL_LOCK = 64\n        };\n\n        enum non_printable_keyboard_keys\n        {\n            KEY_BACKSPACE,\n            KEY_SHIFT,\n            KEY_CTRL,\n            KEY_ALT,\n            KEY_PAUSE,\n            KEY_CAPS_LOCK,\n            KEY_ESC,\n            KEY_PAGE_UP,\n            KEY_PAGE_DOWN,\n            KEY_END,\n            KEY_HOME,\n            KEY_LEFT,           // This is the left arrow key\n            KEY_RIGHT,          // This is the right arrow key\n            KEY_UP,             // This is the up arrow key\n            KEY_DOWN,           // This is the down arrow key\n            KEY_INSERT,\n            KEY_DELETE,\n            KEY_SCROLL_LOCK,\n  \n            // Function Keys\n            KEY_F1,\n            KEY_F2,\n            KEY_F3,\n            KEY_F4,\n            KEY_F5,\n            KEY_F6,\n            KEY_F7,\n            KEY_F8,\n            KEY_F9,\n            KEY_F10,\n            KEY_F11,\n            KEY_F12\n        };\n\n    protected:\n\n        virtual on_close_return_code on_window_close(\n        ){return CLOSE_WINDOW;}\n\n        virtual void on_user_event (\n            void* ,\n            int \n        ){}\n\n        virtual void on_window_resized(\n        ){}\n        \n        virtual void on_window_moved(\n        ){}\n\n        virtual void on_mouse_down (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long ,\n            bool \n        ){}\n\n        virtual void on_mouse_up (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_move (\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_leave (\n        ){}\n\n        virtual void on_mouse_enter (\n        ){}\n\n        virtual void on_wheel_up (\n            unsigned long \n        ){}\n\n        virtual void on_wheel_down (\n            unsigned long \n        ){}\n\n        virtual void on_focus_gained (\n        ){}\n\n        virtual void on_focus_lost (\n        ){}\n\n        virtual void on_keydown (\n            unsigned long ,          \n            bool ,\n            unsigned long \n        ){}\n            \n        virtual void on_string_put (\n            const std::wstring&\n        ){}\n\n    private:\n\n        virtual void paint (\n            const canvas& \n        ) =0;\n\n        base_window(base_window&);        // copy constructor\n        base_window& operator=(base_window&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#ifdef NO_MAKEFILE\n#include \"gui_core_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_GUI_CORE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/gui_core/gui_core_kernel_2.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEL_2_CPp_\n#define DLIB_GUI_CORE_KERNEL_2_CPp_\n#include \"../platform.h\"\n\n#ifdef DLIB_POSIX\n\n#include \"gui_core_kernel_2.h\"\n\n#include <cmath>\n#include <cstring>\n#include <iostream>\n#include <vector>\n#include <set>\n\n#include <X11/Xatom.h>\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/keysym.h>\n#include <X11/Xlocale.h>\n#include <X11/XKBlib.h>\n\n#include <poll.h>\n\n#include \"../assert.h\"\n#include \"../queue.h\"\n#include \"../sync_extension.h\"\n#include \"../logger.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gui_core_kernel_2_globals\n    {\n        void init_keyboard_mod_masks();\n        struct user_event_type\n        {\n            Window w;\n            void* p;\n            int i;\n        };\n\n        typedef sync_extension<queue<user_event_type,memory_manager<char>::kernel_1b>::kernel_2a_c>::kernel_1a queue_of_user_events;\n\n        typedef sync_extension<binary_search_tree<Window,base_window*>::kernel_1a>::kernel_1a \n            window_table_type;\n\n    // ----------------------------------------------------------------------------------------\n\n        const std::shared_ptr<dlib::mutex>& global_mutex()\n        {\n            static std::shared_ptr<dlib::mutex> m(new dlib::mutex);\n            return m;\n        }\n\n        class event_handler_thread : public threaded_object\n        {\n        public:\n\n            enum et_state\n            {\n                uninitialized,\n                initialized,\n                failure_to_init \n            };\n\n            et_state status;\n            logger dlog;\n\n\n            int depth;\n            Display* disp;\n            XIM xim;\n            XIMStyle xim_style;\n            Screen* screen;\n\n            Atom delete_window; \n            Window exit_window;\n            std::wstring clipboard;\n\n            int alt_mask;\n            int meta_mask;\n            int num_lock_mask;\n            int scroll_lock_mask;\n\n            // the mutex in this object is the global mutex used to protect everything\n            // in the gui_core and gui_widgets components.\n            window_table_type window_table;\n\n            rsignaler window_close_signaler;\n            rsignaler et_signaler;\n\n            queue_of_user_events user_events;\n            queue_of_user_events user_events_temp;\n\n            std::shared_ptr<dlib::mutex> reference_to_global_mutex;\n\n            event_handler_thread(\n            ) :\n                dlog(\"dlib.gui_core\"),\n                depth(0),\n                disp(0),\n                xim(0),\n                screen(0),\n                alt_mask(0),\n                meta_mask(0),\n                num_lock_mask(0),\n                scroll_lock_mask(0),\n                window_close_signaler(window_table.get_mutex()),\n                et_signaler(window_table.get_mutex()),\n                reference_to_global_mutex(global_mutex())\n            {\n                auto_mutex M(window_table.get_mutex());\n\n                status = uninitialized;\n\n                // start up the event handler thread\n                start();\n\n                // wait for the event thread to get up and running\n                while (status == uninitialized)\n                    et_signaler.wait();\n\n                if (status == failure_to_init)\n                    throw gui_error(\"Failed to initialize X11 resources\");\n\n                init_keyboard_mod_masks();\n            }\n\n            ~event_handler_thread ()\n            {\n                \n                if (is_alive())\n                {\n                    \n                    if (status != failure_to_init)\n                    {\n                        XConfigureEvent event;\n                        event.type = ConfigureNotify;\n                        event.send_event = True;\n                        event.display = disp;\n                        event.window = exit_window;\n                        event.x = 1;\n                        XFlush(disp);\n                        XPutBackEvent(disp,reinterpret_cast<XEvent*>(&event));\n                        XFlush(disp);\n\n                        // This should cause XNextEvent() to unblock so that it will see \n                        // this ConfigureNotify event we are putting onto the event queue.\n                        XSendEvent(disp,exit_window,False,0,reinterpret_cast<XEvent*>(&event));\n                        XFlush(disp);\n\n                        wait();\n\n                        if (xim != NULL)\n                        {\n                            XCloseIM(xim);\n                        }\n\n                        XCloseDisplay(disp);\n\n\n                    }\n                    else\n                    {\n\n                        wait();\n                    }\n                }\n\n\n            }\n\n        private:\n\n            void thread (\n            )\n            {\n                using namespace std;\n                using namespace dlib;\n                try\n                {\n\n                    // You are supposed to call this if using XLib in a threaded program.  Note\n                    // however that at one point I noticed that calling this causes a dead-lock \n                    // when using XIM.  But I can't reproduce that anymore and not calling it \n                    // sometimes causes XCloseDisplay() to hang.\n                    if (XInitThreads() == 0)\n                    {\n                        dlog << LFATAL << \"Unable to initialize threading support.\";\n                        // signal that an error has occurred\n                        window_table.get_mutex().lock();\n                        status = failure_to_init;\n                        et_signaler.broadcast();\n                        window_table.get_mutex().unlock();\n                        return;\n                    }\n\n                    window_table.get_mutex().lock();\n                    disp = XOpenDisplay(NULL);\n                    window_table.get_mutex().unlock();\n                    if (disp == 0)\n                    {\n                        window_table.get_mutex().lock();\n                        disp = XOpenDisplay(\":0.0\");\n                        window_table.get_mutex().unlock();\n                        if (disp == 0)\n                        {\n                            dlog << LFATAL << \"Unable to connect to the X display.\";\n                            // signal that an error has occurred\n                            window_table.get_mutex().lock();\n                            status = failure_to_init;\n                            et_signaler.broadcast();\n                            window_table.get_mutex().unlock();\n                            return;\n                        }\n                    }\n\n                    window_table.get_mutex().lock();\n                    screen = DefaultScreenOfDisplay(disp);\n                    depth = DefaultDepthOfScreen(screen);\n                    delete_window = XInternAtom(disp,\"WM_DELETE_WINDOW\",1); \n                    window_table.get_mutex().unlock();\n\n                    xim = NULL;\n                    // I'm disabling XIM usage all together because calling XSetICValues()\n                    // in set_im_pos() randomly hangs the application (on Ubuntu 13.10 at\n                    // least).    \n                    /*\n                    window_table.get_mutex().lock();\n                    std::string saved_locale(setlocale (LC_CTYPE, NULL));\n                    if (setlocale( LC_CTYPE, \"\" ) && XSupportsLocale() && XSetLocaleModifiers(\"\"))\n                        xim = XOpenIM(disp, NULL, NULL, NULL);\n                    else\n                        setlocale( LC_CTYPE, saved_locale.c_str() );\n                    window_table.get_mutex().unlock();\n                    */\n                    if (xim)\n                    {\n                        const static XIMStyle preedit_styles[] =\n                            {XIMPreeditPosition, XIMPreeditNothing, XIMPreeditNone, 0};\n                        const static XIMStyle status_styles[] =\n                            {XIMStatusNothing, XIMStatusNone, 0};\n                        xim_style = 0;\n\n                        XIMStyles *xim_styles;\n                        window_table.get_mutex().lock();\n\n                        XGetIMValues (xim, XNQueryInputStyle, &xim_styles, (const void*)NULL);\n                        window_table.get_mutex().unlock();\n                        std::set<XIMStyle> xims;\n                        for (int i = 0; i < xim_styles->count_styles; ++i){\n                            xims.insert(xim_styles->supported_styles[i]);\n                        }\n                        for (int j = 0; status_styles[j]; ++j){\n                            for (int i = 0; preedit_styles[i]; ++i){\n                                xim_style = (status_styles[j] | preedit_styles[i]);\n                                if (xims.count(xim_style)) break;\n                            }\n                            if (xim_style) break;\n                        }\n                        XFree(xim_styles);\n                    }\n\n                    // make this window just so we can send messages to it and trigger\n                    // events in the event thread\n                    XSetWindowAttributes attr;\n                    window_table.get_mutex().lock();\n                    exit_window = XCreateWindow(\n                        disp,\n                        DefaultRootWindow(disp),\n                        0,\n                        0,\n                        10,  // this is the default width of a window\n                        10,  // this is the default width of a window\n                        0,\n                        depth,\n                        InputOutput,\n                        CopyFromParent,\n                        0,\n                        &attr\n                    );\n                    window_table.get_mutex().unlock();\n\n                    // signal that the event thread is now up and running\n                    window_table.get_mutex().lock();\n                    status = initialized;\n                    et_signaler.broadcast();\n                    window_table.get_mutex().unlock();\n\n                    // start the event handler\n                    event_handler();\n                }\n                catch (std::exception& e)\n                {\n                    cout << \"\\nEXCEPTION THROWN: \\n\" << e.what() << endl;\n                    abort();\n                }\n                catch (...)\n                {\n                    cout << \"UNKNOWN EXCEPTION THROWN.\\n\" << endl;\n                    abort();\n                }\n            }\n\n            void event_handler();\n            void init_keyboard_mod_masks();\n        };\n\n        struct x11_base_windowstuff\n        {\n            Window hwnd;\n            Time last_click_time;\n            XIC xic;\n            XFontSet fs;\n            std::shared_ptr<event_handler_thread> globals;\n        };\n\n        // Do all this just to make sure global_mutex() is initialized at program start\n        // and thus hopefully before any threads have the chance to startup and call\n        // global_data() concurrently.\n        struct call_global_mutex { call_global_mutex() { global_mutex(); } };\n        static call_global_mutex call_global_mutex_instance;\n\n        const std::shared_ptr<event_handler_thread>& global_data()\n        {\n            auto_mutex M(*global_mutex());\n            static std::shared_ptr<event_handler_thread> p;\n            if (p.get() == 0)\n                p.reset(new event_handler_thread());\n            return p;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        Bool XCheckIfEventPredicate (\n            Display* ,\n            XEvent* event,\n            XPointer arg\n        )\n        /*!\n            ensures\n                - if (event is an Expose event for the window pointed to by arg) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n        {\n            if (event->type == Expose)\n            {\n                XExposeEvent* e = reinterpret_cast<XExposeEvent*>(event);\n                Window* win= reinterpret_cast<Window*>(arg);\n                if (e->window == *win)\n                {\n                    return 1;\n                }\n            }\n            return 0;\n        }\n\n    // ----------------------------------------------------------------------------------------\n    \n        static bool map_keys (\n            KeySym keycode,\n            bool ,\n            bool ,\n            unsigned long& result,\n            bool& is_printable\n        )\n        /*!\n            requires\n                - if (shift was down for this key) then\n                    - shift == true\n                - if (caps lock was on for this key) then\n                    - caps == true\n                - keycode == the keycode from windows that we are to process\n                - keycode < keyboard_keys_size\n            ensures\n                - if (this key should be ignored) then\n                    - returns false\n                - else\n                    - returns true\n                    - #is_printable == true if result is a printable ascii character\n                    - #result == the keycode converted into the proper number to tbe \n                      returned by the event handler.\n        !*/\n        {\n            is_printable = true;\n            if ((keycode <= 'z' && keycode >= 'a') || \n                (keycode <= 'Z' && keycode >= 'A') || \n                (keycode <= '9' && keycode >= '0'))\n            {\n                result = keycode;\n            }\n            else\n            {\n                is_printable = false;\n                switch (keycode)\n                {\n                case XK_Home:   result = base_window::KEY_HOME; break;\n                case XK_Left:   result = base_window::KEY_LEFT; break;\n                case XK_Right:  result = base_window::KEY_RIGHT; break;\n                case XK_Down:   result = base_window::KEY_DOWN; break;\n                case XK_Up:     result = base_window::KEY_UP; break;\n                case XK_Prior:  result = base_window::KEY_PAGE_UP; break;\n                case XK_Next:   result = base_window::KEY_PAGE_DOWN;     break;\n                case XK_End:    result = base_window::KEY_END; break;\n                case XK_Escape:    result = base_window::KEY_ESC; break;\n                \n                case XK_KP_Delete:    result = base_window::KEY_DELETE; break;\n                case XK_KP_Prior:    result = base_window::KEY_PAGE_UP; break;\n                case XK_KP_Next:    result = base_window::KEY_PAGE_DOWN; break;\n\n\n                case XK_F1:    result = base_window::KEY_F1; break;\n                case XK_F2:    result = base_window::KEY_F2; break;\n                case XK_F3:    result = base_window::KEY_F3; break;\n                case XK_F4:    result = base_window::KEY_F4; break;\n                case XK_F5:    result = base_window::KEY_F5; break;\n                case XK_F6:    result = base_window::KEY_F6; break;\n                case XK_F7:    result = base_window::KEY_F7; break;\n                case XK_F8:    result = base_window::KEY_F8; break;\n                case XK_F9:    result = base_window::KEY_F9; break;\n                case XK_F10:    result = base_window::KEY_F10; break;\n                case XK_F11:    result = base_window::KEY_F11; break;\n                case XK_F12:    result = base_window::KEY_F12; break;\n                    \n                    \n                case XK_Shift_L:    result = base_window::KEY_SHIFT; break;\n                case XK_Shift_R:    result = base_window::KEY_SHIFT; break;\n                case XK_Control_L:    result = base_window::KEY_CTRL; break;\n                case XK_Control_R:    result = base_window::KEY_CTRL; break;\n                case XK_Caps_Lock:    result = base_window::KEY_CAPS_LOCK; break;\n                case XK_Alt_L:    result = base_window::KEY_ALT; break;\n                case XK_Alt_R:    result = base_window::KEY_ALT; break;\n\n                    \n                case XK_BackSpace:    result = base_window::KEY_BACKSPACE; break;\n                case XK_Delete:    result = base_window::KEY_DELETE; break;\n                case XK_Scroll_Lock:    result = base_window::KEY_SCROLL_LOCK; break;\n                case XK_Pause:    result = base_window::KEY_PAUSE; break;\n                case XK_Insert:    result = base_window::KEY_INSERT; break;\n                case XK_KP_Insert:    result = base_window::KEY_INSERT; break;\n\n\n\n\n                case XK_exclam:    \n                    is_printable = true;\n                    result = '!'; break;\n                case XK_quotedbl:    \n                    is_printable = true;\n                    result = '\"'; break;\n                case XK_numbersign:    \n                    is_printable = true;\n                    result = '#'; break;\n                case XK_dollar:    \n                    is_printable = true;\n                    result = '$'; break;\n                case XK_percent:    \n                    is_printable = true;\n                    result = '%'; break;\n                case XK_ampersand:    \n                    is_printable = true;\n                    result = '&'; break;\n                case XK_apostrophe:    \n                    is_printable = true;\n                    result = '\\''; break;\n                case XK_parenleft:    \n                    is_printable = true;\n                    result = '('; break;\n                case XK_parenright:    \n                    is_printable = true;\n                    result = ')'; break;\n                case XK_asterisk:    \n                    is_printable = true;\n                    result = '*'; break;\n                case XK_plus:    \n                    is_printable = true;\n                    result = '+'; break;\n                case XK_comma:    \n                    is_printable = true;\n                    result = ','; break;\n                case XK_minus:    \n                    is_printable = true;\n                    result = '-'; break;\n                case XK_period:    \n                    is_printable = true;\n                    result = '.'; break;\n                case XK_slash:    \n                    is_printable = true;\n                    result = '/'; break;\n                case XK_colon:    \n                    is_printable = true;\n                    result = ':'; break;\n                case XK_semicolon:    \n                    is_printable = true;\n                    result = ';'; break;\n                case XK_less:    \n                    is_printable = true;\n                    result = '<'; break;\n                case XK_equal:    \n                    is_printable = true;\n                    result = '='; break;\n                case XK_greater:    \n                    is_printable = true;\n                    result = '>'; break;\n                case XK_question:    \n                    is_printable = true;\n                    result = '?'; break;\n                case XK_at:    \n                    is_printable = true;\n                    result = '@'; break;\n                case XK_grave:    \n                    is_printable = true;\n                    result = '`'; break;\n                case XK_underscore:    \n                    is_printable = true;\n                    result = '_'; break;\n                case XK_asciicircum:    \n                    is_printable = true;\n                    result = '^'; break;\n                case XK_bracketleft:    \n                    is_printable = true;\n                    result = '['; break;\n                case XK_backslash:    \n                    is_printable = true;\n                    result = '\\\\'; break;\n                case XK_bracketright:    \n                    is_printable = true;\n                    result = ']'; break;\n                case XK_asciitilde:    \n                    is_printable = true;\n                    result = '~'; break;\n                case XK_braceleft:    \n                    is_printable = true;\n                    result = '{'; break;\n                case XK_bar:    \n                    is_printable = true;\n                    result = '|'; break;\n                case XK_braceright:    \n                    is_printable = true;\n                    result = '}'; break;\n            \n\n\n\n                case XK_space:    \n                    is_printable = true;\n                    result = ' '; break;\n                case XK_Return:    \n                    is_printable = true;\n                    result = '\\n'; break;\n                case XK_Tab:    \n                    is_printable = true;\n                    result = '\\t'; break;\n                case XK_KP_Divide: \n                    is_printable = true;\n                    result = '/'; break;\n                case XK_KP_Decimal: \n                    is_printable = true;\n                    result = '.'; break;\n                case XK_KP_Subtract: \n                    is_printable = true;\n                    result = '-'; break;\n                case XK_KP_Add: \n                    is_printable = true;\n                    result = '+'; break;\n                case XK_KP_Multiply: \n                    is_printable = true;\n                    result = '*'; break;\n                case XK_KP_Equal: \n                    is_printable = true;\n                    result = '='; break;\n\n                case XK_KP_0: \n                    is_printable = true;\n                    result = '0'; break;\n                case XK_KP_1: \n                    is_printable = true;\n                    result = '1'; break;\n                case XK_KP_2: \n                    is_printable = true;\n                    result = '2'; break;\n                case XK_KP_3: \n                    is_printable = true;\n                    result = '3'; break;\n                case XK_KP_4: \n                    is_printable = true;\n                    result = '4'; break;\n                case XK_KP_5: \n                    is_printable = true;\n                    result = '5'; break;\n                case XK_KP_6: \n                    is_printable = true;\n                    result = '6'; break;\n                case XK_KP_7: \n                    is_printable = true;\n                    result = '7'; break;\n                case XK_KP_8: \n                    is_printable = true;\n                    result = '8'; break;\n                case XK_KP_9: \n                    is_printable = true;\n                    result = '9'; break;\n\n                default:\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        void event_handler_thread::\n        event_handler (\n        )\n        /*!\n            ensures\n                - will handle all events and event dispatching            \n        !*/\n        {       \n            try\n            {\n                std::vector<unsigned char> bitmap_buffer;\n                bool quit_event_loop = false;\n                while (quit_event_loop == false)\n                {\n                    // get a lock on the window_table's mutex\n                    auto_mutex window_table_locker(window_table.get_mutex());\n\n                    XEvent ev;                \n                    memset(&ev, 0, sizeof(ev));\n                    while (XPending(disp) == 0){\n                        window_table.get_mutex().unlock();\n                        // wait until receiving X11 next event\n                        struct pollfd pfd;\n                        pfd.fd = ConnectionNumber(disp);\n                        pfd.events = POLLIN | POLLPRI;\n                        poll(&pfd, 1, -1);  \n                        \n                        window_table.get_mutex().lock();\n                    }\n                    XNextEvent(disp,&ev);\n\n                    // pass events to input method.\n                    // if this event is needed by input method, XFilterEvent returns True\n                    if (XFilterEvent(&ev, None) == True){\n                        continue;\n                    }\n\n                    // if this event is for one of the windows in the window_table\n                    // then get that window out of the table and put it into win.\n                    XAnyEvent* _ae = reinterpret_cast<XAnyEvent*>(&ev);\n                    base_window** win_ = window_table[_ae->window];\n                    base_window* win = 0;\n                    if (win_)\n                        win = *win_;\n\n\n                    // ignore messages for unmapped windows\n                    if (ev.type != MapNotify && win != 0) \n                    {\n                        if (win->is_mapped == false)\n                           continue;\n                    }\n\n\n                    switch (ev.type)\n                    {\n\n                    case SelectionRequest:\n                        {\n                            Atom a_ct = XInternAtom(disp, \"COMPOUND_TEXT\", False);\n                            XSelectionRequestEvent* req = reinterpret_cast<XSelectionRequestEvent*>(&ev.xselectionrequest);\n                            XEvent respond;\n\n                            if (req->target == XA_STRING)\n                            {\n                                XChangeProperty (disp,\n                                                 req->requestor,\n                                                 req->property,\n                                                 XA_STRING,\n                                                 8,\n                                                 PropModeReplace,\n                                                 reinterpret_cast<const unsigned char*>(convert_wstring_to_mbstring(clipboard).c_str()),\n                                                 clipboard.size()+1);\n                                respond.xselection.property=req->property;\n                            }\n                            else if (req->target == a_ct)\n                            {\n                                XChangeProperty (disp,\n                                                 req->requestor,\n                                                 req->property,\n                                                 a_ct,\n                                                 sizeof(wchar_t)*8,\n                                                 PropModeReplace,\n                                                 reinterpret_cast<const unsigned char*>(clipboard.c_str()),\n                                                 clipboard.size()+1);\n                                respond.xselection.property=req->property;\n                            }\n                            else \n                            {\n                                respond.xselection.property= None;\n                            }\n                            respond.xselection.type= SelectionNotify;\n                            respond.xselection.display= req->display;\n                            respond.xselection.requestor= req->requestor;\n                            respond.xselection.selection=req->selection;\n                            respond.xselection.target= req->target;\n                            respond.xselection.time = req->time;\n                            XSendEvent (disp, req->requestor,0,0,&respond);\n                            XFlush (disp);\n\n                        } break;\n\n                    case MapNotify:\n                        {\n                            if (win == 0)\n                                break;\n\n                            win->is_mapped = true;\n\n                            if (win->resizable == false)\n                            {\n                                XSizeHints* hints = XAllocSizeHints();\n                                hints->flags = PMinSize|PMaxSize;\n                                hints->min_width = win->width;\n                                hints->max_width = win->width;\n                                hints->max_height = win->height; \n                                hints->min_height = win->height; \n                                XSetNormalHints(disp,win->x11_stuff.hwnd,hints);\n                                XFree(hints);\n                            }\n\n\n\n                            if (win->has_been_resized)\n                            {\n                                XResizeWindow(disp,win->x11_stuff.hwnd,win->width,win->height);\n                                win->has_been_resized = false;\n                                win->on_window_resized();\n                            }\n\n                            if (win->has_been_moved)\n                            {\n                                XMoveWindow(disp,win->x11_stuff.hwnd,win->x,win->y);\n                                win->has_been_moved = false;\n                                win->on_window_moved();\n                            }\n                            XFlush(disp);\n\n\n                        } break;\n\n\n                    case KeyPress:\n                        {\n                            XKeyPressedEvent* e = reinterpret_cast<XKeyPressedEvent*>(&ev);\n\n                            if (win == 0)\n                                break;\n\n                            unsigned long state = 0;\n                            bool shift = ((e->state & ShiftMask)!=0);\n                            bool ctrl = ((e->state & ControlMask)!=0);\n                            bool caps = ((e->state & LockMask)!=0);\n                            if(shift)\n                                state |= base_window::KBD_MOD_SHIFT;\n                            if(ctrl)\n                                state |= base_window::KBD_MOD_CONTROL;\n                            if(caps)\n                                state |= base_window::KBD_MOD_CAPS_LOCK;\n                            if((e->state & alt_mask)!=0)\n                                state |= base_window::KBD_MOD_ALT;\n                            if((e->state & meta_mask)!=0)\n                                state |= base_window::KBD_MOD_META;\n                            if((e->state & num_lock_mask)!=0)\n                                state |= base_window::KBD_MOD_NUM_LOCK;\n                            if((e->state & scroll_lock_mask)!=0)\n                                state |= base_window::KBD_MOD_SCROLL_LOCK;\n\n                            KeySym key;\n                            Status status;\n\n                            if (win->x11_stuff.xic) {\n                                std::wstring wstr;\n                                wstr.resize(2);\n                                int len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status);\n                                if (status == XBufferOverflow){\n                                    wstr.resize(len);\n                                    len = XwcLookupString(win->x11_stuff.xic,e,&wstr[0],wstr.size(),&key,&status);\n                                }\n                                if (status == XLookupChars){\n                                    win->on_string_put(wstr);\n                                }\n                            } else {\n                                char buffer[2];\n                                XLookupString(e, buffer, sizeof(buffer), &key, NULL);\n                                status = XLookupKeySym;\n                            }\n\n                            if (status == XLookupKeySym || status == XLookupBoth){\n\n                                bool is_printable;\n                                unsigned long result;\n\n                                if (map_keys(key,shift,caps,result,is_printable))\n                                {\n                                    // signal the keyboard event\n                                    win->on_keydown(result,is_printable,state);\n                                }\n                            }\n                            \n                        } break;\n\n                    case FocusIn:\n                        {\n                            if (win == 0)\n                                break;\n\n                            // signal the focus event \n                            win->on_focus_gained();\n                        } break;\n\n                    case FocusOut:\n                        {\n                            if (win == 0)\n                                break;\n\n                            // signal the focus event \n                            win->on_focus_lost();\n                        } break;\n\n                    case ButtonPress:\n                    case ButtonRelease:\n                        {\n                            XButtonEvent* e = reinterpret_cast<XButtonEvent*>(&ev);\n\n                            if (win == 0)\n                                break;\n\n                            unsigned long btn = base_window::NONE;\n                            if (e->button == Button1)\n                                btn = base_window::LEFT;\n                            else if (e->button == Button3)\n                                btn = base_window::RIGHT;\n                            else if (e->button == Button2)\n                                btn = base_window::MIDDLE;\n\n                            unsigned long state = 0;\n                            if (e->state & ControlMask)\n                                state |= base_window::CONTROL;\n                            if (e->state & Button1Mask)\n                                state |= base_window::LEFT;\n                            if (e->state & Button2Mask)\n                                state |= base_window::MIDDLE;\n                            if (e->state & Button3Mask)\n                                state |= base_window::RIGHT;\n                            if (e->state & ShiftMask)\n                                state |= base_window::SHIFT;\n\n                            // only send the event if this is a button we support\n                            if (btn != (unsigned long)base_window::NONE)\n                            {\n\n\n                                if (ev.type == ButtonPress)\n                                {\n                                    bool is_double_click = false;\n                                    if (win->last_click_button == btn &&\n                                        std::abs((long)win->last_click_x - (long)e->x) < 5 &&\n                                        std::abs((long)win->last_click_y - (long)e->y) < 5 &&\n                                        e->time - win->x11_stuff.last_click_time <= 400)\n                                    {\n                                        // this is a double click\n                                        is_double_click = true;\n                                        // set this to make sure the next click can't be\n                                        // interpreted as a double click\n                                        win->last_click_button = base_window::NONE;\n                                    }\n                                    else\n                                    {\n                                        win->last_click_button = btn;\n                                        win->last_click_x = e->x;\n                                        win->last_click_y = e->y;\n                                        win->x11_stuff.last_click_time = e->time;\n                                    }\n\n                                    // remove the clicked button from the state\n                                    state &= (~btn);\n                                    win->on_mouse_down(btn,state,e->x,e->y,is_double_click);\n\n                                }\n                                else\n                                {\n                                    // remove the clicked button from the state\n                                    state &= (~btn);\n                                    win->on_mouse_up(btn,state,e->x,e->y);\n                                }\n                            }\n                            else if (e->button == Button4 && ev.type == ButtonPress)\n                            {\n                                win->on_wheel_up(state);\n                            }\n                            else if (e->button == Button5 && ev.type == ButtonPress)\n                            {\n                                win->on_wheel_down(state);\n                            }\n                            \n                        } break;\n \n                    case LeaveNotify:\n                        {\n                            if (win == 0)\n                                break;\n\n                            win->on_mouse_leave();\n                            \n                        } break;\n\n                    case EnterNotify:\n                        {\n                            if (win == 0)\n                                break;\n\n                            win->on_mouse_enter();\n                        } break;\n\n                    case MotionNotify:\n                        {\n                            XMotionEvent* e = reinterpret_cast<XMotionEvent*>(&ev);\n\n                            if (win == 0)\n                                break;\n\n                            unsigned long state = 0;\n                            if (e->state & ControlMask)\n                                state |= base_window::CONTROL;\n                            if (e->state & Button1Mask)\n                                state |= base_window::LEFT;\n                            if (e->state & Button2Mask)\n                                state |= base_window::MIDDLE;\n                            if (e->state & Button3Mask)\n                                state |= base_window::RIGHT;\n                            if (e->state & ShiftMask)\n                                state |= base_window::SHIFT;\n\n                            win->on_mouse_move(state,e->x,e->y);\n                            \n                        } break;\n\n                    case ConfigureNotify:\n                        {\n                            XConfigureEvent* e = reinterpret_cast<XConfigureEvent*>(&ev);\n                            if (e->window == exit_window)\n                            {\n                                // this is the signal to quit the event handler\n                                quit_event_loop = true;\n                                break;\n                            }\n\n                            if (win == 0)\n                                break;\n\n                            if (win->width != e->width ||\n                                win->height != e->height ||\n                                win->has_been_resized)\n                            {\n                                win->has_been_resized = false;\n                                // this is a resize\n                                win->width = e->width;\n                                win->height = e->height;\n                                win->on_window_resized();\n                            }\n                            if (win->x != e->x ||\n                                win->y != e->y ||\n                                win->has_been_moved)\n                            {\n                                win->has_been_moved = false;\n                                // this is a move\n                                win->x = e->x;\n                                win->y = e->y;\n                                win->on_window_moved();\n                            }\n                            \n                        } break;\n\n                    case ClientMessage:\n                        {\n                            XClientMessageEvent* e = reinterpret_cast<XClientMessageEvent*>(&ev);\n                            if ((Atom)e->data.l[0] == delete_window)\n                            {\n                                if (win == 0)\n                                    break;\n\n\n                                if (win->on_window_close() == base_window::DO_NOT_CLOSE_WINDOW)\n                                {\n                                    DLIB_ASSERT(win->has_been_destroyed == false,\n                                        \"\\tYou called close_window() inside the on_window_close() event but\" \n                                        << \"\\n\\tthen returned DO_NOT_CLOSE_WINDOW.  You can do one or the other but not both.\"\n                                        << \"\\n\\tthis:     \" << win \n                                        );\n                                    // the client has decided not to close the window\n                                    // after all\n                                }\n                                else\n                                {                                \n                                    if (window_table[e->window])\n                                    {\n                                        window_table.destroy(e->window);\n                                        XDestroyWindow(disp,e->window);\n                                        win->has_been_destroyed = true;\n                                        window_close_signaler.broadcast();\n                                    }\n                                    else\n                                    {\n                                        // in this case the window must have self destructed by\n                                        // calling delete this;  so we don't have to do anything.\n                                    }\n                                }\n                            }\n                        } break;\n\n                    case Expose:\n                        {\n                            XExposeEvent* e = reinterpret_cast<XExposeEvent*>(&ev);\n\n                            if (win == 0)\n                                break;\n\n                            // take all the expose events for this window out\n                            XEvent etemp;\n                            int x = e->x;\n                            int y = e->y;\n                            int width = e->width;\n                            int height = e->height;  \n\n\n\n                            // What we are doing here with this loop is we are combining\n                            // all of the Expose events for this window that are \n                            // currently in the queue.  \n                            while (XCheckIfEvent(disp,&etemp,XCheckIfEventPredicate,reinterpret_cast<XPointer>(&(e->window))))\n                            {\n                                XExposeEvent* e2 = reinterpret_cast<XExposeEvent*>(&etemp);\n                                if (e2->x < x)\n                                {\n                                    width += x - e2->x;\n                                    x = e2->x;                                \n                                }\n                                if (e2->y < y)\n                                {\n                                    height += y - e2->y;\n                                    y = e2->y;\n                                }\n                                if (e2->width + e2->x > width + x)\n                                {\n                                    width = e2->width + e2->x - x;\n                                }\n                                if (e2->height + e2->y > height + y)\n                                {\n                                    height = e2->height + e2->y - y;\n                                }                                \n                            }\n\n                            // I'm not sure if this sort of thing can happen but\n                            // if it does then just ignore this entire event.\n                            if (width == 0 || height == 0)\n                            {\n                                break;\n                            }\n\n                            if (bitmap_buffer.size() < static_cast<unsigned long>(width*height*4))\n                                bitmap_buffer.resize(width*height*4);\n\n                            unsigned char* const bitmap = &bitmap_buffer[0];\n                            unsigned char* const end = bitmap + width*height*4;\n\n                            unsigned char* temp;\n                            canvas c(bitmap,x,y,x+width-1,y+height-1);\n\n\n                            win->paint(c);\n\n                            // the user might have called win->close_window() and if they did\n                            // then just stop right here.  We don't want to paint the window.\n                            if (win->has_been_destroyed)\n                                break;\n\n                            // if the color depth we are working with isn't 24bits then we need\n                            // to transform our image into whatever it is supposed to be.\n                            if (depth != 24)\n                            {\n                                // convert this image into an 8 bit image\n                                unsigned int red_bits = 0;\n                                unsigned int green_bits = 0;\n                                unsigned int blue_bits = 0;\n                                if (depth != 16)\n                                {\n                                    unsigned int bits = depth/3;\n                                    unsigned int extra = depth%3;\n                                    red_bits = bits;\n                                    green_bits = bits;\n                                    blue_bits = bits;\n                                    if (extra)\n                                    {\n                                        ++red_bits;\n                                        --extra;\n                                    }\n                                    if (extra)\n                                    {\n                                        ++green_bits;\n                                    }\n                                }\n                                else if (depth == 16)\n                                {\n                                    red_bits = 5;\n                                    green_bits = 6;\n                                    blue_bits = 5;\n                                }\n\n                                if (depth == 16) \n                                { \n                                    temp = bitmap;\n                                    unsigned char *red, *green, *blue;\n                                    while (temp != end)\n                                    {\n                                        blue = temp;\n                                        ++temp;\n                                        green = temp;\n                                        ++temp;\n                                        red = temp;\n                                        ++temp;\n                                        ++temp;\n\n                                        const unsigned long r = static_cast<unsigned long>(*red)>>(8-red_bits);\n                                        const unsigned long g = static_cast<unsigned long>(*green)>>(8-green_bits);\n                                        const unsigned long b = static_cast<unsigned long>(*blue)>>(8-blue_bits);\n\n                                        unsigned long color = (r<<(depth-red_bits))| (g<<(depth-red_bits-green_bits))| b;\n\n                                        *blue  = (color>>0)&0xFF;\n                                        *green = (color>>8)&0xFF;\n                                    }\n                                }\n                                else if (depth < 24)\n                                {\n                                    temp = bitmap;\n                                    unsigned char *red, *green, *blue;\n                                    while (temp != end)\n                                    {\n                                        blue = temp;\n                                        ++temp;\n                                        green = temp;\n                                        ++temp;\n                                        red = temp;\n                                        ++temp;\n                                        ++temp;\n\n                                        const unsigned long r = static_cast<unsigned long>(*red)>>(8-red_bits);\n                                        const unsigned long g = static_cast<unsigned long>(*green)>>(8-green_bits);\n                                        const unsigned long b = static_cast<unsigned long>(*blue)>>(8-blue_bits);\n\n                                        unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r;\n\n                                        *blue  = (color>>0)&0xFF;\n                                        *green = (color>>8)&0xFF;\n                                        *red   = (color>>16)&0xFF;\n                                    }\n                                }\n                                else if (depth > 24)\n                                {\n                                    temp = bitmap;\n                                    unsigned char *red, *green, *blue, *four;\n                                    while (temp != end)\n                                    {\n                                        blue = temp;\n                                        ++temp;\n                                        green = temp;\n                                        ++temp;\n                                        red = temp;\n                                        ++temp;\n                                        four = temp;\n                                        ++temp;\n\n                                        const unsigned long r = static_cast<unsigned long>(*red)<<(red_bits-8);\n                                        const unsigned long g = static_cast<unsigned long>(*green)<<(green_bits-8);\n                                        const unsigned long b = static_cast<unsigned long>(*blue)<<(blue_bits-8);\n\n                                        unsigned long color = (b<<(depth-blue_bits))| (g<<(depth-blue_bits-green_bits))| r;\n\n                                        *blue  = (color>>0)&0xFF;\n                                        *green = (color>>8)&0xFF;\n                                        *red   = (color>>16)&0xFF;\n                                        *four  = (color>>24)&0xFF;\n                                    }\n                                }\n                            } // if (depth != 24)\n\n\n\n                            XImage img;\n                            memset(&img,0,sizeof(img));\n                            img.width = width;\n                            img.height = height;\n                            img.depth = depth;\n                            img.data = reinterpret_cast<char*>(bitmap);\n                            img.bitmap_bit_order = LSBFirst;\n                            img.byte_order = LSBFirst;\n                            img.format = ZPixmap;\n                            img.bitmap_pad = 32;\n                            img.bitmap_unit = 32;\n                            img.bits_per_pixel = 32;\n\n\n                            XInitImage(&img);\n\n                            GC gc = XCreateGC(disp, e->window, 0, NULL);\n\n                            XPutImage(disp,e->window,gc,&img,0,0,x,y,width,height);\n\n                            XFreeGC(disp,gc);\n                        } break;\n                    } // switch (ev.type)\n                }\n            }\n            catch (std::exception& e)\n            {\n                dlog << LFATAL << \"Exception thrown in event handler: \" << e.what();\n            }\n            catch (...)\n            {\n                dlog << LFATAL << \"Unknown exception thrown in event handler.\";\n            }\n        }\n \n    // ----------------------------------------------------------------------------------------\n\n\n        int index_to_modmask(unsigned long n)\n        {\n            switch ( n )\n            {\n                case 0:\n                    return Mod1Mask;\n                case 1:\n                    return Mod2Mask;\n                case 2:\n                    return Mod3Mask;\n                case 3:\n                    return Mod4Mask;\n            }\n            return Mod5Mask;\n        }\n\n        void event_handler_thread::\n        init_keyboard_mod_masks()\n        {\n            XModifierKeymap* map = XGetModifierMapping( disp );\n            KeyCode* codes = map->modifiermap + map->max_keypermod * Mod1MapIndex;\n            for (int n = 0; n < 5 * map->max_keypermod; n++ )\n            {\n                if ( codes[n] == 0 )\n                    continue;\n                switch(XkbKeycodeToKeysym( disp, codes[n], 0, 0 ))\n                {\n                    case XK_Alt_L:\n                        alt_mask = index_to_modmask(n / map->max_keypermod);\n                        continue;\n                    case XK_Alt_R:\n                        if(alt_mask == 0)\n                            alt_mask = index_to_modmask(n / map->max_keypermod);\n                        continue;\n                    case XK_Meta_L:\n                    case XK_Meta_R:\n                        meta_mask = index_to_modmask(n / map->max_keypermod);\n                        continue;\n                    case XK_Scroll_Lock:\n                        scroll_lock_mask = index_to_modmask(n / map->max_keypermod);\n                        continue;\n                    case XK_Num_Lock:\n                        num_lock_mask = index_to_modmask(n / map->max_keypermod);\n                    default:\n                        continue;\n                }\n            }\n            XFreeModifiermap( map );\n            if ( alt_mask == 0 )\n            {\n                dlog << LWARN << \"Search for Alt-key faild.\";\n                if ( meta_mask != 0 )\n                    alt_mask = meta_mask;\n                else\n                    alt_mask = Mod1Mask; // resort to guessing\n            }\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n\n\n\n\n    } // namespace gui_core_kernel_2_globals\n\n// ----------------------------------------------------------------------------------------\n\n    void canvas::\n    fill (\n        unsigned char red_,\n        unsigned char green_,\n        unsigned char blue_\n    ) const\n    {\n        pixel pixel_value;\n        pixel_value.red = red_;\n        pixel_value.green = green_;\n        pixel_value.blue = blue_;\n        pixel_value._padding = 0;\n\n        pixel* start = reinterpret_cast<pixel*>(bits);\n        pixel* end = start + width_*height_;\n\n        while (start != end)\n        {\n            *start = pixel_value;\n            ++start;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void put_on_clipboard (\n        const std::string& str\n    )\n    {\n        put_on_clipboard(convert_mbstring_to_wstring(str));\n    }\n\n    void put_on_clipboard (\n        const dlib::ustring& str\n    )\n    {\n        put_on_clipboard(convert_utf32_to_wstring(str));\n    }\n\n    void put_on_clipboard (\n        const std::wstring& str\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n\n        std::shared_ptr<event_handler_thread> globals(global_data());\n\n        auto_mutex M(globals->window_table.get_mutex());\n        globals->clipboard = str.c_str();\n\n        XSetSelectionOwner(globals->disp,XA_PRIMARY,globals->exit_window,CurrentTime);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    Bool clip_peek_helper (\n        Display*,\n        XEvent* event,\n        XPointer \n    )\n    {\n        if ( event->type == SelectionNotify)\n        {\n            return True;\n        }\n        else\n        {\n            return False;\n        }\n    }\n\n    void get_from_clipboard (\n        std::string& str\n    )\n    {\n        std::wstring wstr;\n        get_from_clipboard(wstr);\n        str = convert_wstring_to_mbstring(wstr);\n    }\n\n    void get_from_clipboard (\n        dlib::ustring& str\n    )\n    {\n        std::wstring wstr;\n        get_from_clipboard(wstr);\n        str = convert_to_utf32(wstr);\n    }\n\n    void get_from_clipboard (\n        std::wstring& str\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        std::shared_ptr<event_handler_thread> globals(global_data());\n\n        auto_mutex M(globals->window_table.get_mutex());\n        str.clear();\n        unsigned char *data = 0;\n        wchar_t **plist = 0;\n        Window sown;\n        Atom  type;\n        int format, result;\n        unsigned long len, bytes_left, dummy;\n        XEvent e;\n\n        try\n        {\n            Atom atom_ct = XInternAtom(globals->disp, \"COMPOUND_TEXT\", False);\n            sown = XGetSelectionOwner (globals->disp, XA_PRIMARY);\n            if (sown == globals->exit_window)\n            {\n                // if we are copying from ourselfs then don't fool with the Xwindows junk.\n                str = globals->clipboard.c_str();\n            }\n            else if (sown != None)\n            {\n                // request that the selection be copied into the XA_PRIMARY property\n                // of the exit_window.  It doesn't matter what window we put it in \n                // so long as it is one under the control of this process and exit_window\n                // is easy to use here so that is what I'm using.\n                XConvertSelection (globals->disp, XA_PRIMARY, atom_ct, XA_PRIMARY,\n                                   globals->exit_window, CurrentTime);\n\n                // This will wait until we get a SelectionNotify event which should happen\n                // really soon.\n                XPeekIfEvent(globals->disp,&e,clip_peek_helper,0);\n\n                // See how much data we got\n                XGetWindowProperty (globals->disp, globals->exit_window, \n                                    XA_PRIMARY,    // Tricky..\n                                    0, 0,         // offset - len\n                                    0,        // Delete 0==FALSE\n                                    AnyPropertyType,  //flag\n                                    &type,        // return type\n                                    &format,      // return format\n                                    &len, &bytes_left,  //that \n                                    &data);             \n                if (data)\n                {\n                    XFree(data);\n                    data = 0;\n                }\n                if (bytes_left > 0 && type == atom_ct)\n                {\n                    XTextProperty p;\n                    result = XGetWindowProperty (globals->disp, globals->exit_window, \n                                                 XA_PRIMARY, 0,bytes_left,0,\n                                                 AnyPropertyType, &p.encoding,&p.format,\n                                                 &p.nitems, &dummy, &p.value);\n                    if (result == Success && p.encoding == atom_ct)\n                    {\n                        int n;\n                        XwcTextPropertyToTextList(globals->disp, &p, &plist, &n);\n                        str = plist[0];\n                    }\n                    if (plist)\n                    {\n                        XwcFreeStringList(plist);\n                        plist = 0;\n                    }\n                }\n            }\n        }\n        catch (...)\n        {\n            if (data) \n                XFree(data);\n            if (plist)\n            {\n                XwcFreeStringList(plist);\n                plist = 0;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gui_core_kernel_2_globals\n    {\n        void trigger_user_event_threadproc (\n            void*\n        )\n        {\n            std::shared_ptr<event_handler_thread> globals(global_data());\n            auto_mutex M(globals->window_table.get_mutex());\n\n            globals->user_events.lock();\n            globals->user_events.swap(globals->user_events_temp);\n            globals->user_events.unlock();\n\n\n            globals->user_events_temp.reset();\n            // now dispatch all these user events\n            while (globals->user_events_temp.move_next())\n            {\n                base_window** win_ = globals->window_table[globals->user_events_temp.element().w];\n                base_window* win;\n                // if this window exists in the window table then dispatch\n                // its event.\n                if (win_)\n                {\n                    win = *win_;\n                    win->on_user_event(\n                        globals->user_events_temp.element().p,\n                        globals->user_events_temp.element().i\n                    );\n                }\n            }\n            globals->user_events_temp.clear();\n        }\n    }\n\n    void base_window::\n    trigger_user_event (\n        void* p,\n        int i\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        user_event_type e;\n        e.w = x11_stuff.hwnd;\n        e.p = p;\n        e.i = i;\n        {\n            std::shared_ptr<event_handler_thread> globals(global_data());\n            auto_mutex M(globals->user_events.get_mutex());\n            globals->user_events.enqueue(e);\n\n            // we only need to start a thread to deal with this if there isn't already\n            // one out working on the queue\n            if (globals->user_events.size() == 1)\n                create_new_thread (trigger_user_event_threadproc,0);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base_window::\n    base_window (\n        bool resizable_,\n        bool undecorated\n    ) :\n        x11_stuff(*(new gui_core_kernel_2_globals::x11_base_windowstuff)),\n        is_mapped(false),\n        resizable(resizable_),\n        has_been_destroyed(false),\n        has_been_resized(false),\n        has_been_moved(false),\n        wm(gui_core_kernel_2_globals::global_data()->window_table.get_mutex())\n    {\n        DLIB_ASSERT(!(undecorated == true && resizable_ == true),\n            \"\\tbase_window::base_window()\"\n            << \"\\n\\tThere is no such thing as an undecorated window that is resizable by the user.\"\n            << \"\\n\\tthis:     \" << this\n            );\n        using namespace gui_core_kernel_2_globals;\n\n        auto_mutex M(wm);\n\n        x11_stuff.globals = global_data();\n        \n        x11_stuff.last_click_time = 0;\n        last_click_x = 0;\n        last_click_y = 0;\n        last_click_button = NONE;\n\n        XSetWindowAttributes attr;\n        memset(&attr,'\\0',sizeof(attr));\n\n        unsigned long valuemask = 0;\n        if (undecorated)\n        {\n            attr.override_redirect = True;\n            valuemask = CWOverrideRedirect;\n        }\n\n\n        x11_stuff.hwnd = XCreateWindow(\n                        x11_stuff.globals->disp,\n                        DefaultRootWindow(x11_stuff.globals->disp),\n                        0,\n                        0,\n                        10,  // this is the default width of a window\n                        10,  // this is the default width of a window\n                        0,\n                        x11_stuff.globals->depth,\n                        InputOutput,\n                        CopyFromParent,\n                        valuemask,\n                        &attr\n                        );\n\n        x11_stuff.xic = NULL;\n        if (x11_stuff.globals->xim)\n        {\n            XVaNestedList   xva_nlist;\n            XPoint          xpoint;\n\n            char **mlist;\n            int mcount;\n            char *def_str;\n            char fontset[256] = {0};\n            const long native_font_height = 12;\n            snprintf(fontset, sizeof(fontset), \"-*-*-medium-r-normal--%lu-*-*-*-\", native_font_height);\n            x11_stuff.fs = XCreateFontSet(x11_stuff.globals->disp, fontset, &mlist, &mcount, &def_str);\n            xpoint.x = 0;\n            xpoint.y = 0;\n            xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, XNFontSet, x11_stuff.fs, (const void*)NULL);\n            x11_stuff.xic = XCreateIC(\n                x11_stuff.globals->xim,\n                XNInputStyle, x11_stuff.globals->xim_style,\n                XNClientWindow, x11_stuff.hwnd,\n                XNPreeditAttributes, xva_nlist,\n                (const void*)NULL\n                );\n            XFree(xva_nlist);\n            XFreeStringList(mlist);\n        }\n\n        Window temp = x11_stuff.hwnd;\n        base_window* ttemp = this;\n        x11_stuff.globals->window_table.add(temp,ttemp);\n        \n        // query event mask required by input method\n        unsigned long event_xim = 0;\n        if (x11_stuff.xic)\n             XGetICValues( x11_stuff.xic, XNFilterEvents, &event_xim, (const void*)NULL );\n        \n        XSelectInput(\n            x11_stuff.globals->disp,\n            x11_stuff.hwnd,\n            StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask|\n            PointerMotionMask|LeaveWindowMask|EnterWindowMask|KeyPressMask|\n            KeyReleaseMask| FocusChangeMask | event_xim\n            );\n\n        XSetWMProtocols(\n            x11_stuff.globals->disp,\n            x11_stuff.hwnd,\n            &x11_stuff.globals->delete_window,\n            1\n            );\n\n\n        // these are just default values\n        x = 0;\n        y = 0;\n        width = 10;\n        height = 10;\n\n        if (resizable == false)\n        {\n            XSizeHints* hints = XAllocSizeHints();\n            hints->flags = PMinSize|PMaxSize;\n            hints->min_width = width;\n            hints->max_width = width;\n            hints->max_height = height; \n            hints->min_height = height; \n            XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints);\n            XFree(hints);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base_window::\n    ~base_window (\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        close_window();\n\n        if (x11_stuff.globals->xim != NULL)\n        {\n            XDestroyIC(x11_stuff.xic);\n            x11_stuff.xic = 0;\n            XFreeFontSet(x11_stuff.globals->disp,x11_stuff.fs);\n        }\n\n        delete &x11_stuff;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    close_window (\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == false)\n        {\n            has_been_destroyed = true;\n\n            x11_stuff.globals->window_table.destroy(x11_stuff.hwnd);           \n\n            XDestroyWindow(x11_stuff.globals->disp,x11_stuff.hwnd);\n            x11_stuff.hwnd = 0;\n            x11_stuff.globals->window_close_signaler.broadcast();\n        }   \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool base_window::\n    is_closed (\n    ) const\n    {\n        auto_mutex M(wm);\n        return has_been_destroyed;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_title (\n        const std::string& title_\n    )\n    {\n        set_title(convert_mbstring_to_wstring(title_));\n    }\n\n    void base_window::\n    set_title (\n        const ustring& title_\n    )\n    {\n        set_title(convert_utf32_to_wstring(title_));\n    }\n\n    void base_window::\n    set_title (\n        const std::wstring& title_\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        // I'm pretty sure the pointer won't be modified even though\n        // it isn't const anymore.\n        wchar_t *title = const_cast<wchar_t *>(title_.c_str());\n        XTextProperty property;\n        int rc = XwcTextListToTextProperty(x11_stuff.globals->disp,&title,1,XStdICCTextStyle, &property);\n        if (rc >= 0) {\n            XSetWMName(x11_stuff.globals->disp,x11_stuff.hwnd,&property);\n            XFree(property.value);\n            XFlush(x11_stuff.globals->disp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    show (\n    )    \n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        XMapRaised(x11_stuff.globals->disp,x11_stuff.hwnd);\n        XFlush(x11_stuff.globals->disp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    wait_until_closed (\n    ) const\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        while (has_been_destroyed == false)\n            x11_stuff.globals->window_close_signaler.wait();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    hide (\n    )    \n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        XUnmapWindow(x11_stuff.globals->disp,x11_stuff.hwnd);\n        XFlush(x11_stuff.globals->disp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_size (\n        int width_,\n        int height_\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex a(wm);\n        if (has_been_destroyed == true)\n            return;\n\n\n        // do some sanity checking on these values\n        if (width_ < 1)\n            width_ = 1;\n        if (height_ < 1)\n            height_ = 1;\n\n        width = width_;\n        height = height_;\n        has_been_resized = true;\n\n        if (resizable == false)\n        {\n            XSizeHints* hints = XAllocSizeHints();\n            hints->flags = PMinSize|PMaxSize;\n            hints->min_width = width;\n            hints->max_width = width;\n            hints->max_height = height; \n            hints->min_height = height; \n            XSetNormalHints(x11_stuff.globals->disp,x11_stuff.hwnd,hints);\n            XFree(hints);\n        }\n\n        XResizeWindow(x11_stuff.globals->disp,x11_stuff.hwnd,width,height);\n        \n        XFlush(x11_stuff.globals->disp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_pos (\n        long x_,\n        long y_\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex a(wm);\n        if (has_been_destroyed == true)\n            return;\n\n\n        x = x_;\n        y = y_;\n\n        has_been_moved = true;\n\n        XMoveWindow(x11_stuff.globals->disp,x11_stuff.hwnd,x,y);\n        XFlush(x11_stuff.globals->disp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_pos (\n        long& x_,\n        long& y_\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex a(wm);\n        x_ = 0;\n        y_ = 0;\n        if (has_been_destroyed == true)\n            return;\n\n        // we can't really trust the values we have for x and y because some window managers\n        // will have reported bogus values back in the ConfigureNotify event.  So just to be\n        // on the safe side we will use XTranslateCoordinates() \n        int rx, ry;\n        Window desktop_window = DefaultRootWindow(x11_stuff.globals->disp);\n        Window junk;\n        XTranslateCoordinates(x11_stuff.globals->disp,x11_stuff.hwnd,desktop_window,0,0,&rx, &ry, &junk);\n        x_ = rx;\n        y_ = ry;\n        x = rx;\n        y = ry;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_size (\n        unsigned long& width_,\n        unsigned long& height_\n    ) const\n    {\n        auto_mutex M(wm);\n        width_ = 0;\n        height_ = 0;\n        if (has_been_destroyed == true)\n            return;\n\n\n        width_ = width;\n        height_ = height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    get_display_size (\n        unsigned long& width_,\n        unsigned long& height_\n    ) const\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex M(wm);\n        width_ = 0;\n        height_ = 0;\n        if (has_been_destroyed == true)\n            return;\n\n        int screen_number = XScreenNumberOfScreen(x11_stuff.globals->screen);\n        width_ = DisplayWidth(x11_stuff.globals->disp, screen_number);\n        height_ = DisplayHeight(x11_stuff.globals->disp, screen_number);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    invalidate_rectangle (\n        const rectangle& rect\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex a(wm);\n        if (is_mapped == false)\n            return;\n\n        if (rect.is_empty() == false && !has_been_destroyed)\n        {\n            const long x = rect.left();\n            const long y = rect.top();\n            const unsigned long width = rect.width();\n            const unsigned long height = rect.height();\n            \n            XClearArea(x11_stuff.globals->disp,x11_stuff.hwnd,x,y,width,height,1);\n            XFlush(x11_stuff.globals->disp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void base_window::\n    set_im_pos (\n        long x,\n        long y\n    )\n    {\n        using namespace gui_core_kernel_2_globals;\n        auto_mutex a(wm);\n        if (has_been_destroyed == true)\n            return;\n\n        if (!x11_stuff.xic || !(x11_stuff.globals->xim_style & XIMPreeditPosition)) return;\n\n        XVaNestedList   xva_nlist;\n        XPoint          xpoint;\n\n        xpoint.x = x;\n        xpoint.y = y;\n\n        xva_nlist = XVaCreateNestedList(0, XNSpotLocation, &xpoint, (const void*)NULL);\n        XSetICValues(x11_stuff.xic, XNPreeditAttributes, xva_nlist, (const void*)NULL);\n        XFree(xva_nlist);\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_POSIX\n\n#endif // DLIB_GUI_CORE_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/gui_core/gui_core_kernel_2.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEl_2_\n#define DLIB_GUI_CORE_KERNEl_2_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n#ifdef DLIB_NO_GUI_SUPPORT\n#error \"DLIB_NO_GUI_SUPPORT is defined so you can't use the GUI code.  Turn DLIB_NO_GUI_SUPPORT off if you want to use it.\"\n#error \"Also make sure you have libx11-dev installed on your system\"\n#endif\n\n#include <string>\n\n#include \"gui_core_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../threads.h\"\n#include \"../geometry/rectangle.h\"\n#include \"../binary_search_tree.h\"\n#include <string.h>\n#include \"../pixel.h\"\n#include \"../unicode.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace gui_core_kernel_2_globals\n    {\n        class event_handler_thread;\n        void trigger_user_event_threadproc (void*);\n\n        // This is a forward declaration for a struct that contains any \n        // X11 variables.  This allows me to avoid having any dlib header files\n        // include the X11 headers.  Which in turn speeds build times and simplifies\n        // build setups.\n        struct x11_base_windowstuff;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void put_on_clipboard (\n        const std::string& str\n    );\n\n    void put_on_clipboard (\n        const std::wstring& str\n    );\n\n    void put_on_clipboard (\n        const dlib::ustring& str\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void get_from_clipboard (\n        std::string& str\n    );\n\n    void get_from_clipboard (\n        std::wstring& str\n    );\n\n    void get_from_clipboard (\n        dlib::ustring& str\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class canvas : public rectangle\n    {\n    public:\n        struct pixel\n        {\n            unsigned char blue;\n            unsigned char green;\n            unsigned char red;\n        private:\n            friend class canvas;\n            unsigned char _padding;\n        };\n\n        ~canvas() {}\n\n        inline pixel* operator[] (\n            unsigned long row\n        ) const\n        {\n            DLIB_ASSERT(row < height(),\n                \"\\tpixel* canvas::operator[]\"\n                << \"\\n\\tyou have to give a row that is less than the height()\"\n                << \"\\n\\tthis:     \" << this\n                << \"\\n\\trow:      \" << row \n                << \"\\n\\theight(): \" << height() \n                );\n            unsigned char* temp = bits + row_width*row;\n            return reinterpret_cast<pixel*>(temp);\n        }\n\n        void fill (\n            unsigned char red_,\n            unsigned char green_,\n            unsigned char blue_\n        ) const;\n\n    private:\n\n        friend class gui_core_kernel_2_globals::event_handler_thread;\n\n\n        canvas (\n            unsigned char* bits_,\n            unsigned long left_,\n            unsigned long top_,            \n            unsigned long right_,            \n            unsigned long bottom_   \n        ) : \n            rectangle(left_,top_,right_,bottom_),\n            bits(bits_),\n            width_(width()),\n            height_(height()),\n            row_width(width_*4)\n        {}\n\n        // restricted functions\n        canvas();        // normal constructor\n        canvas(canvas&);        // copy constructor\n        canvas& operator=(canvas&);    // assignment operator    \n\n        unsigned char* const bits;\n        const unsigned long width_;\n        const unsigned long height_;\n        const unsigned long row_width;\n    };\n\n    template <>\n    struct pixel_traits<canvas::pixel>\n    {\n        constexpr static bool rgb  = true;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// -----------------\n\n    class base_window\n    {\n        friend class gui_core_kernel_2_globals::event_handler_thread;\n        friend void gui_core_kernel_2_globals::trigger_user_event_threadproc (void*);\n\n    public:\n\n        enum  mouse_state_masks\n        {\n            NONE = 0,\n            LEFT = 1,\n            RIGHT = 2,\n            MIDDLE = 4,\n            SHIFT = 8,\n            CONTROL = 16\n        };\n\n        enum keyboard_state_masks\n        {\n            KBD_MOD_NONE = 0,\n            KBD_MOD_SHIFT = 1,\n            KBD_MOD_CONTROL = 2,\n            KBD_MOD_ALT = 4,\n            KBD_MOD_META = 8,\n            KBD_MOD_CAPS_LOCK = 16,\n            KBD_MOD_NUM_LOCK = 32,\n            KBD_MOD_SCROLL_LOCK = 64\n        };\n\n        enum on_close_return_code\n        {\n            DO_NOT_CLOSE_WINDOW,\n            CLOSE_WINDOW\n        };\n\n        enum non_printable_keyboard_keys\n        {\n            KEY_BACKSPACE,\n            KEY_SHIFT,\n            KEY_CTRL,\n            KEY_ALT,\n            KEY_PAUSE,\n            KEY_CAPS_LOCK,\n            KEY_ESC,\n            KEY_PAGE_UP,\n            KEY_PAGE_DOWN,\n            KEY_END,\n            KEY_HOME,\n            KEY_LEFT,           // This is the left arrow key\n            KEY_RIGHT,          // This is the right arrow key\n            KEY_UP,             // This is the up arrow key\n            KEY_DOWN,           // This is the down arrow key\n            KEY_INSERT,\n            KEY_DELETE,\n            KEY_SCROLL_LOCK,\n  \n            // Function Keys\n            KEY_F1,\n            KEY_F2,\n            KEY_F3,\n            KEY_F4,\n            KEY_F5,\n            KEY_F6,\n            KEY_F7,\n            KEY_F8,\n            KEY_F9,\n            KEY_F10,\n            KEY_F11,\n            KEY_F12\n        };\n\n    private:\n\n        gui_core_kernel_2_globals::x11_base_windowstuff& x11_stuff;\n\n        int x, y, width, height;\n        bool is_mapped;\n\n        const bool resizable;\n        bool has_been_destroyed;\n        bool has_been_resized;  // true if someone called set_size() and the on_window_resized() event \n                                // hasn't yet occurred.\n        bool has_been_moved;    // true if someone called set_pos() and the on_window_moved() event\n                                // hasn't yet occurred.\n\n\n        // The following 3 variables (and x11_stuff.last_click_time) are only accessed from the \n        // event handling loop (except for being initialized below). They record the last \n        // mouse click event details.\n        long last_click_x, last_click_y;\n        unsigned long last_click_button;\n\n\n    protected:\n        const rmutex& wm; \n\n    public:\n\n        base_window (\n            bool resizable_ = true,\n            bool undecorated = false\n        );\n\n        virtual ~base_window (\n        );\n\n        void close_window (\n        );\n\n        void wait_until_closed (\n        ) const;\n\n        void set_im_pos (\n            long x_,\n            long y_\n        );\n\n        bool is_closed (\n        ) const;\n\n        void set_title (\n            const std::string& title_\n        );\n\n        void set_title (\n            const std::wstring& title_\n        );\n\n        void set_title (\n            const dlib::ustring& title_\n        );\n\n        virtual void show (\n        );    \n\n        virtual void hide(\n        );    \n\n        void set_size (\n            int width_,\n            int height_\n        );\n\n        void set_pos (\n            long x_,\n            long y_\n        );\n\n        void get_pos (\n            long& x_,\n            long& y_\n        );\n\n        void get_size (\n            unsigned long& width_,\n            unsigned long& height_\n        ) const;\n\n        void get_display_size (\n            unsigned long& width,\n            unsigned long& height\n        ) const;\n\n        void invalidate_rectangle (\n            const rectangle& rect\n        );\n\n        void trigger_user_event (\n            void* p,\n            int i\n        );\n\n    protected:\n\n        virtual on_close_return_code on_window_close(\n        ){return CLOSE_WINDOW;}\n\n        virtual void on_window_resized(\n        ){}\n\n        virtual void on_window_moved(\n        ){}\n        virtual void on_user_event (\n            void* ,\n            int \n        ){}\n\n        virtual void on_mouse_down (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long ,\n            bool \n        ){}\n\n        virtual void on_mouse_up (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_move (\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_leave (\n        ){}\n\n        virtual void on_mouse_enter (\n        ){}\n\n        virtual void on_wheel_up (\n            unsigned long \n        ){}\n\n        virtual void on_wheel_down (\n            unsigned long \n        ){}\n\n        virtual void on_focus_gained (\n        ){}\n\n        virtual void on_focus_lost (\n        ){}\n\n        virtual void on_keydown (\n            unsigned long ,            \n            bool ,\n            unsigned long \n        ){}\n\n        virtual void on_string_put (\n            const std::wstring&\n        ){}\n\n    private:\n\n        virtual void paint (\n            const canvas& c\n        ) =0;\n\n\n\n        base_window(base_window&);        // copy constructor\n        base_window& operator=(base_window&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n\n}\n\n\n#ifdef NO_MAKEFILE\n#include \"gui_core_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_GUI_CORE_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/gui_core/gui_core_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GUI_CORE_KERNEl_ABSTRACT_\n#ifdef DLIB_GUI_CORE_KERNEl_ABSTRACT_\n\n#include <string>\n#include \"../algs.h\"\n#include \"../geometry/rectangle_abstract.h\"\n#include \"../unicode/unicode_abstract.h\"\n\nnamespace dlib\n{\n\n    /*!\n        OVERVIEW:\n            This is a set of objects and functions which provide a very basic\n            framework for manipulating windows.  It is intended to provide a \n            portable interface which can be used to build a more complex windowing \n            toolkit.\n\n        EXCEPTIONS\n            Do not let an exception leave any of the base_window event handlers. \n            The results of doing so are undefined.\n\n        THREAD SAFETY\n            Event Handlers\n                All event handlers are executed in a special event handling thread. \n                This means that you must not do anything that will take a long time or\n                block while in an event handler.  Doing so will freeze all event \n                processing.  \n                \n                Also, don't rely on get_thread_id() always returning the same ID from\n                inside event handlers.\n\n            canvas\n                Never access a canvas object outside of the paint() callback\n                that supplied it.  Only access a canvas object from the event \n                handling thread.  After the paint() event handler has returned do \n                not access that canvas object again.\n\n            base_window\n                All methods for this class are thread safe.  You may call them \n                from any thread and do not need to serialize access.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void put_on_clipboard (\n        const std::string& str\n    );\n    /*!\n        ensures\n            - posts the contents of str to the system clipboard\n        throws\n            - std::bad_alloc\n            - dlib::gui_error\n            - dlib::thread_error\n    !*/\n\n    // overloads for wide character strings\n    void put_on_clipboard (const std::wstring& str);\n    void put_on_clipboard (const dlib::ustring& str);\n\n// ----------------------------------------------------------------------------------------\n\n    void get_from_clipboard (\n        std::string& str\n    );\n    /*!\n        ensures\n            - if (there is string data on the system clipboard) then\n                - #str == the data from the clipboard\n            - else\n                - #str == \"\"\n        throws\n            - std::bad_alloc\n            - dlib::gui_error\n            - dlib::thread_error\n    !*/\n\n    // overloads for wide character strings\n    void get_from_clipboard (std::wtring& str);\n    void get_from_clipboard (dlib::utring& str);\n\n// ----------------------------------------------------------------------------------------\n\n\n    class canvas : public rectangle\n    {\n        /*!\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                All functions of this object may invalidate pointers and references\n                to internal data.  \n\n            INITIAL VALUE\n                The initial value of each pixel is undefined.  \n                is_empty() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a rectangular area of a window that you \n                can draw on. \n\n                Each pixel can be accessed with the following syntax:\n                    canvas_instance[y][x].red   == the red value for this pixel\n                    canvas_instance[y][x].blue  == the blue value for this pixel\n                    canvas_instance[y][x].green == the green value for this pixel\n\n                The origin, i.e. (0,0), of the x,y coordinate plane of the canvas is in \n                the upper left corner of the canvas.  Note that the upper left corner \n                of the canvas appears at the point (left(),top()) in its window.\n        !*/\n\n    public:\n\n        struct pixel\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a single pixel.  Each pixel's value\n                    ranges from 0 to 255 with 0 indicating that the color is not\n                    present in the pixel at all and 255 indicating that the color\n                    is present in the pixel with maximum intensity.\n\n                    Note that the structure, order, and size of this struct are \n                    implementation dependent.  It will always contain fields called \n                    red, green, and blue but they may not be in that order and there \n                    may be padding.  \n\n                    Also note that pixel_traits<> is defined for this pixel type,\n                    thus you can use it in assign_pixel() calls.\n            !*/\n            unsigned char red;\n            unsigned char green;\n            unsigned char blue;\n        };\n\n\n        pixel* operator[] (\n            unsigned long row\n        ) const;\n        /*!\n            requires\n                - row < height()\n            ensures\n                - returns an array of width() pixel structs that represents the given\n                  row of pixels in the canvas.  \n        !*/\n\n        void fill (\n            unsigned char red,\n            unsigned char green,\n            unsigned char blue\n        ) const;\n        /*!\n            ensures\n                - for all valid values of x and y:\n                    - (#*this)[y][x].red = red\n                    - (#*this)[y][x].green = green\n                    - (#*this)[y][x].blue = blue\n        !*/\n            \n    private:\n\n        // restricted functions\n        canvas();        // normal constructor\n        canvas(canvas&);        // copy constructor\n        canvas& operator=(canvas&);    // assignment operator    \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class base_window\n    {\n\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a window on the desktop.  A window has a \"client \n                area\" that is a region of the screen that you can draw whatever you like \n                on.  You implement the paint() callback and use the canvas object to do \n                this drawing.\n\n            INITIAL STATE\n                - The initial state of the window is to be hidden.  This means you need\n                  to call show() to make it appear.\n                - is_closed() == false\n\n            paint() callback:\n                This is where you will do all your drawing.  It is triggered when\n                part of the window needs to be drawn/redrawn.\n\n            mouse events:\n                It is important to note a few things about the mouse events.  First,\n                the on_mouse_move() event is not triggered for each pixel the mouse crosses\n                but rather its frequency and precision is implementation dependent.  \n                \n                Second, it is possible that a mouse button may be depressed but the \n                corresponding button release event does not go to the window.  For instance, \n                if the mouse is outside the window and some other application jumps to the \n                top it is possible that the new application will receive any mouse button \n                release events rather than the original window.  But the point is that \n                you should not rely on always getting a button up event for every button\n                down event.\n\n            keydown event:\n                Note that the existence of a typematic action (holding down a key\n                and having it start to repeat itself after a moment) for each key is\n                totally implementation dependent.  So don't rely on it for any key\n                and conversely don't assume it isn't present either.  \n\n            The base_window::wm mutex\n                This is a reference to a global rmutex.  All instances of base_window make\n                reference to the same global rmutex.  It is used to synchronize access to \n                the base_window to make it thread safe.  It is also always locked before \n                an event handler is called.\n        !*/\n\n    public:\n\n        enum on_close_return_code\n        {\n            DO_NOT_CLOSE_WINDOW,\n            CLOSE_WINDOW\n        };\n\n        enum mouse_state_masks\n        {\n            /*!\n                These constants represent the various buttons referenced by\n                mouse events.\n            !*/\n            NONE = 0,\n            LEFT = 1,\n            RIGHT = 2,\n            MIDDLE = 4,\n            SHIFT = 8,\n            CONTROL = 16\n        };\n\n        enum keyboard_state_masks\n        {\n            /*!\n                These constants represent the various modifier buttons that\n                could be in effect during a key press on the keyboard\n            !*/\n            KBD_MOD_NONE = 0,\n            KBD_MOD_SHIFT = 1,\n            KBD_MOD_CONTROL = 2,\n            KBD_MOD_ALT = 4,\n            KBD_MOD_META = 8,\n            KBD_MOD_CAPS_LOCK = 16,\n            KBD_MOD_NUM_LOCK = 32,\n            KBD_MOD_SCROLL_LOCK = 64\n        };\n\n        enum non_printable_keyboard_keys\n        {\n            KEY_BACKSPACE,\n            KEY_SHIFT,\n            KEY_CTRL,\n            KEY_ALT,\n            KEY_PAUSE,\n            KEY_CAPS_LOCK,\n            KEY_ESC,\n            KEY_PAGE_UP,\n            KEY_PAGE_DOWN,\n            KEY_END,\n            KEY_HOME,\n            KEY_LEFT,           // This is the left arrow key\n            KEY_RIGHT,          // This is the right arrow key\n            KEY_UP,             // This is the up arrow key\n            KEY_DOWN,           // This is the down arrow key\n            KEY_INSERT,\n            KEY_DELETE,\n            KEY_SCROLL_LOCK,\n  \n            // Function Keys\n            KEY_F1,\n            KEY_F2,\n            KEY_F3,\n            KEY_F4,\n            KEY_F5,\n            KEY_F6,\n            KEY_F7,\n            KEY_F8,\n            KEY_F9,\n            KEY_F10,\n            KEY_F11,\n            KEY_F12\n        };\n\n        base_window (\n            bool resizable = true,\n            bool undecorated = false\n        );\n        /*!\n            requires\n                - if (undecorated == true) then\n                    - resizable == false\n            ensures\n                - #*this has been properly initialized \n                - if (resizable == true) then \n                    - this window will be resizable by the user\n                - else \n                    - this window will not be resizable by the user\n                - if (undecorated == true) then\n                    - this window will not have any graphical elements outside\n                      of its drawable area or appear in the system task bar. It\n                      also won't take the input focus from other windows.\n                      (it is suitable for making things such as popup menus)\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n                - dlib::gui_error\n                    This exception is thrown if there is an error while \n                    creating this window.\n        !*/\n\n        virtual ~base_window (\n        );\n        /*!\n            ensures\n                - does NOT trigger the on_window_close() event\n                - all resources associated with *this have been released                \n                - closes this window\n        !*/\n\n        void close_window (\n        );\n        /*!\n            ensures\n                - #is_closed() == true\n                  (i.e. permanently closes this window.  The window is removed from the \n                  screen and no more events will be dispatched to this window. )\n                - does NOT trigger the on_window_close() event\n        !*/\n\n        void wait_until_closed (\n        ) const;\n        /*!\n            ensures\n                - blocks until is_closed() == true \n        !*/\n\n        bool is_closed (\n        ) const;\n        /*!\n            ensures\n                - returns true if this window has been closed, false otherwise.\n                  (Note that closed windows do not receive any callbacks at all.\n                   They are also not visible on the screen.)\n        !*/\n\n        void set_title (\n            const std::string& title\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - sets the title of the window\n        !*/\n\n        void set_title (\n            const std::wstring& title\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - sets the title of the window\n        !*/\n\n        void set_title (\n            const dlib::ustring& title\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - sets the title of the window\n        !*/\n\n        virtual void show (\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - this window will appear on the screen\n        !*/\n\n        virtual void hide(\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - the window does not appear on the screen\n        !*/\n\n        void set_size (\n            int width,\n            int height\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - The width of the client area of this window is at least width\n                      pixels.\n                    - The height of the client area of this window is at least height\n                      pixels.\n                    - if (the window wasn't already this size) then\n                        - triggers the on_window_resized() callback\n        !*/\n\n        void set_pos (\n            long x,\n            long y\n        );\n        /*!\n            ensures \n                - if (is_closed() == false) then\n                    - sets the upper left corner of this window to the position (x,y) \n                      on the desktop.  Note that the origin (0,0) is at the upper left\n                      corner of the desktop.\n        !*/\n\n        void get_pos (\n            long& x,\n            long& y\n        ) const;\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - #x == the x coordinate of the upper left corner of the client area of\n                      this window.\n                    - #y == the y coordinate of the upper left corner of the client area of\n                      this window.\n                    - i.e. the point (#x,#y) on the desktop is coincident with the point\n                      (0,0) in the client area of this window.\n                - else\n                    - #x == 0\n                    - #y == 0\n        !*/\n\n        void get_size (\n            unsigned long& width,\n            unsigned long& height\n        ) const;\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - #width == the width of the client area of this window in pixels\n                    - #height == the height of the client area of this window in pixels\n                - else\n                    - #width == 0\n                    - #height == 0\n        !*/\n\n        void get_display_size (\n            unsigned long& width,\n            unsigned long& height\n        ) const;\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - #width == the width in pixels of the display device that contains this window \n                    - #height == the height in pixels of the display device that contains this window \n                - else\n                    - #width == 0\n                    - #height == 0\n        !*/\n\n        void invalidate_rectangle (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - causes the area of this window defined by rect to become invalid.\n                      This means that a paint() message will be dispatched to repaint\n                      this area of the window.  Note that it is possible that the \n                      resulting paint() message may include a bigger rectangle than\n                      the one defined by rect.\n        !*/\n\n        void trigger_user_event (\n            void* p,\n            int i\n        );\n        /*!\n            ensures\n                - will never block (even if some other thread has a lock on the\n                  global mutex referenced by wm.)\n                - if (is_closed() == false) then\n                    - causes the on_user_event() event to be called with \n                      the given arguments.\n        !*/\n\n        void set_im_pos (\n            long x_,\n            long y_\n        );\n        /*!\n            ensures\n                - if (is_closed() == false) then\n                    - sets the left-top position of input method rectangle used\n                      for wide character input methods.\n        !*/\n\n    protected:\n        const rmutex& wm;\n\n        // let the window close by default\n        virtual on_close_return_code on_window_close(\n        ){return CLOSE_WINDOW;}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the user attempts to close this window\n                - if (this function returns CLOSE_WINDOW) then\n                    - #is_closed() == true  (i.e. this window will be closed)\n                    - it is safe to call \"delete this;\" inside on_window_close() \n                      if *this was allocated on the heap and no one will try to \n                      access *this anymore.\n                - else\n                    - this window will not be closed and the attempt to close it\n                      by the user will have no effect. \n                    - #is_closed() == false\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_user_event (\n            void* p,\n            int i\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called whenever someone calls trigger_user_event()\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_window_resized(\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when this window is resized\n            ensures\n                - does not change the state of mutex wm\n        !*/\n             \n        // do nothing by default\n        virtual void on_window_moved(\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when this window's position changes \n            ensures\n                - does not change the state of mutex wm\n        !*/\n             \n        // do nothing by default  \n        virtual void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the user depresses one of the mouse buttons\n                - btn == the button that was depressed. (either LEFT, MIDDLE, or RIGHT)\n                - state == the bitwise OR of the buttons that are currently depressed \n                  excluding the button given by btn. (from the mouse_state_masks enum) \n                - (x,y) == the position of the mouse (relative to the upper left corner\n                  of the window) when this event occurred.  Note that the mouse may be\n                  outside the window.\n                - if (this is the second button press of a double click) then\n                    - is_double_click == true\n                - else\n                    - is_double_click == false\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the user releases one of the mouse buttons\n                - btn == the button that was released. (either LEFT, MIDDLE, or RIGHT)\n                - state == the bitwise OR of the buttons that are currently depressed\n                  (from the mouse_state_masks enum)\n                - (x,y) == the position of the mouse (relative to the upper left corner\n                  of the window) when this event occurred.  Note that the mouse may be\n                  outside the window.\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the user moves the mouse\n                - state == the bitwise OR of the buttons that are currently depressed\n                  (from the mouse_state_masks enum)\n                - (x,y) == the position of the mouse (relative to the upper left corner\n                  of the window) when this event occurred. \n                - if (the user is holding down one or more of the mouse buttons) then\n                    - the mouse move events will continue to track the mouse even if\n                      it goes out of the window.  This will continue until the user\n                      releases all the mouse buttons.\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_mouse_leave (\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the mouse leaves this window\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_mouse_enter (\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when the mouse enters this window\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_focus_gained (\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when this window gains input focus \n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_focus_lost (\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when this window loses input focus \n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_wheel_up (\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called every time the mouse wheel is scrolled up one notch\n                - state == the bitwise OR of the buttons that are currently depressed \n                  (from the mouse_state_masks enum) \n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_wheel_down (\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called every time the mouse wheel is scrolled down one notch\n                - state == the bitwise OR of the buttons that are currently depressed \n                  (from the mouse_state_masks enum) \n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        // do nothing by default\n        virtual void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when a keyboard key is pressed or if a key is held\n                  down then this is called repeatedly at a certain rate once the\n                  typematic action begins (note that some keys might not have any \n                  typematic action on some platforms).\n                - if (is_printable) then\n                    - key == the character that was pressed. (e.g. 'a', 'b', '1' etc.)\n                    - this is a printable character.  Note that ' ', '\\t', and \n                      '\\n' (this is the return/enter key) are all considered printable.\n                - else\n                    - key == one of the non_printable_keyboard_keys enums.  \n                - state == the bitwise OR of the keyboard modifiers that are currently\n                  depressed (taken from keyboard_state_masks).  \n                - if (key is not in the range 'a' to 'z' or 'A' to 'Z') then\n                    - if (the shift key was down when this key was pressed) then                    \n                        - (state & KBD_MOD_SHIFT) != 0 \n                    - else\n                        - (state & KBD_MOD_SHIFT) == 0 \n                - else\n                    - the state of the shift key is implementation defined\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        virtual void on_string_put (\n            const std::wstring &str\n        ){}\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when a wide/multibyte character input method determines a string\n                  that is being input to the window.\n                - str == the string that is being input\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n    private:\n\n        virtual void paint (\n            const canvas& c\n        ) =0;\n        /*!\n            requires\n                - is_closed() == false\n                - mutex wm is locked\n                - is called when part of the window needs to be repainted for \n                  any reason.\n                - c == a canvas object that represents the invalid area of this\n                  window which needs to be painted.\n            ensures\n                - does not change the state of mutex wm\n        !*/\n\n        base_window(base_window&);        // copy constructor\n        base_window& operator=(base_window&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GUI_CORE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/gui_core/windows.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEl_2_\n#include \"gui_core_kernel_1.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/gui_core/xlib.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORE_KERNEl_1_\n#include \"gui_core_kernel_2.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/gui_core.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GUI_CORe_\n#define DLIB_GUI_CORe_\n\n\n#include \"platform.h\"\n\n\n\n#ifdef WIN32\n#include \"gui_core/windows.h\"\n#else\n#include \"gui_core/xlib.h\"\n#endif\n\n\n\n#endif // DLIB_GUI_CORe_\n\n"
  },
  {
    "path": "dlib/gui_widgets/base_widgets.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BASE_WIDGETs_CPP_\n#define DLIB_BASE_WIDGETs_CPP_\n\n#include <iostream>\n#include <memory>\n\n#include \"base_widgets.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // button object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle min_rect = style->get_min_size(name_,*mfont);\n        // only change the size if it isn't going to be too small to fit the name\n        if (height >= min_rect.height() &&\n            width >= min_rect.width())\n        {\n            rectangle old(rect);\n            rect = resize_rect(rect,width,height);\n            parent.invalidate_rectangle(style->get_invalidation_rect(rect+old));\n            btn_tooltip.set_size(width,height);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    show (\n    )\n    {\n        button_action::show();\n        btn_tooltip.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    hide (\n    )\n    {\n        button_action::hide();\n        btn_tooltip.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    enable (\n    )\n    {\n        button_action::enable();\n        btn_tooltip.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    disable (\n    )\n    {\n        button_action::disable();\n        btn_tooltip.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_tooltip_text (\n        const std::string& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_tooltip_text (\n        const std::wstring& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_tooltip_text (\n        const ustring& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string button::\n    tooltip_text (\n    ) const\n    {\n        return btn_tooltip.text();\n    }\n\n    const std::wstring button::\n    tooltip_wtext (\n    ) const\n    {\n        return btn_tooltip.wtext();\n    }\n\n    const dlib::ustring button::\n    tooltip_utext (\n    ) const\n    {\n        return btn_tooltip.utext();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        set_name(name_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        button_action::set_pos(x,y);\n        btn_tooltip.set_pos(x,y);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    set_name (\n        const std::string& name\n    )\n    {\n        set_name(convert_mbstring_to_wstring(name));\n    }\n\n    void button::\n    set_name (\n        const std::wstring& name\n    )\n    {\n        set_name(convert_to_utf32(name));\n    }\n\n    void button::\n    set_name (\n        const ustring& name\n    )\n    {\n        auto_mutex M(m);\n        name_ = name;\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        name_[0] = name_[0];\n\n        rectangle old(rect);\n        rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top());\n        btn_tooltip.set_size(rect.width(),rect.height());\n        \n        parent.invalidate_rectangle(style->get_invalidation_rect(rect+old));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string button::\n    name (\n    ) const\n    {\n        auto_mutex M(m);\n        std::string temp = convert_wstring_to_mbstring(wname());\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        char c = temp[0];\n        temp[0] = c;\n        return temp;\n    }\n\n    const std::wstring button::\n    wname (\n    ) const\n    {\n        auto_mutex M(m);\n        std::wstring temp = convert_utf32_to_wstring(uname());\n        // do this to get rid of any reference counting that may be present in \n        // the std::wstring implementation.\n        wchar_t w = temp[0];\n        temp[0] = w;\n        return temp;\n    }\n\n    const dlib::ustring button::\n    uname (\n    ) const\n    {\n        auto_mutex M(m);\n        dlib::ustring temp = name_;\n        // do this to get rid of any reference counting that may be present in \n        // the dlib::ustring implementation.\n        temp[0] = name_[0];\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    on_button_up (\n        bool mouse_over\n    )\n    {\n        if (mouse_over)                \n        {\n            // this is a valid button click\n            if (event_handler.is_set())\n                event_handler();\n            if (event_handler_self.is_set())\n                event_handler_self(*this);\n        }\n        if (button_up_handler.is_set())\n            button_up_handler(mouse_over);\n        if (button_up_handler_self.is_set())\n            button_up_handler_self(mouse_over,*this);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button::\n    on_button_down (\n    )\n    {\n        if (button_down_handler.is_set())\n            button_down_handler();\n        if (button_down_handler_self.is_set())\n            button_down_handler_self(*this);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // draggable object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    draggable::~draggable() {}\n\n// ----------------------------------------------------------------------------------------\n\n    void draggable::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (drag && (state & base_window::LEFT) && enabled && !hidden)\n        {\n            // the user is trying to drag this object.  we should calculate the new\n            // x and y positions for the upper left corner of this object's rectangle\n\n            long new_x = x - this->x;\n            long new_y = y - this->y;\n\n            // make sure these points are inside the draggable area.  \n            if (new_x < area.left())\n                new_x = area.left();\n            if (new_x + static_cast<long>(rect.width()) - 1 > area.right())\n                new_x = area.right() - rect.width() + 1;\n\n            if (new_y + static_cast<long>(rect.height()) - 1 > area.bottom())\n                new_y = area.bottom() - rect.height() + 1;\n            if (new_y < area.top())\n                new_y = area.top();\n\n            // now make the new rectangle for this object\n            rectangle new_rect(\n                new_x,\n                new_y,\n                new_x + rect.width() - 1,\n                new_y + rect.height() - 1\n            );\n\n            // only do anything if this is a new rectangle and it is inside area\n            if (new_rect != rect && area.intersect(new_rect) == new_rect)\n            {\n                parent.invalidate_rectangle(new_rect + rect);\n                rect = new_rect;\n\n                // call the on_drag() event handler\n                on_drag();\n            }\n        }\n        else\n        {\n            drag = false;\n            on_drag_stop();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void draggable::\n    on_mouse_up (\n        unsigned long ,\n        unsigned long state,\n        long ,\n        long \n    )\n    {\n        if (drag && (state & base_window::LEFT) == 0)\n        {\n            drag = false;\n            on_drag_stop();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void draggable::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool \n    )\n    {\n        if (enabled && !hidden && rect.contains(x,y) && btn == base_window::LEFT)\n        {\n            drag = true;\n            this->x = x - rect.left();\n            this->y = y - rect.top();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // mouse_over_event object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    mouse_over_event::~mouse_over_event() {}\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_over_event::\n    on_mouse_leave (\n    )\n    {\n        if (is_mouse_over_)\n        {\n            is_mouse_over_ = false;\n            on_mouse_not_over();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_over_event::\n    on_mouse_move (\n        unsigned long ,\n        long x,\n        long y\n    )\n    {\n        if (rect.contains(x,y) == false)\n        {\n            if (is_mouse_over_)\n            {\n                is_mouse_over_ = false;\n                on_mouse_not_over();\n            }\n        }\n        else if (is_mouse_over_ == false)\n        {\n            is_mouse_over_ = true;\n            if (enabled && !hidden)\n                on_mouse_over();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool mouse_over_event::\n    is_mouse_over (\n    ) const\n    {\n        // check if the mouse is still really over this button\n        if (is_mouse_over_ && rect.contains(lastx,lasty) == false)\n        {\n            // trigger a user event to call on_mouse_not_over() and repaint this object.\n            // we must do this in another event because someone might call is_mouse_over()\n            // from draw() and you don't want this function to end up calling \n            // parent.invalidate_rectangle().  It would lead to draw() being called over\n            // and over.\n            parent.trigger_user_event((void*)this,drawable::next_free_user_event_number());\n            return false;\n        }\n\n        return is_mouse_over_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_over_event::\n    on_user_event (\n        int num \n    )\n    {\n        if (is_mouse_over_ && num == drawable::next_free_user_event_number())\n        {\n            is_mouse_over_ = false;\n            on_mouse_not_over();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // button_action object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    button_action::~button_action() {}\n\n// ----------------------------------------------------------------------------------------\n\n    void button_action::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool\n    )\n    {\n        if (enabled && !hidden && btn == base_window::LEFT && rect.contains(x,y))\n        {\n            is_depressed_ = true;\n            seen_click = true;\n            parent.invalidate_rectangle(rect);\n            on_button_down();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button_action::\n    on_mouse_not_over (\n    )\n    {\n        if (is_depressed_)\n        {\n            is_depressed_ = false;\n            parent.invalidate_rectangle(rect);\n            on_button_up(false);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button_action::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        // forward event to the parent class so it can do it's thing as well as us\n        mouse_over_event::on_mouse_move(state,x,y);\n\n        if (enabled == false || hidden == true)\n            return;\n\n\n        if ((state & base_window::LEFT) == 0)\n        {\n            seen_click = false;\n            if (is_depressed_)\n            {\n                is_depressed_ = false;\n                parent.invalidate_rectangle(rect);\n                on_button_up(false);\n            }\n\n            // the left button isn't down so we don't care about anything else\n            return;\n        }\n\n        if (rect.contains(x,y) == false)\n        {\n            if (is_depressed_)\n            {\n                is_depressed_ = false;\n                parent.invalidate_rectangle(rect);\n                on_button_up(false);\n            }\n        }\n        else if (is_depressed_ == false && seen_click)\n        {\n            is_depressed_ = true;\n            parent.invalidate_rectangle(rect);\n            on_button_down();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button_action::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long,\n        long x,\n        long y\n    )\n    {\n        if (enabled && !hidden && btn == base_window::LEFT)\n        {\n            if (is_depressed_)\n            {\n                is_depressed_ = false;\n                parent.invalidate_rectangle(rect);\n\n                if (rect.contains(x,y))                \n                {\n                    on_button_up(true);\n                }\n                else\n                {\n                    on_button_up(false);\n                }\n            }\n            else if (seen_click && rect.contains(x,y))\n            {\n                // this case here covers the unlikly event that you click on a button,\n                // move the mouse off the button and then move it back very quickly and\n                // release the mouse button.   It is possible that this mouse up event\n                // will occur before any mouse move event so you might not have set\n                // that the button is depressed yet.\n                \n                // So we should say that this triggers an on_button_down() event and\n                // then an on_button_up(true) event.\n\n                parent.invalidate_rectangle(rect);\n\n                on_button_down();\n                on_button_up(true);\n            }\n\n            seen_click = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool button_action::\n    is_depressed (\n    ) const\n    {\n        // check if the mouse is still really over this button\n        if (enabled && !hidden && is_depressed_ && rect.contains(lastx,lasty) == false)\n        {\n            // trigger a user event to call on_button_up() and repaint this object.\n            // we must do this in another event because someone might call is_depressed()\n            // from draw() and you don't want this function to end up calling \n            // parent.invalidate_rectangle().  It would lead to draw() being called over\n            // and over.\n            parent.trigger_user_event((void*)this,mouse_over_event::next_free_user_event_number());\n            return false;\n        }\n\n        return is_depressed_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void button_action::\n    on_user_event (\n        int num\n    )\n    {\n        // forward event to the parent class so it can do it's thing as well as us\n        mouse_over_event::on_user_event(num);\n\n        if (is_depressed_ && num == mouse_over_event::next_free_user_event_number())\n        {\n            is_depressed_ = false;\n            parent.invalidate_rectangle(rect);\n            on_button_up(false);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scroll_bar object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    scroll_bar::\n    scroll_bar(  \n        drawable_window& w,\n        bar_orientation orientation \n    ) :\n        drawable(w),\n        b1(w),\n        b2(w),\n        slider(w,*this,&scroll_bar::on_slider_drag),\n        ori(orientation),\n        top_filler(w,*this,&scroll_bar::top_filler_down,&scroll_bar::top_filler_up),\n        bottom_filler(w,*this,&scroll_bar::bottom_filler_down,&scroll_bar::bottom_filler_up),\n        pos(0),\n        max_pos(0),\n        js(10),\n        b1_timer(*this,&scroll_bar::b1_down_t),\n        b2_timer(*this,&scroll_bar::b2_down_t),\n        top_filler_timer(*this,&scroll_bar::top_filler_down_t),\n        bottom_filler_timer(*this,&scroll_bar::bottom_filler_down_t)\n    {\n        set_style(scroll_bar_style_default());\n\n        // don't show the slider when there is no place it can move.\n        slider.hide();\n\n        set_length(100);\n\n        b1.set_button_down_handler(*this,&scroll_bar::b1_down);\n        b2.set_button_down_handler(*this,&scroll_bar::b2_down);\n\n        b1.set_button_up_handler(*this,&scroll_bar::b1_up);\n        b2.set_button_up_handler(*this,&scroll_bar::b2_up);\n        b1.disable();\n        b2.disable();\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    scroll_bar::\n    ~scroll_bar(\n    )\n    {\n        disable_events();\n        parent.invalidate_rectangle(rect); \n        // wait for all the timers to be stopped\n        b1_timer.stop_and_wait();\n        b2_timer.stop_and_wait();\n        top_filler_timer.stop_and_wait();\n        bottom_filler_timer.stop_and_wait();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    scroll_bar::bar_orientation scroll_bar::\n    orientation (\n    ) const\n    {\n        auto_mutex M(m);\n        return ori;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    void scroll_bar::\n    set_length (\n        unsigned long length\n    )\n    {\n        auto_mutex M(m);\n        // make the min length be at least 1\n        if (length == 0)\n        {\n            length = 1;\n        }\n\n\n        parent.invalidate_rectangle(rect);\n\n        if (ori == HORIZONTAL)\n        {\n            rect.set_right(rect.left() + length - 1);\n            rect.set_bottom(rect.top() + style->get_width() - 1);\n\n            const long btn_size = style->get_button_length(rect.width(), max_pos);\n\n            b1.set_size(btn_size,style->get_width());\n            b2.set_size(btn_size,style->get_width());\n\n            slider.set_size(get_slider_size(),style->get_width());\n        }\n        else\n        {\n            rect.set_right(rect.left() + style->get_width() - 1);\n            rect.set_bottom(rect.top() + length - 1);\n\n            const long btn_size = style->get_button_length(rect.height(), max_pos);\n\n            b1.set_size(style->get_width(),btn_size);\n            b2.set_size(style->get_width(),btn_size);\n\n            slider.set_size(style->get_width(),get_slider_size());\n        }\n\n        // call this to put everything is in the right spot.\n        set_pos (rect.left(),rect.top());\n\n        if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || \n            (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || \n            max_pos == 0)\n        {\n            hide_slider();\n        }\n        else if (enabled && !hidden)\n        {\n            show_slider();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        drawable::set_pos(x,y);\n\n        b1.set_pos(rect.left(),rect.top());\n        if (ori == HORIZONTAL)\n        {\n            // make the b2 button appear at the end of the scroll_bar\n            b2.set_pos(rect.right()-b2.get_rect().width() + 1,rect.top());\n\n            if (max_pos != 0)\n            {\n                double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1;\n                double slider_pos = pos;\n                slider_pos /= max_pos;\n                slider_pos *= range;\n                slider.set_pos(\n                    static_cast<long>(slider_pos)+rect.left() + b1.get_rect().width(),\n                    rect.top()\n                    );\n\n                // move the draggable area for the slider to the new location\n                rectangle area = rect;\n                area.set_left(area.left() + style->get_width());\n                area.set_right(area.right() - style->get_width());\n                slider.set_draggable_area(area);\n\n            }\n\n            \n        }\n        else\n        {\n            // make the b2 button appear at the end of the scroll_bar\n            b2.set_pos(rect.left(), rect.bottom() - b2.get_rect().height() + 1);\n\n            if (max_pos != 0)\n            {\n                double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1;\n                double slider_pos = pos;\n                slider_pos /= max_pos;\n                slider_pos *= range;\n                slider.set_pos(\n                    rect.left(), \n                    static_cast<long>(slider_pos) + rect.top() + b1.get_rect().height()\n                    );\n\n                // move the draggable area for the slider to the new location\n                rectangle area = rect;\n                area.set_top(area.top() + style->get_width());\n                area.set_bottom(area.bottom() - style->get_width());\n                slider.set_draggable_area(area);\n            }\n        }\n\n        adjust_fillers();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long scroll_bar::\n    get_slider_size (\n    ) const\n    {\n        if (ori == HORIZONTAL)\n            return style->get_slider_length(rect.width(),max_pos);\n        else\n            return style->get_slider_length(rect.height(),max_pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    adjust_fillers (\n    )\n    {\n        rectangle top(rect), bottom(rect);\n\n        if (ori == HORIZONTAL)\n        {\n            if (slider.is_hidden())\n            {\n                top.set_left(b1.get_rect().right()+1);\n                top.set_right(b2.get_rect().left()-1);\n                bottom.set_left(1);\n                bottom.set_right(-1);\n            }\n            else\n            {\n                top.set_left(b1.get_rect().right()+1);\n                top.set_right(slider.get_rect().left()-1);\n                bottom.set_left(slider.get_rect().right()+1);\n                bottom.set_right(b2.get_rect().left()-1);\n            }\n        }\n        else\n        {\n            if (slider.is_hidden())\n            {\n                top.set_top(b1.get_rect().bottom()+1);\n                top.set_bottom(b2.get_rect().top()-1);\n                bottom.set_top(1);\n                bottom.set_bottom(-1);\n            }\n            else\n            {\n                top.set_top(b1.get_rect().bottom()+1);\n                top.set_bottom(slider.get_rect().top()-1);\n                bottom.set_top(slider.get_rect().bottom()+1);\n                bottom.set_bottom(b2.get_rect().top()-1);\n            }\n        }\n\n        top_filler.rect = top;\n        bottom_filler.rect = bottom;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    hide_slider (\n    )\n    {\n        rectangle top(rect), bottom(rect);\n        slider.hide();\n        top_filler.disable();\n        bottom_filler.disable();\n        bottom_filler.hide();\n        if (ori == HORIZONTAL)\n        {\n            top.set_left(b1.get_rect().right()+1);\n            top.set_right(b2.get_rect().left()-1);\n        }\n        else\n        {\n            top.set_top(b1.get_rect().bottom()+1);\n            top.set_bottom(b2.get_rect().top()-1);\n        }\n        top_filler.rect = top;\n        bottom_filler.rect = bottom;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    show_slider (\n    )\n    {\n        if ((b2.get_rect().top() - b1.get_rect().bottom() - 1 <= 8 && ori == VERTICAL) || \n            (b2.get_rect().left() - b1.get_rect().right() - 1 <= 8 && ori == HORIZONTAL) || \n            max_pos == 0)\n            return;\n\n        rectangle top(rect), bottom(rect);\n        slider.show();\n        top_filler.enable();\n        bottom_filler.enable();\n        bottom_filler.show();\n        if (ori == HORIZONTAL)\n        {\n            top.set_left(b1.get_rect().right()+1);\n            top.set_right(slider.get_rect().left()-1);\n            bottom.set_left(slider.get_rect().right()+1);\n            bottom.set_right(b2.get_rect().left()-1);\n        }\n        else\n        {\n            top.set_top(b1.get_rect().bottom()+1);\n            top.set_bottom(slider.get_rect().top()-1);\n            bottom.set_top(slider.get_rect().bottom()+1);\n            bottom.set_bottom(b2.get_rect().top()-1);\n        }\n        top_filler.rect = top;\n        bottom_filler.rect = bottom;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scroll_bar::\n    max_slider_pos (\n    ) const\n    {\n        auto_mutex M(m);\n        return max_pos;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    set_max_slider_pos (\n        long mpos\n    )\n    {\n        auto_mutex M(m);\n        max_pos = mpos;\n        if (pos > mpos)\n            pos = mpos;\n\n        if (ori == HORIZONTAL)\n            set_length(rect.width());\n        else\n            set_length(rect.height());\n\n        if (mpos != 0 && enabled)\n        {\n            b1.enable();\n            b2.enable();\n        }\n        else\n        {\n            b1.disable();\n            b2.disable();\n        }\n             \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    set_slider_pos (\n        long pos\n    )\n    {\n        auto_mutex M(m);\n        if (pos < 0)\n            pos = 0;\n        if (pos > max_pos)\n            pos = max_pos;\n\n        this->pos = pos;\n\n        // move the slider object to its new position\n        set_pos(rect.left(),rect.top());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scroll_bar::\n    slider_pos (\n    ) const\n    {\n        auto_mutex M(m);\n        return pos;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    on_slider_drag (\n    )\n    {\n        if (ori == HORIZONTAL)\n        {\n            double slider_pos = slider.get_rect().left() - b1.get_rect().right() - 1;\n            double range = b2.get_rect().left() - b1.get_rect().right() - slider.get_rect().width() - 1;\n            slider_pos /= range;\n            slider_pos *= max_pos;\n            pos = static_cast<unsigned long>(slider_pos);\n        }\n        else\n        {\n            double slider_pos = slider.get_rect().top() - b1.get_rect().bottom() - 1;\n            double range = b2.get_rect().top() - b1.get_rect().bottom() - slider.get_rect().height() - 1;\n            slider_pos /= range;\n            slider_pos *= max_pos;\n            pos = static_cast<unsigned long>(slider_pos);\n        }\n\n        adjust_fillers();\n        \n        if (scroll_handler.is_set())\n            scroll_handler();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    draw (\n        const canvas& \n    ) const\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b1_down (\n    )\n    {\n        if (pos != 0)\n        {\n            set_slider_pos(pos-1);\n            if (scroll_handler.is_set())\n                scroll_handler();\n\n            if (b1_timer.delay_time() == 1000)\n                b1_timer.set_delay_time(500);\n            else\n                b1_timer.set_delay_time(50);\n            b1_timer.start();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b1_up (\n        bool \n    )\n    {\n        b1_timer.stop();\n        b1_timer.set_delay_time(1000);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b2_down (\n    )\n    {\n        if (pos != max_pos)\n        {\n            set_slider_pos(pos+1);\n            if (scroll_handler.is_set())\n                scroll_handler();\n\n            if (b2_timer.delay_time() == 1000)\n                b2_timer.set_delay_time(500);\n            else\n                b2_timer.set_delay_time(50);\n            b2_timer.start();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b2_up (\n        bool \n    )\n    {\n        b2_timer.stop();\n        b2_timer.set_delay_time(1000);\n    }\n        \n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    top_filler_down (\n    )\n    {\n        // ignore this if the mouse is now outside this object.  This could happen\n        // since the timers are also calling this function.\n        if (top_filler.rect.contains(lastx,lasty) == false)\n        {\n            top_filler_up(false);\n            return;\n        }\n\n        if (pos != 0)\n        {\n            if (pos < js)\n            {\n                // if there is less than jump_size() space left then jump the remaining\n                // amount.\n                delayed_set_slider_pos(0);\n            }\n            else\n            {\n                delayed_set_slider_pos(pos-js);\n            }\n\n            if (top_filler_timer.delay_time() == 1000)\n                top_filler_timer.set_delay_time(500);\n            else\n                top_filler_timer.set_delay_time(50);\n            top_filler_timer.start();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    top_filler_up (\n        bool \n    )\n    {\n        top_filler_timer.stop();\n        top_filler_timer.set_delay_time(1000);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    bottom_filler_down (\n    )\n    {\n        // ignore this if the mouse is now outside this object.  This could happen\n        // since the timers are also calling this function.\n        if (bottom_filler.rect.contains(lastx,lasty) == false)\n        {\n            bottom_filler_up(false);\n            return;\n        }\n\n        if (pos != max_pos)\n        {\n            if (max_pos - pos < js)\n            {\n                // if there is less than jump_size() space left then jump the remaining\n                // amount.\n                delayed_set_slider_pos(max_pos);\n            }\n            else\n            {\n                delayed_set_slider_pos(pos+js);\n            }\n\n            if (bottom_filler_timer.delay_time() == 1000)\n                bottom_filler_timer.set_delay_time(500);\n            else\n                bottom_filler_timer.set_delay_time(50);\n            bottom_filler_timer.start();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    bottom_filler_up (\n        bool \n    )\n    {\n        bottom_filler_timer.stop();\n        bottom_filler_timer.set_delay_time(1000);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    set_jump_size (\n        long js_\n    )\n    {\n        auto_mutex M(m);\n        if (js_ < 1)\n            js = 1;\n        else\n            js = js_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scroll_bar::\n    jump_size (\n    ) const\n    {\n        auto_mutex M(m);\n        return js;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    on_user_event (\n        int i\n    )\n    {\n        switch (i)\n        {\n            case 0:\n                b1_down();\n                break;\n            case 1:\n                b2_down();\n                break;\n            case 2:\n                top_filler_down();\n                break;\n            case 3:\n                bottom_filler_down();\n                break;\n            case 4:\n                // if the position we are supposed to switch the slider too isn't \n                // already set\n                if (delayed_pos != pos)\n                {\n                    set_slider_pos(delayed_pos);\n                    if (scroll_handler.is_set())\n                        scroll_handler();\n                }\n                break;\n            default:\n                break;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    delayed_set_slider_pos (\n        unsigned long dpos\n    ) \n    {\n        delayed_pos = dpos;\n        parent.trigger_user_event(this,4); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b1_down_t (\n    ) \n    { \n        parent.trigger_user_event(this,0); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    b2_down_t (\n    ) \n    { \n        parent.trigger_user_event(this,1); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    top_filler_down_t (\n    ) \n    { \n        parent.trigger_user_event(this,2); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar::\n    bottom_filler_down_t (\n    ) \n    { \n        parent.trigger_user_event(this,3); \n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                  widget_group object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    empty (\n    ) \n    {  \n        auto_mutex M(m); \n        widgets.clear(); \n        wg_widgets.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    add (\n        drawable& widget,\n        unsigned long x,\n        unsigned long y\n    )\n    {\n        auto_mutex M(m); \n        drawable* w = &widget;\n        relpos rp;\n        rp.x = x;\n        rp.y = y;\n        if (widgets.is_in_domain(w))\n        {\n            widgets[w].x = x;\n            widgets[w].y = y;\n        }\n        else\n        {\n            widgets.add(w,rp);\n        }\n        if (is_hidden())\n            widget.hide();\n        else\n            widget.show();\n\n        if (is_enabled())\n            widget.enable();\n        else\n            widget.disable();\n\n        widget.set_z_order(z_order());\n        widget.set_pos(x+rect.left(),y+rect.top());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    add (\n        widget_group& widget,\n        unsigned long x,\n        unsigned long y\n    )\n    {\n        auto_mutex M(m); \n        drawable& w = widget;\n        add(w, x, y);\n\n        widget_group* wg = &widget;\n        wg_widgets.add(wg);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool widget_group::\n    is_member (\n        const drawable& widget\n    ) const \n    { \n        auto_mutex M(m); \n        drawable* w = const_cast<drawable*>(&widget);\n        return widgets.is_in_domain(w); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    remove (\n        const drawable& widget\n    )\n    {\n        auto_mutex M(m); \n        drawable* w = const_cast<drawable*>(&widget);\n        if (widgets.is_in_domain(w))\n        {\n            widgets.destroy(w);\n\n            // check if we also have an entry in the wg_widgets set and if\n            // so then remove that too\n            widget_group* wg = reinterpret_cast<widget_group*>(w);\n            if (wg_widgets.is_member(wg))\n            {\n                wg_widgets.destroy(wg);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    size_t widget_group::\n    size (\n    ) const \n    {  \n        auto_mutex M(m); \n        return widgets.size(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n        {\n            const unsigned long rx = widgets.element().value().x;\n            const unsigned long ry = widgets.element().value().y;\n            widgets.element().key()->set_pos(x+rx,y+ry);\n        }\n        drawable::set_pos(x,y);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    set_z_order (\n        long order\n    )\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n            widgets.element().key()->set_z_order(order);\n        drawable::set_z_order(order);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    show (\n    )\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n            widgets.element().key()->show();\n        drawable::show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n            widgets.element().key()->hide();\n        drawable::hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    enable (\n    )\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n            widgets.element().key()->enable();\n        drawable::enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    disable ()\n    {\n        auto_mutex M(m);\n        widgets.reset();\n        while (widgets.move_next())\n            widgets.element().key()->disable();\n        drawable::disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void widget_group::\n    fit_to_contents (\n    )\n    {\n        auto_mutex M(m);\n\n        // call fit_to_contents on all the widget_groups we contain\n        wg_widgets.reset();\n        while (wg_widgets.move_next())\n            wg_widgets.element()->fit_to_contents();\n\n        // now accumulate a rectangle that contains everything in this widget_group\n        rectangle r;\n        widgets.reset();\n        while (widgets.move_next())\n            r = r + widgets.element().key()->get_rect();\n\n        if (r.is_empty())\n        {\n            // make sure it is still empty after we set it at the correct position \n            r.set_right(rect.left()-1);\n            r.set_bottom(rect.top()-1);\n        }\n\n        r.set_left(rect.left());\n        r.set_top(rect.top());\n        rect = r;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                class popup_menu\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    popup_menu::\n    popup_menu (\n    ) :\n        base_window(false,true),\n        pad(2),\n        item_pad(3),\n        cur_rect(pad,pad,pad-1,pad-1),\n        left_width(0),\n        middle_width(0),\n        selected_item(0),\n        submenu_open(false)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    enable_menu_item (\n        unsigned long idx\n    )\n    {\n        DLIB_ASSERT ( idx < size() ,\n                      \"\\tvoid popup_menu::enable_menu_item()\"\n                      << \"\\n\\tidx:    \" << idx\n                      << \"\\n\\tsize(): \" << size() \n        );\n        auto_mutex M(wm);\n        item_enabled[idx] = true;\n        invalidate_rectangle(cur_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    disable_menu_item (\n        unsigned long idx\n    )\n    {\n        DLIB_ASSERT ( idx < size() ,\n                      \"\\tvoid popup_menu::enable_menu_item()\"\n                      << \"\\n\\tidx:    \" << idx\n                      << \"\\n\\tsize(): \" << size() \n        );\n        auto_mutex M(wm);\n        item_enabled[idx] = false;\n        invalidate_rectangle(cur_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    size_t popup_menu::\n    size (\n    ) const\n    { \n        auto_mutex M(wm);\n        return items.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    clear (\n    )\n    {\n        auto_mutex M(wm);\n        hide();\n        cur_rect = rectangle(pad,pad,pad-1,pad-1);\n        win_rect = rectangle();\n        left_width = 0;\n        middle_width = 0;\n        items.clear();\n        item_enabled.clear();\n        left_rects.clear();\n        middle_rects.clear();\n        right_rects.clear();\n        line_rects.clear();\n        submenus.clear();\n        selected_item = 0;\n        submenu_open = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    show (\n    )\n    {\n        auto_mutex M(wm);\n        selected_item = submenus.size();\n        base_window::show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    hide (\n    )\n    {\n        auto_mutex M(wm);\n        // hide ourselves\n        close_submenu();\n        selected_item = submenus.size();\n        base_window::hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    select_first_item (\n    )\n    {\n        auto_mutex M(wm);\n        close_submenu();\n        selected_item = items.size();\n        for (unsigned long i = 0; i < items.size(); ++i)\n        {\n            if ((items[i]->has_click_event() || submenus[i]) && item_enabled[i])\n            {\n                selected_item = i;\n                break;\n            }\n        }\n        invalidate_rectangle(cur_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool popup_menu::\n    forwarded_on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        auto_mutex M(wm);\n        // do nothing if this popup menu is empty\n        if (items.size() == 0)\n            return false;\n\n\n        // check if the selected item is a submenu\n        if (selected_item != submenus.size() && submenus[selected_item] != 0 && submenu_open)\n        {\n            // send the key to the submenu and return if that menu used the key\n            if (submenus[selected_item]->forwarded_on_keydown(key,is_printable,state) == true)\n                return true;\n        }\n\n        if (key == KEY_UP)\n        {\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                selected_item = (selected_item + items.size() - 1)%items.size();\n                // only stop looking if this one is enabled and has a click event or is a submenu\n                if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]) )\n                    break;\n            }\n            invalidate_rectangle(cur_rect);\n            return true;\n        }\n        else if (key == KEY_DOWN)\n        {\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                selected_item = (selected_item + 1)%items.size();\n                // only stop looking if this one is enabled and has a click event or is a submenu\n                if (item_enabled[selected_item] && (items[selected_item]->has_click_event() || submenus[selected_item]))\n                    break;\n            }\n            invalidate_rectangle(cur_rect);\n            return true;\n        }\n        else if (key == KEY_RIGHT && submenu_open == false && display_selected_submenu())\n        {\n            submenus[selected_item]->select_first_item();\n            return true;\n        }\n        else if (key == KEY_LEFT && selected_item != submenus.size() && \n                 submenus[selected_item] != 0 && submenu_open)\n        {\n            close_submenu();\n            return true;\n        }\n        else if (key == '\\n')\n        {\n            if (selected_item != submenus.size() && (items[selected_item]->has_click_event() || submenus[selected_item]))\n            {\n                const long idx = selected_item;\n                // only hide this popup window if this isn't a submenu\n                if (submenus[idx] == 0)\n                {\n                    hide();\n                    hide_handlers.reset();\n                    while (hide_handlers.move_next())\n                        hide_handlers.element()();\n                }\n                else\n                {\n                    display_selected_submenu();\n                    submenus[idx]->select_first_item();\n                }\n                items[idx]->on_click();\n                return true;\n            }\n        }\n        else if (is_printable)\n        {\n            // check if there is a hotkey for this key\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                if (std::tolower(key) == std::tolower(items[i]->get_hot_key()) && \n                    (items[i]->has_click_event() || submenus[i]) && item_enabled[i] )\n                {\n                    // only hide this popup window if this isn't a submenu\n                    if (submenus[i] == 0)\n                    {\n                        hide();\n                        hide_handlers.reset();\n                        while (hide_handlers.move_next())\n                            hide_handlers.element()();\n                    }\n                    else\n                    {\n                        if (selected_item != items.size())\n                            invalidate_rectangle(line_rects[selected_item]);\n\n                        selected_item = i;\n                        display_selected_submenu();\n                        invalidate_rectangle(line_rects[i]);\n                        submenus[i]->select_first_item();\n                    }\n                    items[i]->on_click();\n                }\n            }\n\n            // always say we use a printable key for hotkeys\n            return true;\n        }\n\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    on_submenu_hide (\n    )\n    {\n        hide();\n        hide_handlers.reset();\n        while (hide_handlers.move_next())\n            hide_handlers.element()();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    on_window_resized(\n    )\n    {\n        invalidate_rectangle(win_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long,\n        long x,\n        long y\n    )\n    {\n        if (cur_rect.contains(x,y) && btn == LEFT)\n        {\n            // figure out which item this was on \n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                if (line_rects[i].contains(x,y) && item_enabled[i] && items[i]->has_click_event())\n                {\n                    // only hide this popup window if this isn't a submenu\n                    if (submenus[i] == 0)\n                    {\n                        hide();\n                        hide_handlers.reset();\n                        while (hide_handlers.move_next())\n                            hide_handlers.element()();\n                    }\n                    items[i]->on_click();\n                    break;\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    on_mouse_move (\n        unsigned long ,\n        long x,\n        long y\n    )\n    {\n        if (cur_rect.contains(x,y))\n        {\n            // check if the mouse is still in the same rect it was in last time\n            rectangle last_rect;\n            if (selected_item != submenus.size())\n            {\n                last_rect = line_rects[selected_item];\n            }\n\n            // if the mouse isn't in the same rectangle any more\n            if (last_rect.contains(x,y) == false)\n            {\n                if (selected_item != submenus.size())\n                {\n                    invalidate_rectangle(last_rect);\n                    close_submenu();\n                    selected_item = submenus.size();\n                }\n\n\n                // figure out if we should redraw any menu items \n                for (unsigned long i = 0; i < items.size(); ++i)\n                {\n                    if (items[i]->has_click_event() || submenus[i])\n                    {\n                        if (line_rects[i].contains(x,y))\n                        {\n                            selected_item = i;\n                            break;\n                        }\n                    }\n                }\n\n                // if we found a rectangle that contains the mouse then\n                // tell it to redraw itself\n                if (selected_item != submenus.size())\n                {\n                    display_selected_submenu();\n                    invalidate_rectangle(line_rects[selected_item]);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    close_submenu (\n    )\n    {\n        if (selected_item != submenus.size() && submenus[selected_item] && submenu_open)\n        {\n            submenus[selected_item]->hide();\n            submenu_open = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool popup_menu::\n    display_selected_submenu (\n    )\n    {\n        // show the submenu if one exists\n        if (selected_item != submenus.size() && submenus[selected_item])\n        {\n            long wx, wy;\n            get_pos(wx,wy);\n            wx += line_rects[selected_item].right();\n            wy += line_rects[selected_item].top();\n            submenus[selected_item]->set_pos(wx+1,wy-2);\n            submenus[selected_item]->show();\n            submenu_open = true;\n            return true;\n        }\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    on_mouse_leave (\n    )\n    {\n        if (selected_item != submenus.size())\n        {\n            // only unhighlight a menu item if it isn't a submenu item\n            if (submenus[selected_item] == 0)\n            {\n                invalidate_rectangle(line_rects[selected_item]);\n                selected_item = submenus.size();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu::\n    paint (\n        const canvas& c\n    )\n    {\n        c.fill(200,200,200);\n        draw_rectangle(c, win_rect);\n        for (unsigned long i = 0; i < items.size(); ++i)\n        {\n            bool is_selected = false;\n            if (selected_item != submenus.size() && i == selected_item && \n                item_enabled[i])\n                is_selected = true;\n\n            items[i]->draw_background(c,line_rects[i], item_enabled[i], is_selected);\n            items[i]->draw_left(c,left_rects[i], item_enabled[i], is_selected);\n            items[i]->draw_middle(c,middle_rects[i], item_enabled[i], is_selected);\n            items[i]->draw_right(c,right_rects[i], item_enabled[i], is_selected);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//              class zoomable_region\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    zoomable_region::\n    zoomable_region (\n        drawable_window& w,\n        unsigned long events \n    ) :\n        drawable(w,MOUSE_CLICK | MOUSE_WHEEL | MOUSE_MOVE | events),\n        min_scale(0.15),\n        max_scale(1.0),\n        zoom_increment_(0.90),\n        vsb(w, scroll_bar::VERTICAL),\n        hsb(w, scroll_bar::HORIZONTAL)\n    {\n        scale = 1;\n        mouse_drag_screen = false;\n        style.reset(new scrollable_region_style_default());\n\n        hsb.set_scroll_handler(*this,&zoomable_region::on_h_scroll);\n        vsb.set_scroll_handler(*this,&zoomable_region::on_v_scroll);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    zoomable_region::\n    ~zoomable_region() \n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        drawable::set_pos(x,y);\n        const long border_size = style->get_border_size();\n        vsb.set_pos(rect.right()-border_size+1-vsb.width(),rect.top()+border_size);\n        hsb.set_pos(rect.left()+border_size,rect.bottom()-border_size+1-hsb.height());\n\n        display_rect_ = rectangle(rect.left()+border_size,\n                                  rect.top()+border_size,\n                                  rect.right()-border_size-vsb.width(),\n                                  rect.bottom()-border_size-hsb.height());\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_zoom_increment (\n        double zi\n    )\n    {\n        DLIB_ASSERT(0.0 < zi && zi < 1.0,\n                    \"\\tvoid zoomable_region::set_zoom_increment(zi)\"\n                    << \"\\n\\t the zoom increment must be between 0 and 1\"\n                    << \"\\n\\t zi:   \" << zi\n                    << \"\\n\\t this: \" << this\n        );\n\n        auto_mutex M(m);\n        zoom_increment_ = zi;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double zoomable_region::\n    zoom_increment (\n    ) const\n    {\n        auto_mutex M(m);\n        return zoom_increment_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_max_zoom_scale (\n        double ms \n    )\n    {\n        DLIB_ASSERT(ms > 0,\n                    \"\\tvoid zoomable_region::set_max_zoom_scale(ms)\"\n                    << \"\\n\\t the max zoom scale must be greater than 0\"\n                    << \"\\n\\t ms:   \" << ms \n                    << \"\\n\\t this: \" << this\n        );\n\n        auto_mutex M(m);\n        max_scale = ms;\n        if (scale > ms)\n        {\n            scale = max_scale;\n            lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom()));\n            redraw_graph();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_min_zoom_scale (\n        double ms \n    )\n    {\n        DLIB_ASSERT(ms > 0,\n                    \"\\tvoid zoomable_region::set_min_zoom_scale(ms)\"\n                    << \"\\n\\t the min zoom scale must be greater than 0\"\n                    << \"\\n\\t ms:   \" << ms \n                    << \"\\n\\t this: \" << this\n        );\n\n        auto_mutex M(m);\n        min_scale = ms;\n\n        if (scale < ms)\n        {\n            scale = min_scale;\n        }\n\n        // just call set_size so that everything gets redrawn right\n        set_size(rect.width(), rect.height());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double zoomable_region::\n    min_zoom_scale (\n    ) const\n    {\n        auto_mutex M(m);\n        return min_scale;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double zoomable_region::\n    max_zoom_scale (\n    ) const\n    {\n        auto_mutex M(m);\n        return max_scale;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle old(rect);\n        const long border_size = style->get_border_size();\n        rect = resize_rect(rect,width,height);\n        vsb.set_pos(rect.right()-border_size+1-vsb.width(),  rect.top()+border_size);\n        hsb.set_pos(rect.left()+border_size,  rect.bottom()-border_size+1-hsb.height());\n\n        display_rect_ = rectangle(rect.left()+border_size,\n                                  rect.top()+border_size,\n                                  rect.right()-border_size-vsb.width(),\n                                  rect.bottom()-border_size-hsb.height());\n        vsb.set_length(display_rect_.height());\n        hsb.set_length(display_rect_.width());\n        parent.invalidate_rectangle(rect+old);\n\n        const double old_scale = scale;\n        const vector<double,2> old_gr_orig(gr_orig);\n        scale = min_scale;\n        gr_orig = vector<double,2>(0,0);\n        lr_point = gui_to_graph_space(point(display_rect_.right(),display_rect_.bottom()));\n        scale = old_scale;\n\n        // call adjust_origin() so that the scroll bars get their max slider positions\n        // setup right\n        const point rect_corner(display_rect_.left(), display_rect_.top());\n        adjust_origin(rect_corner, old_gr_orig);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    show (\n    )\n    {\n        auto_mutex M(m);\n        drawable::show();\n        hsb.show();\n        vsb.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        drawable::hide();\n        hsb.hide();\n        vsb.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    enable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::enable();\n        hsb.enable();\n        vsb.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::disable();\n        hsb.disable();\n        vsb.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_z_order (\n        long order\n    )\n    {\n        auto_mutex M(m);\n        drawable::set_z_order(order);\n        hsb.set_z_order(order);\n        vsb.set_z_order(order);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    point zoomable_region::\n    graph_to_gui_space (\n        const vector<double,2>& p\n    ) const\n    {\n        const point rect_corner(display_rect_.left(), display_rect_.top());\n        return (p - gr_orig)*scale + rect_corner;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    vector<double,2> zoomable_region::\n    gui_to_graph_space (\n        const point& p\n    ) const\n    {\n        const point rect_corner(display_rect_.left(), display_rect_.top());\n        return (p - rect_corner)/scale + gr_orig;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    point zoomable_region::\n    max_graph_point (\n    ) const\n    {\n        return lr_point;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle zoomable_region::\n    display_rect (\n    ) const \n    {\n        return display_rect_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    double zoomable_region::\n    zoom_scale (\n    ) const\n    {\n        return scale;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    set_zoom_scale (\n        double new_scale\n    )\n    {\n        // if new_scale isn't in the right range then put it back in range before we do the \n        // rest of this function\n        if (!(min_scale <= new_scale && new_scale <= max_scale))\n        {\n            if (new_scale > max_scale)\n                new_scale = max_scale;\n            else\n                new_scale = min_scale;\n        }\n\n        // find the point in the center of the graph area\n        point center((display_rect_.left()+display_rect_.right())/2,  (display_rect_.top()+display_rect_.bottom())/2);\n        point graph_p(gui_to_graph_space(center));\n        scale = new_scale;\n        adjust_origin(center, graph_p);\n        redraw_graph();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    center_display_at_graph_point (\n        const vector<double,2>& p\n    )\n    {\n        // find the point in the center of the graph area\n        point center((display_rect_.left()+display_rect_.right())/2,  (display_rect_.top()+display_rect_.bottom())/2);\n        adjust_origin(center, p);\n        redraw_graph();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_wheel_down (\n        unsigned long \n    )\n    {\n        // zoom out\n        if (enabled && !hidden && scale > min_scale && display_rect_.contains(lastx,lasty))\n        {\n            point gui_p(lastx,lasty);\n            point graph_p(gui_to_graph_space(gui_p));\n            const double old_scale = scale;\n            scale *= zoom_increment_;\n            if (scale < min_scale)\n                scale = min_scale;\n            redraw_graph(); \n            adjust_origin(gui_p, graph_p);\n\n            if (scale != old_scale)\n                on_view_changed();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_wheel_up (\n        unsigned long \n    )\n    {\n        // zoom in \n        if (enabled && !hidden && scale < max_scale  && display_rect_.contains(lastx,lasty))\n        {\n            point gui_p(lastx,lasty);\n            point graph_p(gui_to_graph_space(gui_p));\n            const double old_scale = scale;\n            scale /= zoom_increment_;\n            if (scale > max_scale)\n                scale = max_scale;\n            redraw_graph(); \n            adjust_origin(gui_p, graph_p);\n\n            if (scale != old_scale)\n                on_view_changed();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (enabled && !hidden && mouse_drag_screen)\n        {\n            adjust_origin(point(x,y), drag_screen_point);\n            redraw_graph();\n            on_view_changed();\n        }\n\n        // check if the mouse isn't being dragged anymore\n        if ((state & base_window::LEFT) == 0)\n        {\n            mouse_drag_screen = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_mouse_up (\n        unsigned long ,\n        unsigned long ,\n        long ,\n        long \n    )\n    {\n        mouse_drag_screen = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool \n    )\n    {\n        if (enabled && !hidden && display_rect_.contains(x,y) && btn == base_window::LEFT)\n        {\n            mouse_drag_screen = true;\n            drag_screen_point = gui_to_graph_space(point(x,y));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    draw (\n        const canvas& c\n    ) const\n    {\n        style->draw_scrollable_region_border(c, rect, enabled);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_h_scroll (\n    )\n    {\n        gr_orig.x() = hsb.slider_pos();\n        redraw_graph();\n\n        on_view_changed();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    on_v_scroll (\n    )\n    {\n        gr_orig.y() = vsb.slider_pos();\n        redraw_graph();\n\n        on_view_changed();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    redraw_graph (\n    )\n    {\n        parent.invalidate_rectangle(display_rect_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void zoomable_region::\n    adjust_origin (\n        const point& gui_p,\n        const vector<double,2>& graph_p\n    )\n    {\n        const point rect_corner(display_rect_.left(), display_rect_.top());\n        const dlib::vector<double,2> v(gui_p - rect_corner);\n        gr_orig = graph_p - v/scale;\n\n\n        // make sure the origin isn't outside the point (0,0)\n        if (gr_orig.x() < 0)\n            gr_orig.x() = 0;\n        if (gr_orig.y() < 0)\n            gr_orig.y() = 0;\n\n        // make sure the lower right corner of the display_rect_ doesn't map to a point beyond lr_point\n        point lr_rect_corner(display_rect_.right(), display_rect_.bottom());\n        point p = graph_to_gui_space(lr_point);\n        vector<double,2> lr_rect_corner_graph_space(gui_to_graph_space(lr_rect_corner));\n        vector<double,2> delta(lr_point - lr_rect_corner_graph_space);\n        if (lr_rect_corner.x() > p.x())\n        {\n            gr_orig.x() += delta.x();\n        }\n\n        if (lr_rect_corner.y() > p.y())\n        {\n            gr_orig.y() += delta.y();\n        }\n\n\n        const vector<double,2> ul_rect_corner_graph_space(gui_to_graph_space(rect_corner));\n        lr_rect_corner_graph_space = gui_to_graph_space(lr_rect_corner);\n        // now adjust the scroll bars\n\n        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));\n        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));\n        // adjust slider position now.  \n        hsb.set_slider_pos(static_cast<long>(ul_rect_corner_graph_space.x()));\n        vsb.set_slider_pos(static_cast<long>(ul_rect_corner_graph_space.y()));\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//              class scrollable_region\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    scrollable_region::\n    scrollable_region (\n        drawable_window& w,\n        unsigned long events \n    ) :\n        drawable(w, MOUSE_WHEEL|events|MOUSE_CLICK|MOUSE_MOVE),\n        hsb(w,scroll_bar::HORIZONTAL),\n        vsb(w,scroll_bar::VERTICAL),\n        hscroll_bar_inc(1),\n        vscroll_bar_inc(1),\n        h_wheel_scroll_bar_inc(1),\n        v_wheel_scroll_bar_inc(1),\n        mouse_drag_enabled_(false),\n        user_is_dragging_mouse(false)\n    {\n        style.reset(new scrollable_region_style_default());\n\n        hsb.set_scroll_handler(*this,&scrollable_region::on_h_scroll);\n        vsb.set_scroll_handler(*this,&scrollable_region::on_v_scroll);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    scrollable_region::\n    ~scrollable_region (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    show (\n    )\n    {\n        auto_mutex M(m);\n        drawable::show();\n        if (need_h_scroll())\n            hsb.show();\n        if (need_v_scroll())\n            vsb.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        drawable::hide();\n        hsb.hide();\n        vsb.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    enable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::enable();\n        hsb.enable();\n        vsb.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::disable();\n        hsb.disable();\n        vsb.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_z_order (\n        long order\n    )\n    {\n        auto_mutex M(m);\n        drawable::set_z_order(order);\n        hsb.set_z_order(order);\n        vsb.set_z_order(order);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle old(rect);\n        rect = resize_rect(rect,width,height);\n        vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size());\n        hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1);\n\n        // adjust the display_rect_\n        if (need_h_scroll() && need_v_scroll())\n        {\n            // both scroll bars aren't hidden\n            if (!hidden)\n            {\n                vsb.show();\n                hsb.show();\n            }\n            display_rect_ = rectangle( rect.left()+style->get_border_size(),\n                                       rect.top()+style->get_border_size(),\n                                       rect.right()-style->get_border_size()-vsb.width(),\n                                       rect.bottom()-style->get_border_size()-hsb.height());\n\n            // figure out how many scroll bar positions there should be\n            unsigned long hdelta = total_rect_.width()-display_rect_.width();\n            unsigned long vdelta = total_rect_.height()-display_rect_.height();\n            hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc;\n            vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc;\n\n            hsb.set_max_slider_pos(hdelta);\n            vsb.set_max_slider_pos(vdelta);\n\n            vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1);\n            hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1);\n        }\n        else if (need_h_scroll())\n        {\n            // only hsb is hidden \n            if (!hidden)\n            {\n                hsb.show();\n                vsb.hide();\n            }\n            display_rect_ = rectangle( rect.left()+style->get_border_size(),\n                                       rect.top()+style->get_border_size(),\n                                       rect.right()-style->get_border_size(),\n                                       rect.bottom()-style->get_border_size()-hsb.height());\n\n            // figure out how many scroll bar positions there should be\n            unsigned long hdelta = total_rect_.width()-display_rect_.width();\n            hdelta = (hdelta+hscroll_bar_inc-1)/hscroll_bar_inc;\n\n            hsb.set_max_slider_pos(hdelta);\n            vsb.set_max_slider_pos(0);\n\n            hsb.set_jump_size((display_rect_.width()+hscroll_bar_inc-1)/hscroll_bar_inc/2+1);\n        }\n        else if (need_v_scroll())\n        {\n            // only vsb is hidden \n            if (!hidden)\n            {\n                hsb.hide();\n                vsb.show();\n            }\n            display_rect_ = rectangle( rect.left()+style->get_border_size(),\n                                       rect.top()+style->get_border_size(),\n                                       rect.right()-style->get_border_size()-vsb.width(),\n                                       rect.bottom()-style->get_border_size());\n\n            unsigned long vdelta = total_rect_.height()-display_rect_.height();\n            vdelta = (vdelta+vscroll_bar_inc-1)/vscroll_bar_inc;\n\n            hsb.set_max_slider_pos(0);\n            vsb.set_max_slider_pos(vdelta);\n\n            vsb.set_jump_size((display_rect_.height()+vscroll_bar_inc-1)/vscroll_bar_inc/2+1);\n        }\n        else\n        {\n            // both are hidden \n            if (!hidden)\n            {\n                hsb.hide();\n                vsb.hide();\n            }\n            display_rect_ = rectangle( rect.left()+style->get_border_size(),\n                                       rect.top()+style->get_border_size(),\n                                       rect.right()-style->get_border_size(),\n                                       rect.bottom()-style->get_border_size());\n\n            hsb.set_max_slider_pos(0);\n            vsb.set_max_slider_pos(0);\n        }\n\n        vsb.set_length(display_rect_.height());\n        hsb.set_length(display_rect_.width());\n\n        // adjust the total_rect_ position by trigging the scroll events\n        on_h_scroll();\n        on_v_scroll();\n\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long scrollable_region::\n    horizontal_mouse_wheel_scroll_increment (\n    ) const\n    {\n        auto_mutex M(m);\n        return h_wheel_scroll_bar_inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long scrollable_region::\n    vertical_mouse_wheel_scroll_increment (\n    ) const\n    {\n        auto_mutex M(m);\n        return v_wheel_scroll_bar_inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_horizontal_mouse_wheel_scroll_increment (\n        unsigned long inc\n    )\n    {\n        auto_mutex M(m);\n        h_wheel_scroll_bar_inc = inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_vertical_mouse_wheel_scroll_increment (\n        unsigned long inc\n    )\n    {\n        auto_mutex M(m);\n        v_wheel_scroll_bar_inc = inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long scrollable_region::\n    horizontal_scroll_increment (\n    ) const\n    {\n        auto_mutex M(m);\n        return hscroll_bar_inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long scrollable_region::\n    vertical_scroll_increment (\n    ) const\n    {\n        auto_mutex M(m);\n        return vscroll_bar_inc;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_horizontal_scroll_increment (\n        unsigned long inc\n    )\n    {\n        auto_mutex M(m);\n        hscroll_bar_inc = inc;\n        // call set_size to reset the scroll bars\n        set_size(rect.width(),rect.height());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_vertical_scroll_increment (\n        unsigned long inc\n    )\n    {\n        auto_mutex M(m);\n        vscroll_bar_inc = inc;\n        // call set_size to reset the scroll bars\n        set_size(rect.width(),rect.height());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scrollable_region::\n    horizontal_scroll_pos (\n    ) const\n    {\n        auto_mutex M(m);\n        return hsb.slider_pos();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scrollable_region::\n    vertical_scroll_pos (\n    ) const\n    {\n        auto_mutex M(m);\n        return vsb.slider_pos();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_horizontal_scroll_pos (\n        long pos\n    )\n    {\n        auto_mutex M(m);\n\n        hsb.set_slider_pos(pos);\n        on_h_scroll();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_vertical_scroll_pos (\n        long pos\n    )\n    {\n        auto_mutex M(m);\n\n        vsb.set_slider_pos(pos);\n        on_v_scroll();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        drawable::set_pos(x,y);\n        vsb.set_pos(rect.right()-style->get_border_size()-vsb.width()+1, rect.top()+style->get_border_size());\n        hsb.set_pos(rect.left()+style->get_border_size(), rect.bottom()-style->get_border_size()-hsb.height()+1);\n\n        const long delta_x = total_rect_.left() - display_rect_.left();\n        const long delta_y = total_rect_.top() - display_rect_.top();\n\n        display_rect_ = move_rect(display_rect_, rect.left()+style->get_border_size(), rect.top()+style->get_border_size());\n\n        total_rect_ = move_rect(total_rect_, display_rect_.left()+delta_x, display_rect_.top()+delta_y);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool scrollable_region::\n    mouse_drag_enabled (\n    ) const\n    {\n        auto_mutex M(m);\n        return mouse_drag_enabled_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    enable_mouse_drag (\n    )\n    {\n        auto_mutex M(m);\n        mouse_drag_enabled_ = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    disable_mouse_drag (\n    )\n    {\n        auto_mutex M(m);\n        mouse_drag_enabled_ = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle& scrollable_region::\n    display_rect (\n    ) const\n    {\n        return display_rect_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    set_total_rect_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        DLIB_ASSERT((width > 0 && height > 0) || (width == 0 && height == 0),\n                    \"\\tvoid scrollable_region::set_total_rect_size(width,height)\"\n                    << \"\\n\\twidth and height must be > 0 or both == 0\"\n                    << \"\\n\\twidth:  \" << width \n                    << \"\\n\\theight: \" << height \n                    << \"\\n\\tthis: \" << this\n        );\n\n        total_rect_ = move_rect(rectangle(width,height), \n                                display_rect_.left()-static_cast<long>(hsb.slider_pos()),\n                                display_rect_.top()-static_cast<long>(vsb.slider_pos()));\n\n        // call this just to reconfigure the scroll bars\n        set_size(rect.width(),rect.height());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rectangle& scrollable_region::\n    total_rect (\n    ) const\n    {\n        return total_rect_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    scroll_to_rect (\n        const rectangle& r_\n    )\n    {\n        const rectangle r(total_rect_.intersect(r_));\n        const rectangle old(total_rect_);\n        // adjust the horizontal scroll bar so that r fits as best as possible\n        if (r.left() < display_rect_.left())\n        {\n            long distance = (r.left()-total_rect_.left())/hscroll_bar_inc;\n            hsb.set_slider_pos(distance);\n        }\n        else if (r.right() > display_rect_.right())\n        {\n            long distance = (r.right()-total_rect_.left()-display_rect_.width()+hscroll_bar_inc)/hscroll_bar_inc;\n            hsb.set_slider_pos(distance);\n        }\n\n        // adjust the vertical scroll bar so that r fits as best as possible\n        if (r.top() < display_rect_.top())\n        {\n            long distance = (r.top()-total_rect_.top())/vscroll_bar_inc;\n            vsb.set_slider_pos(distance);\n        }\n        else if (r.bottom() > display_rect_.bottom())\n        {\n            long distance = (r.bottom()-total_rect_.top()-display_rect_.height()+vscroll_bar_inc)/vscroll_bar_inc;\n            vsb.set_slider_pos(distance);\n        }\n\n\n        // adjust total_rect_ so that it matches where the scroll bars are now\n        total_rect_ = move_rect(total_rect_, \n                                display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), \n                                display_rect_.top()-vscroll_bar_inc*vsb.slider_pos());\n\n        // only redraw if we actually changed something\n        if (total_rect_ != old)\n        {\n            parent.invalidate_rectangle(display_rect_);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_wheel_down (\n        unsigned long \n    )\n    {\n        if (rect.contains(lastx,lasty) && enabled && !hidden)\n        {\n            if (need_v_scroll())\n            {\n                long pos = vsb.slider_pos();\n                vsb.set_slider_pos(pos+(long)v_wheel_scroll_bar_inc);\n                on_v_scroll();\n            }\n            else if (need_h_scroll())\n            {\n                long pos = hsb.slider_pos();\n                hsb.set_slider_pos(pos+(long)h_wheel_scroll_bar_inc);\n                on_h_scroll();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (enabled && !hidden && user_is_dragging_mouse && state==base_window::LEFT)\n        {\n            point current_delta = point(x,y) - point(total_rect().left(), total_rect().top());\n            rectangle new_rect(translate_rect(display_rect(), drag_origin - current_delta));\n            new_rect = centered_rect(new_rect, new_rect.width()-hscroll_bar_inc, new_rect.height()-vscroll_bar_inc);\n            scroll_to_rect(new_rect);\n            on_view_changed();\n        }\n        else\n        {\n            user_is_dragging_mouse = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool \n    )\n    {\n        if (mouse_drag_enabled_ && enabled && !hidden && display_rect().contains(x,y) && (btn==base_window::LEFT))\n        {\n            drag_origin = point(x,y) - point(total_rect().left(), total_rect().top());\n            user_is_dragging_mouse = true;\n        }\n        else\n        {\n            user_is_dragging_mouse = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_mouse_up   (\n        unsigned long ,\n        unsigned long ,\n        long ,\n        long \n    )\n    {\n        user_is_dragging_mouse = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_wheel_up (\n        unsigned long \n    )\n    {\n        if (rect.contains(lastx,lasty) && enabled && !hidden)\n        {\n            if (need_v_scroll())\n            {\n                long pos = vsb.slider_pos();\n                vsb.set_slider_pos(pos-(long)v_wheel_scroll_bar_inc);\n                on_v_scroll();\n            }\n            else if (need_h_scroll())\n            {\n                long pos = hsb.slider_pos();\n                hsb.set_slider_pos(pos-(long)h_wheel_scroll_bar_inc);\n                on_h_scroll();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    draw (\n        const canvas& c\n    ) const\n    {\n        style->draw_scrollable_region_border(c, rect, enabled);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool scrollable_region::\n    need_h_scroll (\n    ) const\n    {\n        if (total_rect_.width() > rect.width()-style->get_border_size()*2)\n        {\n            return true;\n        }\n        else\n        {\n            // check if we would need a vertical scroll bar and if adding one would make us need\n            // a horizontal one\n            if (total_rect_.height() > rect.height()-style->get_border_size()*2 && \n                total_rect_.width() > rect.width()-style->get_border_size()*2-vsb.width())\n                return true;\n            else\n                return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool scrollable_region::\n    need_v_scroll (\n    ) const\n    {\n        if (total_rect_.height() > rect.height()-style->get_border_size()*2)\n        {\n            return true;\n        }\n        else\n        {\n            // check if we would need a horizontal scroll bar and if adding one would make us need\n            // a vertical_scroll_pos one\n            if (total_rect_.width() > rect.width()-style->get_border_size()*2 && \n                total_rect_.height() > rect.height()-style->get_border_size()*2-hsb.height())\n                return true;\n            else\n                return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_h_scroll (\n    )\n    {\n        total_rect_ = move_rect(total_rect_, display_rect_.left()-hscroll_bar_inc*hsb.slider_pos(), total_rect_.top());\n        parent.invalidate_rectangle(display_rect_);\n        if (events_are_enabled())\n            on_view_changed();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scrollable_region::\n    on_v_scroll (\n    )\n    {\n        total_rect_ = move_rect(total_rect_, total_rect_.left(), display_rect_.top()-vscroll_bar_inc*vsb.slider_pos());\n        parent.invalidate_rectangle(display_rect_);\n        if (events_are_enabled())\n            on_view_changed();\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// class popup_menu_region \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    popup_menu_region::\n    popup_menu_region(  \n        drawable_window& w\n    ) :\n        drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | FOCUS_EVENTS | WINDOW_MOVED),\n        popup_menu_shown(false)\n    {\n\n        menu_.set_on_hide_handler(*this,&popup_menu_region::on_menu_becomes_hidden);\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    popup_menu_region::\n    ~popup_menu_region(\n    )\n    { \n        disable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    set_size (\n        unsigned long width, \n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rect = resize_rect(rect,width,height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    set_rect (\n        const rectangle& new_rect\n    )\n    {\n        auto_mutex M(m);\n        rect = new_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    popup_menu& popup_menu_region::\n    menu (\n    )\n    {\n        return menu_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        drawable::hide();\n        menu_.hide();\n        popup_menu_shown = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::disable();\n        menu_.hide();\n        popup_menu_shown = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        if (enabled && !hidden && popup_menu_shown)\n        {\n            menu_.forwarded_on_keydown(key, is_printable, state);\n        }\n        else if (popup_menu_shown)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n\n        if (key == (unsigned long)base_window::KEY_ESC)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_menu_becomes_hidden (\n    )\n    {\n        popup_menu_shown = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_focus_lost (\n    )\n    {\n        if (popup_menu_shown)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_focus_gained (\n    )\n    {\n        if (popup_menu_shown)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_window_moved(\n    )\n    {\n        if (popup_menu_shown)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool \n    )\n    {\n        if (enabled && !hidden && rect.contains(x,y) && btn == base_window::RIGHT)\n        {\n            long orig_x, orig_y;\n            parent.get_pos(orig_x, orig_y);\n            menu_.set_pos(orig_x+x, orig_y+y);\n            menu_.show();\n            popup_menu_shown = true;\n        }\n        else if (popup_menu_shown)\n        {\n            menu_.hide();\n            popup_menu_shown = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void popup_menu_region::\n    draw (\n        const canvas& \n    ) const\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BASE_WIDGETs_CPP_ \n\n"
  },
  {
    "path": "dlib/gui_widgets/base_widgets.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_BASE_WIDGETs_\n#define DLIB_BASE_WIDGETs_\n\n#include <cctype>\n#include <memory>\n\n#include \"base_widgets_abstract.h\"\n#include \"drawable.h\"\n#include \"../gui_core.h\"\n#include \"../algs.h\"\n#include \"../member_function_pointer.h\"\n#include \"../timer.h\"\n#include \"../map.h\"\n#include \"../set.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_transforms/assign_image.h\"\n#include \"../array.h\" \n#include \"style.h\"\n#include \"../unicode.h\"\n#include \"../any.h\"\n\n\nnamespace dlib\n{\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class draggable\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class draggable : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - drag == false\n\n            CONVENTION\n                - if (the user is holding the left button down over this object) then\n                    - drag == true\n                    - x == the x position of the mouse relative to the upper left corner\n                      of this object.\n                    - y == the y position of the mouse relative to the upper left corner\n                      of this object.\n                - else\n                    - drag == false\n        !*/\n\n    public:\n\n        draggable(  \n            drawable_window& w,\n            unsigned long events = 0\n        ) : \n            drawable(w,events | MOUSE_MOVE | MOUSE_CLICK),\n            drag(false)\n        {}\n\n        virtual ~draggable(\n        ) = 0;\n\n        rectangle draggable_area (\n        ) const { auto_mutex M(m); return area; }\n\n        void set_draggable_area (\n            const rectangle& area_ \n        ) { auto_mutex M(m); area = area_; } \n\n    protected:\n\n        bool is_being_dragged (\n        ) const { return drag; }\n\n        virtual void on_drag (\n        ){}\n\n        virtual void on_drag_stop (\n        ){}\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long ,\n            long x,\n            long y,\n            bool \n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n    private:\n\n        rectangle area;\n        bool drag;\n        long x, y;\n\n        // restricted functions\n        draggable(draggable&);        // copy constructor\n        draggable& operator=(draggable&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class mouse_over_event \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class mouse_over_event : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - is_mouse_over_ == false\n\n            CONVENTION\n                - is_mouse_over_ == is_mouse_over()\n        !*/\n\n    public:\n\n        mouse_over_event(  \n            drawable_window& w,\n            unsigned long events = 0\n        ) :\n            drawable(w,events | MOUSE_MOVE),\n            is_mouse_over_(false)\n        {}\n\n\n        virtual ~mouse_over_event(\n        ) = 0;\n\n        int next_free_user_event_number() const\n        {\n            return drawable::next_free_user_event_number()+1;\n        }\n\n    protected:\n\n        bool is_mouse_over (\n        ) const;\n\n        virtual void on_mouse_over (\n        ){}\n\n        virtual void on_mouse_not_over (\n        ){}\n\n        void on_mouse_leave (\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_user_event (\n            int num\n        );\n\n    private:\n        mutable bool is_mouse_over_;\n\n        // restricted functions\n        mouse_over_event(mouse_over_event&);        // copy constructor\n        mouse_over_event& operator=(mouse_over_event&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class button_action \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button_action : public mouse_over_event \n    {\n        /*!\n            INITIAL VALUE\n                - is_depressed_ == false\n                - seen_click == false\n\n            CONVENTION\n                - is_depressed_ == is_depressed()\n                - if (the user has clicked the button but hasn't yet released the\n                      left mouse button) then\n                    - seen_click == true\n                - else \n                    - seen_click == false\n        !*/\n\n    public:\n\n        button_action(  \n            drawable_window& w,\n            unsigned long events = 0\n        ) :\n            mouse_over_event(w,events | MOUSE_MOVE | MOUSE_CLICK),\n            is_depressed_(false),\n            seen_click(false)\n        {}\n\n\n        virtual ~button_action(\n        ) = 0;\n\n        int next_free_user_event_number() const\n        {\n            return mouse_over_event::next_free_user_event_number()+1;\n        }\n\n    protected:\n\n        bool is_depressed (\n        ) const;\n\n        virtual void on_button_down (\n        ){}\n\n        virtual void on_button_up (\n            bool \n        ){}\n\n        void on_mouse_not_over (\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long ,\n            long x,\n            long y,\n            bool\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long,\n            long x,\n            long y\n        );\n\n\n    private:\n        mutable bool is_depressed_;\n        bool seen_click;\n\n        void on_user_event (\n            int num\n        );\n\n        // restricted functions\n        button_action(button_action&);        // copy constructor\n        button_action& operator=(button_action&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class widget_group \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class widget_group : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                widgets.size() == 0\n\n            CONVENTION\n                - widgets contains all the drawable objects and their relative positions\n                  that are in *this.\n                - wg_widgets contains pointers to just the widgets that happen\n                  to be widget_group objects.  \n        !*/\n\n        struct relpos\n        {\n            unsigned long x;\n            unsigned long y;\n        };\n\n    public:\n        widget_group(  \n            drawable_window& w\n        ) : drawable(w) { rect = rectangle(0,0,-1,-1); enable_events();}\n\n        virtual ~widget_group(\n        ){ disable_events(); }\n\n        void empty (\n        );\n\n        void add (\n            drawable& widget,\n            unsigned long x,\n            unsigned long y\n        );\n\n        void add (\n            widget_group& widget,\n            unsigned long x,\n            unsigned long y\n        );\n\n        bool is_member (\n            const drawable& widget\n        ) const;\n\n        void remove (\n            const drawable& widget\n        );\n\n        size_t size (\n        ) const; \n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        void set_z_order (\n            long order\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void fit_to_contents (\n        );\n\n    protected:\n\n        // this object doesn't draw anything but also isn't abstract\n        void draw (\n            const canvas& \n        ) const {}\n\n    private:\n\n        map<drawable*,relpos>::kernel_1a_c widgets;\n        set<widget_group*>::kernel_1a_c wg_widgets;\n\n\n        // restricted functions\n        widget_group(widget_group&);        // copy constructor\n        widget_group& operator=(widget_group&);    // assignment operator\n    };\n\n\n// ----------------------------------------------------------------------------------------\n\n    class image_widget : public draggable\n    {\n        /*!\n            INITIAL VALUE\n                - img.size() == 0\n\n            CONVENTION\n                - img == the image this object displays\n        !*/\n\n    public:\n\n        image_widget(  \n            drawable_window& w\n        ): draggable(w)  { enable_events(); }\n\n        ~image_widget(\n        )\n        {\n            disable_events();\n            parent.invalidate_rectangle(rect); \n        }\n\n        template <\n            typename image_type\n            >\n        void set_image (\n            const image_type& new_img\n        )\n        {\n            auto_mutex M(m);\n            assign_image_scaled(img,new_img);\n            rectangle old(rect);\n            rect.set_right(rect.left()+num_columns(img)-1); \n            rect.set_bottom(rect.top()+num_rows(img)-1);\n            parent.invalidate_rectangle(rect+old);\n        }\n\n    private:\n\n        void draw (\n            const canvas& c\n        ) const\n        {\n            rectangle area = rect.intersect(c);\n            if (area.is_empty())\n                return;\n\n            draw_image(c, point(rect.left(),rect.top()), img);\n        }\n\n        array2d<rgb_alpha_pixel> img;\n\n        // restricted functions\n        image_widget(image_widget&);        // copy constructor\n        image_widget& operator=(image_widget&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class tooltip \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class tooltip : public mouse_over_event \n    {\n        /*!\n            INITIAL VALUE\n                - stuff.get() == 0\n                - events_are_enabled() == false\n\n            CONVENTION\n                - if (events_are_enabled() == true) then\n                    - stuff.get() != 0\n        !*/\n\n    public:\n\n        tooltip(  \n            drawable_window& w\n        ) : \n            mouse_over_event(w,MOUSE_CLICK)\n        {}\n\n        ~tooltip(\n        ){ disable_events();}\n\n        void set_size (\n            unsigned long width, \n            unsigned long height \n        )\n        {\n            auto_mutex M(m);\n            rect = resize_rect(rect,width,height);\n        }\n\n\n        void set_text (\n            const std::string& str\n        )\n        {\n            set_text(convert_to_utf32(str));\n        }\n\n        void set_text (\n            const std::wstring& str\n        )\n        {\n            set_text(convert_to_utf32(str));\n        }\n\n        void set_text (\n            const ustring& str\n        )\n        {\n            auto_mutex M(m);\n            if (!stuff)\n            {\n                stuff.reset(new data(*this));\n                enable_events();\n            }\n\n            stuff->win.set_text(str);\n        }\n\n        const std::string text (\n        ) const\n        {\n            return convert_wstring_to_mbstring(wtext());\n        }\n\n        const std::wstring wtext (\n        ) const\n        {\n            return convert_utf32_to_wstring(utext());\n        }\n\n        const dlib::ustring utext (\n        ) const\n        {\n            auto_mutex M(m);\n            dlib::ustring temp;\n            if (stuff)\n            {\n                temp = stuff->win.text;\n            }\n            return temp.c_str();\n        }\n\n        void hide (\n        )\n        {\n            auto_mutex M(m);\n            mouse_over_event::hide();\n            if (stuff)\n            {\n                stuff->tt_timer.stop();\n                stuff->win.hide();\n            }\n        }\n\n        void disable (\n        )\n        {\n            auto_mutex M(m);\n            mouse_over_event::disable();\n            if (stuff)\n            {\n                stuff->tt_timer.stop();\n                stuff->win.hide();\n            }\n        }\n\n    protected:\n\n        void on_mouse_over()\n        {\n            stuff->x = lastx;\n            stuff->y = lasty;\n            stuff->tt_timer.start();\n        }\n\n        void on_mouse_not_over ()\n        {\n            stuff->tt_timer.stop();\n            stuff->win.hide();\n        }\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        )\n        {\n            mouse_over_event::on_mouse_down(btn,state,x,y,is_double_click);\n            stuff->tt_timer.stop();\n            stuff->win.hide();\n        }\n\n        void draw (\n            const canvas& \n        ) const{}\n\n    private:\n\n        class tooltip_window : public base_window \n        {\n        public:\n            tooltip_window (const std::shared_ptr<font>& f) : base_window(false,true), pad(3), mfont(f)\n            {\n            }\n\n            ustring text;\n            rectangle rect_all;\n            rectangle rect_text;\n            const unsigned long pad;\n            const std::shared_ptr<font> mfont;\n            \n            void set_text (\n                const std::string& str\n            )\n            {\n                set_text(convert_to_utf32(str));\n            }\n\n            void set_text (\n                const std::wstring& str\n            )\n            {\n                set_text(convert_to_utf32(str));\n            }\n\n            void set_text (\n                const dlib::ustring& str\n            )\n            {\n                text = str.c_str();\n\n                unsigned long width, height;\n                mfont->compute_size(text,width,height);\n\n                set_size(width+pad*2, height+pad*2);\n                rect_all.set_left(0);\n                rect_all.set_top(0);\n                rect_all.set_right(width+pad*2-1);\n                rect_all.set_bottom(height+pad*2-1);\n\n                rect_text = move_rect(rectangle(width,height),pad,pad);\n            }\n\n            void paint(const canvas& c)\n            {\n                c.fill(255,255,150);\n                draw_rectangle(c, rect_all);\n                mfont->draw_string(c,rect_text,text);\n            }\n        };\n\n        void show_tooltip (\n        )\n        {\n            auto_mutex M(m);\n            long x, y;\n            // if the mouse has moved since we started the timer then \n            // keep waiting until the user stops moving it\n            if (lastx != stuff->x || lasty != stuff->y)\n            {\n                stuff->x = lastx;\n                stuff->y = lasty;\n                return;\n            }\n\n            unsigned long display_width, display_height;\n            // stop the timer\n            stuff->tt_timer.stop();\n            parent.get_pos(x,y);\n            x += lastx+15;\n            y += lasty+15;\n\n            // make sure the tooltip isn't going to be off the screen\n            parent.get_display_size(display_width, display_height);\n            rectangle wrect(move_rect(stuff->win.rect_all,x,y));\n            rectangle srect(display_width, display_height); \n            if (srect.contains(wrect) == false)\n            {\n                rectangle temp(srect.intersect(wrect));\n                x -= wrect.width()-temp.width();\n                y -= wrect.height()-temp.height();\n            }\n\n            stuff->win.set_pos(x,y);\n            stuff->win.show();\n        }\n\n        // put all this stuff in data so we can arrange to only\n        // construct it when someone is actually using the tooltip widget \n        // rather than just instantiating it.\n        struct data\n        {\n            data(\n                tooltip& self\n            ) : \n                x(-1), \n                y(-1),\n                win(self.mfont),\n                tt_timer(self,&tooltip::show_tooltip) \n            { \n                tt_timer.set_delay_time(400); \n            }\n\n            long x, y;\n            tooltip_window win;\n            timer<tooltip> tt_timer;\n\n        };\n        friend struct data;\n        std::unique_ptr<data> stuff;\n\n\n\n        // restricted functions\n        tooltip(tooltip&);        // copy constructor\n        tooltip& operator=(tooltip&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class button  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button : public button_action \n    {\n    public:\n        button(\n            drawable_window& w\n        ) : \n            button_action(w),\n            btn_tooltip(w)\n        {\n            style.reset(new button_style_default());\n            enable_events();\n        }\n        \n        ~button() { disable_events(); parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }\n\n        void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        void set_name (\n            const std::string& name_\n        );\n\n        void set_name (\n            const std::wstring& name_\n        );\n\n        void set_name (\n            const dlib::ustring& name_\n        );\n\n        const std::string name (\n        ) const;\n\n        const std::wstring wname (\n        ) const;\n\n        const dlib::ustring uname (\n        ) const;\n\n        void set_tooltip_text (\n            const std::string& text\n        );\n\n        void set_tooltip_text (\n            const std::wstring& text\n        );\n\n        void set_tooltip_text (\n            const dlib::ustring& text\n        );\n\n        void set_pos(\n            long x,\n            long y\n        );\n\n        const std::string tooltip_text (\n        ) const;\n\n        const std::wstring tooltip_wtext (\n        ) const;\n\n        const dlib::ustring tooltip_utext (\n        ) const;\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top());\n            parent.invalidate_rectangle(style->get_invalidation_rect(rect));\n        }\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler_)()\n        )\n        {\n            auto_mutex M(m);\n            event_handler = make_mfp(object,event_handler_);\n            event_handler_self.clear();\n        }\n\n        void set_click_handler (\n            const any_function<void()>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            event_handler = event_handler_;\n            event_handler_self.clear();\n        }\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler_)(button&)\n        )\n        {\n            auto_mutex M(m);\n            event_handler_self = make_mfp(object,event_handler_);\n            event_handler.clear();\n        }\n\n        void set_sourced_click_handler (\n            const any_function<void(button&)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            event_handler_self = event_handler_;\n            event_handler.clear();\n        }\n\n        bool is_depressed (\n        ) const\n        {\n            auto_mutex M(m);\n            return button_action::is_depressed();\n        }\n\n        template <\n            typename T\n            >\n        void set_button_down_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            button_down_handler = make_mfp(object,event_handler);\n        }\n\n        void set_button_down_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            button_down_handler = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_button_up_handler (\n            T& object,\n            void (T::*event_handler)(bool mouse_over)\n        )\n        {\n            auto_mutex M(m);\n            button_up_handler = make_mfp(object,event_handler);\n        }\n\n        void set_button_up_handler (\n            const any_function<void(bool)>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            button_up_handler = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_button_down_handler (\n            T& object,\n            void (T::*event_handler)(button&)\n        )\n        {\n            auto_mutex M(m);\n            button_down_handler_self = make_mfp(object,event_handler);\n        }\n\n        void set_sourced_button_down_handler (\n            const any_function<void(button&)>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            button_down_handler_self = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_button_up_handler (\n            T& object,\n            void (T::*event_handler)(bool mouse_over, button&)\n        )\n        {\n            auto_mutex M(m);\n            button_up_handler_self = make_mfp(object,event_handler);\n        }\n\n        void set_sourced_button_up_handler (\n            const any_function<void(bool,button&)>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            button_up_handler_self = event_handler;\n        }\n\n    private:\n\n        // restricted functions\n        button(button&);        // copy constructor\n        button& operator=(button&);    // assignment operator\n\n        dlib::ustring name_;\n        tooltip btn_tooltip;\n\n        any_function<void()> event_handler;\n        any_function<void(button&)> event_handler_self;\n        any_function<void()> button_down_handler;\n        any_function<void(bool)> button_up_handler;\n        any_function<void(button&)> button_down_handler_self;\n        any_function<void(bool,button&)> button_up_handler_self;\n\n        std::unique_ptr<button_style> style;\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const { style->draw_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed()); }\n\n        void on_button_up (\n            bool mouse_over\n        );\n\n        void on_button_down (\n        );\n\n        void on_mouse_over (\n        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }\n\n        void on_mouse_not_over (\n        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(style->get_invalidation_rect(rect)); }\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class scroll_bar \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                - ori == a value given by the constructor\n                - style == a scroll_bar_style_default object\n                - pos == 0\n                - max_pos == 0\n                - js == 10\n\n            CONVENTION\n                - ori == orientation()\n                - b1 == the button that is near the 0 end of the scroll bar\n                - b2 == the button that is near the max_pos() end of the scroll bar\n\n                - max_pos == max_slider_pos()\n                - pos == slider_pos()\n                - js == jump_size()\n        !*/\n\n    public:\n        enum bar_orientation \n        {\n            HORIZONTAL,\n            VERTICAL\n        };\n\n        scroll_bar(  \n            drawable_window& w,\n            bar_orientation orientation_\n        );\n\n        virtual ~scroll_bar(\n        );\n\n        bar_orientation orientation (\n        ) const;\n\n        void set_length (\n            unsigned long length\n        );\n\n        long max_slider_pos (\n        ) const;\n\n        void set_max_slider_pos (\n            long mpos\n        );\n\n        void set_slider_pos (\n            long pos\n        );\n\n        long slider_pos (\n        ) const;\n\n        template <\n            typename T\n            >\n        void set_scroll_handler (\n            T& object,\n            void (T::*eh)()\n        ) { auto_mutex M(m); scroll_handler = make_mfp(object,eh); }\n\n        void set_scroll_handler (\n            const any_function<void()>& eh\n        ) { auto_mutex M(m); scroll_handler = eh; }\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        void enable (\n        )\n        {\n            auto_mutex M(m);\n            if (!hidden)\n                show_slider();\n            if (max_pos != 0)\n            {\n                b1.enable();\n                b2.enable();\n            }\n            drawable::enable();\n        }\n\n        void disable (\n        )\n        {\n            auto_mutex M(m);\n            hide_slider();\n            b1.disable();\n            b2.disable();\n            drawable::disable();\n        }\n            \n        void hide (\n        )\n        {\n            auto_mutex M(m);\n            hide_slider();\n            top_filler.hide();\n            bottom_filler.hide();\n            b1.hide();\n            b2.hide();\n            drawable::hide();\n        }\n            \n        void show (\n        )\n        {\n            auto_mutex M(m);\n            b1.show();\n            b2.show();\n            drawable::show();\n            top_filler.show();\n            if (enabled)\n                show_slider();\n        }\n\n        void set_z_order (\n            long order\n        )\n        {\n            auto_mutex M(m);\n            slider.set_z_order(order);\n            top_filler.set_z_order(order);\n            bottom_filler.set_z_order(order);\n            b1.set_z_order(order);\n            b2.set_z_order(order);\n            drawable::set_z_order(order);\n        }\n\n        void set_jump_size (\n            long js\n        );\n\n        long jump_size (\n        ) const;\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n\n            if (ori == HORIZONTAL)\n            {\n                b1.set_style(style_.get_left_button_style());\n                b2.set_style(style_.get_right_button_style());\n                set_length(rect.width());\n            }\n            else\n            {\n                b1.set_style(style_.get_up_button_style());\n                b2.set_style(style_.get_down_button_style());\n                set_length(rect.height());\n            }\n\n        }\n\n    private:\n\n        void hide_slider (\n        );\n        /*!\n            ensures\n                - hides the slider and makes any other changes needed so that the\n                  scroll_bar still looks right.\n        !*/\n\n        void show_slider (\n        );\n        /*!\n            ensures\n                - shows the slider and makes any other changes needed so that the\n                  scroll_bar still looks right.\n        !*/\n\n\n        void on_slider_drag (\n        ); \n        /*!\n            requires\n                - is called whenever the user drags the slider\n        !*/\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        void b1_down (\n        );\n\n        void b1_up (\n            bool mouse_over\n        );\n\n        void b2_down (\n        );\n\n        void b2_up (\n            bool mouse_over\n        );\n\n        void top_filler_down (\n        );\n\n        void top_filler_up (\n            bool mouse_over\n        );\n\n        void bottom_filler_down (\n        );\n\n        void bottom_filler_up (\n            bool mouse_over\n        );\n\n        void on_user_event (\n            int i\n        );\n\n        void delayed_set_slider_pos (\n            unsigned long dpos\n        );\n\n        void b1_down_t (\n        );\n\n        void b2_down_t (\n        );\n\n        void top_filler_down_t (\n        );\n\n        void bottom_filler_down_t (\n        );\n\n        friend class filler;\n        class filler : public button_action\n        {\n            friend class scroll_bar;\n        public:\n            filler (\n                drawable_window& w,\n                scroll_bar& object,\n                void (scroll_bar::*down)(),\n                void (scroll_bar::*up)(bool)\n            ):\n                button_action(w),\n                my_scroll_bar(object)\n            {\n                bup = make_mfp(object,up);\n                bdown = make_mfp(object,down);\n\n                enable_events();\n            }\n\n            ~filler (\n            )\n            {\n               disable_events();\n            }\n\n            void set_size (\n                unsigned long width,\n                unsigned long height\n            )\n            {\n                rectangle old(rect);\n                const unsigned long x = rect.left();\n                const unsigned long y = rect.top();\n                rect.set_right(x+width-1);\n                rect.set_bottom(y+height-1);\n\n                parent.invalidate_rectangle(rect+old);\n            }\n\n        private:\n\n            void draw (\n                const canvas& c\n            ) const\n            {\n                my_scroll_bar.style->draw_scroll_bar_background(c,rect,enabled,lastx,lasty,is_depressed());\n            }\n\n            void on_button_down (\n            ) { bdown(); } \n\n            void on_button_up (\n                bool mouse_over\n            ) { bup(mouse_over); } \n\n            scroll_bar& my_scroll_bar;\n            any_function<void()> bdown;\n            any_function<void(bool)> bup;\n        };\n\n        friend class slider_class;\n        class slider_class : public draggable\n        {\n            friend class scroll_bar;\n        public:\n            slider_class ( \n                drawable_window& w,\n                scroll_bar& object,\n                void (scroll_bar::*handler)()\n            ) :\n                draggable(w, MOUSE_MOVE),\n                mouse_in_widget(false),\n                my_scroll_bar(object)\n            {\n                callback = make_mfp(object,handler);\n                enable_events();\n            }\n\n            ~slider_class (\n            )\n            {\n               disable_events();\n            }\n\n            void set_size (\n                unsigned long width,\n                unsigned long height\n            )\n            {\n                rectangle old(rect);\n                const unsigned long x = rect.left();\n                const unsigned long y = rect.top();\n                rect.set_right(x+width-1);\n                rect.set_bottom(y+height-1);\n\n                parent.invalidate_rectangle(rect+old);\n            }\n\n        private:\n            virtual void on_mouse_move (\n                unsigned long state,\n                long x,\n                long y\n            )\n            {\n                draggable::on_mouse_move(state,x,y);\n                if (!hidden && my_scroll_bar.style->redraw_on_mouse_over_slider())\n                {\n                    if (rect.contains(x,y) && !mouse_in_widget)\n                    {\n                        mouse_in_widget = true;\n                        parent.invalidate_rectangle(rect);\n                    }\n                    else if (rect.contains(x,y) == false && mouse_in_widget)\n                    {\n                        mouse_in_widget = false;\n                        parent.invalidate_rectangle(rect);\n                    }\n                }\n            }\n\n            void on_mouse_leave (\n            )\n            {\n                if (mouse_in_widget && my_scroll_bar.style->redraw_on_mouse_over_slider())\n                {\n                    mouse_in_widget = false;\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n\n            void on_drag_stop (\n            ) \n            {\n                if (my_scroll_bar.style->redraw_on_mouse_over_slider())\n                    parent.invalidate_rectangle(rect);\n            }\n\n            void on_drag (\n            )\n            {\n                callback();\n            }\n\n            void draw (\n                const canvas& c\n            ) const\n            {\n                my_scroll_bar.style->draw_scroll_bar_slider(c,rect,enabled,lastx,lasty, is_being_dragged());\n            }\n\n            bool mouse_in_widget;\n            scroll_bar& my_scroll_bar;\n            any_function<void()> callback;\n        };\n\n\n        void adjust_fillers (\n        );\n        /*!\n            ensures\n                - top_filler and bottom_filler appear in their correct positions\n                  relative to the current positions of the slider and the b1 and\n                  b2 buttons\n        !*/\n\n        unsigned long get_slider_size (\n        ) const;\n        /*!\n            ensures\n                - returns the length in pixels the slider should have based on the current\n                  state of this scroll bar\n        !*/\n\n\n        button b1, b2;\n        slider_class slider;\n        bar_orientation ori; \n        filler top_filler, bottom_filler;\n        any_function<void()> scroll_handler;\n\n        long pos;\n        long max_pos; \n        long js;\n\n        timer<scroll_bar> b1_timer;\n        timer<scroll_bar> b2_timer;\n        timer<scroll_bar> top_filler_timer;\n        timer<scroll_bar> bottom_filler_timer;\n        long delayed_pos;\n        std::unique_ptr<scroll_bar_style> style;\n\n        // restricted functions\n        scroll_bar(scroll_bar&);        // copy constructor\n        scroll_bar& operator=(scroll_bar&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class popup_menu \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class menu_item\n    {\n    public:\n        virtual ~menu_item() {}\n\n        virtual rectangle get_left_size (\n        ) const { return rectangle(); }\n        virtual rectangle get_middle_size (\n        ) const = 0; \n        virtual rectangle get_right_size (\n        ) const { return rectangle(); }\n\n        virtual unichar get_hot_key (\n        ) const { return 0; }\n\n        virtual void draw_background (\n            const canvas& ,\n            const rectangle& ,\n            const bool ,\n            const bool \n        ) const {}\n\n        virtual void draw_left (\n            const canvas& ,\n            const rectangle& ,\n            const bool ,\n            const bool \n        ) const {}\n\n        virtual void draw_middle (\n            const canvas& ,\n            const rectangle& ,\n            const bool ,\n            const bool \n        ) const = 0;\n\n        virtual void draw_right (\n            const canvas& ,\n            const rectangle& ,\n            const bool ,\n            const bool \n        ) const {}\n\n        virtual void on_click (\n        ) const {}\n\n        virtual bool has_click_event (\n        ) const { return false; }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_submenu : public menu_item\n    {\n        void initialize (\n            unichar hk\n        )\n        {\n            const dlib::ustring &str = text;\n            if (hk != 0)\n            {\n                std::string::size_type pos = str.find_first_of(hk);\n                if (pos != std::string::npos)\n                {\n                    // now compute the location of the underline bar\n                    rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos);\n                    rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1);\n\n                    underline_p1.x() = r1.left()+1;\n                    underline_p2.x() = r2.left()-1;\n                    underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2;\n                    underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2;\n                }\n            }\n        }\n    public:\n        menu_item_submenu (\n            const std::string& str,\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(hk);\n        }\n\n        menu_item_submenu (\n            const std::wstring& str,\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(hk);\n        }\n\n        menu_item_submenu (\n            const dlib::ustring& str,\n            unichar hk = 0\n        ) : \n            text(str),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(hk);\n        }\n\n        virtual unichar get_hot_key (\n        ) const { return hotkey; }\n\n        virtual rectangle get_middle_size (\n        ) const  \n        {\n            unsigned long width, height;\n            f->compute_size(text,width,height);\n            return rectangle(width+30,height);\n        }\n\n        virtual rectangle get_right_size (\n        ) const  \n        {\n            return rectangle(15, 5);\n        }\n\n        virtual void draw_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            if (enabled && is_selected)\n            {\n                fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100));\n                draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100));\n            }\n        }\n\n        virtual void draw_right (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool \n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            unsigned char color = 0;\n\n            if (enabled == false)\n                color = 128;\n\n            long x, y;\n            x = rect.right() - 7;\n            y = rect.top() + rect.height()/2;\n\n            for ( unsigned long i = 0; i < 5; ++i)\n                draw_line (c, point(x - i, y + i), point(x - i, y - i), color);\n        }\n\n        virtual void draw_middle (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool \n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            if (enabled)\n            {\n                f->draw_string(c,rect,text);\n            }\n            else\n            {\n                f->draw_string(c,rect,text,128);\n            }\n\n            if (underline_p1 != underline_p2)\n            {\n                point base(rect.left(),rect.top());\n                draw_line(c, base+underline_p1, base+underline_p2);\n            }\n        }\n\n    private:\n        dlib::ustring text;\n        const std::shared_ptr<font> f;\n        any_function<void()> action;\n        unichar hotkey;\n        point underline_p1;\n        point underline_p2;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_text : public menu_item\n    {\n        void initialize (\n            const any_function<void()>& event_handler_,\n            unichar hk\n        )\n        {\n            dlib::ustring &str = text;\n            action = event_handler_;\n\n            if (hk != 0)\n            {\n                std::string::size_type pos = str.find_first_of(hk);\n                if (pos != std::string::npos)\n                {\n                    // now compute the location of the underline bar\n                    rectangle r1 = f->compute_cursor_rect( rectangle(100000,100000), str, pos);\n                    rectangle r2 = f->compute_cursor_rect( rectangle(100000,100000), str, pos+1);\n\n                    underline_p1.x() = r1.left()+1;\n                    underline_p2.x() = r2.left()-1;\n                    underline_p1.y() = r1.bottom()-f->height()+f->ascender()+2;\n                    underline_p2.y() = r2.bottom()-f->height()+f->ascender()+2;\n                }\n            }\n        }\n\n    public:\n        template <typename T>\n        menu_item_text (\n            const std::string& str,\n            T& object,\n            void (T::*event_handler_)(),\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(make_mfp(object, event_handler_), hk);\n        }\n\n        menu_item_text (\n            const std::string& str,\n            const any_function<void()>& event_handler_,\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(event_handler_, hk);\n        }\n\n        template <typename T>\n        menu_item_text (\n            const std::wstring& str,\n            T& object,\n            void (T::*event_handler_)(),\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(make_mfp(object, event_handler_), hk);\n        }\n\n        menu_item_text (\n            const std::wstring& str,\n            const any_function<void()>& event_handler_,\n            unichar hk = 0\n        ) : \n            text(convert_to_utf32(str)),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(event_handler_, hk);\n        }\n\n        template <typename T>\n        menu_item_text (\n            const dlib::ustring& str,\n            T& object,\n            void (T::*event_handler_)(),\n            unichar hk = 0\n        ) : \n            text(str),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(make_mfp(object, event_handler_), hk);\n        }\n\n        menu_item_text (\n            const dlib::ustring& str,\n            const any_function<void()>& event_handler_,\n            unichar hk = 0\n        ) : \n            text(str),\n            f(default_font::get_font()),\n            hotkey(hk)\n        {\n            initialize(event_handler_, hk);\n        }\n\n        virtual unichar get_hot_key (\n        ) const { return hotkey; }\n\n        virtual rectangle get_middle_size (\n        ) const  \n        {\n            unsigned long width, height;\n            f->compute_size(text,width,height);\n            return rectangle(width,height);\n        }\n\n        virtual void draw_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            if (enabled && is_selected)\n            {\n                fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(0,200,0,100), rgb_alpha_pixel(0,0,0,100));\n                draw_rectangle(c, rect,rgb_alpha_pixel(0,0,0,100));\n            }\n        }\n\n        virtual void draw_middle (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool \n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            unsigned char color = 0;\n\n            if (enabled == false)\n                color = 128;\n\n            f->draw_string(c,rect,text,color);\n\n            if (underline_p1 != underline_p2)\n            {\n                point base(rect.left(),rect.top());\n                draw_line(c, base+underline_p1, base+underline_p2, color);\n            }\n        }\n\n        virtual void on_click (\n        ) const \n        {\n            action();\n        }\n\n        virtual bool has_click_event (\n        ) const { return true; }\n\n    private:\n        dlib::ustring text;\n        const std::shared_ptr<font> f;\n        any_function<void()> action;\n        unichar hotkey;\n        point underline_p1;\n        point underline_p2;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_separator : public menu_item\n    {\n    public:\n        virtual rectangle get_middle_size (\n        ) const  \n        {\n            return rectangle(10,4);\n        }\n\n        virtual void draw_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool ,\n            const bool \n        ) const \n        {\n            if (c.intersect(rect).is_empty())\n                return;\n\n            point p1(rect.left(),rect.top()+rect.height()/2-1);\n            point p2(rect.right(),rect.top()+rect.height()/2-1);\n\n            point p3(rect.left(),rect.top()+rect.height()/2);\n            point p4(rect.right(),rect.top()+rect.height()/2);\n            draw_line(c, p1,p2,128);\n            draw_line(c, p3,p4,255);\n        }\n\n        virtual void draw_middle (\n            const canvas& ,\n            const rectangle& ,\n            const bool ,\n            const bool \n        ) const \n        {\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class popup_menu : public base_window\n    {\n        /*!\n            INITIAL VALUE\n                - pad == 2\n                - item_pad == 3\n                - cur_rect == rectangle(pad,pad,pad-1,pad-1)\n                - left_width == 0\n                - middle_width == 0\n                - selected_item == 0 \n                - submenu_open == false\n                - items.size() == 0\n                - item_enabled.size() == 0\n                - left_rects.size() == 0\n                - middle_rects.size() == 0\n                - right_rects.size() == 0\n                - line_rects.size() == 0\n                - submenus.size() == 0\n                - hide_handlers.size() == 0\n\n            CONVENTION\n                - pad = 2\n                - item_pad = 3\n                - all of the following arrays have the same size:\n                    - items.size() \n                    - item_enabled.size() \n                    - left_rects.size() \n                    - middle_rects.size() \n                    - right_rects.size() \n                    - line_rects.size() \n                    - submenus.size() \n\n                - win_rect == a rectangle that is the exact size of this window and with\n                  its upper left corner at (0,0)\n                - cur_rect == the rect inside which all the menu items are drawn\n\n                - if (a menu_item is supposed to be selected) then\n                    - selected_item == the index in menus of the menu_item\n                - else\n                    - selected_item == submenus.size()\n\n                - if (there is a selected submenu and it is currently open) then\n                    - submenu_open == true\n                - else \n                    - submenu_open == false\n\n                - for all valid i:\n                    - items[i] == a pointer to the ith menu_item\n                    - item_enabled[i] == true if the ith menu_item is enabled, false otherwise\n                    - left_rects[i] == the left rectangle for the ith menu item\n                    - middle_rects[i] == the middle rectangle for the ith menu item\n                    - right_rects[i] == the right rectangle for the ith menu item\n                    - line_rects[i] == the rectangle for the entire line on which the ith menu\n                      item appears. \n                    - if (submenus[i] != 0) then\n                        - the ith menu item has a submenu and it is pointed to by submenus[i]\n\n                - hide_handlers == an array of all the on_hide events registered for\n                  this popup_menu\n        !*/\n\n    public:\n\n        popup_menu (\n        );\n\n        template <\n            typename menu_item_type\n            >\n        unsigned long add_menu_item (\n            const menu_item_type& new_item\n        )\n        {\n            auto_mutex M(wm);\n            bool t = true;\n            std::unique_ptr<menu_item> item(new menu_item_type(new_item));\n            items.push_back(item);\n            item_enabled.push_back(t);\n\n            // figure out how big the window should be now and what not\n            rectangle left = new_item.get_left_size();\n            rectangle middle = new_item.get_middle_size();\n            rectangle right = new_item.get_right_size();\n\n            bool recalc_rect_positions = false;\n            const rectangle all = left+middle+right;\n\n\n            // make sure left_width contains the max of all the left rectangles\n            if (left.width() > left_width)\n            {\n                left_width = left.width();\n                recalc_rect_positions = true;\n            }\n            // make sure middle_width contains the max of all the middle rectangles\n            if (middle.width() > middle_width)\n            {\n                middle_width = middle.width();\n                recalc_rect_positions = true;\n            }\n\n            // make the current rectangle wider if necessary\n            if (cur_rect.width() < left_width + middle_width + right.width() + 2*item_pad)\n            {\n                cur_rect = resize_rect_width(cur_rect, left_width + middle_width + right.width() + 2*item_pad);\n                recalc_rect_positions = true;\n            }\n\n            const long y = cur_rect.bottom()+1 + item_pad;\n            const long x = cur_rect.left() + item_pad;\n\n            // make the current rectangle taller to account for this new menu item\n            cur_rect.set_bottom(cur_rect.bottom()+all.height() + 2*item_pad);\n\n            // adjust all the saved rectangles since the width of the window changed\n            // or left_width changed\n            if (recalc_rect_positions)\n            {\n                long y = cur_rect.top() + item_pad;\n                for (unsigned long i = 0; i < left_rects.size(); ++i)\n                {\n                    middle_rects[i] = move_rect(middle_rects[i], x+left_width, y);\n                    right_rects[i] = move_rect(right_rects[i], x+cur_rect.width()-right_rects[i].width()-item_pad, y);\n                    line_rects[i] = resize_rect_width(line_rects[i], cur_rect.width());\n\n                    y += line_rects[i].height();\n                }\n            }\n\n            // save the rectangles for later use.  Also position them at the\n            // right spots\n            left = move_rect(left,x,y);\n            middle = move_rect(middle,x+left_width,y);\n            right = move_rect(right,x+cur_rect.width()-right.width()-item_pad,y);\n            rectangle line(move_rect(rectangle(cur_rect.width(),all.height()+2*item_pad), x-item_pad, y-item_pad));\n\n            // make sure the left, middle, and right rectangles are centered in the\n            // line. \n            if (left.height() < all.height())\n                left = translate_rect(left,0, (all.height()-left.height())/2);\n            if (middle.height() < all.height())\n                middle = translate_rect(middle,0, (all.height()-middle.height())/2);\n            if (right.height() < all.height())\n                right = translate_rect(right,0, (all.height()-right.height())/2);\n\n            left_rects.push_back(left);\n            middle_rects.push_back(middle);\n            right_rects.push_back(right);\n            line_rects.push_back(line);\n\n            popup_menu* junk = 0;\n            submenus.push_back(junk);\n\n            win_rect.set_right(cur_rect.right()+pad);\n            win_rect.set_bottom(cur_rect.bottom()+pad);\n            set_size(win_rect.width(),win_rect.height());\n\n            // make it so that nothing is selected\n            selected_item = submenus.size();\n\n            return items.size()-1;\n        }\n        \n        template <\n            typename menu_item_type\n            >\n        unsigned long add_submenu (\n            const menu_item_type& new_item,\n            popup_menu& submenu\n        )\n        {\n            auto_mutex M(wm);\n\n            submenus[add_menu_item(new_item)] = &submenu;\n\n            submenu.set_on_hide_handler(*this,&popup_menu::on_submenu_hide);\n\n            return items.size()-1;\n        }\n\n        void enable_menu_item (\n            unsigned long idx\n        );\n\n        void disable_menu_item (\n            unsigned long idx\n        );\n\n        size_t size (\n        ) const;\n\n        void clear (\n        );\n        \n        void show (\n        );\n\n        void hide (\n        );\n\n        template <typename T>\n        void set_on_hide_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(wm);\n\n            member_function_pointer<> temp;\n            temp.set(object,event_handler);\n\n            // if this handler isn't already registered then add it\n            bool found_handler = false;\n            for (unsigned long i = 0; i < hide_handlers.size(); ++i)\n            {\n                if (hide_handlers[i] == temp)\n                {\n                    found_handler = true;\n                    break;\n                }\n            }\n\n            if (found_handler == false)\n            {\n                hide_handlers.push_back(temp);\n            }\n        }\n\n        void select_first_item (\n        );\n\n        bool forwarded_on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n    private:\n\n        void on_submenu_hide (\n        );\n\n        void on_window_resized(\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long,\n            long x,\n            long y\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void close_submenu (\n        );\n\n        bool display_selected_submenu (\n        );\n        /*!\n            ensures\n                - if (submenus[selected_item] isn't null) then\n                    - displays the selected submenu\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void on_mouse_leave (\n        );\n\n        void paint (\n            const canvas& c\n        );\n\n        const long pad;\n        const long item_pad;\n        rectangle cur_rect; \n        rectangle win_rect; \n        unsigned long left_width;    \n        unsigned long middle_width;    \n        array<std::unique_ptr<menu_item> > items;\n        array<bool> item_enabled;\n        array<rectangle> left_rects;\n        array<rectangle> middle_rects;\n        array<rectangle> right_rects;\n        array<rectangle> line_rects;\n        array<popup_menu*> submenus;\n        unsigned long selected_item;\n        bool submenu_open;\n        array<member_function_pointer<> > hide_handlers;\n\n        // restricted functions\n        popup_menu(popup_menu&);        // copy constructor\n        popup_menu& operator=(popup_menu&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class zoomable_region : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                - min_scale == 0.15\n                - max_scale == 1.0\n                - zoom_increment_ == 0.02\n                - scale == 1.0\n                - mouse_drag_screen == false\n\n\n            CONVENTION\n                - zoom_increment() == zoom_increment_\n                - min_zoom_scale() == min_scale\n                - max_zoom_scale() == max_scale\n                - zoom_scale() == scale\n                - if (the user is currently dragging the graph around via the mouse) then \n                    - mouse_drag_screen == true\n                - else\n                    - mouse_drag_screen == false \n\n                - max_graph_point() == lr_point\n                - display_rect() == display_rect_\n                - gui_to_graph_space(point(display_rect.left(),display_rect.top())) == gr_orig\n        !*/\n\n    public:\n\n        zoomable_region (\n            drawable_window& w,\n            unsigned long events = 0\n        );\n\n        virtual ~zoomable_region (\n        )= 0;\n\n        virtual void set_pos (\n            long x,\n            long y\n        );\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            hsb.set_style(style_.get_horizontal_scroll_bar_style());\n            vsb.set_style(style_.get_vertical_scroll_bar_style());\n\n            // do this just so that everything gets redrawn right\n            set_size(rect.width(), rect.height());\n        }\n\n        void set_zoom_increment (\n            double zi\n        );\n\n        double zoom_increment (\n        ) const;\n\n        void set_max_zoom_scale (\n            double ms \n        );\n\n        void set_min_zoom_scale (\n            double ms \n        );\n\n        double min_zoom_scale (\n        ) const;\n\n        double max_zoom_scale (\n        ) const;\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void set_z_order (\n            long order\n        );\n\n    protected:\n\n        virtual void on_view_changed () {}\n\n        point graph_to_gui_space (\n            const vector<double,2>& p\n        ) const;\n\n        vector<double,2> gui_to_graph_space (\n            const point& p\n        ) const;\n\n        point max_graph_point (\n        ) const;\n\n        rectangle display_rect (\n        ) const;\n\n        double zoom_scale (\n        ) const;\n\n        void set_zoom_scale (\n            double new_scale\n        );\n\n        void center_display_at_graph_point (\n            const vector<double,2>& p\n        );\n\n    // ----------- event handlers ---------------\n\n        void on_wheel_down (\n            unsigned long state\n        );\n\n        void on_wheel_up (\n            unsigned long state\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n    private:\n\n        void on_h_scroll (\n        );\n\n        void on_v_scroll (\n        );\n\n        void redraw_graph (\n        );\n\n        void adjust_origin (\n            const point& gui_p,\n            const vector<double,2>& graph_p\n        );\n        /*!\n            ensures\n                - adjusts gr_orig so that we are as close to the following as possible:\n                    - graph_to_gui_space(graph_p) == gui_p\n                    - gui_to_graph_space(gui_p) == graph_p\n        !*/\n\n\n        vector<double,2> gr_orig; // point in graph space such that it's gui space point is the upper left of display_rect_\n        vector<double,2> lr_point; // point in graph space such that it is at the lower right corner of the screen at max zoom\n\n        mutable std::ostringstream sout;\n\n        double scale; // 0 < scale <= 1\n        double min_scale;\n        double max_scale;\n        double zoom_increment_;\n        rectangle display_rect_;\n\n        bool mouse_drag_screen;  // true if the user is dragging the white background area\n        vector<double,2> drag_screen_point; // the starting point the mouse was at in graph space for the background area drag\n\n        scroll_bar vsb;\n        scroll_bar hsb;\n\n        std::unique_ptr<scrollable_region_style> style;\n\n        // restricted functions\n        zoomable_region(zoomable_region&);        // copy constructor\n        zoomable_region& operator=(zoomable_region&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                - hscroll_bar_inc == 1\n                - vscroll_bar_inc == 1\n                - h_wheel_scroll_bar_inc == 1\n                - v_wheel_scroll_bar_inc == 1\n                - mouse_drag_enabled_ == false\n                - user_is_dragging_mouse == false\n\n            CONVENTION\n                - mouse_drag_enabled() == mouse_drag_enabled_\n                - horizontal_scroll_increment() == hscroll_bar_inc\n                - vertical_scroll_increment() == vscroll_bar_inc\n                - horizontal_mouse_wheel_scroll_increment() == h_wheel_scroll_bar_inc\n                - vertical_mouse_wheel_scroll_increment() == v_wheel_scroll_bar_inc\n                - vertical_scroll_pos() == vsb.slider_pos()\n                - horizontal_scroll_pos() == hsb.slider_pos()\n                - total_rect() == total_rect_\n                - display_rect() == display_rect_\n\n                - if (the user is currently dragging the total_rect around with a mouse drag) then\n                    - user_is_dragging_mouse == true\n                    - drag_origin == the point the mouse was at, with respect to total_rect, \n                      when the dragging started\n                - else\n                    - user_is_dragging_mouse == false \n        !*/\n\n    public:\n\n        scrollable_region (\n            drawable_window& w,\n            unsigned long events = 0\n        );\n\n        virtual ~scrollable_region (\n        ) = 0;\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            hsb.set_style(style_.get_horizontal_scroll_bar_style());\n            vsb.set_style(style_.get_vertical_scroll_bar_style());\n\n            // do this just so that everything gets redrawn right\n            set_size(rect.width(), rect.height());\n        }\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void set_z_order (\n            long order\n        );\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        unsigned long horizontal_mouse_wheel_scroll_increment (\n        ) const;\n\n        unsigned long vertical_mouse_wheel_scroll_increment (\n        ) const;\n\n        void set_horizontal_mouse_wheel_scroll_increment (\n            unsigned long inc\n        );\n\n        void set_vertical_mouse_wheel_scroll_increment (\n            unsigned long inc\n        );\n\n        unsigned long horizontal_scroll_increment (\n        ) const;\n\n        unsigned long vertical_scroll_increment (\n        ) const;\n\n        void set_horizontal_scroll_increment (\n            unsigned long inc\n        );\n\n        void set_vertical_scroll_increment (\n            unsigned long inc\n        );\n\n        long horizontal_scroll_pos (\n        ) const;\n\n        long vertical_scroll_pos (\n        ) const;\n\n        void set_horizontal_scroll_pos (\n            long pos\n        );\n\n        void set_vertical_scroll_pos (\n            long pos\n        );\n\n        virtual void set_pos (\n            long x,\n            long y\n        );\n\n        bool mouse_drag_enabled (\n        ) const;\n\n        void enable_mouse_drag (\n        );\n\n        void disable_mouse_drag (\n        );\n\n    protected:\n\n        virtual void on_view_changed () {}\n\n        const rectangle& display_rect (\n        ) const;\n\n        void set_total_rect_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        const rectangle& total_rect (\n        ) const;\n\n        void scroll_to_rect (\n            const rectangle& r_\n        );\n\n        void on_wheel_down (\n            unsigned long state\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up   (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_wheel_up (\n            unsigned long state\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n    private:\n\n        bool need_h_scroll (\n        ) const;\n        \n        bool need_v_scroll (\n        ) const;\n\n        void on_h_scroll (\n        );\n\n        void on_v_scroll (\n        );\n\n        rectangle total_rect_;\n        rectangle display_rect_;\n        scroll_bar hsb;\n        scroll_bar vsb;\n        unsigned long hscroll_bar_inc;\n        unsigned long vscroll_bar_inc;\n        unsigned long h_wheel_scroll_bar_inc;\n        unsigned long v_wheel_scroll_bar_inc;\n        bool mouse_drag_enabled_;\n        bool user_is_dragging_mouse;\n        point drag_origin;\n        std::unique_ptr<scrollable_region_style> style;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class popup_menu_region \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class popup_menu_region : public drawable \n    {\n        /*!\n            CONVENTION\n                popup_menu_visible() == popup_menu_shown\n        !*/\n\n    public:\n\n        popup_menu_region(  \n            drawable_window& w\n        );\n\n        virtual ~popup_menu_region(\n        );\n\n        void set_size (\n            unsigned long width, \n            unsigned long height\n        );\n\n        void set_rect (\n            const rectangle& new_rect\n        );\n\n        popup_menu& menu (\n        );\n\n        void hide (\n        );\n\n        void disable (\n        );\n\n        bool popup_menu_visible (\n        ) const { auto_mutex M(m); return popup_menu_shown; }\n\n    protected:\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_focus_lost (\n        );\n\n        void on_focus_gained (\n        );\n\n        void on_window_moved(\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_menu_becomes_hidden (\n        );\n\n        void draw (\n            const canvas& \n        ) const;\n\n    private:\n\n        popup_menu menu_;\n        bool popup_menu_shown;\n\n        // restricted functions\n        popup_menu_region(popup_menu_region&);        // copy constructor\n        popup_menu_region& operator=(popup_menu_region&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"base_widgets.cpp\"\n#endif\n\n#endif // DLIB_BASE_WIDGETs_\n\n"
  },
  {
    "path": "dlib/gui_widgets/base_widgets_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BASE_WIDGETs_ABSTRACT_\n#ifdef DLIB_BASE_WIDGETs_ABSTRACT_\n\n#include \"fonts_abstract.h\"\n#include \"drawable_abstract.h\"\n\n#include \"../gui_core.h\"\n#include <string>\n\nnamespace dlib\n{\n\n    /*!\n        GENERAL REMARKS\n            This file contains objects that are useful for creating complex drawable \n            widgets.\n\n        THREAD SAFETY\n            All objects and functions defined in this file are thread safe.  You may\n            call them from any thread without serializing access to them.\n\n        EVENT HANDLERS\n            If you derive from any of the drawable objects and redefine any of the on_*() \n            event handlers then you should ensure that your version calls the same event \n            handler in the base object so that the base class part of your object will also \n            be able to process the event. \n\n            Also note that all event handlers, including the user registered callback\n            functions, are executed in the event handling thread.   Additionally,\n            the drawable::m mutex will always be locked while these event handlers\n            are running.  Also, don't rely on get_thread_id() always returning the \n            same ID from inside event handlers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class draggable\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class draggable : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                draggable_area() == an initial value for its type \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a drawable object that is draggable by the mouse.  \n                You use it by inheriting from it and defining the draw() method and any\n                of the on_*() event handlers you need.  \n\n                This object is draggable by the user when is_enabled() == true and \n                not draggable otherwise.\n        !*/\n\n    public:\n\n        draggable(  \n            drawable_window& w,\n            unsigned long events = 0\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n                - This object will not receive any events or draw() requests until \n                  enable_events() is called\n                - the events flags are passed on to the drawable object's \n                  constructor.\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~draggable(\n        ) = 0;\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        rectangle draggable_area (\n        ) const;\n        /*!\n            ensures\n                - returns the area that this draggable can be dragged around in. \n        !*/\n\n        void set_draggable_area (\n            const rectangle& area \n        ); \n        /*!\n            ensures\n                - #draggable_area() == area\n        !*/\n\n    protected:\n\n        bool is_being_dragged (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - if (this widget is currently being dragged by the user) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        // does nothing by default\n        virtual void on_drag (\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - is_enabled() == true\n                - is_hidden() == false\n                - mutex drawable::m is locked\n                - is called when the user drags this object\n                - get_rect() == the rectangle that defines the new position\n                  of this object.\n                - is_being_dragged() == true\n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n        // does nothing by default\n        virtual void on_drag_stop (\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - mutex drawable::m is locked\n                - is called when the user stops dragging this object\n                - is_being_dragged() == false \n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n    private:\n\n        // restricted functions\n        draggable(draggable&);        // copy constructor\n        draggable& operator=(draggable&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class mouse_over_event \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class mouse_over_event : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                is_mouse_over() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a drawable object with the addition of two events\n                that will alert you when the mouse enters or leaves your drawable object.\n\n                You use it by inheriting from it and defining the draw() method and any\n                of the on_*() event handlers you need.  \n        !*/\n\n    public:\n\n        mouse_over_event(  \n            drawable_window& w,\n            unsigned long events = 0\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n                - #*this will not receive any events or draw() requests until \n                  enable_events() is called\n                - the events flags are passed on to the drawable object's \n                  constructor.\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~mouse_over_event(\n        ) = 0;\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n    protected:\n\n        bool is_mouse_over (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - if (the mouse is currently over this widget) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        // does nothing by default\n        virtual void on_mouse_over (\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - mutex drawable::m is locked\n                - is_enabled() == true\n                - is_hidden() == false\n                - is called whenever this object transitions from the state where\n                  is_mouse_over() == false to is_mouse_over() == true\n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n        // does nothing by default\n        virtual void on_mouse_not_over (\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - mutex drawable::m is locked\n                - is called whenever this object transitions from the state where\n                  is_mouse_over() == true to is_mouse_over() == false \n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n    private:\n\n        // restricted functions\n        mouse_over_event(mouse_over_event&);        // copy constructor\n        mouse_over_event& operator=(mouse_over_event&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class button_action \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button_action : public mouse_over_event \n    {\n        /*!\n            INITIAL VALUE\n                is_depressed() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the clicking action of a push button.  It provides\n                simple callbacks that can be used to make various kinds of button \n                widgets.\n\n                You use it by inheriting from it and defining the draw() method and any\n                of the on_*() event handlers you need.  \n        !*/\n\n    public:\n\n        button_action(  \n            drawable_window& w,\n            unsigned long events = 0\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n                - #*this will not receive any events or draw() requests until \n                  enable_events() is called\n                - the events flags are passed on to the drawable object's \n                  constructor.\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~button_action(\n        ) = 0;\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n    protected:\n\n        bool is_depressed (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - if (this button is currently in a depressed state) then\n                    - the user has left clicked on this drawable and is still\n                      holding the left mouse button down over it.\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        // does nothing by default\n        virtual void on_button_down (\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - mutex drawable::m is locked\n                - is_enabled() == true\n                - is_hidden() == false\n                - the area in parent_window() defined by get_rect() has been invalidated. \n                  (This means you don't have to call invalidate_rectangle())\n                - is called whenever this object transitions from the state where\n                  is_depressed() == false to is_depressed() == true\n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n        // does nothing by default\n        virtual void on_button_up (\n            bool mouse_over\n        ){}\n        /*!\n            requires\n                - enable_events() has been called\n                - mutex drawable::m is locked\n                - the area in parent_window() defined by get_rect() has been invalidated. \n                  (This means you don't have to call invalidate_rectangle())\n                - is called whenever this object transitions from the state where\n                  is_depressed() == true to is_depressed() == false \n                - if (the mouse was over this button when this event occurred) then\n                    - mouse_over == true\n                - else\n                    - mouse_over == false\n            ensures\n                - does not change the state of mutex drawable::m. \n        !*/\n\n    private:\n\n        // restricted functions\n        button_action(button_action&);        // copy constructor\n        button_action& operator=(button_action&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class button\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button : public button_action \n    {\n        /*!\n            INITIAL VALUE\n                name() == \"\"\n                tooltip_text() == \"\" (i.e. there is no tooltip by default)\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple button.  \n\n                When this object is disabled it means it will not respond to user clicks.\n        !*/\n\n    public:\n\n        button(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~button(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*! \n            ensures\n                - if (width and height are big enough to contain the name of this button) then\n                    - #width() == width_\n                    - #height() == height_\n                    - #top() == top()\n                    - #left() == left()\n                    - i.e. The location of the upper left corner of this button stays the\n                      same but its width and height are modified\n        !*/\n\n        void set_name (const std::wstring& name);\n        void set_name (const dlib::ustring& name);\n        void set_name (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - #name() == name\n                - this button has been resized such that it is big enough to contain\n                  the new name.\n            throws\n                - std::bad_alloc\n        !*/\n\n        const std::wstring wname () const;\n        const dlib::string uname () const;\n        const std::string  name (\n        ) const;\n        /*!\n            ensures\n                - returns the name of this button\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_tooltip_text (const std::wstring& text);\n        void set_tooltip_text (const dlib::ustring& text);\n        void set_tooltip_text (\n            const std::string& text\n        );\n        /*!\n            ensures\n                - #tooltip_text() == text\n                - enables the tooltip for this button\n        !*/\n\n        const dlib::ustring tooltip_utext () const;\n        const std::wstring  tooltip_wtext () const;\n        const std::string   tooltip_text (\n        ) const;\n        /*!\n            ensures\n                - returns the text that is displayed in the tooltip for this button\n        !*/\n\n        bool is_depressed (\n        ) const;\n        /*!\n            ensures\n                - if (this button is currently in a depressed state) then\n                    - the user has left clicked on this widget and is still\n                      holding the left mouse button down over it.\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from button_style\n            ensures\n                - this button object will draw itself using the given\n                  button style\n        !*/\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the button is \n                  clicked by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_click_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the button is clicked by \n                  the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)(button& self)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - &self == this\n                - the event_handler function is called on object when the button is \n                  clicked by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_sourced_click_handler (\n            const any_function<void(button& self)>& event_handler\n        );\n        /*!\n            ensures\n                - &self == this\n                - the event_handler function is called when the button is clicked by \n                  the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_button_down_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user causes \n                  the button to go into its depressed state.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_button_down_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user causes the button \n                  to go into its depressed state.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_button_up_handler (\n            T& object,\n            void (T::*event_handler)(bool mouse_over)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user causes \n                  the button to go into its non-depressed state.\n                - if (the mouse is over this button when this event occurs) then\n                    - mouse_over == true\n                - else\n                    - mouse_over == false\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_button_up_handler (\n            const any_function<void(bool mouse_over)>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user causes the \n                  button to go into its non-depressed state.\n                - if (the mouse is over this button when this event occurs) then\n                    - mouse_over == true\n                - else\n                    - mouse_over == false\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_button_down_handler (\n            T& object,\n            void (T::*event_handler)(button& self)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - &self == this\n                - the event_handler function is called on object when the user causes \n                  the button to go into its depressed state.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_sourced_button_down_handler (\n            const any_function<void(button& self)>& event_handler\n        );\n        /*!\n            ensures\n                - &self == this\n                - the event_handler function is called when the user causes the button \n                  to go into its depressed state.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_button_up_handler (\n            T& object,\n            void (T::*event_handler)(bool mouse_over, button& self)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - &self == this\n                - the event_handler function is called on object when the user causes \n                  the button to go into its non-depressed state.\n                - if (the mouse is over this button when this event occurs) then\n                    - mouse_over == true\n                - else\n                    - mouse_over == false\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_sourced_button_up_handler (\n            const any_function<void(bool mouse_over, button& self)>& event_handler\n        );\n        /*!\n            ensures\n                - &self == this\n                - the event_handler function is called when the user causes the \n                  button to go into its non-depressed state.\n                - if (the mouse is over this button when this event occurs) then\n                    - mouse_over == true\n                - else\n                    - mouse_over == false\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        button(button&);        // copy constructor\n        button& operator=(button&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class scroll_bar \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                orientation() == a value given to the constructor.\n                max_slider_pos() == 0\n                slider_pos() == 0\n                jump_size() == 10\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a scroll bar.  The slider_pos() of the scroll bar\n                ranges from 0 to max_slider_pos().  The 0 position of the scroll_bar is\n                in the top or left side of the scroll_bar depending on its orientation.\n\n                When this object is disabled it means it will not respond to user clicks.\n        !*/\n\n    public:\n        enum bar_orientation \n        {\n            HORIZONTAL,\n            VERTICAL\n        };\n\n        scroll_bar(  \n            drawable_window& w,\n            bar_orientation orientation \n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #orientation() == orientation \n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~scroll_bar(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        bar_orientation orientation (\n        ) const;\n        /*!\n            ensures\n                - returns the orientation of this scroll_bar \n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from scroll_bar_style \n            ensures\n                - this scroll_bar object will draw itself using the given\n                  scroll bar style\n        !*/\n\n        void set_length (\n            unsigned long length,\n        );\n        /*! \n            ensures\n                - if (orientation() == HORIZONTAL) then\n                    - #width() == max(length,1)\n                - else\n                    - #height() == max(length,1)\n        !*/\n\n        long max_slider_pos (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum value that slider_pos() can take. \n        !*/\n\n        void set_max_slider_pos (\n            long mpos\n        );\n        /*!\n            ensures\n                - if (mpos < 0) then\n                    - #max_slider_pos() == 0\n                - else\n                    - #max_slider_pos() == mpos\n                - if (slider_pos() > #max_slider_pos()) then\n                    - #slider_pos() == #max_slider_pos() \n                - else\n                    - #slider_pos() == slider_pos()\n        !*/\n\n        void set_slider_pos (\n            unsigned long pos\n        );\n        /*!\n            ensures\n                - if (pos < 0) then\n                    - #slider_pos() == 0\n                - else if (pos > max_slider_pos()) then\n                    - #slider_pos() == max_slider_pos()\n                - else\n                    - #slider_pos() == pos\n        !*/\n\n        long slider_pos (\n        ) const;\n        /*!\n            ensures\n                - returns the current position of the slider box within the scroll bar.\n        !*/\n\n        long jump_size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of positions that the slider bar will jump when the\n                  user clicks on the empty gaps above or below the slider bar.\n                  (note that the slider will jump less than the jump size if it hits the \n                  end of the scroll bar)\n        !*/\n\n        void set_jump_size (\n            long js \n        );\n        /*!\n            ensures\n                - if (js < 1) then\n                    - #jump_size() == 1\n                - else\n                    - #jump_size() == js \n        !*/\n\n\n        template <\n            typename T\n            >\n        void set_scroll_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T\n            ensures\n                - The event_handler function is called whenever the user causes the slider box\n                  to move.  \n                - This event is NOT triggered by calling set_slider_pos()\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_scroll_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - The event_handler function is called whenever the user causes the slider box\n                  to move.  \n                - This event is NOT triggered by calling set_slider_pos()\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        scroll_bar(scroll_bar&);        // copy constructor\n        scroll_bar& operator=(scroll_bar&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class widget_group \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class widget_group : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                size() == 0\n                get_rect().is_empty() == true\n                left() == 0\n                top() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a grouping of drawable widgets.  It doesn't draw \n                anything itself, rather it lets you manipulate the position, enabled\n                status, and visibility of a set of widgets as a group.\n        !*/\n\n    public:\n        widget_group(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~widget_group(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released.\n        !*/\n\n        void empty (\n        );\n        /*!\n            ensures\n                - #size() == 0\n        !*/\n\n        void fit_to_contents (\n        );\n        /*!\n            ensures\n                - does not change the position of this object. \n                  (i.e. the upper left corner of get_rect() remains at the same position)\n                - if (size() == 0) then\n                    - #get_rect().is_empty() == true\n                - else\n                    - recursively calls fit_to_contents() on any widget_groups inside\n                      this object.\n                    - #get_rect() will be the smallest rectangle that contains all the \n                      widgets in this group and the upper left corner of get_rect(). \n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of widgets currently in *this.\n        !*/\n\n        void add (\n            drawable& widget,\n            unsigned long x,\n            unsigned long y\n        );\n        /*!\n            ensures\n                - #is_member(widget) == true\n                - if (is_member(widget) == false) then\n                    - #size() == size() + 1\n                - else\n                    - #size() == size()\n                - The following conditions apply to this function as well as to all of the \n                  following functions so long as is_member(widget) == true: \n                  enable(), disable(), hide(), show(), set_z_order(), and set_pos().\n                    - #widget.left() == left()+x\n                    - #widget.width() == widget.width()\n                    - #widget.top() == top()+y\n                    - #widget.height() == widget.height()\n                    - #widget.is_hidden() == is_hidden()\n                    - #widget.is_enabled() == is_enabled()\n                    - #widget.z_order() == z_order()\n            throws\n                - std::bad_alloc\n        !*/\n\n        bool is_member (\n            const drawable& widget\n        ) const;\n        /*!\n            ensures\n                - returns true if widget is currently in this object, returns false otherwise.\n        !*/\n\n        void remove (\n            const drawable& widget\n        );\n        /*!\n            ensures\n                - #is_member(widget) == false \n                - if (is_member(widget) == true) then\n                    - #size() == size() - 1\n                - else\n                    - #size() == size()\n        !*/\n\n    protected:\n\n        // this object doesn't draw anything but also isn't abstract\n        void draw (\n            const canvas& c\n        ) const {}\n\n    private:\n\n        // restricted functions\n        widget_group(widget_group&);        // copy constructor\n        widget_group& operator=(widget_group&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class image_widget \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class image_widget : public draggable\n    {\n        /*!\n            INITIAL VALUE\n                draggable_area() == an initial value for its type.\n                This object isn't displaying anything. \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a draggable image.  You give it an image to display\n                by calling set_image().\n\n                Also note that initially the draggable area is empty so it won't be \n                draggable unless you call set_draggable_area() to some non-empty region.\n\n                The image is drawn such that:\n                    - the pixel img[0][0] is the upper left corner of the image.\n                    - the pixel img[img.nr()-1][0] is the lower left corner of the image.\n                    - the pixel img[0][img.nc()-1] is the upper right corner of the image.\n                    - the pixel img[img.nr()-1][img.nc()-1] is the lower right corner of the image.\n                \n        !*/\n\n    public:\n\n        image_widget(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~image_widget(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename image_type \n            >\n        void set_image (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h\n                - pixel_traits<typename image_type::type> must be defined \n            ensures\n                - #width() == img.nc()\n                - #height() == img.nr()\n                - #*this widget is now displaying the given image img.\n        !*/\n\n    private:\n\n        // restricted functions\n        image_widget(image_widget&);        // copy constructor\n        image_widget& operator=(image_widget&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class tooltip \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class tooltip : public mouse_over_event \n    {\n        /*!\n            INITIAL VALUE\n                - text() == \"\"\n                - the tooltip is inactive until the text is changed to\n                  a non-empty string.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a region on a window where if the user\n                hovers the mouse over this region a tooltip with a message\n                appears.\n        !*/\n\n    public:\n\n        tooltip(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~tooltip(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width_, \n            unsigned long height_ \n        );\n        /*!\n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified\n        !*/\n\n        void set_text (const std::wstring& str);\n        void set_text (const dlib::ustring& str);\n        void set_text (\n            const std::string& str\n        );\n        /*!\n            ensures\n                - #text() == str\n                - activates the tooltip.  i.e. after this function the tooltip\n                  will display on the screen when the user hovers the mouse over it\n        !*/\n\n        const std::wstring  wtext () const;\n        const dlib::ustring utext () const;\n        const std::string   text (\n        ) const;\n        /*!\n            ensures\n                - returns the text that is displayed inside this\n                  tooltip\n        !*/\n\n    private:\n\n        // restricted functions\n        tooltip(tooltip&);        // copy constructor\n        tooltip& operator=(tooltip&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // popup menu stuff  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class menu_item\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                menu item in a popup_menu must implement.\n\n                Note that a menu_item is drawn as 3 separate pieces:\n                    ---------------------------------\n                    | left | middle |         right |\n                    ---------------------------------\n\n                Also note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n\n    public:\n\n        virtual ~menu_item() {}\n\n        virtual void on_click (\n        ) const {}\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - if (has_click_event()) then\n                    - this function is called when the user clicks on this menu_item\n        !*/\n\n        virtual bool has_click_event (\n        ) const { return false; }\n        /*!\n            ensures\n                - if (this menu_item wants to receive on_click events) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        virtual unichar get_hot_key (\n        ) const { return 0; }\n        /*!\n            ensures\n                - if (this menu item has a keyboard hot key) then\n                    - returns the unicode value of the key\n                - else\n                    - returns 0\n        !*/\n\n        virtual rectangle get_left_size (\n        ) const { return rectangle(); } // return empty rect by default\n        /*!\n            ensures\n                - returns the dimensions of the left part of the menu_item\n        !*/\n\n        virtual rectangle get_middle_size (\n        ) const = 0; \n        /*!\n            ensures\n                - returns the dimensions of the middle part of the menu_item\n        !*/\n\n        virtual rectangle get_right_size (\n        ) const { return rectangle(); } // return empty rect by default\n        /*!\n            ensures\n                - returns the dimensions of the right part of the menu_item\n        !*/\n\n        virtual void draw_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const {}\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            requires\n                - c == the canvas to draw on\n                - rect == the rectangle in which we are to draw the background\n                - enabled == true if the menu_item is to be drawn enabled\n                - is_selected == true if the menu_item is to be drawn selected\n            ensures\n                - draws the background of the menu_item on the canvas c at the location \n                  given by rect.  \n        !*/\n\n        virtual void draw_left (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const {}\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            requires\n                - c == the canvas to draw on\n                - rect == the rectangle in which we are to draw the background\n                - enabled == true if the menu_item is to be drawn enabled\n                - is_selected == true if the menu_item is to be drawn selected\n            ensures\n                - draws the left part of the menu_item on the canvas c at the location \n                  given by rect.  \n        !*/\n\n        virtual void draw_middle (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            requires\n                - c == the canvas to draw on\n                - rect == the rectangle in which we are to draw the background\n                - enabled == true if the menu_item is to be drawn enabled\n                - is_selected == true if the menu_item is to be drawn selected\n            ensures\n                - draws the middle part of the menu_item on the canvas c at the location \n                  given by rect.  \n        !*/\n\n        virtual void draw_right (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const bool is_selected\n        ) const {}\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            requires\n                - c == the canvas to draw on\n                - rect == the rectangle in which we are to draw the background\n                - enabled == true if the menu_item is to be drawn enabled\n                - is_selected == true if the menu_item is to be drawn selected\n            ensures\n                - draws the right part of the menu_item on the canvas c at the location \n                  given by rect.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_text : public menu_item\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple text menu item\n        !*/\n\n    public:\n\n        template <\n            typename T\n            >\n        menu_item_text (\n            const std::string& str,\n            T& object,\n            void (T::*on_click_handler)(),\n            unichar hotkey = 0\n        ); \n        /*!\n            ensures\n                - The text of this menu item will be str\n                - the on_click_handler function is called on object when this menu_item \n                  clicked by the user.\n                - #get_hot_key() == hotkey\n        !*/\n        \n        menu_item_text (\n            const std::string& str,\n            const any_function<void()>& on_click_handler,\n            unichar hotkey = 0\n        ); \n        /*!\n            ensures\n                - The text of this menu item will be str\n                - the on_click_handler function is called when this menu_item \n                  clicked by the user.\n                - #get_hot_key() == hotkey\n        !*/\n        \n        // overloads for wide character strings\n        template <\n            typename T\n            >\n        menu_item_text (\n            const std::wstring& str,\n            T& object,\n            void (T::*on_click_handler)(),\n            unichar hotkey = 0\n        ); \n\n        menu_item_text (\n            const std::wstring& str,\n            const any_function<void()>& on_click_handler,\n            unichar hotkey = 0\n        ); \n\n        template <\n            typename T\n            >\n        menu_item_text (\n            const dlib::ustring& str,\n            T& object,\n            void (T::*on_click_handler)(),\n            unichar hotkey = 0\n        ); \n\n        template <\n            typename T\n            >\n        menu_item_text (\n            const dlib::ustring& str,\n            const any_function<void()>& on_click_handler,\n            unichar hotkey = 0\n        ); \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_submenu : public menu_item\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple text item intended to be used with\n                submenus inside a popup_menu.\n        !*/\n\n    public:\n\n        menu_item_submenu (\n            const std::string& str,\n            unichar hotkey = 0\n        ); \n        /*!\n            ensures\n                - The text of this menu item will be str\n                - #get_hot_key() == hotkey\n        !*/\n\n        //overloads for wide character strings\n        menu_item_submenu (\n            const std::wstring& str,\n            unichar hotkey = 0\n        ); \n\n        menu_item_submenu (\n            const dlib::ustring& str,\n            unichar hotkey = 0\n        ); \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class menu_item_separator : public menu_item\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a horizontal separator in a popup menu \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class popup_menu : public base_window\n    {\n        /*!\n            INITIAL VALUE\n                - size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a popup menu window capable of containing\n                menu_item objects.\n        !*/\n\n    public:\n\n        popup_menu (\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n                - dlib::gui_error\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc \n                  if this exception is thrown then *this is unusable\n                  until clear() is called and succeeds\n        !*/\n\n        template <\n            typename menu_item_type\n            >\n        unsigned long add_menu_item (\n            const menu_item_type& new_item\n        );\n        /*!\n            requires\n                - menu_item_type == a type that inherits from menu_item \n            ensures\n                - adds new_item onto the bottom of this popup_menu. \n                - returns size() \n                  (This is also the index by which this item can be\n                  referenced by the enable_menu_item() and disable_menu_item()\n                  functions.)\n        !*/\n        \n        template <\n            typename menu_item_type\n            >\n        unsigned long add_submenu (\n            const menu_item_type& new_item,\n            popup_menu& submenu\n        );\n        /*!\n            requires\n                - menu_item_type == a type that inherits from menu_item \n            ensures\n                - adds new_item onto the bottom of this popup_menu. \n                - when the user puts the mouse above this menu_item the given\n                  submenu popup_menu will be displayed.\n                - returns size() \n                  (This is also the index by which this item can be\n                  referenced by the enable_menu_item() and disable_menu_item()\n                  functions.)\n        !*/\n\n        void enable_menu_item (\n            unsigned long idx\n        );\n        /*!\n            requires\n                - idx < size()\n            ensures\n                - the menu_item in this with the index idx has been enabled \n        !*/\n\n        void disable_menu_item (\n            unsigned long idx\n        );\n        /*!\n            requires\n                - idx < size()\n            ensures\n                - the menu_item in this with the index idx has been disabled\n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of menu_item objects in this popup_menu\n        !*/\n\n        template <typename T>\n        void set_on_hide_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            ensures\n                - the event_handler function is called on object when this popup_menu\n                  hides itself due to an action by the user. \n                - Note that you can register multiple handlers for this event. \n        !*/\n\n        void select_first_item (\n        );\n        /*!\n            ensures\n                - causes this popup menu to highlight the first \n                  menu item that it contains which has a click event \n                  and is enabled.\n        !*/\n\n        bool forwarded_on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n        /*!\n            requires\n                - key, is_printable, and state are the variables from the\n                  base_window::on_keydown() event\n            ensures\n                - forwards this keyboard event to this popup window so that it\n                  may deal with keyboard events from other windows.\n                - if (this popup_menu uses the keyboard event) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n    private:\n\n        // restricted functions\n        popup_menu(popup_menu&);        // copy constructor\n        popup_menu& operator=(popup_menu&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class popup_menu_region \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class popup_menu_region : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                - popup_menu_visible() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a region on a window where if the user\n                right clicks the mouse over this region a popup_menu pops up.\n                \n                Note that this widget doesn't actually draw anything, it just \n                provides a region the user can click on to get a popup menu.\n        !*/\n\n    public:\n\n        popup_menu_region(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~popup_menu_region(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width_, \n            unsigned long height_ \n        );\n        /*!\n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified\n        !*/\n\n        void set_rect (\n            const rectangle& new_rect\n        );\n        /*!\n            ensures\n                - #get_rect() == new_rect\n        !*/\n\n        bool popup_menu_visible (\n        ) const;\n        /*!\n            ensures\n                - if (the popup menu is currently visible on the screen) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        popup_menu& menu (\n        );\n        /*!\n            ensures\n                - returns a reference to the popup_menu for this object. It is\n                  the menu that is displayed when the user right clicks on \n                  this widget\n        !*/\n\n    private:\n\n        // restricted functions\n        popup_menu_region(popup_menu_region&);        // copy constructor\n        popup_menu_region& operator=(popup_menu_region&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class zoomable_region \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class zoomable_region : public drawable \n    {\n        /*\n            INITIAL VALUE\n                - min_zoom_scale() == 0.15\n                - max_zoom_scale() == 1.0\n                - zoom_increment() == 0.90\n                - zoom_scale() == 1.0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a 2D Cartesian graph that you can zoom into and\n                out of.  It is a graphical widget that draws a rectangle with \n                a horizontal and vertical scroll bar that allow the user to scroll\n                around on a Cartesian graph that is much larger than the actual \n                area occupied by this object on the screen.  It also allows \n                the user to zoom in and out.\n\n                To use this object you inherit from it and make use of its public and\n                protected member functions.  It provides functions for converting between\n                pixel locations and the points in our 2D Cartesian graph so that when the \n                user is scrolling/zooming the widget you can still determine where\n                things are to be placed on the screen and what screen pixels correspond\n                to in the Cartesian graph.\n\n                Note that the Cartesian graph in this object is bounded by the point\n                (0,0), corresponding to the upper left corner when we are zoomed all \n                the way out, and max_graph_point() which corresponds to the lower right \n                corner when zoomed all the way out. The value of max_graph_point() is \n                determined automatically from the size of this object's on screen \n                rectangle and the value of min_zoom_scale() which determines how far \n                out you can zoom.\n        */\n\n    public:\n\n        zoomable_region (\n            drawable_window& w,\n            unsigned long events = 0\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n                - This object will not receive any events or draw() requests until \n                  enable_events() is called\n                - the events flags are passed on to the drawable object's \n                  constructor.\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~zoomable_region (\n        ) = 0;\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from scrollable_region_style \n            ensures\n                - this zoomable_region object will draw itself using the given\n                  style\n        !*/\n\n        void set_zoom_increment (\n            double zi\n        );\n        /*!\n            requires\n                - 0 < zi < 1\n            ensures\n                - #zoom_increment() == zi\n        !*/\n\n        double zoom_increment (\n        ) const;\n        /*!\n            ensures\n                - When the user zooms in using the mouse wheel:\n                    - #zoom_scale() == zoom_scale() / zoom_increment()\n                - When the user zooms out using the mouse wheel:\n                    - #zoom_scale() == zoom_scale() * zoom_increment()\n                - So this function returns the number that determines how much the zoom\n                  changes when the mouse wheel is moved.\n        !*/\n\n        void set_max_zoom_scale (\n            double ms \n        );\n        /*!\n            requires\n                - ms > 0\n            ensures\n                - #max_zoom_scale() == ms\n        !*/\n\n        void set_min_zoom_scale (\n            double ms \n        );\n        /*!\n            requires\n                - ms > 0\n            ensures\n                - #min_zoom_scale() == ms\n        !*/\n\n        double min_zoom_scale (\n        ) const;\n        /*!\n            ensures\n                - returns the minimum allowed value of zoom_scale()\n                  (i.e. this is the number that determines how far out the user is allowed to zoom)\n        !*/\n\n        double max_zoom_scale (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum allowed value of zoom_scale() \n                  (i.e. this is the number that determines how far in the user is allowed to zoom)\n        !*/\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n        /*! \n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this button stays the\n                  same but its width and height are modified\n        !*/\n\n    protected:\n\n        rectangle display_rect (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns the rectangle on the screen that contains the Cartesian\n                  graph in this widget.  I.e. this is the area of this widget minus\n                  the area taken up by the scroll bars and border decorations.\n        !*/\n\n        point graph_to_gui_space (\n            const vector<double,2>& graph_point\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns the location of the pixel on the screen that corresponds\n                  to the given point in Cartesian graph space\n        !*/\n\n        vector<double,2> gui_to_graph_space (\n            const point& pixel_point\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns the point in Cartesian graph space that corresponds to the given\n                  pixel location\n        !*/\n\n        vector<double,2> max_graph_point (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns the pixel farthest from the graph point (0,0) that is still\n                  in the graph.  I.e. returns the point in graph space that corresponds\n                  to the lower right corner of the display_rect() when we are zoomed\n                  all the way out.\n        !*/\n\n        double zoom_scale (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns a double Z that represents the current zoom.  \n                    - Smaller values of Z represent the user zooming out. \n                    - Bigger values of Z represent the user zooming in.  \n                    - The default unzoomed case is when Z == 1\n                    - objects should be drawn such that they are zoom_scale() \n                      times their normal size\n        !*/\n\n        void set_zoom_scale (\n            double new_scale\n        );\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - invalidates the display_rect() so that it will be redrawn\n                - if (min_zoom_scale() <= new_scale && new_scale <= max_zoom_scale()) then\n                    - #zoom_scale() == new_scale\n                - else if (new_scale < min_zoom_scale()) then\n                    - #zoom_scale() == min_zoom_scale() \n                - else if (new_scale > max_zoom_scale()) then\n                    - #zoom_scale() == max_zoom_scale() \n        !*/\n\n        void center_display_at_graph_point (\n            const vector<double,2>& graph_point\n        );\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - causes the given graph point to be centered in the display\n                  if possible\n                - invalidates the display_rect() so that it will be redrawn\n        !*/\n\n        virtual void on_view_changed (\n        ) {}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex drawable::m is locked\n            ensures\n                - on_view_changed() is called whenever the user causes the view of the\n                  zoomable_region to change.  That is, this function is called when the\n                  user scrolls or zooms around in the region.\n        !*/\n\n    // ---------------------------- event handlers ----------------------------\n    // The following event handlers are used in this object.  So if you\n    // use any of them in your derived object you should pass the events \n    // back to it so that they still operate unless you wish to hijack the\n    // event for your own reasons (e.g. to override the mouse drag this object\n    // performs)\n\n        void on_wheel_down (unsigned long state);\n        void on_wheel_up (unsigned long state);\n        void on_mouse_move ( unsigned long state, long x, long y);\n        void on_mouse_up ( unsigned long btn, unsigned long state, long x, long y);\n        void on_mouse_down ( unsigned long btn, unsigned long state, long x, long y, bool is_double_click);\n        void draw ( const canvas& c) const;\n\n    private:\n\n        // restricted functions\n        zoomable_region(zoomable_region&);        // copy constructor\n        zoomable_region& operator=(zoomable_region&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                - horizontal_scroll_pos() == 0\n                - horizontal_scroll_increment() == 1\n                - horizontal_mouse_wheel_scroll_increment() == 1\n                - vertical_scroll_pos() == 0\n                - vertical_scroll_increment() == 1\n                - vertical_mouse_wheel_scroll_increment() == 1\n                - total_rect().empty() == true\n                - mouse_drag_enabled() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a 2D region of arbitrary size that is displayed\n                within a possibly smaller scrollable gui widget.  That is, it is a \n                graphical widget that draws a rectangle with a horizontal and vertical \n                scroll bar that allows the user to scroll around on a region that is much \n                larger than the actual area occupied by this object on the screen. \n                \n                To use this object you inherit from it and make use of its public and\n                protected member functions.  It provides a function, total_rect(), that\n                tells you where the 2D region is on the screen.  You draw your stuff \n                inside total_rect() as you would normally except that you only modify \n                pixels that are also inside display_rect().  When the user moves the\n                scroll bars the position of total_rect() is updated accordingly, causing\n                the widget's content to scroll across the screen. \n        !*/\n\n    public:\n        scrollable_region (\n            drawable_window& w,\n            unsigned long events = 0\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n                - This object will not receive any events or draw() requests until \n                  enable_events() is called\n                - the events flags are passed on to the drawable object's \n                  constructor.\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~scrollable_region (\n        ) = 0;\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from scrollable_region_style \n            ensures\n                - this scrollable_region object will draw itself using the given\n                  style\n        !*/\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n        /*! \n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified.\n        !*/\n\n        long horizontal_scroll_pos (\n        ) const;\n        /*!\n            ensures\n                - returns the current position of the horizontal scroll bar.\n                  0 means it is at the far left while bigger values represent\n                  scroll positions closer to the right.\n        !*/\n\n        long vertical_scroll_pos (\n        ) const;\n        /*!\n            ensures\n                - returns the current position of the vertical scroll bar.\n                  0 means it is at the top and bigger values represent scroll positions\n                  closer to the bottom.\n        !*/\n\n        void set_horizontal_scroll_pos (\n            long pos\n        );\n        /*!\n            ensures\n                - if (pos is a valid horizontal scroll position) then\n                    - #horizontal_scroll_pos() == pos\n                - else\n                    - #horizontal_scroll_pos() == the valid scroll position closest to pos\n        !*/\n\n        void set_vertical_scroll_pos (\n            long pos\n        );\n        /*!\n            ensures\n                - if (pos is a valid vertical scroll position) then\n                    - #vertical_scroll_pos() == pos\n                - else\n                    - #vertical_scroll_pos() == the valid scroll position closest to pos\n        !*/\n\n        unsigned long horizontal_mouse_wheel_scroll_increment (\n        ) const;\n        /*!\n            ensures\n                - returns the number of positions the horizontal scroll bar\n                  moves when the user scrolls the mouse wheel.  \n        !*/\n\n        unsigned long vertical_mouse_wheel_scroll_increment (\n        ) const;\n        /*!\n            ensures\n                - returns the number of positions the vertical scroll bar\n                  moves when the user scrolls the mouse wheel.  \n        !*/\n\n        void set_horizontal_mouse_wheel_scroll_increment (\n            unsigned long inc\n        );\n        /*!\n            ensures\n                - #horizontal_mouse_wheel_scroll_increment() == inc\n        !*/\n\n        void set_vertical_mouse_wheel_scroll_increment (\n            unsigned long inc\n        );\n        /*!\n            ensures\n                - #vertical_mouse_wheel_scroll_increment() == inc\n        !*/\n\n\n        unsigned long horizontal_scroll_increment (\n        ) const;\n        /*!\n            ensures\n                - returns the number of pixels that total_rect() is moved by when\n                  the horizontal scroll bar moves by one position\n        !*/\n\n        unsigned long vertical_scroll_increment (\n        ) const;\n        /*!\n            ensures\n                - returns the number of pixels that total_rect() is moved by when\n                  the vertical scroll bar moves by one position\n        !*/\n\n        void set_horizontal_scroll_increment (\n            unsigned long inc\n        );\n        /*!\n            ensures\n                - #horizontal_scroll_increment() == inc\n        !*/\n\n        void set_vertical_scroll_increment (\n            unsigned long inc\n        );\n        /*!\n            ensures\n                - #vertical_scroll_increment() == inc\n        !*/\n\n        bool mouse_drag_enabled (\n        ) const;\n        /*!\n            ensures\n                - if (the user can drag this contents of this widget around by\n                  holding down the left mouse button and dragging) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void enable_mouse_drag (\n        );\n        /*!\n            ensures\n                - #mouse_drag_enabled() == true\n        !*/\n\n        void disable_mouse_drag (\n        );\n        /*!\n            ensures\n                - #mouse_drag_enabled() == false\n        !*/\n\n    protected:\n\n        rectangle display_rect (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns the rectangle on the screen that contains the scrollable \n                  area in this widget.  I.e. this is the area of this widget minus\n                  the area taken up by the scroll bars and border decorations.\n        !*/\n\n        void set_total_rect_size (\n            unsigned long width,\n            unsigned long height\n        );\n        /*!\n            requires\n                - mutex drawable::m is locked\n                - (width > 0 && height > 0) || (width == 0 && height == 0)\n            ensures\n                - #total_rect().width()  == width\n                - #total_rect().height() == height \n                - The scroll bars as well as the position of #total_rect() \n                  is updated so that the total rect is still in the correct\n                  position with respect to the scroll bars.\n        !*/\n\n        const rectangle& total_rect (\n        ) const;\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - returns a rectangle that represents the entire scrollable\n                  region inside this widget, even the parts that are outside\n                  display_rect().  \n        !*/\n\n        void scroll_to_rect (\n            const rectangle& r\n        );\n        /*!\n            requires\n                - mutex drawable::m is locked\n            ensures\n                - Adjusts the scroll bars of this object so that the part of \n                  the total_rect() rectangle that overlaps with r is displayed in \n                  the display_rect() rectangle on the screen.\n        !*/\n\n        virtual void on_view_changed (\n        ) {}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex drawable::m is locked\n            ensures\n                - on_view_changed() is called whenever the user causes the view of the\n                  scrollable_region to change.  That is, this function is called when the\n                  user scrolls around in the region.\n        !*/\n\n    // ---------------------------- event handlers ----------------------------\n    // The following event handlers are used in this object.  So if you\n    // use any of them in your derived object you should pass the events \n    // back to it so that they still operate unless you wish to hijack the\n    // event for your own reasons (e.g. to override the mouse wheel action \n    // this object performs)\n\n        void on_wheel_down (unsigned long state);\n        void on_wheel_up   (unsigned long state);\n        void on_mouse_move (unsigned long state, long x, long y);\n        void on_mouse_down (unsigned long btn, unsigned long state, long x, long y, bool is_double_click);\n        void on_mouse_up   (unsigned long btn, unsigned long state, long x, long y);\n        void draw (const canvas& c) const;\n\n    private:\n\n        // restricted functions\n        scrollable_region(scrollable_region&);        // copy constructor\n        scrollable_region& operator=(scrollable_region&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BASE_WIDGETs_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/gui_widgets/canvas_drawing.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CANVAS_DRAWINg_CPP_\n#define DLIB_CANVAS_DRAWINg_CPP_\n\n#include \"canvas_drawing.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_sunken_rectangle (\n        const canvas& c,\n        const rectangle& border,\n        unsigned char alpha\n    )\n    {\n        rectangle area = border.intersect(c);\n        if (area.is_empty() == false)\n        {\n            const rgb_alpha_pixel dark_gray(64,64,64,alpha);\n            const rgb_alpha_pixel gray(128,128,128,alpha);\n            const rgb_alpha_pixel white(255,255,255,alpha);\n            const rgb_alpha_pixel background(212,208,200,alpha);\n\n            draw_line(c,point(border.left(),border.top()),point(border.right()-1,border.top()),gray);\n\n            draw_line(c,point(border.left(),border.bottom()),point(border.right(),border.bottom()),white);\n            draw_line(c,point(border.left()+1,border.bottom()-1),point(border.right()-1,border.bottom()-1),background);\n\n            draw_line(c,point(border.left(),border.top()+1),point(border.left(),border.bottom()-1),gray);\n\n            draw_line(c,point(border.right(),border.top()),point(border.right(),border.bottom()-1),white);\n            draw_line(c,point(border.right()-1,border.top()+1),point(border.right()-1,border.bottom()-2),background);\n\n            draw_line(c,point(border.left()+1,border.top()+1),point(border.left()+1,border.bottom()-2),dark_gray);\n            draw_line(c,point(border.left()+1,border.top()+1),point(border.right()-2,border.top()+1),dark_gray);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_down (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha\n    )\n    {\n        rectangle area = btn.intersect(c);\n        if (area.is_empty() == false)\n        {\n            const rgb_alpha_pixel dark_gray(64,64,64,alpha);\n            const rgb_alpha_pixel gray(128,128,128,alpha);\n            const rgb_alpha_pixel black(0,0,0,alpha);\n\n            draw_line(c,point(btn.left(),btn.top()),point(btn.right(),btn.top()),black);\n\n            draw_line(c,point(btn.left()+1,btn.bottom()),point(btn.right(),btn.bottom()),dark_gray);\n            draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.right()-1,btn.top()+1),gray);\n\n            draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()),black);\n\n            draw_line(c,point(btn.right(),btn.top()+1),point(btn.right(),btn.bottom()-1),dark_gray);\n            draw_line(c,point(btn.left()+1,btn.top()+1),point(btn.left()+1,btn.bottom()-1),gray);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_up (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha\n    )\n    {\n        rectangle area = btn.intersect(c);\n        if (area.is_empty() == false)\n        {\n            const rgb_alpha_pixel dark_gray(64,64,64,alpha);\n            const rgb_alpha_pixel gray(128,128,128,alpha);\n            const rgb_alpha_pixel white(255,255,255,alpha);\n\n            draw_line(c,point(btn.left(),btn.top()),point(btn.right()-1,btn.top()),white);\n\n            draw_line(c,point(btn.left(),btn.bottom()),point(btn.right(),btn.bottom()),dark_gray);\n            draw_line(c,point(btn.left()+1,btn.bottom()-1),point(btn.right()-1,btn.bottom()-1),gray);\n\n            draw_line(c,point(btn.left(),btn.top()+1),point(btn.left(),btn.bottom()-1),white);\n\n            draw_line(c,point(btn.right(),btn.top()),point(btn.right(),btn.bottom()-1),dark_gray);\n            draw_line(c,point(btn.right()-1,btn.top()+1),point(btn.right()-1,btn.bottom()-2),gray);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CANVAS_DRAWINg_CPP_\n\n"
  },
  {
    "path": "dlib/gui_widgets/canvas_drawing.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_GUI_CANVAS_DRAWINg_\n#define DLIB_GUI_CANVAS_DRAWINg_\n\n#include \"canvas_drawing_abstract.h\"\n#include \"../gui_core.h\"\n#include \"../algs.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_transforms/assign_image.h\"\n#include \"../geometry.h\"\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_line (\n        const canvas& c,\n        const point& p1,\n        const point& p2,\n        const pixel_type& pixel, \n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        rectangle valid_area(c.intersect(area));\n        long x1 = p1.x();\n        long y1 = p1.y();\n        long x2 = p2.x();\n        long y2 = p2.y();\n        if (x1 == x2)\n        {\n            // if the x coordinate is inside the canvas's area\n            if (x1 <= valid_area.right() && x1 >= valid_area.left())\n            {\n                // make sure y1 comes before y2\n                if (y1 > y2)\n                    swap(y1,y2);\n\n                y1 = std::max(y1,valid_area.top());\n                y2 = std::min(y2,valid_area.bottom());\n                // this is a vertical line\n                for (long y = y1; y <= y2; ++y)\n                {\n                    assign_pixel(c[y-c.top()][x1-c.left()], pixel);\n                }\n            }\n        }\n        else if (y1 == y2)\n        {\n            // if the y coordinate is inside the canvas's area\n            if (y1 <= valid_area.bottom() && y1 >= valid_area.top())\n            {\n                // make sure x1 comes before x2\n                if (x1 > x2)\n                    swap(x1,x2);\n\n                x1 = std::max(x1,valid_area.left());\n                x2 = std::min(x2,valid_area.right());\n                // this is a horizontal line\n                for (long x = x1; x <= x2; ++x)\n                {\n                    assign_pixel(c[y1-c.top()][x-c.left()], pixel);\n                }\n            }\n        }\n        else\n        {\n            rgb_alpha_pixel alpha_pixel;\n            assign_pixel(alpha_pixel, pixel);\n            const unsigned char max_alpha = alpha_pixel.alpha;\n\n            const long rise = (((long)y2) - ((long)y1));\n            const long run = (((long)x2) - ((long)x1));\n            if (std::abs(rise) < std::abs(run))\n            {\n                const double slope = ((double)rise)/run;\n\n                double first, last;\n\n                if (x1 > x2)                \n                {\n                    first = std::max(x2,valid_area.left());\n                    last = std::min(x1,valid_area.right());\n                }\n                else\n                {\n                    first = std::max(x1,valid_area.left());\n                    last = std::min(x2,valid_area.right());\n                }                             \n\n\n                long y;\n                long x;\n                const double x1f = x1;\n                const double y1f = y1;\n                for (double i = first; i <= last; ++i)\n                {   \n                    const double dy = slope*(i-x1f) + y1f;\n                    const double dx = i;\n\n                    y = static_cast<long>(dy);\n                    x = static_cast<long>(dx);\n\n\n                    if (y >= valid_area.top() && y <= valid_area.bottom())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dy-y))*max_alpha);\n                        assign_pixel(c[y-c.top()][x-c.left()], alpha_pixel);\n                    }\n                    if (y+1 >= valid_area.top() && y+1 <= valid_area.bottom())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((dy-y)*max_alpha);\n                        assign_pixel(c[y+1-c.top()][x-c.left()], alpha_pixel);\n                    }\n                }         \n            }\n            else\n            {\n                const double slope = ((double)run)/rise;\n\n                double first, last;\n\n                if (y1 > y2)                \n                {\n                    first = std::max(y2,valid_area.top());\n                    last = std::min(y1,valid_area.bottom());\n                }\n                else\n                {\n                    first = std::max(y1,valid_area.top());\n                    last = std::min(y2,valid_area.bottom());\n                }                             \n\n                long x;\n                long y;\n                const double x1f = x1;\n                const double y1f = y1;\n                for (double i = first; i <= last; ++i)\n                {   \n                    const double dx = slope*(i-y1f) + x1f;\n                    const double dy = i;\n\n                    y = static_cast<long>(dy);\n                    x = static_cast<long>(dx);\n\n                    if (x >= valid_area.left() && x <= valid_area.right())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dx-x))*max_alpha);\n                        assign_pixel(c[y-c.top()][x-c.left()], alpha_pixel);\n                    }\n                    if (x+1 >= valid_area.left() && x+1 <= valid_area.right())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((dx-x)*max_alpha);\n                        assign_pixel(c[y-c.top()][x+1-c.left()], alpha_pixel);\n                    }\n                } \n            }\n        }\n\n    }\n    inline void draw_line (\n        const canvas& c,\n        const point& p1,\n        const point& p2\n    ){ draw_line(c,p1,p2,0); }\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_sunken_rectangle (\n        const canvas& c,\n        const rectangle& border,\n        unsigned char alpha = 255\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    inline void draw_pixel (\n        const canvas& c,\n        const point& p,\n        const pixel_type& pixel \n    )\n    {\n        if (c.contains(p))\n        {\n            assign_pixel(c[p.y()-c.top()][p.x()-c.left()],pixel);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_checkered (\n        const canvas& c,\n        const rectangle& a,\n        const pixel_type& pixel1,\n        const pixel_type& pixel2\n    )\n    {\n        rectangle area = a.intersect(c);\n        if (area.is_empty())\n            return;\n\n        for (long i = area.left(); i <= area.right(); ++i)\n        {\n            for (long j = area.top(); j <= area.bottom(); ++j)\n            {\n                canvas::pixel& p = c[j - c.top()][i - c.left()];\n                if ((j&0x1) ^ (i&0x1))\n                {\n                    assign_pixel(p,pixel1);\n                }\n                else\n                {\n                    assign_pixel(p,pixel2);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_down (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha = 255\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_up (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha = 255\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius,\n        const pixel_type& pixel,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        using std::sqrt;\n        rectangle valid_area(c.intersect(area));\n        const long x = center_point.x();\n        const long y = center_point.y();\n        if (radius > 1)\n        {\n            long first_x = std::lround(x - radius);\n            long last_x = std::lround(x + radius);\n            const double rs = radius*radius;\n\n            // ensure that we only loop over the part of the x dimension that this\n            // canvas contains.\n            if (first_x < valid_area.left())\n                first_x = valid_area.left();\n            if (last_x > valid_area.right())\n                last_x = valid_area.right();\n\n            long top, bottom;\n\n            top = std::lround(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0)));\n            top += y;\n            long last = top;\n\n            // draw the left half of the circle\n            long middle = std::min(x-1,last_x);\n            for (long i = first_x; i <= middle; ++i)\n            {\n                double a = i - x + 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    if (top >= valid_area.top() && top <= valid_area.bottom() )\n                    {\n                        assign_pixel(c[top-c.top()][i-c.left()],pixel);\n                    }\n\n                    if (bottom >= valid_area.top() && bottom <= valid_area.bottom() )\n                    {\n                        assign_pixel(c[bottom-c.top()][i-c.left()],pixel);\n                    }\n                    --top;\n                }\n\n                last = temp;\n            }\n\n            middle = std::max(x,first_x);\n            top = std::lround(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0)));\n            top += y;\n            last = top;\n            // draw the right half of the circle\n            for (long i = last_x; i >= middle; --i)\n            {\n                double a = i - x - 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    if (top >= valid_area.top() && top <= valid_area.bottom() )\n                    {\n                        assign_pixel(c[top-c.top()][i-c.left()],pixel);\n                    }\n\n                    if (bottom >= valid_area.top() && bottom <= valid_area.bottom() )\n                    {\n                        assign_pixel(c[bottom-c.top()][i-c.left()],pixel);\n                    }\n                    --top;\n                }\n\n                last = temp;\n            }\n        }\n        else if (radius == 1 &&\n                 x >= valid_area.left() && x <= valid_area.right() &&\n                 y >= valid_area.top() && y <= valid_area.bottom() )\n        {\n            assign_pixel(c[y-c.top()][x-c.left()], pixel);\n        }\n    }\n    inline void draw_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius\n    ){ draw_circle(c, center_point, radius, 0); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_solid_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius,\n        const pixel_type& pixel,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        using std::sqrt;\n        rectangle valid_area(c.intersect(area));\n        const long x = center_point.x();\n        const long y = center_point.y();\n        if (radius > 1)\n        {\n            long first_x = std::lround(x - radius);\n            long last_x = std::lround(x + radius);\n            const double rs = radius*radius;\n\n            // ensure that we only loop over the part of the x dimension that this\n            // canvas contains.\n            if (first_x < valid_area.left())\n                first_x = valid_area.left();\n            if (last_x > valid_area.right())\n                last_x = valid_area.right();\n\n            long top, bottom;\n\n            top = std::lround(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0)));\n            top += y;\n            long last = top;\n\n            // draw the left half of the circle\n            long middle = std::min(x-1,last_x);\n            for (long i = first_x; i <= middle; ++i)\n            {\n                double a = i - x + 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    draw_line(c, point(i,top),point(i,bottom),pixel,area);\n                    --top;\n                }\n\n                last = temp;\n            }\n\n            middle = std::max(x,first_x);\n            top = std::lround(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0)));\n            top += y;\n            last = top;\n            // draw the right half of the circle\n            for (long i = last_x; i >= middle; --i)\n            {\n                double a = i - x - 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    draw_line(c, point(i,top),point(i,bottom),pixel,area);\n                    --top;\n                }\n\n                last = temp;\n            }\n        }\n        else if (radius == 1 &&\n                 x >= valid_area.left() && x <= valid_area.right() &&\n                 y >= valid_area.top() && y <= valid_area.bottom() )\n        {\n            assign_pixel(c[y-c.top()][x-c.left()], pixel);\n        }\n    }\n    inline void draw_solid_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius\n    ) { draw_solid_circle(c, center_point, radius, 0); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_solid_convex_polygon (\n        const canvas& c,\n        const polygon& poly,\n        const pixel_type& pixel,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        using std::max;\n        using std::min;\n        const rectangle valid_area(c.intersect(area));\n\n        const rectangle bounding_box = poly.get_rect();\n\n        // Don't do anything if the polygon is totally outside the area we can draw in\n        // right now.\n        if (bounding_box.intersect(valid_area).is_empty())\n            return;\n\n        rgb_alpha_pixel alpha_pixel;\n        assign_pixel(alpha_pixel, pixel);\n        const unsigned char max_alpha = alpha_pixel.alpha;\n\n        // we will only want to loop over the part of left_boundary that is part of the\n        // valid_area.\n        long top = max(valid_area.top(),bounding_box.top());\n        long bottom = min(valid_area.bottom(),bounding_box.bottom());\n\n        // Since we look at the adjacent rows of boundary information when doing the alpha\n        // blending, we want to make sure we always have some boundary information unless\n        // we are at the absolute edge of the polygon.\n        const long top_offset = (top == bounding_box.top()) ? 0 : 1;\n        const long bottom_offset = (bottom == bounding_box.bottom()) ? 0 : 1;\n        if (top != bounding_box.top())\n            top -= 1;\n        if (bottom != bounding_box.bottom())\n            bottom += 1;\n\n        std::vector<double> left_boundary;\n        std::vector<double> right_boundary;\n        poly.get_left_and_right_bounds(top, bottom, left_boundary, right_boundary);\n\n        // draw the polygon row by row\n        for (unsigned long i = top_offset; i < left_boundary.size(); ++i)\n        {\n            long left_x = static_cast<long>(std::ceil(left_boundary[i]));\n            long right_x = static_cast<long>(std::floor(right_boundary[i]));\n\n            left_x = max(left_x, valid_area.left());\n            right_x = min(right_x, valid_area.right());\n\n            if (i < left_boundary.size()-bottom_offset)\n            {\n                // draw the main body of the polygon\n                for (long x = left_x; x <= right_x; ++x)\n                {\n                    const long y = i+top;\n                    assign_pixel(c[y-c.top()][x-c.left()], pixel);\n                }\n            }\n\n            if (i == 0)\n                continue;\n\n            // Now draw anti-aliased edges so they don't look all pixely.\n\n            // Alpha blend the edges on the left side.\n            double delta = left_boundary[i-1] - left_boundary[i];\n            if (std::abs(delta) <= 1)\n            {\n                if (std::floor(left_boundary[i]) != left_x)\n                {\n                    const point p(static_cast<long>(std::floor(left_boundary[i])), i+top);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = max_alpha-static_cast<unsigned char>((left_boundary[i]-p.x())*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n            else if (delta < 0)  // on the bottom side\n            {\n                for (long x = static_cast<long>(std::ceil(left_boundary[i-1])); x < left_x; ++x)\n                {\n                    const point p(x, i+top);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i-1])/std::abs(delta)*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n            else // on the top side\n            {\n                const long old_left_x = static_cast<long>(std::ceil(left_boundary[i-1]));\n                for (long x = left_x; x < old_left_x; ++x)\n                {\n                    const point p(x, i+top-1);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i])/delta*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n\n\n            // Alpha blend the edges on the right side\n            delta = right_boundary[i-1] - right_boundary[i];\n            if (std::abs(delta) <= 1)\n            {\n                if (std::ceil(right_boundary[i]) != right_x)\n                {\n                    const point p(static_cast<long>(std::ceil(right_boundary[i])), i+top);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = max_alpha-static_cast<unsigned char>((p.x()-right_boundary[i])*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n            else if (delta < 0) // on the top side\n            {\n                for (long x = static_cast<long>(std::floor(right_boundary[i-1]))+1; x <= right_x; ++x)\n                {\n                    const point p(x, i+top-1);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((right_boundary[i]-x)/std::abs(delta)*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n            else // on the bottom side\n            {\n                const long old_right_x = static_cast<long>(std::floor(right_boundary[i-1]));\n                for (long x = right_x+1; x <= old_right_x; ++x)\n                {\n                    const point p(x, i+top);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((right_boundary[i-1]-x)/delta*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(c[p.y()-c.top()][p.x()-c.left()],temp);\n                }\n            }\n        }\n    }\n    inline void draw_solid_convex_polygon (\n        const canvas& c,\n        const std::vector<point>& polygon\n    ) { draw_solid_convex_polygon(c, polygon, 0); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void draw_image (\n        const canvas& c,\n        const point& p,\n        const image_type& img,\n        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        const long x = p.x();\n        const long y = p.y();\n        rectangle rect(x,y,num_columns(img)+x-1,num_rows(img)+y-1);\n        rectangle area = c.intersect(rect).intersect(area_);\n        if (area.is_empty())\n            return;\n\n        for (long row = area.top(); row <= area.bottom(); ++row)\n        {\n            for (long col = area.left(); col <= area.right(); ++col)\n            {\n                assign_pixel(c[row-c.top()][col-c.left()], img[row-rect.top()][col-rect.left()]);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void draw_image (\n        const canvas& c,\n        const rectangle& rect,\n        const image_type& img,\n        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        const rectangle area = c.intersect(rect).intersect(area_);\n        if (area.is_empty() || num_columns(img) * num_rows(img) == 0)\n            return;\n\n        const matrix<long,1> x = matrix_cast<long>(round(linspace(0, num_columns(img)-1, rect.width())));\n        const matrix<long,1> y = matrix_cast<long>(round(linspace(0, num_rows(img)-1, rect.height())));\n\n        for (long row = area.top(); row <= area.bottom(); ++row)\n        {\n            const long r = y(row-rect.top());\n            long cc = area.left() - rect.left();\n            for (long col = area.left(); col <= area.right(); ++col)\n            {\n                assign_pixel(c[row-c.top()][col-c.left()], img[r][x(cc++)]);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_rounded_rectangle (\n        const canvas& c,\n        const rectangle& rect,\n        unsigned radius,\n        const pixel_type& color,\n        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        if ( rect.intersect ( c ).is_empty() )\n            return;\n\n        draw_line ( c, point(rect.left() + radius + 1, rect.bottom()), \n                    point(rect.right() - radius - 1, rect.bottom()), color,area_ );\n\n        draw_line ( c, point(rect.left() + radius + 1, rect.top()), \n                    point(rect.right() - radius - 1, rect.top()), color,area_ );\n\n        draw_line ( c, point(rect.left(), rect.top() + radius + 1), \n                    point(rect.left(), rect.bottom() - radius - 1), color,area_ );\n\n        draw_line ( c, point(rect.right(), rect.top() + radius + 1), \n                    point(rect.right(), rect.bottom() - radius - 1), color,area_ );\n\n        unsigned x = radius, y = 0, old_x = x;\n\n        point p;\n        while ( x > y )\n        {\n            p = point(rect.left() + radius - y, rect.top() + radius - x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + y, rect.top() + radius - x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + y, rect.bottom() - radius + x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.left() + radius - y, rect.bottom() - radius + x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.left() + radius - x, rect.top() + radius - y);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + x, rect.top() + radius - y);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + x, rect.bottom() - radius + y);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.left() + radius - x, rect.bottom() - radius + y);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            y++;\n            old_x = x;\n            x = square_root ( ( radius * radius - y * y ) * 4 ) / 2;\n        }\n\n        if ( x == y && old_x != x )\n        {\n            p = point(rect.left() + radius - y, rect.top() + radius - x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + y, rect.top() + radius - x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.right() - radius + y, rect.bottom() - radius + x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n            p = point(rect.left() + radius - y, rect.bottom() - radius + x);\n            if (area_.contains(p)) draw_pixel (c, p , color );\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void fill_gradient_rounded (\n        const canvas& c,\n        const rectangle& rect,\n        unsigned long radius,\n        const pixel_type& top_color,\n        const pixel_type& bottom_color,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n\n    )\n    {\n        rectangle valid_area(c.intersect(area.intersect(rect)));\n        if ( valid_area.is_empty() )\n            return;\n\n\n        unsigned long m_prev = 0, m = radius, c_div = valid_area.height() - 1;\n\n        const long c_top = valid_area.top();\n        const long c_bottom = valid_area.bottom();\n\n        for ( long y = c_top; y <= c_bottom;y++ )\n        {\n\n            unsigned long c_s = y - c_top;\n\n            unsigned long c_t = c_bottom - y;\n\n\n            if ( c_div == 0 )\n            {\n                // only a single round, just take the average color\n                c_div = 2;\n                c_s = c_t = 1;\n            }\n\n            rgb_alpha_pixel color;\n            vector_to_pixel(color,\n                            ((pixel_to_vector<unsigned long>(top_color)*c_t + pixel_to_vector<unsigned long>(bottom_color)*c_s)/c_div));\n\n            unsigned long s = y - rect.top();\n\n            unsigned long t = rect.bottom() - y;\n\n            if ( s < radius )\n            {\n                m = radius - square_root ( ( radius * radius - ( radius - s ) * ( radius - s ) ) * 4 ) / 2;\n\n                if ( s == m && m + 1 < m_prev )  // these are hacks to remove distracting artefacts at small radii\n                    m++;\n            }\n            else if ( t < radius )\n            {\n                m = radius - square_root ( ( radius * radius - ( radius - t ) * ( radius - t ) ) * 4 ) / 2;\n\n                if ( t == m && m == m_prev )\n                    m++;\n            }\n            else\n            {\n                m = 0;\n            }\n\n            m_prev = m;\n\n            draw_line ( c, point(rect.left() + m, y), \n                        point(rect.right() - m, y), color, valid_area );\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void draw_rectangle (\n        const canvas& c,\n        rectangle rect,\n        const pixel_type& pixel,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        // top line\n        draw_line(c, point(rect.left(),rect.top()),\n                  point(rect.right(),rect.top()),\n                  pixel, area);\n\n        // bottom line\n        draw_line(c, point(rect.left(),rect.bottom()),\n                  point(rect.right(),rect.bottom()),\n                  pixel, area);\n\n        // left line\n        draw_line(c, point(rect.left(),rect.top()),\n                  point(rect.left(),rect.bottom()),\n                  pixel, area);\n\n        // right line\n        draw_line(c, point(rect.right(),rect.top()),\n                  point(rect.right(),rect.bottom()),\n                  pixel, area);\n    }\n    inline void draw_rectangle (\n        const canvas& c,\n        rectangle rect\n    ){ draw_rectangle(c, rect, 0); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void fill_rect (\n        const canvas& c,\n        const rectangle& rect,\n        const pixel_type& pixel\n    )\n    {\n        rectangle area = rect.intersect(c);\n        for (long y = area.top(); y <= area.bottom(); ++y)\n        {\n            for (long x = area.left(); x <= area.right(); ++x)\n            {\n                assign_pixel(c[y-c.top()][x-c.left()], pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void fill_rect_with_vertical_gradient (\n        const canvas& c,\n        const rectangle& rect,\n        const pixel_type& pixel_top,\n        const pixel_type& pixel_bottom,\n        const rectangle& area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        rectangle area = rect.intersect(c).intersect(area_);\n        pixel_type pixel;\n\n        const long s = rect.bottom()-rect.top();\n\n        for (long y = area.top(); y <= area.bottom(); ++y)\n        {\n            const long t = rect.bottom()-y;\n            const long b = y-rect.top();\n            vector_to_pixel(pixel,\n                    ((pixel_to_vector<long>(pixel_top)*t + \n                      pixel_to_vector<long>(pixel_bottom)*b)/s));\n\n            for (long x = area.left(); x <= area.right(); ++x)\n            {\n                assign_pixel(c[y-c.top()][x-c.left()], pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"canvas_drawing.cpp\"\n#endif\n\n#endif // DLIB_GUI_CANVAS_DRAWINg_\n\n"
  },
  {
    "path": "dlib/gui_widgets/canvas_drawing_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_\n#ifdef DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_ \n\n#include \"../gui_core.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_line (\n        const canvas& c,\n        const point& p1,\n        const point& p2,\n        const pixel_type& pixel = rgb_pixel(0,0,0),\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - draws the part of the line from p1 to p1 that overlaps with\n              the canvas and area onto the canvas.  \n            - Uses the given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_rectangle (\n        const canvas& c,\n        rectangle rect,\n        const pixel_type& pixel = rgb_pixel(0,0,0),\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws the part of the rectangle that overlaps with\n              the canvas and area onto the canvas.  \n            - Uses the given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius,\n        const pixel_type& pixel = rgb_pixel(0,0,0),\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - draws the part of the circle centered at center_point with the given radius \n              that overlaps with the canvas and area onto the canvas.  \n            - Uses the given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_pixel (\n        const canvas& c,\n        const point& p,\n        const pixel_type& pixel \n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - if (c.contains(p)) then\n                - sets the pixel in c that represents the point p to the \n                  given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_solid_circle (\n        const canvas& c,\n        const point& center_point,\n        double radius,\n        const pixel_type& pixel = rgb_pixel(0,0,0),\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - draws the part of the solid circle centered at center_point with the given \n              radius that overlaps with the canvas and area onto the canvas.  \n              (\"solid\" means that the interior is also filled in with the given\n              pixel color)\n            - Uses the given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_solid_convex_polygon (\n        const canvas& c,\n        const std::vector<point>& polygon,\n        const pixel_type& pixel = rgb_pixel(0,0,0),\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Interprets the given std::vector polygon object as defining a convex polygon\n              shape.  In particular, the polygon is given by taking the points and drawing\n              lines between them.  That is, imagine drawing a line connecting polygon[i]\n              and polygon[(i+1)%polygon.size()], for all valid i, and then filling in the\n              interior of the polygon.  That is what this function does.\n            - When drawing the polygon, only the part of the polygon which overlaps both\n              the given canvas and area rectangle is drawn.\n            - Uses the given pixel color to draw the polygon.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_down (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha = 255\n    );\n    /*!\n        requires\n            - 0 <= alpha <= 255\n        ensures\n            - draws the border of a button onto canvas c:\n                - the border will be that of a button that is depressed\n                - only the part of the border that overlaps with the canvas object\n                  will be drawn.\n                - the border will be for the button whose area is defined by the\n                  rectangle btn.\n            - performs alpha blending such that the button is drawn with full opacity \n              when alpha is 255 and fully transparent when alpha is 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_sunken_rectangle (\n        const canvas& c,\n        const rectangle& border,\n        unsigned char alpha = 255\n    );\n    /*!\n        requires\n            - 0 <= alpha <= 255\n        ensures\n            - draws a sunken rectangle around the given border.\n              (This is the type of border used for text_fields and\n              check_boxes and the like).\n            - performs alpha blending such that the rectangle is drawn with full opacity \n              when alpha is 255 and fully transparent when alpha is 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_button_up (\n        const canvas& c,\n        const rectangle& btn,\n        unsigned char alpha = 255\n    );\n    /*!\n        requires\n            - 0 <= alpha <= 255\n        ensures\n            - draws the border of a button onto canvas c:\n                - the border will be that of a button that is NOT depressed\n                - only the part of the border that overlaps with the canvas object\n                  will be drawn.\n                - the border will be for the button whose area is defined by the\n                  rectangle btn.\n            - performs alpha blending such that the button is drawn with full opacity \n              when alpha is 255 and fully transparent when alpha is 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_checkered (\n        const canvas& c,\n        const rectangle& area,\n        const pixel_type& pixel1,\n        const pixel_type& pixel2\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - fills the area on the given canvas defined by the rectangle area with a checkers \n              board pattern where every other pixel gets assigned either pixel1 or pixel2.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void draw_image (\n        const canvas& c\n        const point& p,\n        const image_type& image,\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - image_type == an implementation of array2d/array2d_kernel_abstract.h\n            - pixel_traits<typename image_type::type> is defined\n        ensures\n            - draws the given image object onto the canvas such that the upper left corner of the\n              image will appear at the point p in the canvas's window.  (note that the\n              upper left corner of the image is assumed to be the pixel image[0][0] and the\n              lower right corner of the image is assumed to be image[image.nr()-1][image.nc()-1])\n            - only draws the part of the image that overlaps with the area rectangle\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void draw_image (\n        const canvas& c,\n        const rectangle& rect,\n        const image_type& img,\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - image_type == an implementation of array2d/array2d_kernel_abstract.h\n            - pixel_traits<typename image_type::type> is defined\n        ensures\n            - draws the given image object onto the canvas such that the upper left corner\n              of the image will appear at the point rect.tl_corner() in the canvas's window\n              and the lower right corner of the image will appear at rect.br_corner() in\n              the canvas's window.  (note that the upper left corner of the image is\n              assumed to be the pixel image[0][0] and the lower right corner of the image\n              is assumed to be image[image.nr()-1][image.nc()-1])\n            - only draws the part of the image that overlaps with the area rectangle\n            - Uses nearest neighbor interpolation when the given rect isn't the same size\n              as the input image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void fill_rect (\n        const canvas& c,\n        const rectangle& rect,\n        const pixel_type& pixel\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - fills the area defined by rect in the given canvas with the given pixel color.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void fill_rect_with_vertical_gradient (\n        const canvas& c,\n        const rectangle& rect,\n        const pixel_type& pixel_top,\n        const pixel_type& pixel_bottom,\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - fills the rectangle defined by rect in the given canvas with the given colors.  \n              The top of the area will have the pixel_top color and will slowly fade \n              towards the pixel_bottom color towards the bottom of rect.\n            - only draws the part of the image that overlaps with the area rectangle\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void fill_gradient_rounded (\n        const canvas& c,\n        const rectangle& rect,\n        unsigned long radius,\n        const pixel_type& top_color,\n        const pixel_type& bottom_color,\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Fills the region defined by rect in the given canvas with the given colors.  \n              The top of the region will have the top_color color and will slowly fade \n              towards the bottom_color color towards the bottom of rect.\n            - The drawn rectangle will have rounded corners and with the amount of \n            - rounding given by the radius argument.\n            - only the part of this object that overlaps with area and the canvas\n              will be drawn on the canvas\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void draw_rounded_rectangle (\n        const canvas& c,\n        const rectangle& rect,\n        unsigned radius,\n        const pixel_type& color,\n        const rectangle& area = rectangle(-infinity,-infinity,infinity,infinity)\n    );\n    /*!\n        requires\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws the part of the rectangle that overlaps with\n              the canvas onto the canvas.  \n            - The drawn rectangle will have rounded corners and with the amount of \n              rounding given by the radius argument.\n            - Uses the given pixel color.\n            - only draws the part of the image that overlaps with the area rectangle\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GUI_CANVAS_DRAWINg_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/gui_widgets/drawable.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DRAWABLe_CPP_\n#define DLIB_DRAWABLe_CPP_\n\n#include \"drawable.h\"\n\n#include <algorithm>\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// -----------  drawable_window object  ------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    rgb_pixel drawable_window::\n    background_color (\n    ) const\n    {\n        auto_mutex M(wm);\n        return bg_color;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    set_background_color (\n        unsigned long red_,\n        unsigned long green_,\n        unsigned long blue_\n    )\n    {\n        wm.lock();\n        bg_color.red = red_;\n        bg_color.green = green_;\n        bg_color.blue = blue_;\n        wm.unlock();\n        // now repaint the window\n        unsigned long width,height;\n        get_size(width,height);\n        rectangle rect(0,0,width-1,height-1);\n        invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    paint (\n        const canvas& c\n    )\n    {\n        ++event_id;\n        c.fill(bg_color.red,bg_color.green,bg_color.blue);\n\n        widgets.reset();\n        while (widgets.move_next())\n        {\n            widgets.element().value().reset();\n            while (widgets.element().value().move_next())\n            {\n                // only dispatch a draw() call if this widget isn't hidden\n                if (widgets.element().value().element()->hidden == false &&\n                    widgets.element().value().element()->event_id != event_id)\n                {\n                    widgets.element().value().element()->event_id = event_id;\n                    widgets.element().value().element()->draw(c);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_user_event (\n        void* p,\n        int i\n    )\n    {\n        drawable* d = static_cast<drawable*>(p);\n        if (widget_set.is_member(d))\n        {\n            d->on_user_event(i);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_window_moved(\n    )\n    {\n        ++event_id;\n        window_moved.reset();\n        while (window_moved.move_next())\n        {\n            if (window_moved.element()->event_id != event_id)\n            {\n                window_moved.element()->event_id = event_id;\n                window_moved.element()->on_window_moved();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_window_resized(\n    )\n    {\n        ++event_id;\n        window_resized.reset();\n        while (window_resized.move_next())\n        {\n            if (window_resized.element()->event_id != event_id)\n            {\n                window_resized.element()->event_id = event_id;\n                window_resized.element()->on_window_resized();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        ++event_id;\n        keyboard.reset();\n        while (keyboard.move_next())\n        {\n            if (keyboard.element()->event_id != event_id)\n            {\n                keyboard.element()->event_id = event_id;\n                keyboard.element()->on_keydown(key,is_printable,state);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_focus_gained (\n    )\n    {\n        ++event_id;\n        focus.reset();\n        while (focus.move_next())\n        {\n            if (focus.element()->event_id != event_id)\n            {\n                focus.element()->event_id = event_id;\n                focus.element()->on_focus_gained();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_focus_lost (\n    )\n    {\n        ++event_id;\n        focus.reset();\n        while (focus.move_next())\n        {\n            if (focus.element()->event_id != event_id)\n            {\n                focus.element()->event_id = event_id;\n                focus.element()->on_focus_lost();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool is_double_click\n    )\n    {\n        lastx = x;\n        lasty = y;\n\n        ++event_id;\n        mouse_click.reset();\n        while (mouse_click.move_next())\n        {\n            if (mouse_click.element()->event_id != event_id)\n            {\n                mouse_click.element()->event_id = event_id;\n                mouse_click.element()->on_mouse_down(btn,state,x,y,is_double_click);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        lastx = x;\n        lasty = y;\n\n        ++event_id;\n        mouse_click.reset();\n        while (mouse_click.move_next())\n        {\n            if (mouse_click.element()->event_id != event_id)\n            {\n                mouse_click.element()->event_id = event_id;\n                mouse_click.element()->on_mouse_up(btn,state,x,y);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        lastx = x;\n        lasty = y;\n\n        ++event_id;\n        mouse_move.reset();\n        while (mouse_move.move_next())\n        {\n            if (mouse_move.element()->event_id != event_id)\n            {\n                mouse_move.element()->event_id = event_id;\n                mouse_move.element()->on_mouse_move(state,x,y);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_mouse_leave (\n    )\n    {\n        lastx = -1;\n        lasty = -1;\n\n        ++event_id;\n        mouse_move.reset();\n        while (mouse_move.move_next())\n        {\n            if (mouse_move.element()->event_id != event_id)\n            {\n                mouse_move.element()->event_id = event_id;\n                mouse_move.element()->on_mouse_leave();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_mouse_enter (\n    )\n    {\n        ++event_id;\n        mouse_move.reset();\n        while (mouse_move.move_next())\n        {\n            if (mouse_move.element()->event_id != event_id)\n            {\n                mouse_move.element()->event_id = event_id;\n                mouse_move.element()->on_mouse_enter();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_wheel_up (\n        unsigned long state\n    )\n    {\n        ++event_id;\n        mouse_wheel.reset();\n        while (mouse_wheel.move_next())\n        {\n            if (mouse_wheel.element()->event_id != event_id)\n            {\n                mouse_wheel.element()->event_id = event_id;\n                mouse_wheel.element()->on_wheel_up(state);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_wheel_down (\n        unsigned long state\n    )\n    {\n        ++event_id;\n        mouse_wheel.reset();\n        while (mouse_wheel.move_next())\n        {\n            if (mouse_wheel.element()->event_id != event_id)\n            {\n                mouse_wheel.element()->event_id = event_id;\n                mouse_wheel.element()->on_wheel_down(state);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable_window::\n    on_string_put (\n        const std::wstring &str\n    )\n    {\n        ++event_id;\n        string_put.reset();\n        while (string_put.move_next())\n        {\n            if (string_put.element()->event_id != event_id)\n            {\n                string_put.element()->event_id = event_id;\n                string_put.element()->on_string_put(str);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// -----------  drawable object  ----------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void drawable::\n    enable_events (\n    )\n    {\n        auto_mutex M(m);\n        if (enabled_events == false)\n        {\n            enabled_events = true;\n            drawable* temp = this;\n            long zo = z_order_value;\n\n            drawable_window::set_of_drawables* sod = parent.widgets[zo];\n            if (sod == 0)\n            {\n                // this drawable is the first widget at this z order so we need\n                // to make its containing set\n                drawable_window::set_of_drawables s;\n                s.add(temp);\n                parent.widgets.add(zo,s);\n            }\n            else\n            {\n                sod->add(temp);\n            }\n\n            temp = this;\n            parent.widget_set.add(temp);\n\n            if (events & MOUSE_MOVE)\n            {\n                temp = this;\n                parent.mouse_move.add(temp);\n            }\n            if (events & MOUSE_CLICK)\n            {\n                temp = this;\n                parent.mouse_click.add(temp);\n            }\n            if (events & MOUSE_WHEEL)\n            {\n                temp = this;\n                parent.mouse_wheel.add(temp);\n            }\n            if (events & WINDOW_RESIZED)\n            {\n                temp = this;\n                parent.window_resized.add(temp);\n            }\n            if (events & KEYBOARD_EVENTS)\n            {\n                temp = this;\n                parent.keyboard.add(temp);\n            }\n            if (events & FOCUS_EVENTS)\n            {\n                temp = this;\n                parent.focus.add(temp);\n            }\n            if (events & WINDOW_MOVED)\n            {\n                temp = this;\n                parent.window_moved.add(temp);\n            }\n            if (events & STRING_PUT)\n            {\n                temp = this;\n                parent.string_put.add(temp);\n            }\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable::\n    set_z_order (\n        long order\n    )\n    {\n        auto_mutex M(m);\n        if (order != z_order_value && enabled_events)\n        {\n            // first remove this drawable from widgets\n            drawable_window::set_of_drawables* sod = parent.widgets[z_order_value];\n            drawable* junk;\n            sod->remove(this,junk);\n\n            // if there are no more drawables at this z order then destroy the\n            // set for this order\n            if (sod->size() == 0)\n                parent.widgets.destroy(z_order_value);\n\n            // now add this drawable to its new z order\n            sod = parent.widgets[order];                \n            if (sod == 0)\n            {\n                // this drawable is the first widget at this z order so we need\n                // to make its containing set\n                drawable_window::set_of_drawables s, x;\n                s.add(junk);\n                long temp_order = order;\n                parent.widgets.add(temp_order,s);\n            }\n            else\n            {\n                sod->add(junk);\n            }\n            parent.invalidate_rectangle(rect);\n\n        }\n        z_order_value = order;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void drawable::\n    disable_events (\n    )\n    {\n        auto_mutex M(m);\n        if (enabled_events)\n        {\n            enabled_events = false;\n            // first remove this drawable from widgets\n            drawable_window::set_of_drawables* sod = parent.widgets[z_order_value];\n            drawable* junk;\n            sod->remove(this,junk);\n\n            // if there are no more drawables at this z order then destroy the\n            // set for this order\n            if (sod->size() == 0)\n                parent.widgets.destroy(z_order_value);\n\n            parent.widget_set.remove(this,junk);\n\n            // now unregister this drawable from all the events it has registered for.\n            if (events & MOUSE_MOVE)\n                parent.mouse_move.remove(this,junk);\n            if (events & MOUSE_CLICK)\n                parent.mouse_click.remove(this,junk);\n            if (events & MOUSE_WHEEL)\n                parent.mouse_wheel.remove(this,junk);\n            if (events & WINDOW_RESIZED)\n                parent.window_resized.remove(this,junk);\n            if (events & KEYBOARD_EVENTS)\n                parent.keyboard.remove(this,junk);\n            if (events & FOCUS_EVENTS)\n                parent.focus.remove(this,junk);\n            if (events & WINDOW_MOVED)\n                parent.window_moved.remove(this,junk);\n            if (events & STRING_PUT)\n                parent.string_put.remove(this,junk);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    drawable::\n    ~drawable (\n    )\n    {\n        try\n        {\n            DLIB_ASSERT(events_are_enabled() == false,\n                \"\\tdrawable::~drawable()\"\n                << \"\\n\\tYou must disable events for drawable objects in their destructor by calling disable_events().\"\n                << \"\\n\\tthis:     \" << this\n                );\n        }\n        catch (std::exception& e)\n        {\n            std::cerr << e.what() << std::endl;\n            assert(false);\n            abort();\n        }\n        disable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAWABLe_CPP_\n\n"
  },
  {
    "path": "dlib/gui_widgets/drawable.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_DRAWABLe_\n#define DLIB_DRAWABLe_\n\n#include <memory>\n\n#include \"drawable_abstract.h\"\n#include \"../gui_core.h\"\n#include \"../set.h\"\n#include \"../binary_search_tree.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"fonts.h\"\n#include \"../matrix.h\"\n#include \"canvas_drawing.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class drawable_window  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class drawable;\n    class drawable_window : public base_window\n    {\n        /*!\n            INITIAL VALUE\n                - lastx == -1\n                - lasty == -1\n                - event_id == 1\n\n            CONVENTION\n                - bg_color == background_color()\n\n                - widgets == this binary search tree contains every drawable that is in\n                  this window.  It is a mapping of each drawable's z-order to a pointer\n                  to said drawable.\n                - widget_set == a set that contains all the widgets in this window and\n                  want to receive events.\n\n                - mouse_move == this is a set of drawables that are in this window and \n                  want to receive the mouse movement events.\n                - mouse_wheel == this is a set of drawables that are in this window and \n                  want to receive the mouse wheel events.\n                - mouse_click == this is a set of drawables that are in this window and \n                  want to receive the mouse click events.\n                - window_resized == this is a set of drawables that are in this window and \n                  want to receive the window_resized event.\n                - keyboard == this is a set of drawables that are in this window and \n                  want to receive keyboard events.\n                - focus == this is a set of drawables that are in this window and \n                  want to receive focus events.\n                - window_moved == this is a set of drawables that are in this window and \n                  want to receive window move events.\n\n                - lastx == the x coordinate that we last saw the mouse at or -1 if the \n                  mouse is outside this window.\n                - lasty == the y coordinate that we last saw the mouse at or -1 if the \n                  mouse is outside this window.\n\n                - event_id == a number we use to tag events so we don't end up sending\n                  an event to a drawable more than once.  This could happen if one of the\n                  event handlers does something to reset the enumerator while we are\n                  dispatching events (e.g. creating a new widget).\n        !*/\n    public:\n\n        drawable_window(\n            bool resizable = true,\n            bool undecorated = false\n        ) : \n            base_window(resizable,undecorated),\n            bg_color(rgb_pixel(212,208,200)),\n            lastx(-1),\n            lasty(-1),\n            event_id(1)\n        {}\n\n        void set_background_color (\n            unsigned long red,\n            unsigned long green,\n            unsigned long blue\n        );\n\n        rgb_pixel background_color (\n        ) const;\n\n        virtual inline ~drawable_window()=0;\n\n    private:\n\n        void paint (\n            const canvas& c\n        );\n\n    protected:\n\n        void on_window_resized(\n        );\n\n        void on_window_moved(\n        );\n               \n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_leave (\n        );\n\n        void on_mouse_enter (\n        );\n\n        void on_wheel_up (\n            unsigned long state\n        );\n\n        void on_wheel_down (\n            unsigned long state\n        );\n        \n        void on_focus_gained (\n        );\n\n        void on_focus_lost (\n        );\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_string_put (\n            const std::wstring &str\n        );\n\n        void on_user_event (\n            void* p,\n            int i\n        );\n\n    private:\n        \n        friend class drawable;\n\n\n        rgb_pixel bg_color;\n\n        typedef set<drawable*>::kernel_1a_c set_of_drawables;\n\n        binary_search_tree<long,set_of_drawables>::kernel_1a_c widgets;\n\n        set_of_drawables widget_set;\n        set_of_drawables mouse_move;\n        set_of_drawables mouse_wheel;\n        set_of_drawables mouse_click;\n        set_of_drawables window_resized;\n        set_of_drawables keyboard;\n        set_of_drawables focus;\n        set_of_drawables window_moved;\n        set_of_drawables string_put;\n\n        long lastx, lasty;\n        unsigned long event_id;\n\n\n        // restricted functions\n        drawable_window(drawable_window&);        // copy constructor\n        drawable_window& operator=(drawable_window&);    // assignment operator\n\n\n    };\n\n    drawable_window::~drawable_window(){ close_window();}\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class drawable  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum \n    {\n        MOUSE_MOVE = 1,\n        MOUSE_CLICK = 2,\n        MOUSE_WHEEL = 4,\n        WINDOW_RESIZED = 8,\n        KEYBOARD_EVENTS = 16,\n        FOCUS_EVENTS = 32,\n        WINDOW_MOVED = 64,\n        STRING_PUT = 128\n    };\n\n    class drawable \n    {\n\n        /*!\n            INITIAL VALUE \n                - enabled_events == false\n                - event_id == 0\n\n            CONVENTION\n                - events == a bitset specifying what events this drawable is to receive.\n\n                - z_order_value == z_order()\n\n                - if (this drawable has been added to the parent window's sets and\n                  binary search tree) then\n                    - enabled_events == true\n                - else\n                    - enabled_events == false\n\n                - event_id == the id of the last event we got from our parent window\n        !*/\n\n    public:\n\n        friend class drawable_window;\n\n        drawable (\n            drawable_window& w,\n            unsigned long events_ = 0\n        ) :\n            m(w.wm),\n            parent(w),\n            hidden(false),\n            enabled(true),\n            lastx(w.lastx),\n            lasty(w.lasty),\n            mfont(default_font::get_font()),\n            z_order_value(0),\n            events(events_),\n            enabled_events(false),\n            event_id(0)\n        {}\n\n        virtual ~drawable (\n        );\n\n        long z_order (\n        ) const\n        {\n            m.lock();\n            long temp = z_order_value;\n            m.unlock();\n            return temp;\n        }\n\n        virtual void set_z_order (\n            long order\n        );\n\n        const rectangle get_rect (\n        ) const \n        {\n            auto_mutex M(m);\n            return rect;\n        }\n\n        long bottom (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.bottom(); \n        }\n\n        long top (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.top(); \n        }\n\n        long left (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.left(); \n        }\n\n        long right (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.right(); \n        }\n\n        long width (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.width(); \n        }\n\n        long height (\n        ) const \n        { \n            auto_mutex M(m); \n            return rect.height(); \n        }\n\n        bool is_enabled (\n        ) const\n        {\n            auto_mutex M(m);\n            return enabled;\n        }\n\n        virtual void enable (\n        ) \n        {\n            auto_mutex M(m);\n            enabled = true;\n            parent.invalidate_rectangle(rect);\n        }\n\n        virtual void disable (\n        ) \n        {\n            auto_mutex M(m);\n            enabled = false;\n            parent.invalidate_rectangle(rect);\n        }\n\n        virtual void set_main_font (\n            const std::shared_ptr<font>& f\n        )\n        {\n            auto_mutex M(m);\n            mfont = f;\n            parent.invalidate_rectangle(rect);\n        }\n\n        const std::shared_ptr<font> main_font (\n        ) const\n        {\n            auto_mutex M(m);\n            return mfont;\n        }\n\n        bool is_hidden (\n        ) const\n        {\n            auto_mutex M(m);\n            return hidden;\n        }\n\n        virtual void set_pos (\n            long x,\n            long y\n        )\n        {\n            m.lock();       \n            rectangle old(rect);            \n\n            const unsigned long width = rect.width();\n            const unsigned long height = rect.height();\n            rect.set_top(y);\n            rect.set_left(x);\n            rect.set_right(static_cast<long>(x+width)-1);\n            rect.set_bottom(static_cast<long>(y+height)-1);\n            \n            parent.invalidate_rectangle(rect+old);\n            m.unlock();\n        }\n\n        virtual void show (\n        )\n        {\n            m.lock();\n            hidden = false;\n            parent.invalidate_rectangle(rect);\n            m.unlock();\n        }\n\n        virtual void hide (\n        )\n        {\n            m.lock();\n            hidden = true;\n            parent.invalidate_rectangle(rect);\n            m.unlock();\n        }\n\n        base_window& parent_window (\n        ) { return parent; }\n\n        const base_window& parent_window (\n        ) const { return parent; }\n\n        virtual int next_free_user_event_number (\n        )const { return 0; }\n\n    protected:   \n        rectangle rect;\n        const rmutex& m;\n        drawable_window& parent;\n        bool hidden;\n        bool enabled;\n        const long& lastx;\n        const long& lasty;\n        std::shared_ptr<font> mfont;\n\n        \n        void enable_events (\n        );\n\n        bool events_are_enabled (\n        ) const { auto_mutex M(m); return enabled_events; }\n\n        void disable_events (\n        );\n\n    private:\n\n        long z_order_value;\n        const unsigned long events;\n        bool enabled_events;\n        unsigned long event_id;\n\n\n        // restricted functions\n        drawable(drawable&);        // copy constructor\n        drawable& operator=(drawable&);    // assignment operator\n\n\n    protected:\n\n        virtual void draw (\n            const canvas& c\n        ) const=0;\n\n        virtual void on_user_event (\n            int \n        ){}\n\n        virtual void on_window_resized(\n        ){}\n\n        virtual void on_window_moved(\n        ){}\n               \n        virtual void on_mouse_down (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long ,\n            bool \n        ){}\n\n        virtual void on_mouse_up (\n            unsigned long ,\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_move (\n            unsigned long ,\n            long ,\n            long \n        ){}\n\n        virtual void on_mouse_leave (\n        ){}\n\n        virtual void on_mouse_enter (\n        ){}\n\n        virtual void on_wheel_up (\n            unsigned long \n        ){}\n\n        virtual void on_wheel_down (\n            unsigned long \n        ){}\n\n        virtual void on_focus_gained (\n        ){}\n\n        virtual void on_focus_lost (\n        ){}\n\n        virtual void on_keydown (\n            unsigned long ,\n            bool ,\n            unsigned long \n        ){}\n\n        virtual void on_string_put (\n            const std::wstring&\n        ){}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"drawable.cpp\"\n#endif\n\n#endif // DLIB_DRAWABLe_\n\n"
  },
  {
    "path": "dlib/gui_widgets/drawable_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#undef DLIB_DRAWABLe_ABSTRACT_\n#ifdef DLIB_DRAWABLe_ABSTRACT_\n\n#include \"../gui_core.h\"\n#include \"fonts_abstract.h\"\n#include \"canvas_drawing_abstract.h\"\n\nnamespace dlib\n{\n\n    /*!\n        GENERAL REMARKS\n            This file defines the drawable interface class and the drawable_window which\n            is just a window that is capable of displaying drawable objects (i.e. objects\n            that implement the drawable interface).  \n\n            The drawable interface is a simple framework for creating more complex \n            graphical widgets.  It provides a default set of functionality and a \n            set of events which a gui widget may use.\n\n        THREAD SAFETY\n            All objects and functions defined in this file are thread safe.  You may\n            call them from any thread without serializing access to them.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class drawable_window\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class drawable_window : public base_window\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a window on the desktop that is capable of \n                containing drawable objects.\n\n            INITIAL STATE\n                The initial state of the drawable_window is to be hidden.  This means \n                you need to call show() to make it appear.\n\n            EVENTS\n                The drawable_window object uses all the events provided by base_window\n                except for the on_window_close() event.  This means that if you\n                define handlers for these events yourself you will have to call\n                the drawable_window's version of them so that the drawable_window \n                can continue to process and forward these events to its drawable \n                objects.                \n        !*/\n    public:\n\n        drawable_window (\n            bool resizable = true,\n            bool undecorated = false\n        );\n        /*!\n            requires\n                - if (undecorated == true) then\n                    - resizable == false\n            ensures\n                - #*this has been properly initialized \n                - #background_color() == rgb_pixel(212,208,200)\n                - if (resizable == true) then \n                    - this window will be resizable by the user\n                - else \n                    - this window will not be resizable by the user\n                - if (undecorated == true) then\n                    - this window will not have any graphical elements outside\n                      of its drawable area or appear in the system task bar.\n                      (e.g. a popup menu)\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n                - dlib::gui_error\n                    This exception is thrown if there is an error while \n                    creating this window.\n        !*/\n\n        virtual ~drawable_window(\n        )=0;\n        /*!\n            ensures\n                - if (this window has not already been closed) then\n                    - closes the window\n                - does NOT trigger the on_window_close() event\n                - all resources associated with *this have been released                \n        !*/\n\n        void set_background_color (\n            unsigned long red,\n            unsigned long green,\n            unsigned long blue\n        );\n        /*!\n            ensures\n                - #background_color().red == red\n                - #background_color().green == green \n                - #background_color().blue == blue \n        !*/\n\n        rgb_pixel background_color (\n        ) const;\n        /*!\n            ensures\n                - returns the background color this window paints its canvas\n                  with before it passes it onto its drawable widgets\n        !*/\n\n    private:\n        // restricted functions\n        drawable_window(drawable_window&);        // copy constructor\n        drawable_window& operator=(drawable_window&);    // assignment operator\n        \n        friend class drawable;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class drawable\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum \n    {\n        MOUSE_MOVE = 1,\n        MOUSE_CLICK = 2,\n        MOUSE_WHEEL = 4,\n        WINDOW_RESIZED = 8,\n        KEYBOARD_EVENTS = 16,\n        FOCUS_EVENTS = 32,\n        WINDOW_MOVED = 64,\n        STRING_PUT = 128\n    };\n\n    class drawable \n    {\n        /*!\n            INITIAL VALUE\n                top() == 0\n                left() == 0\n                right() == -1 \n                bottom() == -1 \n                get_rect().is_empty() == true\n                is_hidden() == false \n                is_enabled() == true\n                z_order() == 0\n                main_font() == default_font::get_font()\n            \n            WHAT THIS OBJECT REPRESENTS\n                This is an interface that all drawable widgets implement.  It \n                provides a standard method (draw()) to draw a widget onto a canvas \n                and many other convenient functions for drawable objects.\n\n            EVENT FORWARDING\n                All the events that come to a drawable object are forwarded from its\n                parent window.  Additionally, there is no filtering.  This means that\n                if a drawable registers to receive a certain kind of event then whenever\n                its parent window receives that event the drawable object will get a \n                forwarded copy of it as well even if the event occurred outside the\n                drawable's rectangle. \n\n                The only events that have anything in the way of filtering are the \n                draw() and on_user_event() events.  draw() is only called on a drawable \n                object when that object is not hidden.  on_user_event() is only called\n                for drawables that the on_user_event()'s first argument specifically \n                references.  All other events are not filtered at all though.\n\n            Z ORDER\n                Z order defines the order in which drawable objects are drawn.  The\n                lower numbered drawables are drawn first and then the higher numbered\n                ones.  So a drawable with a z order of 0 is drawn before one with a\n                z order of 1 and so on.  \n        !*/\n\n    public:\n\n        friend class drawable_window;\n\n        drawable (\n            drawable_window& w,\n            unsigned long events = 0\n        ) : \n            m(w.wm),\n            parent(w),\n            hidden(false),\n            enabled(true)\n        {}\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #parent_window() == w\n                - #*this will not receive any events or draw() requests until \n                  enable_events() is called\n                - once events_are_enabled() == true this drawable will receive\n                  the on_user_event() event. (i.e. you always get this event, you don't\n                  have to enable it by setting something in the events bitset).\n                - if (events & MOUSE_MOVE) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following events related to mouse movement: on_mouse_move, \n                      on_mouse_leave, and on_mouse_enter.\n                - if (events & MOUSE_CLICK) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following events related to mouse clicks: on_mouse_down and \n                      on_mouse_up.\n                - if (events & MOUSE_WHEEL) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following events related to mouse wheel scrolling: \n                      on_wheel_up and on_wheel_down.\n                - if (events & WINDOW_RESIZED) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following event related to its parent window resizing:  \n                      on_window_resized.    \n                - if (events & KEYBOARD_EVENTS) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following keyboard event: on_keydown.                \n                - if (events & FOCUS_EVENTS) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following focus events: on_focus_gained and on_focus_lost.                \n                - if (events & WINDOW_MOVED) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following event related to its parent window moving:  \n                      on_window_moved.    \n                - if (events & STRING_PUT) then\n                    - once events_are_enabled() == true this drawable will receive \n                      the following event related to wide character string input:  \n                      on_string_put.    \n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~drawable (\n        );\n        /*!\n            requires\n                - events_are_enabled() == false\n            ensures\n                - any resources associated with *this have been released\n                - *this has been removed from its containing window parent_window() and\n                  its parent window will no longer try to dispatch events to it.\n                  Note that this does not trigger a redraw of the parent window.  If you \n                  want to do that you must do it yourself.\n        !*/\n\n        long z_order (\n        ) const;\n        /*!\n            ensures\n                - returns the z order for this drawable.  \n        !*/\n\n        virtual void set_z_order (\n            long order\n        );\n        /*!\n            ensures\n                - #z_order() == order\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n            throws\n                - std::bad_alloc\n        !*/\n\n        const rectangle get_rect (\n        ) const;\n        /*!\n            ensures\n                - returns the rectangle that defines the area and position of this \n                  drawable inside its containing window parent_window().\n        !*/\n\n        long bottom (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().bottom()\n        !*/\n\n        long top (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().top()\n        !*/\n\n        long left (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().left()\n        !*/\n\n        long right (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().right()\n        !*/\n\n        unsigned long width (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().width()\n        !*/\n\n        unsigned long height (\n        ) const;\n        /*!\n            ensures\n                - returns get_rect().height()\n        !*/\n\n        virtual void set_pos (\n            long x,\n            long y\n        );\n        /*! \n            ensures\n                - #top() == y\n                - #left() == x\n                - #width() == width()\n                - #height() == height()\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n                - i.e. This just sets the upper left corner of this drawable to the\n                  location (x,y)\n        !*/\n\n        bool is_enabled (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object is enabled and false otherwise.\n                  (it is up to derived classes to define exactly what it means to be\n                  \"enabled\")\n        !*/\n\n        virtual void enable (\n        );\n        /*!\n            ensures\n                - #is_enabled() == true\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n        !*/\n\n        virtual void disable (\n        );\n        /*!\n            ensures\n                - #is_enabled() == false\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n        !*/\n\n        virtual void set_main_font (\n            const shared_ptr_thread_safe<font>& f\n        );\n        /*!\n            ensures\n                - #main_font() == f\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n        !*/\n\n        const shared_ptr_thread_safe<font> main_font (\n        ) const;\n        /*!\n            ensures\n                - returns the current main font being used by this widget\n        !*/\n\n        bool is_hidden (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object is NOT currently displayed on parent_window()\n                  and false otherwise.\n        !*/\n\n        virtual void show (\n        );\n        /*!\n            ensures\n                - #is_hidden() == false\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n        !*/\n\n        virtual void hide (\n        );\n        /*!\n            ensures\n                - #is_hidden() == true\n                - if (events_are_enabled() == true) then\n                    - parent_window() is updated to reflect the new state of #*this \n        !*/\n\n        drawable_window& parent_window (\n        );\n        /*! \n            ensures\n                - returns a reference to the drawable_window that this drawable is \n                  being drawn on and receiving events from.\n        !*/\n\n        const drawable_window& parent_window (\n        ) const;\n        /*! \n            ensures\n                - returns a const reference to the drawable_window that this drawable \n                  is being drawn on and receiving events from.\n        !*/\n\n        virtual int next_free_user_event_number (\n        )const { return 0; }\n        /*!\n            ensures\n                - returns the smallest number, i, that is the next user event number you \n                  can use in calls to parent.trigger_user_event((void*)this,i).\n                - This function exists because of the following scenario.  Suppose\n                  you make a class called derived1 that inherits from drawable and \n                  in derived1 you use a user event to do something.  Then suppose \n                  you inherit from derived1 to make derived2.  Now in derived2 you \n                  may want to use a user event to do something as well.  How are you\n                  to know which user event numbers are in use already?  This function\n                  solves that problem.  You would define derived1::next_free_user_event_number()\n                  so that it returned a number bigger than any user event numbers used by\n                  derived1 or its ancestors.  Then derived2 could just call \n                  derived1::next_free_user_event_number() to find out what numbers it could use.\n        !*/\n\n    protected:   \n        /*!A drawable_protected_variables \n            \n            These protected members are provided because they are needed to \n            implement drawable widgets.\n        !*/\n\n        // This is the rectangle that is returned by get_rect()\n        rectangle rect;\n\n        // This is the mutex used to serialize access to this class. \n        const rmutex& m;\n\n        // This is the parent window of this drawable\n        drawable_window& parent;\n\n        // This is the bool returned by is_hidden()\n        bool hidden;\n\n        // This is the bool returned by is_enabled()\n        bool enabled;\n\n        // This is the font pointer returned by main_font()\n        shared_ptr_thread_safe<font> mfont;\n\n        // This is the x coordinate that we last saw the mouse at or -1 if the mouse\n        // is outside the parent window.\n        const long& lastx;\n\n        // This is the y coordinate that we last saw the mouse at or -1 if the mouse\n        // is outside the parent window.\n        const long& lasty;\n\n\n        void enable_events (\n        );\n        /*!\n            ensures\n                - #events_are_enabled() == true\n        !*/\n\n        void disable_events (\n        );\n        /*!\n            ensures\n                - #events_are_enabled() == false\n        !*/\n\n        bool events_are_enabled (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object is receiving events and draw()\n                  requests from its parent window.\n                - returns false otherwise\n        !*/\n\n        // ---------------- EVENT HANDLERS ------------------\n\n        virtual void on_user_event (\n            int i\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - is called whenever the parent window receives an on_user_event(p,i) event\n                  where p == this.  (i.e. this is just a redirect of on_user_event for\n                  cases where the first argument of on_user_event is equal to the \n                  this pointer).\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_window_resized(\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_window_resized() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n               \n        virtual void on_window_moved(\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_window_moved() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n               \n        virtual void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_mouse_down() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_mouse_up() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - x == lastx\n                - y == lasty\n                - this is just the base_window::on_mouse_move() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_mouse_leave (\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_mouse_leave() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_mouse_enter (\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_mouse_enter() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_wheel_up (\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_wheel_up() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_wheel_down (\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_wheel_down() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_focus_gained (\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_focus_gained() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_focus_lost (\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_focus_lost() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_keydown() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void on_string_put (\n            const std::wstring &str\n        ){}\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - this is just the base_window::on_put_string() event forwarded to \n                  this object.  See the gui_core specs for the details about this event.\n            ensures\n                - does not change the state of mutex m. \n        !*/\n\n        virtual void draw (\n            const canvas& c\n        ) const=0;\n        /*!\n            requires\n                - events_are_enabled() == true\n                - mutex m is locked\n                - is_hidden() == false\n                - is called by parent_window() when it needs to repaint itself.\n                - c == the canvas object for the area of parent_window() that needs\n                  to be repainted.\n            ensures\n                - does not change the state of mutex m. \n                - draws the area of *this that intersects with the canvas onto\n                  the canvas object c.\n        !*/\n\n    private:\n\n        // restricted functions\n        drawable(drawable&);        // copy constructor\n        drawable& operator=(drawable&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAWABLe_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/gui_widgets/fonts.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt, Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FONTs_CPP_\n#define DLIB_FONTs_CPP_\n\n#include \"fonts.h\"\n\n#include <fstream>\n#include <memory>\n#include <sstream>\n\n#include \"../serialize.h\"\n#include \"../base64.h\"\n#include \"../compress_stream.h\"\n#include \"../tokenizer.h\"\n#include \"nativefont.h\"\n   \nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string get_decoded_string_with_default_font_data()\n    {\n        dlib::base64::kernel_1a base64_coder;\n        dlib::compress_stream::kernel_1ea compressor;\n        std::ostringstream sout;\n        std::istringstream sin;\n\n        /* \n            SOURCE BDF FILE (helvR12.bdf) COMMENTS \n            COMMENT $XConsortium: helvR12.bdf,v 1.15 95/01/26 18:02:58 gildea Exp $\n            COMMENT $Id: helvR12.bdf,v 1.26 2004-11-28 20:08:46+00 mgk25 Rel $\n            COMMENT \n            COMMENT +\n            COMMENT  Copyright 1984-1989, 1994 Adobe Systems Incorporated.\n            COMMENT  Copyright 1988, 1994 Digital Equipment Corporation.\n            COMMENT \n            COMMENT  Adobe is a trademark of Adobe Systems Incorporated which may be\n            COMMENT  registered in certain jurisdictions.\n            COMMENT  Permission to use these trademarks is hereby granted only in\n            COMMENT  association with the images described in this file.\n            COMMENT \n            COMMENT  Permission to use, copy, modify, distribute and sell this software\n            COMMENT  and its documentation for any purpose and without fee is hereby\n            COMMENT  granted, provided that the above copyright notices appear in all\n            COMMENT  copies and that both those copyright notices and this permission\n            COMMENT  notice appear in supporting documentation, and that the names of\n            COMMENT  Adobe Systems and Digital Equipment Corporation not be used in\n            COMMENT  advertising or publicity pertaining to distribution of the software\n            COMMENT  without specific, written prior permission.  Adobe Systems and\n            COMMENT  Digital Equipment Corporation make no representations about the\n            COMMENT  suitability of this software for any purpose.  It is provided \"as\n            COMMENT  is\" without express or implied warranty.\n            COMMENT -\n        */\n\n        // The base64 encoded data we want to decode and return.\n        sout << \"AXF+zOQzCgGitrKiOCGEL4hlIv1ZenWJyjMQ4rJ6f/oPMeHqsZn+8XnpehwFQTz3dtUGlZRAUoOa\";\n        sout << \"uVo8UiplcFxuK69A+94rpMCMAyEeeOwZ/tRzkX4eKuU3L4xtsJDknMiYUNKaMrYimb1QJ0E+SRqQ\";\n        sout << \"wATrMTecYNZvJJm02WibiwE4cJ5scvkHNl4KJT5QfdwRdGopTyUVdZvRvtbTLLjsJP0fQEQLqemf\";\n        sout << \"qPE4kDD79ehrBIwLO1Y6TzxtrrIoQR57zlwTUyLenqRtSN3VLtjWYd82cehRIlTLtuxBg2s+zZVq\";\n        sout << \"jNlNnYTSM+Swy06qnQgg+Dt0lhtlB9shR1OAlcfCtTW6HKoBk/FGeDmjTGW4bNCGv7RjgM6TlLDg\";\n        sout << \"ZYSSA6ZCCAKBgE++U32gLHCCiVkPTkkp9P6ioR+e3SSKRNm9p5MHf+ZQ3LJkW8KFJ/K9gKT1yvyv\";\n        sout << \"F99pAvOOq16tHRFvzBs+xZj/mUpH0lGIS7kLWr9oP2KuccVrz25aJn3kDruwTYoD+CYlOqtPO0Mv\";\n        sout << \"dEI0LUR0Ykp1M2rWo76fJ/fpzHjV7737hjkNPJ13nO72RMDr4R5V3uG7Dw7Ng+vGX3WgJZ4wh1JX\";\n        sout << \"pl2VMqC5JXccctzvnQvnuvBvRm7THgwQUgMKKT3WK6afUUVlJy8DHKuU4k1ibfVMxAmrwKdTUX2w\";\n        sout << \"cje3A05Qji3aop65qEdwgI5O17HIVoRQOG/na+XRMowOfUvI4H8Z4+JGACfRrQctgYDAM9eJzm8i\";\n        sout << \"PibyutmJfZBGg0a3oC75S5R9lTxEjPocnEyJRYNnmVnVAmKKbTbTsznuaD+D1XhPdr2t3A4bRTsp\";\n        sout << \"toKKtlFnd9YGwLWwONDwLnoQ/IXwyF7txrRHNSVToh772U0Aih/yn5vnmcMF750eiMzRAgXu5sbR\";\n        sout << \"VXEOVCiLgVevN5umkvjZt1eGTSSzDMrIvnv4nyOfaFsD+I76wQfgLqd71rheozGtjNc0AOTx4Ggc\";\n        sout << \"eUSFHTDAVfTExBzckurtyuIAqF986a0JLHCtsDpBa2wWNuiQYOH3/LX1zkdU2hdamhBW774bpEwr\";\n        sout << \"dguMxxOeDGOBgIlM5gxXGYXSf5IN3fUAEPfOPRxB7T+tpjFnWd7cg+JMabci3zhJ9ANaYT7HGeTX\";\n        sout << \"bulKnGHjYrR1BxdK3YeliogQRU4ytmxlyL5zlNFU/759mA8XSfIPMEZn9Vxkb00q1htF7REiDcr3\";\n        sout << \"kW1rtPAc7VQNEhT54vK/YF6rMvjO7kBZ/vLYo7E8e8hDKEnY8ucrC3KGmeo31Gei74BBcEbvJBd3\";\n        sout << \"/YAaIKgXWwU2wSUw9wLq2RwGwyguvKBx0J/gn27tjcVAHorRBwxzPpk8r+YPyN+SifSzEL7LEy1G\";\n        sout << \"lPHxmXTrcqnH9qraeAqXJUJvU8SJJpf/tmsAE+XSKD/kpVBnT5qXsJ1SRFS7MtfPjE1j/NYbaQBI\";\n        sout << \"bOrh81zaYCEJR0IKHWCIsu/MC3zKXfkxFgQ9XpYAuWjSSK64YpgkxSMe8VG8yYvigOw2ODg/z4FU\";\n        sout << \"+HpnEKF/M/mKfLKK1i/8BV7xcYVHrhEww1QznoFklJs/pEg3Kd5PE1lRii6hvTn6McVAkw+YbH9q\";\n        sout << \"/sg4gFIAvai64hMcZ1oIZYppj3ZN6KMdyhK5s4++ZS/YOV2nNhW73ovivyi2Tjg7lxjJJtsYrLKb\";\n        sout << \"zIN1slOICKYwBq42TFBcFXaZ6rf0Czd09tL+q6A1Ztgr3BNuhCenjhWN5ji0LccGYZo6bLTggRG/\";\n        sout << \"Uz6K3CBBU/byLs79c5qCohrr7rlpDSdbuR+aJgNiWoU6T0i2Tvua6h51LcWEHy5P2n146/Ae2di4\";\n        sout << \"eh20WQvclrsgm1oFTGD0Oe85GKOTA7vvwKmLBc1wwA0foTuxzVgj0TMTFBiYLTLG4ujUyBYy1N6e\";\n        sout << \"H8EKi8H+ZAlqezrjABO3BQr33ewdZL5IeJ4w7gdGUDA6+P+7cODcBW50X9++6YTnKctuEw6aXBpy\";\n        sout << \"GgcMfPE61G8YKBbFGFic3TVvGCLvre1iURv+F+hU4/ee6ILuPnpYnSXX2iCIK/kmkBse8805d4Qe\";\n        sout << \"DG/8rBW9ojvAgc0jX7CatPEMHGkcz+KIZoKMI7XXK4PJpGQUdq6EdIhJC4koXEynjwwXMeC+jJqH\";\n        sout << \"agwrlDNssq/8AA==\";\n\n\n\n        // Put the data into the istream sin\n        sin.str(sout.str());\n        sout.str(\"\");\n\n        // Decode the base64 text into its compressed binary form\n        base64_coder.decode(sin,sout);\n        sin.clear();\n        sin.str(sout.str());\n        sout.str(\"\");\n\n        // Decompress the data into its original form\n        compressor.decompress(sin,sout);\n\n        // Return the decoded and decompressed data\n        return sout.str();\n    }\n\n\n    default_font::\n    default_font (\n    ) \n    {\n        using namespace std;\n        l = new letter[256];\n\n        try\n        {\n            istringstream sin(get_decoded_string_with_default_font_data());\n\n            for (int i = 0; i < 256; ++i)\n            {\n                deserialize(l[i],sin);\n            }\n\n        }\n        catch (...)\n        {\n            delete [] l;\n            throw;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const letter& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.w,out);\n            serialize(item.count,out);\n\n            for (unsigned long i = 0; i < item.count; ++i)\n            {\n                serialize(item.points[i].x,out);\n                serialize(item.points[i].y,out);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type letter\"); \n        }\n    }\n\n    void deserialize (\n        letter& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            if (item.points)\n                delete [] item.points;\n\n            deserialize(item.w,in);\n            deserialize(item.count,in);\n\n            if (item.count > 0)\n                item.points = new letter::point[item.count];\n            else\n                item.points = 0;\n\n            for (unsigned long i = 0; i < item.count; ++i)\n            {\n                deserialize(item.points[i].x,in);\n                deserialize(item.points[i].y,in);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.w = 0;\n            item.count = 0;\n            item.points = 0;\n            throw serialization_error(e.info + \"\\n   while deserializing object of type letter\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace bdf_font_helpers\n    {\n        class bdf_parser\n        {\n        public:\n            bdf_parser( std::istream& in ) : in_( in )\n            {\n                std::string str_tmp;\n                int int_tmp;\n\n                str_tmp = \"STARTFONT\";      int_tmp = STARTFONT;        keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"FONTBOUNDINGBOX\";int_tmp = FONTBOUNDINGBOX;  keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"DWIDTH\";         int_tmp = DWIDTH;           keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"CHARS\";          int_tmp = CHARS;            keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"STARTCHAR\";      int_tmp = STARTCHAR;        keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"ENCODING\";       int_tmp = ENCODING;         keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"BBX\";            int_tmp = BBX;              keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"BITMAP\";         int_tmp = BITMAP;           keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"ENDCHAR\";        int_tmp = ENDCHAR;          keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"ENDFONT\";        int_tmp = ENDFONT;          keyword_map.add( str_tmp, int_tmp );\n                str_tmp = \"DEFAULT_CHAR\";   int_tmp = DEFAULT_CHAR;     keyword_map.add( str_tmp, int_tmp );\n\n                tokzr.set_identifier_token( tokzr.uppercase_letters(), tokzr.uppercase_letters() + \"_\" );\n                tokzr.set_stream( in );\n\n            }\n\n            enum bdf_enums\n            {\n                NO_KEYWORD = 0,\n                STARTFONT = 1,\n                FONTBOUNDINGBOX = 2,\n                DWIDTH = 4,\n                DEFAULT_CHAR = 8,\n                CHARS = 16,\n                STARTCHAR = 32,\n                ENCODING = 64,\n                BBX = 128,\n                BITMAP = 256,\n                ENDCHAR = 512,\n                ENDFONT = 1024\n\n            };\n            struct header_info\n            {\n                int FBBx, FBBy, Xoff, Yoff;\n                int dwx0, dwy0;\n                bool has_global_dw;\n                long default_char;\n            };\n            struct char_info\n            {\n                int dwx0, dwy0;\n                int BBw, BBh, BBxoff0x, BByoff0y;\n                array2d<char> bitmap;\n                bool has_dw;\n            };\n            bool parse_header( header_info& info )\n            {\n                if ( required_keyword( STARTFONT ) == false )\n                    return false;    // parse_error: required keyword missing\n                info.has_global_dw = false;\n                int find = FONTBOUNDINGBOX | DWIDTH | DEFAULT_CHAR;\n                int stop = CHARS | STARTCHAR | ENCODING | BBX | BITMAP | ENDCHAR | ENDFONT;\n                int res;\n                while ( 1 )\n                {\n                    res = find_keywords( find | stop );\n                    if ( res & FONTBOUNDINGBOX )\n                    {\n                        in_ >> info.FBBx >> info.FBBy >> info.Xoff >> info.Yoff;\n                        if ( in_.fail() )\n                            return false;    // parse_error\n                        find &= ~FONTBOUNDINGBOX;\n                        continue;\n                    }\n                    if ( res & DWIDTH )\n                    {\n                        in_ >> info.dwx0 >> info.dwy0;\n                        if ( in_.fail() )\n                            return false;    // parse_error\n                        find &= ~DWIDTH;\n                        info.has_global_dw = true;\n                        continue;\n                    }\n                    if ( res & DEFAULT_CHAR )\n                    {\n                        in_ >> info.default_char;\n                        if ( in_.fail() )\n                            return false;    // parse_error\n                        find &= ~DEFAULT_CHAR;\n                        continue;\n                    }\n                    if ( res & NO_KEYWORD )\n                        return false;    // parse_error: unexpected EOF\n                    break;\n                }\n                if ( res != CHARS || ( find & FONTBOUNDINGBOX ) )\n                    return false;    // parse_error: required keyword missing or unexpeced keyword\n                return true;\n            }\n            int parse_glyph( char_info& info, unichar& enc )\n            {\n                info.has_dw = false;\n                int e;\n                int res;\n                while ( 1 )\n                {\n                    res = find_keywords( ENCODING );\n                    if ( res != ENCODING )\n                        return 0; // no more glyphs\n                    in_ >> e;\n                    if ( in_.fail() )\n                        return -1;    // parse_error\n                    if ( e >= static_cast<int>(enc) )\n                        break;\n                }\n                int find = BBX | DWIDTH;\n                int stop = STARTCHAR | ENCODING | BITMAP | ENDCHAR | ENDFONT;\n                while ( 1 )\n                {\n                    res = find_keywords( find | stop );\n                    if ( res & BBX )\n                    {\n                        in_ >> info.BBw >> info.BBh >> info.BBxoff0x >> info.BByoff0y;\n                        if ( in_.fail() )\n                            return -1;    // parse_error\n                        find &= ~BBX;\n                        continue;\n                    }\n                    if ( res & DWIDTH )\n                    {\n                        in_ >> info.dwx0 >> info.dwy0;\n                        if ( in_.fail() )\n                            return -1;    // parse_error\n                        find &= ~DWIDTH;\n                        info.has_dw = true;\n                        continue;\n                    }\n                    if ( res & NO_KEYWORD )\n                        return -1;    // parse_error: unexpected EOF\n                    break;\n                }\n                if ( res != BITMAP || ( find != NO_KEYWORD ) )\n                    return -1;     // parse_error: required keyword missing or unexpeced keyword\n                unsigned h = info.BBh;\n                unsigned w = ( info.BBw + 7 ) / 8 * 2;\n                info.bitmap.set_size( h, w );\n                for ( unsigned r = 0;r < h;r++ )\n                {\n                    trim();\n                    std::string str = \"\";\n                    extract_hex(str);\n                    if(str.size() < w)\n                        return -1;    // parse_error\n                    for ( unsigned c = 0;c < w;c++ )\n                        info.bitmap[r][c] = str[c];\n                }\n                if ( in_.fail() )\n                    return -1;      // parse_error\n                if ( required_keyword( ENDCHAR ) == false )\n                    return -1;      // parse_error: required keyword missing\n                enc = e;\n                return 1;\n            }\n        private:\n            map<std::string, int>::kernel_1a_c keyword_map;\n            tokenizer::kernel_1a_c tokzr;\n            std::istream& in_;\n            void extract_hex(std::string& str)\n            {\n                int type;\n                std::string token;\n                while ( 1 )\n                {\n                    type = tokzr.peek_type();\n                    if ( type == tokenizer::kernel_1a_c::IDENTIFIER || type == tokenizer::kernel_1a_c::NUMBER )\n                    {\n                        tokzr.get_token( type, token );\n                        str += token;\n                        continue;\n                    }\n                    break;\n                }\n            }\n            void trim()\n            {\n                int type;\n                std::string token;\n                while ( 1 )\n                {\n                    type = tokzr.peek_type();\n                    if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE )\n                    {\n                        tokzr.get_token( type, token );\n                        continue;\n                    }\n                    break;\n                }\n            }\n            bool required_keyword( int kw )\n            {\n                int type;\n                std::string token;\n                while ( 1 )\n                {\n                    tokzr.get_token( type, token );\n                    if ( type == tokenizer::kernel_1a_c::WHITE_SPACE || type == tokenizer::kernel_1a_c::END_OF_LINE )\n                        continue;\n                    if ( type != tokenizer::kernel_1a_c::IDENTIFIER || keyword_map.is_in_domain( token ) == false || ( keyword_map[token] & kw ) == 0 )\n                        return false;\n                    break;\n                }\n                return true;\n            }\n            int find_keywords( int find )\n            {\n                int type;\n                std::string token;\n                while ( 1 )\n                {\n                    tokzr.get_token( type, token );\n                    if ( type == tokenizer::kernel_1a_c::END_OF_FILE )\n                        return NO_KEYWORD;\n                    if ( type == tokenizer::kernel_1a_c::IDENTIFIER && keyword_map.is_in_domain( token ) == true )\n                    {\n                        int kw = keyword_map[token];\n                        if ( kw & find )\n                            return kw;\n                    }\n                }\n                return true;\n            }\n\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                    bdf_font functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    bdf_font::bdf_font( \n        long default_char_ \n    ) :\n        default_char(0),\n        is_initialized( false ),\n        right_overflow_( 0 ),\n        has_global_width( false ),\n        specified_default_char( default_char_ )\n    {\n        // make sure gl contains at least one letter\n        gl.resize(1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void bdf_font::adjust_metrics(\n    )\n    {\n        if ( is_initialized == false )\n            return;\n        // set starting values for fbb\n        if ( gl[default_char].num_of_points() > 0 )\n        {\n            letter& g =  gl[default_char];\n            fbb.set_top( g[0].y );\n            fbb.set_bottom( g[0].y );\n            fbb.set_left( g[0].x );\n            fbb.set_right( g[0].x );\n        }\n        else\n        {\n            // ok, the default char was a space\n            // let's just choose some safe arbitrary values then...\n            fbb.set_top( 10000 );\n            fbb.set_bottom( -10000 );\n            fbb.set_left( 10000 );\n            fbb.set_right( -10000 );\n        }\n        right_overflow_ = 0;\n        for ( unichar n = 0; n < gl.size(); n++ )\n        {\n            letter& g = gl[n];\n            unsigned short nr_pts = g.num_of_points();\n            for ( unsigned short k = 0;k < nr_pts;k++ )\n            {\n                fbb.set_top( std::min( fbb.top(), (long)g[k].y ) );\n                fbb.set_left( std::min( fbb.left(), (long)g[k].x ) );\n                fbb.set_bottom( std::max( fbb.bottom(), (long)g[k].y ) );\n                fbb.set_right( std::max( fbb.right(), (long)g[k].x ) );\n                right_overflow_ = std::max( right_overflow_, (unsigned long)(g[k].x - g.width()) );  // superfluous?\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long bdf_font::\n    read_bdf_file( \n        std::istream& in, \n        unichar max_enc, \n        unichar min_enc \n    )\n    {\n        using namespace bdf_font_helpers;\n\n        bdf_parser parser( in );\n        bdf_parser::header_info hinfo;\n        bdf_parser::char_info cinfo;\n\n        gl.resize(max_enc+1);\n        hinfo.default_char =  - 1;\n        if ( is_initialized == false || static_cast<std::streamoff>(in.tellg()) == std::ios::beg )\n        {\n            if ( parser.parse_header( hinfo ) == false )\n                return 0;   // parse_error: invalid or missing header\n        }\n        else\n        {\n            // not start of file, so use values from previous read.\n            hinfo.has_global_dw = has_global_width;\n            hinfo.dwx0 = global_width;\n        }\n        int res;\n        unichar nr_letters_added = 0;\n        unsigned width;\n        for ( unichar n = min_enc; n <= max_enc; n++ )\n        {\n            if ( in.eof() )\n                break;\n            long pos = in.tellg();\n            res = parser.parse_glyph( cinfo, n );\n            if ( res < 0 )\n                return 0;  // parse_error\n            if ( res == 0 )\n                continue;\n            if ( n > max_enc )\n            {\n                in.seekg( pos );\n                break;\n            }\n\n            if ( cinfo.has_dw == false )\n            {\n                if ( hinfo.has_global_dw == false )\n                    return 0;    // neither width info for the glyph, nor for the font as a whole (monospace).\n                width = hinfo.dwx0;\n            }\n            else\n                width = cinfo.dwx0;\n\n\n            if ( bitmap_to_letter( cinfo.bitmap, n, width, cinfo.BBxoff0x, cinfo.BByoff0y ) == false )\n                return 0;\n            nr_letters_added++;\n\n            if ( is_initialized == false )\n            {\n                // Bonding rectangle for the font.\n                fbb.set_top( -( hinfo.Yoff + hinfo.FBBy - 1 ) );\n                fbb.set_bottom( -hinfo.Yoff );\n                fbb.set_left( hinfo.Xoff );\n                fbb.set_right( hinfo.Xoff + hinfo.FBBx - 1 );\n                // We need to compute this after all the glyphs are loaded.\n                right_overflow_ = 0;\n                // set this to something valid now, just in case.\n                default_char = n;\n                // Save any global width in case we later read from the same file.\n                has_global_width = hinfo.has_global_dw;\n                if ( has_global_width )\n                    global_width = hinfo.dwx0;\n                // dont override value specified in the constructor with value specified in the file\n                if ( specified_default_char < 0 && hinfo.default_char >= 0 )\n                    specified_default_char = hinfo.default_char;\n\n                is_initialized = true;\n            }\n        }\n        if ( is_initialized == false )\n            return 0;   // Not a single glyph was found within the specified range.\n\n        if ( specified_default_char >= 0 )\n            default_char = specified_default_char;\n        // no default char specified, try find something sane.\n        else \n            default_char = 0;\n\n        return nr_letters_added;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool bdf_font::\n    bitmap_to_letter( \n        array2d<char>& bitmap, \n        unichar enc, \n        unsigned long width, \n        int x_offset,\n        int y_offset \n    )\n    {\n        unsigned nr_points = 0;\n        bitmap.reset();\n        while ( bitmap.move_next() )\n        {\n            unsigned char ch = bitmap.element();\n            if ( ch > '9' )\n                ch -= 'A' - '9' - 1;\n            ch -= '0';\n            if ( ch > 0xF )\n                return false;   // parse error: invalid hex digit\n            bitmap.element() = ch;\n            if ( ch & 8 )\n                nr_points++;\n            if ( ch & 4 )\n                nr_points++;\n            if ( ch & 2 )\n                nr_points++;\n            if ( ch & 1 )\n                nr_points++;\n        }\n\n        letter( width, nr_points ).swap(gl[enc]);\n\n        unsigned index = 0;\n        for ( int r = 0;r < bitmap.nr();r++ )\n        {\n            for ( int c = 0;c < bitmap.nc();c++ )\n            {\n                int x = x_offset + c * 4;\n                int y = -( y_offset + bitmap.nr() - r - 1 );\n                char ch = bitmap[r][c];\n                letter& glyph =  gl[enc];\n                if ( ch & 8 )\n                {\n                    glyph[index] = letter::point( x, y );\n                    right_overflow_ = std::max( right_overflow_, x - width );\n                    index++;\n                }\n                if ( ch & 4 )\n                {\n                    glyph[index] = letter::point( x + 1, y );\n                    right_overflow_ = std::max( right_overflow_, x + 1 - width );\n                    index++;\n                }\n                if ( ch & 2 )\n                {\n                    glyph[index] = letter::point( x + 2, y );\n                    right_overflow_ = std::max( right_overflow_, x + 2 - width );\n                    index++;\n                }\n                if ( ch & 1 )\n                {\n                    glyph[index] = letter::point( x + 3, y );\n                    right_overflow_ = std::max( right_overflow_, x + 3 - width );\n                    index++;\n                }\n            }\n        }\n        return true;\n    }\n\n#ifndef DLIB_NO_GUI_SUPPORT\n// ----------------------------------------------------------------------------------------\n\n    const std::shared_ptr<font> get_native_font (\n    )\n    {\n        return nativefont::native_font::get_font();\n    }\n\n// ----------------------------------------------------------------------------------------\n#endif\n\n}\n\n#endif // DLIB_FONTs_CPP_\n\n"
  },
  {
    "path": "dlib/gui_widgets/fonts.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), and Nils Labugt, Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_FONTs_\n#define DLIB_FONTs_\n\n#include <memory>\n#include <string>\n\n#include \"fonts_abstract.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../unicode.h\"\n#include \"../array.h\"\n#include \"../array2d.h\"\n#include \"../threads.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class letter \n    {    \n        /*!\n            INITIAL VALUE\n                - defined by constructor\n\n            CONVENTION\n                - if (points != 0) then\n                    - points == an array of count point structs\n                - w == width()\n                - count == num_of_points()\n        !*/\n    public:\n        struct point \n        {\n            point (){}\n\n            point (\n                signed char x_,\n                signed char y_\n            ) :\n                x(x_),\n                y(y_)\n            {}\n\n            signed char x;\n            signed char y;\n        };\n\n        letter (\n        ) :\n            points(0),\n            w(0),\n            count(0)\n        {}\n\n        letter (\n            unsigned short width_,\n            unsigned short point_count\n        ) : \n            points(new point[point_count]),\n            w(width_),\n            count(point_count)\n        {}\n\n        ~letter(\n        )\n        {\n            if (points)\n                delete [] points; \n        }\n            \n        unsigned short width (\n        ) const { return w; }\n        \n        unsigned short num_of_points (\n        ) const { return count;}\n\n        point& operator[] (\n            unsigned short i\n        ) \n        { \n            DLIB_ASSERT (i < num_of_points(),\n                    \"\\tvoid letter::operator[]()\"\n                    << \"\\n\\ti:               \" << i \n                    << \"\\n\\tnum_of_points(): \" << num_of_points() );\n            return points[i]; \n        }\n\n        const point& operator[] (\n            unsigned short i\n        ) const \n        { \n            DLIB_ASSERT (i < num_of_points(),\n                    \"\\tvoid letter::operator[]()\"\n                    << \"\\n\\ti:               \" << i \n                    << \"\\n\\tnum_of_points(): \" << num_of_points() );\n            return points[i]; \n        }\n    \n        friend void serialize (\n            const letter& item, \n            std::ostream& out \n        );   \n\n        friend void deserialize (\n            letter& item, \n            std::istream& in\n        );   \n\n        void swap (\n            letter& item\n        )\n        {\n            exchange(points, item.points);\n            exchange(w, item.w);\n            exchange(count, item.count);\n        }\n\n    private:\n        // restricted functions\n        letter(letter&);        // copy constructor\n        letter& operator=(letter&);    // assignment operator\n\n        point* points;\n        unsigned short w;\n        unsigned short count;\n    };\n\n    inline void swap (\n        letter& a,\n        letter& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    class font\n    {\n    public:\n        virtual ~font() {}\n\n        virtual bool has_character (\n            unichar ch\n        )const=0;\n        bool has_character(char ch) const    { return this->has_character(zero_extend_cast<unichar>(ch)); }\n        bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast<unichar>(ch)); }\n\n        const letter& operator[] (char ch)   const { return (*this)[zero_extend_cast<unichar>(ch)]; };\n        const letter& operator[] (wchar_t ch)const { return (*this)[zero_extend_cast<unichar>(ch)]; };\n\n        virtual const letter& operator[] (\n            unichar ch\n        )const=0;\n\n        virtual unsigned long height (\n        ) const = 0;\n\n        virtual unsigned long ascender (\n        ) const = 0;\n\n        virtual unsigned long left_overflow (\n        ) const = 0;\n\n        virtual unsigned long right_overflow (\n        ) const = 0;\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, typename traits, typename alloc>\n        void compute_size (\n            const std::basic_string<T,traits,alloc>& str,\n            unsigned long& width,\n            unsigned long& height,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)\n        ) const\n        {\n            typedef std::basic_string<T,traits,alloc> string;\n            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,\n                          \"\\tvoid font::compute_size()\"\n                          << \"\\n\\tlast == string::npos: \" << ((last == string::npos)?\"true\":\"false\") \n                          << \"\\n\\tfirst: \" << (unsigned long)first \n                          << \"\\n\\tlast:  \" << (unsigned long)last \n                          << \"\\n\\tstr.size():  \" << (unsigned long)str.size() );\n\n            unsigned long line_width = 0;\n            unsigned long newlines = 0;\n            width = 0;\n            height = 0;\n\n            if (str.size())\n            {\n                if (last == string::npos)\n                    last = str.size()-1;\n                const font& f = *this;\n\n                for (typename string::size_type i = first; i <= last; ++i)\n                {\n                    // ignore '\\r' characters\n                    if (str[i] == '\\r')\n                        continue;\n\n                    if (str[i] == '\\n')\n                    {\n                        ++newlines;\n                        width = std::max(width,line_width);\n                        line_width = 0;\n                    }\n                    else\n                    {\n                        if (is_combining_char(str[i]) == false)\n                            line_width += f[str[i]].width();\n                    }\n                }\n                width = std::max(width,line_width);\n\n                height = (newlines+1)*f.height();\n                width += f.left_overflow() + f.right_overflow();\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename C, typename T, typename traits, typename alloc, typename pixel_type>\n        void draw_string (\n            const C& c,\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            const pixel_type& color,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos),\n            const rectangle area_ = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                            std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n        ) const\n        {\n            typedef std::basic_string<T,traits,alloc> string;\n            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,\n                          \"\\tvoid font::draw_string()\"\n                          << \"\\n\\tlast == string::npos: \" << ((last == string::npos)?\"true\":\"false\") \n                          << \"\\n\\tfirst: \" << (unsigned long)first \n                          << \"\\n\\tlast:  \" << (unsigned long)last \n                          << \"\\n\\tstr.size():  \" << (unsigned long)str.size() );\n\n            rectangle area = rect.intersect(c).intersect(area_);\n            if (area.is_empty() || str.size() == 0)\n                return;\n\n            if (last == string::npos)\n                last = str.size();\n\n            const font& f = *this;        \n            long y_offset = rect.top() + f.ascender() - 1;\n            long pos = rect.left()+f.left_overflow();\n\n            convert_to_utf32(str.begin() + first, str.begin() + last, [&](unichar ch)\n            {\n                // ignore the '\\r' character\n                if (ch == '\\r')\n                    return;\n\n                // A combining character should be applied to the previous character, and we\n                // therefore make one step back. If a combining comes right after a newline, \n                // then there must be some kind of error in the string, and we don't combine.\n                if (is_combining_char(ch) &&\n                   pos > rect.left() + static_cast<long>(f.left_overflow()))\n                {\n                    pos -= f[ch].width();\n                }\n\n                if (ch == '\\n')\n                {\n                    y_offset += f.height();\n                    pos = rect.left()+f.left_overflow();\n                    return;\n                }\n\n                // only look at letters in the intersection area\n                if (area.bottom() + static_cast<long>(f.height()) < y_offset)\n                {\n                    // the string is now below our rectangle so we are done\n                    return;\n                }\n                else if (area.left() > pos - static_cast<long>(f.left_overflow()) && \n                    pos + static_cast<long>(f[ch].width() + f.right_overflow()) < area.left() )\n                {\n                    pos += f[ch].width();\n                    return;\n                }\n                else if (area.right() + static_cast<long>(f.right_overflow()) < pos)\n                {\n                    // keep looking because there might be a '\\n' in the string that\n                    // will wrap us around and put us back into our rectangle.\n                    return;\n                }\n\n                // at this point in the loop we know that f[str[i]] overlaps \n                // horizontally with the intersection rectangle area.\n\n                const letter& l = f[ch];\n                for (unsigned short i = 0; i < l.num_of_points(); ++i)\n                {\n                    const long x = l[i].x + pos;\n                    const long y = l[i].y + y_offset;\n                    // draw each pixel of the letter if it is inside the intersection\n                    // rectangle\n                    if (area.contains(x,y))\n                    {\n                        assign_pixel(c[y-c.top()][x-c.left()], color);\n                    }\n                }\n\n                pos += l.width();\n            });\n        }\n\n        template <typename C, typename T, typename traits, typename alloc>\n        void draw_string (\n            const C& c,\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str\n        ) const \n        { \n            draw_string(c,rect, str, 0, 0, (std::basic_string<T,traits,alloc>::npos), \n                        rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                  std::numeric_limits<long>::max(), std::numeric_limits<long>::max())); \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, typename traits, typename alloc>\n        const rectangle compute_cursor_rect (\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            unsigned long index,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)\n        ) const\n        {\n            typedef std::basic_string<T,traits,alloc> string;\n            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,\n                          \"\\trectangle font::compute_cursor_rect()\"\n                          << \"\\n\\tlast == string::npos: \" << ((last == string::npos)?\"true\":\"false\") \n                          << \"\\n\\tfirst: \" << (unsigned long)first \n                          << \"\\n\\tlast:  \" << (unsigned long)last \n                          << \"\\n\\tindex:  \" << index\n                          << \"\\n\\tstr.size():  \" << (unsigned long)str.size() );\n\n            const font& f = *this;\n\n            if (last == string::npos)\n                last = str.size()-1;\n\n            long x = f.left_overflow();\n            long y = 0;\n            int count = 0;\n\n            if (str.size() != 0)\n            {\n                for (typename string::size_type i = first; i <= last && i < index; ++i)\n                {\n                    ++count;\n                    if (str[i] == '\\n')\n                    {\n                        x = f.left_overflow();\n                        y += f.height();\n                        count = 0;\n                    }\n                    else if (is_combining_char(str[i]) == false && \n                             str[i] != '\\r')\n                    {\n                        x += f[str[i]].width();\n                    }\n                }\n            }\n\n            x += rect.left();\n            y += rect.top();\n\n            // if the cursor is at the start of a line then back it up one pixel\n            if (count == 0)\n                --x;\n\n            return rectangle(x,y,x,y+f.height()-1);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, typename traits, typename alloc>\n        unsigned long compute_cursor_pos (\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            long x,\n            long y,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)\n        ) const\n        {\n            typedef std::basic_string<T,traits,alloc> string;\n            DLIB_ASSERT ( (last == string::npos) || (first <= last && last < str.size())  ,\n                          \"\\tunsigned long font::compute_cursor_pos()\"\n                          << \"\\n\\tlast == string::npos: \" << ((last == string::npos)?\"true\":\"false\") \n                          << \"\\n\\tfirst: \" << (unsigned long)first \n                          << \"\\n\\tlast:  \" << (unsigned long)last \n                          << \"\\n\\tx:  \" << x \n                          << \"\\n\\ty:  \" << y \n                          << \"\\n\\tstr.size():  \" << (unsigned long)str.size() );\n            const font& f = *this;\n\n\n            if (str.size() == 0)\n                return 0;\n            else if (first >= str.size())\n                return static_cast<unsigned long>(str.size());\n\n            y -= rect.top();\n            x -= rect.left();\n            if (y < 0)\n                y = 0;\n            if (x < 0)\n                x = 0;\n\n            if (last == string::npos)\n                last = str.size()-1;\n\n\n            // first figure out what line we are on\n            typename string::size_type pos = first;\n            long line = 0;\n            while (static_cast<unsigned long>(y) >= f.height())\n            {\n                ++line;\n                y -= f.height();\n            }\n\n            // find the start of the given line\n            for (typename string::size_type i = first; i <= last && line != 0; ++i)\n            {\n                if (str[i] == '\\n')\n                {\n                    --line;\n                    pos = i + 1;\n                }\n            }\n\n\n            // now str[pos] == the first character of the start of the line\n            // that contains the cursor.\n            const typename string::size_type start_of_line = pos;\n\n\n            long cur_x = f.left_overflow();\n            // set the current cursor position to where the mouse clicked\n            while (pos <= last)\n            {\n                if (x <= cur_x || str[pos] == '\\n')\n                    break;\n\n                if (is_combining_char(str[pos]) == false &&\n                    str[pos] != '\\r')\n                {\n                    cur_x += f[str[pos]].width();\n                }\n                ++pos;\n            }\n\n            if (x <= cur_x)\n            {\n                if (pos != start_of_line)\n                {\n                    // we might actually be closer to the previous character \n                    // so check for that and if so then jump us back one.\n                    const long width = f[str[pos-1]].width();\n                    if (x < cur_x - width/2)\n                        --pos;\n                }\n            }\n            return static_cast<unsigned long>(pos);\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const std::shared_ptr<font> get_native_font ();\n\n// ----------------------------------------------------------------------------------------\n\n    class default_font : public font\n    {\n        letter* l;\n\n\n        default_font(\n        );\n        default_font(default_font&);        // copy constructor\n        default_font& operator=(default_font&);    // assignment operator   \n\n\n\n    public:\n        static const std::shared_ptr<font>& get_font (\n        )\n        {        \n            static mutex m;\n            static std::shared_ptr<font> f;\n            auto_mutex M(m);\n            if (f.get() == 0)\n                f.reset(new default_font);\n\n            return f;\n        }\n\n        ~default_font(\n        )\n        {\n            delete [] l;\n        }\n\n        unsigned long height (\n        ) const { return 16; }\n\n        unsigned long ascender (\n        ) const { return 12; }\n\n        unsigned long left_overflow (\n        ) const { return 1; }\n\n        unsigned long right_overflow (\n        ) const { return 2; }\n\n        bool has_character (\n            unichar ch\n        )const\n        {\n            if (ch < 256 && (l[ch].width() != 0 || l[ch].num_of_points() != 0))\n                return true;\n            else\n                return false;\n        }\n\n        const letter& operator[] (\n            unichar ch\n        ) const\n        {\n            if(ch < 256)\n                return l[ch];\n            return l[0]; // just return one of the empty characters in this case \n        }\n    };\n\n\n// ----------------------------------------------------------------------------------------\n\n    class bdf_font : public font\n    {\n    \n    public:\n        bdf_font( long default_char_ = -1 );\n    \n        long read_bdf_file( std::istream& in, unichar max_enc, unichar min_enc = 0 );\n        unsigned long height() const\n        {\n            return fbb.height();\n        }\n        unsigned long ascender() const\n        {\n            return std::max( 0L, 1 - fbb.top() );\n        }\n        unsigned long left_overflow() const\n        {\n            return std::max( 0L, -fbb.left() );\n        }\n        unsigned long right_overflow() const\n        {\n            return right_overflow_;\n        }\n        const letter& operator[] ( unichar uch ) const\n        {\n            if ( !has_character(uch) )\n            {\n                return gl[default_char];\n            }\n            return gl[uch];\n        }\n\n        bool has_character (\n            unichar ch\n        )const\n        {\n            if (ch < gl.size() && (gl[ch].width() != 0 || gl[ch].num_of_points() != 0))\n                return true;\n            else\n                return false;\n        }\n\n        void adjust_metrics();\n    private:\n\n        bool bitmap_to_letter( array2d<char>& bitmap, unichar enc, unsigned long width, int x_offset, int y_offset );\n\n        array<letter> gl;\n        unichar default_char; // if (is_intialized == true), then this MUST be an actual glyph\n        bool is_initialized;\n        rectangle fbb;\n        unsigned long right_overflow_;\n    \n        unsigned global_width;\n        bool has_global_width;\n        long specified_default_char;\n    \n        bdf_font( bdf_font& );      // copy constructor\n        bdf_font& operator=( bdf_font& );  // assignment operator\n    \n    };\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"fonts.cpp\"\n#endif\n\n#endif // DLIB_FONTs_\n\n"
  },
  {
    "path": "dlib/gui_widgets/fonts_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Nils Labugt, Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FONTs_ABSTRACT_\n#ifdef DLIB_FONTs_ABSTRACT_\n\n#include <string>\n#include \"../serialize.h\"\n#include \"../unicode.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class letter \n    {    \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a letter in a font.  It tells you the nominal \n                width of the letter and which pixels form the letter.\n\n            THREAD SAFETY\n                const versions of this object are thread safe but if you are going to\n                be modifying it then you must serialize access to it.\n        !*/\n    public:\n        struct point \n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents one of the pixels of a letter.  \n                    \n                    The origin (i.e. (0,0)) of the coordinate plane is at the left \n                    side of the letter's baseline.  Also note that y is negative when \n                    above the baseline and positive below (it is zero on the baseline \n                    itself).\n\n                    The x value is positive going to the right and negative to the left.\n                    The meaning of a negative x value is that any points with a negative\n                    x value will overlap with the preceding letter.\n            !*/\n\n            point (\n            );\n            /*!\n                ensures\n                    - This constructor does nothing.  The value of x and y \n                      are undefined after its execution.\n            !*/\n\n            point (\n                signed char x_,\n                signed char y_\n            );\n            /*!\n                ensures\n                    - #x == x_\n                    - #y == y_\n            !*/\n\n\n            signed char x;\n            signed char y;\n        };\n\n        // ---------------------------------\n\n        letter (\n        );\n        /*!\n            ensures\n                - #width() == 0 \n                - #num_of_points() == 0 \n        !*/\n\n        letter (\n            unsigned short width_,\n            unsigned short point_count\n        );\n        /*!\n            ensures\n                - #width() == width_\n                - #num_of_points() == point_count\n        !*/\n\n        ~letter(\n        );\n        /*!\n            ensures\n                - any resources used by *this have been freed\n        !*/\n            \n        const unsigned short width (\n        ) const;\n        /*!\n            ensures\n                - returns the width reserved for this letter in pixels.  This is the \n                  number of pixels that are reserved for this letter between adjoining \n                  letters.  It isn't necessarily the width of the actual letter itself.  \n                  (for example, you can make a letter with a width less than how wide it \n                  actually is so that it overlaps with its neighbor letters.)\n        !*/\n\n        const unsigned short num_of_points (\n        ) const;\n        /*!\n            ensures\n                - returns the number of pixels that make up this letter.\n        !*/\n\n        point& operator[] (\n            unsigned short i\n        );\n        /*!\n            requires\n                - i < num_of_points()\n            ensures\n                - returns a non-const reference to the ith point in this letter.\n        !*/\n\n        const point& operator[] (\n            unsigned short i\n        ) const;\n        /*!\n            requires\n                - i < num_of_points()\n            ensures\n                - returns a const reference to the ith point in this letter.\n        !*/\n\n        void swap (\n            letter& item\n        );\n        /*!\n            ensures\n                - swaps *this with item\n        !*/\n    \n        private:\n\n        // restricted functions\n        letter(letter&);        // copy constructor\n        letter& operator=(letter&);    // assignment operator\n    };\n\n    inline void swap (\n        letter& a,\n        letter& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const letter& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support for letter objects\n    !*/\n\n    void deserialize (\n        letter& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support for letter objects\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class font\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines an interface for a font type.  It provides metrics\n                for the font and functions to help you draw strings on a canvas object.\n\n            THREAD SAFETY\n                All the functions in this class are thread safe.\n        !*/\n\n    public:\n\n        virtual bool has_character (\n            unichar ch\n        )const=0;\n        /*!\n            ensures\n                - if (this font has a glyph for the given character) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n        bool has_character(char ch) const    { return this->has_character(zero_extend_cast<unichar>(ch)); }\n        bool has_character(wchar_t ch) const { return this->has_character(zero_extend_cast<unichar>(ch)); }\n        /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */\n\n        virtual const letter& operator[] (\n            unichar ch\n        )const=0;\n        /*!\n            ensures\n                - if (has_character(ch) == true) then\n                    - returns a letter object that tells you how to draw this character.\n                - else\n                    - returns some default glyph for characters that aren't in this font.\n        !*/\n        const letter& operator[] (char ch)    const { return (*this)[zero_extend_cast<unichar>(ch)]; };\n        const letter& operator[] (wchar_t ch) const { return (*this)[zero_extend_cast<unichar>(ch)]; };\n        /* Cast char and wchar_t to unichar correctly when char or wchar_t is a signed type */\n\n        virtual const unsigned long height (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the height in pixels of the tallest letter in the font                \n        !*/\n\n        virtual const unsigned long ascender (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the height() minus the number of pixels below the baseline used\n                  by the letter that hangs the lowest below the baseline.\n        !*/\n\n        virtual const unsigned long left_overflow (\n        ) const = 0;\n        /*! \n            ensures\n                - returns how far outside and to the left of its width a letter\n                  from this font may set pixels.  (i.e. how many extra pixels to its\n                  left may a font use)\n        !*/\n\n        virtual const unsigned long right_overflow (\n        ) const = 0;\n        /*! \n            ensures\n                - returns how far outside and to the right of its width a letter\n                  from this font may set pixels.  (i.e. how many extra pixels to its\n                  right may a font use)\n        !*/\n\n        template <typename T, typename traits, typename alloc>\n        void compute_size (\n            const std::basic_string<T,traits,alloc>& str,\n            unsigned long& width,\n            unsigned long& height,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos\n        ) const;\n        /*!\n            requires\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - first <= last\n                    - last < str.size()\n            ensures\n                - all characters in str with an index < first are ignored by this\n                  function.\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - all characters in str with an index > last are ignored by \n                      this function.\n                - if (str.size() == 0) then\n                    - #width == 0\n                    - #height == 0\n                - else\n                    - #width == sum of the widths of the characters in the widest \n                      line in str + left_overflow() + right_overflow(). \n                    - #height == (count(str.begin(),str.end(),'\\n')+1)*height()\n        !*/\n\n        template <typename C, typename T, typename traits, typename alloc, typename pixel_type>\n        void draw_string (\n            const C& c,\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            const pixel_type& color = rgb_pixel(0,0,0),\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos,\n            const rectangle area = rectangle(-infinity,-infinity,infinity,infinity)\n        ) const;\n        /*!\n            requires\n                - C is a dlib::canvas or an object with a compatible interface.\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - first <= last\n                    - last < str.size()\n            ensures\n                - all characters in str with an index < first are ignored by this\n                  function.\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - all characters in str with an index > last are ignored by \n                      this function.\n                - if (str.size() == 0) then\n                    - does nothing\n                - else\n                    - draws str on the given canvas at the position defined by rect.  \n                      Also uses the given pixel colors for the font color.\n                - If the string is too big to fit in rect then the right and\n                  bottom sides of it will be clipped to make it fit.                  \n                - only the part of the string that is contained inside the area\n                  rectangle will be drawn\n        !*/\n\n        template <typename T, typename traits, typename alloc>\n        const rectangle compute_cursor_rect (\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            unsigned long index,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos\n        ) const;\n        /*!\n            requires\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - first <= last\n                    - last < str.size()\n            ensures\n                - the returned rectangle has a width of 1 and a \n                  height of this->height().\n                - computes the location of the cursor that would sit just before\n                  the character str[index] if str were drawn on the screen by\n                  draw_string(rect,str,...,first,last).  The cursor location is\n                  returned in the form of a rectangle.\n                - if (index < first) then\n                    - the returned cursor will be just before the character str[first].\n                - if (last != std::basic_string<T,traits,alloc>::npos && index > last) then\n                    - the returned cursor will be just after the character str[last]\n                - if (str.size() == 0) then\n                    - the returned cursor will be just at the start of the rectangle where\n                      str would be drawn if it wasn't empty.\n                - if (index > str.size()-1) then\n                    - the returned cursor will be just after the character str[str.size()-1]\n        !*/\n\n        template <typename T, typename traits, typename alloc>\n        const unsigned long compute_cursor_pos (\n            const rectangle& rect,\n            const std::basic_string<T,traits,alloc>& str,\n            long x,\n            long y,\n            typename std::basic_string<T,traits,alloc>::size_type first = 0,\n            typename std::basic_string<T,traits,alloc>::size_type last = std::basic_string<T,traits,alloc>::npos\n        ) const;\n        /*!\n            requires\n                - if (last != std::basic_string<T,traits,alloc>::npos) then\n                    - first <= last\n                    - last < str.size()\n            ensures\n                - returns a number idx that has the following properties:\n                    - if (first < str.size()) then\n                        - first <= idx\n                    - else\n                        - idx == str.size()\n                    - if (last != std::basic_string<T,traits,alloc>::npos) then\n                        - idx <= last + 1\n                    - compute_cursor_rect(rect,str,idx,first,last) == the cursor\n                      position that is closest to the pixel (x,y)\n        !*/\n\n\n    private:\n\n        // restricted functions\n        font(font&);        // copy constructor\n        font& operator=(font&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class default_font : public font\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an implementation of the Helvetica 12 point font.\n\n            THREAD SAFETY\n                It is safe to call get_font() and access the returned font from any \n                thread and no synchronization is needed as long as it is called \n                after the main() function has been entered.\n        !*/\n\n    public:\n        static const shared_ptr_thread_safe<font> get_font(\n        );\n        /*!\n            ensures\n                - returns an instance of this font.\n            throws\n                - std::bad_alloc\n                    This exception is thrown if there is a problem gathering the needed\n                    memory for the font object.\n        !*/\n\n    private:\n\n        // restricted functions\n        default_font();        // normal constructor\n        default_font(default_font&);        // copy constructor\n        default_font& operator=(default_font&);    // assignment operator   \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class bdf_font : public font\n    {\n    \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a font object that is capable of loading of loading BDF (Glyph \n                Bitmap Distribution Format) font files.\n\n            THREAD SAFETY\n                If you only access this object via the functions in the parent class font \n                then this object is thread safe.  But if you need to call any of the\n                functions introduced in this derived class then you need to serialize \n                access to this object while you call these functions.\n        !*/\n\n    public:\n\n        bdf_font( \n            long default_char = -1 \n        );\n        /*!\n            ensures\n                - for all x:\n                    - #has_character(x) == false\n                      (i.e. this font starts out empty.  You have to call read_bdf_file()\n                      to load it with data)\n                - if (default_char == -1) then\n                    - the letter returned by (*this)[ch] for values of\n                      ch where has_character(ch) == false will be the\n                      default glyph defined in the bdf file.\n                - else\n                    - the letter returned by (*this)[ch] for values of\n                      ch where has_character(ch) == false will be the\n                      letter (*this)[default_char].\n        !*/\n    \n        long read_bdf_file( \n            std::istream& in, \n            unichar max_enc, \n            unichar min_enc = 0 \n        );\n        /*!\n            ensures\n                - attempts to read the font data from the given input stream into\n                  *this.  The input stream is expected to contain a valid BDF file.\n                - reads in characters with encodings in the range min_enc to max_enc\n                  into this font.  All characters in the font file outside this range\n                  are ignored.\n                - returns the number of characters loaded into this font from the\n                  given input stream.\n        !*/\n\n        void adjust_metrics();\n        /*!\n            ensures\n                - Computes metrics based on actual glyphs loaded, instead of using \n                  the values in the bdf file header. (May be useful if loading glyphs \n                  from more than one file or a small part of a file.)\n        !*/\n\n    private:\n    \n        bdf_font( bdf_font& );      // copy constructor\n        bdf_font& operator=( bdf_font& );  // assignment operator\n    \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const shared_ptr_thread_safe<font> get_native_font(\n    );\n    /*!\n        requires\n            - DLIB_NO_GUI_SUPPORT is not defined\n        ensures\n            - returns a font object that uses the local font\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FONTs_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/gui_widgets/nativefont.h",
    "content": "// Copyright (C) 2006 Keita Mochizuki \n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IGG_FONT_RENDERER_H_\n#define DLIB_IGG_FONT_RENDERER_H_\n#ifndef DLIB_NO_GUI_SUPPORT\n\n#include \"../platform.h\"\n\n\n#include \"../gui_widgets/fonts.h\"\n#include \"../unicode.h\"\n#include \"../uintn.h\"\n\n#include <map>\n#include <memory>\n\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <locale.h>\n\n#if defined(WIN32)\n#include <windows.h>\n#include <mbstring.h>\n#elif defined(DLIB_POSIX)\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/Xlocale.h>\n#endif\n\nnamespace nativefont\n{\n// ----------------------------------------------------------------------------------------\n\n    namespace font_renderer\n    {\n        typedef dlib::uint8 byte;\n\n\n#ifdef WIN32\n        template <typename T> struct input2native_trait{\n        };\n        template <> struct input2native_trait<char>{\n            typedef char type_t;\n        };\n        template <> struct input2native_trait<wchar_t>{\n            typedef wchar_t type_t;\n        };\n        template <> struct input2native_trait<dlib::unichar>{\n            typedef wchar_t type_t;\n        };\n#endif\n        // T : N : sizeof_source_type\n        template <int N> struct size2inner_trait{\n        };\n        template <> struct size2inner_trait<1>{\n            typedef char type_t;\n        };\n        template <> struct size2inner_trait<2>{\n            typedef dlib::uint16 type_t;\n        };\n        template <> struct size2inner_trait<4>{\n            typedef dlib::unichar type_t;\n        };\n\n\n// ----------------------------------------------------------------------------------------\n\n        template <int N> struct create_helper{ };\n        template <> struct create_helper<1>{\n            typedef char type_t;\n            type_t *istr;\n            int len;\n            create_helper(char *str){\n                len = (int)strlen(str);\n                istr = str;\n            }\n            ~create_helper(){}\n        };\n        template <> struct create_helper<2>{\n            typedef wchar_t type_t;\n            type_t *istr;\n            bool allocated;\n            int len;\n            create_helper(wchar_t *str){\n                allocated = false;\n                len = (int)wcslen(str);\n                istr = str;\n            }\n            create_helper(dlib::unichar *str){\n                allocated = true;\n                len = 0;\n                int unicount = 0;\n                dlib::unichar *p = str;\n                while(*p){\n                    if (*p > 0xffff){\n                        len += 2;\n                    }else{\n                        len++;\n                    }\n                    unicount++;\n                    p++;\n                }\n                istr = new wchar_t[len+1];\n                for (int i = 0, wi = 0; i < unicount; ++i){\n                    dlib::unichar high, low;\n                    if (str[i] > 0xffff){\n                        dlib::unichar_to_surrogate_pair(str[i], high, low);\n                        istr[wi] = (wchar_t)high, istr[wi+1] = (wchar_t)low;\n                        wi += 2;\n                    }else{\n                        istr[wi] = (wchar_t)str[i];\n                        wi += 1;\n                    }\n                }\n                istr[len] = L'\\0';\n            }\n\n            ~create_helper(){\n                if (allocated) delete[] istr;\n            }\n        };\n        template <> struct create_helper<4>{\n            typedef wchar_t type_t;\n            type_t *istr;\n            int len;\n            create_helper(dlib::unichar *str){\n                len = (int)wcslen((wchar_t *)str);\n                istr = (type_t *)str;\n            }\n            ~create_helper(){}\n        };\n\n// ----------------------------------------------------------------------------------------\n\n        class font_renderer{\n        public:\n\n            struct rgb_type{\n                byte r, g, b;\n                rgb_type() : r(0), g(0), b(0){};\n                rgb_type(byte r_, byte g_, byte b_) : r(r_), g(g_), b(b_){};\n            };\n        private:\n\n            byte *image;\n            int width, height;\n            void destroy(){\n                width = height = 0;\n                delete image;\n                image = 0;\n            }\n            struct vals_internal{\n                int width, height;\n#ifdef WIN32\n                COLORREF rgb2RGB(rgb_type &rgb){\n                    return RGB(rgb.r, rgb.g, rgb.b);\n                }\n                HBITMAP hBmp, hBmpOld;\n                HDC hDCBmp;\n                BYTE *pixelint;\n                HFONT hFont, hFontOld;\n                HBRUSH hBrush;\n                int pix_width_prev, pix_height_prev;\n                bool first;\n                int ascender, descender;\n                int height_prev;\n                char attribute_prev;\n\n                template <typename T> void create(T *str, int height_want, bool italic, bool bold, bool fixed, rgb_type &background, rgb_type &foreground){\n                    struct inner{\n                        inline static BOOL GetTextExtentPoint32(HDC hDC, LPCSTR str, int len, LPSIZE lpsize){\n                            return ::GetTextExtentPoint32A(hDC, str, len, lpsize);\n                        }\n                        inline static BOOL GetTextExtentPoint32(HDC hDC, LPCWSTR str, int len, LPSIZE lpsize){\n                            return ::GetTextExtentPoint32W(hDC, str, len, lpsize);\n                        }\n                        inline static BOOL TextOut(HDC hDC, int nxstart, int nystart, LPCSTR str, int cbstr){\n                            return ::TextOutA(hDC, nxstart, nystart, str, cbstr);\n                        }\n                        inline static BOOL TextOut(HDC hDC, int nxstart, int nystart, LPCWSTR str, int cbstr){\n                            return ::TextOutW(hDC, nxstart, nystart, str, cbstr);\n                        }\n                    };\n\n                    create_helper<sizeof(typename input2native_trait<T>::type_t)> ch(str);\n\n                    if (hDCBmp == NULL){\n                        HWND hWnd = GetDesktopWindow();\n                        HDC hDC = GetDC(hWnd);\n                        hDCBmp = CreateCompatibleDC(hDC);\n                        ReleaseDC(hWnd, hDC);\n                    }\n                    SetTextColor(hDCBmp, rgb2RGB(foreground));\n                    SetBkColor(hDCBmp, rgb2RGB(background));\n\n                    char attribute = (italic ? 1 : 0) | (bold ? 2 : 0) | (fixed ? 4 : 0);\n                    if (!hFont || height_prev != height || attribute != attribute_prev){\n                        attribute_prev = attribute;\n                        height_prev = height_want;\n                        if (hFont){\n                            SelectObject(hDCBmp, hFontOld);\n                            DeleteObject(hFont);\n                        }\n                        hFont = CreateFont(height_want, 0, 0, 0, bold ? FW_BOLD : FW_DONTCARE, italic ? TRUE : FALSE, \n                                           FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\n                                           fixed ? (FIXED_PITCH | FF_DONTCARE) : (VARIABLE_PITCH | FF_DONTCARE), NULL);\n                        hFontOld = (HFONT)SelectObject(hDCBmp, hFont);\n                    }\n\n                    {\n                        SIZE sz;\n                        inner::GetTextExtentPoint32(hDCBmp, ch.istr, ch.len, &sz);\n                        width = ((sz.cx + 3) / 4) * 4;\n                        height = sz.cy;\n                    }\n\n                    if (pix_width_prev < width || pix_height_prev < height){\n                        if (hBmp){\n                            SelectObject(hDCBmp, hBmpOld);\n                            DeleteObject(hBmp);\n                        }\n                        pix_width_prev = width * 2;\n                        pix_height_prev = height * 2;\n                        BITMAPINFO bi;\n                        ZeroMemory(&bi, sizeof(bi));\n                        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n                        bi.bmiHeader.biBitCount = 24;\n                        bi.bmiHeader.biPlanes = 1;\n                        bi.bmiHeader.biWidth = pix_width_prev;\n                        bi.bmiHeader.biHeight = -pix_height_prev;\n                        hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void **)&pixelint, NULL, 0);\n                        hBmpOld = (HBITMAP)SelectObject(hDCBmp, hBmp);\n                    }\n\n                    {\n                        HBRUSH hBrush = CreateSolidBrush(rgb2RGB(background));\n                        RECT rc;\n                        rc.left = rc.top = 0;\n                        rc.right = pix_width_prev;\n                        rc.bottom = pix_height_prev;\n                        FillRect(hDCBmp, &rc, hBrush);\n                    }\n\n                    inner::TextOut(hDCBmp, 0, 0, ch.istr, ch.len);\n                    TEXTMETRICW tm;\n                    GetTextMetricsW(hDCBmp,&tm);\n                    ascender = tm.tmAscent;\n                    descender = tm.tmDescent;\n                }\n\n                template <typename T> vals_internal(T *str, int height_want, bool italic = false,\n                    bool bold = false, bool fixed = false, rgb_type background = rgb_type(), rgb_type foreground = rgb_type()){\n                    first = true;\n                    hFont = NULL;\n                    hDCBmp = 0;\n                    hBmpOld = 0;\n                    hBmp = 0;\n                    hDCBmp = 0;\n                    pixelint = 0;\n                    pix_width_prev = pix_height_prev = 0;\n                    height_prev = -1;\n                    attribute_prev = 0;\n                    create(str, height_want, italic, bold, fixed, background, foreground);\n                    first = false;\n                }\n\n                inline int get_ascender(){\n                    return ascender;\n                }\n\n                inline int get_descender(){\n                    return descender;\n                }\n\n                inline void get_pixel(int x, int y, byte &r, byte &g, byte &b){\n                    byte *p = pixelint + (y * pix_width_prev + x) * 3;\n                    r = *(p+2), g = *(p+1), b = *p;\n                }\n\n                void destroy(){\n                    SelectObject(hDCBmp, hBmpOld);\n                    DeleteObject(hBmp);\n                    SelectObject(hDCBmp, hFontOld);\n                    DeleteObject(hFont);\n                    DeleteDC(hDCBmp);\n                    hFont = NULL;\n                    hDCBmp = 0;\n                    hBmpOld = 0;\n                    hBmp = 0;\n                    hDCBmp = 0;\n                    pixelint = 0;\n                }\n                ~vals_internal(){\n                    destroy();\n                }\n#elif defined(DLIB_POSIX)\n                XImage *ximg;\n                Display *d;\n                GC gc;\n                XFontSet fs;\n                Pixmap pix;\n                Colormap cmap;\n                int ascender, descender;\n                int pix_width_prev, pix_height_prev;\n                char fontset_prev[256];\n                unsigned long rgb2color(rgb_type col, Display *d, Colormap &cmap){\n                    XColor xcol;\n                    xcol.red = col.r * 257;\n                    xcol.green = col.g * 257;\n                    xcol.blue = col.b * 257;\n                    XAllocColor(d, cmap, &xcol);\n                    return xcol.pixel;\n                }\n                template <typename T> void create(T *str, int height_want, bool italic, bool bold, bool fixed, rgb_type background, rgb_type foreground){\n                    struct inner{\n                        inline static int XTextExtents (XFontSet fs, char *str, int len, XRectangle *ink, XRectangle *logical){\n                            return XmbTextExtents(fs, str, len, ink, logical);\n                        }\n                        inline static int XTextExtents (XFontSet fs, wchar_t *str, int len, XRectangle *ink, XRectangle *logical){\n                            return XwcTextExtents(fs, str, len, ink, logical);\n                        }\n                        inline static void XDrawString(Display *d, Window w, XFontSet fs, GC gc, int x, int y, char *str, int num_bytes){\n                            XmbDrawString(d, w, fs, gc, x, y, str, num_bytes);\n                        }\n                        inline static void XDrawString(Display *d, Window w, XFontSet fs, GC gc, int x, int y, wchar_t *str, int num_bytes){\n                            XwcDrawString(d, w, fs, gc, x, y, str, num_bytes);\n                        }\n                    };\n                    create_helper<sizeof(T)> ch((typename size2inner_trait<sizeof(T)>::type_t *)str);\n                    setlocale(LC_CTYPE, \"\");\n                    if (d == NULL){\n                        d = XOpenDisplay(NULL);\n                        if (d == 0)\n                        {\n                            d = XOpenDisplay(\":0.0\");\n                            if (d == 0)\n                            {\n                                throw dlib::gui_error(\"Unable to connect to the X display.\");\n                            }\n                        }\n\n                        cmap = DefaultColormap(d, DefaultScreen(d));\n                    }\n                    char fontset[256] = {0};\n                    {\n                        int offset = snprintf(fontset, sizeof(fontset), \"-*-*-%s-%c-normal--%d-*-*-*-%c\",\n                                              bold ? \"bold\" : \"medium\", italic ? 'i' : 'r', height_want, fixed ? 'c' : 'p');\n                        if (fixed){\n                            snprintf(&fontset[offset], sizeof(fontset) - offset, \",-*-*-%s-%c-normal--%d-*-*-*-m\",\n                                     bold ? \"bold\" : \"medium\", italic ? 'i' : 'r', height_want);\n                        }\n                    }\n                    bool equal_font;\n                    if (strcmp(fontset, fontset_prev) == 0){\n                        equal_font = true;\n                    }else{\n                        equal_font = false;\n                        strcpy(fontset_prev, fontset);\n                    }\n\n                    char **mlist;\n                    int mcount;\n                    char *def_str;\n                    if (!equal_font){\n                        if (fs){\n                            XFreeFontSet(d, fs);\n                        }\n                        fs = XCreateFontSet(d, fontset, &mlist, &mcount, &def_str);\n                        if (fs == NULL)\n                           throw dlib::gui_error(\"gui_error: XCreateFontSet() failure\");\n\n                        XFontSetExtents *extent;\n                        extent = XExtentsOfFontSet(fs);\n                        ascender = -extent->max_logical_extent.y;\n                        descender = extent->max_logical_extent.height - ascender;\n                        XFreeStringList(mlist);\n                    }\n                    XRectangle ink, logical;\n                    inner::XTextExtents (fs, ch.istr, ch.len, &ink, &logical);\n                    width = logical.width;\n                    height = height_want;\n\n                    if (pix == None || pix_width_prev < width || pix_height_prev < height){\n                        if (pix != None){\n                            XFreeGC(d, gc);\n                            XFreePixmap(d, pix);\n                        }\n                        pix_width_prev = width * 2;\n                        pix_height_prev = height * 2;\n                        pix = XCreatePixmap(d, DefaultRootWindow(d), pix_width_prev, pix_height_prev, XDefaultDepth(d, DefaultScreen(d)));\n                        gc = XCreateGC(d, pix, 0, NULL);\n                    }\n\n                    unsigned long backcolor = rgb2color(background, d, cmap);\n                    XSetForeground(d, gc, backcolor);\n                    XSetBackground(d, gc, backcolor);\n                    XFillRectangle(d, pix, gc, 0, 0, width, height);\n                    XSetForeground(d, gc, rgb2color(foreground, d, cmap));\n                    inner::XDrawString(d, pix, fs, gc, 0, ascender, ch.istr, ch.len);\n\n                    if (ximg) XDestroyImage(ximg);\n                    ximg = XGetImage(d, pix, 0, 0, width, height, AllPlanes, ZPixmap );\n                }\n\n                template <typename T> vals_internal(T *str, int height_want, bool italic = false,\n                    bool bold = false, bool fixed = false, rgb_type background = rgb_type(), rgb_type foreground = rgb_type()){\n                    fontset_prev[0] = '\\0';\n                    ximg = NULL;\n                    d = NULL;\n                    pix = None;\n                    fs = NULL;\n                    ascender = descender = -1;\n                    pix_width_prev = pix_height_prev = -1;\n                    create(str, height_want, italic, bold, fixed, background, foreground);\n                }\n\n                inline int get_ascender(){\n                    return ascender;\n                }\n\n                inline int get_descender(){\n                    return descender;\n                }\n\n                std::map<unsigned long,rgb_type> col2rgb;\n                rgb_type color2rgb(unsigned long color, Display *d, Colormap &cmap){\n                    if (col2rgb.count(color)){\n                        return col2rgb[color];\n                    }else{\n                        XColor xcol;\n                        xcol.pixel = color;\n                        XQueryColor(d, cmap, &xcol);\n                        rgb_type rgb_((byte)(xcol.red/257), (byte)(xcol.green/257), (byte)(xcol.blue/257));\n                        col2rgb[color] = rgb_;\n                        return rgb_;\n                    }\n                }\n                inline void get_pixel(int x, int y, byte &r, byte &g, byte &b){\n                    rgb_type c = color2rgb(XGetPixel(ximg,x,y), d, cmap);\n                    r = c.r, g = c.g, b = c.b;\n                }\n\n                ~vals_internal(){\n                    XDestroyImage(ximg);\n\n                    XFreeGC(d, gc);\n                    XFreeFontSet(d, fs);\n                    XFreePixmap(d, pix);\n                    XCloseDisplay(d);\n                }\n#endif\n            };\n\n            struct image_size_setter{\n                void operator()(int&, int&){\n                }\n            };\n\n            int ascender, descender;\n            vals_internal *vi;\n        public:\n            font_renderer() : image(0), width(0), height(0){\n                ascender = descender = 0;\n                vi = NULL;\n            }\n\n            template<typename T> font_renderer(T *str, int height_want, bool italic = false, bool bold = false, bool fixed = false,         rgb_type background = rgb_type(0,0,0), rgb_type foreground = rgb_type(255,255,255)){\n                render(str, height_want, italic, bold, fixed, background, foreground);\n            }\n\n            template<typename T> void render(T *str, int height_want,\n                                             bool italic = false, bool bold = false, bool fixed = false,\n                                             rgb_type background = rgb_type(0,0,0), rgb_type foreground = rgb_type(255,255,255)){\n                if (vi == NULL){\n                    vi = new vals_internal(str, height_want, italic, bold, fixed, background, foreground);\n                }else{\n                    vi->create(str, height_want, italic, bold, fixed, background, foreground);\n                }\n                width = vi->width, height = vi->height;\n                image = new byte[width * height * 3];\n                ascender = vi->get_ascender();\n                descender = vi->get_descender();\n\n                int h = height, w = width;\n                for (int j = 0, i3 = 0; j < h; ++j){\n                    for (int i = 0; i < w; ++i, i3 += 3){\n                        vi->get_pixel(i, j, image[i3], image[i3+1], image[i3+2]);\n                    }\n                }\n            }\n\n            ~font_renderer(){\n                if (vi) delete vi;\n                destroy();\n            }\n            int get_width(){\n                return width;\n            }\n            int get_height(){\n                return height;\n            }\n            inline int get_ascender(){\n                return ascender;\n            }\n            inline int get_descender(){\n                return descender;\n            }\n\n            const byte *get_image(){\n                return image;\n            }\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class native_font : public dlib::font \n    {\n        unsigned long ascender_;\n        native_font(){\n            setlocale(LC_CTYPE, \"\");\n            ascender_ = 0;\n            get_letter((int)('x'));\n        }\n        typedef std::map<int,dlib::letter *> letters_map_type;\n        letters_map_type letters;\n        font_renderer::font_renderer fl;\n    public:\n\n        virtual ~native_font() \n        {\n            // delete all the letter objects we have in our letters map\n            letters_map_type::iterator i;\n            for (i = letters.begin(); i != letters.end(); ++i)\n            {\n                delete i->second;\n            }\n        }\n\n        virtual bool has_character (\n            dlib::unichar ch\n        )const{\n            return (*this)[ch].width() > 0;\n        }\n\n        static const std::shared_ptr<font>& get_font (\n        )\n        {\n            static std::shared_ptr<font> f(new native_font);\n            return f;\n        }\n\n        virtual const dlib::letter& operator[] (dlib::unichar ch) const{\n            return (const_cast<native_font *>(this))->get_letter(ch);\n        }\n\n        dlib::letter& get_letter (\n            dlib::unichar ch\n        ){\n            if (letters.count(ch)){\n                dlib::letter *l = letters.find(ch)->second;\n                return *l;\n            }\n\n            dlib::unichar c[2];\n            c[0] = ch;\n            c[1] = 0;\n\n            fl.render(c, height(),false,false,true);\n            if (ascender_ == 0){\n                ascender_ = fl.get_ascender();\n            }\n            std::vector<dlib::letter::point> v;\n            const font_renderer::byte *bp = fl.get_image();\n            for (int j = 0; j < fl.get_height(); ++j){\n                for (int i = 0; i < fl.get_width(); ++i, bp += 3){\n                    if (*bp){\n                        v.push_back(dlib::letter::point(i,j-ascender()+1));\n                    }\n                }\n            }\n            dlib::letter *l = new dlib::letter(fl.get_width(), (unsigned long)v.size());\n\n            letters.insert(std::make_pair(ch,l));\n            for (int i = 0; i < (int)v.size(); ++i){\n                (*l)[i] = v.at(i);\n            }\n            return *l;\n        }\n\n        virtual unsigned long height (\n        ) const { return 12; }\n\n        virtual unsigned long ascender (\n        ) const { return ascender_; }\n\n        virtual unsigned long left_overflow (\n        ) const { return 1; }\n\n        virtual unsigned long right_overflow (\n        ) const { return 2; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_NO_GUI_SUPPORT\n#endif // DLIB_IGG_FONT_RENDERER_H_\n\n"
  },
  {
    "path": "dlib/gui_widgets/style.cpp",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WIDGETs_STYLE_CPP_\n#define DLIB_WIDGETs_STYLE_CPP_\n\n#include \"style.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // button style stuff \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void button_style_default::draw_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& mfont,\n        const long ,\n        const long ,\n        const ustring& name,\n        const bool is_depressed\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        fill_rect(c,rect,rgb_pixel(212,208,200));\n\n        unsigned char red, green, blue;\n        if (enabled)\n        {\n            red = 0;\n            green = 0;\n            blue = 0;\n        }\n        else\n        {\n            red = 128;\n            green = 128;\n            blue = 128;\n        }\n\n        // compute the name length if it hasn't already been computed\n        if (name_width == 0)\n        {\n            unsigned long height;\n            mfont.compute_size(name,name_width,height);\n        }\n\n        // figure out where the name string should appear\n        rectangle name_rect;\n        const unsigned long width = name_width;\n        const unsigned long height = mfont.height();\n        name_rect.set_left((rect.right() + rect.left() - width)/2);\n        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);\n        name_rect.set_right(name_rect.left()+width-1);\n        name_rect.set_bottom(name_rect.top()+height);\n\n\n        if (is_depressed)\n        {\n            name_rect.set_left(name_rect.left()+1);\n            name_rect.set_right(name_rect.right()+1);\n            name_rect.set_top(name_rect.top()+1);\n            name_rect.set_bottom(name_rect.bottom()+1);\n\n            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));\n\n            draw_button_down(c,rect); \n        }\n        else\n        {\n            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));\n\n            // now draw the edge of the button\n            draw_button_up(c,rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle button_style_default::\n    get_min_size (\n        const ustring& name,\n        const font& mfont \n    ) const \n    {\n\n        unsigned long width; \n        unsigned long height;\n        mfont.compute_size(name,width,height);\n        name_width = width;\n\n        return rectangle(width+2*padding, height+2*padding);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void button_style_toolbar1::draw_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& mfont,\n        const long lastx,\n        const long lasty,\n        const ustring& name,\n        const bool is_depressed\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        const long radius = 4;\n\n        unsigned char red, green, blue;\n        if (enabled)\n        {\n            red = 0;\n            green = 0;\n            blue = 0;\n\n            long d = 0;\n            if (rect.contains(lastx,lasty))\n                d = -70; \n\n            if (is_depressed)\n                d = 20;\n\n            if (d != 0)\n            {\n                rectangle temp(rect);\n                temp.left()--; temp.top()--; temp.right()++; temp.bottom()++;\n                draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,120)); \n                temp.left()--; temp.top()--; temp.right()++; temp.bottom()++;\n                draw_rounded_rectangle(c, temp, radius, rgb_alpha_pixel(255,255,0,40)); \n            }\n\n            fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(255, 255, 255,120-d), \n                                  rgb_alpha_pixel(255, 255, 255,0));\n            draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(30,30,30,200));\n        }\n        else\n        {\n            red = 128;\n            green = 128;\n            blue = 128;\n            draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(red,green,blue,210));\n        }\n\n\n        // compute the name length if it hasn't already been computed\n        if (name_width == 0)\n        {\n            unsigned long height;\n            mfont.compute_size(name,name_width,height);\n        }\n\n        // figure out where the name string should appear\n        rectangle name_rect;\n        const unsigned long width = name_width;\n        const unsigned long height = mfont.height();\n        name_rect.set_left((rect.right() + rect.left() - width)/2);\n        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);\n        name_rect.set_right(name_rect.left()+width-1);\n        name_rect.set_bottom(name_rect.top()+height);\n\n\n        if (is_depressed)\n        {\n            name_rect.set_left(name_rect.left()+1);\n            name_rect.set_right(name_rect.right()+1);\n            name_rect.set_top(name_rect.top()+1);\n            name_rect.set_bottom(name_rect.bottom()+1);\n\n            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));\n\n        }\n        else\n        {\n            mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle button_style_toolbar1::\n    get_min_size (\n        const ustring& name,\n        const font& mfont \n    ) const \n    {\n\n        unsigned long width; \n        unsigned long height;\n        mfont.compute_size(name,width,height);\n        name_width = width;\n\n        return rectangle(width+2*padding, height+2*padding);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void button_style_toolbar_icon1::draw_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& ,\n        const long lastx,\n        const long lasty,\n        const ustring& ,\n        const bool is_depressed\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        const long radius = padding;\n\n        if (enabled)\n        {\n            if (rect.contains(lastx,lasty))\n            {\n                if (is_depressed)\n                {\n                    fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(100,100,200,150), \n                                                        rgb_alpha_pixel(50,50,100,100));\n                    draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200));\n                }\n                else\n                {\n                    fill_gradient_rounded(c,rect,radius,rgb_alpha_pixel(150,150,250,130), \n                                                        rgb_alpha_pixel(100,100,150,90));\n                    draw_rounded_rectangle(c,rect,radius, rgb_alpha_pixel(150,150,30,200));\n                }\n            }\n\n            if (is_depressed)\n            {\n                rectangle img_rect(translate_rect(centered_rect(rect,img_mouseover.nc(),img_mouseover.nr()),1,1));\n                point p(img_rect.left(),img_rect.top());\n                draw_image(c,p,img_mouseover);\n            }\n            else\n            {\n                rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr()));\n                point p(img_rect.left(),img_rect.top());\n                if (rect.contains(lastx,lasty))\n                    draw_image(c,p,img_mouseover);\n                else\n                    draw_image(c,p,img_normal);\n            }\n\n        }\n        else\n        {\n            rectangle img_rect(centered_rect(rect,img_normal.nc(),img_normal.nr()));\n            point p(img_rect.left(),img_rect.top());\n            draw_image(c,p,img_disabled);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle button_style_toolbar_icon1::\n    get_min_size (\n        const ustring& ,\n        const font&  \n    ) const \n    {\n        return rectangle(img_normal.nc()+2*padding, img_normal.nr()+2*padding);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void button_style_arrow::\n    draw_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& ,\n        const long ,\n        const long ,\n        const ustring& ,\n        const bool is_depressed\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        fill_rect(c,rect,rgb_pixel(212,208,200));\n\n        const long height = rect.height();\n        const long width = rect.width();\n\n        const long smallest = (width < height) ? width : height; \n\n        const long rows = (smallest+3)/4;\n        const long start = rows + rows/2-1;\n        long dep;\n\n        long tip_x = 0;\n        long tip_y = 0;\n        long wy = 0;\n        long hy = 0;\n        long wx = 0; \n        long hx = 0;\n\n        if (is_depressed)\n        {\n            dep = 0;\n\n            // draw the button's border\n            draw_button_down(c,rect); \n        }\n        else\n        {\n            dep = -1;\n\n            // draw the button's border\n            draw_button_up(c,rect);\n        }\n\n\n        switch (dir)\n        {\n            case UP:\n                tip_x = width/2 + rect.left() + dep;\n                tip_y = (height - start)/2 + rect.top() + dep + 1;\n                wy = 0;\n                hy = 1;\n                wx = 1;\n                hx = 0;\n                break;\n\n            case DOWN:\n                tip_x = width/2 + rect.left() + dep;\n                tip_y = rect.bottom() - (height - start)/2 + dep;\n                wy = 0;\n                hy = -1;\n                wx = 1;\n                hx = 0;\n                break;\n\n            case LEFT:\n                tip_x = rect.left() + (width - start)/2 + dep + 1;\n                tip_y = height/2 + rect.top() + dep;\n                wy = 1;\n                hy = 0;\n                wx = 0;\n                hx = 1;\n                break;\n\n            case RIGHT:\n                tip_x = rect.right() - (width - start)/2 + dep;\n                tip_y = height/2 + rect.top() + dep;\n                wy = 1;\n                hy = 0;\n                wx = 0;\n                hx = -1;\n                break;\n        }\n\n\n        rgb_pixel color;\n        if (enabled)\n        {\n            color.red = 0;\n            color.green = 0;\n            color.blue = 0;\n        }\n        else\n        {\n            color.red = 128;\n            color.green = 128;\n            color.blue = 128;\n        }\n\n\n\n        for (long i = 0; i < rows; ++i)\n        {\n            draw_line(c,point(tip_x + wx*i + hx*i, tip_y + wy*i + hy*i), \n                      point(tip_x + wx*i*-1 + hx*i, tip_y + wy*i*-1 + hy*i), \n                      color);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // toggle button style stuff \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button_style_default::draw_toggle_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& mfont,\n        const long ,\n        const long ,\n        const ustring& name,\n        const bool is_depressed,\n        const bool is_checked\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        fill_rect(c,rect,rgb_pixel(212,208,200));\n\n        unsigned char red, green, blue;\n        if (enabled)\n        {\n            red = 0;\n            green = 0;\n            blue = 0;\n        }\n        else\n        {\n            red = 128;\n            green = 128;\n            blue = 128;\n        }\n\n        // compute the name length if it hasn't already been computed\n        if (name_width == 0)\n        {\n            unsigned long height;\n            mfont.compute_size(name,name_width,height);\n        }\n\n        // figure out where the name string should appear\n        rectangle name_rect;\n        const unsigned long width = name_width;\n        const unsigned long height = mfont.height();\n        name_rect.set_left((rect.right() + rect.left() - width)/2);\n        name_rect.set_top((rect.bottom() + rect.top() - height)/2 + 1);\n        name_rect.set_right(name_rect.left()+width-1);\n        name_rect.set_bottom(name_rect.top()+height);\n\n        long d = 0;\n        if (is_checked)\n            d = 1;\n\n        if (is_depressed)\n            d = 2;\n\n        name_rect.set_left(name_rect.left()+d);\n        name_rect.set_right(name_rect.right()+d);\n        name_rect.set_top(name_rect.top()+d);\n        name_rect.set_bottom(name_rect.bottom()+d);\n\n        mfont.draw_string(c,name_rect,name,rgb_pixel(red,green,blue));\n\n        // now draw the edge of the button\n        if (is_checked || is_depressed)\n            draw_button_down(c,rect);\n        else\n            draw_button_up(c,rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle toggle_button_style_default::\n    get_min_size (\n        const ustring& name,\n        const font& mfont \n    ) const \n    {\n\n        unsigned long width; \n        unsigned long height;\n        mfont.compute_size(name,width,height);\n        name_width = width;\n\n        return rectangle(width+2*padding, height+2*padding);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button_style_check_box::draw_toggle_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& mfont,\n        const long ,\n        const long ,\n        const ustring& name,\n        const bool is_depressed,\n        const bool is_checked\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n\n        rgb_pixel color;\n        if (enabled)\n        {\n            color.red = 0;\n            color.green = 0;\n            color.blue = 0;\n        }\n        else\n        {\n            color.red = 128;\n            color.green = 128;\n            color.blue = 128;\n        }\n\n\n        // figure out where the name string should appear\n        rectangle name_rect, box_rect;\n        unsigned long padding = 0;\n        if (mfont.height() < 13)\n            padding = (rect.height() - mfont.height())/2;\n\n        name_rect = rect;\n        name_rect.set_left(rect.left() + 17-1);\n        name_rect.set_top(rect.top() + padding);\n        name_rect.set_bottom(rect.bottom() - padding);\n            \n        box_rect = rect;\n        box_rect.set_right(rect.left() + 12);\n        box_rect.set_bottom(rect.top() + 12);\n\n        mfont.draw_string(c,name_rect,name,color);\n\n        if (enabled && is_depressed == false)\n            fill_rect(c, box_rect,rgb_pixel(255,255,255));\n        else\n            fill_rect(c, box_rect,rgb_pixel(212,208,200));\n\n        draw_sunken_rectangle(c, box_rect);\n\n\n        if (is_checked)\n        {\n            const long x = box_rect.left();\n            const long y = box_rect.top();\n            draw_line(c,point(3+x,5+y),point(6+x,8+y),color);\n            draw_line(c,point(3+x,6+y),point(5+x,8+y),color);\n            draw_line(c,point(3+x,7+y),point(5+x,9+y),color);\n            draw_line(c,point(6+x,6+y),point(9+x,3+y),color);\n            draw_line(c,point(6+x,7+y),point(9+x,4+y),color);\n            draw_line(c,point(6+x,8+y),point(9+x,5+y),color);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle toggle_button_style_check_box::\n    get_min_size (\n        const ustring& name,\n        const font& mfont \n    ) const \n    {\n        unsigned long width;\n        unsigned long height;\n        mfont.compute_size(name,width,height);\n\n        if (height < 13)\n            height = 13;\n\n        return rectangle(width + 17 -1, height -1);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button_style_radio_button::draw_toggle_button (\n        const canvas& c,\n        const rectangle& rect,\n        const bool enabled,\n        const font& mfont,\n        const long ,\n        const long ,\n        const ustring& name,\n        const bool is_depressed,\n        const bool is_checked\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n        \n\n        rgb_pixel color;\n\n        // figure out where the name string should appear\n        rectangle name_rect, box_rect;\n        unsigned long padding = 0;\n        if (mfont.height() < 13)\n            padding = (rect.height() - mfont.height())/2;\n\n        name_rect = rect;\n        name_rect.set_left(rect.left() + 17-1);\n        name_rect.set_top(rect.top() + padding);\n        name_rect.set_bottom(rect.bottom() - padding);\n            \n        box_rect = rect;\n        box_rect.set_right(rect.left() + 12);\n        box_rect.set_bottom(rect.top() + 12);\n\n        \n        const long x = box_rect.left();\n        const long y = box_rect.top();\n\n        if (enabled && is_depressed == false)\n            draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(255,255,255));\n        else\n            draw_solid_circle(c,point(rect.left()+5,rect.top()+5),4.5,rgb_pixel(212,208,200));\n\n\n        color = rgb_pixel(128,128,128);\n        draw_line(c,point(0+x,4+y),point(0+x,7+y),color);\n        draw_line(c,point(1+x,2+y),point(1+x,9+y),color);\n        draw_line(c,point(2+x,1+y),point(9+x,1+y),color);\n        draw_line(c,point(4+x,0+y),point(7+x,0+y),color);\n\n        color = rgb_pixel(255,255,255);\n        draw_line(c,point(4+x,11+y),point(7+x,11+y),color);\n        draw_line(c,point(2+x,10+y),point(9+x,10+y),color);\n        draw_line(c,point(10+x,2+y),point(10+x,9+y),color);\n        draw_line(c,point(11+x,4+y),point(11+x,7+y),color);\n\n        color = rgb_pixel(64,64,64);\n        draw_line(c,point(1+x,4+y),point(1+x,7+y),color);\n        draw_line(c,point(4+x,1+y),point(7+x,1+y),color);\n        draw_pixel(c,point(2+x,3+y),color);\n        draw_pixel(c,point(3+x,2+y),color);\n        draw_pixel(c,point(2+x,2+y),color);\n        draw_pixel(c,point(2+x,8+y),color);\n        draw_pixel(c,point(8+x,2+y),color);\n        draw_pixel(c,point(9+x,2+y),color);\n\n        color = rgb_pixel(212,208,200);\n        draw_line(c,point(4+x,10+y),point(7+x,10+y),color);\n        draw_line(c,point(10+x,4+y),point(10+x,7+y),color);\n        draw_pixel(c,point(3+x,9+y),color);\n        draw_pixel(c,point(9+x,3+y),color);\n\n        if (enabled)\n        {\n            color.red = 0;\n            color.green = 0;\n            color.blue = 0;\n        }\n        else\n        {\n            color.red = 128;\n            color.green = 128;\n            color.blue = 128;\n        }\n\n        mfont.draw_string(c,name_rect,name,color);\n\n        if (is_checked)\n        {\n            draw_line(c,point(5+x,4+y),point(6+x,4+y),color);\n            draw_line(c,point(4+x,5+y),point(7+x,5+y),color);\n            draw_line(c,point(4+x,6+y),point(7+x,6+y),color);\n            draw_line(c,point(5+x,7+y),point(6+x,7+y),color);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle toggle_button_style_radio_button::\n    get_min_size (\n        const ustring& name,\n        const font& mfont \n    ) const \n    {\n        unsigned long width;\n        unsigned long height;\n        mfont.compute_size(name,width,height);\n\n        if (height < 13)\n            height = 13;\n\n        return rectangle(width + 17 -1, height -1);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scroll bar style stuff \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    long scroll_bar_style_default::\n    get_slider_length (\n        long total_length,\n        long max_pos\n    ) const\n    {\n        // if the length is too small then we have to smash up the arrow buttons\n        // and hide the slider.\n        if (total_length <= get_width()*2)\n        {\n            return 0;\n        }\n        else\n        {\n            double range = total_length - get_button_length(total_length, max_pos)*2;\n\n            double scale_factor = 30.0/(max_pos + 30.0);\n\n            if (scale_factor < 0.1)\n                scale_factor = 0.1;\n\n\n            double fraction = range/(max_pos + range)*scale_factor;\n            double result = fraction * range;\n            long res = static_cast<long>(result);\n            if (res < 8)\n                res = 8;\n            return res;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long scroll_bar_style_default::\n    get_button_length (\n        long total_length,\n        long \n    ) const\n    {\n        // if the length is too small then we have to smash up the arrow buttons\n        // and hide the slider.\n        if (total_length <= get_width()*2)\n        {\n            return total_length/2;\n        }\n        else\n        {\n            return get_width();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar_style_default::\n    draw_scroll_bar_background (\n        const canvas& c,\n        const rectangle& rect,\n        const bool ,\n        const long ,\n        const long ,\n        const bool is_depressed\n    ) const\n    {\n        if (is_depressed)\n            draw_checkered(c, rect,rgb_pixel(0,0,0),rgb_pixel(43,47,55));\n        else\n            draw_checkered(c, rect,rgb_pixel(255,255,255),rgb_pixel(212,208,200));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void scroll_bar_style_default::\n    draw_scroll_bar_slider (\n        const canvas& c,\n        const rectangle& rect,\n        const bool ,\n        const long ,\n        const long ,\n        const bool \n    ) const\n    {\n        fill_rect(c, rect, rgb_pixel(212,208,200));\n        draw_button_up(c, rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_field styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    unsigned long text_field_style_default::\n    get_padding (\n        const font& mfont \n    ) const  \n    { \n        return mfont.height()-mfont.ascender();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field_style_default::\n    draw_text_field (\n        const canvas& c,\n        const rectangle& rect,\n        const rectangle& text_rect,\n        const bool enabled,\n        const font& mfont,\n        const ustring& text,\n        const unsigned long cursor_x,\n        const unsigned long text_pos,\n        const rgb_pixel& text_color,\n        const rgb_pixel& bg_color,\n        const bool has_focus,\n        const bool cursor_visible,\n        const long highlight_start,\n        const long highlight_end\n    ) const \n    {\n        rectangle area = rect.intersect(c);\n\n        if (enabled)\n        {\n            // first fill our area with the bg_color\n            fill_rect(c, area,bg_color);\n        }\n        else\n        {\n            // first fill our area with gray \n            fill_rect(c, area,rgb_pixel(212,208,200));\n        }\n\n\n        if (enabled)\n            mfont.draw_string(c,text_rect,text,text_color,text_pos);\n        else\n            mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128),text_pos);\n\n        // now draw the edge of the text_field\n        draw_sunken_rectangle(c, rect);\n\n        if (highlight_start <= highlight_end && enabled)\n        {\n            rectangle highlight_rect = text_rect;\n            unsigned long left_pad = 0, right_pad = mfont.left_overflow();\n\n            long i;\n            for (i = text_pos; i <= highlight_end; ++i)\n            {\n                if (i == highlight_start)\n                    left_pad = right_pad;\n\n                right_pad += mfont[text[i]].width();\n            }\n\n            highlight_rect.set_left(text_rect.left()+left_pad);\n            highlight_rect.set_right(text_rect.left()+right_pad);\n\n            // highlight the highlight_rect area\n            highlight_rect = highlight_rect.intersect(c);\n            for (long row = highlight_rect.top(); row <= highlight_rect.bottom(); ++row)\n            {\n                for (long col = highlight_rect.left(); col <= highlight_rect.right(); ++col)\n                {\n                    canvas::pixel& pixel = c[row-c.top()][col-c.left()];\n                    if (pixel.red == 255 && pixel.green == 255 && pixel.blue == 255)\n                    {\n                        // this is a background (and white) pixel so set it to a dark \n                        // blueish color.\n                        pixel.red = 10;\n                        pixel.green = 36;\n                        pixel.blue = 106;\n                    }\n                    else\n                    {\n                        // this should be a pixel that is part of a letter so set it to white\n                        pixel.red = 255;\n                        pixel.green = 255;\n                        pixel.blue = 255;\n                    }\n                }\n            }\n        }\n\n        // now draw the cursor if we need to\n        if (cursor_visible && has_focus && enabled)\n        {\n            const unsigned long top = rect.top()+3;\n            const unsigned long bottom = rect.bottom()-3;\n            draw_line(c, point(rect.left()+cursor_x,top),point(rect.left()+cursor_x,bottom));\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_box styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void text_box_style_default::\n    draw_text_box (\n        const canvas& c,\n        const rectangle& display_rect,\n        const rectangle& text_rect,\n        const bool enabled,\n        const font& mfont,\n        const ustring& text,\n        const rectangle& cursor_rect,\n        const rgb_pixel& text_color,\n        const rgb_pixel& bg_color,\n        const bool has_focus,\n        const bool cursor_visible,\n        const long highlight_start,\n        const long highlight_end\n    ) const \n    {\n        rectangle area = display_rect.intersect(c);\n\n        if (enabled)\n        {\n            // first fill our area with the bg_color\n            fill_rect(c, area,bg_color);\n        }\n        else\n        {\n            // first fill our area with gray \n            fill_rect(c, area,rgb_pixel(212,208,200));\n        }\n\n\n        if (enabled)\n            mfont.draw_string(c,text_rect,text,text_color, 0, ustring::npos, area);\n        else\n            mfont.draw_string(c,text_rect,text,rgb_pixel(128,128,128), 0, ustring::npos, area);\n\n\n        // now draw the highlight if there is any\n        if (highlight_start <= highlight_end && enabled)\n        {\n            const rectangle first_pos = mfont.compute_cursor_rect(text_rect, text, highlight_start);\n            const rectangle last_pos = mfont.compute_cursor_rect(text_rect, text, highlight_end+1);\n\n            const rgb_alpha_pixel color(10, 30, 106, 90);\n\n            // if the highlighted text is all on one line\n            if (first_pos.top() == last_pos.top())\n            {\n                fill_rect(c, (first_pos + last_pos).intersect(display_rect), color);\n            }\n            else\n            {\n                const rectangle min_boundary(display_rect.left()+4, display_rect.top()+4,\n                                             display_rect.right()-4, display_rect.bottom()-4);\n                const rectangle boundary( display_rect.intersect(text_rect) + min_boundary);\n\n                rectangle first_row, last_row, middle_rows;\n                first_row += first_pos;\n                first_row += point(boundary.right(), first_pos.top());\n                last_row += last_pos;\n                last_row += point(boundary.left(), last_pos.bottom());\n\n                middle_rows.left() = boundary.left();\n                middle_rows.right() = boundary.right();\n                middle_rows.top() = first_row.bottom()+1;\n                middle_rows.bottom() = last_row.top()-1;\n\n                fill_rect(c, first_row.intersect(display_rect), color);\n                fill_rect(c, middle_rows, color);\n                fill_rect(c, last_row.intersect(display_rect), color);\n            }\n        }\n\n        // now draw the cursor if we need to\n        if (cursor_visible && has_focus && enabled)\n        {\n            draw_line(c, point(cursor_rect.left(), cursor_rect.top()),point(cursor_rect.left(), cursor_rect.bottom()), 0, area);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WIDGETs_STYLE_CPP_\n\n"
  },
  {
    "path": "dlib/gui_widgets/style.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WIDGETs_STYLE_\n#define DLIB_WIDGETs_STYLE_\n\n#include \"../algs.h\"\n#include \"style_abstract.h\"\n#include \"../gui_core.h\"\n#include \"canvas_drawing.h\"\n#include <string>\n#include <sstream>\n#include \"../unicode.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"fonts.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // button styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button_style\n    {\n    public:\n\n        button_style()\n        {\n        }\n\n        virtual ~button_style() \n        {}\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return false; }\n\n        virtual rectangle get_invalidation_rect (\n            const rectangle& rect\n        ) const { return rect; }\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const = 0;\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_default : public button_style\n    {\n    public:\n        button_style_default () : padding(4), name_width(0) {}\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const;\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    private:\n\n        // this is the minimum amount of padding that can separate the name from the\n        // edge of the button\n        const unsigned long padding;\n        // this is the width of the name string\n        mutable unsigned long name_width;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_toolbar1 : public button_style\n    {\n    public:\n        button_style_toolbar1 () : padding(4), name_width(0) {}\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const;\n\n        virtual rectangle get_invalidation_rect (\n            const rectangle& rect\n        ) const \n        { \n            rectangle temp(rect);\n            temp.left() -= 2;\n            temp.top() -= 2;\n            temp.right() += 2;\n            temp.bottom() += 2;\n            return temp; \n        }\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return true; }\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    private:\n\n        // this is the minimum amount of padding that can separate the name from the\n        // edge of the button\n        const unsigned long padding;\n        // this is the width of the name string\n        mutable unsigned long name_width;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_toolbar_icon1 : public button_style\n    {\n    public:\n        template <typename image_type>\n        button_style_toolbar_icon1 (const image_type& img_, unsigned long pad = 6) : padding(pad) \n        { \n            assign_image(img_mouseover,img_); \n            make_images();  \n        }\n\n        button_style_toolbar_icon1( const button_style_toolbar_icon1& item): button_style(item), padding(item.padding) \n        {\n            assign_image(img_mouseover, item.img_mouseover);\n            assign_image(img_normal, item.img_normal);\n            assign_image(img_disabled, item.img_disabled);\n        }\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const;\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return true; }\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    private:\n\n        void make_images (\n        )\n        {\n            // make the disabled image grayscale and make both non-mouseover images have weaker alpha channels\n            img_disabled.set_size(img_mouseover.nr(), img_mouseover.nc());\n            img_normal.set_size(img_mouseover.nr(), img_mouseover.nc());\n\n            for (long r = 0; r < img_mouseover.nr(); ++r)\n            {\n                for (long c = 0; c < img_mouseover.nc(); ++c)\n                {\n                    rgb_alpha_pixel p = img_mouseover[r][c];\n                    long avg = p.red;\n                    avg += p.green;\n                    avg += p.blue;\n                    avg /= 3;\n\n                    if (p.alpha > 40)\n                        p.alpha -= 40;\n                    else\n                        p.alpha = 0;\n\n                    img_normal[r][c] = p;\n\n                    if (p.alpha > 80)\n                        p.alpha -= 80;\n                    else\n                        p.alpha = 0;\n\n                    p.red = avg;\n                    p.green = avg;\n                    p.blue = avg;\n                    img_disabled[r][c] = p;\n                }\n            }\n        }\n\n        array2d<rgb_alpha_pixel> img_mouseover;\n        array2d<rgb_alpha_pixel> img_normal;\n        array2d<rgb_alpha_pixel> img_disabled;\n\n        // this is the minimum amount of padding that can separate the name from the\n        // edge of the button\n        const unsigned long padding;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_arrow : public button_style\n    {\n\n    public:\n\n        enum arrow_direction \n        {\n            UP,\n            DOWN,\n            LEFT,\n            RIGHT\n        };\n\n        button_style_arrow (\n            arrow_direction dir_\n        ) : dir(dir_) {}\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const;\n\n        virtual rectangle get_min_size (\n            const ustring& ,\n            const font&  \n        ) const { return rectangle(); }\n\n    private:\n        arrow_direction dir;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // toggle button styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style\n    {\n    public:\n\n        toggle_button_style()\n        {\n        }\n\n        virtual ~toggle_button_style() \n        {}\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return false; }\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const = 0;\n\n        virtual void draw_toggle_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed,\n            const bool is_checked\n        ) const = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_default : public toggle_button_style\n    {\n    public:\n        toggle_button_style_default () : padding(4), name_width(0) {}\n\n        virtual void draw_toggle_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed,\n            const bool is_checked\n        ) const;\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    private:\n\n        // this is the minimum amount of padding that can separate the name from the\n        // edge of the button\n        const unsigned long padding;\n        // this is the width of the name string\n        mutable unsigned long name_width;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_check_box : public toggle_button_style\n    {\n    public:\n        virtual void draw_toggle_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed,\n            const bool is_checked\n        ) const;\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_radio_button : public toggle_button_style\n    {\n    public:\n        virtual void draw_toggle_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed,\n            const bool is_checked\n        ) const;\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scroll_bar styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar_style\n    {\n    public:\n\n        virtual ~scroll_bar_style() {}\n\n        virtual bool redraw_on_mouse_over_slider (\n        ) const { return false; }\n\n        virtual long get_width (\n        ) const = 0;\n\n        virtual long get_slider_length (\n            long total_length,\n            long max_pos\n        ) const = 0;\n\n        virtual long get_button_length (\n            long total_length,\n            long max_pos\n        ) const = 0;\n\n        virtual void draw_scroll_bar_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_depressed\n        ) const = 0;\n\n        virtual void draw_scroll_bar_slider (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_being_dragged\n        ) const = 0;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar_style_default : public scroll_bar_style\n    {\n    public:\n        button_style_arrow get_up_button_style (\n        ) const { return button_style_arrow(button_style_arrow::UP); }\n\n        button_style_arrow get_down_button_style (\n        ) const { return button_style_arrow(button_style_arrow::DOWN); }\n\n        button_style_arrow get_left_button_style (\n        ) const { return button_style_arrow(button_style_arrow::LEFT); }\n\n        button_style_arrow get_right_button_style (\n        ) const { return button_style_arrow(button_style_arrow::RIGHT); }\n\n        virtual long get_width (\n        ) const  { return 16; }\n\n        virtual long get_slider_length (\n            long total_length,\n            long max_pos\n        ) const;\n\n        virtual long get_button_length (\n            long total_length,\n            long max_pos\n        ) const;\n\n        virtual void draw_scroll_bar_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_depressed\n        ) const;\n\n        virtual void draw_scroll_bar_slider (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_being_dragged\n        ) const;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scrollable_region styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region_style\n    {\n    public:\n\n        virtual ~scrollable_region_style() {}\n\n        virtual long get_border_size (\n        ) const = 0;\n\n        virtual void draw_scrollable_region_border (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled\n        ) const = 0;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region_style_default : public scrollable_region_style\n    {\n    public:\n        scroll_bar_style_default get_horizontal_scroll_bar_style (\n        ) const { return scroll_bar_style_default(); }\n\n        scroll_bar_style_default get_vertical_scroll_bar_style (\n        ) const { return scroll_bar_style_default(); }\n\n        virtual long get_border_size (\n        ) const { return 2; }\n\n        virtual void draw_scrollable_region_border (\n            const canvas& c,\n            const rectangle& rect,\n            const bool \n        ) const  { draw_sunken_rectangle(c,rect); }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // list_box styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class list_box_style\n    {\n    public:\n\n        virtual ~list_box_style() {}\n\n        virtual void draw_list_box_background (\n            const canvas& c,\n            const rectangle& display_rect,\n            const bool enabled\n        ) const = 0;\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::string& text,\n            const bool is_selected\n        ) const = 0;\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::wstring& text,\n            const bool is_selected\n        ) const = 0;\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const bool is_selected\n        ) const = 0;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class list_box_style_default : public list_box_style\n    {\n    public:\n        scrollable_region_style_default get_scrollable_region_style (\n        ) const { return scrollable_region_style_default(); }\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::string& text,\n            const bool is_selected\n        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::wstring& text,\n            const bool is_selected\n        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const bool is_selected\n        ) const { draw_list_box_item_template(c,rect,display_rect, enabled, mfont, text, is_selected); }\n\n        template <typename string_type>\n        void draw_list_box_item_template (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const string_type& text,\n            const bool is_selected\n        ) const\n        {\n            if (is_selected)\n            {\n                if (enabled)\n                    fill_rect_with_vertical_gradient(c,rect,rgb_pixel(110,160,255),  rgb_pixel(100,130,250),display_rect);\n                else\n                    fill_rect_with_vertical_gradient(c,rect,rgb_pixel(140,190,255),  rgb_pixel(130,160,250),display_rect);\n            }\n\n            if (enabled)\n                mfont.draw_string(c,rect,text,rgb_pixel(0,0,0),0,std::string::npos,display_rect);\n            else\n                mfont.draw_string(c,rect,text,rgb_pixel(128,128,128),0,std::string::npos,display_rect);\n        }\n\n        virtual void draw_list_box_background (\n            const canvas& c,\n            const rectangle& display_rect,\n            const bool enabled\n        ) const\n        {\n            if (enabled)\n            {\n                // first fill our area with white\n                fill_rect(c, display_rect,rgb_pixel(255,255,255));\n            }\n            else\n            {\n                // first fill our area with gray \n                fill_rect(c, display_rect,rgb_pixel(212,208,200));\n            }\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_box styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_box_style\n    {\n    public:\n\n        text_box_style()\n        {\n        }\n\n        virtual ~text_box_style() \n        {}\n\n        virtual unsigned long get_padding (\n            const font& mfont \n        ) const = 0;\n\n        virtual void draw_text_box (\n            const canvas& c,\n            const rectangle& display_rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const rectangle& cursor_rect,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class text_box_style_default : public text_box_style\n    {\n    public:\n\n        text_box_style_default()\n        {\n        }\n\n        scrollable_region_style_default get_scrollable_region_style (\n        ) const { return scrollable_region_style_default(); }\n\n        virtual ~text_box_style_default() \n        {}\n\n        virtual unsigned long get_padding (\n            const font&  \n        ) const { return 1; }\n\n        virtual void draw_text_box (\n            const canvas& c,\n            const rectangle& display_rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const rectangle& cursor_rect,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_field styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_field_style\n    {\n    public:\n\n        text_field_style()\n        {\n        }\n\n        virtual ~text_field_style() \n        {}\n\n        virtual unsigned long get_padding (\n            const font& mfont \n        ) const = 0;\n\n        virtual void draw_text_field (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const unsigned long cursor_x,\n            const unsigned long text_pos,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class text_field_style_default : public text_field_style\n    {\n    public:\n\n        text_field_style_default()\n        {\n        }\n\n        virtual ~text_field_style_default() \n        {}\n\n        virtual unsigned long get_padding (\n            const font& mfont \n        ) const;\n\n        virtual void draw_text_field (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const unsigned long cursor_x,\n            const unsigned long text_pos,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"style.cpp\"\n#endif\n\n#endif // DLIB_WIDGETs_STYLE_\n\n\n"
  },
  {
    "path": "dlib/gui_widgets/style_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), and Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_WIDGETs_STYLE_ABSTRACT_\n#ifdef DLIB_WIDGETs_STYLE_ABSTRACT_\n\n#include \"../algs.h\"\n#include \"../gui_core.h\"\n#include \"widgets_abstract.h\"\n#include \"../unicode/unicode_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // button styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class button_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                button style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n\n    public:\n\n        virtual ~button_style() {}\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return false; }\n        /*!\n            ensures\n                - if (this style draws buttons differently when a mouse is over them) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        virtual rectangle get_invalidation_rect (\n            const rectangle& rect\n        ) const { return rect; }\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - rect == the get_rect() that defines where the button is\n            ensures\n                - returns a rectangle that should be invalidated whenever a button\n                  needs to redraw itself.  (e.g. If you wanted your button style to\n                  draw outside the button then you could return a larger rectangle)\n        !*/\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns a rectangle that represents the minimum size of the button\n                  given the name and font.\n        !*/\n\n        virtual void draw_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect, enabled, mfont, lastx, and lasty are the variables\n                  defined in the protected section of the drawable class.\n                - name == the name of the button to be drawn\n                - is_depressed == true if the button is to be drawn in a depressed state\n            ensures\n                - draws the button on the canvas c at the location given by rect.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_default : public button_style\n    {\n        /*!\n            This is the default style for button objects.  It will cause\n            a button to appear as the simple MS Windows 2000 button style.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_toolbar1 : public button_style\n    {\n        /*!\n            This draws a simple toolbar style button that displays its name in the\n            middle of itself.  When the mouse moves over it it will light up.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_toolbar_icon1 : public button_style\n    {\n        /*!\n            This draws a simple toolbar style button that displays an image in the \n            middle of itself.  When the mouse moves over it it will light up.\n        !*/\n        template <typename image_type>\n        button_style_toolbar_icon1 (\n            const image_type& img, \n            unsigned long border_size = 6\n        );\n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h\n                - pixel_traits<typename image_type::type> is defined\n            ensures\n                - displays image img in the middle of the button\n                - the distance between the edge of the button and the image\n                  will be border_size pixels\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class button_style_arrow : public button_style\n    {\n    public:\n        /*!\n            This draws a simple button with an arrow in it \n        !*/\n\n        enum arrow_direction \n        {\n            UP,\n            DOWN,\n            LEFT,\n            RIGHT\n        };\n\n        button_style_arrow (\n            arrow_direction dir\n        );\n        /*!\n            ensures\n                - the arrow in the button will point in the given direction\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // toggle button styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                toggle button style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n\n    public:\n\n        virtual ~toggle_button_style() {}\n\n        virtual bool redraw_on_mouse_over (\n        ) const { return false; }\n        /*!\n            ensures\n                - if (this style draws buttons differently when a mouse is over them) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        virtual rectangle get_min_size (\n            const ustring& name,\n            const font& mfont \n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns a rectangle that represents the minimum size of the button\n                  given the name and font.\n        !*/\n\n        virtual void draw_toggle_button (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const font& mfont,\n            const long lastx,\n            const long lasty,\n            const ustring& name,\n            const bool is_depressed,\n            const bool is_checked \n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect, enabled, mfont, lastx, and lasty are the variables\n                  defined in the protected section of the drawable class.\n                - name == the name of the button to be drawn\n                - is_depressed == true if the button is to be drawn in a depressed state\n                - is_checked == true if the toggle_button is in the checked state \n            ensures\n                - draws the button on the canvas c at the location given by rect.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_default : public toggle_button_style\n    {\n        /*!\n            This is the default style for toggle_button objects.  It will cause\n            a button to appear as the simple MS Windows 2000 button style.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_check_box : public toggle_button_style\n    {\n        /*!\n            This draws a simple check box style toggle button that displays its \n            name to the right of a check box. \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button_style_radio_button : public toggle_button_style\n    {\n        /*!\n            This draws a simple radio button style toggle button that displays its \n            name to the right of a circular radio button. \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scroll_bar styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                scroll_bar style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n\n                There are three parts of a scroll bar, the slider, the background,\n                and the two buttons on its ends.  The \"slider\" is the thing that you\n                drag around on the scroll bar and the \"background\" is the part\n                in between the slider and the buttons on the ends.\n        !*/\n\n    public:\n\n        virtual ~scroll_bar_style() {}\n\n        virtual bool redraw_on_mouse_over_slider (\n        ) const { return false; }\n        /*!\n            ensures\n                - if (this style draws a scroll_bar's slider differently when a mouse is over it\n                  or it is being dragged) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        virtual long get_width (\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns the width in pixels of the scroll bar\n        !*/\n\n        virtual long get_slider_length (\n            long total_length,\n            long max_pos\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - total_length == the total length in pixels of the scroll bar\n                - max_pos == the value of scroll_bar::max_slider_pos() for this\n                  scroll bar\n            ensures\n                - returns the length in pixels of the scroll bar's slider\n        !*/\n\n        virtual long get_button_length (\n            long total_length,\n            long max_pos\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - total_length == the total length in pixels of the scroll bar\n                - max_pos == the value of scroll_bar::max_slider_pos() for this\n                  scroll bar\n            ensures\n                - returns the length in pixels of each of the scroll bar's\n                  buttons\n        !*/\n\n        virtual void draw_scroll_bar_background (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_depressed\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect, enabled, lastx, and lasty are the variables\n                  defined in the protected section of the drawable class.\n                - is_depressed == true if the background area of the scroll_bar is to \n                  be drawn in a depressed state (because the user is clicking on it)\n            ensures\n                - draws the background part of the scroll_bar on the canvas c at the \n                  location given by rect.  \n        !*/\n\n        virtual void draw_scroll_bar_slider (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled,\n            const long lastx,\n            const long lasty,\n            const bool is_being_dragged\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect, enabled, lastx, and lasty are the variables\n                  defined in the protected section of the drawable class\n                - is_being_dragged == true if the user is dragging the slider\n            ensures\n                - draws the slider part of the scroll_bar on the canvas c at the \n                  location given by rect.  \n        !*/\n\n        button_style_type get_up_button_style (\n        ) const;\n        /*!\n            ensures\n                - returns the type of button_style to use for a button on the\n                  top side of a vertical scroll bar.\n        !*/\n\n        button_style_type get_down_button_style (\n        ) const;\n        /*!\n            ensures\n                - returns the type of button_style to use for a button on the\n                  bottom side of a vertical scroll bar.\n        !*/\n\n        button_style_type get_left_button_style (\n        ) const;\n        /*!\n            ensures\n                - returns the type of button_style to use for a button on the\n                  left side of a horizontal scroll bar.\n        !*/\n\n        button_style_type get_right_button_style (\n        ) const;\n        /*!\n            ensures\n                - returns the type of button_style to use for a button on the\n                  right side of a horizontal scroll bar.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scroll_bar_style_default : public scroll_bar_style\n    {\n        /*!\n            This is the default style for scroll_bar objects.  It will cause\n            a scroll_bar to appear as the simple MS Windows 2000 scroll_bar style.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // scrollable_region (and zoomable_region) styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                scrollable_region and zoomable_region style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n    public:\n\n        virtual ~scrollable_region_style() {}\n\n        virtual long get_border_size (\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns the size of the border region in pixels \n        !*/\n\n        virtual void draw_scrollable_region_border (\n            const canvas& c,\n            const rectangle& rect,\n            const bool enabled\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect and enabled are the variables defined in the protected section \n                  of the drawable class.\n            ensures\n                - draws the border part of a scrollable_region on the canvas c at the \n                  location given by rect.  \n        !*/\n\n        scroll_bar_style_type get_horizontal_scroll_bar_style (\n        ) const;\n        /*!\n            ensures\n                - returns the style of scroll_bar to use for the \n                  horizontal scroll_bar in this widget.\n        !*/\n\n        scroll_bar_style_type get_vertical_scroll_bar_style (\n        ) const;\n        /*!\n            ensures\n                - returns the style of scroll_bar to use for the \n                  vertical scroll_bar in this widget.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class scrollable_region_style_default : public scrollable_region_style\n    {\n    public:\n        /*!\n            This is the default style for scrollable_region and zoomable_region objects.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_box styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_box_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                text_box style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n    public:\n\n        virtual ~text_field_style() {}\n\n        scrollable_region_style_type get_scrollable_region_style (\n        ) const;\n        /*!\n            ensures\n                - returns the style of scrollable_region to use for the \n                  text_box.\n        !*/\n\n        virtual unsigned long get_padding (\n            const font& mfont \n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns the number of pixels that separate the text in the text_box \n                  from the edge of the text_box widget itself.\n        !*/\n\n        virtual void draw_text_box (\n            const canvas& c,\n            const rectangle& display_rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const rectangle& cursor_rect,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - enabled and mfont are the variables defined in the protected section \n                - text_rect == the rectangle in which we should draw the given text\n                  of the drawable class.\n                - display_rect == the rectangle returned by scrollable_region::display_rect()\n                - text == the current text in the text_box \n                - cursor_rect == A rectangle of width 1 that represents the current\n                  position of the cursor on the screen.\n                - text_color == the color of the text to be drawn\n                - bg_color == the background color of the text field\n                - has_focus == true if this text field has keyboard input focus\n                - cursor_visible == true if the cursor should be drawn \n                - if (highlight_start <= highlight_end) then\n                    - text[highlight_start] though text[highlight_end] should be\n                      highlighted\n            ensures\n                - draws the text_box on the canvas c at the location given by text_rect.\n                  (Note that the scroll bars and borders are drawn by the scrollable_region\n                  and therefore the style returned by get_scrollable_region_style() \n                  controls how those appear)\n                - doesn't draw anything outside display_rect\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class text_box_style_default : public text_box_style\n    {\n    public:\n        /*!\n            This is the default style for text_box objects.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // list_box styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class list_box_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                list_box style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n    public:\n\n        virtual ~list_box_style() {}\n\n        virtual void draw_list_box_background (\n            const canvas& c,\n            const rectangle& display_rect,\n            const bool enabled\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - display_rect == the display_rect for the list_box.  This is the area\n                  in which list box items are drawn (see display_rect in the scrollable_region\n                  widget for more info)\n                - enabled == true if the list box is enabled\n            ensures\n                - draws the background of a list box on the canvas c at the location given \n                  by display_rect.  \n        !*/\n\n        scrollable_region_style_type get_scrollable_region_style (\n        ) const;\n        /*!\n            ensures\n                - returns the style of scrollable_region to use for the \n                  list_box.\n        !*/\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::string& text,\n            const bool is_selected\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect == the rectangle that defines where on the screen this list box item is.\n                - display_rect == the display_rect for the list_box.  This is the area\n                  in which list box items are drawn (see display_rect in the scrollable_region\n                  widget for more info)\n                - mfont == the font to use to draw the list box item\n                - text == the text of the list box item to be drawn\n                - enabled == true if the list box is enabled\n                - is_selected == true if the item is to be drawn in a selected state\n            ensures\n                - draws the list box item on the canvas c at the location given by rect.  \n        !*/\n\n        // wide character overloads\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const std::wstring& text,\n            const bool is_selected\n        ) const = 0;\n\n        virtual void draw_list_box_item (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& display_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const bool is_selected\n        ) const = 0;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class list_box_style_default : public list_box_style\n    {\n    public:\n        /*!\n            This is the default style for list_box objects.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_field styles  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_field_style\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an abstract class that defines the interface a\n                text_field style object must implement.\n\n                Note that derived classes must be copyable via\n                their copy constructors.\n        !*/\n    public:\n\n        virtual ~text_field_style() {}\n\n        virtual unsigned long get_padding (\n            const font& mfont \n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n            ensures\n                - returns the number of pixels that separate the text in the text_field\n                  from the edge of the text_field widget itself.\n        !*/\n\n        virtual void draw_text_field (\n            const canvas& c,\n            const rectangle& rect,\n            const rectangle& text_rect,\n            const bool enabled,\n            const font& mfont,\n            const ustring& text,\n            const unsigned long cursor_x,\n            const unsigned long text_pos,\n            const rgb_pixel& text_color,\n            const rgb_pixel& bg_color,\n            const bool has_focus,\n            const bool cursor_visible,\n            const long highlight_start,\n            const long highlight_end\n        ) const = 0;\n        /*!\n            requires\n                - the mutex drawable::m is locked\n                - c == the canvas to draw on\n                - rect, enabled, and mfont are the variables defined in the protected section \n                  of the drawable class.\n                - text == the current text in the text_field \n                - text_rect == the rectangle in which we should draw the given text\n                - cursor_x == the x coordinate of the cursor relative to the left side \n                  of rect.  i.e. the number of pixels that separate the cursor from the\n                  left side of the text_field.\n                - text_pos == the index of the first letter in text that appears in \n                  this text field.\n                - text_color == the color of the text to be drawn\n                - bg_color == the background color of the text field\n                - has_focus == true if this text field has keyboard input focus\n                - cursor_visible == true if the cursor should be drawn \n                - if (highlight_start <= highlight_end) then\n                    - text[highlight_start] though text[highlight_end] should be\n                      highlighted\n            ensures\n                - draws the text_field on the canvas c at the location given by rect.  \n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class text_field_style_default : public text_field_style\n    {\n    public:\n        /*!\n            This is the default style for text_field objects.  \n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WIDGETs_STYLE_ABSTRACT_\n\n\n\n"
  },
  {
    "path": "dlib/gui_widgets/widgets.cpp",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WIDGETs_CPP_\n#define DLIB_WIDGETs_CPP_\n\n#include <algorithm>\n#include <memory>\n\n#include \"widgets.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // toggle_button object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle min_rect = style->get_min_size(name_,*mfont);\n        // only change the size if it isn't going to be too small to fit the name\n        if (height >= min_rect.height() &&\n            width >= min_rect.width())\n        {\n            rectangle old(rect);\n            rect = resize_rect(rect,width,height);\n            parent.invalidate_rectangle(rect+old);\n            btn_tooltip.set_size(width,height);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_checked (\n    )\n    {\n        auto_mutex M(m);\n        checked = true;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_unchecked (\n    )\n    {\n        auto_mutex M(m);\n        checked = false;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool toggle_button::\n    is_checked (\n    ) const\n    {\n        auto_mutex M(m);\n        return checked;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    show (\n    )\n    {\n        button_action::show();\n        btn_tooltip.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    hide (\n    )\n    {\n        button_action::hide();\n        btn_tooltip.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    enable (\n    )\n    {\n        button_action::enable();\n        btn_tooltip.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    disable (\n    )\n    {\n        button_action::disable();\n        btn_tooltip.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_tooltip_text (\n        const std::string& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n    void toggle_button::\n    set_tooltip_text (\n        const std::wstring& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n    void toggle_button::\n    set_tooltip_text (\n        const dlib::ustring& text\n    )\n    {\n        btn_tooltip.set_text(text);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string toggle_button::\n    tooltip_text (\n    ) const\n    {\n        return btn_tooltip.text();\n    }\n\n    const std::wstring toggle_button::\n    tooltip_wtext (\n    ) const\n    {\n        return btn_tooltip.wtext();\n    }\n\n    const dlib::ustring toggle_button::\n    tooltip_utext (\n    ) const\n    {\n        return btn_tooltip.utext();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        set_name(name_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        button_action::set_pos(x,y);\n        btn_tooltip.set_pos(x,y);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    set_name (\n        const std::string& name\n    )\n    {\n        set_name(convert_to_utf32(name));\n    }\n\n    void toggle_button::\n    set_name (\n        const std::wstring& name\n    )\n    {\n        set_name(convert_to_utf32(name));\n    }\n\n    void toggle_button::\n    set_name (\n        const dlib::ustring& name\n    )\n    {\n        auto_mutex M(m);\n        name_ = name;\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        name_[0] = name_[0];\n\n        rectangle old(rect);\n        rect = move_rect(style->get_min_size(name,*mfont),rect.left(),rect.top());\n        btn_tooltip.set_size(rect.width(),rect.height());\n        \n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string toggle_button::\n    name (\n    ) const\n    {\n        return convert_wstring_to_mbstring(wname());\n    }\n\n    const std::wstring toggle_button::\n    wname (\n    ) const\n    {\n        return convert_utf32_to_wstring(uname());\n    }\n\n    const dlib::ustring toggle_button::\n    uname (\n    ) const\n    {\n        auto_mutex M(m);\n        dlib::ustring temp = name_;\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        temp[0] = name_[0];\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void toggle_button::\n    on_button_up (\n        bool mouse_over\n    )\n    {\n        if (mouse_over)                \n        {\n            checked = !checked;\n            // this is a valid toggle_button click\n            if (event_handler.is_set())\n                event_handler();\n            else if (event_handler_self.is_set())\n                event_handler_self(*this);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // label object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void label::\n    draw (\n        const canvas& c\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty() || text_.size() == 0)\n            return;\n\n        using namespace std;\n        unsigned char r = text_color_.red;\n        unsigned char g = text_color_.green;\n        unsigned char b = text_color_.blue;\n        if (!enabled)\n        {\n            r = 128;\n            g = 128;\n            b = 128;\n        }\n\n        rectangle text_rect(rect);\n\n        string::size_type first, last;\n        first = 0;\n        last = text_.find_first_of('\\n');\n        mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last);\n\n        while (last != string::npos)\n        {\n            first = last+1;\n            last = text_.find_first_of('\\n',first);\n            text_rect.set_top(text_rect.top()+mfont->height());\n            mfont->draw_string(c,text_rect,text_,rgb_pixel(r,g,b),first,last);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void label::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        set_text(text_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n    void label::\n    set_text (\n        const std::string& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void label::\n    set_text (\n        const std::wstring& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void label::\n    set_text (\n        const dlib::ustring& text\n    )\n    {\n        using namespace std;\n        auto_mutex M(m);\n        text_ = text;\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        text_[0] = text[0];\n\n        rectangle old(rect);\n\n        unsigned long width; \n        unsigned long height;\n        mfont->compute_size(text,width,height);\n\n        rect.set_right(rect.left() + width - 1); \n        rect.set_bottom(rect.top() + height - 1);\n\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string label::\n    text (\n    ) const\n    {\n        return convert_wstring_to_mbstring(wtext());\n    }\n\n    const std::wstring label::\n    wtext (\n    ) const\n    {\n        return convert_utf32_to_wstring(utext());\n    }\n\n    const dlib::ustring label::\n    utext (\n    ) const\n    {\n        auto_mutex M(m);\n        dlib::ustring temp = text_;\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        temp[0] = text_[0];\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void label::\n    set_text_color (\n        const rgb_pixel color\n    )\n    {\n        m.lock();\n        text_color_ = color;\n        parent.invalidate_rectangle(rect);\n        m.unlock();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel label::\n    text_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return text_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_field object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    rectangle text_field::\n    get_text_rect (\n    ) const\n    {\n        // figure out where the text string should appear        \n        unsigned long vertical_pad = (rect.height() - mfont->height())/2+1;\n\n        rectangle text_rect;\n        text_rect.set_left(rect.left()+style->get_padding(*mfont));\n        text_rect.set_top(rect.top()+vertical_pad);\n        text_rect.set_right(rect.right()-style->get_padding(*mfont));\n        text_rect.set_bottom(text_rect.top()+mfont->height()-1);\n        return text_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    enable (\n    )\n    {\n        drawable::enable();\n        right_click_menu.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    give_input_focus (\n    )\n    {\n        auto_mutex M(m);\n        has_focus = true;\n        cursor_visible = true;\n        parent.invalidate_rectangle(rect);\n        t.start();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool text_field::\n    has_input_focus (\n    ) const\n    {\n        auto_mutex M(m);\n        return has_focus;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    select_all_text (\n    )\n    {\n        auto_mutex M(m);\n        on_select_all();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_cut (\n    )\n    {\n        on_copy();\n        on_delete_selected();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_copy (\n    )\n    {\n        if (highlight_start <= highlight_end)\n        {\n            put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_paste (\n    )\n    {\n        ustring temp_str;\n        get_from_clipboard(temp_str);\n\n        // If this is a multi line string then just take the first line.\n        ustring::size_type pos = temp_str.find_first_of('\\n');\n        if (pos != ustring::npos)\n        {\n            temp_str = temp_str.substr(0,pos);\n        }\n\n        if (highlight_start <= highlight_end)\n        {\n            text_ = text_.substr(0,highlight_start) + temp_str +\n                text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n            move_cursor(highlight_start+temp_str.size());\n            highlight_start = 0;\n            highlight_end = -1;\n            parent.invalidate_rectangle(rect);\n            on_no_text_selected();\n\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n        }\n        else\n        {\n            text_ = text_.substr(0,cursor_pos) + temp_str +\n                text_.substr(cursor_pos,text_.size()-cursor_pos);\n            move_cursor(cursor_pos+temp_str.size());\n\n            // send out the text modified event\n            if (temp_str.size() != 0 && text_modified_handler.is_set())\n                text_modified_handler();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_select_all (\n    )\n    {\n        move_cursor(static_cast<long>(text_.size()));\n        highlight_start = 0;\n        highlight_end = static_cast<long>(text_.size()-1);\n        if (highlight_start <= highlight_end)\n            on_text_is_selected();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_delete_selected (\n    )\n    {\n        if (highlight_start <= highlight_end)\n        {\n            text_ = text_.erase(highlight_start,highlight_end-highlight_start+1);\n            move_cursor(highlight_start);\n            highlight_start = 0;\n            highlight_end = -1;\n\n            on_no_text_selected();\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_text_is_selected (\n    )\n    {\n        right_click_menu.menu().enable_menu_item(0);\n        right_click_menu.menu().enable_menu_item(1);\n        right_click_menu.menu().enable_menu_item(3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_no_text_selected (\n    )\n    {\n        right_click_menu.menu().disable_menu_item(0);\n        right_click_menu.menu().disable_menu_item(1);\n        right_click_menu.menu().disable_menu_item(3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    show (\n    )\n    {\n        drawable::show();\n        right_click_menu.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        drawable::disable();\n        t.stop();\n        has_focus = false;\n        cursor_visible = false;\n        right_click_menu.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        drawable::hide();\n        t.stop();\n        has_focus = false;\n        cursor_visible = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        // adjust the height of this text field so that it is appropriate for the current\n        // font size\n        rect.set_bottom(rect.top() + mfont->height()+ (style->get_padding(*mfont))*2);\n        set_text(text_);\n        right_click_menu.set_rect(get_text_rect());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    draw (\n        const canvas& c\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n       \n        style->draw_text_field(c,rect,get_text_rect(), enabled, *mfont, text_, cursor_x, text_pos,\n                               text_color_, bg_color_, has_focus, cursor_visible, highlight_start,\n                               highlight_end);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_text (\n        const std::string& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void text_field::\n    set_text (\n        const std::wstring& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void text_field::\n    set_text (\n        const dlib::ustring& text\n    )\n    {\n        DLIB_ASSERT ( text.find_first_of('\\n') == std::string::npos ,\n                \"\\tvoid text_field::set_text()\"\n                << \"\\n\\ttext:  \" << narrow(text) );\n        auto_mutex M(m);\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        text_ = text.c_str();\n                \n        move_cursor(0);\n\n        highlight_start = 0;\n        highlight_end = -1;\n        \n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string text_field::\n    text (\n    ) const\n    {\n        std::string temp = convert_wstring_to_mbstring(wtext());\n        return temp;\n    }\n\n    const std::wstring text_field::\n    wtext (\n    ) const\n    {\n        std::wstring temp = convert_utf32_to_wstring(utext());\n        return temp;\n    }\n    \n    const dlib::ustring text_field::\n    utext (\n    ) const\n    {\n        auto_mutex M(m);\n        // do this to get rid of any reference counting that may be present in \n        // the dlib::ustring implementation.\n        dlib::ustring temp = text_.c_str();\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_width (\n        unsigned long width\n    )\n    {        \n        auto_mutex M(m);\n        if (width < style->get_padding(*mfont)*2)\n            return;\n\n        rectangle old(rect);\n\n        rect.set_right(rect.left() + width - 1); \n\n        right_click_menu.set_rect(get_text_rect());\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        drawable::set_pos(x,y);\n        right_click_menu.set_rect(get_text_rect());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_background_color (\n        const rgb_pixel color\n    )\n    {\n        auto_mutex M(m);\n        bg_color_ = color;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_field::\n    background_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return bg_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    set_text_color (\n        const rgb_pixel color\n    )\n    {\n        auto_mutex M(m);\n        text_color_ = color;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_field::\n    text_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return text_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (!enabled || hidden || !has_focus)\n        {\n            return;\n        }\n\n        if (state & base_window::LEFT)\n        {\n            if (highlight_start <= highlight_end)\n            {\n                if (highlight_start == cursor_pos)\n                    shift_pos = highlight_end + 1;\n                else\n                    shift_pos = highlight_start;\n            }\n\n            unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos);\n            if (static_cast<long>(new_pos) != cursor_pos)\n            {\n                move_cursor(new_pos);\n                parent.invalidate_rectangle(rect);\n            }\n        }\n        else if (shift_pos != -1)\n        {\n            shift_pos = -1;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long,\n        long ,\n        long \n    )\n    {\n        if (!enabled || hidden)\n            return;\n\n        if (btn == base_window::LEFT)\n            shift_pos = -1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool double_clicked \n    )\n    {\n        using namespace std;\n        if (!enabled || hidden || btn != (unsigned long)base_window::LEFT)\n            return;\n\n        if (rect.contains(x,y))\n        {\n            has_focus = true;\n            cursor_visible = true;\n            parent.invalidate_rectangle(rect);\n            t.start();\n\n            if (double_clicked)\n            {\n                // highlight the double clicked word\n                string::size_type first, last;\n                const ustring ustr = convert_to_utf32(std::string(\" \\t\\n\"));\n                first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str());\n                last = text_.find_first_of(ustr.c_str(),cursor_pos);\n                long f = static_cast<long>(first);\n                long l = static_cast<long>(last);\n                if (first == string::npos)\n                    f = -1;\n                if (last == string::npos)\n                    l = static_cast<long>(text_.size());\n\n                ++f;\n                --l;\n\n                move_cursor(l+1);\n                highlight_start = f;\n                highlight_end = l;\n                on_text_is_selected();\n            }\n            else\n            {\n                if (state & base_window::SHIFT)\n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        if (highlight_start == cursor_pos)\n                            shift_pos = highlight_end + 1;\n                        else\n                            shift_pos = highlight_start;\n                    }\n                    else\n                    {\n                        shift_pos = cursor_pos;\n                    }\n                }\n\n                bool at_end = false;\n                if (cursor_pos == 0 || cursor_pos == static_cast<long>(text_.size()))\n                    at_end = true;\n                const long old_pos = cursor_pos;\n\n                unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y,text_pos);\n                if (static_cast<long>(new_pos) != cursor_pos)\n                {\n                    move_cursor(new_pos);\n                    parent.invalidate_rectangle(rect);\n                }\n                shift_pos = cursor_pos;\n\n                if (at_end && cursor_pos == old_pos)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n\n        }\n        else if (has_focus)\n        {\n            t.stop();\n            has_focus = false;\n            cursor_visible = false;\n            shift_pos = -1;\n            highlight_start = 0;\n            highlight_end = -1;\n            on_no_text_selected();\n\n            if (focus_lost_handler.is_set())\n                focus_lost_handler();\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        // If the right click menu is up then we don't want to do anything with\n        // the keyboard ourselves.  Let the popup menu use the keyboard for now.\n        if (right_click_menu.popup_menu_visible())\n            return;\n\n        const ustring space_str = convert_to_utf32(std::string(\" \\t\\n\"));\n        const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0;\n        const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0;\n        if (has_focus && enabled && !hidden)\n        {\n            if (shift && is_printable == false)\n            {\n                if (shift_pos == -1)\n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        if (highlight_start == cursor_pos)\n                            shift_pos = highlight_end + 1;\n                        else\n                            shift_pos = highlight_start;\n                    }\n                    else\n                    {\n                        shift_pos = cursor_pos;\n                    }\n                }\n            }\n            else\n            {\n                shift_pos = -1;\n            }\n\n            if (key == base_window::KEY_LEFT ||\n                key == base_window::KEY_UP)\n            {\n                if (cursor_pos != 0)\n                {\n                    unsigned long new_pos;\n                    if (ctrl)\n                    {\n                        // find the first non-whitespace to our left\n                        std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos);\n                        if (pos != std::string::npos)\n                        {\n                            pos = text_.find_last_of(space_str.c_str(),pos);\n                            if (pos != std::string::npos)\n                                new_pos = static_cast<unsigned long>(pos);\n                            else\n                                new_pos = 0;\n                        }\n                        else\n                        {\n                            new_pos = 0;\n                        }\n                    }\n                    else\n                    {\n                        new_pos = cursor_pos-1;\n                    }\n\n                    move_cursor(new_pos);\n                }\n                else if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n\n            }\n            else if (key == base_window::KEY_RIGHT ||\n                key == base_window::KEY_DOWN)\n            {\n                if (cursor_pos != static_cast<long>(text_.size()))\n                {\n                    unsigned long new_pos;\n                    if (ctrl)\n                    {\n                        // find the first non-whitespace to our left\n                        std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos);\n                        if (pos != std::string::npos)\n                        {\n                            pos = text_.find_first_of(space_str.c_str(),pos);\n                            if (pos != std::string::npos)\n                                new_pos = static_cast<unsigned long>(pos+1);\n                            else\n                                new_pos = static_cast<unsigned long>(text_.size());\n                        }\n                        else\n                        {\n                            new_pos = static_cast<unsigned long>(text_.size());\n                        }\n                    }\n                    else\n                    {\n                        new_pos = cursor_pos+1;\n                    }\n\n                    move_cursor(new_pos);\n                }\n                else if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (is_printable)\n            {\n                if (ctrl)\n                {\n                    if (key == 'a')\n                    {\n                        on_select_all();\n                    }\n                    else if (key == 'c')\n                    {\n                        on_copy();\n                    }\n                    else if (key == 'v')\n                    {\n                        on_paste();\n                    }\n                    else if (key == 'x')\n                    {\n                        on_cut();\n                    }\n                }\n                else if (key != '\\n')\n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        text_ = text_.substr(0,highlight_start) + static_cast<unichar>(key) +\n                            text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n                        move_cursor(highlight_start+1);\n                        highlight_start = 0;\n                        highlight_end = -1;\n                        on_no_text_selected();\n                        parent.invalidate_rectangle(rect);\n                    }\n                    else\n                    {\n                        text_ = text_.substr(0,cursor_pos) + static_cast<unichar>(key) +\n                            text_.substr(cursor_pos,text_.size()-cursor_pos);\n                        move_cursor(cursor_pos+1);\n                    }\n                    unsigned long height;\n                    mfont->compute_size(text_,text_width,height,text_pos);\n\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n                }\n                else if (key == '\\n')\n                {\n                    if (enter_key_handler.is_set())\n                        enter_key_handler();\n                }\n            }\n            else if (key == base_window::KEY_BACKSPACE)\n            {                \n                // if something is highlighted then delete that\n                if (highlight_start <= highlight_end)\n                {\n                    on_delete_selected();\n                }\n                else if (cursor_pos != 0)\n                {\n                    text_ = text_.erase(cursor_pos-1,1);\n                    move_cursor(cursor_pos-1);\n\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n                }\n                else\n                {\n                    // do this just so it repaints itself right\n                    move_cursor(cursor_pos);\n                }\n                unsigned long height;\n                mfont->compute_size(text_,text_width,height,text_pos);\n                parent.invalidate_rectangle(rect);\n            }\n            else if (key == base_window::KEY_DELETE)\n            {\n                // if something is highlighted then delete that\n                if (highlight_start <= highlight_end)\n                {\n                    on_delete_selected();\n                }\n                else if (cursor_pos != static_cast<long>(text_.size()))\n                {\n                    text_ = text_.erase(cursor_pos,1);\n\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n                }\n                else\n                {\n                    // do this just so it repaints itself right\n                    move_cursor(cursor_pos);\n                }\n                parent.invalidate_rectangle(rect);\n\n                unsigned long height;\n                mfont->compute_size(text_,text_width,height,text_pos);\n            }\n            else if (key == base_window::KEY_HOME)\n            {\n                move_cursor(0);\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (key == base_window::KEY_END)\n            {\n                move_cursor(static_cast<unsigned long>(text_.size()));\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            cursor_visible = true;\n            recent_movement = true;\n\n        }\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    void text_field::\n    on_string_put(\n        const std::wstring &str\n    )\n    {\n        if (has_focus && enabled && !hidden){\n            ustring ustr = convert_to_utf32(str);\n            if (highlight_start <= highlight_end)\n            {\n                text_ = text_.substr(0,highlight_start) + ustr +\n                    text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n                move_cursor(highlight_start+ustr.size());\n                highlight_start = 0;\n                highlight_end = -1;\n                on_no_text_selected();\n                parent.invalidate_rectangle(rect);\n            }\n            else\n            {\n                text_ = text_.substr(0,cursor_pos) + ustr +\n                    text_.substr(cursor_pos,text_.size()-cursor_pos);\n                move_cursor(cursor_pos+ustr.size());\n            }\n            unsigned long height;\n            mfont->compute_size(text_,text_width,height,text_pos);\n\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    void text_field::\n    move_cursor (\n        unsigned long pos\n    )\n    {\n        using namespace std;\n        const long old_cursor_pos = cursor_pos;\n\n        if (text_pos >= pos)\n        {\n            // the cursor should go all the way to the left side of the text\n            if (pos >= 6)\n                text_pos = pos-6;\n            else\n                text_pos = 0;\n\n            cursor_pos = pos;    \n            unsigned long height;\n            mfont->compute_size(text_,text_width,height,text_pos);\n\n            unsigned long width;\n            unsigned long new_x = style->get_padding(*mfont);\n            if (static_cast<long>(cursor_pos)-1 >= static_cast<long>(text_pos))\n            {\n                mfont->compute_size(text_,width,height,text_pos,cursor_pos-1);\n                if (cursor_pos != 0)\n                    new_x += width - mfont->right_overflow();\n            }\n\n            cursor_x = new_x;\n        }\n        else\n        {\n            unsigned long height;\n            unsigned long width;\n            mfont->compute_size(text_,width,height,text_pos,pos-1);\n\n            unsigned long new_x = style->get_padding(*mfont) + \n                width - mfont->right_overflow();\n\n            // move the text to the left if necessary\n            if (new_x + 4 > rect.width())\n            {\n                while (new_x > rect.width() - rect.width()/5)\n                {\n                    new_x -= (*mfont)[text_[text_pos]].width();\n                    ++text_pos;\n                }\n            }\n\n            cursor_x = new_x;\n            cursor_pos = pos;     \n            mfont->compute_size(text_,text_width,height,text_pos);\n        }\n\n        parent.set_im_pos(rect.left()+cursor_x, rect.top());\n\n        if (old_cursor_pos != cursor_pos)\n        {\n            if (shift_pos != -1)\n            {\n                highlight_start = std::min(shift_pos,cursor_pos);\n                highlight_end = std::max(shift_pos,cursor_pos)-1;\n            }\n            else\n            {\n                highlight_start = 0;\n                highlight_end = -1;\n            }\n\n            if (highlight_start > highlight_end)\n                on_no_text_selected();\n            else\n                on_text_is_selected();\n\n            recent_movement = true;\n            cursor_visible = true;\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//             tabbed_display object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    tabbed_display::\n    tabbed_display(  \n        drawable_window& w\n    ) : \n        drawable(w,MOUSE_CLICK),\n        selected_tab_(0),\n        left_pad(6),\n        right_pad(4),\n        top_pad(3),\n        bottom_pad(3)\n    {\n        rect = rectangle(0,0,40,mfont->height()+top_pad+bottom_pad);\n        enable_events();\n        tabs.set_max_size(1);\n        tabs.set_size(1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    tabbed_display::\n    ~tabbed_display(\n    )\n    {\n        disable_events();\n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        auto_mutex M(m);\n        // we have to adjust the positions of all the tab rectangles\n        const long xdelta = rect.left() - x;\n        const long ydelta = rect.top() - y;\n        for (unsigned long i = 0; i < tabs.size(); ++i)\n        {\n            tabs[i].rect.set_left(tabs[i].rect.left()+xdelta);\n            tabs[i].rect.set_right(tabs[i].rect.right()+xdelta);\n\n            tabs[i].rect.set_top(tabs[i].rect.top()+ydelta);\n            tabs[i].rect.set_bottom(tabs[i].rect.bottom()+ydelta);\n\n\n            // adjust the position of the group associated with this tab if it exists\n            if (tabs[i].group)\n                tabs[i].group->set_pos(x+3, y+mfont->height()+top_pad+bottom_pad+3);\n        }\n        drawable::set_pos(x,y);\n        recompute_tabs();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    fit_to_contents (\n    )\n    {\n        auto_mutex M(m);\n        rectangle new_rect;\n        point p(rect.left(),rect.top());\n        new_rect += p;\n\n        for (unsigned long i = 0; i < tabs.size(); ++i)\n        {\n            if (tabs[i].group)\n            {\n                tabs[i].group->fit_to_contents();\n                new_rect += tabs[i].group->get_rect();\n            }\n        }\n\n        // and give the new rect an additional 4 pixels on the bottom and right sides\n        // so that the contents to hit the edge of the tabbed display\n        new_rect = resize_rect(new_rect, new_rect.width()+4, new_rect.height()+4);\n\n        parent.invalidate_rectangle(new_rect+rect);\n        rect = new_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle old(rect);\n        const long x = rect.left();\n        const long y = rect.top();\n        rect.set_right(x+width-1);\n        rect.set_bottom(y+height-1);\n\n        recompute_tabs();\n\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_number_of_tabs (\n        unsigned long num\n    )\n    {\n        auto_mutex M(m);\n\n        DLIB_ASSERT ( num > 0 ,\n                \"\\tvoid tabbed_display::set_number_of_tabs()\"\n                << \"\\n\\tnum:  \" << num );\n\n        tabs.set_max_size(num);\n        tabs.set_size(num);\n\n        selected_tab_ = 0;\n\n        recompute_tabs();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long tabbed_display::\n    selected_tab (\n    ) const\n    {\n        auto_mutex M(m);\n        return selected_tab_;\n    }\n\n    unsigned long tabbed_display::\n    number_of_tabs (\n    ) const\n    {\n        auto_mutex M(m);\n        return tabs.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string tabbed_display::\n    tab_name (\n        unsigned long idx\n    ) const\n    {\n        return convert_wstring_to_mbstring(tab_wname(idx));\n    }\n    \n    const std::wstring tabbed_display::\n    tab_wname (\n        unsigned long idx\n    ) const\n    {\n        return convert_utf32_to_wstring(tab_uname(idx));\n    }\n    \n    const dlib::ustring& tabbed_display::\n    tab_uname (\n        unsigned long idx\n    ) const\n    {\n        auto_mutex M(m);\n\n        DLIB_ASSERT ( idx < number_of_tabs() ,\n                \"\\tvoid tabbed_display::tab_name()\"\n                << \"\\n\\tidx:              \" << idx \n                << \"\\n\\tnumber_of_tabs(): \" << number_of_tabs() );\n\n        return tabs[idx].name;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_tab_name (\n        unsigned long idx,\n        const std::string& new_name\n    )\n    {\n        set_tab_name(idx, convert_to_utf32(new_name));\n    }\n\n    void tabbed_display::\n    set_tab_name (\n        unsigned long idx,\n        const std::wstring& new_name\n    )\n    {\n        set_tab_name(idx, convert_to_utf32(new_name));\n    }\n\n    void tabbed_display::\n    set_tab_name (\n        unsigned long idx,\n        const dlib::ustring& new_name\n    )\n    {\n        auto_mutex M(m);\n\n\n        DLIB_ASSERT ( idx < number_of_tabs() ,\n                \"\\tvoid tabbed_display::set_tab_name()\"\n                << \"\\n\\tidx:              \" << idx \n                << \"\\n\\tnumber_of_tabs(): \" << number_of_tabs() );\n\n\n        tabs[idx].name = new_name;\n        // do this so that there isn't any reference counting going on\n        tabs[idx].name[0] = tabs[idx].name[0];\n        unsigned long height;\n        mfont->compute_size(new_name,tabs[idx].width,height);\n\n\n        recompute_tabs();\n\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long,\n        long x,\n        long y,\n        bool \n    )\n    {\n        if (rect.contains(x,y) && btn == base_window::LEFT && enabled && !hidden)\n        {\n            rectangle temp = rect;\n            const long offset = mfont->height() + bottom_pad + top_pad;\n            temp.set_bottom(rect.top()+offset);\n            if (temp.contains(x,y))\n            {\n                // now we have to figure out which tab was clicked\n                for (unsigned long i = 0; i < tabs.size(); ++i)\n                {\n                    if (selected_tab_ != i && tabs[i].rect.contains(x,y) &&\n                        tabs[selected_tab_].rect.contains(x,y) == false)\n                    {\n                        unsigned long old_idx = selected_tab_;\n                        selected_tab_ = i;\n                        recompute_tabs();\n                        parent.invalidate_rectangle(temp);\n\n                        // adjust the widget_group objects for these tabs if they exist\n                        if (tabs[i].group)\n                            tabs[i].group->show();\n                        if (tabs[old_idx].group)\n                            tabs[old_idx].group->hide();\n\n                        if (event_handler.is_set())\n                            event_handler(i,old_idx);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_tab_group (\n        unsigned long idx,\n        widget_group& group\n    )\n    {\n        auto_mutex M(m);\n\n        DLIB_ASSERT ( idx < number_of_tabs() ,\n                \"\\tvoid tabbed_display::set_tab_group()\"\n                << \"\\n\\tidx:              \" << idx \n                << \"\\n\\tnumber_of_tabs(): \" << number_of_tabs() );\n\n\n        tabs[idx].group = &group;\n        group.set_pos(rect.left()+3,rect.top()+mfont->height()+top_pad+bottom_pad+2);\n        if (idx == selected_tab_)\n            group.show();\n        else\n            group.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        if (tabs[selected_tab_].group)\n            tabs[selected_tab_].group->disable();\n        drawable::disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    enable (\n    )\n    {\n        auto_mutex M(m);\n        if (tabs[selected_tab_].group)\n            tabs[selected_tab_].group->enable();\n        drawable::enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        if (tabs[selected_tab_].group)\n            tabs[selected_tab_].group->hide();\n        drawable::hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    show (\n    )\n    {\n        auto_mutex M(m);\n        if (tabs[selected_tab_].group)\n            tabs[selected_tab_].group->show();\n        drawable::show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    draw (\n        const canvas& c\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n\n        // draw the main border first\n        rectangle main_box(rect.left(),rect.top()+mfont->height()+top_pad+bottom_pad,rect.right(),rect.bottom());\n        draw_button_up(c,main_box);\n        draw_pixel(c,point(main_box.right()-1,main_box.top()),rgb_pixel(128,128,128));\n\n        rgb_pixel color;\n        if (enabled)\n        {\n            color.red = 0;\n            color.green = 0;\n            color.blue = 0;\n        }\n        else\n        {\n            color.red = 128;\n            color.green = 128;\n            color.blue = 128;\n        }\n\n        // draw the tabs\n        for (unsigned long i = 0; i < tabs.size(); ++i)\n        {\n            if (selected_tab_ != i)\n                draw_tab(tabs[i].rect,c);\n\n            // draw the name string\n            rectangle temp = tabs[i].rect;\n            temp.set_top(temp.top()+top_pad);\n            temp.set_bottom(temp.bottom()+bottom_pad);\n            temp.set_left(temp.left()+left_pad);\n            temp.set_right(temp.right()+right_pad);\n            mfont->draw_string(c,temp,tabs[i].name,color);\n        }\n        draw_tab(tabs[selected_tab_].rect,c);\n        draw_line(c,\n            point(tabs[selected_tab_].rect.left()+1,\n            tabs[selected_tab_].rect.bottom()),\n            point(tabs[selected_tab_].rect.right()-2,\n            tabs[selected_tab_].rect.bottom()),\n            rgb_pixel(212,208,200));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    draw_tab (\n        const rectangle& tab,\n        const canvas& c\n    ) const\n    {\n        const rgb_pixel white(255,255,255);\n        const rgb_pixel background(212,208,200);\n        const rgb_pixel dark_gray(64,64,64);\n        const rgb_pixel gray(128,128,128);\n        draw_line(c,point(tab.left(),tab.top()+2),point(tab.left(),tab.bottom()),white);\n        draw_line(c,point(tab.left()+1,tab.top()+2),point(tab.left()+1,tab.bottom()),background);\n        draw_line(c,point(tab.right(),tab.top()+2),point(tab.right(),tab.bottom()),dark_gray);\n        draw_line(c,point(tab.right()-1,tab.top()+2),point(tab.right()-1,tab.bottom()),gray);\n        draw_line(c,point(tab.left()+2,tab.top()),point(tab.right()-2,tab.top()),white);\n        draw_pixel(c,point(tab.left()+1,tab.top()+1),white);\n        draw_pixel(c,point(tab.right()-1,tab.top()+1),dark_gray);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n\n        for (unsigned long i = 0; i < tabs.size(); ++i)\n        {\n            unsigned long height;\n            mfont->compute_size(tabs[i].name,tabs[i].width,height);\n        }\n\n        recompute_tabs();\n        set_pos(rect.left(), rect.top());\n\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void tabbed_display::\n    recompute_tabs (\n    )\n    {\n        const long offset = mfont->height() + bottom_pad + top_pad;\n\n\n        // figure out the size and position of all the tabs\n        rectangle sel_tab_rect, other_tab;\n        sel_tab_rect.set_top(rect.top());\n        sel_tab_rect.set_bottom(rect.top()+offset);\n\n        other_tab.set_top(rect.top()+2);\n        other_tab.set_bottom(rect.top()+offset-1);\n\n        long cur_x = rect.left();\n        for (unsigned long i = 0; i < tabs.size(); ++i)\n        {\n            const unsigned long str_width = tabs[i].width;\n            if (selected_tab_ != i)\n            {\n                other_tab.set_left(cur_x);\n                cur_x += left_pad + str_width + right_pad;\n                other_tab.set_right(cur_x);\n                tabs[i].rect = other_tab;\n                ++cur_x;\n\n            }\n            else\n            {\n                if (i != 0)\n                    sel_tab_rect.set_left(cur_x-2);\n                else\n                    sel_tab_rect.set_left(cur_x);\n\n                cur_x += left_pad + str_width + right_pad;\n\n                if (i != tabs.size()-1)\n                    sel_tab_rect.set_right(cur_x+2);\n                else\n                    sel_tab_rect.set_right(cur_x);\n                ++cur_x;\n\n                tabs[i].rect = sel_tab_rect;\n            }\n        }\n\n        // make sure this object is wide enough\n        const rectangle& last = tabs[tabs.size()-1].rect;\n        const rectangle& first = tabs[0].rect;\n        rect = last + rect + first;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//             named_rectangle object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    named_rectangle::\n    named_rectangle(  \n        drawable_window& w\n    ) :\n        drawable(w),\n        name_width(0),\n        name_height(0)\n    {\n        make_name_fit_in_rect();\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    named_rectangle::\n    ~named_rectangle(\n    )\n    {\n        disable_events();\n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    set_size (\n        unsigned long width,\n        unsigned long height\n    )\n    {\n        auto_mutex M(m);\n        rectangle old(rect);\n        const long x = rect.left();\n        const long y = rect.top();\n        rect.set_right(x+width-1);\n        rect.set_bottom(y+height-1);\n\n        make_name_fit_in_rect();\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    wrap_around (\n        const rectangle& r\n    )\n    {\n        auto_mutex M(m);\n        rectangle old(rect);\n        const unsigned long pad = name_height/2;\n\n        rect = rectangle(r.left()-pad, r.top()-name_height*4/3, r.right()+pad, r.bottom()+pad);\n\n        make_name_fit_in_rect();\n        parent.invalidate_rectangle(rect+old);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        mfont->compute_size(name_,name_width,name_height);\n        make_name_fit_in_rect();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    make_name_fit_in_rect (\n    )\n    {\n        // make sure the named rectangle is big enough to contain the name\n        const unsigned long wtemp = mfont->height() + name_width;\n        const unsigned long htemp = mfont->height() + name_height;\n        if (rect.width() < wtemp)\n            rect.set_right(rect.left() + wtemp - 1 );\n        if (rect.height() < htemp)\n            rect.set_bottom(rect.bottom() + htemp - 1 );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    set_name (\n        const std::string& name\n    )\n    {\n        set_name(convert_to_utf32(name));\n    }\n\n    void named_rectangle::\n    set_name (\n        const std::wstring& name\n    )\n    {\n        set_name(convert_to_utf32(name));\n    }\n\n    void named_rectangle::\n    set_name (\n        const dlib::ustring& name\n    )\n    {\n        auto_mutex M(m);\n        name_ = name.c_str();\n        mfont->compute_size(name_,name_width,name_height);\n\n        make_name_fit_in_rect();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string named_rectangle::\n    name (\n    ) const\n    {\n        return convert_wstring_to_mbstring(wname());\n    }\n\n    const std::wstring named_rectangle::\n    wname (\n    ) const\n    {\n        return convert_utf32_to_wstring(uname());\n    }\n\n    const dlib::ustring named_rectangle::\n    uname (\n    ) const\n    {\n        auto_mutex M(m);\n        return dlib::ustring(name_.c_str());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void named_rectangle::\n    draw (\n        const canvas& c\n    ) const\n    {\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n        \n        const unsigned long gap = mfont->height()/2;\n        rectangle strrect = rect;\n        strrect.set_left(rect.left() + gap);\n\n        const unsigned long rtop = rect.top() + name_height/2;\n\n        const rgb_pixel white(255,255,255);\n        const rgb_pixel gray(128,128,128);\n\n        mfont->draw_string(c,strrect,name_);\n        draw_line(c,point(rect.left(), rtop),             \n                  point(rect.left()+gap/2, rtop), gray);\n        draw_line(c,point(rect.left(), rtop),             \n                  point(rect.left(), rect.bottom()-1), gray);\n        draw_line(c,point(rect.left(), rect.bottom()-1),  \n                  point(rect.right()-1, rect.bottom()-1), gray);\n        draw_line(c,point(rect.right()-1, rtop),          \n                  point(rect.right()-1, rect.bottom()-2), gray);\n        draw_line(c,point(strrect.left() + name_width + 2, rtop), \n                  point(rect.right()-1, rtop), gray);\n\n        draw_line(c,point(strrect.left() + name_width + 2, rtop+1),   \n                  point( rect.right()-2, rtop+1), white);\n        draw_line(c,point(rect.right(), rtop), \n                  point(rect.right(), rect.bottom()), white);\n        draw_line(c,point(rect.left(), rect.bottom()),                \n                  point(rect.right(), rect.bottom()), white);\n        draw_line(c,point(rect.left()+1, rtop+1), \n                  point(rect.left()+1, rect.bottom()-2), white);\n        draw_line(c,point(rect.left()+1, rtop+1), \n                  point(rect.left()+gap/2, rtop+1), white);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class mouse_tracker\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    mouse_tracker::\n    mouse_tracker(  \n        drawable_window& w\n    ) :\n        draggable(w),\n        offset(18),\n        nr(w),\n        x_label(w),\n        y_label(w),\n        click_x(-1),\n        click_y(-1)\n    {\n        set_draggable_area(rectangle(0,0,500,500));\n\n\n        x_label.set_text(\"x: \");\n        y_label.set_text(\"y: \");\n        nr.set_name(\"mouse position\");\n\n\n        x_label.set_pos(offset,offset);\n        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);\n\n        nr.wrap_around(x_label.get_rect() + y_label.get_rect());\n        rect = nr.get_rect();\n\n        set_z_order(2000000000);\n        x_label.set_z_order(2000000001);\n        y_label.set_z_order(2000000001);\n        nr.set_z_order(2000000001);\n\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    mouse_tracker::\n    ~mouse_tracker(\n    )\n    { \n        disable_events(); \n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        nr.set_main_font(f);\n        x_label.set_main_font(f);\n        y_label.set_main_font(f);\n        mfont = f;\n        nr.wrap_around(x_label.get_rect() + y_label.get_rect());\n        rect = nr.get_rect();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        draggable::set_pos(x,y);\n        nr.set_pos(x,y);\n        x_label.set_pos(rect.left()+offset,rect.top()+offset);\n        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    show (\n    )\n    {\n        draggable::show();\n        nr.show();\n        x_label.show();\n        y_label.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    hide (\n    )\n    {\n        draggable::hide();\n        nr.hide();\n        x_label.hide();\n        y_label.hide();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    enable (\n    )\n    {\n        draggable::enable();\n        nr.enable();\n        x_label.enable();\n        y_label.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    disable (\n    )\n    {\n        draggable::disable();\n        nr.disable();\n        x_label.disable();\n        y_label.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool double_clicked \n    )\n    {\n        draggable::on_mouse_down(btn,state,x,y,double_clicked);\n        if ((state & base_window::SHIFT) && (btn == base_window::LEFT) && enabled && !hidden)\n        {\n            parent.invalidate_rectangle(rectangle(x,y,x,y));\n            parent.invalidate_rectangle(rectangle(click_x,click_y,click_x,click_y));\n            click_x = x;\n            click_y = y;\n\n            y_label.set_text(\"y: 0\");\n            x_label.set_text(\"x: 0\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (!hidden && enabled)\n        {\n            parent.invalidate_rectangle(rect);\n            draggable::on_mouse_move(state,x,y);\n\n            long dx = 0;\n            long dy = 0;\n            if (click_x != -1)\n                dx = click_x;\n            if (click_y != -1)\n                dy = click_y;\n\n            sout.str(\"\");\n            sout << \"y: \" << y - dy;\n            y_label.set_text(sout.str());\n\n            sout.str(\"\");\n            sout << \"x: \" << x - dx;\n            x_label.set_text(sout.str());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    on_drag (\n    )\n    {\n        nr.set_pos(rect.left(),rect.top());\n        x_label.set_pos(rect.left()+offset,rect.top()+offset);\n        y_label.set_pos(x_label.get_rect().left(), x_label.get_rect().bottom()+3);\n\n        long x = 0;\n        long y = 0;\n        if (click_x != -1)\n            x = click_x;\n        if (click_y != -1)\n            y = click_y;\n\n        sout.str(\"\");\n        sout << \"y: \" << lasty - y;\n        y_label.set_text(sout.str());\n\n        sout.str(\"\");\n        sout << \"x: \" << lastx - x;\n        x_label.set_text(sout.str());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void mouse_tracker::\n    draw (\n        const canvas& c\n    ) const \n    { \n        fill_rect(c, rect,rgb_pixel(212,208,200));\n        draw_pixel(c, point(click_x,click_y),rgb_pixel(255,0,0));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class list_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace list_box_helper{\n    template <typename S>\n    list_box<S>::\n    list_box(  \n        drawable_window& w\n    ) : \n        scrollable_region(w,MOUSE_WHEEL|MOUSE_CLICK),\n        ms_enabled(false),\n        last_selected(0)\n    {\n        set_vertical_scroll_increment(mfont->height());\n        set_horizontal_scroll_increment(mfont->height());\n\n        style.reset(new list_box_style_default());\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    list_box<S>::\n    ~list_box(\n    )\n    {\n        disable_events();\n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        // recompute the sizes of all the items\n        for (unsigned long i = 0; i < items.size(); ++i)\n        {\n            mfont->compute_size(items[i].name,items[i].width, items[i].height);\n        }\n        set_vertical_scroll_increment(mfont->height());\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    bool list_box<S>::\n    is_selected (\n        unsigned long index\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( index < size() ,\n                \"\\tbool list_box::is_selected(index)\"\n                << \"\\n\\tindex:  \" << index \n                << \"\\n\\tsize(): \" << size() );\n\n        return items[index].is_selected;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    select (\n        unsigned long index \n    )\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( index < size() ,\n                \"\\tvoid list_box::select(index)\"\n                << \"\\n\\tindex:  \" << index \n                << \"\\n\\tsize(): \" << size() );\n\n        last_selected = index;\n        items[index].is_selected = true;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    unselect (\n        unsigned long index \n    )\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( index < size() ,\n                \"\\tvoid list_box::unselect(index)\"\n                << \"\\n\\tindex:  \" << index \n                << \"\\n\\tsize(): \" << size() );\n        items[index].is_selected = false;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const S& list_box<S>::operator [] (\n        unsigned long index\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( index < size() ,\n                \"\\tconst std::string& list_box::operator[](index)\"\n                << \"\\n\\tindex:  \" << index \n                << \"\\n\\tsize(): \" << size() );\n        return items[index].name;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    bool list_box<S>::\n    multiple_select_enabled (\n    ) const\n    {\n        auto_mutex M(m);\n        return ms_enabled;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    enable_multiple_select (\n    ) \n    {\n        auto_mutex M(m);\n        ms_enabled = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    disable_multiple_select (\n    )\n    {\n        auto_mutex M(m);\n        ms_enabled = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    bool list_box<S>::\n    at_start (\n    ) const\n    {\n        auto_mutex M(m);\n        return items.at_start();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    reset (\n    ) const\n    {\n        auto_mutex M(m);\n        items.reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    bool list_box<S>::\n    current_element_valid (\n    ) const\n    {\n        auto_mutex M(m);\n        return items.current_element_valid();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const S &list_box<S>::\n    element (\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( current_element_valid() ,\n                \"\\tconst std::string& list_box::element()\"\n                 );\n        return items.element().name;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const S &list_box<S>::\n    element (\n    )\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( current_element_valid() ,\n                \"\\tconst std::string& list_box::element()\"\n                 );\n        return items.element().name;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    bool list_box<S>::\n    move_next (\n    ) const\n    {\n        auto_mutex M(m);\n        return items.move_next();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    size_t list_box<S>::\n    size (\n    ) const\n    {\n        auto_mutex M(m);\n        return items.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    draw (\n        const canvas& c\n    ) const\n    {\n        scrollable_region::draw(c);\n\n        rectangle area = display_rect().intersect(c);\n        if (area.is_empty())\n            return;\n\n        style->draw_list_box_background(c, display_rect(), enabled);\n\n        long y = total_rect().top();\n        for (unsigned long i = 0; i < items.size(); ++i)\n        {\n            if (y+(long)items[i].height <= area.top())\n            {\n                y += items[i].height;\n                continue;\n            }\n\n            rectangle r(total_rect().left(), y, display_rect().right(), y+items[i].height-1);\n\n            style->draw_list_box_item(c,r, display_rect(), enabled, *mfont, items[i].name, items[i].is_selected);\n\n\n            y += items[i].height;\n\n            if (y > area.bottom())\n                break;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    void list_box<S>::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool is_double_click\n    )\n    {\n        if (display_rect().contains(x,y) && btn == base_window::LEFT && enabled && !hidden )\n        {\n            if ( ms_enabled == false || \n                 ((!(state&base_window::CONTROL)) && !(state&base_window::SHIFT)))\n            {\n                items.reset();\n                while (items.move_next())\n                {\n                    items.element().is_selected = false;\n                }\n            }\n\n            y -= total_rect().top();\n            long h = 0;\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                h += items[i].height;\n                if (h >= y)\n                {\n                    if (ms_enabled)\n                    {\n                        if (state&base_window::CONTROL)\n                        {\n                            items[i].is_selected = !items[i].is_selected;\n                            if (items[i].is_selected)\n                                last_selected = i;\n                        }\n                        else if (state&base_window::SHIFT)\n                        {\n                            // we want to select everything between (and including) the\n                            // current thing clicked and last_selected.\n                            const unsigned long first = std::min(i,last_selected);\n                            const unsigned long last = std::max(i,last_selected);\n                            for (unsigned long j = first; j <= last; ++j)\n                                items[j].is_selected = true;\n                        }\n                        else\n                        {\n                            items[i].is_selected = true;\n                            last_selected = i;\n                            if (is_double_click && event_handler.is_set())\n                                event_handler(i);\n                            else if (single_click_event_handler.is_set())\n                                single_click_event_handler(i);\n                        }\n                    }\n                    else\n                    {\n                        items[i].is_selected = true;\n                        last_selected = i;\n                        if (is_double_click && event_handler.is_set())\n                            event_handler(i);\n                        else if (single_click_event_handler.is_set())\n                            single_click_event_handler(i);\n                    }\n\n                    break;\n                }\n            }\n\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    unsigned long list_box<S>::\n    get_selected (\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( multiple_select_enabled() == false,\n                \"\\tunsigned long list_box::get_selected()\"\n                 );\n        for (unsigned long i = 0; i < items.size(); ++i)\n        {\n            if (items[i].is_selected)\n                return i;\n        }\n        return items.size();\n    }\n// ----------------------------------------------------------------------------------------\n\n   // making instance of template\n   template class list_box<std::string>;\n   template class list_box<std::wstring>;\n   template class list_box<dlib::ustring>;\n   }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function message_box()  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace message_box_helper\n    {\n        void box_win::\n        initialize (\n        )\n        {\n            msg.set_pos(20,20);\n            msg.set_text(message);\n            rectangle msg_rect = msg.get_rect();\n            btn_ok.set_name(\"OK\");\n            btn_ok.set_size(60,btn_ok.height());\n            if (msg_rect.width() >= 60)\n                btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15);\n            else\n                btn_ok.set_pos(20,msg_rect.bottom()+15);\n            btn_ok.set_click_handler(*this,&box_win::on_click);\n\n            rectangle size = btn_ok.get_rect() + msg_rect;\n            set_size(size.right()+20,size.bottom()+20);\n\n\n            show();\n            set_title(title);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        box_win::\n        box_win (\n            const std::string& title_,\n            const std::string& message_\n        ) : \n            drawable_window(false),\n            title(convert_mbstring_to_wstring(title_)),\n            message(convert_mbstring_to_wstring(message_)),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        box_win::\n        box_win (\n            const std::wstring& title_,\n            const std::wstring& message_\n        ) : \n            drawable_window(false),\n            title(title_),\n            message(message_),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        box_win::\n        box_win (\n            const dlib::ustring& title_,\n            const dlib::ustring& message_\n        ) : \n            drawable_window(false),\n            title(convert_utf32_to_wstring(title_)),\n            message(convert_utf32_to_wstring(message_)),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        box_win::\n        ~box_win (\n        )\n        {\n            close_window();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        deleter_thread (\n            void* param\n        )\n        {\n            // The point of this extra event_handler stuff is to allow the user\n            // to end the program from within the callback.  So we want to destroy the \n            // window *before* we call their callback.\n            box_win& w = *static_cast<box_win*>(param);\n            w.close_window();\n            any_function<void()> event_handler(w.event_handler);\n            delete &w;\n            if (event_handler.is_set())\n                event_handler(); \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_click (\n        )\n        {\n            hide();\n            create_new_thread(&deleter_thread,this);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        base_window::on_close_return_code box_win::\n        on_window_close (\n        )\n        {\n            // The point of this extra event_handler stuff is to allow the user\n            // to end the program within the callback.  So we want to destroy the \n            // window *before* we call their callback. \n            any_function<void()> event_handler_copy(event_handler);\n            delete this;\n            if (event_handler_copy.is_set())\n                event_handler_copy();\n            return CLOSE_WINDOW;\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        void blocking_box_win::\n        initialize (\n        )\n        {\n            msg.set_pos(20,20);\n            msg.set_text(message);\n            rectangle msg_rect = msg.get_rect();\n            btn_ok.set_name(\"OK\");\n            btn_ok.set_size(60,btn_ok.height());\n            if (msg_rect.width() >= 60)\n                btn_ok.set_pos(msg_rect.width()/2+msg_rect.left()-btn_ok.width()/2,msg_rect.bottom()+15);\n            else\n                btn_ok.set_pos(20,msg_rect.bottom()+15);\n            btn_ok.set_click_handler(*this,&blocking_box_win::on_click);\n\n            rectangle size = btn_ok.get_rect() + msg_rect;\n            set_size(size.right()+20,size.bottom()+20);\n\n\n            set_title(title);\n            show();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        blocking_box_win::\n        blocking_box_win (\n            const std::string& title_,\n            const std::string& message_\n        ) : \n            drawable_window(false),\n            title(convert_mbstring_to_wstring(title_)),\n            message(convert_mbstring_to_wstring(message_)),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        blocking_box_win::\n        blocking_box_win (\n            const std::wstring& title_,\n            const std::wstring& message_\n        ) : \n            drawable_window(false),\n            title(title_),\n            message(message_),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        blocking_box_win::\n        blocking_box_win (\n            const dlib::ustring& title_,\n            const dlib::ustring& message_\n        ) : \n            drawable_window(false),\n            title(convert_utf32_to_wstring(title_)),\n            message(convert_utf32_to_wstring(message_)),\n            msg(*this),\n            btn_ok(*this)\n        {\n            initialize();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        blocking_box_win::\n        ~blocking_box_win (\n        )\n        { \n            close_window(); \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void blocking_box_win::\n        on_click (\n        )\n        {\n            close_window();\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function open_file_box() \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace open_file_box_helper\n    {\n        box_win::\n        box_win (\n            const std::string& title,\n            bool has_text_field \n        ) : \n            lbl_dirs(*this),\n            lbl_files(*this),\n            lbl_file_name(*this),\n            lb_dirs(*this),\n            lb_files(*this),\n            btn_ok(*this),\n            btn_cancel(*this),\n            btn_root(*this),\n            tf_file_name(*this)\n        {\n            if (has_text_field == false)\n            {\n                tf_file_name.hide();\n                lbl_file_name.hide();\n            }\n            else\n            {\n                lbl_file_name.set_text(\"File: \");\n            }\n\n            cur_dir = -1;\n            set_size(500,300);\n\n            lbl_dirs.set_text(\"Directories:\");\n            lbl_files.set_text(\"Files:\");\n            btn_ok.set_name(\"Ok\");\n            btn_cancel.set_name(\"Cancel\");\n            btn_root.set_name(\"/\");\n\n            btn_root.set_click_handler(*this,&box_win::on_root_click);\n            btn_cancel.set_click_handler(*this,&box_win::on_cancel_click);\n            btn_ok.set_click_handler(*this,&box_win::on_open_click);\n            lb_dirs.set_double_click_handler(*this,&box_win::on_dirs_click);\n            lb_files.set_click_handler(*this,&box_win::on_files_click);\n            lb_files.set_double_click_handler(*this,&box_win::on_files_double_click);\n\n\n            btn_root.set_pos(5,5);\n\n            set_sizes();\n            set_title(title);\n\n            on_root_click();\n\n            // make it so that the file box starts out in our current working\n            // directory\n            std::string full_name(get_current_dir());\n\n            while (full_name.size() > 0)\n            {\n                std::string::size_type pos = full_name.find_first_of(\"\\\\/\");\n                std::string left(full_name.substr(0,pos));\n                if (pos != std::string::npos)\n                    full_name = full_name.substr(pos+1);\n                else\n                    full_name.clear();\n\n                if (left.size() > 0)\n                    enter_folder(left); \n            }\n\n\n            show();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        box_win::\n        ~box_win (\n        )\n        {\n            close_window();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        set_sizes(\n        )\n        {\n            unsigned long width, height;\n            get_size(width,height);\n\n\n            if (lbl_file_name.is_hidden())\n            {\n                lbl_dirs.set_pos(0,btn_root.bottom()+5);\n                lb_dirs.set_pos(0,lbl_dirs.bottom());\n                lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10);\n\n                lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5);\n                lb_files.set_pos(lb_dirs.right(),lbl_files.bottom());\n                lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10);\n\n                btn_ok.set_pos(width - btn_ok.width()-25,lb_files.bottom()+5);\n                btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,lb_files.bottom()+5);\n            }\n            else\n            {\n\n                lbl_dirs.set_pos(0,btn_root.bottom()+5);\n                lb_dirs.set_pos(0,lbl_dirs.bottom());\n                lb_dirs.set_size(width/2,height-lb_dirs.top()-btn_cancel.height()-10-tf_file_name.height());\n\n                lbl_files.set_pos(lb_dirs.right(),btn_root.bottom()+5);\n                lb_files.set_pos(lb_dirs.right(),lbl_files.bottom());\n                lb_files.set_size(width-lb_files.left(),height-lb_files.top()-btn_cancel.height()-10-tf_file_name.height());\n\n                lbl_file_name.set_pos(lb_files.left(), lb_files.bottom()+8);\n                tf_file_name.set_pos(lbl_file_name.right(), lb_files.bottom()+5);\n                tf_file_name.set_width(width-tf_file_name.left()-5);\n\n                btn_ok.set_pos(width - btn_ok.width()-25,tf_file_name.bottom()+5);\n                btn_cancel.set_pos(btn_ok.left() - btn_cancel.width()-5,tf_file_name.bottom()+5);\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_window_resized (\n        )\n        {\n            set_sizes();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        deleter_thread (\n        ) \n        {  \n            close_window();\n            delete this; \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        enter_folder (\n            const std::string& folder_name\n        )\n        {\n            if (btn_root.is_checked())\n                btn_root.set_unchecked();\n            if (cur_dir != -1)\n                sob[cur_dir]->set_unchecked();\n\n\n            const std::string old_path = path;\n            const long old_cur_dir = cur_dir;\n\n            std::unique_ptr<toggle_button> new_btn(new toggle_button(*this));\n            new_btn->set_name(folder_name);\n            new_btn->set_click_handler(*this,&box_win::on_path_button_click);\n\n            // remove any path buttons that won't be part of the path anymore\n            if (sob.size())\n            {\n                while (sob.size() > (unsigned long)(cur_dir+1))\n                {\n                    std::unique_ptr<toggle_button> junk;\n                    sob.remove(cur_dir+1,junk);\n                }\n            }\n\n            if (sob.size())\n                new_btn->set_pos(sob[sob.size()-1]->right()+5,sob[sob.size()-1]->top());\n            else\n                new_btn->set_pos(btn_root.right()+5,btn_root.top());\n\n            cur_dir = sob.size();\n            sob.add(sob.size(),new_btn);\n\n            path += folder_name + directory::get_separator();\n            if (set_dir(prefix + path) == false)\n            {\n                sob.remove(sob.size()-1,new_btn);\n                path = old_path;\n                cur_dir = old_cur_dir;\n            }\n            else\n            {\n\n                sob[cur_dir]->set_checked();\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_dirs_click (\n            unsigned long idx\n        )\n        {\n            enter_folder(lb_dirs[idx]);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_files_click (\n            unsigned long idx\n        )\n        {\n            if (tf_file_name.is_hidden() == false)\n            {\n                tf_file_name.set_text(lb_files[idx]);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_files_double_click (\n            unsigned long \n        )\n        {\n            on_open_click();\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_cancel_click (\n        )\n        {\n            hide();\n            create_new_thread<box_win,&box_win::deleter_thread>(*this);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_open_click (\n        )\n        {\n            if (lb_files.get_selected() != lb_files.size() || tf_file_name.text().size() > 0)\n            {\n                if (event_handler.is_set())\n                {\n                    if (tf_file_name.is_hidden())\n                        event_handler(prefix + path + lb_files[lb_files.get_selected()]);\n                    else if (tf_file_name.text().size() > 0)\n                        event_handler(prefix + path + tf_file_name.text());\n                }\n                hide();\n                create_new_thread<box_win,&box_win::deleter_thread>(*this);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_path_button_click (\n            toggle_button& btn\n        )\n        {\n            if (btn_root.is_checked())\n                btn_root.set_unchecked();\n            if (cur_dir != -1)\n                sob[cur_dir]->set_unchecked();\n            std::string new_path;\n\n            for (unsigned long i = 0; i < sob.size(); ++i)\n            {\n                new_path += sob[i]->name() + directory::get_separator();\n                if (sob[i].get() == &btn)\n                {\n                    cur_dir = i;\n                    sob[i]->set_checked();\n                    break;\n                }\n            }\n            if (path != new_path)\n            {\n                path = new_path;\n                set_dir(prefix+path);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        struct case_insensitive_compare\n        {\n            bool operator() (\n                const std::string& a,\n                const std::string& b\n            ) const\n            {\n                std::string::size_type i, size;\n                size = std::min(a.size(),b.size());\n                for (i = 0; i < size; ++i)\n                {\n                    if (std::tolower(a[i]) < std::tolower(b[i]))\n                        return true;\n                    else if (std::tolower(a[i]) > std::tolower(b[i]))\n                        return false;\n                }\n                if (a.size() < b.size())\n                    return true;\n                else\n                    return false;\n            }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        bool box_win::\n        set_dir (\n            const std::string& dir\n        )\n        {\n            try\n            {\n                directory d(dir);\n                queue<directory>::kernel_1a_c qod;\n                queue<file>::kernel_1a_c qof;\n                queue<std::string>::sort_1a_c qos;\n                d.get_dirs(qod);\n                d.get_files(qof);\n\n                qod.reset();\n                while (qod.move_next())\n                {\n                    std::string temp = qod.element().name();\n                    qos.enqueue(temp);\n                }\n                qos.sort(case_insensitive_compare());\n                lb_dirs.load(qos);\n                qos.clear();\n\n                qof.reset();\n                while (qof.move_next())\n                {\n                    std::string temp = qof.element().name();\n                    qos.enqueue(temp);\n                }\n                qos.sort(case_insensitive_compare());\n                lb_files.load(qos);\n                return true;\n            }\n            catch (directory::listing_error& )\n            {\n                return false;\n            }\n            catch (directory::dir_not_found&)\n            {\n                return false;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void box_win::\n        on_root_click (\n        )\n        {\n            btn_root.set_checked();\n            if (cur_dir != -1)\n                sob[cur_dir]->set_unchecked();\n\n            queue<directory>::kernel_1a_c qod, qod2;\n            queue<file>::kernel_1a_c qof;\n            queue<std::string>::sort_1a_c qos;\n            get_filesystem_roots(qod);\n            path.clear();\n            cur_dir = -1;\n            if (qod.size() == 1)\n            {\n                qod.current().get_files(qof);\n                qod.current().get_dirs(qod2);\n                prefix = qod.current().full_name();\n\n                qod2.reset();\n                while (qod2.move_next())\n                {\n                    std::string temp = qod2.element().name();\n                    qos.enqueue(temp);\n                }\n                qos.sort(case_insensitive_compare());\n                lb_dirs.load(qos);\n                qos.clear();\n\n                qof.reset();\n                while (qof.move_next())\n                {\n                    std::string temp = qof.element().name();\n                    qos.enqueue(temp);\n                }\n                qos.sort(case_insensitive_compare());\n                lb_files.load(qos);\n            }\n            else\n            {\n                prefix.clear();\n                qod.reset();\n                while (qod.move_next())\n                {\n                    std::string temp = qod.element().full_name();\n                    temp = temp.substr(0,temp.size()-1);\n                    qos.enqueue(temp);\n                }\n                qos.sort(case_insensitive_compare());\n                lb_dirs.load(qos);\n                qos.clear();\n                lb_files.load(qos);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        base_window::on_close_return_code box_win::\n        on_window_close (\n        )\n        {\n            delete this;\n            return CLOSE_WINDOW;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class menu_bar\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    menu_bar::\n    menu_bar(\n        drawable_window& w\n    ) : \n        drawable(w, 0xFFFF), // listen for all events\n        open_menu(0)\n    {\n        adjust_position();\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    menu_bar::\n    ~menu_bar()\n    { \n        disable_events(); \n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        adjust_position();\n        compute_menu_geometry();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    set_number_of_menus (\n        unsigned long num\n    )\n    {\n        auto_mutex M(m);\n        menus.set_max_size(num);\n        menus.set_size(num);\n        open_menu = menus.size();\n        compute_menu_geometry();\n\n        for (unsigned long i = 0; i < menus.size(); ++i)\n        {\n            menus[i].menu.set_on_hide_handler(*this,&menu_bar::on_popup_hide);\n        }\n\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long menu_bar::\n    number_of_menus (\n    ) const\n    {\n        auto_mutex M(m);\n        return menus.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    set_menu_name (\n        unsigned long idx,\n        const std::string name,\n        char underline_ch \n    )\n    {\n        set_menu_name(idx, convert_to_utf32(name), underline_ch);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    set_menu_name (\n        unsigned long idx,\n        const std::wstring name,\n        char underline_ch \n    )\n    {\n        set_menu_name(idx, convert_to_utf32(name), underline_ch);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    set_menu_name (\n        unsigned long idx,\n        const dlib::ustring name,\n        char underline_ch \n    )\n    {\n        DLIB_ASSERT ( idx < number_of_menus() ,\n                      \"\\tvoid menu_bar::set_menu_name()\"\n                      << \"\\n\\tidx:               \" << idx\n                      << \"\\n\\tnumber_of_menus(): \" << number_of_menus() \n        );\n        auto_mutex M(m);\n        menus[idx].name = name.c_str();\n        menus[idx].underline_pos = name.find_first_of(underline_ch);\n        compute_menu_geometry();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string menu_bar::\n    menu_name (\n        unsigned long idx\n    ) const\n    {\n        return convert_wstring_to_mbstring(menu_wname(idx));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::wstring menu_bar::\n    menu_wname (\n        unsigned long idx\n    ) const\n    {\n        return convert_utf32_to_wstring(menu_uname(idx));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const dlib::ustring menu_bar::\n    menu_uname (\n        unsigned long idx\n    ) const\n    {\n        DLIB_ASSERT ( idx < number_of_menus() ,\n                      \"\\tstd::string menu_bar::menu_name()\"\n                      << \"\\n\\tidx:               \" << idx\n                      << \"\\n\\tnumber_of_menus(): \" << number_of_menus() \n        );\n        auto_mutex M(m);\n        return menus[idx].name.c_str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    popup_menu& menu_bar::\n    menu (\n        unsigned long idx\n    )\n    {\n        DLIB_ASSERT ( idx < number_of_menus() ,\n                      \"\\tpopup_menu& menu_bar::menu()\"\n                      << \"\\n\\tidx:               \" << idx\n                      << \"\\n\\tnumber_of_menus(): \" << number_of_menus() \n        );\n        auto_mutex M(m);\n        return menus[idx].menu;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const popup_menu& menu_bar::\n    menu (\n        unsigned long idx\n    ) const\n    {\n        DLIB_ASSERT ( idx < number_of_menus() ,\n                      \"\\tconst popup_menu& menu_bar::menu()\"\n                      << \"\\n\\tidx:               \" << idx\n                      << \"\\n\\tnumber_of_menus(): \" << number_of_menus() \n        );\n        auto_mutex M(m);\n        return menus[idx].menu;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_window_resized (\n    )\n    {\n        adjust_position();\n        hide_menu();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    draw (\n        const canvas& c\n    ) const\n    {\n        rectangle area(rect.intersect(c));\n        if (area.is_empty())\n            return;\n\n        const unsigned char opacity = 40;\n        fill_rect_with_vertical_gradient(c, rect,rgb_alpha_pixel(255,255,255,opacity),\n                                         rgb_alpha_pixel(0,0,0,opacity));\n\n        // first draw the border between the menu and the rest of the window\n        draw_line(c, point(rect.left(),rect.bottom()-1), \n                  point(rect.right(),rect.bottom()-1), 100);\n        draw_line(c, point(rect.left(),rect.bottom()), \n                  point(rect.right(),rect.bottom()), 255);\n\n        // now draw all the menu buttons\n        for (unsigned long i = 0; i < menus.size(); ++i)\n        {\n            mfont->draw_string(c,menus[i].rect, menus[i].name );\n            if (menus[i].underline_p1 != menus[i].underline_p2)\n                draw_line(c, menus[i].underline_p1, menus[i].underline_p2);\n\n            if (open_menu == i)\n            {\n                fill_rect_with_vertical_gradient(c, menus[i].bgrect,rgb_alpha_pixel(255,255,0,40),  rgb_alpha_pixel(0,0,0,40));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_window_moved (\n    )\n    {\n        hide_menu();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_focus_lost (\n    )\n    {\n        hide_menu();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long ,\n        long x,\n        long y,\n        bool \n    )\n    {\n\n        if (rect.contains(x,y) == false || btn != (unsigned long)base_window::LEFT)\n        {\n            hide_menu();\n            return;\n        }\n\n        unsigned long old_menu = menus.size();\n\n        // if a menu is currently open then save its index\n        if (open_menu != menus.size())\n        {\n            old_menu = open_menu;\n            hide_menu();\n        }\n\n        // figure out which menu should be open if any\n        for (unsigned long i = 0; i < menus.size(); ++i)\n        {\n            if (menus[i].bgrect.contains(x,y))\n            {\n                if (old_menu != i)\n                    show_menu(i);\n\n                break;\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_mouse_move (\n        unsigned long ,\n        long x,\n        long y\n    )\n    {\n        // if the mouse is over the menu_bar and some menu is currently open\n        if (rect.contains(x,y) && open_menu != menus.size())\n        {\n            // if the mouse is still in the same rectangle then don't do anything\n            if (menus[open_menu].bgrect.contains(x,y) == false)\n            {\n                // figure out which menu should be instead   \n                for (unsigned long i = 0; i < menus.size(); ++i)\n                {\n                    if (menus[i].bgrect.contains(x,y))\n                    {\n                        show_menu(i);\n                        break;\n                    }\n                }\n\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        if (state&base_window::KBD_MOD_ALT)\n        {\n            // check if the key matches any of our underlined keys\n            for (unsigned long i = 0; i < menus.size(); ++i)\n            {\n                // if we have found a matching key\n                if (is_printable && \n                    menus[i].underline_pos != std::string::npos &&\n                    std::tolower(menus[i].name[menus[i].underline_pos]) == std::tolower(key))\n                {\n                    show_menu(i);\n                    menus[open_menu].menu.select_first_item();\n                    return;\n                }\n            }\n        }\n\n        if (open_menu != menus.size())\n        {\n            unsigned long i = open_menu;\n            // if the submenu doesn't use this key for something then we will\n            if (menus[open_menu].menu.forwarded_on_keydown(key,is_printable,state) == false)\n            {\n                if (key == base_window::KEY_LEFT)\n                {\n                    i = (i+menus.size()-1)%menus.size();\n                    show_menu(i);\n                    menus[open_menu].menu.select_first_item();\n                }\n                else if (key == base_window::KEY_RIGHT)\n                {\n                    i = (i+1)%menus.size();\n                    show_menu(i);\n                    menus[open_menu].menu.select_first_item();\n                }\n                else if (key == base_window::KEY_ESC)\n                {\n                    hide_menu();\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    show_menu (\n        unsigned long i\n    )\n    {\n        rectangle temp;\n\n        // menu already open so do nothing\n        if (i == open_menu)\n            return;\n\n        // if a menu is currently open\n        if (open_menu != menus.size())\n        {\n            menus[open_menu].menu.hide();\n            temp = menus[open_menu].bgrect;\n        }\n\n        // display the new menu\n        open_menu = i;\n        long wx, wy;\n        parent.get_pos(wx,wy);\n        wx += menus[i].bgrect.left();\n        wy += menus[i].bgrect.bottom()+1;\n        menus[i].menu.set_pos(wx,wy);\n        menus[i].menu.show();\n        parent.invalidate_rectangle(menus[i].bgrect+temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    hide_menu (\n    )\n    {\n        // if a menu is currently open\n        if (open_menu != menus.size())\n        {\n            menus[open_menu].menu.hide();\n            parent.invalidate_rectangle(menus[open_menu].bgrect);\n            open_menu = menus.size();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    on_popup_hide (\n    )\n    {\n        // if a menu is currently open\n        if (open_menu != menus.size())\n        {\n            parent.invalidate_rectangle(menus[open_menu].bgrect);\n            open_menu = menus.size();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    compute_menu_geometry (\n    )\n    {\n        long x = 7;\n        long bg_x = 0;\n        for (unsigned long i = 0; i < menus.size(); ++i)\n        {\n            // compute the locations of the text rectangles\n            menus[i].rect.set_top(5);\n            menus[i].rect.set_left(x);\n            menus[i].rect.set_bottom(rect.bottom()-2);\n\n            unsigned long width, height;\n            mfont->compute_size(menus[i].name,width,height);\n            menus[i].rect = resize_rect_width(menus[i].rect, width);\n            x = menus[i].rect.right()+10;\n\n            menus[i].bgrect.set_top(0);\n            menus[i].bgrect.set_left(bg_x);\n            menus[i].bgrect.set_bottom(rect.bottom()-2);\n            menus[i].bgrect.set_right(x-5);\n            bg_x = menus[i].bgrect.right()+1;\n\n            if (menus[i].underline_pos != std::string::npos)\n            {\n                // now compute the location of the underline bar\n                rectangle r1 = mfont->compute_cursor_rect(\n                    menus[i].rect, \n                    menus[i].name,\n                    menus[i].underline_pos);\n\n                rectangle r2 = mfont->compute_cursor_rect(\n                    menus[i].rect, \n                    menus[i].name,\n                    menus[i].underline_pos+1);\n\n                menus[i].underline_p1.x() = r1.left()+1;\n                menus[i].underline_p2.x() = r2.left()-1;\n                menus[i].underline_p1.y() = r1.bottom()-mfont->height()+mfont->ascender()+2;\n                menus[i].underline_p2.y() = r2.bottom()-mfont->height()+mfont->ascender()+2;\n            }\n            else\n            {\n                // there is no underline in this case\n                menus[i].underline_p1 = menus[i].underline_p2;\n            }\n\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void menu_bar::\n    adjust_position (\n    )\n    {\n        unsigned long width, height;\n        rectangle old(rect);\n        parent.get_size(width,height);\n        rect.set_left(0);\n        rect.set_top(0);\n        rect = resize_rect(rect,width,mfont->height()+10);\n        parent.invalidate_rectangle(old+rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// class text_grid\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    text_grid::\n    text_grid (\n        drawable_window& w\n    ) :\n        scrollable_region(w, KEYBOARD_EVENTS | MOUSE_CLICK | FOCUS_EVENTS ),\n        has_focus(false),\n        cursor_timer(*this,&text_grid::timer_action),\n        border_color_(128,128,128)\n    {\n\n        cursor_timer.set_delay_time(500);\n        set_vertical_scroll_increment(10);\n        set_horizontal_scroll_increment(10);\n        enable_events();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    text_grid::\n    ~text_grid (\n    )\n    {\n        // Disable all further events for this drawable object.  We have to do this \n        // because we don't want draw() events coming to this object while or after \n        // it has been destructed.\n        disable_events();\n\n        // wait for the timer to stop doing its thing\n        cursor_timer.stop_and_wait();\n        // Tell the parent window to redraw its area that previously contained this\n        // drawable object.\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_grid_size (\n        unsigned long rows,\n        unsigned long cols\n    )\n    {\n        auto_mutex M(m);\n        row_height.set_max_size(rows);\n        row_height.set_size(rows);\n\n        col_width.set_max_size(cols);\n        col_width.set_size(cols);\n\n        grid.set_size(rows,cols);\n\n        for (unsigned long i = 0; i < row_height.size(); ++i)\n            row_height[i] = (mfont->height()*3)/2;\n        for (unsigned long i = 0; i < col_width.size(); ++i)\n            col_width[i] = mfont->height()*5;\n\n        compute_total_rect();\n        compute_bg_rects();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long text_grid::\n    number_of_columns (\n    ) const\n    {\n        auto_mutex M(m);\n        return grid.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long text_grid::\n    number_of_rows (\n    ) const\n    {\n        auto_mutex M(m);\n        return grid.nr();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    int text_grid::\n    next_free_user_event_number (\n    ) const\n    {\n        return scrollable_region::next_free_user_event_number()+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rgb_pixel text_grid::\n    border_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return border_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_border_color (\n        rgb_pixel color\n    )\n    {\n        auto_mutex M(m);\n        border_color_ = color;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string text_grid::\n    text (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        return convert_wstring_to_mbstring(wtext(row, col));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::wstring text_grid::\n    wtext (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        return convert_utf32_to_wstring(utext(row, col));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const dlib::ustring text_grid::\n    utext (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tconst std::string text_grid::text(row,col)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        return grid[row][col].text.c_str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_text (\n        unsigned long row,\n        unsigned long col,\n        const std::string& str\n    ) \n    {\n        set_text(row, col, convert_to_utf32(str));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_text (\n        unsigned long row,\n        unsigned long col,\n        const std::wstring& str\n    ) \n    {\n        set_text(row, col, convert_to_utf32(str));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_text (\n        unsigned long row,\n        unsigned long col,\n        const dlib::ustring& str\n    ) \n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tvoid text_grid::set_text(row,col)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        grid[row][col].text = str.c_str();\n        parent.invalidate_rectangle(get_text_rect(row,col));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_grid::\n    text_color (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tconst rgb_pixel text_grid::text_color(row,col)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        return grid[row][col].text_color;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_text_color (\n        unsigned long row,\n        unsigned long col,\n        const rgb_pixel color\n    ) \n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tvoid text_grid::set_text_color(row,col,color)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        grid[row][col].text_color = color;\n        parent.invalidate_rectangle(get_text_rect(row,col));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_grid::\n    background_color (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tconst rgb_pixel text_grid::background_color(row,col,color)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        return grid[row][col].bg_color;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_background_color (\n        unsigned long row,\n        unsigned long col,\n        const rgb_pixel color\n    ) \n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tvoid text_grid::set_background_color(row,col,color)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        grid[row][col].bg_color = color;\n        parent.invalidate_rectangle(get_bg_rect(row,col));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool text_grid::\n    is_editable (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tbool text_grid::is_editable(row,col)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\tthis:             \" << this\n        );\n        return grid[row][col].is_editable;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_editable (\n        unsigned long row,\n        unsigned long col,\n        bool editable\n    ) \n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows()  && col < number_of_columns(),\n                      \"\\tvoid text_grid::set_editable(row,col,editable)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\teditable:         \" << editable \n                      << \"\\n\\tthis:             \" << this\n        );\n        grid[row][col].is_editable = editable;\n        if (has_focus && active_row == static_cast<long>(row) && active_col == static_cast<long>(col))\n        {\n            drop_input_focus();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_column_width (\n        unsigned long col,\n        unsigned long width\n    )\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( col < number_of_columns(),\n                      \"\\tvoid text_grid::set_column_width(col,width)\"\n                      << \"\\n\\tcol:              \" << col \n                      << \"\\n\\tnumber_of_columns(): \" << number_of_columns() \n                      << \"\\n\\twidth:            \" << width \n                      << \"\\n\\tthis:             \" << this\n        );\n        col_width[col] = width;\n        compute_total_rect();\n        compute_bg_rects();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    set_row_height (\n        unsigned long row,\n        unsigned long height \n    )\n    {\n        auto_mutex M(m);\n        DLIB_ASSERT ( row < number_of_rows() ,\n                      \"\\tvoid text_grid::set_row_height(row,height)\"\n                      << \"\\n\\trow:              \" << row \n                      << \"\\n\\tnumber_of_rows(): \" << number_of_rows() \n                      << \"\\n\\theight:           \" << height \n                      << \"\\n\\tthis:             \" << this\n        );\n        row_height[row] = height;\n        compute_total_rect();\n        compute_bg_rects();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    disable (\n    ) \n    {\n        auto_mutex M(m);\n        scrollable_region::disable();\n        drop_input_focus();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    hide (\n    ) \n    {\n        auto_mutex M(m);\n        scrollable_region::hide();\n        drop_input_focus();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    on_user_event (\n        int num\n    )\n    {\n        // ignore this user event if it isn't for us\n        if (num != scrollable_region::next_free_user_event_number())\n            return;\n\n        if (has_focus && !recent_cursor_move && enabled && !hidden)\n        {\n            show_cursor = !show_cursor;\n            parent.invalidate_rectangle(get_text_rect(active_row,active_col));\n        }\n        recent_cursor_move = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    timer_action (\n    ) \n    { \n        parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    compute_bg_rects (\n    )\n    {\n        // loop over each element in the grid and figure out what its rectangle should be\n        // with respect to the total_rect()\n        point p1, p2;\n        p1.y() = total_rect().top();\n        for (long row = 0; row < grid.nr(); ++row)\n        {\n            p1.x() = total_rect().left();\n            p2.y() = p1.y() + row_height[row]-1;\n            for (long col = 0; col < grid.nc(); ++col)\n            {\n                // if this is the last box in this row make it super wide so that it always\n                // goes to the end of the widget\n                if (col+1 == grid.nc())\n                    p2.x() = 1000000;\n                else\n                    p2.x() = p1.x() + col_width[col]-1;\n\n                // at this point p1 is the upper left corner of this box and p2 is the \n                // lower right corner of the box;\n                rectangle bg_rect(p1);\n                bg_rect += p2;\n\n                grid[row][col].bg_rect = translate_rect(bg_rect, -total_rect().left(), -total_rect().top());\n\n\n                p1.x() += 1 + col_width[col];\n            }\n            p1.y() += 1 + row_height[row];\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    compute_total_rect (\n    )\n    {\n        if (grid.size() == 0)\n        {\n            set_total_rect_size(0,0);\n        }\n        else\n        {\n            unsigned long width = col_width.size()-1;\n            unsigned long height = row_height.size()-1;\n\n            for (unsigned long i = 0; i < col_width.size(); ++i)\n                width += col_width[i];\n            for (unsigned long i = 0; i < row_height.size(); ++i)\n                height += row_height[i];\n\n            set_total_rect_size(width,height);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    on_keydown (\n        unsigned long key,          \n        bool is_printable,\n        unsigned long state\n    )\n    {\n        // ignore this event if we are disabled or hidden\n        if (!enabled || hidden)\n            return;\n\n        if (has_focus)\n        {\n            if (is_printable)\n            {\n                // if the user hit the tab key then jump to the next box\n                if (key == '\\t')\n                {\n                    if (active_col+1 == grid.nc())\n                    {\n                        if (active_row+1 == grid.nr())\n                            move_cursor(0,0,0);\n                        else\n                            move_cursor(active_row+1,0,0);\n                    }\n                    else\n                    {\n                        move_cursor(active_row,active_col+1,0);\n                    }\n                }\n                if (key == '\\n')\n                {\n                    // ignore the enter key\n                }\n                else if (grid[active_row][active_col].is_editable)\n                {\n                    // insert the key the user pressed into the string\n                    grid[active_row][active_col].text.insert(cursor_pos,1,static_cast<char>(key));\n                    move_cursor(active_row,active_col,cursor_pos+1);\n\n                    if (text_modified_handler.is_set())\n                        text_modified_handler(active_row,active_col);\n                }\n            }\n            else if ((state & base_window::KBD_MOD_CONTROL))\n            {\n                if (key == base_window::KEY_LEFT)\n                    move_cursor(active_row,active_col-1,0);\n                else if (key == base_window::KEY_RIGHT)\n                    move_cursor(active_row,active_col+1,0);\n                else if (key == base_window::KEY_UP)\n                    move_cursor(active_row-1,active_col,0);\n                else if (key == base_window::KEY_DOWN)\n                    move_cursor(active_row+1,active_col,0);\n                else if (key == base_window::KEY_END)\n                    move_cursor(active_row,active_col,grid[active_row][active_col].text.size());\n                else if (key == base_window::KEY_HOME)\n                    move_cursor(active_row,active_col,0);\n            }\n            else\n            {\n                if (key == base_window::KEY_LEFT)\n                    move_cursor(active_row,active_col,cursor_pos-1);\n                else if (key == base_window::KEY_RIGHT)\n                    move_cursor(active_row,active_col,cursor_pos+1);\n                else if (key == base_window::KEY_UP)\n                    move_cursor(active_row-1,active_col,0);\n                else if (key == base_window::KEY_DOWN)\n                    move_cursor(active_row+1,active_col,0);\n                else if (key == base_window::KEY_END)\n                    move_cursor(active_row,active_col,grid[active_row][active_col].text.size());\n                else if (key == base_window::KEY_HOME)\n                    move_cursor(active_row,active_col,0);\n                else if (key == base_window::KEY_BACKSPACE)\n                {\n                    if (cursor_pos > 0 && grid[active_row][active_col].is_editable)\n                    {\n                        grid[active_row][active_col].text.erase(\n                            grid[active_row][active_col].text.begin()+cursor_pos-1,\n                            grid[active_row][active_col].text.begin()+cursor_pos);\n                        move_cursor(active_row,active_col,cursor_pos-1);\n\n                        if (text_modified_handler.is_set())\n                            text_modified_handler(active_row,active_col);\n                    }\n                }\n                else if (key == base_window::KEY_DELETE)\n                {\n                    if (cursor_pos < static_cast<long>(grid[active_row][active_col].text.size()) &&\n                        grid[active_row][active_col].is_editable)\n                    {\n                        grid[active_row][active_col].text.erase(\n                            grid[active_row][active_col].text.begin()+cursor_pos);\n                        move_cursor(active_row,active_col,cursor_pos);\n\n                        if (text_modified_handler.is_set())\n                            text_modified_handler(active_row,active_col);\n                    }\n                }\n            }\n        } // if (has_focus)\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool is_double_click\n    )\n    {\n        scrollable_region::on_mouse_down(btn, state, x, y, is_double_click);\n        if (display_rect().contains(x,y) && enabled && !hidden)\n        {\n            // figure out which box this click landed in\n            rectangle hit;\n\n            // find which column we hit\n            unsigned long col = 0;\n            long box_x = total_rect().left();\n            for (unsigned long i = 0; i < col_width.size(); ++i)\n            {\n                if (box_x <= x && (x < box_x+static_cast<long>(col_width[i]) || (i+1 == col_width.size())))\n                {\n                    col = i;\n                    hit.set_left(box_x);\n                    hit.set_right(box_x+col_width[i]-1);\n                    break;\n                }\n                else\n                {\n                    box_x += col_width[i]+1;\n                }\n            }\n\n            // find which row we hit\n            unsigned long row = 0;\n            long box_y = total_rect().top();\n            for (unsigned long i = 0; i < row_height.size(); ++i)\n            {\n                if (box_y <= y && y < box_y+static_cast<long>(row_height[i]))\n                {\n                    row = i;\n                    hit.set_top(box_y);\n                    hit.set_bottom(box_y+row_height[i]-1);\n                    break;\n                }\n                else\n                {\n                    box_y += row_height[i]+1;\n                }\n            }\n\n            // if we hit a box\n            if (hit.is_empty() == false)\n            {\n                move_cursor(row, \n                            col,\n                            mfont->compute_cursor_pos(get_text_rect(row,col), grid[row][col].text, x, y, grid[row][col].first)\n                );\n            }\n            else\n            {\n                drop_input_focus();\n            }\n        }\n        else\n        {\n            drop_input_focus();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y\n    ) \n    {\n        scrollable_region::on_mouse_up(btn, state, x, y);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    on_focus_lost (\n    )\n    {\n        drop_input_focus();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    draw (\n        const canvas& c\n    ) const\n    {\n        scrollable_region::draw(c);\n        rectangle area = c.intersect(display_rect());\n        if (area.is_empty() == true)\n            return;\n\n        if (enabled)\n            fill_rect(c, area, 255); \n\n        // don't do anything if the grid is empty\n        if (grid.size() == 0)\n            return;\n\n        // draw all the vertical lines\n        point p1, p2;\n        p1.x() = p2.x() = total_rect().left();\n        p1.y() = total_rect().top();\n        p2.y() = total_rect().bottom();\n        for (unsigned long i = 0; i < col_width.size()-1; ++i)\n        {\n            p1.x() += col_width[i];\n            p2.x() += col_width[i];\n            if (enabled)\n                draw_line(c,p1,p2,border_color_,area);\n            else\n                draw_line(c,p1,p2,128,area);\n            p1.x() += 1;\n            p2.x() += 1;\n        }\n\n        // draw all the horizontal lines\n        p1.y() = p2.y() = total_rect().top();\n        p1.x() = display_rect().left();\n        p2.x() = display_rect().right();\n        for (unsigned long i = 0; i < row_height.size(); ++i)\n        {\n            p1.y() += row_height[i];\n            p2.y() += row_height[i];\n            if (enabled)\n                draw_line(c,p1,p2,border_color_,area);\n            else\n                draw_line(c,p1,p2,128,area);\n            p1.y() += 1;\n            p2.y() += 1;\n        }\n\n        // draw the backgrounds and text for each box\n        for (long row = 0; row < grid.nr(); ++row)\n        {\n            for (long col = 0; col < grid.nc(); ++col)\n            {\n                rectangle bg_rect(get_bg_rect(row,col));\n\n                rectangle text_rect(get_text_rect(row,col));\n\n                if (enabled)\n                {\n                    fill_rect(c,bg_rect.intersect(area),grid[row][col].bg_color);\n\n                    mfont->draw_string(c,\n                                       text_rect, \n                                       grid[row][col].text, \n                                       grid[row][col].text_color, \n                                       grid[row][col].first, \n                                       std::string::npos, \n                                       area);\n                }\n                else\n                {\n                    mfont->draw_string(c,\n                                       text_rect, \n                                       grid[row][col].text, \n                                       128, \n                                       grid[row][col].first, \n                                       std::string::npos, \n                                       area);\n                }\n\n                // if this box has input focus then draw it with a cursor\n                if (has_focus && active_col == col && active_row == row && show_cursor)\n                {\n                    rectangle cursor_rect = mfont->compute_cursor_rect(text_rect,\n                                                                       grid[row][col].text,\n                                                                       cursor_pos,\n                                                                       grid[row][col].first);\n                    draw_rectangle(c,cursor_rect,0,area);\n                }\n\n            }\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle text_grid::\n    get_text_rect (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        rectangle bg_rect(get_bg_rect(row,col));\n        long padding = (bg_rect.height() - mfont->height())/2 + (bg_rect.height() - mfont->height())%2;\n        if (padding < 0)\n            padding = 0;\n        bg_rect.set_left(bg_rect.left()+padding);\n        bg_rect.set_top(bg_rect.top()+padding);\n        bg_rect.set_right(bg_rect.right()-padding);\n        bg_rect.set_bottom(bg_rect.bottom()-padding);\n        return bg_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle text_grid::\n    get_bg_rect (\n        unsigned long row,\n        unsigned long col\n    ) const\n    {\n        return translate_rect(grid[row][col].bg_rect, total_rect().left(), total_rect().top());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    drop_input_focus (\n    )\n    {\n        if (has_focus)\n        {\n            parent.invalidate_rectangle(get_text_rect(active_row,active_col));\n            has_focus = false;\n            show_cursor = false;\n            cursor_timer.stop();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_grid::\n    move_cursor (\n        long row,\n        long col,\n        long new_cursor_pos\n    )\n    {\n        // don't do anything if the grid is empty\n        if (grid.size() == 0)\n        {\n            return;\n        }\n\n        if (row < 0)\n            row = 0;\n        if (row >= grid.nr())\n            row = grid.nr()-1;\n        if (col < 0)\n            col = 0;\n        if (col >= grid.nc())\n            col = grid.nc()-1;\n\n        if (new_cursor_pos < 0)\n        {\n            if (col == 0)\n            {\n                new_cursor_pos = 0;\n            }\n            else \n            {\n                --col;\n                new_cursor_pos = grid[row][col].text.size();\n            }\n        }\n\n        if (new_cursor_pos > static_cast<long>(grid[row][col].text.size()))\n        {\n            if (col+1 == grid.nc())\n            {\n                new_cursor_pos = grid[row][col].text.size();\n            }\n            else \n            {\n                ++col;\n                new_cursor_pos = 0;\n            }\n        }\n\n        // if some other box had the input focus then redraw it\n        if (has_focus && (active_row != row || active_col != col ))\n        {\n            parent.invalidate_rectangle(get_text_rect(active_row,active_col));\n        }\n\n        if (has_focus == false)\n        {\n            cursor_timer.start();\n        }\n\n        has_focus = true;\n        recent_cursor_move = true;\n        show_cursor = true;\n        active_row = row;\n        active_col = col;\n        cursor_pos = new_cursor_pos;\n\n        // adjust the first character to draw so that the string is displayed well\n        rectangle text_rect(get_text_rect(active_row,active_col));\n        rectangle cursor_rect = mfont->compute_cursor_rect(text_rect,\n                                                           grid[row][col].text,\n                                                           cursor_pos,\n                                                           grid[row][col].first);\n\n        // if the cursor rect is too far to the left of the string\n        if (cursor_pos < static_cast<long>(grid[row][col].first))\n        {\n            if (cursor_pos > 5)\n            {\n                grid[row][col].first = cursor_pos - 5;\n            }\n            else\n            {\n                grid[row][col].first = 0;\n            }\n        }\n        // if the cursor rect is too far to the right of the string\n        else if (cursor_rect.left() > text_rect.right())\n        {\n            long distance = (cursor_rect.left() - text_rect.right()) + text_rect.width()/3;\n            // find the letter that is distance pixels from the start of the string\n            long sum = 0;\n            for (unsigned long i = grid[row][col].first; i < grid[row][col].text.size(); ++i)\n            {\n                sum += (*mfont)[grid[row][col].text[i]].width();\n                if (sum >= distance)\n                {\n                    grid[row][col].first = i;\n                    break;\n                }\n            }\n        }\n\n        scroll_to_rect(get_bg_rect(row,col));\n\n        // redraw our box\n        parent.invalidate_rectangle(text_rect);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // text_field object methods  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    rectangle text_box::\n    get_text_rect (\n    ) const\n    {\n        const unsigned long padding = style->get_padding(*mfont);\n\n        rectangle text_rect;\n        text_rect.set_left(total_rect().left()+padding);\n        text_rect.set_top(total_rect().top()+padding);\n        text_rect.set_right(total_rect().right()-padding);\n        text_rect.set_bottom(total_rect().bottom()-padding);\n        return text_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    enable (\n    )\n    {\n        scrollable_region::enable();\n        right_click_menu.enable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_cut (\n    )\n    {\n        on_copy();\n        on_delete_selected();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_copy (\n    )\n    {\n        if (highlight_start <= highlight_end)\n        {\n            put_on_clipboard(text_.substr(highlight_start, highlight_end-highlight_start+1));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_paste (\n    )\n    {\n        ustring temp_str;\n        get_from_clipboard(temp_str);\n\n\n        if (highlight_start <= highlight_end)\n        {\n            text_ = text_.substr(0,highlight_start) + temp_str +\n                text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n            move_cursor(highlight_start+temp_str.size());\n            highlight_start = 0;\n            highlight_end = -1;\n            parent.invalidate_rectangle(rect);\n            on_no_text_selected();\n\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n        }\n        else\n        {\n            text_ = text_.substr(0,cursor_pos) + temp_str +\n                text_.substr(cursor_pos,text_.size()-cursor_pos);\n            move_cursor(cursor_pos+temp_str.size());\n\n            // send out the text modified event\n            if (temp_str.size() != 0 && text_modified_handler.is_set())\n                text_modified_handler();\n        }\n\n        adjust_total_rect();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_select_all (\n    )\n    {\n        move_cursor(static_cast<long>(text_.size()));\n        highlight_start = 0;\n        highlight_end = static_cast<long>(text_.size()-1);\n        if (highlight_start <= highlight_end)\n            on_text_is_selected();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_delete_selected (\n    )\n    {\n        if (highlight_start <= highlight_end)\n        {\n            text_ = text_.erase(highlight_start,highlight_end-highlight_start+1);\n            move_cursor(highlight_start);\n            highlight_start = 0;\n            highlight_end = -1;\n\n            on_no_text_selected();\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n\n            adjust_total_rect();\n\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_text_is_selected (\n    )\n    {\n        right_click_menu.menu().enable_menu_item(0);\n        right_click_menu.menu().enable_menu_item(1);\n        right_click_menu.menu().enable_menu_item(3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_no_text_selected (\n    )\n    {\n        right_click_menu.menu().disable_menu_item(0);\n        right_click_menu.menu().disable_menu_item(1);\n        right_click_menu.menu().disable_menu_item(3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    show (\n    )\n    {\n        scrollable_region::show();\n        right_click_menu.show();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        scrollable_region::disable();\n        t.stop();\n        has_focus = false;\n        cursor_visible = false;\n        right_click_menu.disable();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    hide (\n    )\n    {\n        auto_mutex M(m);\n        scrollable_region::hide();\n        t.stop();\n        has_focus = false;\n        cursor_visible = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    adjust_total_rect (\n    )\n    {\n        const unsigned long padding = style->get_padding(*mfont);\n        unsigned long text_width;\n        unsigned long text_height;\n\n        mfont->compute_size(text_, text_width, text_height);\n\n        set_total_rect_size(text_width + padding*2, text_height + padding*2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_main_font (\n        const std::shared_ptr<font>& f\n    )\n    {\n        auto_mutex M(m);\n        mfont = f;\n        adjust_total_rect();\n        right_click_menu.set_rect(display_rect());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    draw (\n        const canvas& c\n    ) const\n    {\n        scrollable_region::draw(c);\n        rectangle area = rect.intersect(c);\n        if (area.is_empty())\n            return;\n       \n        const point origin(total_rect().left(), total_rect().top());\n\n        style->draw_text_box(c,display_rect(),get_text_rect(), enabled, *mfont, text_, \n                             translate_rect(cursor_rect, origin), \n                               text_color_, bg_color_, has_focus, cursor_visible, highlight_start,\n                               highlight_end);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_text (\n        const std::string& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void text_box::\n    set_text (\n        const std::wstring& text\n    )\n    {\n        set_text(convert_to_utf32(text));\n    }\n\n    void text_box::\n    set_text (\n        const dlib::ustring& text\n    )\n    {\n        auto_mutex M(m);\n        // do this to get rid of any reference counting that may be present in \n        // the std::string implementation.\n        text_ = text.c_str();\n                \n        adjust_total_rect();\n        move_cursor(0);\n\n        highlight_start = 0;\n        highlight_end = -1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string text_box::\n    text (\n    ) const\n    {\n        std::string temp = convert_wstring_to_mbstring(wtext());\n        return temp;\n    }\n\n    const std::wstring text_box::\n    wtext (\n    ) const\n    {\n        std::wstring temp = convert_utf32_to_wstring(utext());\n        return temp;\n    }\n    \n    const dlib::ustring text_box::\n    utext (\n    ) const\n    {\n        auto_mutex M(m);\n        // do this to get rid of any reference counting that may be present in \n        // the dlib::ustring implementation.\n        dlib::ustring temp = text_.c_str();\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_size (\n        unsigned long width,\n        unsigned long height \n    )\n    {        \n        auto_mutex M(m);\n        scrollable_region::set_size(width,height);\n        right_click_menu.set_rect(display_rect());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_pos (\n        long x,\n        long y\n    )\n    {\n        scrollable_region::set_pos(x,y);\n        right_click_menu.set_rect(get_text_rect());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_background_color (\n        const rgb_pixel color\n    )\n    {\n        auto_mutex M(m);\n        bg_color_ = color;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_box::\n    background_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return bg_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    set_text_color (\n        const rgb_pixel color\n    )\n    {\n        auto_mutex M(m);\n        text_color_ = color;\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const rgb_pixel text_box::\n    text_color (\n    ) const\n    {\n        auto_mutex M(m);\n        return text_color_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (!enabled || hidden || !has_focus)\n        {\n            return;\n        }\n\n        if (state & base_window::LEFT)\n        {\n            if (highlight_start <= highlight_end)\n            {\n                if (highlight_start == cursor_pos)\n                    shift_pos = highlight_end + 1;\n                else\n                    shift_pos = highlight_start;\n            }\n\n            unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y);\n            if (static_cast<long>(new_pos) != cursor_pos)\n            {\n                move_cursor(new_pos);\n                parent.invalidate_rectangle(rect);\n            }\n        }\n        else if (shift_pos != -1)\n        {\n            shift_pos = -1;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long,\n        long ,\n        long \n    )\n    {\n        if (!enabled || hidden)\n            return;\n\n        if (btn == base_window::LEFT)\n            shift_pos = -1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool double_clicked \n    )\n    {\n        using namespace std;\n        if (!enabled || hidden || btn != (unsigned long)base_window::LEFT)\n            return;\n\n        if (display_rect().contains(x,y))\n        {\n            has_focus = true;\n            cursor_visible = true;\n            parent.invalidate_rectangle(rect);\n            t.start();\n\n            \n            if (double_clicked)\n            {\n                // highlight the double clicked word\n                string::size_type first, last;\n                const ustring ustr = convert_to_utf32(std::string(\" \\t\\n\"));\n                first = text_.substr(0,cursor_pos).find_last_of(ustr.c_str());\n                last = text_.find_first_of(ustr.c_str(),cursor_pos);\n                long f = static_cast<long>(first);\n                long l = static_cast<long>(last);\n                if (first == string::npos)\n                    f = -1;\n                if (last == string::npos)\n                    l = static_cast<long>(text_.size());\n\n                ++f;\n                --l;\n\n                move_cursor(l+1);\n                highlight_start = f;\n                highlight_end = l;\n                on_text_is_selected();\n            }\n            else\n            {\n                if (state & base_window::SHIFT)\n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        if (highlight_start == cursor_pos)\n                            shift_pos = highlight_end + 1;\n                        else\n                            shift_pos = highlight_start;\n                    }\n                    else\n                    {\n                        shift_pos = cursor_pos;\n                    }\n                }\n\n                bool at_end = false;\n                if (cursor_pos == 0 || cursor_pos == static_cast<long>(text_.size()))\n                    at_end = true;\n                const long old_pos = cursor_pos;\n\n                unsigned long new_pos = mfont->compute_cursor_pos(get_text_rect(),text_,x,y);\n                move_cursor(new_pos);\n\n                shift_pos = cursor_pos;\n\n                if (at_end && cursor_pos == old_pos)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                }\n            }\n\n        }\n        else if (has_focus && rect.contains(x,y) == false)\n        {\n            t.stop();\n            has_focus = false;\n            cursor_visible = false;\n            shift_pos = -1;\n            highlight_start = 0;\n            highlight_end = -1;\n            on_no_text_selected();\n\n            if (focus_lost_handler.is_set())\n                focus_lost_handler();\n            parent.invalidate_rectangle(rect);\n        }\n        else\n        {\n            has_focus = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        // If the right click menu is up then we don't want to do anything with\n        // the keyboard ourselves.  Let the popup menu use the keyboard for now.\n        if (right_click_menu.popup_menu_visible())\n            return;\n\n        if (has_focus && enabled && !hidden)\n        {\n            const ustring space_str = convert_to_utf32(std::string(\" \\t\\n\"));\n            const bool shift = (state&base_window::KBD_MOD_SHIFT) != 0;\n            const bool ctrl = (state&base_window::KBD_MOD_CONTROL) != 0;\n\n            if (shift && is_printable == false)\n            {\n                if (shift_pos == -1)\n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        if (highlight_start == cursor_pos)\n                            shift_pos = highlight_end + 1;\n                        else\n                            shift_pos = highlight_start;\n                    }\n                    else\n                    {\n                        shift_pos = cursor_pos;\n                    }\n                }\n            }\n            else\n            {\n                shift_pos = -1;\n            }\n\n            if (key == base_window::KEY_LEFT)\n            {\n                if (cursor_pos != 0)\n                {\n                    unsigned long new_pos;\n                    if (ctrl)\n                    {\n                        // find the first non-whitespace to our left\n                        std::string::size_type pos = text_.find_last_not_of(space_str.c_str(),cursor_pos);\n                        if (pos != std::string::npos)\n                        {\n                            pos = text_.find_last_of(space_str.c_str(),pos);\n                            if (pos != std::string::npos)\n                                new_pos = static_cast<unsigned long>(pos);\n                            else\n                                new_pos = 0;\n                        }\n                        else\n                        {\n                            new_pos = 0;\n                        }\n                    }\n                    else\n                    {\n                        new_pos = cursor_pos-1;\n                    }\n\n                    move_cursor(new_pos);\n                }\n                else if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n\n            }\n            else if (key == base_window::KEY_RIGHT)\n            {\n                if (cursor_pos != static_cast<long>(text_.size()))\n                {\n                    unsigned long new_pos;\n                    if (ctrl)\n                    {\n                        // find the first non-whitespace to our left\n                        std::string::size_type pos = text_.find_first_not_of(space_str.c_str(),cursor_pos);\n                        if (pos != std::string::npos)\n                        {\n                            pos = text_.find_first_of(space_str.c_str(),pos);\n                            if (pos != std::string::npos)\n                                new_pos = static_cast<unsigned long>(pos+1);\n                            else\n                                new_pos = static_cast<unsigned long>(text_.size());\n                        }\n                        else\n                        {\n                            new_pos = static_cast<unsigned long>(text_.size());\n                        }\n                    }\n                    else\n                    {\n                        new_pos = cursor_pos+1;\n                    }\n\n                    move_cursor(new_pos);\n                }\n                else if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (key == base_window::KEY_UP)\n            {\n                if (ctrl)\n                {\n                    move_cursor(0);\n                }\n                else\n                {\n                    const point origin(total_rect().left(), total_rect().top());\n                    // move the cursor so the position that is just a few pixels above \n                    // the current cursor_rect\n                    move_cursor(mfont->compute_cursor_pos(\n                            get_text_rect(), text_, cursor_rect.left()+origin.x(), \n                            cursor_rect.top()+origin.y()-mfont->height()/2));\n\n                }\n\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (key == base_window::KEY_DOWN)\n            {\n                if (ctrl)\n                {\n                    move_cursor(static_cast<unsigned long>(text_.size()));\n                }\n                else\n                {\n                    const point origin(total_rect().left(), total_rect().top());\n                    // move the cursor so the position that is just a few pixels above \n                    // the current cursor_rect\n                    move_cursor(mfont->compute_cursor_pos(\n                            get_text_rect(), text_, cursor_rect.left()+origin.x(), \n                            cursor_rect.bottom()+origin.y()+mfont->height()/2));\n                }\n\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (is_printable)\n            {\n                if (ctrl)\n                {\n                    if (key == 'a')\n                    {\n                        on_select_all();\n                    }\n                    else if (key == 'c')\n                    {\n                        on_copy();\n                    }\n                    else if (key == 'v')\n                    {\n                        on_paste();\n                    }\n                    else if (key == 'x')\n                    {\n                        on_cut();\n                    }\n                }\n                else \n                {\n                    if (highlight_start <= highlight_end)\n                    {\n                        text_ = text_.substr(0,highlight_start) + static_cast<unichar>(key) +\n                            text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n\n                        adjust_total_rect();\n                        move_cursor(highlight_start+1);\n                        highlight_start = 0;\n                        highlight_end = -1;\n                        on_no_text_selected();\n                    }\n                    else\n                    {\n                        text_ = text_.substr(0,cursor_pos) + static_cast<unichar>(key) +\n                            text_.substr(cursor_pos,text_.size()-cursor_pos);\n                        adjust_total_rect();\n                        move_cursor(cursor_pos+1);\n                    }\n\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n\n                }\n\n                if (key == '\\n')\n                {\n                    if (enter_key_handler.is_set())\n                        enter_key_handler();\n                }\n            }\n            else if (key == base_window::KEY_BACKSPACE)\n            {                \n                // if something is highlighted then delete that\n                if (highlight_start <= highlight_end)\n                {\n                    on_delete_selected();\n                }\n                else if (cursor_pos != 0)\n                {\n                    text_ = text_.erase(cursor_pos-1,1);\n                    adjust_total_rect();\n                    move_cursor(cursor_pos-1);\n\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n                }\n                else\n                {\n                    // do this just so it repaints itself right\n                    move_cursor(cursor_pos);\n                }\n\n            }\n            else if (key == base_window::KEY_DELETE)\n            {\n                // if something is highlighted then delete that\n                if (highlight_start <= highlight_end)\n                {\n                    on_delete_selected();\n                }\n                else if (cursor_pos != static_cast<long>(text_.size()))\n                {\n                    text_ = text_.erase(cursor_pos,1);\n\n                    adjust_total_rect();\n                    // send out the text modified event\n                    if (text_modified_handler.is_set())\n                        text_modified_handler();\n                }\n                else\n                {\n                    // do this just so it repaints itself right\n                    move_cursor(cursor_pos);\n                }\n\n            }\n            else if (key == base_window::KEY_HOME)\n            {\n                if (ctrl)\n                {\n                    move_cursor(0);\n                }\n                else if (cursor_pos != 0)\n                {\n                    // find the start of the current line\n                    ustring::size_type pos = text_.find_last_of('\\n',cursor_pos-1);\n                    if (pos == ustring::npos)\n                        pos = 0;\n                    else\n                        pos += 1;\n                    move_cursor(static_cast<unsigned long>(pos));\n\n                }\n\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (key == base_window::KEY_END)\n            {\n                if (ctrl)\n                {\n                    move_cursor(static_cast<unsigned long>(text_.size()));\n                }\n                {\n                    ustring::size_type pos = text_.find_first_of('\\n',cursor_pos);\n                    if (pos == ustring::npos)\n                        pos = text_.size();\n\n                    move_cursor(static_cast<unsigned long>(pos));\n                }\n\n                if (shift_pos == -1)\n                {\n                    highlight_start = 0;\n                    highlight_end = -1;\n                    on_no_text_selected();\n                    parent.invalidate_rectangle(rect);\n                }\n            }\n            else if (key == base_window::KEY_PAGE_DOWN || key == base_window::KEY_PAGE_UP)\n            {\n                long jump_size = display_rect().height() - \n                    std::min(mfont->height()*3, display_rect().height()/5);\n\n                // if we are supposed to page up then just jump in the other direction\n                if (key == base_window::KEY_PAGE_UP)\n                    jump_size = -jump_size;\n\n                scroll_to_rect(translate_rect(display_rect(), point(0, jump_size ))); \n            }\n\n            cursor_visible = true;\n            recent_movement = true;\n\n        }\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    void text_box::\n    on_string_put(\n        const std::wstring &str\n    )\n    {\n        if (has_focus && enabled && !hidden)\n        {\n            ustring ustr = convert_to_utf32(str);\n            if (highlight_start <= highlight_end)\n            {\n                text_ = text_.substr(0,highlight_start) + ustr +\n                    text_.substr(highlight_end+1,text_.size()-highlight_end-1);\n\n                adjust_total_rect();\n                move_cursor(highlight_start+ustr.size());\n                highlight_start = 0;\n                highlight_end = -1;\n                on_no_text_selected();\n            }\n            else\n            {\n                text_ = text_.substr(0,cursor_pos) + ustr +\n                    text_.substr(cursor_pos,text_.size()-cursor_pos);\n\n                adjust_total_rect();\n                move_cursor(cursor_pos+ustr.size());\n            }\n\n\n            // send out the text modified event\n            if (text_modified_handler.is_set())\n                text_modified_handler();\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    void text_box::\n    move_cursor (\n        unsigned long pos\n    )\n    {\n        using namespace std;\n        const long old_cursor_pos = cursor_pos;\n\n\n\n        // figure out where the cursor is supposed to be\n        cursor_rect = mfont->compute_cursor_rect(get_text_rect(), text_, pos);\n        const point origin(total_rect().left(), total_rect().top());\n\n\n        cursor_pos = pos;     \n\n\n        const unsigned long padding = style->get_padding(*mfont);\n\n        // now scroll us so that we can see the current cursor \n        scroll_to_rect(centered_rect(cursor_rect, cursor_rect.width() + padding + 6, cursor_rect.height() + 1));\n\n        // adjust the cursor_rect so that it is relative to the total_rect\n        cursor_rect = translate_rect(cursor_rect, -origin);\n\n        parent.set_im_pos(cursor_rect.left(), cursor_rect.top());\n\n        if (old_cursor_pos != cursor_pos)\n        {\n            if (shift_pos != -1)\n            {\n                highlight_start = std::min(shift_pos,cursor_pos);\n                highlight_end = std::max(shift_pos,cursor_pos)-1;\n            }\n\n            if (highlight_start > highlight_end)\n                on_no_text_selected();\n            else\n                on_text_is_selected();\n\n            recent_movement = true;\n            cursor_visible = true;\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        if (shift_pos == -1)\n        {\n            highlight_start = 0;\n            highlight_end = -1;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//       perspective_display member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    perspective_display::\n    perspective_display(  \n        drawable_window& w\n    ) : \n        drawable(w,MOUSE_MOVE|MOUSE_CLICK|MOUSE_WHEEL)\n    {\n        clear_overlay();\n        enable_events(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    perspective_display::\n    ~perspective_display(\n    )\n    {\n        disable_events();\n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    set_size (\n        unsigned long width,\n        unsigned long height \n    )\n    {\n        auto_mutex lock(m);\n        rectangle old(rect);\n        rect = resize_rect(rect,width,height);\n        tform = camera_transform(tform.get_camera_pos(),\n            tform.get_camera_looking_at(),\n            tform.get_camera_up_direction(),\n            tform.get_camera_field_of_view(),\n            std::min(rect.width(),rect.height()));\n        parent.invalidate_rectangle(old+rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    add_overlay (\n        const std::vector<overlay_line>& overlay\n    )\n    {\n        auto_mutex M(m);\n        if (overlay.size() == 0)\n            return;\n        // push this new overlay into our overlay vector\n        overlay_lines.insert(overlay_lines.end(), overlay.begin(), overlay.end());\n\n        for (unsigned long i = 0; i < overlay.size(); ++i)\n        {\n            sum_pts += overlay[i].p1;\n            sum_pts += overlay[i].p2;\n            max_pts.x() = std::max(overlay[i].p1.x(), max_pts.x());\n            max_pts.x() = std::max(overlay[i].p2.x(), max_pts.x());\n            max_pts.y() = std::max(overlay[i].p1.y(), max_pts.y());\n            max_pts.y() = std::max(overlay[i].p2.y(), max_pts.y());\n            max_pts.z() = std::max(overlay[i].p1.z(), max_pts.z());\n            max_pts.z() = std::max(overlay[i].p2.z(), max_pts.z());\n        }\n\n        tform = camera_transform(max_pts,\n            sum_pts/(overlay_lines.size()*2+overlay_dots.size()),\n            vector<double>(0,0,1),\n            tform.get_camera_field_of_view(),\n            std::min(rect.width(),rect.height()));\n\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    add_overlay (\n        const std::vector<overlay_dot>& overlay\n    )\n    {\n        auto_mutex M(m);\n        if (overlay.size() == 0)\n            return;\n\n        for (unsigned long i = 0; i < overlay.size(); ++i)\n        {\n            overlay_dots.push_back(overlay[i]);\n\n            sum_pts += overlay[i].p;\n            max_pts.x() = std::max(overlay[i].p.x(), max_pts.x());\n            max_pts.y() = std::max(overlay[i].p.y(), max_pts.y());\n            max_pts.z() = std::max(overlay[i].p.z(), max_pts.z());\n        }\n\n        tform = camera_transform(max_pts,\n            sum_pts/(overlay_lines.size()*2+overlay_dots.size()),\n            vector<double>(0,0,1),\n            tform.get_camera_field_of_view(),\n            std::min(rect.width(),rect.height()));\n\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    clear_overlay (\n    )\n    {\n        auto_mutex lock(m);\n        overlay_dots.clear();\n        overlay_lines.clear();\n        sum_pts = vector<double>();\n        max_pts = vector<double>(-std::numeric_limits<double>::infinity(),\n            -std::numeric_limits<double>::infinity(),\n            -std::numeric_limits<double>::infinity());\n\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    set_dot_double_clicked_handler (\n        const any_function<void(const vector<double>&)>& event_handler_\n    )\n    {\n        auto_mutex M(m);\n        dot_clicked_event_handler = event_handler_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    draw (\n        const canvas& c\n    ) const\n    {\n        if (depth.nr() < (long)c.height() || depth.nc() < (long)c.width())\n            depth.set_size(c.height(), c.width());\n        assign_all_pixels(depth, std::numeric_limits<float>::infinity());\n\n        rectangle area = rect.intersect(c);\n        fill_rect(c, area, 0);\n        for (unsigned long i = 0; i < overlay_lines.size(); ++i)\n        {\n            draw_line(c, tform(overlay_lines[i].p1)+rect.tl_corner(),\n                         tform(overlay_lines[i].p2)+rect.tl_corner(), \n                         overlay_lines[i].color, \n                         area);\n        }\n        for (unsigned long i = 0; i < overlay_dots.size(); ++i)\n        {\n            double scale, distance;\n            point p = tform(overlay_dots[i].p, scale, distance) + rect.tl_corner();\n            if (area.contains(p) && depth[p.y()-c.top()][p.x()-c.left()] > distance)\n            {\n                depth[p.y()-c.top()][p.x()-c.left()] = distance;\n                assign_pixel(c[p.y()-c.top()][p.x()-c.left()], overlay_dots[i].color);\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    on_wheel_up (\n        unsigned long //state\n    )\n    {\n        if (rect.contains(lastx,lasty) == false || hidden || !enabled)\n            return;\n\n        const double alpha = 0.10;\n        const vector<double> delta = alpha*(tform.get_camera_pos() - tform.get_camera_looking_at());\n        tform = camera_transform(\n            tform.get_camera_pos() - delta,\n            tform.get_camera_looking_at(),\n            tform.get_camera_up_direction(),\n            tform.get_camera_field_of_view(),\n            std::min(rect.width(),rect.height()));\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    on_wheel_down (\n        unsigned long //state\n    )\n    {\n        if (rect.contains(lastx,lasty) == false || hidden || !enabled)\n            return;\n\n        const double alpha = 0.10;\n        const vector<double> delta = alpha*(tform.get_camera_pos() - tform.get_camera_looking_at());\n        tform = camera_transform(\n            tform.get_camera_pos() + delta,\n            tform.get_camera_looking_at(),\n            tform.get_camera_up_direction(),\n            tform.get_camera_field_of_view(),\n            std::min(rect.width(),rect.height()));\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long, //state\n        long x,\n        long y,\n        bool is_double_click\n    )\n    {\n        if (btn == base_window::LEFT || btn == base_window::RIGHT)\n        {\n            last = point(x,y);\n        }\n        if (is_double_click && btn == base_window::LEFT && enabled && !hidden && overlay_dots.size() != 0)\n        {\n            double best_dist = std::numeric_limits<double>::infinity();\n            unsigned long best_idx = 0;\n            const dpoint pp(x,y);\n            for (unsigned long i = 0; i < overlay_dots.size(); ++i)\n            {\n                dpoint p = tform(overlay_dots[i].p) + rect.tl_corner();\n                double dist = length_squared(p-pp);\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_idx = i;\n                }\n            }\n            if (dot_clicked_event_handler.is_set())\n                dot_clicked_event_handler(overlay_dots[best_idx].p);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void perspective_display::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        if (!enabled || hidden)\n            return;\n\n        if (state == base_window::LEFT)\n        {\n            const point cur(x, y);\n            dpoint delta = last-cur;\n            last = cur;\n\n            const vector<double> radius = tform.get_camera_pos()-tform.get_camera_looking_at();\n            delta *= 2*pi*length(radius)/600.0;\n            vector<double> tangent_x = tform.get_camera_up_direction().cross(radius).normalize();\n            vector<double> tangent_y = radius.cross(tangent_x).normalize();\n            vector<double> new_pos = tform.get_camera_pos() + tangent_x*delta.x() + tangent_y*-delta.y(); \n\n            // now make it have the correct radius relative to the looking at point.\n            new_pos = (new_pos-tform.get_camera_looking_at()).normalize()*length(radius) + tform.get_camera_looking_at();\n\n            tform = camera_transform(new_pos,\n                tform.get_camera_looking_at(),\n                tangent_y,\n                tform.get_camera_field_of_view(),\n                std::min(rect.width(),rect.height()));\n            parent.invalidate_rectangle(rect);\n        }\n        else if (state == (base_window::LEFT|base_window::SHIFT) ||\n            state == base_window::RIGHT)\n        {\n            const point cur(x, y);\n            dpoint delta = last-cur;\n            last = cur;\n\n            const vector<double> radius = tform.get_camera_pos()-tform.get_camera_looking_at();\n            delta *= 2*pi*length(radius)/600.0;\n            vector<double> tangent_x = tform.get_camera_up_direction().cross(radius).normalize();\n            vector<double> tangent_y = radius.cross(tangent_x).normalize();\n\n            vector<double> offset = tangent_x*delta.x() + tangent_y*-delta.y(); \n\n\n            tform = camera_transform(\n                tform.get_camera_pos()+offset,\n                tform.get_camera_looking_at()+offset,\n                tform.get_camera_up_direction(),\n                tform.get_camera_field_of_view(),\n                std::min(rect.width(),rect.height()));\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//       image_display member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class image_display_functor\n        {\n            const std::string str;\n            const member_function_pointer<const std::string&> mfp;\n        public:\n            image_display_functor (\n                const std::string& str_,\n                const member_function_pointer<const std::string&>& mfp_\n            ) : str(str_),\n                mfp(mfp_)\n            {}\n\n            void operator() (\n            ) const { mfp(str); }\n        };\n    }\n\n    image_display::\n    image_display(  \n        drawable_window& w\n    ): \n        scrollable_region(w,KEYBOARD_EVENTS),\n        zoom_in_scale(1),\n        zoom_out_scale(1),\n        drawing_rect(true),\n        rect_is_selected(false),\n        selected_rect(0),\n        default_rect_color(255,0,0,255),\n        parts_menu(w),\n        part_width(100), // \"parts\" circles are drawn 1.0/part_width size on the screen relative to the size of the bounding rectangle. \n        overlay_editing_enabled(true),\n        highlight_timer(*this, &image_display::timer_event_unhighlight_rect),\n        highlighted_rect(std::numeric_limits<unsigned long>::max()),\n        holding_shift_key(false)\n    { \n        enable_mouse_drag();\n\n        highlight_timer.set_delay_time(250);\n        set_horizontal_scroll_increment(1);\n        set_vertical_scroll_increment(1);\n        set_horizontal_mouse_wheel_scroll_increment(30);\n        set_vertical_mouse_wheel_scroll_increment(30);\n\n        parts_menu.disable();\n\n\n        enable_events(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_part_add (\n        const std::string& part_name\n    )\n    {\n        if (!rect_is_selected)\n            return;\n\n        const point loc = last_right_click_pos;\n        \n        // Transform loc from gui window space into the space used by the overlay\n        // rectangles (i.e. relative to the raw image)\n        const point origin(total_rect().tl_corner());\n        point c1 = loc - origin;\n        if (zoom_in_scale != 1)\n        {\n            c1 = c1/zoom_in_scale;\n        }\n        else if (zoom_out_scale != 1)\n        {\n            c1 = c1*zoom_out_scale;\n        }\n\n        overlay_rects[selected_rect].parts[part_name] = c1;\n        parent.invalidate_rectangle(rect); \n\n        if (event_handler.is_set())\n            event_handler();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    image_display::\n    ~image_display(\n    )\n    {\n        highlight_timer.stop_and_wait();\n        disable_events();\n        parent.invalidate_rectangle(rect); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle image_display::\n    get_image_display_rect (\n    ) const\n    {\n        if (zoom_in_scale != 1)\n        {\n            return rectangle(0,0, img.nc()*zoom_in_scale-1, img.nr()*zoom_in_scale-1);\n        }\n        else if (zoom_out_scale != 1)\n        {\n            return rectangle(0,0, img.nc()/zoom_out_scale-1, img.nr()/zoom_out_scale-1);\n        }\n        else\n        {\n            return dlib::get_rect(img);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const overlay_rect& overlay\n    )\n    {\n        auto_mutex M(m);\n        // push this new overlay into our overlay vector\n        overlay_rects.push_back(overlay);\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const overlay_line& overlay\n    )\n    {\n        auto_mutex M(m);\n\n        // push this new overlay into our overlay vector\n        overlay_lines.push_back(overlay);\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(get_rect_on_screen(rectangle(overlay.p1, overlay.p2)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const overlay_circle& overlay\n    )\n    {\n        auto_mutex M(m);\n\n        // push this new overlay into our overlay vector\n        overlay_circles.push_back(overlay);\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const std::vector<overlay_rect>& overlay\n    )\n    {\n        auto_mutex M(m);\n\n        // push this new overlay into our overlay vector\n        overlay_rects.insert(overlay_rects.end(), overlay.begin(), overlay.end());\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const std::vector<overlay_line>& overlay\n    )\n    {\n        auto_mutex M(m);\n\n        // push this new overlay into our overlay vector\n        overlay_lines.insert(overlay_lines.end(), overlay.begin(), overlay.end());\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_overlay (\n        const std::vector<overlay_circle>& overlay\n    )\n    {\n        auto_mutex M(m);\n\n        // push this new overlay into our overlay vector\n        overlay_circles.insert(overlay_circles.end(), overlay.begin(), overlay.end());\n\n        // make the parent window redraw us now that we changed the overlay\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    clear_overlay (\n    )\n    {\n        auto_mutex M(m);\n        overlay_rects.clear();\n        overlay_lines.clear();\n        overlay_circles.clear();\n        parent.invalidate_rectangle(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle image_display::\n    get_rect_on_screen (\n        rectangle orect \n    ) const\n    {\n        const point origin(total_rect().tl_corner());\n        orect.left()   = orect.left()*zoom_in_scale/zoom_out_scale;\n        orect.top()    = orect.top()*zoom_in_scale/zoom_out_scale;\n        if (zoom_in_scale != 1)\n        {\n            // make it so the box surrounds the pixels when we zoom in.\n            orect.right()  = (orect.right()+1)*zoom_in_scale/zoom_out_scale;\n            orect.bottom() = (orect.bottom()+1)*zoom_in_scale/zoom_out_scale;\n        }\n        else\n        {\n            orect.right()  = orect.right()*zoom_in_scale/zoom_out_scale;\n            orect.bottom() = orect.bottom()*zoom_in_scale/zoom_out_scale;\n        }\n\n        return translate_rect(orect, origin);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle image_display::\n    get_rect_on_screen (\n        unsigned long idx\n    ) const\n    {\n        return get_rect_on_screen(overlay_rects[idx].rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    draw (\n        const canvas& c\n    ) const\n    {\n        scrollable_region::draw(c);\n\n        rectangle area = display_rect().intersect(c);\n        if (area.is_empty())\n            return;\n\n        const point origin(total_rect().tl_corner());\n        \n        // draw the image on the screen\n        const double scale = zoom_out_scale/(double)zoom_in_scale;\n        const rectangle img_area = total_rect().intersect(area);\n        for (long row = img_area.top(); row <= img_area.bottom(); ++row)\n        {\n            const long rc = row-c.top();\n            const long rimg = (row-origin.y())*scale;\n            for (long col = img_area.left(); col <= img_area.right(); ++col)\n            {\n                assign_pixel(c[rc][col-c.left()], \n                             img[rimg][(col-origin.x())*scale]);\n            }\n        }\n\n        // draw the mouse cross-hairs\n        if (holding_shift_key && total_rect().contains(lastx,lasty) )\n        {\n            draw_line(c, point(lastx,-10000), point(lastx,100000),rgb_pixel(255,255,0), area);\n            draw_line(c, point(-10000,lasty), point(100000,lasty),rgb_pixel(255,255,0), area);\n        }\n\n        // now draw all the overlay rectangles\n        for (unsigned long i = 0; i < overlay_rects.size(); ++i)\n        {\n            const rectangle orect = get_rect_on_screen(i);\n            rgb_alpha_pixel color = overlay_rects[i].color;\n            // draw crossed out boxes slightly faded\n            if (overlay_rects[i].crossed_out)\n                color.alpha = 150;\n\n            if (rect_is_selected && selected_rect == i)\n            {\n                draw_rectangle(c, orect, invert_pixel(color), area);\n            }\n            else if (highlighted_rect < overlay_rects.size() && highlighted_rect == i)\n            {\n                // Draw the rectangle wider and with a slightly different color that tapers\n                // out at the edges of the line.\n                hsi_pixel temp;\n                assign_pixel(temp, 0);\n                assign_pixel(temp, overlay_rects[i].color);\n                temp.s = 255;\n                temp.h = temp.h + 20;\n                if (temp.i < 245)\n                    temp.i += 10;\n                rgb_pixel p;\n                assign_pixel(p, temp);\n                rgb_alpha_pixel po, po2;\n                assign_pixel(po, p);\n                po.alpha = 160;\n                po2 = po;\n                po2.alpha = 90;\n                draw_rectangle(c, grow_rect(orect,2), po2, area);\n                draw_rectangle(c, grow_rect(orect,1), po, area);\n                draw_rectangle(c, orect, p, area);\n                draw_rectangle(c, shrink_rect(orect,1), po, area);\n                draw_rectangle(c, shrink_rect(orect,2), po2, area);\n            }\n            else\n            {\n                draw_rectangle(c, orect, color, area);\n            }\n\n            if (overlay_rects[i].label.size() != 0)\n            {\n                // make a rectangle that is at the spot we want to draw our string\n                rectangle r(orect.br_corner(),  c.br_corner());\n                mfont->draw_string(c, r, overlay_rects[i].label, color, 0, \n                                   std::string::npos, area);\n            }\n\n\n            // draw circles for each \"part\" in this overlay rectangle.\n            std::map<std::string,point>::const_iterator itr;\n            for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)\n            {\n                if (itr->second == OBJECT_PART_NOT_PRESENT)\n                    continue;\n\n                const long part_size = (long)std::max(1.0,std::round(std::sqrt(orect.area())/part_width));\n                rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_size, part_size);\n\n                if (rect_is_selected && selected_rect == i && \n                    selected_part_name.size() != 0 && selected_part_name == itr->first)\n                {\n                    draw_circle(c, center(temp), temp.width(), invert_pixel(color), area);\n                }\n                else\n                {\n                    draw_circle(c, center(temp), temp.width(), color, area);\n                }\n\n                // make a rectangle that is at the spot we want to draw our string\n                rectangle r((temp.br_corner() + temp.bl_corner())/2,  \n                            c.br_corner());\n                mfont->draw_string(c, r, itr->first, color, 0, \n                                   std::string::npos, area);\n            }\n\n            if (overlay_rects[i].crossed_out)\n            {\n                if (rect_is_selected && selected_rect == i)\n                {\n                    draw_line(c, orect.tl_corner(), orect.br_corner(),invert_pixel(color), area);\n                    draw_line(c, orect.bl_corner(), orect.tr_corner(),invert_pixel(color), area);\n                }\n                else\n                {\n                    draw_line(c, orect.tl_corner(), orect.br_corner(),color, area);\n                    draw_line(c, orect.bl_corner(), orect.tr_corner(),color, area);\n                }\n            }\n        }\n\n        // now draw all the overlay lines \n        for (unsigned long i = 0; i < overlay_lines.size(); ++i)\n        {\n            draw_line(c, \n                      zoom_in_scale*(overlay_lines[i].p1+dpoint(0.5,0.5))/zoom_out_scale + origin, \n                      zoom_in_scale*(overlay_lines[i].p2+dpoint(0.5,0.5))/zoom_out_scale + origin, \n                      overlay_lines[i].color, area);\n        }\n\n        // now draw all the overlay circles \n        for (unsigned long i = 0; i < overlay_circles.size(); ++i)\n        {\n            const dpoint center = (double)zoom_in_scale*(overlay_circles[i].center+dpoint(0.5,0.5))/zoom_out_scale + origin;\n            const double radius = zoom_in_scale*overlay_circles[i].radius/zoom_out_scale;\n            draw_circle(c, \n                      center, \n                      radius, \n                      overlay_circles[i].color, area);\n\n            if (overlay_circles[i].label.size() != 0)\n            {\n                const point temp = center + dpoint(0,radius);\n\n                // make a rectangle that is at the spot we want to draw our string\n                rectangle r(temp,  c.br_corner());\n                mfont->draw_string(c, r, overlay_circles[i].label, overlay_circles[i].color, 0, \n                                   std::string::npos, area);\n            }\n        }\n\n        if (drawing_rect)\n            draw_rectangle(c, rect_to_draw, invert_pixel(default_rect_color), area);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        scrollable_region::on_keydown(key,is_printable, state);\n\n        if (!is_printable && key==base_window::KEY_SHIFT)\n        {\n            if (!holding_shift_key)\n            {\n                holding_shift_key = true;\n                parent.invalidate_rectangle(rect);\n            }\n        }\n        else if (holding_shift_key)\n        {\n            holding_shift_key = false;\n            parent.invalidate_rectangle(rect);\n        }\n\n        if (!is_printable && !hidden && enabled && rect_is_selected && \n            (key == base_window::KEY_BACKSPACE || key == base_window::KEY_DELETE))\n        {\n            moving_overlay = false;\n            rect_is_selected = false;\n            parts_menu.disable();\n            if (selected_part_name.size() == 0)\n                overlay_rects.erase(overlay_rects.begin() + selected_rect);\n            else\n                overlay_rects[selected_rect].parts.erase(selected_part_name);\n            parent.invalidate_rectangle(rect);\n\n            if (event_handler.is_set())\n                event_handler();\n        }\n\n        if (!hidden && enabled && rect_is_selected && \n            ((is_printable && key == 'i') || (!is_printable && key==base_window::KEY_END)))\n        {\n            overlay_rects[selected_rect].crossed_out = !overlay_rects[selected_rect].crossed_out;\n            parent.invalidate_rectangle(rect);\n\n            if (event_handler.is_set())\n                event_handler();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    add_labelable_part_name (\n        const std::string& name\n    )\n    {\n        auto_mutex lock(m);\n        if (part_names.insert(name).second)\n        {\n            member_function_pointer<const std::string&> mfp;\n            mfp.set(*this,&image_display::on_part_add);\n            parts_menu.menu().add_menu_item(menu_item_text(\"Add \" + name,impl::image_display_functor(name,mfp)));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    clear_labelable_part_names (\n    )\n    {\n        auto_mutex lock(m);\n        part_names.clear();\n        parts_menu.menu().clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace \n    {\n        \n        bool only_contains_equal_sized_int_strings(\n            const std::map<std::string,point>& parts\n        )\n        {\n            if (parts.size() == 0)\n                return true;\n\n            const size_t string_size = parts.begin()->first.size();\n            for (const auto& p : parts)\n            {\n                if (p.first.size() != string_size)\n                    return false;\n                for (auto ch : p.first)\n                    if (!std::isdigit(ch))\n                        return false;\n            }\n            return true;\n        }\n\n        void zero_pad_part_names (\n            std::map<std::string,point>& parts\n        )\n        {\n            if (parts.size() < 5)\n                return;\n\n            const size_t num_digits_required = 1+std::floor(std::log10(parts.size()-1));\n            // if the first thing in the map has the right number of digits then assume\n            // everything is fine.\n            if (parts.begin()->first.size() == num_digits_required)\n                return;\n\n            std::map<std::string,point> new_parts;\n\n            for (auto& p : parts)\n            {\n                auto key = p.first;\n                while (key.size() < num_digits_required)\n                    key = '0' + key;\n                new_parts[key] = p.second;\n            }\n\n            parts.swap(new_parts);\n        }\n\n    }\n\n    void image_display::\n    on_mouse_down (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y,\n        bool is_double_click\n    )\n    {\n        scrollable_region::on_mouse_down(btn, state, x, y, is_double_click);\n\n        if (state&base_window::SHIFT)\n        {\n            holding_shift_key = true;\n        }\n        else if (holding_shift_key)\n        {\n            holding_shift_key = false;\n            parent.invalidate_rectangle(rect);\n        }\n\n        // if the user shift left clicks when a rect is selected add a part annotation, but\n        // only if they haven't explicitly indicated part names.  If they have part names\n        // then make them pick them from the right click menu.  But if they haven't set\n        // part names then we will automatically create integer numbered parts starting from 0.\n        // We will also only allow auto part numbering if all the parts are already\n        // numbers.\n        if (btn == base_window::LEFT && (state&base_window::SHIFT) && rect_is_selected &&\n            part_names.size() == 0 && only_contains_equal_sized_int_strings(overlay_rects[selected_rect].parts))\n        {\n            // Find the next part name.  Just find the next unused integer starting from 0.\n            int part_num = 0;\n            size_t num_digits_required = 0;\n            for (const auto& p : overlay_rects[selected_rect].parts)\n            {\n                num_digits_required = p.first.size();\n                const int num = std::atoi(p.first.c_str());\n                if (num != part_num)\n                    break;\n                ++part_num;\n            }\n            std::string part_name = std::to_string(part_num);\n            // pad part name so it's the same length as the other parts.\n            while (part_name.size() < num_digits_required)\n                part_name = '0' + part_name;\n\n\n            const point loc(x,y);\n\n            // Transform loc from gui window space into the space used by the overlay\n            // rectangles (i.e. relative to the raw image)\n            const point origin(total_rect().tl_corner());\n            point c1 = loc - origin;\n            if (zoom_in_scale != 1)\n            {\n                c1 = c1/zoom_in_scale;\n            }\n            else if (zoom_out_scale != 1)\n            {\n                c1 = c1*zoom_out_scale;\n            }\n\n            overlay_rects[selected_rect].parts[part_name] = c1;\n\n            zero_pad_part_names(overlay_rects[selected_rect].parts);\n            parent.invalidate_rectangle(rect); \n\n\n            if (event_handler.is_set())\n                event_handler();\n\n            return;\n        }\n\n\n        if (rect.contains(x,y) == false || hidden || !enabled)\n            return;\n\n        if (image_clicked_handler.is_set())\n        {\n            const point origin(total_rect().tl_corner());\n            point p(x,y);\n            p -= origin;\n            if (zoom_in_scale != 1)\n                p = p/zoom_in_scale;\n            else if (zoom_out_scale != 1)\n                p = p*zoom_out_scale;\n\n            if (dlib::get_rect(img).contains(p))\n                image_clicked_handler(p, is_double_click, btn);\n        }\n\n        if (!overlay_editing_enabled)\n            return;\n\n        if (btn == base_window::RIGHT && (state&base_window::SHIFT))\n        {\n            const bool rect_was_selected = rect_is_selected;\n            parts_menu.disable();\n\n            long best_dist = std::numeric_limits<long>::max();\n            long best_idx = 0;\n            std::string best_part;\n\n            // check if this click landed on any of the overlay rectangles\n            for (unsigned long i = 0; i < overlay_rects.size(); ++i)\n            {\n                const rectangle orect = get_rect_on_screen(i);\n\n                const long dist = distance_to_rect_edge(orect, point(x,y));\n\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_idx = i;\n                    best_part.clear();\n                }\n\n                std::map<std::string,point>::const_iterator itr;\n                for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)\n                {\n                    if (itr->second == OBJECT_PART_NOT_PRESENT)\n                        continue;\n\n                    const long part_size = (long)std::max(1.0,std::round(std::sqrt(orect.area())/part_width));\n                    rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_size, part_size);\n                    point c = center(temp);\n\n                    // distance from edge of part circle\n                    const long dist = static_cast<long>(std::abs(length(c - point(x,y)) + 0.5 - temp.width()));\n                    if (dist < best_dist)\n                    {\n                        best_idx = i;\n                        best_dist = dist;\n                        best_part = itr->first;\n                    }\n                }\n            }\n\n\n            if (best_dist < 13)\n            {\n                moving_overlay = true;\n                moving_rect = best_idx;\n                moving_part_name = best_part;\n                // If we are moving one of the sides  of the rectangle rather than one of\n                // the parts circles then we need to figure out which side of the rectangle\n                // we are moving.\n                if (best_part.size() == 0)\n                {\n                    // which side is the click closest to?\n                    const rectangle orect = get_rect_on_screen(best_idx);\n                    const point p = nearest_point(orect,point(x,y));\n                    long dist_left   = std::abs(p.x()-orect.left());\n                    long dist_top    = std::abs(p.y()-orect.top());\n                    long dist_right  = std::abs(p.x()-orect.right());\n                    long dist_bottom = std::abs(p.y()-orect.bottom());\n                    long min_val = std::min(std::min(dist_left,dist_right),std::min(dist_top,dist_bottom));\n                    if (dist_left == min_val)\n                        moving_what = MOVING_RECT_LEFT;\n                    else if (dist_top == min_val)\n                        moving_what = MOVING_RECT_TOP;\n                    else if (dist_right == min_val)\n                        moving_what = MOVING_RECT_RIGHT;\n                    else \n                        moving_what = MOVING_RECT_BOTTOM;\n                }\n                else\n                {\n                    moving_what = MOVING_PART;\n                }\n                // Do this to make the moving stuff snap to the mouse immediately.\n                on_mouse_move(state|btn,x,y);\n            }\n\n            if (rect_was_selected)\n                parent.invalidate_rectangle(rect);\n\n            return;\n        }\n\n        if (btn == base_window::RIGHT && rect_is_selected)\n        {\n            last_right_click_pos = point(x,y);\n            parts_menu.set_rect(rect);\n            return;\n        }\n\n        if (btn == base_window::LEFT && (state&base_window::CONTROL) && !drawing_rect)\n        {\n            long best_dist = std::numeric_limits<long>::max();\n            long best_idx = 0;\n            // check if this click landed on any of the overlay rectangles\n            for (unsigned long i = 0; i < overlay_rects.size(); ++i)\n            {\n                const rectangle orect = get_rect_on_screen(i);\n                const long dist = distance_to_rect_edge(orect, point(x,y));\n\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_idx = i;\n                }\n            }\n            if (best_dist < 13)\n            {\n                overlay_rects[best_idx].label = default_rect_label;\n                overlay_rects[best_idx].color = default_rect_color;\n                highlighted_rect = best_idx;\n                highlight_timer.stop();\n                highlight_timer.start();\n                if (event_handler.is_set())\n                    event_handler();\n                parent.invalidate_rectangle(rect);\n            }\n            return;\n        }\n\n\n        if (!is_double_click && btn == base_window::LEFT && (state&base_window::SHIFT))\n        {\n            drawing_rect = true;\n            rect_anchor = point(x,y);\n\n            if (rect_is_selected)\n            {\n                rect_is_selected = false;\n                parts_menu.disable();\n                parent.invalidate_rectangle(rect);\n            }\n        }\n        else if (drawing_rect)\n        {\n            if (rect_is_selected)\n            {\n                rect_is_selected = false;\n                parts_menu.disable();\n            }\n\n            drawing_rect = false;\n            parent.invalidate_rectangle(rect);\n        }\n        else if (is_double_click)\n        {\n            const bool rect_was_selected = rect_is_selected;\n            rect_is_selected = false;\n            parts_menu.disable();\n\n            long best_dist = std::numeric_limits<long>::max();\n            long best_idx = 0;\n            std::string best_part;\n\n            // check if this click landed on any of the overlay rectangles\n            for (unsigned long i = 0; i < overlay_rects.size(); ++i)\n            {\n                const rectangle orect = get_rect_on_screen(i);\n\n                const long dist = distance_to_rect_edge(orect, point(x,y));\n\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_idx = i;\n                    best_part.clear();\n                }\n\n                std::map<std::string,point>::const_iterator itr;\n                for (itr = overlay_rects[i].parts.begin(); itr != overlay_rects[i].parts.end(); ++itr)\n                {\n                    if (itr->second == OBJECT_PART_NOT_PRESENT)\n                        continue;\n\n                    const long part_size = (long)std::max(1.0,std::round(std::sqrt(orect.area())/part_width));\n                    rectangle temp = centered_rect(get_rect_on_screen(centered_rect(itr->second,1,1)), part_size, part_size);\n                    point c = center(temp);\n\n                    // distance from edge of part circle\n                    const long dist = static_cast<long>(std::abs(length(c - point(x,y)) + 0.5 - temp.width()));\n                    if (dist < best_dist)\n                    {\n                        best_idx = i;\n                        best_dist = dist;\n                        best_part = itr->first;\n                    }\n                }\n            }\n\n\n            if (best_dist < 13)\n            {\n                rect_is_selected = true;\n                if (part_names.size() != 0)\n                    parts_menu.enable();\n                selected_rect = best_idx;\n                selected_part_name = best_part;\n                if (orect_selected_event_handler.is_set())\n                    orect_selected_event_handler(overlay_rects[best_idx]);\n            }\n\n            if (rect_is_selected || rect_was_selected)\n                parent.invalidate_rectangle(rect);\n        }\n        else if (rect_is_selected)\n        {\n            rect_is_selected = false;\n            parts_menu.disable();\n            parent.invalidate_rectangle(rect);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<image_display::overlay_rect> image_display::\n    get_overlay_rects (\n    ) const\n    {\n        auto_mutex lock(m);\n        return overlay_rects;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    set_default_overlay_rect_label (\n        const std::string& label\n    )\n    {\n        auto_mutex lock(m);\n        default_rect_label = label;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string image_display::\n    get_default_overlay_rect_label (\n    ) const\n    {\n        auto_mutex lock(m);\n        return default_rect_label;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    set_default_overlay_rect_color (\n        const rgb_alpha_pixel& color\n    )\n    {\n        auto_mutex lock(m);\n        default_rect_color = color;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    rgb_alpha_pixel image_display::\n    get_default_overlay_rect_color (\n    ) const\n    {\n        auto_mutex lock(m);\n        return default_rect_color;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_mouse_up (\n        unsigned long btn,\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        scrollable_region::on_mouse_up(btn,state,x,y);\n\n        if (state&base_window::SHIFT)\n        {\n            holding_shift_key = true;\n        }\n        else if (holding_shift_key)\n        {\n            holding_shift_key = false;\n            parent.invalidate_rectangle(rect);\n        }\n\n        if (drawing_rect && btn == base_window::LEFT && (state&base_window::SHIFT) &&\n            !hidden && enabled)\n        {\n            const point origin(total_rect().tl_corner());\n            point c1 = point(x,y) - origin;\n            point c2 = rect_anchor - origin;\n\n            if (zoom_in_scale != 1)\n            {\n                c1 = c1/(double)zoom_in_scale;\n                c2 = c2/(double)zoom_in_scale;\n            }\n            else if (zoom_out_scale != 1)\n            {\n                c1 = c1*(double)zoom_out_scale;\n                c2 = c2*(double)zoom_out_scale;\n            }\n\n            rectangle new_rect(c1,c2);\n            if (zoom_in_scale != 1)\n            {\n                // When we are zoomed in we adjust the rectangles a little so they\n                // are drown surrounding the pixels inside the rect.  This adjustment\n                // is necessary to make this code consistent with this goal.\n                new_rect.right() -= 1;\n                new_rect.bottom() -= 1;\n            }\n\n\n            if (new_rect.width() > 0 && new_rect.height() > 0)\n            {\n                add_overlay(overlay_rect(new_rect, default_rect_color, default_rect_label));\n\n                if (event_handler.is_set())\n                    event_handler();\n            }\n        }\n\n        if (drawing_rect)\n        {\n            drawing_rect = false;\n            parent.invalidate_rectangle(rect);\n        }\n        if (moving_overlay)\n        {\n            moving_overlay = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_mouse_move (\n        unsigned long state,\n        long x,\n        long y\n    )\n    {\n        scrollable_region::on_mouse_move(state,x,y);\n\n        if (enabled && !hidden)\n        {\n            if (holding_shift_key)\n                parent.invalidate_rectangle(rect);\n\n            if (state&base_window::SHIFT)\n                holding_shift_key = true;\n            else if (holding_shift_key)\n                holding_shift_key = false;\n        }\n\n        if (drawing_rect)\n        {\n            if ((state&base_window::LEFT) && (state&base_window::SHIFT) && !hidden && enabled)\n            {\n                rectangle new_rect(point(x,y), rect_anchor);\n                parent.invalidate_rectangle(new_rect + rect_to_draw);\n                rect_to_draw = new_rect;\n            }\n            else\n            {\n                drawing_rect = false;\n                parent.invalidate_rectangle(rect);\n            }\n            moving_overlay = false;\n        }\n        else if (moving_overlay)\n        {\n            if ((state&base_window::RIGHT) && (state&base_window::SHIFT) && !hidden && enabled)\n            {\n                // map point(x,y) into the image coordinate space.\n                point p = point(x,y) - total_rect().tl_corner();\n                if (zoom_in_scale != 1)\n                {\n                    if (moving_what == MOVING_PART)\n                        p = p/(double)zoom_in_scale-dpoint(0.5,0.5);\n                    else\n                        p = p/(double)zoom_in_scale;\n                }\n                else if (zoom_out_scale != 1)\n                {\n                    p = p*(double)zoom_out_scale;\n                }\n\n\n                if (moving_what == MOVING_PART)\n                {\n                    if (overlay_rects[moving_rect].parts[moving_part_name] != p)\n                    {\n                        overlay_rects[moving_rect].parts[moving_part_name] = p;\n                        parent.invalidate_rectangle(rect);\n                        if (event_handler.is_set())\n                            event_handler();\n                    }\n                }\n                else \n                {\n                    rectangle original = overlay_rects[moving_rect].rect;\n                    if (moving_what == MOVING_RECT_LEFT)\n                        overlay_rects[moving_rect].rect.left() = std::min(p.x(), overlay_rects[moving_rect].rect.right());\n                    else if (moving_what == MOVING_RECT_RIGHT)\n                        overlay_rects[moving_rect].rect.right() = std::max(p.x()-1, overlay_rects[moving_rect].rect.left());\n                    else if (moving_what == MOVING_RECT_TOP)\n                        overlay_rects[moving_rect].rect.top() = std::min(p.y(), overlay_rects[moving_rect].rect.bottom());\n                    else \n                        overlay_rects[moving_rect].rect.bottom() = std::max(p.y()-1, overlay_rects[moving_rect].rect.top());\n\n                    if (original != overlay_rects[moving_rect].rect)\n                    {\n                        parent.invalidate_rectangle(rect);\n                        if (event_handler.is_set())\n                            event_handler();\n                    }\n                }\n            }\n            else\n            {\n                moving_overlay = false;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    zoom_in (\n    )\n    {\n        auto_mutex M(m); \n        if (zoom_in_scale < 100 && zoom_out_scale == 1)\n        {\n            const point mouse_loc(lastx, lasty);\n            // the pixel in img that the mouse is over\n            const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale;\n\n            zoom_in_scale = zoom_in_scale*10/9 + 1;\n\n            set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale);\n\n            // make is to the pixel under the mouse doesn't move while we zoom\n            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale);\n            scroll_to_rect(translate_rect(display_rect(), delta)); \n        }\n        else if (zoom_out_scale != 1)\n        {\n            const point mouse_loc(lastx, lasty);\n            // the pixel in img that the mouse is over\n            const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale;\n\n            zoom_out_scale = zoom_out_scale*9/10;\n            if (zoom_out_scale == 0)\n                zoom_out_scale = 1;\n\n            set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale);\n\n            // make is to the pixel under the mouse doesn't move while we zoom\n            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale);\n            scroll_to_rect(translate_rect(display_rect(), delta)); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_wheel_up (\n        unsigned long state\n    )\n    {\n        // disable mouse wheel if the user is drawing a rectangle\n        if (drawing_rect)\n            return;\n\n        // if CONTROL is not being held down\n        if ((state & base_window::CONTROL) == 0)\n        {\n            scrollable_region::on_wheel_up(state);\n            return;\n        }\n\n        if (rect.contains(lastx,lasty) == false || hidden || !enabled)\n            return;\n\n        zoom_in();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    zoom_out (\n    )\n    {\n        auto_mutex M(m); \n        if (zoom_in_scale != 1)\n        {\n            const point mouse_loc(lastx, lasty);\n            // the pixel in img that the mouse is over\n            const point pix_loc = (mouse_loc - total_rect().tl_corner())/zoom_in_scale;\n\n            zoom_in_scale = zoom_in_scale*9/10;\n            if (zoom_in_scale == 0)\n                zoom_in_scale = 1;\n\n            set_total_rect_size(img.nc()*zoom_in_scale, img.nr()*zoom_in_scale);\n\n            // make is to the pixel under the mouse doesn't move while we zoom\n            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc*zoom_in_scale);\n            scroll_to_rect(translate_rect(display_rect(), delta)); \n        }\n        else if (std::max(img.nr(), img.nc())/zoom_out_scale > 10)\n        {\n            const point mouse_loc(lastx, lasty);\n            // the pixel in img that the mouse is over\n            const point pix_loc = (mouse_loc - total_rect().tl_corner())*zoom_out_scale;\n\n            zoom_out_scale = zoom_out_scale*10/9 + 1;\n\n            set_total_rect_size(img.nc()/zoom_out_scale, img.nr()/zoom_out_scale);\n\n            // make is to the pixel under the mouse doesn't move while we zoom\n            const point delta = total_rect().tl_corner() - (mouse_loc - pix_loc/zoom_out_scale);\n            scroll_to_rect(translate_rect(display_rect(), delta)); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_display::\n    on_wheel_down (\n        unsigned long state\n    )\n    {\n        // disable mouse wheel if the user is drawing a rectangle\n        if (drawing_rect)\n            return;\n\n        // if CONTROL is not being held down\n        if ((state & base_window::CONTROL) == 0)\n        {\n            scrollable_region::on_wheel_down(state);\n            return;\n        }\n\n        if (rect.contains(lastx,lasty) == false || hidden || !enabled)\n            return;\n\n        zoom_out();\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//         image_window member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    image_window::\n    image_window(\n    ) :\n        gui_img(*this),\n        window_has_closed(false),\n        have_last_click(false),\n        mouse_btn(0),\n        clicked_signaler(this->wm),\n        tie_input_events(false)\n    {\n\n        gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);\n        gui_img.disable_overlay_editing();\n        // show this window on the screen\n        show();\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    image_window::\n    ~image_window(\n    )\n    {\n        // You should always call close_window() in the destructor of window\n        // objects to ensure that no events will be sent to this window while \n        // it is being destructed.  \n        close_window();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    base_window::on_close_return_code image_window::\n    on_window_close(\n    )\n    {\n        window_has_closed = true;\n        clicked_signaler.broadcast();\n        return base_window::CLOSE_WINDOW;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool image_window::\n    get_next_keypress (\n        unsigned long& key,\n        bool& is_printable,\n        unsigned long& state\n    ) \n    {\n        auto_mutex lock(wm);\n        while (have_last_keypress == false && !window_has_closed &&\n            (have_last_click == false || !tie_input_events))\n        {\n            clicked_signaler.wait();\n        }\n\n        if (window_has_closed)\n            return false;\n\n        if (have_last_keypress)\n        {\n            // Mark that we are taking the key click so the next call to get_next_keypress()\n            // will have to wait for another click.\n            have_last_keypress = false;\n            key = next_key;\n            is_printable = next_is_printable;\n            state = next_state;\n            return true;\n        }\n        else\n        {\n            key = 0;\n            is_printable = true;\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    on_keydown (\n        unsigned long key,\n        bool is_printable,\n        unsigned long state\n    )\n    {\n        dlib::drawable_window::on_keydown(key,is_printable,state);\n\n        have_last_keypress = true;\n        next_key = key;\n        next_is_printable = is_printable;\n        next_state = state;\n        clicked_signaler.signal();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    tie_events (\n    )\n    {\n        auto_mutex lock(wm);\n        tie_input_events = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    untie_events (\n    )\n    {\n        auto_mutex lock(wm);\n        tie_input_events = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool image_window::\n    events_tied (\n    ) const\n    {\n        auto_mutex lock(wm);\n        return tie_input_events;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool image_window::\n    get_next_double_click (\n        point& p,\n        unsigned long& mouse_button \n    ) \n    {\n        p = point(-1,-1);\n\n        auto_mutex lock(wm);\n        while (have_last_click == false && !window_has_closed &&\n            (have_last_keypress==false || !tie_input_events))\n        {\n            clicked_signaler.wait();\n        }\n\n        if (window_has_closed)\n            return false;\n\n        if (have_last_click)\n        {\n            // Mark that we are taking the point click so the next call to\n            // get_next_double_click() will have to wait for another click.\n            have_last_click = false;\n            mouse_button = mouse_btn;\n            p = last_clicked_point;\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    on_image_clicked (\n        const point& p,\n        bool is_double_click,\n        unsigned long btn\n    )\n    {\n        if (is_double_click)\n        {\n            have_last_click = true;\n            last_clicked_point = p;\n            mouse_btn = btn;\n            clicked_signaler.signal();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const overlay_rect& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const overlay_line& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const overlay_circle& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const std::vector<overlay_rect>& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const std::vector<overlay_line>& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    add_overlay (\n        const std::vector<overlay_circle>& overlay\n    ) \n    { \n        gui_img.add_overlay(overlay); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    clear_overlay (\n    ) \n    { \n        gui_img.clear_overlay(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void image_window::\n    on_window_resized(\n    )\n    {\n        drawable_window::on_window_resized();\n        unsigned long width, height;\n        get_size(width,height);\n        gui_img.set_size(width, height);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WIDGETs_CPP_\n\n"
  },
  {
    "path": "dlib/gui_widgets/widgets.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_WIDGETs_\n#define DLIB_WIDGETs_\n\n#include <cctype>\n#include <memory>\n#include <set>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include \"../algs.h\"\n#include \"widgets_abstract.h\"\n#include \"drawable.h\"\n#include \"../gui_core.h\"\n#include \"fonts.h\"\n#include \"../timer.h\"\n#include \"base_widgets.h\"\n#include \"../member_function_pointer.h\"\n#include \"../array.h\"\n#include \"../array2d.h\"\n#include \"../sequence.h\"\n#include \"../dir_nav.h\"\n#include \"../queue.h\"\n#include \"style.h\"\n#include \"../string.h\"\n#include \"../misc_api.h\"\n#include \"../any.h\"\n#include \"../image_processing/full_object_detection.h\"\n#include \"../geometry/line.h\"\n\n#ifdef _MSC_VER\n// This #pragma directive is also located in the algs.h file but for whatever\n// reason visual studio 9 just ignores it when it is only there. \n\n// this is to disable the \"'this' : used in base member initializer list\"\n// warning you get from some of the GUI objects since all the objects\n// require that their parent class be passed into their constructor. \n// In this case though it is totally safe so it is ok to disable this warning.\n#pragma warning(disable : 4355)\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class label  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class label : public drawable\n    {\n    public:\n        label(\n            drawable_window& w\n        ) : \n            drawable(w),\n            text_color_(0,0,0)\n        {\n            enable_events();\n        }\n\n        ~label()\n        { disable_events(); parent.invalidate_rectangle(rect); }\n\n        void set_text (\n            const std::string& text\n        );\n\n        void set_text (\n            const std::wstring& text\n        );\n\n        void set_text (\n            const dlib::ustring& text\n        );\n\n        const std::string text (\n        ) const;\n\n        const std::wstring wtext (\n        ) const;\n\n        const dlib::ustring utext (\n        ) const;\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n\n        const rgb_pixel text_color (\n        ) const;\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n    private:\n        dlib::ustring text_;\n        rgb_pixel text_color_;\n\n\n        // restricted functions\n        label(label&);        // copy constructor\n        label& operator=(label&);    // assignment operator\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class toggle_button\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button : public button_action \n    {\n        /*!\n            INITIAL VALUE\n                - checked == false\n\n            CONVENTION\n                - is_checked() == checked\n        !*/\n\n    public:\n\n        toggle_button(\n            drawable_window& w\n        ) : \n            button_action(w),\n            btn_tooltip(w),\n            checked(false)\n        {\n            style.reset(new toggle_button_style_default());\n            enable_events();\n        }\n        \n        ~toggle_button() { disable_events(); parent.invalidate_rectangle(rect); }\n\n        void set_name (\n            const std::string& name\n        );\n\n        void set_name (\n            const std::wstring& name\n        );\n\n        void set_name (\n            const dlib::ustring& name\n        );\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n\n        void set_tooltip_text (\n            const std::string& text\n        );\n\n        void set_tooltip_text (\n            const std::wstring& text\n        );\n\n        void set_tooltip_text (\n            const ustring& text\n        );\n\n        const std::string tooltip_text (\n        ) const;\n\n        const std::wstring tooltip_wtext (\n        ) const;\n\n        const dlib::ustring tooltip_utext (\n        ) const;\n\n        bool is_checked (\n        ) const;\n\n        const std::string name (\n        ) const;\n\n        const std::wstring wname (\n        ) const;\n\n        const dlib::ustring uname (\n        ) const;\n\n        void set_checked (\n        );\n\n        void set_unchecked (\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            rect = move_rect(style->get_min_size(name_,*mfont), rect.left(), rect.top());\n            parent.invalidate_rectangle(rect);\n        }\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler_)()\n        )\n        {\n            auto_mutex M(m);\n            event_handler = make_mfp(object,event_handler_);\n            event_handler_self.clear();\n        }\n\n        void set_click_handler (\n            const any_function<void()>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            event_handler = event_handler_;\n            event_handler_self.clear();\n        }\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler_)(toggle_button&)\n        )\n        {\n            auto_mutex M(m);\n            event_handler_self = make_mfp(object,event_handler_);\n            event_handler.clear();\n        }\n\n        void set_sourced_click_handler (\n            const any_function<void(toggle_button&)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            event_handler_self = event_handler_;\n            event_handler.clear();\n        }\n\n    private:\n\n        // restricted functions\n        toggle_button(toggle_button&);        // copy constructor\n        toggle_button& operator=(toggle_button&);    // assignment operator\n\n        dlib::ustring name_;\n        tooltip btn_tooltip;\n        bool checked;\n\n        any_function<void()> event_handler;\n        any_function<void(toggle_button&)> event_handler_self;\n\n        std::unique_ptr<toggle_button_style> style;\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const { style->draw_toggle_button(c,rect,enabled,*mfont,lastx,lasty,name_,is_depressed(),checked); }\n\n        void on_button_up (\n            bool mouse_over\n        );\n\n        void on_mouse_over (\n        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }\n\n        void on_mouse_not_over (\n        ){ if (style->redraw_on_mouse_over()) parent.invalidate_rectangle(rect); }\n    };\n \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class text_field  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_field : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                text_color_ == rgb_pixel(0,0,0)\n                bg_color_ == rgb_pixel(255,255,255)\n                cursor_pos == 0\n                text_width == 0\n                text_ == \"\"\n                has_focus == false\n                cursor_visible == false\n                recent_movement == false\n                highlight_start == 0\n                highlight_end == -1\n                shift_pos == -1\n                text_pos == 0\n    \n            CONVENTION\n                - cursor_pos == the position of the cursor in the string text_.  The \n                  cursor appears before the letter text_[cursor_pos]\n                - cursor_x == the x coordinate of the cursor relative to the left side \n                  of rect.  i.e. the number of pixels that separate the cursor from the\n                  left side of the text_field.\n                - has_focus == true if this text field has keyboard input focus\n                - cursor_visible == true if the cursor should be painted\n                - text_ == text()\n                - text_pos == the index of the first letter in text_ that appears in \n                  this text field.\n                - text_width == the width of text_[text_pos] though text_[text.size()-1]\n\n                - if (has_focus && the user has recently moved the cursor) then\n                    - recent_movement == true\n                - else\n                    - recent_movement == false\n\n                - if (highlight_start <= highlight_end) then\n                    - text[highlight_start] though text[highlight_end] should be\n                      highlighted\n\n                - if (shift_pos != -1) then\n                    - has_focus == true\n                    - the shift key is being held down or the left mouse button is\n                      being held down.\n                    - shift_pos == the position of the cursor when the shift or mouse key\n                      was first pressed.\n\n                - text_color() == text_color_\n                - background_color() == bg_color_\n        !*/\n\n    public:\n        text_field(\n            drawable_window& w\n        ) : \n            drawable(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),\n            text_color_(0,0,0),\n            bg_color_(255,255,255),\n            text_width(0),\n            text_pos(0),\n            recent_movement(false),\n            has_focus(false),\n            cursor_visible(false),\n            cursor_pos(0),\n            highlight_start(0),\n            highlight_end(-1),\n            shift_pos(-1),\n            t(*this,&text_field::timer_action),\n            right_click_menu(w)\n        {\n            style.reset(new text_field_style_default());\n            rect.set_bottom(mfont->height()+ (style->get_padding(*mfont))*2);\n            rect.set_right((style->get_padding(*mfont))*2);\n            cursor_x = style->get_padding(*mfont);\n\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Cut\",*this,&text_field::on_cut,'t'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Copy\",*this,&text_field::on_copy,'C'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Paste\",*this,&text_field::on_paste,'P'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Delete\",*this,&text_field::on_delete_selected,'D'));\n            right_click_menu.menu().add_menu_item(menu_item_separator());\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Select All\",*this,&text_field::on_select_all,'A'));\n\n            right_click_menu.set_rect(get_text_rect());\n            enable_events();\n\n            t.set_delay_time(500);\n        }\n\n        ~text_field (\n        )\n        {\n            disable_events();\n            parent.invalidate_rectangle(rect); \n            t.stop_and_wait();\n        }\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            // call this just so that this widget redraws itself with the new style\n            set_main_font(mfont);\n        }\n\n        void set_text (\n            const std::string& text_\n        );\n\n        void set_text (\n            const std::wstring& text_\n        );\n\n        void give_input_focus (\n        );\n\n        bool has_input_focus (\n        ) const;\n\n        void select_all_text (\n        );\n\n        void set_text (\n            const dlib::ustring& text_\n        );\n\n        const std::string text (\n        ) const;\n\n        const std::wstring wtext (\n        ) const;\n\n        const dlib::ustring utext (\n        ) const;\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n\n        const rgb_pixel text_color (\n        ) const;\n\n        void set_background_color (\n            const rgb_pixel color\n        );\n\n        const rgb_pixel background_color (\n        ) const;\n\n        void set_width (\n            unsigned long width\n        );\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        int next_free_user_event_number (\n        ) const\n        {\n            return drawable::next_free_user_event_number()+1;\n        }\n\n        void disable (\n        );\n\n        void enable (\n        );\n\n        void hide (\n        );\n\n        void show (\n        );\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            text_modified_handler = make_mfp(object,event_handler);\n        }\n\n        template <\n            typename T\n            >\n        void set_enter_key_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            enter_key_handler = make_mfp(object,event_handler);\n        }\n\n        void set_text_modified_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            text_modified_handler = event_handler;\n        }\n\n        void set_enter_key_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            enter_key_handler = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_focus_lost_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            focus_lost_handler = make_mfp(object,event_handler);\n        }\n\n        void set_focus_lost_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            focus_lost_handler = event_handler;\n        }\n\n    private:\n\n        void on_cut (\n        );\n        \n        void on_copy (\n        );\n\n        void on_paste (\n        );\n\n        void on_select_all (\n        );\n\n        void on_delete_selected (\n        );\n\n        void on_text_is_selected (\n        );\n\n        void on_no_text_selected (\n        );\n\n        void on_user_event (\n            int num\n        )\n        {\n            // ignore this user event if it isn't for us\n            if (num != drawable::next_free_user_event_number())\n                return;\n\n            if (recent_movement == false)\n            {\n                cursor_visible = !cursor_visible; \n                parent.invalidate_rectangle(rect); \n            }\n            else\n            {\n                if (cursor_visible == false)\n                {\n                    cursor_visible = true;\n                    parent.invalidate_rectangle(rect); \n                }\n                recent_movement = false;\n            }\n        }\n\n        void timer_action (\n        ) { parent.trigger_user_event(this,drawable::next_free_user_event_number()); }\n        /*!\n            ensures\n                - flips the state of cursor_visible\n        !*/\n\n        void move_cursor (\n            unsigned long pos\n        );\n        /*!\n            requires\n                - pos <= text_.size() \n            ensures\n                - moves the cursor to the position given by pos and moves the text \n                  in the text box if necessary\n                - if the position changes then the parent window will be updated\n        !*/\n\n        rectangle get_text_rect (\n        ) const;\n        /*!\n            ensures\n                - returns the rectangle that should contain the text in this widget\n        !*/\n\n        dlib::ustring text_;\n        rgb_pixel text_color_;\n        rgb_pixel bg_color_;\n\n        unsigned long text_width;\n        unsigned long text_pos;\n\n\n        bool recent_movement;\n        bool has_focus;\n        bool cursor_visible;\n        long cursor_pos;\n        unsigned long cursor_x;\n\n        // this tells you what part of the text is highlighted\n        long highlight_start;\n        long highlight_end;\n        long shift_pos;\n        any_function<void()> text_modified_handler;\n        any_function<void()> enter_key_handler;\n        any_function<void()> focus_lost_handler;\n\n        std::unique_ptr<text_field_style> style;\n\n        timer<text_field> t;\n\n        popup_menu_region right_click_menu;\n\n        // restricted functions\n        text_field(text_field&);        // copy constructor\n        text_field& operator=(text_field&);    // assignment operator\n\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_string_put (\n            const std::wstring &str\n        );\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class text_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_box : public scrollable_region\n    {\n        /*!\n            INITIAL VALUE\n                text_color_ == rgb_pixel(0,0,0)\n                bg_color_ == rgb_pixel(255,255,255)\n                cursor_pos == 0\n                text_ == \"\"\n                has_focus == false\n                cursor_visible == false\n                recent_movement == false\n                highlight_start == 0\n                highlight_end == -1\n                shift_pos == -1\n    \n            CONVENTION\n                - cursor_pos == the position of the cursor in the string text_.  The \n                  cursor appears before the letter text_[cursor_pos]\n                - cursor_rect == The rectangle that should be drawn for the cursor. \n                  The position is relative to total_rect().\n                - has_focus == true if this text field has keyboard input focus\n                - cursor_visible == true if the cursor should be painted\n                - text_ == text()\n\n                - if (has_focus && the user has recently moved the cursor) then\n                    - recent_movement == true\n                - else\n                    - recent_movement == false\n\n                - if (highlight_start <= highlight_end) then\n                    - text[highlight_start] though text[highlight_end] should be\n                      highlighted\n\n                - if (shift_pos != -1) then\n                    - has_focus == true\n                    - the shift key is being held down or the left mouse button is\n                      being held down.\n                    - shift_pos == the position of the cursor when the shift or mouse key\n                      was first pressed.\n\n                - text_color() == text_color_\n                - background_color() == bg_color_\n        !*/\n\n    public:\n        text_box(\n            drawable_window& w\n        ) : \n            scrollable_region(w,MOUSE_CLICK | KEYBOARD_EVENTS | MOUSE_MOVE | STRING_PUT),\n            text_color_(0,0,0),\n            bg_color_(255,255,255),\n            recent_movement(false),\n            has_focus(false),\n            cursor_visible(false),\n            cursor_pos(0),\n            highlight_start(0),\n            highlight_end(-1),\n            shift_pos(-1),\n            t(*this,&text_box::timer_action),\n            right_click_menu(w)\n        {\n            style.reset(new text_box_style_default());\n\n            const long padding = static_cast<long>(style->get_padding(*mfont));\n            cursor_rect = mfont->compute_cursor_rect(rectangle(padding,padding,1000000,1000000), text_, 0);\n\n            adjust_total_rect();\n\n            set_vertical_mouse_wheel_scroll_increment(mfont->height());\n            set_horizontal_mouse_wheel_scroll_increment(mfont->height());\n\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Cut\",*this,&text_box::on_cut,'t'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Copy\",*this,&text_box::on_copy,'C'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Paste\",*this,&text_box::on_paste,'P'));\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Delete\",*this,&text_box::on_delete_selected,'D'));\n            right_click_menu.menu().add_menu_item(menu_item_separator());\n            right_click_menu.menu().add_menu_item(menu_item_text(\"Select All\",*this,&text_box::on_select_all,'A'));\n\n            right_click_menu.set_rect(get_text_rect());\n\n            set_size(100,100);\n\n            enable_events();\n\n            t.set_delay_time(500);\n        }\n\n        ~text_box (\n        )\n        {\n            disable_events();\n            parent.invalidate_rectangle(rect); \n            t.stop_and_wait();\n        }\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n\n            scrollable_region::set_style(style_.get_scrollable_region_style());\n            // call this just so that this widget redraws itself with the new style\n            set_main_font(mfont);\n        }\n\n        void set_text (\n            const std::string& text_\n        );\n\n        void set_text (\n            const std::wstring& text_\n        );\n\n        void set_text (\n            const dlib::ustring& text_\n        );\n\n        const std::string text (\n        ) const;\n\n        const std::wstring wtext (\n        ) const;\n\n        const dlib::ustring utext (\n        ) const;\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n\n        const rgb_pixel text_color (\n        ) const;\n\n        void set_background_color (\n            const rgb_pixel color\n        );\n\n        const rgb_pixel background_color (\n        ) const;\n\n        void set_size (\n            unsigned long width,\n            unsigned long height \n        );\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        int next_free_user_event_number (\n        ) const\n        {\n            return scrollable_region::next_free_user_event_number()+1;\n        }\n\n        void disable (\n        );\n\n        void enable (\n        );\n\n        void hide (\n        );\n\n        void show (\n        );\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            text_modified_handler = make_mfp(object,event_handler);\n        }\n\n        void set_text_modified_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            text_modified_handler = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_enter_key_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            enter_key_handler = make_mfp(object,event_handler);\n        }\n\n        void set_enter_key_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            enter_key_handler = event_handler;\n        }\n\n        template <\n            typename T\n            >\n        void set_focus_lost_handler (\n            T& object,\n            void (T::*event_handler)()\n        )\n        {\n            auto_mutex M(m);\n            focus_lost_handler = make_mfp(object,event_handler);\n        }\n\n        void set_focus_lost_handler (\n            const any_function<void()>& event_handler\n        )\n        {\n            auto_mutex M(m);\n            focus_lost_handler = event_handler;\n        }\n\n    private:\n\n        void on_cut (\n        );\n        \n        void on_copy (\n        );\n\n        void on_paste (\n        );\n\n        void on_select_all (\n        );\n\n        void on_delete_selected (\n        );\n\n        void on_text_is_selected (\n        );\n\n        void on_no_text_selected (\n        );\n\n        void on_user_event (\n            int num\n        )\n        {\n            // ignore this user event if it isn't for us\n            if (num != scrollable_region::next_free_user_event_number())\n                return;\n\n            if (recent_movement == false)\n            {\n                cursor_visible = !cursor_visible; \n                parent.invalidate_rectangle(rect); \n            }\n            else\n            {\n                if (cursor_visible == false)\n                {\n                    cursor_visible = true;\n                    parent.invalidate_rectangle(rect); \n                }\n                recent_movement = false;\n            }\n        }\n\n        // The reason for using user actions here rather than just having the timer just call\n        // what it needs directly is to avoid a potential deadlock during destruction of this widget.\n        void timer_action (\n        ) { parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); }\n        /*!\n            ensures\n                - flips the state of cursor_visible\n        !*/\n\n        void move_cursor (\n            unsigned long pos\n        );\n        /*!\n            requires\n                - pos <= text_.size() \n            ensures\n                - moves the cursor to the position given by pos and moves the text \n                  in the text box if necessary\n                - if the position changes then the parent window will be updated\n        !*/\n\n        rectangle get_text_rect (\n        ) const;\n        /*!\n            ensures\n                - returns the rectangle that should contain the text in this widget\n        !*/\n\n        void adjust_total_rect (\n        );\n        /*!\n            ensures\n                - adjusts total_rect() so that it is big enough to contain the text\n                  currently in this object.\n        !*/\n\n        dlib::ustring text_;\n        rgb_pixel text_color_;\n        rgb_pixel bg_color_;\n\n\n\n        bool recent_movement;\n        bool has_focus;\n        bool cursor_visible;\n        long cursor_pos;\n        rectangle cursor_rect;\n\n        // this tells you what part of the text is highlighted\n        long highlight_start;\n        long highlight_end;\n        long shift_pos;\n        any_function<void()> text_modified_handler;\n        any_function<void()> enter_key_handler;\n        any_function<void()> focus_lost_handler;\n\n        std::unique_ptr<text_box_style> style;\n\n        timer<text_box> t;\n\n        popup_menu_region right_click_menu;\n\n        // restricted functions\n        text_box(text_box&);        // copy constructor\n        text_box& operator=(text_box&);    // assignment operator\n\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_string_put (\n            const std::wstring &str\n        );\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class check_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class check_box : public toggle_button \n    {\n    public:\n        check_box(  \n            drawable_window& w\n        ) : toggle_button(w)\n        {\n            set_style(toggle_button_style_check_box());\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class radio_button\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class radio_button : public toggle_button \n    {\n    public:\n        radio_button (  \n            drawable_window& w\n        ) : toggle_button(w)\n        {\n            set_style(toggle_button_style_radio_button());\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class tabbed_display\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class tabbed_display : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - tabs.size() == 0\n                - selected_tab_ == 0\n\n            CONVENTION\n                - number_of_tabs() == tabs.size()\n                - tab_name(idx) == tabs[idx]\n                - if (tabs.size() > 0) then\n                    - selected_tab_ == the index of the tab that is currently selected\n\n                - for all valid i:\n                    - tabs[i].width == mfont->compute_size(tabs[i].name)\n                    - tabs[i].rect == the rectangle that defines where this tab is\n                    - if (tabs[i].group != 0) then\n                        - tabs[i].group == a pointer to the widget_group for this tab.\n\n                - left_pad == the amount of padding in a tab to the left of the name string.\n                - right_pad == the amount of padding in a tab to the right of the name string.\n                - top_pad == the amount of padding in a tab to the top of the name string.\n                - bottom_pad == the amount of padding in a tab to the bottom of the name string.\n\n                - if (event_handler.is_set()) then\n                    - event_handler() is what is called to process click events\n                      on this object.\n        !*/\n\n    public:\n\n        tabbed_display(  \n            drawable_window& w\n        );\n\n        virtual ~tabbed_display(\n        );\n\n        void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        void set_number_of_tabs (\n            unsigned long num\n        );\n\n        unsigned long selected_tab (\n        ) const;\n\n        unsigned long number_of_tabs (\n        ) const;\n\n        const std::string tab_name (\n            unsigned long idx\n        ) const;\n\n        const std::wstring tab_wname (\n            unsigned long idx\n        ) const;\n\n        const dlib::ustring& tab_uname (\n            unsigned long idx\n        ) const;\n\n        void set_tab_name (\n            unsigned long idx,\n            const std::string& new_name\n        );\n\n        void set_tab_name (\n            unsigned long idx,\n            const std::wstring& new_name\n        );\n\n        void set_tab_name (\n            unsigned long idx,\n            const dlib::ustring& new_name\n        );\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*eh)(unsigned long new_idx,unsigned long old_idx)\n        )\n        {\n            auto_mutex M(m);\n            event_handler = make_mfp(object,eh);\n        }\n\n        void set_click_handler (\n            const any_function<void(unsigned long,unsigned long)>& eh\n        )\n        {\n            auto_mutex M(m);\n            event_handler = eh;\n        }\n\n        void set_tab_group (\n            unsigned long idx,\n            widget_group& group\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        void fit_to_contents (\n        );\n\n    protected:\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n    private:\n        void recompute_tabs (\n        );\n        /*!\n            ensures\n                - recomputes the rectangles for all the tabs and makes this object\n                  wider if needed\n        !*/\n\n        void draw_tab (\n            const rectangle& tab,\n            const canvas& c\n        ) const;\n        /*!\n            ensures\n                - draws the outline of a tab as given by the rectangle onto c\n        !*/\n\n        struct tab_data\n        {\n            tab_data() : width(0), group(0) {}\n\n            dlib::ustring name;\n            unsigned long width;\n            rectangle rect;\n            widget_group* group;\n        };\n\n        unsigned long selected_tab_;\n\n        array<tab_data> tabs;\n\n        const long left_pad;\n        const long right_pad;\n        const long top_pad;\n        const long bottom_pad;\n\n        any_function<void(unsigned long,unsigned long)> event_handler;\n\n        // restricted functions\n        tabbed_display(tabbed_display&);        // copy constructor\n        tabbed_display& operator=(tabbed_display&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class named_rectangle\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class named_rectangle : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                name == \"\"\n\n            CONVENTION\n                name_ == name()\n        !*/\n\n    public:\n\n        named_rectangle(  \n            drawable_window& w\n        );\n\n        virtual ~named_rectangle(\n        );\n\n        void set_size (\n            unsigned long width,\n            unsigned long height\n        );\n\n        void set_name (\n            const std::string& name\n        );\n\n        void set_name (\n            const std::wstring& name\n        );\n\n        void set_name (\n            const dlib::ustring& name\n        );\n\n        const std::string name (\n        ) const;\n\n        const std::wstring wname (\n        ) const;\n\n        const dlib::ustring uname (\n        ) const;\n\n        void wrap_around (\n            const rectangle& rect\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n    protected:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n    private:\n\n        void make_name_fit_in_rect (\n        );\n\n        dlib::ustring name_;\n        unsigned long name_width;\n        unsigned long name_height;\n\n        // restricted functions\n        named_rectangle(named_rectangle&);        // copy constructor\n        named_rectangle& operator=(named_rectangle&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class mouse_tracker\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class mouse_tracker : public draggable \n    {\n\n    public:\n\n        mouse_tracker(  \n            drawable_window& w\n        ); \n\n        ~mouse_tracker(\n        );\n\n        void show (\n        );\n\n        void hide (\n        );\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        void set_pos (\n            long x,\n            long y\n        );\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n    protected:\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_drag (\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n\n    private:\n\n        const long offset;\n        named_rectangle nr;\n        label x_label;\n        label y_label; \n        std::ostringstream sout;\n\n        long click_x, click_y;\n\n        // restricted functions\n        mouse_tracker(mouse_tracker&);        // copy constructor\n        mouse_tracker& operator=(mouse_tracker&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function message_box()  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace message_box_helper\n    {\n        class box_win : public drawable_window\n        {\n            void initialize (\n            );\n        public:\n            box_win (\n                const std::string& title_,\n                const std::string& message_\n            );\n\n            box_win (\n                const std::wstring& title_,\n                const std::wstring& message_\n            );\n\n            box_win (\n                const dlib::ustring& title_,\n                const dlib::ustring& message_\n            );\n\n            ~box_win (\n            );\n\n            void set_click_handler (\n                const any_function<void()>& event_handler_\n            )\n            {\n                auto_mutex M(wm);\n                event_handler = event_handler_;\n            }\n\n        private:\n\n            static void deleter_thread (\n                void* param\n            );\n\n            void on_click (\n            );\n\n            on_close_return_code on_window_close (\n            );\n\n            const std::wstring title;\n            const std::wstring message;\n            label msg;\n            button btn_ok;\n\n            any_function<void()> event_handler;\n        };\n\n        class blocking_box_win : public drawable_window\n        {\n            void initialize (\n            );\n\n        public:\n            blocking_box_win (\n                const std::string& title_,\n                const std::string& message_\n            );\n\n            blocking_box_win (\n                const std::wstring& title_,\n                const std::wstring& message_\n            );\n\n            blocking_box_win (\n                const dlib::ustring& title_,\n                const dlib::ustring& message_\n            );\n\n            ~blocking_box_win (\n            );\n\n        private:\n\n            void on_click (\n            );\n\n            const std::wstring title;\n            const std::wstring message;\n            label msg;\n            button btn_ok;\n        };\n    }\n\n    template <\n        typename T\n        >\n    void message_box (\n        const std::string& title,\n        const std::string& message,\n        T& object,\n        void (T::*event_handler)() \n    )\n    {\n        using namespace message_box_helper;\n        box_win* win = new box_win(title,message);\n        win->set_click_handler(make_mfp(object,event_handler));\n    }\n\n    inline void message_box (\n        const std::string& title,\n        const std::string& message,\n        const any_function<void()>& event_handler\n    )\n    {\n        using namespace message_box_helper;\n        box_win* win = new box_win(title,message);\n        win->set_click_handler(event_handler);\n    }\n\n    inline void message_box (\n        const std::string& title,\n        const std::string& message\n    )\n    {\n        using namespace message_box_helper;\n        new box_win(title,message);\n    }\n\n    inline void message_box_blocking (\n        const std::string& title,\n        const std::string& message\n    )\n    {\n        using namespace message_box_helper;\n        blocking_box_win w(title,message);\n        w.wait_until_closed();\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class list_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace list_box_helper{\n    template <typename S = std::string>\n    class list_box : public scrollable_region, \n                     public enumerable<const S>\n    {\n        /*!\n            INITIAL VALUE\n                - ms_enabled == false\n                - items.size() == 0\n                - last_selected = 0\n\n            CONVENTION\n                - size() == items.size()\n                - (*this)[i] == items[i].name\n                - is_selected(i) == items[i].is_selected\n                - ms_enabled == multiple_select_enabled()\n\n                - items[i].width == the width of items[i].name as given by font::compute_size() \n                - items[i].height == the height of items[i].name as given by font::compute_size() \n\n                - last_selected == the last item the user selected\n        !*/\n\n    public:\n\n        list_box(  \n            drawable_window& w\n        );\n\n        ~list_box(\n        );\n\n        bool is_selected (\n            unsigned long index\n        ) const;\n\n        void select (\n            unsigned long index \n        );\n\n        void unselect (\n            unsigned long index \n        );\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style_\n        )\n        {\n            auto_mutex M(m);\n            style.reset(new style_type(style_));\n            scrollable_region::set_style(style_.get_scrollable_region_style());\n            parent.invalidate_rectangle(rect);\n        }\n\n        template <typename T>\n        void get_selected (\n            T& list\n        ) const\n        {\n            auto_mutex M(m);\n            list.clear();\n            for (unsigned long i = 0; i < items.size(); ++i)\n            {\n                if (items[i].is_selected)\n                {\n                    unsigned long idx = i;\n                    list.enqueue(idx);\n                }\n            }\n        }\n\n        template <typename T>\n        void load (\n            const T& list\n        )\n        {\n            auto_mutex M(m);\n            items.clear();\n            unsigned long i = 0;\n            items.set_max_size(list.size());\n            items.set_size(list.size());\n            list.reset();\n            unsigned long max_width = 0;\n            unsigned long total_height = 0;\n            while (list.move_next())\n            {\n                items[i].is_selected = false;\n                items[i].name = list.element();\n                mfont->compute_size(items[i].name,items[i].width, items[i].height);\n\n                if (items[i].width > max_width)\n                    max_width = items[i].width;\n                total_height += items[i].height;\n\n                ++i;\n            }\n            set_total_rect_size(max_width, total_height);\n\n            parent.invalidate_rectangle(rect);\n            last_selected = 0;\n        }\n\n        const S& operator[] (\n            unsigned long index\n        ) const;\n\n        bool multiple_select_enabled (\n        ) const;\n\n        void enable_multiple_select (\n        ); \n\n        void disable_multiple_select (\n        );\n\n        template <\n            typename T\n            >\n        void set_double_click_handler (\n            T& object,\n            void (T::*eh)(unsigned long index)\n        ) { auto_mutex M(m); event_handler = make_mfp(object,eh); }\n\n        void set_double_click_handler (\n            const any_function<void(unsigned long)>& eh\n        ) { auto_mutex M(m); event_handler = eh; }\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*eh)(unsigned long index)\n        ) { auto_mutex M(m); single_click_event_handler = make_mfp(object,eh); }\n\n        void set_click_handler (\n            const any_function<void(unsigned long)>& eh\n        ) { auto_mutex M(m); single_click_event_handler = eh; }\n\n        bool at_start (\n        ) const;\n\n        void reset (\n        ) const;\n\n        bool current_element_valid (\n        ) const;\n\n        const S& element (\n        ) const;\n\n        const S& element (\n        );\n\n        bool move_next (\n        ) const;\n\n        size_t size (\n        ) const;\n\n        unsigned long get_selected (\n        ) const;\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n    private:\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        template <typename SS>\n        struct data\n        {\n            SS name;\n            bool is_selected;\n            unsigned long width;\n            unsigned long height;\n        };\n\n        bool ms_enabled;\n        array<data<S> > items;\n        any_function<void(unsigned long)> event_handler;\n        any_function<void(unsigned long)> single_click_event_handler;\n        unsigned long last_selected;\n\n        std::unique_ptr<list_box_style> style;\n\n        // restricted functions\n        list_box(list_box&);        // copy constructor\n        list_box& operator=(list_box&);    // assignment operator\n    };\n    }\n    typedef list_box_helper::list_box<std::string> list_box;\n    typedef list_box_helper::list_box<std::wstring> wlist_box;\n    typedef list_box_helper::list_box<dlib::ustring> ulist_box;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function open_file_box() \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace open_file_box_helper\n    {\n        class box_win : public drawable_window\n        {\n        public:\n            box_win (\n                const std::string& title,\n                bool has_text_field = false\n            );\n\n            ~box_win (\n            );\n\n            void set_click_handler (\n                const any_function<void(const std::string&)>& event_handler_\n            )\n            {\n                auto_mutex M(wm);\n                event_handler = event_handler_;\n            }\n\n        private:\n\n            void set_sizes(\n            );\n\n            void on_window_resized (\n            );\n\n            void deleter_thread (\n            );\n\n            void enter_folder (\n                const std::string& folder_name\n            );\n\n            void on_dirs_click (\n                unsigned long idx\n            );\n\n            void on_files_click (\n                unsigned long idx\n            );\n\n            void on_files_double_click (\n                unsigned long \n            );\n\n            void on_cancel_click (\n            );\n\n            void on_open_click (\n            );\n\n            void on_path_button_click (\n                toggle_button& btn\n            );\n\n            bool set_dir (\n                const std::string& dir\n            );\n\n            void on_root_click (\n            );\n\n            on_close_return_code on_window_close (\n            );\n\n            label lbl_dirs;\n            label lbl_files;\n            label lbl_file_name;\n            list_box lb_dirs;\n            list_box lb_files;\n            button btn_ok;\n            button btn_cancel;\n            toggle_button btn_root;\n            text_field tf_file_name;\n            std::string path;\n            std::string prefix;\n            int cur_dir;\n\n            any_function<void(const std::string&)> event_handler;\n            sequence<std::unique_ptr<toggle_button> >::kernel_2a_c sob;\n        };\n    }\n\n    template <\n        typename T\n        >\n    void open_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Open File\",true);\n        win->set_click_handler(make_mfp(object,event_handler));\n    }\n\n    inline void open_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Open File\",true);\n        win->set_click_handler(event_handler);\n    }\n\n    template <\n        typename T\n        >\n    void open_existing_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Open File\");\n        win->set_click_handler(make_mfp(object,event_handler));\n    }\n\n    inline void open_existing_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Open File\");\n        win->set_click_handler(event_handler);\n    }\n\n    template <\n        typename T\n        >\n    void save_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Save File\",true);\n        win->set_click_handler(make_mfp(object,event_handler));\n    }\n\n    inline void save_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    )\n    {\n        using namespace open_file_box_helper;\n        box_win* win = new box_win(\"Save File\",true);\n        win->set_click_handler(event_handler);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class menu_bar\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class menu_bar : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - menus.size() == 0\n                - open_menu == 0 \n\n            CONVENTION \n                - size() == menus.size() \n                - all menu data is stored in menus\n                - menus[x].name == the name of the xth menu\n                - if (menus[x].underline_pos != std::string::npos) then\n                    - menus[x].underline_pos == the position of the character in the\n                      menu name that should be underlined\n                    - menus[x].underline_p1 != menus[x].underline_p2\n                      and these two points define the underline bar\n                - else\n                    - menus[x].underline_p1 == menus[x].underline_p2\n                - menus[x].menu == menu(x)\n                - menus[x].rect == the rectangle in which menus[x].name is drawn\n                - menus[x].bgrect == the rectangle for the xth menu button\n\n                - if (there is an open menu on the screen) then\n                    - open_menu == the index of the open menu from menus \n                - else\n                    - open_menu == menus.size() \n        !*/\n\n    public:\n        menu_bar(\n            drawable_window& w\n        );\n\n        ~menu_bar();\n\n        // this function does nothing\n        void set_pos(long,long){}\n\n        void set_main_font (\n            const std::shared_ptr<font>& f\n        );\n\n        void set_number_of_menus (\n            unsigned long num\n        );\n\n        unsigned long number_of_menus (\n        ) const;\n\n        void set_menu_name (\n            unsigned long idx,\n            const std::string name,\n            char underline_ch = '\\0'\n        );\n\n        void set_menu_name (\n            unsigned long idx,\n            const std::wstring name,\n            char underline_ch = '\\0'\n        );\n\n        void set_menu_name (\n            unsigned long idx,\n            const dlib::ustring name,\n            char underline_ch = '\\0'\n        );\n\n        const std::string menu_name (\n            unsigned long idx\n        ) const;\n\n        const std::wstring menu_wname (\n            unsigned long idx\n        ) const;\n\n        const dlib::ustring menu_uname (\n            unsigned long idx\n        ) const;\n\n        popup_menu& menu (\n            unsigned long idx\n        );\n\n        const popup_menu& menu (\n            unsigned long idx\n        ) const;\n\n    protected:\n\n        void on_window_resized (\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        void on_window_moved (\n        );\n\n        void on_focus_lost (\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long ,\n            long x,\n            long y,\n            bool \n        );\n\n        void on_mouse_move (\n            unsigned long ,\n            long x,\n            long y\n        );\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n    private:\n\n        void show_menu (\n            unsigned long i\n        );\n\n        void hide_menu (\n        );\n\n        void on_popup_hide (\n        );\n\n        void compute_menu_geometry (\n        );\n\n        void adjust_position (\n        );\n\n        struct menu_data\n        {\n            menu_data():underline_pos(dlib::ustring::npos){}\n\n            dlib::ustring name;\n            dlib::ustring::size_type underline_pos;\n            popup_menu menu;\n            rectangle rect;\n            rectangle bgrect;\n            point underline_p1;\n            point underline_p2;\n        };\n\n        array<menu_data> menus;\n        unsigned long open_menu;\n\n        // restricted functions\n        menu_bar(menu_bar&);        // copy constructor\n        menu_bar& operator=(menu_bar&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class directed_graph_drawer\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename graph_type>\n    class directed_graph_drawer : public zoomable_region \n    {\n        /*!\n            INITIAL VALUE\n                - edge_selected == false\n                - mouse_drag == false\n                - selected_node == 0\n                - graph_.number_of_nodes() == 0\n                - external_graph.number_of_nodes() == 0\n                - radius == 25\n                - last_mouse_click_in_display == false\n\n            CONVENTION\n                - radius == the radius of the nodes when they aren't zoomed\n                - external_graph and graph_ have the same graph structure\n                - external_graph == graph()\n                - external_graph.node(i) == graph_node(i)\n\n                - if (one of the nodes is selected) then\n                    - selected_node < graph_.number_of_nodes()\n                    - graph_.node(selected_node) == the selected node\n                - else\n                    - selected_node == graph_.number_of_nodes()\n\n                - if (the user is dragging a node with the mouse) then\n                    - mouse_drag == true\n                    - drag_offset == the vector from the mouse position to the\n                      center of the node\n                - else\n                    - mouse_drag == false\n\n                - if (the user has selected an edge) then\n                    - edge_selected == true\n                    - the parent node is graph_.node(selected_edge_parent)\n                    - the child node is graph_.node(selected_edge_parent)\n                - else\n                    - edge_selected == false\n\n                - for all valid i:\n                    - graph_.node(i).data.p == the center of the node in graph space\n                    - graph_.node(i).data.name == node_label(i) \n                    - graph_.node(i).data.color == node_color(i) \n                    - graph_.node(i).data.str_rect == a rectangle sized to contain graph_.node(i).data.name\n\n                - if (the last mouse click in our parent window as in our display_rect_ ) then\n                    - last_mouse_click_in_display == true\n                - else\n                    - last_mouse_click_in_display == false\n        !*/\n\n    public:\n        directed_graph_drawer (\n            drawable_window& w\n        ) :\n            zoomable_region(w,MOUSE_CLICK | MOUSE_WHEEL | KEYBOARD_EVENTS),\n            radius(25),\n            edge_selected(false),\n            last_mouse_click_in_display(false)\n        {\n            mouse_drag = false;\n            selected_node = 0;\n\n            // Whenever you make your own drawable (or inherit from draggable or button_action)\n            // you have to remember to call this function to enable the events.  The idea\n            // here is that you can perform whatever setup you need to do to get your \n            // object into a valid state without needing to worry about event handlers \n            // triggering before you are ready.\n            enable_events();\n        }\n\n        ~directed_graph_drawer (\n        )\n        {\n            // Disable all further events for this drawable object.  We have to do this \n            // because we don't want draw() events coming to this object while or after \n            // it has been destructed.\n            disable_events();\n\n            // Tell the parent window to redraw its area that previously contained this\n            // drawable object.\n            parent.invalidate_rectangle(rect);\n        }\n\n        void clear_graph (\n        )\n        {\n            auto_mutex M(m);\n            graph_.clear();\n            external_graph.clear();\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        const typename graph_type::node_type& graph_node (\n            unsigned long i\n        )  const\n        {\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tgraph_type::node_type& directed_graph_drawer::graph_node(i)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            return external_graph.node(i);\n        }\n\n        typename graph_type::node_type& graph_node (\n            unsigned long i\n        ) \n        {\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tgraph_type::node_type& directed_graph_drawer::graph_node(i)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            return external_graph.node(i);\n        }\n\n        const graph_type& graph (\n        ) const\n        {\n            return external_graph;\n        }\n\n        void save_graph (\n            std::ostream& out\n        )\n        {\n            auto_mutex M(m);\n            serialize(external_graph, out);\n            serialize(graph_, out);\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        void load_graph (\n            std::istream& in \n        )\n        {\n            auto_mutex M(m);\n            deserialize(external_graph, in);\n            deserialize(graph_, in);\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        unsigned long number_of_nodes (\n        ) const\n        {\n            auto_mutex M(m);\n            return graph_.number_of_nodes();\n        }\n\n        void set_node_label (\n            unsigned long i,\n            const std::string& label\n        )\n        {\n            set_node_label(i, convert_to_utf32(label));\n        }\n\n        void set_node_label (\n            unsigned long i,\n            const std::wstring& label\n        )\n        {\n            set_node_label(i, convert_to_utf32(label));\n        }\n\n        void set_node_label (\n            unsigned long i,\n            const dlib::ustring& label\n        )\n        {\n            auto_mutex M(m);\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tvoid directed_graph_drawer::set_node_label(i,label)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tlabel:             \" << narrow(label) \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            graph_.node(i).data.name = label.c_str();\n            unsigned long width, height;\n            mfont->compute_size(label,width,height);\n            graph_.node(i).data.str_rect = rectangle(width,height);\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        void set_node_color (\n            unsigned long i,\n            rgb_pixel color\n        )\n        {\n            auto_mutex M(m);\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tvoid directed_graph_drawer::set_node_color(i,label)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            graph_.node(i).data.color = color;\n            parent.invalidate_rectangle(display_rect());\n        }\n\n        rgb_pixel node_color (\n            unsigned long i\n        ) const\n        {\n            auto_mutex M(m);\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\trgb_pixel directed_graph_drawer::node_color(i)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            return graph_.node(i).data.color;\n        }\n\n        const std::string node_label (\n            unsigned long i\n        ) const\n        {\n            auto_mutex M(m);\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tconst std::ustring directed_graph_drawer::node_label(i)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            return narrow(graph_.node(i).data.name);\n        }\n\n        const std::wstring node_wlabel (\n            unsigned long i\n        ) const\n        {\n            return convert_utf32_to_wstring(node_ulabel(i));\n        }\n\n        const dlib::ustring node_ulabel (\n            unsigned long i\n        ) const\n        {\n            auto_mutex M(m);\n            DLIB_ASSERT ( i < number_of_nodes() ,\n                    \"\\tconst std::ustring directed_graph_drawer::node_label(i)\"\n                    << \"\\n\\ti:                 \" << i \n                    << \"\\n\\tnumber_of_nodes(): \" << number_of_nodes() \n                    );\n            return graph_.node(i).data.name.c_str();\n        }\n\n        template <\n            typename T\n            >\n        void set_node_selected_handler (\n            T& object,\n            void (T::*event_handler_)(unsigned long)\n        )\n        {\n            auto_mutex M(m);\n            node_selected_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_node_selected_handler (\n            const any_function<void(unsigned long)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            node_selected_handler = event_handler_;\n        }\n\n        template <\n            typename T\n            >\n        void set_node_deselected_handler (\n            T& object,\n            void (T::*event_handler_)(unsigned long)\n        )\n        {\n            auto_mutex M(m);\n            node_deselected_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_node_deselected_handler (\n            const any_function<void(unsigned long)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            node_deselected_handler = event_handler_;\n        }\n\n        template <\n            typename T\n            >\n        void set_node_deleted_handler (\n            T& object,\n            void (T::*event_handler_)()\n        )\n        {\n            auto_mutex M(m);\n            node_deleted_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_node_deleted_handler (\n            const any_function<void()>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            node_deleted_handler = event_handler_;\n        }\n\n        template <\n            typename T\n            >\n        void set_graph_modified_handler (\n            T& object,\n            void (T::*event_handler_)()\n        )\n        {\n            auto_mutex M(m);\n            graph_modified_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_graph_modified_handler (\n            const any_function<void()>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            graph_modified_handler = event_handler_;\n        }\n\n    protected:\n\n        void on_keydown (\n            unsigned long key,          \n            bool ,\n            unsigned long \n        )\n        {\n            // ignore all keyboard input if the last thing the user clicked on \n            // wasn't the display area\n            if (last_mouse_click_in_display == false)\n                return;\n\n            // if a node is selected\n            if (selected_node != graph_.number_of_nodes())\n            {\n                // deselect the node if the user hits escape\n                if (key == base_window::KEY_ESC)\n                {\n                    parent.invalidate_rectangle(display_rect());\n                    if (node_deselected_handler.is_set())\n                        node_deselected_handler(selected_node);\n                    selected_node = graph_.number_of_nodes();\n                }\n\n                // delete the node if the user hits delete \n                if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)\n                {\n                    parent.invalidate_rectangle(display_rect());\n                    graph_.remove_node(selected_node);\n                    external_graph.remove_node(selected_node);\n                    selected_node = graph_.number_of_nodes();\n                    mouse_drag = false;\n                    if (graph_modified_handler.is_set())\n                        graph_modified_handler();\n                    if (node_deleted_handler.is_set())\n                        node_deleted_handler();\n                }\n            }\n\n            // if an edge is selected\n            if (edge_selected)\n            {\n                // deselect the node if the user hits escape\n                if (key == base_window::KEY_ESC)\n                {\n                    parent.invalidate_rectangle(display_rect());\n                    edge_selected = false;\n                }\n\n                // delete the node if the user hits delete \n                if (key == base_window::KEY_DELETE || key == base_window::KEY_BACKSPACE)\n                {\n                    parent.invalidate_rectangle(display_rect());\n                    graph_.remove_edge(selected_edge_parent, selected_edge_child);\n                    external_graph.remove_edge(selected_edge_parent, selected_edge_child);\n                    edge_selected = false;\n\n                    if (graph_modified_handler.is_set())\n                        graph_modified_handler();\n                }\n            }\n        }\n\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        )\n        {\n            if (mouse_drag)\n            {\n                const point p(nearest_point(display_rect(),point(x,y)));\n\n                point center = drag_offset + p;\n                graph_.node(selected_node).data.p = gui_to_graph_space(center);\n                parent.invalidate_rectangle(display_rect());\n            }\n            else\n            {\n                zoomable_region::on_mouse_move(state,x,y);\n            }\n\n            // check if the mouse isn't being dragged anymore\n            if ((state & base_window::LEFT) == 0)\n            {\n                mouse_drag = false;\n            }\n        }\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        )\n        {\n            mouse_drag = false;\n            zoomable_region::on_mouse_up(btn,state,x,y);\n        }\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        )\n        {\n            bool redraw = false;\n\n            if (display_rect().contains(x,y) && \n                (btn == base_window::RIGHT || btn == base_window::LEFT) && \n                (state & base_window::SHIFT) == 0 )\n            {\n                // start out saying no edge is selected\n                if (edge_selected)\n                {\n                    edge_selected = false;\n                    redraw = true;\n                }\n\n                bool click_hit_node = false;\n                dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));\n                // check if this click is on an existing node\n                for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)\n                {\n                    dlib::vector<double,2> n(graph_.node(i).data.p);\n                    if ((p-n).length() < radius)\n                    {\n                        click_hit_node = true;\n                        point center = graph_to_gui_space(graph_.node(i).data.p);\n                        mouse_drag = true;\n                        drag_offset = center - point(x,y);\n\n                        // only do something if the click isn't on the currently\n                        // selected node\n                        if (selected_node != i)\n                        {\n                            // send out the deselected event if appropriate\n                            if (selected_node != graph_.number_of_nodes() && node_deselected_handler.is_set())\n                                node_deselected_handler(selected_node);\n\n                            selected_node = i;\n                            redraw = true;\n                            if (node_selected_handler.is_set())\n                                node_selected_handler(selected_node);\n                        }\n                        break;\n                    }\n                }\n\n                // if the click didn't hit any node then make sure nothing is selected\n                if (click_hit_node == false && selected_node != graph_.number_of_nodes())\n                {\n                    if (node_deselected_handler.is_set())\n                        node_deselected_handler(selected_node);\n                    selected_node = graph_.number_of_nodes();\n                    redraw = true;\n                }\n\n\n                // check if this click is on an edge if we didn't click on a node\n                if (click_hit_node == false)\n                {\n                    for (unsigned long n = 0; n < graph_.number_of_nodes() && edge_selected == false; ++n)\n                    {\n                        const dlib::vector<double,2> parent_center(graph_to_gui_space(graph_.node(n).data.p));\n                        for (unsigned long e = 0; e < graph_.node(n).number_of_children() && edge_selected == false; ++e)\n                        {\n                            const dlib::vector<double,2> child_center(graph_to_gui_space(graph_.node(n).child(e).data.p));\n\n                            rectangle area;\n                            area += parent_center;\n                            area += child_center;\n                            // if the point(x,y) is between the two nodes then lets consider it further\n                            if (area.contains(point(x,y)))\n                            {\n                                p = point(x,y);\n                                const dlib::vector<double> z(0,0,1);\n                                // find the distance from the line between the two nodes\n                                const dlib::vector<double,2> perpendicular(z.cross(parent_center-child_center).normalize());\n                                double distance = std::abs((child_center-p).dot(perpendicular));\n                                if (distance < 8)\n                                {\n                                    edge_selected = true;\n                                    selected_edge_parent = n;\n                                    selected_edge_child = graph_.node(n).child(e).index();\n                                    redraw = true;\n                                }\n                            }\n                        }\n                    }\n                }\n\n\n                // if the click didn't land on any node then add a new one if this was\n                // a right mouse button click\n                if (click_hit_node == false && btn == base_window::RIGHT)\n                {\n                    const unsigned long n = graph_.add_node();\n                    external_graph.add_node();\n\n                    graph_.node(n).data.p = gui_to_graph_space(point(x,y));\n\n                    redraw = true;\n                    selected_node = n;\n                    mouse_drag = false;\n                    if (graph_modified_handler.is_set())\n                        graph_modified_handler();\n\n                    if (node_selected_handler.is_set())\n                        node_selected_handler(selected_node);\n\n                }\n                else if (selected_node == graph_.number_of_nodes())\n                {\n                    // in this case the click landed in the white area between nodes\n                    zoomable_region::on_mouse_down( btn, state, x, y, is_double_click);\n                }\n            }\n\n            // If the user is shift clicking with the mouse then see if we\n            // should add a new edge.\n            if (display_rect().contains(x,y) && \n                btn == base_window::LEFT && \n                (state & base_window::SHIFT) && \n                selected_node != graph_.number_of_nodes() )\n            {\n                dlib::vector<double,2> p(gui_to_graph_space(point(x,y)));\n                // check if this click is on an existing node\n                for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)\n                {\n                    dlib::vector<double,2> n(graph_.node(i).data.p);\n                    if ((p-n).length() < radius)\n                    {\n                        // add the edge if it doesn't already exist and isn't an edge back to \n                        // the same node\n                        if (graph_.has_edge(selected_node,i) == false && selected_node != i &&\n                            graph_.has_edge(i, selected_node) == false)\n                        {\n                            graph_.add_edge(selected_node,i);\n                            external_graph.add_edge(selected_node,i);\n                            redraw = true;\n\n                            if (graph_modified_handler.is_set())\n                                graph_modified_handler();\n                        }\n                        break;\n                    }\n                }\n            }\n\n\n            if (redraw)\n                parent.invalidate_rectangle(display_rect());\n\n\n            if (display_rect().contains(x,y) == false)\n                last_mouse_click_in_display = false;\n            else\n                last_mouse_click_in_display = true;\n        }\n\n        void draw (\n            const canvas& c\n        ) const\n        {\n            zoomable_region::draw(c);\n\n            rectangle area = c.intersect(display_rect());\n            if (area.is_empty() == true)\n                return;\n\n\n            if (enabled)\n                fill_rect(c,display_rect(),255);\n            else\n                fill_rect(c,display_rect(),128);\n\n\n            const unsigned long rad = static_cast<unsigned long>(radius*zoom_scale());\n            point center;\n\n\n            // first draw all the edges\n            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)\n            {\n                center = graph_to_gui_space(graph_.node(i).data.p);\n                const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));\n\n                // draw lines to all this node's parents \n                const dlib::vector<double> z(0,0,1);\n                for (unsigned long j = 0; j < graph_.node(i).number_of_parents(); ++j)\n                {\n                    point p(graph_to_gui_space(graph_.node(i).parent(j).data.p));\n\n                    rgb_pixel color(0,0,0);\n                    // if this is the selected edge then draw it with red instead of black\n                    if (edge_selected && selected_edge_child == i && selected_edge_parent == graph_.node(i).parent(j).index())\n                    {\n                        color.red = 255;\n                        // we need to be careful when drawing this line to not draw it over the node dots since it \n                        // has a different color from them and would look weird\n                        dlib::vector<double,2> v(p-center);\n                        v = v.normalize()*rad;\n                        draw_line(c,center+v,p-v ,color, area);\n                    }\n                    else\n                    {\n                        draw_line(c,center,p ,color, area);\n                    }\n\n\n                    // draw the triangle pointing to this node\n                    if (area.intersect(circle_area).is_empty() == false)\n                    {\n                        dlib::vector<double,2> v(p-center);\n                        v = v.normalize();\n\n                        dlib::vector<double,2> cross = z.cross(v).normalize();\n                        dlib::vector<double,2> r(center + v*rad);\n                        for (double i = 0; i < 8*zoom_scale(); i += 0.1)\n                            draw_line(c,(r+v*i)+cross*i, (r+v*i)-cross*i,color,area);\n                    }\n                }\n            }\n\n\n            // now draw all the node dots\n            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)\n            {\n                center = graph_to_gui_space(graph_.node(i).data.p);\n                const rectangle circle_area(centered_rect(center,2*(rad+8),2*(rad+8)));\n\n                // draw the actual dot for this node\n                if (area.intersect(circle_area).is_empty()==false)\n                {\n                    rgb_alpha_pixel color;\n                    assign_pixel(color, graph_.node(i).data.color);\n                    // this node is in area so lets draw it and all of its edges as well\n                    draw_solid_circle(c,center,rad-3,color,area);\n                    color.alpha = 240;\n                    draw_circle(c,center,rad-3,color,area);\n                    color.alpha = 200;\n                    draw_circle(c,center,rad-2.5,color,area);\n                    color.alpha = 160;\n                    draw_circle(c,center,rad-2.0,color,area);\n                    color.alpha = 120;\n                    draw_circle(c,center,rad-1.5,color,area);\n                    color.alpha = 80;\n                    draw_circle(c,center,rad-1.0,color,area);\n                    color.alpha = 40;\n                    draw_circle(c,center,rad-0.5,color,area);\n\n                }\n\n\n                if (i == selected_node)\n                    draw_circle(c,center,rad+5,rgb_pixel(0,0,255),area);\n            }\n\n\n            // now draw all the strings last\n            for (unsigned long i = 0; i < graph_.number_of_nodes(); ++i)\n            {\n                center = graph_to_gui_space(graph_.node(i).data.p);\n                rectangle circle_area(centered_rect(center,2*rad+3,2*rad+3));\n                if (area.intersect(circle_area).is_empty()==false)\n                {\n                    rgb_pixel color = graph_.node(i).data.color;\n                    // invert this color\n                    color.red = 255-color.red;\n                    color.green = 255-color.green;\n                    color.blue = 255-color.blue;\n                    sout << i;\n                    unsigned long width, height;\n                    mfont->compute_size(sout.str(),width,height);\n                    rectangle str_rect(centered_rect(center, width,height));\n                    if (circle_area.contains(str_rect))\n                    {\n                        mfont->draw_string(c,str_rect,sout.str(),color,0,std::string::npos,area);\n\n                        // draw the label for this node if it isn't empty\n                        if(graph_.node(i).data.name.size() > 0)\n                        {\n                            rectangle str_rect(graph_.node(i).data.str_rect);\n                            str_rect = centered_rect(center.x(), center.y()-rad-mfont->height(),  str_rect.width(), str_rect.height());\n                            mfont->draw_string(c,str_rect,graph_.node(i).data.name,0,0,std::string::npos,area);\n                        }\n                    }\n                    sout.str(\"\");\n                }\n            }\n        }\n\n    private:\n\n        struct data\n        {\n            data() : color(0,0,0) {}\n            vector<double> p;\n            dlib::ustring name;\n            rectangle str_rect;\n            rgb_pixel color;\n        };\n\n        friend void serialize(const data& item, std::ostream& out)\n        {\n            serialize(item.p, out);\n            serialize(item.name, out);\n            serialize(item.str_rect, out);\n            serialize(item.color, out);\n        }\n\n        friend void deserialize(data& item, std::istream& in)\n        {\n            deserialize(item.p, in);\n            deserialize(item.name, in);\n            deserialize(item.str_rect, in);\n            deserialize(item.color, in);\n        }\n\n        mutable std::ostringstream sout;\n\n        const double radius;\n        unsigned long selected_node;\n        bool mouse_drag; // true if the user is dragging a node\n        point drag_offset; \n\n        bool edge_selected;\n        unsigned long selected_edge_parent;\n        unsigned long selected_edge_child;\n\n        any_function<void(unsigned long)> node_selected_handler;\n        any_function<void(unsigned long)> node_deselected_handler;\n        any_function<void()> node_deleted_handler;\n        any_function<void()> graph_modified_handler;\n\n        graph_type external_graph;\n        // rebind the graph_ type to make us a graph_ of data structs\n        typename graph_type::template rebind<data,char, typename graph_type::mem_manager_type>::other graph_;\n\n        bool last_mouse_click_in_display;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class text_grid\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_grid : public scrollable_region \n    {\n        /*!\n            INITIAL VALUE\n                - has_focus == false\n                - vertical_scroll_increment() == 10\n                - horizontal_scroll_increment() == 10\n                - border_color_ == rgb_pixel(128,128,128)\n\n            CONVENTION\n                - grid.nr() == row_height.size()\n                - grid.nc() == col_width.size()\n                - border_color() == border_color_\n                - text(r,c) == grid[r][c].text\n                - text_color(r,c) == grid[r][c].text_color\n                - background_color(r,c) == grid[r][c].bg_color\n\n                - if (the user has clicked on this widget and caused one of the\n                    boxes to have input focus) then\n                    - has_focus == true\n                    - grid[active_row][active_col] == the active text box\n                    - cursor_pos == the position of the cursor in the above box\n                    - if (the cursor should be displayed) then\n                        - show_cursor == true\n                    - else\n                        - show_cursor == false\n                - else\n                    - has_focus == false\n        !*/\n\n    public:\n        text_grid (\n            drawable_window& w\n        ); \n\n        ~text_grid (\n        );\n\n        void set_grid_size (\n            unsigned long rows,\n            unsigned long cols\n        );\n\n        unsigned long number_of_columns (\n        ) const;\n\n        unsigned long number_of_rows (\n        ) const;\n\n        int next_free_user_event_number (\n        ) const;\n\n        rgb_pixel border_color (\n        ) const;\n\n        void set_border_color (\n            rgb_pixel color\n        );\n\n        const std::string text (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        const std::wstring wtext (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        const dlib::ustring utext (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        void set_text (\n            unsigned long row,\n            unsigned long col,\n            const std::string& str\n        );\n\n        void set_text (\n            unsigned long row,\n            unsigned long col,\n            const std::wstring& str\n        );\n\n        void set_text (\n            unsigned long row,\n            unsigned long col,\n            const dlib::ustring& str\n        );\n\n        const rgb_pixel text_color (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        void set_text_color (\n            unsigned long row,\n            unsigned long col,\n            const rgb_pixel color\n        );\n\n        const rgb_pixel background_color (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        void set_background_color (\n            unsigned long row,\n            unsigned long col,\n            const rgb_pixel color\n        );\n\n        bool is_editable (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        void set_editable (\n            unsigned long row,\n            unsigned long col,\n            bool editable\n        );\n\n        void set_column_width (\n            unsigned long col,\n            unsigned long width\n        );\n\n        void set_row_height (\n            unsigned long row,\n            unsigned long height \n        );\n\n        void disable (\n        );\n\n        void hide (\n        );\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*eh)(unsigned long, unsigned long)\n        ) { text_modified_handler = make_mfp(object,eh); }\n\n        void set_text_modified_handler (\n            const any_function<void(unsigned long, unsigned long)>& eh\n        ) { text_modified_handler = eh; }\n\n    private:\n\n        void on_user_event (\n            int num\n        );\n\n        void timer_action (\n        ); \n        /*!\n            ensures\n                - flips the state of show_cursor \n        !*/\n\n        void compute_bg_rects (\n        );\n\n        void compute_total_rect (\n        );\n\n        void on_keydown (\n            unsigned long key,          \n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_focus_lost (\n        );\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        rectangle get_text_rect (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        rectangle get_bg_rect (\n            unsigned long row,\n            unsigned long col\n        ) const;\n\n        struct data_type\n        {\n            data_type(): text_color(0,0,0), bg_color(255,255,255),\n            first(0), is_editable(true) \n            {}\n\n            dlib::ustring text;\n            rgb_pixel text_color;\n            rgb_pixel bg_color;\n            rectangle bg_rect;\n            dlib::ustring::size_type first;\n            bool is_editable;\n        };\n\n        void drop_input_focus (\n        );\n\n        void move_cursor (\n            long row,\n            long col,\n            long new_cursor_pos\n        );\n\n        array2d<data_type> grid;\n        array<unsigned long> col_width;\n        array<unsigned long> row_height;\n        bool has_focus;\n        long active_col;\n        long active_row;\n        long cursor_pos;\n        bool show_cursor;\n        bool recent_cursor_move;\n        timer<text_grid> cursor_timer;\n        rgb_pixel border_color_;\n        any_function<void(unsigned long, unsigned long)> text_modified_handler;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class image_display : public scrollable_region \n    {\n        /*!\n            INITIAL VALUE\n                - img.size() == 0\n                - overlay_rects.size() == 0\n                - overlay_lines.size() == 0\n                - drawing_rect == false\n                - rect_is_selected == false\n\n            CONVENTION\n                - img == the image this object displays\n                - overlay_rects == the overlay rectangles this object displays\n                - overlay_lines == the overlay lines this object displays\n\n                - if (drawing_rect) then\n                    - the user is drawing a rectangle on the screen and is\n                      thus holding down CTRL and the left mouse button.\n                    - rect_anchor == the point on the screen where the user\n                      clicked to begin drawing the rectangle.  \n                    - rect_to_draw == the rectangle which should appear on the screen.\n\n                - if (rect_is_selected) then\n                    - selected_rect == the index in overlay_rects of the user selected\n                      rectangle.\n                    - last_right_click_pos == the last place we saw the user right click\n                      the mouse.\n                    - parts_menu.is_enabled() == true\n                    - if (it is actually a part of this rect that is selected) then\n                        - selected_part_name == the name of the part in overlay_rects[selected_rect].parts\n                          that is selected.\n                    - else\n                        - selected_part_name.size() == 0\n                - else\n                    - parts_menu.is_enabled() == false\n                    - selected_part_name.size() == 0\n\n                - if (moving_overlay) then\n                    - moving_rect == the index in overlay_rects that the move applies to.  \n                    - if (moving_what == MOVING_PART) then\n                        - moving_part_name == the name of the part in\n                          overlay_rects[moving_rect] that is being moved around with the\n                          mouse.\n                    - else\n                        - moving_what will tell us which side of the rectangle in\n                          overlay_rects[moving_rect] is being moved by the mouse.\n        !*/\n\n    public:\n\n        image_display(  \n            drawable_window& w\n        );\n\n        ~image_display(\n        );\n\n        template <\n            typename image_type\n            >\n        void set_image (\n            const image_type& new_img\n        )\n        {\n            auto_mutex M(m);\n\n            // if the new image has a different size when compared to the previous image\n            // then we should readjust the total rectangle size.\n            if (num_rows(new_img) != img.nr() || num_columns(new_img) != img.nc())\n            {\n                if (zoom_in_scale != 1)\n                    set_total_rect_size(num_columns(new_img)*zoom_in_scale, num_rows(new_img)*zoom_in_scale);\n                else\n                    set_total_rect_size(num_columns(new_img)/zoom_out_scale, num_rows(new_img)/zoom_out_scale);\n            }\n            else\n            {\n                parent.invalidate_rectangle(rect);\n            }\n\n            highlighted_rect = std::numeric_limits<unsigned long>::max();\n            rect_is_selected = false;\n            parts_menu.disable();\n            assign_image_scaled(img,new_img);\n        }\n\n        virtual void set_pos (\n            long x,\n            long y\n        )\n        {\n            auto_mutex lock(m);\n            scrollable_region::set_pos(x,y);\n            parts_menu.set_rect(rect);\n        }\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height \n        )\n        {\n            auto_mutex lock(m);\n            scrollable_region::set_size(width,height);\n            parts_menu.set_rect(rect);\n        }\n\n        struct overlay_rect\n        {\n            overlay_rect() :crossed_out(false) { assign_pixel(color, 0);}\n\n            template <typename pixel_type>\n            overlay_rect(const rectangle& r, pixel_type p) \n                : rect(r),crossed_out(false) { assign_pixel(color, p); }\n\n            template <typename pixel_type>\n            overlay_rect(const rectangle& r, pixel_type p, const std::string& l) \n                : rect(r),label(l),crossed_out(false) { assign_pixel(color, p); }\n\n            template <typename pixel_type>\n            overlay_rect(const rectangle& r, pixel_type p, const std::string& l, const std::map<std::string,point>& parts_) \n                : rect(r),label(l),parts(parts_),crossed_out(false) { assign_pixel(color, p); }\n\n            rectangle rect;\n            rgb_alpha_pixel color;\n            std::string label;\n            std::map<std::string,point> parts;\n            bool crossed_out;\n        };\n\n        struct overlay_line\n        {\n            overlay_line() { assign_pixel(color, 0);}\n\n            template <typename pixel_type>\n            overlay_line(const dpoint& p1_, const dpoint& p2_, pixel_type p) \n                : p1(p1_), p2(p2_) { assign_pixel(color, p); }\n\n            dpoint p1;\n            dpoint p2;\n            rgb_alpha_pixel color;\n        };\n\n        struct overlay_circle\n        {\n            overlay_circle():radius(0) { assign_pixel(color, 0);}\n\n            template <typename pixel_type>\n            overlay_circle(const point& center_, const double radius_, pixel_type p) \n                : center(center_), radius(radius_) { assign_pixel(color, p); }\n\n            template <typename pixel_type>\n            overlay_circle(const point& center_, const double radius_, pixel_type p, const std::string& l) \n                : center(center_), radius(radius_), label(l) { assign_pixel(color, p); }\n\n            point center;\n            double radius;\n            rgb_alpha_pixel color;\n            std::string label;\n        };\n\n        void add_overlay (\n            const overlay_rect& overlay\n        );\n\n        void add_overlay (\n            const overlay_line& overlay\n        );\n\n        void add_overlay (\n            const overlay_circle& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_rect>& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_circle>& overlay\n        );\n\n        void clear_overlay (\n        );\n\n        rectangle get_image_display_rect (\n        ) const;\n\n        std::vector<overlay_rect> get_overlay_rects (\n        ) const;\n\n        void set_default_overlay_rect_label (\n            const std::string& label\n        );\n\n        std::string get_default_overlay_rect_label (\n        ) const;\n\n        void set_default_overlay_rect_color (\n            const rgb_alpha_pixel& color\n        );\n\n        rgb_alpha_pixel get_default_overlay_rect_color (\n        ) const;\n\n        template <\n            typename T\n            >\n        void set_overlay_rects_changed_handler (\n            T& object,\n            void (T::*event_handler_)()\n        )\n        {\n            auto_mutex M(m);\n            event_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_overlay_rects_changed_handler (\n            const any_function<void()>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            event_handler = event_handler_;\n        }\n\n        template <\n            typename T\n            >\n        void set_overlay_rect_selected_handler (\n            T& object,\n            void (T::*event_handler_)(const overlay_rect& orect)\n        )\n        {\n            auto_mutex M(m);\n            orect_selected_event_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_overlay_rect_selected_handler (\n            const any_function<void(const overlay_rect& orect)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            orect_selected_event_handler = event_handler_;\n        }\n\n        template <\n            typename T\n            >\n        void set_image_clicked_handler (\n            T& object,\n            void (T::*event_handler_)(const point& p, bool is_double_click, unsigned long btn)\n        )\n        {\n            auto_mutex M(m);\n            image_clicked_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_image_clicked_handler (\n            const any_function<void(const point& p, bool is_double_click, unsigned long btn)>& event_handler_\n        )\n        {\n            auto_mutex M(m);\n            image_clicked_handler = event_handler_;\n        }\n\n        void add_labelable_part_name (\n            const std::string& name\n        );\n\n        void clear_labelable_part_names (\n        );\n\n        void enable_overlay_editing (\n        ) { auto_mutex M(m); overlay_editing_enabled = true; }\n\n        void disable_overlay_editing (\n        ) \n        { \n            auto_mutex M(m); \n            overlay_editing_enabled = false;  \n            rect_is_selected = false;\n            drawing_rect = false;\n            parent.invalidate_rectangle(rect);\n        }\n        \n        bool overlay_editing_is_enabled (\n        ) const { auto_mutex M(m); return overlay_editing_enabled; }\n\n        void zoom_in (\n        );\n\n        void zoom_out (\n        );\n\n    private:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        void on_wheel_up (\n            unsigned long state\n        );\n\n        void on_wheel_down (\n            unsigned long state\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_up (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        void on_part_add (\n            const std::string& part_name\n        );\n\n        rectangle get_rect_on_screen (\n            unsigned long idx\n        ) const;\n\n        rectangle get_rect_on_screen (\n            rectangle orect \n        ) const;\n\n        rgb_alpha_pixel invert_pixel (const rgb_alpha_pixel& p) const\n        { return rgb_alpha_pixel(255-p.red, 255-p.green, 255-p.blue, p.alpha); }\n\n        virtual int next_free_user_event_number (\n        ) const { return scrollable_region::next_free_user_event_number()+1; }\n        // The reason for using user actions here rather than just having the timer just call\n        // what it needs directly is to avoid a potential deadlock during destruction of this widget.\n        void timer_event_unhighlight_rect()\n        { \n            highlight_timer.stop(); \n            parent.trigger_user_event(this,scrollable_region::next_free_user_event_number()); \n        }\n        void on_user_event (int num)\n        {\n            // ignore this user event if it isn't for us\n            if (num != scrollable_region::next_free_user_event_number())\n                return;\n            if (highlighted_rect < overlay_rects.size())\n            {\n                highlighted_rect = std::numeric_limits<unsigned long>::max();\n                parent.invalidate_rectangle(rect);\n            }\n        }\n\n\n        array2d<rgb_alpha_pixel> img;\n\n\n        std::vector<overlay_rect> overlay_rects;\n        std::vector<overlay_line> overlay_lines;\n        std::vector<overlay_circle> overlay_circles;\n\n        long zoom_in_scale;\n        long zoom_out_scale;\n        bool drawing_rect;\n        point rect_anchor;\n        rectangle rect_to_draw;\n        bool rect_is_selected;\n        std::string selected_part_name;\n        unsigned long selected_rect;\n        rgb_alpha_pixel default_rect_color;\n        std::string default_rect_label;\n        any_function<void()> event_handler;\n        any_function<void(const overlay_rect& orect)> orect_selected_event_handler;\n        any_function<void(const point& p, bool is_double_click, unsigned long btn)> image_clicked_handler;\n        popup_menu_region parts_menu;\n        point last_right_click_pos;\n        const double part_width;\n        std::set<std::string> part_names;\n        bool overlay_editing_enabled;\n        timer<image_display> highlight_timer;\n        unsigned long highlighted_rect;\n        bool holding_shift_key;\n\n        bool moving_overlay;\n        unsigned long moving_rect;\n        enum  {\n            MOVING_RECT_LEFT,\n            MOVING_RECT_TOP,\n            MOVING_RECT_RIGHT,\n            MOVING_RECT_BOTTOM,\n            MOVING_PART\n        } moving_what;\n        std::string moving_part_name;\n\n        // restricted functions\n        image_display(image_display&);        // copy constructor\n        image_display& operator=(image_display&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class perspective_display : public drawable, noncopyable\n    {\n    public:\n\n        perspective_display(  \n            drawable_window& w\n        );\n\n        ~perspective_display(\n        );\n\n        virtual void set_size (\n            unsigned long width,\n            unsigned long height \n        );\n\n        struct overlay_line\n        {\n            overlay_line() { assign_pixel(color, 0);}\n\n            overlay_line(const vector<double>& p1_, const vector<double>& p2_) \n                : p1(p1_), p2(p2_) { assign_pixel(color, 255); }\n\n            template <typename pixel_type>\n            overlay_line(const vector<double>& p1_, const vector<double>& p2_, pixel_type p) \n                : p1(p1_), p2(p2_) { assign_pixel(color, p); }\n\n            vector<double> p1;\n            vector<double> p2;\n            rgb_pixel color;\n        };\n\n        struct overlay_dot\n        {\n            overlay_dot() { assign_pixel(color, 0);}\n\n            overlay_dot(const vector<double>& p_) \n                : p(p_) { assign_pixel(color, 255); }\n\n            template <typename pixel_type>\n            overlay_dot(const vector<double>& p_, pixel_type color_) \n                : p(p_) { assign_pixel(color, color_); }\n\n            vector<double> p;\n            rgb_pixel color;\n        };\n\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_dot>& overlay\n        );\n\n        void clear_overlay (\n        );\n\n        template <\n            typename T\n            >\n        void set_dot_double_clicked_handler (\n            T& object,\n            void (T::*event_handler_)(const vector<double>&)\n        )\n        {\n            auto_mutex M(m);\n            dot_clicked_event_handler = make_mfp(object,event_handler_);\n        }\n\n        void set_dot_double_clicked_handler (\n            const any_function<void(const vector<double>&)>& event_handler_\n        );\n\n    private:\n\n        void draw (\n            const canvas& c\n        ) const;\n\n        void on_wheel_up (\n            unsigned long state\n        );\n\n        void on_wheel_down (\n            unsigned long state\n        );\n\n        void on_mouse_down (\n            unsigned long btn,\n            unsigned long state,\n            long x,\n            long y,\n            bool is_double_click\n        );\n\n        void on_mouse_move (\n            unsigned long state,\n            long x,\n            long y\n        );\n\n        static bool compare_second (\n            const std::pair<overlay_dot,float>& a,\n            const std::pair<overlay_dot,float>& b\n        ) { return a.second < b.second; }\n\n\n        point last;\n        std::vector<overlay_line> overlay_lines;\n        std::vector<overlay_dot> overlay_dots;\n\n        camera_transform tform;\n        vector<double> sum_pts;\n        vector<double> max_pts;\n        any_function<void(const vector<double>&)> dot_clicked_event_handler;\n        mutable array2d<float> depth;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class perspective_window : public drawable_window, noncopyable\n    {\n    public:\n\n        typedef perspective_display::overlay_line overlay_line;\n        typedef perspective_display::overlay_dot overlay_dot;\n\n        perspective_window(\n        ) : disp(*this) \n        {\n            set_size(100,100);\n            on_window_resized();\n            show();\n        }\n\n        perspective_window(\n            const std::vector<dlib::vector<double> >& point_cloud\n        ) : \n            disp(*this)\n        {  \n            set_size(100,100);\n            on_window_resized();\n            add_overlay(point_cloud); \n            show(); \n        }\n        \n        perspective_window(\n            const std::vector<dlib::vector<double> >& point_cloud,\n            const std::string& title\n        ) : \n            disp(*this)\n        {  \n            set_size(100,100);\n            on_window_resized();\n            add_overlay(point_cloud); \n            set_title(title);\n            show(); \n        }\n        \n        ~perspective_window(\n        )\n        {\n            // You should always call close_window() in the destructor of window\n            // objects to ensure that no events will be sent to this window while \n            // it is being destructed.  \n            close_window();\n        }\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        )\n        {\n            disp.add_overlay(overlay);\n        }\n\n        void add_overlay (\n            const std::vector<overlay_dot>& overlay\n        )\n        {\n            disp.add_overlay(overlay);\n        }\n\n        void clear_overlay (\n        )\n        {\n            disp.clear_overlay();\n        }\n\n        template <typename pixel_type>\n        void add_overlay(const vector<double>& p1, const vector<double>& p2, pixel_type p)\n        {\n            add_overlay(std::vector<overlay_line>(1,overlay_line(p1,p2,p)));\n        }\n\n        void add_overlay(const std::vector<dlib::vector<double> >& d) \n        { \n            add_overlay(d, 255);\n        }\n\n        template <typename pixel_type>\n        void add_overlay(const std::vector<dlib::vector<double> >& d, pixel_type p) \n        { \n            std::vector<overlay_dot> temp;\n            temp.resize(d.size());\n            for (unsigned long i = 0; i < temp.size(); ++i)\n                temp[i] = overlay_dot(d[i], p);\n\n            add_overlay(temp);\n        }\n\n        template <\n            typename T\n            >\n        void set_dot_double_clicked_handler (\n            T& object,\n            void (T::*event_handler_)(const vector<double>&)\n        )\n        {\n            disp.set_dot_double_clicked_handler(object,event_handler_);\n        }\n\n        void set_dot_double_clicked_handler (\n            const any_function<void(const vector<double>&)>& event_handler_\n        )\n        {\n            disp.set_dot_double_clicked_handler(event_handler_);\n        }\n\n    private:\n\n        void on_window_resized(\n        )\n        {\n            drawable_window::on_window_resized();\n            unsigned long width, height;\n            get_size(width,height);\n            disp.set_pos(0,0);\n            disp.set_size(width, height);\n        }\n        \n        perspective_display disp;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class image_window : public drawable_window \n    {\n    public:\n\n        typedef image_display::overlay_rect overlay_rect;\n        typedef image_display::overlay_line overlay_line;\n        typedef image_display::overlay_circle overlay_circle;\n\n        image_window(\n        ); \n\n        template < typename image_type >\n        image_window(\n            const image_type& img\n        ) : \n            gui_img(*this), \n            window_has_closed(false),\n            have_last_click(false),\n            mouse_btn(0),\n            clicked_signaler(this->wm),\n            have_last_keypress(false),\n            tie_input_events(false)\n        {  \n            gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);\n            gui_img.disable_overlay_editing();\n            set_image(img); \n            show(); \n        }\n        \n        template < typename image_type >\n        image_window(\n            const image_type& img,\n            const std::string& title\n        ) : \n            gui_img(*this), \n            window_has_closed(false),\n            have_last_click(false),\n            mouse_btn(0),\n            clicked_signaler(this->wm),\n            have_last_keypress(false),\n            tie_input_events(false)\n        {  \n            gui_img.set_image_clicked_handler(*this, &image_window::on_image_clicked);\n            gui_img.disable_overlay_editing();\n            set_image(img); \n            set_title(title);\n            show(); \n        }\n        \n\n        ~image_window(\n        );\n\n        template < typename image_type >\n        void set_image (\n            const image_type& img\n        ) \n        { \n            const unsigned long padding = scrollable_region_style_default().get_border_size();\n            auto_mutex M(wm);\n            gui_img.set_image(img); \n\n            // Only ever mess with the size of the window if the user is giving us an image\n            // that is a different size.  Otherwise we assume that they will have already\n            // sized the window to whatever they feel is reasonable for an image of the\n            // current size.  \n            if (previous_image_size != get_rect(img))\n            {\n                const rectangle r = gui_img.get_image_display_rect();\n                if (image_rect != r)\n                {\n                    // set the size of this window to match the size of the input image\n                    set_size(r.width()+padding*2,r.height()+padding*2);\n\n                    // call this to make sure everything else is setup properly\n                    on_window_resized();\n\n                    image_rect = r;\n                }\n                previous_image_size = get_rect(img);\n            }\n        }\n\n        void add_overlay (\n            const overlay_rect& overlay\n        );\n\n        template <typename pixel_type>\n        void add_overlay(const rectangle& r, pixel_type p) \n        { add_overlay(image_display::overlay_rect(r,p)); }\n\n        void add_overlay(const rectangle& r) \n        { add_overlay(image_display::overlay_rect(r,rgb_pixel(255,0,0))); }\n\n        template <typename pixel_type>\n        void add_overlay(const rectangle& r, pixel_type p, const std::string& l) \n        { add_overlay(image_display::overlay_rect(r,p,l)); }\n\n        template <typename pixel_type>\n        void add_overlay(const std::vector<rectangle>& r, pixel_type p) \n        { \n            std::vector<overlay_rect> temp;\n            temp.resize(r.size());\n            for (unsigned long i = 0; i < temp.size(); ++i)\n                temp[i] = overlay_rect(r[i], p);\n\n            add_overlay(temp);\n        }\n\n        void add_overlay(const std::vector<rectangle>& r) \n        { add_overlay(r, rgb_pixel(255,0,0)); }\n\n        void add_overlay(\n            const full_object_detection& object,\n            const std::vector<std::string>& part_names\n        ) \n        { \n\n            add_overlay(overlay_rect(object.get_rect(), rgb_pixel(255,0,0)));\n\n            std::vector<overlay_circle> temp;\n            temp.reserve(object.num_parts());\n            for (unsigned long i = 0; i < object.num_parts(); ++i)\n            {\n                if (object.part(i) != OBJECT_PART_NOT_PRESENT)\n                {\n                    if (i < part_names.size())\n                        temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0), part_names[i]));\n                    else\n                        temp.push_back(overlay_circle(object.part(i), 7, rgb_pixel(0,255,0)));\n                }\n            }\n\n            add_overlay(temp);\n        }\n\n        void add_overlay(\n            const full_object_detection& object\n        ) \n        { \n            std::vector<std::string> part_names;\n            add_overlay(object, part_names);\n        }\n\n        void add_overlay(\n            const std::vector<full_object_detection>& objects,\n            const std::vector<std::string>& part_names\n        ) \n        { \n            std::vector<overlay_rect> rtemp;\n            rtemp.reserve(objects.size());\n            for (unsigned long i = 0; i < objects.size(); ++i)\n            {\n                rtemp.push_back(overlay_rect(objects[i].get_rect(), rgb_pixel(255,0,0)));\n            }\n\n            add_overlay(rtemp);\n\n            std::vector<overlay_circle> temp;\n\n            for (unsigned long i = 0; i < objects.size(); ++i)\n            {\n                for (unsigned long j = 0; j < objects[i].num_parts(); ++j)\n                {\n                    if (objects[i].part(j) != OBJECT_PART_NOT_PRESENT)\n                    {\n                        if (j < part_names.size())\n                            temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0),part_names[j]));\n                        else\n                            temp.push_back(overlay_circle(objects[i].part(j), 7, rgb_pixel(0,255,0)));\n                    }\n                }\n            }\n\n            add_overlay(temp);\n        }\n\n        void add_overlay(\n            const std::vector<full_object_detection>& objects\n        ) \n        { \n            std::vector<std::string> part_names;\n            add_overlay(objects, part_names);\n        }\n\n        void add_overlay (\n            const overlay_line& overlay\n        );\n\n        template <typename pixel_type>\n        void add_overlay(const line& l, pixel_type p) \n        { \n            add_overlay(image_display::overlay_line(l.p1(),l.p2(),p)); \n        }\n\n        void add_overlay(const line& l) \n        {\n            add_overlay(l, rgb_pixel(255,0,0));\n        }\n\n        void add_overlay (\n            const overlay_circle& overlay\n        );\n\n        template <typename pixel_type>\n        void add_overlay(const point& p1, const point& p2, pixel_type p) \n        { add_overlay(image_display::overlay_line(p1,p2,p)); }\n\n        void add_overlay (\n            const std::vector<overlay_rect>& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n\n        void add_overlay (\n            const std::vector<overlay_circle>& overlay\n        );\n\n        void clear_overlay (\n        );\n\n        bool get_next_double_click (\n            point& p,\n            unsigned long& mouse_button\n        ); \n\n        void tie_events (\n        );\n\n        void untie_events (\n        );\n\n        bool events_tied (\n        ) const;\n\n        bool get_next_double_click (\n            point& p\n        ) \n        {\n            unsigned long mouse_button;\n            return get_next_double_click(p, mouse_button);\n        }\n\n        bool get_next_keypress (\n            unsigned long& key,\n            bool& is_printable,\n            unsigned long& state\n        );\n\n        bool get_next_keypress (\n            unsigned long& key,\n            bool& is_printable\n        )\n        {\n            unsigned long state;\n            return get_next_keypress(key,is_printable,state);\n        }\n\n    private:\n\n        virtual base_window::on_close_return_code on_window_close(\n        );\n\n        void on_window_resized(\n        );\n        \n        void on_image_clicked (\n            const point& p,\n            bool is_double_click,\n            unsigned long btn\n        );\n\n        virtual void on_keydown (\n            unsigned long key,\n            bool is_printable,\n            unsigned long state\n        );\n\n        // restricted functions\n        image_window(image_window&);\n        image_window& operator= (image_window&);\n\n        image_display gui_img;\n        rectangle image_rect;\n        rectangle previous_image_size;\n        bool window_has_closed;\n        bool have_last_click;\n        point last_clicked_point;\n        unsigned long mouse_btn;\n        rsignaler clicked_signaler;\n\n        bool have_last_keypress;\n        unsigned long next_key;\n        bool next_is_printable;\n        unsigned long next_state;\n        bool tie_input_events;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"widgets.cpp\"\n#endif\n\n#endif // DLIB_WIDGETs_\n\n"
  },
  {
    "path": "dlib/gui_widgets/widgets_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net), Keita Mochizuki\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#undef DLIB_WIDGETs_ABSTRACT_\n#ifdef DLIB_WIDGETs_ABSTRACT_\n\n#include \"fonts_abstract.h\"\n#include \"drawable_abstract.h\"\n#include \"base_widgets_abstract.h\"\n\n#include \"../gui_core.h\"\n#include <string>\n#include <map>\n#include \"../interfaces/enumerable.h\"\n#include \"style_abstract.h\"\n#include \"../image_processing/full_object_detection_abstract.h\"\n#include \"../geometry/line_abstract.h\"\n\nnamespace dlib\n{\n\n    /*!\n        GENERAL REMARKS\n            This component is a collection of various windowing widgets such as buttons,\n            labels, text boxes, and so on.  This component also includes the drawable\n            interface, drawable_window, and font handling objects.  The file you are\n            currently viewing defines all the high level graphical widgets which are \n            provided by this component that can appear in a drawable_window.  To view \n            the specifications for the other members of this component look at \n            fonts_abstract.h, base_widgets_abstract.h, and drawable_abstract.h\n\n        THREAD SAFETY\n            All objects and functions defined in this file are thread safe.  You may\n            call them from any thread without serializing access to them.\n\n        EVENT HANDLERS\n            Note that all event handlers, including the user registered callback\n            functions, are executed in the event handling thread.   Additionally,\n            the drawable::m mutex will always be locked while these event handlers\n            are running.  Also, don't rely on get_thread_id() always returning the \n            same ID from inside event handlers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function open_file_box(), open_existing_file_box(), and save_file_box()\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void open_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    );\n    /*!\n        requires\n            - event_handler == a valid pointer to a member function of object T.\n        ensures\n            - Displays a window titled \"Open File\" that will allow the user to select a \n              file.  \n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called on object if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n    void open_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    );\n    /*!\n        ensures\n            - Displays a window titled \"Open File\" that will allow the user to select a \n              file.  \n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void open_existing_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    );\n    /*!\n        requires\n            - event_handler == a valid pointer to a member function of object T.\n        ensures\n            - Displays a window titled \"Open File\" that will allow the user to select \n              a file.  But only a file that already exists.\n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called on object if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n    void open_existing_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    );\n    /*!\n        ensures\n            - Displays a window titled \"Open File\" that will allow the user to select \n              a file.  But only a file that already exists.\n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void save_file_box (\n        T& object,\n        void (T::*event_handler)(const std::string&) \n    );\n    /*!\n        requires\n            - event_handler == a valid pointer to a member function of object T.\n        ensures\n            - Displays a window titled \"Save File\" that will allow the user to select \n              a file.  \n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called on object if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n    void save_file_box (\n        const any_function<void(const std::string&)>& event_handler\n    );\n    /*!\n        ensures\n            - Displays a window titled \"Save File\" that will allow the user to select \n              a file.  \n            - The displayed window will start out showing the directory get_current_dir()\n              (i.e. it starts in the current working directory)\n            - The event_handler function is called if the user selects\n              a file.  If the user closes the window without selecting a file\n              then nothing occurs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // function message_box() \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void message_box (\n        const std::string& title,\n        const std::string& message\n    );\n    /*!\n        ensures\n            - displays a message box with the given title and message.  It will have a \n              single button and when the user clicks it the message box will go away.\n            - this function does not block but instead returns immediately.\n    !*/\n\n    void message_box_blocking (\n        const std::string& title,\n        const std::string& message\n    );\n    /*!\n        ensures\n            - displays a message box with the given title and message.  It will have a \n              single button and when the user clicks it the message box will go away.\n            - this function blocks until the user clicks on the message box and \n              causes it to go away.\n    !*/\n\n    template <\n        typename T\n        >\n    void message_box (\n        const std::string& title,\n        const std::string& message,\n        T& object,\n        void (T::*event_handler)() \n    );\n    /*!\n        requires\n            - event_handler == a valid pointer to a member function of object T.\n        ensures\n            - Displays a message box with the given title and message.  It will have a \n              single button and when the user clicks it the message box will go away.\n            - The event_handler function is called on object when the user clicks\n              ok or otherwise closes the message box window. \n            - this function does not block but instead returns immediately.\n    !*/\n\n    void message_box (\n        const std::string& title,\n        const std::string& message,\n        const any_function<void()>& event_handler\n    );\n    /*!\n        ensures\n            - Displays a message box with the given title and message.  It will have a \n              single button and when the user clicks it the message box will go away.\n            - The event_handler function is called when the user clicks\n              ok or otherwise closes the message box window. \n            - this function does not block but instead returns immediately.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class label\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class label : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                text() == \"\"\n                the text color will be black\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple text label.  The size of the label\n                is automatically set to be just big enough to contain its text.\n        !*/\n\n    public:\n\n        label(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~label(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_text (const std::wstring& text);\n        void set_text (const dlib::ustring& text);\n        void set_text (\n            const std::string& text\n        );\n        /*!\n            ensures\n                - #text() == text\n            throws\n                - std::bad_alloc\n        !*/\n\n        const std::wstring  wtext () const;\n        const dlib::ustring utext () const;\n        const std::string   text (\n        ) const;\n        /*!\n            ensures\n                - returns the text of this label\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n        /*!\n            ensures\n                - #text_color() == color\n        !*/\n\n        const rgb_pixel text_color (\n        ) const;\n        /*! \n            ensures\n                - returns the color used to draw the text in this widget\n        !*/\n\n    private:\n\n        // restricted functions\n        label(label&);        // copy constructor\n        label& operator=(label&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class toggle_button\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class toggle_button : public button_action \n    {\n        /*!\n            INITIAL VALUE\n                name() == \"\"\n                is_checked() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple two state toggle button.  Is is either\n                in the checked or unchecked state and when a user clicks on it it toggles its\n                state.\n\n                When this object is disabled it means it will not respond to user clicks.\n        !*/\n\n    public:\n\n        toggle_button(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~toggle_button(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_name (const std::wstring& name);\n        void set_name (const dlib::ustring& name);\n        void set_name (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - #name() == name\n                - this toggle_button has been resized such that it is big enough to contain\n                  the new name.\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*! \n            ensures\n                - if (width and height are big enough to contain the name of this button) then\n                    - #width() == width_\n                    - #height() == height_\n                    - #top() == top()\n                    - #left() == left()\n                    - i.e. The location of the upper left corner of this button stays the\n                      same but its width and height are modified\n        !*/\n\n        void set_tooltip_text (const std::wstring& text);\n        void set_tooltip_text (const dlib::ustring& text);\n        void set_tooltip_text (\n            const std::string& text\n        );\n        /*!\n            ensures\n                - #tooltip_text() == text\n                - enables the tooltip for this toggle_button\n        !*/\n\n        const dlib::ustring tooltip_utext () const;\n        const std::wstring  tooltip_wtext () const;\n        const std::string   tooltip_text (\n        ) const;\n        /*!\n            ensures\n                - returns the text that is displayed in the tooltip for this toggle_button\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from toggle_button_style\n            ensures\n                - this toggle_button object will draw itself using the given\n                  button style\n        !*/\n\n        bool is_checked (\n        ) const;\n        /*!\n            ensures\n                - if (this box is currently checked) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        const std::wstring  wname () const;\n        const dlib::ustring uname () const;\n        const std::string   name (\n        ) const;\n        /*!\n            ensures\n                - returns the name of this toggle_button.  The name is a string\n                  that appears to the right of the actual check box.\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_checked (\n        );\n        /*!\n            ensures\n                - #is_checked() == true \n        !*/\n\n        void set_unchecked (\n        );\n        /*! \n            ensures\n                - #is_checked() == false \n        !*/ \n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the toggle_button is \n                  toggled by the user. \n                - this event is NOT triggered by calling set_checked() or set_unchecked().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_click_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the toggle_button is \n                  toggled by the user. \n                - this event is NOT triggered by calling set_checked() or set_unchecked().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)(toggle_button& self)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T.\n            ensures\n                - the event_handler function is called on object when the toggle_button is \n                  toggled by the user. self will be a reference to the toggle_button object\n                  that the user clicked.\n                - this event is NOT triggered by calling set_checked() or set_unchecked().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_sourced_click_handler (\n            const any_function<void(toggle_button& self)>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the toggle_button is \n                  toggled by the user. self will be a reference to the toggle_button object\n                  that the user clicked.\n                - this event is NOT triggered by calling set_checked() or set_unchecked().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        toggle_button(toggle_button&);        // copy constructor\n        toggle_button& operator=(toggle_button&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class text_field\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_field : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - text() == \"\"\n                - width() == 10\n                - height() == a height appropriate for the font used.  The text color will\n                  be black.\n                - has_input_focus() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple one line text input field.  \n        !*/\n\n    public:\n\n        text_field(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~text_field(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from text_field_style \n            ensures\n                - this text_field object will draw itself using the given\n                  text field style\n        !*/\n\n        void set_text (const std::wstring& text);\n        void set_text (const dlib::ustring& text);\n        void set_text (\n            const std::string& text\n        );\n        /*!\n            requires\n                - text.find_first_of('\\n') == std::string::npos \n                  (i.e. there aren't any new lines in text)\n            ensures\n                - #text() == text\n            throws\n                - std::bad_alloc\n        !*/\n\n        const std::wstring  wtext () const;\n        const dlib::ustring utext () const;\n        const std::string   text (\n        ) const;\n        /*!\n            ensures\n                - returns the text of this text_field\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_width (\n            unsigned long width_\n        );\n        /*! \n            ensures\n                - if (width >= 10) then\n                    - #width()  == width_\n                    - #height() == height()\n                    - #top()    == top()\n                    - #left()   == left()\n                    - i.e. The width of this drawable is set to the given width but \n                      nothing else changes.\n        !*/\n\n        void give_input_focus (\n        );\n        /*!\n            ensures\n                - #has_input_focus() == true\n        !*/\n\n        bool has_input_focus (\n        );\n        /*!\n            ensures\n                - Returns true if this txt field has input keyboard focus.  If this\n                  is the case then it means that when the user types on the keyboard\n                  the output will appear inside the text field.\n        !*/\n\n        void select_all_text (\n        );\n        /*!\n            ensures\n                - causes all the text in the text field to become selected.\n                  (note that it doesn't give input focus)\n        !*/\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n        /*!\n            ensures\n                - #text_color() == color\n        !*/\n\n        const rgb_pixel text_color (\n        ) const;\n        /*! \n            ensures\n                - returns the color used to draw the text in this widget\n        !*/\n\n        void set_background_color (\n            const rgb_pixel color\n        );\n        /*!\n            ensures\n                - #background_color() == color\n        !*/\n\n        const rgb_pixel background_color (\n        ) const;\n        /*! \n            ensures\n                - returns the color used to fill in the background of this widget\n        !*/\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the text\n                  in this text_field is modified by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_text_modified_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the text in this text_field \n                  is modified by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_enter_key_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when this text field\n                  has input focus and the user hits the enter key on their keyboard.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_enter_key_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when this text field has input \n                  focus and the user hits the enter key on their keyboard.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_focus_lost_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when this object\n                  loses input focus due to the user clicking outside the text field\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_focus_lost_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when this object loses input \n                  focus due to the user clicking outside the text field\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        text_field(text_field&);        // copy constructor\n        text_field& operator=(text_field&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class text_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class text_box : public scrollable_region \n    {\n        /*!\n            INITIAL VALUE\n                - text() == \"\"\n                - The text color will be black.\n                - width() == 100\n                - height() == 100\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple multi-line text input box.  \n        !*/\n\n    public:\n\n        text_box(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~text_box(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from text_box_style \n            ensures\n                - this text_box object will draw itself using the given\n                  text box style\n        !*/\n\n        void set_text (const std::wstring& text);\n        void set_text (const dlib::ustring& text);\n        void set_text (\n            const std::string& text\n        );\n        /*!\n            ensures\n                - #text() == text\n            throws\n                - std::bad_alloc\n        !*/\n\n        const std::wstring  wtext () const;\n        const dlib::ustring utext () const;\n        const std::string   text (\n        ) const;\n        /*!\n            ensures\n                - returns the text of this text_box\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_size (\n            unsigned long width,\n            unsigned long height \n        );\n        /*! \n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified\n        !*/\n\n        void set_text_color (\n            const rgb_pixel color\n        );\n        /*!\n            ensures\n                - #text_color() == color\n        !*/\n\n        const rgb_pixel text_color (\n        ) const;\n        /*! \n            ensures\n                - returns the color used to draw the text in this widget\n        !*/\n\n        void set_background_color (\n            const rgb_pixel color\n        );\n        /*!\n            ensures\n                - #background_color() == color\n        !*/\n\n        const rgb_pixel background_color (\n        ) const;\n        /*! \n            ensures\n                - returns the color used to fill in the background of this widget\n        !*/\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the text\n                  in this text_box is modified by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_text_modified_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the text in this text_box \n                  is modified by the user.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_enter_key_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when this text box\n                  has input focus and the user hits the enter key on their keyboard.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_enter_key_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when this text box has input \n                  focus and the user hits the enter key on their keyboard.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_focus_lost_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when this object\n                  loses input focus due to the user clicking outside the text box\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_focus_lost_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when this object loses input \n                  focus due to the user clicking outside the text box\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        text_box(text_box&);        // copy constructor\n        text_box& operator=(text_box&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class check_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class check_box : public toggle_button \n    {\n        /*!\n            This is just a toggle button with the style set to \n            toggle_button_style_check_box.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class radio_button\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class radio_button : public toggle_button \n    {\n        /*!\n            This is just a toggle button with the style set to \n            toggle_button_style_radio_button.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class tabbed_display\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class tabbed_display : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                number_of_tabs() == 1\n                selected_tab() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a row of tabs that are user selectable.  \n\n                When this object is disabled it means it will not respond to user clicks.\n        !*/\n\n    public:\n\n        tabbed_display(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~tabbed_display(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*! \n            ensures\n                - if (width and height are big enough to contain the tabs) then\n                    - #width() == width_\n                    - #height() == height_\n                    - #top() == top()\n                    - #left() == left()\n                    - i.e. The location of the upper left corner of this widget stays the\n                      same but its width and height are modified\n        !*/\n\n        void set_number_of_tabs (\n            unsigned long num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #number_of_tabs() == num\n                - no tabs have any widget_groups associated with them.\n                - for all valid idx:\n                    - #tab_name(idx) == \"\"\n            throws\n                - std::bad_alloc\n        !*/\n\n        unsigned long selected_tab (\n        ) const;\n        /*!\n            ensures\n                - returns the index of the currently selected tab\n        !*/\n\n        unsigned long number_of_tabs (\n        ) const;\n        /*!\n            ensures\n                - returns the number of tabs in this tabbed_display\n        !*/\n\n        const std::wstring&  tab_wname (unsigned long idx) const;\n        const dlib::ustring& tab_uname (unsigned long idx) const;\n        const std::string&   tab_name (\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_tabs()\n            ensures\n                - returns a const reference to the name of the tab given by idx\n        !*/\n\n        void set_tab_name (unsigned long idx, const std::wstring& new_name);\n        void set_tab_name (unsigned long idx, const dlib::ustring& new_name);\n        void set_tab_name (\n            unsigned long idx,\n            const std::string& new_name\n        );\n        /*!\n            requires\n                - idx < number_of_tabs()\n            ensures\n                - #tab_name(idx) == new_name\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_tab_group (\n            unsigned long idx,\n            widget_group& group\n        );\n        /*!\n            requires\n                - idx < number_of_tabs()\n            ensures\n                - if (is_hidden()) then\n                    - group.is_hidden() == true\n                - else\n                    - whenever the tab with index idx is selected group.is_hidden() == false \n                    - whenever the tab with index idx is deselected group.is_hidden() == true \n                - whenever the position of *this changes the position of group will be\n                  updated so that it is still inside the tabbed_display.  The position of group\n                  will also be updated after this call to set_tab_group().\n                - any previous calls to set_tab_group() with this index are overridden by this\n                  new call.  (i.e. you can only have one widget_group associated with a single\n                  tab at a time)\n        !*/\n\n        void fit_to_contents (\n        );\n        /*!\n            ensures\n                - Adjusts the size this tabbed_display so that it nicely contains \n                  all of its widget_group objects.   \n                - does not change the position of this object. \n                  (i.e. the upper left corner of get_rect() remains at the same position)\n        !*/\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long new_idx, unsigned long old_idx)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - The event_handler function is called on object when the user clicks\n                  on a tab that isn't already selected.  new_idx will give the index of \n                  the newly selected tab and old_idx will give the index of the tab \n                  that was previously selected. \n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_click_handler (\n            const any_function<void(unsigned long new_idx, unsigned long old_idx)>& eh\n        );\n        /*!\n            ensures\n                - The event_handler function is called when the user clicks on a tab \n                  that isn't already selected.  new_idx will give the index of the \n                  newly selected tab and old_idx will give the index of the tab that \n                  was previously selected. \n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        tabbed_display(tabbed_display&);        // copy constructor\n        tabbed_display& operator=(tabbed_display&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class named_rectangle\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class named_rectangle : public drawable \n    {\n        /*!\n            INITIAL VALUE\n                name() == \"\"\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple named rectangle.  \n        !*/\n\n    public:\n\n        named_rectangle(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~named_rectangle(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*! \n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified\n        !*/\n\n        void wrap_around (\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - This object will be repositioned and sized so that it fits\n                  around the given rectangle.\n        !*/\n\n        void set_name (const std::wstring& name);\n        void set_name (const dlib::ustring& name);\n        void set_name (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - #name() == name\n            throws\n                - std::bad_alloc\n        !*/\n\n        const std::wstring  wname () const;\n        const dlib::ustring uname () const;\n        const std::string   name (\n        ) const;\n        /*!\n            ensures\n                - returns the name of this named_rectangle\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        named_rectangle(named_rectangle&);        // copy constructor\n        named_rectangle& operator=(named_rectangle&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class mouse_tracker\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class mouse_tracker : public draggable \n    {\n        /*!\n            INITIAL VALUE\n                draggable_area() == rectangle(0,0,500,500)\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple draggable box that displays the \n                current location of the mouse.  \n\n                Also, if you hold shift and left click on the parent window then the \n                mouse_tracker will place a single red pixel where you clicked and will\n                display the mouse position relative to that point.\n        !*/\n\n    public:\n\n        mouse_tracker(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~mouse_tracker(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n    private:\n\n        // restricted functions\n        mouse_tracker(mouse_tracker&);        // copy constructor\n        mouse_tracker& operator=(mouse_tracker&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class list_box\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class list_box : public scrollable_region, \n                     public enumerable<const std::string>\n    {\n        /*!\n            INITIAL VALUE\n                multiple_select_enabled() == false \n                size() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the elements in the list_box from\n                the 0th element to the (size()-1)th element.  i.e. (*this)[0] to\n                (*this)[size()-1].\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a simple textual list box.  It contains a \n                vertical list of strings which the user may select from.\n        !*/\n\n    public:\n\n        list_box(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~list_box(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename style_type\n            >\n        void set_style (\n            const style_type& style\n        );\n        /*!\n            requires\n                - style_type == a type that inherits from list_box_style \n            ensures\n                - this list_box object will draw itself using the given style\n        !*/\n\n        void set_size (\n            unsigned long width_,\n            unsigned long height_\n        );\n        /*! \n            ensures\n                - #width() == width_\n                - #height() == height_\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified\n        !*/\n\n        bool is_selected (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < size()\n            ensures\n                - if (the item given by index is currently selected) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void select (\n            unsigned long index \n        );\n        /*!\n            requires\n                - index < size()\n            ensures\n                - #is_selected(index) == true\n        !*/\n\n        void unselect (\n            unsigned long index \n        );\n        /*!\n            requires\n                - index < size()\n            ensures\n                - #is_selected(index) == false\n        !*/\n\n        template <typename T>\n        void get_selected (\n            T& list\n        ) const;\n        /*!\n            requires\n                - T == an implementation of dlib/queue/queue_kernel_abstract.h \n                - T::type == unsigned long\n            ensures\n                - #list == a list of all the currently selected indices for this list_box.\n        !*/\n\n        unsigned long get_selected (\n        ) const;\n        /*!\n            requires\n                - multiple_select_enabled() == false\n            ensures\n                - if (there is currently something selected) then\n                    - returns the index of the selected item\n                - else\n                    - returns size()\n        !*/\n\n        template <typename T>\n        void load (\n            const T& list\n        );\n        /*!\n            requires\n                - T == compatible with dlib::enumerable<std::string>\n            ensures\n                - #size() == list.size()\n                - Copies all the strings from list into *this in the order in which they are enumerated.\n                  (i.e. The first one goes into (*this)[0], the second into (*this)[1], and so on...)\n        !*/\n\n        const std::string& operator[] (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < size()\n            ensures\n                - returns the name of the indexth item/row in this list box.\n        !*/\n\n        bool multiple_select_enabled (\n        ) const;\n        /*!\n            ensures\n                - if (this object will allow the user to select more than one item at a time) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void enable_multiple_select (\n        ); \n        /*!\n            ensures\n                - #multiple_select_enabled() == true\n        !*/\n\n        void disable_multiple_select (\n        );\n        /*!\n            ensures\n                - #multiple_select_enabled() == false\n        !*/\n\n        template <\n            typename T\n            >\n        void set_double_click_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long index)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T.\n            ensures\n                - The event_handler function is called on object when the user double \n                  clicks on one of the rows in this list box.  index gives the row \n                  number for the item the user clicked.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_double_click_handler (\n            const any_function<void(unsigned long index)>& event_handler\n        ); \n        /*!\n            ensures\n                - The event_handler function is called when the user double clicks on \n                  one of the rows in this list box.  index gives the row number for \n                  the item the user clicked.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_click_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long index)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T.\n            ensures\n                - The event_handler function is called on object when the user  \n                  clicks on one of the rows in this list box.  index gives the row \n                  number for the item the user clicked.  (Note that the second click\n                  in a double click triggers the double click handler above instead\n                  of this event)\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_click_handler (\n            const any_function<void(unsigned long index)>& event_handler\n        );\n        /*!\n            ensures\n                - The event_handler function is called when the user clicks on one \n                  of the rows in this list box.  index gives the row number for the \n                  item the user clicked.  (Note that the second click in a double \n                  click triggers the double click handler above instead of this event)\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        list_box(list_box&);        // copy constructor\n        list_box& operator=(list_box&);    // assignment operator\n    };\n\n    class wlist_box : public scrollable_region, \n    public enumerable<const std::wstring>;\n    /*!\n        same as list_box except for std::wstring instead of std::string\n    !*/\n\n    class ulist_box : public scrollable_region, \n    public enumerable<const dlib::ustring>;\n    /*!\n        same as list_box except for dlib::ustring instead of std::string\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // class menu_bar \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class menu_bar : public drawable\n    {\n        /*!\n            INITIAL VALUE\n                - number_of_menus() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a menu bar that appears at the top of a\n                window.\n        !*/\n\n    public:\n\n        menu_bar(\n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~menu_bar(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_number_of_menus (\n            unsigned long num\n        );\n        /*!\n            ensures\n                - #number_of_menus() == num\n        !*/\n\n        unsigned long number_of_menus (\n        ) const;\n        /*!\n            ensures\n                - returns the number of menus in this menu_bar\n        !*/\n\n        void set_menu_name (unsigned long idx, const std::wstring name, char underline_ch = '\\0');\n        void set_menu_name (unsigned long idx, const dlib::ustring name, char underline_ch = '\\0');\n        void set_menu_name (\n            unsigned long idx,\n            const std::string name,\n            char underline_ch = '\\0'\n        );\n        /*!\n            requires\n                - idx < number_of_menus()\n            ensures\n                - #menu_name(idx) == name\n                - if (underline_ch is present in name) then\n                    - The menu with index idx will have the first underline_ch character \n                      in its name underlined and users will be able to activate the menu\n                      by hitting alt+underline_char\n        !*/\n\n        const std::wstring  menu_wname (unsigned long idx) const;\n        const dlib::ustring menu_uname (unsigned long idx) const;\n        const std::string   menu_name (\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_menus()\n            ensures\n                - returns the name of the menu with index idx\n        !*/\n\n        popup_menu& menu (\n            unsigned long idx\n        );\n        /*!\n            requires\n                - idx < number_of_menus()\n            ensures\n                - returns a non-const reference to the popup_menu for the menu with\n                  index idx.\n        !*/\n\n        const popup_menu& menu (\n            unsigned long idx\n        ) const;\n        /*!\n            requires\n                - idx < number_of_menus()\n            ensures\n                - returns a const reference to the popup_menu for the menu with\n                  index idx.\n        !*/\n\n    private:\n\n        // restricted functions\n        menu_bar(menu_bar&);        // copy constructor\n        menu_bar& operator=(menu_bar&);    // assignment operator\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename graph_type\n        >\n    class directed_graph_drawer : public zoomable_region \n    {\n        /*!\n            REQUIREMENTS ON graph_type\n                - must be an implementation of directed_graph/directed_graph_kernel_abstract.h\n\n            INITIAL VALUE\n                - get_graph().size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a graphical widget that allows the user to draw\n                a directed graph.  \n                \n                The user can create nodes by right clicking on the draw area and add \n                edges by selecting a node (via left clicking on it) and then holding \n                shift and clicking on the node that is to be the child node of the \n                selected node.\n        !*/\n\n    public:\n\n        directed_graph_drawer (\n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~directed_graph_drawer (\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        const graph_type& graph (\n        ) const;\n        /*!\n            requires\n                - drawable::m is locked\n            ensures\n                - returns a const reference to the graph that this widget has been drawing\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns graph().number_of_nodes()\n        !*/\n\n        void clear_graph (\n        );\n        /*!\n            ensures\n                - #number_of_nodes() == 0\n        !*/\n\n        const typename graph_type::node_type& graph_node (\n            unsigned long i\n        ) const;\n        /*!\n            requires\n                - drawable::m is locked\n                - i < number_of_nodes()\n            ensures\n                - returns a const reference to get_graph().node(i)\n        !*/\n\n        typename graph_type::node_type& graph_node (\n            unsigned long i\n        );\n        /*!\n            requires\n                - drawable::m is locked\n                - i < number_of_nodes()\n            ensures\n                - returns a non-const reference to get_graph().node(i)\n        !*/\n\n        void save_graph (\n            std::ostream& out\n        );\n        /*!\n            ensures\n                - saves the state of the graph to the output stream.  Does so in a \n                  way that not only preserves the state of the graph this->graph()\n                  but also preserves the graphical layout of the graph in this \n                  GUI widget.\n                - Also, the first part of the saved state is a serialized \n                  version of this->graph().  Thus, you can deserialize just the\n                  this->graph() object from the serialized data if you like.\n        !*/\n\n        void load_graph (\n            std::istream& in \n        );\n        /*!\n            ensures\n                - loads a saved graph from the given input stream.  \n        !*/\n\n        void set_node_label (unsigned long i, const std::wstring& label);\n        void set_node_label (unsigned long i, const dlib::ustring& label);\n        void set_node_label (\n            unsigned long i,\n            const std::string& label\n        );\n        /*!\n            requires\n                - i < number_of_nodes()\n            ensures\n                - #node_label(i) == label\n        !*/\n\n        void set_node_color (\n            unsigned long i,\n            rgb_pixel color\n        );\n        /*!\n            requires\n                - i < number_of_nodes()\n            ensures\n                - #node_color(i) == color \n        !*/\n\n        rgb_pixel node_color (\n            unsigned long i\n        ) const;\n        /*!\n            requires\n                - i < number_of_nodes()\n            ensures\n                - returns the color used to draw node graph_node(i)\n        !*/\n\n        const std::wstring  node_wlabel (unsigned long i) const;\n        const dlib::ustring node_ulabel (unsigned long i) const;\n        const std::string   node_label (\n            unsigned long i\n        ) const;\n        /*!\n            requires\n                - i < number_of_nodes()\n            ensures\n                - returns the text label for node graph_node(i)\n        !*/\n\n        template <\n            typename T\n            >\n        void set_node_selected_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long node_index)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user selects\n                  a node.  \n                - node_index == the index of the node that was selected\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_node_selected_handler (\n            const any_function<void(unsigned long node_index)>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user selects\n                  a node.  \n                - node_index == the index of the node that was selected\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_node_deselected_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long node_index)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user \n                  deselects a node.  \n                - node_index == the index of the node that was deselected\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_node_deselected_handler (\n            const any_function<void(unsigned long node_index)>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user deselects a node.  \n                - node_index == the index of the node that was deselected\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_node_deleted_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user \n                  deletes a node.  \n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_node_deleted_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user deletes a node.  \n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        template <\n            typename T\n            >\n        void set_graph_modified_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user \n                  modifies the graph (i.e. adds or removes a node or edge)\n                - the event_handler function is not called when the user just\n                  moves nodes around on the screen.\n                - This event is always dispatched before any more specific event\n                  that results from the user modifying the graph.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_graph_modified_handler (\n            const any_function<void()>& event_handler\n        );\n        /*!\n            ensures\n                - the event_handler function is called when the user modifies \n                  the graph (i.e. adds or removes a node or edge)\n                - the event_handler function is not called when the user just\n                  moves nodes around on the screen.\n                - This event is always dispatched before any more specific event\n                  that results from the user modifying the graph.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        directed_graph_drawer(directed_graph_drawer&);        // copy constructor\n        directed_graph_drawer& operator=(directed_graph_drawer&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class text_grid : public scrollable_region \n    {\n        /*!\n            INITIAL VALUE\n                - vertical_scroll_increment() == 10\n                - horizontal_scroll_increment() == 10\n                - border_color() == rgb_pixel(128,128,128)\n                - number_of_columns() == 0\n                - number_of_rows() == 0\n\n            WHAT THIS OBJECT REPRESENTS \n                This object represents a simple grid of square text fields that \n                looks more or less like a spreadsheet grid.\n        !*/\n\n    public:\n\n        text_grid (\n            drawable_window& w\n        ); \n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~text_grid (\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_grid_size (\n            unsigned long rows,\n            unsigned long cols\n        );\n        /*!\n            ensures\n                - #number_of_rows() == rows\n                - #number_of_columns() == cols\n                - for all valid r and c:\n                    - #text(r,c) == \"\"\n                    - #text_color(r,c) == rgb_pixel(0,0,0)\n                    - #background_color(r,c) == rgb_pixel(255,255,255)\n                    - #is_editable(r,c) == true\n        !*/\n\n        unsigned long number_of_columns (\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns contained in this grid\n        !*/\n\n        unsigned long number_of_rows (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows contained in this grid\n        !*/\n\n        rgb_pixel border_color (\n        ) const;\n        /*!\n            ensures\n                - returns the color of the lines drawn between the grid elements\n        !*/\n\n        void set_border_color (\n            rgb_pixel color\n        );\n        /*!\n            ensures\n                - #border_color() == color\n        !*/\n\n        const std::wstring  wtext (unsigned long row, unsigned long col) const;\n        const dlib::ustring utext (unsigned long row, unsigned long col) const;\n        const std::string   text (\n            unsigned long row,\n            unsigned long col\n        ) const;\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - returns the text in the given grid location\n        !*/\n\n        void set_text (unsigned long row, unsigned long col, const std::wstring& str);\n        void set_text (unsigned long row, unsigned long col, const dlib::ustring& str);\n        void set_text (\n            unsigned long row,\n            unsigned long col,\n            const std::string& str\n        );\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - #text(row,col) == str\n        !*/\n\n        const rgb_pixel text_color (\n            unsigned long row,\n            unsigned long col\n        ) const;\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - returns the color of the text in the given grid location\n        !*/\n\n        void set_text_color (\n            unsigned long row,\n            unsigned long col,\n            const rgb_pixel color\n        );\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - #text_color(row,col) == color \n        !*/\n\n        const rgb_pixel background_color (\n            unsigned long row,\n            unsigned long col\n        ) const;\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - returns the background color of the given grid location\n        !*/\n\n        void set_background_color (\n            unsigned long row,\n            unsigned long col,\n            const rgb_pixel color\n        ); \n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - #background_color(row,col) == color \n        !*/\n\n        bool is_editable (\n            unsigned long row,\n            unsigned long col\n        ) const;\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - if (the given grid location is editable by the user) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        void set_editable (\n            unsigned long row,\n            unsigned long col,\n            bool editable\n        );\n        /*!\n            requires\n                - row < number_of_rows()\n                - col < number_of_columns()\n            ensures\n                - #is_editable(row,col) == editable \n        !*/\n\n        void set_column_width (\n            unsigned long col,\n            unsigned long width\n        );\n        /*!\n            requires\n                - col < number_of_columns()\n            ensures\n                - the given column will be displayed such that it is width pixels wide\n        !*/\n\n        void set_row_height (\n            unsigned long row,\n            unsigned long height \n        );\n        /*!\n            requires\n                - row < number_of_rows()\n            ensures\n                - the given row will be displayed such that it is height pixels wide\n        !*/\n\n        template <\n            typename T\n            >\n        void set_text_modified_handler (\n            T& object,\n            void (T::*event_handler)(unsigned long row, unsigned long col)\n        );\n        /*!\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user selects\n                  a node.  \n                - row == row will give the row of the grid item that was modified\n                - col == col will give the column of the grid item that was modified\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n        void set_text_modified_handler (\n            const any_function<void(unsigned long row, unsigned long col)>& event_handler\n        ); \n        /*!\n            ensures\n                - the event_handler function is called when the user selects a node.  \n                - row == row will give the row of the grid item that was modified\n                - col == col will give the column of the grid item that was modified\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        text_grid(text_grid&);        // copy constructor\n        text_grid& operator=(text_grid&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class image_display : public scrollable_region \n    {\n        /*!\n            INITIAL VALUE\n                - This object isn't displaying anything. \n                - get_overlay_rects().size() == 0\n                - get_default_overlay_rect_label() == \"\"\n                - get_default_overlay_rect_color() == rgb_alpha_pixel(255,0,0,255) (i.e. RED)\n                - This object does not have any user labelable parts defined.\n                - overlay_editing_is_enabled() == true\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an image inside a scrollable region.  \n                You give it an image to display by calling set_image().\n                This widget also allows you to add rectangle and line overlays that\n                will be drawn on top of the image.  \n                \n                If you hold the Ctrl key you can zoom in and out using the mouse wheel.\n                You can also add new overlay rectangles by holding shift, left clicking,\n                and dragging the mouse.  Additionally, you can delete an overlay rectangle\n                by double clicking on it and hitting delete or backspace.  Finally, you\n                can also add part labels (if they have been defined by calling add_labelable_part_name())\n                by selecting an overlay rectangle with the mouse and then right clicking\n                on the part.  If you want to move any rectangle or an object part then\n                shift+right click and drag it.  Alternatively, if you haven't added any\n                part labels via add_labelable_part_name() you can add parts to a rectangle\n                by simply shift left clicking while it's selected.  This will add parts\n                with integer names and the integer names begin with 0 and increase. This\n                feature is only activated if the rectangle has no parts or all the parts\n                are already integer names.\n                \n                Finally, if you hold Ctrl and left click an overlay rectangle it will\n                change its label to get_default_overlay_rect_label() and color to\n                get_default_overlay_rect_color().\n\n                The image is drawn such that:\n                    - the pixel img[0][0] is the upper left corner of the image.\n                    - the pixel img[img.nr()-1][0] is the lower left corner of the image.\n                    - the pixel img[0][img.nc()-1] is the upper right corner of the image.\n                    - the pixel img[img.nr()-1][img.nc()-1] is the lower right corner of the image.\n        !*/\n\n    public:\n\n        image_display(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n        !*/\n\n        ~image_display(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        template <\n            typename image_type\n            >\n        void set_image (\n            const image_type& new_img\n        );\n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h or\n                  a dlib::matrix or something convertible to a matrix via mat()\n                - pixel_traits<typename image_type::type> must be defined \n            ensures\n                - #*this widget is now displaying the given image new_img.\n        !*/\n\n        struct overlay_rect\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a rectangle that is drawn on top of the\n                    image shown by this object.  Each rectangle is represented by \n                    a rectangle object as well as a color and text label.  The label\n                    is drawn below the lower right corner of the rectangle.\n\n                    Moreover, the rectangle can have sub-parts. Each part is listed\n                    in the parts member variable.  This variable maps the name of the\n                    part to its position.\n\n                    Rectangles with crossed_out == true will be drawn with an X through\n                    them.\n            !*/\n\n            rectangle rect;\n            rgb_alpha_pixel color;\n            std::string label;\n            std::map<std::string,point> parts;\n            bool crossed_out;\n\n            overlay_rect(\n            ); \n            /*!\n                ensures\n                    - #color == rgb_alpha_pixel(0,0,0,0) \n                    - #rect == rectangle()\n                    - #label.size() == 0\n                    - #crossed_out == false\n            !*/\n\n            template <typename pixel_type>\n            overlay_rect(\n                const rectangle& r, \n                pixel_type p\n            );\n            /*!\n                ensures\n                    - #rect == r\n                    - performs assign_pixel(color, p) \n                    - #label.size() == 0\n                    - #crossed_out == false\n            !*/\n\n            template <typename pixel_type>\n            overlay_rect(\n                const rectangle& r,\n                pixel_type p,\n                const std::string& l\n            );\n            /*!\n                ensures\n                    - #rect == r\n                    - performs assign_pixel(color, p)\n                    - #label == l\n                    - #crossed_out == false\n            !*/\n\n            template <typename pixel_type>\n            overlay_rect(\n                const rectangle& r, \n                pixel_type p, \n                const std::string& l, \n                const std::map<std::string,point>& parts_\n            ); \n            /*!\n                ensures\n                    - #rect == r\n                    - performs assign_pixel(color, p)\n                    - #label == l\n                    - #parts == parts_\n                    - #crossed_out == false\n            !*/\n\n        };\n\n        struct overlay_line\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a line that is drawn on top of the\n                    image shown by this object.  Each line is represented by \n                    its two end points (p1 and p2) as well as a color.\n            !*/\n\n            dpoint p1;\n            dpoint p2;\n            rgb_alpha_pixel color;\n\n            overlay_line(\n            );\n            /*!\n                ensures\n                    - #color == rgb_alpha_pixel(0,0,0,0)\n                    - #p1 == point()\n                    - #p2 == point()\n            !*/\n\n            template <typename pixel_type>\n            overlay_line(\n                const dpoint& p1_,\n                const dpoint& p2_,\n                pixel_type p\n            ); \n            /*!\n                ensures\n                    - performs assign_pixel(color, p)\n                    - #p1 == p1_\n                    - #p2 == p2_\n            !*/\n\n        };\n\n        struct overlay_circle\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a circle that is drawn on top of the\n                    image shown by this object.  Each circle is represented by \n                    its center, radius, and color.  It can also have an optional\n                    text label which will appear below the circle.\n            !*/\n\n            point center;\n            int radius;\n            rgb_alpha_pixel color;\n            std::string label;\n\n            overlay_circle(\n            );\n            /*!\n                ensures\n                    - #center == point(0,0)\n                    - #radius == 0\n                    - #color == rgb_alpha_pixel(0,0,0,0)\n                    - #label.size() == 0\n            !*/\n\n            template <typename pixel_type>\n            overlay_circle(\n                const point& center_, \n                const int radius_,\n                pixel_type p\n            ); \n            /*!\n                ensures\n                    - performs assign_pixel(color, p)\n                    - #center == center_\n                    - #radius == radius_\n            !*/\n\n            template <typename pixel_type>\n            overlay_circle(\n                const point& center_, \n                const int radius_,\n                pixel_type p,\n                const std::string& label_\n            ); \n            /*!\n                ensures\n                    - performs assign_pixel(color, p)\n                    - #center == center_\n                    - #radius == radius_\n                    - #label == label_\n            !*/\n\n        };\n\n        void add_overlay (\n            const overlay_rect& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay rectangle into this object such\n                  that it will be displayed. \n        !*/\n\n        void add_overlay (\n            const overlay_line& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay line into this object such\n                  that it will be displayed. \n        !*/\n\n        void add_overlay (\n            const overlay_circle& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay circle into this object such\n                  that it will be displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_rect>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay rectangles into this object such\n                  that they will be displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay lines into this object such\n                  that they will be displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_circle>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay circles into this object such\n                  that they will be displayed. \n        !*/\n\n        void clear_overlay (\n        );\n        /*!\n            ensures\n                - removes all overlays from this object.  \n                - #get_overlay_rects().size() == 0\n        !*/\n\n        std::vector<overlay_rect> get_overlay_rects (\n        ) const;\n        /*!\n            ensures\n                - returns a copy of all the overlay_rect objects currently displayed.\n        !*/\n\n        void set_default_overlay_rect_label (\n            const std::string& label\n        );\n        /*!\n            ensures\n                - #get_default_overlay_rect_label() == label\n        !*/\n\n        std::string get_default_overlay_rect_label (\n        ) const;\n        /*!\n            ensures\n                - returns the label given to new overlay rectangles created by the user\n                  (i.e. when the user holds shift and adds them with the mouse)\n        !*/\n\n        void set_default_overlay_rect_color (\n            const rgb_alpha_pixel& color\n        );\n        /*!\n            ensures\n                - #get_default_overlay_rect_color() == color\n        !*/\n\n        rgb_alpha_pixel get_default_overlay_rect_color (\n        ) const;\n        /*!\n            ensures\n                - returns the color given to new overlay rectangles created by the user\n                  (i.e. when the user holds shift and adds them with the mouse)\n        !*/\n\n        void add_labelable_part_name (\n            const std::string& name\n        );\n        /*!\n            ensures\n                - adds a user labelable part with the given name.  If the name has\n                  already been added then this function has no effect.  \n                - These parts can be added by the user by selecting an overlay box\n                  and then right clicking anywhere in it.  A popup menu will appear\n                  listing the parts.  The user can then click a part name and it will\n                  add it into the overlay_rect::parts variable and also show it on the\n                  screen.\n        !*/\n\n        void clear_labelable_part_names (\n        );\n        /*!\n            ensures\n                - removes all use labelable parts.  Calling this function undoes \n                  all previous calls to add_labelable_part_name().  Therefore, the \n                  user won't be able to label any parts after clear_labelable_part_names()\n                  is called.\n        !*/\n\n        rectangle get_image_display_rect (\n        ) const;\n        /*!\n            ensures\n                - returns a rectangle R that tells you how big the image inside the\n                  display is when it appears on the screen.  Note that it takes the\n                  current zoom level into account.\n                    - R.width()  == the width of the displayed image\n                    - R.height() == the height of the displayed image\n                    - R.tl_corner() == (0,0)\n        !*/\n\n        void enable_overlay_editing (\n        ); \n        /*!\n            ensures\n                - #overlay_editing_is_enabled() == true\n        !*/\n\n        void disable_overlay_editing (\n        );\n        /*!\n            ensures\n                - #overlay_editing_is_enabled() == false \n        !*/\n        \n        bool overlay_editing_is_enabled (\n        ) const; \n        /*!\n            ensures\n                - if this function returns true then it is possible for the user to add or\n                  remove overlay objects (e.g. rectangles) using the mouse and keyboard.\n                  If it returns false then the overlay is not user editable.\n        !*/\n\n        void zoom_in (\n        );\n        /*!\n            ensures\n                - performs a zoom in as if the user tried to zoom by scrolling the mouse wheel.\n        !*/\n\n        void zoom_out (\n        );\n        /*!\n            ensures\n                - performs a zoom out as if the user tried to zoom by scrolling the mouse wheel.\n        !*/\n\n        template <\n            typename T\n            >\n        void set_overlay_rects_changed_handler (\n            T& object,\n            void (T::*event_handler)()\n        );\n        /*\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - the event_handler function is called on object when the user adds,\n                  removes, or modifies an overlay rectangle.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        */\n\n        void set_overlay_rects_changed_handler (\n            const any_function<void()>& event_handler\n        );\n        /*\n            ensures\n                - the event_handler function is called when the user adds or removes \n                  an overlay rectangle.\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        */\n\n        template <\n            typename T\n            >\n        void set_overlay_rect_selected_handler (\n            T& object,\n            void (T::*event_handler)(const overlay_rect& orect)\n        );\n        /*\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - The event_handler function is called on object when the user selects\n                  an overlay rectangle by double clicking on it.  The selected rectangle \n                  will be passed to event_handler().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        */\n\n        void set_overlay_rect_selected_handler (\n            const any_function<void(const overlay_rect& orect)>& event_handler\n        );\n        /*\n            ensures\n                - The event_handler function is called when the user selects an overlay \n                  rectangle by double clicking on it.  The selected rectangle will be \n                  passed to event_handler().\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        */\n\n        template <\n            typename T\n            >\n        void set_image_clicked_handler (\n            T& object,\n            void (T::*event_handler)(const point& p, bool is_double_click, unsigned long btn)\n        );\n        /*\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - The event_handler function is called on object when the user left clicks\n                  anywhere on the image.  When they do so this callback is called with the\n                  location of the image pixel which was clicked.  The is_double_click bool\n                  will also tell you if it was a double click or single click.\n                - btn == the button that was released. (either base_window::LEFT, base_window::MIDDLE, or base_window::RIGHT)\n                - any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n            throws\n                - std::bad_alloc\n        */\n\n        void set_image_clicked_handler (\n            const any_function<void(const point& p, bool is_double_click, unsigned long btn)>& event_handler\n        );\n        /*\n            ensures\n                - The event_handler function is called when the user left clicks anywhere\n                  on the image.  When they do so this callback is called with the location\n                  of the image pixel which was clicked.  The is_double_click bool will also\n                  tell you if it was a double click or single click.\n                - btn == the button that was released. (either base_window::LEFT, base_window::MIDDLE, or base_window::RIGHT)\n                - Any previous calls to this function are overridden by this new call.\n                  (i.e. you can only have one event handler associated with this event at a\n                  time)\n            throws\n                - std::bad_alloc\n        */\n\n    private:\n\n        // restricted functions\n        image_display(image_display&);        // copy constructor\n        image_display& operator=(image_display&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class image_window : public drawable_window \n    {\n        /*!\n            INITIAL VALUE\n                - initially, this object is visible on the screen\n                - events_tied() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple window that is just a container for an image_display.  \n                It exists to make it easy to throw image_displays onto the screen \n                without having to put together your own drawable_window objects.\n        !*/\n    public:\n\n        typedef image_display::overlay_rect overlay_rect;\n        typedef image_display::overlay_line overlay_line;\n        typedef image_display::overlay_circle overlay_circle;\n\n        image_window(\n        ); \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <typename image_type>\n        image_window(\n            const image_type& img\n        ); \n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h or\n                  a dlib::matrix or something convertible to a matrix via mat()\n                - pixel_traits<typename image_type::type> must be defined \n            ensures\n                - this object is properly initialized \n                - #*this window is now displaying the given image img.\n        !*/\n\n        template < typename image_type>\n        image_window(\n            const image_type& img,\n            const std::string& title\n        );\n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h or\n                  a dlib::matrix or something convertible to a matrix via mat()\n                - pixel_traits<typename image_type::type> must be defined \n            ensures\n                - this object is properly initialized \n                - #*this window is now displaying the given image img.\n                - The title of the window will be set to the given title string.\n        !*/\n\n        ~image_window(\n        );\n        /*!\n            ensures\n                - any resources associated with this object have been released\n        !*/\n\n        template <typename image_type>\n        void set_image (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an implementation of array2d/array2d_kernel_abstract.h\n                - pixel_traits<typename image_type::type> must be defined \n            ensures\n                - #*this window is now displaying the given image img.\n        !*/\n\n        void add_overlay (\n            const overlay_rect& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay rectangle into this object such\n                  that it will be displayed. \n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const rectangle& r, \n            pixel_type p = rgb_pixel(255,0,0)\n        );\n        /*!\n            ensures\n                - performs: add_overlay(overlay_rect(r,p));\n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const rectangle& r, \n            pixel_type p, \n            const std::string& l\n        );\n        /*!\n            ensures\n                - performs: add_overlay(overlay_rect(r,p,l));\n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const std::vector<rectangle>& r,\n            pixel_type p = rgb_pixel(255,0,0)\n        );\n        /*!\n            ensures\n                - adds the given set of rectangles into this object such\n                  that they will be displayed with the color specific by p. \n        !*/\n\n        void add_overlay(\n            const full_object_detection& object,\n            const std::vector<std::string>& part_names\n        );\n        /*!\n            ensures\n                - adds the given full_object_detection to the overlays\n                  and shows it on the screen.  This includes any of its\n                  parts that are not set equal to OBJECT_PART_NOT_PRESENT.\n                - for all valid i < part_names.size():\n                    - the part object.part(i) will be labeled with the string\n                      part_names[i].\n        !*/\n\n        void add_overlay(\n            const full_object_detection& object\n        );\n        /*!\n            ensures\n                - adds the given full_object_detection to the overlays\n                  and shows it on the screen.  This includes any of its\n                  parts that are not set equal to OBJECT_PART_NOT_PRESENT.\n        !*/\n\n        void add_overlay(\n            const std::vector<full_object_detection>& objects,\n            const std::vector<std::string>& part_names\n        ); \n        /*!\n            ensures\n                - calling this function is equivalent to calling the following\n                  sequence of functions, for all valid i:\n                    - add_overlay(objects[i], part_names);\n        !*/\n\n        void add_overlay(\n            const std::vector<full_object_detection>& objects\n        );\n        /*!\n            ensures\n                - calling this function is equivalent to calling the following\n                  sequence of functions, for all valid i:\n                    - add_overlay(objects[i]);\n        !*/\n\n        void add_overlay (\n            const overlay_line& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay line into this object such\n                  that it will be displayed. \n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const line& l, \n            pixel_type p\n        );\n        /*!\n            ensures\n                - performs: add_overlay(overlay_line(l.p1(),l.p2(),p)); \n        !*/\n\n        void add_overlay (\n            const overlay_circle& overlay\n        );\n        /*!\n            ensures\n                - adds the given overlay circle into this object such\n                  that it will be displayed. \n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const point& p1,\n            const point& p2,\n            pixel_type p\n        );\n        /*!\n            ensures\n                - performs: add_overlay(overlay_line(p1,p2,p));\n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_rect>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay rectangles into this object such\n                  that they will be displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay lines into this object such\n                  that they will be displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_circle>& overlay\n        );\n        /*!\n            ensures\n                - adds the given set of overlay circles into this object such\n                  that they will be displayed. \n        !*/\n\n        void clear_overlay (\n        );\n        /*!\n            ensures\n                - removes all overlays from this object.  \n        !*/\n\n        void tie_events (\n        );\n        /*!\n            ensures\n                - #events_tied() == true\n        !*/\n\n        void untie_events (\n        );\n        /*!\n            ensures\n                - #events_tied() == false \n        !*/\n\n        bool events_tied (\n        ) const;\n        /*!\n            ensures\n                - returns true if and only if the get_next_double_click() and\n                  get_next_keypress() events are tied together.  If they are tied it means\n                  that you can use a loop of the following form to listen for both events\n                  simultaneously:\n                    while (mywindow.get_next_double_click(p) || mywindow.get_next_keypress(key,printable))\n                    {\n                        if (p.x() < 0)\n                            // Do something with the keyboard event\n                        else\n                            // Do something with the mouse event\n                    }\n        !*/\n\n        bool get_next_double_click (\n            point& p\n        ); \n        /*!\n            ensures\n                - This function blocks until the user double clicks on the image or the\n                  window is closed by the user.  It will also unblock for a keyboard key\n                  press if events_tied() == true.\n                - if (this function returns true) then\n                    - This means the user double clicked the mouse.\n                    - #p == the next image pixel the user clicked.  \n                - else\n                    - #p == point(-1,1)\n        !*/\n\n        bool get_next_double_click (\n            point& p,\n            unsigned long& mouse_button\n        ); \n        /*!\n            ensures\n                - This function blocks until the user double clicks on the image or the\n                  window is closed by the user.  It will also unblock for a keyboard key\n                  press if events_tied() == true.\n                - if (this function returns true) then\n                    - This means the user double clicked the mouse.\n                    - #p == the next image pixel the user clicked.  \n                    - #mouse_button == the mouse button which was used to double click.\n                      This will be either dlib::base_window::LEFT,\n                      dlib::base_window::MIDDLE, or dlib::base_window::RIGHT\n                - else\n                    - #p == point(-1,1)\n                      (Note that this point is outside any possible image)\n        !*/\n\n        bool get_next_keypress (\n            unsigned long& key,\n            bool& is_printable,\n            unsigned long& state\n        );\n        /*!\n            ensures\n                - This function blocks until the user presses a keyboard key or the\n                  window is closed by the user.  It will also unblock for a mouse double\n                  click if events_tied() == true.\n                - if (this function returns true) then\n                    - This means the user pressed a keyboard key.\n                    - The keyboard button press is recorded into #key, #is_printable, and\n                      #state.  In particular, these variables are populated with the three\n                      identically named arguments to the base_window::on_keydown(key,is_printable,state) \n                      event.\n        !*/\n\n        bool get_next_keypress (\n            unsigned long& key,\n            bool& is_printable\n        );\n        /*!\n            ensures\n                - This function blocks until the user presses a keyboard key or the\n                  window is closed by the user.  It will also unblock for a mouse double\n                  click if events_tied() == true.\n                - This function is the equivalent to calling get_next_keypress(key,is_printable,temp) \n                  and then discarding temp.\n        !*/\n\n    private:\n\n        // restricted functions\n        image_window(image_window&);\n        image_window& operator= (image_window&);\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class perspective_display : public drawable, noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for displaying 3D point clouds on a screen.  You can\n                navigate the display with the mouse.  Left click and drag rotates the\n                camera around the displayed data.  Scrolling the mouse wheel zooms and\n                shift+left click (or just right click) and drag pans the view around.\n        !*/\n\n    public:\n\n        perspective_display(  \n            drawable_window& w\n        );\n        /*!\n            ensures \n                - #*this is properly initialized \n                - #*this has been added to window w\n                - #parent_window() == w\n        !*/\n\n        ~perspective_display(\n        );\n        /*!\n            ensures\n                - all resources associated with *this have been released\n        !*/\n\n        void set_size (\n            unsigned long width,\n            unsigned long height \n        );\n        /*! \n            ensures\n                - #width() == width\n                - #height() == height\n                - #top() == top()\n                - #left() == left()\n                - i.e. The location of the upper left corner of this widget stays the\n                  same but its width and height are modified.\n        !*/\n\n        struct overlay_line\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a line that is drawn on the screen.  Each line\n                    is represented by its two end points (p1 and p2) as well as a color.\n            !*/\n\n            overlay_line() { assign_pixel(color, 0);}\n\n            overlay_line(const vector<double>& p1_, const vector<double>& p2_) \n                : p1(p1_), p2(p2_) { assign_pixel(color, 255); }\n\n            template <typename pixel_type>\n            overlay_line(const vector<double>& p1_, const vector<double>& p2_, pixel_type p) \n                : p1(p1_), p2(p2_) { assign_pixel(color, p); }\n\n            vector<double> p1;\n            vector<double> p2;\n            rgb_pixel color;\n        };\n\n        struct overlay_dot\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a dot that is drawn on the screen.  Each dot is\n                    represented by one point and a color.\n            !*/\n\n            overlay_dot() { assign_pixel(color, 0);}\n\n            overlay_dot(const vector<double>& p_) \n                : p(p_) { assign_pixel(color, 255); }\n\n            template <typename pixel_type>\n            overlay_dot(const vector<double>& p_, pixel_type color_) \n                : p(p_) { assign_pixel(color, color_); }\n\n            vector<double> p; // The location of the dot\n            rgb_pixel color;\n        };\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n        /*!\n            ensures\n                - Adds the given overlay lines into this object such that it will be\n                  displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_dot>& overlay\n        );\n        /*!\n            ensures\n                - Adds the given overlay dots into this object such that it will be\n                  displayed. \n        !*/\n\n        void clear_overlay (\n        );\n        /*!\n            ensures\n                - Removes all overlays from this object.  The display will be empty.\n        !*/\n\n        template <typename T>\n        void set_dot_double_clicked_handler (\n            T& object,\n            void (T::*event_handler)(const vector<double>&)\n        );\n        /*\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - The event_handler function is called on object when the user double\n                  clicks on one of the overlay dots.  The selected dot will be passed to\n                  event_handler().\n                - Any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n        */\n\n        void set_dot_double_clicked_handler (\n            const any_function<void(const vector<double>&)>& event_handler\n        );\n        /*\n            ensures\n                - The event_handler function is called when the user double clicks on one\n                  of the overlay dots.  The selected dot will be passed to event_handler().\n                - Any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n        */\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class perspective_window : public drawable_window, noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple window that is just a container for a perspective_display.\n                It exists to make it easy to throw perspective_displays onto the screen\n                without having to put together your own drawable_window objects.\n        !*/\n    public:\n\n        typedef perspective_display::overlay_line overlay_line;\n        typedef perspective_display::overlay_dot overlay_dot;\n\n        perspective_window(\n        );\n        /*!\n            ensures\n                - The window is displayed on the screen and is 100x100 pixels in size.\n        !*/\n\n        perspective_window(\n            const std::vector<dlib::vector<double> >& point_cloud\n        );\n        /*!\n            ensures\n                - The window is displayed on the screen and is 100x100 pixels in size.\n                - This window will have point_cloud added to it via add_overlay() and the\n                  points will all be white.\n        !*/\n        \n        perspective_window(\n            const std::vector<dlib::vector<double> >& point_cloud,\n            const std::string& title\n        );\n        /*!\n            ensures\n                - The window is displayed on the screen and is 100x100 pixels in size.\n                - This window will have point_cloud added to it via add_overlay() and the\n                  points will all be white.\n                - The title of the window will be set to the given title string.\n        !*/\n        \n        ~perspective_window(\n        );\n        /*!\n            ensures\n                - any resources associated with this object have been released\n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_line>& overlay\n        );\n        /*!\n            ensures\n                - Adds the given overlay lines into this object such that it will be\n                  displayed. \n        !*/\n\n        void add_overlay (\n            const std::vector<overlay_dot>& overlay\n        );\n        /*!\n            ensures\n                - Adds the given overlay dots into this object such that it will be\n                  displayed. \n        !*/\n\n        void clear_overlay (\n        );\n        /*!\n            ensures\n                - Removes all overlays from this object.  The display will be empty.\n        !*/\n\n        void add_overlay(\n            const std::vector<dlib::vector<double> >& d\n        ); \n        /*!\n            ensures\n                - Adds the given dots into this object such that it will be\n                  displayed.  They will be colored white.\n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const std::vector<dlib::vector<double> >& d, \n            pixel_type p\n        );\n        /*!\n            ensures\n                - Adds the given dots into this object such that it will be\n                  displayed.  They will be colored by pixel color p.\n        !*/\n\n        template <typename pixel_type>\n        void add_overlay(\n            const vector<double>& p1,\n            const vector<double>& p2, \n            pixel_type color\n        );\n        /*!\n            ensures\n                - Adds an overlay line going from p1 to p2 with the given color.\n        !*/\n\n        template < typename T >\n        void set_dot_double_clicked_handler (\n            T& object,\n            void (T::*event_handler)(const vector<double>&)\n        );\n        /*\n            requires\n                - event_handler is a valid pointer to a member function in T \n            ensures\n                - The event_handler function is called on object when the user double\n                  clicks on one of the overlay dots.  The selected dot will be passed to\n                  event_handler().\n                - Any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n        */\n\n        void set_dot_double_clicked_handler (\n            const any_function<void(const vector<double>&)>& event_handler\n        );\n        /*\n            ensures\n                - The event_handler function is called when the user double clicks on one\n                  of the overlay dots.  The selected dot will be passed to event_handler().\n                - Any previous calls to this function are overridden by this new call.  \n                  (i.e. you can only have one event handler associated with this \n                  event at a time)\n        */\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WIDGETs_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/gui_widgets.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_GUI_WIDGETs_\n#define DLIB_GUI_WIDGETs_\n\n\n\n#include \"gui_widgets/widgets.h\"\n\n\n\n#endif // DLIB_GUI_WIDGETs_\n\n"
  },
  {
    "path": "dlib/hash.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASh_\n#define DLIB_HASh_\n\n\n#include \"general_hash/hash.h\"\n#include \"general_hash/random_hashing.h\"\n#include \"general_hash/count_bits.h\"\n\n\n#endif // DLIB_HASh_\n\n\n"
  },
  {
    "path": "dlib/hash_map/hash_map_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_MAP_KERNEl_1_\n#define DLIB_HASH_MAP_KERNEl_1_\n\n#include \"hash_map_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../general_hash/general_hash.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/remover.h\"\n#include \"../assert.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager = default_memory_manager\n        >\n    class hash_map_kernel_1 : public enumerable<map_pair<domain,range> >,\n                              public pair_remover<domain,range>\n    {\n\n        /*!\n            REQUIREMENTS ON hash_table\n                hash_table is instantiated with domain and range and\n                T_is_POD must be set to false and\n                implements hash_table/hash_table_kernel_abstract.h\n\n            INITIAL VALUE\n                table.size() == 0\n\n            CONVENTION\n                table.size() = size() == the number of elements in the map \n                the elements in this hash_map are stored in table\n        !*/\n        \n\n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef typename hash_table::compare_type compare_type;\n            typedef mem_manager mem_manager_type;\n\n            hash_map_kernel_1(\n            ) :\n                table(expnum)\n            {\n                COMPILE_TIME_ASSERT(expnum < 32);\n            }\n\n            virtual ~hash_map_kernel_1(\n            )\n            {}\n\n            inline void clear(\n            );            \n\n            void add (\n                domain& d,\n                range& r\n            );\n\n            inline bool is_in_domain (\n                const domain& d\n            ) const;\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n \n            void destroy (\n                const domain& d\n            );\n \n            range& operator[] (\n                const domain& d\n            );\n\n            const range& operator[] (\n                const domain& d\n            ) const;\n\n            inline void swap (\n                hash_map_kernel_1& item\n            );\n\n            // functions from the remover interface\n            inline void remove_any (\n                domain& d,\n                range& r\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            inline bool current_element_valid (\n            ) const;\n\n            inline const map_pair<domain,range>& element (\n            ) const;\n\n            inline map_pair<domain,range>& element (\n            );\n\n            inline bool move_next (\n            ) const;\n    \n        private:\n\n            hash_table table;\n\n            // restricted functions\n            hash_map_kernel_1(hash_map_kernel_1&);    \n            hash_map_kernel_1& operator= ( hash_map_kernel_1&);\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    inline void swap (\n        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& a, \n        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& b \n    ) { a.swap(b); } \n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void deserialize (\n        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& item,\n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hash_map_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    clear (\n    )\n    {\n        table.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    add (\n        domain& d,\n        range& r\n    )\n    {\n        table.add(d,r); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    is_in_domain(\n        const domain& d\n    ) const\n    {\n        return (table[d] != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    remove_any (\n        domain& d,\n        range& r\n    )\n    {\n        table.remove_any(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    remove(\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        table.remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    destroy(\n        const domain& d\n    )\n    {\n        table.destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    range& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    operator[](\n        const domain& d\n    )\n    {\n        return *table[d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    const range& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    operator[](\n        const domain& d\n    ) const\n    {\n        return *table[d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    size_t hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    size (\n    ) const\n    {\n        return table.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    swap (\n        hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>& item\n    )\n    {\n        table.swap(item.table);      \n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    at_start (\n    ) const\n    {\n        return table.at_start();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    reset (\n    ) const\n    {\n        table.reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return table.current_element_valid();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    const map_pair<domain,range>& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    element (\n    ) const\n    {\n        return table.element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    map_pair<domain,range>& hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    element (\n    )\n    {\n        return table.element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_map_kernel_1<domain,range,expnum,hash_table,mem_manager>::\n    move_next (\n    ) const\n    {\n        return table.move_next();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_MAP_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/hash_map/hash_map_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HASH_MAP_KERNEl_ABSTRACT_\n#ifdef DLIB_HASH_MAP_KERNEl_ABSTRACT_\n\n#include \"../general_hash/general_hash.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include <functional>\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<T>\n        >\n    class hash_map : public enumerable<map_pair<domain,range> >,\n                     public pair_remover<domain,range>\n    {\n\n        /*!\n            REQUIREMENTS ON domain\n                domain must be comparable by compare where compare is a functor compatible with std::less and\n                domain must be hashable by general_hash \n                (general_hash is defined in dlib/general_hash) and \n                domain must be swappable by a global swap() and\n                domain must have a default constructor\n\n            REQUIREMENTS ON range\n                range must be swappable by a global swap() and\n                range must have a default constructor\n\n            REQUIREMENTS ON expnum\n                expnum < 32\n                2^expnum is the number of buckets to hash items of type T into.\n                Note that this is really just a suggestion to the hash table.\n                Implementations are free to manage the table size however is most\n                appropriate.\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap(), is_in_domain(), and operator[] functions do \n                not invalidate pointers or references to internal data.\n                All other functions have no such guarantees.\n\n            INITIAL VALUE\n                size() == 0\n\n            ENUMERATION ORDER\n                No order is specified.  Only that each element will be visited once\n                and only once.\n\n            WHAT THIS OBJECT REPRESENTS\n                hash_map contains items of type domain and range\n\n                This object is similar an array.  It maps items of type domain on to \n                items of type range.  \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n\n                definition of equivalent:\n                a is equivalent to b if\n                a < b == false and\n                b < a == false\n        !*/\n        \n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            hash_map(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n            !*/\n\n            virtual ~hash_map(\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void add (\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - &d != &r (i.e. d and r cannot be the same variable) \n                    - is_in_domain(d)  == false\n                ensures\n                    - #is_in_domain(d) == true \n                    - #operator[](d)   == r    \n                    - #d and #r have initial values for their types \n                    - #size() == size() + 1\n                    - #at_start() == true\n                throws \n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if add() throws then it has no effect\n            !*/\n\n            bool is_in_domain (\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - returns whether or not an element equivalent to d is in the \n                      domain of *this\n            !*/\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n            /*!\n                requires\n                    - &d != &r (i.e. d and r cannot be the same variable) \n                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable) \n                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable) \n                    - is_in_domain(d) == true\n                ensures\n                    - #is_in_domain(d) == false \n                    - #d_copy is equivalent to d \n                    - the element in the range of *this associated with #d_copy has \n                      been swapped into #r \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            void destroy (\n                const domain& d\n            );\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - #is_in_domain(d) == false \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            range& operator[] (\n                const domain& d\n            );\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - returns a non-const reference to the element in the range of *this \n                      associated with the element equivalent to d\n            !*/\n\n            const range& operator[] (\n                const domain& d\n            ) const;\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - returns a const reference to the element in the range of *this \n                      associated with the element equivalent to d\n            !*/\n\n            void swap (\n                hash_map& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n    \n        private:\n\n            // restricted functions\n            hash_map(hash_map&);        \n            hash_map& operator=(hash_map&);   \n    };\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        hash_map<domain,range,expnum,mem_manager,compare>& a, \n        hash_map<domain,range,expnum,mem_manager,compare>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        hash_map<domain,range,expnum,mem_manager,compare>& item,\n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_HASH_MAP_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/hash_map/hash_map_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_MAP_KERNEl_C_\n#define DLIB_HASH_MAP_KERNEl_C_\n\n#include \"hash_map_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename hash_map_base\n        >\n    class hash_map_kernel_c : public hash_map_base\n    {\n\n        typedef typename hash_map_base::domain_type domain;\n        typedef typename hash_map_base::range_type range;\n\n        \n        public:\n            void add (\n                domain& d,\n                range& r\n            );\n\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            range& operator[] (\n                const domain& d\n            );\n\n            const range& operator[] (\n                const domain& d\n            ) const;\n\n            const map_pair<domain,range>& element (\n            ) const;\n\n            map_pair<domain,range>& element (\n            );\n    };\n\n    template <\n        typename hash_map_base\n        >\n    inline void swap (\n        hash_map_kernel_c<hash_map_base>& a, \n        hash_map_kernel_c<hash_map_base>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    void hash_map_kernel_c<hash_map_base>::\n    add (\n        domain& d,\n        range& r\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (!this->is_in_domain(d)) &&\n                (static_cast<void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid hash_map::add\"\n            << \"\\n\\tdomain element being added must not already be in the hash_map\"\n            << \"\\n\\tand d and r must not be the same variable\"\n            << \"\\n\\tis_in_domain(d): \" << (this->is_in_domain(d) ? \"true\" : \"false\")\n            << \"\\n\\tthis: \" << this\n            << \"\\n\\t&d:   \" << static_cast<void*>(&d)\n            << \"\\n\\t&r:   \" << static_cast<void*>(&r)\n            );\n\n\n        // call the real function\n        hash_map_base::add(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    void hash_map_kernel_c<hash_map_base>::\n    remove_any (\n        domain& d,\n        range& r\n    )\n    {\n\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->size() > 0)  &&\n                (static_cast<void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid hash_map::remove_any\"\n            << \"\\n\\tsize() must be greater than zero if something is going to be removed\"\n            << \"\\n\\tand d and r must not be the same variable.\"\n            << \"\\n\\tsize(): \" << this->size() \n            << \"\\n\\tthis:   \" << this\n            << \"\\n\\t&d:     \" << static_cast<void*>(&d)\n            << \"\\n\\t&r:     \" << static_cast<void*>(&r)\n            );\n\n\n        // call the real function\n        hash_map_base::remove_any(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    void hash_map_kernel_c<hash_map_base>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->is_in_domain(d)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&\n                (static_cast<void*>(&r) != static_cast<void*>(&d_copy)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)),\n            \"\\tvoid hash_map::remove\"\n            << \"\\n\\tcan't remove something that isn't in the hash_map or if the paremeters\"\n            << \"\\n\\tare actually the same variable.  Either way can't remove.\"\n            << \"\\n\\tis_in_domain(d): \" << (this->is_in_domain(d) ? \"true\" : \"false\")\n            << \"\\n\\tthis:      \" << this\n            << \"\\n\\t&d:        \" << static_cast<const void*>(&d)\n            << \"\\n\\t&r:        \" << static_cast<void*>(&r)\n            << \"\\n\\t&d_copy:   \" << static_cast<void*>(&d_copy)\n            );\n\n\n        // call the real function\n        hash_map_base::remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    void hash_map_kernel_c<hash_map_base>::\n    destroy (\n        const domain& d\n    )\n    {\n\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_in_domain(d), \n            \"\\tvoid hash_map::destroy\"\n            << \"\\n\\tcan't remove something that isn't in the hash_map\"\n            << \"\\n\\tthis:      \" << this\n            << \"\\n\\t&d:        \" << static_cast<const void*>(&d)\n            );\n\n\n        // call the real function\n        hash_map_base::destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    typename hash_map_base::range_type& hash_map_kernel_c<hash_map_base>::\n    operator[] (\n        const domain& d\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_in_domain(d),\n            \"\\trange& hash_map::operator[]\"\n            << \"\\n\\td must be in the domain of the hash_map\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return hash_map_base::operator[](d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    const typename hash_map_base::range_type& hash_map_kernel_c<hash_map_base>::\n    operator[] (\n        const domain& d\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_in_domain(d),\n            \"\\tconst range& hash_map::operator[]\"\n            << \"\\n\\td must be in the domain of the hash_map\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return hash_map_base::operator[](d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    const map_pair<typename hash_map_base::domain_type,typename hash_map_base::range_type>& hash_map_kernel_c<hash_map_base>::\n    element (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tconst map_pair<domain,range>& hash_map::element\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return hash_map_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_map_base\n        >\n    map_pair<typename hash_map_base::domain_type,typename hash_map_base::range_type>& hash_map_kernel_c<hash_map_base>::\n    element (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tmap_pair<domain,range>& hash_map::element\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return hash_map_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_MAP_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/hash_map.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_MAp_\n#define DLIB_HASH_MAp_\n\n#include \"hash_map/hash_map_kernel_1.h\"\n#include \"hash_map/hash_map_kernel_c.h\"\n\n#include \"hash_table.h\"\n#include \"algs.h\"\n\n#include \"algs.h\"\n#include <functional>\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        unsigned long expnum,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class hash_map\n    {\n        hash_map() {}\n\n        typedef typename hash_table<domain,range,mem_manager,compare>::kernel_1a\n                hash_table_1;\n        typedef typename hash_table<domain,range,mem_manager,compare>::kernel_2a\n                hash_table_2;\n        typedef typename hash_table<domain,range,mem_manager,compare>::kernel_2b\n                hash_table_3;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     hash_map_kernel_1<domain,range,expnum,hash_table_1,mem_manager>\n                    kernel_1a;\n        typedef     hash_map_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n        // kernel_1b        \n        typedef     hash_map_kernel_1<domain,range,expnum,hash_table_2,mem_manager>\n                    kernel_1b;\n        typedef     hash_map_kernel_c<kernel_1b>\n                    kernel_1b_c;\n \n        // kernel_1c        \n        typedef     hash_map_kernel_1<domain,range,expnum,hash_table_3,mem_manager>\n                    kernel_1c;\n        typedef     hash_map_kernel_c<kernel_1c>\n                    kernel_1c_c;\n\n\n    };\n}\n\n#endif // DLIB_HASH_MAp_\n\n"
  },
  {
    "path": "dlib/hash_set/hash_set_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_SET_KERNEl_1_\n#define DLIB_HASH_SET_KERNEl_1_\n\n#include \"hash_set_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../general_hash/general_hash.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../assert.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager = default_memory_manager \n        >\n    class hash_set_kernel_1 : public enumerable<const T>,\n                              public remover<T>\n    {\n\n        /*!\n            REQUIREMENTS ON hash_table\n                hash_table is instantiated with <domain=T,range=char> and\n                T_is_POD must be set to false and\n                is an implementation of hash_table/hash_table_kernel_abstract.h\n\n            INITIAL VALUE\n                table.size() == 0\n\n            CONVENTION\n                table.size() = size() == the number of elements in the set and\n                the elements in this hash_set are stored in table\n        !*/\n        \n        public:\n\n            typedef T type;\n            typedef typename hash_table::compare_type compare_type;\n            typedef mem_manager mem_manager_type;\n\n            hash_set_kernel_1(\n            ) :\n                table(expnum)\n            {\n                COMPILE_TIME_ASSERT(expnum < 32);\n            }\n\n            virtual ~hash_set_kernel_1(\n            )\n            {}\n\n            inline void clear(\n            );\n\n            inline void add (\n                T& item\n            );\n\n            inline bool is_member (\n                const T& item\n            ) const;\n\n            inline void remove (\n                const T& item,\n                T& item_copy\n            );\n\n            inline void destroy (\n                const T& item\n            );\n\n            inline void swap (\n                hash_set_kernel_1& item\n            );\n\n            // functions from the remover interface\n            inline void remove_any (\n                T& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            inline bool current_element_valid (\n            ) const;\n\n            inline const T& element (\n            ) const;\n\n            inline const T& element (\n            );\n\n            inline bool move_next (\n            ) const;\n\n        private:\n\n            hash_table table;\n            char junk;\n\n            // restricted functions\n            hash_set_kernel_1(hash_set_kernel_1&);    \n            hash_set_kernel_1& operator= ( hash_set_kernel_1&);\n\n    };\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    inline void swap (\n        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& a, \n        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& b \n    ) { a.swap(b); } \n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void deserialize (\n        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& item,\n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            T temp;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(temp,in);\n                item.add(temp);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hash_set_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    clear (\n    )\n    {\n        table.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    add (\n        T& item\n    )\n    {\n        table.add(item,junk);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    is_member(\n        const T& item\n    ) const\n    {\n        return (table[item] != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    remove_any (\n        T& item\n    )\n    {\n        table.remove_any(item,junk);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    remove(\n        const T& item,\n        T& item_copy\n    )\n    {\n        table.remove(item,item_copy,junk);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    destroy(\n        const T& item\n    )\n    {\n        table.destroy(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    size_t hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    size (\n    ) const\n    {\n        return table.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    swap (\n        hash_set_kernel_1<T,expnum,hash_table,mem_manager>& item\n    )\n    {\n        table.swap(item.table);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    at_start (\n    ) const\n    {\n        return table.at_start();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    void hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    reset (\n    ) const\n    {\n        table.reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return table.current_element_valid();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    const T& hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    element (\n    ) const\n    {\n        return table.element().key();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    const T& hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    element (\n    )\n    {\n        return table.element().key();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename hash_table,\n        typename mem_manager\n        >\n    bool hash_set_kernel_1<T,expnum,hash_table,mem_manager>::\n    move_next (\n    ) const\n    {\n        return table.move_next();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_SET_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/hash_set/hash_set_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HASH_SET_KERNEl_ABSTRACT_\n#ifdef DLIB_HASH_SET_KERNEl_ABSTRACT_\n\n#include \"../general_hash/general_hash.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include <functional>\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<T>\n        >\n    class hash_set : public enumerable<const T>,\n                     public remover<T>\n    {\n\n        /*!                \n            REQUIREMENTS ON T\n                domain must be comparable by compare where compare is a functor compatible with std::less and\n                T must be hashable by general_hash\n                (general_hash is defined in dlib/general_hash) and \n                T must be swappable by a global swap() and\n                T must have a default constructor\n\n            REQUIREMENTS ON expnum\n                expnum < 32\n                2^expnum is the number of buckets to hash items of type T into. \n                Note that this is really just a suggestion to the hash table.\n                Implementations are free to manage the table size however is most\n                appropriate.\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap() and is_member() functions do not invalidate \n                pointers or references to internal data.\n                All other functions have no such guarantee.\n\n            INITIAL VALUE\n                size() == 0    \n\n            ENUMERATION ORDER\n                No order is specified.  Only that each element will be visited once\n                and only once.\n\n            WHAT THIS OBJECT REPRESENTS\n                hash_set contains items of type T\n\n                This object represents an unaddressed collection \n                of items.  Every element in a hash_set is unique.\n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n\n                definition of equivalent:\n                a is equivalent to b if\n                a < b == false and\n                b < a == false\n        !*/\n        \n        public:\n\n            typedef T type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            hash_set(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            virtual ~hash_set(\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void add (\n                T& item\n            );\n            /*!\n                requires\n                    - is_member(item) == false\n                ensures\n                    - #is_member(item) == true \n                    - #item has an initial value for its type \n                    - #size() == size() + 1\n                    - #at_start() == true\n                throws \n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if add() throws then it has no effect\n            !*/\n\n            bool is_member (\n                const T& item\n            ) const;\n            /*!\n                ensures\n                    - returns whether or not there is an element in *this equivalent \n                      to item\n            !*/\n\n            void remove (\n                const T& item,\n                T& item_copy\n            );\n            /*!\n                requires\n                    - is_member(item) == true \n                    - &item != &item_copy (i.e. item and item_copy cannot be the \n                      same variable) \n                ensures\n                    - #is_member(item) == false \n                    - the element in *this equivalent to item has been removed and \n                      swapped into #item_copy \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            void destroy (\n                const T& item\n            );\n            /*!\n                requires\n                    - is_member(item) == true \n                ensures\n                    - #is_member(item) == false \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            void swap (\n                hash_set& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n    \n        private:\n\n            // restricted functions\n            hash_set(hash_set&);        // copy constructor\n            hash_set& operator=(hash_set&);    // assignment operator\n\n    };\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        hash_set<T,expnum,mem_manager,compare>& a, \n        hash_set<T,expnum,mem_manager,compare>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        hash_set<T,expnum,mem_manager,compare>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_HASH_SET_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/hash_set/hash_set_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_SET_KERNEl_C_\n#define DLIB_HASH_SET_KERNEl_C_\n\n#include \"hash_set_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename hash_set_base\n        >\n    class hash_set_kernel_c : public hash_set_base\n    {\n        typedef typename hash_set_base::type T;\n        public:\n\n            void add (\n                T& item\n            );\n\n            void remove_any (\n                T& item\n            );\n\n            void remove (\n                const T& item,\n                T& item_copy\n            );\n\n            void destroy (\n                const T& item\n            );\n\n            const T& element (\n            ) const;\n\n            const T& element (\n            );\n\n\n    };\n\n\n    template <\n        typename hash_set_base\n        >\n    inline void swap (\n        hash_set_kernel_c<hash_set_base>& a, \n        hash_set_kernel_c<hash_set_base>& b \n    ) { a.swap(b); } \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    void hash_set_kernel_c<hash_set_base>::\n    add(\n        T& item\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( !this->is_member(item),\n            \"\\tvoid hash_set::add\"\n            << \"\\n\\titem being added must not already be in the hash_set\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        hash_set_base::add(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    void hash_set_kernel_c<hash_set_base>::\n    remove (\n        const T& item,\n        T& item_copy\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_member(item) &&\n                (static_cast<const void*>(&item) != static_cast<void*>(&item_copy)),\n            \"\\tvoid hash_set::remove\"\n            << \"\\n\\titem should be in the hash_set if it's going to be removed\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&item:      \" << &item\n            << \"\\n\\t&item_copy: \" << &item_copy\n            );\n\n        // call the real function\n        hash_set_base::remove(item,item_copy);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    void hash_set_kernel_c<hash_set_base>::\n    destroy (\n        const T& item\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_member(item),\n            \"\\tvoid hash_set::destroy\"\n            << \"\\n\\titem should be in the hash_set if it's going to be removed\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&item:      \" << &item\n            );\n\n        // call the real function\n        hash_set_base::destroy(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    void hash_set_kernel_c<hash_set_base>::\n    remove_any (\n        T& item\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->size() != 0,\n            \"\\tvoid hash_set::remove_any\"\n            << \"\\n\\tsize must be greater than zero if an item is to be removed\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        hash_set_base::remove_any(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    const typename hash_set_base::type& hash_set_kernel_c<hash_set_base>::\n    element (\n    ) const\n    {\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tconst T& hash_set::element()\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        return hash_set_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hash_set_base\n        >\n    const typename hash_set_base::type& hash_set_kernel_c<hash_set_base>::\n    element (\n    ) \n    {\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tT& hash_set::element()\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        return hash_set_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_SET_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/hash_set.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_SEt_\n#define DLIB_HASH_SEt_\n\n#include \"hash_set/hash_set_kernel_1.h\"\n#include \"hash_set/hash_set_kernel_c.h\"\n\n#include \"hash_table.h\"\n#include \"algs.h\"\n\n\n#include \"algs.h\"\n#include <functional>\n\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        unsigned long expnum,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<T>\n        >\n    class hash_set\n    {\n        hash_set() {}\n\n        typedef typename hash_table<T,char,mem_manager,compare>::kernel_1a ht1a;\n        typedef typename hash_table<T,char,mem_manager,compare>::kernel_1a ht2a;\n        typedef typename hash_table<T,char,mem_manager,compare>::kernel_1a ht2b;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     hash_set_kernel_1<T,expnum,ht1a,mem_manager>\n                    kernel_1a;\n        typedef     hash_set_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n        // kernel_1b        \n        typedef     hash_set_kernel_1<T,expnum,ht2a,mem_manager>\n                    kernel_1b;\n        typedef     hash_set_kernel_c<kernel_1b>\n                    kernel_1b_c;\n\n        // kernel_1c\n        typedef     hash_set_kernel_1<T,expnum,ht2b,mem_manager>\n                    kernel_1c;\n        typedef     hash_set_kernel_c<kernel_1c>\n                    kernel_1c_c;\n\n\n\n\n    };\n}\n\n#endif // DLIB_HASH_SEt_\n\n"
  },
  {
    "path": "dlib/hash_table/hash_table_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_TABLE_KERNEl_1_\n#define DLIB_HASH_TABLE_KERNEl_1_\n\n#include \"hash_table_kernel_abstract.h\"\n#include \"../general_hash/general_hash.h\"\n#include \"../algs.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../assert.h\"\n#include \"../serialize.h\"\n#include <functional>\n\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class hash_table_kernel_1 : public enumerable<map_pair<domain, range> >,\n                                public pair_remover<domain,range>\n    {\n\n        /*!\n            INITIAL VALUE\n                hash_size == 0\n                table == pointer to an array of num_of_buckets node pointers\n                num_of_buckets == the number of buckets in the hash table\n                current_element == 0\n                at_start_ == true\n                mask == num_of_buckets-1\n\n            CONVENTION\n                current_element_valid() == (current_element != 0)\n                element() == current_element->d and current_element->r\n                at_start_ == at_start()\n                if (current_element != 0) then\n                    table[current_bucket] == a pointer to the linked list that contains\n                                             the node pointed to by current_element\n\n                mask == num_of_buckets-1\n\n\n\n                hash_size = size() == the number of elements in the hash_table and\n                table == pointer to an array of num_of_buckets node pointers and\n                num_of_buckets == the number of buckets in the hash table and\n                for all i:\n                    table[i] == pointer to the first node in a linked list or\n                    table[i] == 0 if this bucket is currently not in use\n                        \n\n                for all nodes:\n                    d == the domain element stored in this node\n                    r == the range element stored in this node which is associated with\n                         d.\n                    next == pointer to the next node in the linked list or\n                    next == 0 if this is the last node in the linked list\n\n        !*/\n\n        struct node\n        {\n            node* next;\n            domain d;\n            range r;\n        };\n\n\n        class mpair : public map_pair<domain,range>\n        {\n        public:\n            const domain* d;\n            range* r;\n\n            const domain& key( \n            ) const { return *d; }\n\n            const range& value(\n            ) const { return *r; }\n\n            range& value(\n            ) { return *r; }\n        };\n\n\n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            explicit hash_table_kernel_1(\n                unsigned long expnum\n            );\n\n            virtual ~hash_table_kernel_1(\n            ); \n\n            void clear(\n            );\n\n            unsigned long count (\n                const domain& item\n            ) const;\n\n            void add (\n                domain& d,\n                range& r\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            const range* operator[] (\n                const domain& d\n            ) const;\n\n            range* operator[] (\n                const domain& d\n            );\n\n            void swap (\n                hash_table_kernel_1& item\n            );\n\n            // functions from the remover interface\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            const map_pair<domain,range>& element (\n            ) const;\n\n            map_pair<domain,range>& element (\n            );\n\n            bool move_next (\n            ) const;\n\n        private:\n\n            // data members\n            typename mem_manager::template rebind<node>::other pool;         \n            typename mem_manager::template rebind<node*>::other ppool;         \n            unsigned long hash_size;\n            node** table;\n            general_hash<domain> hash;\n            unsigned long num_of_buckets;\n            unsigned long mask;\n            \n            mutable mpair p;\n\n            mutable unsigned long current_bucket;\n            mutable node* current_element;\n            mutable bool at_start_;\n            compare comp;\n\n            // restricted functions\n            hash_table_kernel_1(hash_table_kernel_1&);      \n            hash_table_kernel_1& operator=(hash_table_kernel_1&);\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        hash_table_kernel_1<domain,range,mem_manager,compare>& a, \n        hash_table_kernel_1<domain,range,mem_manager,compare>& b \n    ) { a.swap(b); }\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        hash_table_kernel_1<domain,range,mem_manager,compare>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hash_table_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    hash_table_kernel_1<domain,range,mem_manager,compare>::\n    hash_table_kernel_1(\n        unsigned long expnum\n    ) :\n        hash_size(0),\n        current_element(0),\n        at_start_(true)\n    {\n\n        num_of_buckets = 1;\n        while (expnum != 0)\n        {\n            --expnum;\n            num_of_buckets <<= 1;            \n        }\n        mask = num_of_buckets-1;\n\n        table = ppool.allocate_array(num_of_buckets);\n        for (unsigned long i = 0; i < num_of_buckets; ++i)\n        {\n            table[i] = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    hash_table_kernel_1<domain,range,mem_manager,compare>::\n    ~hash_table_kernel_1(\n    )\n    {\n        for (unsigned long i = 0; i < num_of_buckets; ++i)\n        {\n            // delete this linked list\n            node* temp = table[i];\n            while (temp)\n            {\n                node* t = temp;\n                temp = temp->next;\n                pool.deallocate(t);                    \n            }\n            table[i] = 0;\n        }\n        ppool.deallocate_array(table);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    clear(\n    )\n    {\n        if (hash_size > 0)\n        {\n            for (unsigned long i = 0; i < num_of_buckets; ++i)\n            {\n                // delete this linked list\n                node* temp = table[i];\n                while (temp)\n                {\n                    node* t = temp;\n                    temp = temp->next;\n                    pool.deallocate(t);                    \n                }\n                table[i] = 0;\n            }            \n            hash_size = 0;\n        }\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    size_t hash_table_kernel_1<domain,range,mem_manager,compare>::\n    size(\n    ) const\n    {\n        return hash_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n \n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    unsigned long hash_table_kernel_1<domain,range,mem_manager,compare>::\n    count(\n        const domain& d\n    ) const\n    {\n        unsigned long items_found = 0;\n        node* temp = table[hash(d)&mask];\n\n        while (temp != 0)\n        {\n            // look for an element equivalent to d\n            if ( !(comp(temp->d , d) || comp(d , temp->d)) )\n            {\n                ++items_found;                \n            }\n            temp = temp->next;\n        }      \n\n        return items_found;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    add(\n        domain& d,\n        range& r\n    )\n    {\n        unsigned long hash_value = hash(d)&mask;\n        \n        // make a new node for this item\n        node& temp = *(pool.allocate());\n        exchange(d,temp.d);\n        exchange(r,temp.r);\n        \n        // add this new node to the head of the linked list in bucket number hash_value\n        temp.next = table[hash_value];\n        table[hash_value] = &temp;\n        \n        ++hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    destroy(\n        const domain& d\n    )\n    {\n        node* last;\n        const unsigned long hash_value = hash(d)&mask;\n        node* temp = table[hash_value];\n        \n        // if there is more than one thing in this bucket\n        if (temp->next != 0)\n        {\n            // start looking with the second item in the list\n            last = temp;\n            temp = temp->next;\n            while (true)\n            {\n                // if we hit the end of the list without finding item then it must\n                // be the first element in the list so splice it out\n                if (temp == 0)\n                {\n                    temp = table[hash_value];\n                    table[hash_value] = temp->next;\n\n                    break;\n                }\n\n                // look for an element equivalent to item\n                if ( !(comp(temp->d , d) || comp(d , temp->d)) )\n                {\n                    // splice out the node we want to remove\n                    last->next = temp->next;\n                    break;\n                }\n    \n                last = temp;\n                temp = temp->next;\n            }\n\n        }\n        // else there is only one node in this linked list\n        else\n        {\n            table[hash_value] = 0;\n        }\n\n        pool.deallocate(temp);\n\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    remove(\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        node* last;\n        const unsigned long hash_value = hash(d)&mask;\n        node* temp = table[hash_value];\n        \n        // if there is more than one thing in this bucket\n        if (temp->next != 0)\n        {\n            // start looking with the second item in the list\n            last = temp;\n            temp = temp->next;\n            while (true)\n            {\n                // if we hit the end of the list without finding item then it must\n                // be the first element in the list so splice it out\n                if (temp == 0)\n                {\n                    temp = table[hash_value];\n                    table[hash_value] = temp->next;\n\n                    break;\n                }\n\n                // look for an element equivalent to item\n                if ( !(comp(temp->d , d) || comp(d , temp->d)) )\n                {\n                    // splice out the node we want to remove\n                    last->next = temp->next;\n                    break;\n                }\n    \n                last = temp;\n                temp = temp->next;\n            }\n\n        }\n        // else there is only one node in this linked list\n        else\n        {\n            table[hash_value] = 0;\n        }\n\n        \n        exchange(d_copy,temp->d);\n        exchange(r,temp->r);\n        pool.deallocate(temp);\n\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    remove_any(\n        domain& d,\n        range& r\n    )\n    {\n        unsigned long i = 0;\n\n        // while the ith bucket is empty keep looking\n        while (table[i] == 0)\n        {\n            ++i;\n        }\n\n        // remove the first node in the linked list in the ith bucket\n        node& temp = *(table[i]);\n\n        exchange(temp.d,d);\n        exchange(temp.r,r);\n        table[i] = temp.next;\n        \n        pool.deallocate(&temp);        \n\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    const range* hash_table_kernel_1<domain,range,mem_manager,compare>::\n    operator[](\n        const domain& d\n    ) const\n    {        \n        node* temp = table[hash(d)&mask];\n\n        while (temp != 0)\n        {\n            // look for an element equivalent to item\n            if ( !(comp(temp->d , d) || comp(d , temp->d)) )\n                return &(temp->r);             \n\n            temp = temp->next;\n        }      \n\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    range* hash_table_kernel_1<domain,range,mem_manager,compare>::\n    operator[](\n        const domain& d\n    )\n    {\n        node* temp = table[hash(d)&mask];\n\n        while (temp != 0)\n        {\n            // look for an element equivalent to item\n            if ( !(comp(temp->d , d) || comp(d , temp->d)) )\n                return &(temp->r);             \n\n            temp = temp->next;\n        }      \n\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    swap(\n        hash_table_kernel_1<domain,range,mem_manager,compare>& item\n    )\n    {\n        exchange(mask,item.mask);\n        exchange(table,item.table);\n        exchange(hash_size,item.hash_size);\n        exchange(num_of_buckets,item.num_of_buckets);\n        exchange(current_bucket,item.current_bucket);\n        exchange(current_element,item.current_element);\n        exchange(at_start_,item.at_start_);\n        pool.swap(item.pool);\n        ppool.swap(item.ppool);\n        exchange(p,item.p);\n        exchange(comp,item.comp);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_1<domain,range,mem_manager,compare>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_1<domain,range,mem_manager,compare>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_1<domain,range,mem_manager,compare>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    const map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>::\n    element (\n    ) const\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    map_pair<domain,range>& hash_table_kernel_1<domain,range,mem_manager,compare>::\n    element (\n    )\n    {\n        p.d = &(current_element->d);\n        p.r = &(current_element->r);\n        return p;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_1<domain,range,mem_manager,compare>::\n    move_next (\n    ) const\n    {\n        if (at_start_)\n        {\n            at_start_ = false;\n            // if the queue is empty then there is nothing to do\n            if (hash_size == 0)\n            {\n                return false;\n            }\n            else\n            {\n                // find the first element in the hash table\n                for (current_bucket = 0; true ; ++current_bucket)\n                {\n                    if (table[current_bucket] != 0)\n                    {\n                        current_element = table[current_bucket];\n                        break;\n                    }\n                }\n                return true;\n            }\n        }\n        else\n        {\n            // if we have already enumerated every element\n            if (current_element == 0)\n            {\n                return false;\n            }\n            else\n            {\n                // find the next element if it exists\n                if (current_element->next != 0)\n                {\n                    current_element = current_element->next;\n                    return true;\n                }\n                else\n                {\n                    // find next bucket with something in it\n                    for (current_bucket+=1; current_bucket<num_of_buckets; ++current_bucket)\n                    {\n                        if (table[current_bucket] != 0)\n                        {\n                            // we just found the next bucket\n                            current_element = table[current_bucket];\n                            break;\n                        }\n                    }\n                    // make sure we actually found another nonempty bucket\n                    if (current_bucket == num_of_buckets)\n                    {\n                        // we didn't find anything\n                        current_element = 0;\n                        return false;\n                    }\n                    else\n                    {\n                        // we found another bucket\n                        return true;\n                    }\n                }\n            }\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_TABLE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/hash_table/hash_table_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_TABLE_KERNEl_2_\n#define DLIB_HASH_TABLE_KERNEl_2_\n\n#include \"hash_table_kernel_abstract.h\"\n#include \"../general_hash/general_hash.h\"\n#include \"../algs.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../assert.h\"\n#include \"../serialize.h\"\n#include <functional>\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class hash_table_kernel_2 : public enumerable<map_pair<domain,range> >,\n                                public pair_remover<domain,range>\n    {\n\n        /*!\n            REQUIREMENTS ON bst_base\n                bst_base is instantiated with domain and range and\n                implements binray_search_tree/binary_search_tree_kernel_abstract.h\n\n             INITIAL VALUE\n                hash_size == 0\n                table == pointer to an array of num_of_buckets bst_base objects\n                num_of_buckets == the number of buckets in the hash table\n                current_bucket == 0\n                at_start_ == true\n\n            CONVENTION\n                current_element_valid() == (current_bucket != 0)\n                element() == current_bucket->element()\n                at_start_ == at_start()\n\n                mask == num_of_buckets-1\n\n                for all integers i where &table[i] != current_bucket\n                    table[i].at_start() == true\n\n\n                hash_size = size() == the number of elements in the hash_table and\n                table == pointer to an array of num_of_buckets bst_base objects\n                num_of_buckets == the number of buckets in the hash table and\n                the elements in this hash table are stored in the bst_base objects in the\n                array table\n\n        !*/\n        \n\n \n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            explicit hash_table_kernel_2(\n                unsigned long expnum\n            );\n\n            virtual ~hash_table_kernel_2(\n            )\n            { pool.deallocate_array(table); }\n\n            void clear(\n            );\n\n            unsigned long count (\n                const domain& item\n            ) const;\n\n            inline void add (\n                domain& d,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            const range* operator[] (\n                const domain& item\n            ) const;\n\n            range* operator[] (\n                const domain& item\n            );\n\n            inline void swap (\n                hash_table_kernel_2& item\n            );\n\n            // functions from the remover interface\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            inline const map_pair<domain,range>& element (\n            ) const;\n\n            inline map_pair<domain,range>& element (\n            );\n\n            bool move_next (\n            ) const;\n\n        private:\n\n            // data members   \n            typename mem_manager::template rebind<bst_base>::other pool;         \n            unsigned long mask;\n            unsigned long hash_size;\n            unsigned long num_of_buckets;\n            bst_base* table;\n            general_hash<domain> hash;\n            mutable bst_base* current_bucket;\n            mutable bool at_start_;\n            compare comp;\n\n            // restricted functions\n            hash_table_kernel_2(hash_table_kernel_2&);      \n            hash_table_kernel_2& operator=(hash_table_kernel_2&);\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& a, \n        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& b \n    ) { a.swap(b); }\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hash_table_kernel_2\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    hash_table_kernel_2(\n        unsigned long expnum\n    ) :\n        hash_size(0),\n        current_bucket(0),\n        at_start_(true)\n    {\n\n        num_of_buckets = 1;\n        while (expnum != 0)\n        {\n            --expnum;\n            num_of_buckets <<= 1;            \n        }\n        mask = num_of_buckets-1;\n\n        table = pool.allocate_array(num_of_buckets);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    clear(\n    )\n    {\n        if (hash_size != 0)\n        {\n            hash_size = 0;\n            for (unsigned long i = 0; i < num_of_buckets; ++i)\n                table[i].clear();\n        }\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    size_t hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    size(\n    ) const\n    {\n        return hash_size;\n    }\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    unsigned long hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    count(\n        const domain& item\n    ) const\n    {\n        return table[hash(item)&mask].count(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    destroy(\n        const domain& item\n    ) \n    {\n        table[hash(item)&mask].destroy(item);\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    add(\n        domain& d,\n        range& r\n    )\n    {\n        table[hash(d)&mask].add(d,r);\n        ++hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    remove(\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        table[hash(d)&mask].remove(d,d_copy,r);\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    remove_any(\n        domain& d,\n        range& r\n    )\n    {\n        unsigned long i = 0;\n        while (table[i].size() == 0)\n        {\n            ++i;\n        }\n        table[i].remove_any(d,r);\n        --hash_size;\n\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    const range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    operator[](\n        const domain& d\n    ) const\n    {\n        return table[hash(d)&mask][d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    range* hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    operator[](\n        const domain& d\n    )\n    {\n        return table[hash(d)&mask][d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    swap(\n        hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>& item\n    )\n    {\n        pool.swap(item.pool);\n        exchange(mask,item.mask);\n        exchange(hash_size,item.hash_size);\n        exchange(num_of_buckets,item.num_of_buckets);\n        exchange(table,item.table);\n        exchange(current_bucket,item.current_bucket);\n        exchange(at_start_,item.at_start_);        \n        exchange(comp,item.comp);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    void hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        if (current_bucket != 0)\n        {\n            current_bucket->reset();\n            current_bucket = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    current_element_valid (\n    ) const\n    {\n        return (current_bucket != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    const map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    element (\n    ) const\n    {\n        return current_bucket->element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    map_pair<domain,range>& hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    element (\n    )\n    {\n        return current_bucket->element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager,\n        typename compare\n        >\n    bool hash_table_kernel_2<domain,range,bst_base,mem_manager,compare>::\n    move_next (\n    ) const\n    {\n        if (at_start_)\n        {\n            at_start_ = false;\n            // if the queue is empty then there is nothing to do\n            if (hash_size == 0)\n            {\n                return false;\n            }\n            else\n            {\n                // find the first element in the hash table\n                current_bucket = table;\n                while (current_bucket->size() == 0)\n                {\n                    ++current_bucket;\n                }\n\n                current_bucket->move_next();\n                \n                return true;\n            }\n        }\n        else\n        {\n            // if we have already enumerated every element\n            if (current_bucket == 0)\n            {\n                return false;\n            }\n            else\n            {\n                if (current_bucket->move_next())\n                {\n                    // if there is another element in this current bucket then use that\n                    return true;\n                }\n                else\n                {\n                    // find the next bucket\n                    bst_base* end = table + num_of_buckets;\n                    current_bucket->reset();\n                    \n                    while (true)\n                    {   \n                        ++current_bucket;\n                        // if we ran out of buckets and didn't find anything\n                        if (current_bucket == end)\n                        {\n                            current_bucket = 0;\n                            return false;\n                        }\n                        if (current_bucket->size() > 0)\n                        {\n                            current_bucket->move_next();\n                            return true;\n                        }\n                    }\n                }\n            }\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_TABLE_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/hash_table/hash_table_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HASH_TABLE_KERNEl_ABSTRACT_\n#ifdef DLIB_HASH_TABLE_KERNEl_ABSTRACT_\n\n#include \"../interfaces/map_pair.h\"\n#include \"../general_hash/general_hash.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include <functional>\n\nnamespace dlib \n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class hash_table : public enumerable<map_pair<domain,range> >,\n                       public pair_remover<domain,range>\n    {\n\n        /*!\n            REQUIREMENTS ON domain\n                domain must be comparable by compare where compare is a functor compatible with std::less and\n                domain must be hashable by general_hash \n                (general_hash is defined in dlib/general_hash) and \n                domain must be swappable by a global swap() and\n                domain must have a default constructor\n\n            REQUIREMENTS ON range\n                range must be swappable by a global swap() and\n                range must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap(), count(), and operator[] functions do \n                not invalidate pointers or references to internal data.\n                All other functions have no such guarantee.\n\n            INITIAL VALUE\n                size() == 0\n\n            ENUMERATION ORDER\n                No order is specified.  Only that each element will be visited once\n                and only once.\n                \n            WHAT THIS OBJECT REPRESENTS\n                hash_table contains items of type T\n\n                This object represents a data dictionary that is built on top of some \n                kind of hash table.  The number of buckets in the hash table is \n                defined by the constructor argument and is some power of 2.\n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n                    \n                NOTE:\n                    definition of equivalent:\n                    a is equivalent to b if\n                    a < b == false and\n                    b < a == false\n        !*/\n\n\n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            explicit hash_table(\n                unsigned long expnum\n            );\n            /*!\n                requires\n                    - expnum < 32\n                ensures \n                    - #*this is properly initialized\n                    - #*this will use 2^expnum as a suggestion for the initial number\n                      of buckets.\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n            !*/\n\n            virtual ~hash_table(\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            unsigned long count (\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - returns the number of elements in the domain of *this that are \n                      equivalent to d\n            !*/ \n\n            void add (\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - &d != &r (i.e. d and r cannot be the same variable)\n                ensures \n                    - adds a mapping between d and r to *this\n                    - if (count(d) == 0) then\n                        - #*(*this)[d] == r\n                    - else\n                        - #(*this)[d] != 0\n                    - #d and #r have initial values for their types\n                    - #count(d) == count(d) + 1\n                    - #at_start() == true\n                    - #size() == size() + 1\n                throws \n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if add() throws then it has no effect\n            !*/\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n            /*!\n                requires\n                    - (*this)[d] != 0 \n                    - &d != &r (i.e. d and r cannot be the same variable) \n                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable) \n                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable) \n                ensures\n                    - some element in the domain of *this that is equivalent to d has\n                      been removed and swapped into #d_copy.  Additionally, its \n                      associated range element has been removed and swapped into #r.\n                    - #count(d) = count(d) - 1\n                    - #size() == size() - 1\n                    - #at_start() == true  \n            !*/\n\n            void destroy (\n                const domain& d\n            );\n            /*!\n                requires\n                    - (*this)[d] != 0 \n                ensures\n                    - an element in the domain of *this equivalent to d has been removed.  \n                      The element in the range of *this associated with d has also been \n                      removed.\n                    - #count(d) == count(d) - 1\n                    - #size() == size() - 1\n                    - #at_start() == true  \n            !*/\n\n            const range* operator[] (\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - if (there is an element in the domain equivalent to d) then\n                        - returns a pointer to an element in the range of *this that\n                          is associated with an element in the domain of *this \n                          equivalent to d.\n                    - else\n                        - returns 0\n            !*/\n\n            range* operator[] (\n                const domain& d\n            );\n            /*!\n                ensures\n                    - if (there is an element in the domain equivalent to d) then\n                        - returns a pointer to an element in the range of *this that\n                          is associated with an element in the domain of *this \n                          equivalent to d.\n                    - else\n                        - returns 0\n            !*/\n\n            void swap (\n                hash_table& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n        private:\n\n            // restricted functions\n            hash_table(hash_table&);      \n            hash_table& operator=(hash_table&);\n\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager\n        >\n    inline void swap (\n        hash_table<domain,range,mem_manager>& a, \n        hash_table<domain,range,mem_manager>& b \n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager\n        >\n    void deserialize (\n        hash_table<domain,range,mem_manager>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_HASH_TABLE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/hash_table/hash_table_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_TABLE_KERNEl_C_\n#define DLIB_HASH_TABLE_KERNEl_C_\n\n#include \"hash_table_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../assert.h\"\n\nnamespace dlib \n{\n\n    template <\n        typename ht_base        \n        >\n    class hash_table_kernel_c : public ht_base\n    {\n        typedef typename ht_base::domain_type domain;\n        typedef typename ht_base::range_type range;\n        public:\n\n            explicit hash_table_kernel_c (\n                unsigned long expnum\n            ) :\n                ht_base(expnum)\n            {\n                DLIB_CASSERT(expnum < 32,\n                    \"\\thash_table::hash_table(unsigned long)\"\n                    << \"\\n\\tyou can't set expnum >= 32\"\n                    << \"\\n\\tthis:       \" << this\n                    << \"\\n\\texpnum:     \" << expnum\n                    );                   \n            }\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            void add (\n                domain& d,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            const map_pair<domain,range>& element (\n            ) const\n            {\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tconst map_pair<domain,range>& hash_table::element() const\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                    );\n\n                return ht_base::element();\n            }\n\n            map_pair<domain,range>& element (\n            )\n            {\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tmap_pair<domain,range>& hash_table::element()\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                    );\n\n                return ht_base::element();\n            }\n\n\n    };\n\n\n    template <\n        typename ht_base        \n        >\n    inline void swap (\n        hash_table_kernel_c<ht_base>& a, \n        hash_table_kernel_c<ht_base>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename ht_base        \n        >\n    void hash_table_kernel_c<ht_base>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        DLIB_CASSERT(this->operator[](d) != 0 &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&\n                (static_cast<const void*>(&r) != static_cast<void*>(&d_copy)),\n            \"\\tvoid binary_search_tree::remove\"\n            << \"\\n\\tthe element must be in the table for it to be removed\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&d:         \" << &d \n            << \"\\n\\t&d_copy:    \" << &d_copy\n            << \"\\n\\t&r:         \" << &r\n            );\n\n        ht_base::remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename ht_base        \n        >\n    void hash_table_kernel_c<ht_base>::\n    add(\n        domain& d,\n        range& r\n    )\n    {\n        DLIB_CASSERT( static_cast<const void*>(&d) != static_cast<void*>(&r),\n            \"\\tvoid binary_search_tree::add\"\n            << \"\\n\\tyou can't call add() and give the same object to both arguments.\"\n            << \"\\n\\tthis:       \" << this\n            << \"\\n\\t&d:         \" << &d\n            << \"\\n\\t&r:         \" << &r\n            << \"\\n\\tsize():     \" << this->size()\n            );\n\n        ht_base::add(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename ht_base        \n        >\n    void hash_table_kernel_c<ht_base>::\n    destroy(\n        const domain& d\n    )\n    {\n        DLIB_CASSERT((*this)[d] != 0,\n            \"\\tvoid hash_table::destroy\"\n            << \"\\n\\tthe element must be in the table for it to be destroyed\"\n            << \"\\n\\tthis:  \" << this\n            << \"\\n\\t&d:    \" << &d \n            );\n\n        ht_base::destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename ht_base        \n        >\n    void hash_table_kernel_c<ht_base>::\n    remove_any(\n        domain& d,\n        range& r\n    )\n    {\n        DLIB_CASSERT(this->size() != 0 && \n            (static_cast<const void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid hash_table::remove_any\"\n            << \"\\n\\ttable must not be empty if something is going to be removed\"\n            << \"\\n\\tthis: \" << this\n            << \"\\n\\t&d:   \" << &d\n            << \"\\n\\t&r:   \" << &r\n            );\n\n        ht_base::remove_any(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASH_TABLE_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/hash_table.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASH_TABLe_\n#define DLIB_HASH_TABLe_\n\n\n#include \"hash_table/hash_table_kernel_1.h\"\n#include \"hash_table/hash_table_kernel_2.h\"\n#include \"hash_table/hash_table_kernel_c.h\"\n#include \"algs.h\"\n\n#include \"binary_search_tree.h\"\n#include <functional>\n\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class hash_table\n    {\n        hash_table() {}\n\n        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_1a\n                    bst_1;\n        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_2a\n                    bst_2;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     hash_table_kernel_1<domain,range,mem_manager,compare>    \n                    kernel_1a;\n        typedef     hash_table_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n\n        // kernel_2a        \n        typedef     hash_table_kernel_2<domain,range,bst_1,mem_manager,compare>    \n                    kernel_2a;\n        typedef     hash_table_kernel_c<kernel_2a>\n                    kernel_2a_c;\n\n        // kernel_2b\n        typedef     hash_table_kernel_2<domain,range,bst_2,mem_manager,compare>    \n                    kernel_2b;\n        typedef     hash_table_kernel_c<kernel_2b>\n                    kernel_2b_c;\n    };\n}\n\n#endif // DLIB_HASH_TABLe_\n\n"
  },
  {
    "path": "dlib/http_client/http_client.cpp",
    "content": "\n\n#include \"../sockets.h\"\n#include \"../string.h\"\n#include \"../logger.h\"\n#include \"../sockstreambuf.h\"\n#include \"../timeout.h\"\n#include \"http_client.h\"\n#include <time.h>\n#include <stdio.h>\n#include <fstream>\n#include <sstream>\n#include <iostream>\n\nnamespace dlib\n{\n\n    typedef std::shared_ptr<dlib::timeout> timeout_ptr;\n\n\n#ifdef _MSC_VER\n#define BR_CASECMP strnicmp\n#else\n#define BR_CASECMP strncasecmp\n#endif\n// Default timeout after 60 seconds\n#define DEFAULT_TIMEOUT 60000\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool isXdigit( char c )\n    {\n        return  (c >= '0' && c <= '9') ||\n                (c >= 'A' && c <= 'Z') ||\n                (c >= 'a' && c <= 'z');\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::urldecode( const std::string& s )\n    {\n        std::stringstream ss;\n\n        for ( char const * p_read = s.c_str(), * p_end = (s.c_str() + s.size()); p_read < p_end; p_read++ )\n        {\n            if ( p_read[0] == '%' && p_read+1 != p_end && p_read+2 != p_end && isXdigit(p_read[1]) && isXdigit(p_read[2]) )\n            {\n                ss << static_cast<char>((( (p_read[1] & 0xf) + ((p_read[1] >= 'A') ? 9 : 0) ) << 4 ) | ( (p_read[2] & 0xf) + ((p_read[2] >= 'A') ? 9 : 0) ));\n                p_read += 2;\n            }\n            else if ( p_read[0] == '+' )\n            {\n                // Undo the encoding that replaces spaces with plus signs.\n                ss << ' ';\n            }\n            else\n            {\n                ss << p_read[0];\n            }\n        }\n\n        return ss.str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n//! \\return modified string ``s'' with spaces trimmed from left\n    inline std::string& triml(std::string& s)\n    {\n        std::string::size_type pos(0);\n        for ( ; s[pos] == ' ' || s[pos] == '\\t' || s[pos] == '\\r' || s[pos] == '\\n' ; ++pos );\n        s.erase(0, pos);\n        return s;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n//! \\return modified string ``s'' with spaces trimmed from right\n    inline std::string& trimr(std::string& s)\n    {\n        std::string::size_type pos(s.size());\n        for ( ; pos && (s[pos-1] == ' ' || s[pos-1] == '\\t' || s[pos-1] == '\\r' || s[pos-1] == '\\n') ; --pos );\n        s.erase(pos, s.size()-pos);\n        return s;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n//! \\return modified string ``s'' with spaces trimmed from edges\n    inline std::string& trim(std::string& s)\n    {\n        return triml(trimr(s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    http_client::\n    http_client(\n    ) : \n        http_return(0),\n        timeout(DEFAULT_TIMEOUT),\n        OnDownload(0)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::get_header(const std::string& header_name) const\n    {\n        stringmap::const_iterator ci = headers.find(header_name);\n        return ci != headers.end() ? ci->second : std::string();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::set_header(const std::string& header_name, long header_value)\n    {\n        char buf[21] = { 0 };\n#ifdef __WXMSW__\n        ::ltoa(header_value, buf, 10);\n#else\n        snprintf(buf, sizeof(buf), \"%ld\", header_value);\n#endif\n        set_header(header_name, buf);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::set_header(const std::string& header_name, const std::string& header_value)\n    {\n        headers[header_name] = header_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool http_client::is_header_set(const std::string& header_name) const\n    {\n        stringmap::const_iterator ci = headers.find(header_name);\n        return ci != headers.end() && !ci->second.empty();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::remove_header(const std::string& header_name)\n    {\n        headers.erase(header_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::set_cookie(const std::string& cookie_name, long cookie_value)\n    {\n        char buf[21] = { 0 };\n#ifdef __WXMSW__\n        ::ltoa(cookie_value, buf, 10);\n#else\n        snprintf(buf, sizeof(buf), \"%ld\", cookie_value);\n#endif\n        set_cookie(cookie_name, buf);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::set_cookie(const std::string& cookie_name, const std::string& cookie_value)\n    {\n        cookies[cookie_name] = cookie_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::remove_cookie(const std::string& cookie_name)\n    {\n        cookies.erase(cookie_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// POST\n    const std::string& http_client::post_url (const std::string& url, const string_to_stringmap& postvars, const string_to_stringmap& filenames)\n    {\n        std::string CT;\n        std::string postBody = build_post(CT, postvars, filenames);\n        set_header(\"Content-Type\", CT);\n        set_header(\"Content-Length\", static_cast<long>(postBody.size()));\n\n        grab_url(url, \"POST\", postBody);\n\n        return returned_body;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string& http_client::post_url (const std::string& url, const std::string& postbuffer)\n    {\n        if ( !is_header_set(\"Content-Type\") ) // Maybe they just forgot it?\n            set_header(\"Content-Type\", \"application/x-www-form-urlencoded\");\n\n        set_header(\"Content-Length\", static_cast<long>(postbuffer.size()));\n\n        grab_url(url, \"POST\", postbuffer);\n\n        return returned_body;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::get_random_string( size_t length ) const\n    {\n        static bool has_seeded(false);\n        static std::string allowed_chars(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\");\n\n        if ( !has_seeded )\n        {\n            has_seeded = true;\n            ::srand( static_cast<unsigned int>(::time(NULL)) );\n        }\n\n        std::string retVal; retVal.reserve(length);\n        while ( retVal.size() < length )\n        {\n            retVal += allowed_chars[(rand() % allowed_chars.size())];\n        }\n\n        return retVal;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// static\n    std::string http_client::urlencode(const std::string& in, bool post_encode)\n    {\n        static std::string allowed_chars(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_\");\n\n        std::stringstream ss;\n        ss << std::hex;\n        for (std::string::const_iterator ci = in.begin(); ci != in.end(); ++ci)\n        {\n            if ( allowed_chars.find(*ci) != std::string::npos )\n            {\n                ss << *ci;\n            }\n            else if ( post_encode && *ci == ' ' )\n            {\n                ss << '+';\n            }\n            else\n            {\n                ss << '%' << std::setfill('0') << std::setw(2) << std::right << static_cast<int>(*ci);\n            }\n        }\n\n        return ss.str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::get_basename( const std::string& filename ) const\n    {\n        std::string::size_type pos = filename.find_last_of(\"\\\\/\");\n        if ( pos == std::string::npos )\n            return filename;\n        else\n            return filename.substr(pos+1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool http_client::parse_url(\n        const std::string& url,\n        std::string& scheme,\n        std::string& user,\n        std::string& pass,\n        std::string& host,\n        short& port,\n        std::string& path\n    ) const\n    {\n        scheme.clear();\n        user.clear();\n        pass.clear();\n        host.clear();\n        path.clear();\n        port = 0;\n\n        // Find scheme\n        std::string::size_type pos_scheme = url.find(\"://\");\n        if ( pos_scheme == std::string::npos )\n        {\n            pos_scheme = 0;\n        }\n        else\n        {\n            scheme = strtolower(url.substr(0, pos_scheme));\n            pos_scheme += 3;\n        }\n\n        std::string::size_type pos_path = url.find('/', pos_scheme);\n        if ( pos_path == std::string::npos )\n        {\n            host = url.substr(pos_scheme);\n        }\n        else\n        {\n            host = url.substr(pos_scheme, pos_path - pos_scheme);\n            path = url.substr(pos_path);\n        }\n\n        std::string::size_type pos_at = host.find('@');\n        if ( pos_at != std::string::npos )\n        {\n            std::string::size_type pos_dp = host.find(':');\n            if ( pos_dp != std::string::npos && pos_dp < pos_at )\n            {\n                user = host.substr(0, pos_dp);\n                pass = host.substr(pos_dp+1, pos_at-pos_dp-1);\n            }\n            else\n            {\n                user = host.substr(0, pos_at);\n            }\n            host = host.substr(pos_at+1);\n        }\n\n        std::string::size_type pos_dp = host.find(':');\n        if ( pos_dp != std::string::npos )\n        {\n            port = dlib::string_cast<short>(host.substr(pos_dp+1));\n            host = host.substr(0, pos_dp);\n        }\n\n        host = strtolower(host);\n\n        if ( port == 0 )\n        {\n            if ( scheme == \"http\" )\n                port = 80;\n            else if ( scheme == \"ftp\" )\n                port = 21;\n            else if ( scheme == \"https\" )\n                port = 443;\n        }\n\n        return !host.empty();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::strtolower(const std::string& in) const\n    {\n        std::string retVal = in;\n\n        for (std::string::iterator ii = retVal.begin(); ii != retVal.end(); ++ii)\n        {\n            *ii = ::tolower(*ii);\n        }\n\n        return retVal;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::strtoupper(const std::string& in) const\n    {\n        std::string retVal = in;\n\n        for (std::string::iterator ii = retVal.begin(); ii != retVal.end(); ++ii)\n        {\n            *ii = ::toupper(*ii);\n        }\n\n        return retVal;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// GET\n    const std::string& http_client::get_url(const std::string& url)\n    {\n        std::string CT = get_header(\"Content-Type\");\n\n        // You do a GET with a POST header??\n        if ( CT == \"application/x-www-form-urlencoded\" || CT == \"multipart/form-data\" )\n            remove_header(\"Content-Type\");\n\n        grab_url(url);\n\n        return returned_body;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string http_client::build_post(std::string& content_type, const string_to_stringmap& postvars, const string_to_stringmap& filenames_in) const\n    {\n        if ( postvars.empty() && filenames_in.empty() )\n            return std::string();\n\n        string_to_stringmap filenames = filenames_in;\n\n        // sanitize the files\n        if ( !filenames.empty() )\n        {\n            string_to_stringmap::iterator var_names = filenames.begin();\n            while (var_names != filenames.end())\n            {\n                stringmap::iterator fnames = var_names->second.begin();\n\n                while( fnames != var_names->second.end() )\n                {\n                    FILE *fp = ::fopen(fnames->second.c_str(), \"rb\");\n                    if ( fp == NULL )\n                    {\n                        stringmap::iterator old_one = fnames++;\n                        var_names->second.erase(old_one);\n                    }\n                    else\n                    {\n                        fclose(fp);\n                        ++fnames;\n                    }\n                }\n\n                if ( fnames->second.empty() )\n                {\n                    string_to_stringmap::iterator old_one = var_names++;\n                    filenames.erase(old_one);\n                }\n                else\n                {\n                    ++var_names;\n                }\n            }\n        }\n\n        content_type = !filenames.empty() ? \"multipart/form-data\" : \"application/x-www-form-urlencoded\";\n        std::stringstream postBody;\n        if ( !filenames.empty() )\n        {\n            std::string mime_boundary = get_random_string(32);\n\n            // First add the form vars\n            for (string_to_stringmap::const_iterator ci = postvars.begin(); ci != postvars.end(); ++ci)\n            {\n                for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si)\n                {\n                    postBody << \"--\" << mime_boundary << \"\\r\\n\"\n                        \"Content-Disposition: form-data; name=\\\"\" << ci->first << \"\\\"\\r\\n\\r\\n\"\n                        << si->second << \"\\r\\n\";\n                }\n            }\n\n            // Then add the files\n            for (string_to_stringmap::const_iterator ci = filenames.begin(); ci != filenames.end(); ++ci)\n            {\n                for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si)\n                {\n                    std::ifstream in(si->second.c_str());\n                    postBody << \"--\" << mime_boundary << \"\\r\\n\"\n                        \"Content-Disposition: form-data; name=\\\"\" << ci->first << \"\\\"; filename=\\\"\" << get_basename(si->second) << \"\\\"\\r\\n\\r\\n\"\n                        << in.rdbuf() << \"\\r\\n\";\n                }\n            }\n\n            postBody << \"--\" << mime_boundary << \"--\\r\\n\";\n        }\n        else\n        {\n            // No files...\n            for (string_to_stringmap::const_iterator ci = postvars.begin(); ci != postvars.end(); ++ci)\n            {\n                for (stringmap::const_iterator si = ci->second.begin(); si != ci->second.end(); ++si)\n                {\n                    postBody << urlencode(ci->first) << '=' << urlencode(si->second) << '&';\n                }\n            }\n\n            // read the last '&'\n            char c;\n            postBody.read(&c, 1);\n        }\n\n        return postBody.str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool http_client::grab_url(const std::string& url, const std::string& method, const std::string& post_body)\n    {\n        error_field.clear();\n        returned_headers.clear();\n        http_return = 0;\n        returned_body.clear();\n\n        std::string to_use_method = strtoupper(method);\n\n        std::string scheme, user, pass, host, path;\n        short port;\n        if ( !parse_url(url, scheme, user, pass, host, port, path) )\n        {\n            error_field = \"Couldn't parse the URL!\";\n            return false;\n        }\n\n        // Build request\n        std::stringstream ret;\n        ret << to_use_method << ' ' << path << \" HTTP/1.0\\r\\n\"\n            << \"Host: \" << host;\n        if (port != 80 && port != 443) ret << ':' << port;\n        ret << \"\\r\\n\";\n\n        bool content_length_said = false;\n\n        set_header(\"Connection\", \"Close\");\n        for (stringmap::iterator ci = headers.begin(); ci != headers.end(); ++ci)\n        {\n            std::string head = strtolower(ci->first);\n\n            if ( head == \"content-length\" )\n            {\n                content_length_said = true;\n            }\n\n            ret << ci->first << ':' << ' ' << ci->second << \"\\r\\n\";\n        }\n\n        if ( !content_length_said && to_use_method != \"GET\" )\n            ret << \"Content-Length: \" << static_cast<unsigned int>(post_body.size()) << \"\\r\\n\";\n\n        std::stringstream cookie_ss;\n        for (stringmap::iterator ci = cookies.begin(); ci != cookies.end(); ++ci)\n        {\n            std::string var = ci->first ; trim(var);\n            std::string val = ci->second; trim(val);\n\n            if ( val.empty() || var.empty() )\n                continue;\n\n            if ( !cookie_ss.str().empty() )\n                cookie_ss << ';' << ' ';\n\n            cookie_ss << urlencode(var) << '=' << urlencode(val);\n        }\n\n        if ( !cookie_ss.str().empty() )\n            ret << \"Cookie: \" << cookie_ss.str() << \"\\r\\n\";\n\n        ret << \"\\r\\n\";\n        ret << post_body;\n\n        std::string request_build = ret.str();\n\n        std::stringstream ss;\n        {\n            dlib::connection * conn(0);\n            try\n            {\n                if (timeout > 0)\n                    conn = dlib::connect(host, port, timeout);\n                else\n                    conn = dlib::connect(host, port);\n            }\n            catch (const dlib::socket_error& e)\n            {\n                error_field = e.what();\n                return false;\n            }\n\n            // Implement a timeout\n            timeout_ptr t;\n            if ( timeout > 0 )\n                t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) );\n\n            // Write our request\n            conn->write(request_build.c_str(), static_cast<long>(request_build.size()));\n\n            t.reset();\n\n            // And read the response\n            char buf[512];\n            long bytes_read(0), bytes_total(0);\n            bool read_headers(true);\n\n            if ( timeout > 0 )\n                t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) );\n\n            while ( (bytes_read = conn->read(buf, 512)) > 0 )\n            {\n                ss.write(buf, bytes_read);\n\n                // Incremental read headers\n                if ( read_headers )\n                {\n                    std::string body_with_headers = ss.str();\n                    std::string::size_type ctr(0);\n\n                    while ( true )\n                    {\n                        std::string::size_type pos = body_with_headers.find(\"\\r\\n\", ctr);\n                        if ( pos == std::string::npos )\n                        {\n                            // This is our last position of \"\\r\\n\"\n                            ss.str(\"\");\n                            ss.write( body_with_headers.substr(ctr).c_str(), body_with_headers.size() - ctr );\n                            break;\n                        }\n\n                        std::string header = body_with_headers.substr(ctr, pos-ctr);\n                        if ( header.empty() )\n                        {\n                            // Ok, we're done reading the headers\n                            read_headers = false;\n                            // What follows now is the body\n                            ss.str(\"\");\n                            ss.write( body_with_headers.substr(pos + 2).c_str(), body_with_headers.size() - pos - 2 );\n                            break;\n                        }\n                        ctr = pos + 2;\n\n                        if ( returned_headers.empty() )\n                        {\n                            if (\n                                header[0] == 'H' &&\n                                header[1] == 'T' &&\n                                header[2] == 'T' &&\n                                header[3] == 'P' &&\n                                header[4] == '/' &&\n                                (header[5] >= '0' && header[5] <= '9') &&\n                                header[6] == '.' &&\n                                (header[7] >= '0' && header[7] <= '9') &&\n                                header[8] == ' '\n                            )\n                            {\n                                http_return = (header[9 ] - '0') * 100 +\n                                    (header[10] - '0') * 10 +\n                                    (header[11] - '0');\n                                continue;\n                            }\n                        }\n\n                        std::string::size_type pos_dp = header.find_first_of(':');\n                        std::string header_name, header_value;\n                        if ( pos_dp == std::string::npos )\n                        {\n                            // **TODO** what should I do here??\n                            header_name = header;\n                        }\n                        else\n                        {\n                            header_name  = trim(header.substr(0, pos_dp));\n                            header_value = trim(header.substr(pos_dp+1));\n                        }\n\n                        returned_headers[ header_name ].push_back(header_value);\n\n                        if ( BR_CASECMP(header_name.c_str(), \"Content-Length\", 14) == 0 )\n                        {\n                            bytes_total = atol( header_value.c_str() );\n                        }\n                        else if ( BR_CASECMP(header_name.c_str(), \"Set-Cookie\", 10) == 0 )\n                        {\n                            std::string::size_type cur_pos(0), pos_pk, pos_is;\n                            std::string work, var, val;\n                            for ( cur_pos = 0; cur_pos < header_value.size(); cur_pos++ )\n                            {\n                                pos_pk = header_value.find(';', cur_pos);\n                                work   = trim( header_value.substr(cur_pos, pos_pk - cur_pos) );\n\n                                pos_is = work.find('=');\n                                if ( pos_is != std::string::npos )\n                                { // Hmmm? what in the else case?\n                                    var = trim( http_client::urldecode( work.substr(0, pos_is) ) );\n                                    val = trim( http_client::urldecode( work.substr(pos_is + 1) ) );\n\n                                    if ( var != \"expires\" && var != \"domain\" && var != \"path\" )\n                                        set_cookie( var, val );\n                                }\n                                cur_pos = pos_pk == std::string::npos ? pos_pk - 1 : pos_pk;\n                            }\n                        } // Set-Cookie?\n\n                    } // while (true)\n                } // read_headers?\n\n                // Call the OnDownload function if it's set\n                if ( OnDownload && !read_headers )\n                {\n                    if ( (*OnDownload)(static_cast<long>(ss.tellp()), bytes_total, user_info) == false )\n                    {\n                        t.reset();\n                        break;\n                    }\n                }\n\n                if ( bytes_total != 0 && static_cast<long>(ss.tellp()) == bytes_total )\n                {\n                    t.reset();\n                    break;\n                }\n\n                if ( timeout > 0 )\n                    t.reset( new dlib::timeout(*conn, &dlib::connection::shutdown, timeout) );\n            } // while still data to read\n\n            t.reset();\n\n            delete conn;\n\n\n            switch ( bytes_read )\n            {\n                case dlib::TIMEOUT:      error_field = \"Timeout\";     return false; break;\n                case dlib::WOULDBLOCK:   error_field = \"Would block\"; return false; break;\n                case dlib::OTHER_ERROR:  error_field = \"Other error\"; return false; break;\n                case dlib::SHUTDOWN:     error_field = \"Timeout\";     return false; break;\n                case dlib::PORTINUSE:    error_field = \"Port in use\"; return false; break;\n            }\n        }\n\n        returned_body = ss.str();\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::clear()\n    {\n        headers.clear();\n        cookies.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void http_client::prepare_for_next_url( )\n    {\n        remove_header(\"Content-Type\");\n        remove_header(\"Content-Length\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n"
  },
  {
    "path": "dlib/http_client/http_client.h",
    "content": "#ifndef DLIB_BROWSERhH\n#define DLIB_BROWSERhH\n\n\n#include <map>\n#include <string>\n#include <vector>\n#include \"http_client_abstract.h\"\n\n\n// Default timeout after 60 seconds\n#define DEFAULT_TIMEOUT 60000\n\nnamespace dlib\n{\n\n    // Function which is called when there is data available.\n    //   Return false to stop the download process...\n    typedef bool (*fnOnDownload)(long already_downloaded, long total_to_download, void * userInfo);\n\n\n    class http_client\n    {\n    public:\n        http_client();\n\n        typedef std::map< std::string, std::string > stringmap;\n        typedef std::map< std::string, stringmap   > string_to_stringmap;\n        typedef std::map< std::string, std::vector<std::string> > string_to_stringvector;\n\n        // Header functions\n        void        set_header(const std::string& header_name, const std::string& header_value);\n        void        set_header(const std::string& header_name, long header_value);\n        std::string get_header(const std::string& header_name) const;\n        void        remove_header(const std::string& header_name);\n        bool        is_header_set(const std::string& header_name) const;\n\n        // This function will clear out all cookies & headers set until now\n        void clear();\n        // This function will clear out the Content-Type header\n        void prepare_for_next_url();\n\n        void set_callback_function( fnOnDownload od, void * _user_info ) { OnDownload = od; user_info = _user_info; }\n\n        void set_cookie(const std::string& cookie_name, const std::string& cookie_value);\n        void set_cookie(const std::string& cookie_name, long cookie_value);\n        void remove_cookie(const std::string& cookie_name);\n\n        void set_user_agent(const std::string& new_agent) { set_header(\"User-Agent\", new_agent); }\n\n\n        void set_timeout( unsigned int milliseconds = DEFAULT_TIMEOUT ) { timeout = milliseconds; }\n\n\n        string_to_stringvector get_returned_headers() const { return returned_headers; }\n        short                  get_http_return     () const { return http_return; }\n        const std::string&     get_body            () const { return returned_body; }\n\n        // POST\n        const std::string& post_url (const std::string& url, const string_to_stringmap& postvars, const string_to_stringmap& filenames = string_to_stringmap());\n        const std::string& post_url (const std::string& url, const std::string& postbuffer);\n        // GET\n        const std::string& get_url  (const std::string& url);\n\n        bool has_error( ) const { return !error_field.empty(); }\n        const std::string& get_error( ) const { return error_field; }\n\n        static std::string urlencode(const std::string& in, bool post_encode = false);\n        static std::string urldecode(const std::string& in);\n    private:\n        bool grab_url(const std::string& url, const std::string& method = \"GET\", const std::string& post_body = \"\");\n        std::string build_post(std::string& content_type, const string_to_stringmap& postvars, const string_to_stringmap& filenames) const;\n\n        std::string get_random_string( size_t length = 32 ) const;\n        std::string get_basename( const std::string& filename ) const;\n        std::string strtolower(const std::string& in) const;\n        std::string strtoupper(const std::string& in) const;\n\n        bool parse_url(const std::string& url, std::string& scheme, std::string& user, std::string& pass, std::string& host, short& port, std::string& path) const;\n\n        stringmap headers;\n        stringmap cookies;\n\n        string_to_stringvector returned_headers;\n        short http_return;\n        std::string returned_body, error_field;\n\n        unsigned int timeout;\n\n        fnOnDownload OnDownload;\n        void *       user_info;\n    };\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"http_client.cpp\"\n#endif\n\n#endif // DLIB_BROWSERhH\n\n"
  },
  {
    "path": "dlib/http_client/http_client_abstract.h",
    "content": "#undef DLIB_BROWSER_ABSTRACh_\n#ifdef DLIB_BROWSER_ABSTRACh_\n\n\n\nnamespace dlib\n{\n\n    // Function which is called when there is data available.\n    //   Return false to stop the download process...\n    typedef bool (*fnOnDownload)(long already_downloaded, long total_to_download, void * userInfo);\n\n\n// ----------------------------------------------------------------------------------------\n/*\nTODO:\n- Timed cookie support\n- POSTing files: check it!\n- Don't timeout when still downloading!\n*/\n// ----------------------------------------------------------------------------------------\n\n\n    class Browser\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a possibility for the end user to download webpages (HTTP/1.0)\n                from the internet like a normal webbrowser would do.\n        !*/\n\n    public:\n\n        Browser(\n        );\n        /*!\n            Constructor\n        !*/\n\n        void set_header(\n            const std::string& header_name,\n            const std::string& header_value\n        );\n        /*!\n            Set a header to a certain value\n            Example: set_header(\"User-Agent\", \"Internet Explorer\")\n        !*/\n\n\n        void set_header(\n            const std::string& header_name,\n            long header_value\n        );\n        /*!\n            Set a header to a certain number\n            Example: set_header(\"Content-Length\", 1234)\n        !*/\n\n        std::string get_header(\n            const std::string& header_name\n        ) const;\n        /*!\n            Get the value of the header or an empty string when it's not set.\n            Example: get_header(\"Content-Length\") would return \"1234\"\n        !*/\n\n        void remove_header(\n            const std::string& header_name\n        );\n        /*!\n            Removes a certain header\n        !*/\n\n        bool is_header_set(\n            const std::string& header_name\n        ) const;\n        /*!\n            Returns when a header is set and is not empty\n        !*/\n\n        void set_user_agent(\n            const std::string& new_agent\n        ) { set_header(\"User-Agent\", new_agent); }\n        /*!\n            Convenience function for setting a user agent\n        !*/\n\n        void clear(\n        );\n        /*!\n            Clear out all cookies & headers set until now\n        !*/\n\n        void prepare_for_next_url(\n        );\n        /*!\n            Clear out any header and/or cookie which would obstruct getting a next page.\n            At this moment this is cleared:\n                - the Content-Type header\n        !*/\n\n        void set_callback_function( \n            fnOnDownload od, \n            void * _user_info \n        );\n        /*!\n            Set a callback function for one of the following events:\n            - OnDownload: this will tell you how much is downloaded and how much will need to be downloaded\n        !*/\n\n        void set_cookie(\n            const std::string& cookie_name, \n            const std::string& cookie_value\n        );\n        /*!\n            Set a cookie\n        !*/\n\n        void set_cookie(\n            const std::string& cookie_name, \n            long cookie_value\n        );\n        /*!\n            Set a cookie\n        !*/\n\n        void remove_cookie(\n            const std::string& cookie_name\n        );\n        /*!\n            Remove a cookie if it's set\n        !*/\n\n        void set_timeout( \n            unsigned int milliseconds  \n        );\n        /*!\n            Set the maximum time how long a request can take. Setting this to 0 disables\n            this behavior.\n        !*/\n\n        string_to_stringvector get_returned_headers(\n        ) const; \n        /*!\n            Returns all the headers which are returned in the download of the webpage.\n        !*/\n\n        short get_http_return (\n        ) const;\n        /*!\n            Retrieves the HTTP return code.\n        !*/\n\n        const std::string& get_body (\n        ) const; \n        /*!\n            Retrieves the HTTP body.\n        !*/\n\n        const std::string& post_url (\n            const std::string& url, \n            const string_to_stringmap& postvars,\n            const string_to_stringmap& filenames = string_to_stringmap()\n        );\n        /*!\n            POST an url to the internet.\n            You can pass the post variables as well as a list of filenames\n        !*/\n\n        const std::string& post_url (\n            const std::string& url, \n            const std::string& postbuffer\n        );\n        /*!\n            POST an url to the internet.\n            In this function you have constructed the POST string yourselves\n        !*/\n\n        const std::string& get_url (\n            const std::string& url\n        );\n        /*!\n            GET an url from the internet.\n        !*/\n\n        bool has_error( \n        ) const;\n        /*!\n            Has there happened an error?\n        !*/\n\n        const std::string& get_error( \n        ) const;\n        /*!\n            Get the error explanation\n        !*/\n\n        static std::string urlencode(\n            const std::string& in, \n            bool post_encode = false\n        );\n        /*!\n            Convenience function to URLencode a string\n        !*/\n\n        static std::string urldecode(\n            const std::string& in\n        );\n        /*!\n            Convenience function to URLdecode a string\n        !*/\n\n    };\n\n}\n\n#endif // DLIB_BROWSER_ABSTRACh_\n\n"
  },
  {
    "path": "dlib/image_io.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_IMAGe_IO_ \n#define DLIB_IMAGe_IO_\n\n#include \"image_loader/image_loader.h\"\n#include \"image_loader/png_loader.h\"\n#include \"image_loader/jpeg_loader.h\"\n#include \"image_loader/webp_loader.h\"\n#include \"image_loader/load_image.h\"\n#include \"image_saver/image_saver.h\"\n#include \"image_saver/save_png.h\"\n#include \"image_saver/save_jpeg.h\"\n#include \"image_saver/save_webp.h\"\n#include \"image_saver/save_jxl.h\"\n\n#endif // DLIB_IMAGe_IO_ \n\n"
  },
  {
    "path": "dlib/image_keypoint/binned_vector_feature_image.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_\n#define DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_\n\n#include \"../lsh/projection_hash.h\"\n#include \"binned_vector_feature_image_abstract.h\"\n#include <vector>\n#include \"../algs.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type_ = projection_hash\n        >\n    class binned_vector_feature_image : noncopyable\n    {\n\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef hash_function_type_ hash_function_type;\n\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        binned_vector_feature_image (\n        ); \n\n        void clear (\n        );\n\n        void set_hash (\n            const hash_function_type& hash_\n        );\n\n        const hash_function_type& get_hash (\n        ) const;\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n\n        void copy_configuration (\n            const binned_vector_feature_image& item\n        );\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n\n        inline size_t size (\n        ) const;\n\n        inline long nr (\n        ) const;\n\n        inline long nc (\n        ) const;\n\n        inline long get_num_dimensions (\n        ) const;\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n\n        inline const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n\n        inline const point image_to_feat_space (\n            const point& p\n        ) const;\n\n        inline const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n\n        inline const point feat_to_image_space (\n            const point& p\n        ) const;\n\n        inline const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n\n        template <typename T>\n        friend void serialize (\n            const binned_vector_feature_image<T>& item,\n            std::ostream& out\n        );\n\n        template <typename T>\n        friend void deserialize (\n            binned_vector_feature_image<T>& item,\n            std::istream& in \n        );\n\n    private:\n\n        array2d<descriptor_type> feats;\n        feature_extractor fe;\n        hash_function_type phash;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const binned_vector_feature_image<T>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.feats, out);\n        serialize(item.fe, out);\n        serialize(item.phash, out);\n    }\n\n    template <typename T>\n    void deserialize (\n        binned_vector_feature_image<T>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw dlib::serialization_error(\"Unexpected version found while deserializing dlib::binned_vector_feature_image\");\n        deserialize(item.feats, in);\n        deserialize(item.fe, in);\n        deserialize(item.phash, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                        binned_vector_feature_image member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    binned_vector_feature_image<feature_extractor,hash_function_type>::\n    binned_vector_feature_image (\n    )  \n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void binned_vector_feature_image<feature_extractor,hash_function_type>::\n    clear (\n    )\n    {\n        fe.clear();\n        phash = hash_function_type();\n        feats.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void binned_vector_feature_image<feature_extractor,hash_function_type>::\n    set_hash (\n        const hash_function_type& hash_\n    )\n    {\n        phash = hash_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const hash_function_type& binned_vector_feature_image<feature_extractor,hash_function_type>::\n    get_hash (\n    ) const\n    {\n        return phash;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void binned_vector_feature_image<feature_extractor,hash_function_type>::\n    copy_configuration (\n        const feature_extractor& item\n    )\n    {\n        fe.copy_configuration(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void binned_vector_feature_image<feature_extractor,hash_function_type>::\n    copy_configuration (\n        const binned_vector_feature_image& item\n    )\n    {\n        fe.copy_configuration(item.fe);\n        phash = item.phash;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    template <\n        typename image_type\n        >\n    void binned_vector_feature_image<feature_extractor,hash_function_type>::\n    load (\n        const image_type& img\n    )\n    {\n        fe.load(img);\n\n        if (fe.size() != 0)\n        {\n            feats.set_size(fe.nr(), fe.nc());\n            for (long r = 0; r < feats.nr(); ++r)\n            {\n                for (long c = 0; c < feats.nc(); ++c)\n                {\n                    feats[r][c].clear();\n                    feats[r][c].reserve(fe.get_num_dimensions()+1);\n                    const typename feature_extractor::descriptor_type& des = fe(r,c);\n                    const unsigned long idx = phash(des);\n                    const unsigned long offset = idx*(fe.get_num_dimensions()+1);\n\n                    for (long i = 0; i < des.size(); ++i)\n                    {\n                        feats[r][c].push_back(std::make_pair(offset + i, des(i)));\n                    }\n                    feats[r][c].push_back(std::make_pair(offset + des.size(), 1.0));\n                }\n            }\n        }\n        else\n        {\n            feats.set_size(0,0);\n        }\n\n        fe.unload();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    size_t binned_vector_feature_image<feature_extractor,hash_function_type>::\n    size (\n    ) const\n    {\n        return feats.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long binned_vector_feature_image<feature_extractor,hash_function_type>::\n    nr (\n    ) const\n    {\n        return feats.nr();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long binned_vector_feature_image<feature_extractor,hash_function_type>::\n    nc (\n    ) const\n    {\n        return feats.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long binned_vector_feature_image<feature_extractor,hash_function_type>::\n    get_num_dimensions (\n    ) const\n    {\n        return phash.num_hash_bins()*(fe.get_num_dimensions()+1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const std::vector<std::pair<unsigned int,double> >& binned_vector_feature_image<feature_extractor,hash_function_type>::\n    operator() (\n        long row,\n        long col\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 <= row && row < nr() &&\n                    0 <= col && col < nc(),\n            \"\\t descriptor_type binned_vector_feature_image::operator(row,col)\"\n            << \"\\n\\t Invalid inputs were given to this function\"\n            << \"\\n\\t row:  \" << row\n            << \"\\n\\t col:  \" << col \n            << \"\\n\\t nr(): \" << nr()\n            << \"\\n\\t nc(): \" << nc()\n            << \"\\n\\t this: \" << this\n            );\n\n        return feats[row][col];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::\n    get_block_rect (\n        long row,\n        long col\n    ) const\n    {\n        return fe.get_block_rect(row,col);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const point binned_vector_feature_image<feature_extractor,hash_function_type>::\n    image_to_feat_space (\n        const point& p\n    ) const\n    {\n        return fe.image_to_feat_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::\n    image_to_feat_space (\n        const rectangle& rect\n    ) const\n    {\n        return fe.image_to_feat_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const point binned_vector_feature_image<feature_extractor,hash_function_type>::\n    feat_to_image_space (\n        const point& p\n    ) const\n    {\n        return fe.feat_to_image_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle binned_vector_feature_image<feature_extractor,hash_function_type>::\n    feat_to_image_space (\n        const rectangle& rect\n    ) const \n    {\n        return fe.feat_to_image_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BINNED_VECTOR_IMAGE_FEATUrES_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/binned_vector_feature_image_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_\n#ifdef DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_\n\n#include \"../lsh/projection_hash_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type_ = projection_hash\n        >\n    class binned_vector_feature_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor \n                - must be an object with an interface compatible with dlib::hog_image\n\n            REQUIREMENTS ON hash_function_type_ \n                - must be an object with an interface compatible with projection_hash \n\n            INITIAL VALUE\n                 - size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing image feature extraction.  In\n                particular, it wraps another image feature extractor and converts the\n                wrapped image feature vectors into a high dimensional sparse vector.  For\n                example, if the lower level feature extractor outputs the vector [3,4,5]\n                and this vector is hashed into the second bin of four bins then the output\n                sparse vector is:\n                    [0,0,0,0, 3,4,5,1, 0,0,0,0, 0,0,0,0]. \n                That is, the output vector has a dimensionality that is equal to the number\n                of hash bins times the dimensionality of the lower level vector plus one.\n                The value in the extra dimension concatenated onto the end of the vector is\n                always a constant value of 1 and serves as a bias value.  This means\n                that, if there are N hash bins, these vectors are capable of representing N\n                different linear functions, each operating on the vectors that fall into\n                their corresponding hash bin.\n\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be\n                protected by a mutex lock except for the case where you are copying the\n                configuration (via copy_configuration()) of a binned_vector_feature_image\n                object to many other threads.  In this case, it is safe to copy the\n                configuration of a shared object so long as no other operations are\n                performed on it.\n\n\n            NOTATION \n                let BASE_FE denote the base feature_extractor object contained inside the\n                binned_vector_feature_image.\n        !*/\n\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef hash_function_type_ hash_function_type;\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        binned_vector_feature_image (\n        ); \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void set_hash (\n            const hash_function_type& hash\n        );\n        /*!\n            ensures\n                - #get_hash() == hash\n        !*/\n\n        const hash_function_type& get_hash (\n        ) const;\n        /*!\n            ensures\n                - returns the hash function used by this object to hash\n                  base feature vectors into integers.\n        !*/\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n        /*!\n            ensures\n                - performs BASE_FE.copy_configuration(item)\n        !*/\n\n        void copy_configuration (\n            const binned_vector_feature_image& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two binned_vector_feature_image \n                  objects H1 and H2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == any type that can be supplied to feature_extractor::load() \n            ensures\n                - performs BASE_FE.load(img)\n                  i.e. does feature extraction.  The features can be accessed using\n                  operator() as defined below.\n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.size() \n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nr() \n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nc() \n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the feature vectors returned by operator().\n                  In this case, this is the number of hash bins times the dimensionality of\n                  the features produced by BASE_FE plus one.  That is, this function\n                  returns get_hash().num_hash_bins()*(BASE_FE.get_num_dimensions()+1)\n        !*/\n\n        const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n                - It must be legal to evaluate expressions of the form: get_hash()(BASE_FE(row,col))\n                  (e.g. the hash function must be properly configured to process the feature\n                  vectors produced by the base feature extractor)\n            ensures\n                - hashes BASE_FE(row,col) and returns the resulting sparse vector.  In\n                  particular, we return a vector that is a copy of BASE_FE(row,col) that\n                  has been shifted into the part of the sparse vector indicated by the hash\n                  function.  It will also have a constant bias value of 1 appended to it.\n                - To be precise, this function returns a sparse vector V such that:\n                    - V.size() == BASE_FE.get_num_dimensions()+1\n                    - let IDX = get_hash()(BASE_FE(row,col))\n                    - for i where 0 <= i < BASE_FE.get_num_dimensions():\n                        - V[i].first == IDX*(BASE_FE.get_num_dimensions()+1) + i\n                        - V[i].second == BASE_FE(row,col)(i)\n                    - V[BASE_FE.get_num_dimensions()].first == IDX*(BASE_FE.get_num_dimensions()+1) + BASE_FE.get_num_dimensions()\n                    - V[BASE_FE.get_num_dimensions()].second == 1\n        !*/\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.get_block_rect(row,col)\n                  I.e. returns a rectangle that tells you what part of the original image is associated\n                  with a particular feature vector.\n        !*/\n\n        const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(p)\n                  I.e. Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(rect)\n                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(p)\n                  I.e. returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(rect)\n                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename U\n        >\n    void serialize (\n        const binned_vector_feature_image<T,U>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename U\n        >\n    void deserialize (\n        binned_vector_feature_image<T,U>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BINNED_VECTOR_FEATUrES_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/build_separable_poly_filters.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_\n#define DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_\n\n#include \"../matrix.h\"\n#include \"surf.h\"\n#include \"../uintn.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    typedef std::pair<matrix<double,0,1>, matrix<double,0,1> > separable_filter_type;\n    typedef std::pair<matrix<int32,0,1>, matrix<int32,0,1> > separable_int32_filter_type;\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<std::vector<separable_filter_type> > build_separable_poly_filters (\n        const long order,\n        const long window_size\n    ) \n    /*!\n        requires\n            - 1 <= order <= 6\n            - window_size >= 3 && window_size is odd\n        ensures\n            - the \"first\" element is the row_filter, the second is the col_filter.\n            - Some filters are not totally separable and that's why they are grouped\n              into vectors of vectors.  The groups are all the parts of a partially\n              separable filter.\n    !*/\n    {\n        long num_filters = 6;\n        switch (order)\n        {\n            case 1: num_filters = 3; break;\n            case 2: num_filters = 6; break;\n            case 3: num_filters = 10; break;\n            case 4: num_filters = 15; break;\n            case 5: num_filters = 21; break;\n            case 6: num_filters = 28; break;\n        }\n\n        matrix<double> X(window_size*window_size,num_filters);\n        matrix<double,0,1> G(window_size*window_size,1);\n        const double sigma = window_size/4.0;\n\n\n        long cnt = 0;\n        for (double x = -window_size/2; x <= window_size/2; ++x)\n        {\n            for (double y = -window_size/2; y <= window_size/2; ++y)\n            {\n                X(cnt, 0) = 1;\n                X(cnt, 1) = x;\n                X(cnt, 2) = y;\n\n                if (X.nc() > 5)\n                {\n                    X(cnt, 3) = x*x;\n                    X(cnt, 4) = x*y;\n                    X(cnt, 5) = y*y;\n                }\n                if (X.nc() > 9)\n                {\n                    X(cnt, 6) = x*x*x;\n                    X(cnt, 7) = y*x*x;\n                    X(cnt, 8) = y*y*x;\n                    X(cnt, 9) = y*y*y;\n                }\n                if (X.nc() > 14)\n                {\n                    X(cnt, 10) = x*x*x*x;\n                    X(cnt, 11) = y*x*x*x;\n                    X(cnt, 12) = y*y*x*x;\n                    X(cnt, 13) = y*y*y*x;\n                    X(cnt, 14) = y*y*y*y;\n                }\n                if (X.nc() > 20)\n                {\n                    X(cnt, 15) = x*x*x*x*x;\n                    X(cnt, 16) = y*x*x*x*x;\n                    X(cnt, 17) = y*y*x*x*x;\n                    X(cnt, 18) = y*y*y*x*x;\n                    X(cnt, 19) = y*y*y*y*x;\n                    X(cnt, 20) = y*y*y*y*y;\n                }\n                if (X.nc() > 27)\n                {\n                    X(cnt, 21) = x*x*x*x*x*x;\n                    X(cnt, 22) = y*x*x*x*x*x;\n                    X(cnt, 23) = y*y*x*x*x*x;\n                    X(cnt, 24) = y*y*y*x*x*x;\n                    X(cnt, 25) = y*y*y*y*x*x;\n                    X(cnt, 26) = y*y*y*y*y*x;\n                    X(cnt, 27) = y*y*y*y*y*y;\n                }\n\n                G(cnt) = std::sqrt(gaussian(x,y,sigma));\n                ++cnt;\n            }\n        }\n         \n        X = diagm(G)*X;\n\n        const matrix<double> S = inv(trans(X)*X)*trans(X)*diagm(G);\n\n        matrix<double,0,1> row_filter, col_filter;\n\n        matrix<double> u,v, temp;\n        matrix<double,0,1> w;\n\n        std::vector<std::vector<separable_filter_type> > results(num_filters);\n\n        for (long r = 0; r < S.nr(); ++r)\n        {\n            temp = reshape(rowm(S,r), window_size, window_size);\n            svd3(temp,u,w,v);\n            const double thresh = max(w)*1e-8;\n            for (long i = 0; i < w.size(); ++i)\n            {\n                if (w(i) > thresh)\n                {\n                    col_filter = std::sqrt(w(i))*colm(u,i);\n                    row_filter = std::sqrt(w(i))*colm(v,i);\n                    results[r].push_back(std::make_pair(row_filter, col_filter));\n                }\n            }\n        }\n\n        return results;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<std::vector<separable_int32_filter_type> > build_separable_int32_poly_filters (\n        const long order,\n        const long window_size,\n        const double max_range = 300.0\n    ) \n    /*!\n        requires\n            - 1 <= order <= 6\n            - window_size >= 3 && window_size is odd\n            - max_range > 1\n        ensures\n            - the \"first\" element is the row_filter, the second is the col_filter.\n    !*/\n    {\n        const std::vector<std::vector<separable_filter_type> >& filters = build_separable_poly_filters(order, window_size);\n        std::vector<std::vector<separable_int32_filter_type> > int_filters(filters.size());\n\n        for (unsigned long i = 0; i < filters.size(); ++i)\n        {\n\n            double max_val = 0;\n            for (unsigned long j = 0; j < filters[i].size(); ++j)\n            {\n                const separable_filter_type& filt = filters[i][j];\n                max_val = std::max(max_val, max(abs(filt.first)));\n                max_val = std::max(max_val, max(abs(filt.second)));\n            }\n            if (max_val == 0)\n                max_val = 1;\n\n            int_filters[i].resize(filters[i].size());\n            for (unsigned long j = 0; j < filters[i].size(); ++j)\n            {\n                const separable_filter_type& filt = filters[i][j];\n                int_filters[i][j].first  = matrix_cast<int32>(round(filt.first*max_range/max_val));\n                int_filters[i][j].second = matrix_cast<int32>(round(filt.second*max_range/max_val));\n            }\n        }\n\n        return int_filters;\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_BUILD_SEPARABLE_PoLY_FILTERS_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/draw_surf_points.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DRAW_SURf_POINTS_H_\n#define DLIB_DRAW_SURf_POINTS_H_\n\n#include \"surf.h\"\n#include \"../gui_widgets.h\"\n#include \"draw_surf_points_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    inline void draw_surf_points (\n        image_window& win,\n        const std::vector<surf_point>& sp\n    )\n    {\n        for (unsigned long i = 0; i < sp.size(); ++i)\n        {\n            const unsigned long radius = static_cast<unsigned long>(sp[i].p.scale*3);\n            const point center(sp[i].p.center);\n            point direction = center + point(radius,0);\n            // SURF descriptors are rotated by sp[i].angle.  So we want to include a visual\n            // indication of this rotation on our overlay.\n            direction = rotate_point(center, direction, sp[i].angle);\n\n            win.add_overlay(image_display::overlay_circle(center, radius, rgb_pixel(0,255,0)));\n            // Draw a line showing the orientation of the SURF descriptor.\n            win.add_overlay(center, direction, rgb_pixel(255,0,0));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAW_SURf_POINTS_H_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/draw_surf_points_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DRAW_SURf_POINTS_ABSTRACT_H_\n#ifdef DLIB_DRAW_SURf_POINTS_ABSTRACT_H_\n\n#include \"surf_abstract.h\"\n#include \"../gui_widgets.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void draw_surf_points (\n        image_window& win,\n        const std::vector<surf_point>& sp\n    );\n    /*!\n        ensures\n            - draws all the SURF points in sp onto the given image_window.  They\n              are drawn as overlay circles with extra lines to indicate the rotation\n              of the SURF descriptor.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAW_SURf_POINTS_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/image_keypoint/fine_hog_image.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FINE_HOG_IMaGE_Hh_\n#define DLIB_FINE_HOG_IMaGE_Hh_\n\n#include \"fine_hog_image_abstract.h\"\n#include \"../array2d.h\"\n#include \"../matrix.h\"\n#include \"hog.h\"\n\n\nnamespace dlib\n{\n    template <\n        unsigned long cell_size_,\n        unsigned long block_size_,\n        unsigned long pixel_stride_,\n        unsigned char num_orientation_bins_,\n        int           gradient_type_\n        >\n    class fine_hog_image : noncopyable\n    {\n        COMPILE_TIME_ASSERT(cell_size_ > 1);\n        COMPILE_TIME_ASSERT(block_size_ > 0);\n        COMPILE_TIME_ASSERT(pixel_stride_ > 0);\n        COMPILE_TIME_ASSERT(num_orientation_bins_ > 0);\n\n        COMPILE_TIME_ASSERT( gradient_type_ == hog_signed_gradient ||\n                             gradient_type_ == hog_unsigned_gradient);\n\n\n    public:\n\n        const static unsigned long cell_size = cell_size_;\n        const static unsigned long block_size = block_size_;\n        const static unsigned long pixel_stride = pixel_stride_;\n        const static unsigned long num_orientation_bins = num_orientation_bins_;\n        const static int           gradient_type = gradient_type_;\n\n        const static long min_size = cell_size*block_size+2;\n\n        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;\n\n        fine_hog_image (\n        ) : \n            num_block_rows(0),\n            num_block_cols(0)\n        {}\n\n        void clear (\n        )\n        {\n            num_block_rows = 0;\n            num_block_cols = 0;\n            hist_counts.clear();\n        }\n\n        void copy_configuration (\n            const fine_hog_image&\n        ){}\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        )\n        {\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );\n            load_impl(mat(img));\n        }\n\n        inline void unload(\n        ) { clear(); }\n\n        inline size_t size (\n        ) const { return static_cast<size_t>(nr()*nc()); }\n\n        inline long nr (\n        ) const { return num_block_rows; }\n\n        inline long nc (\n        ) const { return num_block_cols; }\n\n        long get_num_dimensions (\n        ) const\n        {\n            return block_size*block_size*num_orientation_bins;\n        }\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( 0 <= row && row < nr() &&\n                         0 <= col && col < nc(),\n                \"\\t descriptor_type fine_hog_image::operator()()\"\n                << \"\\n\\t invalid row or col argument\"\n                << \"\\n\\t row:  \" << row\n                << \"\\n\\t col:  \" << col \n                << \"\\n\\t nr(): \" << nr() \n                << \"\\n\\t nc(): \" << nc() \n                << \"\\n\\t this: \" << this\n                );\n\n            row *= pixel_stride;\n            col *= pixel_stride;\n\n            des = 0;\n            unsigned long off = 0;\n            for (unsigned long r = 0; r < block_size; ++r)\n            {\n                for (unsigned long c = 0; c < block_size; ++c)\n                {\n                    for (unsigned long rr = 0; rr < cell_size; ++rr)\n                    {\n                        for (unsigned long cc = 0; cc < cell_size; ++cc)\n                        {\n                            const histogram_count& hist = hist_counts[row + r*cell_size + rr][col + c*cell_size + cc];\n                            des(off + hist.quantized_angle_lower) += hist.lower_strength;\n                            des(off + hist.quantized_angle_upper) += hist.upper_strength;\n                        }\n                    }\n\n                    off += num_orientation_bins;\n                }\n            }\n\n            des /= length(des) + 1e-8;\n\n            return des;\n        }\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const\n        {\n            row *= pixel_stride;\n            col *= pixel_stride;\n\n            // do this to account for the 1 pixel padding we use all around the image\n            ++row;\n            ++col;\n\n            return rectangle(col, row, col+cell_size*block_size-1, row+cell_size*block_size-1);\n        }\n\n        const point image_to_feat_space (\n            const point& p\n        ) const\n        {\n            const long border_size = 1 + cell_size*block_size/2;\n            return (p-point(border_size,border_size))/(long)pixel_stride;\n        }\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n        }\n\n        const point feat_to_image_space (\n            const point& p\n        ) const\n        {\n            const long border_size = 1 + cell_size*block_size/2;\n            return p*(long)pixel_stride + point(border_size,border_size);\n        }\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n        }\n\n\n\n        // these _PRIVATE_ functions are only here as a workaround for a bug in visual studio 2005.  \n        void _PRIVATE_serialize (std::ostream& out) const\n        {\n            // serialize hist_counts\n            serialize(hist_counts.nc(),out);\n            serialize(hist_counts.nr(),out);\n            hist_counts.reset();\n            while (hist_counts.move_next())\n                hist_counts.element().serialize(out);\n            hist_counts.reset();\n\n\n            serialize(num_block_rows, out);\n            serialize(num_block_cols, out);\n        }\n\n        void _PRIVATE_deserialize (std::istream& in )\n        {\n            // deserialize item.hist_counts\n            long nc, nr;\n            deserialize(nc,in);\n            deserialize(nr,in);\n            hist_counts.set_size(nr,nc);\n            while (hist_counts.move_next())\n                hist_counts.element().deserialize(in); \n            hist_counts.reset();\n\n\n            deserialize(num_block_rows, in);\n            deserialize(num_block_cols, in);\n        }\n\n    private:\n\n        template <\n            typename image_type\n            >\n        void load_impl (\n            const image_type& img\n        )\n        {\n            // Note that we keep a border of 1 pixel all around the image so that we don't have\n            // to worry about running outside the image when computing the horizontal and vertical \n            // gradients.\n\n\n\n            // check if the window is just too small\n            if (img.nr() < min_size || img.nc() < min_size)\n            {\n                // If the image is smaller than our windows then there aren't any descriptors at all!\n                num_block_rows = 0;\n                num_block_cols = 0;\n                hist_counts.clear();\n                return;\n            }\n\n            hist_counts.set_size(img.nr()-2, img.nc()-2);\n\n\n\n\n            for (long r = 0; r < hist_counts.nr(); ++r)\n            {\n                for (long c = 0; c < hist_counts.nc(); ++c)\n                {\n                    unsigned long left; \n                    unsigned long right;\n                    unsigned long top;   \n                    unsigned long bottom; \n\n                    assign_pixel(left,   img(r+1,c));\n                    assign_pixel(right,  img(r+1,c+2));\n                    assign_pixel(top,    img(r  ,c+1));\n                    assign_pixel(bottom, img(r+2,c+1));\n\n                    double grad_x = (long)right-(long)left;\n                    double grad_y = (long)top-(long)bottom;\n\n                    // obtain the angle of the gradient.  Make sure it is scaled between 0 and 1.\n                    double angle = std::max(0.0, std::atan2(grad_y, grad_x)/pi + 1)/2;\n\n\n                    if (gradient_type == hog_unsigned_gradient)\n                    {\n                        angle *= 2;\n                        if (angle >= 1)\n                            angle -= 1;\n                    }\n\n\n                    // now scale angle to between 0 and num_orientation_bins\n                    angle *= num_orientation_bins;\n\n\n                    const double strength = std::sqrt(grad_y*grad_y + grad_x*grad_x);\n\n\n                    unsigned char quantized_angle_lower = static_cast<unsigned char>(std::floor(angle));\n                    unsigned char quantized_angle_upper = static_cast<unsigned char>(std::ceil(angle));\n\n                    quantized_angle_lower %= num_orientation_bins;\n                    quantized_angle_upper %= num_orientation_bins;\n\n                    const double angle_split = (angle-std::floor(angle));\n                    const double upper_strength = angle_split*strength;\n                    const double lower_strength = (1-angle_split)*strength;\n\n                    // Stick into gradient counts.  Note that we linearly interpolate between neighboring\n                    // histogram buckets.\n                    hist_counts[r][c].quantized_angle_lower = quantized_angle_lower;\n                    hist_counts[r][c].quantized_angle_upper = quantized_angle_upper;\n                    hist_counts[r][c].lower_strength = lower_strength;\n                    hist_counts[r][c].upper_strength = upper_strength;\n\n                }\n            }\n\n\n            // Now figure out how many feature extraction blocks we should have.  \n            num_block_rows = (hist_counts.nr() - block_size*cell_size + 1)/(long)pixel_stride; \n            num_block_cols = (hist_counts.nc() - block_size*cell_size + 1)/(long)pixel_stride; \n\n        }\n\n        struct histogram_count\n        {\n            unsigned char quantized_angle_lower;\n            unsigned char quantized_angle_upper;\n            float lower_strength;\n            float upper_strength;\n\n            void serialize(std::ostream& out) const\n            {\n                dlib::serialize(quantized_angle_lower, out);\n                dlib::serialize(quantized_angle_upper, out);\n                dlib::serialize(lower_strength, out);\n                dlib::serialize(upper_strength, out);\n            }\n            void deserialize(std::istream& in) \n            {\n                dlib::deserialize(quantized_angle_lower, in);\n                dlib::deserialize(quantized_angle_upper, in);\n                dlib::deserialize(lower_strength, in);\n                dlib::deserialize(upper_strength, in);\n            }\n        };\n\n        array2d<histogram_count> hist_counts;\n\n        mutable descriptor_type des;\n\n        long num_block_rows;\n        long num_block_cols;\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned char T4,\n        int           T5\n        >\n    void serialize (\n        const fine_hog_image<T1,T2,T3,T4,T5>& item,\n        std::ostream& out\n    )\n    {\n        item._PRIVATE_serialize(out);\n    }\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned char T4,\n        int           T5\n        >\n    void deserialize (\n        fine_hog_image<T1,T2,T3,T4,T5>& item,\n        std::istream& in \n    )\n    {\n        item._PRIVATE_deserialize(in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FINE_HOG_IMaGE_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/fine_hog_image_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_\n#ifdef DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_\n\n#include \"../array2d.h\"\n#include \"../matrix.h\"\n#include \"hog_abstract.h\"\n\n\nnamespace dlib\n{\n    template <\n        unsigned long cell_size_,\n        unsigned long block_size_,\n        unsigned long pixel_stride_,\n        unsigned char num_orientation_bins_,\n        int           gradient_type_\n        >\n    class fine_hog_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE PARAMETERS \n                - cell_size_ > 1\n                - block_size_ > 0\n                - pixel_stride_ > 0\n                - num_orientation_bins_ > 0\n                - gradient_type_ == hog_signed_gradient or hog_unsigned_gradient\n\n            INITIAL VALUE\n                 - size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a version of the hog_image that allows you to extract HOG\n                features at a finer resolution.  The hog_image can only extract HOG features\n                cell_size_ pixels apart.  However, this object, the fine_hog_image can \n                extract HOG features from every pixel location.\n\n                The template arguments to this class have the same meaning as they do for\n                the hog_image, except for pixel_stride_.  This controls the stepping between\n                HOG extraction locations.  A value of 1 indicates HOG features should be\n                extracted from every pixel location.  A value of 2 indicates every other pixel\n                location, etc.\n\n                Finally, note that the interpolation used by this object is equivalent\n                to using hog_angle_interpolation with hog_image.  \n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a fine_hog_image object to many other threads.  \n                In this case, it is safe to copy the configuration of a shared object so long\n                as no other operations are performed on it.\n        !*/\n\n    public:\n\n        const static unsigned long cell_size = cell_size_;\n        const static unsigned long block_size = block_size_;\n        const static unsigned long pixel_stride = pixel_stride_;\n        const static unsigned long num_orientation_bins = num_orientation_bins_;\n        const static int           gradient_type = gradient_type_;\n\n        const static long min_size = cell_size*block_size+2;\n\n        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;\n\n        fine_hog_image (\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void copy_configuration (\n            const fine_hog_image&\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two fine_hog_image \n                  objects H1 and H2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type is a dlib::matrix or something convertible to a matrix\n                  via mat()\n                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            ensures\n                - if (img.nr() < min_size || img.nc() < min_size) then\n                    - the image is too small so we don't compute anything on it\n                    - #size() == 0\n                - else\n                    - generates a HOG image from the given image.   \n                    - #size() > 0\n        !*/\n\n        inline void unload(\n        );\n        /*!\n            ensures\n                - #nr() == 0\n                - #nc() == 0\n                - clears only the state information which is populated by load().  For \n                  example, let H be a fine_hog_image object.  Then consider the two \n                  sequences of instructions:\n                    Sequence 1:\n                        H.load(img);      \n                        H.unload();\n                        H.load(img);\n\n                    Sequence 2:\n                        H.load(img);\n                  Both sequence 1 and sequence 2 should have the same effect on H.  \n        !*/\n\n        inline size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns nr()*nc()\n        !*/\n\n        inline long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this HOG image\n        !*/\n\n        inline long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this HOG image\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the number of dimensions in the feature vectors generated by\n                  this object.  \n                - In particular, returns the value block_size*block_size*num_orientation_bins\n        !*/\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n            ensures\n                - returns the descriptor for the HOG block at the given row and column.  This descriptor \n                  will include information from a window that is located at get_block_rect(row,col) in\n                  the original image given to load().\n                - The returned descriptor vector will have get_num_dimensions() elements.\n        !*/\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns a rectangle that tells you what part of the original image is associated\n                  with a particular HOG block.  That is, what part of the input image is associated\n                  with (*this)(row,col).\n                - The returned rectangle will be cell_size*block_size pixels wide and tall.\n        !*/\n\n        const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned char T4,\n        int           T5\n        >\n    void serialize (\n        const fine_hog_image<T1,T2,T3,T4,T5>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned char T4,\n        int           T5\n        >\n    void deserialize (\n        fine_hog_image<T1,T2,T3,T4,T5>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FINE_HOG_IMaGE_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/hashed_feature_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HASHED_IMAGE_FEATUrES_Hh_\n#define DLIB_HASHED_IMAGE_FEATUrES_Hh_\n\n#include \"../lsh/projection_hash.h\"\n#include \"hashed_feature_image_abstract.h\"\n#include <vector>\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../statistics.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type_ = projection_hash\n        >\n    class hashed_feature_image : noncopyable\n    {\n\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef hash_function_type_ hash_function_type;\n\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        hashed_feature_image (\n        ); \n\n        void clear (\n        );\n\n        void set_hash (\n            const hash_function_type& hash_\n        );\n\n        const hash_function_type& get_hash (\n        ) const;\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n\n        void copy_configuration (\n            const hashed_feature_image& item\n        );\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n\n        inline size_t size (\n        ) const;\n\n        inline long nr (\n        ) const;\n\n        inline long nc (\n        ) const;\n\n        inline long get_num_dimensions (\n        ) const;\n\n        void use_relative_feature_weights (\n        );\n\n        void use_uniform_feature_weights (\n        );\n\n        bool uses_uniform_feature_weights (\n        ) const;\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n\n        inline const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n\n        inline const point image_to_feat_space (\n            const point& p\n        ) const;\n\n        inline const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n\n        inline const point feat_to_image_space (\n            const point& p\n        ) const;\n\n        inline const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n\n        template <typename T>\n        friend void serialize (\n            const hashed_feature_image<T>& item,\n            std::ostream& out\n        );\n\n        template <typename T>\n        friend void deserialize (\n            hashed_feature_image<T>& item,\n            std::istream& in \n        );\n\n    private:\n\n        array2d<unsigned long> feats;\n        feature_extractor fe;\n        hash_function_type phash;\n        std::vector<float> feat_counts;\n        bool uniform_feature_weights;\n\n\n        // This is a transient variable.  It is just here so it doesn't have to be\n        // reallocated over and over inside operator()\n        mutable descriptor_type hash_feats;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const hashed_feature_image<T>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.feats, out);\n        serialize(item.fe, out);\n        serialize(item.phash, out);\n        serialize(item.feat_counts, out);\n        serialize(item.uniform_feature_weights, out);\n    }\n\n    template <typename T>\n    void deserialize (\n        hashed_feature_image<T>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing a dlib::hashed_feature_image object.\");\n\n        deserialize(item.feats, in);\n        deserialize(item.fe, in);\n        deserialize(item.phash, in);\n        deserialize(item.feat_counts, in);\n        deserialize(item.uniform_feature_weights, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                        hashed_feature_image member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    hashed_feature_image<feature_extractor,hash_function_type>::\n    hashed_feature_image (\n    )  \n    {\n        clear();\n        hash_feats.resize(1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    clear (\n    )\n    {\n        fe.clear();\n        phash = hash_function_type();\n        feats.clear();\n        feat_counts.clear();\n        uniform_feature_weights = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    set_hash (\n        const hash_function_type& hash_\n    )\n    {\n        phash = hash_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const hash_function_type& hashed_feature_image<feature_extractor,hash_function_type>::\n    get_hash (\n    ) const\n    {\n        return phash;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    copy_configuration (\n        const feature_extractor& item\n    )\n    {\n        fe.copy_configuration(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    copy_configuration (\n        const hashed_feature_image& item\n    )\n    {\n        fe.copy_configuration(item.fe);\n        phash = item.phash;\n        uniform_feature_weights = item.uniform_feature_weights;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    template <\n        typename image_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    load (\n        const image_type& img\n    )\n    {\n        fe.load(img);\n\n        if (fe.size() != 0)\n        {\n            feats.set_size(fe.nr(), fe.nc());\n            feat_counts.assign(phash.num_hash_bins(),1);\n            if (uniform_feature_weights)\n            {\n                for (long r = 0; r < feats.nr(); ++r)\n                {\n                    for (long c = 0; c < feats.nc(); ++c)\n                    {\n                        feats[r][c] = phash(fe(r,c));\n                    }\n                }\n            }\n            else\n            {\n                for (long r = 0; r < feats.nr(); ++r)\n                {\n                    for (long c = 0; c < feats.nc(); ++c)\n                    {\n                        feats[r][c] = phash(fe(r,c));\n                        feat_counts[feats[r][c]]++;\n                    }\n                }\n            }\n        }\n        else\n        {\n            feats.set_size(0,0);\n        }\n\n        if (!uniform_feature_weights)\n        {\n            // use the inverse frequency as the scale for each feature.  We also scale\n            // these counts so that they are invariant to the size of the image (we scale\n            // them so they all look like they come from a 500x400 images).\n            const double scale = image_size(img)/(500.0*400.0);\n            for (unsigned long i = 0; i < feat_counts.size(); ++i)\n            {\n                feat_counts[i] = scale/feat_counts[i];\n            }\n        }\n\n        fe.unload();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    size_t hashed_feature_image<feature_extractor,hash_function_type>::\n    size (\n    ) const\n    {\n        return feats.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long hashed_feature_image<feature_extractor,hash_function_type>::\n    nr (\n    ) const\n    {\n        return feats.nr();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long hashed_feature_image<feature_extractor,hash_function_type>::\n    nc (\n    ) const\n    {\n        return feats.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    long hashed_feature_image<feature_extractor,hash_function_type>::\n    get_num_dimensions (\n    ) const\n    {\n        return phash.num_hash_bins();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    use_relative_feature_weights (\n    ) \n    {\n        uniform_feature_weights = false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    void hashed_feature_image<feature_extractor,hash_function_type>::\n    use_uniform_feature_weights (\n    ) \n    {\n        uniform_feature_weights = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    bool hashed_feature_image<feature_extractor,hash_function_type>::\n    uses_uniform_feature_weights (\n    ) const\n    {\n        return uniform_feature_weights;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const std::vector<std::pair<unsigned int,double> >& hashed_feature_image<feature_extractor,hash_function_type>::\n    operator() (\n        long row,\n        long col\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 <= row && row < nr() &&\n                    0 <= col && col < nc(),\n            \"\\t descriptor_type hashed_feature_image::operator(row,col)\"\n            << \"\\n\\t Invalid inputs were given to this function\"\n            << \"\\n\\t row:  \" << row\n            << \"\\n\\t col:  \" << col \n            << \"\\n\\t nr(): \" << nr()\n            << \"\\n\\t nc(): \" << nc()\n            << \"\\n\\t this: \" << this\n            );\n\n        hash_feats[0] = std::make_pair(feats[row][col],feat_counts[feats[row][col]]);\n        return hash_feats;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::\n    get_block_rect (\n        long row,\n        long col\n    ) const\n    {\n        return fe.get_block_rect(row,col);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const point hashed_feature_image<feature_extractor,hash_function_type>::\n    image_to_feat_space (\n        const point& p\n    ) const\n    {\n        return fe.image_to_feat_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::\n    image_to_feat_space (\n        const rectangle& rect\n    ) const\n    {\n        return fe.image_to_feat_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const point hashed_feature_image<feature_extractor,hash_function_type>::\n    feat_to_image_space (\n        const point& p\n    ) const\n    {\n        return fe.feat_to_image_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type\n        >\n    const rectangle hashed_feature_image<feature_extractor,hash_function_type>::\n    feat_to_image_space (\n        const rectangle& rect\n    ) const \n    {\n        return fe.feat_to_image_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASHED_IMAGE_FEATUrES_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/hashed_feature_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_\n#ifdef DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_\n\n#include \"../lsh/projection_hash_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include \"../statistics.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor,\n        typename hash_function_type_ = projection_hash\n        >\n    class hashed_feature_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor \n                - must be an object with an interface compatible with dlib::hog_image\n\n            REQUIREMENTS ON hash_function_type_ \n                - must be an object with an interface compatible with projection_hash \n\n            INITIAL VALUE\n                 - size() == 0\n                 - uses_uniform_feature_weights() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing image feature extraction.  In\n                particular, it wraps another image feature extractor and converts the\n                wrapped image feature vectors into sparse indicator vectors.  It does this\n                by hashing each feature vector into the range [0, get_num_dimensions()-1]\n                and then returns a new vector which is zero everywhere except for the\n                position determined by the hash. \n\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a hashed_feature_image object to many other threads.  \n                In this case, it is safe to copy the configuration of a shared object so long\n                as no other operations are performed on it.\n\n\n            NOTATION \n                let BASE_FE denote the base feature_extractor object contained inside \n                the hashed_feature_image.\n        !*/\n\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef hash_function_type_ hash_function_type;\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        hashed_feature_image (\n        ); \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void set_hash (\n            const hash_function_type& hash\n        );\n        /*!\n            ensures\n                - #get_hash() == hash\n        !*/\n\n        const hash_function_type& get_hash (\n        ) const;\n        /*!\n            ensures\n                - returns the hash function used by this object to hash\n                  base feature vectors into integers.\n        !*/\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n        /*!\n            ensures\n                - performs BASE_FE.copy_configuration(item)\n        !*/\n\n        void copy_configuration (\n            const hashed_feature_image& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two hashed_feature_image \n                  objects H1 and H2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == any type that can be supplied to feature_extractor::load() \n            ensures\n                - performs BASE_FE.load(img)\n                  i.e. does feature extraction.  The features can be accessed using\n                  operator() as defined below.\n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.size() \n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nr() \n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nc() \n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the feature vectors returned by operator().  \n                  In this case, this is the number of hash bins.  That is, get_hash().num_hash_bins()\n        !*/\n\n        void use_relative_feature_weights (\n        );\n        /*!\n            ensures\n                - #uses_uniform_feature_weights() == false\n        !*/\n\n        void use_uniform_feature_weights (\n        );\n        /*!\n            ensures\n                - #uses_uniform_feature_weights() == true \n        !*/\n\n        bool uses_uniform_feature_weights (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object weights each feature with a value of 1 and\n                  false if it uses a weighting of 1/N where N is the number of occurrences\n                  of the feature in an image (note that we normalize N so that it is\n                  invariant to the size of the image given to load()).\n        !*/\n\n        const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n                - It must be legal to evaluate expressions of the form: get_hash()(BASE_FE(row,col))\n                  (e.g. the hash function must be properly configured to process the feature\n                  vectors produced by the base feature extractor)\n            ensures\n                - hashes BASE_FE(row,col) and returns the resulting indicator vector. \n                - To be precise, this function returns a sparse vector V such that:\n                    - V.size() == 1 \n                    - V[0].first == get_hash()(BASE_FE(row,col))\n                    - if (uses_uniform_feature_weights()) then\n                        - V[0].second == 1 \n                    - else\n                        - V[0].second == 1/N where N is the number of times a feature in\n                          hash bin V[0].first was observed in the image given to load().\n                          Note that we scale all the counts so that they are invariant to\n                          the size of the image.\n        !*/\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.get_block_rect(row,col)\n                  I.e. returns a rectangle that tells you what part of the original image is associated\n                  with a particular feature vector.\n        !*/\n\n        const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(p)\n                  I.e. Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(rect)\n                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(p)\n                  I.e. returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(rect)\n                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename U\n        >\n    void serialize (\n        const hashed_feature_image<T,U>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename U\n        >\n    void deserialize (\n        hashed_feature_image<T,U>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HASHED_IMAGE_FEATUrES_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/hessian_pyramid.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HESSIAN_PYRAMId_Hh_\n#define DLIB_HESSIAN_PYRAMId_Hh_\n\n#include \"hessian_pyramid_abstract.h\"\n#include \"../algs.h\"\n#include \"../image_transforms/integral_image.h\"\n#include \"../array.h\"\n#include \"../array2d.h\"\n#include \"../noncopyable.h\"\n#include \"../matrix.h\"\n#include \"../stl_checked.h\"\n#include <algorithm>\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct interest_point\n    {\n        interest_point() : scale(0), score(0), laplacian(0) {}\n\n        dlib::vector<double,2> center;\n        double scale;\n        double score;\n        double laplacian;\n\n        bool operator < (const interest_point& p) const { return score < p.score; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize(\n        const interest_point& item,  \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.center,out);\n            serialize(item.scale,out);\n            serialize(item.score,out);\n            serialize(item.laplacian,out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type interest_point\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize(\n        interest_point& item,  \n        std::istream& in \n    )\n    {\n        try\n        {\n            deserialize(item.center,in);\n            deserialize(item.scale,in);\n            deserialize(item.score,in);\n            deserialize(item.laplacian,in);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while deserializing object of type interest_point\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class hessian_pyramid : noncopyable\n    {\n    public:\n        hessian_pyramid()\n        {\n            num_octaves = 0;\n            num_intervals = 0;\n            initial_step_size = 0;\n        }\n\n        template <typename integral_image_type>\n        void build_pyramid (\n            const integral_image_type& img,\n            long num_octaves,\n            long num_intervals,\n            long initial_step_size\n        )\n        {\n            DLIB_ASSERT(num_octaves > 0 && num_intervals > 0 && initial_step_size > 0,\n                \"\\tvoid build_pyramid()\"\n                << \"\\n\\tAll arguments to this function must be > 0\"\n                << \"\\n\\t this:              \" << this\n                << \"\\n\\t num_octaves:       \" << num_octaves \n                << \"\\n\\t num_intervals:     \" << num_intervals \n                << \"\\n\\t initial_step_size: \" << initial_step_size \n            );\n\n            this->num_octaves = num_octaves;\n            this->num_intervals = num_intervals;\n            this->initial_step_size = initial_step_size;\n\n            // allocate space for the pyramid\n            pyramid.resize(num_octaves*num_intervals);\n            for (long o = 0; o < num_octaves; ++o)\n            {\n                const long step_size = get_step_size(o);\n                for (long i = 0; i < num_intervals; ++i)\n                {\n                    pyramid[num_intervals*o + i].set_size(img.nr()/step_size, img.nc()/step_size);\n                }\n            }\n\n            // now fill out the pyramid with data\n            for (long o = 0; o < num_octaves; ++o)\n            {\n                const long step_size = get_step_size(o);\n\n                for (long i = 0; i < num_intervals; ++i)\n                {\n                    const long border_size = get_border_size(i)*step_size;\n                    const long lobe_size = std::lround(std::pow(2.0, o+1.0))*(i+1) + 1;\n                    const double area_inv = 1.0/std::pow(3.0*lobe_size, 2.0);\n\n                    const long lobe_offset = lobe_size/2+1;\n                    const point tl(-lobe_offset,-lobe_offset);\n                    const point tr(lobe_offset,-lobe_offset);\n                    const point bl(-lobe_offset,lobe_offset);\n                    const point br(lobe_offset,lobe_offset);\n\n                    for (long r = border_size; r < img.nr() - border_size; r += step_size)\n                    {\n                        for (long c = border_size; c < img.nc() - border_size; c += step_size)\n                        {\n                            const point p(c,r);\n\n                            double Dxx = img.get_sum_of_area(centered_rect(p, lobe_size*3, 2*lobe_size-1)) - \n                                         img.get_sum_of_area(centered_rect(p, lobe_size,   2*lobe_size-1))*3.0;\n\n                            double Dyy = img.get_sum_of_area(centered_rect(p, 2*lobe_size-1, lobe_size*3)) - \n                                         img.get_sum_of_area(centered_rect(p, 2*lobe_size-1, lobe_size))*3.0;\n\n                            double Dxy = img.get_sum_of_area(centered_rect(p+bl, lobe_size, lobe_size)) + \n                                         img.get_sum_of_area(centered_rect(p+tr, lobe_size, lobe_size)) -\n                                         img.get_sum_of_area(centered_rect(p+tl, lobe_size, lobe_size)) -\n                                         img.get_sum_of_area(centered_rect(p+br, lobe_size, lobe_size));\n\n                            // now we normalize the filter responses\n                            Dxx *= area_inv;\n                            Dyy *= area_inv;\n                            Dxy *= area_inv;\n\n\n                            double sign_of_laplacian = +1;\n                            if (Dxx + Dyy < 0)\n                                sign_of_laplacian = -1;\n\n                            double determinant = Dxx*Dyy - 0.81*Dxy*Dxy;\n\n                            // If the determinant is negative then just blank it out by setting\n                            // it to zero.\n                            if (determinant < 0)\n                                determinant = 0;\n\n                            // Save the determinant of the Hessian into our image pyramid.  Also\n                            // pack the laplacian sign into the value so we can get it out later.\n                            pyramid[o*num_intervals + i][r/step_size][c/step_size] = sign_of_laplacian*determinant;\n\n                        }\n                    }\n\n                }\n            }\n        }\n\n        long get_border_size (\n            long interval \n        ) const\n        {\n            DLIB_ASSERT(0 <= interval && interval < intervals(),\n                \"\\tlong get_border_size(interval)\"\n                << \"\\n\\tInvalid interval value\"\n                << \"\\n\\t this:   \" << this\n                << \"\\n\\t interval: \" << interval \n            );\n\n            const double lobe_size = 2.0*(interval+1) + 1;\n            const double filter_size = 3*lobe_size;\n\n            const long bs = static_cast<long>(std::ceil(filter_size/2.0));\n            return bs;\n        }\n\n        long get_step_size (\n            long octave\n        ) const\n        {\n            DLIB_ASSERT(0 <= octave && octave < octaves(),\n                \"\\tlong get_step_size(octave)\"\n                << \"\\n\\tInvalid octave value\"\n                << \"\\n\\t this:   \" << this\n                << \"\\n\\t octave: \" << octave \n            );\n\n            return initial_step_size*std::lround(std::pow(2.0, (double)octave));\n        }\n\n        long nr (\n            long octave\n        ) const\n        {\n            DLIB_ASSERT(0 <= octave && octave < octaves(),\n                \"\\tlong nr(octave)\"\n                << \"\\n\\tInvalid octave value\"\n                << \"\\n\\t this:   \" << this\n                << \"\\n\\t octave: \" << octave \n            );\n\n            return pyramid[num_intervals*octave].nr();\n        }\n\n        long nc (\n            long octave\n        ) const\n        {\n            DLIB_ASSERT(0 <= octave && octave < octaves(),\n                \"\\tlong nc(octave)\"\n                << \"\\n\\tInvalid octave value\"\n                << \"\\n\\t this:   \" << this\n                << \"\\n\\t octave: \" << octave \n            );\n\n            return pyramid[num_intervals*octave].nc();\n        }\n\n        double get_value (\n            long octave,\n            long interval,\n            long r,\n            long c\n        ) const\n        {\n            DLIB_ASSERT(0 <= octave && octave < octaves() &&\n                        0 <= interval && interval < intervals() &&\n                        get_border_size(interval) <= r && r < nr(octave)-get_border_size(interval) &&\n                        get_border_size(interval) <= c && c < nc(octave)-get_border_size(interval),\n                \"\\tdouble get_value(octave, interval, r, c)\"\n                << \"\\n\\tInvalid inputs to this function\"\n                << \"\\n\\t this:      \" << this\n                << \"\\n\\t octave:    \" << octave \n                << \"\\n\\t interval:  \" << interval \n                << \"\\n\\t octaves:   \" << octaves() \n                << \"\\n\\t intervals: \" << intervals()\n                << \"\\n\\t r:         \" << r  \n                << \"\\n\\t c:         \" << c \n                << \"\\n\\t nr(octave): \" << nr(octave)  \n                << \"\\n\\t nc(octave): \" << nc(octave) \n                << \"\\n\\t get_border_size(interval): \" << get_border_size(interval) \n            );\n\n            return std::abs(pyramid[num_intervals*octave + interval][r][c]);\n        }\n\n        double get_laplacian (\n            long octave,\n            long interval,\n            long r,\n            long c\n        ) const\n        {\n            DLIB_ASSERT(0 <= octave && octave < octaves() &&\n                        0 <= interval && interval < intervals() &&\n                        get_border_size(interval) <= r && r < nr(octave)-get_border_size(interval) &&\n                        get_border_size(interval) <= c && c < nc(octave)-get_border_size(interval),\n                \"\\tdouble get_laplacian(octave, interval, r, c)\"\n                << \"\\n\\tInvalid inputs to this function\"\n                << \"\\n\\t this:      \" << this\n                << \"\\n\\t octave:    \" << octave \n                << \"\\n\\t interval:  \" << interval \n                << \"\\n\\t octaves:   \" << octaves() \n                << \"\\n\\t intervals: \" << intervals()\n                << \"\\n\\t r:         \" << r  \n                << \"\\n\\t c:         \" << c \n                << \"\\n\\t nr(octave): \" << nr(octave)  \n                << \"\\n\\t nc(octave): \" << nc(octave) \n                << \"\\n\\t get_border_size(interval): \" << get_border_size(interval) \n            );\n\n            // return the sign of the laplacian\n            if (pyramid[num_intervals*octave + interval][r][c] > 0)\n                return +1;\n            else\n                return -1;\n        }\n\n        long octaves (\n        ) const { return num_octaves; }\n\n        long intervals (\n        ) const { return num_intervals; }\n\n    private:\n\n        long num_octaves;\n        long num_intervals;\n        long initial_step_size;\n\n        typedef array2d<double> image_type;\n        typedef array<image_type> pyramid_type;\n\n        pyramid_type pyramid;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace hessian_pyramid_helpers\n    {\n        inline bool is_maximum_in_region(\n            const hessian_pyramid& pyr,\n            long o, \n            long i, \n            long r, \n            long c\n        )\n        {\n            // First check if this point is near the edge of the octave \n            // If it is then we say it isn't a maximum as these points are\n            // not as reliable.\n            if (i <= 0 || i+1 >= pyr.intervals())\n            {\n                return false;\n            }\n\n            const double val = pyr.get_value(o,i,r,c);\n\n            // now check if there are any bigger values around this guy\n            for (long ii = i-1; ii <= i+1; ++ii)\n            {\n                for (long rr = r-1; rr <= r+1; ++rr)\n                {\n                    for (long cc = c-1; cc <= c+1; ++cc)\n                    {\n                        if (pyr.get_value(o,ii,rr,cc) > val)\n                            return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const matrix<double,3,1> get_hessian_gradient (\n            const hessian_pyramid& pyr,\n            long o, \n            long i, \n            long r, \n            long c\n        )\n        {\n            matrix<double,3,1> grad;\n            grad(0) = (pyr.get_value(o,i,r,c+1) - pyr.get_value(o,i,r,c-1))/2.0;\n            grad(1) = (pyr.get_value(o,i,r+1,c) - pyr.get_value(o,i,r-1,c))/2.0;\n            grad(2) = (pyr.get_value(o,i+1,r,c) - pyr.get_value(o,i-1,r,c))/2.0;\n            return grad;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const matrix<double,3,3> get_hessian_hessian (\n            const hessian_pyramid& pyr,\n            long o, \n            long i, \n            long r, \n            long c\n        )\n        {\n            matrix<double,3,3> hess;\n            const double val = pyr.get_value(o,i,r,c);\n\n            double Dxx = (pyr.get_value(o,i,r,c+1) + pyr.get_value(o,i,r,c-1)) - 2*val;\n            double Dyy = (pyr.get_value(o,i,r+1,c) + pyr.get_value(o,i,r-1,c)) - 2*val;\n            double Dss = (pyr.get_value(o,i+1,r,c) + pyr.get_value(o,i-1,r,c)) - 2*val;\n\n            double Dxy = (pyr.get_value(o,i,r+1,c+1) + pyr.get_value(o,i,r-1,c-1) -\n                          pyr.get_value(o,i,r-1,c+1) - pyr.get_value(o,i,r+1,c-1)) / 4.0;\n\n            double Dxs = (pyr.get_value(o,i+1,r,c+1) + pyr.get_value(o,i-1,r,c-1) -\n                          pyr.get_value(o,i-1,r,c+1) - pyr.get_value(o,i+1,r,c-1)) / 4.0;\n\n            double Dys = (pyr.get_value(o,i+1,r+1,c) + pyr.get_value(o,i-1,r-1,c) -\n                          pyr.get_value(o,i-1,r+1,c) - pyr.get_value(o,i+1,r-1,c)) / 4.0;\n\n\n            hess = Dxx, Dxy, Dxs,\n            Dxy, Dyy, Dys,\n            Dxs, Dys, Dss;\n\n            return hess;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const interest_point interpolate_point (\n            const hessian_pyramid& pyr, \n            long o, \n            long i, \n            long r, \n            long c\n        )\n        {\n            dlib::vector<double,2> p(c,r);\n\n            dlib::vector<double,3> start_point(c,r,i);\n            dlib::vector<double,3> interpolated_point = -inv(get_hessian_hessian(pyr,o,i,r,c))*get_hessian_gradient(pyr,o,i,r,c);\n\n            //cout << \"inter: \" <<  trans(interpolated_point);\n\n            interest_point temp;\n            if (max(abs(interpolated_point)) < 0.5)\n            {\n                p = (start_point+interpolated_point)*pyr.get_step_size(o);\n                const double lobe_size = std::pow(2.0, o+1.0)*(i+interpolated_point.z()+1) + 1;\n                const double filter_size = 3*lobe_size;\n                const double scale = 1.2/9.0 * filter_size;\n\n                temp.center = p;\n                temp.scale = scale;\n                temp.score = pyr.get_value(o,i,r,c);\n                temp.laplacian = pyr.get_laplacian(o,i,r,c);\n            }\n            else\n            {\n                // this indicates to the caller that no interest point was found.\n                temp.score = -1;\n            }\n\n            return temp;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename Alloc>\n    void get_interest_points (\n        const hessian_pyramid& pyr,\n        double threshold,\n        std::vector<interest_point,Alloc>& result_points\n    )\n    {\n        DLIB_ASSERT(threshold >= 0,\n            \"\\tvoid get_interest_points()\"\n            << \"\\n\\t Invalid arguments to this function\"\n            << \"\\n\\t threshold: \" << threshold \n        );\n        using namespace hessian_pyramid_helpers;\n\n        result_points.clear();\n\n        for (long o = 0; o < pyr.octaves(); ++o)\n        {\n            const long nr = pyr.nr(o);\n            const long nc = pyr.nc(o);\n\n            // do non-maximum suppression on all the intervals in the current octave and \n            // accumulate the results in result_points\n            for (long i = 1; i < pyr.intervals()-1;  i += 1)\n            {\n                const long border_size = pyr.get_border_size(i+1);\n                for (long r = border_size+1; r < nr - border_size-1; r += 1)\n                {\n                    for (long c = border_size+1; c < nc - border_size-1; c += 1)\n                    {\n                        double max_val = pyr.get_value(o,i,r,c);\n                        long max_i = i;\n                        long max_r = r;\n                        long max_c = c;\n\n\n                        // If the max point we found is really a maximum in its own region and\n                        // is big enough then add it to the results.\n                        if (max_val >= threshold && is_maximum_in_region(pyr, o, max_i, max_r, max_c))\n                        {\n                            //cout << max_val << endl;\n                            interest_point sp = interpolate_point (pyr, o, max_i, max_r, max_c);\n                            if (sp.score >= threshold)\n                            {\n                                result_points.push_back(sp);\n                            }\n                        }\n\n                    }\n                }\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename Alloc>\n    void get_interest_points (\n        const hessian_pyramid& pyr,\n        double threshold,\n        std_vector_c<interest_point,Alloc>& result_points\n    )\n    /*!\n        This function is just an overload that automatically casts std_vector_c objects\n        into std::vector objects.  (Usually this is automatic but the template argument\n        there messes up the conversion so we have to do it explicitly)\n    !*/\n    {\n        std::vector<interest_point,Alloc>& v = result_points;\n        get_interest_points(pyr, threshold, v);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif  // DLIB_HESSIAN_PYRAMId_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/hessian_pyramid_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_\n#ifdef DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_\n\n#include \"../image_transforms/integral_image_abstract.h\"\n#include \"../noncopyable.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n    class hessian_pyramid : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                - octaves() == 0\n                - intervals() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an image pyramid where each level in the\n                pyramid holds determinants of Hessian matrices for the original \n                input image.  This object can be used to find stable interest\n                points in an image.  For further details consult the following\n                papers.\n\n                This object is an implementation of the fast Hessian pyramid \n                as described in the paper: \n                   SURF: Speeded Up Robust Features\n                   By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool\n\n                This implementation was also influenced by the very well documented\n                OpenSURF library and its corresponding description of how the fast\n                Hessian algorithm functions:  \n                    Notes on the OpenSURF Library\n                    Christopher Evans\n        !*/\n    public:\n\n        template <typename integral_image_type>\n        void build_pyramid (\n            const integral_image_type& img,\n            long num_octaves,\n            long num_intervals,\n            long initial_step_size\n        );\n        /*!\n            requires\n                - num_octaves > 0\n                - num_intervals > 0\n                - initial_step_size > 0\n                - integral_image_type == an object such as dlib::integral_image or another\n                  type that implements the interface defined in image_transforms/integral_image_abstract.h\n            ensures\n                - #get_step_size(0) == initial_step_size\n                - #octaves() == num_octaves\n                - #intervals() == num_intervals\n                - creates a Hessian pyramid from the given input image.  \n        !*/\n\n        long octaves (\n        ) const;\n        /*!\n            ensures\n                - returns the number of octaves in this pyramid\n        !*/\n\n        long intervals (\n        ) const; \n        /*!\n            ensures\n                - returns the number of intervals in this pyramid\n        !*/\n\n        long get_border_size (\n            long interval\n        ) const;\n        /*!\n            requires\n                - 0 <= interval < intervals()\n            ensures\n                - Each interval of the pyramid has a certain sized border region where we\n                  can't compute the Hessian values since they are too close to the edge\n                  of the input image.  This function returns the size of that border.\n        !*/\n\n        long get_step_size (\n            long octave\n        ) const;\n        /*!\n            requires\n                - 0 <= octave < octaves()\n            ensures\n                - Each octave has a step size value.  This value determines how many\n                  input image pixels separate each pixel in the given pyramid octave.\n                  As the octave gets larger (i.e. as it goes to the top of the pyramid) the\n                  step size gets bigger and thus the pyramid narrows.\n        !*/\n\n        long nr (\n            long octave\n        ) const;\n        /*!\n            requires\n                - 0 <= octave < octaves()\n            ensures\n                - returns the number of rows there are per layer in the given \n                  octave of pyramid\n        !*/\n\n        long nc (\n            long octave\n        ) const;\n        /*!\n            requires\n                - 0 <= octave < octaves()\n            ensures\n                - returns the number of columns there are per layer in the given \n                  octave of pyramid\n        !*/\n\n        double get_value (\n            long octave,\n            long interval,\n            long r,\n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= octave < octaves()\n                - 0 <= interval < intervals()\n                - Let BS == get_border_size(interval): then\n                    - BS <= r < nr(octave)-BS\n                    - BS <= c < nc(octave)-BS\n            ensures\n                - returns the determinant of the Hessian from the given octave and interval\n                  of the pyramid.  The specific point sampled at this pyramid level is\n                  the one that corresponds to the input image point (point(r,c)*get_step_size(octave)).\n        !*/\n\n        double get_laplacian (\n            long octave,\n            long interval,\n            long r,\n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= octave < octaves()\n                - 0 <= interval < intervals()\n                - Let BS == get_border_size(interval): then\n                    - BS <= r < nr(octave)-BS\n                    - BS <= c < nc(octave)-BS\n            ensures\n                - returns the sign of the laplacian for the given octave and interval\n                  of the pyramid.  The specific point sampled at this pyramid level is\n                  the one that corresponds to the input image point (point(r,c)*get_step_size(octave)).\n                - The laplacian is the trace of the Hessian at the given point.  So this \n                  function returns either +1 or -1 depending on this number's sign.  This\n                  value can be used to distinguish bright blobs on dark backgrounds from\n                  the reverse.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct interest_point\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object contains the interest points found using the \n                hessian_pyramid object.  Its fields have the following\n                meanings:\n                    - center == the x/y location of the center of the interest point\n                      (in image space coordinates.  y gives the row and x gives the\n                      column in the image)\n                    - scale == the scale at which the point was detected.  This is a number\n                      >= 1.  If it is 1 then it means the interest point was detected at\n                      the lowest scale in the image pyramid.  Larger numbers indicate that\n                      the interest point is from high up in the image pyramid.  For\n                      example, a scale of 4 would mean the interest point was located at a\n                      point in the pyramid where the image had been shrunk by a factor of 4.\n                    - score == the determinant of the Hessian for the interest point\n                    - laplacian == the sign of the laplacian for the interest point\n        !*/\n\n        interest_point() : scale(0), score(0), laplacian(0) {}\n\n        dlib::vector<double,2> center;\n        double scale;\n        double score;\n        double laplacian;\n\n        bool operator < (const interest_point& p) const { return score < p.score; }\n        /*!\n            This function is here so you can sort interest points according to \n            their scores\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const interest_point& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        interest_point& item,\n        std::istream& in \n    );\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename Alloc>\n    void get_interest_points (\n        const hessian_pyramid& pyr,\n        double threshold,\n        std::vector<interest_point,Alloc>& result_points\n    )\n    /*!\n        requires\n            - threshold >= 0\n        ensures\n            - extracts interest points from the pyramid pyr and stores them into\n              result_points (note that result_points is cleared before these new interest\n              points are added to it).\n            - Only interest points with determinant values in the pyramid larger than\n              threshold are output.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif  // DLIB_HESSIAN_PYRAMId_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/hog.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HoG_Hh_\n#define DLIB_HoG_Hh_\n\n#include \"hog_abstract.h\"\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include <cmath>\n\nnamespace dlib\n{\n    enum \n    {\n        hog_no_interpolation,\n        hog_angle_interpolation,\n        hog_full_interpolation,\n        hog_signed_gradient,\n        hog_unsigned_gradient\n    };\n\n    template <\n        unsigned long cell_size_,\n        unsigned long block_size_,\n        unsigned long cell_stride_,\n        unsigned long num_orientation_bins_,\n        int           gradient_type_,\n        int           interpolation_type_\n        >\n    class hog_image : noncopyable\n    {\n        COMPILE_TIME_ASSERT(cell_size_ > 1);\n        COMPILE_TIME_ASSERT(block_size_ > 0);\n        COMPILE_TIME_ASSERT(cell_stride_ > 0);\n        COMPILE_TIME_ASSERT(num_orientation_bins_ > 0);\n\n        COMPILE_TIME_ASSERT( gradient_type_ == hog_signed_gradient ||\n                             gradient_type_ == hog_unsigned_gradient);\n\n        COMPILE_TIME_ASSERT( interpolation_type_ == hog_no_interpolation ||\n                             interpolation_type_ == hog_angle_interpolation ||\n                             interpolation_type_ == hog_full_interpolation );\n\n\n    public:\n\n        const static unsigned long cell_size = cell_size_;\n        const static unsigned long block_size = block_size_;\n        const static unsigned long cell_stride = cell_stride_;\n        const static unsigned long num_orientation_bins = num_orientation_bins_;\n        const static int           gradient_type = gradient_type_;\n        const static int           interpolation_type = interpolation_type_;\n\n        const static long min_size = cell_size*block_size+2;\n\n        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;\n\n        hog_image (\n        ) : \n            num_block_rows(0),\n            num_block_cols(0)\n        {}\n\n        void clear (\n        )\n        {\n            num_block_rows = 0;\n            num_block_cols = 0;\n            hist_cells.clear();\n        }\n\n        void copy_configuration (\n            const hog_image&\n        ){}\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        )\n        {\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );\n            load_impl(mat(img));\n        }\n\n        inline void unload(\n        ) { clear(); }\n\n        inline size_t size (\n        ) const { return static_cast<size_t>(nr()*nc()); }\n\n        inline long nr (\n        ) const { return num_block_rows; }\n\n        inline long nc (\n        ) const { return num_block_cols; }\n\n        long get_num_dimensions (\n        ) const\n        {\n            return block_size*block_size*num_orientation_bins;\n        }\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( 0 <= row && row < nr() &&\n                         0 <= col && col < nc(),\n                \"\\t descriptor_type hog_image::operator()()\"\n                << \"\\n\\t invalid row or col argument\"\n                << \"\\n\\t row:  \" << row\n                << \"\\n\\t col:  \" << col \n                << \"\\n\\t nr(): \" << nr() \n                << \"\\n\\t nc(): \" << nc() \n                << \"\\n\\t this: \" << this\n                );\n\n            row *= cell_stride;\n            col *= cell_stride;\n            ++row;\n            ++col;\n\n            int feat = 0;\n            for (unsigned long r = 0; r < block_size; ++r)\n            {\n                for (unsigned long c = 0; c < block_size; ++c)\n                {\n                    for (unsigned long i = 0; i < num_orientation_bins; ++i)\n                    {\n                        des(feat++) = hist_cells[row+r][col+c].values[i];\n                    }\n                }\n            }\n\n            des /= length(des) + 1e-8;\n\n            return des;\n        }\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const\n        {\n            row *= cell_stride;\n            col *= cell_stride;\n\n            row *= cell_size;\n            col *= cell_size;\n\n            // do this to account for the 1 pixel padding we use all around the image\n            ++row;\n            ++col;\n\n            return rectangle(col, row, col+cell_size*block_size-1, row+cell_size*block_size-1);\n        }\n\n        const point image_to_feat_space (\n            const point& p\n        ) const\n        {\n\n            const long half_block = block_size/2;\n            if ((block_size%2) == 0)\n            {\n                return point(((p.x()-1)/(long)cell_size - half_block)/(long)cell_stride,\n                             ((p.y()-1)/(long)cell_size - half_block)/(long)cell_stride);\n            }\n            else\n            {\n                return point(((p.x()-1-(long)cell_size/2)/(long)cell_size - half_block)/(long)cell_stride,\n                             ((p.y()-1-(long)cell_size/2)/(long)cell_size - half_block)/(long)cell_stride);\n            }\n        }\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n        }\n\n        const point feat_to_image_space (\n            const point& p\n        ) const\n        {\n            const long half_block = block_size/2;\n            if ((block_size%2) == 0)\n            {\n                return point((p.x()*cell_stride + half_block)*cell_size + 1,\n                             (p.y()*cell_stride + half_block)*cell_size + 1);\n            }\n            else\n            {\n                return point((p.x()*cell_stride + half_block)*cell_size + 1 + cell_size/2,\n                             (p.y()*cell_stride + half_block)*cell_size + 1 + cell_size/2);\n            }\n        }\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n        }\n\n\n\n        // these _PRIVATE_ functions are only here as a workaround for a bug in visual studio 2005.  \n        void _PRIVATE_serialize (std::ostream& out) const\n        {\n            // serialize hist_cells\n            serialize(hist_cells.nc(),out);\n            serialize(hist_cells.nr(),out);\n            hist_cells.reset();\n            while (hist_cells.move_next())\n                serialize(hist_cells.element().values,out);\n            hist_cells.reset();\n\n\n            serialize(num_block_rows, out);\n            serialize(num_block_cols, out);\n        }\n\n        void _PRIVATE_deserialize (std::istream& in )\n        {\n            // deserialize item.hist_cells\n            long nc, nr;\n            deserialize(nc,in);\n            deserialize(nr,in);\n            hist_cells.set_size(nr,nc);\n            while (hist_cells.move_next())\n                deserialize(hist_cells.element().values,in); \n            hist_cells.reset();\n\n\n            deserialize(num_block_rows, in);\n            deserialize(num_block_cols, in);\n        }\n\n    private:\n\n        template <\n            typename image_type\n            >\n        void load_impl (\n            const image_type& img\n        )\n        {\n            // Note that we keep a border of 1 pixel all around the image so that we don't have\n            // to worry about running outside the image when computing the horizontal and vertical \n            // gradients.\n\n            // Note also that we have a border of unused cells around the hist_cells array so that we\n            // don't have to worry about edge effects when doing the interpolation in the main loop\n            // below.\n\n\n            // check if the window is just too small\n            if (img.nr() < min_size || img.nc() < min_size)\n            {\n                // If the image is smaller than our windows then there aren't any descriptors at all!\n                num_block_rows = 0;\n                num_block_cols = 0;\n                return;\n            }\n\n            // Make sure we have the right number of cell histograms and that they are\n            // all set to zero.\n            hist_cells.set_size((img.nr()-2)/cell_size+2, (img.nc()-2)/cell_size+2);\n            for (long r = 0; r < hist_cells.nr(); ++r)\n            {\n                for (long c = 0; c < hist_cells.nc(); ++c)\n                {\n                    hist_cells[r][c].zero();\n                }\n            }\n\n\n            // loop over all the histogram cells and fill them out\n            for (long rh = 1; rh < hist_cells.nr()-1; ++rh)\n            {\n                for (long ch = 1; ch < hist_cells.nc()-1; ++ch)\n                {\n                    // Fill out the current histogram cell.\n                    // First, figure out the row and column offsets into the image for the current histogram cell.\n                    const long roff = (rh-1)*cell_size + 1;\n                    const long coff = (ch-1)*cell_size + 1;\n\n                    for (long r = 0; r < (long)cell_size; ++r)\n                    {\n                        for (long c = 0; c < (long)cell_size; ++c)\n                        {\n                            unsigned long left; \n                            unsigned long right;\n                            unsigned long top;   \n                            unsigned long bottom; \n\n                            assign_pixel(left,   img(r+roff,c+coff-1));\n                            assign_pixel(right,  img(r+roff,c+coff+1));\n                            assign_pixel(top,    img(r+roff-1,c+coff));\n                            assign_pixel(bottom, img(r+roff+1,c+coff));\n\n                            double grad_x = (long)right-(long)left;\n                            double grad_y = (long)top-(long)bottom;\n\n                            // obtain the angle of the gradient.  Make sure it is scaled between 0 and 1.\n                            double angle = std::max(0.0, std::atan2(grad_y, grad_x)/pi + 1)/2;\n\n\n                            if (gradient_type == hog_unsigned_gradient)\n                            {\n                                angle *= 2;\n                                if (angle >= 1)\n                                    angle -= 1;\n                            }\n\n\n                            // now scale angle to between 0 and num_orientation_bins\n                            angle *= num_orientation_bins;\n\n\n                            const double strength = std::sqrt(grad_y*grad_y + grad_x*grad_x);\n\n\n                            if (interpolation_type == hog_no_interpolation)\n                            {\n                                // no interpolation\n                                hist_cells[rh][ch].values[round_to_int(angle)%num_orientation_bins] += strength;\n                            }\n                            else  // if we should do some interpolation\n                            {\n                                unsigned long quantized_angle_lower = static_cast<unsigned long>(std::floor(angle));\n                                unsigned long quantized_angle_upper = static_cast<unsigned long>(std::ceil(angle));\n\n                                quantized_angle_lower %= num_orientation_bins;\n                                quantized_angle_upper %= num_orientation_bins;\n\n                                const double angle_split = (angle-std::floor(angle));\n                                const double upper_strength = angle_split*strength;\n                                const double lower_strength = (1-angle_split)*strength;\n\n                                if (interpolation_type == hog_angle_interpolation)\n                                {\n                                    // Stick into gradient histogram.  Note that we linearly interpolate between neighboring\n                                    // histogram buckets.\n                                    hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength;\n                                    hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength;\n                                }\n                                else // here we do hog_full_interpolation\n                                {\n                                    const double center_r = (cell_size-1)/2.0;\n                                    const double center_c = (cell_size-1)/2.0;\n\n                                    const double lin_neighbor_r = std::abs(center_r - r)/cell_size;\n                                    const double lin_main_r = 1-lin_neighbor_r;\n\n                                    const double lin_neighbor_c = std::abs(center_c - c)/cell_size;\n                                    const double lin_main_c = 1-lin_neighbor_c;\n\n                                    // Which neighboring cells we interpolate into depends on which\n                                    // corner of our main cell we are nearest.\n                                    if (r < center_r)\n                                    {\n                                        if (c < center_c)\n                                        {\n                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;\n                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;\n\n                                            hist_cells[rh-1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;\n                                            hist_cells[rh-1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;\n\n                                            hist_cells[rh][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;\n                                            hist_cells[rh][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;\n\n                                            hist_cells[rh-1][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;\n                                            hist_cells[rh-1][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;\n                                        }\n                                        else\n                                        {\n                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;\n                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;\n\n                                            hist_cells[rh-1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;\n                                            hist_cells[rh-1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;\n\n                                            hist_cells[rh][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;\n                                            hist_cells[rh][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;\n\n                                            hist_cells[rh-1][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;\n                                            hist_cells[rh-1][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;\n                                        }\n                                    }\n                                    else \n                                    {\n                                        if (c < center_c)\n                                        {\n                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;\n                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;\n\n                                            hist_cells[rh+1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;\n                                            hist_cells[rh+1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;\n\n                                            hist_cells[rh][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;\n                                            hist_cells[rh][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;\n\n                                            hist_cells[rh+1][ch-1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;\n                                            hist_cells[rh+1][ch-1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;\n                                        }\n                                        else\n                                        {\n                                            hist_cells[rh][ch].values[quantized_angle_upper] += upper_strength   * lin_main_r*lin_main_c;\n                                            hist_cells[rh][ch].values[quantized_angle_lower] += lower_strength   * lin_main_r*lin_main_c;\n\n                                            hist_cells[rh+1][ch].values[quantized_angle_upper] += upper_strength * lin_neighbor_r*lin_main_c;\n                                            hist_cells[rh+1][ch].values[quantized_angle_lower] += lower_strength * lin_neighbor_r*lin_main_c;\n\n                                            hist_cells[rh][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_main_r;\n                                            hist_cells[rh][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_main_r;\n\n                                            hist_cells[rh+1][ch+1].values[quantized_angle_upper] += upper_strength * lin_neighbor_c*lin_neighbor_r;\n                                            hist_cells[rh+1][ch+1].values[quantized_angle_lower] += lower_strength * lin_neighbor_c*lin_neighbor_r;\n                                        }\n                                    }\n                                }\n                            }\n\n\n                        }\n                    }\n                }\n            }\n\n\n            // Now figure out how many blocks we should have.  Note again that the hist_cells has a border of \n            // unused cells (thats where that -2 comes from).\n            num_block_rows = (hist_cells.nr()-2 - (block_size-1) + cell_stride - 1)/cell_stride; \n            num_block_cols = (hist_cells.nc()-2 - (block_size-1) + cell_stride - 1)/cell_stride; \n\n        }\n\n        unsigned long round_to_int(\n            double val\n        ) const\n        {\n            return static_cast<unsigned long>(std::floor(val + 0.5));\n        }\n\n        struct histogram\n        {\n            void zero()\n            {\n                for (unsigned long i = 0; i < num_orientation_bins; ++i)\n                    values[i] = 0;\n            }\n            double values[num_orientation_bins];\n        };\n\n        array2d<histogram> hist_cells;\n\n        mutable descriptor_type des;\n\n        long num_block_rows;\n        long num_block_cols;\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned long T4,\n        int           T5,\n        int           T6 \n        >\n    void serialize (\n        const hog_image<T1,T2,T3,T4,T5,T6>& item,\n        std::ostream& out\n    )\n    {\n        item._PRIVATE_serialize(out);\n    }\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned long T4,\n        int           T5,\n        int           T6 \n        >\n    void deserialize (\n        hog_image<T1,T2,T3,T4,T5,T6>& item,\n        std::istream& in \n    )\n    {\n        item._PRIVATE_deserialize(in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HoG_Hh_\n\n"
  },
  {
    "path": "dlib/image_keypoint/hog_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HoG_ABSTRACT_Hh_\n#ifdef DLIB_HoG_ABSTRACT_Hh_\n\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include <cmath>\n\nnamespace dlib\n{\n    enum \n    {\n        hog_no_interpolation,\n        hog_angle_interpolation,\n        hog_full_interpolation,\n        hog_signed_gradient,\n        hog_unsigned_gradient\n    };\n\n    template <\n        unsigned long cell_size_,\n        unsigned long block_size_,\n        unsigned long cell_stride_,\n        unsigned long num_orientation_bins_,\n        int           gradient_type_,\n        int           interpolation_type_\n        >\n    class hog_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE PARAMETERS \n                - cell_size_ > 1\n                - block_size_ > 0\n                - cell_stride_ > 0\n                - num_orientation_bins_ > 0\n                - gradient_type_ == hog_signed_gradient or hog_unsigned_gradient\n                - interpolation_type_ == hog_no_interpolation, hog_angle_interpolation, or \n                                         hog_full_interpolation\n\n            INITIAL VALUE\n                 - size() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing the image feature extraction algorithm\n                described in the following paper:\n                    Histograms of Oriented Gradients for Human Detection\n                    by Navneet Dalal and Bill Triggs\n\n                \n                To summarize the technique, this object tiles non-overlapping cells over an \n                image.  Each of these cells is a box that is cell_size by cell_size pixels \n                in size.  Each cell contains an array of size num_orientation_bins.  The array \n                in a cell is used to store a histogram of all the edge orientations contained\n                within the cell's image region.  \n\n                Once the grid of cells and their histograms has been computed (via load())\n                you can obtain descriptors for each \"block\" in the image.  A block is just a\n                group of cells and blocks are allowed to overlap.  Each block is square and\n                made up of block_size*block_size cells.  So when you call operator()(r,c)\n                what you obtain is a vector that is just a bunch of cell histograms that\n                have been concatenated (and length normalized).\n\n                The template arguments control the various parameters of this algorithm.\n\n                The interpolation_type parameter controls the amount of interpolation\n                that happens during the creation of the edge orientation histograms.  It\n                varies from no interpolation at all to full spatial and angle interpolation.\n                \n                Angle interpolation means that an edge doesn't just go into its nearest \n                histogram bin but instead gets interpolated into its two nearest neighbors.\n                Similarly, spatial interpolation means that an edge doesn't just go into\n                the cell it is in but it also contributes to nearby cells depending on how\n                close they are.  \n\n                The gradient_type parameter controls how edge orientations are measured.  \n                Consider the following ASCII art:\n                    signed gradients:           unsigned gradients:\n                           /\\                           |\n                           ||                           |\n                       <---  ---->                ------+------\n                           ||                           |\n                           \\/                           |\n\n                An image is full of gradients caused by edges between objects.  The direction \n                of a gradient is determined by which end of it has pixels of highest intensity.  \n                So for example, suppose you had a picture containing black and white stripes.  \n                Then the magnitude of the gradient at each point in the image tells you if you \n                are on the edge of a stripe and the gradient's orientation tells you which \n                direction you have to move get into the white stripe.   \n\n                Signed gradients preserve this direction information while unsigned gradients\n                do not.  An unsigned gradient will only tell you the orientation of the stripe\n                but not which direction leads to the white stripe.   \n\n                Finally, the cell_stride parameter controls how much overlap you get between\n                blocks.  The maximum amount of overlap is obtained when cell_stride == 1.\n                At the other extreme, you would have no overlap if cell_stride == block_size. \n\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a hog_image object to many other threads.  \n                In this case, it is safe to copy the configuration of a shared object so long\n                as no other operations are performed on it.\n        !*/\n\n    public:\n\n        const static unsigned long cell_size = cell_size_;\n        const static unsigned long block_size = block_size_;\n        const static unsigned long cell_stride = cell_stride_;\n        const static unsigned long num_orientation_bins = num_orientation_bins_;\n        const static int           gradient_type = gradient_type_;\n        const static int           interpolation_type = interpolation_type_;\n\n        const static long min_size = cell_size*block_size+2;\n\n        typedef matrix<double, block_size*block_size*num_orientation_bins, 1> descriptor_type;\n\n        hog_image (\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void copy_configuration (\n            const hog_image& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two hog_image \n                  objects H1 and H2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type is a dlib::matrix or something convertible to a matrix\n                  via mat().\n                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            ensures\n                - if (img.nr() < min_size || img.nc() < min_size) then\n                    - the image is too small so we don't compute anything on it\n                    - #size() == 0\n                - else\n                    - generates a HOG image from the given image.   \n                    - #size() > 0\n        !*/\n\n        inline void unload (\n        );\n        /*!\n            ensures\n                - #nr() == 0\n                - #nc() == 0\n                - clears only the state information which is populated by load().  For \n                  example, let H be a hog_image object.  Then consider the two sequences \n                  of instructions:\n                    Sequence 1:\n                        H.load(img);      \n                        H.unload();\n                        H.load(img);\n\n                    Sequence 2:\n                        H.load(img);\n                  Both sequence 1 and sequence 2 should have the same effect on H.  \n        !*/\n\n        inline size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns nr()*nc()\n        !*/\n\n        inline long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this HOG image\n        !*/\n\n        inline long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this HOG image\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the number of dimensions in the feature vectors generated by\n                  this object.  \n                - In particular, returns the value block_size*block_size*num_orientation_bins\n        !*/\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n            ensures\n                - returns the descriptor for the HOG block at the given row and column.  This descriptor \n                  will include information from a window that is located at get_block_rect(row,col) in\n                  the original image given to load().\n                - The returned descriptor vector will have get_num_dimensions() elements.\n        !*/\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns a rectangle that tells you what part of the original image is associated\n                  with a particular HOG block.  That is, what part of the input image is associated\n                  with (*this)(row,col).\n                - The returned rectangle will be cell_size*block_size pixels wide and tall.\n        !*/\n\n        const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned long T4,\n        int           T5,\n        int           T6 \n        >\n    void serialize (\n        const hog_image<T1,T2,T3,T4,T5,T6>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        unsigned long T1,\n        unsigned long T2,\n        unsigned long T3,\n        unsigned long T4,\n        int           T5,\n        int           T6 \n        >\n    void deserialize (\n        hog_image<T1,T2,T3,T4,T5,T6>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_HoG_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/nearest_neighbor_feature_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_\n#define DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_\n\n#include \"nearest_neighbor_feature_image_abstract.h\"\n#include <vector>\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../statistics.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class nearest_neighbor_feature_image : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                - nn_feats.size() == 1\n\n            CONVENTION\n                - nn_feats.size() == 1\n\n        !*/\n\n    public:\n\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        nearest_neighbor_feature_image (\n        ); \n\n        void clear (\n        );\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n\n        void copy_configuration (\n            const nearest_neighbor_feature_image& item\n        );\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n\n        inline size_t size (\n        ) const;\n\n        inline long nr (\n        ) const;\n\n        inline long nc (\n        ) const;\n\n        inline long get_num_dimensions (\n        ) const;\n\n        template <typename vector_type>\n        void set_basis (\n            const vector_type& new_basis\n        );\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n\n        inline const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n\n        inline const point image_to_feat_space (\n            const point& p\n        ) const;\n\n        inline const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n\n        inline const point feat_to_image_space (\n            const point& p\n        ) const;\n\n        inline const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n\n        template <typename T>\n        friend void serialize (\n            const nearest_neighbor_feature_image<T>& item,\n            std::ostream& out\n        );\n\n        template <typename T>\n        friend void deserialize (\n            nearest_neighbor_feature_image<T>& item,\n            std::istream& in \n        );\n\n    private:\n\n        array2d<unsigned long> feats;\n        feature_extractor fe;\n        std::vector<typename feature_extractor::descriptor_type> basis;\n\n        // This is a transient variable.  It is just here so it doesn't have to be\n        // reallocated over and over inside operator()\n        mutable descriptor_type nn_feats;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const nearest_neighbor_feature_image<T>& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.feats, out);\n        serialize(item.fe, out);\n        serialize(item.basis, out);\n    }\n\n    template <typename T>\n    void deserialize (\n        nearest_neighbor_feature_image<T>& item,\n        std::istream& in \n    )\n    {\n        deserialize(item.feats, in);\n        deserialize(item.fe, in);\n        deserialize(item.basis, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                        nearest_neighbor_feature_image member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    nearest_neighbor_feature_image<feature_extractor>::\n    nearest_neighbor_feature_image (\n    )  \n    {\n        nn_feats.resize(1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    void nearest_neighbor_feature_image<feature_extractor>::\n    clear (\n    )\n    {\n        feats.clear();\n        fe.clear();\n        basis.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    void nearest_neighbor_feature_image<feature_extractor>::\n    copy_configuration (\n        const feature_extractor& item\n    )\n    {\n        fe.copy_configuration(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    void nearest_neighbor_feature_image<feature_extractor>::\n    copy_configuration (\n        const nearest_neighbor_feature_image& item\n    )\n    {\n        fe.copy_configuration(item.fe);\n        basis = item.basis;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    template <\n        typename image_type\n        >\n    void nearest_neighbor_feature_image<feature_extractor>::\n    load (\n        const image_type& img\n    )\n    {\n        fe.load(img);\n\n        feats.set_size(fe.nr(), fe.nc());\n\n        // find the nearest neighbor for each feature vector and store the\n        // result in feats.\n        for (long r = 0; r < feats.nr(); ++r)\n        {\n            for (long c = 0; c < feats.nc(); ++c)\n            {\n                const typename feature_extractor::descriptor_type& local_feat = fe(r,c);\n\n                double best_dist = std::numeric_limits<double>::infinity();\n                unsigned long best_idx = 0;\n                for (unsigned long i = 0; i < basis.size(); ++i)\n                {\n                    double dist = length_squared(local_feat - basis[i]);\n                    if (dist < best_dist)\n                    {\n                        best_dist = dist;\n                        best_idx = i;\n                    }\n                }\n\n                feats[r][c] = best_idx;\n            }\n        }\n\n        fe.unload();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    size_t nearest_neighbor_feature_image<feature_extractor>::\n    size (\n    ) const\n    {\n        return feats.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    long nearest_neighbor_feature_image<feature_extractor>::\n    nr (\n    ) const\n    {\n        return feats.nr();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    long nearest_neighbor_feature_image<feature_extractor>::\n    nc (\n    ) const\n    {\n        return feats.nc();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    long nearest_neighbor_feature_image<feature_extractor>::\n    get_num_dimensions (\n    ) const\n    {\n        return basis.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename feature_extractor>\n    template <typename vector_type>\n    void nearest_neighbor_feature_image<feature_extractor>::\n    set_basis (\n        const vector_type& new_basis\n    )\n    {\n        basis.assign(new_basis.begin(), new_basis.end());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const typename nearest_neighbor_feature_image<feature_extractor>::descriptor_type& \n    nearest_neighbor_feature_image<feature_extractor>::\n    operator() (\n        long row,\n        long col\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 <= row && row < nr() &&\n                    0 <= col && col < nc(),\n            \"\\t descriptor_type nearest_neighbor_feature_image::operator(row,col)\"\n            << \"\\n\\t Invalid inputs were given to this function\"\n            << \"\\n\\t row:  \" << row\n            << \"\\n\\t col:  \" << col \n            << \"\\n\\t nr(): \" << nr()\n            << \"\\n\\t nc(): \" << nc()\n            << \"\\n\\t this: \" << this\n            );\n\n        nn_feats[0] = std::make_pair(feats[row][col],1);\n        return nn_feats;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const rectangle nearest_neighbor_feature_image<feature_extractor>::\n    get_block_rect (\n        long row,\n        long col\n    ) const\n    {\n        return fe.get_block_rect(row,col);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const point nearest_neighbor_feature_image<feature_extractor>::\n    image_to_feat_space (\n        const point& p\n    ) const\n    {\n        return fe.image_to_feat_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const rectangle nearest_neighbor_feature_image<feature_extractor>::\n    image_to_feat_space (\n        const rectangle& rect\n    ) const\n    {\n        return fe.image_to_feat_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const point nearest_neighbor_feature_image<feature_extractor>::\n    feat_to_image_space (\n        const point& p\n    ) const\n    {\n        return fe.feat_to_image_space(p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    const rectangle nearest_neighbor_feature_image<feature_extractor>::\n    feat_to_image_space (\n        const rectangle& rect\n    ) const \n    {\n        return fe.feat_to_image_space(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_\n#ifdef DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    class nearest_neighbor_feature_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor \n                - must be an object with an interface compatible with dlib::hog_image\n\n            INITIAL VALUE\n                 - size() == 0\n                 - get_num_dimensions() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing image feature extraction.  In\n                particular, it wraps another image feature extractor and converts\n                the wrapped image feature vectors into sparse indicator vectors.  It does\n                this by finding the nearest neighbor for each feature vector and returning an\n                indicator vector that is zero everywhere except for the position indicated by \n                the nearest neighbor.  \n\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a nearest_neighbor_feature_image object to many other \n                threads.  In this case, it is safe to copy the configuration of a shared object so \n                long as no other operations are performed on it.\n\n\n            NOTATION \n                let BASE_FE denote the base feature_extractor object contained inside \n                the nearest_neighbor_feature_image.\n        !*/\n\n    public:\n\n        typedef std::vector<std::pair<unsigned int,double> > descriptor_type;\n\n        nearest_neighbor_feature_image (\n        ); \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n        /*!\n            ensures\n                - performs BASE_FE.copy_configuration(item)\n        !*/\n\n        void copy_configuration (\n            const nearest_neighbor_feature_image& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two \n                  nearest_neighbor_feature_image objects H1 and H2, the following sequence \n                  of instructions should always result in both of them having the exact \n                  same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == any type that can be supplied to feature_extractor::load() \n            ensures\n                - performs BASE_FE.load(img)\n                  i.e. does feature extraction.  The features can be accessed using\n                  operator() as defined below.\n        !*/\n\n        inline size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.size() \n        !*/\n\n        inline long nr (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nr() \n        !*/\n\n        inline long nc (\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.nc() \n        !*/\n\n        inline long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the feature vectors returned by operator().  \n                  In this case, this is the number of basis elements.  That is, it is the number\n                  of vectors given to the set_basis() member function.\n        !*/\n\n        template <typename vector_type>\n        void set_basis (\n            const vector_type& new_basis\n        );\n        /*!\n            ensures\n                - #get_num_dimensions() == new_basis.size()\n                - The operator() member function defined below will use new_basis to \n                  determine nearest neighbors.\n        !*/\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n                - get_num_dimensions() > 0\n            ensures\n                - determines which basis element is nearest to BASE_FE(row,col) and returns a sparse\n                  indicator vector identifying the nearest neighbor. \n                - To be precise, this function returns a sparse vector V such that:\n                    - V.size() == 1 \n                    - V[0].first == The basis element index for the basis vector nearest to BASE_FE(row,col).\n                      \"nearness\" is determined using Euclidean distance.\n                    - V[0].second == 1 \n        !*/\n\n        inline const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.get_block_rect(row,col)\n                  I.e. returns a rectangle that tells you what part of the original image is associated\n                  with a particular feature vector.\n        !*/\n\n        inline const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(p)\n                  I.e. Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        inline const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.image_to_feat_space(rect)\n                  I.e. returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        inline const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(p)\n                  I.e. returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        inline const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns BASE_FE.feat_to_image_space(rect)\n                  I.e. return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const nearest_neighbor_feature_image<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <typename T>\n    void deserialize (\n        nearest_neighbor_feature_image<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_NEAREST_NEIGHBOR_FeATURE_IMAGE_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/poly_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_POLY_ImAGE_Hh_\n#define DLIB_POLY_ImAGE_Hh_\n\n#include \"poly_image_abstract.h\"\n#include \"build_separable_poly_filters.h\"\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long Downsample\n        >\n    class poly_image : noncopyable\n    {\n        COMPILE_TIME_ASSERT(Downsample >= 1);\n    public:\n        const static long downsample = Downsample;\n        typedef matrix<double, 0, 1> descriptor_type;\n\n        poly_image(\n            long order_,\n            long window_size_,\n            bool normalization = true,\n            bool rotation_invariance_ = false\n        )\n        {\n            setup(order_, window_size_);\n            set_uses_normalization(normalization);\n            set_is_rotationally_invariant(rotation_invariance_);\n        }\n\n        poly_image (\n        ) \n        {\n            clear();\n        }\n\n        void clear (\n        )\n        {\n            normalize = true;\n            rotation_invariance = false;\n            poly_coef.clear();\n            order = 3;\n            window_size = 13;\n            border_size = (long)std::ceil(std::floor(window_size/2.0)/downsample);\n            num_rows = 0;\n            num_cols = 0;\n            filters = build_separable_poly_filters(order, window_size);\n        }\n\n        long get_order (\n        ) const\n        {\n            return order;\n        }\n\n        long get_window_size (\n        ) const\n        {\n            return window_size;\n        }\n\n        void setup (\n            long order_,\n            long window_size_\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(1 <= order_ && order_ <= 6 &&\n                        window_size_ >= 3 && (window_size_%2) == 1,\n                \"\\t descriptor_type poly_image::setup()\"\n                << \"\\n\\t Invalid arguments were given to this function.\"\n                << \"\\n\\t order_:       \" << order_ \n                << \"\\n\\t window_size_: \" << window_size_ \n                << \"\\n\\t this: \" << this\n                );\n\n\n            poly_coef.clear();\n            order = order_;\n            window_size = window_size_;\n            border_size = (long)std::ceil(std::floor(window_size/2.0)/downsample);\n            num_rows = 0;\n            num_cols = 0;\n            filters = build_separable_poly_filters(order, window_size);\n        }\n\n        bool uses_normalization (\n        ) const { return normalize; }\n\n        void set_uses_normalization (\n            bool normalization\n        )\n        {\n            normalize = normalization;\n        }\n\n        bool is_rotationally_invariant (\n        ) const { return rotation_invariance; }\n\n        void set_is_rotationally_invariant (\n            bool rotation_invariance_\n        )\n        {\n            rotation_invariance = rotation_invariance_;\n        }\n\n        void copy_configuration (\n            const poly_image& item\n        )\n        {\n            normalize = item.normalize;\n            rotation_invariance = item.rotation_invariance;\n            if (order != item.order || \n                window_size != item.window_size)\n            {\n                order = item.order;\n                window_size = item.window_size;\n                border_size = item.border_size;\n                filters = item.filters;\n            }\n        }\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        )\n        {\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );\n\n            poly_coef.resize(get_num_dimensions());\n            des.set_size(get_num_dimensions());\n\n\n            if (normalize)\n            {\n                array2d<float> coef0;\n                rectangle rect = filter_image(img, coef0, filters[0]);\n                num_rows = rect.height();\n                num_cols = rect.width();\n\n                for (unsigned long i = 1; i < filters.size(); ++i)\n                {\n                    filter_image(img, poly_coef[i-1], filters[i]);\n\n                    // intensity normalize everything\n                    for (long r = 0; r < coef0.nr(); ++r)\n                    {\n                        for (long c = 0; c < coef0.nc(); ++c)\n                        {\n                            if (coef0[r][c] >= 1)\n                                poly_coef[i-1][r][c] /= coef0[r][c];\n                            else\n                                poly_coef[i-1][r][c] = 0;\n                        }\n                    }\n                }\n\n                if (rotation_invariance)\n                    rotate_polys(rect);\n            }\n            else\n            {\n                rectangle rect;\n                for (unsigned long i = 0; i < filters.size(); ++i)\n                {\n                    rect = filter_image(img, poly_coef[i], filters[i]);\n                }\n                num_rows = rect.height();\n                num_cols = rect.width();\n\n                if (rotation_invariance)\n                    rotate_polys(rect);\n            }\n        }\n\n        void unload()\n        {\n            poly_coef.clear();\n            num_rows = 0;\n            num_cols = 0;\n        }\n\n        inline size_t size (\n        ) const { return static_cast<unsigned long>(nr()*nc()); }\n\n        inline long nr (\n        ) const { return num_rows; }\n\n        inline long nc (\n        ) const { return num_cols; }\n\n        long get_num_dimensions (\n        ) const\n        {\n            if (normalize)\n            {\n                // -1 because we discard the constant term of the polynomial.\n                return filters.size()-1;\n            }\n            else\n            {\n                return filters.size();\n            }\n        }\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT( 0 <= row && row < nr() &&\n                         0 <= col && col < nc(),\n                \"\\t descriptor_type poly_image::operator()()\"\n                << \"\\n\\t invalid row or col argument\"\n                << \"\\n\\t row:  \" << row\n                << \"\\n\\t col:  \" << col \n                << \"\\n\\t nr(): \" << nr() \n                << \"\\n\\t nc(): \" << nc() \n                << \"\\n\\t this: \" << this\n                );\n\n            // add because of the zero border around the poly_coef images\n            row += border_size;\n            col += border_size;\n\n            for (long i = 0; i < des.size(); ++i)\n                des(i) = poly_coef[i][row][col];\n\n            return des;\n        }\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const\n        {\n            return centered_rect(Downsample*point(col+border_size, row+border_size), \n                                 window_size, window_size);\n        }\n\n        const point image_to_feat_space (\n            const point& p\n        ) const\n        {\n            return p/Downsample - point(border_size, border_size);\n        }\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n        }\n\n        const point feat_to_image_space (\n            const point& p\n        ) const\n        {\n            return (p + point(border_size, border_size))*Downsample;\n        }\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const\n        {\n            return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n        }\n\n\n\n        friend void serialize (const poly_image& item, std::ostream& out) \n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.poly_coef, out);\n            serialize(item.order, out);\n            serialize(item.window_size, out);\n            serialize(item.border_size, out);\n            serialize(item.num_rows, out);\n            serialize(item.num_cols, out);\n            serialize(item.normalize, out);\n            serialize(item.rotation_invariance, out);\n            serialize(item.filters, out);\n        }\n\n        friend void deserialize (poly_image& item, std::istream& in )\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw dlib::serialization_error(\"Unexpected version found while deserializing dlib::poly_image\");\n\n            deserialize(item.poly_coef, in);\n            deserialize(item.order, in);\n            deserialize(item.window_size, in);\n            deserialize(item.border_size, in);\n            deserialize(item.num_rows, in);\n            deserialize(item.num_cols, in);\n            deserialize(item.normalize, in);\n            deserialize(item.rotation_invariance, in);\n            deserialize(item.filters, in);\n        }\n\n    private:\n\n        matrix<float,2,1> rotate_order_1 (\n            const matrix<float,2,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            matrix<double,2,2> M;\n            M = w1,  w2,\n                w2, -w1;\n\n            matrix<double,2,1> x;\n            x = cos_theta, \n                sin_theta;\n\n            return matrix_cast<float>(M*x);\n        }\n\n        matrix<float,3,1> rotate_order_2 (\n            const matrix<float,3,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            const double w3 = w(2);\n            matrix<double,3,3> M;\n            M = w1, w2,           w3,\n                w2, (2*w3-2*w1), -w2,\n                w3, -w2,          w1;\n\n            matrix<double,3,1> x;\n            x = std::pow(cos_theta,2.0), \n                cos_theta*sin_theta,\n                std::pow(sin_theta,2.0);\n\n            return matrix_cast<float>(M*x);\n        }\n\n        matrix<float,4,1> rotate_order_3 (\n            const matrix<float,4,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            const double w3 = w(2);\n            const double w4 = w(3);\n            matrix<double,4,4> M;\n            M = w1, w2,            w3,           w4,\n                w2, (2*w3-3*w1), (3*w4-2*w2),   -w3,\n                w3, (3*w4-2*w2), (3*w1-2*w3),    w2,\n                w4, -w3,           w2,          -w1;\n\n            matrix<double,4,1> x;\n            x = std::pow(cos_theta,3.0), \n                std::pow(cos_theta,2.0)*sin_theta,\n                cos_theta*std::pow(sin_theta,2.0),\n                std::pow(sin_theta,3.0);\n\n            return matrix_cast<float>(M*x);\n        }\n\n        matrix<float,5,1> rotate_order_4 (\n            const matrix<float,5,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            const double w3 = w(2);\n            const double w4 = w(3);\n            const double w5 = w(4);\n            matrix<double,5,5> M;\n            M = w1, w2,              w3,            w4,          w5,\n                w2, (2*w3-4*w1), (3*w4-3*w2),      (4*w5-2*w3), -w4,\n                w3, (3*w4-3*w2), (6*w1-4*w3+6*w5), (3*w2-3*w4),  w3,\n                w4, (4*w5-2*w3), (3*w2-3*w4),      (2*w3-4*w1), -w2,\n                w5, -w4,            w3,            -w2,          w1;\n\n            matrix<double,5,1> x;\n            x = std::pow(cos_theta,4.0), \n                std::pow(cos_theta,3.0)*sin_theta,\n                std::pow(cos_theta,2.0)*std::pow(sin_theta,2.0),\n                cos_theta*std::pow(sin_theta,3.0),\n                std::pow(sin_theta,4.0);\n\n            return matrix_cast<float>(M*x);\n        }\n\n        matrix<float,6,1> rotate_order_5 (\n            const matrix<float,6,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            const double w3 = w(2);\n            const double w4 = w(3);\n            const double w5 = w(4);\n            const double w6 = w(5);\n            matrix<double,6,6> M;\n            M = w1,     w2,          w3,             w4,                 w5,          w6,\n                w2, (2*w3-5*w1), (3*w4-4*w2),       (4*w5-3*w3),        (5*w6-2*w4), -w5,\n                w3, (3*w4-4*w2), (10*w1-6*w3+6*w5), (6*w2-6*w4+10*w6),  (3*w3-4*w5),  w4,\n                w4, (4*w5-3*w3), (6*w2-6*w4+10*w6), (-10*w1+6*w3-6*w5), (3*w4-4*w2), -w3,\n                w5, (5*w6-2*w4), (3*w3-4*w5),       (3*w4-4*w2),        (5*w1-2*w3),  w2,\n                w6,    -w5,          w4,            -w3,                 w2,         -w1;\n\n            matrix<double,6,1> x;\n            x = std::pow(cos_theta,5.0), \n                std::pow(cos_theta,4.0)*sin_theta,\n                std::pow(cos_theta,3.0)*std::pow(sin_theta,2.0),\n                std::pow(cos_theta,2.0)*std::pow(sin_theta,3.0),\n                cos_theta*std::pow(sin_theta,4.0),\n                std::pow(sin_theta,5.0);\n\n            return matrix_cast<float>(M*x);\n        }\n\n        matrix<float,7,1> rotate_order_6 (\n            const matrix<float,7,1>& w,\n            double cos_theta,\n            double sin_theta\n        ) const\n        {\n            const double w1 = w(0);\n            const double w2 = w(1);\n            const double w3 = w(2);\n            const double w4 = w(3);\n            const double w5 = w(4);\n            const double w6 = w(5);\n            const double w7 = w(6);\n            matrix<double,7,7> M;\n            M = w1,     w2,          w3,              w4,                           w5,                 w6,         w7,\n                w2, (2*w3-6*w1), (3*w4-5*w2),        (4*w5-4*w3),                (5*w6-3*w4),         (6*w7-2*w5), -w6,\n                w3, (3*w4-5*w2), (15*w1-8*w3+ 6*w5), ( 10*w2 -9*w4+10*w6),       (  6*w3-8*w5+15*w7), (3*w4-5*w6),  w5,\n                w4, (4*w5-4*w3), (10*w2-9*w4+10*w6), (-20*w1+12*w3-12*w5+20*w7), (-10*w2+9*w4-10*w6), (4*w5-4*w3), -w4,\n                w5, (5*w6-3*w4), ( 6*w3-8*w5+15*w7), (-10*w2 +9*w4-10*w6),       ( 15*w1-8*w3 +6*w5), (5*w2-3*w4),  w3,\n                w6, (6*w7-2*w5), (3*w4-5*w6),        (4*w5-4*w3),                (5*w2-3*w4),         (2*w3-6*w1), -w2,\n                w7,     -w6,          w5,            -w4,                          w3,                 -w2,         w1;\n\n            matrix<double,7,1> x;\n            x = std::pow(cos_theta,6.0), \n                std::pow(cos_theta,5.0)*sin_theta,\n                std::pow(cos_theta,4.0)*std::pow(sin_theta,2.0),\n                std::pow(cos_theta,3.0)*std::pow(sin_theta,3.0),\n                std::pow(cos_theta,2.0)*std::pow(sin_theta,4.0),\n                cos_theta*std::pow(sin_theta,5.0),\n                std::pow(sin_theta,6.0);\n\n            return matrix_cast<float>(M*x);\n        }\n\n        void rotate_polys (\n            const rectangle& rect\n        )\n        /*!\n            ensures\n                - rotates all the polynomials in poly_coef so that they are\n                  rotationally invariant\n        !*/\n        {\n            // The idea here is to use a rotation matrix to rotate the \n            // coordinate system for the polynomial so that the x axis\n            // always lines up with the gradient vector (or direction of\n            // max curvature).  This way we can make the representation \n            // rotation invariant.\n\n            // Note that the rotation matrix is given by:\n            // [ cos_theta -sin_theta ]\n            // [ sin_theta cos_theta  ]\n\n            // need to offset poly_coef to get past the constant term if there isn't any normalization.\n            const int off = (normalize) ? 0 : 1;\n\n            for (long r = rect.top(); r <= rect.bottom(); ++r)\n            {\n                for (long c = rect.left(); c <= rect.right(); ++c)\n                {\n                    dlib::vector<double,2> g(poly_coef[off+0][r][c],\n                                             poly_coef[off+1][r][c]);\n\n                    const double len = g.length();\n                    if (len != 0)\n                    {\n                        g /= len;\n                    }\n                    else\n                    {\n                        g.x() = 1;\n                        g.y() = 0;\n                    }\n                    // since we normalized g we can find the sin/cos of its angle easily. \n                    const double cos_theta = g.x();\n                    const double sin_theta = g.y();\n\n                    if (order >= 1)\n                    {\n                        matrix<float,2,1> w;\n                        w = poly_coef[off+0][r][c],\n                            poly_coef[off+1][r][c];\n                        w = rotate_order_1(w, cos_theta, sin_theta);\n                        poly_coef[off+0][r][c] = w(0);\n                        poly_coef[off+1][r][c] = w(1);\n                    }\n                    if (order >= 2)\n                    {\n                        matrix<float,3,1> w;\n                        w = poly_coef[off+2][r][c],\n                            poly_coef[off+3][r][c],\n                            poly_coef[off+4][r][c];\n                        w = rotate_order_2(w, cos_theta, sin_theta);\n                        poly_coef[off+2][r][c] = w(0);\n                        poly_coef[off+3][r][c] = w(1);\n                        poly_coef[off+4][r][c] = w(2);\n                    }\n                    if (order >= 3)\n                    {\n                        matrix<float,4,1> w;\n                        w = poly_coef[off+5][r][c],\n                            poly_coef[off+6][r][c],\n                            poly_coef[off+7][r][c],\n                            poly_coef[off+8][r][c];\n                        w = rotate_order_3(w, cos_theta, sin_theta);\n                        poly_coef[off+5][r][c] = w(0);\n                        poly_coef[off+6][r][c] = w(1);\n                        poly_coef[off+7][r][c] = w(2);\n                        poly_coef[off+8][r][c] = w(3);\n                    }\n                    if (order >= 4)\n                    {\n                        matrix<float,5,1> w;\n                        w = poly_coef[off+9][r][c],\n                            poly_coef[off+10][r][c],\n                            poly_coef[off+11][r][c],\n                            poly_coef[off+12][r][c],\n                            poly_coef[off+13][r][c];\n                        w = rotate_order_4(w, cos_theta, sin_theta);\n                        poly_coef[off+9][r][c]  = w(0);\n                        poly_coef[off+10][r][c] = w(1);\n                        poly_coef[off+11][r][c] = w(2);\n                        poly_coef[off+12][r][c] = w(3);\n                        poly_coef[off+13][r][c] = w(4);\n                    }\n                    if (order >= 5)\n                    {\n                        matrix<float,6,1> w;\n                        w = poly_coef[off+14][r][c],\n                            poly_coef[off+15][r][c],\n                            poly_coef[off+16][r][c],\n                            poly_coef[off+17][r][c],\n                            poly_coef[off+18][r][c],\n                            poly_coef[off+19][r][c];\n                        w = rotate_order_5(w, cos_theta, sin_theta);\n                        poly_coef[off+14][r][c] = w(0);\n                        poly_coef[off+15][r][c] = w(1);\n                        poly_coef[off+16][r][c] = w(2);\n                        poly_coef[off+17][r][c] = w(3);\n                        poly_coef[off+18][r][c] = w(4);\n                        poly_coef[off+19][r][c] = w(5);\n                    }\n                    if (order >= 6)\n                    {\n                        matrix<float,7,1> w;\n                        w = poly_coef[off+20][r][c],\n                            poly_coef[off+21][r][c],\n                            poly_coef[off+22][r][c],\n                            poly_coef[off+23][r][c],\n                            poly_coef[off+24][r][c],\n                            poly_coef[off+25][r][c],\n                            poly_coef[off+26][r][c];\n                        w = rotate_order_6(w, cos_theta, sin_theta);\n                        poly_coef[off+20][r][c] = w(0);\n                        poly_coef[off+21][r][c] = w(1);\n                        poly_coef[off+22][r][c] = w(2);\n                        poly_coef[off+23][r][c] = w(3);\n                        poly_coef[off+24][r][c] = w(4);\n                        poly_coef[off+25][r][c] = w(5);\n                        poly_coef[off+26][r][c] = w(6);\n                    }\n                }\n            }\n\n        }\n\n        template <typename image_type>\n        rectangle filter_image (\n            const image_type& img,\n            array2d<float>& out,\n            const std::vector<separable_filter_type>& filter\n        ) const\n        {\n            rectangle rect = spatially_filter_image_separable_down(downsample, img, out, filter[0].first, filter[0].second);\n            for (unsigned long i = 1; i < filter.size(); ++i)\n            {\n                spatially_filter_image_separable_down(downsample, img, out, filter[i].first, filter[i].second, 1, false, true);\n            }\n            return rect;\n        }\n\n\n\n        std::vector<std::vector<separable_filter_type> > filters;\n\n        dlib::array<array2d<float> > poly_coef;\n        long order;\n        long window_size;\n        long border_size;\n        long num_rows;\n        long num_cols;\n\n        bool normalize;\n        bool rotation_invariance;\n\n        mutable descriptor_type des;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_POLY_ImAGE_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/poly_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_POLY_ImAGE_ABSTRACT_Hh_\n#ifdef DLIB_POLY_ImAGE_ABSTRACT_Hh_\n\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../geometry/rectangle_abstract.h\"\n#include <cmath>\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    template <\n        long Downsample\n        >\n    class poly_image : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON TEMPLATE PARAMETERS \n                - Downsample >= 1\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for extracting local feature descriptors from an image.\n                In particular, it fits polynomials to local pixel patches and allows you to \n                query the coefficients of these polynomials.  Additionally, the coefficients \n                may be intensity normalized by dividing them by the constant term of the fitted \n                polynomial and then the constant term is discarded. \n\n                Finally, the user can specify a downsampling rate.  If the template argument\n                Downsample is set to 1 then feature extraction is performed at every pixel of\n                an input image (except for a small area around the image border).  However,\n                if Downsample is set to 2 then feature extraction is only performed at every\n                other pixel location.  More generally, if Downsample is set to N then feature\n                extraction is performed only every N pixels.  \n                \n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a poly_image object to many other threads.  \n                In this case, it is safe to copy the configuration of a shared object so long\n                as no other operations are performed on it.\n        !*/\n\n    public:\n\n        typedef matrix<double, 0, 1> descriptor_type;\n        const static long downsample = Downsample;\n\n        poly_image (\n        ); \n        /*!\n            ensures\n                - #get_order() == 3\n                - #get_window_size() == 13\n                - #size() == 0\n                - #uses_normalization() == true\n                - #is_rotationally_invariant() == false \n        !*/\n\n        poly_image(\n            long order,\n            long window_size,\n            bool normalization = true,\n            bool rotation_invariance = false\n        );\n        /*!\n            requires\n                - 1 <= order <= 6\n                - window_size >= 3 && window_size is odd\n            ensures\n                - #get_order() == order\n                - #get_window_size() == window_size\n                - #size() == 0\n                - #uses_normalization() == normalization\n                - #is_rotationally_invariant() == rotation_invariance\n        !*/\n\n        void clear (\n        );\n        /*!\n            ensures\n                - this object will have its initial value\n        !*/\n\n        void setup (\n            long order,\n            long window_size\n        );\n        /*!\n            requires\n                - 1 <= order <= 6\n                - window_size >= 3 && window_size is odd\n            ensures\n                - #get_order() == order\n                - #get_window_size() == window_size\n        !*/\n\n        long get_order (\n        ) const;\n        /*!\n            ensures\n                - returns the order of the polynomial that will be fitted to \n                  each local pixel patch during feature extraction.\n        !*/\n\n        long get_window_size (\n        ) const;\n        /*!\n            ensures\n                - returns the size of the window used for local feature extraction.\n                  This is the width and height of the window in pixels.\n        !*/\n\n        bool uses_normalization (\n        ) const; \n        /*!\n            ensures\n                - returns true if the polynomial coefficients are intensity normalized\n                  and false otherwise. \n        !*/\n\n        void set_uses_normalization (\n            bool normalization\n        );\n        /*!\n            ensures\n                - #uses_normalization() == normalization\n        !*/\n\n        bool is_rotationally_invariant (\n        );\n        /*!\n            ensures\n                - returns true if the feature extractor will adjust the output so that it\n                  is rotationally invariant.  This is done by rotating each patch such that\n                  the gradient vector always points in the same direction.\n        !*/\n\n        void set_is_rotationally_invariant (\n            bool rotation_invariance\n        );\n        /*!\n            ensures\n                - #is_rotationally_invariant() == rotation_invariance\n        !*/\n\n        void copy_configuration (\n            const poly_image& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two poly_image \n                  objects H1 and H2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    H2.copy_configuration(H1);\n                    H1.load(img);\n                    H2.load(img);\n        !*/\n\n        template <\n            typename image_type\n            >\n        inline void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            ensures\n                - Performs the feature extraction described in the WHAT THIS OBJECT REPRESENTS\n                  section above.  This means after load() finishes you can call (*this)(row,col) \n                  to obtain the polynomial coefficients for an order get_order() polynomial which \n                  was fitted to the image patch get_block_rect(row,col).\n                - #size() > 0\n        !*/\n\n        void unload(\n        );\n        /*!\n            ensures\n                - #nr() == 0\n                - #nc() == 0\n                - clears only the state information which is populated by load().  For \n                  example, let H be a poly_image object.  Then consider the two sequences \n                  of instructions:\n                    Sequence 1:\n                        H.load(img);      \n                        H.unload();\n                        H.load(img);\n\n                    Sequence 2:\n                        H.load(img);\n                  Both sequence 1 and sequence 2 should have the same effect on H.  \n        !*/\n\n        inline size_t size (\n        ) const; \n        /*!\n            ensures\n                - returns nr()*nc()\n        !*/\n\n        inline long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this polynomial feature image\n        !*/\n\n        inline long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this polynomial feature image\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the number of dimensions in the feature vectors generated by\n                  this object.  \n                - In this case, this will be the number of coefficients in an order \n                  get_order() polynomial, except for the constant term of the polynomial\n                  if uses_normalization() == true.\n        !*/\n\n        inline const descriptor_type& operator() (\n            long row,\n            long col\n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= col < nc()\n            ensures\n                - returns the descriptor for the polynomial filtering block at the given row and column.  \n                  This vector will contain the polynomial coefficients for a polynomial fitted to the\n                  image patch located at get_block_rect(row,col) in the original image given to load().\n                - The returned descriptor vector will have get_num_dimensions() elements.\n        !*/\n\n        const rectangle get_block_rect (\n            long row,\n            long col\n        ) const;\n        /*!\n            ensures\n                - returns a rectangle that tells you what part of the original image is associated\n                  with a particular polynomial filter block.  That is, what part of the input image \n                  is associated with (*this)(row,col).\n                - The returned rectangle will be get_window_size() pixels wide and tall.\n        !*/\n\n        const point image_to_feat_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - Each local feature is extracted from a certain point in the input image.\n                  This function returns the identity of the local feature corresponding\n                  to the image location p.  Or in other words, let P == image_to_feat_space(p), \n                  then (*this)(P.y(),P.x()) == the local feature closest to, or centered at, \n                  the point p in the input image.  Note that some image points might not have \n                  corresponding feature locations.  E.g. border points or points outside the \n                  image.  In these cases the returned point will be outside get_rect(*this).\n        !*/\n\n        const rectangle image_to_feat_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns rectangle(image_to_feat_space(rect.tl_corner()), image_to_feat_space(rect.br_corner()));\n                  (i.e. maps a rectangle from image space to feature space)\n        !*/\n\n        const point feat_to_image_space (\n            const point& p\n        ) const;\n        /*!\n            ensures\n                - returns the location in the input image space corresponding to the center\n                  of the local feature at point p.  In other words, this function computes\n                  the inverse of image_to_feat_space().  Note that it may only do so approximately, \n                  since more than one image location might correspond to the same local feature.  \n                  That is, image_to_feat_space() might not be invertible so this function gives \n                  the closest possible result.\n        !*/\n\n        const rectangle feat_to_image_space (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - return rectangle(feat_to_image_space(rect.tl_corner()), feat_to_image_space(rect.br_corner()));\n                  (i.e. maps a rectangle from feature space to image space)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long downsample\n        >\n    void serialize (\n        const poly_image<downsample>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        long downsample\n        >\n    void deserialize (\n        poly_image<downsample>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_POLY_ImAGE_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint/surf.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SURf_H_\n#define DLIB_SURf_H_\n\n#include \"surf_abstract.h\"\n#include \"hessian_pyramid.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    struct surf_point\n    {\n        interest_point p;\n        matrix<double,64,1> des;\n        double angle;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize(\n        const surf_point& item,  \n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.p,out);\n            serialize(item.des,out);\n            serialize(item.angle,out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type surf_point\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize(\n        surf_point& item,  \n        std::istream& in \n    )\n    {\n        try\n        {\n            deserialize(item.p,in);\n            deserialize(item.des,in);\n            deserialize(item.angle,in);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while deserializing object of type surf_point\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double gaussian (double x, double y, double sig)\n    {\n        DLIB_ASSERT(sig > 0,\n            \"\\tdouble gaussian()\"\n            << \"\\n\\t sig must be bigger than 0\"\n            << \"\\n\\t sig: \" << sig \n        );\n        const double sqrt_2_pi = 2.5066282746310002416123552393401041626930;\n        return 1.0/(sig*sqrt_2_pi) * std::exp( -(x*x + y*y)/(2*sig*sig));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type, typename T>\n    double compute_dominant_angle (\n        const integral_image_type& img,\n        const dlib::vector<T,2>& center,\n        const double& scale\n    )\n    {\n        DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(17*scale),(unsigned long)(17*scale))) == true &&\n                    scale > 0,\n            \"\\tdouble compute_dominant_angle(img, center, scale)\"\n            << \"\\n\\tAll arguments to this function must be > 0\"\n            << \"\\n\\t get_rect(img): \" << get_rect(img) \n            << \"\\n\\t center:        \" << center \n            << \"\\n\\t scale:         \" << scale \n        );\n\n\n        std::vector<double> ang;\n        std::vector<dlib::vector<double,2> > samples;\n\n        const long sc = std::lround(scale);\n\n        // accumulate a bunch of angle and vector samples\n        dlib::vector<double,2> vect;\n        for (long r = -6; r <= 6; ++r)\n        {\n            for (long c = -6; c <= 6; ++c)\n            {\n                if (r*r + c*c < 36)\n                {\n                    // compute a Gaussian weighted gradient and the gradient's angle.\n                    const double gauss = gaussian(c,r, 2.5);\n                    vect.x() = gauss*haar_x(img, sc*point(c,r)+center, 4*sc);\n                    vect.y() = gauss*haar_y(img, sc*point(c,r)+center, 4*sc);\n                    samples.push_back(vect);\n                    ang.push_back(atan2(vect.y(), vect.x()));\n                }\n            }\n        }\n\n\n        // now find the dominant direction\n        double max_length = 0;\n        double best_ang = 0;\n        // look at a bunch of pie shaped slices of a circle \n        const long slices = 45;\n        const double ang_step = (2*pi)/slices;\n        for (long ang_i = 0; ang_i < slices; ++ang_i)\n        {\n            // compute the bounding angles\n            double ang1 = ang_step*ang_i - pi;\n            double ang2 = ang1 + pi/3;\n\n\n            // compute sum of all vectors that are within the above two angles\n            vect.x() = 0;\n            vect.y() = 0;\n            for (unsigned long i = 0; i < ang.size(); ++i)\n            {\n                if (ang1 <= ang[i] && ang[i] <= ang2)\n                {\n                    vect += samples[i];\n                }\n                else if (ang2 > pi && (ang[i] >= ang1 || ang[i] <= (-2*pi+ang2)))\n                {\n                    vect += samples[i];\n                }\n            }\n\n\n            // record the angle of the best vectors\n            if (length_squared(vect) > max_length)\n            {\n                max_length = length_squared(vect);\n                best_ang = atan2(vect.y(), vect.x());\n            }\n        }\n\n        return best_ang;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type, typename T, typename MM, typename L>\n    void compute_surf_descriptor (\n        const integral_image_type& img,\n        const dlib::vector<T,2>& center,\n        const double scale,\n        const double angle,\n        matrix<double,64,1,MM,L>& des\n    )\n    {\n        DLIB_ASSERT(get_rect(img).contains(centered_rect(center, (unsigned long)(32*scale),(unsigned long)(32*scale))) == true &&\n                    scale > 0,\n            \"\\tvoid compute_surf_descriptor(img, center, scale, angle)\"\n            << \"\\n\\tAll arguments to this function must be > 0\"\n            << \"\\n\\t get_rect(img): \" << get_rect(img) \n            << \"\\n\\t center:        \" << center \n            << \"\\n\\t scale:         \" << scale \n        );\n\n        point_rotator rot(angle);\n        point_rotator inv_rot(-angle);\n\n        const long sc = std::lround(scale);\n        long count = 0;\n\n        // loop over the 4x4 grid of histogram buckets \n        for (long r = -10; r < 10; r += 5)\n        {\n            for (long c = -10; c < 10; c += 5)\n            {\n                dlib::vector<double,2> vect, abs_vect, temp;\n\n                // now loop over 25 points in this bucket and sum their features.  Note\n                // that we include 1 pixels worth of padding around the outside of each 5x5\n                // cell.  This is to help neighboring cells interpolate their counts into\n                // each other a little bit.\n                for (long y = r-1; y < r+5+1; ++y)\n                {\n                    if (y < -10 || y >= 10)\n                        continue;\n                    for (long x = c-1; x < c+5+1; ++x)\n                    {\n                        if (x < -10 || x >= 10)\n                            continue;\n\n                        // get the rotated point for this extraction point\n                        point p(rot(point(x,y)*scale) + center); \n\n                        // Give points farther from the center of the bucket a lower weight.  \n                        const long center_r = r+2;\n                        const long center_c = c+2;\n                        const double weight = 1.0/(4+std::abs(center_r-y) + std::abs(center_c-x));\n\n                        temp.x() = weight*haar_x(img, p, 2*sc);\n                        temp.y() = weight*haar_y(img, p, 2*sc);\n\n                        // rotate this vector into alignment with the surf descriptor box \n                        temp = inv_rot(temp);\n\n                        vect += temp;\n                        abs_vect += abs(temp);\n                    }\n                }\n\n                des(count++) = vect.x();\n                des(count++) = vect.y();\n                des(count++) = abs_vect.x();\n                des(count++) = abs_vect.y();\n            }\n        }\n\n        // Return the length normalized descriptor.  Add a small number\n        // to guard against division by zero.\n        const double len = length(des) + 1e-7;\n        des = des/len;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    const std::vector<surf_point> get_surf_points (\n        const image_type& img,\n        long max_points = 10000,\n        double detection_threshold = 30.0\n    )\n    {\n        DLIB_ASSERT(max_points > 0 && detection_threshold >= 0,\n            \"\\t std::vector<surf_point> get_surf_points()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            << \"\\n\\t max_points:          \" << max_points \n            << \"\\n\\t detection_threshold: \" << detection_threshold \n        );\n\n        // Figure out the proper scalar type we should use to work with these pixels.  \n        typedef typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type bp_type;\n        typedef typename promote<bp_type>::type working_pixel_type;\n\n        // make an integral image first\n        integral_image_generic<working_pixel_type> int_img;\n        int_img.load(img);\n\n        // now make a hessian pyramid\n        hessian_pyramid pyr;\n        pyr.build_pyramid(int_img, 4, 6, 2);\n\n        // now get all the interest points from the hessian pyramid\n        std::vector<interest_point> points; \n        get_interest_points(pyr, detection_threshold, points);\n        std::vector<surf_point> spoints;\n\n        // sort all the points by how strong their detect is\n        std::sort(points.rbegin(), points.rend());\n\n        // now extract SURF descriptors for the points\n        surf_point sp;\n        for (unsigned long i = 0; i < std::min((size_t)max_points,points.size()); ++i)\n        {\n            // ignore points that are close to the edge of the image\n            const double border = 32;\n            const unsigned long border_size = static_cast<unsigned long>(border*points[i].scale);\n            if (get_rect(int_img).contains(centered_rect(points[i].center, border_size, border_size)))\n            {\n                sp.angle = compute_dominant_angle(int_img, points[i].center, points[i].scale);\n                compute_surf_descriptor(int_img, points[i].center, points[i].scale, sp.angle, sp.des);\n                sp.p = points[i];\n\n                spoints.push_back(sp);\n            }\n        }\n\n        return spoints;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SURf_H_\n\n"
  },
  {
    "path": "dlib/image_keypoint/surf_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SURf_ABSTRACT_H_\n#ifdef DLIB_SURf_ABSTRACT_H_\n\n#include \"hessian_pyramid_abstract.h\"\n#include \"../geometry/vector_abstract.h\"\n#include \"../matrix/matrix_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    /*\n        The functions in this file implement the components of the SURF algorithm\n        for extracting scale invariant feature descriptors from images.\n\n        For the full story on what this algorithm does and how it works\n        you should refer to the following papers.\n\n        This is the original paper which introduced the algorithm:\n            SURF: Speeded Up Robust Features\n            By Herbert Bay, Tinne Tuytelaars, and Luc Van Gool\n\n        This paper provides a nice detailed overview of how the algorithm works:\n            Notes on the OpenSURF Library by Christopher Evans\n    */\n\n// ----------------------------------------------------------------------------------------\n    \n    double gaussian (\n        double x, \n        double y,\n        double sig\n    );\n    /*!\n        requires\n            - sig > 0\n        ensures\n            - computes and returns the value of a 2D Gaussian function with mean 0 \n              and standard deviation sig at the given (x,y) point.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type, typename T>\n    double compute_dominant_angle (\n        const integral_image_type& img,\n        const dlib::vector<T,2>& center,\n        const double& scale\n    );\n    /*!\n        requires\n            - integral_image_type == an object such as dlib::integral_image or another\n              type that implements the interface defined in image_transforms/integral_image_abstract.h\n            - scale > 0\n            - get_rect(img).contains(centered_rect(center, 17*scale, 17*scale)) == true\n              (i.e. center can't be within 17*scale pixels of the edge of the image)\n        ensures\n            - computes and returns the dominant angle (i.e. the angle of the dominant gradient)\n              at the given center point and scale in img.  \n            - The returned angle is in radians.  Specifically, if the angle is described by\n              a vector vect then the angle is exactly the value of std::atan2(vect.y(), vect.x())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type, typename T, typename MM, typename L>\n    void compute_surf_descriptor (\n        const integral_image_type& img,\n        const dlib::vector<T,2>& center,\n        const double scale,\n        const double angle,\n        matrix<double,64,1,MM,L>& des\n    )\n    /*!\n        requires\n            - integral_image_type == an object such as dlib::integral_image or another\n              type that implements the interface defined in image_transforms/integral_image_abstract.h\n            - scale > 0\n            - get_rect(img).contains(centered_rect(center, 32*scale, 32*scale)) == true\n              (i.e. center can't be within 32*scale pixels of the edge of the image)\n        ensures\n            - computes the 64 dimensional SURF descriptor vector of a box centered\n              at the given center point, tilted at an angle determined by the given \n              angle, and sized according to the given scale.  \n            - #des == the computed SURF descriptor vector extracted from the img object.\n            - The angle is measured in radians and measures the degree of counter-clockwise \n              rotation around the center point.  This is the same kind of rotation as is \n              performed by the dlib::rotate_point() function.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct surf_point\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a detected SURF point.  The meanings of \n                its fields are defined below in the get_surf_points() function.\n        !*/\n\n        interest_point p;\n        matrix<double,64,1> des;\n        double angle;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const surf_point& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        surf_point& item,\n        std::istream& in \n    );\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    const std::vector<surf_point> get_surf_points (\n        const image_type& img,\n        long max_points = 10000,\n        double detection_threshold = 30.0\n    );\n    /*!\n        requires\n            - max_points > 0\n            - detection_threshold >= 0\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - Let P denote the type of pixel in img, then we require:\n                - pixel_traits<P>::has_alpha == false \n        ensures\n            - This function runs the complete SURF algorithm on the given input image and \n              returns the points it found. \n            - returns a vector V such that:\n                - V.size() <= max_points\n                - for all valid i:\n                    - V[i] == a SURF point found in the given input image img\n                    - V[i].p == the interest_point extracted from the hessian pyramid for this\n                      SURF point.\n                    - V[i].des == the SURF descriptor for this point (calculated using \n                      compute_surf_descriptor())\n                    - V[i].angle == the angle of the SURF box at this point (calculated using \n                      compute_dominant_angle())\n                    - V[i].p.score >= detection_threshold\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SURf_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/image_keypoint.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_KEYPOINt_H_\n#define DLIB_IMAGE_KEYPOINt_H_ \n\n#include \"image_keypoint/surf.h\"\n#include \"image_keypoint/hessian_pyramid.h\"\n#include \"image_keypoint/hog.h\"\n#include \"image_keypoint/poly_image.h\"\n#include \"image_keypoint/fine_hog_image.h\"\n#include \"image_keypoint/hashed_feature_image.h\"\n#include \"image_keypoint/nearest_neighbor_feature_image.h\"\n#include \"image_keypoint/binned_vector_feature_image.h\"\n\n#endif // DLIB_IMAGE_KEYPOINt_H_\n\n"
  },
  {
    "path": "dlib/image_loader/image_loader.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_LOADEr_\n#define DLIB_IMAGE_LOADEr_\n\n#include \"image_loader_abstract.h\"\n#include <iostream>\n#include <sstream>\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../image_saver/dng_shared.h\"\n#include \"../entropy_decoder_model.h\"\n#include \"../entropy_decoder.h\"\n#include \"../uintn.h\"\n#include \"../image_transforms/assign_image.h\"\n#include <algorithm>\n#include \"../vectorstream.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_load_error : public dlib::error { \n    public: image_load_error(const std::string& str) : error(EIMAGE_LOAD,str){}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void load_bmp (\n        image_type& image_,\n        std::istream& in_\n    )\n    {\n        image_view<image_type> image(image_);\n        try\n        {\n            unsigned long bytes_read_so_far = 0;\n            unsigned long bfSize;\n            unsigned long bfOffBits;\n            unsigned long biSize;\n            unsigned long biWidth;\n            int32 biHeight;\n            unsigned short biBitCount;\n            unsigned long biCompression;\n            unsigned long a, b, c, d, i;\n\n            std::streambuf& in = *in_.rdbuf();\n            unsigned char buf[100];\n\n\n            // first make sure the BMP starts with BM\n            if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)\n                throw image_load_error(\"bmp load error 1: header error\");\n            bytes_read_so_far += 2;\n\n            if (buf[0] != 'B' || buf[1] != 'M')\n                throw image_load_error(\"bmp load error 2: header error\");\n\n            // now read the BITMAPFILEHEADER\n            if (in.sgetn(reinterpret_cast<char*>(buf),12) != 12)\n                throw image_load_error(\"bmp load error 3: header error\");\n\n            bytes_read_so_far += 12;\n\n            i = 0;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            bfSize = a | (b<<8) | (c<<16) | (d<<24);\n\n            // Ignore the next 4 bytes (Reserved Area)\n\n            i = 8;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            bfOffBits = a | (b<<8) | (c<<16) | (d<<24);\n\n            // load the BITMAPINFOHEADER\n            if (in.sgetn(reinterpret_cast<char*>(buf),40) != 40)\n                throw image_load_error(\"bmp load error 5: file too short\");\n            bytes_read_so_far += 40;\n\n\n            i = 0;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            biSize = a | (b<<8) | (c<<16) | (d<<24);\n\n            i += 4;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            biWidth = a | (b<<8) | (c<<16) | (d<<24);\n\n            i += 4;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            biHeight = a | (b<<8) | (c<<16) | (d<<24);\n            \n            bool bottomUp = biHeight < 0;\n            if (bottomUp)\n                biHeight = 0 - biHeight;\n            \n            i += 4+2;\n            a = buf[i]; b = buf[i+1];\n            biBitCount = static_cast<unsigned short>(a | (b<<8));\n\n            i += 2;\n            a = buf[i]; b = buf[i+1]; c = buf[i+2]; d = buf[i+3];\n            biCompression = a | (b<<8) | (c<<16) | (d<<24);\n\n\n            if (biSize != 40)\n                throw image_load_error(\"bmp load error 6: header too small\");\n\n            image.set_size(biHeight, biWidth);\n\n            switch (biBitCount)\n            {\n                case 1:\n                    {\n                        // figure out how the pixels are packed\n                        long padding;\n                        if (bfSize - bfOffBits == biWidth*biHeight/8)\n                            padding = 0;\n                        else\n                            padding = 4 - ((biWidth+7)/8)%4;\n\n                        const unsigned int palette_size = 2;\n                        unsigned char red[palette_size];\n                        unsigned char green[palette_size];\n                        unsigned char blue[palette_size];\n\n                        for (unsigned int i = 0; i < palette_size; ++i)\n                        {\n                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)\n                            {\n                                throw image_load_error(\"bmp load error 20: color palette missing\");\n                            }\n                            bytes_read_so_far += 4;\n                            blue[i] = buf[0];\n                            green[i] = buf[1];\n                            red[i] = buf[2];\n                        }\n\n\n                        // seek to the start of the pixel data\n                        while (bytes_read_so_far != bfOffBits)\n                        {\n                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));\n                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)\n                            {\n                                throw image_load_error(\"bmp load error: missing data\");\n                            }\n                            bytes_read_so_far += to_read;\n                        }\n\n                        // load the image data\n                        for (long row = biHeight-1; row >= 0; --row)\n                        {\n                            for (unsigned long col = 0; col < biWidth; col+=8)\n                            {\n                                if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)\n                                {\n                                    throw image_load_error(\"bmp load error 21.6: file too short\");\n                                }\n\n                                unsigned char pixels[8];\n\n                                pixels[0] = (buf[0]>>7);\n                                pixels[1] = ((buf[0]>>6)&0x01);\n                                pixels[2] = ((buf[0]>>5)&0x01);\n                                pixels[3] = ((buf[0]>>4)&0x01);\n                                pixels[4] = ((buf[0]>>3)&0x01);\n                                pixels[5] = ((buf[0]>>2)&0x01);\n                                pixels[6] = ((buf[0]>>1)&0x01);\n                                pixels[7] = ((buf[0])&0x01);\n\n                                for (int i = 0; i < 8 && col+i < biWidth; ++i)\n                                {\n                                    rgb_pixel p;\n                                    p.red   = red[pixels[i]];\n                                    p.green = green[pixels[i]];\n                                    p.blue  = blue[pixels[i]];\n                                    assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col+i],p);\n                                }\n                            }\n                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)\n                                throw image_load_error(\"bmp load error 9: file too short\");\n                        }\n\n\n\n                    } break;\n                case 4:\n                    {\n                        // figure out how the pixels are packed\n                        long padding;\n                        if (bfSize - bfOffBits == biWidth*biHeight/2)\n                            padding = 0;\n                        else\n                            padding = 4 - ((biWidth+1)/2)%4;\n\n                        const unsigned int palette_size = 16;\n                        unsigned char red[palette_size];\n                        unsigned char green[palette_size];\n                        unsigned char blue[palette_size];\n\n                        for (unsigned int i = 0; i < palette_size; ++i)\n                        {\n                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)\n                            {\n                                throw image_load_error(\"bmp load error 20: color palette missing\");\n                            }\n                            bytes_read_so_far += 4;\n                            blue[i] = buf[0];\n                            green[i] = buf[1];\n                            red[i] = buf[2];\n                        }\n\n\n                        // seek to the start of the pixel data\n                        while (bytes_read_so_far != bfOffBits)\n                        {\n                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));\n                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)\n                            {\n                                throw image_load_error(\"bmp load error: missing data\");\n                            }\n                            bytes_read_so_far += to_read;\n                        }\n\n                        // load the image data\n                        for (long row = biHeight-1; row >= 0; --row)\n                        {\n                            for (unsigned long col = 0; col < biWidth; col+=2)\n                            {\n                                if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)\n                                {\n                                    throw image_load_error(\"bmp load error 21.7: file too short\");\n                                }\n\n                                const unsigned char pixel1 = (buf[0]>>4);\n                                const unsigned char pixel2 = (buf[0]&0x0F);\n\n                                rgb_pixel p;\n                                p.red = red[pixel1];\n                                p.green = green[pixel1];\n                                p.blue = blue[pixel1];\n                                assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col], p);\n\n                                if (col+1 < biWidth)\n                                {\n                                    p.red   = red[pixel2];\n                                    p.green = green[pixel2];\n                                    p.blue  = blue[pixel2];\n                                    assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col+1], p);\n                                }\n                            }\n                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)\n                                throw image_load_error(\"bmp load error 9: file too short\");\n                        }\n\n\n\n                    } break;\n                case 8:\n                    {\n                        // figure out how the pixels are packed\n                        long padding;\n                        if (bfSize - bfOffBits == biWidth*biHeight)\n                            padding = 0;\n                        else\n                            padding = 4 - biWidth%4;\n\n                        // check for this case.  It shouldn't happen but some BMP writers screw up the files\n                        // so we have to do this.\n                        if (biHeight*(biWidth+padding) > bfSize - bfOffBits)\n                            padding = 0;\n\n                        const unsigned int palette_size = 256;\n                        unsigned char red[palette_size];\n                        unsigned char green[palette_size];\n                        unsigned char blue[palette_size];\n\n                        for (unsigned int i = 0; i < palette_size; ++i)\n                        {\n                            if (in.sgetn(reinterpret_cast<char*>(buf),4) != 4)\n                            {\n                                throw image_load_error(\"bmp load error 20: color palette missing\");\n                            }\n                            bytes_read_so_far += 4;\n                            blue[i] = buf[0];\n                            green[i] = buf[1];\n                            red[i] = buf[2];\n                        }\n\n\n                        // seek to the start of the pixel data\n                        while (bytes_read_so_far != bfOffBits)\n                        {\n                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));\n                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)\n                            {\n                                throw image_load_error(\"bmp load error: missing data\");\n                            }\n                            bytes_read_so_far += to_read;\n                        }\n\n                        // Next we load the image data.\n\n                        // if there is no RLE compression\n                        if (biCompression == 0)\n                        {\n                            for (long row = biHeight-1; row >= 0; --row)\n                            {\n                                for (unsigned long col = 0; col < biWidth; ++col)\n                                {\n                                    if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)\n                                    {\n                                        throw image_load_error(\"bmp load error 21.8: file too short\");\n                                    }\n\n                                    rgb_pixel p;\n                                    p.red   = red[buf[0]];\n                                    p.green = green[buf[0]];\n                                    p.blue  = blue[buf[0]];\n                                    assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p);\n                                }\n                                if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)\n                                    throw image_load_error(\"bmp load error 9: file too short\");\n                            }\n                        }\n                        else\n                        {\n                            // Here we deal with the psychotic RLE used by BMP files.\n\n                            // First zero the image since the RLE sometimes jumps over\n                            // pixels and assumes the image has been zero initialized.\n                            assign_all_pixels(image, 0);\n\n                            long row = biHeight-1;\n                            long col = 0;\n                            while (true)\n                            {\n                                if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)\n                                {\n                                    throw image_load_error(\"bmp load error 21.9: file too short\");\n                                }\n\n                                const unsigned char count = buf[0];\n                                const unsigned char command = buf[1];\n\n                                if (count == 0 && command == 0)\n                                {\n                                    // This is an escape code that means go to the next row\n                                    // of the image\n                                    --row;\n                                    col = 0;\n                                    continue;\n                                }\n                                else if (count == 0 && command == 1)\n                                {\n                                    // This is the end of the image.  So quit this loop.\n                                    break;\n                                }\n                                else if (count == 0 && command == 2)\n                                {\n                                    // This is the escape code for the command to jump to\n                                    // a new part of the image relative to where we are now.\n                                    if (in.sgetn(reinterpret_cast<char*>(buf),2) != 2)\n                                    {\n                                        throw image_load_error(\"bmp load error 21.1: file too short\");\n                                    }\n                                    col += buf[0];\n                                    row -= buf[1];\n                                    continue;\n                                }\n                                else if (count == 0)\n                                {\n                                    // This is the escape code for a run of uncompressed bytes\n\n                                    if (row < 0 || col + command > image.nc())\n                                    {\n                                        // If this is just some padding bytes at the end then ignore them\n                                        if (row >= 0 && col + count <= image.nc() + padding)\n                                            continue;\n\n                                        throw image_load_error(\"bmp load error 21.2: file data corrupt\");\n                                    }\n\n                                    // put the bytes into the image\n                                    for (unsigned int i = 0; i < command; ++i)\n                                    {\n                                        if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)\n                                        {\n                                            throw image_load_error(\"bmp load error 21.3: file too short\");\n                                        }\n                                        rgb_pixel p;\n                                        p.red   = red[buf[0]];\n                                        p.green = green[buf[0]];\n                                        p.blue  = blue[buf[0]];\n                                        assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p);\n\n                                        ++col;\n                                    }\n\n                                    // if we read an uneven number of bytes then we need to read and\n                                    // discard the next byte.\n                                    if ((command&1) != 1)\n                                    {\n                                        if (in.sgetn(reinterpret_cast<char*>(buf),1) != 1)\n                                        {\n                                            throw image_load_error(\"bmp load error 21.4: file too short\");\n                                        }\n                                    }\n\n                                    continue;\n                                }\n\n                                rgb_pixel p;\n\n                                if (row < 0 || col + count > image.nc())\n                                {\n                                    // If this is just some padding bytes at the end then ignore them\n                                    if (row >= 0 && col + count <= image.nc() + padding)\n                                        continue;\n\n                                    throw image_load_error(\"bmp load error 21.5: file data corrupt\");\n                                }\n\n                                // put the bytes into the image\n                                for (unsigned int i = 0; i < count; ++i)\n                                {\n                                    p.red   = red[command];\n                                    p.green = green[command];\n                                    p.blue  = blue[command];\n                                    assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col],p);\n\n                                    ++col;\n                                }\n                            }\n                        }\n\n\n\n                    }\n                    break;\n                case 16:\n                    throw image_load_error (\"16 bit BMP images not supported\");\n                case 24:\n                    {\n                        // figure out how the pixels are packed\n                        long padding;\n                        if (bfSize - bfOffBits == biWidth*biHeight*3)\n                            padding = 0;\n                        else\n                            padding = 4 - (biWidth*3)%4;\n\n                        // check for this case.  It shouldn't happen but some BMP writers screw up the files\n                        // so we have to do this.\n                        if (biHeight*(biWidth*3+padding) > bfSize - bfOffBits)\n                            padding = 0;\n                        \n                        // seek to the start of the pixel data\n                        while (bytes_read_so_far != bfOffBits)\n                        {\n                            const long to_read = (long)std::min(bfOffBits - bytes_read_so_far, (unsigned long)sizeof(buf));\n                            if (in.sgetn(reinterpret_cast<char*>(buf), to_read) != to_read)\n                            {\n                                throw image_load_error(\"bmp load error: missing data\");\n                            }\n                            bytes_read_so_far += to_read;\n                        }\n\n                        // load the image data\n                        for (long row = biHeight-1; row >= 0; --row)\n                        {\n                            for (unsigned long col = 0; col < biWidth; ++col)\n                            {\n                                if (in.sgetn(reinterpret_cast<char*>(buf),3) != 3)\n                                {\n                                    throw image_load_error(\"bmp load error 8: file too short\");\n                                }\n\n                                rgb_pixel p;\n                                p.red = buf[2];\n                                p.green = buf[1];\n                                p.blue = buf[0];\n                                assign_pixel(image[bottomUp ? biHeight - row - 1 : row][col], p);\n\n                            }\n                            if (in.sgetn(reinterpret_cast<char*>(buf),padding) != padding)\n                                throw image_load_error(\"bmp load error 9: file too short\");\n                        }\n\n                        break;\n                    }\n                case 32:\n                    throw image_load_error (\"32 bit BMP images not supported\");\n                default:\n                    throw image_load_error(\"bmp load error 10: unknown color depth\");\n\n            }\n        }\n        catch (...)\n        {\n            image.clear();\n            throw;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void load_dng (\n        image_type& image_,\n        std::istream& in\n    )\n    {\n        image_view<image_type> image(image_);\n        using namespace dng_helpers_namespace;\n        try\n        {\n            if (in.get() != 'D' || in.get() != 'N' || in.get() != 'G')\n                throw image_load_error(\"the stream does not contain a dng image file\");\n\n            unsigned long version;\n            deserialize(version,in);\n            if (version != 1)\n                throw image_load_error(\"You need the new version of the dlib library to read this dng file\");\n\n            unsigned long type;\n            deserialize(type,in);\n\n            long width, height;\n            deserialize(width,in);\n            deserialize(height,in);\n\n            if (width > 0 && height > 0)\n                image.set_size(height,width);\n            else\n                image.clear();\n\n            if (type != grayscale_float)\n            {\n                typedef entropy_decoder::kernel_2a decoder_type;\n                decoder_type decoder;\n                decoder.set_stream(in);\n\n                entropy_decoder_model<256,decoder_type>::kernel_5a edm(decoder);\n                unsigned long symbol;\n                rgb_pixel p_rgb;\n                rgb_alpha_pixel p_rgba;\n                hsi_pixel p_hsi;\n                switch (type)\n                {\n                    case rgb_alpha_paeth:\n\n                        for (long r = 0; r < image.nr(); ++r)\n                        {\n                            for (long c = 0; c < image.nc(); ++c)\n                            {\n                                p_rgba = predictor_rgb_alpha_paeth(image,r,c);\n                                edm.decode(symbol);\n                                p_rgba.red += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.green += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.blue += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.alpha += static_cast<unsigned char>(symbol);\n\n                                assign_pixel(image[r][c],p_rgba);\n                            }\n                        }\n                        break;\n\n                    case rgb_alpha:\n\n                        for (long r = 0; r < image.nr(); ++r)\n                        {\n                            for (long c = 0; c < image.nc(); ++c)\n                            {\n                                p_rgba = predictor_rgb_alpha(image,r,c);\n                                edm.decode(symbol);\n                                p_rgba.red += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.green += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.blue += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgba.alpha += static_cast<unsigned char>(symbol);\n\n                                assign_pixel(image[r][c],p_rgba);\n                            }\n                        }\n                        break;\n\n                    case rgb_paeth:\n\n                        for (long r = 0; r < image.nr(); ++r)\n                        {\n                            for (long c = 0; c < image.nc(); ++c)\n                            {\n                                p_rgb = predictor_rgb_paeth(image,r,c);\n                                edm.decode(symbol);\n                                p_rgb.red += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgb.green += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgb.blue += static_cast<unsigned char>(symbol);\n\n                                assign_pixel(image[r][c],p_rgb);\n                            }\n                        }\n                        break;\n\n                    case rgb:\n\n                        for (long r = 0; r < image.nr(); ++r)\n                        {\n                            for (long c = 0; c < image.nc(); ++c)\n                            {\n                                p_rgb = predictor_rgb(image,r,c);\n                                edm.decode(symbol);\n                                p_rgb.red += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgb.green += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_rgb.blue += static_cast<unsigned char>(symbol);\n\n                                assign_pixel(image[r][c],p_rgb);\n                            }\n                        }\n                        break;\n\n                    case hsi:\n\n                        for (long r = 0; r < image.nr(); ++r)\n                        {\n                            for (long c = 0; c < image.nc(); ++c)\n                            {\n                                p_hsi = predictor_hsi(image,r,c);\n                                edm.decode(symbol);\n                                p_hsi.h += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_hsi.s += static_cast<unsigned char>(symbol);\n\n                                edm.decode(symbol);\n                                p_hsi.i += static_cast<unsigned char>(symbol);\n\n                                assign_pixel(image[r][c],p_hsi);\n                            }\n                        }\n                        break;\n\n                    case grayscale:\n                        {\n                            unsigned char p;\n                            for (long r = 0; r < image.nr(); ++r)\n                            {\n                                for (long c = 0; c < image.nc(); ++c)\n                                {\n                                    edm.decode(symbol);\n                                    p = static_cast<unsigned char>(symbol);\n                                    p +=  predictor_grayscale(image,r,c);\n                                    assign_pixel(image[r][c],p);\n                                }\n                            }\n                        }\n                        break;\n\n                    case grayscale_16bit:\n                        {\n                            uint16 p;\n                            for (long r = 0; r < image.nr(); ++r)\n                            {\n                                for (long c = 0; c < image.nc(); ++c)\n                                {\n                                    edm.decode(symbol);\n                                    p = static_cast<uint16>(symbol);\n                                    p <<= 8;\n                                    edm.decode(symbol);\n                                    p |= static_cast<uint16>(symbol);\n\n                                    p +=  predictor_grayscale_16(image,r,c);\n                                    assign_pixel(image[r][c],p);\n                                }\n                            }\n                        }\n                        break;\n\n                    default:\n                        throw image_load_error(\"corruption detected in the dng file\");\n                } // switch (type)\n\n                edm.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n            }\n            else // if this is a grayscale_float type image\n            {\n                std::vector<int64> man(image.size());\n                std::vector<char> expbuf;\n                // get the mantissa data\n                for (unsigned long j = 0; j < man.size(); ++j)\n                    deserialize(man[j], in);\n                // get the compressed exponent data\n                deserialize(expbuf, in);\n                typedef entropy_decoder::kernel_2a decoder_type;\n                typedef entropy_decoder_model<256,decoder_type>::kernel_4a edm_exp_type; \n                vectorstream inexp(expbuf);\n                decoder_type decoder;\n                decoder.set_stream(inexp);\n\n                edm_exp_type edm_exp(decoder);\n                float_details prev;\n                unsigned long i = 0;\n                // fill out the image \n                for (long r = 0; r < image.nr(); ++r)\n                {\n                    for (long c = 0; c < image.nc(); ++c)\n                    {\n                        unsigned long exp1, exp2;\n                        edm_exp.decode(exp1);\n                        edm_exp.decode(exp2);\n\n                        float_details cur(man[i++],(exp2<<8) | exp1);\n                        cur.exponent += prev.exponent;\n                        cur.mantissa += prev.mantissa;\n                        prev = cur;\n                        \n                        // Only use long double precision if the target image contains long\n                        // doubles because it's slower to use those.\n                        if (!is_same_type<typename image_traits<image_type>::pixel_type,long double>::value)\n                        {\n                            double temp = cur;\n                            assign_pixel(image[r][c],temp);\n                        }\n                        else\n                        {\n                            long double temp = cur;\n                            assign_pixel(image[r][c],temp);\n                        }\n                    }\n                }\n                unsigned long symbol;\n                edm_exp.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm_exp.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm_exp.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n                edm_exp.decode(symbol);\n                if (symbol != dng_magic_byte)\n                    throw image_load_error(\"corruption detected in the dng file\");\n            }\n        }\n        catch (...)\n        {\n            image.clear();\n            throw;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void load_bmp (\n        image_type& image,\n        const std::string& file_name\n    )\n    {\n        std::ifstream fin(file_name.c_str(), std::ios::binary);\n        if (!fin)\n            throw image_load_error(\"Unable to open \" + file_name + \" for reading.\");\n        load_bmp(image, fin);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void load_dng (\n        image_type& image,\n        const std::string& file_name\n    )\n    {\n        std::ifstream fin(file_name.c_str(), std::ios::binary);\n        if (!fin)\n            throw image_load_error(\"Unable to open \" + file_name + \" for reading.\");\n        load_dng(image, fin);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_LOADEr_\n\n\n\n"
  },
  {
    "path": "dlib/image_loader/image_loader_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_IMAGE_LOADEr_ABSTRACT_\n#ifdef DLIB_IMAGE_LOADEr_ABSTRACT_\n\n#include <iosfwd>\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    class image_load_error : public dlib::error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an exception used to indicate a failure to load an image.\n                Its type member variable will be set to EIMAGE_LOAD.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void load_bmp (\n        image_type& image,\n        std::istream& in\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - #image == the image of the MS Windows BMP file that was available \n              in the input stream in.  \n            - #image[0][0] will be the upper left corner of the image \n            - #image[image.nr()-1][image.nc()-1] will be the lower right\n              corner of the image\n            - Performs any color space conversion necessary to convert the\n              BMP image data into the pixel type used by the given image\n              object.\n        throws\n            - image_load_error\n                This exception is thrown if there is an error that prevents us\n                from loading the image.  If this exception is thrown then \n                #image will have an initial value for its type.\n            - std::bad_alloc \n                If this exception is thrown then #image will have an initial\n                value for its type.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void load_bmp (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - opens the file indicated by file_name with an input file stream named fin \n              and performs:\n              load_bmp(image,fin);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        dlib dng file format:\n            This is a file format I created for this library.  It is a lossless \n            compressed image format that is similar to the PNG format but uses\n            the dlib PPM compression algorithms instead of the DEFLATE algorithm.\n    !*/\n\n    template <\n        typename image_type \n        >\n    void load_dng (\n        image_type& image,\n        std::istream& in\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - #image == the image of the dlib dng file that was available \n              in the input stream in. \n            - #image[0][0] will be the upper left corner of the image \n            - #image[image.nr()-1][image.nc()-1] will be the lower right\n              corner of the image\n            - Performs any color space conversion necessary to convert the\n              dng image data into the pixel type used by the given image\n              object.\n        throws\n            - image_load_error\n                This exception is thrown if there is an error that prevents us\n                from loading the image.  If this exception is thrown then \n                #image will have an initial value for its type.\n            - std::bad_alloc \n                If this exception is thrown then #image will have an initial\n                value for its type.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_dng (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - opens the file indicated by file_name with an input file stream named fin \n              and performs:\n              load_dng(image,fin);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_LOADEr_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/image_loader/jpeg_loader.cpp",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JPEG_LOADER_CPp_\n#define DLIB_JPEG_LOADER_CPp_\n\n// only do anything with this file if DLIB_JPEG_SUPPORT is defined\n#ifdef DLIB_JPEG_SUPPORT\n\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"jpeg_loader.h\"\n#include <stdio.h>\n#ifdef DLIB_JPEG_STATIC\n#   include \"../external/libjpeg/jpeglib.h\"\n#else\n#   include <jpeglib.h>\n#endif\n#include <sstream>\n#include <setjmp.h>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    jpeg_loader::\n    jpeg_loader( const char* filename ) : height_( 0 ), width_( 0 ), output_components_(0)\n    {\n        read_image( check_file( filename ), NULL, 0L );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jpeg_loader::\n    jpeg_loader( const std::string& filename ) : height_( 0 ), width_( 0 ), output_components_(0)\n    {\n        read_image( check_file( filename.c_str() ), NULL, 0L );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jpeg_loader::\n    jpeg_loader( const dlib::file& f ) : height_( 0 ), width_( 0 ), output_components_(0)\n    {\n        read_image( check_file( f.full_name().c_str() ), NULL, 0L );\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    jpeg_loader::\n    jpeg_loader( const unsigned char* imgbuffer, size_t imgbuffersize ) : height_( 0 ), width_( 0 ), output_components_(0)\n    {\n        read_image( NULL, imgbuffer, imgbuffersize );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool jpeg_loader::is_gray() const\n    {\n        return (output_components_ == 1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool jpeg_loader::is_rgb() const\n    {\n        return (output_components_ == 3);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool jpeg_loader::is_rgba() const\n    {\n        return (output_components_ == 4);\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    long jpeg_loader::nr() const\n    {\n        return static_cast<long>(height_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long jpeg_loader::nc() const\n    {\n        return static_cast<long>(width_);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct jpeg_loader_error_mgr \n    {\n        jpeg_error_mgr pub;    /* \"public\" fields */\n        jmp_buf setjmp_buffer;  /* for return to caller */\n        char jpegLastErrorMsg[JMSG_LENGTH_MAX];\n    };\n\n    void jpeg_loader_error_exit (j_common_ptr cinfo)\n    {\n        /* cinfo->err really points to a jpeg_loader_error_mgr struct, so coerce pointer */\n        jpeg_loader_error_mgr* myerr = (jpeg_loader_error_mgr*) cinfo->err;\n        \n        /* Create the message */\n        ( *( cinfo->err->format_message ) ) ( cinfo, myerr->jpegLastErrorMsg );\n\n        /* Return control to the setjmp point */\n        longjmp(myerr->setjmp_buffer, 1);\n    }\n\n// ----------------------------------------------------------------------------------------\n    FILE * jpeg_loader::check_file( const char* filename )\n    {\n      if ( filename == NULL )\n      {\n          throw image_load_error(\"jpeg_loader: invalid filename, it is NULL\");\n      }\n      FILE *fp = fopen( filename, \"rb\" );\n      if ( !fp )\n      {\n          throw image_load_error(std::string(\"jpeg_loader: unable to open file \") + filename);\n      }\n      return fp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void jpeg_loader::read_image( FILE * file, const unsigned char* imgbuffer, size_t imgbuffersize )\n    {\n        \n        jpeg_decompress_struct cinfo;\n        jpeg_loader_error_mgr jerr;\n\n        cinfo.err = jpeg_std_error(&jerr.pub);\n\n        jerr.pub.error_exit = jpeg_loader_error_exit;\n\n        /* Establish the setjmp return context for my_error_exit to use. */\n        if (setjmp(jerr.setjmp_buffer)) \n        {\n            /* If we get here, the JPEG code has signaled an error.\n             * We need to clean up the JPEG object, and return.\n             */\n            jpeg_destroy_decompress(&cinfo);\n            if (file != NULL) fclose(file);\n            throw image_load_error(std::string(\"jpeg_loader: error while loading image: \") + jerr.jpegLastErrorMsg);\n        }\n\n\n        jpeg_create_decompress(&cinfo);\n        \n        if (file != NULL) jpeg_stdio_src(&cinfo, file);\n        else if (imgbuffer != NULL) jpeg_mem_src(&cinfo, (unsigned char*)imgbuffer, imgbuffersize);\n        else throw image_load_error(std::string(\"jpeg_loader: no valid image source\"));\n\n        jpeg_read_header(&cinfo, TRUE);\n\n        jpeg_start_decompress(&cinfo);\n\n        height_ = cinfo.output_height;\n        width_ = cinfo.output_width;\n        output_components_ = cinfo.output_components;\n\n        if (output_components_ != 1 && \n            output_components_ != 3 &&\n            output_components_ != 4)\n        {\n            if (file != NULL) fclose(file);\n            jpeg_destroy_decompress(&cinfo);\n            std::ostringstream sout;\n            sout << \"jpeg_loader: Unsupported number of colors (\" << output_components_ << \") in image\";\n            throw image_load_error(sout.str());\n        }\n\n        std::vector<unsigned char*> rows;\n        rows.resize(height_);\n\n        // size the image buffer\n        data.resize(height_*width_*output_components_);\n\n        // setup pointers to each row\n        for (size_t i = 0; i < rows.size(); ++i)\n            rows[i] = &data[i*width_*output_components_];\n\n        // read the data into the buffer\n        while (cinfo.output_scanline < cinfo.output_height)\n        {\n            jpeg_read_scanlines(&cinfo, &rows[cinfo.output_scanline], 100);\n        }\n\n        jpeg_finish_decompress(&cinfo);\n        jpeg_destroy_decompress(&cinfo);\n\n        if (file != NULL) fclose(file);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_JPEG_SUPPORT\n\n#endif // DLIB_JPEG_LOADER_CPp_\n\n\n"
  },
  {
    "path": "dlib/image_loader/jpeg_loader.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JPEG_IMPORT\n#define DLIB_JPEG_IMPORT\n\n#include <vector>\n\n#include \"jpeg_loader_abstract.h\"\n#include \"image_loader.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../test_for_odr_violations.h\"\n\nnamespace dlib\n{\n\n    class jpeg_loader : noncopyable\n    {\n    public:\n\n        jpeg_loader( const char* filename );\n        jpeg_loader( const std::string& filename );\n        jpeg_loader( const dlib::file& f );\n        jpeg_loader( const unsigned char* imgbuffer, size_t buffersize );\n\n        bool is_gray() const;\n        bool is_rgb() const;\n        bool is_rgba() const;\n        long nr() const;\n        long nc() const;\n\n        template<typename T>\n        void get_image( T& t_) const\n        {\n#ifndef DLIB_JPEG_SUPPORT\n            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                You are getting this error because you are trying to use the jpeg_loader\n                object but you haven't defined DLIB_JPEG_SUPPORT.  You must do so to use\n                this object.   You must also make sure you set your build environment\n                to link against the libjpeg library.\n            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n            COMPILE_TIME_ASSERT(sizeof(T) == 0);\n#endif\n            image_view<T> t(t_);\n            t.set_size( height_, width_ );\n            for (size_t n = 0; n < height_;n++ )\n            {\n                const unsigned char* v = get_row( n );\n                for (size_t m = 0; m < width_;m++ )\n                {\n                    if ( is_gray() )\n                    {\n                        unsigned char p = v[m];\n                        assign_pixel( t[n][m], p );\n                    }\n                    else if ( is_rgba() ) {\n                        rgb_alpha_pixel p;\n                        p.red = v[m*4];\n                        p.green = v[m*4+1];\n                        p.blue = v[m*4+2];\n                        p.alpha = v[m*4+3];\n                        assign_pixel( t[n][m], p );\n                    }\n                    else // if ( is_rgb() )\n                    {\n                        rgb_pixel p;\n                        p.red = v[m*3];\n                        p.green = v[m*3+1];\n                        p.blue = v[m*3+2];\n                        assign_pixel( t[n][m], p );\n                    }\n                }\n            }\n        }\n\n    private:\n        const unsigned char* get_row(size_t i) const\n        {\n            return &data[i*width_*output_components_];\n        }\n        \n        FILE * check_file(const char* filename );\n        void read_image( FILE *file, const unsigned char* imgbuffer, size_t imgbuffersize );\n        size_t height_; \n        size_t width_;\n        size_t output_components_;\n        std::vector<unsigned char> data;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const std::string& file_name\n    )\n    {\n        jpeg_loader(file_name).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n    )\n    {\n        jpeg_loader(imgbuff, imgbuffsize).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n    )\n    {\n        jpeg_loader(reinterpret_cast<const unsigned char*>(imgbuff), imgbuffsize).get_image(image);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"jpeg_loader.cpp\"\n#endif \n\n#endif // DLIB_JPEG_IMPORT \n\n\n"
  },
  {
    "path": "dlib/image_loader/jpeg_loader_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_JPEG_IMPORT_ABSTRACT\n#ifdef DLIB_JPEG_IMPORT_ABSTRACT\n\n#include \"image_loader_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    class jpeg_loader : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                Defined by the constructors\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a class capable of loading JPEG image files.\n                Once an instance of it is created to contain a JPEG file from\n                disk you can obtain the image stored in it via get_image().\n        !*/\n\n    public:\n\n        jpeg_loader( \n            const char* filename \n        );\n        /*!\n            ensures\n                - loads the JPEG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG file.\n        !*/\n\n        jpeg_loader( \n            const std::string& filename \n        );\n        /*!\n            ensures\n                - loads the JPEG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG file.\n        !*/\n\n        jpeg_loader( \n            const dlib::file& f \n        );\n        /*!\n            ensures\n                - loads the JPEG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG file.\n        !*/\n\n        jpeg_loader( \n            const unsigned char* imgbuffer,\n            size_t buffersize\n        );\n        /*!\n            ensures\n                - loads the JPEG from memory imgbuffer of size buffersize into this object\n            throws\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG buffer.\n        !*/\n\n        ~jpeg_loader(\n        );\n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        bool is_gray(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a grayscale image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n        \n        bool is_rgb(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a 3 channel RGB image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows (height) of the image contained by this\n                  object.\n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of colums (width) of the image contained by this\n                  object.\n        !*/\n\n        template<\n            typename image_type \n            >\n        void get_image( \n            image_type& img\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - loads the JPEG image stored in this object into img\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jpeg_loader(file_name).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jpeg_loader(imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_jpeg (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jpeg_loader((unsigned char*)imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_JPEG_IMPORT_ABSTRACT\n\n"
  },
  {
    "path": "dlib/image_loader/jxl_loader.cpp",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JXL_LOADER_CPp_\n#define DLIB_JXL_LOADER_CPp_\n\n// only do anything with this file if DLIB_JXL_SUPPORT is defined\n#ifdef DLIB_JXL_SUPPORT\n#include \"jxl_loader.h\"\n#include <jxl/decode_cxx.h>\n#include <jxl/resizable_parallel_runner_cxx.h>\n#include <fstream>\n\nnamespace dlib\n{\n\n    static std::vector<unsigned char> load_contents(const std::string& filename)\n    {\n        std::ifstream stream(filename, std::ios::binary);\n        stream.exceptions(std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);\n        std::vector<unsigned char> buffer;\n        vectorstream temp(buffer);\n        temp << stream.rdbuf();\n        return buffer;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jxl_loader::\n    jxl_loader(const char* filename) : height(0), width(0)\n    {\n        data = load_contents(filename);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jxl_loader::\n    jxl_loader(const std::string& filename) : height(0), width(0)\n    {\n        data = load_contents(filename);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jxl_loader::\n    jxl_loader(const dlib::file& f) : height(0), width(0)\n    {\n        data = load_contents(f.full_name());\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    jxl_loader::\n    jxl_loader(const unsigned char* imgbuffer, size_t imgbuffersize) : height(0), width(0)\n    {\n        data.resize(imgbuffersize);\n        memcpy(data.data(), imgbuffer, imgbuffersize);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool jxl_loader::is_gray() const { return depth == 1; }\n    bool jxl_loader::is_graya() const { return depth == 2; };\n    bool jxl_loader::is_rgb() const { return depth == 3; }\n    bool jxl_loader::is_rgba() const { return depth == 4; }\n    unsigned int jxl_loader::bit_depth() const { return bits_per_sample; };\n    long jxl_loader::nr() const { return static_cast<long>(height); };\n    long jxl_loader::nc() const { return static_cast<long>(width); };\n\n// ----------------------------------------------------------------------------------------\n\n    void jxl_loader::get_info()\n    {\n        JxlSignature signature = JxlSignatureCheck(data.data(), data.size());\n        if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER)\n        {\n            throw image_load_error(\"jxl_loader: JxlSignatureCheck failed\");\n        }\n\n        auto dec = JxlDecoderMake(nullptr);\n        if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BASIC_INFO))\n        {\n            throw image_load_error(\"jxl_loader: JxlDecoderSubscribeEvents failed\");\n        }\n\n        JxlDecoderSetInput(dec.get(), data.data(), data.size());\n        JxlDecoderCloseInput(dec.get());\n        if (JXL_DEC_BASIC_INFO != JxlDecoderProcessInput(dec.get())) {\n            throw image_load_error(\"jxl_loader: JxlDecoderProcessInput failed\");\n        }\n\n        JxlBasicInfo basic_info;\n        if (JXL_DEC_SUCCESS != JxlDecoderGetBasicInfo(dec.get(), &basic_info))\n        {\n            throw image_load_error(\"jxl_loader: JxlDecoderGetBasicInfo failed\");\n        }\n        width = basic_info.xsize;\n        height = basic_info.ysize;\n        depth = basic_info.num_color_channels + basic_info.num_extra_channels;\n        bits_per_sample = basic_info.bits_per_sample;\n    }\n// ----------------------------------------------------------------------------------------\n\n    void jxl_loader::decode(unsigned char* out, const size_t out_size) const\n    {\n        auto runner = JxlResizableParallelRunnerMake(nullptr);\n        auto dec = JxlDecoderMake(nullptr);\n        if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_FULL_IMAGE))\n        {\n            throw image_load_error(\"jxl_loader: JxlDecoderSubscribeEvents failed\");\n        }\n\n        if (JXL_DEC_SUCCESS != JxlDecoderSetParallelRunner(dec.get(), JxlResizableParallelRunner, runner.get()))\n        {\n            throw image_load_error(\"jxl_loader: JxlDecoderSetParallelRunner failed\");\n        }\n\n        if (JXL_DEC_SUCCESS != JxlDecoderSetInput(dec.get(), data.data(), data.size()))\n        {\n            throw image_load_error(\"jxl_loader: JxlDecoderSetInput failed\");\n        }\n        JxlDecoderCloseInput(dec.get());\n\n        JxlPixelFormat format = {\n            .num_channels = depth,\n            .data_type = JXL_TYPE_UINT8,\n            .endianness = JXL_NATIVE_ENDIAN,\n            .align=0\n        };\n        for (;;)\n        {\n            JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());\n            if (status == JXL_DEC_ERROR)\n            {\n                throw image_load_error(\"jxl_loader: JxlDecoderProcessInput failed\");\n            }\n            else if (status == JXL_DEC_NEED_MORE_INPUT)\n            {\n                throw image_load_error(\"jxl_loader: Error, expected more input\");\n            }\n            else if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER)\n            {\n                JxlResizableParallelRunnerSetThreads(runner.get(), JxlResizableParallelRunnerSuggestThreads(width, height));\n                size_t buffer_size;\n                if (JXL_DEC_SUCCESS != JxlDecoderImageOutBufferSize(dec.get(), &format, &buffer_size))\n                {\n                    throw image_load_error(\"jxl_loader: JxlDecoderImageOutBufferSize failed\");\n                }\n                if (buffer_size != width * height * depth)\n                {\n                    throw image_load_error(\"jxl_loader: invalid output buffer size\");\n                }\n                if (JXL_DEC_SUCCESS != JxlDecoderSetImageOutBuffer(dec.get(), &format, out, out_size))\n                {\n                    throw image_load_error(\"jxl_loader: JxlDecoderSetImageOutBuffer failed\");\n                }\n            }\n            else if (status == JXL_DEC_FULL_IMAGE)\n            {\n                // If the image is an animation, more full frames may be decoded.\n                // This loader only decodes the first one.\n                return;\n            }\n            else if (status == JXL_DEC_SUCCESS)\n            {\n                return;\n            }\n            else\n            {\n                throw image_load_error(\"jxl_loder: Unknown decoder status\");\n            }\n        }\n    }\n}\n\n#endif // DLIB_JXL_SUPPORT\n#endif // DLIB_JXL_LOADER_CPp_\n"
  },
  {
    "path": "dlib/image_loader/jxl_loader.h",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JXL_IMPORT\n#define DLIB_JXL_IMPORT\n\n#include <vector>\n\n#include \"jxl_loader_abstract.h\"\n#include \"image_loader.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../test_for_odr_violations.h\"\n\nnamespace dlib\n{\n\n    class jxl_loader : noncopyable\n    {\n    public:\n\n        jxl_loader(const char* filename);\n        jxl_loader(const std::string& filename);\n        jxl_loader(const dlib::file& f);\n        jxl_loader(const unsigned char* imgbuffer, size_t buffersize);\n\n        bool is_gray() const;\n        bool is_graya() const;\n        bool is_rgb() const;\n        bool is_rgba() const;\n        unsigned int bit_depth() const;\n        long nr() const;\n        long nc() const;\n\n        template<typename image_type>\n        void get_image(image_type& image) const\n        {\n#ifndef DLIB_JXL_SUPPORT\n            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                You are getting this error because you are trying to use the jxl_loader\n                object but you haven't defined DLIB_JXL_SUPPORT.  You must do so to use\n                this object.   You must also make sure you set your build environment\n                to link against the libjxl library.\n            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n            static_assert(sizeof(image_type) == 0, \"JPEG XL support not enabled.\");\n#endif\n            image_view<image_type> vimg(image);\n            vimg.set_size(height, width);\n            using pixel_type = typename image_traits<image_type>::pixel_type;\n\n            // Fast path: rgb, rgb_alpha, grayscale with matching input depth\n            if (pixel_traits<pixel_type>::num == depth && (\n                pixel_traits<pixel_type>::rgb ||\n                pixel_traits<pixel_type>::rgb_alpha ||\n                (pixel_traits<pixel_type>::grayscale &&\n                 std::is_same<typename pixel_traits<pixel_type>::basic_pixel_type, unsigned char>()))\n            )\n            {\n                const size_t output_size = width * height * depth;\n                unsigned char* output = reinterpret_cast<unsigned char*>(image_data(vimg));\n                decode(output, output_size);\n                return;\n            }\n\n            // Manual decoding: we still need to handle the case wether the input data has alpha.\n            if (depth == 4)\n            {\n                array2d<rgb_alpha_pixel> decoded;\n                decoded.set_size(height, width);\n                unsigned char* output = reinterpret_cast<unsigned char*>(image_data(decoded));\n                decode(output, width * height * depth);\n                assign_image(vimg, decoded);\n            }\n            else\n            {\n                array2d<rgb_pixel> decoded;\n                decoded.set_size(height, width);\n                unsigned char* output = reinterpret_cast<unsigned char*>(image_data(decoded));\n                decode(output, width * height * depth);\n                assign_image(vimg, decoded);\n            }\n        }\n\n    private:\n        void get_info();\n        void decode(unsigned char *out, const size_t out_size) const;\n        uint32_t height;\n        uint32_t width;\n        uint32_t depth;\n        uint32_t bits_per_sample;\n        std::vector<unsigned char> data;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const std::string& file_name\n    )\n    {\n        jxl_loader(file_name).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n    )\n    {\n        jxl_loader(imgbuff, imgbuffsize).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n    )\n    {\n        jxl_loader(reinterpret_cast<const unsigned char*>(imgbuff), imgbuffsize).get_image(image);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"jxl_loader.cpp\"\n#endif\n\n#endif // DLIB_JXL_IMPORT\n"
  },
  {
    "path": "dlib/image_loader/jxl_loader_abstract.h",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_JXL_IMPORT_ABSTRACT\n#ifdef DLIB_JXL_IMPORT_ABSTRACT\n\n#include \"image_loader_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    class jxl_loader : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a class capable of loading JPEG XL image files.\n                Once an instance of it is created to contain a JPEG XL file from\n                disk you can obtain the image stored in it via get_image().\n        !*/\n\n    public:\n\n        jxl_loader( \n            const char* filename \n        );\n        /*!\n            ensures\n                - loads the JPEG XL file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG XL file.\n        !*/\n\n        jxl_loader( \n            const std::string& filename \n        );\n        /*!\n            ensures\n                - loads the JPEG XL file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG XL file.\n        !*/\n\n        jxl_loader( \n            const dlib::file& f \n        );\n        /*!\n            ensures\n                - loads the JPEG XL file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG XL file.\n        !*/\n\n        jxl_loader( \n            const unsigned char* imgbuffer,\n            size_t buffersize\n        );\n        /*!\n            ensures\n                - loads the JPEG XL from memory imgbuffer of size buffersize into\n                  this object\n            throws\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given JPEG XL buffer.\n        !*/\n\n        ~jxl_loader(\n        );\n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        template<\n            typename image_type \n            >\n        void get_image( \n            image_type& img\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - loads the JPEG XL image stored in this object into img\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n        bool is_gray(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a grayscale image without an alpha channel)\n                  then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_graya(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a grayscale image with an alpha channel) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_rgb(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a 3 channel RGB image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_rgba(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a 4 channel RGB alpha image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        unsigned int bit_depth (\n        ) const;\n        /*!\n            ensures\n                - returns the number of bits per channel in the image contained by this\n                  object.\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows (height) of the image contained by this\n                  object.\n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of colums (width) of the image contained by this\n                  object.\n        !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jxl_loader(file_name).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jxl_loader(imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_jxl (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: jxl_loader((unsigned char*)imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_JXL_IMPORT_ABSTRACT\n\n"
  },
  {
    "path": "dlib/image_loader/load_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net), Nils Labugt, Changjiang Yang (yangcha@leidos.com)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOAd_IMAGE_Hh_\n#define DLIB_LOAd_IMAGE_Hh_\n\n#include \"load_image_abstract.h\"\n#include \"../string.h\"\n#include \"png_loader.h\"\n#include \"jpeg_loader.h\"\n#include \"webp_loader.h\"\n#include \"jxl_loader.h\"\n#include \"image_loader.h\"\n#include <fstream>\n#include <sstream>\n#ifdef DLIB_GIF_SUPPORT\n#include <gif_lib.h>\n#endif\n\nnamespace dlib\n{\n    namespace image_file_type\n    {\n        enum type\n        {\n            BMP,\n            JPG,\n            PNG,\n            DNG,\n            GIF,\n            WEBP,\n            JXL,\n            UNKNOWN\n        };\n\n        inline type read_type(const std::string& file_name) \n        {\n            std::ifstream file(file_name.c_str(), std::ios::in|std::ios::binary);\n            if (!file)\n                throw image_load_error(\"Unable to open file: \" + file_name);\n\n            char buffer[13];\n            file.read((char*)buffer, 12);\n            buffer[12] = 0;\n\n            // Determine the true image type using link:\n            // http://en.wikipedia.org/wiki/List_of_file_signatures\n            static const char *pngHeader = \"\\x89\\x50\\x4E\\x47\\x0D\\x0A\\x1A\\x0A\";\n            static const char *jxlHeader = \"\\x00\\x00\\x00\\x0C\\x4A\\x58\\x4C\\x20\\x0D\\x0A\\x87\\x0A\";\n\n            if (buffer[0]=='\\xff' && buffer[1]=='\\xd8' && buffer[2]=='\\xff') \n                return JPG;\n            else if (memcmp(buffer, pngHeader, strlen(pngHeader)) == 0)\n                return PNG;\n            else if (buffer[0]=='B' && buffer[1]=='M') \n                return BMP;\n            else if (buffer[0]=='D' && buffer[1]=='N' && buffer[2] == 'G') \n                return DNG;\n            else if (buffer[0]=='G' && buffer[1]=='I' && buffer[2] == 'F') \n                return GIF;\n            else if ((buffer[0] == '\\xff' && buffer[1] == '\\x0a') ||\n                      memcmp(buffer, jxlHeader, 12) == 0)  // we can't use strlen because the header starts with \\x00.\n                return JXL;\n            else if (buffer[0]=='R' && buffer[1]=='I' && buffer[2] == 'F' && buffer[3] == 'F' &&\n                    buffer[8]=='W' && buffer[9]=='E' && buffer[10] == 'B' && buffer[11] == 'P')\n                return WEBP;\n\n            return UNKNOWN;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// handle the differences in API between libgif v5 and older.\n#if defined(GIFLIB_MAJOR) && (GIFLIB_MAJOR > 5 || (GIFLIB_MAJOR == 5 && defined(GIFLIB_MINOR) && GIFLIB_MINOR >= 1))\n#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS ,0\n#else\n#define DLIB_GIFLIB_HANDLE_DIFF_VERSIONS \n#endif\n\n    template <typename image_type>\n    void load_image (\n        image_type& image,\n        const std::string& file_name\n    )\n    {\n        const image_file_type::type im_type = image_file_type::read_type(file_name);\n        switch (im_type)\n        {\n            case image_file_type::BMP: load_bmp(image, file_name); return;\n            case image_file_type::DNG: load_dng(image, file_name); return;\n#ifdef DLIB_PNG_SUPPORT\n            case image_file_type::PNG: load_png(image, file_name); return;\n#endif\n#ifdef DLIB_JPEG_SUPPORT\n            case image_file_type::JPG: load_jpeg(image, file_name); return;\n#endif\n#ifdef DLIB_WEBP_SUPPORT\n            case image_file_type::WEBP: load_webp(image, file_name); return;\n#endif\n#ifdef DLIB_JXL_SUPPORT\n            case image_file_type::JXL: load_jxl(image, file_name); return;\n#endif\n#ifdef DLIB_GIF_SUPPORT\n            case image_file_type::GIF: \n            {\n                image_view<image_type> img(image);\n                GifFileType* gif = DGifOpenFileName(file_name.c_str() DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);\n                try\n                {\n                    if (gif == 0) throw image_load_error(\"Couldn't open file \" + file_name);\n                    if (DGifSlurp(gif) != GIF_OK)\n                        throw image_load_error(\"Error reading from \" + file_name);\n\n                    if (gif->ImageCount != 1)   throw image_load_error(\"Dlib only supports reading GIF files containing one image.\");\n                    if (gif->SavedImages == 0)  throw image_load_error(\"Unsupported GIF format 1.\");\n\n                    ColorMapObject* cmo=gif->SColorMap?gif->SColorMap:gif->SavedImages->ImageDesc.ColorMap;\n\n                    if (cmo==0)                                             throw image_load_error(\"Unsupported GIF format 2.\");\n                    if (cmo->Colors == 0)                                   throw image_load_error(\"Unsupported GIF format 3.\");\n                    if (gif->SavedImages->ImageDesc.Width != gif->SWidth)   throw image_load_error(\"Unsupported GIF format 4.\");\n                    if (gif->SavedImages->ImageDesc.Height != gif->SHeight) throw image_load_error(\"Unsupported GIF format 5.\");\n                    if (gif->SavedImages->RasterBits == 0)                  throw image_load_error(\"Unsupported GIF format 6.\");\n                    if (gif->Image.Top != 0)                                throw image_load_error(\"Unsupported GIF format 7.\");\n                    if (gif->Image.Left != 0)                               throw image_load_error(\"Unsupported GIF format 8.\");\n\n                    img.set_size(gif->SHeight, gif->SWidth);\n                    unsigned char* raster = gif->SavedImages->RasterBits;\n                    GifColorType* colormap = cmo->Colors;\n                    if (gif->Image.Interlace) \n                    {\n                        const long interlaced_offset[] = { 0, 4, 2, 1 }; \n                        const long interlaced_jumps[] = { 8, 8, 4, 2 }; \n                        for (int i = 0; i < 4; ++i)\n                        {\n                            for (long r = interlaced_offset[i]; r < img.nr(); r += interlaced_jumps[i]) \n                            {\n                                for (long c = 0; c < img.nc(); ++c)\n                                {\n                                    if (*raster >= cmo->ColorCount)\n                                        throw image_load_error(\"Invalid GIF color value\");\n                                    rgb_pixel p;\n                                    p.red = colormap[*raster].Red;\n                                    p.green = colormap[*raster].Green;\n                                    p.blue = colormap[*raster].Blue;\n                                    assign_pixel(img[r][c], p);\n                                    ++raster;\n                                }\n                            }\n                        }\n                    }\n                    else \n                    {\n                        for (long r = 0; r < img.nr(); ++r)\n                        {\n                            for (long c = 0; c < img.nc(); ++c)\n                            {\n                                if (*raster >= cmo->ColorCount)\n                                    throw image_load_error(\"Invalid GIF color value\");\n                                rgb_pixel p;\n                                p.red = colormap[*raster].Red;\n                                p.green = colormap[*raster].Green;\n                                p.blue = colormap[*raster].Blue;\n                                assign_pixel(img[r][c], p);\n                                ++raster;\n                            }\n                        }\n                    }\n                    DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);\n                }\n                catch(...)\n                {\n                    if (gif)\n                        DGifCloseFile(gif DLIB_GIFLIB_HANDLE_DIFF_VERSIONS);\n                    throw;\n                }\n                return;\n            }\n#endif\n            default:  ;\n        }\n\n        if (im_type == image_file_type::JPG)\n        {\n            std::ostringstream sout;\n            sout << \"Unable to load image in file \" + file_name + \".\\n\" +\n                    \"You must #define DLIB_JPEG_SUPPORT and link to libjpeg to read JPEG files.\\n\" +\n                    \"Do this by following the instructions at http://dlib.net/compile.html.\\n\\n\";\n#ifdef _MSC_VER\n            sout << \"Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\\n\";\n            sout << \"field in Visual Studio's Property Pages window so it takes effect for your entire application.\";\n#else\n            sout << \"Note that you must cause DLIB_JPEG_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, use a compiler switch like -DDLIB_JPEG_SUPPORT\\n\";\n            sout << \"so it takes effect for your entire application.\";\n#endif\n            throw image_load_error(sout.str());\n        }\n        else if (im_type == image_file_type::PNG)\n        {\n            std::ostringstream sout;\n            sout << \"Unable to load image in file \" + file_name + \".\\n\" +\n                    \"You must #define DLIB_PNG_SUPPORT and link to libpng to read PNG files.\\n\" +\n                    \"Do this by following the instructions at http://dlib.net/compile.html.\\n\\n\";\n#ifdef _MSC_VER\n            sout << \"Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\\n\";\n            sout << \"field in Visual Studio's Property Pages window so it takes effect for your entire application.\\n\";\n#else\n            sout << \"Note that you must cause DLIB_PNG_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, use a compiler switch like -DDLIB_PNG_SUPPORT\\n\";\n            sout << \"so it takes effect for your entire application.\";\n#endif\n            throw image_load_error(sout.str());\n        }\n        else if (im_type == image_file_type::GIF)\n        {\n            std::ostringstream sout;\n            sout << \"Unable to load image in file \" + file_name + \".\\n\" +\n                    \"You must #define DLIB_GIF_SUPPORT and link to libgif to read GIF files.\\n\\n\";\n#ifdef _MSC_VER\n            sout << \"Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\\n\";\n            sout << \"field in Visual Studio's Property Pages window so it takes effect for your entire application.\\n\";\n#else\n            sout << \"Note that you must cause DLIB_GIF_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, use a compiler switch like -DDLIB_GIF_SUPPORT\\n\";\n            sout << \"so it takes effect for your entire application.\";\n#endif\n            throw image_load_error(sout.str());\n        }\n        else if (im_type == image_file_type::WEBP)\n        {\n            std::ostringstream sout;\n            sout << \"Unable to load image in file \" + file_name + \".\\n\" +\n                    \"You must #define DLIB_WEBP_SUPPORT and link to libwebp to read WebP files.\\n\" +\n                    \"Do this by following the instructions at http://dlib.net/compile.html.\\n\\n\";\n#ifdef _MSC_VER\n            sout << \"Note that you must cause DLIB_WEBP_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\\n\";\n            sout << \"field in Visual Studio's Property Pages window so it takes effect for your entire application.\";\n#else\n            sout << \"Note that you must cause DLIB_WEBP_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, use a compiler switch like -DDLIB_WEBP_SUPPORT\\n\";\n            sout << \"so it takes effect for your entire application.\";\n#endif\n            throw image_load_error(sout.str());\n        }\n        else if (im_type == image_file_type::JXL)\n        {\n            std::ostringstream sout;\n            sout << \"Unable to load image in file \" + file_name + \".\\n\" +\n                    \"You must #define DLIB_JXL_SUPPORT and link to libjxl to read JPEG XL files.\\n\" +\n                    \"Do this by following the instructions at http://dlib.net/compile.html.\\n\\n\";\n#ifdef _MSC_VER\n            sout << \"Note that you must cause DLIB_JXL_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, add it to the C/C++->Preprocessor->Preprocessor Definitions\\n\";\n            sout << \"field in Visual Studio's Property Pages window so it takes effect for your entire application.\";\n#else\n            sout << \"Note that you must cause DLIB_JXL_SUPPORT to be defined for your entire project.\\n\";\n            sout << \"So don't #define it in one file. Instead, use a compiler switch like -DDLIB_JXL_SUPPORT\\n\";\n            sout << \"so it takes effect for your entire application.\";\n#endif\n            throw image_load_error(sout.str());\n        }\n        else\n        {\n            throw image_load_error(\"Unknown image file format: Unable to load image in file \" + file_name);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LOAd_IMAGE_Hh_ \n\n"
  },
  {
    "path": "dlib/image_loader/load_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LOAd_IMAGE_ABSTRACT_\n#ifdef DLIB_LOAd_IMAGE_ABSTRACT_\n\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    template <typename image_type>\n    void load_image (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - This function loads an image from disk, in the indicated file file_name, and\n              writes it to the indicated image object.\n            - It is capable of reading the PNG, JPEG, BMP, GIF, and DNG image formats.  It\n              is always capable of reading BMP and DNG images.  However, for PNG, JPEG, and\n              GIF you must #define DLIB_PNG_SUPPORT, DLIB_JPEG_SUPPORT, and\n              DLIB_GIF_SUPPORT respectively and link your program to libpng, libjpeg, and\n              libgif respectively.\n        throws\n            - image_load_error\n                This exception is thrown if there is some error that prevents\n                us from loading the given image file.\n    !*/\n\n}\n\n#endif // DLIB_LOAd_IMAGE_ABSTRACT_ \n\n \n"
  },
  {
    "path": "dlib/image_loader/png_loader.cpp",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PNG_LOADER_CPp_\n#define DLIB_PNG_LOADER_CPp_\n\n// only do anything with this file if DLIB_PNG_SUPPORT is defined\n#ifdef DLIB_PNG_SUPPORT\n\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"png_loader.h\"\n#include <png.h>\n#include \"../string.h\"\n#include \"../byte_orderer.h\"\n#include <sstream>\n#include <cstring>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    // Don't do anything when libpng calls us to tell us about an error.  Just return to \n    // our own code and throw an exception (at the long jump target).\n    void png_loader_user_error_fn_silent(png_structp  png_struct, png_const_charp ) \n    {\n        longjmp(png_jmpbuf(png_struct),1);\n    }\n\n    void png_loader_user_warning_fn_silent(png_structp , png_const_charp ) \n    {\n    }\n\n    void png_reader_callback(png_structp png, png_bytep data, png_size_t length)\n    {\n        using callback_t = std::function<std::size_t(char*,std::size_t)>;\n        callback_t* clb = static_cast<callback_t*>(png_get_io_ptr(png));\n        const auto ret = (*clb)((char*)data, length);\n        if (ret != length)\n            png_error(png, \"png_loader: read error in png_reader_callback\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void png_loader::load(std::function<std::size_t(char*,std::size_t)> clb)\n    {\n        // Read header\n        png_byte sig[8];\n        if (clb((char*)sig, 8) != 8)\n            throw image_load_error(\"png_loader: error reading file stream\");\n        if (png_sig_cmp(sig, 0, 8 ) != 0)\n            throw image_load_error(\"png_loader: format error\");\n\n        // Create structs\n        png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent );\n        if (png_ptr == NULL)\n            throw image_load_error(\"Error while reading PNG file : png_create_read_struct()\");\n\n        png_infop info_ptr = png_create_info_struct( png_ptr );\n        if ( info_ptr == NULL )\n        {\n            png_destroy_read_struct(&png_ptr, ( png_infopp )NULL, ( png_infopp )NULL );\n            throw image_load_error(\"Error while reading PNG file : png_create_info_struct()\");\n        }\n\n        png_infop end_info = png_create_info_struct( png_ptr );\n        if ( end_info == NULL )\n        {\n            png_destroy_read_struct(&png_ptr, &info_ptr, ( png_infopp )NULL );\n            throw image_load_error(\"Error while reading PNG file : png_create_info_struct()\");\n        }\n\n        if (setjmp(png_jmpbuf(png_ptr)))\n        {\n            // If you get here, then there was an error while parsing.\n            png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);\n            throw image_load_error(\"png_loader: parse error\");\n        }\n\n        png_set_palette_to_rgb(png_ptr);\n        png_set_read_fn(png_ptr, &clb, png_reader_callback);\n        png_set_sig_bytes(png_ptr, 8);\n        // flags force one byte per channel output\n        byte_orderer bo;\n        int png_transforms = PNG_TRANSFORM_PACKING;\n        if (bo.host_is_little_endian())\n            png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;\n        png_read_png(png_ptr, info_ptr, png_transforms, NULL);\n\n        // If you get here, you are no longer affected by C's crazy longjmp \n        finalizer = std::shared_ptr<char>(new char, [=](char* ptr)  mutable {\n            delete ptr;\n            png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);\n        });\n\n        color_type        = png_get_color_type( png_ptr, info_ptr );\n        height            = png_get_image_height( png_ptr, info_ptr );\n        width             = png_get_image_width( png_ptr, info_ptr );\n        bit_depth_        = png_get_bit_depth( png_ptr, info_ptr );\n        rows              = (unsigned char**)png_get_rows( png_ptr, info_ptr );\n\n        if (!is_gray() && !is_graya() && !is_rgb() && !is_rgba())\n            throw image_load_error(\"png_loader: unsupported color type\");\n\n        if (bit_depth_ != 8 && bit_depth_ != 16)\n            throw image_load_error(\"png_loader: unsupported bit depth of \" + std::to_string(bit_depth_));\n\n        if (rows == NULL)\n            throw image_load_error(\"png_loader: parse error\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void png_loader::load(std::istream& in)\n    {\n        load([&](char* data, std::size_t ndata) {\n            in.read(data, ndata);\n            return in.gcount();\n        });\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    png_loader::png_loader(const unsigned char* image_buffer, std::size_t buffer_size)\n    {\n        std::size_t counter{0};\n        load([&](char* data, std::size_t ndata) {\n            ndata = std::min(ndata, buffer_size - counter);\n            std::memcpy(data, image_buffer + counter, ndata);\n            counter += ndata;\n            return ndata;\n        });\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    png_loader::png_loader(std::istream& in)\n    {\n        load(in);\n    }\n\n    png_loader::png_loader( const char* filename )\n    {\n        std::ifstream in(filename, std::ios::binary);\n        load(in);\n    }\n\n    png_loader::png_loader( const std::string& filename ) : png_loader(filename.c_str()) {}\n    png_loader::png_loader( const dlib::file& f )         : png_loader(f.full_name()) {}\n\n// ----------------------------------------------------------------------------------------\n\n    bool png_loader::is_gray()  const { return color_type == PNG_COLOR_TYPE_GRAY; }\n    bool png_loader::is_graya() const { return color_type == PNG_COLOR_TYPE_GRAY_ALPHA; }\n    bool png_loader::is_rgb()   const { return color_type == PNG_COLOR_TYPE_RGB; }\n    bool png_loader::is_rgba()  const { return color_type == PNG_COLOR_TYPE_RGB_ALPHA; }\n    unsigned int png_loader::bit_depth () const {return bit_depth_;}  \n    long png_loader::nr() const { return height; }\n    long png_loader::nc() const { return width; }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PNG_SUPPORT\n\n#endif // DLIB_PNG_LOADER_CPp_\n"
  },
  {
    "path": "dlib/image_loader/png_loader.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PNG_IMPORT\n#define DLIB_PNG_IMPORT\n\n#include <memory>\n#include <cstring>\n#include <functional>\n#include <istream>\n#include <fstream>\n\n#include \"png_loader_abstract.h\"\n#include \"image_loader.h\"\n#include \"../pixel.h\"\n#include \"../type_traits.h\"\n#include \"../test_for_odr_violations.h\"\n#include \"../dir_nav.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class png_loader : noncopyable\n    {\n    public:\n\n        png_loader( std::istream& in );\n        png_loader( const char* filename );\n        png_loader( const std::string& filename );\n        png_loader( const dlib::file& f );\n        png_loader( const unsigned char* image_buffer, std::size_t buffer_size );\n\n        bool is_gray()              const;\n        bool is_graya()             const;\n        bool is_rgb()               const;\n        bool is_rgba()              const;\n        unsigned int bit_depth ()   const;\n        long nr()                   const;\n        long nc()                   const;\n\n        template<class image_type>\n        void get_image(image_type& img) const \n        {\n#ifndef DLIB_PNG_SUPPORT\n            static_assert(sizeof(image_type) == 0, \"You are getting this error because you are trying to use the png_loader object but you haven't defined DLIB_PNG_SUPPORT.  You must do so to use this object.   You must also make sure you set your build environment to link against the libpng library.\");\n#else\n            using pixel_type = pixel_type_t<image_type>;\n            auto t = make_image_view(img);\n\n            t.set_size( height, width );\n\n            const auto assign_gray = [&](const auto** lines) \n            {\n                for ( int n = 0; n < height; ++n )\n                    for ( int m = 0; m < width; ++m )\n                        assign_pixel( t[n][m], lines[n][m]);\n            };\n\n            const auto assign_gray_alpha = [&](const auto** lines) \n            {\n                for ( int n = 0; n < height; ++n )\n                {\n                    for ( int m = 0; m < width; ++m )\n                    {\n                        if (!pixel_traits<pixel_type>::has_alpha)\n                        {\n                            assign_pixel(t[n][m], lines[n][m*2]);\n                        }\n                        else\n                        {\n                            rgb_alpha_pixel pix;\n                            assign_pixel(pix,       lines[n][m*2]);\n                            assign_pixel(pix.alpha, lines[n][m*2+1]);\n                            assign_pixel(t[n][m], pix);\n                        }\n                    }\n                }\n            };\n\n            const auto assign_rgb = [&](const auto** lines) \n            {\n                for ( int n = 0; n < height;++n )\n                {\n                    for ( int m = 0; m < width;++m )\n                    {\n                        rgb_pixel p;\n                        p.red   = static_cast<uint8>(lines[n][m*3]);\n                        p.green = static_cast<uint8>(lines[n][m*3+1]);\n                        p.blue  = static_cast<uint8>(lines[n][m*3+2]);\n                        assign_pixel( t[n][m], p );\n                    }\n                }\n            };\n\n            const auto assign_rgba = [&](const auto** lines) \n            {\n                if (!pixel_traits<pixel_type>::has_alpha)\n                    assign_all_pixels(t,0);\n\n                for ( int n = 0; n < height; ++n )\n                {\n                    for ( int m = 0; m < width; ++m )\n                    {\n                        rgb_alpha_pixel p;\n                        p.red   = static_cast<uint8>(lines[n][m*4]);\n                        p.green = static_cast<uint8>(lines[n][m*4+1]);\n                        p.blue  = static_cast<uint8>(lines[n][m*4+2]);\n                        p.alpha = static_cast<uint8>(lines[n][m*4+3]);\n                        assign_pixel( t[n][m], p );\n                    }\n                }\n            };\n\n            const auto assign = [&](const auto** lines)\n            {\n                if (is_gray())\n                    assign_gray(lines);\n\n                else if (is_graya())\n                    assign_gray_alpha(lines);\n                \n                else if (is_rgb())\n                    assign_rgb(lines);\n\n                else if (is_rgba())\n                    assign_rgba(lines);\n            };\n\n            if (bit_depth_ == 8)\n                assign((const uint8_t**)(rows));\n            \n            else if (bit_depth_ == 16)\n                assign((const uint16_t**)(rows));\n#endif\n        }\n\n    private:\n        void load(std::function<std::size_t(char*,std::size_t)> clb);\n        void load(std::istream& in);\n\n        int             height{0};\n        int             width{0};\n        int             bit_depth_{0};\n        int             color_type{0};\n        unsigned char** rows{nullptr};\n        std::shared_ptr<void> finalizer;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <class image_type>\n    void load_png (\n        image_type& img,\n        std::istream& in\n    )\n    {\n        png_loader(in).get_image(img);\n    }\n\n    template <class image_type>\n    void load_png (\n        image_type& img,\n        const std::string& file_name\n    )\n    {\n        png_loader(file_name).get_image(img);\n    }\n\n    template <\n      class image_type,\n      class Byte,\n      std::enable_if_t<is_byte<Byte>::value, bool> = true\n    >\n    void load_png (\n        image_type& img,\n        const Byte* image_buffer,\n        std::size_t buffer_size\n    )\n    {\n        png_loader((const unsigned char*)image_buffer, buffer_size).get_image(img);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"png_loader.cpp\"\n#endif \n\n#endif // DLIB_PNG_IMPORT\n"
  },
  {
    "path": "dlib/image_loader/png_loader_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_PNG_IMPORT_ABSTRACT\n#ifdef DLIB_PNG_IMPORT_ABSTRACT\n\n#include \"image_loader_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    class png_loader : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                Defined by the constructors\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a class capable of loading PNG image files.\n                Once an instance of it is created to contain a PNG file from\n                disk you can obtain the image stored in it via get_image().\n        !*/\n\n    public:\n\n        png_loader( \n            const char* filename \n        );\n        /*!\n            ensures\n                - loads the PNG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given PNG file.\n        !*/\n\n        png_loader( \n            const std::string& filename \n        );\n        /*!\n            ensures\n                - loads the PNG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given PNG file.\n        !*/\n\n        png_loader( \n            const dlib::file& f \n        );\n        /*!\n            ensures\n                - loads the PNG file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given PNG file.\n        !*/\n\n        png_loader( \n            const unsigned char* image_buffer,\n            size_t buffer_size\n        );\n        /*!\n            ensures\n                - loads the PNG from memory image_buffer of size buffer_size into this object\n            throws\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given PNG buffer.\n        !*/\n\n        png_loader( \n            std::istream& in\n        );\n        /*!\n            ensures\n                - loads the PNG file from the c++ IO stream into this object\n            throws\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given PNG buffer.\n        !*/\n\n        ~png_loader(\n        );\n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        bool is_gray(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a grayscale image without an alpha channel) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n        \n        bool is_graya(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a grayscale image with an alpha channel) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n        \n        bool is_rgb(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a 3 channel RGB image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_rgba(\n        ) const;\n        /*!\n            ensures\n                - if (this object contains a 4 channel RGB alpha image) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        unsigned int bit_depth (\n        ) const;\n        /*!\n            ensures\n                - returns the number of bits per channel in the image contained by this\n                  object.  The possible values are 8 or 16.\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows (height) of the image contained by this\n                  object.\n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of colums (width) of the image contained by this\n                  object.\n        !*/\n\n        template<\n            typename image_type \n            >\n        void get_image( \n            image_type& img\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - loads the PNG image stored in this object into img\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_png (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: png_loader(file_name).get_image(image);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename Byte\n        >\n    void load_png (\n        image_type& image,\n        const Byte* image_buffer,\n        size_t buffer_size\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - Byte is either char, int8_t, uint8_t or std::byte\n        ensures\n            - performs: png_loader(image_buffer, buffer_size).get_image(image);\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type\n    >\n    void load_png (\n        image_type& img,\n        std::istream& in\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in is an input stream containing a complete PNG encoded image\n        ensures\n            - Reads and ecodes the PNG file located in stream\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PNG_IMPORT_ABSTRACT\n"
  },
  {
    "path": "dlib/image_loader/webp_loader.cpp",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WEBP_LOADER_CPp_\n#define DLIB_WEBP_LOADER_CPp_\n\n// only do anything with this file if DLIB_WEBP_SUPPORT is defined\n#ifdef DLIB_WEBP_SUPPORT\n\n#include \"webp_loader.h\"\n\n#include <webp/decode.h>\n#include <fstream>\n\nnamespace dlib\n{\n\n    static std::vector<unsigned char> load_contents(const std::string& filename)\n    {\n        std::ifstream stream(filename, std::ios::binary);\n        stream.exceptions(std::ifstream::failbit | std::ifstream::badbit | std::ifstream::eofbit);\n        stream.seekg(0, std::ios_base::end);\n        std::vector<unsigned char> buffer(stream.tellg());\n        stream.seekg(0);\n        stream.read(reinterpret_cast<char*>(buffer.data()), buffer.size());\n        return buffer;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    webp_loader::\n    webp_loader(const char* filename) : height_(0), width_(0)\n    {\n        data_ = load_contents(filename);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    webp_loader::\n    webp_loader(const std::string& filename) : height_(0), width_(0)\n    {\n        data_ = load_contents(filename);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    webp_loader::\n    webp_loader(const dlib::file& f) : height_(0), width_(0)\n    {\n        data_ = load_contents(f.full_name());\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    webp_loader::\n    webp_loader(const unsigned char* imgbuffer, size_t imgbuffersize) : height_(0), width_(0)\n    {\n        data_.resize(imgbuffersize);\n        memcpy(data_.data(), imgbuffer, imgbuffersize);\n        get_info();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    long webp_loader::nr() const { return height_; }\n    long webp_loader::nc() const { return width_; }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::get_info()\n    {\n        if (!WebPGetInfo(data_.data(), data_.size(), &width_, &height_))\n        {\n            throw image_load_error(\"webp_loader: Invalid header\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::read_argb(unsigned char *out, const size_t out_size, const int out_stride) const\n    {\n        if (!WebPDecodeARGBInto(data_.data(), data_.size(), out, out_size, out_stride))\n        {\n            throw image_load_error(\"webp_loader: decoding failed\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::read_rgba(unsigned char *out, const size_t out_size, const int out_stride) const\n    {\n        if (!WebPDecodeRGBAInto(data_.data(), data_.size(), out, out_size, out_stride))\n        {\n            throw image_load_error(\"webp_loader: decoding failed\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::read_bgra(unsigned char *out, const size_t out_size, const int out_stride) const\n    {\n        if (!WebPDecodeBGRAInto(data_.data(), data_.size(), out, out_size, out_stride))\n        {\n            throw image_load_error(\"webp_loader: decoding failed\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::read_rgb(unsigned char *out, const size_t out_size, const int out_stride) const\n    {\n        if (!WebPDecodeRGBInto(data_.data(), data_.size(), out, out_size, out_stride))\n        {\n            throw image_load_error(\"webp_loader: decoding failed\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void webp_loader::read_bgr(unsigned char *out, const size_t out_size, const int out_stride) const\n    {\n        if (!WebPDecodeBGRInto(data_.data(), data_.size(), out, out_size, out_stride))\n        {\n            throw image_load_error(\"webp_loader: decoding failed\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WEBP_SUPPORT\n\n#endif // DLIB_WEBP_LOADER_CPp_\n\n"
  },
  {
    "path": "dlib/image_loader/webp_loader.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WEBP_IMPORT\n#define DLIB_WEBP_IMPORT\n\n#include <vector>\n\n#include \"webp_loader_abstract.h\"\n#include \"image_loader.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../test_for_odr_violations.h\"\n\nnamespace dlib\n{\n\n    class webp_loader : noncopyable\n    {\n    public:\n\n        webp_loader(const char* filename);\n        webp_loader(const std::string& filename);\n        webp_loader(const dlib::file& f);\n        webp_loader(const unsigned char* imgbuffer, size_t buffersize);\n\n        long nr() const;\n        long nc() const;\n\n        template<typename image_type>\n        void get_image(image_type& image) const\n        {\n#ifndef DLIB_WEBP_SUPPORT\n            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                You are getting this error because you are trying to use the webp_loader\n                object but you haven't defined DLIB_WEBP_SUPPORT.  You must do so to use\n                this object.   You must also make sure you set your build environment\n                to link against the libwebp library.\n            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n            static_assert(sizeof(image_type) == 0, \"webp support not enabled.\");\n#endif\n            image_view<image_type> vimg(image);\n            vimg.set_size(height_, width_);\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n\n            unsigned char* output = reinterpret_cast<unsigned char*>(image_data(vimg));\n            const int stride = width_step(vimg);\n            const size_t output_size = stride * height_;\n\n            if (pixel_traits<pixel_type>::rgb_alpha)\n            {\n                if (pixel_traits<pixel_type>::bgr_layout)\n                    read_bgra(output, output_size, stride);\n                else\n                    read_rgba(output, output_size, stride);\n                return;\n            }\n            if (pixel_traits<pixel_type>::rgb)\n            {\n                if (pixel_traits<pixel_type>::bgr_layout)\n                    read_bgr(output, output_size, stride);\n                else\n                    read_rgb(output, output_size, stride);\n                return;\n            }\n            // If we end up here, we are out of our fast path, and have to do it manually\n\n            array2d<rgb_alpha_pixel> decoded;\n            decoded.set_size(height_, width_);\n            unsigned char* output_dec = reinterpret_cast<unsigned char*>(image_data(decoded));\n            const int stride_dec = width_step(decoded);\n            const size_t output_dec_size = stride_dec * height_;\n\n            read_rgba(output_dec, output_dec_size, stride_dec);\n\n            for (int r = 0; r < height_; r++)\n            {\n                for (int c = 0; c < width_; c++)\n                {\n                    assign_pixel(vimg[r][c], decoded[r][c]);\n                }\n            }\n        }\n\n    private:\n        void get_info();\n        void read_bgra(unsigned char *out, const size_t out_size, const int out_stride) const;\n        void read_bgr(unsigned char *out, const size_t out_size, const int out_stride) const;\n        void read_rgba(unsigned char *out, const size_t out_size, const int out_stride) const;\n        void read_rgb(unsigned char *out, const size_t out_size, const int out_stride) const;\n        void read_argb(unsigned char *out, const size_t out_size, const int out_stride) const;\n\n        int height_;\n        int width_;\n        std::vector<unsigned char> data_;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const std::string& file_name\n   )\n    {\n        webp_loader(file_name).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n   )\n    {\n        webp_loader(imgbuff, imgbuffsize).get_image(image);\n    }\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n   )\n    {\n        webp_loader(reinterpret_cast<const unsigned char*>(imgbuff), imgbuffsize).get_image(image);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"webp_loader.cpp\"\n#endif\n\n#endif // DLIB_WEBP_IMPORT\n\n\n"
  },
  {
    "path": "dlib/image_loader/webp_loader_abstract.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Martin Sandsmark, Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_WEBP_IMPORT_ABSTRACT\n#ifdef DLIB_WEBP_IMPORT_ABSTRACT\n\n#include \"image_loader_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../dir_nav.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    class webp_loader : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a class capable of loading WEBP image files.\n                Once an instance of it is created to contain a WEBP file from\n                disk you can obtain the image stored in it via get_image().\n        !*/\n\n    public:\n\n        webp_loader( \n            const char* filename \n        );\n        /*!\n            ensures\n                - loads the WEBP file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given WEBP file.\n        !*/\n\n        webp_loader( \n            const std::string& filename \n        );\n        /*!\n            ensures\n                - loads the WEBP file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given WEBP file.\n        !*/\n\n        webp_loader( \n            const dlib::file& f \n        );\n        /*!\n            ensures\n                - loads the WEBP file with the given file name into this object\n            throws\n                - std::bad_alloc\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given WEBP file.\n        !*/\n\n        webp_loader( \n            const unsigned char* imgbuffer,\n            size_t buffersize\n        );\n        /*!\n            ensures\n                - loads the WEBP from memory imgbuffer of size buffersize into this object\n            throws\n                - image_load_error\n                  This exception is thrown if there is some error that prevents\n                  us from loading the given WEBP buffer.\n        !*/\n\n        ~webp_loader(\n        );\n        /*!\n            ensures\n                - all resources associated with *this has been released\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows (height) of the image contained by this\n                  object.\n        !*/\n\n        long nc (\n        ) const;\n        /*!\n            ensures\n                - returns the number of colums (width) of the image contained by this\n                  object.\n        !*/\n\n        template<\n            typename image_type \n            >\n        void get_image( \n            image_type& img\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - loads the WEBP image stored in this object into img\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: webp_loader(file_name).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const unsigned char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: webp_loader(imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n    template <\n        typename image_type\n        >\n    void load_webp (\n        image_type& image,\n        const char* imgbuff,\n        size_t imgbuffsize\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: webp_loader((unsigned char*)imgbuff, imgbuffsize).get_image(image);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WEBP_IMPORT_ABSTRACT\n\n"
  },
  {
    "path": "dlib/image_processing/box_overlap_testing.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BOX_OVERlAP_TESTING_Hh_\n#define DLIB_BOX_OVERlAP_TESTING_Hh_\n\n#include \"box_overlap_testing_abstract.h\"\n#include \"../geometry.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_intersection_over_union (\n        const drectangle& a,\n        const drectangle& b\n    ) \n    {\n        const double inner = a.intersect(b).area();\n        if (inner == 0)\n            return 0;\n        const double outer = a.area() + b.area() - inner;\n        return inner / outer;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_intersection_over_union (\n        const rectangle& a,\n        const rectangle& b\n    ) \n    {\n        return box_intersection_over_union(drectangle(a),drectangle(b));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_percent_covered (\n        const drectangle& a,\n        const drectangle& b\n    ) \n    {\n        const double inner = a.intersect(b).area();\n        if (inner == 0)\n            return 0;\n        return std::max(inner/a.area(), inner/b.area());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_percent_covered (\n        const rectangle& a,\n        const rectangle& b\n    ) \n    {\n        return box_percent_covered(drectangle(a), drectangle(b));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class test_box_overlap\n    {\n    public:\n        test_box_overlap (\n        ) : iou_thresh(0.5), percent_covered_thresh(1.0)\n        {}\n\n        explicit test_box_overlap (\n            double iou_thresh_,\n            double percent_covered_thresh_ = 1.0\n        ) : iou_thresh(iou_thresh_), percent_covered_thresh(percent_covered_thresh_) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(0 <= iou_thresh && iou_thresh <= 1  &&\n                        0 <= percent_covered_thresh && percent_covered_thresh <= 1,\n                \"\\t test_box_overlap::test_box_overlap(iou_thresh, percent_covered_thresh)\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t iou_thresh:   \" << iou_thresh\n                << \"\\n\\t percent_covered_thresh: \" << percent_covered_thresh\n                << \"\\n\\t this: \" << this\n                );\n\n        }\n\n        bool operator() (\n            const dlib::rectangle& a,\n            const dlib::rectangle& b\n        ) const\n        {\n            const double inner = a.intersect(b).area();\n            if (inner == 0)\n                return false;\n\n            const double outer = (a+b).area();\n            if (inner/outer > iou_thresh || \n                inner/a.area() > percent_covered_thresh || \n                inner/b.area() > percent_covered_thresh)\n                return true;\n            else\n                return false;\n        }\n\n        double get_percent_covered_thresh (\n        ) const\n        {\n            return percent_covered_thresh;\n        }\n\n        double get_iou_thresh (\n        ) const\n        {\n            return iou_thresh;\n        }\n\n    private:\n        double iou_thresh;\n        double percent_covered_thresh;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const test_box_overlap& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.get_iou_thresh(), out);\n        serialize(item.get_percent_covered_thresh(), out);\n    }\n\n    inline void deserialize (\n        test_box_overlap& item,\n        std::istream& in \n    )\n    {\n        double percent_covered_thresh, iou_thresh;\n        deserialize(iou_thresh, in);\n        deserialize(percent_covered_thresh, in);\n        item = test_box_overlap(iou_thresh, percent_covered_thresh);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline test_box_overlap find_tight_overlap_tester (\n        const std::vector<std::vector<rectangle> >& rects\n    )\n    {\n        double max_pcov = 0;\n        double max_iou_score = 0;\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            for (unsigned long j = 0; j < rects[i].size(); ++j)\n            {\n                for (unsigned long k = j+1; k < rects[i].size(); ++k)\n                {\n                    const rectangle a = rects[i][j];\n                    const rectangle b = rects[i][k];\n                    const double iou_score = (a.intersect(b)).area()/(double)(a+b).area();\n                    const double pcov_a   = (a.intersect(b)).area()/(double)(a).area();\n                    const double pcov_b   = (a.intersect(b)).area()/(double)(b).area();\n\n                    if (iou_score > max_iou_score)\n                        max_iou_score = iou_score;\n\n                    if (pcov_a > max_pcov)\n                        max_pcov = pcov_a;\n                    if (pcov_b > max_pcov)\n                        max_pcov = pcov_b;\n                }\n            }\n        }\n\n        // Relax these thresholds very slightly.  We do this because on some systems the\n        // boxes that generated the max values erroneously trigger a box overlap iou even\n        // though their percent covered and iou values are *equal* to the thresholds but\n        // not greater.  That is, sometimes when double values get moved around they change\n        // their values slightly, so this avoids the problems that can create.\n        max_iou_score = std::min(1.0000001*max_iou_score, 1.0);\n        max_pcov     = std::min(1.0000001*max_pcov,     1.0);\n        return test_box_overlap(max_iou_score, max_pcov);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool overlaps_any_box (\n        const test_box_overlap& tester,\n        const std::vector<rectangle>& rects,\n        const rectangle& rect\n    )\n    {\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            if (tester(rects[i],rect))\n                return true;\n        }\n        return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool overlaps_any_box (\n        const std::vector<rectangle>& rects,\n        const rectangle& rect\n    )\n    {\n        return overlaps_any_box(test_box_overlap(),rects,rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOX_OVERlAP_TESTING_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/box_overlap_testing_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_\n#ifdef DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_\n\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_intersection_over_union (\n        const drectangle& a,\n        const drectangle& b\n    );\n    /*!\n        ensures\n            - returns area of the intersection of a and b divided by the area covered by the union\n              of the boxes.  If both boxes are empty then returns 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_intersection_over_union (\n        const rectangle& a,\n        const rectangle& b\n    );\n    /*!\n        ensures\n            - returns area of the intersection of a and b divided by the area covered by the union\n              of the boxes.  If both boxes are empty then returns 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_percent_covered (\n        const drectangle& a,\n        const drectangle& b\n    ); \n    /*!\n        ensures\n            - let OVERLAP = a.intersect(b).area()\n            - This function returns max(OVERLAP/a.area(), OVERLAP/b.area())\n              e.g. If one box entirely contains another then this function returns 1, if\n              they don't overlap at all it returns 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double box_percent_covered (\n        const rectangle& a,\n        const rectangle& b\n    ); \n    /*!\n        ensures\n            - let OVERLAP = a.intersect(b).area()\n            - This function returns max(OVERLAP/a.area(), OVERLAP/b.area())\n              e.g. If one box entirely contains another then this function returns 1, if\n              they don't overlap at all it returns 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class test_box_overlap\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple function object for determining if two rectangles\n                overlap.  \n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is safe provided that \n                only const member functions are invoked.  Otherwise, access must be\n                protected by a mutex lock.\n        !*/\n\n    public:\n        test_box_overlap (\n        );\n        /*!\n            ensures\n                - #get_iou_thresh()   == 0.5\n                - #get_percent_covered_thresh() == 1.0\n        !*/\n\n        explicit test_box_overlap (\n            double iou_thresh,\n            double percent_covered_thresh = 1.0\n        );\n        /*!\n            requires\n                - 0 <= iou_thresh <= 1\n                - 0 <= percent_covered_thresh <= 1\n            ensures\n                - #get_iou_thresh() == iou_thresh \n                - #get_percent_covered_thresh() == percent_covered_thresh\n        !*/\n\n        bool operator() (\n            const dlib::rectangle& a,\n            const dlib::rectangle& b\n        ) const;\n        /*!\n            ensures\n                - returns true if a and b overlap \"enough\". This is defined precisely below.\n                - if (a.intersect(b).area()/(a+b).area() > get_iou_thresh() ||\n                      a.intersect(b).area()/a.area()     > get_percent_covered_thresh() ||\n                      a.intersect(b).area()/b.area()     > get_percent_covered_thresh() ) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        double get_iou_thresh (\n        ) const;\n        /*!\n            ensures\n                - returns the threshold used to determine if two rectangle's intersection\n                  over union value is big enough to be considered a match.  Note that the\n                  iou score varies from 0 to 1 and only becomes 1 when two rectangles are\n                  identical.\n        !*/\n\n        double get_percent_covered_thresh (\n        ) const;\n        /*!\n            ensures\n                - returns the threshold used to determine if two rectangles overlap.  This\n                  value is the percent of a rectangle's area covered by another rectangle.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const test_box_overlap& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support\n    !*/\n\n    void deserialize (\n        test_box_overlap& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    test_box_overlap find_tight_overlap_tester (\n        const std::vector<std::vector<rectangle> >& rects\n    );\n    /*!\n        ensures\n            - This function finds the most restrictive test_box_overlap object possible \n              that is consistent with the given set of sets of rectangles.  \n            - To be precise, this function finds and returns a test_box_overlap object \n              TBO such that:\n                - TBO.get_iou_thresh() and TBO.get_percent_covered_thresh() are as small\n                  as possible such that the following conditions are satisfied.\n                - for all valid i:\n                    - for all distinct rectangles A and B in rects[i]:\n                        - TBO(A,B) == false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool overlaps_any_box (\n        const test_box_overlap& tester,\n        const std::vector<rectangle>& rects,\n        const rectangle& rect\n    );\n    /*!\n        ensures\n            - returns true if rect overlaps any box in rects and false otherwise.  Overlap\n              is determined based on the given tester object.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool overlaps_any_box (\n        const std::vector<rectangle>& rects,\n        const rectangle& rect\n    );\n    /*!\n        ensures\n            - returns overlaps_any_box(test_box_overlap(), rects, rect)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_BOX_OVERlAP_TESTING_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/correlation_tracker.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CORRELATION_TrACKER_H_\n#define DLIB_CORRELATION_TrACKER_H_\n\n#include \"correlation_tracker_abstract.h\"\n#include \"../geometry.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../image_transforms/assign_image.h\"\n#include \"../image_transforms/interpolation.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class correlation_tracker\n    {\n    public:\n\n        explicit correlation_tracker (unsigned long filter_size = 6, \n            unsigned long num_scale_levels = 5, \n            unsigned long scale_window_size = 23,\n            double regularizer_space = 0.001,\n            double nu_space = 0.025,\n            double regularizer_scale = 0.001,\n            double nu_scale = 0.025,\n            double scale_pyramid_alpha = 1.020\n        ) \n            : filter_size(1 << filter_size), num_scale_levels(1 << num_scale_levels),\n            scale_window_size(scale_window_size),\n            regularizer_space(regularizer_space), nu_space(nu_space), \n            regularizer_scale(regularizer_scale), nu_scale(nu_scale),\n            scale_pyramid_alpha(scale_pyramid_alpha)\n        {\n            // Create the cosine mask used for space filtering.\n            mask = make_cosine_mask();\n\n            // Create the cosine mask used for the scale filtering.\n            scale_cos_mask.resize(get_num_scale_levels());\n            const long max_level = get_num_scale_levels()/2;\n            for (unsigned long k = 0; k < get_num_scale_levels(); ++k)\n            {\n                double dist = std::abs((double)k-max_level)/max_level*pi/2;\n                dist = std::min(dist, pi/2);\n                scale_cos_mask[k] = std::cos(dist);\n            }\n        }\n\n        template <typename image_type>\n        void start_track (\n            const image_type& img,\n            const drectangle& p\n        )\n        {\n            DLIB_CASSERT(p.is_empty() == false,\n                \"\\t void correlation_tracker::start_track()\"\n                << \"\\n\\t You can't give an empty rectangle.\"\n            );\n\n            B.set_size(0,0);\n\n            point_transform_affine tform = inv(make_chip(img, p, F));\n            for (unsigned long i = 0; i < F.size(); ++i)\n                fft_inplace(F[i]);\n            make_target_location_image(tform(center(p)), G);\n            A.resize(F.size());\n            for (unsigned long i = 0; i < F.size(); ++i)\n            {\n                A[i] = pointwise_multiply(G, F[i]);\n                B += squared(real(F[i]))+squared(imag(F[i]));\n            }\n\n            position = p;\n\n            // now do the scale space stuff\n            make_scale_space(img, Fs);\n            for (unsigned long i = 0; i < Fs.size(); ++i)\n                fft_inplace(Fs[i]);\n            make_scale_target_location_image(get_num_scale_levels()/2, Gs);\n            Bs.set_size(0);\n            As.resize(Fs.size());\n            for (unsigned long i = 0; i < Fs.size(); ++i)\n            {\n                As[i] = pointwise_multiply(Gs, Fs[i]);\n                Bs += squared(real(Fs[i]))+squared(imag(Fs[i]));\n            }\n        }\n\n\n        unsigned long get_filter_size (\n        ) const { return filter_size; } \n\n        unsigned long get_num_scale_levels(\n        ) const { return num_scale_levels; }  \n\n        unsigned long get_scale_window_size (\n        ) const { return scale_window_size; }\n\n        double get_regularizer_space (\n        ) const { return regularizer_space; }\n        inline double get_nu_space (\n        ) const { return nu_space;}\n\n        double get_regularizer_scale (\n        ) const { return regularizer_scale; }\n        double get_nu_scale (\n        ) const { return nu_scale;}\n\n        drectangle get_position (\n        ) const \n        { \n            return position;\n        }\n\n        double get_scale_pyramid_alpha (\n        ) const { return scale_pyramid_alpha; }\n\n\n        template <typename image_type>\n        double update_noscale(\n            const image_type& img,\n            const drectangle& guess\n        )\n        {\n            DLIB_CASSERT(get_position().is_empty() == false,\n                \"\\t double correlation_tracker::update()\"\n                << \"\\n\\t You must call start_track() first before calling update().\"\n            );\n\n\n            const point_transform_affine tform = make_chip(img, guess, F);\n            for (unsigned long i = 0; i < F.size(); ++i)\n                fft_inplace(F[i]);\n\n            // use the current filter to predict the object's location\n            G = 0;\n            for (unsigned long i = 0; i < F.size(); ++i)\n                G += pointwise_multiply(F[i],conj(A[i]));\n            G = pointwise_multiply(G, reciprocal(B+get_regularizer_space()));\n            ifft_inplace(G);\n            const dlib::vector<double,2> pp = max_point_interpolated(real(G));\n\n\n            // Compute the peak to side lobe ratio.\n            const point p = pp;\n            running_stats<double> rs;\n            const rectangle peak = centered_rect(p, 8,8);\n            for (long r = 0; r < G.nr(); ++r)\n            {\n                for (long c = 0; c < G.nc(); ++c)\n                {\n                    if (!peak.contains(point(c,r)))\n                        rs.add(G(r,c).real());\n                }\n            }\n            const double psr = (G(p.y(),p.x()).real()-rs.mean())/rs.stddev();\n\n            // update the position of the object\n            position = translate_rect(guess, tform(pp)-center(guess));\n\n            // now update the position filters\n            make_target_location_image(pp, G);\n            B *= (1-get_nu_space());\n            for (unsigned long i = 0; i < F.size(); ++i)\n            {\n                A[i] = get_nu_space()*pointwise_multiply(G, F[i]) + (1-get_nu_space())*A[i];\n                B += get_nu_space()*(squared(real(F[i]))+squared(imag(F[i])));\n            }\n\n            return psr;\n        }\n\n        template <typename image_type>\n        double update (\n            const image_type& img,\n            const drectangle& guess\n        )\n        {\n            double psr = update_noscale(img, guess);\n\n            // Now predict the scale change\n            make_scale_space(img, Fs);\n            for (unsigned long i = 0; i < Fs.size(); ++i)\n                fft_inplace(Fs[i]);\n            Gs = 0;\n            for (unsigned long i = 0; i < Fs.size(); ++i)\n                Gs += pointwise_multiply(Fs[i],conj(As[i]));\n            Gs = pointwise_multiply(Gs, reciprocal(Bs+get_regularizer_scale()));\n            ifft_inplace(Gs);\n            const double pos = max_point_interpolated(real(Gs)).y();\n\n            // update the rectangle's scale\n            position *= std::pow(get_scale_pyramid_alpha(), pos-(double)get_num_scale_levels()/2);\n\n\n\n            // Now update the scale filters\n            make_scale_target_location_image(pos, Gs);\n            Bs *= (1-get_nu_scale());\n            for (unsigned long i = 0; i < Fs.size(); ++i)\n            {\n                As[i] = get_nu_scale()*pointwise_multiply(Gs, Fs[i]) + (1-get_nu_scale())*As[i];\n                Bs += get_nu_scale()*(squared(real(Fs[i]))+squared(imag(Fs[i])));\n            }\n\n\n            return psr;\n        }\n\n        template <typename image_type>\n        double update_noscale (\n            const image_type& img\n        )\n        {\n            return update_noscale(img, get_position());\n        }\n\n        template <typename image_type>\n        double update(\n            const image_type& img\n            )\n        {\n            return update(img, get_position());\n        }\n\n    private:\n\n        template <typename image_type>\n        void make_scale_space(\n            const image_type& img,\n            std::vector<matrix<std::complex<double>,0,1> >& Fs\n        ) const\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n\n            // Make an image pyramid and put it into the chips array.\n            const long chip_size = get_scale_window_size();\n            drectangle ppp = position*std::pow(get_scale_pyramid_alpha(), -(double)get_num_scale_levels()/2);\n            dlib::array<array2d<pixel_type> > chips;\n            std::vector<dlib::vector<double,2> > from_points, to_points;\n            from_points.push_back(point(0,0));\n            from_points.push_back(point(chip_size-1,0));\n            from_points.push_back(point(chip_size-1,chip_size-1));\n            for (unsigned long i = 0; i < get_num_scale_levels(); ++i)\n            {\n                array2d<pixel_type> chip(chip_size,chip_size);\n\n                // pull box into chip\n                to_points.clear();\n                to_points.push_back(ppp.tl_corner());\n                to_points.push_back(ppp.tr_corner());\n                to_points.push_back(ppp.br_corner());\n                transform_image(img,chip,interpolate_bilinear(),find_affine_transform(from_points, to_points));\n\n                chips.push_back(chip);\n                ppp *= get_scale_pyramid_alpha();\n            }\n\n\n            // extract HOG for each chip\n            dlib::array<dlib::array<array2d<float> > > hogs(chips.size());\n            for (unsigned long i = 0; i < chips.size(); ++i)\n            {\n                extract_fhog_features(chips[i], hogs[i], 4);\n                hogs[i].resize(32);\n                assign_image(hogs[i][31], chips[i]);\n                assign_image(hogs[i][31], mat(hogs[i][31])/255.0);\n            }\n\n            // Now copy the hog features into the Fs outputs and also apply the cosine\n            // windowing.\n            Fs.resize(hogs[0].size()*hogs[0][0].size());\n            unsigned long i = 0; \n            for (long r = 0; r < hogs[0][0].nr(); ++r)\n            {\n                for (long c = 0; c < hogs[0][0].nc(); ++c)\n                {\n                    for (unsigned long j = 0; j < hogs[0].size(); ++j)\n                    {\n                        Fs[i].set_size(hogs.size());\n                        for (unsigned long k = 0; k < hogs.size(); ++k)\n                        {\n                            Fs[i](k) = hogs[k][j][r][c]*scale_cos_mask[k];\n                        }\n                        ++i;\n                    }\n                }\n            } \n        }\n\n        template <typename image_type>\n        point_transform_affine make_chip (\n            const image_type& img,\n            drectangle p,\n            std::vector<matrix<std::complex<double> > >& chip\n        ) const\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            array2d<pixel_type> temp;\n            const double padding = 1.4;\n            const chip_details details(p*padding, chip_dims(get_filter_size(), get_filter_size()));\n            extract_image_chip(img, details, temp);\n\n\n            chip.resize(32);\n            dlib::array<array2d<float> > hog;\n            extract_fhog_features(temp, hog, 1, 3,3 );\n            for (unsigned long i = 0; i < hog.size(); ++i)\n                assign_image(chip[i], pointwise_multiply(matrix_cast<double>(mat(hog[i])), mask));\n\n            assign_image(chip[31], temp);\n            assign_image(chip[31], pointwise_multiply(mat(chip[31]), mask)/255.0);\n\n            return inv(get_mapping_to_chip(details));\n        }\n\n        void make_target_location_image (\n            const dlib::vector<double,2>& p,\n            matrix<std::complex<double> >& g\n        ) const\n        {\n            g.set_size(get_filter_size(), get_filter_size());\n            g = 0;\n            rectangle area = centered_rect(p, 21,21).intersect(get_rect(g));\n            for (long r = area.top(); r <= area.bottom(); ++r)\n            {\n                for (long c = area.left(); c <= area.right(); ++c)\n                {\n                    double dist = length(point(c,r)-p);\n                    g(r,c) = std::exp(-dist/3.0);\n                }\n            }\n            fft_inplace(g);\n            g = conj(g);\n        }\n\n\n        void make_scale_target_location_image (\n            const double scale,\n            matrix<std::complex<double>,0,1>& g\n        ) const\n        {\n            g.set_size(get_num_scale_levels());\n            for (long i = 0; i < g.size(); ++i)\n            {\n                double dist = std::pow((i-scale),2.0);\n                g(i) = std::exp(-dist/1.000);\n            }\n            fft_inplace(g);\n            g = conj(g);\n        }\n\n        matrix<double> make_cosine_mask (\n        ) const\n        {\n            const long size = get_filter_size();\n            matrix<double> temp(size,size);\n            point cent = center(get_rect(temp));\n            for (long r = 0; r < temp.nr(); ++r)\n            {\n                for (long c = 0; c < temp.nc(); ++c)\n                {\n                    point delta = point(c,r)-cent;\n                    double dist = length(delta)/(size/2.0)*(pi/2);\n                    dist = std::min(dist*1.0, pi/2);\n\n                    temp(r,c) = std::cos(dist);\n                }\n            }\n            return temp;\n        }\n\n\n        std::vector<matrix<std::complex<double> > > A, F;\n        matrix<double> B;\n\n        std::vector<matrix<std::complex<double>,0,1> > As, Fs;\n        matrix<double,0,1> Bs;\n        drectangle position;\n\n        matrix<double> mask;\n        std::vector<double> scale_cos_mask;\n\n        // G and Gs do not logically contribute to the state of this object.  They are\n        // here just so we can void reallocating them over and over.\n        matrix<std::complex<double> > G;\n        matrix<std::complex<double>,0,1> Gs;\n\n        unsigned long filter_size;\n        unsigned long num_scale_levels;\n        unsigned long scale_window_size;\n        double regularizer_space;\n        double nu_space;\n        double regularizer_scale;\n        double nu_scale;\n        double scale_pyramid_alpha;\n    };\n}\n\n#endif // DLIB_CORRELATION_TrACKER_H_\n\n"
  },
  {
    "path": "dlib/image_processing/correlation_tracker_abstract.h",
    "content": "// Copyright (C) 2015  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CORRELATION_TrACKER_ABSTRACT_H_\n#ifdef DLIB_CORRELATION_TrACKER_ABSTRACT_H_\n\n#include \"../geometry/drectangle_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class correlation_tracker\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for tracking moving objects in a video stream.  You give it\n                the bounding box of an object in the first frame and it attempts to track the\n                object in the box from frame to frame.  \n\n                This tool is an implementation of the method described in the following paper:\n                    Danelljan, Martin, et al. \"Accurate scale estimation for robust visual\n                    tracking.\" Proceedings of the British Machine Vision Conference BMVC. 2014.\n        !*/\n\n    public:\n\n        explicit correlation_tracker (unsigned long filter_size = 6, \n            unsigned long num_scale_levels = 5, \n            unsigned long scale_window_size = 23,\n            double regularizer_space = 0.001,\n            double nu_space = 0.025,\n            double regularizer_scale = 0.001,\n            double nu_scale = 0.025,\n            double scale_pyramid_alpha = 1.020\n        );\n        /*!\n            requires\n                - p.is_empty() == false\n            ensures\n                - Initializes correlation_tracker. Higher value of filter_size and \n                  num_scale_levels increases tracking precision but requires more CPU \n                  for processing. Recommended values for filter_size = 5-7, \n                  default = 6, for num_scale_levels = 4-6, default = 5\n                - #get_position().is_empty() == true\n        !*/\n\n        template <\n            typename image_type\n            >\n        void start_track (\n            const image_type& img,\n            const drectangle& p\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - p.is_empty() == false\n            ensures\n                - This object will start tracking the thing inside the bounding box in the\n                  given image.  That is, if you call update() with subsequent video frames \n                  then it will try to keep track of the position of the object inside p.\n                - #get_position() == p\n        !*/\n\n        drectangle get_position (\n        ) const;\n        /*!\n            ensures\n                - returns the predicted position of the object under track.  \n        !*/\n\n        template <\n            typename image_type\n            >\n        double update_noscale (\n            const image_type& img,\n            const drectangle& guess\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - get_position().is_empty() == false\n                  (i.e. you must have started tracking by calling start_track())\n            ensures\n                - When searching for the object in img, we search in the area around the\n                  provided guess. This function only tracks object position without trying\n                  to track the scale\n                - #get_position() == the new predicted location of the object in img.  This\n                  location will be a copy of guess that has been translated and NOT scaled\n                  appropriately based on the content of img so that it, hopefully, bounds\n                  the object in img.\n                - Returns the peak to side-lobe ratio.  This is a number that measures how\n                  confident the tracker is that the object is inside #get_position().\n                  Larger values indicate higher confidence.\n        !*/\n\n        template <\n            typename image_type\n            >\n        double update (\n            const image_type& img,\n            const drectangle& guess\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - get_position().is_empty() == false\n                  (i.e. you must have started tracking by calling start_track())\n            ensures\n                - When searching for the object in img, we search in the area around the\n                  provided guess.\n                - #get_position() == the new predicted location of the object in img.  This\n                  location will be a copy of guess that has been translated and scaled\n                  appropriately based on the content of img so that it, hopefully, bounds\n                  the object in img.\n                - Returns the peak to side-lobe ratio.  This is a number that measures how\n                  confident the tracker is that the object is inside #get_position().\n                  Larger values indicate higher confidence.\n        !*/\n\n        template <\n            typename image_type\n            >\n        double update_noscale (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - get_position().is_empty() == false\n                  (i.e. you must have started tracking by calling start_track())\n            ensures\n                - performs: return update_noscale(img, get_position())\n        !*/\n        template <\n            typename image_type\n            >\n        double update (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - get_position().is_empty() == false\n                  (i.e. you must have started tracking by calling start_track())\n            ensures\n                - performs: return update(img, get_position())\n        !*/\n\n    };\n}\n\n#endif // DLIB_CORRELATION_TrACKER_ABSTRACT_H_\n\n\n\n"
  },
  {
    "path": "dlib/image_processing/detection_template_tools.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DETECTION_TEMPlATE_TOOLS_Hh_\n#define DLIB_DETECTION_TEMPlATE_TOOLS_Hh_\n\n#include \"detection_template_tools_abstract.h\"\n#include \"../geometry.h\"\n#include \"../matrix.h\"\n#include <utility>\n#include <vector>\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle compute_box_dimensions (\n        const double width_to_height_ratio,\n        const double area\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(width_to_height_ratio > 0 && area > 0,\n            \"\\t rectangle compute_box_dimensions()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t width_to_height_ratio: \" << width_to_height_ratio\n            << \"\\n\\t area: \" << area \n            );\n\n        /*\n            width*height == area\n            width/height == width_to_height_ratio\n        */\n\n        const int height = (int)std::floor(std::sqrt(area/width_to_height_ratio) + 0.5);\n        const int width  = (int)std::floor(area/height + 0.5);\n\n        return centered_rect(0,0,width,height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<rectangle> create_single_box_detection_template (\n        const rectangle& object_box \n    )\n    {\n        std::vector<rectangle> temp;\n        temp.push_back(object_box);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<rectangle> create_overlapped_2x2_detection_template (\n        const rectangle& object_box \n    )\n    {\n        std::vector<rectangle> result;\n\n        const point c = center(object_box);\n\n        result.push_back(rectangle() + c + object_box.tl_corner() + object_box.tr_corner());\n        result.push_back(rectangle() + c + object_box.bl_corner() + object_box.br_corner());\n        result.push_back(rectangle() + c + object_box.tl_corner() + object_box.bl_corner());\n        result.push_back(rectangle() + c + object_box.tr_corner() + object_box.br_corner());\n\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<rectangle> create_grid_detection_template (\n        const rectangle& object_box,\n        unsigned int cells_x,\n        unsigned int cells_y\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(cells_x > 0 && cells_y > 0,\n            \"\\t std::vector<rectangle> create_grid_detection_template()\"\n            << \"\\n\\t The number of cells along a dimension can't be zero. \"\n            << \"\\n\\t cells_x: \" << cells_x\n            << \"\\n\\t cells_y: \" << cells_y\n            );\n\n        std::vector<rectangle> result;\n\n        const matrix<double,1> x = linspace(object_box.left(), object_box.right(), cells_x+1);\n        const matrix<double,1> y = linspace(object_box.top(), object_box.bottom(), cells_y+1);\n\n        for (long j = 0; j+1 < y.size(); ++j)\n        {\n            for (long i = 0; i+1 < x.size(); ++i)\n            {\n                const dlib::vector<double,2> tl(x(i),y(j));\n                const dlib::vector<double,2> br(x(i+1),y(j+1));\n                result.push_back(rectangle(tl,br));\n            }\n        }\n\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // DLIB_DETECTION_TEMPlATE_TOOLS_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/detection_template_tools_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_\n#ifdef DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_\n\n#include \"../geometry.h\"\n#include <utility>\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    rectangle compute_box_dimensions (\n        const double width_to_height_ratio,\n        const double area\n    );\n    /*!\n        requires\n            - area > 0\n            - width_to_height_ratio > 0\n        ensures\n            - returns a rectangle with the given area and width_to_height_ratio.\n            - In particular, returns a rectangle R such that:\n                - R.area() == area (to within integer precision)\n                - R.width()/R.height() == width_to_height_ratio (to within integer precision)\n                - center(R) == point(0,0)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<rectangle> create_single_box_detection_template (\n        const rectangle& object_box \n    );\n    /*!\n        ensures\n            - returns a vector that contains only object_box.  \n            - In particular, returns a vector V such that:\n                - V.size() == 1\n                - V[0] == object_box\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<rectangle> create_overlapped_2x2_detection_template (\n        const rectangle& object_box \n    );\n    /*!\n        ensures\n            - Divides object_box up into four overlapping regions, the\n              top half, bottom half, left half, and right half.  These\n              four rectangles are returned inside a std::vector.\n            - In particular, returns a vector V such that:\n                - V.size() == 4\n                - V[0] == top half of object_box \n                - V[1] == bottom half of object_box \n                - V[2] == left half of object_box \n                - V[3] == right half of object_box \n                - for all valid i: object_box.contains(V[i]) == true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<rectangle> create_grid_detection_template (\n        const rectangle& object_box,\n        unsigned int cells_x,\n        unsigned int cells_y\n    );\n    /*!\n        requires\n            - cells_x > 0\n            - cells_y > 0\n        ensures\n            - Divides object_box up into a grid and returns a vector \n              containing all the rectangles corresponding to elements\n              of the grid.  Moreover, the grid will be cells_x elements\n              wide and cells_y elements tall.\n            - In particular, returns a vector V such that:\n                - V.size() == cells_x*cells_y \n                - for all valid i: \n                    - object_box.contains(V[i]) == true\n                    - V[i] == The rectangle corresponding to the ith grid\n                      element. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n#endif // DLIB_DETECTION_TEMPlATE_TOOLS_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/image_processing/frontal_face_detector.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FRONTAL_FACE_DETECTOr_Hh_\n#define DLIB_FRONTAL_FACE_DETECTOr_Hh_\n\n#include \"frontal_face_detector_abstract.h\"\n#include \"../image_processing/object_detector.h\"\n#include \"../image_processing/scan_fhog_pyramid.h\"\n#include <sstream>\n#include \"../compress_stream.h\"\n#include \"../base64.h\"\n\nnamespace dlib\n{\n    typedef object_detector<scan_fhog_pyramid<pyramid_down<6> > > frontal_face_detector;\n    inline const std::string get_serialized_frontal_faces();\n\n    inline frontal_face_detector get_frontal_face_detector()\n    {\n        std::istringstream sin(get_serialized_frontal_faces());\n        frontal_face_detector detector;\n        deserialize(detector, sin);\n        return detector;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    /*\n        It is built out of 5 HOG filters. A front looking, left looking, right looking, \n        front looking but rotated left, and finally a front looking but rotated right one.\n        \n        Moreover, here is the training log and parameters used to generate the filters:\n        The front detector:\n            trained on mirrored set of labeled_faces_in_the_wild/frontal_faces.xml\n            upsampled each image by 2:1\n            used pyramid_down<6> \n            loss per missed target: 1\n            epsilon: 0.05\n            padding: 0\n            detection window size: 80 80\n            C: 700\n            nuclear norm regularizer: 9\n            cell_size: 8\n            num filters: 78\n            num images: 4748\n            Train detector (precision,recall,AP): 0.999793 0.895517 0.895368 \n            singular value threshold: 0.15\n\n        The left detector:\n            trained on labeled_faces_in_the_wild/left_faces.xml\n            upsampled each image by 2:1\n            used pyramid_down<6> \n            loss per missed target: 2\n            epsilon: 0.05\n            padding: 0\n            detection window size: 80 80\n            C: 250\n            nuclear norm regularizer: 8\n            cell_size: 8\n            num filters: 63\n            num images: 493\n            Train detector (precision,recall,AP): 0.991803  0.86019 0.859486 \n            singular value threshold: 0.15\n\n        The right detector:\n            trained left-right flip of labeled_faces_in_the_wild/left_faces.xml\n            upsampled each image by 2:1\n            used pyramid_down<6> \n            loss per missed target: 2\n            epsilon: 0.05\n            padding: 0\n            detection window size: 80 80\n            C: 250\n            nuclear norm regularizer: 8\n            cell_size: 8\n            num filters: 66\n            num images: 493\n            Train detector (precision,recall,AP): 0.991781  0.85782 0.857341 \n            singular value threshold: 0.19\n\n        The front-rotate-left detector:\n            trained on mirrored set of labeled_faces_in_the_wild/frontal_faces.xml\n            upsampled each image by 2:1\n            used pyramid_down<6> \n            rotated left 27 degrees\n            loss per missed target: 1\n            epsilon: 0.05\n            padding: 0\n            detection window size: 80 80\n            C: 700\n            nuclear norm regularizer: 9\n            cell_size: 8\n            num images: 4748\n            singular value threshold: 0.12\n\n        The front-rotate-right detector:\n            trained on mirrored set of labeled_faces_in_the_wild/frontal_faces.xml\n            upsampled each image by 2:1\n            used pyramid_down<6> \n            rotated right 27 degrees\n            loss per missed target: 1\n            epsilon: 0.05\n            padding: 0\n            detection window size: 80 80\n            C: 700\n            nuclear norm regularizer: 9\n            cell_size: 8\n            num filters: 89\n            num images: 4748\n            Train detector (precision,recall,AP):        1 0.897369 0.897369 \n            singular value threshold: 0.15\n    */\n    inline const std::string get_serialized_frontal_faces()\n    {\n        dlib::base64 base64_coder;\n        dlib::compress_stream::kernel_1ea compressor;\n        std::ostringstream sout;\n        std::istringstream sin;\n\n        // The base64 encoded data from the file 'object_detector.dat' we want to decode and return.\n        sout << \"AW2B5ZIvv09mlKLVYjKqbJC05yeR2KsCpPGEGOgn2QlwM92S4UT4HgQkV0V9WqYRf6xETTSVKz7Z\";\n        sout << \"YcJ84Jc4C3+VdPgZDhV+LDt6qAt3OI4nA9zN4Y9cCIb6ivlETkN/JMmapbOAUW2mrSzDif5zjAaq\";\n        sout << \"+NFvw/5V0Jciopw9tR6nYtV41unWGvyyfsO9CcqvDy81QIydToHh0a7UaL0jCtA2DYzkViDufxyv\";\n        sout << \"Kpsn4xMyiU0haM1ge3UktIO48io/gSzjEKu0YYAffbD2YO1IE34tUH15Z3Z9NjkBFxTytDgrMxk8\";\n        sout << \"i9MYq+Nl9nS421aogmec3ugExJYjLZMHs4KAk71jvG8vtJyJEA3qyLY6lvONt98gzQwGQ9+2B6de\";\n        sout << \"ocb/DDJUza6mvudHQNJBYraR4gCWcIn9gFu2rJiRHf4IiqP4GEB3B1zKiHfJRo9jZbhxQUitAxAx\";\n        sout << \"U/E2SuuHGZDilqK9AJ4K41RAudraxF9li/Bs4f+CK3G8Z/c97P7WLVekJL2ws+MsCdL9ObHE5ePD\";\n        sout << \"uLLQWBy5NUbgPVM6HEnhnOiZk3rA4DYNqbABy3uemablAln9BLGkk4wrm2UcicacnzY8Aq054Ttb\";\n        sout << \"3CCTcG4SOSPfePl/7T1M6Uy1hOesp5MpXfUR8gBKr4466dbdXCDHSahI05gra6NzxkOpOo2mOqBg\";\n        sout << \"LYNGZUkHK4tdRyyD12N1MH+nJiMJbgk+qj54t5i3AuEr/71HTRXoTT8AEYbvc9y4f2WAlliQYXPn\";\n        sout << \"O2Uaza3lKYrH7mFjKMNhLfvrezy9fe+1asbSlRKelnU3eY4lhD6fTVJjXqZypBfMnfmGQQJ0Q7g5\";\n        sout << \"1Z/9GzpRyZnPSzQljtJgzVp8Gk0z3fuKiXPO9g+s4XL2cEuxBOFij0KGTy4eNitM0gcPc6xzp3tz\";\n        sout << \"6Wv0W2h7w4h+V8Bzvyn8ag1sbEO0G1Lf2BrDVM9+pNxFoWFxYHqdoOmJPVvb8PRQqoC5bkqhplFr\";\n        sout << \"TR5l3XsQedgwsnkadxNZQ3MbRJyo0JU0kvV1cfphLcn24MIIKqAnw3daXqbJaba+oCUep5GTuzI7\";\n        sout << \"nad7ykHNN0iFkgYXMmXJl+F5TsS8y+izuHlXAX6wX1qRVzWJwCpM5oVVG/5eYTzg0J9C1bCcNyHL\";\n        sout << \"2w5TJFYrD8bq3O+Y3fiO5LJ8F5/vsu2EBUMi1+eP1WfsTwd6N9jFtF5gA5sHX3zI925aDqVx9byr\";\n        sout << \"j4X5yr68p5P6f8wSLL8jzW8i4a0yP3zXlqN6QQDY1ssfNsMf43tOTtmbBlmxviL2egs4gvadD7Gd\";\n        sout << \"fRNowL71P3mkqRmnrnihlI01NbDl+Trzsh3EOn43PRC9nl8yo+fYVH8GqS8JGy1xOw4G479vOifI\";\n        sout << \"9GC4BGnSDJdKgSnBwI1AJQ2TT8EZ//56lkRlgusg25TwC7uQ1zreeL6baYdgfXSggx3ULdNDGl5o\";\n        sout << \"ftRK9LDaop6XvB6I0ITsLYvAoGP/5sHfttDj6HlQW/LlzkSPmzY/FtV6h6bE+k1gG7BANrQjwOW5\";\n        sout << \"sfHNYadD1v4zIFdt2su3docGbGP/iDMvM+BmYIBP86zX5eIlTYwDmxXht95T6GCCjS/XuMMy12hd\";\n        sout << \"Fdb6lm1O42ieM4KQ/2EOFy3Ij+YOIapzYA6p6Jz9dtINpCojgUHyo6xc4HTNnEKRy+YN+awhb1l2\";\n        sout << \"FJdy2/QI3xGVNNTnWcQrsvjGZb/Z3VaZUltrIbnCeEZOeOCM0TxkBEhqFfI3qwMx8PUj+imUlTDM\";\n        sout << \"7N+p5sxmKLliHHovOO32ajBTKUSI9IMQzf3QY6dZDts4JkMYQ1xc6lpm679s1KMVVrWuOqiAU5Vs\";\n        sout << \"qehfnl+oMRngi0G0BnMne45CjU5RECvhg+Vkkxx0kAp38+9pY3XiO/DuyIxpOSPip2o0+9rZLF1Z\";\n        sout << \"cAUGnG85CFEXl96wpxvqVlIULUV2+pNJxdU+q1MkCsxDeXrvfjhEAJpPE38dUb3t4blsNUZ3wJ2w\";\n        sout << \"s6cXe0nEPWNkZlmEsXcFpw5zHe0Gd7YpXigz7Z+IVhvplpv686TJiLTpVPW2T1uJvSmMuG/FqvT5\";\n        sout << \"JIIMg2of1ydicw5EbWrqhIUzllX3l0u00gFziPmKAioiqCxjWojd9l3Q0Q6IsaZAH+WzV2xFabbY\";\n        sout << \"4b8SwoFvhe4qnUQLFdOSTbzeDIKP9B8bSiQwbjUBg3jYEWUrMz+eR9lpGu8603vChIEXaTxyMrO5\";\n        sout << \"SCeaVOgPE77potDoSUV1hsoW7ZqGCFH+AGyVTohitS0iqZbIxC7+7rnVP8XfXw5YpSajF94z2TSd\";\n        sout << \"jW0KpmuCZ88DTCPFamf5zh917qp/PzQOGTdalr+Ov+ogvrJraDnoE+ONWrdHqBm7Adgn8/wy5vzX\";\n        sout << \"fNu1AT14eYrEmWmXvt6JDAbBYqP8Aw8b1QRZff11MblUh0IpztedWhifGy/RFJUN0/e66Mh0cKeF\";\n        sout << \"plmK6NqchTzOQMKJVq9jxdyurcjcA0uu4dVJ1XXkAtxBim2J2m0zcwX/+HcRe9VbeNehmDbUC49o\";\n        sout << \"ktNvrwbbB1IUV/c0MNCruV359DVINXskQTK12g2X5qprOLW+YPO6CnTFpJRsiFBoLllF1sUTjROH\";\n        sout << \"SrHHRYp3W5t5gqfT4afBxmtTmpJEG0oG4eNfMhxEhQ7HjoVhahOM6px9Be9S+4ca/w+zII7NnUkY\";\n        sout << \"Iaas+FW7vhOIDOiV82SpJqBjdY9eIP//XGR1DFQKI5cLKmT2/DF8tB9XcqTgmVWNMVt9Xw21CaeR\";\n        sout << \"eYeoWvLHlm8o7ahtJCSQ0iHypTZMA16wdJ5IJD5WoYd50rUn58RBa9sTXT/t/KhxJfG5OWXl55eq\";\n        sout << \"abYojSlluFyvFSk7Z/wu/EqFUEBD8r4OIrlJCMZl6kKy4EncmjUrb3mG6aDKxsaRBRBkRRya9t77\";\n        sout << \"epMG60v3MRCcY9E+n9sXAOUpf+ErN7iD6FY4XFpq5R0Z+6MiLRE0af/JQ9R42quTl8CLH7609DDd\";\n        sout << \"s8+8bKA2zjvSJhWbwGURRCW8SK9tNKuemwkt3Eutm+xMJemP2JIVFVXYxjCvDmxIIODneu1vmcSy\";\n        sout << \"XadKkyjtYDwacddFAqGh0kLqHX9i/WoedVKC1Vuup+AYPkyZ1lPraGVqjq0nsiwp/vxm9c/+4/wS\";\n        sout << \"hW99Q+zoAZ0IWWeYAqcXGdZqvd58gx0/fmU/Pq4FqtCdJ2qnoUDMvjZeyWE7lA/Xf7AdLcz4XHNz\";\n        sout << \"VAidxMj7/K8p3KdK+XqED94Ey1WzpUQ2mH+10Zq/6jebtoYJlht9meMsjvjWxg4nwFIZY1QAMZPV\";\n        sout << \"phcmEwrLA+Z/Xjo+FEq4hKD8pIriQi4xT4uAoPzOFGp/ziwBbAb/EfYsspnVxpnERKblbDsV9bFK\";\n        sout << \"df5VSgeqg7p2auZBk/WkX/wOeXkulbiJA5lXTsgInJGoREJ+uaudFadnLD1pmjqq+VFJW6XOT++I\";\n        sout << \"arRHT1sYJY5mhqFztTeUGH5VXZNtRGl1nWpewvmgyK6T5XLUcuZqsyZVtzkkQ0eSR4h+nBuRAQZK\";\n        sout << \"EmqzcPrRKObVC7Xv+kMcnM+M2+zCuZoUSO/zt7OOXNt/B51oQ2DRqthPxgzUrWOvoOgZleeayImR\";\n        sout << \"rqG2QnkA8+Kb/mhxJ+SAqOjsIJATfLc13SzVIKVumz+uX5jUiZXWfWF/e1cdS1w3Nf+dNinnGQ2v\";\n        sout << \"Vf2SxiRlTfDTZTZXcLlT8VrCOP4UYvg0QrzBqU2myM41lZDUS2X/WOzvrNrRpEoCS6/OcbvMj5gf\";\n        sout << \"dzoZ1oqvaL3dosQ9/QAwI7wPC2/QQTRyDIbl4EuhcX/ebyueLqlxKRLPrmq/mE2YU6aU7cf+t8PM\";\n        sout << \"LX7J0eyNGl00TEWN0R7ui2xlfdnLfmILs+lNNthYvmUbtbncoqx0sCWgjk1Iqagp9uFlWA+6vMa6\";\n        sout << \"nx7Qg0Jz+Qn2u4iZpyGDZKUWmHgDYhRcKfsnjnzbztyNms4tEnmwtIeLwDqFPlC4BKefz9gja+tt\";\n        sout << \"0Om7TAtwcmWHve1ENSOQSKTLNvVwhjRLgmfK9SFUUjKeVSMp1g27Rf2WCoDyBXhRauHpqCdj7GH4\";\n        sout << \"AmlI3EUHSjS+/1ZoT/2DnHwuN+GKVh0d8k/7sGrln94r3JuxEPvfyQFvPSRlFkWYyKPdxb+H37L7\";\n        sout << \"DCYzgf43vxZ82JGYVXB7QBpO0VeEXiQcIgXV7uOsGKiXfFUwueL4kdNknk2hAfrFFQcpoBiQSz89\";\n        sout << \"sNRT1tH5Ipbuf19R66cogiaAesXnm42jLjQpnkMwd3S4F6P8zDL7m13u6ahcrWvZiyDuBc/+Th2+\";\n        sout << \"Swex+BSv2TkUorR6nwVoozQEA16/MlZB1acIFSrD0kSr22Vubdbo05svEAZ7DKIdQjDu2wTTOOvL\";\n        sout << \"IVJOYPjdxXZytBv1jRIhUyyYBvRtaFsl57ZWAmvbFEXZXLihnrBskTqxrxNPqhg+bLxicTDlFyHI\";\n        sout << \"UIipzL4AvofdYWolB8RvFyom18/szC67Flr1OW4axZ+k5S7249Y64eqtU1hk98joIhOdWaWBHxkL\";\n        sout << \"nP+ooeHeEvB5hNRIA23Yxoh4zzsWUB1KKvg1XRzjt2CBQ2FPaCfHsOKf52aaj0W2FByC81rpryrm\";\n        sout << \"Ye51T5zP5/N5j7yA+a907774PwIS3eYYyJRUCSh0ywfQ8rgkbjBdf2rKa0alzokz7Kmo2Iswnid0\";\n        sout << \"WzpliQr9KaPwAk7hkLjprMjzdJIug3KOKVAgygXP7rkgETIfTfZRG49EdJOjlW8mlmHZsO+arTFW\";\n        sout << \"vj0FgJCAQrrX0X9BOQ0MPu0friAGK0TNGsFs17lcHjaRNHXz3v6dY/MSR2TY82iyEkRofvNY/Xjr\";\n        sout << \"FRB2KM6Aq2pPpIjY4EuSQS5sU9ur5oxrKo68jNzoB9iRvmKhQq5HRSYKL5ACBF85HM2oWtyVl23y\";\n        sout << \"TqTW+jwNHfF+sc0FPS6xfwr3yvHi/OVlW046gnNLKOxO3RjGntaJeX8EVXGGpXDHLyle0UaZE0iG\";\n        sout << \"1xeLZjyKq5wRJ/Q1MPry/JJbfCXSIHeO2Uznqn7O5rcs5v3Z1PdlF7BfPUhnP7+Wcqryfi4xJ8rS\";\n        sout << \"BzyJkibOCzegvXnKTTw7q5/lrgh7LxfrY/4G6/Js8ibrUU9NGqBkOHUmxa9P7UPK43pz/bS7SWtl\";\n        sout << \"yA/3hBa0bv6hN0OeXVaBxtr8sMfS7FcvR3wtvmtKn4BlIYer3LMSvigPCK3K5seTPH3cx0J2uGzf\";\n        sout << \"SlPZus5idN8MnFCEiBUbs4W1M/BSw9EYA9rJyhDTyOYqKr6s1kagBUoVCXVlEPVgrJoppc4vLghu\";\n        sout << \"NMgUpcakhT8SAulssCjPb1UWPF92XPpn8/byK8dJoSFe1lfFb5Yog5YZMjgoKKbokk0n3eMlrbm2\";\n        sout << \"AGwIh0acdOXRR+lpeJQ240N/Waw3e+FhAI+AYfOkIXodtQcod08+F8uHCAAcd9dZvYyxZxNKjbCc\";\n        sout << \"aYTFUYPN53OZEwEyCIFWwPf0QhdhlpyAGCj9gqVU4N9b5FJYX2ZqVAl5JF4nl9yDWrJ3zmhwL4r1\";\n        sout << \"P8Pdv02ysNeZu76Y60+ffPXCqmjHjllu082gde9BXIEWdS1sd5qaH0qb8KRpV8WAYaM7/ccGTHQ+\";\n        sout << \"H+0C5o2904WS3MG8rR6LI6EqO2fcBnJzZ5BJX2bHv4kNHhQiW2tZjBlwKjuMH8Ddayd1BVqzjeuH\";\n        sout << \"5dfcL8xV4su36eRT/Vmanq/NZ80+KXsXZO1k88RIfQwwZdt5XribJfUSwzKGsKQrhu+8iUCjGP8l\";\n        sout << \"ScrIRdj3gjy2brM+zBr9z9pvFZR5NLjYN1Ko2BptMbEDxdjnYkYWix8BF1P+/PtSEJeGATIyl2al\";\n        sout << \"rAlEHX3ysdDjUic86ZNUx9c6N59ZcQkIr7IwFl6kc5sbuthroXmAnbW0A2UIO/LN6KFbbE53Up4Q\";\n        sout << \"KwoMeMHxlgEwundK+LV5WZ136K5JoA6SpvxzuKhCckg0Ev4+KtyA+1wlna6AHOQaj24BzblSd9k4\";\n        sout << \"2lWsVOwAOtGxFIRIxpou7S4yqPrvS93KPtVkrHDBqIveGcwoGfyw2ZSX+5o5SIZ5PUG3mFM/sNWw\";\n        sout << \"twketaHdV/ndITa3aJyGpqChs3hcwMOgODnpC+vjtY1D8zdp3pn4MBgb33jxc5kOCpDktiKGyaQN\";\n        sout << \"sQ7oaOy4aKmr4TFfWbrH3qeR9gz0utGL/iVHcgSlfl8rw4BFncc8HIB0SGJJhYE+lfEYpsP8H+1p\";\n        sout << \"pfG0yzIA752vcaOIWIGt+C/EvuXl5PP8qyE0aBe637yQd1aMyRhf46rsAIlhzwZ28wPYZ9KCaC41\";\n        sout << \"ap2+7/EJMw3HramAAo5OVqA6M5cV2V+MlGifSoVgTN+5TaY9EnqexQy2Gqw+9484Tv7QNVaEtwtY\";\n        sout << \"/O+aQ8nzc6H+clWCWJkWDvoqIrIqP4jFUaJ/FnqlPEb2GkPoNluJV92HqQj6fD2Iz0TQKCVQkVWq\";\n        sout << \"D/QuFVq8c+EC8Bz2j1cI0D30iwROmneb6XHTYVwn4yHkZ6LAoOz28fjT6dwJFdYo+Ci4Hhyl62tW\";\n        sout << \"P0al3X19i/IjH4Xi+ZH+lISFmA0oEJo4AG/oAklXtGtRtIwfKGIuIzqqEztmX9tY+INu7PtgH/FP\";\n        sout << \"z7d2f3CBZTZY4qTPMEPQ/th8jnjHrROZIM7Cej4v+zYms7NPlJ7x/k+eX5ISG7xEbWr8j+kr+R70\";\n        sout << \"bjGaz/rED73YxTMBmhQSKMDUjNaW/qclrQuvaNwUgM/VCtnY7NANztFMXhCa2hGjZaG/bp8Yc9IN\";\n        sout << \"T20nhrbTX+KPkcEmQjsHwyK8hT9XN6J+TD4iwdnb4A/KQI9JwaqpYPp0S1d99j0iqXlirvdPcotu\";\n        sout << \"AsUmNf1YOlK1I5KxaFA42emXXmg1vr7USuKiX62IslSjknRY0+bPxOcn09P0VK+HTTdLIZ+8p9+k\";\n        sout << \"fKsgY8ajl6qZ/LP5qbZ2KgHJHJNArwRSxNn4CR5ish97R+1A3DglEaWJ4vVuu4oaFIHc9eSgRMdJ\";\n        sout << \"IPJ52p+8SKIpjM3Tnig/Gw35R+sPcuZlpauFplYb3vcIoY7vN/f6+RKxPtWnuOfBh1iPJxJJfz+H\";\n        sout << \"MDVZihR471I+DLXgGrZ0fgMQZqVFelhF5eszKMOxB81TbRuPqUmneRijtWvR8QAySqzV3o+OoM/n\";\n        sout << \"fpoLxmcVQm3LanGF1VfCbk7X9dhocgWTpk9XjDzVjIjPceJ2IPuFjHcrNtu6L/fe/6sMqkKWNRQH\";\n        sout << \"8GGbrJU0/kqXIeYch5gXjiKFTIU/QIRt0e4YKlNV0Rpqkh8vY/X3OL8xbNCBd0bM4nCXMp5Ytwyw\";\n        sout << \"DEyjzBl4SvxgGSqG6ehAzY1LrZ3bHU0Bn/Q7vD6RIEr/WcxUvdr8oy1JuIey4PllgfcCaDdW1+wG\";\n        sout << \"YCz/81Acw7xOiG//gLZ+tApj+tGpMP3Z/vnC7bZmXAmXWCfZeWDwIcxX/V5Sco8G21PpzMYPM7k0\";\n        sout << \"1MEkR1PgNhpKv5he6criGZ6D/xVAfVJbxc7blkovBkLh109MFBCAGiA8zk3MAShzI7cynZVbyWGw\";\n        sout << \"+x5Bvl8/6xSUyG0MLFANqDilWFIEBpT8h6G6StX3WXoEfqJrO2pYMjQdqOg08AvXKWJg/xj4U2Mw\";\n        sout << \"m8+nK+zX8aXHC333WcQ+1eG918/0TEDoQAXep1atGq3wir0iBvurJHbOXffjGQalMd3AeFCLWaFn\";\n        sout << \"7tYSTWYcPnWwWuA47FxTSOPezm1PrihBIC7CyVjGHAGvtBdh2EjCVptJHYgft9Ivp0YpPFaGtT1c\";\n        sout << \"IsaiWl+dF+Yg0K4FVIpNqRq/g1EEpGni0mrTmlTKeeSiKzAXdGnjOZ/9woea73BFZkY0kAqMlrn4\";\n        sout << \"6AOIuXh9Af1UJe0OxzhcYKFjFuzj7Imjv0SgNaah5XePYFfLyqNUCctmTlFna9nZWZ4/Q/N0tqN1\";\n        sout << \"QJwMtZOdFdKoSwFcDrSuMBc2kKNCEgnXAB9azTyR6Frs6RDNbCOdmMKEIF0Ra6v4fqO/rzc+m8nM\";\n        sout << \"2GAyE9yBNQq1THcQSqlataFHDe9KkmlQ41F9hKifZEPJ2eMe4WbpMdXmjT0nNmxif9OiPMKR28EQ\";\n        sout << \"pcqtuJxTE2oQArxmoOD6uUSUpm+Xc190raj1/JA7kfFQPkONEkNn9fYRh7J9VvPk58RIkyDL3RfG\";\n        sout << \"SjlzXsvz0d2uU14U8ppyPSOUEgcvxUu9Zk/TcwZkWvQeJTPd/i7jbUyAHTPXy0secfKXWSoF4T1S\";\n        sout << \"AuuRuErtEIXmJm6bd3v6ozR+Vc494q5Nu80EGIEy+09XWaDi8E0ChYGPUn15jWmkw9aZ2SUGju+0\";\n        sout << \"OS7eaGTSBcbS7l3IaP+053oZvh6NN+iYo5Lb0rs+bog58fqpXLFLeaJFnHUmZipr4oX2EfpI3FuE\";\n        sout << \"1I7xjgdZiWMq57u9UId2PuNahTVN62Du790tZhGfoAACZxKx9xxi8nRwxz1Rh8uFosXdHJridfzF\";\n        sout << \"gzZhDTmxJjYCq7tg6769BcDtHxT2G+JOh2hMFV+aieGZEkBEfj6EWhuot2jR+VVjpLUhys154Fj1\";\n        sout << \"NLN0d0zMnJDThQlNGigIaHgVdQ+l/lNtN9ovAuVJRib/fYnSDRBpOQpOU5NuwyHjeHnYg20iKuBT\";\n        sout << \"ZWphFPD7M+zYlrVVH9Lg0AsaY5Yt0U7g+TXLuT/bi2tUz3rrrk/5bY7iLkGbEmOFZmxzXXqWdm8h\";\n        sout << \"ENOKVj/yrgSa/l93WqyOESSZk7hLMvP+OVkSj8qAKKBQ1+XyqVLODZZae0volbIcZe3HAAIjdYTm\";\n        sout << \"+JQfIGAWgkqcHwgv3WJiGPhq1WOVi4FSq2Dgxi5/J6cRg1Smsr9aCx0uNC2x362lI8Jd9yKn8m+m\";\n        sout << \"te+3Zx6sx0NCnYKxaWcH3V7BfF0hp0WQJ3vQbPG20PD/ACHvMEgmo2dDFit6m4yfWAQxHzQZE/3N\";\n        sout << \"E5TLT4EMnZxi00F6sV0G25nElE2t9CrGkLNxTUbK2sGKx+ybsveIWpoNtQty7hY8NF2KIICOd8QJ\";\n        sout << \"FsAKxGHbydI+9NV/8KyW2UID4JpoNJOQkh4B8pp/1bkBRPsikKLyowC6RWuWmVBm/DCPSIwkiV2A\";\n        sout << \"jNHVRmSoDO+U3eTMxbamjBV/H+xWgrBzBu+4aaFGH0MbKNtXG5COeCVMCtA5v9pmR65GLD/DYWcM\";\n        sout << \"JltMV+H82nUN8qDVTMpCSzrlkiv4Gmvh6b9HkxZC03g+IrBKAkXWkhIl3iYkIjLYNudFSUddDb6g\";\n        sout << \"/wHCk0lGJlbYim9VV0uRYJITZenRrzsMcb6g6Cm22cB9awV0qpixCGVW+jms3MfgcstzqdN36KPw\";\n        sout << \"C0IDdKjN2Bu9aNqHqWafK8Vl+oTYVU6foPJSOmHD3MhFHhuZk0oPtptRs/0aSZKH3FI+jz6KyTM0\";\n        sout << \"E9UDooIsxYAo7og8Ka1QCVel8cH4mmTBWTGLNNxuVwvHYgQc+j+QgKJ8DX3XzEHJQVL2fxCmm3i/\";\n        sout << \"tjJTltGK8o3S66OO3dN5g1KaYyxCDkmKjsGpyqAKGhdrzQzwLru4oof/b4cM6E/3aqGWH9pI27G2\";\n        sout << \"8jNYhu6r5LhYMpczurY9gssS94+RdUn4UFMt2zZSlpFsCY9E0NNaGwQ5sX0pcyk9r/FKWAWxT+e4\";\n        sout << \"b/buzfSIVsHWrzytkKOYCHMylaPd+juDOWX/Y1x5IBmR/VnpsIWbuYFjRlK7bvNoVcwitIZyI1Ku\";\n        sout << \"vmkH9u5YzndkbH9fj8FroFgMdZumIeRSFz2448yoIh/1+2wyEUXUvof32q5kktEutky9XtKCTIen\";\n        sout << \"LlWO9/7k0Kcz2Cp1S8bugmULKSLHEWMTtScZhEOl/o3jyMjLpbHhSfY5IHwZXVp6MO/bxpk4F4ur\";\n        sout << \"C2eAlsHUW0484VZFIm/GtgNRKq5H4MTRSmlzHxh0o5KnK87ZZNGKv2sGFoxhOKT8g9s8uz2ZfkI8\";\n        sout << \"HS0VWQ5y0Y9dY00ShJj9FShAuForC1EW8TBcgW2wjk7uN4CjXgupadGHC4hMFxVjJJ4tPj53PX+w\";\n        sout << \"KKTety47QKF0aeNAXeiNkzo0e/H8XYKYvyRKPpUhWbj5rzdkSev920dKjpq731kGRLUP8kljqmx4\";\n        sout << \"j/1ukvHqJrarb/U0LWECXe1mHUjehedJNCuDsXmlX3OIT4557z3W9vMbzKyu+0R+LN2YtYUFTdXA\";\n        sout << \"z442W3oqy7cJRIMfioDLTO4ry26sNo4uyq83j3iFx2iY4Wc41ZUGg9cwh5TVKg8XEh5US5xlsqVO\";\n        sout << \"kDR3XfYXA3GwuKklaNN6vImd+oP4g2ZYSl51f7tj5hd9xpTSRwIy3RJJ5VoTz+36jpT4Y3fnlppg\";\n        sout << \"GqBmWhJrY5UemTIoZbJ5X12NjQjW2HiKsuiCpLS9Wm0IXYWcRSYfiWYBLP+QZFyRA2VqVpwmY2X1\";\n        sout << \"EafYVxAjG2au8TnbfK+PLccuRg+kYNExJfD/hLUMyVg4wkLxP95L8CB85+g/1VomueeKJFnlrnkO\";\n        sout << \"ezCBls31aI/r4fMbdISFALkRwPav4rVwi8M67zuhxx/K97+5I4ONkaSU8/DI4SpqjfEIzl/y07Rg\";\n        sout << \"VUou00laGIhidjtfwENl18fyXGmjmLI/Mn+/H8gU1mW4Z0stSN/NkPYZjTx1AnvjG/LgaY1750yS\";\n        sout << \"4dk+ygLr07oWPhGB3BhIElS7VDxZnnPo2MFIPXTqWHqZ1/lNq8DE2EqgHgpFQGmp2MZVi060DA0Y\";\n        sout << \"En5g8zk1NXq0irzIv/hXYLbDEnL4ieulF+BlWN1oeERYelY8VkqgMtqGwBlwiO/qN488MVobHHAk\";\n        sout << \"VARDBpkSyX2bsF0KS4BCwybuQtNPVCaozYKWd8Q0RSNvsK72afBC+snd/y2KrFhcE4mE9ZhAwV7R\";\n        sout << \"LRR4IBmgNkDPDi7YXFEVZ4No5G5dJYL3yfsZy4b0kBEplbOoIjYxwz2dXYtX5Wc3hcKzRblKZG2i\";\n        sout << \"GkmTHabzN4BTwbGBxmCTbbyecAIO6MFJGlnxW6tQfdiQbcBbt1utUTpjVhZPVkGolN4VgU/qFPCj\";\n        sout << \"UyO9bO+RUapMvtwhI9+1KPcGiTbQsAX/V9+dSCjQIgD5sLRjfVQcKmK6/R0VSppo3ab0+XHDv55p\";\n        sout << \"FOPkhAKiKvI4Wl1JcKcsx8mwxCoTSchCxp5JhNn+WYBoINpTlmdRKI2hfXvfY+YXUzbATuTLKIZX\";\n        sout << \"IsHeRrzLNmntT4lzgHtEArSwEcYDRXLKBd+L13FZBV8iMX3ON8vUBMLU8QKoSDXatEI//h8RcI2R\";\n        sout << \"pOba7GU2f5TWFy5lB74tBKpcllmmid9w6jE2T3yhxU0E5GFWxWv64oSJDCfyD5GRfY7L2dOVBVwA\";\n        sout << \"H1DuC3NeBQfgaY+DPYFyC2gR6vEihtW5biK4HZoQkEHaBD8nREBdMlh8DcGuXwsTwEH1co2xFaNz\";\n        sout << \"53QpwalF61MYqPbQuFXZBvFEruliv3cYHUgIqtFo902pwFOK447zzj81l+5XzdVZHsA6dCGAjSqW\";\n        sout << \"J//PGJo3M48ERSqeURrEwNN6lD6nOqs9XAkQyGp0xLcv1/EVyzMoYTWazSaTkHbocIh58BOJVDya\";\n        sout << \"rjRytgcV9cAKzYvY9O3NBPvWMBSybUG0weBGTpWXNlydqxlAc7PBND1DfOL4XA6aDHpra2rRpJ/t\";\n        sout << \"xQJvaFWVNRYBOpR34GsrLpczGcf/z5hhR1gpE5y9//b26xf7V66n3kn0w2qGADZz4eL+Y7Wl1rIJ\";\n        sout << \"QXs4U95d6lfp26TVY7MsmQRf1GaO4keltA6LW8XkS9zXro/Ydl49AWToXe7suuJk6OGzaUqJImLB\";\n        sout << \"fI1w0xXDoVdNfY1SgepZyQxrW7PqtQUlLTHccsTDUJqVdu9ZUMnCVlo+6fQNz5lS7wvRbv5iqgkz\";\n        sout << \"DMyynFxFQvzk2L3sZUt1+xTw9r2d7urJ9VmGpj0arjR2+qb+2mfFqH0HaldqN+DGEiibZ7w9PmCT\";\n        sout << \"MNDZvjC0zm2N87yPuRBSbwn4JoAD979lNhFSpExOt7v2zucluinLIqwESRQjWnyun+xTZbu1MAka\";\n        sout << \"JAut97DUpQb5ALQ7TLqKOfk4vSSP07cVRJPSH6K3XnR+ZFX9W+7kb1mYRhJ60r3uKUYAoYJIdGqL\";\n        sout << \"jgbNfvqdTZqUOVq/Sfc2/B2T3kY0W6facFDev+/YnpwWe95pYSfUbewbM35nEZGJ0HVSRHnBTWIO\";\n        sout << \"n7C6Xeg9e29pfohDW3jy7vPL9HU7+GdvhZYMUfNeQTe0zYKuY0+/UtMIuMFzDJ1J9tBy/cLPuI4K\";\n        sout << \"oyPNxmTBGCcf33xcff6ZvAePZPBFgjmbV8izFio89if2qmyhGPDi6LH2NxYGpjC0f+aPj3j3H7Ua\";\n        sout << \"yX5PEPGDl+3l5jZjuY+sLwwqgrUV0skzdcjAyEbLPClOkj2BG5dELl4VcD8ESsOwyk7Yyb2mt44n\";\n        sout << \"GKgKNGm2+EwSNyvECcoEksksg7gaE6ZNXazytt+kRITYczq/v57+U7/tSjyTRL5qPLxWX5OwESUw\";\n        sout << \"y2zx0ulSrfH44+Xxr7ZnI82X5IgDehZJQvNPBmtPTB6JvDuUhJMd+hQF1lboLwEHAfZKpcN4v7FB\";\n        sout << \"GEZi7Sp/iWCZQwtALzUDY4YKGUuS7uOyjpHcQp+hxIlbhXY9byIyhvvVy361/nbVwOnEHo5BaKYE\";\n        sout << \"csaN1xi8WvBN108lpddsUUDRgBW7oKXoiDI06pfubDTDZHSJDABQlnor5sTsIQBMs35yYGuq0lMN\";\n        sout << \"lDJ5h6Nb8r6h2HhenA8tSBmMXoq3j4IAq0jUDpeR9TXX4pBbGfN1HgWpbIrAKmSh9L6Pxa/tB97o\";\n        sout << \"D5seIFPmORWWemSfAMoAs28YqCise3933/HPnCk83PcWH/4S7+KITJx0tIgF8ssoS36XP4J9L/1Y\";\n        sout << \"ym65j7ffiEEDH2rDgip/UQ7utwOHAIW6rOjkComtHS0F+m+yOcdoIwecU9J4rPGLgpq7KW7oSdD8\";\n        sout << \"5/ckw1VAwgUvvo4YT9forakPHIPB9BgroHxUjvbvABXJEkYGw7xUwn51NSj+7LieWTsE+IVs2kWx\";\n        sout << \"TAU1B6hsUPr3f4Z2g74JI1AVGc9KSuJhTtognYLM0amQd7HkR9Y4gmTRYYrSbE1yCWj/gYd5Sn+W\";\n        sout << \"/NUvdGmfqjcmItvBAkDr7lf79aevcKySCPfP5ZzDBfM6aJw/T6EC3KwBpY4obv/Zgx9dLKZhA9Uh\";\n        sout << \"jCKQEEpTnfOOGI7D92zvtySthJNjrGzN8ZVdJHyzXMSYWgHEElfM3bB3LdAe54vVG/XyHag1EMMH\";\n        sout << \"DnH9JOUvMeXHOLRDnkI0RNlGg21wNjl3HTxSiXkIwpANPsBpcoow32KWYqrygnB9iF30IdwfVTbz\";\n        sout << \"OhTNM/4qyrwjdzxSTX4IeMQrviMB+gi12mTcB4G1ggqXuz1q6uFqfxrlmMx+gDAuoEbR0vFF/bXg\";\n        sout << \"M+8PXQ/oKyGYtptl5gM50TsI2CxNaBAU7SUTG2zH9pDkoko6VO3mXfRblwFH4vjJ3XETsr2uAJlS\";\n        sout << \"7wOiJOWfMj9dKFMH6efJkuZPegH2WtkRjomYXO3l/UVkWwW2KuLJgJhAgqJcI3ODJd/kVYoR+THn\";\n        sout << \"IiPnJvoBXfLTKJ6r2lbjeImNg/CwzRVhDVVPJi401mloyrMU6JQ4DtwoqeiS6qAcLDlJMcu2A0bG\";\n        sout << \"+F1isgRc72oPo86rpVxR7oJDEVRSsQqkOhv8O/lVaziMsLCBuqXUGfuohPNE/+mCdSrZZ5LzkKSe\";\n        sout << \"iTlYATHr66c+jnkOETWaEPjUpwQ6ABfit3mbttnnONmDSnenmUnHUf20QyUonJGpFMsWB+DSPFs6\";\n        sout << \"7zI9eOAhqKQh///VoPYY37AdsdacucmhBJY6lmIHHiDyT804IvuNqWLSt5/Cko8t8thgShjeSM8J\";\n        sout << \"9med4U5W4XJ1fEoialm7jil6e/fr23OJJf3VJp8JEaibvAk+rbAbc5VIzwaUG1duo1O4783HLJu5\";\n        sout << \"4we8QCONtekxRwXi5R2gUi//qD1kJKbKxnkYOXaKNWkUbEXPOSy+evfT6jfbYcdk7VvmfA0qioZc\";\n        sout << \"B9nVWevTpoC/1sE/aSX7dqAWjOd5WH+KsReDpJAtB+uMhu4iyzaHV/gPuCAUdm16nVmHgcBP65Ix\";\n        sout << \"Rz93awPYE4aI2yoWBvJnIN/GgUJPBW5rHFcTncTV1LSUMePStawPL7BZaY/V/HRBUOnQ3V+p3xwE\";\n        sout << \"QqFY44ilI49X0t0OR04upM1hjEnx1lVyd/2bSw03lCDr+y6oNwi/hrk389KdFRtlxT0/rItCg+gX\";\n        sout << \"JVV3Q5LyY4WEE5on7coii0m/ZyXMxNT/RitPnLWc2aPtEKhbVOWpVuQGw00eYcKTs+AN1SuqcsrA\";\n        sout << \"7mVcPVIYhQ9/rDYzAzdG3HTcuiFrDWkGIOQp++BZEYitA7zEexC0xZPQZsqcKoH8RieRidrtPNXS\";\n        sout << \"ihFNGNNuxYQWVchClJMvEBrl1ankneT/fJOLTob7xAG+o/n1zdtSeTUtXPN4O4ym3GiubaONLzLL\";\n        sout << \"Z1TzkBa+H/t9NkI+Vp3kVRswJr3cEu6K607OPm6yGAxw/BwpQRBli6uf6SMAdNcAPMwZr9xV7Est\";\n        sout << \"pLz8ibkfNdfMj6fMY9WKJ5CJhajqg0WPFTlnSnaRs5ERtBLK9r8Ip/XS2VUT9/rqeFivpq8OsInl\";\n        sout << \"yV5iKygaW5OyZOtBbI4SrhN30LZZaoP4D4fjXqc5/EzHyzGCYCfgjKrytefR2F6CqUUdBOn0nVtH\";\n        sout << \"Z4xjlb6IBw80vupy3KEjpjsl8eAiYM9JsV9aw4Fd2hjCdeg6yPCNN56pm59Yamga80+31oINYjri\";\n        sout << \"3OcSjN6tVNwdf1Jr0s6Y1+0VgrXT+AbHuMkdPQbhTgQr/AAqHzUr+5FhrIZ7xM2vF3PrqUDakSkQ\";\n        sout << \"P8xIrxYawDr6fXVDWeVPOlVhUSihPBMHjc187YnXDd8Hun9Lww0wUuzOPc9P3Wb8wBTFY2HiXNL1\";\n        sout << \"ciWhFec1G2O1lNNBgYSeclowdwMNrC5z9lk0jhLKLrX2Ji+B5ypECjWGE7ZMNSuETIucCTh4wl/Z\";\n        sout << \"fLIB5I8Lx2D0asU17GjJQk1UdQa9uWdNgpG07osHpTH5FoWxZcQSBl7cvfkqXltox1ItArv9yuKo\";\n        sout << \"3gDp6AgZTFOqYhSdagGzYHdzB6KkEpIUJJlvMZsRzlSNIUtHJ4muh5SbP/X0AAGWnNjNZj95Yf4L\";\n        sout << \"IS5+ZQRnfrzIl7Nvb4KkxbQicPMrtXCcZkWJ0zN+xlNOX4Ph69XZEpmkzj5OBi7H59Kcw6ZB8yEc\";\n        sout << \"3SIw3oNS+6XAIMU1TvhPexpfDTyQNBbIgyycOPYaeA7eSgg6yz/4z1RfNMVZEj8PgPri6IzZc7h7\";\n        sout << \"AzIGqSzGJWAiWCtBFSmDQ3KbDXDMAaG6e8g+zzdm5dnujiAJ+s3PneWlapo5dIvjh4MaL3w6iy6w\";\n        sout << \"T62tjz17F9eEnJD8IM36+Wn13OSPk0iFfPKZfBDZPhEAGRYG7tzc/HKJ/d4m0hEg2GTY3M6pEjZj\";\n        sout << \"nQIcccSE/e76TSkeBNrZGp7lplsixpLjBdRFSFQ59D4juFAU/8tf+MmgtxWd2VVPU/mtkYU9QXzq\";\n        sout << \"JeDq/+MOHtQoMdFuxJvlEj0EE6Aa4E4Ya31LBEoSbp7ln5dDcP/R1LvqaHZr7+XU73GMzpgMec3D\";\n        sout << \"7UY6Rnip+AXpYOaWcfz6XX6y6lLA3kdIsNptHnc+f85kigFZ1RsCXZxugGLjxcFWXVieSKv6PwVG\";\n        sout << \"oQdmyR7KlT+tdjXvfGTP9AwdU3S4QGHi77l1FSZaebpelVkrMgWhcug3s1Ed0/1c55yvaZi/ymXU\";\n        sout << \"OYEtOmPmMAB5wcOagBZsTBP4/6w8Zrfy+27SKh0W1vD/rHQMP083Xsv7HCqWppSVZMWOGJqyUkUV\";\n        sout << \"rBnbjjEmLTyHXr0e5DP7TRCpx4MWMIFUI+fkRdrWSXxNJqPlST0J4BzbQl3XSppj3iURoccQBDpN\";\n        sout << \"VoLZA+61XgLAwY4a+1HGcvVRLzlEhHCmWEaLIeWMfIpb6L7U/LQyfG4nDiMqt5HtmMbLHhSf1Iqy\";\n        sout << \"swpB3hHI+UjL+bFOD5XkCRclzVPucjimVLtsH1QXWKYIcrC23dh5/tfoR4SUxzYn30LEbmcMNctf\";\n        sout << \"ETO3ebcGC9+hvFGH1CwVowGxDhQfxf8tjORR4Vv+L0Xfp7yr0Li/Q8wPnrIQQkbasy2O7PwodnVx\";\n        sout << \"W3iohD3htvNaL90vc5WOf7o0YUKcAWfM5ryT2OJoFFYCSJaI4qLPb/b9OLg2WUL0jV7lYLrK1mBE\";\n        sout << \"JJhgJRQr1OiI4TnIIWrUQsdvkrRVYiUWzVS6RsE9dLpw0ThoXtu3Bi1gWJInLknUCJ/yUPkNqwQS\";\n        sout << \"hKult4TehcOZBfHVc+BOtTdcLNEzQVWy+HPWssvhSNIYtoWp839hdGzzLoFxsIGik40aHU78d+cq\";\n        sout << \"ksDCHIFvnbgBvPkpLxrmvXrKofATp+ywoYFeV0g808/Pl4kX+27zXT6ggZWAO/I9anenVXNcgtvx\";\n        sout << \"ICdGbYeHkfXRr1/IVvTgtN2kaS4sSRbf9LPij72aJoftCIa5EknOgNSOQuqpEDidYdaXZXl+6tg9\";\n        sout << \"lz1qKU3i0ivIjIcaGmxLEi1pBM1LwgEYWcovusXNcv5+pm6SXUgVzQkHu0Iz5MJEdrgsSsc4NN+2\";\n        sout << \"swZHdmviqcDDIk7fuOSwmj4IdjAWUq5lmgYZbpZLZ0pPsmTjqX5uaBFXqmlpKVj/vEIKiFOCGtZu\";\n        sout << \"uEek9ZEpH8aTYqjf+tGKsNNANsDNOFVwLsdD5edStQS0c3U9f2Q1KGKXw16BM7pArxVx6KxFjI4D\";\n        sout << \"LQxcYx18Gm6V4sCn2J0ahj7IO389LWJQJBcfJNyNSFhfaRbVha6itGi8UaBr7Q5LvkCvV01WUcJu\";\n        sout << \"AsuyKjRBScPvjzypYoCxSZp3ln/sXB58RGCVZ6c7UXeZnGs2ABzXEIRYIJyrsNNVky0aGKSHFRem\";\n        sout << \"r2gsZ/RYPQBVw+xt8kGwAkM2km4waF7nHbkN5SYq3VIedvw1gU3UIkbpno8zJeJcwrnoVT9n686i\";\n        sout << \"aE/9ltlEfn/OW7XUGFK4jXB9GBJ455E/9iUejULkvx7iqfRsDnhbI7UsVDn7Q4snN82f65MGUtU0\";\n        sout << \"w9UaxqWKQUZqvP6rX/4u+2IfBKWAksqUG/Rl3O4krkxQRuuOS2KA+u512w/JhgdR/9O0BNG1YuBd\";\n        sout << \"C14QpgMmqPdGEfNrXUZN7uSWJSdBiwqwh+yPFVqoclcjencYDg3ZzKNrfUMun9eKKRBJ2UqPNmJ0\";\n        sout << \"zM06doKb85m39v5GBACWExd6vWsrP8JxcHeWtDkH3Bt6qhZ4YjU38qiTD1avmK12ti8n3lpzOpNB\";\n        sout << \"ObN1g9F9JLpGQs4RrVt5xH7Xv2LsAC3UxcKZMW8nr+QVc9BykqYIU96dVj3kffJlvfM1fTyAtTN0\";\n        sout << \"4016YMvWy9OzdbSeaW9c3ua91Eq0w9Ve7rR4D7rUm0DGwaPPNaCAQP41DDP23U2RkaV2yhcS2ntN\";\n        sout << \"95eArvlyyr0JKWkMochvrYl2iHN/4cv15vog9n/9pUP15ttJdZdqiE+qwBaGA+B78y7kCf4X8dAE\";\n        sout << \"ab3I0Gbc7FLCNEsJGcQlFTSmB+2ccRQtRh74pirUXd5BPNNQUEkZWXyD4tVcDCkWRqHbkxlneyqS\";\n        sout << \"ziQQlbRyiM3MmvSmsUOWYYlq6iKu3rzomWTRukwdFP/LbClcTaMW611t5rXM2Jrl2JXWer6HsRk4\";\n        sout << \"Z65qxcLwDmjokz84nvJ1zpNeDcCq19jnxNqEOaDIpDVQxtM6RY5L96Sn395ecZHJFpL/E1TEHSbk\";\n        sout << \"V9ZnTcZwiga4d4FaVDa/L26ckv1+93o7KzMuxgopuJqf9GJ2c9inY+Y0m+71i6MNharLdfuGkLwr\";\n        sout << \"/iEeyeu8K8QcwNyDDd8QfStXRGgIGhNR573Q6ARI6a9Uft8y0hUYrJSTcaryLZRnV0xYAGAq11p0\";\n        sout << \"YOLr8U2iOncUfz0+Cfc3cu7nytOEpr+jDM70ojkQxjU7DmdCCYqdgik4v093Rv9hTdPEBFtzNNqh\";\n        sout << \"hWlaCaul6E6Pe+PdjMStduOGI8+eNFpOJ7/K7IlXuQLMLcggaXELqeqzUTaXGnMigQeiNsXUhXJr\";\n        sout << \"7g9PJYDPXXLNYIR1TuLPXCc6L5KuF+fjWQ9CwUxT6F0xCBMVMUVHQSkNoqngCeaHsQbIjpkFBbxH\";\n        sout << \"BXjl24RA5TKttRF9mUgNUQK4VV9LU93FJFqPAegUWA8A5AbaRkJbylwWT26qCwRcNcMm+wVFjxdI\";\n        sout << \"BYvJqx7TCrvo5ytBIlgRVx1HLjUcyITmeQ9CCl1j/Tfb4RwslDCgCeW0LHocZde6lCdknTwlOre8\";\n        sout << \"FHdSxxvQAImwiZKBSxPYqsRLXEGMtcFxkpAjbUZjITfHP99qD+h18ywpMp1xQz1FAa6QBaDjFQUy\";\n        sout << \"q6DWqkCYI2cOpovwq+eU9y0HKT/CxiAclgINEMJ26zRPgJDBK2vYmft5gfB0CHj8zUzBuYCK8n+u\";\n        sout << \"6RiFrok3YKqfszQbsWj/M1nBKReS75d282S02qdrnm+OwlbRFmkUX5VNUsI48fffdLUzQAVOD42L\";\n        sout << \"O04+nlesMESB1w0GezPWmsG+eNiUghaLxLnptRrcATVWseeWuqcdcDG9ct3BkyPEjaNSZGbvqN0q\";\n        sout << \"8S0H1IjsnmKrctlK+1ELXGBaND79Uq4HC8NtNseb4gEQFBTj2rI85gXxRTqPwtYvB26mpBPrWmgz\";\n        sout << \"JfLIOawOFX/GEe3W3NelU+CoBpxvGv2wmgqW2quks6TmilBZaQX1ewR61jVhKaI5oG96e4uUksjW\";\n        sout << \"I/cXdAP2GFl20jLWia2m76GGbTimCyffGDV9v3uzu+lpoZ87JgudGUKn/jdJK1uqTad/YQj5t2N2\";\n        sout << \"Y0PnVN59l6Do19E0YwY5vx5vDXs6q0SiWoy/zuY2hqcZ7paY1iJhIaanMAJjFK+3FelY/IH0Xo33\";\n        sout << \"Uhv+4k5pPRuL3AU0nA+rg4JCT9YS3OwOpcwv4kNyQL1xRg2DnlcryXMHHCZPYeVApEruSVmO8nTE\";\n        sout << \"g9cbFMz5nmDHKWdF+KH1Zs9jMTI7tfaOGS5qwX+gBwcMGUPeHf8OMiJ6y0zXo26vHzLJ61wPWLrP\";\n        sout << \"juyapqVcV/YgQl9Ok54s8YGCv9ZB4rxnxjiABMls7ZZquK5kNJ2ShQWW5F9ibtec8EcjMuK4i20B\";\n        sout << \"tTgq8ymele0eOIWVE5AZZ3yD64qqbY7kuCLJG1LxvQRe2zr3FYVYqWhfyRvywRIRFcequso1Bc9b\";\n        sout << \"HKoPDpwJDaTrQn7uhEsb02WZKg7Q4XKZVRXxDGHHcBqwa4fnNM3IPScvskFpmyrZAvR1QrjNLTii\";\n        sout << \"NdjPVn0Klyr0sQlppC50bu1eCy/Wt14QKDUA8OFYOmA5mEjVGtFktwxy9wLssgpAD8LoyPQSxuzD\";\n        sout << \"cgiB2HqNtOwNGPvlE4/ZDfT/N/j8s3lk0q0cZmrAUCBXsBDiAHNbkm3WeDEBDY9+Un6fFF1U5chM\";\n        sout << \"tKKpyvjeZd4bjQXK6zzZNavXSJzOvqVb3OKlH6OTvP11rgv3pMdHYo9T28C0onwMHN53QGPsWbzO\";\n        sout << \"57SmomSDGYs+ERJRpGEVUXgj3D+Q4O4v/fR+XMAtiSOVmz1c3c2y7Ys9Pq9pFX3UF4q6DLIWfBmE\";\n        sout << \"6omLA6O/y/Y6p++EZleosnni/RH3hMH8TvZRYFW4EojNCm7Ss+eyuktlVXQhcPUOuxQ/lK1SUx4k\";\n        sout << \"vCBOk1YCMcl67xok/WdgM/lWJvovLTLqylpQlhsHIM3I8ccuOcJ++lhPABcaXmInXnPMEV9K20kk\";\n        sout << \"d08Q72uJPoU4rjT6SMbBbq8L9UA9Ba7U2cOdK5dr3rUZwQyFZBswroQ7A9cZnuCD4ugJ4l8AnUQo\";\n        sout << \"A7ghXFgGkmzItOKtHoFYz9HmxZa+3qX23EQk3jVdml/8fFh6VjpTK73RPKwrbZyclJs0pyN09eDb\";\n        sout << \"RjZ153ucSgBH0jflZbSIoQhPdmmi+xQBqWV+YjqVYzyYJMJypf5ZrLCb682KW0KF2dpleDJUoX+Q\";\n        sout << \"4pQNhHSZWXtdJTUcRdmM8Wl3AjY0QNsbjyqe8rYj/o7FJaX/Y8b85y1fGLF3qqPJDxZQgR+jKfTg\";\n        sout << \"0vlbJdh3EbV5L//jZX7EcOTDU+dvkXOSyx8zQeS+5xwVXWPmTmaTNIriV/6EvNJBPQ0vmYCjsUoU\";\n        sout << \"6hD4EOcBuuOXADFmEcgRZl9z46qgDwqRasacBLwpaICbLCnpc8Q7QrBhpbmeHsWmqYtK6SzfiQ4j\";\n        sout << \"e19bNsz4SP4zzFzdEpLl/J7PeNWURM4SUBwZcNOZbDbD8as2KcD78JSCs0sG9zWL12JPjZ9lJ7AY\";\n        sout << \"lN9vqJl+2N6H1VGiJR3eO8Zrb/lYX2LkSz87AzRggZxDXdv1DjnPzGj740McdjWa96DZeexzAKtj\";\n        sout << \"DVHwn2PFsYDKzvmwr71zUNYLxwcK2U3ayJf8nuuP5nPkRDwl3b8ttN9QHNo2JWabnVJKWid0Dmiu\";\n        sout << \"zRus2qOuzcXLkGbgE5DdmONYcg7qznU3ostY+QyHO4/UZbDpqOPG+uXuk3SVhp6yBEmO2yE3T/We\";\n        sout << \"WCWw3dfW4DlOTxb4m+nf29ST7WIBoNR8omWSyxyZZodAXRy6NfOnpkYrgFAorXCprqzNiRLSbi8e\";\n        sout << \"hZrbJNNoqEUTrw1R/hXMJHftJH8GotFVuFuXTBV0wcm9eM0UeN1cWvuT/0dc7ORsLdbhNW7X9Uke\";\n        sout << \"tYEHwobKiM0mfa1dCdTWFvee2XkrmYsNjHfMNoQRUN/w+1VHqnFy1Q/qc1MoU/C6L1rPUjth3gNC\";\n        sout << \"oNr7jNNWH/tXMAEGqsHPP3+Hw9pqk4XE/B3QSbeQYrZqcZojBhWcwLJQIbSyJmya3w+QYKqie3k4\";\n        sout << \"/LNyngQb4on/sr1vLNCNc4c8yJAxV/nMoNx5cVDBVg/HNAh+qwhQ9tVhi7xRUpIrAPICcaWaX+RH\";\n        sout << \"Wl9jEeq6PdI1bUaTdBvF7DgSvAriB22oHxG6Jy8X5WIycn4FHMF0/ZlCfwccg8HcjvZzDlvFHfbs\";\n        sout << \"lepXFAJ21XIOWHwDzG19VnizLorKXM/FmOnFwClhG/+yTREVbWCjaTkDsOlWL6JGOehVHckhxWRM\";\n        sout << \"03eFtiNGh2k/oqsqHkDxYtt0rMmGly3vLlLN82Eiijq2iNo19EF+euIVAl2h1iEmOGXQf6lkXCCZ\";\n        sout << \"yscrDfP3XEbe0grXP0+/ETyFrAAl3/zoENKR5MUYxVziTQ2cy733o/8aX8J/X/hFTm3ZFVKKmZRp\";\n        sout << \"vS7HzVzjj8i9zZNshaRzWt1jYnQxKtJ9w9BEn0VLGcb2spLOKyctfmsughG6DDA7wjjkmNDNPFMH\";\n        sout << \"mefa7RvWjXog4gPP6SiKITag5LwuBDotZn966sOaBOWK85QelE/NBsk4hCsf5LNPkMDFJYwB2ZUK\";\n        sout << \"g/+WbwWHIGFI2O/sNsM8W4xDyia/k6ZFpaki6uOZ48uR8uLOu9mMR7NSJ19gRoe/aHeOAi40FC8v\";\n        sout << \"K6Bs4rbxF82hbJmSfp64b0d8pNPevQ4X0UEbQI8d9o8RjmDqgVwV49InO/hobuZNWyY5sIz+8b+0\";\n        sout << \"swgWi4uhT8bsQvMswskKsWmV9bxrrQ4EJFOGtzCIeC1X0Kzm25gSf7biU85dr8/3dXDQcEqdL3x/\";\n        sout << \"BVrjeWsXd3ko8dQTJzD2kNLqi2yNmymIarjj5qzTxlnAZYbJFtFxtPPO4bfPDeRRQ+D5PhiZVZn6\";\n        sout << \"a9WUtuDFmwKmoZKZIaKQfQtwkMQq6F03sU/EsO5UuglsfN9gZmLVZrNR89YPC10gM3cSXmABMYcx\";\n        sout << \"OHnaivD81i4KmkX23r4rltxlqsgzdUKiGvEpPhfRwD1bKlKb+dTFgA6x5cYaOQ+2/KqeGn0JvRHB\";\n        sout << \"HWmQQG0aJvlLelva7sG2mahqaTpsRGunwr6EkeTDwSzY711r2cNcLBRq5VGIg9ODw/Pn2eMN1Sza\";\n        sout << \"0xBt8eEzdGYywXR7zpcalcJfOOKUdpm5D/Lr0Q2y9qGhqr0yambYW4ltxSreDuBWLTp9lxjbPmeg\";\n        sout << \"tpdUAqTqOEIfskeG6FVSzfTSzUN+q9BjZw4RE7aWCtqKm1M7hF7o9FRLMhqws47tamk3AZZTIC3x\";\n        sout << \"sGaCMG1/h/gu5bH/VQUZpzIj7KWgf7PnJEL/WhAsjjgx7XRcEW4OE02pwmhe5C0WQehHYOdTSTQ3\";\n        sout << \"Y6djpbeCYLGJNSW42W9N5Qvrp3GTYyqDlRcFgsZFDK0DmBonUAsSh6Ytr8pxPSNWAejairTkKoi+\";\n        sout << \"gon4K6TAdRrK8VQSSf+eWE9oTlcteftAn4iWQzY99aisuJP0MzOJr6gZgp6s2GlsaiAA0KObTlwm\";\n        sout << \"/SptTPhSn9K+d0Os8QMMXYHlhF6waJ4i2NrCiMulOp0vHYPOKmfyCI0+hQt9R3ArNvY1pqhwBHYo\";\n        sout << \"+PMNqnEJOH28aU5s9HyHPOkQOOSvMTYnUo0kOns0sa2dSxuaZOq9kb7aqV4qG6+ZXzFL9FbAhth+\";\n        sout << \"4FWqkdDxPUbYUh9pKNQucyvCOtJdlrQbrJgMOTHShadJl9g+eF5boVBDAMZI5WP08py+U2sw19IE\";\n        sout << \"/uju0H1VxjRPA4xips+lxnZdrgWQu0zG2nHeLObhdS/gbO3R25LWZxUILdNWpVbxuQrE5dRWlIaj\";\n        sout << \"aB5qbQO7zrwCwjB/ZjDc2dNEH/4lvPv8vnEehJBa/sIoieseVzcQgFRLK0n20sdaXil9vJ3B5qyA\";\n        sout << \"UUJBjOT9I8dtvWAP41Y53UOjkkuqWOoAbfd0sp1wxpmjOgzm3BhPoGmLhJRlJ58LkVYTF2Ix/Hwt\";\n        sout << \"ZvLSvOwNE8HdPFOU8BALTzAPtVpfQCKKDD0iOdAzDJC8NX77Ar/8UGHkgcJP+9LiycmuPnxOzhGa\";\n        sout << \"tsZH//NolNfZ3+4HA2wir+hHAjw0ia6d7OSIJyLV03kjAsL6I/CajovAsT8uAkegs8ydmvLryqGB\";\n        sout << \"+98uO61GMTuZNyrv6TIG0oRDpNiKywoYmXoqdum/Dj2UtsE0A+XAb9KK8Nl6RIM27j6vkFWjgC5p\";\n        sout << \"7Y9u+TIHFd18fxQ20A8RuTKooQaC12h11+nFUR2kAUqkJq0e9LWklG9jiq2kIsfHr6jORWi5b0a5\";\n        sout << \"Tdu2IDMtMCS/58L3+RggG0BAs+hc+uX0txQJUYEUCmJDlzReIAwTWj/5j6YRFpq534fp38muNl0k\";\n        sout << \"OV5OE0UU/K+TLtfXsUQ1QCbKOvEW7RcDICz+5sC2/FIGC0B+5KY8GUeQILlr33+LIxJTKAQwdp3y\";\n        sout << \"G5BZk4EXDjoLiis8OAO6TzgfktYXL/KwAicyHdRzSUAuzQ921QA8TeKMAPd+4UrzhUp3S/cgGxNF\";\n        sout << \"sF9DVFCaYR7t8Wg/ecyZ/Kn71D8ClkIigOWuWyN2XIuHgLVb81DF3gDdcoiMQ9qroTmrCbJCukft\";\n        sout << \"4zE53jcVbaVnhr7hK56cEbe3F1eFW6pEUFNLOxFrFOwyiwngw18cy/PUThn6kpenQoYS5f4FXPul\";\n        sout << \"qlFnVMTXc/j5mWhRSNXddfti53WsTB9eh6UI/MSWNE9z8kjdMUWn4z2perojF4VUavHqea9U+6ms\";\n        sout << \"samqyF9mL9CxEhDNL0+Uof3C+yPo4KSqMC3or2rqSe8IyrAbemjcfKGqMjsxBpSGH0YcRSNoHGw9\";\n        sout << \"wC6wJ37LuOncQ3VLJM9f8zgTpgln3y5NnKz9nMrgXE017K+nW+I/U8o0XdPAJMgXlY66pfkJsShw\";\n        sout << \"JmidbowoBQGAXWO35cYQ92Avtitrs8kvq0GIuUGdIsej9PogzuW1ZLTSNJkee/S9t39cXyQ9YpzC\";\n        sout << \"KSj+H4uhCrGCQJ6Wts6l7kEhHG24Eu/mwSEw0fTTNqL5maeimxJsOdmR/IEVC/pps38ZEUuTJXuq\";\n        sout << \"J2uTsoZmiVs3ImbIkjHnN7NF0I4ryYf11Qd4ULqa3eIjraoiDn1KOZIJK41CkKOYAYIts6aFS2iw\";\n        sout << \"+34SlRxtIsIrn29zkOG3L0yc0o+fRT5gXHXPKv3eVmNca7kPGaqSrBzv+c1Fz6ShHK6tBjiPVtwp\";\n        sout << \"S7k2/05j6t0tMny1O3QzQZDTdaAi0Xx5yg+1oyK3M8XrgLsEU5aN7XNRorjMSHv4XT+xhe7F2B7V\";\n        sout << \"//JUutejh1StxytV/AswArYDSz63Q/7Vs1Eel0/Fkc/Rz9gYPKDqYo0UAFi/baWoUrSYZjYlIvBb\";\n        sout << \"fQn7nAgDTWd8Ry8dx/j8kUSR/CBWx+xz+tNPRl0TjIOWZJtT/MOqLZyODDBisgCpV2en/f9VUr0o\";\n        sout << \"V68sh5TYTczlcSA/lngZLj3uNH6n5Vh7u1kjINhOiYzYgaUzbruQJycDF096vEGTZ8JWnz8PNzT+\";\n        sout << \"gkDfWt8JtyCsQg3UHfO58YSspPbapErvM6zc+nOzOde7dLkjj10pxRtQMGc+fES5ER9QLpNF8wIR\";\n        sout << \"zGF4ENLZ63jytxO/Y3klAguefc14abKtLaOi/SfWseX0HoNpW+cA80GVq+oYU7krKhh4n7mg7NHX\";\n        sout << \"PBsUV4gmzhj0DkVAgmaGd9qT9KlZPWHU4vf1pGE5P8mIoDIwWmpFsN2sz/mEcugGWAT2JhT6CP/J\";\n        sout << \"sPOCAB66Ln2SoLzSJvBQwmtzdBZm0a0NF6TOloCdC18cJZfqYFuEJm2gUozzFMPjLKonOR3Zhr2w\";\n        sout << \"CpBUdXL90wQKDIoTIjnOIorXzjFZv+O9O7y4OBDpjDsFrcdQG3AZPtHcQU49W42aH+6XcOUqlxRc\";\n        sout << \"DYsJdg75GZliymNIWgfGGuQxJ5kysL8iPjmCxVGNnXM5FvYW/JYzcXy4A2DXqO7eyVBw6KXKHxq0\";\n        sout << \"SEF7IIjjj0TgUp7tLKY7/L0aIVuvlNblobJNZDAHYheG6OG4dAAnwaggRO/dneeiQ6hDtFbenFmQ\";\n        sout << \"SWdiYK09ZQIpXbdlXUlPiJIG+mtHudHcbaaZwVlYS5iG3NIOx/IYdKzYnStqv+5NpkBEPySa0sYy\";\n        sout << \"npsOyO7Hz/09SMXbSOo+RBkLYrYXiLtH9qiSj+Lv2N2ueJw1fN2PeCd3I05jcLJwqCEsZ0ch7FfZ\";\n        sout << \"1MaXVqdKYBD3BxBs+SY3qtHgffqUrGXDIbFARc807a65++J1NLuoD5ZXI4empkMcD1O2j46tQqdt\";\n        sout << \"MtApg+jZVUSdVCJl9YArIMwOuUdgH0oPcOItEBlmYRmDDcWX0E/fuPfa6p7u4X6zwQNY5PdI8nG9\";\n        sout << \"+Qp+PhYXKt4fB1xEivvnHXy1x3xMmDwDH7qyZEmvpiNPxZSO5ZGUbDdzUH5AwTCxVRA2/Yd9B0GZ\";\n        sout << \"+WkLsX0Ds1K55I2cTSN5Tcb2IgT2VQnFb7ceok9bY3ABeIipxABdKzhLiDeYDfeI3is/pftpDxGC\";\n        sout << \"vkyX1ZUnB7cpC9lwlwwbRdXhQ8WidAEFZNmt77xdTVeyU4cVby6WCBelfRiKd0+wXtQsSp8s7iRY\";\n        sout << \"rNHSq8FQwmt5LPdhIsvLlD6254b5AV95lYKnriWhCJ3frsNaqWc001OhiyRT2FTtYIb45pxEtFw+\";\n        sout << \"fY3kLR/xs0V7KWpXJCyt7uI51vRNCIlI2PbfEe6epAMg7oLrbXOtjJ+z6f6C5DPlVUf5pxNNg7PT\";\n        sout << \"EEGuVTVEkWOD/hKQB6iJfhLqIbgfOnglwI+pR8JzGJSJg+yuK82g9rRvzhPvIQm8Y/xmsMoQTvg4\";\n        sout << \"zBpA2kgegUxYS+0VXG6ZEbO9CjSdmtUvcIpa1yw6emAmjR1TgiDqtTtQVWksXhRNiQ2XBal/YlBE\";\n        sout << \"+45tqfGRjSiInj056XBdqsQqcQVuXcxXMT90/uslRAEV7oTmVX/XwSahsuP1VIevdVI+rC4liNj8\";\n        sout << \"yWmDEdVfQOM0u0MgevyXmDj8BMQHznlHulIVNQRhEUmX13ibjVIDLBHDyozBbvPneuY7hBejxnV+\";\n        sout << \"0kaG1VGjxSaTpH+jOhXwK2UvlXPTN+FM4UPLS93zEzEiJ4EWDUR1wL9VUXEfx7IveXQSYixy/rMy\";\n        sout << \"zpSX+UpoqFyiiKaG8DGxg2hu4CPjNXfKVI7/IZAFIT6KHcxPrrO/3BZ2HTqwpPUpD7SCiVQkqzwd\";\n        sout << \"gA5zjgo5/vrSFtah1TLBrd3PiN2RBsGn4EzHBdR2IIrDQcE3uB3nEQRyWPhRcO2pkVry8RtcGh4b\";\n        sout << \"hkH0XKI26GAIC3cEuRzdwWU70JlrbuN4beXlL3z3xqxz6J88vpg599N6Offn7V0Ki/z0w+kIgHJN\";\n        sout << \"H2CSc9uBNeKfQMGNdQzutSckMpg/9neWQVhgnegiV9hJ+L2lQODdnUCJp6nBYPHqkgtbOAEFRL+K\";\n        sout << \"tkKQcyc7YkJs20WUsItmeW36T26+0T3uyN72dbmGqBaZIonm32MKPgh+sVTbUspUiLdPGSFz6zuF\";\n        sout << \"89/dwHkVzv/dndOHh5yb+itB1LaCjsDRmdHw9uBYto6eJDdPa+XYOBe2w2qLyOHph/3NaHrQI8ia\";\n        sout << \"gfvPuVAZ+V4XXQgXAaWjPF0XtyBmRuEm+C0J9nWznqrKjja+HXr+hnmlEuJrHGFIJeTcpNrrbcRi\";\n        sout << \"RBdh1oiBTCG1tipAQeDf4fqRy/zrvugJg5Rx6/4fA39XHXW+IjqLMuOpA1qCpOWf/4llleXazoM1\";\n        sout << \"J392TqpJVxxg43Jfxehz+XXl//IZPMCoiNeuztiSaWuGsw8ZjBAc8mMnzehBVPv28axiOixuiofH\";\n        sout << \"WF61WGuAUXWOZ5Jqsg+7dMuHhTZznTPwGVj6hzw0cyL4KEoj02zic8JaSnnprKzhM442UFIADacs\";\n        sout << \"m6PchnrjUqfG3D9DwbGIwwmVFXePtscyV6vb19r5nITmXaQHm2zJdkpVmwe8rB0Vusg+d3Crpxe/\";\n        sout << \"kOWVPy11Gv/rkYx/1BsKd7SQJfTdsZFABUTjLIaJb9pmry7FnI+pNxWNfIyEu4wHTyNSs8ZWPOlM\";\n        sout << \"0oXY2CqzRqdnzt0rOdEp/ncMhjN0p8q93nMhfwSlH3Fvse9KZ5Vrk4Np8HDTOEjjgCQO3vpDveL4\";\n        sout << \"S53oq7IfTsp6lKSyzR3h9iYqa+fnr2G5wDoIlLBPIRXOx9+l9OH64rrNITKFntHEkFFJi8rnkr54\";\n        sout << \"0892mQk/ia9ELfn7V7pxKnEgXnSqDwldLYAWSD6hhGmvUYEvEKbS+4/D/zsfnauYNFkc+cdtPuFx\";\n        sout << \"uo6oFl+6Th5VYBwrmk7xq7j0vu9xxY0NfYXkRcd2gp7tuxAtMn0gJVbfu+IfKW7cneAT1fszraXX\";\n        sout << \"+qVo8SX9+d7phb7a4srtpA6513DcZSBSObMJ9RT+HZeYDn+3l986vZGAOJoQMGIohkU79sFTdqfR\";\n        sout << \"i0lfN9X/JohokHdD9eroMq/F4vMWEDj4ax+OR1wvJ1T9syDfS7YT9IXXt1eXYL78aHwoCJ352IQf\";\n        sout << \"Rv3phfVYK45OdBn0BqAQiUhWdQxPcwuvt9O4cs1JdChTjSSGz7bKtOPTBxst3pj0butIF1ORrs/h\";\n        sout << \"n9iLG4GVA///xeK2m1OFKDuk9AQK8hX+Nm6lEu5zKZO6NBJjSzUX928LJ+Wx93h6F/I2sy6hmBNS\";\n        sout << \"0bhas2TNmGX2Eiu/EslEzPudjbp8uBKLCyHvM5P0kiOdzOqfDD8L0qyuOLNumauOEVB4EuSoROZg\";\n        sout << \"uGPoG2xyiVGdkKIXIfvb9YjLpU3mebY73zeInPcaQCVY0PcbvEYIs/wMXch9CU8FP4wyJRYsp5rP\";\n        sout << \"XELbGL9uDF4FnhmFDjVOTX5j/zV/jVNNWOv98Ue2JkVZ1o1gMweglPMk5Gnxn+twxl/OY785uZkB\";\n        sout << \"CJdsVSNbXanSF4dFQWhkEsmjXyA0PVsw7uD0tfIaHB/BekjR2hWcwbUmsAUzIm4EVvepSk3Ec3rc\";\n        sout << \"v0ZNE6FO3KD0kNueAt8RvhpxbO2AOL5pm3vCt3q7lbz86dalSf4mFuv23Di0Dyl8iZqNAHzsrToW\";\n        sout << \"50Wua4dgrUEhqSgn8ohZq5Y5tI7m3uiP2LTLAfVDag0TdA7IAREMvTT9F3N2f/2Ff3j3b9HW3MEI\";\n        sout << \"2PU2HZOvUzJyyOfuc0TnK2DXpyXwGWfgoeAQ1X8c4CZhEfecXs/FXM+BfUyJEBAxnAkHxSV2oKW3\";\n        sout << \"PPismlBkfTS/XPxnChKJu57uy88MTaL9cEfVexPwEiCWC8VOBAd2nQUYouKadJLVx2UliM/dKQu2\";\n        sout << \"oYzUBJKlphHkLMGgUUuhXmGFa0KFkpisUVwFtyX1ey5myWvdyjm3xGkJJW7+6KzKIuFZ8oF6QEBS\";\n        sout << \"thWf7/v+I+TMG2FI3cl96g0zhRnguGVWeQ1NCzPRsDmK0fDZcgnCGyQGtQkdVgRBysC5hLqgnq0W\";\n        sout << \"+2S+oRxhL7AY+DaVGOHfYnI+7jyf+NVcHhBfqw9qmVH/rZk6cuG23Lj3nS4IzdR96a70EWufMtHo\";\n        sout << \"Mu1zlfyTEcZ0HgZ8vZdaBzCDRT7nkqSou4/uomjQzFUBRkZYD+etcrNb70zi1Pa+AR9kYXVJIO04\";\n        sout << \"TTRLgikAT4Ja36SlxjBbWDS0swHyWy3ecHhdKwVvZcklA8yxzLvdBbiANv51v/o4O8vP2AAqAQV8\";\n        sout << \"AcOjIeo46sslQzYC0aYgaigzGmsx6nYGgQ2zFH8bpWR0KNnP394GdKHx0AuIjmC1/FKtN0KVVQeE\";\n        sout << \"xcU6gbb8Lbe9Mw/WZYDiGtSVXrNBlD59+0dNG/SAyDZj1LqU1Fp0thu+CzID2LVAJtA7z4Wlx8f3\";\n        sout << \"t3iMWYIq9+3fDuCta6hORK3L/FUG89sB3Rqbi6OaYW7nu60+tm+qRP7ECwoNcyVFtGLOOMDonoyM\";\n        sout << \"uHGfkqQcEeQaAfPeWl7sEbnzmBbdqZ+xUj63WTpGQ42Ceqaa+LeoUJT3zdt8tDK4Hc9j39rZh0zX\";\n        sout << \"HtwdVVVlozsSQO6HvvElDrBwO8EY/YPczI4dUGCc28KcHNgEQQ+M7UenP4mbqoTIbo4Q0i7FCvEu\";\n        sout << \"9/TrBv0JQ88ae2xds6Lk5xsQomtH4ITr4VYliRfDO9bD60zxQBhhiHo5joRQ7sW/t3ms1tDzsco0\";\n        sout << \"YG4xVvyLzUHdDh4FBNVXJ5ZHnHnTBnppmNZ3M3ucVQpk3mEXauKEdPt7AWwdX6rCqNR81/ZasFJh\";\n        sout << \"qTU34x7ZH4Lg3Ut+95CHI1qubhh5W9feqPOLbvUaJzuqxlcsTZBhY43N1PSCerMFFez/b1/Rtw0m\";\n        sout << \"OAmNLDlwUfsqtrs4q3OnKlfXyHlwuIDe3fClgcE4r+9i6QSjVzPDaPfRwE+eTFRKPm9uhlLQYAnP\";\n        sout << \"YvVqOtnUCbLQod0SIakYVb24cwnvuHfGwx1tikIizumhn07N/8LXxtVGth+prxi0Lu8b3hMI52e0\";\n        sout << \"LXdzbJfXUa44mXoyEL0ARMyhaombmUt6BX/HaBLx19n6j+munyoheRlpqIdIMWllIAaEMbxCoyXO\";\n        sout << \"ExRZf8NPFANOB0hvtXhN5U17hleB7U8ri/6Uf/j30M+jglbucV015gMXP3h+E8qg8aOy/RoxhkWi\";\n        sout << \"lJBmD8OIGytd0GcoSmpzYzpoOQ+DVNMvVlBJxzG2sQy87PtAiJW0u22n5LGUVEQLxAJrRDdEiKcO\";\n        sout << \"zp/wdKOlFD102SjWbLp1mQIrqkjVgGRs+M8kIzTSyUw3HQPOvucyewaf30EkILRHwNOpUq18WxRt\";\n        sout << \"dE3BXUtm6v0Xc1rn71+Kbka3pXmU3qoLLQaCLLFQXcDBnKGt0olk84XYOb0/cTlnxBJiips2Q0z1\";\n        sout << \"CD8+ny5LOekJtzcze0PcYimx7Rl1EilhFrq9fF2N1cdyF2skG9UfoPVor/6U4dDGzN1qTzN/uflE\";\n        sout << \"harEkP1c3/Dk4BqYx39Vym1nvTSs9dYVYli+6K9EPaxjUu6ng+3ad48uZWE0xA5i8DfEYU+VBYSg\";\n        sout << \"ssaHO3OrblCccri8HgN1U17xnDR5C/zBxpcgoQ5BZfs6GYsjsDmIHz4Kq7dCvZ5xXStqZ9FEPnNf\";\n        sout << \"oeAMmWp6H15Ci6pqj12u9lZRG4rj1kQvaBvnpKgWOiscli6Q6mCTEsgtIYvmQhds27mbO6Y+uwDd\";\n        sout << \"ZP01VsjBxmPZaLxpUabmGIZiwAsAZKLN9qQgRt7EdMIDsyLehadWOzcjiYTHrWTrQQ8R7zN3e/eT\";\n        sout << \"NYJ1wsWhxMslZ+Q96vKEmejIyWAvcVmxkCuiifp6VfXCF8BEYRsf0lY+Y1VFe7yW1BaOfy+8Q4z6\";\n        sout << \"jtBh12vD54vp7dOo9xGlFYZD/w3KQKdKyVnnqm/tbT/pCrc/X6vbrgsf7sIbV7nMUJ12FRKYYX8J\";\n        sout << \"p0C9T9nkvrPZkxNhUKIMkra9+NT4tMsBPw4MyQQsMmyUjLjZMTSRiIyupPjo8U01tXEXElUdaNxj\";\n        sout << \"feSkHmcQS1PBXV8oQfQnwEIXLGUX84fe6q6i46YrhrEhjf0crtCdpYrDOuhJPAKnu46i0sHS+xRG\";\n        sout << \"B6/685zGr8K+1ET/1RqwR7zo8t0vJf4zqhAY8OpWgvY5ASN2f0gK2dzBMfuqrai05tWaJaUhYRqL\";\n        sout << \"7FufcaIyxbmDc1laARn/mvN6pYA8C0VxexvsQqF0OlOhpLOsY31GPy722kMJeKxFLuFYYp9DeHQS\";\n        sout << \"Br1KtYMU2S/RnQ/sIbzZ15aSbYstM0K8J+9hxHCi4aq5K7KGzzNCSsuMTAz/LEDEV5UKCFd7se7E\";\n        sout << \"rs4gwaKuHqH5b9n2cAb1wMpM+VMttHtz5oQplOyrZaz1r5sUV2KGkuU4oWHiHKSgu/tvrBvU9LqT\";\n        sout << \"1TB0RV405rPe3HjtIAzSPD8/VUHZy8pNBjGi/vqZR/ybRNP8GQFWZZ+vt6l7YMX83DqWbTbfk4oR\";\n        sout << \"C06g1YnZcYt9UsV0GldCGJQZ5oJ/UHLM4bfRzSaKiRAWTwOuDv5hHL+AKJcYOvDub5pCp+EsZh7h\";\n        sout << \"kMS9v85LQNmI5vUHbhrS8XE/2Zuki86Oms0AtR3aVWWGWM28oQopU35Ayu0rQE4oexb5NDjsKcP5\";\n        sout << \"A38n8gS7O4cbHdQ3XAIQaPoUx6TVK4xL5Pc5bUJ5aRsyivvPGd6meP4AGW8YBKObMMTL6TSRBD3R\";\n        sout << \"e0B/yqLXd30yRNiazNfw/aajOIAeHfbNuFvNLeqe7IKdpRrDyLg29Fh5n3Pg4Y5+vdaJigi2Iy39\";\n        sout << \"FKvhs6zp5SE0tJubMJuFDUfgYqmW44XVNv8z+ZUIJCYQScuSkCfMmexS3LczxvOTqTm4yShuNr5A\";\n        sout << \"+o4wXi9n6jEa0pcjTVlU45mbOXiX5ELwfbSpYDorlP2BJTZqMAvnfMdxdX7cs123ysQUHxMqKK/Y\";\n        sout << \"fSUaJORhU5zWNpmiSFeTCsH0uVuWMj11H2ttk1+gotSz7I/RCvotGNzuS7SqqOZzb3h6LpjHtplh\";\n        sout << \"04W+r6/FtyAq5z9gOphIZQUhoyO2tvbY7aCciCBBX1lugJWKgCQ7Ui60G80225lAU4b9QKOGzwN6\";\n        sout << \"hqKtxP6c9Dh+rxiERh4NoE6rctk+CfBoCAxDOEFVM/bcWlEbed+KvM49mqrDF9epNJP81oIZZb4i\";\n        sout << \"afVphDQaM8LuV9LNhPSMGLOoPeYNPAxyCHnlNyAsOrZK7otQ4lFc4dLM66NFJBbSA5iBTYaW6MqM\";\n        sout << \"qGCTCWxu5MzZbgNgwMv7QrTgPy4LBH1qwST759B3Um80nBimBa+8HbddXPbsqC/KzjW2yjodKmqx\";\n        sout << \"2t6vnINn3v5Q9dFFKv4oaetAj2dqSfbfCAvcMvS/Tl0Ont6PZt8iFpH2NmwcEbrwSY/2cKKqZIh0\";\n        sout << \"sVj8a5fxwXHAkMcov5J692QQf7P+OUzmkI/P/+TlBoWYW5Zor+79wh05NnrDHqdVMY24aSRKrdIE\";\n        sout << \"qOeME0ZEnPkMyOHJRUzHoPPw5+r7Oowvbske31mERKc3Es0cCjhJ3bab+OSaoXt2xfzgLd1e2eXm\";\n        sout << \"DtOlfyyLT4vK55WTN+IP8xpw+e+D5N4bdGDn4UC13jvhrviBYxasYYU/EtFWpFGonD17FPZ22PAX\";\n        sout << \"pGNpKbM9Eet+Cabzi3hJjAXwKYCmTXHk8+aHceC6DtWExR06Dj1QKoxSJg8vcbuik11BP16e8fEB\";\n        sout << \"UiPiV0hzsLwtHdbg7uZQgvd/e8qoyivF/NqZ9e6A0s4r0NoRO+6s8OPAL1QTpavvLtDhF37g+7HH\";\n        sout << \"vjGkDbTbzU2TOdzl0OvxmSezNfASeloEOSXqIkjMStawtwC+DgLRXzMhACjjVuc+MY0D+/zGt7lp\";\n        sout << \"hQlKeLuLWLDEUYNn3Dvb7G8/6beGyyjKHlHSOr9WK90JsS6OQT+xkEZnOibrIzgZBwmws4SPrhuf\";\n        sout << \"wwwQCiHH0xjOXF7iT/vi5qEKbJePKxh4m6kbcxxaPmP56M7TfmPSYJ62RTfZbnq/FIPurztCgSHG\";\n        sout << \"jmTJvBi4m1qzKgiwHVBoWjHK3wnjQxTuerxN6CMuTA8mv+ayvrabdbRwpVRJgjSXbb/Vzgj2e0PX\";\n        sout << \"IeHUocfZtrz9J0D9f5D5nhIlqv/aSodiEn91GhsasFWwDWwSdvKwAnTtCaC8EF/+rLx/qzCneheg\";\n        sout << \"4gGRJ/VgaQ4ib9Dx0+0SnOEWoE0GJAceSDJImKJ7yi3Oo7Dxy3J/tsJFST+JKNuakqFkNCnTetmm\";\n        sout << \"FkVNEXbo8tKzbeuXlextGxSr3ZCyOYfxXsfNQUJawLDxpL6fVpaDbf6Ot7ip2nejQHL5wt1AqQIA\";\n        sout << \"GNwV3Gszf6q/bx3vXKCTrkL+AFc1VmJR4ZShMwVlVz5pdzMWJWmal5ivqLFkRQ4q4HXA1bPVhS8O\";\n        sout << \"tfnYwzNTBMRaNMpsKGTL7MOOHdmXUHDPKhoMki5bX7Oy66C0x35qEGyTozFQgygLOMFe6eOleXF0\";\n        sout << \"D40Yu6VhauEQko7l/VN0rICXaTJSaemFIgmPLT7lMfrd3Ta6XNKYxXB449SOC63A4doQBIFJnekm\";\n        sout << \"VO2t09QLePM0/ztdbA3toWuK8cTSNZgelZRbSlpgE0+d5rqxjlxmKom9I/8kj5bjS8FrQAbbsnR3\";\n        sout << \"pLEArb7kuWg3W3Gc0pdlONrgWVvoYpTtwQsrY8QfZmIVmQ+Dkcz4q+LqfYRU+TEIM4Y06Gm67JzA\";\n        sout << \"ncMkUYcVm5YS2Adqe/VFsctKTliHEPhPRFpo9Sfn7csGTexvc+IYB1mFIWy2DjRSsfIorQJ25wAy\";\n        sout << \"FX+E8PlVJPf7S9IKNM7NmNX4k0aqJYJt9VVuDidECJrYiTW9vsJ/SDM39qR2bQ01w42aG7/ksF6B\";\n        sout << \"tWPS6j9Gr6KDOtdAK9UOof2Oq6uI1ENoajWJuDMxe9fT3J9/1ruJMMDE4dn8eSXCi09ip7qbnrxv\";\n        sout << \"5splSpCC7MvfBr1bpzbQ6gsZF7tPXz9R6FfM1idioIEJITqqaaYdABv+qwad9Pwv84maHHslw8O0\";\n        sout << \"/SPCYyCpfOAbbYuVpw+cEryeS7RD7LNom1M2Qo6A5Orh6Qmd+xTExUOJCxkPNvyxUDezWtVCPxHk\";\n        sout << \"lu2vn9lqjj3UaUjALvD9xB0WsGhdJbOUtlQw3e/gEloGvQ8rLamwCBAelQqTTwM10iHkvx/AzA4p\";\n        sout << \"TZSpfZOyXY+3HEjROeej+gvP6VXL1lWcYSrEexizEzy2eN/H7kVTEgnHOzYwp2A8x6vlKHWL1gnU\";\n        sout << \"lGV1R9H2bzmhj/iGFom/TMYWmiv6mtUe3PTRTIo3W2yjlLKnBiBFhWMh8TjfcLz63dadzCLEV3hL\";\n        sout << \"D9DPn8fnJYh2HZyd/N2/lVDtEDnxqyd8C5lZnxY28bew7dB/n5euYTo1H6zWvpIHlbbbmXrHd8VQ\";\n        sout << \"iaJew6T+G+bBxuUpUQlu1NscX6mcHZBoT+/g8Ng1Q8bmjiT7/c+Pl7wpRlF/0jwhWxPIL/5mlmPf\";\n        sout << \"+pHBfYj5BWXTDrZNchJKF5Pvwdnl0GbmJsPPiQQ+Wvt+y3lt0wv1gwefzFdGhi77EJyRY841JGSh\";\n        sout << \"LU/TVYCUFn1MdrtVLhGdomxo7Bl6Zj4bZaYlKXf3Qru1bRjD0Ug2tIePfjX6TPymfgxBkgGQ0zVx\";\n        sout << \"dJuLeeRNmhIFVH8T5jJTMcmd/lS9u0hzXrEjvpSFKPmH+Fmv6LJF/D0bl/V0rYEI2gKmpAWJLd1M\";\n        sout << \"iI6/XFF/bt6tQTRu+g4WgPWk8HG3VffsHUSAI7jDK8hjrwrJm5AHIa1a/PRxiSCH5Hi2EHCPRfkB\";\n        sout << \"grfcTEwLwHJA+j0zK0tV668Bal1NBw5bJGMzQSONvQqB/vnVqcRDxhCyztjW4oAnEeeBKPlAmAsy\";\n        sout << \"MlrkLbkVwjiaYbpzkYCsO/KlIAgoahAJEOLghLQGBuhP0voDuN99bKp5JZFaGlaaycEuYFHyk9f7\";\n        sout << \"zo6Xfa+hhmjfgWJ8KCFKKvr50ndwdqRTafQVxjZRe7QkwYB5ZIpwYehKsXlr5SfTLp+ANmZqP832\";\n        sout << \"yXRF39OZLGs7xtsMmPdI6WX/xsOKiCc0oLHdzH7y7tYzLVQVSFdRZtN7HA2r2Aun8gTbLExrbfRW\";\n        sout << \"+16+go4YQEubnMwW3FeRQqbpM+0GCsiuTlBPTgnvNEWi1n3JHGHeJLs/0HRNo6ba+jVE3vIZO6B8\";\n        sout << \"NN1s+3CSDGA0uqpGg/51P21F/Q7wHDgQDxRuTP1KQGNm4u8A7Kbdw5rGZUb0ZREWwGPfUpMU0qXi\";\n        sout << \"TgY2XA4rESFQRvn3Uo8jPP7UOZgKM5bsdToC7Rp3wuKXJwBlmdTZgdly6CmELOILvHVNtGHg4yxO\";\n        sout << \"XA9Co0RF7RsHOg1b9XzfeqibiK27ZiQnZ6sIvl+EdmsnxOY+Qa8oUZdrQ0JnFUiZjC0+P0760Si4\";\n        sout << \"i36AOc4h+GzZ6WbG0yPZlFAFEcPiBbyOCp6VoY76H32BskEuSBJx0U5+iFKvkvK/6lyvr9WDTSX5\";\n        sout << \"n74qoW6/CduCm96RcKbi2ywZ0Sk8vi6V+tWYUnrDaepg/iY84UA0qpAw/QsNZN99BqOlNEWftRVP\";\n        sout << \"SZhPmpxzE2xg/SLUwR5y7NRijA8QalWWQf4G9TotViLV1IkftS1d9TvTMb38vGW4o55pWw5SZlzW\";\n        sout << \"kFf9fbqlQ5ktTZVol/v/n2pwBjDeKu9wbNFlI7bhl2xhg/3nN2e3mW0HikB6K81JywLpxL+sa8+l\";\n        sout << \"SW6bdGwbgj3BTAt9evqejNkQHVb8ALTkmZJUcPP3CmW0DWrKioqolNXrfVRjl9DLcxgQfhG7osjc\";\n        sout << \"zE7/8gU0JYIk9Tr/XDHdk9zzOsMZAHu6nUbKpIL/5mytR193QuNE3x/eCQpsG1dMC/alF8EGn77V\";\n        sout << \"QK8dhMFI3BQCXlo5TmLXd4RWOUmsNGt061t6ZQ/jvP7oPRskGSB6YUtr9Z6CN92wbnBUIf5VFJPD\";\n        sout << \"qf0mPU0vKaMsbwQmD8+rNG/bYItW8lRAZLa4gJR5r6lULMKvcMiHeP9742lYL97T5w5VTo1c0Ec/\";\n        sout << \"YTUMJKSvhfGPq4IfdtYmMOX9pmqd0VKlwnQ5w4pKiGRY3lj8zpXAHjraMA+46wTo9ZJ7Foq1XR1z\";\n        sout << \"eCY3xmnahD5uHBR3Va66rw3W0WGRgbuCk63WTKDULa0dWuvNw0RWy+MkZzbn76QLX9dYGrWYUZWM\";\n        sout << \"9mnQiC9yDObAz9vRcITf5PhEKduGFQgAl9CU0k/ZgmSmAYZ/wFJTb3U/roNqnptdm/KGuegjdQqT\";\n        sout << \"5utMQZwwcgV8DCuE3/Y9DZcnEMoeSjZF5ugB4Hw30EJt5xAvCUpVRA1tygRwwWD5XiKt9srDjBrM\";\n        sout << \"nmkQCbblTb/HTPqOvdkBO+4yHSGtpXfA3G0DdSFtFPO7OTwPLrUxf6rM6CQTgpzP6/eoupLM/I7z\";\n        sout << \"tlfmNGcq+JYCy8csjKaNlPTJextxMVqNScbpeYwG/9SpjmhqObv+oYs/uga5UBWSyS5ls+eF/Tph\";\n        sout << \"QSD9FkMCTY15Twa1LqEJy2TMZaDkE/UVJJB0Xe9eRQRXEgkM/7Olj2qsyN6VaLpzNBhcXT+Q7FDE\";\n        sout << \"NyZ3C6b4MeoE7zRM0/KEXc25ma/uiHu142x4Ar2icGm7NYTp/gxVRUrSpqOOK2EYoHzCTFilsryB\";\n        sout << \"JhzQqEIsDpNqmqyjy0BR5+rrfBJFxXAaEDryGMntT9XoLOF41ZMUAsypcv6yujSkbCemiaCTJ3gc\";\n        sout << \"9p0IkAplKKgb0m1mJ3SrW2WR56ZGhZuVIQ0p24yHi1ECqcEK4GJq1jMpHpqIGfxVLUD8yZ6wFLDl\";\n        sout << \"NP890I+aZC1kFSBSuj0Jee1VbQzTykN9oj6+8Bo8v9Yv/qt67WH1h/oIP5bxmCrjTzbncAT0zs5w\";\n        sout << \"qzi+jN+AcQS4qh+IiuCke78wgaLtnMJIb1yA0GkDM6t9crv7vKAJwGkEFZSSg+p9TucFv2RqCCjQ\";\n        sout << \"D5v0X3g0OpBql7+5IqXmuTiRCJE6BIBeeXVOtD0R6JORJ0e5Hy7SvT1LrIxISqZwat7//kb168WS\";\n        sout << \"cdpRlCa5c0+ds81SVFkjTKViZAnFkOHPGVgzxrsdlfTt1T/2fx9MZO8HT3p5V9eM9XTASzXM/jMN\";\n        sout << \"5X63GR7qz/5hpM12SMJvgcznXESiudVq7d7HYd0NeId04fzMlFaGtgGLDRr+15G0eWPCk7mcF0np\";\n        sout << \"7XLz9ytRsWC/WXaVx2/ucmztaGzksA02If8fHmKuIHbfJ4YkjjKjVRrthMCOLsGYzfb9Hat6WbXv\";\n        sout << \"jkdPQZd/EYGM/ZUd0wfuWo8W7yLidl+zMgMcJ+LeJjvRdBkHU3o70srnlKBaneUv7Ly/r2xPcsj6\";\n        sout << \"wLMH9iuRZ7jZJ45EM3htNEHJzrT/9PxaGKiK3caGIilUnFPpyb+HgousVcBbn4XSdkIjy32UPdmQ\";\n        sout << \"aG5w8GLvMEJ+SDAseg5/B2poqEiGstsA7EbJyJn3ptHk6I0lUFnpCgHI1H/vp7f5vhSIVkDyP4SD\";\n        sout << \"GPPTMLfV3mmMzS/IeIdOLdshYQCrL9I/C1sgaASFLuh0fZoWnNmSxfS1dVA7fU597PnuEzGn4TlM\";\n        sout << \"CVb8UdlIBfEmrFXegOnBEKu8RKspYa2TdawhfTZs1lyPJOxOewWH054k09q5m+p/QLHfmK4kr6wF\";\n        sout << \"eShsc8VFczeBC2MtoBVF+a2gGsz+F2Q8WhtG35kJuTqZK+lqB8clFAVSljny5eVo3WJ83QHoZMO0\";\n        sout << \"L8XspRqErV0+T/n7Uf9p72CQbw059rmyc2X1I1Mka7+cdqewt3RUZbnB7YD17+lg+do05keNDDea\";\n        sout << \"kkjLqmK+oKKOJUyDULGM2syzbhMrJn3WY1v8RuEVsLIUrCxgvMzD/Hwcl+lC3idwjonUrQuWWDyK\";\n        sout << \"dTjkimDohgLx3uoRs2ke/SCb7ERVtB0DMpLF3zytvY3D4ZGIdet4BGQ9H2nXNWMK9ahTfo4GFMxB\";\n        sout << \"EBdLiQLAqBJteGuoJ1CWdYGj6BDbYoy9sXSdnY4Hw0a8ydeBmFqoRm5wZy6ozEpxX0IeEc3W0GfV\";\n        sout << \"+4EojUBei+nfqmpeaDTWFgITbhplcgSU4snYS6dHxO4U66xa6N58YokpK0oSHkL42y9+Ap9qxiTk\";\n        sout << \"eDRtTd1wgP4m4EZS6ld1rTROZMhwgwZoyKizgzW3cc6o3rS7wNBvrdRMtOPVo0YJD0UZJtwCyDzT\";\n        sout << \"/LMXSVs5EQByRsZkKxNFMEky5F+D1IKlVny8ylC3oOI0VNJVxr+hIcuYjOf3adwKeslTQ2AO//HN\";\n        sout << \"4WEyXck1inZFxnDybu7NGa/WhNdet+PzgzEI43go+Nn/9AYLjR3m7nAcBOGgtMqmrwOTPJl0Dhnh\";\n        sout << \"QWv3JWK+OXqz3RFJ2q0lZP7A7EhU+3G5OHdHl6yFOh+Mb9TNh1ofYXPXL/mnnUhxCvUNYEXVdHGD\";\n        sout << \"RALydLzf6oY5id6VdYgCOcQY6c32WcJUEk2zCeMFNxyZ1ntzmn2KlawbF6MPWHqemMEvJM7YCFXl\";\n        sout << \"ObWzVlcxcnecWLltZB5xeRqDBcWetCMJvG5crQJk9V2jV3iXi56gFzOta7HzrEkKsjuYtys2c2aN\";\n        sout << \"EMcOMedGcMH4q3xkzca56eoR5b0mXeZRnFRnK82LczMxJjitaFLOMTA84YAgWWpWt7ENpJ1qA7bu\";\n        sout << \"QFdAdnQC+DKTJuLykS9eGpMZIuOarnlRH00AbK0j98XyjkaOhmL4ygSKNJQghgmFg2vyOfji/XNR\";\n        sout << \"F2M6c1HdfQK3Im0qLTXaMZlEjkWPIZTcDtVt+CdUtiEZaqPQwW1H37Eqk9gZAs1TnLe5AOHAMWh3\";\n        sout << \"mS458zVeG1d59r1BBc7pxrju9CWB1PjF19pxCUc71R8sh2D98ss2W02R8dqCAT2wdUuEC1WQwpL3\";\n        sout << \"GGGEYk8jB/4ccjN/+EdYqAulxV/Bp+q1jspEm10/EU3Cpu6RkNFZj310v0t643E1MqzLjpg7ZSko\";\n        sout << \"FkzcMRM2E7Z7WEzOQwbr4KVgXcXZ+76Xc1ahlvMqwkUQV+/PnYj68Ogv95pj6biD9vweY46XV2dF\";\n        sout << \"uxp1FG2j2e/nzzFJgFfIcsB1411szIaEqmHTUPBo26qg/EyWg0775HTFSZwlw8iDOFG13OBlz7kQ\";\n        sout << \"kTvrxy0iwvM6cTm7IqJUZi8hhC/eAX+Sdx8S6pKhOcy1q0fadSKF5cTynAQtrSYwDK0/xYRjVl28\";\n        sout << \"4oTks7lHxGE3Jdu0+j2ufxNuem5fcEgWFSKZnZGM4XLvUnpVbdjPMEjf+KJ0w8LqDbTbmZYXW69q\";\n        sout << \"Apl9sQ7AdAUcS0ZhGtACegAyg1QcJUjFvDKDhXwx5d1+0ZKChwYt8FFzqht6nWY9WjDT1i61XmbS\";\n        sout << \"m2Emc68sgA9VMv1AL2bOhXq44//vlGYj0bX0gj7ZDEdUhCVNi5aXobYv5fn4nGfTNKp8njHyqGrZ\";\n        sout << \"CT1xO+YrGMY/4qAGiBsOMGtbRrIcFHeeCMKOO/5so80js3nh2fw0L/XNVlY9RJXJA8WkEsalm5O8\";\n        sout << \"MUDzmTukLJQu6YIjFhCHjT0FA9R2agaQnGFZXiiZ+0GnsRoUSrGC5mdkZ9H6jg7Odm+aB5fD7I5M\";\n        sout << \"pHzEi++Jt8xHcbX0jyaQd4Y4pdku3xx1MrdgZht2WmCpUNxg66syuutjS6iWKQlvWSdDtlyf5zVU\";\n        sout << \"rRn2ESMesAxpmuFd4sG0j8Qm/8jzAF0Fwolv5GmJFlwKx5X+RW5Mb3HZdJYg3xou0Uwb3FBgV6aK\";\n        sout << \"mLA7GQUK92IMgRKKNXcDAPJdaF6wT4lin82Ss1QpWBBnWwLNTslobUbn1TJsg+MgurruWUB9byjb\";\n        sout << \"56mNxeoTkMh9h9fEuDZYL7svjxh8U13AgnJCgchaDj7iK0TOd6b+sbz2DadE2SoyFYo4XDTbXcpE\";\n        sout << \"LS8TbCb1rH7G2WAS2a4JKRyahhELZhOB/X+jPRtre+MNSMvoYOFYtHYXjIzoEpOgEGdSPOsLcA8s\";\n        sout << \"JHCoPcU7bFQcnIlB/HZVqbDZwVzAtUxKoven135MSyoRVu8j8nTIcM0RBT1VjQa0L7eHcgQVHPvR\";\n        sout << \"uhtFmhtUJJT6lDJmoolIJt+nxeT45+ndSTz16YrT4pODPMuawO3XIULSvkPDWNhQybkF+2jmUqlX\";\n        sout << \"brWKyviTX/IZsHS/0YMkgXZRX5McLzUH3Vs1PcjNBoj2q6tdCq2HCcIdBKH0Mokm9DLqEi0oY4mq\";\n        sout << \"kEsB6HFUnYZm4xezpAoY/wHkXRq9Y/6lOa4DtgBz8ng6/WwFwKwCIkT3/aTHzKDQSewYiU5jmQGe\";\n        sout << \"R4+wtbbRqGm4yfRc7z0xEsMESF2FJnODPSSSBAFT60rKGdGK4ai0IaYbWoWaHeDxhHVeOUYbwUlr\";\n        sout << \"dBHstgs0/k6t3QKbHDo0KwMv6LN0sYYDK0fD5cLA+92Pf8mOlOAS2YNlR0sG2GrSa8M2gZhpgTcf\";\n        sout << \"dz4j66DDlLmQaC9UozZNf2PxDFLUN8NEHu2XnfzYEyuyt0BQcTQyqs8DvrayzIwV/qiD4o/xRI0T\";\n        sout << \"Ma5RvRpagaW5EUApHgu09rkvFXk6ijL+2L+7j+lDQTgkvn+wHYwbTADm/b9tZs2egY+6pSDDnK97\";\n        sout << \"invYOsWUNUDtgvRxgFTDDrjUNX4xNifDUnGCJrODnhg41dOG4M6ST3gBgxtKkrmuHkcgafuohkCm\";\n        sout << \"w8bPHam0dnd55H+lj0J74uyhw/LreRAthXdcR3RbizO0rWIX5EDP5Y+JYxQfejANE9APE2zFHg6f\";\n        sout << \"6y7DE+GVQHO9iN/N85TOUhN5ya9MZ9fk8M2JR/440Q7gqoqNJ7w1PpzfHCyQBSszPQTPBr5WeirK\";\n        sout << \"3D9axZGpND29nMOQ8iZy/7b+5IinED5SDZq8MTekt6kgW/ScvByBVOeBbxh38DRAcClRnn7CdFT3\";\n        sout << \"Ey+kaJAYlahuErS/gjU3VkqPKGds02dkPwumMWd1G6s37r4hQdPoO0F73+5dxWwqF1dX75nQ5tyz\";\n        sout << \"J6f2pbTFnJcp4+CGMYs/SEoPzODOqMbMt5hDqQHZuEekNwMNI/X80PhnIOiMa7oK7h+8cOb9v4Fc\";\n        sout << \"07AR19kD1T6r53s77u7o8wYLp7/uf7NLT7tA+bc6Qeaiss+JLJznbb0LHa9uSUZ7dK0hvHFAYBjh\";\n        sout << \"fGqkQ2JI+adCJ/eUQLs9zvo/0GvEV4P3dZlRcuXw+y0uj/HhbMnTYgnD8AUbRYLCLS5Lx00m+Vrg\";\n        sout << \"lVyzOLy3d84zSmZMR/xoX1Q27biAyEnvZK5vkX9CmMY4lhP3XnEBfcK/UVxxZDQf5HfZIamjAbOP\";\n        sout << \"ZRyNX/+VYpWja1qGHZmW8Tc3aJfH9GsIKdls9/FKfuydYwfwr2kPuG+PTwXxiHKWWdzUXluLrmB5\";\n        sout << \"T9UCUmf1mkBM+Jv5r5R7qUPldDHzJP3njQfT4SUrNNXL/ooR2NTX/jYMqkTlwSCM5w7jYa19IDe5\";\n        sout << \"lYzspMfRfAnjG/DPX7m8H3fYqHXo6JKfWGL9NsuFzFPzbeVqVac5AQ7XcoEDXj8b5OmGu915yRqO\";\n        sout << \"zs+Oag12V6PRX1w6EKKyhQT9BPvW9E8I9kSKGZrO6rSq9pBaZk5DWES/UX0U7yCSHaBAlYZP2fmt\";\n        sout << \"tvEMLhzKwu5vjk35yr3Nm2ICYBow40OjKI6ft7EpneSgGbkBuHH7X2RxfCVcg0+7THSBMEMgnBzC\";\n        sout << \"+8JERFD94nZDWrX7P/QTaejq4L8yWMb7uIChSHDnIIUleV3h5kGuM0MCRChSUPvXUESKuhkezPTF\";\n        sout << \"KRt5t3r1CbOHFwnuIjB5JAMUhCUF0IEJtk1b0gnCY109aCl/sefPp3yznMH8tDAWTL6G/aJbRLxv\";\n        sout << \"DpBb20+ZyK78kfTrFaJ6xGgAyi/fkcggLa8ANOwU+ZbVKvVEQOzU9d/8ygn1SjNBASKaHfVja6Ym\";\n        sout << \"TffBgjcGFtnz2NkjUBccd83WqOyZOxsFqOugfmoavukdhDAaVtcB/KijSoBYQVhNITRC7/RLRJSE\";\n        sout << \"/obYwojRxTfq//cIE33pXW5RCDP0odyGIr4YVCHioG+li9NK2/xrduroOiLdaKly5eAaFZgiFof2\";\n        sout << \"jVYA3mXRxwH83YBdKUSwHDhItv7R2lAT0nsfXopxcJBQVNwPvCabAmsCf71FTl+Wn/LfALLRgtvl\";\n        sout << \"b9JBLI/gPf7tKXx/MhCyz0Lq33VoyOGm246DvalV2QChpolNafxuxK5AnvLxYox3U+53A88SddqM\";\n        sout << \"P+k7oftTdX+u7RhDmZtjHLYn4ikjLwK+afDTW4hCBGFR/bmDsZvAyp6OOVnnvsj9qSOWpeI0VGQe\";\n        sout << \"tCaSgoPEwP8GtY4AX+Dhy1uIYPmoXZUPyNQ+ng7MlCk5S6HAzLlsd5giVhyzN4b4N7f6vseMubhI\";\n        sout << \"/lG0Hfcg+rMX2VvTF54FMPgPjkf6CWr7QorPDB/Puw8c3dt69dr09Q/r16t6aJmtyVa0EzAxiqsR\";\n        sout << \"n1POTejlH9K3Ul98w2mthFuaFVwk0ILJjCZZVgY1GxlvYRzPs1/qN+VQ6GdLYFaaBWN3mI20aPND\";\n        sout << \"wcKX7LEodSgu63Da0BBrKBkoihTYg+IbO9m473LWf9U4dZDQmSjJeISGLa7HDoh/JAnfp0Ej3EVG\";\n        sout << \"K9oe/ewohkPFTgXIV/qg4LDRny+zIJ+jsEOHeryCzBfml0mR+WWwwYYcPur4cCABhkZfKGVH5L9o\";\n        sout << \"S2pTxevQeY8hDj9dUblfU7W9RBl9t0j6pYm3wP9wwP1yh5AKezedXy5VavBPk82SzWBqtsyTpODJ\";\n        sout << \"AWQzgF5G6yLvPeUChHRDGedP6KzrPxkSxpyKFZq6dTNl8g+yLg/FHwOZH/R8GesbKKCxjjeZqD+4\";\n        sout << \"UjB68IayH6ttcLEjncK/rLOWn8lWrnTsQdOf7GznjWDHILJ9B5hxEsKMKqOfYLKosPMpIJFk8UE6\";\n        sout << \"CYffnCZFI5/M4stj/2A4zYt2kcqIMN5rIBJ0hJtBlfZRTMweBmJjhAKbM3b/ER6jQOlbPBzNNEmN\";\n        sout << \"DvcgFIL1c9/mqfI041LVldLTpHeaNDRVVXzho5+iVi/R5UfYYTvvDU48E6cKh/ErrdGHXURNYRXZ\";\n        sout << \"ghNAKIOA3YeXZk0SpcdzxRhQaFwLcim6U1j3kVLEYnk17GavItFxjv+22zr382ivLNfjVdx9vxBj\";\n        sout << \"bRqj1fy/goe9ilHC5sxCphuoe9vfAe4Le0b2hqn0Y3LyO/lvzJEVbP2hkFbU06YXUOktXJVCH5bk\";\n        sout << \"JO928XrFA98vOciWwqtRXhO26A5yELcjimSmqZ9zwt+TKz5cG53+CXufCssHPHDSaZCbF2gxST9/\";\n        sout << \"TooDJUbagLQ7VfNZMBIwDVoLpl1dG1Z7GgobQ70lkUAA6Rlo7JfhNM5d8N8UgM2dPPukCAQ5yuMl\";\n        sout << \"0KTHpW9a+qp3B3VE3+8mPoX16p+zpRlw5Y+jA5ctu84Pez0FqZcTmM4lFcevPe6C9LCxJGzKJJer\";\n        sout << \"yGyryVbEzPmVk6nsuWnHFodPve6NeeYnlTkifu3FBfP10DzXYSUO6nPwSZiGiG47AYnyQXmIcj0N\";\n        sout << \"iSwKDzHcPf5IVgT4qZswNoy+t8QBATl4run7klhzNdE1QSAp8eNZnjtdmZdGY4UhB3/mto70MIPV\";\n        sout << \"OBRoyQCHkzWx8tPcn7NMUW9lDJdFFgNiHngYBe47fz+Tkuv1iBxRppU32ByeXHOSKMgaTyb5f1XS\";\n        sout << \"ern+rWMqDivMybInX6vMV8BfQ8eOcnl9MS2OblGPj7XDsbLmr/eOe4cFoKdBKg791eavES07Kr6/\";\n        sout << \"LXw/mELHEEXBqkuafGTUlUfatUz5OmHHM6ssKoQM1uUrGqzgcdiAe8vNxuMsapJYJjIb80meaYia\";\n        sout << \"EyAvl8dEYiGSx5etaf8hwCnXAOzEfHNi+qjIC6Dqr5s87SQpYPDexkuUv1hEGSDnEbWuDo7BSwu5\";\n        sout << \"hZCA4T6yoSSki1hhXMMsl0tR45bm6UlB74VX1IsL7VD6HiPY3BcveCMbk9aNCLt61KYwY+4+xEWk\";\n        sout << \"smbgq1BOC31buf7xQxX9UtsyBHQig3dCScPoFBm0nKaEHK1fuf8zN2WIi7+p3pEQqRTphOxHtsVk\";\n        sout << \"QyC7PmZJS4merPZpki9Mh/jo5MM76vCXgESUr91CY5neMliK6mlVDQjWBPenKw6JwM2UeDjjQHTa\";\n        sout << \"5w1vSg47kgvLT4KUfqQjS/JDx+u/RIrKGZbsj7WnZlJXsBvoFYn5N2UGBj/SOLVmCXYhBfUHZxqH\";\n        sout << \"GvrtVWHffKoSHcVlm0G0u0EKYYvrYCydASHOegavtcc66k4YIqge/pv8j5lTBiswafWuBz5OwbDe\";\n        sout << \"zxzAcApflzsfgNLol/DNUutk3QpBTk2qW2XXt4r6tkfCG89NsMcr1L3E0+NqWc1IbIIxJuSBhq9F\";\n        sout << \"wNvPOBUYmMD08jguGFHHFLFTVAhcxP90IP4NN6/ImZWqUmZ7DsQz27ritt7RAgjR0aXUJ2AipCss\";\n        sout << \"LWr6mIptUwcOwPHwqwrb+s5xuLIGsT+hXzwpaNrOq7AjKx4GbRcL2UhNwDJ3jAQe8K6uJxffzABu\";\n        sout << \"x1FLhLe7N63S+rKYHMLSSQMKCdf8uxVRz2NX44QRIdxXpV5/mHXgDd8qysZkv26IGp7DG6Pggag0\";\n        sout << \"DtuCocsV49swsov9/gw2yR4r8ziyO0oUMOygSA0Uirda3B1MOiYAvCULRc/HyzndANKNjef+uagl\";\n        sout << \"U9r+o2c2pqApAZY9JeKNj0vbW5mmIZPU9B+/LNGnLAmJvpbrcRTpkHI/0VUV541n26da7jXoJ9y9\";\n        sout << \"ejOkZUY9xMjkLl4aqgwi4cfg3TJNC+0GXjM7aRlJPk2uPNujEiLSkrPk5GX1+jlZIdBmWSfIkNeo\";\n        sout << \"XVQf2dVu1YlWKqmRHsgnJecopec6lhGHVIeamgsyyO9GEmQBG0cZ0lkkq3Fc3Mhakcbnw8InWFYe\";\n        sout << \"skGjFM2kSHQ8ImGUuGx9UW/cKMZbq++oZJQ8y/rmTDfzASJWXezdCOJsOAEAqstGrVZXO0Aoq2Qr\";\n        sout << \"rwO6oJYlxdCpc4MLBzriX0qlA/kj+3qc/lAb7svIugXusyTAshRsSeKgBb4qNUdJ+31j5UoZbwT1\";\n        sout << \"LQt6WHxVFoqYzdjnYsdbnSbV6llixlEfdmdg+gyAQuYciR5z4B4D/dydNjmbFU2BT9hbeMqkam/3\";\n        sout << \"vZSjziXOOsqMnGj5ZA9yIPwKcU9IqvlhxSsLPyFN6eTq7EUV6/njn97pMQhew7hrhXWpoq66A6lG\";\n        sout << \"5kE6M2y39eZuQnh1GmWhF2Pr+0Y0hk2WHx+h/6sRNVTH2qOm0wFh3g2ZqCPgQSFSdam5f+Jo5yYi\";\n        sout << \"IFxYEsif6HxxKGg100Yt59WpeKCVjYO26uc+bclSKZ9VNFsowfyCI3ZtFOp5aqZne3aB7tNkqUh0\";\n        sout << \"387ffCRsqMoQTLLZcycLiIpcCgmOCb8ASCMi5WgPrtZxKA9oB44xUgosSQlRgchUdu5qtROn1Q7f\";\n        sout << \"PHqeNv9EyJWiwHUyLp26f8pus1iHAYIJWvoFj09Q0vXiyvPM4iSd4tFX7kIXxOSNy3ch1FFHWc6j\";\n        sout << \"FDiXSs9Lf1iWpvF0O9iqXZcMdez9dx3lnNuXBttsbNFg6vBABk8K3DFtwDVWg6a4CCFlVmucQD4F\";\n        sout << \"Nf2eNdlVUwwpJn//rtDlvPnZXqpqx8JCEyBcYt0/oYT5vJdrhOKRNiteeUuWf51JxdJh4XKnLE+e\";\n        sout << \"8JAmuTL3AJ/gp6Bxpi+4P3jAR9mZfA/sQnTqasw32kz427/v+hGWMq5j+Ak0wGrKdTlDeA7KLBGl\";\n        sout << \"vbZUrSR60wvpL7SJSYkM5XraJzR5ICO+IxE+hfsDR2uTSrzfcsb0M6wnVatnXjOFNLL5AY6jpHc5\";\n        sout << \"sHLhUHSziNpnsMsWJ4h22wbZmrbO0zeD6wTHvUtrTwOTiPfGkgvz3DLcNBzcn4oqfaEk5JnXoE06\";\n        sout << \"eH4+bqe1/kZ7tlZLzjd+7lFAO8dlAA1KoIGOvAL1L5aqnPbCuJVaak81GSiwHlaztibjOB9Qolm7\";\n        sout << \"y/ln+qnZ5nbMYuWnn3lN4m3Gnk692nuMfiqh4RQuwwxzR1FZtiCzGBPkVD50VMzUsxs5d170C4MH\";\n        sout << \"ER71dvl0U9lLf8WKsHyiU79tJv4wTOpzSMszbf+WCpWZXCJrfyJ6ylRO3dvk1QfjPmFkUwiuQy67\";\n        sout << \"q+lFfRo9N50ZvVB2bYNsne/tlNHPk9/WdeP1rtTyMBMdl+RfJUf27wduC7RQzMtdUuhFLYxdDGxm\";\n        sout << \"1ZZBolFeteOW4IboI2KanbMlv+GOAwxkAWC9ymADZ9YBecvz1unjZkLSGzge1MY7ORdnLBA8fyUv\";\n        sout << \"JsigTjg7KuX2kpkuKxQHYs2l78Tlkdwo3x2VDKEfNegyiZMGMr8CSksLfxnI9dHwbUmyBQWMZBOR\";\n        sout << \"gWU+s45M6S9+HP3R+lwsT0Pn12HpljhnPde8ZpemkMsTbJW0rCQnYsrdryfL/X1GUxUxhNm5WJk4\";\n        sout << \"blqylbW9X7IbbUCB3+8A0phl522/wLWusDD9ndRsiiXj2EDO2Ah5MXodILg7FBo8PpHDsgKBLZeK\";\n        sout << \"WlYVQlWNtg6m/jC5004csHtx2ra6MjSxAhxyt2Y5qf90KBDt/61iJfKC0N9hWm5KKMsGntwWZBVe\";\n        sout << \"h8eJjOzM8vP4azMfymC9U87PqPuI2/J+IB+JNVnjLsx2z2NumqgAKZc4mVUs0PiNK2sSVRlMU4uF\";\n        sout << \"DdbEn+oK+iQ7ILBnkRhDu/C4h1eSyAQwF8XENwyYaclxhoVGRTCRkqrOaLh3SSb+YFSFvbDz49jo\";\n        sout << \"ZcfxsSvLNgIeW0MnmYUH9ydCunC+y9aiO2sZTfKrl95BeX8aEjtxCjpqVj4daFz0diNEQSiWIWlU\";\n        sout << \"/EqYRDfOIZoA5QkPBp2rioNMsElAHaosb90vh+LiDXpOj5cz0S9cKvQw7hI5Ma0gVmhQbAqFrnOD\";\n        sout << \"Me/94YZgsabKZ5IxOJrajCoF1WO6GgdJCkdSUrfRZTkxe0y4qBPAbVg46BGOTjnOkSxUUzXAjXDE\";\n        sout << \"wPf86SdrIWq0NDJ3N+D2lu0MloB/tabrVHmBXQwNDqk24uMVQPBQRqYUGCTzkjr6awEz6oICB2iC\";\n        sout << \"14KqcsiwuSxIsY2jyL0VG32aHA/XNQTZetsvMq5fee0jzSZWAqA0EFzw6UFW/kUmVEsBdX5kpYpS\";\n        sout << \"XuNVhtxVGey4zANa9P7nc40VmxDM++pP/45XNbpyIUOPxfcBM5YoHjnpAwZlTTUsBi4Kdx2D9oRx\";\n        sout << \"PGlK+TGQF9T9ZvI0mxDTXiotRScPozQ8jom/oINYIVzdH7EWLEG+nmKib+3icO9A09pOYWw8TSZj\";\n        sout << \"HNAxPczCwc98w5FdlLe4zDwHnILl4NwfnAz8x0QU+VyW6kugntyk+G1NvFHIGvOnFnZA/Ku1nqM6\";\n        sout << \"3jErxhCl0Ii8h4dD7+HVUu7FWUMOM91LQHsgmphdHA+NQXm+/J/zj2WxamzK8pfpnq9SCYpNfjGe\";\n        sout << \"NOJGOuytsDuG/Ct5fik3DquGqccuhve3sw9H5RDhaFqjWOEPT2rhlu66UfRsyy6Y2FwRWcB5YuLZ\";\n        sout << \"+96O5+VUhbSynvOuygLQfmCZb4RR7h1x4RLgimV+8DdDaH8abjuhKv9bFlSFUNpireUlxkYk1NoK\";\n        sout << \"q+3XpmpJyDI4N/qB35pf7RUdp0mlTU8/cF7g4OJ05ryskis2/tURAdoKcePaWSzn7xoA1tCGYC1y\";\n        sout << \"+Z9m/7erwcD8n+1ZHu3499wbywGzscGo0q7Drc4SxiwUUDSH2FWpaoUmKEUjsYLMwx57QPZVIiH8\";\n        sout << \"WjLd9hcjaht7OqgIQI7ihdSY5TTvihLif9siWmrJk2kpl7Qpx9B2VSVfFBrie6JU+6Ecn4XIMY4n\";\n        sout << \"GYVF/bao4WKkobcbSYCmUfTr1gx7hh8VkIpmuPfiyBVHXI1dQtY/BDxkLIBiUIk509Kb/U0xA45N\";\n        sout << \"+NPG833fYqJ6p9ygAJCQJfmymr3TXL/TxfXtSQrO42/upQob6+KEjSBpewaULLu3+6diY1/P9n79\";\n        sout << \"gLnJOnGncD988L0KCthNKXM9Rm9hzGjnObcxg2IHckRu8F5Bn298963sUe8x5G5BKCLWTTPFbBxO\";\n        sout << \"Mr/zSVZjlKaafRQYBWKE3BPQRbLKBYN+XaNuEQ/cfxnsN+gUimbvpZUueMU0Jeo1ReHqZpZnjvAE\";\n        sout << \"Upf5Lrmjpa0Iyy3irUQ8HEVEisLMdpg1Qo5RwuWanqTVmGxW0sCjfrCOhV3TwIQqxeWPfc8o4cRO\";\n        sout << \"uN7IkWSyck2HR/4ncq+tfaFXehMA9rxigFkeXNh3divWzV3W+U/SeAAQcrgUgecpcxqmGkQjqV3k\";\n        sout << \"Lttwa2MF5SCMfM8LwEG3Dl5JPvPfTY15dIUGNjEIFJ25UuJ1vK9K/ns4ifG5QxNKGFXLvgdv2WXy\";\n        sout << \"0968qdLYeIMXJAv3ieTFm2ivd6OVs7c+jp7k2Ondx5e/WeC8ciCOt7JKyAbJcCZYbasFlaOOeNOO\";\n        sout << \"tm7/SmLUp1hZALfjTeoDc26EtdeNf2x0HzFsGivu+/qd+eYiQXLGqStyYPVc2IZ08AYLFClR2r+L\";\n        sout << \"to5+RouZ3CCXiBqoaoZVsGiqyM9Dgt1E3PlaXtgLFzhpXNw/l4FXFKPiqS9DZh0X1aNQE1KAqLgM\";\n        sout << \"F/VYjhOpbzycTrRhiJ0vhzaQUiCCe/8QUlSqCVVNZ9w6Dvc7uuNNp+exxN+IjPcWoSYDe2QW4MHi\";\n        sout << \"3Sk99Bhu+5H4tVqc3ehExt01lIjQI/M1A1CpuwGv9Sz3/tspG0hYpOT+Mo7sHZ7ojYfkfLHOfp9J\";\n        sout << \"gtUT2uqV0LtDgctrD5vx6NEgfMzP2dNnj7wopH9P5YsTv2XPW+bKxUp95K5KMz0Ea2xLmrZhZqG9\";\n        sout << \"HXhubQS90G74ibC9p5nvDts1DoIC5swJpo6ZzVude5M6GmzjVUHTaS7LSjIbxQBcjyFrx+panbfB\";\n        sout << \"TLLL2VaFjfxw82RGjjQtaeCeZt0BsnkfL1A4Vb5ItP+qhayO+9lqnSXdECHa1qFTXKDVPvD+SQC1\";\n        sout << \"cXQnxXvCxuLmHf/ao8i5QFXd7tHr96ioCtng0PWHxbXyr3NQhriX2zbwD2kkrrL4udvZo2TRIe3D\";\n        sout << \"/L46KWG8S+zpo/iXc68pt4sjfuc6DNIXDtx8xkFAre/q9dRKmuV1BrtlYiIBQlhDByyQuqD4Cdwj\";\n        sout << \"1QMd3JkiF/WXCc3vsuLH5v54EMHM02MkS0TjzLjOinkMT9s8u+ssSyp0NUE83XRdUoND1Kw8DbI7\";\n        sout << \"e8izxcz3VIpR0PE6MYUKS6SR1Gq+haGlgnZYxBCbrhSkTRn0VQ02rnBF9An6rmXRHbqs1rJZ4yXX\";\n        sout << \"9/jj2dPwYrFW5NMXL35Za8fTfG6pXaDjPnqJokXt2rKX8X2/DVWhYQwBLpZytXTc9RpDis4VA6ao\";\n        sout << \"0ZG/u1qgQeqsmhkwTayh6S+VFpwrQA5upwIL9KI6JdbCCsQhazF7qsEDoc1GeAntjyqntc+mml41\";\n        sout << \"I1ZCYtP0sSOWfWiQ5yZavEsrp94P01thtx7s2UsrMtrYQc5hxs/J8VWtIIpg9AIqDW7g50qsBv4w\";\n        sout << \"id8XQPCcfyXQszUJi+w4Kubu+MPwAMiAVkDmlJGAC9t5oXIIwIbvNZHrq3C1ixd84+VqhvZZgw+/\";\n        sout << \"izIXi9IrhvkcOJmuwxQ9FCyd726/ks2e4H7TafuTXyE1RQ+6Ju3odB4meFU8SIylbCw2jwoI3kTX\";\n        sout << \"XXqHbAcdgMWoxoDXPZ0XzVqC3utfaOARHji4+RXEseqA3tJhS5CPHj+D+6yXJivrVC6KWSwPqLyW\";\n        sout << \"6JI3rVeT9B94EYtGH6qWvcA2GaSJjxiQUZQyqahHk/FxSkmnMTPwtvV6AcmYZjQESUWYI9UQyHvy\";\n        sout << \"5e/ULXf2bVF3dmTWoKOsDchTNOQ/Vtswf5avr9tuz841NKT+1fojuuAhhYP7uvRruvMJqebeiMIL\";\n        sout << \"QBzv27ji9+tQ6D42+Z5U40UW5XtytFKcGR1NWtaxNkWCPMGRLcC4mFLuQMYq8cK3ZZDhpzyVeyIi\";\n        sout << \"nLJRFigzQfHlBeJmXm8UccbJYo6oruyFUEagjILnb+fb4y+uE7vN6WoqPcg4vvr4RzSkuHueZxHL\";\n        sout << \"5ks+O6XyEywn5hU3kqOmI21d+C/HBRjJHbiL39BcHKdzhnHJ2huEtwqSV6SsDiqhxSUL7zYEDECj\";\n        sout << \"zs+9/3LHJ/9TbZZ104stYMWXIWuLc2NSS0bF5NHarE4XedBAcXaJzKzlj2o6NYb4Ifxcs0shAxl4\";\n        sout << \"6ptwCMOtvcTz1t5QB1vG5CHrc7emzriP7+H1tukmCRA2i7cZPumoiw81AM7SPv/A/9yr5EFRdBmv\";\n        sout << \"FCOwJNDKfD9Mfb6U1Lk+ikWFR1wm3MSqq4ZSy1Q1s4F0npfVh1J5nWZTxd0Z/TqDhSAUU47cC9do\";\n        sout << \"qRMBg/bBPxfrWGeDEOLActWvxMr2g6O4tdWLxTtWcGsGiatS9TahYclwL40gnzAC+4g1yOgc4/u4\";\n        sout << \"Ye0T1KyUWUnAfpWmFibwphrKOrVj4ZBVzahAWMG4jWzDcxTaKoZvAtQZi2FOn4V/+bKMURZChDl8\";\n        sout << \"DZpqrBSfSyY7DnPiGRgxOmTKK6/kb36nlas7zwcQvSgQTw3vPJSU+LJg4gKmDycFpl5deILsDRBp\";\n        sout << \"78NSCvjJqK7UVNfdAG/2C9nQHNk9nHEf3jo4Er7ogKGkWOHshaIvzL98Nz8BHbr115gtKo06mD+C\";\n        sout << \"0EJGtywTGXAzkO8J3T/gEuW35KH+kOIBMXzQcJNY1lNud+fALQxNv2Rw5u17KBXqLtABWVaOABgz\";\n        sout << \"IVCkpM90yG5CwxkzyKO+CIxb8JyNs6Shk+CPNoiU8mbqMFigPgXw+yWEEdOMvTdzJuj5dKX28e+I\";\n        sout << \"jwOz6wcXPYod1yzF0kPUlol0XaDR1m3abfEiTwquKsTY7upWPjU+Q4yUnrP0/+W4Oe6TgH7JvEvy\";\n        sout << \"fhqLicE67NkotZ1/+AMZVDYWZOScrGmi8c9Yj5dg3lWi5OtfLYg74TSQ8AOiH6jL+wLc9J+QwOaL\";\n        sout << \"gibI6x/dWW6eJGHxInVjQrt0xmP6I90cDPOnx8JC9tMAEv1MrLMt9VKpjdMut/Gok2doLdEHyTKL\";\n        sout << \"wBNiLGq0viiPXgm9/sbi3KGrWhOdypAbECm0emMVQK/WdkSFZu6PSArdOTvHthXOvyTb58fm7wS6\";\n        sout << \"oWvK8J4f/T9t9aNb4lBAYFtufB5S6ndUr0hEU0nirxgfsXl9ZsRpsQidq58dK6l6WI5CmUpYboL2\";\n        sout << \"6T66Tndz5jnvtPAybpIus/Kbmh3tPsaVtI7e6IRl5mzbEngtlOqfbwlyJyUiC5UuGJAUCtqoKadJ\";\n        sout << \"QKGtTuLv2VqavDmNIuZ1mRX7g+2Kbf6y+7L42iqivvX0Lmo8YSJFTuNkWTNlu7s+yYH91uC8BdT6\";\n        sout << \"3DqKRgiRWVfgKuuJvDp72gyJknKesDa36+iCp2qaZZ+yU0XhK/6U2phZ6XeNJlQY5H8JD8pe+RJk\";\n        sout << \"qgi9XqP8qvLIIv0RkfnDVJtl4V8pi6I6UiaD3dNUeHdN1YHCu+Ub225CFQIDsko0Ly87Iv4oULoI\";\n        sout << \"1gmb6dLkogavqkQfz69GYinC/z5/En7ekQ2TnOgFiPV3SaF70p7RmyMnn1/ON9r8vd4NfFPXXCCL\";\n        sout << \"NBSihPK2Tt3T5i+TRXipLYq4+kghSyTRhT2YRIbpvT3yYs1EGbEekCQQmIltN78NpyWqBwBks9Gt\";\n        sout << \"xpIS1Mj7Ff20DpfjgaSok+XhDSDA8pjNzuM4Hv55IJbF5se3Nj27glEhioHCvKzx84FUuInAjQtT\";\n        sout << \"0+5hsgLkTppvJTdSUg1hzhU7wa6NixwuZgfUenls7CwH9K5WYB7KN6ls8gzbK0V3QMoyZBRIoSuO\";\n        sout << \"7yyzgY5erfXbwfcYQ2LliJQQyYyLiEcm9HCxJGMuBL/41LQxxm5KBXMZhJx4c/S/54GJmTMDfU+3\";\n        sout << \"xceNujbOdtlz9ahcxUBPGOU5iTYBGVUPFscRy0nxuHhOu2VI9rYBhoIUZs01Sh3BDgksu4uUnGof\";\n        sout << \"crDdCqjpR+1UVnpoEmxbW/Z1Ux03tiG90lCn58/g872xPsO/O/DDX4wfNU1yeibFvWrW57k0FND/\";\n        sout << \"lNNeLErDW/nBpQSbaWal3O8lfmjD2SBwk3xtJ2qXx538rFZRM8DQJUOfUjvhycRGITPP4GZBuiE2\";\n        sout << \"cVpeof6Vqbe6J4I3E9Bcrnm3moAyKGiPDJ6UqthQuILGNTH2GOOXAl2I1X0qcJ4G2H5xgLNliett\";\n        sout << \"T+uB6q/kG7Ab+4QNVm0j0zdPdVZdUUtGceMJViJ+ZoRVjunK3QuzwgBHYr89OqNxvULc7tImHva3\";\n        sout << \"xan2frwQ2ZzJy8hRCIdaNSNgdZp4WONm+5Bw8/MU0l3PjjXjtlzjUE+rHSwdv5abDy81XQwkDP0y\";\n        sout << \"CS2C7MMahBsySi7v+PrLljFQbyG+deR6ch15UfFjtyd6Mctr8FcW2umvPYSnl1g2Dl0jE50ZLOHj\";\n        sout << \"2gRAl1EvFXIuPjxcA7gsrlATb2SgCUtrelJSDOJpf8a3WMKrLRYp2MONLXacFRpkI0iU4fNhbzgB\";\n        sout << \"o/CdP3O/AMGGnaZN5kIkmOwm+naBEF3mv1xFE3ZZ5VldoFrWrxZ+9s4lOAScPYzVpABjbJxzOzSo\";\n        sout << \"fz7+pEOY7/OY4oNgqWA4MEtO2pMbjUpdTbSiVuXD87KHJYB48ffxkA5aPKFWpdRFCJHM+J2Zjkaq\";\n        sout << \"ZRRUeBZVzo2rRvFBWrpbvAkkaXEDk+k+N3mOn1LF78Qbm5FWAn8aw8QL7oQnmrkEqUj9EAiYTx+q\";\n        sout << \"v3oRQ/x10A2LctzTyy0mCuM4bR+WQW2h8dGoMUhjJpGPQzeR6owMDi1n09T84aVUDkxfR2PpIHxs\";\n        sout << \"HBag5ryae61mzdzqNmyFzySbIbD83r7ML6FqMCW4xpWF6ru2DvNykb9GYL/kquN1rjNOe9XYEQM8\";\n        sout << \"pyYvcipUqJdEeYj9sjgJBXkuDr8fCBpmvJuklMOeuAwAMXwxL1b53VM0XNgVokPmFTSF5zqesA/p\";\n        sout << \"ah/7f2URRjrP9RR344YUdzGoccdhpNnFQ+g4KRdmd7FuPTJYePyDncJFnVZNT1TP026QrRPzg7H8\";\n        sout << \"sFMoZQuzZxjLy8gSU3JYcBCnfqBdcvrtF5Wb+pKkEZxROE4qURll4Y7zYVxPv03Z2PvA6eovQyap\";\n        sout << \"Pr2jTJPFgyEiAtcdsluxtc7NvY+B0Oxgk+oUyaXAhkihKKSGT2pPRUvd0LqDYU29/7v148UhItLJ\";\n        sout << \"minqiK/TinqUPHOe8oyljHRIO6awrl1oc7HbFs/8ZrK8hd07LG27lMDcrBogEyUZ+mcBRykohy5w\";\n        sout << \"vEPLCUA/hLP4NHaUts+q33Wtrq5n0m+4k79SRjwuvmcSXjf+Uf09CQD32oicQr0UEfo8uhrUPwta\";\n        sout << \"WukfxXE/VF/jfynSXwEomRZopcNoc20gWzRlk+M7HpjY1X3TCi0T6f8qAJuTjSSbUZTFC926jhsk\";\n        sout << \"a7Z67jTJ0woPzPFjK41KLWQcoArKTuqOytbd5fKao7qpxiFnUPd30dq6Xhpnt8oW2QESiOPq/4mT\";\n        sout << \"Bdtd+wl8c3bzgxRpOGBKakq0iI5Vc30wc3vTUw8Mpae/beCHolCN52hJF1LAKRJT4xYWMHLpKwNl\";\n        sout << \"ZqpKMybMAGM7O5X3xqcE4nH+bPkpkMILmNN2x4JfWYfy+667pQdIed0jEaDRHueSfyuXCp+Yu7sV\";\n        sout << \"q7CTe3bwrUSklM7zpU6NxuX++oMNuruKzZ7GwsP/NkepKp8MGUyoT8EOz7yIq7k9z61OLxz0Ylxr\";\n        sout << \"0irk3K8oCPttZz8y3u4ZmkAGcYOs41JR3Lu7D+/V0hjdGtNdb3ALJON1AB7r+OQ2LW3SEP87POnT\";\n        sout << \"R3wayKImuVIpIjZi+yBSMqomZMtH3nExOSKTHzLzkSyefGR3WTSIXI5GqtWNetBTk9y2eeRzbSu5\";\n        sout << \"+7c0XsuaWRQd+2qfns49HNwQocfbM5kNMKa8npRCg8YUBMimQiihwEgM6NJQWJ3ig6vwXncIOAYI\";\n        sout << \"kwcYWkLBme6vSiaeyLRG8y6A78zeoc93lGy87yjRWYkr9CeARb8B3tHX4E1APF0Dcs3/6MTZhnmv\";\n        sout << \"eMdEj9TW/MFATPy0BELuV7nLBpSrH2Intvo1jzPU7dGsw/36MbHr2LFO9a2PrZkMBCixQ5kApER9\";\n        sout << \"HQCKGangWrdU/jO76/8j+mcrxFNUEc7y0OUUFK8ZXwHMXQp7MOew6OVUmRuFSl/jv22Zdz16njaZ\";\n        sout << \"Vd7fVrgOdTG+EXRseg0LvvzZ40qWpRahwg7zqP/sAWp1ZhH1yJVoalrCFuTLgabjWGo5Amp4vyk4\";\n        sout << \"zzseJ+O10oZZrWsFOg1lbPjs4j+U1IhQ48qNS/zk4Y2kaiM7/0q7PkaUxdwdcdHwbOmp7zszAyfu\";\n        sout << \"rwXlt1PBiRyEsBKKKsBLwUzP/KJEoRvFvgc2VgzDxxe7pOsX3E6+ey7gKt08W7RNTTGx70YF2uVG\";\n        sout << \"4cEQHQNqLygscv4DllKnH7Jz+2cHnSES9us1PaWqRwpQ07XG/sSI6t9o8P0xMBVkR6XB9JkdKP1o\";\n        sout << \"Bj1MgxVN8pMbv3ANGQzTbmCQ5IczVK1Io/OQbSEVlZb8ZOatdQ9nq2YZvedMelM3C+t00b5AaQa6\";\n        sout << \"DSslaJ3FWzJLguvwYQgYUKvJ+jOC8dMr74YNAxt06b5RaijSib2TNDjnZ3tIySixM/dYOnygj2QA\";\n        sout << \"gubdj4tuvNpWh04VszgcZd7TbLntvd2IA8b+FDDzMkyT067BC51elULM0CWKoZgaaMglt3LqR43C\";\n        sout << \"H4TQMRoitKUyfjAPE07UmUi6lEGYcrCyawT+Si9YQy+T5vGMpryrpy9gaHAmFQTGCJgit/0g/c5k\";\n        sout << \"mbyZ4pilxX69VO9VHrc23YN0CMQ0W3pP/DpPNYQTcW3jeG2T3d8b48B+iY9boq4ONEGcx6y4wWok\";\n        sout << \"SuOSzK6rTR834/xqlNGMLNZWSOFjLdq7G4oQLmVZVRIkUXrQImDl5W+1EjdglFE0jAnnuxjT6+DU\";\n        sout << \"B9VIMbIzVlVId6xVrp6Kg+Fb5gcxGsKcpH83c18DbuuIoLsywmIEiWQfrSV7bPVuPKJVof/t+Mar\";\n        sout << \"Q32TiRHMO2ZsUXC8w46fkI7EsH7mWMWOMfhkvnY3AVoAj2i6+orDHNwnTmWQiGj7FR9Aw5CQcCbh\";\n        sout << \"W57bPF88lkQMxdEHBd0Hk1c8Pm+p3x71xzdIofXjTnCd71R8FIIvoduLv6XQttPFatTHY0CeRmjI\";\n        sout << \"49yWBFJ+w+BSEP6cnTQeSo7uAOyit2S3EdLudn7XEBr9eN4wIVAF5lhti7HqJqV/pfqpkgaAQeEv\";\n        sout << \"mbTG0L3+6Mr4RPAKaa1H1aQXcYT32jdC7w4BKaxvACcyjNuukUwhi8GxxXxIktPrOJnwNCs719MY\";\n        sout << \"TbFkKOxloVafybwRZx5DdrEKMq+jKyCffePTaM77bvL1hNyK/78Q9TdEO4hx2q0m853zlnibtbwM\";\n        sout << \"YcO9adPVjghDSU5amF4Ul5+rMxroEoaGKLW8+gL9DbmcW6Uj/vg7TRQohnGbzmKwPWT0hu22ID7w\";\n        sout << \"+ILYIhGhG337Pr0Osu6m80nETubjTijMQHAb1/Pwv2eNOOdu8X2EM2awT+qtxqHCq6il4YFSbUdi\";\n        sout << \"+i8vY32x0cXZ1EdKfgciuKtK180q1S57ZNZTCwe26z5eLXomvjtxLxBZl5z2TJyPEnJprnZWNOo7\";\n        sout << \"5nuXsYypcrV3W2KlRmybUjRfc+/6nMKKBtU8U2phCUg1uVbzAXgyKJuGRmwxUOXXWeiS6f+X02yn\";\n        sout << \"ZpJda7aMY2VBMEuxMRw7P+S18C/drO223DaUROCv25mTOZGKRI8iXQYEa9UxLvXgRfUB+eEGOuAS\";\n        sout << \"7N4NVz2kfzGWlQdKqRoh7fWDkM6R8J3BgWhXvl6dacJcZyeRQGjpR0ZEKDFTtLK8Dr9NFYXk6Pnq\";\n        sout << \"N9kMrQpwK3bDmdv++XISq0WHnf6SBJcNhSx74TUlUDBxsYAcoFefI1FNbFFobGmT7lEX+L7uQNmS\";\n        sout << \"/TMxpzGwSeRavNmjkanqTTZFpWNvRXrfsod+TmJPe53ApSSZpiuOAedN0/3AGsVuqjNtcxf4DUCZ\";\n        sout << \"13v1FAYWluQfSXtsM0weQ0q6ZvhM2SyX3VjNleA0/X/PPmOLLK423iG/d4m5+D95t3NRAbU+TEUp\";\n        sout << \"Nff+BWEiVSlWCTwbP7mTaJPnAUWND7rjif1IIrQLL9IdyauKUOP04yMgCk/LQs0HsDkLxSexCMHZ\";\n        sout << \"rK0S8Bh+/2V/dNF54MVJEqln+Urz2REIGmzqSjly38FZqDwG8Rn3dPYImGASFgGgrCAbYza3ZyEb\";\n        sout << \"yaPzMiO8wN+1F+DbMDfvMtlfkY3fO8LvJ5csTKK94rSw2erFACsU0cXqThvGma5gOcpL1H9CwUsa\";\n        sout << \"zKLfBclmCCGrP4rX1/SN7OBpNjbrCHZnkEebf2TrzxT2moacNtJt1cwVUVGhiJ/DYdZawCRUE8IS\";\n        sout << \"IKDq/tSGREdGSMLEwJdXyRk+4LyVF1V+YF3Jp55yFh5skh3Be2lP5YY4+YiaZDb4IjJh7qxjjO0R\";\n        sout << \"RmvES9HZTw0GhCa3ep3x8dvbHTp1NB4//onnMx9JheeyZRZOdEK/Suw5BlXNgCvc8UJJR4ZLtyuU\";\n        sout << \"7HxX7orjWgkHNdix0VnJKSFYfn2uJ0LTPrz3sARjeVnQ3W0On0DIXqNe4thTZDwUFWUKklmQGV2d\";\n        sout << \"bgVLPmuKff8DHP0xgGyiy1kHollAqwEUzD6bW3Tkrtu2f+LzTN2yAQxKkVsiW+sqEKqUtzNoXVQD\";\n        sout << \"36tnDjAFotkirlS5Bzk5pXgDpbAxFnVsTDq/TcT0XbIR7QvBd0bXq4am1uoZjaLGA6bF0l3Ej6Ub\";\n        sout << \"pB0ZMs2nLo/8EHNIgx4cBgXL2FN0DWyb2CzchL+jsPU4s7xBYuVvGA1bLaM/nlRV7DohA29pE5jw\";\n        sout << \"MXQPYIDzraGVsOdJ0ghhlqqnwPgO0oCaGDxIlBehjzkJcgXPhWarYGGBdk19SUjt9y+aqDQmxShW\";\n        sout << \"PrJagqBImi4S4N99hOHnIxGa46BFlk72ddnCvaJ4n5LahIZXXAhqOrxRiCKGKBX20/vzOh2ICqUn\";\n        sout << \"MgfLtH5T87Mho0k7hh5gVFpYktOqOowwqPJp7Q7Qlwty07GrnkriILYvkp1bftSHHyepPxAAgaJo\";\n        sout << \"jeyuGTtsa+K0jHc8WaDSZncIqmuKs8oVUZ/1YD2EkVlVXIh5NjyDc6RFfYhP5/w043WKp7xqeRwq\";\n        sout << \"zaMTKjrUr02omLUduz14J+ka9uUErd5O2xPaV2O0LpLuZaMjoZ83ZirW6U6ipV6d7c0B3kC4CcVk\";\n        sout << \"kUdzqBoH3VVbTav1vugceepwBjBiXsRqReTJBzNRJK4PPu/ApBKQKp6jyZoWCfhJiuJNB1sEjCbc\";\n        sout << \"o6XEZWbBEjqRaCujvVzo/dLLGHUUOXyGA8sKJq/iAM2dqvDoaduLBnCsp2oBIFw1q0s2psDRLdvY\";\n        sout << \"KiTAKEAypmqRB37gV45Mrmn0zYeDR2/EsWDoo1HFu7Kh3FX/y2fL0155dtiBJxkHDJIXj7POIea9\";\n        sout << \"Bl/qheUN9FwqXsVheoacBp+Uh9NulkH01NsKCyX3nV9ec1sdzwh8hj3zWZIpD+ATVH3S9Hh0pt2+\";\n        sout << \"FHzfu7z+YtwgpWfSqim/C0/yfDF1QoRws09DqLTke3TmnvxoRfkdOwsc5y1s4YR72xFXVrmIRpkW\";\n        sout << \"pqHx43/MxHaQ8WrEABai43+FqGJmR70fvCNecLDPm0ZlGySkOCrfgMH9lK018QD+DRu5D3n6alPI\";\n        sout << \"3bEqruPXlP/N8eNnJFEeDbxQ0aQFJFxSOmTkYWr3LZBjtjX1Cc4qujxcCaUH2hnKvdyxejlt8fEa\";\n        sout << \"h/I2aSaD3ejPS2xz8y5D7Ve0mxx6znMEO8E61RbXztaIRzze57GvfwpTa+NbAjtX43ltW48u0yeu\";\n        sout << \"5UM25BNbXDdmfUzzVFpiaflImZj4Ga/k8TjlTVURwRXX1GzB7lfdEukFRdQnY6VQcsjzo3O0gKDA\";\n        sout << \"+ZUtku8C2JpdWVYYsTVoyR+5rNlgHdaGqbqzADSrSqNBBs0OLaEH+pqoVvN7gNNk/hCHN7tvmi8n\";\n        sout << \"LZQHQ+0Ukp9p3bPTUapH+h+NJ/SXUHdjHrJpaFJR+ANmN8a79zacX7v09ig91M4yRTSxzMzsbQef\";\n        sout << \"xnNKm4+2JxpFLH2fmM4FM+Rx30KcqLmUdBGOaJYNHQqBVJYYMNVfdRCo/KwBX7r+V9SRlLQ5ijED\";\n        sout << \"zKbJlHi7LyjYOq0iv0R4MIiW67OR+5O0aHeoXQ5RJ6Rs1Xytaiipn7aXphPVPo+fZ2xH6nLTQfFq\";\n        sout << \"fEutvtOrYIR8G0dGUSYsbZEhdPC/gpSdHsO0bOJlxgXhNGNeOFtYohwIKP9Z7Giv+lM15GPlxnm6\";\n        sout << \"usrSaqlZWs75RuyOn7etmGBSg86+J5wE3ihgVXcsprkgs/y5mnP9iPifs1UBfDO+2L6UnmceygSm\";\n        sout << \"sIOIuMzGUkrM6iOLYHtp15txD6bUYZsIEeCCnjaIJujQc0lvbU9bh5AVae/HG+SfuWqE5nzp2TD0\";\n        sout << \"jug6A2KoPK/ufGzjCJJ6VIe9v2bG3WXApQGWyj8lWCO+d6YtKFA4agCPTv4FSnS+Ip3Bws18ZKxj\";\n        sout << \"M+AFJKpr7lmSJURUl38hITa//w1TKSA3vSoMaEFGEH8OFkOCDFOHoGK/z/ievfyBkC0/WgvwcSbj\";\n        sout << \"uvaOd+M4umm/BCNqcPjZ86HSej9mSb24Kl3Rn2pxywK74b8P3z41Z2yVbRIjK1Dwvo6t0zPp8vtD\";\n        sout << \"QHW/9v2uZ0VhBdbRAL2+qFD6qKg/sacjR0kE/o/zRR5vsW4K0efFZ8uerG5hLs4rYhZPtiDOHr/M\";\n        sout << \"xOGIfBpL30xzMdMs2zTnbXF7wECjcklZcwlefbO5ubaT0doKkVSZ6YkCQqVXL9LNVNHqULonUgBs\";\n        sout << \"Xrbe3KKGFrToxCljsw4+3+RUVnNN48CklcKfEfTHEXoUNZ/p5msufJct4JL4K+35Ecfauq0GOsLX\";\n        sout << \"sTkVaLfkelv8Uiju3VEggHb+lLdrY7oKT7aC+kyQu8SjtJQY7b2aKQNELwrX9u95mPNZkySc5vaA\";\n        sout << \"xwL/6ar2Y5/UA/Lh+5d4hGSkQ0PbSacBStFaLzJ8AVdOcXihah1a1ddYNtfH6kNsck9XJqz9Y4G0\";\n        sout << \"YdFr6DGHNLBlu2ksVL0ta/tfPZy9BVFo6Vz3tbpnBwkPJ1vo9EZrJxo5GJ309oeLz6mYG+0ctXJr\";\n        sout << \"PC90nYz7s4RxXkWZBzq3RbNiBGNgP1iOU3x9INOf1CbKBhNSp3b5QJDfM+hVzL0Xd78pBpO/XWQq\";\n        sout << \"hdl2dL5XZtd3XYslKjHDaZQyZgnaoWD9hhRlk9lhweUSB5bFjHOH/FZjlAH8et4Eri7N9Y/OFHFP\";\n        sout << \"+a+FoLLT0YiBGFsJiqe9udoECrxUR/A1Yi3Wen2xOQv+eMMQ6IcvA5xYONHWrS8WgMT/I7oELwnx\";\n        sout << \"GK3kwjKy8lQJ9HOmVa0yuQsV5bbrtjQcP72TmuWKOcyNWf9vHvLbWSZUDEXchz4HfADCJEehJzh2\";\n        sout << \"vIYiVvotktpiC/MzHmHoTw0Sf/hOT8AALmyPqVFGrkZHhLU4GZTqcJEzBNUvkvuwo3qMHzOc3zfk\";\n        sout << \"VtoQHlg0pOcKczFo/44eMRlpf0Cn4KTcU6vEmUncnvx1nNMHEYKQNGp/IXHpXp+PN7s9zFDFbQHY\";\n        sout << \"iXURtZZ/cF6jW5TshrT/CgpldM4oi/gn3yTm8AJoqATWeF83ft0AphzHDfz+B0qf2wF9Te8adqcb\";\n        sout << \"ekFiLrNf0VfA/wMCE3drkqLhZKO6L99EK9SZqsly4Q1rwLr+sIgOrI5v5g82DOFpY9zL8Sxvg7Gp\";\n        sout << \"03KDCEsW/2eFfxNtGGZ2P6JJOWLIe/6Zsx+1F5lcbYxPhSirbDYp+1bMZvbm4uLWHttHS6e5NQH9\";\n        sout << \"pW9+qFTlk68lJWtpI5Nzy2CutML4mI1uVDgIctZLSHZOTlWW3LICiFxYVLjvE7JExUZMI5J+3VZx\";\n        sout << \"OTTeFGiuzoEveGJ34tOMrHxoj3dIMkRN9kh2dN10crD8MKoo1sb2EqZvhKu3yb+XxKKl/RkHTuBv\";\n        sout << \"JZjCnoTnGa9JltcMDgzO6demBWSN9950HXwS0cZRcDIgG+eDQnfSfHGGJ0UuL9ydA0KYWYAPxVMt\";\n        sout << \"tqR+S8lKMzk18k7FuGBsFjloOSgsychm0GSTKu+AVUJJohpnT5KhE9Z7Y1iSc1pBOxyf4iS+FF5v\";\n        sout << \"AzB7BEivwSPqcjPplzSQ1uGNZsa/mCfGy77XBBm5wYUpKDshd4l8mOHPFofPW9WrpI4X2e3LuiMJ\";\n        sout << \"8BijYVutWZv/8BrhhFuUnngfLsaJBhO+KL1m/JsQEvWIJ53jPt5qgEOn/4Tei953J2hanoVzKelM\";\n        sout << \"l2OhgHFUxvIYGvKMwLRMPQ4kUH3C1vvBJivvyIZ/JWcHRq/0CCjvg1aPUXSXhBrgkqFwQduoNW9G\";\n        sout << \"D3BowPV9v7Mk+IPddFxHdQeyHdaquVKxWoWHzlDnv0gbzlv/EdZVUd7k8rbqYgUdPl9os0dbh8gq\";\n        sout << \"nRpOW6MTBdFojgzrdOHPhdHM+Rs/TIntPPd2YmryOjdHhAyrVgFTS/rx+yDRrP+ChjTPAF+k8lG+\";\n        sout << \"qvN+Z8gDFq3B2vfIgAUs0rbSMRfOahM4+EH0pX7fe9ylY9yPHtWKs9i3mU+uVTgB5ZtRKuSKkpnO\";\n        sout << \"MgWOp94H7Ui/tI7b7hAC673dprCx1PZgdIncutPRIlxzv8exEVhjhH5AsW4gRNxLX9pukC5fVdXF\";\n        sout << \"nWif4xcZbEcsW+mm6IV8NE7iokkhEC0bahxpHeS0H0RB28nZY2idhHP6hLDMkSg9b8mlJgqcGBtj\";\n        sout << \"Q2Vd396H38VydtreELEV2FgC6Ski/PFP37rc3/NDStzcY7d8twoEiWa1msraDn7zlvORuk+Cu/Ec\";\n        sout << \"VaHwuWQdyqf7dhOhrH+/wK0RTPMKHDyLxkwJmO31Ka0LEOvqMcsUzEaxAMUNz406l0r6pLW2MbP4\";\n        sout << \"AdGu/pH2HwxZ7b1ps+8JiOu+U3SDrmhMZH7kS8LUhCNpH21Ty6QzgJcaw2jC9HYUoNeobJSQaOFu\";\n        sout << \"kiOHd69hw7VbD752KMiVur1AYmRegfhkEm9850zS/AjT+SntphKTtFNsc5cR074M9iucA3cH6Dv2\";\n        sout << \"AUSKvl15U83cbs/B8NA/4iSp1OTEb58O97rM0iLsWyBLSq2Lx5ZblFZeLi/rPkoVGMo/o9UV8pNa\";\n        sout << \"Cy/ushHj3CMku0REQZQfcxl3OgQ6U6avNywmwdncjoDCwX2j7MwoZ9SrAKvxSedrSkdRhMvVkuJO\";\n        sout << \"l9c6Mp86g8KafJQIp2ZS7CMC16uoiaUZCqdcdIEsKvzMreCoM+XGxXE589e5BsfV2gTuxpvnWVCs\";\n        sout << \"8BaKUgLnLKCHzyioUVC7bzz8Ov1/Wqa1LHzsrobPw7DV+dIDHqAS0d7TRra2q6rXAqYA/0P99NTp\";\n        sout << \"uhJkixu4ACmGbuBO2ob+t8cdczxIBSRPHHZNCXQG1t6A1IYpozEWiFjATpoD+gEL7Mv8AZW7AF3Y\";\n        sout << \"wFQEt2JapH373jpvJ/lAIt33yTMgyTQHKQ6bsTOWpK1EK8NvnOSOeiFfmtseS85l33K8vl8pyXBL\";\n        sout << \"Fx3dqms9fdbwhUmUWGcpzynCrKyV6DVGFznQtpr4QCl67Oz7RaaYXGe+lOmyrBgrnjKcQk4ue99C\";\n        sout << \"ucZa94y9SaRBTFNbXtpRm9jjdzoDmtd0JPCGzSACGikNArk4gC2AVKMJpFdJrS3e11Ew+pprc2uR\";\n        sout << \"fq/nf3C9WQ9lQ+KbpwEokeXHWNmWBwDZwFCf2w41zxYqjTu2XjGt27ea7nleb1IA1PtQtcSz/qoC\";\n        sout << \"6A7G4EFk2WE6VNL7/Wv81DjrdTdYy8DFQBzab3Qc7T0+T+aNZdNfoZSj5YK35BB0mmPbxw2U4sfx\";\n        sout << \"1nahYLG8OEQgoOVG/3vG+EmA+iCAcCBHPObthul5KdW5JXwPw3AMgL0UL/3GIpXRrzE4JTPrFfzX\";\n        sout << \"zFmbikWuDkDw9sP8UNfHAOGWE+OorN/Y43rcSfVA6xNgMhqr0pBbvVTIXbeIy/nR34IJGR5xN6YS\";\n        sout << \"G1SriivqytwRmJLC+Z4OoSVtqNPzPvUBzs2wHPF00gGAE1FpUa/CfxOfXhbx8VoZWMcuysBgpRCg\";\n        sout << \"Xne4u7qvre3CRkuXLazM6qKDt47OA1is3gG6ZA/XCvcI8EA61YccN6zTpFNT2cBGQNQ11tK5jqEV\";\n        sout << \"JeONoq3L4SCF6qCiCKMg0nsc6sk/xJ5Tam9Rl292lzxTV1Xa3be+lfSjUdiWnmbU4ml2Y7FEVbWv\";\n        sout << \"4A3WHted4mKb0HiCz8wgbHrjTnNQyIntFcXuNAUUzri4nGsV128EuJrPmbYXqWuKIe1wPT2Lbco+\";\n        sout << \"7qH3xg/zxl+t/bqlyqghqoYQMPw1FJXz7Z1TMI9TNbxUtCd+J+mX3xkrYI5AtCbTZh3lMvbwWJZa\";\n        sout << \"4AOY4WRavT6XHsBs7hKl0iHOmTyMe1bkM6sg2BChZ2B4T3BoeFISya1Qn2U3R0Y61plw8OFrTsAT\";\n        sout << \"FKgD4pSc2VaV5bOPM/vqg4B1In01SOw4itnoIC9N4+IvHvzQFYzeqiueAcHYGss+uaTMqqc9c+gz\";\n        sout << \"cgiJCv480X1iiauIKK1Szm/06GiT5WWnkyqWEqxmNyMPrj125XXg75AZeRDazTWXjObzZkJ7UA6i\";\n        sout << \"YQRFCFH0enKb75qIjHQ7635m/Xegoboat9VCJDGGVNVG58hQAVMAWHmnIb6oK9t1aaqXmAYXXgFo\";\n        sout << \"3uchUubvOjQXN+txW64ZRXzM5lAw4TklqmhDjxruXRdddoBONkvSPSh/XiDTkdmO6QKTCh/t6NLo\";\n        sout << \"Jb9Z7nfmQUd4adkS/+aUfb9LNOPd0GHxq2O/y9XXHvRTBASUV6xlJzpnOBAtTJSDrbLj9NIhiWpF\";\n        sout << \"nsQ+Nq9aEthi7RHvc6rujDGF1gqfJjsdPUTxveNk22Xc0fe4Qm+07HEg0HvhfFWJdFJJHirD5j82\";\n        sout << \"bZ+QZTppInMAQRh+dxZhlCzPKdqS7WPS8dpXp45xBpYH4GsG7SaRgbCBm8R96j5iSW3oYd+ql99U\";\n        sout << \"OC5fYGDbbGT8zl+mtYi23CAV6AY/izASsZHq7KzSV5taKzEZyJXf9D+wRaopIZ5JPPtmi/fr2HAC\";\n        sout << \"XyKoAPNAywLXUTtDezuKTJiyy/DBlHKxloa3uVTeG9YBJfiloyym8p9GsCOcz1p0s4K1Oyph1NCo\";\n        sout << \"CyklDAHvlMNjTA4hkWIHTyIStVmgvVkNN93qpPYYNnV+fIETW0tvJDnyJ2OnHVP4h4VBWbntk+uE\";\n        sout << \"JDG+DLleC5n87Kk+e/lurPTik1Yqpicwe2ct0AgA9XJCrDO6CYGT7QzFhEujgOYqzUmFe+KGn9u8\";\n        sout << \"4QMY5HbYXY1P9V3pR/QyoyxtuZNU/caTzRM58Hxe62q7BHmsL53db7cDUE5dYVR3Lx2uK/pm3QWH\";\n        sout << \"IIoyUhcLmk04dLwoi7YAhnao9IJQ12KlFISFoa/3WvhWbb5M/GttUDXGX1A9JuGrhjzXMIfGyS/u\";\n        sout << \"wugpWw/5SnWaCis9sNGmmMNC2rniqemMrjAUv5mGPYA57KyKzvVGGKK7VM8qyrtwSKOQ7fWRevDE\";\n        sout << \"NVAwhR5NnzdQmL1x2UrFcEkARtk/8RU/tfy3nXqg6Bi8g+myCn4hH4BOtK5E9GItI4R68YjNDVBR\";\n        sout << \"MiW9KS5gXcigTV1fXrChyjn4Enh+GrdLBpWDJQr7MKSVSmqGXntmhyTAD8Hgi111whRmKXgwi7OC\";\n        sout << \"k1Jn/NAURbtbi18YCjCc/+NfStTpuMv01C7+iZSQbO2rzP2aqaYSSvIx2e3/e1fWfZfTJBMQzcfs\";\n        sout << \"zITZqhDilOIDxPPYv9xAkBxnwGXIkPAi5133yWC5gcNh9hzEq146cKvQ8BFi1RHGL/yOiDjADrns\";\n        sout << \"Ky2PGu1fBfFNfw7tqF03f6zNB5IVWVjmnKtXhM2bIGqI/EM6Qx79bcYKYXcFg8yYbTc3z9KAcgp8\";\n        sout << \"es3R4Rwfg9irMdI0DK1CyYnpoa+zWhUXUzpTbSlFx0zZ0Vfx4xnPh7ZJqJ7/U/QNAU3lUP8LXVAP\";\n        sout << \"+jMIEj/H2mx80xaTNCDp/Sl+QcU1jZYx1Ycl1B4gH2/wsYYr59q/mDD0gE70hQpsE9ODlZzx9hoE\";\n        sout << \"HFRmDUTI0um1u5fLykqAJFVPcfk920vT5TqEZSMX0WvMVxqvN92IUxy2JNpXXMlBiekCZhEKKQqg\";\n        sout << \"D3MqZCUlGFkFpO/zc35vlTBUCuTvbcnak5HVcREFV0yNbTyukhEJzcdZArcCZs0xIbM873u1y/mZ\";\n        sout << \"+dUcW4zZJ4jNSa/Vz3W6sj41hSQKrQfPyeeKpFd5iKxJPXDxV2iuv+ZBgJi584KVpYSVOUA8Bzi0\";\n        sout << \"0kQh/NO5BdU1qaekY5lfrpA+O/tTzkTL1ZslaaBimJapn5KZcTtsZR0YmrE0E5okd4DxUccbElFb\";\n        sout << \"81SuaH/YCvib5kUbkXA0ooelAU5UmmMCZ1ArVVgwlLti65IqtSWD3LB8rIOUT+QKutHVEOpNMOrJ\";\n        sout << \"A8DnPVgF2kmeOngOlOwb8Hgpg9I9YCuu2cojbmROM8BZh2V6E9oiBTeKPgqgZ2tkgqGSf27SEpPo\";\n        sout << \"xHPyKMhQewkcq3WQ132hIb0s96PdEfniPUSig2MLn+5qBZDFLHHuB6K+pl/6OF/h7ZaAaCa4NCA9\";\n        sout << \"32ecTvY2MzUHmBM6CI/QKLRtBjmE09TB8s/5/X++k3cde6xPE77c0/G6qLrOUKFITVb+iLVADv3O\";\n        sout << \"zhj95j7URImm87lmo9ZBDTm6bbKoQtNAzEpBAiGs/VDuFfA5ZoQcwTwEnhmOs/4bT4591uwosx/T\";\n        sout << \"G4whvzgfcbPt9yHc2nnSSrIdYTSAwFZ1Ksh36RgvDXxaOHozLvlduvPaJkYSk9HijbmULXMUcyvD\";\n        sout << \"6IrzOnn/8NY6m++hE3KxgFM+hlrlAp3qQBDEGj5FAYFu7AcCT2r7YB5kiuwjM/7J8KyJYWg7Z6Nh\";\n        sout << \"zJbYleW8QA54s40d7D6AmOBX4+5Mx4e0roOM7WEFoqvXqK0ebAOrgwZ7MmqtGwe+5/bqkfNqg06m\";\n        sout << \"o0UCVDLmF/SzqAsxgIJt1P4/l8HzWtrFINUcBwcDY4ZhV1fbWICOmej8aBMJ4j/iUHLkxbnzQFBr\";\n        sout << \"xuNgC5/5I+iLjiYTd5+bdsITz2aRpXgUHx94KdOtcdEJ7uLjUeo7jeYvQVt50x/V2thmd8zHebNA\";\n        sout << \"6Yj14+3dHQH8c29EghfihdNobQHSyw9eVo8RyVI40oUxykuk65ILT1mLbnASJcKIInvh57YMVTRv\";\n        sout << \"rpPmXm/b5ZUfTMbzpTwO5DThvD+TTGvLY+eC0awfepSJj9CjiBTqNBJDbd5yKVjH+oM0wTufEUgP\";\n        sout << \"Fr0fondoPNTB61iwLzHrGVbzU9Rl8rsuiQOr6Yz/Dj9OjgzyuvDb3zMilAEcLydUFmkZlq3uVCl+\";\n        sout << \"LTYgz2tAQIl0+6SWZCel1bGyRKY50U2bJO0dbHawgGrUgZ/OO2k2HJnC+0+WKZeSj4s3v1OfCZbq\";\n        sout << \"F1nQDtk64Q2X857gH4kTx3MQ8gZCok7M+sd3p3eA43nUuis/SwComUQODyRA+TmuoE9AdASWTZQw\";\n        sout << \"Vz/To25UixKQtov8has8TRMEPOWqtZGHg/1tGGyZKkTbHQlulKwyb9uusuzC+FAQUEtpTcXkQzDE\";\n        sout << \"RNHKa/I1/zTSLVnaADsLgrQA13Igh5w86Bpn1bFgE8iEW5zQoNs6KDYwsRQ7mMiJI75ylVIvfbN1\";\n        sout << \"Cp7tpGCKCL/8xtWWII5ygWogcGhi5abUDxG0WQOaYk3+kPU6w8OPpbaT7h9TDO94XhcwUb5q11O7\";\n        sout << \"LAKIZY5+/7DhdVfMnplHpLNftDihrGwf8r46FUrZ8MRHAREnHSsch5dYY3boGxsFoNLc5r+fbJVD\";\n        sout << \"TxslZ5TEbJCFrBtFqbT3xuLReyo4FsOPZd0N3ZtFXt/ChTutUudGtCLfD3ucoJohZuz0Y5Mq5sHQ\";\n        sout << \"Kb1vAx9sRwpFnpO5o+RKYaGh9QkdrPXqUlcyXkSrXeNVfGGyET2vZB4VtQEAlG0nF2dkiF2uxKbc\";\n        sout << \"6swYBEYWLaftOzle9xXK6NrwQCrH/guAo10Ct+7uLmhK6P5MZW4kxyLi5nhOPkB/jiASFRPN1NOw\";\n        sout << \"KdNeaakEO7PEKPdcIhWjvw3sePbhOyHnmdJGHRB5WUvjOqD553+DFu4pgpUPHx2PV2IfEF2Wtfvk\";\n        sout << \"1J4pPO9DvXw5kBSFmoR/VdU1bGkVfkDMafaHt2diRtBZwbJb6XgkzJsuSiEtzaZ3BLaieOYJKCFf\";\n        sout << \"LK0/Jj4SEEDYj9NIHq5MsWH9PyVYvV3+IpJa/AB/WHXF6XAMOsLR7ulEmViNjv3UYOiWYEyT2v2o\";\n        sout << \"hYYg+6/lbwOg3frwE4tHu8IMfIZZzoFHbfT6MnP9ajoZWuSbbIj5KwvJ27wLUsQPevjbTypUXIEv\";\n        sout << \"W5WLBcBCegLZyIdElFV+1kJmSF5dZhY9RJeDOs2/CpgRctMX8hUGtMjLIAMjm2yzS6FgTtuuPJdr\";\n        sout << \"ErWoYhOWgGSZEitvtLZn6tGl+JZghT2F7dfmMaJH8y86txR7YCaPQgThH1zCh+yE5hvZPXW7+OCj\";\n        sout << \"D/MUIXp648v2+9ItiAlAZ+ho+JzhIA1jgC3h5fWWmEc7RnWvtyiatDFAGo9Z4UCz1qtRqoKdlhr9\";\n        sout << \"loA5N8Q/E1vPO/G3X++gNdEU6/ykRYyAODNhxYTnkiT47qRUzqSgOwsi6ePyQVuLDbSCwcpZK0ps\";\n        sout << \"qR803wEQBh1/nA3ZUeO9g7ZGaybxNoTj6Qs0u5vRNudI6OkjlUMMTdXVWf5ZyV338dihwHho3RQT\";\n        sout << \"Y6nYvFbud7IP9HMA5ga98s8z1ImzGbKGTMqy15rL5/PVkyddf7MArGuMSKWR4F0njVU40ILJh4Ns\";\n        sout << \"xkuzzPGZHb68JdMit3OazsaLvkZ6kBlq3KwWH6BISfiFv8eLYRxCKSfGWoqcw1qlUaFM1MQTJ0Zf\";\n        sout << \"4IK+R9+6/GGQJmSEDCyK1t4jbWDr6pjoXOIsihE/hsJj+Uy0mcQ/pRQpxGc9DvL2/7rA09Lr+Hk1\";\n        sout << \"xmm09tLOMEtd6mNexizTXHotFeN0+M/fMRwjIUY3lZSOHFVhb3AcNRcVE8IhsOnrUu9SuZCP5cLI\";\n        sout << \"xpc66aGsMww2jY/TEMBmWn5IUpX3vNe26iJ8kXZYYqPKz67I1BmH1wOXBaHZVznvMHXBMF7WhwhN\";\n        sout << \"gq7Pf38r16eou+L80O0aAaHE840lzt+jynl/vNb5tZ6F75G6jIPW+ARUy002bD+n/k1lnmwZ1WgP\";\n        sout << \"WnxwFloLan9gTO8dZG6uPyDHL8HaXU7cpty67AFbDMnYnajqpixUyDYCZeeYDvcCv+lqDm3YgKPx\";\n        sout << \"XQPEQQP+qpwvPcwLIebl3F15EhdJuy1gdwt3Dyca13/+aQOq4Rd4AYFl9U8ehlJsrUOus7Q6xohm\";\n        sout << \"J6wNJJzJpnRwNH+qekXnqKqRdTUwcQ8JwcN9u4sUE4pmBWS4/hJSYHpFVaUbMPmun0Dou54UPzod\";\n        sout << \"HFGXXZd76cZ+1MqaoyofxHU95d3rh/47EjPtQInAKAXmQlud1wYLjOhdDwGyvhPN3XfohEPrH+s0\";\n        sout << \"n/tMDShXPyFIaS+WLQZbaid5LuarlwA1rQc5cJ16xtSrW9sRjpEM22MxGmCyyuR5mMhbYLlULR1R\";\n        sout << \"b9UJ6/BbJ9iqO2LOh4geqx7Pl+kvdiOwAfXLP3mFZ8PHTHk9mJMa1TlA/fLSo8O0YqHMTnFe7OtW\";\n        sout << \"qMNzs0Pz4ucJ5uGzptFUXyCqq4vmSS3Cx4eolZv36mgGa7Ll2TJDCJckb6m3lsroRCTs6zF4B2yN\";\n        sout << \"VfTekTPXttFqhi4GI85Y+ZBvMoOIAsvysWCsV31AzKg/qlb2+dOumyMScT0GX5+l3OMO0iqG1QXG\";\n        sout << \"3fJZOpDQHq07WuCisGH2DOO1sEE43+d8fZHb1l7PQ2w25w6hq0IA8u73oDWRyTr5IqY+oDM5d2K4\";\n        sout << \"Ysuzkl+odreYxlUvxCjwgG1UkXw31DQ50xIwpChB8rEd/5gW10lnXK8XTbVgL3fPuy0cd74toIhY\";\n        sout << \"JFg1jyA1ZST25w82oJBYq8f0NQtHc7bK01cS4OM0hmOGd7PDKiRGiIrsLcjgfw/J/jx3mBuEaR5J\";\n        sout << \"X0NRxcrJZN0RdwhmwfRIybRGdSX46JVUCrf15yD6vFi08cwkMxqpdn6fDfh0BTXzhmdJU0+219/a\";\n        sout << \"JFJBFD8iktFAl629X8denKKlc2sMyBT0IODc2OYlS1+xn1t13uEeLar2l/EgG15/eeBsELvM+M61\";\n        sout << \"7uSI7t1szDmeZmWrO5yVcOBq1HFoEmHIlDJNtYQ7sOqRiaJehiRNhnj/9umPDOWCmBdnIXYAxWMB\";\n        sout << \"TJXpWzOOeRvpFNXUHN8MDttwWjx7Osmal/5ZqIbX66+jdQrLih+L4//J8oLyCBjawxIj+4BVLSpI\";\n        sout << \"/jyMUEbzBmRM3HiOoqqgiTFlLeRAM666O6oGhNmrFC/Zf32boZ6YmU0OicO1P1zsaRLJkvMbCYaU\";\n        sout << \"Dmi4reAoKBG1PBqaWEhDE2VmjiPPCs2WqZfll85wyGQDgKKdyboLm26UWwW44oM698E6stYbg8cv\";\n        sout << \"P8eyOR8awT6WwPgOS3fJZFuKTgN5LXJxk2BVCzx1F3gnmMQ5FHhIVm1srDDFIIwSkuP9mgjN9lEI\";\n        sout << \"SGCLsFYdEhVedNZuOWMYCvV4RChI5XCPh0ZRilVbCP4kkj0Xaqq3SbNWD90lwwJvFdIkZOEPeYc3\";\n        sout << \"xfLARYjHqHbNkYZLpnTw6BPH8L4BCDl4v7ndyl5Ef5zvShk7L2VIyKUK+3lboiVjwDoI+k6A7iNC\";\n        sout << \"UW5f3fTA9D/s1hxS/LxaFU+9Z/bOMjiRaPLQ/ioOkwyrUJpsy8/K+T78Vv5XXqtOct0aXrtUydgP\";\n        sout << \"uWZKhAFxJe5467wlC1aja4hHwyEeQmn0P8ilBq2G2hDYGEnKEF3XN7bwyFS9RGFdU06jkKlop8cm\";\n        sout << \"s9bVHFI4NeItHNO48LVlRFQaVdq1p5vD5elrH1h+J0s0BzDauJaraINeTlF/PrpGzdxiA/vq7sB2\";\n        sout << \"DHPBfrxe/yTTu3YTnSzMYR5mvPdjKh9mH6PmzTYyu/lUN780SUyW7mmEqoNT3LcgPg6QGUfg7hqn\";\n        sout << \"HP7ml/WtBRhZh1eLok4o0lVOhX5S5vMkXFa7K2pObSkGyyItCW+Kk9SkH2BboW7aYomw/3tAd2ce\";\n        sout << \"FUm8H6Q9NP8KDpaebg/67KZijw5kCSH9dBi/XzfZY8vzWGPW6Uj6zpbcDfRQDb1jwrPKZRhQHHiT\";\n        sout << \"dU6ZscvJMqSdHXsCNByBtKrUX37K8C59AaEmCdshNlaIOQLvceIIpJ7XTfmtnjSSvK0zJzBWt+xf\";\n        sout << \"RdpAeZwDNK66MCl0DIJwG0aRK0nwuePf0f2k51xlsrnl5nY5rM+hfblfsm2BKH6BH/SYlUSLxQlC\";\n        sout << \"MhdXA3MGhxN9yuHCm0m8WVc4/4g+SCKnp70ZghQORzaijlU/0KS6P3e1po+y554gEqicyXXndnwA\";\n        sout << \"qmRp58+1pxbwORmCQIdgriAZxPQl77hXxCMES9WQkBVb0RKNnbWCWvVdkwxxYHBGhO+m4kZVjFwW\";\n        sout << \"0jxlEcKNa7WdQStRXCap2VDFA0c5kUS7WN6R9HbM/u8xMNLzzE6jrH8l2h8QrLkjHE2R5y/NIVAX\";\n        sout << \"G2+cQp2X9XxHVWQmfflpXPKcDGGYR70ALFrgeRkQQAxfR4WBDLLQitSat8H/q+yyl6hdGj5nmYXW\";\n        sout << \"BRy7URAh0ibk4K/Bs4d2mN8ivkxahOB1wPZS2FFHP/I9C7nikHmQwlg4VlPJTwLp25JDsOypt2sH\";\n        sout << \"J8CK02T35fcv89Dg6GKoIp9RFkJ2RcSUXyWP3JWFxH/u1rdTmOlVP7mAW4MgT8AQdXWXkfaJxq4S\";\n        sout << \"n0ZRo9RT68RvAcrdv2z6Hwh4klmlRw9qFtokZMGLk8BOtPGSOU/Av3k0RjEsqHLiQaRo0JpnBCw7\";\n        sout << \"JcdRwIuqvfWRJMpGF6DhHkIQCFZcTSftnNDKUBLVBn41O/VnUCakShsRIy0a3hjQpg0M/7hFbZI1\";\n        sout << \"wqiEu/aR4jZE3wixAJhXFC86bb59UwlH6TZ1Eszn7eH0inEqCSlMMRKTo5Bz5kybjP8As1pkPS4Z\";\n        sout << \"/A8L6SnY/HIm6jy1MiZJmzdimBLwv14JNZ2oUM/TWMzgnFayE0C1dwiX+75KOrJqLl5hnM/5r+Rz\";\n        sout << \"dB3emOb6i0OQI444QHxHLK6ZkLlJr8kY5opZlAfjyzuWzJUG9p1CXDfL4t99GOoq8TebYYdjmbyV\";\n        sout << \"BLn51c8VBQ63UM/dzKKgL6n5aUWAenJ9sNV3/b+fmN4cPWAv6TZQTDt6XZxPz+GT74rFhMv5YcwV\";\n        sout << \"zkuiYPllmx7WE0pegs+TV7BpKef2DBNlo6D/7ELNsr7L3+rz6w3l+m95i8jtIpeoPRzNxMWfvFZw\";\n        sout << \"OP46naSo+j+8Euy3CnMnx5HQVwBpEeGbqjwyhsKmRyev5wzgYGe4mxNTgrTKsVh4exFOYkFJovWm\";\n        sout << \"l9VKTRY4/Zd0H4dodHVquSWT/i6ogNNwB1O4T0I8hs8T8i4XybD4hM//dNvbPxq82HobB1R77rqz\";\n        sout << \"7wGi/X9MmX3ct7FIpU/sYUT2DeHZ8QFMfiBhSLqoHcJj2RgNr4cX9ZbFXk2nzw4Dz/ggTDOx8XRO\";\n        sout << \"qLovxOk8Sw7KXBDVmW1/kBhLVN/yffDJjzwwk/JqiUI3kPaLOiiJnnLRH+fS52mC/+M/xg7JHde/\";\n        sout << \"oGmlCCGQb/1q2j7he+nBCFZM8F6BVHnlA7DoGCzSetTLkOLo4OZssfDw3OSU/2vxTxkZ9qsarMCF\";\n        sout << \"uIl0MrtO59MbXtiMtGS5gcZL7Tu0SMDJUQYFtoZ6+QnDgHD3P3BsqyXfjRR+DTGvcVSyh878HpJV\";\n        sout << \"3R786KM3ZwW8iVxFabz1OOFx0Ox1fCspZa3L1ckftSTD6ypZAN4f5ox3Ad2iY3l2J7iPeE6/a9sk\";\n        sout << \"MnHQmuMy7pMum4VVepnd3lfqJljkCG5ptnznCTmp2wPgkqmvzXl1UU7kyYrdMt1jTzg6fiKsbROp\";\n        sout << \"wGSxXLbRGT2sFjU0KExb/rjG21a0NVVp2PnYMQuyF6glGmCeSqohLsV3nv7eCbUd42IacVWAR0qN\";\n        sout << \"c+5Dj8hdAmRMU5DJrbaLpuHeg0gouaBYrmCYGrcMqcI77VLyeQGF5hzq6t6IhiPk9uLrW2tpF5Df\";\n        sout << \"gHr/I94WMSy4Wf0RnACjVxSeRewTXJDuA5pKq0EqNs2RzmiB7LoktPBzqBgMjCRyKlCAzwZ63XOt\";\n        sout << \"vOvKGWCbjXcVEOZGAY3s4lQRiNIJ1Wat62u0MSj9BERVU8kd/NWueMn+tbdGTSR6Hgyk9bvHF+Q8\";\n        sout << \"CdFQntiNHHU2Qx5ZbzPPoNNjqwy+FGicBBG8/xV2bPd/JWm3uo/8BFPqzORzGAnG/BHSARPbEvkJ\";\n        sout << \"ix1Nw+gepwJ/M8YNp2aE+hYTBUBJueaSPyPR5FS6ocR5oLd5j6biPlTv9gHGg03Wc4W3BqrC4/He\";\n        sout << \"R5sSsRThAGj/wbDu6SMIoT+2gUNTbUZ7Lx+8rVcWGY4OLaySvre1BzyhGPpNDuIhmbW7n2jfEO9C\";\n        sout << \"MYbtPL7skgqV4L9JlLup+vbCNC5ccOpxm0Y+XSA/Gidd+aZu9D4R9Ddz66ns1Ida6bWLFM7T8BpE\";\n        sout << \"dYgcQBJ63ixc2nYknR7w5Ez6JPnmfUSDjXTrY+tnXlbyWIrF1fI1Og7V5i0d3G2jcuitqs0v6SwR\";\n        sout << \"rgEDVnVz0O+cd56TOssSv1d2KPIY6tv22oH9P1sNzjBYN9np1jRH7e1GpnoEvY7MA2gNyBIWdrKA\";\n        sout << \"uUs0c5gYr88/DbJvZtSnmPUMRr2Lp/RtOHnabXkbAevAovdIvmh/BfnXnSjrOkH+BH3Ici47ohO2\";\n        sout << \"Da/7OlZj4wAESZO3WO0SKN4fUwC6M6LUM2L7kg1tvqLA5KtYokFOc2dMSRs8qz6qpneGUv/f8NMu\";\n        sout << \"PphJtFjOixUrhCOZVv+0dN94L3dNPRyjXlDp4EejgUxWdeYVPxiyXor+LSIP/s4yPNmn6wIYWF4l\";\n        sout << \"hIFjh3drkdxwsaS6QWeYL3knA6I2rR0NERayOsVKxcVftkonwoZJHpdRkhDhBj0Sa8TicGcSgQt5\";\n        sout << \"kqnjLvOqNA3A4XkXj445r/HiNWVbd/v3DRYn0lh09HU7ihGo/qrC1DDjIQjRm5MO64mM9xZY58yU\";\n        sout << \"2fHWbglRconR2QeXmQ1D71aEvNZwBs1G6s1VqbCNgpeA+7kvjlzwFzyvfIqMuLTlvUo+4uCHf03O\";\n        sout << \"im1AxMxq1zvmRPM844aIenx1bhx4vKmeEwTeHKYvjUkTCMFqOXxq0UeK5XSKJkXrK0F98MORKeEI\";\n        sout << \"lhpQXL7ky8QZChU2k8DDBaocWzF9oRtrXDY6vfuvcituo7gbfVIDzQrp4ran2eY/pvucYyn/Maai\";\n        sout << \"W5IQzzordTdlVKX99bpoGJrmFzYrrpUa7xxb5Hs+YvwicR8IE/2ePoZ0t04dBaIwPP3ZuPO0G3EA\";\n        sout << \"2XGdG7f9AARr1098ES4qU/JRanR/5XZY16deNuVPRKMdUEBMKijfHoQCCorvA2HoQz/jD1nhg2ZR\";\n        sout << \"cB19h0shhjnz/OVgb60bN4izBugSDZfyiuZvvdpnCbc7bReVBCM8456EG4mHdI1NSdGJfATpvYbT\";\n        sout << \"lKBwrESSbmkYIVCcBxn845i5lrPHMdlt0s0qwtcqBTvjBmhRpezoF/U1BnPdETs303TMgApql/xS\";\n        sout << \"MWS/Jme3ioI6E35BzkTXABoxIxyjdFkFTququq686oqyGCSpCxlJA2OyXwUc7XkBI4Ki35ewV3Yh\";\n        sout << \"DbONeeMe9NAred9EhUBg+uLO3W8oI3094ZbMa7N9b0tVpewsJuqP7nfW4hZtLSpFEtjlQVGsqfQv\";\n        sout << \"TqljECWVoZ4cbclYUXTMqtd/5okENdDEk4BJnmd5b091PoGNeSqYPf94LVrlyVSM6G9DmQm1UTFr\";\n        sout << \"bUipf0LcSMZ+DKYhwIJLpP/GppEMORYKRhDtgPy66GNfhiNKzLP+fyPpSf6LbtCUbE3Ni+PJ8zux\";\n        sout << \"k810i0by9lVlFUW9tNnUcSE7IPrcFs8fozpLwNSI/gTKFy0mNEnHJ4hlSgaVB157PLKmHSv6WJIe\";\n        sout << \"6LE89xQbc/Rl2TRjh2SxZXB62FoRLXApUFcSdCl4ZRdfA5p5zXcQVWxl3RUdJbpUhsqNA7vmHT9q\";\n        sout << \"qinoGtKuPZvANZr9Yn5hB8zzHLiRvk9NHhFdR/Ibw2gGXq6XMuJmrShSFRMZrTiIVtQeBWZNzQBL\";\n        sout << \"jViE75H59XWkpeUM8hAUUawEH+CFcYynOsbTECPSbgIbt1w6DRB096vYoMnxnttX3J7SIf4JtpEZ\";\n        sout << \"iSI/Xzdcu9L3QX7bQaHzaf/FIqWvdl3quN2CrSnBd/UbGCdgylgCQyBtQjcr2lP9O3QKav9laEz2\";\n        sout << \"YJbjjXldgdumq2W/0rTopOIX3V3xCHB6xkZq1SS773LCHWAaoPRMwgfrJplzRSNIaD9fRsVQuS79\";\n        sout << \"TUwphVg4iGrl/0u8YLEr9TmSTojfTS3M23HNJU/K8l1zOB1gfCYwmj6jGxTCuvDHvgpJ/UnViT2j\";\n        sout << \"fnQjGXg/WUwEoaD+66ZePipeu+PlIHDSX3Jj2+jHAmMMsFX7PZlP3xhWUyG6U0hJ1guDe4HOcMWQ\";\n        sout << \"97gJDdYzwSE+S7vB1LQWKNdEnZPmZ+rQ79gpjNYVfzE2djCO9Sn0rQD5W6O7Wd/QCV+qu619i1wN\";\n        sout << \"IziA40bBSmDLiEtZv9Aviu7q7Au24X7ZcXxRqruz9zKPSFd6dhpWAK9lD8PCNwUrDXAvlHT8pS+U\";\n        sout << \"8K2ISz2knDjOiHIb1P4jF374K89RNSNvefvkGBNrJ8H7JiseiuhumYfAiSVqBQwGUeh8lnPq4aeQ\";\n        sout << \"V0gFbCj8kNEs8/cDLBnnwCGZbqRfSGgSXTKWu3/oSmn/bMralWdW35AgMM2tJ3Fo5fIkfzsq4ykT\";\n        sout << \"ywlPUtOOHIS8ImXHCQgVt1+/OPbTpgCly1i3ssNeIkjPY5DyGk08WWYiih7IAKxjFeHSavuYKy1P\";\n        sout << \"1QMI0dJ3y2Wp717Zg46c+iKxlg+oUR7It9UT+ePKJCm/UAayU7LyOWThMfP73hM9k5G/h+8oENw2\";\n        sout << \"D/Kj5IkwB3iK6iC/6QrZaIHTWVRNYioSzsEndB0X9NhBMlcTmyvPJfctFydhK5JjQwjjx96k4FvS\";\n        sout << \"P3C7zh1ww1K/x1J5vK/2NViZxgSFmIz7L3NbwUb87eXPictC8NVReqskmSw8hxNmgTHG/WEU6NZi\";\n        sout << \"XRI+HIV5erFIeNRIixP7gp1z/o/5bL1QH5ALgBk4TRc1B9qG+fcWfJg7o0NckPbkkueM3u1J79mu\";\n        sout << \"pcs18OQ2A8zehkFZeaTCC6Q6BRijJFBpPNnDIxJ7RDazpi3i366Hds6mD/r8IDRT8TbWqedF8bNv\";\n        sout << \"vGRPs1aEWykMumZdtkRZXfByK14T0gF0CSjUeIRnPuhXbfMBznBUGue7eCj3jHnLynEKdtuA7CyU\";\n        sout << \"FlXmJWrixsWkohwNSY+2jCNgmIWsUsvKS+dlNktC7OdSo+QEIDnCfPio5AwCTWBBvUaxwR90GeWW\";\n        sout << \"yk3Rob5grT0wgxQGoCoew1J9DJT6iLEuy/jJ4FjFSB581f5186b4lOYaMoSCpOp+uWEz+I0c2G0o\";\n        sout << \"DZKFloHMTpZyEt8LggzchgxypR0SGSFxm1X0/lhdPwa+8lKRdcXmhe2ai6H0R3lhR9ZTBaCWhMMo\";\n        sout << \"GJ6SvT1ttMF3rg9qfFc1RKjK4+TsRxwYOP1XDz1rjEp7KWHLxZ/JKzp4IXomPm2f6exs+miIPME/\";\n        sout << \"yo+Dtmev/tYJLd9poc+LAVkFIDqQ5ID08LgCGwAwLz7J+nLxSww2OjOxhbVfRIm0Bj0ERLmvy0jv\";\n        sout << \"9Oz6hHcYVHPqSGN2aMsPtpWUWOgND2ofYfAJqqUMbwalMYUyaimuIU9ODyoT0xIMH3VeN/nrIHDB\";\n        sout << \"u1J1iY/Lshk4okLUB8OnbtJY8t3KATibzVtoLaoOcmcQzOJahRLw861zYSlCs7SQpAqVEoRjYtZC\";\n        sout << \"5JPGKLY9zqoogM41u3uy16DfVEvDYr7XZm9PRYY7H33QZiOYhPRgzZvs9nJZAJ7QGRDYiNQG5V6a\";\n        sout << \"Zc/qLzF9UaRbUOxVKJ6FkdhuIuK8d38cN1ky2uUM2m2cFAyJmzKosMn1+ZKo85F097lSyuDqgXvF\";\n        sout << \"hD9fu2ze0hTo2zqFmHHoDvA/3dN3Ilt5omMSSf/HQdvOeXj/2vtmJhpnERGJo0NCiOZfKI5QG4qP\";\n        sout << \"313wIpwQPZxAvJzh9YEHdb3fv6GpwlEygu93G8Uu4WZkT7P+XXqhH5PL3cZ2MYQeYGR70nvUzJWM\";\n        sout << \"lz7g/DvPE2aQHxGSlH+W6JEabNL1YUvAim6/uLWXvjbU+QdKDUQsml0P/auI6oHYMAgXnifheH85\";\n        sout << \"xyT4TLqA33Bc0SRpwPV6lIigxQg8OEX1czyeYInQ7Y+YhaPF9Dh+YR2Kf6xLS/qnhOJrAr102gf1\";\n        sout << \"apYuPnSogxRcir2pFtltl7k7xjaAcfcOUfM10VkYOoq92X9XTfbEBbeEAhFtw5AgWJw/iryapVb0\";\n        sout << \"nNPvXwZ6g8e0LM8cky8/CR+68D7KCkxTQ+C3cq6Fco2niuPO1/IbF4nnpLB7vDS7qjrgqU4/t0bq\";\n        sout << \"qMPMFgX4MhBikxwzWh6xnQgylA47Rbzy0EKMD1j4NLSkySg7zpm29sTTvEh68OnSBaaiNm7yoIpv\";\n        sout << \"41yj7kewoFyIY6wqbc6bxfAc+cKLdxYIxwwXRknJQuZW2mx4wpsjXYqEwZ6OCDldMgYkQWuLd1r0\";\n        sout << \"LNY80XRGlKZw4bV3eBiEAo8E7yU6VBqi/C+fTWCdaD3kjC1mu7V9XX2tMg4G2kaSqc6JMjOZ9VF1\";\n        sout << \"06FJujVmJxzZ8t4Z8yI3JGUpmWgYnvY3baanLpy54Fd7M2JgoXJrElrfsEMFsci44CmK54NpntkB\";\n        sout << \"wFoMnSxymuW02SsBU3DEBbZJmXspP2yqCUVHyqpp2Wez21u9T2LV2yNLpKHm8uNRf++WJ49zGBDY\";\n        sout << \"vJ2xirDEOgRWCQ/z4J7fg6AwMrG0PhqX5Rw1NStM8rPEWqKd9+6KKTL3lMj0rvvVjUCylKvev2Vw\";\n        sout << \"aWeVNhBWgelJ9v/Kdp8lQRsSyqJ7JP9CQ9iRicBTKpKio0NTaYn8LEo0yH5B8HVycOVJmPjjYCg6\";\n        sout << \"eiZ6Vxr0laxchTlNPwRAU9hsZky0eO68C/cLrfgqB2IxJeZH0z1XWmsA5dGcYAWMDamqBNPTm1jW\";\n        sout << \"USE/0iR1KPxvIemOxt2V565of+jareTk/Q77E+jkopN7K2AmKOGouPeRUGEmfrtZQY2sarl0tF2r\";\n        sout << \"f3TvsoqK47umT9s3R208qwO7nC1TQjaEdP2KIfcPxbyuZ38d+GxQcyuID5+qS3IQR4X1k+lyUxY9\";\n        sout << \"wtfNYYbmsXnqAXnM/mKlfGlYalVxalvxo9eJdugBIVbaQ3JmEovseS8IV0dZz9ItdrW3HtHquix1\";\n        sout << \"xKf4VBhFqpCdVXBY0/mMlcWws6nItmS20yCf8i6jJ1HcaHGuPQvhyiv+xL8kELcu2avfpf93i4m5\";\n        sout << \"KaJb4xkjSXNAcBerhBlZ+DO58TBlEZSI8UTw1+yuzymxOyNbq2o5rwqAqMDxmfJlJvbum5OnTWCc\";\n        sout << \"2AgSoTUVOUmg1br3xDxH5xX81Ty+fMaizY/8P+dFg6MGikZZuUky2R/nJRilgi4thJV2q9iCm3sX\";\n        sout << \"KVW0vt0AHRnUb+QkaLl4ZJwGUcx37S2YcsFCAk/GG9F3g1zo3zUNgbl7WelqICfme9vwcl+LDnvK\";\n        sout << \"q8jgEUNwGe4ZcgDuPAxiOmIo0W0iRDbt97R56EnRs9n0E4W+/DWBvHY09nBYtVrQWpodvZ3ZkEp7\";\n        sout << \"9zg0d0rwaLtb21iZPH1swSnf3hTYC2sxq8ppPJKENrTOYj6qiaye/kqg/u+rZmhd/LwNckkjFy4H\";\n        sout << \"9OA+Te/sjSoRCoSSGXtGSexAhh9WfFMnivoJ+9kAIGRUCJPQCx+NPQ5s1+d5sMZHyGs6CsR2Hpjf\";\n        sout << \"ZvXMpbZVEV/4Fgf7VMtSexPTV27hFxD0wHrhU4lsQp0T3QcI20VYx9kTz025uiMWUD29Fm3b7peD\";\n        sout << \"K2bXo7y3G3k4ykOPrF4kR0VSkjB1NbhXftQImcpZiSDce0MZOZZvQ3lH0pZ7LaU5d++Dyp8xsxLt\";\n        sout << \"4toEQgoyLaS22tEe1jSQsT7v4AWwjMBAQngr8MsqmcWyu1UYshp3kmosoxHZ5N0w+RN6P8dnRWuR\";\n        sout << \"N3gIp6dBvllTNVG1Nf1zJ1r0w8KITbzsS4bBLijKlUilL4b/P8N81fEUDaXCrcdcL9b0fzv64vg4\";\n        sout << \"9ZXsKIfw3rjw+/ZiDt6a4WtwCZvCyI7cRRB2YGxaeynx/Yyqq9xwnWThHA0a/SAwkokg/zbxfi3u\";\n        sout << \"kzPOBau+RpDKYDL6DBkYaxMeTnbF9dRZnckTEhu8kcSh5uHhVNSeyYSngJ0YXZV+tEzNi8yI0wA+\";\n        sout << \"6M9OX5gcHv1pbem3Fyx/3Rqu/LbjD19TtdwuyhXnnGcCXPGzqFrpEdN6504IdM7WDRrkdjpyTlOR\";\n        sout << \"5hzk1GymO/IPAk8uRPEHeU+873xDLoxeuNseeNDRuNwFa5FcIKmIAEGeSydVPv2uPH6l0VQezasr\";\n        sout << \"XMXlWOCOFo9eGGJW0p4tz4qX35tClsU+0ml1uaRR/fFeJyJ7+WrqyqDdHpTqnGWp9OdyyCiowxFD\";\n        sout << \"T7MJ/Py4+ytZ++sArWxfC5KATdztRSzuquLbzKfLtF5x3vihfHzonsdHzZNUTi6py1JV0uQO6by/\";\n        sout << \"1HjNlxiNqfOEaQxfLe/KwZvvvSVasZQz+64BSVLPlmwFnha6iUXYl0m8pNQ/E3QlysaeDvf6j6nC\";\n        sout << \"By2Ft84JgN/2Gy/XJuQRobhPiDh2Fro4ebBwOjIIfgQx9Q9FNzKRDHAS0/HXB+P41/CzXWr2eTu2\";\n        sout << \"PXZ0O8TshRiD5gH7Su23qpwB7qlNrPbULE06oc8ftAJtuKAGDPFXbom3zFVjsj/yeTmS2HvU/b80\";\n        sout << \"8FCgSSxx8cvIqfPHLLOSPBUxJAVyCFPvDIUzHE3sBPyw9OY40bgSyaYoC+hoKuf0lHgt20r1Tz5A\";\n        sout << \"Em0sAZfnbWRESfaM8lafrA+OjaSDQQW7wAI4+XO+HbWYxz6Zj3hu4qfmID2Iz2kuo57Ci1RLOUzl\";\n        sout << \"sWcTkVqUrdnoGzjtese/OnbbsCUQIfCM5ygX1KKgmlb331Er2So/dqrYpCFAqBo3SmctlCtmERuC\";\n        sout << \"hkB59TSoGqV6ePxidHGWKBsEHudcQyRv+pwNhnRkW+l1XmpzMmdQqeBjqcw0RAVJgDmHS1SMrpPE\";\n        sout << \"GZmNu+LmuN8xdGV1tbylOTC4TVND5NOWaPDE+vx0YaRi2orc7KgrLc9OhtAQdTC7hlk/8jlmYxFp\";\n        sout << \"xl0Fe0oW1fU0avYFk0p+dUXfYCA6HXTetcQJdo7Ai4JveZIUdZ5xW2snKTZXd/IAE1UG1o5Uz0LA\";\n        sout << \"/y3Q2+1hBR+4cVnmqVftEf4ZQQoJlY2CN5Wltg8kWf3nsgSmu1JNtRXEV0DKODWTAGSizMJJleG7\";\n        sout << \"ilV6GJU335MapNMUrlHYVNicy1NY8CX/PhZtbGzqNM3gfwS0KhWmKN6HS2BYwfPllMYJk4koLHWS\";\n        sout << \"R9dpGgz8n+PDrKOcLG4U8xYocSvLUVJ6YmdbYWtWunGa0I0egn3YmUc6RTflJ6G2rRpjY/B//CY/\";\n        sout << \"tAKUuY+4e+4/VTH/sm1z3yHSycLOorAeMjKnPpDfN5d4hyrqeHgG/PKdZ/QlMZYw0M2Kb9fpvefl\";\n        sout << \"cqeu2IZaH1E7G/YbqnL4wRlPq6HSQcT7C4r7vJxwYGGwZ2wClOXdvvbdjAOxZITv116e6jaMQ3vN\";\n        sout << \"NNd09s9zZlXyXDyBfdLgFebbKLjrxC+2eB16aURJkorv9jQydbdMMsZ7DnW75DppDplDyPvMC3TT\";\n        sout << \"0o4PDSd+YBeWo6CAZcWNR+lB/ZB36tA/RIyCopqeUOL/P8cfeJSX+3k1yghKm4HeY6VaWJSALiiP\";\n        sout << \"/0nEgGc4dbVmspZGzaORpGOTqqGnHm7TiZmOJW0PFrCVY0N0VqHcSkTOZn6PtuQKFXtFHYEtpepB\";\n        sout << \"0d332dQEz4AxgF0qrhrviqEZpXTxG1bWE4uC3H0tDWIJhyJe16xF96vE3QN6z4P2+esYwjsfRdQp\";\n        sout << \"3CYcxcjagfWBngiEfRsseTLhVf1KsFIXgafpK36gWlZan3O/7uyqhOYyg3W7aJ20bvZWuZZ94Gls\";\n        sout << \"7VLJyTKS4LNKHcb9Y2PtX7nzosb7tL2hcYgGChva73FTDSuf56HcC5+KM+t/MXf+BPBr4FUsgN3M\";\n        sout << \"1QrQiRM4dZte2DfAvSaZmWQuqtsH2uOLimHU2AAsfZav6k+7Qb4mQs6zdRPTMPcd8cUv8MWf3aOW\";\n        sout << \"skdmBW3ausbs+iQFW1MUqr/4lwe4DUekn8nfniBCI129E9p0JLXLw9NrT+669orbCX3UOGc5UHTg\";\n        sout << \"0SvFTMRqw7Y9mw4NMLOMCn8/mINMrmmaTvtEwLhHSOTwYjRCJ1A353ENYX3T551pA3QS1CrWfIrI\";\n        sout << \"apV92iQiSH5A/rzOjhq3BDCU8HIXihgVCsR/w5Kcy7nCkI4pvbsIjPNivZsDhx8H+IKNTUNpSRt/\";\n        sout << \"CPzh885kcdofM5k/nqVvvJhQzhpk18+IRuxTp5Dqa62MYZwgEgURS1lVVzWQX86wJl6/4cbIVEcb\";\n        sout << \"1dowX6FrycYfy81NkQdF06egVOZVYCaZdW7f1W4Xn4l7PWb6pb1HRb3/0Wu8YuYjm8pSY/wA70cJ\";\n        sout << \"G141hphqUxQeblVInhyk40zcaroWoWWGTkiHUnAp2cQgjZJRHbrfoJgF5UVmdDJrwdwiMREmR7zZ\";\n        sout << \"uSS4xTZ85fXMH1NGcOAu3tFt97bY2uh/Nzk+XucsND69TUp4s7RBmiahbRw8XQa5izZMRPgYkVss\";\n        sout << \"A4ggkTd9wiuotgjMtjd+NsitkGhuoQiQHLW0R0PVPEfG5mtdlp6/PlqCsTum8bRuxivsPkCcjEB5\";\n        sout << \"9gdgEeSfSOSRTe0hnm/gDQXs4BnFeyG/YzHm1pHHIP2VHkr3GlWVu0w7tLPXFLXF8kRESZgo1Np5\";\n        sout << \"WFYh5OmLS+J3xhJMfzNjUJ0bzfN5BnlQMDT8vttfAovg4IO7zFTexfLBxgKLWJZ2aQnoPeoBIJFk\";\n        sout << \"uPBxTjUY29133ygl2fAylnqP9zIipFbgkLEw0NrfKrfKIPK2Kf9VI1+adXQlsHo0vsI7l/uWbW5n\";\n        sout << \"XMP598ROkdbP5aSkpXPdld++HGzYtfD76teXubxsFcCpmm3OSbcLo2vAOMDQdpfFTOLM0ig1VhC6\";\n        sout << \"tCC32GUIWix0VLb2dZCdidXJXu40BNL+ASvXUAipVBD+qBL0uSHZXjns8B6XFD88zrW+reKH9ZO/\";\n        sout << \"gRZI+FH7eqxkZlu5ChFHJeZVSK1MwHk1ikQxAe8jVXTzzVAMcK3EVGvH/l0RKX/SJvU58t0SuHOr\";\n        sout << \"HVule85Z1pwxt5DWS5IYXibDgxOWfrcKp1iTXhhKsmOmqLA4M8iGbtJ59RjGp3ndoc8k5lgx0YXO\";\n        sout << \"CZKSNjMhF/swTPJF3fvVwzBU9vvWe2HCUTejmLi+bivqW3n+qtHiI1y9VWPY9B90N9OalQHJD2OB\";\n        sout << \"myHYFjs7AVdwFYoQZIBFtaKpozISrGZBa47RfYaS3zH2aNzYnT6zDsgKJYdA8skR/tNgMQPdgEtD\";\n        sout << \"d/NZPBXg0YnjIJNX9z3kcvXuwNnpv/ZafofCuHJQDRlWe2hvfHXZJf22IWrkeFjTGAzVl7bGry9d\";\n        sout << \"zaaFJKt73ogJ4IM36xHJ4pgGuP+daAnif+2sdHoEavTV6zvkV8T2UXgdP5LmPVnoz0zue+DBTt9q\";\n        sout << \"Lco7T8RhIgRDQL3K/PB23bc/gYdGKh2ISHY1klB2pUWu30sBa+g1ap7cTFIC5eDQ0L19jaJNlLWf\";\n        sout << \"MQR0Tshn9dRsznAfmjIm4RvhMvf97Wer3t9CjFOOaQfSXxdPQ0KpnxeyfyuBpRYScUX2cCEkIXjA\";\n        sout << \"IiOHn7aTJ22O3S7vZ2a4jVygPosfhvd/nNfWhAukM9UfVIFi/kG8CXvuPjKhn77k1ddfIbsp7Q2L\";\n        sout << \"Na7xoC6HiPus1PI5kd/p1NkclRSCiMBCl2qQfHqVIioK25jAjHl8SxsiPpkGDgiBJTO+HR39syAt\";\n        sout << \"iyjvIv5KH/yAzl+w13S68pDbAGZ7U8hDI/NKlhgVycVmkfKZzGB/9wzJVemHhvosb5tY/P9ZHqgB\";\n        sout << \"HuIUgdxusvm5IyzBBl0DbaMxwdHevHQgJ7NmxtvGDDofkHQ8JQXkr+N7+Oswa8KAEdJc2t9fST82\";\n        sout << \"X2NPa6s0wEQ9PvZhUQd45UcFtXCBbkCoisIEA4X5Af1xG7gqwo/PqEW3g0hYwmbWDgNTnEHaHSsI\";\n        sout << \"4k18Jcem/+3cNZx6zFKEZ6u6/JlvGJsNjvoZQlRluwF64lvxtmvxwD7ak+UmFc9Ll+cYhiHhdy7h\";\n        sout << \"e2RAF5HLTVf4BZkUs+NI4h4c5z+pU4dxM4JOVNQ5OoBisyMeFbFDlBd2x6wRMtiREIF4h/yDm5/g\";\n        sout << \"QIQN6sXCt4zrBLoPvFBvC7UvVPaLEpW4Ay7yeYoFhTUcZ7G11HdyJHIrWhXj8mazBuT33wiXPXD0\";\n        sout << \"fgDO2G5kVrYv837OEagI68UWoYwHFVQyKy7rXAqnJOH6rUOiSeXwrAs0VXCOo/iWz0+H7Vgkjvo3\";\n        sout << \"a+RGXFU0PakfqhrS4elT76gTx27rIG2VuKjWnNWi91g2MnD9dwS4xGNu0nB/HiOTDKKfzQ3uoE/D\";\n        sout << \"oP/Fn1wFPtBDC6935HgjJA30RBpTT4lZtqaVhy4F/pFfqFBL/RUU0jmlG8WvHSF28NkXMJFxqJqr\";\n        sout << \"FdZj/ImUTWIBtAOXIMgu8OQ9LXpd6kyh7dpy2lLG5ik8X18yJnJS6WZnRAx6nX3Egg7zi+jq6P+B\";\n        sout << \"AGQecbLJ+ngHGqQd6fP8hOU7ujU4yyAEKX3CWnvjK3DKN+fH9enZ3VHAgBS6uy4BicQeqNJx0D2k\";\n        sout << \"ab3+B1WPW98ieaG+G6TjyFGNFwqA7ComKR7X745Px3MW0qoQXJVK6FkV1x5zOjrI09hc3G/NqzC8\";\n        sout << \"5hR5EA4ebicmVwYgc2rftfhZ9FY8vTslWklZHaZosv3/QsoFuoDNMA82bg0/tDUo7G47EAETe7lj\";\n        sout << \"7MRS+dqjw9rMDlry6erLVu9vOvz5gVxhNM2+Q2VKx2f2ugkn8/VGq3ufEEoEkKtnLI0aJuli0ZFM\";\n        sout << \"yEDEHqombS/JdKacUNhM/zevqMA+F63pABb/wTCYhNIZWZM5SRCoYiduOSQYs7eR4ex+Y9a2T2cc\";\n        sout << \"UyRYpcFRySR4XB1Nf5GVdBmuuVqvg7wuRwCKXDkxcesKSrg7HLlUT9xaIReIHoFsZj5w3RcZvSCT\";\n        sout << \"q+d61nOKgP5ym2c5BwxytP42yQ3SisRyykroBgipHm7QmrJnrsw0OZvAkFh/bo/mhstLDPKkoA89\";\n        sout << \"Dg/kr5VTRG7Id11Qb6CKvSb9hq0mtnGAGnYa7XTmmojYhVXeFF1aj7E94bUVjtl1rJHlpNSBRl8U\";\n        sout << \"LffnXik6Ju9PK+gw/WXTgcyOM0Gmw91IqJsBiNVmLMB8VPpunL+J27aoPVdSxIpR1H5PjWhWyqNz\";\n        sout << \"jDTlxcIKpM0PBs7PyNJ3a0QSQYQrGDYI9VkTQJpxwYhPOAWdIjTKDBfx/wl5UyxbcAzD2e4mXkGq\";\n        sout << \"535EjhmfhG0SRvXP4heNN4Vzl7KMDjO9VNMB4/L7500528rL2b1wC81igCwNWpUL7Pn8/XTK8jRz\";\n        sout << \"KCcb92liptbbjGVb1V9hh6o2aR5l6ZQtS2MHlkZG5rucr+NT/SFYoVKB93lLnq2CbGPlzZZdPHLv\";\n        sout << \"+RG2+80boVipNp8XD53hLWtOvWMQGWYwVWSqQ6jrO24yXdRjZCn+F7mn9mP/8U2dEi546WLWvaOi\";\n        sout << \"RzQJdz+5IcL8RBPWCcUqR2VSyPIT5Fzw4D2+W6G3cvc7mWgiEjT9Vzjpeo5D5rWM3pAPl/kI+gMg\";\n        sout << \"42h/H45O4HY7CTb1Isa5GyX4L9vPfLXyfqU0N/8v8/UvQyB8TyKaDMedoiA7+hdWtXRMJ3cFxepR\";\n        sout << \"WqHTCK3o0Lhh29qPjMh7hKtC4xNVL5/Cz9KmIu8ZYAC4aWXX0g7wzBb9o/Xb6mJ+ZEDmtI25DiFy\";\n        sout << \"McNqoVFxoxYhTrUYNOaAqJYVTOauV8N3Mv9WiR+s00mjLAIEOrcExjt6WrCUVAI6XCqsWPibNFTM\";\n        sout << \"tSBPtg/w6jDsX9H13vPzwv2Wt1gGzejC2nuqaEVXlr1UKExiXjQGAJyiw13PjRHSOD5zUWOhkPBr\";\n        sout << \"h7lzK/HcCTA6S8PzM3yIPWYUtlzfFT1a1gIoBvO6dx3EbGGRYcePQ+xCln/07SFsUXfbKu43/RIV\";\n        sout << \"LUXeP19XnLIFDk9NRlK577rEfl3rZN2TkeFXMESPA2E3WtUXLw/rQxAi+E9n4pHJ1dfLJDrXcuH4\";\n        sout << \"iY3QbOnJj/ay/dY0eDCjoR8XBlbvqDCvuKDZd/SPNLseIwXXTSFxnRBONagPDgQTwM6s0bqn99DJ\";\n        sout << \"CEVWRIrkCH9o44FsWgF/gZEcEwFbZifnkjRSbiYPRn+euaJrvU8t+x86gbdywBJg/NdAPdn7gmyR\";\n        sout << \"V0mxYX035zo6xzjvYlOVP8cDewPK76P5sFFM/00tE134eK0jCmw2uMJ+AX2mEm3RhtmUdShzk8Y1\";\n        sout << \"lVbWyEn8VGdiZmsaB9SbeWAX4vj763YnH8pogS5AfRtR7+Z/B8dB7wBowpfs0Kvtm6LzPAqpyUYI\";\n        sout << \"OqvwEK1/f+fwq70lm3K0jFwda0ycYlBWhmGhpuFWYh60ictb+b19JLmdT59NrIme9aHqB8+SrEnN\";\n        sout << \"C5eh/Ee6eAU7fcsai415NdkTphEqSj/0IJNNqpoAm6WYXyNcFeXDma7VCa/6mXZFTHi18+qWqdYa\";\n        sout << \"FjFmYunmwGz5eEXqWwZrN0RQlZLzGTjAkNuVnrDhUqfPtTQ3Jg9Q/g514VBc/e1f4tcmY4lBDeGZ\";\n        sout << \"yAfWnvwG76t3EfpMmnfgTyHXf+cf2g6OUsha7eTpLNh6DUT6TBPtMElNMOWMDlCRrNUAvUGaiDCk\";\n        sout << \"dkZ0LcNkPZmrS9YTvzVVXU/DfKQk2Lc4kJw08UoAFRTXRPA3reX47HbrXeo7bU4PAhA6Flkzays6\";\n        sout << \"NWx7RVOmdSvo0Jc0Ec2rzSfShigqkmjXo/CSxvmuemnMZaBJb6o+R3iVOdMpCsw5+PwCtlG9ghH+\";\n        sout << \"egfrWDE2MA4hENDmgbONs1XrTLrEWl26avRL15OcLNfjb4Q85Db+r+8Q8ApGlnw3Sk76VrAoqY5W\";\n        sout << \"RIsD0jH/CD5VBtJnFNU+qFtYVNp3kBNKcNTP9RDpi9BxY0qZuEcRGtfGJMIAtqrjo9STIe7RxdfE\";\n        sout << \"wy30LUHKaHZSURLZgUYeY5h+OTOYDpTMjwm+xT9r2GyOOQSmNL+2QVXyrBq7BxtbTwDUOd+a/9SU\";\n        sout << \"rCqZfwqmA6OrPbLHkRkQHYJmtsR9k/+C3R4bSl28PQDEf4jfiA2ztVZ3Ot3FLHooVKF5Vk8kIVsp\";\n        sout << \"ZnbVJA52R4CLnmUyLsqqwDaUJYVfiOQ3zuqR8lDzhNDKYuTzkS2g+X9b91wF58wA+Mg/PyhUpWFs\";\n        sout << \"iYsELBbYlTW6eZYdDsIlI2x7khrgJuralZPQpwt2+3cg4NThKyKTpCIDQee6stuiUXqh1NKE4F/k\";\n        sout << \"U2M6WifViFrXuKqIChGe9DSraR3UfTyjDm4l3uGX6oE2MWXRyigPCfkHCqunq34357V0Bds/Q341\";\n        sout << \"hA6uDgedbPjXqPj5MF7/bZUHvqnnwD22WkGXfzgCpGAwN+WOWFxUZL2adBjJoEC7hYwx+umcXQZa\";\n        sout << \"H+p04+MqMvyzyfnI8d20mZQaZef/nY6vdNy5rXna6ZyFJnKR757m/OUaL9wrvO5Wlk0nzhQYnexX\";\n        sout << \"KyOvQYBbd4Hu5tWQ518f2RtMZzm7ReM7Xr78leb7GVB0claKWD+7ptwWwFVn7eiphI0rnxmSY7Fm\";\n        sout << \"BABTROBL//vZp3c2VqmpdZbhgeSyWEvyZ8KUheldonXlpbm0OahvTVNZHafDX2aUph5zYHSzT8YE\";\n        sout << \"cvm85ivZA1XdQfLkQot0Y3H6rQKiW89VE3qNoU2IReWEYZYbTk2FHIgIEicG9LECWuoPaHMLf+tr\";\n        sout << \"8dwW4q37Bz4IpwhsPrlBmXDdlPJnWDvq/C5AWpDkgr5JEg2E1CL2QA0YsUqLMt3ogOyqhr8jvAFI\";\n        sout << \"mWgYRweFTHjCMSbsRHRKr/WRRljRHqIs4sV1X7wzsXXR9V0GwYnkwHWu7SekTSivJHoedUspgymz\";\n        sout << \"Xk/OkmO3hJlvow4lyNXI/QsF4ObXSF5xvUuUtNHy4EF54IRqc1chr8E073MVyHdYbK/LYDoHJ1Kn\";\n        sout << \"wx+A4+BWLmeVS5weTfUHronUZlRIv1YgrSzw8M3Uxf3tA9+Vi9Pzu29X2IeNt7DbiZzGzMZWkgeD\";\n        sout << \"ye0enuQfIDcZ/AV+5B2mG6uxjLnMFp3S5HxSQEfbCwyvpxHEwImq2NR+9/J4UcxXNsqe2k92Wz8H\";\n        sout << \"jPlROh4/lFbmzxE2kT49ro3ewacP+bvpRpWyXpuVQo/oMQ0NuljpBtIoig4csJHhp/cREvXVsp2O\";\n        sout << \"q3nF/kxgs6BrfptKS6RE5R+gz1s9WNJ0yJk2QkurEWQReloMW/w0ktcfENcFevr/HkOtTr28gP1i\";\n        sout << \"vMleP2QxZrdNad2iBLdpJRs9SH663kVa67RTfBczDeXTqQiFtCpI16Dr7GZWnBoYtT8d2AXtCsNQ\";\n        sout << \"wUfRuiVc23aXnOkgD5PtRmcp7WvBDczaGtBBmTbKSy4DhlWol+B8kUcajMRGnrKDC6j1a5mYtWkK\";\n        sout << \"XzGrqT7Bsg0Tffj61OjYU6nCDLPm2Mm2XLHmhf8Ud3WJWANjsiWQKFTNH7eZUhzL3XhK/Iet+dPk\";\n        sout << \"Y1h1o4tGWeZPgFm9lLIhXuT/SkLR+XAGNNgrbAMGSlyTP6d2EPn5WvAL8Txt+1EaMITteGO0uKwM\";\n        sout << \"X+vpdPJC8cocJroQOethNqV+vK7brbtz7NZsdgFov5VYoLNWpwQLigIcaDxORQBC5yMh1ygeDQjD\";\n        sout << \"exiUJVF6Y0blMVyLqBz5OwIO1ftDAxeirjE5CIwSAs/E/CslH8dTJAL6hmTJ5Ncw70pf0NvzXkJz\";\n        sout << \"GUFSaWzRNyrpqFh7vtXVSqy/YAPOmvbU6TxUR8I/1O5afmTKkETJQP90BiuzjYs1N84IYoVt17YD\";\n        sout << \"xPWkQWH4LxwDdA51WSGCIwE/svX3BMYH/0TB8EMdL3FwVpNMgjCVW4srZP0KShXr6oJ18/RVSe8e\";\n        sout << \"Ls5HmsOL5vbvGarpKLvt0IXmveJx1Lr7h+9FAOG/n0HHD9S3Ug1JrgweszosdeIho7KDV0tGCEZR\";\n        sout << \"lLtI0p0KkoNEc6Hcm7VZyMOx6d4aN12NuVL3l6DFtd4SCFwBrIgqyDIf6ZAb4xeH2RckVs/uTBQo\";\n        sout << \"tNCZQKMaxcgc3Eee/IOjDVzFhjW4lo33FHhTrzYzvCISWREM4eDr4/ce+UZ6E00IsClZI2h2HkiO\";\n        sout << \"3k6ydBh51dHWHf5CZPp6gU218nIU7usc+XttaZpsodclSmh+LpXGroacfKyUGTB+I7lf+yzzBrmk\";\n        sout << \"Eo+WFBgemz3Rbcyem+zZaRS8YXKi4NlUX5lS3heqA2ogFwFDbQJB42FBCEMi3WVr33GELllqWSqw\";\n        sout << \"FZPBsn6RrIcIwI0/ehYLjO01/iOmI2Z+YAg/DRuxYDI/eV49z/xv0fCU2Xs3vYv8q7ZH3fjwyusW\";\n        sout << \"R7lKhO5nksDaJ1OS3bf0u237OCQYoc7dB/BkC9BHX2eo2Ou4x3pKBn5HQnldPNqA8Om/tdCgQeVx\";\n        sout << \"izQq9KJefumUdCmn4ChiVdPs7SK1DfhBnyL2xVHck9bC4fb3MuWZYL2XgwMwQ4OOOtUY+/sX8z/U\";\n        sout << \"O1EM/l936v45oXW1LJJYQtIhBf/rlqxqc/3l2YtHR7Sa40RknaaukggYYQJB2PJqXNBs3kI3FwIO\";\n        sout << \"z1mMafTy12d1ROBlqBee7AF5QJ25fCM90GgxqRwuF8yrGyXwv9pbnqmLBC6tz5DjQcYWpwm6qric\";\n        sout << \"pQu/xFI6RKtMM+tq+ETci06pbHQIcQaTvvW6iX5tEJ1iMFJaCueVEx7Q0MOgNhux+338+BEe7Gwq\";\n        sout << \"5g8xr553nO6KTDIrcTAgkRnQIL29WN3AOoFl5JWtP4uo1/cKqKpN3JcAIW9yQTjKtVOfSvZgSRxg\";\n        sout << \"Eir9UhU9SgMrM0/cdNLZed3+P8U6AYn5LxZDNWIlFzmxCBRh0SuJJ+yXtPkqApgvzso7d60FhUPa\";\n        sout << \"H0LYx+zhjx7jPhABHXhu3lY5uzsMcRnndIEOx5+N27vFUwxJC+KmgOi31g6XcPIBqwaWV5YxdVf3\";\n        sout << \"7cYOF9FYgRaCwiE0OKGADJJA6mbTYv7s4tzcPtHEyg3XK4UuT3lJjaxjsl/VLXbWW3JKKXwOuYGQ\";\n        sout << \"w7ExwYxyfm0tbXgwlK5nctw7Xg9U5CJA09jh2RXOQku+PmwbtseSP1HbWFC0pOskZatQneNQ6jd7\";\n        sout << \"kcYZ49MxSI5q5+rZuEOke5NytoWvPIeCFsKMUC9HqsRPivSrczNf51yX0fIuSTXts/ch5fakqj8f\";\n        sout << \"cA3Ln8e3wASkQo6qtG3PP2tAyEOP3qj39DAZT9/a7e5m49vjCx+ui8Kq7tj5ehGuKhrteERJ02q2\";\n        sout << \"ObOq3gYffJ4LDddCB1HQlrK1vV0ZSDctR4QZbEhD5PC0ToKsarT+FKHCDN2GngDIh7zSmEkq1YHk\";\n        sout << \"VXzD3V406Uij54UzOXv+6riqiv139xC8jo5TntvqR7S7/CNQu7D2ix+l+WMlUbFWy3PT6pL+Al2g\";\n        sout << \"ydAx24ZbJ3PQLivg44d64nA87Ii+eDsrJNIFt7jitB7w8tDfpJRsCyGWDOkA81Y6Us8udhe5KDUR\";\n        sout << \"7jekzGrKuX5VfUGAQi5+Vmk9W4d6C8U9Ma/D4wHIWkU+M0ffMVEgJjETYNMDyefi1gcCwh+OMCgC\";\n        sout << \"wbPlRBhdqaUMFlMBv7ysGeYJUQ6VoDw/TFcNtDMZV7G5mMwtsMhfJQV32hxLDhscF8nsafoeWIhU\";\n        sout << \"9aoihwKib0H9EvT2gg3KyvAIwNM/EjpninJXaaMNGbEFJ/7gEAZ2W/jAJ/eGmkLjYvv7Hh2oAkYn\";\n        sout << \"5UOk7TabvEFSsoCdeTjR4YjQS18zZcz3Ta7ffCgp2htZaAyJwVeHbBBL6KoJAlsgKi1yVtP8HXY/\";\n        sout << \"lpulZcwuaKXjQJVcHS/RcgZsaam9WxNbYh+X/CBouHSoZ2/LbtimWXb0WbQE3xk2Ntq3j7FJArKl\";\n        sout << \"gLGaykVfPzTfXFPKF6BduSPmxLCmgLgeZU2rIYBC0UXMVtEtizbU/4MF/Qo+0jjbO2BZGb/6tyea\";\n        sout << \"PRE/tXWyjGHkcx2T0ZUYTTpPtWI4MQN2LxopbcmDkZszXvxH9MlWC1jkhv2xBnddamb3jc1d4qmP\";\n        sout << \"YetgmnmQzoozyXiu95T4s6V+H6gNZVhle4+QmwxOe+zNzZaLhn9GBiwfLDGfBqc2usa2FvFWpqke\";\n        sout << \"PGE7LZ5HN+A4XFJ7NrEva9PtoPUOCM3FU9gyGdzKUyyW2ilrPX6rAil7+ZF6KDAVYOmnQQCtp5Ls\";\n        sout << \"P8t9MlqGMM5uwELErplaidbu2fNVTXvySFbZkga6AYWWV+xQfekzRYoN3LSs+Y0OuUU86RBqyOe3\";\n        sout << \"+5F9fvPztVD8Zc/c1jfY7/3lgJMtgEO/+TDa+gDQAZoalgf/SGpvv66MuiABp8LALajU0a2k1DYT\";\n        sout << \"otIdBHlVLj/JKD2tfHDi0FevTo3l2N2do9NEx2tyMGoLQwuJplvP40vHr3aII9Acuim4GEqh8cXT\";\n        sout << \"XWT5KzFF5L8f+QK27m4lgotZVF1ujXVuQRT+CHFwv5LTiwHaZ/KFgVVY3gIkjCRoP0XRARMk5oIh\";\n        sout << \"F7G9FnoQM7oV8f2b4mTKVvqMMv3uWzd4zr0Tx7GTSgL5YfcJox9my7ibHgpBpBNtej8uX6MtzHXT\";\n        sout << \"SbBoG3lDrdZ4fhMx8d9+/oACjVThf3PPa0exxvme5s6T3GaTnZt2BgzLrSknMaRZ1Rx2/kT/1ecn\";\n        sout << \"GALfb5irpfKmQPLdGJv8EIAB/Br50DqHGC7DfCtZ1BshNTwgY77mI9cus0SGrgmPRXYuuEUVhFHf\";\n        sout << \"OfrUwDNX/L8+ztdvlgJ4NnE5tUnegEz0ApOyZWywtxDodl3AZoZfBV5ODhoHNsCyZCqD/HYZXHb+\";\n        sout << \"u3ZJ2PB7wcBbxSCf3mLSo8Kknq1d87o9YAQdyyNR0s2XvQO9IakDz3HfBFugDO0LQn0ewgxAFhMs\";\n        sout << \"O6hA4M0Q9NS3X+Dr/Roy7wn51BkJhrLvh9TSO0+VCa1EBxo3mI5vM0m+Aji9HwySVBcd9L5FcNIm\";\n        sout << \"PTCkaKyAd3DsqBIoHFhdLhauODisNzUFC32TZiz6VxSwxFnNvyrRQUDidLEwWWcp8Kmm//Q4nq1f\";\n        sout << \"F2Qq30IqkLC9nObGbVSjZb+n+EwqMlE8mJxqbgkh5TQ94V+zQY1ykiRa5a98cFA5MLazMniE0JXv\";\n        sout << \"YqUtmkvvbyFjbAZ+/RPUqG3eQxyvWxBSQSC/zpbG8rJ58ZUzuPkmmXe2z3PIzFpb2BMVi7U9t8Kh\";\n        sout << \"+ywyagKP5gLgUTqOS6Sz6p30dvtDsayhngpRtVfmOoJ+Px1iw8f+3o+JEdJGnXEcecaGIzABCOST\";\n        sout << \"mEC/TQQ5ecV4yEwN/cN695Nu76+cSiHR+7UyWNSVV1A9WJhsaW6NJl/YY7dZDlMYWCtlB8kUCfWr\";\n        sout << \"4bhrudo8xW5XeM1EtmmpONd8HeMN0479Y0KqMHYCnxYz+UnC7XZBJkweyFPa6TroZoqjaIZMEyRm\";\n        sout << \"YizuyvyaX1eYGM3Q58/qti2hIgrRovGl8VYnJWJbaU41OB2CY+R/TsuQo4EcqfvAUCgNxZwwmvkG\";\n        sout << \"brIAJ5+fOVfI4Fa6swJ2PulbJBXXS+fCrjCEvBAqg2j4GxupCDk92IF6cUH0dgmx1TBFgRTNDfzf\";\n        sout << \"ENcymno2Q8HKz6uvMenEfNDAsmV+giNq1jIY6gm09kMwtDk2hs1c0hqFuno7pOrkS1RFbd8onyGC\";\n        sout << \"qoN7GtGpMk6q82mLqrEc4chaIOF5UpPSH3sRa8tbiP44q8ItnbXnMlzox3ZhZqJN6QgrNWnQa3wD\";\n        sout << \"4qp2gUxGkFE4i242i/9xzvfYu8h461f7e3Es8rW0sB5PZ+FQ8SImlpE5vh+Q1qhXoNof+I0fGGb7\";\n        sout << \"fbTZmz4ZZrhCS6KgP6HBmbohfPXCKubfc8Q+F9PCaAN31Fp9ycTV8FAfXySbQzdShgnnhnddJl/T\";\n        sout << \"Vhx2PFPythxz7GEv62hwjLuZdxZq3nCykVHZ/yTE5yoLBaYUvsVVZn9rv1YD5+oSYeJZTbjR6Hif\";\n        sout << \"t7geARjzf6oe85YZdQvODK9SMHYo/QwdcPwwnSf4Dtmvvg5XnSG41s16X0n7o7g5ZgFr+HTLwMzR\";\n        sout << \"k1Zk3offnOMpkcpEXvM8OhFvFiXoN91CoCvin7f2gX7IWrNv0mSj92fbKzQ9Qa7N5cH1pldFuDcA\";\n        sout << \"kQ9wHFmz+rrnzgEl03Br7NqKsB6koxE5YEzHkNLHmg+pTOyu+yDREbopMHBi+jTUReVS+5fKFMLY\";\n        sout << \"LEB6T96s1i+ygPVSt/4H/DQsU+0caW2dCfrm0onr04auJcU+oBYjbR3OlM+6SD9UaUjt2PtNEQ8j\";\n        sout << \"fZocgKhSxt855hYm0y5qvfBLoDaADhziF6Exuh7YM/G6ywKMi04Ab7qecuut0c2bWHXYrQPhmmCE\";\n        sout << \"NXCiCX64ZIGfsFR1pf8eCChyiA/GW+rQvxv23bl1RxbDFk2ZO9o5581NjEPjQKJ8AyE57W0bZjol\";\n        sout << \"8s4S1ZNwMF46UgZEJwCPLuqJEJvZyLBwahHwC1B7dgoDdZ4hjaJdH+jYEZusfsvV8ZC7hS5e8V6U\";\n        sout << \"rkOARJZwmYES8JJlVtfbfpCqBXZ0gTPuBKt2yYIlGTqGwGu+biiNMVt3spu2Ov6MlVoxY37UZax8\";\n        sout << \"B0Bl1cbrqIBC3LN3uWsmnR99chFqEmhi1cRQR7+3DtD9gpkt1Uo0STq0YCgbVmr4azLoJ3kcEdRa\";\n        sout << \"cfZ4LQ+7zlFTAqOhh/kBPsL51ZLQ83ipFUgz+c1f71aM0eCFharOyhIPy6YAAPHpm0FdMv9Q53V2\";\n        sout << \"p7flk/h/s2eqe6M2jbtud3bxxUdercWJvaioQZWMkNSXcP4jKaRN88np7Xc44pjUnPgO+AYc3Kl0\";\n        sout << \"2DXf19IXDjAegihkFzqvAKV4zttcsT5gi8wN3M+zdoG1TcnG5gJfXumw+Bu5giUudQ9P0mUZPc4t\";\n        sout << \"vMWo3r7ajnqeiUaN3PZaItRimu7vzun5+qOEIT5nxHNDuwKVN8ZTigvOrFRUxYkyzoUzUsOPUdla\";\n        sout << \"nE3MUbT1bj2cs6ih5jqtbqgutSNQSGupC8Xve/W8tiQcrfRPBMdtvJIp6Iz+Z7g/SXpunCoFaBSa\";\n        sout << \"mAuCHeTbUrCQ5xbQ5k8G5qIYRglHRADsWO/oM+vWtc1jEEBZ9UwLdFZxIdj1ytNnTwIZWstliRQw\";\n        sout << \"hwNPyxfJQwng2WNJFG9LPvzxxnpCwYG4Fk75wPd05j14gLMcERPyWpwYurfqeQG673BTCuBeF/DV\";\n        sout << \"zZHI0nIV9CLhSSbuo46Vkb1+FaZwwpsD5sBg4+EwKcglHUzrqiskq83hIryVcvSKRNdb2R8VDLCa\";\n        sout << \"pPblCQx811bg68OJ9UHqbw8FPcSu8M5zbahisVzxszdjmyZ7fqWR1twCBsJu+kLjNEsgC1cmC1ca\";\n        sout << \"OLyaDYs0sad92UjkYqqBQijASoQgafhSPuJ7sEoXvLXrPP9GWb1DV6S6mD1ZBRicwlo7pWb6LREQ\";\n        sout << \"HFXvVkX4/seCn3O76cNuqenVr3EtIOhKC+lKDCBbnKZ2ggyoIqgO5BIteeFcs5rz4yuQRM+lB7gT\";\n        sout << \"Nvdwa7iYLDOsYOrtBpNMD5KO95LQw6m/Okd9RKQ9yKTcV3jQFGfAlYcvXt3g7tfz7Zyj8ED/thPO\";\n        sout << \"pcrsgQE1E99T07ozCCDNRaPc+DhgHyyIEHNNxmgGUWziRBKqhsnei3nPCg123K00ifq005MgO5wF\";\n        sout << \"oHUXDMjbWBF+ELX8MWGaMh+a5OWq50xs6wPw1WhPug4vnEJa1j1rJxeGRSa3SsELXmeY2QoAX/9b\";\n        sout << \"S8HeDJq2O9OdVy8bMKdfxxvxL+Q/5m35EGdExoccnU+LcpGc1fIKqLfJn5oKPS6BlNKZnMpkyV+8\";\n        sout << \"z6VQA7zKvYP/Coj8NSmZkBJm4SoUkTBt0hZ9KEXEAAzR7Xf7BzR710lXcFdRCYWxz4KEjsu8z1e6\";\n        sout << \"NcjhBpcgvFTnowMThMLtaWotUJ4KnGU2ys5wMNh9E94+pZNkEQ8xShAEt9le6/gSLLuXpssWJIZE\";\n        sout << \"JR6PlTgQtFoSwYfx4+/iqbMVtbH7f6tBpLbnrIzQXRUY07Uw13p7kblM28k91GxRDqbu0FR3cWnI\";\n        sout << \"nTZBplbiYcOM/SlFJFfThLbgAtTO0RWgJkSr0n0n4duBka7ZzfUiMXjyAHvBAQTGkHIb+YidnC0w\";\n        sout << \"eY86YsFjo3jTqJpLYuciQLJ/ZUI1g9v681JJVICEw4CxgguvGJJNOgQDh2CEZI3AGLlbm81ftzRs\";\n        sout << \"MpKPE/RoI5kzoo43tcr3WCUImlVdrNak6K4gaNXH4J8aui6MN3kmZ0LWS0l/7Of/bVs56dEOozSm\";\n        sout << \"PcGfVLmvLExSbXU90kmknOftcUcTG6J9r1S6PR6qaF2w/G1t3wx4mdberrM9hOIMoXQhXEFShNHn\";\n        sout << \"uZ/DLE6t4Dl1pvD707gtoY6UpHpv9oV5xVVPVnq7smExwf3gQsuiHnDDGrPlz+DmLnkZ1XYCaKSf\";\n        sout << \"EQleJCCuZApUfEl9F0EjFjSDBgPoPpwQ4mhDXFjhYjYhdWmOfANCDsfXm2PUoBm4JJNI5tV6fa1+\";\n        sout << \"S+yaFaIw3TiqWvaOGIA0GyicfP4SaHodizLUVo+yfYJhycZrWqclh3OkuT2SVndIDLs+8Xc2oSBY\";\n        sout << \"uJr8P3Rm+Du02X7X3D94XvNI+tl22SU9CMMfG5E2kReYpkvtVsejWaeg7QKil8gyRLtkH1kIb4Bl\";\n        sout << \"Nu1oeg25ufTr+pyX5nqCNqeStAsIMH6ynVRecIVr0R+AF0+winGiFVVoeedIQzWc2pe1nD1F8LwD\";\n        sout << \"H1NTNdcm8ukf6AA3O4pl1uvLPIZIwC3Qk+AW3u/Xwhjq6AxEpkCGoLrUztB4Xj+uzoBpQ2ka3Lu8\";\n        sout << \"K5XooiNcanVGjWC+0/IBmB9gioabhNXit99vFEdTQCsZzlDY8D9le1IZ5lXIGgSZR5LMPOAzSaTA\";\n        sout << \"b7vXFps/tixvj3n9wxtOTAMREIVaGkJgunwSNST9lQ3tcveAJWnowLztcn861ystgFGuDgW65xgF\";\n        sout << \"Fo1EHK/Sq38jEw9frNatPCJK3eIJRih53VdvB9A+viAX9IoSK+KH70Jo25Bcrv1c+6Gr2H/Rhv4o\";\n        sout << \"quxm7d9XpPAA5dGZb20fFloxerWOvWO+QHghXZjyD81o/1hhR6ZkOiK0trPkvDLcLOfPl++YIjPP\";\n        sout << \"vI1hZ7uTmn6qlN20FCN6P5H2YVJBnhSZrKx8gFkULKgXdT5SpVSR194vK5cwoOUY0V5b4EdSAkWa\";\n        sout << \"3cQm6ibiokDAktBSDS8vpitwP0sLI5K/7QfLuXjihWXONCSf+RobFWqWPXzYW51q43+MP7xb0gbM\";\n        sout << \"39I93rn8s5XNNwVdO/IXzd/HmMHiElOr6xEHMzCUErUuQQQ59NbJ/N/iVuv2c4JZ7ppFWcz1ZQRz\";\n        sout << \"dgtOzq49kBMIxksFoFuEWuRV8LEqBbNBQkW2zFNNWpV59mqwpikzNsraFEvUPBUJKz5JNSuXVLF5\";\n        sout << \"vq+hYqVmhd3UC5RU50BWbQgMgRm1Bw98ScOPxfMMqBFPiMntTDcd2UuFptT066sbXg8slg/itSSO\";\n        sout << \"/CQmixHP0Km3Lz7K5OqVdIr8GYAeP1M3pjxZCEsaLGF8YGrPnIjMyjyFxFhyteYsgU6330hc0TGN\";\n        sout << \"LKJw1F8lbEyGt5lujwnumUFn4Wdg+gtd91ewchV+uCkT8Atrrd5gvCc2AEWxRceQHrUTuW+u6UCf\";\n        sout << \"LZvF/BC/8PJszVQsoy6dHruw4E7UwlX+TCUvP3G/wMeDf9SBsgnn/KsRr0aQmzuIJpWNNULXGyXZ\";\n        sout << \"0OHSxs3fJYq/X1FB2EgjJMXrAczU6aKHAj1AbCUbBIaJcB2umY4YAQqt4x2q/iOJDbJ+k3K28+Ry\";\n        sout << \"vW5w7JdiinwwjNpQkF5OO+4bQ+rqPzJare1PT1eBn5OxRpVlZYpn6AZIt6/La8Ir2iWtAdUu9Krm\";\n        sout << \"9F4qrhoykAlcXnI2GZi+U3I5ftBgWfDVodX8hxzyS5Soo2LFCwmG4aYayxu+RigV4YRyuXdHe3vD\";\n        sout << \"L6Vs2qmyKQ4JE+IbtJQq9jkC2PrFMwfP3nOstccqgnlGMrKMmN/UX2R0emMXsImuMGTn+rKctWJn\";\n        sout << \"sXIysVIEupHUUD4qC1RuZGvdGk/LsV7mQO4SkPJWD1JjUADB+8Cw2nkMVCxn8gFTf1JU+ovxgHl6\";\n        sout << \"nMrlYnN46eRJSFIFvZP0S0gZf18aJaxkgZt/YPxm7m8ZT6NLqLE54+st+e+sWHlP+9VeqA5u4aLh\";\n        sout << \"XEJGaJozsDZxkNfKN9lGMkacM7LZzR3lhjX1o7cjZ9D5l4m40M7DS8sbMg0/5wXn3WxlPimZFLvC\";\n        sout << \"IBLsEAoUM+oWB1xRq58SAPIAgic3jETi8vYhDR3vlN8ubWsXyTqOJKIXJ8O9Tz+aKkgLq1P/1y21\";\n        sout << \"Py1VM0VW3XRnnzs1mN1NLO0A9Ot7NMluCUEJekVYi3jrhhLRG/tGYkLUiYcUq3ozoUZjBI3nX+g3\";\n        sout << \"4d9uDIXJT7GH+ovsh1q5Rw7H9bijVF/qT2TNJH0DoI25kuplXnihc1+PAMp9XseXwA3lPZhxMVLU\";\n        sout << \"ftPlCMbdP/LUPrfoq2MaAQ9oKokaK99YSEumcKzgcNyx6wUrB7ILTO3zqFDPsxTO6pxaPgOXC+yM\";\n        sout << \"mLm+LXoEFMsByb+F8xXsrtCFDwNBR8XU92UgjMQLbvymvFE/fEeYMwOd5VOPcPeOwPs8Jwn6K1TK\";\n        sout << \"Gl/QNu8NQOgVK9rIISGbRdpmcLRW7JY4sp84q8CHBaZ+uVRBYzdFDw8VokNyWestrK06wQG7UOMa\";\n        sout << \"AZGqcttVsN0aePOk13IfTG1llEL2fczoNioOpCaVqzzUSU4wA0QBOa33h1VHOY2Py3x7PWI2QIJt\";\n        sout << \"v1IJSEmnpKgVzYjSnpt7kUlB2dYv7w3qwDeiE47NuK4ywMZAUuONlL/ZMpR3+I/EIu3VJRo0RknW\";\n        sout << \"jKkYUjOdo0FrGhQWjuISkZB8prJxAFrTDxI4aiHSnfMB0q+L2LJU8LMLLI3Ok2NIxWmdIJaFKckH\";\n        sout << \"f3JUFpn784RDpdHlIUU5EOzfqal9flGrMlz03gMrvUiq+9ZtJR44EXoUwLLdAWN+FO8a9Rrj3PUw\";\n        sout << \"E9q2KZ9M6BqLc/YdZFHlpZYOiIlE5x34OqkVqcQOmlWmPVP4bSwbXwmk6oWjruRxmaA2YQ/sLIHm\";\n        sout << \"XBZZQdMe+i8TqEjte84I5EebJRi0oiAzTFUlf89NWonCzSnzdFQPOiB6Ik6dX8o4607SkyijR81F\";\n        sout << \"5ZiusAkWNx6zksMfeZzCxnS93TqiOSmFVrbxMx6BkArmc1IWPCFu0OAQYC2af0KciOEndo00R0xf\";\n        sout << \"wQAtJyKyfM68kaHebkMhRWDwk9HEwznfn52y6evH3n7NnDttgw8PnphD4/l19wWJdZ2l4tcmY4eX\";\n        sout << \"ly2zjWCcaIsx4QMz1gEGc7lvMq0J6RbzsoH4oa6Zdu6kaCN0Fy246vkDDBaW4n/fZt+RvT9YbiqO\";\n        sout << \"fzMs1dcXd9mCOz2yB0/i+XzzG7awbdiR7bafVk+7/8H4y3qVyfGrhilzYSP7qEjF0ossijkvU1bo\";\n        sout << \"OblpwSw4RLL1npCLQDtXh5ugQGcsEesLEBq2uFpxPTSLKWgqTr3P/XL+EwNJgkWDIXdMgG0Ft52X\";\n        sout << \"bNQpevk0mqynVmh3HiVnAZ/mUaRXZG40kqcfQzxtH1gvf41S71sDXT+EOQDdwxygNV9BhOfyA4eO\";\n        sout << \"gNeFlhuCPE3cAzKDUrE3ITYl1++4JIpP3BAcsT03GlBlSL4N1nXi8YuTCliEmN3TRF6FLJ5DkSN6\";\n        sout << \"tCk/xGsBkaZlQXjj2P4FV/BdS//Uqh6EBRnRMoRH7LgLl0QJxJrj9RxDdRwW91fNOAJjg53IIBX/\";\n        sout << \"XCsZr09+jke+Ci0r1NWHRhmF6qNY27CVKs3Wub6dYS/GifyrN++qpK4aTOLkkXQv5v6Zhs48qFAZ\";\n        sout << \"4XORp6I1s7vCQ/yU6R4UeBNoRAT4naUFGc3gvmszzFb0Cp+li0RM9wgW25miE5Y1PMpne0nBvV8a\";\n        sout << \"k1RYRJA1ZyOEQbmFxLMqanwITgwxZT7tK+nSITSmHAo7/m9IaopgYOumkPGdy/KsrjkR2gTq0XxL\";\n        sout << \"OSjhTS/sOrZhSV0HJ4pBgjZMIAlEwv6k9XsefXyREo+rudBS9CiXW6TzIViAWCMc/hQo5zo5tUeA\";\n        sout << \"vmTrWxkRgUmdsj6FGS21aQFPADj3oPrAXsTiH1ZcwpyzJrT42+4P/SLFw/h0NBYRozI01AVVaxQ8\";\n        sout << \"sbJ8VUFliiZnB++Mh46aAF1PzomK1NiHC7n+llPAdEqpqiWqVH5YK7CpKdmCPnTUuOb4a7A2Ylow\";\n        sout << \"rodSKCOX4VHwxzARShJxnQz+FIfVIzpiCFs9ZJKM6x89ybXTKVRrmwTbTAXRbihUKa9d6t1vmoDP\";\n        sout << \"07z8WyFDoeWoSmK4XZfegZeZMIXF3hrDPCYcZEluxujpPG3ZPPw+/pGjBOx3/QFJTQdeHBz/PQ/G\";\n        sout << \"wM7DkD3NM3fVApST0LbPQFKxlEXx9tCL3GBul7YnnUmF+N3OIs8vDoJQqNqVi5ZQnGt2uFLOYRo/\";\n        sout << \"67XsBQv/ZwYNC88VlJykWEbbVDN3rY6i1JLr/9WRygS6aqF2JJBTgLwXpjfvaq7Ygttm3WiT/dxj\";\n        sout << \"QtLg9L/y3Q+LoLOKZ5syIdk1+oQhYnSqUgTNEuw4dcTXj3v2lHm5oxzst2dtierbluemr//Bnclq\";\n        sout << \"8FdWTT2JC9N/YI+CZi6K1lz1Bq2yblxL+BC9UE3rtsq81Rm8kJxSIVQ9HsS2ligaxnEfCIPNvMhV\";\n        sout << \"orLVKxoWuOfhJt++IepP8kap2JZtLdmdZSr9/6suSkInlANS9SkwaNWB+EiTUm5cfu7s90V+m4J2\";\n        sout << \"SEiAMESJKLywmeQi/JcV+8lEiThyYTxhm5huK2dUGPWnzKK0HsdOuqRs0RnHn8SQIgLndjyTzcV9\";\n        sout << \"2mpVtjcwCRKVBFiPdyeqyVI1j7srk8WrRc0GozuUkSBMVk5KHQa3/qZqiV1w9KN7eMRaYiT46bP4\";\n        sout << \"2dpdvqNrms7/qmyv0q+Bxp7JYv8bYqlQPaXgHxS78I7HqFsLvP4kZVWxmhCXIoIObX304w3KRWH3\";\n        sout << \"WlQEj/llet0DPOhF6EPfcuMeSvH1UhucSS2pnYwo/P0BvMYvj6gcbjTowWMk3vmjiZV6a1xq0Nm3\";\n        sout << \"sgrrS/RqYJeGPM6THw80LulT4e0aflcyFN3QQ+C01vGHjpaw0OwIW/iWAMQolVwcZznJPq+6Aya/\";\n        sout << \"aYbiphirZC6fZtUMIXiKRrUxQDyfgI0y8XzJgf28AxgdyCP9Dashm9uelYMGU0Jglf/iwa2K1pkL\";\n        sout << \"FTS7zfGJmz66x2+7agbLuCHd7AQhZb/rfOwauykZXpCE9ooLMLgW+BlKpqgVynLrt+b0I3KqQZy9\";\n        sout << \"KkFxFwC9cumQJPtKGKUigDLV6+orLNwgtVmNal9RFHppuj95RWG3XgwNLLGoE+K5TiLhLY1na4AF\";\n        sout << \"1NXsHL3pFjM2VHEU6cOqVLqhEWwGhrmBoxIGrbmT//lUiGwSLcmDHCvv3Qig43HbRmuQWW90qFzc\";\n        sout << \"Sp7atxofyP8SqmW2aRw2SRH/nvCTTpKw4s9bhDEWCukZKo+bpfp1ti0P4DzSiUxTy9uSjWs3+7Cf\";\n        sout << \"nWsTsoUxU+YdC6rDJYq2TAcn3Zl6YBU9XZl3YLckRqpUGUQ0IkF0Fc0bb5kQCJH8h9qc0Olnqa6s\";\n        sout << \"sjHyjTwkzZWFmuvJPfxEZzsZZFu9qWdk/Pzx/46e3J7/VaQhtyYidoCdV+wtN9IOuxnbyIV0A+vx\";\n        sout << \"ZAjS2f7y5aPxzc2XAmlsmNLBqrRfMm9dvxN+gYVD3UcWgzTVxfIXRyZqmdAvuHoTq7BV8FYPMIqb\";\n        sout << \"SKpCcdEztosRjzsCxioB0JPCGxMhHgPU4FCNBy24fa5RIz3rZkR7xFdTNw4LTkJ15BRKMsBxHaiS\";\n        sout << \"E30FSLCvFvBVlUITI7aOrvc8+2IgX5cXLxHQeqaSTyKm76ioORshYyRkp8K1Ao0hZXCW8rks9fxm\";\n        sout << \"FeRen1ureYGmkoKJUWq92iAPwNsFvvxTm4IprFoUDn4s56Ung85NTvcEJEyc4yVyevqb7hh4axAu\";\n        sout << \"h9N2uFPhx9YPLbOHA9m84PWgt/IPOfdwhlylIL50MZ9qitPPG02an2gjybEvicqckLYZt4cY1Utu\";\n        sout << \"pslZJgCrFZ7ITUBixaxhkuXW1wxwkF8RGosHdfB5zycnXkvXhdV41+QDvhZ1tR2E10jwqjVR/7W+\";\n        sout << \"suB35kUFqrlvWs/bBTQHwwPdNmGiNFi+uq6hIBQCm/J0MbCaYcPPfhtO3LIsd2KeiTz5oV8AqBVu\";\n        sout << \"NPQav6McdWJjg6dBQw4G+raxkUf9Qf9TPQspS2Ll/Kmt8WwbqiRHutPOaxaBBeE8Igx6BT5kIASc\";\n        sout << \"OsAnqIzudE0cclrkxN4aeTglqmwwq/eeZUSOzkv6Ge0xtpYDgqfGbe53fxtYvItYYExMgy5HdojY\";\n        sout << \"1zDaNXsfHTebUUjPnsXitzIQQpRobTCe5ttWhfeeXOvE+MPLRt19KxSrFKHaRlQtjYsmxdg78zc3\";\n        sout << \"8ceNlnoQbh/puSKv+QWnnELfDnmgVZnU7lIKs2xM2B+pNy4Q2YX1wmIqlC53rsTzU/Ik7Db7Z59s\";\n        sout << \"i5QWZ0R1ll6rdkCsUCTkK8aqsF+mSvWNbMd269Nch0fSx1D1q2NN/4lHDDoOX1JjLPMxVNbdxLMt\";\n        sout << \"gP8gpiQrFJWZRmTgYBW+biZPtiKgOztsDrZ+eolNWpsGnLTK9Xe11lZrS2fPton4L4jnr+R5AnHk\";\n        sout << \"F6tBVhSBRHtZdF/xNcCsSOKvTOZJCtftMO6XaKMfsI/yexeLz41D5qfMVSBHY4bIgL3Jgh952tlH\";\n        sout << \"2blbe7lcZxZN2XkUXXaVaX60XDTLgZUbGzqJo0+x/TJIAuCAlGF1XeF52jTY7X1veE63l423NPsf\";\n        sout << \"kCmiRcepJT1ihXQDd/VU37tJfeGZrN8FjJzx53PVp70r7eLJMedMbBUJBYmOofO2F+OU4Rfyab3Q\";\n        sout << \"Wy1ngiJXrfjF1DVqmKNfY79SQWWjlzST97ldjTICsyQdHWn8j+Bof6sL5k/3d/cT/sohhSSl0Bux\";\n        sout << \"GssAFa27VYsJYMjnriFZD13ZYmjuesSXyQ+EkUsHn56MB2xEwLRVEhq8ygDP2eO82PnsIXh+uVFe\";\n        sout << \"0ZQ+eGSiGZtqeL1aoePOA51s2eE4DxGBHWdSNr/7Nc43oUU0P7sV2lut9VmhgDleV+Du8IaZUMIb\";\n        sout << \"2MS/TkvMW5S/ebAoXaL68zmsU32tk3C0FG5oxbdZD1tcZ4yHNJ38HPSx39uOfRG+FrmDqomfs3k9\";\n        sout << \"pu6KaH/Be6Urzd7mr4EvxaXHz58hsJGVH31tOdo1jhg7i+6lCJAuJX01FWfnClLz0mSJnIrcPge4\";\n        sout << \"zQrhghg31+fLZw4FtNmiJJcU/hJPGhUZ5LDJWFHUi04u3+dfP1pYR4e+CEOyvlK2YXx8CHcvjWJ2\";\n        sout << \"kCW8TMN9I5arBUTXdFfOg/v/EH4cw54bmTgzjpn10HlKqfJn/mJPPbBGCCS+pdGmNIzItVME9IES\";\n        sout << \"Gco5a+DT/a/TThfkRVKhJShe7ccCC6uQPdU10P+DV2KPxOfKvar2ww3I+VZ3FKxhC0AcMZBbN0V/\";\n        sout << \"0tTOJVH4GxjH84c9Jr6niQJ/2w4G6tuTcJ2RLb+HnzfingM7J9VOr9C3IfG0jndHCww96Exjjk0j\";\n        sout << \"bE+Aq4H39i5pH3jEvdMspm1B3VY7EN2s+fC5jpmZpA5kRb6Vj+CYCbyEYNicyAJqCHdJLrtHDiGN\";\n        sout << \"fIhpfrkpc4+g5xHHel+nnJKgduqzs5eecM68vOtBTdmLa/nxUz/VBywqWNmmN0v1/g0Jlw3U+IGb\";\n        sout << \"bZOvv2Kg0FO5rJmnRIUsokPkcVxnfz9iyf+l1d2QIBmeR+YeNtLS3XUfIjHvHwSrZ3lJdfXNnnwr\";\n        sout << \"zZcKmHHNAoRLIhM/0ZYQXMbOvfEqUBZ0GCzMdwiEuNwVPtbDkgmcWjYR6ew4YjRZR9alIas8o+qF\";\n        sout << \"GkL+PT4LEHfASjQPnCZIhUISIpwzuf7Ii1I2Fk/v8jBbL47msvPsQcVH8JiFiWBGCBfSB8IfSSw8\";\n        sout << \"sgc4bo2hwHMIES5W+rXXoQMSkGFP6tUfd4GvS+8t60UyDUePQbBGj1lt3ETsinD0btygvMOqDhD6\";\n        sout << \"H+E5gRWBXOV6QrXtQSPG4ZSPlDvATmDdgLCBtQBBMTLMg36Kvia0W+Yyu0bFtFEJre9N/bmyyvRR\";\n        sout << \"P4tHn8uOTi3ry5PT2PQiJ9c9utByvU3ydcBhoIlcdQz0f1Rf8y0eyKj6qt1/OhnzVXuLrkqXLylC\";\n        sout << \"sthAWqyIavUltofLnsAP1uMHZ0pHeX6R1lwpIROxtRH6p/0+//OK4lIZx+7D8aMPIaefQAB6Cf3C\";\n        sout << \"jKnvyCpR3QEh9JLv22OghKwswHT50P/+z2XbyoQsRySXNTUbTsGJuYBazgG10fe6YHQOTrUDUp24\";\n        sout << \"6PS/wEco60z1OF49dVlYak9zGA6kTRndkjWDu49NFhJRY8sBd7TVxeiU34NVyjIDLrLlx7DcuZ6P\";\n        sout << \"1/XcA8czU9m2n6VDgkkAB6eaeL0XhB6XZfOrg9lY6R+xjVYo50Fg9A8AGen5T6+m0PeUr20e3WV1\";\n        sout << \"H4KANYIvY6+zN+Fe6K37VaO+CbDZfvFMzifvzTQWQ3kDDTWX/BLfFgLGZ6QBWrTwF7MNiQ6fCpG9\";\n        sout << \"BAYy9V+QWy4Iz9lqnp19J4Q+cqlIUDBp8b8vBNyrOjjLjAC7ezFUujvB/7RrKtnbaYmS8vYF1f9+\";\n        sout << \"mGqA78owo1zfad8DsvGEnr5J5mC8d10rXhVXXb/udkiU5iEhYPnSxRy62tgLbKHJOvW+R28r7lpc\";\n        sout << \"yDK1++NYKRpDIHYMuaZ13oDNdIoQD+d42Su0NsP0wECAoMmQKkWUaJyYUyFqzmQ2FJmvl6hDSbrs\";\n        sout << \"lDipexBL2U3slCAJbX/PyvE0KrBPBe+vT/w1Z5s2GBvSoGwmFlN/oa5I4TfcTA5W4ie1rBHUKqPr\";\n        sout << \"az/4un38eXTaF0Gfiw86pwlgJXWr+D9qvXQApo6KmaJhjKo+4/MaPw+iEQrU3IM44eaqq9exmiNF\";\n        sout << \"/SgBv76gC8hXFrucFFp5znYrl6ISQUedvk81jnI7ce0Up1jYsh8fpfp+0V54IUNKqxT9YlgfIkbG\";\n        sout << \"THuQQ3p2F3gLaflJWfZEo/lPtKc6RqVadizBP/oxl7q+zTriiyK1JWiJojr97xQcNpj5j1QF6uqK\";\n        sout << \"+7NQgfVevfP9FGVKOlIgvsqc9fnqWd7pzWKEt+kfjbpMGpr0XFERPld0+EqLts1kAj/ejnMymrXY\";\n        sout << \"LF9QJotJBy/QvCuoaxdptGBtrC+qJIuoYKTNTwW4A+kaf3RrNr4ohuLBcH8RRpHFU+3fEDW/kOx0\";\n        sout << \"fdRlEUJoxdfK4Za4moLfsmI8pfl5rBvlh9oumT0sgvPg1P3zp70UXJI0tSHisCb/uK+Hggdk5AJC\";\n        sout << \"gC3NM9uf3AubM+CW8rJXM6qz+xwOeTuMawJTGTrSg6bB0jREYOXfvwZ7oNgiSdqe4+s7tIhd21Hd\";\n        sout << \"A4cJw2aRWk0ft7jp9O/6A8II+hJoxReOnEFn54/kdM5LFasSjd/wwxsdtGevYixIItCTJ36K48dU\";\n        sout << \"nndygDo7qFWaryImEjgErq5NT9VUfg/VdIhCfAro6xE/1C5mMZ083LOjvTdxdRO2qtgKYCvL3HWO\";\n        sout << \"Q0k2/WqcaAKyh19cHsnoVKd1gXCummMSRahTGpmK82fAE2vP7MThuNel1CGti+nKVvzu7Yf3i9eJ\";\n        sout << \"rUapLrviTwh0cQzVAWHXxgE1PB5O1Hj1/hxwRVStuKNsPjZKFmNu+j02TT98hpYCFQ3F2hE/jsIT\";\n        sout << \"VN7hr7k16mXUqWbCzNWO/xo86NyCS/8HYFXMomE9KRLlP1cw1KrmBltivEnesHGCi9sAyHnE9bcX\";\n        sout << \"mWXL/tg8wP96Eh10KeJKzx80xfSPz929wa2Z+fAfjHqVgroE6AJQNKengtaLjTo9vBo2E4mFbs+O\";\n        sout << \"AUy5hDVB7Mm/koguhT3+BxefAXoUbaUkNlIewCbDUlLIT2o7ZLYhoR1WTBv5K0eQIt1wTFytuCVq\";\n        sout << \"Ldoni/6ad1IzqamnGBam4hFQlbQgpezUea29Idj4dhUqTmksk0fV6sXYaT7P9ELB+W/OnF6IY/d3\";\n        sout << \"6TUUvnSPfyfOHHxts3HnXQjDqrRhPeJown/p6tzdtytVCLeUtXu2o1SgfGJrs9uAtT5+3mt/NjFb\";\n        sout << \"Z+VX86HZQ0A5XgYWiBDvd/Lu+ptgu5kMX/QAzBZp4Ubxo/sF57ZuA3TJMx3CjUFgNBwHgdWsiMHf\";\n        sout << \"X+sBqB17McUR4Ar0OVoRewmYlRL/J9vN3ZJ/P24Ctp/7Y2Ozk6vJZBIKnTvcapys6mah6rzYurq1\";\n        sout << \"vQ2xWL0+hq2nsbkZ6bMl0ummFaCrPrMmBLGAQTa0Qa6QqO8sCtepBHRzJdCH8InI/jRBJKrGM2jt\";\n        sout << \"s/bM1qvX3U8jLY+vGwt8URt+H9VrF13rKxlgTJmu15oC0duyGyc0ejeDsopX4NkOQ6xScBsPAMV3\";\n        sout << \"ObV53ImrQQxdypGM8UWByxISLsLxMDDB49DhgBvOqfJCJ62M/m3zZNV7PzUkUcI3iB8QDpovj4Iz\";\n        sout << \"CmTXnRgtsARcRc977luV5QiiofiyUOVQFbBY7obGei9EnfRspuXIwDsShcRIEHEz49K5SdToZ3Ky\";\n        sout << \"XLZUEdbMsZDXWjmE1A+hN8G1oAh+fkFoXav5S1xvmYqr28vAff3UhxXH1ZKVGM0ePGoaE+AgPIuC\";\n        sout << \"NawQwcyWFoPqLjaWg9bgf1K+gbhxH4ot5ehVVMb5YiAbMrIp03ONvVFLGWzI3tzFMMTOemMgM7UI\";\n        sout << \"1T5rYrWbm0q0IBIhEpRCpR1Smtgf3wK4pUX5y+1+xGk3bIl+Sk2Niyl0DmrmqZlenbbts1n/hDyX\";\n        sout << \"ZS+148JBO7FJvG6L/oD7LaIzjBAPMWB2TLARdbc/ShtzxMY8l58fxDoOs8gZXcpLPHpdgEALIJWi\";\n        sout << \"GHRB0U1osylCUfS64GUzB/mVA4677H/n31R1WaghcDrZRgZs/aeyy8DIO8fprsM8MwamVSDoXU4y\";\n        sout << \"YNyDupAJA6GKeYC98bCgZ64TdmXX3pDp++8TOyDJ0VDNrp6LfdqOaMNZBoG4G8KduFcUssKyGs8D\";\n        sout << \"mGZ49omOt6rvrlZpGgBxi6afE/7tg4ac2hHd368gOLuPyLY8UKBEqhRGG4POlbg+v4AEegzLQdmx\";\n        sout << \"GrtxnwcojpDFU3k+HPD7wQwv6dSpzCGJy3d0682y/x3muJLZ/bQaZUV5yj2SCfgSIaIZcmVW6YFE\";\n        sout << \"dB6GXs8kxAZgfLLPT49+5jIL2XXkcmK/LK4dY3ah3zGKd/Gl+NUxbZmgvOzG2LFmPvp1Mr73WZ4L\";\n        sout << \"q/K4XId/B35/LLnT1bboTQ0L4BaJR0r8uURHEUO2fo9HtByhvRmaDXy/+EAxT01G0sjy4Nhwd0oj\";\n        sout << \"AZrryg3KSdCTwUoi/CMme7l7udmRxUMSg+L6+pTXgONqyBNDwkksQ5aw5YP0q02WH8pd4kVHHLkc\";\n        sout << \"oVv3diXYApXi3VBhtVmpyjAm9xy2SPL/iaoitL7/0d9nIlPymzGh3Ko+ghijUD0Ft1CJHr2pn4QI\";\n        sout << \"zWL0rF8DTAP2TcD1dl/I1VNW6e+GLtWgI5+/iDElGyrELfamWyu63q14Yp/Uk/PrMTsxRxZBzZ6j\";\n        sout << \"whO3UnC70N0EWPc5M1q2HdWuUadl9tbXFj4eX5F2OABfnMgQHDo9F+pux+TxpCZcNFWHsd3frjF4\";\n        sout << \"HEg6qkqxyaqgZLUM7e90wLxYi2/XV59BWFuZC6kVAkBCNWMZm+jisGYdf+kLWVrbZ091mYTllIpt\";\n        sout << \"qP2NaF948T+/rfiT1TbhmAGwj3NI4dd3azqqJuobPSjj9pdK9JEKhyC2QlkZ4HgRqyKTH0xPA1Bo\";\n        sout << \"mBCwzYhubIB2Ro/oxS152TwESUPDvZXTsDbmJXGsdCrrmfQy4NCXNQEDQrjrRY40qXKi9Cxr7wjn\";\n        sout << \"W6NrSshxpsV1NwlSGT1Omn7RUMTpe1JaKLINxTUJCCPOuNCAgbkmPfB2L/vzOq/PJ3/EGbolcvCc\";\n        sout << \"b9zvJpUeKfNOK9oqBZ2dZQqgGAD70uTPitKu0/5pA8I+14sLkIfVpVAiJI/54Jl7cz9lhMQ/X6oh\";\n        sout << \"ILDtsAHQjcDXP9BCfByca38PJy1k56vOjfg6Tuc+0hPcDkhWobXqi5xhJaS8WftAOhqwiYZKsimZ\";\n        sout << \"yFuYCz0EeT8EGFa4APSgjPSmsV7jCpOWoY0RtUYvhNMLSmFuwOVOiUHLrlsb8gFXQ9nmw/K8hxHc\";\n        sout << \"9kP96Rx3f+y79BSrhUcQyUrCSV50Dkvq07wfcAEvz2dzSKvz6zTDIKUFxfz6ejsAvrcx/7UgP0i+\";\n        sout << \"1rtTnLXH/Qy6rlJAkxXknkQQ6YG8egWa0mX9Wh7RxpTIBHPaUU8gnIxo5/RZEPOqrF9DtYoJMOkB\";\n        sout << \"T6davyvC84bSPrk5QW0DMqzZtHDDuzqiRYZt9PfEvURu7iI0IJxcVWYQcXJL/ZCp2GVS8689pmYU\";\n        sout << \"zIse1tFwwd64kJJfyBqN/vW9A4aI/PutNu14PwgPVr+NeH8wQk1L6MhOvcnJwYDWm504takuedAe\";\n        sout << \"hB3lePRnMEBawImStuD73hcZV1KzTKFvu+ebNR8414Wj6gVJYfPvHFv333u0ROqJ4/Mhb8occomU\";\n        sout << \"iedo9jM8ZJCMNbPF2Vxxgg0ahEwTKyq49Qht9fhwUTm6pMQKUXOWU/rD3x2BwrKQ7NZoOUqTlfGI\";\n        sout << \"/czGxGeP9PqmLcleyMhHuC4GdlvI+ulMTlngO760teQeuF7EYqbwwuwqtSV3E/pbXm15OFGSr+Jo\";\n        sout << \"FrOdb5/WWAQ7OZPwdgYiWxbLELUCjNu22PoVAN+PlAYShXG/qR2lO6I8Mh6TXZ2Oo1tP68lGp83c\";\n        sout << \"zpgoFpNuaQzLCWIjC4ka5v5k+Y06crZnzCzxaPsanjgOtAlQ+BOykH38ErkDlM4M2SGs8IAZXW0R\";\n        sout << \"zHgZygNho43FDRQHPiYxFtGV2ktVmtGNTG9YtWQsBcnd/T8xtUP8DI3tR3nCg7Q9esbsZOgbzCIL\";\n        sout << \"bbtn92I2iiTkjuPSuuYoWPzVS+hi4dB/BQWeHtnwdNAmqU8IAJki4jNkjh/6NfTgVepkT2Nc58pT\";\n        sout << \"V2DzfqFrhOW+whXsJIFkMSW0dXp5TCuJBbXTIiChMjXI3c+Dzes1/6CF7l2lFA9Ol+AiPwjPvhhQ\";\n        sout << \"/9WCwWzfsmp3+w+9nLLt5CtWRePIB4LC4nugM985fxf10qYES/K0vxKR1W/Ox90s3D4aG57SHpsX\";\n        sout << \"8frJ3HU/ouV73ZOtCg/lOfdocNCQa8KsoKhy0T7tDnWoKJvk0tT0RhFWltVQHV+sVteGXOImaxcZ\";\n        sout << \"MXDU6mnRzp5PEkQnNnBDeynPvs0vWfVSYpzQnO1tyIM2YYwfyf4vdn82ikk/Bq7onvdohQH02/jU\";\n        sout << \"VQjCfYj7X93of1bK2ja4vdEtcFpH34YTnSyZ7Rc+Np8BjO915a5XsUagea3ZHQbC9bWM75QKp9f3\";\n        sout << \"HuDpEn4tNg6RTcwWf8s2G2vZCfIDkH0geal//39BsVC9LqIyEF6urWV10NerZXv8fumNmX/5JraN\";\n        sout << \"aZ4GGdnhHPnryfHkHG62ESpmUCBO+85oDXrZcI1riSFKCYP1eBn/KCWkjMf0oV/pYljo1KrZgQay\";\n        sout << \"6vXXMdX3Ur6UUBO8iFht7ETaE5BeQ+3CZQEe3tdz1Z87V8rI1Qe0Mkq40CwniIxvk86JigLkt1Yo\";\n        sout << \"iQBWhcgJXCdVPSB1XpOdtZjgMPQNJqJtcbu3SDHsWQ3TWA6BDtVbHH7xY7CPVN2si2K8B8/Czxmq\";\n        sout << \"xptTLBIMfU0xaBZTXLSmRKNTEj9D0H+PwHvzPper0tQU5NEs0tZ5h6FZER1mgFzEmbZ6PUVgc79f\";\n        sout << \"ZnMaLmKpirOVc7HwFfLuwxAlvZRWtykLc8AvkZAp+bYGHERo3uHgdIKkeW82HQUKsUMN1VglX/YJ\";\n        sout << \"gT3Htmy3dEuYGNh+OKulcvAoRvLmTMYgACr/0ZNWoYjqAeilI7ZoqBWHYswLrvefHlIz6WAAHwKC\";\n        sout << \"xkbk1H0uWe9IRcf0DgEvWkXSrWRFHSS7uTePFxtLM7OQW/GmGfS3wt4/YLomS1enK1L4tH8fEPoL\";\n        sout << \"ZeZgjNYiMg4gQLm0+FyseqNjiUnQPkoFQg1jztPOZSxxZToCSdeUIawgr/3KKQ5+d2w3LEOQNAy+\";\n        sout << \"Vf+o5CjsfXpYJ8HVxpLsEC3xwVEzhpeY/04yUW2ygAfZqbsLARAAWtW2GcPN77MnGAmm46PeCSe/\";\n        sout << \"2QS7gM0ygtJewBCaxSfij+Xg4HQhXiKDGuwDYqUDmLInHskRXyVuuojyCbmuNmtyj+Uh+HsdFeOU\";\n        sout << \"fqTBHfEQzzAFVyORf14oEhGBwDuvMzLjciKSfLu6KcMCFo0TGgW3Niu7kDdbxOxg6Kwa4wiaWWk5\";\n        sout << \"mJpG6uhNFaDqpfVLY5D/o0Hn/QfMZwR/MzmiFjstPVEd9ZzuRvKKSDOM9Ult2lTU6z6Ci2b4unu/\";\n        sout << \"qfLIE8CjUAZrZnEFbC/KWx9I9zuUuoXS8elD9aG4if80uCyJ/tT4MXjx8iRsbvZ9B2MoFdO9gAUn\";\n        sout << \"qafo/IYR+5BOderTedEwe6FanPX4opAcpmpXM/cbD51QA9LCLyNtSoSPlwji/ZtYA97UUV6k5c47\";\n        sout << \"TNFB+QtUaW7/DpPZbxsU92jE19ztQ8VV5Ylm8v9RdvZDQ6T37KVEYu/z2bHX5L0r/bkEtQQ3gf/e\";\n        sout << \"TRfpy9j5f1lVMpN/UccOtsZfQpW1WvDcbAbOjcuPuuwNOudfzztYg8vjJNn0pMATK1+p4adLcxJ6\";\n        sout << \"uCh+zVgxAS9W+z/t5X3YTMnFDULRXqs8lsN6H/1t+gVBp1uG04BBDO8YMXZsUB8dLyb5BHbkjPiU\";\n        sout << \"c/zt703lv2U6So90+H+6hlnWDBvfLHI1W1C/RkelOCD8WVZ0rk/sgI9UYf+jk/SkIkZgbtVTB5S5\";\n        sout << \"gd5IXkexjN/kP372AvWgX1t+uKVmKRCrYlG8TZzDrjRD4BjS1M72OGwm3MDT6GPRcaGc+jtSGAxd\";\n        sout << \"eW+6BPofMujBNOBsrxKejRcLsddfOrGTBqP0Wc8B3cNOjEg/ITJ3LOu3FFA5TyLh0BvOEkuiD7Yf\";\n        sout << \"SpB8L9jDYG9nCcgFC19CA0Ji/Oc+aYFDMiDM4be+gG9QUdAxk7Yg13HdJirKRiOvJkf++ayrJBbZ\";\n        sout << \"xs8NEcd6lN3XoogW4gChg9mwlUNehzzjIl56wG01T+29FhD8Z8ebywHq0xEbP5aVGrEzwj4HF7kz\";\n        sout << \"erUrxlRZbmRgleNhldZDjqUpMcHyJzF+OxZ7W2AfpjJf5FaF3E4Rb9IG6vBtPhZbk3X41VpKx5Ih\";\n        sout << \"DedeX1BVHzRYAPt6JchdpOa+F0Y4Evke5XR97NecmGoYXrSkLrArSXDu2qqeQVx6XJ2Qginw4711\";\n        sout << \"fJwfVb8QMMRouBWEYz7k2LflgRG3c3XL1KP8npyz3yNw+6b3/K5JSq4hRFzXfsIWoLArSWgfboMa\";\n        sout << \"w/wIVdPgwPnUh3bfYKEXsQSenrazuqhPosJRMsX8qdZ1HB9PBwMKMHqDessyUX8u4kFMZwo1egfw\";\n        sout << \"7x8xkykzBeY8Iy0y6uOVpowXPgEPg9PZnquqW/r7qQAiqgoW/4oMU8DZtcfT9fTEN8BI0YPPNPFY\";\n        sout << \"1N02ocPS4kd5V8/bcTWkYmtCWIqlDtyPCEcEoBQbhneOdw6EmOmTqJVArAwydyN8TLsJq5A4WOf5\";\n        sout << \"wWO407yhoizBhRjGlqsp+LW9DlG4LHKLWyKCXb+iozkdD8Bh9RX3iYz4RWNSm552G1u8YQtZkeN6\";\n        sout << \"ISOxeylEI9OFkxvueA6u7juBnwpmt3sjcvCOLbbwwpc0JyWfAhiRdBfC7aXLjHm0NcwiULATnoJ8\";\n        sout << \"AMfNt/qzosP8LYQCvRYwJYShbskncZCd5amEmN4eStNaebKyFX++T+XC9EiG9FysF2VZdRf3OhzG\";\n        sout << \"dDBtLbkdALyBU3A6GhCueeZ4c5vEsHC8RMH5iJtYHXwLc0OWzUPC/DVlhVi82avRChrbJQ55qHza\";\n        sout << \"DBnr3I00eUsfGxijrqaQ4bfLLv6S5e4jP6C6waRbf4RY/Q6kTb/9oECBuXgayar3WIvLp9txdLEi\";\n        sout << \"dc0sokRgOMXjrheq/gZ+WHBm88SLRpecDwc4D0kGo7UQC/PIajFQ6b+rTJBKwYxeaaVpA2gaakqR\";\n        sout << \"BeQurXrdpAW7hWwBHjzWtxG/qKwO/w1+x/zAICr9N2/1Bex8yhnnIEcltD2qN5ykzqBzrKrbAzaT\";\n        sout << \"+6+ZV4ZTvaeeR9ELOBDYzkkUF6cgTWAZnwT0dKySp2C6FSPkpNseYrrgwg4Ddp49pN7ehwCE6V99\";\n        sout << \"ebgMYWGWqJkBJ7ID8NSMDFjOTvuWzz08QpaygfGSGgipHcuEKdHEe+waRMOMZSPVD7uDdV67805a\";\n        sout << \"67OTB9j4JiA9zhyXqx3STc/ICLFkSjZbl0VC5XAyVSrC0ssNFCVLp7OQ1REJYnj2bCPMpZCX7VHF\";\n        sout << \"RY8HRrA7V+X0HGBVPAcCrBn47lFvImWGBWGAWFO+TltuyKwvuiBOU1VfG1mxFCJJj/+dv7jIdDp5\";\n        sout << \"+VEE6pCWOJxzveqnJ31PvwrlGjxY8WondS64rNe2qnQ+grQCp69T4vHe7zuYfta+QyjtQxHiXSBV\";\n        sout << \"Zyu+R1M648V5jmGpQUT1bek5FLy5LoDDjkHITygysq4NzrytxR7Ncmgns3tdB9LV5zcHBG2I2gzc\";\n        sout << \"lHRBaE17Z3Lo6zdwTlGpfumcYid4Rlj7OgZIZTz3ogfaWU3OblHZ7Kqs3GGvctnHnaEtK9oqQQFP\";\n        sout << \"zEvAG1nL5qjUKB70e9YgDiUYKAC7xyWVoB0BCIjIXdJh8JlwXMRQDQwEwAeV8FAYKQffZB/2JEeR\";\n        sout << \"NnlaRxoQVuiNom9Dh7AokAEHuitMI+KD0n/bijH01pr9cxGoz9uimYQwc13mw+ZS0GsWeeEqYSWV\";\n        sout << \"kUsJVrisNxDeJMKW0hQuZmNTkjve2aX70+V9ouwgMlYQusDxVGugu0HNUQBgWbnE7CW9fh8GQV6d\";\n        sout << \"42/8i28kLjJ5wiiReXFbXDQ1XBz2lwyXXm4ITq5e3tqn/BDX5S6yQg5yKGl+2pISvDvZipWVNj0i\";\n        sout << \"vNeVWDITOZw8OAceKLZJ0WDSaV5W+F2Io89LI4mdzDdvOk/Ct9OpxFAacJ+H3Kx2S6b70hcdrx2u\";\n        sout << \"0Z+LB5tDRmxItNYMfz7br1fZKyAO8hUxeWN3EF6v5Kh8t0R7ZZaCEJgt19e/3sFnR8ssvG3yrdXG\";\n        sout << \"RT6qvp2JAUyP53dm4Z8+6e/k7YA7WR1sv7d7omc56Q3LXhpvmJJPbAJ/qBXHog0pO1ypN8szYVUo\";\n        sout << \"MbTlTlz0TECPbqdThQFSps4oXTeCcR+5fj7SR2K3FVjbxHfWhrUfw35Nh7nPfzyDHwfmX+CMdwoj\";\n        sout << \"oosswTADZSwvEh46PBffUydxEG7X70qyn8VhwtZGHTFNTjjncB9AXeEpYpqxo9ZzOXcCM4JwI+jC\";\n        sout << \"eDsx+HOZdie9keAE27XUcvKhNYv+G5Hq3rAVNe2GRgDdt47Ysz9vECFOBxO4RVAl0jr3TmfKoqmR\";\n        sout << \"3WBN07KGMf2q1osu+RZ0I2wAQBwQOFG4c7IjxqEh1tlBsFUQBE207K8zhrYyURXulKfdHL+iWMFs\";\n        sout << \"LxDsVCo3kG1L1WRBXynobD9DGvbx3EJf8eIgrKuHSEF46SHUWs6HjACerAjryYxvgHUoUez5cD88\";\n        sout << \"TcQwFBS662AAs2ZAp/uA2Y5Pc+mnluC+5HYwxYI1hh9TVEQPXRPLccrfkitZYn/kV1nf7AzK8lEm\";\n        sout << \"lavQkdl8e0rKXTunMcuayFgtPCyqiUPn16MkaQBfaNM9B+gw/fFeRctuRq46xbF0fTzBS8iQBkoB\";\n        sout << \"jTV7UmXA0Ysi+iVFAod6e4o9eyW/WEhGUCrAWefyUqbytPJDH7/1VnTdlN0bpeXXSyqWgTpsWYay\";\n        sout << \"GhdYTsPDdfTSzkEU/0wdKm/w8Mjcf3+ZcVNJhPtJpEXzoFsSL0VVGym0kDsJooOizfSqJPyczVD/\";\n        sout << \"b3vN7al2kuDcNZjVyWiZCfPyED1UQTSQFVZBygAfmjg/spVyg3zbiW6BjcDuxOxOHmBGXuE2XOjM\";\n        sout << \"Qa4Qcw7ioTk8dw1VobafnWiGN2S01drTqLFry6ZOG2es7IejQh6HsGig3Iis3xAxWWGS/Wazhw8v\";\n        sout << \"M3OQzSmbW7j0L0KcLOMtSxiYo5LHXxhti/pAaI0VZSLkQYgyMD/mBdbs0B8i3diXoAM/BzqfoU7L\";\n        sout << \"7SNslWLwXXscPrJsCwFqe2UiahyQyIvf+qXqBhKuFnIHVt0cF5cFAeEh1kYzAd0JDbi/LB2hYsVX\";\n        sout << \"rosavz3xN715cRmjpjuQvlIDUGfmmJPPvUIbbXiT6q+TrDdQaPw56G7vz5llNd17QS7UUZymWjY8\";\n        sout << \"p/8bq6MieVzWeOmiBPbmWRtmZ4GPTc0bmau8FH77JxwgrkdH/7jDL6uhcd3grTrsm8X8ZX9FGCZy\";\n        sout << \"QZQ52pU3tWbfy7KsWnBZjkRwzZVRY3EVjg9V1PMQYKAqps7mU0LrDBPwrgHW0c9EvuYa9SIShUgX\";\n        sout << \"JtiWswoJVbbJXltdhclBmvuDsyK/MfLJrSE7qnPOD009hILCojdSCmqdaFgpmw88EiYAVDqwcFzw\";\n        sout << \"EiDdvqg91OFplvWoGEQx5wsjOKaQst1Z1LSc/C1ZZH+mmBMgHfYmr3ZiX/eYUjGzYpdKGa00v8gk\";\n        sout << \"dDEkUCLQ1I0ayiaz9cMPWkZ3avnYb7TdUKa3iwERVVFEJWfhpWe/4KP5qBL3Ih8qLicgtdkt6FOM\";\n        sout << \"ymOpNQmfe2X+P3U6042OQPIU1vmig0euGeKQmsE4K3NoSOEy2QheNv/2GSSNRzc925zhjAk1zxXQ\";\n        sout << \"04KKCDA4HJKFK0tly5P6KjSVTiQXZ6e+IWH9CQfAJWumCVtHNCulD2epjCPlTEjHH332gl5c7h7u\";\n        sout << \"eJRVbsJKZm9z1TgFN5w1iDWI1cBLZipzM0BznWEvEoYNixyZot+Yfm6IC0SZi8DA7c4Ngn9V0ydg\";\n        sout << \"c8JNp+A7T7LqB/LWgma/E4+wv/cdoXiKi3mwg71ZQRM1d5oWknFfm8hq0KNOl2RsSOYO92PIF8Lp\";\n        sout << \"kG2KPK2nBU7VkbNtaJwjmJpadvkAEPPpCbYDdRjrvKaSw9yehsWKfLVuCLQHlO7uJmGe2LHWKojj\";\n        sout << \"BtYYau7+Vfyjj8K4eNqABvny8hj8zV0HyToirIxVpBmH/6/8p2imqYx8hc7yBE84LSNCEac3UJYf\";\n        sout << \"8sxZluHs/ZD3t6s9jVisgtx67iv8u3A4toAOlYjBqj/RXVQRAb30MzAFy1YCdxedXIvKBa/jXMwk\";\n        sout << \"0DsQ+YcRsnKmnGQ2yOxNVfiJZIg+KqN2Ork0y2QNEy7aTv25OEUM8U2wKaRkiyNYh9VmvZpYk5xM\";\n        sout << \"OPOsReX2FOJOFTCUGZ+w4Lp13OI+QLc9TBllim4bhtbBscCMN78WOpnUccS17gXHnqtpK1Nx7R3N\";\n        sout << \"dwpVTYBCxVVUSCHAREPvmPlHj7c7nnIfO5LRxuGxrg0TfCBUwCNiJvuUpiuqNyJha+eJCPS+SlXy\";\n        sout << \"BN9m4jvEM4KGbkGSwelXon6LWOKq3cya+8xOqQ6KliFrdQaNk0Tdg1Mi2oRjBlqjyb55oXYNeRgT\";\n        sout << \"wQ8wAPqY5TM/z/Zk9ELGeQz7JjS/ru5Q1LGNUU3tL0AjqUdU6adovph7CC0/g8lX/NqYg1oRT575\";\n        sout << \"7m4ihHqVTIN3pMkB8TJBZNAa3i1rlom4qcOFGdjTi4WTRd9r3ll0y4PB7V81SddpOk8RPTOIDKR8\";\n        sout << \"pgIa6xFOQ/GTIaB8i7uLax+IMs4dIq+gzpxE9g35BP7J5cbIYJJeMFIm92l7wJB93ANTT84yQABm\";\n        sout << \"oBnlfu/fjcbGvfHw41CTRpMWraO5d9nABxuIX4wFKEzxse0iAVsJA21RbpdBtIHLBcbYKCh1bUW/\";\n        sout << \"hRSk1yislMs9Mtjx/VSUn50NAompaF3NLpG10/hGd7pp1co4wZm7+fiW6sIPBCqLtkg6A1+qGUxG\";\n        sout << \"nUU6NqUvmyWo5B4Re3mDggASRSIFdD8ckv7LlAbyDgVyIxsBrf80ISQN7jRDDd7MjkyAJ5CRlrUu\";\n        sout << \"vFCwCo11+7E/Yfk2dadQJTjGvuyyDXW72l4ze1PuBrjnql0vBe7CCPZKgKJWWDzbGIEKGbBqDfBV\";\n        sout << \"EVA0NrVpWYBu3uhj8sHi+cAMwiXy2T1ar59Cz8bvuIA+9egegV19YAay92S86BsJbhVfb/THW/G9\";\n        sout << \"sbTgF3MWTUgvDFmaJzYn7mkR/2xsBn6UQsLYPZPxOQ4VaEUzAKFSP0zwGZfMYE/REnDIbdOR1ai+\";\n        sout << \"zrA5gWXmbLlr09hkM7tIn2Tw/+X7zEzZ66oDyjDs6g4a+CBt8OtOLi7Ga/dO1DP2y4n1YPAsGADW\";\n        sout << \"Jf24rVZGv8IWyGmlYJZWX2tBKV++HDUTxnmbsDSI7Jy3r1UXNWskyDC9zYWetsp8UxAVRYBDhwfv\";\n        sout << \"fqlchxnmTpm6ozULqYI6ExncbbbK1IBSbY2A+VBUrEqdH7Rxg45S0HKRbvB2jAkksOyhbXUwngM8\";\n        sout << \"6uG1TUcRdnxLvZniKptRcYJthyx0HDHCzLoTT1AlyTB9kvrktDArOUa1zmF2hCZAYP1swqb+zBjP\";\n        sout << \"CHd4aExlUf/UokEBduXCWomJLGXsJpVG1EVz6kTZb2Twdt5x5vZJK3O/LCBKgZNMuS7/xLFZpvsB\";\n        sout << \"cUA0MoO577pa7SECGSrUrSblkliCMKmIECRrQoEJaNKCs1r991ptT9aWnLSbl6HTTWXKcceN0vXQ\";\n        sout << \"tKwTpiM5nhBmea6eOQn5JP5oeytyDul1Jd0SHR4WILgQvYQSrqdyQOf5zDBQHe2/EsinsfonJy50\";\n        sout << \"4M4l2ArPeWEjJKtQBpgQaLF7CRGTjnv0TPJ1Xjo2Cy2OFvWpkA1ZjK3Q/I5PJsMrlkYkTSgQql/k\";\n        sout << \"HwmLiFL0KGdVfo6F1HT5J/5ZxCDOWhO+DmvLXtvTQSEE2asJVZWDo1rpKOq6H3AhObvUgp8AtPec\";\n        sout << \"+KXWiyzTH9YYq5RFU4JE8a+lt8+bGtYHxGOE6AuVgQsvUvAJ2kgqgi+kLYF19FZjeYbvuxzI3t7j\";\n        sout << \"+qCO3v59HfjZWfQ7FOJ/ciLVAAEM65r1sX1JpZRodNnZUvbxT7QoVOm0LwjW3qw2VxZCbVU/jPkc\";\n        sout << \"XQ+8lxiZpHO9mSxBXvQkwRW4K9MZ9dBl0oYdvq8IK33SkyTcaHBqlp2oszKYwDFyLo2C9uiE2BSE\";\n        sout << \"gj9UpPG4M7XOUjUMJ3gs7aitPsTdI5oHG1xklLOTvyWYIJ6vk2/uBrMImGSExPSMMGw0NEbHFEX0\";\n        sout << \"Fh4Td6+cO6QgCQeobzV6Hxsi+HTk5mtAbMGXiIKi7bAiSC3tkoiCeDfBxzqROYgSVQU9fW8PeyW9\";\n        sout << \"xEmwZSABCNRog1xAwHaOuosBqYDMidyh7F5ID9XeYHH0qaMxLmzYkZ0SAl1qECFzJ7wUSiwRzvzC\";\n        sout << \"VfatrCs84cDUKQIpr82LPouxQBeVFQAlj0Plcuo6CxrJgVR8q6ciC8eCnZ5WaF27pKHrfPc7ZjdL\";\n        sout << \"h4AwTLGOpUg0N0/aUJxvFGOVbm/g8pH7duFC3+ycmYrOXZPbhz2qthsxf894+lkU6TfmN3OOoTwG\";\n        sout << \"EXrda/bR2NQNvqJWBRTv//VdXIr1RmlNMDcz2d9lL3rwF9Gq5EupgYIfe1FhiiqDjyrTzh7fw2Qw\";\n        sout << \"P5T1SfKa5Ww9mGxa1psmYlJ/IzOQlSlSzSHxMVvD7c6UDpWwKWFlzzRPjl3WPS9Dmzk3tzUo2ZYx\";\n        sout << \"RdP7RBZg7Cveb3lkIn+gU5XII4cD79YzKPesFWpWR1ejkLVGW1YQB7jtRaJmoz8T81UTuqhxhBt4\";\n        sout << \"NswM1L0VtG8asAidWd9nT3Y/WWI2ydJ9YgiepKeMdtpt8aYqoutZUFzPKGhdZsZIYikb9r1Svrd3\";\n        sout << \"MAyceFX5RIKLVcyJJC9n1QlJVSXz2e47rrj99prVvMN4ROB4hpORryHzGuPMMhpn21ZywDk1aH9D\";\n        sout << \"0WGZq8Nm4YZEjneUtkkW0nXcF0nxJ0wTFBmOrXEgjpk6jzfQ+9+b803WlwtqRUJ6S6FYirRyTv6X\";\n        sout << \"r8xCqyXgNioZycZSgjxzLcoFqq/65u935jK7BEMtBGWa4zQcwq38IcmZu9xfCrQLCfHpIfydjxBs\";\n        sout << \"8PrNV84ccG5Yfs4zN6oaLOahJBukoFHUZLLM+67oALQzsStEXS+HQhWMJCRj5M/8/SwoxZM0ACfQ\";\n        sout << \"XY5G7OnF21/5NwpsUoYboT1wNFT2r8TKrFOx9bEIbKV8xTUgdrnZwbKGPemsypnnsFHoA3BwIWKx\";\n        sout << \"+w0vNWVqK2vsbL/pTiZiov1lxvfKFV25Q9uylplUaSnzYuaDQFLOPBFr8nhcmnfZA8r4ljcjMNw6\";\n        sout << \"0AUHO03MyUDfu0BUVYQEyGXpEvwnI5JmVOI/y3/TqnVnReemG4D+diuwm2Q5UgyY8KyykxJam4Zv\";\n        sout << \"W+Tn3DHT0emJNWv3imi5itW0rUIaTpt/9a0LvqIWi0Q1OOvrxGgUcrsRzfUVi+ru+tX9YZrBOYXe\";\n        sout << \"Ut+KwUCvITG88r9m7o8aovNyH9V7bC4axTrIxmtpRiRP5e0Z/IiH6b560Z9ixQ0MRv5SUn/lhX/l\";\n        sout << \"AP2rTsqxLmt2mWz9b3GqtEO0iW8XisORLiHzupEX9jRbcqShrBoG9bu+4DUO9hGdemq5lX1782dh\";\n        sout << \"FeZOjhIE0/8JttTmz7EZwzp7SeHup1yqlForPR0hhkFzfOOQk5CwfYR1tD+0ImdmbL/QyE/TRsnP\";\n        sout << \"NoDB0NVyXcmlJQzRH+s/dK9kJjHFn4FAUJ7Eaw5xi8/O5VokSz3gfwwPHbKFexrY18fDiyeZ404M\";\n        sout << \"cAGYSGyYzxkpa1HwuZE7UzUNlyzpuja8RR/8XaUv1XRK1lIkmDFA9cKT81vtXJBY8/04Jh2OsPBT\";\n        sout << \"mFRnFF6+vItwlsmOaF/WUstZg2XxP+MePh2jGkKj3b4c4Vw9YwzD0/xNlkCk22jnN60wtM5WHiLT\";\n        sout << \"Opu4ZnP6/woOP+7uOOHdjEJvo2d/v3TOmNmfx38TBCBdAbRpMzy4XDZdsWpP7l0DN9/OnbErxD30\";\n        sout << \"2sECWhkxKygkNxeq+CoeiS6Zl3mzEKkQ9q/XHccCioWgiODFt6+Wg9MtPHGaR1cnaDDBBp4YQWJG\";\n        sout << \"c0D1Urc9H4Tpn0lmJkx0p09nBoMHGIBUKmHuhMOnuEuZp9wDYSQ6UnjtLy/+QJcCB8QDvTCg9mhu\";\n        sout << \"W2HNZPqa9DFD2tmV5e3+pTojHI4O0tOwA5B2OYmqFzdvMWLuFn0uMHOu5285KE0ZDykOOv4Nupq9\";\n        sout << \"z/rjTtrxInMTU+a7hynQ7Ra75F5nCnEefKXL2lgD90IkuNDpmxHBX5OgOYb9RUwqcVGAFSZq1jYm\";\n        sout << \"rg7sxuDJu/honmXsDohqfo3/vBVca9U28wnCJ2IsuJXRQwzBLOJAz44ijj6+Bx4R/7U3IbN6nSNW\";\n        sout << \"5fXiqV1JD/r3AMAf6THZKnYy88mv6kMzt0ZXPd4PlyHCYhLTIzw3AZP36xPjEWBRP8FGaJw5Pm02\";\n        sout << \"Kh91uM2QdF2jowNV/Ago7rHS09R3B/aWjmGdVTyhCjdogPtrhVHdaq33OftcCuCF7q/wZ8kL56HD\";\n        sout << \"2T2BxxmsZY0XqSlU3757R/VoeGdk7XjAGbpOeyxn+yrP8/stbyIwxq8PSv6YhRN2c3+H9AYka8Lr\";\n        sout << \"Vrb16X3aEEP49jxNwEOL4hM2rcgS7f3uayVLwsuviWxiUcQdWcmjTVgTos/11pdXpSaPqSAvpAMs\";\n        sout << \"m79R8fdq1V5+kmZZ8UZKUdQwjJxeg83dCTDpYRTXAdSdKDLXeD4Kkvd2ebKOGb+1j345x4HUnuef\";\n        sout << \"ijTom/Xz3fEw1jLgqZd/nVeUCBYcXpozL50LwzYDZzjxERSVCMCgmt6VJBgpvwFBXyAYJql5972d\";\n        sout << \"vIP6cFU9K1AGAUipBxgaVR/5NBFTIjgo2CEOJulAQkwWXE1TOUXHF6hD+Tp9Zf3nZRmTBU2OXA/U\";\n        sout << \"8M5Q6nyDRaV/qRdB3GMrYPHZIXcy+uh9xI6OYDWSfv6uZxGfKDzN2JjMNLuK5CEIu4hiLj3JHC5o\";\n        sout << \"vHJ77Vimbm7wa/cTYx4ztSvSSFwSXy82nSd3o6d3Z7vL4FlzDjxkW+6AfP+8SQLvC8yiKiGr6U9/\";\n        sout << \"cqFdi3xOg3Ska+3F1sn/OIrDZVLkP5eyqo2aDC++WnVv4Aig14Xf7lgD/nOV16X4sn6BmpIysM/i\";\n        sout << \"Cjqh7AuHgDkB9kgr7jQXFeGAhdGCNby93jgIRBdWTY61JRX6Isek98cdoL1XqCheIxKckNMmljnr\";\n        sout << \"lHL4Fi8okkonI43IKV+8NJ5eH/JmUEtrcOuaB9M4rEI1NsEQK72dIWyuuIYyocaeA87R2dt2biia\";\n        sout << \"SsZLV5jE2O9YE/AWY5fDGAH9PA40TD8bC6bxgaik/QFegoo4tRw2yR+GwtUh9Utsu9LUofRnq6KZ\";\n        sout << \"hq+3Bqzu3U9grOYNU9MUxNo5jZS52U28A8NSuHBDeS2870sdUvEM2RftmNusMnCDR1bw/tru/i33\";\n        sout << \"iYIUoaX6EPN2UOJMm1TGqIOMs4QWkDTXYAsIdpBgq2nMfXVDb5y/nqpmQH2eJCgz/7Ly0VtZISf9\";\n        sout << \"mkDrrok3cIEMKMgvM5X/dA4F6Bv929nkXqqSi6AtUER/jJJARkpAJHJTj0IxUgY2unVx4KP4OuL5\";\n        sout << \"b1HeIkWdlln4V64OPJnBiKl17p4pX5BGtEXngsMR3kdDBJwliLv6ciLvPKybgggvLSQbQ/vqnZdh\";\n        sout << \"1x1GlnvrpKfoLFH1S6f4HiDicapOP3wKOp8ECyNZp2IAVbRmmPhjKjPry1EdgySgpXFZUHVEHdR3\";\n        sout << \"R7cGnH1AGhZinYuoN74cFsNooe+LxT74F4KWSW08+S659M7862DADzaxlHAbd9BL79Tu8RGS5CUB\";\n        sout << \"i2ATQ4rUgRvzC9OGcwCpOAfbp33+jqLmAWRllB5f5uBJuO2nG7OiKHV9jeunOyHxNnp4UTpblCBW\";\n        sout << \"yKx4EVA7p5T7qH8krIftUpBbUx38XhCtPMcsIZIMp2w+nmrlZeHyPGVGFrA+Z1+VjmRtiwGCghXG\";\n        sout << \"JjZ9j+HPIniiHK78MNAPoRlt4G5mtBopMopDn/1cdVroLuJkxX1CpCOu3MmkQQghl/km3jphiehr\";\n        sout << \"Bj/E9IZI3/LesK3Esv1J5VJCFl+Eyn8i90S2ij6sBBPF+eqY7TAMYAr7MK9mFtfM9orEpIJTvG+U\";\n        sout << \"Uun4ibgHRw0t6UQ4nnvZKHL4qmZXZB4clGgvF2Sl1hj3FpUhQLr4YWJbMeBVddvi8Ifsl/KpN/J8\";\n        sout << \"k0iL9nhnyDfLBNy9iT6Fnyrt6wKEJKAmvMTUS/U5YZ3CFAgWEmqI04ESYkZ1F/pVjwgfDtwjbkPV\";\n        sout << \"Vr+9zaxAa2gT5yZZ8m6CqMJJ+Hr1857AgVw+msikx4c3G0zFZpUEv4o3PiprOr0t0bGSzr4rWnLb\";\n        sout << \"rPNfMq0mQI2bWIMeZDtiAeMLOwrGdlnBUekp8NydJeL1XNAMMJjHKvNEnopNqkZ9Gt1Kmvl3Eqcx\";\n        sout << \"TuwbsX2ew5yNJOUD7T9q4lYRdKSNs88fdTFzE6heGTV9UGs6z0PMP2HoLXSShBhvPAIX3t92KK+9\";\n        sout << \"8986KZvRZ/QVN93Aqt1mczK4SEgo2X6Tm5814X6WcCWiZpH8CcwQjW23psQyguC4PyLhGJo92XJY\";\n        sout << \"GRVVisGEARz1qjm/GY/jW9kE6alXImoLE+F0opY6QTQXAo+KKleXAWmMEUs972E/aFQtmR2V2mxo\";\n        sout << \"Ga6EtSNXobw7jP+kMkYoSiav9pYhII3t/v/badrNBhKksNt56Zx6BYFOnfhPrwGkR+YoRz2+x+gR\";\n        sout << \"GMHLwRFe8lMPR584WNMrC8r0r3i+qrp2TeG5vFM+VKwWLSBUoG+bgZShS7ITSJiSjkuDMpa7jy3w\";\n        sout << \"1s1AIgtNyvxrKPTKr6C2FjVuhDkpSInVX+Cdr7utecsExirDn7uyb46oI46oNbsD/6HW3sIkvrVH\";\n        sout << \"xWY1bwvcKlT1+aFWKYtdZEOk8JE60pwiat+MpxgOk9TC5EUdJvcxOP8M8zQsIuQhWlkgNhsm3G7X\";\n        sout << \"1xWL302yhLrl66DlkKHjCH8+ee7/RCRm3l4nS62XeVQ9ZlzEIUbPP1tnnzg2aFi/VxMxk+EfF23P\";\n        sout << \"auIEXL5jALZVnr1D93LlSiqGwKoAq7s1bblpIGyxcXOsuaZ8Ls/J7FsxcLD8BQiK9v3wotEzaOOD\";\n        sout << \"jSfsH5DDUQ/nIdlBwZk1J8aOTSIo7DZ1wZRBSz66ptR9sSqcwrXvFndHulLtva04DfNDPzPNaCoH\";\n        sout << \"cAjxsOZRKl+ZPi9X/qsVzCr6DijJYeWT+UqbhTOGX/Vrl3M3Mt7q4Pcs0vcdXH+SUV8YlF/zmaD/\";\n        sout << \"xxZcFz5DPz8NRAculqklupW4Wc1D421TC78Kka2NTJKLzivgisWROR9c6g4ml5cqbrizhraRbvXP\";\n        sout << \"ilWQ0PSOq+uyJqeo+1JOSH3KWoyGWfOfGxlRffmvsOOuY2oblonsSCz6sYKySsnKeTezRcSP9PFg\";\n        sout << \"6EGCjFg1WodhnA/KWixJtQ8QsfhaRDoIYklDBWlPBEKxgvHi3yVF3vTyakoY/VR82B8UWfzxW+gL\";\n        sout << \"ldM+gn3H/DTpzR8/h7xBK2yoOw2Gpv2TcEB5oMtPsXsN58QdoqAsgBcHI/GNdfqaQDK0lt+npV2M\";\n        sout << \"8NAnFcK3r/wdAJ6OwJYtXPEIbhHxRkEY7GLUT1IwLeV2PIV8gy3Eh03ULZDcmii5xO/MsPgrUSKM\";\n        sout << \"Z9s+JmBmJhQISUjumZ2SBkAU5V3SG3T8c8EaeN/9yNYMFmSXX/jAjlAViNK8bCfnPUkrmnTAMaMv\";\n        sout << \"blW6tw1yhXV1WSAe075/Zl9slrZhcCJHYX+mZ1yKDpt7x/QxayGmwypWDo9ukTnE66UKiZ0udTiE\";\n        sout << \"awN5uFe+qvj+zZLrnM4Bf4ZjMjKzjd67W8UaxMJCVtx2SHeNC7Ffjo9xN4bicDUnpqTt5phMV+hX\";\n        sout << \"lBRiuUYA067qUb58MbkIE02F36n/ioHNYj15Eteh9wv1IMIpMLz/1UGm6+97m8xIAKH5B691KOsD\";\n        sout << \"k1ovwfjzGXmFX12KsdSplPSmH9UCo6CsuJmFkhAkYd5vCw99+JVu7RNqhJGF4h6Lg22AqisjfHde\";\n        sout << \"5CFUks0DocGrgDw3GcmVMFAV1Ix29iekfAgEJcOphJBGJ3FvwRmGkflrIJW5x2sPMaRHeU8Fkzso\";\n        sout << \"o/IF8537YleWU45S1m+GXNdomkGIFVXZCKwiQ8bRr1MmzMcs+0EkU0r6ei7yxi+6LlKfp2NQOv/Q\";\n        sout << \"owQ74v4YHvyNJcI+YLLMHaZySYlxIjL33H6b8vjrzsDntYXii8lVRRXhykAiLldwH+89cFk2tbeO\";\n        sout << \"am9kZeEIlCX889URxsw58TRlwd0Lfag6IhNO/hHpi652lgEYcZu5NPaDQPRRC6vkl/+ocoMmTDhX\";\n        sout << \"uGhphdczLsCBpIejuQVqI1dhrnko128Jzl6yIe6mpuhzRT1ReFL80F6VRjegnDa67Srztleu6qzi\";\n        sout << \"OUgU3EDRfE8IJ4i97SsnTFJR7Eyou2/GP1U+ai1U7JTknHbg7fNeD5wjTIyQVE31oOR2WTNELWa0\";\n        sout << \"/GWO3P6Em3J7vZJifeKTGYWf1124uh+oBYgv+j3vUuX01i1P9kmeUP0nmVgzWs6AGIvbIp6vF+gV\";\n        sout << \"Uc+8TvNYH+0f19q/lPOBnBT46URHpJ9EZxodLin8K5aTCB3sLjpXiqQDPD9fbMzL2r0s1Z0YPWgH\";\n        sout << \"Mllgxh7l6bIhAmymXIUX3+Iw9rnW/6ODO1huBbvgZOAUrLMnTA9j54trOL/n2DxwAU7JJ/fCeH5u\";\n        sout << \"PKH6nM9l/PvCTslH7ahvT/uqGD3/++3FeHok90oU0QxyDVbsMDX+ksj5Hn15ZQZQtYqToONe/OI2\";\n        sout << \"F+xJHU1CWejRZDJgDICcBYQSI9e6crc1vdf0y7aUeNRthj2xLC0zbtfy7PaIEy/R2E93I3jOoAq2\";\n        sout << \"Mz+0icoUb3Hckf2St+HqfYPL59yCrEyqoFONN5XMArC/MTYpMn/XQfCQL2X9xV9T7WaScs9TAqQ2\";\n        sout << \"/qZrrcfRxUaPCVIBtG5V+of/vfYoZzwQrLTioTohrX6SC0WvxS05UlbYo9sDwrchmIxPmrf5vI10\";\n        sout << \"T4Sc1b7sRfiijqZA+YTnYyBPG5c2qqsmSXLmtctpzUn94XPhS76qLj6uQEcoaYTOwFK2dVTvFpfu\";\n        sout << \"zlRNDzCCfzXc64lA9oKwEhn2tTH4ddClyYobly+2HH3xz3NQMrLxeYXblIKBFJzn6IlY26a+77qM\";\n        sout << \"srMzEwRmnzUojuRBO6n7BxGFfP1JuP4FhIpKLTgA1Ql5mf7Z9LrsM2lORzMuO/og7LvjrO5jVs/w\";\n        sout << \"+ZKmQzSzNBjEgq09UDk3gMG5OV38SgLXQCkUnCUThGU6En5OTQkSAF0IDQ9Bmmyadqp/+V6WiViv\";\n        sout << \"Py/WYbFDSAb95ME/J9YGfTg9VWncLDEU4otj6Milbr8OLjlR5YbbGkieo2I4jYfuKHR+/C1uXVWk\";\n        sout << \"HEOZBv2lYRKteXx18m8DLOZ1PO0PC20KRwcep1QSmw8SH0NJ2Gj5L2WvkpfCSwKYJOJECrAc2PcI\";\n        sout << \"Bzf363+QgmckMylMuHJ0Kf6AAP2xFtKYw3qM7tTUjt14QkC1Bi0l7ViNGt1vvyTq8erWFJYveVwm\";\n        sout << \"lJQMmyvrHq5g+hbj9ftT8cPxbKJ/EPYGKrtrM8AGxTxrtA0FHqmzjPTm9rHXhGYfm3ALWw+frbVc\";\n        sout << \"d06D+iiyRXpTTDZoEcbMaZYCSyHI1QQmTR9Wfr64r6XSk+/jDLNlL/Syp/Hzs5dK3P2YR/UjTB3I\";\n        sout << \"8U70K/yeV0v9rDUI41COSK/akYmpybimqmexTop7zqNUIFOqFHbH7TCqRxfq76DFebeHbE1Nq7l9\";\n        sout << \"p8HRuOuavv9wKGBJx5BoYl0h+ujVfqWIJHas9QuCbJK8Z2eNht/j/FFSvdlPfWIrRu20Anay6EHN\";\n        sout << \"bEDl6/voathXXz8Rtc+/xkb4A2D0+WwXHrYh0onectahnSjI6sK35wtf8UF653KENWSOVFiFAwjr\";\n        sout << \"XHV4YZb+VWi5jQ7470jOdd+6eg9v47AymA+6Z6ZeTWazbxSgfV8hCsAepHyZ+U2Z0B1Zgeuc5rKp\";\n        sout << \"MhBQZ8xf5x+yM1G9Jtu4Z5kgQ8NdliztMLkquT+mbY9U4eri/WsAQa0BvC6hisueLg7IGqjQGgIJ\";\n        sout << \"29Y6iqD9fJZuGAgbEbW7qu7J3DyYzGaKyAx4+GOyctio9ChW1v4uq7gkc8XNpmYiGl/90mo20hzR\";\n        sout << \"vEXjcg3Hh/aHJlVXH0hJ6W4kOuBFkZxptoDFi4vKdSCVWAgnQgWhmhkeI492Y9bUaDTxejYhTfDX\";\n        sout << \"N08UiRXnAN96KK9iL1fJZxB5MUX7cJ/GvW7RjTVP1MNzy/FdlAN+k6Sb8vyst3Sz3eGHOgO1hpTq\";\n        sout << \"Wz9Moc4BVabx5NLlb74ScQHCHX3dnKXle6sPCzfbPjM2Z8rbm8NvB/VH1FZ/EzriephAUYdra8OV\";\n        sout << \"+f9V3o9zEYMGujKxqZysPfheqaA3gKKDVgKGhfUn51dEq5YC61aWqxjO1suUrW6rQpBHN/V/VadA\";\n        sout << \"hpuSHr2UHCeL8yUzC2nnXxpHCifGCrx1/R+A7EXBjTlrxd0n83pEV5paIK1AB8Vsv7RNrT0bEPxx\";\n        sout << \"uNxgTVdFUVHVLZf2zuhlqQCSr6zKzQgdlsW2Rbkzqm/RpdwRmONCWkS5IRTwdqLM3rfStz3zt3U2\";\n        sout << \"PklWaPeSMTUzREfa9xfaxA99Yn8QcQZU0GK+zEe0d/iyeDr+7XPYH6ZOgQbFp3BgHWk9tAgeVx3d\";\n        sout << \"hOwbut1u5WRa4azjGkYUUlvXLJpehNwKEiaej7u9jKrdQMTRi7gtSYliGdNr0nnw4ADV60LXD0Fi\";\n        sout << \"uYvPQwJnbICCYdy/Yx0X/HBu0dUS9D15JuHuT9z1D/dqirMKNiWhXlEzC99gX4/mGGM4Q6l53SQw\";\n        sout << \"0205XkJ21NasDxznXp8UE2e4GsI+N40b6mLvLZaauw9dB2IeNhwZvn7mkGDraXjDnpnnmX0iV0Y3\";\n        sout << \"OH6OCq5ZBlk9/IIVJpS6Xtec6MiuVBYrhKj2MVn0tI7rRalXXqk+7Plmg/9S/Vh6U5RM3pCjTTf4\";\n        sout << \"ZEAxFH7LhT/JRpkk7fPxcncaHQVrnrbM8xEYc9/2nptKYriJdXHXecsiH8xYjjzw8ACs/FeFyPsK\";\n        sout << \"84MjAvnsSWnPVpJe9n51BIQ68dUG87+igoKtNjWomVVSAMlBKtbiNrzFN+4AvESKCufoTC4gpGPD\";\n        sout << \"2sFkTO5yg8+v3rwFK4aAjBLA6eKzSGkcJqcThom+NfRjrvCtPysEisAdXHc40muhThMiIiOFXwbH\";\n        sout << \"T4722yaSHEMGNwDqY9dlixhGz8L5G/B3hbrlqCPe2+GHcmmMI58oFMgZhEh4u/1t5nkCDizZ1COg\";\n        sout << \"+CDWA4n4lcOXfVMwp/8u7GXZMMLuGSJUy38DgjLzy6f8bji0+EEZ8rbFsvMjssgcx25YJ9Jy23eq\";\n        sout << \"rcwGu8iMKUQ6t8J2sZFPXuFrn9cyFP/vP6qFNWZ1CtiN2fRVbqwtBj6DXmSae7NDMmL8XfGlTD5i\";\n        sout << \"aiIWK5SPqYzS0K6oPFagYWYjIKqkNRyIAseq0fqTLKnyKmv8oj///TlXGawbehr9clexoKbAM5Mv\";\n        sout << \"1RKu3/pJiPVwOPXcwCIlQ+BemtjmsnBzJySAkA1I9mpgkPm4Pg4qblWhgq/aVulwN5uSkJP4ZU6n\";\n        sout << \"reWj3khTO6Svsua3toMPYm6FOoioKOOrMMXQCoIjsybBmSaEHeAFxZmHODtbf/WrGL4YbhUMal5o\";\n        sout << \"90Ay+c0apxZIV+8d7Bm5L0dRXmQfSUCnP1CKyUEGPaMAPK+DYRZNU97lzpowFRdjTlrJX5aN3jrk\";\n        sout << \"WN8/xaU0PTVo1LtIesYvyG8n8gBSmj90hw5QLFt/94H1NDvPYMvw5A6oGoQUYdCXTXzrRJ2OEow1\";\n        sout << \"0/qEzLCWExSS9q8nbsf9Ne5ZC24XA9KHmiJot5v7MZ4KBORjPy/Ub223U3xuJqVGHlSjYuHqmOFC\";\n        sout << \"bhqGY4yNo/7PU1/cvg6LbtQSriMj8+85GQSheMBI73EnwIHgPOIV7EGEr/GHrfyM1jI763x7Pr0H\";\n        sout << \"Bcsg5o34glMy6YWSMLd16/Djq277MW4XiMoGPK7Rptwh9ahtgjS+SAl92VTVyx+kr7gZXfecCivl\";\n        sout << \"gXUmA8sQugTC3Zf7QqR5eJvYA/i+PMRWkLw4YCogDOYXK7tKY86djtBHftkYob6bMj8a7/1/XGzm\";\n        sout << \"Xz1OGinw9yYz7N19wgkVZEubmK08ZnKINN7A9IU98iAauGaLizHRlQ1y84Sz13coFKe9lRtgnNHr\";\n        sout << \"zsG5yqiTSIlH1jLyxVh1O94Qj6RlNT65LPJa714IW1ot0XsS8QgX7Jazdb8mqyiBky3/w+VoLWGx\";\n        sout << \"kplBp4VZN5gRvTIHRBq4LaoGgzc1C5us3loLsxNUDgKBCBjUkywWAD+l7sCB+2btJo2HAcmgbNBQ\";\n        sout << \"zITjO+dRirzIS6GerX9+zbzv4lC2d5K8ZmDUMHV2x2NKaXIU3mP6II/iBaP7W2VRx5qfAAChmMAP\";\n        sout << \"B6zDwzc7LNopXp/GgOKhYzjctxbbpOcMjP1gnQ/2F4EAyXOU+iMZeXqlmbJcXk9S+bCK/Q8i96kW\";\n        sout << \"k8lbmB/ecQxbYJKynBJoijaSzeRYL5wC/IZyqScchpePu8J84p7DEu4ECqd9+vhjp28/u6aCgnKe\";\n        sout << \"T0mE9aIOVS9DLgIURa5qmWUFvolbrZ698AwXlEV8vkMgSDZyxgRSBdyZcmQawO26rEVQWeAr7dw2\";\n        sout << \"zQIGGtM4wACd+Vv3e1FgjvkytZOwyo0NLlURyqdykYhZx+youz/Kmmri50XG/hpD1+5gXtVFWUhO\";\n        sout << \"V5G9Aw6GG3+trxtMJnjCdkaA7DTjTIU8nUjNnx3TsCqXK0OqDMvem3e2TTeXorRPe2zYbhYB5pVY\";\n        sout << \"lSJ5yYpUrIzJCb3xPGNxQP1qVv/tCEq7IIKGqPl2RS0NihXE1uz8xPMu3cxu1juHsw4Mx3qi2C3z\";\n        sout << \"KH4LvPoEbP7fO9uELQD6ipi+AmmB7bKabD2AwsHFurh8oFtaCt+KuVy+676ggvwGEFm0j28Cj/ff\";\n        sout << \"SQzCut2j0HQjychGdngbYIF3HLJQNr8rbh7k1FPpJhdpJc5lH4QXMddVxuydPbwQuB5zGOWZdc6y\";\n        sout << \"0O4zjCgP0ibSPyEdhkolB5T7Sm6ftL3dctp49kJKtIyGd5scyxMreHGJxeaGADdgqken2Ahx9izm\";\n        sout << \"VoVdjhj2tvLlJ5FbAlHqir5ZcZIu+prlMkAnW20mXjeWdh5lSCUFGcOTTyxirXkUfyDRFVwfMnOi\";\n        sout << \"Y8j4v6X/LyNIKgBPY5qFKfbwAjYWyAPYYQVBurLEu5gsYGSYhmtm6BGZ39gnxbBfhB/JkCyE68Pp\";\n        sout << \"wwAA3SA3Uxha5yMTYK75ClGNsWyI1AwnkfYuYgEyCbBv/psf+I/jSpT3yvcEDKiI7FwToriSgA61\";\n        sout << \"3ksBBfw9E7Y66wmwTHq9O4alqsltIAVLkj/Lp+DxSc6tZn5lI66aOj7paImjnZac/GoJAxVUfcKL\";\n        sout << \"q8pBZEwlJoAZb6T3wCuEdgZlYp3MZ5uInqAZSOsqQQ1/S1vCj5pwdzHrHF6Q0FJemS1AO2/GCk8p\";\n        sout << \"dEaniaohFtWT+AMdEQi5TLVmtpltYP8J1Sm+U0/TazrQStLUXm7Wpc2DkMdU3cZw+ncK5znAzzn4\";\n        sout << \"dQGBHVR7TMfIpx8anoWGhShI6oHh4zPXYtRtiV0Y514GWxAMB7oeLOjnJTWeiwO8VS9IPCjcKEbO\";\n        sout << \"zTpPAwMiBrZEnglnKmIGxQXRmGMpag1JZfPRj/XyucX+LreWYF+PabGLPrjSnG5e2D4aDlNx9wGH\";\n        sout << \"raYpvkG/LJJp81U+s3VsS2vUA6uWgz2XiHonASuttcV+a5vo5tcKUDXDaFckDzjpIJe2rn+Z1Xxo\";\n        sout << \"X8OomKyPCCGmMEmE3SxPkGCkTIDrbb5Pc9j0NDVXbRyjVZUf2hrZ7pR+H8+jzUVgt4IfnB8Q7/Yq\";\n        sout << \"uKW+YvA6w3hYv94BqXPHeO6FMLhH14iBLVLp1Yp2aOp1ehJUQ21OgrhNGjMmF04P/2EF8DXy2V9s\";\n        sout << \"h+ohPrdH13fyVrQWRUkG+7Fn+GAYcpD1K5jvRavlli9pHys/axwdu089ivNpA5D3D+t+SHVGEw/L\";\n        sout << \"ZcWpKRQrUZnOLTNjJEpEIAkryuxqTcGDzZlB6ngOVxK7oUiwzocC+zjKtmafaH1BqxhX3RxkXy/8\";\n        sout << \"sXA9pDQ2HIn82Y7vv1+9L+88KXcTLTIUSI6iwrL43h6IhM018jTNfCgdVx2Uav7Vax1kmu9O8mhT\";\n        sout << \"NOxDk0uYoMJfLPhr/nSWlKjgojoEj4IBmALtiMtqe8L4zNpHTRxgvLW8wMQAyj/woN1mLxLb7Lxr\";\n        sout << \"UIY+ECqQomA4TLPWXuTsLMJXQyFgd4nQgqVTL3PUdAtwes3xrHTODTYv9f5CLEiTBV3BP5V6lo5O\";\n        sout << \"Wj50oMM6yJWV4jZypwEp8osWHksLQjPEubu5CiBucOv3abc3Zvteygzp8J0la8wjOT3cd4+LHFwg\";\n        sout << \"hQjO7JuNXwM1xhgdostGxjYExHC6KB9HDG3OUQ0wtxsrh5QITF3hmlvkE//xrWsyDzTcbWCgG5Wo\";\n        sout << \"NRy0RpsXsMImYHlzO3hV5wQHz1Xjswc0ATMArZ+YJvXieYgEyhkIIzYlFlc1/GgnScyJs5Al2mvs\";\n        sout << \"5GFjwMfC7wnMNRmV97SuDzQjKOiwMFochKCR8pSbMzJ4+dW0W9LMvasWGVAnwvQdfIm+E4+O0W2N\";\n        sout << \"ArEB7utReECczQcBVWjdKqK6/N6QbXobZfvLto8AqTTw5CjOgTpoEybY4og+zNemINlmYgzuU7Jk\";\n        sout << \"IwiyzZLohI6UaTrPWd9Ck2lLn9kJf07TnWVw5+2gIqhr5M0d4Yz1Xlgy7EfAWMhPEu6MuD0WKKB9\";\n        sout << \"1MSe1zl2pbq14zDGyICSCXCLTTnLjc5Yj+E92s76igXq71sobtFNGzjQfZtK9VLTrAaeKf4Ql4jO\";\n        sout << \"KWQJTFYbvd1ScHzbPyF3S/T0CHPDZssQQTd/VBOuspVr48Vl2/MRdLpdzjd2b9gwCh2EwGeJIy3o\";\n        sout << \"R+AdmgHfA6PwhJKBkIliNMMR1DEhwN6QDY+b4GKnRHe3+k6tChrTNUqZpZ7Eyhret/Hz//LhmPn5\";\n        sout << \"EJ7PSeJR7K8PKE5WoCzr0h/o7SeiHi9qi+2STfd6J940/2D4HBkYvJOEH4Tu+1XBPi589dh6vnhP\";\n        sout << \"aQkicmf2fG4KuHO9f9Jlt21I4ksrEaibH+BKFFw2Rq2cHME8Bg2cG6HO+TyRwIROhy9yxtWQEYqY\";\n        sout << \"g+zU+DM/WCXBCNDCPqy2q8nY19izJrU3R/9ZCUF6Ji4GjEzjjb+mErVhPcWpaLk1FWAPxtC/A+By\";\n        sout << \"rEiAVG7+asI05YWpap2g7apUyGoyIdnHQ2g8QucKspJQhW5BiF4pi7Kh/zzPQPXkuxQ3biy1pOQ6\";\n        sout << \"/6EEXB6W8dLKHTHn3cXCphbbQzqnti+yQdGuvwDiC/GWZbB7ePUsUSJ3+b7gcR54EjMeIX6rBUxF\";\n        sout << \"2xXAs8El87oP8PCp023NStXDjpiRFCyQ9mYweS0bRh7MewCbvgDIGBuJfXL46eVRfj1sdwlnpS1w\";\n        sout << \"aN7ePzPyTR66zIu6kwZzfv5zw10c2LC9cj/WcujPSKir/nCMFaAUroinmmNiH8C4M/CL4mU7SBkZ\";\n        sout << \"/hidsIh9YDq7cQRP+vBwLgoVewGxnS2Q8yfZ0K9lAEsEo1Lpxg/Bhr6Ei21nnfaWcMQEVj3Gwpdb\";\n        sout << \"fqKrvOzQrUbQBADmmksC7FSgEBUTYze282+qXvS5jnhFg23iV6bafe7LOnZmqLivJGA6S0Y2D0nN\";\n        sout << \"HNP+0t/IutdM96z446RKbwvUrfNiPZF1CJWu+T7Gifwib9XOmMCvamYUqI+dplpbgCxmwbSnMwJM\";\n        sout << \"yK2++dILo2W4OfcPyM9eSBgY/fWKdcv330fbSE74lTUiInCJr0hECkFD6gThcDVRY1MJY1hX2Dak\";\n        sout << \"E+r/OKBGTM5i0AlXeZoi5+RyIiA6wRTKEzjznz3eHhAe8gRKj57DUbhXd0L7BK1ZPs/F4y3/GHtZ\";\n        sout << \"rfh8fPWKi3TX77vcIOANXRmGtpDm3CDxlhcWq/bWxEL2u6wk4Cqqn7xxYLNmvnZHB3GF8aFfPRdW\";\n        sout << \"iqdGfvdkoEWNNAd+OJd5dmu+kdqFXnoGtlItp5myxabhN/I5sdFxalICuAm+kAl0ocG98Q7v9YVI\";\n        sout << \"PaajznXTdN79Fn3cFSHlgrJ7yDb5T5mzpk6ud45ux/SxLw4ERY0jykYeAYV7NQp87gSxDfp/xyJu\";\n        sout << \"LKgD5aTz1RUrkC6VnCDdij8ZnqWx6FlSUdXt7+mDe7GAKFBHsKBUY0B7/nqnP+wS9GU7SqPuHa54\";\n        sout << \"fxgnq2fQi/VaMA4ZTugMOvCKP6PgHWuzhFOorZKnkN/Au+/iOH4z+1NvTzBiBjCH1ZPzXEU8pXMC\";\n        sout << \"d+XzQyzL1fd1xS5+FTOq/FV9fm5ihRm3f4qVxdJFmSnNKBdUt6+BnrDoReWLDOpNiOF9oOfADJMM\";\n        sout << \"c55TRsb7ikJpOUhXHQsldLRMCBQOB1YRiDjLgRXnPM2Kh1/YUFV7dOS/tLUj6Th4Tmtq833I1AWD\";\n        sout << \"CLADK2WJXlXL5s9HzGBwR4eVwzuvQsTfIFZmbnsjb+pIDR1Ek7JH3eyAEwy3WWATtUfSC0HXjEgo\";\n        sout << \"lKpcSGD6BZsJ7IkSo7Yf/pVcQbpqOV0W0QyGcnu9IUu8q1O8iF7Nu5LNEFWBm+hpN/sUgzE+XIBn\";\n        sout << \"3sInc0pG0ehnOT3HznAl24ljHBudSqVqoT/O/K2aswIhxOl6RHw20PypAGvTEDQThB3prX1RuTeg\";\n        sout << \"kmQnQir2ffAp7pxEtxvQJ1kjA7Xp88ZdE+xOFX/8yvCnCWh7jzidGLOZrh6T/OlPIhd0Ipj5GiM/\";\n        sout << \"CZqxIuPwEyKbZJ612Ny57dLmPK2J/J5AuWaX/wmMlItloLwNSvTwQ2tSiLUraT98oIVqhu/GSRs5\";\n        sout << \"pRbWOeTspkUZVC1306DklVBAKqWSDalxyilnxToN3l1+DG+UgJtSevkNqlDpNfH9LqrcRrfmokTW\";\n        sout << \"cymYpib926UvmWf9lsMzJfBqFg3QU5Sa/eF+BwdMgB8Cno/p7FsZ3hKytbOM5fnPzm2MYR7Kw5Mp\";\n        sout << \"xPcptC3Al6ammAMjlp51IMU/1wyfDEZslTCZrBCGSeYBke5D9Qz31gl1Oyp+RV2lxhNngKZcBKez\";\n        sout << \"HjNzzJHm/PvqfxyAILoth+5Cb5LxcBp49XjcuPhZ3sFIfNUs8IhjnT4RUZxJHs0PMFHwx9NwgryB\";\n        sout << \"4UqLFn0+Xves6a9xW6mIzgSJZXxgKcWmA4MZFR1welVzD7l0Y6Rl+Wjw+qrklobDSNgntToguXwR\";\n        sout << \"mrSM3jnAYy00HnoxJVcDFZ47Fa1aYpZvAlZHbgqJ42LrR1KvI4Qfe+cJVyV2iq3FNB+4aO6DUVkn\";\n        sout << \"2dBbf2jmR8fNIjz4XkSCXPpwx9OZuYB2C6JjUkQ9lGfDGPfFcDNA0mjkX/FmKf67UaGkJsG+DV2m\";\n        sout << \"sxojbh+zm48COhWz0xrBGSdj0viVa10iqcKs4+izaPgDSHMFdez7nT1aIBqf/ys792hN9h8kybET\";\n        sout << \"GZw6HGYgD0u5+hbXeXVC11f+8aUi2vjGW9gc+R0cAnAjcLNBH6IPIhAzC3E3IJ3R37wqQ5huxyrm\";\n        sout << \"qZ5AWYXo3PRswYjxwlXvUSwEbc+GxcFR+jirERKaqgwoVOw/2F2WHFQ5yQ5R0nI6uUhNMbTjlF9x\";\n        sout << \"2MYa3H19/dgtY4UC496uQ0uVJ06wlVRCL1SCRpSn8y9IIvAEpkhX1b2o8NAMxR1duq4U0fUhCDo7\";\n        sout << \"GtzXFiUKyLgKT6tEZdww8+FztcaEB5GmoIxy25ReE9Y2Yz1w/IjIvyOQvqDxqNMC64ETTqYYlF7o\";\n        sout << \"oOGEBqO3JnTVdOtwbv18JsefEaqWs6hyUboe3zxvZqnrmSrF2Ezydw6jFhjHyTdI2rRNK7mTCg2i\";\n        sout << \"/1fxkFC4Rlw3U4NctvjVXqhVG7/NafRynbtBxSVq17MH1Sz3IRDsKS1/HtORRuAYX5/KYcgDjNyL\";\n        sout << \"ew/mVxTedPDQ+NDsj/5k4gjpHB28TQrYD4R8DheQ9liqV7R+shaUz98cdqoamEcpi+Vvo9eftqpo\";\n        sout << \"/tfL8h88W/BFEBPqG5u0CrSasq88l2EWUflOfdHaVjPiUpA03DhJ6d7WEXIgKqR4KQ2QUFqhft1V\";\n        sout << \"x6XQ5c6HvkYEA3JXB9WY7pqwhh807ucN0Kp30K87OElOIDXe7FWotG1Nu0IjnhIK93NW9W4g9CRw\";\n        sout << \"jDvID7dpdENEY4wzLG3Q+PX6srxE/bjKkWXRrIVe4egRq1yc1BdTPd8SuxHKgVvQYGNlDHZww/Cm\";\n        sout << \"sdtNn9gO2AN+zouZkXsG5JdkJVoGZq7SoLF1JNiBi0asFYTD3y6q6wvfonilbZSnc6V70VVmjY53\";\n        sout << \"NUCkcTs9H8acP44DwzIAMSm+IWWynZnEmul7B9+ViqgqsHW63Q7AdBCd1O9oqYaLKa16iFiHXAGS\";\n        sout << \"AAwYVBuirfpq/yGh2obX9w5LuIfc1Ohmm22xT1tL5Tbx1y6rOFL/LirpgtqOKACxNbxiCzEvUEpB\";\n        sout << \"XHMNDcX/fRaVFYss25guCVEj9/YsVcDz+lf0+qb88TM8LGqYCb0A2lVHbL1O3jdvBtfw3MXHX+3f\";\n        sout << \"UqH4kjiyAkgn/TLXzlbEjkGu9EdImol1ikOMjffpoXri7J3Rakpq19cJcXZEfN8Nl/J0IxjghnQc\";\n        sout << \"/Ge2ls1WqEwMUrKyQfRwoJL8Pe/8JErvyUuIIIjG1PHDPAUDmEHVXWU7wDms6GPAxh5hWM9Gwghx\";\n        sout << \"xDxn6q999jMjBmut7Xvl2yozhYpzs0KCNYzpFwSOyIjfwU/S1SvpXbV/fOlzGLqM8uDMveoDeLTG\";\n        sout << \"5LmSt1eI2ZMnKoDquGtw9Up/Wrj191RIHkurW0RubmX95xu9KJaLOSQ07cDP/FDiME9LyrHlT1e7\";\n        sout << \"4DkaBHyVw9fNhbeEWjF9dCOT/IQz3dQhiNizidYZgJX3d/coX3xjbBKhI18DAtQPLdx3EP6IFcPe\";\n        sout << \"AiU6yzb6lcthTbZ+DAntjRMbEh4sCd/OtjC1HHKm0foDGYcpsN6R3pxA2fJ13yU0ZPLYSJT+3hCE\";\n        sout << \"vyjvV1go70WzRw5TJ02F1ROusAkZnL+LVJj5cOIKQ+MNifUgd+jtwdiUhpFs4HWEnDxq2tWLNf5d\";\n        sout << \"xQ3igiJjm1MTfsrex6ehzwmyueSZKxTBgVRQdLTcSSSiivdx0zO+/TqN/0s5WkgCufzMm6uMf/1o\";\n        sout << \"eWPkERpbGs8c740XtOwHi/3JxDC135mV1Gfau8qPUA4VRqfTKMKwcCk2j7SYzx0RaQvaNDa94aNd\";\n        sout << \"a8gVcQhLQcStjdUOR8smPQtqtEoIsHqLLXDZF/3gWIEjQfYjbchQcscXEi5iM4jMQCP1/Gf/oR2s\";\n        sout << \"BY/eEjhzUNnDxyikEt+idxkKLnuRYJoRVTzfCk3Gdlc556Vz14By+uKeAmmgVVH2+U9WtTMOO7J6\";\n        sout << \"vlpJ3lMEQ9ANonhWe788Jz9pzjzIHhx2UfmZM20I/t4U90+iTJ29/AoDc7g73bHfzugK+2WpYocd\";\n        sout << \"ecImcUaQLdMqL8gyK882q967InpmujoXoDo4hrqpaLsowHhWiAbcPTIH6hrvkNYJ++PYo3QGCYwf\";\n        sout << \"z7z1vc6pUEuKEx02TvYO3PX6e/i7RVBQ5HBjVsuNiAw9ai0fsc9sKjwOml7//NR/o6hdFvNnn7wE\";\n        sout << \"Qk7pP/kasS/nVGYvsxAcqQBBXRDfDEB1mpkZX2bcNzZ/PrP5t9aS9t7LQYfqA7lWVgY+brfPTdmE\";\n        sout << \"haXezSHgRgy8iQjBAVdBl+Y972kmR4zZuW/SiK3mkOe92GD0dVXz6l4/HL5VFflONDAHCpM8s0zR\";\n        sout << \"HIlzwxAHl2wwiKqW2LtUIfnHA8Tb36Uix1nyKcGiYjHtv3+mc13GzYU4KZ4sj4suUs6Yr/XEtAXm\";\n        sout << \"WYO9T8LJ3zzbxMNJZgsVHWx1UWKixJwGCv1HrEAzQNmm5aDBGYrutpNtcC8B2DKIBex+IGlpTwrJ\";\n        sout << \"Avo0T5uJCfw3hCNwVpoSvpaOpP/hFVJYI5RLtDQbgshmFI4iFz4pIN55qCA98tYAg7a1m2g4CH0l\";\n        sout << \"1R1ErZK5A08UpTFnxKWS4pVB1XAy7hqtEd8YTADZvNpFTkocwBFsYSsDU92hTS1GzEQ3+NPIj+pg\";\n        sout << \"i9G8bDLaAY/bojHUktrnaYL47+BmrKQ7N9YWtFsjFrOaS39NIw6WUf4nPd5uxcoqlaM59SrOyEBT\";\n        sout << \"r4emeEzPDzF7GJd69qFOek/DrjX87M0rDcyCOKABNJfIBaeEJKKnyniWOx+ZN4fb9meuM5bKTqr5\";\n        sout << \"p6JLFbf7WFzqgs3h7tOcMhSvpVv4ve5Ap4yx4w8ftImJrW8f2j/OUiX6jtA9shoYI+4DOqYL1mRS\";\n        sout << \"xYK5WKMnkftUB6lK1ldv0ogi8Z2Niil3ZBpWqhY4+tuEvTLAT8nQtX+p9/gtHxNCyGUV9nQk/T/N\";\n        sout << \"lN/kBTdZs+KzJ0K+AIi7K1t4dVKggZ4vmqYVPj2WTKHboSzNg+oxAL8VmZAxnY2bS5AFR4wRSLgF\";\n        sout << \"8yQj9xfyDKTPRK4D7b+Axh0s/ra4XzE0S+M2wk0cmRbb0I8/pG7yXSFzYPM0bVhRuiTVT+mrxcpA\";\n        sout << \"qSJRKzFQ6h+KQLSYUVAspQeGnIQX70fF1/BcYviKGzwiN+T6zLH+thLJnZX/lgHwZZOtHYnCaBBc\";\n        sout << \"t1WFi3G/Ex2+UHo+nPBCFPq9TNEWcAArNxPwPb9e2H+ZH7dNgLZjZtGQoEiEI2uwI5l7/X1++/3N\";\n        sout << \"EWAKPziqUxX1sZeW/T9cLMiDsVajYh6wqn11+RM+lCUKvYZym15JcEKAxxsFxo3S3gbILFXSy6IL\";\n        sout << \"AkGGUsKtITt1LB3PO3sIare5OP3YAk+PzEVZcwp80V9dHq72cSskofr8hvUkzsBZ/iH9dC1dupTF\";\n        sout << \"UbI4YOrA0nQRnvx9AQVrPldyzgxv9y7mVakcgLLpd1YOUDS7We9Wh7exElCVuB73RtXfcd7hEjRb\";\n        sout << \"fu0xg2KT3wOTQy7WDAnidLZLtWeKRqDLxmO/W7370N1TgXS2sKLG6lGk6UY5mEOmoLsBtu6G2bRj\";\n        sout << \"QIZnC0q9x7sUVMyg0TOZ3698MgxWXpvNqocP7+TYdJeptTkg0RZdgON1WLlCs/yBSm9DYpN6u1ak\";\n        sout << \"pr7GDx/Yira5gaDGvnLtoL/6L4/0bUH3UJmeNACcLec9V+qxUJnYjQPYPjGjALRfRNPV8YRsjWBn\";\n        sout << \"eEP8OJG4i1dQAif8ehmV1Q++qHcmf5je2IQwcsrgj3+UIw6urMoRWVwDISw5Xy5Y1HwitWZ6VW2Y\";\n        sout << \"eeeLRYBIWAsoJAw7rSyLqKjaihO8rlGw3IeVrAHt3k12wX2t2f7eLF/MKv/8JjK7d/rr7EbNKrGA\";\n        sout << \"iyp1zQFtenTYrjr1/Wh12/lmTnipKS8ZDCJuMM0i8NTXB1fuisqNI35HCuXXoJQmc0Yfu0jA99jL\";\n        sout << \"T87FUwkmKQA5+Q0HV2C70CfE01ALVU9ZbdP80mvHlMhiLURPjRmYjXl++FKpHU4wvRmflXG2K7KD\";\n        sout << \"aKccgkYqc+Pw5T2AGX5LiJscIykcNaMLVtH/QYPasG8jfgVH3dENDXagJjuYDwkROZ7Dm36vvMZG\";\n        sout << \"QkRDHXApzY0T9GizL6V9WWflM0lopSWELw4HNPExg+ZMSE1eAebW58HHTDZEnu/Yrr/itfWUid8t\";\n        sout << \"od265bhRmkCVeEwIL6Kt7DBdDVDu268mwE/OlCRmE0Z1XHDIR8ggVbDjoQHV8Fzr9YCM/36qexHL\";\n        sout << \"v5VxMx6PzZGBMIGuPHIiqnqaDPHhVpMGbD6Xowd50iE82GANJrgulQOlIg66T5znMtXg6g6hOqh4\";\n        sout << \"WL4qrPm7T/2mH+T5PVIR/D+VJSoEtnRLdnO6zZnIZp7tj3jXjhNSo+YGzZmdp/H1iuSqC6GuWKue\";\n        sout << \"agUBFs+p5Zz/yMrYI31yx1URhmsLJrIQU8llICpkRo3uqhPzpXcZs/MZIS5pWniqIfGnqUtzeusS\";\n        sout << \"bouAVAOgf2rModIu5NWIwdnf+FEsDsw4sYDEI0jkJD8StwBgTg3uiq1jV3FP8nHWgu/QoWWXGtpx\";\n        sout << \"u7OR7HYi+Aq4lK6sVu2qld+deujeO27r4atK+wQfmbuPyjJugTMJEdLfT2SkkW9mN2Qx4jPmABq+\";\n        sout << \"5tCUgibAdWz5SqJBDr/jxW8WZ5YCfAhLifSbTdcM/IUF5Nq+NCT9vrcWaUak2K2uhfvoJjN7DWVW\";\n        sout << \"6KZMzeN5XIRKMZc2ItCW7sUmAy120f3LWzGZtlX49LIY5nsawUDOrPIENNab3CWEPAuKAciOsFU7\";\n        sout << \"CV6BvOxRekHvH/6clgwrfSCGgJsru77XV43H1/wZciyR/4QDMXPaewDGxdH1FNddnkZVAuYWrRzq\";\n        sout << \"PF763f2SQmwM5GERk2bxwr4eeeBWBRqMCK4ZNWpdYBseupT694Rrk/bnUKjuo3kwYrs2LzRXDJVz\";\n        sout << \"Fvj0UjorGcr63LSXNyLhyBGo/Uhn7dgtVUaYzsY5rChqvLthaBhab+268cfGyYhacN/E3vezmySL\";\n        sout << \"J1Bj4twQ+kcbWWQE/Jx5zGkgorM3Yu1vbjilzv/UbmNb+Cul6MgnKDRFS+cGQ5UMw2DD9OyTKJZ4\";\n        sout << \"5k+BcnLih6kE/s4UmFkeC4QRqLMBBhTlScS3wXS2lFsvMd/BXNXWtyFtk+dUP0AH5tgrRsaY2/h8\";\n        sout << \"xTgN0sMK70yvSzojbnExkON5mDszehIEHnfBlL14eqImQRiUKlGQlP55T2AKSYBbpKFJtzy+/aXp\";\n        sout << \"SxmkYMQcvFD+AH0oaqJFaB9JBLT7JW5D4ZwTHpMX7AS6W0LxgriTgPZnSqVgosl2DZLKBUt1zXjw\";\n        sout << \"dbSmrROYcUAXJxMOAj6jNlv7nMkn2xV28QS7lFE+aq5yBIX+UBTF1uqk1XI6OddMKrtzh0SH9Dey\";\n        sout << \"q2NWoOiH5YIxHHbWx2c4fiFrSCo9v2JQlk/rv0GKz5jX4GEI9+UPWzr4MA6GzJrYS9cydN/NXwY8\";\n        sout << \"lvHx0e+zI0aiQkbZb3hNnWsjQ5q2gk2pj4yT4zCFhdL9NBTAwWrWqjSi/Zf8BU5R23WHHMMPBfEj\";\n        sout << \"1gX3IdAZXw6tNUseFnBithp1Zo52/Rv+OUyNIC5o9whYx7T+e1Yyr2ytlKeiAHOWmiP8h+Mqnb0l\";\n        sout << \"BXYuP1fiYcGClI5Krh/05hb4CCW0n385qHMIGDiFTw1emVktV9OTiM0Z5M8PUHDi7IGUyrJcwXyr\";\n        sout << \"Bjh5HwdrsCA7NdLqE+8QPYnAPj+rMJWw+xrrlcPSpRBTTPTPiVnn/PXL6khN9lBiwz6Kn+X61bhO\";\n        sout << \"8yN+OP1IWu/DZUzauOoVqhEPEARq316Uj15VXoPpy2oa9/L0Pqzna3d+8/VxnSlWWo7i7bWEXbc5\";\n        sout << \"N9OKxooZQ6XAFihvJMIsVvkYp0oAQ4AIoOLUSm0w0ejFIWsQ/goNmLj+CQneb3+YUpdYtpLODhln\";\n        sout << \"/4HgBsPjGnEug/fzuWbEqWXb/e+VL8RUX/r9nXe2rGeQtdQkdqsNj8avFShnnth+UNk/2TRAq9Cd\";\n        sout << \"eDYJMWOQgP9NSecba1B8FGmBdvC6gRsp06uKfGesrktOPlzgKmZPoqsjHhrLLV58KwTavZSoIriF\";\n        sout << \"Mzj6ZAalNMDEqUGuhtXZrhTVoRiYsy+3jjJ8IubSS/RxiQfPS3+3nudS8jzA5u4uHJcy42t04z/l\";\n        sout << \"NkN5/kjem3F1fAu79/16XeDD/wk9A7FyjqsnyvNXsiX1yKcEC1Bw/yxCh33mgcAlh5ilP+gWc7sg\";\n        sout << \"QQXi/dnqQebktoqyUYklPN/cYQpCQhhY+YRp1wwbLJYWYrBXiN3TbACI1koRROZw8pT8YKG4utqc\";\n        sout << \"P+IjOrAVYg94bzGeuRVI/T+mpmGHs+lsgUY/WLx52PqnmLgBORLHZzM1sFp50ALnbYah3gAR19rz\";\n        sout << \"twGYVQXIIhK8rewz/RwJJYwSvilMiJNx5UqJc8VFaEnwKcr2QTqlJ9FezDpuE5kvqlYl4tywsnwU\";\n        sout << \"ta1MB0FXAC86i+4pXWfaRt5Y1g48PGEI3TdjkpiRJwEQ6YGSoDngFX5K5l+rZePE6FHNLBoRcIp1\";\n        sout << \"5aNK7cS3MPyb1MN8zhjX400wFp208a28cBpCH0KmHvt8+ip26ejS1C1/aLvdz9j9sQtixw7JU4Jb\";\n        sout << \"ytPOVlxKjAzFFFdaQnVEAkFCKetYCkMzrARSzcLQJcBhhChb8NQDZoQWxe2286/y9p1ImU+jHlzC\";\n        sout << \"iTREz2ADRBGQO3JGz2h5GYjU6YjZn6ojyUyMECTZASV8RbvNy0/8yYPNONYWm8v4/LLOUM0fq8iv\";\n        sout << \"xwag9U6L0Y+TWtW1YD13ThbTjTrg1lTHKzyp6KeGWNWGH141FgXz9+r04Qkvulcn+rGimg4SuvNJ\";\n        sout << \"XLotrbWuhULd/esyJIAqfTtHzHZMSBoQ0WauyWV+so3c2rGDjo197k87SJkfGp+l78kqj03jh6ev\";\n        sout << \"WyjhQZizdnuNdBpm26GnuDYmZdEaOAADCtkR9dvMWdeNsDCjyRcCbFEPiUX2xduSbw6aulm6mW4l\";\n        sout << \"CckSOv3l0/pfw8bTKEszFqeXiPEI2SwIbSx9R1nWd62VVDrYmAkAXzdJ33QOlJm6YJT97+QuU+61\";\n        sout << \"RVXpRanpmC4Eh3jEZKV2BWIuGPXzrDGgAHoHNhRG6vJ0Kp3RqaxFv3cPrLZdxDnQhZQH01O/dZ8S\";\n        sout << \"swcpb3/D5GdWvUS6MsIPhO+nhoabkyxwvbBNzyaLVDoXZK6taVT2GWFyYqguu3ubVBGd0H0Mksh9\";\n        sout << \"luAh4ogG6drswOFxJhR4S8VIMkF3x8PDUj5w8WTC2nlhxIYVh1fxvdj8fEfIH7WzBElS8vpZ1tXC\";\n        sout << \"1JSgHngiEYafDFX4OJeHxKFu994g18YvLkJDdQKzTDvOiD9TaKnnaSGGXZuasKTtD9z87GX4O84P\";\n        sout << \"rye5DvbYUP3bZx8GOmhf5YsaLI6b5m+iX0Mm8ulB0hOla8uE6EfLBovorLCKke5iPFU/gynxeCkR\";\n        sout << \"8RL9zw58ATEm3YuzE6nDNaIekqV7Q0MqCpnpAdBPxjtEGo9yRRPeu8SSSGL7IGKUUcr/6Xp8ooyK\";\n        sout << \"iK4f+mB0hgO0pQqffQHkEXxGg7Zd/eTGAO/n3Acq6bjGr03T6LEO0KFJl1/m96ZEBQK/iiV4m5+V\";\n        sout << \"bZvr6xOrErUE+ih4g6vk30cSQqFvyH574K93bx/uyydqzyPEQTZ0oJmT/KoUrYti7CxlGwrqPDTZ\";\n        sout << \"AuEOwQGqqxoW097Ql1bpxekOevJPSL21snAT+Lf7JZ/79YwZu2WZnWoDQRNNm4nwn5M6IPmErESJ\";\n        sout << \"szsF5VmUs71cj2/gnK7NDU4c1kLjXSsVVnN3/VL1mOnYV25Nh/ktPRfTLn1TDNG+rkdJDjGcjjSd\";\n        sout << \"JY9Ro1Rab18UKm9nE2tWjgbNUQbzsisy9P4F7cBLBd5K6y47wRYZ7MamnAUZMUEDmIiO1SR1uLey\";\n        sout << \"gugfd3Sb93PYjImZCjulVD/w64IThgqDIgVd1BOdAN23laLSQpfuR0xW5k6GqGtiP98VwULbV9rJ\";\n        sout << \"thalp5t6mwsOdo46101N512/p70XcZuX/VyFxw3bGO597RbO2nj+gM4UanMOfTEQch/kaJsk/WTu\";\n        sout << \"m4QMSxd9SAn9/aRXKR55Im98Fx/m9q2GB0vn8RZqfqHAqjmO6F3usDuUFxk0kn5Hq+8jXBephw4/\";\n        sout << \"YCOP8eBKnY9V2k2bnQO/9BWhCyuwun8huNz6keaC+qa9PFFwXmAf54BIYdgr+NspegaRej7bOISM\";\n        sout << \"WpHZ77YuKL04uozXUz6B+0Jy/zDzI9EgLTCk9L1CUpGPSoNGpDfb9VqkOdTvjQphSOPB5PxD7NNC\";\n        sout << \"tV4tl1nhB46JCCEalhhsip0/ZEtx0Hd+UNxYRA+qjaGiEXDPPDyjbYYHWNRhYKo1SDJLVZG8hoVh\";\n        sout << \"stl5hebAI8t8rCBUF3x1HrMRdrRX/GEzLfx8xZgk/YAegRw68TfN9V1bY63aRS712i/twY6KDxD0\";\n        sout << \"V0DeubXqkK+N1ERAn8ygvQ7EJNvGbp0OTu765R4zv8y9u+GqdmpA5E1Ti6+2l/L6008zbYQVWG6z\";\n        sout << \"ejkRAp4UjMSDTf2zTNjP76zzQQOQwsmwodggF1paT6UlXpb5HHp9osSrdwGXb06FiXf2uVo1rtSh\";\n        sout << \"Stzfee1i+BebVOqKM38qGjBhXwGiiiZh/mwuG4Fa4wOKlrqaTVEHgGm5N0uxr9by1E78BXj7Nha7\";\n        sout << \"XuDtqivJf0brsiAUNNtfUjBT5WJrj+iYT16Zs7ds6Fm60mdF7vSBrxXPNw7ZuueSA5xuN2bkeP/m\";\n        sout << \"CQ/3N3lGgTQlMNkMUzgY37ln3xYCXGcMpQ67ACMf4gf3l6FhI0S+JMwzxD4XMZBTxgt/2YX410Ia\";\n        sout << \"ZijtokULoOBQRqLjxREcBBhm+tpSSU5cRb071EVhz4K+aSN7PfcFOTMC1mVGy4cibxeRIq5Un1o0\";\n        sout << \"NYSkHLiVCA4OCLkemWvzxswd9Fduc9mK11xyqBPu688yHH9y2e4Fo5YjiKiZynd/kydWuNsYM9i0\";\n        sout << \"U9ukHpMFmrDmIPZJMGDgZm0I2QPvoieRcpitQwNYh5x3cvsEs3eAAc4mfxQZUR+v0gClhfu7wSn2\";\n        sout << \"XBPPNVyzE16RK8q96Z+w1paaFKHR2t4TRGhmeCcxR3vS+jvqpGaYFJ+YJe8hvJYK0IMZTBSPg6Qx\";\n        sout << \"Cx/cwlr7gStMvrFBKjLGDMAsrw0OyDbIe6/E3Erq43GHsAplYSxYAvOFZUwX0b6VkfAB8CsBnRFb\";\n        sout << \"jnZmZP+cZPIySLLGJJm/oIs/Hy1wYuyn2XpI/uCuBDZifE6fnNzdpzQ0BpH3qjaIF4OV4gghhruD\";\n        sout << \"toj7yNaS1FZl8IhQ59Z7P1eSvQNulTHYsfBw6E8RE780AO+aRHAxVtuS08RWGrde4wV3ma1NzMaT\";\n        sout << \"6fHsCr9IYY1qACpBtyGz389+cnXpeN2VZczNw7JBx3VthteVNdpX7cpftA0e/mazMuKLX0vcBfus\";\n        sout << \"/p3Vj1SxPevb5pslgkfBTVcFxmEM9Doy5dSKQ32SVFgYwTppEuyviNKuUzQWwO/XhsL50gcuUhyU\";\n        sout << \"ELpBLIkpABrbGRa9K9ye5qLWYYzzBzlPoyhEwt8cWi4hVnafg+RHEJ7lXXQ5GlEMlzxPJw18LwZs\";\n        sout << \"jjbC/PE4abuILrfHlOygD1CqQeYzzBN+gwwaTbmquBtZyIMvGr5FrRqz6sRP/W2OvOBN5iVSUa50\";\n        sout << \"VjKdnNUwSkeLCU14Lp1zN0WQQVVNeR3o1JfJsGvQNjD74MnSlHTFSUYloSFgHbM2ANeKgiYN3uB+\";\n        sout << \"xLb+hRJPxIwiTshZyclnLmv5mh63OWU+7afdA07BMdmnK77uFB1rdXFJIWUBiUG8u2yqUk3PKVg6\";\n        sout << \"9rJYvVu3eA7mjBqRvL//koo7VJt6g1Hj+8lnqu71OwsodU/t+W4tmcIKP9S0eafHEQC6hYCu8b5v\";\n        sout << \"QgVuWf1LnTXwTGbm1ohar6OTxyZV07nJGC0xscQ2yzhxnssaCoAw5xFUzFrgo8a0J1Nj9aOaV40C\";\n        sout << \"3y5lP6NgiO+3r2J8wUcKWEVFLHDAYMXiMfe3XMp9/ERswAGSkzfXSxZN8T4RPorh+pjPH7sZJExm\";\n        sout << \"o4ZOdqaWLdLS03+0kRuPXm6FvZCaMY7Hz0e2Zv9X22KYmXluGqcgErFTjYWhQFhcpt8oZA5T3mU5\";\n        sout << \"NDE3qI+bgtkN9vvNbhIrrOH7mKm0af/zrHA8nnU33sc6Gnv0wfCvolpiyTqla+HU7rwapX0+Ge6j\";\n        sout << \"SZZht4l8OPe3/mSmwGjX9U8xWxiIhhr9VbVxZZ9UTnAhfcceB3TrDA7F2SxGmfBSRvQ50uRp9Yi4\";\n        sout << \"14Sasx4kgF6e2wJh7TBRfDMQM6dew3rmIn1p7l8f43AcBe7T3rnWB6UJ5eh14+xb6HwyT260Njvy\";\n        sout << \"vF8Z4nTq/1MCLv3c4lQoO8yuhFA+J3rWlYTQmc2ilfWbYpdiAOxT7k44QYoHTZDS58anIywl9J8Z\";\n        sout << \"uBYa+giIPDINPDLGNobNEPl3kerfygAFfVkxd33eO9LwDAMGAZmbywt/OwRmraCFhT8Qz9jygFse\";\n        sout << \"mT1tZ7+hF2rfTvyF4OiTz2nutfzVvYQ45DLjmbHFQsHMVGzU6xdLQlZYWq+h5tfVng4zhwIge8tB\";\n        sout << \"mA9ndgrTZx5tspm45fVKTjE3MYL5qNsmzghyfasarz1MOD/2wml6uzWZjtljHIzap5gtIchaIF3f\";\n        sout << \"JMOvFu8Y4R0Fu2UNkbOfy/YLRnKlUHEChwTeEavSkaHBkprvRZJuMsIWcvEZHDIWdRte0qfNm9V9\";\n        sout << \"zWmj4B3RchqvXh5XsoDkMqergDisI4gCiHFIxzzfJBsX8TQDUQIvAGk0pc3ib1/6xwCvLs+NXC+8\";\n        sout << \"0sI9e/aruBe9uEXGya5n6Vqy8z9soOoBCcFqc4B+1ZUOyN2zpIxVFd9/20NKmp1W8RjRforBvF7F\";\n        sout << \"2E4IkWh/3RcL8tNyPpWkAA7Snlm8oO8L5cc+lMx0ph7DzYX5NcIc6V7otI+Bd7w8xLSVxzfX3Awu\";\n        sout << \"S6bjrU2af39KbPFq2LpGOakR+1gAh15sd6WYscozdkSZu7kGpuEppnuMxYFmbMrCxtw2lDt4IwMY\";\n        sout << \"ttBHEP2XwF5z6DQpRqsWBMcuBbztZ9BNa3y2aR8pASldncrnRjYQ1Iq6KGrHeau/uq80ui3VPbOD\";\n        sout << \"IrV/JeNFGet12rX0zneHBGYUxG+Pbso07l1fJxd6OgaIrwVksovd1psBmD6qYsbc3V3dJLacNOdt\";\n        sout << \"fvFnHWz6EDWivzMDWvumzAO1JPVFB1TebaaWaINSxaxS3h3IKUVPTu+2Ytw4Plwt6fc/LakedkFH\";\n        sout << \"fxE4uN3LR8Y1bKQN+/VvTHXGUtf+UyZx/VWHaxuiqoxXUazpT+l2muie+/2l6v8JUCBTUYwa+2W7\";\n        sout << \"WWvrBxyliD2V+KaN4dybWey+3RIp68UgV0gP8h579kezx0+Q2Ku60vjCIKJ4vJB8Gt06a15lHOmx\";\n        sout << \"WcJq2DmQuyWTXsqaJPuljuHUhqYWMPnqY9gi53ddw9SwcpgE8cCC0cG65FKn23C1Ihh5NnuBohYp\";\n        sout << \"ly/QVOFi/rGW9kKrF9FW7C93p2DxgBhygKC5E582EIjRXm15bQ5bUSwxfYfQ8VDCPlL1cR4yhpqf\";\n        sout << \"CpAd5/ls0MJ3SFgUS4e96011A5intr3a3UMPqdMKWrwCW6cP+7TJKC22+LwvAvyS2dI+NdyLt0qY\";\n        sout << \"o2t9/ml4u0bbBjwl24o/CIvm7T+045fz+3h4yrKYYPSbHPgGiN0+oTcGhtjBgtil6WCBMuzgEn4Y\";\n        sout << \"zVaTD4gQV2l6Cnpi6fi3ZIOwuEi8aqfRdNrPc8+Rtik2wWdmbYZ66d52HweeALKwfzIm1DESb/Dd\";\n        sout << \"qc+pz+yVNmYp5fffsjf70WrDyGWMDqSVvj3tXMkxKiKRetutfs0Tf3vGDdUEdTmtw4rEca/1K8p1\";\n        sout << \"eNpotuLSio7xp4/gz4cmq3IUEXzk7b++TAs6GAq5ddjbcTJoyRSnOhu2oetJGzWJSglrWwGpAAoC\";\n        sout << \"l5jHFfMXIyi4lggUHjIcpEosLLxntEai5cP9bcGzTw3bnnQMo2mI8bCKSrw3uzKapI6MdDJ7fXZD\";\n        sout << \"aR+zuSlVjO98VU+BugUHWJcrHneh7tRZ5ijux8t2d6y/iGeJm0gs2C6ukA9PTwSV7UxnmVOCsGqp\";\n        sout << \"kh37fINlLQWIjS+fVQZwYcm5XyzPzsyHa/x1DZ9CJgSaLrOCm8PDPk2BHFSdoYMrUGn9CSL6zRNN\";\n        sout << \"TL8KprKSZLrhrk4wtgRrTAkO9twMovO8Pjq/xgO6djfJygflU/Yn3VPYjg31O0SQLXGQLTL2SMcf\";\n        sout << \"NlIqmLEov/m6A5cs5pJF7be1yX0XneDEa7arl7v4tcvMw9Ot57OytQUTbFu2iUb6zviTVWMEMJST\";\n        sout << \"eLj7c/+RNy+lhBjlxG756YIjtWULrrdPBkie+AYHMSJ7PnJ/QAl3D126W7D9ubCjagGVZ2cLX/ft\";\n        sout << \"/pLcIuPRcRUeL/jTGshsfijbq8us89JPjLS08HMiaaPhTtSOKbyqHwVEvfu++thQZsu/3wM8f2a8\";\n        sout << \"CnKdaRAkLethTUyv2xNyQmx36Qg3LVGf5W/tzC9U2AQ1XRE5l/IoL1AJ08JdQDqHSAEAiw0LWMIW\";\n        sout << \"a2alrr54YOp0qiPcRTLKo0gZLr6Sy4jKmQqEFrPCxqPSGMe2pc/pzVuxlYhW9fDMjE1vvfzmWnhU\";\n        sout << \"SSTXpxONjtMDtFWol0pYyjOLyJcATXCrOK3PXPX50e+S2Xjl1iJezlgtdqWVR6mK8yJ63GyAtjzT\";\n        sout << \"oBIBQjydPb9tpuVY3Qy129f/Pnw/MT/6wggYCZDuhhNmOqmSRbm3runLfwSX3G8XbN8LEw94wy+n\";\n        sout << \"yMs17FWzTwWk2fMEIV88TuqsxDPW0Ko+a+OuiOQ+7TGVdOLxtqmUDW/3n5QA6Ryc2kbaFhZAhONU\";\n        sout << \"zJXyJzll6UPZfUsmAiX3u/qyTWlbB3EKngamgmD/1WNGX6ysD3RYPu2olopo9wOqihwweOtxfQYr\";\n        sout << \"QdXhUKreENZAZ/lOjn0tSfAFsB21/MuDNpuz37dI0ACfvKyPdGnFpNocIXHWmSWZbOB6OypSbzMP\";\n        sout << \"5r1fNPRk9qMY01lKWRz+lkFGzl1vbfKfSO17q073cCPouHosT+RpE5HBBf6E0yG84m5o3u1bLUBb\";\n        sout << \"8V4YyMREOIa/2wkUH99l3YksFc3eeUMzHSIoHrvCQq1CTyaed3tNbZw0rHPLzwSSgQMZAhsi5mxp\";\n        sout << \"ZnMABMsXSHdvgBRkVn6PH5rjrKAcSnikddL8F9/FXvJR21nKfo78g6RULWdlcc8tPQR0E+PyOoLW\";\n        sout << \"VR3yw7L8Ddl1zHu7hoerz+cM4gW+67kjehlzV+BAA70h43CfxsmvZm0Kaw9GOkxjDs8F5b5XRtdN\";\n        sout << \"gxh9Y5o/vlxI8f1w388jL7od20NPAYSqvONaJjF4nthDN+CqlNWjy3K44Xeghk1o4smFlbJM1ZdM\";\n        sout << \"taj+ZlPozWzYEugvDe7/9woqdFtYqCWDlIAcMGqw6QGFGE9EVwP25LeGWnM4bcSWkdP/Fc+Bpssq\";\n        sout << \"QaRpCt/+Igw9C26fM3zSM3y+RfDs6dseYokawF7xp7oo++opFuMO18Flo9dJw9HeXMZ6R8lXrNrD\";\n        sout << \"l1RWaWakmYp2KgPJYT9USAV6S0JI0m9MxL0R0t7XT23cWgtQsG1m/gLb7HT+CFNm4SYnWMGpza7N\";\n        sout << \"4w6hXTItZLuRrC3pH6AF/m8MuwdlKJEkTn0Mmu0e+MVe/DJmnA2w46oxML03wNy4qZMj0LywOnIu\";\n        sout << \"Ip8p1oLIviccDGpnXqZORZGVMqzuidIfNBSgalxT1A+ySEAVroXtGjtW/L7sedcTElNyK+aspa3l\";\n        sout << \"O10XSF3gjgcZnN7W1j3wiqePmtzL/RlZj81ruAoYJRWaNUDT28p67/k75Uhl4Sh7qWwc/mJnG9qm\";\n        sout << \"rvZSX5GiW11EJs35JJ08G3UHAUa98VEIOesPMaL1Wr0CVHFVC9eW2iHwEq6vk3JrGfsKARrZgg9B\";\n        sout << \"YDhkyO+3c+qNgTk1WMC3MXaSZg+mwqwx0TGeJRg6/+rcKr0Y+y0ZEDLz3kMD/aihZ0ictCZlcYAz\";\n        sout << \"8pqdirBd1Dbi8AaMCJTWHGWaOIxmrdU2XyVWVk5Vpc0rmzyc3ya8WfXjkdDzXKUS1IIFi34b3/7G\";\n        sout << \"qYpJNqtVAPT1TXnnM+2koRgGaCARu/RoKzl169YpDYPHVJuRJDjy6lfrKNEqPzJY9phbh6WhmZ4X\";\n        sout << \"CZMPrgnrs+0Bs///61zNUJA3fArNyessRIkZqSxnKjVOHz6/LUB7/UzJXAd/XfMYi4yNw72BSAjJ\";\n        sout << \"Z2AdnjGIO9p0E2KIOVx39bETt8l8JKOyT4JbimwFT0IN1AcvwH4wgwtKYAJ29L0kSNoBmMwaKCAj\";\n        sout << \"1I1b8usj6EM/OUjn+e9xmLMkeAUo8HM9BvLP33TuKJwLINhNcggbZVeaFSwBsvj6hEQ8dN06eLJ/\";\n        sout << \"yIGaRsni2n6oXeRUo8/TVWmNIbloEE7mQUuttR1pVBdkbJsHGWm/S5hwEmsKKOpvQo44Rao7fsDK\";\n        sout << \"cCtKATplclwuCDCPIogRMkpHRSSrHUKE4tzdA7rWWj/jaYc1Sw6hG7OaDFSWuP09Qq7klmC3F+0U\";\n        sout << \"CIAtQbKJevYhCSdWHfo4THHFR5CeuA+shfbdWyPNmP1HRA3pvo52jSsJi8HtPBp6XmGmM8dN8Vaz\";\n        sout << \"pG5d28HH76fj2Ny9McHrxGFaV/WhhoST0GDqN4PnqV1X6d05aBKfwRbqdWo2XvmrC2YNI7Ou6+3M\";\n        sout << \"Ovp0NH7MHXpLY0B+GMf+x2X8hoXkffnGCa5CQ1SwTbZRkeGjejwGhpOybsOl7AaSA/fqymEW9JMF\";\n        sout << \"1E9XEtZtzyATkj0cBUlofwC6N3N//altqBAbmDKrHThV3SDsvn+tpPiZG4+pQQOWqQomy3QAWwVV\";\n        sout << \"nZTorQIvoPMUdJWPwsVLaRldOrUEjmK0OF36+QysxIJLgj9x5uQDymixyS0Pvu6ybdB5Z+ggH+hs\";\n        sout << \"A4wt9pW2wbaOGU6jjYN42C/ehSOClqGP9JE1qejqcLRAXm+JDDFZGmCBfZRw7W6R39cNfrbbACVF\";\n        sout << \"de9yicnqvNbpaeAWAmfjrwg0QvVVmmlvsgDinO2OdZ+TLx0KKj+4+Zrt0fFfXQgUa2oIFGoeCuQv\";\n        sout << \"eyjv6ZUnkYHtJLeMDfuhaxaV6dIG7US6tdGcxKxw0/Z3Cl1AqyDSOSeZIfABudI/tNrQF3bk/x3g\";\n        sout << \"Kb/i4VNKLwEq6O1T8HrZSJzTWus7XcQncGAOJWTsuC0/0Cv/Eg7pY87c6VtF2/kltcQeH0qWNix8\";\n        sout << \"qHpkEC5Nmjm2erJhQ2gsdVQFrVjxv+irSaO7GLhuVwFgj0pMzKDQTFvd49DRMyrwb9cml+u9MZgs\";\n        sout << \"Uqwmc0zXzCCT51uF3LMqVbeDEgt/Q59+03U1N2QAJXtTScjJO97PYZSJvMEPONjSI5AeRlRqpD23\";\n        sout << \"4O5xrQGkzb31WrZP54ZyZ7Gt4T4bxdwVIZSrgSrGJt8RjREWl6LuDpuRsPgnt85EKNRjf+icgibb\";\n        sout << \"sGxnWWdqFdOLHdPKDyeCTiJb/5dc9YvjVxWINlgOMxdYpUU1OZ1hX3OmDDepo9HP5OWA4GnGXR8Q\";\n        sout << \"cNS85y2Q+DS7RF+qxSbIO7hOcNL2PyFxScBXYyrkLUWWxzfc0BnyCaCg4lrMr6uH8vnM+7u16IsY\";\n        sout << \"0f/y4nxYNholE4Q9JlbhXVTBL/ZZaC4qU+/mXrEBkUVY/xj8NqYSicBJpv2c0IYwtf6hwOFdMm8H\";\n        sout << \"y+l26vbWkXEGS9XV/dKKKLbW8EqhKxtlRGB+Tle1HnOp7HhcINVwH97RL9vS8EurSNlSWJCHc/1P\";\n        sout << \"Ui+ZsmkNIQtV6tATb57g/AaResCtNWa7znBxzJUW4stpxdxjD7fLZxyP1dSAlXDluOaJ3vaUpdnt\";\n        sout << \"JqkG/gHcvI/0DK84ddN4VLKIZ0XTrCxvTQJLJcUhA0ENgzdIPQj96CN1XvJ/DdFxx4YKBnb5qyA3\";\n        sout << \"51z6P84v5wm+ciOVpTFERffXwtPPfro5z7/ZWazbUjB4AcOFxj5Sk4EweqTrVSD2Ujv3quBT8SUj\";\n        sout << \"A8Mc7LBMtANusOZeMURs5vqoI5O5hwicxsnqHJeGe7FMRRVH9lrM/+3W5dfm+jJ/ntoZJArHCrWQ\";\n        sout << \"wJqFWJksHTraWTJ8crxkGSgZzFhSHv5pkz/FfVPRW91XprikZvTlVhgyTFbB5gVGeEu1X+M1m+29\";\n        sout << \"8Gqo/AYNTsXS6KfOWnfc+jfQRkkjiLsBS2vsnV255hPBz7Fvr0mqaN6AawiESUSXcFBnfzWQbOdN\";\n        sout << \"wzA468JTsVoOz1MUXZ71hOcXpGMVdKN5ABH+8imVfDYGVUUTXv1e1Z41jrzXVphOQcQA+bJYc3mP\";\n        sout << \"K0HVQQfyuwo73PTJ1pINwbi4OrAJvTP1vEuo9xMtyc2d9zIN5lVg0gTlEE7uwGWVctS67onu5vd9\";\n        sout << \"cQ4/+1axVD2yy/Z+s9JGRZ78DA8rIUqVhOTWNlqmqquxf/mh+nY9Q3PdHfcpNoqc4g465Xe3CvO1\";\n        sout << \"cBGJT0vnZw1vV7rtQ2FqAB1LPAp0f8nIT3VExu/mABWauAImnDE7ZiEnOuiuq2vdS8WspLMjktCg\";\n        sout << \"vlvwF+7AGxfwDCImKSzh4Ph5AA1VuYW3sVQ5I3XuONfappCoJjZwiV8jyKC91rHY1/jP4eMb5vwy\";\n        sout << \"8T5ciRyzv977mW5MK5sx3ujnlVFWr8y8VDhp4qmhnvvswLIKBRbrmW7jkG8Jg1YB7mjY0rP0sVJl\";\n        sout << \"zICdb33DVPWxgRHDjyO189HiKWkzbH7JTQfKOBQwufTNQ4v94HlyUYNTzHg9S6nqI7LiBq8zO784\";\n        sout << \"hGYDRvfB37TziuwR5oHeQ0IiV3x79V0+qLUHMY7ZFpQB+LnGcxG41kvposK0UBUCPDLKsLNQDSn3\";\n        sout << \"ltl6K1uTz/4gjdLjNVlkpO05xJXjK4JEoG+siPuABINp/7iLAgYGHq2G9p8KmKiu2CLtN/g5Aa37\";\n        sout << \"pewz9BkOuvCHm+J9/V8+rMHTCxD3QT962/XOO+iguzglwO+YlN3BpWTnr0VhpQN4ZZZcZcucEze4\";\n        sout << \"PgoLS6CcGSP6xrMdnasvqM1kFCvgOn2ROITQEJzaakPDaB7fzVIw6WyusM85BSNnyc8XT2RkDJaf\";\n        sout << \"VTGEMba9qIAi36u+pC/PH6XTEW+x6nehFJu8q8e7B+VrnN9lkpvVHVDxjci3CHvG1QLPGl1GaGYJ\";\n        sout << \"oLeINwB1VTKtRtEyKENgc0MS2FMk2G81MoKGKVKId2oddu9ACvHqzQMbOqnzp0l7RJewHez830/f\";\n        sout << \"8oKpsUvl1N/b9wfTXJwN77MF/n2zAg3VSv4HInhkdGA9HRSg1JylghqBAOrqpRsh6r/TG6ByJ1uQ\";\n        sout << \"rv0aYvVdVaHQ0kHH+ma5Mlc73U0x+ncDjlicbrIca7x6y/b90emfyRcN0uEKr0fZWtcbK0+1XJXX\";\n        sout << \"WWMGGDUO5b5cJOpDzW7GJe6i1m6yIPPlfp4AWLa4M6F/ys1ONLrbXqjYCFJY4y62OeRK32Ff2zN2\";\n        sout << \"/Lw3hMt6iPTm7oiJOJjDcamybQlWOoYIv8tkEQYN2nCX7k7DD6z183yX7KtJF8Sj95nOeYpzAnLG\";\n        sout << \"YOfY00SA1cM4aLRUPG+FYrzn8UFF8Bl9UFrLXoJ/IxXOWKqrbjhsKxMvC4xriww6KZqHx0L5FWGO\";\n        sout << \"lcFkhdpx2fFeswyfjQwtyqsGsiY7MXGsWA7fA1TOv+FZhJbgCixrx1rxwJaNel8uMo6pGHsZt1N5\";\n        sout << \"Cr4CkiA5ZZ0ITa63oOGM0tD30yaSLkSDZahPT7xo5s33HNAgXNxZmYnv8M6p421yuNPraabZyJ5P\";\n        sout << \"3FtNwzPpw7Q4BPSEBoKc/UbY+mdzm8ES0nKPI6Oeg1tzc9NgP5JaNVgWymA408iLfTjxaxS7FqOw\";\n        sout << \"BCYBbz0EdJigWmF73di27QmfsygTWbHrfdqxCafzsOPuk7l+W26tfJTVxP7S5snKfhbqVNrV/4M3\";\n        sout << \"uhpZthruy0mSHtBx5CuXAtGNQoesk06k22scTmX89BgNsYJAshikS3IHg+LMMfaxBe8KQaaySUX9\";\n        sout << \"j/ULsdT1YZKTeV3NVn/Z01BxF/ZPvV33Dbj4bjEcf2N9byWwicz2CFpkFyQlXaSPPSzMYYtSPCZH\";\n        sout << \"QqXL7ZKh1Xkgh68h5WyuoKkzDXGuZcl0bGVWXSOfO6gK1Mz22to6vJ3lfssNBUV1mxA7Yos1bUb+\";\n        sout << \"tGBxyzoBmphWy8dFCdE5vN/WS+w7VV6O/JQ6j8qbpBn596kNhL4iaK9Lzh0yXRR85nqJbi8bkIZZ\";\n        sout << \"FWskXD/A31jO2IUZKCdB/iqtIuEFZQnq4LLgCTlwF3GbxPeZTlJ1yKcy/2e7nIHZ7xHeG5tzyqjP\";\n        sout << \"oi2AAttJbrL9n4Ebk20aqzYxdYUkR8DcflVhCjPDfeczGwzwJxwznHHhEV/OuxZpWYRvTQDOuUzJ\";\n        sout << \"Qpu+291rSMqntqfrUo7uxCGJLmyRwWqfesAluH9y3GQco+V9yYzqf7ekdNpuygq+htLNc2lG6deM\";\n        sout << \"02oxJHjYyjDlG48zlMEFy9OhLLLPvFVmQWVL/D4FwAwKSQfYWmkUbgqgB0QwHBFSA+xqZBWZbzoC\";\n        sout << \"3xLt42o0hhdlZkXEQtGhtaqMfU4rBbKWxKx1gKhHYk/Gzba+PSi3J0e1A0fC4chtUfWc9UTZT0HO\";\n        sout << \"9QLCXzuC90KrYTYOeaPSoxfOm2aboXBWQfyxZGX9fKRdLgfJ9+8EHw7rD2TUTJueSdfvVahIRi+t\";\n        sout << \"eiEAG3CWoToa3S7i3tpR+YczkNVTl9DCuwD/QMAuPo2mul4bdVQt2NVnoz7PKMWim/JYSFPlJBXP\";\n        sout << \"RaKg8manuhMoDfHTVx3FcToGnIDBd2in/rfbEjE46d+98FRs8p/zhmyQ6/+xw34DKX/NrnU42qli\";\n        sout << \"1+erGDbJFhLmIoU3OhYTiABG5JVefsXQFgIL4kSF+Scratkn+s1aW28PLoooaClnGF14imxCA1Dc\";\n        sout << \"Y/O0HqBFR5lAn+57fsKP195CJBvmyPR+UE8pBE818w09TvBmN6onwBCFtsrEnzTmstINfz0TX5lP\";\n        sout << \"7eOD6+XiZM3y+5YBEK140cgAUae91wD0Hjz8chAlXmgE8xZfalAjHnS1c7ROuPxV9zhj5AjnXV/Q\";\n        sout << \"7Bllgaqoyl3q8Sc6eXgEpJMz8fyZ+LfMkKkMBycdjKG0AZAkF5902y9b1VPVIhgIHueHDt5irhQE\";\n        sout << \"2slLN6pSkRg/3FxPb97BOt0/zt96EvehPVGoKs7OlOd5C6tQLWio1Eh9IL67ldEsXOiwaSMw8QLs\";\n        sout << \"wAw3Vx1VfWnDCReIT7/yxZGHmEGhjdtqs+gGPtZ5jkIp0l4QPQwLhVL1tC4RSWlt8BR2Nq0Ivon0\";\n        sout << \"E4t8jhH5zWeLYZxLIVkyW0SKj5xi7s4Xo2XOZL95m43Kv2zrxzNngy1oPOXTAEUaEwuRKmo90B5k\";\n        sout << \"xdxVS3x9BarxlfUKwNBvwQ8OVmJu6VPWQ5hx++9ZLDfwK63V0gH0tIU69q3diMOjXv+fmvQe28cx\";\n        sout << \"iUh9o3Em/w+7P3DTZu35eSPUD6yzP67VH3pDvahh4uLzes3bdTYmpo39kD+gFc7ADodPWp2E4787\";\n        sout << \"JZaS2A+efTMt/OPen2TV+wMSSK80nbAta3VE1KSQogWp2bFPi0NXqC6GZ+bHV1DVnw5YGs28V5Zd\";\n        sout << \"RuuIzTLauK958DBeAc57QbcAun5sEsPtg+CICI1pcOGhv8hdLzT+YKcuUhji95EAYzCj41nxMM1b\";\n        sout << \"wP1rH0TG7jaHvET8IY4dQb5VvzNXVne0FExHIyIFGIUWoyQgjROX+cHDLe39tvjZo2xs27/CAhZH\";\n        sout << \"dsrgamGD6wj8ZMH+8gHzu6b1yy2crBAw1Ot2JdNhW0kp4DNdFgjqMcZVCfDM8qRZ71DBO82U9QU9\";\n        sout << \"hXh0DCIAyryS/6W9mY2I4IxPrbSL4RkmKzhepcIoui74zu3p+lKY9LgUxYbGNOK46S2olWwJYf7Y\";\n        sout << \"qkOPWcN6yen8rO/9Wkvmxl06qSDDhcYdsc5S409X/VeWz67rJ2vNDiyTKjUJaDWcSU/znMnhtosm\";\n        sout << \"QT5LyX0ZVd++zQvXfjSjBLkJrki5vvKMZSUKhiYL3mIapZpcnsOQ1WRwnmSEave/MidONmZEP4rH\";\n        sout << \"OgS00fnCK7eAWXsZb/rk7tq0cjAFsNeJsHe53E2hJK4TyaYcUi1IM7ZNSQ1yqMYbcFn5bEHBpuxS\";\n        sout << \"+TUy1QppziHZ9xoLn8nOxRstSGxrhBG3WjfMhOwR6JNOe4Y1RDfxVHYeo2BAmtKUutztKsf04UNy\";\n        sout << \"XTP5HSaKx1tZVMDn2fkIj6W+s07imc8sg68Sd1lwJx09bG9ggOw6D0eouy/IeJi9YQAyZT2BqBQ7\";\n        sout << \"2D5CrrD6hqhVF4IVhBPCkJ8+9hbFs5EA8XhItGVBPyXg4/alIJq2ZeBsjhK+tuKMunwOl13sxzn7\";\n        sout << \"iSO4+wO3geQ3+SzKShzywLk+uGm2BdS6teWxatVdm5hKNDirghiEzqdHdwGSoZUlLMYp3KTdzpMg\";\n        sout << \"eAAPELcLl78jObmQkun0ECGaV0paIRhytIRpV3yJGmrRIxWNI5WrqLtocN7hnm4fTrzdlSGnDojf\";\n        sout << \"CBmISIwp60UVjJijLDTVYBIP3VcwaoT9V2F2HkDZ7ifQUTvHmxRDFHuquws0bNRjLSBSPa4jh6th\";\n        sout << \"6h62qlgbHQ/BBLIUXi/I12CwYwlg3ute/qQJIpTCsRxf4rgtEjvV2dG9ltlo8PPMhOd9fkqQcvua\";\n        sout << \"BJaZYLYw9rxq4U4TY/IxFQe8MGJ6It9BOFHD83v3awKPKP84inEWXAkFyI0YYmzFjW/gofECo69R\";\n        sout << \"Wk4/2wv+K5MFEEIzBUGsyrjz0TmiKvzEJ08KZOuWtFXeF2LUGvYeL3TO8FyLRpPnCAoErjZzVAhI\";\n        sout << \"9Sd3ukmv2oZ5oYk52HrUQZ9WywqVgFL8r1KKEouCd3iNhmb+2qUSh8VcvAncWTQbn8yjpGe+kwUf\";\n        sout << \"HssRskQ0nKLIvCz6JwWEjoaglBC3PiJ0EOwDLNP1fKXqPtcPglnu6aGaTrb/lOTCX70yvk2XpdPE\";\n        sout << \"HzsxZHKsV2LxqDI/IT8yIxvM67v8b9CSGOv64a8MSBZ5zYOQR0hunA/iYWfjzuvX5dgW90GnM5ZR\";\n        sout << \"VWoq9zxcBEr+Nk0HlWHpPm3o08OPGmfx/ndMbLLtuH85q4/7Kelm3NSXLXfOxjkRuSZkcAeiRk8e\";\n        sout << \"64X1nXADtf6z1Uaj8H0JfREe91GPSUfyZjwI0pQLDnnsgGoG0DGn01qshIL3ANXsLTHDsdgjaFGP\";\n        sout << \"zZ2f/7V/NKLrJ6HrVpWoQiwhNGY5OYv/KXa2q2XMGybUaoONCdnjGKzPYyXA6C0utQNy7JTKcbgV\";\n        sout << \"/71QilRGXbV8OPBFLLN1VNHV2rQJDSH6UL4RYDdhRSsItpsl2tMJGGS2RLH/FwEv0jDo9e/218Fd\";\n        sout << \"0P3DIy3wAevcgLQu6Ex2SFlTpZcvO+yidCgCv56rJHlVxgN7eSbcKS/l7CiAcafTsjsNm5VtgTx0\";\n        sout << \"CM3ehbIeuPrV5GqbZPgbF1akOkP9vzeNsGGW5kep471Q+xn5o78MZBz7YsMT3IAHd6RViNn/Rrbj\";\n        sout << \"gLWyleDnUQ13gY1xNXl1SD8xaQVvWvvpmlZKyB7uIPEL2VrDZSxmFYyhdhK64yb4Nvvawge8jIWM\";\n        sout << \"a43Sgazodlobk0CkFktZz10gZEUobBos3idIWk0hQP+nGOLhiGO//fwpiplh+g6NBMLj6vI3GoHZ\";\n        sout << \"MKoqqYh4LPDaEtnvILpMCP5NJoBbxNLrUALf17ObB5Kgz9YQsxRIhtrXoyK0XdU98ws4zxDGn5Od\";\n        sout << \"Mj4Zpw/QpI2cCvc6fiue8+l/6BsFse0JL8pvOZDYhy73kaVarhJhQgoZabwnyATtN5VltM8niedj\";\n        sout << \"reSbVYi75bWEdYZrO1PESHmhr7lx+s4gBJQd7kz8wbRADk4dJBf8QDccgMO2yxf6biY6ezjB9GtZ\";\n        sout << \"DnGrIuG867zq9fMbooU1PUrXEMYkeeccI3d3ClrF11AiOxFAh/tSSj05pwl7UWVKDXJrP/T9sl37\";\n        sout << \"qW5Uy21+/Mi+kNMCaunB+fgJHsjvoQpwSmEb9k7b35H04v/qe1deEKPua/xXlawyTt4vv9OFwLFV\";\n        sout << \"ovcegUF44BJCRF7zlZnLMzyveCE2Uizux/z5zXOW21bFEaODnvc9N8oTl7XkQAyDT67JrBC7WbH3\";\n        sout << \"g8lzwSjSyC4paGxi87EifET4QFZ/wdhP/mP8lZXzkq8xieb2ad9dSCHS1T36XB40s2QmiSu/dXNN\";\n        sout << \"yaGFiWtFCKYhie16fkeBuCuzcW98RXOUQYBVCbSaDVM7nNTXU5+2B5NfM6ts6+7fO+ovsJh74pGx\";\n        sout << \"HrPXVdWPNb1Y0v7YhX7fLu77zpFbr5Mo1tdL3H1P8k/y+ep5/vsBE+git78nNPeoZajrbKuf3QtR\";\n        sout << \"uKx/sDQrnt3opQr2k0BEt2HZOPeDw0HuPJnpUNg0u31w+xWZN5YsTO6HBpfg9x5hsYX9YybRFoWJ\";\n        sout << \"bpfcNHrNzlc940Pbn7cy/XKiIsegvY8JKScIsmP0pnv/3rr3M+FDocBoe9QDnj7a044KpD2ghnwl\";\n        sout << \"4uJjqFHv7RoGkY4365yAFnD/vm7tEvO09ibX74jzreb5lcSu/f0hy3IA2IbFEYiY1MBL8MPDBh6h\";\n        sout << \"dKL6Jf+UHWrz7MM2bSfDzf467cr65Pt+N3bmX/BR5yd5sPyaiqQhEewGImg/bOiaqpRnIKIFNrF1\";\n        sout << \"dHziLHvI5n/RvsyKPc1ScVFFHdGs9VMXR3ODzG4Q4wNyGYm8Bt9ciTw+Cd1VuAODX8fjGFhCRq5m\";\n        sout << \"wlIDo6rwxR8ME68IXNMqztq1JPQU1VqEXWGAOBIewAYPLOepF4PR28SUgEGqn32oSG6hutM8UAK/\";\n        sout << \"4LEsqVBnc1XrCczlpF2vad4Oux/Qd27JfspaVThUqSc2x0kY1Ca8Keggn3j0s5GCSXxzsQh0CuYq\";\n        sout << \"jSJjKBVxbOP7XU9EHt6w4/9SOnEmd2QVJ26x5o/znpYpW1zTwrIG1ZhvU5AhBtzFtlLEOs1WzBH9\";\n        sout << \"c2jFEPc221taxwBmLaOqa22VULgiW0zJ0nFkXZ4vfoJghqWOK9N9ux14hpKyWUtPPwPHT+oqctBf\";\n        sout << \"RzNzQ/ODTSIkbFdJzskMR10TAYT3zsY27dWLgdAnmwXE1xr4SCbilLOEZcsJJDEX+XkRUsMbxKxp\";\n        sout << \"Cr/IrdTuAzx5MogSWKsUj0W3cT+EG8Nv+iHw/q5PIag2y98b99gk73KWnswo+QXx6nTCwuSuON2s\";\n        sout << \"KlVN2mvKk/t6dNJCbLNQoEnIxoHumQimOrsmgtD5rTXK2fR8rZlnBzUG5Bp/45YBEK2a4JMWivLu\";\n        sout << \"nY+zNxxg0wslFV8OJaH3yfssBMr7lzi3jX0D1dCD86mSslQZ9hAx/pkgNPogz8KDbmoQjozc05Dr\";\n        sout << \"nUKPCCTYq7OUxpGXu9JAFsQsbqnWIkqyxAg3+s4M2cc9+P+dFpb99cQAHDIn0LSBR57f6o8lojFg\";\n        sout << \"nPtdvUF4gNJd1EVqy2ERrWmwRQ8gnzLHVI6wJYlJVUa7p6gk2yZBz4yRak1JJUgxp3l1goGG/0Ci\";\n        sout << \"PsE78UDJQW+3FmtOwLuphs51+Clq65O/n5RIeLQpQ89mh1govqglh7o7nHyyulhQTrEpBEvy2GWh\";\n        sout << \"LhFNp5FWc1ZV/yl4SwQEIbSpGk/MTmlPM2vZcOwTGNIxHia1PISF2LNDMDMmqQ0N8y/NlaKha2T/\";\n        sout << \"ZfRhOQdR9nOgI0svhZQtke/ExHkpYNHsF4bbGisnGyzmtrKgr47s3l527s8lP8Pxe2g5cgX1focZ\";\n        sout << \"aeI+CIeKPFynBjP5GmbCoBpOBpFfOgPrMU5cPMvBktXq27wF0eKbZ1pi3WvJo5Yt5SNlRbs8cX6V\";\n        sout << \"dM0WDcqw39ff+2ztBdDR+aeFRmHelayiPJ6Rmd3dWgH5Zk/vIGEaSsc7/KfYuJQXkca+gR1SVE67\";\n        sout << \"wez78yJbRDcoXiWhFOC4ilWR1DDKgTy7ej+qsbEtgEQcAqLukxeAnICNaIYzrQsPacqSvE6MLBiN\";\n        sout << \"DcoQ5TnAjtFPGGkkhYH8TwD4kTMQgSDXt5yqADxbAMLu+XsmgOJzyAL597+yMJm0w/COAOvVYPRw\";\n        sout << \"kgsDb3IXuTpW+bL/xGC9RvOefz1UoxpwP7znW1IYeltHBqT9JLiGLMQSRTl2x+OudBurZ66LiqQf\";\n        sout << \"TnX+HXrN7MnTdshMCQ339YwnY6b1baYKnxVwNdIUcLnpyVqMCKZNu92bPJsdj4af5nZuIP8HMwoR\";\n        sout << \"g29BOeXRb8UNtWd/EMGiuHiNwMMhpDBN/L4H1f6GS6ZeNobN9k613HrCeJmlXQDBWCHE66vVsAhX\";\n        sout << \"X/Qwi0w5PCLwwpoIsgMDnZDLa9ZCyfBez3VP48ur6Qs0llb1j5y2gHz24yGH/fVlWPdnc0pbKvFR\";\n        sout << \"KKW9jVKicLU9NGaOq5vLvBmFMnx2YLwhGMIlOgnnDLUkB7wCY3ADrQau1lPLfQ4QHr919kbUpCmq\";\n        sout << \"3syJxq1j5248HvzVQRCQV9H35RIQGwd0fjwtK8Y60fxa6W0tD7B/hf1b9lrodaHQL4gYt9/lrCQU\";\n        sout << \"LezUF2Y3HN9LxAWQNfoCbYaz9HebHTfCM+ynCUXAXabGngBLCat1GxbYaWlbotAXawMKxRplVYnB\";\n        sout << \"mORrYoF3NaBlDPznNhgiU0Uz6t7Nh03r3wR8NMho/VNPv4XggWVXyyoNvqY1NDZVtHEPVaSlVq12\";\n        sout << \"yUOiQ2qEpATWET8P+19RL1KAtCoRzPcuY2Ikir9MR8sTbog1FWyTqZN42P6Bx+darDn7eQTRmaHv\";\n        sout << \"DrC97SY8szr6hZEA2ei3vM0JpNWKYTOHo7pTlaDWt8gEDt/oQFPUSk7WJmJJ3DeXCGOdnRABlCXI\";\n        sout << \"NXDZx79pTuebQNZWIysOeisk2h2TXVvghE7J7QyqIYh80zqZn6nuAy05mtUT5igW4twr21r/X+W+\";\n        sout << \"Eu+dnXFU/Cw04SFh4MVLMaZ8kCerQ21GQn0NSgFCPd/bfeJyonCdXaO4rVATPw8tgbsI93po//q3\";\n        sout << \"Ps0KQWV//ZPdqERqZJYkZKZm7CNJRC9mcLsPAfnE8PRF191kr/A7BjLJu4UgxcGZlyQbi/uOJFd2\";\n        sout << \"mErOsNiJIC7MuRTh3SF5baHXsjiVg+l9m9lBGXmaSHAHBsKpGqpFHF2UuJnkWihfK1QoNhEkUhBV\";\n        sout << \"QOI63RPKJlgU7h7hi8fEzxzDbXbpWhsMwcKQ+j3UBSBzUGbRYznWar5vHxf8GQ1LklLRr+8jBJwZ\";\n        sout << \"fIPGjtKXXyMNJACNv0iulszYy3XUM56cIdLXqjVgEu41sMUfJGvbi3aP0tX6wl2GO5gptrX40j6d\";\n        sout << \"Qys2Evu2rH26dj/oCWFOqK0EKcH/Nfj/+EY+gm1GI6rSTgKq8RtD5J9fEe1nro4Sz+B9J230FWd9\";\n        sout << \"G89GSwEnpPOE6hRzubd/NyFZqe9sxVIFdNqRlOsPbXC/gJw7Gx9B83I5j1dpYAsqWyBKhalrGRz4\";\n        sout << \"UMLThFH6rJkGO0YWO2FF3Y59cWk3rS7taKomqL37407f3VWOtRH3YNhvxXI/6m0LV6czsmFHrSp1\";\n        sout << \"lkpYyq/UlH4kL0c/m/P2w8JrXwD+1SwgMtMjuwIQsETng1TeEgdyRlkRnmKXVFDfSLQSppfq3U4Y\";\n        sout << \"zrlnUiKPk511ZcXkg7TOkHxIMUpkhlSihUaBPwT02QpbcJR73i50BzQNDVQbQfMrXny8LEv2D331\";\n        sout << \"mtjKrWCWThul7ReXcJV7p3LpWuJWD8h/6dwx8WuBg4/zKPXZst6WHD/xoEjYG8QNoDDOE+SylSks\";\n        sout << \"AwuI4F5meYJNpFAoCj7qQXJKKyzyeTz2Y0nISbP34Ue1H01zu4SBN7OMvhP/Kl7RSFpc6JkV2brz\";\n        sout << \"zksgJZ4vpuqdij2S4lQfJbtdrk8smc1VWsVtkRKZzRfbPmECuz/0aNHsWe7sFyqISk2Pe5kwuj3O\";\n        sout << \"3mvWDzXBK05J63FYRnpemGdnvIkKLddEmxNecMuotq2s7fIWy2xeu1Ge6/8ILJmtwm9Bq3afgFfw\";\n        sout << \"nRBQ7dj40h9kCgGUoAx0a2oEwTdvdgHp3eEjlyGMqdodEC5F7Cn+uSh89UsHUYbxAI/qTpYekaVh\";\n        sout << \"5MRydNwdIg+3XCHQi+QGEr41DECSXUAoL+mCG6W87WE70G1BsvA3ofdGtKUxTXskdWVtyNip/qXC\";\n        sout << \"f7Fez1i7Cd5U8rzkdCZD56P4KKx7H9N10aU5jIyfba6IKOG6WEqgf92SISTXCVuQSHqVBNHoGiG3\";\n        sout << \"r1xxH8KEzApRHJF+whOvt+pP8eDVfVIdLrzDH7YP5nzQvnD1eVv6iZw0izQu7ArxMoqgSXOZlKBW\";\n        sout << \"L3nkAohU98uR9oYPGck8HNiyKzuiI+DCeu7BOg7unI0WJsn0qE/F6EFEFYoqusBXRgDVwmySLyAo\";\n        sout << \"+0eB/sUawsnUh/w0lRHBso36uynLjUSMBCwppQUU84pJ8fqr5aUfdGfWzogc/q0pFxppiexM6xHd\";\n        sout << \"P8/lVcbgKEclaNJRkE401wDUWHDmtVAHiaZA/532FWyrucLOp6IRgM+eZAtao2/hQUtwOOcaAQNa\";\n        sout << \"DcCN488KJmPQntnz9zn7Ep2ZZvsrx6fg9ubEEjHHIiRYSUDClLUqqFAJZaGrGsXmrSDxF0AEfQgJ\";\n        sout << \"aZF7CJ0WBl4qyUBcIIeWr/+u7Xm9WDnD3Aowl3/RVxH4L9ffGDEMkCeY/rmNp2SDuWfti7vSrxge\";\n        sout << \"NSQEaqiPPMHrgQ0vuGU7ipACRYtW8MgxSwxMc8AaAbhPQu8L/ZEC+/pfxDBy9mtMKnF8Jj2scJtB\";\n        sout << \"GKhZ4s1s7F1fqA/m3Ts4rfA0HLY7bAWeXa2sNAdvkjoQHMLAiP/5BB9B4vNqVGLSrislMJ0sYfcr\";\n        sout << \"t/O0wfihW++wYxK5HJWn/g7U7+lu4OZHco87HB62wHcvy24LqwNKY1w033SQJzkLb6Nkqj4HU9cw\";\n        sout << \"E82PHpVUAXqR6FRqOSGX9bMMqWL/e66vl0G3hbhIwQs5toUgg3XVv13F1o2sTzjiQ+22wf3PEuD+\";\n        sout << \"aYIYKQiE4R8kl3/96og7QmVfWoPxZiVEGBzM9bTDHx88W1D/CkwPkH389oV1Xky/L9UHd8adnI6l\";\n        sout << \"kfuHNP/geDSReFNJ3vtqUo6RnWHAFaTj+x5GDJDtol2hC0KaDLJCETOQRXUOOW371wB3I6slEKjG\";\n        sout << \"gANfqlMyzsO/7bxUw8X71uDns683wpW+Kwr73bJwe0OeP4dgwgTdTLQApMZncaphcpuZCEn9iSpw\";\n        sout << \"GX3EO37EZR2RvLBMvlHhkZSAWr8TqOALJeFEuYiduuUmyM2xh7mLw73AqGA0Wm6rnc7oZwXhwaBa\";\n        sout << \"VhwUZyv5rGMNQl/p5bMO49+tQiaIP5UXxheMCUN8eD6m7qDyHsljVQ+Madsj5iaJw5rkNcO4oquG\";\n        sout << \"mkrQOI62kZGM7reBAZjYYjf33ttAZspzXJVFkNt8geb8e9/AFBdfB2nkJebf8aAAie13umwDR09c\";\n        sout << \"44fUO0jtn43FxMBMXRt8SN3zVf4ycLW0WBYliqRrfhbOlN4wfzHNnII0JBO4wuDMC0zXnurwcLA3\";\n        sout << \"SWng9i7SI/XH9YZLdEn1cEtkTNulFFsZJGbLci2EvHEnG6D/m041JrCBRP7oCGonxdi2zaKe02B2\";\n        sout << \"LHaMeX7Of28XebQgQ3ZQrpSxW+h5FqIVNNo9EYxnqDDKyB7TeQnuISmSOwrcARqs7EgNAQ3Wbepu\";\n        sout << \"Fciu2AFnzjsW37Di4Z+L8tVWDN4nZstII68QCzlx78pYFiWD7lBQvuMYXGPujFgNGXIW+uk8NM/H\";\n        sout << \"ZWKV4UopvDx32VBudzMGJn3XPfrFqeMDukDYZXe+8G/jo8poz/kPfQmBqMSoHZyoKZ6yPNEeo1pD\";\n        sout << \"JyR5/neJsSu8rCPX61ZMuInitxMKRTS8OD7RhcO5o0kNsFwXxe2AhJm2HbOCqSnGktciP5M3gvpL\";\n        sout << \"d25K7cTMNvZIpmwH8eQmOoicl8IRKpj6qzxZt4m8yZU5yFiYzkMfEPjUwCmJs7tCZelrNnaLoFpD\";\n        sout << \"LxraAAsxLtsTcIL9ajBequXTFW3SFL7jsG8WiYRSYmu60gWPgUcmpaK+dk6HFy8SFCsaxlTmCn4G\";\n        sout << \"cbIFfJU1O45770/tHsDxNOBu/vsdp5yZw97L/xl6jSM9gTMdFbTdYw4Va3nr3L99zk9WnSYVZtwl\";\n        sout << \"C5LtQR0xUAldgCgSUfM06Y85VismlOis/GxVfYqYSwN17u3Rv5xj8JDpTxV8N2CwRXxrq013NXoj\";\n        sout << \"eDztUxX0NWUEDZuVvZUIBv9IO+9UaBHLZ834PTzKolkznv0dfedf47H18EWGxhXcJs/bqIP7qlm2\";\n        sout << \"B3bpaGxX3BbRVzuGrWRccOO2K6K1wxDPBSh03z/qH2ddZsTPArbhqlvRiD7kmMDGJzX/Y2i0SuCw\";\n        sout << \"nwhTENF7U/QfBFD8hWqi6/5rHArt/YSfPhaJyBOoRhTWgGc5RPlvMKviM7fE41Yhyd0vD4BqylQh\";\n        sout << \"iOKpy350GOo7g72UBTjlUHq0uWTX9rMpghHkZrMt2bvNzUn9SCx31vC/H7dVjcuEjCeUH4xkVpWu\";\n        sout << \"g820oyLQSkreplnhgE8IyG9OjJ07t1A2YcKHq0sr3t+TMLp23O6D2b/ZAYcnBFVIu1T2LIuX7NAp\";\n        sout << \"tOmFBbO315b3PV8bQdywYBSlIcILFc9AGlttfB2ksqGF9Juhx7UOPczWeBgaTOhBFFcBoSELVoqJ\";\n        sout << \"YP1KMe2EreYgzjVdUEAlbUh5R7mOs/pPF6XjoP++qnu9YE82r567jLBo3fmMGQJqURjgAIxr12l1\";\n        sout << \"+O9rTfxhjumcmJo6iOeK6/wCPuiD2QosXIlYHi/nFlS3qJ8d5z+tU3R9mi6v6I70GRSB4TkFuHmy\";\n        sout << \"5AX3LA05BcrjPH5LO/ulytgvkKsNIgOA4lRgZ9Z+whgI/MxvgGEzmTEyM2nxUFfzxlM4Abi210+2\";\n        sout << \"WFu1QMDXI6MQ54KGwi17BQOckYEFa+0PSrxwf0ntQcgcGnpPNCSlSATUQZKCN6E67UTP1KRbak1K\";\n        sout << \"nMvD3D9t061X0fAWW1txiUca/iO3KLYtMqAKgW6DZXuUzJdgtk2aqUYTKoI7sVkyVHo03aBBr3fT\";\n        sout << \"optSJzBz8UIRxzRauuWo6o1mCyja2eM8fn7TMvSsZx4QkIF9XZA6UNdeUpbSzwa4XkdTqdzmoa7J\";\n        sout << \"V3z+mkCQ/AaaEctE6Oi63jOlzfPmAOobY9Vp9i+ojaeo77SXu/7cwoWgeASY6zOHdN66e/zedP/L\";\n        sout << \"SNYH+B7QfAvUgBLK7QuP26mtws0qeeGWPYCB3x5+pbeS/PHqIF578D3lasqUUXwa3Nz+OzyBGXBl\";\n        sout << \"AB587DXXvbqK5gsoPE+mh4CJ0qYcUGWOhDejTpuEG50OQiGORtaswXqr86d+3vWdsmoJq8YFEWTR\";\n        sout << \"Pd+TwEF9FO3qrN+R73YWEZ5nihD5eG2Q9ABWg+C9Us9KqtlPYQOeUjwrEBhAJZ1j3UT+OKHXuR6e\";\n        sout << \"6dFh0fmlpXewt/gZ2z2WMZT3okC5JyKIMROWN7m+W+mBMmYg19gvib1KdBeBLO4sxdB/mElqdYYt\";\n        sout << \"k+mwhcuKUWYmaSmnzXdU8/Lxyvfr+hpPIPJHYLXftm1DpNHQjLY2bX+UROQ67weTACWOtfz0VJGv\";\n        sout << \"auzt3Kd5UG7m9nLXgk8ZibGOie2MWMY8C2reyrfU5sqOnLO9VNwazWvKb34cFEPKrGU1QqVELim9\";\n        sout << \"kq/0gFdbsyiotlds/Va5AkeVAVC81yYhYRnQm2W23NY62dMMgorLZoxuJV3RPVUoAa5RKRPq346V\";\n        sout << \"HnC7z8pqOsVfoslTCivd2CEzNQK/cYT/LJ7n2Kw3bhT5niBsVNyAjZaK4oI5fqzMoqC75ipQz1IP\";\n        sout << \"JwLqRuBTBjipG1Boum2TahnMriKcAhV1vAiHcB1GkYf9Bwnne8KiWpVdN54drWw7otSWxpsD7oyi\";\n        sout << \"nPfN7o9CrAcERG94IxkZJD3uY748ly7UrScLvIS0M/zcC3f0FuBHb3k1LKOa53B4Q/wo9FfffpYA\";\n        sout << \"RoixLpFQRoFkC4l2wfMenZEgaYkYyfWoWEfGD9ucOiu8h5IrffBDzs8Ck8/y32oHvL/FlouHrmpz\";\n        sout << \"5SKBIez1dkvdFTI/378ArjAwoJ0i2QsGyS/uO7FqgTAgd/9iIqeGonMnJFRPmH/VdT5mZwwj1BhY\";\n        sout << \"2/L0tu2kF3uwGX4c7fSDN8AkPK+DexcvcRBwG6cdmFs1871Ltv0A+i2UTgdk6/Q7MGnhRxnDUp56\";\n        sout << \"7cTxaOSfGTgKcJJ/US0PZjyWLN6tinlrYxkDq7uODDifVo8kEIOzYn/Zo7YbrC2FEXSqw7khbirb\";\n        sout << \"5ErpT55vaggbD/HtahzrQeYIc6lF5oVtW5TuAAdBBwnPwtYrkAVYQ2KZeGh68JKCEbKfNoAeKr3Y\";\n        sout << \"hhU51cHOBC8p6hm5T5p4JZppu15YmKxbLZIscvWCfriYVwPycUde10Nu+AixLGcaJQCr5LdWm06+\";\n        sout << \"ZJPovwV5yErl40B+WEa4YTBm9HJqYXOI3JRAEkwvioR9TotiOOqCaoo8YtIHRU4y3YOUcAdqvtIW\";\n        sout << \"Sj9eLPFLgTQ33kOtsZKDDzBJ/eVl6eSv559u23AuaeuI0ynarOjvQPw/543W/lCKibBGhuaKbYJy\";\n        sout << \"igAy49KqZ2IBHGJEOxd/7e4pnBgW2Yg7T7oeruGrIlJk3BFKQxEOO9Usc7XYSiXMVXwzGDA4huZt\";\n        sout << \"2zq/k193xAGK86lvndpmzpJ/eyVqxqGSN7yyr9o9Mq8mfVJ6CYGXgb+CybtXX1r5FfNTT7ikJreQ\";\n        sout << \"koaSxOGLvHfys0h09POLbTZ4jXBVrcuLuYoN2Dg6vpnMQSEoZzY85NOGxyCPUHXf9KFRfUe+r5zp\";\n        sout << \"O4NnC66UUzrBan3eTYs5X7DEksg+bPx4KGMQ/byJm4Jr8Jzeug6S1qV1diRpkgR60KCS8Q2zCmqa\";\n        sout << \"Y42riGdaBXcaZ3MM1onSKNWiIWa62QGu/GuwY64JUXkSTZViCgkPbieNk4J9WSjwKWPHwPq97qBy\";\n        sout << \"UcJb7MNuA5cxGXOUpUgo1I6ewBWZJvTIU4o/b+hBbBntfgacsZDooFmU2xUYycL0/ornfsEuJczW\";\n        sout << \"1dI+thnc10hcf/WWhUpOuMLQK3f34AUL7tUWtsuYFaRN+1dabnldREIXMFnZs6G+gmbaX0c4TDLh\";\n        sout << \"i31s8ch2irdU8aSTT/1J7EkMvyDZt7NLHeTRgRRrVtGg8nYbBrB/MxwqGTjtD8X7+MYzloLLiUrc\";\n        sout << \"7ST+dShb/DY4JS5RA8I0RBJbqOcMYzdv61UaxfYOnvZHtbCGlj5MmIMaPCDe4ZTSPsk1+NhUZSKr\";\n        sout << \"NcbSth2EUMRZsJqDLN5Xh8LFoerrFLNfbb6r/Zo1I4T7NcVaSKim7u03ti6xCQj4Ds4yqDLrql0P\";\n        sout << \"8IP3w1WmY07b+YRN9eqS7gFN4ReqCPVlk1qnZOzzPjH8pUPqgb+0cjuvQyJslbT98FrPljGtXbJ5\";\n        sout << \"si6Cp+zT+aIEy9HTtQ8Wq3ojrVLtjMl/aRNPb94A0ncTZYuoZCnOC75i2lLru7HOwHCdA7Acyt4M\";\n        sout << \"a7xgqqPiV13DaPpOQYp5rwKHNelo56FyhrmhBC2qQznvwqLJPRcnMEvfsg3Prs26ncYOOwXJ8DK0\";\n        sout << \"GzXkJVznLs71ggUJY00mOvTS5+5sPWwxyjKhdckQfSil9orOJJWeDExnCVZYuIWBij5VXQiACLyN\";\n        sout << \"WBKo52tef5NJwqNbjInxKmFChkX8N6en0uHyEAPxNLrYrn5I8+HibsvccOOIwb9yeT3TV/DB4SiF\";\n        sout << \"rKq/nLdDdQjbReZfZUHhjKz7i/QB7eHinoBVgLcmAkN5lDJVec1Oq9GNwqKTpM9hzHl9KZueqC0h\";\n        sout << \"EJILZgoJDs6Vy9NgjK+FYD6O/2Uv9CGfnCL47ziWfyWgLX2UPFX8DTrnWG71HfNjdlWO0oAmwJxh\";\n        sout << \"0zoURT4B03KBdm54pk6TNeoThxauGpNkK+vU6qcILlI64ZFxaO42b5rjQXtnmYEGL9d5MroM39vC\";\n        sout << \"hykPHjc2j2qFIRUQ2Eg4mtSR++AAriXGpDu3WuIygTiKMNy4Jbt8AnInqnHe5IeWgzE2eAomR8Yp\";\n        sout << \"ZkI4LCBOIPRQbFZ+DnX9Ntxqx/6rJmXE9njSqgbepHd4e38SMP9iMBR6u5fX9joI6rcRikf9W5nu\";\n        sout << \"G/TiDJNhEwvSOtgdEu3pv/urCx7CFwbkhSVz3r/HbQwup/g5FDuTxteiAXYn9TKCWXomd4oKtip5\";\n        sout << \"aZw1aIIYHKR4zNPsNPw6uJUpwKU6aaJjAjXJtaB3Aq/fcvuHdCYL0AkL5AAItGnCq3TOli3VAHg0\";\n        sout << \"zLm6OpVaCUravHHyYSuwXHB58w/zjz88c3tlOLRJO2CoFIUzvesT7FkKN8+y9itHmIdvgZCCWbm8\";\n        sout << \"uoYwp4U7dy6bBVvcxjca4A9f5BcsnZ0u3h8JRxdhMpwk3H1kt6PwEFTrk2Gb4IemrBh4GugYC1NU\";\n        sout << \"ZGgtiPD9Lk9pXqPb9LHcY4nWCEioiMUBd9IJlcWa5NOnZe+xeEHgVpy0vYrtqVHsoRAiXzRTxgaa\";\n        sout << \"2RlSne0P1g0NgU4YCnRf12ZIS+LvPMbYe3mXfDpn099AvuQiUngIFGKm//F59pxxMjZg/ADElluv\";\n        sout << \"0eOBWtYiaYVDL7D0hiffIcBcKQotLJ5p4q7t5v+7oowQ7cMyM4hvL5IjS3BqCpKNwWg3PA9jnhun\";\n        sout << \"sAVHJa9lLMk3cdXix+BKNhfq3IfqpzXAMdlk7GeKbEl3F1/+q4sxVq7sd9X9XLNR2lhJVy93soM8\";\n        sout << \"HfWHR7qaHnA/7XlDMDORDxuT7H3IKxDa+TkORiI9ldqwCEzC0ZGDBU3rBBxNK1jzXH7vzQ1vX7x7\";\n        sout << \"eqYl74NRYH8j1jDxWeQx6bQWSy0V6N+c8uC9N9HPVuH/18KArH+sEDxGRW+Hxi1Wkls6+QyBiweA\";\n        sout << \"tlHueW6h53s3Hc79AEK7gM+40nwvjCOG9vojSoI7bc2ndc+gdqRxYdUz8mu79bx8CI9Y/WlGO/Vk\";\n        sout << \"opsB2ETODt3OdS5xMTUZfSO732Hj3nQUTmVVheFbxDpVPUXNx6AAp63iRR1oYv8b4w6rXrjpj2ru\";\n        sout << \"8U+EXxv2W29LDJFC/JRBwj8JyTR9lDhARPqehW6EZmUYERihI4NZbM9mhgszbC+XDiM5rL80FVz+\";\n        sout << \"4eIA3mJrPNgmevZC2Y8osV71pnmt54foH2yERar9tqSS+q0q7PWX3+5jIrM/IDT/TBrHQ+Boo0y3\";\n        sout << \"bz8JHPnwCKXv34Kjg4NxbDjFT0G8hL1+LsNle+d+PyYPAKSLOjtzDicknXz3M6DgjwMrzD3zLf0O\";\n        sout << \"jUlwIR13B4f1mwH/cOatF5LfXQRCmUxJt/16/VtPsB9FuC0sziuda+4/CGAIjJ5GB0gqzwN7DSOt\";\n        sout << \"7cNdIO7w0CTNOOfVq9C1zPi4fndOnX9F3M+sPSzv7YjeUbkchXzJhip96etsRY855grSR//reW8P\";\n        sout << \"XNodO/FvibrfkHKpG7fZOU+CRLqnikcNgIGBDYumpgdWA1ynvAOFPgAk5tqtLZKmrIe3ceptlG6X\";\n        sout << \"E3UDGPMNVgExa9GFR1e5bIq0GZCNeIyGMq8cGLny0uRC/u9nPu0NoTMxFb9rr2iEp1DJB/zyiped\";\n        sout << \"EoTpBPDptrXVQ9DOLvpZnplsmuuCMELZ7eP10CaDzNXodNNSFr6bk5oDTHJG3foIB/VHzdH7WDDG\";\n        sout << \"DKMcvwwXAB+gAe0Uz3C+W3DlvI2xAHxpjx4hPvATyJwVgYLus9pHzKzZCJ/gLYMgcgyArdTPI7JT\";\n        sout << \"ExgJcLp8QTosu4zuYCJ6GgPmtYlVtUdLWiPz6lHCW77bkkFmz+c6u9WF3yzzY1nyhecgnt/7jbyA\";\n        sout << \"iSeDme7x/u9K3n3CTHc7+ZXHLT6HSdxKlwZ6811c5Z12X8aP6vvL/ysGTVwa8lRngJOOiGQuX6GT\";\n        sout << \"PMohKZIhYGudZundQNXPOCavN+dpdT5m3AVMN9IrU/ht8o9eH+Hmhs0gw/iEwos7GgEJDl7IUcAg\";\n        sout << \"TZb8blBMrDfdTyAKjYcuj6iA8aDYes9sB/W8R6AtNRG4S9vQcJuCD9JBKjxwd/5jG4hrpibV5bMD\";\n        sout << \"F7dW4/5kQsc3AEdYIeGITaDjXorQ8UZ4zF9Zy81kTw6RAoTKdMYtDgnEffkDSRWGUqySn1CkTs/p\";\n        sout << \"cdY3SRk1HMd98JwlVLpED+mWbcLwRuROBimfERC048b/vfUXzGSCgdYZ9AGQhHPzu8y/nr7Lp74h\";\n        sout << \"I0ghlojt4zEkgBgK1JRMXD/dxwqIu+PIOo6s+8vwOMCLytvqCcTR8hqs63JgVGJ0c4/O8R1nbwFg\";\n        sout << \"iQiCrQ2EjBbGaBMq8vhYNA1r9QzZwHejoHm2Z4a+JXoef2al/GqOWnuOUHBotsp70MwvCS8Q/EtU\";\n        sout << \"TFGRttRKcrm7OhNmeiFLAr4P6C6O7gJxMBu78s0bIzpSIDTZFCZRYU7NWdSysmRq1ngerD9inrKg\";\n        sout << \"zt/qQLnry4PmY8NjPwt7QYcQziZLN2ruCtbvk2DrPVSx24HDHGvB+0g8jLNLQDfS552/Xs2G4zc1\";\n        sout << \"wwPpayeQy7HFGT7Gtf3oCI4jb35g8MTCXoOMgM1Dk+EYJIyDT2PBae1AcDcDVj2JKOI1UbvanFI2\";\n        sout << \"sFpsLkIgj8SVUI5dX2PEEl7AjmoFJqyeVpqmBgNEfNwPEqfNNLUp6mic3WusrWO/jQwFtUIdEWAc\";\n        sout << \"tjyIqyXeF1e1zO5po9/kJOrRJFAFxMFI8PVZNSQJ6KIQDhjPJHi/z5cCaf+lxqSo6OUt0D7z9o5A\";\n        sout << \"hfA5GwHX6oy8tGqommBrb6nF1AWVInk19mynB6E17TQRo3T5W2OFG+BaMRO1xlg1znAurKht21fr\";\n        sout << \"6VZscHHtctXifsg4dequ2SkchmjJ5yWpxqRqckES9B3nVTSiqn71/T2O/poDieJhqADWNw3gj96c\";\n        sout << \"GI4vlUR4Zo1drdvtgwHFFR+RKndNuzv2BIYvB4nm5SBqx0nuKcvbbxkEEhIRVOb/GiMJ8ZwjeVxy\";\n        sout << \"b07lDWMdBxLyxytbDoNZbefVc8N0YFrsFvrc16W8y4XKS2NG7Kfa4u977Rr6Yd6+u2+DIYwfsrzM\";\n        sout << \"DWs67DC1+vHawIhIQ5NyB/R6hx/Tym42s7IK7l9w80SaBvpN2A6vaDlNlOD7ANeZsmaAG8L6zFsb\";\n        sout << \"FLBPRNFxm+HxHYjpG3+dBySqcIyK0tSFfykLVffPMFCtgzTwDM3+5VJEghCyVlGEhDl5tv97jwVI\";\n        sout << \"aTYM84hH/JqKcDUQwmilCXqbb8bh/kTEWKzsuuyaLxr3D6+5MhVMakjG3RkIKfjddRukZC341efa\";\n        sout << \"fFJVWanSIf3lSrhFjsiH5k63EjbZmAmuMpfiLZ/Eh+zjBbh0dE1spYJ62S+PwkIXMTjCxmoJW46O\";\n        sout << \"5Bdl71SqZW7lnQUubNcgRlxAZGKY3aQlIV2qHptzubV04SMqdcyVYPrPmvZSM5U40eDoJB9UYB/D\";\n        sout << \"JaxlWFMYrW1ntJTv+LrtYepKdD3uC9SLKi5VYrWjx9WzRMxxkDcNt85Ak2cfpA3MQXI+uT7lQVoG\";\n        sout << \"vDM472l4Ruls317G1X95HA3lcJNseSQnFsAeE9GhE6XXmxDwIDqUQ6Mk+F71rvDufNIj+GaUTISI\";\n        sout << \"+lwC4tqse9dg+7wcqSTqe1cx0K7tZo3ZwR+Y3JEe+6HyURImluo6BRV0n6URS2MLpgN4geV0m+6z\";\n        sout << \"ZIML0oUAKyJVdyj4XWEq5Q/pPDvz7jDfKyqcHTCwBCuBQEnhsxi7Pr3yEac/dwYDKRSkX+7Q9mdo\";\n        sout << \"lAjgzkEnxlR2JUJxtrsEuhTiWql6HjmrkT6ohOeR/k24Y5cEiKx3QM7gBcB57IoxxMVaDJut+Q3x\";\n        sout << \"o4HQ7J/IRtkKCPp0LLSK4Ue+nSgJY5LWtD2a4KzmVnahmXeYXCuAsKm3+7dGFISapet16Grci2+j\";\n        sout << \"ETdZGgs0DEdZWncLxrCnhnvXHrfsSsVyqocOtTs1KiwUgGgcEhlSBZyH6bpF7IYhQhPzML/SIwy9\";\n        sout << \"ByDnFZIvESXwQObXa1iYfR37SyV0Yw/75bcWAnx/+jbodjLZF+RMskqs/i+PnEasmlC5wrjYo55o\";\n        sout << \"E0tqAakxpTNP8+TrRgNMLFP4tP25lfDLUka+pUXoeLC7gWQ0MTA8LDx5GyMlblaIFGHx/eMZv05r\";\n        sout << \"he2nLJgKs5ZtTMh+8pMNkEBWXQDKyJn0oVLcRQL80bPfpUfsnTW+jrEkmH8azM7CN028QyPEhBPx\";\n        sout << \"lvDsEjVbElUqBH+eo3o0CYLpnABUQ28KvsJQhHAsk2WVScBv/hm/T4c2zABqaDOl2LkRCK9ZeF2W\";\n        sout << \"kqLNjVH/iZBVQcjo49++lINm4Nupi0GPnWpsuMnNoOdZzK7Oygqbxs9Zz5VqdjRCpxQGQgOhAD2x\";\n        sout << \"aifYz6RSk7i0RB33QkjE3u+MMEQLL51zl2EOREXed6AJT0U9D0+hSLH39wqMbdEV9bIFcJ7XprJP\";\n        sout << \"ueO/zZOmCHIBfz+47Kec5BAWkufEOfKxOxwV/Wvh9+VA2RcbA0exvVj3Fy/hPmRaw6E+SBZTJoi0\";\n        sout << \"aQltfhFmfLQtT4SRl2FjDwlpNJHjmbmVOALldNBRhxSz4oWfurPqAB1A4MazDorJI74vqElH1SMQ\";\n        sout << \"7RZI0hDhS100VqCdgnYhtMa/We1kNuLcLi7cSq28JPUE0tkIE8SVLldq2Ekn90XBP3mY8LJe0WMR\";\n        sout << \"J/LzfvopGKYrqday/eYuiXl+lihXp0dpph9ZUpRzmAYWtns/djnzFSGS3bF7VOOaFuGxwYHi/1p1\";\n        sout << \"SaiBJV2a4U1vr0mh2OU3wMuqd/t5nfl+Sv75zG3YOAvcoiUH76xxHvRnn+D97TegC72k4mUgBCPs\";\n        sout << \"NZJUhjyKF5S3rerk5uhxFmlAmy+XMo9VJJaYs6OxiIeSQa3iAnbnWDzY3m1chupbDYK2fs8tBg3c\";\n        sout << \"ta7LM5SgWZLMN5Lj1RtEbFBpAylXWrb3JXGuaK/C2biFNTSFU10Xoit4NcqZuYTXu6OhNahZqayp\";\n        sout << \"IYXTMXUy1KPyHHMFWZ9gXXB/igOg80NZ2O+EYHHfRiqSOFJ7xhnY+H4X0kh9v6N7lxlv1WOudRnJ\";\n        sout << \"lWg4FktfX+JVDflDvJ0IqKuM77O5fgtBpRL3tpS2dn4U227ZiXRybiv9zCnbpK7cfq7/t69AVgUG\";\n        sout << \"qjyTGZ+YG+PDjVBWC0KGsJWIBIHwCoTgIZO5kgU/831jcG+LyuHWf1Q9bIEkOXy6UzexKYCJgIaf\";\n        sout << \"EH8IsTAVe+uUvVSBpr/Eis7LJkyx6KOAbDR3eXjXjhXJTSTK2efctB2Bb3GraweN/LUZ7suO16Ng\";\n        sout << \"odHLPnS7jsgag4B7sLNCE3NeGfd4VIE6bYg/9+Ci8k26WMJzOHIO3H+Kc7cTPCdohAQS93epRcLz\";\n        sout << \"bz957op4v9NBlgMcIKW3Fp1opHX/+vApvBecnNDF2oJ0bUq4pFuM8Ag+2PdSDlJfcdnq6S0lNA8w\";\n        sout << \"H/65WlKeVTHRt0nm/p3jJ8JNUlIZa8iZyGa/vpCaLqymASIcIfYEdfi4ugCOvbKgBOT//4cl8kji\";\n        sout << \"3BpcImX1IRx1UzgcIcK4lqO8WoSpGqhClHHi+/ezdj06JLKP27zKeHZwhTMAyYifDnCOJG2XtuY6\";\n        sout << \"gg4LTyI7BcZ5jAogPeibS+GdwlEfN+hOk1idevzrgEdzJTIR3i6p7ugPS4unLC2+waQfdJMs4Vjd\";\n        sout << \"aCmDdalKnQlpHL0Smr7Ezu0P1jPQcyO2hGupDOHl/TslPpoPcA1N6OSTraByTWL4yo9aKG1QDIOX\";\n        sout << \"NLGvos5UGUwmPxJMTeBGkxT7hyKmNzMmhfKB/yfqDaBaV6fosCm7S1FVsdnU4PvcFxa61Jrtok6n\";\n        sout << \"/lwuY3BM5VCG9/kZQtVUtImeRB4hYy8fETZI/WH+WSGhZZaum+Z7r4Ngg8/DC21U33wyR/WElnVE\";\n        sout << \"+Ny+yHoK9xkiLpLlx4ns79XnKV+S511udI6XniRyg36kCNdRWTfN81HfbS6h/KXzl2ByPVo0Q9Op\";\n        sout << \"lTF2Ox2WJ0x0RMrE1SyS1KMyL1ff+ToYLKarrgalvFUvSMI7cxPlc6phczmtYojlm9R7JdJDpuGB\";\n        sout << \"k9qA/UEnH0v+wl1+5rt+RZ4dHtD4FOXvnqW3GdN7XvISIFJLhq+UMhBPiI4M39ZRxGpuROiF3Dzd\";\n        sout << \"gD19YX9c930yj3JEhkbYzjzwa9CWLcnXbSYe9sayBJmCjpUxYmfrWo+mH66POo9ZxJeeEOPiVS77\";\n        sout << \"HXv52am6J9m3gm2Buruibflo5CGo6Ngw9slSm2rcP+pGEAyKjQoLrU6fb0TxqUnRB8q4PVvbBRFj\";\n        sout << \"c1y5MU03KShFhFfcM7iND5az9RcBJwyNZtCZr7OxlUDVDJP5IJubY/5dahCfiX3EfMXT/dR6R8Yq\";\n        sout << \"jnUNqjVGnIVm456KF1xlEZBDwCL5LNUhGCV+kp90STd77lypcQPP1q8iFDo1HhHnJDj8is+5eMY6\";\n        sout << \"5bfMP1EP13tCqPnHgD4hK7Ega8bkvoEKZInxohWoaS6F6o3lslr267EKKvjHDmnA9uGWzxss7nuj\";\n        sout << \"3PlaWuYpU9NfJp6Eq0xYNYcf4qLTN3Nhd/GRpptxzdMCuu8x2CYKBkHKMy5iJELoJ8ntEdLtVdd+\";\n        sout << \"46L46j8oPIUyswAbmodfp82VIodnJ8xvJUyJWRCXpCa2esfid02xvel9h8w1V8Uc7BKu9HMsFCDn\";\n        sout << \"+FbebdVIahMe67eUI3i9+mSZ3BNq0qbkn/dDabGwixw9lsCU5uyHZrzafG6lIA/MiepNzIRLO2Wp\";\n        sout << \"iwhMc4f4l8ZRb89HhL4bjl0Wo44VEBP+Sqf+jWMPS8qo5st+MZbtu89RObDH4fOr+1v5dvGkl5/d\";\n        sout << \"YROeKTCWyAWWSSoinCHoR/IcBi8J31l34Pk3nNrZ7BAyMn28ZY7mue6AF6hpieJ+o/0RRv5m6VM1\";\n        sout << \"1OpAFyajq7E9/BjrAfRSpCtoicoIx+APfjrLbCkEehMCBZoOM9USTMi92Id+Fm2iI+/AMStEU6tJ\";\n        sout << \"zumgP60vNm3VwZw6ep1m1DSb+2lduAxtuDtaspztXYx3QhksLmbzeKD91/v2Mu/JveEfy35tf1kY\";\n        sout << \"fcFtGY/puCXnAIxEeKY26aiZroOWt6HLIafNvD4wg//A/9iTszmQauiTWQbBLxcK/KreAE2TOpJ4\";\n        sout << \"klwh8NfDhULKVKoJ/AgNS4I/Y/LFZSX1VerAImW/WQmpkqvjnOUrpLNkuV2NjA2tKP1G45dInmG/\";\n        sout << \"nAnaPoGs/bAdQLIJayWx42xsKM1pil6q86WvoKcEH1WrRRXsRJgw0dU+Z1QIFlC+xKqP7xS0LZEs\";\n        sout << \"fjyeED07SGKBhUj1kbSp9E3PMr32yDHj23zmnFyBcwihktaRV8fEquoE0CacrSoxfdxzdWIDy9Ya\";\n        sout << \"6tVBbCcxWoz4CSGzBKSrEXVjedHR6H3etlrGwzPWYwbiFQQu3oSNml6ORLh2fu87qIjz8VrO2804\";\n        sout << \"dAqaUcJBtHOOB5KnNMSyZWA1+62WX3P/yJN8Be3AcHY7xf9bP1HUxyq5cWcAbtx9yJV1dhXyvPz6\";\n        sout << \"D4k1sntDiWgivLkY7l3OBVRs/QKGOOTj1uLei/v6X1vR54lH5wsRwq6niPYsyEcCnWk2zzTKOcK/\";\n        sout << \"OBhLQHtj5Wxf+NQ/S1zZnIBS0cww5BqZD0aATVsHfifZLEw2eRM+vap33o0ozqXIdbCzzsotLwlx\";\n        sout << \"CfFT2a/MUDatTSTuGjOPpjbmVtK7qWkWmHAF0j/GQFs73K/8PGmAWomFb2WWB8frlHkkJoEPyHVR\";\n        sout << \"N6hlsAEd8ylb6SwVawZglxdpqfhQpn71NaRU/ZJnk7fnSVmKwcGVeh1sppPYKEu/Q7i4YrAGtLDp\";\n        sout << \"Osipwqh5gL/skuxQwsBI/VNqoxIELFbJKhGrVqr2kHWB3yE9cB5puaP/MPPvIwbPSNRZVVbvGV+m\";\n        sout << \"Mmi4LDSKPlxDmjl3wWnzdldnNUb281O5dA7lMuPHgibIFjl8EeVHBFLocpnFbSLRiCZx+xh8sNRX\";\n        sout << \"ti+5Zl/pGvlloP2k7yVNRFpB3Av30jzQePY/DOy5DoF2k4eY0qvSR7HtV2IG+9wpBAUCbIaD/2t3\";\n        sout << \"FBcQT2cWEx0TPZbBqPLAxruNGcv1z23BdWUeQpeEV6ij78xVILQegtNiJlCgMTCmIRr1meCfuVJ5\";\n        sout << \"vbvNLxRiL4JSZbjKgfonK98os72YhGB0Y2oL7ZpcthGFKCGAjo76XrMB/hoeXlx6UKYlLknZImWO\";\n        sout << \"NQj5SAhZElv+LKdSZ1oc9U+0Qm8K4G9+8OnQ4wS61R0MpZKXnfFAMp99XHqN0tD6W5Br22/IOyj9\";\n        sout << \"x2QH50KAfIYZFrJaLt0MMylpVhHPQ1RBembk0wDcwDt2phnU5nm3m22r81uUHp5Sc0Or/vrzpMEc\";\n        sout << \"9vqhEFhFG74o+EGTigUiyzCGUHJu9ITqb55xDmPm829KOqkOEV3L4XX/jLwRFVkbAHaijjmg17xN\";\n        sout << \"yJZkFlYG/RntbFd+p+10JuhI9ahBvvCjFnkC+8/F64Umx4jlWJRPIADPr3yH6tt+nVkC2Cbx+U4y\";\n        sout << \"bgINetMWF1b3syNyJh4qJy/KXX5UckzU9A1Xkz2MvXWiB8Jp0f+Q/bZ0inTmecpyBGWCsD0xRYPv\";\n        sout << \"Ktm2zqD2HL3Qtfpyi0khXGmUDKwvuFnjX5V57ustxKCq2h/ylqTDCMpqS/QQ122Tr2DuHHVjGwGG\";\n        sout << \"PajaD64n0qEj+zaqyUgpDZatEVMgFxpLpbJ+sTyBaYKYPYqGxoo+XycDYIWoc7K+7d2NT76qQcI/\";\n        sout << \"LHo0kGXRTNiciphMn4EX3PkH7zUqR/yCWBRsP4wtPax6aM2m6IpY3bDbOfwMzXDTZDLAfi3is8Lb\";\n        sout << \"H5AfK2DDG45w4olFJuLKO27zafuz9GIAgoTsUwpJIJeR4xdtlP9EtMjG6SZdp22+MBSh6w4CXe82\";\n        sout << \"iIquldB5HzaHvBr3UP5LGQR3W/Wky4udFj2+XCpKsDUll+4MZCeGz1VM5ZYjDKfRDzSaLjJspoVH\";\n        sout << \"TT05yuagEN3+w/ROxo419ZEnvR+X4QLyp0JofhFpSsr+J9fQwaz3IGpPMs7wA+Q9CfEw3FkrFfeH\";\n        sout << \"022qfnq3naUsXyh8xAeI4r+MP6WGlscgFkWPZhM/vDq2IcIbCwZ10Ivx8r9bwi6bAfPE5cru0oRf\";\n        sout << \"YYs7kU0l9z3yzeSvjVjkdZbmgRNPpED67KlUQyRibkWe34KGglSuSClFu6PWrfFxb/9ch0KTFVQS\";\n        sout << \"fo3NDryMrF6oeLHe7osiyJ1ismBimKN3idmZ7yUknYbpR7/Z2K0LbAIttidcQ8LpgUzy/6jROtHE\";\n        sout << \"MRLxKl4ba6tx6BP8WpXWVzx6xYox42qMX24SkhhNVR/9ETntqyFEeDXXlS88Nm14AZARVAp8wJ3n\";\n        sout << \"WaA9OydaCeVzFVZ614BRC41g8VoHz9iZxHF/7fL5gz+YTJH7ccf18hxv4U/y0ROiZAQflTW6+lYI\";\n        sout << \"kIO8t9A9eQ7Djh7cOHCyA7E391UriFUZH8kBzKjnMeF27uYx5U9acC5YUVtDk7O7Xq3wqeGaxS1b\";\n        sout << \"oTVKitvXCbdmvIiCK8N8RZeVlteuYhJ20u7LTHsO87c1Tv83pu9OiYDMwEpAFLwfHwi5YfZecAIA\";\n        sout << \"bkkveDusgnh80pxc/24zp7W42Hm6hfq852ZLLWD2bHm3YZdey2WIbGsjvQS+io4xoEKGLHUOi7Vs\";\n        sout << \"/Te80Yujo61Y3BjY8w58xNplBAXvK4Fn2EenYcDz839o62+xeUuGN4wSUpJF94aU9//hEF93J9Zf\";\n        sout << \"CxFPlooKe1W7nU3sl2ziEh0PeM4RImmQ9zVNkDEx8ahdmvWWSWlmlv1K754XAdwp68cdfKUIY8kk\";\n        sout << \"M666TRZrSCDUvDufPL4y1LTpQUmIhtNLkrYZg0WEXx5QRF00x90VrsIFcXA/3Sjc2MPi0iMck6vM\";\n        sout << \"kh4kYbIqlvgQSwTqc6XmXEM/W3HRuVCH8kQKIXjN5my0C3RbbYIr4vAPaQL8PCWaIjbLSHDcutk1\";\n        sout << \"LBjyPnJQzn2/vvm+3oKN2JXPxeKvTbaoYu7EvWtXxkFJlrKY+o+FQfxmtN8qxniGWVLuLX6k8keB\";\n        sout << \"wCLZV6wF1XG5FsqBoVh8qvAV/Tykk0VO5FJnoJ0sVwOveUgbCFKsReM24lZlgzHsHFaTN4qSWHyi\";\n        sout << \"BGg3nr0dETiOyEfLP/ckF4GhGMMQZmT9jMFyUEgDfszoDgF+jxA1buvCKTRm4iVgFT16pi4wTG8I\";\n        sout << \"fCOM+SU2UltyA9EHdOW3rm8P8w4z0D0/IzH9Vd/O8Y2kB4TUOW4yHdB95MBCJbvEGYXR/A1eTsMW\";\n        sout << \"J96ZVGCmlcOzWqPsX61LShr57TLbE7+hJzxUMEW+ri+goqnSehcpGurw0+d4K3+5jFHxUpNaT5n+\";\n        sout << \"t0p0S42lOvrgigSZrQiJozBCCpm4sCCM91bzGge0VpyuIGTVkzbzXfjzF5J/wliLSVyzqSNq+HqL\";\n        sout << \"06BqMB0leDtLT/msAUV6SRKr7/n6qMgkrIfrAri4d13kZTpexQTRTFXxcoIgwUelzsxhdwZQ4yMX\";\n        sout << \"dAeL/oKOQdjCgnsVFD5BD7clhTEOA8gVVxASHinziac7ZkdYaHwESDZBxJhv4j1nkKNLWZLifph7\";\n        sout << \"NdJBK51yqlBvkZKROBbTiQi7UCe/YGXusDPCBsu55iieo/o65HkF7olpANKxvHxBrQuCTxYnL1tl\";\n        sout << \"pMjxmZc1BA2T7vyd4AzXRJ6tMUdqUqnjPVFY7OIKMgUn7qRieMqt95vzJqh8+jdApnY+xwnIKosv\";\n        sout << \"ox55mijPLs9oUBzAJPpD3nDLR9pnTVIkY2RmVRQFUN/kuJHYbNtc0PRIAv6iDiZhe+jeCkTx/dXC\";\n        sout << \"sSVwD5hp/v0TvaPa0XSPr1BbqlvK6KjtdsVJsUOjHFskNm/8qlIGKp9F5QCtLOBhp1eoy2AZlNlN\";\n        sout << \"+eYQRzwMSsJNxq44rixF97d7qeiOkC/Uu3wNk7aL11AR5iS7gau10LHLs3YhMbUcb+4kf2j9NpWG\";\n        sout << \"wqMklOYYJag/XNyoQs8g44qAha1rVyeq4eXodi0JegvjkXWEB4Mq8jBuHXbYjYiRiHoL68/9mry5\";\n        sout << \"nlN2Duwp7g5yl982CZLZc0k7uSjKaDkWyynH60MwLnmVj2sA\";\n\n        // Put the data into the istream sin\n        sin.str(sout.str());\n        sout.str(\"\");\n\n        // Decode the base64 text into its compressed binary form\n        base64_coder.decode(sin,sout);\n        sin.clear();\n        sin.str(sout.str());\n        sout.str(\"\");\n\n        // Decompress the data into its original form\n        compressor.decompress(sin,sout);\n\n        // Return the decoded and decompressed data\n        return sout.str();\n    }\n\n}\n\n#endif // DLIB_FRONTAL_FACE_DETECTOr_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/frontal_face_detector_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_\n#ifdef DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_\n\n#include \"object_detector_abstract.h\"\n#include \"scan_fhog_pyramid_abstract.h\"\n#include \"../image_transforms/image_pyramid_abstract.h\"\n\nnamespace dlib\n{\n    typedef object_detector<scan_fhog_pyramid<pyramid_down<6> > > frontal_face_detector;\n\n    frontal_face_detector get_frontal_face_detector(\n    );\n    /*!\n        ensures\n            - returns an object_detector that is configured to find human faces that are\n              looking more or less towards the camera.\n    !*/\n\n}\n\n#endif // DLIB_FRONTAL_FACE_DETECTOr_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/full_object_detection.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FULL_OBJECT_DeTECTION_Hh_\n#define DLIB_FULL_OBJECT_DeTECTION_Hh_\n\n#include \"../geometry.h\"\n#include \"full_object_detection_abstract.h\"\n#include <vector>\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const static dpoint OBJECT_PART_NOT_PRESENT(0x7FFFFFFFFFFFF,\n                                                0x7FFFFFFFFFFFF);\n\n// ----------------------------------------------------------------------------------------\n\n    class full_object_detection\n    {\n    public:\n        full_object_detection(\n            const rectangle& rect_,\n            const std::vector<dpoint>& parts_\n        ) : rect(rect_), parts(parts_) {}\n\n        full_object_detection(\n            const rectangle& rect_,\n            const std::vector<point>& parts_\n        ) : rect(rect_), parts (parts_.begin(), parts_.end())\n        {}\n\n        full_object_detection(){}\n\n        explicit full_object_detection(\n            const rectangle& rect_\n        ) : rect(rect_) {}\n\n        const rectangle& get_rect() const { return rect; }\n        rectangle& get_rect() { return rect; }\n        unsigned long num_parts() const { return parts.size(); }\n\n        const dpoint& part(\n            unsigned long idx\n        ) const \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(idx < num_parts(),\n                \"\\t dpoint full_object_detection::part()\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t idx:         \" << idx  \n                << \"\\n\\t num_parts(): \" << num_parts()  \n                << \"\\n\\t this:        \" << this\n                );\n            return parts[idx]; \n        }\n\n        dpoint& part(\n            unsigned long idx\n        )  \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(idx < num_parts(),\n                \"\\t dpoint full_object_detection::part()\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t idx:         \" << idx  \n                << \"\\n\\t num_parts(): \" << num_parts()  \n                << \"\\n\\t this:        \" << this\n                );\n            return parts[idx]; \n        }\n\n        friend void serialize (\n            const full_object_detection& item,\n            std::ostream& out\n        )\n        {\n            int version = 2;\n            serialize(version, out);\n            serialize(item.rect, out);\n            serialize(item.parts, out);\n        }\n\n        friend void deserialize (\n            full_object_detection& item,\n            std::istream& in\n        )\n        {\n            int version = 0;\n            deserialize(version, in);\n\n            if (version != 1 && version != 2)\n                throw serialization_error(\"Unexpected version encountered while deserializing dlib::full_object_detection.\");\n\n            deserialize(item.rect, in);\n\n            // Legacy support: read vector<point, 2> and cast to vector<dpoint, 2>\n            if (version == 1) \n            {\n                std::vector<point> legacy_parts;\n                deserialize(legacy_parts, in);\n                item.parts = std::vector<dpoint>(legacy_parts.begin(), legacy_parts.end());\n            }\n            else \n            { \n                // version 2 - deserialize into vector<dpoint, 2>\n                deserialize(item.parts, in);\n            }\n\n        }\n\n        bool operator==(\n            const full_object_detection& rhs\n        ) const\n        {\n            if (rect != rhs.rect)\n                return false;\n            if (parts.size() != rhs.parts.size())\n                return false;\n            for (size_t i = 0; i < parts.size(); ++i)\n            {\n                if (parts[i] != rhs.parts[i])\n                    return false;\n            }\n            return true;\n        }\n\n    private:\n        rectangle rect;\n        std::vector<dpoint> parts;  \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline bool all_parts_in_rect (\n        const full_object_detection& obj\n    )\n    {\n        for (unsigned long i = 0; i < obj.num_parts(); ++i)\n        {\n            if (obj.get_rect().contains(obj.part(i)) == false &&\n                obj.part(i) != OBJECT_PART_NOT_PRESENT)\n                return false;\n        }\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct mmod_rect\n    {\n        mmod_rect() = default; \n        mmod_rect(const rectangle& r) : rect(r) {}\n        mmod_rect(const rectangle& r, double score) : rect(r),detection_confidence(score) {}\n        mmod_rect(const rectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score), label(label) {}\n\n        rectangle rect;\n        double detection_confidence = 0;\n        bool ignore = false;\n        std::string label;\n\n        operator rectangle() const { return rect; }\n        bool operator == (const mmod_rect& rhs) const\n        { \n            return rect == rhs.rect \n                   && detection_confidence == rhs.detection_confidence\n                   && ignore == rhs.ignore \n                   && label == rhs.label;\n        }\n    };\n\n    inline mmod_rect ignored_mmod_rect(const rectangle& r)\n    {\n        mmod_rect temp(r);\n        temp.ignore = true;\n        return temp;\n    }\n\n    inline void serialize(const mmod_rect& item, std::ostream& out)\n    {\n        int version = 2;\n        serialize(version, out);\n        serialize(item.rect, out);\n        serialize(item.detection_confidence, out);\n        serialize(item.ignore, out);\n        serialize(item.label, out);\n    }\n\n    inline void deserialize(mmod_rect& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1 && version != 2)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::mmod_rect\");\n        deserialize(item.rect, in);\n        deserialize(item.detection_confidence, in);\n        deserialize(item.ignore, in);\n        if (version == 2)\n            deserialize(item.label, in);\n        else\n            item.label = \"\";\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct yolo_rect\n    {\n        yolo_rect() = default;\n        yolo_rect(const drectangle& r) : rect(r) {}\n        yolo_rect(const drectangle& r, double score) : rect(r),detection_confidence(score) {}\n        yolo_rect(const drectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score), label(label) {}\n        yolo_rect(const mmod_rect& r) : rect(r.rect), detection_confidence(r.detection_confidence), ignore(r.ignore), label(r.label) {}\n\n        drectangle rect;\n        double detection_confidence = 0;\n        bool ignore = false;\n        std::string label;\n        std::vector<std::pair<double, std::string>> labels;\n\n        operator rectangle() const { return rect; }\n        bool operator == (const yolo_rect& rhs) const\n        {\n            return rect == rhs.rect\n                   && detection_confidence == rhs.detection_confidence\n                   && ignore == rhs.ignore\n                   && label == rhs.label;\n        }\n        bool operator<(const yolo_rect& rhs) const\n        {\n            return detection_confidence < rhs.detection_confidence;\n        }\n    };\n\n    inline void serialize(const yolo_rect& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.rect, out);\n        serialize(item.detection_confidence, out);\n        serialize(item.ignore, out);\n        serialize(item.label, out);\n        serialize(item.labels, out);\n    }\n\n    inline void deserialize(yolo_rect& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::yolo_rect\");\n        deserialize(item.rect, in);\n        deserialize(item.detection_confidence, in);\n        deserialize(item.ignore, in);\n        deserialize(item.label, in);\n        deserialize(item.labels, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FULL_OBJECT_DeTECTION_H_\n\n"
  },
  {
    "path": "dlib/image_processing/full_object_detection_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_\n#ifdef DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../geometry.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    const static dpoint OBJECT_PART_NOT_PRESENT(0x7FFFFFFFFFFFF,\n                                                0x7FFFFFFFFFFFF);\n\n// ----------------------------------------------------------------------------------------\n\n    class full_object_detection\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the location of an object in an image along with the\n                positions of each of its constituent parts.\n        !*/\n\n    public:\n\n        full_object_detection(\n            const rectangle& rect,\n            const std::vector<dpoint>& parts\n        );\n        /*!\n            ensures\n                - #get_rect() == rect\n                - #num_parts() == parts.size()\n                - for all valid i:\n                    - part(i) == parts[i]\n        !*/\n\n        full_object_detection(\n            const rectangle& rect_,\n            const std::vector<point>& parts_\n        );\n        /*!\n            ensures\n                - #get_rect() == rect\n                - #num_parts() == parts.size()\n        !*/\n\n        full_object_detection(\n        );\n        /*!\n            ensures\n                - #get_rect().is_empty() == true\n                - #num_parts() == 0\n        !*/\n\n        explicit full_object_detection(\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - #get_rect() == rect\n                - #num_parts() == 0\n        !*/\n\n        const rectangle& get_rect(\n        ) const;\n        /*!\n            ensures\n                - returns the rectangle that indicates where this object is.  In general,\n                  this should be the bounding box for the object.\n        !*/\n\n        rectangle& get_rect(\n        ); \n        /*!\n            ensures\n                - returns the rectangle that indicates where this object is.  In general,\n                  this should be the bounding box for the object.\n        !*/\n\n        unsigned long num_parts(\n        ) const;\n        /*!\n            ensures\n                - returns the number of parts in this object.  \n        !*/\n\n        const dpoint& part(\n            unsigned long idx\n        ) const; \n        /*!\n            requires\n                - idx < num_parts()\n            ensures\n                - returns the location of the center of the idx-th part of this object.\n                  Note that it is valid for a part to be \"not present\".  This is indicated\n                  when the return value of part() is equal to OBJECT_PART_NOT_PRESENT. \n                  This is useful for modeling object parts that are not always observed.\n        !*/\n\n        dpoint& part(\n            unsigned long idx\n        ); \n        /*!\n            requires\n                - idx < num_parts()\n            ensures\n                - returns the location of the center of the idx-th part of this object.\n                  Note that it is valid for a part to be \"not present\".  This is indicated\n                  when the return value of part() is equal to OBJECT_PART_NOT_PRESENT. \n                  This is useful for modeling object parts that are not always observed.\n        !*/\n\n        bool operator==(\n            const full_object_detection& rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if and only if *this and rhs have identical state.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const full_object_detection& item, \n        std::ostream& out\n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        full_object_detection& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool all_parts_in_rect (\n        const full_object_detection& obj\n    );\n    /*!\n        ensures\n            - returns true if all the parts in obj are contained within obj.get_rect().\n              That is, returns true if and only if, for all valid i, the following is\n              always true:\n                obj.get_rect().contains(obj.part(i)) == true || obj.part(i) == OBJECT_PART_NOT_PRESENT\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct mmod_rect\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that is used to give training data and receive detections\n                from the Max-Margin Object Detection loss layer loss_mmod_ object.\n        !*/\n\n        mmod_rect() = default; \n        mmod_rect(const rectangle& r) : rect(r) {}\n        mmod_rect(const rectangle& r, double score) : rect(r),detection_confidence(score) {}\n        mmod_rect(const rectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score),label(label) {}\n\n        rectangle rect;\n        double detection_confidence = 0;\n        bool ignore = false;\n        std::string label;\n\n        operator rectangle() const { return rect; }\n\n        bool operator == (const mmod_rect& rhs) const;\n        /*!\n            ensures\n                - returns true if and only if all the elements of this object compare equal\n                  to the corresponding elements of rhs.\n        !*/\n    };\n\n    mmod_rect ignored_mmod_rect(\n        const rectangle& r\n    );\n    /*!\n        ensures\n            - returns a mmod_rect R such that:\n                - R.rect == r\n                - R.ignore == true\n                - R.detection_confidence == 0\n                - R.label == \"\"\n    !*/\n\n    void serialize(const mmod_rect& item, std::ostream& out);\n    void deserialize(mmod_rect& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct yolo_rect\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that is used to give training data and receive detections\n                from the YOLO Detection loss layer loss_yolo_ object.\n        !*/\n\n        yolo_rect() = default;\n        yolo_rect(const drectangle& r) : rect(r) {}\n        yolo_rect(const drectangle& r, double score) : rect(r),detection_confidence(score) {}\n        yolo_rect(const drectangle& r, double score, const std::string& label) : rect(r),detection_confidence(score), label(label) {}\n        yolo_rect(const mmod_rect& r) : rect(r.rect), detection_confidence(r.detection_confidence), ignore(r.ignore), label(r.label) {}\n\n        drectangle rect;\n        double detection_confidence = 0;\n        bool ignore = false;\n        std::string label;\n        // YOLO detectors are multi label detectors: this field will contain all confidences and labels for a particular detection\n        std::vector<std::pair<double, std::string>> labels;\n\n        operator rectangle() const { return rect; }\n        bool operator== (const yolo_rect& rhs) const;\n        /*!\n            ensures\n                - returns true if and only if rect == rhs.rect && detection_confidence == rhs.detection_confidence && label == rhs.label.\n        !*/\n\n        bool operator<(const yolo_rect& rhs) const\n        /*!\n            ensures\n                - returns true if and only if detection_confidence < rhs.detection_confidence.\n        !*/\n\n    };\n\n    inline void serialize(const yolo_rect& item, std::ostream& out);\n    inline void deserialize(yolo_rect& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FULL_OBJECT_DeTECTION_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/generic_image.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_GeNERIC_IMAGE_Hh_\n#define DLIB_GeNERIC_IMAGE_Hh_\n\n#include \"../assert.h\"\n#include \"../pixel.h\"\n#include <type_traits>\n\nnamespace dlib\n{\n\n    /*!\n        In dlib, an \"image\" is any object that implements the generic image interface.  In\n        particular, this simply means that an image type (let's refer to it as image_type\n        from here on) has the following seven global functions defined for it:\n            - long        num_rows      (const image_type& img)\n            - long        num_columns   (const image_type& img)\n            - void        set_image_size(      image_type& img, long rows, long cols)\n            - void*       image_data    (      image_type& img)\n            - const void* image_data    (const image_type& img)\n            - size_t      width_step    (const image_type& img)\n            - void        swap          (      image_type& a, image_type& b)\n        And also provides a specialization of the image_traits template that looks like:\n            namespace dlib\n            {\n                template <> \n                struct image_traits<image_type>\n                {\n                    typedef the_type_of_pixel_used_in_image_type pixel_type;\n                };\n            }\n\n        Additionally, an image object must be default constructable.  This means that \n        expressions of the form:\n            image_type img;\n        Must be legal.\n\n        Finally, the type of pixel in image_type must have a pixel_traits specialization.\n        That is, pixel_traits<typename image_traits<image_type>::pixel_type> must be one of\n        the specializations of pixel_traits.  \n        \n        \n        To be very precise, the seven functions defined above are defined thusly:\n\n            long num_rows(\n                const image_type& img\n            ); \n            /!*\n                ensures\n                    - returns the number of rows in the given image\n            *!/\n\n            long num_columns(\n                const image_type& img\n            );\n            /!*\n                ensures\n                    - returns the number of columns in the given image\n            *!/\n\n            void set_image_size(\n                image_type& img,\n                long rows,\n                long cols \n            );\n            /!*\n                requires\n                    - rows >= 0 && cols >= 0\n                ensures\n                    - num_rows(#img) == rows\n                    - num_columns(#img) == cols\n            *!/\n\n            void* image_data(\n                image_type& img\n            );\n            /!*\n                ensures\n                    - returns a non-const pointer to the pixel at row and column position 0,0\n                      in the given image.  Or if the image has zero rows or columns in it\n                      then this function returns NULL.\n                    - The image lays pixels down in row major order.  However, there might\n                      be padding at the end of each row.  The amount of padding is given by\n                      width_step(img).\n            *!/\n\n            const void* image_data(\n                const image_type& img\n            );\n            /!*\n                ensures\n                    - returns a const pointer to the pixel at row and column position 0,0 in\n                      the given image.  Or if the image has zero rows or columns in it then\n                      this function returns NULL.\n                    - The image lays pixels down in row major order.  However, there might\n                      be padding at the end of each row.  The amount of padding is given by\n                      width_step(img).\n            *!/\n\n            size_t width_step(\n                const image_type& img\n            );\n            /!*\n                ensures\n                    - returns the size of one row of the image, in bytes.  More precisely,\n                      return a number N such that: (char*)image_data(img) + N*R == a\n                      pointer to the first pixel in the R-th row of the image. This means\n                      that the image must lay its pixels down in row major order.\n            *!/\n\n            void swap(\n                image_type& a,\n                image_type& b\n            );\n            /!*\n                ensures\n                    - swaps the state of a and b\n            *!/\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    struct image_traits;\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This is a traits class for generic image objects.  You can use it to find out\n            the pixel type contained within an image via an expression of the form:\n                image_traits<image_type>::pixel_type\n    !*/\n\n    /*!A pixel_type_t \n        An alias for the type of pixel in an image.\n    !*/\n    template <typename image_type>\n    using pixel_type_t = typename image_traits<image_type>::pixel_type;\n\n    /*!A is_rgb_image\n        A type traits class telling you if a type is an image holding RGB pixels.\n    !*/\n    template <typename image_type>\n    struct is_rgb_image { const static bool value = pixel_traits<pixel_type_t<image_type>>::rgb; };\n\n    /*!A is_color_space_cartesian_image\n        A type traits class telling you if a type is an image holding some type of cartesian pixel type.\n\n        E.g. as contrasted with polar coordinates pixel types.\n    !*/\n    template <typename image_type>\n    struct is_color_space_cartesian_image { const static bool value = \n        pixel_traits<pixel_type_t<image_type>>::rgb || \n        pixel_traits<pixel_type_t<image_type>>::lab || \n        pixel_traits<pixel_type_t<image_type>>::grayscale; };\n\n    /*!A is_grayscale_image\n        A type traits class telling you if a type is an image holding a single channel (i.e.\n        grayscale) pixel type.\n    !*/\n    template <typename image_type>\n    struct is_grayscale_image { const static bool value = pixel_traits<pixel_type_t<image_type>>::grayscale; };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace details\n    {\n        template<class Container, class Alwaysvoid = void>\n        struct is_image_type : std::false_type{};\n\n        template<class Container>\n        struct is_image_type<Container, dlib::void_t<is_pixel_check<pixel_type_t<Container>>>> : std::true_type{};\n    }\n\n    /*!A is_image_type \n\n        A type traits struct telling you if Container satisfies the generic image interface.\n\n        i.e. there exists an image_traits<> specialization and the underlying pixel type has a pixel_trait<> specialiation\n        e.g. array2d<rgb_pixel>, matrix<float>, etc...\n    !*/\n    template<class Container>\n    using is_image_type = details::is_image_type<Container>;\n\n    /*!A is_image_check\n\n        This is a SFINAE tool for restricting a template to only image types.\n    !*/\n    template<class Container>\n    using is_image_check = std::enable_if_t<is_image_type<Container>::value, bool>;\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                   UTILITIES TO MAKE ACCESSING IMAGE PIXELS SIMPLER\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    class image_view\n    {\n        /*!\n            REQUIREMENTS ON image_type\n                image_type must be an image object as defined at the top of this file.  \n\n            WHAT THIS OBJECT REPRESENTS\n                This object takes an image object and wraps it with an interface that makes\n                it look like a dlib::array2d.  That is, it makes it look similar to a\n                regular 2-dimensional C style array, making code which operates on the\n                pixels simple to read.\n\n                Note that an image_view instance is valid until the image given to its\n                constructor is modified through an interface other than the image_view\n                instance.  This is because, for example, someone might cause the underlying\n                image object to reallocate its memory, thus invalidating the pointer to its\n                pixel data stored in the image_view.    \n\n                As an side, the reason why this object stores a pointer to the image\n                object's data and uses that pointer instead of calling image_data() each\n                time a pixel is accessed is to allow for image objects to implement\n                complex, and possibly slow, image_data() functions.  For example, an image\n                object might perform some kind of synchronization between a GPU and the\n                host memory during a call to image_data().  Therefore, we call image_data()\n                only in image_view's constructor to avoid the performance penalty of\n                calling it for each pixel access.\n        !*/\n\n    public:\n        using pixel_type = pixel_type_t<image_type>;\n\n        image_view(\n            image_type& img\n        ) : \n            _data(reinterpret_cast<char*>(image_data(img))), \n            _width_step(width_step(img)),\n            _nr(num_rows(img)),\n            _nc(num_columns(img)),\n            _img(&img) \n        {}\n\n        long nr() const { return _nr; }\n        /*!\n            ensures\n                - returns the number of rows in this image.\n        !*/\n\n        long nc() const { return _nc; }\n        /*!\n            ensures\n                - returns the number of columns in this image.\n        !*/\n\n        unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); }\n        /*!\n            ensures\n                - returns the number of pixels in this image.\n        !*/\n\n#ifndef ENABLE_ASSERTS\n        pixel_type* operator[] (long row) { return (pixel_type*)(_data+_width_step*row); }\n        /*!\n            requires\n                - 0 <= row < nr()\n            ensures\n                - returns a pointer to the first pixel in the row-th row.  Therefore, the\n                  pixel at row and column position r,c can be accessed via (*this)[r][c].\n        !*/\n\n        const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); }\n        /*!\n            requires\n                - 0 <= row < nr()\n            ensures\n                - returns a const pointer to the first pixel in the row-th row.  Therefore,\n                  the pixel at row and column position r,c can be accessed via\n                  (*this)[r][c].\n        !*/\n#else\n        // If asserts are enabled then we need to return a proxy class so we can make sure\n        // the column accesses don't go out of bounds.\n        struct pix_row\n        {\n            pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {}\n            const pixel_type& operator[] (long col) const\n            {\n                DLIB_ASSERT(0 <= col && col < _nc, \n                    \"\\t The given column index is out of range.\"\n                    << \"\\n\\t col: \" << col \n                    << \"\\n\\t _nc: \" << _nc);\n                return data[col];\n            }\n            pixel_type& operator[] (long col)\n            {\n                DLIB_ASSERT(0 <= col && col < _nc, \n                    \"\\t The given column index is out of range.\"\n                    << \"\\n\\t col: \" << col \n                    << \"\\n\\t _nc: \" << _nc);\n                return data[col];\n            }\n        private:\n            pixel_type* const data;\n            const long _nc;\n        };\n        pix_row operator[] (long row) \n        { \n            DLIB_ASSERT(0 <= row && row < _nr, \n                \"\\t The given row index is out of range.\"\n                << \"\\n\\t row: \" << row \n                << \"\\n\\t _nr: \" << _nr);\n            return pix_row((pixel_type*)(_data+_width_step*row), _nc); \n        }\n        const pix_row operator[] (long row) const \n        { \n            DLIB_ASSERT(0 <= row && row < _nr, \n                \"\\t The given row index is out of range.\"\n                << \"\\n\\t row: \" << row \n                << \"\\n\\t _nr: \" << _nr);\n            return pix_row((pixel_type*)(_data+_width_step*row), _nc); \n        }\n#endif\n\n        void set_size(long rows, long cols) \n        /*!\n            requires\n                - rows >= 0 && cols >= 0\n            ensures\n                - Tells the underlying image to resize itself to have the given number of\n                  rows and columns.\n                - #nr() == rows\n                - #nc() == cols\n        !*/\n        { \n            DLIB_ASSERT((cols >= 0 && rows >= 0),\n                        \"\\t image_view::set_size(long rows, long cols)\"\n                        << \"\\n\\t The images can't have negative rows or columns.\"\n                        << \"\\n\\t cols: \" << cols \n                        << \"\\n\\t rows: \" << rows \n            );\n            set_image_size(*_img, rows, cols); *this = *_img; \n        }\n\n        void clear() { set_size(0,0); }\n        /*!\n            ensures\n                - sets the image to have 0 pixels in it.\n        !*/\n\n        size_t get_width_step() const { return _width_step; }\n\n    private:\n\n        char* _data;\n        size_t _width_step;\n        long _nr;\n        long _nc;\n        image_type* _img;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    class const_image_view\n    {\n        /*!\n            REQUIREMENTS ON image_type\n                image_type must be an image object as defined at the top of this file.  \n\n            WHAT THIS OBJECT REPRESENTS\n                This object is just like the image_view except that it provides a \"const\"\n                view into an image.  That is, it has the same interface as image_view\n                except that you can't modify the image through a const_image_view.\n        !*/\n\n    public:\n        using pixel_type = pixel_type_t<image_type>;\n\n        const_image_view(\n            const image_type& img\n        ) : \n            _data(reinterpret_cast<const char*>(image_data(img))), \n            _width_step(width_step(img)),\n            _nr(num_rows(img)),\n            _nc(num_columns(img))\n        {}\n\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n        unsigned long size() const { return static_cast<unsigned long>(nr()*nc()); }\n#ifndef ENABLE_ASSERTS\n        const pixel_type* operator[] (long row) const { return (const pixel_type*)(_data+_width_step*row); }\n#else\n        // If asserts are enabled then we need to return a proxy class so we can make sure\n        // the column accesses don't go out of bounds.\n        struct pix_row\n        {\n            pix_row(pixel_type* data_, long nc_) : data(data_),_nc(nc_) {}\n            const pixel_type& operator[] (long col) const\n            {\n                DLIB_ASSERT(0 <= col && col < _nc, \n                    \"\\t The given column index is out of range.\"\n                    << \"\\n\\t col: \" << col \n                    << \"\\n\\t _nc: \" << _nc);\n                return data[col];\n            }\n        private:\n            pixel_type* const data;\n            const long _nc;\n        };\n        const pix_row operator[] (long row) const \n        { \n            DLIB_ASSERT(0 <= row && row < _nr, \n                \"\\t The given row index is out of range.\"\n                << \"\\n\\t row: \" << row \n                << \"\\n\\t _nr: \" << _nr);\n            return pix_row((pixel_type*)(_data+_width_step*row), _nc); \n        }\n#endif\n\n        size_t get_width_step() const { return _width_step; }\n\n    private:\n        const char* _data;\n        size_t _width_step;\n        long _nr;\n        long _nc;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    image_view<image_type> make_image_view ( image_type& img) \n    { return image_view<image_type>(img); }\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined at the\n              top of this file.\n        ensures\n            - constructs an image_view from an image object\n    !*/\n\n    template <typename image_type>\n    const_image_view<image_type> make_image_view (const image_type& img) \n    { return const_image_view<image_type>(img); }\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined at the\n              top of this file.\n        ensures\n            - constructs a const_image_view from an image object\n    !*/\n\n\n    // Don't stack image views on image views since that's pointless and just slows the\n    // compilation.\n    template <typename T> image_view<T>&             make_image_view ( image_view<T>& img)             { return img; }\n    template <typename T> const image_view<T>&       make_image_view ( const image_view<T>& img)       { return img; }\n    template <typename T> const_image_view<T>&       make_image_view ( const_image_view<T>& img)       { return img; }\n    template <typename T> const const_image_view<T>& make_image_view ( const const_image_view<T>& img) { return img; }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    inline unsigned long image_size(\n        const image_type& img\n    ) { return num_columns(img)*num_rows(img); }\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined at the\n              top of this file.\n        ensures\n            - returns the number of pixels in the given image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    inline long num_rows(\n        const image_type& img\n    ) { return img.nr(); }\n    /*!\n        ensures\n            - By default, try to use the member function .nr() to determine the number\n              of rows in an image.  However, as stated at the top of this file, image\n              objects should provide their own overload of num_rows() if needed.\n    !*/\n\n    template <typename image_type>\n    inline long num_columns(\n        const image_type& img\n    ) { return img.nc(); }\n    /*!\n        ensures\n            - By default, try to use the member function .nc() to determine the number\n              of columns in an image.  However, as stated at the top of this file, image\n              objects should provide their own overload of num_rows() if needed.\n    !*/\n\n    template <typename image_type1, typename image_type2>\n    typename std::enable_if<is_image_type<image_type1>::value&&is_image_type<image_type2>::value, bool>::type \n    have_same_dimensions (\n        const image_type1& img1,\n        const image_type2& img2\n    ) { return num_rows(img1)==num_rows(img2) && num_columns(img1)==num_columns(img2); }\n    /*!\n        ensures\n            - returns true if and only if the two given images have the same dimensions.\n    !*/\n\n    template <typename image_type1, typename image_type2, typename ...T>\n    typename std::enable_if<is_image_type<image_type1>::value&&is_image_type<image_type2>::value, bool>::type \n    have_same_dimensions (\n        const image_type1& img1,\n        const image_type2& img2,\n        T&& ...args\n    ) { return have_same_dimensions(img1,img2) && have_same_dimensions(img1,args...); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//            Make the image views implement the generic image interface\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct image_traits<image_view<T>> { using pixel_type = pixel_type_t<T>; };\n\n    template <typename T>\n    struct image_traits<const image_view<T>> { using pixel_type = pixel_type_t<T>; };\n\n    template <typename T>\n    inline long num_rows( const image_view<T>& img) { return img.nr(); }\n    template <typename T>\n    inline long num_columns( const image_view<T>& img) { return img.nc(); }\n\n    template <typename T>\n    inline void set_image_size( image_view<T>& img, long rows, long cols ) { img.set_size(rows,cols); }\n\n    template <typename T>\n    inline void* image_data( image_view<T>& img)\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T>\n    inline const void* image_data(\n        const image_view<T>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T>\n    inline size_t width_step( const image_view<T>& img) { return img.get_width_step(); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct image_traits<const_image_view<T>> {using pixel_type = pixel_type_t<T>; };\n\n    template <typename T>\n    struct image_traits<const const_image_view<T>> {using pixel_type = pixel_type_t<T>; };\n\n    template <typename T>\n    inline long num_rows( const const_image_view<T>& img) { return img.nr(); }\n    template <typename T>\n    inline long num_columns( const const_image_view<T>& img) { return img.nc(); }\n\n    template <typename T>\n    inline const void* image_data(\n        const const_image_view<T>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T>\n    inline size_t width_step( const const_image_view<T>& img) { return img.get_width_step(); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_GeNERIC_IMAGE_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/object_detector.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OBJECT_DeTECTOR_Hh_\n#define DLIB_OBJECT_DeTECTOR_Hh_\n\n#include \"object_detector_abstract.h\"\n#include \"../geometry.h\"\n#include <vector>\n#include \"box_overlap_testing.h\"\n#include \"full_object_detection.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct rect_detection\n    {\n        double detection_confidence;\n        unsigned long weight_index;\n        rectangle rect;\n\n        bool operator<(const rect_detection& item) const { return detection_confidence < item.detection_confidence; }\n    };\n\n    struct full_detection\n    {\n        double detection_confidence;\n        unsigned long weight_index;\n        full_object_detection rect;\n\n        bool operator<(const full_detection& item) const { return detection_confidence < item.detection_confidence; }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_scanner_type>\n    struct processed_weight_vector\n    {\n        processed_weight_vector(){}\n\n        typedef typename image_scanner_type::feature_vector_type feature_vector_type;\n\n        void init (\n            const image_scanner_type& \n        ) \n        /*!\n            requires\n                - w has already been assigned its value.  Note that the point of this\n                  function is to allow an image scanner to overload the\n                  processed_weight_vector template and provide some different kind of\n                  object as the output of get_detect_argument().  For example, the\n                  scan_fhog_pyramid object uses an overload that causes\n                  get_detect_argument() to return the special fhog_filterbank object\n                  instead of a feature_vector_type.  This avoids needing to construct the\n                  fhog_filterbank during each call to detect and therefore speeds up\n                  detection.\n        !*/\n        {}\n\n        // return the first argument to image_scanner_type::detect()\n        const feature_vector_type& get_detect_argument() const { return w; }\n\n        feature_vector_type w;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type_\n        >\n    class object_detector\n    {\n    public:\n        typedef image_scanner_type_ image_scanner_type;\n        typedef typename image_scanner_type::feature_vector_type feature_vector_type;\n\n        object_detector (\n        );\n\n        object_detector (\n            const object_detector& item \n        );\n\n        object_detector (\n            const image_scanner_type& scanner_, \n            const test_box_overlap& overlap_tester_,\n            const feature_vector_type& w_ \n        );\n\n        object_detector (\n            const image_scanner_type& scanner_, \n            const test_box_overlap& overlap_tester_,\n            const std::vector<feature_vector_type>& w_ \n        );\n\n        explicit object_detector (\n            const std::vector<object_detector>& detectors\n        );\n\n        unsigned long num_detectors (\n        ) const { return w.size(); }\n\n        const feature_vector_type& get_w (\n            unsigned long idx = 0\n        ) const { return w[idx].w; }\n        \n        const processed_weight_vector<image_scanner_type>& get_processed_w (\n            unsigned long idx = 0\n        ) const { return w[idx]; }\n\n        const test_box_overlap& get_overlap_tester (\n        ) const;\n\n        const image_scanner_type& get_scanner (\n        ) const;\n\n        object_detector& operator= (\n            const object_detector& item \n        );\n\n        template <\n            typename image_type\n            >\n        std::vector<rectangle> operator() (\n            const image_type& img,\n            double adjust_threshold = 0\n        );\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<std::pair<double, rectangle> >& final_dets,\n            double adjust_threshold = 0\n        );\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<std::pair<double, full_object_detection> >& final_dets,\n            double adjust_threshold = 0\n        );\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<full_object_detection>& final_dets,\n            double adjust_threshold = 0\n        );\n\n        // These typedefs are here for backwards compatibility with previous versions of\n        // dlib.\n        typedef ::dlib::rect_detection rect_detection;\n        typedef ::dlib::full_detection full_detection;\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<rect_detection>& final_dets,\n            double adjust_threshold = 0\n        );\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<full_detection>& final_dets,\n            double adjust_threshold = 0\n        );\n\n        template <typename T>\n        friend void serialize (\n            const object_detector<T>& item,\n            std::ostream& out\n        );\n\n        template <typename T>\n        friend void deserialize (\n            object_detector<T>& item,\n            std::istream& in \n        );\n\n    private:\n\n        bool overlaps_any_box (\n            const std::vector<rect_detection>& rects,\n            const dlib::rectangle& rect\n        ) const\n        {\n            for (unsigned long i = 0; i < rects.size(); ++i)\n            {\n                if (boxes_overlap(rects[i].rect, rect))\n                    return true;\n            }\n            return false;\n        }\n\n        test_box_overlap boxes_overlap;\n        std::vector<processed_weight_vector<image_scanner_type> > w;\n        image_scanner_type scanner;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const object_detector<T>& item,\n        std::ostream& out\n    )\n    {\n        int version = 2;\n        serialize(version, out);\n\n        T scanner;\n        scanner.copy_configuration(item.scanner);\n        serialize(scanner, out);\n        serialize(item.boxes_overlap, out);\n        // serialize all the weight vectors\n        serialize(item.w.size(), out);\n        for (unsigned long i = 0; i < item.w.size(); ++i)\n            serialize(item.w[i].w, out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void deserialize (\n        object_detector<T>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version == 1)\n        {\n            deserialize(item.scanner, in);\n            item.w.resize(1);\n            deserialize(item.w[0].w, in);\n            item.w[0].init(item.scanner);\n            deserialize(item.boxes_overlap, in);\n        }\n        else if (version == 2)\n        {\n            deserialize(item.scanner, in);\n            deserialize(item.boxes_overlap, in);\n            unsigned long num_detectors = 0;\n            deserialize(num_detectors, in);\n            item.w.resize(num_detectors);\n            for (unsigned long i = 0; i < item.w.size(); ++i)\n            {\n                deserialize(item.w[i].w, in);\n                item.w[i].init(item.scanner);\n            }\n        }\n        else \n        {\n            throw serialization_error(\"Unexpected version encountered while deserializing a dlib::object_detector object.\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                      object_detector member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>::\n    object_detector (\n    )\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>::\n    object_detector (\n        const object_detector& item \n    )\n    {\n        boxes_overlap = item.boxes_overlap;\n        w = item.w;\n        scanner.copy_configuration(item.scanner);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>::\n    object_detector (\n        const image_scanner_type& scanner_, \n        const test_box_overlap& overlap_tester,\n        const feature_vector_type& w_ \n    ) :\n        boxes_overlap(overlap_tester)\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(scanner_.get_num_detection_templates() > 0 &&\n                    w_.size() == scanner_.get_num_dimensions() + 1, \n            \"\\t object_detector::object_detector(scanner_,overlap_tester,w_)\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t scanner_.get_num_detection_templates(): \" << scanner_.get_num_detection_templates()\n            << \"\\n\\t w_.size():                     \" << w_.size()\n            << \"\\n\\t scanner_.get_num_dimensions(): \" << scanner_.get_num_dimensions()\n            << \"\\n\\t this: \" << this\n            );\n\n        scanner.copy_configuration(scanner_);\n        w.resize(1);\n        w[0].w = w_;\n        w[0].init(scanner);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>::\n    object_detector (\n        const image_scanner_type& scanner_, \n        const test_box_overlap& overlap_tester,\n        const std::vector<feature_vector_type>& w_ \n    ) :\n        boxes_overlap(overlap_tester)\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(scanner_.get_num_detection_templates() > 0 && w_.size() > 0,\n            \"\\t object_detector::object_detector(scanner_,overlap_tester,w_)\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t scanner_.get_num_detection_templates(): \" << scanner_.get_num_detection_templates()\n            << \"\\n\\t w_.size():                     \" << w_.size()\n            << \"\\n\\t this: \" << this\n            );\n\n        for (unsigned long i = 0; i < w_.size(); ++i)\n        {\n            DLIB_CASSERT(w_[i].size() == scanner_.get_num_dimensions() + 1, \n                \"\\t object_detector::object_detector(scanner_,overlap_tester,w_)\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t scanner_.get_num_detection_templates(): \" << scanner_.get_num_detection_templates()\n                << \"\\n\\t w_[\"<<i<<\"].size():                     \" << w_[i].size()\n                << \"\\n\\t scanner_.get_num_dimensions(): \" << scanner_.get_num_dimensions()\n                << \"\\n\\t this: \" << this\n                );\n        }\n\n        scanner.copy_configuration(scanner_);\n        w.resize(w_.size());\n        for (unsigned long i = 0; i < w.size(); ++i)\n        {\n            w[i].w = w_[i];\n            w[i].init(scanner);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>::\n    object_detector (\n        const std::vector<object_detector>& detectors\n    )\n    {\n        DLIB_CASSERT(detectors.size() != 0,\n                \"\\t object_detector::object_detector(detectors)\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t this: \" << this\n        );\n        std::vector<feature_vector_type> weights;\n        weights.reserve(detectors.size());\n        for (unsigned long i = 0; i < detectors.size(); ++i)\n        {\n            for (unsigned long j = 0; j < detectors[i].num_detectors(); ++j)\n                weights.push_back(detectors[i].get_w(j));\n        }\n\n        *this = object_detector(detectors[0].get_scanner(), detectors[0].get_overlap_tester(), weights);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    object_detector<image_scanner_type>& object_detector<image_scanner_type>::\n    operator= (\n        const object_detector& item \n    )\n    {\n        if (this == &item)\n            return *this;\n\n        boxes_overlap = item.boxes_overlap;\n        w = item.w;\n        scanner.copy_configuration(item.scanner);\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    void object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        std::vector<rect_detection>& final_dets,\n        double adjust_threshold\n    ) \n    {\n        scanner.load(img);\n        std::vector<std::pair<double, rectangle> > dets;\n        std::vector<rect_detection> dets_accum;\n        for (unsigned long i = 0; i < w.size(); ++i)\n        {\n            const double thresh = w[i].w(scanner.get_num_dimensions());\n            scanner.detect(w[i].get_detect_argument(), dets, thresh + adjust_threshold);\n            for (unsigned long j = 0; j < dets.size(); ++j)\n            {\n                rect_detection temp;\n                temp.detection_confidence = dets[j].first-thresh;\n                temp.weight_index = i;\n                temp.rect = dets[j].second;\n                dets_accum.push_back(temp);\n            }\n        }\n\n        // Do non-max suppression\n        final_dets.clear();\n        if (w.size() > 1)\n            std::sort(dets_accum.rbegin(), dets_accum.rend());\n        for (unsigned long i = 0; i < dets_accum.size(); ++i)\n        {\n            if (overlaps_any_box(final_dets, dets_accum[i].rect))\n                continue;\n\n            final_dets.push_back(dets_accum[i]);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    void object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        std::vector<full_detection>& final_dets,\n        double adjust_threshold \n    )\n    {\n        std::vector<rect_detection> dets;\n        (*this)(img,dets,adjust_threshold);\n\n        final_dets.resize(dets.size());\n\n        // convert all the rectangle detections into full_object_detections.\n        for (unsigned long i = 0; i < dets.size(); ++i)\n        {\n            final_dets[i].detection_confidence = dets[i].detection_confidence;\n            final_dets[i].weight_index = dets[i].weight_index;\n            final_dets[i].rect = scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    std::vector<rectangle> object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        double adjust_threshold\n    ) \n    {\n        std::vector<rect_detection> dets;\n        (*this)(img,dets,adjust_threshold);\n\n        std::vector<rectangle> final_dets(dets.size());\n        for (unsigned long i = 0; i < dets.size(); ++i)\n            final_dets[i] = dets[i].rect;\n\n        return final_dets;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    void object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        std::vector<std::pair<double, rectangle> >& final_dets,\n        double adjust_threshold\n    ) \n    {\n        std::vector<rect_detection> dets;\n        (*this)(img,dets,adjust_threshold);\n\n        final_dets.resize(dets.size());\n        for (unsigned long i = 0; i < dets.size(); ++i)\n            final_dets[i] = std::make_pair(dets[i].detection_confidence,dets[i].rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    void object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        std::vector<std::pair<double, full_object_detection> >& final_dets,\n        double adjust_threshold\n    ) \n    {\n        std::vector<rect_detection> dets;\n        (*this)(img,dets,adjust_threshold);\n\n        final_dets.clear();\n        final_dets.reserve(dets.size());\n\n        // convert all the rectangle detections into full_object_detections.\n        for (unsigned long i = 0; i < dets.size(); ++i)\n        {\n            final_dets.push_back(std::make_pair(dets[i].detection_confidence, \n                                                scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w)));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    template <\n        typename image_type\n        >\n    void object_detector<image_scanner_type>::\n    operator() (\n        const image_type& img,\n        std::vector<full_object_detection>& final_dets,\n        double adjust_threshold\n    ) \n    {\n        std::vector<rect_detection> dets;\n        (*this)(img,dets,adjust_threshold);\n\n        final_dets.clear();\n        final_dets.reserve(dets.size());\n\n        // convert all the rectangle detections into full_object_detections.\n        for (unsigned long i = 0; i < dets.size(); ++i)\n        {\n            final_dets.push_back(scanner.get_full_object_detection(dets[i].rect, w[dets[i].weight_index].w));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    const test_box_overlap& object_detector<image_scanner_type>::\n    get_overlap_tester (\n    ) const\n    {\n        return boxes_overlap;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    const image_scanner_type& object_detector<image_scanner_type>::\n    get_scanner (\n    ) const\n    {\n        return scanner;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OBJECT_DeTECTOR_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/object_detector_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_\n#ifdef DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_\n\n#include \"../geometry.h\"\n#include <vector>\n#include \"box_overlap_testing_abstract.h\"\n#include \"full_object_detection_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct rect_detection\n    {\n        double detection_confidence;\n        unsigned long weight_index;\n        rectangle rect;\n    };\n\n    struct full_detection\n    {\n        double detection_confidence;\n        unsigned long weight_index;\n        full_object_detection rect;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type_\n        >\n    class object_detector\n    {\n        /*!\n            REQUIREMENTS ON image_scanner_type_\n                image_scanner_type_ must be an implementation of \n                dlib/image_processing/scan_image_pyramid_abstract.h or \n                dlib/image_processing/scan_fhog_pyramid.h or \n                dlib/image_processing/scan_image_custom.h or \n                dlib/image_processing/scan_image_boxes_abstract.h \n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for detecting the positions of objects in an image.\n                In particular, it is a simple container to aggregate an instance of an image \n                scanner (i.e. scan_image_pyramid, scan_fhog_pyramid, scan_image_custom, or\n                scan_image_boxes), the weight vector needed by one of these image scanners,\n                and finally an instance of test_box_overlap.  The test_box_overlap object\n                is used to perform non-max suppression on the output of the image scanner\n                object.  \n\n                Note further that this object can contain multiple weight vectors.  In this\n                case, it will run the image scanner multiple times, once with each of the\n                weight vectors.  Then it will aggregate the results from all runs, perform\n                non-max suppression and then return the results.  Therefore, the object_detector \n                can also be used as a container for a set of object detectors that all use\n                the same image scanner but different weight vectors.  This is useful since\n                the object detection procedure has two parts.  A loading step where the\n                image is loaded into the scanner, then a detect step which uses the weight\n                vector to locate objects in the image.  Since the loading step is independent \n                of the weight vector it is most efficient to run multiple detectors by\n                performing one load into a scanner followed by multiple detect steps.  This\n                avoids unnecessarily loading the same image into the scanner multiple times.  \n        !*/\n    public:\n        typedef image_scanner_type_ image_scanner_type;\n        typedef typename image_scanner_type::feature_vector_type feature_vector_type;\n\n        object_detector (\n        );\n        /*!\n            ensures\n                - This detector won't generate any detections when\n                  presented with an image.\n                - #num_detectors() == 0\n        !*/\n\n        object_detector (\n            const object_detector& item \n        );\n        /*!\n            ensures\n                - #*this is a copy of item\n                - #get_scanner() == item.get_scanner()\n                  (note that only the \"configuration\" of item.get_scanner() is copied.\n                  I.e. the copy is done using copy_configuration())\n        !*/\n\n        object_detector (\n            const image_scanner_type& scanner, \n            const test_box_overlap& overlap_tester,\n            const feature_vector_type& w \n        );\n        /*!\n            requires\n                - w.size() == scanner.get_num_dimensions() + 1\n                - scanner.get_num_detection_templates() > 0\n            ensures\n                - When the operator() member function is called it will\n                  invoke scanner.detect(w,dets,w(w.size()-1)), suppress\n                  overlapping detections, and then report the results.\n                - when #*this is used to detect objects, the set of\n                  output detections will never contain any overlaps\n                  with respect to overlap_tester.  That is, for all \n                  pairs of returned detections A and B, we will always\n                  have: overlap_tester(A,B) == false\n                - #get_w() == w\n                - #get_overlap_tester() == overlap_tester\n                - #get_scanner() == scanner\n                  (note that only the \"configuration\" of scanner is copied.\n                  I.e. the copy is done using copy_configuration())\n                - #num_detectors() == 1\n        !*/\n\n        object_detector (\n            const image_scanner_type& scanner, \n            const test_box_overlap& overlap_tester,\n            const std::vector<feature_vector_type>& w \n        );\n        /*!\n            requires\n                - for all valid i:\n                    - w[i].size() == scanner.get_num_dimensions() + 1\n                - scanner.get_num_detection_templates() > 0\n                - w.size() > 0\n            ensures\n                - When the operator() member function is called it will invoke\n                  get_scanner().detect(w[i],dets,w[i](w[i].size()-1)) for all valid i.  Then it\n                  will take all the detections output by the calls to detect() and suppress\n                  overlapping detections, and finally report the results.\n                - when #*this is used to detect objects, the set of output detections will\n                  never contain any overlaps with respect to overlap_tester.  That is, for\n                  all pairs of returned detections A and B, we will always have:\n                    overlap_tester(A,B) == false\n                - for all valid i:\n                    - #get_w(i) == w[i]\n                - #num_detectors() == w.size()\n                - #get_overlap_tester() == overlap_tester\n                - #get_scanner() == scanner\n                  (note that only the \"configuration\" of scanner is copied.\n                  I.e. the copy is done using copy_configuration())\n        !*/\n\n        explicit object_detector (\n            const std::vector<object_detector>& detectors\n        );\n        /*!\n            requires\n                - detectors.size() != 0\n                - All the detectors must use compatibly configured scanners.  That is, it\n                  must make sense for the weight vector from one detector to be used with\n                  the scanner from any other.\n                - for all valid i:\n                    - detectors[i].get_scanner().get_num_dimensions() == detectors[0].get_scanner().get_num_dimensions()\n                      (i.e. all the detectors use scanners that use the same kind of feature vectors.)\n            ensures\n                - Very much like the above constructor, this constructor takes all the\n                  given detectors and packs them into #*this.  That is, invoking operator()\n                  on #*this will run all the detectors, perform non-max suppression, and\n                  then report the results.\n                - When #*this is used to detect objects, the set of output detections will\n                  never contain any overlaps with respect to overlap_tester.  That is, for\n                  all pairs of returned detections A and B, we will always have:\n                    overlap_tester(A,B) == false\n                - #num_detectors() == The sum of detectors[i].num_detectors() for all valid i. \n                - #get_overlap_tester() == detectors[0].get_overlap_tester()\n                - #get_scanner() == detectors[0].get_scanner()\n                  (note that only the \"configuration\" of scanner is copied.  I.e. the copy\n                  is done using copy_configuration())\n        !*/\n\n        unsigned long num_detectors (\n        ) const; \n        /*!\n            ensures\n                - returns the number of weight vectors in this object.  Since each weight\n                  vector logically represents an object detector, this returns the number\n                  of object detectors contained in this object.\n        !*/\n\n        const feature_vector_type& get_w (\n            unsigned long idx = 0\n        ) const;\n        /*!\n            requires\n                - idx < num_detectors()\n            ensures\n                - returns the idx-th weight vector loaded into this object.  All the weight vectors\n                  have the same dimension and logically each represents a different detector.\n        !*/\n\n        const test_box_overlap& get_overlap_tester (\n        ) const;\n        /*!\n            ensures\n                - returns the overlap tester used by this object\n        !*/\n\n        const image_scanner_type& get_scanner (\n        ) const;\n        /*!\n            ensures\n                - returns the image scanner used by this object.  \n        !*/\n\n        object_detector& operator= (\n            const object_detector& item \n        );\n        /*!\n            ensures\n                - #*this is a copy of item\n                - #get_scanner() == item.get_scanner()\n                  (note that only the \"configuration\" of item.get_scanner() is \n                  copied.  I.e. the copy is done using copy_configuration())\n                - returns #*this\n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<rect_detection>& dets,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - Performs object detection on the given image and stores the detected\n                  objects into #dets.  In particular, we will have that:\n                    - #dets is sorted such that the highest confidence detections come\n                      first.  E.g. element 0 is the best detection, element 1 the next\n                      best, and so on.\n                    - #dets.size() == the number of detected objects.\n                    - #dets[i].detection_confidence == The strength of the i-th detection.\n                      Larger values indicate that the detector is more confident that\n                      #dets[i] is a correct detection rather than being a false alarm.\n                      Moreover, the detection_confidence is equal to the detection value\n                      output by the scanner minus the threshold value stored at the end of\n                      the weight vector in get_w(#dets[i].weight_index). \n                    - #dets[i].weight_index == the index for the weight vector that\n                      generated this detection. \n                    - #dets[i].rect == the bounding box for the i-th detection.\n                - #get_scanner() will have been loaded with img. Therefore, you can call\n                  #get_scanner().get_feature_vector() to obtain the feature vectors or\n                  #get_scanner().get_full_object_detection() to get the\n                  full_object_detections for the resulting object detection boxes.\n                - The detection threshold is adjusted by having adjust_threshold added to\n                  it.  Therefore, an adjust_threshold value > 0 makes detecting objects\n                  harder while a negative value makes it easier.  Moreover, the following\n                  will be true for all valid i:\n                    - #dets[i].detection_confidence >= adjust_threshold\n                  This means that, for example, you can obtain the maximum possible number\n                  of detections by setting adjust_threshold equal to negative infinity.\n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<full_detection>& dets,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - This function is identical to the above operator() routine, except that\n                  it outputs full_object_detections instead of rectangles.  This means that\n                  the output includes part locations.  In particular, calling this function\n                  is the same as calling the above operator() routine and then using\n                  get_scanner().get_full_object_detection() to resolve all the rectangles\n                  into full_object_detections.  Therefore, this version of operator() is\n                  simply a convenience function for performing this set of operations.\n        !*/\n\n        template <\n            typename image_type\n            >\n        std::vector<rectangle> operator() (\n            const image_type& img,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - This function is identical to the above operator() routine, except that\n                  it returns a std::vector<rectangle> which contains just the bounding\n                  boxes of all the detections. \n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<std::pair<double, rectangle> >& dets,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - performs object detection on the given image and stores the\n                  detected objects into #dets.  In particular, we will have that:\n                    - #dets is sorted such that the highest confidence detections \n                      come first.  E.g. element 0 is the best detection, element 1 \n                      the next best, and so on.\n                    - #dets.size() == the number of detected objects.\n                    - #dets[i].first gives the \"detection confidence\", of the i-th\n                      detection.  This is the detection value output by the scanner minus\n                      the threshold value stored at the end of the weight vector in get_w(). \n                    - #dets[i].second == the bounding box for the i-th detection.\n                - #get_scanner() will have been loaded with img. Therefore, you can call\n                  #get_scanner().get_feature_vector() to obtain the feature vectors or\n                  #get_scanner().get_full_object_detection() to get the\n                  full_object_detections for the resulting object detection boxes.\n                - The detection threshold is adjusted by having adjust_threshold added to\n                  it.  Therefore, an adjust_threshold value > 0 makes detecting objects\n                  harder while a negative value makes it easier.  Moreover, the following\n                  will be true for all valid i:\n                    - #dets[i].first >= adjust_threshold\n                  This means that, for example, you can obtain the maximum possible number\n                  of detections by setting adjust_threshold equal to negative infinity.\n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<std::pair<double, full_object_detection> >& dets,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - This function is identical to the above operator() routine, except that\n                  it outputs full_object_detections instead of rectangles.  This means that\n                  the output includes part locations.  In particular, calling this function\n                  is the same as calling the above operator() routine and then using\n                  get_scanner().get_full_object_detection() to resolve all the rectangles\n                  into full_object_detections.  Therefore, this version of operator() is\n                  simply a convenience function for performing this set of operations.\n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            const image_type& img,\n            std::vector<full_object_detection>& dets,\n            double adjust_threshold = 0\n        );\n        /*!\n            requires\n                - img == an object which can be accepted by image_scanner_type::load()\n            ensures\n                - This function is identical to the above operator() routine, except that\n                  it doesn't include a double valued score.  That is, it just outputs the\n                  full_object_detections.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const object_detector<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support.  Note that this function only saves the\n        configuration part of item.get_scanner().  That is, we use the scanner's\n        copy_configuration() function to get a copy of the scanner that doesn't contain any\n        loaded image data and we then save just the configuration part of the scanner.\n        This means that any serialized object_detectors won't remember any images they have\n        processed but will otherwise contain all their state and be able to detect objects\n        in new images.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void deserialize (\n        object_detector<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OBJECT_DeTECTOR_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/remove_unobtainable_rectangles.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_\n#define DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_\n\n#include \"remove_unobtainable_rectangles_abstract.h\"\n#include \"scan_image_pyramid.h\"\n#include \"scan_image_boxes.h\"\n#include \"scan_image_custom.h\"\n#include \"scan_fhog_pyramid.h\"\n#include \"../svm/structural_object_detection_trainer.h\"\n#include \"../geometry.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline bool matches_rect (\n            const std::vector<rectangle>& rects,\n            const rectangle& rect,\n            const double eps\n        )\n        {\n            for (unsigned long i = 0; i < rects.size(); ++i)\n            {\n                const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();\n                if (score > eps)\n                    return true;\n            }\n\n            return false;\n        }\n\n        inline rectangle get_best_matching_rect (\n            const std::vector<rectangle>& rects,\n            const rectangle& rect\n        ) \n        {\n            double best_score = -1;\n            rectangle best_rect;\n            for (unsigned long i = 0; i < rects.size(); ++i)\n            {\n                const double score = (rect.intersect(rects[i])).area()/(double)(rect+rects[i]).area();\n                if (score > best_score)\n                {\n                    best_score = score;\n                    best_rect = rects[i];\n                }\n            }\n            return best_rect;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename image_array_type,\n            typename image_scanner_type\n            >\n        std::vector<std::vector<rectangle> > pyramid_remove_unobtainable_rectangles (\n            const structural_object_detection_trainer<image_scanner_type>& trainer,\n            const image_array_type& images,\n            std::vector<std::vector<rectangle> >& object_locations\n        )\n        {\n            using namespace dlib::impl;\n            // make sure requires clause is not broken\n            DLIB_ASSERT(images.size() == object_locations.size(),\n                \"\\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n            );\n\n\n            std::vector<std::vector<rectangle> > rejects(images.size());\n\n            // If the trainer is setup to automatically fit the overlap tester to the data then\n            // we should use the loosest possible overlap tester here.  Otherwise we should use\n            // the tester the trainer will use.\n            test_box_overlap boxes_overlap(0.9999999,1); \n            if (!trainer.auto_set_overlap_tester())\n                boxes_overlap = trainer.get_overlap_tester();\n\n            for (unsigned long k = 0; k < images.size(); ++k)\n            {\n                std::vector<rectangle> objs = object_locations[k];\n\n                // First remove things that don't have any matches with the candidate object\n                // locations.\n                std::vector<rectangle> good_rects;\n                for (unsigned long j = 0; j < objs.size(); ++j)\n                {\n                    const rectangle rect = trainer.get_scanner().get_best_matching_rect(objs[j]);\n                    const double score = (objs[j].intersect(rect)).area()/(double)(objs[j] + rect).area();\n                    if (score > trainer.get_match_eps())\n                        good_rects.push_back(objs[j]);\n                    else\n                        rejects[k].push_back(objs[j]);\n                }\n                object_locations[k] = good_rects;\n\n\n                // Remap these rectangles to the ones that can come out of the scanner.  That\n                // way when we compare them to each other in the following loop we will know if\n                // any distinct truth rectangles get mapped to overlapping boxes.\n                objs.resize(good_rects.size());\n                for (unsigned long i = 0; i < good_rects.size(); ++i)\n                    objs[i] = trainer.get_scanner().get_best_matching_rect(good_rects[i]);\n\n                good_rects.clear();\n                // now check for truth rects that are too close together.\n                for (unsigned long i = 0; i < objs.size(); ++i)\n                {\n                    // check if objs[i] hits another box\n                    bool hit_box = false;\n                    for (unsigned long j = i+1; j < objs.size(); ++j)\n                    {\n                        if (boxes_overlap(objs[i], objs[j]))\n                        {\n                            hit_box = true;\n                            break;\n                        }\n                    }\n                    if (hit_box)\n                        rejects[k].push_back(object_locations[k][i]);\n                    else\n                        good_rects.push_back(object_locations[k][i]);\n                }\n                object_locations[k] = good_rects;\n            }\n\n            return rejects;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n        const structural_object_detection_trainer<scan_image_pyramid<Pyramid_type, Feature_extractor_type> >& trainer,\n        const image_array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations\n    )\n    {\n        return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n        const structural_object_detection_trainer<scan_fhog_pyramid<Pyramid_type,Feature_extractor_type> >& trainer,\n        const image_array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations\n    )\n    {\n        return impl::pyramid_remove_unobtainable_rectangles(trainer, images, object_locations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename image_array_type,\n            typename scanner_type, \n            typename get_boxes_functor\n            >\n        std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n            get_boxes_functor& bg,\n            const structural_object_detection_trainer<scanner_type>& trainer,\n            const image_array_type& images,\n            std::vector<std::vector<rectangle> >& object_locations\n        )\n        {\n            using namespace dlib::impl;\n            // make sure requires clause is not broken\n            DLIB_ASSERT(images.size() == object_locations.size(),\n                \"\\t std::vector<std::vector<rectangle>> remove_unobtainable_rectangles()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n            );\n\n            std::vector<rectangle> rects;\n\n            std::vector<std::vector<rectangle> > rejects(images.size());\n\n            // If the trainer is setup to automatically fit the overlap tester to the data then\n            // we should use the loosest possible overlap tester here.  Otherwise we should use\n            // the tester the trainer will use.\n            test_box_overlap boxes_overlap(0.9999999,1); \n            if (!trainer.auto_set_overlap_tester())\n                boxes_overlap = trainer.get_overlap_tester();\n\n            for (unsigned long k = 0; k < images.size(); ++k)\n            {\n                std::vector<rectangle> objs = object_locations[k];\n                // Don't even bother computing the candidate rectangles if there aren't any\n                // object locations for this image since there isn't anything to do anyway.\n                if (objs.size() == 0)\n                    continue;\n\n                bg(images[k], rects);\n\n\n                // First remove things that don't have any matches with the candidate object\n                // locations.\n                std::vector<rectangle> good_rects;\n                for (unsigned long j = 0; j < objs.size(); ++j)\n                {\n                    if (matches_rect(rects, objs[j], trainer.get_match_eps()))\n                        good_rects.push_back(objs[j]);\n                    else\n                        rejects[k].push_back(objs[j]);\n                }\n                object_locations[k] = good_rects;\n\n\n                // Remap these rectangles to the ones that can come out of the scanner.  That\n                // way when we compare them to each other in the following loop we will know if\n                // any distinct truth rectangles get mapped to overlapping boxes.\n                objs.resize(good_rects.size());\n                for (unsigned long i = 0; i < good_rects.size(); ++i)\n                    objs[i] = get_best_matching_rect(rects, good_rects[i]);\n\n                good_rects.clear();\n                // now check for truth rects that are too close together.\n                for (unsigned long i = 0; i < objs.size(); ++i)\n                {\n                    // check if objs[i] hits another box\n                    bool hit_box = false;\n                    for (unsigned long j = i+1; j < objs.size(); ++j)\n                    {\n                        if (boxes_overlap(objs[i], objs[j]))\n                        {\n                            hit_box = true;\n                            break;\n                        }\n                    }\n                    if (hit_box)\n                        rejects[k].push_back(object_locations[k][i]);\n                    else\n                        good_rects.push_back(object_locations[k][i]);\n                }\n                object_locations[k] = good_rects;\n            }\n\n            return rejects;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename T>\n        struct load_to_functor\n        {\n            load_to_functor(T& obj_) : obj(obj_) {}\n            T& obj;\n\n            template <typename U, typename V>\n            void operator()(const U& u, V& v) \n            {\n                obj.load(u,v);\n            }\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename feature_extractor, \n        typename box_generator\n        >\n    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n        const structural_object_detection_trainer<scan_image_boxes<feature_extractor, box_generator> >& trainer,\n        const image_array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations\n    )\n    {\n        box_generator bg = trainer.get_scanner().get_box_generator();\n        return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename feature_extractor\n        >\n    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n        const structural_object_detection_trainer<scan_image_custom<feature_extractor> >& trainer,\n        const image_array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations\n    )\n    {\n        feature_extractor fe;\n        fe.copy_configuration(trainer.get_scanner().get_feature_extractor());\n        impl::load_to_functor<feature_extractor> bg(fe);\n        return impl::remove_unobtainable_rectangles(bg, trainer, images, object_locations);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/remove_unobtainable_rectangles_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_\n#ifdef DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_\n\n#include \"scan_image_pyramid_abstract.h\"\n#include \"scan_image_boxes_abstract.h\"\n#include \"scan_image_custom_abstract.h\"\n#include \"scan_fhog_pyramid_abstract.h\"\n#include \"../svm/structural_object_detection_trainer_abstract.h\"\n#include \"../geometry.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type,\n        typename image_array_type\n        >\n    std::vector<std::vector<rectangle> > remove_unobtainable_rectangles (\n        const structural_object_detection_trainer<image_scanner_type>& trainer,\n        const image_array_type& images,\n        std::vector<std::vector<rectangle> >& object_locations\n    );\n    /*!\n        requires\n            - image_scanner_type must be either scan_image_boxes, scan_image_pyramid,\n              scan_image_custom, or scan_fhog_pyramid.\n            - images.size() == object_locations.size()\n        ensures\n            - Recall that the image scanner objects can't produce all possible rectangles\n              as object detections since they only consider a limited subset of all possible\n              object positions.  Moreover, the structural_object_detection_trainer requires\n              its input training data to not contain any object positions which are unobtainable\n              by its scanner object.  Therefore, remove_unobtainable_rectangles() is a tool\n              to filter out these unobtainable rectangles from the training data before giving\n              it to a structural_object_detection_trainer.\n            - This function interprets object_locations[i] as the set of object positions for\n              image[i], for all valid i.\n            - In particular, this function removes unobtainable rectangles from object_locations\n              and also returns a vector V such that:\n                - V.size() == object_locations.size()\n                - for all valid i:\n                    - V[i] == the set of rectangles removed from object_locations[i]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_REMOVE_UnOBTAINABLE_RECTANGLES_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/render_face_detections.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RENDER_FACE_DeTECTIONS_H_\n#define DLIB_RENDER_FACE_DeTECTIONS_H_\n\n#include \"full_object_detection.h\"\n#include \"../gui_widgets.h\"\n#include \"render_face_detections_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n    inline std::vector<image_window::overlay_line> render_face_detections (\n        const std::vector<full_object_detection>& dets,\n        const rgb_pixel color = rgb_pixel(0,255,0)\n    )\n    {\n        std::vector<image_window::overlay_line> lines;\n        for (unsigned long i = 0; i < dets.size(); ++i)\n        {\n            DLIB_CASSERT(dets[i].num_parts() == 68 || dets[i].num_parts() == 5,\n                \"\\t std::vector<image_window::overlay_line> render_face_detections()\"\n                << \"\\n\\t You have to give either a 5 point or 68 point face landmarking output to this function. \"\n                << \"\\n\\t dets[\"<<i<<\"].num_parts():  \" << dets[i].num_parts() \n            );\n\n            const full_object_detection& d = dets[i];\n\n            if (d.num_parts() == 5)\n            {\n                lines.push_back(image_window::overlay_line(d.part(0), d.part(1), color));\n                lines.push_back(image_window::overlay_line(d.part(1), d.part(4), color));\n                lines.push_back(image_window::overlay_line(d.part(4), d.part(3), color));\n                lines.push_back(image_window::overlay_line(d.part(3), d.part(2), color));\n            }\n            else\n            {\n                // Around Chin. Ear to Ear\n                for (unsigned long i = 1; i <= 16; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n\n                // Line on top of nose\n                for (unsigned long i = 28; i <= 30; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n\n                // left eyebrow\n                for (unsigned long i = 18; i <= 21; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                // Right eyebrow\n                for (unsigned long i = 23; i <= 26; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                // Bottom part of the nose\n                for (unsigned long i = 31; i <= 35; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                // Line from the nose to the bottom part above\n                lines.push_back(image_window::overlay_line(d.part(30), d.part(35), color));\n\n                // Left eye\n                for (unsigned long i = 37; i <= 41; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                lines.push_back(image_window::overlay_line(d.part(36), d.part(41), color));\n\n                // Right eye\n                for (unsigned long i = 43; i <= 47; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                lines.push_back(image_window::overlay_line(d.part(42), d.part(47), color));\n\n                // Lips outer part\n                for (unsigned long i = 49; i <= 59; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                lines.push_back(image_window::overlay_line(d.part(48), d.part(59), color));\n\n                // Lips inside part\n                for (unsigned long i = 61; i <= 67; ++i)\n                    lines.push_back(image_window::overlay_line(d.part(i), d.part(i-1), color));\n                lines.push_back(image_window::overlay_line(d.part(60), d.part(67), color));\n            }\n        }\n        return lines;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<image_window::overlay_line> render_face_detections (\n        const full_object_detection& det,\n        const rgb_pixel color = rgb_pixel(0,255,0)\n    )\n    {\n        std::vector<full_object_detection> dets;\n        dets.push_back(det);\n        return render_face_detections(dets, color);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RENDER_FACE_DeTECTIONS_H_\n\n"
  },
  {
    "path": "dlib/image_processing/render_face_detections_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_\n#ifdef DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_\n\n#include \"full_object_detection_abstract.h\"\n#include \"../gui_widgets.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<image_window::overlay_line> render_face_detections (\n        const std::vector<full_object_detection>& dets,\n        const rgb_pixel color = rgb_pixel(0,255,0)\n    );\n    /*!\n        requires\n            - for all valid i:\n                - dets[i].num_parts() == 68 || dets[i].num_parts() == 5\n        ensures\n            - Interprets the given objects as face detections with parts annotated using\n              either the iBUG face landmark scheme or a 5 point face annotation.  We then\n              return a set of overlay lines that will draw the objects onto the screen in a\n              way that properly draws the outline of the face features defined by the part\n              locations.\n            - returns a vector with dets.size() elements, each containing the lines\n              necessary to render a face detection from dets.\n            - The 5 point face annotation scheme is assumed to be:\n                - det part 0 == left eye corner, outside part of eye.\n                - det part 1 == left eye corner, inside part of eye.\n                - det part 2 == right eye corner, outside part of eye.\n                - det part 3 == right eye corner, inside part of eye.\n                - det part 4 == immediately under the nose, right at the top of the philtrum.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<image_window::overlay_line> render_face_detections (\n        const full_object_detection& det,\n        const rgb_pixel color = rgb_pixel(0,255,0)\n    );\n    /*!\n        requires\n            - det.num_parts() == 68 || det.num_parts() == 5\n        ensures\n            - This function is identical to the above render_face_detections() routine\n              except that it takes just a single full_object_detection instead of a\n              std::vector of them.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RENDER_FACE_DeTECTIONS_ABSTRACT_H_\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_fhog_pyramid.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_fHOG_PYRAMID_Hh_\n#define DLIB_SCAN_fHOG_PYRAMID_Hh_\n\n#include \"scan_fhog_pyramid_abstract.h\"\n#include \"../matrix.h\"\n#include \"../image_transforms.h\"\n#include \"../array.h\"\n#include \"../array2d.h\"\n#include \"object_detector.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class default_fhog_feature_extractor\n    {\n    public:\n        inline rectangle image_to_feats (\n            const rectangle& rect,\n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const\n        {\n            return image_to_fhog(rect, cell_size, filter_rows_padding, filter_cols_padding);\n        }\n\n        inline rectangle feats_to_image (\n            const rectangle& rect,\n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const\n        {\n            return fhog_to_image(rect, cell_size, filter_rows_padding, filter_cols_padding);\n        }\n\n        template <\n            typename image_type\n            >\n        void operator()(\n            const image_type& img, \n            dlib::array<array2d<float> >& hog, \n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const\n        {\n            extract_fhog_features(img,hog,cell_size,filter_rows_padding,filter_cols_padding);\n        }\n\n        inline unsigned long get_num_planes (\n        ) const\n        {\n            return 31;\n        }\n    };\n\n    inline void serialize   (const default_fhog_feature_extractor&, std::ostream&) {}\n    inline void deserialize (default_fhog_feature_extractor&, std::istream&) {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type = default_fhog_feature_extractor\n        >\n    class scan_fhog_pyramid : noncopyable\n    {\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n\n        typedef Pyramid_type pyramid_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_fhog_pyramid (\n        );  \n\n        explicit scan_fhog_pyramid (\n            const feature_extractor_type& fe_\n        );  \n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n\n        inline bool is_loaded_with_image (\n        ) const;\n\n        inline void copy_configuration (\n            const scan_fhog_pyramid& item\n        );\n\n        void set_detection_window_size (\n            unsigned long width,\n            unsigned long height\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(width > 0 && height > 0,\n                \"\\t void scan_fhog_pyramid::set_detection_window_size()\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t width:  \" << width\n                << \"\\n\\t height: \" << height\n                << \"\\n\\t this:   \" << this\n                );\n\n            window_width = width;\n            window_height = height;\n            feats.clear();\n        }\n\n        inline unsigned long get_detection_window_width (\n        ) const { return window_width; }\n        inline unsigned long get_detection_window_height (\n        ) const { return window_height; }\n\n        inline unsigned long get_num_detection_templates (\n        ) const;\n\n        inline unsigned long get_num_movable_components_per_detection_template (\n        ) const;\n\n        void set_padding (\n            unsigned long new_padding\n        )\n        {\n            padding = new_padding;\n            feats.clear();\n        }\n\n        unsigned long get_padding (\n        ) const { return padding; }\n\n        void set_cell_size (\n            unsigned long new_cell_size\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(new_cell_size > 0 ,\n                \"\\t void scan_fhog_pyramid::set_cell_size()\"\n                << \"\\n\\t You can't have zero sized fHOG cells. \"\n                << \"\\n\\t this: \" << this\n                );\n\n            cell_size = new_cell_size;\n            feats.clear();\n        }\n\n        unsigned long get_cell_size (\n        ) const { return cell_size; }\n\n        inline long get_num_dimensions (\n        ) const;\n\n        unsigned long get_max_pyramid_levels (\n        ) const;\n\n        const feature_extractor_type& get_feature_extractor(\n        ) const { return fe; }\n\n        void set_max_pyramid_levels (\n            unsigned long max_levels\n        );\n\n        void set_min_pyramid_layer_size (\n            unsigned long width,\n            unsigned long height \n        );\n\n        inline unsigned long get_min_pyramid_layer_width (\n        ) const;\n\n        inline unsigned long get_min_pyramid_layer_height (\n        ) const;\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_loaded_with_image() &&\n                        w.size() >= get_num_dimensions(), \n                \"\\t void scan_fhog_pyramid::detect()\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n                << \"\\n\\t w.size():               \" << w.size()\n                << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n                << \"\\n\\t this: \" << this\n                );\n\n            fhog_filterbank temp = build_fhog_filterbank(w);\n            detect(temp, dets, thresh);\n        }\n\n        class fhog_filterbank \n        {\n            friend class scan_fhog_pyramid;\n        public:\n            inline long get_num_dimensions() const\n            {\n                unsigned long dims = 0;\n                for (unsigned long i = 0; i < filters.size(); ++i)\n                {\n                    dims += filters[i].size();\n                }\n                return dims;\n            }\n\n            const std::vector<matrix<float> >& get_filters() const { return filters;} \n\n            unsigned long num_separable_filters() const \n            {\n                unsigned long num = 0;\n                for (unsigned long i = 0; i < row_filters.size(); ++i)\n                {\n                    num += row_filters[i].size();\n                }\n                return num;\n            }\n\n            std::vector<matrix<float> > filters;\n            std::vector<std::vector<matrix<float,0,1> > > row_filters, col_filters;\n        };\n\n        fhog_filterbank build_fhog_filterbank (\n            const feature_vector_type& weights \n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(weights.size() >= get_num_dimensions(),\n                \"\\t fhog_filterbank scan_fhog_pyramid::build_fhog_filterbank()\"\n                << \"\\n\\t The number of weights isn't enough to fill out the filterbank. \"\n                << \"\\n\\t weights.size():       \" << weights.size() \n                << \"\\n\\t get_num_dimensions(): \" << get_num_dimensions() \n                << \"\\n\\t this: \" << this\n                );\n\n            fhog_filterbank temp;\n            temp.filters.resize(fe.get_num_planes());\n            temp.row_filters.resize(fe.get_num_planes());\n            temp.col_filters.resize(fe.get_num_planes());\n\n            // load filters from w\n            unsigned long width, height;\n            compute_fhog_window_size(width, height);\n            const long size = width*height;\n            for (unsigned long i = 0; i < temp.filters.size(); ++i)\n            {\n                matrix<double> u,v,w,f;\n                f = reshape(rowm(weights, range(i*size, (i+1)*size-1)), height, width);\n                temp.filters[i] = matrix_cast<float>(f);\n\n                svd3(f, u,w,v);\n\n                matrix<double> w2 = w;\n                rsort_columns(u,w);\n                rsort_columns(v,w2);\n\n                double thresh = std::max(1e-4, max(w)*0.001);\n                w = round_zeros(w, thresh);\n\n\n                for (long j = 0; j < w.size(); ++j)\n                {\n                    if (w(j) != 0)\n                    {\n                        temp.col_filters[i].push_back(matrix_cast<float>(colm(u,j)*std::sqrt(w(j))));\n                        temp.row_filters[i].push_back(matrix_cast<float>(colm(v,j)*std::sqrt(w(j))));\n                    }\n                }\n            }\n\n            return temp;\n        }\n\n        void detect (\n            const fhog_filterbank& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n\n        double get_nuclear_norm_regularization_strength (\n        ) const { return nuclear_norm_regularization_strength; }\n\n        void set_nuclear_norm_regularization_strength (\n            double strength\n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(strength >= 0 ,\n                \"\\t void scan_fhog_pyramid::set_nuclear_norm_regularization_strength()\"\n                << \"\\n\\t You can't have a negative regularization strength.\"\n                << \"\\n\\t strength: \" << strength \n                << \"\\n\\t this: \" << this\n            );\n\n            nuclear_norm_regularization_strength = strength;\n        }\n\n        unsigned long get_fhog_window_width (\n        ) const \n        {\n            unsigned long width, height;\n            compute_fhog_window_size(width, height);\n            return width;\n        }\n\n        unsigned long get_fhog_window_height (\n        ) const \n        {\n            unsigned long width, height;\n            compute_fhog_window_size(width, height);\n            return height;\n        }\n\n        template <typename T, typename U>\n        friend void serialize (\n            const scan_fhog_pyramid<T,U>& item,\n            std::ostream& out\n        );\n\n        template <typename T, typename U>\n        friend void deserialize (\n            scan_fhog_pyramid<T,U>& item,\n            std::istream& in \n        );\n\n    private:\n        inline void compute_fhog_window_size(\n            unsigned long& width,\n            unsigned long& height\n        ) const\n        {\n            const rectangle rect = centered_rect(point(0,0),window_width,window_height);\n            const rectangle temp = grow_rect(fe.image_to_feats(rect, cell_size, 1, 1), padding);\n            width = temp.width();\n            height = temp.height();\n        }\n\n        void get_mapped_rect_and_metadata (\n            const unsigned long number_pyramid_levels,\n            const rectangle& rect,\n            rectangle& mapped_rect,\n            rectangle& fhog_rect,\n            unsigned long& best_level\n        ) const;\n\n        double get_match_score (\n            rectangle r1,\n            rectangle r2\n        ) const\n        {\n            // make the rectangles overlap as much as possible before computing the match score.\n            r1 = move_rect(r1, r2.tl_corner());\n            return (r1.intersect(r2).area())/(double)(r1 + r2).area();\n        }\n\n        typedef array<array2d<float> > fhog_image;\n\n        feature_extractor_type fe;\n        array<fhog_image> feats;\n        int cell_size;\n        unsigned long padding; \n        unsigned long window_width;\n        unsigned long window_height;\n        unsigned long max_pyramid_levels;\n        unsigned long min_pyramid_layer_width;\n        unsigned long min_pyramid_layer_height;\n        double nuclear_norm_regularization_strength;\n\n        void init()\n        {\n            cell_size = 8;\n            padding = 1;\n            window_width = 64;\n            window_height = 64;\n            max_pyramid_levels = 1000;\n            min_pyramid_layer_width = 64;\n            min_pyramid_layer_height = 64;\n            nuclear_norm_regularization_strength = 0;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename fhog_filterbank>\n        rectangle apply_filters_to_fhog (\n            const fhog_filterbank& w,\n            const array<array2d<float> >& feats,\n            array2d<float>& saliency_image\n        )\n        {\n            const unsigned long num_separable_filters = w.num_separable_filters();\n            rectangle area;\n            // use the separable filters if they would be faster than running the regular filters.\n            if (num_separable_filters > w.filters.size()*std::min(w.filters[0].nr(),w.filters[0].nc())/3.0)\n            {\n                area = spatially_filter_image(feats[0], saliency_image, w.filters[0]);\n                for (unsigned long i = 1; i < w.filters.size(); ++i)\n                {\n                    // now we filter but the output adds to saliency_image rather than\n                    // overwriting it.\n                    spatially_filter_image(feats[i], saliency_image, w.filters[i], 1, false, true);\n                }\n            }\n            else\n            {\n                saliency_image.clear();\n                array2d<float> scratch;\n\n                // find the first filter to apply\n                unsigned long i = 0;\n                while (i < w.row_filters.size() && w.row_filters[i].size() == 0) \n                    ++i;\n\n                for (; i < w.row_filters.size(); ++i)\n                {\n                    for (unsigned long j = 0; j < w.row_filters[i].size(); ++j)\n                    {\n                        if (saliency_image.size() == 0)\n                            area = float_spatially_filter_image_separable(feats[i], saliency_image, w.row_filters[i][j], w.col_filters[i][j],scratch,false);\n                        else\n                            area = float_spatially_filter_image_separable(feats[i], saliency_image, w.row_filters[i][j], w.col_filters[i][j],scratch,true);\n                    }\n                }\n                if (saliency_image.size() == 0)\n                {\n                    saliency_image.set_size(feats[0].nr(), feats[0].nc());\n                    assign_all_pixels(saliency_image, 0);\n                }\n            }\n            return area;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void serialize (\n        const scan_fhog_pyramid<T,U>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.fe, out);\n        serialize(item.feats, out);\n        serialize(item.cell_size, out);\n        serialize(item.padding, out);\n        serialize(item.window_width, out);\n        serialize(item.window_height, out);\n        serialize(item.max_pyramid_levels, out);\n        serialize(item.min_pyramid_layer_width, out);\n        serialize(item.min_pyramid_layer_height, out);\n        serialize(item.nuclear_norm_regularization_strength, out);\n        serialize(item.get_num_dimensions(), out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void deserialize (\n        scan_fhog_pyramid<T,U>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unsupported version found when deserializing a scan_fhog_pyramid object.\");\n\n        deserialize(item.fe, in);\n        deserialize(item.feats, in);\n        deserialize(item.cell_size, in);\n        deserialize(item.padding, in);\n        deserialize(item.window_width, in);\n        deserialize(item.window_height, in);\n        deserialize(item.max_pyramid_levels, in);\n        deserialize(item.min_pyramid_layer_width, in);\n        deserialize(item.min_pyramid_layer_height, in);\n        deserialize(item.nuclear_norm_regularization_strength, in);\n\n        // When developing some feature extractor, it's easy to accidentally change its\n        // number of dimensions and then try to deserialize data from an older version of\n        // your extractor into the current code.  This check is here to catch that kind of\n        // user error.\n        long dims;\n        deserialize(dims, in);\n        if (item.get_num_dimensions() != dims)\n            throw serialization_error(\"Number of dimensions in serialized scan_fhog_pyramid doesn't match the expected number.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                         scan_fhog_pyramid member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    scan_fhog_pyramid (\n    ) \n    {\n        init();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    scan_fhog_pyramid (\n        const feature_extractor_type& fe_\n    ) \n    {\n        init();\n        fe = fe_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename pyramid_type,\n            typename image_type,\n            typename feature_extractor_type\n            >\n        void create_fhog_pyramid (\n            const image_type& img,\n            const feature_extractor_type& fe,\n            array<array<array2d<float> > >& feats,\n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding,\n            unsigned long min_pyramid_layer_width,\n            unsigned long min_pyramid_layer_height,\n            unsigned long max_pyramid_levels\n        )\n        {\n            unsigned long levels = 0;\n            rectangle rect = get_rect(img);\n\n            // figure out how many pyramid levels we should be using based on the image size\n            pyramid_type pyr;\n            do\n            {\n                rect = pyr.rect_down(rect);\n                ++levels;\n            } while (rect.width() >= min_pyramid_layer_width && rect.height() >= min_pyramid_layer_height &&\n                levels < max_pyramid_levels);\n\n            if (feats.max_size() < levels)\n                feats.set_max_size(levels);\n            feats.set_size(levels);\n\n\n\n            // build our feature pyramid\n            fe(img, feats[0], cell_size,filter_rows_padding,filter_cols_padding);\n            DLIB_ASSERT(feats[0].size() == fe.get_num_planes(), \n                \"Invalid feature extractor used with dlib::scan_fhog_pyramid.  The output does not have the \\n\"\n                \"indicated number of planes.\");\n\n            if (feats.size() > 1)\n            {\n                typedef typename image_traits<image_type>::pixel_type pixel_type;\n                array2d<pixel_type> temp1, temp2;\n                pyr(img, temp1);\n                fe(temp1, feats[1], cell_size,filter_rows_padding,filter_cols_padding);\n                swap(temp1,temp2);\n\n                for (unsigned long i = 2; i < feats.size(); ++i)\n                {\n                    pyr(temp2, temp1);\n                    fe(temp1, feats[i], cell_size,filter_rows_padding,filter_cols_padding);\n                    swap(temp1,temp2);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    template <\n        typename image_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    load (\n        const image_type& img\n    )\n    {\n        unsigned long width, height;\n        compute_fhog_window_size(width,height);\n        impl::create_fhog_pyramid<Pyramid_type>(img, fe, feats, cell_size, height,\n            width, min_pyramid_layer_width, min_pyramid_layer_height,\n            max_pyramid_levels);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    bool scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    is_loaded_with_image (\n    ) const\n    {\n        return feats.size() != 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    copy_configuration (\n        const scan_fhog_pyramid& item\n    )\n    {\n        cell_size = item.cell_size;\n        padding = item.padding;\n        window_width = item.window_width;\n        window_height = item.window_height;\n        max_pyramid_levels = item.max_pyramid_levels;\n        min_pyramid_layer_width = item.min_pyramid_layer_width;\n        min_pyramid_layer_height = item.min_pyramid_layer_height;\n        nuclear_norm_regularization_strength = item.nuclear_norm_regularization_strength;\n        fe = item.fe;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_num_detection_templates (\n    ) const\n    {\n        return 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_num_movable_components_per_detection_template (\n    ) const\n    {\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_num_dimensions (\n    ) const\n    {\n        unsigned long width, height;\n        compute_fhog_window_size(width,height);\n        return width*height*fe.get_num_planes();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_max_pyramid_levels (\n    ) const\n    {\n        return max_pyramid_levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    set_max_pyramid_levels (\n        unsigned long max_levels\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(max_levels > 0 ,\n            \"\\t void scan_fhog_pyramid::set_max_pyramid_levels()\"\n            << \"\\n\\t You can't have zero levels. \"\n            << \"\\n\\t max_levels: \" << max_levels \n            << \"\\n\\t this: \" << this\n            );\n\n        max_pyramid_levels = max_levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline bool compare_pair_rect (\n            const std::pair<double, rectangle>& a,\n            const std::pair<double, rectangle>& b\n        )\n        {\n            return a.first < b.first;\n        }\n\n        template <\n            typename pyramid_type,\n            typename feature_extractor_type,\n            typename fhog_filterbank\n            >\n        void detect_from_fhog_pyramid (\n            const array<array<array2d<float> > >& feats,\n            const feature_extractor_type& fe,\n            const fhog_filterbank& w,\n            const double thresh,\n            const unsigned long det_box_height,\n            const unsigned long det_box_width,\n            const int cell_size,\n            const int filter_rows_padding,\n            const int filter_cols_padding,\n            std::vector<std::pair<double, rectangle> >& dets\n        ) \n        {\n            dets.clear();\n\n            array2d<float> saliency_image;\n            pyramid_type pyr;\n\n            // for all pyramid levels\n            for (unsigned long l = 0; l < feats.size(); ++l)\n            {\n                const rectangle area = apply_filters_to_fhog(w, feats[l], saliency_image);\n\n                // now search the saliency image for any detections\n                for (long r = area.top(); r <= area.bottom(); ++r)\n                {\n                    for (long c = area.left(); c <= area.right(); ++c)\n                    {\n                        // if we found a detection\n                        if (saliency_image[r][c] >= thresh)\n                        {\n                            rectangle rect = fe.feats_to_image(centered_rect(point(c,r),det_box_width,det_box_height), \n                                cell_size, filter_rows_padding, filter_cols_padding);\n                            rect = pyr.rect_up(rect, l);\n                            dets.push_back(std::make_pair(saliency_image[r][c], rect));\n                        }\n                    }\n                }\n            }\n\n            std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);\n        }\n\n        inline bool overlaps_any_box (\n            const test_box_overlap& tester,\n            const std::vector<rect_detection>& rects,\n            const rect_detection& rect\n        ) \n        {\n            for (unsigned long i = 0; i < rects.size(); ++i)\n            {\n                // Only compare detections from the same detector.  That is, we don't want\n                // the output of one detector to stop on the output of another detector. \n                if (rects[i].weight_index == rect.weight_index && tester(rects[i].rect, rect.rect))\n                    return true;\n            }\n            return false;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    detect (\n        const fhog_filterbank& w,\n        std::vector<std::pair<double, rectangle> >& dets,\n        const double thresh\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    w.get_num_dimensions() == get_num_dimensions(), \n            \"\\t void scan_fhog_pyramid::detect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t w.get_num_dimensions(): \" << w.get_num_dimensions()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t this: \" << this\n            );\n\n        unsigned long width, height;\n        compute_fhog_window_size(width,height);\n\n        impl::detect_from_fhog_pyramid<pyramid_type>(feats, fe, w, thresh,\n            height-2*padding, width-2*padding, cell_size, height, width, dets);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    const rectangle scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_best_matching_rect (\n        const rectangle& rect\n    ) const\n    {\n        rectangle mapped_rect, fhog_rect;\n        unsigned long best_level;\n        get_mapped_rect_and_metadata(max_pyramid_levels, rect, mapped_rect, fhog_rect, best_level);\n        return mapped_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_mapped_rect_and_metadata (\n        const unsigned long number_pyramid_levels,\n        const rectangle& rect,\n        rectangle& mapped_rect,\n        rectangle& fhog_rect,\n        unsigned long& best_level\n    ) const\n    {\n        pyramid_type pyr;\n        best_level = 0;\n        double best_match_score = -1;\n\n\n        unsigned long width, height;\n        compute_fhog_window_size(width,height);\n\n        // Figure out the pyramid level which best matches rect against our detection\n        // window. \n        for (unsigned long l = 0; l < number_pyramid_levels; ++l)\n        {\n            const rectangle rect_fhog_space = fe.image_to_feats(pyr.rect_down(rect,l), cell_size, height,width);\n\n            const rectangle win_image_space = pyr.rect_up(fe.feats_to_image(centered_rect(center(rect_fhog_space),width-2*padding,height-2*padding), cell_size, height,width), l);\n\n            const double match_score = get_match_score(win_image_space, rect); \n            if (match_score > best_match_score)\n            {\n                best_match_score = match_score;\n                best_level = l;\n                fhog_rect = centered_rect(center(rect_fhog_space), width, height);\n            }\n\n            if (rect_fhog_space.area() <= 1) \n                break;\n        }\n        mapped_rect = pyr.rect_up(fe.feats_to_image(shrink_rect(fhog_rect,padding), cell_size,height,width),best_level);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    full_object_detection scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_full_object_detection (\n        const rectangle& rect,\n        const feature_vector_type& \n    ) const\n    {\n        return full_object_detection(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_feature_vector (\n        const full_object_detection& obj,\n        feature_vector_type& psi\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    psi.size() >= get_num_dimensions() &&\n                    obj.num_parts() == 0,\n            \"\\t void scan_fhog_pyramid::get_feature_vector()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t psi.size():             \" << psi.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t obj.num_parts():                            \" << obj.num_parts()\n            << \"\\n\\t this: \" << this\n            );\n\n\n\n        rectangle mapped_rect;\n        unsigned long best_level;\n        rectangle fhog_rect;\n        get_mapped_rect_and_metadata(feats.size(), obj.get_rect(), mapped_rect, fhog_rect, best_level);\n\n\n        long i = 0;\n        for (unsigned long ii = 0; ii < feats[best_level].size(); ++ii)\n        {\n            const rectangle rect = get_rect(feats[best_level][0]);\n            for (long r = fhog_rect.top(); r <= fhog_rect.bottom(); ++r)\n            {\n                for (long c = fhog_rect.left(); c <= fhog_rect.right(); ++c)\n                {\n                    if (rect.contains(c,r))\n                        psi(i) += feats[best_level][ii][r][c];\n                    ++i;\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    void scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    set_min_pyramid_layer_size (\n        unsigned long width,\n        unsigned long height \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(width > 0 && height > 0 ,\n            \"\\t void scan_fhog_pyramid::set_min_pyramid_layer_size()\"\n            << \"\\n\\t These sizes can't be zero. \"\n            << \"\\n\\t width:  \" << width \n            << \"\\n\\t height: \" << height \n            << \"\\n\\t this:   \" << this\n            );\n\n        min_pyramid_layer_width = width;\n        min_pyramid_layer_height = height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_min_pyramid_layer_width (\n    ) const\n    {\n        return min_pyramid_layer_width;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::\n    get_min_pyramid_layer_height (\n    ) const\n    {\n        return min_pyramid_layer_height;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    matrix<unsigned char> draw_fhog (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        const unsigned long weight_index = 0,\n        const long cell_draw_size = 15\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(weight_index < detector.num_detectors(),\n            \"\\t matrix draw_fhog()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t weight_index:             \" << weight_index\n            << \"\\n\\t detector.num_detectors(): \" << detector.num_detectors()\n            );\n        DLIB_ASSERT(cell_draw_size > 0 && detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions(),\n            \"\\t matrix draw_fhog()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t cell_draw_size:                              \" << cell_draw_size\n            << \"\\n\\t weight_index:                                \" << weight_index\n            << \"\\n\\t detector.get_w(weight_index).size():         \" << detector.get_w(weight_index).size()\n            << \"\\n\\t detector.get_scanner().get_num_dimensions(): \" << detector.get_scanner().get_num_dimensions()\n            );\n\n        typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fb = detector.get_scanner().build_fhog_filterbank(detector.get_w(weight_index));\n        return draw_fhog(fb.get_filters(),cell_draw_size);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long num_separable_filters (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        const unsigned long weight_index = 0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(weight_index < detector.num_detectors(),\n            \"\\t unsigned long num_separable_filters()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t weight_index:             \" << weight_index\n            << \"\\n\\t detector.num_detectors(): \" << detector.num_detectors()\n            );\n        DLIB_ASSERT(detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions() ,\n            \"\\t unsigned long num_separable_filters()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t detector.get_w(weight_index).size():         \" << detector.get_w(weight_index).size()\n            << \"\\n\\t detector.get_scanner().get_num_dimensions(): \" << detector.get_scanner().get_num_dimensions()\n            );\n\n        typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fb = detector.get_scanner().build_fhog_filterbank(detector.get_w(weight_index));\n        return fb.num_separable_filters();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> > threshold_filter_singular_values (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        double thresh,\n        const unsigned long weight_index = 0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(thresh >= 0 ,\n            \"\\t object_detector threshold_filter_singular_values()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t thresh: \" << thresh \n        );\n\n        DLIB_ASSERT(weight_index < detector.num_detectors(),\n            \"\\t object_detector threshold_filter_singular_values()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t weight_index:             \" << weight_index\n            << \"\\n\\t detector.num_detectors(): \" << detector.num_detectors()\n            );\n        DLIB_ASSERT(detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions() ,\n            \"\\t object_detector threshold_filter_singular_values()\"\n            << \"\\n\\t Invalid arguments were given to this function. \"\n            << \"\\n\\t detector.get_w(weight_index).size():         \" << detector.get_w(weight_index).size()\n            << \"\\n\\t detector.get_scanner().get_num_dimensions(): \" << detector.get_scanner().get_num_dimensions()\n            );\n\n\n        const unsigned long width = detector.get_scanner().get_fhog_window_width();\n        const unsigned long height = detector.get_scanner().get_fhog_window_height();\n        const long num_planes = detector.get_scanner().get_feature_extractor().get_num_planes();\n        const long size = width*height;\n\n        std::vector<matrix<double,0,1> > detector_weights;\n        for (unsigned long j = 0; j < detector.num_detectors(); ++j)\n        {\n            matrix<double,0,1> weights = detector.get_w(j);\n\n            if (j == weight_index)\n            {\n                matrix<double> u,v,w,f;\n                for (long i = 0; i < num_planes; ++i)\n                {\n                    f = reshape(rowm(weights, range(i*size, (i+1)*size-1)), height, width);\n\n                    svd3(f, u,w,v);\n                    const double scaled_thresh = std::max(1e-3, max(w)*thresh);\n                    w = round_zeros(w, scaled_thresh);\n                    f = u*diagm(w)*trans(v);\n\n                    set_rowm(weights,range(i*size, (i+1)*size-1)) = reshape_to_column_vector(f);\n                }\n            }\n            detector_weights.push_back(weights);\n        }\n        \n        return object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >(detector.get_scanner(), \n                                                                 detector.get_overlap_tester(),\n                                                                 detector_weights);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type,\n        typename svm_struct_prob_type\n        >\n    void configure_nuclear_norm_regularizer (\n        const scan_fhog_pyramid<Pyramid_type,feature_extractor_type>& scanner,\n        svm_struct_prob_type& prob\n    )\n    { \n        const double strength = scanner.get_nuclear_norm_regularization_strength();\n        const long num_planes = scanner.get_feature_extractor().get_num_planes();\n        if (strength != 0)\n        {\n            const unsigned long width = scanner.get_fhog_window_width();\n            const unsigned long height = scanner.get_fhog_window_height();\n            for (long i = 0; i < num_planes; ++i)\n            {\n                prob.add_nuclear_norm_regularizer(i*width*height, height, width, strength);\n            }\n            prob.set_cache_based_epsilon(0.001);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    struct processed_weight_vector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >\n    {\n        processed_weight_vector(){}\n\n        typedef matrix<double,0,1> feature_vector_type;\n        typedef typename scan_fhog_pyramid<Pyramid_type,feature_extractor_type>::fhog_filterbank fhog_filterbank;\n\n        void init (\n            const scan_fhog_pyramid<Pyramid_type,feature_extractor_type>& scanner\n        ) \n        {\n            fb = scanner.build_fhog_filterbank(w);\n        }\n\n        const fhog_filterbank& get_detect_argument() const { return fb; }\n\n        feature_vector_type w;\n        fhog_filterbank fb;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_type\n        >\n    void evaluate_detectors (\n        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type> > >& detectors,\n        const image_type& img,\n        std::vector<rect_detection>& dets,\n        const double adjust_threshold = 0\n    )\n    {\n        typedef scan_fhog_pyramid<pyramid_type> scanner_type;\n\n        dets.clear();\n        if (detectors.size() == 0)\n            return;\n\n        const unsigned long cell_size = detectors[0].get_scanner().get_cell_size();\n\n        // Find the maximum sized filters and also most extreme pyramiding settings used.\n        unsigned long max_filter_width = 0;\n        unsigned long max_filter_height = 0;\n        unsigned long min_pyramid_layer_width = std::numeric_limits<unsigned long>::max();\n        unsigned long min_pyramid_layer_height = std::numeric_limits<unsigned long>::max();\n        unsigned long max_pyramid_levels = 0;\n        bool all_cell_sizes_the_same = true;\n        for (unsigned long i = 0; i < detectors.size(); ++i)\n        {\n            const scanner_type& scanner = detectors[i].get_scanner();\n            max_filter_width = std::max(max_filter_width, scanner.get_fhog_window_width());\n            max_filter_height = std::max(max_filter_height, scanner.get_fhog_window_height());\n            max_pyramid_levels = std::max(max_pyramid_levels, scanner.get_max_pyramid_levels());\n            min_pyramid_layer_width = std::min(min_pyramid_layer_width, scanner.get_min_pyramid_layer_width());\n            min_pyramid_layer_height = std::min(min_pyramid_layer_height, scanner.get_min_pyramid_layer_height());\n            if (cell_size != scanner.get_cell_size())\n                all_cell_sizes_the_same = false;\n        }\n\n        std::vector<rect_detection> dets_accum;\n        // Do to the HOG feature extraction to make the fhog pyramid.  Again, note that we\n        // are making a pyramid that will work with any of the detectors.  But only if all\n        // the cell sizes are the same.  If they aren't then we have to calculate the\n        // pyramid for each detector individually.\n        array<array<array2d<float> > > feats;\n        if (all_cell_sizes_the_same)\n        {\n            impl::create_fhog_pyramid<pyramid_type>(img,\n                detectors[0].get_scanner().get_feature_extractor(), feats, cell_size,\n                max_filter_height, max_filter_width, min_pyramid_layer_width,\n                min_pyramid_layer_height, max_pyramid_levels);\n        }\n\n        std::vector<std::pair<double, rectangle> > temp_dets;\n        for (unsigned long i = 0; i < detectors.size(); ++i)\n        {\n            const scanner_type& scanner = detectors[i].get_scanner();\n            if (!all_cell_sizes_the_same)\n            {\n                impl::create_fhog_pyramid<pyramid_type>(img,\n                    scanner.get_feature_extractor(), feats, scanner.get_cell_size(),\n                    max_filter_height, max_filter_width, min_pyramid_layer_width,\n                    min_pyramid_layer_height, max_pyramid_levels);\n            }\n\n            const unsigned long det_box_width  = scanner.get_fhog_window_width()  - 2*scanner.get_padding();\n            const unsigned long det_box_height = scanner.get_fhog_window_height() - 2*scanner.get_padding();\n            // A single detector object might itself have multiple weight vectors in it. So\n            // we need to evaluate all of them.\n            for (unsigned d = 0; d < detectors[i].num_detectors(); ++d)\n            {\n                const double thresh = detectors[i].get_processed_w(d).w(scanner.get_num_dimensions());\n\n                impl::detect_from_fhog_pyramid<pyramid_type>(feats, scanner.get_feature_extractor(),\n                    detectors[i].get_processed_w(d).get_detect_argument(), thresh+adjust_threshold,\n                    det_box_height, det_box_width, cell_size, max_filter_height,\n                    max_filter_width, temp_dets);\n\n                for (unsigned long j = 0; j < temp_dets.size(); ++j)\n                {\n                    rect_detection temp;\n                    temp.detection_confidence = temp_dets[j].first-thresh;\n                    temp.weight_index = i;\n                    temp.rect = temp_dets[j].second;\n                    dets_accum.push_back(temp);\n                }\n            }\n        }\n\n\n        // Do non-max suppression\n        if (detectors.size() > 1)\n            std::sort(dets_accum.rbegin(), dets_accum.rend());\n        for (unsigned long i = 0; i < dets_accum.size(); ++i)\n        {\n            const test_box_overlap tester = detectors[dets_accum[i].weight_index].get_overlap_tester();\n            if (impl::overlaps_any_box(tester, dets, dets_accum[i]))\n                continue;\n\n            dets.push_back(dets_accum[i]);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename image_type\n        >\n    std::vector<rectangle> evaluate_detectors (\n        const std::vector<object_detector<scan_fhog_pyramid<Pyramid_type> > >& detectors,\n        const image_type& img,\n        const double adjust_threshold = 0\n    )\n    {\n        std::vector<rectangle> out_dets;\n        std::vector<rect_detection> dets;\n        evaluate_detectors(detectors, img, dets, adjust_threshold);\n        out_dets.reserve(dets.size());\n        for (unsigned long i = 0; i < dets.size(); ++i)\n            out_dets.push_back(dets[i].rect);\n        return out_dets;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_fHOG_PYRAMID_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/scan_fhog_pyramid_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../image_transforms/fhog_abstract.h\"\n#include \"object_detector_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    matrix<unsigned char> draw_fhog (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        const unsigned long weight_index = 0,\n        const long cell_draw_size = 15\n    );\n    /*!\n        requires\n            - cell_draw_size > 0\n            - weight_index < detector.num_detectors()\n            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()\n              (i.e. the detector must have been populated with a HOG filter)\n        ensures\n            - Converts the HOG filters in the given detector (specifically, the filters in\n              detector.get_w(weight_index)) into an image suitable for display on the\n              screen.  In particular, we draw all the HOG cells into a grayscale image in a\n              way that shows the magnitude and orientation of the gradient energy in each\n              cell.  The resulting image is then returned.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    unsigned long num_separable_filters (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        const unsigned long weight_index = 0\n    );\n    /*!\n        requires\n            - weight_index < detector.num_detectors()\n            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()\n              (i.e. the detector must have been populated with a HOG filter)\n        ensures\n            - Returns the number of separable filters necessary to represent the HOG\n              filters in the given detector's weight_index'th filter.  This is the filter\n              defined by detector.get_w(weight_index).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename feature_extractor_type\n        >\n    object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> > threshold_filter_singular_values (\n        const object_detector<scan_fhog_pyramid<Pyramid_type,feature_extractor_type> >& detector,\n        double thresh,\n        const unsigned long weight_index = 0\n    );\n    /*!\n        requires\n            - thresh >= 0\n            - weight_index < detector.num_detectors()\n            - detector.get_w(weight_index).size() >= detector.get_scanner().get_num_dimensions()\n              (i.e. the detector must have been populated with a HOG filter)\n        ensures\n            - Removes all components of the filters in the given detector that have\n              singular values that are smaller than the given threshold.  Therefore, this\n              function allows you to control how many separable filters are in a detector.\n              In particular, as thresh gets larger the quantity\n              num_separable_filters(threshold_filter_singular_values(detector,thresh,weight_index),weight_index)\n              will generally get smaller and therefore give a faster running detector.\n              However, note that at some point a large enough thresh will drop too much\n              information from the filters and their accuracy will suffer.  \n            - returns the updated detector\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class default_fhog_feature_extractor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                The scan_fhog_pyramid object defined below is primarily meant to be used\n                with the feature extraction technique implemented by extract_fhog_features().  \n                This technique can generally be understood as taking an input image and\n                outputting a multi-planed output image of floating point numbers that\n                somehow describe the image contents.  Since there are many ways to define\n                how this feature mapping is performed, the scan_fhog_pyramid allows you to\n                replace the extract_fhog_features() method with a customized method of your\n                choosing.  To do this you implement a class with the same interface as\n                default_fhog_feature_extractor.  \n\n                Therefore, the point of default_fhog_feature_extractor is two fold.  First,\n                it provides the default FHOG feature extraction method used by scan_fhog_pyramid.\n                Second, it serves to document the interface you need to implement to define \n                your own custom HOG style feature extraction. \n        !*/\n\n    public:\n\n        rectangle image_to_feats (\n            const rectangle& rect,\n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const { return image_to_fhog(rect, cell_size, filter_rows_padding, filter_cols_padding); }\n        /*!\n            requires\n                - cell_size > 0\n                - filter_rows_padding > 0\n                - filter_cols_padding > 0\n            ensures\n                - Maps a rectangle from the coordinates in an input image to the corresponding\n                  area in the output feature image.\n        !*/\n\n        rectangle feats_to_image (\n            const rectangle& rect,\n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const { return fhog_to_image(rect, cell_size, filter_rows_padding, filter_cols_padding); }\n        /*!\n            requires\n                - cell_size > 0\n                - filter_rows_padding > 0\n                - filter_cols_padding > 0\n            ensures\n                - Maps a rectangle from the coordinates of the hog feature image back to\n                  the input image.\n                - Mapping from feature space to image space is an invertible\n                  transformation.  That is, for any rectangle R we have:\n                    R == image_to_feats(feats_to_image(R,cell_size,filter_rows_padding,filter_cols_padding),\n                                                         cell_size,filter_rows_padding,filter_cols_padding).\n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator()(\n            const image_type& img, \n            dlib::array<array2d<float> >& hog, \n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) const { extract_fhog_features(img,hog,cell_size,filter_rows_padding,filter_cols_padding); }\n        /*!\n            requires\n                - image_type == is an implementation of array2d/array2d_kernel_abstract.h\n                - img contains some kind of pixel type. \n                  (i.e. pixel_traits<typename image_type::type> is defined)\n            ensures\n                - Extracts FHOG features by calling extract_fhog_features().  The results are\n                  stored into #hog.  Note that if you are implementing your own feature extractor you can\n                  pretty much do whatever you want in terms of feature extraction so long as the following\n                  conditions are met:\n                    - #hog.size() == get_num_planes()\n                    - Each image plane in #hog has the same dimensions.\n                    - for all valid i, r, and c:\n                        - #hog[i][r][c] == a feature value describing the image content centered at the \n                          following pixel location in img: \n                            feats_to_image(point(c,r),cell_size,filter_rows_padding,filter_cols_padding)\n        !*/\n\n        inline unsigned long get_num_planes (\n        ) const { return 31; }\n        /*!\n            ensures\n                - returns the number of planes in the hog image output by the operator()\n                  method.\n        !*/\n    };\n\n    inline void serialize   (const default_fhog_feature_extractor&, std::ostream&) {}\n    inline void deserialize (default_fhog_feature_extractor&, std::istream&) {}\n    /*!\n        Provides serialization support.  Note that there is no state in the default hog\n        feature extractor so these functions do nothing.  But if you define a custom\n        feature extractor then make sure you remember to serialize any state in your\n        feature extractor.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type = default_fhog_feature_extractor\n        >\n    class scan_fhog_pyramid : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON Pyramid_type\n                - Must be one of the pyramid_down objects defined in\n                  dlib/image_transforms/image_pyramid_abstract.h or an object with a\n                  compatible interface\n\n            REQUIREMENTS ON Feature_extractor_type\n                - Must be a type with an interface compatible with the\n                  default_fhog_feature_extractor.\n\n            INITIAL VALUE\n                - get_padding()   == 1\n                - get_cell_size() == 8\n                - get_detection_window_width()   == 64\n                - get_detection_window_height()  == 64\n                - get_max_pyramid_levels()       == 1000\n                - get_min_pyramid_layer_width()  == 64\n                - get_min_pyramid_layer_height() == 64\n                - get_nuclear_norm_regularization_strength() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for running a fixed sized sliding window classifier\n                over an image pyramid.  In particular,  it slides a linear classifier over\n                a HOG pyramid as discussed in the paper:  \n                    Histograms of Oriented Gradients for Human Detection by Navneet Dalal\n                    and Bill Triggs, CVPR 2005\n                However, we augment the method slightly to use the version of HOG features \n                from: \n                    Object Detection with Discriminatively Trained Part Based Models by\n                    P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan\n                    IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010\n                Since these HOG features have been shown to give superior performance. \n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be\n                protected by a mutex lock except for the case where you are copying the\n                configuration (via copy_configuration()) of a scan_fhog_pyramid object to\n                many other threads.  In this case, it is safe to copy the configuration of\n                a shared object so long as no other operations are performed on it.\n        !*/\n\n    public:\n        typedef matrix<double,0,1> feature_vector_type;\n        typedef Pyramid_type pyramid_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_fhog_pyramid (\n        );  \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        explicit scan_fhog_pyramid (\n            const feature_extractor_type& fe\n        );  \n        /*!\n            ensures\n                - this object is properly initialized\n                - #get_feature_extractor() == fe\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == is an implementation of array2d/array2d_kernel_abstract.h\n                - img contains some kind of pixel type. \n                  (i.e. pixel_traits<typename image_type::type> is defined)\n            ensures\n                - #is_loaded_with_image() == true\n                - This object is ready to run a classifier over img to detect object\n                  locations.  Call detect() to do this.\n        !*/\n\n        const feature_extractor_type& get_feature_extractor(\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the feature extractor used by this object.\n        !*/\n\n        bool is_loaded_with_image (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object has been loaded with an image to process and\n                  false otherwise.\n        !*/\n\n        void copy_configuration (\n            const scan_fhog_pyramid& item\n        );\n        /*!\n            ensures\n                - Copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two scan_fhog_pyramid\n                  objects S1 and S2, the following sequence of instructions should always \n                  result in both of them having the exact same state:\n                    S2.copy_configuration(S1);\n                    S1.load(img);\n                    S2.load(img);\n        !*/\n\n        void set_detection_window_size (\n            unsigned long window_width,\n            unsigned long window_height\n        );\n        /*!\n            requires\n                - window_width > 0\n                - window_height > 0\n            ensures\n                - When detect() is called, this object scans a window that is of the given\n                  width and height (in pixels) over each layer in an image pyramid.  This\n                  means that the rectangle detections which come out of detect() will have\n                  a width to height ratio approximately equal to window_width/window_height\n                  and will be approximately window_width*window_height pixels in area or\n                  larger.  Therefore, the smallest object that can be detected is roughly\n                  window_width by window_height pixels in size.\n                - #get_detection_window_width() == window_width\n                - #get_detection_window_height() == window_height\n                - Since we use a HOG feature representation, the detection procedure works\n                  as follows:\n                    Step 1. Make an image pyramid.\n                    Step 2. Convert each layer of the image pyramid into a multi-planed HOG \"image\".\n                    (the number of bands is given by get_feature_extractor().get_num_planes())\n                    Step 3. Scan a linear classifier over each HOG image in the pyramid. \n                  Moreover, the HOG features quantize the input image into a grid of cells,\n                  each cell being get_cell_size() by get_cell_size() pixels in size.  So\n                  when we scan the object detector over the pyramid we are scanning an\n                  appropriately sized window over these smaller quantized HOG features.  In\n                  particular, the size of the window we scan over the HOG feature pyramid\n                  is #get_fhog_window_width() by #get_fhog_window_height() HOG cells in\n                  size.    \n                - #is_loaded_with_image() == false\n        !*/\n\n        unsigned long get_detection_window_width (\n        ) const;\n        /*!\n            ensures\n                - returns the width, in pixels, of the detection window that is scanned\n                  over the image when detect() is called.    \n        !*/\n\n        inline unsigned long get_detection_window_height (\n        ) const; \n        /*!\n            ensures\n                - returns the height, in pixels, of the detection window that is scanned\n                  over the image when detect() is called.  \n        !*/\n\n        unsigned long get_fhog_window_width (\n        ) const; \n        /*!\n            ensures\n                - Returns the width of the HOG scanning window in terms of HOG cell blocks.\n                  Note that this is a function of get_detection_window_width(), get_cell_size(), \n                  and get_padding() and is therefore not something you set directly. \n                - #get_fhog_window_width() is approximately equal to the number of HOG cells \n                  that fit into get_detection_window_width() pixels plus 2*get_padding()\n                  since we include additional padding around each window to add context.\n        !*/\n\n        unsigned long get_fhog_window_height (\n        ) const;\n        /*!\n            ensures\n                - Returns the height of the HOG scanning window in terms of HOG cell blocks.  \n                  Note that this is a function of get_detection_window_height(), get_cell_size(), \n                  and get_padding() and is therefore not something you set directly. \n                - #get_fhog_window_height() is approximately equal to the number of HOG cells \n                  that fit into get_detection_window_height() pixels plus 2*get_padding()\n                  since we include additional padding around each window to add context.\n        !*/\n\n        void set_padding (\n            unsigned long new_padding\n        );\n        /*!\n            ensures\n                - #get_padding() == new_padding\n                - #is_loaded_with_image() == false\n        !*/\n\n        unsigned long get_padding (\n        ) const;\n        /*!\n            ensures\n                - The HOG windows scanned over the HOG pyramid can include additional HOG\n                  cells outside the detection window.  This can help add context and\n                  improve detection accuracy.  This function returns the number of extra\n                  HOG cells added onto the border of the HOG windows which are scanned by\n                  detect().\n        !*/\n\n        unsigned long get_cell_size (\n        ) const;\n        /*!\n            ensures\n                - Returns the size of the HOG cells.  Each HOG cell is square and contains\n                  get_cell_size()*get_cell_size() pixels.\n        !*/\n\n        void set_cell_size (\n            unsigned long new_cell_size\n        );\n        /*!\n            requires\n                - new_cell_size > 0\n            ensures\n                - #get_cell_size() == new_cell_size\n                - #is_loaded_with_image() == false\n        !*/\n\n        inline long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns get_fhog_window_width()*get_fhog_window_height()*get_feature_extractor().get_num_planes()\n                  (i.e. The number of features is equal to the size of the HOG window times\n                  the number of planes output by the feature extractor. )\n        !*/\n\n        inline unsigned long get_num_detection_templates (\n        ) const { return 1; }\n        /*!\n            ensures\n                - returns 1.  Note that this function is here only for compatibility with \n                  the scan_image_pyramid object.  Notionally, its return value indicates \n                  that a scan_fhog_pyramid object is always ready to detect objects once\n                  an image has been loaded.\n        !*/\n\n        inline unsigned long get_num_movable_components_per_detection_template (\n        ) const { return 0; }\n        /*!\n            ensures\n                - returns 0.  Note that this function is here only for compatibility with\n                  the scan_image_pyramid object.  Its return value means that this object\n                  does not support using movable part models.\n        !*/\n\n        unsigned long get_max_pyramid_levels (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum number of image pyramid levels this object will use.\n                  Note that #get_max_pyramid_levels() == 1 indicates that no image pyramid\n                  will be used at all.  That is, only the original image will be processed\n                  and no lower scale versions will be created.  \n        !*/\n\n        void set_max_pyramid_levels (\n            unsigned long max_levels\n        );\n        /*!\n            requires\n                - max_levels > 0\n            ensures\n                - #get_max_pyramid_levels() == max_levels\n        !*/\n\n        void set_min_pyramid_layer_size (\n            unsigned long width,\n            unsigned long height \n        );\n        /*!\n            requires\n                - width > 0\n                - height > 0\n            ensures\n                - #get_min_pyramid_layer_width() == width\n                - #get_min_pyramid_layer_height() == height\n        !*/\n\n        inline unsigned long get_min_pyramid_layer_width (\n        ) const;\n        /*!\n            ensures\n                - returns the smallest allowable width of an image in the image pyramid.\n                  All pyramids will always include the original input image, however, no\n                  pyramid levels will be created which have a width smaller than the\n                  value returned by this function.\n        !*/\n\n        inline unsigned long get_min_pyramid_layer_height (\n        ) const;\n        /*!\n            ensures\n                - returns the smallest allowable height of an image in the image pyramid.\n                  All pyramids will always include the original input image, however, no\n                  pyramid levels will be created which have a height smaller than the\n                  value returned by this function.\n        !*/\n\n        fhog_filterbank build_fhog_filterbank (\n            const feature_vector_type& weights \n        ) const;\n        /*!\n            requires\n                - weights.size() >= get_num_dimensions()\n            ensures\n                - Creates and then returns a fhog_filterbank object FB such that:\n                    - FB.get_num_dimensions() == get_num_dimensions()\n                    - FB.get_filters() == the values in weights unpacked into get_feature_extractor().get_num_planes() filters.\n                    - FB.num_separable_filters() == the number of separable filters necessary to\n                      represent all the filters in FB.get_filters().\n        !*/\n\n        class fhog_filterbank \n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents a HOG filter bank.  That is, the classifier that is \n                    slid over a HOG pyramid is a set of get_feature_extractor().get_num_planes() \n                    linear filters, each get_fhog_window_width() rows by get_fhog_window_height() \n                    columns in size.  This object contains that set of filters.  \n            !*/\n\n        public:\n            long get_num_dimensions(\n            ) const;\n            /*!\n                ensures\n                    - Returns the total number of values in the filters.  \n            !*/\n\n            const std::vector<matrix<float> >& get_filters(\n            ) const; \n            /*!\n                ensures\n                    - returns the set of HOG filters in this object.\n            !*/\n\n            unsigned long num_separable_filters(\n            ) const;\n            /*!\n                ensures\n                    - returns the number of separable filters necessary to represent all\n                      the filters in get_filters().\n            !*/\n        };\n\n        void detect (\n            const fhog_filterbank& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n        /*!\n            requires\n                - w.get_num_dimensions() == get_num_dimensions()\n                - is_loaded_with_image() == true\n            ensures\n                - Scans the HOG filter defined by w over the HOG pyramid that was populated\n                  by the last call to load() and stores all object detections into #dets.  \n                - for all valid i:\n                    - #dets[i].second == The object box which produced this detection.  This rectangle gives\n                      the location of the detection.  Note that the rectangle will have been converted back into\n                      the original image input space.  That is, if this detection was made at a low level in the\n                      image pyramid then the object box will have been automatically mapped up the pyramid layers\n                      to the original image space.  Or in other words, if you plot #dets[i].second on top of the \n                      image given to load() it will show up in the right place.\n                    - #dets[i].first == The score for this detection.  This value is equal to dot(w, feature vector\n                      for this sliding window location).\n                    - #dets[i].first >= thresh\n                - #dets will be sorted in descending order. (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)\n                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only the first\n                  get_num_dimensions() are used.\n                - Note that no form of non-max suppression is performed.  If a window has a score >= thresh\n                  then it is reported in #dets.\n        !*/\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n                - is_loaded_with_image() == true\n            ensures\n                - performs: detect(build_fhog_filterbank(w), dets, thresh)\n        !*/\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n        /*!\n            requires\n                - obj.num_parts() == 0 \n                - is_loaded_with_image() == true\n                - psi.size() >= get_num_dimensions()\n                  (i.e. psi must have preallocated its memory before this function is called)\n            ensures\n                - This function allows you to determine the feature vector used for an\n                  object detection output from detect().  Note that this vector is\n                  added to psi.  Note also that you can use get_full_object_detection() to\n                  convert a rectangle from detect() into the needed full_object_detection.\n                - The dimensionality of the vector added to psi is get_num_dimensions().  This\n                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.\n                - Since scan_fhog_pyramid only searches a limited set of object locations,\n                  not all possible rectangles can be output by detect().  So in the case\n                  where obj.get_rect() could not arise from a call to detect(), this\n                  function will map obj.get_rect() to the nearest possible rectangle and\n                  then add the feature vector for the mapped rectangle into #psi.\n                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()\n                  gets mapped to for feature extraction.\n        !*/\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n        /*!\n            ensures\n                - returns full_object_detection(rect)\n                  (This function is here only for compatibility with the scan_image_pyramid\n                  object)\n        !*/\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n        /*!\n            ensures\n                - Since scan_fhog_pyramid only searches a limited set of object locations,\n                  not all possible rectangles can be represented.  Therefore, this function\n                  allows you to supply a rectangle and obtain the nearest possible\n                  candidate object location rectangle.\n        !*/\n\n        double get_nuclear_norm_regularization_strength (\n        ) const;\n        /*!\n            ensures\n                - If the number of separable filters in a fhog_filterbank is small then the\n                  filter bank can be scanned over an image much faster than a normal set of\n                  filters.  Therefore, this object provides the option to encourage\n                  machine learning methods that learn a HOG filter bank (i.e.\n                  structural_object_detection_trainer) to select filter banks that have\n                  this beneficial property.  In particular, the value returned by\n                  get_nuclear_norm_regularization_strength() is a multiplier on a nuclear\n                  norm regularizer which will encourage the selection of filters that use a\n                  small number of separable components.  Larger values encourage tend to\n                  give a smaller number of separable filters. \n                - if (get_nuclear_norm_regularization_strength() == 0) then\n                    - This feature is disabled\n                - else\n                    - A nuclear norm regularizer will be added when\n                      structural_object_detection_trainer is used to learn a HOG filter\n                      bank.  Note that this can make the training process take\n                      significantly longer (but can result in faster object detectors).\n        !*/\n\n        void set_nuclear_norm_regularization_strength (\n            double strength\n        );\n        /*!\n            requires\n                - strength >= 0\n            ensures\n                - #get_nuclear_norm_regularization_strength() == strength\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const scan_fhog_pyramid<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void deserialize (\n        scan_fhog_pyramid<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_type\n        >\n    void evaluate_detectors (\n        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type>>>& detectors,\n        const image_type& img,\n        std::vector<rect_detection>& dets,\n        const double adjust_threshold = 0\n    );\n    /*!\n        requires\n            - image_type == is an implementation of array2d/array2d_kernel_abstract.h\n            - img contains some kind of pixel type. \n              (i.e. pixel_traits<typename image_type::type> is defined)\n        ensures\n            - This function runs each of the provided object_detector objects over img and\n              stores the resulting detections into #dets.  Importantly, this function is\n              faster than running each detector individually because it computes the HOG\n              features only once and then reuses them for each detector.  However, it is\n              important to note that this speedup is only possible if all the detectors use\n              the same cell_size parameter that determines how HOG features are computed.\n              If different cell_size values are used then this function will not be any\n              faster than running the detectors individually.\n            - This function applies non-max suppression individually to the output of each\n              detector.  Therefore, the output is the same as if you ran each detector\n              individually and then concatenated the results. \n            - To be precise, this function performs object detection on the given image and\n              stores the detected objects into #dets.  In particular, we will have that:\n                - #dets is sorted such that the highest confidence detections come first.\n                  E.g. element 0 is the best detection, element 1 the next best, and so on.\n                - #dets.size() == the number of detected objects.\n                - #dets[i].detection_confidence == The strength of the i-th detection.\n                  Larger values indicate that the detector is more confident that #dets[i]\n                  is a correct detection rather than being a false alarm.  Moreover, the\n                  detection_confidence is equal to the detection value output by the\n                  scanner minus the threshold value stored at the end of the weight vector.\n                - #dets[i].rect == the bounding box for the i-th detection.\n                - The detection #dets[i].rect was produced by detectors[#dets[i].weight_index].\n            - The detection threshold is adjusted by having adjust_threshold added to it.\n              Therefore, an adjust_threshold value > 0 makes detecting objects harder while\n              a negative value makes it easier.  Moreover, the following will be true for\n              all valid i:\n                - #dets[i].detection_confidence >= adjust_threshold\n              This means that, for example, you can obtain the maximum possible number of\n              detections by setting adjust_threshold equal to negative infinity.\n            - This function is threadsafe in the sense that multiple threads can call\n              evaluate_detectors() with the same instances of detectors and img without\n              requiring a mutex lock.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_type\n        >\n    std::vector<rectangle> evaluate_detectors (\n        const std::vector<object_detector<scan_fhog_pyramid<pyramid_type>>>& detectors,\n        const image_type& img,\n        const double adjust_threshold = 0\n    );\n    /*!\n        requires\n            - image_type == is an implementation of array2d/array2d_kernel_abstract.h\n            - img contains some kind of pixel type. \n              (i.e. pixel_traits<typename image_type::type> is defined)\n        ensures\n            - This function just calls the above evaluate_detectors() routine and copies\n              the output dets into a vector<rectangle> object and returns it.  Therefore,\n              this function is provided for convenience.\n            - This function is threadsafe in the sense that multiple threads can call\n              evaluate_detectors() with the same instances of detectors and img without\n              requiring a mutex lock.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_fHOG_PYRAMID_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_iMAGE_Hh_\n#define DLIB_SCAN_iMAGE_Hh_\n\n#include <vector>\n#include <utility>\n#include \"scan_image_abstract.h\"\n#include \"../matrix.h\"\n#include \"../algs.h\"\n#include \"../rand.h\"\n#include \"../array2d.h\"\n#include \"../image_transforms/spatial_filtering.h\"\n#include \"../image_transforms/thresholding.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n        inline rectangle bounding_box_of_rects (\n            const std::vector<std::pair<unsigned int, rectangle> >& rects,\n            const point& position\n        )\n        /*!\n            ensures\n                - returns the smallest rectangle that contains all the \n                  rectangles in rects.  That is, returns the rectangle that\n                  contains translate_rect(rects[i].second,position) for all valid i.\n        !*/\n        {\n            rectangle rect;\n\n            for (unsigned long i = 0; i < rects.size(); ++i)\n            {\n                rect += translate_rect(rects[i].second,position);\n            }\n\n            return rect;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    bool all_images_same_size (\n        const image_array_type& images\n    )\n    {\n        if (images.size() == 0)\n            return true;\n\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            if (num_rows(images[0]) != num_rows(images[i]) ||\n                num_columns(images[0]) != num_columns(images[i]))\n                return false;\n        }\n\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    double sum_of_rects_in_images (\n        const image_array_type& images,\n        const std::vector<std::pair<unsigned int, rectangle> >& rects,\n        const point& position\n    )\n    {\n        DLIB_ASSERT(all_images_same_size(images),\n            \"\\t double sum_of_rects_in_images()\"\n            << \"\\n\\t Invalid arguments given to this function.\"\n            << \"\\n\\t all_images_same_size(images): \" << all_images_same_size(images)\n        );\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            DLIB_ASSERT(rects[i].first < images.size(),\n                \"\\t double sum_of_rects_in_images()\"\n                << \"\\n\\t rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t rects[\"<<i<<\"].first: \" << rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n        }\n#endif\n\n\n        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;\n        typedef typename promote<pixel_type>::type ptype;\n\n        ptype temp = 0;\n\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            const typename image_array_type::type& img = images[rects[i].first];\n            const rectangle rect = get_rect(img).intersect(translate_rect(rects[i].second,position));\n            temp += sum(matrix_cast<ptype>(subm(mat(img), rect)));\n        }\n\n        return static_cast<double>(temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    double sum_of_rects_in_images_movable_parts (\n        const image_array_type& images,\n        const rectangle& window,\n        const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,\n        const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,\n        const point& position\n    )\n    {\n        DLIB_ASSERT(all_images_same_size(images) && center(window) == point(0,0),\n            \"\\t double sum_of_rects_in_images_movable_parts()\"\n            << \"\\n\\t Invalid arguments given to this function.\"\n            << \"\\n\\t all_images_same_size(images): \" << all_images_same_size(images)\n            << \"\\n\\t center(window): \" << center(window)\n        );\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < fixed_rects.size(); ++i)\n        {\n            DLIB_ASSERT(fixed_rects[i].first < images.size(),\n                \"\\t double sum_of_rects_in_images_movable_parts()\"\n                << \"\\n\\t fixed_rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t fixed_rects[\"<<i<<\"].first: \" << fixed_rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n        }\n        for (unsigned long i = 0; i < movable_rects.size(); ++i)\n        {\n            DLIB_ASSERT(movable_rects[i].first < images.size(),\n                \"\\t double sum_of_rects_in_images_movable_parts()\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].first: \" << movable_rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n            DLIB_ASSERT(center(movable_rects[i].second) == point(0,0),\n                \"\\t double sum_of_rects_in_images_movable_parts()\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].second: \" << movable_rects[i].second \n            );\n        }\n#endif\n        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;\n        typedef typename promote<pixel_type>::type ptype;\n\n        ptype temp = 0;\n\n        // compute TOTAL_FIXED part\n        for (unsigned long i = 0; i < fixed_rects.size(); ++i)\n        {\n            const typename image_array_type::type& img = images[fixed_rects[i].first];\n            const rectangle rect = get_rect(img).intersect(translate_rect(fixed_rects[i].second,position));\n            temp += sum(matrix_cast<ptype>(subm(mat(img), rect)));\n        }\n\n        if (images.size() > 0)\n        {\n            // compute TOTAL_MOVABLE part\n            array2d<ptype> tempimg(images[0].nr(), images[0].nc());\n            for (unsigned long i = 0; i < movable_rects.size(); ++i)\n            {\n                const typename image_array_type::type& img = images[movable_rects[i].first];\n\n                sum_filter_assign(img, tempimg, movable_rects[i].second);\n\n                const rectangle rect = get_rect(tempimg).intersect(translate_rect(window,position));\n                if (rect.is_empty() == false)\n                    temp += std::max(0,max(matrix_cast<ptype>(subm(mat(tempimg), rect))));\n            }\n        }\n\n        return static_cast<double>(temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void find_points_above_thresh (\n        std::vector<std::pair<double, point> >& dets,\n        const image_type& img_,\n        const double thresh,\n        const unsigned long max_dets\n    )\n    {\n        const_image_view<image_type> img(img_);\n        typedef typename image_traits<image_type>::pixel_type ptype;\n\n        dets.clear();\n        if (max_dets == 0)\n            return;\n\n        unsigned long count = 0;\n        dlib::rand rnd;\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                const ptype val = img[r][c];\n                if (val >= thresh)\n                {\n                    ++count;\n\n                    if (dets.size() < max_dets)\n                    {\n                        dets.push_back(std::make_pair(val, point(c,r)));\n                    }\n                    else \n                    {\n                        // The idea here is to cause us to randomly sample possible detection\n                        // locations throughout the image rather than just stopping the detection\n                        // procedure once we hit the max_dets limit. So this method will result\n                        // in a random subsample of all the detections >= thresh being in dets\n                        // at the end of scan_image().\n                        const unsigned long random_index = rnd.get_random_32bit_number()%count;\n                        if (random_index < dets.size())\n                        {\n                            dets[random_index] = std::make_pair(val, point(c,r));\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img_,\n        const double non_max_suppression_radius,\n        const typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& thresh\n    )\n    {\n        DLIB_CASSERT(non_max_suppression_radius >= 0);\n        const_image_view<image_type> img(img_);\n\n        using basic_pixel_type = typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type;\n\n        std::vector<std::pair<basic_pixel_type,point>> peaks;\n\n        for (long r = 1; r+1 < img.nr(); ++r)\n        {\n            for (long c = 1; c+1 < img.nc(); ++c)\n            {\n                auto val = img[r][c];\n                if (val < thresh)\n                    continue;\n\n                if (\n                    val <= img[r-1][c] ||\n                    val <= img[r+1][c] ||\n                    val <= img[r][c+1] ||\n                    val <= img[r][c-1] ||\n                    val <= img[r-1][c-1] ||\n                    val <= img[r+1][c+1] ||\n                    val <= img[r-1][c+1] ||\n                    val <= img[r+1][c-1]\n                )\n                {\n                    continue;\n                }\n\n                peaks.emplace_back(val,point(c,r));\n            }\n        }\n\n\n        // now do non-max suppression of the peaks according to the supplied radius.\n        using pt = std::pair<basic_pixel_type,point>;\n        // First sort the peaks so the strongest peaks come first.  We will greedily accept\n        // them and then do the normal peak sorting/non-max suppression thing.\n        std::sort(peaks.rbegin(), peaks.rend(), [](const pt& a, const pt&b ){ return a.first < b.first; });\n        std::vector<point> final_peaks;\n        const double radius_sqr = non_max_suppression_radius*non_max_suppression_radius;\n\n        // If there are a lot of peaks then we will make a mask image and use that to do\n        // the non-max suppression since this is fast when peaks.size() is large.  Otherwise we\n        // will do the simpler thing in the else block that doesn't require us to allocate a\n        // temporary mask image.\n        if (peaks.size() > 500 && radius_sqr != 0)\n        {\n            // hit will record which areas of the image have already been accounted for by some\n            // peak.  So it is our mask image.\n            matrix<unsigned char> hit(img.nr(), img.nc());\n            // initially nothing has been hit.\n            hit = 0;\n            const unsigned long win_size = std::round(2*non_max_suppression_radius);\n            const rectangle area = get_rect(img);\n            for (auto& pp : peaks)\n            {\n                auto& p = pp.second;\n                if (!hit(p.y(),p.x()))\n                {\n                    final_peaks.emplace_back(p);\n\n                    // mask out a circle around this new peak\n                    rectangle win = centered_rect(p, win_size, win_size).intersect(area); \n                    for (long r = win.top(); r <= win.bottom(); ++r)\n                    {\n                        for (long c = win.left(); c <= win.right(); ++c)\n                        {\n                            if (length_squared(point(c,r)-p) <= radius_sqr)\n                                hit(r,c) = 1;\n                        }\n                    }\n                }\n            }\n        }\n        else\n        {\n            // if peaks.size() is relatively small then this is a faster way to do the non-max\n            // suppression.\n            for (auto& p : peaks)\n            {\n                bool hits_any_existing_peak = false;\n                // If the user set the radius to 0 then just copy the peaks to the output without\n                // checking anything.\n                if (radius_sqr != 0)\n                {\n                    for (auto& v : final_peaks)\n                    {\n                        if (length_squared(p.second-v) <= radius_sqr)\n                        {\n                            hits_any_existing_peak = true;\n                            break;\n                        }\n                    }\n                }\n                if (!hits_any_existing_peak)\n                {\n                    final_peaks.emplace_back(p.second);\n                }\n            }\n        }\n\n        return final_peaks;\n    }\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img\n    )\n    {\n        return find_peaks(img, 0, partition_pixels(img));\n    }\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img,\n        const double non_max_suppression_radius\n    )\n    {\n        return find_peaks(img, non_max_suppression_radius, partition_pixels(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void scan_image (\n        std::vector<std::pair<double, point> >& dets,\n        const image_array_type& images,\n        const std::vector<std::pair<unsigned int, rectangle> >& rects,\n        const double thresh,\n        const unsigned long max_dets\n    )\n    {\n        DLIB_ASSERT(images.size() > 0 && rects.size() > 0 && all_images_same_size(images),\n            \"\\t void scan_image()\"\n            << \"\\n\\t Invalid arguments given to this function.\"\n            << \"\\n\\t images.size(): \" << images.size() \n            << \"\\n\\t rects.size():  \" << rects.size() \n            << \"\\n\\t all_images_same_size(images): \" << all_images_same_size(images)\n        );\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            DLIB_ASSERT(rects[i].first < images.size(),\n                \"\\t void scan_image()\"\n                << \"\\n\\t rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t rects[\"<<i<<\"].first: \" << rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n        }\n#endif\n\n\n\n\n        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;\n        typedef typename promote<pixel_type>::type ptype;\n\n        array2d<ptype> accum(images[0].nr(), images[0].nc());\n        assign_all_pixels(accum, 0);\n\n        for (unsigned long i = 0; i < rects.size(); ++i)\n            sum_filter(images[rects[i].first], accum, rects[i].second);\n\n        find_points_above_thresh(dets, accum, thresh, max_dets);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void scan_image_movable_parts (\n        std::vector<std::pair<double, point> >& dets,\n        const image_array_type& images,\n        const rectangle& window,\n        const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,\n        const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,\n        const double thresh,\n        const unsigned long max_dets\n    )\n    {\n        DLIB_ASSERT(images.size() > 0 && all_images_same_size(images) && \n                    center(window) == point(0,0) && window.area() > 0,\n            \"\\t void scan_image_movable_parts()\"\n            << \"\\n\\t Invalid arguments given to this function.\"\n            << \"\\n\\t all_images_same_size(images): \" << all_images_same_size(images)\n            << \"\\n\\t center(window): \" << center(window)\n            << \"\\n\\t window.area():  \" << window.area() \n            << \"\\n\\t images.size():  \" << images.size() \n        );\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < fixed_rects.size(); ++i)\n        {\n            DLIB_ASSERT(fixed_rects[i].first < images.size(),\n                \"\\t void scan_image_movable_parts()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t fixed_rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t fixed_rects[\"<<i<<\"].first: \" << fixed_rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n        }\n        for (unsigned long i = 0; i < movable_rects.size(); ++i)\n        {\n            DLIB_ASSERT(movable_rects[i].first < images.size(),\n                \"\\t void scan_image_movable_parts()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].first must refer to a valid image.\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].first: \" << movable_rects[i].first \n                << \"\\n\\t images.size(): \" << images.size() \n            );\n            DLIB_ASSERT(center(movable_rects[i].second) == point(0,0) &&\n                        movable_rects[i].second.area() > 0,\n                \"\\t void scan_image_movable_parts()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t movable_rects[\"<<i<<\"].second: \" << movable_rects[i].second \n                << \"\\n\\t movable_rects[\"<<i<<\"].second.area(): \" << movable_rects[i].second.area()\n            );\n        }\n#endif\n\n        if (movable_rects.size() == 0 && fixed_rects.size() == 0)\n            return;\n\n        typedef typename image_traits<typename image_array_type::type>::pixel_type pixel_type;\n        typedef typename promote<pixel_type>::type ptype;\n\n        array2d<ptype> accum(images[0].nr(), images[0].nc());\n        assign_all_pixels(accum, 0);\n\n        for (unsigned long i = 0; i < fixed_rects.size(); ++i)\n            sum_filter(images[fixed_rects[i].first], accum, fixed_rects[i].second);\n\n        array2d<ptype> temp(accum.nr(), accum.nc());\n        for (unsigned long i = 0; i < movable_rects.size(); ++i)\n        {\n            const rectangle rect = movable_rects[i].second;\n            sum_filter_assign(images[movable_rects[i].first], temp, rect);\n            max_filter(temp, accum, window.width(), window.height(), 0);  \n        }\n\n        find_points_above_thresh(dets, accum, thresh, max_dets);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_iMAGE_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_iMAGE_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_iMAGE_ABSTRACT_Hh_\n\n#include <vector>\n#include <utility>\n#include \"../algs.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    bool all_images_same_size (\n        const image_array_type& images\n    );\n    /*!\n        requires\n            - image_array_type       == an implementation of array/array_kernel_abstract.h\n            - image_array_type::type == an image object that implements the interface\n              defined in dlib/image_processing/generic_image.h \n        ensures\n            - if (all elements of images have the same dimensions (i.e. \n              for all i and j: get_rect(images[i]) == get_rect(images[j]))) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    double sum_of_rects_in_images (\n        const image_array_type& images,\n        const std::vector<std::pair<unsigned int, rectangle> >& rects,\n        const point& position\n    );\n    /*!\n        requires\n            - image_array_type             == an implementation of array/array_kernel_abstract.h\n            - image_array_type::type       == an image object that implements the interface\n              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must\n              contain a scalar pixel type (e.g. int rather than rgb_pixel)\n            - all_images_same_size(images) == true\n            - for all valid i: rects[i].first < images.size()\n              (i.e. all the rectangles must reference valid elements of images)\n        ensures\n            - returns the sum of the pixels inside the given rectangles.  To be precise, \n              let RECT_SUM[i] = sum of pixels inside the rectangle translate_rect(rects[i].second, position) \n              from the image images[rects[i].first].  Then this function returns the \n              sum of RECT_SUM[i] for all the valid values of i.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    double sum_of_rects_in_images_movable_parts (\n        const image_array_type& images,\n        const rectangle& window,\n        const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,\n        const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,\n        const point& position\n    );\n    /*!\n        requires\n            - image_array_type             == an implementation of array/array_kernel_abstract.h\n            - image_array_type::type       == an image object that implements the interface\n              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must\n              contain a scalar pixel type (e.g. int rather than rgb_pixel)\n            - all_images_same_size(images) == true\n            - center(window) == point(0,0)\n            - for all valid i: \n                - fixed_rects[i].first < images.size()\n                  (i.e. all the rectangles must reference valid elements of images)\n            - for all valid i: \n                - movable_rects[i].first < images.size()\n                  (i.e. all the rectangles must reference valid elements of images)\n                - center(movable_rects[i].second) == point(0,0) \n        ensures\n            - returns the sum of the pixels inside fixed_rects as well as the sum of the pixels\n              inside movable_rects when these latter rectangles are placed at their highest\n              scoring locations inside the given window.  To be precise: \n                - let RECT_SUM(r,x) = sum of pixels inside the rectangle translate_rect(r.second, x) \n                  from the image images[r.first].\n                - let WIN_MAX(i) = The maximum value of RECT_SUM(movable_rects[i],X) when maximizing\n                  over all the X such that translate_rect(window,position).contains(X) == true.\n\n                - let TOTAL_FIXED   == sum over all elements R in fixed_rects of: RECT_SUM(R,position)\n                - let TOTAL_MOVABLE == sum over all valid i of: max(WIN_MAX(i), 0)\n\n              Then this function returns TOTAL_FIXED + TOTAL_MOVABLE.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void find_points_above_thresh (\n        std::vector<std::pair<double, point> >& dets,\n        const image_type& img,\n        const double thresh,\n        const unsigned long max_dets\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h.  Moreover, these it must contain a\n              scalar pixel type (e.g. int rather than rgb_pixel)\n        ensures\n            - #dets == a list of points from img which had pixel values >= thresh.  \n            - Specifically, we have:\n                - #dets.size() <= max_dets\n                  (note that dets is cleared before new detections are added by find_points_above_thresh())\n                - for all valid i:\n                    - #dets[i].first == img[#dets[i].second.y()][#dets[i].second.x()] \n                      (i.e. the first field contains the value of the pixel at this detection location)\n                    - #dets[i].first >= thresh\n            - if (there are more than max_dets locations that pass the above threshold test) then\n                - #dets == a random subsample of all the locations which passed the threshold\n                  test.  \n            - else\n                - #dets == all the points which passed the threshold test.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img,\n        const double non_max_suppression_radius,\n        const typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& thresh\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h.  Moreover, these it must contain a\n              scalar pixel type (e.g. int rather than rgb_pixel)\n            - non_max_suppression_radius >= 0\n        ensures\n            - Scans the given image and finds all pixels with values >= thresh that are\n              also local maximums within their 8-connected neighborhood of the image.  Such\n              pixels are collected, sorted in decreasing order of their pixel values, and\n              then non-maximum suppression is applied to this list of points using the\n              given non_max_suppression_radius.  The final list of peaks is then returned.\n\n              Therefore, the returned list, V, will have these properties:\n                - V.size() == the number of peaks found in the image.\n                - When measured in image coordinates, no elements of V are within\n                  non_max_suppression_radius distance of each other.  That is, for all valid i!=j\n                  it is true that length(V[i]-V[j]) > non_max_suppression_radius.\n                - For each element of V, that element has the maximum pixel value of all\n                  pixels in the ball centered on that pixel with radius\n                  non_max_suppression_radius.\n    !*/\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img\n    );\n    /*!\n        ensures\n            - performs: return find_peaks(img, 0, partition_pixels(img))\n    !*/\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_peaks (\n        const image_type& img,\n        const double non_max_suppression_radius\n    );\n    /*!\n        ensures\n            - performs: return find_peaks(img, non_max_suppression_radius, partition_pixels(img))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void scan_image (\n        std::vector<std::pair<double, point> >& dets,\n        const image_array_type& images,\n        const std::vector<std::pair<unsigned int, rectangle> >& rects,\n        const double thresh,\n        const unsigned long max_dets\n    );\n    /*!\n        requires\n            - image_array_type             == an implementation of array/array_kernel_abstract.h\n            - image_array_type::type       == an image object that implements the interface\n              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must\n              contain a scalar pixel type (e.g. int rather than rgb_pixel)\n            - images.size() > 0\n            - rects.size() > 0 \n            - all_images_same_size(images) == true\n            - for all valid i: rects[i].first < images.size()\n              (i.e. all the rectangles must reference valid elements of images)\n        ensures\n            - slides the set of rectangles over the image space and reports the locations\n              which give a sum bigger than thresh. \n            - Specifically, we have:\n                - #dets.size() <= max_dets\n                  (note that dets is cleared before new detections are added by scan_image())\n                - for all valid i:\n                    - #dets[i].first == sum_of_rects_in_images(images,rects,#dets[i].second) >= thresh\n            - if (there are more than max_dets locations that pass the threshold test) then\n                - #dets == a random subsample of all the locations which passed the threshold\n                  test.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void scan_image_movable_parts (\n        std::vector<std::pair<double, point> >& dets,\n        const image_array_type& images,\n        const rectangle& window,\n        const std::vector<std::pair<unsigned int, rectangle> >& fixed_rects,\n        const std::vector<std::pair<unsigned int, rectangle> >& movable_rects,\n        const double thresh,\n        const unsigned long max_dets\n    );\n    /*!\n        requires\n            - image_array_type             == an implementation of array/array_kernel_abstract.h\n            - image_array_type::type       == an image object that implements the interface\n              defined in dlib/image_processing/generic_image.h.  Moreover, these objects must\n              contain a scalar pixel type (e.g. int rather than rgb_pixel)\n            - images.size() > 0\n            - all_images_same_size(images) == true\n            - center(window) == point(0,0)\n            - window.area() > 0\n            - for all valid i: \n                - fixed_rects[i].first < images.size()\n                  (i.e. all the rectangles must reference valid elements of images)\n            - for all valid i: \n                - movable_rects[i].first < images.size()\n                  (i.e. all the rectangles must reference valid elements of images)\n                - center(movable_rects[i].second) == point(0,0) \n                - movable_rects[i].second.area() > 0\n        ensures\n            - Scans the given window over the images and reports the locations with a score bigger\n              than thresh.\n            - Specifically, we have:\n                - #dets.size() <= max_dets\n                  (note that dets is cleared before new detections are added by scan_image_movable_parts())\n                - for all valid i:\n                    - #dets[i].first == sum_of_rects_in_images_movable_parts(images,\n                                                                             window,\n                                                                             fixed_rects,\n                                                                             movable_rects,\n                                                                             #dets[i].second) >= thresh\n            - if (there are more than max_dets locations that pass the above threshold test) then\n                - #dets == a random subsample of all the locations which passed the threshold\n                  test.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_iMAGE_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_boxes.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_IMAGE_bOXES_Hh_\n#define DLIB_SCAN_IMAGE_bOXES_Hh_\n\n#include \"scan_image_boxes_abstract.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../array2d.h\"\n#include <vector>\n#include \"../image_processing/full_object_detection.h\"\n#include \"../image_transforms.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class default_box_generator\n    {\n    public:\n        template <typename image_type>\n        void operator() (\n            const image_type& img,\n            std::vector<rectangle>& rects\n        ) const\n        {\n            rects.clear();\n            find_candidate_object_locations(img, rects);\n        }\n    };\n\n    inline void serialize(const default_box_generator&, std::ostream& ) {}\n    inline void deserialize(default_box_generator&, std::istream& ) {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator = default_box_generator\n        >\n    class scan_image_boxes : noncopyable\n    {\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n\n        typedef Feature_extractor_type feature_extractor_type;\n        typedef Box_generator box_generator;\n\n        scan_image_boxes (\n        );  \n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n\n        inline bool is_loaded_with_image (\n        ) const;\n\n        inline void copy_configuration(\n            const feature_extractor_type& fe\n        );\n\n        inline void copy_configuration(\n            const box_generator& bg\n        );\n\n        const box_generator& get_box_generator (\n        ) const { return detect_boxes; } \n\n        const Feature_extractor_type& get_feature_extractor (\n        ) const { return feats; }\n\n        inline void copy_configuration (\n            const scan_image_boxes& item\n        );\n\n        inline long get_num_dimensions (\n        ) const;\n\n        unsigned long get_num_spatial_pyramid_levels (\n        ) const;\n\n        void set_num_spatial_pyramid_levels (\n            unsigned long levels\n        );\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - is_loaded_with_image() == true\n        !*/\n\n        inline unsigned long get_num_detection_templates (\n        ) const { return 1; }\n\n        inline unsigned long get_num_movable_components_per_detection_template (\n        ) const { return 0; }\n\n        template <typename T, typename U>\n        friend void serialize (\n            const scan_image_boxes<T,U>& item,\n            std::ostream& out\n        );\n\n        template <typename T, typename U>\n        friend void deserialize (\n            scan_image_boxes<T,U>& item,\n            std::istream& in \n        );\n\n    private:\n        static bool compare_pair_rect (\n            const std::pair<double, rectangle>& a,\n            const std::pair<double, rectangle>& b\n        )\n        {\n            return a.first < b.first;\n        }\n\n        void test_coordinate_transforms()\n        {\n            for (long x = -10; x <= 10; x += 10)\n            {\n                for (long y = -10; y <= 10; y += 10)\n                {\n                    const rectangle rect = centered_rect(x,y,5,6);\n                    rectangle a;\n\n                    a = feats.image_to_feat_space(rect);\n                    if (a.width()  > 10000000 || a.height() > 10000000 )\n                    {\n                        DLIB_CASSERT(false, \"The image_to_feat_space() routine is outputting rectangles of an implausibly \"\n                                     << \"\\nlarge size.  This means there is probably a bug in your feature extractor.\");\n                    }\n                    a = feats.feat_to_image_space(rect);\n                    if (a.width()  > 10000000 || a.height() > 10000000 )\n                    {\n                        DLIB_CASSERT(false, \"The feat_to_image_space() routine is outputting rectangles of an implausibly \"\n                                     << \"\\nlarge size.  This means there is probably a bug in your feature extractor.\");\n                    }\n                }\n            }\n            \n        }\n\n        static void add_grid_rects (\n            std::vector<rectangle>& rects,\n            const rectangle& object_box,\n            unsigned int cells_x,\n            unsigned int cells_y\n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(cells_x > 0 && cells_y > 0,\n                \"\\t void add_grid_rects()\"\n                << \"\\n\\t The number of cells along a dimension can't be zero. \"\n                << \"\\n\\t cells_x: \" << cells_x\n                << \"\\n\\t cells_y: \" << cells_y\n            );\n\n            const matrix_range_exp<double>& x = linspace(object_box.left(), object_box.right(), cells_x+1);\n            const matrix_range_exp<double>& y = linspace(object_box.top(), object_box.bottom(), cells_y+1);\n\n            for (long j = 0; j+1 < y.size(); ++j)\n            {\n                for (long i = 0; i+1 < x.size(); ++i)\n                {\n                    const dlib::vector<double,2> tl(x(i),y(j));\n                    const dlib::vector<double,2> br(x(i+1),y(j+1));\n                    rects.push_back(rectangle(tl,br));\n                }\n            }\n        }\n\n        void get_feature_extraction_regions (\n            const rectangle& rect,\n            std::vector<rectangle>& regions\n        ) const \n        /*!\n            ensures\n                - #regions.size() is always the same number no matter what the input is.  The\n                  regions also have a consistent ordering.\n                - all the output rectangles are contained within rect.\n        !*/\n        {\n            regions.clear();\n\n            for (unsigned int l = 1; l <= num_spatial_pyramid_levels; ++l)\n            {\n                const int cells = (int)std::pow(2.0, l-1.0);\n                add_grid_rects(regions, rect, cells, cells);\n            }\n        }\n\n        unsigned int get_num_components_per_detection_template(\n        ) const\n        {\n            return (unsigned int)(std::pow(4.0,(double)num_spatial_pyramid_levels)-1)/3;\n        }\n\n        feature_extractor_type feats;\n        std::vector<rectangle> search_rects;\n        bool loaded_with_image;\n        unsigned int num_spatial_pyramid_levels;\n        box_generator detect_boxes;\n\n        const long box_sizedims;\n        const long box_maxsize;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void serialize (\n        const scan_image_boxes<T,U>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.feats, out);\n        serialize(item.search_rects, out);\n        serialize(item.loaded_with_image, out);\n        serialize(item.num_spatial_pyramid_levels, out);\n        serialize(item.detect_boxes, out);\n        serialize(item.get_num_dimensions(), out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void deserialize (\n        scan_image_boxes<T,U>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unsupported version found when deserializing a scan_image_boxes object.\");\n\n        deserialize(item.feats, in);\n        deserialize(item.search_rects, in);\n        deserialize(item.loaded_with_image, in);\n        deserialize(item.num_spatial_pyramid_levels, in);\n        deserialize(item.detect_boxes, in);\n\n        // When developing some feature extractor, it's easy to accidentally change its\n        // number of dimensions and then try to deserialize data from an older version of\n        // your extractor into the current code.  This check is here to catch that kind of\n        // user error.\n        long dims;\n        deserialize(dims, in);\n        if (item.get_num_dimensions() != dims)\n            throw serialization_error(\"Number of dimensions in serialized scan_image_boxes doesn't match the expected number.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                         scan_image_boxes member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    scan_image_boxes<Feature_extractor_type,Box_generator>::\n    scan_image_boxes (\n    ) :\n        loaded_with_image(false),\n        num_spatial_pyramid_levels(3),\n        box_sizedims(20),\n        box_maxsize(1200)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    template <\n        typename image_type\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    load (\n        const image_type& img\n    )\n    {\n        feats.load(img);\n        detect_boxes(img, search_rects);\n        loaded_with_image = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    bool scan_image_boxes<Feature_extractor_type,Box_generator>::\n    is_loaded_with_image (\n    ) const\n    {\n        return loaded_with_image;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    copy_configuration(\n        const feature_extractor_type& fe\n    )\n    {\n        test_coordinate_transforms();\n        feats.copy_configuration(fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    copy_configuration(\n        const box_generator& bg \n    )\n    {\n        detect_boxes = bg;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    copy_configuration (\n        const scan_image_boxes& item\n    )\n    {\n        feats.copy_configuration(item.feats);\n        detect_boxes = item.detect_boxes;\n        num_spatial_pyramid_levels = item.num_spatial_pyramid_levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    unsigned long scan_image_boxes<Feature_extractor_type,Box_generator>::\n    get_num_spatial_pyramid_levels (\n    ) const\n    {\n        return num_spatial_pyramid_levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    set_num_spatial_pyramid_levels (\n        unsigned long levels\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(levels > 0, \n            \"\\t void scan_image_boxes::set_num_spatial_pyramid_levels()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t levels: \" << levels \n            << \"\\n\\t this: \" << this\n            );\n        \n\n        num_spatial_pyramid_levels = levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    long scan_image_boxes<Feature_extractor_type,Box_generator>::\n    get_num_dimensions (\n    ) const\n    {\n        return feats.get_num_dimensions()*get_num_components_per_detection_template() + box_sizedims*2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    detect (\n        const feature_vector_type& w,\n        std::vector<std::pair<double, rectangle> >& dets,\n        const double thresh\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    w.size() >= get_num_dimensions(), \n            \"\\t void scan_image_boxes::detect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t w.size():               \" << w.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t this: \" << this\n            );\n        \n        dets.clear();\n\n        array<integral_image_generic<double> > saliency_images(get_num_components_per_detection_template());\n\n        array2d<double> temp_img(feats.nr(), feats.nc());\n\n        // build saliency images  \n        for (unsigned long i = 0; i < saliency_images.size(); ++i)\n        {\n            const unsigned long offset = 2*box_sizedims + feats.get_num_dimensions()*i;\n\n            // make the basic saliency image for the i-th feature extraction region\n            for (long r = 0; r < feats.nr(); ++r)\n            {\n                for (long c = 0; c < feats.nc(); ++c)\n                {\n                    const typename feature_extractor_type::descriptor_type& descriptor = feats(r,c);\n\n                    double sum = 0;\n                    for (unsigned long k = 0; k < descriptor.size(); ++k)\n                    {\n                        sum += w(descriptor[k].first + offset)*descriptor[k].second;\n                    }\n                    temp_img[r][c] = sum;\n                }\n            }\n\n            // now convert base saliency image into final integral image\n            saliency_images[i].load(temp_img);\n        }\n\n\n        // now search the saliency images\n        std::vector<rectangle> regions;\n        const rectangle bounds = get_rect(feats);\n        for (unsigned long i = 0; i < search_rects.size(); ++i)\n        {\n            const rectangle rect = feats.image_to_feat_space(search_rects[i]).intersect(bounds);\n            if (rect.is_empty())\n                continue;\n            get_feature_extraction_regions(rect, regions);\n            double score = 0;\n            for (unsigned long k = 0; k < regions.size(); ++k)\n            {\n                score += saliency_images[k].get_sum_of_area(regions[k]);\n            }\n            const double width = search_rects[i].width();\n            const double height = search_rects[i].height();\n\n            score += dot(linpiece(width,  linspace(0, box_maxsize, box_sizedims+1)), rowm(w, range(0,box_sizedims-1)));\n            score += dot(linpiece(height, linspace(0, box_maxsize, box_sizedims+1)), rowm(w, range(box_sizedims,2*box_sizedims-1)));\n\n            if (score >= thresh)\n            {\n                dets.push_back(std::make_pair(score, search_rects[i]));\n            }\n        }\n\n        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    const rectangle scan_image_boxes<Feature_extractor_type,Box_generator>::\n    get_best_matching_rect (\n        const rectangle& rect\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image(),\n            \"\\t const rectangle scan_image_boxes::get_best_matching_rect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t this: \" << this\n            );\n\n\n        double best_score = -1;\n        rectangle best_rect;\n        for (unsigned long i = 0; i < search_rects.size(); ++i)\n        {\n            const double score = (rect.intersect(search_rects[i])).area()/(double)(rect+search_rects[i]).area();\n            if (score > best_score)\n            {\n                best_score = score;\n                best_rect = search_rects[i];\n            }\n        }\n        return best_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    full_object_detection scan_image_boxes<Feature_extractor_type,Box_generator>::\n    get_full_object_detection (\n        const rectangle& rect,\n        const feature_vector_type& /*w*/\n    ) const\n    {\n        return full_object_detection(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator\n        >\n    void scan_image_boxes<Feature_extractor_type,Box_generator>::\n    get_feature_vector (\n        const full_object_detection& obj,\n        feature_vector_type& psi\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    psi.size() >= get_num_dimensions() &&\n                    obj.num_parts() == 0,\n            \"\\t void scan_image_boxes::get_feature_vector()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t psi.size():             \" << psi.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t obj.num_parts():                            \" << obj.num_parts()\n            << \"\\n\\t this: \" << this\n            );\n\n\n\n        const rectangle best_rect = get_best_matching_rect(obj.get_rect());\n        const rectangle mapped_rect = feats.image_to_feat_space(best_rect).intersect(get_rect(feats));\n        if (mapped_rect.is_empty())\n            return;\n\n        std::vector<rectangle> regions;\n        get_feature_extraction_regions(mapped_rect, regions);\n\n        // pull features out of all the boxes in regions.\n        for (unsigned long j = 0; j < regions.size(); ++j)\n        {\n            const rectangle rect = regions[j];\n\n            const unsigned long template_region_id = j;\n            const unsigned long offset = box_sizedims*2 + feats.get_num_dimensions()*template_region_id;\n            for (long r = rect.top(); r <= rect.bottom(); ++r)\n            {\n                for (long c = rect.left(); c <= rect.right(); ++c)\n                {\n                    const typename feature_extractor_type::descriptor_type& descriptor = feats(r,c);\n                    for (unsigned long k = 0; k < descriptor.size(); ++k)\n                    {\n                        psi(descriptor[k].first + offset) += descriptor[k].second;\n                    }\n                }\n            }\n        }\n\n        const double width = best_rect.width();\n        const double height = best_rect.height();\n        set_rowm(psi, range(0,box_sizedims-1))              += linpiece(width,  linspace(0, box_maxsize, box_sizedims+1));\n        set_rowm(psi, range(box_sizedims,box_sizedims*2-1)) += linpiece(height, linspace(0, box_maxsize, box_sizedims+1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMAGE_bOXES_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_boxes_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../image_processing.h\"\n#include \"../array2d.h\"\n#include \"full_object_detection_abstract.h\"\n#include \"../image_transforms/segment_image_abstract.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class default_box_generator\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object that takes in an image and outputs a set of\n                candidate object locations.  It is also the default box generator used by\n                the scan_image_boxes object defined below.\n        !*/\n\n    public:\n\n        template <typename image_type>\n        void operator() (\n            const image_type& img,\n            std::vector<rectangle>& rects\n        ) const\n        /*!\n            ensures\n                - #rects == the set of candidate object locations which should be searched\n                  inside img.  That is, these are the rectangles which might contain\n                  objects of interest within the given image.\n        !*/\n        {\n            rects.clear();\n            find_candidate_object_locations(img, rects);\n        }\n    };\n\n    inline void serialize  (const default_box_generator&, std::ostream& ) {}\n    inline void deserialize(      default_box_generator&, std::istream& ) {}\n    /*!\n        ensures\n            - provides serialization support.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator = default_box_generator\n        >\n    class scan_image_boxes : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON Feature_extractor_type\n                - must be an object with an interface compatible with the hashed_feature_image \n                  object defined in dlib/image_keypoint/hashed_feature_image_abstract.h or \n                  with the nearest_neighbor_feature_image object defined in \n                  dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h\n\n            REQUIREMENTS ON Box_generator\n                - must be an object with an interface compatible with the\n                  default_box_generator object defined at the top of this file.\n\n            INITIAL VALUE\n                - get_num_spatial_pyramid_levels() == 3\n                - is_loaded_with_image() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for running a classifier over an image with the goal\n                of localizing each object present.  The localization is in the form of the\n                bounding box around each object of interest.  \n\n                Unlike the scan_image_pyramid object which scans a fixed sized window over\n                an image pyramid, the scan_image_boxes tool allows you to define your own\n                list of \"candidate object locations\" which should be evaluated.  This is\n                simply a list of rectangle objects which might contain objects of interest.\n                The scan_image_boxes object will then evaluate the classifier at each of\n                these locations and return the subset of rectangles which appear to have\n                objects in them.  The candidate object location generation is provided by\n                the Box_generator that is passed in as a template argument.  \n\n                This object can also be understood as a general tool for implementing the\n                spatial pyramid models described in the paper:\n                    Beyond Bags of Features: Spatial Pyramid Matching for Recognizing \n                    Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid, \n                    and Jean Ponce\n\n\n                The classifiers used by this object have three parts: \n                   1. The underlying feature extraction provided by Feature_extractor_type\n                      objects, which associate a vector with each location in an image.\n\n                   2. A rule for extracting a feature vector from a candidate object\n                      location.  In this object we use the spatial pyramid matching method.\n                      This means we cut an object's detection window into a set of \"feature\n                      extraction regions\" and extract a bag-of-words vector from each\n                      before finally concatenating them to form the final feature vector\n                      representing the entire object window.  The set of feature extraction\n                      regions can be configured by the user by calling\n                      set_num_spatial_pyramid_levels().  To be a little more precise, the\n                      feature vector for a candidate object window is defined as follows:\n                        - Let N denote the number of feature extraction zones.\n                        - Let M denote the dimensionality of the vectors output by\n                          Feature_extractor_type objects.\n                        - Let F(i) == the M dimensional vector which is the sum of all\n                          vectors given by our Feature_extractor_type object inside the\n                          i-th feature extraction zone.  So this is notionally a\n                          bag-of-words vector from the i-th zone.\n                        - Then the feature vector for an object window is an M*N\n                          dimensional vector [F(1) F(2) F(3) ... F(N)] (i.e. it is a\n                          concatenation of the N vectors).  This feature vector can be\n                          thought of as a collection of N bags-of-words, each bag coming\n                          from a spatial location determined by one of the feature\n                          extraction zones.\n                          \n                   3. A weight vector and a threshold value.  The dot product between the\n                      weight vector and the feature vector for a candidate object location\n                      gives the score of the location.  If this score is greater than the\n                      threshold value then the candidate object location is output as a\n                      detection.\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be\n                protected by a mutex lock except for the case where you are copying the\n                configuration (via copy_configuration()) of a scan_image_boxes object to\n                many other threads.  In this case, it is safe to copy the configuration of\n                a shared object so long as no other operations are performed on it.\n        !*/\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n\n        typedef Feature_extractor_type feature_extractor_type;\n        typedef Box_generator box_generator;\n\n        scan_image_boxes (\n        );  \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type must be a type with the following properties:\n                    - image_type objects can be loaded into Feature_extractor_type\n                      objects via Feature_extractor_type::load().\n                    - image_type objects can be passed to the first argument of\n                      Box_generator::operator()\n            ensures\n                - #is_loaded_with_image() == true\n                - This object is ready to run a classifier over img to detect object\n                  locations.  Call detect() to do this.\n        !*/\n\n        bool is_loaded_with_image (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object has been loaded with an image to process and\n                  false otherwise.\n        !*/\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the feature_extractor_type object used \n                  internally for local feature extraction.  \n        !*/\n\n        void copy_configuration(\n            const feature_extractor_type& fe\n        );\n        /*!\n            ensures\n                - This function performs the equivalent of\n                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows\n                  you to configure the parameters of the underlying feature extractor used\n                  by a scan_image_boxes object)\n        !*/\n\n        void copy_configuration(\n            const box_generator& bg\n        );\n        /*!\n            ensures\n                - #get_box_generator() == bg\n                  (i.e. this function allows you to configure the parameters of the\n                  underlying box generator used by a scan_image_boxes object)\n        !*/\n\n        const box_generator& get_box_generator (\n        ) const;\n        /*!\n            ensures\n                - returns the box_generator used by this object to generate candidate\n                  object locations.\n        !*/\n\n        void copy_configuration (\n            const scan_image_boxes& item\n        );\n        /*!\n            ensures\n                - Copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two scan_image_boxes \n                  objects S1 and S2, the following sequence of instructions should always \n                  result in both of them having the exact same state:\n                    S2.copy_configuration(S1);\n                    S1.load(img);\n                    S2.load(img);\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the number of dimensions in the feature vector for a candidate\n                  object location.  This value is the dimensionality of the underlying\n                  feature vectors produced by Feature_extractor_type times the number of\n                  feature extraction regions used.  Note that the number of feature\n                  extraction regions used is a function of\n                  get_num_spatial_pyramid_levels().\n        !*/\n\n        unsigned long get_num_spatial_pyramid_levels (\n        ) const;\n        /*!\n            ensures\n                - returns the number of layers in the spatial pyramid.  For example, if\n                  this function returns 1 then it means we use a simple bag-of-words\n                  representation over the whole object window.  If it returns 2 then it\n                  means the feature representation is the concatenation of 5 bag-of-words\n                  vectors, one from the entire object window and 4 others from 4 different\n                  parts of the object window.  If it returns 3 then there are 1+4+16\n                  bag-of-words vectors concatenated together in the feature representation,\n                  and so on.\n        !*/\n\n        void set_num_spatial_pyramid_levels (\n            unsigned long levels\n        );\n        /*!\n            requires\n                - levels > 0\n            ensures\n                - #get_num_spatial_pyramid_levels() == levels\n        !*/\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n                - is_loaded_with_image() == true\n            ensures\n                - Scans over all the candidate object locations as discussed in the WHAT\n                  THIS OBJECT REPRESENTS section and stores all detections into #dets.\n                - for all valid i:\n                    - #dets[i].second == The candidate object location which produced this\n                      detection.  This rectangle gives the location of the detection.  \n                    - #dets[i].first == The score for this detection.  This value is equal\n                      to dot(w, feature vector for this candidate object location).\n                    - #dets[i].first >= thresh\n                - #dets will be sorted in descending order. \n                  (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)\n                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only\n                  the first get_num_dimensions() are used.\n                - Note that no form of non-max suppression is performed.  If a locations\n                  has a score >= thresh then it is reported in #dets.\n        !*/\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n        /*!\n            requires\n                - obj.num_parts() == 0 \n                - is_loaded_with_image() == true\n                - psi.size() >= get_num_dimensions()\n                  (i.e. psi must have preallocated its memory before this function is called)\n            ensures\n                - This function allows you to determine the feature vector used for a\n                  candidate object location output from detect().  Note that this vector is\n                  added to psi.  Note also that you must use get_full_object_detection() to\n                  convert a rectangle from detect() into the needed full_object_detection.\n                - The dimensionality of the vector added to psi is get_num_dimensions().  This\n                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.\n                - Since scan_image_boxes only searches a limited set of object locations,\n                  not all possible rectangles can be output by detect().  So in the case\n                  where obj.get_rect() could not arise from a call to detect(), this\n                  function will map obj.get_rect() to the nearest possible rectangle and\n                  then add the feature vector for the mapped rectangle into #psi.\n                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()\n                  gets mapped to for feature extraction.\n        !*/\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n        /*!\n            ensures\n                - returns full_object_detection(rect)\n                  (This function is here only for compatibility with the scan_image_pyramid\n                  object)\n        !*/\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - is_loaded_with_image() == true\n            ensures\n                - Since scan_image_boxes only searches a limited set of object locations,\n                  not all possible rectangles can be represented.  Therefore, this function\n                  allows you to supply a rectangle and obtain the nearest possible\n                  candidate object location rectangle.\n        !*/\n\n        unsigned long get_num_detection_templates (\n        ) const { return 1; }\n        /*!\n            ensures\n                - returns 1.  Note that this function is here only for compatibility with \n                  the scan_image_pyramid object.  Notionally, its return value indicates \n                  that a scan_image_boxes object is always ready to detect objects once\n                  an image has been loaded.\n        !*/\n\n        unsigned long get_num_movable_components_per_detection_template (\n        ) const { return 0; }\n        /*!\n            ensures\n                - returns 0.  Note that this function is here only for compatibility with\n                  the scan_image_pyramid object.  Its return value means that this object\n                  does not support using movable part models.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator \n        >\n    void serialize (\n        const scan_image_boxes<Feature_extractor_type,Box_generator>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        typename Feature_extractor_type,\n        typename Box_generator \n        >\n    void deserialize (\n        scan_image_boxes<Feature_extractor_type,Box_generator>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMAGE_bOXES_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_custom.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_IMAGE_CuSTOM_Hh_\n#define DLIB_SCAN_IMAGE_CuSTOM_Hh_\n\n#include \"scan_image_custom_abstract.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include <vector>\n#include \"../image_processing/full_object_detection.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    class scan_image_custom : noncopyable\n    {\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_image_custom (\n        );  \n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n\n        inline bool is_loaded_with_image (\n        ) const;\n\n        inline void copy_configuration(\n            const feature_extractor_type& fe\n        );\n\n        const Feature_extractor_type& get_feature_extractor (\n        ) const { return feats; }\n\n        inline void copy_configuration (\n            const scan_image_custom& item\n        );\n\n        inline long get_num_dimensions (\n        ) const;\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n\n        inline unsigned long get_num_detection_templates (\n        ) const { return 1; }\n\n        inline unsigned long get_num_movable_components_per_detection_template (\n        ) const { return 0; }\n\n        template <typename T>\n        friend void serialize (\n            const scan_image_custom<T>& item,\n            std::ostream& out\n        );\n\n        template <typename T>\n        friend void deserialize (\n            scan_image_custom<T>& item,\n            std::istream& in \n        );\n\n    private:\n        static bool compare_pair_rect (\n            const std::pair<double, rectangle>& a,\n            const std::pair<double, rectangle>& b\n        )\n        {\n            return a.first < b.first;\n        }\n\n\n        DLIB_MAKE_HAS_MEMBER_FUNCTION_TEST(\n            has_compute_object_score,\n            double, \n            compute_object_score,\n            ( const matrix<double,0,1>& w, const rectangle& obj) const\n        )\n\n        template <typename fe_type>\n        typename enable_if<has_compute_object_score<fe_type> >::type compute_all_rect_scores (\n            const fe_type& feats,\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const\n        {\n            for (unsigned long i = 0; i < search_rects.size(); ++i)\n            {\n                const double score = feats.compute_object_score(w, search_rects[i]);\n                if (score >= thresh)\n                {\n                    dets.push_back(std::make_pair(score, search_rects[i]));\n                }\n            }\n        }\n\n        template <typename fe_type>\n        typename disable_if<has_compute_object_score<fe_type> >::type compute_all_rect_scores (\n            const fe_type& feats,\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const\n        {\n            matrix<double,0,1> psi(w.size());\n            psi = 0;\n            double prev_dot = 0;\n            for (unsigned long i = 0; i < search_rects.size(); ++i)\n            {\n                // Reset these back to zero every so often to avoid the accumulation of\n                // rounding error.  Note that the only reason we do this loop in this\n                // complex way is to avoid needing to zero the psi vector every iteration.\n                if ((i%500) == 499)\n                {\n                    psi = 0;\n                    prev_dot = 0;\n                }\n\n                feats.get_feature_vector(search_rects[i], psi);\n                const double cur_dot = dot(psi, w);\n                const double score = cur_dot - prev_dot;\n                if (score >= thresh)\n                {\n                    dets.push_back(std::make_pair(score, search_rects[i]));\n                }\n                prev_dot = cur_dot;\n            }\n        }\n\n\n        feature_extractor_type feats;\n        std::vector<rectangle> search_rects;\n        bool loaded_with_image;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const scan_image_custom<T>& item,\n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.feats, out);\n        serialize(item.search_rects, out);\n        serialize(item.loaded_with_image, out);\n        serialize(item.get_num_dimensions(), out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void deserialize (\n        scan_image_custom<T>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unsupported version found when deserializing a scan_image_custom object.\");\n\n        deserialize(item.feats, in);\n        deserialize(item.search_rects, in);\n        deserialize(item.loaded_with_image, in);\n\n        // When developing some feature extractor, it's easy to accidentally change its\n        // number of dimensions and then try to deserialize data from an older version of\n        // your extractor into the current code.  This check is here to catch that kind of\n        // user error.\n        long dims;\n        deserialize(dims, in);\n        if (item.get_num_dimensions() != dims)\n            throw serialization_error(\"Number of dimensions in serialized scan_image_custom doesn't match the expected number.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                         scan_image_custom member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    scan_image_custom<Feature_extractor_type>::\n    scan_image_custom (\n    ) :\n        loaded_with_image(false)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    template <\n        typename image_type\n        >\n    void scan_image_custom<Feature_extractor_type>::\n    load (\n        const image_type& img\n    )\n    {\n        feats.load(img, search_rects);\n        loaded_with_image = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    bool scan_image_custom<Feature_extractor_type>::\n    is_loaded_with_image (\n    ) const\n    {\n        return loaded_with_image;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    void scan_image_custom<Feature_extractor_type>::\n    copy_configuration(\n        const feature_extractor_type& fe\n    )\n    {\n        feats.copy_configuration(fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    void scan_image_custom<Feature_extractor_type>::\n    copy_configuration (\n        const scan_image_custom& item\n    )\n    {\n        feats.copy_configuration(item.feats);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    long scan_image_custom<Feature_extractor_type>::\n    get_num_dimensions (\n    ) const\n    {\n        return feats.get_num_dimensions();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    void scan_image_custom<Feature_extractor_type>::\n    detect (\n        const feature_vector_type& w,\n        std::vector<std::pair<double, rectangle> >& dets,\n        const double thresh\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    w.size() >= get_num_dimensions(), \n            \"\\t void scan_image_custom::detect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t w.size():               \" << w.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t this: \" << this\n            );\n        \n        dets.clear();\n        compute_all_rect_scores(feats, w,dets,thresh);\n        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    const rectangle scan_image_custom<Feature_extractor_type>::\n    get_best_matching_rect (\n        const rectangle& rect\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image(),\n            \"\\t const rectangle scan_image_custom::get_best_matching_rect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t this: \" << this\n            );\n\n\n        double best_score = -1;\n        rectangle best_rect;\n        for (unsigned long i = 0; i < search_rects.size(); ++i)\n        {\n            const double score = (rect.intersect(search_rects[i])).area()/(double)(rect+search_rects[i]).area();\n            if (score > best_score)\n            {\n                best_score = score;\n                best_rect = search_rects[i];\n            }\n        }\n        return best_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    full_object_detection scan_image_custom<Feature_extractor_type>::\n    get_full_object_detection (\n        const rectangle& rect,\n        const feature_vector_type& /*w*/\n    ) const\n    {\n        return full_object_detection(rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    void scan_image_custom<Feature_extractor_type>::\n    get_feature_vector (\n        const full_object_detection& obj,\n        feature_vector_type& psi\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_loaded_with_image() &&\n                    psi.size() >= get_num_dimensions() &&\n                    obj.num_parts() == 0,\n            \"\\t void scan_image_custom::get_feature_vector()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t psi.size():             \" << psi.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t obj.num_parts():                            \" << obj.num_parts()\n            << \"\\n\\t this: \" << this\n            );\n\n\n        feats.get_feature_vector(get_best_matching_rect(obj.get_rect()), psi);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMAGE_CuSTOM_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_custom_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../image_processing/full_object_detection_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class example_feature_extractor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines the interface a feature extractor must implement if it\n                is to be used with the scan_image_custom object defined at the bottom of\n                this file.  \n\n                In this case, the purpose of a feature extractor is to associated a\n                complete feature vector with each rectangle in an image.  In particular,\n                each rectangle is scored by taking the dot product between this feature\n                vector and a weight vector.  If this score is greater than a threshold then\n                the rectangle is output as a detection.\n        !*/\n\n    public:\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& image,\n            std::vector<rectangle>& candidate_objects\n        );\n        /*!\n            ensures\n                - Loads the given image into this feature extractor.  This means that\n                  subsequent calls to get_feature_vector() will return the feature vector\n                  corresponding to locations in the image given to load().\n                - #candidate_objects == a set of bounding boxes in the given image that\n                  might contain objects of interest.  These are the locations that will be\n                  checked for the presents of objects when this feature extractor is used\n                  with the scan_image_custom object.\n\n        !*/\n\n        void copy_configuration (\n            const feature_extractor& item\n        );\n        /*!\n            ensures\n                - Copies all the state information of item into *this, except for state\n                  information populated by load().  More precisely, given two\n                  feature extractor objects S1 and S2, the following sequence of\n                  instructions should always result in both of them having the exact same\n                  state:\n                    S2.copy_configuration(S1);\n                    S1.load(img, temp);\n                    S2.load(img, temp);\n        !*/\n\n        unsigned long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the dimensionality of the feature vectors output by this object.\n        !*/\n\n        void get_feature_vector (\n            const rectangle& obj,\n            matrix<double,0,1>& psi\n        ) const;\n        /*!\n            requires\n                - psi.size() >= get_num_dimensions()\n                  (i.e. psi must have preallocated its memory before this function is called)\n            ensures\n                - This function computes the feature vector associated with the given rectangle\n                  in obj.  This rectangle is interpreted as a bounding box within the last image\n                  given to this->load() and a feature vector describing that bounding box is \n                  output into psi.\n                - The feature vector is added into psi.  That is, it does not overwrite the\n                  previous contents of psi, but instead, it adds the vector to psi.\n                - The dimensionality of the vector added to psi is get_num_dimensions().  This\n                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.\n                - #psi.size() == psi.size()\n                  (i.e. this function does not change the size of the psi vector)\n        !*/\n\n        double compute_object_score (\n            const matrix<double,0,1>& w,\n            const rectangle& obj\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n            ensures\n                - This function returns the dot product between the feature vector for\n                  object box obj and the given w vector.  That is, this function computes\n                  the same number as the following code snippet:\n                     matrix<double,0,1> psi(w.size());\n                     psi = 0;\n                     get_feature_vector(obj, psi);\n                     return dot(psi, w);\n                  The point of the compute_object_score() routine is to compute this dot\n                  product in a much more efficient way than directly calling\n                  get_feature_vector() and dot().  Therefore, compute_object_score() is an\n                  optional function.  If you can't think of a faster way to compute these\n                  scores then do not implement compute_object_score() and the\n                  scan_image_custom object will simply compute these scores for you.\n                  However, it is often the case that there is something clever you can do\n                  to make this computation faster.  If that is the case, then you can\n                  provide an implementation of this function with your feature extractor\n                  and then scan_image_custom will use it instead of using the default\n                  calculation method shown in the above code snippet.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n    \n    void serialize( \n        const feature_extractor& item, \n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize( \n        feature_extractor& item, \n        std::istream& in\n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Feature_extractor_type\n        >\n    class scan_image_custom : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON Feature_extractor_type\n                - must be an object with an interface compatible with the\n                  example_feature_extractor defined at the top of this file.\n\n            INITIAL VALUE\n                - is_loaded_with_image() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for running a classifier over an image with the goal\n                of localizing each object present.  The localization is in the form of the\n                bounding box around each object of interest.  \n\n                Unlike the scan_image_pyramid and scan_image_boxes objects, this image\n                scanner delegates all the work of constructing the object feature vector to\n                its Feature_extractor_type template argument.  That is, scan_image_custom\n                simply asks the supplied feature extractor what boxes in the image we\n                should investigate and then asks the feature extractor for the complete\n                feature vector for each box.  That is, scan_image_custom does not apply any\n                kind of pyramiding or other higher level processing to the features coming\n                out of the feature extractor.  That means that when you use\n                scan_image_custom it is completely up to you to define the feature vector\n                used with each image box.\n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be\n                protected by a mutex lock except for the case where you are copying the\n                configuration (via copy_configuration()) of a scan_image_custom object to\n                many other threads.  In this case, it is safe to copy the configuration of\n                a shared object so long as no other operations are performed on it.\n        !*/\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_image_custom (\n        );  \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type must be a type with the following properties:\n                    - image_type objects can be loaded into Feature_extractor_type\n                      objects via Feature_extractor_type::load().\n            ensures\n                - #is_loaded_with_image() == true\n                - Calls get_feature_extractor().load() on the given image.  That is, we\n                  will have loaded the image into the feature extractor in this\n                  scan_image_custom object.  We will also have stored the candidate\n                  object locations generated by the feature extractor and will scan\n                  over them when this->detect() is called.\n                - This object is ready to run a classifier over img to detect object\n                  locations.  Call detect() to do this.\n        !*/\n\n        bool is_loaded_with_image (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object has been loaded with an image to process and\n                  false otherwise.\n        !*/\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const; \n        /*!\n            ensures\n                - returns a const reference to the feature_extractor_type object used \n                  internally for local feature extraction.  \n        !*/\n\n        void copy_configuration(\n            const feature_extractor_type& fe\n        );\n        /*!\n            ensures\n                - This function performs the equivalent of\n                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows\n                  you to configure the parameters of the underlying feature extractor used\n                  by a scan_image_custom object)\n        !*/\n\n        void copy_configuration (\n            const scan_image_custom& item\n        );\n        /*!\n            ensures\n                - Copies all the state information of item into *this, except for state\n                  information populated by load().  More precisely, given two\n                  scan_image_custom objects S1 and S2, the following sequence of\n                  instructions should always result in both of them having the exact same\n                  state:\n                    S2.copy_configuration(S1);\n                    S1.load(img);\n                    S2.load(img);\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            ensures\n                - returns the number of dimensions in the feature vector for a candidate\n                  object location.  That is, this function returns get_feature_extractor().get_num_dimensions().\n        !*/\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n                - is_loaded_with_image() == true\n            ensures\n                - Scans over all the candidate object locations produced by the feature\n                  extractor during image loading and stores all detections into #dets.\n                - for all valid i:\n                    - #dets[i].second == The candidate object location which produced this\n                      detection.  This rectangle gives the location of the detection.  \n                    - #dets[i].first == The score for this detection.  This value is equal\n                      to dot(w, feature vector for this candidate object location).\n                    - #dets[i].first >= thresh\n                - #dets will be sorted in descending order. \n                  (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)\n                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only\n                  the first get_num_dimensions() are used.\n                - Note that no form of non-max suppression is performed.  If a locations\n                  has a score >= thresh then it is reported in #dets.\n        !*/\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n        /*!\n            requires\n                - obj.num_parts() == 0 \n                - is_loaded_with_image() == true\n                - psi.size() >= get_num_dimensions()\n                  (i.e. psi must have preallocated its memory before this function is called)\n            ensures\n                - This function allows you to determine the feature vector used for a\n                  candidate object location output from detect().  Note that this vector is\n                  added to psi.  Note also that you must use get_full_object_detection() to\n                  convert a rectangle from detect() into the needed full_object_detection.\n                - The dimensionality of the vector added to psi is get_num_dimensions().  This\n                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.\n                - Since scan_image_custom only searches a limited set of object locations,\n                  not all possible rectangles can be output by detect().  So in the case\n                  where obj.get_rect() could not arise from a call to detect(), this\n                  function will map obj.get_rect() to the nearest possible rectangle and\n                  then add the feature vector for the mapped rectangle into #psi.\n                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()\n                  gets mapped to for feature extraction.\n        !*/\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n        /*!\n            ensures\n                - returns full_object_detection(rect)\n                  (This function is here only for compatibility with the scan_image_pyramid\n                  object)\n        !*/\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - is_loaded_with_image() == true\n            ensures\n                - Since scan_image_custom only searches a limited set of object locations,\n                  not all possible rectangles can be represented.  Therefore, this function\n                  allows you to supply a rectangle and obtain the nearest possible\n                  candidate object location rectangle.\n        !*/\n\n        unsigned long get_num_detection_templates (\n        ) const { return 1; }\n        /*!\n            ensures\n                - returns 1.  Note that this function is here only for compatibility with\n                  the scan_image_pyramid object.  Notionally, its return value indicates\n                  that a scan_image_custom object is always ready to detect objects once an\n                  image has been loaded.\n        !*/\n\n        unsigned long get_num_movable_components_per_detection_template (\n        ) const { return 0; }\n        /*!\n            ensures\n                - returns 0.  Note that this function is here only for compatibility with\n                  the scan_image_pyramid object.  Its return value means that this object\n                  does not support using movable part models.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const scan_image_custom<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <typename T>\n    void deserialize (\n        scan_image_custom<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMAGE_CuSTOM_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_pyramid.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_IMaGE_PYRAMID_Hh_\n#define DLIB_SCAN_IMaGE_PYRAMID_Hh_\n\n#include \"scan_image_pyramid_abstract.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"scan_image.h\"\n#include \"../array2d.h\"\n#include <vector>\n#include \"full_object_detection.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    class scan_image_pyramid : noncopyable\n    {\n\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n\n        typedef Pyramid_type pyramid_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_image_pyramid (\n        );  \n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n\n        inline bool is_loaded_with_image (\n        ) const;\n\n        inline void copy_configuration(\n            const feature_extractor_type& fe\n        );\n\n        inline void copy_configuration (\n            const scan_image_pyramid& item\n        );\n\n        const Feature_extractor_type& get_feature_extractor (\n        ) const { return feats_config; }\n\n        void add_detection_template (\n            const rectangle& object_box,\n            const std::vector<rectangle>& stationary_feature_extraction_regions,\n            const std::vector<rectangle>& movable_feature_extraction_regions\n        );\n\n        void add_detection_template (\n            const rectangle& object_box,\n            const std::vector<rectangle>& stationary_feature_extraction_regions\n        );\n\n        inline unsigned long get_num_detection_templates (\n        ) const;\n\n        inline unsigned long get_num_movable_components_per_detection_template (\n        ) const;\n\n        inline unsigned long get_num_stationary_components_per_detection_template (\n        ) const;\n\n        inline unsigned long get_num_components_per_detection_template (\n        ) const;\n\n        inline long get_num_dimensions (\n        ) const;\n\n        unsigned long get_max_pyramid_levels (\n        ) const;\n\n        void set_max_pyramid_levels (\n            unsigned long max_levels\n        );\n\n        inline unsigned long get_max_detections_per_template (\n        ) const;\n\n        void set_min_pyramid_layer_size (\n            unsigned long width,\n            unsigned long height \n        );\n\n        inline unsigned long get_min_pyramid_layer_width (\n        ) const;\n\n        inline unsigned long get_min_pyramid_layer_height (\n        ) const;\n\n        void set_max_detections_per_template (\n            unsigned long max_dets\n        );\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n\n        template <typename T, typename U>\n        friend void serialize (\n            const scan_image_pyramid<T,U>& item,\n            std::ostream& out\n        );\n\n        template <typename T, typename U>\n        friend void deserialize (\n            scan_image_pyramid<T,U>& item,\n            std::istream& in \n        );\n\n    private:\n        static bool compare_pair_rect (\n            const std::pair<double, rectangle>& a,\n            const std::pair<double, rectangle>& b\n        )\n        {\n            return a.first < b.first;\n        }\n\n        struct detection_template\n        {\n            rectangle object_box; // always centered at (0,0)\n            std::vector<rectangle> rects; // template with respect to (0,0)\n            std::vector<rectangle> movable_rects; \n        };\n\n        friend void serialize(const detection_template& item, std::ostream& out)\n        {\n            int version = 1;\n            serialize(version, out);\n            serialize(item.object_box, out);\n            serialize(item.rects, out);\n            serialize(item.movable_rects, out);\n        }\n        friend void deserialize(detection_template& item, std::istream& in)\n        {\n            int version = 0;\n            deserialize(version, in);\n            if (version != 1)\n                throw serialization_error(\"Unexpected version found while deserializing a dlib::scan_image_pyramid::detection_template object.\");\n\n            deserialize(item.object_box, in);\n            deserialize(item.rects, in);\n            deserialize(item.movable_rects, in);\n        }\n\n        void get_mapped_rect_and_metadata (\n            const unsigned long number_pyramid_levels,\n            rectangle rect,\n            rectangle& mapped_rect,\n            detection_template& best_template,\n            rectangle& object_box,\n            unsigned long& best_level,\n            unsigned long& detection_template_idx\n        ) const;\n\n        double get_match_score (\n            rectangle r1,\n            rectangle r2\n        ) const\n        {\n            // make the rectangles overlap as much as possible before computing the match score.\n            r1 = move_rect(r1, r2.tl_corner());\n            return (r1.intersect(r2).area())/(double)(r1 + r2).area();\n        }\n\n        void test_coordinate_transforms()\n        {\n            for (long x = -10; x <= 10; x += 10)\n            {\n                for (long y = -10; y <= 10; y += 10)\n                {\n                    const rectangle rect = centered_rect(x,y,5,6);\n                    rectangle a;\n\n                    a = feats_config.image_to_feat_space(rect);\n                    if (a.width()  > 10000000 || a.height() > 10000000 )\n                    {\n                        DLIB_CASSERT(false, \"The image_to_feat_space() routine is outputting rectangles of an implausibly \"\n                                     << \"\\nlarge size.  This means there is probably a bug in your feature extractor.\");\n                    }\n                    a = feats_config.feat_to_image_space(rect);\n                    if (a.width()  > 10000000 || a.height() > 10000000 )\n                    {\n                        DLIB_CASSERT(false, \"The feat_to_image_space() routine is outputting rectangles of an implausibly \"\n                                     << \"\\nlarge size.  This means there is probably a bug in your feature extractor.\");\n                    }\n                }\n            }\n            \n        }\n\n        feature_extractor_type feats_config; // just here to hold configuration.  use it to populate the feats elements.\n        array<feature_extractor_type> feats;\n        std::vector<detection_template> det_templates;\n        unsigned long max_dets_per_template;\n        unsigned long max_pyramid_levels;\n        unsigned long min_pyramid_layer_width;\n        unsigned long min_pyramid_layer_height;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void serialize (\n        const scan_image_pyramid<T,U>& item,\n        std::ostream& out\n    )\n    {\n        int version = 3;\n        serialize(version, out);\n        serialize(item.feats_config, out);\n        serialize(item.feats, out);\n        serialize(item.det_templates, out);\n        serialize(item.max_dets_per_template, out);\n        serialize(item.max_pyramid_levels, out);\n        serialize(item.min_pyramid_layer_width, out);\n        serialize(item.min_pyramid_layer_height, out);\n        serialize(item.get_num_dimensions(), out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void deserialize (\n        scan_image_pyramid<T,U>& item,\n        std::istream& in \n    )\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 3)\n            throw serialization_error(\"Unsupported version found when deserializing a scan_image_pyramid object.\");\n\n        deserialize(item.feats_config, in);\n        deserialize(item.feats, in);\n        deserialize(item.det_templates, in);\n        deserialize(item.max_dets_per_template, in);\n        deserialize(item.max_pyramid_levels, in);\n        deserialize(item.min_pyramid_layer_width, in);\n        deserialize(item.min_pyramid_layer_height, in);\n\n        // When developing some feature extractor, it's easy to accidentally change its\n        // number of dimensions and then try to deserialize data from an older version of\n        // your extractor into the current code.  This check is here to catch that kind of\n        // user error.\n        long dims;\n        deserialize(dims, in);\n        if (item.get_num_dimensions() != dims)\n            throw serialization_error(\"Number of dimensions in serialized scan_image_pyramid doesn't match the expected number.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                         scan_image_pyramid member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    scan_image_pyramid (\n    ) : \n        max_dets_per_template(10000),\n        max_pyramid_levels(1000),\n        min_pyramid_layer_width(20),\n        min_pyramid_layer_height(20)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    template <\n        typename image_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    load (\n        const image_type& img\n    )\n    {\n        unsigned long levels = 0;\n        rectangle rect = get_rect(img);\n\n        // figure out how many pyramid levels we should be using based on the image size\n        pyramid_type pyr;\n        do\n        {\n            rect = pyr.rect_down(rect);\n            ++levels;\n        } while (rect.width() >= min_pyramid_layer_width && rect.height() >= min_pyramid_layer_height &&\n                 levels < max_pyramid_levels);\n\n        if (feats.max_size() < levels)\n            feats.set_max_size(levels);\n        feats.set_size(levels);\n\n        for (unsigned long i = 0; i < feats.size(); ++i)\n            feats[i].copy_configuration(feats_config);\n\n        // build our feature pyramid\n        feats[0].load(img);\n        if (feats.size() > 1)\n        {\n            image_type temp1, temp2;\n            pyr(img, temp1);\n            feats[1].load(temp1);\n            swap(temp1,temp2);\n\n            for (unsigned long i = 2; i < feats.size(); ++i)\n            {\n                pyr(temp2, temp1);\n                feats[i].load(temp1);\n                swap(temp1,temp2);\n            }\n        }\n\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_max_detections_per_template (\n    ) const\n    {\n        return max_dets_per_template;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    set_max_detections_per_template (\n        unsigned long max_dets\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(max_dets > 0 ,\n            \"\\t void scan_image_pyramid::set_max_detections_per_template()\"\n            << \"\\n\\t The max number of possible detections can't be zero. \"\n            << \"\\n\\t max_dets: \" << max_dets\n            << \"\\n\\t this: \" << this\n            );\n\n        max_dets_per_template = max_dets;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    bool scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    is_loaded_with_image (\n    ) const\n    {\n        return feats.size() != 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    copy_configuration(\n        const feature_extractor_type& fe\n    )\n    {\n        test_coordinate_transforms();\n        feats_config.copy_configuration(fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    copy_configuration (\n        const scan_image_pyramid& item\n    )\n    {\n        feats_config.copy_configuration(item.feats_config);\n        det_templates = item.det_templates;\n        max_dets_per_template = item.max_dets_per_template;\n        max_pyramid_levels = item.max_pyramid_levels;\n        min_pyramid_layer_width = item.min_pyramid_layer_width;\n        min_pyramid_layer_height = item.min_pyramid_layer_height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    add_detection_template (\n        const rectangle& object_box,\n        const std::vector<rectangle>& stationary_feature_extraction_regions,\n        const std::vector<rectangle>& movable_feature_extraction_regions\n    )\n    {\n#ifdef ENABLE_ASSERTS\n        // make sure requires clause is not broken\n        DLIB_ASSERT((get_num_detection_templates() == 0 || \n                        (get_num_stationary_components_per_detection_template() == stationary_feature_extraction_regions.size() &&\n                        get_num_movable_components_per_detection_template() == movable_feature_extraction_regions.size())) &&\n                        center(object_box) == point(0,0),\n            \"\\t void scan_image_pyramid::add_detection_template()\"\n            << \"\\n\\t The number of rects in this new detection template doesn't match \"\n            << \"\\n\\t the number in previous detection templates.\"\n            << \"\\n\\t get_num_stationary_components_per_detection_template(): \" << get_num_stationary_components_per_detection_template()\n            << \"\\n\\t stationary_feature_extraction_regions.size():           \" << stationary_feature_extraction_regions.size()\n            << \"\\n\\t get_num_movable_components_per_detection_template():    \" << get_num_movable_components_per_detection_template()\n            << \"\\n\\t movable_feature_extraction_regions.size():              \" << movable_feature_extraction_regions.size()\n            << \"\\n\\t this: \" << this\n            );\n\n        for (unsigned long i = 0; i < movable_feature_extraction_regions.size(); ++i)\n        {\n            DLIB_ASSERT(center(movable_feature_extraction_regions[i]) == point(0,0),\n                        \"Invalid inputs were given to this function.\"\n                        << \"\\n\\t center(movable_feature_extraction_regions[\"<<i<<\"]): \" << center(movable_feature_extraction_regions[i]) \n                        << \"\\n\\t this: \" << this\n            );\n        }\n#endif\n\n        detection_template temp;\n        temp.object_box = object_box;\n        temp.rects = stationary_feature_extraction_regions;\n        temp.movable_rects = movable_feature_extraction_regions;\n        det_templates.push_back(temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    add_detection_template (\n        const rectangle& object_box,\n        const std::vector<rectangle>& stationary_feature_extraction_regions\n    )\n    {\n        // an empty set of movable feature regions\n        const std::vector<rectangle> movable_feature_extraction_regions;\n        add_detection_template(object_box, stationary_feature_extraction_regions,\n                               movable_feature_extraction_regions);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_num_detection_templates (\n    ) const\n    {\n        return det_templates.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_num_stationary_components_per_detection_template (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 ,\n            \"\\t unsigned long scan_image_pyramid::get_num_stationary_components_per_detection_template()\"\n            << \"\\n\\t You need to give some detection templates before calling this function. \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t this: \" << this\n            );\n\n        return det_templates[0].rects.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_num_movable_components_per_detection_template (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 ,\n            \"\\t unsigned long scan_image_pyramid::get_num_movable_components_per_detection_template()\"\n            << \"\\n\\t You need to give some detection templates before calling this function. \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t this: \" << this\n            );\n\n        return det_templates[0].movable_rects.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_num_components_per_detection_template (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 ,\n            \"\\t unsigned long scan_image_pyramid::get_num_components_per_detection_template()\"\n            << \"\\n\\t You need to give some detection templates before calling this function. \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t this: \" << this\n            );\n\n        return get_num_movable_components_per_detection_template() +\n               get_num_stationary_components_per_detection_template();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_num_dimensions (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 ,\n            \"\\t long scan_image_pyramid::get_num_dimensions()\"\n            << \"\\n\\t You need to give some detection templates before calling this function. \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t this: \" << this\n            );\n\n        return feats_config.get_num_dimensions()*get_num_components_per_detection_template() + get_num_detection_templates();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_max_pyramid_levels (\n    ) const\n    {\n        return max_pyramid_levels;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    set_max_pyramid_levels (\n        unsigned long max_levels\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(max_levels > 0 ,\n            \"\\t void scan_image_pyramid::set_max_pyramid_levels()\"\n            << \"\\n\\t You can't have zero levels. \"\n            << \"\\n\\t max_levels: \" << max_levels \n            << \"\\n\\t this: \" << this\n            );\n\n        max_pyramid_levels = max_levels;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    detect (\n        const feature_vector_type& w,\n        std::vector<std::pair<double, rectangle> >& dets,\n        const double thresh\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 &&\n                    is_loaded_with_image() &&\n                    w.size() >= get_num_dimensions(), \n            \"\\t void scan_image_pyramid::detect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t w.size():               \" << w.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t this: \" << this\n            );\n\n        dets.clear();\n\n        array<array2d<double> > saliency_images;\n        saliency_images.set_max_size(get_num_components_per_detection_template());\n        saliency_images.set_size(get_num_components_per_detection_template());\n        std::vector<std::pair<unsigned int,rectangle> > stationary_region_rects(get_num_stationary_components_per_detection_template()); \n        std::vector<std::pair<unsigned int,rectangle> > movable_region_rects(get_num_movable_components_per_detection_template()); \n        pyramid_type pyr;\n        std::vector<std::pair<double, point> > point_dets;\n\n        // for all pyramid levels\n        for (unsigned long l = 0; l < feats.size(); ++l)\n        {\n            for (unsigned long i = 0; i < saliency_images.size(); ++i)\n            {\n                saliency_images[i].set_size(feats[l].nr(), feats[l].nc());\n                const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*i;\n\n                // build saliency images for pyramid level l \n                for (long r = 0; r < feats[l].nr(); ++r)\n                {\n                    for (long c = 0; c < feats[l].nc(); ++c)\n                    {\n                        const typename feature_extractor_type::descriptor_type& descriptor = feats[l](r,c);\n\n                        double sum = 0;\n                        for (unsigned long k = 0; k < descriptor.size(); ++k)\n                        {\n                            sum += w(descriptor[k].first + offset)*descriptor[k].second;\n                        }\n                        saliency_images[i][r][c] = sum;\n                    }\n                }\n            }\n\n            // now search the saliency images\n            for (unsigned long i = 0; i < det_templates.size(); ++i)\n            {\n                const point offset = -feats[l].image_to_feat_space(point(0,0));\n                for (unsigned long j = 0; j < stationary_region_rects.size(); ++j)\n                {\n                    stationary_region_rects[j] = std::make_pair(j, translate_rect(feats[l].image_to_feat_space(det_templates[i].rects[j]),offset)); \n                }\n                for (unsigned long j = 0; j < movable_region_rects.size(); ++j)\n                {\n                    // Scale the size of the movable rectangle but make sure its center\n                    // stays at point(0,0).\n                    const rectangle temp = feats[l].image_to_feat_space(det_templates[i].movable_rects[j]);\n                    movable_region_rects[j] = std::make_pair(j+stationary_region_rects.size(),\n                                                             centered_rect(point(0,0),temp.width(), temp.height())); \n                }\n\n                // Scale the object box into the feature extraction image, but keeping it\n                // centered at point(0,0).\n                rectangle scaled_object_box = feats[l].image_to_feat_space(det_templates[i].object_box);\n                scaled_object_box = centered_rect(point(0,0),scaled_object_box.width(), scaled_object_box.height());\n\n                // Each detection template gets its own special threshold in addition to\n                // the global detection threshold.  This allows us to model the fact that\n                // some detection templates might be more prone to false alarming or since\n                // their size is different naturally require a larger or smaller threshold\n                // (since they integrate over a larger or smaller region of the image).\n                const double template_specific_thresh = w(i);\n\n                scan_image_movable_parts(point_dets, saliency_images, scaled_object_box,\n                                         stationary_region_rects, movable_region_rects,\n                                         thresh+template_specific_thresh, max_dets_per_template); \n\n                // convert all the point detections into rectangles at the original image scale and coordinate system\n                for (unsigned long j = 0; j < point_dets.size(); ++j)\n                {\n                    const double score = point_dets[j].first-template_specific_thresh;\n                    point p = point_dets[j].second;\n                    p = feats[l].feat_to_image_space(p);\n                    rectangle rect = translate_rect(det_templates[i].object_box, p);\n                    rect = pyr.rect_up(rect, l);\n\n                    dets.push_back(std::make_pair(score, rect));\n                }\n            }\n        }\n\n        std::sort(dets.rbegin(), dets.rend(), compare_pair_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    const rectangle scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_best_matching_rect (\n        const rectangle& rect\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 ,\n            \"\\t const rectangle scan_image_pyramid::get_best_matching_rect()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t this: \" << this\n            );\n\n        rectangle mapped_rect, object_box;\n        detection_template best_template;\n        unsigned long best_level, junk;\n        get_mapped_rect_and_metadata(max_pyramid_levels, rect, mapped_rect, best_template, object_box, best_level, junk);\n        return mapped_rect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_mapped_rect_and_metadata (\n        const unsigned long number_pyramid_levels,\n        rectangle rect,\n        rectangle& mapped_rect,\n        detection_template& best_template,\n        rectangle& object_box,\n        unsigned long& best_level,\n        unsigned long& detection_template_idx\n    ) const\n    {\n        pyramid_type pyr;\n        // Figure out the pyramid level which best matches rect against one of our \n        // detection template object boxes.\n        best_level = 0;\n        double best_match_score = -1;\n\n\n        // Find the best matching detection template for rect\n        for (unsigned long l = 0; l < number_pyramid_levels; ++l)\n        {\n            const rectangle temp = pyr.rect_down(rect,l);\n            if (temp.area() <= 1) \n                break;\n\n            // At this pyramid level, what matches best?\n            for (unsigned long t = 0; t < det_templates.size(); ++t)\n            {\n                const double match_score = get_match_score(det_templates[t].object_box, temp);\n                if (match_score > best_match_score)\n                {\n                    best_match_score = match_score;\n                    best_level = l;\n                    best_template = det_templates[t];\n                    detection_template_idx = t;\n                }\n            }\n        }\n\n\n        // Now we translate best_template into the right spot (it should be centered at the location \n        // determined by rect) and convert it into the feature image coordinate system.\n        rect = pyr.rect_down(rect,best_level);\n        const point offset = -feats_config.image_to_feat_space(point(0,0));\n        const point origin = feats_config.image_to_feat_space(center(rect)) + offset;\n        for (unsigned long k = 0; k < best_template.rects.size(); ++k)\n        {\n            rectangle temp = best_template.rects[k];\n            temp = feats_config.image_to_feat_space(temp);\n            temp = translate_rect(temp, origin);\n            best_template.rects[k] = temp;\n        }\n        for (unsigned long k = 0; k < best_template.movable_rects.size(); ++k)\n        {\n            rectangle temp = best_template.movable_rects[k];\n            temp = feats_config.image_to_feat_space(temp);\n            temp = centered_rect(point(0,0), temp.width(), temp.height());\n            best_template.movable_rects[k] = temp;\n        }\n\n        const rectangle scaled_object_box = feats_config.image_to_feat_space(best_template.object_box);\n        object_box = centered_rect(origin-offset, scaled_object_box.width(), scaled_object_box.height());\n\n        // The input rectangle was mapped to one of the detection templates.  Reverse the process\n        // to figure out what the mapped rectangle is in the original input space.\n        mapped_rect = translate_rect(best_template.object_box, feats_config.feat_to_image_space(origin-offset));\n        mapped_rect = pyr.rect_up(mapped_rect, best_level);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    full_object_detection scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_full_object_detection (\n        const rectangle& rect,\n        const feature_vector_type& w\n    ) const\n    {\n        // fill in movable part positions.  \n\n        rectangle mapped_rect;\n        detection_template best_template;\n        unsigned long best_level, junk;\n        rectangle object_box;\n        get_mapped_rect_and_metadata(feats.size(), rect, mapped_rect, best_template, object_box, best_level, junk);\n\n        Pyramid_type pyr;\n\n        array2d<double> saliency_image, sum_img;\n\n        double total_temp_score = 0;\n        // convert into feature space.\n        object_box = object_box.intersect(get_rect(feats[best_level]));\n\n        std::vector<dpoint> movable_parts;\n        movable_parts.reserve(get_num_movable_components_per_detection_template());\n        for (unsigned long i = 0; i < get_num_movable_components_per_detection_template(); ++i)\n        {\n            // make the saliency_image for the ith movable part.\n\n            const rectangle part_rect = best_template.movable_rects[i];\n            const rectangle area = grow_rect(object_box, \n                                             part_rect.width()/2, \n                                             part_rect.height()/2).intersect(get_rect(feats[best_level]));\n\n            saliency_image.set_size(area.height(), area.width());\n            const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*(i+get_num_stationary_components_per_detection_template());\n\n            // build saliency image for pyramid level best_level \n            for (long r = area.top(); r <= area.bottom(); ++r)\n            {\n                for (long c = area.left(); c <= area.right(); ++c)\n                {\n                    const typename feature_extractor_type::descriptor_type& descriptor = feats[best_level](r,c);\n\n                    double sum = 0;\n                    for (unsigned long k = 0; k < descriptor.size(); ++k)\n                    {\n                        sum += w(descriptor[k].first + offset)*descriptor[k].second;\n                    }\n                    saliency_image[r-area.top()][c-area.left()] = sum;\n                }\n            }\n\n            sum_img.set_size(saliency_image.nr(), saliency_image.nc());\n            sum_filter_assign(saliency_image, sum_img, part_rect);\n            // Figure out where the maximizer is in sum_img.  Note that we\n            // only look in the part of sum_img that corresponds to a location inside\n            // object_box.\n            rectangle valid_area = get_rect(sum_img);\n            valid_area.left()   += object_box.left()   - area.left();\n            valid_area.top()    += object_box.top()    - area.top();\n            valid_area.right()  += object_box.right()  - area.right();\n            valid_area.bottom() += object_box.bottom() - area.bottom();\n            double max_val = 0;\n            point max_loc;\n            for (long r = valid_area.top(); r <= valid_area.bottom(); ++r)\n            {\n                for (long c = valid_area.left(); c <= valid_area.right(); ++c)\n                {\n                    if (sum_img[r][c] > max_val)\n                    {\n                        //if (object_box.contains(point(c,r) + area.tl_corner()))\n                        {\n                            max_loc = point(c,r);\n                            max_val = sum_img[r][c];\n                        }\n                    }\n                }\n            }\n\n            if (max_val <= 0)\n            {\n                max_loc = OBJECT_PART_NOT_PRESENT;\n            }\n            else\n            {\n                total_temp_score += max_val;\n                // convert max_loc back into feature image space from our cropped image.\n                max_loc += area.tl_corner();\n\n                // now convert from feature space to image space.\n                max_loc = feats[best_level].feat_to_image_space(max_loc);\n                max_loc = pyr.point_up(max_loc, best_level);\n                max_loc = nearest_point(rect, max_loc);\n            }\n\n            movable_parts.push_back(max_loc);\n        }\n\n        return full_object_detection(rect, movable_parts);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_feature_vector (\n        const full_object_detection& obj,\n        feature_vector_type& psi\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(get_num_detection_templates() > 0 &&\n                    is_loaded_with_image() &&\n                    psi.size() >= get_num_dimensions() &&\n                    obj.num_parts() == get_num_movable_components_per_detection_template(),\n            \"\\t void scan_image_pyramid::get_feature_vector()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t get_num_detection_templates(): \" << get_num_detection_templates()\n            << \"\\n\\t is_loaded_with_image(): \" << is_loaded_with_image()\n            << \"\\n\\t psi.size():             \" << psi.size()\n            << \"\\n\\t get_num_dimensions():   \" << get_num_dimensions()\n            << \"\\n\\t get_num_movable_components_per_detection_template(): \" << get_num_movable_components_per_detection_template()\n            << \"\\n\\t obj.num_parts():                            \" << obj.num_parts()\n            << \"\\n\\t this: \" << this\n            );\n        DLIB_ASSERT(all_parts_in_rect(obj), \n            \"\\t void scan_image_pyramid::get_feature_vector()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t obj.get_rect(): \" << obj.get_rect()\n            << \"\\n\\t this: \" << this\n        );\n\n\n\n        rectangle mapped_rect;\n        detection_template best_template;\n        unsigned long best_level, detection_template_idx;\n        rectangle object_box;\n        get_mapped_rect_and_metadata(feats.size(), obj.get_rect(), mapped_rect, best_template, object_box, best_level, detection_template_idx);\n\n        psi(detection_template_idx) -= 1;\n\n        Pyramid_type pyr;\n\n        // put the movable rects at the places indicated by obj.\n        std::vector<rectangle> rects = best_template.rects;\n        for (unsigned long i = 0; i < obj.num_parts(); ++i)\n        {\n            if (obj.part(i) != OBJECT_PART_NOT_PRESENT)\n            {\n                // map from the original image to scaled feature space.\n                point loc = feats[best_level].image_to_feat_space(pyr.point_down(obj.part(i), best_level));\n                // Make sure the movable part always stays within the object_box.\n                // Otherwise it would be at a place that the detect() function can never\n                // look.  \n                loc = nearest_point(object_box, loc);\n                rects.push_back(translate_rect(best_template.movable_rects[i], loc));\n            }\n            else\n            {\n                // add an empty rectangle since this part wasn't observed.\n                rects.push_back(rectangle());\n            }\n        }\n\n        // pull features out of all the boxes in rects.\n        for (unsigned long j = 0; j < rects.size(); ++j)\n        {\n            const rectangle rect = rects[j].intersect(get_rect(feats[best_level]));\n            const unsigned long template_region_id = j;\n            const unsigned long offset = get_num_detection_templates() + feats_config.get_num_dimensions()*template_region_id;\n            for (long r = rect.top(); r <= rect.bottom(); ++r)\n            {\n                for (long c = rect.left(); c <= rect.right(); ++c)\n                {\n                    const typename feature_extractor_type::descriptor_type& descriptor = feats[best_level](r,c);\n                    for (unsigned long k = 0; k < descriptor.size(); ++k)\n                    {\n                        psi(descriptor[k].first + offset) += descriptor[k].second;\n                    }\n                }\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    set_min_pyramid_layer_size (\n        unsigned long width,\n        unsigned long height \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(width > 0 && height > 0 ,\n            \"\\t void scan_image_pyramid::set_min_pyramid_layer_size()\"\n            << \"\\n\\t These sizes can't be zero. \"\n            << \"\\n\\t width:  \" << width \n            << \"\\n\\t height: \" << height \n            << \"\\n\\t this:   \" << this\n            );\n\n        min_pyramid_layer_width = width;\n        min_pyramid_layer_height = height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_min_pyramid_layer_width (\n    ) const\n    {\n        return min_pyramid_layer_width;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    unsigned long scan_image_pyramid<Pyramid_type,Feature_extractor_type>::\n    get_min_pyramid_layer_height (\n    ) const\n    {\n        return min_pyramid_layer_height;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMaGE_PYRAMID_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_pyramid_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../image_processing.h\"\n#include \"../array2d.h\"\n#include <vector>\n#include \"full_object_detection_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    class scan_image_pyramid : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON Pyramid_type\n                - must be one of the pyramid_down objects defined in \n                  dlib/image_transforms/image_pyramid_abstract.h or an object with\n                  a compatible interface\n\n            REQUIREMENTS ON Feature_extractor_type\n                - must be an object with an interface compatible with the hashed_feature_image \n                  object defined in dlib/image_keypoint/hashed_feature_image_abstract.h or \n                  with the nearest_neighbor_feature_image object defined in \n                  dlib/image_keypoint/nearest_neighbor_feature_image_abstract.h\n\n            INITIAL VALUE\n                - get_num_detection_templates() == 0\n                - is_loaded_with_image() == false\n                - get_max_detections_per_template() == 10000\n                - get_max_pyramid_levels() == 1000\n                - get_min_pyramid_layer_width() == 20\n                - get_min_pyramid_layer_height() == 20\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for running a sliding window classifier over\n                an image pyramid.  This object can also be understood as a general \n                tool for implementing the spatial pyramid models described in the paper:\n                    Beyond Bags of Features: Spatial Pyramid Matching for Recognizing \n                    Natural Scene Categories by Svetlana Lazebnik, Cordelia Schmid, \n                    and Jean Ponce\n                It also includes the ability to represent movable part models.\n\n                \n\n\n                The sliding window classifiers used by this object have three parts: \n                   1. The underlying feature extraction provided by Feature_extractor_type\n                      objects, which associate a vector with each location in an image.\n\n                   2. A detection template.  This is a rectangle which defines the shape of a \n                      sliding window (i.e. the object_box), as well as a set of rectangular feature \n                      extraction regions inside it.  This set of regions defines the spatial \n                      structure of the overall feature extraction within a sliding window.  In \n                      particular, each location of a sliding window has a feature vector \n                      associated with it.  This feature vector is defined as follows:\n                        - Let N denote the number of feature extraction zones.\n                        - Let M denote the dimensionality of the vectors output by Feature_extractor_type\n                          objects.\n                        - Let F(i) == the M dimensional vector which is the sum of all vectors \n                          given by our Feature_extractor_type object inside the i-th feature extraction\n                          zone.\n                        - Then the feature vector for a sliding window is an M*N dimensional vector\n                          [F(1) F(2) F(3) ... F(N)] (i.e. it is a concatenation of the N vectors).\n                          This feature vector can be thought of as a collection of N \"bags of features\",\n                          each bag coming from a spatial location determined by one of the rectangular\n                          feature extraction zones.\n                          \n                   3. A weight vector and a threshold value.  The dot product between the weight\n                      vector and the feature vector for a sliding window location gives the score \n                      of the window.  If this score is greater than the threshold value then the \n                      window location is output as a detection.\n\n                Finally, the sliding window classifiers described above are applied to every level of\n                an image pyramid.  Moreover, some of the feature extraction zones are allowed to move\n                freely within the object box.  This means that when we are sliding the classifier over\n                an image, some feature extraction zones are stationary (i.e. always in the same place\n                relative to the object box) while others are allowed to move anywhere within the object\n                box.  In particular, the movable regions are placed at the locations that maximize the\n                score of the classifier.  Note further that each of the movable feature extraction\n                zones must pass a threshold test for it to be included.  That is, if the score that a\n                movable zone would contribute to the overall score for a sliding window location is not\n                positive then that zone is not included in the feature vector (i.e.  its part of the\n                feature vector is set to zero.  This way the length of the feature vector stays\n                constant).  This movable region construction allows us to represent objects with parts\n                that move around relative to the object box.  For example, a human has hands but they\n                aren't always in the same place relative to a person's bounding box.  \n\n            THREAD SAFETY\n                Concurrent access to an instance of this object is not safe and should be protected\n                by a mutex lock except for the case where you are copying the configuration \n                (via copy_configuration()) of a scan_image_pyramid object to many other threads.  \n                In this case, it is safe to copy the configuration of a shared object so long\n                as no other operations are performed on it.\n        !*/\n    public:\n\n        typedef matrix<double,0,1> feature_vector_type;\n\n        typedef Pyramid_type pyramid_type;\n        typedef Feature_extractor_type feature_extractor_type;\n\n        scan_image_pyramid (\n        );  \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename image_type\n            >\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type must be a type with the following properties:\n                    - image_type is default constructable.\n                    - image_type is swappable by the global swap() function.\n                    - image_type logically represents some kind of image and therefore its\n                      number of rows and columns can be queried via num_rows(img) and\n                      num_columns(img) respectively.\n                    - image_type objects can be loaded into Feature_extractor_type\n                      objects via Feature_extractor_type::load().\n                    - image_type objects can be used with Pyramid_type.  That is,\n                      if pyr is an object of type Pyramid_type while img1 and img2\n                      are objects of image_type, then pyr(img1,img2) should be\n                      a valid expression which downsamples img1 into img2.\n            ensures\n                - #is_loaded_with_image() == true\n                - This object is ready to run sliding window classifiers over img.  Call\n                  detect() to do this.\n        !*/\n\n        bool is_loaded_with_image (\n        ) const;\n        /*!\n            ensures\n                - returns true if this object has been loaded with an image to process\n                  and false otherwise.\n        !*/\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the feature_extractor_type object used \n                  internally for local feature extraction.  \n        !*/\n\n        void copy_configuration(\n            const feature_extractor_type& fe\n        );\n        /*!\n            ensures\n                - This function performs the equivalent of\n                  get_feature_extractor().copy_configuration(fe) (i.e. this function allows\n                  you to configure the parameters of the underlying feature extractor used\n                  by a scan_image_pyramid object)\n        !*/\n\n        void copy_configuration (\n            const scan_image_pyramid& item\n        );\n        /*!\n            ensures\n                - copies all the state information of item into *this, except for state \n                  information populated by load().  More precisely, given two scan_image_pyramid \n                  objects S1 and S2, the following sequence of instructions should always \n                  result in both of them having the exact same state.\n                    S2.copy_configuration(S1);\n                    S1.load(img);\n                    S2.load(img);\n        !*/\n\n        void add_detection_template (\n            const rectangle& object_box,\n            const std::vector<rectangle>& stationary_feature_extraction_regions,\n            const std::vector<rectangle>& movable_feature_extraction_regions\n        );\n        /*!\n            requires\n                - center(object_box) == point(0,0)\n                - for all valid i:\n                    - center(movable_feature_extraction_regions[i]) == point(0,0)\n                - if (get_num_detection_templates() > 0) then\n                    - get_num_stationary_components_per_detection_template() == stationary_feature_extraction_regions.size() \n                    - get_num_movable_components_per_detection_template() == movable_feature_extraction_regions.size() \n                      (i.e. if you already have detection templates in this object, then\n                      any new detection template must declare a consistent number of \n                      feature extraction regions)\n            ensures\n                - Adds another detection template to this object.  In particular, object_box \n                  defines the size and shape of a sliding window while stationary_feature_extraction_regions \n                  and movable_feature_extraction_regions defines the locations for feature extraction as \n                  discussed in the WHAT THIS OBJECT REPRESENTS section above.  Note also that the locations of \n                  the stationary feature extraction regions are relative to the object_box.  \n                - #get_num_detection_templates() == get_num_detection_templates() + 1\n                - The order of rectangles in stationary_feature_extraction_regions and\n                  movable_feature_extraction_regions matters.  Recall that each rectangle\n                  gets its own set of features.  So given two different templates, their\n                  i-th rectangles will both share the same part of the weight vector (i.e. the w\n                  supplied to detect()).  So there should be some reasonable correspondence\n                  between the rectangle ordering in different detection templates.  For,\n                  example, different detection templates should place corresponding feature\n                  extraction regions in roughly the same part of the object_box.\n                - #get_num_stationary_components_per_detection_template() = stationary_feature_extraction_regions.size() \n                - #get_num_movable_components_per_detection_template()    = movable_feature_extraction_regions.size() \n        !*/\n\n        void add_detection_template (\n            const rectangle& object_box,\n            const std::vector<rectangle>& stationary_feature_extraction_regions\n        );\n        /*!\n            ensures\n                - calls add_detection_template(object_box, stationary_feature_extraction_regions, empty_list)\n                  where empty_list is a vector of size 0.  I.e. this function is just a convenience\n                  routine for adding detection templates with no movable regions.\n        !*/\n\n        unsigned long get_num_detection_templates (\n        ) const;\n        /*!\n            ensures\n                - returns the number of detection templates in this object\n        !*/\n\n        unsigned long get_num_stationary_components_per_detection_template (\n        ) const;\n        /*!\n            requires\n                - get_num_detection_templates() > 0\n            ensures\n                - A detection template is a rectangle which defines the shape of a sliding\n                  window (the object_box), as well as a set of rectangles which define\n                  feature extraction zones.  This function returns the number of stationary\n                  feature extraction zones in the detection templates used by this object. \n        !*/\n\n        unsigned long get_num_movable_components_per_detection_template (\n        ) const;\n        /*!\n            requires\n                - get_num_detection_templates() > 0\n            ensures\n                - A detection template is a rectangle which defines the shape of a sliding\n                  window (the object_box), as well as a set of rectangles which define\n                  feature extraction zones.  This function returns the number of movable \n                  feature extraction zones in the detection templates used by this object. \n        !*/\n\n        unsigned long get_num_components_per_detection_template (\n        ) const;\n        /*!\n            requires\n                - get_num_detection_templates() > 0\n            ensures\n                - returns the total number of feature extraction zones in the detection\n                  templates used by this object.  That is, returns the following:\n                    - get_num_movable_components_per_detection_template() + \n                      get_num_stationary_components_per_detection_template()\n        !*/\n\n        long get_num_dimensions (\n        ) const;\n        /*!\n            requires\n                - get_num_detection_templates() > 0\n            ensures\n                - returns the number of dimensions in the feature vector for a sliding window\n                  location.  This value is the dimensionality of the underlying feature vectors \n                  produced by Feature_extractor_type times (get_num_stationary_components_per_detection_template() + \n                  get_num_movable_components_per_detection_template()).\n        !*/\n\n        unsigned long get_max_pyramid_levels (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum number of image pyramid levels this object will use.\n                  Note that #get_max_pyramid_levels() == 1 indicates that no image pyramid\n                  will be used at all.  That is, only the original image will be processed\n                  and no lower scale versions will be created.  \n        !*/\n\n        void set_max_pyramid_levels (\n            unsigned long max_levels\n        );\n        /*!\n            requires\n                - max_levels > 0\n            ensures\n                - #get_max_pyramid_levels() == max_levels\n        !*/\n\n        void set_min_pyramid_layer_size (\n            unsigned long width,\n            unsigned long height \n        );\n        /*!\n            requires\n                - width > 0\n                - height > 0\n            ensures\n                - #get_min_pyramid_layer_width() == width\n                - #get_min_pyramid_layer_height() == height\n        !*/\n\n        inline unsigned long get_min_pyramid_layer_width (\n        ) const;\n        /*!\n            ensures\n                - returns the smallest allowable width of an image in the image pyramid.\n                  All pyramids will always include the original input image, however, no\n                  pyramid levels will be created which have a width smaller than the\n                  value returned by this function.\n        !*/\n\n        inline unsigned long get_min_pyramid_layer_height (\n        ) const;\n        /*!\n            ensures\n                - returns the smallest allowable height of an image in the image pyramid.\n                  All pyramids will always include the original input image, however, no\n                  pyramid levels will be created which have a height smaller than the\n                  value returned by this function.\n        !*/\n\n        unsigned long get_max_detections_per_template (\n        ) const;\n        /*!\n            ensures\n                - For each image pyramid layer and detection template, this object scans a sliding\n                  window classifier over an image and produces a number of detections.  This\n                  function returns a number which defines a hard upper limit on the number of\n                  detections allowed by a single scan.  This means that the total number of\n                  possible detections produced by detect() is get_max_detections_per_template()*\n                  get_num_detection_templates()*(number of image pyramid layers).  Additionally, \n                  if the maximum number of detections is reached during a scan then this object \n                  will return a random subsample of all detections which are above the detection \n                  threshold.\n        !*/\n\n        void set_max_detections_per_template (\n            unsigned long max_dets\n        );\n        /*!\n            requires\n                - max_dets > 0\n            ensures\n                - #get_max_detections_per_template() == max_dets\n        !*/\n\n        void detect (\n            const feature_vector_type& w,\n            std::vector<std::pair<double, rectangle> >& dets,\n            const double thresh\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n                - is_loaded_with_image() == true\n                - get_num_detection_templates() > 0\n            ensures\n                - Scans all the detection templates over all pyramid layers as discussed in the \n                  WHAT THIS OBJECT REPRESENTS section and stores all detections into #dets.\n                - for all valid i:\n                    - #dets[i].second == The object box which produced this detection.  This rectangle gives\n                      the location of the detection.  Note that the rectangle will have been converted back into\n                      the original image input space.  That is, if this detection was made at a low level in the\n                      image pyramid then the object box will have been automatically mapped up the pyramid layers\n                      to the original image space.  Or in other words, if you plot #dets[i].second on top of the \n                      image given to load() it will show up in the right place.\n                    - #dets[i].first == The score for this detection.  This value is equal to dot(w, feature vector\n                      for this sliding window location).\n                    - #dets[i].first >= thresh\n                - #dets will be sorted in descending order. (i.e.  #dets[i].first >= #dets[j].first for all i, and j>i)\n                - Elements of w beyond index get_num_dimensions()-1 are ignored.  I.e. only the first\n                  get_num_dimensions() are used.\n                - Note that no form of non-max suppression is performed.  If a window has a score >= thresh\n                  then it is reported in #dets (assuming the limit imposed by get_max_detections_per_template() hasn't \n                  been reached).\n        !*/\n\n        const rectangle get_best_matching_rect (\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - get_num_detection_templates() > 0\n            ensures\n                - Since scan_image_pyramid is a sliding window classifier system, not all possible rectangles \n                  can be represented.  Therefore, this function allows you to supply a rectangle and obtain the\n                  nearest possible sliding window rectangle.\n        !*/\n\n        void get_feature_vector (\n            const full_object_detection& obj,\n            feature_vector_type& psi\n        ) const;\n        /*!\n            requires\n                - all_parts_in_rect(obj) == true\n                - obj.num_parts() == get_num_movable_components_per_detection_template()\n                - is_loaded_with_image() == true\n                - get_num_detection_templates() > 0\n                - psi.size() >= get_num_dimensions()\n                  (i.e. psi must have preallocated its memory before this function is called)\n            ensures\n                - This function allows you to determine the feature vector used for a\n                  sliding window location.  Note that this vector is added to psi.  Note\n                  also that you must use get_full_object_detection() to convert a rect from\n                  detect() into the needed full_object_detection.\n                - The dimensionality of the vector added to psi is get_num_dimensions().  This\n                  means that elements of psi after psi(get_num_dimensions()-1) are not modified.\n                - Since scan_image_pyramid is a sliding window classifier system, not all\n                  possible rectangles can be output by detect().  So in the case where\n                  obj.get_rect() could not arise from a call to detect(), this function\n                  will map obj.get_rect() to the nearest possible object box and then add\n                  the feature vector for the mapped rectangle into #psi.\n                - get_best_matching_rect(obj.get_rect()) == the rectangle obj.get_rect()\n                  gets mapped to for feature extraction.\n        !*/\n\n        full_object_detection get_full_object_detection (\n            const rectangle& rect,\n            const feature_vector_type& w\n        ) const;\n        /*!\n            requires\n                - w.size() >= get_num_dimensions()\n                - is_loaded_with_image() == true\n                - get_num_detection_templates() > 0\n            ensures\n                - This function allows you to determine the full_object_detection\n                  corresponding to a sliding window location.  Note that the detect()\n                  routine doesn't return the locations of the movable parts in a detected\n                  object.  Therefore, if you are using any movable parts in your model you\n                  must use get_full_object_detection() to find out where the movable parts\n                  were detected.  To do this, you supply the w and detected rectangle.\n                  Then the corresponding fully populated full_object_detection will be\n                  returned.\n                - returns a full_object_detection, OBJ, such that: \n                    - OBJ.get_rect() == rect\n                    - OBJ.num_parts() == get_num_movable_components_per_detection_template()\n                    - OBJ.part(i) == the location of the i-th movable part inside this detection,\n                      or OBJECT_PART_NOT_PRESENT if the part was not found.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void serialize (\n        const scan_image_pyramid<Pyramid_type,Feature_extractor_type>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    template <\n        typename Pyramid_type,\n        typename Feature_extractor_type\n        >\n    void deserialize (\n        scan_image_pyramid<Pyramid_type,Feature_extractor_type>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMaGE_PYRAMID_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_pyramid_tools.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_\n#define DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_\n\n#include \"scan_image_pyramid_tools_abstract.h\"\n#include \"../statistics.h\"\n#include <list>\n#include \"../geometry.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline bool compare_first (\n            const std::pair<unsigned long,rectangle>& a,\n            const std::pair<unsigned long,rectangle>& b\n        )\n        {\n            return a.first < b.first;\n        }\n    }\n\n\n    template <typename image_scanner_type>\n    std::vector<rectangle> determine_object_boxes (\n        const image_scanner_type& scanner,\n        const std::vector<rectangle>& rects,\n        double min_match_score\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,\n            \"\\t std::vector<rectangle> determine_object_boxes()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t min_match_score: \" << min_match_score \n            );\n\n        typename image_scanner_type::pyramid_type pyr;\n\n        typedef std::list<std::pair<unsigned long, rectangle> > list_type;\n\n        unsigned long max_area = 0;\n\n        // Copy rects into sorted_rects and sort them in order of increasing area.  But\n        // only include the rectangles that aren't already obtainable by the scanner.\n        list_type sorted_rects;\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            if (scanner.get_num_detection_templates() > 0)\n            {\n                rectangle temp = scanner.get_best_matching_rect(rects[i]);\n                const double match_score = (rects[i].intersect(temp).area())/(double)(rects[i] + temp).area();\n                // skip this rectangle if it's already matched well enough.\n                if (match_score > min_match_score)\n                    continue;\n            }\n            max_area = std::max(rects[i].area(), max_area);\n            sorted_rects.push_back(std::make_pair(rects[i].area(), rects[i]));\n        }\n        sorted_rects.sort(dlib::impl::compare_first);\n\n        // Make sure this area value is comfortably larger than all the \n        // rectangles' areas.\n        max_area = 3*max_area + 100;\n\n        std::vector<rectangle> object_boxes;\n\n        while (sorted_rects.size() != 0)\n        {\n            rectangle cur = sorted_rects.front().second;\n            sorted_rects.pop_front();\n            object_boxes.push_back(centered_rect(point(0,0), cur.width(), cur.height()));\n\n            // Scale cur up the image pyramid and remove any rectangles which match.\n            // But also stop when cur gets large enough to not match anything.\n            for (unsigned long itr = 0; \n                 itr < scanner.get_max_pyramid_levels() && cur.area() < max_area; \n                 ++itr)\n            {\n                list_type::iterator i = sorted_rects.begin();\n                while (i != sorted_rects.end())\n                {\n                    const rectangle temp = move_rect(i->second, cur.tl_corner());\n                    const double match_score = (cur.intersect(temp).area())/(double)(cur + temp).area();\n                    if (match_score > min_match_score)\n                    {\n                        i = sorted_rects.erase(i);\n                    }\n                    else\n                    {\n                        ++i;\n                    }\n                }\n\n                cur = pyr.rect_up(cur);\n            }\n\n        }\n\n        return object_boxes;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_scanner_type>\n    std::vector<rectangle> determine_object_boxes (\n        const image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        double min_match_score\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < min_match_score && min_match_score <= 1,\n            \"\\t std::vector<rectangle> determine_object_boxes()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t min_match_score: \" << min_match_score \n            );\n\n        std::vector<rectangle> temp;\n        for (unsigned long i = 0; i < rects.size(); ++i)\n        {\n            for (unsigned long j = 0; j < rects[i].size(); ++j)\n            {\n                temp.push_back(rects[i][j]);\n            }\n        }\n\n        return determine_object_boxes(scanner, temp, min_match_score);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_scanner_type>\n    void setup_grid_detection_templates (\n        image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        unsigned int cells_x,\n        unsigned int cells_y,\n        double min_match_score = 0.75\n    )\n    {\n        const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);\n        for (unsigned long i = 0; i < object_boxes.size(); ++i)\n        {\n            scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_scanner_type>\n    void setup_grid_detection_templates_verbose (\n        image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        unsigned int cells_x,\n        unsigned int cells_y,\n        double min_match_score = 0.75\n    )\n    {\n        const std::vector<rectangle>& object_boxes = determine_object_boxes(scanner, rects, min_match_score);\n        std::cout << \"number of detection templates: \"<< object_boxes.size() << std::endl;\n        for (unsigned long i = 0; i < object_boxes.size(); ++i)\n        {\n            std::cout << \"  object box \" << i << \":  width: \" << object_boxes[i].width() \n                      << \"  height: \"<< object_boxes[i].height() << std::endl;\n            scanner.add_detection_template(object_boxes[i], create_grid_detection_template(object_boxes[i], cells_x, cells_y));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMaGE_PYRAMID_TOOLS_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/scan_image_pyramid_tools_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_\n#ifdef DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_\n\n#include \"scan_image_pyramid_abstract.h\"\n#include <vector>\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    std::vector<rectangle> determine_object_boxes (\n        const image_scanner_type& scanner,\n        const std::vector<rectangle>& rects,\n        double min_match_score\n    );\n    /*!\n        requires\n            - 0 < min_match_score <= 1\n            - image_scanner_type == an implementation of the scan_image_pyramid\n              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h\n        ensures\n            - returns a set of object boxes which, when used as detection templates with\n              the given scanner, can attain at least min_match_score alignment with every\n              element of rects.  Note that the alignment between two rectangles A and B is\n              defined as:\n                (A.intersect(B).area())/(double)(A+B).area()\n            - Only elements of rects which are not already well matched by the scanner are\n              considered.  That is, if the scanner already has some detection templates in\n              it then the contents of rects will be checked against those detection\n              templates and elements with a match better than min_match_score are ignore.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    std::vector<rectangle> determine_object_boxes (\n        const image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        double min_match_score\n    );\n    /*!\n        requires\n            - 0 < min_match_score <= 1\n            - image_scanner_type == an implementation of the scan_image_pyramid\n              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h\n        ensures\n            - copies all rectangles in rects into a std::vector<rectangle> object, call it\n              R.  Then this function returns determine_object_boxes(scanner,R,min_match_score).\n              That is, it just called the version of determine_object_boxes() defined above\n              and returns the results.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    void setup_grid_detection_templates (\n        image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        unsigned int cells_x,\n        unsigned int cells_y,\n        double min_match_score = 0.75\n    );\n    /*!\n        requires\n            - cells_x > 0\n            - cells_y > 0\n            - 0 < min_match_score <= 1\n            - image_scanner_type == an implementation of the scan_image_pyramid\n              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h\n        ensures\n            - uses determine_object_boxes(scanner,rects,min_match_score) to obtain a set of\n              object boxes and then adds them to the given scanner object as detection templates.\n              Also uses create_grid_detection_template(object_box, cells_x, cells_y) to create\n              each feature extraction region.  Therefore, the detection templates will extract\n              features from a regular grid inside each object box.\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner_type\n        >\n    void setup_grid_detection_templates_verbose (\n        image_scanner_type& scanner,\n        const std::vector<std::vector<rectangle> >& rects,\n        unsigned int cells_x,\n        unsigned int cells_y,\n        double min_match_score = 0.75\n    );\n    /*!\n        requires\n            - cells_x > 0\n            - cells_y > 0\n            - 0 < min_match_score <= 1\n            - image_scanner_type == an implementation of the scan_image_pyramid\n              object defined in dlib/image_processing/scan_image_pyramid_tools_abstract.h\n        ensures\n            - this function is identical to setup_grid_detection_templates() except\n              that it also outputs the selected detection templates to standard out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SCAN_IMaGE_PYRAMID_TOOLS_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_processing/setup_hashed_features.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SETUP_HAShED_FEATURES_Hh_\n#define DLIB_SETUP_HAShED_FEATURES_Hh_\n\n#include \"setup_hashed_features_abstract.h\"\n#include \"scan_image_pyramid.h\"\n#include \"scan_image_boxes.h\"\n#include \"../lsh.h\"\n#include \"../statistics.h\"\n#include \"../image_keypoint.h\"\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_hash_construction_failure : public error\n    {\n    public:\n        image_hash_construction_failure(\n            const std::string& a\n        ): error(a) {}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner\n        >\n    void use_uniform_feature_weights (\n        image_scanner& scanner\n    )\n    {\n        typename image_scanner::feature_extractor_type fe;\n        fe.copy_configuration(scanner.get_feature_extractor());\n        fe.use_uniform_feature_weights();\n        scanner.copy_configuration(fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner\n        >\n    void use_relative_feature_weights (\n        image_scanner& scanner\n    )\n    {\n        typename image_scanner::feature_extractor_type fe;\n        fe.copy_configuration(scanner.get_feature_extractor());\n        fe.use_relative_feature_weights();\n        scanner.copy_configuration(fe);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                 stuff for scan_image_pyramid\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename pyramid,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image\n        >\n    void setup_hashed_features (\n        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,\n        const image_array& images,\n        const feature_extractor& fe,\n        int bits,\n        unsigned long num_samples = 200000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    num_samples > 1 && \n                    images.size() > 0,\n            \"\\t void setup_hashed_features()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t bits:          \" << bits \n            << \"\\n\\t num_samples:   \" << num_samples \n            << \"\\n\\t images.size(): \" << images.size() \n            );\n\n        pyramid pyr;\n\n        const random_subset_selector<typename feature_extractor::descriptor_type>& samps = \n            randomly_sample_image_features(images, pyr, fe, num_samples);\n\n        if (samps.size() <= 1)\n            throw dlib::image_hash_construction_failure(\"Images too small, not able to gather enough samples to make hash\");\n\n        projection_hash phash = create_random_projection_hash(samps, bits);\n\n        feature_image<feature_extractor, projection_hash> hfe;\n        hfe.copy_configuration(scanner.get_feature_extractor());\n        hfe.set_hash(phash);\n        hfe.copy_configuration(fe);\n        scanner.copy_configuration(hfe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename pyramid,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image\n        >\n    void setup_hashed_features (\n        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,\n        const image_array& images,\n        int bits,\n        unsigned long num_samples = 200000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    num_samples > 1 && \n                    images.size() > 0,\n            \"\\t void setup_hashed_features()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t bits:          \" << bits \n            << \"\\n\\t num_samples:   \" << num_samples \n            << \"\\n\\t images.size(): \" << images.size() \n            );\n\n        feature_extractor fe;\n        setup_hashed_features(scanner, images, fe, bits, num_samples);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                 stuff for scan_image_boxes\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image,\n        typename box_generator\n        >\n    void setup_hashed_features (\n        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator >& scanner,\n        const image_array& images,\n        const feature_extractor& fe,\n        int bits,\n        unsigned long num_samples = 200000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    num_samples > 1 && \n                    images.size() > 0,\n            \"\\t void setup_hashed_features()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t bits:          \" << bits \n            << \"\\n\\t num_samples:   \" << num_samples \n            << \"\\n\\t images.size(): \" << images.size() \n            );\n\n        pyramid_disable pyr;\n\n        const random_subset_selector<typename feature_extractor::descriptor_type>& samps = \n            randomly_sample_image_features(images, pyr, fe, num_samples);\n\n        if (samps.size() <= 1)\n            throw dlib::image_hash_construction_failure(\"Images too small, not able to gather enough samples to make hash\");\n\n        projection_hash phash = create_random_projection_hash(samps, bits);\n\n        feature_image<feature_extractor, projection_hash> hfe;\n        hfe.copy_configuration(scanner.get_feature_extractor());\n        hfe.set_hash(phash);\n        hfe.copy_configuration(fe);\n        scanner.copy_configuration(hfe);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image,\n        typename box_generator\n        >\n    void setup_hashed_features (\n        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,\n        const image_array& images,\n        int bits,\n        unsigned long num_samples = 200000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    num_samples > 1 && \n                    images.size() > 0,\n            \"\\t void setup_hashed_features()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t bits:          \" << bits \n            << \"\\n\\t num_samples:   \" << num_samples \n            << \"\\n\\t images.size(): \" << images.size() \n            );\n\n        feature_extractor fe;\n        setup_hashed_features(scanner, images, fe, bits, num_samples);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SETUP_HAShED_FEATURES_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/setup_hashed_features_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_\n#ifdef DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_\n\n#include \"scan_image_pyramid_abstract.h\"\n#include \"scan_image_boxes_abstract.h\"\n#include \"../lsh/projection_hash_abstract.h\"\n#include \"../image_keypoint/hashed_feature_image_abstract.h\"\n#include \"../image_keypoint/binned_vector_feature_image_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_hash_construction_failure : public error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception object used by the routines in this file.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner\n        >\n    void use_uniform_feature_weights (\n        image_scanner& scanner\n    );\n    /*!\n        requires\n            - image_scanner should be either scan_image_pyramid or scan_image_boxes and\n              should use the hashed_feature_image as its local feature extractor.\n        ensures\n            - #scanner.get_feature_extractor().uses_uniform_feature_weights() == true\n              (i.e. Make the scanner's feature extractor use the uniform feature weighting\n              scheme)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_scanner\n        >\n    void use_relative_feature_weights (\n        image_scanner& scanner\n    );\n    /*!\n        requires\n            - image_scanner should be either scan_image_pyramid or scan_image_boxes and\n              should use the hashed_feature_image as its local feature extractor.\n        ensures\n            - #scanner.get_feature_extractor().uses_uniform_feature_weights() == false \n              (i.e. Make the scanner's feature extractor use the relative feature weighting\n              scheme)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename pyramid,\n        typename feature_extractor\n        template <typename fe, typename hash> class feature_image\n        >\n    void setup_hashed_features (\n        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,\n        const image_array& images,\n        const feature_extractor& fe,\n        int bits,\n        unsigned long num_samples = 200000\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - num_samples > 1\n            - images.size() > 0\n            - it must be valid to pass images[0] into scanner.load().\n              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)\n            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,\n              or a type with a compatible interface.\n        ensures\n            - Creates a projection_hash suitable for hashing the feature vectors produced by\n              fe and then configures scanner to use this hash function.\n            - The hash function will map vectors into integers in the range [0, pow(2,bits))\n            - The hash function will be setup so that it hashes a random sample of num_samples\n              vectors from fe such that each bin ends up with roughly the same number of \n              elements in it.\n        throws\n            - image_hash_construction_failure\n              This exception is thrown if there is a problem creating the projection_hash.\n              This should only happen the images are so small they contain less than 2\n              feature vectors.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename pyramid,\n        typename feature_extractor\n        template <typename fe, typename hash> class feature_image\n        >\n    void setup_hashed_features (\n        scan_image_pyramid<pyramid, feature_image<feature_extractor, projection_hash> >& scanner,\n        const image_array& images,\n        int bits,\n        unsigned long num_samples = 200000\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - num_samples > 1\n            - images.size() > 0\n            - it must be valid to pass images[0] into scanner.load().\n              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)\n            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,\n              or a type with a compatible interface.\n        ensures\n            - performs: setup_hashed_features(scanner, images, feature_extractor(), bits, num_samples)\n        throws\n            - image_hash_construction_failure\n              This exception is thrown if there is a problem creating the projection_hash.\n              This should only happen the images are so small they contain less than 2\n              feature vectors.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image\n        typename box_generator\n        >\n    void setup_hashed_features (\n        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,\n        const image_array& images,\n        const feature_extractor& fe,\n        int bits,\n        unsigned long num_samples = 200000\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - num_samples > 1\n            - images.size() > 0\n            - it must be valid to pass images[0] into scanner.load().\n              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)\n            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,\n              or a type with a compatible interface.\n        ensures\n            - Creates a projection_hash suitable for hashing the feature vectors produced by\n              fe and then configures scanner to use this hash function.\n            - The hash function will map vectors into integers in the range [0, pow(2,bits))\n            - The hash function will be setup so that it hashes a random sample of num_samples\n              vectors from fe such that each bin ends up with roughly the same number of \n              elements in it.\n        throws\n            - image_hash_construction_failure\n              This exception is thrown if there is a problem creating the projection_hash.\n              This should only happen the images are so small they contain less than 2\n              feature vectors.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array,\n        typename feature_extractor,\n        template <typename fe, typename hash> class feature_image\n        typename box_generator\n        >\n    void setup_hashed_features (\n        scan_image_boxes<feature_image<feature_extractor, projection_hash>,box_generator>& scanner,\n        const image_array& images,\n        int bits,\n        unsigned long num_samples = 200000\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - num_samples > 1\n            - images.size() > 0\n            - it must be valid to pass images[0] into scanner.load().\n              (also, image_array must be an implementation of dlib/array/array_kernel_abstract.h)\n            - feature_image == must be either hashed_feature_image, binned_vector_feature_image,\n              or a type with a compatible interface.\n        ensures\n            - performs: setup_hashed_features(scanner, images, feature_extractor(), bits, num_samples)\n        throws\n            - image_hash_construction_failure\n              This exception is thrown if there is a problem creating the projection_hash.\n              This should only happen the images are so small they contain less than 2\n              feature vectors.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SETUP_HAShED_FEATURES_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_processing/shape_predictor.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SHAPE_PREDICToR_H_\n#define DLIB_SHAPE_PREDICToR_H_\n\n#include \"shape_predictor_abstract.h\"\n#include \"full_object_detection.h\"\n#include \"../algs.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../pixel.h\"\n#include \"../statistics.h\"\n#include <utility>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        struct split_feature\n        {\n            unsigned long idx1;\n            unsigned long idx2;\n            float thresh;\n\n            friend inline void serialize (const split_feature& item, std::ostream& out)\n            {\n                dlib::serialize(item.idx1, out);\n                dlib::serialize(item.idx2, out);\n                dlib::serialize(item.thresh, out);\n            }\n            friend inline void deserialize (split_feature& item, std::istream& in)\n            {\n                dlib::deserialize(item.idx1, in);\n                dlib::deserialize(item.idx2, in);\n                dlib::deserialize(item.thresh, in);\n            }\n        };\n\n\n        // a tree is just a std::vector<impl::split_feature>.  We use this function to navigate the\n        // tree nodes\n        inline unsigned long left_child (unsigned long idx) { return 2*idx + 1; }\n        /*!\n            ensures\n                - returns the index of the left child of the binary tree node idx\n        !*/\n        inline unsigned long right_child (unsigned long idx) { return 2*idx + 2; }\n        /*!\n            ensures\n                - returns the index of the left child of the binary tree node idx\n        !*/\n\n        struct regression_tree\n        {\n            std::vector<split_feature> splits;\n            std::vector<matrix<float,0,1> > leaf_values;\n\n            unsigned long num_leaves() const { return leaf_values.size(); }\n\n            inline const matrix<float,0,1>& operator()(\n                const std::vector<float>& feature_pixel_values,\n                unsigned long& i\n            ) const\n            /*!\n                requires\n                    - All the index values in splits are less than feature_pixel_values.size()\n                    - leaf_values.size() is a power of 2.\n                      (i.e. we require a tree with all the levels fully filled out.\n                    - leaf_values.size() == splits.size()+1\n                      (i.e. there needs to be the right number of leaves given the number of splits in the tree)\n                ensures\n                    - runs through the tree and returns the vector at the leaf we end up in.\n                    - #i == the selected leaf node index.\n            !*/\n            {\n                i = 0;\n                while (i < splits.size())\n                {\n                    if ((float)feature_pixel_values[splits[i].idx1] - (float)feature_pixel_values[splits[i].idx2] > splits[i].thresh)\n                        i = left_child(i);\n                    else\n                        i = right_child(i);\n                }\n                i = i - splits.size();\n                return leaf_values[i];\n            }\n\n            friend void serialize (const regression_tree& item, std::ostream& out)\n            {\n                dlib::serialize(item.splits, out);\n                dlib::serialize(item.leaf_values, out);\n            }\n            friend void deserialize (regression_tree& item, std::istream& in)\n            {\n                dlib::deserialize(item.splits, in);\n                dlib::deserialize(item.leaf_values, in);\n            }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        inline vector<float,2> location (\n            const matrix<float,0,1>& shape,\n            unsigned long idx\n        )\n        /*!\n            requires\n                - idx < shape.size()/2\n                - shape.size()%2 == 0\n            ensures\n                - returns the idx-th point from the shape vector.\n        !*/\n        {\n            return vector<float,2>(shape(idx*2), shape(idx*2+1));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline unsigned long nearest_shape_point (\n            const matrix<float,0,1>& shape,\n            const dlib::vector<float,2>& pt\n        )\n        {\n            // find the nearest part of the shape to this pixel\n            float best_dist = std::numeric_limits<float>::infinity();\n            const unsigned long num_shape_parts = shape.size()/2;\n            unsigned long best_idx = 0;\n            for (unsigned long j = 0; j < num_shape_parts; ++j)\n            {\n                const float dist = length_squared(location(shape,j)-pt);\n                if (dist < best_dist)\n                {\n                    best_dist = dist;\n                    best_idx = j;\n                }\n            }\n            return best_idx;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void create_shape_relative_encoding (\n            const matrix<float,0,1>& shape,\n            const std::vector<dlib::vector<float,2> >& pixel_coordinates,\n            std::vector<unsigned long>& anchor_idx, \n            std::vector<dlib::vector<float,2> >& deltas\n        )\n        /*!\n            requires\n                - shape.size()%2 == 0 \n                - shape.size() > 0\n            ensures\n                - #anchor_idx.size() == pixel_coordinates.size()\n                - #deltas.size()     == pixel_coordinates.size()\n                - for all valid i:\n                    - pixel_coordinates[i] == location(shape,#anchor_idx[i]) + #deltas[i]\n        !*/\n        {\n            anchor_idx.resize(pixel_coordinates.size());\n            deltas.resize(pixel_coordinates.size());\n\n\n            for (unsigned long i = 0; i < pixel_coordinates.size(); ++i)\n            {\n                anchor_idx[i] = nearest_shape_point(shape, pixel_coordinates[i]);\n                deltas[i] = pixel_coordinates[i] - location(shape,anchor_idx[i]);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline point_transform_affine find_tform_between_shapes (\n            const matrix<float,0,1>& from_shape,\n            const matrix<float,0,1>& to_shape\n        )\n        {\n            DLIB_ASSERT(from_shape.size() == to_shape.size() && (from_shape.size()%2) == 0 && from_shape.size() > 0,\"\");\n            std::vector<vector<float,2> > from_points, to_points;\n            const unsigned long num = from_shape.size()/2;\n            from_points.reserve(num);\n            to_points.reserve(num);\n            if (num == 1)\n            {\n                // Just use an identity transform if there is only one landmark.\n                return point_transform_affine();\n            }\n\n            for (unsigned long i = 0; i < num; ++i)\n            {\n                from_points.push_back(location(from_shape,i));\n                to_points.push_back(location(to_shape,i));\n            }\n            return find_similarity_transform(from_points, to_points);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline point_transform_affine normalizing_tform (\n            const rectangle& rect\n        )\n        /*!\n            ensures\n                - returns a transform that maps rect.tl_corner() to (0,0) and rect.br_corner()\n                  to (1,1).\n        !*/\n        {\n            std::vector<vector<float,2> > from_points, to_points;\n            from_points.push_back(rect.tl_corner()); to_points.push_back(point(0,0));\n            from_points.push_back(rect.tr_corner()); to_points.push_back(point(1,0));\n            from_points.push_back(rect.br_corner()); to_points.push_back(point(1,1));\n            return find_affine_transform(from_points, to_points);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline point_transform_affine unnormalizing_tform (\n            const rectangle& rect\n        )\n        /*!\n            ensures\n                - returns a transform that maps (0,0) to rect.tl_corner() and (1,1) to\n                  rect.br_corner().\n        !*/\n        {\n            std::vector<vector<float,2> > from_points, to_points;\n            to_points.push_back(rect.tl_corner()); from_points.push_back(point(0,0));\n            to_points.push_back(rect.tr_corner()); from_points.push_back(point(1,0));\n            to_points.push_back(rect.br_corner()); from_points.push_back(point(1,1));\n            return find_affine_transform(from_points, to_points);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename image_type, typename feature_type>\n        void extract_feature_pixel_values (\n            const image_type& img_,\n            const rectangle& rect,\n            const matrix<float,0,1>& current_shape,\n            const matrix<float,0,1>& reference_shape,\n            const std::vector<unsigned long>& reference_pixel_anchor_idx,\n            const std::vector<dlib::vector<float,2> >& reference_pixel_deltas,\n            std::vector<feature_type>& feature_pixel_values\n        )\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - reference_pixel_anchor_idx.size() == reference_pixel_deltas.size()\n                - current_shape.size() == reference_shape.size()\n                - reference_shape.size()%2 == 0\n                - max(mat(reference_pixel_anchor_idx)) < reference_shape.size()/2\n            ensures\n                - #feature_pixel_values.size() == reference_pixel_deltas.size()\n                - for all valid i:\n                    - #feature_pixel_values[i] == the value of the pixel in img_ that\n                      corresponds to the pixel identified by reference_pixel_anchor_idx[i]\n                      and reference_pixel_deltas[i] when the pixel is located relative to\n                      current_shape rather than reference_shape.\n        !*/\n        {\n            const matrix<float,2,2> tform = matrix_cast<float>(find_tform_between_shapes(reference_shape, current_shape).get_m());\n            const point_transform_affine tform_to_img = unnormalizing_tform(rect);\n\n            const rectangle area = get_rect(img_);\n\n            const_image_view<image_type> img(img_);\n            feature_pixel_values.resize(reference_pixel_deltas.size());\n            for (unsigned long i = 0; i < feature_pixel_values.size(); ++i)\n            {\n                // Compute the point in the current shape corresponding to the i-th pixel and\n                // then map it from the normalized shape space into pixel space.\n                point p = tform_to_img(tform*reference_pixel_deltas[i] + location(current_shape, reference_pixel_anchor_idx[i]));\n                if (area.contains(p))\n                    feature_pixel_values[i] = get_pixel_intensity(img[p.y()][p.x()]);\n                else\n                    feature_pixel_values[i] = 0;\n            }\n        }\n\n    } // end namespace impl\n\n// ----------------------------------------------------------------------------------------\n\n    class shape_predictor\n    {\n    public:\n\n\n        shape_predictor (\n        ) \n        {}\n\n        shape_predictor (\n            const matrix<float,0,1>& initial_shape_,\n            const std::vector<std::vector<impl::regression_tree> >& forests_,\n            const std::vector<std::vector<dlib::vector<float,2> > >& pixel_coordinates\n        ) : initial_shape(initial_shape_), forests(forests_)\n        /*!\n            requires\n                - initial_shape.size()%2 == 0\n                - forests.size() == pixel_coordinates.size() == the number of cascades\n                - for all valid i:\n                    - all the index values in forests[i] are less than pixel_coordinates[i].size()\n                - for all valid i and j: \n                    - forests[i][j].leaf_values.size() is a power of 2.\n                      (i.e. we require a tree with all the levels fully filled out.\n                    - forests[i][j].leaf_values.size() == forests[i][j].splits.size()+1\n                      (i.e. there need to be the right number of leaves given the number of splits in the tree)\n        !*/\n        {\n            anchor_idx.resize(pixel_coordinates.size());\n            deltas.resize(pixel_coordinates.size());\n            // Each cascade uses a different set of pixels for its features.  We compute\n            // their representations relative to the initial shape now and save it.\n            for (unsigned long i = 0; i < pixel_coordinates.size(); ++i)\n                impl::create_shape_relative_encoding(initial_shape, pixel_coordinates[i], anchor_idx[i], deltas[i]);\n        }\n\n        unsigned long num_parts (\n        ) const\n        {\n            return initial_shape.size()/2;\n        }\n\n        unsigned long num_features (\n        ) const\n        {\n            unsigned long num = 0;\n            for (unsigned long iter = 0; iter < forests.size(); ++iter)\n                for (unsigned long i = 0; i < forests[iter].size(); ++i)\n                    num += forests[iter][i].num_leaves();\n            return num;\n        }\n\n        template <typename image_type>\n        full_object_detection operator()(\n            const image_type& img,\n            const rectangle& rect\n        ) const\n        {\n            using namespace impl;\n            matrix<float,0,1> current_shape = initial_shape;\n            std::vector<float> feature_pixel_values;\n            for (unsigned long iter = 0; iter < forests.size(); ++iter)\n            {\n                extract_feature_pixel_values(img, rect, current_shape, initial_shape,\n                                             anchor_idx[iter], deltas[iter], feature_pixel_values);\n                unsigned long leaf_idx;\n                // evaluate all the trees at this level of the cascade.\n                for (unsigned long i = 0; i < forests[iter].size(); ++i)\n                    current_shape += forests[iter][i](feature_pixel_values, leaf_idx);\n            }\n\n            // convert the current_shape into a full_object_detection\n            const point_transform_affine tform_to_img = unnormalizing_tform(rect);\n            std::vector<point> parts(current_shape.size()/2);\n            for (unsigned long i = 0; i < parts.size(); ++i)\n                parts[i] = tform_to_img(location(current_shape, i));\n            return full_object_detection(rect, parts);\n        }\n\n        template <typename image_type, typename T, typename U>\n        full_object_detection operator()(\n            const image_type& img,\n            const rectangle& rect,\n            std::vector<std::pair<T,U> >& feats\n        ) const\n        {\n            feats.clear();\n            using namespace impl;\n            matrix<float,0,1> current_shape = initial_shape;\n            std::vector<float> feature_pixel_values;\n            unsigned long feat_offset = 0;\n            for (unsigned long iter = 0; iter < forests.size(); ++iter)\n            {\n                extract_feature_pixel_values(img, rect, current_shape, initial_shape,\n                                             anchor_idx[iter], deltas[iter], feature_pixel_values);\n                // evaluate all the trees at this level of the cascade.\n                for (unsigned long i = 0; i < forests[iter].size(); ++i)\n                {\n                    unsigned long leaf_idx;\n                    current_shape += forests[iter][i](feature_pixel_values, leaf_idx);\n\n                    feats.push_back(std::make_pair(feat_offset+leaf_idx, 1));\n                    feat_offset += forests[iter][i].num_leaves();\n                }\n            }\n\n            // convert the current_shape into a full_object_detection\n            const point_transform_affine tform_to_img = unnormalizing_tform(rect);\n            std::vector<point> parts(current_shape.size()/2);\n            for (unsigned long i = 0; i < parts.size(); ++i)\n                parts[i] = tform_to_img(location(current_shape, i));\n            return full_object_detection(rect, parts);\n        }\n\n        friend void serialize (const shape_predictor& item, std::ostream& out);\n\n        friend void deserialize (shape_predictor& item, std::istream& in);\n\n    private:\n        matrix<float,0,1> initial_shape;\n        std::vector<std::vector<impl::regression_tree> > forests;\n        std::vector<std::vector<unsigned long> > anchor_idx; \n        std::vector<std::vector<dlib::vector<float,2> > > deltas;\n    };\n\n    inline void serialize (const shape_predictor& item, std::ostream& out)\n    {\n        int version = 1;\n        dlib::serialize(version, out);\n        dlib::serialize(item.initial_shape, out);\n        dlib::serialize(item.forests, out);\n        dlib::serialize(item.anchor_idx, out);\n        dlib::serialize(item.deltas, out);\n    }\n\n    inline void deserialize (shape_predictor& item, std::istream& in)\n    {\n        int version = 0;\n        dlib::deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::shape_predictor.\");\n        dlib::deserialize(item.initial_shape, in);\n        dlib::deserialize(item.forests, in);\n        dlib::deserialize(item.anchor_idx, in);\n        dlib::deserialize(item.deltas, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array\n        >\n    double test_shape_predictor (\n        const shape_predictor& sp,\n        const image_array& images,\n        const std::vector<std::vector<full_object_detection> >& objects,\n        const std::vector<std::vector<double> >& scales\n    )\n    {\n        // make sure requires clause is not broken\n#ifdef ENABLE_ASSERTS\n        DLIB_CASSERT( images.size() == objects.size() ,\n            \"\\t double test_shape_predictor()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t images.size():  \" << images.size() \n            << \"\\n\\t objects.size(): \" << objects.size() \n        );\n        for (unsigned long i = 0; i < objects.size(); ++i)\n        {\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                DLIB_CASSERT(objects[i][j].num_parts() == sp.num_parts(), \n                    \"\\t double test_shape_predictor()\"\n                    << \"\\n\\t Invalid inputs were given to this function. \"\n                    << \"\\n\\t objects[\"<<i<<\"][\"<<j<<\"].num_parts(): \" << objects[i][j].num_parts()\n                    << \"\\n\\t sp.num_parts(): \" << sp.num_parts()\n                );\n            }\n            if (scales.size() != 0)\n            {\n                DLIB_CASSERT(objects[i].size() == scales[i].size(), \n                    \"\\t double test_shape_predictor()\"\n                    << \"\\n\\t Invalid inputs were given to this function. \"\n                    << \"\\n\\t objects[\"<<i<<\"].size(): \" << objects[i].size()\n                    << \"\\n\\t scales[\"<<i<<\"].size(): \" << scales[i].size()\n                );\n\n            }\n        }\n#endif\n\n        running_stats<double> rs;\n        for (unsigned long i = 0; i < objects.size(); ++i)\n        {\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                // Just use a scale of 1 (i.e. no scale at all) if the caller didn't supply\n                // any scales.\n                const double scale = scales.size()==0 ? 1 : scales[i][j]; \n\n                full_object_detection det = sp(images[i], objects[i][j].get_rect());\n\n                for (unsigned long k = 0; k < det.num_parts(); ++k)\n                {\n                    if (objects[i][j].part(k) != OBJECT_PART_NOT_PRESENT)\n                    {\n                        double score = length(det.part(k) - objects[i][j].part(k))/scale;\n                        rs.add(score);\n                    }\n                }\n            }\n        }\n        return rs.mean();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array\n        >\n    double test_shape_predictor (\n        const shape_predictor& sp,\n        const image_array& images,\n        const std::vector<std::vector<full_object_detection> >& objects\n    )\n    {\n        std::vector<std::vector<double> > no_scales;\n        return test_shape_predictor(sp, images, objects, no_scales);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SHAPE_PREDICToR_H_\n\n"
  },
  {
    "path": "dlib/image_processing/shape_predictor_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SHAPE_PREDICToR_ABSTRACT_H_\n#ifdef DLIB_SHAPE_PREDICToR_ABSTRACT_H_\n\n#include \"full_object_detection_abstract.h\"\n#include \"../matrix.h\"\n#include \"../geometry.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class shape_predictor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool that takes in an image region containing some object\n                and outputs a set of point locations that define the pose of the object.\n                The classic example of this is human face pose prediction, where you take\n                an image of a human face as input and are expected to identify the\n                locations of important facial landmarks such as the corners of the mouth\n                and eyes, tip of the nose, and so forth.\n\n                To create useful instantiations of this object you need to use the\n                shape_predictor_trainer object defined in the\n                shape_predictor_trainer_abstract.h file to train a shape_predictor using a\n                set of training images, each annotated with shapes you want to predict.\n\n            THREAD SAFETY\n                No synchronization is required when using this object.  In particular, a\n                single instance of this object can be used from multiple threads at the\n                same time.  \n        !*/\n\n    public:\n\n        shape_predictor (\n        );\n        /*!\n            ensures\n                - #num_parts() == 0\n                - #num_features() == 0\n        !*/\n\n        unsigned long num_parts (\n        ) const;\n        /*!\n            ensures\n                - returns the number of parts in the shapes predicted by this object.\n        !*/\n\n        unsigned long num_features (\n        ) const;\n        /*!\n            ensures\n                - Returns the dimensionality of the feature vector output by operator().\n                  This number is the total number of trees in this object times the number\n                  of leaves on each tree.  \n        !*/\n\n        template <typename image_type, typename T, typename U>\n        full_object_detection operator()(\n            const image_type& img,\n            const rectangle& rect,\n            std::vector<std::pair<T,U> >& feats\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - T is some unsigned integral type (e.g. unsigned int).\n                - U is any scalar type capable of storing the value 1 (e.g. float).\n            ensures\n                - Runs the shape prediction algorithm on the part of the image contained in\n                  the given bounding rectangle.  So it will try and fit the shape model to\n                  the contents of the given rectangle in the image.  For example, if there\n                  is a human face inside the rectangle and you use a face landmarking shape\n                  model then this function will return the locations of the face landmarks\n                  as the parts.  So the return value is a full_object_detection DET such\n                  that:\n                    - DET.get_rect() == rect\n                    - DET.num_parts() == num_parts()\n                    - for all valid i:\n                        - DET.part(i) == the location in img for the i-th part of the shape\n                          predicted by this object.\n                - #feats == a sparse vector that records which leaf each tree used to make\n                  the shape prediction.   Moreover, it is an indicator vector, Therefore,\n                  for all valid i:\n                    - #feats[i].second == 1\n                  Further, #feats is a vector from the space of num_features() dimensional\n                  vectors.  The output shape positions can be represented as the dot\n                  product between #feats and a weight vector.  Therefore, #feats encodes\n                  all the information from img that was used to predict the returned shape\n                  object.\n        !*/\n\n        template <typename image_type>\n        full_object_detection operator()(\n            const image_type& img,\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - Calling this function is equivalent to calling (*this)(img, rect, ignored)\n                  where the 3d argument is discarded.\n        !*/\n\n    };\n\n    void serialize (const shape_predictor& item, std::ostream& out);\n    void deserialize (shape_predictor& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array\n        >\n    double test_shape_predictor (\n        const shape_predictor& sp,\n        const image_array& images,\n        const std::vector<std::vector<full_object_detection> >& objects,\n        const std::vector<std::vector<double> >& scales\n    );\n    /*!\n        requires\n            - image_array is a dlib::array of image objects where each image object\n              implements the interface defined in dlib/image_processing/generic_image.h \n            - images.size() == objects.size()\n            - for all valid i and j:\n                - objects[i][j].num_parts() == sp.num_parts()\n            - if (scales.size() != 0) then\n                - There must be a scale value for each full_object_detection in objects.\n                  That is, it must be the case that:\n                    - scales.size() == objects.size()\n                    - for all valid i:\n                        - scales[i].size() == objects[i].size()\n        ensures\n            - Tests the given shape_predictor by running it on each of the given objects and\n              checking how well it recovers the part positions.  In particular, for all \n              valid i and j we perform:\n                sp(images[i], objects[i][j].get_rect())\n              and compare the result with the truth part positions in objects[i][j].  We\n              then return the average distance (measured in pixels) between a predicted\n              part location and its true position.  \n            - Note that any parts in objects that are set to OBJECT_PART_NOT_PRESENT are\n              simply ignored.\n            - if (scales.size() != 0) then\n                - Each time we compute the distance between a predicted part location and\n                  its true location in objects[i][j] we divide the distance by\n                  scales[i][j].  Therefore, if you want the reported error to be the\n                  average pixel distance then give an empty scales vector, but if you want\n                  the returned value to be something else like the average distance\n                  normalized by some feature of each object (e.g. the interocular distance)\n                  then you can supply those normalizing values via scales.\n    !*/\n\n    template <\n        typename image_array\n        >\n    double test_shape_predictor (\n        const shape_predictor& sp,\n        const image_array& images,\n        const std::vector<std::vector<full_object_detection> >& objects\n    );\n    /*!\n        requires\n            - image_array is a dlib::array of image objects where each image object\n              implements the interface defined in dlib/image_processing/generic_image.h \n            - images.size() == objects.size()\n            - for all valid i and j:\n                - objects[i][j].num_parts() == sp.num_parts()\n        ensures\n            - returns test_shape_predictor(sp, images, objects, no_scales) where no_scales\n              is an empty vector.  So this is just a convenience function for calling the\n              above test_shape_predictor() routine without a scales argument.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SHAPE_PREDICToR_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/image_processing/shape_predictor_trainer.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SHAPE_PREDICToR_TRAINER_H_\n#define DLIB_SHAPE_PREDICToR_TRAINER_H_\n\n#include \"shape_predictor_trainer_abstract.h\"\n#include \"shape_predictor.h\"\n#include \"../console_progress_indicator.h\"\n#include \"../threads.h\"\n#include \"../data_io/image_dataset_metadata.h\"\n#include \"box_overlap_testing.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class shape_predictor_trainer\n    {\n        /*!\n            This thing really only works with unsigned char or rgb_pixel images (since we assume the threshold \n            should be in the range [-128,128]).\n        !*/\n    public:\n\n        enum padding_mode_t\n        {\n            bounding_box_relative,\n            landmark_relative \n        };\n\n        shape_predictor_trainer (\n        )\n        {\n            _cascade_depth = 10;\n            _tree_depth = 4;\n            _num_trees_per_cascade_level = 500;\n            _nu = 0.1;\n            _oversampling_amount = 20;\n            _oversampling_translation_jitter = 0;\n            _feature_pool_size = 400;\n            _lambda = 0.1;\n            _num_test_splits = 20;\n            _feature_pool_region_padding = 0;\n            _verbose = false;\n            _num_threads = 0;\n            _padding_mode = landmark_relative;\n        }\n\n        unsigned long get_cascade_depth (\n        ) const { return _cascade_depth; }\n\n        void set_cascade_depth (\n            unsigned long depth\n        )\n        {\n            DLIB_CASSERT(depth > 0, \n                \"\\t void shape_predictor_trainer::set_cascade_depth()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t depth:  \" << depth\n            );\n\n            _cascade_depth = depth;\n        }\n\n        unsigned long get_tree_depth (\n        ) const { return _tree_depth; }\n\n        void set_tree_depth (\n            unsigned long depth\n        )\n        {\n            DLIB_CASSERT(depth > 0, \n                \"\\t void shape_predictor_trainer::set_tree_depth()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t depth:  \" << depth\n            );\n\n            _tree_depth = depth;\n        }\n\n        unsigned long get_num_trees_per_cascade_level (\n        ) const { return _num_trees_per_cascade_level; }\n\n        void set_num_trees_per_cascade_level (\n            unsigned long num\n        )\n        {\n            DLIB_CASSERT( num > 0,\n                \"\\t void shape_predictor_trainer::set_num_trees_per_cascade_level()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t num:  \" << num\n            );\n            _num_trees_per_cascade_level = num;\n        }\n\n        double get_nu (\n        ) const { return _nu; } \n        void set_nu (\n            double nu\n        )\n        {\n            DLIB_CASSERT(0 < nu && nu <= 1,\n                \"\\t void shape_predictor_trainer::set_nu()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t nu:  \" << nu \n            );\n\n            _nu = nu;\n        }\n\n        std::string get_random_seed (\n        ) const { return rnd.get_seed(); }\n        void set_random_seed (\n            const std::string& seed\n        ) { rnd.set_seed(seed); }\n\n        unsigned long get_oversampling_amount (\n        ) const { return _oversampling_amount; }\n\n        void set_oversampling_amount (\n            unsigned long amount\n        )\n        {\n            DLIB_CASSERT(amount > 0, \n                \"\\t void shape_predictor_trainer::set_oversampling_amount()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t amount: \" << amount \n            );\n\n            _oversampling_amount = amount;\n        }\n\n        double get_oversampling_translation_jitter (\n        ) const { return _oversampling_translation_jitter; }\n\n        void set_oversampling_translation_jitter (\n            double amount\n        )\n        {\n            DLIB_CASSERT(amount >= 0, \n                \"\\t void shape_predictor_trainer::set_oversampling_translation_jitter()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t amount: \" << amount \n            );\n\n            _oversampling_translation_jitter = amount;\n        }\n\n        unsigned long get_feature_pool_size (\n        ) const { return _feature_pool_size; }\n        void set_feature_pool_size (\n            unsigned long size\n        ) \n        {\n            DLIB_CASSERT(size > 1, \n                \"\\t void shape_predictor_trainer::set_feature_pool_size()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t size: \" << size \n            );\n\n            _feature_pool_size = size;\n        }\n\n        double get_lambda (\n        ) const { return _lambda; }\n        void set_lambda (\n            double lambda\n        )\n        {\n            DLIB_CASSERT(lambda > 0,\n                \"\\t void shape_predictor_trainer::set_lambda()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t lambda: \" << lambda \n            );\n\n            _lambda = lambda;\n        }\n\n        unsigned long get_num_test_splits (\n        ) const { return _num_test_splits; }\n        void set_num_test_splits (\n            unsigned long num\n        )\n        {\n            DLIB_CASSERT(num > 0, \n                \"\\t void shape_predictor_trainer::set_num_test_splits()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t num: \" << num \n            );\n\n            _num_test_splits = num;\n        }\n\n        void set_padding_mode (\n            padding_mode_t mode\n        )\n        {\n            _padding_mode = mode;\n        }\n\n        padding_mode_t get_padding_mode (\n        ) const { return _padding_mode; }\n\n        double get_feature_pool_region_padding (\n        ) const { return _feature_pool_region_padding; }\n        void set_feature_pool_region_padding (\n            double padding \n        )\n        {\n            DLIB_CASSERT(padding > -0.5,\n                \"\\t void shape_predictor_trainer::set_feature_pool_region_padding()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t padding: \" << padding \n            );\n\n            _feature_pool_region_padding = padding;\n        }\n\n        void be_verbose (\n        )\n        {\n            _verbose = true;\n        }\n\n        void be_quiet (\n        )\n        {\n            _verbose = false;\n        }\n\n        unsigned long get_num_threads (\n        ) const { return _num_threads; }\n        void set_num_threads (\n                unsigned long num\n        )\n        {\n            _num_threads = num;\n        }\n\n        template <typename image_array>\n        shape_predictor train (\n            const image_array& images,\n            const std::vector<std::vector<full_object_detection> >& objects\n        ) const\n        {\n            using namespace impl;\n            DLIB_CASSERT(images.size() == objects.size() && images.size() > 0,\n                \"\\t shape_predictor shape_predictor_trainer::train()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t images.size():  \" << images.size() \n                << \"\\n\\t objects.size(): \" << objects.size() \n            );\n            // make sure the objects agree on the number of parts and that there is at\n            // least one full_object_detection. \n            unsigned long num_parts = 0;\n            std::vector<int> part_present;\n            for (unsigned long i = 0; i < objects.size(); ++i)\n            {\n                for (unsigned long j = 0; j < objects[i].size(); ++j)\n                {\n                    if (num_parts == 0)\n                    {\n                        num_parts = objects[i][j].num_parts();\n                        DLIB_CASSERT(objects[i][j].num_parts() != 0,\n                            \"\\t shape_predictor shape_predictor_trainer::train()\"\n                            << \"\\n\\t You can't give objects that don't have any parts to the trainer.\"\n                        );\n                        part_present.resize(num_parts);\n                    }\n                    else\n                    {\n                        DLIB_CASSERT(objects[i][j].num_parts() == num_parts,\n                            \"\\t shape_predictor shape_predictor_trainer::train()\"\n                            << \"\\n\\t All the objects must agree on the number of parts. \"\n                            << \"\\n\\t objects[\"<<i<<\"][\"<<j<<\"].num_parts(): \" << objects[i][j].num_parts()\n                            << \"\\n\\t num_parts:  \" << num_parts \n                        );\n                    }\n                    for (unsigned long p = 0; p < objects[i][j].num_parts(); ++p)\n                    {\n                        if (objects[i][j].part(p) != OBJECT_PART_NOT_PRESENT)\n                            part_present[p] = 1;\n                    }\n                }\n            }\n            DLIB_CASSERT(num_parts != 0,\n                \"\\t shape_predictor shape_predictor_trainer::train()\"\n                << \"\\n\\t You must give at least one full_object_detection if you want to train a shape model and it must have parts.\"\n            );\n            DLIB_CASSERT(sum(mat(part_present)) == (long)num_parts,\n                \"\\t shape_predictor shape_predictor_trainer::train()\"\n                << \"\\n\\t Each part must appear at least once in this training data.  That is, \"\n                << \"\\n\\t you can't have a part that is always set to OBJECT_PART_NOT_PRESENT.\"\n            );\n\n            // creating thread pool. if num_threads <= 1, trainer should work in caller thread\n            thread_pool tp(_num_threads > 1 ? _num_threads : 0);\n\n            // determining the type of features used for this type of images\n            typedef typename std::remove_const<typename std::remove_reference<decltype(images[0])>::type>::type image_type;\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            typedef typename pixel_traits<pixel_type>::basic_pixel_type feature_type;\n\n            rnd.set_seed(get_random_seed());\n\n            std::vector<training_sample<feature_type>> samples;\n            const matrix<float,0,1> initial_shape = populate_training_sample_shapes(objects, samples);\n            const std::vector<std::vector<dlib::vector<float,2> > > pixel_coordinates = randomly_sample_pixel_coordinates(initial_shape);\n\n            unsigned long trees_fit_so_far = 0;\n            console_progress_indicator pbar(get_cascade_depth()*get_num_trees_per_cascade_level());\n            if (_verbose)\n                std::cout << \"Fitting trees...\" << std::endl;\n\n            std::vector<std::vector<impl::regression_tree> > forests(get_cascade_depth());\n            // Now start doing the actual training by filling in the forests\n            for (unsigned long cascade = 0; cascade < get_cascade_depth(); ++cascade)\n            {\n                // Each cascade uses a different set of pixels for its features.  We compute\n                // their representations relative to the initial shape first.\n                std::vector<unsigned long> anchor_idx; \n                std::vector<dlib::vector<float,2> > deltas;\n                create_shape_relative_encoding(initial_shape, pixel_coordinates[cascade], anchor_idx, deltas);\n\n                // First compute the feature_pixel_values for each training sample at this\n                // level of the cascade.\n                parallel_for(tp, 0, samples.size(), [&](unsigned long i)\n                {\n                    impl::extract_feature_pixel_values(images[samples[i].image_idx], samples[i].rect,\n                                                 samples[i].current_shape, initial_shape, anchor_idx,\n                                                 deltas, samples[i].feature_pixel_values);\n                }, 1);\n\n                // Now start building the trees at this cascade level.\n                for (unsigned long i = 0; i < get_num_trees_per_cascade_level(); ++i)\n                {\n                    forests[cascade].push_back(make_regression_tree(tp, samples, pixel_coordinates[cascade]));\n\n                    if (_verbose)\n                    {\n                        ++trees_fit_so_far;\n                        pbar.print_status(trees_fit_so_far);\n                    }\n                }\n            }\n\n            if (_verbose)\n                std::cout << \"\\nTraining complete\" << std::endl;\n\n            return shape_predictor(initial_shape, forests, pixel_coordinates);\n        }\n\n    private:\n\n        static void object_to_shape (\n            const full_object_detection& obj,\n            matrix<float,0,1>& shape,\n            matrix<float,0,1>& present // a mask telling which elements of #shape are present.\n        )\n        {\n            shape.set_size(obj.num_parts()*2);\n            present.set_size(obj.num_parts()*2);\n            const point_transform_affine tform_from_img = impl::normalizing_tform(obj.get_rect());\n            for (unsigned long i = 0; i < obj.num_parts(); ++i)\n            {\n                if (obj.part(i) != OBJECT_PART_NOT_PRESENT)\n                {\n                    vector<float,2> p = tform_from_img(obj.part(i));\n                    shape(2*i)   = p.x();\n                    shape(2*i+1) = p.y();\n                    present(2*i)   = 1;\n                    present(2*i+1) = 1;\n\n                    if (length(p) > 100)\n                    {\n                        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;\n                    }\n                }\n                else\n                {\n                    shape(2*i)   = 0;\n                    shape(2*i+1) = 0;\n                    present(2*i)   = 0;\n                    present(2*i+1) = 0;\n                }\n            }\n        }\n\n        template<typename feature_type>\n        struct training_sample\n        {\n            /*!\n\n            CONVENTION\n                - feature_pixel_values.size() == get_feature_pool_size()\n                - feature_pixel_values[j] == the value of the j-th feature pool\n                  pixel when you look it up relative to the shape in current_shape.\n\n                - target_shape == The truth shape.  Stays constant during the whole\n                  training process (except for the parts that are not present, those are\n                  always equal to the current_shape values).\n                - present == 0/1 mask saying which parts of target_shape are present.\n                - rect == the position of the object in the image_idx-th image.  All shape\n                  coordinates are coded relative to this rectangle.\n                - diff_shape == temporary value for holding difference between current\n                  shape and target shape\n            !*/\n\n            unsigned long image_idx;\n            rectangle rect;\n            matrix<float,0,1> target_shape;\n            matrix<float,0,1> present;\n\n            matrix<float,0,1> current_shape;\n            matrix<float,0,1> diff_shape;\n            std::vector<feature_type> feature_pixel_values;\n\n            void swap(training_sample& item)\n            {\n                std::swap(image_idx, item.image_idx);\n                std::swap(rect, item.rect);\n                target_shape.swap(item.target_shape);\n                present.swap(item.present);\n                current_shape.swap(item.current_shape);\n                diff_shape.swap(item.diff_shape);\n                feature_pixel_values.swap(item.feature_pixel_values);\n            }\n        };\n\n        template<typename feature_type>\n        impl::regression_tree make_regression_tree (\n            thread_pool& tp,\n            std::vector<training_sample<feature_type>>& samples,\n            const std::vector<dlib::vector<float,2> >& pixel_coordinates\n        ) const\n        {\n            using namespace impl;\n            std::deque<std::pair<unsigned long, unsigned long> > parts;\n            parts.push_back(std::make_pair(0, (unsigned long)samples.size()));\n\n            impl::regression_tree tree;\n\n            // walk the tree in breadth first order\n            const unsigned long num_split_nodes = static_cast<unsigned long>(std::pow(2.0, (double)get_tree_depth())-1);\n            std::vector<matrix<float,0,1> > sums(num_split_nodes*2+1);\n            if (tp.num_threads_in_pool() > 1)\n            {\n                // Here we need to calculate shape differences and store sum of differences into sums[0]\n                // to make it. I am splitting samples into blocks, each block will be processed by\n                // separate thread, and the sum of differences of each block is stored into separate\n                // place in block_sums\n\n                const unsigned long num_workers = std::max(1UL, tp.num_threads_in_pool());\n                const unsigned long num =  samples.size();\n                const unsigned long block_size = std::max(1UL, (num + num_workers - 1) / num_workers);\n                std::vector<matrix<float,0,1> > block_sums(num_workers);\n\n                parallel_for(tp, 0, num_workers, [&](unsigned long block)\n                {\n                    const unsigned long block_begin = block * block_size;\n                    const unsigned long block_end =  std::min(num, block_begin + block_size);\n                    for (unsigned long i = block_begin; i < block_end; ++i)\n                    {\n                        samples[i].diff_shape = samples[i].target_shape - samples[i].current_shape;\n                        block_sums[block] += samples[i].diff_shape;\n                    }\n                }, 1);\n\n                // now calculate the total result from separate blocks\n                for (unsigned long i = 0; i < block_sums.size(); ++i)\n                    sums[0] += block_sums[i];\n            }\n            else\n            {\n                // synchronous implementation\n                for (unsigned long i = 0; i < samples.size(); ++i)\n                {\n                    samples[i].diff_shape = samples[i].target_shape - samples[i].current_shape;\n                    sums[0] += samples[i].diff_shape;\n                }\n            }\n\n            for (unsigned long i = 0; i < num_split_nodes; ++i)\n            {\n                std::pair<unsigned long,unsigned long> range = parts.front();\n                parts.pop_front();\n\n                const impl::split_feature split = generate_split(tp, samples, range.first,\n                    range.second, pixel_coordinates, sums[i], sums[left_child(i)],\n                    sums[right_child(i)]);\n                tree.splits.push_back(split);\n                const unsigned long mid = partition_samples(split, samples, range.first, range.second);\n\n                parts.push_back(std::make_pair(range.first, mid));\n                parts.push_back(std::make_pair(mid, range.second));\n            }\n\n            // Now all the parts contain the ranges for the leaves so we can use them to\n            // compute the average leaf values.\n            matrix<float,0,1> present_counts(samples[0].target_shape.size());\n            tree.leaf_values.resize(parts.size());\n            for (unsigned long i = 0; i < parts.size(); ++i)\n            {\n                // Get the present counts for each dimension so we can divide each\n                // dimension by the number of observations we have on it to find the mean\n                // displacement in each leaf.\n                present_counts = 0;\n                for (unsigned long j = parts[i].first; j < parts[i].second; ++j)\n                    present_counts += samples[j].present;\n                present_counts = dlib::reciprocal(present_counts);\n\n                if (parts[i].second != parts[i].first)\n                    tree.leaf_values[i] = pointwise_multiply(present_counts,sums[num_split_nodes+i]*get_nu());\n                else\n                    tree.leaf_values[i] = zeros_matrix(samples[0].target_shape);\n\n                // now adjust the current shape based on these predictions\n                parallel_for(tp, parts[i].first, parts[i].second, [&](unsigned long j)\n                {\n                    samples[j].current_shape += tree.leaf_values[i];\n                    // For parts that aren't present in the training data, we just make\n                    // sure that the target shape always matches and therefore gives zero\n                    // error.  So this makes the algorithm simply ignore non-present\n                    // landmarks.\n                    for (long k = 0; k < samples[j].present.size(); ++k)\n                    {\n                        // if this part is not present\n                        if (samples[j].present(k) == 0)\n                            samples[j].target_shape(k) = samples[j].current_shape(k);\n                    }\n                }, 1);\n            }\n\n            return tree;\n        }\n\n        impl::split_feature randomly_generate_split_feature (\n            const std::vector<dlib::vector<float,2> >& pixel_coordinates\n        ) const\n        {\n            const double lambda = get_lambda(); \n            impl::split_feature feat;\n            const size_t max_iters = get_feature_pool_size()*get_feature_pool_size();\n            for (size_t i = 0; i < max_iters; ++i)\n            {\n                feat.idx1   = rnd.get_integer(get_feature_pool_size());\n                feat.idx2   = rnd.get_integer(get_feature_pool_size());\n                while (feat.idx1 == feat.idx2)\n                    feat.idx2   = rnd.get_integer(get_feature_pool_size());\n                const double dist = length(pixel_coordinates[feat.idx1]-pixel_coordinates[feat.idx2]);\n                const double accept_prob = std::exp(-dist/lambda);\n                if (accept_prob > rnd.get_random_double())\n                    break;\n            }\n\n            feat.thresh = (rnd.get_random_double()*256 - 128)/2.0;\n\n            return feat;\n        }\n\n        template<typename feature_type>\n        impl::split_feature generate_split (\n            thread_pool& tp,\n            const std::vector<training_sample<feature_type>>& samples,\n            unsigned long begin,\n            unsigned long end,\n            const std::vector<dlib::vector<float,2> >& pixel_coordinates,\n            const matrix<float,0,1>& sum,\n            matrix<float,0,1>& left_sum,\n            matrix<float,0,1>& right_sum \n        ) const\n        {\n            // generate a bunch of random splits and test them and return the best one.\n\n            const unsigned long num_test_splits = get_num_test_splits();  \n\n            // sample the random features we test in this function\n            std::vector<impl::split_feature> feats;\n            feats.reserve(num_test_splits);\n            for (unsigned long i = 0; i < num_test_splits; ++i)\n                feats.push_back(randomly_generate_split_feature(pixel_coordinates));\n\n            std::vector<matrix<float,0,1> > left_sums(num_test_splits);\n            std::vector<unsigned long> left_cnt(num_test_splits);\n\n            const unsigned long num_workers = std::max(1UL, tp.num_threads_in_pool());\n            const unsigned long block_size = std::max(1UL, (num_test_splits + num_workers - 1) / num_workers);\n\n            // now compute the sums of vectors that go left for each feature\n            parallel_for(tp, 0, num_workers, [&](unsigned long block)\n            {\n                const unsigned long block_begin = block * block_size;\n                const unsigned long block_end   = std::min(block_begin + block_size, num_test_splits);\n\n                for (unsigned long j = begin; j < end; ++j)\n                {\n                    for (unsigned long i = block_begin; i < block_end; ++i)\n                    {\n                        if ((float)samples[j].feature_pixel_values[feats[i].idx1] - (float)samples[j].feature_pixel_values[feats[i].idx2] > feats[i].thresh)\n                        {\n                            left_sums[i] += samples[j].diff_shape;\n                            ++left_cnt[i];\n                        }\n                    }\n                }\n\n            }, 1);\n\n            // now figure out which feature is the best\n            double best_score = -1;\n            unsigned long best_feat = 0;\n            matrix<float,0,1> temp;\n            for (unsigned long i = 0; i < num_test_splits; ++i)\n            {\n                // check how well the feature splits the space.\n                double score = 0;\n                unsigned long right_cnt = end-begin-left_cnt[i];\n                if (left_cnt[i] != 0 && right_cnt != 0)\n                {\n                    temp = sum - left_sums[i];\n                    score = dot(left_sums[i],left_sums[i])/left_cnt[i] + dot(temp,temp)/right_cnt;\n                    if (score > best_score)\n                    {\n                        best_score = score;\n                        best_feat = i;\n                    }\n                }\n            }\n\n            left_sums[best_feat].swap(left_sum);\n            if (left_sum.size() != 0)\n            {\n                right_sum = sum - left_sum;\n            }\n            else\n            {\n                right_sum = sum;\n                left_sum = zeros_matrix(sum);\n            }\n            return feats[best_feat];\n        }\n\n        template<typename feature_type>\n        unsigned long partition_samples (\n            const impl::split_feature& split,\n            std::vector<training_sample<feature_type>>& samples,\n            unsigned long begin,\n            unsigned long end\n        ) const\n        {\n            // splits samples based on split (sorta like in quick sort) and returns the mid\n            // point.  make sure you return the mid in a way compatible with how we walk\n            // through the tree.\n\n            unsigned long i = begin;\n            for (unsigned long j = begin; j < end; ++j)\n            {\n                if ((float)samples[j].feature_pixel_values[split.idx1] - (float)samples[j].feature_pixel_values[split.idx2] > split.thresh)\n                {\n                    samples[i].swap(samples[j]);\n                    ++i;\n                }\n            }\n            return i;\n        }\n\n\n\n        template<typename feature_type>\n        matrix<float,0,1> populate_training_sample_shapes(\n            const std::vector<std::vector<full_object_detection> >& objects,\n            std::vector<training_sample<feature_type>>& samples\n        ) const\n        {\n            samples.clear();\n            matrix<float,0,1> mean_shape;\n            matrix<float,0,1> count;\n            // first fill out the target shapes\n            for (unsigned long i = 0; i < objects.size(); ++i)\n            {\n                for (unsigned long j = 0; j < objects[i].size(); ++j)\n                {\n                    training_sample<feature_type> sample;\n                    sample.image_idx = i;\n                    sample.rect = objects[i][j].get_rect();\n                    object_to_shape(objects[i][j], sample.target_shape, sample.present);\n                    for (unsigned long itr = 0; itr < get_oversampling_amount(); ++itr)\n                        samples.push_back(sample);\n                    mean_shape += sample.target_shape;\n                    count += sample.present;\n                }\n            }\n\n            mean_shape = pointwise_multiply(mean_shape,reciprocal(count));\n\n            // now go pick random initial shapes\n            for (unsigned long i = 0; i < samples.size(); ++i)\n            {\n                if ((i%get_oversampling_amount()) == 0)\n                {\n                    // The mean shape is what we really use as an initial shape so always\n                    // include it in the training set as an example starting shape.\n                    samples[i].current_shape = mean_shape;\n                }\n                else\n                {\n                    samples[i].current_shape.set_size(0);\n\n                    matrix<float,0,1> hits(mean_shape.size());\n                    hits = 0;\n\n                    int iter = 0;\n                    // Pick a few samples at random and randomly average them together to\n                    // make the initial shape.  Note that we make sure we get at least one\n                    // observation (i.e. non-OBJECT_PART_NOT_PRESENT) on each part\n                    // location.\n                    while(min(hits) == 0 || iter < 2)\n                    {\n                        ++iter;\n                        const unsigned long rand_idx = rnd.get_random_32bit_number()%samples.size();\n                        const double alpha = rnd.get_random_double()+0.1;\n                        samples[i].current_shape += alpha*samples[rand_idx].target_shape;\n                        hits += alpha*samples[rand_idx].present;\n                    }\n                    samples[i].current_shape = pointwise_multiply(samples[i].current_shape, reciprocal(hits));\n\n                    if (_oversampling_translation_jitter != 0)\n                    {\n                        dpoint off;\n                        off.x() = rnd.get_double_in_range(-_oversampling_translation_jitter,_oversampling_translation_jitter);\n                        off.y() = rnd.get_double_in_range(-_oversampling_translation_jitter,_oversampling_translation_jitter);\n                        for (long j = 0; j < samples[i].current_shape.size()/2; ++j)\n                        {\n                            samples[i].current_shape(2*j) += off.x();\n                            samples[i].current_shape(2*j+1) += off.y();\n                        }\n                    }\n                }\n\n            }\n            for (unsigned long i = 0; i < samples.size(); ++i)\n            {\n                for (long k = 0; k < samples[i].present.size(); ++k)\n                {\n                    // if this part is not present\n                    if (samples[i].present(k) == 0)\n                        samples[i].target_shape(k) = samples[i].current_shape(k);\n                }\n            }\n\n\n            return mean_shape;\n        }\n\n\n        void randomly_sample_pixel_coordinates (\n            std::vector<dlib::vector<float,2> >& pixel_coordinates,\n            const double min_x,\n            const double min_y,\n            const double max_x,\n            const double max_y\n        ) const\n        /*!\n            ensures\n                - #pixel_coordinates.size() == get_feature_pool_size() \n                - for all valid i:\n                    - pixel_coordinates[i] == a point in the box defined by the min/max x/y arguments.\n        !*/\n        {\n            pixel_coordinates.resize(get_feature_pool_size());\n            for (unsigned long i = 0; i < get_feature_pool_size(); ++i)\n            {\n                pixel_coordinates[i].x() = rnd.get_random_double()*(max_x-min_x) + min_x;\n                pixel_coordinates[i].y() = rnd.get_random_double()*(max_y-min_y) + min_y;\n            }\n        }\n\n        std::vector<std::vector<dlib::vector<float,2> > > randomly_sample_pixel_coordinates (\n            const matrix<float,0,1>& initial_shape\n        ) const\n        {\n            const double padding = get_feature_pool_region_padding();\n            // Figure out the bounds on the object shapes.  We will sample uniformly\n            // from this box.\n            matrix<float> temp = reshape(initial_shape, initial_shape.size()/2, 2);\n            double min_x = min(colm(temp,0));\n            double min_y = min(colm(temp,1));\n            double max_x = max(colm(temp,0));\n            double max_y = max(colm(temp,1));\n\n            if (get_padding_mode() == bounding_box_relative)\n            {\n                min_x = std::min(0.0, min_x);\n                min_y = std::min(0.0, min_y);\n                max_x = std::max(1.0, max_x);\n                max_y = std::max(1.0, max_y);\n            }\n\n            min_x -= padding;\n            min_y -= padding;\n            max_x += padding;\n            max_y += padding;\n\n            std::vector<std::vector<dlib::vector<float,2> > > pixel_coordinates;\n            pixel_coordinates.resize(get_cascade_depth());\n            for (unsigned long i = 0; i < get_cascade_depth(); ++i)\n                randomly_sample_pixel_coordinates(pixel_coordinates[i], min_x, min_y, max_x, max_y);\n            return pixel_coordinates;\n        }\n\n\n\n        mutable dlib::rand rnd;\n\n        unsigned long _cascade_depth;\n        unsigned long _tree_depth;\n        unsigned long _num_trees_per_cascade_level;\n        double _nu;\n        unsigned long _oversampling_amount;\n        unsigned long _feature_pool_size;\n        double _lambda;\n        unsigned long _num_test_splits;\n        double _feature_pool_region_padding;\n        bool _verbose;\n        unsigned long _num_threads;\n        padding_mode_t _padding_mode;\n        double _oversampling_translation_jitter;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename some_type_of_rectangle\n        >\n    image_dataset_metadata::dataset make_bounding_box_regression_training_data (\n        const image_dataset_metadata::dataset& truth,\n        const std::vector<std::vector<some_type_of_rectangle>>& detections\n    )\n    {\n        DLIB_CASSERT(truth.images.size() == detections.size(), \n            \"truth.images.size(): \"<< truth.images.size() <<\n            \"\\tdetections.size(): \"<< detections.size()\n        );\n        image_dataset_metadata::dataset result = truth;\n\n        for (size_t i = 0; i < truth.images.size(); ++i)\n        {\n            result.images[i].boxes.clear();\n            for (auto truth_box : truth.images[i].boxes)\n            {\n                if (truth_box.ignore)\n                    continue;\n\n                // Find the detection that best matches the current truth_box.\n                auto det = max_scoring_element(detections[i], [&truth_box](const rectangle& r) { return box_intersection_over_union(r, truth_box.rect); });\n                if (det.second > 0.5)\n                {\n                    // Remove any existing parts and replace them with the truth_box corners.\n                    truth_box.parts.clear();\n                    auto b = truth_box.rect;\n                    truth_box.parts[\"left\"]     = (b.tl_corner()+b.bl_corner())/2;\n                    truth_box.parts[\"right\"]    = (b.tr_corner()+b.br_corner())/2;\n                    truth_box.parts[\"top\"]      = (b.tl_corner()+b.tr_corner())/2;\n                    truth_box.parts[\"bottom\"]   = (b.bl_corner()+b.br_corner())/2;\n                    truth_box.parts[\"middle\"]   = center(b);\n\n                    // Now replace the bounding truth_box with the detector's bounding truth_box.\n                    truth_box.rect = det.first;\n\n                    result.images[i].boxes.push_back(truth_box);\n                }\n            }\n        }\n        return result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SHAPE_PREDICToR_TRAINER_H_\n\n"
  },
  {
    "path": "dlib/image_processing/shape_predictor_trainer_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_\n#ifdef DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_\n\n#include \"shape_predictor_abstract.h\"\n#include \"../data_io/image_dataset_metadata.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class shape_predictor_trainer\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for training shape_predictors based on annotated training\n                images.  Its implementation uses the algorithm described in:\n                    One Millisecond Face Alignment with an Ensemble of Regression Trees\n                    by Vahid Kazemi and Josephine Sullivan, CVPR 2014\n\n        !*/\n\n    public:\n\n        shape_predictor_trainer (\n        );\n        /*!\n            ensures\n                - #get_cascade_depth() == 10\n                - #get_tree_depth() == 4\n                - #get_num_trees_per_cascade_level() == 500\n                - #get_nu() == 0.1\n                - #get_oversampling_amount() == 20\n                - #get_oversampling_translation_jitter() == 0\n                - #get_feature_pool_size() == 400\n                - #get_lambda() == 0.1\n                - #get_num_test_splits() == 20\n                - #get_feature_pool_region_padding() == 0\n                - #get_random_seed() == \"\"\n                - #get_num_threads() == 0\n                - #get_padding_mode() == landmark_relative \n                - This object will not be verbose\n        !*/\n\n        unsigned long get_cascade_depth (\n        ) const;\n        /*!\n            ensures\n                - returns the number of cascades created when you train a model.  This\n                  means that the total number of trees in the learned model is equal to\n                  get_cascade_depth()*get_num_trees_per_cascade_level().\n        !*/\n\n        void set_cascade_depth (\n            unsigned long depth\n        );\n        /*!\n            requires\n                - depth > 0\n            ensures\n                - #get_cascade_depth() == depth\n        !*/\n\n        unsigned long get_tree_depth (\n        ) const; \n        /*!\n            ensures\n                - returns the depth of the trees used in the cascade.  In particular, there\n                  are pow(2,get_tree_depth()) leaves in each tree.\n        !*/\n\n        void set_tree_depth (\n            unsigned long depth\n        );\n        /*!\n            requires\n                - depth > 0\n            ensures\n                - #get_tree_depth() == depth\n        !*/\n\n        unsigned long get_num_trees_per_cascade_level (\n        ) const;\n        /*!\n            ensures\n                - returns the number of trees created for each cascade.  This means that\n                  the total number of trees in the learned model is equal to\n                  get_cascade_depth()*get_num_trees_per_cascade_level().  \n        !*/\n\n        void set_num_trees_per_cascade_level (\n            unsigned long num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_num_trees_per_cascade_level() == num\n        !*/\n\n        double get_nu (\n        ) const; \n        /*!\n            ensures\n                - returns the regularization parameter.  Larger values of this parameter\n                  will cause the algorithm to fit the training data better but may also\n                  cause overfitting.\n        !*/\n\n        void set_nu (\n            double nu\n        );\n        /*!\n            requires\n                - 0 < nu <= 1\n            ensures\n                - #get_nu() == nu\n        !*/\n\n        std::string get_random_seed (\n        ) const;\n        /*!\n            ensures\n                - returns the random seed used by the internal random number generator.\n                  Since this algorithm is a random forest style algorithm it relies on a\n                  random number generator for generating the trees.  So each setting of the\n                  random seed will produce slightly different outputs.  \n        !*/\n\n        void set_random_seed (\n            const std::string& seed\n        );\n        /*!\n            ensures\n                - #get_random_seed() == seed\n        !*/\n\n        unsigned long get_oversampling_amount (\n        ) const;\n        /*!\n            ensures\n                - You give annotated images to this object as training examples.  You\n                  can effectively increase the amount of training data by adding in each\n                  training example multiple times but with a randomly selected deformation\n                  applied to it.  That is what this parameter controls.  That is, if you\n                  supply N training samples to train() then the algorithm runs internally\n                  with N*get_oversampling_amount() training samples.  So the bigger this\n                  parameter the better (excepting that larger values make training take\n                  longer).  In terms of the Kazemi paper, this parameter is the number of\n                  randomly selected initial starting points sampled for each training\n                  example.\n        !*/\n\n        void set_oversampling_amount (\n            unsigned long amount\n        );\n        /*!\n            requires\n                - amount > 0\n            ensures\n                - #get_oversampling_amount() == amount\n        !*/\n\n        double get_oversampling_translation_jitter (\n        ) const; \n        /*!\n            ensures\n                - When generating the get_oversampling_amount() factor of extra training\n                  samples you can also jitter the bounding box by adding random small\n                  translational shifts.  You can tell the shape_predictor_trainer to do\n                  this by setting get_oversampling_translation_jitter() to some non-zero\n                  value.  For instance, if you set it to 0.1 then it would randomly\n                  translate the bounding boxes by between 0% and 10% their width and\n                  height in the x and y directions respectively.  Doing this is essentially\n                  equivalent to randomly jittering the bounding boxes in the training data\n                  (i.e. the boxes given by full_object_detection::get_rect()).  This is\n                  useful because the seed shape is determined by the bounding box position,\n                  so doing this kind of jittering can help make the learned model more\n                  robust against slightly misplaced bounding boxes.\n        !*/\n\n        void set_oversampling_translation_jitter (\n            double amount\n        );\n        /*!\n            requires\n                - amount >= 0\n            ensures\n                - #get_oversampling_translation_jitter() == amount\n        !*/\n\n        unsigned long get_feature_pool_size (\n        ) const;\n        /*!\n            ensures\n                - At each level of the cascade we randomly sample get_feature_pool_size()\n                  pixels from the image.  These pixels are used to generate features for\n                  the random trees.  So in general larger settings of this parameter give\n                  better accuracy but make the algorithm run slower.  \n        !*/\n\n        void set_feature_pool_size (\n            unsigned long size\n        );\n        /*!\n            requires\n                - size > 1\n            ensures\n                - #get_feature_pool_size() == size\n        !*/\n\n        enum padding_mode_t\n        {\n            bounding_box_relative,\n            landmark_relative \n        };\n\n        padding_mode_t get_padding_mode (\n        ) const; \n        /*!\n            ensures\n                - returns the current padding mode.  See get_feature_pool_region_padding()\n                  for a discussion of the modes.\n        !*/\n\n        void set_padding_mode (\n            padding_mode_t mode\n        );\n        /*!\n            ensures\n                - #get_padding_mode() == mode\n        !*/\n\n        double get_feature_pool_region_padding (\n        ) const; \n        /*!\n            ensures\n                - This algorithm works by comparing the relative intensity of pairs of\n                  pixels in the input image.  To decide which pixels to look at, the\n                  training algorithm randomly selects pixels from a box roughly centered\n                  around the object of interest.  We call this box the feature pool region\n                  box.  \n                  \n                  Each object of interest is defined by a full_object_detection, which\n                  contains a bounding box and a list of landmarks.  If\n                  get_padding_mode()==landmark_relative then the feature pool region box is\n                  the tightest box that contains the landmarks inside the\n                  full_object_detection.  In this mode the full_object_detection's bounding\n                  box is ignored.  Otherwise, if the padding mode is bounding_box_relative\n                  then the feature pool region box is the tightest box that contains BOTH\n                  the landmarks and the full_object_detection's bounding box.\n\n                  Additionally, you can adjust the size of the feature pool padding region\n                  by setting get_feature_pool_region_padding() to some value.  If\n                  get_feature_pool_region_padding()==0 then the feature pool region box is\n                  unmodified and defined exactly as stated above. However, you can expand\n                  the size of the box by setting the padding > 0 or shrink it by setting it\n                  to something < 0.\n\n                  To explain this precisely, for a padding of 0 we say that the pixels are\n                  sampled from a box of size 1x1.  The padding value is added to each side\n                  of the box.  So a padding of 0.5 would cause the algorithm to sample\n                  pixels from a box that was 2x2, effectively multiplying the area pixels\n                  are sampled from by 4.  Similarly, setting the padding to -0.2 would\n                  cause it to sample from a box 0.6x0.6 in size.\n        !*/\n\n        void set_feature_pool_region_padding (\n            double padding \n        );\n        /*!\n            requires\n                - padding > -0.5\n            ensures\n                - #get_feature_pool_region_padding() == padding\n        !*/\n\n        double get_lambda (\n        ) const;\n        /*!\n            ensures\n                - To decide how to split nodes in the regression trees the algorithm looks\n                  at pairs of pixels in the image.  These pixel pairs are sampled randomly\n                  but with a preference for selecting pixels that are near each other.\n                  get_lambda() controls this \"nearness\" preference.  In particular, smaller\n                  values of get_lambda() will make the algorithm prefer to select pixels\n                  close together and larger values of get_lambda() will make it care less\n                  about picking nearby pixel pairs.  \n\n                  Note that this is the inverse of how it is defined in the Kazemi paper.\n                  For this object, you should think of lambda as \"the fraction of the\n                  bounding box will we traverse to find a neighboring pixel\".  Nominally,\n                  this is normalized between 0 and 1.  So reasonable settings of lambda are\n                  values in the range 0 < lambda < 1.\n        !*/\n\n        void set_lambda (\n            double lambda\n        );\n        /*!\n            requires\n                - lambda > 0\n            ensures\n                - #get_lambda() == lambda\n        !*/\n\n        unsigned long get_num_test_splits (\n        ) const;\n        /*!\n            ensures\n                - When generating the random trees we randomly sample get_num_test_splits()\n                  possible split features at each node and pick the one that gives the best\n                  split.  Larger values of this parameter will usually give more accurate\n                  outputs but take longer to train.\n        !*/\n\n        void set_num_test_splits (\n            unsigned long num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_num_test_splits() == num\n        !*/\n\n        unsigned long get_num_threads (\n        ) const;\n        /*!\n            ensures\n                - When running training process, it is possible to make some parts of it parallel\n                  using CPU threads with #parallel_for() extension and creating #thread_pool internally\n                  When get_num_threads() == 0, trainer will not create threads and all processing will\n                  be done in the calling thread\n        !*/\n\n        void set_num_threads (\n            unsigned long num\n        );\n        /*!\n            requires\n                - num >= 0\n            ensures\n                - #get_num_threads() == num\n        !*/\n\n        void be_verbose (\n        );\n        /*!\n            ensures\n                - This object will print status messages to standard out so that a \n                  user can observe the progress of the algorithm.\n        !*/\n\n        void be_quiet (\n        );\n        /*!\n            ensures\n                - This object will not print anything to standard out\n        !*/\n\n        template <typename image_array>\n        shape_predictor train (\n            const image_array& images,\n            const std::vector<std::vector<full_object_detection> >& objects\n        ) const;\n        /*!\n            requires\n                - image_array is a dlib::array of image objects where each image object\n                  implements the interface defined in dlib/image_processing/generic_image.h \n                - images.size() == objects.size()\n                - images.size() > 0\n                - for some i: objects[i].size() != 0\n                  (i.e. there has to be at least one full_object_detection in the training set)\n                - for all valid p, there must exist i and j such that: \n                  objects[i][j].part(p) != OBJECT_PART_NOT_PRESENT.\n                  (i.e. You can't define a part that is always set to OBJECT_PART_NOT_PRESENT.)\n                - for all valid i,j,k,l:\n                    - objects[i][j].num_parts() == objects[k][l].num_parts()\n                      (i.e. all objects must agree on the number of parts)\n                    - objects[i][j].num_parts() > 0\n            ensures\n                - This object will try to learn to predict the locations of an object's parts \n                  based on the object bounding box (i.e.  full_object_detection::get_rect()) \n                  and the image pixels in that box.  That is, we will try to learn a\n                  shape_predictor, SP, such that:\n                    SP(images[i], objects[i][j].get_rect()) == objects[i][j]\n                  This learned SP object is then returned.\n                - Not all parts are required to be observed for all objects.  So if you\n                  have training instances with missing parts then set the part positions\n                  equal to OBJECT_PART_NOT_PRESENT and this algorithm will basically ignore\n                  those missing parts.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename some_type_of_rectangle\n        >\n    image_dataset_metadata::dataset make_bounding_box_regression_training_data (\n        const image_dataset_metadata::dataset& truth,\n        const std::vector<std::vector<some_type_of_rectangle>>& detections\n    );\n    /*!\n        requires\n            - truth.images.size() == detections.size()\n            - some_type_of_rectangle == rectangle, drectangle, mmod_rect, or any other type\n              that is convertible to a rectangle.\n        ensures\n            - Suppose you have an object detector that can roughly locate objects in an\n              image.  This means your detector draws boxes around objects, but these are\n              *rough* boxes in the sense that they aren't positioned super accurately.  For\n              instance, HOG based detectors usually have a stride of 8 pixels.  So the\n              positional accuracy is going to be, at best, +/-8 pixels.  \n              \n              If you want to get better positional accuracy one easy thing to do is train a\n              shape_predictor to give you the location of the object's box.  The\n              make_bounding_box_regression_training_data() routine helps you do this by\n              creating an appropriate training dataset.  It does this by taking the dataset\n              you used to train your detector (given by the truth object), and combining\n              that with the output of your detector on each image in the training dataset\n              (given by the detections object).  In particular, it will create a new\n              annotated dataset where each object box is one of the rectangles from\n              detections and that object has 5 part annotations.  These annotations\n              identify the sides and middle of the truth rectangle corresponding to the\n              detection rectangle.  You can then take the returned dataset and train a\n              shape_predictor on it.  The resulting shape_predictor can then be used to do\n              bounding box regression.  \n              \n              As an aside, the reason we create 5 part annotations in this way is because\n              it gives the best shape_predictor when trained.  If instead you used the 4\n              corners it wouldn't work as well, due to tedious vagaries of the shape_predictor \n              training process.\n\n            - We assume that detections[i] contains object detections corresponding to \n              the image truth.images[i].\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SHAPE_PREDICToR_TRAINER_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/image_processing.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_IMAGE_PROCESSInG_H_h_\n#define DLIB_IMAGE_PROCESSInG_H_h_ \n\n#include \"image_processing/scan_image.h\"\n#include \"image_processing/scan_image_pyramid.h\"\n#include \"image_processing/detection_template_tools.h\"\n#include \"image_processing/object_detector.h\"\n#include \"image_processing/box_overlap_testing.h\"\n#include \"image_processing/scan_image_pyramid_tools.h\"\n#include \"image_processing/setup_hashed_features.h\"\n#include \"image_processing/scan_image_boxes.h\"\n#include \"image_processing/scan_image_custom.h\"\n#include \"image_processing/remove_unobtainable_rectangles.h\"\n#include \"image_processing/scan_fhog_pyramid.h\"\n#include \"image_processing/shape_predictor.h\"\n#include \"image_processing/shape_predictor_trainer.h\"\n#include \"image_processing/correlation_tracker.h\"\n\n#endif // DLIB_IMAGE_PROCESSInG_H_h_\n\n\n"
  },
  {
    "path": "dlib/image_saver/dng_shared.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DNG_SHAREd_\n#define DLIB_DNG_SHAREd_\n\n#include \"../pixel.h\"\n#include <cmath>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    namespace dng_helpers_namespace\n    {\n        enum \n        {\n            grayscale = 1,\n            rgb,\n            hsi,\n            rgb_paeth,\n            rgb_alpha,\n            rgb_alpha_paeth,\n            grayscale_16bit,\n            grayscale_float\n        };\n\n        const unsigned long dng_magic_byte = 100;\n\n        template <typename T>\n        rgb_pixel predictor_rgb_paeth (const T& img, long row, long col)\n        /*\n            This is similar to the Paeth filter from the PNG image format.\n        */\n        {\n            // a = left, b = above, c = upper left\n            rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);\n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n            else\n                assign_pixel(a,(unsigned char)0);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n            else\n                assign_pixel(c,(unsigned char)0);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n            else\n                assign_pixel(b,(unsigned char)0);\n\n\n            rgb_pixel p;\n            p.red = a.red + b.red - c.red;\n            p.green = a.green + b.green - c.green;\n            p.blue = a.blue + b.blue - c.blue;\n\n            short pa = std::abs((short)p.red - (short)a.red) +\n                       std::abs((short)p.green - (short)a.green) +\n                       std::abs((short)p.blue - (short)a.blue);\n            short pb = std::abs((short)p.red - (short)b.red) +\n                       std::abs((short)p.green - (short)b.green) +\n                       std::abs((short)p.blue - (short)b.blue);\n            short pc = std::abs((short)p.red - (short)c.red) +\n                       std::abs((short)p.green - (short)c.green) +\n                       std::abs((short)p.blue - (short)c.blue);\n\n            if (pa <= pb && pa <= pc) \n                return a;\n            else if (pb <= pc) \n                return b;\n            else \n                return c;\n        }\n\n\n        template <typename T>\n        rgb_pixel predictor_rgb (const T& img, long row, long col)\n        {\n            // a = left, b = above, c = upper left\n            rgb_pixel a(0,0,0), b(0,0,0), c(0,0,0);\n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n            else\n                assign_pixel(a,(unsigned char)0);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n            else\n                assign_pixel(c,(unsigned char)0);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n            else\n                assign_pixel(b,(unsigned char)0);\n\n\n            rgb_pixel p;\n            p.red = a.red + b.red - c.red;\n            p.green = a.green + b.green - c.green;\n            p.blue = a.blue + b.blue - c.blue;\n            return p;\n        }\n\n        template <typename T>\n        rgb_alpha_pixel predictor_rgb_alpha_paeth (const T& img, long row, long col)\n        /*\n            This is similar to the Paeth filter from the PNG image format.\n        */\n        {\n            // a = left, b = above, c = upper left\n            rgb_alpha_pixel a, b, c;\n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n            else\n                assign_pixel(a,(unsigned char)0);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n            else\n                assign_pixel(c,(unsigned char)0);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n            else\n                assign_pixel(b,(unsigned char)0);\n\n\n            rgb_alpha_pixel p;\n            p.red = a.red + b.red - c.red;\n            p.green = a.green + b.green - c.green;\n            p.blue = a.blue + b.blue - c.blue;\n\n            short pa = std::abs((short)p.red - (short)a.red) +\n                       std::abs((short)p.green - (short)a.green) +\n                       std::abs((short)p.blue - (short)a.blue);\n            short pb = std::abs((short)p.red - (short)b.red) +\n                       std::abs((short)p.green - (short)b.green) +\n                       std::abs((short)p.blue - (short)b.blue);\n            short pc = std::abs((short)p.red - (short)c.red) +\n                       std::abs((short)p.green - (short)c.green) +\n                       std::abs((short)p.blue - (short)c.blue);\n\n            if (pa <= pb && pa <= pc) \n                return a;\n            else if (pb <= pc) \n                return b;\n            else \n                return c;\n        }\n\n\n        template <typename T>\n        rgb_alpha_pixel predictor_rgb_alpha (const T& img, long row, long col)\n        {\n            // a = left, b = above, c = upper left\n            rgb_alpha_pixel a, b, c;\n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n            else\n                assign_pixel(a,(unsigned char)0);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n            else\n                assign_pixel(c,(unsigned char)0);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n            else\n                assign_pixel(b,(unsigned char)0);\n\n\n            rgb_alpha_pixel p;\n            p.red = a.red + b.red - c.red;\n            p.green = a.green + b.green - c.green;\n            p.blue = a.blue + b.blue - c.blue;\n            p.alpha = a.alpha + b.alpha - c.alpha;\n            return p;\n        }\n\n\n        template <typename T>\n        hsi_pixel predictor_hsi (const T& img, long row, long col)\n        {\n            // a = left, b = above, c = upper left\n            hsi_pixel a(0,0,0), b(0,0,0), c(0,0,0);\n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n            else\n                assign_pixel(a,(unsigned char)0);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n            else\n                assign_pixel(c,(unsigned char)0);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n            else\n                assign_pixel(b,(unsigned char)0);\n\n\n            hsi_pixel p;\n            p.h = a.h + b.h - c.h;\n            p.s = a.s + b.s - c.s;\n            p.i = a.i + b.i - c.i;\n            return p;\n        }\n\n        template <typename T>\n        unsigned char predictor_grayscale (const T& img, long row, long col)\n        {\n            // a = left, b = above, c = upper left\n            unsigned char a = 0, b = 0, c = 0; \n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n\n\n            unsigned char p = a + b - c;\n            return p;\n        }\n\n        template <typename T>\n        uint16 predictor_grayscale_16 (const T& img, long row, long col)\n        {\n            // a = left, b = above, c = upper left\n            uint16 a = 0, b = 0, c = 0; \n\n\n            const long c1 = col-1;\n            const long r1 = row-1;\n\n            if (c1 >= 0)            \n                assign_pixel(a, img[row][c1]);\n\n            if (c1 >= 0 && r1 >= 0) \n                assign_pixel(c, img[r1][c1]);\n\n            if (r1 >= 0)            \n                assign_pixel(b, img[r1][col]);\n\n\n            uint16 p = a + b - c;\n            return p;\n        }\n\n    }\n}\n\n#endif  // DLIB_DNG_SHAREd_\n\n"
  },
  {
    "path": "dlib/image_saver/image_saver.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_SAVEr_\n#define DLIB_IMAGE_SAVEr_\n\n#include \"image_saver_abstract.h\"\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../byte_orderer.h\"\n#include \"../entropy_encoder.h\"\n#include \"../entropy_encoder_model.h\"\n#include \"dng_shared.h\"\n#include \"../uintn.h\"\n#include \"../dir_nav.h\"\n#include \"../float_details.h\"\n#include \"../vectorstream.h\"\n#include \"../matrix/matrix_exp.h\"\n#include \"../image_transforms/assign_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class image_save_error : public dlib::error { \n    public: image_save_error(const std::string& str) : error(EIMAGE_SAVE,str){}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        bool grayscale = pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale\n        >\n    struct save_bmp_helper;\n\n\n    template <typename image_type>\n    struct save_bmp_helper<image_type,false>\n    {\n        static void save_bmp (\n            const image_type& image_,\n            std::ostream& out \n        )\n        {\n            const_image_view<image_type> image(image_);\n            // we are going to write out a 24bit color image.\n            byte_orderer::kernel_1a bo;\n\n            out.write(\"BM\",2);\n            \n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n\n\n            unsigned long pad = 4 - (image.nc()*3)%4;\n            if (pad == 4)\n                pad = 0;\n\n            unsigned long bfSize = 14 + 40 + (image.nc()*3 + pad)*image.nr();\n            unsigned long bfReserved = 0;\n            unsigned long bfOffBits = 14 + 40;\n            unsigned long biSize = 40;\n            unsigned long biWidth = image.nc();\n            unsigned long biHeight = image.nr();\n            unsigned short biPlanes = 1;\n            unsigned short biBitCount = 24;\n            unsigned long biCompression = 0;\n            unsigned long biSizeImage = 0;\n            unsigned long biXPelsPerMeter = 0;\n            unsigned long biYPelsPerMeter = 0;\n            unsigned long biClrUsed = 0;\n            unsigned long biClrImportant = 0;\n\n            bo.host_to_little(bfSize);\n            bo.host_to_little(bfOffBits);\n            bo.host_to_little(biSize);\n            bo.host_to_little(biWidth);\n            bo.host_to_little(biHeight);\n            bo.host_to_little(biPlanes);\n            bo.host_to_little(biBitCount);\n\n            out.write((char*)&bfSize,4);\n            out.write((char*)&bfReserved,4);\n            out.write((char*)&bfOffBits,4);\n            out.write((char*)&biSize,4);\n            out.write((char*)&biWidth,4);\n            out.write((char*)&biHeight,4);\n            out.write((char*)&biPlanes,2);\n            out.write((char*)&biBitCount,2);\n            out.write((char*)&biCompression,4);\n            out.write((char*)&biSizeImage,4);\n            out.write((char*)&biXPelsPerMeter,4);\n            out.write((char*)&biYPelsPerMeter,4);\n            out.write((char*)&biClrUsed,4);\n            out.write((char*)&biClrImportant,4);\n\n\n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n\n            // now we write out the pixel data\n            for (long row = image.nr()-1; row >= 0; --row)\n            {\n                for (long col = 0; col < image.nc(); ++col)\n                {\n                    rgb_pixel p;\n                    p.red = 0;\n                    p.green = 0;\n                    p.blue = 0;\n                    assign_pixel(p,image[row][col]);\n                    out.write((char*)&p.blue,1);\n                    out.write((char*)&p.green,1);\n                    out.write((char*)&p.red,1);\n                }\n\n                // write out some zeros so that this line is a multiple of 4 bytes\n                for (unsigned long i = 0; i < pad; ++i)\n                {\n                    unsigned char p = 0;\n                    out.write((char*)&p,1);\n                }\n            }\n\n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n        }\n    };\n\n    template <typename image_type>\n    struct save_bmp_helper<image_type,true>\n    {\n        static void save_bmp (\n            const image_type& image_,\n            std::ostream& out\n        )\n        {\n            const_image_view<image_type> image(image_);\n            // we are going to write out an 8bit color image.\n            byte_orderer::kernel_1a bo;\n\n            out.write(\"BM\",2);\n            \n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n\n            unsigned long pad = 4 - image.nc()%4;\n            if (pad == 4)\n                pad = 0;\n\n            unsigned long bfSize = 14 + 40 + (image.nc() + pad)*image.nr() + 256*4;\n            unsigned long bfReserved = 0;\n            unsigned long bfOffBits = 14 + 40 + 256*4;\n            unsigned long biSize = 40;\n            unsigned long biWidth = image.nc();\n            unsigned long biHeight = image.nr();\n            unsigned short biPlanes = 1;\n            unsigned short biBitCount = 8;\n            unsigned long biCompression = 0;\n            unsigned long biSizeImage = 0;\n            unsigned long biXPelsPerMeter = 0;\n            unsigned long biYPelsPerMeter = 0;\n            unsigned long biClrUsed = 0;\n            unsigned long biClrImportant = 0;\n\n            bo.host_to_little(bfSize);\n            bo.host_to_little(bfOffBits);\n            bo.host_to_little(biSize);\n            bo.host_to_little(biWidth);\n            bo.host_to_little(biHeight);\n            bo.host_to_little(biPlanes);\n            bo.host_to_little(biBitCount);\n\n            out.write((char*)&bfSize,4);\n            out.write((char*)&bfReserved,4);\n            out.write((char*)&bfOffBits,4);\n            out.write((char*)&biSize,4);\n            out.write((char*)&biWidth,4);\n            out.write((char*)&biHeight,4);\n            out.write((char*)&biPlanes,2);\n            out.write((char*)&biBitCount,2);\n            out.write((char*)&biCompression,4);\n            out.write((char*)&biSizeImage,4);\n            out.write((char*)&biXPelsPerMeter,4);\n            out.write((char*)&biYPelsPerMeter,4);\n            out.write((char*)&biClrUsed,4);\n            out.write((char*)&biClrImportant,4);\n\n\n            // write out the color palette\n            for (unsigned int i = 0; i <= 255; ++i)\n            {\n                unsigned char ch = static_cast<unsigned char>(i);\n                out.write((char*)&ch,1);\n                out.write((char*)&ch,1);\n                out.write((char*)&ch,1);\n                ch = 0;\n                out.write((char*)&ch,1);\n            }\n\n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n\n            // now we write out the pixel data\n            for (long row = image.nr()-1; row >= 0; --row)\n            {\n                for (long col = 0; col < image.nc(); ++col)\n                {\n                    unsigned char p = 0;\n                    assign_pixel(p,image[row][col]);\n                    out.write((char*)&p,1);\n                }\n\n                // write out some zeros so that this line is a multiple of 4 bytes\n                for (unsigned long i = 0; i < pad; ++i)\n                {\n                    unsigned char p = 0;\n                    out.write((char*)&p,1);\n                }\n            }\n\n            if (!out)\n                throw image_save_error(\"error writing image to output stream\");\n\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    inline typename disable_if<is_matrix<image_type> >::type save_bmp (\n        const image_type& image,\n        std::ostream& out\n    )\n    {\n        save_bmp_helper<image_type>::save_bmp(image,out);\n    }\n\n    template <\n        typename EXP \n        >\n    inline void save_bmp (\n        const matrix_exp<EXP>& image,\n        std::ostream& out\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, image);\n        save_bmp_helper<array2d<typename EXP::type> >::save_bmp(temp,out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace dng_helpers_namespace\n    {\n        template <\n            typename image_type,\n            typename enabled = void\n            >\n        struct save_dng_helper;\n\n        typedef entropy_encoder::kernel_2a encoder_type;\n        typedef entropy_encoder_model<256,encoder_type>::kernel_5a eem_type; \n\n        typedef entropy_encoder_model<256,encoder_type>::kernel_4a eem_exp_type; \n\n        template <typename image_type >\n        struct save_dng_helper<image_type, typename enable_if<is_float_type<typename image_traits<image_type>::pixel_type> >::type >\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out \n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n                unsigned long type = grayscale_float;\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n\n                // Write the compressed exponent data into expbuf.  We will append it\n                // to the stream at the end of the loops.\n                std::vector<char> expbuf;\n                expbuf.reserve(image.size()*2);\n                vectorstream outexp(expbuf);\n                encoder_type encoder;\n                encoder.set_stream(outexp);\n\n                eem_exp_type eem_exp(encoder);\n                float_details prev;\n                for (long r = 0; r < image.nr(); ++r)\n                {\n                    for (long c = 0; c < image.nc(); ++c)\n                    {\n                        float_details cur = image[r][c];\n                        int16 exp = cur.exponent-prev.exponent;\n                        int64 man = cur.mantissa-prev.mantissa;\n                        prev = cur;\n\n                        unsigned char ebyte1 = exp&0xFF;\n                        unsigned char ebyte2 = exp>>8;\n                        eem_exp.encode(ebyte1);\n                        eem_exp.encode(ebyte2);\n\n                        serialize(man, out);\n                    }\n                }\n                // write out the magic byte to mark the end of the compressed data.\n                eem_exp.encode(dng_magic_byte);\n                eem_exp.encode(dng_magic_byte);\n                eem_exp.encode(dng_magic_byte);\n                eem_exp.encode(dng_magic_byte);\n\n                encoder.clear();\n                serialize(expbuf, out);\n            }\n        };\n\n\n        template <typename image_type>\n        struct is_non_float_non8bit_grayscale\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            const static bool value = pixel_traits<pixel_type>::grayscale && \n                                      sizeof(pixel_type) != 1 && \n                                      !is_float_type<pixel_type>::value;\n        };\n\n        template <typename image_type >\n        struct save_dng_helper<image_type, typename enable_if<is_non_float_non8bit_grayscale<image_type> >::type>\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out \n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n                unsigned long type = grayscale_16bit;\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n                encoder_type encoder;\n                encoder.set_stream(out);\n\n                eem_type eem(encoder);\n                for (long r = 0; r < image.nr(); ++r)\n                {\n                    for (long c = 0; c < image.nc(); ++c)\n                    {\n                        uint16 cur;\n                        assign_pixel(cur, image[r][c]);\n                        cur -= predictor_grayscale_16(image,r,c);\n                        unsigned char byte1 = cur&0xFF;\n                        unsigned char byte2 = cur>>8;\n                        eem.encode(byte2);\n                        eem.encode(byte1);\n                    }\n                }\n                // write out the magic byte to mark the end of the data\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n            }\n        };\n\n        template <typename image_type>\n        struct is_8bit_grayscale\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            const static bool value = pixel_traits<pixel_type>::grayscale && sizeof(pixel_type) == 1;\n        };\n\n        template <typename image_type>\n        struct save_dng_helper<image_type, typename enable_if<is_8bit_grayscale<image_type> >::type>\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out \n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n                unsigned long type = grayscale;\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n                encoder_type encoder;\n                encoder.set_stream(out);\n\n                eem_type eem(encoder);\n                for (long r = 0; r < image.nr(); ++r)\n                {\n                    for (long c = 0; c < image.nc(); ++c)\n                    {\n                        unsigned char cur;\n                        assign_pixel(cur, image[r][c]);\n                        cur -= predictor_grayscale(image,r,c);\n                        eem.encode(cur);\n                    }\n                }\n                // write out the magic byte to mark the end of the data\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n            }\n        };\n\n        template <typename image_type>\n        struct save_dng_helper<image_type,typename enable_if<is_rgb_image<image_type> >::type>\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out\n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n\n                unsigned long type = rgb;\n                // if this is a small image then we will use a different predictor\n                if (image.size() < 4000)\n                    type = rgb_paeth;\n\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n                encoder_type encoder;\n                encoder.set_stream(out);\n\n                rgb_pixel pre, cur;\n                eem_type eem(encoder);\n\n                if (type == rgb)\n                {\n                    for (long r = 0; r < image.nr(); ++r)\n                    {\n                        for (long c = 0; c < image.nc(); ++c)\n                        {\n                            pre = predictor_rgb(image,r,c);\n                            assign_pixel(cur, image[r][c]);\n\n                            eem.encode((unsigned char)(cur.red - pre.red));\n                            eem.encode((unsigned char)(cur.green - pre.green));\n                            eem.encode((unsigned char)(cur.blue - pre.blue));\n                        }\n                    }\n                }\n                else\n                {\n                    for (long r = 0; r < image.nr(); ++r)\n                    {\n                        for (long c = 0; c < image.nc(); ++c)\n                        {\n                            pre = predictor_rgb_paeth(image,r,c);\n                            assign_pixel(cur, image[r][c]);\n\n                            eem.encode((unsigned char)(cur.red - pre.red));\n                            eem.encode((unsigned char)(cur.green - pre.green));\n                            eem.encode((unsigned char)(cur.blue - pre.blue));\n                        }\n                    }\n                }\n                // write out the magic byte to mark the end of the data\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n            }\n        };\n\n        template <typename image_type>\n        struct is_rgb_alpha_image\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            const static bool value = pixel_traits<pixel_type>::rgb_alpha;\n        };\n\n        template <typename image_type>\n        struct save_dng_helper<image_type,typename enable_if<is_rgb_alpha_image<image_type> >::type>\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out\n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n\n                unsigned long type = rgb_alpha;\n                // if this is a small image then we will use a different predictor\n                if (image.size() < 4000)\n                    type = rgb_alpha_paeth;\n\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n                encoder_type encoder;\n                encoder.set_stream(out);\n\n                rgb_alpha_pixel pre, cur;\n                eem_type eem(encoder);\n\n                if (type == rgb_alpha)\n                {\n                    for (long r = 0; r < image.nr(); ++r)\n                    {\n                        for (long c = 0; c < image.nc(); ++c)\n                        {\n                            pre = predictor_rgb_alpha(image,r,c);\n                            assign_pixel(cur, image[r][c]);\n\n                            eem.encode((unsigned char)(cur.red - pre.red));\n                            eem.encode((unsigned char)(cur.green - pre.green));\n                            eem.encode((unsigned char)(cur.blue - pre.blue));\n                            eem.encode((unsigned char)(cur.alpha - pre.alpha));\n                        }\n                    }\n                }\n                else\n                {\n                    for (long r = 0; r < image.nr(); ++r)\n                    {\n                        for (long c = 0; c < image.nc(); ++c)\n                        {\n                            pre = predictor_rgb_alpha_paeth(image,r,c);\n                            assign_pixel(cur, image[r][c]);\n\n                            eem.encode((unsigned char)(cur.red - pre.red));\n                            eem.encode((unsigned char)(cur.green - pre.green));\n                            eem.encode((unsigned char)(cur.blue - pre.blue));\n                            eem.encode((unsigned char)(cur.alpha - pre.alpha));\n                        }\n                    }\n                }\n                // write out the magic byte to mark the end of the data\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n            }\n        };\n\n        template <typename image_type>\n        struct is_hsi_image\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            const static bool value = pixel_traits<pixel_type>::hsi;\n        };\n\n        template <typename image_type>\n        struct save_dng_helper<image_type,typename enable_if<is_hsi_image<image_type> >::type>\n        {\n            static void save_dng (\n                const image_type& image_,\n                std::ostream& out\n            )\n            {\n                const_image_view<image_type> image(image_);\n                out.write(\"DNG\",3);\n                unsigned long version = 1;\n                serialize(version,out);\n                unsigned long type = hsi;\n                serialize(type,out);\n                serialize(image.nc(),out);\n                serialize(image.nr(),out);\n\n                encoder_type encoder;\n                encoder.set_stream(out);\n\n                hsi_pixel pre, cur;\n                eem_type eem(encoder);\n                for (long r = 0; r < image.nr(); ++r)\n                {\n                    for (long c = 0; c < image.nc(); ++c)\n                    {\n                        pre = predictor_hsi(image,r,c);\n                        assign_pixel(cur, image[r][c]);\n\n                        eem.encode((unsigned char)(cur.h - pre.h));\n                        eem.encode((unsigned char)(cur.s - pre.s));\n                        eem.encode((unsigned char)(cur.i - pre.i));\n                    }\n                }\n                // write out the magic byte to mark the end of the data\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n                eem.encode(dng_magic_byte);\n            }\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    inline typename disable_if<is_matrix<image_type> >::type save_dng (\n        const image_type& image,\n        std::ostream& out\n    )\n    {\n        using namespace dng_helpers_namespace;\n        save_dng_helper<image_type>::save_dng(image,out);\n    }\n\n    template <\n        typename EXP \n        >\n    inline void save_dng (\n        const matrix_exp<EXP>& image,\n        std::ostream& out\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, image);\n        using namespace dng_helpers_namespace;\n        save_dng_helper<array2d<typename EXP::type> >::save_dng(temp,out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void save_dng (\n        const image_type& image,\n        const std::string& file_name\n    )\n    {\n        std::ofstream fout(file_name.c_str(), std::ios::binary);\n        if (!fout)\n            throw image_save_error(\"Unable to open \" + file_name + \" for writing.\");\n        save_dng(image, fout);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void save_bmp (\n        const image_type& image,\n        const std::string& file_name\n    )\n    {\n        std::ofstream fout(file_name.c_str(), std::ios::binary);\n        if (!fout)\n            throw image_save_error(\"Unable to open \" + file_name + \" for writing.\");\n        save_bmp(image, fout);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_SAVEr_\n\n\n\n\n"
  },
  {
    "path": "dlib/image_saver/image_saver_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_IMAGE_SAVEr_ABSTRACT_\n#ifdef DLIB_IMAGE_SAVEr_ABSTRACT_\n\n#include <iosfwd>\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    class image_save_error : public dlib::error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an exception used to indicate a failure to save an image.\n                Its type member variable will be set to EIMAGE_SAVE.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void save_bmp (\n        const image_type& image,\n        std::ostream& out \n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any kind of matrix expression.\n        ensures\n            - writes the image to the out stream in the Microsoft Windows BMP format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right\n              corner of the image.\n            - This routine can save images containing any type of pixel. However, it \n              will convert all color pixels into rgb_pixel and grayscale pixels into \n              uint8 type before saving to disk.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us\n                from saving the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void save_bmp (\n        const image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any kind of matrix expression.\n        ensures\n            - opens the file indicated by file_name with an output file stream named fout\n              and performs:\n              save_bmp(image,fout);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        dlib dng file format:\n            This is a file format I created for this library.  It is a lossless \n            compressed image format that is similar to the PNG format but uses\n            the dlib PPM compression algorithms instead of the DEFLATE algorithm.\n    !*/\n\n    template <\n        typename image_type \n        >\n    void save_dng (\n        const image_type& image,\n        std::ostream& out \n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any kind of matrix expression.\n        ensures\n            - writes the image to the out stream in the dlib dng format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right\n              corner of the image.\n            - This routine can save images containing any type of pixel.  However, the DNG\n              format can natively store only the following pixel types: rgb_pixel,\n              hsi_pixel, rgb_alpha_pixel, uint8, uint16, float, and double.\n              All other pixel types will be converted into one of these types as\n              appropriate before being saved to disk.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us\n                from saving the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void save_dng (\n        const image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any kind of matrix expression.\n        ensures\n            - opens the file indicated by file_name with an output file stream named fout \n              and performs:\n              save_dng(image,fout);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_SAVEr_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/image_saver/save_jpeg.cpp",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net), Nils Labugt\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JPEG_SAVER_CPp_\n#define DLIB_JPEG_SAVER_CPp_\n\n// only do anything with this file if DLIB_JPEG_SUPPORT is defined\n#ifdef DLIB_JPEG_SUPPORT\n\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"save_jpeg.h\"\n#include <stdio.h>\n#include <sstream>\n#include <setjmp.h>\n#include \"image_saver.h\"\n\n#ifdef DLIB_JPEG_STATIC\n#   include \"../external/libjpeg/jpeglib.h\"\n#else\n#   include <jpeglib.h>\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct jpeg_saver_error_mgr \n    {\n        jpeg_error_mgr pub;    /* \"public\" fields */\n        jmp_buf setjmp_buffer;  /* for return to caller */\n    };\n\n    void jpeg_saver_error_exit (j_common_ptr cinfo)\n    {\n        /* cinfo->err really points to a jpeg_saver_error_mgr struct, so coerce pointer */\n        jpeg_saver_error_mgr* myerr = (jpeg_saver_error_mgr*) cinfo->err;\n\n        /* Return control to the setjmp point */\n        longjmp(myerr->setjmp_buffer, 1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void save_jpeg (\n        const array2d<rgb_pixel>& img,\n        const std::string& filename,\n        int quality\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(img.size() != 0,\n            \"\\t save_jpeg()\"\n            << \"\\n\\t You can't save an empty image as a JPEG.\"\n            );\n        DLIB_CASSERT(0 <= quality && quality <= 100,\n            \"\\t save_jpeg()\"\n            << \"\\n\\t Invalid quality value.\"\n            << \"\\n\\t quality: \" << quality\n            );\n\n        FILE* outfile = fopen(filename.c_str(), \"wb\");\n        if (!outfile)\n            throw image_save_error(\"Can't open file \" + filename + \" for writing.\");\n\n        jpeg_compress_struct cinfo;\n\n        jpeg_saver_error_mgr jerr;\n        cinfo.err = jpeg_std_error(&jerr.pub);\n        jerr.pub.error_exit = jpeg_saver_error_exit;\n        /* Establish the setjmp return context for my_error_exit to use. */\n        if (setjmp(jerr.setjmp_buffer)) \n        {\n            /* If we get here, the JPEG code has signaled an error.\n             * We need to clean up the JPEG object, close the input file, and return.\n             */\n            jpeg_destroy_compress(&cinfo);\n            fclose(outfile);\n            throw image_save_error(\"save_jpeg: error while writing \" + filename);\n        }\n         \n        jpeg_create_compress(&cinfo);\n        jpeg_stdio_dest(&cinfo, outfile);\n         \n        cinfo.image_width      = img.nc();\n        cinfo.image_height     = img.nr();\n        cinfo.input_components = 3;\n        cinfo.in_color_space   = JCS_RGB;\n        jpeg_set_defaults(&cinfo);\n        jpeg_set_quality (&cinfo, quality, TRUE);\n        jpeg_start_compress(&cinfo, TRUE);\n         \n        // now write out the rows one at a time\n        while (cinfo.next_scanline < cinfo.image_height) {\n            JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];\n            jpeg_write_scanlines(&cinfo, &row_pointer, 1);\n        }\n\n        jpeg_finish_compress(&cinfo);\n        jpeg_destroy_compress(&cinfo);\n        fclose( outfile );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void save_jpeg (\n        const array2d<unsigned char>& img,\n        const std::string& filename,\n        int quality\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(img.size() != 0,\n            \"\\t save_jpeg()\"\n            << \"\\n\\t You can't save an empty image as a JPEG.\"\n            );\n        DLIB_CASSERT(0 <= quality && quality <= 100,\n            \"\\t save_jpeg()\"\n            << \"\\n\\t Invalid quality value.\"\n            << \"\\n\\t quality: \" << quality\n            );\n\n\n        FILE* outfile = fopen(filename.c_str(), \"wb\");\n        if (!outfile)\n            throw image_save_error(\"Can't open file \" + filename + \" for writing.\");\n\n        jpeg_compress_struct cinfo;\n\n        jpeg_saver_error_mgr jerr;\n        cinfo.err = jpeg_std_error(&jerr.pub);\n        jerr.pub.error_exit = jpeg_saver_error_exit;\n        /* Establish the setjmp return context for my_error_exit to use. */\n        if (setjmp(jerr.setjmp_buffer)) \n        {\n            /* If we get here, the JPEG code has signaled an error.\n             * We need to clean up the JPEG object, close the input file, and return.\n             */\n            jpeg_destroy_compress(&cinfo);\n            fclose(outfile);\n            throw image_save_error(\"save_jpeg: error while writing \" + filename);\n        }\n         \n        jpeg_create_compress(&cinfo);\n        jpeg_stdio_dest(&cinfo, outfile);\n         \n        cinfo.image_width      = img.nc();\n        cinfo.image_height     = img.nr();\n        cinfo.input_components = 1;\n        cinfo.in_color_space   = JCS_GRAYSCALE;\n        jpeg_set_defaults(&cinfo);\n        jpeg_set_quality (&cinfo, quality, TRUE);\n        jpeg_start_compress(&cinfo, TRUE);\n         \n        // now write out the rows one at a time\n        while (cinfo.next_scanline < cinfo.image_height) {\n            JSAMPROW row_pointer = (JSAMPROW) &img[cinfo.next_scanline][0];\n            jpeg_write_scanlines(&cinfo, &row_pointer, 1);\n        }\n\n        jpeg_finish_compress(&cinfo);\n        jpeg_destroy_compress(&cinfo);\n        fclose( outfile );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_JPEG_SUPPORT\n\n#endif // DLIB_JPEG_SAVER_CPp_\n\n\n\n"
  },
  {
    "path": "dlib/image_saver/save_jpeg.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAVE_JPEG_Hh_\n#define DLIB_SAVE_JPEG_Hh_\n\n#include \"save_jpeg_abstract.h\"\n\n#include \"../enable_if.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void save_jpeg (\n        const array2d<rgb_pixel>& img,\n        const std::string& filename,\n        int quality = 75\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void save_jpeg (\n        const array2d<unsigned char>& img,\n        const std::string& filename,\n        int quality = 75\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    typename disable_if<is_matrix<image_type> >::type save_jpeg(\n        const image_type& img,\n        const std::string& filename,\n        int quality = 75\n    )\n    {\n        // Convert any kind of grayscale image to an unsigned char image \n        if (pixel_traits<typename image_traits<image_type>::pixel_type>::grayscale)\n        {\n            array2d<unsigned char> temp;\n            assign_image(temp, img);\n            save_jpeg(temp, filename, quality);\n        }\n        else\n        {\n            // This is some other kind of color image so just save it as an RGB image.\n            array2d<rgb_pixel> temp;\n            assign_image(temp, img);\n            save_jpeg(temp, filename, quality);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP \n        >\n    void save_jpeg(\n        const matrix_exp<EXP>& img,\n        const std::string& file_name,\n        int quality = 75\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, img);\n        save_jpeg(temp, file_name, quality);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_JPEG_Hh_\n\n"
  },
  {
    "path": "dlib/image_saver/save_jpeg_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SAVE_JPEG_ABSTRACT_Hh_\n#ifdef DLIB_SAVE_JPEG_ABSTRACT_Hh_\n\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void save_jpeg (\n        const image_type& img,\n        const std::string& filename,\n        int quality = 75\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n            - 0 <= quality <= 100\n        ensures\n            - writes the image to the file indicated by file_name in the JPEG format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the\n              image.\n            - This routine can save images containing any type of pixel.  However,\n              save_jpeg() can only natively store rgb_pixel and uint8 pixel types.  All\n              other pixel types will be converted into one of these types as appropriate\n              before being saved to disk.\n            - The quality value determines how lossy the compression is.  Larger quality \n              values result in larger output images but the images will look better.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving \n                the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_JPEG_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_saver/save_jxl.cpp",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_JXL_SAVER_CPp_\n#define DLIB_JXL_SAVER_CPp_\n\n// only do anything with this file if DLIB_JXL_SUPPORT is defined\n#ifdef DLIB_JXL_SUPPORT\n\n#include \"save_jxl.h\"\n#include \"image_saver.h\"\n#include <sstream>\n#include <jxl/encode_cxx.h>\n#include <jxl/resizable_parallel_runner_cxx.h>\n\nnamespace dlib {\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        void impl_save_jxl (\n            const std::string& filename,\n            const uint8_t* pixels,\n            const uint32_t width,\n            const uint32_t height,\n            const uint32_t num_channels,\n            const float quality\n        )\n        {\n            std::ofstream fout(filename, std::ios::binary);\n            if (!fout.good())\n            {\n                throw image_save_error(\"Unable to open \" + filename + \" for writing.\");\n            }\n\n            auto enc = JxlEncoderMake(nullptr);\n            auto runner = JxlResizableParallelRunnerMake(nullptr);\n            JxlResizableParallelRunnerSetThreads(runner.get(), JxlResizableParallelRunnerSuggestThreads(width, height));\n\n            if (JXL_ENC_SUCCESS != JxlEncoderSetParallelRunner(enc.get(), JxlResizableParallelRunner, runner.get()))\n            {\n                throw image_save_error(\"jxl_saver: JxlResizableParallelRunner failed\");\n            }\n\n            JxlPixelFormat pixel_format{\n                .num_channels = num_channels,\n                .data_type = JXL_TYPE_UINT8,\n                .endianness = JXL_NATIVE_ENDIAN,\n                .align = 0\n            };\n            JxlBasicInfo basic_info;\n            JxlEncoderInitBasicInfo(&basic_info);\n            basic_info.xsize = width;\n            basic_info.ysize = height;\n            basic_info.bits_per_sample = 8;\n            basic_info.uses_original_profile = quality == 100;\n            switch (num_channels)\n            {\n            case 1:\n                basic_info.num_color_channels = 1;\n                basic_info.num_extra_channels = 0;\n                basic_info.alpha_bits = 0;\n                basic_info.alpha_exponent_bits = 0;\n                break;\n            case 3:\n                basic_info.num_color_channels = 3;\n                basic_info.num_extra_channels = 0;\n                basic_info.alpha_bits = 0;\n                basic_info.alpha_exponent_bits = 0;\n                break;\n            case 4:\n                basic_info.num_color_channels = 3;\n                basic_info.num_extra_channels = 1;\n                basic_info.alpha_bits = basic_info.bits_per_sample;\n                basic_info.alpha_exponent_bits = 0;\n                break;\n            default:\n                throw (\"jxl_saver: unsupported number of channels\");\n            }\n\n            if (JXL_ENC_SUCCESS != JxlEncoderSetBasicInfo(enc.get(), &basic_info))\n            {\n                throw image_save_error(\"jxl_saver: JxlEncoderSetBasicInfo failed\");\n            }\n\n            JxlColorEncoding color_encoding = {};\n            JxlColorEncodingSetToSRGB(&color_encoding, /* is_gray = */ num_channels < 3);\n            if (JXL_ENC_SUCCESS != JxlEncoderSetColorEncoding(enc.get(), &color_encoding))\n            {\n                throw image_save_error(\"jxl_saver: JxlEncoderSetColorEncoding failed\");\n            }\n\n            JxlEncoderFrameSettings* frame_settings = JxlEncoderFrameSettingsCreate(enc.get(), nullptr);\n            JxlEncoderFrameSettingsSetOption(frame_settings, JXL_ENC_FRAME_SETTING_DECODING_SPEED, 0);\n\n            const float distance = JxlEncoderDistanceFromQuality(quality);\n            if (JXL_ENC_SUCCESS != JxlEncoderSetFrameDistance(frame_settings, distance))\n            {\n                throw image_save_error(\"jxl_saver: JxlEncoderSetFrameDistance failed\");\n            }\n            if (basic_info.alpha_bits > 0)\n            {\n                if (JXL_ENC_SUCCESS != JxlEncoderSetExtraChannelDistance(frame_settings, 0, distance))\n                {\n                    throw image_save_error(\"jxl_saver: JxlEncoderSetExtraChannelDistance failed\");\n                }\n            }\n\n            // explictly enable lossless mode\n            if (distance == 0)\n            {\n                if (JXL_ENC_SUCCESS != JxlEncoderSetFrameLossless(frame_settings, JXL_TRUE))\n                {\n                    throw image_save_error(\"jxl_saver: JxlEncoderSetFrameLossless failed\");\n                }\n            }\n\n            void* pixels_data = reinterpret_cast<void*>(const_cast<uint8_t*>(pixels));\n            const size_t pixels_size = width * height * num_channels;\n            if (JXL_ENC_SUCCESS != JxlEncoderAddImageFrame(frame_settings, &pixel_format, pixels_data, pixels_size))\n            {\n                throw image_save_error(\"jxl_saver: JxlEncoderAddImageFrame failed\");\n            }\n            JxlEncoderCloseInput(enc.get());\n\n            std::vector<uint8_t> compressed;\n            compressed.resize(64);\n            uint8_t* next_out = compressed.data();\n            size_t avail_out = compressed.size() - (next_out - compressed.data());\n            JxlEncoderStatus process_result = JXL_ENC_NEED_MORE_OUTPUT;\n            while (process_result == JXL_ENC_NEED_MORE_OUTPUT)\n            {\n                process_result = JxlEncoderProcessOutput(enc.get(), &next_out, &avail_out);\n                if (process_result == JXL_ENC_NEED_MORE_OUTPUT)\n                {\n                    size_t offset = next_out - compressed.data();\n                    compressed.resize(compressed.size() * 2);\n                    next_out = compressed.data() + offset;\n                    avail_out = compressed.size() - offset;\n                }\n            }\n            compressed.resize(next_out - compressed.data());\n            if (JXL_ENC_SUCCESS != process_result)\n            {\n                throw image_save_error(\"jxl_saver: JxlEncoderProcessOutput failed\");\n            }\n            fout.write(reinterpret_cast<char*>(compressed.data()), compressed.size());\n            if (!fout.good())\n            {\n                throw image_save_error(\"Error while writing JPEG XL image to \" + filename + \".\");\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_JXL_SUPPORT\n\n#endif // DLIB_JXL_SAVER_CPp_\n\n"
  },
  {
    "path": "dlib/image_saver/save_jxl.h",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAVE_JXL_Hh_\n#define DLIB_SAVE_JXL_Hh_\n\n#include \"save_jxl_abstract.h\"\n\n#include \"../enable_if.h\"\n#include \"image_saver.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        void impl_save_jxl (\n            const std::string& filename,\n            const uint8_t* data,\n            const uint32_t width,\n            const uint32_t height,\n            const uint32_t num_channels,\n            const float quality\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    typename disable_if<is_matrix<image_type>>::type save_jxl (\n        const image_type& img_,\n        const std::string& filename,\n        const float quality = 90\n    )\n    {\n#ifndef DLIB_JXL_SUPPORT\n            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                You are getting this error because you are trying to use the save_jxl\n                function but you haven't defined DLIB_JXL_SUPPORT.  You must do so to use\n                this object.   You must also make sure you set your build environment\n                to link against the libjxl library.\n            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n            static_assert(sizeof(image_type) == 0, \"JPEG XL support not enabled.\");\n#endif\n        const_image_view<image_type> img(img_);\n        using pixel_type = typename image_traits<image_type>::pixel_type;\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(img.size() != 0,\n            \"\\t save_jxl()\"\n            << \"\\n\\t You can't save an empty image as a JPEG XL.\"\n            );\n        DLIB_CASSERT(0 <= quality && quality <= 100,\n            \"\\t save_jxl()\"\n            << \"\\n\\t Invalid quality value.\"\n            << \"\\n\\t quality: \" << quality\n            );\n\n        auto data = reinterpret_cast<const uint8_t*>(image_data(img));\n        const int width = img.nc();\n        const int height = img.nr();\n        const int depth = pixel_traits<pixel_type>::num;\n        // Fast path: rgb, rgb_alpha, 8-bit grayscale\n        if (pixel_traits<pixel_type>::rgb ||\n            pixel_traits<pixel_type>::rgb_alpha ||\n            (pixel_traits<pixel_type>::grayscale &&\n             std::is_same<typename pixel_traits<pixel_type>::basic_pixel_type, unsigned char>()))\n        {\n            impl::impl_save_jxl(filename, data, width, height, depth, quality);\n        }\n        else\n        {\n            // This is probably a single-channel float image resulting from some matrix operation.\n            if (depth == 1)\n            {\n                array2d<unsigned char> temp;\n                assign_image(temp, img);\n                auto data = reinterpret_cast<const uint8_t*>(image_data(temp));\n                impl::impl_save_jxl(filename, data, width, height, 1, quality);\n            }\n            // This is some other kind of color image so just save it as an RGB image.\n            else if (pixel_traits<pixel_type>::has_alpha)\n            {\n                array2d<rgb_alpha_pixel> temp;\n                assign_image(temp, img);\n                auto data = reinterpret_cast<const uint8_t*>(image_data(temp));\n                impl::impl_save_jxl(filename, data, width, height, 4, quality);\n            }\n            else\n            {\n                array2d<rgb_pixel> temp;\n                assign_image(temp, img);\n                auto data = reinterpret_cast<const uint8_t*>(image_data(temp));\n                impl::impl_save_jxl(filename, data, width, height, 3, quality);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    void save_jxl(\n        const matrix_exp<EXP>& img,\n        const std::string& filename,\n        const float quality = 90\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, img);\n        save_jxl(temp, filename, quality);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_JXL_Hh_\n"
  },
  {
    "path": "dlib/image_saver/save_jxl_abstract.h",
    "content": "// Copyright (C) 2024  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SAVE_JXL_ABSTRACT_Hh_\n#ifdef DLIB_SAVE_JXL_ABSTRACT_Hh_\n\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void save_jxl (\n        const image_type& img,\n        const std::string& filename,\n        float quality = 90\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n            - quality >= 0\n        ensures\n            - writes the image to the file indicated by filename in the JPEG XL format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the\n              image.\n            - This routine can save images containing any type of pixel.  However,\n              save_jxl() can only natively store rgb_pixel, rgb_alpha_pixel and unsigned\n              char pixel types.  All other pixel types will be converted into one of\n              these types as appropriate before being saved to disk.\n            - The quality value determines how lossy the compression is.  Larger quality\n              values result in larger output images but the images will look better.\n              Although it can range from 0 to 100, the recommended range is between\n              68 and 96.  A value of 90 means visually lossless, while a value of 100\n              means mathematically lossless.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving\n                the image.\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_JXL_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_saver/save_png.cpp",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAVE_PnG_CPPh_\n#define DLIB_SAVE_PnG_CPPh_\n\n// only do anything with this file if DLIB_PNG_SUPPORT is defined\n#ifdef DLIB_PNG_SUPPORT\n\n#include \"save_png.h\"\n#include <cstdio>\n#include <png.h>\n#include \"../byte_orderer.h\"\n\nnamespace dlib\n{\n    // Don't do anything when libpng calls us to tell us about an error.  Just return to \n    // our own code and throw an exception (at the long jump target).\n    void png_reader_user_error_fn_silent(png_structp  png_struct, png_const_charp ) \n    {\n        longjmp(png_jmpbuf(png_struct),1);\n    }\n    void png_reader_user_warning_fn_silent(png_structp , png_const_charp ) \n    {\n    }\n\n    void png_writer_data_callback(png_structp png, png_bytep data, png_size_t length)\n    {\n        using clb_t = std::function<void(const char*, std::size_t)>;\n        clb_t* clb = (clb_t*)png_get_io_ptr(png);\n        (*clb)((const char*)data, length);\n    }\n\n    void png_writer_flush_callback(png_structp png)\n    {\n        /*no-op*/\n    }\n\n    namespace impl\n    {\n        void impl_save_png (\n            std::function<void(const char*, std::size_t)> clb,\n            std::vector<unsigned char*>& row_pointers,\n            const long width,\n            const png_type type,\n            const int bit_depth,\n            const bool swap_rgb\n        )\n        {\n            png_structp png_ptr;\n            png_infop info_ptr;\n\n            /* Create and initialize the png_struct with the desired error handler\n            * functions.  If you want to use the default stderr and longjump method,\n            * you can supply NULL for the last three parameters.  We also check that\n            * the library version is compatible with the one used at compile time,\n            * in case we are using dynamically linked libraries.  REQUIRED.\n            */\n            png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent);\n\n            if (png_ptr == NULL)\n                throw image_save_error(\"Error while writing PNG file : png_create_write_struct()\");\n\n            /* Allocate/initialize the image information data.  REQUIRED */\n            info_ptr = png_create_info_struct(png_ptr);\n            if (info_ptr == NULL)\n            {\n                png_destroy_write_struct(&png_ptr,  NULL);\n                throw image_save_error(\"Error while writing PNG file : png_create_info_struct()\");\n            }\n\n            /* Set error handling.  REQUIRED if you aren't supplying your own\n            * error handling functions in the png_create_write_struct() call.\n            */\n            if (setjmp(png_jmpbuf(png_ptr)))\n            {\n                /* If we get here, we had a problem writing the file */\n                png_destroy_write_struct(&png_ptr, &info_ptr);\n                throw image_save_error(\"Error while writing PNG file\");\n            }\n\n            int color_type = 0;\n            switch(type)\n            {\n                case png_type_rgb:       color_type = PNG_COLOR_TYPE_RGB; break;\n                case png_type_rgb_alpha: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;\n                case png_type_gray:      color_type = PNG_COLOR_TYPE_GRAY; break;\n                default:\n                    {\n                        png_destroy_write_struct(&png_ptr, &info_ptr);\n                        throw image_save_error(\"Invalid color type\");\n                    }\n            }\n\n            png_set_write_fn(\n                png_ptr, &clb, \n                png_writer_data_callback,\n                png_writer_flush_callback\n            );\n\n            int png_transforms = PNG_TRANSFORM_IDENTITY;\n            byte_orderer bo;\n            if (bo.host_is_little_endian())\n                png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;\n            if (swap_rgb)\n                png_transforms |= PNG_TRANSFORM_BGR;\n                \n            const long height = row_pointers.size();\n\n            png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);\n            png_set_rows(png_ptr, info_ptr, &row_pointers[0]);\n            png_write_png(png_ptr, info_ptr, png_transforms, NULL);\n\n            /* Clean up after the write, and free any memory allocated */\n            png_destroy_write_struct(&png_ptr, &info_ptr);\n        }\n    }\n}\n\n#endif // DLIB_PNG_SUPPORT\n\n#endif // DLIB_SAVE_PnG_CPPh_\n\n\n"
  },
  {
    "path": "dlib/image_saver/save_png.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAVE_PnG_Hh_\n#define DLIB_SAVE_PnG_Hh_\n\n#include <vector>\n#include <string>\n#include <fstream>\n#include <functional>\n#include \"save_png_abstract.h\"\n#include \"image_saver.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../matrix/matrix_exp.h\"\n#include \"../image_transforms/assign_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        enum png_type\n        {\n            png_type_rgb,\n            png_type_rgb_alpha,\n            png_type_gray,\n        };\n\n        void impl_save_png (\n            std::function<void(const char*, std::size_t)> clb,\n            std::vector<unsigned char*>& row_pointers,\n            const long width,\n            const png_type type,\n            const int bit_depth,\n            const bool swap_rgb = false\n        );\n\n// ----------------------------------------------------------------------------------------\n\n        template <\n          class image_type\n        >\n        void save_png(\n            const image_type& img_,\n            std::function<void(const char*, std::size_t)> clb\n        )\n        {\n            const_image_view<image_type> img(img_);\n\n            // make sure requires clause is not broken\n            DLIB_CASSERT(img.size() != 0,\n                \"\\t save_png()\"\n                << \"\\n\\t You can't save an empty image as a PNG\"\n                );\n\n\n#ifndef DLIB_PNG_SUPPORT\n                /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                    You are getting this error because you are trying to use save_png() \n                    but you haven't defined DLIB_PNG_SUPPORT.  You must do so to use\n                    this function.   You must also make sure you set your build environment\n                    to link against the libpng library.\n                !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n                COMPILE_TIME_ASSERT(sizeof(image_type) == 0);\n#else\n            std::vector<unsigned char*> row_pointers(img.nr());\n            using pixel_type = pixel_type_t<image_type>;\n\n            if (std::is_same<rgb_pixel,pixel_type>::value)\n            {\n                for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                    row_pointers[i] = (unsigned char*)(&img[i][0]);\n\n                impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);\n            }\n            else if (std::is_same<bgr_pixel,pixel_type>::value)\n            {\n                for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                    row_pointers[i] = (unsigned char*)(&img[i][0]);\n\n                impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8, true);\n            }\n            else if (std::is_same<rgb_alpha_pixel,pixel_type>::value)\n            {\n                for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                    row_pointers[i] = (unsigned char*)(&img[i][0]);\n\n                impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);\n            }\n            else if (pixel_traits<pixel_type>::lab || pixel_traits<pixel_type>::hsi || pixel_traits<pixel_type>::rgb)\n            {\n                // convert from Lab or HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B)\n                array2d<rgb_pixel> temp_img;\n                assign_image(temp_img, img_);\n                for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                    row_pointers[i] = (unsigned char*)(&temp_img[i][0]);\n\n                impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);\n            }\n            else if (pixel_traits<pixel_type>::rgb_alpha)\n            {\n                // convert from RGBA pixels that aren't laid out as R G B A\n                array2d<rgb_alpha_pixel> temp_img;\n                assign_image(temp_img, img_);\n                for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                    row_pointers[i] = (unsigned char*)(&temp_img[i][0]);\n\n                impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);\n            }\n            else // this is supposed to be grayscale \n            {\n                DLIB_CASSERT(pixel_traits<pixel_type>::grayscale, \"impossible condition detected\");\n\n                if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 1)\n                {\n                    for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                        row_pointers[i] = (unsigned char*)(&img[i][0]);\n\n                    impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 8);\n                }\n                else if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 2)\n                {\n                    for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                        row_pointers[i] = (unsigned char*)(&img[i][0]);\n\n                    impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);\n                }\n                else\n                {\n                    // convert from whatever this is to 16bit grayscale \n                    array2d<dlib::uint16> temp_img;\n                    assign_image(temp_img, img_);\n                    for (unsigned long i = 0; i < row_pointers.size(); ++i)\n                        row_pointers[i] = (unsigned char*)(&temp_img[i][0]);\n\n                    impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);\n                }\n            }\n#endif\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type\n    >\n    void save_png (\n        const image_type& img,\n        std::ostream& out\n    )\n    {\n        impl::save_png (\n            img,\n            [&out](const char* data, std::size_t ndata) {\n                out.write(data, ndata);\n            }\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type\n    >\n    void save_png (\n        const image_type& img,\n        const std::string& file_name\n    )\n    {\n        std::ofstream out(file_name, std::ios::binary);\n        save_png(img, out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type,\n      class Byte,\n      class Alloc\n    >\n    void save_png (\n        const image_type& img,\n        std::vector<Byte, Alloc>& buf\n    )\n    {\n        static_assert(is_byte<Byte>::value, \"Byte must be char, int8_t or uint8_t\");\n        impl::save_png (\n            img,\n            [&buf](const char* data, std::size_t ndata) {\n                buf.insert(end(buf), data, data + ndata);\n            }\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class T, long NR, long NC, class MM, class L,\n      class Output\n    >\n    void save_png (\n        const matrix<T,NR,NC,MM,L>& img,\n        Output&& out\n    )\n    {\n        save_png(make_image_view(img), std::forward<Output>(out));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class EXP,\n      class Output\n    >\n    void save_png (\n        const matrix_exp<EXP>& img,\n        Output&& out\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, img);\n        save_png(temp, std::forward<Output>(out));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"save_png.cpp\"\n#endif\n\n#endif // DLIB_SAVE_PnG_Hh_\n\n"
  },
  {
    "path": "dlib/image_saver/save_png_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SAVE_PnG_ABSTRACT_\n#ifdef DLIB_SAVE_PnG_ABSTRACT_\n\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type \n        >\n    void save_png (\n        const image_type& image,\n        const std::string& file_name\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n        ensures\n            - writes the image to the file indicated by file_name in the PNG (Portable Network Graphics) \n              format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right\n              corner of the image.\n            - This routine can save images containing any type of pixel.  However, save_png() can\n              only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8, \n              and uint16.  All other pixel types will be converted into one of these types as \n              appropriate before being saved to disk.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving \n                the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type\n    >\n    void save_png (\n        const image_type& img,\n        std::ostream& out\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n        ensures\n            - writes the image to the output stream in the PNG (Portable Network Graphics) \n              format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right\n              corner of the image.\n            - This routine can save images containing any type of pixel.  However, save_png() can\n              only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8, \n              and uint16.  All other pixel types will be converted into one of these types as \n              appropriate before being saved to disk.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving \n                the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n      class image_type,\n      class Byte,\n      class Alloc\n    >\n    void save_png (\n        const image_type& img,\n        std::vector<Byte, Alloc>& buf\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n        ensures\n            - writes the image to the vector buffer in the PNG (Portable Network Graphics) \n              format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right\n              corner of the image.\n            - This routine can save images containing any type of pixel.  However, save_png() can\n              only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8, \n              and uint16.  All other pixel types will be converted into one of these types as \n              appropriate before being saved to disk.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving \n                the image.  \n            - std::bad_alloc \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_PnG_ABSTRACT_\n\n\n\n"
  },
  {
    "path": "dlib/image_saver/save_webp.cpp",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_WEBP_SAVER_CPp_\n#define DLIB_WEBP_SAVER_CPp_\n\n// only do anything with this file if DLIB_WEBP_SUPPORT is defined\n#ifdef DLIB_WEBP_SUPPORT\n\n#include \"save_webp.h\"\n#include \"image_saver.h\"\n#include <sstream>\n\n#include <webp/encode.h>\n\nnamespace dlib {\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        void impl_save_webp (\n            const std::string& filename,\n            const uint8_t* data,\n            const int width,\n            const int height,\n            const int stride,\n            const float quality,\n            const webp_type type\n        )\n        {\n            if (width > WEBP_MAX_DIMENSION || height > WEBP_MAX_DIMENSION)\n                throw image_save_error(\"Error while encoding \" + filename + \". Bad picture dimensions: \"\n                + std::to_string(width) + \"x\" + std::to_string(height)\n                + \". Maximum WebP width and height allowed is \"\n                + std::to_string(WEBP_MAX_DIMENSION) + \" pixels\");\n\n            std::ofstream fout(filename, std::ios::binary);\n            if (!fout.good())\n                throw image_save_error(\"Unable to open \" + filename + \" for writing.\");\n\n            uint8_t* output;\n            size_t output_size = 0;\n            switch (type)\n            {\n            case webp_type::rgb:\n                if (quality > 100)\n                    output_size = WebPEncodeLosslessRGB(data, width, height, stride, &output);\n                else\n                    output_size = WebPEncodeRGB(data, width, height, stride, quality, &output);\n                break;\n            case webp_type::rgba:\n                if (quality > 100)\n                    output_size = WebPEncodeLosslessRGBA(data, width, height, stride, &output);\n                else\n                    output_size = WebPEncodeRGBA(data, width, height, stride, quality, &output);\n                break;\n            case webp_type::bgr:\n                if (quality > 100)\n                    output_size = WebPEncodeLosslessBGR(data, width, height, stride, &output);\n                else\n                    output_size = WebPEncodeBGR(data, width, height, stride, quality, &output);\n                break;\n            case webp_type::bgra:\n                if (quality > 100)\n                    output_size = WebPEncodeLosslessBGRA(data, width, height, stride, &output);\n                else\n                    output_size = WebPEncodeBGRA(data, width, height, stride, quality, &output);\n                break;\n            default:\n                throw image_save_error(\"Invalid WebP color type\");\n            }\n\n            if (output_size > 0)\n            {\n                fout.write(reinterpret_cast<char*>(output), output_size);\n                if (!fout.good())\n                {\n                    WebPFree(output);\n                    throw image_save_error(\"Error while writing WebP image to \" + filename + \".\");\n                }\n            }\n            else\n            {\n                throw image_save_error(\"Error while encoding WebP image to \" + filename + \".\");\n            }\n            WebPFree(output);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_WEBP_SUPPORT\n\n#endif // DLIB_WEBP_SAVER_CPp_\n\n"
  },
  {
    "path": "dlib/image_saver/save_webp.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SAVE_WEBP_Hh_\n#define DLIB_SAVE_WEBP_Hh_\n\n#include \"save_webp_abstract.h\"\n\n#include \"../enable_if.h\"\n#include \"image_saver.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        enum class webp_type\n        {\n            rgb,\n            bgr,\n            rgba,\n            bgra\n        };\n\n        void impl_save_webp (\n            const std::string& filename,\n            const uint8_t* data,\n            const int width,\n            const int height,\n            const int stride,\n            const float quality,\n            const webp_type type\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    typename disable_if<is_matrix<image_type>>::type save_webp (\n        const image_type& img_,\n        const std::string& filename,\n        float quality = 75\n    )\n    {\n#ifndef DLIB_WEBP_SUPPORT\n            /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n                You are getting this error because you are trying to use the save_webp\n                function but you haven't defined DLIB_WEBP_SUPPORT.  You must do so to use\n                this object.   You must also make sure you set your build environment\n                to link against the libwebp library.\n            !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/\n            static_assert(sizeof(image_type) == 0, \"webp support not enabled.\");\n#endif\n        const_image_view<image_type> img(img_);\n        using pixel_type = typename image_traits<image_type>::pixel_type;\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(img.size() != 0,\n            \"\\t save_webp()\"\n            << \"\\n\\t You can't save an empty image as a WEBP.\"\n            );\n        DLIB_CASSERT(0 <= quality,\n            \"\\t save_webp()\"\n            << \"\\n\\t Invalid quality value.\"\n            << \"\\n\\t quality: \" << quality\n            );\n\n        auto data = reinterpret_cast<const uint8_t*>(image_data(img));\n        const int width = img.nc();\n        const int height = img.nr();\n        int stride = width_step(img);\n        if (pixel_traits<pixel_type>::rgb_alpha)\n        {\n            if (pixel_traits<pixel_type>::bgr_layout)\n                impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::bgra);\n            else\n                impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgba);\n        }\n        else if (pixel_traits<pixel_type>::rgb)\n        {\n            if (pixel_traits<pixel_type>::bgr_layout)\n                impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::bgr);\n            else\n                impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgb);\n        }\n        else\n        {\n            // This is some other kind of color image so just save it as an RGB image.\n            // We also need to recompute the stride in case we were given a grayscale image.\n            array2d<rgb_pixel> temp;\n            assign_image(temp, img);\n            stride = width_step(temp);\n            auto data = reinterpret_cast<const uint8_t*>(image_data(temp));\n            impl::impl_save_webp(filename, data, width, height, stride, quality, impl::webp_type::rgb);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    void save_webp(\n        const matrix_exp<EXP>& img,\n        const std::string& filename,\n        float quality = 75\n    )\n    {\n        array2d<typename EXP::type> temp;\n        assign_image(temp, img);\n        save_webp(temp, filename, quality);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_WEBP_Hh_\n"
  },
  {
    "path": "dlib/image_saver/save_webp_abstract.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net), Adrià Arrufat\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SAVE_WEBP_ABSTRACT_Hh_\n#ifdef DLIB_SAVE_WEBP_ABSTRACT_Hh_\n\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void save_webp (\n        const image_type& img,\n        const std::string& filename,\n        float quality = 75\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a matrix expression\n            - image.size() != 0\n            - quality >= 0\n        ensures\n            - writes the image to the file indicated by filename in the WEBP format.\n            - image[0][0] will be in the upper left corner of the image.\n            - image[image.nr()-1][image.nc()-1] will be in the lower right corner of the\n              image.\n            - This routine can save images containing any type of pixel.  However,\n              save_webp() can only natively store rgb_pixel, bgr_pixel, rgb_alpha_pixel and\n              bgr_alpha_pixel pixel types.  All other pixel types will be converted into one\n              of these types as appropriate before being saved to disk.\n            - The quality value determines how lossy the compression is.  Larger quality\n              values result in larger output images but the images will look better.  A value\n              between 0 and 100 will use lossy compression, while any value larger than\n              100 will perform lossless compression.\n        throws\n            - image_save_error\n                This exception is thrown if there is an error that prevents us from saving\n                the image.\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SAVE_WEBP_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/assign_image.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ASSIGN_IMAGe_\n#define DLIB_ASSIGN_IMAGe_\n\n#include \"../pixel.h\"\n#include \"assign_image_abstract.h\"\n#include \"../statistics.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void impl_assign_image (\n        image_view<dest_image_type>& dest,\n        const src_image_type& src\n    )\n    {\n        dest.set_size(src.nr(),src.nc());\n        for (long r = 0; r < src.nr(); ++r)\n        {\n            for (long c = 0; c < src.nc(); ++c)\n            {\n                assign_pixel(dest[r][c], src(r,c));\n            }\n        }\n    }\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void impl_assign_image (\n        dest_image_type& dest_,\n        const src_image_type& src\n    )\n    {\n        image_view<dest_image_type> dest(dest_);\n        impl_assign_image(dest, src);\n    }\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void assign_image (\n        dest_image_type& dest,\n        const src_image_type& src\n    )\n    {\n        // check for the case where dest is the same object as src\n        if (is_same_object(dest,src))\n            return;\n\n        impl_assign_image(dest, mat(src));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void impl_assign_image_scaled (\n        image_view<dest_image_type>& dest,\n        const src_image_type& src,\n        const double thresh \n    )\n    {\n        DLIB_ASSERT( thresh > 0,\n            \"\\tvoid assign_image_scaled()\"\n            << \"\\n\\t You have given an threshold value\"\n            << \"\\n\\t thresh: \" << thresh \n            );\n\n\n        typedef typename image_traits<dest_image_type>::pixel_type dest_pixel;\n\n        // If the destination has a dynamic range big enough to contain the source image data then just do a \n        // regular assign_image()\n        if (pixel_traits<dest_pixel>::max() >= pixel_traits<typename src_image_type::type>::max() &&\n            pixel_traits<dest_pixel>::min() <= pixel_traits<typename src_image_type::type>::min() )\n        {\n            impl_assign_image(dest, src);\n            return;\n        }\n\n        dest.set_size(src.nr(),src.nc());\n\n        if (src.size() == 0)\n            return;\n\n        if (src.size() == 1)\n        {\n            impl_assign_image(dest, src);\n            return;\n        }\n\n        // gather image statistics \n        running_stats<double> rs;\n        for (long r = 0; r < src.nr(); ++r)\n        {\n            for (long c = 0; c < src.nc(); ++c)\n            {\n                rs.add(get_pixel_intensity(src(r,c)));\n            }\n        }\n        typedef typename pixel_traits<typename src_image_type::type>::basic_pixel_type spix_type;\n\n        if (std::numeric_limits<spix_type>::is_integer)\n        {\n            // If the destination has a dynamic range big enough to contain the source image data then just do a \n            // regular assign_image()\n            if (pixel_traits<dest_pixel>::max() >= rs.max() &&\n                pixel_traits<dest_pixel>::min() <= rs.min() )\n            {\n                impl_assign_image(dest, src);\n                return;\n            }\n        }\n\n        // Figure out the range of pixel values based on image statistics.  There might be some huge\n        // outliers so don't just pick the min and max values.\n        const double upper = std::min(rs.mean() + thresh*rs.stddev(), rs.max());\n        const double lower = std::max(rs.mean() - thresh*rs.stddev(), rs.min());\n\n\n        const double dest_min = pixel_traits<dest_pixel>::min();\n        const double dest_max = pixel_traits<dest_pixel>::max();\n\n        const double scale = (upper!=lower)? ((dest_max - dest_min) / (upper - lower)) : 0;\n\n        for (long r = 0; r < src.nr(); ++r)\n        {\n            for (long c = 0; c < src.nc(); ++c)\n            {\n                const double val = get_pixel_intensity(src(r,c)) - lower;\n\n                assign_pixel(dest[r][c], scale*val + dest_min);\n            }\n        }\n    }\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void impl_assign_image_scaled (\n        dest_image_type& dest_,\n        const src_image_type& src,\n        const double thresh \n    )\n    {\n        image_view<dest_image_type> dest(dest_);\n        impl_assign_image_scaled(dest, src, thresh);\n    }\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void assign_image_scaled (\n        dest_image_type& dest,\n        const src_image_type& src,\n        const double thresh = 4\n    )\n    {\n        // check for the case where dest is the same object as src\n        if (is_same_object(dest,src))\n            return;\n\n        impl_assign_image_scaled(dest, mat(src),thresh);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_pixel_type\n        >\n    void assign_all_pixels (\n        image_view<dest_image_type>& dest_img,\n        const src_pixel_type& src_pixel\n    )\n    {\n        for (long r = 0; r < dest_img.nr(); ++r)\n        {\n            for (long c = 0; c < dest_img.nc(); ++c)\n            {\n                assign_pixel(dest_img[r][c], src_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_pixel_type\n        >\n    void assign_all_pixels (\n        dest_image_type& dest_img_,\n        const src_pixel_type& src_pixel\n    )\n    {\n        image_view<dest_image_type> dest_img(dest_img_);\n        assign_all_pixels(dest_img, src_pixel);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void assign_border_pixels (\n        image_view<image_type>& img,\n        long x_border_size,\n        long y_border_size,\n        const typename image_traits<image_type>::pixel_type& p\n    )\n    {\n        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,\n            \"\\tvoid assign_border_pixels(img, p, border_size)\"\n            << \"\\n\\tYou have given an invalid border_size\"\n            << \"\\n\\tx_border_size: \" << x_border_size\n            << \"\\n\\ty_border_size: \" << y_border_size\n            );\n\n        y_border_size = std::min(y_border_size, img.nr()/2+1);\n        x_border_size = std::min(x_border_size, img.nc()/2+1);\n\n        // assign the top border\n        for (long r = 0; r < y_border_size; ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                img[r][c] = p;\n            }\n        }\n\n        // assign the bottom border\n        for (long r = img.nr()-y_border_size; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                img[r][c] = p;\n            }\n        }\n\n        // now assign the two sides\n        for (long r = y_border_size; r < img.nr()-y_border_size; ++r)\n        {\n            // left border\n            for (long c = 0; c < x_border_size; ++c)\n                img[r][c] = p;\n\n            // right border\n            for (long c = img.nc()-x_border_size; c < img.nc(); ++c)\n                img[r][c] = p;\n        }\n    }\n\n    template <\n        typename image_type\n        >\n    void assign_border_pixels (\n        image_type& img_,\n        long x_border_size,\n        long y_border_size,\n        const typename image_traits<image_type>::pixel_type& p\n    )\n    {\n        image_view<image_type> img(img_);\n        assign_border_pixels(img, x_border_size, y_border_size, p);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_type& img,\n        long x_border_size,\n        long y_border_size\n    )\n    {\n        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,\n            \"\\tvoid zero_border_pixels(img, p, border_size)\"\n            << \"\\n\\tYou have given an invalid border_size\"\n            << \"\\n\\tx_border_size: \" << x_border_size\n            << \"\\n\\ty_border_size: \" << y_border_size\n            );\n\n        typename image_traits<image_type>::pixel_type zero_pixel;\n        assign_pixel_intensity(zero_pixel, 0);\n        assign_border_pixels(img, x_border_size, y_border_size, zero_pixel);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_view<image_type>& img,\n        long x_border_size,\n        long y_border_size\n    )\n    {\n        DLIB_ASSERT( x_border_size >= 0 && y_border_size >= 0,\n            \"\\tvoid zero_border_pixels(img, p, border_size)\"\n            << \"\\n\\tYou have given an invalid border_size\"\n            << \"\\n\\tx_border_size: \" << x_border_size\n            << \"\\n\\ty_border_size: \" << y_border_size\n            );\n\n        typename image_traits<image_type>::pixel_type zero_pixel;\n        assign_pixel_intensity(zero_pixel, 0);\n        assign_border_pixels(img, x_border_size, y_border_size, zero_pixel);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_view<image_type>& img,\n        rectangle inside\n    )\n    {\n        inside = inside.intersect(get_rect(img));\n        if (inside.is_empty())\n        {\n            assign_all_pixels(img, 0);\n            return;\n        }\n\n        for (long r = 0; r < inside.top(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n                assign_pixel(img[r][c], 0);\n        }\n        for (long r = inside.top(); r <= inside.bottom(); ++r)\n        {\n            for (long c = 0; c < inside.left(); ++c)\n                assign_pixel(img[r][c], 0);\n            for (long c = inside.right()+1; c < img.nc(); ++c)\n                assign_pixel(img[r][c], 0);\n        }\n        for (long r = inside.bottom()+1; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n                assign_pixel(img[r][c], 0);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_type& img_,\n        const rectangle& inside\n    )\n    {\n        image_view<image_type> img(img_);\n        zero_border_pixels(img, inside);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ASSIGN_IMAGe_\n\n\n\n"
  },
  {
    "path": "dlib/image_transforms/assign_image_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ASSIGN_IMAGe_ABSTRACT\n#ifdef DLIB_ASSIGN_IMAGe_ABSTRACT\n\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void assign_image (\n        dest_image_type& dest_img,\n        const src_image_type& src_img\n    );\n    /*!\n        requires\n            - src_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any object convertible to a matrix\n              via mat().\n            - dest_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view.\n        ensures\n            - #dest_img.nc() == src_img.nc()\n            - #dest_img.nr() == src_img.nr()\n            - for all valid r and c:\n                - performs assign_pixel(#dest_img[r][c],src_img[r][c]) \n                  (i.e. copies the src image to dest image)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_image_type\n        >\n    void assign_image_scaled (\n        dest_image_type& dest_img,\n        const src_image_type& src_img,\n        const double thresh = 4\n    );\n    /*!\n        requires\n            - src_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or any object convertible to a matrix\n              via mat().\n            - dest_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view.\n            - thresh > 0\n        ensures\n            - #dest_img.nc() == src_img.nc()\n            - #dest_img.nr() == src_img.nr()\n            - if (dest_img's pixels have a wide enough dynamic range to contain all the\n              pixels in src_img.  (Note that dynamic range is determined by the min() and \n              max() pixel_traits properties)) then\n                - performs: assign_image(dest_img, src_img) \n                  (i.e. in this case, no scaling is performed.  Just a normal color space \n                  conversion and copy )\n            - else\n                - #dest_img will be converted to a grayscale image\n                - scales the contents of src_img into the dynamic range of dest_img and then\n                  assigns the result into dest_img.  The thresh parameter is used to filter \n                  source pixel values which are outliers.  These outliers will saturate\n                  at the edge of the destination image's dynamic range.\n                - Specifically, for all valid r and c:\n                    - scales get_pixel_intensity(src_img[r][c]) into the dynamic range\n                      of the dest_img.  This is done using the mean and standard deviation\n                      of src_img. Call the mean M and the standard deviation D.  Then the\n                      scaling from src_img to dest_img is performed using the following\n                      mapping:\n                        let SRC_UPPER  = min(M + thresh*D, max(mat(src_img)))\n                        let SRC_LOWER  = max(M - thresh*D, min(mat(src_img)))\n                        let DEST_UPPER = pixel_traits<image_traits<dest_image_type>::pixel_type>::max()\n                        let DEST_LOWER = pixel_traits<image_traits<dest_image_type>::pixel_type>::min()\n\n                        MAPPING: [SRC_LOWER, SRC_UPPER] -> [DEST_LOWER, DEST_UPPER]\n\n                      Where this mapping is a linear mapping of values from the left range\n                      into the right range of values.  Source pixel values outside the left\n                      range are modified to be at the appropriate end of the range.\n\n                      The scaled pixel is then stored in dest_img[r][c].\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename dest_image_type,\n        typename src_pixel_type\n        >\n    void assign_all_pixels (\n        dest_image_type& dest_img,\n        const src_pixel_type& src_pixel\n    );\n    /*!\n        requires\n            - dest_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view.\n            - pixel_traits<src_pixel_type> is defined  \n        ensures\n            - #dest_img.nc() == dest_img.nc()\n            - #dest_img.nr() == dest_img.nr()\n              (i.e. the size of dest_img isn't changed by this function)\n            - for all valid r and c:\n                - performs assign_pixel(#dest_img[r][c],src_pixel) \n                  (i.e. assigns the src pixel to every pixel in the dest image)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void assign_border_pixels (\n        image_type& img,\n        long x_border_size,\n        long y_border_size,\n        const typename image_traits<image_type>::pixel_type& p\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view\n            - x_border_size >= 0\n            - y_border_size >= 0\n        ensures\n            - #img.nc() == img.nc()\n            - #img.nr() == img.nr()\n              (i.e. the size of img isn't changed by this function)\n            - for all valid r such that r+y_border_size or r-y_border_size gives an invalid row\n                - for all valid c such that c+x_border_size or c-x_border_size gives an invalid column \n                    - performs assign_pixel(#img[r][c],p) \n                      (i.e. assigns the given pixel to every pixel in the border of img)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_type& img,\n        long x_border_size,\n        long y_border_size\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view\n            - x_border_size >= 0\n            - y_border_size >= 0\n        ensures\n            - #img.nc() == img.nc()\n            - #img.nr() == img.nr()\n              (i.e. the size of img isn't changed by this function)\n            - for all valid r such that r+y_border_size or r-y_border_size gives an invalid row\n                - for all valid c such that c+x_border_size or c-x_border_size gives an invalid column \n                    - performs assign_pixel(#img[r][c], 0 ) \n                      (i.e. assigns 0 to every pixel in the border of img)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void zero_border_pixels (\n        image_type& img,\n        rectangle inside\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or an image_view\n        ensures\n            - #img.nc() == img.nc()\n            - #img.nr() == img.nr()\n              (i.e. the size of img isn't changed by this function)\n            - All the pixels in img that are not contained inside the inside rectangle\n              given to this function are set to 0.  That is, anything not \"inside\" is on\n              the border and set to 0.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ASSIGN_IMAGe_ABSTRACT\n\n\n"
  },
  {
    "path": "dlib/image_transforms/colormaps.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANDOMLY_COlOR_IMAGE_Hh_\n#define DLIB_RANDOMLY_COlOR_IMAGE_Hh_\n\n#include \"colormaps_abstract.h\"\n#include \"../hash.h\"\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_randomly_color_image : does_not_alias \n    {\n        op_randomly_color_image( const T& img_) : img(img_){}\n\n        const T& img;\n\n        const static long cost = 7;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef rgb_pixel type;\n        typedef const rgb_pixel const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const \n        { \n            const unsigned long gray = get_pixel_intensity(mat(img)(r,c));\n            if (gray != 0)\n            {\n                const uint32 h = murmur_hash3_2(gray,0);\n                rgb_pixel pix;\n                pix.red   = static_cast<unsigned char>(h)%200 + 55;\n                pix.green = static_cast<unsigned char>(h>>8)%200 + 55;\n                pix.blue  = static_cast<unsigned char>(h>>16)%200 + 55;\n                return pix;\n            }\n            else\n            {\n                // keep black pixels black\n                return rgb_pixel(0,0,0);\n            }\n        }\n\n        long nr () const { return num_rows(img); }\n        long nc () const { return num_columns(img); }\n    }; \n\n    template <\n        typename image_type\n        >\n    const matrix_op<op_randomly_color_image<image_type> >  \n    randomly_color_image (\n        const image_type& img\n    )\n    {\n        typedef op_randomly_color_image<image_type> op;\n        return matrix_op<op>(op(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rgb_pixel colormap_heat (\n        double value,\n        double min_val,\n        double max_val\n    )\n    {\n        // scale the gray value into the range [0, 1]\n        const double gray = put_in_range(0, 1, (value - min_val)/(max_val-min_val));\n        rgb_pixel pix(0,0,0);\n\n        pix.red = static_cast<unsigned char>(std::min(gray/0.4,1.0)*255 + 0.5);\n\n        if (gray > 0.4)\n        {\n            pix.green = static_cast<unsigned char>(std::min((gray-0.4)/0.4,1.0)*255 + 0.5);\n        }\n        if (gray > 0.8)\n        {\n            pix.blue = static_cast<unsigned char>(std::min((gray-0.8)/0.2,1.0)*255 + 0.5);\n        }\n\n        return pix;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_heatmap : does_not_alias \n    {\n        op_heatmap( \n            const T& img_,\n            const double max_val_,\n            const double min_val_\n            ) : img(img_), max_val(max_val_), min_val(min_val_){}\n\n        const T& img;\n\n        const double max_val;\n        const double min_val;\n\n        const static long cost = 7;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef rgb_pixel type;\n        typedef const rgb_pixel const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const \n        { \n            return colormap_heat(get_pixel_intensity(mat(img)(r,c)), min_val, max_val);\n        }\n\n        long nr () const { return num_rows(img); }\n        long nc () const { return num_columns(img); }\n    }; \n\n    template <\n        typename image_type\n        >\n    const matrix_op<op_heatmap<image_type> >  \n    heatmap (\n        const image_type& img,\n        double max_val,\n        double min_val = 0\n    )\n    {\n        typedef op_heatmap<image_type> op;\n        return matrix_op<op>(op(img,max_val,min_val));\n    }\n\n    template <\n        typename image_type\n        >\n    const matrix_op<op_heatmap<image_type> >  \n    heatmap (\n        const image_type& img\n    )\n    {\n        typedef op_heatmap<image_type> op;\n        if (num_columns(img) * num_rows(img) != 0)\n            return matrix_op<op>(op(img,max(mat(img)),min(mat(img))));\n        else\n            return matrix_op<op>(op(img,0,0));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rgb_pixel colormap_jet (\n        double value,\n        double min_val,\n        double max_val\n    )\n    {\n        // scale the gray value into the range [0, 8]\n        const double gray = 8*put_in_range(0, 1, (value - min_val)/(max_val-min_val));\n        rgb_pixel pix;\n        // s is the slope of color change\n        const double s = 1.0/2.0;\n\n        if (gray <= 1)\n        {\n            pix.red = 0;\n            pix.green = 0;\n            pix.blue = static_cast<unsigned char>((gray+1)*s*255 + 0.5);\n        }\n        else if (gray <= 3)\n        {\n            pix.red = 0;\n            pix.green = static_cast<unsigned char>((gray-1)*s*255 + 0.5);\n            pix.blue = 255;\n        }\n        else if (gray <= 5)\n        {\n            pix.red = static_cast<unsigned char>((gray-3)*s*255 + 0.5);\n            pix.green = 255;\n            pix.blue = static_cast<unsigned char>((5-gray)*s*255 + 0.5);\n        }\n        else if (gray <= 7)\n        {\n            pix.red = 255;\n            pix.green = static_cast<unsigned char>((7-gray)*s*255 + 0.5);\n            pix.blue = 0;\n        }\n        else\n        {\n            pix.red = static_cast<unsigned char>((9-gray)*s*255 + 0.5);\n            pix.green = 0;\n            pix.blue = 0;\n        }\n\n        return pix;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_jet : does_not_alias \n    {\n        op_jet( \n            const T& img_,\n            const double max_val_,\n            const double min_val_\n            ) : img(img_), max_val(max_val_), min_val(min_val_){}\n\n        const T& img;\n\n        const double max_val;\n        const double min_val;\n\n        const static long cost = 7;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef rgb_pixel type;\n        typedef const rgb_pixel const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const \n        { \n            return colormap_jet(get_pixel_intensity(mat(img)(r,c)), min_val, max_val);\n        }\n\n        long nr () const { return num_rows(img); }\n        long nc () const { return num_columns(img); }\n    }; \n\n    template <\n        typename image_type\n        >\n    const matrix_op<op_jet<image_type> >  \n    jet (\n        const image_type& img,\n        double max_val,\n        double min_val = 0\n    )\n    {\n        typedef op_jet<image_type> op;\n        return matrix_op<op>(op(img,max_val,min_val));\n    }\n\n    template <\n        typename image_type\n        >\n    const matrix_op<op_jet<image_type> >  \n    jet (\n        const image_type& img\n    )\n    {\n        typedef op_jet<image_type> op;\n        if (num_columns(img) * num_rows(img) != 0)\n            return matrix_op<op>(op(img,max(mat(img)),min(mat(img))));\n        else\n            return matrix_op<op>(op(img,0,0));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANDOMLY_COlOR_IMAGE_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/colormaps_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_\n#ifdef DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_\n\n#include \"../hash.h\"\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    const matrix_exp randomly_color_image (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h, or something convertible to a matrix\n              via mat().\n        ensures\n            - randomly generates a mapping from gray level pixel values\n              to the RGB pixel space and then uses this mapping to create\n              a colored version of img.  Returns a matrix which represents\n              this colored version of img.\n            - black pixels in img will remain black in the output image.  \n            - The returned matrix will have the same dimensions as img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    rgb_pixel colormap_heat (\n        double value,\n        double min_val,\n        double max_val\n    );\n    /*!\n        requires\n            - min_val <= max_val\n        ensures\n            - Maps value to a color.  In particular, we use a heatmap color scheme where\n              values <= min_val are black and larger values become more red, then yellow,\n              and then white as they approach max_val.\n    !*/\n\n    template <\n        typename image_type\n        >\n    const matrix_exp heatmap (\n        const image_type& img,\n        double max_val,\n        double min_val = 0\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h, or something convertible to a matrix\n              via mat().\n        ensures\n            - Interprets img as a grayscale image and returns a new matrix which represents\n              a colored version of img.  In particular, the colormap is defined by\n              out_color = colormap_heat(grayscale_pixel_value, min_val, max_val).\n            - The returned matrix will have the same dimensions as img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    const matrix_exp heatmap (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h, or something convertible to a matrix\n              via mat().\n        ensures\n            - returns heatmap(img, max(mat(img)), min(mat(img)))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    rgb_pixel colormap_jet (\n        double value,\n        double min_val,\n        double max_val\n    );\n    /*!\n        requires\n            - min_val <= max_val\n        ensures\n            - Maps value to a color.  In particular, we use a jet color scheme where \n              values <= min_val are dark blue and larger values become light blue, then\n              yellow, and then finally red as they approach max_val.\n    !*/\n\n    template <\n        typename image_type\n        >\n    const matrix_exp jet (\n        const image_type& img,\n        double max_val,\n        double min_val = 0\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h, or something convertible to a matrix\n              via mat().\n        ensures\n            - Interprets img as a grayscale image and returns a new matrix which represents\n              a colored version of img.  In particular, the colormap is defined by\n              out_color = colormap_jet(grayscale_pixel_value, min_val, max_val).\n            - The returned matrix will have the same dimensions as img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    const matrix_exp jet (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h, or something convertible to a matrix\n              via mat().\n        ensures\n            - returns jet(img, max(mat(img)), min(mat(img)))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANDOMLY_COlOR_IMAGE_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/draw.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_DRAW_IMAGe_\n#define DLIB_DRAW_IMAGe_\n\n#include \"draw_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n#include \"../gui_widgets/fonts.h\"\n#include \"../geometry.h\"\n#include <cmath>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_line (\n        long x1,\n        long y1,\n        long x2,\n        long y2,\n        image_type& c_,\n        const pixel_type& val\n    ) \n    {\n        image_view<image_type> c(c_);\n        if (x1 == x2)\n        {\n            // make sure y1 comes before y2\n            if (y1 > y2)\n                swap(y1,y2);\n\n            if (x1 < 0 || x1 >= c.nc())\n                return;\n\n\n            // this is a vertical line\n            for (long y = y1; y <= y2; ++y)\n            {\n                if (y < 0 || y >= c.nr())\n                    continue;\n\n                assign_pixel(c[y][x1], val);\n            }\n        }\n        else if (y1 == y2)\n        {\n\n            // make sure x1 comes before x2\n            if (x1 > x2)\n                swap(x1,x2);\n\n            if (y1 < 0 || y1 >= c.nr())\n                return;\n\n            // this is a horizontal line\n            for (long x = x1; x <= x2; ++x)\n            {\n                if (x < 0 || x >= c.nc())\n                    continue;\n\n                assign_pixel(c[y1][x] , val);\n            }\n        }\n        else\n        {\n            // This part is a little more complicated because we are going to perform alpha\n            // blending so the diagonal lines look nice.\n            const rectangle valid_area = get_rect(c);\n            rgb_alpha_pixel alpha_pixel;\n            assign_pixel(alpha_pixel, val);\n            const unsigned char max_alpha = alpha_pixel.alpha;\n\n            const long rise = (((long)y2) - ((long)y1));\n            const long run = (((long)x2) - ((long)x1));\n            if (std::abs(rise) < std::abs(run))\n            {\n                const double slope = ((double)rise)/run;\n\n\n                double first, last;\n\n\n                if (x1 > x2)                \n                {\n                    first = std::max(x2,valid_area.left());\n                    last = std::min(x1,valid_area.right());\n                }\n                else\n                {\n                    first = std::max(x1,valid_area.left());\n                    last = std::min(x2,valid_area.right());\n                }                             \n\n                long y;\n                long x;\n                const double x1f = x1;\n                const double y1f = y1;\n                for (double i = first; i <= last; ++i)\n                {   \n                    const double dy = slope*(i-x1f) + y1f;\n                    const double dx = i;\n\n                    y = static_cast<long>(dy);\n                    x = static_cast<long>(dx);\n\n\n                    if (y >= valid_area.top() && y <= valid_area.bottom())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dy-y))*max_alpha);\n                        assign_pixel(c[y][x], alpha_pixel);\n                    }\n                    if (y+1 >= valid_area.top() && y+1 <= valid_area.bottom())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((dy-y)*max_alpha);\n                        assign_pixel(c[y+1][x], alpha_pixel);\n                    }\n                }         \n            }\n            else\n            {\n                const double slope = ((double)run)/rise;\n\n\n                double first, last;\n\n\n                if (y1 > y2)                \n                {\n                    first = std::max(y2,valid_area.top());\n                    last = std::min(y1,valid_area.bottom());\n                }\n                else\n                {\n                    first = std::max(y1,valid_area.top());\n                    last = std::min(y2,valid_area.bottom());\n                }                             \n\n                long x;\n                long y;\n                const double x1f = x1;\n                const double y1f = y1;\n                for (double i = first; i <= last; ++i)\n                {   \n                    const double dx = slope*(i-y1f) + x1f;\n                    const double dy = i;\n\n                    y = static_cast<long>(dy);\n                    x = static_cast<long>(dx);\n\n                    if (x >= valid_area.left() && x <= valid_area.right())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((1.0-(dx-x))*max_alpha);\n                        assign_pixel(c[y][x], alpha_pixel);\n                    }\n                    if (x+1 >= valid_area.left() && x+1 <= valid_area.right())\n                    {\n                        alpha_pixel.alpha = static_cast<unsigned char>((dx-x)*max_alpha);\n                        assign_pixel(c[y][x+1], alpha_pixel);\n                    }\n                } \n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_line (\n        image_type& c,\n        const point& p1,\n        const point& p2,\n        const pixel_type& val\n    ) \n    {\n        draw_line(p1.x(),p1.y(),p2.x(),p2.y(),c,val);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_rectangle (\n        image_type& c,\n        const rectangle& rect,\n        const pixel_type& val\n    ) \n    {\n        draw_line(c, rect.tl_corner(), rect.tr_corner(), val);\n        draw_line(c, rect.bl_corner(), rect.br_corner(), val);\n        draw_line(c, rect.tl_corner(), rect.bl_corner(), val);\n        draw_line(c, rect.tr_corner(), rect.br_corner(), val);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_rectangle (\n        image_type& c,\n        const rectangle& rect,\n        const pixel_type& val,\n        unsigned int thickness\n    ) \n    {\n        for (unsigned int i = 0; i < thickness; ++i)\n        {\n            if ((i%2)==0)\n                draw_rectangle(c,shrink_rect(rect,(i+1)/2),val);\n            else\n                draw_rectangle(c,grow_rect(rect,(i+1)/2),val);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct string_dims\n    {\n        string_dims() = default;\n        string_dims (\n            unsigned long width,\n            unsigned long height\n        ) : width(width), height(height) {}\n        unsigned long width = 0;\n        unsigned long height = 0;\n    };\n\n    template <\n        typename T, typename traits,\n        typename alloc\n    >\n    string_dims compute_string_dims (\n        const std::basic_string<T, traits, alloc>& str,\n        const std::shared_ptr<font>& f_ptr = default_font::get_font()\n    )\n    {\n        using string = std::basic_string<T, traits, alloc>;\n\n        const font& f = *f_ptr;\n\n        long height = f.height();\n        long width = 0;\n        for (typename string::size_type i = 0; i < str.size(); ++i)\n        {\n            // ignore the '\\r' character\n            if (str[i] == '\\r')\n                continue;\n\n            // A combining character should be applied to the previous character, and we\n            // therefore make one step back. If a combining comes right after a newline,\n            // then there must be some kind of error in the string, and we don't combine.\n            if (is_combining_char(str[i]))\n            {\n                width -= f[str[i]].width();\n            }\n\n            if (str[i] == '\\n')\n            {\n                height += f.height();\n                width = f.left_overflow();\n                continue;\n            }\n\n            const letter& l = f[str[i]];\n            width += l.width();\n        }\n        return string_dims(width, height);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename traits,\n        typename alloc,\n        typename image_type,\n        typename pixel_type\n    >\n    void draw_string (\n        image_type& image,\n        const dlib::point& p,\n        const std::basic_string<T,traits,alloc>& str,\n        const pixel_type& color,\n        const std::shared_ptr<font>& f_ptr = default_font::get_font(),\n        typename std::basic_string<T,traits,alloc>::size_type first = 0,\n        typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)\n    )\n    {\n        using string = std::basic_string<T,traits,alloc>;\n        DLIB_ASSERT((last == string::npos) || (first <= last && last < str.size()),\n                    \"\\tvoid dlib::draw_string()\"\n                    << \"\\n\\tlast == string::npos: \" << ((last == string::npos)?\"true\":\"false\")\n                    << \"\\n\\tfirst: \" << (unsigned long)first\n                    << \"\\n\\tlast:  \" << (unsigned long)last\n                    << \"\\n\\tstr.size():  \" << (unsigned long)str.size());\n\n        if (last == string::npos)\n            last = str.size();\n\n        const rectangle rect(p, p);\n        const font& f = *f_ptr;\n        image_view<image_type> img(image);\n\n        long y_offset = rect.top() + f.ascender() - 1;\n\n        long pos = rect.left()+f.left_overflow();\n        convert_to_utf32(str.begin() + first, str.begin() + last, [&](unichar ch)\n        {\n            // ignore the '\\r' character\n            if (ch == '\\r')\n                return;\n\n            // A combining character should be applied to the previous character, and we\n            // therefore make one step back. If a combining comes right after a newline, \n            // then there must be some kind of error in the string, and we don't combine.\n            if(is_combining_char(ch) &&\n               pos > rect.left() + static_cast<long>(f.left_overflow()))\n            {\n                pos -= f[ch].width();\n            }\n\n            if (ch == '\\n')\n            {\n                y_offset += f.height();\n                pos = rect.left()+f.left_overflow();\n                return;\n            }\n\n            // only look at letters in the intersection area\n            if (img.nr() + static_cast<long>(f.height()) < y_offset)\n            {\n                // the string is now below our rectangle so we are done\n                return;\n            }\n            else if (0 > pos - static_cast<long>(f.left_overflow()) && \n                pos + static_cast<long>(f[ch].width() + f.right_overflow()) < 0)\n            {\n                pos += f[ch].width();\n                return;\n            }\n            else if (img.nc() + static_cast<long>(f.right_overflow()) < pos)\n            {\n                // keep looking because there might be a '\\n' in the string that\n                // will wrap us around and put us back into our rectangle.\n                return;\n            }\n\n            // at this point in the loop we know that f[str[i]] overlaps \n            // horizontally with the intersection rectangle area.\n\n            const letter& l = f[ch];\n            for (unsigned short i = 0; i < l.num_of_points(); ++i)\n            {\n                const long x = l[i].x + pos;\n                const long y = l[i].y + y_offset;\n                // draw each pixel of the letter if it is inside the intersection\n                // rectangle\n                if (x >= 0 && x < img.nc() && y >= 0 && y < img.nr())\n                {\n                    assign_pixel(img[y][x], color);\n                }\n            }\n\n            pos += l.width();\n        });\n\n    }\n\n    template <\n        typename image_type,\n        typename pixel_type\n    >\n    void draw_string (\n        image_type& image,\n        const dlib::point& p,\n        const char* str,\n        const pixel_type& color,\n        const std::shared_ptr<font>& f_ptr = default_font::get_font(),\n        typename std::string::size_type first = 0,\n        typename std::string::size_type last = std::string::npos\n    )\n    {\n        draw_string(image, p, std::string(str), color, f_ptr, first, last);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void fill_rect (\n        image_type& img_,\n        const rectangle& rect,\n        const pixel_type& pixel\n    )\n    {\n        image_view<image_type> img(img_);\n        rectangle area = rect.intersect(get_rect(img));\n\n        for (long r = area.top(); r <= area.bottom(); ++r)\n        {\n            for (long c = area.left(); c <= area.right(); ++c)\n            {\n                assign_pixel(img[r][c], pixel);\n            }\n        }\n    }\n\n// ---------------------------------------------------------------------------------------\n\n    template <typename image_type, typename pixel_type>\n    void draw_solid_convex_polygon (\n        image_type& image,\n        const polygon& poly,\n        const pixel_type& color,\n        const bool antialias = true,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        const rectangle image_rect = get_rect(image);\n        const rectangle bounding_box = poly.get_rect();\n        rectangle valid_area(image_rect.intersect(area));\n\n        // Don't do anything if the polygon is totally outside the area we can draw in\n        // right now.\n        if (bounding_box.intersect(valid_area).is_empty())\n            return;\n\n        image_view<image_type> img(image);\n        rgb_alpha_pixel alpha_pixel;\n        assign_pixel(alpha_pixel, color);\n        const unsigned char max_alpha = alpha_pixel.alpha;\n\n        // we will only want to loop over the part of left_boundary that is part of the\n        // valid_area.\n        valid_area = shrink_rect(valid_area.intersect(bounding_box), 1);\n\n        // Since we look at the adjacent rows of boundary information when doing the alpha\n        // blending, we want to make sure we always have some boundary information unless\n        // we are at the absolute edge of the polygon.\n        const long left_offset = (antialias && valid_area.left() == bounding_box.left()) ? 0 : 1;\n        const long top_offset = (antialias && valid_area.top() == bounding_box.top()) ? 0 : 1;\n        const long right_offset = (antialias && valid_area.right() == bounding_box.right()) ? 0 : 1;\n        const long bottom_offset = (antialias && valid_area.bottom() == bounding_box.bottom()) ? 0 : 1;\n        if (antialias)\n            valid_area = grow_rect(valid_area, 1).intersect(image_rect);\n\n        std::vector<double> left_boundary;\n        std::vector<double> right_boundary;\n        poly.get_left_and_right_bounds(valid_area.top(), valid_area.bottom(), left_boundary, right_boundary);\n\n        // draw the polygon row by row\n        for (unsigned long i = top_offset; i < left_boundary.size(); ++i)\n        {\n            long left_x = static_cast<long>(std::ceil(left_boundary[i]));\n            long right_x = static_cast<long>(std::floor(right_boundary[i]));\n\n            left_x = std::max(left_x, valid_area.left());\n            right_x = std::min(right_x, valid_area.right());\n\n            if (i < left_boundary.size() - bottom_offset)\n            {\n                // draw the main body of the polygon\n                for (long x = left_x + left_offset; x <= right_x - right_offset; ++x)\n                {\n                    const long y = i + valid_area.top();\n                    assign_pixel(img[y][x], color);\n                }\n            }\n\n            if (i == 0 || !antialias)\n                continue;\n\n            // Now draw anti-aliased edges so they don't look all pixely.\n\n            // Alpha blend the edges on the left side.\n            double delta = left_boundary[i-1] - left_boundary[i];\n            if (std::abs(delta) <= 1)\n            {\n                if (std::floor(left_boundary[i]) != left_x)\n                {\n                    const point p(static_cast<long>(std::floor(left_boundary[i])), i + valid_area.top());\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = max_alpha-static_cast<unsigned char>((left_boundary[i]-p.x())*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()], temp);\n                }\n            }\n            else if (delta < 0)  // on the bottom side\n            {\n                for (long x = static_cast<long>(std::ceil(left_boundary[i-1])); x < left_x; ++x)\n                {\n                    const point p(x, i+valid_area.top());\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i-1])/std::abs(delta)*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()], temp);\n                }\n            }\n            else // on the top side\n            {\n                const long old_left_x = static_cast<long>(std::ceil(left_boundary[i-1]));\n                for (long x = left_x; x < old_left_x; ++x)\n                {\n                    const point p(x, i + valid_area.top()-1);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((x-left_boundary[i])/delta*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()],temp);\n                }\n            }\n\n\n            // Alpha blend the edges on the right side\n            delta = right_boundary[i-1] - right_boundary[i];\n            if (std::abs(delta) <= 1)\n            {\n                if (std::ceil(right_boundary[i]) != right_x)\n                {\n                    const point p(static_cast<long>(std::ceil(right_boundary[i])), i + valid_area.top());\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = max_alpha-static_cast<unsigned char>((p.x()-right_boundary[i])*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()],temp);\n                }\n            }\n            else if (delta < 0) // on the top side\n            {\n                for (long x = static_cast<long>(std::floor(right_boundary[i-1]))+1; x <= right_x; ++x)\n                {\n                    const point p(x, i + valid_area.top() - 1);\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((right_boundary[i]-x)/std::abs(delta)*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()],temp);\n                }\n            }\n            else // on the bottom side\n            {\n                const long old_right_x = static_cast<long>(std::floor(right_boundary[i-1]));\n                for (long x = right_x+1; x <= old_right_x; ++x)\n                {\n                    const point p(x, i + valid_area.top());\n                    rgb_alpha_pixel temp = alpha_pixel;\n                    temp.alpha = static_cast<unsigned char>((right_boundary[i-1]-x)/delta*max_alpha);\n                    if (valid_area.contains(p))\n                        assign_pixel(img[p.y()][p.x()],temp);\n                }\n            }\n        }\n    }\n\n// ---------------------------------------------------------------------------------------\n\n    template <typename image_type, typename pixel_type>\n    void draw_solid_polygon (\n        image_type& image,\n        const polygon& poly,\n        const pixel_type& color,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    )\n    {\n        image_view<image_type> img(image);\n        rectangle valid_area(get_rect(image).intersect(area));\n        const rectangle bounding_box = poly.get_rect();\n        if (bounding_box.intersect(valid_area).is_empty())\n            return;\n\n        valid_area = shrink_rect(valid_area.intersect(bounding_box), 1);\n\n        std::vector<double> intersections;\n        for (long y = valid_area.top(); y <= valid_area.bottom(); ++y)\n        {\n            // Compute the intersections with the scanline.\n            intersections.clear();\n            for (size_t i = 0; i < poly.size(); ++i)\n            {\n                const auto& p1 = poly[i];\n                const auto& p2 = poly[(i + 1) % poly.size()];\n                // Skip horizontal edges\n                if (p1.y() == p2.y())\n                    continue;\n\n                // Skip if there are no intersections at this position\n                if ((y <= p1.y() && y <= p2.y()) || (y > p1.y() && y > p2.y()))\n                    continue;\n\n                // Add x coordinates of intersecting points\n                intersections.push_back(p1.x() + (y - p1.y()) * (p2.x() - p1.x()) / static_cast<double>(p2.y() - p1.y()));\n            }\n\n            std::sort(intersections.begin(), intersections.end());\n\n            for (size_t i = 0; i < intersections.size(); i += 2)\n            {\n                long left_x = static_cast<long>(std::ceil(intersections[i]));\n                long right_x = static_cast<long>(std::floor(intersections[i + 1]));\n                left_x = std::max(left_x, valid_area.left());\n                right_x = std::min(right_x, valid_area.right());\n\n                // Draw the main body of the polygon\n                for (long x = left_x; x <= right_x; ++x)\n                {\n                    assign_pixel(img[y][x], color);\n                }\n            }\n        }\n    }\n\n// ---------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    matrix<typename image_traits<typename image_array_type::value_type>::pixel_type> tile_images (\n        const image_array_type& images\n    )\n    {\n        typedef typename image_traits<typename image_array_type::value_type>::pixel_type T;\n\n        if (images.size() == 0)\n            return matrix<T>();\n\n        const unsigned long size_nc = square_root(images.size());\n        const unsigned long size_nr = (size_nc*(size_nc-1)>=images.size())? size_nc-1 : size_nc;\n        // Figure out the size we have to use for each chip in the big main image.  We will\n        // use the largest dimensions seen across all the chips.\n        long nr = 0;\n        long nc = 0;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            nr = std::max(num_rows(images[i]), nr);\n            nc = std::max(num_columns(images[i]), nc);\n        }\n\n        matrix<T> temp(size_nr*nr, size_nc*nc);\n        T background_color;\n        assign_pixel(background_color, 0);\n        temp = background_color;\n        unsigned long idx = 0;\n        for (unsigned long r = 0; r < size_nr; ++r)\n        {\n            for (unsigned long c = 0; c < size_nc; ++c)\n            {\n                if (idx < images.size())\n                {\n                    set_subm(temp, r*nr, c*nc, nr, nc) = mat(images[idx]);\n                }\n                ++idx;\n            }\n        }\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_solid_circle (\n        image_type& img_,\n        const dpoint& center_point,\n        double radius,\n        const pixel_type& pixel\n    )\n    {\n        image_view<image_type> img(img_);\n        using std::sqrt;\n        const rectangle valid_area(get_rect(img));\n        const double x = center_point.x();\n        const double y = center_point.y();\n        const point cp(center_point);\n        if (radius > 1)\n        {\n            long first_x = static_cast<long>(x - radius + 0.5);\n            long last_x = static_cast<long>(x + radius + 0.5);\n            const double rs = radius*radius;\n\n            // ensure that we only loop over the part of the x dimension that this\n            // image contains.\n            if (first_x < valid_area.left())\n                first_x = valid_area.left();\n            if (last_x > valid_area.right())\n                last_x = valid_area.right();\n\n            long top, bottom;\n\n            top = std::lround(sqrt(std::max(rs - (first_x-x-0.5)*(first_x-x-0.5),0.0)));\n            top += y;\n            long last = top;\n\n            // draw the left half of the circle\n            long middle = std::min(cp.x()-1,last_x);\n            for (long i = first_x; i <= middle; ++i)\n            {\n                double a = i - x + 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    draw_line(img_, point(i,top),point(i,bottom),pixel);\n                    --top;\n                }\n\n                last = temp;\n            }\n\n            middle = std::max(cp.x(),first_x);\n            top = std::lround(sqrt(std::max(rs - (last_x-x+0.5)*(last_x-x+0.5),0.0)));\n            top += y;\n            last = top;\n            // draw the right half of the circle\n            for (long i = last_x; i >= middle; --i)\n            {\n                double a = i - x - 0.5;\n                // find the top of the arc\n                top = std::lround(sqrt(std::max(rs - a*a,0.0)));\n                top += y;\n                long temp = top;\n\n                while(top >= last) \n                {\n                    bottom = y - top + y;\n                    draw_line(img_, point(i,top),point(i,bottom),pixel);\n                    --top;\n                }\n\n                last = temp;\n            }\n        }\n        else if (valid_area.contains(cp))\n        {\n            // For circles smaller than a pixel we will just alpha blend them in proportion\n            // to how small they are.\n            rgb_alpha_pixel temp;\n            assign_pixel(temp, pixel);\n            temp.alpha = static_cast<unsigned char>(255*radius + 0.5);\n            assign_pixel(img[cp.y()][cp.x()], temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAW_IMAGe_\n\n\n\n\n"
  },
  {
    "path": "dlib/image_transforms/draw_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_DRAW_IMAGe_ABSTRACT\n#ifdef DLIB_DRAW_IMAGe_ABSTRACT\n\n#include \"../matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_line (\n        image_type& img,\n        const point& p1,\n        const point& p2,\n        const pixel_type& val\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - #img.nr() == img.nr() && #img.nc() == img.nc()\n              (i.e. the dimensions of the input image are not changed)\n            - for all valid r and c that are on the line between point p1 and p2:\n                - performs assign_pixel(img[r][c], val)\n                  (i.e. it draws the line from p1 to p2 onto the image)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_line (\n        long x1,\n        long y1,\n        long x2,\n        long y2,\n        image_type& img,\n        const pixel_type& val\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs draw_line(img, point(x1,y1), point(x2,y2), val)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_rectangle (\n        image_type& img,\n        const rectangle& rect,\n        const pixel_type& val,\n        unsigned int thickness = 1\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws the given rectangle onto the image img.  It does this by calling\n              draw_line() four times to draw the four sides of the rectangle.  \n            - The rectangle is drawn with the color given by val.\n            - The drawn rectangle will have edges that are thickness pixels wide.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct string_dims\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents the size (width and height) of a\n                string in pixels.\n        !*/\n\n        string_dims() = default;\n        string_dims (\n            unsigned long width,\n            unsigned long height\n        ) : width(width), height(height) {}\n        unsigned long width = 0;\n        unsigned long height = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, typename traits,\n        typename alloc\n    >\n    string_dims compute_string_dims (\n        const std::basic_string<T, traits, alloc>& str,\n        const std::shared_ptr<font>& f_ptr = default_font::get_font()\n    )\n\n    /*!\n        ensures\n            - computes the size of the given string with the specified font in pixels.  To be very specific,\n              if dims is the returned object by this function, then:\n              - dims.width == width of the string\n              - dims.height == height of the string\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename traits,\n        typename alloc,\n        typename image_type,\n        typename pixel_type\n    >\n    void draw_string (\n        image_type& img,\n        const dlib::point& p,\n        const std::basic_string<T,traits,alloc>& str,\n        const pixel_type& val,\n        const std::shared_ptr<font>& f = default_font::get_font(),\n        typename std::basic_string<T,traits,alloc>::size_type first = 0,\n        typename std::basic_string<T,traits,alloc>::size_type last = (std::basic_string<T,traits,alloc>::npos)\n    );\n\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws the given string from first to last character onto the image img\n              starting from point p.\n            - The string is drawn with the color given by val and font f;\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void draw_solid_circle (\n        image_type& img,\n        const dpoint& center_point,\n        double radius,\n        const pixel_type& pixel\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws a fully filled in circle onto image that is centered at center_point\n              and has the given radius.  The circle will be filled by assigning the given\n              pixel value to each element of the circle.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename image_type,\n        typename pixel_type\n        >\n    void fill_rect (\n        image_type& img,\n        const rectangle& rect,\n        const pixel_type& pixel\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<pixel_type> is defined\n        ensures\n            - fills the area defined by rect in the given image with the given pixel value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type, typename pixel_type>\n    void draw_solid_convex_polygon (\n        image_type& image,\n        const polygon& poly,\n        const pixel_type& color,\n        const bool antialias = true,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Assigns all pixels in the given polygon with the given color.  Moreover, some regions\n              that are also in the convex hull of the polygon will also be filled as well.  In\n              particular, any row of pixels falling horizontally between two parts of the polygon\n              will be filled as well.\n            - When drawing the polygon, only the part of the polygon which overlaps both\n              the given image and area rectangle is drawn.\n            - Uses the given pixel color to draw the polygon.\n            - if (antialias == true) then we draw anti-aliased edges so they don't\n              look all pixely by alpha-blending them with the image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type, typename pixel_type>\n    void draw_solid_polygon (\n        image_type& image,\n        const polygon& poly,\n        const pixel_type& color,\n        const rectangle& area = rectangle(std::numeric_limits<long>::min(), std::numeric_limits<long>::min(),\n                                          std::numeric_limits<long>::max(), std::numeric_limits<long>::max())\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - pixel_traits<pixel_type> is defined\n        ensures\n            - Draws the given polygon onto the image, filling in the interior and edges of the\n              polygon.\n            - When drawing the polygon, only the part of the polygon which overlaps both\n              the given image and area rectangle is drawn.\n            - Uses the given pixel color to draw the polygon.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    matrix<typename image_traits<typename image_array_type::value_type>::pixel_type> tile_images (\n        const image_array_type& images\n    );\n    /*!\n        requires\n            - image_array_type is a dlib::array of image objects where each image object\n              implements the interface defined in dlib/image_processing/generic_image.h \n        ensures\n            - This function takes the given images and tiles them into a single large\n              square image and returns this new big tiled image.  Therefore, it is a useful\n              method to visualize many small images at once.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_DRAW_IMAGe_ABSTRACT\n\n\n"
  },
  {
    "path": "dlib/image_transforms/edge_detector.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_EDGE_DETECTOr_\n#define DLIB_EDGE_DETECTOr_\n\n#include \"edge_detector_abstract.h\"\n#include \"../pixel.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include <vector>\n#include \"../image_keypoint/build_separable_poly_filters.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    inline char edge_orientation (\n        const T& x_,\n        const T& y_\n    )\n    {\n\n        // if this is a perfectly horizontal gradient then return right away\n        if (x_ == 0)\n        {\n            return '|';\n        }\n        else if (y_ == 0) // if this is a perfectly vertical gradient then return right away\n        {\n            return '-';\n        }\n\n        // Promote x so that when we multiply by 128 later we know overflow won't happen.\n        typedef typename promote<T>::type type;\n        type x = x_;\n        type y = y_;\n\n        if (x < 0)\n        {\n            x = -x;\n            if (y < 0)\n            {\n                y = -y;\n                x *= 128;\n                const type temp = x/y;\n                if (temp > 309)\n                    return '-';\n                else if (temp > 53)\n                    return '/';\n                else\n                    return '|';\n            }\n            else\n            {\n                x *= 128;\n                const type temp = x/y;\n                if (temp > 309)\n                    return '-';\n                else if (temp > 53)\n                    return '\\\\';\n                else\n                    return '|';\n            }\n        }\n        else\n        {\n            if (y < 0)\n            {\n                y = -y;\n                x *= 128;\n\n                const type temp = x/y;\n                if (temp > 309)\n                    return '-';\n                else if (temp > 53)\n                    return '\\\\';\n                else\n                    return '|';\n            }\n            else\n            {\n                x *= 128;\n\n                const type temp = x/y;\n                if (temp > 309)\n                    return '-';\n                else if (temp > 53)\n                    return '/';\n                else\n                    return '|';\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void sobel_edge_detector (\n        const in_image_type& in_img_,\n        out_image_type& horz_,\n        out_image_type& vert_\n    )\n    {\n        typedef typename image_traits<out_image_type>::pixel_type pixel_type;\n        COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::is_unsigned == false);\n        DLIB_ASSERT( !is_same_object(in_img_,horz_) && !is_same_object(in_img_,vert_) &&\n                     !is_same_object(horz_,vert_),\n            \"\\tvoid sobel_edge_detector(in_img_, horz_, vert_)\"\n            << \"\\n\\t You can't give the same image as more than one argument\"\n            << \"\\n\\t is_same_object(in_img_,horz_): \" << is_same_object(in_img_,horz_)\n            << \"\\n\\t is_same_object(in_img_,vert_): \" << is_same_object(in_img_,vert_)\n            << \"\\n\\t is_same_object(horz_,vert_):    \" << is_same_object(horz_,vert_)\n            );\n\n\n        const int vert_filter[3][3] = {{-1,-2,-1}, \n        {0,0,0}, \n        {1,2,1}};\n        const int horz_filter[3][3] = { {-1,0,1}, \n        {-2,0,2}, \n        {-1,0,1}};\n\n        const long M = 3;\n        const long N = 3;\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> horz(horz_);\n        image_view<out_image_type> vert(vert_);\n\n        horz.set_size(in_img.nr(),in_img.nc());\n        vert.set_size(in_img.nr(),in_img.nc());\n\n        assign_border_pixels(horz,1,1,0);\n        assign_border_pixels(vert,1,1,0);\n\n        // figure out the range that we should apply the filter to\n        const long first_row = M/2;\n        const long first_col = N/2;\n        const long last_row = in_img.nr() - M/2;\n        const long last_col = in_img.nc() - N/2;\n\n\n        // apply the filter to the image\n        for (long r = first_row; r < last_row; ++r)\n        {\n            for (long c = first_col; c < last_col; ++c)\n            {\n                typedef typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type bp_type;\n\n                typename promote<bp_type>::type p, horz_temp, vert_temp;\n                horz_temp = 0;\n                vert_temp = 0;\n                for (long m = 0; m < M; ++m)\n                {\n                    for (long n = 0; n < N; ++n)\n                    {\n                        // pull out the current pixel and put it into p\n                        p = get_pixel_intensity(in_img[r-M/2+m][c-N/2+n]);\n\n                        horz_temp += p*horz_filter[m][n];\n                        vert_temp += p*vert_filter[m][n];\n                    }\n                }\n\n                assign_pixel(horz[r][c] , horz_temp);\n                assign_pixel(vert[r][c] , vert_temp);\n\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        typename promote<T>::type square (const T& a)\n        { \n            return static_cast<T>(a)*static_cast<T>(a); \n        }\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void suppress_non_maximum_edges (\n        const in_image_type& horz_,\n        const in_image_type& vert_,\n        out_image_type& out_img_\n    )\n    {\n        const_image_view<in_image_type> horz(horz_);\n        const_image_view<in_image_type> vert(vert_);\n        image_view<out_image_type> out_img(out_img_);\n\n        COMPILE_TIME_ASSERT(is_signed_type<typename image_traits<in_image_type>::pixel_type>::value);\n        DLIB_ASSERT( horz.nr() == vert.nr() && horz.nc() == vert.nc(),\n            \"\\tvoid suppress_non_maximum_edges(horz, vert, out_img)\"\n            << \"\\n\\tYou have to give horz and vert gradient images that are the same size\"\n            << \"\\n\\thorz.nr():   \" << horz.nr() \n            << \"\\n\\thorz.nc():   \" << horz.nc() \n            << \"\\n\\tvert.nr():   \" << vert.nr() \n            << \"\\n\\tvert.nc():   \" << vert.nc() \n            );\n        DLIB_ASSERT( !is_same_object(out_img_,horz_) && !is_same_object(out_img_,vert_),\n            \"\\tvoid suppress_non_maximum_edges(horz_, vert_, out_img_)\"\n            << \"\\n\\t out_img can't be the same as one of the input images.\"\n            << \"\\n\\t is_same_object(out_img_,horz_):    \" << is_same_object(out_img_,horz_)\n            << \"\\n\\t is_same_object(out_img_,vert_):    \" << is_same_object(out_img_,vert_)\n            );\n\n        using std::min;\n        using std::abs;\n\n\n        // if there isn't any input image then don't do anything\n        if (horz.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(horz.nr(),horz.nc());\n\n        zero_border_pixels(out_img,1,1);\n\n        // now do non maximum suppression while we copy the \n        const long M = 3;\n        const long N = 3;\n\n        // figure out the range that we should apply the filter to\n        const long first_row = M/2;\n        const long first_col = N/2;\n        const long last_row = horz.nr() - M/2;\n        const long last_col = horz.nc() - N/2;\n\n\n        // apply the filter to the image\n        for (long r = first_row; r < last_row; ++r)\n        {\n            for (long c = first_col; c < last_col; ++c)\n            {\n                typedef typename promote<typename image_traits<in_image_type>::pixel_type>::type T;\n                const T y = horz[r][c];\n                const T x = vert[r][c];\n\n                using impl::square;\n\n                const T val = square(horz[r][c]) + square(vert[r][c]); \n\n                const char ori = edge_orientation(x,y);\n                const unsigned char zero = 0;\n                switch (ori)\n                {\n                    case '-':\n                        if (square(horz[r-1][c])+square(vert[r-1][c]) > val || square(horz[r+1][c]) + square(vert[r+1][c]) > val)\n                            assign_pixel(out_img[r][c] , zero);\n                        else\n                            assign_pixel(out_img[r][c] , std::sqrt((double)val));\n                        break;\n\n                    case '|':\n                        if (square(horz[r][c-1]) + square(vert[r][c-1]) > val || square(horz[r][c+1]) + square(vert[r][c+1]) > val)\n                            assign_pixel(out_img[r][c] , zero);\n                        else\n                            assign_pixel(out_img[r][c] , std::sqrt((double)val));\n                        break;\n\n                    case '/':\n                        if (square(horz[r-1][c-1]) + square(vert[r-1][c-1]) > val || square(horz[r+1][c+1]) + square(vert[r+1][c+1]) > val)\n                            assign_pixel(out_img[r][c] , zero);\n                        else\n                            assign_pixel(out_img[r][c] , std::sqrt((double)val));\n                        break;\n\n                    case '\\\\':\n                        if (square(horz[r+1][c-1]) + square(vert[r+1][c-1]) > val || square(horz[r-1][c+1]) + square(vert[r-1][c+1]) > val)\n                            assign_pixel(out_img[r][c] , zero);\n                        else\n                            assign_pixel(out_img[r][c] , std::sqrt((double)val));\n                        break;\n\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void normalize_image_gradients (\n        image_type& img1_,\n        image_type& img2_\n    )\n    {\n        image_view<image_type> img1(img1_);\n        image_view<image_type> img2(img2_);\n\n        using pixel_type = typename image_traits<image_type>::pixel_type;\n        static_assert(std::is_same<pixel_type,float>::value || \n            std::is_same<pixel_type,double>::value ||\n            std::is_same<pixel_type,long double>::value, \n            \"normalize_image_gradients() requires the input images to use floating point pixel types.\");\n\n        DLIB_CASSERT(img1.nr() == img2.nr());\n        DLIB_CASSERT(img1.nc() == img2.nc());\n\n        // normalize all the gradients\n        for (long r = 0; r < img1.nr(); ++r)\n        {\n            for (long c = 0; c < img1.nc(); ++c)\n            {\n                if (img1[r][c] != 0 || img2[r][c] != 0)\n                {\n                    double len = std::sqrt(img1[r][c]*img1[r][c] + img2[r][c]*img2[r][c]);\n                    img1[r][c] /= len;\n                    img2[r][c] /= len;\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> remove_incoherent_edge_pixels (\n        const std::vector<point>& line,\n        const image_type& horz_gradient_,\n        const image_type& vert_gradient_,\n        double angle_threshold\n    )\n    {\n        const_image_view<image_type> horz_gradient(horz_gradient_);\n        const_image_view<image_type> vert_gradient(vert_gradient_);\n\n        DLIB_CASSERT(horz_gradient.nr() == vert_gradient.nr());\n        DLIB_CASSERT(horz_gradient.nc() == vert_gradient.nc());\n        DLIB_CASSERT(angle_threshold >= 0);\n#ifdef ENABLE_ASSERTS\n        for (auto& p : line)\n            DLIB_ASSERT(get_rect(horz_gradient).contains(p), \"All line points must be inside the given images.\");\n#endif\n\n        // We make sure that each vector is within this threshold of the mean vector.  So\n        // to make sure they are pairwise within the user supplied angel threshold we need\n        // to divide by 2 before we proceed.\n        angle_threshold /= 2;\n\n        const double dotthresh = std::cos(angle_threshold*pi/180);\n        // find the average gradient on this line\n        dpoint avg;\n        for (auto p : line)\n            avg += dpoint(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]);\n        dpoint ref = avg.normalize();\n\n        // now iterate a few times and find the most common average gradient.\n        for (int i = 0; i < 10; ++i)\n        {\n            avg = dpoint();\n            for (auto p : line)\n            {\n                const dpoint v(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]);\n                const double dp = ref.dot(v);\n                if (dp > dotthresh)\n                    avg += v;\n                else if (-dp > dotthresh)\n                    avg -= v;\n            }\n            ref = avg.normalize();\n        }\n\n        // now remove all the points that deviate from the average gradient too much.\n        std::vector<point> newpixels;\n        for (auto p : line)\n        {\n            dpoint v(horz_gradient[p.y()][p.x()], vert_gradient[p.y()][p.x()]);\n            if (std::abs(ref.dot(v)) > dotthresh)\n                newpixels.push_back(p);\n        }\n        return newpixels;\n    }\n\n    template <\n        typename image_type\n        >\n    std::vector<std::vector<point>> remove_incoherent_edge_pixels (\n        const std::vector<std::vector<point>>& line_pixels,\n        const image_type& horz_gradient_,\n        const image_type& vert_gradient_,\n        const double angle_threshold\n    )\n    {\n        std::vector<std::vector<point>> temp;\n        temp.reserve(line_pixels.size());\n        for (auto& line : line_pixels)\n            temp.emplace_back(remove_incoherent_edge_pixels(line, horz_gradient_, vert_gradient_, angle_threshold));\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class image_gradients\n    {\n\n    public:\n\n        image_gradients (\n        ) : image_gradients(1) {}\n\n        image_gradients (\n            long scale\n        ) : the_scale(scale)\n        {\n            DLIB_CASSERT(scale >= 1);\n\n            scale = 2*scale+1;\n\n            auto dfilters = build_separable_poly_filters(2,scale); \n            DLIB_CASSERT(dfilters[1].size() == 1);\n            DLIB_CASSERT(dfilters[2].size() == 1);\n            DLIB_CASSERT(dfilters[3].size() == 1);\n            DLIB_CASSERT(dfilters[4].size() == 1);\n            DLIB_CASSERT(dfilters[5].size() == 1);\n\n            filter_x.first = matrix_cast<float>(dfilters[1][0].first);\n            filter_x.second = matrix_cast<float>(dfilters[1][0].second);\n\n            filter_y.first = matrix_cast<float>(dfilters[2][0].first);\n            filter_y.second = matrix_cast<float>(dfilters[2][0].second);\n\n            // We multiply by 2 so that the filter gives the gradient rather than the x^2\n            // polynomial coefficient.\n            filter_xx.first = 2*matrix_cast<float>(dfilters[3][0].first);\n            filter_xx.second = matrix_cast<float>(dfilters[3][0].second);\n\n            filter_xy.first = matrix_cast<float>(dfilters[4][0].first);\n            filter_xy.second = matrix_cast<float>(dfilters[4][0].second);\n\n            // We multiply by 2 so that the filter gives the gradient rather than the y^2\n            // polynomial coefficient.\n            filter_yy.first = 2*matrix_cast<float>(dfilters[5][0].first);\n            filter_yy.second = matrix_cast<float>(dfilters[5][0].second);\n        }\n\n\n        long get_scale() const { return the_scale; }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_x(\n            const in_image_type& img,\n            out_image_type& out\n        ) const \n        { \n            return spatially_filter_image_separable(img, out, filter_x.second, filter_x.first); \n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_y(\n            const in_image_type& img,\n            out_image_type& out\n        ) const \n        { \n            return spatially_filter_image_separable(img, out, filter_y.second, filter_y.first); \n        }\n\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_xx(\n            const in_image_type& img,\n            out_image_type& out\n        )  const\n        { \n            return spatially_filter_image_separable(img, out, filter_xx.second, filter_xx.first); \n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_xy(\n            const in_image_type& img,\n            out_image_type& out\n        ) const \n        { \n            return spatially_filter_image_separable(img, out, filter_xy.second, filter_xy.first); \n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_yy(\n            const in_image_type& img,\n            out_image_type& out\n        ) const\n        { \n            return spatially_filter_image_separable(img, out, filter_yy.second, filter_yy.first); \n        }\n\n        matrix<float> get_x_filter()  const { return filter_x.first*trans(filter_x.second); }\n        matrix<float> get_y_filter()  const { return filter_y.first*trans(filter_y.second); }\n        matrix<float> get_xx_filter() const { return filter_xx.first*trans(filter_xx.second); }\n        matrix<float> get_xy_filter() const { return filter_xy.first*trans(filter_xy.second); }\n        matrix<float> get_yy_filter() const { return filter_yy.first*trans(filter_yy.second); }\n\n    private:\n        std::pair<matrix<float,0,1>,matrix<float,0,1>> filter_x;\n        std::pair<matrix<float,0,1>,matrix<float,0,1>> filter_y;\n        std::pair<matrix<float,0,1>,matrix<float,0,1>> filter_xx;\n        std::pair<matrix<float,0,1>,matrix<float,0,1>> filter_xy;\n        std::pair<matrix<float,0,1>,matrix<float,0,1>> filter_yy;\n\n        long the_scale;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void find_lines(\n            const in_image_type& xx_,\n            const in_image_type& xy_,\n            const in_image_type& yy_,\n            out_image_type& horz_,\n            out_image_type& vert_,\n            double positive_if_should_find_dark_lines\n        )\n        {\n            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n            static_assert(std::is_same<float,out_pixel_type>::value || std::is_same<double,out_pixel_type>::value,\n                \"Output images must contain either float or double valued pixels\");\n\n            const_image_view<in_image_type> xx(xx_);\n            const_image_view<in_image_type> xy(xy_);\n            const_image_view<in_image_type> yy(yy_);\n\n            DLIB_CASSERT(xx.nr() == xy.nr());\n            DLIB_CASSERT(xx.nr() == yy.nr());\n            DLIB_CASSERT(xx.nc() == xy.nc());\n            DLIB_CASSERT(xx.nc() == yy.nc());\n\n\n            image_view<out_image_type> x(horz_);\n            image_view<out_image_type> y(vert_);\n\n            x.set_size(xx.nr(), xx.nc());\n            y.set_size(xx.nr(), xx.nc());\n\n\n            // store the max eigenvalue into xy and then the associated eigen vector into [xx,yy]\n            for (long r = 0; r < xx.nr(); ++r)\n            {\n                for (long c = 0; c < xx.nc(); ++c)\n                {\n                    // negate to that lambda will be the *minimum* eigenvalue\n                    double w1 = positive_if_should_find_dark_lines*xx[r][c]/2.0;\n                    double w2 = positive_if_should_find_dark_lines*yy[r][c]/2.0;\n                    double w3 = positive_if_should_find_dark_lines*xy[r][c];\n\n\n                    auto lambda = w1 + w2 + std::sqrt((w1-w2)*(w1-w2) + w3*w3);\n                    if (lambda < 0)\n                        lambda = 0;\n\n                    if (2*w1!=lambda)\n                    {\n                        x[r][c] = -w3/(2*w1-lambda);\n                        y[r][c] = 1;\n\n                        double norm = std::sqrt(x[r][c]*x[r][c] + y[r][c]*y[r][c]);\n                        x[r][c] *= lambda/norm;\n                        y[r][c] *= lambda/norm;\n                    }\n                    else\n                    {\n                        x[r][c] = lambda;\n                        y[r][c] = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_bright_lines(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& horz,\n        out_image_type& vert\n    )\n    {\n        impl::find_lines(xx,xy,yy,horz,vert,-1);\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_dark_lines(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& horz,\n        out_image_type& vert\n    )\n    {\n        impl::find_lines(xx,xy,yy,horz,vert,+1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_bright_keypoints(\n        const in_image_type& xx_,\n        const in_image_type& xy_,\n        const in_image_type& yy_,\n        out_image_type& saliency_\n    )\n    {\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        static_assert(std::is_same<float,out_pixel_type>::value || std::is_same<double,out_pixel_type>::value,\n            \"Output images must contain either float or double valued pixels\");\n\n        const_image_view<in_image_type> xx(xx_);\n        const_image_view<in_image_type> xy(xy_);\n        const_image_view<in_image_type> yy(yy_);\n\n        DLIB_CASSERT(xx.nr() == xy.nr());\n        DLIB_CASSERT(xx.nr() == yy.nr());\n        DLIB_CASSERT(xx.nc() == xy.nc());\n        DLIB_CASSERT(xx.nc() == yy.nc());\n\n\n        image_view<out_image_type> saliency(saliency_);\n        saliency.set_size(xx.nr(), xx.nc());\n\n\n        for (long r = 0; r < xx.nr(); ++r)\n        {\n            for (long c = 0; c < xx.nc(); ++c)\n            {\n                matrix<double,2,2> tmp;\n                tmp = xx[r][c], xy[r][c],\n                      xy[r][c], yy[r][c];\n\n                matrix<double,2,1> e = real_eigenvalues(tmp);\n                saliency[r][c] = prod(upperbound(e,0));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_dark_keypoints(\n        const in_image_type& xx_,\n        const in_image_type& xy_,\n        const in_image_type& yy_,\n        out_image_type& saliency_\n    )\n    {\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        static_assert(std::is_same<float,out_pixel_type>::value || std::is_same<double,out_pixel_type>::value,\n            \"Output images must contain either float or double valued pixels\");\n\n        const_image_view<in_image_type> xx(xx_);\n        const_image_view<in_image_type> xy(xy_);\n        const_image_view<in_image_type> yy(yy_);\n\n        DLIB_CASSERT(xx.nr() == xy.nr());\n        DLIB_CASSERT(xx.nr() == yy.nr());\n        DLIB_CASSERT(xx.nc() == xy.nc());\n        DLIB_CASSERT(xx.nc() == yy.nc());\n\n\n        image_view<out_image_type> saliency(saliency_);\n        saliency.set_size(xx.nr(), xx.nc());\n\n\n        for (long r = 0; r < xx.nr(); ++r)\n        {\n            for (long c = 0; c < xx.nc(); ++c)\n            {\n                matrix<double,2,2> tmp;\n                tmp = xx[r][c], xy[r][c],\n                      xy[r][c], yy[r][c];\n\n                matrix<double,2,1> e = real_eigenvalues(tmp);\n                saliency[r][c] = prod(lowerbound(e,0));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EDGE_DETECTOr_\n\n\n\n"
  },
  {
    "path": "dlib/image_transforms/edge_detector_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_EDGE_DETECTOr_ABSTRACT_\n#ifdef DLIB_EDGE_DETECTOr_ABSTRACT_\n\n#include \"../pixel.h\"\n#include \"../image_processing/generic_image.h\"\n#include \"../geometry.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    inline char edge_orientation (\n        const T& x,\n        const T& y\n    );\n    /*!\n        ensures\n            - returns the orientation of the line drawn from the origin to the point (x,y).\n              The orientation is represented pictorially using the four ascii \n              characters /,|,\\, and -.\n            - if (the line is horizontal) then \n                returns '-' \n            - if (the line is vertical) then \n                returns '|' \n            - if (the line is diagonal with a positive slope) then \n                returns '/' \n            - if (the line is diagonal with a negative slope) then \n                returns '\\\\' \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void sobel_edge_detector (\n        const in_image_type& in_img,\n        out_image_type& horz,\n        out_image_type& vert\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type must use signed grayscale pixels\n            - is_same_object(in_img,horz) == false\n            - is_same_object(in_img,vert) == false\n            - is_same_object(horz,vert) == false\n        ensures\n            - Applies the sobel edge detector to the given input image and stores the resulting\n              edge detections in the horz and vert images\n            - #horz.nr() == in_img.nr()\n            - #horz.nc() == in_img.nc()\n            - #vert.nr() == in_img.nr()\n            - #vert.nc() == in_img.nc()\n            - for all valid r and c:    \n                - #horz[r][c] == the magnitude of the horizontal gradient at the point in_img[r][c]\n                - #vert[r][c] == the magnitude of the vertical gradient at the point in_img[r][c]\n                - edge_orientation(#vert[r][c], #horz[r][c]) == the edge direction at this point in \n                  the image\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void suppress_non_maximum_edges (\n        const in_image_type& horz,\n        const in_image_type& vert,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - horz.nr() == vert.nr()\n            - horz.nc() == vert.nc()\n            - is_same_object(out_img, horz) == false\n            - is_same_object(out_img, vert) == false\n            - image_traits<in_image_type>::pixel_type == A signed scalar type (e.g. int, double, etc.) \n        ensures\n            - #out_img.nr() = horz.nr()\n            - #out_img.nc() = horz.nc()\n            - let edge_strength(r,c) == sqrt(pow(horz[r][c],2) + pow(vert[r][c],2))\n              (i.e. The Euclidean norm of the gradient)\n            - for all valid r and c:\n                - if (edge_strength(r,c) is at a maximum with respect to its 2 neighboring\n                  pixels along the line given by edge_orientation(vert[r][c],horz[r][c])) then\n                    - performs assign_pixel(#out_img[r][c], edge_strength(r,c))\n                - else\n                    - performs assign_pixel(#out_img[r][c], 0)\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void normalize_image_gradients (\n        image_type& img1,\n        image_type& img2 \n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type contains float, double, or long double pixels.\n            - img1.nr() == img2.nr()\n            - img1.nc() == img2.nc()\n        ensures\n            - #out_img.nr() = img1.nr()\n            - #out_img.nc() = img1.nc()\n            - This function assumes img1 and img2 are the two gradient images produced by a\n              function like sobel_edge_detector().  It then unit normalizes the gradient\n              vectors. That is, for all valid r and c, this function ensures that:\n                - img1[r][c]*img1[r][c] + img2[r][c]*img2[r][c] == 1 \n                  unless both img1[r][c] and img2[r][c] were 0 initially, then they stay zero.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> remove_incoherent_edge_pixels (\n        const std::vector<point>& line,\n        const image_type& horz_gradient,\n        const image_type& vert_gradient,\n        const double angle_threshold\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type contains float, double, or long double pixels.\n            - horz_gradient.nr() == vert_gradient.nr()\n            - horz_gradient.nc() == vert_gradient.nc()\n            - horz_gradient and vert_gradient represent unit normalized vectors.  That is,\n              you should have called normalize_image_gradients(horz_gradient,vert_gradient)\n              or otherwise caused all the gradients to have unit norm.\n            - for all valid i:\n                get_rect(horz_gradient).contains(line[i])\n        ensures\n            - This routine looks at all the points in the given line and discards the ones that\n              have outlying gradient directions.  To be specific, this routine returns a set\n              of points PTS such that: \n                - for all valid i,j:\n                    - The difference in angle between the gradients for PTS[i] and PTS[j] is \n                      less than angle_threshold degrees.  \n                - PTS.size() <= line.size()\n                - PTS is just line with some elements removed.\n    !*/\n\n    template <\n        typename image_type\n        >\n    std::vector<std::vector<point>> remove_incoherent_edge_pixels (\n        const std::vector<std::vector<point>>& lines,\n        const image_type& horz_gradient,\n        const image_type& vert_gradient,\n        const double angle_threshold\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type contains float, double, or long double pixels.\n            - horz_gradient.nr() == vert_gradient.nr()\n            - horz_gradient.nc() == vert_gradient.nc()\n            - horz_gradient and vert_gradient represent unit normalized vectors.  That is,\n              you should have called normalize_image_gradients(horz_gradient,vert_gradient)\n              or otherwise caused all the gradients to have unit norm.\n            - for all valid i,j:\n                get_rect(horz_gradient).contains(lines[i][j])\n        ensures\n            - Returns a vector LINES where:\n                - LINES.size() == lines.size()\n                - LINES[i] == remove_incoherent_edge_pixels(lines[i], horz_gradient, vert_gradient, angle_threshold)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class image_gradients\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This class is a tool for computing first and second derivatives of an\n                image.  It does this by fitting a quadratic surface around each pixel and\n                then computing the gradients of that quadratic surface.  For the details\n                see the paper:\n                    Quadratic models for curved line detection in SAR CCD by Davis E. King\n                    and Rhonda D. Phillips\n\n                This technique gives very accurate gradient estimates and is also very fast\n                since the entire gradient estimation procedure, for each type of gradient,\n                is accomplished by cross-correlating the image with a single separable\n                filter.  This means you can compute gradients at very large scales (e.g. by\n                fitting the quadratic to a large window, like a 99x99 window) and it still\n                runs very quickly.\n        !*/\n\n    public:\n\n        image_gradients (\n        );\n        /*!\n            ensures\n                - #get_scale() == 1\n        !*/\n\n        image_gradients (\n            long scale\n        ); \n        /*!\n            requires\n                - scale >= 1\n            ensures\n                - #get_scale() == scale\n        !*/\n\n        long get_scale(\n        ) const;\n        /*!\n            ensures\n                - When we estimate a gradient we do so by fitting a quadratic filter to a\n                  window of size get_scale()*2+1 centered on each pixel.  Therefore, the\n                  scale parameter controls the size of gradients we will find.  For\n                  example, a very large scale will cause the gradient_xx() to be\n                  insensitive to high frequency noise in the image while smaller scales\n                  would be more sensitive to such fluctuations in the image.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_x(\n            const in_image_type& img,\n            out_image_type& out\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - out_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - img and out do not contain pixels with an alpha channel.  That is,\n                  pixel_traits::has_alpha is false for the pixels in these objects.\n                - is_same_object(img, out) == false \n                - out_image_type must use signed grayscale pixels\n            ensures\n                - Let VALID_AREA = shrink_rect(get_rect(img),get_scale()).\n                - Computes the 1st order gradient of img in the x direction at each\n                  location in VALID_AREA.  The gradients are stored in out.  All pixels in\n                  #out that are outside VALID_AREA are set to 0.\n                - #num_rows(out) == num_rows(img)\n                - #num_columns(out) == num_columns(img)\n                - While not a requirement, it is a good idea if the output image contains\n                  float or double pixels.  If get_scale() is small then this is less of an\n                  issue, but at large scales the gradient can easily be a small number\n                  which is not well represented by integer pixel type such as short. Also,\n                  if you use float pixels in the input and output images then this routine\n                  will use SIMD instructions and is particularly fast.\n                - returns VALID_AREA.  That is, returns the part of the output image which\n                  contains actual valid gradient values.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_y(\n            const in_image_type& img,\n            out_image_type& out\n        ) const;\n        /*!\n            This routine is identical to gradient_x() (defined above) except that it\n            computes the 1st order y gradient.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_xx(\n            const in_image_type& img,\n            out_image_type& out\n        )  const;\n        /*!\n            This routine is identical to gradient_x() (defined above) except that it\n            computes the 2nd order x gradient. \n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_xy(\n            const in_image_type& img,\n            out_image_type& out\n        ) const;\n        /*!\n            This routine is identical to gradient_x() (defined above) except that it\n            computes the partial derivative with respect to x and y.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        rectangle gradient_yy(\n            const in_image_type& img,\n            out_image_type& out\n        ) const;\n        /*!\n            This routine is identical to gradient_x() (defined above) except that it\n            computes the 2nd order y gradient. \n        !*/\n\n        matrix<float> get_x_filter(\n        )  const; \n        /*!\n            ensures\n                - Returns the filter used by gradient_x() to compute the image gradient.\n                  That is, the output of gradient_x() is found by cross correlating the\n                  filter get_x_filter() with the image.\n                - The returned filter has get_scale()*2+1 rows and columns.\n        !*/\n\n        matrix<float> get_y_filter(\n        )  const; \n        /*!\n            ensures\n                - Returns the filter used by gradient_y() to compute the image gradient.\n                  That is, the output of gradient_y() is found by cross correlating the\n                  filter get_y_filter() with the image.\n                - The returned filter has get_scale()*2+1 rows and columns.\n        !*/\n\n        matrix<float> get_xx_filter(\n        ) const; \n        /*!\n            ensures\n                - Returns the filter used by gradient_xx() to compute the image gradient.\n                  That is, the output of gradient_xx() is found by cross correlating the\n                  filter get_xx_filter() with the image.\n                - The returned filter has get_scale()*2+1 rows and columns.\n        !*/\n\n\n        matrix<float> get_xy_filter(\n        ) const; \n        /*!\n            ensures\n                - Returns the filter used by gradient_xy() to compute the image gradient.\n                  That is, the output of gradient_xy() is found by cross correlating the\n                  filter get_xy_filter() with the image.\n                - The returned filter has get_scale()*2+1 rows and columns.\n        !*/\n\n\n        matrix<float> get_yy_filter(\n        ) const; \n        /*!\n            ensures\n                - Returns the filter used by gradient_yy() to compute the image gradient.\n                  That is, the output of gradient_yy() is found by cross correlating the\n                  filter get_yy_filter() with the image.\n                - The returned filter has get_scale()*2+1 rows and columns.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_bright_lines(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& horz,\n        out_image_type& vert\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - All images are grayscale and the horz and vert images must contain float or\n              double pixel types.\n            - num_rows(xx) == num_rows(xy) == num_rows(yy)\n            - num_columns(xx) == num_columns(xy) == num_columns(yy)\n        ensures\n            - This routine is similar to sobel_edge_detector(), except instead of finding\n              an edge it finds a bright/white line.  For example, the border between a\n              black piece of paper and a white table is an edge, but a curve drawn with a\n              pencil on a piece of paper makes a line.  Therefore, the output of this\n              routine is a vector field encoded in the horz and vert images.  The vector\n              obtains a large magnitude when centered on a bright line in an image and the\n              direction of the vector is perpendicular to the line.  To be very precise,\n              each vector points in the direction of greatest change in second derivative\n              and the magnitude of the vector encodes the derivative magnitude in that\n              direction.  Moreover, if the second derivative is positive then the output\n              vector is zero.  This zeroing if positive gradients causes the output to be\n              sensitive only to bright lines surrounded by darker pixels.\n            - We assume that xx, xy, and yy are the 3 second order gradients of the image\n              in question.  You can obtain these gradients using the image_gradients class.\n            - The output images will have the same sizes as the input images, that is:\n                - #num_rows(horz) == #num_rows(vert) == num_rows(xx)\n                - #num_columns(horz) == #num_columns(vert) == num_columns(xx)\n    !*/\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_dark_lines(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& horz,\n        out_image_type& vert\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - All images are grayscale and the horz and vert images must contain float or\n              double pixel types.\n            - num_rows(xx) == num_rows(xy) == num_rows(yy)\n            - num_columns(xx) == num_columns(xy) == num_columns(yy)\n        ensures\n            - This routine is similar to sobel_edge_detector(), except instead of finding\n              an edge it finds a dark/black line.  For example, the border between a\n              black piece of paper and a white table is an edge, but a curve drawn with a\n              pencil on a piece of paper makes a line.  Therefore, the output of this\n              routine is a vector field encoded in the horz and vert images.  The vector\n              obtains a large magnitude when centered on a dark line in an image and the\n              direction of the vector is perpendicular to the line.  To be very precise,\n              each vector points in the direction of greatest change in second derivative\n              and the magnitude of the vector encodes the derivative magnitude in that\n              direction.  Moreover, if the second derivative is negative then the output\n              vector is zero.  This zeroing if negative gradients causes the output to be\n              sensitive only to dark lines surrounded by light pixels.\n            - We assume that xx, xy, and yy are the 3 second order gradients of the image\n              in question.  You can obtain these gradients using the image_gradients class.\n            - The output images will have the same sizes as the input images, that is:\n                - #num_rows(horz) == #num_rows(vert) == num_rows(xx)\n                - #num_columns(horz) == #num_columns(vert) == num_columns(xx)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_bright_keypoints(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& saliency\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - All images are grayscale and the saliency image must contain float or double\n              pixel types.\n            - num_rows(xx) == num_rows(xy) == num_rows(yy)\n            - num_columns(xx) == num_columns(xy) == num_columns(yy)\n        ensures\n            - This routine finds bright \"keypoints\" in an image.  In general, these are\n              bright/white localized blobs.  It does this by computing the determinant of\n              the image Hessian at each location and storing this value into the output\n              saliency image if both eigenvalues of the Hessian are negative.  If either\n              eigenvalue is positive then the saliency for that pixel is 0.  I.e.\n                - for all valid r,c:\n                    - #saliency[r][c] == a number >= 0 and larger values indicate the\n                      presence of a keypoint at this pixel location.\n            - We assume that xx, xy, and yy are the 3 second order gradients of the image\n              in question.  You can obtain these gradients using the image_gradients class.\n            - The output image will have the same size as the input images, that is:\n                - #num_rows(saliency) == num_rows(xx)\n                - #num_columns(saliency) == num_columns(xx)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void find_dark_keypoints(\n        const in_image_type& xx,\n        const in_image_type& xy,\n        const in_image_type& yy,\n        out_image_type& saliency\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - All images are grayscale and the saliency image must contain float or double\n              pixel types.\n            - num_rows(xx) == num_rows(xy) == num_rows(yy)\n            - num_columns(xx) == num_columns(xy) == num_columns(yy)\n        ensures\n            - This routine finds dark \"keypoints\" in an image.  In general, these are dark\n              localized blobs.  It does this by computing the determinant of the image\n              Hessian at each location and storing this value into the output saliency\n              image if both eigenvalues of the Hessian are positive.  If either eigenvalue\n              is negative then the saliency for that pixel is 0.  I.e.\n                - for all valid r,c:\n                    - #saliency[r][c] == a number >= 0 and larger values indicate the\n                      presence of a keypoint at this pixel location.\n            - We assume that xx, xy, and yy are the 3 second order gradients of the image\n              in question.  You can obtain these gradients using the image_gradients class.\n            - The output image will have the same size as the input images, that is:\n                - #num_rows(saliency) == num_rows(xx)\n                - #num_columns(saliency) == num_columns(xx)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EDGE_DETECTOr_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/equalize_histogram.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_EQUALIZE_HISTOGRAm_\n#define DLIB_EQUALIZE_HISTOGRAm_\n\n#include \"../pixel.h\"\n#include \"equalize_histogram_abstract.h\"\n#include <vector>\n#include \"../enable_if.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        long R,\n        long C,\n        typename MM\n        >\n    void get_histogram (\n        const in_image_type& in_img_,\n        matrix<unsigned long,R,C,MM>& hist,\n        size_t hist_size\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<pixel_type>::is_unsigned == true );\n\n        // make sure hist is the right size\n        if (R == 1)\n            hist.set_size(1,hist_size);\n        else\n            hist.set_size(hist_size,1);\n\n\n        set_all_elements(hist,0);\n\n        const_image_view<in_image_type> in_img(in_img_);\n        // compute the histogram \n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                auto p = get_pixel_intensity(in_img[r][c]);\n                if (p < hist_size)\n                    ++hist(p);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        long R,\n        long C,\n        typename MM\n        >\n    void get_histogram (\n        const in_image_type& in_img_,\n        matrix<unsigned long,R,C,MM>& hist\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<pixel_type>::is_unsigned == true );\n\n        typedef typename pixel_traits<pixel_type>::basic_pixel_type in_image_basic_pixel_type;\n        COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) <= 2);\n\n        // make sure hist is the right size\n        if (R == 1)\n            hist.set_size(1,pixel_traits<pixel_type>::max()+1);\n        else\n            hist.set_size(pixel_traits<pixel_type>::max()+1,1);\n\n\n        set_all_elements(hist,0);\n\n        const_image_view<in_image_type> in_img(in_img_);\n        // compute the histogram \n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                unsigned long p = get_pixel_intensity(in_img[r][c]);\n                ++hist(p);\n            }\n        }\n    }\n\n// ---------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type \n        >\n    void equalize_histogram (\n        const in_image_type& in_img_,\n        out_image_type& out_img_\n    )\n    {\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::is_unsigned == true );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::is_unsigned == true );\n\n        typedef typename pixel_traits<in_pixel_type>::basic_pixel_type in_image_basic_pixel_type;\n        COMPILE_TIME_ASSERT( sizeof(in_image_basic_pixel_type) <= 2);\n\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        unsigned long p;\n\n        matrix<unsigned long,1,0> histogram;\n        get_histogram(in_img_, histogram);\n        in_img = in_img_;\n\n        double scale = pixel_traits<out_pixel_type>::max();\n        if (in_img.size() > histogram(0))\n            scale /= in_img.size()-histogram(0);\n        else\n            scale = 0;\n\n        // make the black pixels remain black in the output image\n        histogram(0) = 0;\n\n        // compute the transform function\n        for (long i = 1; i < histogram.size(); ++i)\n            histogram(i) += histogram(i-1);\n        // scale so that it is in the range [0,pixel_traits<out_pixel_type>::max()]\n        for (long i = 0; i < histogram.size(); ++i)\n            histogram(i) = static_cast<unsigned long>(histogram(i)*scale);\n\n        // now do the transform\n        for (long row = 0; row < in_img.nr(); ++row)\n        {\n            for (long col = 0; col < in_img.nc(); ++col)\n            {\n                p = histogram(get_pixel_intensity(in_img[row][col]));\n                assign_pixel(out_img[row][col], in_img[row][col]);\n                assign_pixel_intensity(out_img[row][col],p);\n            }\n        }\n\n    }\n\n    template <\n        typename image_type \n        >\n    void equalize_histogram (\n        image_type& img\n    )\n    {\n        equalize_histogram(img,img);\n    }\n\n// ---------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EQUALIZE_HISTOGRAm_\n\n\n\n"
  },
  {
    "path": "dlib/image_transforms/equalize_histogram_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_\n#ifdef DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_\n\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type \n        >\n    void equalize_histogram (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - Let pixel_type be the type of pixel in either input or output images, then we\n              must have:\n                - pixel_traits<pixel_type>::has_alpha == false\n                - pixel_traits<pixel_type>::is_unsigned == true \n            - For the input image pixel type, we have the additional requirement that:\n                - pixel_traits<pixel_type>::max() <= 65535 \n        ensures\n            - #out_img == the histogram equalized version of in_img\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n    template <\n        typename image_type \n        >\n    void equalize_histogram (\n        image_type& img\n    );\n    /*!\n        requires\n            - it is valid to call equalize_histogram(img,img)\n        ensures\n            - calls equalize_histogram(img,img);\n    !*/\n\n// ---------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        long R,\n        long C,\n        typename MM\n        >\n    void get_histogram (\n        const in_image_type& in_img,\n        matrix<unsigned long,R,C,MM>& hist\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - Let pixel_type denote the type of pixel in in_img, then we must have:\n                - pixel_traits<pixel_type>::is_unsigned == true \n                - pixel_traits<pixel_type>::max() <= 65535 \n            - hist must be capable of representing a column or row vector of length \n              pixel_traits<typename in_image_type>::max(). I.e. if R and C are nonzero\n              then they must be values that don't conflict with the previous sentence.\n        ensures\n            - #hist.size() == pixel_traits<typename in_image_type>::max()\n            - #hist.nc() == 1 || #hist.nr() == 1 (i.e. hist is either a row or column vector)\n            - #hist == the histogram for in_img.  I.e. it is the case that for all\n              valid i:\n                - hist(i) == the number of times a pixel with intensity i appears\n                  in in_img\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        long R,\n        long C,\n        typename MM\n        >\n    void get_histogram (\n        const in_image_type& in_img,\n        matrix<unsigned long,R,C,MM>& hist,\n        size_t hist_size\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - Let pixel_type denote the type of pixel in in_img, then we must have:\n                - pixel_traits<pixel_type>::is_unsigned == true \n            - hist must be capable of representing a column or row vector of length\n              hist_size. I.e. if R and C are nonzero then they must be values that don't\n              conflict with the previous sentence.\n        ensures\n            - #hist.size() == hist_size \n            - #hist.nc() == 1 || #hist.nr() == 1 (i.e. hist is either a row or column vector)\n            - #hist == the histogram for in_img, except pixel values >= hist_size are\n              ignored.  I.e. it is the case that for all valid i:\n                - hist(i) == the number of times a pixel with intensity i appears\n                  in in_img\n    !*/\n\n// ---------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_EQUALIZE_HISTOGRAm_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/fhog.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_fHOG_Hh_\n#define DLIB_fHOG_Hh_\n\n#include \"fhog_abstract.h\"\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../array.h\"\n#include \"../geometry.h\"\n#include \"assign_image.h\"\n#include \"draw.h\"\n#include \"interpolation.h\"\n#include \"../simd.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl_fhog\n    {\n        template <typename image_type, typename T>\n        inline typename dlib::enable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (\n            const int r,\n            const int c,\n            const image_type& img,\n            matrix<T,2,1>& grad,\n            T& len\n        )\n        {\n            matrix<T, 2, 1> grad2, grad3;\n            // get the red gradient\n            grad(0) = (int)img[r][c+1].red-(int)img[r][c-1].red; \n            grad(1) = (int)img[r+1][c].red-(int)img[r-1][c].red;\n            len = length_squared(grad);\n\n            // get the green gradient\n            grad2(0) = (int)img[r][c+1].green-(int)img[r][c-1].green; \n            grad2(1) = (int)img[r+1][c].green-(int)img[r-1][c].green;\n            T v2 = length_squared(grad2);\n\n            // get the blue gradient\n            grad3(0) = (int)img[r][c+1].blue-(int)img[r][c-1].blue; \n            grad3(1) = (int)img[r+1][c].blue-(int)img[r-1][c].blue;\n            T v3 = length_squared(grad3);\n\n            // pick color with strongest gradient\n            if (v2 > len) \n            {\n                len = v2;\n                grad = grad2;\n            } \n            if (v3 > len) \n            {\n                len = v3;\n                grad = grad3;\n            }\n        }\n\n        template <typename image_type>\n        inline typename dlib::enable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (\n            const int r,\n            const int c,\n            const image_type& img,\n            simd4f& grad_x,\n            simd4f& grad_y,\n            simd4f& len\n        )\n        {\n            simd4i rleft((int)img[r][c-1].red, \n                        (int)img[r][c].red,\n                        (int)img[r][c+1].red,\n                        (int)img[r][c+2].red);\n            simd4i rright((int)img[r][c+1].red, \n                         (int)img[r][c+2].red,\n                         (int)img[r][c+3].red,\n                         (int)img[r][c+4].red);\n            simd4i rtop((int)img[r-1][c].red,\n                       (int)img[r-1][c+1].red,\n                       (int)img[r-1][c+2].red,\n                       (int)img[r-1][c+3].red);\n            simd4i rbottom((int)img[r+1][c].red,\n                          (int)img[r+1][c+1].red,\n                          (int)img[r+1][c+2].red,\n                          (int)img[r+1][c+3].red);\n\n            simd4i gleft((int)img[r][c-1].green, \n                        (int)img[r][c].green,\n                        (int)img[r][c+1].green,\n                        (int)img[r][c+2].green);\n            simd4i gright((int)img[r][c+1].green, \n                         (int)img[r][c+2].green,\n                         (int)img[r][c+3].green,\n                         (int)img[r][c+4].green);\n            simd4i gtop((int)img[r-1][c].green,\n                       (int)img[r-1][c+1].green,\n                       (int)img[r-1][c+2].green,\n                       (int)img[r-1][c+3].green);\n            simd4i gbottom((int)img[r+1][c].green,\n                          (int)img[r+1][c+1].green,\n                          (int)img[r+1][c+2].green,\n                          (int)img[r+1][c+3].green);\n\n            simd4i bleft((int)img[r][c-1].blue, \n                        (int)img[r][c].blue,\n                        (int)img[r][c+1].blue,\n                        (int)img[r][c+2].blue);\n            simd4i bright((int)img[r][c+1].blue, \n                         (int)img[r][c+2].blue,\n                         (int)img[r][c+3].blue,\n                         (int)img[r][c+4].blue);\n            simd4i btop((int)img[r-1][c].blue,\n                       (int)img[r-1][c+1].blue,\n                       (int)img[r-1][c+2].blue,\n                       (int)img[r-1][c+3].blue);\n            simd4i bbottom((int)img[r+1][c].blue,\n                          (int)img[r+1][c+1].blue,\n                          (int)img[r+1][c+2].blue,\n                          (int)img[r+1][c+3].blue);\n\n            simd4i grad_x_red   = rright-rleft;\n            simd4i grad_y_red   = rbottom-rtop;\n            simd4i grad_x_green = gright-gleft;\n            simd4i grad_y_green = gbottom-gtop;\n            simd4i grad_x_blue  = bright-bleft;\n            simd4i grad_y_blue  = bbottom-btop;\n\n            simd4i rlen = grad_x_red*grad_x_red + grad_y_red*grad_y_red;\n            simd4i glen = grad_x_green*grad_x_green + grad_y_green*grad_y_green;\n            simd4i blen = grad_x_blue*grad_x_blue + grad_y_blue*grad_y_blue;\n\n            simd4i cmp = rlen>glen;\n            simd4i tgrad_x = select(cmp,grad_x_red,grad_x_green);\n            simd4i tgrad_y = select(cmp,grad_y_red,grad_y_green);\n            simd4i tlen = select(cmp,rlen,glen);\n\n            cmp = tlen>blen;\n            grad_x = select(cmp,tgrad_x,grad_x_blue);\n            grad_y = select(cmp,tgrad_y,grad_y_blue);\n            len = select(cmp,tlen,blen);\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        template <typename image_type>\n        inline typename dlib::enable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient(\n            const int r,\n            const int c,\n            const image_type& img,\n            simd8f& grad_x,\n            simd8f& grad_y,\n            simd8f& len\n            )\n        {\n            simd8i rleft((int)img[r][c - 1].red,\n                (int)img[r][c].red,\n                (int)img[r][c + 1].red,\n                (int)img[r][c + 2].red,\n                (int)img[r][c + 3].red,\n                (int)img[r][c + 4].red,\n                (int)img[r][c + 5].red,\n                (int)img[r][c + 6].red);\n            simd8i rright((int)img[r][c + 1].red,\n                (int)img[r][c + 2].red,\n                (int)img[r][c + 3].red,\n                (int)img[r][c + 4].red,\n                (int)img[r][c + 5].red,\n                (int)img[r][c + 6].red,\n                (int)img[r][c + 7].red,\n                (int)img[r][c + 8].red);\n            simd8i rtop((int)img[r - 1][c].red,\n                (int)img[r - 1][c + 1].red,\n                (int)img[r - 1][c + 2].red,\n                (int)img[r - 1][c + 3].red,\n                (int)img[r - 1][c + 4].red,\n                (int)img[r - 1][c + 5].red,\n                (int)img[r - 1][c + 6].red,\n                (int)img[r - 1][c + 7].red);\n            simd8i rbottom((int)img[r + 1][c].red,\n                (int)img[r + 1][c + 1].red,\n                (int)img[r + 1][c + 2].red,\n                (int)img[r + 1][c + 3].red,\n                (int)img[r + 1][c + 4].red,\n                (int)img[r + 1][c + 5].red,\n                (int)img[r + 1][c + 6].red,\n                (int)img[r + 1][c + 7].red);\n\n            simd8i gleft((int)img[r][c - 1].green,\n                (int)img[r][c].green,\n                (int)img[r][c + 1].green,\n                (int)img[r][c + 2].green,\n                (int)img[r][c + 3].green,\n                (int)img[r][c + 4].green,\n                (int)img[r][c + 5].green,\n                (int)img[r][c + 6].green);\n            simd8i gright((int)img[r][c + 1].green,\n                (int)img[r][c + 2].green,\n                (int)img[r][c + 3].green,\n                (int)img[r][c + 4].green,\n                (int)img[r][c + 5].green,\n                (int)img[r][c + 6].green,\n                (int)img[r][c + 7].green,\n                (int)img[r][c + 8].green);\n            simd8i gtop((int)img[r - 1][c].green,\n                (int)img[r - 1][c + 1].green,\n                (int)img[r - 1][c + 2].green,\n                (int)img[r - 1][c + 3].green,\n                (int)img[r - 1][c + 4].green,\n                (int)img[r - 1][c + 5].green,\n                (int)img[r - 1][c + 6].green,\n                (int)img[r - 1][c + 7].green);\n            simd8i gbottom((int)img[r + 1][c].green,\n                (int)img[r + 1][c + 1].green,\n                (int)img[r + 1][c + 2].green,\n                (int)img[r + 1][c + 3].green,\n                (int)img[r + 1][c + 4].green,\n                (int)img[r + 1][c + 5].green,\n                (int)img[r + 1][c + 6].green,\n                (int)img[r + 1][c + 7].green);\n\n            simd8i bleft((int)img[r][c - 1].blue,\n                (int)img[r][c].blue,\n                (int)img[r][c + 1].blue,\n                (int)img[r][c + 2].blue,\n                (int)img[r][c + 3].blue,\n                (int)img[r][c + 4].blue,\n                (int)img[r][c + 5].blue,\n                (int)img[r][c + 6].blue);\n            simd8i bright((int)img[r][c + 1].blue,\n                (int)img[r][c + 2].blue,\n                (int)img[r][c + 3].blue,\n                (int)img[r][c + 4].blue,\n                (int)img[r][c + 5].blue,\n                (int)img[r][c + 6].blue,\n                (int)img[r][c + 7].blue,\n                (int)img[r][c + 8].blue);\n            simd8i btop((int)img[r - 1][c].blue,\n                (int)img[r - 1][c + 1].blue,\n                (int)img[r - 1][c + 2].blue,\n                (int)img[r - 1][c + 3].blue,\n                (int)img[r - 1][c + 4].blue,\n                (int)img[r - 1][c + 5].blue,\n                (int)img[r - 1][c + 6].blue,\n                (int)img[r - 1][c + 7].blue);\n            simd8i bbottom((int)img[r + 1][c].blue,\n                (int)img[r + 1][c + 1].blue,\n                (int)img[r + 1][c + 2].blue,\n                (int)img[r + 1][c + 3].blue,\n                (int)img[r + 1][c + 4].blue,\n                (int)img[r + 1][c + 5].blue,\n                (int)img[r + 1][c + 6].blue,\n                (int)img[r + 1][c + 7].blue);\n\n            simd8i grad_x_red = rright - rleft;\n            simd8i grad_y_red = rbottom - rtop;\n            simd8i grad_x_green = gright - gleft;\n            simd8i grad_y_green = gbottom - gtop;\n            simd8i grad_x_blue = bright - bleft;\n            simd8i grad_y_blue = bbottom - btop;\n\n            simd8i rlen = grad_x_red*grad_x_red + grad_y_red*grad_y_red;\n            simd8i glen = grad_x_green*grad_x_green + grad_y_green*grad_y_green;\n            simd8i blen = grad_x_blue*grad_x_blue + grad_y_blue*grad_y_blue;\n\n            simd8i cmp = rlen > glen;\n            simd8i tgrad_x = select(cmp, grad_x_red, grad_x_green);\n            simd8i tgrad_y = select(cmp, grad_y_red, grad_y_green);\n            simd8i tlen = select(cmp, rlen, glen);\n\n            cmp = tlen > blen;\n            grad_x = select(cmp, tgrad_x, grad_x_blue);\n            grad_y = select(cmp, tgrad_y, grad_y_blue);\n            len = select(cmp, tlen, blen);\n        }\n        \n        // ------------------------------------------------------------------------------------\n\n        template <typename image_type, typename T>\n        inline typename dlib::disable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (\n            const int r,\n            const int c,\n            const image_type& img,\n            matrix<T, 2, 1>& grad,\n            T& len\n        )\n        {\n            grad(0) = (int)get_pixel_intensity(img[r][c+1])-(int)get_pixel_intensity(img[r][c-1]); \n            grad(1) = (int)get_pixel_intensity(img[r+1][c])-(int)get_pixel_intensity(img[r-1][c]);\n            len = length_squared(grad);\n        }\n\n        template <typename image_type>\n        inline typename dlib::disable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient (\n            int r,\n            int c,\n            const image_type& img,\n            simd4f& grad_x,\n            simd4f& grad_y,\n            simd4f& len\n        )\n        {\n            simd4i left((int)get_pixel_intensity(img[r][c-1]), \n                        (int)get_pixel_intensity(img[r][c]),\n                        (int)get_pixel_intensity(img[r][c+1]),\n                        (int)get_pixel_intensity(img[r][c+2]));\n            simd4i right((int)get_pixel_intensity(img[r][c+1]), \n                         (int)get_pixel_intensity(img[r][c+2]),\n                         (int)get_pixel_intensity(img[r][c+3]),\n                         (int)get_pixel_intensity(img[r][c+4]));\n\n            simd4i top((int)get_pixel_intensity(img[r-1][c]),\n                       (int)get_pixel_intensity(img[r-1][c+1]),\n                       (int)get_pixel_intensity(img[r-1][c+2]),\n                       (int)get_pixel_intensity(img[r-1][c+3]));\n            simd4i bottom((int)get_pixel_intensity(img[r+1][c]),\n                          (int)get_pixel_intensity(img[r+1][c+1]),\n                          (int)get_pixel_intensity(img[r+1][c+2]),\n                          (int)get_pixel_intensity(img[r+1][c+3]));\n\n            grad_x = right-left;\n            grad_y = bottom-top;\n\n            len = (grad_x*grad_x + grad_y*grad_y);\n        }\n\n        // ------------------------------------------------------------------------------------\n\n        template <typename image_type>\n        inline typename dlib::disable_if_c<pixel_traits<typename image_type::pixel_type>::rgb>::type get_gradient(\n            int r,\n            int c,\n            const image_type& img,\n            simd8f& grad_x,\n            simd8f& grad_y,\n            simd8f& len\n            )\n        {\n            simd8i left((int)get_pixel_intensity(img[r][c - 1]),\n                (int)get_pixel_intensity(img[r][c]),\n                (int)get_pixel_intensity(img[r][c + 1]),\n                (int)get_pixel_intensity(img[r][c + 2]),\n                (int)get_pixel_intensity(img[r][c + 3]),\n                (int)get_pixel_intensity(img[r][c + 4]),\n                (int)get_pixel_intensity(img[r][c + 5]),\n                (int)get_pixel_intensity(img[r][c + 6]));\n            simd8i right((int)get_pixel_intensity(img[r][c + 1]),\n                (int)get_pixel_intensity(img[r][c + 2]),\n                (int)get_pixel_intensity(img[r][c + 3]),\n                (int)get_pixel_intensity(img[r][c + 4]),\n                (int)get_pixel_intensity(img[r][c + 5]),\n                (int)get_pixel_intensity(img[r][c + 6]),\n                (int)get_pixel_intensity(img[r][c + 7]),\n                (int)get_pixel_intensity(img[r][c + 8]));\n\n            simd8i top((int)get_pixel_intensity(img[r - 1][c]),\n                (int)get_pixel_intensity(img[r - 1][c + 1]),\n                (int)get_pixel_intensity(img[r - 1][c + 2]),\n                (int)get_pixel_intensity(img[r - 1][c + 3]),\n                (int)get_pixel_intensity(img[r - 1][c + 4]),\n                (int)get_pixel_intensity(img[r - 1][c + 5]),\n                (int)get_pixel_intensity(img[r - 1][c + 6]),\n                (int)get_pixel_intensity(img[r - 1][c + 7]));\n            simd8i bottom((int)get_pixel_intensity(img[r + 1][c]),\n                (int)get_pixel_intensity(img[r + 1][c + 1]),\n                (int)get_pixel_intensity(img[r + 1][c + 2]),\n                (int)get_pixel_intensity(img[r + 1][c + 3]),\n                (int)get_pixel_intensity(img[r + 1][c + 4]),\n                (int)get_pixel_intensity(img[r + 1][c + 5]),\n                (int)get_pixel_intensity(img[r + 1][c + 6]),\n                (int)get_pixel_intensity(img[r + 1][c + 7]));\n\n            grad_x = right - left;\n            grad_y = bottom - top;\n\n            len = (grad_x*grad_x + grad_y*grad_y);\n        }\n        \n        // ------------------------------------------------------------------------------------\n\n        template <typename T, typename mm1, typename mm2>\n        inline void set_hog (\n            dlib::array<array2d<T,mm1>,mm2>& hog,\n            int o,\n            int x, \n            int y,\n            const float& value\n        )\n        {\n            hog[o][y][x] = value;\n        }\n\n        template <typename T, typename mm1, typename mm2>\n        void init_hog (\n            dlib::array<array2d<T,mm1>,mm2>& hog,\n            int hog_nr,\n            int hog_nc,\n            int filter_rows_padding,\n            int filter_cols_padding\n        )\n        {\n            const int num_hog_bands = 27+4;\n            hog.resize(num_hog_bands);\n            for (int i = 0; i < num_hog_bands; ++i)\n            {\n                hog[i].set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);\n                rectangle rect = get_rect(hog[i]);\n                rect.top() +=   (filter_rows_padding-1)/2;\n                rect.left() +=  (filter_cols_padding-1)/2;\n                rect.right() -= filter_cols_padding/2;\n                rect.bottom() -= filter_rows_padding/2;\n                zero_border_pixels(hog[i],rect);\n            }\n        }\n\n        template <typename T, typename mm1, typename mm2>\n        void init_hog_zero_everything (\n            dlib::array<array2d<T,mm1>,mm2>& hog,\n            int hog_nr,\n            int hog_nc,\n            int filter_rows_padding,\n            int filter_cols_padding\n        )\n        {\n            const int num_hog_bands = 27+4;\n            hog.resize(num_hog_bands);\n            for (int i = 0; i < num_hog_bands; ++i)\n            {\n                hog[i].set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);\n                assign_all_pixels(hog[i], 0);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, typename mm>\n        inline void set_hog (\n            array2d<matrix<T,31,1>,mm>& hog,\n            int o,\n            int x, \n            int y,\n            const float& value\n        )\n        {\n            hog[y][x](o) = value;\n        }\n\n        template <typename T, typename mm>\n        void init_hog (\n            array2d<matrix<T,31,1>,mm>& hog,\n            int hog_nr,\n            int hog_nc,\n            int filter_rows_padding,\n            int filter_cols_padding\n        )\n        {\n            hog.set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);\n\n            // now zero out the border region\n            rectangle rect = get_rect(hog);\n            rect.top() +=   (filter_rows_padding-1)/2;\n            rect.left() +=  (filter_cols_padding-1)/2;\n            rect.right() -= filter_cols_padding/2;\n            rect.bottom() -= filter_rows_padding/2;\n            border_enumerator be(get_rect(hog),rect);\n            while (be.move_next())\n            {\n                const point p = be.element();\n                set_all_elements(hog[p.y()][p.x()], 0); \n            }\n        }\n\n        template <typename T, typename mm>\n        void init_hog_zero_everything (\n            array2d<matrix<T,31,1>,mm>& hog,\n            int hog_nr,\n            int hog_nc,\n            int filter_rows_padding,\n            int filter_cols_padding\n        )\n        {\n            hog.set_size(hog_nr+filter_rows_padding-1, hog_nc+filter_cols_padding-1);\n\n            for (long r = 0; r < hog.nr(); ++r)\n            {\n                for (long c = 0; c < hog.nc(); ++c)\n                {\n                    set_all_elements(hog[r][c], 0); \n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename image_type, \n            typename out_type\n            >\n        void impl_extract_fhog_features_cell_size_1(\n            const image_type& img_, \n            out_type& hog, \n            int filter_rows_padding,\n            int filter_cols_padding\n        ) \n        {\n            const_image_view<image_type> img(img_);\n            // make sure requires clause is not broken\n            DLIB_ASSERT( filter_rows_padding > 0 &&\n                         filter_cols_padding > 0 ,\n                \"\\t void extract_fhog_features()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n                << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n                );\n\n            /*\n                This function is an optimized version of impl_extract_fhog_features() for\n                the case where cell_size == 1.\n            */\n\n\n            // unit vectors used to compute gradient orientation\n            matrix<float,2,1> directions[9];\n            directions[0] =  1.0000, 0.0000; \n            directions[1] =  0.9397, 0.3420;\n            directions[2] =  0.7660, 0.6428;\n            directions[3] =  0.500,  0.8660;\n            directions[4] =  0.1736, 0.9848;\n            directions[5] = -0.1736, 0.9848;\n            directions[6] = -0.5000, 0.8660;\n            directions[7] = -0.7660, 0.6428;\n            directions[8] = -0.9397, 0.3420;\n\n\n\n            if (img.nr() <= 2 || img.nc() <= 2)\n            {\n                hog.clear();\n                return;\n            }\n\n            array2d<unsigned char> angle(img.nr(), img.nc());\n\n            array2d<float> norm(img.nr(), img.nc());\n            zero_border_pixels(norm,1,1);\n\n            // memory for HOG features\n            const long hog_nr = img.nr()-2;\n            const long hog_nc = img.nc()-2;\n\n            const int padding_rows_offset = (filter_rows_padding-1)/2;\n            const int padding_cols_offset = (filter_cols_padding-1)/2;\n            init_hog_zero_everything(hog, hog_nr, hog_nc, filter_rows_padding, filter_cols_padding);\n\n\n            const int visible_nr = img.nr()-1;\n            const int visible_nc = img.nc()-1;\n\n            // First populate the gradient histograms\n            for (int y = 1; y < visible_nr; y++) \n            {\n                int x;\n                for (x = 1; x < visible_nc - 7; x += 8)\n                {\n                    // v will be the length of the gradient vectors.\n                    simd8f grad_x, grad_y, v;\n                    get_gradient(y, x, img, grad_x, grad_y, v);\n\n                    float _vv[8];\n                    v.store(_vv);\n\n                    // Now snap the gradient to one of 18 orientations\n                    simd8f best_dot = 0;\n                    simd8f best_o = 0;\n                    for (int o = 0; o < 9; o++)\n                    {\n                        simd8f dot = grad_x*directions[o](0) + grad_y*directions[o](1);\n                        simd8f_bool cmp = dot>best_dot;\n                        best_dot = select(cmp, dot, best_dot);\n                        dot *= -1;\n                        best_o = select(cmp, o, best_o);\n\n                        cmp = dot > best_dot;\n                        best_dot = select(cmp, dot, best_dot);\n                        best_o = select(cmp, o + 9, best_o);\n                    }\n\n                    int32 _best_o[8]; simd8i(best_o).store(_best_o);\n\n                    norm[y][x + 0] = _vv[0];\n                    norm[y][x + 1] = _vv[1];\n                    norm[y][x + 2] = _vv[2];\n                    norm[y][x + 3] = _vv[3];\n                    norm[y][x + 4] = _vv[4];\n                    norm[y][x + 5] = _vv[5];\n                    norm[y][x + 6] = _vv[6];\n                    norm[y][x + 7] = _vv[7];\n\n                    angle[y][x + 0] = _best_o[0];\n                    angle[y][x + 1] = _best_o[1];\n                    angle[y][x + 2] = _best_o[2];\n                    angle[y][x + 3] = _best_o[3];\n                    angle[y][x + 4] = _best_o[4];\n                    angle[y][x + 5] = _best_o[5];\n                    angle[y][x + 6] = _best_o[6];\n                    angle[y][x + 7] = _best_o[7];\n                }\n                // Now process the right columns that don't fit into simd registers.\n                for (; x < visible_nc; x++) \n                {\n                    matrix<float,2,1> grad;\n                    float v;\n                    get_gradient(y,x,img,grad,v);\n\n                    // snap to one of 18 orientations\n                    float best_dot = 0;\n                    int best_o = 0;\n                    for (int o = 0; o < 9; o++) \n                    {\n                        const float dot = dlib::dot(directions[o], grad);\n                        if (dot > best_dot) \n                        {\n                            best_dot = dot;\n                            best_o = o;\n                        } \n                        else if (-dot > best_dot) \n                        {\n                            best_dot = -dot;\n                            best_o = o+9;\n                        }\n                    }\n\n                    norm[y][x] = v;\n                    angle[y][x] = best_o;\n                }\n            }\n\n            const float eps = 0.0001;\n            // compute features\n            for (int y = 0; y < hog_nr; y++) \n            {\n                const int yy = y+padding_rows_offset; \n                for (int x = 0; x < hog_nc; x++) \n                {\n                    const simd4f z1(norm[y+1][x+1],\n                                    norm[y][x+1], \n                                    norm[y+1][x],  \n                                    norm[y][x]);\n\n                    const simd4f z2(norm[y+1][x+2],\n                                    norm[y][x+2],\n                                    norm[y+1][x+1],\n                                    norm[y][x+1]);\n\n                    const simd4f z3(norm[y+2][x+1],\n                                    norm[y+1][x+1],\n                                    norm[y+2][x],\n                                    norm[y+1][x]);\n\n                    const simd4f z4(norm[y+2][x+2],\n                                    norm[y+1][x+2],\n                                    norm[y+2][x+1],\n                                    norm[y+1][x+1]);\n\n                    const simd4f temp0 = std::sqrt(norm[y+1][x+1]);\n                    const simd4f nn = 0.2*sqrt(z1+z2+z3+z4+eps);\n                    const simd4f n = 0.1/nn;\n\n                    simd4f t = 0;\n\n                    const int xx = x+padding_cols_offset; \n\n                    simd4f h0 = min(temp0,nn)*n;\n                    const float vv = sum(h0);\n                    set_hog(hog,angle[y+1][x+1],xx,yy,   vv);\n                    t += h0;\n\n                    t *= 2*0.2357;\n\n                    // contrast-insensitive features\n                    set_hog(hog,angle[y+1][x+1]%9+18,xx,yy, vv);\n\n\n                    float temp[4];\n                    t.store(temp);\n\n                    // texture features\n                    set_hog(hog,27,xx,yy, temp[0]);\n                    set_hog(hog,28,xx,yy, temp[1]);\n                    set_hog(hog,29,xx,yy, temp[2]);\n                    set_hog(hog,30,xx,yy, temp[3]);\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename image_type, \n            typename out_type\n            >\n        void impl_extract_fhog_features(\n            const image_type& img_, \n            out_type& hog, \n            int cell_size,\n            int filter_rows_padding,\n            int filter_cols_padding\n        ) \n        {\n            const_image_view<image_type> img(img_);\n            // make sure requires clause is not broken\n            DLIB_ASSERT( cell_size > 0 &&\n                         filter_rows_padding > 0 &&\n                         filter_cols_padding > 0 ,\n                \"\\t void extract_fhog_features()\"\n                << \"\\n\\t Invalid inputs were given to this function. \"\n                << \"\\n\\t cell_size: \" << cell_size \n                << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n                << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n                );\n\n            /*\n                This function implements the HOG feature extraction method described in \n                the paper:\n                    P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan\n                    Object Detection with Discriminatively Trained Part Based Models\n                    IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010\n\n                Moreover, this function is derived from the HOG feature extraction code\n                from the features.cc file in the voc-releaseX code (see\n                http://people.cs.uchicago.edu/~rbg/latent/) which is has the following\n                license (note that the code has been modified to work with grayscale and\n                color as well as planar and interlaced input and output formats):\n\n                Copyright (C) 2011, 2012 Ross Girshick, Pedro Felzenszwalb\n                Copyright (C) 2008, 2009, 2010 Pedro Felzenszwalb, Ross Girshick\n                Copyright (C) 2007 Pedro Felzenszwalb, Deva Ramanan\n\n                Permission is hereby granted, free of charge, to any person obtaining\n                a copy of this software and associated documentation files (the\n                \"Software\"), to deal in the Software without restriction, including\n                without limitation the rights to use, copy, modify, merge, publish,\n                distribute, sublicense, and/or sell copies of the Software, and to\n                permit persons to whom the Software is furnished to do so, subject to\n                the following conditions:\n\n                The above copyright notice and this permission notice shall be\n                included in all copies or substantial portions of the Software.\n\n                THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n                EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n                MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n                NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n                LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n                OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n                WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n            */\n\n            if (cell_size == 1)\n            {\n                impl_extract_fhog_features_cell_size_1(img_,hog,filter_rows_padding,filter_cols_padding);\n                return;\n            }\n\n            // unit vectors used to compute gradient orientation\n            matrix<float,2,1> directions[9];\n            directions[0] =  1.0000, 0.0000; \n            directions[1] =  0.9397, 0.3420;\n            directions[2] =  0.7660, 0.6428;\n            directions[3] =  0.500,  0.8660;\n            directions[4] =  0.1736, 0.9848;\n            directions[5] = -0.1736, 0.9848;\n            directions[6] = -0.5000, 0.8660;\n            directions[7] = -0.7660, 0.6428;\n            directions[8] = -0.9397, 0.3420;\n\n\n\n            // First we allocate memory for caching orientation histograms & their norms.\n            const int cells_nr = (int)((float)img.nr()/(float)cell_size + 0.5);\n            const int cells_nc = (int)((float)img.nc()/(float)cell_size + 0.5);\n\n            if (cells_nr == 0 || cells_nc == 0)\n            {\n                hog.clear();\n                return;\n            }\n\n            // We give hist extra padding around the edges (1 cell all the way around the\n            // edge) so we can avoid needing to do boundary checks when indexing into it\n            // later on.  So some statements assign to the boundary but those values are\n            // never used.\n            array2d<matrix<float,18,1> > hist(cells_nr+2, cells_nc+2);\n            for (long r = 0; r < hist.nr(); ++r)\n            {\n                for (long c = 0; c < hist.nc(); ++c)\n                {\n                    hist[r][c] = 0;\n                }\n            }\n\n            array2d<float> norm(cells_nr, cells_nc);\n            assign_all_pixels(norm, 0);\n\n            // memory for HOG features\n            const int hog_nr = std::max(cells_nr-2, 0);\n            const int hog_nc = std::max(cells_nc-2, 0);\n            if (hog_nr == 0 || hog_nc == 0)\n            {\n                hog.clear();\n                return;\n            }\n            const int padding_rows_offset = (filter_rows_padding-1)/2;\n            const int padding_cols_offset = (filter_cols_padding-1)/2;\n            init_hog(hog, hog_nr, hog_nc, filter_rows_padding, filter_cols_padding);\n\n            const int visible_nr = std::min(cells_nr*cell_size,static_cast<int>(img.nr()))-1;\n            const int visible_nc = std::min(cells_nc*cell_size,static_cast<int>(img.nc()))-1;\n\n            // First populate the gradient histograms\n            for (int y = 1; y < visible_nr; y++) \n            {\n                const float yp = (y + 0.5) / static_cast<float>(cell_size) - 0.5;\n                const int iyp = static_cast<int>(std::floor(yp));\n                const float vy0 = yp - iyp;\n                const float vy1 = 1.0 - vy0;\n                int x;\n                for (x = 1; x < visible_nc - 7; x += 8)\n                {\n                    simd8f xx(x, x + 1, x + 2, x + 3, x + 4, x + 5, x + 6, x + 7);\n                    // v will be the length of the gradient vectors.\n                    simd8f grad_x, grad_y, v;\n                    get_gradient(y, x, img, grad_x, grad_y, v);\n\n                    // We will use bilinear interpolation to add into the histogram bins.\n                    // So first we precompute the values needed to determine how much each\n                    // pixel votes into each bin.\n                    simd8f xp = (xx + 0.5) / static_cast<float>(cell_size) + 0.5;\n                    simd8i ixp = simd8i(xp);\n                    simd8f vx0 = xp - ixp;\n                    simd8f vx1 = 1.0f - vx0;\n\n                    v = sqrt(v);\n\n                    // Now snap the gradient to one of 18 orientations\n                    simd8f best_dot = 0;\n                    simd8f best_o = 0;\n                    for (int o = 0; o < 9; o++)\n                    {\n                        simd8f dot = grad_x*directions[o](0) + grad_y*directions[o](1);\n                        simd8f_bool cmp = dot>best_dot;\n                        best_dot = select(cmp, dot, best_dot);\n                        dot *= -1;\n                        best_o = select(cmp, o, best_o);\n\n                        cmp = dot > best_dot;\n                        best_dot = select(cmp, dot, best_dot);\n                        best_o = select(cmp, o + 9, best_o);\n                    }\n\n\n                    // Add the gradient magnitude, v, to 4 histograms around pixel using\n                    // bilinear interpolation.\n                    vx1 *= v;\n                    vx0 *= v;\n                    // The amounts for each bin\n                    simd8f v11 = vy1*vx1;\n                    simd8f v01 = vy0*vx1;\n                    simd8f v10 = vy1*vx0;\n                    simd8f v00 = vy0*vx0;\n\n                    int32 _best_o[8]; simd8i(best_o).store(_best_o);\n                    int32 _ixp[8];    ixp.store(_ixp);\n                    float _v11[8];    v11.store(_v11);\n                    float _v01[8];    v01.store(_v01);\n                    float _v10[8];    v10.store(_v10);\n                    float _v00[8];    v00.store(_v00);\n\n                    hist[iyp + 1][_ixp[0]](_best_o[0]) += _v11[0];\n                    hist[iyp + 1 + 1][_ixp[0]](_best_o[0]) += _v01[0];\n                    hist[iyp + 1][_ixp[0] + 1](_best_o[0]) += _v10[0];\n                    hist[iyp + 1 + 1][_ixp[0] + 1](_best_o[0]) += _v00[0];\n\n                    hist[iyp + 1][_ixp[1]](_best_o[1]) += _v11[1];\n                    hist[iyp + 1 + 1][_ixp[1]](_best_o[1]) += _v01[1];\n                    hist[iyp + 1][_ixp[1] + 1](_best_o[1]) += _v10[1];\n                    hist[iyp + 1 + 1][_ixp[1] + 1](_best_o[1]) += _v00[1];\n\n                    hist[iyp + 1][_ixp[2]](_best_o[2]) += _v11[2];\n                    hist[iyp + 1 + 1][_ixp[2]](_best_o[2]) += _v01[2];\n                    hist[iyp + 1][_ixp[2] + 1](_best_o[2]) += _v10[2];\n                    hist[iyp + 1 + 1][_ixp[2] + 1](_best_o[2]) += _v00[2];\n\n                    hist[iyp + 1][_ixp[3]](_best_o[3]) += _v11[3];\n                    hist[iyp + 1 + 1][_ixp[3]](_best_o[3]) += _v01[3];\n                    hist[iyp + 1][_ixp[3] + 1](_best_o[3]) += _v10[3];\n                    hist[iyp + 1 + 1][_ixp[3] + 1](_best_o[3]) += _v00[3];\n\n                    hist[iyp + 1][_ixp[4]](_best_o[4]) += _v11[4];\n                    hist[iyp + 1 + 1][_ixp[4]](_best_o[4]) += _v01[4];\n                    hist[iyp + 1][_ixp[4] + 1](_best_o[4]) += _v10[4];\n                    hist[iyp + 1 + 1][_ixp[4] + 1](_best_o[4]) += _v00[4];\n\n                    hist[iyp + 1][_ixp[5]](_best_o[5]) += _v11[5];\n                    hist[iyp + 1 + 1][_ixp[5]](_best_o[5]) += _v01[5];\n                    hist[iyp + 1][_ixp[5] + 1](_best_o[5]) += _v10[5];\n                    hist[iyp + 1 + 1][_ixp[5] + 1](_best_o[5]) += _v00[5];\n\n                    hist[iyp + 1][_ixp[6]](_best_o[6]) += _v11[6];\n                    hist[iyp + 1 + 1][_ixp[6]](_best_o[6]) += _v01[6];\n                    hist[iyp + 1][_ixp[6] + 1](_best_o[6]) += _v10[6];\n                    hist[iyp + 1 + 1][_ixp[6] + 1](_best_o[6]) += _v00[6];\n\n                    hist[iyp + 1][_ixp[7]](_best_o[7]) += _v11[7];\n                    hist[iyp + 1 + 1][_ixp[7]](_best_o[7]) += _v01[7];\n                    hist[iyp + 1][_ixp[7] + 1](_best_o[7]) += _v10[7];\n                    hist[iyp + 1 + 1][_ixp[7] + 1](_best_o[7]) += _v00[7];\n                }\n                // Now process the right columns that don't fit into simd registers.\n                for (; x < visible_nc; x++) \n                {\n                    matrix<float, 2, 1> grad;\n                    float v;\n                    get_gradient(y,x,img,grad,v);\n\n                    // snap to one of 18 orientations\n                    float best_dot = 0;\n                    int best_o = 0;\n                    for (int o = 0; o < 9; o++) \n                    {\n                        const float dot = dlib::dot(directions[o], grad);\n                        if (dot > best_dot) \n                        {\n                            best_dot = dot;\n                            best_o = o;\n                        } \n                        else if (-dot > best_dot) \n                        {\n                            best_dot = -dot;\n                            best_o = o+9;\n                        }\n                    }\n\n                    v = std::sqrt(v);\n                    // add to 4 histograms around pixel using bilinear interpolation\n                    const float xp = (x + 0.5) / static_cast<double>(cell_size) - 0.5;\n                    const int ixp = static_cast<int>(std::floor(xp));\n                    const float vx0 = xp - ixp;\n                    const float vx1 = 1.0 - vx0;\n\n                    hist[iyp+1][ixp+1](best_o) += vy1*vx1*v;\n                    hist[iyp+1+1][ixp+1](best_o) += vy0*vx1*v;\n                    hist[iyp+1][ixp+1+1](best_o) += vy1*vx0*v;\n                    hist[iyp+1+1][ixp+1+1](best_o) += vy0*vx0*v;\n                }\n            }\n\n            // compute energy in each block by summing over orientations\n            for (int r = 0; r < cells_nr; ++r)\n            {\n                for (int c = 0; c < cells_nc; ++c)\n                {\n                    for (int o = 0; o < 9; o++) \n                    {\n                        norm[r][c] += (hist[r+1][c+1](o) + hist[r+1][c+1](o+9)) * (hist[r+1][c+1](o) + hist[r+1][c+1](o+9));\n                    }\n                }\n            }\n\n            const float eps = 0.0001;\n            // compute features\n            for (int y = 0; y < hog_nr; y++) \n            {\n                const int yy = y+padding_rows_offset; \n                for (int x = 0; x < hog_nc; x++) \n                {\n                    const simd4f z1(norm[y+1][x+1],\n                                    norm[y][x+1], \n                                    norm[y+1][x],  \n                                    norm[y][x]);\n\n                    const simd4f z2(norm[y+1][x+2],\n                                    norm[y][x+2],\n                                    norm[y+1][x+1],\n                                    norm[y][x+1]);\n\n                    const simd4f z3(norm[y+2][x+1],\n                                    norm[y+1][x+1],\n                                    norm[y+2][x],\n                                    norm[y+1][x]);\n\n                    const simd4f z4(norm[y+2][x+2],\n                                    norm[y+1][x+2],\n                                    norm[y+2][x+1],\n                                    norm[y+1][x+1]);\n\n                    const simd4f nn = 0.2*sqrt(z1+z2+z3+z4+eps);\n                    const simd4f n = 0.1/nn;\n\n                    simd4f t = 0;\n\n                    const int xx = x+padding_cols_offset; \n\n                    // contrast-sensitive features\n                    for (int o = 0; o < 18; o+=3) \n                    {\n                        simd4f temp0(hist[y+1+1][x+1+1](o));\n                        simd4f temp1(hist[y+1+1][x+1+1](o+1));\n                        simd4f temp2(hist[y+1+1][x+1+1](o+2));\n                        simd4f h0 = min(temp0,nn)*n;\n                        simd4f h1 = min(temp1,nn)*n;\n                        simd4f h2 = min(temp2,nn)*n;\n                        set_hog(hog,o,xx,yy,   sum(h0));\n                        set_hog(hog,o+1,xx,yy, sum(h1));\n                        set_hog(hog,o+2,xx,yy, sum(h2));\n                        t += h0+h1+h2;\n                    }\n\n                    t *= 2*0.2357;\n\n                    // contrast-insensitive features\n                    for (int o = 0; o < 9; o+=3) \n                    {\n                        simd4f temp0 = hist[y+1+1][x+1+1](o)   + hist[y+1+1][x+1+1](o+9);\n                        simd4f temp1 = hist[y+1+1][x+1+1](o+1) + hist[y+1+1][x+1+1](o+9+1);\n                        simd4f temp2 = hist[y+1+1][x+1+1](o+2) + hist[y+1+1][x+1+1](o+9+2);\n                        simd4f h0 = min(temp0,nn)*n;\n                        simd4f h1 = min(temp1,nn)*n;\n                        simd4f h2 = min(temp2,nn)*n;\n                        set_hog(hog,o+18,xx,yy, sum(h0));\n                        set_hog(hog,o+18+1,xx,yy, sum(h1));\n                        set_hog(hog,o+18+2,xx,yy, sum(h2));\n                    }\n\n\n                    float temp[4];\n                    t.store(temp);\n\n                    // texture features\n                    set_hog(hog,27,xx,yy, temp[0]);\n                    set_hog(hog,28,xx,yy, temp[1]);\n                    set_hog(hog,29,xx,yy, temp[2]);\n                    set_hog(hog,30,xx,yy, temp[3]);\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void create_fhog_bar_images (\n            dlib::array<matrix<float> >& mbars,\n            const long w\n        )\n        {\n            const long bdims = 9;\n            // Make the oriented lines we use to draw on each HOG cell.\n            mbars.resize(bdims);\n            dlib::array<array2d<unsigned char> > bars(bdims);\n            array2d<unsigned char> temp(w,w);\n            for (unsigned long i = 0; i < bars.size(); ++i)\n            {\n                assign_all_pixels(temp, 0);\n                draw_line(temp, point(w/2,0), point(w/2,w-1), 255);\n                rotate_image(temp, bars[i], i*-pi/bars.size());\n\n                mbars[i] = subm(matrix_cast<float>(mat(bars[i])), centered_rect(get_rect(bars[i]),w,w) );\n            }\n        }\n\n    } // end namespace impl_fhog\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type, \n        typename T, \n        typename mm1, \n        typename mm2\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        dlib::array<array2d<T,mm1>,mm2>& hog, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    ) \n    {\n        impl_fhog::impl_extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);\n        // If the image is too small then the above function outputs an empty feature map.\n        // But to make things very uniform in usage we require the output to still have the\n        // 31 planes (but they are just empty).\n        if (hog.size() == 0)\n            hog.resize(31);\n    }\n\n    template <\n        typename image_type, \n        typename T, \n        typename mm\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        array2d<matrix<T,31,1>,mm>& hog, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    ) \n    {\n        impl_fhog::impl_extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        matrix<T,0,1>& feats,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    )\n    {\n        dlib::array<array2d<T> > hog;\n        extract_fhog_features(img, hog, cell_size, filter_rows_padding, filter_cols_padding);\n        feats.set_size(hog.size()*hog[0].size());\n        for (unsigned long i = 0; i < hog.size(); ++i)\n        {\n            const long size = hog[i].size();\n            set_rowm(feats, range(i*size, (i+1)*size-1)) = reshape_to_column_vector(mat(hog[i]));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    matrix<double,0,1> extract_fhog_features(\n        const image_type& img, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    )\n    {\n        matrix<double, 0, 1> feats;\n        extract_fhog_features(img, feats, cell_size, filter_rows_padding, filter_cols_padding);\n        return feats;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    inline point image_to_fhog (\n        point p,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_size > 0 &&\n            filter_rows_padding > 0 &&\n            filter_cols_padding > 0 ,\n            \"\\t point image_to_fhog()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_size: \" << cell_size \n            << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n            << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n        );\n\n        // There is a one pixel border around the image.\n        p -= point(1,1);\n        // There is also a 1 \"cell\" border around the HOG image formation.\n        return p/cell_size - point(1,1) + point((filter_cols_padding-1)/2,(filter_rows_padding-1)/2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle image_to_fhog (\n        const rectangle& rect,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_size > 0 &&\n            filter_rows_padding > 0 &&\n            filter_cols_padding > 0 ,\n            \"\\t rectangle image_to_fhog()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_size: \" << cell_size \n            << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n            << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n        );\n\n        return rectangle(image_to_fhog(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),\n                         image_to_fhog(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point fhog_to_image (\n        point p,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_size > 0 &&\n            filter_rows_padding > 0 &&\n            filter_cols_padding > 0 ,\n            \"\\t point fhog_to_image()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_size: \" << cell_size \n            << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n            << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n        );\n\n        // Convert to image space and then set to the center of the cell.\n        point offset;\n        \n        p = (p+point(1,1)-point((filter_cols_padding-1)/2,(filter_rows_padding-1)/2))*cell_size + point(1,1);\n        if (p.x() >= 0 && p.y() >= 0) offset = point(cell_size/2,cell_size/2);\n        if (p.x() <  0 && p.y() >= 0) offset = point(-cell_size/2,cell_size/2);\n        if (p.x() >= 0 && p.y() <  0) offset = point(cell_size/2,-cell_size/2);\n        if (p.x() <  0 && p.y() <  0) offset = point(-cell_size/2,-cell_size/2);\n        return p + offset;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle fhog_to_image (\n        const rectangle& rect,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_size > 0 &&\n            filter_rows_padding > 0 &&\n            filter_cols_padding > 0 ,\n            \"\\t rectangle fhog_to_image()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_size: \" << cell_size \n            << \"\\n\\t filter_rows_padding: \" << filter_rows_padding \n            << \"\\n\\t filter_cols_padding: \" << filter_cols_padding \n        );\n\n        return rectangle(fhog_to_image(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding),\n                         fhog_to_image(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename mm1, \n        typename mm2\n        >\n    matrix<unsigned char> draw_fhog(\n        const dlib::array<array2d<T,mm1>,mm2>& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_draw_size > 0 && hog.size()==31,\n            \"\\t matrix<unsigned char> draw_fhog()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_draw_size: \" << cell_draw_size \n            << \"\\n\\t hog.size(): \" << hog.size() \n        );\n\n        dlib::array<matrix<float> > mbars;\n        impl_fhog::create_fhog_bar_images(mbars,cell_draw_size);\n\n        // now draw the bars onto the HOG cells\n        matrix<float> himg(hog[0].nr()*cell_draw_size, hog[0].nc()*cell_draw_size);\n        himg = 0;\n        for (unsigned long d = 0; d < mbars.size(); ++d)\n        {\n            for (long r = 0; r < himg.nr(); r+=cell_draw_size)\n            {\n                for (long c = 0; c < himg.nc(); c+=cell_draw_size)\n                {\n                    const float val = hog[d][r/cell_draw_size][c/cell_draw_size] +\n                        hog[d+mbars.size()][r/cell_draw_size][c/cell_draw_size] +\n                        hog[d+mbars.size()*2][r/cell_draw_size][c/cell_draw_size];\n                    if (val > min_response_threshold)\n                    {\n                        set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()];\n                    }\n                }\n            }\n        }\n\n        const float thresh = mean(himg) + 4 * stddev(himg);\n        if (thresh != 0)\n            return matrix_cast<unsigned char>(upperbound(round(himg*255/thresh),255));\n        else\n            return matrix_cast<unsigned char>(himg);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    matrix<unsigned char> draw_fhog (\n        const std::vector<matrix<T> >& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_draw_size > 0 && hog.size()==31,\n            \"\\t matrix<unsigned char> draw_fhog()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_draw_size: \" << cell_draw_size \n            << \"\\n\\t hog.size(): \" << hog.size() \n        );\n\n        // Just convert the input into the right object and then call the above draw_fhog()\n        // function on it.\n        dlib::array<array2d<T> > temp(hog.size());\n        for (unsigned long i = 0; i < temp.size(); ++i)\n        {\n            temp[i].set_size(hog[i].nr(), hog[i].nc());\n            for (long r = 0; r < hog[i].nr(); ++r)\n            {\n                for (long c = 0; c < hog[i].nc(); ++c)\n                {\n                    temp[i][r][c] = hog[i](r,c);\n                }\n            }\n        }\n        return draw_fhog(temp,cell_draw_size, min_response_threshold);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename mm\n        >\n    matrix<unsigned char> draw_fhog(\n        const array2d<matrix<T,31,1>,mm>& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( cell_draw_size > 0,\n            \"\\t matrix<unsigned char> draw_fhog()\"\n            << \"\\n\\t Invalid inputs were given to this function. \"\n            << \"\\n\\t cell_draw_size: \" << cell_draw_size \n        );\n\n        dlib::array<matrix<float> > mbars;\n        impl_fhog::create_fhog_bar_images(mbars,cell_draw_size);\n\n        // now draw the bars onto the HOG cells\n        matrix<float> himg(hog.nr()*cell_draw_size, hog.nc()*cell_draw_size);\n        himg = 0;\n        for (unsigned long d = 0; d < mbars.size(); ++d)\n        {\n            for (long r = 0; r < himg.nr(); r+=cell_draw_size)\n            {\n                for (long c = 0; c < himg.nc(); c+=cell_draw_size)\n                {\n                    const float val = hog[r/cell_draw_size][c/cell_draw_size](d) +\n                        hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()) +\n                        hog[r/cell_draw_size][c/cell_draw_size](d+mbars.size()*2);\n                    if (val > min_response_threshold)\n                    {\n                        set_subm(himg, r, c, cell_draw_size, cell_draw_size) += val*mbars[d%mbars.size()];\n                    }\n                }\n            }\n        }\n\n        const float thresh = mean(himg) + 4 * stddev(himg);\n        if (thresh != 0)\n            return matrix_cast<unsigned char>(upperbound(round(himg*255/thresh),255));\n        else\n            return matrix_cast<unsigned char>(himg);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_fHOG_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/fhog_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_fHOG_ABSTRACT_Hh_\n#ifdef DLIB_fHOG_ABSTRACT_Hh_\n\n#include \"../matrix/matrix_abstract.h\"\n#include \"../array2d/array2d_kernel_abstract.h\"\n#include \"../array/array_kernel_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type, \n        typename T, \n        typename mm\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        array2d<matrix<T,31,1>,mm>& hog, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - T should be float or double\n        ensures\n            - This function implements the HOG feature extraction method described in \n              the paper:\n                Object Detection with Discriminatively Trained Part Based Models by\n                P. Felzenszwalb, R. Girshick, D. McAllester, D. Ramanan\n                IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 32, No. 9, Sep. 2010\n              This means that it takes an input image img and outputs Felzenszwalb's\n              31 dimensional version of HOG features, which are stored into #hog.\n            - The input image is broken into cells that are cell_size by cell_size pixels\n              and within each cell we compute a 31 dimensional FHOG vector.  This vector\n              describes the gradient structure within the cell.  \n            - A common task is to convolve each channel of the hog image with a linear\n              filter.  This is made more convenient if the contents of #hog includes extra\n              rows and columns of zero padding along the borders.  This extra padding\n              allows for more efficient convolution code since the code does not need to\n              perform expensive boundary checking.  Therefore, you can set\n              filter_rows_padding and filter_cols_padding to indicate the size of the\n              filter you wish to use and this function will ensure #hog has the appropriate\n              extra zero padding along the borders.  In particular, it will include the\n              following extra padding:\n                - (filter_rows_padding-1)/2 extra rows of zeros on the top of #hog.\n                - (filter_cols_padding-1)/2 extra columns of zeros on the left of #hog.\n                - filter_rows_padding/2 extra rows of zeros on the bottom of #hog.\n                - filter_cols_padding/2 extra columns of zeros on the right of #hog.\n              Therefore, the extra padding is done such that functions like\n              spatially_filter_image() apply their filters to the entire content containing\n              area of a hog image (note that you should use the following planar version of\n              extract_fhog_features() instead of the interlaced version if you want to use\n              spatially_filter_image() on a hog image).\n            - #hog.nr() == max(round(img.nr()/(double)cell_size)-2,0) + filter_rows_padding-1.\n            - #hog.nc() == max(round(img.nc()/(double)cell_size)-2,0) + filter_cols_padding-1.\n              (i.e.  Each output dimension is roughly 1/cell_size the original size but\n              there is a one cell_size border all around the image that is lost and then we\n              add on any additional padding that is requested.)\n            - for all valid r and c:\n                - #hog[r][c] == the FHOG vector describing the cell centered at the pixel location \n                  fhog_to_image(point(c,r),cell_size,filter_rows_padding,filter_cols_padding) in img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T, \n        typename mm1, \n        typename mm2\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        dlib::array<array2d<T,mm1>,mm2>& hog, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - T should be float or double\n        ensures\n            - This function is identical to the above extract_fhog_features() routine\n              except that it outputs the results in a planar format rather than the\n              interlaced format used above.  That is, each element of the hog vector is\n              placed into one of 31 images inside #hog.  To be precise, if vhog is the\n              output of the above interlaced version of extract_fhog_features() then we\n              will have, for all valid r and c:\n                - #hog[i][r][c] == vhog[r][c](i)\n                  (where 0 <= i < 31)\n            - #hog.size() == 31\n            - for all valid i:\n                - #hog[i].nr() == hog[0].nr()\n                - #hog[i].nc() == hog[0].nc()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    matrix<double,0,1> extract_fhog_features(\n        const image_type& img, \n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - This function calls the above extract_fhog_features() routine and simply\n              packages the entire output into a dlib::matrix.  The matrix is constructed\n              using the planar version of extract_fhog_features() and then each output\n              plane is converted into a column vector and subsequently all 31 column\n              vectors are concatenated together and returned.\n            - Each plane is converted into a column vector using reshape_to_column_vector(), \n              and is therefore represented in row major order inside the returned vector.  \n            - If H is the array<array2d<double>> object output by the planar\n              extract_fhog_features() then the returned vector is composed by concatenating\n              H[0], then H[1], then H[2], and so on in ascending index order.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_fhog_features(\n        const image_type& img, \n        matrix<T,0,1>& feats,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - T is float, double, or long double\n        ensures\n            - This function is identical to the above version of extract_fhog_features()\n              that returns a matrix<double,0,1> except that it returns the matrix here\n              through a reference argument instead of returning it by value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline point image_to_fhog (\n        point p,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n        ensures\n            - When using extract_fhog_features(), each FHOG cell is extracted from a\n              certain region in the input image.  image_to_fhog() returns the identity of\n              the FHOG cell containing the image pixel at location p.  Or in other words,\n              let P == image_to_fhog(p) and hog be a FHOG feature map output by\n              extract_fhog_features(), then hog[P.y()][P.x()] == the FHOG vector/cell\n              containing the point p in the input image.  Note that some image points\n              might not have corresponding feature locations.  E.g. border points or points\n              outside the image.  In these cases the returned point will be outside the\n              input image.\n            - Note that you should use the same values of cell_size, filter_rows_padding,\n              and filter_cols_padding that you used with extract_fhog_features().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle image_to_fhog (\n        const rectangle& rect,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n        ensures\n            - maps a rectangle from image space to fhog space.  In particular this function returns:\n              rectangle(image_to_fhog(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding), \n                        image_to_fhog(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline point fhog_to_image (\n        point p,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n        ensures\n            - Maps a pixel in a FHOG image (produced by extract_fhog_features()) back to the\n              corresponding original input pixel.  Note that since FHOG images are\n              spatially downsampled by aggregation into cells the mapping is not totally\n              invertible.  Therefore, the returned location will be the center of the cell\n              in the original image that contained the FHOG vector at position p.  Moreover,\n              cell_size, filter_rows_padding, and filter_cols_padding should be set to the\n              values used by the call to extract_fhog_features().\n            - Mapping from fhog space to image space is an invertible transformation.  That\n              is, for any point P we have P == image_to_fhog(fhog_to_image(P,cell_size,filter_rows_padding,filter_cols_padding),\n                                                             cell_size,filter_rows_padding,filter_cols_padding).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline rectangle fhog_to_image (\n        const rectangle& rect,\n        int cell_size = 8,\n        int filter_rows_padding = 1,\n        int filter_cols_padding = 1\n    );\n    /*!\n        requires\n            - cell_size > 0\n            - filter_rows_padding > 0\n            - filter_cols_padding > 0\n        ensures\n            - maps a rectangle from fhog space to image space.  In particular this function returns:\n              rectangle(fhog_to_image(rect.tl_corner(),cell_size,filter_rows_padding,filter_cols_padding), \n                        fhog_to_image(rect.br_corner(),cell_size,filter_rows_padding,filter_cols_padding))\n            - Mapping from fhog space to image space is an invertible transformation.  That\n              is, for any rectangle R we have R == image_to_fhog(fhog_to_image(R,cell_size,filter_rows_padding,filter_cols_padding),\n                                                                 cell_size,filter_rows_padding,filter_cols_padding).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename mm1, \n        typename mm2\n        >\n    matrix<unsigned char> draw_fhog(\n        const dlib::array<array2d<T,mm1>,mm2>& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    );\n    /*!\n        requires\n            - cell_draw_size > 0\n            - hog.size() == 31\n        ensures\n            - Interprets hog as a FHOG feature map output by extract_fhog_features() and\n              converts it into an image suitable for display on the screen.  In particular,\n              we draw all the hog cells into a grayscale image in a way that shows the\n              magnitude and orientation of the gradient energy in each cell.  The result is\n              then returned.\n            - The size of the cells in the output image will be rendered as cell_draw_size \n              pixels wide and tall.\n            - HOG cells with a response value less than min_response_threshold are not\n              drawn.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    matrix<unsigned char> draw_fhog (\n        const std::vector<matrix<T> >& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    );\n    /*!\n        requires\n            - cell_draw_size > 0\n            - hog.size() == 31\n        ensures\n            - This function just converts the given hog object into an array<array2d<T>>\n              and passes it to the above draw_fhog() routine and returns the results.\n            - HOG cells with a response value less than min_response_threshold are not\n              drawn.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename mm\n        >\n    matrix<unsigned char> draw_fhog(\n        const array2d<matrix<T,31,1>,mm>& hog,\n        const long cell_draw_size = 15,\n        const float min_response_threshold = 0.0\n    );\n    /*!\n        requires\n            - cell_draw_size > 0\n        ensures\n            - Interprets hog as a FHOG feature map output by extract_fhog_features() and\n              converts it into an image suitable for display on the screen.  In particular,\n              we draw all the hog cells into a grayscale image in a way that shows the\n              magnitude and orientation of the gradient energy in each cell.  The result is \n              then returned.\n            - The size of the cells in the output image will be rendered as cell_draw_size \n              pixels wide and tall.\n            - HOG cells with a response value less than min_response_threshold are not\n              drawn.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_fHOG_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/hough_transform.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_HOUGH_tRANSFORM_Hh_\n#define DLIB_HOUGH_tRANSFORM_Hh_\n\n#include \"hough_transform_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n#include \"../geometry.h\"\n#include \"../algs.h\"\n#include \"assign_image.h\"\n#include <limits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class hough_transform\n    {\n\n    public:\n        explicit hough_transform (\n            unsigned long size_\n        ) : _size(size_) \n        {\n            DLIB_CASSERT(size_ > 0,\n                \"\\t hough_transform::hough_transform(size_)\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                );\n\n            even_size = _size - (_size%2);\n\n            const point cent = center(rectangle(0,0,size_-1,size_-1));\n            xcos_theta.set_size(size_, size_);\n            ysin_theta.set_size(size_, size_);\n\n            std::vector<double> cos_theta(size_), sin_theta(size_);\n            const double scale = 1<<16;\n            for (unsigned long t = 0; t < size_; ++t)\n            {\n                double theta = t*pi/even_size;\n\n                cos_theta[t] = scale*std::cos(theta)/sqrt_2;\n                sin_theta[t] = scale*std::sin(theta)/sqrt_2;\n            }\n            const double offset = scale*even_size/4.0 + 0.5;\n\n            for (unsigned long c = 0; c < size_; ++c)\n            {\n                const long x = c - cent.x();\n                for (unsigned long t = 0; t < size_; ++t)\n                    xcos_theta(c,t) = static_cast<int32>(x*cos_theta[t] + offset);\n            }\n            for (unsigned long r = 0; r < size_; ++r)\n            {\n                const long y = r - cent.y();\n                for (unsigned long t = 0; t < size_; ++t)\n                    ysin_theta(r,t) = static_cast<int32>(y*sin_theta[t] + offset);\n            }\n        }\n\n        inline unsigned long size(\n        ) const { return _size; }\n\n        long nr(\n        ) const { return _size; }\n\n        long nc(\n        ) const { return _size; }\n\n        std::pair<dpoint, dpoint> get_line (\n            const dpoint& p\n        ) const\n        {\n            DLIB_ASSERT(rectangle(0,0,size()-1,size()-1).contains(p) == true,\n                \"\\t pair<dpoint,dpoint> hough_transform::get_line(dpoint)\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t p:      \" << p \n                << \"\\n\\t size(): \" << size()\n                );\n\n            // First we compute the radius measured in pixels from the center and the theta\n            // angle in radians.\n            double theta, radius;\n            get_line_properties(p, theta, radius);\n            theta *= pi/180;\n\n            // now make a line segment on the line.\n            const rectangle box = get_rect(*this);\n            const dpoint cent = center(box);\n            dpoint v1 = cent + dpoint(size()+1000,0) + dpoint(0,radius);\n            dpoint v2 = cent - dpoint(size()+1000,0) + dpoint(0,radius);\n            dpoint p1 = rotate_point(cent, v1, theta);\n            dpoint p2 = rotate_point(cent, v2, theta);\n\n            clip_line_to_rectangle(box, p1, p2);\n\n            return std::make_pair(p1,p2);\n        }\n\n        double get_line_angle_in_degrees (\n            const dpoint& p \n        ) const\n        {\n            double angle, radius;\n            get_line_properties(p, angle, radius);\n            return angle;\n        }\n\n        void get_line_properties (\n            const dpoint& p,\n            double& angle_in_degrees,\n            double& radius\n        ) const\n        {\n            const dpoint cent = center(get_rect(*this));\n            double theta = p.x()-cent.x();\n            radius = p.y()-cent.y();\n            angle_in_degrees = 180*theta/even_size;\n            radius = radius*sqrt_2 + 0.5;\n        }\n\n        template <\n            typename image_type\n            >\n        point get_best_hough_point (\n            const point& p,\n            const image_type& himg_\n        )\n        {\n            const const_image_view<image_type> himg(himg_);\n\n            DLIB_ASSERT(himg.nr() == size() && himg.nc() == size() &&\n                rectangle(0,0,size()-1,size()-1).contains(p) == true,\n                \"\\t point hough_transform::get_best_hough_point()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t himg.nr(): \" << himg.nr()\n                << \"\\n\\t himg.nc(): \" << himg.nc()\n                << \"\\n\\t size():    \" << size()\n                << \"\\n\\t p:         \" << p \n                );\n\n\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::grayscale == true);\n            pixel_type best_val = std::numeric_limits<pixel_type>::min();\n            point best_point;\n\n\n            const long max_n8 = (himg.nc()/8)*8;\n            const long max_n4 = (himg.nc()/4)*4;\n            const long r = p.y();\n            const long c = p.x();\n\n            const int32* ysin = &ysin_theta(r,0);\n            const int32* xcos = &xcos_theta(c,0);\n            long t = 0;\n            while(t < max_n8)\n            {\n                long rr0 = (*xcos++ + *ysin++)>>16;\n                long rr1 = (*xcos++ + *ysin++)>>16;\n                long rr2 = (*xcos++ + *ysin++)>>16;\n                long rr3 = (*xcos++ + *ysin++)>>16;\n                long rr4 = (*xcos++ + *ysin++)>>16;\n                long rr5 = (*xcos++ + *ysin++)>>16;\n                long rr6 = (*xcos++ + *ysin++)>>16;\n                long rr7 = (*xcos++ + *ysin++)>>16;\n\n                if (himg[rr0][t++] > best_val)\n                {\n                    best_val = himg[rr0][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr0;\n                }\n                if (himg[rr1][t++] > best_val)\n                {\n                    best_val = himg[rr1][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr1;\n                }\n                if (himg[rr2][t++] > best_val)\n                {\n                    best_val = himg[rr2][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr2;\n                }\n                if (himg[rr3][t++] > best_val)\n                {\n                    best_val = himg[rr3][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr3;\n                }\n                if (himg[rr4][t++] > best_val)\n                {\n                    best_val = himg[rr4][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr4;\n                }\n                if (himg[rr5][t++] > best_val)\n                {\n                    best_val = himg[rr5][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr5;\n                }\n                if (himg[rr6][t++] > best_val)\n                {\n                    best_val = himg[rr6][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr6;\n                }\n                if (himg[rr7][t++] > best_val)\n                {\n                    best_val = himg[rr7][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr7;\n                }\n            }\n            while(t < max_n4)\n            {\n                long rr0 = (*xcos++ + *ysin++)>>16;\n                long rr1 = (*xcos++ + *ysin++)>>16;\n                long rr2 = (*xcos++ + *ysin++)>>16;\n                long rr3 = (*xcos++ + *ysin++)>>16;\n                if (himg[rr0][t++] > best_val)\n                {\n                    best_val = himg[rr0][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr0;\n                }\n                if (himg[rr1][t++] > best_val)\n                {\n                    best_val = himg[rr1][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr1;\n                }\n                if (himg[rr2][t++] > best_val)\n                {\n                    best_val = himg[rr2][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr2;\n                }\n                if (himg[rr3][t++] > best_val)\n                {\n                    best_val = himg[rr3][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr3;\n                }\n            }\n            while(t < himg.nc())\n            {\n                long rr0 = (*xcos++ + *ysin++)>>16;\n                if (himg[rr0][t++] > best_val)\n                {\n                    best_val = himg[rr0][t-1];\n                    best_point.x() = t-1;\n                    best_point.y() = rr0;\n                }\n            }\n\n            return best_point;\n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& img_,\n            const rectangle& box,\n            out_image_type& himg_\n        ) const\n        {\n            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n\n            DLIB_CASSERT(box.width() == size() && box.height() == size(),\n                \"\\t void hough_transform::operator()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t box.width():  \" << box.width()\n                << \"\\n\\t box.height(): \" << box.height()\n                << \"\\n\\t size():       \" << size()\n                );\n\n            COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale == true);\n            COMPILE_TIME_ASSERT(pixel_traits<out_pixel_type>::grayscale == true);\n\n            const_image_view<in_image_type> img(img_);\n            image_view<out_image_type> himg(himg_);\n\n            himg.set_size(size(), size());\n            assign_all_pixels(himg, 0);\n\n            auto record_hit = [&](const point& hough_point, const point& /*img_point*/, const in_pixel_type& val)\n            {\n                himg[hough_point.y()][hough_point.x()] += val;\n            };\n            perform_generic_hough_transform(img_, box, record_hit);\n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& img_,\n            out_image_type& himg_\n        ) const\n        {\n            rectangle box(0,0, num_columns(img_)-1, num_rows(img_)-1);\n            (*this)(img_, box, himg_);\n        }\n\n        template <\n            typename in_image_type\n            >\n        std::vector<std::vector<point>> find_pixels_voting_for_lines (\n            const in_image_type& img,\n            const rectangle& box,\n            const std::vector<point>& hough_points,\n            const unsigned long angle_window_size = 1,\n            const unsigned long radius_window_size = 1\n        ) const\n        {\n\n            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n\n            DLIB_CASSERT(angle_window_size >= 1);\n            DLIB_CASSERT(radius_window_size >= 1);\n            DLIB_CASSERT(box.width() == size() && box.height() == size(),\n                \"\\t std::vector<std::vector<point>> hough_transform::find_pixels_voting_for_lines()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t box.width():  \" << box.width()\n                << \"\\n\\t box.height(): \" << box.height()\n                << \"\\n\\t size():       \" << size()\n                );\n#ifdef ENABLE_ASSERTS\n            for (auto& p : hough_points)\n                DLIB_CASSERT(get_rect(*this).contains(p), \n                    \"You gave a hough_points that isn't actually in the Hough space of this object.\"\n                    << \"\\n\\t get_rect(*this): \"<< get_rect(*this) \n                    << \"\\n\\t p: \"<< p \n                    );\n#endif\n\n            std::vector<std::vector<point>> constituent_points(hough_points.size());\n\n            // make a map that lets us look up in constant time if a hough point is in the\n            // constituent_points output and if so where.\n            matrix<uint32> hmap(size(),size());\n            hmap = hough_points.size();\n            for (size_t i = 0; i < hough_points.size(); ++i)\n            {\n                rectangle area = centered_rect(hough_points[i],angle_window_size,radius_window_size).intersect(get_rect(hmap));\n                for (long r = area.top(); r <= area.bottom(); ++r)\n                {\n                    for (long c = area.left(); c <= area.right(); ++c)\n                    {\n                        hmap(r,c) = i;\n                    }\n                }\n            }\n\n            // record that this image point voted for this Hough point\n            auto record_hit = [&](const point& hough_point, const point& img_point, in_pixel_type)\n            {\n                auto idx = hmap(hough_point.y(), hough_point.x());\n                if (idx < constituent_points.size())\n                {\n                    // don't add img_point if it's already in the list.\n                    if (constituent_points[idx].size() == 0 || constituent_points[idx].back() != img_point)\n                        constituent_points[idx].push_back(img_point);\n                }\n            };\n\n            perform_generic_hough_transform(img, box, record_hit);\n\n            return constituent_points;\n        }\n\n        template <\n            typename in_image_type\n            >\n        std::vector<std::vector<point>> find_pixels_voting_for_lines (\n            const in_image_type& img,\n            const std::vector<point>& hough_points,\n            const unsigned long angle_window_size = 1,\n            const unsigned long radius_window_size = 1\n        ) const\n        {\n            rectangle box(0,0, num_columns(img)-1, num_rows(img)-1);\n            return find_pixels_voting_for_lines(img, box, hough_points, angle_window_size, radius_window_size);\n        }\n\n        template <\n            typename image_type,\n            typename thresh_type\n            >\n        std::vector<point> find_strong_hough_points(\n            const image_type& himg_,\n            const thresh_type hough_count_threshold,\n            const double angle_nms_thresh,\n            const double radius_nms_thresh\n        )\n        {\n            const_image_view<image_type> himg(himg_);\n\n            DLIB_CASSERT(himg.nr() == size());\n            DLIB_CASSERT(himg.nc() == size());\n            DLIB_CASSERT(angle_nms_thresh >= 0)\n            DLIB_CASSERT(radius_nms_thresh >= 0)\n\n            std::vector<std::pair<double,point>> initial_lines;\n            for (long r = 0; r < himg.nr(); ++r)\n            {\n                for (long c = 0; c < himg.nc(); ++c)\n                {\n                    if (himg[r][c] >= hough_count_threshold)\n                        initial_lines.emplace_back(himg[r][c], point(c,r));\n                }\n            }\n\n\n            std::vector<point> final_lines;\n            std::vector<std::pair<double,double>> final_angle_and_radius;\n\n            // Now do non-max suppression.  First, sort the initial_lines so the best lines come first.\n            std::sort(initial_lines.rbegin(), initial_lines.rend(), \n                [](const std::pair<double,point>& a, const std::pair<double,point>& b){ return a.first<b.first;});\n            for (auto& r : initial_lines)\n            {\n                double angle, radius;\n                get_line_properties(r.second, angle, radius);\n\n                // check if anything in final_lines is too close to r.second.  If\n                // something is found then discard r.second.\n                auto too_close = false;\n                for (auto& ref : final_angle_and_radius)\n                {\n                    auto& ref_angle = ref.first;\n                    auto& ref_radius = ref.second;\n\n                    // We need to check for wrap around in angle since, for instance, a\n                    // line with angle and radius of 90 and 10 is the same line as one with\n                    // angle -90 and radius -10.\n                    if ((std::abs(ref_angle - angle) < angle_nms_thresh && std::abs(ref_radius-radius) < radius_nms_thresh) ||\n                        (180 - std::abs(ref_angle - angle) < angle_nms_thresh && std::abs(ref_radius+radius) < radius_nms_thresh))\n                    {\n                        too_close = true;\n                        break;\n                    }\n                }\n\n                if (!too_close)\n                {\n                    final_lines.emplace_back(r.second);\n                    final_angle_and_radius.emplace_back(angle, radius);\n                }\n            }\n\n            return final_lines;\n        }\n\n\n        template <\n            typename in_image_type,\n            typename record_hit_function_type\n            >\n        void perform_generic_hough_transform (\n            const in_image_type& img_,\n            const rectangle& box,\n            record_hit_function_type record_hit\n        ) const\n        {\n\n            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n\n            DLIB_ASSERT(box.width() == size() && box.height() == size(),\n                \"\\t void hough_transform::perform_generic_hough_transform()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t box.width():  \" << box.width()\n                << \"\\n\\t box.height(): \" << box.height()\n                << \"\\n\\t size():       \" << size()\n                );\n\n            COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale == true);\n\n\n            const_image_view<in_image_type> img(img_);\n\n\n            const rectangle area = box.intersect(get_rect(img));\n\n            const long max_n8 = (size()/8)*8;\n            const long max_n4 = (size()/4)*4;\n            for (long r = area.top(); r <= area.bottom(); ++r)\n            {\n                const int32* ysin_base = &ysin_theta(r-box.top(),0);\n                for (long c = area.left(); c <= area.right(); ++c)\n                {\n                    const auto val = img[r][c];\n                    if (val != 0)\n                    {\n                        /*\n                        // The code in this comment is equivalent to the more complex but\n                        // faster code below.  We keep this simple version of the Hough\n                        // transform implementation here just to document what it's doing\n                        // more clearly.\n                        const point cent = center(box);\n                        const long x = c - cent.x();\n                        const long y = r - cent.y();\n                        for (long t = 0; t < size(); ++t)\n                        {\n                            double theta = t*pi/even_size;\n                            double radius = (x*std::cos(theta) + y*std::sin(theta))/sqrt_2 + even_size/2 + 0.5;\n                            long rr = static_cast<long>(radius);\n\n                            record_hit(point(t,rr), point(c,r), val);\n                        }\n                        continue;\n                        */\n\n                        // Run the speed optimized version of the code in the above\n                        // comment.\n                        const int32* ysin = ysin_base;\n                        const int32* xcos = &xcos_theta(c-box.left(),0);\n                        long t = 0;\n                        while(t < max_n8)\n                        {\n                            long rr0 = (*xcos++ + *ysin++)>>16;\n                            long rr1 = (*xcos++ + *ysin++)>>16;\n                            long rr2 = (*xcos++ + *ysin++)>>16;\n                            long rr3 = (*xcos++ + *ysin++)>>16;\n                            long rr4 = (*xcos++ + *ysin++)>>16;\n                            long rr5 = (*xcos++ + *ysin++)>>16;\n                            long rr6 = (*xcos++ + *ysin++)>>16;\n                            long rr7 = (*xcos++ + *ysin++)>>16;\n\n                            record_hit(point(t++,rr0), point(c,r), val);\n                            record_hit(point(t++,rr1), point(c,r), val);\n                            record_hit(point(t++,rr2), point(c,r), val);\n                            record_hit(point(t++,rr3), point(c,r), val);\n                            record_hit(point(t++,rr4), point(c,r), val);\n                            record_hit(point(t++,rr5), point(c,r), val);\n                            record_hit(point(t++,rr6), point(c,r), val);\n                            record_hit(point(t++,rr7), point(c,r), val);\n                        }\n                        while(t < max_n4)\n                        {\n                            long rr0 = (*xcos++ + *ysin++)>>16;\n                            long rr1 = (*xcos++ + *ysin++)>>16;\n                            long rr2 = (*xcos++ + *ysin++)>>16;\n                            long rr3 = (*xcos++ + *ysin++)>>16;\n                            record_hit(point(t++,rr0), point(c,r), val);\n                            record_hit(point(t++,rr1), point(c,r), val);\n                            record_hit(point(t++,rr2), point(c,r), val);\n                            record_hit(point(t++,rr3), point(c,r), val);\n                        }\n                        while(t < (long)size())\n                        {\n                            long rr0 = (*xcos++ + *ysin++)>>16;\n                            record_hit(point(t++,rr0), point(c,r), val);\n                        }\n                    }\n                }\n            }\n        }\n\n        template <\n            typename in_image_type,\n            typename record_hit_function_type\n            >\n        void perform_generic_hough_transform (\n            const in_image_type& img_,\n            record_hit_function_type record_hit\n        ) const\n        {\n            rectangle box(0,0, num_columns(img_)-1, num_rows(img_)-1);\n            perform_generic_hough_transform(img_, box, record_hit);\n        }\n        \n    private:\n\n        unsigned long _size;\n        unsigned long even_size; // equal to _size if _size is even, otherwise equal to _size-1.\n        matrix<int32> xcos_theta, ysin_theta;\n    };\n}\n\n#endif // DLIB_HOUGH_tRANSFORM_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/hough_transform_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_\n#ifdef DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_\n\n#include \"../geometry.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class hough_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for computing the line finding version of the Hough\n                transform given some kind of edge detection image as input.  It also allows\n                the edge pixels to be weighted such that higher weighted edge pixels\n                contribute correspondingly more to the output of the Hough transform,\n                allowing stronger edges to create correspondingly stronger line detections\n                in the final Hough transform.\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent accesses to this object\n                without synchronization.\n        !*/\n\n    public:\n\n        explicit hough_transform (\n            unsigned long size_\n        ); \n        /*!\n            requires\n                - size_ > 0\n            ensures\n                - This object will compute Hough transforms that are size_ by size_ pixels.  \n                  This is in terms of both the Hough accumulator array size as well as the\n                  input image size.\n                - #size() == size_\n        !*/\n\n        unsigned long size(\n        ) const;\n        /*!\n            ensures\n                - returns the size of the Hough transforms generated by this object.  In\n                  particular, this object creates Hough transform images that are size() by\n                  size() pixels in size.\n        !*/\n\n        long nr(\n        ) const;\n        /*!\n            ensures\n                - returns size()\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns size()\n        !*/\n\n        std::pair<dpoint, dpoint> get_line (\n            const dpoint& p\n        ) const;\n        /*!\n            requires\n                - rectangle(0,0,size()-1,size()-1).contains(p) == true\n                  (i.e. p must be a point inside the Hough accumulator array)\n            ensures\n                - returns the line segment in the original image space corresponding\n                  to Hough transform point p. \n                - The returned points are inside rectangle(0,0,size()-1,size()-1).\n        !*/\n\n        double get_line_angle_in_degrees (\n            const dpoint& p \n        ) const;\n        /*!\n            requires\n                - rectangle(0,0,size()-1,size()-1).contains(p) == true\n                  (i.e. p must be a point inside the Hough accumulator array)\n            ensures\n                - returns the angle, in degrees, of the line corresponding to the Hough\n                  transform point p.\n        !*/\n\n        void get_line_properties (\n            const dpoint& p,\n            double& angle_in_degrees,\n            double& radius\n        ) const;\n        /*!\n            requires\n                - rectangle(0,0,size()-1,size()-1).contains(p) == true\n                  (i.e. p must be a point inside the Hough accumulator array)\n            ensures\n                - Converts a point in the Hough transform space into an angle, in degrees,\n                  and a radius, measured in pixels from the center of the input image.\n                - #angle_in_degrees == the angle of the line corresponding to the Hough\n                  transform point p.  Moreover: -90 <= #angle_in_degrees < 90.\n                - #radius == the distance from the center of the input image, measured in\n                  pixels, and the line corresponding to the Hough transform point p.\n                  Moreover: -sqrt(size()*size()/2) <= #radius <= sqrt(size()*size()/2)\n                - Note that the line properties are calculated to sub-pixel accuracy.  That\n                  is, p doesn't have to contain integer values, it can reference locations\n                  between pixels and the appropriate calculation will be done to find the\n                  corresponding line.\n        !*/\n\n        template <\n            typename image_type\n            >\n        point get_best_hough_point (\n            const point& p,\n            const image_type& himg\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - himg.nr() == size()\n                - himg.nc() == size()\n                - rectangle(0,0,size()-1,size()-1).contains(p) == true\n            ensures\n                - This function interprets himg as a Hough image and p as a point in the\n                  original image space.  Given this, it finds the maximum scoring line that\n                  passes though p.  That is, it checks all the Hough accumulator bins in\n                  himg corresponding to lines though p and returns the location with the\n                  largest score.  \n                - returns a point X such that get_rect(himg).contains(X) == true\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& img,\n            const rectangle& box,\n            out_image_type& himg\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - out_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - box.width() == size()\n                - box.height() == size()\n            ensures\n                - Computes the Hough transform of the part of img contained within box.\n                  In particular, we do a grayscale version of the Hough transform where any\n                  non-zero pixel in img is treated as a potential component of a line and\n                  accumulated into the Hough accumulator #himg.  However, rather than\n                  adding 1 to each relevant accumulator bin we add the value of the pixel\n                  in img to each Hough accumulator bin.  This means that, if all the\n                  pixels in img are 0 or 1 then this routine performs a normal Hough\n                  transform.  However, if some pixels have larger values then they will be\n                  weighted correspondingly more in the resulting Hough transform.\n                - #himg.nr() == size()\n                - #himg.nc() == size()\n                - #himg is the Hough transform of the part of img contained in box.  Each\n                  point in #himg corresponds to a line in the input box.  In particular,\n                  the line for #himg[y][x] is given by get_line(point(x,y)).  Also, when\n                  viewing the #himg image, the x-axis gives the angle of the line and the\n                  y-axis the distance of the line from the center of the box.  The\n                  conversion between Hough coordinates and angle and pixel distance can be\n                  obtained by calling get_line_properties().\n        !*/\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& img,\n            out_image_type& himg\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - out_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - num_rows(img) == size()\n                - num_columns(img) == size()\n            ensures\n                - performs: (*this)(img, get_rect(img), himg);\n                  That is, just runs the hough transform on the whole input image.\n        !*/\n\n        template <\n            typename in_image_type\n            >\n        std::vector<std::vector<point>> find_pixels_voting_for_lines (\n            const in_image_type& img,\n            const rectangle& box,\n            const std::vector<point>& hough_points,\n            const unsigned long angle_window_size = 1,\n            const unsigned long radius_window_size = 1\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - box.width() == size()\n                - box.height() == size()\n                - for all valid i:\n                    - get_rect(*this).contains(hough_points[i]) == true\n                      (i.e. hough_points must contain points in the output Hough transform\n                      space generated by this object.)\n                - angle_window_size >= 1\n                - radius_window_size >= 1\n            ensures\n                - This function computes the Hough transform of the part of img contained\n                  within box.  It does the same computation as operator() defined above,\n                  except instead of accumulating into an image we create an explicit list\n                  of all the points in img that contributed to each line (i.e each point in\n                  the Hough image). To do this we take a list of Hough points as input and\n                  only record hits on these specifically identified Hough points.  A\n                  typical use of find_pixels_voting_for_lines() is to first run the normal\n                  Hough transform using operator(), then find the lines you are interested\n                  in, and then call find_pixels_voting_for_lines() to determine which\n                  pixels in the input image belong to those lines.\n                - This routine returns a vector, CONSTITUENT_POINTS, with the following\n                  properties:\n                    - #CONSTITUENT_POINTS.size() == hough_points.size()\n                    - for all valid i:\n                        - Let HP[i] = centered_rect(hough_points[i], angle_window_size, radius_window_size)\n                        - Any point in img with a non-zero value that lies on a line\n                          corresponding to one of the Hough points in HP[i] is added to\n                          CONSTITUENT_POINTS[i].  Therefore, when this routine finishes,\n                          #CONSTITUENT_POINTS[i] will contain all the points in img that\n                          voted for the lines associated with the Hough accumulator bins in\n                          HP[i].\n                        - #CONSTITUENT_POINTS[i].size() == the number of points in img that\n                          voted for any of the lines HP[i] in Hough space.  Note, however,\n                          that if angle_window_size or radius_window_size are made so large\n                          that HP[i] overlaps HP[j] for i!=j then the overlapping regions\n                          of Hough space are assigned to HP[i] or HP[j] arbitrarily.\n                          That is, we treat HP[i] and HP[j] as disjoint even if their boxes\n                          overlap.  In this case, the overlapping region is assigned to\n                          either HP[i] or HP[j] in an arbitrary manner.\n        !*/\n\n        template <\n            typename in_image_type\n            >\n        std::vector<std::vector<point>> find_pixels_voting_for_lines (\n            const in_image_type& img,\n            const std::vector<point>& hough_points,\n            const unsigned long angle_window_size = 1,\n            const unsigned long radius_window_size = 1\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - num_rows(img) == size()\n                - num_columns(img) == size()\n                - for all valid i:\n                    - get_rect(*this).contains(hough_points[i]) == true\n                      (i.e. hough_points must contain points in the output Hough transform\n                      space generated by this object.)\n                - angle_window_size >= 1\n                - radius_window_size >= 1\n            ensures\n                - performs: return find_pixels_voting_for_lines(img, get_rect(img), hough_points, angle_window_size, radius_window_size);\n                  That is, just runs the routine on the whole input image.\n        !*/\n\n        template <\n            typename image_type,\n            typename thresh_type\n            >\n        std::vector<point> find_strong_hough_points(\n            const image_type& himg,\n            const thresh_type hough_count_threshold,\n            const double angle_nms_thresh,\n            const double radius_nms_thresh\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - himg.nr() == size()\n                - himg.nc() == size()\n                - angle_nms_thresh >= 0\n                - radius_nms_thresh >= 0\n            ensures\n                - This routine finds strong lines in a Hough transform and performs\n                  non-maximum suppression on the detected lines.  Recall that each point in\n                  Hough space is associated with a line. Therefore, this routine finds all\n                  the pixels in himg (a Hough transform image) with values >=\n                  hough_count_threshold and performs non-maximum suppression on the\n                  identified list of pixels.  It does this by discarding lines that are\n                  within angle_nms_thresh degrees of a stronger line or within\n                  radius_nms_thresh distance (in terms of radius as defined by\n                  get_line_properties()) to a stronger Hough point.\n                - The identified lines are returned as a list of coordinates in himg.\n                - The returned points are sorted so that points with larger Hough transform\n                  values come first.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename record_hit_function_type\n            >\n        void perform_generic_hough_transform (\n            const in_image_type& img,\n            const rectangle& box,\n            record_hit_function_type record_hit\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - box.width() == size()\n                - box.height() == size()\n                - record_hit is a function object with the signature:\n                    void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value)\n            ensures\n                - Computes the Hough transform of the part of img contained within box.\n                  This routine is very general and allows you to implement a wide variety\n                  of Hough transforms, in fact, the operator() and\n                  find_pixels_voting_for_lines() routines defined above are implemented in\n                  terms of perform_generic_hough_transform().  The behavior is described by\n                  the following pseudo-code:\n                    for (image_coordinate : all_coordinates_in_img)\n                        for (hough_point : all_Hough_space_coordinates_for_lines_passing_through_image_coordinate)\n                            record_hit(hough_point, image_coordinate, img[image_coordinate.y][image_coordinate.x()]);\n                  That is, we perform the Hough transform, but rather than accumulating\n                  into a Hough accumulator image, we call record_hit() and record_hit()\n                  does whatever it wants.  For example, in the operator() method defined\n                  above record_hit() simply accumulates into an image, and therefor\n                  performs the classic Hough transform.  But there are many other options.\n        !*/\n\n        template <\n            typename in_image_type,\n            typename record_hit_function_type\n            >\n        void perform_generic_hough_transform (\n            const in_image_type& img,\n            record_hit_function_type record_hit\n        ) const;\n        /*!\n            requires\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n                - record_hit is a function object with the signature:\n                    void record_hit(const point& hough_point, const point& img_point, in_image_pixel_type value)\n                - num_rows(img) == size()\n                - num_columns(img) == size()\n            ensures\n                - performs: perform_generic_hough_transform(img, get_rect(img), record_hit);\n                  That is, just runs the routine on the whole input image.\n        !*/\n\n    };\n}\n\n#endif // DLIB_HOUGH_tRANSFORM_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/image_pyramid.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IMAGE_PYRaMID_Hh_\n#define DLIB_IMAGE_PYRaMID_Hh_\n\n#include \"image_pyramid_abstract.h\"\n#include \"../pixel.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include \"spatial_filtering.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class pyramid_disable : noncopyable\n    {\n    public:\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& \n        ) const\n        {\n            return vector<double,2>(0,0);\n        }\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& \n        ) const\n        {\n            return vector<double,2>(0,0);\n        }\n\n    // -----------------------------\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const\n        {\n            if (levels == 0)\n                return p;\n            else\n                return vector<double,2>(0,0);\n        }\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const\n        {\n            if (levels == 0)\n                return p;\n            else\n                return vector<double,2>(0,0);\n        }\n\n    // -----------------------------\n\n        drectangle rect_up (\n            const drectangle& rect\n        ) const\n        {\n            return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));\n        }\n\n        drectangle rect_up (\n            const drectangle& rect,\n            unsigned int levels\n        ) const\n        {\n            return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));\n        }\n\n    // -----------------------------\n\n        drectangle rect_down (\n            const drectangle& rect\n        ) const\n        {\n            return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));\n        }\n\n        drectangle rect_down (\n            const drectangle& rect,\n            unsigned int levels\n        ) const\n        {\n            return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));\n        }\n\n    // -----------------------------\n\n    public:\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            // we do this #ifdef stuff to avoid compiler warnings about unused variables.\n#ifdef ENABLE_ASSERTS\n            const in_image_type& original,\n#else\n            const in_image_type& ,\n#endif\n            out_image_type& down\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_same_object(original, down) == false, \n                        \"\\t void pyramid_disable::operator()\"\n                        << \"\\n\\t is_same_object(original, down): \" << is_same_object(original, down) \n                        << \"\\n\\t this:                           \" << this\n                        );\n\n            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n            COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n            COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n            set_image_size(down, 0, 0);\n        }\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            image_type& img\n        ) const\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            COMPILE_TIME_ASSERT( pixel_traits<pixel_type>::has_alpha == false );\n            set_image_size(img, 0, 0);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n        class pyramid_down_2_1 : noncopyable\n        {\n        public:\n\n            template <typename T>\n            vector<double,2> point_down (\n                const vector<T,2>& p\n            ) const\n            {\n                return p/2.0 - vector<double,2>(1.25,0.75);\n            }\n\n            template <typename T>\n            vector<double,2> point_up (\n                const vector<T,2>& p\n            ) const\n            {\n                return (p + vector<T,2>(1.25,0.75))*2;\n            }\n\n        // -----------------------------\n\n            template <typename T>\n            vector<double,2> point_down (\n                const vector<T,2>& p,\n                unsigned int levels\n            ) const\n            {\n                vector<double,2> temp = p;\n                for (unsigned int i = 0; i < levels; ++i)\n                    temp = point_down(temp);\n                return temp;\n            }\n\n            template <typename T>\n            vector<double,2> point_up (\n                const vector<T,2>& p,\n                unsigned int levels\n            ) const\n            {\n                vector<double,2> temp = p;\n                for (unsigned int i = 0; i < levels; ++i)\n                    temp = point_up(temp);\n                return temp;\n            }\n\n        // -----------------------------\n\n            drectangle rect_up (\n                const drectangle& rect\n            ) const\n            {\n                return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));\n            }\n\n            drectangle rect_up (\n                const drectangle& rect,\n                unsigned int levels\n            ) const\n            {\n                return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));\n            }\n\n        // -----------------------------\n\n            drectangle rect_down (\n                const drectangle& rect\n            ) const\n            {\n                return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));\n            }\n\n            drectangle rect_down (\n                const drectangle& rect,\n                unsigned int levels\n            ) const\n            {\n                return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));\n            }\n\n        // -----------------------------\n\n        private:\n            template <typename T, typename U>\n            struct both_images_rgb\n            {\n                typedef typename image_traits<T>::pixel_type T_pix;\n                typedef typename image_traits<U>::pixel_type U_pix;\n                const static bool value = pixel_traits<T_pix>::rgb && pixel_traits<U_pix>::rgb;\n            };\n        public:\n\n            template <\n                typename in_image_type,\n                typename out_image_type\n                >\n            typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (\n                const in_image_type& original_,\n                out_image_type& down_\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT( is_same_object(original_, down_) == false, \n                            \"\\t void pyramid_down_2_1::operator()\"\n                            << \"\\n\\t is_same_object(original_, down_): \" << is_same_object(original_, down_) \n                            << \"\\n\\t this:                           \" << this\n                            );\n\n                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n                const_image_view<in_image_type> original(original_);\n                image_view<out_image_type> down(down_);\n\n                if (original.nr() <= 8 || original.nc() <= 8)\n                {\n                    down.clear();\n                    return;\n                }\n\n                typedef typename pixel_traits<in_pixel_type>::basic_pixel_type bp_type;\n                typedef typename promote<bp_type>::type ptype;\n                array2d<ptype> temp_img;\n                temp_img.set_size(original.nr(), (original.nc()-3)/2);\n                down.set_size((original.nr()-3)/2, (original.nc()-3)/2);\n\n\n                // This function applies a 5x5 Gaussian filter to the image.  It\n                // does this by separating the filter into its horizontal and vertical\n                // components and then downsamples the image by dropping every other\n                // row and column.  Note that we can do these things all together in\n                // one step.\n\n                // apply row filter\n                for (long r = 0; r < temp_img.nr(); ++r)\n                {\n                    long oc = 0;\n                    for (long c = 0; c < temp_img.nc(); ++c)\n                    {\n                        ptype pix1;\n                        ptype pix2;\n                        ptype pix3;\n                        ptype pix4;\n                        ptype pix5;\n\n                        assign_pixel(pix1, original[r][oc]);\n                        assign_pixel(pix2, original[r][oc+1]);\n                        assign_pixel(pix3, original[r][oc+2]);\n                        assign_pixel(pix4, original[r][oc+3]);\n                        assign_pixel(pix5, original[r][oc+4]);\n\n                        pix2 *= 4;\n                        pix3 *= 6;\n                        pix4 *= 4;\n                        \n                        assign_pixel(temp_img[r][c], pix1 + pix2 + pix3 + pix4 + pix5);\n                        oc += 2;\n                    }\n                }\n\n\n                // apply column filter\n                long dr = 0;\n                for (long r = 2; r < temp_img.nr()-2; r += 2)\n                {\n                    for (long c = 0; c < temp_img.nc(); ++c)\n                    {\n                        ptype temp = temp_img[r-2][c] + \n                                    temp_img[r-1][c]*4 +  \n                                    temp_img[r  ][c]*6 +  \n                                    temp_img[r+1][c]*4 +  \n                                    temp_img[r+2][c];  \n\n                        assign_pixel(down[dr][c],temp/256);\n                    }\n                    ++dr;\n                }\n\n            }\n\n        private:\n            struct rgbptype \n            {\n                uint16 red;\n                uint16 green;\n                uint16 blue;\n            };\n        public:\n        // ------------------------------------------\n        //       OVERLOAD FOR RGB TO RGB IMAGES\n        // ------------------------------------------\n            template <\n                typename in_image_type,\n                typename out_image_type\n                >\n            typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (\n                const in_image_type& original_,\n                out_image_type& down_\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT( is_same_object(original_, down_) == false, \n                            \"\\t void pyramid_down_2_1::operator()\"\n                            << \"\\n\\t is_same_object(original_, down_): \" << is_same_object(original_, down_) \n                            << \"\\n\\t this:                           \" << this\n                            );\n\n                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n                const_image_view<in_image_type> original(original_);\n                image_view<out_image_type> down(down_);\n\n                if (original.nr() <= 8 || original.nc() <= 8)\n                {\n                    down.clear();\n                    return;\n                }\n\n                array2d<rgbptype> temp_img;\n                temp_img.set_size(original.nr(), (original.nc()-3)/2);\n                down.set_size((original.nr()-3)/2, (original.nc()-3)/2);\n\n\n                // This function applies a 5x5 Gaussian filter to the image.  It\n                // does this by separating the filter into its horizontal and vertical\n                // components and then downsamples the image by dropping every other\n                // row and column.  Note that we can do these things all together in\n                // one step.\n\n                // apply row filter\n                for (long r = 0; r < temp_img.nr(); ++r)\n                {\n                    long oc = 0;\n                    for (long c = 0; c < temp_img.nc(); ++c)\n                    {\n                        rgbptype pix1;\n                        rgbptype pix2;\n                        rgbptype pix3;\n                        rgbptype pix4;\n                        rgbptype pix5;\n\n                        pix1.red = original[r][oc].red;\n                        pix2.red = original[r][oc+1].red;\n                        pix3.red = original[r][oc+2].red;\n                        pix4.red = original[r][oc+3].red;\n                        pix5.red = original[r][oc+4].red;\n                        pix1.green = original[r][oc].green;\n                        pix2.green = original[r][oc+1].green;\n                        pix3.green = original[r][oc+2].green;\n                        pix4.green = original[r][oc+3].green;\n                        pix5.green = original[r][oc+4].green;\n                        pix1.blue = original[r][oc].blue;\n                        pix2.blue = original[r][oc+1].blue;\n                        pix3.blue = original[r][oc+2].blue;\n                        pix4.blue = original[r][oc+3].blue;\n                        pix5.blue = original[r][oc+4].blue;\n\n                        pix2.red *= 4;\n                        pix3.red *= 6;\n                        pix4.red *= 4;\n\n                        pix2.green *= 4;\n                        pix3.green *= 6;\n                        pix4.green *= 4;\n\n                        pix2.blue *= 4;\n                        pix3.blue *= 6;\n                        pix4.blue *= 4;\n                        \n                        rgbptype temp;\n                        temp.red = pix1.red + pix2.red + pix3.red + pix4.red + pix5.red;\n                        temp.green = pix1.green + pix2.green + pix3.green + pix4.green + pix5.green;\n                        temp.blue = pix1.blue + pix2.blue + pix3.blue + pix4.blue + pix5.blue;\n\n                        temp_img[r][c] = temp;\n\n                        oc += 2;\n                    }\n                }\n\n\n                // apply column filter\n                long dr = 0;\n                for (long r = 2; r < temp_img.nr()-2; r += 2)\n                {\n                    for (long c = 0; c < temp_img.nc(); ++c)\n                    {\n                        rgbptype temp;\n                        temp.red = temp_img[r-2][c].red + \n                                temp_img[r-1][c].red*4 +  \n                                temp_img[r  ][c].red*6 +  \n                                temp_img[r+1][c].red*4 +  \n                                temp_img[r+2][c].red;  \n                        temp.green = temp_img[r-2][c].green + \n                                    temp_img[r-1][c].green*4 +  \n                                    temp_img[r  ][c].green*6 +  \n                                    temp_img[r+1][c].green*4 +  \n                                    temp_img[r+2][c].green;  \n                        temp.blue = temp_img[r-2][c].blue + \n                                    temp_img[r-1][c].blue*4 +  \n                                    temp_img[r  ][c].blue*6 +  \n                                    temp_img[r+1][c].blue*4 +  \n                                    temp_img[r+2][c].blue;  \n\n                        down[dr][c].red = temp.red/256;\n                        down[dr][c].green = temp.green/256;\n                        down[dr][c].blue = temp.blue/256;\n                    }\n                    ++dr;\n                }\n\n            }\n\n            template <\n                typename image_type\n                >\n            void operator() (\n                image_type& img\n            ) const\n            {\n                image_type temp;\n                (*this)(img, temp);\n                swap(temp, img);\n            }\n\n        private:\n\n\n        };\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        class pyramid_down_3_2 : noncopyable\n        {\n        public:\n\n            template <typename T>\n            vector<double,2> point_down (\n                const vector<T,2>& p\n            ) const\n            {\n                const double ratio = 2.0/3.0;\n                return p*ratio - vector<double,2>(1,1);\n            }\n\n            template <typename T>\n            vector<double,2> point_up (\n                const vector<T,2>& p\n            ) const\n            {\n                const double ratio = 3.0/2.0;\n                return p*ratio + vector<T,2>(ratio,ratio);\n            }\n\n        // -----------------------------\n\n            template <typename T>\n            vector<double,2> point_down (\n                const vector<T,2>& p,\n                unsigned int levels\n            ) const\n            {\n                vector<double,2> temp = p;\n                for (unsigned int i = 0; i < levels; ++i)\n                    temp = point_down(temp);\n                return temp;\n            }\n\n            template <typename T>\n            vector<double,2> point_up (\n                const vector<T,2>& p,\n                unsigned int levels\n            ) const\n            {\n                vector<double,2> temp = p;\n                for (unsigned int i = 0; i < levels; ++i)\n                    temp = point_up(temp);\n                return temp;\n            }\n\n        // -----------------------------\n\n            drectangle rect_up (\n                const drectangle& rect\n            ) const\n            {\n                return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));\n            }\n\n            drectangle rect_up (\n                const drectangle& rect,\n                unsigned int levels\n            ) const\n            {\n                return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));\n            }\n\n        // -----------------------------\n\n            drectangle rect_down (\n                const drectangle& rect\n            ) const\n            {\n                return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));\n            }\n\n            drectangle rect_down (\n                const drectangle& rect,\n                unsigned int levels\n            ) const\n            {\n                return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));\n            }\n\n        // -----------------------------\n\n        private:\n            template <typename T, typename U>\n            struct both_images_rgb\n            {\n                typedef typename image_traits<T>::pixel_type T_pix;\n                typedef typename image_traits<U>::pixel_type U_pix;\n                const static bool value = pixel_traits<T_pix>::rgb && pixel_traits<U_pix>::rgb;\n            };\n        public:\n\n            template <\n                typename in_image_type,\n                typename out_image_type\n                >\n            typename disable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (\n                const in_image_type& original_,\n                out_image_type& down_\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT(is_same_object(original_, down_) == false, \n                            \"\\t void pyramid_down_3_2::operator()\"\n                            << \"\\n\\t is_same_object(original_, down_): \" << is_same_object(original_, down_) \n                            << \"\\n\\t this:                           \" << this\n                            );\n\n                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n                const_image_view<in_image_type> original(original_);\n                image_view<out_image_type> down(down_);\n\n                if (original.nr() <= 8 || original.nc() <= 8)\n                {\n                    down.clear();\n                    return;\n                }\n\n                const long size_in = 3;\n                const long size_out = 2;\n\n                typedef typename pixel_traits<in_pixel_type>::basic_pixel_type bp_type;\n                typedef typename promote<bp_type>::type ptype;\n                const long full_nr =  size_out*((original.nr()-2)/size_in);\n                const long part_nr = (size_out*(original.nr()-2))/size_in;\n                const long full_nc =  size_out*((original.nc()-2)/size_in);\n                const long part_nc = (size_out*(original.nc()-2))/size_in;\n                down.set_size(part_nr, part_nc);\n\n\n                long rr = 1;\n                long r;\n                for (r = 0; r < full_nr; r+=size_out)\n                {\n                    long cc = 1;\n                    long c;\n                    for (c = 0; c < full_nc; c+=size_out)\n                    {\n                        ptype block[size_in][size_in];\n                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate block \n                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));\n                        assign_pixel(down[r][c+1]   , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256));\n                        assign_pixel(down[r+1][c]   , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256));\n                        assign_pixel(down[r+1][c+1] , (block[2][2]*9 + block[1][2]*3 + block[2][1]*3 + block[1][1])/(16*256));\n\n                        cc += size_in;\n                    }\n                    if (part_nc - full_nc == 1)\n                    {\n                        ptype block[size_in][2];\n                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));\n                        assign_pixel(down[r+1][c]   , (block[2][0]*9 + block[1][0]*3 + block[2][1]*3 + block[1][1])/(16*256));\n                    }\n                    rr += size_in;\n                }\n                if (part_nr - full_nr == 1)\n                {\n                    long cc = 1;\n                    long c;\n                    for (c = 0; c < full_nc; c+=size_out)\n                    {\n                        ptype block[2][size_in];\n                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));\n                        assign_pixel(down[r][c+1]   , (block[0][2]*9 + block[1][2]*3 + block[0][1]*3 + block[1][1])/(16*256));\n\n                        cc += size_in;\n                    }\n                    if (part_nc - full_nc == 1)\n                    {\n                        ptype block[2][2];\n                        separable_3x3_filter_block_grayscale(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        assign_pixel(down[r][c]     , (block[0][0]*9 + block[1][0]*3 + block[0][1]*3 + block[1][1])/(16*256));\n                    }\n                }\n\n            }\n\n        private:\n            struct rgbptype \n            {\n                uint32 red;\n                uint32 green;\n                uint32 blue;\n            };\n\n        public:\n        // ------------------------------------------\n        //       OVERLOAD FOR RGB TO RGB IMAGES\n        // ------------------------------------------\n            template <\n                typename in_image_type,\n                typename out_image_type\n                >\n            typename enable_if<both_images_rgb<in_image_type,out_image_type> >::type operator() (\n                const in_image_type& original_,\n                out_image_type& down_\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT( is_same_object(original_, down_) == false, \n                            \"\\t void pyramid_down_3_2::operator()\"\n                            << \"\\n\\t is_same_object(original_, down_): \" << is_same_object(original_, down_) \n                            << \"\\n\\t this:                           \" << this\n                            );\n\n                typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n                typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n                COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n                COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n                const_image_view<in_image_type> original(original_);\n                image_view<out_image_type> down(down_);\n\n                if (original.nr() <= 8 || original.nc() <= 8)\n                {\n                    down.clear();\n                    return;\n                }\n\n                const long size_in = 3;\n                const long size_out = 2;\n\n                const long full_nr =  size_out*((original.nr()-2)/size_in);\n                const long part_nr = (size_out*(original.nr()-2))/size_in;\n                const long full_nc =  size_out*((original.nc()-2)/size_in);\n                const long part_nc = (size_out*(original.nc()-2))/size_in;\n                down.set_size(part_nr, part_nc);\n\n\n                long rr = 1;\n                long r;\n                for (r = 0; r < full_nr; r+=size_out)\n                {\n                    long cc = 1;\n                    long c;\n                    for (c = 0; c < full_nc; c+=size_out)\n                    {\n                        rgbptype block[size_in][size_in];\n                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate block \n                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        down[r][c+1].red     = (block[0][2].red*9   + block[1][2].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c+1].green   = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c+1].blue    = (block[0][2].blue*9  + block[1][2].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        down[r+1][c].red     = (block[2][0].red*9   + block[1][0].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);\n                        down[r+1][c].green   = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);\n                        down[r+1][c].blue    = (block[2][0].blue*9  + block[1][0].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        down[r+1][c+1].red   = (block[2][2].red*9   + block[1][2].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);\n                        down[r+1][c+1].green = (block[2][2].green*9 + block[1][2].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);\n                        down[r+1][c+1].blue  = (block[2][2].blue*9  + block[1][2].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        cc += size_in;\n                    }\n                    if (part_nc - full_nc == 1)\n                    {\n                        rgbptype block[size_in][2];\n                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        down[r+1][c].red     = (block[2][0].red*9   + block[1][0].red*3   + block[2][1].red*3   + block[1][1].red)/(16*256);\n                        down[r+1][c].green   = (block[2][0].green*9 + block[1][0].green*3 + block[2][1].green*3 + block[1][1].green)/(16*256);\n                        down[r+1][c].blue    = (block[2][0].blue*9  + block[1][0].blue*3  + block[2][1].blue*3  + block[1][1].blue)/(16*256);\n                    }\n                    rr += size_in;\n                }\n                if (part_nr - full_nr == 1)\n                {\n                    long cc = 1;\n                    long c;\n                    for (c = 0; c < full_nc; c+=size_out)\n                    {\n                        rgbptype block[2][size_in];\n                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        down[r][c+1].red     = (block[0][2].red*9   + block[1][2].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c+1].green   = (block[0][2].green*9 + block[1][2].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c+1].blue    = (block[0][2].blue*9  + block[1][2].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n\n                        cc += size_in;\n                    }\n                    if (part_nc - full_nc == 1)\n                    {\n                        rgbptype block[2][2];\n                        separable_3x3_filter_block_rgb(block, original_, rr, cc, 2, 12, 2);\n\n                        // bi-linearly interpolate partial block \n                        down[r][c].red       = (block[0][0].red*9   + block[1][0].red*3   + block[0][1].red*3   + block[1][1].red)/(16*256);\n                        down[r][c].green     = (block[0][0].green*9 + block[1][0].green*3 + block[0][1].green*3 + block[1][1].green)/(16*256);\n                        down[r][c].blue      = (block[0][0].blue*9  + block[1][0].blue*3  + block[0][1].blue*3  + block[1][1].blue)/(16*256);\n                    }\n                }\n            }\n\n            template <\n                typename image_type\n                >\n            void operator() (\n                image_type& img\n            ) const\n            {\n                image_type temp;\n                (*this)(img, temp);\n                swap(temp, img);\n            }\n        private:\n\n\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned int N\n        >\n    class pyramid_down : noncopyable\n    {\n    public:\n\n        COMPILE_TIME_ASSERT(N > 0);\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& p\n        ) const\n        {\n            const double ratio = (N-1.0)/N;\n            return (p - 0.3)*ratio;\n        }\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& p\n        ) const\n        {\n            const double ratio = N/(N-1.0);\n            return p*ratio + 0.3;\n        }\n\n    // -----------------------------\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const\n        {\n            vector<double,2> temp = p;\n            for (unsigned int i = 0; i < levels; ++i)\n                temp = point_down(temp);\n            return temp;\n        }\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const\n        {\n            vector<double,2> temp = p;\n            for (unsigned int i = 0; i < levels; ++i)\n                temp = point_up(temp);\n            return temp;\n        }\n\n    // -----------------------------\n\n        drectangle rect_up (\n            const drectangle& rect\n        ) const\n        {\n            return drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));\n        }\n\n        drectangle rect_up (\n            const drectangle& rect,\n            unsigned int levels\n        ) const\n        {\n            return drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));\n        }\n\n    // -----------------------------\n\n        drectangle rect_down (\n            const drectangle& rect\n        ) const\n        {\n            return drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));\n        }\n\n        drectangle rect_down (\n            const drectangle& rect,\n            unsigned int levels\n        ) const\n        {\n            return drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));\n        }\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& original,\n            out_image_type& down\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_same_object(original, down) == false, \n                        \"\\t void pyramid_down::operator()\"\n                        << \"\\n\\t is_same_object(original, down): \" << is_same_object(original, down) \n                        << \"\\n\\t this:                           \" << this\n                        );\n\n            typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n            typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n            COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n            COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n\n            set_image_size(down, std::lround(((N-1)*num_rows(original))/N), std::lround(((N-1)*num_columns(original))/N));\n            resize_image(original, down);\n        }\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            image_type& img\n        ) const\n        {\n            image_type temp;\n            (*this)(img, temp);\n            swap(temp, img);\n        }\n    };\n\n    template <>\n    class pyramid_down<1> : public pyramid_disable {};\n\n    template <>\n    class pyramid_down<2> : public dlib::impl::pyramid_down_2_1 {};\n\n    template <>\n    class pyramid_down<3> : public dlib::impl::pyramid_down_3_2 {};\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <unsigned int N>\n    double pyramid_rate(const pyramid_down<N>&)\n    {\n        return (N-1.0)/N;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <unsigned int N>\n    void find_pyramid_down_output_image_size(\n        const pyramid_down<N>& pyr,\n        long& nr,\n        long& nc\n    )\n    {\n        const double rate = pyramid_rate(pyr);\n        nr = std::floor(rate*nr);\n        nc = std::floor(rate*nc);\n    }\n\n    inline void find_pyramid_down_output_image_size(\n        const pyramid_down<3>& /*pyr*/,\n        long& nr,\n        long& nc\n    )\n    {\n        nr = 2*(nr-2)/3;\n        nc = 2*(nc-2)/3;\n    }\n\n    inline void find_pyramid_down_output_image_size(\n        const pyramid_down<2>& /*pyr*/,\n        long& nr,\n        long& nc\n    )\n    {\n        nr = (nr-3)/2;\n        nc = (nc-3)/2;\n    }\n\n    inline void find_pyramid_down_output_image_size(\n        const pyramid_down<1>& /*pyr*/,\n        long& nr,\n        long& nc\n    )\n    {\n        nr = 0;\n        nc = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    namespace impl\n    {\n        template <typename pyramid_type>\n        void compute_tiled_image_pyramid_details (\n            const pyramid_type& pyr,\n            long nr,\n            long nc,\n            const unsigned long padding,\n            const unsigned long outer_padding,\n            std::vector<rectangle>& rects,\n            long& pyramid_image_nr,\n            long& pyramid_image_nc\n        )\n        {\n            rects.clear();\n            if (nr*nc == 0)\n            {\n                pyramid_image_nr = 0;\n                pyramid_image_nc = 0;\n                return;\n            }\n\n            const long min_height = 5;\n            rects.reserve(100);\n            rects.push_back(rectangle(nc,nr));\n            // build the whole pyramid\n            while(true)\n            {\n                find_pyramid_down_output_image_size(pyr, nr, nc);\n                if (nr*nc == 0 || nr < min_height)\n                    break;\n                rects.push_back(rectangle(nc,nr));\n            }\n\n            // figure out output image size\n            long total_height = 0;\n            for (auto&& i : rects)\n                total_height += i.height()+padding;\n            total_height -= padding*2; // don't add unnecessary padding to the very right side.\n            long height = 0;\n            long prev_width = 0;\n            for (auto&& i : rects)\n            {\n                // Figure out how far we go on the first column.  We go until the next image can\n                // fit next to the previous one, which means we can double back for the second\n                // column of images.\n                if (i.width() <= rects[0].width()-prev_width-(long)padding && \n                    (height-rects[0].height())*2 >= (total_height-rects[0].height()))\n                {\n                    break;\n                }\n                height += i.height() + padding;\n                prev_width = i.width();\n            }\n            height -= padding; // don't add unnecessary padding to the very right side.\n\n            const long width = rects[0].width();\n            pyramid_image_nr = height+outer_padding*2;\n            pyramid_image_nc = width+outer_padding*2;\n\n\n            long y = outer_padding;\n            size_t i = 0;\n            while(y < height+(long)outer_padding && i < rects.size())\n            {\n                rects[i] = translate_rect(rects[i],point(outer_padding,y));\n                DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rects[i]));\n                y += rects[i].height()+padding;\n                ++i;\n            }\n            y -= padding;\n            while (i < rects.size())\n            {\n                point p1(outer_padding+width-1,y-1);\n                point p2 = p1 - rects[i].br_corner();\n                rectangle rect(p1,p2);\n                DLIB_ASSERT(rectangle(pyramid_image_nc,pyramid_image_nr).contains(rect));\n                // don't keep going on the last row if it would intersect the original image.\n                if (!rects[0].intersect(rect).is_empty())\n                    break;\n\n                rects[i] = rect;\n                y -= rects[i].height()+padding;\n                ++i;\n            }\n\n            // Delete any extraneous rectangles if we broke out of the above loop early due to\n            // intersection with the original image.\n            rects.resize(i);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_type1,\n        typename image_type2\n        >\n    void create_tiled_pyramid (\n        const image_type1& img,\n        image_type2& out_img,\n        std::vector<rectangle>& rects,\n        const unsigned long padding = 10,\n        const unsigned long outer_padding = 0\n    )\n    {\n        DLIB_ASSERT(!is_same_object(img, out_img));\n\n        long out_nr, out_nc;\n        pyramid_type pyr;\n        impl::compute_tiled_image_pyramid_details(pyr, img.nr(), img.nc(), padding, outer_padding, rects, out_nr, out_nc);\n\n        set_image_size(out_img, out_nr, out_nc);\n        assign_all_pixels(out_img, 0);\n\n        if (rects.size() == 0)\n            return;\n\n        // now build the image pyramid into out_img\n        auto si = sub_image(out_img, rects[0]);\n        assign_image(si, img);\n        for (size_t i = 1; i < rects.size(); ++i)\n        {\n            auto s1 = sub_image(out_img, rects[i-1]);\n            auto s2 = sub_image(out_img, rects[i]);\n            pyr(s1,s2);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    dpoint image_to_tiled_pyramid (\n        const std::vector<rectangle>& rects,\n        double scale,\n        dpoint p\n    )\n    {\n        DLIB_CASSERT(rects.size() > 0);\n        DLIB_CASSERT(0 < scale && scale <= 1);\n        pyramid_type pyr;\n        // This scale factor maps this many levels down the pyramid\n        long pyramid_down_iter = std::lround(std::log(scale)/std::log(pyramid_rate(pyr)));\n        pyramid_down_iter = put_in_range(0, (long)rects.size()-1, pyramid_down_iter);\n\n        return rects[pyramid_down_iter].tl_corner() + pyr.point_down(p, pyramid_down_iter);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    drectangle image_to_tiled_pyramid (\n        const std::vector<rectangle>& rects,\n        double scale,\n        drectangle r\n    )\n    {\n        DLIB_ASSERT(rects.size() > 0);\n        DLIB_ASSERT(0 < scale && scale <= 1);\n        return drectangle(image_to_tiled_pyramid<pyramid_type>(rects, scale, r.tl_corner()),\n                          image_to_tiled_pyramid<pyramid_type>(rects, scale, r.br_corner()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    dpoint tiled_pyramid_to_image (\n        const std::vector<rectangle>& rects,\n        dpoint p\n    )\n    {\n        DLIB_CASSERT(rects.size() > 0);\n\n        size_t pyramid_down_iter = nearest_rect(rects, p);\n\n        p -= rects[pyramid_down_iter].tl_corner();\n        pyramid_type pyr;\n        return pyr.point_up(p, pyramid_down_iter);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    drectangle tiled_pyramid_to_image (\n        const std::vector<rectangle>& rects,\n        drectangle r \n    )\n    {\n        DLIB_CASSERT(rects.size() > 0);\n\n        size_t pyramid_down_iter = nearest_rect(rects, dcenter(r));\n\n        dpoint origin = rects[pyramid_down_iter].tl_corner();\n        r = drectangle(r.tl_corner()-origin, r.br_corner()-origin);\n        pyramid_type pyr;\n        return pyr.rect_up(r, pyramid_down_iter);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_PYRaMID_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/image_pyramid_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_\n#ifdef DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_\n\n#include \"../pixel.h\"\n#include \"../array2d.h\"\n#include \"../geometry.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    template <\n        unsigned int N\n        >\n    class pyramid_down : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON N\n                N > 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple functor to help create image pyramids.  In particular, it\n                downsamples images at a ratio of N to N-1.\n\n                Note that setting N to 1 means that this object functions like\n                pyramid_disable (defined at the bottom of this file).  \n\n                WARNING, when mapping rectangles from one layer of a pyramid\n                to another you might end up with rectangles which extend slightly \n                outside your images.  This is because points on the border of an \n                image at a higher pyramid layer might correspond to points outside \n                images at lower layers.  So just keep this in mind.  Note also\n                that it's easy to deal with.  Just say something like this:\n                    rect = rect.intersect(get_rect(my_image)); // keep rect inside my_image \n        !*/\n    public:\n\n        template <\n            typename in_image_type,\n            typename out_image_type\n            >\n        void operator() (\n            const in_image_type& original,\n            out_image_type& down\n        ) const;\n        /*!\n            requires\n                - is_same_object(original, down) == false\n                - in_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - out_image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - for both pixel types P in the input and output images, we require:\n                    - pixel_traits<P>::has_alpha == false\n            ensures\n                - #down will contain an image that is roughly (N-1)/N times the size of the\n                  original image.  \n                - If both input and output images contain RGB pixels then the downsampled image will\n                  be in color.  Otherwise, the downsampling will be performed in a grayscale mode.\n                - The location of a point P in original image will show up at point point_down(P)\n                  in the #down image.  \n                - Note that some points on the border of the original image might correspond to \n                  points outside the #down image.  \n        !*/\n\n        template <\n            typename image_type\n            >\n        void operator() (\n            image_type& img\n        ) const;\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            ensures\n                - This function downsamples the given image and stores the results in #img.\n                  In particular, it is equivalent to performing: \n                    (*this)(img, temp); \n                    swap(img, temp);\n        !*/\n\n    // -------------------------------\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& p\n        ) const;\n        /*!\n            ensures\n                - interprets p as a point in a parent image and returns the\n                  point in a downsampled image which corresponds to p.\n                - This function is the inverse of point_up().  I.e. for a point P:\n                  point_down(point_up(P)) == P\n        !*/\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& p\n        ) const;\n        /*!\n            ensures\n                - interprets p as a point in a downsampled image and returns the\n                  point in a parent image which corresponds to p.\n                - This function is the inverse of point_down().  I.e. for a point P:\n                  point_up(point_down(P)) == P\n        !*/\n\n        drectangle rect_down (\n            const drectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns drectangle(point_down(rect.tl_corner()), point_down(rect.br_corner()));\n                  (i.e. maps rect into a downsampled image)\n        !*/\n\n        drectangle rect_up (\n            const drectangle& rect\n        ) const;\n        /*!\n            ensures\n                - returns drectangle(point_up(rect.tl_corner()), point_up(rect.br_corner()));\n                  (i.e. maps rect into a parent image)\n        !*/\n\n    // -------------------------------\n\n        template <typename T>\n        vector<double,2> point_down (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const;\n        /*!\n            ensures\n                - applies point_down() to p levels times and returns the result.\n                  (i.e. point_down(p,2) == point_down(point_down(p)),\n                        point_down(p,1) == point_down(p),\n                        point_down(p,0) == p,  etc. )\n        !*/\n\n        template <typename T>\n        vector<double,2> point_up (\n            const vector<T,2>& p,\n            unsigned int levels\n        ) const;\n        /*!\n            ensures\n                - applies point_up() to p levels times and returns the result.\n                  (i.e. point_up(p,2) == point_up(point_up(p)),\n                        point_up(p,1) == point_up(p),\n                        point_up(p,0) == p,  etc. )\n        !*/\n\n        drectangle rect_down (\n            const drectangle& rect,\n            unsigned int levels\n        ) const;\n        /*!\n            ensures\n                - returns drectangle(point_down(rect.tl_corner(),levels), point_down(rect.br_corner(),levels));\n                  (i.e. Basically applies rect_down() to rect levels times and returns the result.)\n        !*/\n\n        drectangle rect_up (\n            const drectangle& rect,\n            unsigned int levels\n        ) const;\n        /*!\n            ensures\n                - returns drectangle(point_up(rect.tl_corner(),levels), point_up(rect.br_corner(),levels));\n                  (i.e. Basically applies rect_up() to rect levels times and returns the result.)\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class pyramid_disable : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object with an interface identical to pyramid_down (defined\n                at the top of this file) except that it downsamples images at a ratio of infinity\n                to 1.  That means it always outputs images of size 0 regardless of the size\n                of the inputs.  \n                \n                This is useful because it can be supplied to routines which take a pyramid_down \n                function object and it will essentially disable pyramid processing.  This way, \n                a pyramid oriented function can be turned into a regular routine which processes\n                just the original undownsampled image.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned int N\n        >\n    double pyramid_rate(\n        const pyramid_down<N>& pyr\n    );\n    /*!\n        ensures\n            - returns (N-1.0)/N\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned int N\n        >\n    void find_pyramid_down_output_image_size(\n        const pyramid_down<N>& pyr,\n        long& nr,\n        long& nc\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n        ensures\n            - If pyr() were called on an image with nr by nc rows and columns, what would\n              be the size of the output image?  This function finds the size of the output\n              image and stores it back into #nr and #nc.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_type1,\n        typename image_type2\n        >\n    void create_tiled_pyramid (\n        const image_type1& img,\n        image_type2& out_img,\n        std::vector<rectangle>& rects,\n        const unsigned long padding = 10,\n        const unsigned long outer_padding = 0\n    );\n    /*!\n        requires\n            - pyramid_type == one of the dlib::pyramid_down template instances defined above.\n            - is_same_object(img, out_img) == false\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - for both pixel types P in the input and output images, we require:\n                - pixel_traits<P>::has_alpha == false\n        ensures\n            - Creates an image pyramid from the input image img.  The pyramid is made using\n              pyramid_type.  The highest resolution image is img and then all further\n              pyramid levels are generated from pyramid_type's downsampling.  The entire\n              resulting pyramid is packed into a single image and stored in out_img.\n            - When packing pyramid levels into out_img, there will be padding pixels of\n              space between each sub-image.  There will also be outer_padding pixels of\n              padding around the edge of the image.  All padding pixels have a value of 0.\n            - The resulting pyramid will be composed of #rects.size() images packed into\n              out_img.  Moreover, #rects[i] is the location inside out_img of the i-th\n              pyramid level. \n            - #rects.size() > 0\n            - #rects[0] == get_rect(img).  I.e. the first rectangle is the highest\n              resolution pyramid layer.  Subsequent elements of #rects correspond to\n              smaller and smaller pyramid layers inside out_img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    dpoint image_to_tiled_pyramid (\n        const std::vector<rectangle>& rects,\n        double scale,\n        dpoint p\n    );\n    /*!\n        requires\n            - pyramid_type == one of the dlib::pyramid_down template instances defined above.\n            - 0 < scale <= 1\n            - rects.size() > 0\n        ensures\n            - The function create_tiled_pyramid() converts an image, img, to a \"tiled\n              pyramid\" called out_img.  It also outputs a vector of rectangles, rect, that\n              show where each pyramid layer appears in out_img.   Therefore,\n              image_to_tiled_pyramid() allows you to map from coordinates in img (i.e. p)\n              to coordinates in the tiled pyramid out_img, when given the rects metadata.  \n\n              So given a point p in img, you can ask, what coordinate in out_img\n              corresponds to img[p.y()][p.x()] when things are scale times smaller?  This\n              new coordinate is a location in out_img and is what is returned by this\n              function.\n            - A scale of 1 means we don't move anywhere in the pyramid scale space relative\n              to the input image while smaller values of scale mean we move down the\n              pyramid.\n            - Assumes pyramid_type is the pyramid class used to produce the tiled image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    drectangle image_to_tiled_pyramid (\n        const std::vector<rectangle>& rects,\n        double scale,\n        drectangle r\n    );\n    /*!\n        requires\n            - pyramid_type == one of the dlib::pyramid_down template instances defined above.\n            - 0 < scale <= 1\n            - rects.size() > 0\n        ensures\n            - This function maps from input image space to tiled pyramid coordinate space\n              just as the above image_to_tiled_pyramid() does, except it operates on\n              rectangle objects instead of points.\n            - Assumes pyramid_type is the pyramid class used to produce the tiled image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    dpoint tiled_pyramid_to_image (\n        const std::vector<rectangle>& rects,\n        dpoint p\n    );\n    /*!\n        requires\n            - pyramid_type == one of the dlib::pyramid_down template instances defined above.\n            - rects.size() > 0\n        ensures\n            - This function maps from a coordinate in a tiled pyramid to the corresponding\n              input image coordinate.  Therefore, it is essentially the inverse of\n              image_to_tiled_pyramid().\n            - It should be noted that this function isn't always an inverse of\n              image_to_tiled_pyramid().  This is because you can ask\n              image_to_tiled_pyramid() for the coordinates of points outside the input\n              image and they will be mapped to somewhere that doesn't have an inverse.  But\n              for points actually inside the image this function performs an approximate\n              inverse mapping.\n            - Assumes pyramid_type is the pyramid class used to produce the tiled image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type\n        >\n    drectangle tiled_pyramid_to_image (\n        const std::vector<rectangle>& rects,\n        drectangle r \n    );\n    /*!\n        requires\n            - pyramid_type == one of the dlib::pyramid_down template instances defined above.\n            - rects.size() > 0\n        ensures\n            - This function maps from a coordinate in a tiled pyramid to the corresponding\n              input image coordinate.  Therefore, it is essentially the inverse of\n              image_to_tiled_pyramid().\n            - It should be noted that this function isn't always an inverse of\n              image_to_tiled_pyramid().  This is because you can ask\n              image_to_tiled_pyramid() for the coordinates of points outside the input\n              image and they will be mapped to somewhere that doesn't have an inverse.  But\n              for points actually inside the image this function performs an approximate\n              inverse mapping.\n            - Assumes pyramid_type is the pyramid class used to produce the tiled image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IMAGE_PYRaMID_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/integral_image.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_INTEGRAL_IMAGE\n#define DLIB_INTEGRAL_IMAGE\n\n#include \"integral_image_abstract.h\"\n\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include \"../geometry.h\"\n#include \"../array2d.h\"\n#include \"../matrix.h\"\n#include \"../pixel.h\"\n#include \"../noncopyable.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class integral_image_generic : noncopyable\n    {\n    public:\n        typedef T value_type;\n\n        long nr() const { return int_img.nr(); }\n        long nc() const { return int_img.nc(); }\n\n        template <typename image_type>\n        void load (\n            const image_type& img_\n        )\n        {\n            const_image_view<image_type> img(img_);\n            T pixel;\n            int_img.set_size(img.nr(), img.nc());\n\n            // compute the first row of the integral image\n            T temp = 0;\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                assign_pixel(pixel, img[0][c]);\n                temp += pixel;\n                int_img[0][c] = temp;\n            }\n\n            // now compute the rest of the integral image\n            for (long r = 1; r < img.nr(); ++r)\n            {\n                temp = 0;\n                for (long c = 0; c < img.nc(); ++c)\n                {\n                    assign_pixel(pixel, img[r][c]);\n                    temp += pixel;\n                    int_img[r][c] = temp + int_img[r-1][c];\n                }\n            }\n\n        }\n\n        value_type get_sum_of_area (\n            const rectangle& rect\n        ) const\n        {\n            DLIB_ASSERT(get_rect(*this).contains(rect) == true && rect.is_empty() == false,\n                \"\\tvalue_type get_sum_of_area(rect)\"\n                << \"\\n\\tYou have given a rectangle that goes outside the image\"\n                << \"\\n\\tthis:            \" << this\n                << \"\\n\\trect.is_empty(): \" << rect.is_empty()\n                << \"\\n\\trect:            \" << rect \n                << \"\\n\\tget_rect(*this): \" << get_rect(*this) \n            );\n\n            T top_left = 0, top_right = 0, bottom_left = 0, bottom_right = 0;\n\n            bottom_right = int_img[rect.bottom()][rect.right()];\n            if (rect.left()-1 >= 0 && rect.top()-1 >= 0)\n            {\n                top_left = int_img[rect.top()-1][rect.left()-1];\n                bottom_left = int_img[rect.bottom()][rect.left()-1];\n                top_right = int_img[rect.top()-1][rect.right()];\n            }\n            else if (rect.left()-1 >= 0)\n            {\n                bottom_left = int_img[rect.bottom()][rect.left()-1];\n            }\n            else if (rect.top()-1 >= 0)\n            {\n                top_right = int_img[rect.top()-1][rect.right()];\n            }\n\n            return bottom_right - bottom_left - top_right + top_left;\n        }\n\n        void swap(integral_image_generic& item)\n        {\n            int_img.swap(item.int_img);\n        }\n\n    private:\n\n        array2d<T> int_img;\n    };\n\n\n    template <\n        typename T\n        >\n    void swap (\n        integral_image_generic<T>& a,\n        integral_image_generic<T>& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    typedef integral_image_generic<long> integral_image;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type>\n    typename integral_image_type::value_type haar_x (\n        const integral_image_type& img,\n        const point& p,\n        long width\n    )\n    {\n        DLIB_ASSERT(get_rect(img).contains(centered_rect(p,width,width)) == true,\n            \"\\tlong haar_x(img,p,width)\"\n            << \"\\n\\tYou have given a point and with that goes outside the image\"\n            << \"\\n\\tget_rect(img):  \" << get_rect(img) \n            << \"\\n\\tp:              \" << p \n            << \"\\n\\twidth:          \" << width \n        );\n\n        rectangle left_rect;\n        left_rect.set_left ( p.x() - width / 2 );\n        left_rect.set_top ( p.y() - width / 2 );\n        left_rect.set_right ( p.x()-1 );\n        left_rect.set_bottom ( left_rect.top() + width - 1 );\n\n        rectangle right_rect;\n        right_rect.set_left ( p.x() );\n        right_rect.set_top ( left_rect.top() );\n        right_rect.set_right ( left_rect.left() + width -1 );\n        right_rect.set_bottom ( left_rect.bottom() );\n\n        return img.get_sum_of_area(right_rect) - img.get_sum_of_area(left_rect);\n    }\n\n    //  ----------------------------------------------------------------------------\n\n    template <typename integral_image_type>\n    typename integral_image_type::value_type haar_y (\n        const integral_image_type& img,\n        const point& p,\n        long width\n    )\n    {\n        DLIB_ASSERT(get_rect(img).contains(centered_rect(p,width,width)) == true,\n            \"\\tlong haar_y(img,p,width)\"\n            << \"\\n\\tYou have given a point and with that goes outside the image\"\n            << \"\\n\\tget_rect(img):  \" << get_rect(img) \n            << \"\\n\\tp:              \" << p \n            << \"\\n\\twidth:          \" << width \n        );\n\n        rectangle top_rect;\n        top_rect.set_left ( p.x() - width / 2 );\n        top_rect.set_top ( p.y() - width / 2 );\n        top_rect.set_right ( top_rect.left() + width - 1 );\n        top_rect.set_bottom ( p.y()-1 );\n\n        rectangle bottom_rect;\n        bottom_rect.set_left ( top_rect.left() );\n        bottom_rect.set_top ( p.y() );\n        bottom_rect.set_right ( top_rect.right() );\n        bottom_rect.set_bottom ( top_rect.top() + width - 1 );\n\n        return img.get_sum_of_area(bottom_rect) - img.get_sum_of_area(top_rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_INTEGRAL_IMAGE\n\n"
  },
  {
    "path": "dlib/image_transforms/integral_image_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_INTEGRAL_IMAGe_ABSTRACT_\n#ifdef DLIB_INTEGRAL_IMAGe_ABSTRACT_\n\n#include \"../geometry/rectangle_abstract.h\"\n#include \"../array2d/array2d_kernel_abstract.h\"\n#include \"../pixel.h\"\n#include \"../noncopyable.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class integral_image_generic : noncopyable\n    {\n        /*!\n            REQUIREMENTS ON T\n                T should be a built in scalar type.  Moreover, it should\n                be capable of storing sums of whatever kind of pixel\n                you will be dealing with.\n\n            INITIAL VALUE\n                - nr() == 0\n                - nc() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is an alternate way of representing image data\n                that allows for very fast computations of sums of pixels in \n                rectangular regions.  To use this object you load it with a\n                normal image and then you can use the get_sum_of_area()\n                function to compute sums of pixels in a given area in\n                constant time.\n        !*/\n    public:\n        typedef T value_type;\n\n        const long nr(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this integral image object\n        !*/\n\n        const long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this integral image object\n        !*/\n\n        template <typename image_type>\n        void load (\n            const image_type& img\n        );\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - Let P denote the type of pixel in img, then we require:\n                    - pixel_traits<P>::has_alpha == false \n            ensures\n                - #nr() == img.nr()\n                - #nc() == img.nc()\n                - #*this will now contain an \"integral image\" representation of the\n                  given input image.  \n        !*/\n\n        value_type get_sum_of_area (\n            const rectangle& rect\n        ) const;\n        /*!\n            requires\n                - rect.is_empty() == false\n                - get_rect(*this).contains(rect) == true\n                  (i.e. rect must not be outside the integral image)\n            ensures\n                - Let O denote the image this integral image was generated from.\n                  Then this function returns sum(subm(mat(O),rect)).\n                  That is, this function returns the sum of the pixels in O that\n                  are contained within the given rectangle.\n        !*/\n\n        void swap(\n            integral_image_generic& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template < typename T >\n    void swap (\n        integral_image_generic<T>& a,\n        integral_image_generic<T>& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/ \n\n// ----------------------------------------------------------------------------------------\n\n    typedef integral_image_generic<long> integral_image;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type>\n    typename integral_image_type::value_type haar_x (\n        const integral_image_type& img,\n        const point& p,\n        long width\n    )\n    /*!\n        requires\n            - get_rect(img).contains(centered_rect(p,width,width)) == true\n            - integral_image_type == a type that implements the integral_image_generic \n              interface defined above\n        ensures\n            - returns the response of a Haar wavelet centered at the point p\n              with the given width.  The wavelet is oriented along the X axis\n              and has the following shape:\n                ----++++\n                ----++++\n                ----++++\n                ----++++\n              That is, the wavelet is square and computes the sum of pixels on the\n              right minus the sum of pixels on the left.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename integral_image_type>\n    typename integral_image_type::value_type haar_y (\n        const integral_image_type& img,\n        const point& p,\n        long width\n    )\n    /*!\n        requires\n            - get_rect(img).contains(centered_rect(p,width,width)) == true\n            - integral_image_type == a type that implements the integral_image_generic \n              interface defined above\n        ensures\n            - returns the response of a Haar wavelet centered at the point p\n              with the given width in the given image.  The wavelet is oriented \n              along the Y axis and has the following shape:\n                --------\n                --------\n                ++++++++\n                ++++++++\n              That is, the wavelet is square and computes the sum of pixels on the\n              bottom minus the sum of pixels on the top.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_INTEGRAL_IMAGe_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/image_transforms/interpolation.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_INTERPOlATIONh_\n#define DLIB_INTERPOlATIONh_ \n\n#include \"../threads.h\"\n#include <algorithm>\n\n#include \"interpolation_abstract.h\"\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n#include \"assign_image.h\"\n#include \"image_pyramid.h\"\n#include \"../simd.h\"\n#include \"../image_processing/full_object_detection.h\"\n#include <limits>\n#include <array>\n#include \"../rand.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct sub_image_proxy\n    {\n        sub_image_proxy() = default;\n\n        sub_image_proxy (\n            T& img,\n            rectangle rect\n        ) \n        {\n            rect = rect.intersect(get_rect(img));\n            typedef typename image_traits<T>::pixel_type pixel_type;\n\n            _nr = rect.height();\n            _nc = rect.width();\n            _width_step = width_step(img);\n            _data = (char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step;\n        }\n\n        void* _data = 0;\n        size_t _width_step = 0;\n        long _nr = 0;\n        long _nc = 0;\n    };\n\n    template <typename T>\n    struct const_sub_image_proxy\n    {\n        const_sub_image_proxy() = default;\n\n        const_sub_image_proxy (\n            const T& img,\n            rectangle rect\n        ) \n        {\n            rect = rect.intersect(get_rect(img));\n            typedef typename image_traits<T>::pixel_type pixel_type;\n\n            _nr = rect.height();\n            _nc = rect.width();\n            _width_step = width_step(img);\n            _data = (const char*)image_data(img) + sizeof(pixel_type)*rect.left() + rect.top()*_width_step;\n        }\n\n        const void* _data = 0;\n        size_t _width_step = 0;\n        long _nr = 0;\n        long _nc = 0;\n    };\n\n    template <typename T>\n    struct image_traits<sub_image_proxy<T> >\n    {\n        typedef typename image_traits<T>::pixel_type pixel_type;\n    };\n    template <typename T>\n    struct image_traits<const sub_image_proxy<T> >\n    {\n        typedef typename image_traits<T>::pixel_type pixel_type;\n    };\n    template <typename T>\n    struct image_traits<const_sub_image_proxy<T> >\n    {\n        typedef typename image_traits<T>::pixel_type pixel_type;\n    };\n    template <typename T>\n    struct image_traits<const const_sub_image_proxy<T> >\n    {\n        typedef typename image_traits<T>::pixel_type pixel_type;\n    };\n\n    template <typename T>\n    inline long num_rows( const sub_image_proxy<T>& img) { return img._nr; }\n    template <typename T>\n    inline long num_columns( const sub_image_proxy<T>& img) { return img._nc; }\n\n    template <typename T>\n    inline long num_rows( const const_sub_image_proxy<T>& img) { return img._nr; }\n    template <typename T>\n    inline long num_columns( const const_sub_image_proxy<T>& img) { return img._nc; }\n\n    template <typename T>\n    inline void* image_data( sub_image_proxy<T>& img) \n    { \n        return img._data; \n    } \n    template <typename T>\n    inline const void* image_data( const sub_image_proxy<T>& img) \n    {\n        return img._data; \n    }\n\n    template <typename T>\n    inline const void* image_data( const const_sub_image_proxy<T>& img) \n    {\n        return img._data; \n    }\n\n    template <typename T>\n    inline size_t width_step(\n        const sub_image_proxy<T>& img\n    ) { return img._width_step; }\n\n    template <typename T>\n    inline size_t width_step(\n        const const_sub_image_proxy<T>& img\n    ) { return img._width_step; }\n\n    template <typename T>\n    void set_image_size(sub_image_proxy<T>& img, long rows, long cols)\n    {\n        DLIB_CASSERT(img._nr == rows && img._nc == cols, \"A sub_image can't be resized.\"\n            << \"\\n\\t img._nr: \"<< img._nr\n            << \"\\n\\t img._nc: \"<< img._nc\n            << \"\\n\\t rows:    \"<< rows\n            << \"\\n\\t cols:    \"<< cols\n            );\n    }\n\n    template <\n        typename image_type\n        >\n    sub_image_proxy<image_type> sub_image (\n        image_type& img,\n        const rectangle& rect\n    )\n    {\n        return sub_image_proxy<image_type>(img,rect);\n    }\n\n    template <\n        typename image_type\n        >\n    const const_sub_image_proxy<image_type> sub_image (\n        const image_type& img,\n        const rectangle& rect\n    )\n    {\n        return const_sub_image_proxy<image_type>(img,rect);\n    }\n\n    template <typename T>\n    inline sub_image_proxy<matrix<T>> sub_image (\n        T* img,\n        long nr,\n        long nc,\n        long row_stride\n    )\n    {\n        sub_image_proxy<matrix<T>> tmp;\n        tmp._data = img;\n        tmp._nr = nr;\n        tmp._nc = nc;\n        tmp._width_step = row_stride*sizeof(T);\n        return tmp;\n    }\n\n    template <typename T>\n    inline const const_sub_image_proxy<matrix<T>> sub_image (\n        const T* img,\n        long nr,\n        long nc,\n        long row_stride\n    )\n    {\n        const_sub_image_proxy<matrix<T>> tmp;\n        tmp._data = img;\n        tmp._nr = nr;\n        tmp._nc = nc;\n        tmp._width_step = row_stride*sizeof(T);\n        return tmp;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_nearest_neighbor\n    {\n    public:\n\n        template <typename image_view_type, typename pixel_type>\n        bool operator() (\n            const image_view_type& img,\n            const dlib::point& p,\n            pixel_type& result\n        ) const\n        {\n            COMPILE_TIME_ASSERT(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false);\n\n            if (get_rect(img).contains(p))\n            {\n                assign_pixel(result, img[p.y()][p.x()]);\n                return true;\n            }\n            else\n            {\n                return false;\n            }\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_bilinear\n    {\n    public:\n        template <typename T, typename image_view_type, typename pixel_type>\n        bool operator() (\n            const image_view_type& img,\n            const dlib::vector<T,2>& p,\n            pixel_type& result\n        ) const\n        {\n            // Assign pixel gives special meaning to alpha channel that would break interpolation\n            static_assert(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false, \"Images with alpha channel not supported\");\n            // Interpolation currently supports only fully cartesian (non-polar) spaces.\n            static_assert(is_color_space_cartesian_image<image_view_type>::value == true, \"Non-cartesian color space used in interpolation\");\n\n\n            const long left   = static_cast<long>(std::floor(p.x()));\n            const long top    = static_cast<long>(std::floor(p.y()));\n            const long right  = left+1;\n            const long bottom = top+1;\n\n            // if the interpolation goes outside img \n            if (!(left >= 0 && top >= 0 && right < img.nc() && bottom < img.nr()))\n                return false;\n\n            const double lr_frac = p.x() - left;\n            const double tb_frac = p.y() - top;\n\n            const auto tl = pixel_to_vector<double>(img[top][left]);\n            const auto tr = pixel_to_vector<double>(img[top][right]);\n            const auto bl = pixel_to_vector<double>(img[bottom][left]);\n            const auto br = pixel_to_vector<double>(img[bottom][right]);\n            typename image_view_type::pixel_type temp;\n            vector_to_pixel(temp, (1 - tb_frac) * ((1 - lr_frac) * tl + lr_frac * tr) +\n                tb_frac * ((1 - lr_frac) * bl + lr_frac * br));\n            assign_pixel(result, temp);\n            return true;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_quadratic\n    {\n\n    public:\n\n        template <typename T, typename image_view_type, typename pixel_type>\n        bool operator() (\n            const image_view_type& img,\n            const dlib::vector<T,2>& p,\n            pixel_type& result\n        ) const\n        {\n            // Assign pixel gives special meaning to alpha channel that would break interpolation\n            static_assert(pixel_traits<typename image_view_type::pixel_type>::has_alpha == false, \"Images with alpha channel not supported\");\n            // Interpolation currently supports only fully cartesian (non-polar) spaces.\n            static_assert(is_color_space_cartesian_image<image_view_type>::value == true, \"Non-cartesian color space used in interpolation\");\n\n            using traits = pixel_traits<typename image_view_type::pixel_type>;\n\n            const point pp(p);\n\n            // if the interpolation goes outside img \n            if (!get_rect(img).contains(grow_rect(pp,1)))\n                return false;\n\n            const long r = pp.y();\n            const long c = pp.x();\n\n            matrix<double, traits::num, 1> pvout;\n            for (long i = 0; i < traits::num; ++i)\n                pvout(i) = interpolate(p-pp,\n                    pixel_to_vector<double>(img[r-1][c-1])(i),\n                    pixel_to_vector<double>(img[r-1][c  ])(i),\n                    pixel_to_vector<double>(img[r-1][c+1])(i),\n                    pixel_to_vector<double>(img[r  ][c-1])(i),\n                    pixel_to_vector<double>(img[r  ][c  ])(i),\n                    pixel_to_vector<double>(img[r  ][c+1])(i),\n                    pixel_to_vector<double>(img[r+1][c-1])(i),\n                    pixel_to_vector<double>(img[r+1][c  ])(i),\n                    pixel_to_vector<double>(img[r+1][c+1])(i));\n            typename image_view_type::pixel_type temp;\n            const auto min_val = pixel_traits<pixel_type_t<image_view_type>>::min();\n            const auto max_val = pixel_traits<pixel_type_t<image_view_type>>::max();\n            vector_to_pixel(temp, clamp(pvout, min_val, max_val));\n            assign_pixel(result, temp);\n            return true;\n        }\n\n    private:\n\n        /*  tl tm tr\n            ml mm mr\n            bl bm br\n        */\n        // The above is the pixel layout in our little 3x3 neighborhood.  interpolate() will \n        // fit a quadratic to these 9 pixels and then use that quadratic to find the interpolated \n        // value at point p.\n        inline double interpolate(\n            const dpoint& p,\n            double tl, double tm, double tr, \n            double ml, double mm, double mr, \n            double bl, double bm, double br\n        ) const\n        {\n            matrix<double,6,1> w;\n            // x\n            w(0) = (tr + mr + br - tl - ml - bl)*0.16666666666;\n            // y\n            w(1) = (bl + bm + br - tl - tm - tr)*0.16666666666;\n            // x^2\n            w(2) = (tl + tr + ml + mr + bl + br)*0.16666666666 - (tm + mm + bm)*0.333333333;\n            // x*y\n            w(3) = (tl - tr - bl + br)*0.25;\n            // y^2\n            w(4) = (tl + tm + tr + bl + bm + br)*0.16666666666 - (ml + mm + mr)*0.333333333;\n            // 1 (constant term)\n            w(5) = (tm + ml + mr + bm)*0.222222222 - (tl + tr + bl + br)*0.11111111 + (mm)*0.55555556;\n\n            const double x = p.x();\n            const double y = p.y();\n\n            matrix<double,6,1> z;\n            z = x, y, x*x, x*y, y*y, 1.0;\n                            \n            return dot(w,z);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class black_background\n    {\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& p) const { assign_pixel(p, 0); }\n    };\n\n    class white_background\n    {\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& p) const { assign_pixel(p, 255); }\n    };\n\n    class no_background\n    {\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& ) const { }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type,\n        typename background_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point,\n        const background_type& set_background,\n        const rectangle& area\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( get_rect(out_img).contains(area) == true &&\n                     is_same_object(in_img, out_img) == false ,\n            \"\\t void transform_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t get_rect(out_img).contains(area): \" << get_rect(out_img).contains(area)\n            << \"\\n\\t get_rect(out_img): \" << get_rect(out_img)\n            << \"\\n\\t area:              \" << area\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        const_image_view<image_type1> imgv(in_img);\n        image_view<image_type2> out_imgv(out_img);\n\n        for (long r = area.top(); r <= area.bottom(); ++r)\n        {\n            for (long c = area.left(); c <= area.right(); ++c)\n            {\n                if (!interp(imgv, map_point(dpoint(c,r)), out_imgv[r][c]))\n                    set_background(out_imgv[r][c]);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type,\n        typename background_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point,\n        const background_type& set_background\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void transform_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        transform_image(in_img, out_img, interp, map_point, set_background, get_rect(out_img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void transform_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n\n        transform_image(in_img, out_img, interp, map_point, black_background(), get_rect(out_img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    point_transform_affine rotate_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        double angle,\n        const interpolation_type& interp\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t point_transform_affine rotate_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        const rectangle rimg = get_rect(in_img);\n\n\n        // figure out bounding box for rotated rectangle\n        rectangle rect;\n        rect += rotate_point(center(rimg), rimg.tl_corner(), -angle);\n        rect += rotate_point(center(rimg), rimg.tr_corner(), -angle);\n        rect += rotate_point(center(rimg), rimg.bl_corner(), -angle);\n        rect += rotate_point(center(rimg), rimg.br_corner(), -angle);\n        set_image_size(out_img, rect.height(), rect.width());\n\n        const matrix<double,2,2> R = rotation_matrix(angle);\n\n        point_transform_affine trans = point_transform_affine(R, -R*dcenter(get_rect(out_img)) + dcenter(rimg));\n        transform_image(in_img, out_img, interp, trans);\n        return inv(trans);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine rotate_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        double angle\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t point_transform_affine rotate_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        return rotate_image(in_img, out_img, angle, interpolate_quadratic());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class helper_resize_image \n        {\n        public:\n            helper_resize_image(\n                double x_scale_,\n                double y_scale_\n            ):\n                x_scale(x_scale_),\n                y_scale(y_scale_)\n            {}\n\n            dpoint operator() (\n                const dpoint& p\n            ) const\n            {\n                return dpoint(p.x()*x_scale, p.y()*y_scale);\n            }\n\n        private:\n            const double x_scale;\n            const double y_scale;\n        };\n    }\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void resize_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        const double x_scale = (num_columns(in_img)-1)/(double)std::max<long>((num_columns(out_img)-1),1);\n        const double y_scale = (num_rows(in_img)-1)/(double)std::max<long>((num_rows(out_img)-1),1);\n        transform_image(in_img, out_img, interp, \n                        dlib::impl::helper_resize_image(x_scale,y_scale));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    // This is an optimized version of resize_image for the case where bilinear\n    // interpolation is used.\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    typename disable_if_c<(is_rgb_image<image_type1>::value&&is_rgb_image<image_type2>::value) || \n                          (is_grayscale_image<image_type1>::value&&is_grayscale_image<image_type2>::value)>::type \n    resize_image (\n        const image_type1& in_img_,\n        image_type2& out_img_,\n        interpolate_bilinear\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img_, out_img_):  \" << is_same_object(in_img_, out_img_)\n            );\n\n        const_image_view<image_type1> in_img(in_img_);\n        image_view<image_type2> out_img(out_img_);\n\n        if (out_img.size() == 0 || in_img.size() == 0)\n            return;\n\n\n        typedef typename image_traits<image_type1>::pixel_type T;\n        typedef typename image_traits<image_type2>::pixel_type U;\n        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);\n        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);\n        double y = -y_scale;\n        for (long r = 0; r < out_img.nr(); ++r)\n        {\n            y += y_scale;\n            const long top    = static_cast<long>(std::floor(y));\n            const long bottom = std::min(top+1, in_img.nr()-1);\n            const double tb_frac = y - top;\n            double x = -x_scale;\n            if (pixel_traits<U>::grayscale)\n            {\n                for (long c = 0; c < out_img.nc(); ++c)\n                {\n                    x += x_scale;\n                    const long left   = static_cast<long>(std::floor(x));\n                    const long right  = std::min(left+1, in_img.nc()-1);\n                    const double lr_frac = x - left;\n\n                    double tl = 0, tr = 0, bl = 0, br = 0;\n\n                    assign_pixel(tl, in_img[top][left]);\n                    assign_pixel(tr, in_img[top][right]);\n                    assign_pixel(bl, in_img[bottom][left]);\n                    assign_pixel(br, in_img[bottom][right]);\n\n                    double temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) + \n                        tb_frac*((1-lr_frac)*bl + lr_frac*br);\n\n                    assign_pixel(out_img[r][c], temp);\n                }\n            }\n            else\n            {\n                for (long c = 0; c < out_img.nc(); ++c)\n                {\n                    x += x_scale;\n                    const long left   = static_cast<long>(std::floor(x));\n                    const long right  = std::min(left+1, in_img.nc()-1);\n                    const double lr_frac = x - left;\n\n                    const T tl = in_img[top][left];\n                    const T tr = in_img[top][right];\n                    const T bl = in_img[bottom][left];\n                    const T br = in_img[bottom][right];\n\n                    T temp;\n                    assign_pixel(temp, 0);\n                    vector_to_pixel(temp, \n                        (1-tb_frac)*((1-lr_frac)*pixel_to_vector<double>(tl) + lr_frac*pixel_to_vector<double>(tr)) + \n                            tb_frac*((1-lr_frac)*pixel_to_vector<double>(bl) + lr_frac*pixel_to_vector<double>(br)));\n                    assign_pixel(out_img[r][c], temp);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    struct images_have_same_pixel_types\n    {\n        typedef typename image_traits<image_type1>::pixel_type ptype1;\n        typedef typename image_traits<image_type2>::pixel_type ptype2;\n        const static bool value = is_same_type<ptype1, ptype2>::value;\n    };\n\n    template <\n        typename image_type,\n        typename image_type2\n        >\n    typename enable_if_c<is_grayscale_image<image_type>::value && is_grayscale_image<image_type2>::value && images_have_same_pixel_types<image_type,image_type2>::value>::type \n    resize_image (\n        const image_type& in_img_,\n        image_type2& out_img_,\n        interpolate_bilinear\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img_, out_img_):  \" << is_same_object(in_img_, out_img_)\n            );\n\n        const_image_view<image_type> in_img(in_img_);\n        image_view<image_type2> out_img(out_img_);\n\n        if (out_img.size() == 0 || in_img.size() == 0)\n            return;\n\n        typedef typename image_traits<image_type>::pixel_type T;\n        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);\n        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);\n        double y = -y_scale;\n        for (long r = 0; r < out_img.nr(); ++r)\n        {\n            y += y_scale;\n            const long top    = static_cast<long>(std::floor(y));\n            const long bottom = std::min(top+1, in_img.nr()-1);\n            const double tb_frac = y - top;\n            double x = -4*x_scale;\n\n            const simd4f _tb_frac = tb_frac;\n            const simd4f _inv_tb_frac = 1-tb_frac;\n            const simd4f _x_scale = 4*x_scale;\n            simd4f _x(x, x+x_scale, x+2*x_scale, x+3*x_scale);\n            long c = 0;\n            for (;; c+=4)\n            {\n                _x += _x_scale;\n                simd4i left = simd4i(_x);\n\n                simd4f _lr_frac = _x-left;\n                simd4f _inv_lr_frac = 1-_lr_frac; \n                simd4i right = left+1;\n\n                simd4f tlf = _inv_tb_frac*_inv_lr_frac;\n                simd4f trf = _inv_tb_frac*_lr_frac;\n                simd4f blf = _tb_frac*_inv_lr_frac;\n                simd4f brf = _tb_frac*_lr_frac;\n\n                int32 fleft[4];\n                int32 fright[4];\n                left.store(fleft);\n                right.store(fright);\n\n                if (fright[3] >= in_img.nc())\n                    break;\n                simd4f tl(in_img[top][fleft[0]],     in_img[top][fleft[1]],     in_img[top][fleft[2]],     in_img[top][fleft[3]]);\n                simd4f tr(in_img[top][fright[0]],    in_img[top][fright[1]],    in_img[top][fright[2]],    in_img[top][fright[3]]);\n                simd4f bl(in_img[bottom][fleft[0]],  in_img[bottom][fleft[1]],  in_img[bottom][fleft[2]],  in_img[bottom][fleft[3]]);\n                simd4f br(in_img[bottom][fright[0]], in_img[bottom][fright[1]], in_img[bottom][fright[2]], in_img[bottom][fright[3]]);\n\n                simd4f out = simd4f(tlf*tl + trf*tr + blf*bl + brf*br);\n                float fout[4];\n                out.store(fout);\n\n                const auto convert_to_output_type = [](float value)\n                {\n                    if (std::is_integral<T>::value)\n                        return static_cast<T>(value + 0.5);\n                    else\n                        return static_cast<T>(value);\n                };\n\n                out_img[r][c]   = convert_to_output_type(fout[0]);\n                out_img[r][c+1] = convert_to_output_type(fout[1]);\n                out_img[r][c+2] = convert_to_output_type(fout[2]);\n                out_img[r][c+3] = convert_to_output_type(fout[3]);\n            }\n            x = -x_scale + c*x_scale;\n            for (; c < out_img.nc(); ++c)\n            {\n                x += x_scale;\n                const long left   = static_cast<long>(std::floor(x));\n                const long right  = std::min(left+1, in_img.nc()-1);\n                const float lr_frac = x - left;\n\n                float tl = 0, tr = 0, bl = 0, br = 0;\n\n                assign_pixel(tl, in_img[top][left]);\n                assign_pixel(tr, in_img[top][right]);\n                assign_pixel(bl, in_img[bottom][left]);\n                assign_pixel(br, in_img[bottom][right]);\n\n                float temp = (1-tb_frac)*((1-lr_frac)*tl + lr_frac*tr) + \n                    tb_frac*((1-lr_frac)*bl + lr_frac*br);\n\n                assign_pixel(out_img[r][c], temp);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    typename enable_if_c<is_rgb_image<image_type1>::value && is_rgb_image<image_type2>::value >::type resize_image (\n        const image_type1& in_img_,\n        image_type2& out_img_,\n        interpolate_bilinear\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img_, out_img_) == false ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img_, out_img_):  \" << is_same_object(in_img_, out_img_)\n            );\n\n        const_image_view<image_type1> in_img(in_img_);\n        image_view<image_type2> out_img(out_img_);\n\n        if (out_img.size() == 0 || in_img.size() == 0)\n            return;\n\n\n        typedef typename image_traits<image_type1>::pixel_type T;\n        const double x_scale = (in_img.nc()-1)/(double)std::max<long>((out_img.nc()-1),1);\n        const double y_scale = (in_img.nr()-1)/(double)std::max<long>((out_img.nr()-1),1);\n        double y = -y_scale;\n        for (long r = 0; r < out_img.nr(); ++r)\n        {\n            y += y_scale;\n            const long top    = static_cast<long>(std::floor(y));\n            const long bottom = std::min(top+1, in_img.nr()-1);\n            const double tb_frac = y - top;\n            double x = -4*x_scale;\n\n            const simd4f _tb_frac = tb_frac;\n            const simd4f _inv_tb_frac = 1-tb_frac;\n            const simd4f _x_scale = 4*x_scale;\n            simd4f _x(x, x+x_scale, x+2*x_scale, x+3*x_scale);\n            long c = 0;\n            for (;; c+=4)\n            {\n                _x += _x_scale;\n                simd4i left = simd4i(_x);\n                simd4f lr_frac = _x-left;\n                simd4f _inv_lr_frac = 1-lr_frac; \n                simd4i right = left+1;\n\n                simd4f tlf = _inv_tb_frac*_inv_lr_frac;\n                simd4f trf = _inv_tb_frac*lr_frac;\n                simd4f blf = _tb_frac*_inv_lr_frac;\n                simd4f brf = _tb_frac*lr_frac;\n\n                int32 fleft[4];\n                int32 fright[4];\n                left.store(fleft);\n                right.store(fright);\n\n                if (fright[3] >= in_img.nc())\n                    break;\n                simd4f tl(in_img[top][fleft[0]].red,     in_img[top][fleft[1]].red,     in_img[top][fleft[2]].red,     in_img[top][fleft[3]].red);\n                simd4f tr(in_img[top][fright[0]].red,    in_img[top][fright[1]].red,    in_img[top][fright[2]].red,    in_img[top][fright[3]].red);\n                simd4f bl(in_img[bottom][fleft[0]].red,  in_img[bottom][fleft[1]].red,  in_img[bottom][fleft[2]].red,  in_img[bottom][fleft[3]].red);\n                simd4f br(in_img[bottom][fright[0]].red, in_img[bottom][fright[1]].red, in_img[bottom][fright[2]].red, in_img[bottom][fright[3]].red);\n\n                simd4i out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);\n                int32 fout[4];\n                out.store(fout);\n\n                out_img[r][c].red   = static_cast<unsigned char>(fout[0]);\n                out_img[r][c+1].red = static_cast<unsigned char>(fout[1]);\n                out_img[r][c+2].red = static_cast<unsigned char>(fout[2]);\n                out_img[r][c+3].red = static_cast<unsigned char>(fout[3]);\n\n\n                tl = simd4f(in_img[top][fleft[0]].green,    in_img[top][fleft[1]].green,    in_img[top][fleft[2]].green,    in_img[top][fleft[3]].green);\n                tr = simd4f(in_img[top][fright[0]].green,   in_img[top][fright[1]].green,   in_img[top][fright[2]].green,   in_img[top][fright[3]].green);\n                bl = simd4f(in_img[bottom][fleft[0]].green, in_img[bottom][fleft[1]].green, in_img[bottom][fleft[2]].green, in_img[bottom][fleft[3]].green);\n                br = simd4f(in_img[bottom][fright[0]].green, in_img[bottom][fright[1]].green, in_img[bottom][fright[2]].green, in_img[bottom][fright[3]].green);\n                out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);\n                out.store(fout);\n                out_img[r][c].green   = static_cast<unsigned char>(fout[0]);\n                out_img[r][c+1].green = static_cast<unsigned char>(fout[1]);\n                out_img[r][c+2].green = static_cast<unsigned char>(fout[2]);\n                out_img[r][c+3].green = static_cast<unsigned char>(fout[3]);\n\n\n                tl = simd4f(in_img[top][fleft[0]].blue,     in_img[top][fleft[1]].blue,     in_img[top][fleft[2]].blue,     in_img[top][fleft[3]].blue);\n                tr = simd4f(in_img[top][fright[0]].blue,    in_img[top][fright[1]].blue,    in_img[top][fright[2]].blue,    in_img[top][fright[3]].blue);\n                bl = simd4f(in_img[bottom][fleft[0]].blue,  in_img[bottom][fleft[1]].blue,  in_img[bottom][fleft[2]].blue,  in_img[bottom][fleft[3]].blue);\n                br = simd4f(in_img[bottom][fright[0]].blue, in_img[bottom][fright[1]].blue, in_img[bottom][fright[2]].blue, in_img[bottom][fright[3]].blue);\n                out = simd4i(tlf*tl + trf*tr + blf*bl + brf*br);\n                out.store(fout);\n                out_img[r][c].blue   = static_cast<unsigned char>(fout[0]);\n                out_img[r][c+1].blue = static_cast<unsigned char>(fout[1]);\n                out_img[r][c+2].blue = static_cast<unsigned char>(fout[2]);\n                out_img[r][c+3].blue = static_cast<unsigned char>(fout[3]);\n            }\n            x = -x_scale + c*x_scale;\n            for (; c < out_img.nc(); ++c)\n            {\n                x += x_scale;\n                const long left   = static_cast<long>(std::floor(x));\n                const long right  = std::min(left+1, in_img.nc()-1);\n                const double lr_frac = x - left;\n\n                const T tl = in_img[top][left];\n                const T tr = in_img[top][right];\n                const T bl = in_img[bottom][left];\n                const T br = in_img[bottom][right];\n\n                T temp;\n                assign_pixel(temp, 0);\n                vector_to_pixel(temp, \n                    (1-tb_frac)*((1-lr_frac)*pixel_to_vector<double>(tl) + lr_frac*pixel_to_vector<double>(tr)) + \n                    tb_frac*((1-lr_frac)*pixel_to_vector<double>(bl) + lr_frac*pixel_to_vector<double>(br)));\n                assign_pixel(out_img[r][c], temp);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void resize_image (\n        const image_type1& in_img,\n        image_type2& out_img\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        resize_image(in_img, out_img, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void resize_image (\n        double size_scale,\n        image_type& img \n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( size_scale > 0 ,\n            \"\\t void resize_image()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t size_scale:  \" << size_scale\n            );\n        if (size_scale == 1.0) return; // no need to do anything at all\n        image_type temp;\n        set_image_size(temp, std::round(size_scale*num_rows(img)), std::round(size_scale*num_columns(img)));\n        resize_image(img, temp);\n        swap(img, temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    point_transform_affine letterbox_image (\n        const image_type1& img_in,\n        image_type2& img_out,\n        const interpolation_type& interp\n    )\n    {\n        const_image_view<image_type1> vimg_in(img_in);\n        image_view<image_type2> vimg_out(img_out);\n        const long rows = vimg_out.nr();\n        const long cols = vimg_out.nc();\n        DLIB_CASSERT(vimg_out.size() > 0, \"img_out size must be bigger than zero, but was \" << rows << \"x\" << cols);\n\n        // early return if the image has already the requested size and no padding is needed\n        if (have_same_dimensions(vimg_in, vimg_out))\n        {\n            assign_image(vimg_out, vimg_in);\n            return point_transform_affine();\n        }\n\n        const double rows_scale = rows / static_cast<double>(vimg_in.nr());\n        const double cols_scale = cols / static_cast<double>(vimg_in.nc());\n        const double scale = rows_scale * vimg_in.nc() > rows ? cols_scale : rows_scale;\n\n        const long nr = std::lround(scale * vimg_in.nr());\n        const long nc = std::lround(scale * vimg_in.nc());\n        const dpoint offset((cols - nc) / 2.0, (rows - nr) / 2.0);\n        const auto r = rectangle(offset.x(), offset.y(), offset.x() + nc - 1, offset.y() + nr - 1);\n        zero_border_pixels(vimg_out, r);\n        auto si = sub_image(img_out, r);\n        resize_image(vimg_in, si, interp);\n        return point_transform_affine(identity_matrix<double>(2) * scale, offset);\n    }\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine letterbox_image (\n        const image_type1& img_in,\n        image_type2& img_out\n    )\n    {\n        return letterbox_image(img_in, img_out, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine flip_image_left_right (\n        const image_type1& in_img,\n        image_type2& out_img\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void flip_image_left_right()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        assign_image(out_img, fliplr(mat(in_img)));\n        std::vector<dpoint> from, to;\n        rectangle r = get_rect(in_img);\n        from.push_back(r.tl_corner()); to.push_back(r.tr_corner());\n        from.push_back(r.bl_corner()); to.push_back(r.br_corner());\n        from.push_back(r.tr_corner()); to.push_back(r.tl_corner());\n        from.push_back(r.br_corner()); to.push_back(r.bl_corner());\n        return find_affine_transform(from,to);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    point_transform_affine flip_image_left_right (\n        image_type& img\n    )\n    {\n        image_type temp;\n        auto tform = flip_image_left_right(img, temp);\n        swap(temp,img);\n        return tform;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void flip_image_up_down (\n        const image_type1& in_img,\n        image_type2& out_img\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void flip_image_up_down()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        assign_image(out_img, flipud(mat(in_img)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline rectangle flip_rect_left_right (\n            const rectangle& rect,\n            const rectangle& window \n        )\n        {\n            rectangle temp;\n            temp.top() = rect.top();\n            temp.bottom() = rect.bottom();\n\n            const long left_dist = rect.left()-window.left();\n\n            temp.right() = window.right()-left_dist; \n            temp.left()  = temp.right()-rect.width()+1; \n            return temp;\n        }\n\n        inline rectangle tform_object (\n            const rectangle_transform& tran,\n            const rectangle& rect\n        )\n        {\n            return tran(rect);\n        }\n\n        inline mmod_rect tform_object (\n            const rectangle_transform& tran,\n            mmod_rect rect\n        )\n        {\n            rect.rect = tform_object(tran, rect.rect);\n            return rect;\n        }\n\n        inline full_object_detection tform_object(\n            const point_transform_affine& tran,\n            const full_object_detection& obj\n        )\n        {\n            std::vector<dpoint> parts; \n            parts.reserve(obj.num_parts());\n            for (unsigned long i = 0; i < obj.num_parts(); ++i)\n            {\n                if (obj.part(i) != OBJECT_PART_NOT_PRESENT)\n                    parts.push_back(tran(obj.part(i)));\n                else\n                    parts.push_back(OBJECT_PART_NOT_PRESENT);\n            }\n            return full_object_detection(tform_object(tran,obj.get_rect()), parts);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename T\n        >\n    void add_image_left_right_flips (\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size(),\n            \"\\t void add_image_left_right_flips()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():  \" << images.size() \n            << \"\\n\\t objects.size(): \" << objects.size() \n            );\n\n        typename image_array_type::value_type temp;\n        std::vector<T> rects;\n\n        const unsigned long num = images.size();\n        for (unsigned long j = 0; j < num; ++j)\n        {\n            const point_transform_affine tran = flip_image_left_right(images[j], temp);\n\n            rects.clear();\n            for (unsigned long i = 0; i < objects[j].size(); ++i)\n                rects.push_back(impl::tform_object(tran, objects[j][i]));\n\n            images.push_back(std::move(temp));\n            objects.push_back(rects);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename T,\n        typename U\n        >\n    void add_image_left_right_flips (\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects,\n        std::vector<std::vector<U> >& objects2\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size() &&\n                     images.size() == objects2.size(),\n            \"\\t void add_image_left_right_flips()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            << \"\\n\\t objects2.size(): \" << objects2.size() \n            );\n\n        typename image_array_type::value_type temp;\n        std::vector<T> rects;\n        std::vector<U> rects2;\n\n        const unsigned long num = images.size();\n        for (unsigned long j = 0; j < num; ++j)\n        {\n            const point_transform_affine tran = flip_image_left_right(images[j], temp);\n            images.push_back(std::move(temp));\n\n            rects.clear();\n            for (unsigned long i = 0; i < objects[j].size(); ++i)\n                rects.push_back(impl::tform_object(tran, objects[j][i]));\n            objects.push_back(rects);\n\n            rects2.clear();\n            for (unsigned long i = 0; i < objects2[j].size(); ++i)\n                rects2.push_back(impl::tform_object(tran, objects2[j][i]));\n            objects2.push_back(rects2);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_array_type>\n    void flip_image_dataset_left_right (\n        image_array_type& images, \n        std::vector<std::vector<rectangle> >& objects\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size(),\n            \"\\t void flip_image_dataset_left_right()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            );\n\n        typename image_array_type::value_type temp;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            flip_image_left_right(images[i], temp); \n            swap(temp,images[i]);\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                objects[i][j] = impl::flip_rect_left_right(objects[i][j], get_rect(images[i]));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_array_type>\n    void flip_image_dataset_left_right (\n        image_array_type& images, \n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size() &&\n                     images.size() == objects2.size(),\n            \"\\t void flip_image_dataset_left_right()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            << \"\\n\\t objects2.size(): \" << objects2.size() \n            );\n\n        typename image_array_type::value_type temp;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            flip_image_left_right(images[i], temp); \n            swap(temp, images[i]);\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                objects[i][j] = impl::flip_rect_left_right(objects[i][j], get_rect(images[i]));\n            }\n            for (unsigned long j = 0; j < objects2[i].size(); ++j)\n            {\n                objects2[i][j] = impl::flip_rect_left_right(objects2[i][j], get_rect(images[i]));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_array_type\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size(),\n            \"\\t void upsample_image_dataset()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            );\n\n        typename image_array_type::value_type temp;\n        pyramid_type pyr;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            const unsigned long img_size = num_rows(images[i])*num_columns(images[i]);\n            if (img_size <= max_image_size)\n            {\n                pyramid_up(images[i], temp, pyr);\n                swap(temp, images[i]);\n                for (unsigned long j = 0; j < objects[i].size(); ++j)\n                {\n                    objects[i][j] = pyr.rect_up(objects[i][j]);\n                }\n            }\n        }\n    }\n\n    template <\n        typename pyramid_type,\n        typename image_array_type\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<mmod_rect>>& objects,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size(),\n            \"\\t void upsample_image_dataset()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            );\n\n        typename image_array_type::value_type temp;\n        pyramid_type pyr;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            const unsigned long img_size = num_rows(images[i])*num_columns(images[i]);\n            if (img_size <= max_image_size)\n            {\n                pyramid_up(images[i], temp, pyr);\n                swap(temp, images[i]);\n                for (unsigned long j = 0; j < objects[i].size(); ++j)\n                {\n                    objects[i][j].rect = pyr.rect_up(objects[i][j].rect);\n                }\n            }\n        }\n    }\n\n    template <\n        typename pyramid_type,\n        typename image_array_type\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size() &&\n                     images.size() == objects2.size(),\n            \"\\t void upsample_image_dataset()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            << \"\\n\\t objects2.size(): \" << objects2.size() \n            );\n\n        typename image_array_type::value_type temp;\n        pyramid_type pyr;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            const unsigned long img_size = num_rows(images[i])*num_columns(images[i]);\n            if (img_size <= max_image_size)\n            {\n                pyramid_up(images[i], temp, pyr);\n                swap(temp, images[i]);\n                for (unsigned long j = 0; j < objects[i].size(); ++j)\n                {\n                    objects[i][j] = pyr.rect_up(objects[i][j]);\n                }\n                for (unsigned long j = 0; j < objects2[i].size(); ++j)\n                {\n                    objects2[i][j] = pyr.rect_up(objects2[i][j]);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_array_type>\n    void rotate_image_dataset (\n        double angle,\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size(),\n            \"\\t void rotate_image_dataset()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            );\n\n        typename image_array_type::value_type temp;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            const rectangle_transform tran = rotate_image(images[i], temp, angle);\n            swap(temp, images[i]);\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                const rectangle rect = objects[i][j];\n                objects[i][j] = tran(rect);\n            }\n        }\n    }\n\n    template <typename image_array_type>\n    void rotate_image_dataset (\n        double angle,\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( images.size() == objects.size() &&\n                     images.size() == objects2.size(),\n            \"\\t void rotate_image_dataset()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t images.size():   \" << images.size() \n            << \"\\n\\t objects.size():  \" << objects.size() \n            << \"\\n\\t objects2.size(): \" << objects2.size() \n            );\n\n        typename image_array_type::value_type temp;\n        for (unsigned long i = 0; i < images.size(); ++i)\n        {\n            const rectangle_transform tran = rotate_image(images[i], temp, angle);\n            swap(temp, images[i]);\n            for (unsigned long j = 0; j < objects[i].size(); ++j)\n            {\n                const rectangle rect = objects[i][j];\n                objects[i][j] = tran(rect);\n            }\n            for (unsigned long j = 0; j < objects2[i].size(); ++j)\n            {\n                const rectangle rect = objects2[i][j];\n                objects2[i][j] = tran(rect);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type, \n        typename EXP, \n        typename T, \n        typename U\n        >\n    void add_image_rotations (\n        const matrix_exp<EXP>& angles,\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects,\n        std::vector<std::vector<U> >& objects2\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_vector(angles) && angles.size() > 0 && \n                     images.size() == objects.size() &&\n                     images.size() == objects2.size(),\n            \"\\t void add_image_rotations()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_vector(angles): \" << is_vector(angles) \n            << \"\\n\\t angles.size():     \" << angles.size() \n            << \"\\n\\t images.size():     \" << images.size() \n            << \"\\n\\t objects.size():    \" << objects.size() \n            << \"\\n\\t objects2.size():   \" << objects2.size() \n            );\n\n        using namespace impl;\n\n        image_array_type new_images(images.size() * angles.size());\n        std::vector<std::vector<T>> new_objects(images.size() * angles.size());\n        std::vector<std::vector<U>> new_objects2(images.size() * angles.size());\n\n        dlib::parallel_for(0, images.size(), [&](long j) {\n            typename image_array_type::value_type temp;\n\n            long dst_base = j * angles.size();\n            for (long i = 0; i < angles.size(); ++i)\n            {\n                long dst = dst_base + i;\n                const point_transform_affine tran = rotate_image(images[j], temp, angles(i));\n                exchange(new_images[dst], temp);\n\n                for (unsigned long k = 0; k < objects[j].size(); ++k)\n                    new_objects[dst].push_back(tform_object(tran, objects[j][k]));\n\n                for (unsigned long k = 0; k < objects2[j].size(); ++k)\n                    new_objects2[dst].push_back(tform_object(tran, objects2[j][k]));\n            }\n        });\n\n        new_images.swap(images);\n        new_objects.swap(objects);\n        new_objects2.swap(objects2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type, \n        typename EXP,\n        typename T\n        >\n    void add_image_rotations (\n        const matrix_exp<EXP>& angles,\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects\n    )\n    {\n        std::vector<std::vector<T> > objects2(objects.size());\n        add_image_rotations(angles, images, objects, objects2);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename pyramid_type,\n        typename interpolation_type\n        >\n    void pyramid_up (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const pyramid_type& pyr,\n        const interpolation_type& interp\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void pyramid_up()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        if (image_size(in_img) == 0)\n        {\n            set_image_size(out_img, 0, 0);\n            return;\n        }\n\n        rectangle rect = get_rect(in_img);\n        rectangle uprect = pyr.rect_up(rect);\n        if (uprect.is_empty())\n        {\n            set_image_size(out_img, 0, 0);\n            return;\n        }\n        set_image_size(out_img, uprect.bottom()+1, uprect.right()+1);\n\n        resize_image(in_img, out_img, interp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename pyramid_type\n        >\n    void pyramid_up (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const pyramid_type& pyr\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( is_same_object(in_img, out_img) == false ,\n            \"\\t void pyramid_up()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_same_object(in_img, out_img):  \" << is_same_object(in_img, out_img)\n            );\n\n        pyramid_up(in_img, out_img, pyr, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pyramid_type\n        >\n    void pyramid_up (\n        image_type& img,\n        const pyramid_type& pyr\n    )\n    {\n        image_type temp;\n        pyramid_up(img, temp, pyr);\n        swap(temp, img);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void pyramid_up (\n        image_type& img\n    )\n    {\n        pyramid_down<2> pyr;\n        pyramid_up(img, pyr);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct chip_dims\n    {\n        chip_dims (\n            unsigned long rows_,\n            unsigned long cols_\n        ) : rows(rows_), cols(cols_) { }\n\n        unsigned long rows;\n        unsigned long cols;\n    };\n\n    struct chip_details\n    {\n        chip_details() : angle(0), rows(0), cols(0) {}\n        chip_details(const rectangle& rect_) : rect(rect_),angle(0), rows(rect_.height()), cols(rect_.width()) {}\n        chip_details(const drectangle& rect_) : rect(rect_),angle(0), \n          rows(std::lround(rect_.height())), cols(std::lround(rect_.width())) {}\n        chip_details(const drectangle& rect_, unsigned long size) : rect(rect_),angle(0) \n        { compute_dims_from_size(size); }\n        chip_details(const drectangle& rect_, unsigned long size, double angle_) : rect(rect_),angle(angle_) \n        { compute_dims_from_size(size); }\n\n        chip_details(const drectangle& rect_, const chip_dims& dims) : \n            rect(rect_),angle(0),rows(dims.rows), cols(dims.cols) {}\n        chip_details(const drectangle& rect_, const chip_dims& dims, double angle_) : \n            rect(rect_),angle(angle_),rows(dims.rows), cols(dims.cols) {}\n\n        template <typename T>\n        chip_details(\n            const std::vector<dlib::vector<T,2> >& chip_points,\n            const std::vector<dlib::vector<T,2> >& img_points,\n            const chip_dims& dims\n        ) : \n            rows(dims.rows), cols(dims.cols) \n        {\n            DLIB_CASSERT( chip_points.size() == img_points.size() && chip_points.size() >= 2,\n                \"\\t chip_details::chip_details(chip_points,img_points,dims)\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t chip_points.size(): \" << chip_points.size() \n                << \"\\n\\t img_points.size():  \" << img_points.size() \n            );\n\n            const point_transform_affine tform = find_similarity_transform(chip_points,img_points);\n            dpoint p(1,0);\n            p = tform.get_m()*p;\n\n            // There are only 3 things happening in a similarity transform.  There is a\n            // rescaling, a rotation, and a translation.  So here we pick out the scale and\n            // rotation parameters.\n            angle = std::atan2(p.y(),p.x());\n            // Note that the translation and scale part are represented by the extraction\n            // rectangle.  So here we build the appropriate rectangle.\n            const double scale = length(p); \n            rect = centered_drect(tform(point(dims.cols,dims.rows)/2.0), \n                                  dims.cols*scale, \n                                  dims.rows*scale);\n        }\n\n\n        drectangle rect;\n        double angle;\n        unsigned long rows; \n        unsigned long cols;\n\n        inline unsigned long size() const \n        {\n            return rows*cols;\n        }\n\n    private:\n        void compute_dims_from_size (\n            unsigned long size\n        ) \n        {\n            if (rect.is_empty())\n            {\n                cols = rows = std::round(std::sqrt((double)size));\n            }\n            else\n            {\n                const double relative_size = std::sqrt(size/(double)rect.area());\n                rows = static_cast<unsigned long>(rect.height()*relative_size + 0.5);\n                cols  = static_cast<unsigned long>(size/(double)rows + 0.5);\n                rows = std::max(1ul,rows);\n                cols = std::max(1ul,cols);\n            }\n        }\n    };\n\n    inline void serialize(const chip_details& item, std::ostream& out)\n    {\n        int version = 1;\n        serialize(version, out);\n        serialize(item.rect, out);\n        serialize(item.angle, out);\n        serialize(item.rows, out);\n        serialize(item.cols, out);\n    }\n\n    inline void deserialize(chip_details& item, std::istream& in)\n    {\n        int version = 0;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Unexpected version found while deserializing dlib::chip_details\");\n        deserialize(item.rect, in);\n        deserialize(item.angle, in);\n        deserialize(item.rows, in);\n        deserialize(item.cols, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline point_transform_affine get_mapping_to_chip (\n        const chip_details& details\n    )\n    {\n        std::vector<dpoint> from, to;\n        point p1(0,0);\n        point p2(details.cols-1,0);\n        point p3(details.cols-1, details.rows-1);\n        to.push_back(p1);  \n        from.push_back(rotate_point<double>(center(details.rect),details.rect.tl_corner(),details.angle));\n        to.push_back(p2);  \n        from.push_back(rotate_point<double>(center(details.rect),details.rect.tr_corner(),details.angle));\n        to.push_back(p3);  \n        from.push_back(rotate_point<double>(center(details.rect),details.rect.br_corner(),details.angle));\n        return find_affine_transform(from, to);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline full_object_detection map_det_to_chip(\n        const full_object_detection& det,\n        const chip_details& details\n    )\n    {\n        point_transform_affine tform = get_mapping_to_chip(details);\n        full_object_detection res(det);\n        // map the parts\n        for (unsigned long l = 0; l < det.num_parts(); ++l)\n        {\n            if (det.part(l) != OBJECT_PART_NOT_PRESENT)\n                res.part(l) = tform(det.part(l));\n            else\n                res.part(l) = OBJECT_PART_NOT_PRESENT;\n        }\n        // map the main rectangle\n        rectangle rect;\n        rect += tform(det.get_rect().tl_corner());\n        rect += tform(det.get_rect().tr_corner());\n        rect += tform(det.get_rect().bl_corner());\n        rect += tform(det.get_rect().br_corner());\n        res.get_rect() = rect;\n        return res;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename image_type1,\n            typename image_type2\n            >\n        void basic_extract_image_chip (\n            const image_type1& img,\n            const rectangle& location,\n            image_type2& chip\n        )\n        /*!\n            ensures\n                - This function doesn't do any scaling or rotating. It just pulls out the\n                  chip in the given rectangle.  This also means the output image has the\n                  same dimensions as the location rectangle.\n        !*/\n        {\n            const_image_view<image_type1> vimg(img);\n            image_view<image_type2> vchip(chip);\n\n            vchip.set_size(location.height(), location.width());\n\n            // location might go outside img so clip it\n            rectangle area = location.intersect(get_rect(img));\n\n            // find the part of the chip that corresponds to area in img.\n            rectangle chip_area = translate_rect(area, -location.tl_corner());\n\n            zero_border_pixels(chip, chip_area);\n            // now pull out the contents of area/chip_area.\n            for (long r = chip_area.top(), rr = area.top(); r <= chip_area.bottom(); ++r,++rr)\n            {\n                for (long c = chip_area.left(), cc = area.left(); c <= chip_area.right(); ++c,++cc)\n                {\n                    assign_pixel(vchip[r][c], vimg[rr][cc]);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void extract_image_chips (\n        const image_type1& img,\n        const std::vector<chip_details>& chip_locations,\n        dlib::array<image_type2>& chips,\n        const interpolation_type& interp\n    )\n    {\n        // make sure requires clause is not broken\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < chip_locations.size(); ++i)\n        {\n            DLIB_CASSERT(chip_locations[i].size() != 0 &&\n                         chip_locations[i].rect.is_empty() == false,\n            \"\\t void extract_image_chips()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t chip_locations[\"<<i<<\"].size():            \" << chip_locations[i].size()\n            << \"\\n\\t chip_locations[\"<<i<<\"].rect.is_empty(): \" << chip_locations[i].rect.is_empty()\n            );\n        }\n#endif \n\n        // If nearest-neighbor interpolation is wanted, then don't use an image pyramid.\n        constexpr bool image_pyramid_enabled = !std::is_same<\n            typename std::remove_const<typename std::remove_reference<decltype(interp)>::type>::type,\n            interpolate_nearest_neighbor\n        >::value;\n\n        pyramid_down<2> pyr;\n        long max_depth = 0;\n        // If the chip is supposed to be much smaller than the source subwindow then you\n        // can't just extract it using bilinear interpolation since at a high enough\n        // downsampling amount it would effectively turn into nearest neighbor\n        // interpolation.  So we use an image pyramid to make sure the interpolation is\n        // fast but also high quality.  The first thing we do is figure out how deep the\n        // image pyramid needs to be.\n        rectangle bounding_box;\n        for (unsigned long i = 0; i < chip_locations.size(); ++i)\n        {\n            long depth = 0;\n            double grow = 2;\n            drectangle rect = pyr.rect_down(chip_locations[i].rect);\n            while (rect.area() > chip_locations[i].size() && image_pyramid_enabled)\n            {\n                rect = pyr.rect_down(rect);\n                ++depth;\n                // We drop the image size by a factor of 2 each iteration and then assume a\n                // border of 2 pixels is needed to avoid any border effects of the crop.\n                grow = grow*2 + 2;\n            }\n            drectangle rot_rect;\n            const vector<double,2> cent = center(chip_locations[i].rect);\n            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.tl_corner(),chip_locations[i].angle);\n            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.tr_corner(),chip_locations[i].angle);\n            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.bl_corner(),chip_locations[i].angle);\n            rot_rect += rotate_point<double>(cent,chip_locations[i].rect.br_corner(),chip_locations[i].angle);\n            bounding_box += grow_rect(rot_rect, grow).intersect(get_rect(img));\n            max_depth = std::max(depth,max_depth);\n        }\n        //std::cout << \"max_depth: \" << max_depth << std::endl;\n        //std::cout << \"crop amount: \" << bounding_box.area()/(double)get_rect(img).area() << std::endl;\n\n        // now make an image pyramid\n        dlib::array<array2d<typename image_traits<image_type1>::pixel_type> > levels(max_depth);\n        if (levels.size() != 0)\n            pyr(sub_image(img,bounding_box),levels[0]);\n        for (unsigned long i = 1; i < levels.size(); ++i)\n            pyr(levels[i-1],levels[i]);\n\n        std::vector<dpoint> from, to;\n\n        // now pull out the chips\n        chips.resize(chip_locations.size());\n        for (unsigned long i = 0; i < chips.size(); ++i)\n        {\n            // If the chip doesn't have any rotation or scaling then use the basic version\n            // of chip extraction that just does a fast copy.\n            if (chip_locations[i].angle == 0 && \n                chip_locations[i].rows == chip_locations[i].rect.height() &&\n                chip_locations[i].cols == chip_locations[i].rect.width())\n            {\n                impl::basic_extract_image_chip(img, chip_locations[i].rect, chips[i]);\n            }\n            else\n            {\n                set_image_size(chips[i], chip_locations[i].rows, chip_locations[i].cols);\n\n                // figure out which level in the pyramid to use to extract the chip\n                int level = -1;\n                drectangle rect = translate_rect(chip_locations[i].rect, -bounding_box.tl_corner());\n                while (pyr.rect_down(rect).area() > chip_locations[i].size() && image_pyramid_enabled)\n                {\n                    ++level;\n                    rect = pyr.rect_down(rect);\n                }\n\n                // find the appropriate transformation that maps from the chip to the input\n                // image\n                from.clear();\n                to.clear();\n                from.push_back(get_rect(chips[i]).tl_corner());  to.push_back(rotate_point<double>(center(rect),rect.tl_corner(),chip_locations[i].angle));\n                from.push_back(get_rect(chips[i]).tr_corner());  to.push_back(rotate_point<double>(center(rect),rect.tr_corner(),chip_locations[i].angle));\n                from.push_back(get_rect(chips[i]).bl_corner());  to.push_back(rotate_point<double>(center(rect),rect.bl_corner(),chip_locations[i].angle));\n                point_transform_affine trns = find_affine_transform(from,to);\n\n                // now extract the actual chip\n                if (level == -1)\n                    transform_image(sub_image(img,bounding_box),chips[i],interp,trns);\n                else\n                    transform_image(levels[level],chips[i],interp,trns);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void extract_image_chips(\n        const image_type1& img,\n        const std::vector<chip_details>& chip_locations,\n        dlib::array<image_type2>& chips\n    )\n    {\n        extract_image_chips(img, chip_locations, chips, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void extract_image_chip (\n        const image_type1& img,\n        const chip_details& location,\n        image_type2& chip,\n        const interpolation_type& interp\n    )\n    {\n        // If the chip doesn't have any rotation or scaling then use the basic version of\n        // chip extraction that just does a fast copy.\n        if (location.angle == 0 && \n            location.rows == location.rect.height() &&\n            location.cols == location.rect.width())\n        {\n            impl::basic_extract_image_chip(img, location.rect, chip);\n        }\n        else\n        {\n            std::vector<chip_details> chip_locations(1,location);\n            dlib::array<image_type2> chips;\n            extract_image_chips(img, chip_locations, chips, interp);\n            swap(chips[0], chip);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void extract_image_chip (\n        const image_type1& img,\n        const chip_details& location,\n        image_type2& chip\n    )\n    {\n        extract_image_chip(img, location, chip, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n    >\n    void insert_image_chip (\n        image_type1& image,\n        const image_type2& chip,\n        const chip_details& location,\n        const interpolation_type& interp\n    )\n    {\n        image_view<image_type1> vimg(image);\n        const_image_view<image_type2> vchip(chip);\n        DLIB_CASSERT(static_cast<unsigned long>(vchip.nr()) == location.rows &&\n                     static_cast<unsigned long>(vchip.nc()) == location.cols,\n                     \"The chip and the location do not have the same size.\")\n        const auto tf = get_mapping_to_chip(location);\n        for (long r = 0; r < vimg.nr(); ++r)\n        {\n            for (long c = 0; c < vimg.nc(); ++c)\n            {\n                interp(vchip, tf(dpoint(c, r)), vimg[r][c]);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n    >\n    void insert_image_chip (\n        image_type1& image,\n        const image_type2& chip,\n        const chip_details& location\n    )\n    {\n        insert_image_chip(image, chip, location, interpolate_bilinear());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline chip_details get_face_chip_details (\n        const full_object_detection& det,\n        const unsigned long size = 200,\n        const double padding = 0.2\n    )\n    {\n        DLIB_CASSERT(det.num_parts() == 68 || det.num_parts() == 5,\n            \"\\t chip_details get_face_chip_details()\"\n            << \"\\n\\t You have to give either a 5 point or 68 point face landmarking output to this function. \"\n            << \"\\n\\t det.num_parts(): \" << det.num_parts()\n        );\n        DLIB_CASSERT(padding >= 0 && size > 0,\n            \"\\t chip_details get_face_chip_details()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t padding: \" << padding \n            << \"\\n\\t size:    \" << size \n            );\n\n\n        std::vector<dpoint> from_points, to_points;\n        if (det.num_parts() == 5)\n        {\n            dpoint p0(0.8595674595992, 0.2134981538014);\n            dpoint p1(0.6460604764104, 0.2289674387677);\n            dpoint p2(0.1205750620789, 0.2137274526848);\n            dpoint p3(0.3340850613712, 0.2290642403242);\n            dpoint p4(0.4901123135679, 0.6277975316475);\n\n\n            p0 = (padding+p0)/(2*padding+1);\n            p1 = (padding+p1)/(2*padding+1);\n            p2 = (padding+p2)/(2*padding+1);\n            p3 = (padding+p3)/(2*padding+1);\n            p4 = (padding+p4)/(2*padding+1);\n\n            from_points.push_back(p0*size);\n            to_points.push_back(det.part(0));\n\n            from_points.push_back(p1*size);\n            to_points.push_back(det.part(1));\n\n            from_points.push_back(p2*size);\n            to_points.push_back(det.part(2));\n\n            from_points.push_back(p3*size);\n            to_points.push_back(det.part(3));\n\n            from_points.push_back(p4*size);\n            to_points.push_back(det.part(4));\n        }\n        else\n        {\n            // Average positions of face points 17-67\n            const double mean_face_shape_x[] = {\n                0.000213256, 0.0752622, 0.18113, 0.29077, 0.393397, 0.586856, 0.689483, 0.799124,\n                0.904991, 0.98004, 0.490127, 0.490127, 0.490127, 0.490127, 0.36688, 0.426036,\n                0.490127, 0.554217, 0.613373, 0.121737, 0.187122, 0.265825, 0.334606, 0.260918,\n                0.182743, 0.645647, 0.714428, 0.793132, 0.858516, 0.79751, 0.719335, 0.254149,\n                0.340985, 0.428858, 0.490127, 0.551395, 0.639268, 0.726104, 0.642159, 0.556721,\n                0.490127, 0.423532, 0.338094, 0.290379, 0.428096, 0.490127, 0.552157, 0.689874,\n                0.553364, 0.490127, 0.42689\n            };\n            const double mean_face_shape_y[] = {\n                0.106454, 0.038915, 0.0187482, 0.0344891, 0.0773906, 0.0773906, 0.0344891,\n                0.0187482, 0.038915, 0.106454, 0.203352, 0.307009, 0.409805, 0.515625, 0.587326,\n                0.609345, 0.628106, 0.609345, 0.587326, 0.216423, 0.178758, 0.179852, 0.231733,\n                0.245099, 0.244077, 0.231733, 0.179852, 0.178758, 0.216423, 0.244077, 0.245099,\n                0.780233, 0.745405, 0.727388, 0.742578, 0.727388, 0.745405, 0.780233, 0.864805,\n                0.902192, 0.909281, 0.902192, 0.864805, 0.784792, 0.778746, 0.785343, 0.778746,\n                0.784792, 0.824182, 0.831803, 0.824182\n            };\n\n            COMPILE_TIME_ASSERT(sizeof(mean_face_shape_x)/sizeof(double) == 68-17);\n\n            for (unsigned long i = 17; i < det.num_parts(); ++i)\n            {\n                // Ignore the lower lip\n                if ((55 <= i && i <= 59) || (65 <= i && i <= 67))\n                    continue;\n                // Ignore the eyebrows \n                if (17 <= i && i <= 26)\n                    continue;\n\n                dpoint p;\n                p.x() = (padding+mean_face_shape_x[i-17])/(2*padding+1);\n                p.y() = (padding+mean_face_shape_y[i-17])/(2*padding+1);\n                from_points.push_back(p*size);\n                to_points.push_back(det.part(i));\n            }\n        }\n\n        return chip_details(from_points, to_points, chip_dims(size,size));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::vector<chip_details> get_face_chip_details (\n        const std::vector<full_object_detection>& dets,\n        const unsigned long size = 200,\n        const double padding = 0.2\n    )\n    {\n        std::vector<chip_details> res;\n        res.reserve(dets.size());\n        for (unsigned long i = 0; i < dets.size(); ++i)\n            res.push_back(get_face_chip_details(dets[i], size, padding));\n        return res;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n\n    template <\n        typename image_type\n        >\n    point_transform_projective extract_image_4points (\n        const image_type& img_,\n        image_type& out_,\n        const std::array<dpoint,4>& pts\n    )\n    {\n        const_image_view<image_type> img(img_);\n        image_view<image_type> out(out_);\n        if (out.size() == 0)\n            return point_transform_projective();\n\n        drectangle bounding_box;\n        for (auto& p : pts)\n            bounding_box += p;\n\n        const std::array<dpoint,4> corners = {{bounding_box.tl_corner(), bounding_box.tr_corner(),\n                                               bounding_box.bl_corner(), bounding_box.br_corner()}};\n\n        matrix<double> dists(4,4);\n        for (long r = 0; r < dists.nr(); ++r)\n        {\n            for (long c = 0; c < dists.nc(); ++c)\n            {\n                dists(r,c) = length_squared(corners[r] - pts[c]);\n            }\n        }\n\n        matrix<long long> idists = matrix_cast<long long>(-round(std::numeric_limits<long long>::max()*(dists/max(dists))));\n\n\n        const drectangle area = get_rect(out);\n        std::vector<dpoint> from_points = {area.tl_corner(), area.tr_corner(),\n                                           area.bl_corner(), area.br_corner()};\n\n        // find the assignment of corners to pts\n        auto assignment = max_cost_assignment(idists);\n        std::vector<dpoint> to_points(4);\n        for (size_t i = 0; i < assignment.size(); ++i)\n            to_points[i] = pts[assignment[i]];\n\n        auto tform = find_projective_transform(from_points, to_points);\n        transform_image(img_, out_, interpolate_bilinear(), tform);\n        return inv(tform);\n    }\n\n    template <\n        typename image_type\n        >\n    point_transform_projective extract_image_4points (\n        const image_type& img,\n        image_type& out,\n        const std::array<line,4>& lines \n    )\n    {\n        return extract_image_4points(img, out, find_convex_quadrilateral(lines));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    image_type jitter_image(\n        const image_type& img,\n        dlib::rand& rnd\n    )\n    {\n        DLIB_CASSERT(num_rows(img)*num_columns(img) != 0);\n        DLIB_CASSERT(num_rows(img)==num_columns(img));\n\n        const double max_rotation_degrees = 3;\n        const double min_object_height = 0.97; \n        const double max_object_height = 0.99999; \n        const double translate_amount = 0.02;\n\n\n        const auto rect = shrink_rect(get_rect(img),3);\n\n        // perturb the location of the crop by a small fraction of the object's size.\n        const point rand_translate = dpoint(rnd.get_double_in_range(-translate_amount,translate_amount)*rect.width(), \n            rnd.get_double_in_range(-translate_amount,translate_amount)*rect.height());\n\n        // perturb the scale of the crop by a fraction of the object's size\n        const double rand_scale_perturb = rnd.get_double_in_range(min_object_height, max_object_height); \n\n        const long box_size = rect.height()/rand_scale_perturb;\n        const auto crop_rect = centered_rect(center(rect)+rand_translate, box_size, box_size);\n        const double angle = rnd.get_double_in_range(-max_rotation_degrees, max_rotation_degrees)*pi/180;\n        image_type crop;\n        extract_image_chip(img, chip_details(crop_rect, chip_dims(num_rows(img),num_columns(img)), angle), crop);\n        if (rnd.get_random_double() > 0.5)\n            flip_image_left_right(crop); \n\n        return crop;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_INTERPOlATIONh_\n\n"
  },
  {
    "path": "dlib/image_transforms/interpolation_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_INTERPOlATION_ABSTRACT_\n#ifdef DLIB_INTERPOlATION_ABSTRACT_ \n\n#include \"../pixel.h\"\n#include \"../image_processing/full_object_detection_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n#include <array>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_nearest_neighbor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing nearest neighbor interpolation\n                on an image.  \n        !*/\n\n    public:\n\n        template <\n            typename image_view_type, \n            typename pixel_type\n            >\n        bool operator() (\n            const image_view_type& img,\n            const dlib::point& p,\n            pixel_type& result\n        ) const;\n        /*!\n            requires\n                - image_view_type == an image_view or const_image_view object. \n                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false\n                - pixel_traits<pixel_type> is defined\n            ensures\n                - if (p is located inside img) then\n                    - #result == img[p.y()][p.x()]\n                      (This assignment is done using assign_pixel(#result, img[p.y()][p.x()]), \n                      therefore any necessary color space conversion will be performed)\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_bilinear\n    {\n\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing bilinear interpolation\n                on an image.  This is performed by looking at the 4 pixels\n                nearest to a point and deriving an interpolated value from them.\n        !*/\n\n    public:\n\n        template <\n            typename T, \n            typename image_view_type,\n            typename pixel_type\n            >\n        bool operator() (\n            const image_view_type& img,\n            const dlib::vector<T,2>& p,\n            pixel_type& result\n        ) const;\n        /*!\n            requires\n                - image_view_type == an image_view or const_image_view object \n                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false\n                - pixel_traits<pixel_type> is defined\n                - is_color_space_cartesian_image<image_view_type>::value == true\n            ensures\n                - if (there is an interpolatable image location at point p in img) then\n                    - #result == the interpolated pixel value from img at point p.\n                    - assign_pixel() will be used to write to #result, therefore any\n                      necessary color space conversion will be performed.\n                    - returns true\n                - else\n                    - returns false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class interpolate_quadratic\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing quadratic interpolation\n                on an image.  This is performed by looking at the 9 pixels\n                nearest to a point and deriving an interpolated value from them.\n        !*/\n\n    public:\n\n        template <\n            typename T, \n            typename image_view_type,\n            typename pixel_type\n            >\n        bool operator() (\n            const image_view_type& img,\n            const dlib::vector<T,2>& p,\n            pixel_type& result\n        ) const;\n        /*!\n            requires\n                - image_view_type == an image_view or const_image_view object. \n                - pixel_traits<typename image_view_type::pixel_type>::has_alpha == false\n                - pixel_traits<pixel_type> is defined\n                - is_color_space_cartesian_image<image_view_type>::value == true\n            ensures\n                - if (there is an interpolatable image location at point p in img) then\n                    - #result == the interpolated pixel value from img at point p\n                    - assign_pixel() will be used to write to #result, therefore any\n                      necessary color space conversion will be performed.\n                    - returns true\n                - else\n                    - returns false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class black_background\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object which simply sets a pixel \n                to have a black value.\n        !*/\n\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& p) const { assign_pixel(p, 0); }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class white_background\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object which simply sets a pixel \n                to have a white value.\n        !*/\n\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& p) const { assign_pixel(p, 255); }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class no_background\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a function object which does nothing.  It is useful\n                when used with the transform_image() routine defined below\n                if no modification of uninterpolated output pixels is desired.\n        !*/\n    public:\n        template <typename pixel_type>\n        void operator() ( pixel_type& ) const { }\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type,\n        typename background_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point,\n        const background_type& set_background,\n        const rectangle& area\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - map_point should be a function which takes dlib::vector<T,2> objects and\n              returns dlib::vector<T,2> objects.  An example is point_transform_affine.\n            - set_background should be a function which can take a single argument of\n              type image_traits<image_type2>::pixel_type.  Examples are black_background,\n              white_background, and no_background.\n            - get_rect(out_img).contains(area) == true\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - The map_point function defines a mapping from pixels in out_img to pixels\n              in in_img.  transform_image() uses this mapping, along with the supplied\n              interpolation routine interp, to fill the region of out_img defined by\n              area with an interpolated copy of in_img.  \n            - This function does not change the size of out_img.\n            - Only pixels inside the region defined by area in out_img are modified.\n            - For all locations r and c such that area.contains(c,r) but have no corresponding \n              locations in in_img:\n                - set_background(out_img[r][c]) is invoked\n                  (i.e. some parts of out_img might correspond to areas outside in_img and\n                  therefore can't supply interpolated values.  In these cases, these\n                  pixels can be assigned a value by the supplied set_background() routine)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type,\n        typename background_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point,\n        const background_type& set_background\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - map_point should be a function which takes dlib::vector<T,2> objects and\n              returns dlib::vector<T,2> objects.  An example is point_transform_affine.\n            - set_background should be a function which can take a single argument of\n              type image_traits<image_type2>::pixel_type.  Examples are black_background, white_background,\n              and no_background.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - performs: \n              transform_image(in_img, out_img, interp, map_point, set_background, get_rect(out_img));\n              (i.e. runs transform_image() on the entire out_img)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type,\n        typename point_mapping_type\n        >\n    void transform_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp,\n        const point_mapping_type& map_point\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - map_point should be a function which takes dlib::vector<T,2> objects and\n              returns dlib::vector<T,2> objects.  An example is point_transform_affine.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - performs: \n              transform_image(in_img, out_img, interp, map_point, black_background(), get_rect(out_img));\n              (i.e. runs transform_image() on the entire out_img and sets non-interpolated\n              pixels to black)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    point_transform_affine rotate_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        double angle,\n        const interpolation_type& interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img == a copy of in_img which has been rotated angle radians counter clockwise.\n              The rotation is performed with respect to the center of the image.  \n            - Parts of #out_img which have no corresponding locations in in_img are set to black.\n            - uses the supplied interpolation routine interp to perform the necessary\n              pixel interpolation.\n            - returns a transformation object that maps points in in_img into their corresponding \n              location in #out_img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine rotate_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        double angle\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img == a copy of in_img which has been rotated angle radians counter clockwise.\n              The rotation is performed with respect to the center of the image.  \n            - Parts of #out_img which have no corresponding locations in in_img are set to black.\n            - uses the interpolate_quadratic object to perform the necessary pixel interpolation.\n            - returns a transformation object that maps points in in_img into their corresponding \n              location in #out_img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void resize_image (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const interpolation_type& interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img == A copy of in_img which has been stretched so that it \n              fits exactly into out_img.   \n            - The size of out_img is not modified.  I.e. \n                - #out_img.nr() == out_img.nr()\n                - #out_img.nc() == out_img.nc()\n            - uses the supplied interpolation routine interp to perform the necessary\n              pixel interpolation.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void resize_image (\n        const image_type1& in_img,\n        image_type2& out_img\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img == A copy of in_img which has been stretched so that it \n              fits exactly into out_img.   \n            - The size of out_img is not modified.  I.e. \n                - #out_img.nr() == out_img.nr()\n                - #out_img.nc() == out_img.nc()\n            - Uses the bilinear interpolation to perform the necessary pixel interpolation.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void resize_image (\n        double size_scale,\n        image_type& img \n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n        ensures\n            - Resizes img so that each of its dimensions are size_scale times larger than img.\n              In particular, we will have:\n                - #img.nr() == std::round(size_scale*img.nr())\n                - #img.nc() == std::round(size_scale*img.nc())\n                - #img == a bilinearly interpolated copy of the input image.\n            - Returns immediately, if size_scale == 1.0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    point_transform_affine letterbox_image (\n        const image_type1& img_in,\n        image_type2& img_out,\n        const interpolation_type interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - img_out.size() > 0\n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear,\n              interpolate_quadratic, or a type with a compatible interface.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - Scales in_img so that it fits into img_out.\n            - Preserves the aspect ratio of in_img by 0-padding the shortest side.\n            - Uses the supplied interpolation routine interp to perform the necessary\n              pixel interpolation.\n            - Returns a transformation object that maps points in in_img into their\n              corresponding location in #out_img.\n    !*/\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine letterbox_image (\n        const image_type1& img_in,\n        image_type2& img_out\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - img_out.size() > 0\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - Scales in_img so that it fits into img_out using bilinear interpolation.\n            - Preserves the aspect ratio of in_img by 0-padding the shortest side.\n            - Returns a transformation object that maps points in in_img into their\n              corresponding location in #out_img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    point_transform_affine flip_image_left_right (\n        const image_type1& in_img,\n        image_type2& out_img\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img.nr() == in_img.nr()\n            - #out_img.nc() == in_img.nc()\n            - #out_img == a copy of in_img which has been flipped from left to right.  \n              (i.e. it is flipped as if viewed though a mirror)\n            - returns a transformation object that maps points in in_img into their\n              corresponding location in #out_img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    point_transform_affine flip_image_left_right (\n        image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - This function is identical to the above version of flip_image_left_right()\n              except that it operates in-place.\n            - #img.nr() == img.nr()\n            - #img.nc() == img.nc()\n            - #img == a copy of img which has been flipped from left to right.  \n              (i.e. it is flipped as if viewed though a mirror)\n            - returns a transformation object that maps points in img into their\n              corresponding location in #img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename T\n        >\n    void add_image_left_right_flips (\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - T == rectangle, full_object_detection, or mmod_rect\n            - images.size() == objects.size()\n        ensures\n            - This function computes all the left/right flips of the contents of images and\n              then appends them onto the end of the images array.  It also finds the\n              left/right flips of the rectangles in objects and similarly appends them into\n              objects.  That is, we assume objects[i] is the set of bounding boxes in\n              images[i] and we flip the bounding boxes so that they still bound the same\n              objects in the new flipped images.\n            - #images.size() == images.size()*2\n            - #objects.size() == objects.size()*2\n            - All the original elements of images and objects are left unmodified.  That\n              is, this function only appends new elements to each of these containers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename T,\n        typename U\n        >\n    void add_image_left_right_flips (\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects,\n        std::vector<std::vector<U> >& objects2\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n            - images.size() == objects2.size()\n            - T == rectangle, full_object_detection, or mmod_rect\n            - U == rectangle, full_object_detection, or mmod_rect\n        ensures\n            - This function computes all the left/right flips of the contents of images and\n              then appends them onto the end of the images array.  It also finds the\n              left/right flips of the rectangles in objects and objects2 and similarly\n              appends them into objects and objects2 respectively.  That is, we assume\n              objects[i] is the set of bounding boxes in images[i] and we flip the bounding\n              boxes so that they still bound the same objects in the new flipped images.\n              We similarly flip the boxes in objects2.\n            - #images.size()   == images.size()*2\n            - #objects.size()  == objects.size()*2\n            - #objects2.size() == objects2.size()*2\n            - All the original elements of images, objects, and objects2 are left unmodified.\n              That is, this function only appends new elements to each of these containers.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename EXP, \n        typename T, \n        typename U\n        >\n    void add_image_rotations (\n        const matrix_exp<EXP>& angles,\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects,\n        std::vector<std::vector<U> >& objects2\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - is_vector(angles) == true\n            - angles.size() > 0\n            - images.size() == objects.size()\n            - images.size() == objects2.size()\n            - T == rectangle, full_object_detection, or mmod_rect\n            - U == rectangle, full_object_detection, or mmod_rect\n        ensures\n            - This function computes angles.size() different rotations of all the given\n              images and then replaces the contents of images with those rotations of the\n              input dataset.  We will also adjust the rectangles inside objects and\n              objects2 so that they still bound the same objects in the new rotated images.\n              That is, we assume objects[i] and objects2[i] are bounding boxes for things\n              in images[i].  So we will adjust the positions of the boxes in objects and\n              objects2 accordingly.\n            - The elements of angles are interpreted as angles in radians and we will\n              rotate the images around their center using the values in angles.  Moreover,\n              the rotation is done counter clockwise.\n            - #images.size()   == images.size()*angles.size()\n            - #objects.size()  == objects.size()*angles.size()\n            - #objects2.size() == objects2.size()*angles.size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type,\n        typename EXP,\n        typename T\n        >\n    void add_image_rotations (\n        const matrix_exp<EXP>& angles,\n        image_array_type& images,\n        std::vector<std::vector<T> >& objects\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - is_vector(angles) == true\n            - angles.size() > 0\n            - images.size() == objects.size()\n            - T == rectangle, full_object_detection, or mmod_rect\n        ensures\n            - This function is identical to the add_image_rotations() define above except\n              that it doesn't have objects2 as an argument.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void flip_image_dataset_left_right (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n        ensures\n            - This function replaces each image in images with the left/right flipped\n              version of the image.  Therefore, #images[i] will contain the left/right\n              flipped version of images[i].  It also flips all the rectangles in objects so\n              that they still bound the same visual objects in each image.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_array_type\n        >\n    void flip_image_dataset_left_right (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n            - images.size() == objects2.size()\n        ensures\n            - This function replaces each image in images with the left/right flipped\n              version of the image.  Therefore, #images[i] will contain the left/right\n              flipped version of images[i].  It also flips all the rectangles in objects\n              and objects2 so that they still bound the same visual objects in each image.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - #objects2.size() == objects2.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n            - for all valid i:\n                #objects2[i].size() == objects2[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_array_type\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h \n            - images.size() == objects.size()\n        ensures\n            - This function replaces each image in images with an upsampled version of that\n              image.  Each image is upsampled using pyramid_up() and the given\n              pyramid_type.  Therefore, #images[i] will contain the larger upsampled\n              version of images[i].  It also adjusts all the rectangles in objects so that\n              they still bound the same visual objects in each image.\n            - Input images already containing more than max_image_size pixels are not upsampled.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_array_type\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<mmod_rect>>& objects,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h \n            - images.size() == objects.size()\n        ensures\n            - This function replaces each image in images with an upsampled version of that\n              image.  Each image is upsampled using pyramid_up() and the given\n              pyramid_type.  Therefore, #images[i] will contain the larger upsampled\n              version of images[i].  It also adjusts all the rectangles in objects so that\n              they still bound the same visual objects in each image.\n            - Input images already containing more than max_image_size pixels are not upsampled.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pyramid_type,\n        typename image_array_type,\n        >\n    void upsample_image_dataset (\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2,\n        unsigned long max_image_size = std::numeric_limits<unsigned long>::max()\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n            - images.size() == objects2.size()\n        ensures\n            - This function replaces each image in images with an upsampled version of that\n              image.  Each image is upsampled using pyramid_up() and the given\n              pyramid_type.  Therefore, #images[i] will contain the larger upsampled\n              version of images[i].  It also adjusts all the rectangles in objects and\n              objects2 so that they still bound the same visual objects in each image.\n            - Input images already containing more than max_image_size pixels are not upsampled.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - #objects2.size() == objects2.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n            - for all valid i:\n                #objects2[i].size() == objects2[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_array_type>\n    void rotate_image_dataset (\n        double angle,\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n        ensures\n            - This function replaces each image in images with a rotated version of that\n              image.  In particular, each image is rotated using\n              rotate_image(original,rotated,angle).  Therefore, the images are rotated\n              angle radians counter clockwise around their centers. That is, #images[i]\n              will contain the rotated version of images[i].  It also adjusts all\n              the rectangles in objects so that they still bound the same visual objects in\n              each image.\n            - All the rectangles will still have the same sizes and aspect ratios after\n              rotation.  They will simply have had their positions adjusted so they still\n              fall on the same objects.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_array_type>\n    void rotate_image_dataset (\n        double angle,\n        image_array_type& images,\n        std::vector<std::vector<rectangle> >& objects,\n        std::vector<std::vector<rectangle> >& objects2\n    );\n    /*!\n        requires\n            - image_array_type == a dlib::array or std::vector of image objects that each\n              implement the interface defined in dlib/image_processing/generic_image.h\n            - images.size() == objects.size()\n            - images.size() == objects2.size()\n        ensures\n            - This function replaces each image in images with a rotated version of that\n              image.  In particular, each image is rotated using\n              rotate_image(original,rotated,angle).  Therefore, the images are rotated\n              angle radians counter clockwise around their centers. That is, #images[i]\n              will contain the rotated version of images[i].  It also adjusts all\n              the rectangles in objects and objects2 so that they still bound the same\n              visual objects in each image.\n            - All the rectangles will still have the same sizes and aspect ratios after\n              rotation.  They will simply have had their positions adjusted so they still\n              fall on the same objects.\n            - #images.size() == image.size()\n            - #objects.size() == objects.size()\n            - #objects2.size() == objects2.size()\n            - for all valid i:\n                #objects[i].size() == objects[i].size()\n            - for all valid i:\n                #objects2[i].size() == objects2[i].size()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void flip_image_up_down (\n        const image_type1& in_img,\n        image_type2& out_img\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img.nr() == in_img.nr()\n            - #out_img.nc() == in_img.nc()\n            - #out_img == a copy of in_img which has been flipped upside down.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename pyramid_type,\n        typename interpolation_type\n        >\n    void pyramid_up (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const pyramid_type& pyr,\n        const interpolation_type& interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pyramid_type == a type compatible with the image pyramid objects defined \n              in dlib/image_transforms/image_pyramid_abstract.h\n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - This function inverts the downsampling transformation performed by pyr().\n              In particular, it attempts to make an image, out_img, which would result\n              in in_img when downsampled with pyr().  \n            - #out_img == An upsampled copy of in_img.  In particular, downsampling\n              #out_img 1 time with pyr() should result in a final image which looks like\n              in_img.\n            - Uses the supplied interpolation routine interp to perform the necessary\n              pixel interpolation.\n            - Note that downsampling an image with pyr() and then upsampling it with \n              pyramid_up() will not necessarily result in a final image which is\n              the same size as the original.  This is because the exact size of the\n              original image cannot be determined based on the downsampled image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename pyramid_type\n        >\n    void pyramid_up (\n        const image_type1& in_img,\n        image_type2& out_img,\n        const pyramid_type& pyr\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pyramid_type == a type compatible with the image pyramid objects defined \n              in dlib/image_transforms/image_pyramid_abstract.h\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - performs: pyramid_up(in_img, out_img, pyr, interpolate_bilinear());\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename pyramid_type\n        >\n    void pyramid_up (\n        image_type& img,\n        const pyramid_type& pyr\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pyramid_type == a type compatible with the image pyramid objects defined \n              in dlib/image_transforms/image_pyramid_abstract.h\n        ensures\n            - Performs an in-place version of pyramid_up() on the given image.  In\n              particular, this function is equivalent to:\n                pyramid_up(img, temp, pyr); \n                temp.swap(img);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void pyramid_up (\n        image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - performs: pyramid_up(img, pyramid_down<2>());\n              (i.e. it upsamples the given image and doubles it in size.)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct chip_dims\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple tool for passing in a pair of row and column values to the\n                chip_details constructor.\n        !*/\n\n        chip_dims (\n            unsigned long rows_,\n            unsigned long cols_\n        ) : rows(rows_), cols(cols_) { }\n\n        unsigned long rows;\n        unsigned long cols;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct chip_details\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object describes where an image chip is to be extracted from within\n                another image.  In particular, it specifies that the image chip is\n                contained within the rectangle this->rect and that prior to extraction the\n                image should be rotated counter-clockwise by this->angle radians.  Finally,\n                the extracted chip should have this->rows rows and this->cols columns in it\n                regardless of the shape of this->rect.  This means that the extracted chip\n                will be stretched to fit via bilinear interpolation when necessary.\n        !*/\n\n        chip_details(\n        ); \n        /*!\n            ensures\n                - #rect.is_empty() == true\n                - #size() == 0\n                - #angle == 0\n                - #rows == 0\n                - #cols == 0\n        !*/\n\n        chip_details(\n            const drectangle& rect_\n        );\n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == rect_.area()\n                - #angle == 0\n                - #rows == rect_.height()\n                - #cols == rect_.width()\n        !*/\n\n        chip_details(\n            const rectangle& rect_\n        );\n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == rect_.area()\n                - #angle == 0\n                - #rows == rect_.height()\n                - #cols == rect_.width()\n        !*/\n\n        chip_details(\n            const drectangle& rect_, \n            unsigned long size_\n        );\n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == size_\n                - #angle == 0\n                - #rows and #cols is set such that the total size of the chip is as close\n                  to size_ as possible but still matches the aspect ratio of rect_.\n                - As long as size_ and the aspect ratio of rect_ stays constant then\n                  #rows and #cols will always have the same values.  This means that, for\n                  example, if you want all your chips to have the same dimensions then\n                  ensure that size_ is always the same and also that rect_ always has the\n                  same aspect ratio.  Otherwise the calculated values of #rows and #cols\n                  may be different for different chips.  Alternatively, you can use the\n                  chip_details constructor below that lets you specify the exact values for\n                  rows and cols.\n        !*/\n\n        chip_details(\n            const drectangle& rect_, \n            unsigned long size_,\n            double angle_\n        );\n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == size_\n                - #angle == angle_\n                - #rows and #cols is set such that the total size of the chip is as close\n                  to size_ as possible but still matches the aspect ratio of rect_.\n                - As long as size_ and the aspect ratio of rect_ stays constant then\n                  #rows and #cols will always have the same values.  This means that, for\n                  example, if you want all your chips to have the same dimensions then\n                  ensure that size_ is always the same and also that rect_ always has the\n                  same aspect ratio.  Otherwise the calculated values of #rows and #cols\n                  may be different for different chips.  Alternatively, you can use the\n                  chip_details constructor below that lets you specify the exact values for\n                  rows and cols.\n        !*/\n\n        chip_details(\n            const drectangle& rect_, \n            const chip_dims& dims\n        ); \n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == dims.rows*dims.cols \n                - #angle == 0\n                - #rows == dims.rows\n                - #cols == dims.cols\n        !*/\n\n        chip_details(\n            const drectangle& rect_, \n            const chip_dims& dims,\n            double angle_\n        ); \n        /*!\n            ensures\n                - #rect == rect_\n                - #size() == dims.rows*dims.cols \n                - #angle == angle_\n                - #rows == dims.rows\n                - #cols == dims.cols\n        !*/\n\n        template <typename T>\n        chip_details(\n            const std::vector<dlib::vector<T,2> >& chip_points,\n            const std::vector<dlib::vector<T,2> >& img_points,\n            const chip_dims& dims\n        );\n        /*!\n            requires\n                - chip_points.size() == img_points.size()\n                - chip_points.size() >= 2 \n            ensures\n                - The chip will be extracted such that the pixel locations chip_points[i]\n                  in the chip are mapped to img_points[i] in the original image by a\n                  similarity transform.  That is, if you know the pixelwize mapping you\n                  want between the chip and the original image then you use this function\n                  of chip_details constructor to define the mapping.\n                - #rows == dims.rows\n                - #cols == dims.cols\n                - #size() == dims.rows*dims.cols \n                - #rect and #angle are computed based on the given size of the output chip\n                  (specified by dims) and the similarity transform between the chip and\n                  image (specified by chip_points and img_points).\n        !*/\n\n        inline unsigned long size() const { return rows*cols; }\n        /*!\n            ensures\n                - returns the number of pixels in this chip.  This is just rows*cols.\n        !*/\n\n        drectangle rect;\n        double angle;\n        unsigned long rows; \n        unsigned long cols;\n    };\n\n    void serialize(const chip_details& item, std::ostream& out);\n    void deserialize(chip_details& item, std::istream& in);\n    /*!\n        provides serialization support.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point_transform_affine get_mapping_to_chip (\n        const chip_details& details\n    );\n    /*!\n        ensures\n            - returns a transformation that maps from the pixels in the original image\n              to the pixels in the cropped image defined by the given details object.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    full_object_detection map_det_to_chip (\n        const full_object_detection& det,\n        const chip_details& details\n    );\n    /*!\n        ensures\n            - Maps the given detection into the pixel space of the image chip defined by\n              the given details object.  That is, this function returns an object D such\n              that:\n                - D.get_rect() == a box that bounds the same thing in the image chip as\n                  det.get_rect() bounds in the original image the chip is extracted from.\n                - for all valid i:\n                    - D.part(i) == the location in the image chip corresponding to\n                      det.part(i) in the original image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void extract_image_chips (\n        const image_type1& img,\n        const std::vector<chip_details>& chip_locations,\n        dlib::array<image_type2>& chips,\n        const interpolation_type& interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false\n            - for all valid i: \n                - chip_locations[i].rect.is_empty() == false\n                - chip_locations[i].size() != 0\n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n        ensures\n            - This function extracts \"chips\" from an image.  That is, it takes a list of\n              rectangular sub-windows (i.e. chips) within an image and extracts those\n              sub-windows, storing each into its own image.  It also scales and rotates the\n              image chips according to the instructions inside each chip_details object.\n              It uses the interpolation method supplied as a parameter.\n            - #chips == the extracted image chips\n            - #chips.size() == chip_locations.size()\n            - for all valid i:\n                - #chips[i] == The image chip extracted from the position\n                  chip_locations[i].rect in img.\n                - #chips[i].nr() == chip_locations[i].rows\n                - #chips[i].nc() == chip_locations[i].cols\n                - The image will have been rotated counter-clockwise by\n                  chip_locations[i].angle radians, around the center of\n                  chip_locations[i].rect, before the chip was extracted. \n            - Any pixels in an image chip that go outside img are set to 0 (i.e. black).\n    !*/\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void extract_image_chips (\n        const image_type1& img,\n        const std::vector<chip_details>& chip_locations,\n        dlib::array<image_type2>& chips\n    );\n    /*!\n        ensures\n            - This function is a simple convenience / compatibility wrapper that calls the\n              above-defined extract_image_chips() function using bilinear interpolation.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n        >\n    void extract_image_chip (\n        const image_type1& img,\n        const chip_details& chip_location,\n        image_type2& chip,\n        const interpolation_type& interp\n    );\n    /*!\n        ensures\n            - This function simply calls extract_image_chips() with a single chip location\n              and stores the single output chip into #chip.  It uses the provided\n              interpolation method.\n    !*/\n\n    template <\n        typename image_type1,\n        typename image_type2\n        >\n    void extract_image_chip (\n        const image_type1& img,\n        const chip_details& chip_location,\n        image_type2& chip\n    );\n    /*!\n        ensures\n            - This function is a simple convenience / compatibility wrapper that calls the\n              above-defined extract_image_chip() function using bilinear interpolation.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1,\n        typename image_type2,\n        typename interpolation_type\n    >\n    void insert_image_chip (\n        image_type1& image,\n        const image_type2& chip,\n        const chip_details& location,\n        const interpolation_type& interp\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n            - pixel_traits<typename image_traits<image_type1>::pixel_type>::has_alpha == false\n            - num_rows(chip) == location.rows && num_columns(chip) == location.cols\n            - interpolation_type == interpolate_nearest_neighbor, interpolate_bilinear, \n              interpolate_quadratic, or a type with a compatible interface.\n        ensures\n            - This function inserts chip into the image according to the location and the\n              interpolation method supplied as a parameter.\n    !*/\n\n    template <\n        typename image_type1,\n        typename image_type2\n    >\n    void insert_image_chip (\n        image_type1& image,\n        const image_type2& chip,\n        const chip_details& location\n    );\n    /*!\n        ensures\n            - This function is a simple convenience / compatibility wrapper that calls the\n              above-defined insert_image_chip() function using bilinear interpolation.\n    !*/\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    struct sub_image_proxy\n    {\n        /*!\n            REQUIREMENTS ON image_type\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n\n            WHAT THIS OBJECT REPRESENTS\n                This is a lightweight image object for referencing a subwindow of an image.\n                It implements the generic image interface and can therefore be used with\n                any function that expects a generic image, excepting that you cannot change\n                the size of a sub_image_proxy.  \n                \n                Note that it only stores a pointer to the image data given to its\n                constructor and therefore does not perform a copy.  Moreover, this means\n                that an instance of this object becomes invalid after the underlying image\n                data it references is destroyed.\n        !*/\n        sub_image_proxy (\n            T& img,\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - This object is an image that represents the part of img contained within\n                  rect.  If rect is larger than img then rect is cropped so that it does\n                  not go outside img.\n        !*/\n    };\n\n    template <\n        typename image_type\n        >\n    sub_image_proxy<image_type> sub_image (\n        image_type& img,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - returns sub_image_proxy<image_type>(img,rect)\n    !*/\n\n    template <typename T>\n    sub_image_proxy<some_appropriate_type> sub_image (\n        T* img,\n        long nr,\n        long nc,\n        long row_stride\n    );\n    /*!\n        requires\n            - img == a pointer to at least nr*row_stride T objects\n            - nr >= 0\n            - nc >= 0\n            - row_stride >= 0\n        ensures\n            - This function returns an image that is just a thin wrapper around the given\n              pointer.  It will have the dimensions defined by the supplied longs.  To be\n              precise, this function returns an image object IMG such that:\n                - image_data(IMG) == img\n                - num_rows(IMG) == nr\n                - num_columns(IMG) == nc\n                - width_step(IMG) == row_stride*sizeof(T)\n                - IMG contains pixels of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    struct const_sub_image_proxy\n    {\n        /*!\n            REQUIREMENTS ON image_type\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n\n            WHAT THIS OBJECT REPRESENTS\n                This object is just like sub_image_proxy except that it does not allow the\n                pixel data to be modified.\n        !*/\n        const_sub_image_proxy (\n            const T& img,\n            const rectangle& rect\n        );\n        /*!\n            ensures\n                - This object is an image that represents the part of img contained within\n                  rect.  If rect is larger than img then rect is cropped so that it does\n                  not go outside img.\n        !*/\n    };\n\n    template <\n        typename image_type\n        >\n    const const_sub_image_proxy<image_type> sub_image (\n        const image_type& img,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n        ensures\n            - returns const_sub_image_proxy<image_type>(img,rect)\n    !*/\n\n    template <typename T>\n    const const_sub_image_proxy<some_appropriate_type> sub_image (\n        const T* img,\n        long nr,\n        long nc,\n        long row_stride\n    );\n    /*!\n        requires\n            - img == a pointer to at least nr*row_stride T objects\n            - nr >= 0\n            - nc >= 0\n            - row_stride >= 0\n        ensures\n            - This function returns an image that is just a thin wrapper around the given\n              pointer.  It will have the dimensions defined by the supplied longs.  To be\n              precise, this function returns an image object IMG such that:\n                - image_data(IMG) == img\n                - num_rows(IMG) == nr\n                - num_columns(IMG) == nc\n                - width_step(IMG) == row_stride*sizeof(T)\n                - IMG contains pixels of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    chip_details get_face_chip_details (\n        const full_object_detection& det,\n        const unsigned long size = 200,\n        const double padding = 0.2\n    );\n    /*!\n        requires\n            - det.num_parts() == 68 || det.num_parts() == 5\n            - size > 0\n            - padding >= 0\n        ensures\n            - This function assumes det contains a human face detection with face parts\n              annotated using the annotation scheme from the iBUG 300-W face landmark\n              dataset or a 5 point face annotation.  Given these assumptions, it creates a\n              chip_details object that will extract a copy of the face that has been\n              rotated upright, centered, and scaled to a standard size when given to\n              extract_image_chip(). \n            - This function is specifically calibrated to work with one of these models:\n                - http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2\n                - http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2\n            - The extracted chips will have size rows and columns in them.\n            - if padding == 0 then the chip will be closely cropped around the face.\n              Setting larger padding values will result a looser cropping.  In particular,\n              a padding of 0.5 would double the width of the cropped area, a value of 1\n              would triple it, and so forth.\n            - The 5 point face annotation scheme is assumed to be:\n                - det part 0 == left eye corner, outside part of eye.\n                - det part 1 == left eye corner, inside part of eye.\n                - det part 2 == right eye corner, outside part of eye.\n                - det part 3 == right eye corner, inside part of eye.\n                - det part 4 == immediately under the nose, right at the top of the philtrum.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::vector<chip_details> get_face_chip_details (\n        const std::vector<full_object_detection>& dets,\n        const unsigned long size = 200,\n        const double padding = 0.2\n    );\n    /*!\n        requires\n            - for all valid i:\n                - det[i].num_parts() == 68\n            - size > 0\n            - padding >= 0\n        ensures\n            - This function is identical to the version of get_face_chip_details() defined\n              above except that it creates and returns an array of chip_details objects,\n              one for each input full_object_detection.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    point_transform_projective extract_image_4points (\n        const image_type& img,\n        image_type& out,\n        const std::array<dpoint,4>& pts\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n        ensures\n            - The 4 points in pts define a convex quadrilateral and this function extracts\n              that part of the input image img and stores it into #out.  Therefore, each\n              corner of the quadrilateral is associated to a corner of #out and bilinear\n              interpolation and a projective mapping is used to transform the pixels in the\n              quadrilateral into #out.  To determine which corners of the quadrilateral map\n              to which corners of #out we fit the tightest possible rectangle to the\n              quadrilateral and map its vertices to their nearest rectangle corners.  These\n              corners are then trivially mapped to #out (i.e.  upper left corner to upper\n              left corner, upper right corner to upper right corner, etc.).\n            - #out.nr() == out.nr() && #out.nc() == out.nc().  \n              I.e. out should already be sized to whatever size you want it to be.\n            - Returns a transformation object that maps points in img into their\n              corresponding location in #out.\n    !*/\n\n    template <\n        typename image_type\n        >\n    point_transform_projective extract_image_4points (\n        const image_type& img,\n        image_type& out,\n        const std::array<line,4>& lines \n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n        ensures\n            - This routine finds the 4 intersecting points of the given lines which form a\n              convex quadrilateral and uses them in a call to the version of\n              extract_image_4points() defined above.  i.e. extract_image_4points(img, out,\n              intersections_between_lines)\n            - Returns a transformation object that maps points in img into their\n              corresponding location in #out.\n        throws \n            - no_convex_quadrilateral: this is thrown if you can't make a convex\n              quadrilateral out of the given lines.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    image_type jitter_image(\n        const image_type& img,\n        dlib::rand& rnd\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            - img.size() > 0\n            - img.nr() == img.nc()\n        ensures\n            - Randomly jitters the image a little bit and returns this new jittered image.\n              To be specific, the returned image has the same size as img and will look\n              generally similar.  The difference is that the returned image will have been\n              slightly rotated, zoomed, and translated.  There is also a 50% chance it will\n              be mirrored left to right.\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_INTERPOlATION_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/image_transforms/label_connected_blobs.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LABEL_CONNeCTED_BLOBS_H_\n#define DLIB_LABEL_CONNeCTED_BLOBS_H_\n\n#include \"label_connected_blobs_abstract.h\"\n#include \"../geometry.h\"\n#include <stack>\n#include <vector>\n#include \"thresholding.h\"\n#include \"assign_image.h\"\n#include <queue>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct neighbors_24\n    {\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const\n        {\n            for (long i = -2; i <= 2; ++i)\n                for (long j = -2; j <= 2; ++j)\n                    if (i!=0||j!=0)\n                        neighbors.emplace_back(p.x()+i,p.y()+j);\n        }\n    };\n\n    struct neighbors_8 \n    {\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const\n        {\n            neighbors.emplace_back(p.x()+1,p.y()+1);\n            neighbors.emplace_back(p.x()+1,p.y()  );\n            neighbors.emplace_back(p.x()+1,p.y()-1);\n\n            neighbors.emplace_back(p.x(),p.y()+1);\n            neighbors.emplace_back(p.x(),p.y()-1);\n\n            neighbors.emplace_back(p.x()-1,p.y()+1);\n            neighbors.emplace_back(p.x()-1,p.y()  );\n            neighbors.emplace_back(p.x()-1,p.y()-1);\n        }\n    };\n\n    struct neighbors_4 \n    {\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const\n        {\n            neighbors.emplace_back(p.x()+1,p.y());\n            neighbors.emplace_back(p.x()-1,p.y());\n            neighbors.emplace_back(p.x(),p.y()+1);\n            neighbors.emplace_back(p.x(),p.y()-1);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct connected_if_both_not_zero\n    {\n        template <typename image_type>\n        bool operator() (\n            const image_type& img,\n            const point& a,\n            const point& b\n        ) const\n        {\n            return (img[a.y()][a.x()] != 0 && img[b.y()][b.x()] != 0);\n        }\n    };\n\n    struct connected_if_equal\n    {\n        template <typename image_type>\n        bool operator() (\n            const image_type& img,\n            const point& a,\n            const point& b\n        ) const\n        {\n            return (img[a.y()][a.x()] == img[b.y()][b.x()]);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct zero_pixels_are_background\n    {\n        template <typename image_type>\n        bool operator() (\n            const image_type& img,\n            const point& p\n        ) const\n        {\n            return img[p.y()][p.x()] == 0;\n        }\n\n    };\n\n    struct nothing_is_background \n    {\n        template <typename image_type>\n        bool operator() (\n            const image_type&, \n            const point& \n        ) const\n        {\n            return false;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename label_image_type,\n        typename background_functor_type,\n        typename neighbors_functor_type,\n        typename connected_functor_type\n        >\n    unsigned long label_connected_blobs (\n        const image_type& img_,\n        const background_functor_type& is_background,\n        const neighbors_functor_type&  get_neighbors,\n        const connected_functor_type&  is_connected,\n        label_image_type& label_img_\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_same_object(img_, label_img_) == false,\n            \"\\t unsigned long label_connected_blobs()\"\n            << \"\\n\\t The input image and output label image can't be the same object.\"\n            );\n\n        const_image_view<image_type> img(img_);\n        image_view<label_image_type> label_img(label_img_);\n\n        std::stack<point> neighbors;\n        label_img.set_size(img.nr(), img.nc());\n        assign_all_pixels(label_img, 0);\n        unsigned long next = 1;\n\n        if (img.size() == 0)\n            return 0;\n\n        const rectangle area = get_rect(img);\n\n        std::vector<point> window;\n\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                // skip already labeled pixels or background pixels\n                if (label_img[r][c] != 0 || is_background(img,point(c,r)))\n                    continue;\n\n                label_img[r][c] = next;\n\n                // label all the neighbors of this point \n                neighbors.push(point(c,r));\n                while (neighbors.size() > 0)\n                {\n                    const point p = neighbors.top();\n                    neighbors.pop();\n\n                    window.clear();\n                    get_neighbors(p, window);\n\n                    for (unsigned long i = 0; i < window.size(); ++i)\n                    {\n                        if (area.contains(window[i]) &&                     // point in image.\n                            !is_background(img,window[i]) &&                // isn't background.\n                            label_img[window[i].y()][window[i].x()] == 0 && // haven't already labeled it.\n                            is_connected(img, p, window[i]))                // it's connected.\n                        {\n                            label_img[window[i].y()][window[i].x()] = next;\n                            neighbors.push(window[i]);\n                        }\n                    }\n                }\n\n                ++next;\n            }\n        }\n\n        return next;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    unsigned long label_connected_blobs_watershed (\n        const in_image_type& img_,\n        out_image_type& labels_,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type background_thresh,\n        const double smoothing = 0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_same_object(img_, labels_) == false,\n            \"\\t unsigned long segment_image_watersheds()\"\n            << \"\\n\\t The input images can't be the same object.\"\n            );\n\n        using label_pixel_type = typename image_traits<out_image_type>::pixel_type;\n\n        DLIB_ASSERT(smoothing >= 0);\n        COMPILE_TIME_ASSERT(is_unsigned_type<label_pixel_type>::value);\n\n\n        struct watershed_points\n        {\n            watershed_points() = default;\n            watershed_points(const point& p_, float score_, label_pixel_type label_): p(p_), score(score_), label(label_) {}\n\n            point p;\n            float score = 0;\n            label_pixel_type label = std::numeric_limits<label_pixel_type>::max();\n\n            bool is_seed() const { return label == std::numeric_limits<label_pixel_type>::max(); }\n\n            bool operator< (const watershed_points& rhs) const\n            {\n                // If two pixels have the same score then we take the one with the smallest \n                // label out of the priority queue first.  We do this so that seed points\n                // that are downhill from some larger blob will be consumed by it if they\n                // haven't grown before the larger blob's flooding reaches them.  Doing\n                // this helps a lot to avoid spuriously splitting blobs.\n                if (score == rhs.score)\n                {\n                    return label > rhs.label;\n                }\n                return score < rhs.score;\n            }\n\n        };\n\n        const_image_view<in_image_type> img(img_);\n        image_view<out_image_type> labels(labels_);\n        \n        labels.set_size(img.nr(), img.nc());\n        // Initially, all pixels have the background label of 0.\n        assign_all_pixels(labels, 0);\n\n        std::priority_queue<watershed_points> next;\n\n\n        // Note that we never blur the image values we use to check against the\n        // background_thresh.  We do however blur, if smoothing!=0, the pixel values used\n        // to do the watershed.\n        in_image_type img2_;\n        if (smoothing != 0)\n            gaussian_blur(img_, img2_, smoothing); \n        const_image_view<in_image_type> img2view(img2_);\n        // point us at img2 if we are doing smoothing, otherwise point us at the input\n        // image.\n        const auto& img2 = smoothing!=0?img2view:img;\n\n        // first find all the local maxima \n        for (long r = 1; r+1 < img.nr(); ++r)\n        {\n            for (long c = 1; c+1 < img.nc(); ++c)\n            {\n\n                if (img[r][c] < background_thresh)\n                    continue;\n\n                auto val = img2[r][c];\n                // if img2[r][c] isn't a local maximum then skip it\n                if (val < img2[r+1][c] ||\n                    val < img2[r-1][c] ||\n                    val < img2[r][c+1] ||\n                    val < img2[r][c-1]\n                )\n                {\n                    continue;\n                }\n\n                next.push(watershed_points(point(c,r), val, std::numeric_limits<label_pixel_type>::max()));\n            }\n        }\n\n\n        const rectangle area = get_rect(img);\n\n\n        label_pixel_type next_label = 1;\n\n\n        std::vector<point> neighbors;\n        neighbors_8 get_neighbors;\n        while(next.size() > 0)\n        {\n            auto p = next.top();\n            next.pop();\n\n            label_pixel_type label;\n            // If the next pixel is a seed of a new blob and is still labeled as a\n            // background pixel (i.e. it hasn't been flooded over by a neighboring blob and\n            // consumed by it) then we create a new label for this new blob.\n            if (p.is_seed() && labels[p.p.y()][p.p.x()] == 0)\n            {\n                label = next_label++;\n                labels[p.p.y()][p.p.x()] = label;\n            }\n            else\n            {\n                label = p.label;\n            }\n\n\n            neighbors.clear();\n            get_neighbors(p.p, neighbors);\n            for (auto& n : neighbors)\n            {\n                if (!area.contains(n) || labels[n.y()][n.x()] != 0 || img[n.y()][n.x()] < background_thresh)\n                    continue;\n\n                labels[n.y()][n.x()] = label;\n                next.push(watershed_points(n, img2[n.y()][n.x()], label));\n            }\n        }\n\n        return next_label;\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    unsigned long label_connected_blobs_watershed (\n        const in_image_type& img,\n        out_image_type& labels\n    )\n    {\n        return label_connected_blobs_watershed(img, labels, partition_pixels(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LABEL_CONNeCTED_BLOBS_H_\n\n"
  },
  {
    "path": "dlib/image_transforms/label_connected_blobs_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_\n#ifdef DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_\n\n#include \"../geometry.h\"\n#include <vector>\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct neighbors_24\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a pixel neighborhood generating functor for \n                use with the label_connected_blobs() routine defined below.\n        !*/\n\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const;\n        /*!\n            ensures\n                - adds the 24 neighboring pixels surrounding p into neighbors\n        !*/\n    };\n\n    struct neighbors_8 \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a pixel neighborhood generating functor for \n                use with the label_connected_blobs() routine defined below.\n        !*/\n\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const;\n        /*!\n            ensures\n                - adds the 8 neighboring pixels surrounding p into neighbors\n        !*/\n    };\n\n    struct neighbors_4 \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a pixel neighborhood generating functor for \n                use with the label_connected_blobs() routine defined below.\n        !*/\n\n        void operator() (\n            const point& p,\n            std::vector<point>& neighbors\n        ) const;\n        /*!\n            ensures\n                - adds the 4 neighboring pixels of p into neighbors.  These\n                  are the ones immediately to the left, top, right, and bottom.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct connected_if_both_not_zero\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a pixel connection testing functor for use\n                with the label_connected_blobs() routine defined below.\n        !*/\n\n        template <typename image_view_type>\n        bool operator() (\n            const image_view_type& img,\n            const point& a,\n            const point& b\n        ) const\n        {\n            return (img[a.y()][a.x()] != 0 && img[b.y()][b.x()] != 0);\n        }\n    };\n\n    struct connected_if_equal\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a pixel connection testing functor for use\n                with the label_connected_blobs() routine defined below.\n        !*/\n\n        template <typename image_view_type>\n        bool operator() (\n            const image_view_type& img,\n            const point& a,\n            const point& b\n        ) const\n        {\n            return (img[a.y()][a.x()] == img[b.y()][b.x()]);\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct zero_pixels_are_background\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a background testing functor for use\n                with the label_connected_blobs() routine defined below.\n        !*/\n\n        template <typename image_view_type>\n        bool operator() (\n            const image_view_type& img,\n            const point& p\n        ) const\n        {\n            return img[p.y()][p.x()] == 0;\n        }\n\n    };\n\n    struct nothing_is_background \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a background testing functor for use\n                with the label_connected_blobs() routine defined below.\n        !*/\n\n        template <typename image_view_type>\n        bool operator() (\n            const image_view_type&, \n            const point& \n        ) const\n        {\n            return false;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename label_image_type,\n        typename background_functor_type,\n        typename neighbors_functor_type,\n        typename connected_functor_type\n        >\n    unsigned long label_connected_blobs (\n        const image_type& img,\n        const background_functor_type& is_background,\n        const neighbors_functor_type&  get_neighbors,\n        const connected_functor_type&  is_connected,\n        label_image_type& label_img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - label_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain integer pixels.\n            - is_background(img, point(c,r)) is a legal expression that evaluates to a bool.\n            - is_connected(img, point(c,r), point(c2,r2)) is a legal expression that\n              evaluates to a bool.\n            - get_neighbors(point(c,r), neighbors) is a legal expression where neighbors \n              is of type std::vector<point>.\n            - is_same_object(img, label_img) == false\n        ensures\n            - This function labels each of the connected blobs in img with a unique integer \n              label.  \n            - An image can be thought of as a graph where pixels A and B are connected if \n              and only if the following two statements are satisfied:\n                - is_connected(img,A,B) == true\n                - get_neighbors(A, neighbors) results in neighbors containing B or\n                  get_neighbors(B, neighbors) results in neighbors containing A.\n              Then this function can be understood as labeling all the connected components \n              of this pixel graph such that all pixels in a component get the same label while\n              pixels in different components get different labels.  Note that there is a \n              special \"background\" component determined by is_background().  Any pixels which \n              are \"background\" always get a blob id of 0 regardless of any other considerations.\n            - #label_img.nr() == img.nr()\n            - #label_img.nc() == img.nc()\n            - for all valid r and c:\n                - #label_img[r][c] == the blob label number for pixel img[r][c].  \n                - #label_img[r][c] >= 0\n                - if (is_background(img, point(c,r))) then\n                    - #label_img[r][c] == 0\n                - else\n                    - #label_img[r][c] != 0\n            - if (img.size() != 0) then \n                - returns max(mat(#label_img))+1\n                  (i.e. returns a number one greater than the maximum blob id number, \n                  this is the number of blobs found.)\n            - else\n                - returns 0\n            - blob labels are contiguous, therefore, the number returned by this function is\n              the number of blobs in the image (including the background blob).\n            - It is guaranteed that is_connected() and is_background() will never be \n              called with points outside the image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    unsigned long label_connected_blobs_watershed (\n        const in_image_type& img,\n        out_image_type& labels,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type background_thresh,\n        const double smoothing = 0\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_image_type must contain a grayscale pixel type. \n            - out_image_type must contain an unsigned integer pixel type.\n            - is_same_object(img, labels) == false\n            - smoothing >= 0\n        ensures\n            - This routine performs a watershed segmentation of the given input image and\n              labels each resulting flooding region with a unique integer label. It does\n              this by marking the brightest pixels as sources of flooding and then flood\n              fills the image outward from those sources.  Each flooded area is labeled\n              with the identity of the source pixel and flooding stops when another flooded\n              area is reached or pixels with values < background_thresh are encountered.  \n            - The flooding will also overrun a source pixel if that source pixel has yet to\n              label any neighboring pixels.  This behavior helps to mitigate spurious\n              splits of objects due to noise.  You can further control this behavior by\n              setting the smoothing parameter.  The flooding will take place on an image\n              that has been Gaussian blurred with a sigma==smoothing.  So setting smoothing\n              to a larger number will in general cause more regions to be merged together.\n              Note that the smoothing parameter has no effect on the interpretation of\n              background_thresh since the decision of \"background or not background\" is\n              always made relative to the unsmoothed input image.\n            - #labels.nr() == img.nr()\n            - #labels.nc() == img.nc()\n            - for all valid r and c:\n                - if (img[r][c] < background_thresh) then\n                    - #labels[r][c] == 0, (i.e. the pixel is labeled as background)\n                - else\n                    - #labels[r][c] == an integer value indicating the identity of the segment\n                      containing the pixel img[r][c].  \n            - returns the number of labeled segments, including the background segment.\n              Therefore, the returned number is 1+(the max value in #labels).\n    !*/\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    unsigned long label_connected_blobs_watershed (\n        const in_image_type& img,\n        out_image_type& labels\n    );\n    /*!\n        simply invokes: return label_connected_blobs_watershed(img, labels, partition_pixels(img));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LABEL_CONNeCTED_BLOBS_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/image_transforms/lbp.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LBP_Hh_\n#define DLIB_LBP_Hh_\n\n#include \"lbp_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n#include \"assign_image.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename image_type2\n        >\n    void make_uniform_lbp_image (\n        const image_type& img_,\n        image_type2& lbp_\n    )\n    {\n        const static unsigned char uniform_lbps[] = {\n            0, 1, 2, 3, 4, 58, 5, 6, 7, 58, 58, 58, 8, 58, 9, 10, 11, 58, 58, 58, 58, 58,\n            58, 58, 12, 58, 58, 58, 13, 58, 14, 15, 16, 58, 58, 58, 58, 58, 58, 58, 58, 58,\n            58, 58, 58, 58, 58, 58, 17, 58, 58, 58, 58, 58, 58, 58, 18, 58, 58, 58, 19, 58,\n            20, 21, 22, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,\n            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 23, 58, 58, 58, 58, 58,\n            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 24, 58, 58, 58, 58, 58, 58, 58, 25, 58,\n            58, 58, 26, 58, 27, 28, 29, 30, 58, 31, 58, 58, 58, 32, 58, 58, 58, 58, 58, 58,\n            58, 33, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 34, 58, 58,\n            58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,\n            58, 58, 58, 58, 58, 58, 58, 58, 58, 35, 36, 37, 58, 38, 58, 58, 58, 39, 58, 58,\n            58, 58, 58, 58, 58, 40, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,\n            58, 41, 42, 43, 58, 44, 58, 58, 58, 45, 58, 58, 58, 58, 58, 58, 58, 46, 47, 48,\n            58, 49, 58, 58, 58, 50, 51, 52, 58, 53, 54, 55, 56, 57\n        };\n\n        COMPILE_TIME_ASSERT(sizeof(uniform_lbps) == 256);\n\n        const_image_view<image_type> img(img_);\n        image_view<image_type2> lbp(lbp_);\n\n        lbp.set_size(img.nr(), img.nc());\n\n        // set all the border pixels to the \"non-uniform LBP value\".\n        assign_border_pixels(lbp, 1, 1, 58);\n\n        typedef typename image_traits<image_type>::pixel_type pixel_type;\n        typedef typename pixel_traits<pixel_type>::basic_pixel_type basic_pixel_type;\n\n        for (long r = 1; r+1 < img.nr(); ++r)\n        {\n            for (long c = 1; c+1 < img.nc(); ++c)\n            {\n                const basic_pixel_type pix = get_pixel_intensity(img[r][c]);\n                unsigned char b1 = 0;\n                unsigned char b2 = 0;\n                unsigned char b3 = 0;\n                unsigned char b4 = 0;\n                unsigned char b5 = 0;\n                unsigned char b6 = 0;\n                unsigned char b7 = 0;\n                unsigned char b8 = 0;\n\n                unsigned char x = 0;\n                if (get_pixel_intensity(img[r-1][c-1]) > pix) b1 = 0x80; \n                if (get_pixel_intensity(img[r-1][c  ]) > pix) b2 = 0x40;\n                if (get_pixel_intensity(img[r-1][c+1]) > pix) b3 = 0x20;\n                x |= b1;\n                if (get_pixel_intensity(img[r  ][c-1]) > pix) b4 = 0x10;\n                x |= b2;\n                if (get_pixel_intensity(img[r  ][c+1]) > pix) b5 = 0x08;\n                x |= b3;\n                if (get_pixel_intensity(img[r+1][c-1]) > pix) b6 = 0x04;\n                x |= b4;\n                if (get_pixel_intensity(img[r+1][c  ]) > pix) b7 = 0x02;\n                x |= b5;\n                if (get_pixel_intensity(img[r+1][c+1]) > pix) b8 = 0x01;\n\n                x |= b6;\n                x |= b7;\n                x |= b8;\n\n                lbp[r][c] = uniform_lbps[x];\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_histogram_descriptors (\n        const image_type& img_,\n        const point& loc,\n        std::vector<T>& histograms,\n        const unsigned int cell_size = 10,\n        const unsigned int block_size = 4,\n        const unsigned int max_val = 58\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(cell_size >= 1 && block_size >= 1 && max_val < 256 && \n                    (unsigned int)max(mat(img_)) <= max_val,\n            \"\\t void extract_histogram_descriptors()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t cell_size:      \" << cell_size\n            << \"\\n\\t block_size:     \" << block_size\n            << \"\\n\\t max_val:        \" << max_val\n            << \"\\n\\t max(mat(img_)): \" << max(mat(img_))\n            );\n\n        typedef typename image_traits<image_type>::pixel_type pixel_type;\n        COMPILE_TIME_ASSERT((is_same_type<pixel_type, unsigned char>::value));\n\n        const_image_view<image_type> img(img_);\n\n        const rectangle area = get_rect(img);\n        const rectangle window = centered_rect(loc, block_size*cell_size, block_size*cell_size);\n        unsigned int cell_top = window.top();\n        for (unsigned int br = 0; br < block_size; ++br)\n        {\n            unsigned int cell_left = window.left();\n            for (unsigned int bc = 0; bc < block_size; ++bc)\n            {\n                // figure out the cell boundaries\n                rectangle cell(cell_left, cell_top, cell_left+cell_size-1, cell_top+cell_size-1);\n                cell = cell.intersect(area);\n\n                // make the actual histogram for this cell\n                unsigned int hist[256] = {0};\n                for (long r = cell.top(); r <= cell.bottom(); ++r)\n                {\n                    for (long c = cell.left(); c <= cell.right(); ++c)\n                    {\n                        hist[img[r][c]]++;\n                    }\n                }\n\n                // copy histogram into the output.\n                histograms.insert(histograms.end(), hist, hist + max_val+1);\n\n                cell_left += cell_size;\n            }\n            cell_top += cell_size;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_uniform_lbp_descriptors (\n        const image_type& img,\n        std::vector<T>& feats,\n        const unsigned int cell_size = 10\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(cell_size >= 1,\n            \"\\t void extract_uniform_lbp_descriptors()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t cell_size:      \" << cell_size\n            );\n\n        feats.clear();\n        array2d<unsigned char> lbp;\n        make_uniform_lbp_image(img, lbp);\n        for (long r = 0; r < lbp.nr(); r+=cell_size)\n        {\n            for (long c = 0; c < lbp.nc(); c+=cell_size)\n            {\n                const rectangle cell = rectangle(c,r,c+cell_size-1,r+cell_size-1).intersect(get_rect(lbp));\n                // make the actual histogram for this cell\n                unsigned int hist[59] = {0};\n                for (long r = cell.top(); r <= cell.bottom(); ++r)\n                {\n                    for (long c = cell.left(); c <= cell.right(); ++c)\n                    {\n                        hist[lbp[r][c]]++;\n                    }\n                }\n\n                // copy histogram into the output.\n                feats.insert(feats.end(), hist, hist + 59);\n            }\n        }\n\n        for (unsigned long i = 0; i < feats.size(); ++i)\n            feats[i] = std::sqrt(feats[i]);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_highdim_face_lbp_descriptors (\n        const image_type& img,\n        const full_object_detection& det,\n        std::vector<T>& feats\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(det.num_parts() == 68,\n            \"\\t void extract_highdim_face_lbp_descriptors()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t det.num_parts(): \" << det.num_parts()\n            );\n\n        const unsigned long num_scales = 5; \n        feats.clear();\n        dlib::vector<double,2> l, r;\n        double cnt = 0;\n        // Find the center of the left eye by averaging the points around \n        // the eye.\n        for (unsigned long i = 36; i <= 41; ++i) \n        {\n            l += det.part(i);\n            ++cnt;\n        }\n        l /= cnt;\n\n        // Find the center of the right eye by averaging the points around \n        // the eye.\n        cnt = 0;\n        for (unsigned long i = 42; i <= 47; ++i) \n        {\n            r += det.part(i);\n            ++cnt;\n        }\n        r /= cnt;\n\n        // We only do feature extraction from these face parts.  These are things like the\n        // corners of the eyes and mouth and stuff like that.\n        std::vector<point> parts;\n        parts.reserve(30);\n        parts.push_back(l);\n        parts.push_back(r);\n        parts.push_back(det.part(17));\n        parts.push_back(det.part(21));\n        parts.push_back(det.part(22));\n        parts.push_back(det.part(26));\n        parts.push_back(det.part(36));\n        parts.push_back(det.part(39));\n        parts.push_back(det.part(42));\n        parts.push_back(det.part(45));\n        parts.push_back(det.part(27));\n        parts.push_back(det.part(28));\n        parts.push_back(det.part(29));\n        parts.push_back(det.part(30));\n        parts.push_back(det.part(31));\n        parts.push_back(det.part(35));\n        parts.push_back(det.part(33));\n        parts.push_back(det.part(48));\n        parts.push_back(det.part(54));\n        parts.push_back(det.part(51));\n        parts.push_back(det.part(57));\n\n        array2d<unsigned char> lbp;\n        make_uniform_lbp_image(img, lbp);\n        for (unsigned long i = 0; i < parts.size(); ++i)\n            extract_histogram_descriptors(lbp, parts[i], feats);\n\n        if (num_scales > 1)\n        {\n            pyramid_down<4> pyr;\n            image_type img_temp;\n            pyr(img, img_temp);\n            unsigned long num_pyr_calls = 1;\n\n            // now pull the features out at coarser scales\n            for (unsigned long iter = 1; iter < num_scales; ++iter)\n            {\n                // now do the feature extraction\n                make_uniform_lbp_image(img_temp, lbp);\n                for (unsigned long i = 0; i < parts.size(); ++i)\n                    extract_histogram_descriptors(lbp, pyr.point_down(parts[i],num_pyr_calls), feats);\n\n                if (iter+1 < num_scales)\n                {\n                    pyr(img_temp);\n                    ++num_pyr_calls;\n                }\n            }\n        }\n\n        for (unsigned long i = 0; i < feats.size(); ++i)\n            feats[i] = std::sqrt(feats[i]);\n\n        DLIB_ASSERT(feats.size() == 99120, feats.size());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LBP_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/lbp_abstract.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LBP_ABSTRACT_Hh_\n#ifdef DLIB_LBP_ABSTRACT_Hh_\n\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename image_type2\n        >\n    void make_uniform_lbp_image (\n        const image_type& img,\n        image_type2& lbp\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type2 should contain a grayscale pixel type such as unsigned char.\n        ensures\n            - #lbp.nr() == img.nr()\n            - #lbp.nc() == img.nc()\n            - This function extracts the uniform local-binary-pattern feature at every pixel\n              and stores it into #lbp.  In particular, we have the following for all valid \n              r and c:\n                - #lbp[r][c] == the uniform LBP for the 3x3 pixel window centered on img[r][c].  \n                  In particular, this is a value in the range 0 to 58 inclusive. \n            - We use the idea of uniform LBPs from the paper: \n                Face Description with Local Binary Patterns: Application to Face Recognition\n                by Ahonen, Hadid, and Pietikainen.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_histogram_descriptors (\n        const image_type& img,\n        const point& loc,\n        std::vector<T>& histograms,\n        const unsigned int cell_size = 10,\n        const unsigned int block_size = 4,\n        const unsigned int max_val = 58\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - image_type contains unsigned char valued pixels.\n            - T is some scalar type like int or double\n            - All pixel values in img are <= max_val\n            - cell_size >= 1\n            - block_size >= 1\n            - max_val < 256\n        ensures\n            - This function extracts histograms of pixel values from block_size*block_size\n              windows in the area in img immediately around img[loc.y()][loc.x()].  The\n              histograms are appended onto the end of #histograms.  Each window is\n              cell_size pixels wide and tall.  Moreover, the windows do not overlap.\n            - #histograms.size() == histograms.size() + block_size*block_size*(max_val+1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_uniform_lbp_descriptors (\n        const image_type& img,\n        std::vector<T>& feats,\n        const unsigned int cell_size = 10\n    );\n    /*!\n        requires\n            - cell_size >= 1\n            - T is some scalar type like int or double\n        ensures\n            - Extracts histograms of uniform local-binary-patterns from img.  The\n              histograms are from densely tiled windows that are cell_size pixels wide and\n              tall.  The windows do not overlap and cover all of img.\n            - #feats.size() == 59*(number of windows that fit into img)\n              (i.e. #feats contains the LBP histograms)\n            - We will have taken the square root of all the histogram elements.  That is,\n              #feats[i] is the square root of the number of LBPs that appeared in its\n              corresponding window.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type,\n        typename T\n        >\n    void extract_highdim_face_lbp_descriptors (\n        const image_type& img,\n        const full_object_detection& det,\n        std::vector<T>& feats\n    );\n    /*!\n        requires\n            - T is some scalar type like int or double\n            - det.num_parts() == 68\n        ensures\n            - This function extracts the high-dimensional LBP feature described in the\n              paper:\n                Blessing of Dimensionality: High-dimensional Feature and Its Efficient\n                Compression for Face Verification by Dong Chen, Xudong Cao, Fang Wen, and\n                Jian Sun\n            - #feats == the high-dimensional LBP descriptor.  It is the concatenation of\n              many LBP histograms, each extracted from different scales and from different\n              windows around different face landmarks.  We also take the square root of\n              each histogram element before storing it into #feats.\n            - #feats.size() == 99120\n            - This function assumes img has already been aligned and normalized to a\n              standard size.\n            - This function assumes det contains a human face detection with face parts\n              annotated using the annotation scheme from the iBUG 300-W face landmark\n              dataset.  This means that det.part(i) gives the locations of different face\n              landmarks according to the iBUG 300-W annotation scheme.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LBP_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/morphological_operations.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MORPHOLOGICAL_OPERATIONs_\n#define DLIB_MORPHOLOGICAL_OPERATIONs_\n\n#include \"../pixel.h\"\n#include \"thresholding.h\"\n#include \"morphological_operations_abstract.h\"\n#include \"assign_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace morphological_operations_helpers\n    {\n        template <typename image_type>\n        bool is_binary_image (\n            const image_type& img_\n        )\n        /*!\n            ensures\n                - returns true if img_ contains only on_pixel and off_pixel values.\n                - returns false otherwise\n        !*/\n        {\n            const_image_view<image_type> img(img_);\n            for (long r = 0; r < img.nr(); ++r)\n            {\n                for (long c = 0; c < img.nc(); ++c)\n                {\n                    if (img[r][c] != on_pixel && img[r][c] != off_pixel)\n                    {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        }\n\n        template <\n            long M,\n            long N\n            >\n        bool is_binary_image (\n            const unsigned char (&structuring_element)[M][N]\n        )\n        /*!\n            ensures\n                - returns true if structuring_element contains only on_pixel and off_pixel values.\n                - returns false otherwise\n        !*/\n        {\n            for (long m = 0; m < M; ++m)\n            {\n                for (long n = 0; n < N; ++n)\n                {\n                    if (structuring_element[m][n] != on_pixel &&\n                        structuring_element[m][n] != off_pixel)\n                    {\n                        return false;\n                    }\n                }\n            }\n            return true;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_dilation (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const unsigned char (&structuring_element)[M][N]\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(M%2 == 1);\n        COMPILE_TIME_ASSERT(N%2 == 1);\n        DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,\n            \"\\tvoid binary_dilation()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img_) ,\n            \"\\tvoid binary_dilation()\"\n            << \"\\n\\tin_img must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(structuring_element) ,\n            \"\\tvoid binary_dilation()\"\n            << \"\\n\\tthe structuring_element must be a binary image\"\n            );\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        // apply the filter to the image\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                unsigned char out_pixel = off_pixel;\n                for (long m = 0; m < M && out_pixel == off_pixel; ++m)\n                {\n                    for (long n = 0; n < N && out_pixel == off_pixel; ++n)\n                    {\n                        if (structuring_element[m][n] == on_pixel)\n                        {\n                            // if this pixel is inside the image then get it from the image\n                            // but if it isn't just pretend it was an off_pixel value\n                            if (r+m >= M/2 && c+n >= N/2 &&\n                                r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())\n                            {\n                                out_pixel = in_img[r+m-M/2][c+n-N/2];\n                            }\n                        }\n                    }\n                }\n                assign_pixel(out_img[r][c], out_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_erosion (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const unsigned char (&structuring_element)[M][N]\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(M%2 == 1);\n        COMPILE_TIME_ASSERT(N%2 == 1);\n        DLIB_ASSERT(is_same_object(in_img_,out_img_) == false,\n            \"\\tvoid binary_erosion()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img_) ,\n            \"\\tvoid binary_erosion()\"\n            << \"\\n\\tin_img must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(structuring_element) ,\n            \"\\tvoid binary_erosion()\"\n            << \"\\n\\tthe structuring_element must be a binary image\"\n            );\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        // apply the filter to the image\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                unsigned char out_pixel = on_pixel;\n                for (long m = 0; m < M && out_pixel == on_pixel; ++m)\n                {\n                    for (long n = 0; n < N && out_pixel == on_pixel; ++n)\n                    {\n                        if (structuring_element[m][n] == on_pixel)\n                        {\n                            // if this pixel is inside the image then get it from the image\n                            // but if it isn't just pretend it was an off_pixel value\n                            if (r+m >= M/2 && c+n >= N/2 &&\n                                r+m-M/2 < in_img.nr() && c+n-N/2 < in_img.nc())\n                            {\n                                out_pixel = in_img[r+m-M/2][c+n-N/2];\n                            }\n                            else\n                            {\n                                out_pixel = off_pixel;\n                            }\n                        }\n                    }\n                }\n                assign_pixel(out_img[r][c], out_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_open (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N],\n        const unsigned long iter = 1\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(M%2 == 1);\n        COMPILE_TIME_ASSERT(N%2 == 1);\n        DLIB_ASSERT(is_same_object(in_img,out_img) == false,\n            \"\\tvoid binary_open()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img) ,\n            \"\\tvoid binary_open()\"\n            << \"\\n\\tin_img must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(structuring_element) ,\n            \"\\tvoid binary_open()\"\n            << \"\\n\\tthe structuring_element must be a binary image\"\n            );\n\n\n        // if there isn't any input image then don't do anything\n        if (num_rows(in_img)*num_columns(in_img) == 0)\n        {\n            set_image_size(out_img, 0,0);\n            return;\n        }\n\n        set_image_size(out_img, num_rows(in_img), num_columns(in_img));\n\n        if (iter == 0)\n        {\n            // just copy the image over\n            assign_image(out_img, in_img);\n        }\n        else if (iter == 1)\n        {\n            in_image_type temp;\n            binary_erosion(in_img,temp,structuring_element);\n            binary_dilation(temp,out_img,structuring_element);\n        }\n        else\n        {\n            in_image_type temp1, temp2;\n            binary_erosion(in_img,temp1,structuring_element);\n\n            // do the extra erosions\n            for (unsigned long i = 1; i < iter; ++i)\n            {\n                swap(temp1, temp2);\n                binary_erosion(temp2,temp1,structuring_element);\n            }\n\n            // do the extra dilations \n            for (unsigned long i = 1; i < iter; ++i)\n            {\n                swap(temp1, temp2);\n                binary_dilation(temp2,temp1,structuring_element);\n            }\n\n            binary_dilation(temp1,out_img,structuring_element);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_close (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N],\n        const unsigned long iter = 1\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(M%2 == 1);\n        COMPILE_TIME_ASSERT(N%2 == 1);\n        DLIB_ASSERT(is_same_object(in_img,out_img) == false,\n            \"\\tvoid binary_close()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img) ,\n            \"\\tvoid binary_close()\"\n            << \"\\n\\tin_img must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(structuring_element) ,\n            \"\\tvoid binary_close()\"\n            << \"\\n\\tthe structuring_element must be a binary image\"\n            );\n\n\n        // if there isn't any input image then don't do anything\n        if (num_rows(in_img)*num_columns(in_img) == 0)\n        {\n            set_image_size(out_img, 0,0);\n            return;\n        }\n\n        set_image_size(out_img, num_rows(in_img), num_columns(in_img));\n\n        if (iter == 0)\n        {\n            // just copy the image over\n            assign_image(out_img, in_img);\n        }\n        else if (iter == 1)\n        {\n            in_image_type temp;\n            binary_dilation(in_img,temp,structuring_element);\n            binary_erosion(temp,out_img,structuring_element);\n        }\n        else\n        {\n            in_image_type temp1, temp2;\n            binary_dilation(in_img,temp1,structuring_element);\n\n            // do the extra dilations \n            for (unsigned long i = 1; i < iter; ++i)\n            {\n                swap(temp1, temp2);\n                binary_dilation(temp2,temp1,structuring_element);\n            }\n\n            // do the extra erosions \n            for (unsigned long i = 1; i < iter; ++i)\n            {\n                swap(temp1, temp2);\n                binary_erosion(temp2,temp1,structuring_element);\n            }\n\n            binary_erosion(temp1,out_img,structuring_element);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_intersection (\n        const in_image_type1& in_img1_,\n        const in_image_type2& in_img2_,\n        out_image_type& out_img_\n    )\n    {\n        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;\n        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img1_) ,\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(in_img2_) ,\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img2 must be a binary image\"\n            );\n\n        const_image_view<in_image_type1> in_img1(in_img1_);\n        const_image_view<in_image_type2> in_img2(in_img2_);\n        image_view<out_image_type> out_img(out_img_);\n\n        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same ncs.\"\n            << \"\\n\\tin_img1.nc(): \" << in_img1.nc()\n            << \"\\n\\tin_img2.nc(): \" << in_img2.nc()\n            );\n        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same nrs.\"\n            << \"\\n\\tin_img1.nr(): \" << in_img1.nr()\n            << \"\\n\\tin_img2.nr(): \" << in_img2.nr()\n            );\n            \n\n\n        // if there isn't any input image then don't do anything\n        if (in_img1.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img1.nr(),in_img1.nc());\n\n        for (long r = 0; r < in_img1.nr(); ++r)\n        {\n            for (long c = 0; c < in_img1.nc(); ++c)\n            {\n                if (in_img1[r][c] == on_pixel && in_img2[r][c] == on_pixel)\n                    assign_pixel(out_img[r][c], on_pixel);\n                else\n                    assign_pixel(out_img[r][c], off_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_union (\n        const in_image_type1& in_img1_,\n        const in_image_type2& in_img2_,\n        out_image_type& out_img_\n    )\n    {\n        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;\n        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img1_) ,\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(in_img2_) ,\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img2 must be a binary image\"\n            );\n\n        const_image_view<in_image_type1> in_img1(in_img1_);\n        const_image_view<in_image_type2> in_img2(in_img2_);\n        image_view<out_image_type> out_img(out_img_);\n\n        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same ncs.\"\n            << \"\\n\\tin_img1.nc(): \" << in_img1.nc()\n            << \"\\n\\tin_img2.nc(): \" << in_img2.nc()\n            );\n        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),\n            \"\\tvoid binary_intersection()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same nrs.\"\n            << \"\\n\\tin_img1.nr(): \" << in_img1.nr()\n            << \"\\n\\tin_img2.nr(): \" << in_img2.nr()\n            );\n            \n\n\n        // if there isn't any input image then don't do anything\n        if (in_img1.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img1.nr(),in_img1.nc());\n\n        for (long r = 0; r < in_img1.nr(); ++r)\n        {\n            for (long c = 0; c < in_img1.nc(); ++c)\n            {\n                if (in_img1[r][c] == on_pixel || in_img2[r][c] == on_pixel)\n                    assign_pixel(out_img[r][c], on_pixel);\n                else\n                    assign_pixel(out_img[r][c], off_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_difference (\n        const in_image_type1& in_img1_,\n        const in_image_type2& in_img2_,\n        out_image_type& out_img_\n    )\n    {\n        typedef typename image_traits<in_image_type1>::pixel_type in_pixel_type1;\n        typedef typename image_traits<in_image_type2>::pixel_type in_pixel_type2;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type1>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type2>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type1>::grayscale);\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type2>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img1_) ,\n            \"\\tvoid binary_difference()\"\n            << \"\\n\\tin_img1 must be a binary image\"\n            );\n        DLIB_ASSERT(is_binary_image(in_img2_) ,\n            \"\\tvoid binary_difference()\"\n            << \"\\n\\tin_img2 must be a binary image\"\n            );\n\n        const_image_view<in_image_type1> in_img1(in_img1_);\n        const_image_view<in_image_type2> in_img2(in_img2_);\n        image_view<out_image_type> out_img(out_img_);\n\n        DLIB_ASSERT(in_img1.nc() == in_img2.nc(),\n            \"\\tvoid binary_difference()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same ncs.\"\n            << \"\\n\\tin_img1.nc(): \" << in_img1.nc()\n            << \"\\n\\tin_img2.nc(): \" << in_img2.nc()\n            );\n        DLIB_ASSERT(in_img1.nr() == in_img2.nr(),\n            \"\\tvoid binary_difference()\"\n            << \"\\n\\tin_img1 and in_img2 must have the same nrs.\"\n            << \"\\n\\tin_img1.nr(): \" << in_img1.nr()\n            << \"\\n\\tin_img2.nr(): \" << in_img2.nr()\n            );\n            \n\n\n        // if there isn't any input image then don't do anything\n        if (in_img1.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img1.nr(),in_img1.nc());\n\n        for (long r = 0; r < in_img1.nr(); ++r)\n        {\n            for (long c = 0; c < in_img1.nc(); ++c)\n            {\n                if (in_img1[r][c] == on_pixel && in_img2[r][c] == off_pixel)\n                    assign_pixel(out_img[r][c], on_pixel);\n                else\n                    assign_pixel(out_img[r][c], off_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void binary_complement (\n        const in_image_type& in_img_,\n        out_image_type& out_img_\n    )\n    {\n        typedef typename image_traits<in_image_type>::pixel_type in_pixel_type;\n        typedef typename image_traits<out_image_type>::pixel_type out_pixel_type;\n        COMPILE_TIME_ASSERT( pixel_traits<in_pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<out_pixel_type>::has_alpha == false );\n\n\n        using namespace morphological_operations_helpers;\n        COMPILE_TIME_ASSERT(pixel_traits<in_pixel_type>::grayscale);\n        DLIB_ASSERT(is_binary_image(in_img_) ,\n            \"\\tvoid binary_complement()\"\n            << \"\\n\\tin_img must be a binary image\"\n            );\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                if (in_img[r][c] == on_pixel)\n                    assign_pixel(out_img[r][c], off_pixel);\n                else\n                    assign_pixel(out_img[r][c], on_pixel);\n            }\n        }\n    }\n\n    template <\n        typename image_type\n        >\n    void binary_complement (\n        image_type& img\n    )\n    {\n        binary_complement(img,img);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename image_type>\n        inline bool should_remove_pixel (\n            const image_type& img,\n            long r,\n            long c,\n            int iter\n        )\n        {\n            unsigned int p2 = img[r-1][c];\n            unsigned int p3 = img[r-1][c+1];\n            unsigned int p4 = img[r][c+1];\n            unsigned int p5 = img[r+1][c+1];\n            unsigned int p6 = img[r+1][c];\n            unsigned int p7 = img[r+1][c-1];\n            unsigned int p8 = img[r][c-1];\n            unsigned int p9 = img[r-1][c-1];\n\n            int A  = (p2 == 0 && p3 == 255) + (p3 == 0 && p4 == 255) + \n                (p4 == 0 && p5 == 255) + (p5 == 0 && p6 == 255) + \n                (p6 == 0 && p7 == 255) + (p7 == 0 && p8 == 255) +\n                (p8 == 0 && p9 == 255) + (p9 == 0 && p2 == 255);\n            int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;\n            int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);\n            int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);\n            // Decide if we should remove the pixel img[r][c].  \n            return (A == 1 && (B >= 2*255 && B <= 6*255) && m1 == 0 && m2 == 0);\n        }\n\n        template <typename image_type>\n        inline void add_to_remove (\n            std::vector<point>& to_remove,\n            array2d<unsigned char>& marker, \n            const image_type& img,\n            long r,\n            long c,\n            int iter\n        )\n        {\n            if (marker[r][c]&&should_remove_pixel(img,r,c,iter)) \n            {\n                to_remove.push_back(point(c,r));\n                marker[r][c] = 0;\n            }\n        }\n\n        template <typename image_type>\n        inline bool is_bw_border_pixel(\n            const image_type& img,\n            long r,\n            long c\n        )\n        {\n            unsigned int p2 = img[r-1][c];\n            unsigned int p3 = img[r-1][c+1];\n            unsigned int p4 = img[r][c+1];\n            unsigned int p5 = img[r+1][c+1];\n            unsigned int p6 = img[r+1][c];\n            unsigned int p7 = img[r+1][c-1];\n            unsigned int p8 = img[r][c-1];\n            unsigned int p9 = img[r-1][c-1];\n\n            int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;\n            // If you are on but at least one of your neighbors isn't.\n            return B<8*255 && img[r][c];\n\n        }\n\n        inline void add_if(\n            std::vector<point>& to_check2, \n            const array2d<unsigned char>& marker,\n            long c,\n            long r\n        )\n        {\n            if (marker[r][c])\n                to_check2.push_back(point(c,r));\n        }\n\n    } // end namespace impl\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void skeleton(\n        image_type& img_\n    )\n    {\n        /*\n            The implementation of this function is based on the paper\n            \"A fast parallel algorithm for thinning digital patterns\" by T.Y. Zhang and C.Y. Suen.\n            and also the excellent discussion of it at:\n            http://opencv-code.com/quick-tips/implementation-of-thinning-algorithm-in-opencv/\n        */\n\n        typedef typename image_traits<image_type>::pixel_type pixel_type;\n\n        // This function only works on grayscale images\n        COMPILE_TIME_ASSERT(pixel_traits<pixel_type>::grayscale);\n\n        using namespace impl;\n        // Note that it's important to zero the border for 2 reasons. First, it allows\n        // thinning to being at the border of the image.  But more importantly, it causes\n        // the mask to have a border of 0 pixels as well which we use later to avoid\n        // indexing outside the image inside add_to_remove().\n        zero_border_pixels(img_,1,1);\n        image_view<image_type> img(img_);\n\n        // We use the marker to keep track of pixels we have committed to removing but\n        // haven't yet removed from img.\n        array2d<unsigned char> marker(img.nr(), img.nc());\n        assign_image(marker, img);\n\n\n        // Begin by making a list of the pixels on the borders of binary blobs.\n        std::vector<point> to_remove, to_check, to_check2;\n        for (int r = 1; r < img.nr()-1; r++)\n        {\n            for (int c = 1; c < img.nc()-1; c++)\n            {\n                if (is_bw_border_pixel(img, r, c))\n                {\n                    to_check.push_back(point(c,r));\n                }\n            }\n        }\n\n        // Now start iteratively looking at the border pixels and removing them.\n        while(to_check.size() != 0)\n        {\n            for (int iter = 0; iter <= 1; ++iter)\n            {\n                // Check which pixels we should remove\n                to_remove.clear();\n                for (unsigned long i = 0; i < to_check.size(); ++i)\n                {\n                    long r = to_check[i].y();\n                    long c = to_check[i].x();\n                    add_to_remove(to_remove, marker, img, r, c, iter);\n                }\n                for (unsigned long i = 0; i < to_check2.size(); ++i)\n                {\n                    long r = to_check2[i].y();\n                    long c = to_check2[i].x();\n                    add_to_remove(to_remove, marker, img, r, c, iter);\n                }\n                // Now remove those pixels.  Also add their neighbors into the \"to check\"\n                // pixel list for the next iteration.\n                for (unsigned long i = 0; i < to_remove.size(); ++i)\n                {\n                    long r = to_remove[i].y();\n                    long c = to_remove[i].x();\n                    // remove the pixel\n                    img[r][c] = 0;\n                    add_if(to_check2, marker, c-1, r-1);\n                    add_if(to_check2, marker, c,   r-1);\n                    add_if(to_check2, marker, c+1, r-1);\n                    add_if(to_check2, marker, c-1, r);\n                    add_if(to_check2, marker, c+1, r);\n                    add_if(to_check2, marker, c-1, r+1);\n                    add_if(to_check2, marker, c,   r+1);\n                    add_if(to_check2, marker, c+1, r+1);\n                }\n            }\n            to_check.clear();\n            to_check.swap(to_check2);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    unsigned char encode_8_pixel_neighbors (\n        const const_image_view<image_type>& img,\n        const point& p\n    )\n    {\n        unsigned char ch = 0;\n\n        const rectangle area = get_rect(img);\n\n        auto check = [&](long r, long c) \n        {\n            ch <<= 1;\n            if (area.contains(c,r) && img[r][c]) \n                ch |= 1;\n        };\n\n        long r = p.y();\n        long c = p.x();\n\n        check(r-1,c-1);\n        check(r-1,c);\n        check(r-1,c+1);\n        check(r,c+1);\n        check(r+1,c+1);\n        check(r+1,c);\n        check(r+1,c-1);\n        check(r,c-1);\n\n        return ch;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_line_endpoints (\n        const image_type& img_\n    )\n    {\n        const_image_view<image_type> img(img_);\n\n        std::array<bool,256> line_ending_patterns;\n        line_ending_patterns.fill(false);\n        line_ending_patterns[0b00000001] = true;\n        line_ending_patterns[0b00000010] = true;\n        line_ending_patterns[0b00000100] = true;\n        line_ending_patterns[0b00001000] = true;\n        line_ending_patterns[0b00010000] = true;\n        line_ending_patterns[0b00100000] = true;\n        line_ending_patterns[0b01000000] = true;\n        line_ending_patterns[0b10000000] = true;\n        line_ending_patterns[0b00000011] = true;\n        line_ending_patterns[0b00000110] = true;\n        line_ending_patterns[0b00001100] = true;\n        line_ending_patterns[0b00011000] = true;\n        line_ending_patterns[0b00110000] = true;\n        line_ending_patterns[0b01100000] = true;\n        line_ending_patterns[0b11000000] = true;\n        line_ending_patterns[0b10000001] = true;\n\n\n        std::vector<point> results;\n\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                if (img[r][c] && line_ending_patterns[encode_8_pixel_neighbors(img,point(c,r))])\n                {\n                    results.emplace_back(c,r);\n                }\n            }\n        }\n\n        return results;\n    }\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MORPHOLOGICAL_OPERATIONs_\n\n"
  },
  {
    "path": "dlib/image_transforms/morphological_operations_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_\n#ifdef DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_\n\n#include \"../pixel.h\"\n#include \"thresholding_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_dilation (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N]\n    );\n    /*!\n        requires\n            - in_image_type and out_image_type are image objects that implement the\n              interface defined in dlib/image_processing/generic_image.h \n            - in_img must contain a grayscale pixel type.\n            - both in_img and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - is_same_object(in_img,out_img) == false\n            - M % 2 == 1  (i.e. M must be odd)\n            - N % 2 == 1  (i.e. N must be odd)\n            - all pixels in in_img are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n            - all pixels in structuring_element are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n        ensures\n            - Does a binary dilation of in_img using the given structuring element and \n              stores the result in out_img.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_erosion (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N]\n    );\n    /*!\n        requires\n            - in_image_type and out_image_type are image objects that implement the\n              interface defined in dlib/image_processing/generic_image.h \n            - in_img must contain a grayscale pixel type.\n            - both in_img and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - is_same_object(in_img,out_img) == false\n            - M % 2 == 1  (i.e. M must be odd)\n            - N % 2 == 1  (i.e. N must be odd)\n            - all pixels in in_img are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n            - all pixels in structuring_element are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n        ensures\n            - Does a binary erosion of in_img using the given structuring element and \n              stores the result in out_img.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_open (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N],\n        const unsigned long iter = 1\n    );\n    /*!\n        requires\n            - in_image_type and out_image_type are image objects that implement the\n              interface defined in dlib/image_processing/generic_image.h \n            - in_img must contain a grayscale pixel type.\n            - both in_img and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - is_same_object(in_img,out_img) == false\n            - M % 2 == 1  (i.e. M must be odd)\n            - N % 2 == 1  (i.e. N must be odd)\n            - all pixels in in_img are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n            - all pixels in structuring_element are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n        ensures\n            - Does a binary open of in_img using the given structuring element and \n              stores the result in out_img.  Specifically, iter iterations of binary \n              erosion are applied and then iter iterations of binary dilation.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        long M,\n        long N\n        >\n    void binary_close (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const unsigned char (&structuring_element)[M][N],\n        const unsigned long iter = 1\n    );\n    /*!\n        requires\n            - in_image_type and out_image_type are image objects that implement the\n              interface defined in dlib/image_processing/generic_image.h \n            - in_img must contain a grayscale pixel type.\n            - both in_img and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - is_same_object(in_img,out_img) == false\n            - M % 2 == 1  (i.e. M must be odd)\n            - N % 2 == 1  (i.e. N must be odd)\n            - all pixels in in_img are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n            - all pixels in structuring_element are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n        ensures\n            - Does a binary close of in_img using the given structuring element and \n              stores the result in out_img.  Specifically, iter iterations of binary \n              dilation are applied and then iter iterations of binary erosion.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_intersection (\n        const in_image_type1& in_img1,\n        const in_image_type2& in_img2,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type1, in_image_type2, and out_image_type are image objects that\n              implement the interface defined in dlib/image_processing/generic_image.h \n            - in_img1 and in_img2 must contain grayscale pixel types.\n            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel\n              (i.e. they must be binary images)\n            - in_img1.nc() == in_img2.nc()\n            - in_img1.nr() == in_img2.nr()\n        ensures\n            - #out_img == the binary intersection of in_img1 and in_img2.  (i.e. All\n              the pixels that are set to on_pixel in both in_img1 and in_img2 will be set\n              to on_pixel in #out_img.  All other pixels will be set to off_pixel)\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_union (\n        const in_image_type1& in_img1,\n        const in_image_type2& in_img2,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type1, in_image_type2, and out_image_type are image objects that\n              implement the interface defined in dlib/image_processing/generic_image.h \n            - in_img1 and in_img2 must contain grayscale pixel types.\n            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel\n              (i.e. they must be binary images)\n            - in_img1.nc() == in_img2.nc()\n            - in_img1.nr() == in_img2.nr()\n        ensures\n            - #out_img == the binary union of in_img1 and in_img2.  (i.e. All\n              the pixels that are set to on_pixel in in_img1 and/or in_img2 will be set\n              to on_pixel in #out_img.  All other pixels will be set to off_pixel)\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type1,\n        typename in_image_type2,\n        typename out_image_type\n        >\n    void binary_difference (\n        const in_image_type1& in_img1,\n        const in_image_type2& in_img2,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type1, in_image_type2, and out_image_type are image objects that\n              implement the interface defined in dlib/image_processing/generic_image.h \n            - in_img1 and in_img2 must contain grayscale pixel types.\n            - in_img1, in_img2, and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - all pixels in in_img1 and in_img2 are set to either on_pixel or off_pixel\n              (i.e. they must be binary images)\n            - in_img1.nc() == in_img2.nc()\n            - in_img1.nr() == in_img2.nr()\n        ensures\n            - #out_img == the binary difference of in_img1 and in_img2.  (i.e. #out_img\n              will be a copy of in_img1 except that any pixels in in_img2 that are set to \n              on_pixel will be set to off_pixel)\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void binary_complement (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type and out_image_type are image objects that implement the\n              interface defined in dlib/image_processing/generic_image.h \n            - in_img must contain a grayscale pixel type.\n            - both in_img and out_img must contain pixels with no alpha channel.\n              (i.e. pixel_traits::has_alpha==false for their pixels)\n            - all pixels in in_img are set to either on_pixel or off_pixel\n              (i.e. it must be a binary image)\n        ensures\n            - #out_img == the binary complement of in_img.  (i.e. For each pixel in\n              in_img, if it is on_pixel then it will be set to off_pixel in #out_img and\n              if it was off_pixel in in_img then it will be on_pixel in #out_img)\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n    template <\n        typename image_type\n        >\n    void binary_complement (\n        image_type& img\n    );\n    /*!\n        requires\n            - it must be valid to call binary_complement(img,img);\n        ensures\n            - calls binary_complement(img,img);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void skeleton(\n        image_type& img\n    );\n    /*!\n        requires\n            - image_type is an object that implement the interface defined in\n              dlib/image_processing/generic_image.h \n            - img must contain a grayscale pixel type.\n            - all pixels in img are set to either on_pixel or off_pixel.\n              (i.e. it must be a binary image)\n        ensures\n            - This function computes the skeletonization of img and stores the result in\n              #img.  That is, given a binary image, we progressively thin the binary blobs\n              (composed of on_pixel values) until only a single pixel wide skeleton of the\n              original blobs remains.\n            - #img.nc() == img.nc()\n            - #img.nr() == img.nr()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    unsigned char encode_8_pixel_neighbors (\n        const const_image_view<image_type>& img,\n        const point& p\n    );\n    /*!\n        requires\n            - image_type is an object that implement the interface defined in\n              dlib/image_processing/generic_image.h \n            - img must contain a grayscale pixel type.\n            - all pixels in img are set to either on_pixel or off_pixel.\n              (i.e. it must be a binary image)\n            - get_rect(img).contains(p) == true\n        ensures\n            - This routine looks at the 8 pixels immediately surrounding the pixel\n              img[p.y()][p.x()] and encodes their on/off pattern into the bits of an\n              unsigned char and returns it.  To be specific, the neighbors are read\n              clockwise starting from the upper left and written to the unsigned char\n              starting with the high order bits.  Therefore, the mapping between\n              neighboring pixels to bits is:\n                 7 6 5\n                 0   4\n                 1 2 3\n              Where 0 refers to the lowest order bit in the unsigned char and 7 to the\n              highest order bit.  Finally, a bit in the unsigned char is 1 if and only if\n              the corresponding pixel is on_pixel.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    std::vector<point> find_line_endpoints (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type is an object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - img must contain a grayscale pixel type.\n            - all pixels in img are set to either on_pixel or off_pixel.\n              (i.e. it must be a binary image)\n        ensures\n            - This routine finds endpoints of lines in a thinned binary image.  For\n              example, if the image was produced by skeleton() or something like a Canny\n              edge detector then you can use find_line_endpoints() to find the pixels\n              sitting on the ends of lines.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MORPHOLOGICAL_OPERATIONs_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/random_color_transform.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANDOM_cOLOR_TRANSFORM_Hh_\n#define DLIB_RANDOM_cOLOR_TRANSFORM_Hh_\n\n#include \"random_color_transform_abstract.h\"\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include \"../rand.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class color_transform\n    {\n    public:\n        color_transform(\n            const double gamma_ = 1,\n            const double red_scale_ = 1,\n            const double green_scale_ = 1,\n            const double blue_scale_ = 1\n        ) : gamma(gamma_), red_scale(red_scale_), green_scale(green_scale_), blue_scale(blue_scale_)\n        {\n            DLIB_CASSERT(gamma_ >= 0)\n            DLIB_CASSERT(0 <= red_scale_ && red_scale_ <= 1)\n            DLIB_CASSERT(0 <= green_scale_ && green_scale_ <= 1)\n            DLIB_CASSERT(0 <= blue_scale_ && blue_scale_ <= 1)\n            const double m = 255 * std::max({red_scale_, green_scale_, blue_scale_});\n            red_scale /= m;\n            green_scale /= m;\n            blue_scale /= m;\n            // Now compute a lookup table for all the color channels.  The table tells us\n            // what the transform does.\n            table.resize(256 * 3);\n            unsigned long i = 0;\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(255 * std::pow(k * red_scale, gamma) + 0.5);\n            }\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(255 * std::pow(k * green_scale, gamma) + 0.5);\n            }\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(255 * std::pow(k * blue_scale, gamma) + 0.5);\n            }\n        }\n\n        rgb_pixel operator()(rgb_pixel p) const\n        {\n            p.red = table[static_cast<unsigned int>(p.red)];\n            p.green = table[static_cast<unsigned int>(p.green + 256)];\n            p.blue = table[static_cast<unsigned int>(p.blue + 512)];\n            return p;\n        }\n\n        double get_gamma() const { return gamma; }\n        double get_red_scale() const { return red_scale; }\n        double get_green_scale() const { return green_scale; }\n        double get_blue_scale() const { return blue_scale; }\n\n    private:\n        std::vector<unsigned char> table;\n        double gamma;\n        double red_scale;\n        double green_scale;\n        double blue_scale;\n    };\n\n    class inv_color_transform\n    {\n    public:\n        inv_color_transform(\n            const color_transform& tform\n        )\n        {\n            const auto gamma = tform.get_gamma();\n            const auto red_scale = tform.get_red_scale();\n            const auto green_scale = tform.get_green_scale();\n            const auto blue_scale = tform.get_blue_scale();\n\n            // Now compute a lookup table for all the color channels.  The table tells us\n            // what the transform does.\n            table.resize(256 * 3);\n            unsigned long i = 0;\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(std::pow(k / 255.0, 1 / gamma) / red_scale + 0.5);\n            }\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(std::pow(k / 255.0, 1 / gamma) / green_scale + 0.5);\n            }\n            for (int k = 0; k < 256; ++k)\n            {\n                table[i++] = static_cast<unsigned char>(std::pow(k / 255.0, 1 / gamma) / blue_scale + 0.5);\n            }\n        }\n\n        rgb_pixel operator()(rgb_pixel p) const\n        {\n            p.red = table[static_cast<unsigned int>(p.red)];\n            p.green = table[static_cast<unsigned int>(p.green + 256)];\n            p.blue = table[static_cast<unsigned int>(p.blue + 512)];\n            return p;\n        }\n\n    private:\n        std::vector<unsigned char> table;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline color_transform random_color_transform (\n            dlib::rand& rnd,\n            const double gamma_magnitude = 0.5,\n            const double color_magnitude = 0.2\n    )\n    {\n        // pick a random gamma correction factor.\n        const double gamma = std::max(0.0, 1 + gamma_magnitude * (rnd.get_random_double() - 0.5));\n        // pick a random color balancing scheme.\n        const double red_scale = 1 - rnd.get_random_double() * color_magnitude;\n        const double green_scale = 1 - rnd.get_random_double() * color_magnitude;\n        const double blue_scale = 1 - rnd.get_random_double() * color_magnitude;\n        return color_transform(gamma, red_scale, green_scale, blue_scale);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    color_transform disturb_colors (\n        image_type& img_,\n        dlib::rand& rnd,\n        const double gamma_magnitude = 0.5,\n        const double color_magnitude = 0.2\n    )\n    {\n        if (gamma_magnitude == 0 && color_magnitude == 0)\n            return {};\n\n        image_view<image_type> img(img_);\n        const auto tform = random_color_transform(rnd, gamma_magnitude, color_magnitude);\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                rgb_pixel temp;\n                assign_pixel(temp, img[r][c]);\n                temp = tform(temp);\n                assign_pixel(img[r][c], temp);\n            }\n        }\n        return tform;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void apply_random_color_offset (\n        image_type& img_,\n        dlib::rand& rnd\n    )\n    {\n        // Make a random color offset.  This tform matrix came from looking at the\n        // covariance matrix of RGB values in a bunch of images.  In particular, if you\n        // multiply Gaussian random vectors by tform it will result in vectors with the\n        // same covariance matrix as the original RGB data.  Also, this color transform is\n        // what is suggested by the paper:\n        //  Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. \"Imagenet\n        //  classification with deep convolutional neural networks.\" Advances in neural\n        //  information processing systems. 2012.\n        // Except that we used the square root of the eigenvalues (which I'm pretty sure is\n        // what the authors intended).\n        matrix<double,3,3> tform;\n        tform = -66.379,    25.094,   6.79698,\n                -68.0492, -0.302309,  -13.9539,\n                -68.4907,  -24.0199,   7.27653;\n        matrix<double,3,1> v;\n        v = rnd.get_random_gaussian(),rnd.get_random_gaussian(),rnd.get_random_gaussian();\n        v = round(tform*0.1*v);\n        const int roffset = v(0);\n        const int goffset = v(1);\n        const int boffset = v(2);\n\n        // Make up lookup tables that apply the color mapping so we don't have to put a\n        // bunch of complicated conditional branches in the loop below.\n        unsigned char rtable[256];\n        unsigned char gtable[256];\n        unsigned char btable[256];\n        for (int i = 0; i < 256; ++i)\n        {\n            rtable[i] = put_in_range(0, 255, i+roffset);\n            gtable[i] = put_in_range(0, 255, i+goffset);\n            btable[i] = put_in_range(0, 255, i+boffset);\n        }\n\n        // now transform the image.\n        image_view<image_type> img(img_);\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                rgb_pixel temp;\n                assign_pixel(temp, img[r][c]);\n                temp.red   = rtable[temp.red];\n                temp.green = gtable[temp.green];\n                temp.blue  = btable[temp.blue];\n                assign_pixel(img[r][c], temp);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANDOM_cOLOR_TRANSFORM_Hh_\n"
  },
  {
    "path": "dlib/image_transforms/random_color_transform_abstract.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_\n#ifdef DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_\n\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class color_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object generates a color balancing and gamma correction transform.\n                It then allows you to apply that specific transform to as many\n                rgb_pixel objects as you like.\n        !*/\n\n    public:\n\n        color_transform (\n            const double gamma = 1.0,\n            const double red_scale = 1.0,\n            const double green_scale = 1.0,\n            const double blue_scale = 1.0\n        );\n        /*!\n            requires\n                - 0 <= gamma\n                - 0 <= red_scale <= 1\n                - 0 <= green_scale <= 1\n                - 0 <= blue_scale <= 1\n            ensures\n                - This constructor generates a color transform which can be applied by\n                  calling this object's operator() method.\n                - The color transform is a gamma correction and color rebalancing.  If\n                  gamma == 1, red_scale == 1, green_scale == 1 and blue_scale == 1 then\n                  the transform doesn't change any colors at all.  However, the farther\n                  away from 1 these parameters are, the more noticeable the resulting\n                  transform.\n        !*/\n\n        rgb_pixel operator()(\n            rgb_pixel p\n        ) const;\n        /*!\n            ensures\n                - returns the color transformed version of p.\n        !*/\n\n        double get_gamma() const;\n        /*!\n            ensures\n                - returns the gamma used in this color transform.\n        !*/\n\n        double get_red_scale() const;\n        /*!\n            ensures\n                - returns the red scale used in this color transform.\n        !*/\n\n        double get_green_scale() const;\n        /*!\n            ensures\n                - returns the green scale used in this color transform.\n        !*/\n\n        double get_blue_scale() const;\n        /*!\n            ensures\n                - returns the blue scale used in this color transform.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class inv_color_transform\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object generates a color balancing and gamma correction transform.\n                It then allows you to apply that specific transform to as many\n                rgb_pixel objects as you like. In particular, it generates the inverse\n                transform of the one passed as an argument to the constructor.\n        !*/\n\n    public:\n\n        inv_color_transform (\n            const color_transform& tform\n        );\n        /*!\n            ensures\n                - This constructor generates a color transform which can be applied by\n                  calling this object's operator() method.\n                - The resulting transform is the inverse of tform, which can be used to\n                  undo the effect of tform.\n        !*/\n\n        rgb_pixel operator()(\n            rgb_pixel p\n        ) const;\n        /*!\n            ensures\n                - returns the color transformed version of p.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline color_transform random_color_transform (\n            dlib::rand& rnd,\n            const double gamma_magnitude = 0.5,\n            const double color_magnitude = 0.2\n    );\n    /*!\n        ensures\n            - returns a random color balancing and gamma corection transform.  It then\n              allows you to apply that specific transform to as many rgb_pixel objects as\n              you like.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    color_transform disturb_colors (\n        image_type& img,\n        dlib::rand& rnd,\n        const double gamma_magnitude = 0.5,\n        const double color_magnitude = 0.2\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h\n        ensures\n            - Applies a random color transform to the given image.  This is done by\n              creating a random_color_transform with the given parameters and then\n              transforming each pixel in the image with the resulting transform.\n            - Returns the color transform used to transform the given image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    void apply_random_color_offset (\n        image_type& img,\n        dlib::rand& rnd\n    );\n    /*!\n        ensures\n            - Picks a random color offset vector and adds it to the given image.  The offset\n              vector is selected using the method described in the paper:\n                Krizhevsky, Alex, Ilya Sutskever, and Geoffrey E. Hinton. \"Imagenet\n                classification with deep convolutional neural networks.\" Advances in neural\n                information processing systems. 2012.\n              In particular, we sample an RGB value from the typical distribution of RGB\n              values, assuming it has a Gaussian distribution, and then divide it by 10.\n              This sampled RGB vector is added to each pixel of img.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_RANDOM_cOLOR_TRANSFORM_ABSTRACT_Hh_\n"
  },
  {
    "path": "dlib/image_transforms/random_cropper.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RaNDOM_CROPPER_H_\n#define DLIB_RaNDOM_CROPPER_H_\n\n#include \"random_cropper_abstract.h\"\n#include \"../threads.h\"\n#include <mutex>\n#include <vector>\n#include \"interpolation.h\"\n#include \"../image_processing/full_object_detection.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n    class random_cropper\n    {\n        chip_dims dims = chip_dims(300,300);\n        bool randomly_flip = true;\n        double max_rotation_degrees = 30;\n        long min_object_length_long_dim = 75; // cropped object will be at least this many pixels along its longest edge.\n        long min_object_length_short_dim = 30; // cropped object will be at least this many pixels along its shortest edge.\n        double max_object_size = 0.7; // cropped object will be at most this fraction of the size of the image.\n        double background_crops_fraction = 0.5;\n        double translate_amount = 0.10;\n        double min_object_coverage = 1.0;\n\n        std::mutex rnd_mutex;\n        dlib::rand rnd;\n    public:\n\n        void set_seed (\n            time_t seed\n        ) { rnd = dlib::rand(seed); }\n\n        double get_translate_amount (\n        ) const { return translate_amount; }\n\n        void set_translate_amount (\n            double value\n        )  \n        { \n            DLIB_CASSERT(0 <= value);\n            translate_amount = value;\n        }\n\n        double get_background_crops_fraction (\n        ) const { return background_crops_fraction; }\n\n        void set_background_crops_fraction (\n            double value\n        )\n        {\n            DLIB_CASSERT(0 <= value && value <= 1);\n            background_crops_fraction = value;\n        }\n\n        const chip_dims& get_chip_dims(\n        ) const { return dims; }\n\n        void set_chip_dims (\n            const chip_dims& dims_\n        ) { dims = dims_; }\n\n        void set_chip_dims (\n            unsigned long rows,\n            unsigned long cols\n        ) { set_chip_dims(chip_dims(rows,cols)); }\n\n        bool get_randomly_flip (\n        ) const { return randomly_flip; }\n\n        void set_randomly_flip (\n            bool value\n        ) { randomly_flip = value; }\n\n        double get_max_rotation_degrees (\n        ) const { return max_rotation_degrees; }\n        void set_max_rotation_degrees (\n            double value\n        ) { max_rotation_degrees = std::abs(value); }\n\n        long get_min_object_length_long_dim (\n        ) const { return min_object_length_long_dim; }\n        long get_min_object_length_short_dim (\n        ) const { return min_object_length_short_dim; }\n\n        void set_min_object_size (\n            long long_dim,\n            long short_dim\n        ) \n        { \n            DLIB_CASSERT(0 < short_dim && short_dim <= long_dim);\n            min_object_length_long_dim = long_dim; \n            min_object_length_short_dim = short_dim; \n        }\n\n        double get_max_object_size (\n        ) const { return max_object_size; }\n        void set_max_object_size (\n            double value\n        ) \n        { \n            DLIB_CASSERT(0 < value);\n            max_object_size = value; \n        }\n\n        double get_min_object_coverage (\n        ) const { return min_object_coverage; }\n        void set_min_object_coverage (\n            double value\n        )\n        {\n            DLIB_CASSERT(0 < value && value <= 1);\n            min_object_coverage = value;\n        }\n\n        template <\n            typename array_type,\n            typename rectangle_type\n            >\n        void operator() (\n            size_t num_crops,\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            array_type& crops,\n            std::vector<std::vector<rectangle_type>>& crop_rects\n        )\n        {\n            DLIB_CASSERT(images.size() == rects.size());\n            crops.clear();\n            crop_rects.clear();\n            append(num_crops, images, rects, crops, crop_rects);\n        }\n\n        template <\n            typename array_type,\n            typename rectangle_type\n            >\n        void append (\n            size_t num_crops,\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            array_type& crops,\n            std::vector<std::vector<rectangle_type>>& crop_rects\n        )\n        {\n            DLIB_CASSERT(images.size() == rects.size());\n            DLIB_CASSERT(crops.size() == crop_rects.size());\n            auto original_size = crops.size();\n            crops.resize(crops.size()+num_crops);\n            crop_rects.resize(crop_rects.size()+num_crops);\n            parallel_for(original_size, original_size+num_crops, [&](long i) {\n                (*this)(images, rects, crops[i], crop_rects[i]);\n            });\n        }\n\n\n        template <\n            typename array_type,\n            typename image_type,\n            typename rectangle_type\n            >\n        void operator() (\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            image_type& crop,\n            std::vector<rectangle_type>& crop_rects\n        )\n        {\n            DLIB_CASSERT(images.size() == rects.size());\n            size_t idx;\n            { std::lock_guard<std::mutex> lock(rnd_mutex);\n                idx = rnd.get_integer(images.size());\n            }\n            (*this)(images[idx], rects[idx], crop, crop_rects);\n        }\n\n        template <\n            typename image_type1,\n            typename rectangle_type\n            >\n        image_type1 operator() (\n            const image_type1& img\n        )\n        {\n            image_type1 crop;\n            std::vector<rectangle_type> junk1, junk2;\n            (*this)(img, junk1, crop, junk2);\n            return crop;\n        }\n\n        template <\n            typename image_type1,\n            typename image_type2,\n            typename rectangle_type\n            >\n        void operator() (\n            const image_type1& img,\n            const std::vector<rectangle_type>& rects,\n            image_type2& crop,\n            std::vector<rectangle_type>& crop_rects\n        )\n        {\n            DLIB_CASSERT(num_rows(img)*num_columns(img) != 0);\n            chip_details crop_plan;\n            bool should_flip_crop;\n            make_crop_plan(img, rects, crop_plan, should_flip_crop);\n\n            extract_image_chip(img, crop_plan, crop);\n            const rectangle_transform tform = get_mapping_to_chip(crop_plan);\n\n            // copy rects into crop_rects and set ones that are outside the crop to ignore or\n            // drop entirely as appropriate.\n            crop_rects.clear();\n            for (auto rect : rects)\n            {\n                // map to crop\n                rect.rect = tform(rect.rect);\n\n                const double intersection = get_rect(crop).intersect(rect.rect).area();\n\n                // if the rect is at least partly in the crop\n                if (intersection != 0)\n                {\n                    // set to ignore if not totally in the crop or if too small.\n                    if (intersection / rect.rect.area() < min_object_coverage ||\n                        ((long)rect.rect.height() < min_object_length_long_dim  && (long)rect.rect.width() < min_object_length_long_dim) ||\n                        ((long)rect.rect.height() < min_object_length_short_dim || (long)rect.rect.width() < min_object_length_short_dim))\n                    {\n                        rect.ignore = true;\n                    }\n\n                    crop_rects.push_back(rect);\n                }\n            }\n\n            // Also randomly flip the image\n            if (should_flip_crop)\n            {\n                image_type2 temp;\n                flip_image_left_right(crop, temp); \n                swap(crop,temp);\n                for (auto&& rect : crop_rects)\n                    rect.rect = impl::flip_rect_left_right(rect.rect, get_rect(crop));\n            }\n        }\n\n    private:\n\n        template <\n            typename image_type1,\n            typename rectangle_type\n            >\n        void make_crop_plan (\n            const image_type1& img,\n            const std::vector<rectangle_type>& rects,\n            chip_details& crop_plan,\n            bool& should_flip_crop\n        )\n        {\n            std::lock_guard<std::mutex> lock(rnd_mutex);\n            rectangle crop_rect;\n            if (has_non_ignored_box(rects) && rnd.get_random_double() >= background_crops_fraction)\n            {\n                auto rect = rects[randomly_pick_rect(rects)].rect;\n\n                // perturb the location of the crop by a small fraction of the object's size.\n                const point rand_translate = dpoint(rnd.get_double_in_range(-translate_amount,translate_amount)*std::max(rect.height(),rect.width()), \n                                                    rnd.get_double_in_range(-translate_amount,translate_amount)*std::max(rect.height(),rect.width()));\n\n                // We are going to grow rect into the cropping rect.  First, we grow it a\n                // little so that it has the desired minimum border around it.  \n                drectangle drect = centered_drect(center(rect)+rand_translate, rect.width()/max_object_size, rect.height()/max_object_size);\n\n                // Now make rect have the same aspect ratio as dims so that there won't be\n                // any funny stretching when we crop it.  We do this by growing it along\n                // whichever dimension is too short.\n                const double target_aspect = dims.cols/(double)dims.rows;\n                if (drect.width()/drect.height() < target_aspect)\n                    drect = centered_drect(drect, target_aspect*drect.height(), drect.height());\n                else \n                    drect = centered_drect(drect, drect.width(), drect.width()/target_aspect);\n\n                // Now perturb the scale of the crop.  We do this by shrinking it, but not\n                // so much that it gets smaller than the min object sizes require. \n                double current_width = dims.cols*rect.width()/drect.width();\n                double current_height = dims.rows*rect.height()/drect.height();\n\n                // never make any dimension smaller than the short dim.\n                double min_scale1 = std::max(min_object_length_short_dim/current_width, min_object_length_short_dim/current_height);\n                // at least one dimension needs to be longer than the long dim.\n                double min_scale2 = std::min(min_object_length_long_dim/current_width, min_object_length_long_dim/current_height);\n                double min_scale = std::max(min_scale1, min_scale2); \n\n                const double rand_scale_perturb = 1.0/rnd.get_double_in_range(min_scale, 1); \n                crop_rect = centered_drect(drect, drect.width()*rand_scale_perturb, drect.height()*rand_scale_perturb);\n\n            }\n            else\n            {\n                crop_rect = make_random_cropping_rect(img);\n            }\n            should_flip_crop = randomly_flip && rnd.get_random_double() > 0.5;\n            const double angle = rnd.get_double_in_range(-max_rotation_degrees, max_rotation_degrees)*pi/180;\n            crop_plan = chip_details(crop_rect, dims, angle);\n        }\n\n        template <typename rectangle_type>\n        bool has_non_ignored_box (\n            const std::vector<rectangle_type>& rects\n        ) const\n        {\n            for (auto&& b : rects)\n            {\n                if (!b.ignore)\n                    return true;\n            }\n            return false;\n        }\n\n        template <typename rectangle_type>\n        size_t randomly_pick_rect (\n            const std::vector<rectangle_type>& rects\n        ) \n        {\n            DLIB_CASSERT(has_non_ignored_box(rects));\n            size_t idx = rnd.get_integer(rects.size());\n            while(rects[idx].ignore)\n                idx = rnd.get_integer(rects.size());\n            return idx;\n        }\n\n        template <typename image_type>\n        rectangle make_random_cropping_rect(\n            const image_type& img_\n        )\n        {\n            const_image_view<image_type> img(img_);\n            // Figure out what rectangle we want to crop from the image.  We are going to\n            // crop out an image of size this->dims, so we pick a random scale factor that\n            // lets this random box be either as big as it can be while still fitting in\n            // the image or as small as a 3x zoomed in box randomly somewhere in the image. \n            double mins = 1.0/3.0, maxs = std::min(img.nr()/(double)dims.rows, img.nc()/(double)dims.cols);\n            mins = std::min(mins, maxs);\n            auto scale = rnd.get_double_in_range(mins, maxs);\n            rectangle rect(scale*dims.cols, scale*dims.rows);\n            // randomly shift the box around\n            point offset(rnd.get_integer(1+img.nc()-rect.width()),\n                         rnd.get_integer(1+img.nr()-rect.height()));\n            return move_rect(rect, offset);\n        }\n\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline std::ostream& operator<< (\n        std::ostream& out,\n        const random_cropper& item\n    )\n    {\n        using std::endl;\n        out << \"random_cropper details: \" << endl;\n        out << \"  chip_dims.rows:              \" << item.get_chip_dims().rows << endl;\n        out << \"  chip_dims.cols:              \" << item.get_chip_dims().cols << endl;\n        out << \"  randomly_flip:               \" << std::boolalpha << item.get_randomly_flip() << endl;\n        out << \"  max_rotation_degrees:        \" << item.get_max_rotation_degrees() << endl;\n        out << \"  min_object_length_long_dim:  \" << item.get_min_object_length_long_dim() << endl;\n        out << \"  min_object_length_short_dim: \" << item.get_min_object_length_short_dim() << endl;\n        out << \"  max_object_size:             \" << item.get_max_object_size() << endl;\n        out << \"  background_crops_fraction:   \" << item.get_background_crops_fraction() << endl;\n        out << \"  translate_amount:            \" << item.get_translate_amount() << endl;\n        return out;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RaNDOM_CROPPER_H_\n\n"
  },
  {
    "path": "dlib/image_transforms/random_cropper_abstract.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RaNDOM_CROPPER_ABSTRACT_H_\n#ifdef DLIB_RaNDOM_CROPPER_ABSTRACT_H_\n\n#include \"../threads.h\"\n#include <mutex>\n#include <vector>\n#include \"interpolation.h\"\n#include \"../image_processing/full_object_detection.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n    class random_cropper\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for extracting random crops of objects from a set of\n                images.  The crops are randomly jittered in scale, translation, and\n                rotation but more or less centered on objects specified by mmod_rect\n                objects (or other rectangle types with a compatible interface).\n\n            THREAD SAFETY\n                It is safe for multiple threads to make concurrent calls to this object's\n                operator() methods.\n        !*/\n\n    public:\n\n        random_cropper (\n        );\n        /*!\n            ensures\n                - #get_chip_dims() == chip_dims(300,300)\n                - #get_randomly_flip() == true\n                - #get_max_rotation_degrees() == 30\n                - #get_min_object_length_long_dim() == 70 \n                - #get_min_object_length_short_dim() == 30\n                - #get_max_object_size() == 0.7\n                - #get_background_crops_fraction() == 0.5\n                - #get_translate_amount() == 0.1\n                - #get_min_object_coverage == 1.0\n        !*/\n\n        void set_seed (\n            time_t seed\n        );\n        /*!\n            ensures\n                - Seeds the internal random number generator with the given seed.\n        !*/\n\n        double get_translate_amount (\n        ) const; \n        /*!\n            ensures\n                - When a box is cropped out, it will be randomly translated prior to\n                  cropping by #get_translate_amount()*(the box's height) up or down and\n                  #get_translate_amount()*(the box's width) left or right.\n        !*/\n\n        void set_translate_amount (\n            double value\n        );\n        /*!\n            requires\n                - value >= 0\n            ensures\n                - #get_translate_amount() == value\n        !*/\n\n        double get_background_crops_fraction (\n        ) const; \n        /*!\n            ensures\n                - When making random crops, get_background_crops_fraction() fraction of\n                  them will be from random background rather than being centered on some\n                  object in the dataset.\n        !*/\n\n        void set_background_crops_fraction (\n            double value\n        );\n        /*!\n            requires\n                - 0 <= value <= 1\n            ensures\n                - #get_background_crops_fraction() == value\n        !*/\n\n        const chip_dims& get_chip_dims(\n        ) const; \n        /*!\n            ensures\n                - returns the dimensions of image chips produced by this object.\n        !*/\n\n        void set_chip_dims (\n            const chip_dims& dims\n        );\n        /*!\n            ensures\n                - #get_chip_dims() == dims\n        !*/\n\n        void set_chip_dims (\n            unsigned long rows,\n            unsigned long cols\n        );\n        /*!\n            ensures\n                - #get_chip_dims() == chip_dims(rows,cols)\n        !*/\n\n        bool get_randomly_flip (\n        ) const;\n        /*!\n            ensures\n                - if this object will randomly mirror chips left to right.\n        !*/\n\n        void set_randomly_flip (\n            bool value\n        );\n        /*!\n            ensures\n                - #get_randomly_flip() == value\n        !*/\n\n        double get_max_rotation_degrees (\n        ) const;\n        /*!\n            ensures\n                - When extracting an image chip, this object will pick a random rotation\n                  in the range [-get_max_rotation_degrees(), get_max_rotation_degrees()]\n                  and rotate the chip by that amount.\n        !*/\n\n        void set_max_rotation_degrees (\n            double value\n        );\n        /*!\n            ensures\n                - #get_max_rotation_degrees() == std::abs(value)\n        !*/\n\n        long get_min_object_length_long_dim (\n        ) const; \n        /*!\n            ensures\n                - When a chip is extracted around an object, the chip will be sized so that\n                  the longest edge of the object (i.e. either its height or width,\n                  whichever is longer) is at least #get_min_object_length_long_dim() pixels\n                  in length.  When we say \"object\" here we are referring specifically to\n                  the rectangle in the rectangle_type output by the cropper.\n        !*/\n\n        long get_min_object_length_short_dim (\n        ) const;\n        /*!\n            ensures\n                - When a chip is extracted around an object, the chip will be sized so that\n                  the shortest edge of the object (i.e. either its height or width,\n                  whichever is shorter) is at least #get_min_object_length_short_dim()\n                  pixels in length.  When we say \"object\" here we are referring\n                  specifically to the rectangle in the rectangle_type output by the cropper.\n        !*/\n\n        void set_min_object_size (\n            long long_dim,\n            long short_dim\n        ); \n        /*!\n            requires\n                - 0 < short_dim <= long_dim\n            ensures\n                - #get_min_object_length_short_dim() == short_dim\n                - #get_min_object_length_long_dim() == long_dim\n        !*/\n\n        double get_max_object_size (\n        ) const; \n        /*!\n            ensures\n                - When a chip is extracted around an object, the chip will be sized so that\n                  both the object's height and width are at most get_max_object_size() *\n                  the chip's height and width, respectively.  E.g. if the chip is 640x480\n                  pixels in size then the object will be at most 480*get_max_object_size()\n                  pixels tall and 640*get_max_object_size() pixels wide. \n        !*/\n\n        void set_max_object_size (\n            double value\n        ); \n        /*!\n            requires\n                - 0 < value \n            ensures\n                - #get_max_object_size() == value\n        !*/\n\n        double get_min_object_coverage (\n        ) const;\n        /*!\n            ensures\n                - When a chip is extracted, any object that has less than get_min_object_coverage() fraction of its \n                   total area contained within the crop will have its ignore field set to true.\n        !*/\n\n        void set_min_object_coverage (\n            double value\n        );\n        /*!\n            requires\n                - 0 < value <= 1\n            ensures\n                - #get_min_object_coverage() == value\n        !*/\n\n        template <\n            typename array_type,\n            typename rectangle_type\n            >\n        void append (\n            size_t num_crops,\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            array_type& crops,\n            std::vector<std::vector<rectangle_type>>& crop_rects\n        );\n        /*!\n            requires\n                - images.size() == rects.size()\n                - crops.size() == crop_rects.size()\n                - for all valid i:\n                    - images[i].size() != 0\n                - array_type is a type with an interface compatible with dlib::array or\n                  std::vector and it must in turn contain image objects that implement the\n                  interface defined in dlib/image_processing/generic_image.h \n                - rectangle_type is a type with an interface compatible with mmod_rect, such\n                  as yolo_rect.\n            ensures\n                - Randomly extracts num_crops chips from images and appends them to the end\n                  of crops.  We also copy the object metadata for each extracted crop and\n                  store it into #crop_rects.  In particular, calling this function is the\n                  same as making multiple calls to the version of operator() below that\n                  outputs a single crop, except that append() will use multiple CPU cores\n                  to do the processing and is therefore faster.\n                - #crops.size() == crops.size()+num_crops\n                - #crop_rects.size() == crop_rects.size()+num_crops\n        !*/\n\n        template <\n            typename array_type,\n            typename rectangle_type\n            >\n        void operator() (\n            size_t num_crops,\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            array_type& crops,\n            std::vector<std::vector<rectangle_type>>& crop_rects\n        );\n        /*!\n            requires\n                - images.size() == rects.size()\n                - for all valid i:\n                    - images[i].size() != 0\n                - array_type is a type with an interface compatible with dlib::array or\n                  std::vector and it must in turn contain image objects that implement the\n                  interface defined in dlib/image_processing/generic_image.h \n                - rectangle_type is a type with an interface compatible with mmod_rect, such\n                  as yolo_rect.\n            ensures\n                - Randomly extracts num_crops chips from images.  We also copy the object\n                  metadata for each extracted crop and store it into #crop_rects.  In\n                  particular, calling this function is the same as invoking the version of\n                  operator() below multiple times, except that this version of operator()\n                  will use multiple CPU cores to do the processing and is therefore faster.\n                - #crops.size() == num_crops\n                - #crop_rects.size() == num_crops\n        !*/\n\n        template <\n            typename array_type,\n            typename image_type,\n            typename rectangle_type\n            >\n        void operator() (\n            const array_type& images,\n            const std::vector<std::vector<rectangle_type>>& rects,\n            image_type& crop,\n            std::vector<rectangle_type>& crop_rects\n        );\n        /*!\n            requires\n                - images.size() == rects.size()\n                - for all valid i:\n                    - images[i].size() != 0\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - array_type is a type with an interface compatible with dlib::array or\n                  std::vector and it must in turn contain image objects that implement the\n                  interface defined in dlib/image_processing/generic_image.h \n                - rectangle_type is a type with an interface compatible with mmod_rect, such\n                  as yolo_rect.\n            ensures\n                - Selects a random image and creates a random crop from it.  Specifically,\n                  we pick a random index IDX < images.size() and then execute \n                    (*this)(images[IDX],rects[IDX],crop,crop_rects) \n        !*/\n\n        template <\n            typename image_type1,\n            typename image_type2,\n            typename rectangle_type\n            >\n        void operator() (\n            const image_type1& img,\n            const std::vector<rectangle_type>& rects,\n            image_type2& crop,\n            std::vector<rectangle_type>& crop_rects\n        );\n        /*!\n            requires\n                - img.size() != 0\n                - image_type1 == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - image_type2 == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - rectangle_type is a type with an interface compatible with mmod_rect, such\n                  as yolo_rect.\n            ensures\n                - Extracts a random crop from img and copies over the rectangle_type objects\n                  in rects to #crop_rects if they are contained inside the crop.  Moreover,\n                  rectangles are marked as ignore if they aren't completely contained\n                  inside the crop.\n                - #crop_rects.size() <= rects.size()\n        !*/\n\n        template <\n            typename image_type1\n            >\n        image_type1 operator() (\n            const image_type1& img\n        );\n        /*!\n            requires\n                - img.size() != 0\n                - image_type1 == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n            ensures\n                - This function simply calls (*this)(img, junk1, crop, junk2) and returns\n                  crop.  Therefore it is simply a convenience function for extracting a\n                  random background patch.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    std::ostream& operator<< (\n        std::ostream& out,\n        const random_cropper& item\n    );\n    /*!\n        ensures\n            - Prints the state of all the parameters of item to out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RaNDOM_CROPPER_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/image_transforms/segment_image.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEGMENT_ImAGE_Hh_\n#define DLIB_SEGMENT_ImAGE_Hh_\n\n#include \"segment_image_abstract.h\"\n#include \"../algs.h\"\n#include <vector>\n#include \"../geometry.h\"\n#include \"../disjoint_subsets.h\"\n#include \"assign_image.h\"\n#include \"../set.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        inline T edge_diff_uint(\n            const T& a,\n            const T& b\n        )\n        {\n            if (a > b)\n                return a - b;\n            else\n                return b - a;\n        }\n\n    // ----------------------------------------\n\n        template <typename T, typename enabled = void>\n        struct edge_diff_funct \n        {\n            typedef double diff_type;\n\n            template <typename pixel_type>\n            double operator()(\n                const pixel_type& a,\n                const pixel_type& b\n            ) const\n            {\n                return length(pixel_to_vector<double>(a) - pixel_to_vector<double>(b));\n            }\n        };\n\n        template <>\n        struct edge_diff_funct<uint8,void>\n        { \n            typedef uint8 diff_type; \n            uint8 operator()( const uint8& a, const uint8& b) const { return edge_diff_uint(a,b); } \n        };\n\n        template <>\n        struct edge_diff_funct<uint16,void>\n        { \n            typedef uint16 diff_type; \n            uint16 operator()( const uint16& a, const uint16& b) const { return edge_diff_uint(a,b); } \n        };\n\n        template <>\n        struct edge_diff_funct<uint32,void>\n        { \n            typedef uint32 diff_type; \n            uint32 operator()( const uint32& a, const uint32& b) const { return edge_diff_uint(a,b); } \n        };\n\n        template <>\n        struct edge_diff_funct<double,void>\n        { \n            typedef double diff_type; \n            double operator()( const double& a, const double& b) const { return std::abs(a-b); } \n        };\n\n        template <typename T>\n        struct edge_diff_funct<T, typename enable_if<is_matrix<T> >::type>\n        {\n            typedef double diff_type;\n            double operator()(\n                const T& a,\n                const T& b\n            ) const\n            {\n                return length(a-b);\n            }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        struct graph_image_segmentation_data_T\n        {\n            graph_image_segmentation_data_T() : component_size(1), internal_diff(0) {}\n            unsigned long component_size;\n            T internal_diff;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        struct segment_image_edge_data_T\n        {\n            segment_image_edge_data_T (){}\n\n            segment_image_edge_data_T (\n                const rectangle& rect,\n                const point& p1,\n                const point& p2,\n                const T& diff_\n            ) :\n                idx1(p1.y()*rect.width() + p1.x()),\n                idx2(p2.y()*rect.width() + p2.x()),\n                diff(diff_)\n            {}\n\n            bool operator<(const segment_image_edge_data_T& item) const\n            { return diff < item.diff; }\n\n            unsigned long idx1;\n            unsigned long idx2;\n            T diff;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename image_view_type>\n        struct uint8_or_uint16_pixels\n        {\n            typedef typename image_view_type::pixel_type pixel_type;\n            const static bool value = is_same_type<pixel_type,uint8>::value ||\n                is_same_type<pixel_type,uint16>::value;\n        };\n\n        // This is an overload of get_pixel_edges() that is optimized to segment images\n        // with 8bit or 16bit  pixels very quickly.  We do this by using a radix sort\n        // instead of quicksort.\n        template <typename in_image_type, typename T>\n        typename enable_if<uint8_or_uint16_pixels<in_image_type> >::type \n        get_pixel_edges (\n            const in_image_type& in_img,\n            std::vector<segment_image_edge_data_T<T> >& sorted_edges\n        )\n        {\n            typedef typename in_image_type::pixel_type ptype;\n            typedef T diff_type;\n            std::vector<unsigned long> counts(std::numeric_limits<ptype>::max()+1, 0);\n\n            edge_diff_funct<ptype> edge_diff;\n\n            border_enumerator be(get_rect(in_img), 1);\n            // we are going to do a radix sort on the edge weights.  So the first step\n            // is to accumulate them into count.\n            const rectangle area = get_rect(in_img);\n            while (be.move_next())\n            {\n                const long r = be.element().y();\n                const long c = be.element().x();\n                const ptype pix = in_img[r][c];\n                if (area.contains(c-1,r))   counts[edge_diff(pix, in_img[r  ][c-1])] += 1;\n                if (area.contains(c+1,r))   counts[edge_diff(pix, in_img[r  ][c+1])] += 1;\n                if (area.contains(c  ,r-1)) counts[edge_diff(pix, in_img[r-1][c  ])] += 1;\n                if (area.contains(c  ,r+1)) counts[edge_diff(pix, in_img[r+1][c  ])] += 1;\n            }\n            for (long r = 1; r+1 < in_img.nr(); ++r)\n            {\n                for (long c = 1; c+1 < in_img.nc(); ++c)\n                {\n                    const ptype pix = in_img[r][c];\n                    counts[edge_diff(pix, in_img[r-1][c+1])] += 1;\n                    counts[edge_diff(pix, in_img[r  ][c+1])] += 1;\n                    counts[edge_diff(pix, in_img[r+1][c  ])] += 1;\n                    counts[edge_diff(pix, in_img[r+1][c+1])] += 1;\n                }\n            }\n\n            const unsigned long num_edges = shrink_rect(area,1).area()*4 + in_img.nr()*2*3 - 4 + (in_img.nc()-2)*2*3;\n            typedef segment_image_edge_data_T<T> segment_image_edge_data;\n            sorted_edges.resize(num_edges);\n\n            // integrate counts.  The idea is to have sorted_edges[counts[i]] be the location that edges\n            // with an edge_diff of i go.  So counts[0] == 0, counts[1] == number of 0 edge diff edges, etc.\n            unsigned long prev = counts[0];\n            for (unsigned long i = 1; i < counts.size(); ++i)\n            {\n                const unsigned long temp = counts[i];\n                counts[i] += counts[i-1];\n                counts[i-1] -= prev;\n                prev = temp;\n            }\n            counts[counts.size()-1] -= prev;\n\n\n            // now build a sorted list of all the edges\n            be.reset();\n            while(be.move_next())\n            {\n                const point p = be.element();\n                const long r = p.y();\n                const long c = p.x();\n                const ptype pix = in_img[r][c];\n                if (area.contains(c-1,r))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r  ][c-1]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c-1,r),diff);\n                }\n\n                if (area.contains(c+1,r))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r  ][c+1]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);\n                }\n\n                if (area.contains(c  ,r-1))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r-1][c  ]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r-1),diff);\n                }\n\n                if (area.contains(c  ,r+1))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r+1][c  ]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r+1),diff);\n                }\n            }\n            // same thing as the above loop but now we do it on the interior of the image and therefore\n            // don't have to include the boundary checking if statements used above.\n            for (long r = 1; r+1 < in_img.nr(); ++r)\n            {\n                for (long c = 1; c+1 < in_img.nc(); ++c)\n                {\n                    const point p(c,r);\n                    const ptype pix = in_img[r][c];\n                    diff_type diff;\n\n                    diff = edge_diff(pix, in_img[r  ][c+1]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r),diff);\n                    diff = edge_diff(pix, in_img[r-1][c+1]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r-1),diff);\n                    diff = edge_diff(pix, in_img[r+1][c+1]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c+1,r+1),diff);\n                    diff = edge_diff(pix, in_img[r+1][c  ]);\n                    sorted_edges[counts[diff]++] = segment_image_edge_data(area,p,point(c  ,r+1),diff);\n                }\n            }\n        }\n        \n    // ----------------------------------------------------------------------------------------\n\n        // This is the general purpose version of get_pixel_edges().  It handles all pixel types.\n        template <typename in_image_type, typename T>\n        typename disable_if<uint8_or_uint16_pixels<in_image_type> >::type \n        get_pixel_edges (\n            const in_image_type& in_img,\n            std::vector<segment_image_edge_data_T<T> >& sorted_edges\n        )\n        {   \n            const rectangle area = get_rect(in_img);\n            sorted_edges.reserve(area.area()*4);\n\n            typedef typename in_image_type::pixel_type ptype;\n            edge_diff_funct<ptype> edge_diff;\n            typedef T diff_type;\n            typedef segment_image_edge_data_T<T> segment_image_edge_data;\n\n            border_enumerator be(get_rect(in_img), 1);\n\n            // now build a sorted list of all the edges\n            be.reset();\n            while(be.move_next())\n            {\n                const point p = be.element();\n                const long r = p.y();\n                const long c = p.x();\n                const ptype& pix = in_img[r][c];\n                if (area.contains(c-1,r))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r  ][c-1]);\n                    sorted_edges.push_back(segment_image_edge_data(area,p,point(c-1,r),diff));\n                }\n\n                if (area.contains(c+1,r))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r  ][c+1]);\n                    sorted_edges.push_back(segment_image_edge_data(area,p,point(c+1,r),diff));\n                }\n\n                if (area.contains(c  ,r-1))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r-1][c  ]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r-1),diff));\n                }\n                if (area.contains(c  ,r+1))\n                {\n                    const diff_type diff = edge_diff(pix, in_img[r+1][c  ]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r+1),diff));\n                }\n            }\n            // same thing as the above loop but now we do it on the interior of the image and therefore\n            // don't have to include the boundary checking if statements used above.\n            for (long r = 1; r+1 < in_img.nr(); ++r)\n            {\n                for (long c = 1; c+1 < in_img.nc(); ++c)\n                {\n                    const point p(c,r);\n                    const ptype& pix = in_img[r][c];\n                    diff_type diff;\n\n                    diff = edge_diff(pix, in_img[r  ][c+1]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r),diff));\n                    diff = edge_diff(pix, in_img[r+1][c+1]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r+1),diff));\n                    diff = edge_diff(pix, in_img[r+1][c  ]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c  ,r+1),diff));\n                    diff = edge_diff(pix, in_img[r-1][c+1]);\n                    sorted_edges.push_back( segment_image_edge_data(area,p,point(c+1,r-1),diff));\n                }\n            }\n\n            std::sort(sorted_edges.begin(), sorted_edges.end());\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    } // end of namespace impl\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void segment_image (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const double k = 200,\n        const unsigned long min_size = 10\n    )\n    {\n        using namespace dlib::impl;\n        typedef typename image_traits<in_image_type>::pixel_type ptype;\n        typedef typename edge_diff_funct<ptype>::diff_type diff_type;\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\t void segment_image()\"\n            << \"\\n\\t The input images can't be the same object.\"\n            );\n\n        COMPILE_TIME_ASSERT(is_unsigned_type<typename image_traits<out_image_type>::pixel_type>::value);\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        out_img.set_size(in_img.nr(), in_img.nc());\n        // don't bother doing anything if the image is too small\n        if (in_img.nr() < 2 || in_img.nc() < 2)\n        {\n            assign_all_pixels(out_img,0);\n            return;\n        }\n\n        disjoint_subsets sets;\n        sets.set_size(in_img.size());\n\n        std::vector<segment_image_edge_data_T<diff_type> > sorted_edges;\n        get_pixel_edges(in_img, sorted_edges);\n\n        std::vector<graph_image_segmentation_data_T<diff_type> > data(in_img.size());\n\n        // now start connecting blobs together to make a minimum spanning tree.\n        for (unsigned long i = 0; i < sorted_edges.size(); ++i)\n        {\n            const unsigned long idx1 = sorted_edges[i].idx1;\n            const unsigned long idx2 = sorted_edges[i].idx2;\n\n            unsigned long set1 = sets.find_set(idx1);\n            unsigned long set2 = sets.find_set(idx2);\n            if (set1 != set2)\n            {\n                const diff_type diff = sorted_edges[i].diff;\n                const diff_type tau1 = static_cast<diff_type>(k/data[set1].component_size);\n                const diff_type tau2 = static_cast<diff_type>(k/data[set2].component_size);\n\n                const diff_type mint = std::min(data[set1].internal_diff + tau1, \n                                                data[set2].internal_diff + tau2);\n                if (diff <= mint)\n                {\n                    const unsigned long new_set = sets.merge_sets(set1, set2);\n                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;\n                    data[new_set].internal_diff = diff;\n                }\n            }\n        }\n\n        // now merge any really small blobs\n        if (min_size != 0)\n        {\n            for (unsigned long i = 0; i < sorted_edges.size(); ++i)\n            {\n                const unsigned long idx1 = sorted_edges[i].idx1;\n                const unsigned long idx2 = sorted_edges[i].idx2;\n\n                unsigned long set1 = sets.find_set(idx1);\n                unsigned long set2 = sets.find_set(idx2);\n                if (set1 != set2 && (data[set1].component_size < min_size || data[set2].component_size < min_size))\n                {\n                    const unsigned long new_set = sets.merge_sets(set1, set2);\n                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;\n                    //data[new_set].internal_diff = sorted_edges[i].diff;\n                }\n            }\n        }\n\n        unsigned long idx = 0;\n        for (long r = 0; r < out_img.nr(); ++r)\n        {\n            for (long c = 0; c < out_img.nc(); ++c)\n            {\n                out_img[r][c] = sets.find_set(idx++);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                     Candidate object location generation code.\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        struct edge_data\n        {\n            double edge_diff;\n            unsigned long set1;  \n            unsigned long set2;\n            bool operator<(const edge_data& item) const\n            {\n                return edge_diff < item.edge_diff;\n            }\n        };\n\n        template <\n            typename in_image_type,\n            typename diff_type\n            >\n        void find_basic_candidate_object_locations (\n            const in_image_type& in_img,\n            const std::vector<dlib::impl::segment_image_edge_data_T<diff_type> >& sorted_edges,\n            std::vector<rectangle>& out_rects,\n            std::vector<edge_data>& edges,\n            const double k,\n            const unsigned long min_size \n        )\n        {\n            using namespace dlib::impl;\n\n            std::vector<dlib::impl::segment_image_edge_data_T<diff_type> > rejected_edges;\n            rejected_edges.reserve(sorted_edges.size());\n\n            out_rects.clear();\n            edges.clear();\n\n            // don't bother doing anything if the image is too small\n            if (in_img.nr() < 2 || in_img.nc() < 2)\n            {\n                return;\n            }\n\n            disjoint_subsets sets;\n            sets.set_size(in_img.size());\n\n\n            std::vector<graph_image_segmentation_data_T<diff_type> > data(in_img.size());\n\n\n\n            std::pair<unsigned long,unsigned long> last_blob_edge(std::numeric_limits<unsigned long>::max(),\n                                                                  std::numeric_limits<unsigned long>::max());;\n            // now start connecting blobs together to make a minimum spanning tree.\n            for (unsigned long i = 0; i < sorted_edges.size(); ++i)\n            {\n                const unsigned long idx1 = sorted_edges[i].idx1;\n                const unsigned long idx2 = sorted_edges[i].idx2;\n\n                unsigned long set1 = sets.find_set(idx1);\n                unsigned long set2 = sets.find_set(idx2);\n                if (set1 != set2)\n                {\n                    const diff_type diff = sorted_edges[i].diff;\n                    const diff_type tau1 = static_cast<diff_type>(k/data[set1].component_size);\n                    const diff_type tau2 = static_cast<diff_type>(k/data[set2].component_size);\n\n                    const diff_type mint = std::min(data[set1].internal_diff + tau1, \n                        data[set2].internal_diff + tau2);\n                    if (diff <= mint)\n                    {\n                        const unsigned long new_set = sets.merge_sets(set1, set2);\n                        data[new_set].component_size = data[set1].component_size + data[set2].component_size;\n                        data[new_set].internal_diff = diff;\n                    }\n                    else\n                    {\n                        // Don't bother keeping multiple edges from the same pair of blobs, we\n                        // only need one for what we will do later.\n                        if (std::make_pair(set1,set2) != last_blob_edge)\n                        {\n                            segment_image_edge_data_T<diff_type> temp = sorted_edges[i];\n                            temp.idx1 = set1;\n                            temp.idx2 = set2;\n                            rejected_edges.push_back(temp);\n                            last_blob_edge = std::make_pair(set1,set2);\n                        }\n                    }\n                }\n            }\n\n\n            // merge small blobs\n            for (unsigned long i = 0; i < rejected_edges.size(); ++i)\n            {\n                const unsigned long idx1 = rejected_edges[i].idx1;\n                const unsigned long idx2 = rejected_edges[i].idx2;\n\n                unsigned long set1 = sets.find_set(idx1);\n                unsigned long set2 = sets.find_set(idx2);\n                rejected_edges[i].idx1 = set1;\n                rejected_edges[i].idx2 = set2;\n                if (set1 != set2 && (data[set1].component_size < min_size || data[set2].component_size < min_size))\n                {\n                    const unsigned long new_set = sets.merge_sets(set1, set2);\n                    data[new_set].component_size = data[set1].component_size + data[set2].component_size;\n                    data[new_set].internal_diff = rejected_edges[i].diff;\n                }\n            }\n\n            // find bounding boxes of each blob\n            std::map<unsigned long, rectangle> boxes;\n            std::map<unsigned long, unsigned long> box_id_map;\n            unsigned long idx = 0;\n            for (long r = 0; r < in_img.nr(); ++r)\n            {\n                for (long c = 0; c < in_img.nc(); ++c)\n                {\n                    const unsigned long id = sets.find_set(idx++);\n                    // Accumulate the current point into its box and if it is the first point\n                    // in the box then also record the id number for this box.\n                    if ((boxes[id] += point(c,r)).area() == 1)\n                        box_id_map[id] = boxes.size()-1;\n                }\n            }\n\n            // copy boxes into out_rects\n            out_rects.resize(boxes.size());\n            for (std::map<unsigned long,rectangle>::iterator i = boxes.begin(); i != boxes.end(); ++i)\n            {\n                out_rects[box_id_map[i->first]] = i->second;\n            }\n\n            // Now find the edges between the boxes \n            typedef dlib::memory_manager<char>::kernel_2c mm_type;\n            dlib::set<std::pair<unsigned long, unsigned long>, mm_type>::kernel_1a neighbors_final;\n            for (unsigned long i = 0; i < rejected_edges.size(); ++i)\n            {\n                const unsigned long idx1 = rejected_edges[i].idx1;\n                const unsigned long idx2 = rejected_edges[i].idx2;\n\n                unsigned long set1 = sets.find_set(idx1);\n                unsigned long set2 = sets.find_set(idx2);\n                if (set1 != set2)\n                {\n                    std::pair<unsigned long, unsigned long> p = std::make_pair(set1,set2);\n                    if (!neighbors_final.is_member(p))\n                    {\n                        neighbors_final.add(p);\n\n                        edge_data temp;\n                        const diff_type mint = std::min(data[set1].internal_diff , \n                                                        data[set2].internal_diff );\n                        temp.edge_diff = rejected_edges[i].diff - mint;\n                        temp.set1 = box_id_map[set1];\n                        temp.set2 = box_id_map[set2];\n                        edges.push_back(temp);\n                    }\n                }\n            }\n\n            std::sort(edges.begin(), edges.end());\n        }\n    } // end namespace impl\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc>\n    void remove_duplicates (\n        std::vector<T,alloc>& items\n    )\n    {\n        std::sort(items.begin(), items.end(), std::less<T>());\n        unsigned long num_unique = 1;\n        for (unsigned long i = 1; i < items.size(); ++i)\n        {\n            if (items[i] != items[i-1])\n            {\n                items[num_unique++] = items[i];\n            }\n        }\n        if (items.size() != 0)\n            items.resize(num_unique);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename EXP\n        >\n    void find_candidate_object_locations (\n        const in_image_type& in_img_,\n        std::vector<rectangle>& rects,\n        const matrix_exp<EXP>& kvals,\n        const unsigned long min_size = 20,\n        const unsigned long max_merging_iterations = 50\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_vector(kvals) && kvals.size() > 0,\n            \"\\t void find_candidate_object_locations()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t is_vector(kvals): \" << is_vector(kvals)\n            << \"\\n\\t kvals.size():     \" << kvals.size()\n            );\n\n        typedef dlib::memory_manager<char>::kernel_2c mm_type;\n        typedef dlib::set<rectangle, mm_type>::kernel_1a set_of_rects;\n\n        using namespace dlib::impl;\n        typedef typename image_traits<in_image_type>::pixel_type ptype;\n        typedef typename edge_diff_funct<ptype>::diff_type diff_type;\n\n        const_image_view<in_image_type> in_img(in_img_);\n\n        // don't bother doing anything if the image is too small\n        if (in_img.nr() < 2 || in_img.nc() < 2)\n        {\n            return;\n        }\n\n        std::vector<edge_data> edges;\n        std::vector<rectangle> working_rects;\n        std::vector<segment_image_edge_data_T<diff_type> > sorted_edges;\n        get_pixel_edges(in_img, sorted_edges);\n\n        disjoint_subsets sets;\n\n        for (long j = 0; j < kvals.size(); ++j)\n        {\n            const double k = kvals(j);\n\n            find_basic_candidate_object_locations(in_img, sorted_edges, working_rects, edges, k, min_size);\n            rects.insert(rects.end(), working_rects.begin(), working_rects.end());\n\n\n            // Now iteratively merge all the rectangles we have and record the results.\n            // Note that, unlike what is described in the paper \n            //    Segmentation as Selective Search for Object Recognition\" by Koen E. A. van de Sande, et al.\n            // we don't use any kind of histogram/SIFT like thing to order the edges\n            // between the blobs.  Here we simply order by the pixel difference value.\n            // Additionally, note that we keep progressively merging boxes in the outer\n            // loop rather than performing just a single iteration as indicated in the\n            // paper.\n            set_of_rects detected_rects;\n            bool did_merge = true;\n            for (unsigned long iter = 0; did_merge && iter < max_merging_iterations; ++iter) \n            {\n                did_merge = false;\n                sets.clear();\n                sets.set_size(working_rects.size());\n\n                // recursively merge neighboring blobs until we have merged everything\n                for (unsigned long i = 0; i < edges.size(); ++i)\n                {\n                    edge_data temp = edges[i];\n\n                    temp.set1 = sets.find_set(temp.set1);\n                    temp.set2 = sets.find_set(temp.set2);\n                    if (temp.set1 != temp.set2)\n                    {\n                        rectangle merged_rect = working_rects[temp.set1] + working_rects[temp.set2];\n                        // Skip merging this pair of blobs if it was merged in a previous\n                        // iteration.  Doing this lets us consider other possible blob\n                        // merges.\n                        if (!detected_rects.is_member(merged_rect))\n                        {\n                            const unsigned long new_set = sets.merge_sets(temp.set1, temp.set2);\n                            rects.push_back(merged_rect);\n                            working_rects[new_set] = merged_rect;\n                            did_merge = true;\n                            detected_rects.add(merged_rect);\n                        }\n                    }\n                }\n            }\n        }\n\n        remove_duplicates(rects);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type\n        >\n    void find_candidate_object_locations (\n        const in_image_type& in_img,\n        std::vector<rectangle>& rects\n    )\n    {\n        find_candidate_object_locations(in_img, rects, linspace(50, 200, 3));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename funct1_t,\n            typename funct2_t\n            >\n        inline void mbd_raster_scan_top_bottom(\n            const rectangle& area,\n            funct1_t funct1,\n            funct2_t funct2\n        )\n        {\n            // scan top to bottom\n            for (long r = area.top(); r <= area.bottom(); ++r)\n            {\n                for (long c = area.left(); c <= area.right(); ++c)\n                {\n                    funct1(r,c, r-1,c);\n                    funct2(r,c, r,c-1);\n                }\n            }\n\n            // scan bottom to top\n            for (long r = area.bottom(); r >= area.top(); --r)\n            {\n                for (long c = area.right(); c >= area.left(); --c)\n                {\n                    funct2(r,c, r+1,c);\n                    funct2(r,c, r,c+1);\n                }\n            }\n        }\n\n        template <\n            typename funct_t\n            >\n        inline void mbd_raster_scan_left_right(\n            const rectangle& area,\n            funct_t funct\n        )\n        {\n            // scan left to right \n            for (long c = area.left(); c <= area.right(); ++c)\n            {\n                for (long r = area.top(); r <= area.bottom(); ++r)\n                {\n                    funct(r,c, r-1,c);\n                    funct(r,c, r,c-1);\n                }\n            }\n\n            // scan right to left \n            for (long c = area.right(); c >= area.left(); --c)\n            {\n                for (long r = area.bottom(); r >= area.top(); --r)\n                {\n                    funct(r,c, r+1,c);\n                    funct(r,c, r,c+1);\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    typename disable_if_c<is_rgb_image<in_image_type>::value>::type min_barrier_distance(\n        const in_image_type& img_,\n        out_image_type& dist_,\n        size_t iterations = 10,\n        bool do_left_right_scans = true\n    )\n    {\n        DLIB_CASSERT(iterations > 0);\n\n        static_assert(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale, \n            \"min_barrier_distance() requires a grayscale output image.\");\n\n        const_image_view<in_image_type> img(img_);\n        image_view<out_image_type> dist(dist_);\n\n        typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n        typedef typename pixel_traits<pixel_type>::basic_pixel_type basic_pixel_type;\n\n\n        dist.set_size(img.nr(), img.nc());\n        array2d<basic_pixel_type> lower, upper;\n        assign_all_pixels(dist, pixel_traits<pixel_type>::max());\n        zero_border_pixels(dist,1,1);\n        assign_image(lower, img);\n        assign_image(upper, img);\n\n\n        auto check_neighbor = [&](long r, long c, long neighbor_r, long neighbor_c) \n        {\n            auto l = std::min(lower[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c]));\n            auto u = std::max(upper[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c]));\n            auto d = u-l;\n            if (d < dist[r][c])\n            {\n                lower[r][c] = l;\n                upper[r][c] = u;\n                dist[r][c] = d;\n            }\n        };\n\n        // The very first pass we make needs to use this version.  We do this because the\n        // initial setting of dist is the max pixel value, but that value might naturally\n        // occur in the data, especially for 8bit images.  So we use this version on the\n        // first pass to make sure that the lower and upper bounds get set with real data.\n        auto check_neighbor_init = [&](long r, long c, long neighbor_r, long neighbor_c) \n        {\n            auto l = std::min(lower[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c]));\n            auto u = std::max(upper[neighbor_r][neighbor_c], get_pixel_intensity(img[r][c]));\n            auto d = u-l;\n            lower[r][c] = l;\n            upper[r][c] = u;\n            dist[r][c] = d;\n        };\n\n        auto area = shrink_rect(get_rect(img),1);\n\n        impl::mbd_raster_scan_top_bottom(area, check_neighbor_init, check_neighbor);\n        if (do_left_right_scans)\n            impl::mbd_raster_scan_left_right(area, check_neighbor);\n        for (size_t i = 1; i < iterations; ++i)\n        {\n            impl::mbd_raster_scan_top_bottom(area, check_neighbor, check_neighbor);\n            if (do_left_right_scans)\n                impl::mbd_raster_scan_left_right(area, check_neighbor);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    typename enable_if_c<is_rgb_image<in_image_type>::value>::type min_barrier_distance(\n        const in_image_type& img_,\n        out_image_type& dist_,\n        size_t iterations = 10,\n        bool do_left_right_scans = true\n    )\n    {\n        DLIB_CASSERT(iterations > 0);\n\n        static_assert(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale, \n            \"min_barrier_distance() requires a grayscale output image.\");\n\n        const_image_view<in_image_type> img(img_);\n\n        typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n\n\n        array2d<rgb_pixel> dist(img.nr(), img.nc());\n        array2d<rgb_pixel> lower, upper;\n        assign_all_pixels(dist, pixel_traits<pixel_type>::max());\n        zero_border_pixels(dist,1,1);\n        assign_image(lower, img);\n        assign_image(upper, img);\n\n        auto check_neighbor = [&](long r, long c, long neighbor_r, long neighbor_c) \n        {\n            auto l = std::min(lower[neighbor_r][neighbor_c].red, img[r][c].red);\n            auto u = std::max(upper[neighbor_r][neighbor_c].red, img[r][c].red);\n            auto d = u-l;\n            if (d < dist[r][c].red)\n            {\n                lower[r][c].red = l;\n                upper[r][c].red = u;\n                dist[r][c].red = d;\n            }\n\n            l = std::min(lower[neighbor_r][neighbor_c].green, img[r][c].green);\n            u = std::max(upper[neighbor_r][neighbor_c].green, img[r][c].green);\n            d = u-l;\n            if (d < dist[r][c].green)\n            {\n                lower[r][c].green = l;\n                upper[r][c].green = u;\n                dist[r][c].green = d;\n            }\n\n            l = std::min(lower[neighbor_r][neighbor_c].blue, img[r][c].blue);\n            u = std::max(upper[neighbor_r][neighbor_c].blue, img[r][c].blue);\n            d = u-l;\n            if (d < dist[r][c].blue)\n            {\n                lower[r][c].blue = l;\n                upper[r][c].blue = u;\n                dist[r][c].blue = d;\n            }\n        };\n\n        // The very first pass we make needs to use this version.  We do this because the\n        // initial setting of dist is the max pixel value, but that value might naturally\n        // occur in the data, especially for 8bit images.  So we use this version on the\n        // first pass to make sure that the lower and upper bounds get set with real data.\n        auto check_neighbor_init = [&](long r, long c, long neighbor_r, long neighbor_c) \n        {\n            auto l = std::min(lower[neighbor_r][neighbor_c].red, img[r][c].red);\n            auto u = std::max(upper[neighbor_r][neighbor_c].red, img[r][c].red);\n            auto d = u-l;\n            lower[r][c].red = l;\n            upper[r][c].red = u;\n            dist[r][c].red = d;\n\n            l = std::min(lower[neighbor_r][neighbor_c].green, img[r][c].green);\n            u = std::max(upper[neighbor_r][neighbor_c].green, img[r][c].green);\n            d = u-l;\n            lower[r][c].green = l;\n            upper[r][c].green = u;\n            dist[r][c].green = d;\n\n            l = std::min(lower[neighbor_r][neighbor_c].blue, img[r][c].blue);\n            u = std::max(upper[neighbor_r][neighbor_c].blue, img[r][c].blue);\n            d = u-l;\n            lower[r][c].blue = l;\n            upper[r][c].blue = u;\n            dist[r][c].blue = d;\n        };\n\n        auto area = shrink_rect(get_rect(img),1);\n\n        impl::mbd_raster_scan_top_bottom(area, check_neighbor_init, check_neighbor);\n        if (do_left_right_scans)\n            impl::mbd_raster_scan_left_right(area, check_neighbor);\n        for (size_t i = 1; i < iterations; ++i)\n        {\n            impl::mbd_raster_scan_top_bottom(area, check_neighbor, check_neighbor);\n            if (do_left_right_scans)\n                impl::mbd_raster_scan_left_right(area, check_neighbor);\n        }\n\n        // convert to grayscale for output.\n        assign_image(dist_,dist);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEGMENT_ImAGE_Hh_\n\n"
  },
  {
    "path": "dlib/image_transforms/segment_image_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_\n#ifdef DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void segment_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const double k = 200,\n        const unsigned long min_size = 10\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_image_type can contain any pixel type with a pixel_traits specialization\n              or a dlib matrix object representing a row or column vector.\n            - out_image_type must contain an unsigned integer pixel type.\n            - is_same_object(in_img, out_img) == false\n        ensures\n            - Attempts to segment in_img into regions which have some visual consistency to\n              them.  In particular, this function implements the algorithm described in the\n              paper: Efficient Graph-Based Image Segmentation by Felzenszwalb and Huttenlocher.\n            - #out_img.nr() == in_img.nr()\n            - #out_img.nc() == in_img.nc()\n            - for all valid r and c:\n                - #out_img[r][c] == an integer value indicating the identity of the segment\n                  containing the pixel in_img[r][c].  \n            - The k parameter is a measure used to influence how large the segment regions\n              will be.  Larger k generally results in larger segments being produced.  For\n              a deeper discussion of the k parameter you should consult the above\n              referenced paper.\n            - min_size is a lower bound on the size of the output segments.  That is, it is\n              guaranteed that all output segments will have at least min_size pixels in\n              them (unless the whole image contains fewer than min_size pixels, in this\n              case the entire image will be put into a single segment).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename EXP\n        >\n    void find_candidate_object_locations (\n        const in_image_type& in_img,\n        std::vector<rectangle>& rects,\n        const matrix_exp<EXP>& kvals = linspace(50, 200, 3),\n        const unsigned long min_size = 20,\n        const unsigned long max_merging_iterations = 50\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - is_vector(kvals) == true\n            - kvals.size() > 0\n        ensures\n            - This function takes an input image and generates a set of candidate\n              rectangles which are expected to bound any objects in the image.  It does\n              this by running a version of the segment_image() routine on the image and\n              then reports rectangles containing each of the segments as well as rectangles\n              containing unions of adjacent segments.  The basic idea is described in the\n              paper: \n                  Segmentation as Selective Search for Object Recognition by Koen E. A. van de Sande, et al.\n              Note that this function deviates from what is described in the paper slightly. \n              See the code for details.\n            - The basic segmentation is performed kvals.size() times, each time with the k\n              parameter (see segment_image() and the Felzenszwalb paper for details on k)\n              set to a different value from kvals.   \n            - When doing the basic segmentations prior to any box merging, we discard all\n              rectangles that have an area < min_size.  Therefore, all outputs and\n              subsequent merged rectangles are built out of rectangles that contain at\n              least min_size pixels.  Note that setting min_size to a smaller value than\n              you might otherwise be interested in using can be useful since it allows a\n              larger number of possible merged boxes to be created.\n            - There are max_merging_iterations rounds of neighboring blob merging.\n              Therefore, this parameter has some effect on the number of output rectangles\n              you get, with larger values of the parameter giving more output rectangles.\n            - This function appends the output rectangles into #rects.  This means that any\n              rectangles in rects before this function was called will still be in there\n              after it terminates.  Note further that #rects will not contain any duplicate\n              rectangles.  That is, for all valid i and j where i != j it will be true\n              that:\n                - #rects[i] != rects[j]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        template T,\n        typename alloc\n        >\n    void remove_duplicates (\n        std::vector<T,alloc>& items \n    );\n    /*!\n        requires\n            - T is comparable via operator != and std::less.\n        ensures\n            - This function finds any duplicate objects in items and removes the extra\n              instances.  This way, the result is that items contains only unique\n              instances.  It does this by sorting items and removing neighboring elements\n              unless they compare != according to operator !=.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void min_barrier_distance(\n        const in_image_type& img,\n        out_image_type& dist,\n        size_t iterations = 10,\n        bool do_left_right_scans = true\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true\n              (i.e. dist must be a grayscale image)\n            - iterations > 0\n        ensures\n            - This function implements the salient object detection method described in the paper:\n                \"Minimum barrier salient object detection at 80 fps\" by Zhang, Jianming, et al. \n              In particular, we compute the minimum barrier distance between the borders of\n              the image and all the other pixels.  The result is stored in dist.  Note that\n              the paper talks about a bunch of other things you could do beyond computing\n              the minimum barrier distance, but this function doesn't do any of that. It's\n              just the vanilla MBD.\n            - We will perform iterations iterations of MBD passes over the image.  Larger\n              values might give better results but run slower.\n            - During each MBD iteration we make raster scans over the image.  These pass\n              from top->bottom, bottom->top, left->right, and right->left.  If\n              do_left_right_scans==false then the left/right passes are not executed.\n              Skipping them makes the algorithm about 2x faster but might reduce the\n              quality of the output.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEGMENT_ImAGE_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/spatial_filtering.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SPATIAL_FILTERINg_H_\n#define DLIB_SPATIAL_FILTERINg_H_\n\n#include \"../pixel.h\"\n#include \"spatial_filtering_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include \"../array2d.h\"\n#include \"../matrix.h\"\n#include \"../geometry/border_enumerator.h\"\n#include \"../simd.h\"\n#include <limits>\n#include \"assign_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename in_image_type,\n            typename out_image_type,\n            typename EXP,\n            typename T\n            >\n        rectangle grayscale_spatially_filter_image (\n            const in_image_type& in_img_,\n            out_image_type& out_img_,\n            const matrix_exp<EXP>& filter_,\n            T scale,\n            bool use_abs,\n            bool add_to\n        )\n        {\n            const_temp_matrix<EXP> filter(filter_);\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n            DLIB_ASSERT(scale != 0 && filter.size() != 0,\n                \"\\trectangle spatially_filter_image()\"\n                << \"\\n\\t You can't give a scale of zero or an empty filter.\"\n                << \"\\n\\t scale: \"<< scale\n                << \"\\n\\t filter.nr(): \"<< filter.nr()\n                << \"\\n\\t filter.nc(): \"<< filter.nc()\n            );\n            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n                \"\\trectangle spatially_filter_image()\"\n                << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n            const_image_view<in_image_type> in_img(in_img_);\n            image_view<out_image_type> out_img(out_img_);\n\n            // if there isn't any input image then don't do anything\n            if (in_img.size() == 0)\n            {\n                out_img.clear();\n                return rectangle();\n            }\n\n            out_img.set_size(in_img.nr(),in_img.nc());\n\n\n            // figure out the range that we should apply the filter to\n            const long first_row = filter.nr()/2;\n            const long first_col = filter.nc()/2;\n            const long last_row = in_img.nr() - ((filter.nr()-1)/2);\n            const long last_col = in_img.nc() - ((filter.nc()-1)/2);\n\n            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n            if (!add_to)\n                zero_border_pixels(out_img_, non_border); \n\n            // apply the filter to the image\n            for (long r = first_row; r < last_row; ++r)\n            {\n                for (long c = first_col; c < last_col; ++c)\n                {\n                    typedef typename EXP::type ptype;\n                    ptype p;\n                    ptype temp = 0;\n                    for (long m = 0; m < filter.nr(); ++m)\n                    {\n                        for (long n = 0; n < filter.nc(); ++n)\n                        {\n                            // pull out the current pixel and put it into p\n                            p = get_pixel_intensity(in_img[r-first_row+m][c-first_col+n]);\n                            temp += p*filter(m,n);\n                        }\n                    }\n\n                    temp /= scale;\n\n                    if (use_abs && temp < 0)\n                    {\n                        temp = -temp;\n                    }\n\n                    // save this pixel to the output image\n                    if (add_to == false)\n                    {\n                        assign_pixel(out_img[r][c], temp);\n                    }\n                    else\n                    {\n                        assign_pixel(out_img[r][c], temp + out_img[r][c]);\n                    }\n                }\n            }\n\n            return non_border;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename in_image_type,\n            typename out_image_type,\n            typename EXP\n            >\n        rectangle float_spatially_filter_image (\n            const in_image_type& in_img_,\n            out_image_type& out_img_,\n            const matrix_exp<EXP>& filter_,\n            bool add_to\n        )\n        {\n\n            const_temp_matrix<EXP> filter(filter_);\n            DLIB_ASSERT(filter.size() != 0,\n                \"\\trectangle spatially_filter_image()\"\n                << \"\\n\\t You can't give an empty filter.\"\n                << \"\\n\\t filter.nr(): \"<< filter.nr()\n                << \"\\n\\t filter.nc(): \"<< filter.nc()\n            );\n            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n                \"\\trectangle spatially_filter_image()\"\n                << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n            const_image_view<in_image_type> in_img(in_img_);\n            image_view<out_image_type> out_img(out_img_);\n\n            // if there isn't any input image then don't do anything\n            if (in_img.size() == 0)\n            {\n                out_img.clear();\n                return rectangle();\n            }\n\n            out_img.set_size(in_img.nr(),in_img.nc());\n\n\n            // figure out the range that we should apply the filter to\n            const long first_row = filter.nr()/2;\n            const long first_col = filter.nc()/2;\n            const long last_row = in_img.nr() - ((filter.nr()-1)/2);\n            const long last_col = in_img.nc() - ((filter.nc()-1)/2);\n\n            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n            if (!add_to)\n                zero_border_pixels(out_img_, non_border); \n\n            // apply the filter to the image\n            for (long r = first_row; r < last_row; ++r)\n            {\n                long c = first_col;\n                for (; c < last_col-7; c+=8)\n                {\n                    simd8f p,p2,p3;\n                    simd8f temp = 0, temp2=0, temp3=0;\n                    for (long m = 0; m < filter.nr(); ++m)\n                    {\n                        long n = 0;\n                        for (; n < filter.nc()-2; n+=3)\n                        {\n                            // pull out the current pixel and put it into p\n                            p.load(&in_img[r-first_row+m][c-first_col+n]);\n                            p2.load(&in_img[r-first_row+m][c-first_col+n+1]);\n                            p3.load(&in_img[r-first_row+m][c-first_col+n+2]);\n                            temp += p*filter(m,n);\n                            temp2 += p2*filter(m,n+1);\n                            temp3 += p3*filter(m,n+2);\n                        }\n                        for (; n < filter.nc(); ++n)\n                        {\n                            // pull out the current pixel and put it into p\n                            p.load(&in_img[r-first_row+m][c-first_col+n]);\n                            temp += p*filter(m,n);\n                        }\n                    }\n                    temp += temp2+temp3;\n\n                    // save this pixel to the output image\n                    if (add_to == false)\n                    {\n                        temp.store(&out_img[r][c]);\n                    }\n                    else\n                    {\n                        p.load(&out_img[r][c]);\n                        temp += p;\n                        temp.store(&out_img[r][c]);\n                    }\n                }\n                for (; c < last_col; ++c)\n                {\n                    float p;\n                    float temp = 0;\n                    for (long m = 0; m < filter.nr(); ++m)\n                    {\n                        for (long n = 0; n < filter.nc(); ++n)\n                        {\n                            // pull out the current pixel and put it into p\n                            p = in_img[r-first_row+m][c-first_col+n];\n                            temp += p*filter(m,n);\n                        }\n                    }\n\n                    // save this pixel to the output image\n                    if (add_to == false)\n                    {\n                        out_img[r][c] = temp;\n                    }\n                    else\n                    {\n                        out_img[r][c] += temp;\n                    }\n                }\n            }\n\n            return non_border;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP\n        >\n    struct is_float_filtering2\n    {\n        const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value &&\n                                  is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value &&\n                                  is_same_type<typename EXP::type,float>::value;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP,\n        typename T\n        >\n    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && \n                         is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type \n    spatially_filter_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP>& filter,\n        T scale,\n        bool use_abs = false,\n        bool add_to = false\n    )\n    {\n        if (use_abs == false)\n        {\n            if (scale == 1)\n                return impl::float_spatially_filter_image(in_img, out_img, filter, add_to);\n            else\n                return impl::float_spatially_filter_image(in_img, out_img, filter/scale, add_to);\n        }\n        else\n        {\n            return impl::grayscale_spatially_filter_image(in_img, out_img, filter, scale, true, add_to);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP,\n        typename T\n        >\n    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && \n                         !is_float_filtering2<in_image_type,out_image_type,EXP>::value,rectangle>::type \n    spatially_filter_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP>& filter,\n        T scale,\n        bool use_abs = false,\n        bool add_to = false\n    )\n    {\n        return impl::grayscale_spatially_filter_image(in_img,out_img,filter,scale,use_abs,add_to);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP,\n        typename T\n        >\n    typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type \n    spatially_filter_image (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const matrix_exp<EXP>& filter_,\n        T scale\n    )\n    {\n        const_temp_matrix<EXP> filter(filter_);\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n        DLIB_ASSERT(scale != 0 && filter.size() != 0,\n            \"\\trectangle spatially_filter_image()\"\n            << \"\\n\\t You can't give a scale of zero or an empty filter.\"\n            << \"\\n\\t scale: \"<< scale\n            << \"\\n\\t filter.nr(): \"<< filter.nr()\n            << \"\\n\\t filter.nc(): \"<< filter.nc()\n            );\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\trectangle spatially_filter_image()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return rectangle();\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n\n        // figure out the range that we should apply the filter to\n        const long first_row = filter.nr()/2;\n        const long first_col = filter.nc()/2;\n        const long last_row = in_img.nr() - ((filter.nr()-1)/2);\n        const long last_col = in_img.nc() - ((filter.nc()-1)/2);\n\n        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n        zero_border_pixels(out_img, non_border); \n\n        // apply the filter to the image\n        for (long r = first_row; r < last_row; ++r)\n        {\n            for (long c = first_col; c < last_col; ++c)\n            {\n                typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n                typedef matrix<typename EXP::type,pixel_traits<pixel_type>::num,1> ptype;\n                ptype p;\n                ptype temp;\n                temp = 0;\n                for (long m = 0; m < filter.nr(); ++m)\n                {\n                    for (long n = 0; n < filter.nc(); ++n)\n                    {\n                        // pull out the current pixel and put it into p\n                        p = pixel_to_vector<typename EXP::type>(in_img[r-first_row+m][c-first_col+n]);\n                        temp += p*filter(m,n);\n                    }\n                }\n\n                temp /= scale;\n\n                pixel_type pp;\n                vector_to_pixel(pp, temp);\n                assign_pixel(out_img[r][c], pp);\n            }\n        }\n\n        return non_border;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP\n        >\n    rectangle spatially_filter_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP>& filter\n    )\n    {\n        return spatially_filter_image(in_img,out_img,filter,1);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename in_image_type,\n            typename out_image_type,\n            typename EXP1,\n            typename EXP2,\n            typename T\n            >\n        rectangle grayscale_spatially_filter_image_separable (\n            const in_image_type& in_img_,\n            out_image_type& out_img_,\n            const matrix_exp<EXP1>& _row_filter,\n            const matrix_exp<EXP2>& _col_filter,\n            T scale,\n            bool use_abs,\n            bool add_to \n        )\n        {\n            const_temp_matrix<EXP1> row_filter(_row_filter);\n            const_temp_matrix<EXP2> col_filter(_col_filter);\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n            DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 &&\n                is_vector(row_filter) &&\n                is_vector(col_filter),\n                \"\\trectangle spatially_filter_image_separable()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t scale: \"<< scale\n                << \"\\n\\t row_filter.size(): \"<< row_filter.size()\n                << \"\\n\\t col_filter.size(): \"<< col_filter.size()\n                << \"\\n\\t is_vector(row_filter): \"<< is_vector(row_filter)\n                << \"\\n\\t is_vector(col_filter): \"<< is_vector(col_filter)\n            );\n            DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n                \"\\trectangle spatially_filter_image_separable()\"\n                << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n            const_image_view<in_image_type> in_img(in_img_);\n            image_view<out_image_type> out_img(out_img_);\n\n            // if there isn't any input image then don't do anything\n            if (in_img.size() == 0)\n            {\n                out_img.clear();\n                return rectangle();\n            }\n\n            out_img.set_size(in_img.nr(),in_img.nc());\n\n\n            // figure out the range that we should apply the filter to\n            const long first_row = col_filter.size()/2;\n            const long first_col = row_filter.size()/2;\n            const long last_row = in_img.nr() - ((col_filter.size()-1)/2);\n            const long last_col = in_img.nc() - ((row_filter.size()-1)/2);\n\n            const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n            if (!add_to)\n                zero_border_pixels(out_img, non_border); \n\n            typedef typename EXP1::type ptype;\n\n            array2d<ptype> temp_img;\n            temp_img.set_size(in_img.nr(), in_img.nc());\n\n            // apply the row filter\n            for (long r = 0; r < in_img.nr(); ++r)\n            {\n                for (long c = first_col; c < last_col; ++c)\n                {\n                    ptype p;\n                    ptype temp = 0;\n                    for (long n = 0; n < row_filter.size(); ++n)\n                    {\n                        // pull out the current pixel and put it into p\n                        p = get_pixel_intensity(in_img[r][c-first_col+n]);\n                        temp += p*row_filter(n);\n                    }\n                    temp_img[r][c] = temp;\n                }\n            }\n\n            // apply the column filter \n            for (long r = first_row; r < last_row; ++r)\n            {\n                for (long c = first_col; c < last_col; ++c)\n                {\n                    ptype temp = 0;\n                    for (long m = 0; m < col_filter.size(); ++m)\n                    {\n                        temp += temp_img[r-first_row+m][c]*col_filter(m);\n                    }\n\n                    temp /= scale;\n\n                    if (use_abs && temp < 0)\n                    {\n                        temp = -temp;\n                    }\n\n                    // save this pixel to the output image\n                    if (add_to == false)\n                    {\n                        assign_pixel(out_img[r][c], temp);\n                    }\n                    else\n                    {\n                        assign_pixel(out_img[r][c], temp + out_img[r][c]);\n                    }\n                }\n            }\n            return non_border;\n        }\n\n    } // namespace impl\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2\n        >\n    struct is_float_filtering\n    {\n        const static bool value = is_same_type<typename image_traits<in_image_type>::pixel_type,float>::value &&\n                                  is_same_type<typename image_traits<out_image_type>::pixel_type,float>::value &&\n                                  is_same_type<typename EXP1::type,float>::value &&\n                                  is_same_type<typename EXP2::type,float>::value;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    // This overload is optimized to use SIMD instructions when filtering float images with\n    // float filters.\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2\n        >\n    rectangle float_spatially_filter_image_separable (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const matrix_exp<EXP1>& _row_filter,\n        const matrix_exp<EXP2>& _col_filter,\n        out_image_type& scratch_,\n        bool add_to = false\n    )\n    {\n        // You can only use this function with images and filters containing float\n        // variables.\n        COMPILE_TIME_ASSERT((is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value == true));\n\n\n        const_temp_matrix<EXP1> row_filter(_row_filter);\n        const_temp_matrix<EXP2> col_filter(_col_filter);\n        DLIB_ASSERT(row_filter.size() != 0 && col_filter.size() != 0 &&\n            is_vector(row_filter) &&\n            is_vector(col_filter),\n            \"\\trectangle float_spatially_filter_image_separable()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t row_filter.size(): \"<< row_filter.size()\n            << \"\\n\\t col_filter.size(): \"<< col_filter.size()\n            << \"\\n\\t is_vector(row_filter): \"<< is_vector(row_filter)\n            << \"\\n\\t is_vector(col_filter): \"<< is_vector(col_filter)\n        );\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\trectangle float_spatially_filter_image_separable()\"\n            << \"\\n\\tYou must give two different image objects\"\n        );\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return rectangle();\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        // figure out the range that we should apply the filter to\n        const long first_row = col_filter.size()/2;\n        const long first_col = row_filter.size()/2;\n        const long last_row = in_img.nr() - ((col_filter.size()-1)/2);\n        const long last_col = in_img.nc() - ((row_filter.size()-1)/2);\n\n        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n        if (!add_to)\n            zero_border_pixels(out_img, non_border); \n\n        image_view<out_image_type> scratch(scratch_);\n        scratch.set_size(in_img.nr(), in_img.nc());\n\n        // apply the row filter\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            long c = first_col;\n            for (; c < last_col-7; c+=8)\n            {\n                simd8f p,p2,p3, temp = 0, temp2=0, temp3=0;\n                long n = 0;\n                for (; n < row_filter.size()-2; n+=3)\n                {\n                    // pull out the current pixel and put it into p\n                    p.load(&in_img[r][c-first_col+n]);\n                    p2.load(&in_img[r][c-first_col+n+1]);\n                    p3.load(&in_img[r][c-first_col+n+2]);\n                    temp += p*row_filter(n);\n                    temp2 += p2*row_filter(n+1);\n                    temp3 += p3*row_filter(n+2);\n                }\n                for (; n < row_filter.size(); ++n)\n                {\n                    // pull out the current pixel and put it into p\n                    p.load(&in_img[r][c-first_col+n]);\n                    temp += p*row_filter(n);\n                }\n                temp += temp2 + temp3;\n                temp.store(&scratch[r][c]);\n            }\n            for (; c < last_col; ++c)\n            {\n                float p;\n                float temp = 0;\n                for (long n = 0; n < row_filter.size(); ++n)\n                {\n                    // pull out the current pixel and put it into p\n                    p = in_img[r][c-first_col+n];\n                    temp += p*row_filter(n);\n                }\n                scratch[r][c] = temp;\n            }\n        }\n\n        // apply the column filter \n        for (long r = first_row; r < last_row; ++r)\n        {\n            long c = first_col;\n            for (; c < last_col-7; c+=8)\n            {\n                simd8f p, p2, p3, temp = 0, temp2 = 0, temp3 = 0;\n                long m = 0;\n                for (; m < col_filter.size()-2; m+=3)\n                {\n                    p.load(&scratch[r-first_row+m][c]);\n                    p2.load(&scratch[r-first_row+m+1][c]);\n                    p3.load(&scratch[r-first_row+m+2][c]);\n                    temp += p*col_filter(m);\n                    temp2 += p2*col_filter(m+1);\n                    temp3 += p3*col_filter(m+2);\n                }\n                for (; m < col_filter.size(); ++m)\n                {\n                    p.load(&scratch[r-first_row+m][c]);\n                    temp += p*col_filter(m);\n                }\n                temp += temp2+temp3;\n\n                // save this pixel to the output image\n                if (add_to == false)\n                {\n                    temp.store(&out_img[r][c]);\n                }\n                else\n                {\n                    p.load(&out_img[r][c]);\n                    temp += p;\n                    temp.store(&out_img[r][c]);\n                }\n            }\n            for (; c < last_col; ++c)\n            {\n                float temp = 0;\n                for (long m = 0; m < col_filter.size(); ++m)\n                {\n                    temp += scratch[r-first_row+m][c]*col_filter(m);\n                }\n\n                // save this pixel to the output image\n                if (add_to == false)\n                {\n                    out_img[r][c] = temp;\n                }\n                else\n                {\n                    out_img[r][c] += temp;\n                }\n            }\n        }\n        return non_border;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && \n                         is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type \n    spatially_filter_image_separable (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        T scale,\n        bool use_abs = false,\n        bool add_to = false\n    )\n    {\n        if (use_abs == false)\n        {\n            out_image_type scratch;\n            if (scale == 1)\n                return float_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scratch, add_to);\n            else\n                return float_spatially_filter_image_separable(in_img, out_img, row_filter/scale, col_filter, scratch,  add_to);\n        }\n        else\n        {\n            return impl::grayscale_spatially_filter_image_separable(in_img, out_img, row_filter, col_filter, scale, true, add_to);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    typename enable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale && \n                         !is_float_filtering<in_image_type,out_image_type,EXP1,EXP2>::value,rectangle>::type \n    spatially_filter_image_separable (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        T scale,\n        bool use_abs = false,\n        bool add_to = false\n    )\n    {\n        return impl::grayscale_spatially_filter_image_separable(in_img,out_img, row_filter, col_filter, scale, use_abs, add_to);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    typename disable_if_c<pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale,rectangle>::type \n    spatially_filter_image_separable (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const matrix_exp<EXP1>& _row_filter,\n        const matrix_exp<EXP2>& _col_filter,\n        T scale\n    )\n    {\n        const_temp_matrix<EXP1> row_filter(_row_filter);\n        const_temp_matrix<EXP2> col_filter(_col_filter);\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n        DLIB_ASSERT(scale != 0 && row_filter.size() != 0 && col_filter.size() != 0 &&\n                    is_vector(row_filter) &&\n                    is_vector(col_filter),\n            \"\\trectangle spatially_filter_image_separable()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t scale: \"<< scale\n            << \"\\n\\t row_filter.size(): \"<< row_filter.size()\n            << \"\\n\\t col_filter.size(): \"<< col_filter.size()\n            << \"\\n\\t is_vector(row_filter): \"<< is_vector(row_filter)\n            << \"\\n\\t is_vector(col_filter): \"<< is_vector(col_filter)\n            );\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\trectangle spatially_filter_image_separable()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return rectangle();\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n\n        // figure out the range that we should apply the filter to\n        const long first_row = col_filter.size()/2;\n        const long first_col = row_filter.size()/2;\n        const long last_row = in_img.nr() - ((col_filter.size()-1)/2);\n        const long last_col = in_img.nc() - ((row_filter.size()-1)/2);\n\n        const rectangle non_border = rectangle(first_col, first_row, last_col-1, last_row-1);\n        zero_border_pixels(out_img, non_border); \n\n        typedef typename image_traits<in_image_type>::pixel_type pixel_type;\n        typedef matrix<typename EXP1::type,pixel_traits<pixel_type>::num,1> ptype;\n\n        array2d<ptype> temp_img;\n        temp_img.set_size(in_img.nr(), in_img.nc());\n\n        // apply the row filter\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = first_col; c < last_col; ++c)\n            {\n                ptype p;\n                ptype temp;\n                temp = 0;\n                for (long n = 0; n < row_filter.size(); ++n)\n                {\n                    // pull out the current pixel and put it into p\n                    p = pixel_to_vector<typename EXP1::type>(in_img[r][c-first_col+n]);\n                    temp += p*row_filter(n);\n                }\n                temp_img[r][c] = temp;\n            }\n        }\n\n        // apply the column filter \n        for (long r = first_row; r < last_row; ++r)\n        {\n            for (long c = first_col; c < last_col; ++c)\n            {\n                ptype temp;\n                temp = 0;\n                for (long m = 0; m < col_filter.size(); ++m)\n                {\n                    temp += temp_img[r-first_row+m][c]*col_filter(m);\n                }\n\n                temp /= scale;\n\n\n                // save this pixel to the output image\n                pixel_type p;\n                vector_to_pixel(p, temp);\n                assign_pixel(out_img[r][c], p);\n            }\n        }\n        return non_border;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2\n        >\n    rectangle spatially_filter_image_separable (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter\n    )\n    {\n        return spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,1);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    rectangle spatially_filter_image_separable_down (\n        const unsigned long downsample,\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        T scale,\n        bool use_abs = false,\n        bool add_to = false\n    )\n    {\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true );\n\n        DLIB_ASSERT(downsample > 0 &&\n                    scale != 0 &&\n                    row_filter.size()%2 == 1 &&\n                    col_filter.size()%2 == 1 &&\n                    is_vector(row_filter) &&\n                    is_vector(col_filter),\n            \"\\trectangle spatially_filter_image_separable_down()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t downsample: \"<< downsample\n            << \"\\n\\t scale: \"<< scale\n            << \"\\n\\t row_filter.size(): \"<< row_filter.size()\n            << \"\\n\\t col_filter.size(): \"<< col_filter.size()\n            << \"\\n\\t is_vector(row_filter): \"<< is_vector(row_filter)\n            << \"\\n\\t is_vector(col_filter): \"<< is_vector(col_filter)\n            );\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\trectangle spatially_filter_image_separable_down()\"\n            << \"\\n\\tYou must give two different image objects\"\n            );\n\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return rectangle();\n        }\n\n        out_img.set_size((long)(std::ceil((double)in_img.nr()/downsample)),\n                         (long)(std::ceil((double)in_img.nc()/downsample)));\n\n        const double col_border = std::floor(col_filter.size()/2.0);\n        const double row_border = std::floor(row_filter.size()/2.0);\n\n        // figure out the range that we should apply the filter to\n        const long first_row = (long)std::ceil(col_border/downsample);\n        const long first_col = (long)std::ceil(row_border/downsample);\n        const long last_row  = (long)std::ceil((in_img.nr() - col_border)/downsample) - 1;\n        const long last_col  = (long)std::ceil((in_img.nc() - row_border)/downsample) - 1;\n\n        // zero border pixels\n        const rectangle non_border = rectangle(first_col, first_row, last_col, last_row);\n        zero_border_pixels(out_img,non_border);\n\n        typedef typename EXP1::type ptype;\n\n        array2d<ptype> temp_img;\n        temp_img.set_size(in_img.nr(), out_img.nc());\n\n        // apply the row filter\n        for (long r = 0; r < temp_img.nr(); ++r)\n        {\n            for (long c = non_border.left(); c <= non_border.right(); ++c)\n            {\n                ptype p;\n                ptype temp = 0;\n                for (long n = 0; n < row_filter.size(); ++n)\n                {\n                    // pull out the current pixel and put it into p\n                    p = get_pixel_intensity(in_img[r][c*downsample-row_filter.size()/2+n]);\n                    temp += p*row_filter(n);\n                }\n                temp_img[r][c] = temp;\n            }\n        }\n\n        // apply the column filter \n        for (long r = non_border.top(); r <= non_border.bottom(); ++r)\n        {\n            for (long c = non_border.left(); c <= non_border.right(); ++c)\n            {\n                ptype temp = 0;\n                for (long m = 0; m < col_filter.size(); ++m)\n                {\n                    temp += temp_img[r*downsample-col_filter.size()/2+m][c]*col_filter(m);\n                }\n\n                temp /= scale;\n\n                if (use_abs && temp < 0)\n                {\n                    temp = -temp;\n                }\n\n                // save this pixel to the output image\n                if (add_to == false)\n                {\n                    assign_pixel(out_img[r][c], temp);\n                }\n                else\n                {\n                    assign_pixel(out_img[r][c], temp + out_img[r][c]);\n                }\n            }\n        }\n\n        return non_border;\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2\n        >\n    rectangle spatially_filter_image_separable_down (\n        const unsigned long downsample,\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter\n    )\n    {\n        return spatially_filter_image_separable_down(downsample,in_img,out_img,row_filter,col_filter,1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR,\n        long NC,\n        typename T,\n        typename U,\n        typename in_image_type\n        >\n    inline void separable_3x3_filter_block_grayscale (\n        T (&block)[NR][NC],\n        const in_image_type& img_,\n        const long& r,\n        const long& c,\n        const U& fe1, // separable filter end\n        const U& fm,  // separable filter middle \n        const U& fe2 // separable filter end 2\n    ) \n    {\n        const_image_view<in_image_type> img(img_);\n        // make sure requires clause is not broken\n        DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) &&\n                    shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1),\n            \"\\t void separable_3x3_filter_block_grayscale()\"\n            << \"\\n\\t The sub-window doesn't fit inside the given image.\"\n            << \"\\n\\t get_rect(img):       \" << get_rect(img) \n            << \"\\n\\t (c,r):               \" << point(c,r) \n            << \"\\n\\t (c+NC-1,r+NR-1): \" << point(c+NC-1,r+NR-1) \n            );\n\n\n        T row_filt[NR+2][NC];\n        for (long rr = 0; rr < NR+2; ++rr)\n        {\n            for (long cc = 0; cc < NC; ++cc)\n            {\n                row_filt[rr][cc] = get_pixel_intensity(img[r+rr-1][c+cc-1])*fe1 + \n                                   get_pixel_intensity(img[r+rr-1][c+cc])*fm + \n                                   get_pixel_intensity(img[r+rr-1][c+cc+1])*fe2;\n            }\n        }\n\n        for (long rr = 0; rr < NR; ++rr)\n        {\n            for (long cc = 0; cc < NC; ++cc)\n            {\n                block[rr][cc] = (row_filt[rr][cc]*fe1 + \n                                row_filt[rr+1][cc]*fm + \n                                row_filt[rr+2][cc]*fe2);\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR,\n        long NC,\n        typename T,\n        typename U,\n        typename in_image_type\n        >\n    inline void separable_3x3_filter_block_rgb (\n        T (&block)[NR][NC],\n        const in_image_type& img_,\n        const long& r,\n        const long& c,\n        const U& fe1, // separable filter end\n        const U& fm,  // separable filter middle \n        const U& fe2  // separable filter end 2\n    ) \n    {\n        const_image_view<in_image_type> img(img_);\n        // make sure requires clause is not broken\n        DLIB_ASSERT(shrink_rect(get_rect(img),1).contains(c,r) &&\n                    shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1),\n            \"\\t void separable_3x3_filter_block_rgb()\"\n            << \"\\n\\t The sub-window doesn't fit inside the given image.\"\n            << \"\\n\\t get_rect(img):       \" << get_rect(img) \n            << \"\\n\\t (c,r):               \" << point(c,r) \n            << \"\\n\\t (c+NC-1,r+NR-1): \" << point(c+NC-1,r+NR-1) \n            );\n\n        T row_filt[NR+2][NC];\n        for (long rr = 0; rr < NR+2; ++rr)\n        {\n            for (long cc = 0; cc < NC; ++cc)\n            {\n                row_filt[rr][cc].red   = img[r+rr-1][c+cc-1].red*fe1   + img[r+rr-1][c+cc].red*fm   + img[r+rr-1][c+cc+1].red*fe2;\n                row_filt[rr][cc].green = img[r+rr-1][c+cc-1].green*fe1 + img[r+rr-1][c+cc].green*fm + img[r+rr-1][c+cc+1].green*fe2;\n                row_filt[rr][cc].blue  = img[r+rr-1][c+cc-1].blue*fe1  + img[r+rr-1][c+cc].blue*fm  + img[r+rr-1][c+cc+1].blue*fe2;\n            }\n        }\n\n        for (long rr = 0; rr < NR; ++rr)\n        {\n            for (long cc = 0; cc < NC; ++cc)\n            {\n                block[rr][cc].red   = row_filt[rr][cc].red*fe1   + row_filt[rr+1][cc].red*fm   + row_filt[rr+2][cc].red*fe2;\n                block[rr][cc].green = row_filt[rr][cc].green*fe1 + row_filt[rr+1][cc].green*fm + row_filt[rr+2][cc].green*fe2;\n                block[rr][cc].blue  = row_filt[rr][cc].blue*fe1  + row_filt[rr+1][cc].blue*fm  + row_filt[rr+2][cc].blue*fe2;\n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double gaussian (\n        double x, \n        double sigma\n    )\n    {\n        DLIB_ASSERT(sigma > 0,\n            \"\\tdouble gaussian(x)\"\n            << \"\\n\\t sigma must be bigger than 0\"\n            << \"\\n\\t sigma: \" << sigma \n        );\n        const double sqrt_2_pi = 2.5066282746310002416123552393401041626930;\n        return 1.0/(sigma*sqrt_2_pi) * std::exp( -(x*x)/(2*sigma*sigma));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    matrix<T,0,1> create_gaussian_filter (\n        double sigma,\n        int max_size \n    )\n    {\n        DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1,\n            \"\\t matrix<T,0,1> create_gaussian_filter()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t sigma: \" << sigma \n            << \"\\n\\t max_size:  \" << max_size \n        );\n\n        // Adjust the size so that the ratio of the gaussian values isn't huge.  \n        // This only matters when T is an integer type.  However, we do it for\n        // all types so that the behavior of this function is always relatively\n        // the same.\n        while (gaussian(0,sigma)/gaussian(max_size/2,sigma) > 50)\n            --max_size;\n\n\n        matrix<double,0,1> f(max_size);\n        for (long i = 0; i < f.size(); ++i)\n        {\n            f(i) = gaussian(i-max_size/2, sigma);\n        }\n\n        if (is_float_type<T>::value == false)\n        {\n            f /= f(0);\n            return matrix_cast<T>(round(f));\n        }\n        else\n        {\n            return matrix_cast<T>(f);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    rectangle gaussian_blur (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        double sigma = 1,\n        int max_size = 1001\n    )\n    {\n        DLIB_ASSERT(sigma > 0 && max_size > 0 && (max_size%2)==1 &&\n                    is_same_object(in_img, out_img) == false,\n            \"\\t void gaussian_blur()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t sigma: \" << sigma \n            << \"\\n\\t max_size:  \" << max_size \n            << \"\\n\\t is_same_object(in_img,out_img): \" << is_same_object(in_img,out_img) \n        );\n\n        if (sigma < 18)\n        {\n            typedef typename pixel_traits<typename image_traits<out_image_type>::pixel_type>::basic_pixel_type type;\n            typedef typename promote<type>::type ptype;\n            const matrix<ptype,0,1>& filt = create_gaussian_filter<ptype>(sigma, max_size);\n            ptype scale = sum(filt);\n            scale = scale*scale;\n            return spatially_filter_image_separable(in_img, out_img, filt, filt, scale);\n        }\n        else\n        {\n            // For large sigma we need to use a type with a lot of precision to avoid\n            // numerical problems.  So we use double here.\n            typedef double ptype;\n            const matrix<ptype,0,1>& filt = create_gaussian_filter<ptype>(sigma, max_size);\n            ptype scale = sum(filt);\n            scale = scale*scale;\n            return spatially_filter_image_separable(in_img, out_img, filt, filt, scale);\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n    template <\n        bool add_to,\n        typename image_type1, \n        typename image_type2\n        >\n    void sum_filter (\n        const image_type1& img_,\n        image_type2& out_,\n        const rectangle& rect\n    )\n    {\n        const_image_view<image_type1> img(img_);\n        image_view<image_type2> out(out_);\n        DLIB_ASSERT(img.nr() == out.nr() &&\n                    img.nc() == out.nc() &&\n                    is_same_object(img_,out_) == false,\n            \"\\t void sum_filter()\"\n            << \"\\n\\t Invalid arguments given to this function.\"\n            << \"\\n\\t img.nr(): \" << img.nr() \n            << \"\\n\\t img.nc(): \" << img.nc() \n            << \"\\n\\t out.nr(): \" << out.nr() \n            << \"\\n\\t out.nc(): \" << out.nc() \n            << \"\\n\\t is_same_object(img_,out_): \" << is_same_object(img_,out_) \n        );\n\n        typedef typename image_traits<image_type1>::pixel_type pixel_type;\n        typedef typename promote<pixel_type>::type ptype;\n\n        std::vector<ptype> column_sum;\n        column_sum.resize(img.nc() + rect.width(),0);\n\n        const long top    = -1 + rect.top();\n        const long bottom = -1 + rect.bottom();\n        long left = rect.left()-1;\n\n        // initialize column_sum at row -1\n        for (unsigned long j = 0; j < column_sum.size(); ++j)\n        {\n            rectangle strip(left,top,left,bottom);\n            strip = strip.intersect(get_rect(img));\n            if (!strip.is_empty())\n            {\n                column_sum[j] = sum(matrix_cast<ptype>(subm(mat(img),strip)));\n            }\n\n            ++left;\n        }\n\n\n        const rectangle area = get_rect(img);\n\n        // Save width to avoid computing it over and over.\n        const long width = rect.width();\n\n\n        // Now do the bulk of the filtering work.\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            // set to sum at point(-1,r). i.e. should be equal to sum(mat(img), translate_rect(rect, point(-1,r)))\n            // We compute it's value in the next loop.\n            ptype cur_sum = 0; \n\n            // Update the first part of column_sum since we only work on the c+width part of column_sum\n            // in the main loop.\n            const long top    = r + rect.top() - 1;\n            const long bottom = r + rect.bottom();\n            for (long k = 0; k < width; ++k)\n            {\n                const long right  = k-width + rect.right();\n\n                const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;\n                const ptype tr_corner = area.contains(right,top)    ? img[top][right]    : 0;\n                // update the sum in this column now that we are on the next row\n                column_sum[k] = column_sum[k] + br_corner - tr_corner;\n                cur_sum += column_sum[k];\n            }\n\n            for (long c = 0; c < img.nc(); ++c)\n            {\n                const long top    = r + rect.top() - 1;\n                const long bottom = r + rect.bottom();\n                const long right  = c + rect.right();\n\n                const ptype br_corner = area.contains(right,bottom) ? img[bottom][right] : 0;\n                const ptype tr_corner = area.contains(right,top)    ? img[top][right]    : 0;\n\n                // update the sum in this column now that we are on the next row\n                column_sum[c+width] = column_sum[c+width] + br_corner - tr_corner;\n\n                // add in the new right side of the rect and subtract the old right side.\n                cur_sum = cur_sum + column_sum[c+width] - column_sum[c];\n\n                if (add_to)\n                    out[r][c] += static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum);\n                else\n                    out[r][c] = static_cast<typename image_traits<image_type2>::pixel_type>(cur_sum);\n            }\n        }\n    }\n    }\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void sum_filter (\n        const image_type1& img,\n        image_type2& out,\n        const rectangle& rect\n    )\n    {\n        impl::sum_filter<true>(img,out,rect);\n    }\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void sum_filter_assign (\n        const image_type1& img,\n        image_type2& out,\n        const rectangle& rect\n    )\n    {\n        set_image_size(out, num_rows(img), num_columns(img));\n        impl::sum_filter<false>(img,out,rect);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        class fast_deque\n        {\n        /*\n            This is a fast and minimal implementation of std::deque for \n            use with the max_filter.  \n\n            This object assumes that no more than max_size elements\n            will ever be pushed into it at a time.\n        */\n        public:\n\n            explicit fast_deque(unsigned long max_size)\n            {\n                // find a power of two that upper bounds max_size\n                mask = 2;\n                while (mask < max_size)\n                    mask *= 2;\n\n                clear();\n\n                data.resize(mask);\n                --mask;  // make into bit mask\n            }\n\n            void clear()\n            {\n                first = 1;\n                last = 0;\n                size = 0;\n            }\n\n            bool empty() const\n            {\n                return size == 0;\n            }\n\n            void pop_back()\n            {\n                last = (last-1)&mask;\n                --size;\n            }\n\n            void push_back(const T& item)\n            {\n                last = (last+1)&mask;\n                ++size;\n                data[last] = item;\n            }\n\n            void pop_front()\n            {\n                first = (first+1)&mask;\n                --size;\n            }\n\n            const T& front() const\n            {\n                return data[first];\n            }\n\n            const T& back() const\n            {\n                return data[last];\n            }\n\n        private:\n\n            std::vector<T> data;\n            unsigned long mask;\n            unsigned long first;\n            unsigned long last;\n            unsigned long size;\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void max_filter (\n        image_type1& img_,\n        image_type2& out_,\n        const long width,\n        const long height,\n        const typename image_traits<image_type1>::pixel_type& thresh\n    )\n    {\n        image_view<image_type1> img(img_);\n        image_view<image_type2> out(out_);\n        DLIB_ASSERT( width > 0 &&\n                     height > 0 &&\n                     out.nr() == img.nr() &&\n                     out.nc() == img.nc() &&\n                     is_same_object(img_,out_) == false,\n                \"\\t void max_filter()\"\n                << \"\\n\\t Invalid arguments given to this function.\"\n                << \"\\n\\t img.nr(): \" << img.nr() \n                << \"\\n\\t img.nc(): \" << img.nc() \n                << \"\\n\\t out.nr(): \" << out.nr() \n                << \"\\n\\t out.nc(): \" << out.nc() \n                << \"\\n\\t width:    \" << width \n                << \"\\n\\t height:   \" << height \n                << \"\\n\\t is_same_object(img_,out_): \" << is_same_object(img_,out_) \n                     );\n\n        typedef typename image_traits<image_type1>::pixel_type pixel_type;\n\n\n        dlib::impl::fast_deque<std::pair<long,pixel_type> > Q(std::max(width,height));\n\n        const long last_col = std::max(img.nc(), ((width-1)/2));\n        const long last_row = std::max(img.nr(), ((height-1)/2));\n\n        // run max filter along rows of img\n        for (long r = 0; r < img.nr(); ++r)\n        {\n            Q.clear();\n            for (long c = 0; c < (width-1)/2 && c < img.nc(); ++c)\n            {\n                while (!Q.empty() && img[r][c] >= Q.back().second)\n                    Q.pop_back();\n                Q.push_back(std::make_pair(c,img[r][c]));\n            }\n\n            for (long c = (width-1)/2; c < img.nc(); ++c)\n            {\n                while (!Q.empty() && img[r][c] >= Q.back().second)\n                    Q.pop_back();\n                while (!Q.empty() && Q.front().first <= c-width)\n                    Q.pop_front();\n                Q.push_back(std::make_pair(c,img[r][c]));\n\n                img[r][c-((width-1)/2)] = Q.front().second;\n            }\n\n            for (long c = last_col; c < img.nc() + ((width-1)/2); ++c)\n            {\n                while (!Q.empty() && Q.front().first <= c-width)\n                    Q.pop_front();\n\n                img[r][c-((width-1)/2)] = Q.front().second;\n            }\n        }\n\n        // run max filter along columns of img.  Store result in out.\n        for (long cc = 0; cc < img.nc(); ++cc)\n        {\n            Q.clear();\n            for (long rr = 0; rr < (height-1)/2 && rr < img.nr(); ++rr)\n            {\n                while (!Q.empty() && img[rr][cc] >= Q.back().second)\n                    Q.pop_back();\n                Q.push_back(std::make_pair(rr,img[rr][cc]));\n            }\n\n            for (long rr = (height-1)/2; rr < img.nr(); ++rr)\n            {\n                while (!Q.empty() && img[rr][cc] >= Q.back().second)\n                    Q.pop_back();\n                while (!Q.empty() && Q.front().first <= rr-height)\n                    Q.pop_front();\n                Q.push_back(std::make_pair(rr,img[rr][cc]));\n\n                out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh);\n            }\n\n            for (long rr = last_row; rr < img.nr() + ((height-1)/2); ++rr)\n            {\n                while (!Q.empty() && Q.front().first <= rr-height)\n                    Q.pop_front();\n\n                out[rr-((height-1)/2)][cc] += std::max(Q.front().second, thresh);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SPATIAL_FILTERINg_H_\n\n\n"
  },
  {
    "path": "dlib/image_transforms/spatial_filtering_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SPATIAL_FILTERINg_ABSTRACT_\n#ifdef DLIB_SPATIAL_FILTERINg_ABSTRACT_\n\n#include \"../pixel.h\"\n#include \"../matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP,\n        typename T\n        >\n    rectangle spatially_filter_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP>& filter,\n        T scale = 1,\n        bool use_abs = false,\n        bool add_to = false\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_img and out_img do not contain pixels with an alpha channel.  That is,\n              pixel_traits::has_alpha is false for the pixels in these objects.\n            - is_same_object(in_img, out_img) == false \n            - T must be some scalar type\n            - filter.size() != 0\n            - scale != 0\n            - if (in_img doesn't contain grayscale pixels) then\n                - use_abs == false && add_to == false\n                  (i.e. You can only use the use_abs and add_to options with grayscale images)\n        ensures\n            - Applies the given spatial filter to in_img and stores the result in out_img (i.e.\n              cross-correlates in_img with filter).  Also divides each resulting pixel by scale.  \n            - The intermediate filter computations will be carried out using variables of type EXP::type.\n              This is whatever scalar type is used inside the filter matrix. \n            - Pixel values are stored into out_img using the assign_pixel() function and therefore\n              any applicable color space conversion or value saturation is performed.  Note that if \n              add_to is true then the filtered output value will be added to out_img rather than \n              overwriting the original value.\n            - if (in_img doesn't contain grayscale pixels) then\n                - The filter is applied to each color channel independently.\n            - if (use_abs == true) then\n                - pixel values after filtering that are < 0 are converted to their absolute values.\n            - The filter is applied such that it's centered over the pixel it writes its\n              output into.  For centering purposes, we consider the center element of the\n              filter to be filter(filter.nr()/2,filter.nc()/2).  This means that the filter\n              that writes its output to a pixel at location point(c,r) and is W by H (width\n              by height) pixels in size operates on exactly the pixels in the rectangle\n              centered_rect(point(c,r),W,H) within in_img.\n            - Pixels close enough to the edge of in_img to not have the filter still fit \n              inside the image are always set to zero.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n            - returns a rectangle which indicates what pixels in #out_img are considered \n              non-border pixels and therefore contain output from the filter.\n            - if (use_abs == false && all images and filers contain float types) then\n                - This function will use SIMD instructions and is particularly fast.  So if\n                  you can use this form of the function it can give a decent speed boost.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    rectangle spatially_filter_image_separable (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        T scale = 1,\n        bool use_abs = false,\n        bool add_to = false\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_img and out_img do not contain pixels with an alpha channel.  That is,\n              pixel_traits::has_alpha is false for the pixels in these objects.\n            - is_same_object(in_img, out_img) == false \n            - T must be some scalar type\n            - scale != 0\n            - row_filter.size() != 0\n            - col_filter.size() != 0\n            - is_vector(row_filter) == true\n            - is_vector(col_filter) == true\n            - if (in_img doesn't contain grayscale pixels) then\n                - use_abs == false && add_to == false\n                  (i.e. You can only use the use_abs and add_to options with grayscale images)\n        ensures\n            - Applies the given separable spatial filter to in_img and stores the result in out_img.  \n              Also divides each resulting pixel by scale.  Calling this function has the same\n              effect as calling the regular spatially_filter_image() routine with a filter,\n              FILT, defined as follows: \n                - FILT(r,c) == col_filter(r)*row_filter(c)\n            - The intermediate filter computations will be carried out using variables of type EXP1::type.\n              This is whatever scalar type is used inside the row_filter matrix. \n            - Pixel values are stored into out_img using the assign_pixel() function and therefore\n              any applicable color space conversion or value saturation is performed.  Note that if \n              add_to is true then the filtered output value will be added to out_img rather than \n              overwriting the original value.\n            - if (in_img doesn't contain grayscale pixels) then\n                - The filter is applied to each color channel independently.\n            - if (use_abs == true) then\n                - pixel values after filtering that are < 0 are converted to their absolute values\n            - The filter is applied such that it's centered over the pixel it writes its\n              output into.  For centering purposes, we consider the center element of the\n              filter to be FILT(col_filter.size()/2,row_filter.size()/2).  This means that\n              the filter that writes its output to a pixel at location point(c,r) and is W\n              by H (width by height) pixels in size operates on exactly the pixels in the\n              rectangle centered_rect(point(c,r),W,H) within in_img.\n            - Pixels close enough to the edge of in_img to not have the filter still fit \n              inside the image are always set to zero.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n            - returns a rectangle which indicates what pixels in #out_img are considered \n              non-border pixels and therefore contain output from the filter.\n            - if (use_abs == false && all images and filers contain float types) then\n                - This function will use SIMD instructions and is particularly fast.  So if\n                  you can use this form of the function it can give a decent speed boost.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2\n        >\n    rectangle float_spatially_filter_image_separable (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        out_image_type& scratch,\n        bool add_to = false\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_img, out_img, row_filter, and col_filter must all contain float type elements.\n            - is_same_object(in_img, out_img) == false \n            - row_filter.size() != 0\n            - col_filter.size() != 0\n            - is_vector(row_filter) == true\n            - is_vector(col_filter) == true\n        ensures\n            - This function is identical to the above spatially_filter_image_separable()\n              function except that it can only be invoked on float images with float\n              filters.  In fact, spatially_filter_image_separable() invokes\n              float_spatially_filter_image_separable() in those cases.  So why is\n              float_spatially_filter_image_separable() in the public API?  The reason is\n              because the separable filtering routines internally allocate an image each\n              time they are called.  If you want to avoid this memory allocation then you\n              can call float_spatially_filter_image_separable() and provide the scratch\n              image as input.  This allows you to reuse the same scratch image for many\n              calls to float_spatially_filter_image_separable() and thereby avoid having it\n              allocated and freed for each call.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type,\n        typename EXP1,\n        typename EXP2,\n        typename T\n        >\n    rectangle spatially_filter_image_separable_down (\n        const unsigned long downsample,\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        const matrix_exp<EXP1>& row_filter,\n        const matrix_exp<EXP2>& col_filter,\n        T scale = 1,\n        bool use_abs = false,\n        bool add_to = false\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_img and out_img do not contain pixels with an alpha channel.  That is,\n              pixel_traits::has_alpha is false for the pixels in these objects.\n            - out_img contains grayscale pixels.\n            - is_same_object(in_img, out_img) == false \n            - T must be some scalar type\n            - scale != 0\n            - is_vector(row_filter) == true\n            - is_vector(col_filter) == true\n            - row_filter.size() % 2 == 1  (i.e. must be odd)\n            - col_filter.size() % 2 == 1  (i.e. must be odd)\n            - downsample > 0\n        ensures\n            - This function is equivalent to calling \n              spatially_filter_image_separable(in_img,out_img,row_filter,col_filter,scale,use_abs,add_to)\n              and then downsampling the output image by a factor of downsample.  Therefore, \n              we will have that:\n                - #out_img.nr() == ceil((double)in_img.nr()/downsample)\n                - #out_img.nc() == ceil((double)in_img.nc()/downsample)\n                - #out_img[r][c] == filtered pixel corresponding to in_img[r*downsample][c*downsample]\n            - returns a rectangle which indicates what pixels in #out_img are considered \n              non-border pixels and therefore contain output from the filter.\n            - Note that the first row and column of non-zero padded data are the following\n                - first_row == ceil(floor(col_filter.size()/2.0)/downsample)\n                - first_col == ceil(floor(row_filter.size()/2.0)/downsample)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR,\n        long NC,\n        typename T,\n        typename U,\n        typename in_image_type\n        >\n    inline void separable_3x3_filter_block_grayscale (\n        T (&block)[NR][NC],\n        const in_image_type& img,\n        const long& r,\n        const long& c,\n        const U& fe1, \n        const U& fm,  \n        const U& fe2 \n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - T and U should be scalar types\n            - shrink_rect(get_rect(img),1).contains(c,r)\n            - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1)\n        ensures\n            - Filters the image in the sub-window of img defined by a rectangle \n              with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1).\n            - The output of the filter is stored in #block.  Note that img will be \n              interpreted as a grayscale image.\n            - The filter used is defined by the separable filter [fe1 fm fe2].  So the\n              spatial filter is thus:\n                fe1*fe1  fe1*fm  fe2*fe1\n                fe1*fm   fm*fm   fe2*fm\n                fe1*fe2  fe2*fm  fe2*fe2\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long NR,\n        long NC,\n        typename T,\n        typename U,\n        typename in_image_type\n        >\n    inline void separable_3x3_filter_block_rgb (\n        T (&block)[NR][NC],\n        const in_image_type& img,\n        const long& r,\n        const long& c,\n        const U& fe1, \n        const U& fm, \n        const U& fe2\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - img must contain RGB pixels, that is pixel_traits::rgb == true for the pixels\n              in img.\n            - T should be a struct with .red .green and .blue members.\n            - U should be a scalar type\n            - shrink_rect(get_rect(img),1).contains(c,r)\n            - shrink_rect(get_rect(img),1).contains(c+NC-1,r+NR-1)\n        ensures\n            - Filters the image in the sub-window of img defined by a rectangle \n              with its upper left corner at (c,r) and lower right at (c+NC-1,r+NR-1).\n            - The output of the filter is stored in #block.  Note that the filter is applied\n              to each color component independently.\n            - The filter used is defined by the separable filter [fe1 fm fe2].  So the\n              spatial filter is thus:\n                fe1*fe1  fe1*fm  fe2*fe1\n                fe1*fm   fm*fm   fe2*fm\n                fe1*fe2  fe2*fm  fe2*fe2\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double gaussian (\n        double x, \n        double sigma\n    );\n    /*!\n        requires\n            - sigma > 0\n        ensures\n            - computes and returns the value of a 1D Gaussian function with mean 0 \n              and standard deviation sigma at the given x value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    matrix<T,0,1> create_gaussian_filter (\n        double sigma,\n        int size \n    );\n    /*!\n        requires\n            - sigma > 0\n            - size > 0 \n            - size is an odd number\n        ensures\n            - returns a separable Gaussian filter F such that:\n                - is_vector(F) == true \n                - F.size() == size \n                - F is suitable for use with the spatially_filter_image_separable() routine\n                  and its use with this function corresponds to running a Gaussian filter \n                  of sigma width over an image.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    rectangle gaussian_blur (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        double sigma = 1,\n        int max_size = 1001\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - in_img and out_img do not contain pixels with an alpha channel.  That is,\n              pixel_traits::has_alpha is false for the pixels in these objects.\n            - is_same_object(in_img, out_img) == false \n            - sigma > 0\n            - max_size > 0\n            - max_size is an odd number\n        ensures\n            - Filters in_img with a Gaussian filter of sigma width.  The actual spatial filter will\n              be applied to pixel blocks that are at most max_size wide and max_size tall (note that\n              this function will automatically select a smaller block size as appropriate).  The \n              results are stored into #out_img.\n            - Pixel values are stored into out_img using the assign_pixel() function and therefore\n              any applicable color space conversion or value saturation is performed.\n            - if (in_img doesn't contain grayscale pixels) then\n                - The filter is applied to each color channel independently.\n            - Pixels close enough to the edge of in_img to not have the filter still fit \n              inside the image are set to zero.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n            - returns a rectangle which indicates what pixels in #out_img are considered \n              non-border pixels and therefore contain output from the filter.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void sum_filter (\n        const image_type1& img,\n        image_type2& out,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - out.nr() == img.nr() \n            - out.nc() == img.nc()\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - is_same_object(img,out) == false\n        ensures\n            - for all valid r and c:\n                - let SUM(r,c) == sum of pixels from img which are inside the rectangle \n                  translate_rect(rect, point(c,r)).\n                - #out[r][c] == out[r][c] + SUM(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void sum_filter_assign (\n        const image_type1& img,\n        image_type2& out,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - is_same_object(img,out) == false\n        ensures\n            - #out.nr() == img.nr() \n            - #out.nc() == img.nc()\n            - for all valid r and c:\n                - let SUM(r,c) == sum of pixels from img which are inside the rectangle \n                  translate_rect(rect, point(c,r)).\n                - #out[r][c] == SUM(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type1, \n        typename image_type2\n        >\n    void max_filter (\n        image_type1& img,\n        image_type2& out,\n        const long width,\n        const long height,\n        const typename image_traits<image_type1>::pixel_type& thresh\n    );\n    /*!\n        requires\n            - out.nr() == img.nr() \n            - out.nc() == img.nc()\n            - image_type1 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - image_type2 == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h and it must contain grayscale pixels.\n            - is_same_object(img,out) == false\n            - width > 0 && height > 0\n        ensures\n            - for all valid r and c:\n                - let MAX(r,c) == maximum of pixels from img which are inside the rectangle \n                  centered_rect(point(c,r), width, height)\n                - if (MAX(r,c) >= thresh)\n                    - #out[r][c] == out[r][c] + MAX(r,c)\n                - else\n                    - #out[r][c] == out[r][c] + thresh \n            - Does not change the size of img.\n            - Uses img as scratch space.  Therefore, the pixel values in img will have\n              been modified by this function.  That is, max_filter() destroys the contents\n              of img. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SPATIAL_FILTERINg_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/image_transforms/thresholding.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_THRESHOLDINg_\n#define DLIB_THRESHOLDINg_ \n\n#include \"../pixel.h\"\n#include \"thresholding_abstract.h\"\n#include \"equalize_histogram.h\"\n#include \"../enable_if.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const unsigned char on_pixel = 255;\n    const unsigned char off_pixel = 0;\n\n// ----------------------------------------------------------------------------------------\n    \n    namespace impl\n    {\n        template <\n            typename U,\n            typename V,\n            typename basic_pixel_type\n            >\n        void partition_pixels_float_work (\n            unsigned long begin,\n            unsigned long end,\n            U&& cumsum,\n            V&& sorted,\n            basic_pixel_type& pix_thresh,\n            unsigned long& int_thresh\n        ) \n        {\n\n            auto histsum = [&](long begin, long end) \n            { \n                return end-begin;\n            };\n            auto histsumi = [&](long begin, long end) \n            { \n                return cumsum[end]-cumsum[begin]; \n            };\n\n            // If we split the pixels into two groups, those < thresh (the left group) and\n            // those >= thresh (the right group), what would the sum of absolute deviations of\n            // each pixel from the mean of its group be?  total_abs(thresh) computes that\n            // value.\n            unsigned long left_idx = 0;\n            unsigned long right_idx = 0;\n            auto total_abs = [&](unsigned long thresh)\n            {\n                auto left_avg = histsumi(begin,thresh);\n                auto tmp = histsum(begin,thresh);\n                if (tmp != 0)\n                    left_avg /= tmp;\n                auto right_avg = histsumi(thresh,end);\n                tmp = histsum(thresh,end);\n                if (tmp != 0)\n                    right_avg /= tmp;\n\n\n                while(left_idx+1 < sorted.size() && sorted[left_idx] <= left_avg)\n                    ++left_idx;\n                while(right_idx+1 < sorted.size() && sorted[right_idx] <= right_avg)\n                    ++right_idx;\n\n                double score = 0;\n                score += left_avg*histsum(begin,left_idx) - histsumi(begin,left_idx); \n                score -= left_avg*histsum(left_idx,thresh) - histsumi(left_idx,thresh); \n                score += right_avg*histsum(thresh,right_idx) - histsumi(thresh,right_idx); \n                score -= right_avg*histsum(right_idx,end) - histsumi(right_idx,end); \n                return score;\n            };\n\n\n\n            int_thresh = begin;\n            double min_sad = std::numeric_limits<double>::infinity();\n            for (unsigned long i = begin; i < end; ++i)\n            {\n                // You can't drop a threshold in-between pixels with identical values.  So\n                // skip thresholds corresponding to this degenerate case.\n                if (i > 0 && sorted[i-1]==sorted[i])\n                    continue;\n\n                double sad = total_abs(i);\n                if (sad <= min_sad)\n                {\n                    min_sad = sad;\n                    int_thresh = i;\n                }\n            }\n\n            pix_thresh = sorted[int_thresh];\n        }\n\n        template <\n            typename U,\n            typename V,\n            typename basic_pixel_type\n            >\n        void recursive_partition_pixels_float (\n            unsigned long begin,\n            unsigned long end,\n            U&& cumsum,\n            V&& sorted,\n            basic_pixel_type& pix_thresh\n        ) \n        {\n            unsigned long int_thresh;\n            partition_pixels_float_work(begin, end, cumsum, sorted, pix_thresh, int_thresh);\n        }\n\n        template <\n            typename U,\n            typename V,\n            typename basic_pixel_type,\n            typename ...T\n            >\n        void recursive_partition_pixels_float (\n            unsigned long begin,\n            unsigned long end,\n            U&& cumsum,\n            V&& sorted,\n            basic_pixel_type& pix_thresh,\n            T&& ...more_thresholds\n        ) \n        {\n            unsigned long int_thresh;\n            partition_pixels_float_work(begin, end, cumsum, sorted, pix_thresh, int_thresh);\n            recursive_partition_pixels_float(int_thresh, end, cumsum, sorted, more_thresholds...);\n        }\n\n        template <\n            typename image_type,\n            typename ...T\n            >\n        void partition_pixels_float (\n            const image_type& img_,\n            typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& pix_thresh,\n            T&& ...more_thresholds\n        ) \n        {\n            /*\n              This is a version of partition_pixels() that doesn't use the histogram to\n              perform a radix sort but rather uses std::sort() as the first processing\n              step.  It is therefor useful in cases where the range of possible pixels is\n              too large for the faster histogram version.\n            */\n\n            COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );\n\n            typedef typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type basic_pixel_type;\n\n            const_image_view<image_type> img(img_);\n\n            std::vector<basic_pixel_type> sorted;\n            sorted.reserve(img.size());\n\n            for (long r = 0; r < img.nr(); ++r)\n            {\n                for (long c = 0; c < img.nc(); ++c)\n                    sorted.emplace_back(get_pixel_intensity(img[r][c]));\n            }\n            std::sort(sorted.begin(), sorted.end());\n\n            std::vector<double> cumsum;\n            cumsum.reserve(sorted.size()+1);\n\n            // create integral array \n            cumsum.emplace_back(0);\n            for (auto& v : sorted)\n                cumsum.emplace_back(cumsum.back()+v);\n\n\n\n            recursive_partition_pixels_float(0, img.size(), cumsum, sorted, pix_thresh, more_thresholds...);\n\n        }\n\n\n        template <typename image_type>\n        struct is_u16img_or_less\n        {\n            typedef typename image_traits<image_type>::pixel_type pixel_type;\n            typedef typename pixel_traits<pixel_type>::basic_pixel_type basic_pixel_type;\n\n            const static bool value = sizeof(basic_pixel_type) <= 2 && pixel_traits<pixel_type>::is_unsigned;\n        };\n    }\n\n    template <\n        typename image_type,\n        typename ...T\n        >\n    typename disable_if<impl::is_u16img_or_less<image_type>>::type\n    partition_pixels (\n        const image_type& img,\n        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& pix_thresh,\n        T&& ...more_thresholds\n    ) \n    {\n        impl::partition_pixels_float(img, pix_thresh, more_thresholds...);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl \n    {\n        template <\n            typename U,\n            typename basic_pixel_type\n            >\n        void partition_pixels_work (\n            unsigned long begin,\n            unsigned long end,\n            U&& total_abs,\n            basic_pixel_type& pix_thresh,\n            unsigned long& int_thresh\n        ) \n        {\n            int_thresh = begin;\n            double min_sad = std::numeric_limits<double>::infinity();\n            for (unsigned long i = begin; i < end; ++i)\n            {\n                double sad = total_abs(begin, i);\n                if (sad <= min_sad)\n                {\n                    min_sad = sad;\n                    int_thresh = i;\n                }\n            }\n\n            pix_thresh = int_thresh;\n        }\n\n        template <\n            typename U,\n            typename basic_pixel_type\n            >\n        void recursive_partition_pixels (\n            unsigned long begin,\n            unsigned long end,\n            U&& total_abs,\n            basic_pixel_type& pix_thresh\n        ) \n        {\n            unsigned long int_thresh;\n            partition_pixels_work(begin, end, total_abs, pix_thresh, int_thresh);\n        }\n\n        template <\n            typename U,\n            typename basic_pixel_type,\n            typename ...T\n            >\n        void recursive_partition_pixels (\n            unsigned long begin,\n            unsigned long end,\n            U&& total_abs,\n            basic_pixel_type& pix_thresh,\n            T&& ...more_thresholds\n        ) \n        {\n            unsigned long int_thresh;\n            partition_pixels_work(begin, end, total_abs, pix_thresh, int_thresh);\n            recursive_partition_pixels(int_thresh, end, total_abs, more_thresholds...);\n        }\n\n    }\n\n    template <\n        typename image_type,\n        typename ...T\n        >\n    typename enable_if<impl::is_u16img_or_less<image_type>>::type\n    partition_pixels (\n        const image_type& img,\n        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& pix_thresh,\n        T&& ...more_thresholds\n    ) \n    {\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<image_type>::pixel_type>::is_unsigned == true );\n\n\n        matrix<unsigned long,1> hist;\n        get_histogram(img,hist);\n\n        // create integral histograms\n        matrix<double,1> cum_hist(hist.size()+1), cum_histi(hist.size()+1);\n        cum_hist(0) = 0;\n        cum_histi(0) = 0;\n        for (long i = 0; i < hist.size(); ++i)\n        {\n            cum_hist(i+1) = cum_hist(i) + hist(i);\n            cum_histi(i+1) = cum_histi(i) + hist(i)*(double)i;\n        }\n\n        auto histsum = [&](long begin, long end) \n        { \n            return cum_hist(end)-cum_hist(begin); \n        };\n        auto histsumi = [&](long begin, long end) \n        { \n            return cum_histi(end)-cum_histi(begin); \n        };\n\n        // If we split the pixels into two groups, those < thresh (the left group) and\n        // those >= thresh (the right group), what would the sum of absolute deviations of\n        // each pixel from the mean of its group be?  total_abs(thresh) computes that\n        // value.\n        auto total_abs = [&](unsigned long begin, unsigned long thresh)\n        {\n            auto left_avg = histsumi(begin,thresh);\n            auto tmp = histsum(begin,thresh);\n            if (tmp != 0)\n                left_avg /= tmp;\n            auto right_avg = histsumi(thresh,hist.size());\n            tmp = histsum(thresh,hist.size());\n            if (tmp != 0)\n                right_avg /= tmp;\n\n\n            const long left_idx = (long)std::ceil(left_avg);\n            const long right_idx = (long)std::ceil(right_avg);\n\n            double score = 0;\n            score += left_avg*histsum(begin,left_idx) - histsumi(begin,left_idx); \n            score -= left_avg*histsum(left_idx,thresh) - histsumi(left_idx,thresh); \n            score += right_avg*histsum(thresh,right_idx) - histsumi(thresh,right_idx); \n            score -= right_avg*histsum(right_idx,hist.size()) - histsumi(right_idx,hist.size()); \n            return score;\n        };\n\n\n        impl::recursive_partition_pixels(0, hist.size(), total_abs, pix_thresh, more_thresholds...);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type\n    partition_pixels (\n        const image_type& img\n    ) \n    {\n        typedef typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type basic_pixel_type;\n        basic_pixel_type thresh;\n        partition_pixels(img, thresh);\n        return thresh;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void threshold_image (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type thresh\n    )\n    {\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                if (get_pixel_intensity(in_img[r][c]) >= thresh)\n                    assign_pixel(out_img[r][c], on_pixel);\n                else\n                    assign_pixel(out_img[r][c], off_pixel);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void threshold_image (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    )\n    {\n        threshold_image(in_img,out_img,partition_pixels(in_img));\n    }\n\n    template <\n        typename image_type\n        >\n    void threshold_image (\n        image_type& img,\n        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type thresh\n    )\n    {\n        threshold_image(img,img,thresh);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    void threshold_image (\n        image_type& img\n    )\n    {\n        threshold_image(img,img,partition_pixels(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void auto_threshold_image (\n        const in_image_type& in_img_,\n        out_image_type& out_img_\n    )\n    {\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::is_unsigned == true );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::is_unsigned == true );\n\n        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);\n\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (image_size(in_img_) == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        unsigned long thresh;\n        // find the threshold we should use\n        matrix<unsigned long,1> hist;\n        get_histogram(in_img_,hist);\n\n        const_image_view<in_image_type> in_img(in_img_);\n\n        // Start our two means (a and b) out at the ends of the histogram\n        long a = 0;\n        long b = hist.size()-1;\n        bool moved_a = true;\n        bool moved_b = true;\n        while (moved_a || moved_b)\n        {\n            moved_a = false;\n            moved_b = false;\n\n            // catch the degenerate case where the histogram is empty\n            if (a >= b)\n                break;\n\n            if (hist(a) == 0)\n            {\n                ++a;\n                moved_a = true;\n            }\n\n            if (hist(b) == 0)\n            {\n                --b;\n                moved_b = true;\n            }\n        }\n        \n        // now do k-means clustering with k = 2 on the histogram. \n        moved_a = true;\n        moved_b = true;\n        while (moved_a || moved_b)\n        {\n            moved_a = false;\n            moved_b = false;\n\n            int64 a_hits = 0;\n            int64 b_hits = 0;\n            int64 a_mass = 0;\n            int64 b_mass = 0;\n\n            for (long i = 0; i < hist.size(); ++i)\n            {\n                // if i is closer to a\n                if (std::abs(i-a) < std::abs(i-b))\n                {\n                    a_mass += hist(i)*i;\n                    a_hits += hist(i);\n                }\n                else // if i is closer to b\n                {\n                    b_mass += hist(i)*i;\n                    b_hits += hist(i);\n                }\n            }\n\n            long new_a = (a_mass + a_hits/2)/a_hits;\n            long new_b = (b_mass + b_hits/2)/b_hits;\n\n            if (new_a != a)\n            {\n                moved_a = true;\n                a = new_a;\n            }\n\n            if (new_b != b)\n            {\n                moved_b = true;\n                b = new_b;\n            }\n        }\n        \n        // put the threshold between the two means we found\n        thresh = (a + b)/2;\n\n        // now actually apply the threshold\n        threshold_image(in_img_,out_img_,thresh);\n    }\n\n    template <\n        typename image_type\n        >\n    void auto_threshold_image (\n        image_type& img\n    )\n    {\n        auto_threshold_image(img,img);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void hysteresis_threshold (\n        const in_image_type& in_img_,\n        out_image_type& out_img_,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type lower_thresh,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type upper_thresh\n    )\n    {\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false );\n        COMPILE_TIME_ASSERT( pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false );\n\n        COMPILE_TIME_ASSERT(pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale);\n\n        DLIB_ASSERT(is_same_object(in_img_, out_img_) == false,\n            \"\\tvoid hysteresis_threshold(in_img_, out_img_, lower_thresh, upper_thresh)\"\n            << \"\\n\\tis_same_object(in_img_,out_img_): \" << is_same_object(in_img_,out_img_) \n            );\n\n        const_image_view<in_image_type> in_img(in_img_);\n        image_view<out_image_type> out_img(out_img_);\n\n        // if there isn't any input image then don't do anything\n        if (in_img.size() == 0)\n        {\n            out_img.clear();\n            return;\n        }\n\n        out_img.set_size(in_img.nr(),in_img.nc());\n        assign_all_pixels(out_img, off_pixel);\n\n        std::vector<std::pair<long,long>> stack;\n        using std::make_pair;\n\n        // now do the thresholding\n        for (long r = 0; r < in_img.nr(); ++r)\n        {\n            for (long c = 0; c < in_img.nc(); ++c)\n            {\n                typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type p;\n                assign_pixel(p,in_img[r][c]);\n                if (p >= upper_thresh)\n                {\n                    // now do line following for pixels >= lower_thresh.\n                    // set the stack position to 0.\n                    stack.push_back(make_pair(r,c));\n\n                    while (stack.size() > 0)\n                    {\n                        const long r = stack.back().first;\n                        const long c = stack.back().second;\n                        stack.pop_back();\n\n                        // This is the base case of our recursion.  We want to stop if we hit a\n                        // pixel we have already visited.\n                        if (out_img[r][c] == on_pixel)\n                            continue;\n\n                        out_img[r][c] = on_pixel;\n\n                        // put the neighbors of this pixel on the stack if they are bright enough\n                        if (r-1 >= 0)\n                        {\n                            if (get_pixel_intensity(in_img[r-1][c]) >= lower_thresh)\n                                stack.push_back(make_pair(r-1, c));\n                            if (c-1 >= 0 && get_pixel_intensity(in_img[r-1][c-1]) >= lower_thresh)\n                                stack.push_back(make_pair(r-1, c-1));\n                            if (c+1 < in_img.nc() && get_pixel_intensity(in_img[r-1][c+1]) >= lower_thresh)\n                                stack.push_back(make_pair(r-1, c+1));\n                        }\n\n                        if (c-1 >= 0 && get_pixel_intensity(in_img[r][c-1]) >= lower_thresh)\n                            stack.push_back(make_pair(r,c-1));\n                        if (c+1 < in_img.nc() && get_pixel_intensity(in_img[r][c+1]) >= lower_thresh)\n                            stack.push_back(make_pair(r,c+1));\n\n                        if (r+1 < in_img.nr())\n                        {\n                            if (get_pixel_intensity(in_img[r+1][c]) >= lower_thresh)\n                                stack.push_back(make_pair(r+1,c));\n                            if (c-1 >= 0 && get_pixel_intensity(in_img[r+1][c-1]) >= lower_thresh)\n                                stack.push_back(make_pair(r+1,c-1));\n                            if (c+1 < in_img.nc() && get_pixel_intensity(in_img[r+1][c+1]) >= lower_thresh)\n                                stack.push_back(make_pair(r+1,c+1));\n                        }\n\n                    } // end while (stack.size() > 0)\n                }\n            }\n        }\n    }\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void hysteresis_threshold (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    )\n    {\n        using basic_pixel_type = typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type;\n\n        basic_pixel_type t1, t2;\n        partition_pixels(in_img, t1, t2);\n        hysteresis_threshold(in_img, out_img, t1, t2);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_THRESHOLDINg_ \n\n"
  },
  {
    "path": "dlib/image_transforms/thresholding_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_THRESHOLDINg_ABSTRACT_\n#ifdef DLIB_THRESHOLDINg_ABSTRACT_ \n\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const unsigned char on_pixel = 255;\n    const unsigned char off_pixel = 0;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type \n    partition_pixels (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n        ensures\n            - Finds a threshold value that would be reasonable to use with\n              threshold_image(img, threshold).  It does this by finding the threshold that\n              partitions the pixels in img into two groups such that the sum of absolute\n              deviations between each pixel and the mean of its group is minimized.\n    !*/\n\n    template <\n        typename image_type,\n        typename ...T\n        >\n    void partition_pixels (\n        const image_type& img,\n        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type& pix_thresh,\n        T&& ...more_thresholds\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<image_type>::pixel_type>::has_alpha == false\n            - more_thresholds == a bunch of parameters of the same type as pix_thresh.\n        ensures\n            - This version of partition_pixels() finds multiple partitions rather than just\n              one partition.  It does this by first partitioning the pixels just as the\n              above partition_pixels(img) does.  Then it forms a new image with only pixels\n              >= that first partition value and recursively partitions this new image.\n              However, the recursion is implemented in an efficient way which is faster than\n              explicitly forming these images and calling partition_pixels(), but the\n              output is the same as if you did.  For example, suppose you called\n              partition_pixels(img, t1, t2, t3).  Then we would have:\n                - t1 == partition_pixels(img)\n                - t2 == partition_pixels(an image with only pixels with values >= t1 in it)\n                - t3 == partition_pixels(an image with only pixels with values >= t2 in it)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void threshold_image (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type thresh\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true  \n            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false\n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false \n        ensures\n            - #out_img == the thresholded version of in_img (in_img is converted to a grayscale\n              intensity image if it is color).  Pixels in in_img with grayscale values >= thresh \n              have an output value of on_pixel and all others have a value of off_pixel.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n    template <\n        typename image_type\n        >\n    void threshold_image (\n        image_type& img,\n        typename pixel_traits<typename image_traits<image_type>::pixel_type>::basic_pixel_type thresh\n    );\n    /*!\n        requires\n            - it is valid to call threshold_image(img,img,thresh);\n        ensures\n            - calls threshold_image(img,img,thresh);\n    !*/\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void threshold_image (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - it is valid to call threshold_image(in_img,out_img,partition_pixels(in_img));\n        ensures\n            - calls threshold_image(in_img,out_img,partition_pixels(in_img));\n    !*/\n\n    template <\n        typename image_type\n        >\n    void threshold_image (\n        image_type& img\n    );\n    /*!\n        requires\n            - it is valid to call threshold_image(img,img,partition_pixels(img));\n        ensures\n            - calls threshold_image(img,img,partition_pixels(img));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void hysteresis_threshold (\n        const in_image_type& in_img,\n        out_image_type& out_img,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type lower_thresh,\n        typename pixel_traits<typename image_traits<in_image_type>::pixel_type>::basic_pixel_type upper_thresh\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true  \n            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false\n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false \n            - is_same_object(in_img, out_img) == false\n        ensures\n            - #out_img == the hysteresis thresholded version of in_img (in_img is converted to a \n              grayscale intensity image if it is color). Pixels in in_img with grayscale \n              values >= upper_thresh have an output value of on_pixel and all others have a \n              value of off_pixel unless they are >= lower_thresh and are connected to a pixel\n              with a value >= upper_thresh, in which case they have a value of on_pixel.  Here\n              pixels are connected if there is a path between them composed of pixels that \n              would receive an output of on_pixel.\n            - #out_img.nc() == in_img.nc()\n            - #out_img.nr() == in_img.nr()\n    !*/\n\n    template <\n        typename in_image_type,\n        typename out_image_type\n        >\n    void hysteresis_threshold (\n        const in_image_type& in_img,\n        out_image_type& out_img\n    );\n    /*!\n        requires\n            - in_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - out_image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h \n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::grayscale == true  \n            - pixel_traits<typename image_traits<in_image_type>::pixel_type>::has_alpha == false\n            - pixel_traits<typename image_traits<out_image_type>::pixel_type>::has_alpha == false \n            - is_same_object(in_img, out_img) == false\n        ensures\n            - performs: hysteresis_threshold(in_img, out_img, t1, t2) where the thresholds\n              are first obtained by calling partition_pixels(in_img, t1, t2).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_THRESHOLDINg_ABSTRACT_ \n\n\n"
  },
  {
    "path": "dlib/image_transforms.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_IMAGE_TRANSFORMs_\n#define DLIB_IMAGE_TRANSFORMs_ \n\n#include \"image_transforms/assign_image.h\"\n#include \"image_transforms/equalize_histogram.h\"\n#include \"image_transforms/morphological_operations.h\"\n#include \"image_transforms/spatial_filtering.h\"\n#include \"image_transforms/thresholding.h\"\n#include \"image_transforms/edge_detector.h\"\n#include \"image_transforms/draw.h\"\n#include \"image_transforms/integral_image.h\"\n#include \"image_transforms/image_pyramid.h\"\n#include \"image_transforms/hough_transform.h\"\n#include \"image_transforms/label_connected_blobs.h\"\n#include \"image_transforms/colormaps.h\"\n#include \"image_transforms/segment_image.h\"\n#include \"image_transforms/interpolation.h\"\n#include \"image_transforms/fhog.h\"\n#include \"image_transforms/lbp.h\"\n#include \"image_transforms/random_color_transform.h\"\n#include \"image_transforms/random_cropper.h\"\n\n#endif // DLIB_IMAGE_TRANSFORMs_\n\n"
  },
  {
    "path": "dlib/interfaces/cmd_line_parser_option.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CMD_LINE_PARSER_OPTIOn_\n#define DLIB_CMD_LINE_PARSER_OPTIOn_\n\n#include <string>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename charT\n        >\n    class cmd_line_parser_option\n    {\n        /*!\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                None of the functions in cmd_line_parser_option will invalidate\n                pointers or references to internal data when called.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a command line option.  \n        !*/\n\n    public:\n\n        typedef charT char_type;\n        typedef std::basic_string<charT> string_type;\n\n        virtual ~cmd_line_parser_option (\n        ) = 0;\n\n        virtual const string_type& name (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the name of this option\n        !*/\n\n        virtual const string_type& group_name (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the name of the group this option is in.  If no group was set for\n                  this option then this function returns \"\".\n        !*/\n\n        virtual const string_type& description (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the description for this option\n        !*/\n\n        virtual unsigned long number_of_arguments( \n        ) const = 0;\n        /*!\n            ensures\n                - returns the number of arguments for this option\n        !*/\n\n        virtual unsigned long count(\n        ) const = 0;\n        /*!\n            ensures\n                - returns the number of times this option appears on the command line.\n        !*/\n\n        virtual const string_type& argument (\n            unsigned long arg = 0,\n            unsigned long N = 0\n        ) const = 0;\n        /*!\n            requires\n                - arg < number_of_arguments()\n                - N < count()\n            ensures\n                - returns the arg-th argument to the Nth occurrence of this \n                  option on the command line.\n        !*/\n\n        inline operator bool (\n        ) const { return count() > 0; }\n        /*!\n            ensures\n                - returns true if this option appears on the command line at all\n        !*/\n\n    protected:\n\n        // restricted functions\n        cmd_line_parser_option& operator=(const cmd_line_parser_option&){return *this;}\n\n    };\n\n    // destructor does nothing\n    template < typename charT >\n    cmd_line_parser_option<charT>::~cmd_line_parser_option() {}\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CMD_LINE_PARSER_OPTIOn_\n\n"
  },
  {
    "path": "dlib/interfaces/enumerable.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ENUMERABLe_INTERFACE_\n#define DLIB_ENUMERABLe_INTERFACE_\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class enumerable\n    {\n        /*!\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                - if (at_start()) then\n                    - all pointers and references to data returned via element() are \n                      invalid.\n                - calling move_next() or reset() invalidates pointers and references to \n                  data returned via element() and only data returned via element().\n                - calling at_start(), current_element_valid(), size(), or element() \n                  does NOT invalidate pointers or references to any internal data.\n\n            INITIAL VALUE\n                current_element_valid() == false \n                at_start() == true\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represent an interface for iterating through the \n                elements in a container.  It starts out one before the first element\n                in the container. \n\n\n                EXAMPLE:  The following loops though all elements in the container\n                          and prints them to cout.\n\n                    container.reset();\n                    while(container.move_next()) {\n                        cout << container.element();\n                    }\n        !*/\n\n    public:\n        typedef T type;\n\n        inline virtual ~enumerable(\n        ) = 0;\n\n        virtual bool at_start (\n        ) const = 0;\n        /*!\n            ensures\n                - returns true if *this represents one position before the first element\n                  in the container (this would also make the current element invalid) \n                  else returns false                \n        !*/\n\n        virtual void reset (\n        ) const = 0;\n        /*!\n            ensures\n                - #current_element_valid() == false \n                - #at_start() == true\n        !*/\n\n        virtual bool current_element_valid (\n        ) const = 0;\n        /*!\n            ensures\n                - returns true if we are currently at a valid element else\n                  returns false \n        !*/\n\n        virtual const T& element (\n        ) const = 0;\n        /*!\n            requires\n                - current_element_valid() == true\n            ensures\n                - returns a const reference to the current element\n        !*/\n\n        virtual T& element (\n        ) = 0;\n        /*!\n            requires\n                - current_element_valid() == true\n            ensures\n                - returns a non-const reference to the current element\n        !*/\n\n        virtual bool move_next (\n        ) const = 0;\n        /*!\n            ensures\n                - moves to the next element.  i.e. #element() will now \n                  return the next element in the container \n                - the return value will be equal to #current_element_valid() \n                - #at_start() == false \n\n                - returns true if there is another element \n                - returns false if there are no more elements in the container\n        !*/\n\n        virtual size_t size (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the number of elements in *this\n        !*/\n\n    protected:\n\n        // restricted functions\n        enumerable& operator=(const enumerable&) {return *this;} // no assignment operator\n\n    };\n\n    // destructor does nothing\n    template <typename T>\n    enumerable<T>::~enumerable() {}\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ENUMERABLe_INTERFACE_\n\n"
  },
  {
    "path": "dlib/interfaces/map_pair.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAP_PAIr_INTERFACE_\n#define DLIB_MAP_PAIr_INTERFACE_\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename T1,\n        typename T2\n        >\n    class map_pair  \n    {\n        /*!\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                None of the functions in map_pair will invalidate\n                pointers or references to internal data when called.\n\n            WHAT THIS OBJECT REPRESENTS\n                this object is used to return the key/value pair used in the \n                map and hash_map containers when using the enumerable interface.\n\n                note that the enumerable interface is defined in\n                interfaces/enumerable.h\n        !*/\n\n    public:\n        typedef T1 key_type;\n        typedef T2 value_type;\n\n        map_pair() = default;\n        map_pair(const map_pair&) = default;\n\n        virtual ~map_pair(\n        )=0;\n\n        virtual const T1& key( \n        ) const =0;\n        /*!\n            ensures\n                - returns a const reference to the key\n        !*/\n\n        virtual const T2& value(\n        ) const =0;\n        /*!\n            ensures\n                - returns a const reference to the value associated with key\n        !*/\n\n        virtual T2& value(\n        )=0;\n        /*!\n            ensures\n                - returns a non-const reference to the value associated with key\n        !*/\n\n    protected:\n\n        // restricted functions\n        map_pair<T1,T2>& operator=(const map_pair<T1,T2>&) {return *this;} // no assignment operator\n\n    };\n\n    // destructor does nothing\n    template <typename T1,typename T2> \n    map_pair<T1,T2>::~map_pair () {}\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAP_PAIr_INTERFACE_\n\n"
  },
  {
    "path": "dlib/interfaces/remover.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_REMOVER_KERNEl_INTERFACE_\n#define DLIB_REMOVER_KERNEl_INTERFACE_\n\n#include <functional>\n\n\nnamespace dlib\n{\n\n    template <\n        typename T\n        >\n    class remover \n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T is swappable by a global swap() and                \n                T must have a default constructor\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                The size() function does not invalidate pointers or \n                references to internal data.  All other functions have no such \n                guarantee.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some generalized interface for removing\n                single items from container classes.                  \n        !*/\n        \n\n        public:\n            typedef T type;\n\n            virtual ~remover(\n            ); \n            /*!\n                ensures\n                    - all resources associated with *this have been released.\n            !*/\n\n            virtual void remove_any (\n                T& item\n            ) = 0;\n            /*!\n                requires \n                    - size() != 0\n                ensures\n                    - #size() == size() - 1\n                    - removes an element from *this and swaps it into item.  \n                    - if (*this implements the enumerable interface) then\n                        - #at_start() == true\n            !*/\n\n            virtual size_t size (\n            ) const = 0;\n            /*!\n                ensures\n                    - returns the number of elements in *this\n            !*/\n\n        protected:\n\n            // restricted functions\n            remover& operator=(const remover&) {return *this;}    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename compare\n        >\n    class asc_remover : public remover<T>\n    {\n        /*!\n            REQUIREMENTS ON T\n                T is swappable by a global swap() and                \n                T must have a default constructor and\n                T must be comparable by compare where compare is a functor compatible with std::less \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the same thing as remover except\n                that remove_any() will remove elements in ascending order\n                according to the compare functor.  \n        !*/\n    public:\n        typedef compare compare_type;\n\n    protected:\n        // restricted functions\n        asc_remover& operator=(const asc_remover&) {return *this;}    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range\n        >\n    class pair_remover \n    {\n\n        /*!\n            REQUIREMENTS ON domain\n                domain is swappable by a global swap() and                \n                domain must have a default constructor\n\n            REQUIREMENTS ON range\n                range is swappable by a global swap() and\n                range must have a default constructor\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                The size() function does not invalidate pointers or \n                references to internal data.  All other functions have no such \n                guarantee.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some generalized interface for removing\n                pairs from container classes which enforce some kind of pairing on\n                the elements that they contain.  \n        !*/\n        \n        public:\n            typedef domain domain_type;\n            typedef range range_type;\n\n            virtual ~pair_remover(\n            ); \n            /*!\n                ensures\n                    - all resources associated with *this have been released.\n            !*/\n\n            virtual void remove_any (\n                domain& d,\n                range& r\n            ) = 0;\n            /*!\n                requires                     \n                    - &d != &r (i.e. d and r cannot be the same variable) \n                    - size() != 0\n                ensures\n                    - #size() == size() - 1\n                    - removes an element from the domain of *this and swaps it\n                      into d.  \n                    - removes the element in *this's range that is associated \n                      with #d and swaps it into r.\n                    - if (*this implements the enumerable interface) then\n                        - #at_start() == true\n            !*/\n\n            virtual size_t size (\n            ) const = 0;\n            /*!\n                ensures\n                    - returns the number of elements in *this \n            !*/\n\n\n        protected:\n\n            // restricted functions\n            pair_remover& operator=(const pair_remover&) {return *this;}    // assignment operator\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename compare\n        >\n    class asc_pair_remover : public pair_remover<domain,range>\n    {\n        /*!\n            REQUIREMENTS ON domain\n                domain is swappable by a global swap() and                \n                domain must have a default constructor and\n                domain must be comparable by compare where compare is a functor compatible with std::less \n\n            REQUIREMENTS ON range\n                range is swappable by a global swap() and\n                range must have a default constructor\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the same thing as pair_remover except\n                that remove_any() will remove domain elements in ascending \n                order according to the compare functor.  \n        !*/\n    public:\n        typedef compare compare_type;\n\n    protected:\n        // restricted functions\n        asc_pair_remover& operator=(const asc_pair_remover&) {return *this;}    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    // destructor does nothing\n    template <typename T>\n    remover<T>::~remover() {}\n\n    // destructor does nothing\n    template <typename domain, typename range>\n    pair_remover<domain,range>::~pair_remover() {}\n\n\n// ----------------------------------------------------------------------------------------\n\n\n}\n\n#endif // DLIB_REMOVER_KERNEl_INTERFACE_\n\n"
  },
  {
    "path": "dlib/invoke.h",
    "content": "// Copyright (C) 2021  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_INVOKE_Hh_\n#define DLIB_INVOKE_Hh_\n\n#include \"functional.h\"\n\n#endif //DLIB_INVOKE_Hh_\n"
  },
  {
    "path": "dlib/iomanip",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/iosfwd",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/iosockstream/iosockstream.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IOSOCKSTrEAM_Hh_\n#define DLIB_IOSOCKSTrEAM_Hh_\n\n#include \"iosockstream_abstract.h\"\n\n#include <iostream>\n#include <memory>\n\n#include \"../sockstreambuf.h\"\n#include \"../timeout.h\"\n\n#ifdef _MSC_VER\n// Disable the warning about inheriting from std::iostream 'via dominance' since this warning is a warning about\n// visual studio conforming to the standard and is ignorable.  \n// See http://connect.microsoft.com/VisualStudio/feedback/details/733720/inheriting-from-std-fstream-produces-c4250-warning\n// for further details if interested.\n#pragma warning(disable : 4250)\n#endif // _MSC_VER\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------- \n\n    class iosockstream : public std::iostream\n    {\n    public:\n\n        iosockstream(\n        ) :\n            std::iostream(0)\n        {\n        }\n\n        iosockstream( \n            const network_address& addr\n        ) :\n            std::iostream(0)\n        { \n            open(addr); \n        }\n\n        iosockstream( \n            const network_address& addr,\n            unsigned long timeout \n        ) :\n            std::iostream(0)\n        { \n            open(addr, timeout); \n        }\n\n        ~iosockstream()\n        {\n            close();\n        }\n\n        void open (\n            const network_address& addr\n        )\n        {\n            auto_mutex lock(class_mutex);\n            close();\n            con.reset(connect(addr));\n            buf.reset(new sockstreambuf(con.get()));\n            // Note that we use the sockstreambuf's ability to autoflush instead of \n            // telling the iostream::tie() function to tie the stream to itself even though\n            // that should work fine.  The reason we do it this way is because there is a\n            // bug in visual studio 2012 that causes a program to crash when a stream is\n            // tied to itself and then used.  See\n            // http://connect.microsoft.com/VisualStudio/feedback/details/772293/tying-a-c-iostream-object-to-itself-causes-a-stack-overflow-in-visual-studio-2012\n            // for further details.\n            buf->flush_output_on_read();\n            rdbuf(buf.get());\n            clear();\n        }\n\n        void open (\n            const network_address& addr,\n            unsigned long timeout\n        )\n        {\n            auto_mutex lock(class_mutex);\n            close(timeout);\n            con.reset(connect(addr.host_address, addr.port, timeout));\n            buf.reset(new sockstreambuf(con.get()));\n            buf->flush_output_on_read();\n            rdbuf(buf.get());\n            clear();\n        }\n\n        void close(\n            unsigned long timeout = 10000\n        )\n        {\n            auto_mutex lock(class_mutex);\n            rdbuf(0);\n            try\n            {\n                if (buf)\n                {\n                    dlib::timeout t(*con,&connection::shutdown,timeout);\n\n                    // This will flush the sockstreambuf and also destroy it.\n                    buf.reset();\n\n                    if(con->shutdown_outgoing())\n                    {\n                        // there was an error so just close it now and return\n                        con->shutdown();\n                    }\n                    else\n                    {\n                        char junk[100];\n                        // wait for the other end to close their side\n                        while (con->read(junk,sizeof(junk)) > 0);\n                    }\n                }\n            }\n            catch (...)\n            {\n                con.reset();\n                throw;\n            }\n            con.reset();\n        }\n\n        void terminate_connection_after_timeout (\n            unsigned long timeout\n        )\n        {\n            auto_mutex lock(class_mutex);\n            if (con)\n            {\n                con_timeout.reset(new dlib::timeout(*this,&iosockstream::terminate_connection,timeout,con));\n            }\n        }\n\n        void shutdown (\n        ) \n        {\n            auto_mutex lock(class_mutex);\n            if (con)\n                con->shutdown();\n        }\n\n    private:\n\n        void terminate_connection(\n            std::shared_ptr<connection> thecon\n        )\n        {\n            thecon->shutdown();\n        }\n\n        std::unique_ptr<timeout> con_timeout;\n        rmutex class_mutex; \n        std::shared_ptr<connection> con;\n        std::unique_ptr<sockstreambuf> buf;\n\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n}\n\n\n#endif // DLIB_IOSOCKSTrEAM_Hh_\n\n\n"
  },
  {
    "path": "dlib/iosockstream/iosockstream_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_\n#ifdef DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_\n\n#include \"../sockstreambuf/sockstreambuf_abstract.h\"\n\n#include <iostream>\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------- \n\n    class iosockstream : public std::iostream\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an iostream object that reads/writes from a TCP network connection.\n\n                Note that any attempt to read from this stream will automatically flush the\n                stream's output buffers.  \n\n            THREAD SAFETY\n                It is not safe for multiple threads to make concurrent accesses to the same\n                instance of this object (except for calls to shutdown() which are always\n                threadsafe).  Therefore, you should mutex lock an instance of this object\n                if you need to touch it from multiple threads. \n        !*/\n\n    public:\n\n        iosockstream(\n        );\n        /*!\n            ensures\n                - #good() == false\n        !*/\n\n        iosockstream( \n            const network_address& addr\n        );\n        /*!\n            ensures\n                - Attempts to connect to the given network address. \n                - Calling this constructor is equivalent to calling the default constructor\n                  and then invoking open(addr).\n                - #good() == true \n            throws\n                - dlib::socket_error\n                    This exception is thrown if there is some problem that prevents us from\n                    creating the connection.  \n        !*/\n\n        iosockstream( \n            const network_address& addr,\n            unsigned long timeout\n        ); \n        /*!\n            ensures\n                - Attempts to connect to the given network address. \n                - Calling this constructor is equivalent to calling the default constructor\n                  and then invoking open(addr, timeout).\n                - #good() == true \n            throws\n                - dlib::socket_error\n                    This exception is thrown if there is some problem that prevents us from\n                    creating the connection or if timeout milliseconds elapses before the\n                    connect is successful.\n        !*/\n\n        ~iosockstream(\n        );\n        /*!\n            ensures\n                - Invokes close() before destructing the stream.  Therefore, any open\n                  connection will be gracefully closed using the default timeout time.\n                  This also means any data in the stream will be flushed to the connection.\n        !*/\n\n        void open (\n            const network_address& addr\n        );\n        /*!\n            ensures\n                - This object will attempt to create a TCP connection with the remote host\n                  indicated by addr.  \n                - Any previous connection in this iosockstream is closed by calling close()\n                  before we make any new connection.\n                - #good() == true\n                  (i.e. the error flags are reset by calling open())\n            throws\n                - dlib::socket_error\n                    This exception is thrown if there is some problem that prevents us from\n                    creating the connection.  \n        !*/\n\n        void open (\n            const network_address& addr,\n            unsigned long timeout \n        );\n        /*!\n            ensures\n                - This object will attempt to create a TCP connection with the remote host\n                  indicated by addr.  \n                - Any previous connection in this iosockstream is closed by calling close()\n                  before we make any new connection.\n                - #good() == true\n                  (i.e. the error flags are reset by calling open())\n            throws\n                - dlib::socket_error\n                    This exception is thrown if there is some problem that prevents us from\n                    creating the connection or if timeout milliseconds elapses before the\n                    connect is successful.\n        !*/\n\n        void close(\n            unsigned long timeout = 10000\n        );\n        /*!\n            ensures\n                - #good() == false \n                - if (there is an active TCP connection) then\n                    - Flushes any data buffered in the output part of the stream\n                      to the connection.  \n                    - Performs a proper graceful close (i.e. like dlib::close_gracefully()).\n                    - Will only wait timeout milliseconds for the buffer flush and graceful\n                      close to finish before the connection is terminated forcefully.\n                      Therefore, close() will only block for at most timeout milliseconds.\n        !*/\n\n        void terminate_connection_after_timeout (\n            unsigned long timeout\n        );\n        /*!\n            ensures\n                - if (there is an active TCP connection) then\n                    - Any operations on this TCP connection will return error or\n                      end-of-file once timeout milliseconds have elapsed from this call to\n                      terminate_connection_after_timeout().  This is true unless another\n                      call to terminate_connection_after_timeout() is made which gives a\n                      new time.  In this case, the previous call is forgotten and the\n                      timeout is reset.\n                    - This timeout only applies to the current TCP connection.  That is, if\n                      the iosockstream is closed and a new connection is established, any\n                      previous timeouts setup by terminate_connection_after_timeout() do\n                      not apply. \n                - else\n                    - This function has no effect on this object.\n        !*/\n\n        void shutdown (\n        );\n        /*!\n            ensures\n                - Immediately closes the TCP connection and causes all I/O operations on\n                  this object to return an error.  \n                - It is safe to call this function from any thread, therefore, you can use\n                  it to signal when you want a connection to terminate from another thread.\n        !*/\n    };\n\n// ---------------------------------------------------------------------------------------- \n\n}\n\n\n#endif // DLIB_IOSOCKSTrEAM_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/iosockstream.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IOSOCkSTREAM_H_h_\n#define DLIB_IOSOCkSTREAM_H_h_\n\n#include \"iosockstream/iosockstream.h\"\n\n\n#endif // DLIB_IOSOCkSTREAM_H_h_\n\n\n"
  },
  {
    "path": "dlib/iostream",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/is_kind.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_IS_KINd_H_\n#define DLIB_IS_KINd_H_\n\n#include <vector>\n\nnamespace dlib\n{\n    /*!\n        This file contains a set of templates that enable you to determine if\n        a given type implements an abstract interface defined in one of the\n        dlib *_abstract.h files.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct default_is_kind_value { static const bool value = false; };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_graph : public default_is_kind_value\n    {\n        /*!\n            - if (T is an implementation of graph/graph_kernel_abstract.h) then\n                - is_graph<T>::value == true\n            - else\n                - is_graph<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_directed_graph : public default_is_kind_value\n    {\n        /*!\n            - if (T is an implementation of directed_graph/directed_graph_kernel_abstract.h) then\n                - is_directed_graph<T>::value == true\n            - else\n                - is_directed_graph<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename helper = void>\n    struct is_matrix : public default_is_kind_value  \n    {\n        /*!\n            - if (T is some kind of matrix expression from the matrix/matrix_exp_abstract.h component) then\n                - is_matrix<T>::value == true\n            - else\n                - is_matrix<T>::value == false\n        !*/\n\n        // Don't set the helper to anything.  Just let it be void.\n        ASSERT_ARE_SAME_TYPE(helper,void);\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_array2d : public default_is_kind_value  \n    {\n        /*!\n            - if (T is an implementation of array2d/array2d_kernel_abstract.h) then\n                - is_array2d<T>::value == true\n            - else\n                - is_array2d<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_array : public default_is_kind_value  \n    {\n        /*!\n            - if (T is an implementation of array/array_kernel_abstract.h) then\n                - is_array<T>::value == true\n            - else\n                - is_array<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_std_vector : public default_is_kind_value  \n    {\n        /*!\n            - if (T is an implementation of the standard C++ std::vector object) then\n                - is_std_vector<T>::value == true\n            - else\n                - is_std_vector<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_pair : public default_is_kind_value  \n    {\n        /*!\n            - if (T is a std::pair object) then\n                - is_std_vector<T>::value == true\n            - else\n                - is_std_vector<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_rand : public default_is_kind_value  \n    {\n        /*!\n            - if (T is an implementation of rand/rand_kernel_abstract.h) then\n                - is_rand<T>::value == true\n            - else\n                - is_rand<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_config_reader : public default_is_kind_value  \n    {\n        /*!\n            - if (T is an implementation of config_reader/config_reader_kernel_abstract.h) then\n                - is_config_reader<T>::value == true\n            - else\n                - is_config_reader<T>::value == false\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Implementation details\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc> \n    struct is_std_vector<std::vector<T,alloc> >         { const static bool value = true; };\n    template <typename T> struct is_std_vector<T&>      { const static bool value = is_std_vector<T>::value; };\n    template <typename T> struct is_std_vector<const T&>{ const static bool value = is_std_vector<T>::value; };\n    template <typename T> struct is_std_vector<const T> { const static bool value = is_std_vector<T>::value; };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    struct is_pair<std::pair<T,U> > { const static bool value = true; };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_IS_KINd_H_\n\n"
  },
  {
    "path": "dlib/istream",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/java/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\nproject (myproject)\nset(java_package_name net.dlib)\nset(source_files\n   )\n\ninclude(../cmake_utils/release_build_by_default)\n\ninclude_directories(\n   .\n   )\n\n# Additional dependencies\n#add_subdirectory(../../dlib dlib_build)\n#set(additional_link_libraries dlib::dlib)\n\n# Tell swig to put the output files (the shared library and .jar) into the local folder.\nset(install_target_output_folder .)\n\n# Alternatively, instead of using install_target_output_folder, you can tell\n# cmake to output the shared library, java source files, and the jar to\n# separate output folders.  These commands would put them into folders thelib,\n# thesrc, and thejar, respectively.\n#set(install_shared_library_output_folder thelib)\n#set(install_java_source_output_folder    thesrc)\n#set(install_jar_output_folder            thejar)\n\n\ninclude(cmake_swig_jni)\n\n\n"
  },
  {
    "path": "dlib/java/cmake_swig_jni",
    "content": "# This file is used to create SWIG based JNI interfaces to C++ code.  You use\n# it by defining some CMake variables and then include(cmake_swig_jni).  You\n# would make a CMakeLists.txt file that looks like the following:\n#\n#   cmake_minimum_required (VERSION 3.8.0)\n#   project (example)\n#   set(java_package_name \"org.mycompany\")\n#   set(source_files\n#       your_cpp_source.cpp\n#       more_cpp_source.cpp\n#   )\n#\n#   ### We might need to link our code to some other C++ library like dlib.  You\n#   ### can do that by setting additional_link_libraries.  Here is an example of\n#   ### linking to dlib:\n#   include(../../dlib/dlib/cmake)\n#   set(additional_link_libraries dlib::dlib)\n#\n#   ### Tell swig to put the output files into the parent folder of your CMakeLists.txt \n#   ### file when you run make install.\n#   set(install_target_output_folder ..)\n#   include(cmake_swig_jni)\n#\n#   ### Alternatively, instead of using install_target_output_folder, you can tell\n#   ### cmake to output the shared library, java source files, and the jar to\n#   ### separate output folders.  These commands would put them into folders\n#   ### thelib, thesrc, and thejar, respectively.\n#   # set(install_shared_library_output_folder thelib)\n#   # set(install_java_source_output_folder    thesrc)\n#   # set(install_jar_output_folder            thejar)\n\n\n\n\n\n\n################################################################################\n################################################################################\n#                             IMPLEMENTATION DETAILS\n################################################################################\n################################################################################\n\ncmake_minimum_required (VERSION 3.8.0)\n\n# This block of code tries to figure out what the JAVA_HOME environment\n# variable should be by looking at the folder that contains the java\n# executable.\nif (NOT DEFINED ENV{JAVA_HOME})\n   message(STATUS \"JAVA_HOME environment variable not set, trying to guess it...\")\n   find_program(JAVA_EXECUTABLE java)\n   # Resolve symbolic links, hopefully this will give us a path in the proper\n   # java home directory.\n   get_filename_component(JAVA_EXECUTABLE ${JAVA_EXECUTABLE} REALPATH)\n   # Pick out the parent directories\n   get_filename_component(JAVA_PATH1 ${JAVA_EXECUTABLE} PATH)\n   get_filename_component(JAVA_PATH2 ${JAVA_PATH1} PATH)\n   get_filename_component(JAVA_PATH3 ${JAVA_PATH2} PATH)\n   # and search them for include/jni.h.  If we find that then we probably have\n   # a good java home candidate.\n   find_path(AUTO_JAVA_HOME include/jni.h\n      PATHS\n      ${JAVA_PATH1}\n      ${JAVA_PATH2}\n      ${JAVA_PATH3}\n      \"C:/Program Files/Java/jdk*\"\n      \"C:/Program Files (x86)/Java/jdk*\"\n      )\n\n   if (AUTO_JAVA_HOME)\n      set(ENV{JAVA_HOME} ${AUTO_JAVA_HOME})\n      message(STATUS \"Using JAVA_HOME OF \" ${AUTO_JAVA_HOME})\n   else()\n      message(FATAL_ERROR \"Couldn't find a folder for JAVA_HOME.  You must set the JAVA_HOME environment variable before running CMake.\")\n   endif()\nendif()\n\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/lib\")\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE \"${CMAKE_CURRENT_BINARY_DIR}/lib\")\n\nfind_package(SWIG REQUIRED)\nfind_package(Java REQUIRED)\nfind_package(JNI REQUIRED)\ninclude(UseSWIG)\n\nmacro (add_global_switch def_name )\n   if (NOT CMAKE_CXX_FLAGS MATCHES \"${def_name}\")\n      set (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${def_name}\" \n         CACHE STRING \"Flags used by the compiler during all C++ builds.\" \n         FORCE)\n   endif ()\n   if (NOT CMAKE_C_FLAGS MATCHES \"${def_name}\")\n      set (CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${def_name}\" \n         CACHE STRING \"Flags used by the compiler during all C builds.\" \n         FORCE)\n   endif ()\nendmacro()\n\n# SWIG doesn't work if optimizations are enabled and strict aliasing is not\n# turned off.  This is a little wonky but it's how SWIG is.\nif (CMAKE_COMPILER_IS_GNUCXX)\n    add_definitions(-fno-strict-aliasing)\nendif()\nif (UNIX)\n    # we need to make sure all the code is compiled with -fPIC. In particular,\n    # it's important that all the code for the whole project is, not just the\n    # stuff immediately compiled by us in this cmake file.  So we add -fPIC to\n    # the top level cmake flags variables.\n    add_global_switch(-fPIC)\nendif()\n\nset(dlib_root_path ${CMAKE_CURRENT_LIST_DIR}/../../)\n\nstring(REGEX REPLACE \"\\\\.\" \"/\" package_path ${java_package_name})\nstring(REGEX REPLACE \"\\\\..*\" \"\" package_root_name ${java_package_name})\n\ninclude_directories(${dlib_root_path})\n\nset(CMAKE_SWIG_FLAGS -package ${java_package_name} -I${dlib_root_path})\nset(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/lib/java_src/${package_path})\n\nset(output_library_name ${PROJECT_NAME})\n\n# Create the swig.i interface file that swig will run on.  We do it here in\n# the cmake script because this lets us automatically include the correct\n# output library name into the call to System.loadLibrary().\nFILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/swig.i \n        \"\n    // Put the global functions in our api into a java class called global.\n    %module global \n\n    %{\n    #include <exception>\n    #include <stdexcept>\n    static JavaVM *cached_jvm = 0;\n\n    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {\n        cached_jvm = jvm;\n        return JNI_VERSION_1_6;\n    }\n\n    static JNIEnv * JNI_GetEnv() {\n        JNIEnv *env;\n        jint rc = cached_jvm->GetEnv((void **)&env, JNI_VERSION_1_6);\n        if (rc == JNI_EDETACHED)\n            throw std::runtime_error(\\\"current thread not attached\\\");\n        if (rc == JNI_EVERSION)\n            throw std::runtime_error(\\\"jni version not supported\\\");\n        return env;\n    }\n\n    #include \\\"swig_api.h\\\"\n    %}\n\n    // Convert all C++ exceptions into java.lang.Exception\n    %exception {\n        try {\n            $action\n        } catch(std::exception& e) {\n            jclass clazz = jenv->FindClass(\\\"java/lang/Exception\\\");\n            jenv->ThrowNew(clazz, e.what());\n            return $null;\n        }\n    }\n\n    %pragma(java) jniclasscode=%{\n    static { System.loadLibrary(\\\"${output_library_name}\\\"); }\n    %}\n\n    %include \\\"swig_api.h\\\"\n    \"\n)\n\n# There is a bug in CMake's Swig scripts that causes the build to fail if the\n# binary folder doesn't contain a folder with the same name as the binary dir.\n# So we make a subfolder of the same name to avoid that bug.\nget_filename_component(binary_dir_name \"${CMAKE_CURRENT_BINARY_DIR}\" NAME)\nFILE(MAKE_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/${binary_dir_name}\")\n\nset_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/swig.i PROPERTIES CPLUSPLUS ON)\nswig_add_module(${output_library_name} java ${CMAKE_CURRENT_BINARY_DIR}/swig.i ${source_files})\ntarget_compile_features(${output_library_name} PUBLIC cxx_std_14)\n\ninclude_directories(${JNI_INCLUDE_DIRS})\nswig_link_libraries(${output_library_name}  ${additional_link_libraries})\n\n# Things to delete when \"make clean\" is run.\nset(clean_files\n    ${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled\n    ${CMAKE_CURRENT_BINARY_DIR}/lib/java_src \n    )\nset_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES \"${clean_files}\")\n\n# Compile the java files into a jar file and stick it in the lib folder.  Also, one problem\n# with this cmake setup is that it doesn't know that modifications to swig_api.h mean that\n# swig.i is invalidated and thus swig needs to be rerun.  So here we also touch swig.i\n# every time we build to make it always out of date and force swig to run on each build,\n# thus avoiding the stale swig outputs problem that would otherwise irritate people who\n# modify something and attempt to rebuild.\nadd_custom_command(TARGET ${output_library_name} \n   POST_BUILD\n   COMMAND cmake -E echo \"compiling Java files...\"\n   COMMAND cmake -E make_directory \"${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled\"\n   COMMAND ${Java_JAVAC_EXECUTABLE} ${CMAKE_SWIG_OUTDIR}/*.java -d \"${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled\"\n   COMMAND cmake -E echo \"Making jar file...\"\n   COMMAND ${Java_JAR_EXECUTABLE} cvf \"${CMAKE_CURRENT_BINARY_DIR}/lib/${PROJECT_NAME}.jar\" -C \"${CMAKE_CURRENT_BINARY_DIR}/intermediate_files_compiled\" ${package_root_name}\n   COMMAND cmake -E touch swig.i\n   )\n\n\n# Determine the path to our CMakeLists.txt file.\n# There is either a bug (or break in compatability maybe) between versions\n# of cmake that cause the or expression in this regular expression to be\n# necessary.\nstring(REGEX REPLACE \"(cmake_swig_jni|CMakeLists.txt)$\" \"\" base_path ${CMAKE_PARENT_LIST_FILE})\n\n#if the including cmake script set the install_target_output_folder variable\n#then make it so we install the compiled library and jar into that folder\nif (install_target_output_folder)\n    # The directory we will write the output files to.\n    set(install_dir \"${base_path}${install_target_output_folder}\")\n    set(CMAKE_INSTALL_PREFIX \"${install_dir}\")\n    set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION \"${install_dir}\")\n    install(TARGETS ${output_library_name} \n        DESTINATION \"${install_dir}\"\n        )\n    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/${PROJECT_NAME}.jar \n        DESTINATION \"${install_dir}\"\n        )\nendif()\n\nif (install_shared_library_output_folder)\n    set(install_dir \"${base_path}${install_shared_library_output_folder}\")\n    install(TARGETS ${output_library_name} \n        DESTINATION \"${install_dir}\"\n        )\nendif()\n\nif (install_java_source_output_folder)\n    set(install_dir \"${base_path}${install_java_source_output_folder}\")\n    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib/java_src/${package_root_name}\n        DESTINATION \"${install_dir}\"\n        )\nendif()\n\nif (install_jar_output_folder)\n    set(install_dir \"${base_path}${install_jar_output_folder}\")\n    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib/${PROJECT_NAME}.jar \n        DESTINATION \"${install_dir}\"\n        )\nendif()\n\n\n# Copy any system libraries to the output folder.  This really only matters on\n# windows where it's good to have the visual studio runtime show up in the lib\n# folder so that you don't forget to include it in your binary distribution.\nINCLUDE(InstallRequiredSystemLibraries)\nforeach (file_i ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})\n   add_custom_command(TARGET ${output_library_name}\n      POST_BUILD\n      COMMAND cmake -E copy ${file_i} \"${CMAKE_CURRENT_BINARY_DIR}/lib/\"\n      )\nendforeach()\n\n"
  },
  {
    "path": "dlib/java/java_array.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SWIG_JAVA_ARRAY_H_\n#define DLIB_SWIG_JAVA_ARRAY_H_\n\n\n/*\n\n    This file defines three special classes: array, array_view, and array_view_crit.  An\n    array is a simple opaque handle to a java array, like a double[] array.  The array_view\n    and array_view_crit objects allow you to access the contents of an array.  The\n    interfaces of these objects is shown below, but for an example use, suppose you had an\n    array of int in java and you wanted to pass it to C++.  You could create a C++ function\n    like this:\n\n        void my_function(const array_view<int32_t>& array);\n\n    and then within java you could call it with code like this:\n\n       int[] array = new int[100];\n       my_function(array);\n\n    and it will work just like you would expect.  The array_view<int32_t> will usually result in\n    the JVM doing a copy in the background.  However, you can also declare your function\n    like this:\n\n        void my_function(const array_view_crit<int32_t>& array);\n\n    and still call it the same way in java, however, using array_view_crit<int32_t> will usually\n    not result in any copying, and is therefore very fast.  array_view_crit uses the JNI\n    routine GetPrimitiveArrayCritical() to get a lock on the java memory underlying the\n    array.  So it will probably prevent the garbage collector from running while your\n    function is executing.  The JNI documentation is somewhat vague on the limitations of\n    GetPrimitiveArrayCritical(), saying only that you shouldn't hold the lock on the array\n    for \"an extended period\" or call back into the JVM.  Deciding whether or not this\n    matters in your application is left as an exercise for the reader.\n\n\n    There are two ways you can declare your methods if they take an array_view or\n    array_view_crit.  Taking a const reference or a non-const reference.  E.g.\n        void my_function(const array_view<int32_t>& array);\n        void my_function(array_view<int32_t>& array);\n    You can't declare them to be by value.  The non-const version allows you to modify the\n    contents of the array and the modifications will be visible to java, as you would\n    expect.  You can also make functions that take array objects directly, but that's only\n    useful if you want to store the array handle somewhere, like in a member of a long\n    lived class.  You can also write functions that return arrays back to java. E.g.\n        array<int32_t> make_an_array(size_t s) \n        { \n            array<int32_t> arr(s);\n            array_view<int32_t> aview(arr);\n            // Use aview to put data into the array and generally do something useful. \n            ...\n            return arr;\n        }\n    This would create an array and return it as a java int[] array.  \n\n\n    You can also of course use functions taking many arguments, as is normally the case\n    with SWIG.  Finally, these classes work with the following primitive types:\n        - int16_t\n        - int32_t\n        - int64_t\n        - char     (corresponding to java byte)\n        - float\n        - double\n\n\n\n\nnamespace java\n{\n    template <typename T>\n    class array\n    {\n        /!*\n            WHAT THIS OBJECT REPRESENTS\n                This is a handle to a java array.  I.e. a reference to an array instance in\n                java like a double[] or int[].  It doesn't do anything other than tell you\n                the size of the array and allow you to hold a reference to it.\n\n                To access the array contents, you need to create an array_view or\n                array_view_crit from the array.\n        *!/\n    public:\n        array();\n        /!*\n            ensures\n                - #size() == 0\n                - this array is a null reference, i.e. it doesn't reference any array.\n        *!/\n\n        explicit array(size_t new_size);\n        /!*\n            ensures\n                - #size() == new_size\n                - Allocates a new java array.\n                - This array is a reference to the newly allocated java array object.\n        *!/\n\n        size_t size() const;\n        /!*\n            ensures\n                - returns the number of elements in this java array.\n        *!/\n\n        void swap(array& item); \n        /!*\n            ensures\n                - swaps the state of *this and item.\n        *!/\n\n        array(const array& item);\n        array& operator= (const array& item)\n        array(array&& item);\n        array& operator= (array&& item);\n        /!*\n            ensures\n                - The array is copyable, assignable, and movable.  All copies will\n                  reference the same underlying array.  So the copies are shallow, as is\n                  normally the case with java reference semantics.\n        *!/\n    };\n\n\n\n    template <typename T>\n    class array_view\n    {\n        /!*\n            WHAT THIS OBJECT REPRESENTS\n                This is a view into a java array object.  It allows you to access the\n                values stored in an array and modify them if you want to.\n\n                You should only create array_view objects locally in a function since an\n                array_view is only valid as long as the array it references exists.  So\n                don't store array_view objects in the member area of a class or globally.\n        *!/\n\n    public:\n        array_view();\n        /!*\n            ensures\n                - #size() == 0\n                - #data() == nullptr\n        *!/\n\n        array_view(const array<T>& arr, bool might_be_modified=true); \n        /!*\n            ensures\n                - #size() == arr.size()\n                - #data() == a pointer to the beginning of the array data referenced by arr.\n                - When you get a view on a java array, sometimes the JVM will actually\n                  give you a pointer to a copy of the original array.  You therefore have\n                  to tell the JVM if you modified the array when you are done using it.  If\n                  you say you modified it then the JVM will perform another copy from your\n                  memory buffer back into the JVM.  The state of might_be_modified controls\n                  if we do this.  So if you are going to modify the array via this\n                  array_view you should set might_be_modified==true.\n        *!/\n\n        size_t size() const; \n        /!*\n            ensures\n                - returns the number of elements in this java array.\n        *!/\n\n        T* data(); \n        const T* data() const; \n        /!*\n            ensures\n                - returns a pointer to the beginning of the array.  Or nullptr if this is a\n                  handle to null, rather than an actual array instance.\n        *!/\n\n        T* begin(); \n        T* end(); \n        const T* begin() const; \n        const T* end() const; \n        /!*\n            ensures\n                - returns iterators to the start and one-past-the-end of the array, as is\n                  the convention for iterator ranges in C++.\n        *!/\n\n        T& operator[](size_t i); \n        const T& operator[](size_t i) const; \n        /!*\n            ensures\n                - returns data()[i]\n        *!/\n\n    private:\n        // this object is non-copyable.\n        array_view(const array_view&);\n        array_view& operator=(const array_view&);\n    };\n\n\n    template <typename T>\n    class array_view_crit\n    {\n        /!*\n            WHAT THIS OBJECT REPRESENTS\n                This is just like an array_view and has an identical interface.  The only\n                difference is that we use the JNI call GetPrimitiveArrayCritical() to get a\n                critical lock on the array's memory.  Therefore, using array_view_crit is\n                usually faster than array_view since it avoids any unnecessary copying back\n                and forth between the JVM. \n\n                However, this critical lock can block the JVM's garbage collector from\n                running.  So don't create long lived array_view_crit objects.\n        *!/\n    };\n\n}\n*/\n\n\n\n\n\n\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              IMPLEMENTATION DETAILS\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n\n\n\n\n\n\n\nnamespace java\n{\n\ntemplate <typename T>\nclass array_view_base\n{\npublic:\n    array_view_base() = default;\n\n    size_t size() const { return sz; }\n    T* data() { return pdata; }\n    const T* data() const { return pdata; }\n\n    T* begin() { return pdata; }\n    T* end() { return pdata+sz; }\n    const T* begin() const { return pdata; }\n    const T* end() const { return pdata+sz; }\n\n    T& operator[](size_t i) { return pdata[i]; }\n    const T& operator[](size_t i) const { return pdata[i]; }\n\nprotected:\n    T* pdata = nullptr;\n    size_t sz = 0;\n\nprivate:\n    // this object is non-copyable\n    array_view_base(const array_view_base&);\n    array_view_base& operator=(const array_view_base&);\n\n};\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\ntemplate <typename T>\nstruct find_java_array_type;\n\ntemplate <> struct find_java_array_type<int16_t> { typedef jshortArray type; };\ntemplate <> struct find_java_array_type<int32_t> { typedef jintArray type; };\ntemplate <> struct find_java_array_type<int64_t> { typedef jlongArray type; };\ntemplate <> struct find_java_array_type<char>    { typedef jbyteArray type; };\ntemplate <> struct find_java_array_type<float>   { typedef jfloatArray type; };\ntemplate <> struct find_java_array_type<double>  { typedef jdoubleArray type; };\n\njshortArray  create_java_array(int16_t, size_t size) { return JNI_GetEnv()->NewShortArray(size); }\njintArray    create_java_array(int32_t, size_t size) { return JNI_GetEnv()->NewIntArray(size); }\njlongArray   create_java_array(int64_t, size_t size) { return JNI_GetEnv()->NewLongArray(size); }\njbyteArray   create_java_array(char,    size_t size) { return JNI_GetEnv()->NewByteArray(size); }\njfloatArray  create_java_array(float,   size_t size) { return JNI_GetEnv()->NewFloatArray(size); }\njdoubleArray create_java_array(double , size_t size) { return JNI_GetEnv()->NewDoubleArray(size); }\n\ntemplate <typename T>\nclass array\n{\npublic:\n\n    typedef typename find_java_array_type<T>::type java_type;\n\n    array() {}\n\n    explicit array(size_t size) \n    {\n        ref = create_java_array(T(),size);\n        is_global_ref = false;\n    }\n\n    array(java_type ref_)\n    {\n        if (ref_)\n        {\n            ref = (java_type)JNI_GetEnv()->NewGlobalRef(ref_);\n            is_global_ref = true;\n        }\n    }\n\n#ifndef SWIG\n    array(array&& item)\n    {\n        ref = item.ref;\n        is_global_ref = item.is_global_ref;\n        item.ref = NULL;\n        item.is_global_ref = false;\n    }\n    array& operator= (array&& item)\n    {\n        array(std::move(item)).swap(*this);\n        return *this;\n    }\n#endif\n\n    ~array()\n    {\n        if (ref)\n        {\n            // Don't delete the reference if it's a local reference, since the only reason\n            // we will normally be using array object's that contain local references\n            // is because we plan on returning the newly constructed array back to the JVM,\n            // which automatically frees local references using the normal JVM garbage\n            // collection scheme.\n            if (is_global_ref)\n                JNI_GetEnv()->DeleteGlobalRef(ref);\n\n            ref = NULL;\n            is_global_ref = false;\n        }\n    }\n\n    size_t size() const \n    { \n        if (ref)\n            return JNI_GetEnv()->GetArrayLength(ref); \n        else\n            return 0;\n    }\n\n    array(const array& item)\n    {\n        array(item.ref).swap(*this);\n    }\n\n    array& operator= (const array& item)\n    {\n        array(item).swap(*this);\n        return *this;\n    }\n\n    operator java_type() const { return ref;}\n\n    void swap(array& item) \n    { \n        std::swap(ref, item.ref);  \n        std::swap(is_global_ref, item.is_global_ref);  \n    }\n\nprivate:\n    java_type ref = NULL;\n    bool is_global_ref = false;\n};\n\n#ifdef SWIG\n// Tell SWIG to not use it's SwigValueWrapper stuff on array objects since they aren't\n// needed and it causes superfluous construction and destruction of array objects.\n%feature(\"novaluewrapper\") array<int16_t>;\n%template() array<int16_t>;\n%feature(\"novaluewrapper\") array<int32_t>;\n%template() array<int32_t>;\n%feature(\"novaluewrapper\") array<int64_t>;\n%template() array<int64_t>;\n%feature(\"novaluewrapper\") array<char>;\n%template() array<char>;\n%feature(\"novaluewrapper\") array<float>;\n%template() array<float>;\n%feature(\"novaluewrapper\") array<double>;\n%template() array<double>;\n#endif\n\n#ifdef SWIG\n%define tostring(token) \n    #token\n%enddef\n\n%define define_javaObjectRef_converion(type, java_type)\n    // Define array conversions for non-const arrays\n    %typemap(jtype)       (array<type>)  \"java_type[]\"\n    %typemap(jstype)      (array<type>)  \"java_type[]\"\n    %typemap(jni)         (array<type>)  tostring(j##java_type##Array)\n    %typemap(javain)      (array<type>)  \"$javainput\"\n    %typemap(in)          (array<type>)  { $1 = java::array<type>($input); }\n    %typemap(javaout)     (array<type>)  {return $jnicall; }   \n    %typemap(out)         (array<type>)  {jresult = result;}\n\n    %typemap(jtype)       (array<type>&)  \"java_type[]\"\n    %typemap(jstype)      (array<type>&)  \"java_type[]\"\n    %typemap(jni)         (array<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (array<type>&)  \"$javainput\"\n    %typemap(arginit)     (array<type>&) { $1 = &temp$argnum; }\n    %typemap(in)          (array<type>&) (java::array<type> temp) { *($1) = java::array<type>($input); }\n\n    %typemap(jtype)       (const array<type>&)  \"java_type[]\"\n    %typemap(jstype)      (const array<type>&)  \"java_type[]\"\n    %typemap(jni)         (const array<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (const array<type>&)  \"$javainput\"\n    %typemap(arginit)     (const array<type>&) { $1 = &temp$argnum; }\n    %typemap(in)          (const array<type>&) (java::array<type> temp) { *($1) = java::array<type>($input); }\n%enddef\ndefine_javaObjectRef_converion(int16_t,short)\ndefine_javaObjectRef_converion(int32_t,int)\ndefine_javaObjectRef_converion(int64_t,long)\ndefine_javaObjectRef_converion(char,byte)\ndefine_javaObjectRef_converion(float,float)\ndefine_javaObjectRef_converion(double,double)\n\n#endif\n// ----------------------------------------------------------------------------------------\n\ntemplate <typename T> class array_view;\n\n#define JAVA_ARRAY_CLASS_SPEC(ctype, type, Type)                                               \\\ntemplate <> class array_view<ctype> : public array_view_base<ctype>                               \\\n{                                                                                           \\\npublic:                                                                                     \\\n    ~array_view() { clear(); }                                                                 \\\n    array_view() {}                                                                            \\\n    array_view(const array<ctype>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} \\\n    void reset(JNIEnv* jenv_, j##type##Array arr, bool might_be_modified_) {                  \\\n        clear();                                                                            \\\n        jenv = jenv_;                                                                       \\\n        oldArr = arr;                                                                       \\\n        if (arr) {                                                                          \\\n            pdata = (ctype*)jenv->Get##Type##ArrayElements(arr, 0);                         \\\n            sz = jenv->GetArrayLength(arr);                                                 \\\n        }                                                                                   \\\n        might_be_modified = might_be_modified_;                                             \\\n    }                                                                                       \\\nprivate:                                                                                    \\\n    void clear() {                                                                          \\\n        if (pdata) {                                                                        \\\n            jenv->Release##Type##ArrayElements(oldArr, (j##type*)pdata, might_be_modified?0:JNI_ABORT); \\\n            pdata = nullptr;                                                                \\\n            sz = 0;                                                                         \\\n        }                                                                                   \\\n    }                                                                                       \\\n    JNIEnv* jenv = nullptr;                                                                 \\\n    j##type##Array oldArr;                                                                  \\\n    bool might_be_modified;                                                                   \\\n};\n\nJAVA_ARRAY_CLASS_SPEC(int16_t,short, Short)\nJAVA_ARRAY_CLASS_SPEC(int32_t,int, Int)\nJAVA_ARRAY_CLASS_SPEC(int64_t,long, Long)\nJAVA_ARRAY_CLASS_SPEC(char,byte, Byte)\nJAVA_ARRAY_CLASS_SPEC(float,float, Float)\nJAVA_ARRAY_CLASS_SPEC(double,double, Double)\n\n \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n\ntemplate <typename T, typename JARR> \nclass array_view_crit_base \n{\npublic:\n    array_view_crit_base() = default;\n\n    size_t size() const { return sz; }\n    T* data() { return pdata; }\n    const T* data() const { return pdata; }\n\n    T* begin() { return pdata; }\n    T* end() { return pdata+sz; }\n    const T* begin() const { return pdata; }\n    const T* end() const { return pdata+sz; }\n    T& operator[](size_t i) { return pdata[i]; }\n    const T& operator[](size_t i) const { return pdata[i]; }\n\n    ~array_view_crit_base() { clear(); }\n\n    void reset(JNIEnv* jenv_, JARR arr, bool might_be_modified_)\n    {\n        clear();\n        jenv = jenv_;\n        oldArr = arr;\n        if (arr) \n        {\n            pdata = (T*)jenv->GetPrimitiveArrayCritical(arr, 0);\n            sz = jenv->GetArrayLength(arr);\n        }\n        might_be_modified = might_be_modified_;\n    }\n\nprivate:\n\n    void clear()\n    {\n        if (pdata) {\n            jenv->ReleasePrimitiveArrayCritical(oldArr, pdata, might_be_modified?0:JNI_ABORT);\n            pdata = nullptr;\n            sz = 0;\n        }\n    }\n\n    // this object is non-copyable\n    array_view_crit_base(const array_view_crit_base&);\n    array_view_crit_base& operator=(const array_view_crit_base&);\n\n    T* pdata = nullptr;\n    size_t sz = 0;\n    JNIEnv* jenv = nullptr;\n    JARR oldArr;\n    bool might_be_modified;\n};\n\ntemplate <typename T> class array_view_crit;\n\ntemplate <> class array_view_crit<int16_t> : public array_view_crit_base<int16_t,jshortArray> { public: array_view_crit(){} array_view_crit(const array<int16_t>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\ntemplate <> class array_view_crit<int32_t> : public array_view_crit_base<int32_t,jintArray>   { public: array_view_crit(){} array_view_crit(const array<int32_t>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\ntemplate <> class array_view_crit<int64_t> : public array_view_crit_base<int64_t,jlongArray>  { public: array_view_crit(){} array_view_crit(const array<int64_t>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\ntemplate <> class array_view_crit<char>    : public array_view_crit_base<char,jbyteArray>     { public: array_view_crit(){} array_view_crit(const array<char>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\ntemplate <> class array_view_crit<float>   : public array_view_crit_base<float,jfloatArray>   { public: array_view_crit(){} array_view_crit(const array<float>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\ntemplate <> class array_view_crit<double>  : public array_view_crit_base<double,jdoubleArray> { public: array_view_crit(){} array_view_crit(const array<double>& arr, bool might_be_modified_=true){reset(JNI_GetEnv(),arr,might_be_modified_);} };\n\n// ----------------------------------------------------------------------------------------\n\n// Define SWIG typemaps so SWIG will know what to do with the array_view and array_view_crit\n// objects.\n#ifdef SWIG\n%define define_array_converion(type, java_type)\n    // Define array conversions for non-const arrays\n    %typemap(jtype)       (array_view<type>&)  \"java_type[]\"\n    %typemap(jstype)      (array_view<type>&)  \"java_type[]\"\n    %typemap(jni)         (array_view<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (array_view<type>&)  \"$javainput\"\n    %typemap(arginit)     (array_view<type>&)  { $1 = &temp$argnum; }\n    %typemap(in)          (array_view<type>&) (java::array_view<type> temp)  { $1->reset(jenv, $input, true); }\n\n    %typemap(jtype)       (const array_view<type>&)  \"java_type[]\"\n    %typemap(jstype)      (const array_view<type>&)  \"java_type[]\"\n    %typemap(jni)         (const array_view<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (const array_view<type>&)  \"$javainput\"\n    %typemap(arginit)     (const array_view<type>&)  { $1 = &temp$argnum; }\n    %typemap(in)          (const array_view<type>&) (java::array_view<type> temp)  { $1->reset(jenv, $input, false); }\n%enddef\ndefine_array_converion(int16_t,short)\ndefine_array_converion(int32_t,int)\ndefine_array_converion(int64_t,long)\ndefine_array_converion(char,byte)\ndefine_array_converion(float,float)\ndefine_array_converion(double,double)\n\n\n\n%define define_array_crit_converion(type, java_type)\n    // Define array conversions for non-const arrays\n    %typemap(jtype)       (array_view_crit<type>&)  \"java_type[]\"\n    %typemap(jstype)      (array_view_crit<type>&)  \"java_type[]\"\n    %typemap(jni)         (array_view_crit<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (array_view_crit<type>&)  \"$javainput\"\n    %typemap(arginit)     (array_view_crit<type>&)  { $1 = &temp$argnum; }\n    %typemap(in)          (array_view_crit<type>&) (java::array_view_crit<type> temp)  { $1->reset(jenv, $input, true); }\n\n    %typemap(jtype)       (const array_view_crit<type>&)  \"java_type[]\"\n    %typemap(jstype)      (const array_view_crit<type>&)  \"java_type[]\"\n    %typemap(jni)         (const array_view_crit<type>&)  tostring(j##java_type##Array)\n    %typemap(javain)      (const array_view_crit<type>&)  \"$javainput\"\n    %typemap(arginit)     (const array_view_crit<type>&)  { $1 = &temp$argnum; }\n    %typemap(in)          (const array_view_crit<type>&) (java::array_view_crit<type> temp)  { $1->reset(jenv, $input, false); }\n%enddef\ndefine_array_crit_converion(int16_t,short)\ndefine_array_crit_converion(int32_t,int)\ndefine_array_crit_converion(int64_t,long)\ndefine_array_crit_converion(char,byte)\ndefine_array_crit_converion(float,float)\ndefine_array_crit_converion(double,double)\n\n#endif // SWIG\n\n}\n\n#endif // DLIB_SWIG_JAVA_ARRAY_H_\n\n"
  },
  {
    "path": "dlib/java/run_test.sh",
    "content": "\n# build the jar and shared library of C++ code needed by the JVM\nmkdir build\ncd build\ncmake ..\ncmake --build . --config Release --target install\ncd ..\n\n\n# setup paths so the JVM can find our jar and shared library.\nexport LD_LIBRARY_PATH=.\nexport DYLD_LIBRARY_PATH=.\nexport CLASSPATH=myproject.jar:. \n\n# Now compile and run our java test that calls our C++ code.\njavac swig_test.java\njava swig_test\n"
  },
  {
    "path": "dlib/java/swig_api.h",
    "content": "#ifndef EXAMPLE_SWIG_ApI_H_ \n#define EXAMPLE_SWIG_ApI_H_\n\n// This file is essentially a small unit test for the swig cmake scripts and the java array\n// classes.  All it does it define a few simple functions for writing to and summing\n// arrays.  The swig_test.java file then calls these C++ functions and checks if they work\n// correctly.  \n\n\n\n// Let's use java_array.h, a tool for efficiently binding java native arrays to C++\n// function arguments.  You do this by putting this pair of include statements in your\n// swig_api.h file.  Then after that you can use the java::array, java::array_view, and\n// java::array_view_crit classes.  \n#include <dlib/java/java_array.h>\n#ifdef SWIG\n%include <dlib/java/java_array.h>\n#endif\n\n\nusing namespace java;\n\n\n// SWIG can't expose templated functions to java.  We declare these here as helper\n// functions to make the non-templated routines swig will expose easier to write.  You can\n// see these java exposed methods below (i.e. sum(), sum_crit(), assign(), and\n// assign_crit()).\ntemplate <typename T>\nT tsum(const array_view_crit<T>& arr)\n{\n    T s = 0;\n    for (auto& v : arr)\n        s += v;\n    return s;\n}\ntemplate <typename T>\nT tsum(const array_view<T>& arr)\n{\n    T s = 0;\n    for (auto& v : arr)\n        s += v;\n    return s;\n}\ntemplate <typename T>\nvoid tassign(T& arr)\n{\n    for (size_t i = 0; i < arr.size(); ++i)\n        arr[i] = i;\n}\n\n// ----------------------------------------------------------------------------------------\n\n// Now write some functions SWIG will expose to java.  SWIG will automatically expose\n// pretty much any non-template C++ code to java.  So just by defining these functions here\n// we expose them to java.\n// \n// All global C++ functions will appear in java as static member functions of class called\n// \"global\", which is where these sum and assign routines will appear.  You can see\n// examples of java code that calls them in swig_test.java.\n\ninline int sum_crit(const array_view_crit<int16_t>& arr) { return tsum(arr); }\ninline int sum(const array_view<int16_t>& arr) { return tsum(arr); }\ninline void assign_crit(array_view_crit<int16_t>& arr) { tassign(arr); }\ninline void assign(array_view<int16_t>& arr) { tassign(arr); }\n\n\ninline int sum_crit(const array_view_crit<int32_t>& arr) { return tsum(arr); }\ninline int sum(const array_view<int32_t>& arr) { return tsum(arr); }\ninline void assign_crit(array_view_crit<int32_t>& arr) { tassign(arr); }\ninline void assign(array_view<int32_t>& arr) { tassign(arr); }\n\n\ninline int sum_crit(const array_view_crit<int64_t>& arr) { return tsum(arr); }\ninline int sum(const array_view<int64_t>& arr) { return tsum(arr); }\ninline void assign_crit(array_view_crit<int64_t>& arr) { tassign(arr); }\ninline void assign(array_view<int64_t>& arr) { tassign(arr); }\n\n\ninline int sum_crit(const array_view_crit<char>& arr) { return tsum(arr); }\ninline int sum(const array_view<char>& arr) { return tsum(arr); }\ninline void assign_crit(array_view_crit<char>& arr) { tassign(arr); }\ninline void assign(array_view<char>& arr) { tassign(arr); }\n\n\n\ninline double sum_crit(const array_view_crit<double>& arr) { return tsum(arr); }\ninline double sum(const array_view<double>& arr) { return tsum(arr); }\ninline void assign_crit(array_view_crit<double>& arr) { tassign(arr); }\ninline void assign(array_view<double>& arr) { tassign(arr); }\n\n\ninline float sum_crit(array<float> arr) \n{ \n    array_view_crit<float> a(arr);\n    return tsum(a); \n}\ninline float sum(const array<float>& arr) \n{ \n    array_view<float> a(arr);\n    return tsum(a); \n}\ninline void assign_crit(array_view_crit<float>& arr) { tassign(arr); }\ninline void assign(array<float>& arr) \n{ \n    array_view<float> a(arr);\n    tassign(a); \n}\n\narray<int32_t> make_an_array(size_t s)\n{\n    array<int32_t> arr(s);\n    array_view_crit<int32_t> a(arr);\n\n    for (size_t i = 0; i < a.size(); ++i)\n        a[i] = i;\n\n    return arr;\n}\n\n\n// ----------------------------------------------------------------------------------------\n\n\n#endif // EXAMPLE_SWIG_ApI_H_\n\n\n"
  },
  {
    "path": "dlib/java/swig_test.java",
    "content": "\n/*\n\n    This file tests all the ways of using jvector and jvector_crit. \n\n*/\n\n\nimport net.dlib.*;\n\npublic class swig_test\n{\n    public static int sum(long[] arr)\n    {\n        int s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(long[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n\n    public static int sum(byte[] arr)\n    {\n        int s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(byte[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n    public static int sum(short[] arr)\n    {\n        int s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(short[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n\n    public static int sum(int[] arr)\n    {\n        int s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(int[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n\n    public static void assertIs28(int val)\n    {\n        if (val != 28)\n        {\n            throw new RuntimeException(\"Test failed \" + val);\n        }\n    }\n\n    public static void assertIsEqual(int val1, int val2)\n    {\n        if (val1 != val2)\n        {\n            throw new RuntimeException(\"Test failed \" + val1 + \" should be equal to \" + val2);\n        }\n    }\n\n    public static double sum(double[] arr)\n    {\n        double s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(double[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n\n    public static void assertIs28(double val)\n    {\n        if (val != 28)\n        {\n            throw new RuntimeException(\"Test failed \" + val);\n        }\n    }\n\n    public static float sum(float[] arr)\n    {\n        float s = 0;\n        for (int i = 0; i < arr.length; ++i)\n            s += arr[i];\n        return s;\n    }\n    public static void zero(float[] arr)\n    {\n        for (int i = 0; i < arr.length; ++i)\n            arr[i] = 0;\n    }\n\n    public static void assertIs28(float val)\n    {\n        if (val != 28)\n        {\n            throw new RuntimeException(\"Test failed \" + val);\n        }\n    }\n\n    public static void main(String[] args)\n    {\n        {\n            float[] arr = new float[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            double[] arr = new double[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            byte[] arr = new byte[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            long[] arr = new long[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            short[] arr = new short[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            int[] arr = new int[8];\n\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n            }\n            for (int round = 0; round < 100; ++round)\n            {\n                zero(arr); global.assign(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum(arr));\n                zero(arr); global.assign_crit(arr);\n                assertIs28(sum(arr));\n                assertIs28(global.sum_crit(arr));\n            }\n        }\n        {\n            int[] a = global.make_an_array(4);\n            for (int i = 0; i < a.length; ++i)\n            {\n                assertIsEqual(a[i], i);\n            }\n        }\n\n        System.out.println(\"\\n\\n   ALL TESTS COMPLETED SUCCESSFULLY\\n\");\n    }\n}\n"
  },
  {
    "path": "dlib/linker/linker_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LINKER_KERNEL_1_CPp_\n#define DLIB_LINKER_KERNEL_1_CPp_\n#include \"linker_kernel_1.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    linker::\n    linker (\n    ) :\n        running(false),\n        running_signaler(running_mutex),\n        A(0),\n        B(0),\n        service_connection_running_signaler(service_connection_running_mutex)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    linker::\n    linker (\n        connection& a,\n        connection& b\n    ) :\n        running(false),\n        running_signaler(running_mutex),\n        A(0),\n        B(0),\n        service_connection_running_signaler(service_connection_running_mutex)\n    {\n        link(a,b);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    linker::\n    ~linker (\n    )\n    {\n        clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void linker::\n    clear (\n    )\n    {\n\n        // shutdown the connections\n        cons_mutex.lock();\n        if (A != 0 )\n        {\n            A->shutdown();\n            A = 0;\n        }\n        if (B != 0)\n        {\n            B->shutdown();\n            B = 0;\n        }\n        cons_mutex.unlock();\n       \n\n        // wait for the other threads to signal that they have ended\n        running_mutex.lock();\n        while (running == true)\n        {\n            running_signaler.wait();\n        }\n        running_mutex.unlock();\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool linker::\n    is_running (\n    ) const\n    {\n        running_mutex.lock();\n        bool temp = running;\n        running_mutex.unlock();\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void linker::\n    link (\n        connection& a,\n        connection& b\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( \n            this->is_running() == false ,\n            \"\\tvoid linker::link\"\n            << \"\\n\\tis_running() == \" << this->is_running() \n            << \"\\n\\tthis: \" << this\n            );\n\n        running_mutex.lock();\n        running = true;\n        running_mutex.unlock();\n\n        cons_mutex.lock();\n        A = &a;\n        B = &b;\n        cons_mutex.unlock();\n\n        \n\n        service_connection_running_mutex.lock();\n        service_connection_running = true;\n        service_connection_running_mutex.unlock();\n\n        service_connection_error_mutex.lock();\n        service_connection_error = false;\n        service_connection_error_mutex.unlock();\n\n        // if we fail to make the thread\n        if (!create_new_thread(service_connection,this))\n        {\n            a.shutdown();\n            b.shutdown();\n\n            service_connection_running_mutex.lock();\n            service_connection_running = false;\n            service_connection_running_mutex.unlock();\n\n            cons_mutex.lock();\n            A = 0;\n            B = 0;\n            cons_mutex.unlock();  \n\n            running_mutex.lock();\n            running = false;\n            running_mutex.unlock();\n\n\n\n            throw dlib::thread_error (\n                ECREATE_THREAD,\n                \"failed to make new thread in linker::link()\"\n                );\n        }\n\n\n\n        // forward data from a to b\n        char buf[200];\n        long status;\n        bool error = false; // becomes true if one of the connections returns an error\n        while (true)\n        {\n            status = a.read(buf,sizeof(buf));\n            // if there was an error reading from the socket\n            if (status == OTHER_ERROR)\n            {\n                error = true;\n                break;\n            }\n            else if (status == SHUTDOWN)\n            {\n                b.shutdown();\n            }\n\n            if (status <= 0)\n            {\n                // if a has closed normally\n                if (status == 0)\n                    b.shutdown_outgoing();\n                break;            \n            }\n\n            status = b.write(buf,status);\n            // if there was an error writing to the socket then break\n            if (status == OTHER_ERROR)\n            {\n                error = true;\n                break;\n            }\n            \n            if (status <= 0)\n                break;            \n        }\n\n\n        // if there was an error then shutdown both connections\n        if (error)\n        {\n            a.shutdown();\n            b.shutdown();\n        }\n\n\n\n\n        // wait for the other thread to end\n        service_connection_running_mutex.lock();\n        while(service_connection_running)\n        {\n            service_connection_running_signaler.wait();\n        }\n        service_connection_running_mutex.unlock();\n\n\n        // make sure connections are shutdown\n        a.shutdown();\n        b.shutdown();\n\n\n        // both threads have ended so the connections are no longer needed\n        cons_mutex.lock();\n        A = 0;\n        B = 0;\n        cons_mutex.unlock();\n\n\n        // if service_connection terminated due to an error then set error to true\n        service_connection_error_mutex.lock();\n        if (service_connection_error)\n            error = true;\n        service_connection_error_mutex.unlock();\n\n\n        // if we are ending because of an error\n        if (error)\n        {\n\n            // signal that the link() function is ending\n            running_mutex.lock();\n            running = false;\n            running_signaler.broadcast();\n            running_mutex.unlock();\n\n            // throw the exception for this error\n            throw dlib::socket_error (\n                ECONNECTION,\n                \"a connection returned an error in linker::link()\"\n                );\n         \n        }\n\n        // signal that the link() function is ending\n        running_mutex.lock();\n        running = false;\n        running_signaler.broadcast();\n        running_mutex.unlock();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void linker::\n    service_connection (\n        void* param\n    )\n    {\n        linker& p = *static_cast<linker*>(param);\n\n        p.cons_mutex.lock();\n        // if the connections are gone for whatever reason then return\n        if (p.A == 0 || p.B == 0)\n        {\n            // signal that this function is ending\n            p.service_connection_running_mutex.lock();\n            p.service_connection_running = false;\n            p.service_connection_running_signaler.broadcast();\n            p.service_connection_running_mutex.unlock();\n            return;\n        }\n        connection& a = *p.A;\n        connection& b = *p.B;\n        p.cons_mutex.unlock();\n\n\n\n        // forward data from b to a\n        char buf[200];\n        long status;\n        bool error = false;\n        while (true)\n        {\n            status = b.read(buf,sizeof(buf));\n            // if there was an error reading from the socket\n            if (status == OTHER_ERROR)\n            {\n                error = true;\n                break;\n            }\n            else if (status == SHUTDOWN)\n            {\n                a.shutdown();\n            }\n\n\n            if (status <= 0)\n            {\n                // if b has closed normally \n                if (status == 0)\n                    a.shutdown_outgoing();\n                break;            \n            }\n\n\n            status = a.write(buf,status);\n            // if there was an error writing to the socket then break\n            if (status == OTHER_ERROR)\n            {\n                error = true;\n                break;\n            }\n            \n            if (status <= 0)\n                break;            \n        }\n\n\n        // if there was an error then shutdown both connections\n        if (error)\n        {\n            a.shutdown();\n            b.shutdown();\n        }\n\n\n        // if there was an error then signal that\n        if (error)\n        {\n            p.service_connection_error_mutex.lock();\n            p.service_connection_error = true;\n            p.service_connection_error_mutex.unlock();\n        }\n\n        // signal that this function is ending\n        p.service_connection_running_mutex.lock();\n        p.service_connection_running = false;\n        p.service_connection_running_signaler.broadcast();\n        p.service_connection_running_mutex.unlock();\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_LINKER_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/linker/linker_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LINKER_KERNEl_1_\n#define DLIB_LINKER_KERNEl_1_\n\n#include \"linker_kernel_abstract.h\"\n#include \"../threads.h\"\n#include \"../sockets.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n    class linker \n    {\n\n        /*!\n            INITIAL VALUE\n                running             == false\n                A                   == 0\n                B                   == 0\n                running_mutex       == a mutex \n                running_signaler    == a signaler associated with running_mutex\n                cons_mutex          == a mutex\n                service_connection_running          == false\n                service_connection_running_mutex    == a mutex\n                service_connection_running_signaler == a signaler associated with \n                                                       service_connection_running_mutex\n\n                service_connection_error        == false\n                service_connection_error_mutex  == a mutex\n\n               \n\n            CONVENTION\n                running             == is_running()\n                running_mutex       == a mutex for running\n                running_signaler    == a signaler for signaling when\n                                       running becomes false and is associated with\n                                       running_mutex\n                cons_mutex          == a mutex for A and B\n\n                service_connection_running          == true when service_connection() is\n                                                       running or is about to run else\n                                                       false\n                service_connection_running_mutex    == a mutex for service_connection_running\n                service_connection_running_signaler == a signaler associated with \n                                                       service_connection_running_mutex\n\n                if (running) then\n                    A               == address of a from link()\n                    B               == address of b from link()\n                else\n                    A               == 0\n                    B               == 0\n\n                service_connection_error        == service_connection uses this bool\n                                                   to indicate if it terminated due to \n                                                   an error or not\n                service_connection_error_mutex  == a mutex for service_connection_error\n\n\n        !*/\n\n        public:\n\n            // These two typedefs are here for backwards compatibility with previous\n            // versions of dlib.\n            typedef linker kernel_1a;\n            typedef linker kernel_1a_c;\n\n            linker(\n            );\n\n            linker (\n                connection& a,\n                connection& b\n            );\n\n            virtual ~linker(\n            ); \n\n            void clear(\n            );\n\n            bool is_running(\n            ) const;\n\n            void link (\n                connection& a,\n                connection& b\n            );\n\n\n        private:\n\n            static void service_connection (\n                void* param\n            );\n            /*!\n                requires\n                    param == pointer to a linker object\n                ensures\n                    waits for data from b and forwards it to a and\n                    if (b closes normally or is shutdown()) service_connection ends and\n                    if (b closes normally) then a.shutdown_outgoing() is called and\n                    if (a or b returns an error) then a and b are shutdown() \n            !*/\n\n\n            // data members\n            bool running;\n            mutex running_mutex;\n            signaler running_signaler;\n            connection* A;\n            connection* B;\n            mutex cons_mutex;\n\n            bool service_connection_running;\n            mutex service_connection_running_mutex;\n            signaler service_connection_running_signaler;\n\n            bool service_connection_error;\n            mutex service_connection_error_mutex;\n\n            // restricted functions\n            linker(linker&);        // copy constructor\n            linker& operator=(linker&);    // assignment operator\n    };\n\n\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"linker_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_LINKER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/linker/linker_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LINKER_KERNEl_ABSTRACT_\n#ifdef DLIB_LINKER_KERNEl_ABSTRACT_\n\n#include \"../threads/threads_kernel_abstract.h\"\n#include \"../sockets/sockets_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    class linker \n    {\n\n        /*!\n            INITIAL VALUE\n                is_running() == false\n\n               \n            WHAT THIS OBJECT REPRESENTS\n                This object represents something that takes two connections and lets\n                them talk to each other.  i.e. any incoming data from one connection is\n                passed unaltered to the other and vice versa.\n\n                note that linker objects are not swappable.\n\n                Also note that when one connection is closed shutdown_outgoing()\n                is called on the other to signal that no more data will be sent\n                in that direction on the connection.\n                (i.e. the FIN packet is effectively also forwarded by the linker object)\n\n            THREAD SAFETY\n                all member functions are thread-safe.\n\n        !*/\n\n        public:\n\n            linker(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n                    - dlib::thread_error\n            !*/\n\n            linker (\n                connection& a,\n                connection& b\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                    - immediately invokes link(a,b); \n                      (i.e. using this constructor is the same as creating a linker with\n                      the default constructor and then immediately invoking link() on it)\n                throws\n                    - std::bad_alloc\n                    - dlib::thread_error\n            !*/\n\n            virtual ~linker(\n            ); \n            /*!\n                ensures\n                    - all resources associated with *this have been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value \n                    - if (is_running()) then \n                        - the two connections being linked will be shutdown()\n                throws\n                    - std::bad_alloc\n                        if this exception is thrown then the linker object is unusable\n                        until clear() is called and succeeds and\n                        if is_running() then the connections will STILL be shutdown() \n                        even though an exception is being thrown\n            !*/\n\n            bool is_running(\n            ) const;\n            /*!\n                ensures\n                    - returns true if link() is running else\n                    - returns false if link() is not running or has released all its \n                      resources and is about to terminate\n                throws\n                    - std::bad_alloc\n            !*/\n\n\n            void link (\n                connection& a,\n                connection& b\n            );\n            /*!\n                requires\n                    - is_running() == false\n                ensures\n                    - all incoming data from connection a will be forwarded to b \n                    - all incoming data from connection b will be forwarded to a \n                    - #a and #b will have been shutdown() \n                    - link() will block until both of the connections have ended\n                      or an error occurs                     \n                throws\n                    - std::bad_alloc\n                        link() may throw this exception and if it does then the object \n                        will be unusable until clear() is called and succeeds and\n                        connections a and b will be shutdown()\n                    - dlib::socket_error\n                        link() will throw a this exception if one of the connections\n                        returns an error value (being shutdown is not an error). \n                        If this happens then the linker object will be cleared and \n                        have its initial value.  note that if this happens then the \n                        connections being linked will be shutdown()\n                    - dlib::thread_error\n                        link() will throw a this exception if there is a problem \n                        creating new threads.  Or it may throw this exception if there\n                        is a problem creating threading objects. If this happens \n                        then the linker object will be cleared and have its initial value.\n                        note that if this happens then the connections being linked will\n                        be shutdown().\n            !*/\n\n        private:\n\n            // restricted functions\n            linker(linker&);        // copy constructor\n            linker& operator=(linker&);    // assignment operator\n    };\n\n}\n\n#endif // DLIB_LINKER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/linker.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LINKEr_\n#define DLIB_LINKEr_\n\n#include \"linker/linker_kernel_1.h\"\n\n#endif // DLIB_LINKEr_\n\n"
  },
  {
    "path": "dlib/locale",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/logger/extra_logger_headers.cpp",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_EXTRA_LOGGER_HEADERs_CPP_\n#define DLIB_EXTRA_LOGGER_HEADERs_CPP_\n\n#include \"extra_logger_headers.h\"\n#include <ctime>\n#include <cstring>\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n    void print_datetime_logger_header (\n        std::ostream& out,\n        const std::string& logger_name,\n        const log_level& l,\n        const uint64 thread_id\n    )\n    {\n        using namespace std;\n        char* buf;\n\n        time_t t = time(0);\n        buf = ctime(&t);\n        // remove the trailing '\\n'\n        size_t size = strlen(buf);\n        buf[size-1] = '\\0';\n\n        out << l.name << \" (\" << buf << \") [\" << thread_id << \"] \" << logger_name << \": \";\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_EXTRA_LOGGER_HEADERs_CPP_\n\n\n"
  },
  {
    "path": "dlib/logger/extra_logger_headers.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_EXTRA_LOGGER_HEADERs_\n#define DLIB_EXTRA_LOGGER_HEADERs_\n\n#include \"logger_kernel_abstract.h\"\n#include \"logger_kernel_1.h\"\n#include <iostream>\n#include <string>\n#include \"../uintn.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n    void print_datetime_logger_header (\n        std::ostream& out,\n        const std::string& logger_name,\n        const log_level& l,\n        const uint64 thread_id\n    );\n    /*!\n        requires\n            - is not called more than once at a time (i.e. is not called from multiple\n              threads at the same time).\n        ensures\n            - let DATE be the current date and time (e.g. Thu Aug 31 16:41:52 2006).  \n            - prints a string to out in the form:  \"l.name (DATE) [thread_id] logger_name:\"\n    !*/\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef NO_MAKEFILE\n#include \"extra_logger_headers.cpp\"\n#endif\n\n#endif // DLIB_EXTRA_LOGGER_HEADERs_\n\n"
  },
  {
    "path": "dlib/logger/logger_config_file.cpp",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOGGER_CONFIg_FILE_CPP\n#define DLIB_LOGGER_CONFIg_FILE_CPP\n\n#include \"logger_config_file.h\"\n#include <string>\n#include \"../config_reader.h\"\n#include <fstream>\n#include <sstream>\n#include \"../error.h\"\n#include \"../map.h\"\n#include \"../string.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n    namespace logger_config_file_helpers \n    {\n\n// ----------------------------------------------------------------------------------------\n\n        std::ostream& get_file_stream (\n            const std::string& file_name\n        )\n        {\n            using namespace std;\n            static dlib::mutex m;\n            auto_mutex M(m);\n            static dlib::map<string,ostream*>::kernel_1a_c file_map;\n\n            if (file_map.is_in_domain(file_name) == false)\n            {\n                // We won't ever delete this output stream.  It should be around for the\n                // entire life of the program so just let the OS take care of it.\n                ostream* fout = new ofstream(file_name.c_str());\n                if (!(*fout))\n                {\n                    delete fout;\n                    throw error(\"logger_config: unable to open output file \" + file_name);\n                }\n\n                // add this file to our file map\n                string temp(file_name);\n                file_map.add(temp,fout);\n            }\n\n            return *file_map[file_name];\n        }\n\n// ----------------------------------------------------------------------------------------\n\n        log_level string_to_log_level (\n            const std::string& level \n        )\n        {\n            using namespace std;\n            if (level == \"LALL\" || level == \"ALL\" || level == \"all\")\n                return LALL;\n            else if (level == \"LNONE\" || level == \"NONE\" || level == \"none\")\n                return LNONE;\n            else if (level == \"LTRACE\" || level == \"TRACE\" || level == \"trace\")\n                return LTRACE;\n            else if (level == \"LDEBUG\" || level == \"DEBUG\" || level == \"debug\")\n                return LDEBUG;\n            else if (level == \"LINFO\" || level == \"INFO\" || level == \"info\")\n                return LINFO;\n            else if (level == \"LWARN\" || level == \"WARN\" || level == \"warn\")\n                return LWARN;\n            else if (level == \"LERROR\" || level == \"ERROR\" || level == \"error\")\n                return LERROR;\n            else if (level == \"LFATAL\" || level == \"FATAL\" || level == \"fatal\")\n                return LFATAL;\n            else\n            {\n                const int priority = string_cast<int>(level);\n                return log_level(priority,\"CONFIG_FILE_DEFINED\");\n            }\n        }\n\n// ----------------------------------------------------------------------------------------\n        \n        void configure_sub_blocks (\n            const config_reader& cr,\n            const std::string& name \n        )\n        {\n            using namespace std;\n\n            logger dlog(name.c_str());\n\n            if (cr.is_key_defined(\"logging_level\"))\n            {\n                dlog.set_level(string_to_log_level(cr[\"logging_level\"]));\n            }\n\n            if (cr.is_key_defined(\"output\"))\n            {\n                string output = cr[\"output\"];\n                if (output == \"cout\")\n                    dlog.set_output_stream(cout);\n                else if (output == \"cerr\")\n                    dlog.set_output_stream(cerr);\n                else if (output == \"clog\")\n                    dlog.set_output_stream(clog);\n                else\n                {\n                    istringstream sin(output);\n                    string one, two, three;\n                    sin >> one;\n                    sin >> two;\n                    sin >> three;\n                    if (one == \"file\" && three.size() == 0)\n                        dlog.set_output_stream(get_file_stream(two));\n                    else\n                        throw error(\"logger_config: invalid argument to output option: \" + output);\n                }\n\n            } // if (cr.is_key_defined(\"output\"))\n\n            // now configure all the sub-blocks\n            std_vector_c<std::string> blocks;\n            cr.get_blocks(blocks);\n            for (unsigned long i = 0; i < blocks.size(); ++i)\n            {\n                configure_sub_blocks(cr.block(blocks[i]), name + \".\" + blocks[i]);\n            }\n\n        }\n\n// ----------------------------------------------------------------------------------------\n\n    } // namespace\n\n// ----------------------------------------------------------------------------------------\n\n    void configure_loggers_from_file (\n        const std::string& file_name \n    )\n    {\n        std::ifstream fin(file_name.c_str());\n\n        if (!fin)\n            throw logger_config_file_error(\"logger_config: unable to open config file \" + file_name);\n\n        config_reader temp(fin);\n        configure_loggers_from_file(temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void configure_loggers_from_file (\n        const config_reader& main_cr \n    )\n    {\n        using namespace logger_config_file_helpers;\n        using namespace std;\n\n        if (main_cr.is_block_defined(\"logger_config\"))\n        {\n            const config_reader& cr = main_cr.block(\"logger_config\");\n\n            if (cr.is_key_defined(\"logging_level\"))\n            {\n                set_all_logging_levels(string_to_log_level(cr[\"logging_level\"]));\n            }\n\n            if (cr.is_key_defined(\"output\"))\n            {\n                string output = cr[\"output\"];\n                if (output == \"cout\")\n                    set_all_logging_output_streams(cout);\n                else if (output == \"cerr\")\n                    set_all_logging_output_streams(cerr);\n                else if (output == \"clog\")\n                    set_all_logging_output_streams(clog);\n                else\n                {\n                    istringstream sin(output);\n                    string one, two, three;\n                    sin >> one;\n                    sin >> two;\n                    sin >> three;\n                    if (one == \"file\" && three.size() == 0)\n                        set_all_logging_output_streams(get_file_stream(two));\n                    else\n                        throw logger_config_file_error(\"logger_config: invalid argument to output option: \" + output);\n                }\n\n            } // if (cr.is_key_defined(\"output\"))\n\n            // now configure all the sub-blocks\n            std_vector_c<std::string> blocks;\n            cr.get_blocks(blocks);\n            for (unsigned long i = 0; i < blocks.size(); ++i)\n            {\n                configure_sub_blocks(cr.block(blocks[i]), blocks[i]);\n            }\n\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LOGGER_CONFIg_FILE_CPP\n\n\n\n"
  },
  {
    "path": "dlib/logger/logger_config_file.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOGGER_CONFIg_FILE_\n#define DLIB_LOGGER_CONFIg_FILE_ \n\n#include \"logger_kernel_abstract.h\"\n#include \"logger_kernel_1.h\"\n#include <string>\n#include \"../config_reader.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    class logger_config_file_error : public error \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception class used by the configure_loggers_from_file()\n                function defined below.\n        !*/\n    public: \n        logger_config_file_error(const std::string& s):error(s){}\n    };\n\n    void configure_loggers_from_file (\n        const std::string& file_name\n    );\n    /*!\n        ensures\n            - configures the loggers with the contents of the file_name file\n        throws\n            - dlib::logger_config_file_error\n                this exception is thrown if there is a problem reading the config file\n    !*/\n\n    void configure_loggers_from_file (\n        const config_reader& cr \n    );\n    /*!\n        ensures\n            - configures the loggers with the contents of cr.  This function is just like\n              the above version that reads from a file except that it reads from an in-memory\n              config_reader instead.\n        throws\n            - dlib::logger_config_file_error\n                this exception is thrown if there is a problem reading the config file\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!  \n        #  -----------------------------------------------\n        #  ------------- EXAMPLE CONFIG FILE -------------\n        #  -----------------------------------------------\n\n        # The overall format of the config file is the same as the one defined by\n        # the config_reader component of this library.  \n        \n        # This line is a comment line\n\n        # The config file always has a block named logger_config.  This is where all the \n        # config data for the loggers reside.\n        logger_config\n        {\n            # This sets all loggers to the level LINFO since it is just inside the \n            # logger_config block\n            logging_level = info\n\n            # Alternatively we could specify a user defined logging level by\n            # supplying a priority number.  The following line would specify \n            # that only logging levels at or above 100 are printed.  (note that \n            # you would have to comment out the logging_level statement above \n            # to avoid a conflict).\n            # logging_level = 100 \n\n            parent_logger \n            {\n                # This sets all loggers named \"parent_logger\" or children of\n                # loggers with that name to not log at all (i.e. to logging level\n                # LNONE).\n                logging_level = none\n            }\n\n\n            parent_logger2\n            {\n                # set loggers named \"parent_logger2\" and its children loggers\n                # to write their output to a file named out.txt\n                output = file out.txt \n\n                child_logger\n                {\n                    # Set loggers named \"parent_logger2.child_logger\" and children of loggers\n                    # with this name to logging level LALL\n                    logging_level = all\n\n                    # Note that this logger will also log to out.txt because that is what\n                    # its parent does and we haven't overridden it here with something else.\n                    # if we wanted this logger to write to cout instead we could uncomment\n                    # the following line:\n                    # output = cout\n                }\n            }\n        }\n\n        # So in summary, all logger config stuff goes inside a block named logger_config.  Then\n        # inside that block all blocks must be the names of loggers.  There are only two keys,\n        # logging_level and output.\n        #\n        # The valid values of logging_level are:\n        #   \"LALL\", \"LNONE\", \"LTRACE\", \"LDEBUG\", \"LINFO\", \"LWARN\", \"LERROR\", \"LFATAL\",  \n        #   \"ALL\",   \"NONE\",  \"TRACE\",  \"DEBUG\",  \"INFO\",  \"WARN\",  \"ERROR\",  \"FATAL\", \n        #   \"all\",   \"none\",  \"trace\",  \"debug\",  \"info\",  \"warn\",  \"error\",  \"fatal\", or  \n        #   any integral value\n        # \n        # The valid values of output are:\n        #   \"cout\", \"cerr\", \"clog\", or a string of the form \"file some_file_name\"\n        #   which causes the output to be logged to the specified file.\n        #\n    !*/\n\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef NO_MAKEFILE\n#include \"logger_config_file.cpp\"\n#endif\n\n#endif // DLIB_LOGGER_CONFIg_FILE_\n\n\n\n"
  },
  {
    "path": "dlib/logger/logger_kernel_1.cpp",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOGGER_KERNEL_1_CPp_\n#define DLIB_LOGGER_KERNEL_1_CPp_\n\n#include \"logger_kernel_1.h\"\n#include <iostream>\n#include <sstream>\n\nnamespace dlib\n{\n    \n// ----------------------------------------------------------------------------------------\n\n    void set_all_logging_output_streams (\n        std::ostream& out_\n    )\n    {\n        logger::global_data& gd = logger::get_global_data();\n        auto_mutex M(gd.m);\n        gd.loggers.reset();\n        while (gd.loggers.move_next())\n        {\n            gd.loggers.element()->out.rdbuf(out_.rdbuf());\n            gd.loggers.element()->hook.clear();\n        }\n\n        gd.set_output_stream(\"\",out_);\n\n        // set the default hook to be an empty member function pointer\n        logger::hook_mfp hook;\n        gd.set_output_hook(\"\",hook);\n    }\n\n    void set_all_logging_levels (\n        const log_level& new_level\n    )\n    {\n        logger::global_data& gd = logger::get_global_data();\n        auto_mutex M(gd.m);\n        gd.loggers.reset();\n        while (gd.loggers.move_next())\n        {\n            gd.loggers.element()->cur_level = new_level;\n        }\n\n        gd.set_level(\"\",new_level);\n    }\n\n    void set_all_logging_headers (\n        const print_header_type& new_header\n    )\n    {\n        logger::global_data& gd = logger::get_global_data();\n        auto_mutex M(gd.m);\n        gd.loggers.reset();\n        while (gd.loggers.move_next())\n        {\n            gd.loggers.element()->print_header = new_header;\n        }\n\n        gd.set_logger_header(\"\",new_header);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace logger_helper_stuff\n    {\n        class helper\n        {\n        public:\n            helper()\n            {\n                std::ostringstream sout;\n                print_default_logger_header(sout,\"some_name\",LDEBUG,0);\n            }\n        };\n        // do this to make sure all the static members of print_default_logger_header get \n        // initialized when the program turns on.\n        static helper a;\n        // make a logger to make extra sure the static global_data object gets\n        // initialized before any threads start up.  Also do this so that there is always\n        // at least one logger so that the global data won't be deleted until the \n        // program is terminating.\n        static logger log(\"dlib\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void print_default_logger_header (\n        std::ostream& out,\n        const std::string& logger_name,\n        const log_level& l,\n        const uint64 thread_id\n    )\n    {\n        using namespace std;\n        static timestamper ts;\n        static const uint64 first_time = ts.get_timestamp();\n\n        const uint64 cur_time = (ts.get_timestamp() - first_time)/1000;\n        streamsize old_width = out.width(); out.width(5);\n        out << cur_time << \" \" << l.name; \n        out.width(old_width);\n\n        out << \" [\" << thread_id << \"] \" << logger_name << \": \";\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                 global_data stuff\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    logger::global_data::\n    ~global_data (\n    )\n    {\n        unregister_thread_end_handler(*this,&global_data::thread_end_handler);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    logger::global_data::\n    global_data(\n    ) : \n        next_thread_name(1) \n    { \n        // make sure the main program thread always has id 0.  Since there is\n        // a global logger object declared in this file we should expect that \n        // the global_data object will be initialized in the main program thread\n        // so if we call get_thread_id() now we should get the main thread id.\n        thread_id_type main_id = get_thread_id();\n        uint64 id_zero = 0;\n        thread_names.add(main_id,id_zero);\n\n        // set up the defaults\n        auto_flush_table.val = true;\n        streambuf_table.val = std::cout.rdbuf(); \n        header_table.val = print_default_logger_header;\n\n        // also allocate an initial buffer for hook based logging\n        hookbuf.buffer.reserve(1000);\n    }\n\n    logger::global_data::level_container::\n    level_container (\n    ) : val(300,\"ERROR\") {}\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const T& search_tables (\n        const T& c,\n        const std::string& name\n    )\n    {\n        if (c.table.size() == 0 || name.size() == 0)\n            return c;\n\n        const std::string::size_type pos = name.find_first_of(\".\");\n        const std::string first = name.substr(0,pos);\n        std::string last;\n        if (pos != std::string::npos)\n            last = name.substr(pos+1);\n\n        if (c.table.is_in_domain(first))\n        {\n            return search_tables(*c.table[first], last); \n        }\n        else\n        {\n            return c;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    void assign_tables (\n        T& c,\n        const std::string& name,\n        const U& val\n    )\n    {\n        if (name.size() == 0)\n        {\n            c.val = val;\n            c.table.clear();\n            return;\n        }\n\n        const std::string::size_type pos = name.find_first_of(\".\");\n        std::string first = name.substr(0,pos);\n        std::string last;\n        if (pos != std::string::npos)\n            last = name.substr(pos+1);\n\n        if (c.table.is_in_domain(first))\n        {\n            assign_tables(*c.table[first], last, val); \n        }\n        else\n        {\n            std::unique_ptr<T> temp (new T);\n            temp->val = c.val;\n            assign_tables(*temp, last, val);\n            c.table.add(first,temp);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const log_level logger::global_data::\n    level (\n        const std::string& name\n    ) const \n    {  \n        auto_mutex M(m);\n        return search_tables(level_table, name).val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_level (\n        const std::string& name,\n        const log_level& new_level\n    )\n    {\n        auto_mutex M(m);\n        assign_tables(level_table, name, new_level);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    bool logger::global_data::\n    auto_flush (\n        const std::string& name\n    ) const\n    {\n        auto_mutex M(m);\n        return search_tables(auto_flush_table, name).val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_auto_flush (\n        const std::string& name,\n        bool enabled\n    )\n    {\n        auto_mutex M(m);\n        assign_tables(auto_flush_table, name, enabled);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::streambuf* logger::global_data::\n    output_streambuf (\n        const std::string& name\n    )\n    {\n        auto_mutex M(m);\n        return search_tables(streambuf_table, name).val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_output_stream (\n        const std::string& name,\n        std::ostream& out_\n    )\n    {\n        auto_mutex M(m);\n        assign_tables( streambuf_table, name, out_.rdbuf());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_output_stream (\n        const std::string& name,\n        std::streambuf& buf \n    )\n    {\n        auto_mutex M(m);\n        assign_tables( streambuf_table, name, &buf);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    logger::hook_mfp logger::global_data::\n    output_hook (\n        const std::string& name\n    )\n    {\n        auto_mutex M(m);\n        return search_tables(hook_table, name).val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_output_hook (\n        const std::string& name,\n        const hook_mfp& hook\n    )\n    {\n        auto_mutex M(m);\n        assign_tables( hook_table, name, hook);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    print_header_type logger::global_data::\n    logger_header (\n        const std::string& name\n    )\n    {\n        auto_mutex M(m);\n        return search_tables(header_table, name).val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    set_logger_header (\n        const std::string& name,\n        print_header_type ph\n    )\n    {\n        auto_mutex M(m);\n        assign_tables(header_table, name, ph);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    logger::global_data& logger::get_global_data()\n    {\n        // Allocate the global_data on the heap rather than on the stack because\n        // we want to guard against the case where this static object would be destroyed\n        // during program termination BEFORE all logger objects are destroyed.\n        static global_data* gd = new global_data;\n        return *gd;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::global_data::\n    thread_end_handler (\n    )\n    {\n        auto_mutex M(m);\n        thread_id_type id = get_thread_id();\n        thread_id_type junkd;\n        uint64 junkr;\n        thread_names.remove(id,junkd,junkr);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    uint64 logger::global_data::\n    get_thread_name (\n    )\n    {\n        thread_id_type id = get_thread_id();\n        uint64 thread_name;\n        if (thread_names.is_in_domain(id))\n        {\n            thread_name = thread_names[id];\n        }\n        else\n        {\n            if (is_dlib_thread(id))\n                register_thread_end_handler(*this,&global_data::thread_end_handler);\n            thread_name = next_thread_name;\n            thread_names.add(id,thread_name);\n            thread_name = next_thread_name;\n            ++next_thread_name;\n        }\n        return thread_name;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//               logger_stream stuff\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void logger::logger_stream::\n    print_header_and_stuff (\n    )\n    {\n        if (!been_used)\n        {\n            log.gd.m.lock();\n\n            // Check if the output hook is setup.  If it isn't then we print the logger\n            // header like normal.  Otherwise we need to remember to clear out the output\n            // stringstream we always write to.\n            if (log.hook.is_set() == false)\n            {\n                log.logger_header()(log.out,log.name(),l,log.gd.get_thread_name());\n            }\n            else\n            {\n                // Make sure the hook buffer doesn't have any old data in it before we start\n                // logging a new message into it.\n                log.gd.hookbuf.buffer.resize(0);\n            }\n            been_used = true;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void logger::logger_stream::\n    print_end_of_line (\n    )\n    {\n        auto_unlock M(log.gd.m);\n\n        if (log.hook.is_set() == false)\n        {\n            if (log.auto_flush_enabled)\n                log.out << std::endl;\n            else\n                log.out << \"\\n\";\n        }\n        else\n        {\n            // Make sure the buffer is a proper C-string\n            log.gd.hookbuf.buffer.push_back('\\0');\n            // call the output hook with all the info regarding this log message.\n            log.hook(log.name(), l, log.gd.get_thread_name(), &log.gd.hookbuf.buffer[0]);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//         logger stuff\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    logger::\n    logger (  \n        const std::string& name_\n    ) : \n        gd(get_global_data()),\n        logger_name(name_),\n        out(gd.output_streambuf(logger_name)),\n        cur_level(gd.level(logger_name))\n    {\n        DLIB_ASSERT(name_[0] != '\\0',\n                    \"\\tlogger::logger()\"\n                    << \"\\n\\tYou can't make a logger with an empty name\"\n                    << \"\\n\\tthis: \" << this\n        );\n\n        auto_mutex M(gd.m);\n        logger* temp = this;\n        gd.loggers.add(temp);\n\n        // load the appropriate settings\n        print_header        = gd.logger_header(logger_name);\n        auto_flush_enabled  = gd.auto_flush(logger_name);\n        hook                = gd.output_hook(logger_name);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    logger::\n    ~logger (\n    ) \n    { \n        gd.m.lock();\n        gd.loggers.destroy(this);            \n        // if this was the last logger then delete the global data\n        if (gd.loggers.size() == 0)\n        {\n            gd.m.unlock();\n            delete &gd;\n        }\n        else\n        {\n            gd.m.unlock();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LOGGER_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/logger/logger_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOGGER_KERNEl_1_\n#define DLIB_LOGGER_KERNEl_1_\n\n#include <limits>\n#include <memory>\n#include <cstring>\n#include <streambuf>\n#include <vector>\n\n#include \"../threads.h\"\n#include \"../misc_api.h\"\n#include \"../set.h\"\n#include \"logger_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include \"../uintn.h\"\n#include \"../map.h\"\n#include \"../member_function_pointer.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class log_level\n    {\n    public:\n        log_level(\n            int priority_, \n            const char* name_\n        ) : \n            priority(priority_)\n        {\n            strncpy(name,name_,19);\n            name[19] = '\\0';\n        }\n\n        bool operator< (const log_level& rhs) const { return priority <  rhs.priority; }\n        bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }\n        bool operator> (const log_level& rhs) const { return priority >  rhs.priority; }\n        bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }\n\n        int priority;\n        char name[20];\n    };\n\n    inline std::ostream& operator<< (std::ostream& out, const log_level& item)\n    {\n        out << item.name;\n        return out;\n    }\n\n    const log_level LALL  (std::numeric_limits<int>::min(),\"ALL\");\n    const log_level LNONE (std::numeric_limits<int>::max(),\"NONE\");\n    const log_level LTRACE(-100,\"TRACE\");\n    const log_level LDEBUG(0  ,\"DEBUG\");\n    const log_level LINFO (100,\"INFO \");\n    const log_level LWARN (200,\"WARN \");\n    const log_level LERROR(300,\"ERROR\");\n    const log_level LFATAL(400,\"FATAL\");\n\n// ----------------------------------------------------------------------------------------\n\n    void set_all_logging_output_streams (\n        std::ostream& out\n    );\n\n    void set_all_logging_levels (\n        const log_level& new_level\n    );\n\n    typedef void (*print_header_type)(\n        std::ostream& out, \n        const std::string& logger_name, \n        const log_level& l,\n        const uint64 thread_id\n    );\n\n    void set_all_logging_headers (\n        const print_header_type& new_header\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void print_default_logger_header (\n        std::ostream& out,\n        const std::string& logger_name,\n        const log_level& l,\n        const uint64 thread_id\n    );\n\n    template <\n        typename T\n        >\n    void set_all_logging_output_hooks (\n        T& object,\n        void (T::*hook_)(const std::string& logger_name, \n                         const log_level& l,\n                         const uint64 thread_id,\n                         const char* message_to_log)\n    );\n\n    template <\n        typename T\n        >\n    void set_all_logging_output_hooks (\n        T& object\n    )\n    {\n        set_all_logging_output_hooks(object, &T::log);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class logger \n    {\n        /*!\n            INITIAL VALUE\n                - print_header == print_default_logger_header\n                - out.rdbuf() == std::cout.rdbuf()\n                - cur_level == LERROR\n                - auto_flush_enabled == true \n                - hook.is_set() == false\n\n            CONVENTION\n                - print_header == logger_header()\n                - if (hook.is_set() == false) then\n                    - out.rdbuf() == output_streambuf()\n                - else\n                    - out.rdbuf() == &gd.hookbuf\n                    - output_streambuf() == 0\n\n                - cur_level == level()\n                - logger_name == name()\n                - auto_flush_enabled == auto_flush()\n\n                - logger::gd::loggers == a set containing all currently existing loggers.\n                - logger::gd::m == the mutex used to lock everything in the logger\n                - logger::gd::thread_names == a map of thread ids to thread names.  \n                - logger::gd::next_thread_name == the next thread name that will be given out\n                  to a thread when we find that it isn't already in thread_names.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        class logger_stream\n        {\n            /*!\n                INITIAL VALUE\n                    - been_used == false\n\n                CONVENTION\n                    - enabled == is_enabled()\n                    - if (been_used) then\n                        - logger::gd::m is locked\n                        - someone has used the << operator to write something to the\n                          output stream.\n            !*/\n        public:\n            logger_stream (\n                const log_level& l_,\n                logger& log_\n            ) :\n                l(l_),\n                log(log_),\n                been_used(false),\n                enabled (l.priority >= log.cur_level.priority)\n            {}\n\n            inline ~logger_stream(\n            )\n            {\n                if (!been_used)\n                {\n                    return;\n                }\n                else\n                {\n                    print_end_of_line();\n                }\n            }\n\n            bool is_enabled (\n            ) const { return enabled; }\n\n            template <typename T>\n            inline logger_stream& operator << (\n                const T& item\n            )\n            {\n                if (!enabled)\n                {\n                    return *this;\n                }\n                else\n                {\n                    print_header_and_stuff();\n                    log.out << item;\n                    return *this;\n                }\n            }\n\n        private:\n\n            void print_header_and_stuff (\n            );\n            /*!\n                ensures\n                    - if (!been_used) then\n                        - prints the logger header \n                        - locks log.gd.m\n                        - #been_used == true\n            !*/\n\n            void print_end_of_line (\n            );\n            /*!\n                ensures\n                    - prints a newline to log.out\n                    - unlocks log.gd.m\n            !*/\n\n            const log_level& l;\n            logger& log;\n            bool been_used;\n            const bool enabled;\n        }; // end of class logger_stream\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        friend class logger_stream;\n    public:\n\n        typedef member_function_pointer<const std::string&, const log_level&, \n                                        const uint64, const char*> hook_mfp;\n\n        logger (  \n            const std::string& name_\n        );\n\n        virtual ~logger (\n        ); \n\n        const std::string& name (\n        ) const { return logger_name; }\n\n        logger_stream operator << (\n            const log_level& l\n        ) const { return logger_stream(l,const_cast<logger&>(*this)); }\n\n        bool is_child_of (\n            const logger& log\n        ) const\n        {\n            return (name().find(log.name() + \".\") == 0) || (log.name() == name());\n        }\n\n        const log_level level (\n        ) const \n        { \n            auto_mutex M(gd.m);\n            return log_level(cur_level); \n        };\n\n        void set_level (\n            const log_level& new_level\n        )\n        {\n            auto_mutex M(gd.m);\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                if (gd.loggers.element()->is_child_of(*this))\n                    gd.loggers.element()->cur_level = new_level;\n            }\n\n            gd.set_level(logger_name, new_level);\n        }\n\n        bool auto_flush (\n        ) const \n        { \n            auto_mutex M(gd.m);\n            return auto_flush_enabled;\n        };\n\n        void set_auto_flush (\n            bool enabled\n        )\n        {\n            auto_mutex M(gd.m);\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                if (gd.loggers.element()->is_child_of(*this))\n                    gd.loggers.element()->auto_flush_enabled = enabled;\n            }\n\n            gd.set_auto_flush(logger_name, enabled);\n        }\n\n        std::streambuf* output_streambuf (\n        )\n        {\n            auto_mutex M(gd.m);\n\n            // if there is an output hook set then we are supposed to return 0.\n            if (hook)\n                return 0;\n            else\n                return out.rdbuf();\n        }\n\n        template <\n            typename T\n            >\n        void set_output_hook (\n            T& object,\n            void (T::*hook_)(const std::string& logger_name, \n                            const log_level& l,\n                            const uint64 thread_id,\n                            const char* message_to_log)\n        )\n        {\n            auto_mutex M(gd.m);\n            hook.set(object, hook_);\n\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                if (gd.loggers.element()->is_child_of(*this))\n                {\n                    gd.loggers.element()->out.rdbuf(&gd.hookbuf);\n                    gd.loggers.element()->hook = hook;\n                }\n            }\n\n            gd.set_output_hook(logger_name, hook);\n            gd.set_output_stream(logger_name, gd.hookbuf);\n        }\n\n        void set_output_stream (\n            std::ostream& out_\n        ) \n        {\n            auto_mutex M(gd.m);\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                if (gd.loggers.element()->is_child_of(*this))\n                {\n                    gd.loggers.element()->out.rdbuf(out_.rdbuf());\n                    gd.loggers.element()->hook.clear();\n                }\n            }\n\n            gd.set_output_stream(logger_name, out_);\n\n            hook.clear();\n            gd.set_output_hook(logger_name, hook);\n        }\n\n        print_header_type logger_header (\n        ) const { return print_header; }\n\n        void set_logger_header (\n            print_header_type ph\n        )\n        {\n            auto_mutex M(gd.m);\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                if (gd.loggers.element()->is_child_of(*this))\n                    gd.loggers.element()->print_header = ph;\n            }\n\n            gd.set_logger_header(logger_name, ph);\n        }\n\n    private:\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        struct global_data\n        {\n            rmutex m;\n            set<logger*>::kernel_1b loggers;\n            map<thread_id_type,uint64>::kernel_1b thread_names;\n            uint64 next_thread_name;\n\n            // Make a very simple streambuf that writes characters into a std::vector<char>.  We can\n            // use this as the output target for hooks.  The reason we don't just use a std::ostringstream\n            // instead is that this way we can be guaranteed that logging doesn't perform memory allocations.\n            // This is because a std::vector never frees memory.  I.e. its capacity() doesn't go down when\n            // you resize it back to 0.  It just stays the same.\n            class hook_streambuf : public std::streambuf\n            {\n            public:\n                std::vector<char> buffer;\n                int_type overflow ( int_type c)\n                {\n                    if (c != EOF) buffer.push_back(static_cast<char>(c));\n                    return c;\n                }\n\n                std::streamsize xsputn ( const char* s, std::streamsize num)\n                {\n                    buffer.insert(buffer.end(), s, s+num);\n                    return num;\n                }\n            };\n\n            hook_streambuf hookbuf;\n\n            global_data (\n            );\n\n            ~global_data(\n            );\n\n            uint64 get_thread_name (\n            );\n            /*!\n                requires\n                    - m is locked\n                ensures\n                    - returns a unique id for the calling thread.  also makes the number\n                      small and nice unlike what you get from get_thread_id()\n            !*/\n\n            void thread_end_handler (\n            );\n            /*!\n                ensures\n                    - removes the terminated thread from thread_names\n            !*/\n\n            struct level_container\n            {\n                level_container ();\n\n                log_level val;\n                map<std::string,std::unique_ptr<level_container> >::kernel_1b_c table;\n            } level_table;\n\n            const log_level level (\n                const std::string& name\n            ) const; \n            /*!\n                ensures\n                    - returns the level loggers with the given name are supposed \n                      to have\n            !*/\n\n            void set_level (\n                const std::string& name,\n                const log_level& new_level\n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #level(C) == new_level\n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #level(L) == new_level\n            !*/\n\n            struct auto_flush_container\n            {\n                bool val;\n                map<std::string,std::unique_ptr<auto_flush_container> >::kernel_1b_c table;\n            } auto_flush_table;\n\n            bool auto_flush (\n                const std::string& name\n            ) const;\n            /*!\n                ensures\n                    - returns the auto_flush value loggers with the given name are supposed \n                      to have\n            !*/\n\n            void set_auto_flush (\n                const std::string& name,\n                bool enabled\n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #auto_flush_enabled(C) == enabled \n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #auto_flush_enabled(L) == enabled \n            !*/\n\n            struct output_streambuf_container\n            {\n                std::streambuf* val;\n                map<std::string,std::unique_ptr<output_streambuf_container> >::kernel_1b_c table;\n            } streambuf_table;\n\n            std::streambuf* output_streambuf (\n                const std::string& name\n            );\n            /*!\n                ensures\n                    - returns the streambuf loggers with the given name are supposed \n                      to have\n            !*/\n\n            void set_output_stream (\n                const std::string& name,\n                std::ostream& out_\n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #output_streambuf(C) == out_.rdbuf() \n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #output_streambuf(L) == out_.rdbuf() \n            !*/\n\n            void set_output_stream (\n                const std::string& name,\n                std::streambuf& buf \n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #output_streambuf(C) == &buf \n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #output_streambuf(L) == &buf \n            !*/\n\n            struct output_hook_container\n            {\n                hook_mfp val;\n                map<std::string,std::unique_ptr<output_hook_container> >::kernel_1b_c table;\n            } hook_table;\n\n            hook_mfp output_hook (\n                const std::string& name\n            );\n            /*!\n                ensures\n                    - returns the hook loggers with the given name are supposed \n                      to have\n            !*/\n\n            void set_output_hook (\n                const std::string& name,\n                const hook_mfp& hook\n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #output_hook(C) == hook \n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #output_hook(L) == hook \n            !*/\n\n            struct logger_header_container\n            {\n                print_header_type val;\n                map<std::string,std::unique_ptr<logger_header_container> >::kernel_1b_c table;\n            } header_table;\n\n            print_header_type logger_header (\n                const std::string& name\n            );\n            /*!\n                ensures\n                    - returns the header function loggers with the given name are supposed \n                      to have\n            !*/\n\n            void set_logger_header (\n                const std::string& name,\n                print_header_type ph\n            );\n            /*!\n                ensures\n                    - for all children C of name:\n                        - #logger_header(C) == ph \n                    - if name == \"\" then\n                        - for all loggers L:\n                            - #logger_header(L) == ph \n            !*/\n\n        }; // end of struct global_data\n\n        static global_data& get_global_data();\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        friend void set_all_logging_levels (\n            const log_level& new_level\n        );\n\n        friend void set_all_logging_headers (\n            const print_header_type& new_header \n        );\n\n        friend void set_all_logging_output_streams (\n            std::ostream& out\n        );\n\n        template <\n            typename T\n            >\n        friend void set_all_logging_output_hooks (\n            T& object,\n            void (T::*hook_)(const std::string& logger_name, \n                            const log_level& l,\n                            const uint64 thread_id,\n                            const char* message_to_log)\n        )\n        {\n            logger::hook_mfp hook;\n\n            // There is a bug in one of the versions (but not all apparently) of \n            // Visual studio 2005 that causes it to error out if <T> isn't in the\n            // following line of code.  However, there is also a bug in gcc-3.3 \n            // that causes it to error out if <T> is present.  So this works around\n            // this problem.\n#if defined(_MSC_VER) && _MSC_VER == 1400\n            hook.set<T>(object, hook_);\n#else\n            hook.set(object, hook_);\n#endif\n\n            logger::global_data& gd = logger::get_global_data();\n            auto_mutex M(gd.m);\n            gd.loggers.reset();\n            while (gd.loggers.move_next())\n            {\n                gd.loggers.element()->out.rdbuf(&gd.hookbuf);\n                gd.loggers.element()->hook = hook;\n            }\n\n            gd.set_output_stream(\"\",gd.hookbuf);\n            gd.set_output_hook(\"\",hook);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        global_data& gd;\n\n        const std::string logger_name;\n\n        print_header_type print_header;\n        bool auto_flush_enabled;\n        std::ostream out;\n        log_level cur_level;\n\n        hook_mfp hook;\n\n\n        // restricted functions\n        logger(const logger&);        // copy constructor\n        logger& operator=(const logger&);    // assignment operator\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n\n\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"logger_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_LOGGER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/logger/logger_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LOGGER_KERNEl_ABSTRACT_\n#ifdef DLIB_LOGGER_KERNEl_ABSTRACT_\n\n#include \"../threads.h\"\n#include <limits>\n#include <string>\n#include <iostream>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class log_level\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a simple named level to log at.  It contains a numeric \n                priority and a name to use in the logging messages.\n        !*/\n    public:\n        log_level(\n            int priority_, \n            const char* name_\n        );  \n        /*!\n            ensures\n                - #priority = priority_\n                - the first 19 characters of name_ are copied into name and name\n                  is null terminated.\n        !*/\n\n        bool operator< (const log_level& rhs) const { return priority <  rhs.priority; }\n        bool operator<=(const log_level& rhs) const { return priority <= rhs.priority; }\n        bool operator> (const log_level& rhs) const { return priority >  rhs.priority; }\n        bool operator>=(const log_level& rhs) const { return priority >= rhs.priority; }\n\n        int priority;\n        char name[20];\n    };\n\n    inline std::ostream& operator<< (std::ostream& out, const log_level& item);\n    /*!\n        ensures\n            - performs out << item.name\n            - returns out\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const log_level LALL  (std::numeric_limits<int>::min(),\"ALL\");\n    const log_level LNONE (std::numeric_limits<int>::max(),\"NONE\");\n    const log_level LTRACE(-100,\"TRACE\");\n    const log_level LDEBUG(0   ,\"DEBUG\");\n    const log_level LINFO (100 ,\"INFO \");\n    const log_level LWARN (200 ,\"WARN \");\n    const log_level LERROR(300 ,\"ERROR\");\n    const log_level LFATAL(400 ,\"FATAL\");\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void set_all_logging_output_streams (\n        std::ostream& out\n    );\n    /*!\n        ensures\n            - for all loggers L (even loggers not yet constructed):\n                - #L.output_streambuf() == out.rdbuf() \n                - Removes any previous output hook from L.  So now the logger\n                  L will write all its messages to the given output stream.\n        throws\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    typedef void (*print_header_type)(\n        std::ostream& out, \n        const std::string& logger_name, \n        const log_level& l,\n        const uint64 thread_id\n    );\n\n    void set_all_logging_headers (\n        const print_header_type& new_header\n    );\n    /*!\n        ensures\n            - for all loggers L (even loggers not yet constructed):\n                - #L.logger_header() == new_header \n        throws\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void set_all_logging_output_hooks (\n        T& object,\n        void (T::*hook)(const std::string& logger_name, \n                        const log_level& l,\n                        const uint64 thread_id,\n                        const char* message_to_log)\n    );\n    /*!\n        ensures\n            - for all loggers L (even loggers not yet constructed):\n                - #L.output_streambuf() == 0\n                - performs the equivalent to calling L.set_output_hook(object, hook);\n                  (i.e. sets all loggers so that they will use the given hook function)\n        throws\n            - std::bad_alloc\n    !*/\n\n    template <\n        typename T\n        >\n    void set_all_logging_output_hooks (\n        T& object\n    );\n    /*!\n        ensures\n            - calls set_all_logging_output_hooks(object, &T::log);\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void set_all_logging_levels (\n        const log_level& new_level\n    );\n    /*!\n        ensures\n            - for all loggers L (even loggers not yet constructed):\n                - #L.level() == new_level\n        throws\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void print_default_logger_header (\n        std::ostream& out,\n        const std::string& logger_name,\n        const log_level& l,\n        const uint64 thread_id\n    );\n    /*!\n        requires\n            - is not called more than once at a time (i.e. is not called from multiple\n              threads at the same time).\n        ensures\n            - let MS be the number of milliseconds since program start.  \n            - prints a string to out in the form:  \"MS l.name [thread_id] logger_name:\"\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    class logger \n    {\n        /*!\n            INITIAL VALUE\n                - name() == a user supplied value given to the constructor\n                - The values of level(), output_streambuf(), logger_header(), and\n                  auto_flush() are inherited from the parent of this logger. \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a logging output stream in the style of the log4j\n                logger available for Java.  \n                \n                Additionally, the logger doesn't perform any memory allocations during\n                each logging action.  It just writes directly into the user supplied output\n                stream.  Alternatively, if you use a logging output hook no memory allocations\n                are performed either.  Logging just goes straight into a memory buffer\n                which gets passed to the user supplied logging hook.\n\n            DEFAULTS\n                If the user hasn't specified values for the four inherited values level(),\n                output_streambuf(), logger_header(), or auto_flush() then the default\n                values will be used.  The defaults are as follows:\n                - level() == LERROR\n                - output_streambuf() == std::cout.rdbuf() (i.e. the default is to log\n                  to standard output).  \n                - logger_header() == print_default_logger_header\n                - auto_flush() == true\n            \n            THREAD SAFETY\n                All methods of this class are thread safe.  Note that it is safe to \n                chain calls to operator << such as:\n                    log << LINFO << \"message \" << variable << \" more message\";\n                The logger ensures that the entire statement executes atomically so the \n                message won't be broken up by other loggers in other threads.\n        !*/\n\n        class logger_stream\n        {\n        public:\n\n            bool is_enabled (\n            ) const;\n            /*!\n                ensures\n                    - returns true if this logger stream will print out items\n                      given to it by the << operator.  returns false otherwise.\n            !*/\n\n            template <typename T>\n            logger_stream& operator << (\n                const T& item\n            );\n            /*!\n                ensures\n                    - if (is_enabled()) then\n                        - writes item to this output stream\n                    - returns *this\n            !*/\n        };\n\n    public:\n\n        logger (  \n            const std::string& name_\n        );\n        /*!\n            requires\n                - name_ != \"\"\n            ensures                \n                - #*this is properly initialized\n                - #name() == name_\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~logger (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        const std::string& name (\n        ) const;\n        /*!\n            ensures\n                - returns the name of this logger\n        !*/\n\n        logger_stream operator << (\n            const log_level& l\n        ) const;\n        /*!\n            ensures\n                - if (l.priority >= level().priority) then\n                    - returns a logger_stream with is_enabled() == true.  I.e. this\n                      returned stream will write its output to the I/O destination \n                      used by this logger object.\n                - else\n                    - returns a logger stream with is_enabled() == false \n            throws\n                - std::bad_alloc\n        !*/\n\n        bool is_child_of (\n            const logger& log\n        ) const;\n        /*!\n            ensures\n                - if ( (name().find(log.name() + \".\") == 0) || (log.name() == name()) ) then\n                    - returns true\n                      (i.e. if log.name() + \".\" is a prefix of name() or if both *this and log\n                      have the same name then return true)\n                - else\n                    - returns false\n        !*/\n\n        const log_level level (\n        ) const;\n        /*!\n            ensures\n                - returns the current log level of this logger.\n        !*/\n\n        void set_level (\n            const log_level& new_level\n        );\n        /*!\n            ensures\n                - for all loggers L such that L.is_child_of(*this) == true:\n                    - #L.level() == new_level\n            throws\n                - std::bad_alloc\n        !*/\n\n        bool auto_flush (\n        );\n        /*!\n            ensures\n                - returns true if the output stream is flushed after every logged message.\n                  returns false otherwise.  (Note that flushing only does anything if\n                  the logger is set to use an output stream rather than a hook)\n        !*/\n\n        void set_auto_flush (\n            bool enabled\n        );\n        /*!\n            ensures\n                - for all loggers L such that L.is_child_of(*this) == true:\n                    - #L.auto_flush() == enabled \n            throws\n                - std::bad_alloc\n        !*/\n\n                \n        template <\n            typename T\n            >\n        void set_output_hook (\n            T& object,\n            void (T::*hook)(const std::string& logger_name, \n                            const log_level& l,\n                            const uint64 thread_id,\n                            const char* message_to_log)\n        );\n        /*!\n            requires\n                - hook is a valid pointer to a member function in T \n            ensures\n                - for all loggers L such that L.is_child_of(*this) == true:\n                    - #L.output_streambuf() == 0\n                    - #L will not send its log messages to an ostream object anymore.  Instead\n                      it will call the given hook member function (i.e. (object.*hook)(name,l,id,msg) )\n                      for each message that needs to be logged.\n                    - The arguments to the hook function have the following meanings:\n                        - logger_name == The name of the logger that is printing the log message.\n                        - l == The level of the logger that is printing the log message.\n                        - thread_id == A number that uniquely identifies the thread trying to log\n                          the message.  Note that this number is unique among all threads, past and\n                          present.  Also note that this id is not the same one returned by\n                          get_thread_id().\n                        - message_to_log == the actual text of the message the user is giving to\n                          the logger object to log.\n                    - All hook functions will also only be called one at a time. This means\n                      that hook functions don't need to be thread safe.\n        !*/\n\n        std::streambuf* output_streambuf (\n        );\n        /*!\n            ensures\n                - if (an output hook isn't set) then\n                    - returns the output stream buffer that this logger writes all\n                      messages to.\n                - else\n                    - returns 0\n        !*/\n\n        void set_output_stream (\n            std::ostream& out\n        );\n        /*!\n            ensures\n                - for all loggers L such that L.is_child_of(*this) == true:\n                    - #L.output_streambuf() == out.rdbuf() \n                    - Removes any previous output hook from L.  So now the logger\n                      L will write all its messages to the given output stream.\n            throws\n                - std::bad_alloc\n        !*/\n\n        print_header_type logger_header (\n        ) const;\n        /*!\n            ensures\n                - returns the function that is called to print the header information \n                  onto each logged message.  The arguments to the function have the following\n                  meanings:\n                    - out == The output stream this function writes the header to.\n                    - logger_name == The name of the logger that is printing the log message.\n                    - l == The level of the logger that is printing the log message.\n                    - thread_id == A number that uniquely identifies the thread trying to log\n                      the message.  Note that this number is unique among all threads, past and\n                      present.  Also note that this id is not the same one returned by\n                      get_thread_id().\n                - This logger_header function will also only be called once at a time. This means\n                  the logger_header function doesn't need to be thread safe.\n                - the logger_header function is only used when output_streambuf() != 0\n        !*/\n\n        void set_logger_header (\n            print_header_type print_header\n        );\n        /*!\n            ensures\n                - for all loggers L such that L.is_child_of(*this) == true:\n                    - #L.logger_header() == print_header \n            throws\n                - std::bad_alloc\n        !*/\n\n    private:\n\n        // restricted functions\n        logger(const logger&);        // copy constructor\n        logger& operator=(const logger&);    // assignment operator\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LOGGER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/logger.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LOGGEr_\n#define DLIB_LOGGEr_\n\n#include \"logger/logger_kernel_1.h\"\n#include \"logger/extra_logger_headers.h\"\n#include \"logger/logger_config_file.h\"\n\n#endif // DLIB_LOGGEr_ \n\n"
  },
  {
    "path": "dlib/lsh/create_random_projection_hash.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_\n#define DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_\n\n#include \"create_random_projection_hash_abstract.h\"\n#include \"projection_hash.h\"\n#include \"../matrix.h\"\n#include \"../rand.h\"\n#include \"../statistics.h\"\n#include \"../svm.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_random_projection_hash (\n        const vector_type& v,\n        const int bits,\n        dlib::rand& rnd\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    v.size() > 1,\n            \"\\t projection_hash create_random_projection_hash()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            << \"\\n\\t bits: \" << bits\n            << \"\\n\\t v.size(): \" << v.size() \n            );\n\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < v.size(); ++i)\n        {\n            DLIB_ASSERT(v[0].size() == v[i].size() && v[i].size() > 0 && is_col_vector(v[i]), \n                    \"\\t projection_hash create_random_projection_hash()\"\n                   << \"\\n\\t Invalid arguments were given to this function.\"\n                   << \"\\n\\t m(0).size(): \" << v[0].size()\n                   << \"\\n\\t m(\"<<i<<\").size(): \" << v[i].size() \n                   << \"\\n\\t is_col_vector(v[\"<<i<<\"]): \" << is_col_vector(v[i]) \n                );\n        }\n#endif\n\n        running_covariance<matrix<double> > rc;\n        for (unsigned long i = 0; i < v.size(); ++i)\n            rc.add(matrix_cast<double>(v[i]));\n\n        // compute a whitening matrix\n        matrix<double> whiten = trans(chol(pinv(rc.covariance())));\n\n\n        // hashes\n        std::vector<unsigned long> h(v.size(),0);\n\n        std::vector<double> vals(v.size(),0);\n\n        // number of hits for each hash value\n        std::vector<unsigned long> counts;\n\n        std::vector<double> temp;\n\n        // build a random projection matrix\n        matrix<double> proj(bits, v[0].size());\n        for (long r = 0; r < proj.nr(); ++r)\n            for (long c = 0; c < proj.nc(); ++c)\n                proj(r,c) = rnd.get_random_gaussian();\n\n        // merge whitening matrix with projection matrix\n        proj = proj*whiten;\n\n        matrix<double,0,1> offset(bits);\n\n\n        // figure out what the offset values should be\n        for (int itr = 0; itr < offset.size(); ++itr)\n        {\n            counts.assign(static_cast<unsigned long>(std::pow(2.0,bits)), 0);\n            // count the popularity of each hash value\n            for (unsigned long i = 0; i < h.size(); ++i)\n            {\n                h[i] <<= 1;\n                counts[h[i]] += 1;\n            }\n\n            const unsigned long max_h = index_of_max(mat(counts));\n\n            temp.clear();\n            for (unsigned long i = 0; i < v.size(); ++i)\n            {\n                vals[i] = dot(rowm(proj,itr), matrix_cast<double>(v[i]));\n                if (h[i] == max_h)\n                    temp.push_back(vals[i]);\n            }\n\n            // split down the middle\n            std::sort(temp.begin(), temp.end());\n            const double split = temp[temp.size()/2];\n            offset(itr) = -split;\n\n            for (unsigned long i = 0; i < vals.size(); ++i)\n            {\n                if (vals[i] - split > 0)\n                    h[i] |= 1;\n            }\n        }\n\n\n        return projection_hash(proj, offset);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_random_projection_hash (\n        const vector_type& v,\n        const int bits\n    ) \n    {\n        dlib::rand rnd;\n        return create_random_projection_hash(v,bits,rnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_max_margin_projection_hash (\n        const vector_type& v,\n        const int bits,\n        const double C,\n        dlib::rand& rnd\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(0 < bits && bits <= 32 &&\n                    v.size() > 1,\n            \"\\t projection_hash create_max_margin_projection_hash()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            << \"\\n\\t bits: \" << bits\n            << \"\\n\\t v.size(): \" << v.size() \n            );\n\n#ifdef ENABLE_ASSERTS\n        for (unsigned long i = 0; i < v.size(); ++i)\n        {\n            DLIB_ASSERT(v[0].size() == v[i].size() && v[i].size() > 0 && is_col_vector(v[i]), \n                    \"\\t projection_hash create_max_margin_projection_hash()\"\n                   << \"\\n\\t Invalid arguments were given to this function.\"\n                   << \"\\n\\t m(0).size(): \" << v[0].size()\n                   << \"\\n\\t m(\"<<i<<\").size(): \" << v[i].size() \n                   << \"\\n\\t is_col_vector(v[\"<<i<<\"]): \" << is_col_vector(v[i]) \n                );\n        }\n#endif\n\n        running_covariance<matrix<double> > rc;\n        for (unsigned long i = 0; i < v.size(); ++i)\n            rc.add(matrix_cast<double>(v[i]));\n\n        // compute a whitening matrix\n        matrix<double> whiten = trans(chol(pinv(rc.covariance())));\n        const matrix<double,0,1> meanval = whiten*rc.mean();\n\n\n\n        typedef matrix<double,0,1> sample_type;\n        random_subset_selector<sample_type> training_samples;\n        random_subset_selector<double> training_labels;\n        // We set this up to use enough samples to cover the vector space used by elements\n        // of v.  \n        training_samples.set_max_size(v[0].size()*10);\n        training_labels.set_max_size(v[0].size()*10);\n\n        matrix<double> proj(bits, v[0].size());\n        matrix<double,0,1> offset(bits);\n\n        // learn the random planes and put them into proj and offset.\n        for (int itr = 0; itr < offset.size(); ++itr)\n        {\n            training_samples.make_empty();\n            training_labels.make_empty();\n            // pick random training data and give each sample a random label.\n            for (unsigned long i = 0; i < v.size(); ++i)\n            {\n                training_samples.add(whiten*v[i]-meanval);\n                if (rnd.get_random_double() > 0.5)\n                    training_labels.add(+1);\n                else\n                    training_labels.add(-1);\n            }\n\n            svm_c_linear_dcd_trainer<linear_kernel<sample_type> > trainer;\n            trainer.set_c(C);\n            decision_function<linear_kernel<sample_type> > df = trainer.train(training_samples, training_labels);\n            offset(itr) = -df.b;\n            set_rowm(proj,itr) = trans(df.basis_vectors(0));\n        }\n\n\n        return projection_hash(proj*whiten, offset-proj*meanval);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_max_margin_projection_hash (\n        const vector_type& v,\n        const int bits,\n        const double C = 10\n    ) \n    {\n        dlib::rand rnd;\n        return create_max_margin_projection_hash(v,bits,C,rnd);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CREATE_RANDOM_PROJECTION_HAsH_Hh_\n\n"
  },
  {
    "path": "dlib/lsh/create_random_projection_hash_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_\n#ifdef DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_\n\n#include \"projection_hash_abstract.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_random_projection_hash (\n        const vector_type& v,\n        const int bits,\n        dlib::rand& rnd\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - v.size() > 1\n            - vector_type == a std::vector or compatible type containing dlib::matrix \n              objects, each representing a column vector of the same size.\n            - for all valid i, j:\n                - is_col_vector(v[i]) == true \n                - v[i].size() > 0\n                - v[i].size() == v[j].size() \n                - i.e. v contains only column vectors and all the column vectors\n                  have the same non-zero length\n            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface\n        ensures\n            - returns a hash function H such that:\n                - H.num_hash_bins() == pow(2,bits)\n                - H will be setup so that it hashes the contents of v such that each bin\n                  ends up with roughly the same number of elements in it.  This is\n                  accomplished by picking random hyperplanes passing though the data.  In\n                  particular, each plane normal vector is filled with Gaussian random\n                  numbers and we also perform basic centering to ensure the plane passes\n                  though the data.\n            - This function uses the supplied random number generator, rnd, to drive part\n              of its processing.  Therefore, giving different random number generators\n              will produce different outputs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_random_projection_hash (\n        const vector_type& v,\n        const int bits\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - v.size() > 1\n            - vector_type == a std::vector or compatible type containing dlib::matrix \n              objects, each representing a column vector of the same size.\n            - for all valid i, j:\n                - is_col_vector(v[i]) == true \n                - v[i].size() > 0\n                - v[i].size() == v[j].size() \n                - i.e. v contains only column vectors and all the column vectors\n                  have the same non-zero length\n        ensures\n            - returns create_random_projection_hash(v,bits,dlib::rand())\n              (i.e. calls the above function with a default initialized random number generator)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_max_margin_projection_hash (\n        const vector_type& v,\n        const int bits,\n        const double C,\n        dlib::rand& rnd\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - v.size() > 1\n            - vector_type == a std::vector or compatible type containing dlib::matrix \n              objects, each representing a column vector of the same size.\n            - for all valid i, j:\n                - is_col_vector(v[i]) == true \n                - v[i].size() > 0\n                - v[i].size() == v[j].size() \n                - i.e. v contains only column vectors and all the column vectors\n                  have the same non-zero length\n            - rand_type == a type that implements the dlib/rand/rand_kernel_abstract.h interface\n        ensures\n            - returns a hash function H such that:\n                - H.num_hash_bins() == pow(2,bits)\n                - H will be setup so that it hashes the contents of v such that\n                  each bin ends up with roughly the same number of elements\n                  in it.  This is accomplished using a variation on the random hyperplane\n                  generation technique from the paper:\n                    Random Maximum Margin Hashing by Alexis Joly and Olivier Buisson\n                  In particular, we use the svm_c_linear_dcd_trainer to generate planes.\n                  We train it on randomly selected and randomly labeled points from v.\n                  The C SVM parameter is set to the given C argument.\n            - This function uses the supplied random number generator, rnd, to drive part\n              of its processing.  Therefore, giving different random number generators\n              will produce different outputs.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename vector_type\n        >\n    projection_hash create_max_margin_projection_hash (\n        const vector_type& v,\n        const int bits,\n        const double C = 10\n    );\n    /*!\n        requires\n            - 0 < bits <= 32\n            - v.size() > 1\n            - vector_type == a std::vector or compatible type containing dlib::matrix \n              objects, each representing a column vector of the same size.\n            - for all valid i, j:\n                - is_col_vector(v[i]) == true \n                - v[i].size() > 0\n                - v[i].size() == v[j].size() \n                - i.e. v contains only column vectors and all the column vectors\n                  have the same non-zero length\n        ensures\n            - returns create_max_margin_projection_hash(v,bits,C,dlib::rand())\n              (i.e. calls the above function with a default initialized random number generator)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CREATE_RANDOM_PROJECTION_HAsH_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/lsh/hashes.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LSH_HAShES_Hh_\n#define DLIB_LSH_HAShES_Hh_\n\n#include \"hashes_abstract.h\"\n#include \"../hash.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class hash_similar_angles_64\n    {\n    public:\n        hash_similar_angles_64 (\n        ) : seed(0) {}\n\n        hash_similar_angles_64 (\n            const uint64 seed_ \n        ) : seed(seed_) {}\n\n        uint64 get_seed (\n        ) const { return seed; }\n\n\n        typedef uint64 result_type;\n\n        template <\n            typename sparse_vector_type\n            >\n        typename disable_if<is_matrix<sparse_vector_type>,uint64>::type operator() (\n            const sparse_vector_type& v\n        ) const\n        {\n            typedef typename sparse_vector_type::value_type::second_type scalar_type;\n\n            uint64 temp = 0;\n            for (int i = 0; i < 64; ++i)\n            {\n                // compute the dot product between v and a Gaussian random vector.\n                scalar_type val = 0;\n                for (typename sparse_vector_type::const_iterator j = v.begin(); j != v.end(); ++j)\n                    val += j->second*gaussian_random_hash(j->first, i, seed);\n\n                if (val > 0)\n                    temp |= 1;\n                temp <<= 1;\n            }\n            return temp;\n        }\n\n        template <typename EXP>\n        uint64 operator() ( \n            const matrix_exp<EXP>& v\n        ) const\n        {\n            typedef typename EXP::type T;\n            uint64 temp = 0;\n            for (unsigned long i = 0; i < 64; ++i)\n            {\n                if (dot(matrix_cast<T>(gaussian_randm(v.size(),1,i+seed*64)), v) > 0)\n                    temp |= 1;\n                temp <<= 1;\n            }\n            return temp;\n        }\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const\n        {\n            return hamming_distance(a,b);\n        }\n\n    private:\n        const uint64 seed;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class hash_similar_angles_128\n    {\n    public:\n        hash_similar_angles_128 (\n        ) : seed(0),hasher1(0), hasher2(1) {}\n\n        hash_similar_angles_128 (\n            const uint64 seed_\n        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}\n\n        uint64 get_seed (\n        ) const { return seed; }\n\n        typedef std::pair<uint64,uint64> result_type;\n\n        template <\n            typename vector_type \n            >\n        result_type operator() (\n            const vector_type& v\n        ) const\n        {\n            return std::make_pair(hasher1(v), hasher2(v));\n        }\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const\n        {\n            return hamming_distance(a.first,b.first) + \n                   hamming_distance(a.second,b.second);\n        }\n\n    private:\n        const uint64 seed;\n        hash_similar_angles_64 hasher1;\n        hash_similar_angles_64 hasher2;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class hash_similar_angles_256\n    {\n    public:\n        hash_similar_angles_256 (\n        ) : seed(0), hasher1(0), hasher2(1) {}\n\n        hash_similar_angles_256 (\n            const uint64 seed_\n        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}\n\n        uint64 get_seed (\n        ) const { return seed; }\n\n        typedef std::pair<uint64,uint64> hash128_type;\n        typedef std::pair<hash128_type,hash128_type> result_type;\n\n        template <\n            typename vector_type \n            >\n        result_type operator() (\n            const vector_type& v\n        ) const\n        {\n            return std::make_pair(hasher1(v), hasher2(v));\n        }\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const\n        {\n            return hasher1.distance(a.first,b.first) + \n                   hasher1.distance(a.second,b.second);\n        }\n\n    private:\n        const uint64 seed;\n        hash_similar_angles_128 hasher1;\n        hash_similar_angles_128 hasher2;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class hash_similar_angles_512\n    {\n    public:\n        hash_similar_angles_512 (\n        ) : seed(0), hasher1(0), hasher2(1) {}\n\n        hash_similar_angles_512 (\n            const uint64 seed_\n        ) : seed(seed_),hasher1(2*seed),hasher2(2*seed+1) {}\n\n        uint64 get_seed (\n        ) const { return seed; }\n\n\n        typedef hash_similar_angles_256::result_type hash256_type;\n        typedef std::pair<hash256_type,hash256_type> result_type;\n\n        template <\n            typename vector_type \n            >\n        result_type operator() (\n            const vector_type& v\n        ) const\n        {\n            return std::make_pair(hasher1(v), hasher2(v));\n        }\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const\n        {\n            return hasher1.distance(a.first,b.first) + \n                   hasher1.distance(a.second,b.second);\n        }\n\n    private:\n        const uint64 seed;\n        hash_similar_angles_256 hasher1;\n        hash_similar_angles_256 hasher2;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LSH_HAShES_Hh_\n\n"
  },
  {
    "path": "dlib/lsh/hashes_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LSH_HAShES_ABSTRACT_Hh_\n#ifdef DLIB_LSH_HAShES_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class hash_similar_angles_64\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for computing locality sensitive hashes that give\n                vectors with small angles between each other similar hash values.  In\n                particular, this object creates 64 random planes which pass though the\n                origin and uses them to create a 64bit hash.  To compute the hash for a new\n                vector, this object checks which side of each plane the vector falls on and\n                records this information into a 64bit integer.  \n        !*/\n\n    public:\n\n        hash_similar_angles_64 (\n        ); \n        /*!\n            ensures\n                - #get_seed() == 0\n        !*/\n\n        hash_similar_angles_64 (\n            const uint64 seed\n        );\n        /*!\n            ensures\n                - #get_seed() == seed\n        !*/\n\n        uint64 get_seed (\n        ) const;\n        /*!\n            ensures\n                - returns the random seed used to generate the random planes used for\n                  hashing.\n        !*/\n\n        typedef uint64 result_type;\n\n        template <typename vector_type>\n        result_type operator() (\n            const vector_type& v\n        ) const;\n        /*!\n            requires\n                - v is an unsorted sparse vector or a dlib matrix representing either a\n                  column or row vector.\n            ensures\n                - returns a 64 bit hash of the input vector v.  The bits in the hash record\n                  which side of each random plane v falls on.  \n\n        !*/\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const;\n        /*!\n            ensures\n                - returns the Hamming distance between the two hashes given to this\n                  function.  That is, we return the number of bits in a and b which differ.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct hash_similar_angles_128\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for computing locality sensitive hashes that give\n                vectors with small angles between each other similar hash values.  In\n                particular, this object creates 128 random planes which pass though the\n                origin and uses them to create a 128bit hash.  To compute the hash for a new\n                vector, this object checks which side of each plane the vector falls on and\n                records this information into a 128bit integer.  \n        !*/\n\n    public:\n\n        hash_similar_angles_128 (\n        ); \n        /*!\n            ensures\n                - #get_seed() == 0\n        !*/\n\n        hash_similar_angles_128 (\n            const uint64 seed\n        );\n        /*!\n            ensures\n                - #get_seed() == seed\n        !*/\n\n        uint64 get_seed (\n        ) const;\n        /*!\n            ensures\n                - returns the random seed used to generate the random planes used for\n                  hashing.\n        !*/\n\n        typedef std::pair<uint64,uint64> result_type;\n\n        template <typename vector_type>\n        result_type operator() (\n            const vector_type& v\n        ) const;\n        /*!\n            requires\n                - v is an unsorted sparse vector or a dlib matrix representing either a\n                  column or row vector.\n            ensures\n                - returns a 128 bit hash of the input vector v.  The bits in the hash record\n                  which side of each random plane v falls on.  \n\n        !*/\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const;\n        /*!\n            ensures\n                - returns the Hamming distance between the two hashes given to this\n                  function.  That is, we return the number of bits in a and b which differ.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct hash_similar_angles_256\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for computing locality sensitive hashes that give\n                vectors with small angles between each other similar hash values.  In\n                particular, this object creates 256 random planes which pass though the\n                origin and uses them to create a 256bit hash.  To compute the hash for a new\n                vector, this object checks which side of each plane the vector falls on and\n                records this information into a 256bit integer.  \n        !*/\n\n    public:\n\n        hash_similar_angles_256 (\n        ); \n        /*!\n            ensures\n                - #get_seed() == 0\n        !*/\n\n        hash_similar_angles_256 (\n            const uint64 seed\n        );\n        /*!\n            ensures\n                - #get_seed() == seed\n        !*/\n\n        uint64 get_seed (\n        ) const;\n        /*!\n            ensures\n                - returns the random seed used to generate the random planes used for\n                  hashing.\n        !*/\n\n        typedef std::pair<uint64,uint64> hash128_type;\n        typedef std::pair<hash128_type,hash128_type> result_type;\n\n        template <typename vector_type>\n        result_type operator() (\n            const vector_type& v\n        ) const;\n        /*!\n            requires\n                - v is an unsorted sparse vector or a dlib matrix representing either a\n                  column or row vector.\n            ensures\n                - returns a 256 bit hash of the input vector v.  The bits in the hash record\n                  which side of each random plane v falls on.  \n\n        !*/\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const;\n        /*!\n            ensures\n                - returns the Hamming distance between the two hashes given to this\n                  function.  That is, we return the number of bits in a and b which differ.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct hash_similar_angles_512\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for computing locality sensitive hashes that give\n                vectors with small angles between each other similar hash values.  In\n                particular, this object creates 512 random planes which pass though the\n                origin and uses them to create a 512bit hash.  To compute the hash for a new\n                vector, this object checks which side of each plane the vector falls on and\n                records this information into a 512bit integer.  \n        !*/\n\n    public:\n\n        hash_similar_angles_512 (\n        ); \n        /*!\n            ensures\n                - #get_seed() == 0\n        !*/\n\n        hash_similar_angles_512 (\n            const uint64 seed\n        );\n        /*!\n            ensures\n                - #get_seed() == seed\n        !*/\n\n        uint64 get_seed (\n        ) const;\n        /*!\n            ensures\n                - returns the random seed used to generate the random planes used for\n                  hashing.\n        !*/\n\n        typedef hash_similar_angles_256::result_type hash256_type;\n        typedef std::pair<hash256_type,hash256_type> result_type;\n\n        template <typename vector_type>\n        result_type operator() (\n            const vector_type& v\n        ) const;\n        /*!\n            requires\n                - v is an unsorted sparse vector or a dlib matrix representing either a\n                  column or row vector.\n            ensures\n                - returns a 512 bit hash of the input vector v.  The bits in the hash record\n                  which side of each random plane v falls on.  \n\n        !*/\n\n        unsigned int distance (\n            const result_type& a,\n            const result_type& b\n        ) const;\n        /*!\n            ensures\n                - returns the Hamming distance between the two hashes given to this\n                  function.  That is, we return the number of bits in a and b which differ.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LSH_HAShES_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/lsh/projection_hash.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PROJECTION_HASh_Hh_\n#define DLIB_PROJECTION_HASh_Hh_\n\n#include \"projection_hash_abstract.h\"\n#include \"../matrix.h\"\n#include \"../rand.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class projection_hash\n    {\n    public:\n\n        projection_hash() {}\n\n        template <typename EXP1, typename EXP2>\n        projection_hash(\n            const matrix_exp<EXP1>& proj_,\n            const matrix_exp<EXP2>& offset_\n        ) : proj(proj_), offset(offset_) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(proj.nr() == offset.nr(),\n                \"\\t projection_hash::projection_hash()\"\n                << \"\\n\\t Invalid arguments were given to this function.\"\n                << \"\\n\\t proj.nr():   \" << proj.nr() \n                << \"\\n\\t offset.nr(): \" << offset.nr() \n                );\n\n        }\n\n        const matrix<double>& get_projection_matrix (\n        ) const { return proj; }\n\n        const matrix<double,0,1>& get_offset_matrix (\n        ) const { return offset; }\n\n        unsigned long num_hash_bins (\n        ) const\n        {\n            return static_cast<unsigned long>(std::pow(2.0, (double)offset.size()));\n        }\n\n        template <typename EXP>\n        unsigned long operator() (\n            const matrix_exp<EXP>& v\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_col_vector(v) && \n                        v.size() == get_projection_matrix().nc() &&\n                        v.size() > 0,\n                \"\\t unsigned long projection_hash::operator()(v)\"\n                << \"\\n\\t Invalid arguments were given to this function.\"\n                << \"\\n\\t is_col_vector(v):             \" << is_col_vector(v) \n                << \"\\n\\t get_projection_matrix().nc(): \" << get_projection_matrix().nc() \n                << \"\\n\\t v.size():                     \" << v.size() \n                );\n\n            return do_hash(proj*matrix_cast<double>(v) + offset);\n        }\n\n    private:\n\n        template <typename EXP>\n        unsigned long do_hash (\n            const matrix_exp<EXP>& v\n        ) const\n        {\n            unsigned long h = 0;\n            for (long i = 0; i < v.size(); ++i)\n            {\n                h <<= 1;\n                if (v(i) > 0)\n                    h |= 1;\n            }\n            return h;\n        }\n\n        matrix<double> proj;\n        matrix<double,0,1> offset;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const projection_hash& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.get_projection_matrix(), out);\n        serialize(item.get_offset_matrix(), out);\n    }\n\n    inline void deserialize (\n        projection_hash& item,\n        std::istream& in \n    )\n    {\n        matrix<double> proj;\n        matrix<double,0,1> offset;\n        deserialize(proj, in);\n        deserialize(offset, in);\n        item = projection_hash(proj, offset);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PROJECTION_HASh_Hh_\n\n"
  },
  {
    "path": "dlib/lsh/projection_hash_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_PROJECTION_HASh_ABSTRACT_Hh_\n#ifdef DLIB_PROJECTION_HASh_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class projection_hash\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for hashing elements of a vector space into the integers.  \n                It is intended to represent locality sensitive hashing functions such as \n                the popular random projection hashing method.\n                \n                In particular, it represents hash functions of the form:\n                    hash bit 0 = sign(rowm(P*v + O,0))\n                    hash bit 1 = sign(rowm(P*v + O,1))\n                    hash bit 2 = sign(rowm(P*v + O,2))\n                    ...\n                Where v is the vector to be hashed.  The parameters of the projection\n                hash are the P and O matrices.  \n\n            THREAD SAFETY\n                The const members of this object can be called concurrently from multiple\n                threads, however, any operation that modifies the state of an instance of\n                this object must serialize access to that instance.\n        !*/\n    public:\n\n        projection_hash(\n        );\n        /*!\n            ensures\n                - #get_projection_matrix().size() == 0\n                - #get_offset_matrix().size() == 0\n        !*/\n\n        template <typename EXP1, typename EXP2>\n        projection_hash(\n            const matrix_exp<EXP1>& proj,\n            const matrix_exp<EXP2>& offset\n        ); \n        /*!\n            requires\n                - proj.nr() == offset.nr()\n            ensures\n                - #get_projection_matrix() == proj\n                - #get_offset_matrix() == offset\n        !*/\n\n        const matrix<double>& get_projection_matrix (\n        ) const;\n        /*!\n            ensures\n                - returns the P matrix discussed above in the WHAT THIS OBJECT REPRESENTS\n                  section.\n        !*/\n\n        const matrix<double,0,1>& get_offset_matrix (\n        ) const; \n        /*!\n            ensures\n                - returns the O matrix discussed above in the WHAT THIS OBJECT REPRESENTS\n                  section.\n        !*/\n\n        unsigned long num_hash_bins (\n        ) const;\n        /*!\n            ensures\n                - returns the number of possible outputs from this hashing function.\n                - Specifically, returns: std::pow(2, get_offset_matrix().size())\n        !*/\n\n        template <typename EXP>\n        unsigned long operator() (\n            const matrix_exp<EXP>& v\n        ) const;\n        /*!\n            requires\n                - is_col_vector(v) == true\n                - v.size() == get_projection_matrix().nc()\n                - v.size() > 0\n            ensures\n                - hashes v into the range [0, num_hash_bins()) using the method\n                  discussed in the WHAT THIS OBJECT REPRESENTS section.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    void serialize (\n        const projection_hash& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        projection_hash& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PROJECTION_HASh_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/lsh.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LSh_\n#define DLIB_LSh_\n\n\n#include \"lsh/projection_hash.h\"\n#include \"lsh/create_random_projection_hash.h\"\n#include \"lsh/hashes.h\"\n\n\n#endif // DLIB_LSh_\n\n\n"
  },
  {
    "path": "dlib/lz77_buffer/lz77_buffer_kernel_1.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZ77_BUFFER_KERNEl_1_\n#define DLIB_LZ77_BUFFER_KERNEl_1_\n\n#include \"lz77_buffer_kernel_abstract.h\"\n#include \"../algs.h\"\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename sliding_buffer\n        >\n    class lz77_buffer_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON sliding_buffer\n                sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h\n\n            INITIAL VALUE\n                history_limit == defined by constructor arguments\n                lookahead_limit == defined by constructor arguments\n                history_size == 0\n                lookahead_size == 0\n                buffer.size() == history_limit + lookahead_limit\n\n\n            CONVENTION           \n                history_limit == get_history_buffer_limit()\n                lookahead_limit == get_lookahead_buffer_limit()\n                history_size == get_history_buffer_size()\n                lookahead_limit == get_lookahead_buffer_size()\n                              \n                buffer.size() == history_limit + lookahead_limit\n\n                lookahead_buffer(i) == buffer[lookahead_limit-1-i]\n                history_buffer(i) == buffer[lookahead_limit+i]\n        !*/\n\n    public:\n\n        lz77_buffer_kernel_1 (\n            unsigned long total_limit_,\n            unsigned long lookahead_limit_  \n        );\n\n        virtual ~lz77_buffer_kernel_1 (\n        ) {}\n\n        void clear(\n        );\n\n        void add (\n            unsigned char symbol\n        );\n\n        void find_match (\n            unsigned long& index,\n            unsigned long& length,\n            unsigned long min_match_length\n        );\n\n        inline unsigned long get_history_buffer_limit (\n        ) const { return history_limit; }\n\n        inline unsigned long get_lookahead_buffer_limit (\n        ) const { return lookahead_limit; }\n\n        inline unsigned long get_history_buffer_size (\n        ) const { return history_size; }\n\n        inline unsigned long get_lookahead_buffer_size (\n        ) const { return lookahead_size; }\n\n        inline unsigned char lookahead_buffer (\n            unsigned long index\n        ) const { return buffer[lookahead_limit-1-index]; }\n\n        inline unsigned char history_buffer (\n            unsigned long index\n        ) const { return buffer[lookahead_limit+index]; }\n\n\n        inline void shift_buffers (\n            unsigned long N\n        ) { shift_buffer(N); }\n\n    private:\n\n\n        inline void shift_buffer (\n            unsigned long N\n        )\n        /*!\n            requires\n                - N <= lookahead_size\n            ensuers\n                - #lookahead_size == lookahead_size - N\n                - if (history_size+N < history_limit) then\n                    - #history_size == history_size+N\n                - else\n                    - #history_size == history_limit\n                - for all i where 0 <= i < N:\n                  #history_buffer(N-1-i) == lookahead_buffer(i)\n                - for all i where 0 <= i < #history_size-N:\n                  #history_buffer(N+i) == history_buffer(i)\n                - for all i where 0 <= i < #lookahead_size\n                  #lookahead_buffer(i) == lookahead_buffer(N+i)                \n        !*/\n        {\n            unsigned long temp = history_size+N;\n            buffer.rotate_left(N);\n            lookahead_size -= N;\n            if (temp < history_limit)\n                history_size = temp;\n            else\n                history_size = history_limit;\n        }\n\n\n        // member data        \n        sliding_buffer buffer;\n        unsigned long lookahead_limit;\n        unsigned long history_limit;\n        \n\n        unsigned long lookahead_size;\n        unsigned long history_size;\n\n\n        // restricted functions\n        lz77_buffer_kernel_1(lz77_buffer_kernel_1<sliding_buffer>&);        // copy constructor\n        lz77_buffer_kernel_1<sliding_buffer>& operator=(lz77_buffer_kernel_1<sliding_buffer>&);    // assignment operator\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    lz77_buffer_kernel_1<sliding_buffer>::\n    lz77_buffer_kernel_1 (\n        unsigned long total_limit_,\n        unsigned long lookahead_limit_  \n    ) :        \n        lookahead_size(0), \n        history_size(0)\n    {\n        buffer.set_size(total_limit_);\n        lookahead_limit = lookahead_limit_;\n        history_limit = buffer.size() - lookahead_limit_;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_1<sliding_buffer>::\n    clear(\n    )\n    {\n        lookahead_size = 0;\n        history_size = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_1<sliding_buffer>::\n    add (\n        unsigned char symbol\n    )\n    {\n        if (lookahead_size == lookahead_limit)\n        {\n            shift_buffer(1);            \n        }\n        buffer[lookahead_limit-1-lookahead_size] = symbol;\n        ++lookahead_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_1<sliding_buffer>::\n    find_match (\n        unsigned long& index,\n        unsigned long& length,\n        unsigned long min_match_length\n    )\n    {\n        unsigned long hpos = history_size;  // current position in the history buffer\n        unsigned long lpos = 0;             // current position in the lookahead buffer\n\n        unsigned long match_length = 0;   // the length of the longest match we find\n        unsigned long match_index = 0;    // the index of the longest match we find\n\n        // try to find a match\n        while (hpos != 0)\n        {\n            --hpos;\n            // if we are finding a match\n            if (history_buffer(hpos) == lookahead_buffer(lpos))\n            {\n                ++lpos;   \n                // if we have found a match that is as long as the lookahead buffer\n                // then we are done\n                if (lpos == lookahead_size)\n                    break;\n            }\n            // else if we found the end of a match\n            else if (lpos > 0)\n            {\n                // if this match is longer than the last match we saw\n                if (lpos > match_length)\n                {\n                    match_length = lpos;\n                    match_index = hpos + lpos;\n                }\n                lpos = 0;\n            }\n        } // while (hpos != 0)\n\n        // if we found a match at the end of the loop that is greater than \n        // the match in match_index\n        if (lpos > match_length)\n        {\n            match_length = lpos;\n            match_index = hpos + lpos - 1;\n        }\n\n\n        // if we found a match that was long enough then report it\n        if (match_length >= min_match_length)\n        {\n            shift_buffer(match_length);\n            index = match_index;\n            length = match_length;\n        }\n        else\n        {\n            length = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZ77_BUFFER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/lz77_buffer/lz77_buffer_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZ77_BUFFER_KERNEl_2_\n#define DLIB_LZ77_BUFFER_KERNEl_2_\n\n#include \"lz77_buffer_kernel_abstract.h\"\n#include \"../algs.h\"\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename sliding_buffer\n        >\n    class lz77_buffer_kernel_2 \n    {\n        /*!\n            REQUIREMENTS ON sliding_buffer\n                sliding_buffer must be an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h\n                and must be instantiated to contain unsigned char data\n\n            INITIAL VALUE\n                history_limit == defined by constructor arguments\n                lookahead_limit == defined by constructor arguments\n                history_size == 0\n                lookahead_size == 0\n                buffer.size() == history_limit + lookahead_limit\n                buffer[i] == 0 for all valid i\n\n                nodes == an array of history_limit-3 nodes\n                id_table == an array of buffer.size() pointers\n                hash_table == an array of buffer.size() pointers and all are set to 0\n                mask == buffer.size() - 1\n                next_free_node == 0\n\n\n            CONVENTION           \n                history_limit == get_history_buffer_limit()\n                lookahead_limit == get_lookahead_buffer_limit()\n                history_size == get_history_buffer_size()\n                lookahead_limit == get_lookahead_buffer_size()\n                              \n                buffer.size() == history_limit + lookahead_limit\n\n                lookahead_buffer(i) == buffer[lookahead_limit-1-i]\n                history_buffer(i) == buffer[lookahead_limit+i]\n\n\n                hash_table[hash(a,b,c,d)] points to the head of a linked list.\n                    Each node in this linked list tells the location in the buffer\n                    of a string that begins with abcd or a string who's first four\n                    letters have the same hash.  The linked list is terminated by a\n                    node with a null next pointer.\n\n                hash_table[i] == 0 if there is no linked list for this element of the hash\n                    table.\n\n                each node in the hash table is allocated from the array nodes.\n                When adding a node to hash_table:\n                    if (if all nodes aren't already in the hash_table) then\n                    {\n                        the next node to use is nodes[next_free_node].                \n                    }\n                    else\n                    {\n                        recycle nodes from the hash_table itself.  This works because\n                        when we add new nodes we also have to remove nodes.\n                    }\n\n                if (there is a node defined with an id of i) then\n                {\n                    if (id_table[i] != 0) then\n                        id_table[i]->next->id == i\n                    else\n                        hash_table[some_hash]->id == i\n                }\n        !*/\n\n    public:\n\n        lz77_buffer_kernel_2 (\n            unsigned long total_limit_,\n            unsigned long lookahead_limit_  \n        );\n\n        virtual ~lz77_buffer_kernel_2 (\n        );\n\n        void clear(\n        );\n\n        void add (\n            unsigned char symbol\n        );\n\n        void find_match (\n            unsigned long& index,\n            unsigned long& length,\n            unsigned long min_match_length\n        );\n\n        inline unsigned long get_history_buffer_limit (\n        ) const { return history_limit; }\n\n        inline unsigned long get_lookahead_buffer_limit (\n        ) const { return lookahead_limit; }\n\n        inline unsigned long get_history_buffer_size (\n        ) const { return history_size; }\n\n        inline unsigned long get_lookahead_buffer_size (\n        ) const { return lookahead_size; }\n\n        inline unsigned char lookahead_buffer (\n            unsigned long index\n        ) const { return buffer[lookahead_limit-1-index]; }\n\n        inline unsigned char history_buffer (\n            unsigned long index\n        ) const { return buffer[lookahead_limit+index]; }\n\n\n        inline void shift_buffers (\n            unsigned long N\n        ) { shift_buffer(N); }\n\n    private:\n\n        inline unsigned long hash (\n            unsigned char a,\n            unsigned char b,\n            unsigned char c,\n            unsigned char d\n        ) const\n        /*!\n            ensures\n                - returns a hash of the 4 arguments and the hash is in the range\n        !*/\n        {\n            unsigned long B = b << 3;\n            unsigned long C = c << 6;\n            unsigned long D = d << 9;\n\n            unsigned long temp = a + B;\n            temp += C;\n            temp += D;\n\n            return (temp&mask); /**/\n        }\n\n        void shift_buffer (\n            unsigned long N\n        );\n        /*!\n            requires\n                - N <= lookahead_size\n            ensuers\n                - #lookahead_size == lookahead_size - N\n                - if (history_size+N < history_limit) then\n                    - #history_size == history_size+N\n                - else\n                    - #history_size == history_limit\n                - for all i where 0 <= i < N:\n                  #history_buffer(N-1-i) == lookahead_buffer(i)\n                - for all i where 0 <= i < #history_size-N:\n                  #history_buffer(N+i) == history_buffer(i)\n                - for all i where 0 <= i < #lookahead_size\n                  #lookahead_buffer(i) == lookahead_buffer(N+i)                \n        !*/\n\n\n\n        // member data        \n        sliding_buffer buffer;\n        unsigned long lookahead_limit;\n        unsigned long history_limit;\n\n        struct node\n        {\n            unsigned long id;\n            node* next;\n        };\n        \n        node** hash_table;\n        node* nodes;\n        node** id_table;\n        unsigned long next_free_node;\n        unsigned long mask;\n\n        unsigned long lookahead_size;\n        unsigned long history_size;\n\n\n        // restricted functions\n        lz77_buffer_kernel_2(lz77_buffer_kernel_2<sliding_buffer>&);        // copy constructor\n        lz77_buffer_kernel_2<sliding_buffer>& operator=(lz77_buffer_kernel_2<sliding_buffer>&);    // assignment operator\n    };   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    lz77_buffer_kernel_2<sliding_buffer>::\n    lz77_buffer_kernel_2 (\n        unsigned long total_limit_,\n        unsigned long lookahead_limit_  \n    ) :        \n        lookahead_size(0),       \n        history_size(0)\n    {\n        buffer.set_size(total_limit_);\n        lookahead_limit = lookahead_limit_;\n        history_limit = buffer.size() - lookahead_limit_;\n\n        nodes = new node[history_limit-3];\n\n        try { id_table = new node*[buffer.size()]; }\n        catch (...) { delete [] nodes; throw; }\n\n        try { hash_table = new node*[buffer.size()]; }\n        catch (...) { delete [] id_table; delete [] nodes; throw; }\n\n        mask = buffer.size()-1;\n        next_free_node = 0;\n\n            \n        node** start = hash_table;\n        node** end = hash_table + buffer.size();\n        while (start != end)\n        {\n            *start = 0;\n            ++start;\n        }\n\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n            buffer[i] = 0;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sliding_buffer\n        >\n    lz77_buffer_kernel_2<sliding_buffer>::\n    ~lz77_buffer_kernel_2 (\n    )      \n    {\n        delete [] nodes;\n        delete [] hash_table;\n        delete [] id_table;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_2<sliding_buffer>::\n    clear(\n    )\n    {\n        lookahead_size = 0;\n        history_size = 0;\n        next_free_node = 0;\n\n        node** start = hash_table;\n        node** end = hash_table + buffer.size();\n        while (start != end)\n        {\n            *start = 0;\n            ++start;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n      \n    template <\n        typename sliding_buffer\n        >      \n    void lz77_buffer_kernel_2<sliding_buffer>::\n    shift_buffer (\n        unsigned long N\n    )        \n    {\n        unsigned long old_history_size = history_size;\n        unsigned long temp = history_size+N;    \n        unsigned long new_nodes; // the number of nodes to pull from the nodes array\n        unsigned long recycled_nodes; // the number of nodes to pull from hash_table\n        lookahead_size -= N;\n        if (temp <= history_limit)\n        {               \n            if (history_size <= 3)\n            {\n                if ((3-history_size) >= N)\n                    new_nodes = 0;\n                else\n                    new_nodes = N - (3-history_size);\n            }\n            else\n            {\n                new_nodes = N;\n            }\n                \n            recycled_nodes = 0;\n            history_size = temp;\n        }\n        else\n        {\n            if (history_size != history_limit)\n            {\n                new_nodes = history_limit - history_size;\n                recycled_nodes = temp - history_limit;\n                history_size = history_limit;                \n            }\n            else\n            {\n                new_nodes = 0;\n                recycled_nodes = N;\n            }\n        }\n\n        unsigned long i = lookahead_limit + 2;\n    \n        // if there are any \"new\" nodes to add to the hash table \n        if (new_nodes != 0)\n        {\n            unsigned long stop = i - new_nodes;             \n            for (; i > stop; --i)\n            {\n                nodes[next_free_node].next = 0;\n                nodes[next_free_node].id = buffer.get_element_id(i);\n                id_table[nodes[next_free_node].id] = 0;\n\n                unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]);\n\n                if (hash_table[new_hash] != 0)\n                    id_table[hash_table[new_hash]->id] = &nodes[next_free_node];\n                nodes[next_free_node].next = hash_table[new_hash];\n                hash_table[new_hash] = &nodes[next_free_node];\n\n                ++next_free_node;                \n            }\n        } // if (new_nodes != 0)\n\n\n    \n        unsigned long stop = i - recycled_nodes;     \n        unsigned long old = old_history_size-1+lookahead_limit;\n        for (; i > stop; --i)\n        {            \n            // find the next node to recycle in hash_table\n            node* recycled_node;\n            \n            \n            unsigned long old_id = buffer.get_element_id(old);\n            \n            // find the node with id old_id  \n            if (id_table[old_id] == 0)\n            {\n                unsigned long old_hash = hash(buffer[old],buffer[old-1],buffer[old-2],buffer[old-3]);\n                recycled_node = hash_table[old_hash];\n\n                // fill the gap left by removing this node\n                hash_table[old_hash] = recycled_node->next;\n            }\n            else\n            {\n                recycled_node = id_table[old_id]->next;\n\n                // fill the gap left by removing this node\n                id_table[old_id]->next = recycled_node->next;\n            }\n\n            --old;\n\n\n\n\n\n\n            recycled_node->next = 0;\n            recycled_node->id = buffer.get_element_id(i);\n            id_table[recycled_node->id] = 0;\n\n            unsigned long new_hash = hash(buffer[i],buffer[i-1],buffer[i-2],buffer[i-3]);\n\n            if (hash_table[new_hash] != 0) \n                id_table[hash_table[new_hash]->id] = recycled_node;\n\n            recycled_node->next = hash_table[new_hash];\n            hash_table[new_hash] = recycled_node;\n       \n        } // for (; i > stop; --i)\n\n\n\n\n        buffer.rotate_left(N);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_2<sliding_buffer>::\n    add (\n        unsigned char symbol\n    )\n    {\n        if (lookahead_size == lookahead_limit)\n        {\n            shift_buffer(1);            \n        }\n        buffer[lookahead_limit-1-lookahead_size] = symbol;\n        ++lookahead_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename sliding_buffer\n        >\n    void lz77_buffer_kernel_2<sliding_buffer>::\n    find_match (\n        unsigned long& index,\n        unsigned long& length,\n        unsigned long min_match_length\n    )\n    {\n        unsigned long match_length = 0;   // the length of the longest match we find\n        unsigned long match_index = 0;    // the index of the longest match we find\n\n \n        const unsigned long hash_value = hash(lookahead_buffer(0),\n                                              lookahead_buffer(1),\n                                              lookahead_buffer(2),\n                                              lookahead_buffer(3)\n                                              );\n\n\n \n        node* temp = hash_table[hash_value];\n        while (temp != 0)\n        {             \n            // current position in the history buffer\n            unsigned long hpos = buffer.get_element_index(temp->id)-lookahead_limit;  \n            // current position in the lookahead buffer\n            unsigned long lpos = 0;             \n\n            // find length of this match\n            while (history_buffer(hpos) == lookahead_buffer(lpos))\n            {\n                ++lpos;\n                if (hpos == 0)\n                    break;\n                --hpos;\n                if (lpos == lookahead_size)\n                    break;                    \n            }\n\n            if (lpos > match_length)\n            {\n                match_length = lpos;\n                match_index = buffer.get_element_index(temp->id)-lookahead_limit;\n                // if this is the longest possible match then stop looking\n                if (lpos == lookahead_limit)\n                    break;\n            }\n            \n\n            temp = temp->next;\n        } // while (temp != 0)\n\n\n\n\n        // if we found a match that was long enough then report it\n        if (match_length >= min_match_length)\n        {\n            shift_buffer(match_length);\n            index = match_index;\n            length = match_length;\n        }\n        else\n        {\n            length = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZ77_BUFFER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/lz77_buffer/lz77_buffer_kernel_abstract.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_\n#ifdef DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    class lz77_buffer \n    {\n        /*!\n            INITIAL VALUE\n                get_history_buffer_limit() == defined by constructor arguments\n                get_lookahead_buffer_limit() == defined by constructor arguments\n                get_history_buffer_size() == 0\n                get_lookahead_buffer_size() == 0\n\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a pair of buffers (history and lookahead buffers) \n                used during lz77 style compression.\n\n                It's main function is to search the history buffer for long strings which\n                match the contents (or a part of the contents) of the lookahead buffer.\n                \n\n            HISTORY AND LOOKAHEAD BUFFERS\n                The buffers have the following structure:\n                | history buffer | lookahead buffer |  <-- contents of buffers\n                |  ...9876543210 | 0123456789...    |  <-- index numbers\n\n                So this means that history_buffer(0) == 'r', history_buffer(1) == 'e'\n                and so on.  And lookahead_buffer(0) == 'l', lookahead_buffer(1) == 'o'\n                and so on.\n\n\n                What shift_buffers() does in english:\n                    This function just means that the buffers have their contents shifted\n                    left by N elements and that elements shifted out of the lookahead buffer \n                    go into the history buffer.   An example will make it clearer.\n\n                    Suppose that we have the following buffers before we apply shift_buffers()\n                        history_buffer() == \"hey\" and\n                        lookahead_buffer() == \"lookahead buffer\"\n                    And in the same format as the above diagram it would be\n                        | hey | lookahead buffer |  <-- contents of buffers\n                        | 210 | 0123456789...    |  <-- index numbers\n\n                    Applying shift_buffers(4) will give\n                        lookahead_buffer() == \"ahead buffer\"\n                        history_buffer() == \"heylook\" or \"eylook\" or \"ylook\" or \"look\"\n\n                    You might be wondering why the history_buffer can resize itself in \n                    such a nondeterministic way.  It is just to allow a lot of freedom in the \n                    implementations of this object.                                  \n        !*/\n\n    public:\n\n        lz77_buffer (\n            unsigned long total_limit,\n            unsigned long lookahead_limit            \n        );\n        /*!\n            requires\n                - 6 < total_limit < 32\n                - 15 < lookahead_limit <= 2^(total_limit-2)\n            ensures                \n                - #*this is properly initialized\n                - #get_history_buffer_limit() == 2^total_limit  - lookahead_limit\n                - #get_lookahead_buffer_limit() == lookahead_limit\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~lz77_buffer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void shift_buffers (\n            unsigned long N\n        );\n        /*!\n            requires\n                - N <= get_lookahead_buffer_size()\n            ensures\n                - #get_lookahead_buffer_size() == get_lookahead_buffer_size() - N\n                - #get_history_buffer_size() >= N\n                - #get_history_buffer_size() <= get_history_buffer_size()+N\n                - #get_history_buffer_size() <= get_history_buffer_limit()\n                - for all i where 0 <= i < N:\n                    #history_buffer(N-1-i) == lookahead_buffer(i)\n                - for all i where 0 <= i < #get_history_buffer_size()-N:\n                    #history_buffer(N+i) == history_buffer(i)\n                - for all i where 0 <= i < #get_lookahead_buffer_size()\n                    #lookahead_buffer(i) == lookahead_buffer(N+i)            \n        !*/\n\n        void add (\n            unsigned char symbol\n        );\n        /*!\n            ensures\n                - if (get_lookahead_buffer_size() == get_lookahead_buffer_limit()) then\n                    - performs shift_buffers(1)\n                    - #lookahead_buffer(get_lookahead_buffer_limit()-1) == symbol\n                    - #get_lookahead_buffer_size() == get_lookahead_buffer_size()\n                - else\n                    - #lookahead_buffer(get_lookahead_buffer_size()) == symbol\n                    - #get_lookahead_buffer_size() == get_lookahead_buffer_size() + 1                                    \n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void find_match (\n            unsigned long& index,\n            unsigned long& length,\n            unsigned long min_match_length\n        );\n        /*!\n            ensures\n                - if (#length != 0) then\n                    - #length >= min_match_length\n                    - for all i where 0 <= i < #length:\n                      history_buffer(#index-i) == lookahead_buffer(i)\n                    - performs shift_buffers(#length)\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        unsigned long get_history_buffer_limit (\n        ) const;\n        /*!\n            ensures\n                - returns the max number of symbols that can fit in the history buffer\n        !*/\n\n        unsigned long get_lookahead_buffer_limit (\n        ) const;\n        /*!\n            ensures\n                - returns the max number of symbols that can fit in the lookahead buffer\n        !*/\n\n        unsigned long get_history_buffer_size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of symbols currently in the history buffer\n        !*/\n\n        unsigned long get_lookahead_buffer_size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of symbols currently in the lookahead buffer\n        !*/\n\n        unsigned char lookahead_buffer (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < get_lookahead_buffer_size()\n            ensures\n                - returns the symbol in the lookahead buffer at location index\n        !*/\n\n        unsigned char history_buffer (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < get_history_buffer_size()\n            ensures\n                - returns the symbol in the history buffer at location index\n        !*/\n\n\n    private:\n\n        // restricted functions\n        lz77_buffer(lz77_buffer&);        // copy constructor\n        lz77_buffer& operator=(lz77_buffer&);    // assignment operator\n\n    };      \n}\n\n#endif // DLIB_LZ77_BUFFER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/lz77_buffer/lz77_buffer_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZ77_BUFFER_KERNEl_C_\n#define DLIB_LZ77_BUFFER_KERNEl_C_\n\n#include \"lz77_buffer_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename lz77_base\n        >\n    class lz77_buffer_kernel_c : public lz77_base\n    {\n        \n        public:\n        lz77_buffer_kernel_c (\n            unsigned long total_limit,\n            unsigned long lookahead_limit            \n        );\n\n        unsigned char lookahead_buffer (\n            unsigned long index\n        ) const;\n\n        unsigned char history_buffer (\n            unsigned long index\n        ) const;\n\n        void shift_buffers (\n            unsigned long N\n        );\n\n\n\n        unsigned long make_safe (\n            unsigned long total_limit,\n            unsigned long lookahead_limit\n        )\n        /*!\n            ensures\n                - if ( 6 < total_limit < 32 && \n                       15 < lookahead_limit <= 2^(total_limit-2) \n                       ) then\n                    - returns total_limit\n                - else\n                    - throws due to failed CASSERT\n        !*/\n        {\n            unsigned long exp_size = (total_limit!=0)?total_limit-2:0;\n            unsigned long two_pow_total_limit_minus_2 = 1;\n            while (exp_size != 0)\n            {\n                --exp_size;\n                two_pow_total_limit_minus_2 <<= 1;            \n            }\n\n            // make sure requires clause is not broken\n            DLIB_CASSERT( 6 < total_limit && total_limit < 32 &&\n                    15 < lookahead_limit && lookahead_limit <= two_pow_total_limit_minus_2,\n                \"\\tlz77_buffer::lz77_buffer(unsigned long,unsigned long)\"\n                << \"\\n\\ttotal_limit must be in the range 7 to 31 and \\n\\tlookahead_limit in the range 15 to 2^(total_limit-2)\"\n                << \"\\n\\tthis:            \" << this\n                << \"\\n\\ttotal_limit:     \" << total_limit\n                << \"\\n\\tlookahead_limit: \" << lookahead_limit\n                );\n\n            return total_limit;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lz77_base\n        >\n    void lz77_buffer_kernel_c<lz77_base>::\n    shift_buffers (\n            unsigned long N\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( N <= this->get_lookahead_buffer_size(),\n            \"\\tvoid lz77_buffer::shift_buffers(unsigned long)\"\n            << \"\\n\\tN must be <= the number of chars in the lookahead buffer\"\n            << \"\\n\\tthis:                        \" << this\n            << \"\\n\\tget_lookahead_buffer_size(): \" << this->get_lookahead_buffer_size()\n            << \"\\n\\tN:                           \" << N\n            );\n\n        // call the real function\n        lz77_base::shift_buffers(N);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lz77_base\n        >\n    unsigned char lz77_buffer_kernel_c<lz77_base>::\n    history_buffer (\n            unsigned long index\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( index < this->get_history_buffer_size(),\n            \"\\tunsigned char lz77_buffer::history_buffer(unsigned long) const\"\n            << \"\\n\\tindex must be in the range 0 to get_history_buffer_size()-1\"\n            << \"\\n\\tthis:                      \" << this\n            << \"\\n\\tget_history_buffer_size(): \" << this->get_history_buffer_size()\n            << \"\\n\\tindex:                     \" << index\n            );\n\n        // call the real function\n        return lz77_base::history_buffer(index);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lz77_base\n        >\n    unsigned char lz77_buffer_kernel_c<lz77_base>::\n    lookahead_buffer (\n            unsigned long index\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( index < this->get_lookahead_buffer_size(),\n            \"\\tunsigned char lz77_buffer::lookahead_buffer(unsigned long) const\"\n            << \"\\n\\tindex must be in the range 0 to get_lookahead_buffer_size()-1\"\n            << \"\\n\\tthis:                        \" << this\n            << \"\\n\\tget_lookahead_buffer_size(): \" << this->get_lookahead_buffer_size()\n            << \"\\n\\tindex:                       \" << index\n            );\n\n        // call the real function\n        return lz77_base::lookahead_buffer(index);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lz77_base\n        >\n    lz77_buffer_kernel_c<lz77_base>::\n    lz77_buffer_kernel_c (\n        unsigned long total_limit,\n        unsigned long lookahead_limit  \n    ) :\n        lz77_base(make_safe(total_limit,lookahead_limit),lookahead_limit)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZ77_BUFFER_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/lz77_buffer.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZ77_BUFFEr_\n#define DLIB_LZ77_BUFFEr_\n\n\n#include \"lz77_buffer/lz77_buffer_kernel_1.h\"\n#include \"lz77_buffer/lz77_buffer_kernel_2.h\"\n#include \"lz77_buffer/lz77_buffer_kernel_c.h\"\n\n#include \"sliding_buffer.h\"\n\n\nnamespace dlib\n{\n\n\n    class lz77_buffer\n    {\n\n        lz77_buffer() {}\n\n        typedef sliding_buffer<unsigned char>::kernel_1a sb1;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     lz77_buffer_kernel_1<sb1>   \n                    kernel_1a;\n        typedef     lz77_buffer_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n\n        // kernel_2a        \n        typedef     lz77_buffer_kernel_2<sb1>   \n                    kernel_2a;\n        typedef     lz77_buffer_kernel_c<kernel_2a>\n                    kernel_2a_c;\n   \n\n    };\n}\n\n#endif // DLIB_LZ77_BUFFEr_\n\n"
  },
  {
    "path": "dlib/lzp_buffer/lzp_buffer_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZP_BUFFER_KERNEl_1_\n#define DLIB_LZP_BUFFER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"lzp_buffer_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename sbuf\n        >\n    class lzp_buffer_kernel_1 \n    {\n        /*!\n            REQUIREMENTS ON sbuf\n                sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h\n                T == unsigned char\n\n            INITIAL VALUE\n                - buffer.size() == the size as defined by the constructor\n                - table_size == the number of elements in the table array\n                - for all i: buffer[i] == 0\n                - for all i: table[i] == buffer.size()                \n\n            CONVENTION\n                - table_size == the number of elements in the table array\n                - size() == buffer.size()\n                - operator[](i) == buffer[i]\n\n                - if (table[hash()] != buffer.size()) then\n                    - buffer.get_element_index(table[hash()]) == the index we will \n                      predict for the current context\n                - else\n                    - there is no prediction for the current context\n\n                - last_element == buffer.size()-1\n\n                \n                This is LZP with just an order-3 model without context confirmation.\n        \n        !*/\n\n    public:\n\n        explicit lzp_buffer_kernel_1 (\n            unsigned long buffer_size           \n        );\n\n        virtual ~lzp_buffer_kernel_1 (\n        );\n\n        void clear(\n        );\n\n        inline void add (\n            unsigned char symbol\n        );\n\n        inline unsigned long predict_match (\n            unsigned long& index\n        );\n\n        inline size_t size (\n        ) const;\n\n        inline unsigned char operator[] (\n            unsigned long index\n        ) const;\n\n    private:\n\n        inline unsigned long hash (\n        ) const\n        /*!\n            ensures\n                - returns a hash computed from the current context.  This hash\n                  is always in the range for table.\n        !*/\n        {\n            unsigned long temp = buffer[0];\n            temp <<= 16;\n            unsigned long temp2 = buffer[1];\n            temp2 <<= 8;\n            unsigned long temp3 = buffer[2];\n            temp = temp|temp2|temp3;\n\n            temp = ((temp>>11)^temp)&0xFFFF;\n           \n            return temp;\n        }\n\n        sbuf buffer;\n        const unsigned long table_size;\n        unsigned long* const table;\n        unsigned long last_element;\n\n        // restricted functions\n        lzp_buffer_kernel_1(const lzp_buffer_kernel_1<sbuf>&);        // copy constructor\n        lzp_buffer_kernel_1<sbuf>& operator=(const lzp_buffer_kernel_1<sbuf>&);    // assignment operator\n\n    };      \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    lzp_buffer_kernel_1<sbuf>::\n    lzp_buffer_kernel_1 (\n        unsigned long buffer_size           \n    ) :\n        table_size(65536),\n        table(new unsigned long[table_size])\n    {\n        buffer.set_size(buffer_size);\n\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n            buffer[i] = 0;\n\n        for (unsigned long i = 0; i < table_size; ++i)\n            table[i] = buffer.size();\n\n        last_element = buffer.size()-1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    lzp_buffer_kernel_1<sbuf>::\n    ~lzp_buffer_kernel_1 (\n    )\n    {\n        delete [] table;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    void lzp_buffer_kernel_1<sbuf>::\n    clear(\n    )\n    {\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n            buffer[i] = 0;\n\n        for (unsigned long i = 0; i < table_size; ++i)\n            table[i] = buffer.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    void lzp_buffer_kernel_1<sbuf>::\n    add (\n        unsigned char symbol\n    ) \n    { \n        buffer.rotate_left(1); \n        buffer[0] = symbol; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    unsigned long lzp_buffer_kernel_1<sbuf>::\n    predict_match (\n        unsigned long& index\n    )\n    {\n        const unsigned long i = hash();\n\n        if (table[i] != buffer.size())\n        {\n            index = buffer.get_element_index(table[i]);\n\n            if (index > 20)\n            {\n                // update the prediction for this context\n                table[i] = buffer.get_element_id(last_element);\n            }\n            return 3;\n        }\n        else\n        {\n            // update the prediction for this context\n            table[i] = buffer.get_element_id(last_element);\n            return 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    size_t lzp_buffer_kernel_1<sbuf>::\n    size (\n    ) const \n    { \n        return buffer.size(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    unsigned char lzp_buffer_kernel_1<sbuf>::\n    operator[] (\n        unsigned long index\n    ) const \n    { \n        return buffer[index]; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZP_BUFFER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/lzp_buffer/lzp_buffer_kernel_2.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZP_BUFFER_KERNEl_2_\n#define DLIB_LZP_BUFFER_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"lzp_buffer_kernel_abstract.h\"\n#include <new>\n\nnamespace dlib\n{\n\n    template <\n        typename sbuf\n        >\n    class lzp_buffer_kernel_2 \n    {\n        /*!\n            REQUIREMENTS ON sbuf\n                sbuf is an implementation of sliding_buffer/sliding_buffer_kernel_abstract.h\n                T == unsigned char\n\n            INITIAL VALUE\n                - buffer.size() == the size as defined by the constructor\n                - table_size == the number of elements in the table3 and table4 arrays\n                - for all i: buffer[i] == 0\n                - for all i: table3[i] == buffer.size()\n                - for all i: table4[i] == buffer.size()\n\n            CONVENTION\n                - table_size == the number of elements in the table3 and table4 arrays\n                - size() == buffer.size()\n                - operator[](i) == buffer[i]\n\n                \n\n                - last_element == buffer.size()-1\n\n                \n                This is LZP with an order-5-4-3 model with context confirmation.\n                To save memory the order5 and order3 predictions exist in the same\n                table, that is, table3.\n        \n        !*/\n\n    public:\n\n        explicit lzp_buffer_kernel_2 (\n            unsigned long buffer_size           \n        );\n\n        virtual ~lzp_buffer_kernel_2 (\n        );\n\n        void clear(\n        );\n\n        inline void add (\n            unsigned char symbol\n        );\n\n        inline unsigned long predict_match (\n            unsigned long& index\n        );\n\n        inline size_t size (\n        ) const;\n\n        inline unsigned char operator[] (\n            unsigned long index\n        ) const;\n\n    private:\n\n        inline bool verify (\n            unsigned long index\n        ) const\n        /*!\n            ensures\n                - returns true if buffer[index]'s context matches the current context\n        !*/\n        { \n            if (index+3 < buffer.size())\n            {\n                if (buffer[0] != buffer[index+1])\n                    return false;\n                if (buffer[1] != buffer[index+2])\n                    return false;\n                if (buffer[2] != buffer[index+3])\n                    return false;\n                return true;\n            }\n            else\n            {\n                // just call this a match\n                return true;\n            }\n        }\n\n\n        sbuf buffer;        \n        unsigned long* table3;\n        unsigned long* table4;\n        unsigned long last_element;\n        const unsigned long table_size;\n\n        // restricted functions\n        lzp_buffer_kernel_2(const lzp_buffer_kernel_2<sbuf>&);        // copy constructor\n        lzp_buffer_kernel_2<sbuf>& operator=(const lzp_buffer_kernel_2<sbuf>&);    // assignment operator\n\n    };      \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    lzp_buffer_kernel_2<sbuf>::\n    lzp_buffer_kernel_2 (\n        unsigned long buffer_size           \n    ) :\n        table3(0),\n        table4(0),\n        table_size(65536)\n    {\n        buffer.set_size(buffer_size);\n\n        table3 = new (std::nothrow) unsigned long[table_size];\n        table4 = new (std::nothrow) unsigned long[table_size];\n\n        if (!table3 || !table4)\n        {\n            if (!table3)\n                delete [] table3;\n            if (!table4)\n                delete [] table4;\n\n            throw std::bad_alloc();\n        }\n        \n        \n\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n            buffer[i] = 0;\n\n        for (unsigned long i = 0; i < table_size; ++i)\n        {\n            table3[i] = buffer.size();\n            table4[i] = buffer.size();\n        }\n\n        last_element = buffer.size()-1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    lzp_buffer_kernel_2<sbuf>::\n    ~lzp_buffer_kernel_2 (\n    )\n    {\n        delete [] table3;\n        delete [] table4;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    void lzp_buffer_kernel_2<sbuf>::\n    clear(\n    )\n    {\n        for (unsigned long i = 0; i < buffer.size(); ++i)\n            buffer[i] = 0;\n\n        for (unsigned long i = 0; i < table_size; ++i)\n        {\n            table3[i] = buffer.size();\n            table4[i] = buffer.size();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    void lzp_buffer_kernel_2<sbuf>::\n    add (\n        unsigned char symbol\n    ) \n    { \n        buffer.rotate_left(1); \n        buffer[0] = symbol; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    unsigned long lzp_buffer_kernel_2<sbuf>::\n    predict_match (\n        unsigned long& index\n    )\n    {\n        unsigned long temp1 = buffer[0];\n        unsigned long temp2 = buffer[1];\n        temp2 <<= 8;\n        unsigned long temp3 = buffer[2];\n        temp3 <<= 16;\n        unsigned long temp4 = buffer[3];\n        temp4 <<= 24;\n        unsigned long temp5 = buffer[4];\n        temp5 <<= 12;\n        \n        unsigned long context1 = temp1|temp2|temp3;    \n        unsigned long context2 = context1|temp4;\n\n\n        const unsigned long i5 = ((temp5|(context2>>20))^context2)&0xFFFF;\n        const unsigned long i4 = ((context2>>15)^context2)&0xFFFF;\n        const unsigned long i3 = ((context1>>11)^context1)&0xFFFF;\n      \n\n\n        // check the 5-order context's prediction\n        if (table3[i5] != buffer.size() && \n            verify(buffer.get_element_index(table3[i5])) )\n        {\n            index = buffer.get_element_index(table3[i5]);\n            if (index > 20)\n            {\n                // update the prediction for this context\n                table3[i3] = buffer.get_element_id(last_element);\n                table4[i4] = table3[i3];     \n                table3[i5] = table3[i3];\n            }\n            return 5;\n        }\n        // check the 4-order context's prediction\n        else if (table4[i4] != buffer.size() && \n            verify(buffer.get_element_index(table4[i4])) )\n        {\n            index = buffer.get_element_index(table4[i4]);\n            if (index > 20)\n            {\n                // update the prediction for this context\n                table3[i3] = buffer.get_element_id(last_element);\n                table4[i4] = table3[i3];           \n                table3[i5] = table3[i3];          \n            }\n            return 4;\n        }\n        // check the 3-order context's prediction\n        else if (table3[i3] != buffer.size() &&\n            verify(buffer.get_element_index(table3[i3])))\n        {\n            index = buffer.get_element_index(table3[i3]);\n            \n            if (index > 20)\n            {\n                // update the prediction for this context\n                table3[i3] = buffer.get_element_id(last_element);\n                table4[i4] = table3[i3];        \n                table3[i5] = table3[i3];             \n            }\n            return 3;\n        } \n        else\n        {\n            // update the prediction for this context\n            table3[i3] = buffer.get_element_id(last_element);\n            table4[i4] = table3[i3];            \n            table3[i5] = table3[i3];         \n            \n            return 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    size_t lzp_buffer_kernel_2<sbuf>::\n    size (\n    ) const \n    { \n        return buffer.size(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sbuf\n        >\n    unsigned char lzp_buffer_kernel_2<sbuf>::\n    operator[] (\n        unsigned long index\n    ) const \n    { \n        return buffer[index]; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZP_BUFFER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/lzp_buffer/lzp_buffer_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_\n#ifdef DLIB_LZP_BUFFER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    class lzp_buffer \n    {\n        /*!\n            INITIAL VALUE\n                size() == some value defined by the constructor argument\n                Initially this object is at some predefined empty or ground state.\n                for all i: (*this)[i] == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some varation on the LZP algorithm\n                described by Charles Bloom in his paper \"LZP: a new data\n                compression algorithm\"\n\n                The LZP algorithm is a lot like lz77 except there is no need to pass\n                the location of matches in the history buffer to the decoder because\n                LZP uses the data it has already seen to predict the location of the\n                next match.  \n\n            NOTE\n                The add() and predict_match() functions must be called in the same\n                order by the coder and decoder.  If they aren't the state of the \n                lzp_buffer objects in the coder and decoder may differ and the decoder \n                won't be able to correctly decode the data stream.\n        !*/\n\n    public:\n\n        explicit lzp_buffer (\n            unsigned long buffer_size           \n        );\n        /*!\n            requires\n                - 10 < buffer_size < 32\n            ensures                \n                - #*this is properly initialized\n                - #size() == 2^buffer_size\n            throws\n                - std::bad_alloc\n        !*/\n\n        virtual ~lzp_buffer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds\n        !*/\n\n        void add (\n            unsigned char symbol\n        );\n        /*!\n            ensures\n                - shifts everything in the history buffer left 1.\n                  (i.e. #(*this)[i+1] == (*this)[i])\n                - #(*this)[0] == symbol\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds  \n        !*/\n\n        unsigned long predict_match (\n            unsigned long& index\n        );\n        /*!\n            ensures\n                - updates the prediction for the current context.\n                  (the current context is the last few symbols seen. i.e. (*this)[0], \n                   (*this)[1], etc.)\n                - if (*this can generate a prediction) then\n                    - #index == the predicted location of a match in the history buffer.\n                      (i.e. (*this)[#index] is the first symbol of the predicted match)\n                    - returns the order this prediction came from\n                - else\n                    - returns 0\n            throws\n                - std::bad_alloc\n                    if this exception is thrown then #*this is unusable \n                    until clear() is called and succeeds            \n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns the size of the history buffer\n        !*/\n\n        unsigned char operator[] (\n            unsigned long index\n        ) const;\n        /*!\n            requires\n                - index < size()\n            ensures\n                - returns the symbol at the given index in the history buffer\n        !*/\n\n    private:\n\n        // restricted functions\n        lzp_buffer(const lzp_buffer&);        // copy constructor\n        lzp_buffer& operator=(const lzp_buffer&);    // assignment operator\n\n    };      \n}\n\n#endif // DLIB_LZP_BUFFER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/lzp_buffer/lzp_buffer_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZP_BUFFER_KERNEl_C_\n#define DLIB_LZP_BUFFER_KERNEl_C_\n\n#include \"lzp_buffer_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n    template <\n        typename lzp_base\n        >\n    class lzp_buffer_kernel_c : public lzp_base\n    {\n        \n        public:\n        lzp_buffer_kernel_c (\n            unsigned long buffer_size         \n        );\n\n     \n        unsigned char operator[] (\n            unsigned long index\n        ) const;\n\n\n        unsigned long make_safe (\n            unsigned long buffer_size\n        )\n        /*!\n            ensures\n                - if ( 10 < buffer_size < 32) then\n                    - returns buffer_size\n                - else\n                    - throws due to failed CASSERT\n        !*/\n        {\n\n            // make sure requires clause is not broken\n            DLIB_CASSERT( 10 < buffer_size && buffer_size < 32,\n                \"\\tlzp_buffer::lzp_buffer(unsigned long)\"\n                << \"\\n\\tbuffer_size must be in the range 11 to 31.\"\n                << \"\\n\\tthis:         \" << this\n                << \"\\n\\tbuffer_size:  \" << buffer_size\n                );\n\n            return buffer_size;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lzp_base\n        >\n    unsigned char lzp_buffer_kernel_c<lzp_base>::\n    operator[] (\n            unsigned long index\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( index < this->size(),\n            \"\\tunsigned char lzp_buffer::operator[](unsigned long) const\"\n            << \"\\n\\tindex must be in the range 0 to size()()-1\"\n            << \"\\n\\tthis:    \" << this\n            << \"\\n\\tsize():  \" << this->size()\n            << \"\\n\\tindex:   \" << index\n            );\n\n        // call the real function\n        return lzp_base::operator[](index);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename lzp_base\n        >\n    lzp_buffer_kernel_c<lzp_base>::\n    lzp_buffer_kernel_c (\n        unsigned long buffer_size\n    ) :\n        lzp_base(make_safe(buffer_size))\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_LZP_BUFFER_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/lzp_buffer.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LZP_BUFFEr_\n#define DLIB_LZP_BUFFEr_\n\n\n#include \"lzp_buffer/lzp_buffer_kernel_1.h\"\n#include \"lzp_buffer/lzp_buffer_kernel_2.h\"\n#include \"lzp_buffer/lzp_buffer_kernel_c.h\"\n\n#include \"sliding_buffer.h\"\n\n\nnamespace dlib\n{\n\n\n    class lzp_buffer\n    {\n\n        lzp_buffer() {}\n\n        typedef sliding_buffer<unsigned char>::kernel_1a sb1;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     lzp_buffer_kernel_1<sb1>   \n                    kernel_1a;\n        typedef     lzp_buffer_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n        // kernel_2a        \n        typedef     lzp_buffer_kernel_2<sb1>   \n                    kernel_2a;\n        typedef     lzp_buffer_kernel_c<kernel_2a>\n                    kernel_2a_c;\n  \n\n    };\n}\n\n#endif // DLIB_LZP_BUFFEr_\n\n"
  },
  {
    "path": "dlib/manifold_regularization/linear_manifold_regularizer.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LINEAR_MANIFOLD_ReGULARIZER_Hh_\n#define DLIB_LINEAR_MANIFOLD_ReGULARIZER_Hh_\n\n#include \"linear_manifold_regularizer_abstract.h\"\n#include <limits>\n#include <vector>\n#include \"../serialize.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace impl\n    {\n        class undirected_adjacency_list\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is simply a tool for turning a vector of sample_pair objects\n                    into an adjacency list with floating point weights on each edge.  \n            !*/\n        public:\n\n            undirected_adjacency_list (\n            )\n            {\n                _size = 0;\n                sum_edge_weights = 0;\n            }\n\n            struct neighbor \n            {\n                neighbor(unsigned long idx, double w):index(idx), weight(w) {}\n                neighbor():index(0), weight(0) {}\n\n                unsigned long index;\n                double weight;\n            };\n\n            typedef std::vector<neighbor>::const_iterator const_iterator;\n\n            size_t size (\n            ) const\n            /*!\n                ensures\n                    - returns the number of vertices in this graph\n            !*/\n            {\n                return _size;\n            }\n\n            const_iterator begin(\n                unsigned long idx\n            ) const\n            /*!\n                requires\n                    - idx < size()\n                ensures\n                    - returns an iterator that points to the first neighbor of \n                      the idx'th vertex.\n            !*/\n            {\n                return blocks[idx];\n            }\n\n            const_iterator end(\n                unsigned long idx\n            ) const\n            /*!\n                requires\n                    - idx < size()\n                ensures\n                    - returns an iterator that points one past the last neighbor\n                      of the idx'th vertex.\n            !*/\n            {\n                return blocks[idx+1];\n            }\n\n\n            template <typename vector_type, typename weight_function_type>\n            void build (\n                const vector_type& edges,\n                const weight_function_type& weight_funct\n            ) \n            /*!\n                requires\n                    - vector_type == a type with an interface compatible with std::vector and \n                      it must in turn contain objects with an interface compatible with dlib::sample_pair\n                    - edges.size() > 0\n                    - contains_duplicate_pairs(edges) == false\n                    - weight_funct(edges[i]) must be a valid expression that evaluates to a\n                      floating point number >= 0\n                ensures\n                    - #size() == one greater than the max index in edges.\n                    - builds the adjacency list so that it contains all the given edges.\n                    - The weight in each neighbor is set to the output of the weight_funct()\n                      for the associated edge.\n            !*/\n            {\n\n\n                // Figure out how many neighbors each sample ultimately has.  We do this so \n                // we will know how much space to allocate in the data vector.\n                std::vector<unsigned long> num_neighbors;\n                num_neighbors.reserve(edges.size());\n\n                for (unsigned long i = 0; i < edges.size(); ++i)\n                {\n                    // make sure num_neighbors is always big enough \n                    const unsigned long min_size = std::max(edges[i].index1(), edges[i].index2())+1;\n                    if (num_neighbors.size() < min_size)\n                        num_neighbors.resize(min_size,  0);\n\n                    num_neighbors[edges[i].index1()] += 1;\n                    num_neighbors[edges[i].index2()] += 1;\n                }\n\n                _size = num_neighbors.size();\n\n                // Now setup the iterators in blocks.  Also setup a version of blocks that holds\n                // non-const iterators so we can use it below when we populate data.\n                std::vector<std::vector<neighbor>::iterator> mutable_blocks;\n                data.resize(edges.size()*2); // each edge will show up twice \n                blocks.resize(_size + 1);\n                blocks[0] = data.begin();\n                mutable_blocks.resize(_size + 1);\n                mutable_blocks[0] = data.begin();\n                for (unsigned long i = 0; i < num_neighbors.size(); ++i)\n                {\n                    blocks[i+1]         = blocks[i]         + num_neighbors[i];\n                    mutable_blocks[i+1] = mutable_blocks[i] + num_neighbors[i];\n                }\n\n                sum_edge_weights = 0;\n                // finally, put the edges into data\n                for (unsigned long i = 0; i < edges.size(); ++i)\n                {\n                    const double weight = weight_funct(edges[i]);\n                    sum_edge_weights += weight;\n\n                    // make sure requires clause is not broken\n                    DLIB_ASSERT(weight >= 0,\n                        \"\\t void linear_manifold_regularizer::build()\"\n                        << \"\\n\\t You supplied a weight_funct() that generated a negative weight.\"\n                        << \"\\n\\t weight: \" << weight \n                        );\n\n                    *mutable_blocks[edges[i].index1()]++ = neighbor(edges[i].index2(), weight);\n                    *mutable_blocks[edges[i].index2()]++ = neighbor(edges[i].index1(), weight);\n                }\n\n            }\n\n            double sum_of_edge_weights (\n            ) const\n            {\n                return sum_edge_weights;\n            }\n\n        private:\n\n            /*!\n                INITIAL VALUE\n                    - _size == 0\n                    - data.size() == 0\n                    - blocks.size() == 0\n                    - sum_edge_weights == 0\n\n                CONVENTION\n                    - size() == _size\n                    - blocks.size() == _size + 1\n                    - sum_of_edge_weights() == sum_edge_weights\n                    - blocks == a vector of iterators that point into data.  \n                      For all valid i:\n                        - The iterator range [blocks[i], blocks[i+1]) contains all the edges\n                          for the i'th node in the graph\n            !*/\n\n            std::vector<neighbor> data;\n            std::vector<const_iterator> blocks; \n            unsigned long _size;\n\n            double sum_edge_weights;\n        };\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class linear_manifold_regularizer\n    {\n\n    public:\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n\n\n        template <\n            typename vector_type1, \n            typename vector_type2, \n            typename weight_function_type\n            >\n        void build (\n            const vector_type1& samples,\n            const vector_type2& edges,\n            const weight_function_type& weight_funct\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(edges.size() > 0 &&\n                        contains_duplicate_pairs(edges) == false &&\n                        max_index_plus_one(edges) <= samples.size(),\n                \"\\t void linear_manifold_regularizer::build()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t edges.size():                    \" << edges.size()\n                << \"\\n\\t samples.size():                  \" << samples.size()\n                << \"\\n\\t contains_duplicate_pairs(edges): \" << contains_duplicate_pairs(edges) \n                << \"\\n\\t max_index_plus_one(edges):       \" << max_index_plus_one(edges) \n                );\n\n\n            impl::undirected_adjacency_list graph;\n            graph.build(edges, weight_funct);\n\n            sum_edge_weights = graph.sum_of_edge_weights();\n\n            make_mr_matrix(samples, graph);\n        }\n\n        long dimensionality (\n        ) const { return reg_mat.nr(); }\n\n        general_matrix get_transformation_matrix (\n            scalar_type intrinsic_regularization_strength\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(intrinsic_regularization_strength >= 0,\n                \"\\t matrix linear_manifold_regularizer::get_transformation_matrix()\"\n                << \"\\n\\t This value must not be negative\"\n                << \"\\n\\t intrinsic_regularization_strength: \" << intrinsic_regularization_strength \n                );\n\n            if (dimensionality() == 0)\n                return general_matrix();\n\n\n            // This isn't how it's defined in the referenced paper but normalizing these kinds of\n            // sums is typical of most machine learning algorithms.  Moreover, doing this makes\n            // the argument to this function more invariant to the size of the edge set.  So it\n            // should make it easier for the user.\n            intrinsic_regularization_strength /= sum_edge_weights;\n\n            return inv_lower_triangular(chol(identity_matrix<scalar_type>(reg_mat.nr()) + intrinsic_regularization_strength*reg_mat));\n        }\n\n    private:\n\n        template <typename vector_type>\n        void make_mr_matrix (\n            const vector_type& samples,\n            const impl::undirected_adjacency_list& graph\n        )\n        /*!\n            requires\n                - samples.size() == graph.size()\n            ensures\n                - computes trans(X)*lap(graph)*X where X is the data matrix \n                  (i.e. the matrix that contains all the samples in its rows)\n                  and lap(graph) is the laplacian matrix of the graph.  The\n                  resulting matrix is stored in reg_mat.\n        !*/\n        {\n            const unsigned long dims = samples[0].size();\n            reg_mat.set_size(dims,dims);\n            reg_mat = 0;\n\n\n            typename impl::undirected_adjacency_list::const_iterator beg, end;\n\n            // loop over the columns of the X matrix\n            for (unsigned long d = 0; d < dims; ++d)\n            {\n                // loop down the row of X\n                for (unsigned long i = 0; i < graph.size(); ++i)\n                {\n                    beg = graph.begin(i);\n                    end = graph.end(i);\n\n                    // if this node in the graph has any neighbors\n                    if (beg != end)\n                    {\n                        double weight_sum = 0;\n                        double val = 0;\n                        for (; beg != end; ++beg)\n                        {\n                            val -= beg->weight * samples[beg->index](d);\n                            weight_sum += beg->weight;\n                        }\n                        val += weight_sum * samples[i](d);\n\n                        for (unsigned long j = 0; j < dims; ++j)\n                        {\n                            reg_mat(d,j) += val*samples[i](j);\n                        }\n                    }\n                }\n            }\n\n        }\n\n        general_matrix reg_mat;\n        double sum_edge_weights;\n    };\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LINEAR_MANIFOLD_ReGULARIZER_Hh_\n\n"
  },
  {
    "path": "dlib/manifold_regularization/linear_manifold_regularizer_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_\n#ifdef DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_\n\n#include <limits>\n#include <vector>\n#include \"../serialize.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class linear_manifold_regularizer\n    {\n        /*!\n            REQUIREMENTS ON matrix_type\n                Must be some type of dlib::matrix.\n\n            INITIAL VALUE\n                - dimensionality() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                Many learning algorithms attempt to minimize a function that, at a high \n                level, looks like this:   \n                    f(w) == complexity + training_set_error\n\n                The idea is to find the set of parameters, w, that gives low error on \n                your training data but also is not \"complex\" according to some particular\n                measure of complexity.  This strategy of penalizing complexity is \n                usually called regularization.\n\n                In the above setting, all the training data consists of labeled samples.  \n                However, it would be nice to be able to benefit from unlabeled data.  \n                The idea of manifold regularization is to extract useful information from \n                unlabeled data by first defining which data samples are \"close\" to each other \n                (perhaps by using their 3 nearest neighbors) and then adding a term to \n                the above function that penalizes any decision rule which produces \n                different outputs on data samples which we have designated as being close.\n                \n                It turns out that it is possible to transform these manifold regularized \n                learning problems into the normal form shown above by applying a certain kind \n                of preprocessing to all our data samples.  Once this is done we can use a \n                normal learning algorithm, such as the svm_c_linear_trainer, on just the\n                labeled data samples and obtain the same output as the manifold regularized\n                learner would have produced.  \n                \n                The linear_manifold_regularizer is a tool for creating this preprocessing \n                transformation.  In particular, the transformation is linear.  That is, it \n                is just a matrix you multiply with all your samples.  For a more detailed \n                discussion of this topic you should consult the following paper.  In \n                particular, see section 4.2.  This object computes the inverse T matrix \n                described in that section.\n\n                    Linear Manifold Regularization for Large Scale Semi-supervised Learning\n                    by Vikas Sindhwani, Partha Niyogi, and Mikhail Belkin\n        !*/\n\n    public:\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n\n        template <\n            typename vector_type1, \n            typename vector_type2, \n            typename weight_function_type\n            >\n        void build (\n            const vector_type1& samples,\n            const vector_type2& edges,\n            const weight_function_type& weight_funct\n        );\n        /*!\n            requires\n                - vector_type1 == a type with an interface compatible with std::vector and it must\n                  in turn contain dlib::matrix objects.\n                - vector_type2 == a type with an interface compatible with std::vector and \n                  it must in turn contain objects with an interface compatible with dlib::sample_pair\n                - edges.size() > 0\n                - contains_duplicate_pairs(edges) == false\n                - max_index_plus_one(edges) <= samples.size()\n                - weight_funct(edges[i]) must be a valid expression that evaluates to a\n                  floating point number >= 0\n            ensures\n                - #dimensionality() == samples[0].size()\n                - This function sets up the transformation matrix describe above.  The manifold\n                  regularization is done assuming that the samples are meant to be \"close\" \n                  according to the graph defined by the given edges.  I.e:\n                    - for all valid i:  samples[edges[i].index1()] is close to samples[edges[i].index2()].\n                      How much we care about these two samples having similar outputs according\n                      to the learned rule is given by weight_funct(edges[i]).  Bigger weights mean\n                      we care more.\n        !*/\n\n        long dimensionality (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows and columns in the transformation matrix\n                  produced by this object.\n        !*/\n\n        general_matrix get_transformation_matrix (\n            scalar_type intrinsic_regularization_strength\n        ) const;\n        /*!\n            requires\n                - intrinsic_regularization_strength >= 0\n            ensures\n                - returns a matrix that represents the preprocessing transformation described above.\n                - You must choose how important the manifold regularizer is relative to the basic\n                  \"don't be complex\" regularizer described above.  The intrinsic_regularization_strength\n                  is the parameter that controls this trade-off.  A large value of \n                  intrinsic_regularization_strength means that more emphasis should be placed on\n                  finding decision rules which produce the same output on similar samples.  On \n                  the other hand, a small value would mean that we don't care much about the \n                  manifold regularizer.  For example, using 0 will cause this function to return the \n                  identity matrix.\n                - The returned matrix will have dimensionality() rows and columns.\n        !*/\n\n    };\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LINEAR_MANIFOLD_ReGULARIZER_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/manifold_regularization.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MANIFOLD_REGULARIzATION_HEADER\n#define DLIB_MANIFOLD_REGULARIzATION_HEADER\n\n#include \"graph_utils/edge_list_graphs.h\"\n#include \"manifold_regularization/linear_manifold_regularizer.h\"\n#include \"graph_utils/function_objects.h\"\n\n#endif // DLIB_MANIFOLD_REGULARIzATION_HEADER\n\n\n\n"
  },
  {
    "path": "dlib/map/map_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAP_KERNEl_1_\n#define DLIB_MAP_KERNEl_1_\n\n#include \"map_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,  \n        typename mem_manager = default_memory_manager \n        >\n    class map_kernel_1 : public enumerable<map_pair<domain,range> >,\n                         public asc_pair_remover<domain,range,typename bst_base::compare_type>\n    {\n\n        /*!\n            REQUIREMENTS ON BST_BASE\n                bst_base is instantiated with domain and range and\n                implements binary_search_tree/binary_search_tree_kernel_abstract.h\n\n            INITIAL VALUE\n                bst has its initial value\n\n            CONVENTION\n                bst.size() == the number of elements in the map and\n                the elements in map are stored in bst_base\n        !*/\n        \n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef typename bst_base::compare_type compare_type;\n            typedef mem_manager mem_manager_type;\n\n            map_kernel_1(\n            ) \n            {}\n\n            virtual ~map_kernel_1(\n            )\n            {}\n\n            inline void clear(\n            );            \n\n            inline void add (\n                domain& d,\n                range& r\n            );\n\n            inline bool is_in_domain (\n                const domain& d\n            ) const;\n\n            inline void remove_any (\n                domain& d,\n                range& r\n            );\n\n            inline void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n \n            inline void destroy (\n                const domain& d\n            );\n \n            inline range& operator[] (\n                const domain& d\n            );\n\n            inline const range& operator[] (\n                const domain& d\n            ) const;\n\n            inline void swap (\n                map_kernel_1& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            inline bool current_element_valid (\n            ) const;\n\n            inline const map_pair<domain,range>& element (\n            ) const;\n\n            inline map_pair<domain,range>& element (\n            );\n\n            inline bool move_next (\n            ) const;\n\n\n        private:\n\n            bst_base bst;\n\n            // restricted functions\n            map_kernel_1(map_kernel_1&);      \n            map_kernel_1& operator= ( map_kernel_1&);\n    };\n\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    inline void swap (\n        map_kernel_1<domain,range,bst_base,mem_manager>& a, \n        map_kernel_1<domain,range,bst_base,mem_manager>& b \n    ) { a.swap(b); }   \n\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void deserialize (\n        map_kernel_1<domain,range,bst_base,mem_manager>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.add(d,r);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type map_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    clear (\n    )\n    {\n        bst.clear();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    add(\n        domain& d,\n        range& r\n    )\n    {\n        // try to add pair to bst_base\n        bst.add(d,r); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    bool map_kernel_1<domain,range,bst_base,mem_manager>::\n    is_in_domain(\n        const domain& d\n    ) const\n    {\n        return (bst[d] != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    remove_any(\n        domain& d,\n        range& r\n    )\n    {\n        bst.remove_any(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        bst.remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    destroy (\n        const domain& d\n    )\n    {\n        bst.destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    range& map_kernel_1<domain,range,bst_base,mem_manager>::\n    operator[](\n        const domain& d\n    )\n    {\n        return *bst[d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    const range& map_kernel_1<domain,range,bst_base,mem_manager>::\n    operator[](\n        const domain& d\n    ) const\n    {\n        return *bst[d];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    size_t map_kernel_1<domain,range,bst_base,mem_manager>::\n    size (\n    ) const\n    {\n        return bst.size();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    swap (\n        map_kernel_1<domain,range,bst_base,mem_manager>& item\n    )\n    {\n        bst.swap(item.bst);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    bool map_kernel_1<domain,range,bst_base,mem_manager>::\n    at_start (\n    ) const\n    {\n        return bst.at_start();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    void map_kernel_1<domain,range,bst_base,mem_manager>::\n    reset (\n    ) const\n    {\n        bst.reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    bool map_kernel_1<domain,range,bst_base,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return bst.current_element_valid();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    const map_pair<domain,range>& map_kernel_1<domain,range,bst_base,mem_manager>::\n    element (\n    ) const\n    {\n        return bst.element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    map_pair<domain,range>& map_kernel_1<domain,range,bst_base,mem_manager>::\n    element (\n    )\n    {\n        return bst.element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range,\n        typename bst_base,\n        typename mem_manager\n        >\n    bool map_kernel_1<domain,range,bst_base,mem_manager>::\n    move_next (\n    ) const\n    {\n        return bst.move_next();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAP_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/map/map_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MAP_KERNEl_ABSTRACT_\n#ifdef DLIB_MAP_KERNEl_ABSTRACT_\n\n#include \"../interfaces/map_pair.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include <functional>\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class map : public enumerable<map_pair<domain,range> >, \n                public asc_pair_remover<domain,range,compare>\n    {\n\n        /*!\n            REQUIREMENTS ON domain\n                domain must be comparable by compare where compare is a functor compatible with std::less and\n                domain is swappable by a global swap() and                \n                domain must have a default constructor\n\n            REQUIREMENTS ON range\n                range is swappable by a global swap() and\n                range must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap(), is_in_domain(), and operator[] functions do not invalidate \n                pointers or references to internal data.\n                All other functions have no such guarantee.\n\n            INITIAL VALUE\n                size() == 0\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the domain (and each associated\n                range element) elements in ascending order according to the compare functor. \n                (i.e. the elements are enumerated in sorted order)\n\n            WHAT THIS OBJECT REPRESENTS\n                map contains items of type domain and range\n\n                This object is similar an array.  It maps items of type domain on to \n                items of type range.   \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n\n                definition of equivalent:\n                a is equivalent to b if\n                a < b == false and\n                b < a == false\n        !*/\n        \n        public:\n\n            typedef domain domain_type;\n            typedef range range_type;\n            typedef compare compare_type;\n            typedef mem_manager mem_manager_type;\n\n            map(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n            !*/\n\n            virtual ~map(\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void add (\n                domain& d,\n                range& r\n            );\n            /*!\n                requires\n                    - &d != &r (i.e. d and r cannot be the same variable)\n                    - is_in_domain(d)  == false\n                ensures\n                    - #is_in_domain(d) == true\n                    - #operator[](d)   == r\n                    - #d and #r have initial values for their types \n                    - #size() == size() + 1\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by domain's or range's \n                      constructor.\n                        if add() throws then it has no effect\n            !*/\n\n            bool is_in_domain (\n                const domain& d\n            ) const;\n            /*!\n                ensures\n                    - returns whether or not an element equivalent to d is in the \n                      domain of *this\n            !*/\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n            /*!\n                requires\n                    - &d != &r (i.e. d and r cannot be the same variable) \n                    - &d != &d_copy (i.e. d and d_copy cannot be the same variable) \n                    - &r != &d_copy (i.e. r and d_copy cannot be the same variable) \n                    - is_in_domain(d) == true\n                ensures\n                    - #is_in_domain(d) == false \n                    - #d_copy is equivalent to d \n                    - the element in the range of *this associated with #d_copy has been \n                      swapped into #r \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            void destroy (\n                const domain& d\n            );\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - #is_in_domain(d) == false \n                    - #size() == size() - 1\n                    - #at_start() == true\n            !*/\n\n            range& operator[] (\n                const domain& d\n            );\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - returns a non-const reference to the element in the range of *this \n                      associated with the element equivalent to d\n            !*/\n\n            const range& operator[] (\n                const domain& d\n            ) const;\n            /*!\n                requires\n                    - is_in_domain(d) == true\n                ensures\n                    - returns a const reference to the element in the range of *this \n                      associated with the element equivalent to d\n            !*/\n\n            void swap (\n                map& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n    \n        private:\n\n            // restricted functions\n            map(map&);        // copy constructor\n            map& operator=(map&);    // assignment operator\n    };\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    inline void swap (\n        map<domain,range,mem_manager,compare>& a, \n        map<domain,range,mem_manager,compare>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager,\n        typename compare\n        >\n    void deserialize (\n        map<domain,range,mem_manager,compare>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_MAP_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/map/map_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAP_KERNEl_C_\n#define DLIB_MAP_KERNEl_C_\n\n#include \"map_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include \"../interfaces/map_pair.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename map_base\n        >\n    class map_kernel_c : public map_base\n    {\n\n        typedef typename map_base::domain_type domain;\n        typedef typename map_base::range_type range;\n        \n        public:\n            void add (\n                domain& d,\n                range& r\n            );\n\n            void remove_any (\n                domain& d,\n                range& r\n            );\n\n            void remove (\n                const domain& d,\n                domain& d_copy,\n                range& r\n            );\n\n            void destroy (\n                const domain& d\n            );\n\n            range& operator[] (\n                const domain& d\n            );\n\n            const range& operator[] (\n                const domain& d\n            ) const;\n\n            const map_pair<domain,range>& element (\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tconst map_pair<domain,range>& map::element\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                    );\n\n                // call the real function\n                return map_base::element();\n            }\n\n            map_pair<domain,range>& element (\n            )\n            {\n                // make sure requires clause is not broken\n                DLIB_CASSERT(this->current_element_valid() == true,\n                    \"\\tmap_pair<domain,range>& map::element\"\n                    << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                    << \"\\n\\tthis: \" << this\n                    );\n\n                // call the real function\n                return map_base::element();\n            }\n\n    };\n\n    template <\n        typename map_base\n        >\n    inline void swap (\n        map_kernel_c<map_base>& a, \n        map_kernel_c<map_base>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    void map_kernel_c<map_base>::\n    add (\n        domain& d,\n        range& r\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (!this->is_in_domain(d)) &&\n                (static_cast<void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid map::add\"\n            << \"\\n\\tdomain element being added must not already be in the map\"\n            << \"\\n\\tand d and r must not be the same variable\"\n            << \"\\n\\tis_in_domain(d): \" << (this->is_in_domain(d) ? \"true\" : \"false\")\n            << \"\\n\\tthis: \" << this\n            << \"\\n\\t&d:   \" << static_cast<void*>(&d)\n            << \"\\n\\t&r:   \" << static_cast<void*>(&r)\n            );\n\n        // call the real function\n        map_base::add(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    void map_kernel_c<map_base>::\n    remove_any (\n        domain& d,\n        range& r\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->size() > 0)  &&\n                (static_cast<void*>(&d) != static_cast<void*>(&r)),\n            \"\\tvoid map::remove_any\"\n            << \"\\n\\tsize() must be greater than zero if something is going to be removed\"\n            << \"\\n\\tand d and r must not be the same variable.\"\n            << \"\\n\\tsize(): \" << this->size() \n            << \"\\n\\tthis:   \" << this\n            << \"\\n\\t&d:     \" << static_cast<void*>(&d)\n            << \"\\n\\t&r:     \" << static_cast<void*>(&r)\n            );\n\n        // call the real function\n        map_base::remove_any(d,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    void map_kernel_c<map_base>::\n    remove (\n        const domain& d,\n        domain& d_copy,\n        range& r\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->is_in_domain(d)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&r)) &&\n                (static_cast<void*>(&r) != static_cast<void*>(&d_copy)) &&\n                (static_cast<const void*>(&d) != static_cast<void*>(&d_copy)),\n            \"\\tvoid map::remove\"\n            << \"\\n\\tcan't remove something that isn't in the map or if the paremeters actually\"\n            << \"\\n\\tare the same variable.  Either way can't remove.\"\n            << \"\\n\\tis_in_domain(d): \" << (this->is_in_domain(d) ? \"true\" : \"false\")\n            << \"\\n\\tthis:      \" << this\n            << \"\\n\\t&d:        \" << static_cast<const void*>(&d)\n            << \"\\n\\t&r:        \" << static_cast<void*>(&r)\n            << \"\\n\\t&d_copy:   \" << static_cast<void*>(&d_copy)\n            );\n\n        // call the real function\n        map_base::remove(d,d_copy,r);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    void map_kernel_c<map_base>::\n    destroy (\n        const domain& d\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->is_in_domain(d),\n            \"\\tvoid map::destroy\"\n            << \"\\n\\tcan't remove something that isn't in the map\"\n            << \"\\n\\tthis:      \" << this\n            << \"\\n\\t&d:        \" << static_cast<const void*>(&d)\n            );\n\n        // call the real function\n        map_base::destroy(d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    typename map_base::range_type& map_kernel_c<map_base>::\n    operator[] (\n        const domain& d\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_in_domain(d),\n            \"\\trange& map::operator[]\"\n            << \"\\n\\td must be in the domain of the map\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return map_base::operator[](d);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_base\n        >\n    const typename map_base::range_type& map_kernel_c<map_base>::\n    operator[] (\n        const domain& d\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( this->is_in_domain(d),\n            \"\\tconst range& map::operator[]\"\n            << \"\\n\\td must be in the domain of the map\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return map_base::operator[](d);\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAP_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/map.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAp_\n#define DLIB_MAp_\n\n#include \"map/map_kernel_1.h\"\n#include \"map/map_kernel_c.h\"\n\n#include \"binary_search_tree.h\"\n\n\n#include \"algs.h\"\n#include <functional>\n\n\nnamespace dlib\n{\n\n    template <\n        typename domain,\n        typename range,\n        typename mem_manager = default_memory_manager,\n        typename compare = std::less<domain>\n        >\n    class map\n    {\n        map() {}\n                \n\n        // a typedef for the binary search tree used by kernel_2\n        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_1a\n                binary_search_tree_1;\n\n        // a typedef for the binary search tree used by kernel_2\n        typedef typename binary_search_tree<domain,range,mem_manager,compare>::kernel_2a\n                binary_search_tree_2;\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     map_kernel_1<domain,range,binary_search_tree_1,mem_manager>    \n                    kernel_1a;\n        typedef     map_kernel_c<kernel_1a >\n                    kernel_1a_c;   \n\n        // kernel_1b        \n        typedef     map_kernel_1<domain,range,binary_search_tree_2,mem_manager>    \n                    kernel_1b;\n        typedef     map_kernel_c<kernel_1b >\n                    kernel_1b_c;   \n\n\n    };\n}\n\n#endif // DLIB_MAp_\n\n"
  },
  {
    "path": "dlib/math/bessel.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATH_BESSEL\n#define DLIB_MATH_BESSEL\n\n#include \"details/bessel.h\"\n\nnamespace dlib\n{\n    template<typename R1, typename R2>\n    auto cyl_bessel_i(R1 nu, R2 x)\n    /*!\n        This is the the regular modified cylindrical Bessel function\n\n        ensures\n            - identical to std::cyl_bessel_i()\n            - works with C++11 onwards\n    !*/\n    {\n        using R = std::common_type_t<R1,R2>;\n        return detail::cyl_bessel_i((R)nu, (R)x);\n    }\n\n    template<typename R1, typename R2>\n    auto cyl_bessel_j(R1 nu, R2 x)\n    /*!\n        This is the cylindrical Bessel functions (of the first kind)\n\n        ensures\n            - identical to std::cyl_bessel_j()\n            - works with C++11 onwards\n    !*/\n    {\n        using R = std::common_type_t<R1,R2>;\n        return detail::cyl_bessel_j((R)nu, (R)x);\n    }\n}\n\n#endif //DLIB_MATH_BESSEL\n"
  },
  {
    "path": "dlib/math/details/bessel.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_MATH_DETAIL_BESSEL\n#define DLIB_MATH_DETAIL_BESSEL\n\n#include <cmath>\n#include <limits>\n#include <stdexcept>\n#include <type_traits>\n#include \"../../numeric_constants.h\"\n#include \"../../assert.h\"\n\nnamespace dlib\n{\n    namespace detail\n    {\n#if __cpp_lib_math_special_functions\n        using std::cyl_bessel_i;\n        using std::cyl_bessel_j;\n#else\n        constexpr unsigned int BESSEL_NITERATIONS = 250;\n\n        template<typename R>\n        R cyl_bessel_i(R nu, R x)\n        {\n            static_assert(std::is_floating_point<R>::value, \"template parameter must be a floating point type\");\n            DLIB_ASSERT(nu >= R{0} && x >= R{0}, \"bad arguments. Contract preconditions are : nu >= 0 and x >= 0\");\n\n            if (std::isnan(nu) || std::isnan(x))\n                return std::numeric_limits<R>::quiet_NaN();\n\n            if(x == 0)\n            {\n                return (nu == R{0}) ? R{1} : R{0};\n            }\n            else if(nu == R(0.5))\n            {\n                // common special case\n                return std::sqrt(2 / (x * pi)) * std::sinh(x);\n            }\n            else\n            {\n                // Compute sum in log-domain to avoid overflow issues\n                const R fact = nu == R{0} ? R{1} : std::pow(R(0.5)*x, nu); //factorize (x/2)^nu\n                R a{};\n                R b{};\n                R c{};\n                R sum{0};\n\n                for (unsigned int k=0; k < BESSEL_NITERATIONS; ++k)\n                {\n                    a = 2 * k * std::log(R(0.5)*x); // log((x/2)^(2k))\n                    b = std::lgamma(R(k) + R{1});   // log(k!) = log(gamma(k+1)). Recall gamma(k) = (k-1)!\n                    c = std::lgamma(nu + k + 1);\n                    sum += std::exp( a - b - c );\n                }\n\n                return fact * sum;\n            }\n        }\n\n        template<typename R>\n        R cyl_bessel_j(R nu, R x)\n        {\n            static_assert(std::is_floating_point<R>::value, \"template parameter must be a floating point type\");\n            DLIB_ASSERT(nu >= R{0} && x >= R{0}, \"bad arguments. Contract preconditions are : nu >= 0 and x >= 0\");\n\n            if (std::isnan(nu) || std::isnan(x))\n                return std::numeric_limits<R>::quiet_NaN();\n\n            /*! Special case !*/\n            else if (x == R{0})\n            {\n                return (nu == R{0}) ? R{1} : R{0};\n            }\n            else\n            {\n                // Compute sum in log-domain to avoid overflow issues\n                const R fact = nu == R{0} ? R{1} : std::pow(R(0.5)*x, nu); //factorize (x/2)^nu\n                R a{};\n                R b{};\n                R c{};\n                R sum{0};\n\n                for (unsigned int k=0; k < BESSEL_NITERATIONS; ++k)\n                {\n                    a = 2 * k * std::log(R(0.5)*x); // log((x/2)^(2k))\n                    b = std::lgamma(R(k) + R{1});   // log(k!) = log(gamma(k+1)). Recall gamma(k) = (k-1)!\n                    c = std::lgamma(nu + k + 1);\n                    if (k&1)\n                        sum -= std::exp(a-b-c);\n                    else\n                        sum += std::exp(a-b-c);\n                }\n\n                return fact * sum;\n            }\n        }\n#endif\n    }\n}\n\n#endif //DLIB_MATH_DETAIL_BESSEL\n"
  },
  {
    "path": "dlib/math/windows.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATH_WINDOWS\n#define DLIB_MATH_WINDOWS\n\n#include <type_traits>\n#include \"bessel.h\"\n\nnamespace dlib\n{\n    // ----------------------------------------------------------------------------------------\n\n    /*! Strong types !*/\n\n    struct attenuation_t\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a desired attenuation in dB.\n                This is automatically converted into a beta_t value suitable\n                for constructing a kaiser window.\n                See https://www.mathworks.com/help/signal/ug/kaiser-window.html on\n                filter design.\n        !*/\n        attenuation_t() = default;\n        explicit attenuation_t(double attenuation_db) : v{attenuation_db} {}\n        double v = 0.0;\n    };\n\n    struct beta_t\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This value determines the shape of the kaiser window.\n                See https://en.wikipedia.org/wiki/Kaiser_window#Definition for more details.\n        !*/\n        beta_t() = default;\n        explicit beta_t(double beta) : v{beta} {}\n        beta_t(attenuation_t attenuation_db)\n        {\n            if (attenuation_db.v > 50.0)\n                v = 0.1102*(attenuation_db.v - 8.7);\n            else if (attenuation_db.v >= 21.0)\n                v = 0.5842*std::pow(attenuation_db.v - 21, 0.4) + 0.07886*(attenuation_db.v - 21);\n        }\n        double v = 0.0;\n    };\n\n    enum window_symmetry\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This enum controls whether the window is a symmetric or periodic window.\n                See https://en.wikipedia.org/wiki/Window_function#Symmetry for a discussion on\n                symmetric vs periodic windows. This is using the same nomenclature as Matlab and Scipy\n                when describing windows as either symmetric or periodic.\n        !*/\n        SYMMETRIC,\n        PERIODIC\n    };\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double kaiser(double x, double L, beta_t beta)\n    /*!\n        This computes the kaiser window function or kaiser-bessel window function.\n        See https://en.wikipedia.org/wiki/Kaiser_window.\n\n        ensures\n            - returns the kaiser window function when |x| <= L/2 where L is the window duration\n            - returns 0 otherwise\n    !*/\n    {\n        if (std::abs(x) <= L/2.0)\n        {\n            const double r = 2*x/L;\n            const double a = dlib::cyl_bessel_i(0, beta.v*std::sqrt(1-r*r));\n            const double b = dlib::cyl_bessel_i(0, beta.v);\n            return a / b;\n        }\n        else\n        {\n            return 0.0;\n        }\n    }\n\n    inline double kaiser(std::size_t i, std::size_t N, beta_t beta, window_symmetry type)\n    /*!\n        This computes the kaiser window function or kaiser-bessel window function.\n        See https://en.wikipedia.org/wiki/Kaiser_window\n        This variant is a short-cut for computing a window function and storing it\n        in an array of size N where 0 <= i < N is the array index.\n\n        requires\n            - 0 <= i < N\n        ensures\n            - returns kaiser(i - (N-1)/2, window_duration{N-1}, beta)\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t L = type == SYMMETRIC ? N-1 : N;\n        return kaiser(i - L / 2.0, (double)L, beta);\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double hann(std::size_t i, std::size_t N, window_symmetry type)\n    /*!\n        This computes the hann window function.\n        See https://en.wikipedia.org/wiki/Window_function#Hann_and_Hamming_windows.\n\n        requires\n            - 0 <= i < N\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t size = type == SYMMETRIC ? N-1 : N;\n        const double phi = (2.0 * pi * i) / size;\n        return 0.5 - 0.5 * std::cos(phi);\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double blackman(std::size_t i, std::size_t N, window_symmetry type)\n    /*!\n        This computes the Blackman window function.\n        See https://en.wikipedia.org/wiki/Window_function#Blackman_window and\n        https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.windows.blackman.html.\n\n        requires\n            - 0 <= i < N\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t size = type == SYMMETRIC ? N-1 : N;\n        const double phi = (2.0 * pi * i) / size;\n        return 0.42 -\n               0.5 * std::cos(phi) +\n               0.08 * std::cos(2.0 * phi);\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double blackman_nuttall(std::size_t i, std::size_t N, window_symmetry type)\n    /*!\n        This computes the Blackman-Nuttall window function.\n        See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Nuttall_window.\n\n        requires\n            - 0 <= i < N\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t size = type == SYMMETRIC ? N-1 : N;\n        const double phi = (2.0 * pi * i) / size;\n        return 0.3635819 -\n               0.4891775 * std::cos(phi) +\n               0.1365995 * std::cos(2*phi) -\n               0.0106411 * std::cos(3*phi);\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double blackman_harris(std::size_t i, std::size_t N, window_symmetry type)\n    /*!\n        This computes the Blackman-Harris window function.\n        See https://en.wikipedia.org/wiki/Window_function#Blackman%E2%80%93Harris_window.\n\n        requires\n            - R is float, double, or long double\n            - 0 <= i < N\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t size = type == SYMMETRIC ? N-1 : N;\n        const double phi = (2.0 * pi * i) / size;\n        return 0.35875 -\n               0.48829 * std::cos(phi) +\n               0.14128 * std::cos(2*phi) -\n               0.01168 * std::cos(3*phi);\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    inline double blackman_harris7(std::size_t i, std::size_t N, window_symmetry type)\n    /*!\n        This computes the 7-order Blackman-Harris window function.\n\n        requires\n            - R is float, double, or long double\n            - 0 <= i < N\n    !*/\n    {\n        DLIB_ASSERT(i < N, \"index out of range\");\n        const std::size_t size = type == SYMMETRIC ? N-1 : N;\n        const double phi = (2.0 * pi * i) / size;\n        return 0.27105 -\n               0.43329 * std::cos(phi) +\n               0.21812 * std::cos(2*phi) -\n               0.06592 * std::cos(3*phi) +\n               0.01081 * std::cos(4*phi) -\n               0.00077 * std::cos(5*phi) +\n               0.00001 * std::cos(6*phi);\n    }\n\n    // ----------------------------------------------------------------------------------------\n}\n\n#endif //DLIB_MATH_WINDOWS\n"
  },
  {
    "path": "dlib/math.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATH\n#define DLIB_MATH\n\n#include \"math/bessel.h\"\n#include \"math/windows.h\"\n\n#endif //DLIB_MATH\n"
  },
  {
    "path": "dlib/matlab/CMakeLists.txt",
    "content": "\ncmake_minimum_required(VERSION 3.10.0)\n\nPROJECT(mex_functions)\n\ninclude(cmake_mex_wrapper)\n\nadd_subdirectory(.. dlib_build)\n\n\n# You can tell cmake where to put the mex files when you run 'make install' by\n# setting this variable.  The path is relative to this CMakeLists.txt file.\nset(install_target_output_folder .)\n\n# Compile the example_mex_function.cpp file and link it to dlib.  Note\n# that you can give a list of things to link to here.  E.g. \n#    add_mex_function(some_other_mex_function pthread dlib fftw) \nadd_mex_function(example_mex_function dlib::dlib)\nadd_mex_function(example_mex_callback dlib::dlib)\nadd_mex_function(example_mex_struct dlib::dlib)\nadd_mex_function(example_mex_class dlib::dlib)\n\n"
  },
  {
    "path": "dlib/matlab/README.txt",
    "content": "This folder contains a set of tools which make it easy to create MATLAB mex\nfunctions.  To understand how they work, you should read the\nexample_mex_function.cpp, example_mex_struct.cpp, and  example_mex_callback.cpp examples.\n\nTo compile them, you can use CMake.  In particular, from this folder execute\nthese commands:\n\n   mkdir build\n   cd build\n   cmake ..\n   cmake --build . --config release --target install\n\nThat should build the mex files on any platform.\n\nNote that on windows you will probably need to tell CMake to use a 64bit\nversion of visual studio.  You can do this by using a command like:\n   cmake -G \"Visual Studio 10 Win64\" ..\ninstead of\n   cmake ..\n\n"
  },
  {
    "path": "dlib/matlab/call_matlab.h",
    "content": "// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory\n// License: Boost Software License   See LICENSE.txt for the full license.\n// Authors: Davis E. King (davis@dlib.net)\n#ifndef MIT_LL_CALL_MATLAB_H__\n#define MIT_LL_CALL_MATLAB_H__\n\n#include <string>\n#include <sstream>\n#include <dlib/error.h>\n#include <dlib/assert.h>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\nstruct invalid_args_exception : error\n{\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This is the exception thrown when the mex wrapper tries to convert a matlab\n            object into a C++ object but for whatever reason can't (usually because the\n            types don't match).\n    !*/\n    invalid_args_exception(const std::string& msg_): error(msg_) {}\n    invalid_args_exception(const std::ostringstream& msg_): error(msg_.str()) {}\n};\n\n// ----------------------------------------------------------------------------------------\n\nvoid check_for_matlab_ctrl_c();\n/*!\n    ensures\n        - If the user of MATLAB has pressed ctrl+c then this function will throw an\n          exception.\n!*/\n\n// ----------------------------------------------------------------------------------------\n\nclass matlab_object\n{\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This object is a simple wrapper around matlab's generic mxArray, which is the\n            thing that is matlab's \"anything object\".  So a matlab_object can be used as an\n            argument to a mex_function() that can bind to any matlab object at all. It can\n            also bind to \"nothing\" and so is inherently also an optional argument when\n            present in a mex_funciton().\n    !*/\npublic:\n    matlab_object() : handle(0),should_free(false),arg_idx(0) {}\n    matlab_object(const matlab_object&) = delete;\n\n    ~matlab_object();\n\n\n    // Check if a matlab object is bound to this object.\n    bool is_empty() const { return handle==0; }\n    operator bool() const { return handle!=0; }\n\n    // Convert from MATLAB to C++, throw invalid_args_exception if not possible.\n    template <typename T> operator T() const;\n    template <typename T> void get(T& item) const; \n\n    // Convert from a C++ object to MATLAB\n    template <typename T> matlab_object& operator= (const T& new_val);\n\n\n    template <typename T> bool try_get(T& item) const\n    {\n        try { get(item); return true; }\n        catch(invalid_args_exception&) { return false; }\n    }\n\n    const void* get_handle() const { return handle; }\n    /*!\n        ensures\n            - returns a pointer to the mxArray object.  Might be NULL. \n    !*/\n\n\n    matlab_object& operator=(const matlab_object&) = delete;\n\n    // Users shouldn't call these functions\n    const void* release_object_to_matlab() { const void* temp=handle; handle = 0; return temp; }\n    void set_object_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!handle); handle = sh; arg_idx=arg_idx_; }\nprivate:\n\n    const void* handle;\n    bool should_free;\n    int arg_idx;\n};\n\n// ----------------------------------------------------------------------------------------\n\nclass matlab_struct \n{\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This object lets you interface with MATLAB structs from C++.  For example,\n            given a MATLAB struct named mystruct, you could access it's fields like this:\n                MATLAB way: mystruct.field\n                C++ way:    mystruct[\"field\"]\n                MATLAB way: mystruct.field.subfield\n                C++ way:    mystruct[\"field\"][\"subfield\"]\n\n            To get the values as C++ types you do something like this:\n                int val = mystruct[\"field\"];\n            or \n                int val;  \n                mystruct[\"field\"].get(val);\n\n            See also example_mex_struct.cpp for an example that uses this part of the API.\n    !*/\n\n    class sub;\npublic:\n    matlab_struct() : struct_handle(0),should_free(false),arg_idx(0) {}\n    matlab_struct(const matlab_struct&) = delete;\n    ~matlab_struct();\n\n    const sub operator[] (const std::string& name) const;\n    sub operator[] (const std::string& name);\n    bool has_field(const std::string& name) const;\n\n    const void* release_struct_to_matlab() { const void* temp=struct_handle; struct_handle = 0; return temp; }\n    void set_struct_handle(int arg_idx_, const void* sh) { DLIB_CASSERT(!struct_handle); struct_handle = sh; arg_idx=arg_idx_; }\nprivate:\n\n    class sub \n    {\n    public:\n        sub() : struct_handle(0), field_idx(-1) {}\n\n        template <typename T> operator T() const;\n        template <typename T> void get(T& item) const; \n        template <typename T> sub& operator= (const T& new_val);\n        const sub operator[] (const std::string& name) const;\n        sub operator[] (const std::string& name);\n        bool has_field(const std::string& name) const;\n    private:\n        friend class matlab_struct;\n        const void* struct_handle;\n        int field_idx;\n        sub& operator=(const sub&);\n    };\n    const void* struct_handle;\n    bool should_free;\n    int arg_idx;\n    matlab_struct& operator=(const matlab_struct&); \n};\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\ntemplate <typename T> \nstruct output_decorator\n{\n    output_decorator(T& item_):item(item_){}\n    T& item;\n};\n\ntemplate <typename T>\noutput_decorator<T> returns(T& item) { return output_decorator<T>(item); }\n/*!\n    ensures\n        - decorates item as an output type.  This stuff is used by the call_matlab()\n          functions to tell if an argument is an input to the function or is supposed\n          to be bound to one of the return arguments.\n!*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\nstruct function_handle\n{\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This type is used to represent function handles passed from MATLAB into a\n            mex function.  You can call the function referenced by the handle by\n            saying:\n                call_matlab(my_handle);\n    !*/\n\n    // These two lines are just implementation details, ignore them.\n    function_handle():h(0){}\n    void* const h;\n};\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\nvoid call_matlab (\n    const std::string& function_name\n);\n/*!\n    ensures\n        - Calls MATLAB's function of the given name\n!*/\n\n// ----------------------------------------------------------------------------------------\n\nvoid call_matlab (\n    const function_handle& funct \n);\n/*!\n    ensures\n        - Calls MATLAB's function represented by the handle funct\n!*/\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1\n);\n/*!\n    ensures\n        - calls MATLAB's function of the given name.  \n        - if (A1 is not decorated as an output by returns()) then\n            - A1 is passed as an argument into the MATLAB function\n        - else\n            - A1 is treated as the first return value from the MATLAB function.\n!*/\n\ntemplate <\n    typename T1\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1\n) { call_matlab(\"feval\", funct, A1); }\n/*!\n    ensures\n        - Calls MATLAB's function represented by the handle funct\n        - if (A1 is not decorated as an output by returns()) then\n            - A1 is passed as an argument into the MATLAB function\n        - else\n            - A1 is treated as the first return value from the MATLAB function.\n!*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n/*\n    The rest of this file is just overloads of call_matlab() for up to 10 arguments (or\n    just 9 arguments if function_handle is used).  They all do the same thing as the above \n    version of call_matlab().  Generally, any argument not decorated by returns() is an \n    input to the MATLAB function.  On the other hand, all arguments decorated by returns() \n    are treated as outputs.  \n*/\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3,\n    typename T4\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6,\n    typename T7\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6,\n    const T7& A7\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, \n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6,\n    typename T7,\n    typename T8\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6,\n    const T7& A7,\n    const T8& A8\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12& A12\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17, typename T18\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,\n    const T18& A18\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,\n    const T18& A18, const T19& A19\n);\n\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19,\n    typename T20\n    >\nvoid call_matlab (\n    const std::string& function_name,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,\n    const T18& A18, const T19& A19, const T20& A20\n);\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\ntemplate <\n    typename T1,\n    typename T2\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2\n)\n{\n    call_matlab(\"feval\", funct, A1, A2);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3,\n    typename T4\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6,\n    typename T7\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6,\n    const T7& A7\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7);\n}\n\ntemplate <\n    typename T1,\n    typename T2,\n    typename T3,\n    typename T4,\n    typename T5,\n    typename T6,\n    typename T7,\n    typename T8\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1,\n    const T2& A2,\n    const T3& A3,\n    const T4& A4,\n    const T5& A5,\n    const T6& A6,\n    const T7& A7,\n    const T8& A8\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17, typename T18\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,\n    const T18& A18\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);\n}\n\ntemplate <\n    typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename\n    T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13,\n    typename T14, typename T15, typename T16, typename T17, typename T18, typename T19\n    >\nvoid call_matlab (\n    const function_handle& funct,\n    const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n    const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const T12&\n    A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const T17& A17,\n    const T18& A18, const T19& A19\n)\n{\n    call_matlab(\"feval\", funct, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);\n}\n\n// ----------------------------------------------------------------------------------------\n\n// We define this function here so that, if you write some code that has check_for_matlab_ctrl_c()\n// sprinkled throughout it you can still compile that code outside the mex wrapper\n// environment and these calls will simply be no-ops.\n#ifndef MATLAB_MEX_FILE\ninline void check_for_matlab_ctrl_c() {}\n#endif\n\n}\n\n#endif // MIT_LL_CALL_MATLAB_H__\n\n"
  },
  {
    "path": "dlib/matlab/cmake_mex_wrapper",
    "content": "# This file figures out where MATLAB is and then defines a macro, add_mex_function(name)\n# which when called instructs CMake to build a mex file from a file called name.cpp.  Note\n# that additional library dependencies can be added like this: add_mex_function(name lib1 dlib libetc).\n# That is, just add more libraries after the name and they will be build into the mex file.\n\ncmake_minimum_required(VERSION 3.8.0)\n\nset(BUILDING_MATLAB_MEX_FILE true)\nset(CMAKE_POSITION_INDEPENDENT_CODE True)\n\n# Trying to use cuda with matlab hasn't worked well, so just disable it.\nSET(DLIB_USE_CUDA OFF CACHE BOOL \"\" FORCE)\n\n# Find MATLAB's include directory and needed libraries \nfind_program(MATLAB_EXECUTABLE matlab PATHS\n        \"C:/Program Files/MATLAB/*/bin\"\n        \"C:/Program Files (x86)/MATLAB/*/bin\"\n        )\n# Resolve symbolic links to try and get the real path to the MATLAB executable\nget_filename_component(MATLAB_EXECUTABLE ${MATLAB_EXECUTABLE} REALPATH)\n# Now get MATLAB root directory\nget_filename_component(MATLAB_HOME ${MATLAB_EXECUTABLE} PATH)\nget_filename_component(MATLAB_HOME ${MATLAB_HOME} PATH)\nset(MATLAB_LIB_FOLDERS\n   \"${MATLAB_HOME}/extern/lib/win64/microsoft\"\n   \"${MATLAB_HOME}/bin/glnxa64\"\n   )\n# If there is a MATLAB_HOME environment variable then look there as well.\nif (DEFINED ENV{MATLAB_HOME})\n    set(MATLAB_LIB_FOLDERS\n        \"$ENV{MATLAB_HOME}/extern/lib/win64/microsoft\"\n        \"$ENV{MATLAB_HOME}/bin/glnxa64\"\n        ${MATLAB_LIB_FOLDERS}\n    )\nendif()\n# Find the MATLAB libraries that need to get linked into the mex file\nif (WIN32)\n   find_library(MATLAB_MEX_LIBRARY libmex PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_MX_LIBRARY  libmx  PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_ENG_LIBRARY libeng PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_UT_LIBRARY  libut  PATHS ${MATLAB_LIB_FOLDERS} )\nelse()\n   find_library(MATLAB_MEX_LIBRARY mex    PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_MX_LIBRARY  mx     PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_ENG_LIBRARY eng    PATHS ${MATLAB_LIB_FOLDERS} )\n   find_library(MATLAB_UT_LIBRARY  ut     PATHS ${MATLAB_LIB_FOLDERS} )\nendif()\nset(MATLAB_LIBRARIES ${MATLAB_MEX_LIBRARY} ${MATLAB_MX_LIBRARY} ${MATLAB_ENG_LIBRARY} ${MATLAB_UT_LIBRARY})\n# Figure out the path to MATLAB's mex.h so we can add it to the include search path.\nfind_path(mex_header_path mex.h\n    PATHS \"$ENV{MATLAB_HOME}/extern/include\"\n        \"${MATLAB_HOME}/extern/include\"\n    )\nINCLUDE_DIRECTORIES(${mex_header_path})\n\n# Determine the path to cmake_mex_wrapper file so we can add it to the include search path..\nstring(REGEX REPLACE \"cmake_mex_wrapper$\" \"\" dlib_matlab_binding_path ${CMAKE_CURRENT_LIST_FILE})\nINCLUDE_DIRECTORIES(\"${dlib_matlab_binding_path}\")\n# Also add dlib to the include search path \nINCLUDE_DIRECTORIES(${dlib_matlab_binding_path}/../..) \n\nadd_definitions(-DMATLAB_MEX_FILE)\n\n# Determine the path to our CMakeLists.txt file.  This is the file that\n# includeded the one you are reading right now.  So here we make it so that\n# when you run the install target it will copy the compiled mex files into the\n# same folder as the parent CMakeLists.txt file.\nstring(REGEX REPLACE \"CMakeLists.txt$\" \"\" install_dir ${CMAKE_PARENT_LIST_FILE})\nset(CMAKE_INSTALL_PREFIX \"${install_dir}\")\nset(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION \"${install_dir}\")\nINCLUDE(InstallRequiredSystemLibraries)\n\n\nMACRO(add_mex_function name )\n    if (EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/${name}.C\")\n        ADD_LIBRARY(${name} MODULE ${name}.C)\n    elseif(EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/${name}.c\")\n        ADD_LIBRARY(${name} MODULE ${name}.c)\n    else()\n        ADD_LIBRARY(${name} MODULE ${name}.cpp )\n    endif()\n\n    target_compile_definitions(${name} PRIVATE -DMEX_FILENAME=${name})\n    if (UNIX)\n        # Doing this prevents our mex function from exporting any symbols\n        # other than mexFunction().  This sometimes doesn't matter but sometimes\n        # avoids causing errors or otherwise bad behavior in MATLAB.\n        if (DEFINED ENV{MATLAB_HOME})\n            set_target_properties(${name} PROPERTIES LINK_FLAGS \"-Wl,--version-script,$ENV{MATLAB_HOME}/extern/lib/glnxa64/mexFunction.map\")\n        else()\n            set_target_properties(${name} PROPERTIES LINK_FLAGS \"-Wl,--version-script,${MATLAB_HOME}/extern/lib/glnxa64/mexFunction.map\")\n        endif()\n    endif()\n\n    # Change the output file extension to a mex extension.\n   if (WIN32)\n      set_target_properties(${name} PROPERTIES SUFFIX \".mexw64\")\n   elseif(APPLE)\n      set_target_properties(${name} PROPERTIES SUFFIX \".mexmaci64\")\n   else()\n      set_target_properties(${name} PROPERTIES SUFFIX \".mexa64\")\n   endif()\n   set_target_properties(${name} PROPERTIES PREFIX \"\")\n   TARGET_LINK_LIBRARIES(${name} ${MATLAB_LIBRARIES} ${ARGN})\n   if (install_target_output_folder)\n      install(TARGETS ${name} DESTINATION \"${install_target_output_folder}\")\n   else()\n      install(TARGETS ${name} DESTINATION \"${install_dir}\")\n   endif()\nENDMACRO()\n\n\n"
  },
  {
    "path": "dlib/matlab/example.m",
    "content": "% This example calls the three mex functions defined in this folder.  As you\n% can see, you call them just like you would normal MATLAB functions.\n\nx = magic(3)\ny = 2*magic(3)\n\n[out1, out2] = example_mex_function(x,y, 12345)\n\nz = example_mex_callback(x, @(a)a+a)\n\n\ninput = {}\ninput.val = 2\ninput.stuff = 'some string'\noutput = example_mex_struct(input)\n\n"
  },
  {
    "path": "dlib/matlab/example_mex_callback.cpp",
    "content": "// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt\n\n#include \"call_matlab.h\"\n#include \"dlib/matrix.h\"\n\nusing namespace dlib;\nusing namespace std;\n\n/*\n    This mex function takes a MATLAB function handle, calls it, and\n    returns the results.\n\n    For example, you can call this function in MATLAB like so:\n        A = magic(3)\n        y = example_mex_callback(A, @(x)x+x)\n\n    This will result in y containing the value 2*A.\n*/\n\nvoid mex_function (\n    const matrix<double>& A,\n    const function_handle& f,\n    matrix<double>& result\n) \n{\n    // The f argument to this function is a function handle passed from MATLAB.  To\n    // call it we use the following syntax:\n    call_matlab(f, A, returns(result));\n    // This is equivalent to result = f(A). Therefore, the returns(variable) syntax \n    // is used to indicate which variables are outputs of the function.\n\n\n\n\n    // Another thing we can do is call MATLAB functions based on their string name\n    // rather than a function_handle.  Here is an example of calling eigs().   \n    matrix<double> m(2,2);\n    m = 1,2,\n        3,4;\n    matrix<double> v,d;\n\n    // This is equivalent to [v,d] = eigs(m);\n    call_matlab(\"eigs\", m, returns(v), returns(d));\n    cout << \"eigenvectors: \\n\" << v << endl;\n    cout << \"eigenvalues:  \\n\" << d << endl;\n}\n\n\n\n// #including this brings in all the mex boiler plate needed by MATLAB.\n#include \"mex_wrapper.cpp\"\n\n"
  },
  {
    "path": "dlib/matlab/example_mex_class.cpp",
    "content": "// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt\n/*\n    This mex file will create a MATLAB function called example_mex_class.  If you call it\n    with no arguments it will output the MATLAB .m code to create a MATLAB wrapper class.\n    Paste that code into a .m file.  Then you will be able to work with this C++ class\n    directly in MATLAB.\n*/\n\n#include <iostream>\n#include <dlib/matrix.h>\n\n\nusing namespace std;\nusing namespace dlib;\n\nclass example_class \n{\npublic:\n\n    // The class must have a default constructor.  It's also the only kind of constructor\n    // you can call from MATLAB.\n    example_class()\n    {\n        xx.set_size(3,2);\n        xx = 1;\n    }\n\n    // The rest of the member functions that you want to bind have to return void and\n    // generally have the same syntax limitations as regular mex funcitons.\n    void do_stuff(const matrix_colmajor& x)\n    {\n        cout << \"in do_stuff\" << endl;\n        cout << x << endl;\n        xx = x;\n    }\n\n    void do_other_stuff(int x)\n    {\n        cout << \"in do_other_stuff\" << endl;\n        cout << \"x: \" << x << endl;\n    }\n\n    void print_state()\n    {\n        cout << xx << endl;\n    }\n\n    // saveobj() and load_obj() are special functions. If you provide these then you will\n    // be able to save() and load() your objects using MATLAB's built in object\n    // serialization.\n    void saveobj(matrix_colmajor& state)\n    {\n        // save this object's state to state.\n        state = xx;\n    }\n    void load_obj(const matrix_colmajor& state)\n    {\n        xx = state;\n    }\n\nprivate:\n    matrix_colmajor xx;\n};\n\n// Just tell the mex wrapper the name of your class and list the methods you want to bind.\n#define MEX_CLASS_NAME example_class \n#define MEX_CLASS_METHODS do_stuff, do_other_stuff, print_state, saveobj, load_obj\n\n\n#include \"mex_wrapper.cpp\"\n\n\n"
  },
  {
    "path": "dlib/matlab/example_mex_function.cpp",
    "content": "// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt\n\n#include \"dlib/matrix.h\"\nusing namespace dlib;\nusing namespace std;\n\n\n/*!\n    This file defines a function callable from MATLAB once you mex it. \n\n    It computes the same thing as the following MATLAB function:\n\n        function [A, B] = example_mex_function(x, y, some_number)\n            A = x+y;\n            B = sum(sum(x+y));\n            disp(['some_number: ' num2str(some_number)])\n        end\n\n\n    VALID INPUT AND OUTPUT ARGUMENTS\n        The mex wrapper can handle the following kinds of input and output arguments:\n            - Types corresponding to a MATLAB matrix\n                - a dlib::matrix containing any kind of scalar value.\n                - a dlib::array2d containing any kind of scalar value.\n                - a dlib::vector containing any kind of scalar value.\n                - a dlib::point\n                - matrix_colmajor or fmatrix_colmajor\n                  These are just typedefs for matrix containing double or float and using a\n                  column major memory layout.  However, they have the special distinction\n                  of being fast to use in mex files since they sit directly on top of\n                  MATLAB's built in matrices.  That is, while other types of arguments copy\n                  a MATLAB object into themselves, the matrix_colmajor and fmatrix_colmajor\n                  do no such copy and are effectively zero overhead methods for working on\n                  MATLAB's matrices.\n\n            - RGB color images\n                - dlib::array2d<dlib::rgb_pixel> can be used to represent \n                  MATLAB uint8 MxNx3 images.\n\n            - Types corresponding to a MATLAB scalar\n                - any kind of scalar value, e.g. double, int, etc.\n\n            - Types corresponding to a MATLAB string \n                - std::string \n        \n            - Types corresponding to a MATLAB cell array\n                - a std::vector or dlib::array containing any of the above \n                  types of objects or std::vector or dlib::array objects.\n\n            - matlab_struct and matlab_object.  These are special types defined in the\n              call_matlab.h file and correspond to matlab structs and arbitrary matlab\n              objects respectively.\n!*/\n\n\n// You can also define default values for your input arguments.  So\n// here we say that if the user in MATLAB doesn't provide the \"some_number\" \n// then it will get a value of 3.141.  \n#define ARG_5_DEFAULT 3.141\n\n// Make a function named mex_function() and put your code inside it.\n// Note that the return type should be void.  Use non-const reference\n// arguments to return outputs.  Finally, mex_function() must have no\n// more than 20 arguments.\nvoid mex_function (\n    const matrix_colmajor& x,\n    const matrix_colmajor& y,\n    matrix_colmajor& out1,\n    double& out2,\n    double some_number \n) \n{\n    out1 = x + y;\n    out2 = sum(x+y);\n\n    // we can also use cout to print things as usual:\n    cout << \"some_number: \"<< some_number << endl;\n}\n\n\n\n// #including this brings in all the mex boiler plate needed by MATLAB.\n#include \"mex_wrapper.cpp\"\n\n"
  },
  {
    "path": "dlib/matlab/example_mex_struct.cpp",
    "content": "// The contents of this file are in the public domain. See LICENSE_FOR_EXAMPLE_PROGRAMS.txt\n\n#include \"call_matlab.h\"\n#include \"dlib/matrix.h\"\nusing namespace dlib;\nusing namespace std;\n\n\n/*\n    This mex function takes a MATLAB struct, prints a few of its fields,\n    and then returns a new struct.\n\n    For example, you can call this function in MATLAB like so:\n        input = {}\n        input.val = 2\n        input.stuff = 'some string'\n        output = example_mex_struct(input)\n\n        output.number\n        output.number2\n        output.sub.stuff\n        output.sub.some_matrix\n*/\n\n\nvoid mex_function (\n    const matlab_struct& input,\n    matlab_struct& output \n) \n{\n    int val = input[\"val\"];\n    string stuff = input[\"stuff\"];\n\n    if (input.has_field(\"val2\")) \n    {\n        string val2 = input[\"val2\"];\n        cout << \"The optional val2 field was set to: \" << val2 << endl;\n    }\n\n    cout << \"val: \"<< val << endl;\n    cout << \"stuff: \" << stuff << endl;\n\n    output[\"number\"] = 999;\n\n    output[\"number2\"] = 1000;\n    output[\"sub\"][\"stuff\"] = \"some other string\";\n    matrix<double> m = randm(2,2);\n    output[\"sub\"][\"some_matrix\"] = m;\n}\n\n\n\n// #including this brings in all the mex boiler plate needed by MATLAB.\n#include \"mex_wrapper.cpp\"\n\n"
  },
  {
    "path": "dlib/matlab/mex_wrapper.cpp",
    "content": "// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory\n// License: Boost Software License   See LICENSE.txt for the full license.\n// Authors: Davis E. King (davis@dlib.net)\n/*\n                               READ THIS FIRST\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                               \\############/\n                                \\##########/\n                                 \\########/\n                                  \\######/\n                                   \\####/\n                                    \\##/\n                                     \\/\n\n    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n    See example_mex_function.cpp for a discussion of how to use the mex wrapper.\n\n    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n                                     /\\\n                                    /##\\\n                                   /####\\\n                                  /######\\\n                                 /########\\\n                                /##########\\\n                               /############\\\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                                   ######\n                               READ THIS FIRST\n*/\n\n// Copyright (C) 2012 Massachusetts Institute of Technology, Lincoln Laboratory\n// License: Boost Software License   See LICENSE.txt for the full license.\n// Authors: Davis E. King (davis@dlib.net)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                            BEGIN IMPLEMENTATION DETAILS\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n#include \"../array.h\"\n#include \"../image_transforms.h\"\n#include \"../is_kind.h\"\n#include \"../string.h\"\n#include \"sig_traits.h\" // for sig_traits\n#include \"../hash.h\"\n#include <tuple>\n#include <map>\n\n#if defined(_MSC_VER)\n#define DLL_EXPORT_SYM __declspec(dllexport)\n#endif\n#include \"mex.h\"\n#include <sstream>\n#include \"call_matlab.h\"\n\n// ----------------------------------------------------------------------------------------\n\n#ifdef ARG_1_DEFAULT \n#define ELSE_ASSIGN_ARG_1 else A1 = ARG_1_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_1\n#endif\n\n#ifdef ARG_2_DEFAULT \n#define ELSE_ASSIGN_ARG_2 else A2 = ARG_2_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_2\n#endif\n\n#ifdef ARG_3_DEFAULT \n#define ELSE_ASSIGN_ARG_3 else A3 = ARG_3_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_3\n#endif\n\n#ifdef ARG_4_DEFAULT \n#define ELSE_ASSIGN_ARG_4 else A4 = ARG_4_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_4\n#endif\n\n#ifdef ARG_5_DEFAULT \n#define ELSE_ASSIGN_ARG_5 else A5 = ARG_5_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_5\n#endif\n\n#ifdef ARG_6_DEFAULT \n#define ELSE_ASSIGN_ARG_6 else A6 = ARG_6_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_6\n#endif\n\n#ifdef ARG_7_DEFAULT \n#define ELSE_ASSIGN_ARG_7 else A7 = ARG_7_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_7\n#endif\n\n#ifdef ARG_8_DEFAULT \n#define ELSE_ASSIGN_ARG_8 else A8 = ARG_8_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_8\n#endif\n\n#ifdef ARG_9_DEFAULT \n#define ELSE_ASSIGN_ARG_9 else A9 = ARG_9_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_9\n#endif\n\n#ifdef ARG_10_DEFAULT \n#define ELSE_ASSIGN_ARG_10 else A10 = ARG_10_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_10\n#endif\n\n#ifdef ARG_11_DEFAULT \n#define ELSE_ASSIGN_ARG_11 else A11 = ARG_11_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_11\n#endif\n\n#ifdef ARG_12_DEFAULT \n#define ELSE_ASSIGN_ARG_12 else A12 = ARG_12_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_12\n#endif\n\n#ifdef ARG_13_DEFAULT \n#define ELSE_ASSIGN_ARG_13 else A13 = ARG_13_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_13\n#endif\n\n#ifdef ARG_14_DEFAULT \n#define ELSE_ASSIGN_ARG_14 else A14 = ARG_14_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_14\n#endif\n\n#ifdef ARG_15_DEFAULT \n#define ELSE_ASSIGN_ARG_15 else A15 = ARG_15_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_15\n#endif\n\n#ifdef ARG_16_DEFAULT \n#define ELSE_ASSIGN_ARG_16 else A16 = ARG_16_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_16\n#endif\n\n#ifdef ARG_17_DEFAULT \n#define ELSE_ASSIGN_ARG_17 else A17 = ARG_17_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_17\n#endif\n\n#ifdef ARG_18_DEFAULT \n#define ELSE_ASSIGN_ARG_18 else A18 = ARG_18_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_18\n#endif\n\n#ifdef ARG_19_DEFAULT \n#define ELSE_ASSIGN_ARG_19 else A19 = ARG_19_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_19\n#endif\n\n#ifdef ARG_20_DEFAULT \n#define ELSE_ASSIGN_ARG_20 else A20 = ARG_20_DEFAULT;\n#else\n#define ELSE_ASSIGN_ARG_20\n#endif\n\n// ----------------------------------------------------------------------------------------\n\nnamespace mex_binding\n{\n    using namespace dlib;\n\n    template <typename T>\n    struct is_input_type \n    {\n        const static unsigned long value = (!is_same_type<void,T>::value && (!is_reference_type<T>::value || is_const_type<T>::value )) ? 1 : 0;\n    };\n    template <typename T>\n    struct is_output_type \n    {\n        const static unsigned long value = (!is_same_type<void,T>::value && is_reference_type<T>::value && !is_const_type<T>::value) ? 1 : 0;\n    };\n\n\n    template <typename funct>\n    struct funct_traits\n    {\n        const static unsigned long num_inputs = is_input_type<typename sig_traits<funct>::arg1_type>::value +\n            is_input_type<typename sig_traits<funct>::arg2_type>::value +\n            is_input_type<typename sig_traits<funct>::arg3_type>::value +\n            is_input_type<typename sig_traits<funct>::arg4_type>::value +\n            is_input_type<typename sig_traits<funct>::arg5_type>::value +\n            is_input_type<typename sig_traits<funct>::arg6_type>::value +\n            is_input_type<typename sig_traits<funct>::arg7_type>::value +\n            is_input_type<typename sig_traits<funct>::arg8_type>::value +\n            is_input_type<typename sig_traits<funct>::arg9_type>::value +\n            is_input_type<typename sig_traits<funct>::arg10_type>::value + \n            is_input_type<typename sig_traits<funct>::arg11_type>::value + \n            is_input_type<typename sig_traits<funct>::arg12_type>::value + \n            is_input_type<typename sig_traits<funct>::arg13_type>::value + \n            is_input_type<typename sig_traits<funct>::arg14_type>::value + \n            is_input_type<typename sig_traits<funct>::arg15_type>::value + \n            is_input_type<typename sig_traits<funct>::arg16_type>::value + \n            is_input_type<typename sig_traits<funct>::arg17_type>::value + \n            is_input_type<typename sig_traits<funct>::arg18_type>::value + \n            is_input_type<typename sig_traits<funct>::arg19_type>::value + \n            is_input_type<typename sig_traits<funct>::arg20_type>::value; \n\n        const static unsigned long num_outputs= is_output_type<typename sig_traits<funct>::arg1_type>::value +\n            is_output_type<typename sig_traits<funct>::arg2_type>::value +\n            is_output_type<typename sig_traits<funct>::arg3_type>::value +\n            is_output_type<typename sig_traits<funct>::arg4_type>::value +\n            is_output_type<typename sig_traits<funct>::arg5_type>::value +\n            is_output_type<typename sig_traits<funct>::arg6_type>::value +\n            is_output_type<typename sig_traits<funct>::arg7_type>::value +\n            is_output_type<typename sig_traits<funct>::arg8_type>::value +\n            is_output_type<typename sig_traits<funct>::arg9_type>::value +\n            is_output_type<typename sig_traits<funct>::arg10_type>::value + \n            is_output_type<typename sig_traits<funct>::arg11_type>::value + \n            is_output_type<typename sig_traits<funct>::arg12_type>::value + \n            is_output_type<typename sig_traits<funct>::arg13_type>::value + \n            is_output_type<typename sig_traits<funct>::arg14_type>::value + \n            is_output_type<typename sig_traits<funct>::arg15_type>::value + \n            is_output_type<typename sig_traits<funct>::arg16_type>::value + \n            is_output_type<typename sig_traits<funct>::arg17_type>::value + \n            is_output_type<typename sig_traits<funct>::arg18_type>::value + \n            is_output_type<typename sig_traits<funct>::arg19_type>::value + \n            is_output_type<typename sig_traits<funct>::arg20_type>::value; \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct is_array_type\n    {\n        // true if T is std::vector or dlib::array\n        const static bool value = is_std_vector<T>::value || dlib::is_array<T>::value;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename enabled = void \n        >\n    struct inner_type\n    {\n        typedef T type;\n    };\n\n    template < typename T>\n    struct inner_type<T, typename dlib::enable_if_c<is_matrix<T>::value || is_array2d<T>::value || dlib::is_array<T>::value >::type>\n    {\n        typedef typename T::type type;\n    };\n\n    template < typename T>\n    struct inner_type<T, typename dlib::enable_if<is_std_vector<T> >::type>\n    {\n        typedef typename T::value_type type;\n    };\n\n\n// -------------------------------------------------------\n\n    struct user_hit_ctrl_c {};\n\n// -------------------------------------------------------\n\n    template <typename T>\n    void validate_and_populate_arg (\n        long arg_idx,\n        const mxArray *prhs,\n        T& arg\n    ); \n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        matlab_struct& arg\n    );\n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        matlab_object& arg\n    );\n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        std::string& arg\n    );\n\n// -------------------------------------------------------\n\n    template <typename T>\n    struct is_column_major_matrix : public default_is_kind_value {};\n\n    template <\n        typename T,\n        long num_rows,\n        long num_cols,\n        typename mem_manager\n        >\n    struct is_column_major_matrix<matrix<T,num_rows,num_cols,mem_manager,column_major_layout> > \n    { static const bool value = true; }; \n\n// -------------------------------------------------------\n\n    string escape_percent(const string& str)\n    {\n        string temp;\n        for(auto c : str)\n        {\n            if (c != '%')\n            {\n                temp += c;\n            }\n            else\n            {\n                temp += c;\n                temp += c;\n            }\n        }\n        return temp;\n    }\n\n    string escape_percent(const std::ostringstream& sout)\n    {\n        return escape_percent(sout.str());\n    }\n\n// -------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    typename dlib::enable_if_c<is_matrix<matrix_type>::value || is_array2d<matrix_type>::value >::type\n    clear_mat (\n        matrix_type& m\n    )  \n    {\n        m.set_size(0,0);\n    }\n\n    template <\n        typename matrix_type\n        >\n    typename dlib::disable_if_c<is_matrix<matrix_type>::value || is_array2d<matrix_type>::value >::type\n    clear_mat (\n        matrix_type& \n    )  \n    {\n    }\n\n// -------------------------------------------------------\n\n    template <\n        typename matrix_type,\n        typename EXP\n        >\n    typename dlib::enable_if_c<is_matrix<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type\n    assign_mat (\n        const long arg_idx,\n        matrix_type& m,\n        const matrix_exp<EXP>& src\n    )  \n    {\n        if (matrix_type::NR != 0 && matrix_type::NR != src.nc())\n        {\n            std::ostringstream sout;\n            sout << \"Argument \" << arg_idx+1 << \" expects a matrix with \" << matrix_type::NR << \" rows but got one with \" << src.nc();\n            throw invalid_args_exception(sout);\n        }\n        if (matrix_type::NC != 0 && matrix_type::NC != src.nr())\n        {\n            std::ostringstream sout;\n            sout << \"Argument \" << arg_idx+1 << \" expects a matrix with \" << matrix_type::NC << \" columns but got one with \" << src.nr();\n            throw invalid_args_exception(sout);\n        }\n\n\n        m = trans(src);\n    }\n\n    template <\n        typename matrix_type,\n        typename EXP\n        >\n    typename dlib::enable_if_c<is_array2d<matrix_type>::value && is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type\n    assign_mat (\n        const long arg_idx,\n        matrix_type& m,\n        const matrix_exp<EXP>& src\n    )  \n    {\n        assign_image(m , trans(src));\n    }\n\n    template <\n        typename matrix_type,\n        typename EXP\n        >\n    typename disable_if_c<(is_array2d<matrix_type>::value || is_matrix<matrix_type>::value) && \n    is_same_type<typename inner_type<matrix_type>::type,typename EXP::type>::value >::type\n    assign_mat (\n        const long arg_idx,\n        matrix_type& ,\n        const matrix_exp<EXP>& \n    ) \n    {\n        std::ostringstream sout;\n        sout << \"mex_function has some bug in it related to processing input argument \" << arg_idx+1;\n        throw invalid_args_exception(sout);\n    }\n\n\n// -------------------------------------------------------\n\n    template <\n        typename T,\n        typename U\n        >\n    typename dlib::enable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type\n    assign_scalar (\n        const long arg_idx,\n        T& dest,\n        const U& src\n    )  \n    {\n        if (is_signed_type<U>::value && src < 0 && is_unsigned_type<T>::value)\n        {\n            std::ostringstream sout;\n            sout << \"Error, input argument \" << arg_idx+1 << \" must be a non-negative number.\";\n            throw invalid_args_exception(sout);\n        }\n        else\n        {\n            dest = src;\n        }\n    }\n\n    template <\n        typename T,\n        typename U\n        >\n    typename dlib::disable_if_c<is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value >::type\n    assign_scalar (\n        const long arg_idx,\n        T& ,\n        const U& \n    )  \n    {\n        std::ostringstream sout;\n        sout << \"mex_function has some bug in it related to processing input argument \" << arg_idx+1;\n        throw invalid_args_exception(sout);\n    }\n\n\n// -------------------------------------------------------\n\n    void assign_function_handle (\n        const long arg_idx,\n        function_handle& dest,\n        const mxArray* src\n    )  \n    {\n        const_cast<void*&>(dest.h) = (void*)src;\n    }\n\n    template <\n        typename T\n        >\n    void assign_function_handle (\n        const long arg_idx,\n        T& ,\n        const mxArray* \n    )  \n    {\n        std::ostringstream sout;\n        sout << \"mex_function has some bug in it related to processing input argument \" << arg_idx+1;\n        throw invalid_args_exception(sout);\n    }\n\n\n// -------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename dlib::enable_if<is_array_type<T> >::type\n    assign_std_vector (\n        const long arg_idx,\n        T& dest,\n        const mxArray* src\n    )  \n    {\n        const long nr = mxGetM(src);\n        const long nc = mxGetN(src);\n\n        typedef typename inner_type<T>::type type;\n\n        if (!mxIsCell(src))\n        {\n            std::ostringstream sout;\n            sout << \"Input argument \" << arg_idx+1 << \" must be a cell array\";\n            throw invalid_args_exception(sout);\n        }\n        if (nr != 1 && nc != 1)\n        {\n            std::ostringstream sout;\n            sout << \"Input argument \" << arg_idx+1 << \" must be a cell array with exactly 1 row or 1 column (i.e. a row or column vector)\";\n            throw invalid_args_exception(sout);\n        }\n\n        const long size = nr*nc;\n        dest.resize(size);\n\n        for (unsigned long i = 0; i < dest.size(); ++i)\n        {\n            try\n            {\n                validate_and_populate_arg(i, mxGetCell(src, i), dest[i]);\n            }\n            catch (invalid_args_exception& e)\n            {\n                std::ostringstream sout;\n                sout << \"Error in argument \" << arg_idx+1 << \": element \" << i+1 << \" of cell array not the expected type.\\n\";\n                sout << \"\\t\" << e.what();\n                throw invalid_args_exception(sout);\n            }\n        }\n\n    }\n\n    template <\n        typename T\n        >\n    typename disable_if<is_array_type<T> >::type\n    assign_std_vector (\n        const long arg_idx,\n        T& ,\n        const mxArray*\n    )  \n    {\n        std::ostringstream sout;\n        sout << \"mex_function has some bug in it related to processing input argument \" << arg_idx+1;\n        throw invalid_args_exception(sout);\n    }\n\n// -------------------------------------------------------\n\n    template <typename T> \n    void assign_image (\n        const long arg_idx,\n        T&,\n        const dlib::uint8* data,\n        long nr,\n        long nc\n    )\n    {\n        std::ostringstream sout;\n        sout << \"mex_function has some bug in it related to processing input argument \" << arg_idx+1;\n        throw invalid_args_exception(sout);\n    }\n\n    template <typename MM>\n    void assign_image(\n        const long ,\n        array2d<dlib::rgb_pixel,MM>& img,\n        const dlib::uint8* data,\n        long nr,\n        long nc\n    )\n    {\n        img.set_size(nr, nc);\n        for (long c = 0; c < img.nc(); ++c)\n            for (long r = 0; r < img.nr(); ++r)\n                img[r][c].red = *data++;\n        for (long c = 0; c < img.nc(); ++c)\n            for (long r = 0; r < img.nr(); ++r)\n                img[r][c].green = *data++;\n        for (long c = 0; c < img.nc(); ++c)\n            for (long r = 0; r < img.nr(); ++r)\n                img[r][c].blue = *data++;\n    }\n\n// -------------------------------------------------------\n\n    template <typename T>\n    void call_private_set_mxArray(T&, mxArray*) {}\n    void call_private_set_mxArray(matrix_colmajor& item, mxArray* m) { item._private_set_mxArray(m); }\n    void call_private_set_mxArray(fmatrix_colmajor& item, mxArray* m) { item._private_set_mxArray(m); }\n\n// -------------------------------------------------------\n\n    template <typename T>\n    void validate_and_populate_arg (\n        long arg_idx,\n        const mxArray *prhs,\n        T& arg\n    ) \n    {\n        using namespace mex_binding;\n        if (is_built_in_scalar_type<T>::value || is_same_type<T,bool>::value)\n        {\n            if( !(mxIsDouble(prhs) || mxIsSingle(prhs) || mxIsLogical(prhs) ) || \n                mxIsComplex(prhs) ||\n                mxGetNumberOfElements(prhs)!=1 ) \n            {\n                std::ostringstream sout;\n                sout << \"Input argument \" << arg_idx+1 << \" must be a scalar\";\n                throw invalid_args_exception(sout);\n            }\n\n            assign_scalar(arg_idx, arg , mxGetScalar(prhs));\n        }\n        else if (is_matrix<T>::value || is_array2d<T>::value)\n        {\n            if (prhs == NULL)\n            {\n                clear_mat(arg);\n                return;\n            }\n\n            typedef typename inner_type<T>::type type;\n\n            const int num_dims = mxGetNumberOfDimensions(prhs);\n            const long nr = mxGetM(prhs);\n            const long nc = mxGetN(prhs);\n\n            if (is_same_type<type,dlib::rgb_pixel>::value)\n            {\n                if (!(num_dims == 3 && mxGetDimensions(prhs)[2] == 3 && mxIsUint8(prhs)))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a 3-D NxMx3 image matrix of uint8\";\n                    throw invalid_args_exception(sout);\n                }\n\n                const long rows = mxGetDimensions(prhs)[0];\n                const long cols = mxGetDimensions(prhs)[1];\n                assign_image(arg_idx, arg , (const dlib::uint8*)mxGetData(prhs), rows, cols);\n                return;\n            }\n\n            if (num_dims != 2)\n            {\n                std::ostringstream sout;\n                sout << \"Input argument \" << arg_idx+1 << \" must be a 2-D matrix (got a \" << num_dims << \"-D matrix)\";\n                throw invalid_args_exception(sout);\n            }\n\n\n            if (is_same_type<type,double>::value)\n            {\n                if (!mxIsDouble(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of doubles\";\n                    throw invalid_args_exception(sout);\n                }\n                if (is_column_major_matrix<T>::value)\n                    call_private_set_mxArray(arg, (mxArray*)prhs);\n                else\n                    assign_mat(arg_idx, arg , pointer_to_matrix(mxGetPr(prhs), nc, nr));\n            }\n            else if (is_same_type<type, float>::value)\n            {\n                if (!mxIsSingle(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of single/float\";\n                    throw invalid_args_exception(sout);\n                }\n\n                if (is_column_major_matrix<T>::value)\n                    call_private_set_mxArray(arg,(mxArray*)prhs);\n                else\n                    assign_mat(arg_idx, arg , pointer_to_matrix((const float*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, bool>::value)\n            {\n                if (!mxIsLogical(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of logical elements.\";\n                    throw invalid_args_exception(sout);\n                }\n                DLIB_CASSERT(sizeof(mxLogical) == sizeof(bool),\"logical matrices are not supported by the mex wrapper when mxLogical isn't a bool.\");\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const bool*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::uint8>::value)\n            {\n                if (!mxIsUint8(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of uint8\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::uint8*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::int8>::value)\n            {\n                if (!mxIsInt8(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of int8\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const dlib::int8*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::int16>::value ||\n                    (is_same_type<type, short>::value && sizeof(short) == sizeof(dlib::int16)))\n            {\n                if (!mxIsInt16(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of int16\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::uint16>::value ||\n                    (is_same_type<type, unsigned short>::value && sizeof(unsigned short) == sizeof(dlib::uint16)))\n            {\n                if (!mxIsUint16(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of uint16\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::int32>::value ||\n                    (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int32)) ||\n                    (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int32)))\n            {\n                if (!mxIsInt32(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of int32\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::uint32>::value ||\n                    (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint32)) ||\n                    (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint32)))\n            {\n                if (!mxIsUint32(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of uint32\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::uint64>::value ||\n                    (is_same_type<type, unsigned int>::value && sizeof(unsigned int) == sizeof(dlib::uint64)) ||\n                    (is_same_type<type, unsigned long>::value && sizeof(unsigned long) == sizeof(dlib::uint64)))\n            {\n                if (!mxIsUint64(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of uint64\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else if (is_same_type<type, dlib::int64>::value ||\n                    (is_same_type<type, int>::value && sizeof(int) == sizeof(dlib::int64)) ||\n                    (is_same_type<type, long>::value && sizeof(long) == sizeof(dlib::int64)))\n            {\n                if (!mxIsInt64(prhs) || mxIsComplex(prhs))\n                {\n                    std::ostringstream sout;\n                    sout << \"Input argument \" << arg_idx+1 << \" must be a matrix of int64\";\n                    throw invalid_args_exception(sout);\n                }\n\n                assign_mat(arg_idx, arg , pointer_to_matrix((const type*)mxGetData(prhs), nc, nr));\n            }\n            else\n            {\n                throw invalid_args_exception(\"mex_function uses unsupported matrix type\");\n            }\n        }\n        else if (is_array_type<T>::value)\n        {\n            assign_std_vector(arg_idx, arg, prhs);\n\n        }\n        else if (is_same_type<T,function_handle>::value)\n        {\n            if (!mxIsClass(prhs, \"function_handle\"))\n            {\n                std::ostringstream sout;\n                sout << \"Input argument \" << arg_idx+1 << \" must be a function handle.\";\n                throw invalid_args_exception(sout);\n            }\n            assign_function_handle(arg_idx, arg, prhs);\n        }\n        else\n        {\n            throw invalid_args_exception(\"mex_function uses unsupported input argument type\");\n        }\n    }\n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        matlab_struct& arg\n    )\n    {\n        if (!mxIsStruct(prhs))\n        {\n            std::ostringstream sout;\n            sout << \"Input argument \" << arg_idx+1 << \" must be a struct\";\n            throw invalid_args_exception(sout);\n        }\n\n        arg.set_struct_handle(arg_idx, prhs);\n    }\n\n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        matlab_object& arg\n    )\n    {\n        arg.set_object_handle(arg_idx, prhs);\n    }\n\n\n    void validate_and_populate_arg(\n        long arg_idx,\n        const mxArray *prhs,\n        std::string& arg\n    )\n    {\n        if (!mxIsChar(prhs))\n        {\n            std::ostringstream sout;\n            sout << \"Input argument \" << arg_idx+1 << \" must be a char string\";\n            throw invalid_args_exception(sout);\n        }\n\n        const long nr = mxGetM(prhs);\n        const long nc = mxGetN(prhs);\n        const long size = nr*nc;\n        arg.resize(size+1);\n        if (mxGetString(prhs, &arg[0], arg.size()))\n        {\n            std::ostringstream sout;\n            sout << \"Input argument \" << arg_idx+1 << \" encountered an error while calling mxGetString()\";\n            throw invalid_args_exception(sout);\n        }\n        arg.resize(size);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    typename dlib::enable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab (\n        dlib::uint8* mat,\n        const matrix_exp<EXP>& item\n    )\n    {\n        for (long c = 0; c < item.nc(); ++c)\n            for (long r = 0; r < item.nr(); ++r)\n                *mat++ = item(r,c).red;\n        for (long c = 0; c < item.nc(); ++c)\n            for (long r = 0; r < item.nr(); ++r)\n                *mat++ = item(r,c).green;\n        for (long c = 0; c < item.nc(); ++c)\n            for (long r = 0; r < item.nr(); ++r)\n                *mat++ = item(r,c).blue;\n    }\n\n    template <typename T, typename EXP>\n    typename disable_if<is_same_type<dlib::rgb_pixel,typename EXP::type> >::type assign_image_to_matlab (\n        T* mat,\n        const matrix_exp<EXP>& \n    )\n    {\n        mexErrMsgIdAndTxt(\"mex_function:validate_and_populate_arg\",\n                          \"mex_function uses unsupported output image argument type\");\n    }\n\n    template <typename T>\n    typename dlib::enable_if<is_matrix<T> >::type assign_to_matlab(\n        mxArray*& plhs,\n        const T& item\n    ) \n    {\n        typedef typename T::type type;\n\n        type* mat = 0;\n\n        if (is_same_type<double, type>::value)\n        {\n            plhs = mxCreateDoubleMatrix(item.nr(),\n                                        item.nc(),\n                                        mxREAL);\n\n            mat = (type*)mxGetPr(plhs);\n        }\n        else if (is_same_type<float, type>::value )\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxSINGLE_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<bool, type>::value )\n        {\n            plhs = mxCreateLogicalMatrix(item.nr(),\n                                         item.nc());\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::uint8, type>::value )\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxUINT8_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::int8, type>::value )\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxINT8_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::int16, type>::value ||\n                 (is_same_type<short,type>::value && sizeof(short) == sizeof(dlib::int16)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxINT16_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::uint16, type>::value ||\n                 (is_same_type<unsigned short,type>::value && sizeof(unsigned short) == sizeof(dlib::uint16)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxUINT16_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::int32, type>::value ||\n                 (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int32)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxINT32_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::uint32, type>::value ||\n                 (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint32)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxUINT32_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::uint64, type>::value ||\n                 (is_same_type<unsigned long,type>::value && sizeof(unsigned long) == sizeof(dlib::uint64)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxUINT64_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::int64, type>::value  || \n                 (is_same_type<long,type>::value && sizeof(long) == sizeof(dlib::int64)))\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxINT64_CLASS,\n                                         mxREAL);\n\n            mat = (type*)mxGetData(plhs);\n        }\n        else if (is_same_type<dlib::rgb_pixel, type>::value)\n        {\n            mwSize dims[3] = {(mwSize)item.nr(), (mwSize)item.nc(), 3};\n            plhs = mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL);\n\n            assign_image_to_matlab((dlib::uint8*)mxGetData(plhs), item);\n            return;\n        }\n        else\n        {\n            mexErrMsgIdAndTxt(\"mex_function:validate_and_populate_arg\",\n                              \"mex_function uses unsupported output argument type\");\n        }\n\n\n        const_temp_matrix<T> m(item);\n\n        for (long c = 0; c < m.nc(); ++c)\n        {\n            for ( long r = 0; r < m.nr(); ++r)\n            {\n                *mat++ = m(r,c);\n            }\n        }\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        matrix_colmajor& item\n    )\n    {\n        if(item._private_is_owned_by_matlab())\n        {\n            // Don't need to do a copy if it's this kind of matrix since we can just\n            // pull the underlying mxArray out directly and thus avoid a copy.\n            plhs = item._private_release_mxArray();\n            // If there isn't anything there because the matrix is empty then set it to an\n            // empty matrix.\n            if (!plhs)\n                plhs = mxCreateDoubleMatrix(item.nr(),\n                                            item.nc(),\n                                            mxREAL);\n        }\n        else\n        {\n            plhs = mxCreateDoubleMatrix(item.nr(),\n                                        item.nc(),\n                                        mxREAL);\n            if (item.size() != 0)\n                memcpy(mxGetPr(plhs), &item(0,0), item.size()*sizeof(double));\n        }\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        fmatrix_colmajor& item\n    )\n    {\n        if(item._private_is_owned_by_matlab())\n        {\n            // Don't need to do a copy if it's this kind of matrix since we can just\n            // pull the underlying mxArray out directly and thus avoid a copy.\n            plhs = item._private_release_mxArray();\n            // If there isn't anything there because the matrix is empty then set it to an\n            // empty matrix.\n            if (!plhs)\n                plhs = mxCreateNumericMatrix(item.nr(),\n                                            item.nc(),\n                                            mxSINGLE_CLASS,\n                                            mxREAL);\n        }\n        else\n        {\n            plhs = mxCreateNumericMatrix(item.nr(),\n                                         item.nc(),\n                                         mxSINGLE_CLASS,\n                                         mxREAL);\n            if (item.size() != 0)\n                memcpy(mxGetPr(plhs), &item(0,0), item.size()*sizeof(float));\n        }\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        matlab_struct& item\n    )\n    {\n        plhs = (mxArray*)item.release_struct_to_matlab();\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        matlab_object& item\n    )\n    {\n        plhs = (mxArray*)item.release_object_to_matlab();\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        const std::string& item\n    ) \n    {\n        plhs = mxCreateString(item.c_str());\n    }\n\n    template <typename T, typename MM>\n    void assign_to_matlab(\n        mxArray*& plhs,\n        const array2d<T,MM>& item\n    ) \n    {\n        assign_to_matlab(plhs,array_to_matrix(item));\n    }\n\n    template <typename T>\n    typename dlib::disable_if_c<is_matrix<T>::value || is_array_type<T>::value || \n                                is_same_type<T,function_handle>::value>::type assign_to_matlab(\n        mxArray*& plhs,\n        const T& item\n    ) \n    {\n        plhs = mxCreateDoubleScalar(item);\n    }\n\n\n    void assign_to_matlab (\n        mxArray*& plhs,\n        const char* str\n    )\n    {\n        assign_to_matlab(plhs, std::string(str));\n    }\n\n    void assign_to_matlab(\n        mxArray*& plhs,\n        const function_handle& h\n    )\n    {\n    }\n\n    template <typename T>\n    typename dlib::enable_if<is_array_type<T> >::type assign_to_matlab(\n        mxArray*& plhs,\n        const T& item\n    ) \n    {\n        mwSize dims[1] = {item.size()};\n        plhs = mxCreateCellArray(1,dims);\n        for (unsigned long i = 0; i < item.size(); ++i)\n        {\n            mxArray* next = 0;\n            assign_to_matlab(next, item[i]);\n            mxSetCell(plhs, i, next);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void mark_owned_by_matlab (const T&){}\n\n    void mark_owned_by_matlab(matrix_colmajor& item) { item._private_mark_owned_by_matlab(); }\n    void mark_owned_by_matlab(fmatrix_colmajor& item) { item._private_mark_owned_by_matlab(); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        unsigned long num_args\n        >\n    struct call_mex_function_helper;\n\n    template <>\n    struct call_mex_function_helper<0>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int , mxArray **,\n            int , const mxArray **\n        ) const\n        {\n            f();\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<1>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n\n            typename basic_type<arg1_type>::type A1;\n\n            mark_owned_by_matlab(A1);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n\n            f(A1);\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<2>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n\n            f(A1,A2);\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<3>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n\n            f(A1,A2,A3);\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<4>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n\n            f(A1,A2,A3,A4);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<5>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n\n            f(A1,A2,A3,A4,A5);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n        }\n    };\n\n\n    template <>\n    struct call_mex_function_helper<6>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n\n            f(A1,A2,A3,A4,A5,A6);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n        }\n    };\n\n\n    template <>\n    struct call_mex_function_helper<7>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n\n            f(A1,A2,A3,A4,A5,A6,A7);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n        }\n    };\n\n\n    template <>\n    struct call_mex_function_helper<8>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n        }\n    };\n\n\n    template <>\n    struct call_mex_function_helper<9>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n        }\n    };\n\n\n\n    template <>\n    struct call_mex_function_helper<10>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<11>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<12>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<13>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<14>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<15>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<16>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n            typedef typename sig_traits<funct>::arg16_type arg16_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n            typename basic_type<arg16_type>::type A16;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n            mark_owned_by_matlab(A16);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n            if (i < nrhs && is_input_type<arg16_type>::value) {validate_and_populate_arg(i,prhs[i],A16); ++i;} ELSE_ASSIGN_ARG_16;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n            if (is_output_type<arg16_type>::value) {assign_to_matlab(plhs[i],A16); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<17>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n            typedef typename sig_traits<funct>::arg16_type arg16_type;\n            typedef typename sig_traits<funct>::arg17_type arg17_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n            typename basic_type<arg16_type>::type A16;\n            typename basic_type<arg17_type>::type A17;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n            mark_owned_by_matlab(A16);\n            mark_owned_by_matlab(A17);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n            if (i < nrhs && is_input_type<arg16_type>::value) {validate_and_populate_arg(i,prhs[i],A16); ++i;} ELSE_ASSIGN_ARG_16;\n            if (i < nrhs && is_input_type<arg17_type>::value) {validate_and_populate_arg(i,prhs[i],A17); ++i;} ELSE_ASSIGN_ARG_17;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n            if (is_output_type<arg16_type>::value) {assign_to_matlab(plhs[i],A16); ++i;}\n            if (is_output_type<arg17_type>::value) {assign_to_matlab(plhs[i],A17); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<18>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n            typedef typename sig_traits<funct>::arg16_type arg16_type;\n            typedef typename sig_traits<funct>::arg17_type arg17_type;\n            typedef typename sig_traits<funct>::arg18_type arg18_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n            typename basic_type<arg16_type>::type A16;\n            typename basic_type<arg17_type>::type A17;\n            typename basic_type<arg18_type>::type A18;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n            mark_owned_by_matlab(A16);\n            mark_owned_by_matlab(A17);\n            mark_owned_by_matlab(A18);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n            if (i < nrhs && is_input_type<arg16_type>::value) {validate_and_populate_arg(i,prhs[i],A16); ++i;} ELSE_ASSIGN_ARG_16;\n            if (i < nrhs && is_input_type<arg17_type>::value) {validate_and_populate_arg(i,prhs[i],A17); ++i;} ELSE_ASSIGN_ARG_17;\n            if (i < nrhs && is_input_type<arg18_type>::value) {validate_and_populate_arg(i,prhs[i],A18); ++i;} ELSE_ASSIGN_ARG_18;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n            if (is_output_type<arg16_type>::value) {assign_to_matlab(plhs[i],A16); ++i;}\n            if (is_output_type<arg17_type>::value) {assign_to_matlab(plhs[i],A17); ++i;}\n            if (is_output_type<arg18_type>::value) {assign_to_matlab(plhs[i],A18); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<19>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n            typedef typename sig_traits<funct>::arg16_type arg16_type;\n            typedef typename sig_traits<funct>::arg17_type arg17_type;\n            typedef typename sig_traits<funct>::arg18_type arg18_type;\n            typedef typename sig_traits<funct>::arg19_type arg19_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n            typename basic_type<arg16_type>::type A16;\n            typename basic_type<arg17_type>::type A17;\n            typename basic_type<arg18_type>::type A18;\n            typename basic_type<arg19_type>::type A19;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n            mark_owned_by_matlab(A16);\n            mark_owned_by_matlab(A17);\n            mark_owned_by_matlab(A18);\n            mark_owned_by_matlab(A19);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n            if (i < nrhs && is_input_type<arg16_type>::value) {validate_and_populate_arg(i,prhs[i],A16); ++i;} ELSE_ASSIGN_ARG_16;\n            if (i < nrhs && is_input_type<arg17_type>::value) {validate_and_populate_arg(i,prhs[i],A17); ++i;} ELSE_ASSIGN_ARG_17;\n            if (i < nrhs && is_input_type<arg18_type>::value) {validate_and_populate_arg(i,prhs[i],A18); ++i;} ELSE_ASSIGN_ARG_18;\n            if (i < nrhs && is_input_type<arg19_type>::value) {validate_and_populate_arg(i,prhs[i],A19); ++i;} ELSE_ASSIGN_ARG_19;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n            if (is_output_type<arg16_type>::value) {assign_to_matlab(plhs[i],A16); ++i;}\n            if (is_output_type<arg17_type>::value) {assign_to_matlab(plhs[i],A17); ++i;}\n            if (is_output_type<arg18_type>::value) {assign_to_matlab(plhs[i],A18); ++i;}\n            if (is_output_type<arg19_type>::value) {assign_to_matlab(plhs[i],A19); ++i;}\n        }\n    };\n\n    template <>\n    struct call_mex_function_helper<20>\n    {\n        template <typename funct>\n        void callit(\n            const funct& f,\n            int nlhs, mxArray *plhs[],\n            int nrhs, const mxArray *prhs[]\n        ) const\n        {\n            typedef typename sig_traits<funct>::arg1_type arg1_type;\n            typedef typename sig_traits<funct>::arg2_type arg2_type;\n            typedef typename sig_traits<funct>::arg3_type arg3_type;\n            typedef typename sig_traits<funct>::arg4_type arg4_type;\n            typedef typename sig_traits<funct>::arg5_type arg5_type;\n            typedef typename sig_traits<funct>::arg6_type arg6_type;\n            typedef typename sig_traits<funct>::arg7_type arg7_type;\n            typedef typename sig_traits<funct>::arg8_type arg8_type;\n            typedef typename sig_traits<funct>::arg9_type arg9_type;\n            typedef typename sig_traits<funct>::arg10_type arg10_type;\n            typedef typename sig_traits<funct>::arg11_type arg11_type;\n            typedef typename sig_traits<funct>::arg12_type arg12_type;\n            typedef typename sig_traits<funct>::arg13_type arg13_type;\n            typedef typename sig_traits<funct>::arg14_type arg14_type;\n            typedef typename sig_traits<funct>::arg15_type arg15_type;\n            typedef typename sig_traits<funct>::arg16_type arg16_type;\n            typedef typename sig_traits<funct>::arg17_type arg17_type;\n            typedef typename sig_traits<funct>::arg18_type arg18_type;\n            typedef typename sig_traits<funct>::arg19_type arg19_type;\n            typedef typename sig_traits<funct>::arg20_type arg20_type;\n\n            typename basic_type<arg1_type>::type A1;\n            typename basic_type<arg2_type>::type A2;\n            typename basic_type<arg3_type>::type A3;\n            typename basic_type<arg4_type>::type A4;\n            typename basic_type<arg5_type>::type A5;\n            typename basic_type<arg6_type>::type A6;\n            typename basic_type<arg7_type>::type A7;\n            typename basic_type<arg8_type>::type A8;\n            typename basic_type<arg9_type>::type A9;\n            typename basic_type<arg10_type>::type A10;\n            typename basic_type<arg11_type>::type A11;\n            typename basic_type<arg12_type>::type A12;\n            typename basic_type<arg13_type>::type A13;\n            typename basic_type<arg14_type>::type A14;\n            typename basic_type<arg15_type>::type A15;\n            typename basic_type<arg16_type>::type A16;\n            typename basic_type<arg17_type>::type A17;\n            typename basic_type<arg18_type>::type A18;\n            typename basic_type<arg19_type>::type A19;\n            typename basic_type<arg20_type>::type A20;\n\n            mark_owned_by_matlab(A1);\n            mark_owned_by_matlab(A2);\n            mark_owned_by_matlab(A3);\n            mark_owned_by_matlab(A4);\n            mark_owned_by_matlab(A5);\n            mark_owned_by_matlab(A6);\n            mark_owned_by_matlab(A7);\n            mark_owned_by_matlab(A8);\n            mark_owned_by_matlab(A9);\n            mark_owned_by_matlab(A10);\n            mark_owned_by_matlab(A11);\n            mark_owned_by_matlab(A12);\n            mark_owned_by_matlab(A13);\n            mark_owned_by_matlab(A14);\n            mark_owned_by_matlab(A15);\n            mark_owned_by_matlab(A16);\n            mark_owned_by_matlab(A17);\n            mark_owned_by_matlab(A18);\n            mark_owned_by_matlab(A19);\n            mark_owned_by_matlab(A20);\n\n            int i = 0;\n            if (i < nrhs && is_input_type<arg1_type>::value) {validate_and_populate_arg(i,prhs[i],A1); ++i;} ELSE_ASSIGN_ARG_1;\n            if (i < nrhs && is_input_type<arg2_type>::value) {validate_and_populate_arg(i,prhs[i],A2); ++i;} ELSE_ASSIGN_ARG_2;\n            if (i < nrhs && is_input_type<arg3_type>::value) {validate_and_populate_arg(i,prhs[i],A3); ++i;} ELSE_ASSIGN_ARG_3;\n            if (i < nrhs && is_input_type<arg4_type>::value) {validate_and_populate_arg(i,prhs[i],A4); ++i;} ELSE_ASSIGN_ARG_4;\n            if (i < nrhs && is_input_type<arg5_type>::value) {validate_and_populate_arg(i,prhs[i],A5); ++i;} ELSE_ASSIGN_ARG_5;\n            if (i < nrhs && is_input_type<arg6_type>::value) {validate_and_populate_arg(i,prhs[i],A6); ++i;} ELSE_ASSIGN_ARG_6;\n            if (i < nrhs && is_input_type<arg7_type>::value) {validate_and_populate_arg(i,prhs[i],A7); ++i;} ELSE_ASSIGN_ARG_7;\n            if (i < nrhs && is_input_type<arg8_type>::value) {validate_and_populate_arg(i,prhs[i],A8); ++i;} ELSE_ASSIGN_ARG_8;\n            if (i < nrhs && is_input_type<arg9_type>::value) {validate_and_populate_arg(i,prhs[i],A9); ++i;} ELSE_ASSIGN_ARG_9;\n            if (i < nrhs && is_input_type<arg10_type>::value) {validate_and_populate_arg(i,prhs[i],A10); ++i;} ELSE_ASSIGN_ARG_10;\n            if (i < nrhs && is_input_type<arg11_type>::value) {validate_and_populate_arg(i,prhs[i],A11); ++i;} ELSE_ASSIGN_ARG_11;\n            if (i < nrhs && is_input_type<arg12_type>::value) {validate_and_populate_arg(i,prhs[i],A12); ++i;} ELSE_ASSIGN_ARG_12;\n            if (i < nrhs && is_input_type<arg13_type>::value) {validate_and_populate_arg(i,prhs[i],A13); ++i;} ELSE_ASSIGN_ARG_13;\n            if (i < nrhs && is_input_type<arg14_type>::value) {validate_and_populate_arg(i,prhs[i],A14); ++i;} ELSE_ASSIGN_ARG_14;\n            if (i < nrhs && is_input_type<arg15_type>::value) {validate_and_populate_arg(i,prhs[i],A15); ++i;} ELSE_ASSIGN_ARG_15;\n            if (i < nrhs && is_input_type<arg16_type>::value) {validate_and_populate_arg(i,prhs[i],A16); ++i;} ELSE_ASSIGN_ARG_16;\n            if (i < nrhs && is_input_type<arg17_type>::value) {validate_and_populate_arg(i,prhs[i],A17); ++i;} ELSE_ASSIGN_ARG_17;\n            if (i < nrhs && is_input_type<arg18_type>::value) {validate_and_populate_arg(i,prhs[i],A18); ++i;} ELSE_ASSIGN_ARG_18;\n            if (i < nrhs && is_input_type<arg19_type>::value) {validate_and_populate_arg(i,prhs[i],A19); ++i;} ELSE_ASSIGN_ARG_19;\n            if (i < nrhs && is_input_type<arg20_type>::value) {validate_and_populate_arg(i,prhs[i],A20); ++i;} ELSE_ASSIGN_ARG_20;\n\n            f(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,A20);\n\n\n            i = 0;\n            if (is_output_type<arg1_type>::value) {assign_to_matlab(plhs[i],A1); ++i;}\n            if (is_output_type<arg2_type>::value) {assign_to_matlab(plhs[i],A2); ++i;}\n            if (is_output_type<arg3_type>::value) {assign_to_matlab(plhs[i],A3); ++i;}\n            if (is_output_type<arg4_type>::value) {assign_to_matlab(plhs[i],A4); ++i;}\n            if (is_output_type<arg5_type>::value) {assign_to_matlab(plhs[i],A5); ++i;}\n            if (is_output_type<arg6_type>::value) {assign_to_matlab(plhs[i],A6); ++i;}\n            if (is_output_type<arg7_type>::value) {assign_to_matlab(plhs[i],A7); ++i;}\n            if (is_output_type<arg8_type>::value) {assign_to_matlab(plhs[i],A8); ++i;}\n            if (is_output_type<arg9_type>::value) {assign_to_matlab(plhs[i],A9); ++i;}\n            if (is_output_type<arg10_type>::value) {assign_to_matlab(plhs[i],A10); ++i;}\n            if (is_output_type<arg11_type>::value) {assign_to_matlab(plhs[i],A11); ++i;}\n            if (is_output_type<arg12_type>::value) {assign_to_matlab(plhs[i],A12); ++i;}\n            if (is_output_type<arg13_type>::value) {assign_to_matlab(plhs[i],A13); ++i;}\n            if (is_output_type<arg14_type>::value) {assign_to_matlab(plhs[i],A14); ++i;}\n            if (is_output_type<arg15_type>::value) {assign_to_matlab(plhs[i],A15); ++i;}\n            if (is_output_type<arg16_type>::value) {assign_to_matlab(plhs[i],A16); ++i;}\n            if (is_output_type<arg17_type>::value) {assign_to_matlab(plhs[i],A17); ++i;}\n            if (is_output_type<arg18_type>::value) {assign_to_matlab(plhs[i],A18); ++i;}\n            if (is_output_type<arg19_type>::value) {assign_to_matlab(plhs[i],A19); ++i;}\n            if (is_output_type<arg20_type>::value) {assign_to_matlab(plhs[i],A20); ++i;}\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T> struct is_matlab_object                         { const static bool value = false; };\n    template <>           struct is_matlab_object <matlab_object>         { const static bool value = true; };\n    template <>           struct is_matlab_object <const matlab_object>   { const static bool value = true; };\n    template <>           struct is_matlab_object <matlab_object&>        { const static bool value = true; };\n    template <>           struct is_matlab_object <const matlab_object&>  { const static bool value = true; };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    void call_mex_function (\n        const funct& f,\n        int nlhs, mxArray *plhs[],\n        int nrhs, const mxArray *prhs[]\n    )\n    {\n        const long expected_nrhs = funct_traits<funct>::num_inputs;\n        const long expected_nlhs = funct_traits<funct>::num_outputs;\n        const long expected_args = expected_nrhs + expected_nlhs;\n\n        long defaulted_args = 0;\n\n        #ifdef ARG_1_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg1_type>::value);\n            #ifndef ARG_2_DEFAULT\n                // You can't define a default for argument 1 if you don't define one for argument 2 also.\n                COMPILE_TIME_ASSERT(expected_args < 2);\n            #endif\n            COMPILE_TIME_ASSERT(1 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_2_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg2_type>::value);\n            #ifndef ARG_3_DEFAULT\n                // You can't define a default for argument 2 if you don't define one for argument 3 also.\n                COMPILE_TIME_ASSERT(expected_args < 3);\n            #endif\n            COMPILE_TIME_ASSERT(2 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_3_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg3_type>::value);\n            #ifndef ARG_4_DEFAULT\n                // You can't define a default for argument 3 if you don't define one for argument 4 also.\n                COMPILE_TIME_ASSERT(expected_args < 4);\n            #endif\n            COMPILE_TIME_ASSERT(3 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_4_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg4_type>::value);\n            #ifndef ARG_5_DEFAULT\n                // You can't define a default for argument 4 if you don't define one for argument 5 also.\n                COMPILE_TIME_ASSERT(expected_args < 5);\n            #endif\n            COMPILE_TIME_ASSERT(4 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_5_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg5_type>::value);\n            #ifndef ARG_6_DEFAULT\n                // You can't define a default for argument 5 if you don't define one for argument 6 also.\n                COMPILE_TIME_ASSERT(expected_args < 6);\n            #endif\n            COMPILE_TIME_ASSERT(5 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_6_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg6_type>::value);\n            #ifndef ARG_7_DEFAULT\n                // You can't define a default for argument 6 if you don't define one for argument 7 also.\n                COMPILE_TIME_ASSERT(expected_args < 7);\n            #endif\n            COMPILE_TIME_ASSERT(6 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_7_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg7_type>::value);\n            #ifndef ARG_8_DEFAULT\n                // You can't define a default for argument 7 if you don't define one for argument 8 also.\n                COMPILE_TIME_ASSERT(expected_args < 8);\n            #endif\n            COMPILE_TIME_ASSERT(7 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_8_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg8_type>::value);\n            #ifndef ARG_9_DEFAULT\n                // You can't define a default for argument 8 if you don't define one for argument 9 also.\n                COMPILE_TIME_ASSERT(expected_args < 9);\n            #endif\n            COMPILE_TIME_ASSERT(8 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_9_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg9_type>::value);\n            #ifndef ARG_10_DEFAULT\n                // You can't define a default for argument 9 if you don't define one for argument 10 also.\n                COMPILE_TIME_ASSERT(expected_args < 10);\n            #endif\n            COMPILE_TIME_ASSERT(9 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_10_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg10_type>::value);\n            #ifndef ARG_11_DEFAULT\n                // You can't define a default for argument 10 if you don't define one for argument 11 also.\n                COMPILE_TIME_ASSERT(expected_args < 11);\n            #endif\n            COMPILE_TIME_ASSERT(10 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_11_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg11_type>::value);\n            #ifndef ARG_12_DEFAULT\n                // You can't define a default for argument 11 if you don't define one for argument 12 also.\n                COMPILE_TIME_ASSERT(expected_args < 12);\n            #endif\n            COMPILE_TIME_ASSERT(11 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_12_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg12_type>::value);\n            #ifndef ARG_13_DEFAULT\n                // You can't define a default for argument 12 if you don't define one for argument 13 also.\n                COMPILE_TIME_ASSERT(expected_args < 13);\n            #endif\n            COMPILE_TIME_ASSERT(12 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_13_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg13_type>::value);\n            #ifndef ARG_14_DEFAULT\n                // You can't define a default for argument 13 if you don't define one for argument 14 also.\n                COMPILE_TIME_ASSERT(expected_args < 14);\n            #endif\n            COMPILE_TIME_ASSERT(13 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_14_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg14_type>::value);\n            #ifndef ARG_15_DEFAULT\n                // You can't define a default for argument 14 if you don't define one for argument 15 also.\n                COMPILE_TIME_ASSERT(expected_args < 15);\n            #endif\n            COMPILE_TIME_ASSERT(14 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_15_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg15_type>::value);\n            #ifndef ARG_16_DEFAULT\n                // You can't define a default for argument 15 if you don't define one for argument 16 also.\n                COMPILE_TIME_ASSERT(expected_args < 16);\n            #endif\n            COMPILE_TIME_ASSERT(15 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_16_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg16_type>::value);\n            #ifndef ARG_17_DEFAULT\n                // You can't define a default for argument 16 if you don't define one for argument 17 also.\n                COMPILE_TIME_ASSERT(expected_args < 17);\n            #endif\n            COMPILE_TIME_ASSERT(16 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_17_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg17_type>::value);\n            #ifndef ARG_18_DEFAULT\n                // You can't define a default for argument 17 if you don't define one for argument 18 also.\n                COMPILE_TIME_ASSERT(expected_args < 18);\n            #endif\n            COMPILE_TIME_ASSERT(17 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_18_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg18_type>::value);\n            #ifndef ARG_19_DEFAULT\n                // You can't define a default for argument 18 if you don't define one for argument 19 also.\n                COMPILE_TIME_ASSERT(expected_args < 19);\n            #endif\n            COMPILE_TIME_ASSERT(18 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_19_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg19_type>::value);\n            #ifndef ARG_20_DEFAULT\n                // You can't define a default for argument 19 if you don't define one for argument 20 also.\n                COMPILE_TIME_ASSERT(expected_args < 20);\n            #endif\n            COMPILE_TIME_ASSERT(19 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n        #ifdef ARG_20_DEFAULT\n            ++defaulted_args;\n            // You can only set an argument's default value if it is an input argument.\n            COMPILE_TIME_ASSERT(is_input_type<typename sig_traits<funct>::arg20_type>::value);\n            COMPILE_TIME_ASSERT(20 <= expected_args); // You can't define a default for an argument that doesn't exist.\n        #endif\n\n\n        //  Arguments with type matlab_object are optional in both input and output.\n        int num_optional_inputs = 0;\n        int num_optional_outputs = 0;\n        if (is_matlab_object<typename sig_traits<funct>::arg20_type>::value) if (is_input_type<typename sig_traits<funct>::arg20_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg19_type>::value) if (is_input_type<typename sig_traits<funct>::arg19_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg18_type>::value) if (is_input_type<typename sig_traits<funct>::arg18_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg17_type>::value) if (is_input_type<typename sig_traits<funct>::arg17_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg16_type>::value) if (is_input_type<typename sig_traits<funct>::arg16_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg15_type>::value) if (is_input_type<typename sig_traits<funct>::arg15_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg14_type>::value) if (is_input_type<typename sig_traits<funct>::arg14_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg13_type>::value) if (is_input_type<typename sig_traits<funct>::arg13_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg12_type>::value) if (is_input_type<typename sig_traits<funct>::arg12_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg11_type>::value) if (is_input_type<typename sig_traits<funct>::arg11_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg10_type>::value) if (is_input_type<typename sig_traits<funct>::arg10_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg9_type>::value) if (is_input_type<typename sig_traits<funct>::arg9_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg8_type>::value) if (is_input_type<typename sig_traits<funct>::arg8_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg7_type>::value) if (is_input_type<typename sig_traits<funct>::arg7_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg6_type>::value) if (is_input_type<typename sig_traits<funct>::arg6_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg5_type>::value) if (is_input_type<typename sig_traits<funct>::arg5_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg4_type>::value) if (is_input_type<typename sig_traits<funct>::arg4_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg3_type>::value) if (is_input_type<typename sig_traits<funct>::arg3_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg2_type>::value) if (is_input_type<typename sig_traits<funct>::arg2_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n        if (is_matlab_object<typename sig_traits<funct>::arg1_type>::value) if (is_input_type<typename sig_traits<funct>::arg1_type>::value) ++num_optional_inputs; else ++num_optional_outputs;\n\n\n        /* check for proper number of arguments */\n        if(nrhs > expected_nrhs || nrhs < expected_nrhs - defaulted_args - num_optional_inputs) \n        {\n            std::ostringstream sout;\n            sout << \"Expected between \" << expected_nrhs-defaulted_args - num_optional_inputs \n                << \" and \" << expected_nrhs << \" input arguments, got \" << nrhs << \".\";\n\n            mexErrMsgIdAndTxt(\"mex_function:nrhs\",\n                              escape_percent(sout).c_str());\n        }\n\n        if (nlhs > expected_nlhs)\n        {\n            std::ostringstream sout;\n            sout << \"Expected at most \" << expected_nlhs << \" output arguments, got \" << nlhs << \".\";\n\n            mexErrMsgIdAndTxt(\"mex_function:nlhs\",\n                              escape_percent(sout).c_str());\n        }\n\n        call_mex_function_helper<sig_traits<funct>::num_args> helper;\n        helper.callit(f, nlhs, plhs, nrhs, prhs);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class mex_streambuf : public std::streambuf\n    {\n\n    public:\n        mex_streambuf (\n        ) \n        {\n            buf.resize(1000);\n            setp(&buf[0], &buf[0] + buf.size()-2);\n\n            // make cout send data to mex_streambuf\n            oldbuf = std::cout.rdbuf(this);\n        }\n\n        ~mex_streambuf()\n        {\n            // put cout back to the way we found it before running our mex function.\n            std::cout.rdbuf(oldbuf);\n        }\n\n\n    protected:\n\n\n        int sync (\n        )\n        {\n            int num = static_cast<int>(pptr()-pbase());\n            if (num != 0)\n            {\n                check_for_matlab_ctrl_c();\n\n                buf[num] = 0; // null terminate the string\n                mexPrintf(\"%s\",&buf[0]);\n                mexEvalString(\"drawnow\"); // flush print to screen\n                pbump(-num);\n            }\n            return 0;\n        }\n\n        int_type overflow (\n            int_type c\n        )\n        {\n            if (c != EOF)\n            {\n                *pptr() = c;\n                pbump(1);\n            }\n            sync();\n            return c;\n        }\n\n    private:\n        std::vector<char> buf;\n        std::streambuf* oldbuf;\n\n    };\n\n    class mex_warn_streambuf : public std::streambuf\n    {\n\n    public:\n        mex_warn_streambuf (\n        ) \n        {\n            buf.resize(1000);\n            setp(&buf[0], &buf[0] + buf.size()-2);\n\n            // make cout send data to mex_warn_streambuf\n            oldbuf = std::cerr.rdbuf(this);\n        }\n\n        ~mex_warn_streambuf()\n        {\n            // put cerr back to the way we found it before running our mex function.\n            std::cerr.rdbuf(oldbuf);\n        }\n\n    protected:\n\n\n        int sync (\n        )\n        {\n            int num = static_cast<int>(pptr()-pbase());\n            if (num != 0)\n            {\n                check_for_matlab_ctrl_c();\n\n                buf[num] = 0; // null terminate the string\n                mexWarnMsgTxt(&buf[0]);\n                mexEvalString(\"drawnow\"); // flush print to screen\n                pbump(-num);\n            }\n            return 0;\n        }\n\n        int_type overflow (\n            int_type c\n        )\n        {\n            if (c != EOF)\n            {\n                *pptr() = c;\n                pbump(1);\n            }\n            sync();\n            return c;\n        }\n\n    private:\n        std::vector<char> buf;\n        std::streambuf* oldbuf;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void setup_input_args (\n        mxArray*& array,\n        const T& item,\n        int& nrhs\n    )\n    {\n        assign_to_matlab(array, item);\n        ++nrhs;\n    }\n\n    void setup_input_args (\n        mxArray*& array,\n        const function_handle& item,\n        int& nrhs\n    )\n    {\n        array = static_cast<mxArray*>(item.h);\n        ++nrhs;\n    }\n\n    template <typename T>\n    void setup_input_args (\n        mxArray*& array,\n        const output_decorator<T>& item,\n        int& nrhs\n    )\n    {\n    }\n\n    template <typename T>\n    void setup_output_args (\n        const std::string& function_name,\n        mxArray* array,\n        const T& item,\n        int& nrhs\n    )\n    {\n    }\n\n    template <typename T>\n    void setup_output_args (\n        const std::string& function_name,\n        mxArray* array,\n        const output_decorator<T>& item,\n        int& i\n    )\n    {\n        try\n        {\n            validate_and_populate_arg(i,array,const_cast<T&>(item.item));\n            ++i;\n        }\n        catch (invalid_args_exception& e)\n        {\n            throw dlib::error(\"Error occurred calling MATLAB function '\" + function_name + \"' from mex file. \\n\"\n                              \"The MATLAB function didn't return what we expected it to.  \\nIn particular, return\" + string(e.what()));\n        }\n    }\n\n    void call_matlab_for_real (\n        int nlhs,\n        mxArray* plhs[],\n        int nrhs,\n        mxArray* prhs[],\n        const std::string& function_name\n    )\n    {\n        int status = mexCallMATLAB(nlhs, plhs, nrhs, prhs, function_name.c_str());\n        if (status)\n        {\n            throw dlib::error(\"Error, an exception was thrown when we tried to call the MATLAB function '\" + function_name + \"'.\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    void call_matlab (\n        const std::string& function_name\n    ) \n    {\n        using namespace mex_binding;\n\n        call_matlab_for_real(0,NULL,0,NULL, function_name);\n    }\n\n    template <typename T1>\n    void free_callback_resources (\n        int nlhs,\n        mxArray* plhs[],\n        int nrhs,\n        mxArray* prhs[]\n    )\n    {\n        // free resources\n        for (int i = 0; i < nlhs; ++i)\n            mxDestroyArray(plhs[i]);\n\n        for (int i = 0; i < nrhs; ++i)\n        {\n            // don't call mxDestroyArray() on function handles (which should only ever be in prhs[0])\n            if (i == 0 && dlib::is_same_type<T1,function_handle>::value)\n                continue;\n            mxDestroyArray(prhs[i]);\n        }\n    }\n\n    template <\n        typename T1\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 1;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 2;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 3;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 4;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 5;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 6;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 7;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 8;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 9;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 10;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 11;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 12;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12,\n        typename T13\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12,\n        const T13& A13\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 13;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12,\n        typename T13,\n        typename T14\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12,\n        const T13& A13,\n        const T14& A14\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 14;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12,\n        typename T13,\n        typename T14,\n        typename T15\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12,\n        const T13& A13,\n        const T14& A14,\n        const T15& A15\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 15;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12,\n        typename T13,\n        typename T14,\n        typename T15,\n        typename T16\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12,\n        const T13& A13,\n        const T14& A14,\n        const T15& A15,\n        const T16& A16\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 16;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n        setup_input_args(prhs[nrhs], A16, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n        setup_output_args(function_name, plhs[i], A16, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, \n        typename T2,\n        typename T3,\n        typename T4,\n        typename T5,\n        typename T6,\n        typename T7,\n        typename T8,\n        typename T9,\n        typename T10,\n        typename T11,\n        typename T12,\n        typename T13,\n        typename T14,\n        typename T15,\n        typename T16,\n        typename T17\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1,\n        const T2& A2,\n        const T3& A3,\n        const T4& A4,\n        const T5& A5,\n        const T6& A6,\n        const T7& A7,\n        const T8& A8,\n        const T9& A9,\n        const T10& A10,\n        const T11& A11,\n        const T12& A12,\n        const T13& A13,\n        const T14& A14,\n        const T15& A15,\n        const T16& A16,\n        const T17& A17\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 17;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n        setup_input_args(prhs[nrhs], A16, nrhs);\n        setup_input_args(prhs[nrhs], A17, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n        setup_output_args(function_name, plhs[i], A16, i);\n        setup_output_args(function_name, plhs[i], A17, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, typename T2, typename T3, typename T4, typename T5, typename T6,\n        typename T7, typename T8, typename T9, typename T10, typename T11, typename T12,\n        typename T13, typename T14, typename T15, typename T16, typename T17, typename T18\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n        const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const\n        T12& A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const\n        T17& A17, const T18& A18\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 18;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n        setup_input_args(prhs[nrhs], A16, nrhs);\n        setup_input_args(prhs[nrhs], A17, nrhs);\n        setup_input_args(prhs[nrhs], A18, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n        setup_output_args(function_name, plhs[i], A16, i);\n        setup_output_args(function_name, plhs[i], A17, i);\n        setup_output_args(function_name, plhs[i], A18, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, typename T2, typename T3, typename T4, typename T5, typename T6,\n        typename T7, typename T8, typename T9, typename T10, typename T11, typename T12,\n        typename T13, typename T14, typename T15, typename T16, typename T17, typename T18,\n        typename T19\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n        const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const\n        T12& A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const\n        T17& A17, const T18& A18, const T19& A19\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 19;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n        setup_input_args(prhs[nrhs], A16, nrhs);\n        setup_input_args(prhs[nrhs], A17, nrhs);\n        setup_input_args(prhs[nrhs], A18, nrhs);\n        setup_input_args(prhs[nrhs], A19, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n        setup_output_args(function_name, plhs[i], A16, i);\n        setup_output_args(function_name, plhs[i], A17, i);\n        setup_output_args(function_name, plhs[i], A18, i);\n        setup_output_args(function_name, plhs[i], A19, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n    template <\n        typename T1, typename T2, typename T3, typename T4, typename T5, typename T6,\n        typename T7, typename T8, typename T9, typename T10, typename T11, typename T12,\n        typename T13, typename T14, typename T15, typename T16, typename T17, typename T18,\n        typename T19, typename T20\n        >\n    void call_matlab (\n        const std::string& function_name,\n        const T1& A1, const T2& A2, const T3& A3, const T4& A4, const T5& A5, const T6& A6,\n        const T7& A7, const T8& A8, const T9& A9, const T10& A10, const T11& A11, const\n        T12& A12, const T13& A13, const T14& A14, const T15& A15, const T16& A16, const\n        T17& A17, const T18& A18, const T19& A19, const T20& A20\n    ) \n    {\n        using namespace mex_binding;\n        const int num_args = 20;\n        mxArray* plhs[num_args] = {0};\n        mxArray* prhs[num_args] = {0};\n\n        int nrhs = 0;\n        setup_input_args(prhs[nrhs], A1, nrhs);\n        setup_input_args(prhs[nrhs], A2, nrhs);\n        setup_input_args(prhs[nrhs], A3, nrhs);\n        setup_input_args(prhs[nrhs], A4, nrhs);\n        setup_input_args(prhs[nrhs], A5, nrhs);\n        setup_input_args(prhs[nrhs], A6, nrhs);\n        setup_input_args(prhs[nrhs], A7, nrhs);\n        setup_input_args(prhs[nrhs], A8, nrhs);\n        setup_input_args(prhs[nrhs], A9, nrhs);\n        setup_input_args(prhs[nrhs], A10, nrhs);\n        setup_input_args(prhs[nrhs], A11, nrhs);\n        setup_input_args(prhs[nrhs], A12, nrhs);\n        setup_input_args(prhs[nrhs], A13, nrhs);\n        setup_input_args(prhs[nrhs], A14, nrhs);\n        setup_input_args(prhs[nrhs], A15, nrhs);\n        setup_input_args(prhs[nrhs], A16, nrhs);\n        setup_input_args(prhs[nrhs], A17, nrhs);\n        setup_input_args(prhs[nrhs], A18, nrhs);\n        setup_input_args(prhs[nrhs], A19, nrhs);\n        setup_input_args(prhs[nrhs], A20, nrhs);\n\n        const int nlhs = num_args - nrhs;\n        call_matlab_for_real(nlhs,plhs,nrhs,prhs, function_name);\n\n        int i = 0;\n        setup_output_args(function_name, plhs[i], A1, i);\n        setup_output_args(function_name, plhs[i], A2, i);\n        setup_output_args(function_name, plhs[i], A3, i);\n        setup_output_args(function_name, plhs[i], A4, i);\n        setup_output_args(function_name, plhs[i], A5, i);\n        setup_output_args(function_name, plhs[i], A6, i);\n        setup_output_args(function_name, plhs[i], A7, i);\n        setup_output_args(function_name, plhs[i], A8, i);\n        setup_output_args(function_name, plhs[i], A9, i);\n        setup_output_args(function_name, plhs[i], A10, i);\n        setup_output_args(function_name, plhs[i], A11, i);\n        setup_output_args(function_name, plhs[i], A12, i);\n        setup_output_args(function_name, plhs[i], A13, i);\n        setup_output_args(function_name, plhs[i], A14, i);\n        setup_output_args(function_name, plhs[i], A15, i);\n        setup_output_args(function_name, plhs[i], A16, i);\n        setup_output_args(function_name, plhs[i], A17, i);\n        setup_output_args(function_name, plhs[i], A18, i);\n        setup_output_args(function_name, plhs[i], A19, i);\n        setup_output_args(function_name, plhs[i], A20, i);\n\n        free_callback_resources<T1>(nlhs,plhs,nrhs,prhs);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    matlab_object::~matlab_object(\n    )\n    {\n        if (handle && should_free)\n        {\n            mxDestroyArray((mxArray*)handle);\n            handle = 0;\n        }\n    }\n\n    template <typename T> \n    matlab_object::\n    operator T(\n    ) const\n    {\n        T item;\n        get(item);\n        return item;\n    }\n\n    template <typename T> \n    void matlab_object::\n    get(\n        T& item\n    ) const \n    {\n        if (handle == 0)\n            throw dlib::invalid_args_exception(\"An attempt was made to access an empty matlab_object.\");\n\n        mex_binding::validate_and_populate_arg(arg_idx,(mxArray*)handle,item);\n    }\n\n    template <typename T> \n    matlab_object& matlab_object::\n    operator= (\n        const T& new_val\n    )\n    {\n        mxArray* item;\n        mex_binding::assign_to_matlab(item, new_val);\n        handle = item;\n        should_free = true;\n        return *this;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    matlab_struct::sub::operator T() const\n    {\n        T item;\n        get(item);\n        return item;\n    }\n\n    template <typename T>\n    void matlab_struct::sub::get(T& item) const\n    {\n        if (struct_handle == 0)\n            throw dlib::error(\"Attempt to access data in an empty struct.\");\n\n        mxArray* temp = mxGetFieldByNumber((const mxArray*)struct_handle, 0, field_idx);\n        if (temp == 0)\n            throw dlib::error(\"Attempt to access data in an empty struct.\");\n\n        try\n        {\n            mex_binding::validate_and_populate_arg(0,temp,item);\n        }\n        catch(mex_binding::invalid_args_exception& e)\n        {\n            std::ostringstream sout;\n            sout << \"Struct field '\" << mxGetFieldNameByNumber((const mxArray*)struct_handle, field_idx) << \"' can't be interpreted as the requested type.\"\n                << endl << e.what();\n            throw dlib::error(sout.str());\n        }\n    }\n\n    const matlab_struct::sub matlab_struct::\n    operator[] (const std::string& name) const\n    {\n        if (struct_handle == 0)\n            throw dlib::error(\"Struct does not have a field named '\" + name + \"'.\");\n\n        matlab_struct::sub temp;\n        temp.struct_handle = struct_handle;\n        temp.field_idx = mxGetFieldNumber((const mxArray*)struct_handle, name.c_str());\n        if (temp.field_idx == -1 )\n            throw dlib::error(\"Struct does not have a field named '\" + name + \"'.\");\n        return temp;\n    }\n\n    matlab_struct::sub matlab_struct::\n    operator[] (const std::string& name) \n    {\n        if (struct_handle == 0)\n        {\n            // We make a struct from scratch and mark that we will free it unless it gets\n            // written back to matlab by assign_to_matlab().\n            mwSize dims[1] = {1};\n            const char* name_str = name.c_str();\n            struct_handle = mxCreateStructArray(1, dims, 1, &name_str);\n            should_free = true;\n            if (struct_handle == 0)\n                throw dlib::error(\"Error creating struct from within mex function.\");\n        }\n\n\n        matlab_struct::sub temp;\n        temp.struct_handle = struct_handle;\n        if ((temp.field_idx=mxGetFieldNumber((mxArray*)struct_handle, name.c_str())) == -1)\n        {\n            if ((temp.field_idx=mxAddField((mxArray*)struct_handle, name.c_str())) == -1)\n            {\n                throw dlib::error(\"Unable to add field '\"+name + \"' to struct.\");\n            }\n        }\n        return temp;\n    }\n\n    const matlab_struct::sub matlab_struct::sub::\n    operator[] (const std::string& name) const\n    {\n        if (struct_handle == 0)\n            throw dlib::error(\"Struct does not have a field named '\" + name + \"'.\");\n\n        matlab_struct::sub temp;\n        temp.struct_handle = mxGetFieldByNumber((const mxArray*)struct_handle, 0, field_idx);\n        if (temp.struct_handle == 0)\n            throw dlib::error(\"Failure to get struct field while calling mxGetFieldByNumber()\");\n\n        if (!mxIsStruct((const mxArray*)temp.struct_handle))\n            throw dlib::error(\"Struct sub-field element '\"+name+\"' is not another struct.\");\n\n        temp.field_idx = mxGetFieldNumber((const mxArray*)temp.struct_handle, name.c_str());\n        if (temp.field_idx == -1 )\n            throw dlib::error(\"Struct does not have a field named '\" + name + \"'.\");\n        return temp;\n    }\n\n    matlab_struct::sub matlab_struct::sub::\n    operator[] (const std::string& name) \n    {\n        if (struct_handle == 0)\n            throw dlib::error(\"Struct does not have a field named '\" + name + \"'.\");\n\n        matlab_struct::sub temp;\n        temp.struct_handle = mxGetFieldByNumber((const mxArray*)struct_handle, 0, field_idx);\n        // We are replacing this field with a struct if it exists and isn't already a struct\n        if (temp.struct_handle != 0 && !mxIsStruct((const mxArray*)temp.struct_handle))\n        {\n            mxDestroyArray((mxArray*)temp.struct_handle);\n            temp.struct_handle = 0;\n        }\n        if (temp.struct_handle == 0)\n        {\n            mwSize dims[1] = {1};\n            temp.struct_handle = mxCreateStructArray(1, dims, 0, 0);\n            if (temp.struct_handle == 0)\n                throw dlib::error(\"Failure to create new sub-struct field\");\n            mxSetFieldByNumber((mxArray*)struct_handle, 0, field_idx, (mxArray*)temp.struct_handle);\n        }\n\n\n        if ((temp.field_idx=mxGetFieldNumber((mxArray*)temp.struct_handle, name.c_str())) == -1)\n        {\n            if ((temp.field_idx=mxAddField((mxArray*)temp.struct_handle, name.c_str())) == -1)\n            {\n                throw dlib::error(\"Unable to add field '\"+name + \"' to struct.\");\n            }\n        }\n        return temp;\n    }\n\n    bool matlab_struct::has_field (\n        const std::string& name\n    ) const\n    {\n        if (struct_handle == 0)\n            return false;\n        return mxGetFieldNumber((const mxArray*)struct_handle, name.c_str()) != -1;\n    }\n\n    bool matlab_struct::sub::has_field (\n        const std::string& name\n    ) const\n    {\n        if (struct_handle == 0)\n            return false;\n        mxArray* temp = mxGetFieldByNumber((const mxArray*)struct_handle, 0, field_idx);\n        if (temp == 0 || !mxIsStruct(temp))\n            return false;\n        return mxGetFieldNumber(temp, name.c_str()) != -1;\n    }\n\n    template <typename T>\n    matlab_struct::sub& matlab_struct::sub::operator= (\n        const T& new_val \n    )\n    {\n        // Delete anything in the field before we overwrite it\n        mxArray* item = mxGetFieldByNumber((mxArray*)struct_handle, 0, field_idx);\n        if (item != 0)\n        {\n            mxDestroyArray((mxArray*)item);\n            item = 0;\n        }\n\n        // Now set the field\n        mex_binding::assign_to_matlab(item, new_val);\n        mxSetFieldByNumber((mxArray*)struct_handle, 0, field_idx, item);\n\n        return *this;\n    }\n\n    matlab_struct::\n    ~matlab_struct (\n    )\n    {\n        if (struct_handle && should_free)\n        {\n            mxDestroyArray((mxArray*)struct_handle);\n            struct_handle = 0;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    void call_matlab (\n        const function_handle& funct \n    )\n    {\n        call_matlab(\"feval\", funct);\n    }\n\n    extern \"C\" bool utIsInterruptPending();\n    void check_for_matlab_ctrl_c(\n    )\n    {\n        if (utIsInterruptPending())\n            throw mex_binding::user_hit_ctrl_c();\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n#ifdef MEX_CLASS_NAME\ntemplate <typename T, typename mfp_type>\nclass mex_class_wrapper\n{\npublic:\n    mex_class_wrapper(T& obj_, mfp_type mfp_) : obj(obj_), mfp(mfp_) {}\n\n    template <typename... Args>\n    void operator()(Args&&... args) const\n    {\n        (obj.*mfp)(std::forward<Args>(args)...);\n    }\n\n    mfp_type mfp;\n    T& obj;\n};\n\ntemplate <typename T, typename mfp_type>\nmex_class_wrapper<T,mfp_type> wrap_mex_class(T& obj, mfp_type mfp) { return mex_class_wrapper<T,mfp_type>(obj, mfp); }\n\nnamespace dlib\n{\n    template <typename T, typename mfp_type>\n    struct sig_traits<mex_class_wrapper<T,mfp_type>>\n    : public sig_traits<mfp_type>\n    {};\n\n    template <size_t i, typename T, bool is_good = i < std::tuple_size<T>::value>\n    struct tuple_element_default_void\n    {\n        typedef void type;\n    };\n\n    template <size_t i, typename T>\n    struct tuple_element_default_void<i,T,true>\n    {\n        typedef typename std::tuple_element<i,T>::type type;\n    };\n\n    template <typename class_type, typename return_type, typename... Args>\n    struct sig_traits<return_type(class_type::*)(Args...) >\n    {\n        enum { num_args = sizeof...(Args) };\n\n        typedef return_type result_type;\n\n        template <size_t i>\n        struct arg\n        {\n            typedef typename tuple_element_default_void<i-1, std::tuple<Args...>>::type type;\n        };\n\n        // These are here because that's how things are defined in sig_traits (since it is\n        // older than C++11, along with most of the other code in this file)\n        typedef typename arg<1>::type arg1_type;\n        typedef typename arg<2>::type arg2_type;\n        typedef typename arg<3>::type arg3_type;\n        typedef typename arg<4>::type arg4_type;\n        typedef typename arg<5>::type arg5_type;\n        typedef typename arg<6>::type arg6_type;\n        typedef typename arg<7>::type arg7_type;\n        typedef typename arg<8>::type arg8_type;\n        typedef typename arg<9>::type arg9_type;\n        typedef typename arg<10>::type arg10_type;\n        typedef typename arg<11>::type arg11_type;\n        typedef typename arg<12>::type arg12_type;\n        typedef typename arg<13>::type arg13_type;\n        typedef typename arg<14>::type arg14_type;\n        typedef typename arg<15>::type arg15_type;\n        typedef typename arg<16>::type arg16_type;\n        typedef typename arg<17>::type arg17_type;\n        typedef typename arg<18>::type arg18_type;\n        typedef typename arg<19>::type arg19_type;\n        typedef typename arg<20>::type arg20_type;\n    };\n\n    template <typename class_type, typename return_type, typename... Args>\n    struct sig_traits<return_type(class_type::*)(Args...) const>\n    {\n        enum { num_args = sizeof...(Args) };\n\n        typedef return_type result_type;\n\n        template <size_t i>\n        struct arg\n        {\n            typedef typename tuple_element_default_void<i-1, std::tuple<Args...>>::type type;\n        };\n\n        // These are here because that's how things are defined in sig_traits (since it is\n        // older than C++11, along with most of the other code in this file)\n        typedef typename arg<1>::type arg1_type;\n        typedef typename arg<2>::type arg2_type;\n        typedef typename arg<3>::type arg3_type;\n        typedef typename arg<4>::type arg4_type;\n        typedef typename arg<5>::type arg5_type;\n        typedef typename arg<6>::type arg6_type;\n        typedef typename arg<7>::type arg7_type;\n        typedef typename arg<8>::type arg8_type;\n        typedef typename arg<9>::type arg9_type;\n        typedef typename arg<10>::type arg10_type;\n        typedef typename arg<11>::type arg11_type;\n        typedef typename arg<12>::type arg12_type;\n        typedef typename arg<13>::type arg13_type;\n        typedef typename arg<14>::type arg14_type;\n        typedef typename arg<15>::type arg15_type;\n        typedef typename arg<16>::type arg16_type;\n        typedef typename arg<17>::type arg17_type;\n        typedef typename arg<18>::type arg18_type;\n        typedef typename arg<19>::type arg19_type;\n        typedef typename arg<20>::type arg20_type;\n    };\n}\n\n// ----------------------------------------------------------------------------------------\n\n\ntemplate <size_t I>\nstruct visit_impl\n{\n    template <typename T, typename F>\n    static void visit(T& tup, size_t idx, F fun)\n    {\n        if (idx == I - 1) fun(std::get<I - 1>(tup));\n        else visit_impl<I - 1>::visit(tup, idx, fun);\n    }\n};\n\ntemplate <>\nstruct visit_impl<0>\n{\n    template <typename T, typename F>\n    static void visit(T& tup, size_t idx, F fun) { DLIB_CASSERT(false,\"this should never happen\"); }\n};\n\ntemplate <typename F, typename... Ts>\nvoid visit_at(std::tuple<Ts...> const& tup, size_t idx, F fun)\n{\n    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);\n}\n\ntemplate <typename F, typename... Ts>\nvoid visit_at(std::tuple<Ts...>& tup, size_t idx, F fun)\n{\n    visit_impl<sizeof...(Ts)>::visit(tup, idx, fun);\n}\n\nclass mex_class_dispatch\n{\npublic:\n    mex_class_dispatch(\n        MEX_CLASS_NAME* ptr_,\n        int nlhs_, \n        mxArray** plhs_,\n        int nrhs_, \n        const mxArray** prhs_\n    ) : \n        ptr(ptr_),\n        nlhs(nlhs_),\n        plhs(plhs_),\n        nrhs(nrhs_),\n        prhs(prhs_)\n    {}\n\n    template <typename funct>\n    void operator() (const funct& mfp)\n    {\n        mex_binding::call_mex_function(wrap_mex_class(*ptr,mfp), nlhs, plhs, nrhs, prhs);\n    }\n\nprivate:\n    MEX_CLASS_NAME* ptr;\n    int nlhs; \n    mxArray** plhs;\n    int nrhs; \n    const mxArray** prhs;\n};\n\nclass class_factory_type : dlib::noncopyable\n{\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            This is a container class for all the MEX_CLASS_NAME objects we create.  It allows\n            us to track what we have created and make sure the MATLAB user doesn't do any\n            double frees or use any stale pointers.   \n\n            It also helps us deal with the problem that would otherwise arise when a mex file\n            is unloaded from MATLAB when there are still active pointers to MEX_CLASS_NAME objects\n            in MATLAB, since we will be able to detect stale pointers.\n    !*/\npublic:\n\n    class_factory_type()\n    {\n        seed = (uint64)time(0);\n    }\n\n    ~class_factory_type()\n    {\n        for (auto i : object_table)\n            delete i.second;\n    }\n\n    template <typename ...T>\n    uint64 create(T&& ...args)\n    {\n        MEX_CLASS_NAME* item = new MEX_CLASS_NAME(std::forward<T>(args)...);\n        uint64 id = (uint64)item;\n        // Now generate a unique id that incorporates our seed value. The point of doing\n        // this is to avoid any chance that a mex file will get unloaded and then reloaded\n        // and start constructing objects with the same addresses, while old stale objects\n        // at those addresses are still stored in matlab, which would then call into the\n        // mex file and make things go crazy.  So here we try to generate ID numbers that\n        // are globally unique.\n        uint64 i = 0;\n        id = murmur_hash3_128bit_3(id, seed, ++i).first;\n        // very unlikely but make sure there aren't any hash collisions.\n        while(object_table.count(id) != 0)\n            id = murmur_hash3_128bit_3(id, seed, ++i).first;\n\n        object_table[id] = item;\n        return id;\n    }\n\n    void free(uint64 item)\n    {\n        if (object_table.count(item) == 0)\n        {\n            throw dlib::error(\"An attempt to deallocate a mex class object with an invalid pointer was detected.\");\n        }\n\n        delete object_table[item];\n        object_table.erase(item);\n    }\n\n    MEX_CLASS_NAME* access(uint64 item) // convert numeric ID to pointer to object that can be used.\n    {\n        if (object_table.count(item) == 0)\n        {\n            throw dlib::error(\"An attempt to access a mex class object with an invalid pointer was detected.\");\n        }\n\n        return object_table[item];\n    }\n\nprivate:\n\n    std::map<uint64, MEX_CLASS_NAME*> object_table;\n    uint64 seed;\n} class_factory;\n\n// ----------------------------------------------------------------------------------------\n\n// Make a FOREACH macro\n#define FE_1(WHAT, X) WHAT(X) \n#define FE_2(WHAT, X, ...) WHAT(X),FE_1(WHAT, __VA_ARGS__)\n#define FE_3(WHAT, X, ...) WHAT(X),FE_2(WHAT, __VA_ARGS__)\n#define FE_4(WHAT, X, ...) WHAT(X),FE_3(WHAT, __VA_ARGS__)\n#define FE_5(WHAT, X, ...) WHAT(X),FE_4(WHAT, __VA_ARGS__)\n#define FE_6(WHAT, X, ...) WHAT(X),FE_5(WHAT, __VA_ARGS__)\n#define FE_7(WHAT, X, ...) WHAT(X),FE_6(WHAT, __VA_ARGS__)\n#define FE_8(WHAT, X, ...) WHAT(X),FE_7(WHAT, __VA_ARGS__)\n#define FE_9(WHAT, X, ...) WHAT(X),FE_8(WHAT, __VA_ARGS__)\n#define FE_10(WHAT, X, ...) WHAT(X),FE_9(WHAT, __VA_ARGS__)\n#define FE_11(WHAT, X, ...) WHAT(X),FE_10(WHAT, __VA_ARGS__)\n#define FE_12(WHAT, X, ...) WHAT(X),FE_11(WHAT, __VA_ARGS__)\n#define FE_13(WHAT, X, ...) WHAT(X),FE_12(WHAT, __VA_ARGS__)\n#define FE_14(WHAT, X, ...) WHAT(X),FE_13(WHAT, __VA_ARGS__)\n#define FE_15(WHAT, X, ...) WHAT(X),FE_14(WHAT, __VA_ARGS__)\n#define FE_16(WHAT, X, ...) WHAT(X),FE_15(WHAT, __VA_ARGS__)\n#define FE_17(WHAT, X, ...) WHAT(X),FE_16(WHAT, __VA_ARGS__)\n#define FE_18(WHAT, X, ...) WHAT(X),FE_17(WHAT, __VA_ARGS__)\n#define FE_19(WHAT, X, ...) WHAT(X),FE_18(WHAT, __VA_ARGS__)\n#define FE_20(WHAT, X, ...) WHAT(X),FE_19(WHAT, __VA_ARGS__)\n//... repeat as needed\n#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME \n#define FOR_EACH(action,...) GET_MACRO(__VA_ARGS__,FE_20,FE_19,FE_18,FE_17,FE_16,FE_15,FE_14,FE_13,FE_12,FE_11,FE_10,FE_9,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)\n#define MEX_CLASS_ANNOTATE(x) &MEX_CLASS_NAME::x \n\n// Now make a tuple containing all the member function pointers to our MEX_CLASS_NAME\nauto mex_class_methods = std::make_tuple(FOR_EACH(MEX_CLASS_ANNOTATE, MEX_CLASS_METHODS));\n\n\n#endif // MEX_CLASS_NAME\n\n// ----------------------------------------------------------------------------------------\n\nbool is_string(const mxArray* arr, const char* str)\n{\n    if (mxIsChar(arr))\n    {\n        char ch[20];\n        DLIB_CASSERT(mxGetString(arr, ch, sizeof(ch))==0, \"Unable to retrieve string\");\n        ch[sizeof(ch)-1] = 0;// ensure NULL termination regardless of what MATLAB does.\n        return strcmp(str,ch)==0;\n    }\n    return false;\n}\n\n// ----------------------------------------------------------------------------------------\n\n/* The gateway function called by MATLAB*/\nvoid mexFunction( int nlhs, mxArray *plhs[],\n                  int nrhs, const mxArray *prhs[])\n{\n    // Only remap cout and cerr if we aren't using octave since octave already does this.\n#if !defined(OCTAVE_IMPORT) && !defined(OCTAVE_API)\n    // make it so cout prints to mexPrintf()\n    mex_binding::mex_streambuf sb;\n    // make it so cerr prints to mexWarnMsgTxt()\n    mex_binding::mex_warn_streambuf wsb;\n#endif\n\n    try\n    {\n#ifdef MEX_CLASS_NAME\n        if (nrhs == 0)\n        {\n            #define DEF2STR(x) DEF2STR2((x))\n            #define DEF2STR2(x) #x\n\n            string classname = trim(string(DEF2STR(MEX_CLASS_NAME)), \" \\t()\");\n            std::vector<string> methods = split(trim(string(DEF2STR(MEX_CLASS_METHODS)), \" \\t()\"), \" \\t,\");\n\n            string mex_filename = trim(string(DEF2STR(MEX_FILENAME)),\" \\t()\");\n            bool has_load_obj = false;\n            size_t load_obj_idx = 0;\n\n            cout << \"classdef \" << classname << \" < handle\\n\"\n                 << \"    properties (Access = private)\\n\"\n                 << \"        cpp_ptr\\n\"\n                 << \"    end\\n\"\n                 << \"\\n\"\n                 << \"    methods\\n\"\n                 << \"        function this = \"<<classname<<\"()\\n\"\n                 << \"            this.cpp_ptr = \"<<mex_filename<<\"('construct');\\n\"\n                 << \"        end\\n\"\n                 << \"\\n\"\n                 << \"        function copied_obj = clone(this)\\n\"\n                 << \"            %Returns a new independent object that is a copy of this.\\n\"\n                 << \"            copied_obj = \"<<classname<<\"();\\n\"\n                 << \"            copied_obj.cpp_ptr = \"<<mex_filename<<\"(this.cpp_ptr,'clone');\\n\"\n                 << \"        end\\n\"\n                 << \"\\n\";\n            for (size_t i = 0; i < methods.size(); ++i)\n            {\n                if (methods[i] == \"load_obj\")\n                {\n                    has_load_obj = true;\n                    load_obj_idx = i;\n                }\n                else\n                {\n                    cout << \"        function varargout = \"<<methods[i]<<\"(this, varargin) \\n\"\n                        << \"            [varargout{1:nargout}] = \"<<mex_filename<<\"(this.cpp_ptr, \"<<i+1<<\", varargin{:}); \\n\"\n                        << \"        end \\n\\n\";\n                }\n            }\n            cout << \"    end\\n\\n\";\n\n            cout << \"    methods(Access=private) \\n\"\n                << \"        function delete(this) \\n\"\n                << \"            \"<<mex_filename<<\"(this.cpp_ptr); \\n\"\n                << \"        end         \\n\";\n            if (has_load_obj)\n            {\n                cout << \"        function varargout = load_obj(this, varargin) \\n\"\n                    << \"            [varargout{1:nargout}] = \"<<mex_filename<<\"(this.cpp_ptr, \"<<load_obj_idx+1<<\", varargin{:}); \\n\"\n                    << \"        end \\n\";\n            }\n            cout << \"    end \\n\\n\";\n\n            if (has_load_obj)\n            {\n                cout << \"    methods(Static) \\n\"\n                    << \"        function this = loadobj(in) \\n\"\n                    << \"            this = \"<<classname<<\"(); \\n\"\n                    << \"            this.load_obj(in); \\n\"\n                    << \"        end          \\n\"\n                    << \"    end \\n\";\n            }\n            cout << \"end \\n\";\n        }\n        else if (nrhs == 1) \n        {\n            // this is a constructor call\n            if (is_string(prhs[0],\"construct\"))\n            {\n                DLIB_CASSERT(nlhs == 1, \"If you want to construct a new object then you must assign the pointer to something.\");\n                plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);\n                uint64* ptr_int = (uint64*)mxGetData(plhs[0]);\n                *ptr_int = class_factory.create();\n            }\n            else // destructor call\n            {\n                DLIB_CASSERT(mxIsUint64(prhs[0]) && mxGetNumberOfElements(prhs[0])==1, \"When calling a class destructor the first argument must be a pointer (a UINT64 in matlab)\");\n                const uint64 ptr_int = *((uint64*)mxGetData(prhs[0]));\n                class_factory.free(ptr_int);\n            }\n        }\n        else // a regular function call\n        {\n            DLIB_CASSERT(mxIsUint64(prhs[0]) && mxGetNumberOfElements(prhs[0])==1, \"When calling a class member function the first argument must be a pointer (a UINT64 in matlab)\");\n            if (is_string(prhs[1], \"clone\"))\n            {\n                DLIB_CASSERT(nlhs == 1, \"If you want to construct a new object then you must assign the pointer to something.\");\n                const uint64 ptr_int = *((uint64*)mxGetData(prhs[0]));\n\n                MEX_CLASS_NAME* ptr = class_factory.access(ptr_int);\n\n                plhs[0] = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);\n                uint64* ptr_int2 = (uint64*)mxGetData(plhs[0]);\n                // copy construct a new object\n                *ptr_int2 = class_factory.create(*ptr);\n            }\n            else\n            {\n                DLIB_CASSERT(mxIsDouble(prhs[1]) && mxGetNumberOfElements(prhs[1])==1, \"When calling a class member function the second argument must be a number indicating which member function\");\n                const uint64 ptr_int = *((uint64*)mxGetData(prhs[0]));\n                const int funct_idx = *(mxGetPr(prhs[1]));\n\n                auto num_registered_functions = std::tuple_size<decltype(mex_class_methods)>::value;\n                DLIB_CASSERT(1 <= funct_idx && funct_idx <= num_registered_functions, \"Invalid function index provided.\");\n\n                MEX_CLASS_NAME* ptr = class_factory.access(ptr_int);\n\n                // we used the first two arguments to decide what function to call.  So adjust nrhs\n                // and prhs so the member function never sees them.\n                mex_class_dispatch dispatch(ptr, nlhs, plhs, nrhs-2, prhs+2);\n                // now invoke the member function,  subtract 1 to convert to 0 indexing.\n                visit_at(mex_class_methods, funct_idx-1, dispatch);\n            }\n        }\n#else\n        mex_binding::call_mex_function(mex_function, nlhs, plhs, nrhs, prhs);\n#endif\n    }\n    catch (mex_binding::invalid_args_exception& e)\n    {\n        mexErrMsgIdAndTxt(\"mex_function:validate_and_populate_arg\",\n                            mex_binding::escape_percent(e.what()).c_str());\n    }\n    catch (mex_binding::user_hit_ctrl_c& )\n    {\n        // do nothing, just return to matlab\n    }\n    catch (std::exception& e)\n    {\n        mexErrMsgIdAndTxt(\"mex_function:error\",\n                            mex_binding::escape_percent(e.what()).c_str());\n    }\n\n    cout << flush;\n    cerr << flush;\n}\n\n// ----------------------------------------------------------------------------------------\n\n"
  },
  {
    "path": "dlib/matlab/sig_traits.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SiG_TRAITS_Hh_\n#define DLIB_SiG_TRAITS_Hh_\n\nnamespace dlib\n{\n\n    template <typename T>\n    struct sig_traits {};\n\n    template <\n        typename T\n        >\n    struct sig_traits<T ()> \n    { \n        typedef T result_type; \n        typedef void arg1_type; \n        typedef void arg2_type; \n        typedef void arg3_type; \n        typedef void arg4_type; \n        typedef void arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 0;\n    };\n\n    template <\n        typename T,\n        typename A1\n        >\n    struct sig_traits<T (A1)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef void arg2_type; \n        typedef void arg3_type; \n        typedef void arg4_type; \n        typedef void arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 1;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2\n        >\n    struct sig_traits<T (A1,A2)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef void arg3_type; \n        typedef void arg4_type; \n        typedef void arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 2;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3\n        >\n    struct sig_traits<T (A1,A2,A3)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef void arg4_type; \n        typedef void arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 3;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4\n        >\n    struct sig_traits<T (A1,A2,A3,A4)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef void arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 4;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef void arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 5;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef void arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 6;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef void arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 7;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef void arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 8;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef void arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 9;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef void arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 10;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef void arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 11;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef void arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 12;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef void arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 13;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef void arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 14;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef void arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 15;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15,\n        typename A16\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef A16 arg16_type; \n        typedef void arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 16;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15,\n        typename A16,\n        typename A17\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef A16 arg16_type; \n        typedef A17 arg17_type; \n        typedef void arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 17;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15,\n        typename A16,\n        typename A17,\n        typename A18\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef A16 arg16_type; \n        typedef A17 arg17_type; \n        typedef A18 arg18_type; \n        typedef void arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 18;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15,\n        typename A16,\n        typename A17,\n        typename A18,\n        typename A19\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef A16 arg16_type; \n        typedef A17 arg17_type; \n        typedef A18 arg18_type; \n        typedef A19 arg19_type; \n        typedef void arg20_type; \n\n        const static unsigned long num_args = 19;\n    };\n\n    template <\n        typename T,\n        typename A1, typename A2, typename A3,\n        typename A4, typename A5, typename A6,\n        typename A7, typename A8, typename A9,\n        typename A10,\n        typename A11,\n        typename A12,\n        typename A13,\n        typename A14,\n        typename A15,\n        typename A16,\n        typename A17,\n        typename A18,\n        typename A19,\n        typename A20\n        >\n    struct sig_traits<T (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14,A15,A16,A17,A18,A19,A20)> \n    { \n        typedef T result_type; \n        typedef A1 arg1_type; \n        typedef A2 arg2_type; \n        typedef A3 arg3_type; \n        typedef A4 arg4_type; \n        typedef A5 arg5_type; \n        typedef A6 arg6_type; \n        typedef A7 arg7_type; \n        typedef A8 arg8_type; \n        typedef A9 arg9_type; \n        typedef A10 arg10_type; \n        typedef A11 arg11_type; \n        typedef A12 arg12_type; \n        typedef A13 arg13_type; \n        typedef A14 arg14_type; \n        typedef A15 arg15_type; \n        typedef A16 arg16_type; \n        typedef A17 arg17_type; \n        typedef A18 arg18_type; \n        typedef A19 arg19_type; \n        typedef A20 arg20_type; \n\n        const static unsigned long num_args = 20;\n    };\n\n}\n\n#endif // DLIB_AnY_FUNCTION_Hh_\n"
  },
  {
    "path": "dlib/matlab/subprocess_stream.cpp",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#include \"subprocess_stream.h\"\n\n#include <sstream>\n#include <utility>\n#include <iostream>\n#include <cstdio>\n#include <fcntl.h>\n#include <signal.h>\n#include <sys/wait.h>\n#include <sys/select.h>\n#include \"call_matlab.h\"\n\nusing namespace std;\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void make_fd_non_blocking(int fd)\n    {\n        int flags = fcntl(fd, F_GETFL, 0);\n        fcntl(fd, F_SETFL, flags | O_NONBLOCK);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    // Block until fd is ready to read,  while also echoing whatever is in fd_printf to\n    // cout.\n    int read_echoing_select(int fd, int fd_printf)\n    {\n        // run until fd has data ready\n        while(fd_printf >= 0)\n        {\n            fd_set rfds;\n            int retval;\n\n            while(true)\n            {\n                FD_ZERO(&rfds);\n                FD_SET(fd, &rfds);\n                FD_SET(fd_printf, &rfds);\n\n                // select times out every second just so we can check for matlab ctrl+c.\n                struct timeval tv;\n                tv.tv_sec = 1;\n                tv.tv_usec = 0;\n\n                try{check_for_matlab_ctrl_c();} catch(...) { return 1; }\n                retval = select(std::max(fd,fd_printf)+1, &rfds, NULL, NULL, &tv);\n                try{check_for_matlab_ctrl_c();} catch(...) { return 1; }\n                if (retval == 0) // keep going if it was just a timeout.\n                    continue;\n                else if (retval == -1 && errno == EINTR)\n                    continue;\n\n                break;\n            }\n\n            if (retval == -1)\n            {\n                return 1;\n            }\n            else \n            {\n                if (FD_ISSET(fd,&rfds))\n                {\n                    return 0;\n                }\n                else\n                {\n                    char buf[1024];\n                    int num = read(fd_printf,buf, sizeof(buf)-1);\n                    if (num == -1)\n                        return 1;\n                    if (num > 0)\n                    {\n                        buf[num] = 0;\n                        cout << buf << flush;\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n    int write_echoing_select(int fd, int fd_printf)\n    {\n        // run until fd has data ready\n        while(fd_printf >= 0)\n        {\n            fd_set rfds, wfds;\n            int retval;\n            while(true)\n            {\n                FD_ZERO(&rfds);\n                FD_ZERO(&wfds);\n                FD_SET(fd, &wfds);\n                FD_SET(fd_printf, &rfds);\n\n                // select times out every second just so we can check for matlab ctrl+c.\n                struct timeval tv;\n                tv.tv_sec = 1;\n                tv.tv_usec = 0;\n\n                try{check_for_matlab_ctrl_c();} catch(...) { return 1; }\n                retval = select(std::max(fd,fd_printf)+1, &rfds, &wfds, NULL, &tv);\n                try{check_for_matlab_ctrl_c();} catch(...) { return 1; }\n                if (retval == 0) // keep going if it was just a timeout.\n                    continue;\n                else if (retval == -1 && errno == EINTR)\n                    continue;\n\n                break;\n            }\n\n            if (retval == -1)\n            {\n                return 1;\n            }\n            else \n            {\n                if (FD_ISSET(fd,&wfds))\n                {\n                    return 0;\n                }\n                else\n                {\n                    char buf[1024];\n                    int num = read(fd_printf,buf, sizeof(buf)-1);\n                    if (num == -1)\n                        return 1;\n                    if (num > 0)\n                    {\n                        buf[num] = 0;\n                        cout << buf << flush;\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class filestreambuf : public std::streambuf\n    {\n        /*!\n                    INITIAL VALUE\n                        - fd == the file descriptor we read from.\n                        - in_buffer == an array of in_buffer_size bytes\n                        - out_buffer == an array of out_buffer_size bytes\n\n                    CONVENTION\n                        - in_buffer == the input buffer used by this streambuf\n                        - out_buffer == the output buffer used by this streambuf\n                        - max_putback == the maximum number of chars to have in the put back buffer.\n        !*/\n\n    public:\n\n        filestreambuf (\n            int fd_,\n            int fd_printf_\n        ) :\n            fd(fd_),\n            fd_printf(fd_printf_),\n            out_buffer(0),\n            in_buffer(0)\n        {\n            init();\n        }\n\n        virtual ~filestreambuf (\n        )\n        {\n            sync();\n            delete [] out_buffer;\n            delete [] in_buffer;\n        }\n\n        int sync (\n        )\n        {\n            if (flush_out_buffer() == EOF)\n            {\n                // an error occurred\n                return -1;\n            }\n            return 0;\n        }\n    protected:\n\n        void init (\n        )\n        {\n            try\n            {\n                out_buffer = new char[out_buffer_size];\n                in_buffer = new char[in_buffer_size];\n            }\n            catch (...)\n            {\n                if (out_buffer) delete [] out_buffer;\n                throw;\n            }\n            setp(out_buffer, out_buffer + (out_buffer_size-1));\n            setg(in_buffer+max_putback, \n                in_buffer+max_putback, \n                in_buffer+max_putback);\n        }\n\n        int flush_out_buffer (\n        )\n        {\n            int num = static_cast<int>(pptr()-pbase());\n            const int num_written = num;\n            char* buf = out_buffer;\n            while(num != 0)\n            {\n                if(write_echoing_select(fd, fd_printf))\n                    return EOF;\n                int status = write(fd,buf,num);\n                if (status < 0)\n                {\n                    // the write was not successful so return EOF \n                    return EOF;\n                } \n                num -= status;\n                buf += status;\n            }\n            pbump(-num_written);\n            return num_written;\n        }\n\n        // output functions\n        int_type overflow (\n            int_type c\n        )\n        {\n            if (c != EOF)\n            {\n                *pptr() = c;\n                pbump(1);\n            }\n            if (flush_out_buffer() == EOF)\n            {\n                // an error occurred\n                return EOF;\n            }\n            return c;\n        }\n\n\n        std::streamsize xsputn (\n            const char* s,\n            std::streamsize num\n        )\n        {\n            // Add a sanity check here \n            DLIB_ASSERT(num >= 0,\n                \"\\tstd::streamsize filestreambuf::xsputn\"\n                << \"\\n\\tThe number of bytes to write can't be negative\"\n                << \"\\n\\tnum:  \" << num \n                << \"\\n\\tthis: \" << this\n            );\n\n            std::streamsize space_left = static_cast<std::streamsize>(epptr()-pptr());\n            if (num <= space_left)\n            {\n                std::memcpy(pptr(),s,static_cast<size_t>(num));\n                pbump(static_cast<int>(num));\n                return num;\n            }\n            else\n            {\n                std::memcpy(pptr(),s,static_cast<size_t>(space_left));\n                s += space_left;\n                pbump(space_left);\n                std::streamsize num_left = num - space_left;\n\n                if (flush_out_buffer() == EOF)\n                {\n                    // the write was not successful so return that 0 bytes were written\n                    return 0;\n                }\n\n                if (num_left < out_buffer_size)\n                {\n                    std::memcpy(pptr(),s,static_cast<size_t>(num_left));\n                    pbump(num_left);\n                    return num;\n                }\n                else\n                {\n                    while(num_left != 0)\n                    {\n                        if(write_echoing_select(fd, fd_printf))\n                            return EOF;\n                        int status = write(fd,s,num_left);\n                        if (status < 0)\n                        {\n                            // the write was not successful so return that 0 bytes were written\n                            return 0;\n                        } \n                        num_left -= status;\n                        s += status;\n                    }\n                    return num;\n                }\n            }\n        }\n\n        // input functions\n        int_type underflow( \n        )\n        {\n            if (gptr() < egptr())\n            {\n                return static_cast<unsigned char>(*gptr());\n            }\n\n            int num_put_back = static_cast<int>(gptr() - eback());\n            if (num_put_back > max_putback)\n            {\n                num_put_back = max_putback;\n            }\n\n            // copy the putback characters into the putback end of the in_buffer\n            std::memmove(in_buffer+(max_putback-num_put_back), gptr()-num_put_back, num_put_back);\n\n\n            if (read_echoing_select(fd, fd_printf))\n                return EOF;\n            int num = read(fd,in_buffer+max_putback, in_buffer_size-max_putback);\n            if (num <= 0)\n            {\n                // an error occurred or the connection is over which is EOF\n                return EOF;\n            }\n\n            // reset in_buffer pointers\n            setg (in_buffer+(max_putback-num_put_back),\n                in_buffer+max_putback,\n                in_buffer+max_putback+num);\n\n            return static_cast<unsigned char>(*gptr());\n        }\n\n        std::streamsize xsgetn (\n            char_type* s, \n            std::streamsize n\n        )\n        { \n            std::streamsize temp = n;\n            while (n > 0)\n            {\n                int num = static_cast<int>(egptr() - gptr());\n                if (num >= n)\n                {\n                    // copy data from our buffer \n                    std::memcpy(s, gptr(), static_cast<size_t>(n));\n                    gbump(static_cast<int>(n));\n                    return temp;\n                }\n\n                // read more data into our buffer  \n                if (num == 0)\n                {\n                    if (underflow() == EOF)\n                        break;\n                    continue;\n                }\n\n                // copy all the data from our buffer \n                std::memcpy(s, gptr(), num);\n                n -= num;\n                gbump(num);\n                s += num;\n            }\n            return temp-n;       \n        }\n\n    private:\n\n        // member data\n        int  fd;\n        int  fd_printf;\n        static const std::streamsize max_putback = 4;\n        static const std::streamsize out_buffer_size = 10000;\n        static const std::streamsize in_buffer_size = 10000;\n        char* out_buffer;\n        char* in_buffer;\n\n    };\n\n    namespace impl\n    {\n        int get_data_fd()\n        {\n            char* env_fd = getenv(\"DLIB_SUBPROCESS_DATA_FD\");\n            DLIB_CASSERT(env_fd != 0,\"\");\n            return atoi(env_fd);\n        }\n\n        std::iostream& get_data_iostream()\n        {\n            static filestreambuf dbuff(get_data_fd(), -1);\n            static iostream out(&dbuff);\n            return out;\n        }\n    }\n\n// ---------------------------------------------------------------------------------------- \n\n    subprocess_stream::\n    subprocess_stream(const char* program_name) : stderr(NULL), iosub(NULL)\n    {\n        if (access(program_name, F_OK))\n            throw dlib::error(\"Error: '\" + std::string(program_name) + \"' file does not exist.\");\n        if (access(program_name, X_OK))\n            throw dlib::error(\"Error: '\" + std::string(program_name) + \"' file is not executable.\");\n\n        child_pid = fork();\n        if (child_pid == -1) \n            throw dlib::error(\"Failed to start child process\"); \n\n        if (child_pid == 0) \n        {   \n            // In child process\n            dup2(stdout_pipe.child_fd(), STDOUT_FILENO);\n            dup2(stderr_pipe.child_fd(),  STDERR_FILENO);\n            stdout_pipe.close();\n            stderr_pipe.close();\n\n            char* argv[] = {(char*)program_name, nullptr};\n            char* cudadevs = getenv(\"CUDA_VISIBLE_DEVICES\");\n            if (cudadevs)\n            {\n                std::ostringstream sout;\n                sout << \"DLIB_SUBPROCESS_DATA_FD=\"<<data_pipe.child_fd();\n                std::string extra = sout.str();\n\n                std::string extra2 = std::string(\"CUDA_VISIBLE_DEVICES=\") + cudadevs;\n                char* envp[] = {(char*)extra.c_str(), (char*)extra2.c_str(), nullptr};\n                execve(argv[0], argv, envp);\n            }\n            else\n            {\n                std::ostringstream sout;\n                sout << \"DLIB_SUBPROCESS_DATA_FD=\"<<data_pipe.child_fd();\n                std::string extra = sout.str();\n                char* envp[] = {(char*)extra.c_str(), nullptr};\n                execve(argv[0], argv, envp);\n            }\n\n\n            // If launching the child didn't work then bail immediately so the parent\n            // process has no chance to get tweaked out (*cough* MATLAB *cough*).\n            _Exit(1);\n        }\n        else \n        {\n            // In parent process\n            close(data_pipe.child_fd());\n            close(stdout_pipe.child_fd());\n            close(stderr_pipe.child_fd());\n            make_fd_non_blocking(data_pipe.parent_fd());\n            make_fd_non_blocking(stdout_pipe.parent_fd());\n            make_fd_non_blocking(stderr_pipe.parent_fd());\n            inout_buf = std::unique_ptr<filestreambuf>(new filestreambuf(data_pipe.parent_fd(), stdout_pipe.parent_fd()));\n            err_buf = std::unique_ptr<filestreambuf>(new filestreambuf(stderr_pipe.parent_fd(), stdout_pipe.parent_fd()));\n            iosub.rdbuf(inout_buf.get());\n            stderr.rdbuf(err_buf.get());\n            iosub.tie(&iosub);\n            stderr.tie(&iosub);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    subprocess_stream::\n    ~subprocess_stream() \n    {\n        try\n        {\n            wait();\n        }\n        catch (dlib::error& e)\n        {\n            std::cerr << e.what() << std::endl;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void subprocess_stream::\n    wait() \n    {\n        if (!wait_called)\n        {\n            wait_called = true;\n            send_eof();\n\n            std::ostringstream sout;\n            sout << stderr.rdbuf();\n\n            try{check_for_matlab_ctrl_c();} catch(...) \n            { \n                kill(child_pid, SIGTERM);\n            }\n\n            int status;\n            waitpid(child_pid, &status, 0);\n            if (status)\n                throw dlib::error(\"Child process terminated with an error.\\n\" + sout.str());\n\n            if (sout.str().size() != 0)\n                throw dlib::error(\"Child process terminated with an error.\\n\" + sout.str());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void subprocess_stream::\n    send_eof() { inout_buf->sync();  ::close(data_pipe.parent_fd()); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n\n"
  },
  {
    "path": "dlib/matlab/subprocess_stream.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SUBPROCeSS_STREAM_H_\n#define DLIB_SUBPROCeSS_STREAM_H_\n\n#include <utility>\n#include <unistd.h>\n#include <iostream>\n#include <memory>\n#include <dlib/matrix.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n\n\nnamespace dlib\n{\n\n// --------------------------------------------------------------------------------------\n\n    // Call dlib's serialize and deserialize by default.   The point of this version of\n    // serialize is to do something fast that normally we wouldn't do, like directly copy\n    // memory.  This is safe since this is an interprocess communication happening the same\n    // machine.\n    template <typename T> void interprocess_serialize ( const T& item, std::ostream& out) { serialize(item, out); } \n    template <typename T> void interprocess_deserialize (T& item, std::istream& in) { deserialize(item, in); } \n\n    // But have overloads for direct memory copies for some types since this is faster than\n    // their default serialization.\n    template <typename T, long NR, long NC, typename MM, typename L>\n    void interprocess_serialize(const dlib::matrix<T,NR,NC,MM,L>& item, std::ostream& out)\n    {\n        dlib::serialize(item.nr(), out);\n        dlib::serialize(item.nc(), out);\n        if (item.size() != 0)\n            out.write((const char*)&item(0,0), sizeof(T)*item.size());\n        if (!out)\n            throw dlib::serialization_error(\"Error writing matrix to interprocess iostream.\");\n    }\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    void interprocess_deserialize(dlib::matrix<T,NR,NC,MM,L>& item, std::istream& in)\n    {\n        long nr, nc;\n        dlib::deserialize(nr, in);\n        dlib::deserialize(nc, in);\n        item.set_size(nr,nc);\n        if (item.size() != 0)\n            in.read((char*)&item(0,0), sizeof(T)*item.size());\n        if (!in)\n            throw dlib::serialization_error(\"Error reading matrix from interprocess iostream.\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl{ std::iostream& get_data_iostream(); }\n\n    inline void send_to_parent_process() {impl::get_data_iostream().flush();}\n    template <typename U, typename ...T>\n    void send_to_parent_process(U&& arg1, T&& ...args)\n    /*!\n        ensures\n            - sends all the arguments to send_to_parent_process() to the parent process by\n              serializing them with interprocess_serialize().\n    !*/\n    {\n        interprocess_serialize(arg1, impl::get_data_iostream());\n        send_to_parent_process(std::forward<T>(args)...);\n        if (!impl::get_data_iostream())\n            throw dlib::error(\"Error sending object to parent process.\");\n    }\n\n    inline void receive_from_parent_process() {}\n    template <typename U, typename ...T>\n    void receive_from_parent_process(U&& arg1, T&& ...args)\n    /*!\n        ensures\n            - receives all the arguments to receive_from_parent_process() from the parent\n              process by deserializing them from interprocess_serialize().\n    !*/\n    {\n        interprocess_deserialize(arg1, impl::get_data_iostream());\n        receive_from_parent_process(std::forward<T>(args)...);\n        if (!impl::get_data_iostream())\n            throw dlib::error(\"Error receiving object from parent process.\");\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    class filestreambuf;\n\n    class subprocess_stream : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a tool for spawning a subprocess and communicating with it.  Here\n                is an example: \n\n                    subprocess_stream s(\"/usr/bin/some_program\");\n                    s.send(obj1, obj2, obj3);\n                    s.receive(obj4, obj5);\n                    s.wait(); // wait for sub process to terminate \n\n                Then in the sub process you would have:\n\n                    receive_from_parent_process(obj1, obj2, obj3);\n                    // do stuff\n                    cout << \"echo this text to parent cout\" << endl;\n                    send_to_parent_process(obj4, obj5);\n\n\n                Additionally, if the sub process writes to its standard out then that will\n                be echoed to std::cout in the parent process.  Writing to std::cerr or\n                returning a non-zero value from main will also be noted by the parent\n                process and an appropriate exception will be thrown.\n        !*/\n\n    public:\n\n        explicit subprocess_stream(\n            const char* program_name\n        );\n        /*!\n            ensures\n                - spawns a sub process by executing the file with the given program_name.\n        !*/\n\n        ~subprocess_stream(\n        );\n        /*!\n            ensures\n                - calls wait().  Note that the destructor never throws even though wait() can. \n                  If an exception is thrown by wait() it is just logged to std::cerr.\n        !*/\n\n        void wait(\n        );\n        /*!\n            ensures\n                - closes the input stream to the child process and then waits for the child\n                  to terminate.  \n                - If the child returns an error (by returning != 0 from its main) or\n                  outputs to its standard error then wait() throws a dlib::error() with the\n                  standard error output in it.\n        !*/\n\n        int get_child_pid() const { return child_pid; }\n        /*!\n            ensures\n                - returns the PID of the child process\n        !*/\n\n        template <typename U, typename ...T>\n        void send(U&& arg1, T&& ...args)\n        /*!\n            ensures\n                - sends all the arguments to send() to the subprocess by serializing them\n                  with interprocess_serialize().\n        !*/\n        {\n            interprocess_serialize(arg1, iosub);\n            send(std::forward<T>(args)...);\n            if (!iosub)\n            {\n                std::ostringstream sout;\n                sout << stderr.rdbuf();\n                throw dlib::error(\"Error sending object to child process.\\n\" + sout.str());\n            }\n        }\n        void send() {iosub.flush();}\n\n        template <typename U, typename ...T>\n        void receive(U&& arg1, T&& ...args)\n        /*!\n            ensures\n                - receives all the arguments to receive() to the subprocess by deserializing\n                  them with interprocess_deserialize().\n        !*/\n        {\n            interprocess_deserialize(arg1, iosub);\n            receive(std::forward<T>(args)...);\n            if (!iosub)\n            {\n                std::ostringstream sout;\n                sout << stderr.rdbuf();\n                throw dlib::error(\"Error receiving object from child process.\\n\" + sout.str() );\n            }\n        }\n        void receive() {}\n\n\n    private:\n\n        void send_eof(); \n\n        class cpipe : noncopyable\n        {\n        private:\n            int fd[2];\n        public:\n            cpipe() { if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)) throw dlib::error(\"Failed to create pipe\"); }\n            ~cpipe() { close(); }\n            int parent_fd() const { return fd[0]; }\n            int child_fd() const { return fd[1]; }\n            void close() { ::close(fd[0]); ::close(fd[1]); }\n        };\n\n        cpipe data_pipe;\n        cpipe stdout_pipe;\n        cpipe stderr_pipe;\n        bool wait_called = false;\n        std::unique_ptr<filestreambuf> inout_buf; \n        std::unique_ptr<filestreambuf> err_buf;\n        int child_pid = -1;\n        std::istream stderr;\n        std::iostream iosub;\n    };\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_SUBPROCeSS_STREAM_H_\n\n"
  },
  {
    "path": "dlib/matrix/cblas_constants.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CBLAS_CONSTAnTS_Hh_\n#define DLIB_CBLAS_CONSTAnTS_Hh_\n\n#if !(defined(__GSL_CBLAS_H__) || defined(CBLAS_H))\n\n// Setting this tells other headers to define their own copy of the cblas API so we can\n// call it.  We only do this if some other cblas API hasn't already been included.  \n#define DLIB_DEFINE_CBLAS_API\n\n\n#ifndef CBLAS_INT_TYPE\n#define CBLAS_INT_TYPE int \n#endif\n\nnamespace dlib\n{\n    namespace blas_bindings\n    {\n        enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};\n        enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};\n        enum CBLAS_UPLO {CblasUpper=121, CblasLower=122};\n        enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};\n        enum CBLAS_SIDE {CblasLeft=141, CblasRight=142};\n\n    }\n}\n#endif \n\n#endif // DLIB_CBLAS_CONSTAnTS_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/lapack/fortran_id.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H\n#define DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//       FORTRAN BINDING STUFF FROM BOOST \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n//  Permission to copy, use, modify, sell and\n//  distribute this software is granted provided this copyright notice appears\n//  in all copies. This software is provided \"as is\" without express or implied\n//  warranty, and with no claim as to its suitability for any purpose.\n//  Copyright (C) 2002, 2003 Si-Lab b.v.b.a., Toon Knapen and Kresimir Fresl \n\n\n// First we need to know what the conventions for linking\n// C with Fortran is on this platform/toolset\n#if defined(LAPACK_FORCE_UNDERSCORE)\n#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE\n#elif defined(LAPACK_FORCE_NOUNDERSCORE)\n#define DLIB_BIND_FORTRAN_LOWERCASE\n#elif defined(__GNUC__) || defined(__ICC) || defined(__sgi) || defined(__COMO__) || defined(__KCC)\n#define DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE\n#elif defined(__IBMCPP__) || defined(_MSC_VER) || defined(__BORLANDC__)\n#define DLIB_BIND_FORTRAN_LOWERCASE\n#else\n#error do not know how to link with fortran for the given platform\n#endif\n\n// Next we define macros to convert our symbols to \n// the current convention\n#if defined(DLIB_BIND_FORTRAN_LOWERCASE_UNDERSCORE)\n#define DLIB_FORTRAN_ID( id ) id##_\n#elif defined(DLIB_BIND_FORTRAN_LOWERCASE)\n#define DLIB_FORTRAN_ID( id ) id\n#else\n#error do not know how to bind to fortran calling convention\n#endif\n\n\n\nnamespace dlib\n{\n    namespace lapack\n    {\n            // stuff from f2c used to define what exactly is an integer in fortran\n#if (defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__) || defined(__aarch64__) || defined(__powerpc64__) || defined(__mips64) || (defined(__riscv) && __riscv_xlen == 64)) && !defined(MATLAB_MEX_FILE) && !defined(USE_64BIT_LAPACK_INTEGERS)\n            typedef int integer;\n            typedef unsigned int uinteger;\n#else\n            typedef long int integer;\n            typedef unsigned long int uinteger;\n#endif\n\n    }\n}\n\n#endif // DLIB_BOOST_NUMERIC_BINDINGS_TRAITS_FORTRAN_H\n\n"
  },
  {
    "path": "dlib/matrix/lapack/gees.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_ES_Hh_\n#define DLIB_LAPACk_ES_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n#if defined(__alpha__) || defined(__sparc64__) || defined(__x86_64__) || defined(__ia64__)\n            typedef int logical;\n#else\n            typedef long int logical;\n#endif\n            typedef logical (*L_fp)(...);\n\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgees) (const char *jobvs, const char *sort, const L_fp select, const integer *n, \n                                             double *a, const integer *lda, integer *sdim, double *wr, \n                                             double *wi, double *vs, const integer *ldvs, double *work, \n                                             const integer *lwork, logical *bwork, integer *info);\n\n                void DLIB_FORTRAN_ID(sgees) (const char *jobvs, const char *sort, const L_fp select, const integer *n, \n                                             float *a, const integer *lda, integer *sdim, float *wr, \n                                             float *wi, float *vs, const integer *ldvs, float *work, \n                                             const integer *lwork, logical *bwork, integer *info);\n\n            }\n\n            inline int gees (char jobvs, integer n, \n                             double *a, integer lda, double *wr, \n                             double *wi, double *vs, integer ldvs, double *work, \n                             integer lwork)\n            {\n                // No sorting allowed\n                integer info = 0;\n                char sort = 'N';\n                L_fp fnil = 0;\n                logical bwork = 0;\n                integer sdim = 0;\n                DLIB_FORTRAN_ID(dgees)(&jobvs, &sort, fnil, &n,\n                                       a, &lda, &sdim, wr,\n                                       wi, vs, &ldvs, work,\n                                       &lwork, &bwork, &info);\n                return info;\n            }\n\n\n            inline int gees (char jobvs, integer n, \n                             float *a, integer lda, float *wr, \n                             float *wi, float *vs, integer ldvs, float *work, \n                             integer lwork)\n            {\n                // No sorting allowed\n                integer info = 0;\n                char sort = 'N';\n                L_fp fnil = 0;\n                logical bwork = 0;\n                integer sdim = 0;\n                DLIB_FORTRAN_ID(sgees)(&jobvs, &sort, fnil, &n,\n                                       a, &lda, &sdim, wr,\n                                       wi, vs, &ldvs, work,\n                                       &lwork, &bwork, &info);\n                return info;\n            }\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK driver routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n/*     .. Function Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGEES computes for an N-by-N real nonsymmetric matrix A, the */\n/*  eigenvalues, the real Schur form T, and, optionally, the matrix of */\n/*  Schur vectors Z.  This gives the Schur factorization A = Z*T*(Z**T). */\n\n/*  Optionally, it also orders the eigenvalues on the diagonal of the */\n/*  real Schur form so that selected eigenvalues are at the top left. */\n/*  The leading columns of Z then form an orthonormal basis for the */\n/*  invariant subspace corresponding to the selected eigenvalues. */\n\n/*  A matrix is in real Schur form if it is upper quasi-triangular with */\n/*  1-by-1 and 2-by-2 blocks. 2-by-2 blocks will be standardized in the */\n/*  form */\n/*          [  a  b  ] */\n/*          [  c  a  ] */\n\n/*  where b*c < 0. The eigenvalues of such a block are a +- sqrt(bc). */\n\n/*  Arguments */\n/*  ========= */\n\n/*  JOBVS   (input) CHARACTER*1 */\n/*          = 'N': Schur vectors are not computed; */\n/*          = 'V': Schur vectors are computed. */\n\n/*  SORT    (input) CHARACTER*1 */\n/*          Specifies whether or not to order the eigenvalues on the */\n/*          diagonal of the Schur form. */\n/*          = 'N': Eigenvalues are not ordered; */\n/*          = 'S': Eigenvalues are ordered (see SELECT). */\n\n/*  SELECT  (external procedure) LOGICAL FUNCTION of two DOUBLE PRECISION arguments */\n/*          SELECT must be declared EXTERNAL in the calling subroutine. */\n/*          If SORT = 'S', SELECT is used to select eigenvalues to sort */\n/*          to the top left of the Schur form. */\n/*          If SORT = 'N', SELECT is not referenced. */\n/*          An eigenvalue WR(j)+sqrt(-1)*WI(j) is selected if */\n/*          SELECT(WR(j),WI(j)) is true; i.e., if either one of a complex */\n/*          conjugate pair of eigenvalues is selected, then both complex */\n/*          eigenvalues are selected. */\n/*          Note that a selected complex eigenvalue may no longer */\n/*          satisfy SELECT(WR(j),WI(j)) = .TRUE. after ordering, since */\n/*          ordering may change the value of complex eigenvalues */\n/*          (especially if the eigenvalue is ill-conditioned); in this */\n/*          case INFO is set to N+2 (see INFO below). */\n\n/*  N       (input) INTEGER */\n/*          The order of the matrix A. N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the N-by-N matrix A. */\n/*          On exit, A has been overwritten by its real Schur form T. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,N). */\n\n/*  SDIM    (output) INTEGER */\n/*          If SORT = 'N', SDIM = 0. */\n/*          If SORT = 'S', SDIM = number of eigenvalues (after sorting) */\n/*                         for which SELECT is true. (Complex conjugate */\n/*                         pairs for which SELECT is true for either */\n/*                         eigenvalue count as 2.) */\n\n/*  WR      (output) DOUBLE PRECISION array, dimension (N) */\n/*  WI      (output) DOUBLE PRECISION array, dimension (N) */\n/*          WR and WI contain the real and imaginary parts, */\n/*          respectively, of the computed eigenvalues in the same order */\n/*          that they appear on the diagonal of the output Schur form T. */\n/*          Complex conjugate pairs of eigenvalues will appear */\n/*          consecutively with the eigenvalue having the positive */\n/*          imaginary part first. */\n\n/*  VS      (output) DOUBLE PRECISION array, dimension (LDVS,N) */\n/*          If JOBVS = 'V', VS contains the orthogonal matrix Z of Schur */\n/*          vectors. */\n/*          If JOBVS = 'N', VS is not referenced. */\n\n/*  LDVS    (input) INTEGER */\n/*          The leading dimension of the array VS.  LDVS >= 1; if */\n/*          JOBVS = 'V', LDVS >= N. */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) contains the optimal LWORK. */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK.  LWORK >= max(1,3*N). */\n/*          For good performance, LWORK must generally be larger. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  BWORK   (workspace) LOGICAL array, dimension (N) */\n/*          Not referenced if SORT = 'N'. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0: successful exit */\n/*          < 0: if INFO = -i, the i-th argument had an illegal value. */\n/*          > 0: if INFO = i, and i is */\n/*             <= N: the QR algorithm failed to compute all the */\n/*                   eigenvalues; elements 1:ILO-1 and i+1:N of WR and WI */\n/*                   contain those eigenvalues which have converged; if */\n/*                   JOBVS = 'V', VS contains the matrix which reduces A */\n/*                   to its partially converged Schur form. */\n/*             = N+1: the eigenvalues could not be reordered because some */\n/*                   eigenvalues were too close to separate (the problem */\n/*                   is very ill-conditioned); */\n/*             = N+2: after reordering, roundoff changed values of some */\n/*                   complex eigenvalues so that leading eigenvalues in */\n/*                   the Schur form no longer satisfy SELECT=.TRUE.  This */\n/*                   could also be caused by underflow due to scaling. */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM,\n            typename layout\n            >\n        int gees (\n            const char jobz,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,layout>& wr,\n            matrix<T,NR3,NC3,MM,layout>& wi,\n            matrix<T,NR4,NC4,MM,column_major_layout>& vs\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            const long n = a.nr();\n\n            wr.set_size(n,1);\n            wi.set_size(n,1);\n\n            if (jobz == 'V')\n                vs.set_size(n,n);\n            else\n                vs.set_size(NR4?NR4:1, NC4?NC4:1);\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::gees(jobz, n, \n                                     &a(0,0), a.nr(), &wr(0,0), \n                                     &wi(0,0), &vs(0,0), vs.nr(), &work_size, \n                                     -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual decomposition \n            info = binding::gees(jobz, n, \n                                 &a(0,0), a.nr(), &wr(0,0), \n                                 &wi(0,0), &vs(0,0), vs.nr(), &work(0,0), \n                                 work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_ES_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/lapack/geev.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_GEEV_Hh_\n#define DLIB_LAPACk_GEEV_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgeev) (const char *jobvl, const char *jobvr, const integer *n, double * a, \n                                             const integer *lda, double *wr, double *wi, double *vl, \n                                             const integer *ldvl, double *vr, const integer *ldvr, double *work, \n                                             const integer *lwork, integer *info);\n\n                void DLIB_FORTRAN_ID(sgeev) (const char *jobvl, const char *jobvr, const integer *n, float * a, \n                                             const integer *lda, float *wr, float *wi, float *vl, \n                                             const integer *ldvl, float *vr, const integer *ldvr, float *work, \n                                             const integer *lwork, integer *info);\n\n            }\n\n            inline int geev (char jobvl, char jobvr, integer n, double *a, \n                             integer lda, double *wr, double *wi, double *vl, \n                             integer ldvl, double *vr, integer ldvr, double *work, \n                             integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dgeev)(&jobvl, &jobvr, &n, a,\n                                       &lda, wr, wi, vl, \n                                       &ldvl, vr, &ldvr, work,\n                                       &lwork, &info);\n                return info;\n            }\n\n            inline int geev (char jobvl, char jobvr, integer n, float *a, \n                             integer lda, float *wr, float *wi, float *vl, \n                             integer ldvl, float *vr, integer ldvr, float *work, \n                             integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sgeev)(&jobvl, &jobvr, &n, a,\n                                       &lda, wr, wi, vl, \n                                       &ldvl, vr, &ldvr, work,\n                                       &lwork, &info);\n                return info;\n            }\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK driver routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGEEV computes for an N-by-N real nonsymmetric matrix A, the */\n/*  eigenvalues and, optionally, the left and/or right eigenvectors. */\n\n/*  The right eigenvector v(j) of A satisfies */\n/*                   A * v(j) = lambda(j) * v(j) */\n/*  where lambda(j) is its eigenvalue. */\n/*  The left eigenvector u(j) of A satisfies */\n/*                u(j)**H * A = lambda(j) * u(j)**H */\n/*  where u(j)**H denotes the conjugate transpose of u(j). */\n\n/*  The computed eigenvectors are normalized to have Euclidean norm */\n/*  equal to 1 and largest component real. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  JOBVL   (input) CHARACTER*1 */\n/*          = 'N': left eigenvectors of A are not computed; */\n/*          = 'V': left eigenvectors of A are computed. */\n\n/*  JOBVR   (input) CHARACTER*1 */\n/*          = 'N': right eigenvectors of A are not computed; */\n/*          = 'V': right eigenvectors of A are computed. */\n\n/*  N       (input) INTEGER */\n/*          The order of the matrix A. N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the N-by-N matrix A. */\n/*          On exit, A has been overwritten. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,N). */\n\n/*  WR      (output) DOUBLE PRECISION array, dimension (N) */\n/*  WI      (output) DOUBLE PRECISION array, dimension (N) */\n/*          WR and WI contain the real and imaginary parts, */\n/*          respectively, of the computed eigenvalues.  Complex */\n/*          conjugate pairs of eigenvalues appear consecutively */\n/*          with the eigenvalue having the positive imaginary part */\n/*          first. */\n\n/*  VL      (output) DOUBLE PRECISION array, dimension (LDVL,N) */\n/*          If JOBVL = 'V', the left eigenvectors u(j) are stored one */\n/*          after another in the columns of VL, in the same order */\n/*          as their eigenvalues. */\n/*          If JOBVL = 'N', VL is not referenced. */\n/*          If the j-th eigenvalue is real, then u(j) = VL(:,j), */\n/*          the j-th column of VL. */\n/*          If the j-th and (j+1)-st eigenvalues form a complex */\n/*          conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and */\n/*          u(j+1) = VL(:,j) - i*VL(:,j+1). */\n\n/*  LDVL    (input) INTEGER */\n/*          The leading dimension of the array VL.  LDVL >= 1; if */\n/*          JOBVL = 'V', LDVL >= N. */\n\n/*  VR      (output) DOUBLE PRECISION array, dimension (LDVR,N) */\n/*          If JOBVR = 'V', the right eigenvectors v(j) are stored one */\n/*          after another in the columns of VR, in the same order */\n/*          as their eigenvalues. */\n/*          If JOBVR = 'N', VR is not referenced. */\n/*          If the j-th eigenvalue is real, then v(j) = VR(:,j), */\n/*          the j-th column of VR. */\n/*          If the j-th and (j+1)-st eigenvalues form a complex */\n/*          conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and */\n/*          v(j+1) = VR(:,j) - i*VR(:,j+1). */\n\n/*  LDVR    (input) INTEGER */\n/*          The leading dimension of the array VR.  LDVR >= 1; if */\n/*          JOBVR = 'V', LDVR >= N. */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK.  LWORK >= max(1,3*N), and */\n/*          if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N.  For good */\n/*          performance, LWORK must generally be larger. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */\n/*          > 0:  if INFO = i, the QR algorithm failed to compute all the */\n/*                eigenvalues, and no eigenvectors have been computed; */\n/*                elements i+1:N of WR and WI contain eigenvalues which */\n/*                have converged. */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4, long NR5,\n            long NC1, long NC2, long NC3, long NC4, long NC5,\n            typename MM,\n            typename layout\n            >\n        int geev (\n            const char jobvl,\n            const char jobvr,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,layout>& wr,\n            matrix<T,NR3,NC3,MM,layout>& wi,\n            matrix<T,NR4,NC4,MM,column_major_layout>& vl,\n            matrix<T,NR5,NC5,MM,column_major_layout>& vr\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            const long n = a.nr();\n\n            wr.set_size(n,1);\n            wi.set_size(n,1);\n\n            if (jobvl == 'V')\n                vl.set_size(n,n);\n            else\n                vl.set_size(NR4?NR4:1, NC4?NC4:1);\n\n            if (jobvr == 'V')\n                vr.set_size(n,n);\n            else\n                vr.set_size(NR5?NR5:1, NC5?NC5:1);\n\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::geev(jobvl, jobvr, n, &a(0,0),\n                                     a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),\n                                     vl.nr(), &vr(0,0), vr.nr(), &work_size, \n                                     -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual decomposition \n            info = binding::geev(jobvl, jobvr, n, &a(0,0),\n                                 a.nr(), &wr(0,0), &wi(0,0), &vl(0,0),\n                                 vl.nr(), &vr(0,0), vr.nr(), &work(0,0), \n                                 work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_GEEV_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/geqrf.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_GEQRF_Hh_\n#define DLIB_LAPACk_GEQRF_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgeqrf) (const integer *m, const integer *n, double *a, const integer*\n                                              lda, double *tau, double *work, const integer *lwork, \n                                              integer *info);\n\n                void DLIB_FORTRAN_ID(sgeqrf) (const integer *m, const integer *n, float *a, const integer*\n                                              lda, float *tau, float *work, const integer *lwork, \n                                              integer *info);\n            }\n\n            inline int geqrf (integer m, integer n, double *a, integer lda, \n                              double *tau, double *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dgeqrf)(&m, &n, a, &lda,\n                                        tau, work, &lwork, &info);\n                return info;\n            }\n\n            inline int geqrf (integer m, integer n, float *a, integer lda, \n                              float *tau, float *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sgeqrf)(&m, &n, a, &lda,\n                                        tau, work, &lwork, &info);\n                return info;\n            }\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGEQRF computes a QR factorization of a real M-by-N matrix A: */\n/*  A = Q * R. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  M       (input) INTEGER */\n/*          The number of rows of the matrix A.  M >= 0. */\n\n/*  N       (input) INTEGER */\n/*          The number of columns of the matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the M-by-N matrix A. */\n/*          On exit, the elements on and above the diagonal of the array */\n/*          contain the min(M,N)-by-N upper trapezoidal matrix R (R is */\n/*          upper triangular if m >= n); the elements below the diagonal, */\n/*          with the array TAU, represent the orthogonal matrix Q as a */\n/*          product of min(m,n) elementary reflectors (see Further */\n/*          Details). */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,M). */\n\n/*  TAU     (output) DOUBLE PRECISION array, dimension (min(M,N)) */\n/*          The scalar factors of the elementary reflectors (see Further */\n/*          Details). */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK.  LWORK >= max(1,N). */\n/*          For optimum performance LWORK >= N*NB, where NB is */\n/*          the optimal blocksize. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value */\n\n/*  Further Details */\n/*  =============== */\n\n/*  The matrix Q is represented as a product of elementary reflectors */\n\n/*     Q = H(1) H(2) . . . H(k), where k = min(m,n). */\n\n/*  Each H(i) has the form */\n\n/*     H(i) = I - tau * v * v' */\n\n/*  where tau is a real scalar, and v is a real vector with */\n/*  v(1:i-1) = 0 and v(i) = 1; v(i+1:m) is stored on exit in A(i+1:m,i), */\n/*  and tau in TAU(i). */\n\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2,\n            long NC1, long NC2,\n            typename MM\n            >\n        int geqrf (\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,column_major_layout>& tau\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            tau.set_size(std::min(a.nr(), a.nc()), 1);\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),\n                                      &tau(0,0), &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual decomposition \n            info = binding::geqrf(a.nr(), a.nc(), &a(0,0), a.nr(),\n                                  &tau(0,0), &work(0,0), work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_GEQRF_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/gesdd.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_SDD_Hh_\n#define DLIB_LAPACk_SDD_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgesdd) (char const* jobz, \n                                              const integer* m, const integer* n, double* a, const integer* lda,\n                                              double* s, double* u, const integer* ldu,\n                                              double* vt, const integer* ldvt,\n                                              double* work, const integer* lwork, integer* iwork, integer* info);\n\n                void DLIB_FORTRAN_ID(sgesdd) (char const* jobz, \n                                              const integer* m, const integer* n, float* a, const integer* lda,\n                                              float* s, float* u, const integer* ldu,\n                                              float* vt, const integer* ldvt,\n                                              float* work, const integer* lwork, integer* iwork, integer* info);\n\n            }\n\n            inline integer gesdd (const char jobz, \n                              const integer m, const integer n, double* a, const integer lda,\n                              double* s, double* u, const integer ldu,\n                              double* vt, const integer ldvt,\n                              double* work, const integer lwork, integer* iwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);\n                return info;\n            }\n\n            inline integer gesdd (const char jobz, \n                              const integer m, const integer n, float* a, const integer lda,\n                              float* s, float* u, const integer ldu,\n                              float* vt, const integer ldvt,\n                              float* work, const integer lwork, integer* iwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sgesdd)(&jobz, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, iwork, &info);\n                return info;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK driver routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGESDD computes the singular value decomposition (SVD) of a real */\n/*  M-by-N matrix A, optionally computing the left and right singular */\n/*  vectors.  If singular vectors are desired, it uses a */\n/*  divide-and-conquer algorithm. */\n\n/*  The SVD is written */\n\n/*       A = U * SIGMA * transpose(V) */\n\n/*  where SIGMA is an M-by-N matrix which is zero except for its */\n/*  min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */\n/*  V is an N-by-N orthogonal matrix.  The diagonal elements of SIGMA */\n/*  are the singular values of A; they are real and non-negative, and */\n/*  are returned in descending order.  The first min(m,n) columns of */\n/*  U and V are the left and right singular vectors of A. */\n\n/*  Note that the routine returns VT = V**T, not V. */\n\n/*  The divide and conquer algorithm makes very mild assumptions about */\n/*  floating point arithmetic. It will work on machines with a guard */\n/*  digit in add/subtract, or on those binary machines without guard */\n/*  digits which subtract like the Cray X-MP, Cray Y-MP, Cray C-90, or */\n/*  Cray-2. It could conceivably fail on hexadecimal or decimal machines */\n/*  without guard digits, but we know of none. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  JOBZ    (input) CHARACTER*1 */\n/*          Specifies options for computing all or part of the matrix U: */\n/*          = 'A':  all M columns of U and all N rows of V**T are */\n/*                  returned in the arrays U and VT; */\n/*          = 'S':  the first min(M,N) columns of U and the first */\n/*                  min(M,N) rows of V**T are returned in the arrays U */\n/*                  and VT; */\n/*          = 'O':  If M >= N, the first N columns of U are overwritten */\n/*                  on the array A and all rows of V**T are returned in */\n/*                  the array VT; */\n/*                  otherwise, all columns of U are returned in the */\n/*                  array U and the first M rows of V**T are overwritten */\n/*                  in the array A; */\n/*          = 'N':  no columns of U or rows of V**T are computed. */\n\n/*  M       (input) INTEGER */\n/*          The number of rows of the input matrix A.  M >= 0. */\n\n/*  N       (input) INTEGER */\n/*          The number of columns of the input matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the M-by-N matrix A. */\n/*          On exit, */\n/*          if JOBZ = 'O',  A is overwritten with the first N columns */\n/*                          of U (the left singular vectors, stored */\n/*                          columnwise) if M >= N; */\n/*                          A is overwritten with the first M rows */\n/*                          of V**T (the right singular vectors, stored */\n/*                          rowwise) otherwise. */\n/*          if JOBZ .ne. 'O', the contents of A are destroyed. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,M). */\n\n/*  S       (output) DOUBLE PRECISION array, dimension (min(M,N)) */\n/*          The singular values of A, sorted so that S(i) >= S(i+1). */\n\n/*  U       (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */\n/*          UCOL = M if JOBZ = 'A' or JOBZ = 'O' and M < N; */\n/*          UCOL = min(M,N) if JOBZ = 'S'. */\n/*          If JOBZ = 'A' or JOBZ = 'O' and M < N, U contains the M-by-M */\n/*          orthogonal matrix U; */\n/*          if JOBZ = 'S', U contains the first min(M,N) columns of U */\n/*          (the left singular vectors, stored columnwise); */\n/*          if JOBZ = 'O' and M >= N, or JOBZ = 'N', U is not referenced. */\n\n/*  LDU     (input) INTEGER */\n/*          The leading dimension of the array U.  LDU >= 1; if */\n/*          JOBZ = 'S' or 'A' or JOBZ = 'O' and M < N, LDU >= M. */\n\n/*  VT      (output) DOUBLE PRECISION array, dimension (LDVT,N) */\n/*          If JOBZ = 'A' or JOBZ = 'O' and M >= N, VT contains the */\n/*          N-by-N orthogonal matrix V**T; */\n/*          if JOBZ = 'S', VT contains the first min(M,N) rows of */\n/*          V**T (the right singular vectors, stored rowwise); */\n/*          if JOBZ = 'O' and M < N, or JOBZ = 'N', VT is not referenced. */\n\n/*  LDVT    (input) INTEGER */\n/*          The leading dimension of the array VT.  LDVT >= 1; if */\n/*          JOBZ = 'A' or JOBZ = 'O' and M >= N, LDVT >= N; */\n/*          if JOBZ = 'S', LDVT >= min(M,N). */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK. LWORK >= 1. */\n/*          If JOBZ = 'N', */\n/*            LWORK >= 3*min(M,N) + max(max(M,N),7*min(M,N)). */\n/*          If JOBZ = 'O', */\n/*            LWORK >= 3*min(M,N)*min(M,N) + */\n/*                     max(max(M,N),5*min(M,N)*min(M,N)+4*min(M,N)). */\n/*          If JOBZ = 'S' or 'A' */\n/*            LWORK >= 3*min(M,N)*min(M,N) + */\n/*                     max(max(M,N),4*min(M,N)*min(M,N)+4*min(M,N)). */\n/*          For good performance, LWORK should generally be larger. */\n/*          If LWORK = -1 but other input arguments are legal, WORK(1) */\n/*          returns the optimal LWORK. */\n\n/*  IWORK   (workspace) INTEGER array, dimension (8*min(M,N)) */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit. */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */\n/*          > 0:  DBDSDC did not converge, updating process failed. */\n\n/*  Further Details */\n/*  =============== */\n\n/*  Based on contributions by */\n/*     Ming Gu and Huan Ren, Computer Science Division, University of */\n/*     California at Berkeley, USA */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int gesdd (\n            const char jobz,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,column_major_layout>& s,\n            matrix<T,NR3,NC3,MM,column_major_layout>& u,\n            matrix<T,NR4,NC4,MM,column_major_layout>& vt\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n            matrix<integer,0,1,MM,column_major_layout> iwork;\n\n            const long m = a.nr();\n            const long n = a.nc();\n            s.set_size(std::min(m,n), 1);\n\n            // make sure the iwork memory block is big enough\n            if (iwork.size() < 8*std::min(m,n))\n                iwork.set_size(8*std::min(m,n), 1);\n\n            if (jobz == 'A')\n            {\n                u.set_size(m,m);\n                vt.set_size(n,n);\n            }\n            else if (jobz == 'S')\n            {\n                u.set_size(m, std::min(m,n));\n                vt.set_size(std::min(m,n), n);\n            }\n            else if (jobz == 'O')\n            {\n                DLIB_CASSERT(false, \"jobz == 'O' not supported\");\n            }\n            else\n            {\n                u.set_size(NR3?NR3:1, NC3?NC3:1);\n                vt.set_size(NR4?NR4:1, NC4?NC4:1);\n            }\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),\n                                      &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),\n                                      &work_size, -1, &iwork(0,0));\n\n            if (info != 0)\n                return info;\n\n            // There is a bug in an older version of LAPACK in Debian etch \n            // that causes the gesdd to return the wrong value for work_size\n            // when jobz == 'N'.  So verify the value of work_size.\n            if (jobz == 'N')\n            {\n                using std::min; \n                using std::max; \n                const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));\n                if (work_size < min_work_size)\n                    work_size = min_work_size;\n            }\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual SVD\n            info = binding::gesdd(jobz, a.nr(), a.nc(), &a(0,0), a.nr(),\n                                  &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),\n                                  &work(0,0), work.size(), &iwork(0,0));\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int gesdd (\n            const char jobz,\n            matrix<T,NR1,NC1,MM,row_major_layout>& a,\n            matrix<T,NR2,NC2,MM,row_major_layout>& s,\n            matrix<T,NR3,NC3,MM,row_major_layout>& u_,\n            matrix<T,NR4,NC4,MM,row_major_layout>& vt_\n        )\n        {\n            matrix<T,0,1,MM,row_major_layout> work;\n            matrix<integer,0,1,MM,row_major_layout> iwork;\n\n            // Row major order matrices are transposed from LAPACK's point of view.\n            matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;\n            matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;\n\n\n            const long m = a.nc();\n            const long n = a.nr();\n            s.set_size(std::min(m,n), 1);\n\n            // make sure the iwork memory block is big enough\n            if (iwork.size() < 8*std::min(m,n))\n                iwork.set_size(8*std::min(m,n), 1);\n\n            if (jobz == 'A')\n            {\n                u.set_size(m,m);\n                vt.set_size(n,n);\n            }\n            else if (jobz == 'S')\n            {\n                u.set_size(std::min(m,n), m);\n                vt.set_size(n, std::min(m,n));\n            }\n            else if (jobz == 'O')\n            {\n                DLIB_CASSERT(false, \"jobz == 'O' not supported\");\n            }\n            else\n            {\n                u.set_size(NR4?NR4:1, NC4?NC4:1);\n                vt.set_size(NR3?NR3:1, NC3?NC3:1);\n            }\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),\n                                      &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),\n                                      &work_size, -1, &iwork(0,0));\n\n            if (info != 0)\n                return info;\n\n            // There is a bug in an older version of LAPACK in Debian etch \n            // that causes the gesdd to return the wrong value for work_size\n            // when jobz == 'N'.  So verify the value of work_size.\n            if (jobz == 'N')\n            {\n                using std::min; \n                using std::max; \n                const T min_work_size = 3*min(m,n) + max(max(m,n),7*min(m,n));\n                if (work_size < min_work_size)\n                    work_size = min_work_size;\n            }\n\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual SVD\n            info = binding::gesdd(jobz, m, n, &a(0,0), a.nc(),\n                                  &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),\n                                  &work(0,0), work.size(), &iwork(0,0));\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_SDD_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/gesvd.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_SVD_Hh_\n#define DLIB_LAPACk_SVD_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgesvd) (const char* jobu, const char* jobvt,\n                                              const integer* m, const integer* n, double* a, const integer* lda,\n                                              double* s, double* u, const integer* ldu,\n                                              double* vt, const integer* ldvt,\n                                              double* work, const integer* lwork, integer* info);\n\n                void DLIB_FORTRAN_ID(sgesvd) (const char* jobu, const char* jobvt,\n                                              const integer* m, const integer* n, float* a, const integer* lda,\n                                              float* s, float* u, const integer* ldu,\n                                              float* vt, const integer* ldvt,\n                                              float* work, const integer* lwork, integer* info);\n\n            }\n\n            inline integer gesvd (const char jobu, const char jobvt,\n                              const integer m, const integer n, double* a, const integer lda,\n                              double* s, double* u, const integer ldu,\n                              double* vt, const integer ldvt,\n                              double* work, const integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);\n                return info;\n            }\n\n            inline integer gesvd (const char jobu, const char jobvt,\n                              const integer m, const integer n, float* a, const integer lda,\n                              float* s, float* u, const integer ldu,\n                              float* vt, const integer ldvt,\n                              float* work, const integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sgesvd)(&jobu, &jobvt, &m, &n, a, &lda, s, u, &ldu, vt, &ldvt, work, &lwork, &info);\n                return info;\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK driver routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGESVD computes the singular value decomposition (SVD) of a real */\n/*  M-by-N matrix A, optionally computing the left and/or right singular */\n/*  vectors. The SVD is written */\n\n/*       A = U * SIGMA * transpose(V) */\n\n/*  where SIGMA is an M-by-N matrix which is zero except for its */\n/*  min(m,n) diagonal elements, U is an M-by-M orthogonal matrix, and */\n/*  V is an N-by-N orthogonal matrix.  The diagonal elements of SIGMA */\n/*  are the singular values of A; they are real and non-negative, and */\n/*  are returned in descending order.  The first min(m,n) columns of */\n/*  U and V are the left and right singular vectors of A. */\n\n/*  Note that the routine returns V**T, not V. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  JOBU    (input) CHARACTER*1 */\n/*          Specifies options for computing all or part of the matrix U: */\n/*          = 'A':  all M columns of U are returned in array U: */\n/*          = 'S':  the first min(m,n) columns of U (the left singular */\n/*                  vectors) are returned in the array U; */\n/*          = 'O':  the first min(m,n) columns of U (the left singular */\n/*                  vectors) are overwritten on the array A; */\n/*          = 'N':  no columns of U (no left singular vectors) are */\n/*                  computed. */\n\n/*  JOBVT   (input) CHARACTER*1 */\n/*          Specifies options for computing all or part of the matrix */\n/*          V**T: */\n/*          = 'A':  all N rows of V**T are returned in the array VT; */\n/*          = 'S':  the first min(m,n) rows of V**T (the right singular */\n/*                  vectors) are returned in the array VT; */\n/*          = 'O':  the first min(m,n) rows of V**T (the right singular */\n/*                  vectors) are overwritten on the array A; */\n/*          = 'N':  no rows of V**T (no right singular vectors) are */\n/*                  computed. */\n\n/*          JOBVT and JOBU cannot both be 'O'. */\n\n/*  M       (input) INTEGER */\n/*          The number of rows of the input matrix A.  M >= 0. */\n\n/*  N       (input) INTEGER */\n/*          The number of columns of the input matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the M-by-N matrix A. */\n/*          On exit, */\n/*          if JOBU = 'O',  A is overwritten with the first min(m,n) */\n/*                          columns of U (the left singular vectors, */\n/*                          stored columnwise); */\n/*          if JOBVT = 'O', A is overwritten with the first min(m,n) */\n/*                          rows of V**T (the right singular vectors, */\n/*                          stored rowwise); */\n/*          if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A */\n/*                          are destroyed. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,M). */\n\n/*  S       (output) DOUBLE PRECISION array, dimension (min(M,N)) */\n/*          The singular values of A, sorted so that S(i) >= S(i+1). */\n\n/*  U       (output) DOUBLE PRECISION array, dimension (LDU,UCOL) */\n/*          (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'. */\n/*          If JOBU = 'A', U contains the M-by-M orthogonal matrix U; */\n/*          if JOBU = 'S', U contains the first min(m,n) columns of U */\n/*          (the left singular vectors, stored columnwise); */\n/*          if JOBU = 'N' or 'O', U is not referenced. */\n\n/*  LDU     (input) INTEGER */\n/*          The leading dimension of the array U.  LDU >= 1; if */\n/*          JOBU = 'S' or 'A', LDU >= M. */\n\n/*  VT      (output) DOUBLE PRECISION array, dimension (LDVT,N) */\n/*          If JOBVT = 'A', VT contains the N-by-N orthogonal matrix */\n/*          V**T; */\n/*          if JOBVT = 'S', VT contains the first min(m,n) rows of */\n/*          V**T (the right singular vectors, stored rowwise); */\n/*          if JOBVT = 'N' or 'O', VT is not referenced. */\n\n/*  LDVT    (input) INTEGER */\n/*          The leading dimension of the array VT.  LDVT >= 1; if */\n/*          JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N). */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK; */\n/*          if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged */\n/*          superdiagonal elements of an upper bidiagonal matrix B */\n/*          whose diagonal is in S (not necessarily sorted). B */\n/*          satisfies A = U * B * VT, so it has the same singular values */\n/*          as A, and singular vectors related by U and VT. */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK. */\n/*          LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)). */\n/*          For good performance, LWORK should generally be larger. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit. */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value. */\n/*          > 0:  if DBDSQR did not converge, INFO specifies how many */\n/*                superdiagonals of an intermediate bidiagonal form B */\n/*                did not converge to zero. See the description of WORK */\n/*                above for details. */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int gesvd (\n            const char jobu,\n            const char jobvt,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,column_major_layout>& s,\n            matrix<T,NR3,NC3,MM,column_major_layout>& u,\n            matrix<T,NR4,NC4,MM,column_major_layout>& vt\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            const long m = a.nr();\n            const long n = a.nc();\n            s.set_size(std::min(m,n), 1);\n\n            if (jobu == 'A')\n                u.set_size(m,m);\n            else if (jobu == 'S')\n                u.set_size(m, std::min(m,n));\n            else\n                u.set_size(NR3?NR3:1, NC3?NC3:1);\n\n            if (jobvt == 'A')\n                vt.set_size(n,n);\n            else if (jobvt == 'S')\n                vt.set_size(std::min(m,n), n);\n            else\n                vt.set_size(NR4?NR4:1, NC4?NC4:1);\n\n\n            if (jobu == 'O' || jobvt == 'O')\n            {\n                DLIB_CASSERT(false, \"job == 'O' not supported\");\n            }\n\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),\n                                      &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),\n                                      &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual SVD\n            info = binding::gesvd(jobu, jobvt, a.nr(), a.nc(), &a(0,0), a.nr(),\n                                  &s(0,0), &u(0,0), u.nr(), &vt(0,0), vt.nr(),\n                                  &work(0,0), work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int gesvd (\n            char jobu,\n            char jobvt,\n            matrix<T,NR1,NC1,MM,row_major_layout>& a,\n            matrix<T,NR2,NC2,MM,row_major_layout>& s,\n            matrix<T,NR3,NC3,MM,row_major_layout>& u_,\n            matrix<T,NR4,NC4,MM,row_major_layout>& vt_\n        )\n        {\n            matrix<T,0,1,MM,row_major_layout> work;\n\n            // Row major order matrices are transposed from LAPACK's point of view.\n            matrix<T,NR4,NC4,MM,row_major_layout>& u = vt_;\n            matrix<T,NR3,NC3,MM,row_major_layout>& vt = u_;\n            std::swap(jobu, jobvt);\n\n            const long m = a.nc();\n            const long n = a.nr();\n            s.set_size(std::min(m,n), 1);\n\n            if (jobu == 'A')\n                u.set_size(m,m);\n            else if (jobu == 'S')\n                u.set_size(std::min(m,n), m);\n            else\n                u.set_size(NR4?NR4:1, NC4?NC4:1);\n\n            if (jobvt == 'A')\n                vt.set_size(n,n);\n            else if (jobvt == 'S')\n                vt.set_size(n, std::min(m,n));\n            else\n                vt.set_size(NR3?NR3:1, NC3?NC3:1);\n\n            if (jobu == 'O' || jobvt == 'O')\n            {\n                DLIB_CASSERT(false, \"job == 'O' not supported\");\n            }\n\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),\n                                      &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),\n                                      &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual SVD\n            info = binding::gesvd(jobu, jobvt, m, n, &a(0,0), a.nc(),\n                                  &s(0,0), &u(0,0), u.nc(), &vt(0,0), vt.nc(),\n                                  &work(0,0), work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_SVD_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/lapack/getrf.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_GETRF_Hh_\n#define DLIB_LAPACk_GETRF_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dgetrf) (const integer *m, const integer *n, double *a, \n                                              const integer *lda, integer *ipiv, integer *info);\n\n                void DLIB_FORTRAN_ID(sgetrf) (const integer *m, const integer *n, float *a, \n                                              const integer *lda, integer *ipiv, integer *info);\n\n            }\n\n            inline int getrf (integer m, integer n, double *a, \n                              integer lda, integer *ipiv)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dgetrf)(&m, &n, a, &lda, ipiv, &info);\n                return info;\n            }\n\n            inline int getrf (integer m, integer n, float *a, \n                              integer lda, integer *ipiv)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sgetrf)(&m, &n, a, &lda, ipiv, &info);\n                return info;\n            }\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n\n/*  -- LAPACK routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DGETRF computes an LU factorization of a general M-by-N matrix A */\n/*  using partial pivoting with row interchanges. */\n\n/*  The factorization has the form */\n/*     A = P * L * U */\n/*  where P is a permutation matrix, L is lower triangular with unit */\n/*  diagonal elements (lower trapezoidal if m > n), and U is upper */\n/*  triangular (upper trapezoidal if m < n). */\n\n/*  This is the right-looking Level 3 BLAS version of the algorithm. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  M       (input) INTEGER */\n/*          The number of rows of the matrix A.  M >= 0. */\n\n/*  N       (input) INTEGER */\n/*          The number of columns of the matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the M-by-N matrix to be factored. */\n/*          On exit, the factors L and U from the factorization */\n/*          A = P*L*U; the unit diagonal elements of L are not stored. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,M). */\n\n/*  IPIV    (output) INTEGER array, dimension (min(M,N)) */\n/*          The pivot indices; for 1 <= i <= min(M,N), row i of the */\n/*          matrix was interchanged with row IPIV(i). */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value */\n/*          > 0:  if INFO = i, U(i,i) is exactly zero. The factorization */\n/*                has been completed, but the factor U is exactly */\n/*                singular, and division by zero will occur if it is used */\n/*                to solve a system of equations. */\n\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2,\n            long NC1, long NC2, \n            typename MM,\n            typename layout\n            >\n        int getrf (\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<integer,NR2,NC2,MM,layout>& ipiv \n        )\n        {\n            const long m = a.nr();\n            const long n = a.nc();\n\n            ipiv.set_size(std::min(m,n), 1);\n\n            // compute the actual decomposition \n            return binding::getrf(m, n, &a(0,0), a.nr(), &ipiv(0,0));\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_GETRF_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/lapack/ormqr.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_ORMQR_Hh_\n#define DLIB_LAPACk_ORMQR_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dormqr) (const char *side, const char *trans, const integer *m, const integer *n, \n                                              const integer *k, const double *a, const integer *lda, const double *tau, \n                                              double * c_, const integer *ldc, double *work, const integer *lwork, \n                                              integer *info);\n\n                void DLIB_FORTRAN_ID(sormqr) (const char *side, const char *trans, const integer *m, const integer *n, \n                                              const integer *k, const float *a, const integer *lda, const float *tau, \n                                              float * c_, const integer *ldc, float *work, const integer *lwork, \n                                              integer *info);\n\n            }\n\n            inline int ormqr (char side, char trans, integer m, integer n, \n                              integer k, const double *a, integer lda, const double *tau, \n                              double *c_, integer ldc, double *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dormqr)(&side, &trans, &m, &n,\n                                        &k, a, &lda, tau,\n                                        c_, &ldc, work, &lwork, &info);\n                return info;\n            }\n\n            inline int ormqr (char side, char trans, integer m, integer n, \n                              integer k, const float *a, integer lda, const float *tau, \n                              float *c_, integer ldc, float *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(sormqr)(&side, &trans, &m, &n,\n                                        &k, a, &lda, tau,\n                                        c_, &ldc, work, &lwork, &info);\n                return info;\n            }\n\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DORMQR overwrites the general real M-by-N matrix C with */\n\n/*                  SIDE = 'L'     SIDE = 'R' */\n/*  TRANS = 'N':      Q * C          C * Q */\n/*  TRANS = 'T':      Q**T * C       C * Q**T */\n\n/*  where Q is a real orthogonal matrix defined as the product of k */\n/*  elementary reflectors */\n\n/*        Q = H(1) H(2) . . . H(k) */\n\n/*  as returned by DGEQRF. Q is of order M if SIDE = 'L' and of order N */\n/*  if SIDE = 'R'. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  SIDE    (input) CHARACTER*1 */\n/*          = 'L': apply Q or Q**T from the Left; */\n/*          = 'R': apply Q or Q**T from the Right. */\n\n/*  TRANS   (input) CHARACTER*1 */\n/*          = 'N':  No transpose, apply Q; */\n/*          = 'T':  Transpose, apply Q**T. */\n\n/*  M       (input) INTEGER */\n/*          The number of rows of the matrix C. M >= 0. */\n\n/*  N       (input) INTEGER */\n/*          The number of columns of the matrix C. N >= 0. */\n\n/*  K       (input) INTEGER */\n/*          The number of elementary reflectors whose product defines */\n/*          the matrix Q. */\n/*          If SIDE = 'L', M >= K >= 0; */\n/*          if SIDE = 'R', N >= K >= 0. */\n\n/*  A       (input) DOUBLE PRECISION array, dimension (LDA,K) */\n/*          The i-th column must contain the vector which defines the */\n/*          elementary reflector H(i), for i = 1,2,...,k, as returned by */\n/*          DGEQRF in the first k columns of its array argument A. */\n/*          A is modified by the routine but restored on exit. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A. */\n/*          If SIDE = 'L', LDA >= max(1,M); */\n/*          if SIDE = 'R', LDA >= max(1,N). */\n\n/*  TAU     (input) DOUBLE PRECISION array, dimension (K) */\n/*          TAU(i) must contain the scalar factor of the elementary */\n/*          reflector H(i), as returned by DGEQRF. */\n\n/*  C       (input/output) DOUBLE PRECISION array, dimension (LDC,N) */\n/*          On entry, the M-by-N matrix C. */\n/*          On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. */\n\n/*  LDC     (input) INTEGER */\n/*          The leading dimension of the array C. LDC >= max(1,M). */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */\n\n/*  LWORK   (input) INTEGER */\n/*          The dimension of the array WORK. */\n/*          If SIDE = 'L', LWORK >= max(1,N); */\n/*          if SIDE = 'R', LWORK >= max(1,M). */\n/*          For optimum performance LWORK >= N*NB if SIDE = 'L', and */\n/*          LWORK >= M*NB if SIDE = 'R', where NB is the optimal */\n/*          blocksize. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3,\n            long NC1, long NC2, long NC3,\n            typename MM,\n            typename C_LAYOUT\n            >\n        int ormqr (\n            char side, \n            char trans,\n            const matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            const matrix<T,NR2,NC2,MM,column_major_layout>& tau,\n            matrix<T,NR3,NC3,MM,C_LAYOUT>& c \n        )\n        {\n            long m = c.nr();\n            long n = c.nc();\n            const long k = a.nc();\n            long ldc;\n            if (is_same_type<C_LAYOUT,column_major_layout>::value)\n            {\n                ldc = c.nr();\n            }\n            else\n            {\n                // Since lapack expects c to be in column major layout we have to \n                // do something to make this work.  Since a row major layout matrix\n                // will look just like a transposed C we can just swap a few things around.\n\n                ldc = c.nc();\n                swap(m,n);\n\n                if (side == 'L')\n                    side = 'R';\n                else\n                    side = 'L';\n\n                if (trans == 'T')\n                    trans = 'N';\n                else\n                    trans = 'T';\n            }\n\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::ormqr(side, trans, m, n, \n                                      k, &a(0,0), a.nr(), &tau(0,0),\n                                      &c(0,0), ldc, &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual result \n            info = binding::ormqr(side, trans, m, n, \n                                  k, &a(0,0), a.nr(), &tau(0,0),\n                                  &c(0,0), ldc, &work(0,0), work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_ORMQR_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/lapack/pbtrf.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_BDC_Hh_\n#define DLIB_LAPACk_BDC_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dpbtrf) (const char *uplo, const integer *n, const integer *kd,\n                                              double *ab, const integer *ldab, integer *info);\n\n                void DLIB_FORTRAN_ID(spbtrf) (const char *uplo, const integer *n, const integer *kd,\n                                              float *ab, const integer *ldab, integer *info);\n\n            }\n\n            inline integer pbtrf (const char uplo, const integer n, const integer kd,\n                                  double* ab, const integer ldab)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dpbtrf)(&uplo, &n, &kd, ab, &ldab, &info);\n                return info;\n            }\n\n            inline integer pbtrf (const char uplo, const integer n, const integer kd,\n                                  float* ab, const integer ldab)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(spbtrf)(&uplo, &n, &kd, ab, &ldab, &info);\n                return info;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n/*  DPBTRF(l)\t\tLAPACK routine (version\t1.1)\t\t    DPBTRF(l)\n\nNAME\n  DPBTRF - compute the Cholesky\tfactorization of a real\tsymmetric positive\n  definite band\tmatrix A\n\nSYNOPSIS\n\n  SUBROUTINE DPBTRF( UPLO, N, KD, AB, LDAB, INFO )\n\n      CHARACTER\t     UPLO\n\n      INTEGER\t     INFO, KD, LDAB, N\n\n      DOUBLE\t     PRECISION AB( LDAB, * )\n\nPURPOSE\n  DPBTRF computes the Cholesky factorization of\ta real symmetric positive\n  definite band\tmatrix A.\n\n  The factorization has\tthe form\n     A = U**T *\tU,  if UPLO = 'U', or\n     A = L  * L**T,  if\tUPLO = 'L',\n  where\tU is an\tupper triangular matrix\tand L is lower triangular.\n\nARGUMENTS\n\n  UPLO\t  (input) CHARACTER*1\n\t  = 'U':  Upper\ttriangle of A is stored;\n\t  = 'L':  Lower\ttriangle of A is stored.\n\n  N\t  (input) INTEGER\n\t  The order of the matrix A.  N\t>= 0.\n\n  KD\t  (input) INTEGER\n\t  The number of\tsuperdiagonals of the matrix A if UPLO = 'U', or the\n\t  number of subdiagonals if UPLO = 'L'.\t KD >= 0.\n\n  AB\t  (input/output) DOUBLE\tPRECISION array, dimension (LDAB,N)\n\t  On entry, the\tupper or lower triangle\tof the symmetric band matrix\n\t  A, stored in the first KD+1 rows of the array.  The j-th column of\n\t  A is stored in the j-th column of the\tarray AB as follows: if\tUPLO\n\t  = 'U', AB(kd+1+i-j,j)\t= A(i,j) for max(1,j-kd)<=i<=j;\tif UPLO\t=\n\t  'L', AB(1+i-j,j)    =\tA(i,j) for j<=i<=min(n,j+kd).\n\n\t  On exit, if INFO = 0,\tthe triangular factor U\tor L from the Chole-\n\t  sky factorization A =\tU**T*U or A = L*L**T of\tthe band matrix\tA, in\n\t  the same storage format as A.\n\n  LDAB\t  (input) INTEGER\n\t  The leading dimension\tof the array AB.  LDAB >= KD+1.\n\n  INFO\t  (output) INTEGER\n\t  = 0:\tsuccessful exit\n\t  < 0:\tif INFO\t= -i, the i-th argument\thad an illegal value\n\t  > 0:\tif INFO\t= i, the leading minor of order\ti is not positive\n\t  definite, and\tthe factorization could\tnot be completed.\n\nFURTHER\tDETAILS\n  The band storage scheme is illustrated by the\tfollowing example, when\tN =\n  6, KD\t= 2, and UPLO =\t'U':\n\n  On entry:\t\t\t  On exit:\n\n      *\t   *   a13  a24\t a35  a46      *    *\tu13  u24  u35  u46\n      *\t  a12  a23  a34\t a45  a56      *   u12\tu23  u34  u45  u56\n     a11  a22  a33  a44\t a55  a66     u11  u22\tu33  u44  u55  u66\n\n  Similarly, if\tUPLO = 'L' the format of A is as follows:\n\n  On entry:\t\t\t  On exit:\n\n     a11  a22  a33  a44\t a55  a66     l11  l22\tl33  l44  l55  l66\n     a21  a32  a43  a54\t a65   *      l21  l32\tl43  l54  l65\t*\n     a31  a42  a53  a64\t  *    *      l31  l42\tl53  l64   *\t*\n\n  Array\telements marked\t* are not used by the routine.\n\n  Contributed by\n  Peter\tMayes and Giuseppe Radicati, IBM ECSEC,\tRome, March 23,\t1989 */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NC1,\n            typename MM\n            >\n        int pbtrf (\n            char uplo, matrix<T,NR1,NC1,MM,column_major_layout>& ab\n        )\n        {\n            const long ldab = ab.nr();\n            const long n = ab.nc();\n            const long kd = ldab - 1; // assume fully packed \n\n            int info = binding::pbtrf(uplo, n, kd, &ab(0,0), ldab);\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n\n        template <\n            typename T, \n            long NR1, long NC1,\n            typename MM\n            >\n        int pbtrf (\n            char uplo, matrix<T,NR1,NC1,MM,row_major_layout>& ab\n        )\n        {\n            const long ldab = ab.nr();\n            const long n = ab.nc();\n            const long kd = ldab - 1; // assume fully packed \n\n            matrix<T,NC1,NR1,MM,row_major_layout> abt = trans(ab);\n\n            int info = binding::pbtrf(uplo, n, kd, &abt(0,0), ldab);\n\n            ab = trans(abt);\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_BDC_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/potrf.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_POTRF_Hh_\n#define DLIB_LAPACk_POTRF_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dpotrf) (const char *uplo, const integer *n, double *a, \n                                              const integer *lda, integer *info);\n\n                void DLIB_FORTRAN_ID(spotrf) (const char *uplo, const integer *n, float *a, \n                                              const integer *lda, integer *info);\n\n            }\n\n            inline int potrf (char uplo, integer n, double *a, integer lda)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dpotrf)(&uplo, &n, a, &lda, &info);\n                return info;\n            }\n\n            inline int potrf (char uplo, integer n, float *a, integer lda)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(spotrf)(&uplo, &n, a, &lda, &info);\n                return info;\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DPOTRF computes the Cholesky factorization of a real symmetric */\n/*  positive definite matrix A. */\n\n/*  The factorization has the form */\n/*     A = U**T * U,  if UPLO = 'U', or */\n/*     A = L  * L**T,  if UPLO = 'L', */\n/*  where U is an upper triangular matrix and L is lower triangular. */\n\n/*  This is the block version of the algorithm, calling Level 3 BLAS. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  UPLO    (input) CHARACTER*1 */\n/*          = 'U':  Upper triangle of A is stored; */\n/*          = 'L':  Lower triangle of A is stored. */\n\n/*  N       (input) INTEGER */\n/*          The order of the matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N) */\n/*          On entry, the symmetric matrix A.  If UPLO = 'U', the leading */\n/*          N-by-N upper triangular part of A contains the upper */\n/*          triangular part of the matrix A, and the strictly lower */\n/*          triangular part of A is not referenced.  If UPLO = 'L', the */\n/*          leading N-by-N lower triangular part of A contains the lower */\n/*          triangular part of the matrix A, and the strictly upper */\n/*          triangular part of A is not referenced. */\n\n/*          On exit, if INFO = 0, the factor U or L from the Cholesky */\n/*          factorization A = U**T*U or A = L*L**T. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,N). */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value */\n/*          > 0:  if INFO = i, the leading minor of order i is not */\n/*                positive definite, and the factorization could not be */\n/*                completed. */\n\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1,\n            long NC1, \n            typename MM\n            >\n        int potrf (\n            char uplo,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a\n        )\n        {\n            // compute the actual decomposition \n            int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());\n\n            // If it fails part way though the factorization then make sure\n            // the end of the matrix gets properly initialized with zeros.\n            if (info > 0)\n            {\n                if (uplo == 'L')\n                    set_colm(a, range(info-1, a.nc()-1)) = 0;\n                else\n                    set_rowm(a, range(info-1, a.nr()-1)) = 0;\n            }\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1,\n            long NC1, \n            typename MM\n            >\n        int potrf (\n            char uplo,\n            matrix<T,NR1,NC1,MM,row_major_layout>& a\n        )\n        {\n            // since we are working on a row major order matrix we need to ask\n            // LAPACK for the transpose of whatever the user asked for.\n\n            if (uplo == 'L')\n                uplo = 'U';\n            else\n                uplo = 'L';\n\n            // compute the actual decomposition \n            int info = binding::potrf(uplo, a.nr(), &a(0,0), a.nr());\n\n            // If it fails part way though the factorization then make sure\n            // the end of the matrix gets properly initialized with zeros.\n            if (info > 0)\n            {\n                if (uplo == 'U')\n                    set_colm(a, range(info-1, a.nc()-1)) = 0;\n                else\n                    set_rowm(a, range(info-1, a.nr()-1)) = 0;\n            }\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_POTRF_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/syev.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_EV_Hh_\n#define DLIB_LAPACk_EV_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dsyev) (const char *jobz, const char *uplo, const integer *n, double *a,\n                                             const integer *lda, double *w, double *work, const integer *lwork, \n                                             integer *info);\n\n                void DLIB_FORTRAN_ID(ssyev) (const char *jobz, const char *uplo, const integer *n, float *a,\n                                             const integer *lda, float *w, float *work, const integer *lwork, \n                                             integer *info);\n\n            }\n\n            inline int syev (char jobz, char uplo, integer n, double *a,\n                             integer lda, double *w, double *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dsyev)(&jobz, &uplo, &n, a,\n                                       &lda, w, work, &lwork, &info);\n                return info;\n            }\n\n            inline int syev (char jobz, char uplo, integer n, float *a,\n                             integer lda, float *w, float *work, integer lwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(ssyev)(&jobz, &uplo, &n, a,\n                                       &lda, w, work, &lwork, &info);\n                return info;\n            }\n\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n/*  -- LAPACK driver routine (version 3.1) -- */\n/*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */\n/*     November 2006 */\n\n/*     .. Scalar Arguments .. */\n/*     .. */\n/*     .. Array Arguments .. */\n/*     .. */\n\n/*  Purpose */\n/*  ======= */\n\n/*  DSYEV computes all eigenvalues and, optionally, eigenvectors of a */\n/*  real symmetric matrix A. */\n\n/*  Arguments */\n/*  ========= */\n\n/*  JOBZ    (input) CHARACTER*1 */\n/*          = 'N':  Compute eigenvalues only; */\n/*          = 'V':  Compute eigenvalues and eigenvectors. */\n\n/*  UPLO    (input) CHARACTER*1 */\n/*          = 'U':  Upper triangle of A is stored; */\n/*          = 'L':  Lower triangle of A is stored. */\n\n/*  N       (input) INTEGER */\n/*          The order of the matrix A.  N >= 0. */\n\n/*  A       (input/output) DOUBLE PRECISION array, dimension (LDA, N) */\n/*          On entry, the symmetric matrix A.  If UPLO = 'U', the */\n/*          leading N-by-N upper triangular part of A contains the */\n/*          upper triangular part of the matrix A.  If UPLO = 'L', */\n/*          the leading N-by-N lower triangular part of A contains */\n/*          the lower triangular part of the matrix A. */\n/*          On exit, if JOBZ = 'V', then if INFO = 0, A contains the */\n/*          orthonormal eigenvectors of the matrix A. */\n/*          If JOBZ = 'N', then on exit the lower triangle (if UPLO='L') */\n/*          or the upper triangle (if UPLO='U') of A, including the */\n/*          diagonal, is destroyed. */\n\n/*  LDA     (input) INTEGER */\n/*          The leading dimension of the array A.  LDA >= max(1,N). */\n\n/*  W       (output) DOUBLE PRECISION array, dimension (N) */\n/*          If INFO = 0, the eigenvalues in ascending order. */\n\n/*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */\n/*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */\n\n/*  LWORK   (input) INTEGER */\n/*          The length of the array WORK.  LWORK >= max(1,3*N-1). */\n/*          For optimal efficiency, LWORK >= (NB+2)*N, */\n/*          where NB is the blocksize for DSYTRD returned by ILAENV. */\n\n/*          If LWORK = -1, then a workspace query is assumed; the routine */\n/*          only calculates the optimal size of the WORK array, returns */\n/*          this value as the first entry of the WORK array, and no error */\n/*          message related to LWORK is issued by XERBLA. */\n\n/*  INFO    (output) INTEGER */\n/*          = 0:  successful exit */\n/*          < 0:  if INFO = -i, the i-th argument had an illegal value */\n/*          > 0:  if INFO = i, the algorithm failed to converge; i */\n/*                off-diagonal elements of an intermediate tridiagonal */\n/*                form did not converge to zero. */\n\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, \n            long NC1, long NC2,\n            typename MM\n            >\n        int syev (\n            const char jobz,\n            const char uplo,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            matrix<T,NR2,NC2,MM,column_major_layout>& w\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n\n            const long n = a.nr();\n\n            w.set_size(n,1);\n\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::syev(jobz, uplo, n, &a(0,0),\n                                     a.nr(), &w(0,0), &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual decomposition \n            info = binding::syev(jobz, uplo, n, &a(0,0),\n                                 a.nr(), &w(0,0), &work(0,0), work.size());\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, \n            long NC1, long NC2,\n            typename MM\n            >\n        int syev (\n            char jobz,\n            char uplo,\n            matrix<T,NR1,NC1,MM,row_major_layout>& a,\n            matrix<T,NR2,NC2,MM,row_major_layout>& w\n        )\n        {\n            matrix<T,0,1,MM,row_major_layout> work;\n\n            if (uplo == 'L')\n                uplo = 'U';\n            else\n                uplo = 'L';\n\n            const long n = a.nr();\n\n            w.set_size(n,1);\n\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            int info = binding::syev(jobz, uplo, n, &a(0,0),\n                                     a.nc(), &w(0,0), &work_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n\n            // compute the actual decomposition \n            info = binding::syev(jobz, uplo, n, &a(0,0),\n                                 a.nc(), &w(0,0), &work(0,0), work.size());\n\n\n            a = trans(a);\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_EV_Hh_\n\n\n\n\n"
  },
  {
    "path": "dlib/matrix/lapack/syevr.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_LAPACk_EVR_Hh_\n#define DLIB_LAPACk_EVR_Hh_\n\n#include \"fortran_id.h\"\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n    namespace lapack\n    {\n        namespace binding\n        {\n            extern \"C\"\n            {\n                void DLIB_FORTRAN_ID(dsyevr) (const char *jobz, const char *range, const char *uplo, const integer *n, \n                                              double *a, const integer *lda, const double *vl, const double *vu, const integer *il, \n                                              const integer *iu, const double *abstol, integer *m, double *w, \n                                              double *z_, const integer *ldz, integer *isuppz, double *work, \n                                              const integer *lwork, integer *iwork, const integer *liwork, integer *info);\n\n                void DLIB_FORTRAN_ID(ssyevr) (const char *jobz, const char *range, const char *uplo, const integer *n, \n                                              float *a, const integer *lda, const float *vl, const float *vu, const integer *il, \n                                              const integer *iu, const float *abstol, integer *m, float *w, \n                                              float *z_, const integer *ldz, integer *isuppz, float *work, \n                                              const integer *lwork, integer *iwork, const integer *liwork, integer *info);\n            }\n\n            inline int syevr (char jobz, char range, char uplo, integer n, \n                              double* a, integer lda, double vl, double vu, integer il, \n                              integer iu, double abstol, integer *m, double *w, \n                              double *z, integer ldz, integer *isuppz, double *work, \n                              integer lwork, integer *iwork, integer liwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(dsyevr)(&jobz, &range, &uplo, &n,\n                                        a, &lda, &vl, &vu, &il,\n                                        &iu, &abstol, m, w,\n                                        z, &ldz, isuppz, work,\n                                        &lwork, iwork, &liwork, &info);\n                return info;\n            }\n\n            inline int syevr (char jobz, char range, char uplo, integer n, \n                              float* a, integer lda, float vl, float vu, integer il, \n                              integer iu, float abstol, integer *m, float *w, \n                              float *z, integer ldz, integer *isuppz, float *work, \n                              integer lwork, integer *iwork, integer liwork)\n            {\n                integer info = 0;\n                DLIB_FORTRAN_ID(ssyevr)(&jobz, &range, &uplo, &n,\n                                        a, &lda, &vl, &vu, &il,\n                                        &iu, &abstol, m, w,\n                                        z, &ldz, isuppz, work,\n                                        &lwork, iwork, &liwork, &info);\n                return info;\n            }\n\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        /*\n\n*  -- LAPACK driver routine (version 3.1) --\n*     Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..\n*     November 2006\n*\n*     .. Scalar Arguments ..\n      CHARACTER          JOBZ, RANGE, UPLO\n      INTEGER            IL, INFO, IU, LDA, LDZ, LIWORK, LWORK, M, N\n      DOUBLE PRECISION   ABSTOL, VL, VU\n*     ..\n*     .. Array Arguments ..\n      INTEGER            ISUPPZ( * ), IWORK( * )\n      DOUBLE PRECISION   A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * )\n*     ..\n*\n*  Purpose\n*  =======\n*\n*  DSYEVR computes selected eigenvalues and, optionally, eigenvectors\n*  of a real symmetric matrix A.  Eigenvalues and eigenvectors can be\n*  selected by specifying either a range of values or a range of\n*  indices for the desired eigenvalues.\n*\n*  DSYEVR first reduces the matrix A to tridiagonal form T with a call\n*  to DSYTRD.  Then, whenever possible, DSYEVR calls DSTEMR to compute\n*  the eigenspectrum using Relatively Robust Representations.  DSTEMR\n*  computes eigenvalues by the dqds algorithm, while orthogonal\n*  eigenvectors are computed from various \"good\" L D L^T representations\n*  (also known as Relatively Robust Representations). Gram-Schmidt\n*  orthogonalization is avoided as far as possible. More specifically,\n*  the various steps of the algorithm are as follows.\n*\n*  For each unreduced block (submatrix) of T,\n*     (a) Compute T - sigma I  = L D L^T, so that L and D\n*         define all the wanted eigenvalues to high relative accuracy.\n*         This means that small relative changes in the entries of D and L\n*         cause only small relative changes in the eigenvalues and\n*         eigenvectors. The standard (unfactored) representation of the\n*         tridiagonal matrix T does not have this property in general.\n*     (b) Compute the eigenvalues to suitable accuracy.\n*         If the eigenvectors are desired, the algorithm attains full\n*         accuracy of the computed eigenvalues only right before\n*         the corresponding vectors have to be computed, see steps c) and d).\n*     (c) For each cluster of close eigenvalues, select a new\n*         shift close to the cluster, find a new factorization, and refine\n*         the shifted eigenvalues to suitable accuracy.\n*     (d) For each eigenvalue with a large enough relative separation compute\n*         the corresponding eigenvector by forming a rank revealing twisted\n*         factorization. Go back to (c) for any clusters that remain.\n*\n*  The desired accuracy of the output can be specified by the input\n*  parameter ABSTOL.\n*\n*  For more details, see DSTEMR's documentation and:\n*  - Inderjit S. Dhillon and Beresford N. Parlett: \"Multiple representations\n*    to compute orthogonal eigenvectors of symmetric tridiagonal matrices,\"\n*    Linear Algebra and its Applications, 387(1), pp. 1-28, August 2004.\n*  - Inderjit Dhillon and Beresford Parlett: \"Orthogonal Eigenvectors and\n*    Relative Gaps,\" SIAM Journal on Matrix Analysis and Applications, Vol. 25,\n*    2004.  Also LAPACK Working Note 154.\n*  - Inderjit Dhillon: \"A new O(n^2) algorithm for the symmetric\n*    tridiagonal eigenvalue/eigenvector problem\",\n*    Computer Science Division Technical Report No. UCB/CSD-97-971,\n*    UC Berkeley, May 1997.\n*\n*\n*  Note 1 : DSYEVR calls DSTEMR when the full spectrum is requested\n*  on machines which conform to the ieee-754 floating point standard.\n*  DSYEVR calls DSTEBZ and SSTEIN on non-ieee machines and\n*  when partial spectrum requests are made.\n*\n*  Normal execution of DSTEMR may create NaNs and infinities and\n*  hence may abort due to a floating point exception in environments\n*  which do not handle NaNs and infinities in the ieee standard default\n*  manner.\n*\n*  Arguments\n*  =========\n*\n*  JOBZ    (input) CHARACTER*1\n*          = 'N':  Compute eigenvalues only;\n*          = 'V':  Compute eigenvalues and eigenvectors.\n*\n*  RANGE   (input) CHARACTER*1\n*          = 'A': all eigenvalues will be found.\n*          = 'V': all eigenvalues in the half-open interval (VL,VU]\n*                 will be found.\n*          = 'I': the IL-th through IU-th eigenvalues will be found.\n********** For RANGE = 'V' or 'I' and IU - IL < N - 1, DSTEBZ and\n********** DSTEIN are called\n*\n*  UPLO    (input) CHARACTER*1\n*          = 'U':  Upper triangle of A is stored;\n*          = 'L':  Lower triangle of A is stored.\n*\n*  N       (input) INTEGER\n*          The order of the matrix A.  N >= 0.\n*\n*  A       (input/output) DOUBLE PRECISION array, dimension (LDA, N)\n*          On entry, the symmetric matrix A.  If UPLO = 'U', the\n*          leading N-by-N upper triangular part of A contains the\n*          upper triangular part of the matrix A.  If UPLO = 'L',\n*          the leading N-by-N lower triangular part of A contains\n*          the lower triangular part of the matrix A.\n*          On exit, the lower triangle (if UPLO='L') or the upper\n*          triangle (if UPLO='U') of A, including the diagonal, is\n*          destroyed.\n*\n*  LDA     (input) INTEGER\n*          The leading dimension of the array A.  LDA >= max(1,N).\n*\n*  VL      (input) DOUBLE PRECISION\n*  VU      (input) DOUBLE PRECISION\n*          If RANGE='V', the lower and upper bounds of the interval to\n*          be searched for eigenvalues. VL < VU.\n*          Not referenced if RANGE = 'A' or 'I'.\n*\n*  IL      (input) INTEGER\n*  IU      (input) INTEGER\n*          If RANGE='I', the indices (in ascending order) of the\n*          smallest and largest eigenvalues to be returned.\n*          1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0.\n*          Not referenced if RANGE = 'A' or 'V'.\n*\n*  ABSTOL  (input) DOUBLE PRECISION\n*          The absolute error tolerance for the eigenvalues.\n*          An approximate eigenvalue is accepted as converged\n*          when it is determined to lie in an interval [a,b]\n*          of width less than or equal to\n*\n*                  ABSTOL + EPS *   max( |a|,|b| ) ,\n*\n*          where EPS is the machine precision.  If ABSTOL is less than\n*          or equal to zero, then  EPS*|T|  will be used in its place,\n*          where |T| is the 1-norm of the tridiagonal matrix obtained\n*          by reducing A to tridiagonal form.\n*\n*          See \"Computing Small Singular Values of Bidiagonal Matrices\n*          with Guaranteed High Relative Accuracy,\" by Demmel and\n*          Kahan, LAPACK Working Note #3.\n*\n*          If high relative accuracy is important, set ABSTOL to\n*          DLAMCH( 'Safe minimum' ).  Doing so will guarantee that\n*          eigenvalues are computed to high relative accuracy when\n*          possible in future releases.  The current code does not\n*          make any guarantees about high relative accuracy, but\n*          future releases will. See J. Barlow and J. Demmel,\n*          \"Computing Accurate Eigensystems of Scaled Diagonally\n*          Dominant Matrices\", LAPACK Working Note #7, for a discussion\n*          of which matrices define their eigenvalues to high relative\n*          accuracy.\n*\n*  M       (output) INTEGER\n*          The total number of eigenvalues found.  0 <= M <= N.\n*          If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.\n*\n*  W       (output) DOUBLE PRECISION array, dimension (N)\n*          The first M elements contain the selected eigenvalues in\n*          ascending order.\n*\n*  Z       (output) DOUBLE PRECISION array, dimension (LDZ, max(1,M))\n*          If JOBZ = 'V', then if INFO = 0, the first M columns of Z\n*          contain the orthonormal eigenvectors of the matrix A\n*          corresponding to the selected eigenvalues, with the i-th\n*          column of Z holding the eigenvector associated with W(i).\n*          If JOBZ = 'N', then Z is not referenced.\n*          Note: the user must ensure that at least max(1,M) columns are\n*          supplied in the array Z; if RANGE = 'V', the exact value of M\n*          is not known in advance and an upper bound must be used.\n*          Supplying N columns is always safe.\n*\n*  LDZ     (input) INTEGER\n*          The leading dimension of the array Z.  LDZ >= 1, and if\n*          JOBZ = 'V', LDZ >= max(1,N).\n*\n*  ISUPPZ  (output) INTEGER array, dimension ( 2*max(1,M) )\n*          The support of the eigenvectors in Z, i.e., the indices\n*          indicating the nonzero elements in Z. The i-th eigenvector\n*          is nonzero only in elements ISUPPZ( 2*i-1 ) through\n*          ISUPPZ( 2*i ).\n********** Implemented only for RANGE = 'A' or 'I' and IU - IL = N - 1\n*\n*  WORK    (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))\n*          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.\n*\n*  LWORK   (input) INTEGER\n*          The dimension of the array WORK.  LWORK >= max(1,26*N).\n*          For optimal efficiency, LWORK >= (NB+6)*N,\n*          where NB is the max of the blocksize for DSYTRD and DORMTR\n*          returned by ILAENV.\n*\n*          If LWORK = -1, then a workspace query is assumed; the routine\n*          only calculates the optimal size of the WORK array, returns\n*          this value as the first entry of the WORK array, and no error\n*          message related to LWORK is issued by XERBLA.\n*\n*  IWORK   (workspace/output) INTEGER array, dimension (MAX(1,LIWORK))\n*          On exit, if INFO = 0, IWORK(1) returns the optimal LWORK.\n*\n*  LIWORK  (input) INTEGER\n*          The dimension of the array IWORK.  LIWORK >= max(1,10*N).\n*\n*          If LIWORK = -1, then a workspace query is assumed; the\n*          routine only calculates the optimal size of the IWORK array,\n*          returns this value as the first entry of the IWORK array, and\n*          no error message related to LIWORK is issued by XERBLA.\n*\n*  INFO    (output) INTEGER\n*          = 0:  successful exit\n*          < 0:  if INFO = -i, the i-th argument had an illegal value\n*          > 0:  Internal error\n*\n*  Further Details\n*  ===============\n*\n*  Based on contributions by\n*     Inderjit Dhillon, IBM Almaden, USA\n*     Osni Marques, LBNL/NERSC, USA\n*     Ken Stanley, Computer Science Division, University of\n*       California at Berkeley, USA\n*     Jason Riedy, Computer Science Division, University of\n*       California at Berkeley, USA\n*\n* =====================================================================\n\n        */\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int syevr (\n            const char jobz,\n            const char range,\n            const char uplo,\n            matrix<T,NR1,NC1,MM,column_major_layout>& a,\n            const double vl,\n            const double vu,\n            const integer il,\n            const integer iu,\n            const double abstol,\n            integer& num_eigenvalues_found,\n            matrix<T,NR2,NC2,MM,column_major_layout>& w,\n            matrix<T,NR3,NC3,MM,column_major_layout>& z,\n            matrix<integer,NR4,NC4,MM,column_major_layout>& isuppz\n        )\n        {\n            matrix<T,0,1,MM,column_major_layout> work;\n            matrix<integer,0,1,MM,column_major_layout> iwork;\n\n            const long n = a.nr();\n\n            w.set_size(n,1);\n\n            isuppz.set_size(2*n, 1);\n\n            if (jobz == 'V')\n            {\n                z.set_size(n,n);\n            }\n            else\n            {\n                z.set_size(NR3?NR3:1, NC3?NC3:1);\n            }\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            integer iwork_size = 1;\n            int info = binding::syevr(jobz, range, uplo, n, &a(0,0),\n                                      a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,\n                                      &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work_size, -1,\n                                      &iwork_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n            if (iwork.size() < iwork_size)\n                iwork.set_size(iwork_size, 1);\n\n            // compute the actual decomposition \n            info = binding::syevr(jobz, range, uplo, n, &a(0,0),\n                                  a.nr(), vl, vu, il, iu, abstol, &num_eigenvalues_found,\n                                  &w(0,0), &z(0,0), z.nr(), &isuppz(0,0), &work(0,0), work.size(),\n                                  &iwork(0,0), iwork.size());\n\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, \n            long NR1, long NR2, long NR3, long NR4,\n            long NC1, long NC2, long NC3, long NC4,\n            typename MM\n            >\n        int syevr (\n            const char jobz,\n            const char range,\n            char uplo,\n            matrix<T,NR1,NC1,MM,row_major_layout>& a,\n            const double vl,\n            const double vu,\n            const integer il,\n            const integer iu,\n            const double abstol,\n            integer& num_eigenvalues_found,\n            matrix<T,NR2,NC2,MM,row_major_layout>& w,\n            matrix<T,NR3,NC3,MM,row_major_layout>& z,\n            matrix<integer,NR4,NC4,MM,row_major_layout>& isuppz\n        )\n        {\n            matrix<T,0,1,MM,row_major_layout> work;\n            matrix<integer,0,1,MM,row_major_layout> iwork;\n\n            if (uplo == 'L')\n                uplo = 'U';\n            else\n                uplo = 'L';\n\n            const long n = a.nr();\n\n            w.set_size(n,1);\n\n            isuppz.set_size(2*n, 1);\n\n            if (jobz == 'V')\n            {\n                z.set_size(n,n);\n            }\n            else\n            {\n                z.set_size(NR3?NR3:1, NC3?NC3:1);\n            }\n\n            // figure out how big the workspace needs to be.\n            T work_size = 1;\n            integer iwork_size = 1;\n            int info = binding::syevr(jobz, range, uplo, n, &a(0,0),\n                                      a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,\n                                      &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work_size, -1,\n                                      &iwork_size, -1);\n\n            if (info != 0)\n                return info;\n\n            if (work.size() < work_size)\n                work.set_size(static_cast<long>(work_size), 1);\n            if (iwork.size() < iwork_size)\n                iwork.set_size(iwork_size, 1);\n\n            // compute the actual decomposition \n            info = binding::syevr(jobz, range, uplo, n, &a(0,0),\n                                  a.nc(), vl, vu, il, iu, abstol, &num_eigenvalues_found,\n                                  &w(0,0), &z(0,0), z.nc(), &isuppz(0,0), &work(0,0), work.size(),\n                                  &iwork(0,0), iwork.size());\n\n            z = trans(z);\n\n            return info;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_LAPACk_EVR_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_\n#define DLIB_MATRIx_\n\n#include \"matrix_exp.h\"\n#include \"matrix_abstract.h\"\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../enable_if.h\"\n#include <sstream>\n#include <algorithm>\n#include \"../memory_manager.h\"\n#include \"../is_kind.h\"\n#include \"matrix_data_layout.h\"\n#include \"matrix_assign_fwd.h\"\n#include \"matrix_op.h\"\n#include <utility>\n#ifdef DLIB_HAS_INITIALIZER_LISTS\n#include <initializer_list>\n#endif\n\n#ifdef MATLAB_MEX_FILE\n#include <mex.h>\n#endif\n\n#ifdef _MSC_VER\n#pragma warning(push)\n\n// Disable the following warnings for Visual Studio\n\n// This warning is:\n//    \"warning C4355: 'this' : used in base member initializer list\"\n// Which we get from this code but it is not an error so I'm turning this\n// warning off and then turning it back on at the end of the file.\n#pragma warning(disable : 4355)\n\n// \"warning C4723: potential divide by 0\" - This warning is triggered in\n// matrix(const std::initializer_list<T>& l) where the compiler can see that\n// matrix<> was templated in a way making NR ending up 0, but division by 0 at runtime\n// is not possible because the division operation is inside \"if (NR!=0)\" block.\n#pragma warning(disable : 4723)\n\n// \"warning C4724: potential mod by 0\" - This warning is triggered in\n// matrix(const std::initializer_list<T>& l) where the compiler can see that\n// matrix<> was templated in a way making NR ending up 0, but mod by 0 at runtime\n// is not possible because the mod operation is inside \"if (NR!=0)\" block.\n#pragma warning(disable : 4724)\n\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    // This template will perform the needed loop for element multiplication using whichever\n    // dimension is provided as a compile time constant (if one is at all).\n    template <\n        typename LHS,\n        typename RHS,\n        long lhs_nc = LHS::NC,\n        long rhs_nr = RHS::NR\n        >\n    struct matrix_multiply_helper \n    {\n        typedef typename LHS::type type;\n        template <typename RHS_, typename LHS_>\n        inline const static type  eval (\n            const RHS_& rhs,\n            const LHS_& lhs,\n            const long r, \n            const long c\n        )  \n        { \n            type temp = lhs(r,0)*rhs(0,c);\n            for (long i = 1; i < rhs.nr(); ++i)\n            {\n                temp += lhs(r,i)*rhs(i,c);\n            }\n            return temp;\n        }\n    };\n\n    template <\n        typename LHS,\n        typename RHS,\n        long lhs_nc \n        >\n    struct matrix_multiply_helper <LHS,RHS,lhs_nc,0>\n    {\n        typedef typename LHS::type type;\n        template <typename RHS_, typename LHS_>\n        inline const static type  eval (\n            const RHS_& rhs,\n            const LHS_& lhs,\n            const long r, \n            const long c\n        )  \n        { \n            type temp = lhs(r,0)*rhs(0,c);\n            for (long i = 1; i < lhs.nc(); ++i)\n            {\n                temp += lhs(r,i)*rhs(i,c);\n            }\n            return temp;\n        }\n    };\n\n    template <typename LHS, typename RHS>\n    class matrix_multiply_exp;\n\n    template <typename LHS, typename RHS>\n    struct matrix_traits<matrix_multiply_exp<LHS,RHS> >\n    {\n        typedef typename LHS::type type;\n        typedef typename LHS::type const_ret_type;\n        typedef typename LHS::mem_manager_type mem_manager_type;\n        typedef typename LHS::layout_type layout_type;\n        const static long NR = LHS::NR;\n        const static long NC = RHS::NC;\n\n#ifdef DLIB_USE_BLAS\n        // if there are BLAS functions to be called then we want to make sure we\n        // always evaluate any complex expressions so that the BLAS bindings can happen.\n        const static bool lhs_is_costly = (LHS::cost > 2)&&(RHS::NC != 1 || LHS::cost >= 10000);\n        const static bool rhs_is_costly = (RHS::cost > 2)&&(LHS::NR != 1 || RHS::cost >= 10000);\n#else\n        const static bool lhs_is_costly = (LHS::cost > 4)&&(RHS::NC != 1);\n        const static bool rhs_is_costly = (RHS::cost > 4)&&(LHS::NR != 1);\n#endif\n\n        // Note that if we decide that one of the matrices is too costly we will evaluate it\n        // into a temporary.  Doing this resets its cost back to 1.\n        const static long lhs_cost = ((lhs_is_costly==true)? 1 : (LHS::cost));\n        const static long rhs_cost = ((rhs_is_costly==true)? 1 : (RHS::cost));\n\n        // The cost of evaluating an element of a matrix multiply is the cost of evaluating elements from\n        // RHS and LHS times the number of rows/columns in the RHS/LHS matrix.  If we don't know the matrix\n        // dimensions then just assume it is really large.\n        const static long cost = ((tmax<LHS::NC,RHS::NR>::value!=0)? ((lhs_cost+rhs_cost)*tmax<LHS::NC,RHS::NR>::value):(10000));\n    };\n\n    template <typename T, bool is_ref> struct conditional_matrix_temp { typedef typename T::matrix_type type; };\n    template <typename T> struct conditional_matrix_temp<T,true>      { typedef T& type; };\n\n    template <\n        typename LHS,\n        typename RHS\n        >\n    class matrix_multiply_exp : public matrix_exp<matrix_multiply_exp<LHS,RHS> >\n    {\n        /*!\n            REQUIREMENTS ON LHS AND RHS\n                - must be matrix_exp objects.\n        !*/\n    public:\n\n        typedef typename matrix_traits<matrix_multiply_exp>::type type;\n        typedef typename matrix_traits<matrix_multiply_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_multiply_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_multiply_exp>::NR;\n        const static long NC = matrix_traits<matrix_multiply_exp>::NC;\n        const static long cost = matrix_traits<matrix_multiply_exp>::cost;\n        typedef typename matrix_traits<matrix_multiply_exp>::layout_type layout_type;\n\n\n        const static bool lhs_is_costly = matrix_traits<matrix_multiply_exp>::lhs_is_costly;\n        const static bool rhs_is_costly = matrix_traits<matrix_multiply_exp>::rhs_is_costly;\n        const static bool either_is_costly = lhs_is_costly || rhs_is_costly;\n        const static bool both_are_costly = lhs_is_costly && rhs_is_costly;\n\n        typedef typename conditional_matrix_temp<const LHS,lhs_is_costly == false>::type LHS_ref_type;\n        typedef typename conditional_matrix_temp<const RHS,rhs_is_costly == false>::type RHS_ref_type;\n\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of objects.\n        template <typename T1, typename T2>\n        matrix_multiply_exp (T1,T2); \n\n        inline matrix_multiply_exp (\n            const LHS& lhs_,\n            const RHS& rhs_\n        ) :\n            lhs(lhs_),\n            rhs(rhs_)\n        {\n            // You are trying to multiply two incompatible matrices together.  The number of columns \n            // in the matrix on the left must match the number of rows in the matrix on the right.\n            COMPILE_TIME_ASSERT(LHS::NC == RHS::NR || LHS::NC*RHS::NR == 0);\n            DLIB_ASSERT(lhs.nc() == rhs.nr() && lhs.size() > 0 && rhs.size() > 0, \n                \"\\tconst matrix_exp operator*(const matrix_exp& lhs, const matrix_exp& rhs)\"\n                << \"\\n\\tYou are trying to multiply two incompatible matrices together\"\n                << \"\\n\\tlhs.nr(): \" << lhs.nr()\n                << \"\\n\\tlhs.nc(): \" << lhs.nc()\n                << \"\\n\\trhs.nr(): \" << rhs.nr()\n                << \"\\n\\trhs.nc(): \" << rhs.nc()\n                << \"\\n\\t&lhs: \" << &lhs \n                << \"\\n\\t&rhs: \" << &rhs \n                );\n\n            // You can't multiply matrices together if they don't both contain the same type of elements.\n            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));\n        }\n\n        inline const type operator() (\n            const long r, \n            const long c\n        ) const \n        { \n            return matrix_multiply_helper<LHS,RHS>::eval(rhs,lhs,r,c);\n        }\n\n        inline const type operator() ( long i ) const \n        { return matrix_exp<matrix_multiply_exp>::operator()(i); }\n\n        long nr (\n        ) const { return lhs.nr(); }\n\n        long nc (\n        ) const { return rhs.nc(); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return lhs.aliases(item) || rhs.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return aliases(item); }\n\n        LHS_ref_type lhs;\n        RHS_ref_type rhs;\n    };\n\n    template < typename EXP1, typename EXP2 >\n    inline const matrix_multiply_exp<EXP1, EXP2> operator* (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        return matrix_multiply_exp<EXP1, EXP2>(m1.ref(), m2.ref());\n    }\n\n    template <typename M, bool use_reference = true>\n    class matrix_mul_scal_exp;\n\n    // -------------------------\n\n    // Now we declare some overloads that cause any scalar multiplications to percolate \n    // up and outside of any matrix multiplies.  Note that we are using the non-reference containing\n    // mode of the matrix_mul_scal_exp object since we are passing in locally constructed matrix_multiply_exp \n    // objects.  So the matrix_mul_scal_exp object will contain copies of matrix_multiply_exp objects\n    // rather than references to them.  This could result in extra matrix copies if the matrix_multiply_exp\n    // decided it should evaluate any of its arguments.  So we also try to not apply this percolating operation \n    // if the matrix_multiply_exp would contain a fully evaluated copy of the original matrix_mul_scal_exp \n    // expression.\n    // \n    // Also, the reason we want to apply this transformation in the first place is because it (1) makes\n    // the expressions going into matrix multiply expressions simpler and (2) it makes it a lot more\n    // straightforward to bind BLAS calls to matrix expressions involving scalar multiplies.\n    template < typename EXP1, typename EXP2 >\n    inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, matrix_mul_scal_exp<EXP2> >::both_are_costly ,      \n                                        matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (\n        const matrix_mul_scal_exp<EXP1>& m1,\n        const matrix_mul_scal_exp<EXP2>& m2\n    )\n    {\n        typedef matrix_multiply_exp<EXP1, EXP2> exp1;\n        typedef matrix_mul_scal_exp<exp1,false> exp2;\n        return exp2(exp1(m1.m, m2.m), m1.s*m2.s);\n    }\n\n    template < typename EXP1, typename EXP2 >\n    inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, EXP2 >::lhs_is_costly ,      \n                                      matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (\n        const matrix_mul_scal_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        typedef matrix_multiply_exp<EXP1, EXP2> exp1;\n        typedef matrix_mul_scal_exp<exp1,false> exp2;\n        return exp2(exp1(m1.m, m2.ref()), m1.s);\n    }\n\n    template < typename EXP1, typename EXP2 >\n    inline const typename disable_if_c< matrix_multiply_exp<EXP1, matrix_mul_scal_exp<EXP2> >::rhs_is_costly ,      \n                                      matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (\n        const matrix_exp<EXP1>& m1,\n        const matrix_mul_scal_exp<EXP2>& m2\n    )\n    {\n        typedef matrix_multiply_exp<EXP1, EXP2> exp1;\n        typedef matrix_mul_scal_exp<exp1,false> exp2;\n        return exp2(exp1(m1.ref(), m2.m), m2.s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename LHS, typename RHS>\n    class matrix_add_exp;\n\n    template <typename LHS, typename RHS>\n    struct matrix_traits<matrix_add_exp<LHS,RHS> >\n    {\n        typedef typename LHS::type type;\n        typedef typename LHS::type const_ret_type;\n        typedef typename LHS::mem_manager_type mem_manager_type;\n        typedef typename LHS::layout_type layout_type;\n        const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;\n        const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;\n        const static long cost = LHS::cost+RHS::cost+1;\n    };\n\n    template <\n        typename LHS,\n        typename RHS\n        >\n    class matrix_add_exp : public matrix_exp<matrix_add_exp<LHS,RHS> >\n    {\n        /*!\n            REQUIREMENTS ON LHS AND RHS\n                - must be matrix_exp objects. \n        !*/\n    public:\n        typedef typename matrix_traits<matrix_add_exp>::type type;\n        typedef typename matrix_traits<matrix_add_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_add_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_add_exp>::NR;\n        const static long NC = matrix_traits<matrix_add_exp>::NC;\n        const static long cost = matrix_traits<matrix_add_exp>::cost;\n        typedef typename matrix_traits<matrix_add_exp>::layout_type layout_type;\n\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of objects.\n        template <typename T1, typename T2>\n        matrix_add_exp (T1,T2); \n\n        matrix_add_exp (\n            const LHS& lhs_,\n            const RHS& rhs_\n        ) :\n            lhs(lhs_),\n            rhs(rhs_)\n        {\n            // You can only add matrices together if they both have the same number of rows and columns.\n            COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);\n            COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);\n            DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                   lhs.nr() == rhs.nr(), \n                \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n                << \"\\n\\tYou are trying to add two incompatible matrices together\"\n                << \"\\n\\tlhs.nr(): \" << lhs.nr()\n                << \"\\n\\tlhs.nc(): \" << lhs.nc()\n                << \"\\n\\trhs.nr(): \" << rhs.nr()\n                << \"\\n\\trhs.nc(): \" << rhs.nc()\n                << \"\\n\\t&lhs: \" << &lhs \n                << \"\\n\\t&rhs: \" << &rhs \n                );\n\n            // You can only add matrices together if they both contain the same types of elements.\n            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));\n        }\n\n        const type operator() (\n            long r, \n            long c\n        ) const { return lhs(r,c) + rhs(r,c); }\n\n        inline const type operator() ( long i ) const \n        { return matrix_exp<matrix_add_exp>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return lhs.aliases(item) || rhs.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }\n\n        long nr (\n        ) const { return lhs.nr(); }\n\n        long nc (\n        ) const { return lhs.nc(); }\n\n        const LHS& lhs;\n        const RHS& rhs;\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_add_exp<EXP1, EXP2> operator+ (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        return matrix_add_exp<EXP1, EXP2>(m1.ref(),m2.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename LHS, typename RHS>\n    class matrix_subtract_exp;\n\n    template <typename LHS, typename RHS>\n    struct matrix_traits<matrix_subtract_exp<LHS,RHS> >\n    {\n        typedef typename LHS::type type;\n        typedef typename LHS::type const_ret_type;\n        typedef typename LHS::mem_manager_type mem_manager_type;\n        typedef typename LHS::layout_type layout_type;\n        const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;\n        const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;\n        const static long cost = LHS::cost+RHS::cost+1;\n    };\n\n    template <\n        typename LHS,\n        typename RHS\n        >\n    class matrix_subtract_exp : public matrix_exp<matrix_subtract_exp<LHS,RHS> >\n    {\n        /*!\n            REQUIREMENTS ON LHS AND RHS\n                - must be matrix_exp objects. \n        !*/\n    public:\n        typedef typename matrix_traits<matrix_subtract_exp>::type type;\n        typedef typename matrix_traits<matrix_subtract_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_subtract_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_subtract_exp>::NR;\n        const static long NC = matrix_traits<matrix_subtract_exp>::NC;\n        const static long cost = matrix_traits<matrix_subtract_exp>::cost;\n        typedef typename matrix_traits<matrix_subtract_exp>::layout_type layout_type;\n\n\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of objects.\n        template <typename T1, typename T2>\n        matrix_subtract_exp (T1,T2); \n\n        matrix_subtract_exp (\n            const LHS& lhs_,\n            const RHS& rhs_\n        ) : \n            lhs(lhs_),\n            rhs(rhs_)\n        {\n            // You can only subtract one matrix from another if they both have the same number of rows and columns.\n            COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);\n            COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);\n            DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                   lhs.nr() == rhs.nr(), \n                \"\\tconst matrix_exp operator-(const matrix_exp& lhs, const matrix_exp& rhs)\"\n                << \"\\n\\tYou are trying to subtract two incompatible matrices\"\n                << \"\\n\\tlhs.nr(): \" << lhs.nr()\n                << \"\\n\\tlhs.nc(): \" << lhs.nc()\n                << \"\\n\\trhs.nr(): \" << rhs.nr()\n                << \"\\n\\trhs.nc(): \" << rhs.nc()\n                << \"\\n\\t&lhs: \" << &lhs \n                << \"\\n\\t&rhs: \" << &rhs \n                );\n\n            // You can only subtract one matrix from another if they both contain elements of the same type.\n            COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));\n        }\n\n        const type operator() (\n            long r, \n            long c\n        ) const { return lhs(r,c) - rhs(r,c); }\n\n        inline const type operator() ( long i ) const \n        { return matrix_exp<matrix_subtract_exp>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return lhs.aliases(item) || rhs.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }\n\n        long nr (\n        ) const { return lhs.nr(); }\n\n        long nc (\n        ) const { return lhs.nc(); }\n\n        const LHS& lhs;\n        const RHS& rhs;\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_subtract_exp<EXP1, EXP2> operator- (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        return matrix_subtract_exp<EXP1, EXP2>(m1.ref(),m2.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    class matrix_div_scal_exp;\n\n    template <typename M>\n    struct matrix_traits<matrix_div_scal_exp<M> >\n    {\n        typedef typename M::type type;\n        typedef typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        const static long cost = M::cost+1;\n    };\n\n    template <\n        typename M\n        >\n    class matrix_div_scal_exp : public matrix_exp<matrix_div_scal_exp<M> >\n    {\n        /*!\n            REQUIREMENTS ON M \n                - must be a matrix_exp object.\n        !*/\n    public:\n        typedef typename matrix_traits<matrix_div_scal_exp>::type type;\n        typedef typename matrix_traits<matrix_div_scal_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_div_scal_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_div_scal_exp>::NR;\n        const static long NC = matrix_traits<matrix_div_scal_exp>::NC;\n        const static long cost = matrix_traits<matrix_div_scal_exp>::cost;\n        typedef typename matrix_traits<matrix_div_scal_exp>::layout_type layout_type;\n\n\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of objects.\n        template <typename T1>\n        matrix_div_scal_exp (T1, const type&); \n\n        matrix_div_scal_exp (\n            const M& m_,\n            const type& s_\n        ) :\n            m(m_),\n            s(s_)\n        {}\n\n        const type operator() (\n            long r, \n            long c\n        ) const { return m(r,c)/s; }\n\n        inline const type operator() ( long i ) const \n        { return matrix_exp<matrix_div_scal_exp>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return m.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return m.destructively_aliases(item); }\n\n        long nr (\n        ) const { return m.nr(); }\n\n        long nc (\n        ) const { return m.nc(); }\n\n        const M& m;\n        const type s;\n    };\n\n    template <\n        typename EXP,\n        typename S\n        >\n    inline const typename enable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_div_scal_exp<EXP> >::type operator/ (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        return matrix_div_scal_exp<EXP>(m.ref(),static_cast<typename EXP::type>(s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, bool use_reference >\n    struct matrix_traits<matrix_mul_scal_exp<M,use_reference> >\n    {\n        typedef typename M::type type;\n        typedef typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        const static long cost = M::cost+1;\n    };\n\n    template <typename T, bool is_ref> struct conditional_reference { typedef T type; };\n    template <typename T> struct conditional_reference<T,true>      { typedef T& type; };\n\n\n    template <\n        typename M,\n        bool use_reference\n        >\n    class matrix_mul_scal_exp : public matrix_exp<matrix_mul_scal_exp<M,use_reference> >\n    {\n        /*!\n            REQUIREMENTS ON M \n                - must be a matrix_exp object.\n\n        !*/\n    public:\n        typedef typename matrix_traits<matrix_mul_scal_exp>::type type;\n        typedef typename matrix_traits<matrix_mul_scal_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_mul_scal_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_mul_scal_exp>::NR;\n        const static long NC = matrix_traits<matrix_mul_scal_exp>::NC;\n        const static long cost = matrix_traits<matrix_mul_scal_exp>::cost;\n        typedef typename matrix_traits<matrix_mul_scal_exp>::layout_type layout_type;\n\n        // You aren't allowed to multiply a matrix of matrices by a scalar.   \n        COMPILE_TIME_ASSERT(is_matrix<type>::value == false);\n\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of objects.\n        template <typename T1>\n        matrix_mul_scal_exp (T1, const type&); \n\n        matrix_mul_scal_exp (\n            const M& m_,\n            const type& s_\n        ) :\n            m(m_),\n            s(s_)\n        {}\n\n        const type operator() (\n            long r, \n            long c\n        ) const { return m(r,c)*s; }\n\n        inline const type operator() ( long i ) const \n        { return matrix_exp<matrix_mul_scal_exp>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return m.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return m.destructively_aliases(item); }\n\n        long nr (\n        ) const { return m.nr(); }\n\n        long nc (\n        ) const { return m.nc(); }\n\n        typedef typename conditional_reference<const M,use_reference>::type M_ref_type;\n\n        M_ref_type m;\n        const type s;\n    };\n\n    template <\n        typename EXP,\n        typename S \n        >\n    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        typedef typename EXP::type type;\n        return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));\n    }\n\n    template <\n        typename EXP,\n        typename S,\n        bool B\n        >\n    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (\n        const matrix_mul_scal_exp<EXP,B>& m,\n        const S& s\n    )\n    {\n        typedef typename EXP::type type;\n        return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);\n    }\n\n    template <\n        typename EXP,\n        typename S \n        >\n    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename EXP::type type;\n        return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));\n    }\n\n    template <\n        typename EXP,\n        typename S,\n        bool B\n        >\n    inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (\n        const S& s,\n        const matrix_mul_scal_exp<EXP,B>& m\n    )\n    {\n        typedef typename EXP::type type;\n        return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);\n    }\n\n    template <\n        typename EXP ,\n        typename S\n        >\n    inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        typedef typename EXP::type type;\n        const type one = 1;\n        return matrix_mul_scal_exp<EXP>(m.ref(),one/static_cast<type>(s));\n    }\n\n    template <\n        typename EXP,\n        bool B,\n        typename S\n        >\n    inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (\n        const matrix_mul_scal_exp<EXP,B>& m,\n        const S& s\n    )\n    {\n        typedef typename EXP::type type;\n        return matrix_mul_scal_exp<EXP>(m.m,m.s/static_cast<type>(s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_s_div_m : basic_op_m<M> \n    {\n        typedef typename M::type type;\n\n        op_s_div_m( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+1;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return s/this->m(r,c);\n        }\n    };\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename disable_if<is_matrix<S>, matrix_op<op_s_div_m<EXP> > >::type operator/ (\n        const S& val,\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename EXP::type type;\n\n        typedef op_s_div_m<EXP> op;\n        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    inline const matrix_mul_scal_exp<EXP> operator- (\n        const matrix_exp<EXP>& m\n    )\n    {\n        return matrix_mul_scal_exp<EXP>(m.ref(),-1);\n    }\n\n    template <\n        typename EXP,\n        bool B\n        >\n    inline const matrix_mul_scal_exp<EXP> operator- (\n        const matrix_mul_scal_exp<EXP,B>& m\n    )\n    {\n        return matrix_mul_scal_exp<EXP>(m.m,-1*m.s);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_add_scalar : basic_op_m<M> \n    {\n        typedef typename M::type type;\n\n        op_add_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+1;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return this->m(r,c) + s;\n        }\n    };\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (\n        const matrix_exp<EXP>& m,\n        const T& val\n    )\n    {\n        typedef typename EXP::type type;\n\n        typedef op_add_scalar<EXP> op;\n        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));\n    }\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (\n        const T& val,\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename EXP::type type;\n\n        typedef op_add_scalar<EXP> op;\n        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_subl_scalar : basic_op_m<M> \n    {\n        typedef typename M::type type;\n\n        op_subl_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+1;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return s - this->m(r,c) ;\n        }\n    };\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const typename disable_if<is_matrix<T>, matrix_op<op_subl_scalar<EXP> > >::type operator- (\n        const T& val,\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename EXP::type type;\n\n        typedef op_subl_scalar<EXP> op;\n        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_subr_scalar : basic_op_m<M> \n    {\n        typedef typename M::type type;\n\n        op_subr_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+1;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return this->m(r,c) - s;\n        }\n    };\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const typename disable_if<is_matrix<T>, matrix_op<op_subr_scalar<EXP> > >::type operator- (\n        const matrix_exp<EXP>& m,\n        const T& val\n    )\n    {\n        typedef typename EXP::type type;\n\n        typedef op_subr_scalar<EXP> op;\n        return matrix_op<op>(op(m.ref(), static_cast<type>(val)));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    bool operator== (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        if (m1.nr() == m2.nr() && m1.nc() == m2.nc())\n        {\n            for (long r = 0; r < m1.nr(); ++r)\n            {\n                for (long c = 0; c < m1.nc(); ++c)\n                {\n                    if (m1(r,c) != m2(r,c))\n                        return false;\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline bool operator!= (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    ) { return !(m1 == m2); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_pointer_to_mat;\n    template <typename T>\n    struct op_pointer_to_col_vect;\n\n    template <\n        typename T,\n        long num_rows,\n        long num_cols,\n        typename mem_manager,\n        typename layout\n        >\n    struct matrix_traits<matrix<T,num_rows, num_cols, mem_manager, layout> >\n    {\n        typedef T type;\n        typedef const T& const_ret_type;\n        typedef mem_manager mem_manager_type;\n        typedef layout layout_type;\n        const static long NR = num_rows;\n        const static long NC = num_cols;\n        const static long cost = 1;\n\n    };\n\n    template <\n        typename T,\n        long num_rows,\n        long num_cols,\n        typename mem_manager,\n        typename layout\n        >\n    class matrix : public matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> > \n    {\n\n        COMPILE_TIME_ASSERT(num_rows >= 0 && num_cols >= 0); \n\n    public:\n        typedef typename matrix_traits<matrix>::type type;\n        typedef typename matrix_traits<matrix>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix>::mem_manager_type mem_manager_type;\n        typedef typename matrix_traits<matrix>::layout_type layout_type;\n        const static long NR = matrix_traits<matrix>::NR;\n        const static long NC = matrix_traits<matrix>::NC;\n        const static long cost = matrix_traits<matrix>::cost;\n        typedef T*          iterator;       \n        typedef const T*    const_iterator; \n\n        matrix () \n        {\n        }\n\n        explicit matrix (\n            long length \n        ) \n        {\n            // This object you are trying to call matrix(length) on is not a column or \n            // row vector.\n            COMPILE_TIME_ASSERT(NR == 1 || NC == 1);\n            DLIB_ASSERT( length >= 0, \n                \"\\tmatrix::matrix(length)\"\n                << \"\\n\\tlength must be at least 0\"\n                << \"\\n\\tlength: \" << length \n                << \"\\n\\tNR:     \" << NR \n                << \"\\n\\tNC:     \" << NC \n                << \"\\n\\tthis:   \" << this\n                );\n\n            if (NR == 1)\n            {\n                DLIB_ASSERT(NC == 0 || NC == length,\n                    \"\\tmatrix::matrix(length)\"\n                    << \"\\n\\tSince this is a statically sized matrix length must equal NC\"\n                    << \"\\n\\tlength: \" << length \n                    << \"\\n\\tNR:     \" << NR \n                    << \"\\n\\tNC:     \" << NC \n                    << \"\\n\\tthis:   \" << this\n                    );\n\n                data.set_size(1,length);\n            }\n            else\n            {\n                DLIB_ASSERT(NR == 0 || NR == length,\n                    \"\\tvoid matrix::set_size(length)\"\n                    << \"\\n\\tSince this is a statically sized matrix length must equal NR\"\n                    << \"\\n\\tlength: \" << length \n                    << \"\\n\\tNR:     \" << NR \n                    << \"\\n\\tNC:     \" << NC \n                    << \"\\n\\tthis:   \" << this\n                    );\n\n                data.set_size(length,1);\n            }\n        }\n\n        matrix (\n            long rows,\n            long cols \n        )  \n        {\n            DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) && \n                    rows >= 0 && cols >= 0, \n                \"\\tvoid matrix::matrix(rows, cols)\"\n                << \"\\n\\tYou have supplied conflicting matrix dimensions\"\n                << \"\\n\\trows: \" << rows\n                << \"\\n\\tcols: \" << cols\n                << \"\\n\\tNR:   \" << NR \n                << \"\\n\\tNC:   \" << NC \n                );\n            data.set_size(rows,cols);\n        }\n\n        template <typename EXP>\n        matrix (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // You get an error on this line if the matrix m contains a type that isn't\n            // the same as the type contained in the target matrix.\n            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||\n                                (is_matrix<typename EXP::type>::value == true));\n\n            // The matrix you are trying to assign m to is a statically sized matrix and \n            // m's dimensions don't match that of *this. \n            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);\n            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);\n            DLIB_ASSERT((NR == 0 || NR == m.nr()) && (NC == 0 || NC == m.nc()), \n                \"\\tmatrix& matrix::matrix(const matrix_exp& m)\"\n                << \"\\n\\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size\"\n                << \"\\n\\tNR:     \" << NR\n                << \"\\n\\tNC:     \" << NC\n                << \"\\n\\tm.nr(): \" << m.nr()\n                << \"\\n\\tm.nc(): \" << m.nc()\n                << \"\\n\\tthis:   \" << this\n                );\n\n            data.set_size(m.nr(),m.nc());\n\n            matrix_assign(*this, m);\n        }\n\n        matrix (\n            const matrix& m\n        ) : matrix_exp<matrix>(*this) \n        {\n            data.set_size(m.nr(),m.nc());\n            matrix_assign(*this, m);\n        }\n\n#ifdef DLIB_HAS_INITIALIZER_LISTS\n        matrix(const std::initializer_list<T>& l)\n        {\n            if (NR*NC != 0)\n            {\n                DLIB_ASSERT(l.size() == NR*NC, \n                    \"\\t matrix::matrix(const std::initializer_list& l)\"\n                    << \"\\n\\t You are trying to initialize a statically sized matrix with a list that doesn't have a matching size.\"\n                    << \"\\n\\t l.size(): \"<< l.size()\n                    << \"\\n\\t NR*NC:    \"<< NR*NC);\n\n                data.set_size(NR, NC);\n            }\n            else if (NR!=0) \n            {\n                DLIB_ASSERT(l.size()%NR == 0, \n                    \"\\t matrix::matrix(const std::initializer_list& l)\"\n                    << \"\\n\\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size.\"\n                    << \"\\n\\t l.size(): \"<< l.size()\n                    << \"\\n\\t NR:       \"<< NR);\n\n                if (l.size() != 0)\n                    data.set_size(NR, l.size()/NR);\n            }\n            else if (NC!=0) \n            {\n                DLIB_ASSERT(l.size()%NC == 0, \n                    \"\\t matrix::matrix(const std::initializer_list& l)\"\n                    << \"\\n\\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size.\"\n                    << \"\\n\\t l.size(): \"<< l.size()\n                    << \"\\n\\t NC:       \"<< NC);\n\n                if (l.size() != 0)\n                    data.set_size(l.size()/NC, NC);\n            }\n            else if (l.size() != 0)\n            {\n                data.set_size(l.size(),1);\n            }\n\n            if (l.size() != 0)\n            {\n                T* d = &data(0,0);\n                for (auto&& v : l)\n                    *d++ = v;\n            }\n\n        }\n\n        std::unique_ptr<T[]> steal_memory(\n        )\n        {\n            return data.steal_memory();\n        }\n\n        matrix& operator=(const std::initializer_list<T>& l)\n        {\n            matrix temp(l);\n            temp.swap(*this);\n            return *this;\n        }\n#endif // DLIB_HAS_INITIALIZER_LISTS\n\n#ifdef DLIB_HAS_RVALUE_REFERENCES\n        matrix(matrix&& item)\n        {\n        #ifdef MATLAB_MEX_FILE\n            // You can't move memory around when compiled in a matlab mex file and the\n            // different locations have different ownership settings.\n            if (data._private_is_owned_by_matlab() == item.data._private_is_owned_by_matlab())\n            {\n                swap(item);\n            }\n            else\n            {\n                data.set_size(item.nr(),item.nc());\n                matrix_assign(*this, item);\n            }\n        #else\n            swap(item);\n        #endif\n        }\n\n        matrix& operator= (\n            matrix&& rhs\n        )\n        {\n        #ifdef MATLAB_MEX_FILE\n            // You can't move memory around when compiled in a matlab mex file and the\n            // different locations have different ownership settings.\n            if (data._private_is_owned_by_matlab() == rhs.data._private_is_owned_by_matlab())\n            {\n                swap(rhs);\n            }\n            else\n            {\n                data.set_size(rhs.nr(),rhs.nc());\n                matrix_assign(*this, rhs);\n            }\n        #else\n            swap(rhs);\n        #endif\n            return *this;\n        }\n#endif // DLIB_HAS_RVALUE_REFERENCES\n\n        template <typename U, size_t len>\n        explicit matrix (\n            U (&array)[len]\n        ) \n        {\n            COMPILE_TIME_ASSERT(NR*NC == len && len > 0);\n            size_t idx = 0;\n            for (long r = 0; r < NR; ++r)\n            {\n                for (long c = 0; c < NC; ++c)\n                {\n                    data(r,c) = static_cast<T>(array[idx]);\n                    ++idx;\n                }\n            }\n        }\n\n        T& operator() (\n            long r, \n            long c\n        ) \n        { \n            DLIB_ASSERT(r < nr() && c < nc() &&\n                   r >= 0 && c >= 0, \n                \"\\tT& matrix::operator(r,c)\"\n                << \"\\n\\tYou must give a valid row and column\"\n                << \"\\n\\tr:    \" << r \n                << \"\\n\\tc:    \" << c\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc() \n                << \"\\n\\tthis: \" << this\n                );\n            return data(r,c); \n        }\n\n        const T& operator() (\n            long r, \n            long c\n        ) const \n        { \n            DLIB_ASSERT(r < nr() && c < nc() &&\n                   r >= 0 && c >= 0, \n                \"\\tconst T& matrix::operator(r,c)\"\n                << \"\\n\\tYou must give a valid row and column\"\n                << \"\\n\\tr:    \" << r \n                << \"\\n\\tc:    \" << c\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc() \n                << \"\\n\\tthis: \" << this\n                );\n            return data(r,c);\n        }\n\n        T& operator() (\n            long i\n        ) \n        {\n            // You can only use this operator on column vectors.\n            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);\n            DLIB_ASSERT(nc() == 1 || nr() == 1, \n                \"\\tconst type matrix::operator(i)\"\n                << \"\\n\\tYou can only use this operator on column or row vectors\"\n                << \"\\n\\ti:    \" << i\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc()\n                << \"\\n\\tthis: \" << this\n                );\n            DLIB_ASSERT( 0 <= i && i < size(), \n                \"\\tconst type matrix::operator(i)\"\n                << \"\\n\\tYou must give a valid row/column number\"\n                << \"\\n\\ti:      \" << i\n                << \"\\n\\tsize(): \" << size()\n                << \"\\n\\tthis:   \" << this\n                );\n            return data(i);\n        }\n\n        const T& operator() (\n            long i\n        ) const\n        {\n            // You can only use this operator on column vectors.\n            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);\n            DLIB_ASSERT(nc() == 1 || nr() == 1, \n                \"\\tconst type matrix::operator(i)\"\n                << \"\\n\\tYou can only use this operator on column or row vectors\"\n                << \"\\n\\ti:    \" << i\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc()\n                << \"\\n\\tthis: \" << this\n                );\n            DLIB_ASSERT( 0 <= i && i < size(), \n                \"\\tconst type matrix::operator(i)\"\n                << \"\\n\\tYou must give a valid row/column number\"\n                << \"\\n\\ti:      \" << i\n                << \"\\n\\tsize(): \" << size()\n                << \"\\n\\tthis:   \" << this\n                );\n            return data(i);\n        }\n\n        inline operator const type (\n        ) const \n        {\n            COMPILE_TIME_ASSERT(NC == 1 || NC == 0);\n            COMPILE_TIME_ASSERT(NR == 1 || NR == 0);\n            DLIB_ASSERT( nr() == 1 && nc() == 1 , \n                \"\\tmatrix::operator const type\"\n                << \"\\n\\tYou can only attempt to implicit convert a matrix to a scalar if\"\n                << \"\\n\\tthe matrix is a 1x1 matrix\"\n                << \"\\n\\tnr(): \" << nr() \n                << \"\\n\\tnc(): \" << nc() \n                << \"\\n\\tthis: \" << this\n                );\n            return data(0);\n        }\n\n#ifdef MATLAB_MEX_FILE\n        void _private_set_mxArray(\n            mxArray* mem \n        )\n        {\n            data._private_set_mxArray(mem);\n        }\n\n        mxArray* _private_release_mxArray(\n        )\n        {\n            return data._private_release_mxArray();\n        }\n\n        void _private_mark_owned_by_matlab()\n        {\n            data._private_mark_owned_by_matlab();\n        }\n\n        bool _private_is_owned_by_matlab()\n        {\n            return data._private_is_owned_by_matlab();\n        }\n#endif\n\n        void set_size (\n            long rows,\n            long cols\n        )\n        {\n            DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) &&\n                    rows >= 0 && cols >= 0, \n                \"\\tvoid matrix::set_size(rows, cols)\"\n                << \"\\n\\tYou have supplied conflicting matrix dimensions\"\n                << \"\\n\\trows: \" << rows\n                << \"\\n\\tcols: \" << cols\n                << \"\\n\\tNR:   \" << NR \n                << \"\\n\\tNC:   \" << NC \n                << \"\\n\\tthis: \" << this\n                );\n            if (nr() != rows || nc() != cols)\n                data.set_size(rows,cols);\n        }\n\n        void set_size (\n            long length\n        )\n        {\n            // This object you are trying to call set_size(length) on is not a column or \n            // row vector.\n            COMPILE_TIME_ASSERT(NR == 1 || NC == 1);\n            DLIB_ASSERT( length >= 0, \n                \"\\tvoid matrix::set_size(length)\"\n                << \"\\n\\tlength must be at least 0\"\n                << \"\\n\\tlength: \" << length \n                << \"\\n\\tNR:     \" << NR \n                << \"\\n\\tNC:     \" << NC \n                << \"\\n\\tthis:   \" << this\n                );\n\n            if (NR == 1)\n            {\n                DLIB_ASSERT(NC == 0 || NC == length,\n                    \"\\tvoid matrix::set_size(length)\"\n                    << \"\\n\\tSince this is a statically sized matrix length must equal NC\"\n                    << \"\\n\\tlength: \" << length \n                    << \"\\n\\tNR:     \" << NR \n                    << \"\\n\\tNC:     \" << NC \n                    << \"\\n\\tthis:   \" << this\n                    );\n\n                if (nc() != length)\n                    data.set_size(1,length);\n            }\n            else\n            {\n                DLIB_ASSERT(NR == 0 || NR == length,\n                    \"\\tvoid matrix::set_size(length)\"\n                    << \"\\n\\tSince this is a statically sized matrix length must equal NR\"\n                    << \"\\n\\tlength: \" << length \n                    << \"\\n\\tNR:     \" << NR \n                    << \"\\n\\tNC:     \" << NC \n                    << \"\\n\\tthis:   \" << this\n                    );\n\n                if (nr() != length)\n                    data.set_size(length,1);\n            }\n        }\n\n        long nr (\n        ) const { return data.nr(); }\n\n        long nc (\n        ) const { return data.nc(); }\n\n        long size (\n        ) const { return data.nr()*data.nc(); }\n\n        template <typename U, size_t len>\n        matrix& operator= (\n            U (&array)[len]\n        )\n        {\n            COMPILE_TIME_ASSERT(NR*NC == len && len > 0);\n            size_t idx = 0;\n            for (long r = 0; r < NR; ++r)\n            {\n                for (long c = 0; c < NC; ++c)\n                {\n                    data(r,c) = static_cast<T>(array[idx]);\n                    ++idx;\n                }\n            }\n            return *this;\n        }\n\n        template <typename EXP>\n        matrix& operator= (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // You get an error on this line if the matrix you are trying to \n            // assign m to is a statically sized matrix and  m's dimensions don't \n            // match that of *this. \n            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);\n            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);\n            DLIB_ASSERT((NR == 0 || nr() == m.nr()) && \n                   (NC == 0 || nc() == m.nc()), \n                \"\\tmatrix& matrix::operator=(const matrix_exp& m)\"\n                << \"\\n\\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size\"\n                << \"\\n\\tnr():   \" << nr()\n                << \"\\n\\tnc():   \" << nc()\n                << \"\\n\\tm.nr(): \" << m.nr()\n                << \"\\n\\tm.nc(): \" << m.nc()\n                << \"\\n\\tthis:   \" << this\n                );\n\n            // You get an error on this line if the matrix m contains a type that isn't\n            // the same as the type contained in the target matrix.\n            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||\n                                (is_matrix<typename EXP::type>::value == true));\n            if (m.destructively_aliases(*this) == false)\n            {\n                // This if statement is seemingly unnecessary since set_size() contains this\n                // exact same if statement.  However, structuring the code this way causes\n                // gcc to handle the way it inlines this function in a much more favorable way.\n                if (data.nr() == m.nr() && data.nc() == m.nc())\n                {\n                    matrix_assign(*this, m);\n                }\n                else\n                {\n                    set_size(m.nr(),m.nc());\n                    matrix_assign(*this, m);\n                }\n            }\n            else\n            {\n                // we have to use a temporary matrix object here because\n                // *this is aliased inside the matrix_exp m somewhere.\n                matrix temp;\n                temp.set_size(m.nr(),m.nc());\n                matrix_assign(temp, m);\n                temp.swap(*this);\n            }\n            return *this;\n        }\n\n        template <typename EXP>\n        matrix& operator += (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // The matrix you are trying to assign m to is a statically sized matrix and \n            // m's dimensions don't match that of *this. \n            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);\n            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);\n            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));\n            if (nr() == m.nr() && nc() == m.nc())\n            {\n                if (m.destructively_aliases(*this) == false)\n                {\n                    matrix_assign(*this, *this + m);\n                }\n                else\n                {\n                    // we have to use a temporary matrix object here because\n                    // this->data is aliased inside the matrix_exp m somewhere.\n                    matrix temp;\n                    temp.set_size(m.nr(),m.nc());\n                    matrix_assign(temp, *this + m);\n                    temp.swap(*this);\n                }\n            }\n            else\n            {\n                DLIB_ASSERT(size() == 0, \n                    \"\\t const matrix::operator+=(m)\"\n                    << \"\\n\\t You are trying to add two matrices that have incompatible dimensions.\");\n                *this = m;\n            }\n            return *this;\n        }\n\n\n        template <typename EXP>\n        matrix& operator -= (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // The matrix you are trying to assign m to is a statically sized matrix and \n            // m's dimensions don't match that of *this. \n            COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);\n            COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);\n            COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));\n            if (nr() == m.nr() && nc() == m.nc())\n            {\n                if (m.destructively_aliases(*this) == false)\n                {\n                    matrix_assign(*this, *this - m);\n                }\n                else\n                {\n                    // we have to use a temporary matrix object here because\n                    // this->data is aliased inside the matrix_exp m somewhere.\n                    matrix temp;\n                    temp.set_size(m.nr(),m.nc());\n                    matrix_assign(temp, *this - m);\n                    temp.swap(*this);\n                }\n            }\n            else\n            {\n                DLIB_ASSERT(size() == 0, \n                    \"\\t const matrix::operator-=(m)\"\n                    << \"\\n\\t You are trying to subtract two matrices that have incompatible dimensions.\");\n                *this = -m;\n            }\n            return *this;\n        }\n\n        template <typename EXP>\n        matrix& operator *= (\n            const matrix_exp<EXP>& m\n        )\n        {\n            *this = *this * m;\n            return *this;\n        }\n\n        matrix& operator += (\n            const matrix& m\n        )\n        {\n            const long size = m.nr()*m.nc();\n            if (nr() == m.nr() && nc() == m.nc())\n            {\n                for (long i = 0; i < size; ++i)\n                    data(i) += m.data(i);\n            }\n            else\n            {\n                DLIB_ASSERT(this->size() == 0, \n                    \"\\t const matrix::operator+=(m)\"\n                    << \"\\n\\t You are trying to add two matrices that have incompatible dimensions.\");\n\n                set_size(m.nr(), m.nc());\n                for (long i = 0; i < size; ++i)\n                    data(i) = m.data(i);\n            }\n            return *this;\n        }\n\n        matrix& operator -= (\n            const matrix& m\n        )\n        {\n            const long size = m.nr()*m.nc();\n            if (nr() == m.nr() && nc() == m.nc())\n            {\n                for (long i = 0; i < size; ++i)\n                    data(i) -= m.data(i);\n            }\n            else\n            {\n                DLIB_ASSERT(this->size() == 0, \n                    \"\\t const matrix::operator-=(m)\"\n                    << \"\\n\\t You are trying to subtract two matrices that have incompatible dimensions.\");\n                set_size(m.nr(), m.nc());\n                for (long i = 0; i < size; ++i)\n                    data(i) = -m.data(i);\n            }\n            return *this;\n        }\n\n        matrix& operator += (\n            const T val\n        )\n        {\n            const size_t size = nr()*(size_t)nc();\n            for (size_t i = 0; i < size; ++i)\n                data(i) += val;\n\n            return *this;\n        }\n\n        matrix& operator -= (\n            const T val\n        )\n        {\n            const size_t size = nr()*(size_t)nc();\n            for (size_t i = 0; i < size; ++i)\n                data(i) -= val;\n\n            return *this;\n        }\n\n        matrix& operator *= (\n            const T a\n        )\n        {\n            *this = *this * a;\n            return *this;\n        }\n\n        matrix& operator /= (\n            const T a\n        )\n        {\n            *this = *this / a;\n            return *this;\n        }\n\n        matrix& operator= (\n            const matrix& m\n        )\n        {\n            if (this != &m)\n            {\n                set_size(m.nr(),m.nc());\n                const long size = m.nr()*m.nc();\n                for (long i = 0; i < size; ++i)\n                    data(i) = m.data(i);\n            }\n            return *this;\n        }\n\n        void swap (\n            matrix& item\n        )\n        {\n            data.swap(item.data);\n        }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        bool aliases (\n            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item\n        ) const { return (this == &item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        // These two aliases() routines are defined in matrix_mat.h\n        bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item\n        ) const;\n        bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item\n        ) const;\n\n        iterator begin() \n        {\n            if (size() != 0)\n                return &data(0,0);\n            else\n                return 0;\n        }\n\n        iterator end()\n        {\n            if (size() != 0)\n                return &data(0,0)+size();\n            else\n                return 0;\n        }\n\n        const_iterator begin()  const\n        {\n            if (size() != 0)\n                return &data(0,0);\n            else\n                return 0;\n        }\n\n        const_iterator end() const\n        {\n            if (size() != 0)\n                return &data(0,0)+size();\n            else\n                return 0;\n        }\n\n    private:\n        struct literal_assign_helper\n        {\n            /*\n                This struct is a helper struct returned by the operator<<() function below.  It is\n                used primarily to enable us to put DLIB_CASSERT statements on the usage of the\n                operator<< form of matrix assignment.\n            */\n\n            literal_assign_helper(const literal_assign_helper& item) : m(item.m), r(item.r), c(item.c), has_been_used(false) {}\n            explicit literal_assign_helper(matrix* m_): m(m_), r(0), c(0),has_been_used(false) {next();}\n            ~literal_assign_helper() noexcept(false)\n            {\n                DLIB_CASSERT(!has_been_used || r == (*m).nr(),\n                             \"You have used the matrix comma based assignment incorrectly by failing to\\n\"\n                             \"supply a full set of values for every element of a matrix object.\\n\");\n            }\n\n            const literal_assign_helper& operator, (\n                const T& val\n            ) const\n            {\n                DLIB_CASSERT(r < (*m).nr() && c < (*m).nc(),\n                             \"You have used the matrix comma based assignment incorrectly by attempting to\\n\" <<\n                             \"supply more values than there are elements in the matrix object being assigned to.\\n\\n\" <<\n                             \"Did you forget to call set_size()?\" \n                             << \"\\n\\t r: \" << r \n                             << \"\\n\\t c: \" << c \n                             << \"\\n\\t m->nr(): \" << (*m).nr()\n                             << \"\\n\\t m->nc(): \" << (*m).nc());\n                (*m)(r,c) = val;\n                next();\n                has_been_used = true;\n                return *this;\n            }\n\n        private:\n\n            friend class matrix<T,num_rows,num_cols,mem_manager,layout>;\n\n            void next (\n            ) const\n            {\n                ++c;\n                if (c == (*m).nc())\n                {\n                    c = 0;\n                    ++r;\n                }\n            }\n\n            matrix* m;\n            mutable long r;\n            mutable long c;\n            mutable bool has_been_used;\n        };\n\n    public:\n\n        matrix& operator = (\n            const literal_assign_helper& val\n        ) \n        {  \n            *this = *val.m;\n            return *this;\n        }\n\n        const literal_assign_helper operator = (\n            const T& val\n        ) \n        {  \n            // assign the given value to every spot in this matrix\n            const size_t size = nr()*(size_t)nc();\n            for (size_t i = 0; i < size; ++i)\n                data(i) = val;\n\n            // Now return the literal_assign_helper so that the user\n            // can use the overloaded comma notation to initialize \n            // the matrix if they want to.\n            return literal_assign_helper(this); \n        }\n\n    private:\n\n\n        typename layout::template layout<T,NR,NC,mem_manager> data;\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void swap(\n        matrix<T,NR,NC,mm,l>& a,\n        matrix<T,NR,NC,mm,l>& b\n    ) { a.swap(b); }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void serialize (\n        const matrix<T,NR,NC,mm,l>& item, \n        std::ostream& out\n    )\n    {\n        try\n        {\n            // The reason the serialization is a little funny is because we are trying to\n            // maintain backwards compatibility with an older serialization format used by\n            // dlib while also encoding things in a way that lets the array2d and matrix\n            // objects have compatible serialization formats.\n            serialize(-item.nr(),out);\n            serialize(-item.nc(),out);\n            for (long r = 0; r < item.nr(); ++r)\n            {\n                for (long c = 0; c < item.nc(); ++c)\n                {\n                    serialize(item(r,c),out);\n                }\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing dlib::matrix\");\n        }\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void deserialize (\n        matrix<T,NR,NC,mm,l>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            long nr, nc;\n            deserialize(nr,in); \n            deserialize(nc,in); \n\n            // this is the newer serialization format\n            if (nr < 0 || nc < 0)\n            {\n                nr *= -1;\n                nc *= -1;\n            }\n\n            if (NR != 0 && nr != NR)\n                throw serialization_error(\"Error while deserializing a dlib::matrix.  Invalid rows\");\n            if (NC != 0 && nc != NC)\n                throw serialization_error(\"Error while deserializing a dlib::matrix.  Invalid columns\");\n\n            item.set_size(nr,nc);\n            for (long r = 0; r < nr; ++r)\n            {\n                for (long c = 0; c < nc; ++c)\n                {\n                    deserialize(item(r,c),in);\n                }\n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing a dlib::matrix\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void serialize (\n        const ramdump_t<matrix<T,NR,NC,mm,l>>& item_, \n        std::ostream& out\n    )\n    {\n        auto& item = item_.item;\n        serialize(item.nr(), out);\n        serialize(item.nc(), out);\n        if (item.size() != 0)\n            out.write((char*)&item(0,0), sizeof(item(0,0))*item.size());\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void deserialize (\n        ramdump_t<matrix<T,NR,NC,mm,l>>&& item_, \n        std::istream& in \n    )\n    {\n        auto& item = item_.item;\n        long nr, nc;\n        deserialize(nr, in);\n        deserialize(nc, in);\n        item.set_size(nr,nc);\n        if (item.size() != 0)\n            in.read((char*)&item(0,0), sizeof(item(0,0))*item.size());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    std::ostream& operator<< (\n        std::ostream& out,\n        const matrix_exp<EXP>& m\n    )\n    {\n        const std::streamsize old = out.width();\n\n        // first figure out how wide we should make each field\n        std::string::size_type w = 0;\n        std::ostringstream sout;\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                sout << m(r,c); \n                w = std::max(sout.str().size(),w);\n                sout.str(\"\");\n            }\n        }\n\n        // now actually print it\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                out.width(static_cast<std::streamsize>(w));\n                out << m(r,c) << \" \";\n            }\n            out << \"\\n\";\n        }\n        out.width(old);\n        return out;\n    }\n\n    /*\n    template <\n        typename T, \n        long NR, \n        long NC,\n        typename MM,\n        typename L\n        >\n    std::istream& operator>> (\n        std::istream& in,\n        matrix<T,NR,NC,MM,L>& m\n    );\n\n    This function is defined inside the matrix_read_from_istream.h file.\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    class print_matrix_as_csv_helper \n    {\n        /*!\n            This object is used to define an io manipulator for matrix expressions.\n            In particular, this code allows you to write statements like:\n                cout << csv << yourmatrix;\n            and have it print the matrix with commas separating each element.\n        !*/\n    public:\n        print_matrix_as_csv_helper (std::ostream& out_) : out(out_) {}\n\n        template <typename EXP>\n        std::ostream& operator<< (\n            const matrix_exp<EXP>& m\n        ) \n        {\n            for (long r = 0; r < m.nr(); ++r)\n            {\n                for (long c = 0; c < m.nc(); ++c)\n                {\n                    if (c+1 == m.nc())\n                        out << m(r,c) << \"\\n\";\n                    else\n                        out << m(r,c) << \", \";\n                }\n            }\n            return out;\n        }\n\n    private:\n        std::ostream& out;\n    };\n\n    class print_matrix_as_csv {};\n    const print_matrix_as_csv csv = print_matrix_as_csv();\n    inline print_matrix_as_csv_helper operator<< (\n        std::ostream& out,\n        const print_matrix_as_csv& \n    )\n    {\n        return print_matrix_as_csv_helper(out);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    class const_temp_matrix;\n\n    template <\n        typename EXP\n        >\n    struct matrix_traits<const_temp_matrix<EXP> >\n    {\n        typedef typename EXP::type type;\n        typedef typename EXP::const_ret_type const_ret_type;\n        typedef typename EXP::mem_manager_type mem_manager_type;\n        typedef typename EXP::layout_type layout_type;\n        const static long NR = EXP::NR;\n        const static long NC = EXP::NC;\n        const static long cost = 1;\n    };\n\n    template <typename EXP>\n    class const_temp_matrix : public matrix_exp<const_temp_matrix<EXP> >, noncopyable \n    {\n    public:\n        typedef typename matrix_traits<const_temp_matrix>::type type;\n        typedef typename matrix_traits<const_temp_matrix>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<const_temp_matrix>::mem_manager_type mem_manager_type;\n        typedef typename matrix_traits<const_temp_matrix>::layout_type layout_type;\n        const static long NR = matrix_traits<const_temp_matrix>::NR;\n        const static long NC = matrix_traits<const_temp_matrix>::NC;\n        const static long cost = matrix_traits<const_temp_matrix>::cost;\n\n        const_temp_matrix (\n            const matrix_exp<EXP>& item\n        ) :\n            ref_(item.ref())\n        {}\n        const_temp_matrix (\n            const EXP& item\n        ) :\n            ref_(item)\n        {}\n\n        const_ret_type operator() (\n            long r, \n            long c\n        ) const { return ref_(r,c); }\n\n        const_ret_type operator() ( long i ) const \n        { return ref_(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return ref_.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return ref_.destructively_aliases(item); }\n\n        long nr (\n        ) const { return ref_.nr(); }\n\n        long nc (\n        ) const { return ref_.nc(); }\n\n    private:\n\n        typename conditional_matrix_temp<const EXP, (EXP::cost <= 1)>::type ref_;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    typedef matrix<double,0,0,default_memory_manager,column_major_layout> matrix_colmajor;\n    typedef matrix<float,0,0,default_memory_manager,column_major_layout> fmatrix_colmajor;\n\n}\n\n#ifdef _MSC_VER\n// restore warnings back to their previous settings\n#pragma warning(pop)\n#endif\n\n#endif // DLIB_MATRIx_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_ABSTRACT_\n#ifdef DLIB_MATRIx_ABSTRACT_\n\n#include \"matrix_exp_abstract.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n#include \"matrix_data_layout_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*\n        Note that these operator prototypes are not correct C++ (the real versions, which \n        you can see in the implementation are really complex and so probably would \n        distract/confuse people if shown here).  Think of this as just a list of the \n        operators available to you and what they do.\n    */\n\n    const matrix_exp operator* (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1.nc() == m2.nr()\n            - m1.size() > 0 && m2.size() > 0\n              (you can't multiply any sort of empty matrices together)\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns the result of doing the matrix multiplication m1*m2.  The resulting\n              matrix will have m1.nr() rows and m2.nc() columns.\n    !*/\n\n    const matrix_exp operator+ (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1.nr() == m2.nr()\n            - m1.nc() == m2.nc()\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that for all valid r and c:\n              R(r,c) == m1(r,c) + m2(r,c)\n              (i.e. returns the result of doing a pairwise addition of the matrices m1 and m2.)\n              The resulting matrix will have the same dimensions as the originals.\n    !*/\n\n    const matrix_exp operator- (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1.nr() == m2.nr()\n            - m1.nc() == m2.nc()\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that for all valid r and c:\n              R(r,c) == m1(r,c) - m2(r,c)\n              (i.e. returns the result of doing a pairwise subtraction of the matrices m1 and m2.)\n              The resulting matrix will have the same dimensions as the originals.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator* (\n        const matrix_exp& m,\n        const T& value\n    );\n    /*!\n        ensures\n            - returns the result of multiplying all the elements of matrix m by the given \n              scalar value.  The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator* (\n        const T& value,\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the result of multiplying all the elements of matrix m by the given \n              scalar value.  The resulting matrix will have the same dimensions as m.\n    !*/\n\n    const matrix_exp operator- (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns -1*m\n    !*/\n\n    template <typename T>\n    const matrix_exp operator/ (\n        const matrix_exp& m,\n        const T& value\n    );\n    /*!\n        ensures\n            - returns the result of dividing all the elements of matrix m by the given \n              scalar value.  The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator/ (\n        const T& value,\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the result of dividing the given scalar value by all the elements \n              of matrix m.  The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator+ (\n        const matrix_exp& m,\n        const T& value\n    );\n    /*!\n        ensures\n            - returns the result of adding value to all the elements of matrix m.  \n              The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator+ (\n        const T& value,\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the result of adding value to all the elements of matrix m.  \n              The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator- (\n        const matrix_exp& m,\n        const T& value\n    );\n    /*!\n        ensures\n            - returns the result of subtracting value from all the elements of matrix m.  \n              The resulting matrix will have the same dimensions as m.\n    !*/\n\n    template <typename T>\n    const matrix_exp operator- (\n        const T& value,\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - Returns a matrix M such that:\n                - M has the same dimensions as m\n                - M contains the same type of element as m\n                - for all valid r and c:\n                    - M(r,c) == value - m(r,c)\n    !*/\n\n    bool operator== (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        ensures\n            - if (m1.nr() == m2.nr() && m1.nc() == m2.nc() &&\n              for all valid r and c:  m1(r,c) == m2(r,c) ) then\n                - returns true\n            - else\n                - returns false\n    !*/\n\n    bool operator!= (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        ensures\n            - returns !(m1 == m2)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long num_rows = 0,\n        long num_cols = 0,\n        typename mem_manager = default_memory_manager,\n        typename layout = row_major_layout \n        >\n    class matrix : public matrix_exp<matrix<T,num_rows,num_cols,mem_manager,layout> > \n    {\n        /*!\n            REQUIREMENTS ON num_rows and num_cols\n                both must be bigger than or equal to 0\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            REQUIREMENTS ON layout\n                Must be either row_major_layout or column_major_layout\n\n            INITIAL VALUE\n                - if (num_rows > 0) then\n                    - nr() == num_rows\n                - else\n                    - nr() == 0\n\n                - if (num_cols > 0) then\n                    - nc() == num_cols\n                - else\n                    - nc() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a matrix of nr() rows and nc() columns.  This object\n                is also a matrix_exp.  Thus it can be used in all of the above\n                global operators.\n\n                The number of rows and columns of this object are determined by the template\n                arguments num_rows and num_cols.  If num_rows or num_cols are 0 then\n                the matrix starts out empty (i.e. nr() == 0 and nc() == 0) and you may change\n                its size via the set_size() member function. \n                \n                Setting num_rows or num_cols to something other than 0 causes that dimension\n                to have a fixed size.  Setting a fixed size at compile time is useful because \n                any errors related to operating on matrices with incompatible dimensions will \n                be detected at compile time.  It also allows the compiler to perform loop \n                unrolling which can result in substantially faster code.\n\n                Also note that the elements of this matrix are laid out in memory by the layout \n                object supplied as a template argument to this class.  The row_major_layout  \n                sets elements down contiguously in memory and in row major order.  Additionally, \n                all memory allocations are performed using the memory manager object supplied as \n                a template argument to this class.\n        !*/\n\n    public:\n        typedef T type;\n        typedef mem_manager mem_manager_type;\n        typedef layout layout_type;\n        const static long NR = num_rows;\n        const static long NC = num_cols;\n        const static long cost = 1;\n        typedef T*          iterator;       \n        typedef const T*    const_iterator; \n\n        matrix (\n        );\n        /*!\n            ensures\n                - #*this is properly initialized\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n        !*/\n\n        explicit matrix (\n            long length \n        );\n        /*!\n            requires\n                - NR == 1 || NC == 1 (i.e. this must be a column or row vector)\n                - length >= 0 \n                - if (NR == 1 && NC > 0) then\n                    - length == NC\n                - if (NC == 1 && NR > 0) then\n                    - length == NR\n            ensures\n                - #*this is properly initialized\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n                - if (NR == 1) then\n                    - #nr() == 1\n                    - #nc() == length\n                - else\n                    - #nr() == length\n                    - #nc() == 1\n        !*/\n\n        matrix (\n            long rows,\n            long cols\n        );\n        /*!\n            requires\n                - rows == NR || NR == 0\n                - cols == NC || NC == 0\n                - rows >= 0 && cols >= 0\n            ensures\n                - #*this is properly initialized\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n                - #nr() == rows\n                - #nc() == cols\n        !*/\n\n        template <typename EXP>\n        matrix (\n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - matrix_exp<EXP>::type == T\n                  (i.e. m contains the same type as *this does)\n                - if (NR != 0) then NR == m.nr()\n                - if (NC != 0) then NC == m.nc()\n            ensures\n                - #*this == m\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n        !*/\n\n        template <typename U, size_t len>\n        explicit matrix (\n            U (&array)[len]\n        );\n        /*!\n            requires\n                - NR != 0 && NC != 0 (i.e. you can only use this constructor on statically sized matrices)\n                - len == nr()*nc()  (i.e. the array you give here must be the right size)\n            ensures\n                - for all valid r and c:\n                  #(*this)(r,c) == array[r*nc() + c]\n                  (i.e. initializes this matrix with the contents of the given array)\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n        !*/\n        \n        matrix(\n            const std::initializer_list<T>& l\n        );\n        /*!\n            requires\n                - This matrix is capable of having a size() == l.size().  Therefore, if\n                  NR*NC != 0 then l.size() must equal NR*NC.  Alternatively, if NR or NC is\n                  != 0 then l.size() must be a multiple of the non-zero NR or NC.\n            ensures\n                - #size() == l.size()\n                - The contents of l are enumerated and read into the matrix in row major order.\n                - if (NR != 0) then\n                    - #nr() == NR\n                    - #nc() == l.size()/NR\n                - if (NC != 0) then\n                    - #nr() == l.size()/NC\n                    - #nc() == NC\n                - if (NR*NC==0) then\n                    - #nr() == l.size()\n                    - #nc() == 1\n                - #aliases(*this) == true\n                - #ref().aliases(*this) == true\n        !*/\n\n        T& operator() (\n            long r, \n            long c\n        ); \n        /*!\n            requires\n                - 0 <= r < nr()\n                - 0 <= c < nc()\n            ensures\n                - returns a reference to the value at the given row and column in \n                  this matrix.\n        !*/\n\n        const T& operator() (\n            long r, \n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= r < nr()\n                - 0 <= c < nc()\n            ensures\n                - returns a const reference to the value at the given row and column in \n                  this matrix.\n        !*/\n\n        T& operator() (\n            long i\n        ); \n        /*!\n            requires\n                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)\n                - 0 <= i < size()\n            ensures\n                - if (nc() == 1) then\n                    - returns a reference to (*this)(i,0)\n                - else\n                    - returns a reference to (*this)(0,i)\n        !*/\n\n        const T& operator() (\n            long i\n        ) const;\n        /*!\n            requires\n                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)\n                - 0 <= i < size()\n            ensures\n                - if (nc() == 1) then\n                    - returns a reference to (*this)(i,0)\n                - else\n                    - returns a reference to (*this)(0,i)\n        !*/\n\n        operator const type (\n        ) const;\n        /*!\n            requires\n                - nr() == 1\n                - nc() == 1\n            ensures\n                - returns (*this)(0,0)\n        !*/\n\n        long nr(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this matrix\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this matrix\n        !*/\n\n        long size (\n        ) const;\n        /*!\n            ensures\n                - returns nr()*nc()\n        !*/\n\n        void set_size (\n            long rows,\n            long cols\n        );\n        /*!\n            requires\n                - rows == NR || NR == 0\n                - cols == NC || NC == 0\n                - rows >= 0 && cols >= 0\n            ensures\n                - #nr() == rows\n                - #nc() == cols\n        !*/\n\n        void set_size (\n            long length\n        );\n        /*!\n            requires\n                - NR == 1 || NC == 1 (i.e. this must be a column or row vector)\n                - length >= 0 \n                - if (NR == 1 && NC > 0) then\n                    - length == NC\n                - if (NC == 1 && NR > 0) then\n                    - length == NR\n            ensures\n                - if (NR == 1) then\n                    - #nr() == 1\n                    - #nc() == length\n                - else\n                    - #nr() == length\n                    - #nc() == 1\n        !*/\n\n        std::unique_ptr<T[]> steal_memory(\n        );\n        /*!\n            requires\n                - NR*NC==0\n                  (i.e. this array isn't statically sized)\n            ensures\n                - Returns a pointer containing the memory block underlying this matrix.\n                  After calling steal_memory() this matrix doesn't own the memory anymore\n                  and is automatically set to the empty matrix.\n                - The returned pointer points to an array of size() T objects and in\n                  particular is the pointer &(*this)(0,0).\n                - #size() == 0\n        !*/\n\n        template <typename U, size_t len>\n        matrix& operator= (\n            U (&array)[len]\n        );\n        /*!\n            requires\n                - len == nr()*nc()  (i.e. the array you give here must be the right size)\n            ensures\n                - for all valid r and c:\n                  #(*this)(r,c) == array[r*nc() + c]\n                  (i.e. loads this matrix with the contents of the given array)\n                - returns *this\n        !*/\n\n        matrix& operator=(\n            const std::initializer_list<T>& l\n        );\n        /*!\n            requires\n                - This matrix is capable of having a size() == l.size().  Therefore, if\n                  NR*NC != 0 then l.size() must equal NR*NC.  Alternatively, if NR or NC is\n                  != 0 then l.size() must be a multiple of the non-zero NR or NC.\n            ensures\n                - Assigns the contents of l to *this by performing: matrix(l).swap(*this)\n                - returns *this\n        !*/\n\n        template <typename EXP>\n        matrix& operator= (\n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - matrix_exp<EXP>::type == T\n                  (i.e. m contains the same type as *this does)\n                - if (NR != 0) then NR == m.nr()\n                - if (NC != 0) then NC == m.nc()\n            ensures\n                - copies the given matrix expression m to *this\n                - returns *this\n        !*/\n\n        template <typename EXP>\n        matrix& operator += (\n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - matrix_exp<EXP>::type == T\n                - One of the following is true:\n                    - nr() == m.nr() && nc() == m.nc()\n                    - size() == 0\n                  (i.e. this matrix must have matching dimensions or it must be empty)\n            ensures\n                - if (nr() == m.nr() && nc() == m.nc()) then\n                    - #(*this) == *this + m\n                - else\n                    - #(*this) == m\n                      (i.e. if the dimensions don't match then this function performs a \n                      normal assignment)\n                - returns *this\n        !*/\n\n        template <typename EXP>\n        matrix& operator -= (\n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - matrix_exp<EXP>::type == T\n                - One of the following is true:\n                    - nr() == m.nr() && nc() == m.nc()\n                    - size() == 0\n                  (i.e. this matrix must have matching dimensions or it must be empty)\n            ensures\n                - if (nr() == m.nr() && nc() == m.nc()) then\n                    - #(*this) == *this - m\n                - else\n                    - #(*this) == -m\n                - returns *this\n        !*/\n\n        template <typename EXP>\n        matrix& operator *= (\n            const matrix_exp<EXP>& m\n        );\n        /*!\n            requires\n                - matrix_exp<EXP>::type == T\n                  (i.e. m must contain the same type of element as *this)\n                - nc() == m.nr()\n                - size() > 0 && m.size() > 0\n                  (you can't multiply any sort of empty matrices together)\n            ensures\n                - #(*this) == *this * m\n                - returns *this\n        !*/\n\n        matrix& operator *= (\n            const T& a\n        );\n        /*!\n            ensures\n                - #(*this) == *this * a\n                - returns *this\n        !*/\n\n        matrix& operator /= (\n            const T& a\n        );\n        /*!\n            ensures\n                - #(*this) == *this / a\n                - returns *this\n        !*/\n\n        matrix& operator += (\n            const T& a\n        );\n        /*!\n            ensures\n                - #(*this) == *this + a\n                - returns *this\n        !*/\n\n        matrix& operator -= (\n            const T& a\n        );\n        /*!\n            ensures\n                - #(*this) == *this - a\n                - returns *this\n        !*/\n\n        const literal_assign_helper operator = (\n            const T& val\n        );\n        /*!\n            This function is somewhat different than all the others defined in this file.\n            The purpose of this function is to enable you to easily initialize a matrix object.\n            For example:\n                matrix<double> m(2,3);\n                m = 1,2,3,\n                    4,5,6;\n\n            The above code creates a matrix m with 2 rows and 3 columns and sets it so that\n            it contains the matrix | 1 2 3 |\n                                   | 4 5 6 |\n\n            You can also use this function to assign to all elements of a matrix.  So\n            saying m = 3; would assign all elements of m equal to 3.\n\n            Note that to use this method of assignment it is required that you supply \n            exactly m.size() or 1 values so that the matrix is fully initialized.  Supplying \n            fewer or more than that is an error that will cause a dlib::fatal_error to be \n            thrown.\n\n            Note also that using an expression of the form m = scalar; when m.size() == 0\n            is legal but has no effect on m.\n        !*/\n\n        void swap (\n            matrix& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n        iterator begin(\n        );\n        /*!\n            ensures\n                - returns a random access iterator pointing to the first element in this\n                  matrix.\n                - The iterator will iterate over the elements of the matrix in row major\n                  order if layout is row_major_layout or in column major order if layout is\n                  column_major_layout.\n        !*/\n\n        iterator end(\n        );\n        /*!\n            ensures\n                - returns a random access iterator pointing to one past the end of the last\n                  element in this matrix.\n        !*/\n\n        const_iterator begin(\n        ) const;\n        /*!\n            ensures\n                - returns a random access iterator pointing to the first element in this\n                  matrix.  \n                - The iterator will iterate over the elements of the matrix in row major\n                  order if layout is row_major_layout or in column major order if layout is\n                  column_major_layout.\n        !*/\n\n        const_iterator end(\n        ) const;\n        /*!\n            ensures\n                - returns a random access iterator pointing to one past the end of the last\n                  element in this matrix.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A matrix_colmajor \n        This is just a typedef of the matrix object that uses column major layout. \n    !*/\n    typedef matrix<double,0,0,default_memory_manager,column_major_layout> matrix_colmajor;\n\n    /*!A fmatrix_colmajor \n        This is just a typedef of the matrix object that uses column major layout. \n    !*/\n    typedef matrix<float,0,0,default_memory_manager,column_major_layout> fmatrix_colmajor;\n\n// ----------------------------------------------------------------------------------------\ntemplate <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void swap(\n        matrix<T,NR,NC,mm,l>& a,\n        matrix<T,NR,NC,mm,l>& b\n    ) { a.swap(b); }\n    /*!\n        Provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void serialize (\n        const matrix<T,NR,NC,mm,l>& item, \n        std::ostream& out\n    );   \n    /*!\n        Provides serialization support.  Note that the serialization formats used by the\n        dlib::matrix and dlib::array2d objects are compatible.  That means you can load the\n        serialized data from one into another and it will work properly.\n    !*/\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename mm,\n        typename l\n        >\n    void deserialize (\n        matrix<T,NR,NC,mm,l>& item, \n        std::istream& in\n    );   \n    /*!\n        Provides deserialization support \n    !*/\n\n    template <\n        typename EXP\n        >\n    std::ostream& operator<< (\n        std::ostream& out,\n        const matrix_exp<EXP>& m\n    );\n    /*!\n        ensures\n            - writes m to the given out stream in a form suitable for human consumption.\n            - returns out\n    !*/\n\n    template <\n        typename T, \n        long NR, \n        long NC,\n        typename MM,\n        typename L\n        >\n    std::istream& operator>> (\n        std::istream& in,\n        matrix<T,NR,NC,MM,L>& m\n    );\n    /*!\n        ensures\n            - Tries to read a matrix from the given input stream and store it into #m.\n            - The format expected is the text format output by the above operator<<().\n              That is, the format should be a grid of text such as:\n                2 3 4\n                5 2 6 \n            - The separation between numbers can be any number of whitespace characters or\n              commas.      \n            - The matrix data is assumed to end upon the first blank line or end-of-file,\n              whichever comes first.  This means you can create an input stream with\n              multiple matrices in it by separating them with empty lines.\n            - returns in. \n            - If there was a formatting error or something which prevents the input data\n              from being parsed into a matrix then #in.fail() == true.\n    !*/\n\n    /*!A csv\n        This object is used to define an io manipulator for matrix expressions.  In\n        particular, you can write statements like:\n            cout << csv << yourmatrix;\n        and have it print the matrix with commas separating each element.\n    !*/\n    some_undefined_iomnaip_type csv;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    class const_temp_matrix : public matrix_exp<const_temp_matrix<EXP> >, noncopyable \n    {\n        /*!\n            REQUIREMENTS ON EXP\n                - must be an object that inherits publicly from matrix_exp.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a copy of a matrix expression.  The twist\n                is that it only actually makes a copy of its input matrix expression\n                if that matrix expression is costly to evaluate.  If it has\n                low cost then this object just stores a reference.  \n\n                This class is useful in cases where you write a function that\n                takes a matrix_exp object as input and you want to do some\n                intensive computation that looks at each element of that matrix_exp\n                many times.  If the input matrix_exp has a high cost then you want\n                to store it into a temporary matrix.  But if it has low cost then\n                it is faster if you just use a reference to it.  The const_temp_matrix\n                makes doing this easy.\n        !*/\n    public:\n\n        const_temp_matrix (\n            const matrix_exp<EXP>& item\n        );\n        /*!\n            ensures\n                - #*this == item\n                - if (EXP::cost <= 1) then\n                    - this const_temp_matrix stores a reference to the item matrix\n                - else\n                    - this const_temp_matrix creates a temporary matrix and copies \n                      item into it\n        !*/\n\n        const_temp_matrix (\n            const EXP& item\n        );\n        /*!\n            ensures\n                - #*this == item\n                - if (EXP::cost <= 1) then\n                    - this const_temp_matrix stores a reference to the item matrix\n                - else\n                    - this const_temp_matrix creates a temporary matrix and copies \n                      item into it\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_assign.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_ASSIGn_\n#define DLIB_MATRIx_ASSIGn_\n\n#include \"matrix.h\"\n#include \"matrix_utilities.h\"\n#include \"matrix_subexp.h\"\n#include \"../enable_if.h\"\n#include \"matrix_assign_fwd.h\"\n#include \"matrix_default_mul.h\"\n#include \"matrix_conj_trans.h\"\n#include \"matrix_mat.h\"\n\nnamespace dlib\n{\n    /*\n        This file contains some templates that are used inside the matrix_blas_bindings.h\n        file to bind various matrix expressions to optimized code for carrying them out.\n    */\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace blas_bindings \n    {\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        void zero_matrix (\n            T& m\n        )\n        {\n            for (long r = 0; r < m.nr(); ++r)\n            {\n                for (long c = 0; c < m.nc(); ++c)\n                {\n                    m(r,c) = 0;\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    // This template struct is used to tell us if a matrix expression contains a matrix multiply.\n        template <typename T>\n        struct has_matrix_multiply\n        {\n            const static bool value = false;\n        };\n\n        template <typename T, typename U> \n        struct has_matrix_multiply<matrix_multiply_exp<T,U> > \n        { const static bool value = true; };\n\n        template <typename T, typename U> \n        struct has_matrix_multiply<matrix_add_exp<T,U> >  \n        { const static bool value = has_matrix_multiply<T>::value || has_matrix_multiply<U>::value; };\n\n        template <typename T, typename U> \n        struct has_matrix_multiply<matrix_subtract_exp<T,U> >  \n        { const static bool value = has_matrix_multiply<T>::value || has_matrix_multiply<U>::value; };\n\n        template <typename T, bool Tb> \n        struct has_matrix_multiply<matrix_mul_scal_exp<T,Tb> >  \n        { const static bool value = true; };\n\n        template <typename T> \n        struct has_matrix_multiply<matrix_div_scal_exp<T> >  \n        { const static bool value = has_matrix_multiply<T>::value; };\n\n        template <typename T> \n        struct has_matrix_multiply<matrix_op<T> >  \n        { const static bool value = has_matrix_multiply<T>::value; };\n\n        template <typename T> \n        struct has_matrix_multiply<op_trans<T> >  \n        { const static bool value = has_matrix_multiply<T>::value; };\n\n        template <typename T> \n        struct has_matrix_multiply<op_conj_trans<T> >  \n        { const static bool value = has_matrix_multiply<T>::value; };\n\n        template <typename T> \n        struct has_matrix_multiply<op_conj<T> >  \n        { const static bool value = has_matrix_multiply<T>::value; };\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        const int unknown_matrix = 0;\n        const int general_matrix = 1;\n        const int row_matrix = 2;\n        const int column_matrix = 3;\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        struct matrix_type_id\n        {\n            const static int value = unknown_matrix;\n        };\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix<T,NR,NC,MM,L> >\n        {\n            const static int value = general_matrix;\n        };\n\n        template <typename T, long NR, typename MM, typename L>\n        struct matrix_type_id<matrix<T,NR,1,MM,L> >\n        {\n            const static int value = column_matrix;\n        };\n\n        template <typename T, typename MM, typename L>\n        struct matrix_type_id<matrix<T,1,1,MM,L> >\n        {\n            const static int value = column_matrix;\n        };\n\n        template <typename T, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix<T,1,NC,MM,L> >\n        {\n            const static int value = row_matrix;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix_op<op_colm<matrix<T,NR,NC,MM,L> > > >\n        {\n            const static int value = column_matrix;\n        };\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix_op<op_rowm<matrix<T,NR,NC,MM,L> > > >\n        {\n            const static int value = row_matrix;\n        };\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix_op<op_colm2<matrix<T,NR,NC,MM,L> > > >\n        {\n            const static int value = column_matrix;\n        };\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix_op<op_rowm2<matrix<T,NR,NC,MM,L> > > >\n        {\n            const static int value = row_matrix;\n        };\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        struct matrix_type_id<matrix_op<op_subm<matrix<T,NR,NC,MM,L> > > >\n        {\n            const static int value = general_matrix;\n        };\n\n        template < typename T, typename MM >\n        struct matrix_type_id<matrix_op<op_array2d_to_mat<array2d<T,MM> > > >\n        { const static int value = general_matrix; };\n\n        template < typename T, typename MM >\n        struct matrix_type_id<matrix_op<op_array_to_mat<array<T,MM> > > >\n        { const static int value = column_matrix; };\n\n        template < typename value_type, typename alloc >\n        struct matrix_type_id<matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > >\n        { const static int value = column_matrix; };\n\n        template < typename value_type, typename alloc >\n        struct matrix_type_id<matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > >\n        { const static int value = column_matrix; };\n\n        template < typename T >\n        struct matrix_type_id<matrix_op<op_pointer_to_col_vect<T> > >\n        { const static int value = column_matrix; };\n        template < typename T >\n        struct matrix_type_id<matrix_op<op_pointer_to_mat<T> > >\n        { const static int value = general_matrix; };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T, typename U>\n        struct same_matrix\n        {\n            const static int T_id = matrix_type_id<T>::value;\n            const static int U_id = matrix_type_id<U>::value;\n            // The check for unknown_matrix is here so that we can be sure that matrix types\n            // other than the ones specifically enumerated above never get pushed into\n            // any of the BLAS bindings.  So saying they are never the same as anything\n            // else prevents them from matching any of the BLAS bindings.\n            const static bool value = (T_id == U_id) && (T_id != unknown_matrix);\n        };\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n    // This template struct is used to tell us if two matrix expressions both contain the same\n    // sequence of operators, expressions.    It also only has a value of true if the T expression\n    // contains only matrices with the given layout. \n        template <typename T, typename U, typename layout>\n        struct same_exp\n        {\n            const static bool value = (is_same_type<typename T::exp_type, typename U::exp_type>::value ||\n                                       same_matrix<typename T::exp_type, typename U::exp_type>::value) &&\n                                is_same_type<typename T::layout_type,layout>::value;\n\n        };\n\n        // Used only below.  They help strip off the const and & qualifiers that can show up \n        // in the LHS_ref_type and RHS_ref_type typedefs.\n        template <typename T> struct noref{ typedef T type;};\n        template <typename T> struct noref<T&>{ typedef T type;}; \n        template <typename T> struct noref<const T&>{ typedef T type;}; \n        template <typename T> struct noref<const T>{ typedef T type;}; \n\n        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout> \n        struct same_exp<matrix_multiply_exp<Tlhs,Trhs>, matrix_multiply_exp<Ulhs,Urhs>,layout > \n        { \n            // The reason this case is more complex than the others is because the matrix_multiply_exp \n            // will use a temporary matrix instead of Tlhs or Trhs in the event that one of these \n            // types corresponds to an expensive expression.  So we have to use the type that really\n            // gets used.  The following typedefs are here to pick out that true type.\n            typedef typename matrix_multiply_exp<Tlhs,Trhs>::LHS_ref_type T_LHS_ref_type;\n            typedef typename matrix_multiply_exp<Tlhs,Trhs>::RHS_ref_type T_RHS_ref_type;\n            typedef typename noref<T_LHS_ref_type>::type T_lhs_type;\n            typedef typename noref<T_RHS_ref_type>::type T_rhs_type;\n\n            typedef typename matrix_multiply_exp<Ulhs,Urhs>::LHS_ref_type U_LHS_ref_type;\n            typedef typename matrix_multiply_exp<Ulhs,Urhs>::RHS_ref_type U_RHS_ref_type;\n            typedef typename noref<U_LHS_ref_type>::type U_lhs_type;\n            typedef typename noref<U_RHS_ref_type>::type U_rhs_type;\n\n            const static bool value = same_exp<T_lhs_type,U_lhs_type,layout>::value && \n                                      same_exp<T_rhs_type,U_rhs_type,layout>::value; \n        };\n\n        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout> \n        struct same_exp<matrix_add_exp<Tlhs,Trhs>, matrix_add_exp<Ulhs,Urhs>, layout > \n        { const static bool value = same_exp<Tlhs,Ulhs,layout>::value && same_exp<Trhs,Urhs,layout>::value; };\n\n        template <typename Tlhs, typename Ulhs, typename Trhs, typename Urhs, typename layout> \n        struct same_exp<matrix_subtract_exp<Tlhs,Trhs>, matrix_subtract_exp<Ulhs,Urhs>, layout > \n        { const static bool value = same_exp<Tlhs,Ulhs,layout>::value && same_exp<Trhs,Urhs,layout>::value; };\n\n        template <typename T, typename U, bool Tb, bool Ub, typename layout> \n        struct same_exp<matrix_mul_scal_exp<T,Tb>, matrix_mul_scal_exp<U,Ub>, layout > \n        { const static bool value = same_exp<T,U,layout>::value; };\n\n        template <typename T, typename U, typename layout> \n        struct same_exp<matrix_div_scal_exp<T>, matrix_div_scal_exp<U>, layout > \n        { const static bool value = same_exp<T,U,layout>::value; };\n\n        template <typename T, typename U, typename layout> \n        struct same_exp<matrix_op<op_trans<T> >, matrix_op<op_trans<U> >, layout > \n        { const static bool value = same_exp<T,U,layout>::value; };\n\n        template <typename T, typename U, typename layout> \n        struct same_exp<matrix_op<op_conj<T> >, matrix_op<op_conj<U> >, layout > \n        { const static bool value = same_exp<T,U,layout>::value; };\n\n        template <typename T, typename U, typename layout> \n        struct same_exp<matrix_op<op_conj_trans<T> >, matrix_op<op_conj_trans<U> >, layout > \n        { const static bool value = same_exp<T,U,layout>::value; };\n\n    // ------------------------------------------------------------------------------------\n\n        struct yes_type\n        {\n            char ch;\n        };\n        struct no_type\n        {\n            yes_type a, b;\n        };\n\n        // This is a helper that is used below to apply the same_exp template to matrix expressions.\n        template <typename T, typename layout, typename U>\n        typename enable_if<same_exp<T,U,layout>,yes_type>::type test(U);\n        template <typename T, typename layout, typename U>\n        typename disable_if<same_exp<T,U,layout>,no_type>::type test(U);\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp,\n            typename enabled = void\n            >\n        struct matrix_assign_blas_helper\n        {\n            // We are in the default version of the blas helper so this\n            // means there wasn't any more specific overload.  So just\n            // let the default matrix assignment happen.\n            template <typename EXP>\n            static void assign (\n                dest_exp& dest,\n                const EXP& src,\n                typename src_exp::type alpha,\n                bool add_to,\n                bool transpose\n            )\n            {\n                if (transpose == false)\n                    matrix_assign_default(dest,src,alpha,add_to);\n                else\n                    matrix_assign_default(dest,trans(src),alpha,add_to);\n            }\n\n            // If we know this is a matrix multiply then apply the\n            // default dlib matrix multiply to speed things up a bit more\n            // than the above default function would.\n            template <typename EXP1, typename EXP2>\n            static void assign (\n                dest_exp& dest,\n                const matrix_multiply_exp<EXP1,EXP2>& src,\n                typename src_exp::type alpha,\n                bool add_to,\n                bool transpose\n            )\n            {\n                // At some point I need to improve the default (i.e. non BLAS) matrix \n                // multiplication algorithm...\n\n                if (alpha == static_cast<typename src_exp::type>(1))\n                {\n                    if (add_to == false)\n                    {\n                        zero_matrix(dest);\n                    }\n\n                    if (transpose == false)\n                        default_matrix_multiply(dest, src.lhs, src.rhs);\n                    else\n                        default_matrix_multiply(dest, trans(src.rhs), trans(src.lhs));\n                }\n                else\n                {\n                    if (add_to)\n                    {\n                        typename dest_exp::matrix_type temp(dest.nr(),dest.nc());\n                        zero_matrix(temp);\n\n                        if (transpose == false)\n                            default_matrix_multiply(temp, src.lhs, src.rhs);\n                        else\n                            default_matrix_multiply(temp, trans(src.rhs), trans(src.lhs));\n\n                        matrix_assign_default(dest,temp, alpha,true);\n                    }\n                    else\n                    {\n                        zero_matrix(dest);\n                        \n                        if (transpose == false)\n                            default_matrix_multiply(dest, src.lhs, src.rhs);\n                        else\n                            default_matrix_multiply(dest, trans(src.rhs), trans(src.lhs));\n\n                        matrix_assign_default(dest,dest, alpha, false);\n                    }\n                }\n            }\n        };\n\n        // This is a macro to help us add overloads for the matrix_assign_blas_helper template.  \n        // Using this macro it is easy to add overloads for arbitrary matrix expressions.\n#define DLIB_ADD_BLAS_BINDING(src_expression)                                               \\\n    template <typename T, typename L> struct DLIB_BOOST_JOIN(blas,__LINE__)                      \\\n    { const static bool value = sizeof(yes_type) == sizeof(test<T,L>(src_expression)); };   \\\n                                                                                            \\\n    template < typename dest_exp, typename src_exp >                                       \\\n    struct matrix_assign_blas_helper<dest_exp, src_exp,                                    \\\n    typename enable_if<DLIB_BOOST_JOIN(blas,__LINE__)<src_exp,typename dest_exp::layout_type> >::type > {   \\\n        static void assign (                                                                \\\n            dest_exp& dest,                                                                \\\n            const src_exp& src,                                                             \\\n            typename src_exp::type alpha,                                                   \\\n            bool add_to,                                                                    \\\n            bool DLIB_NO_WARN_UNUSED transpose                      \\\n        ) {                                                                                 \\\n            DLIB_NO_WARN_UNUSED typedef typename dest_exp::type T;                                             \n\n#define DLIB_END_BLAS_BINDING }};\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n    // ------------------- Forward Declarations -------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const src_exp& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        );\n        /*!\n            requires\n                - src.aliases(dest) == false\n                - dest.nr() == src.nr()\n                - dest.nc() == src.nc()\n        !*/\n\n        template <\n            typename dest_exp,\n            typename src_exp, typename src_exp2 \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_add_exp<src_exp, src_exp2>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        );\n        /*!\n            requires\n                - src.aliases(dest) == false\n                - dest.nr() == src.nr()\n                - dest.nc() == src.nc()\n        !*/\n\n        template <\n            typename dest_exp,\n            typename src_exp, bool Sb \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_mul_scal_exp<src_exp,Sb>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        );\n        /*!\n            requires\n                - src.aliases(dest) == false\n                - dest.nr() == src.nr()\n                - dest.nc() == src.nc()\n        !*/\n\n        template <\n            typename dest_exp,\n            typename src_exp\n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_op<op_trans<src_exp> >& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        );\n        /*!\n            requires\n                - src.aliases(dest) == false\n                - dest.nr() == src.nr()\n                - dest.nc() == src.nc()\n        !*/\n\n        template <\n            typename dest_exp,\n            typename src_exp, typename src_exp2 \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_subtract_exp<src_exp, src_exp2>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        );\n        /*!\n            requires\n                - src.aliases(dest) == false\n                - dest.nr() == src.nr()\n                - dest.nc() == src.nc()\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const src_exp& src\n        );\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src\n        );\n        /*!\n            This function catches the expressions of the form:  \n                M = M + exp; \n            and converts them into the appropriate matrix_assign_blas() call.\n            This is an important case to catch because it is the expression used\n            to represent the += matrix operator.\n        !*/\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_add_exp<src_exp, matrix<T,NR,NC,MM,L> >& src\n        );\n        /*!\n            This function catches the expressions of the form:  \n                M = exp + M; \n            and converts them into the appropriate matrix_assign_blas() call.\n            This is an important case to catch because it is the expression used\n            to represent the += matrix operator.\n        !*/\n            \n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_subtract_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src\n        );\n        /*!\n            This function catches the expressions of the form:  \n                M = M - exp; \n            and converts them into the appropriate matrix_assign_blas() call.\n            This is an important case to catch because it is the expression used\n            to represent the -= matrix operator.\n        !*/\n\n\n        //   End of forward declarations for overloaded matrix_assign_blas functions\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const src_exp& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        )\n        {\n            matrix_assign_blas_helper<dest_exp,src_exp>::assign(dest,src,alpha,add_to, transpose);\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp, typename src_exp2 \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_add_exp<src_exp, src_exp2>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        )\n        {\n            if (has_matrix_multiply<src_exp>::value || has_matrix_multiply<src_exp2>::value)\n            {\n                matrix_assign_blas_proxy(dest, src.lhs, alpha, add_to, transpose);\n                matrix_assign_blas_proxy(dest, src.rhs, alpha, true, transpose);\n            }\n            else\n            {\n                if (transpose == false)\n                    matrix_assign_default(dest, src, alpha, add_to);\n                else\n                    matrix_assign_default(dest, trans(src), alpha, add_to);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp, bool Sb \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_mul_scal_exp<src_exp,Sb>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        )\n        {\n            matrix_assign_blas_proxy(dest, src.m, alpha*src.s, add_to, transpose);\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp\n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_op<op_trans<src_exp> >& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        )\n        {\n            matrix_assign_blas_proxy(dest, src.op.m, alpha, add_to, !transpose);\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename dest_exp,\n            typename src_exp, typename src_exp2 \n            >\n        void matrix_assign_blas_proxy (\n            dest_exp& dest,\n            const matrix_subtract_exp<src_exp, src_exp2>& src,\n            typename src_exp::type alpha,\n            bool add_to,\n            bool transpose\n        )\n        {\n            \n            if (has_matrix_multiply<src_exp>::value || has_matrix_multiply<src_exp2>::value)\n            {\n                matrix_assign_blas_proxy(dest, src.lhs, alpha, add_to, transpose);\n                matrix_assign_blas_proxy(dest, src.rhs, -alpha, true, transpose);\n            }\n            else\n            {\n                if (transpose == false)\n                    matrix_assign_default(dest, src, alpha, add_to);\n                else\n                    matrix_assign_default(dest, trans(src), alpha, add_to);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n    // Once we get into this function it means that we are dealing with a matrix of float,\n    // double, complex<float>, or complex<double> and the src_exp contains at least one\n    // matrix multiply.\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            long NR2, long NC2, bool Sb\n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_mul_scal_exp<matrix<T,NR2,NC2,MM,L>,Sb>& src\n        )\n        {\n            // It's ok that we don't check for aliasing in this case because there isn't\n            // any complex unrolling of successive + or - operators in this expression.\n            matrix_assign_blas_proxy(dest,src.m,src.s,false, false);\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const src_exp& src\n        )\n        {\n            if (src.aliases(dest))\n            {\n                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());\n                matrix_assign_blas_proxy(temp,src,1,false, false);\n                temp.swap(dest);\n            }\n            else\n            {\n                matrix_assign_blas_proxy(dest,src,1,false, false);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            assignable_sub_matrix<T,NR,NC,MM,L>& dest,\n            const src_exp& src\n        )\n        {\n            if (src.aliases(dest.m))\n            {\n                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());\n                matrix_assign_blas_proxy(temp,src,1,false, false);\n                matrix_assign_default(dest,temp);\n            }\n            else\n            {\n                matrix_assign_blas_proxy(dest,src,1,false, false);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            assignable_ptr_matrix<T>& dest,\n            const src_exp& src\n        )\n        {\n            if (src.aliases(mat(dest.ptr,dest.height,dest.width)))\n            {\n                matrix<T> temp(dest.nr(),dest.nc());\n                matrix_assign_blas_proxy(temp,src,1,false, false);\n                matrix_assign_default(dest,temp);\n            }\n            else\n            {\n                matrix_assign_blas_proxy(dest,src,1,false, false);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            assignable_row_matrix<T,NR,NC,MM,L>& dest,\n            const src_exp& src\n        )\n        {\n            if (src.aliases(dest.m))\n            {\n                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());\n                matrix_assign_blas_proxy(temp,src,1,false, false);\n                matrix_assign_default(dest,temp);\n            }\n            else\n            {\n                matrix_assign_blas_proxy(dest,src,1,false, false);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            assignable_col_matrix<T,NR,NC,MM,L>& dest,\n            const src_exp& src\n        )\n        {\n            if (src.aliases(dest.m))\n            {\n                matrix<T,NR,NC,MM,L> temp(dest.nr(),dest.nc());\n                matrix_assign_blas_proxy(temp,src,1,false, false);\n                matrix_assign_default(dest,temp);\n            }\n            else\n            {\n                matrix_assign_blas_proxy(dest,src,1,false, false);\n            }\n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src\n        )\n        {\n            if (src.rhs.aliases(dest) == false)\n            {\n                if (&src.lhs != &dest)\n                {\n                    dest = src.lhs;\n                }\n\n                matrix_assign_blas_proxy(dest, src.rhs, 1, true, false);\n            }\n            else\n            {\n                matrix<T,NR,NC,MM,L> temp(src.lhs);\n                matrix_assign_blas_proxy(temp, src.rhs, 1, true, false);\n                temp.swap(dest);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_add_exp<src_exp, matrix<T,NR,NC,MM,L> >& src\n        )\n        {\n            // Just switch around the left and right hand sides of the incoming \n            // add expression and pass it back into matrix_assign_blas() so that\n            // the above function will be called.\n            typedef matrix_add_exp<matrix<T,NR,NC,MM,L> ,src_exp> swapped_add_exp;\n            matrix_assign_blas(dest, swapped_add_exp(src.rhs, src.lhs)); \n        }\n            \n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L,\n            typename src_exp \n            >\n        void matrix_assign_blas (\n            matrix<T,NR,NC,MM,L>& dest,\n            const matrix_subtract_exp<matrix<T,NR,NC,MM,L> ,src_exp>& src\n        )\n        {\n            if (src.rhs.aliases(dest) == false)\n            {\n                if (&src.lhs != &dest)\n                {\n                    dest = src.lhs;\n                }\n\n                matrix_assign_blas_proxy(dest, src.rhs, -1, true, false);\n            }\n            else\n            {\n                matrix<T,NR,NC,MM,L> temp(src.lhs);\n                matrix_assign_blas_proxy(temp, src.rhs, -1, true, false);\n                temp.swap(dest);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n    // ------------------------------------------------------------------------------------\n\n    } // end of namespace blas_bindings \n\n    // ------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L,\n        typename src_exp \n        >\n    inline typename enable_if_c<(is_same_type<T,float>::value ||\n                                is_same_type<T,double>::value ||\n                                is_same_type<T,std::complex<float> >::value ||\n                                is_same_type<T,std::complex<double> >::value) &&\n                                blas_bindings::has_matrix_multiply<src_exp>::value\n    >::type matrix_assign_big (\n        matrix<T,NR,NC,MM,L>& dest,\n        const src_exp& src\n    )\n    {\n        blas_bindings::matrix_assign_blas(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L,\n        typename src_exp \n        >\n    inline typename enable_if_c<(is_same_type<T,float>::value ||\n                                is_same_type<T,double>::value ||\n                                is_same_type<T,std::complex<float> >::value ||\n                                is_same_type<T,std::complex<double> >::value) &&\n                                blas_bindings::has_matrix_multiply<src_exp>::value\n    >::type matrix_assign_big (\n        assignable_sub_matrix<T,NR,NC,MM,L>& dest,\n        const src_exp& src\n    )\n    {\n        blas_bindings::matrix_assign_blas(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename src_exp \n        >\n    inline typename enable_if_c<(is_same_type<T,float>::value ||\n                                is_same_type<T,double>::value ||\n                                is_same_type<T,std::complex<float> >::value ||\n                                is_same_type<T,std::complex<double> >::value) &&\n                                blas_bindings::has_matrix_multiply<src_exp>::value\n    >::type matrix_assign_big (\n        assignable_ptr_matrix<T>& dest,\n        const src_exp& src\n    )\n    {\n        blas_bindings::matrix_assign_blas(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L,\n        typename src_exp \n        >\n    inline typename enable_if_c<(is_same_type<T,float>::value ||\n                                is_same_type<T,double>::value ||\n                                is_same_type<T,std::complex<float> >::value ||\n                                is_same_type<T,std::complex<double> >::value) &&\n                                blas_bindings::has_matrix_multiply<src_exp>::value\n    >::type matrix_assign_big (\n        assignable_row_matrix<T,NR,NC,MM,L>& dest,\n        const src_exp& src\n    )\n    {\n        blas_bindings::matrix_assign_blas(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L,\n        typename src_exp \n        >\n    inline typename enable_if_c<(is_same_type<T,float>::value ||\n                                is_same_type<T,double>::value ||\n                                is_same_type<T,std::complex<float> >::value ||\n                                is_same_type<T,std::complex<double> >::value) &&\n                                blas_bindings::has_matrix_multiply<src_exp>::value\n    >::type matrix_assign_big (\n        assignable_col_matrix<T,NR,NC,MM,L>& dest,\n        const src_exp& src\n    )\n    {\n        blas_bindings::matrix_assign_blas(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_ASSIGn_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_assign_fwd.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_ASSIGn_FWD_\n#define DLIB_MATRIx_ASSIGn_FWD_\n\n// GCC 4.8 gives false alarms about some variables being uninitialized.  Disable these\n// false warnings.\n#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wmaybe-uninitialized\"\n#endif\n\n#include \"../enable_if.h\"\n#include \"matrix_data_layout.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n    \n    /*\n        The point of the matrix_assign() functions is to contain all the various \n        optimizations that help the matrix assign a matrix_exp to an actual matrix \n        object quickly.\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    namespace ma\n    {\n        // This template here controls how big a compile time sized matrix needs\n        // to be for it to get passed into the optimized versions of the \n        // matrix_assign() function.  So small matrices are evaluated with a simple\n        // loop like the ones in this file and bigger matrices may get sent to BLAS\n        // routines or some other kind of optimized thing.\n        template < typename EXP, typename enable = void >\n        struct is_small_matrix { static const bool value = false; };\n        template < typename EXP >\n        struct is_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&\n        EXP::NR<=17 && EXP::NC<=17 && (EXP::cost <= 70)>::type> { static const bool value = true; };\n\n        // I wouldn't use this mul object to do the multiply but visual studio 7.1 wouldn't\n        // compile otherwise.\n        template <long a, long b>\n        struct mul { const static long value = a*b; };\n\n        template < typename EXP, typename enable = void >\n        struct is_very_small_matrix { static const bool value = false; };\n        template < typename EXP >\n        struct is_very_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&\n        (mul<EXP::NR,EXP::NC>::value <= 16) && (EXP::cost <= 70)>::type> { static const bool value = true; };\n\n\n        template < typename EXP, typename enable = void >\n        struct has_column_major_layout { static const bool value = false; };\n        template < typename EXP >\n        struct has_column_major_layout<EXP, typename enable_if<is_same_type<typename EXP::layout_type, column_major_layout> >::type > \n        { static const bool value = true; };\n\n\n        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    class matrix_exp;\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP1, typename EXP2>\n    inline typename disable_if<ma::has_column_major_layout<EXP1> >::type  \n    matrix_assign_default (\n        EXP1& dest,\n        const EXP2& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        for (long r = 0; r < src.nr(); ++r)\n        {\n            for (long c = 0; c < src.nc(); ++c)\n            {\n                dest(r,c) = src(r,c);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP1, typename EXP2>\n    inline typename enable_if<ma::has_column_major_layout<EXP1> >::type  \n    matrix_assign_default (\n        EXP1& dest,\n        const EXP2& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        for (long c = 0; c < src.nc(); ++c)\n        {\n            for (long r = 0; r < src.nr(); ++r)\n            {\n                dest(r,c) = src(r,c);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP1, typename EXP2>\n    inline typename disable_if<ma::has_column_major_layout<EXP1> >::type  \n    matrix_assign_default (\n        EXP1& dest,\n        const EXP2& src,\n        typename EXP2::type alpha,\n        bool add_to\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - if (add_to == false) then\n                - #dest == alpha*src\n            - else\n                - #dest == dest + alpha*src\n    !*/\n    {\n        if (add_to)\n        {\n            if (alpha == static_cast<typename EXP2::type>(1))\n            {\n                for (long r = 0; r < src.nr(); ++r)\n                {\n                    for (long c = 0; c < src.nc(); ++c)\n                    {\n                        dest(r,c) += src(r,c);\n                    }\n                }\n            }\n            else if (alpha == static_cast<typename EXP2::type>(-1))\n            {\n                for (long r = 0; r < src.nr(); ++r)\n                {\n                    for (long c = 0; c < src.nc(); ++c)\n                    {\n                        dest(r,c) -= src(r,c);\n                    }\n                }\n            }\n            else\n            {\n                for (long r = 0; r < src.nr(); ++r)\n                {\n                    for (long c = 0; c < src.nc(); ++c)\n                    {\n                        dest(r,c) += alpha*src(r,c);\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (alpha == static_cast<typename EXP2::type>(1))\n            {\n                for (long r = 0; r < src.nr(); ++r)\n                {\n                    for (long c = 0; c < src.nc(); ++c)\n                    {\n                        dest(r,c) = src(r,c);\n                    }\n                }\n            }\n            else\n            {\n                for (long r = 0; r < src.nr(); ++r)\n                {\n                    for (long c = 0; c < src.nc(); ++c)\n                    {\n                        dest(r,c) = alpha*src(r,c);\n                    }\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP1, typename EXP2>\n    inline typename enable_if<ma::has_column_major_layout<EXP1> >::type  \n    matrix_assign_default (\n        EXP1& dest,\n        const EXP2& src,\n        typename EXP2::type alpha,\n        bool add_to\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - if (add_to == false) then\n                - #dest == alpha*src\n            - else\n                - #dest == dest + alpha*src\n    !*/\n    {\n        if (add_to)\n        {\n            if (alpha == static_cast<typename EXP2::type>(1))\n            {\n                for (long c = 0; c < src.nc(); ++c)\n                {\n                    for (long r = 0; r < src.nr(); ++r)\n                    {\n                        dest(r,c) += src(r,c);\n                    }\n                }\n            }\n            else if (alpha == static_cast<typename EXP2::type>(-1))\n            {\n                for (long c = 0; c < src.nc(); ++c)\n                {\n                    for (long r = 0; r < src.nr(); ++r)\n                    {\n                        dest(r,c) -= src(r,c);\n                    }\n                }\n            }\n            else\n            {\n                for (long c = 0; c < src.nc(); ++c)\n                {\n                    for (long r = 0; r < src.nr(); ++r)\n                    {\n                        dest(r,c) += alpha*src(r,c);\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (alpha == static_cast<typename EXP2::type>(1))\n            {\n                for (long c = 0; c < src.nc(); ++c)\n                {\n                    for (long r = 0; r < src.nr(); ++r)\n                    {\n                        dest(r,c) = src(r,c);\n                    }\n                }\n            }\n            else\n            {\n                for (long c = 0; c < src.nc(); ++c)\n                {\n                    for (long r = 0; r < src.nr(); ++r)\n                    {\n                        dest(r,c) = alpha*src(r,c);\n                    }\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename src_exp \n        >\n    void matrix_assign_big (\n        matrix_dest_type& dest,\n        const matrix_exp<src_exp>& src\n    )\n    {\n        matrix_assign_default(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename src_exp \n        >\n    inline typename disable_if<ma::is_small_matrix<src_exp> >::type matrix_assign (\n        matrix_dest_type& dest,\n        const matrix_exp<src_exp>& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        // Call src.ref() here so that the derived type of the matrix_exp shows \n        // up so we can overload matrix_assign_big() based on various matrix expression\n        // types.\n        matrix_assign_big(dest,src.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n// this code is here to perform an unrolled version of the matrix_assign() function\n    template < typename DEST, typename SRC, long NR, long NC,\n    long R = 0, long C = 0, bool base_case = (R==NR) >\n    struct matrix_unroll_helper\n    {\n        inline static void go ( DEST& dest, const SRC& src)\n        {\n            dest(R,C) = src(R,C);\n            matrix_unroll_helper<DEST,SRC,NR,NC, R + (C+1)/NC,  (C+1)%NC>::go(dest,src);\n        }\n    };\n\n    template < typename DEST, typename SRC, long NR, long NC, long R, long C >\n    struct matrix_unroll_helper<DEST,SRC,NR,NC,R,C,true>\n    { inline static void go ( DEST& , const SRC& ) {} };\n\n    template <typename DEST, typename SRC>\n    inline void matrix_assign_unrolled (\n        DEST& dest,\n        const SRC& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        COMPILE_TIME_ASSERT(SRC::NR*SRC::NC != 0);\n        matrix_unroll_helper<DEST,SRC, SRC::NR, SRC::NC>::go(dest,src);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename src_exp \n        >\n    inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==false >::type matrix_assign (\n        matrix_dest_type& dest,\n        const matrix_exp<src_exp>& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        matrix_assign_default(dest,src.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename src_exp \n        >\n    inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==true >::type matrix_assign (\n        matrix_dest_type& dest,\n        const matrix_exp<src_exp>& src\n    )\n    /*!\n        requires\n            - src.destructively_aliases(dest) == false\n            - dest.nr() == src.nr()\n            - dest.nc() == src.nc()\n        ensures\n            - #dest == src\n    !*/\n    {\n        matrix_assign_unrolled(dest,src.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))\n#pragma GCC diagnostic pop\n#endif\n\n#endif // DLIB_MATRIx_ASSIGn_FWD_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_blas_bindings.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_BLAS_BINDINGS_\n#define DLIB_MATRIx_BLAS_BINDINGS_\n\n\n#ifndef DLIB_USE_BLAS\n#error \"DLIB_USE_BLAS should be defined if you want to use the BLAS bindings\"\n#endif\n\n#include \"matrix_assign.h\"\n#include \"matrix_conj_trans.h\"\n#include \"cblas_constants.h\"\n#include <stdint.h>\n\n//#include <iostream>\n//using namespace std;\n\nnamespace dlib\n{\n\n\n    namespace blas_bindings \n    {\n\n#ifdef DLIB_TEST_BLAS_BINDINGS\n        int& counter_gemm();\n        int& counter_gemv();\n        int& counter_ger();\n        int& counter_dot();\n        int& counter_axpy();\n        int& counter_scal();\n\n        #define DLIB_TEST_BLAS_BINDING_GEMM ++counter_gemm();\n        #define DLIB_TEST_BLAS_BINDING_GEMV ++counter_gemv();\n        #define DLIB_TEST_BLAS_BINDING_GER ++counter_ger();\n        #define DLIB_TEST_BLAS_BINDING_DOT ++counter_dot();\n        #define DLIB_TEST_BLAS_BINDING_AXPY ++counter_axpy();\n        #define DLIB_TEST_BLAS_BINDING_SCAL ++counter_scal();\n#else\n        #define DLIB_TEST_BLAS_BINDING_GEMM \n        #define DLIB_TEST_BLAS_BINDING_GEMV \n        #define DLIB_TEST_BLAS_BINDING_GER \n        #define DLIB_TEST_BLAS_BINDING_DOT \n        #define DLIB_TEST_BLAS_BINDING_AXPY\n        #define DLIB_TEST_BLAS_BINDING_SCAL\n#endif\n\n#ifdef DLIB_DEFINE_CBLAS_API\n        extern \"C\"\n        {\n            // Here we declare the prototypes for the CBLAS calls used by the BLAS bindings below\n\n            void cblas_saxpy(const CBLAS_INT_TYPE N, const float alpha, const float *X,\n                            const CBLAS_INT_TYPE incX, float *Y, const CBLAS_INT_TYPE incY);\n            void cblas_daxpy(const CBLAS_INT_TYPE N, const double alpha, const double *X,\n                            const CBLAS_INT_TYPE incX, double *Y, const CBLAS_INT_TYPE incY);\n            void cblas_caxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                            const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY);\n            void cblas_zaxpy(const CBLAS_INT_TYPE N, const void *alpha, const void *X,\n                            const CBLAS_INT_TYPE incX, void *Y, const CBLAS_INT_TYPE incY);\n\n            void cblas_sscal(const CBLAS_INT_TYPE N, const float alpha, float *X, const CBLAS_INT_TYPE incX);\n            void cblas_dscal(const CBLAS_INT_TYPE N, const double alpha, double *X, const CBLAS_INT_TYPE incX);\n            void cblas_cscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX);\n            void cblas_zscal(const CBLAS_INT_TYPE N, const void *alpha, void *X, const CBLAS_INT_TYPE incX);\n\n            void cblas_sgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const CBLAS_INT_TYPE K, const float alpha, const float *A,\n                             const CBLAS_INT_TYPE lda, const float *B, const CBLAS_INT_TYPE ldb,\n                             const float beta, float *C, const CBLAS_INT_TYPE ldc);\n            void cblas_dgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const CBLAS_INT_TYPE K, const double alpha, const double *A,\n                             const CBLAS_INT_TYPE lda, const double *B, const CBLAS_INT_TYPE ldb,\n                             const double beta, double *C, const CBLAS_INT_TYPE ldc);\n            void cblas_cgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                             const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb,\n                             const void *beta, void *C, const CBLAS_INT_TYPE ldc);\n            void cblas_zgemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_TRANSPOSE TransB, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const CBLAS_INT_TYPE K, const void *alpha, const void *A,\n                             const CBLAS_INT_TYPE lda, const void *B, const CBLAS_INT_TYPE ldb,\n                             const void *beta, void *C, const CBLAS_INT_TYPE ldc);\n            void cblas_sgemv(const CBLAS_ORDER order,\n                             const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                             const float *X, const CBLAS_INT_TYPE incX, const float beta,\n                             float *Y, const CBLAS_INT_TYPE incY);\n            void cblas_dgemv(const CBLAS_ORDER order,\n                             const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                             const double *X, const CBLAS_INT_TYPE incX, const double beta,\n                             double *Y, const CBLAS_INT_TYPE incY);\n            void cblas_cgemv(const CBLAS_ORDER order,\n                             const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                             const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                             void *Y, const CBLAS_INT_TYPE incY);\n            void cblas_zgemv(const CBLAS_ORDER order,\n                             const CBLAS_TRANSPOSE TransA, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *A, const CBLAS_INT_TYPE lda,\n                             const void *X, const CBLAS_INT_TYPE incX, const void *beta,\n                             void *Y, const CBLAS_INT_TYPE incY);\n            void cblas_sger(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                            const float alpha, const float *X, const CBLAS_INT_TYPE incX,\n                            const float *Y, const CBLAS_INT_TYPE incY, float *A, const CBLAS_INT_TYPE lda);\n            void cblas_dger(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                            const double alpha, const double *X, const CBLAS_INT_TYPE incX,\n                            const double *Y, const CBLAS_INT_TYPE incY, double *A, const CBLAS_INT_TYPE lda);\n            void cblas_cgerc(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                             const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\n            void cblas_zgerc(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                             const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\n            float  cblas_sdot(const CBLAS_INT_TYPE N, const float  *X, const CBLAS_INT_TYPE incX,\n                              const float  *Y, const CBLAS_INT_TYPE incY);\n            double cblas_ddot(const CBLAS_INT_TYPE N, const double *X, const CBLAS_INT_TYPE incX,\n                              const double *Y, const CBLAS_INT_TYPE incY);\n            void   cblas_cdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                                   const void *Y, const CBLAS_INT_TYPE incY, void *dotu);\n            void   cblas_zdotu_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                                   const void *Y, const CBLAS_INT_TYPE incY, void *dotu);\n            void   cblas_cdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                                   const void *Y, const CBLAS_INT_TYPE incY, void *dotc);\n            void   cblas_zdotc_sub(const CBLAS_INT_TYPE N, const void *X, const CBLAS_INT_TYPE incX,\n                                   const void *Y, const CBLAS_INT_TYPE incY, void *dotc);\n            void cblas_cgeru(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                             const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\n            void cblas_zgeru(const CBLAS_ORDER order, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const void *alpha, const void *X, const CBLAS_INT_TYPE incX,\n                             const void *Y, const CBLAS_INT_TYPE incY, void *A, const CBLAS_INT_TYPE lda);\n        }\n#endif // if DLIB_DEFINE_CBLAS_API\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_axpy(const int N, const float alpha, const float *X,\n                        const int incX, float *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_AXPY;\n            cblas_saxpy(N, alpha, X, incX, Y, incY);\n        }\n\n        inline void cblas_axpy(const int N, const double alpha, const double *X,\n                        const int incX, double *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_AXPY;\n            cblas_daxpy(N, alpha, X, incX, Y, incY);\n        }\n\n        inline void cblas_axpy(const int N, const std::complex<float>& alpha, const std::complex<float> *X,\n                        const int incX, std::complex<float> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_AXPY;\n            cblas_caxpy(N, (float*)&alpha, (float*)X, incX, (float*)Y, incY);\n        }\n\n        inline void cblas_axpy(const int N, const std::complex<double>& alpha, const std::complex<double> *X,\n                        const int incX, std::complex<double> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_AXPY;\n            cblas_zaxpy(N, (double*)&alpha, (double*)X, incX, (double*)Y, incY);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_scal(const int N, const float alpha, float *X)\n        {\n            DLIB_TEST_BLAS_BINDING_SCAL;\n            cblas_sscal(N, alpha, X, 1);\n        }\n\n        inline void cblas_scal(const int N, const double alpha, double *X)\n        {\n            DLIB_TEST_BLAS_BINDING_SCAL;\n            cblas_dscal(N, alpha, X, 1);\n        }\n\n        inline void cblas_scal(const int N, const std::complex<float>& alpha, std::complex<float> *X)\n        {\n            DLIB_TEST_BLAS_BINDING_SCAL;\n            cblas_cscal(N, (float*)&alpha, (float*)X, 1);\n        }\n\n        inline void cblas_scal(const int N, const std::complex<double>& alpha, std::complex<double> *X)\n        {\n            DLIB_TEST_BLAS_BINDING_SCAL;\n            cblas_zscal(N, (double*)&alpha, (double*)X, 1);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_gemm( const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                                const CBLAS_TRANSPOSE TransB, const int M, const int N,\n                                const int K, const float alpha, const float *A,\n                                const int lda, const float *B, const int ldb,\n                                const float beta, float *C, const int ldc)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMM;\n            cblas_sgemm( Order, TransA, TransB,  M,  N,\n                          K,  alpha, A, lda, B,  ldb, beta, C,  ldc);\n        }\n\n        inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                         const CBLAS_TRANSPOSE TransB, const int M, const int N,\n                         const int K, const double alpha, const double *A,\n                         const int lda, const double *B, const int ldb,\n                         const double beta, double *C, const int ldc)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMM;\n            cblas_dgemm( Order, TransA, TransB,  M,  N,\n                          K,  alpha, A, lda, B,  ldb, beta, C,  ldc);\n        }\n\n        inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                         const CBLAS_TRANSPOSE TransB, const int M, const int N,\n                         const int K, const std::complex<float>& alpha, const std::complex<float> *A,\n                         const int lda, const std::complex<float> *B, const int ldb,\n                         const std::complex<float>& beta, std::complex<float> *C, const int ldc)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMM;\n            cblas_cgemm( Order, TransA, TransB,  M,  N,\n                          K,  (float*)&alpha, (float*)A, lda, (float*)B,  ldb, (float*)&beta, (float*)C,  ldc);\n        }\n\n        inline void cblas_gemm(const CBLAS_ORDER Order, const CBLAS_TRANSPOSE TransA,\n                         const CBLAS_TRANSPOSE TransB, const int M, const int N,\n                         const int K, const std::complex<double>& alpha, const std::complex<double> *A,\n                         const int lda, const std::complex<double> *B, const int ldb,\n                         const std::complex<double>& beta, std::complex<double> *C, const int ldc)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMM;\n            cblas_zgemm( Order, TransA, TransB,  M,  N,\n                          K,  (double*)&alpha, (double*)A, lda, (double*)B,  ldb, (double*)&beta, (double*)C,  ldc);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_gemv(const CBLAS_ORDER order,\n                        const CBLAS_TRANSPOSE TransA, const int M, const int N,\n                        const float alpha, const float *A, const int lda,\n                        const float *X, const int incX, const float beta,\n                        float *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMV;\n            cblas_sgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        }\n\n        inline void cblas_gemv(const CBLAS_ORDER order,\n                        const CBLAS_TRANSPOSE TransA, const int M, const int N,\n                        const double alpha, const double *A, const int lda,\n                        const double *X, const int incX, const double beta,\n                        double *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMV;\n            cblas_dgemv(order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        }\n\n        inline void cblas_gemv(const CBLAS_ORDER order,\n                        const CBLAS_TRANSPOSE TransA, const int M, const int N,\n                        const std::complex<float>& alpha, const std::complex<float> *A, const int lda,\n                        const std::complex<float> *X, const int incX, const std::complex<float>& beta,\n                        std::complex<float> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMV;\n            cblas_cgemv(order, TransA, M, N, (float*)&alpha, (float*)A, lda, (float*)X, incX, (float*)&beta, (float*)Y, incY);\n        }\n\n        inline void cblas_gemv(const CBLAS_ORDER order,\n                        const CBLAS_TRANSPOSE TransA, const int M, const int N,\n                        const std::complex<double>& alpha, const std::complex<double> *A, const int lda,\n                        const std::complex<double> *X, const int incX, const std::complex<double>& beta,\n                        std::complex<double> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_GEMV;\n            cblas_zgemv(order, TransA, M, N, (double*)&alpha, (double*)A, lda, (double*)X, incX, (double*)&beta, (double*)Y, incY);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N,\n                        const std::complex<float>& alpha, const std::complex<float> *X, const int incX,\n                        const std::complex<float> *Y, const int incY, std::complex<float> *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_cgeru (order,  M, N, (float*)&alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda);\n        }\n\n        inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N,\n                        const std::complex<double>& alpha, const std::complex<double> *X, const int incX,\n                        const std::complex<double> *Y, const int incY, std::complex<double> *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_zgeru (order,  M, N, (double*)&alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda);\n        }\n\n        inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N,\n                        const float alpha, const float *X, const int incX,\n                        const float *Y, const int incY, float *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_sger (order,  M, N, alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda);\n        }\n\n        inline void cblas_ger(const CBLAS_ORDER order, const int M, const int N,\n                        const double alpha, const double *X, const int incX,\n                        const double *Y, const int incY, double *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_dger (order,  M, N, alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline void cblas_gerc(const CBLAS_ORDER order, const int M, const int N,\n                        const std::complex<float>& alpha, const std::complex<float> *X, const int incX,\n                        const std::complex<float> *Y, const int incY, std::complex<float> *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_cgerc (order,  M, N, (float*)&alpha, (float*)X, incX, (float*)Y, incY, (float*)A, lda);\n        }\n\n        inline void cblas_gerc(const CBLAS_ORDER order, const int M, const int N,\n                        const std::complex<double>& alpha, const std::complex<double> *X, const int incX,\n                        const std::complex<double> *Y, const int incY, std::complex<double> *A, const int lda)\n        {\n            DLIB_TEST_BLAS_BINDING_GER;\n            cblas_zgerc (order,  M, N, (double*)&alpha, (double*)X, incX, (double*)Y, incY, (double*)A, lda);\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline float cblas_dot(const int N, const float  *X, const int incX,\n                        const float  *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            return cblas_sdot(N, X, incX, Y, incY);\n        }\n\n        inline double cblas_dot(const int N, const double *X, const int incX,\n                        const double *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            return cblas_ddot(N, X, incX, Y, incY);\n        }\n\n        inline std::complex<float> cblas_dot(const int N, const std::complex<float> *X, const int incX,\n                            const std::complex<float> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            std::complex<float> result;\n            cblas_cdotu_sub(N, (float*)X, incX, (float*)Y, incY, (float*)&result);\n            return result;\n        }\n\n        inline std::complex<double> cblas_dot(const int N, const std::complex<double> *X, const int incX,\n                            const std::complex<double> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            std::complex<double> result;\n            cblas_zdotu_sub(N, (double*)X, incX, (double*)Y, incY, (double*)&result);\n            return result;\n        }\n\n    // ----------------------------------------------------------------------------------------\n\n        inline std::complex<float> cblas_dotc(const int N, const std::complex<float> *X, const int incX,\n                            const std::complex<float> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            std::complex<float> result;\n            cblas_cdotc_sub(N, (float*)X, incX, (float*)Y, incY, (float*)&result);\n            return result;\n        }\n\n        inline std::complex<double> cblas_dotc(const int N, const std::complex<double> *X, const int incX,\n                            const std::complex<double> *Y, const int incY)\n        {\n            DLIB_TEST_BLAS_BINDING_DOT;\n            std::complex<double> result;\n            cblas_zdotc_sub(N, (double*)X, incX, (double*)Y, incY, (double*)&result);\n            return result;\n        }\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    // Helpers for determining the data pointer, LDA, and incX arguments to BLAS functions.\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const matrix<T,NR,NC,MM,row_major_layout>& m) { return m.nc(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const matrix<T,NR,NC,MM,column_major_layout>& m) { return m.nr(); }\n\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const matrix_op<op_subm<matrix<T,NR,NC,MM,row_major_layout> > >& m) { return m.op.m.nc(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const matrix_op<op_subm<matrix<T,NR,NC,MM,column_major_layout> > >& m) { return m.op.m.nr(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_sub_matrix<T,NR,NC,MM,row_major_layout>& m) { return m.m.nc(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_sub_matrix<T,NR,NC,MM,column_major_layout>& m) { return m.m.nr(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_col_matrix<T,NR,NC,MM,row_major_layout>& m) { return m.m.nc(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_col_matrix<T,NR,NC,MM,column_major_layout>& m) { return m.m.nr(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_row_matrix<T,NR,NC,MM,row_major_layout>& m) { return m.m.nc(); }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_ld (const assignable_row_matrix<T,NR,NC,MM,column_major_layout>& m) { return m.m.nr(); }\n\n        template <typename T>\n        int get_ld (const assignable_ptr_matrix<T>& m) { return m.nc(); }\n\n        template <typename T, typename MM>\n        int get_ld (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& m) { return m.nc(); }\n        template <typename T, typename MM>\n        int get_ld (const matrix_op<op_array_to_mat<array<T,MM> > >& m) { return m.nc(); }\n        template < typename value_type, typename alloc >\n        int get_ld (const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > >& m) { return m.nc(); }\n        template < typename value_type, typename alloc >\n        int get_ld (const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > >& m) { return m.nc(); }\n        template <typename T>\n        int get_ld (const matrix_op<op_pointer_to_col_vect<T> >& m) { return m.nc(); }\n        template <typename T>\n        int get_ld (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.stride; }\n\n        // --------\n\n        // get_inc() returns the offset from one element to another.  If an object has a\n        // non-uniform offset between elements then returns 0 (e.g. a subm() view could\n        // have a non-uniform offset between elements).\n\n        template <typename T, typename MM>\n        int get_inc (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& ) { return 1; }\n        template <typename T, typename MM>\n        int get_inc (const matrix_op<op_array_to_mat<array<T,MM> > >& ) { return 1; }\n        template < typename value_type, typename alloc >\n        int get_inc (const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > >& ) { return 1; }\n        template < typename value_type, typename alloc >\n        int get_inc (const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > >& ) { return 1; }\n        template <typename T>\n        int get_inc (const matrix_op<op_pointer_to_col_vect<T> >& ) { return 1; }\n        template <typename T>\n        int get_inc (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.stride==m.op.cols ? 1 : 0; }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        int get_inc (const matrix<T,NR,NC,MM,L>& ) { return 1; }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc (const matrix_op<op_subm<matrix<T,NR,NC,MM,row_major_layout> > >& m) \n        { \n            // if the sub-view doesn't cover all the columns then it can't have a uniform\n            // layout.\n            if (m.nc() < m.op.m.nc())\n                return 0;\n            else\n                return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc (const matrix_op<op_subm<matrix<T,NR,NC,MM,column_major_layout> > >& m) \n        { \n            if (m.nr() < m.op.m.nr())\n                return 0;\n            else\n                return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc (const assignable_sub_matrix<T,NR,NC,MM,row_major_layout>& m) \n        { \n            if (m.nc() < m.m.nc())\n                return 0;\n            else\n                return 1;\n        }\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc (const assignable_sub_matrix<T,NR,NC,MM,column_major_layout>& m) \n        {\n            if (m.nr() < m.m.nr())\n                return 0;\n            else\n                return 1;\n        }\n\n        template <typename T>\n        int get_inc (const assignable_ptr_matrix<T>& ) { return 1; }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_colm<matrix<T,NR,NC,MM,row_major_layout> > >& m)\n        {\n            return m.op.m.nc();\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_rowm<matrix<T,NR,NC,MM,row_major_layout> > >& )\n        {\n            return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_colm2<matrix<T,NR,NC,MM,row_major_layout> > >& m)\n        {\n            return m.op.m.nc();\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_rowm2<matrix<T,NR,NC,MM,row_major_layout> > >& )\n        {\n            return 1;\n        }\n\n\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_colm<matrix<T,NR,NC,MM,column_major_layout> > >& )\n        {\n            return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_rowm<matrix<T,NR,NC,MM,column_major_layout> > >& m)\n        {\n            return m.op.m.nr();\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_colm2<matrix<T,NR,NC,MM,column_major_layout> > >& )\n        {\n            return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const matrix_op<op_rowm2<matrix<T,NR,NC,MM,column_major_layout> > >& m)\n        {\n            return m.op.m.nr();\n        }\n\n\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const assignable_row_matrix<T,NR,NC,MM,row_major_layout>& )\n        {\n            return 1;\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const assignable_row_matrix<T,NR,NC,MM,column_major_layout>& m)\n        {\n            return m.m.nr();\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const assignable_col_matrix<T,NR,NC,MM,row_major_layout>& m)\n        {\n            return m.m.nc();\n        }\n\n        template <typename T, long NR, long NC, typename MM>\n        int get_inc(const assignable_col_matrix<T,NR,NC,MM,column_major_layout>& )\n        {\n            return 1;\n        }\n\n        // --------\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        T* get_ptr (matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix_op<op_subm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.r_,m.op.c_); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix_op<op_colm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(0,m.op.col); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix_op<op_rowm<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.row,0); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix_op<op_colm2<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(0,m.op.col); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        const T* get_ptr (const matrix_op<op_rowm2<matrix<T,NR,NC,MM,L> > >& m) { return &m.op.m(m.op.row,0); }\n\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        T* get_ptr (assignable_col_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        T* get_ptr (assignable_row_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }\n\n        template <typename T, long NR, long NC, typename MM, typename L>\n        T* get_ptr (assignable_sub_matrix<T,NR,NC,MM,L>& m) { return &m(0,0); }\n\n        template <typename T>\n        T* get_ptr (assignable_ptr_matrix<T>& m) { return m.ptr; }\n\n        template <typename T, typename MM>\n        const T* get_ptr (const matrix_op<op_array2d_to_mat<array2d<T,MM> > >& m) { return &m.op.array[0][0]; }\n        template <typename T, typename MM>\n        const T* get_ptr (const matrix_op<op_array_to_mat<array<T,MM> > >& m) { return &m.op.vect[0]; }\n        template < typename T, typename alloc >\n        const T* get_ptr (const matrix_op<op_std_vect_to_mat<std::vector<T,alloc> > >& m) { return &m.op.vect[0]; }\n        template < typename T, typename alloc >\n        const T* get_ptr (const matrix_op<op_std_vect_to_mat<std_vector_c<T,alloc> > >& m) { return &m.op.vect[0]; }\n        template <typename T>\n        const T* get_ptr (const matrix_op<op_pointer_to_col_vect<T> >& m) { return m.op.ptr; }\n        template <typename T>\n        const T* get_ptr (const matrix_op<op_pointer_to_mat<T> >& m) { return m.op.ptr; }\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        // Here we declare some matrix objects for use in the DLIB_ADD_BLAS_BINDING macro.  These\n        // extern declarations don't actually correspond to any real matrix objects.  They are\n        // simply here so we can build matrix expressions with the DLIB_ADD_BLAS_BINDING marco.\n\n\n        // Note that the fact that these are double matrices isn't important, it is just a placeholder in this case.  \n        extern matrix<double> m;     // general matrix \n        extern matrix<double,1,0> rv;  // general row vector\n        extern matrix<double,0,1> cv;  // general column vector\n        extern const double s;\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       AXPY/SCAL overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m)\n        {\n\n            const int N = static_cast<int>(src.size());\n            if (transpose == false && N != 0)\n            {\n                if (add_to)\n                {\n                    if (get_inc(src) && get_inc(dest))\n                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n                else\n                {\n                    if (get_ptr(src) == get_ptr(dest))\n                        cblas_scal(N, alpha, get_ptr(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n            }\n            else\n            {\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n            }\n\n        } DLIB_END_BLAS_BINDING\n\n        DLIB_ADD_BLAS_BINDING(rv)\n        {\n\n            const int N = static_cast<int>(src.size());\n            if (transpose == false && N != 0)\n            {\n                if (add_to)\n                {\n                    if (get_inc(src) && get_inc(dest))\n                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n                else\n                {\n                    if (get_ptr(src) == get_ptr(dest))\n                        cblas_scal(N, alpha, get_ptr(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n            }\n            else\n            {\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n            }\n\n        } DLIB_END_BLAS_BINDING\n\n        DLIB_ADD_BLAS_BINDING(cv)\n        {\n\n            const int N = static_cast<int>(src.size());\n            if (transpose == false && N != 0)\n            {\n                if (add_to)\n                {\n                    if (get_inc(src) && get_inc(dest))\n                        cblas_axpy(N, alpha, get_ptr(src), get_inc(src), get_ptr(dest), get_inc(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n                else\n                {\n                    if (get_ptr(src) == get_ptr(dest))\n                        cblas_scal(N, alpha, get_ptr(dest));\n                    else\n                        matrix_assign_default(dest, src, alpha, add_to);\n                }\n            }\n            else\n            {\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n            }\n\n        } DLIB_END_BLAS_BINDING\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       GEMM overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m*m)\n        {\n            //cout << \"BLAS GEMM: m*m\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs);\n            const int lda = get_ld(src.lhs);\n            const T* B = get_ptr(src.rhs);\n            const int ldb = get_ld(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, CblasNoTrans, CblasNoTrans, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                cblas_gemm(Order, CblasTrans, CblasTrans, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(m)*m)\n        {\n            //cout << \"BLAS GEMM: trans(m)*m\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const CBLAS_TRANSPOSE TransB = CblasNoTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs);\n            const int ldb = get_ld(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                cblas_gemm(Order, TransA, TransB, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m*trans(m))\n        {\n            //cout << \"BLAS GEMM: m*trans(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const CBLAS_TRANSPOSE TransB = CblasTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs);\n            const int lda = get_ld(src.lhs);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                cblas_gemm(Order, TransA, TransB, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(m)*trans(m))\n        {\n            //cout << \"BLAS GEMM: trans(m)*trans(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, CblasTrans, CblasTrans, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                cblas_gemm(Order, CblasNoTrans, CblasNoTrans, N, M, K, alpha, B, ldb, A, lda, beta, C, ldc);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n        // --------------------------------------\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(m))*m)\n        {\n            //cout << \"BLAS GEMM: trans(conj(m))*m\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const CBLAS_TRANSPOSE TransB = CblasNoTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs);\n            const int ldb = get_ld(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(m))\n        {\n            //cout << \"BLAS GEMM: trans(conj(m))*trans(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const CBLAS_TRANSPOSE TransB = CblasTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m*trans(conj(m)))\n        {\n            //cout << \"BLAS GEMM: m*trans(conj(m))\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const CBLAS_TRANSPOSE TransB = CblasConjTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs);\n            const int lda = get_ld(src.lhs);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(m)*trans(conj(m)))\n        {\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const CBLAS_TRANSPOSE TransB = CblasConjTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(conj(m)))\n        {\n            //cout << \"BLAS GEMM: trans(conj(m))*trans(conj(m))\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const CBLAS_TRANSPOSE TransB = CblasConjTrans;\n            const int M = static_cast<int>(src.nr());\n            const int N = static_cast<int>(src.nc());\n            const int K = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* B = get_ptr(src.rhs.op.m);\n            const int ldb = get_ld(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* C = get_ptr(dest);\n            const int ldc = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gemm(Order, TransA, TransB, M, N, K, alpha, A, lda, B, ldb, beta, C, ldc);\n            else\n                matrix_assign_default(dest, trans(src), alpha, add_to);\n        } DLIB_END_BLAS_BINDING\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       GEMV overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m*cv)\n        {\n            //cout << \"BLAS GEMV: m*cv\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const int M = static_cast<int>(src.lhs.nr());\n            const int N = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs);\n            const int lda = get_ld(src.lhs);\n            const T* X = get_ptr(src.rhs);\n            const int incX = get_inc(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(rv*m)\n        {\n            // Note that rv*m is the same as trans(m)*trans(rv)\n\n            //cout << \"BLAS GEMV: rv*m\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const int M = static_cast<int>(src.rhs.nr());\n            const int N = static_cast<int>(src.rhs.nc());\n            const T* A = get_ptr(src.rhs);\n            const int lda = get_ld(src.rhs);\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(cv)*m)\n        {\n            // Note that trans(cv)*m is the same as trans(m)*cv\n\n            //cout << \"BLAS GEMV: trans(cv)*m\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const int M = static_cast<int>(src.rhs.nr());\n            const int N = static_cast<int>(src.rhs.nc());\n            const T* A = get_ptr(src.rhs);\n            const int lda = get_ld(src.rhs);\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(m*trans(rv))\n        {\n            //cout << \"BLAS GEMV: m*trans(rv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const int M = static_cast<int>(src.lhs.nr());\n            const int N = static_cast<int>(src.lhs.nc());\n            const T* A = get_ptr(src.lhs);\n            const int lda = get_ld(src.lhs);\n            const T* X = get_ptr(src.rhs.op.m);\n            const int incX = get_inc(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n        // --------------------------------------\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(m)*cv)\n        {\n            //cout << \"BLAS GEMV: trans(m)*cv\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const int M = static_cast<int>(src.lhs.op.m.nr());\n            const int N = static_cast<int>(src.lhs.op.m.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* X = get_ptr(src.rhs);\n            const int incX = get_inc(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(rv*trans(m))\n        {\n            // Note that rv*trans(m) is the same as m*trans(rv)\n\n            //cout << \"BLAS GEMV: rv*trans(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const int M = static_cast<int>(src.rhs.op.m.nr());\n            const int N = static_cast<int>(src.rhs.op.m.nc());\n            const T* A = get_ptr(src.rhs.op.m);\n            const int lda = get_ld(src.rhs.op.m);\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(cv)*trans(m))\n        {\n            // Note that trans(cv)*trans(m) is the same as m*cv\n\n            //cout << \"BLAS GEMV: trans(cv)*trans(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasNoTrans;\n            const int M = static_cast<int>(src.rhs.op.m.nr());\n            const int N = static_cast<int>(src.rhs.op.m.nc());\n            const T* A = get_ptr(src.rhs.op.m);\n            const int lda = get_ld(src.rhs.op.m);\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(m)*trans(rv))\n        {\n            //cout << \"BLAS GEMV: trans(m)*trans(rv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasTrans;\n            const int M = static_cast<int>(src.lhs.op.m.nr());\n            const int N = static_cast<int>(src.lhs.op.m.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* X = get_ptr(src.rhs.op.m);\n            const int incX = get_inc(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n        // --------------------------------------\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(cv)*conj(m))\n        {\n            // Note that trans(cv)*conj(m) == conj(trans(m))*cv\n            //cout << \"BLAS GEMV: trans(cv)*conj(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const int M = static_cast<int>(src.rhs.op.m.nr());\n            const int N = static_cast<int>(src.rhs.op.m.nc());\n            const T* A = get_ptr(src.rhs.op.m);\n            const int lda = get_ld(src.rhs.op.m);\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(rv*conj(m))\n        {\n            // Note that rv*conj(m) == conj(trans(m))*cv\n            //cout << \"BLAS GEMV: rv*conj(m)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const int M = static_cast<int>(src.rhs.op.m.nr());\n            const int N = static_cast<int>(src.rhs.op.m.nc());\n            const T* A = get_ptr(src.rhs.op.m);\n            const int lda = get_ld(src.rhs.op.m);\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(m))*cv)\n        {\n            //cout << \"BLAS GEMV: trans(conj(m))*cv\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const int M = static_cast<int>(src.lhs.op.m.nr());\n            const int N = static_cast<int>(src.lhs.op.m.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* X = get_ptr(src.rhs);\n            const int incX = get_inc(src.rhs);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(m))*trans(rv))\n        {\n            //cout << \"BLAS GEMV: trans(conj(m))*trans(rv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const CBLAS_TRANSPOSE TransA = CblasConjTrans;\n            const int M = static_cast<int>(src.lhs.op.m.nr());\n            const int N = static_cast<int>(src.lhs.op.m.nc());\n            const T* A = get_ptr(src.lhs.op.m);\n            const int lda = get_ld(src.lhs.op.m);\n            const T* X = get_ptr(src.rhs.op.m);\n            const int incX = get_inc(src.rhs.op.m);\n\n            const T beta = static_cast<T>(add_to?1:0);\n            T* Y = get_ptr(dest);\n            const int incY = get_inc(dest);\n\n            cblas_gemv(Order, TransA, M, N, alpha, A, lda, X, incX, beta, Y, incY);\n        } DLIB_END_BLAS_BINDING\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       GER overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(cv*rv)\n        {\n            //cout << \"BLAS GER: cv*rv\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(rv)*rv)\n        {\n            //cout << \"BLAS GER: trans(rv)*rv\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(cv*trans(cv))\n        {\n            //cout << \"BLAS GER: cv*trans(cv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(rv)*trans(cv))\n        {\n            //cout << \"BLAS GER: trans(rv)*trans(cv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_ger(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_ger(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n        } DLIB_END_BLAS_BINDING\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       GERC overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        /*\n        DLIB_ADD_BLAS_BINDING(cv*conj(rv))\n        {\n            //cout << \"BLAS GERC: cv*conj(rv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n        } DLIB_END_BLAS_BINDING\n        */\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(cv*conj(trans(cv)))\n        {\n            //cout << \"BLAS GERC: cv*conj(trans(cv))\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n\n            if (transpose == false)\n            {\n                T* A = get_ptr(dest);\n                const int lda = get_ld(dest);\n\n                if (add_to == false)\n                    zero_matrix(dest);\n\n                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            }\n            else\n            {\n                matrix_assign_default(dest,trans(src),alpha,add_to);\n                //cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n            }\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(rv)*conj(trans(cv)))\n        {\n            //cout << \"BLAS GERC: trans(rv)*conj(trans(cv))\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n\n            if (transpose == false)\n            {\n                if (add_to == false)\n                    zero_matrix(dest);\n\n                T* A = get_ptr(dest);\n                const int lda = get_ld(dest);\n\n                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            }\n            else\n            {\n                matrix_assign_default(dest,trans(src),alpha,add_to);\n                //cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n            }\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        /*\n        DLIB_ADD_BLAS_BINDING(trans(rv)*conj(rv))\n        {\n            //cout << \"BLAS GERC: trans(rv)*conj(rv)\" << endl;\n            const bool is_row_major_order = is_same_type<typename dest_exp::layout_type,row_major_layout>::value;  \n            const CBLAS_ORDER Order = is_row_major_order ? CblasRowMajor : CblasColMajor;\n            const int M = static_cast<int>(dest.nr());\n            const int N = static_cast<int>(dest.nc());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                zero_matrix(dest);\n\n            T* A = get_ptr(dest);\n            const int lda = get_ld(dest);\n\n            if (transpose == false)\n                cblas_gerc(Order, M, N, alpha, X, incX, Y, incY, A, lda);\n            else\n                cblas_gerc(Order, M, N, alpha, Y, incY, X, incX, A, lda);\n        } DLIB_END_BLAS_BINDING\n        */\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       DOT overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(rv*cv)\n        {\n            //cout << \"BLAS DOT: rv*cv\" << endl;\n            const int N = static_cast<int>(src.lhs.size());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(cv)*cv)\n        {\n            //cout << \"BLAS DOT: trans(cv)*cv\" << endl;\n            const int N = static_cast<int>(src.lhs.size());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(rv*trans(rv))\n        {\n            //cout << \"BLAS DOT: rv*trans(rv)\" << endl;\n            const int N = static_cast<int>(src.lhs.size());\n            const T* X = get_ptr(src.lhs);\n            const int incX = get_inc(src.lhs);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(cv)*trans(rv))\n        {\n            //cout << \"BLAS DOT: trans(cv)*trans(rv)\" << endl;\n            const int N = static_cast<int>(src.lhs.op.m.size());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dot(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dot(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n    //                       DOTC overloads\n    // ----------------------------------------------------------------------------------------\n    // ----------------------------------------------------------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(conj(rv)*cv)\n        {\n            //cout << \"BLAS DOTC: conj(rv)*cv\" << endl;\n            const int N = static_cast<int>(src.lhs.op.m.size());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(conj(trans(cv))*cv)\n        {\n            //cout << \"BLAS DOTC: conj(trans(cv))*cv\" << endl;\n            const int N = static_cast<int>(src.lhs.op.m.size());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs);\n            const int incY = get_inc(src.rhs);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n        // --------------------------------------\n\n        DLIB_ADD_BLAS_BINDING(trans(conj(cv))*trans(rv))\n        {\n            //cout << \"BLAS DOTC: trans(conj(cv))*trans(rv)\" << endl;\n            const int N = static_cast<int>(src.lhs.op.m.size());\n            const T* X = get_ptr(src.lhs.op.m);\n            const int incX = get_inc(src.lhs.op.m);\n            const T* Y = get_ptr(src.rhs.op.m);\n            const int incY = get_inc(src.rhs.op.m);\n\n            if (add_to == false)\n                dest(0) = alpha*cblas_dotc(N, X, incX, Y, incY);\n            else\n                dest(0) += alpha*cblas_dotc(N, X, incX, Y, incY);\n\n        } DLIB_END_BLAS_BINDING\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_BLAS_BINDINGS_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_cholesky.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n// This code was adapted from code from the JAMA part of NIST's TNT library.\n//    See: http://math.nist.gov/tnt/ \n#ifndef DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H\n#define DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H\n\n#include \"matrix.h\" \n#include \"matrix_utilities.h\"\n#include \"matrix_subexp.h\"\n#include <cmath>\n\n#ifdef DLIB_USE_LAPACK\n#include \"lapack/potrf.h\"\n#endif\n\n#include \"matrix_trsm.h\"\n\nnamespace dlib \n{\n\n    template <\n        typename matrix_exp_type\n        >\n    class cholesky_decomposition\n    {\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n\n        // You have supplied an invalid type of matrix_exp_type.  You have\n        // to use this object with matrices that contain float or double type data.\n        COMPILE_TIME_ASSERT((is_same_type<float, type>::value || \n                             is_same_type<double, type>::value ));\n\n\n\n        template <typename EXP>\n        cholesky_decomposition(\n            const matrix_exp<EXP>& A\n        );\n\n        bool is_spd(\n        ) const;\n\n        const matrix_type& get_l(\n        ) const;\n\n        template <typename EXP>\n        const typename EXP::matrix_type solve (\n            const matrix_exp<EXP>& B\n        ) const;\n\n    private:\n\n        matrix_type L_;     // lower triangular factor\n        bool isspd;         // true if matrix to be factored was SPD\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                      Member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    bool cholesky_decomposition<matrix_exp_type>::\n    is_spd(\n    ) const\n    {\n        return isspd;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename cholesky_decomposition<matrix_exp_type>::matrix_type& cholesky_decomposition<matrix_exp_type>::\n    get_l(\n    ) const\n    {\n        return L_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    cholesky_decomposition<matrix_exp_type>::\n    cholesky_decomposition(\n        const matrix_exp<EXP>& A_\n    )\n    {\n        using std::sqrt;\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A_.nr() == A_.nc() && A_.size() > 0,\n            \"\\tcholesky_decomposition::cholesky_decomposition(A_)\"\n            << \"\\n\\tYou can only use this on square matrices\"\n            << \"\\n\\tA_.nr():   \" << A_.nr()\n            << \"\\n\\tA_.nc():   \" << A_.nc()\n            << \"\\n\\tA_.size(): \" << A_.size()\n            << \"\\n\\tthis:      \" << this\n            );\n\n#ifdef DLIB_USE_LAPACK\n        L_ = A_;\n        const type eps = max(abs(diag(L_)))*std::sqrt(std::numeric_limits<type>::epsilon())/100;\n\n        // check if the matrix is actually symmetric\n        bool is_symmetric = true;\n        for (long r = 0; r < L_.nr() && is_symmetric; ++r)\n        {\n            for (long c = r+1; c < L_.nc() && is_symmetric; ++c)\n            {\n                // this is approximately doing: is_symmetric = is_symmetric && ( L_(k,j) == L_(j,k))\n                is_symmetric = is_symmetric && (std::abs(L_(r,c) - L_(c,r)) < eps ); \n            }\n        }\n\n        // now compute the actual cholesky decomposition\n        int info = lapack::potrf('L', L_);\n\n        // check if it's really SPD\n        if (info == 0 && is_symmetric && min(abs(diag(L_))) > eps*100)\n            isspd = true;\n        else\n            isspd = false;\n\n        L_ = lowerm(L_);\n#else\n        const_temp_matrix<EXP> A(A_);\n\n\n        isspd = true;\n\n        const long n = A.nc();\n        L_.set_size(n,n); \n\n\n        // do nothing if the matrix is empty\n        if (A.size() == 0)\n            return;\n\n        const type eps = std::numeric_limits<type>::epsilon();\n\n        const type eps2 = max(abs(diag(A)))*std::sqrt(std::numeric_limits<type>::epsilon())/100;\n\n\n\n        // compute the upper left corner\n        if (A(0,0) > 0)\n        {\n            L_(0,0) = std::sqrt(A(0,0));\n            if (A(0,0) <= eps2)\n                isspd = false;\n        }\n        else\n        {\n            isspd = false;\n            L_(0,0) = 0;\n        }\n\n        // compute the first column\n        for (long r = 1; r < A.nr(); ++r)\n        {\n            // if (L_(0,0) > 0)\n            if (L_(0,0) > eps*std::abs(A(r,0)))\n            {\n                L_(r,0) = A(r,0)/L_(0,0);\n            }\n            else\n            {\n                isspd = false;\n                L_(r,0) = 0;\n            }\n\n            isspd = isspd && (std::abs(A(r,0) - A(0,r)) <= eps*std::abs(A(r,0)) ); \n        }\n\n        // now compute all the other columns\n        for (long c = 1; c < A.nc(); ++c)\n        {\n            // compute the diagonal element\n            type temp = A(c,c);\n            for (long i = 0; i < c; ++i)\n                temp -= L_(c,i)*L_(c,i);\n\n            if (temp > 0)\n            {\n                L_(c,c) = std::sqrt(temp);\n                if (temp <= eps2)\n                    isspd = false;\n            }\n            else\n            {\n                L_(c,c) = 0;\n                isspd = false;\n            }\n\n            for (long r = 0; r < c; ++r)\n                L_(r,c) = 0;\n\n            // compute the non diagonal elements\n            for (long r = c+1; r < A.nr(); ++r)\n            {\n                temp = A(r,c);\n                for (long i = 0; i < c; ++i)\n                {\n                    temp -= L_(r,i)*L_(c,i);\n                }\n\n                // if (L_(c,c) > 0)\n                if (L_(c,c) > eps*std::abs(temp))\n                {\n                    L_(r,c) = temp/L_(c,c);\n                }\n                else\n                {\n                    isspd = false;\n                    L_(r,c) = 0;\n                }\n\n                isspd = isspd && (std::abs(A(r,c) - A(c,r)) <= eps*std::abs(A(r,c)) ); \n            }\n        }\n\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    const typename EXP::matrix_type cholesky_decomposition<matrix_exp_type>::\n    solve(\n        const matrix_exp<EXP>& B\n    ) const\n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(L_.nr() == B.nr(),\n            \"\\tconst matrix cholesky_decomposition::solve(B)\"\n            << \"\\n\\tInvalid arguments were given to this function.\"\n            << \"\\n\\tL_.nr():  \" << L_.nr() \n            << \"\\n\\tB.nr():   \" << B.nr() \n            << \"\\n\\tthis:     \" << this\n            );\n\n        matrix<type, NR, EXP::NC, mem_manager_type, layout_type>  X(B); \n\n        using namespace blas_bindings;\n        // Solve L*y = b;\n        triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, L_, X);\n        // Solve L'*X = Y;\n        triangular_solver(CblasLeft, CblasLower, CblasTrans, CblasNonUnit, L_, X);\n        return X;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n\n} \n\n#endif // DLIB_MATRIX_CHOLESKY_DECOMPOSITION_H \n\n\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_conj_trans.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_CONJ_TRANS_FUNCTIONS\n#define DLIB_MATRIx_CONJ_TRANS_FUNCTIONS \n\n#include \"matrix_utilities.h\"\n#include \"matrix_math_functions.h\"\n#include \"matrix.h\"\n#include \"../algs.h\"\n#include <cmath>\n#include <complex>\n#include <limits>\n\n\nnamespace dlib\n{\n    /*!\n        The point of the two functions defined in this file is to make statements\n        of the form conj(trans(m)) and trans(conj(m)) look the same so that it is\n        easier to map them to BLAS functions later on.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_conj_trans \n    {\n        op_conj_trans( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost+1;\n        const static long NR = M::NC;\n        const static long NC = M::NR;\n        typedef typename M::type type;\n        typedef typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply (long r, long c) const { return std::conj(m(c,r)); }\n\n        long nr () const { return m.nc(); }\n        long nc () const { return m.nr(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    }; \n\n    template <typename EXP>\n    const matrix_op<op_conj_trans<EXP> > trans (\n        const matrix_op<op_conj<EXP> >& m\n    )\n    {\n        typedef op_conj_trans<EXP> op;\n        return matrix_op<op>(op(m.op.m));\n    }\n\n    template <typename EXP>\n    const matrix_op<op_conj_trans<EXP> > conj (\n        const matrix_op<op_trans<EXP> >& m\n    )\n    {\n        typedef op_conj_trans<EXP> op;\n        return matrix_op<op>(op(m.op.m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_CONJ_TRANS_FUNCTIONS\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_conv.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_CONV_Hh_\n#define DLIB_MATRIx_CONV_Hh_\n\n#include \"matrix_conv_abstract.h\"\n#include \"matrix.h\"\n#include \"matrix_fft.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        const T& conj(const T& item) { return item; }\n        template <typename T>\n        std::complex<T> conj(const std::complex<T>& item) { return std::conj(item); }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, bool flip_m2 = false>\n    struct op_conv \n    {\n        op_conv( const M1& m1_, const M2& m2_) : \n            m1(m1_),\n            m2(m2_), \n            nr_(m1.nr()+m2.nr()-1),\n            nc_(m1.nc()+m2.nc()-1)\n        {\n            if (nr_ < 0 || m1.size() == 0 || m2.size() == 0)\n                nr_ = 0;\n            if (nc_ < 0 || m1.size() == 0 || m2.size() == 0)\n                nc_ = 0;\n        }\n\n        const M1& m1;\n        const M2& m2;\n        long nr_; \n        long nc_;\n\n        const static long cost = (M1::cost+M2::cost)*10;\n        const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR+M2::NR-1);\n        const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC+M2::NC-1);\n        typedef typename M1::type type;\n        typedef type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const \n        { \n            type temp = 0;\n\n            const long min_rr = std::max<long>(r-m2.nr()+1, 0);\n            const long max_rr = std::min<long>(m1.nr()-1, r);\n\n            const long min_cc = std::max<long>(c-m2.nc()+1, 0);\n            const long max_cc = std::min<long>(m1.nc()-1, c);\n\n            for (long rr = min_rr; rr <= max_rr; ++rr)\n            {\n                for (long cc = min_cc; cc <= max_cc; ++cc)\n                {\n                    if (flip_m2)\n                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));\n                    else\n                        temp += m1(rr,cc)*m2(r-rr,c-cc);\n                }\n            }\n\n            return temp; \n        }\n\n        long nr () const { return nr_; }\n        long nc () const { return nc_; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n\n    }; \n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv<M1,M2> > conv (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv<M1,M2> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv<M1,M2,true> > xcorr (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv<M1,M2,true> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline size_t bounding_power_of_two (\n            size_t n\n        )\n        {\n            size_t s = 1;\n            for (unsigned int i = 0; i < sizeof(s)*8 && s < n; ++i)\n                s <<= 1;\n            return s;\n        }\n    }\n\n    template <\n        typename EXP1, \n        typename EXP2\n        >\n    typename EXP1::matrix_type xcorr_fft(\n        const matrix_exp<EXP1>& u,\n        const matrix_exp<EXP2>& v\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type, typename EXP2::type>::value == true));\n        using T = typename EXP1::type;\n        COMPILE_TIME_ASSERT((is_same_type<double,T>::value || is_same_type<float,T>::value || is_same_type<long double,T>::value ));\n\n        const long pad_nr = impl::bounding_power_of_two(u.nr() + v.nr() - 1);\n        const long pad_nc = impl::bounding_power_of_two(u.nc() + v.nc() - 1);\n\n        matrix<std::complex<T>> U(pad_nr, pad_nc), V(pad_nr,pad_nc);\n\n        U = 0;\n        V = 0;\n        set_subm(U,U.nr()-u.nr(),U.nc()-u.nc(),u.nr(),u.nc()) = u;\n        set_subm(V,get_rect(v)) = v;\n\n        fft_inplace(U);\n        fft_inplace(V);\n\n        return subm(real(ifft(pointwise_multiply(U, conj(V)))),\n            U.nr()-u.nr()-v.nr()+1, \n            U.nc()-u.nc()-v.nc()+1, \n            u.nr()+v.nr()-1,\n            u.nc()+v.nc()-1\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, bool flip_m2 = false>\n    struct op_conv_same \n    {\n        op_conv_same( const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),nr_(m1.nr()),nc_(m1.nc())\n        {\n            if (m1.size() == 0 || m2.size() == 0)\n                nr_ = 0;\n            if (m1.size() == 0 || m2.size() == 0)\n                nc_ = 0;\n        }\n\n        const M1& m1;\n        const M2& m2;\n        long nr_;\n        long nc_;\n\n        const static long cost = (M1::cost+M2::cost)*10;\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n        typedef typename M1::type type;\n        typedef type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const \n        { \n            r += m2.nr()/2;\n            c += m2.nc()/2;\n\n            type temp = 0;\n\n            const long min_rr = std::max<long>(r-m2.nr()+1, 0);\n            const long max_rr = std::min<long>(m1.nr()-1, r);\n\n            const long min_cc = std::max<long>(c-m2.nc()+1, 0);\n            const long max_cc = std::min<long>(m1.nc()-1, c);\n\n            for (long rr = min_rr; rr <= max_rr; ++rr)\n            {\n                for (long cc = min_cc; cc <= max_cc; ++cc)\n                {\n                    if (flip_m2)\n                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));\n                    else\n                        temp += m1(rr,cc)*m2(r-rr,c-cc);\n                }\n            }\n\n            return temp; \n        }\n\n        long nr () const { return nr_; }\n        long nc () const { return nc_; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n\n    }; \n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv_same<M1,M2> > conv_same (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv_same<M1,M2> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv_same<M1,M2,true> > xcorr_same (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv_same<M1,M2,true> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, bool flip_m2 = false>\n    struct op_conv_valid \n    {\n        op_conv_valid( const M1& m1_, const M2& m2_) : \n            m1(m1_),m2(m2_),\n            nr_(m1.nr()-m2.nr()+1),\n            nc_(m1.nc()-m2.nc()+1)\n        {\n            if (nr_ < 0 || nc_ <= 0 || m1.size() == 0 || m2.size() == 0)\n                nr_ = 0;\n            if (nc_ < 0 || nr_ <= 0 || m1.size() == 0 || m2.size() == 0)\n                nc_ = 0;\n        }\n\n        const M1& m1;\n        const M2& m2;\n        long nr_; \n        long nc_;\n\n        const static long cost = (M1::cost+M2::cost)*10;\n        const static long NR = (M1::NR*M2::NR==0) ? (0) : (M1::NR-M2::NR+1);\n        const static long NC = (M1::NC*M2::NC==0) ? (0) : (M1::NC-M2::NC+1);\n        typedef typename M1::type type;\n        typedef type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const \n        { \n            r += m2.nr()-1;\n            c += m2.nc()-1;\n\n            type temp = 0;\n\n            const long min_rr = std::max<long>(r-m2.nr()+1, 0);\n            const long max_rr = std::min<long>(m1.nr()-1, r);\n\n            const long min_cc = std::max<long>(c-m2.nc()+1, 0);\n            const long max_cc = std::min<long>(m1.nc()-1, c);\n\n            for (long rr = min_rr; rr <= max_rr; ++rr)\n            {\n                for (long cc = min_cc; cc <= max_cc; ++cc)\n                {\n                    if (flip_m2)\n                        temp += m1(rr,cc)*dlib::impl::conj(m2(m2.nr()-r+rr-1, m2.nc()-c+cc-1));\n                    else\n                        temp += m1(rr,cc)*m2(r-rr,c-cc);\n                }\n            }\n\n            return temp; \n        }\n\n        long nr () const { return nr_; }\n        long nc () const { return nc_; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m1.aliases(item) || m2.aliases(item); }\n\n    }; \n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv_valid<M1,M2> > conv_valid (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv_valid<M1,M2> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n    template <\n        typename M1,\n        typename M2\n        >\n    const matrix_op<op_conv_valid<M1,M2,true> > xcorr_valid (\n        const matrix_exp<M1>& m1,\n        const matrix_exp<M2>& m2\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename M1::type,typename M2::type>::value == true));\n\n        typedef op_conv_valid<M1,M2,true> op;\n        return matrix_op<op>(op(m1.ref(),m2.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_CONV_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_conv_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_CONV_ABSTRACT_Hh_\n#ifdef DLIB_MATRIx_CONV_ABSTRACT_Hh_\n\n#include \"matrix_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp conv (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the convolution of m1 with m2.  In particular, this function is \n                  equivalent to performing the following in matlab: R = conv2(m1,m2).\n                - R::type == the same type that was in m1 and m2.\n                - R.nr() == m1.nr()+m2.nr()-1\n                - R.nc() == m1.nc()+m2.nc()-1\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp xcorr (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the cross-correlation of m1 with m2.  In particular, this\n                  function returns conv(m1,flip(m2)) if the matrices contain real\n                  elements and conv(m1,flip(conj(m2))) if they are complex.\n                - R::type == the same type that was in m1 and m2.\n                - R.nr() == m1.nr()+m2.nr()-1\n                - R.nc() == m1.nc()+m2.nc()-1\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp xcorr_fft (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n            - m1 and m2 contain real or complex values and must be double, float, or long\n              double valued. (e.g. not integers)\n        ensures\n            - This function is identical to xcorr() except that it uses a fast Fourier\n              transform to do the convolution and is therefore much faster when both m1 and\n              m2 are large.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp conv_same (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the convolution of m1 with m2.  In particular, this function is \n                  equivalent to performing the following in matlab: R = conv2(m1,m2,'same').\n                  In particular, this means the result will have the same dimensions as m1 and will\n                  contain the central part of the full convolution.  Therefore, conv_same(m1,m2) is \n                  equivalent to subm(conv(m1,m2), m2.nr()/2, m2.nc()/2, m1.nr(), m1.nc()).\n                - R::type == the same type that was in m1 and m2.\n                - R.nr() == m1.nr()\n                - R.nc() == m1.nc()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp xcorr_same (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the cross-correlation of m1 with m2.  In particular, this\n                  function returns conv_same(m1,flip(m2)) if the matrices contain real\n                  elements and conv_same(m1,flip(conj(m2))) if they are complex.\n                - R::type == the same type that was in m1 and m2.\n                - R.nr() == m1.nr()\n                - R.nc() == m1.nc()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp conv_valid (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the convolution of m1 with m2.  In particular, this function is \n                  equivalent to performing the following in matlab: R = conv2(m1,m2,'valid').\n                  In particular, this means only elements of the convolution which don't require \n                  zero padding are included in the result.\n                - R::type == the same type that was in m1 and m2.\n                - if (m1 has larger dimensions than m2) then\n                    - R.nr() == m1.nr()-m2.nr()+1\n                    - R.nc() == m1.nc()-m2.nc()+1\n                - else\n                    - R.nr() == 0\n                    - R.nc() == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp xcorr_valid (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - m1 and m2 both contain elements of the same type\n        ensures\n            - returns a matrix R such that:\n                - R is the cross-correlation of m1 with m2.  In particular, this\n                  function returns conv_valid(m1,flip(m2)) if the matrices contain real\n                  elements and conv_valid(m1,flip(conj(m2))) if they are complex.\n                - R::type == the same type that was in m1 and m2.\n                - if (m1 has larger dimensions than m2) then\n                    - R.nr() == m1.nr()-m2.nr()+1\n                    - R.nc() == m1.nc()-m2.nc()+1\n                - else\n                    - R.nr() == 0\n                    - R.nc() == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_CONV_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_data_layout.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_DATA_LAYOUT_\n#define DLIB_MATRIx_DATA_LAYOUT_\n\n#include \"../algs.h\"\n#include \"matrix_fwd.h\"\n#include \"matrix_data_layout_abstract.h\"\n#ifdef MATLAB_MEX_FILE\n#include <mex.h>\n#endif\n\n// GCC 4.8 gives false alarms about some matrix operations going out of bounds.  Disable\n// these false warnings.\n#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Warray-bounds\"\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        A matrix layout object is any object that contains a templated class called \"layout\"\n        with an interface identical to one below:\n        (Note that all the template arguments are just the template arguments from the dlib::matrix \n        object and the member functions are defined identically to the ones with the same \n        signatures inside the matrix object.)\n\n        struct matrix_layout\n        {\n            template <\n                typename T,\n                long num_rows,\n                long num_cols,\n                typename mem_manager\n                >\n            class layout \n            {\n            public:\n\n                T& operator() (\n                    size_t r, \n                    size_t c\n                );\n\n                const T& operator() (\n                    size_t r, \n                    size_t c\n                );\n\n                T& operator() (\n                    size_t i \n                );\n\n                const T& operator() (\n                    size_t i\n                ) const;\n\n                void swap(\n                    layout& item\n                );\n\n                long nr (\n                ) const;\n\n                long nc (\n                ) const;\n\n                void set_size (\n                    size_t nr_,\n                    size_t nc_\n                );\n            };\n        };\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    struct row_major_layout\n    {\n        // if a matrix is bigger than this many bytes then don't put it on the stack\n        const static size_t max_stack_based_size = 256;\n\n        // this is a hack to avoid a compile time error in visual studio 8.  I would just \n        // use sizeof(T) and be done with it but that won't compile.  The idea here \n        // is to avoid using the stack allocation of the layout object if it \n        // is going to contain another matrix and also avoid asking for the sizeof()\n        // the contained matrix.\n        template <typename T>\n        struct get_sizeof_helper\n        {\n            const static std::size_t val = sizeof(T);\n        };\n\n        template <typename T, long NR, long NC, typename mm, typename l>\n        struct get_sizeof_helper<matrix<T,NR,NC,mm,l> >\n        {\n            const static std::size_t val = 1000000;\n        };\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager,\n            int val = static_switch <\n                // when the sizes are all non zero and small\n                (num_rows*num_cols*get_sizeof_helper<T>::val <= max_stack_based_size) && (num_rows != 0 && num_cols != 0),\n            // when the sizes are all non zero and big \n            (num_rows*num_cols*get_sizeof_helper<T>::val >  max_stack_based_size) && (num_rows != 0 && num_cols != 0),\n            num_rows == 0 && num_cols != 0,\n            num_rows != 0 && num_cols == 0,\n            num_rows == 0 && num_cols == 0\n            >::value\n            >\n        class layout ;\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the actual allocation of space for a matrix.\n                Small matrices allocate all their data on the stack and bigger ones\n                use a memory_manager to get their memory.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,1> : noncopyable // when the sizes are all non zero and small\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout() {}\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return *(data+r*num_cols + c); }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return *(data+r*num_cols + c); }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i\n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                for (long r = 0; r < num_rows; ++r)\n                {\n                    for (long c = 0; c < num_cols; ++c)\n                    {\n                        exchange((*this)(r,c),item(r,c));\n                    }\n                }\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t ,\n                size_t \n            )\n            {\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n            T data[num_rows*num_cols];\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,2> : noncopyable // when the sizes are all non zero and big \n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ) { data = pool.allocate_array(num_rows*num_cols); }\n\n            ~layout ()\n            { pool.deallocate_array(data); }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[r*num_cols + c]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[r*num_cols + c]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t ,\n                size_t \n            )\n            {\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,3> : noncopyable // when num_rows == 0 && num_cols != 0,\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nr_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                    pool.deallocate_array(data); \n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[r*num_cols + c]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[r*num_cols + c]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nr_,nr_);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nr_ = nr;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nr_ = 0;\n                return ret;\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            long nr_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,4> : noncopyable // when num_rows != 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nc_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[r*nc_ + c]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[r*nc_ + c]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nc_ = nc;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nc_ = 0;\n                return ret;\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            long nc_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nr_(0), nc_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[r*nc_ + c]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[r*nc_ + c]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                std::swap(item.nr_,nr_);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nr_ = nr;\n                nc_ = nc;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nr_ = 0;\n                nc_ = 0;\n                return ret;\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n        private:\n            T* data;\n            long nr_;\n            long nc_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct column_major_layout\n    {\n        // if a matrix is bigger than this many bytes then don't put it on the stack\n        const static size_t max_stack_based_size = 256;\n\n\n        // this is a hack to avoid a compile time error in visual studio 8.  I would just \n        // use sizeof(T) and be done with it but that won't compile.  The idea here \n        // is to avoid using the stack allocation of the layout object if it \n        // is going to contain another matrix and also avoid asking for the sizeof()\n        // the contained matrix.\n        template <typename T>\n        struct get_sizeof_helper\n        {\n            const static std::size_t val = sizeof(T);\n        };\n\n        template <typename T, long NR, long NC, typename mm, typename l>\n        struct get_sizeof_helper<matrix<T,NR,NC,mm,l> >\n        {\n            const static std::size_t val = 1000000;\n        };\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager,\n            int val = static_switch <\n                // when the sizes are all non zero and small\n                (num_rows*num_cols*get_sizeof_helper<T>::val <= max_stack_based_size) && (num_rows != 0 && num_cols != 0),\n            // when the sizes are all non zero and big \n            (num_rows*num_cols*get_sizeof_helper<T>::val > max_stack_based_size) && (num_rows != 0 && num_cols != 0),\n            num_rows == 0 && num_cols != 0,\n            num_rows != 0 && num_cols == 0,\n            num_rows == 0 && num_cols == 0\n            >::value\n            >\n        class layout ;\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the actual allocation of space for a matrix.\n                Small matrices allocate all their data on the stack and bigger ones\n                use a memory_manager to get their memory.\n        !*/\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,1> : noncopyable // when the sizes are all non zero and small\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout() {}\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return *(data+c*num_rows + r); }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return *(data+c*num_rows + r); }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i\n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                for (long r = 0; r < num_rows; ++r)\n                {\n                    for (long c = 0; c < num_cols; ++c)\n                    {\n                        exchange((*this)(r,c),item(r,c));\n                    }\n                }\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t,\n                size_t \n            )\n            {\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n            T data[num_cols*num_rows];\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,2> : noncopyable // when the sizes are all non zero and big \n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ) { data = pool.allocate_array(num_rows*num_cols); }\n\n            ~layout ()\n            { pool.deallocate_array(data); }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*num_rows + r]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*num_rows + r]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t ,\n                size_t \n            )\n            {\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,3> : noncopyable // when num_rows == 0 && num_cols != 0,\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nr_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                    pool.deallocate_array(data); \n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*nr_ + r]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*nr_ + r]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nr_,nr_);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return num_cols; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nr_ = nr;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nr_ = 0;\n                return ret;\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            long nr_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,4> : noncopyable // when num_rows != 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nc_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*num_rows + r]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*num_rows + r]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                pool.swap(item.pool);\n            }\n\n            long nr (\n            ) const { return num_rows; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nc_ = nc;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nc_ = 0;\n                return ret;\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n        private:\n\n            T* data;\n            long nc_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long num_rows,\n            long num_cols,\n            typename mem_manager\n            >\n        class layout<T,num_rows,num_cols,mem_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ):data(0), nr_(0), nc_(0) { }\n\n            ~layout ()\n            { \n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n            }\n\n            T& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*nr_ + r]; }\n\n            const T& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*nr_ + r]; }\n\n            T& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const T& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                std::swap(item.nr_,nr_);\n                pool.swap(item.pool);\n            }\n\n#ifdef MATLAB_MEX_FILE\n            void _private_set_mxArray ( mxArray* ) { DLIB_CASSERT(false, \"This function should never be called.\"); }\n            mxArray* _private_release_mxArray(){DLIB_CASSERT(false, \"This function should never be called.\"); }\n            void _private_mark_owned_by_matlab() {DLIB_CASSERT(false, \"This function should never be called.\"); } \n            bool _private_is_owned_by_matlab() const { return false; }\n#endif\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (data) \n                {\n                    pool.deallocate_array(data);\n                }\n                data = pool.allocate_array(nr*nc);\n                nr_ = nr;\n                nc_ = nc;\n            }\n\n            std::unique_ptr<T[]> steal_memory()\n            {\n                auto ret = pool.extract_array(data);\n                data = nullptr;\n                nr_ = 0;\n                nc_ = 0;\n                return ret;\n            }\n\n        private:\n            T* data;\n            long nr_;\n            long nc_;\n            typename mem_manager::template rebind<T>::other pool;\n        };\n\n#ifdef MATLAB_MEX_FILE\n        template <\n            long num_rows,\n            long num_cols\n            >\n        class layout<double,num_rows,num_cols,default_memory_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ): data(0), nr_(0), nc_(0), owned_by_matlab(false),set_by_private_set_mxArray(false),mem(0) { }\n\n            ~layout ()\n            { \n                if (owned_by_matlab)\n                {\n                    if (!set_by_private_set_mxArray && mem) \n                    {\n                        mxDestroyArray(mem); \n                        mem = 0;\n                        data = 0;\n                    }\n                }\n                else if (data)\n                {\n                    delete [] data;\n                    data = 0;\n                }\n            }\n\n            double& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*nr_ + r]; }\n\n            const double& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*nr_ + r]; }\n\n            double& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const double& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void _private_set_mxArray (\n                mxArray* mem_\n            )\n            {\n                DLIB_CASSERT(mem == 0 && data == 0,\"You can't call this function on an already allocated matrix.\");\n                // We don't own the pointer, so make note of that so we won't try to free\n                // it.\n                set_by_private_set_mxArray = true;\n                owned_by_matlab = true;\n                mem = mem_;\n                data = mxGetPr(mem);\n                nr_ = mxGetM(mem);\n                nc_ = mxGetN(mem);\n            }\n\n            mxArray* _private_release_mxArray()\n            {\n                DLIB_CASSERT(owned_by_matlab,\"\");\n                mxArray* temp = mem;\n                mem = 0;\n                set_by_private_set_mxArray = false;\n                data = 0;\n                nr_ = 0;\n                nc_ = 0;\n                return temp;\n            }\n\n            void _private_mark_owned_by_matlab()\n            {\n                DLIB_CASSERT(mem == 0 && data == 0,\"You can't say a matrix should be owned by matlab after it's been allocated.\");\n                owned_by_matlab = true;\n            }\n            bool _private_is_owned_by_matlab() const\n            {\n                return owned_by_matlab;\n            }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.owned_by_matlab,owned_by_matlab);\n                std::swap(item.set_by_private_set_mxArray,set_by_private_set_mxArray);\n                std::swap(item.mem,mem);\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                std::swap(item.nr_,nr_);\n            }\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (owned_by_matlab)\n                {\n                    if (!set_by_private_set_mxArray && mem) \n                    {\n                        mxDestroyArray(mem); \n                        mem = 0;\n                        data = 0;\n                    }\n                    set_by_private_set_mxArray = false;\n\n                    mem = mxCreateDoubleMatrix(nr, nc, mxREAL);\n                    if (mem == 0)\n                        throw std::bad_alloc();\n                    data = mxGetPr(mem);\n                }\n                else\n                {\n                    if (data)\n                        delete [] data;\n                    data = new double[nr*nc];\n                }\n                nr_ = nr;\n                nc_ = nc;\n            }\n\n            std::unique_ptr<double[]> steal_memory()\n            {\n                DLIB_CASSERT(!owned_by_matlab, \"You can't steal the memory from a matrix if it's owned by MATLAB.\");\n                std::unique_ptr<double[]> ret(data);\n                data = nullptr;\n                nr_ = 0;\n                nc_ = 0;\n                return ret;\n            }\n\n        private:\n            double* data;\n            long nr_;\n            long nc_;\n            bool owned_by_matlab;\n            bool set_by_private_set_mxArray;\n            mxArray* mem;\n        };\n\n        template <\n            long num_rows,\n            long num_cols\n            >\n        class layout<float,num_rows,num_cols,default_memory_manager,5> : noncopyable // when num_rows == 0 && num_cols == 0\n        {\n        public:\n            const static long NR = num_rows;\n            const static long NC = num_cols;\n\n            layout (\n            ): data(0), nr_(0), nc_(0), owned_by_matlab(false),set_by_private_set_mxArray(false),mem(0) { }\n\n            ~layout ()\n            { \n                if (owned_by_matlab)\n                {\n                    if (!set_by_private_set_mxArray && mem) \n                    {\n                        mxDestroyArray(mem); \n                        mem = 0;\n                        data = 0;\n                    }\n                }\n                else if (data)\n                {\n                    delete [] data;\n                    data = 0;\n                }\n            }\n\n            float& operator() (\n                size_t r, \n                size_t c\n            ) { return data[c*nr_ + r]; }\n\n            const float& operator() (\n                size_t r, \n                size_t c\n            ) const { return data[c*nr_ + r]; }\n\n            float& operator() (\n                size_t i \n            ) { return data[i]; }\n\n            const float& operator() (\n                size_t i \n            ) const { return data[i]; }\n\n            void _private_set_mxArray (\n                mxArray* mem_\n            )\n            {\n                DLIB_CASSERT(mem == 0 && data == 0,\"You can't call this function on an already allocated matrix.\");\n                // We don't own the pointer, so make note of that so we won't try to free\n                // it.\n                set_by_private_set_mxArray = true;\n                owned_by_matlab = true;\n                mem = mem_;\n                data = (float*)mxGetData(mem);\n                nr_ = mxGetM(mem);\n                nc_ = mxGetN(mem);\n            }\n\n            mxArray* _private_release_mxArray()\n            {\n                DLIB_CASSERT(owned_by_matlab,\"\");\n                mxArray* temp = mem;\n                mem = 0;\n                set_by_private_set_mxArray = false;\n                data = 0;\n                nr_ = 0;\n                nc_ = 0;\n                return temp;\n            }\n\n            void _private_mark_owned_by_matlab()\n            {\n                DLIB_CASSERT(mem == 0 && data == 0,\"You can't say a matrix should be owned by matlab after it's been allocated.\");\n                owned_by_matlab = true;\n            }\n            bool _private_is_owned_by_matlab() const\n            {\n                return owned_by_matlab;\n            }\n\n            void swap(\n                layout& item\n            )\n            {\n                std::swap(item.owned_by_matlab,owned_by_matlab);\n                std::swap(item.set_by_private_set_mxArray,set_by_private_set_mxArray);\n                std::swap(item.mem,mem);\n                std::swap(item.data,data);\n                std::swap(item.nc_,nc_);\n                std::swap(item.nr_,nr_);\n            }\n\n            long nr (\n            ) const { return nr_; }\n\n            long nc (\n            ) const { return nc_; }\n\n            void set_size (\n                size_t nr,\n                size_t nc\n            )\n            {\n                if (owned_by_matlab)\n                {\n                    if (!set_by_private_set_mxArray && mem) \n                    {\n                        mxDestroyArray(mem); \n                        mem = 0;\n                        data = 0;\n                    }\n                    set_by_private_set_mxArray = false;\n\n                    mem = mxCreateNumericMatrix(nr, nc, mxSINGLE_CLASS, mxREAL);\n                    if (mem == 0)\n                        throw std::bad_alloc();\n                    data = (float*)mxGetData(mem);\n                }\n                else\n                {\n                    if (data)\n                        delete [] data;\n                    data = new float[nr*nc];\n                }\n                nr_ = nr;\n                nc_ = nc;\n            }\n\n            std::unique_ptr<float[]> steal_memory()\n            {\n                DLIB_CASSERT(!owned_by_matlab, \"You can't steal the memory from a matrix if it's owned by MATLAB.\");\n                std::unique_ptr<float[]> ret(data);\n                data = nullptr;\n                nr_ = 0;\n                nc_ = 0;\n                return ret;\n            }\n\n        private:\n            float* data;\n            long nr_;\n            long nc_;\n            bool owned_by_matlab;\n            bool set_by_private_set_mxArray;\n            mxArray* mem;\n        };\n#endif\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))\n#pragma GCC diagnostic pop\n#endif\n\n#endif // DLIB_MATRIx_DATA_LAYOUT_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_data_layout_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_\n#ifdef DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct row_major_layout\n    {\n        /*!\n            This is the default matrix layout.  Any matrix object that uses this\n            layout will be laid out in memory in row major order.  Additionally,\n            all elements are contiguous (e.g. there isn't any padding at the ends of\n            rows or anything like that)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct column_major_layout\n    {\n        /*!\n            Any matrix object that uses this layout will be laid out in memory in \n            column major order.  Additionally, all elements are contiguous (e.g. \n            there isn't any padding at the ends of rows or anything like that)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_DATA_LAYOUT_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_default_mul.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_DEFAULT_MULTIPLY_\n#define DLIB_MATRIx_DEFAULT_MULTIPLY_\n\n#include \"../geometry/rectangle.h\"\n#include \"matrix.h\"\n#include \"matrix_utilities.h\"\n#include \"../enable_if.h\"\n\nnamespace dlib\n{\n\n// ------------------------------------------------------------------------------------\n\n    namespace ma\n    {\n        template < typename EXP, typename enable = void >\n        struct matrix_is_vector { static const bool value = false; };\n        template < typename EXP >\n        struct matrix_is_vector<EXP, typename enable_if_c<EXP::NR==1 || EXP::NC==1>::type > { static const bool value = true; };\n    }\n\n// ------------------------------------------------------------------------------------\n\n    /*!  This file defines the default_matrix_multiply() function.  It is a function \n         that conforms to the following definition:\n\n        template <\n            typename matrix_dest_type,\n            typename EXP1,\n            typename EXP2\n            >\n        void default_matrix_multiply (\n            matrix_dest_type& dest,\n            const EXP1& lhs,\n            const EXP2& rhs\n        );\n            requires\n                - (lhs*rhs).destructively_aliases(dest) == false\n                - dest.nr() == (lhs*rhs).nr()\n                - dest.nc() == (lhs*rhs).nc()\n            ensures\n                - #dest == dest + lhs*rhs\n    !*/\n\n// ------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename EXP1,\n        typename EXP2\n        >\n    typename enable_if_c<ma::matrix_is_vector<EXP1>::value == true || ma::matrix_is_vector<EXP2>::value == true>::type \n    default_matrix_multiply (\n        matrix_dest_type& dest,\n        const EXP1& lhs,\n        const EXP2& rhs\n    )\n    {\n        matrix_assign_default(dest, lhs*rhs, 1, true);\n    }\n\n// ------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_dest_type,\n        typename EXP1,\n        typename EXP2\n        >\n    typename enable_if_c<ma::matrix_is_vector<EXP1>::value == false && ma::matrix_is_vector<EXP2>::value == false>::type \n    default_matrix_multiply (\n        matrix_dest_type& dest,\n        const EXP1& lhs,\n        const EXP2& rhs\n    )\n    {\n        const long bs = 90;\n\n        // if the matrices are small enough then just use the simple multiply algorithm\n        if (lhs.nc() <= 2 || rhs.nc() <= 2 || lhs.nr() <= 2 || rhs.nr() <= 2 || (lhs.size() <= bs*10 && rhs.size() <= bs*10) )\n        {\n            matrix_assign_default(dest, lhs*rhs, 1, true);\n        }\n        else\n        {\n            // if the lhs and rhs matrices are big enough we should use a cache friendly\n            // algorithm that computes the matrix multiply in blocks.  \n\n\n            // Loop over all the blocks in the lhs matrix\n            for (long r = 0; r < lhs.nr(); r+=bs)\n            {\n                for (long c = 0; c < lhs.nc(); c+=bs)\n                {\n                    // make a rect for the block from lhs \n                    rectangle lhs_block(c, r, std::min(c+bs-1,lhs.nc()-1), std::min(r+bs-1,lhs.nr()-1));\n\n                    // now loop over all the rhs blocks we have to multiply with the current lhs block\n                    for (long i = 0; i < rhs.nc(); i += bs)\n                    {\n                        // make a rect for the block from rhs \n                        rectangle rhs_block(i, c, std::min(i+bs-1,rhs.nc()-1), std::min(c+bs-1,rhs.nr()-1));\n\n                        // make a target rect in res\n                        rectangle res_block(rhs_block.left(),lhs_block.top(), rhs_block.right(), lhs_block.bottom());\n\n                        // This loop is optimized assuming that the data is laid out in \n                        // row major order in memory.\n                        for (long r = lhs_block.top(); r <= lhs_block.bottom(); ++r)\n                        {\n                            for (long c = lhs_block.left(); c<= lhs_block.right(); ++c)\n                            {\n                                const typename EXP2::type temp = lhs(r,c);\n                                for (long i = rhs_block.left(); i <= rhs_block.right(); ++i)\n                                {\n                                    dest(r,i) += rhs(c,i)*temp;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n\n    }\n\n// ------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_DEFAULT_MULTIPLY_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_eigenvalue.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n// This code was adapted from code from the JAMA part of NIST's TNT library.\n//    See: http://math.nist.gov/tnt/ \n#ifndef DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H\n#define DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H\n\n#include \"matrix.h\" \n#include \"matrix_utilities.h\"\n#include \"matrix_subexp.h\"\n#include <algorithm>\n#include <complex>\n#include <cmath>\n\n#ifdef DLIB_USE_LAPACK\n#include \"lapack/geev.h\"\n#include \"lapack/syev.h\"\n#include \"lapack/syevr.h\"\n#endif\n\n#define DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH 4\n\nnamespace dlib \n{\n\n    template <\n        typename matrix_exp_type\n        >\n    class eigenvalue_decomposition\n    {\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef typename matrix_exp_type::matrix_type matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n\n        typedef matrix<std::complex<type>,0,0,mem_manager_type,layout_type> complex_matrix_type;\n        typedef matrix<std::complex<type>,NR,1,mem_manager_type,layout_type> complex_column_vector_type;\n\n\n        // You have supplied an invalid type of matrix_exp_type.  You have\n        // to use this object with matrices that contain float or double type data.\n        COMPILE_TIME_ASSERT((is_same_type<float, type>::value || \n                             is_same_type<double, type>::value ));\n\n\n        template <typename EXP>\n        eigenvalue_decomposition(\n            const matrix_exp<EXP>& A\n        ); \n\n        template <typename EXP>\n        eigenvalue_decomposition(\n            const matrix_op<op_make_symmetric<EXP> >& A\n        ); \n\n        long dim (\n        ) const;\n\n        const complex_column_vector_type get_eigenvalues (\n        ) const;\n\n        const column_vector_type& get_real_eigenvalues (\n        ) const;\n\n        const column_vector_type& get_imag_eigenvalues (\n        ) const;\n\n        const complex_matrix_type get_v (\n        ) const;\n\n        const complex_matrix_type get_d (\n        ) const; \n\n        const matrix_type& get_pseudo_v (\n        ) const;\n\n        const matrix_type get_pseudo_d (\n        ) const; \n\n    private:\n\n        /** Row and column dimension (square matrix).  */\n        long n;\n\n        bool issymmetric; \n\n        /** Arrays for internal storage of eigenvalues. */\n\n        column_vector_type d;         /* real part */\n        column_vector_type e;         /* img part */\n\n        /** Array for internal storage of eigenvectors. */\n        matrix_type V;\n\n        /** Array for internal storage of nonsymmetric Hessenberg form.\n        @serial internal storage of nonsymmetric Hessenberg form.\n        */\n        matrix_type H;\n\n\n        /** Working storage for nonsymmetric algorithm.\n        @serial working storage for nonsymmetric algorithm.\n        */\n        column_vector_type ort;\n\n        // Symmetric Householder reduction to tridiagonal form.\n        void tred2();\n\n\n        // Symmetric tridiagonal QL algorithm.\n        void tql2 ();\n\n\n        // Nonsymmetric reduction to Hessenberg form.\n        void orthes ();\n\n\n        // Complex scalar division.\n        type cdivr, cdivi;\n        void cdiv_(type xr, type xi, type yr, type yi);\n\n\n        // Nonsymmetric reduction from Hessenberg to real Schur form.\n        void hqr2 (); \n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                        Public member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    eigenvalue_decomposition<matrix_exp_type>::\n    eigenvalue_decomposition(\n        const matrix_exp<EXP>& A_\n    ) \n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n\n        const_temp_matrix<EXP> A(A_);\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A.nr() == A.nc() && A.size() > 0,\n            \"\\teigenvalue_decomposition::eigenvalue_decomposition(A)\"\n            << \"\\n\\tYou can only use this on square matrices\"\n            << \"\\n\\tA.nr():   \" << A.nr()\n            << \"\\n\\tA.nc():   \" << A.nc()\n            << \"\\n\\tA.size(): \" << A.size()\n            << \"\\n\\tthis:     \" << this\n            );\n\n\n        n = A.nc();\n        V.set_size(n,n);\n        d.set_size(n);\n        e.set_size(n);\n\n\n        issymmetric = true;\n        for (long j = 0; (j < n) && issymmetric; j++) \n        {\n            for (long i = 0; (i < n) && issymmetric; i++) \n            {\n                issymmetric = (A(i,j) == A(j,i));\n            }\n        }\n\n        if (issymmetric) \n        {\n            V = A;\n\n#ifdef DLIB_USE_LAPACK\n            if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)\n            {\n                e = 0;\n\n                // We could compute the result using syev()\n                //lapack::syev('V', 'L', V,  d);\n\n                // Instead, we use syevr because its faster and maybe more stable.\n                matrix_type tempA(A);\n                matrix<lapack::integer,0,0,mem_manager_type,layout_type> isupz;\n\n                lapack::integer temp;\n                lapack::syevr('V','A','L',tempA,0,0,0,0,-1,temp,d,V,isupz);\n                return;\n            }\n#endif\n            // Tridiagonalize.\n            tred2();\n\n            // Diagonalize.\n            tql2();\n\n        } \n        else \n        {\n\n#ifdef DLIB_USE_LAPACK\n            if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)\n            {\n                matrix<type,0,0,mem_manager_type, column_major_layout> temp, vl, vr;\n                temp = A;\n                lapack::geev('N', 'V', temp, d, e, vl, vr);\n                V = vr;\n                return;\n            }\n#endif\n            H = A;\n\n            ort.set_size(n);\n\n            // Reduce to Hessenberg form.\n            orthes();\n\n            // Reduce Hessenberg to real Schur form.\n            hqr2();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    eigenvalue_decomposition<matrix_exp_type>::\n    eigenvalue_decomposition(\n        const matrix_op<op_make_symmetric<EXP> >& A\n    ) \n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A.nr() == A.nc() && A.size() > 0,\n            \"\\teigenvalue_decomposition::eigenvalue_decomposition(A)\"\n            << \"\\n\\tYou can only use this on square matrices\"\n            << \"\\n\\tA.nr():   \" << A.nr()\n            << \"\\n\\tA.nc():   \" << A.nc()\n            << \"\\n\\tA.size(): \" << A.size()\n            << \"\\n\\tthis:     \" << this\n            );\n\n\n        n = A.nc();\n        V.set_size(n,n);\n        d.set_size(n);\n        e.set_size(n);\n\n\n        V = A;\n\n#ifdef DLIB_USE_LAPACK\n        if (A.nr() > DLIB_LAPACK_EIGENVALUE_DECOMP_SIZE_THRESH)\n        {\n            e = 0;\n\n            // We could compute the result using syev()\n            //lapack::syev('V', 'L', V,  d);\n\n            // Instead, we use syevr because its faster and maybe more stable.\n            matrix_type tempA(A);\n            matrix<lapack::integer,0,0,mem_manager_type,layout_type> isupz;\n\n            lapack::integer temp;\n            lapack::syevr('V','A','L',tempA,0,0,0,0,-1,temp,d,V,isupz);\n            return;\n        }\n#endif\n        // Tridiagonalize.\n        tred2();\n\n        // Diagonalize.\n        tql2();\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::matrix_type& eigenvalue_decomposition<matrix_exp_type>::\n    get_pseudo_v (\n    ) const\n    {\n        return V;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    long eigenvalue_decomposition<matrix_exp_type>::\n    dim (\n    ) const\n    {\n        return V.nr();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::complex_column_vector_type eigenvalue_decomposition<matrix_exp_type>::\n    get_eigenvalues (\n    ) const\n    {\n        return complex_matrix(get_real_eigenvalues(), get_imag_eigenvalues());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::column_vector_type& eigenvalue_decomposition<matrix_exp_type>::\n    get_real_eigenvalues (\n    ) const\n    {\n        return d;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::column_vector_type& eigenvalue_decomposition<matrix_exp_type>::\n    get_imag_eigenvalues (\n    ) const\n    {\n        return e;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::complex_matrix_type eigenvalue_decomposition<matrix_exp_type>::\n    get_d (\n    ) const \n    {\n        return diagm(complex_matrix(get_real_eigenvalues(), get_imag_eigenvalues()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::complex_matrix_type eigenvalue_decomposition<matrix_exp_type>::\n    get_v (\n    ) const \n    {\n        complex_matrix_type CV(n,n);\n\n        for (long i = 0; i < n; i++) \n        {\n            if (e(i) > 0) \n            {\n                set_colm(CV,i) = complex_matrix(colm(V,i), colm(V,i+1));\n            } \n            else if (e(i) < 0) \n            {\n                set_colm(CV,i) = complex_matrix(colm(V,i), colm(V,i-1));\n            }\n            else\n            {\n                set_colm(CV,i) = complex_matrix(colm(V,i), uniform_matrix<type>(n,1,0));\n            }\n        }\n\n        return CV;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename eigenvalue_decomposition<matrix_exp_type>::matrix_type eigenvalue_decomposition<matrix_exp_type>::\n    get_pseudo_d (\n    ) const \n    {\n        matrix_type D(n,n);\n\n        for (long i = 0; i < n; i++) \n        {\n            for (long j = 0; j < n; j++) \n            {\n                D(i,j) = 0.0;\n            }\n            D(i,i) = d(i);\n            if (e(i) > 0) \n            {\n                D(i,i+1) = e(i);\n            } \n            else if (e(i) < 0) \n            {\n                D(i,i-1) = e(i);\n            }\n        }\n\n        return D;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                        Private member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n// Symmetric Householder reduction to tridiagonal form.\n    template <typename matrix_exp_type>\n    void eigenvalue_decomposition<matrix_exp_type>::\n    tred2() \n    {\n        using std::abs;\n        using std::sqrt;\n\n        //  This is derived from the Algol procedures tred2 by\n        //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for\n        //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding\n        //  Fortran subroutine in EISPACK.\n\n        for (long j = 0; j < n; j++) \n        {\n            d(j) = V(n-1,j);\n        }\n\n        // Householder reduction to tridiagonal form.\n\n        for (long i = n-1; i > 0; i--) \n        {\n\n            // Scale to avoid under/overflow.\n\n            type scale = 0.0;\n            type h = 0.0;\n            for (long k = 0; k < i; k++) \n            {\n                scale = scale + abs(d(k));\n            }\n            if (scale == 0.0) \n            {\n                e(i) = d(i-1);\n                for (long j = 0; j < i; j++) \n                {\n                    d(j) = V(i-1,j);\n                    V(i,j) = 0.0;\n                    V(j,i) = 0.0;\n                }\n            }\n            else \n            {\n\n                // Generate Householder vector.\n\n                for (long k = 0; k < i; k++) \n                {\n                    d(k) /= scale;\n                    h += d(k) * d(k);\n                }\n                type f = d(i-1);\n                type g = sqrt(h);\n                if (f > 0) \n                {\n                    g = -g;\n                }\n                e(i) = scale * g;\n                h = h - f * g;\n                d(i-1) = f - g;\n                for (long j = 0; j < i; j++) \n                {\n                    e(j) = 0.0;\n                }\n\n                // Apply similarity transformation to remaining columns.\n\n                for (long j = 0; j < i; j++) \n                {\n                    f = d(j);\n                    V(j,i) = f;\n                    g = e(j) + V(j,j) * f;\n                    for (long k = j+1; k <= i-1; k++) \n                    {\n                        g += V(k,j) * d(k);\n                        e(k) += V(k,j) * f;\n                    }\n                    e(j) = g;\n                }\n                f = 0.0;\n                for (long j = 0; j < i; j++) \n                {\n                    e(j) /= h;\n                    f += e(j) * d(j);\n                }\n                type hh = f / (h + h);\n                for (long j = 0; j < i; j++) \n                {\n                    e(j) -= hh * d(j);\n                }\n                for (long j = 0; j < i; j++) \n                {\n                    f = d(j);\n                    g = e(j);\n                    for (long k = j; k <= i-1; k++) \n                    {\n                        V(k,j) -= (f * e(k) + g * d(k));\n                    }\n                    d(j) = V(i-1,j);\n                    V(i,j) = 0.0;\n                }\n            }\n            d(i) = h;\n        }\n\n        // Accumulate transformations.\n\n        for (long i = 0; i < n-1; i++) \n        {\n            V(n-1,i) = V(i,i);\n            V(i,i) = 1.0;\n            type h = d(i+1);\n            if (h != 0.0) \n            {\n                for (long k = 0; k <= i; k++) \n                {\n                    d(k) = V(k,i+1) / h;\n                }\n                for (long j = 0; j <= i; j++) \n                {\n                    type g = 0.0;\n                    for (long k = 0; k <= i; k++) \n                    {\n                        g += V(k,i+1) * V(k,j);\n                    }\n                    for (long k = 0; k <= i; k++) \n                    {\n                        V(k,j) -= g * d(k);\n                    }\n                }\n            }\n            for (long k = 0; k <= i; k++) \n            {\n                V(k,i+1) = 0.0;\n            }\n        }\n        for (long j = 0; j < n; j++) \n        {\n            d(j) = V(n-1,j);\n            V(n-1,j) = 0.0;\n        }\n        V(n-1,n-1) = 1.0;\n        e(0) = 0.0;\n    } \n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    void eigenvalue_decomposition<matrix_exp_type>::\n    tql2 () \n    {\n        using std::pow;\n        using std::min;\n        using std::max;\n        using std::abs;\n\n        //  This is derived from the Algol procedures tql2, by\n        //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for\n        //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding\n        //  Fortran subroutine in EISPACK.\n\n        for (long i = 1; i < n; i++) \n        {\n            e(i-1) = e(i);\n        }\n        e(n-1) = 0.0;\n\n        type f = 0.0;\n        type tst1 = 0.0;\n        const type eps = std::numeric_limits<type>::epsilon();\n        for (long l = 0; l < n; l++) \n        {\n\n            // Find small subdiagonal element\n\n            tst1 = max(tst1,abs(d(l)) + abs(e(l)));\n            long m = l;\n\n            // Original while-loop from Java code\n            while (m < n) \n            {\n                if (abs(e(m)) <= eps*tst1) \n                {\n                    break;\n                }\n                m++;\n            }\n            if (m == n)\n                --m;\n\n\n            // If m == l, d(l) is an eigenvalue,\n            // otherwise, iterate.\n\n            if (m > l) \n            {\n                long iter = 0;\n                do \n                {\n                    iter = iter + 1;  // (Could check iteration count here.)\n\n                    // Compute implicit shift\n\n                    type g = d(l);\n                    type p = (d(l+1) - g) / (2.0 * e(l));\n                    type r = hypot(p,(type)1.0);\n                    if (p < 0) \n                    {\n                        r = -r;\n                    }\n                    d(l) = e(l) / (p + r);\n                    d(l+1) = e(l) * (p + r);\n                    type dl1 = d(l+1);\n                    type h = g - d(l);\n                    for (long i = l+2; i < n; i++) \n                    {\n                        d(i) -= h;\n                    }\n                    f = f + h;\n\n                    // Implicit QL transformation.\n\n                    p = d(m);\n                    type c = 1.0;\n                    type c2 = c;\n                    type c3 = c;\n                    type el1 = e(l+1);\n                    type s = 0.0;\n                    type s2 = 0.0;\n                    for (long i = m-1; i >= l; i--) \n                    {\n                        c3 = c2;\n                        c2 = c;\n                        s2 = s;\n                        g = c * e(i);\n                        h = c * p;\n                        r = hypot(p,e(i));\n                        e(i+1) = s * r;\n                        s = e(i) / r;\n                        c = p / r;\n                        p = c * d(i) - s * g;\n                        d(i+1) = h + s * (c * g + s * d(i));\n\n                        // Accumulate transformation.\n\n                        for (long k = 0; k < n; k++) \n                        {\n                            h = V(k,i+1);\n                            V(k,i+1) = s * V(k,i) + c * h;\n                            V(k,i) = c * V(k,i) - s * h;\n                        }\n                    }\n                    p = -s * s2 * c3 * el1 * e(l) / dl1;\n                    e(l) = s * p;\n                    d(l) = c * p;\n\n                    // Check for convergence.\n\n                } while (abs(e(l)) > eps*tst1);\n            }\n            d(l) = d(l) + f;\n            e(l) = 0.0;\n        }\n\n        /*\n            The code to sort the eigenvalues and eigenvectors \n            has been removed from here since, in the non-symmetric case,\n            we can't sort the eigenvalues in a meaningful way.  If we left this\n            code in here then the user might supply what they thought was a symmetric\n            matrix but was actually slightly non-symmetric due to rounding error\n            and then they would end up in the non-symmetric eigenvalue solver\n            where the eigenvalues don't end up getting sorted.  So to avoid\n            any possible user confusion I'm just removing this.\n        */\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    void eigenvalue_decomposition<matrix_exp_type>::\n    orthes () \n    {\n        using std::abs;\n        using std::sqrt;\n\n        //  This is derived from the Algol procedures orthes and ortran,\n        //  by Martin and Wilkinson, Handbook for Auto. Comp.,\n        //  Vol.ii-Linear Algebra, and the corresponding\n        //  Fortran subroutines in EISPACK.\n\n        long low = 0;\n        long high = n-1;\n\n        for (long m = low+1; m <= high-1; m++) \n        {\n\n            // Scale column.\n\n            type scale = 0.0;\n            for (long i = m; i <= high; i++) \n            {\n                scale = scale + abs(H(i,m-1));\n            }\n            if (scale != 0.0) \n            {\n\n                // Compute Householder transformation.\n\n                type h = 0.0;\n                for (long i = high; i >= m; i--) \n                {\n                    ort(i) = H(i,m-1)/scale;\n                    h += ort(i) * ort(i);\n                }\n                type g = sqrt(h);\n                if (ort(m) > 0) \n                {\n                    g = -g;\n                }\n                h = h - ort(m) * g;\n                ort(m) = ort(m) - g;\n\n                // Apply Householder similarity transformation\n                // H = (I-u*u'/h)*H*(I-u*u')/h)\n\n                for (long j = m; j < n; j++) \n                {\n                    type f = 0.0;\n                    for (long i = high; i >= m; i--) \n                    {\n                        f += ort(i)*H(i,j);\n                    }\n                    f = f/h;\n                    for (long i = m; i <= high; i++) \n                    {\n                        H(i,j) -= f*ort(i);\n                    }\n                }\n\n                for (long i = 0; i <= high; i++) \n                {\n                    type f = 0.0;\n                    for (long j = high; j >= m; j--) \n                    {\n                        f += ort(j)*H(i,j);\n                    }\n                    f = f/h;\n                    for (long j = m; j <= high; j++) \n                    {\n                        H(i,j) -= f*ort(j);\n                    }\n                }\n                ort(m) = scale*ort(m);\n                H(m,m-1) = scale*g;\n            }\n        }\n\n        // Accumulate transformations (Algol's ortran).\n\n        for (long i = 0; i < n; i++) \n        {\n            for (long j = 0; j < n; j++) \n            {\n                V(i,j) = (i == j ? 1.0 : 0.0);\n            }\n        }\n\n        for (long m = high-1; m >= low+1; m--) \n        {\n            if (H(m,m-1) != 0.0) \n            {\n                for (long i = m+1; i <= high; i++) \n                {\n                    ort(i) = H(i,m-1);\n                }\n                for (long j = m; j <= high; j++) \n                {\n                    type g = 0.0;\n                    for (long i = m; i <= high; i++) \n                    {\n                        g += ort(i) * V(i,j);\n                    }\n                    // Double division avoids possible underflow\n                    g = (g / ort(m)) / H(m,m-1);\n                    for (long i = m; i <= high; i++) \n                    {\n                        V(i,j) += g * ort(i);\n                    }\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    void eigenvalue_decomposition<matrix_exp_type>::\n    cdiv_(type xr, type xi, type yr, type yi)  \n    {\n        using std::abs;\n        type r,d;\n        if (abs(yr) > abs(yi)) \n        {\n            r = yi/yr;\n            d = yr + r*yi;\n            cdivr = (xr + r*xi)/d;\n            cdivi = (xi - r*xr)/d;\n        } \n        else \n        {\n            r = yr/yi;\n            d = yi + r*yr;\n            cdivr = (r*xr + xi)/d;\n            cdivi = (r*xi - xr)/d;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    void eigenvalue_decomposition<matrix_exp_type>::\n    hqr2 ()\n    {\n        using std::pow;\n        using std::min;\n        using std::max;\n        using std::abs;\n        using std::sqrt;\n\n        //  This is derived from the Algol procedure hqr2,\n        //  by Martin and Wilkinson, Handbook for Auto. Comp.,\n        //  Vol.ii-Linear Algebra, and the corresponding\n        //  Fortran subroutine in EISPACK.\n\n        // Initialize\n\n        long nn = this->n;\n        long n = nn-1;\n        long low = 0;\n        long high = nn-1;\n        const type eps = std::numeric_limits<type>::epsilon();\n        type exshift = 0.0;\n        type p=0,q=0,r=0,s=0,z=0,t,w,x,y;\n\n        // Store roots isolated by balanc and compute matrix norm\n\n        type norm = 0.0;\n        for (long i = 0; i < nn; i++) \n        {\n            if ((i < low) || (i > high)) \n            {\n                d(i) = H(i,i);\n                e(i) = 0.0;\n            }\n            for (long j = max(i-1,0L); j < nn; j++) \n            {\n                norm = norm + abs(H(i,j));\n            }\n        }\n\n        // Outer loop over eigenvalue index\n\n        long iter = 0;\n        while (n >= low) \n        {\n\n            // Look for single small sub-diagonal element\n\n            long l = n;\n            while (l > low) \n            {\n                s = abs(H(l-1,l-1)) + abs(H(l,l));\n                if (s == 0.0) \n                {\n                    s = norm;\n                }\n                if (abs(H(l,l-1)) < eps * s) \n                {\n                    break;\n                }\n                l--;\n            }\n\n            // Check for convergence\n            // One root found\n\n            if (l == n) \n            {\n                H(n,n) = H(n,n) + exshift;\n                d(n) = H(n,n);\n                e(n) = 0.0;\n                n--;\n                iter = 0;\n\n                // Two roots found\n\n            } \n            else if (l == n-1) \n            {\n                w = H(n,n-1) * H(n-1,n);\n                p = (H(n-1,n-1) - H(n,n)) / 2.0;\n                q = p * p + w;\n                z = sqrt(abs(q));\n                H(n,n) = H(n,n) + exshift;\n                H(n-1,n-1) = H(n-1,n-1) + exshift;\n                x = H(n,n);\n\n                // type pair\n\n                if (q >= 0) \n                {\n                    if (p >= 0) \n                    {\n                        z = p + z;\n                    } \n                    else \n                    {\n                        z = p - z;\n                    }\n                    d(n-1) = x + z;\n                    d(n) = d(n-1);\n                    if (z != 0.0) \n                    {\n                        d(n) = x - w / z;\n                    }\n                    e(n-1) = 0.0;\n                    e(n) = 0.0;\n                    x = H(n,n-1);\n                    s = abs(x) + abs(z);\n                    p = x / s;\n                    q = z / s;\n                    r = sqrt(p * p+q * q);\n                    p = p / r;\n                    q = q / r;\n\n                    // Row modification\n\n                    for (long j = n-1; j < nn; j++) \n                    {\n                        z = H(n-1,j);\n                        H(n-1,j) = q * z + p * H(n,j);\n                        H(n,j) = q * H(n,j) - p * z;\n                    }\n\n                    // Column modification\n\n                    for (long i = 0; i <= n; i++) \n                    {\n                        z = H(i,n-1);\n                        H(i,n-1) = q * z + p * H(i,n);\n                        H(i,n) = q * H(i,n) - p * z;\n                    }\n\n                    // Accumulate transformations\n\n                    for (long i = low; i <= high; i++) \n                    {\n                        z = V(i,n-1);\n                        V(i,n-1) = q * z + p * V(i,n);\n                        V(i,n) = q * V(i,n) - p * z;\n                    }\n\n                    // Complex pair\n\n                } \n                else \n                {\n                    d(n-1) = x + p;\n                    d(n) = x + p;\n                    e(n-1) = z;\n                    e(n) = -z;\n                }\n                n = n - 2;\n                iter = 0;\n\n                // No convergence yet\n\n            } \n            else \n            {\n\n                // Form shift\n\n                x = H(n,n);\n                y = 0.0;\n                w = 0.0;\n                if (l < n) \n                {\n                    y = H(n-1,n-1);\n                    w = H(n,n-1) * H(n-1,n);\n                }\n\n                // Wilkinson's original ad hoc shift\n\n                if (iter == 10) \n                {\n                    exshift += x;\n                    for (long i = low; i <= n; i++) \n                    {\n                        H(i,i) -= x;\n                    }\n                    s = abs(H(n,n-1)) + abs(H(n-1,n-2));\n                    x = y = 0.75 * s;\n                    w = -0.4375 * s * s;\n                }\n\n                // MATLAB's new ad hoc shift\n\n                if (iter == 30) \n                {\n                    s = (y - x) / 2.0;\n                    s = s * s + w;\n                    if (s > 0) \n                    {\n                        s = sqrt(s);\n                        if (y < x) \n                        {\n                            s = -s;\n                        }\n                        s = x - w / ((y - x) / 2.0 + s);\n                        for (long i = low; i <= n; i++) \n                        {\n                            H(i,i) -= s;\n                        }\n                        exshift += s;\n                        x = y = w = 0.964;\n                    }\n                }\n\n                iter = iter + 1;   // (Could check iteration count here.)\n\n                // Look for two consecutive small sub-diagonal elements\n\n                long m = n-2;\n                while (m >= l) \n                {\n                    z = H(m,m);\n                    r = x - z;\n                    s = y - z;\n                    p = (r * s - w) / H(m+1,m) + H(m,m+1);\n                    q = H(m+1,m+1) - z - r - s;\n                    r = H(m+2,m+1);\n                    s = abs(p) + abs(q) + abs(r);\n                    p = p / s;\n                    q = q / s;\n                    r = r / s;\n                    if (m == l) \n                    {\n                        break;\n                    }\n                    if (abs(H(m,m-1)) * (abs(q) + abs(r)) <\n                        eps * (abs(p) * (abs(H(m-1,m-1)) + abs(z) +\n                                         abs(H(m+1,m+1))))) \n                    {\n                        break;\n                    }\n                    m--;\n                }\n\n                for (long i = m+2; i <= n; i++) \n                {\n                    H(i,i-2) = 0.0;\n                    if (i > m+2) \n                    {\n                        H(i,i-3) = 0.0;\n                    }\n                }\n\n                // Double QR step involving rows l:n and columns m:n\n\n                for (long k = m; k <= n-1; k++) \n                {\n                    long notlast = (k != n-1);\n                    if (k != m) \n                    {\n                        p = H(k,k-1);\n                        q = H(k+1,k-1);\n                        r = (notlast ? H(k+2,k-1) : 0.0);\n                        x = abs(p) + abs(q) + abs(r);\n                        if (x != 0.0) \n                        {\n                            p = p / x;\n                            q = q / x;\n                            r = r / x;\n                        }\n                    }\n                    if (x == 0.0) \n                    {\n                        break;\n                    }\n                    s = sqrt(p * p + q * q + r * r);\n                    if (p < 0) \n                    {\n                        s = -s;\n                    }\n                    if (s != 0) \n                    {\n                        if (k != m) \n                        {\n                            H(k,k-1) = -s * x;\n                        } \n                        else if (l != m) \n                        {\n                            H(k,k-1) = -H(k,k-1);\n                        }\n                        p = p + s;\n                        x = p / s;\n                        y = q / s;\n                        z = r / s;\n                        q = q / p;\n                        r = r / p;\n\n                        // Row modification\n\n                        for (long j = k; j < nn; j++) \n                        {\n                            p = H(k,j) + q * H(k+1,j);\n                            if (notlast) \n                            {\n                                p = p + r * H(k+2,j);\n                                H(k+2,j) = H(k+2,j) - p * z;\n                            }\n                            H(k,j) = H(k,j) - p * x;\n                            H(k+1,j) = H(k+1,j) - p * y;\n                        }\n\n                        // Column modification\n\n                        for (long i = 0; i <= min(n,k+3); i++) \n                        {\n                            p = x * H(i,k) + y * H(i,k+1);\n                            if (notlast) \n                            {\n                                p = p + z * H(i,k+2);\n                                H(i,k+2) = H(i,k+2) - p * r;\n                            }\n                            H(i,k) = H(i,k) - p;\n                            H(i,k+1) = H(i,k+1) - p * q;\n                        }\n\n                        // Accumulate transformations\n\n                        for (long i = low; i <= high; i++) \n                        {\n                            p = x * V(i,k) + y * V(i,k+1);\n                            if (notlast) \n                            {\n                                p = p + z * V(i,k+2);\n                                V(i,k+2) = V(i,k+2) - p * r;\n                            }\n                            V(i,k) = V(i,k) - p;\n                            V(i,k+1) = V(i,k+1) - p * q;\n                        }\n                    }  // (s != 0)\n                }  // k loop\n            }  // check convergence\n        }  // while (n >= low)\n\n        // Backsubstitute to find vectors of upper triangular form\n\n        if (norm == 0.0) \n        {\n            return;\n        }\n\n        for (n = nn-1; n >= 0; n--) \n        {\n            p = d(n);\n            q = e(n);\n\n            // Real vector\n\n            if (q == 0) \n            {\n                long l = n;\n                H(n,n) = 1.0;\n                for (long i = n-1; i >= 0; i--) \n                {\n                    w = H(i,i) - p;\n                    r = 0.0;\n                    for (long j = l; j <= n; j++) \n                    {\n                        r = r + H(i,j) * H(j,n);\n                    }\n                    if (e(i) < 0.0) \n                    {\n                        z = w;\n                        s = r;\n                    } \n                    else \n                    {\n                        l = i;\n                        if (e(i) == 0.0) \n                        {\n                            if (w != 0.0) \n                            {\n                                H(i,n) = -r / w;\n                            } \n                            else \n                            {\n                                H(i,n) = -r / (eps * norm);\n                            }\n\n                            // Solve real equations\n\n                        } \n                        else \n                        {\n                            x = H(i,i+1);\n                            y = H(i+1,i);\n                            q = (d(i) - p) * (d(i) - p) + e(i) * e(i);\n                            t = (x * s - z * r) / q;\n                            H(i,n) = t;\n                            if (abs(x) > abs(z)) \n                            {\n                                H(i+1,n) = (-r - w * t) / x;\n                            } \n                            else \n                            {\n                                H(i+1,n) = (-s - y * t) / z;\n                            }\n                        }\n\n                        // Overflow control\n\n                        t = abs(H(i,n));\n                        if ((eps * t) * t > 1) \n                        {\n                            for (long j = i; j <= n; j++) \n                            {\n                                H(j,n) = H(j,n) / t;\n                            }\n                        }\n                    }\n                }\n\n                // Complex vector\n\n            } \n            else if (q < 0) \n            {\n                long l = n-1;\n\n                // Last vector component imaginary so matrix is triangular\n\n                if (abs(H(n,n-1)) > abs(H(n-1,n))) \n                {\n                    H(n-1,n-1) = q / H(n,n-1);\n                    H(n-1,n) = -(H(n,n) - p) / H(n,n-1);\n                } \n                else \n                {\n                    cdiv_(0.0,-H(n-1,n),H(n-1,n-1)-p,q);\n                    H(n-1,n-1) = cdivr;\n                    H(n-1,n) = cdivi;\n                }\n                H(n,n-1) = 0.0;\n                H(n,n) = 1.0;\n                for (long i = n-2; i >= 0; i--) \n                {\n                    type ra,sa,vr,vi;\n                    ra = 0.0;\n                    sa = 0.0;\n                    for (long j = l; j <= n; j++) \n                    {\n                        ra = ra + H(i,j) * H(j,n-1);\n                        sa = sa + H(i,j) * H(j,n);\n                    }\n                    w = H(i,i) - p;\n\n                    if (e(i) < 0.0) \n                    {\n                        z = w;\n                        r = ra;\n                        s = sa;\n                    } \n                    else \n                    {\n                        l = i;\n                        if (e(i) == 0) \n                        {\n                            cdiv_(-ra,-sa,w,q);\n                            H(i,n-1) = cdivr;\n                            H(i,n) = cdivi;\n                        } \n                        else \n                        {\n\n                            // Solve complex equations\n\n                            x = H(i,i+1);\n                            y = H(i+1,i);\n                            vr = (d(i) - p) * (d(i) - p) + e(i) * e(i) - q * q;\n                            vi = (d(i) - p) * 2.0 * q;\n                            if ((vr == 0.0) && (vi == 0.0)) \n                            {\n                                vr = eps * norm * (abs(w) + abs(q) +\n                                                   abs(x) + abs(y) + abs(z));\n                            }\n                            cdiv_(x*r-z*ra+q*sa,x*s-z*sa-q*ra,vr,vi);\n                            H(i,n-1) = cdivr;\n                            H(i,n) = cdivi;\n                            if (abs(x) > (abs(z) + abs(q))) \n                            {\n                                H(i+1,n-1) = (-ra - w * H(i,n-1) + q * H(i,n)) / x;\n                                H(i+1,n) = (-sa - w * H(i,n) - q * H(i,n-1)) / x;\n                            }\n                            else \n                            {\n                                cdiv_(-r-y*H(i,n-1),-s-y*H(i,n),z,q);\n                                H(i+1,n-1) = cdivr;\n                                H(i+1,n) = cdivi;\n                            }\n                        }\n\n                        // Overflow control\n\n                        t = max(abs(H(i,n-1)),abs(H(i,n)));\n                        if ((eps * t) * t > 1) \n                        {\n                            for (long j = i; j <= n; j++) \n                            {\n                                H(j,n-1) = H(j,n-1) / t;\n                                H(j,n) = H(j,n) / t;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        // Vectors of isolated roots\n\n        for (long i = 0; i < nn; i++) \n        {\n            if (i < low || i > high) \n            {\n                for (long j = i; j < nn; j++) \n                {\n                    V(i,j) = H(i,j);\n                }\n            }\n        }\n\n        // Back transformation to get eigenvectors of original matrix\n\n        for (long j = nn-1; j >= low; j--) \n        {\n            for (long i = low; i <= high; i++) \n            {\n                z = 0.0;\n                for (long k = low; k <= min(j,high); k++) \n                {\n                    z = z + V(i,k) * H(k,j);\n                }\n                V(i,j) = z;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n} \n\n#endif // DLIB_MATRIX_EIGENVALUE_DECOMPOSITION_H \n\n\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_exp.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_EXP_h_\n#define DLIB_MATRIx_EXP_h_\n\n#include \"../algs.h\"\n#include \"../is_kind.h\"\n#include \"matrix_fwd.h\"\n#include \"matrix_exp_abstract.h\"\n#include <iterator>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    // We want to return the compile time constant if our NR and NC dimensions\n    // aren't zero but if they are then we want to call ref_.nx() and return\n    // the correct values. \n    template < typename exp_type, long NR >\n    struct get_nr_helper\n    {\n        static inline long get(const exp_type&) { return NR; }\n    };\n\n    template < typename exp_type >\n    struct get_nr_helper<exp_type,0>\n    {\n        static inline long get(const exp_type& m) { return m.nr(); }\n    };\n\n    template < typename exp_type, long NC >\n    struct get_nc_helper\n    {\n        static inline long get(const exp_type&) { return NC; }\n    };\n\n    template < typename exp_type >\n    struct get_nc_helper<exp_type,0>\n    {\n        static inline long get(const exp_type& m) { return m.nc(); }\n    };\n\n    template <typename EXP>\n    struct matrix_traits\n    {\n        typedef typename EXP::type type;\n        typedef typename EXP::const_ret_type const_ret_type;\n        typedef typename EXP::mem_manager_type mem_manager_type;\n        typedef typename EXP::layout_type layout_type;\n        const static long NR = EXP::NR;\n        const static long NC = EXP::NC;\n        const static long cost = EXP::cost;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP> class matrix_exp;\n    template <typename EXP>\n    class matrix_exp_iterator\n    {\n        friend class matrix_exp<EXP>;\n        matrix_exp_iterator(const EXP& m_, long r_, long c_)\n        {\n            r = r_;\n            c = c_;\n            nc = m_.nc();\n            m = &m_;\n        }\n\n    public:\n\n        matrix_exp_iterator() : r(0), c(0), nc(0), m(0) {}\n\n        using type = typename matrix_traits<EXP>::type;\n        using const_ret_type = typename matrix_traits<EXP>::const_ret_type;\n        using iterator_category = std::forward_iterator_tag;\n        using value_type = type;\n        using difference_type = std::ptrdiff_t;\n        using pointer = value_type*;\n        using reference = value_type&;\n\n\n        bool operator == ( const matrix_exp_iterator& itr) const\n        { return r == itr.r && c == itr.c; }\n\n        bool operator != ( const matrix_exp_iterator& itr) const\n        { return !(*this == itr); }\n\n        matrix_exp_iterator& operator++()\n        {\n            ++c;\n            if (c==nc)\n            {\n                c = 0;\n                ++r;\n            }\n            return *this;\n        }\n\n        matrix_exp_iterator operator++(int)\n        {\n            matrix_exp_iterator temp(*this);\n            ++(*this);\n            return temp;\n        }\n\n        const_ret_type operator* () const { return (*m)(r,c); }\n\n    private:\n        long r, c;\n        long nc;\n        const EXP* m;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    class matrix_exp \n    {\n        /*!\n            REQUIREMENTS ON EXP\n                EXP should be something convertible to a matrix_exp.  That is,\n                it should inherit from matrix_exp\n        !*/\n\n    public:\n        typedef typename matrix_traits<EXP>::type type;\n        typedef type value_type;\n        typedef typename matrix_traits<EXP>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<EXP>::mem_manager_type mem_manager_type;\n        typedef typename matrix_traits<EXP>::layout_type layout_type;\n        const static long NR = matrix_traits<EXP>::NR;\n        const static long NC = matrix_traits<EXP>::NC;\n        const static long cost = matrix_traits<EXP>::cost;\n\n        typedef matrix<type,NR,NC,mem_manager_type,layout_type> matrix_type;\n        typedef EXP exp_type;\n        typedef matrix_exp_iterator<EXP> iterator;\n        typedef matrix_exp_iterator<EXP> const_iterator;\n\n        inline const_ret_type operator() (\n            long r,\n            long c\n        ) const \n        { \n            DLIB_ASSERT(r < nr() && c < nc() && r >= 0 && c >= 0, \n                \"\\tconst type matrix_exp::operator(r,c)\"\n                << \"\\n\\tYou must give a valid row and column\"\n                << \"\\n\\tr:    \" << r \n                << \"\\n\\tc:    \" << c\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc() \n                << \"\\n\\tthis: \" << this\n                );\n            return ref()(r,c); \n        }\n\n        const_ret_type operator() (\n            long i\n        ) const \n        {\n            COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);\n            DLIB_ASSERT(nc() == 1 || nr() == 1, \n                \"\\tconst type matrix_exp::operator(i)\"\n                << \"\\n\\tYou can only use this operator on column or row vectors\"\n                << \"\\n\\ti:    \" << i\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc()\n                << \"\\n\\tthis: \" << this\n                );\n            DLIB_ASSERT( ((nc() == 1 && i < nr()) || (nr() == 1 && i < nc())) && i >= 0, \n                \"\\tconst type matrix_exp::operator(i)\"\n                << \"\\n\\tYou must give a valid row/column number\"\n                << \"\\n\\ti:    \" << i\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc()\n                << \"\\n\\tthis: \" << this\n                );\n            if (nc() == 1)\n                return ref()(i,0);\n            else\n                return ref()(0,i);\n        }\n\n        long size (\n        ) const { return nr()*nc(); }\n\n        long nr (\n        ) const { return get_nr_helper<exp_type,NR>::get(ref()); }\n\n        long nc (\n        ) const { return get_nc_helper<exp_type,NC>::get(ref()); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return ref().aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return ref().destructively_aliases(item); }\n\n        inline const exp_type& ref (\n        ) const { return *static_cast<const exp_type*>(this); }\n\n        inline operator const type (\n        ) const \n        {\n            COMPILE_TIME_ASSERT(NC == 1 || NC == 0);\n            COMPILE_TIME_ASSERT(NR == 1 || NR == 0);\n            DLIB_ASSERT(nr() == 1 && nc() == 1, \n                \"\\tmatrix_exp::operator const type() const\"\n                << \"\\n\\tYou can only use this operator on a 1x1 matrix\"\n                << \"\\n\\tnr(): \" << nr()\n                << \"\\n\\tnc(): \" << nc()\n                << \"\\n\\tthis: \" << this\n                );\n\n            // Put the expression contained in this matrix_exp into\n            // a temporary 1x1 matrix so that the expression will encounter\n            // all the overloads of matrix_assign() and have the chance to\n            // go through any applicable optimizations.\n            matrix<type,1,1,mem_manager_type,layout_type> temp(ref());\n            return temp(0);\n        }\n\n        const_iterator begin() const { return matrix_exp_iterator<EXP>(ref(),0,0); }\n        const_iterator end()   const { return matrix_exp_iterator<EXP>(ref(),nr(),0); }\n\n    protected:\n        matrix_exp() {}\n        matrix_exp(const matrix_exp& ) {}\n\n    private:\n\n        matrix_exp& operator= (const matrix_exp&);\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    // something is a matrix if it is convertible to a matrix_exp object\n    template <typename T>\n    struct is_matrix<T, typename enable_if<is_convertible<T, const matrix_exp<typename T::exp_type>& > >::type > \n    { static const bool value = true; }; \n    /*\n        is_matrix<T>::value == 1 if T is a matrix type else 0\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    class matrix_diag_exp : public matrix_exp<EXP> \n    {\n        /*!\n            This is a matrix expression type used to represent diagonal matrices.\n            That is, square matrices with all off diagonal elements equal to 0.\n        !*/\n\n    protected:\n        matrix_diag_exp() {}\n        matrix_diag_exp(const matrix_diag_exp& item ):matrix_exp<EXP>(item) {}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_EXP_h_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_exp_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_EXP_ABSTRACT_\n#ifdef DLIB_MATRIx_EXP_ABSTRACT_\n\n#include \"matrix_fwd.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    class matrix_exp\n    {\n        /*!\n            REQUIREMENTS ON EXP\n                - must be an object that inherits publicly from matrix_exp (this class).\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an expression that evaluates to a matrix \n                of nr() rows and nc() columns.  \n                \n                The reason for having an object that represents an expression is that it \n                allows us to use the \"expression templates\" technique to eliminate the \n                temporary matrix objects that would normally be returned from expressions \n                such as M = A+B+C+D;  Normally each invocation of the + operator would\n                construct and return a temporary matrix object but using this technique we \n                can avoid creating all of these temporary objects and receive a large \n                speed boost.\n\n                Note that every time you invoke operator() on this object it recomputes \n                its result which may not be what you want to do.  For example, if you \n                are going to be accessing the same element over and over it might \n                be faster to assign the matrix_exp to a temporary matrix and then \n                use that temporary.\n\n\n                const_ret_type typedef (defined below)\n                    The purpose of the const_ret_type typedef is to allow matrix expressions\n                    to return their elements by reference when appropriate.  So const_ret_type \n                    should be one of the following types:\n                        - const type\n                        - const type& \n        !*/\n\n    public:\n        typedef typename EXP::type type;\n        typedef type value_type; // Redefined for compatibility with the STL\n        typedef typename EXP::const_ret_type const_ret_type;\n        typedef typename EXP::mem_manager_type mem_manager_type;\n        typedef typename EXP::layout_type layout_type;\n        const static long cost = EXP::cost;\n        const static long NR = EXP::NR;\n        const static long NC = EXP::NC;\n        typedef matrix<type,NR,NC, mem_manager_type,layout_type> matrix_type;\n        typedef EXP exp_type;\n        typedef matrix_exp_iterator<EXP> iterator;\n        typedef matrix_exp_iterator<EXP> const_iterator;\n\n        const_ret_type operator() (\n            long r,\n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= r < nr()\n                - 0 <= c < nc()\n            ensures\n                - returns ref()(r,c)\n                  (i.e. returns the value at the given row and column that would be in\n                  the matrix represented by this matrix expression)\n        !*/\n\n        const_ret_type operator() (\n            long i\n        ) const;\n        /*!\n            requires\n                - nc() == 1 || nr() == 1 (i.e. this must be a column or row vector)\n                - if (nc() == 1) then\n                    - 0 <= i < nr()\n                - else\n                    - 0 <= i < nc()\n            ensures\n                - if (nc() == 1) then\n                    - returns (*this)(i,0)\n                - else\n                    - returns (*this)(0,i)\n        !*/\n\n        operator const type (\n        ) const;\n        /*!\n            requires\n                - nr() == 1\n                - nc() == 1\n            ensures\n                - returns (*this)(0,0)\n        !*/\n\n        long nr (\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in this matrix expression. \n        !*/\n\n        long nc (\n        ) const; \n        /*!\n            ensures\n                - returns the number of columns in this matrix expression.\n        !*/\n\n        long size (\n        ) const;\n        /*!\n            ensures\n                - returns nr()*nc()\n        !*/\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const;\n        /*!\n            ensures\n                - if (A change to the state of item could cause a change to the state of *this\n                      matrix_exp object.  ) then\n                    - returns true\n                    - This happens when this matrix_exp contains item in some way. \n                - else\n                    - returns false\n        !*/\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const; \n        /*!\n            ensures\n                - if (aliases(item)) then \n                    - if (nr() != item.nr() || nc() != item.nc()\n                        - returns true\n                          (i.e. if this expression has different dimensions than item then\n                          we have destructive aliasing)\n\n                    - returns true if the following assignment would evaluate incorrectly:\n                      for (long r = 0; r < nr(); ++r)\n                        for (long c = 0; c < nc(); ++c)\n                          item(r,c) = (*this)(r,c)\n                    - That is, if this matrix expression aliases item in such a way that a modification\n                      to element item(r,c) causes a change in the value of something other than\n                      (*this)(r,c) then this function returns true.  \n\n                    - returns false if none of the above conditions say we should return true\n                - else\n                    - returns false\n        !*/\n\n        inline const exp_type& ref (\n        ) const; \n        /*!\n            ensures\n                - returns a reference to the expression contained in *this.\n                  (i.e. returns *static_cast<const exp_type*>(this) )\n        !*/\n\n        const_iterator begin(\n        ) const;\n        /*!\n            ensures\n                - returns a forward access iterator pointing to the first element in this\n                  matrix expression.\n                - Since matrix_exp objects represent immutable views of a matrix, the\n                  returned iterator does not allow the user to modify the matrix\n                  expression's elements.\n                - The iterator will iterate over the elements of the matrix in row major\n                  order.\n        !*/\n\n        const_iterator end(\n        ) const;\n        /*!\n            ensures\n                - returns a forward access iterator pointing to one past the end of the\n                  last element in this matrix expression.\n        !*/\n\n    protected:\n\n        // Only derived classes of matrix_exp may call the matrix_exp constructors.\n        matrix_exp(const matrix_exp&); \n        matrix_exp();\n\n    private:\n        // no one may ever use the assignment operator on a matrix_exp\n        matrix_exp& operator= (const matrix_exp&);\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_EXP_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_expressions.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_EXPRESSIONS_H_\n#define DLIB_MATRIx_EXPRESSIONS_H_\n\n#include \"matrix_fwd.h\"\n\n#ifdef _MSC_VER\n// This #pragma directive is also located in the algs.h file but for whatever\n// reason visual studio 9 just ignores it when it is only there. \n\n// this is to disable the \"'this' : used in base member initializer list\"\n// warning you get from some of the GUI objects since all the objects\n// require that their parent class be passed into their constructor. \n// In this case though it is totally safe so it is ok to disable this warning.\n#pragma warning(disable : 4355)\n#endif\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//            Helper templates for making operators used by expression objects\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class matrix_range_exp;\n\n    template <typename T>\n    struct matrix_traits<matrix_range_exp<T> >\n    {\n        typedef T type;\n        typedef const T const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        const static long NR = 1;\n        const static long NC = 0;\n        const static long cost = 1;\n    };\n\n    template <typename T>\n    class matrix_range_exp : public matrix_exp<matrix_range_exp<T> >\n    {\n    public:\n        typedef typename matrix_traits<matrix_range_exp>::type type;\n        typedef typename matrix_traits<matrix_range_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_range_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_range_exp>::NR;\n        const static long NC = matrix_traits<matrix_range_exp>::NC;\n        const static long cost = matrix_traits<matrix_range_exp>::cost;\n        typedef typename matrix_traits<matrix_range_exp>::layout_type layout_type;\n\n\n        matrix_range_exp (\n            T start_,\n            T end_\n        ) \n        {\n            start = start_;\n            if (start_ <= end_)\n                inc = 1;\n            else \n                inc = -1;\n            nc_ = std::abs(end_ - start_) + 1;\n        }\n        matrix_range_exp (\n            T start_,\n            T inc_,\n            T end_\n        ) \n        {\n            start = start_;\n            nc_ = std::abs(end_ - start_)/inc_ + 1;\n            if (start_ <= end_)\n                inc = inc_;\n            else\n                inc = -inc_;\n        }\n\n        matrix_range_exp (\n            T start_,\n            T end_,\n            long num,\n            bool\n        ) \n        {\n            start = start_;\n            nc_ = num;\n            if (num > 1)\n            {\n                inc = (end_-start_)/(num-1);\n            }\n            else \n            {\n                inc = 0;\n                start = end_;\n            }\n\n        }\n\n        const_ret_type operator() (\n            long, \n            long c\n        ) const { return start + c*inc;  }\n\n        const_ret_type operator() (\n            long c\n        ) const { return start + c*inc;  }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        long nr (\n        ) const { return NR; }\n\n        long nc (\n        ) const { return nc_; }\n\n        long nc_;\n        T start;\n        T inc;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class matrix_log_range_exp;\n\n    template <typename T>\n    struct matrix_traits<matrix_log_range_exp<T> >\n    {\n        typedef T type;\n        typedef const T const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        const static long NR = 1;\n        const static long NC = 0;\n        const static long cost = 1;\n    };\n\n    template <typename T>\n    class matrix_log_range_exp : public matrix_exp<matrix_log_range_exp<T> >\n    {\n    public:\n        typedef typename matrix_traits<matrix_log_range_exp>::type type;\n        typedef typename matrix_traits<matrix_log_range_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_log_range_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_log_range_exp>::NR;\n        const static long NC = matrix_traits<matrix_log_range_exp>::NC;\n        const static long cost = matrix_traits<matrix_log_range_exp>::cost;\n        typedef typename matrix_traits<matrix_log_range_exp>::layout_type layout_type;\n\n\n        matrix_log_range_exp (\n            T start_,\n            T end_,\n            long num\n        ) \n        {\n            start = start_;\n            nc_ = num;\n            if (num > 1)\n            {\n                inc = (end_-start_)/(num-1);\n            }\n            else \n            {\n                inc = 0;\n                start = end_;\n            }\n\n        }\n\n        const_ret_type operator() (\n            long,\n            long c\n        ) const { return std::pow((T)10,start + c*inc);  }\n\n        const_ret_type operator() (\n            long c\n        ) const { return std::pow((T)10,start + c*inc);  }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        long nr (\n        ) const { return NR; }\n\n        long nc (\n        ) const { return nc_; }\n\n        long nc_;\n        T start;\n        T inc;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <long start, long inc_, long end>\n    class matrix_range_static_exp;\n\n    template <long start, long inc_, long end>\n    struct matrix_traits<matrix_range_static_exp<start,inc_,end> >\n    {\n        typedef long type;\n        typedef const long const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        const static long NR = 1;\n        const static long NC = tabs<(end - start)>::value/inc_ + 1;\n        const static long cost = 1;\n        typedef row_major_layout layout_type;\n    };\n\n    template <long start, long inc_, long end_>\n    class matrix_range_static_exp : public matrix_exp<matrix_range_static_exp<start,inc_,end_> > \n    {\n    public:\n        typedef typename matrix_traits<matrix_range_static_exp>::type type;\n        typedef typename matrix_traits<matrix_range_static_exp>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_range_static_exp>::mem_manager_type mem_manager_type;\n        const static long NR = matrix_traits<matrix_range_static_exp>::NR;\n        const static long NC = matrix_traits<matrix_range_static_exp>::NC;\n        const static long cost = matrix_traits<matrix_range_static_exp>::cost;\n        typedef typename matrix_traits<matrix_range_static_exp>::layout_type layout_type;\n\n        const static long inc = (start <= end_)?inc_:-inc_;\n\n\n        matrix_range_static_exp (\n        ) {}\n\n        const_ret_type operator() (\n            long , \n            long c\n        ) const { return start + c*inc;  }\n\n        const_ret_type operator() (\n            long c\n        ) const { return start + c*inc;  }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& \n        ) const { return false; }\n\n        long nr (\n        ) const { return NR; }\n\n        long nc (\n        ) const { return NC; }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_EXPRESSIONS_H_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_fft.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FFt_Hh_\n#define DLIB_FFt_Hh_\n\n#include \"matrix_fft_abstract.h\"\n#include \"matrix_utilities.h\"\n#include \"../hash.h\"\n#include \"../algs.h\"\n#include \"../math.h\"\n#include \"../fft/fft.h\"\n#include \"../fft/fft_stl.h\"\n\nnamespace dlib\n{     \n  \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, typename Alloc >\n    matrix<std::complex<T>,0,1> fft (const std::vector<std::complex<T>, Alloc>& in)\n    {\n        //complex FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        matrix<std::complex<T>,0,1> out(in.size());\n        if (in.size() != 0)\n            fft({(long)in.size()}, &in[0], &out(0,0), false);\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, long NR, long NC, typename MM, typename L >\n    matrix<std::complex<T>,NR,NC,MM,L> fft (const matrix<std::complex<T>,NR,NC,MM,L>& in)\n    {\n        //complex FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        matrix<std::complex<T>,NR,NC,MM,L> out(in.nr(), in.nc());\n        if (in.size() != 0)\n            fft({in.nr(),in.nc()}, &in(0,0), &out(0,0), false);\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    typename EXP::matrix_type fft (const matrix_exp<EXP>& data)\n    {\n        //complex FFT for expression template\n        static_assert(is_complex<typename EXP::type>::value, \"input should be complex\");\n        typename EXP::matrix_type in(data);\n        return fft(in);\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, typename Alloc >\n    matrix<std::complex<T>,0,1> ifft (const std::vector<std::complex<T>, Alloc>& in)\n    {\n        //complex FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        matrix<std::complex<T>,0,1> out(in.size());\n        if (in.size() != 0)\n        {\n            fft({(long)in.size()}, &in[0], &out(0,0), true);\n            out /= out.size();\n        }\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, long NR, long NC, typename MM, typename L >\n    matrix<std::complex<T>,NR,NC,MM,L> ifft (const matrix<std::complex<T>,NR,NC,MM,L>& in)\n    {\n        //inverse complex FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        matrix<std::complex<T>,NR,NC,MM,L> out(in.nr(), in.nc());\n        if (in.size() != 0)\n        {\n            fft({in.nr(),in.nc()}, &in(0,0), &out(0,0), true);\n            out /= out.size();\n        }\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    typename EXP::matrix_type ifft (const matrix_exp<EXP>& data)\n    {\n        //inverse complex FFT for expression template\n        static_assert(is_complex<typename EXP::type>::value, \"input should be complex\");\n        typename EXP::matrix_type in(data);\n        return ifft(in);\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    template<typename T, long NR, long NC, typename MM, typename L>\n    matrix<std::complex<T>,NR,fftr_nc_size(NC),MM,L> fftr (const matrix<T,NR,NC,MM,L>& in)\n    {\n        //real FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        DLIB_ASSERT(in.nc() % 2 == 0, \"last dimension \" << in.nc() << \" needs to be even otherwise ifftr(fftr(data)) won't have matching dimensions\");\n        matrix<std::complex<T>,NR,fftr_nc_size(NC),MM,L> out(in.nr(), fftr_nc_size(in.nc()));\n        if (in.size() != 0)\n            fftr({in.nr(),in.nc()}, &in(0,0), &out(0,0));\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    matrix<add_complex_t<typename EXP::type>> fftr (const matrix_exp<EXP>& data)\n    {\n        //real FFT for expression template\n        static_assert(std::is_floating_point<typename EXP::type>::value, \"input should be real\");\n        matrix<typename EXP::type> in(data);\n        return fftr(in);\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template<typename T, long NR, long NC, typename MM, typename L>\n    matrix<T,NR,ifftr_nc_size(NC),MM,L> ifftr (const matrix<std::complex<T>,NR,NC,MM,L>& in)\n    {\n        //inverse real FFT\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        matrix<T,NR,ifftr_nc_size(NC),MM,L> out(in.nr(), ifftr_nc_size(in.nc()));\n        if (in.size() != 0)\n        {\n            ifftr({out.nr(),out.nc()}, &in(0,0), &out(0,0));\n            out /= out.size();\n        }\n        return out;\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    matrix<remove_complex_t<typename EXP::type>> ifftr (const matrix_exp<EXP>& data)\n    {\n        //inverse real FFT for expression template\n        static_assert(is_complex<typename EXP::type>::value, \"input should be complex\");        \n        matrix<typename EXP::type> in(data);\n        return ifftr(in);\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, long NR, long NC, typename MM, typename L >\n    void fft_inplace (matrix<std::complex<T>,NR,NC,MM,L>& data)\n    {\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        if (data.size() != 0)\n            fft({data.nr(),data.nc()}, &data(0,0), &data(0,0), false);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template < typename T, long NR, long NC, typename MM, typename L >\n    void ifft_inplace (matrix<std::complex<T>,NR,NC,MM,L>& data)\n    {\n        static_assert(std::is_floating_point<T>::value, \"only support floating point types\");\n        if (data.size() != 0)\n            fft({data.nr(),data.nc()}, &data(0,0), &data(0,0), true);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace details\n    {\n        struct fft_func\n        {\n            template<typename MAT, typename T = typename MAT::type, typename std::enable_if<is_complex<T>::value, bool>::type = true>\n            auto operator()(const MAT& mat) const { return dlib::fft(mat); }\n\n            template<typename MAT, typename T = typename MAT::type, typename std::enable_if<!is_complex<T>::value, bool>::type = true>\n            auto operator()(const MAT& mat) const { return dlib::fft(dlib::complex_matrix(mat)); }\n\n            static constexpr std::size_t freqsize(std::size_t fftsize) { return fftsize; }\n        };\n\n        struct fftr_func\n        {\n            template<typename MAT>\n            auto operator()(const MAT& mat) const { return dlib::fftr(mat); }\n\n            static constexpr std::size_t freqsize(std::size_t fftsize) { return dlib::fftr_nc_size(fftsize); }\n        };\n\n        struct ifft_func\n        {\n            template<typename MAT>\n            auto operator()(const MAT& mat) const { return dlib::ifft(mat); }\n        };\n\n        struct ifftr_func\n        {\n            template<typename MAT>\n            auto operator()(const MAT& mat) const { return dlib::ifftr(mat); }\n        };\n\n        template <\n            typename EXP,\n            typename WINDOW,\n            typename FFT_FUNC\n        >\n        auto stft_impl (\n            const matrix_exp<EXP>& signal,\n            const WINDOW& w,\n            std::size_t fftsize,\n            std::size_t wlen,\n            std::size_t hoplen,\n            const FFT_FUNC& fft_obj\n        )\n        {\n            using T = typename EXP::type;\n            using R = remove_complex_t<T>;\n            using C = add_complex_t<T>;\n\n            static_assert(std::is_floating_point<R>::value, \"underlying type must be real or complex floating point type\");\n            DLIB_ASSERT(is_vector(signal), \"input must be a vector type\");\n            DLIB_ASSERT(signal.size() >= (long)wlen, \"signal.size() >= wlen not satisfied\");\n            DLIB_ASSERT(fftsize >= wlen, \"fftsize >= wlen not satisfied\");\n            DLIB_ASSERT(wlen >= hoplen, \"wlen >= hoplen not satisfied\");\n\n            // Input is left-padded by wlen/2 and right-padded wlen/2\n            const std::size_t total_padding = wlen;\n            const std::size_t overlap       = wlen - hoplen;\n            const std::size_t nframes       = (signal.size() + total_padding - overlap) / hoplen;\n            matrix<C> stft = zeros_matrix<C>(nframes,\n                                             FFT_FUNC::freqsize(fftsize));\n            matrix<R> win(1,wlen);\n            for (std::size_t i = 0 ; i < wlen ; ++i)\n                win(0, i) = w(i, wlen);\n\n            // TODO: reduce extra buffers, e.g. padded\n            matrix<T> padded;\n\n            if (is_row_vector(signal))\n                padded = join_rows(join_rows(zeros_matrix<T>(1, wlen/2), signal), zeros_matrix<T>(1, wlen/2));\n            else\n                padded = join_rows(join_rows(zeros_matrix<T>(1, wlen/2), trans(signal)), zeros_matrix<T>(1, wlen/2));\n\n            for (long i = 0 ; i < stft.nr() ; ++i)\n            {\n                set_rowm(stft, i) = fft_obj(join_rows(pointwise_multiply(win, subm(padded, 0, i*hoplen, 1, wlen)),\n                                                      zeros_matrix<T>(1, fftsize - wlen)));\n            }\n\n            return stft;\n        }\n\n        template <\n            typename ReturnType,\n            typename EXP,\n            typename WINDOW,\n            typename IFFT_FUNC\n        >\n        auto istft_impl (\n            const matrix_exp<EXP>& stft,\n            const WINDOW& w,\n            std::size_t wlen,\n            std::size_t hoplen,\n            const IFFT_FUNC& ifft_obj\n        )\n        {\n            using T = typename EXP::type;\n            using R = remove_complex_t<T>;\n\n            static_assert(is_complex<T>::value, \"matrix type must be complex\");\n            static_assert(std::is_floating_point<R>::value, \"underlying type must be complex floating point type\");\n            DLIB_ASSERT(stft.nc() > 0 && stft.nr() > 0, \"stft must be non-empty\");\n            DLIB_ASSERT(ifftr_nc_size(stft.nc()) >= (long)wlen, \"fftsize >= wlen not satisfied\");\n            DLIB_ASSERT(wlen >= hoplen, \"wlen >= hoplen not satisfied\");\n\n            const size_t ntime = (stft.nr() - 1) * hoplen + wlen;\n            matrix<ReturnType> signal = zeros_matrix<ReturnType>(1, ntime);\n            matrix<R> norm = zeros_matrix<R>(1, ntime);\n            matrix<R> win(1, wlen);\n            for (std::size_t i = 0 ; i < wlen ; ++i)\n                win(0, i) = w(i, wlen);\n            matrix<R> win2 = squared(win);\n\n            for (long t = 0 ; t < stft.nr() ; ++t)\n            {\n                set_subm(signal, 0, t*hoplen, 1, wlen) += pointwise_multiply(win, subm(ifft_obj(rowm(stft, t)), 0, 0, 1, wlen));\n                set_subm(norm,   0, t*hoplen, 1, wlen) += win2;\n            }\n\n            // Remove padding of wlen/2 and wlen/2 on either end\n            DLIB_ASSERT(sum(subm(norm, 0, wlen/2, 1, ntime - wlen) < 1e-13) == 0, \"NOLA constraint not satisfied\");\n            signal = pointwise_divide(subm(signal, 0, wlen/2, 1, ntime - wlen),\n                                      subm(norm,   0, wlen/2, 1, ntime - wlen));\n\n            return signal;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline auto make_hann()\n    {\n        return [](std::size_t i, std::size_t N) {return hann(i, N, PERIODIC); };\n    }\n\n    inline auto make_blackman()\n    {\n        return [](std::size_t i, std::size_t N) {return blackman(i, N, PERIODIC);};\n    }\n\n    inline auto make_blackman_nuttall()\n    {\n        return [](std::size_t i, std::size_t N) {return blackman_nuttall(i, N, PERIODIC);};\n    }\n\n    inline auto make_blackman_harris()\n    {\n        return [](std::size_t i, std::size_t N) { return blackman_harris(i, N, PERIODIC); };\n    }\n\n    inline auto make_blackman_harris7()\n    {\n        return [](std::size_t i, std::size_t N) { return blackman_harris7(i, N, PERIODIC); };\n    }\n\n    inline auto make_kaiser(beta_t beta)\n    {\n        return [=](std::size_t i, std::size_t N){return kaiser(i, N, beta, PERIODIC);};\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    auto stft (\n        const matrix_exp<EXP>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        return details::stft_impl(signal, w, fftsize, wlen, hoplen, details::fft_func{});\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename Alloc, typename WINDOW>\n    auto stft (\n        const std::vector<T, Alloc>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        return stft(dlib::mat(signal), w, fftsize, wlen, hoplen);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP,typename WINDOW>\n    auto istft (\n        const matrix_exp<EXP>& stft,\n        const WINDOW& w,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        using T = typename EXP::type;\n        return details::istft_impl<T>(stft, w, wlen, hoplen, details::ifft_func{});\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    auto stftr (\n        const matrix_exp<EXP>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        return details::stft_impl(signal, w, fftsize, wlen, hoplen, details::fftr_func{});\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename Alloc, typename WINDOW>\n    auto stftr (\n        const std::vector<T, Alloc>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        return stftr(dlib::mat(signal), w, fftsize, wlen, hoplen);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    auto istftr (\n        const matrix_exp<EXP>& stft,\n        const WINDOW& w,\n        std::size_t wlen,\n        std::size_t hoplen\n    )\n    {\n        using R = remove_complex_t<typename EXP::type>;\n        return details::istft_impl<R>(stft, w, wlen, hoplen, details::ifftr_func{});\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_FFt_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_fft_abstract.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FFt_ABSTRACT_Hh_\n#ifdef DLIB_FFt_ABSTRACT_Hh_\n\n#include \"matrix_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    typename EXP::matrix_type fft (\n        const matrix_exp<EXP>& data\n    );  \n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - Computes the 1 or 2 dimensional discrete Fourier transform of the given data\n              matrix and returns it.  In particular, we return a matrix D such that:\n                - D.nr() == data.nr()\n                - D.nc() == data.nc()\n                - D(0,0) == the DC term of the Fourier transform.\n                - starting with D(0,0), D contains progressively higher frequency components\n                  of the input data.\n                - ifft(D) == data\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, typename Alloc >\n    matrix<std::complex<T>,0,1> fft (\n        const std::vector<std::complex<T>, Alloc>& data\n    );\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - Computes the 1 dimensional discrete Fourier transform of the given data\n              vector and returns it.  In particular, we return a matrix D such that:\n                - D.nr() == data.size()\n                - D.nc() == 1\n                - D(0,0) == the DC term of the Fourier transform.\n                - starting with D(0,0), D contains progressively higher frequency components\n                  of the input data.\n                - ifft(D) == data\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    typename EXP::matrix_type ifft (\n        const matrix_exp<EXP>& data\n    );  \n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - Computes the 1 or 2 dimensional inverse discrete Fourier transform of the\n              given data vector and returns it.  In particular, we return a matrix D such\n              that:\n                - D.nr() == data.nr()\n                - D.nc() == data.nc()\n                - fft(D) == data \n    !*/\n\n// ----------------------------------------------------------------------------------------\n    \n    template < typename T, typename Alloc >\n    matrix<std::complex<T>,0,1> ifft (\n        const std::vector<std::complex<T>, Alloc>& data\n    )\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - Computes the 1 dimensional inverse discrete Fourier transform of the\n              given data vector and returns it.  In particular, we return a matrix D such\n              that:\n                - D.nr() == data.size()\n                - D.nc() == 1\n                - fft(D) == data \n    !*/\n    \n// ----------------------------------------------------------------------------------------\n        \n    template <typename EXP>\n    matrix<add_complex_t<typename EXP::type>> fftr (\n        const matrix_exp<EXP>& data\n    );  \n    /*!\n        requires\n            - data contains elements of type double, float, or long double.\n            - data.nc() is even\n        ensures\n            - Computes the 1 or 2 dimensional real discrete Fourier transform of the given data\n              matrix and returns it.  In particular, we return a matrix D such that:\n                - D.nr() == data.nr()\n                - D.nc() == fftr_nc_size(data.nc())\n                - D(0,0) == the DC term of the Fourier transform.\n                - starting with D(0,0), D contains progressively higher frequency components\n                  of the input data.\n                - ifftr(D) == data\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    matrix<remove_complex_t<typename EXP::type>> ifftr (\n        const matrix_exp<EXP>& data\n    );  \n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - Computes the 1 or 2 dimensional inverse real discrete Fourier transform of the\n              given data vector and returns it.  In particular, we return a matrix D such\n              that:\n                - D.nr() == data.nr()\n                - D.nc() == ifftr_nc_size(data.nc())\n                - fftr(D) == data\n    !*/\n\n// ----------------------------------------------------------------------------------------\n    \n    template < \n        typename T, \n        long NR,\n        long NC,\n        typename MM,\n        typename L \n        >\n    void fft_inplace (\n        matrix<std::complex<T>,NR,NC,MM,L>& data\n    );\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - This function is identical to fft() except that it does the FFT in-place.\n              That is, after this function executes we will have:\n                - #data == fft(data)\n    !*/\n    \n// ----------------------------------------------------------------------------------------\n\n    template < \n        typename T, \n        long NR,\n        long NC,\n        typename MM,\n        typename L \n        >\n    void ifft_inplace (\n        matrix<std::complex<T>,NR,NC,MM,L>& data\n    );\n    /*!\n        requires\n            - data contains elements of type std::complex<> that itself contains double, float, or long double.\n        ensures\n            - This function is identical to ifft() except that it does the inverse FFT\n              in-place.  That is, after this function executes we will have:\n                - #data == ifft(data)*data.size()\n                - Note that the output needs to be divided by data.size() to complete the \n                  inverse transformation.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    // These return function objects with signature double(size_t i, size_t wlen)\n    // defining PERIODIC window functions suitable for passing to STFT functions\n\n    inline function_object make_hann();\n    inline function_object make_blackman();\n    inline function_object make_blackman_nuttall();\n    inline function_object make_blackman_harris();\n    inline function_object make_blackman_harris7();\n    inline function_object make_kaiser(beta_t beta);\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    matrix<complex_type> stft (\n        const matrix_exp<EXP>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        requires\n            - is_vector(signal) == true, i.e. signal has rank 1\n            - signal.size() >= wlen\n            - w is a function object with signature double(size_t i, size_t wlen) that defines a PERIODIC window,\n              e.g. the output of make_hann().\n            - fftsize >= wlen\n            - wlen >= hoplen\n            - EXP::type is a floating point type (float, double or long double), real or complex\n        ensures\n            - Performs a Short-Time-Fourier-Transform (STFT) on 1D data.\n            - Returns a matrix D where first dimension correponds to time and second dimension corresponds to frequency.\n            - Dimensions of D are:\n                - D.nr() == (signal.size() + hoplen) / hoplen and corresponds to the number of time frames.\n                - D.nc() == fftsize\n            - The type of D is add_complex_t<EXP::type>\n            - Each time frame t (equivalently, each row t) is centered on signal(t*hoplen)\n            - This is equivalent to calling the following in python\n              (provided w is converted into a string representation which scipy can interpret)\n                win     = scipy.signal.get_window(w, wlen)\n                scale   = win.sum()\n                _, _, Z = scipy.signal.stft(signal, nfft=fftsize, nperseg=wlen, noverlap=(wlen-hoplen), window=win, return_onesided=False)\n                Z       *= scale\n\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename Alloc, typename WINDOW>\n    matrix<complex_type> stft (\n        const std::vector<T, Alloc>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        ensures\n            - This is a shortcut to calling stft(dlib::mat(signal), w, fftsize, wlen, hoplen)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP,typename WINDOW>\n    matrix<complex_type> istft (\n        const matrix_exp<EXP>& stft,\n        const WINDOW& w,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        requires\n            - m has rank 2 where 1st dimension corresponds to time and second dimension corresponds to frequency\n            - w is a function object with signature double(size_t i, size_t wlen) that defines a PERIODIC window,\n              e.g. the output of make_hann().\n            - wlen >= hoplen\n            - EXP::type is a complex floating point type (complex<float>, complex<double> or complex<long double>)\n            - If you wish to satisfy istft(stft(x, ...), ...) == x then:\n                - w is the same as what was used with stft()\n                - wlen is the same as what was used with stft()\n                - hoplen is the same as what was used with stft()\n        ensures\n            - Performs an inverse Short-Time-Fourier-Transform (STFT)\n            - istft(stft(x, w, wlen, wlen, hoplen), w, wlen, hoplen)) == x\n            - istft(stft(x, w, fftsize, wlen, hoplen), w, wlen, hoplen)) == x\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    matrix<complex_type> stftr (\n        const matrix_exp<EXP>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        requires\n            - is_vector(signal) == true, i.e. signal has rank 1\n            - signal.size() >= wlen\n            - w is a function object with signature double(size_t i, size_t wlen) that defines a PERIODIC window,\n              e.g. the output of make_hann().\n            - fftsize >= wlen\n            - wlen >= hoplen\n            - EXP::type is a floating point type (float, double or long double) and must be real\n        ensures\n            - Performs a real Short-Time-Fourier-Transform (STFTr) on 1D data.\n            - Returns a matrix D where first dimension correponds to time and second dimension corresponds to frequency.\n            - Dimensions of D are:\n                - D.nr() == (signal.size() + hoplen) / hoplen and corresponds to the number of time frames.\n                - D.nc() == fftsize/2 + 1\n            - The type of D is add_complex_t<EXP::type>\n            - Each time frame t (equivalently each row t) is centered on signal(t*hoplen)\n            - This is equivalent to calling the follwoing in python\n              (provided w is converted into a string representation which scipy can interpret)\n                win     = scipy.signal.get_window(w, wlen)\n                scale   = win.sum()\n                _, _, Z = scipy.signal.stft(signal, nfft=fftsize, nperseg=wlen, noverlap=(wlen-hoplen), window=win, return_onesided=True)\n                Z       *= scale\n\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename Alloc, typename WINDOW>\n    matrix<complex_type> stftr (\n        const std::vector<T, Alloc>& signal,\n        const WINDOW& w,\n        std::size_t fftsize,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        ensures\n            - This is a shortcut to calling istft(dlib::mat(signal), w, wlen, hoplen)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename WINDOW>\n    matrix<real_type> istftr (\n        const matrix_exp<EXP>& stft,\n        const WINDOW& w,\n        std::size_t wlen,\n        std::size_t hoplen\n    );\n    /*!\n        requires\n            - m has rank 2 where 1st dimension corresponds to time and second dimension corresponds to frequency\n            - w is a function object with signature double(size_t i, size_t wlen) that defines a PERIODIC window,\n              e.g. the output of make_hann().\n            - wlen >= hoplen\n            - EXP::type is a complex floating point type (complex<float>, complex<double> or complex<long double>)\n            - If you wish to satisfy istftr(stftr(x, ...), ...) == x then:\n                - w is the same as what was used with stftr()\n                - wlen is the same as what was used with stftr()\n                - hoplen is the same as what was used with stftr()\n        ensures\n            - Performs an inverse Short-Time-Fourier-Transform (STFT)\n            - istftr(stftr(x, w, wlen, wlen, hoplen), w, wlen, hoplen)) == x\n            - istftr(stftr(x, w, fftsize, wlen, hoplen), w, wlen, hoplen)) == x\n    !*/\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_FFt_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_fwd.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_FWD\n#define DLIB_MATRIx_FWD\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    struct row_major_layout;\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long num_rows = 0,\n        long num_cols = 0,\n        typename mem_manager = default_memory_manager,\n        typename layout = row_major_layout \n        >\n    class matrix; \n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_FWD\n\n"
  },
  {
    "path": "dlib/matrix/matrix_generic_image.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIX_GENERIC_iMAGE_Hh_\n#define DLIB_MATRIX_GENERIC_iMAGE_Hh_\n\n#include \"matrix.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    struct image_traits<matrix<T,NR,NC,MM> >\n    {\n        typedef T pixel_type;\n    };\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    struct image_traits<const matrix<T,NR,NC,MM> >\n    {\n        typedef T pixel_type;\n    };\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline long num_rows( const matrix<T,NR,NC,MM>& img) { return img.nr(); }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline long num_columns( const matrix<T,NR,NC,MM>& img) { return img.nc(); }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline void set_image_size(\n        matrix<T,NR,NC,MM>& img,\n        long rows,\n        long cols \n    ) { img.set_size(rows,cols); }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline void* image_data(\n        matrix<T,NR,NC,MM>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img(0,0);\n        else\n            return 0;\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline const void* image_data(\n        const matrix<T,NR,NC,MM>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img(0,0);\n        else\n            return 0;\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    inline size_t width_step(\n        const matrix<T,NR,NC,MM>& img\n    ) \n    { \n        return img.nc()*sizeof(T);\n    }\n\n}\n\n#endif // DLIB_MATRIX_GENERIC_iMAGE_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_la.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_LA_FUNCTS_\n#define DLIB_MATRIx_LA_FUNCTS_ \n\n#include \"matrix_la_abstract.h\"\n#include \"matrix_utilities.h\"\n#include \"../sparse_vector.h\"\n#include \"../optimization/optimization_line_search.h\"\n\n// The 4 decomposition objects described in the matrix_la_abstract.h file are\n// actually implemented in the following 4 files.  \n#include \"matrix_lu.h\"\n#include \"matrix_qr.h\"\n#include \"matrix_cholesky.h\"\n#include \"matrix_eigenvalue.h\"\n\n#ifdef DLIB_USE_LAPACK\n#include \"lapack/potrf.h\"\n#include \"lapack/pbtrf.h\"\n#include \"lapack/gesdd.h\"\n#include \"lapack/gesvd.h\"\n#endif\n\n#include \"../threads.h\"\n\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    enum svd_u_mode\n    {\n        SVD_NO_U,\n        SVD_SKINNY_U,\n        SVD_FULL_U\n    };\n\n    template <\n        typename EXP,\n        long qN, long qX,\n        long uM, long uN,\n        long vM, long vN,\n        typename MM1,\n        typename MM2,\n        typename MM3,\n        typename L1\n        >\n    long svd4 (\n        svd_u_mode u_mode, \n        bool withv, \n        const matrix_exp<EXP>& a,\n        matrix<typename EXP::type,uM,uN,MM1,L1>& u, \n        matrix<typename EXP::type,qN,qX,MM2,L1>& q, \n        matrix<typename EXP::type,vM,vN,MM3,L1>& v\n    )\n    {\n        /*  \n            Singular value decomposition. Translated to 'C' from the\n            original Algol code in \"Handbook for Automatic Computation,\n            vol. II, Linear Algebra\", Springer-Verlag.  Note that this\n            published algorithm is considered to be the best and numerically\n            stable approach to computing the real-valued svd and is referenced\n            repeatedly in ieee journal papers, etc where the svd is used.\n\n            This is almost an exact translation from the original, except that\n            an iteration counter is added to prevent stalls. This corresponds\n            to similar changes in other translations.\n\n            Returns an error code = 0, if no errors and 'k' if a failure to\n            converge at the 'kth' singular value.\n\n            USAGE: given the singular value decomposition a = u * diagm(q) * trans(v) for an m*n \n                    matrix a with m >= n ...  \n                    After the svd call u is an m x m matrix which is columnwise \n                    orthogonal. q will be an n element vector consisting of singular values \n                    and v an n x n orthogonal matrix. eps and tol are tolerance constants. \n                    Suitable values are eps=1e-16 and tol=(1e-300)/eps if T == double. \n\n                    If u_mode == SVD_NO_U then u won't be computed and similarly if withv == false\n                    then v won't be computed.  If u_mode == SVD_SKINNY_U then u will be m x n instead of m x m.\n        */\n\n\n        DLIB_ASSERT(a.nr() >= a.nc(), \n            \"\\tconst matrix_exp svd4()\"\n            << \"\\n\\tYou have given an invalidly sized matrix\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            );\n\n\n        typedef typename EXP::type T;\n\n#ifdef DLIB_USE_LAPACK\n        matrix<typename EXP::type,0,0,MM1,L1> temp(a), vtemp;\n\n        char jobu = 'A';\n        char jobvt = 'A';\n        if (u_mode == SVD_NO_U)\n            jobu = 'N';\n        else if (u_mode == SVD_SKINNY_U)\n            jobu = 'S';\n        if (withv == false)\n            jobvt = 'N';\n\n        int info;\n        if (jobu == jobvt)\n        {\n            info = lapack::gesdd(jobu, temp, q, u, vtemp);\n        }\n        else\n        {\n            info = lapack::gesvd(jobu, jobvt, temp, q, u, vtemp);\n        }\n\n        // pad q with zeros if it isn't the length we want\n        if (q.nr() < a.nc())\n            q = join_cols(q, zeros_matrix<T>(a.nc()-q.nr(),1));\n\n        if (withv)\n            v = trans(vtemp);\n\n        return info;\n#else\n        using std::abs;\n        using std::sqrt;\n\n        T eps = std::numeric_limits<T>::epsilon();\n        T tol = std::numeric_limits<T>::min()/eps;\n\n        const long m = a.nr();\n        const long n = a.nc();\n        long i, j, k, l = 0, l1, iter, retval;\n        T c, f, g, h, s, x, y, z;\n\n        matrix<T,qN,1,MM2> e(n,1); \n        q.set_size(n,1);\n        if (u_mode == SVD_FULL_U)\n            u.set_size(m,m);\n        else\n            u.set_size(m,n);\n        retval = 0;\n\n        if (withv)\n        {\n            v.set_size(n,n);\n        }\n\n        /* Copy 'a' to 'u' */    \n        for (i=0; i<m; i++) \n        {\n            for (j=0; j<n; j++)\n                u(i,j) = a(i,j);\n        }\n\n        /* Householder's reduction to bidiagonal form. */\n        g = x = 0.0;    \n        // We use *ei instead of e(i) because some versions of gcc emit a bogus warning message\n        // otherwise.\n        auto ei = e.begin();\n        for (i=0; i<n; i++, ei++)\n        {\n            *ei = g;\n            s = 0.0;\n            l = i + 1;\n\n            for (j=i; j<m; j++)\n                s += (u(j,i) * u(j,i));\n\n            if (s < tol)\n                g = 0.0;\n            else \n            {\n                f = u(i,i);\n                g = (f < 0) ? sqrt(s) : -sqrt(s);\n                h = f * g - s;\n                u(i,i) = f - g;\n\n                for (j=l; j<n; j++) \n                {\n                    s = 0.0;\n\n                    for (k=i; k<m; k++)\n                        s += (u(k,i) * u(k,j));\n\n                    f = s / h;\n\n                    for (k=i; k<m; k++)\n                        u(k,j) += (f * u(k,i));\n                } /* end j */\n            } /* end s */\n\n            q(i) = g;\n            s = 0.0;\n\n            for (j=l; j<n; j++)\n                s += (u(i,j) * u(i,j));\n\n            if (s < tol)\n                g = 0.0;\n            else \n            {\n                f = u(i,i+1);\n                g = (f < 0) ? sqrt(s) : -sqrt(s);\n                h = f * g - s;\n                u(i,i+1) = f - g;\n\n                for (j=l; j<n; j++) \n                    e(j) = u(i,j) / h;\n\n                for (j=l; j<m; j++) \n                {\n                    s = 0.0;\n\n                    for (k=l; k<n; k++) \n                        s += (u(j,k) * u(i,k));\n\n                    for (k=l; k<n; k++)\n                        u(j,k) += (s * e(k));\n                } /* end j */\n            } /* end s */\n\n            y = abs(q(i)) + abs(*ei);\n            if (y > x)\n                x = y;\n        } /* end i */\n\n        /* accumulation of right-hand transformations */\n        if (withv) \n        {\n            for (i=n-1; i>=0; i--) \n            {\n                if (g != 0.0) \n                {\n                    h = u(i,i+1) * g;\n\n                    for (j=l; j<n; j++)\n                        v(j,i) = u(i,j)/h;\n\n                    for (j=l; j<n; j++) \n                    {\n                        s = 0.0;\n\n                        for (k=l; k<n; k++) \n                            s += (u(i,k) * v(k,j));\n\n                        for (k=l; k<n; k++)\n                            v(k,j) += (s * v(k,i));\n                    } /* end j */\n                } /* end g */\n\n                for (j=l; j<n; j++)\n                    v(i,j) = v(j,i) = 0.0;\n\n                v(i,i) = 1.0;\n                g = e(i);\n                l = i;\n            } /* end i */\n        } /* end withv, parens added for clarity */\n\n        /* accumulation of left-hand transformations */\n        if (u_mode != SVD_NO_U) \n        {\n            for (i=n; i<u.nr(); i++) \n            {\n                for (j=n;j<u.nc();j++)\n                    u(i,j) = 0.0;\n\n                if (i < u.nc())\n                    u(i,i) = 1.0;\n            }\n        }\n\n        if (u_mode != SVD_NO_U) \n        {\n            for (i=n-1; i>=0; i--) \n            {\n                l = i + 1;\n                g = q(i);\n\n                for (j=l; j<u.nc(); j++)  \n                    u(i,j) = 0.0;\n\n                if (g != 0.0) \n                {\n                    h = u(i,i) * g;\n\n                    for (j=l; j<u.nc(); j++) \n                    { \n                        s = 0.0;\n\n                        for (k=l; k<m; k++)\n                            s += (u(k,i) * u(k,j));\n\n                        f = s / h;\n\n                        for (k=i; k<m; k++) \n                            u(k,j) += (f * u(k,i));\n                    } /* end j */\n\n                    for (j=i; j<m; j++) \n                        u(j,i) /= g;\n                } /* end g */\n                else \n                {\n                    for (j=i; j<m; j++)\n                        u(j,i) = 0.0;\n                }\n\n                u(i,i) += 1.0;\n            } /* end i*/\n        } \n\n        /* diagonalization of the bidiagonal form */\n        eps *= x;\n\n        for (k=n-1; k>=0; k--) \n        {\n            iter = 0;\n\ntest_f_splitting:\n\n            for (l=k; l>=0; l--) \n            {\n                if (abs(e(l)) <= eps) \n                    goto test_f_convergence;\n\n                if (abs(q(l-1)) <= eps) \n                    goto cancellation;\n            } /* end l */\n\n            /* cancellation of e(l) if l > 0 */\n\ncancellation:\n\n            c = 0.0;\n            s = 1.0;\n            l1 = l - 1;\n\n            for (i=l; i<=k; i++) \n            {\n                f = s * e(i);\n                e(i) *= c;\n\n                if (abs(f) <= eps) \n                    goto test_f_convergence;\n\n                g = q(i);\n                h = q(i) = sqrt(f*f + g*g);\n                c = g / h;\n                s = -f / h;\n\n                if (u_mode != SVD_NO_U) \n                {\n                    for (j=0; j<m; j++) \n                    {\n                        y = u(j,l1);\n                        z = u(j,i);\n                        u(j,l1) = y * c + z * s;\n                        u(j,i) = -y * s + z * c;\n                    } /* end j */\n                } \n            } /* end i */\n\ntest_f_convergence:\n\n            z = q(k);\n            if (l == k) \n                goto convergence;\n\n            /* shift from bottom 2x2 minor */\n            iter++;\n            if (iter > 300) \n            {\n                retval = k;\n                break;\n            }\n            x = q(l);\n            y = q(k-1);\n            g = e(k-1);\n            h = e(k);\n            f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2 * h * y);\n            g = sqrt(f * f + 1.0);\n            f = ((x - z) * (x + z) + h * (y / ((f < 0)?(f - g) : (f + g)) - h)) / x;\n\n            /* next QR transformation */\n            c = s = 1.0;\n\n            for (i=l+1; i<=k; i++) \n            {\n                g = e(i);\n                y = q(i);\n                h = s * g;\n                g *= c;\n                e(i-1) = z = sqrt(f * f + h * h);\n                c = f / z;\n                s = h / z;\n                f = x * c + g * s;\n                g = -x * s + g * c;\n                h = y * s;\n                y *= c;\n\n                if (withv) \n                {\n                    for (j=0;j<n;j++) \n                    {\n                        x = v(j,i-1);\n                        z = v(j,i);\n                        v(j,i-1) = x * c + z * s;\n                        v(j,i) = -x * s + z * c;\n                    } /* end j */\n                } /* end withv, parens added for clarity */\n\n                q(i-1) = z = sqrt(f * f + h * h);\n                if (z != 0)\n                {\n                    c = f / z;\n                    s = h / z;\n                }\n                f = c * g + s * y;\n                x = -s * g + c * y;\n                if (u_mode != SVD_NO_U) \n                {\n                    for (j=0; j<m; j++) \n                    {\n                        y = u(j,i-1);\n                        z = u(j,i);\n                        u(j,i-1) = y * c + z * s;\n                        u(j,i) = -y * s + z * c;\n                    } /* end j */\n                } \n            } /* end i */\n\n            e(l) = 0.0;\n            e(k) = f;\n            q(k) = x;\n\n            goto test_f_splitting;\n\nconvergence:\n\n            if (z < 0.0) \n            {\n                /* q(k) is made non-negative */\n                q(k) = -z;\n                if (withv) \n                {\n                    for (j=0; j<n; j++)\n                        v(j,k) = -v(j,k);\n                } /* end withv, parens added for clarity */\n            } /* end z */\n        } /* end k */\n\n        return retval;\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        long qN, long qX,\n        long uM, \n        long vN, \n        typename MM1,\n        typename MM2,\n        typename MM3,\n        typename L1\n        >\n    long svd2 (\n        bool withu, \n        bool withv, \n        const matrix_exp<EXP>& a,\n        matrix<typename EXP::type,uM,uM,MM1,L1>& u, \n        matrix<typename EXP::type,qN,qX,MM2,L1>& q, \n        matrix<typename EXP::type,vN,vN,MM3,L1>& v\n    )\n    {\n        const long NR = matrix_exp<EXP>::NR;\n        const long NC = matrix_exp<EXP>::NC;\n\n        // make sure the output matrices have valid dimensions if they are statically dimensioned\n        COMPILE_TIME_ASSERT(qX == 0 || qX == 1);\n        COMPILE_TIME_ASSERT(NR == 0 || uM == 0 || NR == uM);\n        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);\n\n        DLIB_ASSERT(a.nr() >= a.nc(), \n            \"\\tconst matrix_exp svd4()\"\n            << \"\\n\\tYou have given an invalidly sized matrix\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            );\n\n        if (withu)\n            return svd4(SVD_FULL_U, withv, a,u,q,v);\n        else\n            return svd4(SVD_NO_U, withv, a,u,q,v);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    void orthogonalize (\n        matrix<T,NR,NC,MM,row_major_layout>& m\n    )\n    {\n        // We don't really need to use this temporary, but doing it this way runs a lot\n        // faster.\n        matrix<T,NR,NC,MM,column_major_layout> temp;\n        qr_decomposition<matrix<T,NR,NC,MM,row_major_layout>>(m).get_q(temp);\n        m = temp;\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    void orthogonalize (\n        matrix<T,NR,NC,MM,column_major_layout>& m\n    )\n    {\n        qr_decomposition<matrix<T,NR,NC,MM,column_major_layout>>(m).get_q(m);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long Anr, long Anc,\n        typename MM,\n        typename L\n        >\n    void find_matrix_range (\n        const matrix<T,Anr,Anc,MM,L>& A,\n        unsigned long l,\n        matrix<T,Anr,0,MM,L>& Q,\n        unsigned long q \n    )\n    /*!\n        requires\n            - A.nr() >= l\n        ensures\n            - #Q.nr() == A.nr() \n            - #Q.nc() == l\n            - #Q == an orthonormal matrix whose range approximates the range of the\n              matrix A.  \n            - This function implements the randomized subspace iteration defined \n              in the algorithm 4.4 box of the paper: \n                Finding Structure with Randomness: Probabilistic Algorithms for\n                Constructing Approximate Matrix Decompositions by Halko et al.\n            - q defines the number of extra subspace iterations this algorithm will\n              perform.  Often q == 0 is fine, but performing more iterations can lead to a\n              more accurate approximation of the range of A if A has slowly decaying\n              singular values.  In these cases, using a q of 1 or 2 is good.\n    !*/\n    {\n        DLIB_ASSERT(A.nr() >= (long)l, \"Invalid inputs were given to this function.\");\n        Q = A*matrix_cast<T>(gaussian_randm(A.nc(), l));\n\n        orthogonalize(Q);\n\n        // Do some extra iterations of the power method to make sure we get Q into the \n        // span of the most important singular vectors of A.\n        if (q != 0)\n        {\n            for (unsigned long itr = 0; itr < q; ++itr)\n            {\n                Q = trans(A)*Q;\n                orthogonalize(Q);\n\n                Q = A*Q;\n                orthogonalize(Q);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long Anr, long Anc,\n        long Unr, long Unc,\n        long Wnr, long Wnc,\n        long Vnr, long Vnc,\n        typename MM,\n        typename L\n        >\n    void svd_fast (\n        const matrix<T,Anr,Anc,MM,L>& A,\n        matrix<T,Unr,Unc,MM,L>& u,\n        matrix<T,Wnr,Wnc,MM,L>& w,\n        matrix<T,Vnr,Vnc,MM,L>& v,\n        unsigned long l,\n        unsigned long q = 1\n    )\n    {\n        const unsigned long k = std::min(l, std::min<unsigned long>(A.nr(),A.nc()));\n\n        DLIB_ASSERT(l > 0 && A.size() > 0, \n            \"\\t void svd_fast()\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t l: \" << l \n            << \"\\n\\t A.size(): \" << A.size() \n            );\n\n        matrix<T,Anr,0,MM,L> Q;\n        find_matrix_range(A, k, Q, q);\n\n        // Compute trans(B) = trans(Q)*A.   The reason we store B transposed\n        // is so that when we take its SVD later using svd3() it doesn't consume\n        // a whole lot of RAM.  That is, we make sure the square matrix coming out\n        // of svd3() has size lxl rather than the potentially much larger nxn.\n        matrix<T,0,0,MM,L> B = trans(A)*Q;\n        svd3(B, v,w,u);\n        u = Q*u;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sparse_vector_type, \n        typename T,\n        typename MM,\n        typename L\n        >\n    void find_matrix_range (\n        const std::vector<sparse_vector_type>& A,\n        unsigned long l,\n        matrix<T,0,0,MM,L>& Q,\n        unsigned long q \n    )\n    /*!\n        requires\n            - A.size() >= l\n        ensures\n            - #Q.nr() == A.size()\n            - #Q.nc() == l\n            - #Q == an orthonormal matrix whose range approximates the range of the\n              matrix A.  In this case, we interpret A as a matrix of A.size() rows,\n              where each row is defined by a sparse vector.\n            - This function implements the randomized subspace iteration defined \n              in the algorithm 4.4 box of the paper: \n                Finding Structure with Randomness: Probabilistic Algorithms for\n                Constructing Approximate Matrix Decompositions by Halko et al.\n            - q defines the number of extra subspace iterations this algorithm will\n              perform.  Often q == 0 is fine, but performing more iterations can lead to a\n              more accurate approximation of the range of A if A has slowly decaying\n              singular values.  In these cases, using a q of 1 or 2 is good.\n    !*/\n    {\n        DLIB_ASSERT(A.size() >= l, \"Invalid inputs were given to this function.\");\n        Q.set_size(A.size(), l);\n\n        // Compute Q = A*gaussian_randm()\n        parallel_for(0, Q.nr(), [&](long r)\n        {\n            for (long c = 0; c < Q.nc(); ++c)\n            {\n                Q(r,c) = dot(A[r], gaussian_randm(std::numeric_limits<long>::max(), 1, c));\n            }\n        });\n\n        orthogonalize(Q);\n\n        // Do some extra iterations of the power method to make sure we get Q into the \n        // span of the most important singular vectors of A.\n        if (q != 0)\n        {\n            dlib::mutex mut;\n            const unsigned long n = max_index_plus_one(A);\n            for (unsigned long itr = 0; itr < q; ++itr)\n            {\n                matrix<T,0,0,MM> Z;\n                // Compute Z = trans(A)*Q\n                parallel_for_blocked(0, A.size(), [&](long begin, long end)\n                {\n                    matrix<T,0,0,MM> Zlocal(n,l);\n                    Zlocal = 0;\n                    for (long m = begin; m < end; ++m)\n                    {\n                        for (unsigned long r = 0; r < l; ++r)\n                        {\n                            for (auto& i : A[m])\n                            {\n                                const auto c = i.first;\n                                const auto val = i.second;\n\n                                Zlocal(c,r) += Q(m,r)*val;\n                            }\n                        }\n                    }\n                    auto_mutex lock(mut);\n                    Z += Zlocal;\n                },1);\n\n                Q.set_size(0,0); // free RAM\n                orthogonalize(Z);\n\n                // Compute Q = A*Z\n                Q.set_size(A.size(), l);\n                parallel_for(0, Q.nr(), [&](long r)\n                {\n                    for (long c = 0; c < Q.nc(); ++c)\n                    {\n                        Q(r,c) = dot(A[r], colm(Z,c));\n                    }\n                });\n\n                Z.set_size(0,0); // free RAM\n                orthogonalize(Q);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace simpl\n    {\n        template <\n            typename sparse_vector_type, \n            typename T,\n            long Unr, long Unc,\n            long Wnr, long Wnc,\n            long Vnr, long Vnc,\n            typename MM,\n            typename L\n            >\n        void svd_fast (\n            bool compute_u,\n            const std::vector<sparse_vector_type>& A,\n            matrix<T,Unr,Unc,MM,L>& u,\n            matrix<T,Wnr,Wnc,MM,L>& w,\n            matrix<T,Vnr,Vnc,MM,L>& v,\n            unsigned long l,\n            unsigned long q \n        )\n        {\n            const long n = max_index_plus_one(A);\n            const unsigned long k = std::min(l, std::min<unsigned long>(A.size(),n));\n\n            DLIB_ASSERT(l > 0 && A.size() > 0 && n > 0, \n                \"\\t void svd_fast()\"\n                << \"\\n\\t Invalid inputs were given to this function.\"\n                << \"\\n\\t l: \" << l \n                << \"\\n\\t n (i.e. max_index_plus_one(A)): \" << n \n                << \"\\n\\t A.size(): \" << A.size() \n                );\n\n            matrix<T,0,0,MM,L> Q;\n            find_matrix_range(A, k, Q, q);\n\n            // Compute trans(B) = trans(Q)*A.   The reason we store B transposed\n            // is so that when we take its SVD later using svd3() it doesn't consume\n            // a whole lot of RAM.  That is, we make sure the square matrix coming out\n            // of svd3() has size lxl rather than the potentially much larger nxn.\n            matrix<T,0,0,MM> B;\n            dlib::mutex mut;\n            parallel_for_blocked(0, A.size(), [&](long begin, long end)\n            {\n                matrix<T,0,0,MM> Blocal(n,k);\n                Blocal = 0;\n                for (long m = begin; m < end; ++m)\n                {\n                    for (unsigned long r = 0; r < k; ++r)\n                    {\n                        for (auto& i : A[m])\n                        {\n                            const auto c = i.first;\n                            const auto val = i.second;\n\n                            Blocal(c,r) += Q(m,r)*val;\n                        }\n                    }\n                }\n                auto_mutex lock(mut);\n                B += Blocal;\n            },1);\n\n            svd3(B, v,w,u);\n            if (compute_u)\n                u = Q*u;\n        }\n    }\n\n    template <\n        typename sparse_vector_type, \n        typename T,\n        long Unr, long Unc,\n        long Wnr, long Wnc,\n        long Vnr, long Vnc,\n        typename MM,\n        typename L\n        >\n    void svd_fast (\n        const std::vector<sparse_vector_type>& A,\n        matrix<T,Unr,Unc,MM,L>& u,\n        matrix<T,Wnr,Wnc,MM,L>& w,\n        matrix<T,Vnr,Vnc,MM,L>& v,\n        unsigned long l,\n        unsigned long q = 1\n    )\n    {\n        simpl::svd_fast(true, A,u,w,v,l,q);\n    }\n\n    template <\n        typename sparse_vector_type, \n        typename T,\n        long Wnr, long Wnc,\n        long Vnr, long Vnc,\n        typename MM,\n        typename L\n        >\n    void svd_fast (\n        const std::vector<sparse_vector_type>& A,\n        matrix<T,Wnr,Wnc,MM,L>& w,\n        matrix<T,Vnr,Vnc,MM,L>& v,\n        unsigned long l,\n        unsigned long q = 1\n    )\n    {\n        matrix<T,0,0,MM,L> u;\n        simpl::svd_fast(false, A,u,w,v,l,q);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        long N\n        >\n    struct inv_helper\n    {\n        static const typename matrix_exp<EXP>::matrix_type inv (\n            const matrix_exp<EXP>& m\n        )\n        {\n            // you can't invert a non-square matrix\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC || \n                                matrix_exp<EXP>::NR == 0 ||\n                                matrix_exp<EXP>::NC == 0);\n            DLIB_ASSERT(m.nr() == m.nc(), \n                \"\\tconst matrix_exp::type inv(const matrix_exp& m)\"\n                << \"\\n\\tYou can only apply inv() to a square matrix\"\n                << \"\\n\\tm.nr(): \" << m.nr()\n                << \"\\n\\tm.nc(): \" << m.nc() \n                );\n            typedef typename matrix_exp<EXP>::type type;\n\n            lu_decomposition<EXP> lu(m);\n            return lu.solve(identity_matrix<type>(m.nr()));\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct inv_helper<EXP,1>\n    {\n        static const typename matrix_exp<EXP>::matrix_type inv (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            matrix<type, 1, 1, typename EXP::mem_manager_type> a;\n            // if m is invertible\n            if (m(0) != 0)\n                a(0) = 1/m(0);\n            else\n                a(0) = 1;\n            return a;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct inv_helper<EXP,2>\n    {\n        static const typename matrix_exp<EXP>::matrix_type inv (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            matrix<type, 2, 2, typename EXP::mem_manager_type> a;\n            type d = det(m);\n            if (d != 0)\n            {\n                d = static_cast<type>(1.0/d);\n                a(0,0) = m(1,1)*d;\n                a(0,1) = m(0,1)*-d;\n                a(1,0) = m(1,0)*-d;\n                a(1,1) = m(0,0)*d;\n            }\n            else\n            {\n                // Matrix isn't invertible so just return the identity matrix.\n                a = identity_matrix<type,2>();\n            }\n            return a;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct inv_helper<EXP,3>\n    {\n        static const typename matrix_exp<EXP>::matrix_type inv (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            matrix<type, 3, 3, typename EXP::mem_manager_type> ret;\n            type de = det(m);\n            if (de != 0)\n            {\n                de = static_cast<type>(1.0/de);\n                const type a = m(0,0);\n                const type b = m(0,1);\n                const type c = m(0,2);\n                const type d = m(1,0);\n                const type e = m(1,1);\n                const type f = m(1,2);\n                const type g = m(2,0);\n                const type h = m(2,1);\n                const type i = m(2,2);\n\n                ret(0,0) = (e*i - f*h)*de;\n                ret(1,0) = (f*g - d*i)*de;\n                ret(2,0) = (d*h - e*g)*de;\n\n                ret(0,1) = (c*h - b*i)*de;\n                ret(1,1) = (a*i - c*g)*de;\n                ret(2,1) = (b*g - a*h)*de;\n\n                ret(0,2) = (b*f - c*e)*de;\n                ret(1,2) = (c*d - a*f)*de;\n                ret(2,2) = (a*e - b*d)*de;\n            }\n            else\n            {\n                ret = identity_matrix<type,3>();\n            }\n\n            return ret;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct inv_helper<EXP,4>\n    {\n        static const typename matrix_exp<EXP>::matrix_type inv (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            matrix<type, 4, 4, typename EXP::mem_manager_type> ret;\n            type de = det(m);\n            if (de != 0)\n            {\n                de = static_cast<type>(1.0/de);\n                ret(0,0) =  det(removerc<0,0>(m));\n                ret(0,1) = -det(removerc<0,1>(m));\n                ret(0,2) =  det(removerc<0,2>(m));\n                ret(0,3) = -det(removerc<0,3>(m));\n\n                ret(1,0) = -det(removerc<1,0>(m));\n                ret(1,1) =  det(removerc<1,1>(m));\n                ret(1,2) = -det(removerc<1,2>(m));\n                ret(1,3) =  det(removerc<1,3>(m));\n\n                ret(2,0) =  det(removerc<2,0>(m));\n                ret(2,1) = -det(removerc<2,1>(m));\n                ret(2,2) =  det(removerc<2,2>(m));\n                ret(2,3) = -det(removerc<2,3>(m));\n\n                ret(3,0) = -det(removerc<3,0>(m));\n                ret(3,1) =  det(removerc<3,1>(m));\n                ret(3,2) = -det(removerc<3,2>(m));\n                ret(3,3) =  det(removerc<3,3>(m));\n\n                return trans(ret)*de;\n            }\n            else\n            {\n                return identity_matrix<type,4>();\n            }\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    inline const typename matrix_exp<EXP>::matrix_type inv (\n        const matrix_exp<EXP>& m\n    ) { return inv_helper<EXP,matrix_exp<EXP>::NR>::inv(m); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_diag_inv\n    {\n        template <typename EXP>\n        op_diag_inv( const matrix_exp<EXP>& m_) : m(m_){}\n\n\n        const static long cost = 1;\n        const static long NR = ((M::NC!=0)&&(M::NR!=0))? (tmax<M::NR,M::NC>::value) : (0);\n        const static long NC = NR;\n        typedef typename M::type type;\n        typedef const type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n\n        // hold the matrix by value\n        const matrix<type,NR,1,mem_manager_type,layout_type> m;\n\n        const_ret_type apply ( long r, long c) const \n        { \n            if (r==c)\n                return m(r);\n            else\n                return 0;\n        }\n\n        long nr () const { return m.size(); }\n        long nc () const { return m.size(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_diag_op<op_diag_inv<EXP> > inv (\n        const matrix_diag_exp<EXP>& m\n    ) \n    { \n        typedef op_diag_inv<EXP> op;\n        return matrix_diag_op<op>(op(reciprocal(diag(m))));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_diag_op<op_diag_inv<EXP> > pinv (\n        const matrix_diag_exp<EXP>& m\n    ) \n    { \n        typedef op_diag_inv<EXP> op;\n        return matrix_diag_op<op>(op(reciprocal(diag(m))));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_diag_op<op_diag_inv<EXP> > pinv (\n        const matrix_diag_exp<EXP>& m,\n        double tol\n    ) \n    { \n        DLIB_ASSERT(tol >= 0, \n            \"\\tconst matrix_exp::type pinv(const matrix_exp& m)\"\n            << \"\\n\\t tol can't be negative\"\n            << \"\\n\\t tol: \"<<tol \n            );\n        typedef op_diag_inv<EXP> op;\n        return matrix_diag_op<op>(op(reciprocal(round_zeros(diag(m),tol))));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    const typename matrix_exp<EXP>::matrix_type  inv_lower_triangular (\n        const matrix_exp<EXP>& A \n    )\n    {\n        DLIB_ASSERT(A.nr() == A.nc(), \n            \"\\tconst matrix inv_lower_triangular(const matrix_exp& A)\"\n            << \"\\n\\tA must be a square matrix\"\n            << \"\\n\\tA.nr(): \" << A.nr()\n            << \"\\n\\tA.nc(): \" << A.nc() \n            );\n\n        typedef typename matrix_exp<EXP>::matrix_type matrix_type;\n\n        matrix_type m(A);\n\n        for(long c = 0; c < m.nc(); ++c)\n        {\n            if( m(c,c) == 0 )\n            {\n                // there isn't an inverse so just give up\n                return m;\n            }\n\n            // compute m(c,c)\n            m(c,c) = 1/m(c,c);\n\n            // compute the values in column c that are below m(c,c).\n            // We do this by just doing the same thing we do for upper triangular\n            // matrices because we take the transpose of m which turns m into an\n            // upper triangular matrix.\n            for(long r = 0; r < c; ++r)\n            {\n                const long n = c-r;\n                m(c,r) = -m(c,c)*subm(trans(m),r,r,1,n)*subm(trans(m),r,c,n,1);\n            }\n        }\n\n        return m;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    const typename matrix_exp<EXP>::matrix_type  inv_upper_triangular (\n        const matrix_exp<EXP>& A \n    )\n    {\n        DLIB_ASSERT(A.nr() == A.nc(), \n            \"\\tconst matrix inv_upper_triangular(const matrix_exp& A)\"\n            << \"\\n\\tA must be a square matrix\"\n            << \"\\n\\tA.nr(): \" << A.nr()\n            << \"\\n\\tA.nc(): \" << A.nc() \n            );\n\n        typedef typename matrix_exp<EXP>::matrix_type matrix_type;\n\n        matrix_type m(A);\n\n        for(long c = 0; c < m.nc(); ++c)\n        {\n            if( m(c,c) == 0 )\n            {\n                // there isn't an inverse so just give up\n                return m;\n            }\n\n            // compute m(c,c)\n            m(c,c) = 1/m(c,c);\n\n            // compute the values in column c that are above m(c,c)\n            for(long r = 0; r < c; ++r)\n            {\n                const long n = c-r;\n                m(r,c) = -m(c,c)*subm(m,r,r,1,n)*subm(m,r,c,n,1);\n            }\n        }\n\n        return m;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    inline const typename matrix_exp<EXP>::matrix_type chol (\n        const matrix_exp<EXP>& A\n    )\n    {\n        DLIB_ASSERT(A.nr() == A.nc(), \n            \"\\tconst matrix chol(const matrix_exp& A)\"\n            << \"\\n\\tYou can only apply the chol to a square matrix\"\n            << \"\\n\\tA.nr(): \" << A.nr()\n            << \"\\n\\tA.nc(): \" << A.nc() \n            );\n        typename matrix_exp<EXP>::matrix_type L(A.nr(),A.nc());\n\n        typedef typename EXP::type T;\n\n        bool banded = false;\n        long bandwidth = 0;\n\n        if (A.nr() > 4) // Only test for banded matrix if matrix is big enough\n        {\n            // Detect if matrix is banded and, if so, matrix bandwidth\n            banded = true;\n            for (long r = 0; r < A.nr(); ++r)\n                for (long c = (r + bandwidth + 1); c < A.nc(); ++c)\n                    if (A(r, c) != 0)\n                    {\n                        bandwidth = c - r;\n                        if (bandwidth > A.nr() / 2)\n                        {\n                            banded = false;\n                            goto escape_banded_detection;\n                        }\n                    }\n        }\nescape_banded_detection:\n\n        if (banded)\n        {\n            // Store in compact form - use column major for LAPACK\n            matrix<T,0,0,default_memory_manager,column_major_layout> B(bandwidth + 1, A.nc());\n            set_all_elements(B, 0);\n\n            for (long r = 0; r < A.nr(); ++r)\n                for (long c = r; c < std::min(r + bandwidth + 1, A.nc()); ++c)\n                    B(c - r, r) = A(r, c);\n\n#ifdef DLIB_USE_LAPACK \n\n            lapack::pbtrf('L', B);\n\n#else\n\n            // Perform compact Cholesky\n            for (long k = 0; k < A.nr(); ++k)\n            {\n                long last = std::min(k + bandwidth, A.nr() - 1) - k;\n                for (long j = 1; j <= last; ++j)\n                {\n                    long i = k + j;\n                    for (long c = 0; c <= (last - j); ++c)\n                        B(c, i) -= B(j, k) / B(0, k) * B(c + j, k);\n                }\n                T norm = std::sqrt(B(0, k));\n                for (long i = 0; i <= bandwidth; ++i)\n                    B(i, k) /= norm;\n            }\n            for (long c = A.nc() - bandwidth + 1; c < A.nc(); ++c)\n                B(bandwidth, c) = 0;\n\n#endif\n\n            // Unpack lower triangular area\n            set_all_elements(L, 0);\n            for (long c = 0; c < A.nc(); ++c)\n                for (long i = 0; i <= bandwidth; ++i)\n                {\n                    long ind = c + i;\n                    if (ind < A.nc())\n                        L(ind, c) = B(i, c);\n                }\n\n            return L;\n        }\n\n#ifdef DLIB_USE_LAPACK        \n        // Only call LAPACK if the matrix is big enough.  Otherwise,\n        // our own code is faster, especially for statically dimensioned \n        // matrices.\n        if (A.nr() > 4)\n        {\n            L = A;\n            lapack::potrf('L', L);\n            // mask out upper triangular area\n            return lowerm(L);\n        }\n#endif\n        set_all_elements(L,0);\n\n        // do nothing if the matrix is empty\n        if (A.size() == 0)\n            return L;\n\n        const T eps = std::numeric_limits<T>::epsilon();\n\n        // compute the upper left corner\n        if (A(0,0) > 0)\n            L(0,0) = std::sqrt(A(0,0));\n\n        // compute the first column\n        for (long r = 1; r < A.nr(); ++r)\n        {\n            // if (L(0,0) > 0)\n            if (L(0,0) > eps*std::abs(A(r,0)))\n                L(r,0) = A(r,0)/L(0,0);\n            else\n                return L;\n        }\n\n        // now compute all the other columns\n        for (long c = 1; c < A.nc(); ++c)\n        {\n            // compute the diagonal element\n            T temp = A(c,c);\n            for (long i = 0; i < c; ++i)\n            {\n                temp -= L(c,i)*L(c,i);\n            }\n            if (temp > 0)\n                L(c,c) = std::sqrt(temp);\n\n            // compute the non diagonal elements\n            for (long r = c+1; r < A.nr(); ++r)\n            {\n                temp = A(r,c);\n                for (long i = 0; i < c; ++i)\n                {\n                    temp -= L(r,i)*L(c,i);\n                }\n\n                // if (L(c,c) > 0)\n                if (L(c,c) > eps*std::abs(temp))\n                    L(r,c) = temp/L(c,c);\n                else\n                    return L;\n            }\n        }\n\n        return L;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        long uNR, \n        long uNC,\n        long wN, \n        long vN,\n        long wX,\n        typename MM1,\n        typename MM2,\n        typename MM3,\n        typename L1\n        >\n    inline void svd3 (\n        const matrix_exp<EXP>& m,\n        matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1>& u,\n        matrix<typename matrix_exp<EXP>::type, wN, wX,MM2,L1>& w,\n        matrix<typename matrix_exp<EXP>::type, vN, vN,MM3,L1>& v\n    )\n    {\n        typedef typename matrix_exp<EXP>::type T;\n        const long NR = matrix_exp<EXP>::NR;\n        const long NC = matrix_exp<EXP>::NC;\n\n        // make sure the output matrices have valid dimensions if they are statically dimensioned\n        COMPILE_TIME_ASSERT(NR == 0 || uNR == 0 || NR == uNR);\n        COMPILE_TIME_ASSERT(NC == 0 || uNC == 0 || NC == uNC);\n        COMPILE_TIME_ASSERT(NC == 0 || wN == 0 || NC == wN);\n        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);\n        COMPILE_TIME_ASSERT(wX == 0 || wX == 1);\n\n#ifdef DLIB_USE_LAPACK\n        // use LAPACK but only if it isn't a really small matrix we are taking the SVD of.\n        if (NR*NC == 0 || NR*NC > 3*3)\n        {\n            matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1> temp(m);\n            lapack::gesvd('S','A', temp, w, u, v);\n            v = trans(v);\n            // if u isn't the size we want then pad it (and v) with zeros\n            if (u.nc() < m.nc())\n            {\n                w = join_cols(w, zeros_matrix<T>(m.nc()-u.nc(),1));\n                u = join_rows(u, zeros_matrix<T>(u.nr(), m.nc()-u.nc()));\n            }\n            return;\n        }\n#endif\n        if (m.nr() >= m.nc())\n        {\n            svd4(SVD_SKINNY_U,true, m, u,w,v);\n        }\n        else\n        {\n            svd4(SVD_FULL_U,true, trans(m), v,w,u);\n\n            // if u isn't the size we want then pad it (and v) with zeros\n            if (u.nc() < m.nc())\n            {\n                w = join_cols(w, zeros_matrix<T>(m.nc()-u.nc(),1));\n                u = join_rows(u, zeros_matrix<T>(u.nr(), m.nc()-u.nc()));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix<typename EXP::type,EXP::NC,EXP::NR,typename EXP::mem_manager_type> pinv_helper ( \n        const matrix_exp<EXP>& m,\n        double tol\n    )\n    /*!\n        ensures\n            - computes the results of pinv(m) but does so using a method that is fastest\n              when m.nc() <= m.nr().  So if m.nc() > m.nr() then it is best to use\n              trans(pinv_helper(trans(m))) to compute pinv(m).\n    !*/\n    { \n        typename matrix_exp<EXP>::matrix_type u;\n        typedef typename EXP::mem_manager_type MM1;\n        typedef typename EXP::layout_type layout_type;\n        matrix<typename EXP::type, EXP::NC, EXP::NC,MM1, layout_type > v;\n\n        typedef typename matrix_exp<EXP>::type T;\n\n        matrix<T,matrix_exp<EXP>::NC,1,MM1, layout_type> w;\n\n        svd3(m, u,w,v);\n\n        const double machine_eps = std::numeric_limits<typename EXP::type>::epsilon();\n        // compute a reasonable epsilon below which we round to zero before doing the\n        // reciprocal.  Unless a non-zero tol is given then we just use tol*max(w).\n        const double eps = (tol!=0) ? tol*max(w) :  machine_eps*std::max(m.nr(),m.nc())*max(w);\n\n        // now compute the pseudoinverse\n        return tmp(scale_columns(v,reciprocal(round_zeros(w,eps))))*trans(u);\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix<typename EXP::type,EXP::NC,EXP::NR,typename EXP::mem_manager_type> pinv ( \n        const matrix_exp<EXP>& m,\n        double tol = 0\n    )\n    { \n        DLIB_ASSERT(tol >= 0, \n            \"\\tconst matrix_exp::type pinv(const matrix_exp& m)\"\n            << \"\\n\\t tol can't be negative\"\n            << \"\\n\\t tol: \"<<tol \n            );\n        // if m has more columns then rows then it is more efficient to\n        // compute the pseudo-inverse of its transpose (given the way I'm doing it below).\n        if (m.nc() > m.nr())\n            return trans(pinv_helper(trans(m),tol));\n        else\n            return pinv_helper(m,tol);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        long uNR, \n        long uNC,\n        long wN, \n        long vN,\n        typename MM1,\n        typename MM2,\n        typename MM3,\n        typename L1\n        >\n    inline void svd (\n        const matrix_exp<EXP>& m,\n        matrix<typename matrix_exp<EXP>::type, uNR, uNC,MM1,L1>& u,\n        matrix<typename matrix_exp<EXP>::type, wN, wN,MM2,L1>& w,\n        matrix<typename matrix_exp<EXP>::type, vN, vN,MM3,L1>& v\n    )\n    {\n        typedef typename matrix_exp<EXP>::type T;\n        const long NR = matrix_exp<EXP>::NR;\n        const long NC = matrix_exp<EXP>::NC;\n\n        // make sure the output matrices have valid dimensions if they are statically dimensioned\n        COMPILE_TIME_ASSERT(NR == 0 || uNR == 0 || NR == uNR);\n        COMPILE_TIME_ASSERT(NC == 0 || uNC == 0 || NC == uNC);\n        COMPILE_TIME_ASSERT(NC == 0 || wN == 0 || NC == wN);\n        COMPILE_TIME_ASSERT(NC == 0 || vN == 0 || NC == vN);\n\n        matrix<T,matrix_exp<EXP>::NC,1,MM1, L1> W;\n        svd3(m,u,W,v);\n        w = diagm(W);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type trace (\n        const matrix_exp<EXP>& m\n    ) \n    { \n        COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC ||\n                            matrix_exp<EXP>::NR == 0 ||\n                            matrix_exp<EXP>::NC == 0 \n                            );\n        DLIB_ASSERT(m.nr() == m.nc(), \n            \"\\tconst matrix_exp::type trace(const matrix_exp& m)\"\n            << \"\\n\\tYou can only apply trace() to a square matrix\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            );\n        return sum(diag(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        long N = EXP::NR\n        >\n    struct det_helper\n    {\n        static const typename matrix_exp<EXP>::type det (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC ||\n                                matrix_exp<EXP>::NR == 0 ||\n                                matrix_exp<EXP>::NC == 0 \n                                );\n            DLIB_ASSERT(m.nr() == m.nc(), \n                \"\\tconst matrix_exp::type det(const matrix_exp& m)\"\n                << \"\\n\\tYou can only apply det() to a square matrix\"\n                << \"\\n\\tm.nr(): \" << m.nr()\n                << \"\\n\\tm.nc(): \" << m.nc() \n                );\n\n            return lu_decomposition<EXP>(m).det();\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct det_helper<EXP,1>\n    {\n        static const typename matrix_exp<EXP>::type det (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n\n            return m(0);\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct det_helper<EXP,2>\n    {\n        static const typename matrix_exp<EXP>::type det (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n\n            return m(0,0)*m(1,1) - m(0,1)*m(1,0);\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    struct det_helper<EXP,3>\n    {\n        static const typename matrix_exp<EXP>::type det (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            type temp = m(0,0)*(m(1,1)*m(2,2) - m(1,2)*m(2,1)) -\n                        m(0,1)*(m(1,0)*m(2,2) - m(1,2)*m(2,0)) +\n                        m(0,2)*(m(1,0)*m(2,1) - m(1,1)*m(2,0));\n            return temp;\n        }\n    };\n\n\n    template <\n        typename EXP\n        >\n    inline const typename matrix_exp<EXP>::type det (\n        const matrix_exp<EXP>& m\n    ) { return det_helper<EXP>::det(m); }\n\n\n    template <\n        typename EXP\n        >\n    struct det_helper<EXP,4>\n    {\n        static const typename matrix_exp<EXP>::type det (\n            const matrix_exp<EXP>& m\n        )\n        {\n            COMPILE_TIME_ASSERT(matrix_exp<EXP>::NR == matrix_exp<EXP>::NC);\n            typedef typename matrix_exp<EXP>::type type;\n\n            type temp = m(0,0)*(dlib::det(removerc<0,0>(m))) -\n                        m(0,1)*(dlib::det(removerc<0,1>(m))) +\n                        m(0,2)*(dlib::det(removerc<0,2>(m))) -\n                        m(0,3)*(dlib::det(removerc<0,3>(m)));\n            return temp;\n        }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    const matrix<typename EXP::type, EXP::NR, 1, typename EXP::mem_manager_type, typename EXP::layout_type> real_eigenvalues (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // You can only use this function with matrices that contain float or double values\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP::type, float>::value ||\n                             is_same_type<typename EXP::type, double>::value));\n\n        DLIB_ASSERT(m.nr() == m.nc(), \n            \"\\tconst matrix real_eigenvalues()\"\n            << \"\\n\\tYou have given an invalidly sized matrix\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            );\n\n        if (m.nr() == 2)\n        {\n            typedef typename EXP::type T;\n            const T m00 = m(0,0);\n            const T m01 = m(0,1);\n            const T m10 = m(1,0);\n            const T m11 = m(1,1);\n\n            const T b = -(m00 + m11);\n            const T c = m00*m11 - m01*m10;\n            matrix<T,EXP::NR,1, typename EXP::mem_manager_type, typename EXP::layout_type> v(2);\n\n\n            T disc = b*b - 4*c;\n            if (disc >= 0)\n                disc = std::sqrt(disc);\n            else\n                disc = 0;\n\n            v(0) = (-b + disc)/2;\n            v(1) = (-b - disc)/2;\n            return v;\n        }\n        else\n        {\n            // Call .ref() so that the symmetric matrix overload can take effect if m \n            // has the appropriate type.\n            return eigenvalue_decomposition<EXP>(m.ref()).get_real_eigenvalues();\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP \n        >\n    dlib::vector<double,2> max_point_interpolated (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\tdlib::vector<double,2> point max_point_interpolated(const matrix_exp& m)\"\n            << \"\\n\\tm can't be empty\"\n            << \"\\n\\tm.size():   \" << m.size() \n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        const point p = max_point(m);\n\n        // If this is a column vector then just do interpolation along a line.\n        if (m.nc()==1)\n        {\n            const long pos = p.y();\n            if (0 < pos && pos+1 < m.nr())\n            {\n                double v1 = dlib::impl::magnitude(m(pos-1));\n                double v2 = dlib::impl::magnitude(m(pos));\n                double v3 = dlib::impl::magnitude(m(pos+1));\n                double y = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3);\n                return vector<double,2>(0,y);\n            }\n        }\n        // If this is a row vector then just do interpolation along a line.\n        if (m.nr()==1)\n        {\n            const long pos = p.x();\n            if (0 < pos && pos+1 < m.nc())\n            {\n                double v1 = dlib::impl::magnitude(m(pos-1));\n                double v2 = dlib::impl::magnitude(m(pos));\n                double v3 = dlib::impl::magnitude(m(pos+1));\n                double x = lagrange_poly_min_extrap(pos-1,pos,pos+1, -v1, -v2, -v3);\n                return vector<double,2>(x,0);\n            }\n        }\n\n\n        // If it's on the border then just return the regular max point.\n        if (shrink_rect(get_rect(m),1).contains(p) == false)\n            return p;\n\n        //matrix<double> A(9,6);\n        //matrix<double,0,1> G(9);\n\n        matrix<double,9,1> pix;\n        long i = 0;\n        for (long r = -1; r <= +1; ++r)\n        {\n            for (long c = -1; c <= +1; ++c)\n            {\n                pix(i) = dlib::impl::magnitude(m(p.y()+r,p.y()+c));\n                /*\n                A(i,0) = c*c;\n                A(i,1) = c*r;\n                A(i,2) = r*r;\n                A(i,3) = c;\n                A(i,4) = r;\n                A(i,5) = 1;\n                G(i) = std::exp(-1*(r*r+c*c)/2.0); // Use a gaussian windowing function around p.\n                */\n                ++i;\n            }\n        }\n\n        // This bit of code is how we generated the derivative_filters matrix below.  \n        //A = diagm(G)*A; \n        //std::cout << std::setprecision(20) << inv(trans(A)*A)*trans(A)*diagm(G) << std::endl; exit(1);\n\n        const double m10 = 0.10597077880854270659;\n        const double m21 = 0.21194155761708535768;\n        const double m28 = 0.28805844238291455905;\n        const double m57 = 0.57611688476582878504;\n        // So this derivative_filters finds the parameters of the quadratic surface that best fits\n        // the 3x3 region around p.  Then we find the maximizer of that surface within that\n        // small region and return that as the maximum location.\n        const double derivative_filters[] = {\n                // xx\n                m10,-m21,m10,\n                m28,-m57,m28,\n                m10,-m21,m10,\n\n                // xy\n                0.25 ,0,-0.25,\n                0    ,0, 0,\n                -0.25,0,0.25,\n\n                // yy\n                m10,  m28, m10,\n                -m21,-m57,-m21,\n                m10,  m28, m10,\n\n                // x\n                -m10,0,m10,\n                -m28,0,m28,\n                -m10,0,m10,\n\n                // y\n                -m10,-m28,-m10,\n                0,   0,   0,\n                m10, m28, m10\n            };\n        const matrix<double,5,9> filt(derivative_filters);\n        // Now w contains the parameters of the quadratic surface\n        const matrix<double,5,1> w = filt*pix;\n\n\n        // Now newton step to the max point on the surface\n        matrix<double,2,2> H;\n        matrix<double,2,1> g;\n        H = 2*w(0), w(1),\n              w(1), 2*w(2);\n        g = w(3), \n            w(4);\n        const dlib::vector<double,2> delta = -inv(H)*g;\n\n        // if delta isn't in an ascent direction then just use the normal max point.\n        if (dot(delta, g) < 0)\n            return p;\n        else\n            return vector<double,2>(p)+dlib::clamp(delta, -1, 1);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_LA_FUNCTS_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_la_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_LA_FUNCTS_ABSTRACT_\n#ifdef DLIB_MATRIx_LA_FUNCTS_ABSTRACT_ \n\n#include \"matrix_abstract.h\"\n#include <complex>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                             Global linear algebra functions \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::matrix_type inv (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m is a square matrix\n        ensures\n            - returns the inverse of m \n              (Note that if m is singular or so close to being singular that there\n              is a lot of numerical error then the returned matrix will be bogus.  \n              You can check by seeing if m*inv(m) is an identity matrix)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix pinv (\n        const matrix_exp& m,\n        double tol = 0\n    );\n    /*!\n        requires\n            - tol >= 0\n        ensures\n            - returns the Moore-Penrose pseudoinverse of m.\n            - The returned matrix has m.nc() rows and m.nr() columns.\n            - if (tol == 0) then\n                - singular values less than max(m.nr(),m.nc()) times the machine epsilon \n                  times the largest singular value are ignored.  \n            - else\n                - singular values less than tol*max(singular value in m) are ignored.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void svd (\n        const matrix_exp& m,\n        matrix<matrix_exp::type>& u,\n        matrix<matrix_exp::type>& w,\n        matrix<matrix_exp::type>& v\n    );\n    /*!\n        ensures\n            - computes the singular value decomposition of m\n            - m == #u*#w*trans(#v)\n            - trans(#u)*#u == identity matrix\n            - trans(#v)*#v == identity matrix\n            - diag(#w) == the singular values of the matrix m in no \n              particular order.  All non-diagonal elements of #w are\n              set to 0.\n            - #u.nr() == m.nr()\n            - #u.nc() == m.nc()\n            - #w.nr() == m.nc()\n            - #w.nc() == m.nc()\n            - #v.nr() == m.nc()\n            - #v.nc() == m.nc()\n            - if DLIB_USE_LAPACK is #defined then the xGESVD routine\n              from LAPACK is used to compute the SVD.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    long svd2 (\n        bool withu, \n        bool withv, \n        const matrix_exp& m,\n        matrix<matrix_exp::type>& u,\n        matrix<matrix_exp::type>& w,\n        matrix<matrix_exp::type>& v\n    );\n    /*!\n        requires\n            - m.nr() >= m.nc()\n        ensures\n            - computes the singular value decomposition of matrix m\n            - m == subm(#u,get_rect(m))*diagm(#w)*trans(#v)\n            - trans(#u)*#u == identity matrix\n            - trans(#v)*#v == identity matrix\n            - #w == the singular values of the matrix m in no \n              particular order.  \n            - #u.nr() == m.nr()\n            - #u.nc() == m.nr()\n            - #w.nr() == m.nc()\n            - #w.nc() == 1 \n            - #v.nr() == m.nc()\n            - #v.nc() == m.nc()\n            - if (widthu == false) then\n                - ignore the above regarding #u, it isn't computed and its\n                  output state is undefined.\n            - if (widthv == false) then\n                - ignore the above regarding #v, it isn't computed and its\n                  output state is undefined.\n            - returns an error code of 0, if no errors and 'k' if we fail to\n              converge at the 'kth' singular value.\n            - if (DLIB_USE_LAPACK is #defined) then \n                - if (withu == withv) then\n                    - the xGESDD routine from LAPACK is used to compute the SVD.\n                - else\n                    - the xGESVD routine from LAPACK is used to compute the SVD.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void svd3 (\n        const matrix_exp& m,\n        matrix<matrix_exp::type>& u,\n        matrix<matrix_exp::type>& w,\n        matrix<matrix_exp::type>& v\n    );\n    /*!\n        ensures\n            - computes the singular value decomposition of m\n            - m == #u*diagm(#w)*trans(#v)\n            - trans(#u)*#u == identity matrix\n            - trans(#v)*#v == identity matrix\n            - #w == the singular values of the matrix m in no \n              particular order.  \n            - #u.nr() == m.nr()\n            - #u.nc() == m.nc()\n            - #w.nr() == m.nc()\n            - #w.nc() == 1 \n            - #v.nr() == m.nc()\n            - #v.nc() == m.nc()\n            - if DLIB_USE_LAPACK is #defined then the xGESVD routine\n              from LAPACK is used to compute the SVD.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void svd_fast (\n        const matrix<T>& A,\n        matrix<T>& u,\n        matrix<T>& w,\n        matrix<T>& v,\n        unsigned long l,\n        unsigned long q = 1\n    );\n    /*!\n        requires\n            - l > 0\n            - A.size() > 0 \n              (i.e. A can't be an empty matrix)\n        ensures\n            - computes the singular value decomposition of A.  \n            - Lets define some constants we use to document the behavior of svd_fast():\n                - Let m = A.nr()\n                - Let n = A.nc() \n                - Let k = min(l, min(m,n))\n                - Therefore, A represents an m by n matrix and svd_fast() is designed\n                  to find a rank-k representation of it.\n            - if (the rank of A is <= k) then \n                - A == #u*diagm(#w)*trans(#v)\n            - else\n                - A is approximated by #u*diagm(#w)*trans(#v)\n                  (i.e. In this case A can't be represented with a rank-k matrix, so the\n                  matrix you get by trying to reconstruct A from the output of the SVD is\n                  not exactly the same.)\n            - trans(#u)*#u == identity matrix\n            - trans(#v)*#v == identity matrix\n            - #w == the top k singular values of the matrix A (in no particular order).  \n            - #u.nr() == m \n            - #u.nc() == k \n            - #w.nr() == k \n            - #w.nc() == 1 \n            - #v.nr() == n \n            - #v.nc() == k \n            - This function implements the randomized subspace iteration defined in the\n              algorithm 4.4 and 5.1 boxes of the paper: \n                Finding Structure with Randomness: Probabilistic Algorithms for\n                Constructing Approximate Matrix Decompositions by Halko et al.\n              Therefore, it is very fast and suitable for use with very large matrices.\n              Moreover, q is the number of subspace iterations performed.  Larger\n              values of q might increase the accuracy of the solution but the default\n              value should be good for many problems.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename sparse_vector_type, \n        typename T\n        >\n    void svd_fast (\n        const std::vector<sparse_vector_type>& A,\n        matrix<T>& u,\n        matrix<T>& w,\n        matrix<T>& v,\n        unsigned long l,\n        unsigned long q = 1\n    );\n    /*!\n        requires\n            - A contains a set of sparse vectors.  See dlib/svm/sparse_vector_abstract.h\n              for a definition of what constitutes a sparse vector.\n            - l > 0\n            - max_index_plus_one(A) > 0\n              (i.e. A can't be an empty matrix)\n        ensures\n            - computes the singular value decomposition of A.  In this case, we interpret A\n              as a matrix of A.size() rows, where each row is defined by a sparse vector.\n            - Lets define some constants we use to document the behavior of svd_fast():\n                - Let m = A.size()\n                - Let n = max_index_plus_one(A)\n                - Let k = min(l, min(m,n))\n                - Therefore, A represents an m by n matrix and svd_fast() is designed\n                  to find a rank-k representation of it.\n            - if (the rank of A is <= k) then \n                - A == #u*diagm(#w)*trans(#v)\n            - else\n                - A is approximated by #u*diagm(#w)*trans(#v)\n                  (i.e. In this case A can't be represented with a rank-k matrix, so the\n                  matrix you get by trying to reconstruct A from the output of the SVD is\n                  not exactly the same.)\n            - trans(#u)*#u == identity matrix\n            - trans(#v)*#v == identity matrix\n            - #w == the top k singular values of the matrix A (in no particular order).  \n            - #u.nr() == m \n            - #u.nc() == k \n            - #w.nr() == k \n            - #w.nc() == 1 \n            - #v.nr() == n \n            - #v.nc() == k \n            - This function implements the randomized subspace iteration defined in the\n              algorithm 4.4 and 5.1 boxes of the paper: \n                Finding Structure with Randomness: Probabilistic Algorithms for\n                Constructing Approximate Matrix Decompositions by Halko et al.\n              Therefore, it is very fast and suitable for use with very large matrices.\n              Moreover, q is the number of subspace iterations performed.  Larger\n              values of q might increase the accuracy of the solution but the default\n              value should be good for many problems.\n    !*/\n\n    template <\n        typename sparse_vector_type, \n        typename T\n        >\n    void svd_fast (\n        const std::vector<sparse_vector_type>& A,\n        matrix<T>& w,\n        matrix<T>& v,\n        unsigned long l,\n        unsigned long q = 1\n    );\n    /*!\n        This function is identical to the above svd_fast() except it doesn't compute u.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM,\n        typename L\n        >\n    void orthogonalize (\n        matrix<T,NR,NC,MM,L>& m\n    );\n    /*!\n        requires\n            - m.nr() >= m.nc()\n            - m.size() > 0\n        ensures\n            - #m == an orthogonal matrix with the same dimensions as m.  In particular,\n              the columns of #m have the same span as the columns of m.\n            - trans(#m)*#m == identity matrix\n            - This function is just shorthand for computing the QR decomposition of m\n              and then storing the Q factor into #m.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix real_eigenvalues (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.nr() == m.nc()\n            - matrix_exp::type == float or double\n        ensures\n            - returns a matrix E such that:\n                - E.nr() == m.nr()\n                - E.nc() == 1\n                - E contains the real part of all eigenvalues of the matrix m.\n                  (note that the eigenvalues are not sorted)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type det (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m is a square matrix\n        ensures\n            - returns the determinant of m\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type trace (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m is a square matrix\n        ensures\n            - returns the trace of m\n              (i.e. returns sum(diag(m)))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::matrix_type chol (\n        const matrix_exp& A\n    );\n    /*!\n        requires\n            - A is a square matrix\n        ensures\n            - if (A has a Cholesky Decomposition) then\n                - returns the decomposition of A.  That is, returns a matrix L\n                  such that L*trans(L) == A.  L will also be lower triangular.\n            - else\n                - returns a matrix with the same dimensions as A but it \n                  will have a bogus value.  I.e. it won't be a decomposition.\n                  In this case the algorithm returns a partial decomposition.\n                - You can tell when chol fails by looking at the lower right\n                  element of the returned matrix.  If it is 0 then it means\n                  A does not have a cholesky decomposition.  \n\n            - If DLIB_USE_LAPACK is defined then the LAPACK routine xPOTRF \n              is used to compute the cholesky decomposition.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::matrix_type inv_lower_triangular (\n        const matrix_exp& A\n    );\n    /*!\n        requires\n            - A is a square matrix\n        ensures\n            - if (A is lower triangular) then\n                - returns the inverse of A. \n            - else\n                - returns a matrix with the same dimensions as A but it \n                  will have a bogus value.  I.e. it won't be an inverse.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::matrix_type inv_upper_triangular (\n        const matrix_exp& A\n    );\n    /*!\n        requires\n            - A is a square matrix\n        ensures\n            - if (A is upper triangular) then\n                - returns the inverse of A. \n            - else\n                - returns a matrix with the same dimensions as A but it \n                  will have a bogus value.  I.e. it won't be an inverse.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                             Matrix decomposition classes \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_exp_type\n        >\n    class lu_decomposition\n    {\n        /*!\n            REQUIREMENTS ON matrix_exp_type\n                must be some kind of matrix expression as defined in the \n                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)\n                The matrix type must also contain float or double values.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents something that can compute an LU \n                decomposition of a real valued matrix.  That is, for any \n                matrix A it computes matrices L, U, and a pivot vector P such \n                that rowm(A,P) == L*U.\n\n                The LU decomposition with pivoting always exists, even if the matrix is\n                singular, so the constructor will never fail.  The primary use of the\n                LU decomposition is in the solution of square systems of simultaneous\n                linear equations.  This will fail if is_singular() returns true (or\n                if A is very nearly singular).\n\n                If DLIB_USE_LAPACK is defined then the LAPACK routine xGETRF \n                is used to compute the LU decomposition.\n        !*/\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n        typedef matrix<long,NR,1,mem_manager_type,layout_type> pivot_column_vector_type;\n\n        template <typename EXP>\n        lu_decomposition (\n            const matrix_exp<EXP> &A\n        );\n        /*!\n            requires\n                - EXP::type == lu_decomposition::type \n                - A.size() > 0\n            ensures\n                - #nr() == A.nr()\n                - #nc() == A.nc()\n                - #is_square() == (A.nr() == A.nc())\n                - computes the LU factorization of the given A matrix.\n        !*/\n\n        bool is_square (\n        ) const;\n        /*!\n            ensures\n                - if (the input A matrix was a square matrix) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool is_singular (\n        ) const;\n        /*!\n            requires\n                - is_square() == true\n            ensures\n                - if (the input A matrix is singular) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        long nr(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in the input matrix\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in the input matrix\n        !*/\n\n        const matrix_type get_l (\n        ) const; \n        /*!\n            ensures\n                - returns the lower triangular L factor of the LU factorization.  \n                - L.nr() == nr()\n                - L.nc() == min(nr(),nc())\n        !*/\n\n        const matrix_type get_u (\n        ) const;\n        /*!\n            ensures\n                - returns the upper triangular U factor of the LU factorization.  \n                - U.nr() == min(nr(),nc())\n                - U.nc() == nc()\n        !*/\n\n        const pivot_column_vector_type& get_pivot (\n        ) const;\n        /*!\n            ensures\n                - returns the pivot permutation vector.  That is,\n                  if A is the input matrix then this function \n                  returns a vector P such that:\n                    - rowm(A,P) == get_l()*get_u() \n                    - P.nr() == A.nr()\n        !*/\n\n        type det (\n        ) const;\n        /*!\n            requires\n                - is_square() == true\n            ensures\n                - computes and returns the determinant of the input \n                  matrix using LU factors.\n        !*/\n\n        template <typename EXP>\n        const matrix_type solve (\n            const matrix_exp<EXP> &B\n        ) const;\n        /*!\n            requires\n                - EXP::type == lu_decomposition::type\n                - is_square() == true\n                - B.nr() == nr()\n            ensures\n                - Let A denote the input matrix to this class's constructor.  \n                  Then this function solves A*X == B for X and returns X.  \n                - Note that if A is singular (or very close to singular) then\n                  the X returned by this function won't fit A*X == B very well (if at all).\n        !*/\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_exp_type\n        >\n    class cholesky_decomposition\n    {\n        /*! \n            REQUIREMENTS ON matrix_exp_type\n                must be some kind of matrix expression as defined in the \n                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)\n                The matrix type must also contain float or double values.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents something that can compute a cholesky \n                decomposition of a real valued matrix.  That is, for any \n                symmetric, positive definite matrix A, it computes a lower \n                triangular matrix L such that A == L*trans(L).\n                \n                If the matrix is not symmetric or positive definite, the function\n                computes only a partial decomposition.  This can be tested with\n                the is_spd() flag.\n            \n                If DLIB_USE_LAPACK is defined then the LAPACK routine xPOTRF \n                is used to compute the cholesky decomposition.\n        !*/\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef typename matrix_exp_type::matrix_type matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n\n        template <typename EXP>\n        cholesky_decomposition(\n            const matrix_exp<EXP>& A\n        );\n        /*!\n            requires\n                - EXP::type == cholesky_decomposition::type \n                - A.size() > 0\n                - A.nr() == A.nc() \n                  (i.e. A must be a square matrix)\n            ensures\n                - if (A is symmetric positive-definite) then\n                    - #is_spd() == true \n                    - Constructs a lower triangular matrix L, such that L*trans(L) == A.\n                      and #get_l() == L\n                - else\n                    - #is_spd() == false\n        !*/\n\n        bool is_spd(\n        ) const;\n        /*!\n            ensures\n                - if (the input matrix was symmetric positive-definite) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        const matrix_type& get_l(\n        ) const;\n        /*!\n            ensures\n                - returns the lower triangular factor, L, such that L*trans(L) == A\n                  (where A is the input matrix to this class's constructor)\n                - Note that if A is not symmetric positive definite or positive semi-definite\n                  then the equation L*trans(L) == A won't hold.  \n        !*/\n\n        template <typename EXP>\n        const matrix solve (\n            const matrix_exp<EXP>& B\n        ) const;\n        /*!\n            requires\n                - EXP::type == cholesky_decomposition::type\n                - B.nr() == get_l().nr()\n                  (i.e. the number of rows in B must match the number of rows in the\n                  input matrix A)\n            ensures\n                - Let A denote the input matrix to this class's constructor.  Then \n                  this function solves A*X = B for X and returns X.  \n                - Note that if is_spd() == false or A was really close to being\n                  non-SPD then the solver will fail to find an accurate solution.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_exp_type\n        >\n    class qr_decomposition \n    {\n        /*! \n            REQUIREMENTS ON matrix_exp_type\n                must be some kind of matrix expression as defined in the \n                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)\n                The matrix type must also contain float or double values.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents something that can compute a classical\n                QR decomposition of an m-by-n real valued matrix A with m >= n.  \n\n                The QR decomposition is an m-by-n orthogonal matrix Q and an \n                n-by-n upper triangular matrix R so that A == Q*R. The QR decomposition \n                always exists, even if the matrix does not have full rank, so the \n                constructor will never fail.  The primary use of the QR decomposition \n                is in the least squares solution of non-square systems of simultaneous \n                linear equations.  This will fail if is_full_rank() returns false or\n                A is very nearly not full rank.\n\n                The Q and R factors can be retrieved via the get_q() and get_r()\n                methods. Furthermore, a solve() method is provided to find the\n                least squares solution of Ax=b using the QR factors.  \n\n                If DLIB_USE_LAPACK is #defined then the xGEQRF routine\n                from LAPACK is used to compute the QR decomposition.\n        !*/\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef matrix<type,0,0,mem_manager_type,layout_type> matrix_type;\n\n        template <typename EXP>\n        qr_decomposition(\n            const matrix_exp<EXP>& A\n        );\n        /*!\n            requires\n                - EXP::type == qr_decomposition::type\n                - A.nr() >= A.nc()\n                - A.size() > 0\n            ensures\n                - #nr() == A.nr()\n                - #nc() == A.nc()\n                - computes the QR decomposition of the given A matrix.\n        !*/\n\n        bool is_full_rank(\n        ) const;\n        /*!\n            ensures\n                - if (the input A matrix had full rank) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        long nr(\n        ) const;\n        /*!\n            ensures\n                - returns the number of rows in the input matrix\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in the input matrix\n        !*/\n\n        const matrix_type get_r (\n        ) const;\n        /*!\n            ensures\n                - returns a matrix R such that: \n                    - R is the upper triangular factor, R, of the QR factorization\n                    - get_q()*R == input matrix A\n                    - R.nr() == nc()\n                    - R.nc() == nc()\n        !*/\n\n        const matrix_type get_q (\n        ) const;\n        /*!\n            ensures\n                - returns a matrix Q such that:\n                    - Q is the economy-sized orthogonal factor Q from the QR \n                      factorization.  \n                    - trans(Q)*Q == identity matrix\n                    - Q*get_r() == input matrix A \n                    - Q.nr() == nr()\n                    - Q.nc() == nc()\n        !*/\n\n        void get_q (\n            matrix_type& Q\n        ) const;\n        /*!\n            ensures\n                - #Q == get_q()\n                - This function exists to allow a user to get the Q matrix without the\n                  overhead of returning a matrix by value.\n        !*/\n\n        template <typename EXP>\n        const matrix_type solve (\n            const matrix_exp<EXP>& B\n        ) const;\n        /*!\n            requires\n                - EXP::type == qr_decomposition::type\n                - B.nr() == nr()\n            ensures\n                - Let A denote the input matrix to this class's constructor.  \n                  Then this function finds the least squares solution to the equation A*X = B \n                  and returns X.  X has the following properties: \n                    - X is the matrix that minimizes the two norm of A*X-B.  That is, it\n                      minimizes sum(squared(A*X - B)).\n                    - X.nr() == nc()\n                    - X.nc() == B.nc()\n                - Note that this function will fail to output a good solution if is_full_rank() == false\n                  or the A matrix is close to not being full rank.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_exp_type\n        >\n    class eigenvalue_decomposition\n    {\n        /*!\n            REQUIREMENTS ON matrix_exp_type\n                must be some kind of matrix expression as defined in the \n                dlib/matrix/matrix_abstract.h file.   (e.g. a dlib::matrix object)\n                The matrix type must also contain float or double values.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents something that can compute an eigenvalue \n                decomposition of a real valued matrix.   So it gives \n                you the set of eigenvalues and eigenvectors for a matrix.   \n\n                Let A denote the input matrix to this object's constructor.  Then \n                what this object does is it finds two matrices, D and V, such that\n                    - A*V == V*D\n                Where V is a square matrix that contains all the eigenvectors\n                of the A matrix (each column of V is an eigenvector) and\n                D is a diagonal matrix containing the eigenvalues of A.\n\n\n                It is important to note that if A is symmetric or non-symmetric you\n                get somewhat different results.  If A is a symmetric matrix (i.e. A == trans(A))\n                then:\n                    - All the eigenvalues and eigenvectors of A are real numbers. \n                        - Because of this there isn't really any point in using the\n                          part of this class's interface that returns complex matrices.\n                          All you need are the get_real_eigenvalues() and\n                          get_pseudo_v() functions.  \n                    - V*trans(V) should be equal to the identity matrix.  That is, all the\n                      eigenvectors in V should be orthonormal. \n                        - So A == V*D*trans(V)\n                    - If DLIB_USE_LAPACK is #defined then this object uses the xSYEVR LAPACK\n                      routine.\n\n                On the other hand, if A is not symmetric then:\n                    - Some of the eigenvalues and eigenvectors might be complex numbers.  \n                        - An eigenvalue is complex if and only if its corresponding eigenvector \n                          is complex.  So you can check for this case by just checking \n                          get_imag_eigenvalues() to see if any values are non-zero.  You don't \n                          have to check the V matrix as well.\n                    - V*trans(V) won't be equal to the identity matrix but it is usually\n                      invertible.  So A == V*D*inv(V) is usually a valid statement but\n                      A == V*D*trans(V) won't be.\n                    - If DLIB_USE_LAPACK is #defined then this object uses the xGEEV LAPACK\n                      routine.\n        !*/\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef typename matrix_exp_type::matrix_type matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n\n        typedef matrix<std::complex<type>,0,0,mem_manager_type,layout_type> complex_matrix_type;\n        typedef matrix<std::complex<type>,NR,1,mem_manager_type,layout_type> complex_column_vector_type;\n\n\n        template <typename EXP>\n        eigenvalue_decomposition(\n            const matrix_exp<EXP>& A\n        ); \n        /*!\n            requires\n                - A.nr() == A.nc() \n                - A.size() > 0\n                - EXP::type == eigenvalue_decomposition::type \n            ensures\n                - #dim() == A.nr()\n                - computes the eigenvalue decomposition of A.  \n                - #get_eigenvalues() == the eigenvalues of A\n                - #get_v() == all the eigenvectors of A\n        !*/\n\n        template <typename EXP>\n        eigenvalue_decomposition(\n            const matrix_op<op_make_symmetric<EXP> >& A\n        ); \n        /*!\n            requires\n                - A.nr() == A.nc() \n                - A.size() > 0\n                - EXP::type == eigenvalue_decomposition::type \n            ensures\n                - #dim() == A.nr()\n                - computes the eigenvalue decomposition of the symmetric matrix A.  Does so\n                  using a method optimized for symmetric matrices.\n                - #get_eigenvalues() == the eigenvalues of A\n                - #get_v() == all the eigenvectors of A\n                - moreover, since A is symmetric there won't be any imaginary eigenvalues. So \n                  we will have:\n                    - #get_imag_eigenvalues() == 0\n                    - #get_real_eigenvalues() == the eigenvalues of A\n                    - #get_pseudo_v() == all the eigenvectors of A\n                    - diagm(#get_real_eigenvalues()) == #get_pseudo_d()\n\n                Note that the symmetric matrix operator is created by the\n                dlib::make_symmetric() function.  This function simply reflects\n                the lower triangular part of a square matrix into the upper triangular\n                part to create a symmetric matrix.  It can also be used to denote that a \n                matrix is already symmetric using the C++ type system.\n        !*/\n\n        long dim (\n        ) const;\n        /*!\n            ensures\n                - dim() == the number of rows/columns in the input matrix A \n        !*/\n\n        const complex_column_vector_type get_eigenvalues (\n        ) const;\n        /*!\n            ensures\n                - returns diag(get_d()).  That is, returns a \n                  vector that contains the eigenvalues of the input \n                  matrix.\n                - the returned vector has dim() rows\n                - the eigenvalues are not sorted in any particular way\n        !*/\n\n        const column_vector_type& get_real_eigenvalues (\n        ) const;\n        /*! \n            ensures\n                - returns the real parts of the eigenvalues.  That is,\n                  returns real(get_eigenvalues()) \n                - the returned vector has dim() rows\n                - the eigenvalues are not sorted in any particular way\n        !*/\n\n        const column_vector_type& get_imag_eigenvalues (\n        ) const;\n        /*! \n            ensures\n                - returns the imaginary parts of the eigenvalues.  That is,\n                  returns imag(get_eigenvalues()) \n                - the returned vector has dim() rows\n                - the eigenvalues are not sorted in any particular way\n        !*/\n\n        const complex_matrix_type get_v (\n        ) const;\n        /*!\n            ensures\n                - returns the eigenvector matrix V that is \n                  dim() rows by dim() columns\n                - Each column in V is one of the eigenvectors of the input \n                  matrix\n        !*/\n\n        const complex_matrix_type get_d (\n        ) const; \n        /*!\n            ensures\n                - returns a matrix D such that:\n                    - D.nr() == dim()\n                    - D.nc() == dim()\n                    - diag(D) == get_eigenvalues()\n                      (i.e. the diagonal of D contains all the eigenvalues in the input matrix)\n                    - all off diagonal elements of D are set to 0\n        !*/\n\n        const matrix_type& get_pseudo_v (\n        ) const;\n        /*!\n            ensures\n                - returns a matrix that is dim() rows by dim() columns\n                - Let A denote the input matrix given to this object's constructor.\n                - if (A has any imaginary eigenvalues) then\n                    - returns the pseudo-eigenvector matrix V  \n                    - The matrix V returned by this function is structured such that:\n                        - A*V == V*get_pseudo_d()\n                - else\n                    - returns the eigenvector matrix V with A's eigenvectors as\n                      the columns of V\n                    - A*V == V*diagm(get_real_eigenvalues())\n        !*/\n\n        const matrix_type get_pseudo_d (\n        ) const; \n        /*!\n            ensures\n                - The returned matrix is dim() rows by dim() columns\n                - Computes and returns the block diagonal eigenvalue matrix.\n                  If the original matrix A is not symmetric, then the eigenvalue \n                  matrix D is block diagonal with the real eigenvalues in 1-by-1 \n                  blocks and any complex eigenvalues,\n                  a + i*b, in 2-by-2 blocks, (a, b; -b, a).  That is, if the complex\n                  eigenvalues look like\n\n                      u + iv     .        .          .      .    .\n                        .      u - iv     .          .      .    .\n                        .        .      a + ib       .      .    .\n                        .        .        .        a - ib   .    .\n                        .        .        .          .      x    .\n                        .        .        .          .      .    y\n\n                  Then D looks like\n\n                        u        v        .          .      .    .\n                       -v        u        .          .      .    . \n                        .        .        a          b      .    .\n                        .        .       -b          a      .    .\n                        .        .        .          .      x    .\n                        .        .        .          .      .    y\n\n                  This keeps V (The V you get from get_pseudo_v()) a real matrix in both \n                  symmetric and non-symmetric cases, and A*V = V*D.\n                - the eigenvalues are not sorted in any particular way\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_LA_FUNCTS_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_lu.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n// This code was adapted from code from the JAMA part of NIST's TNT library.\n//    See: http://math.nist.gov/tnt/ \n#ifndef DLIB_MATRIX_LU_DECOMPOSITION_H\n#define DLIB_MATRIX_LU_DECOMPOSITION_H\n\n#include \"matrix.h\" \n#include \"matrix_utilities.h\"\n#include \"matrix_subexp.h\"\n#include \"matrix_trsm.h\"\n#include <algorithm>\n\n#ifdef DLIB_USE_LAPACK \n#include \"lapack/getrf.h\"\n#endif\n\n\nnamespace dlib \n{\n\n    template <\n        typename matrix_exp_type\n        >\n    class lu_decomposition\n    {\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;\n        typedef matrix<type,NR,1,mem_manager_type,layout_type> column_vector_type;\n        typedef matrix<long,NR,1,mem_manager_type,layout_type> pivot_column_vector_type;\n\n        // You have supplied an invalid type of matrix_exp_type.  You have\n        // to use this object with matrices that contain float or double type data.\n        COMPILE_TIME_ASSERT((is_same_type<float, type>::value || \n                             is_same_type<double, type>::value ));\n\n        template <typename EXP>\n        lu_decomposition (\n            const matrix_exp<EXP> &A\n        );\n\n        bool is_square (\n        ) const;\n\n        bool is_singular (\n        ) const;\n\n        long nr(\n        ) const;\n\n        long nc(\n        ) const;\n\n        const matrix_type get_l (\n        ) const; \n\n        const matrix_type get_u (\n        ) const;\n\n        const pivot_column_vector_type& get_pivot (\n        ) const;\n\n        type det (\n        ) const;\n\n        template <typename EXP>\n        const matrix_type solve (\n            const matrix_exp<EXP> &B\n        ) const;\n\n    private:\n\n        /* Array for internal storage of decomposition.  */\n        matrix<type,0,0,mem_manager_type,column_major_layout>  LU;\n        long m, n, pivsign; \n        pivot_column_vector_type piv;\n\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Public member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    lu_decomposition<matrix_exp_type>::\n    lu_decomposition (\n        const matrix_exp<EXP>& A\n    ) : \n        LU(A),\n        m(A.nr()),\n        n(A.nc())\n    {\n        using std::abs;\n\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A.size() > 0,\n            \"\\tlu_decomposition::lu_decomposition(A)\"\n            << \"\\n\\tInvalid inputs were given to this function\"\n            << \"\\n\\tA.size(): \" << A.size()\n            << \"\\n\\tthis:     \" << this\n            );\n\n#ifdef DLIB_USE_LAPACK\n        matrix<lapack::integer,0,1,mem_manager_type,layout_type> piv_temp;\n        lapack::getrf(LU, piv_temp);\n\n        pivsign = 1;\n\n        // Turn the piv_temp vector into a more useful form.  This way we will have the identity\n        // rowm(A,piv) == L*U.  The permutation vector that comes out of LAPACK is somewhat\n        // different.\n        piv = trans(range(0,m-1));\n        for (long i = 0; i < piv_temp.size(); ++i)\n        {\n            // -1 because FORTRAN is indexed starting with 1 instead of 0\n            if (piv(piv_temp(i)-1) != piv(i))\n            {\n                std::swap(piv(i), piv(piv_temp(i)-1));\n                pivsign = -pivsign;\n            }\n        }\n\n#else\n\n        // Use a \"left-looking\", dot-product, Crout/Doolittle algorithm.\n\n\n        piv = trans(range(0,m-1));\n        pivsign = 1;\n\n        column_vector_type LUcolj(m);\n\n        // Outer loop.\n        for (long j = 0; j < n; j++) \n        {\n\n            // Make a copy of the j-th column to localize references.\n            LUcolj = colm(LU,j);\n\n            // Apply previous transformations.\n            for (long i = 0; i < m; i++) \n            {\n                // Most of the time is spent in the following dot product.\n                const long kmax = std::min(i,j);\n                type s;\n                if (kmax > 0)\n                    s = rowm(LU,i, kmax)*colm(LUcolj,0,kmax);\n                else \n                    s = 0;\n\n                LU(i,j) = LUcolj(i) -= s;\n            }\n\n            // Find pivot and exchange if necessary.\n            long p = j;\n            for (long i = j+1; i < m; i++) \n            {\n                if (abs(LUcolj(i)) > abs(LUcolj(p))) \n                {\n                    p = i;\n                }\n            }\n            if (p != j) \n            {\n                long k=0;\n                for (k = 0; k < n; k++) \n                {\n                    type t = LU(p,k); \n                    LU(p,k) = LU(j,k); \n                    LU(j,k) = t;\n                }\n                k = piv(p); \n                piv(p) = piv(j); \n                piv(j) = k;\n                pivsign = -pivsign;\n            }\n\n            // Compute multipliers.\n            if ((j < m) && (LU(j,j) != 0.0)) \n            {\n                for (long i = j+1; i < m; i++) \n                {\n                    LU(i,j) /= LU(j,j);\n                }\n            }\n        }\n\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    bool lu_decomposition<matrix_exp_type>::\n    is_square (\n    ) const\n    {\n        return m == n;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    long lu_decomposition<matrix_exp_type>::\n    nr (\n    ) const\n    {\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    long lu_decomposition<matrix_exp_type>::\n    nc (\n    ) const\n    {\n        return n;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    bool lu_decomposition<matrix_exp_type>::\n    is_singular (\n    ) const\n    {\n        /* Is the matrix singular?\n          if upper triangular factor U (and hence A) is singular, false otherwise.\n        */\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_square() == true,\n            \"\\tbool lu_decomposition::is_singular()\"\n            << \"\\n\\tYou can only use this on square matrices\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        type max_val, min_val;\n        find_min_and_max (abs(diag(LU)), min_val, max_val);\n        type eps = max_val;\n        if (eps != 0)\n            eps *= std::sqrt(std::numeric_limits<type>::epsilon())/10;\n        else\n            eps = 1;  // there is no max so just use 1\n\n        return min_val < eps;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::\n    get_l (\n    ) const\n    {\n        if (LU.nr() >= LU.nc())\n            return lowerm(LU,1.0);\n        else\n            return lowerm(subm(LU,0,0,m,m), 1.0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::\n    get_u (\n    ) const \n    {\n        if (LU.nr() >= LU.nc())\n            return upperm(subm(LU,0,0,n,n));\n        else\n            return upperm(LU);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename lu_decomposition<matrix_exp_type>::pivot_column_vector_type& lu_decomposition<matrix_exp_type>::\n    get_pivot (\n    ) const\n    {\n        return piv;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    typename lu_decomposition<matrix_exp_type>::type lu_decomposition<matrix_exp_type>::\n    det (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_square() == true,\n            \"\\ttype lu_decomposition::det()\"\n            << \"\\n\\tYou can only use this on square matrices\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // Check if it is singular and if it is just return 0.  \n        // We want to do this because a prod() operation can easily\n        // overcome a single diagonal element that is effectively 0 when\n        // LU is a big enough matrix.\n        if (is_singular())\n            return 0;\n\n        return prod(diag(LU))*static_cast<type>(pivsign);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    const typename lu_decomposition<matrix_exp_type>::matrix_type lu_decomposition<matrix_exp_type>::\n    solve (\n        const matrix_exp<EXP> &B\n    ) const\n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_square() == true && B.nr() == nr(),\n            \"\\ttype lu_decomposition::solve()\"\n            << \"\\n\\tInvalid arguments to this function\"\n            << \"\\n\\tis_square():   \" << (is_square()? \"true\":\"false\" )\n            << \"\\n\\tB.nr():        \" << B.nr() \n            << \"\\n\\tnr():          \" << nr() \n            << \"\\n\\tthis:          \" << this\n            );\n\n        // Copy right hand side with pivoting\n        matrix<type,0,0,mem_manager_type,column_major_layout> X(rowm(B, piv));\n\n        using namespace blas_bindings;\n        // Solve L*Y = B(piv,:)\n        triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasUnit, LU, X);\n        // Solve U*X = Y;\n        triangular_solver(CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, LU, X);\n        return X;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n} \n\n#endif // DLIB_MATRIX_LU_DECOMPOSITION_H \n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_mat.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_MAT_Hh_\n#define DLIB_MATRIx_MAT_Hh_\n\n#include \"matrix_mat_abstract.h\"\n#include \"../stl_checked.h\"\n#include <vector>\n#include \"matrix_op.h\"\n#include \"../array2d.h\"\n#include \"../array.h\"\n#include \"../image_processing/generic_image.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename EXP\n        >\n    const matrix_exp<EXP>& mat (\n        const matrix_exp<EXP>& m\n    )\n    {\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type, typename pixel_type>\n    struct op_image_to_mat : does_not_alias \n    {\n        op_image_to_mat( const image_type& img) : imgview(img){}\n\n        const_image_view<image_type> imgview;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef pixel_type type;\n        typedef const pixel_type& const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }\n\n        long nr () const { return imgview.nr(); }\n        long nc () const { return imgview.nc(); }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        > // The reason we disable this if it is a matrix is because this matrix_op claims\n          // to not alias any matrix.  But obviously that would be a problem if we let it\n          // take a matrix.\n    const typename disable_if<is_matrix<image_type>,matrix_op<op_image_to_mat<image_type, typename image_traits<image_type>::pixel_type> > >::type mat (\n        const image_type& img \n    )\n    {\n        typedef op_image_to_mat<image_type, typename image_traits<image_type>::pixel_type> op;\n        return matrix_op<op>(op(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    struct op_image_view_to_mat : does_not_alias \n    {\n        op_image_view_to_mat( const image_view<image_type>& img) : imgview(img){}\n\n        typedef typename image_traits<image_type>::pixel_type pixel_type;\n\n        const image_view<image_type>& imgview;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef pixel_type type;\n        typedef const pixel_type& const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }\n\n        long nr () const { return imgview.nr(); }\n        long nc () const { return imgview.nc(); }\n    }; \n\n    template <\n        typename image_type\n        > \n    const matrix_op<op_image_view_to_mat<image_type> > mat (\n        const image_view<image_type>& img \n    )\n    {\n        typedef op_image_view_to_mat<image_type> op;\n        return matrix_op<op>(op(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename image_type>\n    struct op_const_image_view_to_mat : does_not_alias \n    {\n        op_const_image_view_to_mat( const const_image_view<image_type>& img) : imgview(img){}\n\n        typedef typename image_traits<image_type>::pixel_type pixel_type;\n\n        const const_image_view<image_type>& imgview;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef pixel_type type;\n        typedef const pixel_type& const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return imgview[r][c]; }\n\n        long nr () const { return imgview.nr(); }\n        long nc () const { return imgview.nc(); }\n    }; \n\n    template <\n        typename image_type\n        > \n    const matrix_op<op_const_image_view_to_mat<image_type> > mat (\n        const const_image_view<image_type>& img \n    )\n    {\n        typedef op_const_image_view_to_mat<image_type> op;\n        return matrix_op<op>(op(img));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_array_to_mat : does_not_alias \n    {\n        op_array_to_mat( const T& vect_) : vect(vect_){}\n\n        const T& vect;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 1;\n        typedef typename T::type type;\n        typedef const typename T::type& const_ret_type;\n        typedef typename T::mem_manager_type mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long  ) const { return vect[r]; }\n\n        long nr () const { return vect.size(); }\n        long nc () const { return 1; }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename MM\n        >\n    const matrix_op<op_array_to_mat<array<T,MM> > > mat (\n        const array<T,MM>& m \n    )\n    {\n        typedef op_array_to_mat<array<T,MM> > op;\n        return matrix_op<op>(op(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename U>\n        struct not_bool { typedef U type; };\n        template <>\n        struct not_bool<const bool&> { typedef bool type; };\n    }\n\n    template <typename T>\n    struct op_std_vect_to_mat : does_not_alias \n    {\n        op_std_vect_to_mat( const T& vect_) : vect(vect_){}\n\n        const T& vect;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 1;\n        typedef typename T::value_type type;\n        // Since std::vector returns a proxy for bool types we need to make sure we don't\n        // return an element by reference if it is a bool type.\n        typedef typename impl::not_bool<const typename T::value_type&>::type const_ret_type;\n\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long ) const { return vect[r]; }\n\n        long nr () const { return vect.size(); }\n        long nc () const { return 1; }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > mat (\n        const std::vector<value_type,alloc>& vector\n    )\n    {\n        typedef op_std_vect_to_mat<std::vector<value_type,alloc> > op;\n        return matrix_op<op>(op(vector));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > mat (\n        const std_vector_c<value_type,alloc>& vector\n    )\n    {\n        typedef op_std_vect_to_mat<std_vector_c<value_type,alloc> > op;\n        return matrix_op<op>(op(vector));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_pointer_to_mat;   \n\n    template <typename T>\n    struct op_pointer_to_col_vect   \n    {\n        op_pointer_to_col_vect(\n            const T* ptr_,\n            const long size_\n        ) : ptr(ptr_), size(size_){}\n\n        const T* ptr;\n        const long size;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 1;\n        typedef T type;\n        typedef const T& const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long ) const { return ptr[r]; }\n\n        long nr () const { return size; }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& ) const { return false; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& ) const { return false; }\n\n        template <long num_rows, long num_cols, typename mem_manager, typename layout>\n        bool aliases (\n            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item\n        ) const \n        { \n            if (item.size() == 0)\n                return false;\n            else\n                return (ptr == &item(0,0)); \n        }\n\n        inline bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item\n        ) const;\n\n        bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item\n        ) const\n        {\n            return item.ref().op.ptr == ptr;\n        }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_pointer_to_col_vect<T> > mat (\n        const T* ptr,\n        long nr\n    )\n    {\n        DLIB_ASSERT(nr >= 0 , \n                    \"\\tconst matrix_exp mat(ptr, nr)\"\n                    << \"\\n\\t nr must be >= 0\"\n                    << \"\\n\\t nr: \" << nr\n        );\n        typedef op_pointer_to_col_vect<T> op;\n        return matrix_op<op>(op(ptr, nr));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_pointer_to_mat  \n    {\n        op_pointer_to_mat(\n            const T* ptr_,\n            const long nr_,\n            const long nc_ \n        ) : ptr(ptr_), rows(nr_), cols(nc_), stride(nc_){}\n\n        op_pointer_to_mat(\n            const T* ptr_,\n            const long nr_,\n            const long nc_,\n            const long stride_\n        ) : ptr(ptr_), rows(nr_), cols(nc_), stride(stride_){}\n\n        const T* ptr;\n        const long rows;\n        const long cols;\n        const long stride;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef T type;\n        typedef const T& const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c) const { return ptr[r*stride + c]; }\n\n        long nr () const { return rows; }\n        long nc () const { return cols; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& ) const { return false; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& ) const { return false; }\n\n        template <long num_rows, long num_cols, typename mem_manager, typename layout>\n        bool aliases (\n            const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item\n        ) const \n        { \n            if (item.size() == 0)\n                return false;\n            else\n                return (ptr == &item(0,0)); \n        }\n\n        bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item\n        ) const\n        {\n            return item.ref().op.ptr == ptr;\n        }\n\n        bool aliases (\n            const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item\n        ) const\n        {\n            return item.ref().op.ptr == ptr;\n        }\n    }; \n\n    template <typename T>\n    bool op_pointer_to_col_vect<T>::\n    aliases (\n        const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item\n    ) const\n    {\n        return item.ref().op.ptr == ptr;\n    }\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    bool matrix<T,NR,NC,MM,L>::aliases (\n        const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item\n    ) const\n    {\n        if (size() != 0)\n            return item.ref().op.ptr == &data(0,0);\n        else\n            return false;\n    }\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    bool matrix<T,NR,NC,MM,L>::aliases (\n        const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item\n    ) const\n    {\n        if (size() != 0)\n            return item.ref().op.ptr == &data(0,0);\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_pointer_to_mat<T> > mat (\n        const T* ptr,\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0 , \n                    \"\\tconst matrix_exp mat(ptr, nr, nc)\"\n                    << \"\\n\\t nr and nc must be >= 0\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n        );\n        typedef op_pointer_to_mat<T> op;\n        return matrix_op<op>(op(ptr,nr,nc));\n    }\n\n    template <\n        typename T\n        >\n    const matrix_op<op_pointer_to_mat<T> > mat (\n        const T* ptr,\n        long nr,\n        long nc,\n        long stride\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0 && stride > 0 , \n                    \"\\tconst matrix_exp mat(ptr, nr, nc, stride)\"\n                    << \"\\n\\t nr and nc must be >= 0 while stride > 0\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n                    << \"\\n\\t stride: \" << stride\n        );\n        typedef op_pointer_to_mat<T> op;\n        return matrix_op<op>(op(ptr,nr,nc,stride));\n    }\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    typename enable_if<std::is_trivially_copyable<T>>::type matrix_assign (\n        matrix<T,NR,NC,MM,row_major_layout>& dest,\n        const matrix_exp<matrix_op<op_pointer_to_mat<T>>>& src\n    )\n    /*!\n        An overload to catch statements of the form:\n           some_matrix = mat(ptr,rows,cols, stride)\n        and convert them into a memcpy(), which is a faster way to do the copy.\n    !*/\n    {\n        if (dest.size() == 0) return;\n\n        // If the op_pointer_to_mat is referring to a contiguous block of memory then just one memcopy\n        // is needed.\n        if (src.ref().op.stride == dest.nc()) \n        {\n            std::memcpy(&dest(0, 0), src.ref().op.ptr, dest.nr() * dest.nc() * sizeof(T));\n        } \n        else \n        {\n            // Otherwise memcpy() each row separately.\n            for (long r=0; r<dest.nr(); r++)\n            {\n                std::memcpy(&dest(r, 0), &src(r,0), src.nc() * sizeof(T));\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\nnamespace arma\n{\n    template <typename T> class Mat;\n}\nnamespace dlib\n{\n    template <typename T>\n    struct op_arma_Mat_to_mat : does_not_alias \n    {\n        op_arma_Mat_to_mat( const T& array_) : array(array_){}\n\n        const T& array;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef typename T::elem_type type;\n        typedef typename T::elem_type const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return array(r,c); }\n\n        long nr () const { return array.n_rows; }\n        long nc () const { return array.n_cols; }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_arma_Mat_to_mat< ::arma::Mat<T> > > mat (\n        const ::arma::Mat<T>& array\n    )\n    {\n        typedef op_arma_Mat_to_mat< ::arma::Mat<T> > op;\n        return matrix_op<op>(op(array));\n    }\n}\n\nnamespace Eigen\n{\n    template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>\n    class Matrix;\n}\n\nnamespace dlib\n{\n    template <typename T, int _Rows, int _Cols>\n    struct op_eigen_Matrix_to_mat : does_not_alias \n    {\n        op_eigen_Matrix_to_mat( const T& array_) : m(array_){}\n\n        const T& m;\n\n        const static long cost = 1;\n        const static long NR = (_Rows > 0) ? _Rows : 0;\n        const static long NC = (_Cols > 0) ? _Cols : 0;\n        typedef typename T::Scalar type;\n        typedef typename T::Scalar const_ret_type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return m(r,c); }\n\n        long nr () const { return m.rows(); }\n        long nc () const { return m.cols(); }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols\n        >\n    const matrix_op<op_eigen_Matrix_to_mat< ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>,_Rows,_Cols > > mat (\n        const ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>& m\n    )\n    {\n        typedef op_eigen_Matrix_to_mat< ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>,_Rows,_Cols > op;\n        return matrix_op<op>(op(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                  DEPRECATED FUNCTIONS\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n// vector_to_matrix(), array_to_matrix(), pointer_to_matrix(), and\n// pointer_to_column_vector() have been deprecated in favor of the more uniform mat()\n// function.  But they are here for backwards compatibility.\n\n    template <\n        typename vector_type\n        >\n    const typename disable_if<is_matrix<vector_type>, matrix_op<op_array_to_mat<vector_type> > >::type \n    vector_to_matrix (\n        const vector_type& vector\n    )\n    {\n        typedef op_array_to_mat<vector_type> op;\n        return matrix_op<op>(op(vector));\n    }\n\n    template <\n        typename vector_type\n        >\n    const typename enable_if<is_matrix<vector_type>,vector_type>::type& vector_to_matrix (\n        const vector_type& vector\n    )\n    /*!\n        This overload catches the case where the argument to this function is\n        already a matrix.\n    !*/\n    {\n        return vector;\n    }\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_op<op_std_vect_to_mat<std::vector<value_type,alloc> > > vector_to_matrix (\n        const std::vector<value_type,alloc>& vector\n    )\n    {\n        typedef op_std_vect_to_mat<std::vector<value_type,alloc> > op;\n        return matrix_op<op>(op(vector));\n    }\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_op<op_std_vect_to_mat<std_vector_c<value_type,alloc> > > vector_to_matrix (\n        const std_vector_c<value_type,alloc>& vector\n    )\n    {\n        typedef op_std_vect_to_mat<std_vector_c<value_type,alloc> > op;\n        return matrix_op<op>(op(vector));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename array_type\n        >\n    const typename enable_if<is_matrix<array_type>,array_type>::type& \n    array_to_matrix (\n        const array_type& array\n    )\n    {\n        return array;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct op_array2d_to_mat : does_not_alias \n    {\n        op_array2d_to_mat( const T& array_) : array(array_){}\n\n        const T& array;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef typename T::type type;\n        typedef const typename T::type& const_ret_type;\n        typedef typename T::mem_manager_type mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        const_ret_type apply (long r, long c ) const { return array[r][c]; }\n\n        long nr () const { return array.nr(); }\n        long nc () const { return array.nc(); }\n    }; \n\n    // Note that we have this version of mat() because it's slightly faster executing\n    // than the general one that handles any generic image.  This is because it avoids\n    // calling image_data() which for array2d involves a single if statement but this\n    // version here has no if statement in its construction.\n    template < typename T, typename MM >\n    const matrix_op<op_array2d_to_mat<array2d<T,MM> > > mat (\n        const array2d<T,MM>& array\n    )\n    {\n        typedef op_array2d_to_mat<array2d<T,MM> > op;\n        return matrix_op<op>(op(array));\n    }\n\n    template <\n        typename array_type\n        >\n    const typename disable_if<is_matrix<array_type>,matrix_op<op_array2d_to_mat<array_type> > >::type \n    array_to_matrix (\n        const array_type& array\n    )\n    {\n        typedef op_array2d_to_mat<array_type> op;\n        return matrix_op<op>(op(array));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_pointer_to_mat<T> > pointer_to_matrix (\n        const T* ptr,\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(nr > 0 && nc > 0 , \n                    \"\\tconst matrix_exp pointer_to_matrix(ptr, nr, nc)\"\n                    << \"\\n\\t nr and nc must be bigger than 0\"\n                    << \"\\n\\t nr: \" << nr\n                    << \"\\n\\t nc: \" << nc\n        );\n        typedef op_pointer_to_mat<T> op;\n        return matrix_op<op>(op(ptr,nr,nc));\n    }\n\n    template <\n        typename T\n        >\n    const matrix_op<op_pointer_to_col_vect<T> > pointer_to_column_vector (\n        const T* ptr,\n        long nr\n    )\n    {\n        DLIB_ASSERT(nr > 0 , \n                    \"\\tconst matrix_exp pointer_to_column_vector(ptr, nr)\"\n                    << \"\\n\\t nr must be bigger than 0\"\n                    << \"\\n\\t nr: \" << nr\n        );\n        typedef op_pointer_to_col_vect<T> op;\n        return matrix_op<op>(op(ptr, nr));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    inline matrix<double,1,1> mat (\n        double value\n    )\n    {\n        matrix<double,1,1> temp;\n        temp(0) = value;\n        return temp;\n    }\n\n    inline matrix<float,1,1> mat (\n        float value\n    )\n    {\n        matrix<float,1,1> temp;\n        temp(0) = value;\n        return temp;\n    }\n\n    inline matrix<long double,1,1> mat (\n        long double value\n    )\n    {\n        matrix<long double,1,1> temp;\n        temp(0) = value;\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_MAT_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_mat_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_MAT_ABSTRACT_Hh_\n#ifdef DLIB_MATRIx_MAT_ABSTRACT_Hh_\n\n#include \"matrix_abstract.h\"\n#inclue <vector>\n#include \"../array/array_kernel_abstract.h\"\n#include \"../array2d/array2d_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_exp<EXP>& mat (\n        const matrix_exp<EXP>& m\n    );\n    /*!\n        ensures\n            - returns m\n              (i.e. this function just returns the input matrix without any modifications)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    const matrix_exp mat (\n        const image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or image_type is a image_view or\n              const_image_view object.\n        ensures\n            - This function converts any kind of generic image object into a dlib::matrix\n              expression.  Therefore, it is capable of converting objects like dlib::array2d\n              of dlib::cv_image.\n            - returns a matrix R such that:\n                - R.nr() == array.nr() \n                - R.nc() == array.nc()\n                - for all valid r and c:\n                  R(r, c) == array[r][c]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename MM\n        >\n    const matrix_exp mat (\n        const array<T,MM>& m \n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - is_col_vector(R) == true \n                - R.size() == m.size()\n                - for all valid r:\n                  R(r) == m[r]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_exp mat (\n        const std::vector<value_type,alloc>& vector\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - is_col_vector(R) == true \n                - R.size() == vector.size()\n                - for all valid r:\n                  R(r) == vector[r]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename value_type,\n        typename alloc\n        >\n    const matrix_exp mat (\n        const std_vector_c<value_type,alloc>& vector\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - is_col_vector(R) == true \n                - R.size() == vector.size()\n                - for all valid r:\n                  R(r) == vector[r]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp mat (\n        const T* ptr,\n        long nr\n    );\n    /*!\n        requires\n            - nr >= 0\n            - ptr == a pointer to at least nr T objects (or the NULL pointer if nr==0)\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == nr\n                - m.nc() == 1\n                - for all valid i:\n                  M(i) == ptr[i]\n            - Note that the returned matrix doesn't take \"ownership\" of\n              the pointer and thus will not delete or free it.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp mat (\n        const T* ptr,\n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n            - ptr == a pointer to at least nr*nc T objects (or the NULL pointer if nr*nc==0)\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == nr\n                - m.nc() == nc \n                - for all valid r and c:\n                  M(r,c) == ptr[r*nc + c]\n                  (i.e. the pointer is interpreted as a matrix laid out in memory\n                  in row major order)\n            - Note that the returned matrix doesn't take \"ownership\" of\n              the pointer and thus will not delete or free it.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp mat (\n        const T* ptr,\n        long nr,\n        long nc,\n        long stride\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n            - stride > 0\n            - ptr == a pointer to at least (nr-1)*stride+nc T objects (or the NULL pointer if nr*nc==0)\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == nr\n                - m.nc() == nc \n                - for all valid r and c:\n                  M(r,c) == ptr[r*stride + c]\n                  (i.e. the pointer is interpreted as a matrix laid out in memory\n                  in row major order, with a row stride of the given stride amount.)\n            - Note that the returned matrix doesn't take \"ownership\" of\n              the pointer and thus will not delete or free it.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp mat (\n        const ::arma::Mat<T>& m\n    );\n    /*!\n        ensures\n            - Converts a matrix from the Armadillo library into a dlib matrix.\n            - returns a matrix R such that:\n                - R.nr() == m.n_rows \n                - R.nc() == m.n_cols\n                - for all valid r:\n                  R(r,c) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename _Scalar, \n        int _Rows, \n        int _Cols, \n        int _Options, \n        int _MaxRows, \n        int _MaxCols\n        >\n    const matrix_exp mat (\n        const ::Eigen::Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols>& m\n    );\n    /*!\n        ensures\n            - Converts a matrix from the Eigen library into a dlib matrix.\n            - returns a matrix R such that:\n                - R.nr() == m.rows()\n                - R.nc() == m.cols()\n                - for all valid r:\n                  R(r,c) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    matrix<double,1,1>      mat (double value);\n    matrix<float,1,1>       mat (float value);\n    matrix<long double,1,1> mat (long double value);\n    /*!\n        ensures\n            - Converts a scalar into a matrix containing just that scalar and returns the\n              results.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_MAT_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_math_functions.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_MATH_FUNCTIONS\n#define DLIB_MATRIx_MATH_FUNCTIONS \n\n#include \"matrix_math_functions_abstract.h\"\n#include \"matrix_op.h\"\n#include \"matrix_utilities.h\"\n#include \"matrix.h\"\n#include \"../algs.h\"\n#include <cmath>\n#include <complex>\n#include <limits>\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    DLIB_DEFINE_FUNCTION_M(op_sqrt, sqrt, std::sqrt, 7)\n    DLIB_DEFINE_FUNCTION_M(op_log, log, std::log, 7)\n    DLIB_DEFINE_FUNCTION_M(op_log10, log10, std::log10, 7)\n    DLIB_DEFINE_FUNCTION_M(op_exp, exp, std::exp, 7)\n\n    DLIB_DEFINE_FUNCTION_M(op_conj, conj, std::conj, 2)\n\n    DLIB_DEFINE_FUNCTION_M(op_ceil, ceil, std::ceil, 7)\n    DLIB_DEFINE_FUNCTION_M(op_floor, floor, std::floor, 7)\n\n    DLIB_DEFINE_FUNCTION_M(op_sin, sin, std::sin, 7)\n    DLIB_DEFINE_FUNCTION_M(op_cos, cos, std::cos, 7)\n    DLIB_DEFINE_FUNCTION_M(op_tan, tan, std::tan, 7)\n    DLIB_DEFINE_FUNCTION_M(op_sinh, sinh, std::sinh, 7)\n    DLIB_DEFINE_FUNCTION_M(op_cosh, cosh, std::cosh, 7)\n    DLIB_DEFINE_FUNCTION_M(op_tanh, tanh, std::tanh, 7)\n    DLIB_DEFINE_FUNCTION_M(op_asin, asin, std::asin, 7)\n    DLIB_DEFINE_FUNCTION_M(op_acos, acos, std::acos, 7)\n    DLIB_DEFINE_FUNCTION_M(op_atan, atan, std::atan, 7)\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type>\n        inline type sigmoid (const type& val)\n        {\n            return static_cast<type>(1/(1 + std::exp(-val)));\n        }\n\n        template <typename type, typename S>\n        inline type round_zeros_eps (const type& val, const S& eps)\n        {\n            // you can only round matrices that contain built in scalar types like double, long, float, etc.\n            COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);\n\n            if (val >= eps || val <= -eps)\n                return val;\n            else\n                return 0;\n        }\n\n        template <typename type>\n        inline type round_zeros (const type& val)\n        {\n            // you can only round matrices that contain built in scalar types like double, long, float, etc.\n            COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);\n\n            const type eps = 10*std::numeric_limits<type>::epsilon();\n            if (val >= eps || val <= -eps)\n                return val;\n            else\n                return 0;\n        }\n\n        template <typename type>\n        inline type squared (const type& val)\n        {\n            return val*val;\n        }\n\n        template <typename type>\n        inline type sign (const type& val)\n        {\n            if (val >= 0)\n                return +1;\n            else\n                return -1;\n        }\n\n        template <typename type>\n        type cubed (const type& val)\n        {\n            return val*val*val;\n        }\n\n        template <typename type, typename S>\n        inline type pow1 (const type& val, const S& s)\n        {\n            // you can only call pow() on matrices that contain floats, doubles or long doubles.\n            COMPILE_TIME_ASSERT((\n                    is_same_type<type,float>::value == true || \n                    is_same_type<type,double>::value == true || \n                    is_same_type<type,long double>::value == true \n            ));\n\n            return std::pow(val,static_cast<type>(s));\n        }\n\n        template <typename type, typename S>\n        inline type pow2 (const S& s, const type& val)\n        {\n            // you can only call pow() on matrices that contain floats, doubles or long doubles.\n            COMPILE_TIME_ASSERT((\n                    is_same_type<type,float>::value == true || \n                    is_same_type<type,double>::value == true || \n                    is_same_type<type,long double>::value == true \n            ));\n\n            return std::pow(static_cast<type>(s),val);\n        }\n\n        template <typename type>\n        inline type reciprocal (const type& val)\n        {\n            // you can only compute reciprocal matrices that contain floats, doubles or long doubles.\n            COMPILE_TIME_ASSERT((\n                    is_same_type<type,float>::value == true || \n                    is_same_type<type,double>::value == true || \n                    is_same_type<type,long double>::value == true  ||\n                    is_same_type<type,std::complex<float> >::value == true || \n                    is_same_type<type,std::complex<double> >::value == true || \n                    is_same_type<type,std::complex<long double> >::value == true \n            ));\n\n            if (val != static_cast<type>(0))\n                return static_cast<type>((type)1.0/val);\n            else\n                return 0;\n        }\n\n        template <typename type>\n        inline type reciprocal_max (const type& val)\n        {\n            // you can only compute reciprocal_max matrices that contain floats, doubles or long doubles.\n            COMPILE_TIME_ASSERT((\n                    is_same_type<type,float>::value == true || \n                    is_same_type<type,double>::value == true || \n                    is_same_type<type,long double>::value == true \n            ));\n\n            if (val != static_cast<type>(0))\n                return static_cast<type>((type)1.0/val);\n            else\n                return std::numeric_limits<type>::max();\n        }\n\n    }\n\n    DLIB_DEFINE_FUNCTION_M(op_sigmoid, sigmoid, impl::sigmoid, 7)\n    DLIB_DEFINE_FUNCTION_MS(op_round_zeros, round_zeros, impl::round_zeros_eps, 7)\n    DLIB_DEFINE_FUNCTION_M(op_round_zeros2, round_zeros, impl::round_zeros, 7)\n    DLIB_DEFINE_FUNCTION_M(op_cubed, cubed, impl::cubed, 7)\n    DLIB_DEFINE_FUNCTION_M(op_squared, squared, impl::squared, 6)\n    DLIB_DEFINE_FUNCTION_M(op_sign, sign, impl::sign, 6)\n    DLIB_DEFINE_FUNCTION_MS(op_pow1, pow, impl::pow1, 7)\n    DLIB_DEFINE_FUNCTION_SM(op_pow2, pow, impl::pow2, 7)\n    DLIB_DEFINE_FUNCTION_M(op_reciprocal, reciprocal, impl::reciprocal, 6)\n    DLIB_DEFINE_FUNCTION_M(op_reciprocal_max, reciprocal_max, impl::reciprocal_max, 6)\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename enabled = void>\n    struct op_round : basic_op_m<M> \n    {\n        op_round( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+7;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        {\n            return static_cast<type>(std::round(this->m(r,c)));\n        }\n    };\n\n    template <typename M>\n    struct op_round<M,typename enable_if_c<std::numeric_limits<typename M::type>::is_integer>::type > \n    : basic_op_m<M>\n    {\n        op_round( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return this->m(r,c);\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_round<EXP> > round (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only round matrices that contain built in scalar types like double, long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_round<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_normalize : basic_op_m<M> \n    {\n        typedef typename M::type type;\n\n        op_normalize( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+5;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { \n            return this->m(r,c)*s;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_normalize<EXP> > normalize (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only compute normalized matrices that contain floats, doubles or long doubles.\n        COMPILE_TIME_ASSERT((\n                is_same_type<typename EXP::type,float>::value == true || \n                is_same_type<typename EXP::type,double>::value == true || \n                is_same_type<typename EXP::type,long double>::value == true \n        ));\n\n\n        typedef op_normalize<EXP> op;\n        typename EXP::type temp = std::sqrt(sum(squared(m)));\n        if (temp != 0.0)\n            temp = 1.0/temp;\n\n        return matrix_op<op>(op(m.ref(),temp));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename return_type = typename M::type>\n    struct op_abs : basic_op_m<M>\n    {\n        op_abs( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+7;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            return static_cast<type>(std::abs(this->m(r,c))); \n        }\n    };\n\n    template <typename M, typename T>\n    struct op_abs<M, std::complex<T> > : basic_op_m<M>\n    {\n        op_abs( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost;\n        typedef T type;\n        typedef const T const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            return static_cast<type>(std::abs(this->m(r,c))); \n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_abs<EXP> > abs (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_abs<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_complex_matrix : basic_op_m<M>\n    {\n        op_complex_matrix( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+1;\n        typedef std::complex<typename M::type> type;\n        typedef const std::complex<typename M::type> const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            return type(this->m(r,c));\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_complex_matrix<EXP> > complex_matrix (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_complex_matrix<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_complex_matrix2 : basic_op_mm<M1,M2>\n    {\n        op_complex_matrix2( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        const static long cost = M1::cost+M2::cost+1;\n        typedef std::complex<typename M1::type> type;\n        typedef const std::complex<typename M1::type> const_ret_type;\n\n        const_ret_type apply ( long r, long c) const\n        { return type(this->m1(r,c), this->m2(r,c)); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_complex_matrix2<EXP1,EXP2> > complex_matrix (\n        const matrix_exp<EXP1>& real_part,\n        const matrix_exp<EXP2>& imag_part \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n\n        DLIB_ASSERT(real_part.nr() == imag_part.nr() &&\n               real_part.nc() == imag_part.nc(), \n            \"\\tconst matrix_exp::type complex_matrix(real_part, imag_part)\"\n            << \"\\n\\tYou can only make a complex matrix from two equally sized matrices\"\n            << \"\\n\\treal_part.nr(): \" << real_part.nr()\n            << \"\\n\\treal_part.nc(): \" << real_part.nc() \n            << \"\\n\\timag_part.nr(): \" << imag_part.nr()\n            << \"\\n\\timag_part.nc(): \" << imag_part.nc() \n            );\n\n        typedef op_complex_matrix2<EXP1,EXP2> op;\n        return matrix_op<op>(op(real_part.ref(),imag_part.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_norm : basic_op_m<M>\n    {\n        op_norm( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+6;\n        typedef typename M::type::value_type type;\n        typedef const typename M::type::value_type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { return std::norm(this->m(r,c)); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_norm<EXP> > norm (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_norm<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_real : basic_op_m<M>\n    {\n        op_real( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost;\n        typedef typename M::type::value_type type;\n        typedef const typename M::type::value_type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { return std::real(this->m(r,c)); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_real<EXP> > real (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_real<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_imag : basic_op_m<M>\n    {\n        op_imag( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost;\n        typedef typename M::type::value_type type;\n        typedef const typename M::type::value_type const_ret_type;\n        const_ret_type apply (long r, long c) const\n        { return std::imag(this->m(r,c)); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_imag<EXP> > imag (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_imag<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_softmax : basic_op_m<M>\n    {\n        typedef typename M::type type;\n\n        op_softmax(const M& m_, const type& s_, const type& v_) : basic_op_m<M>(m_), s(s_), v(v_){}\n\n        const type s;\n        const type v;\n\n        const static long cost = M::cost + 9;\n        typedef type const_ret_type;\n        const_ret_type apply(long r, long c) const { return std::exp(this->m(r, c) - v) * s; }\n    };\n\n    template <\n      typename EXP\n      >\n    const matrix_op<op_softmax<EXP> > soft_max (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only compute softmax on matrices that contain floats, doubles or long doubles.\n        COMPILE_TIME_ASSERT((\n              is_same_type<typename EXP::type,float>::value == true ||\n              is_same_type<typename EXP::type,double>::value == true ||\n              is_same_type<typename EXP::type,long double>::value == true\n        ));\n        typedef op_softmax<EXP> op;\n        typename EXP::type max_val = max(m);\n        typename EXP::type temp = static_cast<typename EXP::type>(1) / sum(exp(m - max_val));\n        return matrix_op<op>(op(m.ref(), temp, max_val));\n    }\n\n}\n\n#endif // DLIB_MATRIx_MATH_FUNCTIONS\n\n"
  },
  {
    "path": "dlib/matrix/matrix_math_functions_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_\n#ifdef DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_\n\n#include \"matrix_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                          Exponential Functions \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp exp (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::exp(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp log10 (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::log10(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp log (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::log(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sqrt (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == sqrt(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const matrix_exp pow (\n        const matrix_exp& m,\n        const T& e\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == pow(m(r,c),e) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    const matrix_exp pow (\n        const T& b,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == pow(b, m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp squared (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == m(r,c)*m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp cubed (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == m(r,c)*m(r,c)*m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                               Miscellaneous\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sign (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix that tells the sign of each element in m. In particular:\n              returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) >= 0) then\n                        - R(r,c) == +1\n                    - else\n                        - R(r,c) == -1\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sigmoid (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == 1/(1 + exp(-m(r,c))) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp abs (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - if (m contains std::complex<T> objects) then\n                    - R::type == T \n                - else\n                    - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::abs(m(r,c)) \n                  (note that if m is complex then std::abs(val) performs sqrt(std::norm(val))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp reciprocal (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, long double, std::complex<float>,\n              std::complex<double>, or std::complex<long double>\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) != 0) then\n                        - R(r,c) == 1.0/m(r,c) \n                    - else\n                        - R(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp reciprocal_max (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, long double\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) != 0) then\n                        - R(r,c) == 1.0/m(r,c) \n                    - else\n                        - R(r,c) == std::numeric_limits<R::type>::max() \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp normalize (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - if (sqrt(sum(squared(m))) != 0) then\n                - returns m/sqrt(sum(squared(m)))\n            - else\n                - returns m\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                          Rounding numbers one way or another\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp round (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n              (i.e. m must contain a type like int, float, double, long, etc.)\n        ensures\n            - if (m contains integers) then\n                - returns m unmodified\n            - else\n                - returns a matrix R such that:\n                    - R::type == the same type that was in m\n                    - R has the same dimensions as m\n                    - for all valid r and c:\n                      R(r,c) == m(r,c) rounded to the nearest integral value\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp ceil (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::ceil(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp floor (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::floor(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp round_zeros (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n              (i.e. m must contain a type like int, float, double, long, etc.)\n        ensures\n            - if (m contains integers) then\n                - returns m unmodified\n            - else\n                - returns a matrix R such that:\n                    - R::type == the same type that was in m\n                    - R has the same dimensions as m\n                    - let eps == 10*std::numeric_limits<matrix_exp::type>::epsilon()\n                    - for all valid r and c:\n                        - if (abs(m(r,c)) >= eps) then\n                            - R(r,c) == m(r,c)\n                        - else\n                            - R(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp round_zeros (\n        const matrix_exp& m,\n        matrix_exp::type eps \n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n              (i.e. m must contain a type like int, float, double, long, etc.)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (abs(m(r,c)) >= eps) then\n                        - R(r,c) == m(r,c)\n                    - else\n                        - R(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Complex number utility functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp conj (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == std::complex<T>\n        ensures\n            - returns a matrix R such that:\n                - R::type == std::complex<T>\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::conj(m(r,c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp norm (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == std::complex<T>\n        ensures\n            - returns a matrix R such that:\n                - R::type == T\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::norm(m(r,c))\n                  (note that std::norm(val) == val.real()*val.real() + val.imag()*val.imag())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp imag (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == std::complex<T>\n        ensures\n            - returns a matrix R such that:\n                - R::type == T\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::imag(m(r,c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp real (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == std::complex<T>\n        ensures\n            - returns a matrix R such that:\n                - R::type == T\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::real(m(r,c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp complex_matrix (\n        const matrix_exp& real_part\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == std::complex<T> where T is whatever type real_part used.\n                - R has the same dimensions as real_part. \n                - for all valid r and c:\n                  R(r,c) == std::complex(real_part(r,c), 0)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp complex_matrix (\n        const matrix_exp& real_part,\n        const matrix_exp& imag_part\n    );\n    /*!\n        requires\n            - real_part.nr() == imag_part.nr()\n            - real_part.nc() == imag_part.nc()\n            - real_part and imag_part both contain the same type of element\n        ensures\n            - returns a matrix R such that:\n                - R::type == std::complex<T> where T is whatever type real_part and imag_part used.\n                - R has the same dimensions as real_part and imag_part\n                - for all valid r and c:\n                  R(r,c) == std::complex(real_part(r,c),imag_part(r,c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Trigonometric Functions \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sin (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::sin(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp cos (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::cos(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp tan (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::tan(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp asin (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::asin(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp acos (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::acos(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp atan (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::atan(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sinh (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::sinh(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp cosh (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::cosh(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp tanh (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::tanh(m(r,c)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp soft_max (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == float, double, or long double\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R(r,c) == std::exp(m(r,c)) / sum(std::exp(m))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_MATH_FUNCTIONS_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_op.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_OP_H_\n#define DLIB_MATRIx_OP_H_\n\n#include \"matrix_exp.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename OP >\n    class matrix_op;\n\n    template < typename OP >\n    struct matrix_traits<matrix_op<OP> >\n    {\n        typedef typename OP::type type;\n        typedef typename OP::const_ret_type const_ret_type;\n        typedef typename OP::mem_manager_type mem_manager_type;\n        typedef typename OP::layout_type layout_type;\n        const static long NR = OP::NR;\n        const static long NC = OP::NC;\n        const static long cost = OP::cost;\n    };\n\n    template <\n        typename OP\n        >\n    class matrix_op : public matrix_exp<matrix_op<OP> >\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                The matrix_op is simply a tool for reducing the amount of boilerplate\n                you need to write when creating matrix expressions.  \n        !*/\n\n    public:\n        typedef typename matrix_traits<matrix_op>::type type;\n        typedef typename matrix_traits<matrix_op>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_op>::mem_manager_type mem_manager_type;\n        typedef typename matrix_traits<matrix_op>::layout_type layout_type;\n        const static long NR = matrix_traits<matrix_op>::NR;\n        const static long NC = matrix_traits<matrix_op>::NC;\n        const static long cost = matrix_traits<matrix_op>::cost;\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1>\n        matrix_op (T1); \n    public:\n\n        matrix_op (\n            const OP& op_\n        ) :\n            op(op_)\n        {}\n\n        const_ret_type operator() (\n            long r, \n            long c\n        ) const { return op.apply(r,c); }\n\n        const_ret_type operator() ( long i ) const \n        { return matrix_exp<matrix_op>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return op.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return op.destructively_aliases(item); }\n\n        long nr (\n        ) const { return op.nr(); }\n\n        long nc (\n        ) const { return op.nc(); }\n\n\n        const OP op;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename OP >\n    class matrix_diag_op;\n\n    template < typename OP >\n    struct matrix_traits<matrix_diag_op<OP> >\n    {\n        typedef typename OP::type type;\n        typedef typename OP::const_ret_type const_ret_type;\n        typedef typename OP::mem_manager_type mem_manager_type;\n        typedef typename OP::layout_type layout_type;\n        const static long NR = OP::NR;\n        const static long NC = OP::NC;\n        const static long cost = OP::cost;\n    };\n\n    template <\n        typename OP\n        >\n    class matrix_diag_op : public matrix_diag_exp<matrix_diag_op<OP> >\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                The matrix_diag_op is simply a tool for reducing the amount of boilerplate\n                you need to write when creating matrix expressions.  \n        !*/\n\n    public:\n        typedef typename matrix_traits<matrix_diag_op>::type type;\n        typedef typename matrix_traits<matrix_diag_op>::const_ret_type const_ret_type;\n        typedef typename matrix_traits<matrix_diag_op>::mem_manager_type mem_manager_type;\n        typedef typename matrix_traits<matrix_diag_op>::layout_type layout_type;\n        const static long NR = matrix_traits<matrix_diag_op>::NR;\n        const static long NC = matrix_traits<matrix_diag_op>::NC;\n        const static long cost = matrix_traits<matrix_diag_op>::cost;\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1>\n        matrix_diag_op (T1); \n    public:\n\n        matrix_diag_op (\n            const OP& op_\n        ) :\n            op(op_)\n        {}\n\n        const_ret_type operator() (\n            long r, \n            long c\n        ) const { return op.apply(r,c); }\n\n        const_ret_type operator() ( long i ) const \n        { return matrix_exp<matrix_diag_op>::operator()(i); }\n\n        template <typename U>\n        bool aliases (\n            const matrix_exp<U>& item\n        ) const { return op.aliases(item); }\n\n        template <typename U>\n        bool destructively_aliases (\n            const matrix_exp<U>& item\n        ) const { return op.destructively_aliases(item); }\n\n        long nr (\n        ) const { return op.nr(); }\n\n        long nc (\n        ) const { return op.nc(); }\n\n\n        const OP op;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct does_not_alias \n    {\n        /*!\n            This is a partial implementation of a matrix operator that never aliases\n            another expression.\n        !*/\n\n        template <typename U> bool aliases               ( const U& ) const { return false; }\n        template <typename U> bool destructively_aliases ( const U& ) const { return false; }\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct basic_op_m \n    {\n        /*!\n            This is a partial implementation of a matrix operator that preserves\n            the dimensions of its argument and doesn't have destructive aliasing.\n        !*/\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1>\n        basic_op_m (T1); \n    public:\n\n        basic_op_m(\n            const M& m_\n        ) : m(m_){}\n\n        const M& m;\n\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m.destructively_aliases(item); }\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct basic_op_mm \n    {\n        /*!\n            This is a partial implementation of a matrix operator that preserves\n            the dimensions of its arguments and doesn't have destructive aliasing.\n        !*/\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1, typename T2>\n        basic_op_mm (T1, T2); \n    public:\n\n        basic_op_mm(\n            const M1& m1_,\n            const M2& m2_\n        ) : m1(m1_), m2(m2_){}\n\n        const M1& m1;\n        const M2& m2;\n\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.destructively_aliases(item); }\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct basic_op_mmm \n    {\n        /*!\n            This is a partial implementation of a matrix operator that preserves\n            the dimensions of its arguments and doesn't have destructive aliasing.\n        !*/\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1, typename T2, typename T3>\n        basic_op_mmm (T1, T2, T3); \n    public:\n\n        basic_op_mmm(\n            const M1& m1_,\n            const M2& m2_,\n            const M3& m3_\n        ) : m1(m1_), m2(m2_), m3(m3_){}\n\n        const M1& m1;\n        const M2& m2;\n        const M3& m3;\n\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.destructively_aliases(item) ||\n                 m3.destructively_aliases(item);}\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3, typename M4>\n    struct basic_op_mmmm \n    {\n        /*!\n            This is a partial implementation of a matrix operator that preserves\n            the dimensions of its arguments and doesn't have destructive aliasing.\n        !*/\n\n    private:\n        // This constructor exists simply for the purpose of causing a compile time error if\n        // someone tries to create an instance of this object with the wrong kind of object.\n        template <typename T1, typename T2, typename T3, typename T4>\n        basic_op_mmmm (T1, T2, T3, T4); \n    public:\n\n        basic_op_mmmm(\n            const M1& m1_,\n            const M2& m2_,\n            const M3& m3_,\n            const M4& m4_\n        ) : m1(m1_), m2(m2_), m3(m3_), m4(m4_){}\n\n        const M1& m1;\n        const M2& m2;\n        const M3& m3;\n        const M4& m4;\n\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item) || m4.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.destructively_aliases(item) ||\n                 m3.destructively_aliases(item) || m4.destructively_aliases(item);}\n\n    }; \n\n// ----------------------------------------------------------------------------------------\n\n#define DLIB_DEFINE_OP_M(op_name, function, extra_cost)                                         \\\n    template <typename M>                                                                       \\\n    struct op_name                                                                              \\\n    {                                                                                           \\\n        op_name(                                                                                \\\n            const M& m_                                                                         \\\n        ) : m(m_){}                                                                             \\\n                                                                                                \\\n        const M& m;                                                                             \\\n                                                                                                \\\n        const static long cost = M::cost+(extra_cost);                                          \\\n        const static long NR = M::NR;                                                           \\\n        const static long NC = M::NC;                                                           \\\n        typedef typename M::type type;                                                          \\\n        typedef const typename M::type const_ret_type;                                          \\\n        typedef typename M::mem_manager_type mem_manager_type;                                  \\\n        typedef typename M::layout_type layout_type;                                            \\\n                                                                                                \\\n        const_ret_type apply (long r, long c) const { return function(m(r,c)); }                \\\n                                                                                                \\\n        long nr () const { return m.nr(); }                                                     \\\n        long nc () const { return m.nc(); }                                                     \\\n                                                                                                \\\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \\\n        { return m.aliases(item); }                                                             \\\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \\\n        { return m.destructively_aliases(item); }                                               \\\n                                                                                                \\\n    }\n\n#define DLIB_DEFINE_FUNCTION_M(op_name, name, function, extra_cost)                             \\\n    DLIB_DEFINE_OP_M(op_name, function, extra_cost);                                            \\\n    template < typename M >                                                                     \\\n    const matrix_op<op_name<M> > name ( const matrix_exp<M>& m)                                 \\\n    {                                                                                           \\\n        typedef op_name<M> op;                                                                  \\\n        return matrix_op<op>(op(m.ref()));                                                      \\\n    }\n\n// ----------------------------------------------------------------------------------------\n\n#define DLIB_DEFINE_OP_MS(op_name, function, extra_cost)                                        \\\n    template <typename M, typename S>                                                           \\\n    struct op_name                                                                              \\\n    {                                                                                           \\\n        op_name(                                                                                \\\n            const M& m_,                                                                        \\\n            const S& s_                                                                         \\\n        ) : m(m_), s(s_){}                                                                      \\\n                                                                                                \\\n        const M& m;                                                                             \\\n        const S s;                                                                              \\\n                                                                                                \\\n        const static long cost = M::cost+(extra_cost);                                          \\\n        const static long NR = M::NR;                                                           \\\n        const static long NC = M::NC;                                                           \\\n        typedef typename M::type type;                                                          \\\n        typedef const typename M::type const_ret_type;                                          \\\n        typedef typename M::mem_manager_type mem_manager_type;                                  \\\n        typedef typename M::layout_type layout_type;                                            \\\n                                                                                                \\\n        const_ret_type apply (long r, long c) const { return function(m(r,c), s); }             \\\n                                                                                                \\\n        long nr () const { return m.nr(); }                                                     \\\n        long nc () const { return m.nc(); }                                                     \\\n                                                                                                \\\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \\\n        { return m.aliases(item); }                                                             \\\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \\\n        { return m.destructively_aliases(item); }                                               \\\n                                                                                                \\\n    }\n\n#define DLIB_DEFINE_FUNCTION_MS(op_name, name, function, extra_cost)                            \\\n    DLIB_DEFINE_OP_MS(op_name, function, extra_cost);                                           \\\n    template < typename M, typename S >                                                         \\\n    const matrix_op<op_name<M, S> > name ( const matrix_exp<M>& m, const S& s)                  \\\n    {                                                                                           \\\n        typedef op_name<M, S> op;                                                               \\\n        return matrix_op<op>(op(m.ref(), s));                                                   \\\n    }\n\n// ----------------------------------------------------------------------------------------\n\n#define DLIB_DEFINE_OP_SM(op_name, function, extra_cost)                                        \\\n    template <typename S, typename M>                                                           \\\n    struct op_name                                                                              \\\n    {                                                                                           \\\n        op_name(                                                                                \\\n            const S& s_,                                                                        \\\n            const M& m_                                                                         \\\n        ) : m(m_), s(s_){}                                                                      \\\n                                                                                                \\\n        const M& m;                                                                             \\\n        const S s;                                                                              \\\n                                                                                                \\\n        const static long cost = M::cost+(extra_cost);                                          \\\n        const static long NR = M::NR;                                                           \\\n        const static long NC = M::NC;                                                           \\\n        typedef typename M::type type;                                                          \\\n        typedef const typename M::type const_ret_type;                                          \\\n        typedef typename M::mem_manager_type mem_manager_type;                                  \\\n        typedef typename M::layout_type layout_type;                                            \\\n                                                                                                \\\n        const_ret_type apply (long r, long c) const { return function(s, m(r,c)); }             \\\n                                                                                                \\\n        long nr () const { return m.nr(); }                                                     \\\n        long nc () const { return m.nc(); }                                                     \\\n                                                                                                \\\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const     \\\n        { return m.aliases(item); }                                                             \\\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const     \\\n        { return m.destructively_aliases(item); }                                               \\\n                                                                                                \\\n    }\n\n#define DLIB_DEFINE_FUNCTION_SM(op_name, name, function, extra_cost)                            \\\n    DLIB_DEFINE_OP_SM(op_name, function, extra_cost);                                           \\\n    template < typename S, typename M >                                                         \\\n    const matrix_op<op_name<S, M> > name (const S& s, const matrix_exp<M>& m)                   \\\n    {                                                                                           \\\n        typedef op_name<S, M> op;                                                               \\\n        return matrix_op<op>(op(s, m.ref()));                                                   \\\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_OP_H_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_qr.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n// This code was adapted from code from the JAMA part of NIST's TNT library.\n//    See: http://math.nist.gov/tnt/ \n#ifndef DLIB_MATRIX_QR_DECOMPOSITION_H\n#define DLIB_MATRIX_QR_DECOMPOSITION_H\n\n#include \"matrix.h\" \n#include \"matrix_utilities.h\"\n#include \"matrix_subexp.h\"\n\n#ifdef DLIB_USE_LAPACK\n#include \"lapack/geqrf.h\"\n#include \"lapack/ormqr.h\"\n#endif\n\n#include \"matrix_trsm.h\"\n\nnamespace dlib \n{\n\n    template <\n        typename matrix_exp_type\n        >\n    class qr_decomposition \n    {\n\n    public:\n\n        const static long NR = matrix_exp_type::NR;\n        const static long NC = matrix_exp_type::NC;\n        typedef typename matrix_exp_type::type type;\n        typedef typename matrix_exp_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_exp_type::layout_type layout_type;\n\n        typedef matrix<type,0,0,mem_manager_type,layout_type>  matrix_type;\n\n        // You have supplied an invalid type of matrix_exp_type.  You have\n        // to use this object with matrices that contain float or double type data.\n        COMPILE_TIME_ASSERT((is_same_type<float, type>::value || \n                             is_same_type<double, type>::value ));\n\n\n\n        template <typename EXP>\n        qr_decomposition(\n            const matrix_exp<EXP>& A\n        );\n\n        bool is_full_rank(\n        ) const;\n\n        long nr(\n        ) const;\n\n        long nc(\n        ) const;\n\n        const matrix_type get_r (\n        ) const;\n\n        const matrix_type get_q (\n        ) const;\n\n        template <typename T, long R, long C, typename MM, typename L>\n        void get_q (\n            matrix<T,R,C,MM,L>& Q\n        ) const;\n\n        template <typename EXP>\n        const matrix_type solve (\n            const matrix_exp<EXP>& B\n        ) const;\n\n    private:\n\n#ifndef DLIB_USE_LAPACK\n        template <typename EXP>\n        const matrix_type solve_mat (\n            const matrix_exp<EXP>& B\n        ) const;\n\n        template <typename EXP>\n        const matrix_type solve_vect (\n            const matrix_exp<EXP>& B\n        ) const;\n#endif\n\n\n        /** Array for internal storage of decomposition.\n        @serial internal array storage.\n        */\n        matrix<type,0,0,mem_manager_type,column_major_layout> QR_;\n\n        /** Row and column dimensions.\n        @serial column dimension.\n        @serial row dimension.\n        */\n        long m, n;\n\n        /** Array for internal storage of diagonal of R.\n        @serial diagonal of R.\n        */\n        typedef matrix<type,0,1,mem_manager_type,column_major_layout> column_vector_type;\n        column_vector_type tau;\n        column_vector_type Rdiag;\n\n\n    };\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                      Member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    qr_decomposition<matrix_exp_type>::\n    qr_decomposition(\n        const matrix_exp<EXP>& A\n    )\t\t\n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A.nr() >= A.nc() && A.size() > 0,\n            \"\\tqr_decomposition::qr_decomposition(A)\"\n            << \"\\n\\tInvalid inputs were given to this function\"\n            << \"\\n\\tA.nr():   \" << A.nr()\n            << \"\\n\\tA.nc():   \" << A.nc()\n            << \"\\n\\tA.size(): \" << A.size()\n            << \"\\n\\tthis:     \" << this\n            );\n\n\n        QR_ = A;\n        m = A.nr();\n        n = A.nc();\n\n#ifdef DLIB_USE_LAPACK\n\n        lapack::geqrf(QR_, tau);\n        Rdiag = diag(QR_);\n\n#else\n        Rdiag.set_size(n);\n        long i=0, j=0, k=0;\n\n        // Main loop.\n        for (k = 0; k < n; k++) \n        {\n            // Compute 2-norm of k-th column without under/overflow.\n            type nrm = 0;\n            for (i = k; i < m; i++) \n            {\n                nrm = hypot(nrm,QR_(i,k));\n            }\n\n            if (nrm != 0.0) \n            {\n                // Form k-th Householder vector.\n                if (QR_(k,k) < 0) \n                {\n                    nrm = -nrm;\n                }\n                for (i = k; i < m; i++) \n                {\n                    QR_(i,k) /= nrm;\n                }\n                QR_(k,k) += 1.0;\n\n                // Apply transformation to remaining columns.\n                for (j = k+1; j < n; j++) \n                {\n                    type s = 0.0; \n                    for (i = k; i < m; i++) \n                    {\n                        s += QR_(i,k)*QR_(i,j);\n                    }\n                    s = -s/QR_(k,k);\n                    for (i = k; i < m; i++) \n                    {\n                        QR_(i,j) += s*QR_(i,k);\n                    }\n                }\n            }\n            Rdiag(k) = -nrm;\n        }\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    long qr_decomposition<matrix_exp_type>::\n    nr (\n    ) const\n    {\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    long qr_decomposition<matrix_exp_type>::\n    nc (\n    ) const\n    {\n        return n;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    bool qr_decomposition<matrix_exp_type>::\n    is_full_rank(\n    ) const\t\t\n    {\n        type eps = max(abs(Rdiag));\n        if (eps != 0)\n            eps *= std::sqrt(std::numeric_limits<type>::epsilon())/100;\n        else\n            eps = 1;  // there is no max so just use 1\n\n        // check if any of the elements of Rdiag are effectively 0\n        return min(abs(Rdiag)) > eps;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::\n    get_r(\n    ) const\n    {\n        matrix_type R(n,n);\n        for (long i = 0; i < n; i++) \n        {\n            for (long j = 0; j < n; j++) \n            {\n                if (i < j) \n                {\n                    R(i,j) = QR_(i,j);\n                } \n                else if (i == j) \n                {\n                    R(i,j) = Rdiag(i);\n                } \n                else \n                {\n                    R(i,j) = 0.0;\n                }\n            }\n        }\n        return R;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::\n    get_q(\n    ) const\n    {\n        matrix_type Q;\n        get_q(Q);\n        return Q;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename T, long R, long C, typename MM, typename L>\n    void qr_decomposition<matrix_exp_type>::\n    get_q(\n        matrix<T,R,C,MM,L>& X\n    ) const\n    {\n#ifdef DLIB_USE_LAPACK\n        // Take only the first n columns of an identity matrix.  This way\n        // X ends up being an m by n matrix.\n        X = colm(identity_matrix<type>(m), range(0,n-1));\n\n        // Compute Y = Q*X \n        lapack::ormqr('L','N', QR_, tau, X);\n\n#else\n        long i=0, j=0, k=0;\n\n        X.set_size(m,n);\n        for (k = n-1; k >= 0; k--) \n        {\n            for (i = 0; i < m; i++) \n            {\n                X(i,k) = 0.0;\n            }\n            X(k,k) = 1.0;\n            for (j = k; j < n; j++) \n            {\n                if (QR_(k,k) != 0) \n                {\n                    type s = 0.0;\n                    for (i = k; i < m; i++) \n                    {\n                        s += QR_(i,k)*X(i,j);\n                    }\n                    s = -s/QR_(k,k);\n                    for (i = k; i < m; i++) \n                    {\n                        X(i,j) += s*QR_(i,k);\n                    }\n                }\n            }\n        }\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::\n    solve(\n        const matrix_exp<EXP>& B\n    ) const\n    {\n        COMPILE_TIME_ASSERT((is_same_type<type, typename EXP::type>::value));\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(B.nr() == nr(),\n            \"\\tconst matrix_type qr_decomposition::solve(B)\"\n            << \"\\n\\tInvalid inputs were given to this function\"\n            << \"\\n\\tB.nr():         \" << B.nr()\n            << \"\\n\\tnr():           \" << nr()\n            << \"\\n\\tthis:           \" << this\n            );\n\n#ifdef DLIB_USE_LAPACK\n\n        using namespace blas_bindings;\n        matrix<type,0,0,mem_manager_type,column_major_layout> X(B);\n        // Compute Y = transpose(Q)*B\n        lapack::ormqr('L','T',QR_, tau, X);\n        // Solve R*X = Y;\n        triangular_solver(CblasLeft, CblasUpper, CblasNoTrans, CblasNonUnit, QR_, X, n);\n\n        /* return n x nx portion of X */\n        return subm(X,0,0,n,B.nc());\n\n#else\n        // just call the right version of the solve function\n        if (B.nc() == 1)\n            return solve_vect(B);\n        else\n            return solve_mat(B);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                           Private member functions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n#ifndef DLIB_USE_LAPACK\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::\n    solve_vect(\n        const matrix_exp<EXP>& B\n    ) const\n    {\n\n        column_vector_type x(B);\n\n        // Compute Y = transpose(Q)*B\n        for (long k = 0; k < n; k++) \n        {\n            type s = 0.0; \n            for (long i = k; i < m; i++) \n            {\n                s += QR_(i,k)*x(i);\n            }\n            s = -s/QR_(k,k);\n            for (long i = k; i < m; i++) \n            {\n                x(i) += s*QR_(i,k);\n            }\n        }\n        // Solve R*X = Y;\n        for (long k = n-1; k >= 0; k--) \n        {\n            x(k) /= Rdiag(k);\n            for (long i = 0; i < k; i++) \n            {\n                x(i) -= x(k)*QR_(i,k);\n            }\n        }\n\n\n        /* return n x 1 portion of x */\n        return colm(x,0,n);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename matrix_exp_type>\n    template <typename EXP>\n    const typename qr_decomposition<matrix_exp_type>::matrix_type qr_decomposition<matrix_exp_type>::\n    solve_mat(\n        const matrix_exp<EXP>& B\n    ) const\n    {\n        const long nx = B.nc(); \n        matrix_type X(B);\n        long i=0, j=0, k=0;\n\n        // Compute Y = transpose(Q)*B\n        for (k = 0; k < n; k++) \n        {\n            for (j = 0; j < nx; j++) \n            {\n                type s = 0.0; \n                for (i = k; i < m; i++) \n                {\n                    s += QR_(i,k)*X(i,j);\n                }\n                s = -s/QR_(k,k);\n                for (i = k; i < m; i++) \n                {\n                    X(i,j) += s*QR_(i,k);\n                }\n            }\n        }\n        // Solve R*X = Y;\n        for (k = n-1; k >= 0; k--) \n        {\n            for (j = 0; j < nx; j++) \n            {\n                X(k,j) /= Rdiag(k);\n            }\n            for (i = 0; i < k; i++) \n            {\n                for (j = 0; j < nx; j++) \n                {\n                    X(i,j) -= X(k,j)*QR_(i,k);\n                }\n            }\n        }\n\n        /* return n x nx portion of X */\n        return subm(X,0,0,n,nx);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_USE_LAPACK not defined\n\n} \n\n#endif // DLIB_MATRIX_QR_DECOMPOSITION_H \n\n\n\n"
  },
  {
    "path": "dlib/matrix/matrix_read_from_istream.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_READ_FROM_ISTREAM_H_h_\n#define DLIB_MATRIx_READ_FROM_ISTREAM_H_h_\n\n#include \"matrix.h\"\n#include <vector>\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        inline bool next_is_whitespace (\n            std::istream& in\n        )\n        {\n            return in.peek() == '\\n' ||\n                in.peek() == ' ' || \n                in.peek() == ',' || \n                in.peek() == ';' ||\n                in.peek() == '\\t' ||\n                in.peek() == '\\r';\n        }\n    }\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    std::istream& operator>> (\n        std::istream& in,\n        matrix<T,NR,NC,MM,L>& m\n    )\n    {\n        using namespace dlib::impl;\n        long num_rows = 0;\n        std::vector<T> buf;\n        buf.reserve(100);\n\n        // eat any leading whitespace\n        while (next_is_whitespace(in))\n            in.get();\n\n        bool at_start_of_line = true;\n        bool stop = false;\n        while(!stop && in.peek() != EOF)\n        {\n            T temp;\n            in >> temp;\n            if (!in)\n                return in;\n\n            buf.push_back(temp);\n            if (at_start_of_line)\n            {\n                at_start_of_line = false;\n                ++num_rows;\n            }\n\n            // Eat next block of whitespace but also note if we hit the start of the next\n            // line. \n            while (next_is_whitespace(in))\n            {\n                if (at_start_of_line && in.peek() == '\\n')\n                {\n                    stop = true;\n                    break;\n                }\n\n                if (in.get() == '\\n')\n                    at_start_of_line = true;\n            }\n        }\n\n        // It's an error for there to not be any matrix data in the input stream\n        if (num_rows == 0)\n        {\n            in.clear(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n        const long num_cols = buf.size()/num_rows;\n        // It's also an error if the sizes don't make sense.\n        if (num_rows*num_cols != (long)buf.size() ||\n            (NR != 0 && NR != num_rows) ||\n            (NC != 0 && NC != num_cols))\n        {\n            in.clear(in.rdstate() | std::ios::failbit);\n            return in;\n        }\n\n\n        m = reshape(mat(buf),num_rows, buf.size()/num_rows);\n\n        if (in.eof())\n        {\n            // Clear the eof and fail bits since this is caused by peeking at the EOF.\n            // But in the current case, we have successfully read the matrix.\n            in.clear(in.rdstate() & (~(std::ios::eofbit | std::ios::failbit)));\n        }\n        return in;\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_MATRIx_READ_FROM_ISTREAM_H_h_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_subexp.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_SUBEXP_\n#define DLIB_MATRIx_SUBEXP_\n\n#include \"matrix_subexp_abstract.h\"\n#include \"matrix_op.h\"\n#include \"matrix.h\"\n#include \"../geometry/rectangle.h\"\n#include \"matrix_expressions.h\"\n#include \"matrix_mat.h\"\n\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    template <long start, long inc, long end>\n    const matrix_range_static_exp<start,inc,end> range (\n    ) \n    { \n        COMPILE_TIME_ASSERT(inc > 0);\n        return matrix_range_static_exp<start,inc,end>(); \n    }\n\n    template <long start, long end>\n    const matrix_range_static_exp<start,1,end> range (\n    ) \n    { \n        return matrix_range_static_exp<start,1,end>(); \n    }\n\n    inline const matrix_range_exp<long> range (\n        long start,\n        long end\n    ) \n    { \n        return matrix_range_exp<long>(start,end); \n    }\n\n    inline const matrix_range_exp<long> range (\n        long start,\n        long inc,\n        long end\n    ) \n    { \n        DLIB_ASSERT(inc > 0, \n            \"\\tconst matrix_exp range(start, inc, end)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tstart: \" << start \n            << \"\\n\\tinc:   \" << inc\n            << \"\\n\\tend:   \" << end\n            );\n\n        return matrix_range_exp<long>(start,inc,end); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_subm \n    {\n        op_subm (\n            const M& m_x,\n            const long& r_x,\n            const long& c_x,\n            const long& nr_x,\n            const long& nc_x\n        ) : m(m_x), r_(r_x), c_(c_x), nr_(nr_x), nc_(nc_x) { }\n\n        const M& m;\n        const long r_;\n        const long c_;\n        const long nr_;\n        const long nc_;\n\n        const static long cost = M::cost+1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const static long NR = 0;\n        const static long NC = 0;\n\n        const_ret_type apply ( long r, long c) const { return m(r+r_,c+c_); }\n\n        long nr () const { return nr_; }\n        long nc () const { return nc_; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); } \n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_subm<EXP> > subm (\n        const matrix_exp<EXP>& m,\n        long r, \n        long c,\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(), \n            \"\\tconst matrix_exp subm(const matrix_exp& m, r, c, nr, nc)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tr:      \" << r \n            << \"\\n\\tc:      \" << c \n            << \"\\n\\tnr:     \" << nr \n            << \"\\n\\tnc:     \" << nc \n            );\n\n        typedef op_subm<EXP> op;\n        return matrix_op<op>(op(m.ref(),r,c,nr,nc));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_subm<EXP> > subm_clipped (\n        const matrix_exp<EXP>& m,\n        long r, \n        long c,\n        long nr,\n        long nc\n    )\n    {\n        rectangle box(c,r,c+nc-1,r+nr-1);\n        box = box.intersect(get_rect(m));\n        typedef op_subm<EXP> op;\n        return matrix_op<op>(op(m.ref(),box.top(),box.left(),box.height(),box.width()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_subm<EXP> > subm (\n        const matrix_exp<EXP>& m,\n        const rectangle& rect\n    )\n    {\n        DLIB_ASSERT(get_rect(m).contains(rect) == true, \n            \"\\tconst matrix_exp subm(const matrix_exp& m, const rectangle& rect)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trect.left():   \" << rect.left()\n            << \"\\n\\trect.top():    \" << rect.top()\n            << \"\\n\\trect.right():  \" << rect.right()\n            << \"\\n\\trect.bottom(): \" << rect.bottom()\n            );\n\n        typedef op_subm<EXP> op;\n        return matrix_op<op>(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_subm<EXP> > subm_clipped (\n        const matrix_exp<EXP>& m,\n        rectangle rect\n    )\n    {\n        rect = rect.intersect(get_rect(m));\n\n        typedef op_subm<EXP> op;\n        return matrix_op<op>(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_subm_range \n    {\n        op_subm_range( const M1& m1_, const M2& rows_, const M3& cols_) : \n            m1(m1_), rows(rows_), cols(cols_) {}\n        const M1& m1;\n        const M2& rows;\n        const M3& cols;\n\n        const static long cost = M1::cost+M2::cost+M3::cost;\n        typedef typename M1::type type;\n        typedef typename M1::const_ret_type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M2::NC*M2::NR;\n        const static long NC = M3::NC*M3::NR;\n\n        const_ret_type apply ( long r, long c) const { return m1(rows(r),cols(c)); }\n\n        long nr () const { return rows.size(); }\n        long nc () const { return cols.size(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }\n    };\n\n    template <\n        typename EXP,\n        typename EXPr,\n        typename EXPc\n        >\n    const matrix_op<op_subm_range<EXP,EXPr,EXPc> > subm (\n        const matrix_exp<EXP>& m,\n        const matrix_exp<EXPr>& rows,\n        const matrix_exp<EXPc>& cols\n    )\n    {\n        // the rows and cols matrices must contain integer elements \n        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPr::type>::is_integer);\n        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPc::type>::is_integer);\n\n        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&\n                    (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1), \n            \"\\tconst matrix_exp subm(const matrix_exp& m, const matrix_exp& rows, const matrix_exp& cols)\"\n            << \"\\n\\tYou have given invalid arguments to this function\"\n            << \"\\n\\tm.nr():     \" << m.nr()\n            << \"\\n\\tm.nc():     \" << m.nc() \n            << \"\\n\\tmin(rows):  \" << min(rows) \n            << \"\\n\\tmax(rows):  \" << max(rows) \n            << \"\\n\\tmin(cols):  \" << min(cols) \n            << \"\\n\\tmax(cols):  \" << max(cols) \n            << \"\\n\\trows.nr():  \" << rows.nr()\n            << \"\\n\\trows.nc():  \" << rows.nc()\n            << \"\\n\\tcols.nr():  \" << cols.nr()\n            << \"\\n\\tcols.nc():  \" << cols.nc()\n            );\n\n        typedef op_subm_range<EXP,EXPr,EXPc> op;\n        return matrix_op<op>(op(m.ref(),rows.ref(),cols.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_rowm \n    {\n        op_rowm(const M& m_, const long& row_) : m(m_), row(row_) {}\n        const M& m;\n        const long row;\n\n        const static long cost = M::cost;\n        const static long NR = 1;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long, long c) const { return m(row,c); }\n\n        long nr () const { return 1; }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_rowm<EXP> > rowm (\n        const matrix_exp<EXP>& m,\n        long row\n    )\n    {\n        DLIB_ASSERT(row >= 0 && row < m.nr(), \n            \"\\tconst matrix_exp rowm(const matrix_exp& m, row)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trow:    \" << row \n            );\n\n        typedef op_rowm<EXP> op;\n        return matrix_op<op>(op(m.ref(),row));\n    }\n\n    template <typename EXP>\n    struct rowm_exp\n    {\n        typedef matrix_op<op_rowm<EXP> > type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_rowm2 \n    {\n        op_rowm2(const M& m_, const long& row_, const long& len) : m(m_), row(row_), length(len) {}\n        const M& m;\n        const long row;\n        const long length;\n\n        const static long cost = M::cost;\n        const static long NR = 1;\n        const static long NC = 0;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long , long c) const { return m(row,c); }\n\n        long nr () const { return 1; }\n        long nc () const { return length; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_rowm2<EXP> > rowm (\n        const matrix_exp<EXP>& m,\n        long row,\n        long length\n    )\n    {\n        DLIB_ASSERT(row >= 0 && row < m.nr() && \n                    length >= 0 && length <= m.nc(), \n            \"\\tconst matrix_exp rowm(const matrix_exp& m, row, length)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trow:    \" << row \n            << \"\\n\\tlength: \" << length \n            );\n\n        typedef op_rowm2<EXP> op;\n        return matrix_op<op>(op(m.ref(), row, length));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_rowm_range \n    {\n        op_rowm_range( const M1& m1_, const M2& rows_) : m1(m1_), rows(rows_) {}\n        const M1& m1;\n        const M2& rows;\n\n        const static long cost = M1::cost+M2::cost;\n        typedef typename M1::type type;\n        typedef typename M1::const_ret_type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M2::NC*M2::NR;\n        const static long NC = M1::NC;\n\n        const_ret_type apply ( long r, long c) const { return m1(rows(r),c); }\n\n        long nr () const { return rows.size(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || rows.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || rows.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_rowm_range<EXP1,EXP2> > rowm (\n        const matrix_exp<EXP1>& m,\n        const matrix_exp<EXP2>& rows\n    )\n    {\n        // the rows matrix must contain integer elements \n        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);\n\n#ifdef ENABLE_ASSERTS\n        if (rows.size() != 0) {\n            DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1), \n                \"\\tconst matrix_exp rowm(const matrix_exp& m, const matrix_exp& rows)\"\n                << \"\\n\\tYou have given invalid arguments to this function\"\n                << \"\\n\\tm.nr():     \" << m.nr()\n                << \"\\n\\tm.nc():     \" << m.nc() \n                << \"\\n\\tmin(rows):  \" << min(rows) \n                << \"\\n\\tmax(rows):  \" << max(rows) \n                << \"\\n\\trows.nr():  \" << rows.nr()\n                << \"\\n\\trows.nc():  \" << rows.nc()\n            );\n        }\n#endif // ENABLE_ASSERTS\n\n        typedef op_rowm_range<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),rows.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_colm \n    {\n        op_colm(const M& m_, const long& col_) : m(m_), col(col_) {}\n        const M& m;\n        const long col;\n\n        const static long cost = M::cost;\n        const static long NR = M::NR;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long) const { return m(r,col); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_colm<EXP> > colm (\n        const matrix_exp<EXP>& m,\n        long col \n    )\n    {\n        DLIB_ASSERT(col >= 0 && col < m.nc(), \n            \"\\tconst matrix_exp colm(const matrix_exp& m, row)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tcol:    \" << col \n            );\n\n        typedef op_colm<EXP> op;\n        return matrix_op<op>(op(m.ref(),col));\n    }\n\n    template <typename EXP>\n    struct colm_exp\n    {\n        typedef matrix_op<op_colm<EXP> > type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_colm2 \n    {\n        op_colm2(const M& m_, const long& col_, const long& len) : m(m_), col(col_), length(len) {}\n        const M& m;\n        const long col;\n        const long length;\n\n        const static long cost = M::cost;\n        const static long NR = 0;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long ) const { return m(r,col); }\n\n        long nr () const { return length; }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_colm2<EXP> > colm (\n        const matrix_exp<EXP>& m,\n        long col,\n        long length\n    )\n    {\n        DLIB_ASSERT(col >= 0 && col < m.nc() && \n                    length >= 0 && length <= m.nr(), \n            \"\\tconst matrix_exp colm(const matrix_exp& m, col, length)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tcol:    \" << col \n            << \"\\n\\tlength: \" << length \n            );\n\n        typedef op_colm2<EXP> op;\n        return matrix_op<op>(op(m.ref(),col, length));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_colm_range \n    {\n        op_colm_range( const M1& m1_, const M2& cols_) : m1(m1_), cols(cols_) {}\n        const M1& m1;\n        const M2& cols;\n\n        typedef typename M1::type type;\n        typedef typename M1::const_ret_type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR;\n        const static long NC = M2::NC*M2::NR;\n        const static long cost = M1::cost+M2::cost;\n\n        const_ret_type apply (long r, long c) const { return m1(r,cols(c)); }\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return cols.size(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || cols.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || cols.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_colm_range<EXP1,EXP2> > colm (\n        const matrix_exp<EXP1>& m,\n        const matrix_exp<EXP2>& cols\n    )\n    {\n        // the rows matrix must contain integer elements \n        COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);\n\n#ifdef ENABLE_ASSERTS\n        if (cols.size() != 0) {\n            DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1), \n                \"\\tconst matrix_exp colm(const matrix_exp& m, const matrix_exp& cols)\"\n                << \"\\n\\tYou have given invalid arguments to this function\"\n                << \"\\n\\tm.nr():     \" << m.nr()\n                << \"\\n\\tm.nc():     \" << m.nc() \n                << \"\\n\\tmin(cols):  \" << min(cols) \n                << \"\\n\\tmax(cols):  \" << max(cols) \n                << \"\\n\\tcols.nr():  \" << cols.nr()\n                << \"\\n\\tcols.nc():  \" << cols.nc()\n            );\n        }\n#endif // ENABLE_ASSERTS\n\n        typedef op_colm_range<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),cols.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class assignable_ptr_matrix\n    {\n    public:\n        typedef T type;\n        typedef row_major_layout layout_type;\n        typedef matrix<T,0,0,default_memory_manager,layout_type> matrix_type;\n\n        assignable_ptr_matrix(\n            T* ptr_,\n            long nr_,\n            long nc_\n        ) : ptr(ptr_), height(nr_), width(nc_){}\n\n        T& operator() (\n            long r,\n            long c\n        )\n        {\n            return ptr[r*width + c];\n        }\n\n        const T& operator() (\n            long r,\n            long c\n        ) const\n        {\n            return ptr[r*width + c];\n        }\n\n        long nr() const { return height; }\n        long nc() const { return width; }\n\n        template <typename EXP>\n        assignable_ptr_matrix& operator= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            // You can only assign to a set_ptrm() expression with a source matrix that\n            // contains the same type of elements as the target (i.e. you can't mix double\n            // and float types).\n            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));\n\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_ptrm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(mat(ptr,height,width)) == false)\n            {\n                matrix_assign(*this, exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to ptr to \n                // avoid aliasing issues during the copy\n                this->operator=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_ptr_matrix& operator+= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            // You can only assign to a set_ptrm() expression with a source matrix that\n            // contains the same type of elements as the target (i.e. you can't mix double\n            // and float types).\n            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));\n\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_ptrm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(mat(ptr,height,width)) == false)\n            {\n                matrix_assign(*this, mat(ptr,height,width)+exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to ptr to \n                // avoid aliasing issues during the copy\n                this->operator+=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_ptr_matrix& operator-= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            // You can only assign to a set_ptrm() expression with a source matrix that\n            // contains the same type of elements as the target (i.e. you can't mix double\n            // and float types).\n            COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));\n\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_ptrm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(mat(ptr,height,width)) == false)\n            {\n                matrix_assign(*this, mat(ptr,height,width)-exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to ptr to \n                // avoid aliasing issues during the copy\n                this->operator-=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        assignable_ptr_matrix& operator= (\n            const T& value\n        )\n        {\n            const long size = width*height;\n            for (long i = 0; i < size; ++i)\n                ptr[i] = value;\n\n            return *this;\n        }\n\n        assignable_ptr_matrix& operator+= (\n            const T& value\n        )\n        {\n            const long size = width*height;\n            for (long i = 0; i < size; ++i)\n                ptr[i] += value;\n\n            return *this;\n        }\n\n        assignable_ptr_matrix& operator-= (\n            const T& value\n        )\n        {\n            const long size = width*height;\n            for (long i = 0; i < size; ++i)\n                ptr[i] -= value;\n\n            return *this;\n        }\n\n\n        T* ptr;\n        const long height;\n        const long width;\n    };\n\n\n    template <typename T>\n    assignable_ptr_matrix<T> set_ptrm (\n        T* ptr,\n        long nr,\n        long nc = 1\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\t assignable_matrix_expression set_ptrm(T* ptr, long nr, long nc)\"\n            << \"\\n\\t The dimensions can't be negative.\"\n            << \"\\n\\t nr: \" << nr\n            << \"\\n\\t nc: \" << nc\n            );\n\n\n        return assignable_ptr_matrix<T>(ptr,nr,nc);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    class assignable_sub_matrix\n    {\n    public:\n        typedef T type;\n        typedef l layout_type;\n        typedef matrix<T,NR,NC,mm,l> matrix_type;\n\n        assignable_sub_matrix(\n            matrix<T,NR,NC,mm,l>& m_,\n            long top_,\n            long left_,\n            long height_,\n            long width_\n        ) : m(m_), left(left_), top(top_), width(width_), height(height_) {}\n\n        T& operator() (\n            long r,\n            long c\n        )\n        {\n            return m(r+top,c+left);\n        }\n\n        const T& operator() (\n            long r,\n            long c\n        ) const\n        {\n            return m(r+top,c+left);\n        }\n\n        long nr() const { return height; }\n        long nc() const { return width; }\n\n        template <typename EXP>\n        assignable_sub_matrix& operator= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_subm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_sub_matrix& operator+= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_subm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, subm(m,top,left,height,width)+exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator+=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_sub_matrix& operator-= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == height && exp.nc() == width,\n                \"\\tassignable_matrix_expression set_subm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\twidth (target matrix):    \" << width\n                << \"\\n\\theight (target matrix):   \" << height\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, subm(m,top,left,height,width)-exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator-=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        assignable_sub_matrix& operator= (\n            const T& value\n        )\n        {\n            const long bottom = top+height-1;\n            const long right = left+width-1;\n            for (long r = top; r <= bottom; ++r)\n            {\n                for (long c = left; c <= right; ++c)\n                {\n                    m(r,c) = value;\n                }\n            }\n\n            return *this;\n        }\n\n        assignable_sub_matrix& operator+= (\n            const T& value\n        )\n        {\n            const long bottom = top+height-1;\n            const long right = left+width-1;\n            for (long r = top; r <= bottom; ++r)\n            {\n                for (long c = left; c <= right; ++c)\n                {\n                    m(r,c) += value;\n                }\n            }\n\n            return *this;\n        }\n\n        assignable_sub_matrix& operator-= (\n            const T& value\n        )\n        {\n            const long bottom = top+height-1;\n            const long right = left+width-1;\n            for (long r = top; r <= bottom; ++r)\n            {\n                for (long c = left; c <= right; ++c)\n                {\n                    m(r,c) -= value;\n                }\n            }\n\n            return *this;\n        }\n\n\n        matrix<T,NR,NC,mm,l>& m;\n        const long left, top, width, height;\n    };\n\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    assignable_sub_matrix<T,NR,NC,mm,l> set_subm (\n        matrix<T,NR,NC,mm,l>& m,\n        const rectangle& rect\n    )\n    {\n        DLIB_ASSERT(get_rect(m).contains(rect) == true, \n            \"\\tassignable_matrix_expression set_subm(matrix& m, const rectangle& rect)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trect.left():   \" << rect.left()\n            << \"\\n\\trect.top():    \" << rect.top()\n            << \"\\n\\trect.right():  \" << rect.right()\n            << \"\\n\\trect.bottom(): \" << rect.bottom()\n            );\n\n\n        return assignable_sub_matrix<T,NR,NC,mm,l>(m,rect.top(), rect.left(), rect.height(), rect.width());\n    }\n\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    assignable_sub_matrix<T,NR,NC,mm,l> set_subm (\n        matrix<T,NR,NC,mm,l>& m,\n        long r, \n        long c,\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(), \n                    \"\\tassignable_matrix_expression set_subm(matrix& m, r, c, nr, nc)\"\n                    << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n                    << \"\\n\\tm.nr(): \" << m.nr()\n                    << \"\\n\\tm.nc(): \" << m.nc() \n                    << \"\\n\\tr:      \" << r \n                    << \"\\n\\tc:      \" << c \n                    << \"\\n\\tnr:     \" << nr \n                    << \"\\n\\tnc:     \" << nc \n        );\n\n        return assignable_sub_matrix<T,NR,NC,mm,l>(m,r,c, nr, nc);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>\n    class assignable_sub_range_matrix\n    {\n    public:\n        typedef T type;\n        typedef l layout_type;\n        typedef matrix<T,NR,NC,mm,l> matrix_type;\n\n        assignable_sub_range_matrix(\n            matrix<T,NR,NC,mm,l>& m_,\n            const EXPr& rows_,\n            const EXPc& cols_\n        ) : m(m_), rows(rows_), cols(cols_) {}\n\n        T& operator() (\n            long r,\n            long c\n        )\n        {\n            return m(rows(r),cols(c));\n        }\n\n        long nr() const { return rows.size(); }\n        long nc() const { return cols.size(); }\n\n\n        template <typename EXP>\n        assignable_sub_range_matrix& operator= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),\n                \"\\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\trows.size() (target matrix):  \" << rows.size()\n                << \"\\n\\tcols.size() (target matrix):  \" << cols.size()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, exp);\n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_sub_range_matrix& operator+= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),\n                \"\\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\trows.size() (target matrix):  \" << rows.size()\n                << \"\\n\\tcols.size() (target matrix):  \" << cols.size()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, subm(m,rows,cols)+exp);\n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator+=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_sub_range_matrix& operator-= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),\n                \"\\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\trows.size() (target matrix):  \" << rows.size()\n                << \"\\n\\tcols.size() (target matrix):  \" << cols.size()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, subm(m,rows,cols)-exp);\n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator-=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        assignable_sub_range_matrix& operator= (\n            const T& value\n        )\n        {\n            for (long r = 0; r < rows.size(); ++r)\n            {\n                for (long c = 0; c < cols.size(); ++c)\n                {\n                    m(rows(r),cols(c)) = value;\n                }\n            }\n\n            return *this;\n        }\n\n        assignable_sub_range_matrix& operator+= (\n            const T& value\n        )\n        {\n            for (long r = 0; r < rows.size(); ++r)\n            {\n                for (long c = 0; c < cols.size(); ++c)\n                {\n                    m(rows(r),cols(c)) += value;\n                }\n            }\n\n            return *this;\n        }\n\n        assignable_sub_range_matrix& operator-= (\n            const T& value\n        )\n        {\n            for (long r = 0; r < rows.size(); ++r)\n            {\n                for (long c = 0; c < cols.size(); ++c)\n                {\n                    m(rows(r),cols(c)) -= value;\n                }\n            }\n\n            return *this;\n        }\n\n    private:\n\n        matrix<T,NR,NC,mm,l>& m;\n        const EXPr rows;\n        const EXPc cols;\n    };\n\n    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>\n    assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc > set_subm (\n        matrix<T,NR,NC,mm,l>& m,\n        const matrix_exp<EXPr>& rows,\n        const matrix_exp<EXPc>& cols\n    )\n    {\n        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&\n                    (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1), \n            \"\\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp& rows, const matrix_exp& cols)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr():     \" << m.nr()\n            << \"\\n\\tm.nc():     \" << m.nc() \n            << \"\\n\\tmin(rows):  \" << min(rows) \n            << \"\\n\\tmax(rows):  \" << max(rows) \n            << \"\\n\\tmin(cols):  \" << min(cols) \n            << \"\\n\\tmax(cols):  \" << max(cols) \n            << \"\\n\\trows.nr():  \" << rows.nr()\n            << \"\\n\\trows.nc():  \" << rows.nc()\n            << \"\\n\\tcols.nr():  \" << cols.nr()\n            << \"\\n\\tcols.nc():  \" << cols.nc()\n            );\n\n        return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc >(m,rows.ref(),cols.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename mm, typename l, typename EXPr>\n    assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> > set_rowm (\n        matrix<T,NR,NC,mm,l>& m,\n        const matrix_exp<EXPr>& rows\n    )\n    {\n        DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1), \n            \"\\tassignable_matrix_expression set_rowm(matrix& m, const matrix_exp& rows)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr():     \" << m.nr()\n            << \"\\n\\tm.nc():     \" << m.nc() \n            << \"\\n\\tmin(rows):  \" << min(rows) \n            << \"\\n\\tmax(rows):  \" << max(rows) \n            << \"\\n\\trows.nr():  \" << rows.nr()\n            << \"\\n\\trows.nc():  \" << rows.nc()\n            );\n\n        return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> >(m,rows.ref(),range(0,m.nc()-1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename mm, typename l, typename EXPc>\n    assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc > set_colm (\n        matrix<T,NR,NC,mm,l>& m,\n        const matrix_exp<EXPc>& cols\n    )\n    {\n        DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1), \n            \"\\tassignable_matrix_expression set_colm(matrix& m, const matrix_exp& cols)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr():     \" << m.nr()\n            << \"\\n\\tm.nc():     \" << m.nc() \n            << \"\\n\\tmin(cols):  \" << min(cols) \n            << \"\\n\\tmax(cols):  \" << max(cols) \n            << \"\\n\\tcols.nr():  \" << cols.nr()\n            << \"\\n\\tcols.nc():  \" << cols.nc()\n            );\n\n        return assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc >(m,range(0,m.nr()-1),cols.ref());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    class assignable_col_matrix\n    {\n    public:\n        typedef T type;\n        typedef l layout_type;\n        typedef matrix<T,NR,NC,mm,l> matrix_type;\n\n        assignable_col_matrix(\n            matrix<T,NR,NC,mm,l>& m_,\n            const long col_ \n        ) : m(m_), col(col_) {}\n\n        T& operator() (\n            long r,\n            long \n        )\n        {\n            return m(r,col);\n        }\n\n        const T& operator() (\n            long r,\n            long \n        ) const\n        {\n            return m(r,col);\n        }\n\n        long nr() const { return m.nr(); }\n        long nc() const { return 1; }\n\n        template <typename EXP>\n        assignable_col_matrix& operator= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),\n                \"\\tassignable_matrix_expression set_colm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nr() (target matrix):   \" << m.nr()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_col_matrix& operator+= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),\n                \"\\tassignable_matrix_expression set_colm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nr() (target matrix):   \" << m.nr()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, colm(m,col)+exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator+=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_col_matrix& operator-= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),\n                \"\\tassignable_matrix_expression set_colm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nr() (target matrix):   \" << m.nr()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, colm(m,col)-exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator-=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        assignable_col_matrix& operator= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nr(); ++i)\n            {\n                m(i,col) = value;\n            }\n\n            return *this;\n        }\n\n        assignable_col_matrix& operator+= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nr(); ++i)\n            {\n                m(i,col) += value;\n            }\n\n            return *this;\n        }\n\n        assignable_col_matrix& operator-= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nr(); ++i)\n            {\n                m(i,col) -= value;\n            }\n\n            return *this;\n        }\n\n\n        matrix<T,NR,NC,mm,l>& m;\n        const long col;\n    };\n\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    assignable_col_matrix<T,NR,NC,mm,l> set_colm (\n        matrix<T,NR,NC,mm,l>& m,\n        const long col \n    )\n    {\n        DLIB_ASSERT(col >= 0 && col < m.nc(), \n            \"\\tassignable_matrix_expression set_colm(matrix& m, col)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tcol:    \" << col \n            );\n\n\n        return assignable_col_matrix<T,NR,NC,mm,l>(m,col);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    class assignable_row_matrix\n    {\n    public:\n        typedef T type;\n        typedef l layout_type;\n        typedef matrix<T,NR,NC,mm,l> matrix_type;\n\n        assignable_row_matrix(\n            matrix<T,NR,NC,mm,l>& m_,\n            const long row_ \n        ) : m(m_), row(row_) {}\n\n\n        T& operator() (\n            long ,\n            long c\n        )\n        {\n            return m(row,c);\n        }\n\n        const T& operator() (\n            long ,\n            long c\n        ) const\n        {\n            return m(row,c);\n        }\n\n        long nr() const { return 1; }\n        long nc() const { return m.nc(); }\n\n\n        template <typename EXP>\n        assignable_row_matrix& operator= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),\n                \"\\tassignable_matrix_expression set_rowm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nc() (target matrix):   \" << m.nc()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_row_matrix& operator+= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),\n                \"\\tassignable_matrix_expression set_rowm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nc() (target matrix):   \" << m.nc()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, rowm(m,row)+exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator+=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        template <typename EXP>\n        assignable_row_matrix& operator-= (\n            const matrix_exp<EXP>& exp\n        ) \n        {\n            DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),\n                \"\\tassignable_matrix_expression set_rowm()\"\n                << \"\\n\\tYou have tried to assign to this object using a matrix that isn't the right size\"\n                << \"\\n\\texp.nr() (source matrix): \" << exp.nr()\n                << \"\\n\\texp.nc() (source matrix): \" << exp.nc() \n                << \"\\n\\tm.nc() (target matrix):   \" << m.nc()\n                );\n\n            if (exp.destructively_aliases(m) == false)\n            {\n                matrix_assign(*this, rowm(m,row)-exp); \n            }\n            else\n            {\n                // make a temporary copy of the matrix we are going to assign to m to \n                // avoid aliasing issues during the copy\n                this->operator-=(tmp(exp));\n            }\n\n            return *this;\n        }\n\n        assignable_row_matrix& operator= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nc(); ++i)\n            {\n                m(row,i) = value;\n            }\n\n            return *this;\n        }\n\n        assignable_row_matrix& operator+= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nc(); ++i)\n            {\n                m(row,i) += value;\n            }\n\n            return *this;\n        }\n\n        assignable_row_matrix& operator-= (\n            const T& value\n        )\n        {\n            for (long i = 0; i < m.nc(); ++i)\n            {\n                m(row,i) -= value;\n            }\n\n            return *this;\n        }\n\n\n        matrix<T,NR,NC,mm,l>& m;\n        const long row;\n    };\n\n\n    template <typename T, long NR, long NC, typename mm, typename l>\n    assignable_row_matrix<T,NR,NC,mm,l> set_rowm (\n        matrix<T,NR,NC,mm,l>& m,\n        const long row \n    )\n    {\n        DLIB_ASSERT(row >= 0 && row < m.nr(), \n            \"\\tassignable_matrix_expression set_rowm(matrix& m, row)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trow:    \" << row \n            );\n\n\n        return assignable_row_matrix<T,NR,NC,mm,l>(m,row);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_SUBEXP_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_subexp_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_SUBEXP_ABSTRACT_\n#ifdef DLIB_MATRIx_SUBEXP_ABSTRACT_\n\n#include \"matrix_abstract.h\"\n#include \"../geometry/rectangle.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <long start, long inc, long end>\n    const matrix_exp range (\n    );\n    /*!\n        requires\n            - inc > 0\n        ensures\n            - returns a matrix R such that:\n                - R::type == long\n                - R.nr() == 1\n                - R.nc() == abs(end - start)/inc + 1\n                - if (start <= end) then\n                    - R(i) == start + i*inc\n                - else\n                    - R(i) == start - i*inc\n    !*/\n\n    template <long start, long end>\n    const matrix_exp range (\n    ) { return range<start,1,end>(); }\n\n    const matrix_exp range (\n        long start,\n        long inc,\n        long end\n    ); \n    /*!\n        requires\n            - inc > 0\n        ensures\n            - returns a matrix R such that:\n                - R::type == long\n                - R.nr() == 1\n                - R.nc() == abs(end - start)/inc + 1\n                - if (start <= end) then\n                    - R(i) == start + i*inc\n                - else\n                    - R(i) == start - i*inc\n    !*/\n\n    const matrix_exp range (\n        long start,\n        long end\n    ) { return range(start,1,end); }\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp subm (\n        const matrix_exp& m,\n        const matrix_exp& rows,\n        const matrix_exp& cols,\n    );\n    /*!\n        requires\n            - rows and cols contain integral elements (e.g. int, long)\n            - 0 <= min(rows) && max(rows) < m.nr() \n            - 0 <= min(cols) && max(cols) < m.nc()\n            - rows.nr() == 1 || rows.nc() == 1\n            - cols.nr() == 1 || cols.nc() == 1\n              (i.e. rows and cols must be vectors)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R.nr() == rows.size()\n                - R.nc() == cols.size()\n                - for all valid r and c:\n                  R(r,c) == m(rows(r),cols(c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp subm (\n        const matrix_exp& m,\n        long row,\n        long col,\n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - row >= 0\n            - col >= 0\n            - nr >= 0\n            - nc >= 0\n            - row + nr <= m.nr()\n            - col + nc <= m.nc()\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == nr \n                - R.nc() == nc\n                - for all valid r and c:\n                  R(r, c) == m(r+row,c+col)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp subm (\n        const matrix_exp& m,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - get_rect(m).contains(rect) == true\n              (i.e. rect is a region inside the matrix m)\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == rect.height()  \n                - R.nc() == rect.width()\n                - for all valid r and c:\n                  R(r, c) == m(r+rect.top(), c+rect.left())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp subm_clipped (\n        const matrix_exp& m,\n        long row,\n        long col,\n        long nr,\n        long nc\n    );\n    /*!\n        ensures\n            - This function is just like subm() except that it will automatically clip the\n              indicated sub matrix window so that it does not extend outside m.\n              In particular:\n                - Let box = rectangle(col,row,col+nc-1,row+nr-1)\n                  (i.e. the box that contains the indicated sub matrix)\n                - Let box_clipped = box.intersect(get_rect(m))\n                - Then this function returns a matrix R such that:\n                    - R.nr() == box_clipped.height()\n                    - R.nc() == box_clipped.width()\n                    - for all valid r and c:\n                      R(r, c) == m(r+box_clipped.top(),c+box_clipped.left())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp subm_clipped (\n        const matrix_exp& m,\n        const rectangle& rect\n    );\n    /*!\n        ensures\n            - Let box_clipped == rect.intersect(get_rect(m))\n            - returns a matrix R such that:\n                - R.nr() == box_clipped.height()  \n                - R.nc() == box_clipped.width()\n                - for all valid r and c:\n                  R(r, c) == m(r+box_clipped.top(), c+box_clipped.left())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp rowm (\n        const matrix_exp& m,\n        long row\n    );\n    /*!\n        requires\n            - 0 <= row < m.nr()\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == 1\n                - R.nc() == m.nc()\n                - for all valid i:\n                  R(i) == m(row,i)\n    !*/\n\n    template <typename EXP>\n    struct rowm_exp\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This struct allows you to determine the type of matrix expression \n                object returned from the rowm(m,row) function.  An example makes its\n                use clear:\n\n                template <typename EXP>\n                void do_something( const matrix_exp<EXP>& mat)\n                {\n                    // r is a matrix expression that aliases mat.\n                    typename rowm_exp<EXP>::type r = rowm(mat,0);\n\n                    // Print the first row of mat.  So we see that by using\n                    // rowm_exp we can save the object returned by rowm() in\n                    // a local variable.    \n                    cout << r << endl;\n\n                    // Note that you can only save the return value of rowm() to\n                    // a local variable if the argument to rowm() has a lifetime\n                    // beyond the rowm() expression.  The example shown above is\n                    // OK but the following would result in undefined behavior:\n                    typename rowm_exp<EXP>::type bad = rowm(mat + mat,0);\n                }\n        !*/\n        typedef type_of_expression_returned_by_rowm type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp rowm (\n        const matrix_exp& m,\n        long row,\n        long length\n    );\n    /*!\n        requires\n            - 0 <= row < m.nr()\n            - 0 <= length <= m.nc()\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == 1\n                - R.nc() == length\n                - for all valid i:\n                  R(i) == m(row,i)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp rowm (\n        const matrix_exp& m,\n        const matrix_exp& rows\n    );\n    /*!\n        requires\n            - rows contains integral elements (e.g. int, long)\n            - 0 <= min(rows) && max(rows) < m.nr() \n            - rows.nr() == 1 || rows.nc() == 1 || rows.size() == 0\n              (i.e. rows must be a vector, or just empty)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R.nr() == rows.size()\n                - R.nc() == m.nc() \n                - for all valid r and c:\n                  R(r,c) == m(rows(r),c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp colm (\n        const matrix_exp& m,\n        long col \n    );\n    /*!\n        requires\n            - 0 <= col < m.nc()\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == m.nr() \n                - R.nc() == 1\n                - for all valid i:\n                  R(i) == m(i,col)\n    !*/\n\n    template <typename EXP>\n    struct colm_exp\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This struct allows you to determine the type of matrix expression \n                object returned from the colm(m,col) function.  An example makes its\n                use clear:\n\n                template <typename EXP>\n                void do_something( const matrix_exp<EXP>& mat)\n                {\n                    // c is a matrix expression that aliases mat.\n                    typename colm_exp<EXP>::type c = colm(mat,0);\n\n                    // Print the first column of mat.  So we see that by using\n                    // colm_exp we can save the object returned by colm() in\n                    // a local variable.    \n                    cout << c << endl;\n\n                    // Note that you can only save the return value of colm() to\n                    // a local variable if the argument to colm() has a lifetime\n                    // beyond the colm() expression.  The example shown above is\n                    // OK but the following would result in undefined behavior:\n                    typename colm_exp<EXP>::type bad = colm(mat + mat,0);\n                }\n        !*/\n        typedef type_of_expression_returned_by_colm type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp colm (\n        const matrix_exp& m,\n        long col,\n        long length\n    );\n    /*!\n        requires\n            - 0 <= col < m.nc()\n            - 0 <= length <= m.nr()\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == length \n                - R.nc() == 1\n                - for all valid i:\n                  R(i) == m(i,col)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp colm (\n        const matrix_exp& m,\n        const matrix_exp& cols\n    );\n    /*!\n        requires\n            - cols contains integral elements (e.g. int, long)\n            - 0 <= min(cols) && max(cols) < m.nc() \n            - cols.nr() == 1 || cols.nc() == 1 || cols.size() == 0\n              (i.e. cols must be a vector, or just empty)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R.nr() == m.nr()\n                - R.nc() == cols.size()\n                - for all valid r and c:\n                  R(r,c) == m(r,cols(c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    assignable_matrix_expression set_ptrm (\n        T* ptr,\n        long nr,\n        long nc = 1\n    );\n    /*!\n        requires\n            - ptr == a pointer to nr*nc elements of type T\n            - nr >= 0\n            - nc >= 0\n        ensures\n            - statements of the following form:\n                - set_ptrm(ptr,nr,nc) = some_matrix;\n              result in it being the case that:\n                - mat(ptr,nr,nc) == some_matrix.\n\n            - statements of the following form:\n                - set_ptrm(ptr,nr,nc) = scalar_value;\n              result in it being the case that:\n                - mat(ptr,nr,nc) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_subm (\n        matrix& m,\n        long row,\n        long col,\n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - row >= 0\n            - col >= 0\n            - nr >= 0\n            - nc >= 0\n            - row + nr <= m.nr()\n            - col + nc <= m.nc()\n        ensures\n            - statements of the following form:\n                - set_subm(m,row,col,nr,nc) = some_matrix;\n              result in it being the case that:\n                - subm(m,row,col,nr,nc) == some_matrix.\n\n            - statements of the following form:\n                - set_subm(m,row,col,nr,nc) = scalar_value;\n              result in it being the case that:\n                - subm(m,row,col,nr,nc) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_subm (\n        matrix& m,\n        const rectangle& rect\n    );\n    /*!\n        requires\n            - get_rect(m).contains(rect) == true\n              (i.e. rect is a region inside the matrix m)\n        ensures\n            - statements of the following form:\n                - set_subm(m,rect) = some_matrix;\n              result in it being the case that:\n                - subm(m,rect) == some_matrix.\n\n            - statements of the following form:\n                - set_subm(m,rect) = scalar_value;\n              result in it being the case that:\n                - subm(m,rect) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_subm (\n        matrix& m,\n        const matrix_exp& rows,\n        const matrix_exp& cols\n    );\n    /*!\n        requires\n            - rows and cols contain integral elements (e.g. int, long)\n            - 0 <= min(rows) && max(rows) < m.nr() \n            - 0 <= min(cols) && max(cols) < m.nc()\n            - rows.nr() == 1 || rows.nc() == 1\n            - cols.nr() == 1 || cols.nc() == 1\n              (i.e. rows and cols must be vectors)\n        ensures\n            - statements of the following form:\n                - set_subm(m,rows,cols) = some_matrix;\n              result in it being the case that:\n                - subm(m,rows,cols) == some_matrix.\n\n            - statements of the following form:\n                - set_subm(m,rows,cols) = scalar_value;\n              result in it being the case that:\n                - subm(m,rows,cols) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_rowm (\n        matrix& m,\n        long row\n    );\n    /*!\n        requires\n            - 0 <= row < m.nr()\n        ensures\n            - statements of the following form:\n                - set_rowm(m,row) = some_matrix;\n              result in it being the case that:\n                - rowm(m,row) == some_matrix.\n\n            - statements of the following form:\n                - set_rowm(m,row) = scalar_value;\n              result in it being the case that:\n                - rowm(m,row) == uniform_matrix<matrix::type>(1,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_rowm (\n        matrix& m,\n        const matrix_exp& rows\n    );\n    /*!\n        requires\n            - rows contains integral elements (e.g. int, long)\n            - 0 <= min(rows) && max(rows) < m.nr() \n            - rows.nr() == 1 || rows.nc() == 1\n              (i.e. rows must be a vector)\n        ensures\n            - statements of the following form:\n                - set_rowm(m,rows) = some_matrix;\n              result in it being the case that:\n                - rowm(m,rows) == some_matrix.\n\n            - statements of the following form:\n                - set_rowm(m,rows) = scalar_value;\n              result in it being the case that:\n                - rowm(m,rows) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_colm (\n        matrix& m,\n        long col \n    );\n    /*!\n        requires\n            - 0 <= col < m.nr()\n        ensures\n            - statements of the following form:\n                - set_colm(m,col) = some_matrix;\n              result in it being the case that:\n                - colm(m,col) == some_matrix.\n\n            - statements of the following form:\n                - set_colm(m,col) = scalar_value;\n              result in it being the case that:\n                - colm(m,col) == uniform_matrix<matrix::type>(nr,1,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    assignable_matrix_expression set_colm (\n        matrix& m,\n        const matrix_exp& cols\n    );\n    /*!\n        requires\n            - cols contains integral elements (e.g. int, long)\n            - 0 <= min(cols) && max(cols) < m.nc() \n            - cols.nr() == 1 || cols.nc() == 1\n              (i.e. cols must be a vector)\n        ensures\n            - statements of the following form:\n                - set_colm(m,cols) = some_matrix;\n              result in it being the case that:\n                - colm(m,cols) == some_matrix.\n\n            - statements of the following form:\n                - set_colm(m,cols) = scalar_value;\n              result in it being the case that:\n                - colm(m,cols) == uniform_matrix<matrix::type>(nr,nc,scalar_value).\n\n            - In addition to the normal assignment statements using the = symbol, you may\n              also use the usual += and -= versions of the assignment operator.  In these\n              cases, they have their usual effect.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_SUBEXP_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_trsm.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRiX_TRSM_Hh_\n#define DLIB_MATRiX_TRSM_Hh_\n#include \"lapack/fortran_id.h\"\n#include \"cblas_constants.h\"\n\nnamespace dlib\n{\n    namespace blas_bindings\n    {\n#ifdef DLIB_USE_BLAS\n#ifdef DLIB_DEFINE_CBLAS_API\n        extern \"C\"\n        {\n            void cblas_strsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side,\n                             const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const float alpha, const float *A, const CBLAS_INT_TYPE lda,\n                             float *B, const CBLAS_INT_TYPE ldb);\n\n            void cblas_dtrsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side,\n                             const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA,\n                             const CBLAS_DIAG Diag, const CBLAS_INT_TYPE M, const CBLAS_INT_TYPE N,\n                             const double alpha, const double *A, const CBLAS_INT_TYPE lda,\n                             double *B, const CBLAS_INT_TYPE ldb);\n        }\n#endif // if DLIB_DEFINE_CBLAS_API \n#endif // if DLIB_USE_BLAS\n\n    // ------------------------------------------------------------------------------------\n\n/*  Purpose */\n/*  ======= */\n\n/*  DTRSM  solves one of the matrix equations */\n\n/*     op( A )*X = alpha*B,   or   X*op( A ) = alpha*B, */\n\n/*  where alpha is a scalar, X and B are m by n matrices, A is a unit, or */\n/*  non-unit,  upper or lower triangular matrix  and  op( A )  is one  of */\n\n/*     op( A ) = A   or   op( A ) = A'. */\n\n/*  The matrix X is overwritten on B. */\n\n/*  Arguments */\n/*  ========== */\n\n/*  SIDE   - CHARACTER*1. */\n/*           On entry, SIDE specifies whether op( A ) appears on the left */\n/*           or right of X as follows: */\n\n/*              SIDE = 'L' or 'l'   op( A )*X = alpha*B. */\n\n/*              SIDE = 'R' or 'r'   X*op( A ) = alpha*B. */\n\n/*           Unchanged on exit. */\n\n/*  UPLO   - CHARACTER*1. */\n/*           On entry, UPLO specifies whether the matrix A is an upper or */\n/*           lower triangular matrix as follows: */\n\n/*              UPLO = 'U' or 'u'   A is an upper triangular matrix. */\n\n/*              UPLO = 'L' or 'l'   A is a lower triangular matrix. */\n\n/*           Unchanged on exit. */\n\n/*  TRANSA - CHARACTER*1. */\n/*           On entry, TRANSA specifies the form of op( A ) to be used in */\n/*           the matrix multiplication as follows: */\n\n/*              TRANSA = 'N' or 'n'   op( A ) = A. */\n\n/*              TRANSA = 'T' or 't'   op( A ) = A'. */\n\n/*              TRANSA = 'C' or 'c'   op( A ) = A'. */\n\n/*           Unchanged on exit. */\n\n/*  DIAG   - CHARACTER*1. */\n/*           On entry, DIAG specifies whether or not A is unit triangular */\n/*           as follows: */\n\n/*              DIAG = 'U' or 'u'   A is assumed to be unit triangular. */\n\n/*              DIAG = 'N' or 'n'   A is not assumed to be unit */\n/*                                  triangular. */\n\n/*           Unchanged on exit. */\n\n/*  M      - INTEGER. */\n/*           On entry, M specifies the number of rows of B. M must be at */\n/*           least zero. */\n/*           Unchanged on exit. */\n\n/*  N      - INTEGER. */\n/*           On entry, N specifies the number of columns of B.  N must be */\n/*           at least zero. */\n/*           Unchanged on exit. */\n\n/*  ALPHA  - DOUBLE PRECISION. */\n/*           On entry,  ALPHA specifies the scalar  alpha. When  alpha is */\n/*           zero then  A is not referenced and  B need not be set before */\n/*           entry. */\n/*           Unchanged on exit. */\n\n/*  A      - DOUBLE PRECISION array of DIMENSION ( LDA, k ), where k is m */\n/*           when  SIDE = 'L' or 'l'  and is  n  when  SIDE = 'R' or 'r'. */\n/*           Before entry  with  UPLO = 'U' or 'u',  the  leading  k by k */\n/*           upper triangular part of the array  A must contain the upper */\n/*           triangular matrix  and the strictly lower triangular part of */\n/*           A is not referenced. */\n/*           Before entry  with  UPLO = 'L' or 'l',  the  leading  k by k */\n/*           lower triangular part of the array  A must contain the lower */\n/*           triangular matrix  and the strictly upper triangular part of */\n/*           A is not referenced. */\n/*           Note that when  DIAG = 'U' or 'u',  the diagonal elements of */\n/*           A  are not referenced either,  but are assumed to be  unity. */\n/*           Unchanged on exit. */\n\n/*  LDA    - INTEGER. */\n/*           On entry, LDA specifies the first dimension of A as declared */\n/*           in the calling (sub) program.  When  SIDE = 'L' or 'l'  then */\n/*           LDA  must be at least  max( 1, m ),  when  SIDE = 'R' or 'r' */\n/*           then LDA must be at least max( 1, n ). */\n/*           Unchanged on exit. */\n\n/*  B      - DOUBLE PRECISION array of DIMENSION ( LDB, n ). */\n/*           Before entry,  the leading  m by n part of the array  B must */\n/*           contain  the  right-hand  side  matrix  B,  and  on exit  is */\n/*           overwritten by the solution matrix  X. */\n\n/*  LDB    - INTEGER. */\n/*           On entry, LDB specifies the first dimension of B as declared */\n/*           in  the  calling  (sub)  program.   LDB  must  be  at  least */\n/*           max( 1, m ). */\n/*           Unchanged on exit. */\n\n\n/*  Level 3 Blas routine. */\n\n\n/*  -- Written on 8-February-1989. */\n/*     Jack Dongarra, Argonne National Laboratory. */\n/*     Iain Duff, AERE Harwell. */\n/*     Jeremy Du Croz, Numerical Algorithms Group Ltd. */\n/*     Sven Hammarling, Numerical Algorithms Group Ltd. */\n\n        template <typename T>\n        void local_trsm(\n            const CBLAS_ORDER Order,\n            CBLAS_SIDE Side,\n            CBLAS_UPLO Uplo, \n            const CBLAS_TRANSPOSE TransA,\n            const CBLAS_DIAG Diag, \n            long m, \n            long n, \n            T alpha, \n            const T *a, \n            long lda, \n            T *b, \n            long ldb\n        )\n        /*!\n            This is a copy of the dtrsm routine from the netlib.org BLAS which was run though\n            f2c and converted into this form for use when a BLAS library is not available.\n        !*/\n        {\n            if (Order == CblasRowMajor)\n            {\n                // since row major ordering looks like transposition to FORTRAN we need to flip a\n                // few things.\n                if (Side == CblasLeft)\n                    Side = CblasRight;\n                else\n                    Side = CblasLeft;\n\n                if (Uplo == CblasUpper)\n                    Uplo = CblasLower;\n                else\n                    Uplo = CblasUpper;\n\n                std::swap(m,n);\n            }\n\n            /* System generated locals */\n            long a_dim1, a_offset, b_dim1, b_offset, i__1, i__2, i__3;\n\n            /* Local variables */\n            long i__, j, k, info;\n            T temp;\n            bool lside;\n            long nrowa;\n            bool upper;\n            bool nounit;\n\n            /* Parameter adjustments */\n            a_dim1 = lda;\n            a_offset = 1 + a_dim1;\n            a -= a_offset;\n            b_dim1 = ldb;\n            b_offset = 1 + b_dim1;\n            b -= b_offset;\n\n            /* Function Body */\n            lside = (Side == CblasLeft);\n            if (lside) \n            {\n                nrowa = m;\n            } else \n            {\n                nrowa = n;\n            }\n            nounit = (Diag == CblasNonUnit); \n            upper = (Uplo == CblasUpper); \n\n            info = 0;\n            if (! lside && ! (Side == CblasRight)) {\n                info = 1;\n            } else if (! upper && !(Uplo == CblasLower) ) {\n                info = 2;\n            } else if (!(TransA == CblasNoTrans) && \n                       !(TransA == CblasTrans) && \n                       !(TransA == CblasConjTrans))  {\n                info = 3;\n            } else if (!(Diag == CblasUnit) && \n                       !(Diag == CblasNonUnit) ) {\n                info = 4;\n            } else if (m < 0) {\n                info = 5;\n            } else if (n < 0) {\n                info = 6;\n            } else if (lda < std::max<long>(1,nrowa)) {\n                info = 9;\n            } else if (ldb < std::max<long>(1,m)) {\n                info = 11;\n            }\n            DLIB_CASSERT( info == 0, \"Invalid inputs given to local_trsm\");\n\n            /*     Quick return if possible. */\n\n            if (m == 0 || n == 0) {\n                return;\n            }\n\n            /*     And when  alpha.eq.zero. */\n\n            if (alpha == 0.) {\n                i__1 = n;\n                for (j = 1; j <= i__1; ++j) {\n                    i__2 = m;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        b[i__ + j * b_dim1] = 0.;\n                        /* L10: */\n                    }\n                    /* L20: */\n                }\n                return;\n            }\n\n            /*     Start the operations. */\n\n            if (lside) {\n                if (TransA == CblasNoTrans) {\n\n                    /*           Form  B := alpha*inv( A )*B. */\n\n                    if (upper) {\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            if (alpha != 1.) {\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]\n                                        ;\n                                    /* L30: */\n                                }\n                            }\n                            for (k = m; k >= 1; --k) {\n                                if (b[k + j * b_dim1] != 0.) {\n                                    if (nounit) {\n                                        b[k + j * b_dim1] /= a[k + k * a_dim1];\n                                    }\n                                    i__2 = k - 1;\n                                    for (i__ = 1; i__ <= i__2; ++i__) {\n                                        b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[\n                                            i__ + k * a_dim1];\n                                        /* L40: */\n                                    }\n                                }\n                                /* L50: */\n                            }\n                            /* L60: */\n                        }\n                    } else {\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            if (alpha != 1.) {\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]\n                                        ;\n                                    /* L70: */\n                                }\n                            }\n                            i__2 = m;\n                            for (k = 1; k <= i__2; ++k) {\n                                if (b[k + j * b_dim1] != 0.) {\n                                    if (nounit) {\n                                        b[k + j * b_dim1] /= a[k + k * a_dim1];\n                                    }\n                                    i__3 = m;\n                                    for (i__ = k + 1; i__ <= i__3; ++i__) {\n                                        b[i__ + j * b_dim1] -= b[k + j * b_dim1] * a[\n                                            i__ + k * a_dim1];\n                                        /* L80: */\n                                    }\n                                }\n                                /* L90: */\n                            }\n                            /* L100: */\n                        }\n                    }\n                } else {\n\n                    /*           Form  B := alpha*inv( A' )*B. */\n\n                    if (upper) {\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            i__2 = m;\n                            for (i__ = 1; i__ <= i__2; ++i__) {\n                                temp = alpha * b[i__ + j * b_dim1];\n                                i__3 = i__ - 1;\n                                for (k = 1; k <= i__3; ++k) {\n                                    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];\n                                    /* L110: */\n                                }\n                                if (nounit) {\n                                    temp /= a[i__ + i__ * a_dim1];\n                                }\n                                b[i__ + j * b_dim1] = temp;\n                                /* L120: */\n                            }\n                            /* L130: */\n                        }\n                    } else {\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            for (i__ = m; i__ >= 1; --i__) {\n                                temp = alpha * b[i__ + j * b_dim1];\n                                i__2 = m;\n                                for (k = i__ + 1; k <= i__2; ++k) {\n                                    temp -= a[k + i__ * a_dim1] * b[k + j * b_dim1];\n                                    /* L140: */\n                                }\n                                if (nounit) {\n                                    temp /= a[i__ + i__ * a_dim1];\n                                }\n                                b[i__ + j * b_dim1] = temp;\n                                /* L150: */\n                            }\n                            /* L160: */\n                        }\n                    }\n                }\n            } else {\n                if (TransA == CblasNoTrans) {\n\n                    /*           Form  B := alpha*B*inv( A ). */\n\n                    if (upper) {\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            if (alpha != 1.) {\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]\n                                        ;\n                                    /* L170: */\n                                }\n                            }\n                            i__2 = j - 1;\n                            for (k = 1; k <= i__2; ++k) {\n                                if (a[k + j * a_dim1] != 0.) {\n                                    i__3 = m;\n                                    for (i__ = 1; i__ <= i__3; ++i__) {\n                                        b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[\n                                            i__ + k * b_dim1];\n                                        /* L180: */\n                                    }\n                                }\n                                /* L190: */\n                            }\n                            if (nounit) {\n                                temp = 1. / a[j + j * a_dim1];\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];\n                                    /* L200: */\n                                }\n                            }\n                            /* L210: */\n                        }\n                    } else {\n                        for (j = n; j >= 1; --j) {\n                            if (alpha != 1.) {\n                                i__1 = m;\n                                for (i__ = 1; i__ <= i__1; ++i__) {\n                                    b[i__ + j * b_dim1] = alpha * b[i__ + j * b_dim1]\n                                        ;\n                                    /* L220: */\n                                }\n                            }\n                            i__1 = n;\n                            for (k = j + 1; k <= i__1; ++k) {\n                                if (a[k + j * a_dim1] != 0.) {\n                                    i__2 = m;\n                                    for (i__ = 1; i__ <= i__2; ++i__) {\n                                        b[i__ + j * b_dim1] -= a[k + j * a_dim1] * b[\n                                            i__ + k * b_dim1];\n                                        /* L230: */\n                                    }\n                                }\n                                /* L240: */\n                            }\n                            if (nounit) {\n                                temp = 1. / a[j + j * a_dim1];\n                                i__1 = m;\n                                for (i__ = 1; i__ <= i__1; ++i__) {\n                                    b[i__ + j * b_dim1] = temp * b[i__ + j * b_dim1];\n                                    /* L250: */\n                                }\n                            }\n                            /* L260: */\n                        }\n                    }\n                } else {\n\n                    /*           Form  B := alpha*B*inv( A' ). */\n\n                    if (upper) {\n                        for (k = n; k >= 1; --k) {\n                            if (nounit) {\n                                temp = 1. / a[k + k * a_dim1];\n                                i__1 = m;\n                                for (i__ = 1; i__ <= i__1; ++i__) {\n                                    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];\n                                    /* L270: */\n                                }\n                            }\n                            i__1 = k - 1;\n                            for (j = 1; j <= i__1; ++j) {\n                                if (a[j + k * a_dim1] != 0.) {\n                                    temp = a[j + k * a_dim1];\n                                    i__2 = m;\n                                    for (i__ = 1; i__ <= i__2; ++i__) {\n                                        b[i__ + j * b_dim1] -= temp * b[i__ + k * \n                                            b_dim1];\n                                        /* L280: */\n                                    }\n                                }\n                                /* L290: */\n                            }\n                            if (alpha != 1.) {\n                                i__1 = m;\n                                for (i__ = 1; i__ <= i__1; ++i__) {\n                                    b[i__ + k * b_dim1] = alpha * b[i__ + k * b_dim1]\n                                        ;\n                                    /* L300: */\n                                }\n                            }\n                            /* L310: */\n                        }\n                    } else {\n                        i__1 = n;\n                        for (k = 1; k <= i__1; ++k) {\n                            if (nounit) {\n                                temp = 1. / a[k + k * a_dim1];\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + k * b_dim1] = temp * b[i__ + k * b_dim1];\n                                    /* L320: */\n                                }\n                            }\n                            i__2 = n;\n                            for (j = k + 1; j <= i__2; ++j) {\n                                if (a[j + k * a_dim1] != 0.) {\n                                    temp = a[j + k * a_dim1];\n                                    i__3 = m;\n                                    for (i__ = 1; i__ <= i__3; ++i__) {\n                                        b[i__ + j * b_dim1] -= temp * b[i__ + k * \n                                            b_dim1];\n                                        /* L330: */\n                                    }\n                                }\n                                /* L340: */\n                            }\n                            if (alpha != 1.) {\n                                i__2 = m;\n                                for (i__ = 1; i__ <= i__2; ++i__) {\n                                    b[i__ + k * b_dim1] = alpha * b[i__ + k * b_dim1]\n                                        ;\n                                    /* L350: */\n                                }\n                            }\n                            /* L360: */\n                        }\n                    }\n                }\n            }\n        } \n\n    // ------------------------------------------------------------------------------------\n\n        inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side,\n                               const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA,\n                               const CBLAS_DIAG Diag, const int M, const int N,\n                               const float alpha, const float *A, const int lda,\n                               float *B, const int ldb)\n        {\n#ifdef DLIB_USE_BLAS\n            if (M > 4)\n            {\n                cblas_strsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);\n                return;\n            }\n#endif\n            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);\n        }\n\n        inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side,\n                               const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA,\n                               const CBLAS_DIAG Diag, const int M, const int N,\n                               const double alpha, const double *A, const int lda,\n                               double *B, const int ldb)\n        {\n#ifdef DLIB_USE_BLAS\n            if (M > 4)\n            {\n                cblas_dtrsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);\n                return;\n            }\n#endif\n            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);\n        }\n\n        inline void cblas_trsm(const CBLAS_ORDER Order, const CBLAS_SIDE Side,\n                               const CBLAS_UPLO Uplo, const CBLAS_TRANSPOSE TransA,\n                               const CBLAS_DIAG Diag, const int M, const int N,\n                               const long double alpha, const long double *A, const int lda,\n                               long double *B, const int ldb)\n        {\n            local_trsm(Order, Side, Uplo, TransA, Diag, M, N, alpha, A, lda, B, ldb);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long NR1, long NR2,\n            long NC1, long NC2,\n            typename MM\n            >\n        inline void triangular_solver (\n            const CBLAS_SIDE Side,\n            const CBLAS_UPLO Uplo, \n            const CBLAS_TRANSPOSE TransA,\n            const CBLAS_DIAG Diag,\n            const matrix<T,NR1,NC1,MM,row_major_layout>& A,\n            const T alpha,\n            matrix<T,NR2,NC2,MM,row_major_layout>& B\n        )\n        {\n            cblas_trsm(CblasRowMajor, Side,  Uplo, TransA, Diag, B.nr(), B.nc(),\n                       alpha, &A(0,0), A.nc(), &B(0,0), B.nc());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long NR1, long NR2,\n            long NC1, long NC2,\n            typename MM\n            >\n        inline void triangular_solver (\n            const CBLAS_SIDE Side,\n            const CBLAS_UPLO Uplo, \n            const CBLAS_TRANSPOSE TransA,\n            const CBLAS_DIAG Diag,\n            const matrix<T,NR1,NC1,MM,column_major_layout>& A,\n            const T alpha,\n            matrix<T,NR2,NC2,MM,column_major_layout>& B\n        )\n        {\n            cblas_trsm(CblasColMajor, Side,  Uplo, TransA, Diag, B.nr(), B.nc(),\n                       alpha, &A(0,0), A.nr(), &B(0,0), B.nr());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long NR1, long NR2,\n            long NC1, long NC2,\n            typename MM\n            >\n        inline void triangular_solver (\n            const CBLAS_SIDE Side,\n            const CBLAS_UPLO Uplo, \n            const CBLAS_TRANSPOSE TransA,\n            const CBLAS_DIAG Diag,\n            const matrix<T,NR1,NC1,MM,column_major_layout>& A,\n            matrix<T,NR2,NC2,MM,column_major_layout>& B,\n            long rows_of_B\n        )\n        {\n            const T alpha = 1;\n            cblas_trsm(CblasColMajor, Side,  Uplo, TransA, Diag, rows_of_B, B.nc(),\n                       alpha, &A(0,0), A.nr(), &B(0,0), B.nr());\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T,\n            long NR1, long NR2,\n            long NC1, long NC2,\n            typename MM,\n            typename layout\n            >\n        inline void triangular_solver (\n            const CBLAS_SIDE Side,\n            const CBLAS_UPLO Uplo, \n            const CBLAS_TRANSPOSE TransA,\n            const CBLAS_DIAG Diag,\n            const matrix<T,NR1,NC1,MM,layout>& A,\n            matrix<T,NR2,NC2,MM,layout>& B\n        )\n        {\n            const T alpha = 1;\n            triangular_solver(Side, Uplo, TransA, Diag, A, alpha, B);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif // DLIB_MATRiX_TRSM_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_utilities.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_UTILITIES_\n#define DLIB_MATRIx_UTILITIES_\n\n#include \"matrix_utilities_abstract.h\"\n#include \"matrix.h\"\n#include <cmath>\n#include <complex>\n#include <limits>\n#include \"../pixel.h\"\n#include \"../stl_checked.h\"\n#include <vector>\n#include <algorithm>\n#include \"../std_allocator.h\"\n#include \"matrix_expressions.h\"\n#include \"matrix_math_functions.h\"\n#include \"matrix_op.h\"\n#include \"../general_hash/random_hashing.h\"\n#include \"matrix_mat.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A is_complex\n        This is a template that can be used to determine if a type is a specialization\n        of the std::complex template class.\n\n        For example:\n            is_complex<float>::value == false              \n            is_complex<std::complex<float> >::value == true   \n    !*/\n\n    template <typename T>\n    struct is_complex { static const bool value = false; };\n\n    template <typename T>\n    struct is_complex<std::complex<T> >         { static const bool value = true; };\n    template <typename T>\n    struct is_complex<std::complex<T>& >        { static const bool value = true; };\n    template <typename T>\n    struct is_complex<const std::complex<T>& >  { static const bool value = true; };\n    template <typename T>\n    struct is_complex<const std::complex<T> >   { static const bool value = true; };\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A remove_complex\n        This is a template that can be used to remove std::complex from the underlying type.\n\n        For example:\n            remove_complex<float>::type == float\n            remove_complex<std::complex<float> >::type == float\n    !*/\n    template <typename T>\n    struct remove_complex {typedef T type;};\n    template <typename T>\n    struct remove_complex<std::complex<T> > {typedef T type;};\n    \n    template<typename T>\n    using remove_complex_t = typename remove_complex<T>::type;\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A add_complex\n        This is a template that can be used to add std::complex to the underlying type if it isn't already complex.\n\n        For example:\n            add_complex<float>::type == std::complex<float>\n            add_complex<std::complex<float> >::type == std::complex<float>\n    !*/\n    template <typename T>\n    struct add_complex {typedef std::complex<T> type;};\n    template <typename T>\n    struct add_complex<std::complex<T> > {typedef std::complex<T> type;};\n    \n    template<typename T>\n    using add_complex_t = typename add_complex<T>::type;\n\n// ----------------------------------------------------------------------------------------\n    \n    template <typename EXP>\n    inline bool is_row_vector (\n        const matrix_exp<EXP>& m\n    ) { return m.nr() == 1; }\n\n    template <typename EXP>\n    inline bool is_col_vector (\n        const matrix_exp<EXP>& m\n    ) { return m.nc() == 1; }\n\n    template <typename EXP>\n    inline bool is_vector (\n        const matrix_exp<EXP>& m\n    ) { return is_row_vector(m) || is_col_vector(m); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    inline bool is_finite (\n        const matrix_exp<EXP>& m\n    ) \n    { \n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                if (!is_finite(m(r,c)))\n                    return false;\n            }\n        }\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        const T& magnitude (const T& item) { return item; }\n        template <typename T>\n        T magnitude (const std::complex<T>& item) { return std::norm(item); }\n    }\n\n    template <\n        typename EXP\n        >\n    void find_min_and_max (\n        const matrix_exp<EXP>& m,\n        typename EXP::type& min_val,\n        typename EXP::type& max_val\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\ttype find_min_and_max(const matrix_exp& m, min_val, max_val)\"\n            << \"\\n\\tYou can't ask for the min and max of an empty matrix\"\n            << \"\\n\\tm.size():     \" << m.size() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        min_val = m(0,0);\n        max_val = min_val;\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                type temp = m(r,c);\n                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(max_val))\n                    max_val = temp;\n                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(min_val))\n                    min_val = temp;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    point max_point (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\tpoint max_point(const matrix_exp& m)\"\n            << \"\\n\\tm can't be empty\"\n            << \"\\n\\tm.size():   \" << m.size() \n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        point best_point(0,0);\n        type val = m(0,0);\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                type temp = m(r,c);\n                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))\n                {\n                    val = temp;\n                    best_point = point(c,r);\n                }\n            }\n        }\n        return best_point;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    point min_point (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\tpoint min_point(const matrix_exp& m)\"\n            << \"\\n\\tm can't be empty\"\n            << \"\\n\\tm.size():   \" << m.size() \n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        point best_point(0,0);\n        type val = m(0,0);\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                type temp = m(r,c);\n                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))\n                {\n                    val = temp;\n                    best_point = point(c,r);\n                }\n            }\n        }\n        return best_point;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    long index_of_max (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0 && is_vector(m) == true, \n            \"\\tlong index_of_max(const matrix_exp& m)\"\n            << \"\\n\\tm must be a row or column matrix\"\n            << \"\\n\\tm.size():   \" << m.size() \n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = m(0);\n        long best_idx = 0;\n        for (long i = 1; i < m.size(); ++i)\n        {\n            type temp = m(i);\n            if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))\n            {\n                val = temp;\n                best_idx = i;\n            }\n        }\n        return best_idx;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    long index_of_min (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0 && is_vector(m), \n            \"\\tlong index_of_min(const matrix_exp& m)\"\n            << \"\\n\\tm must be a row or column matrix\"\n            << \"\\n\\tm.size():   \" << m.size() \n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = m(0);\n        long best_idx = 0;\n        for (long i = 1; i < m.size(); ++i)\n        {\n            type temp = m(i);\n            if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))\n            {\n                val = temp;\n                best_idx = i;\n            }\n        }\n        return best_idx;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type max (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\ttype max(const matrix_exp& m)\"\n            << \"\\n\\tYou can't ask for the max() of an empty matrix\"\n            << \"\\n\\tm.size():     \" << m.size() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = m(0,0);\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                type temp = m(r,c);\n                if (dlib::impl::magnitude(temp) > dlib::impl::magnitude(val))\n                    val = temp;\n            }\n        }\n        return val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type min (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0, \n            \"\\ttype min(const matrix_exp& m)\"\n            << \"\\n\\tYou can't ask for the min() of an empty matrix\"\n            << \"\\n\\tm.size():     \" << m.size() \n            );\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = m(0,0);\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                type temp = m(r,c);\n                if (dlib::impl::magnitude(temp) < dlib::impl::magnitude(val))\n                    val = temp;\n            }\n        }\n        return val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_binary_min : basic_op_mm<M1,M2>\n    {\n        op_binary_min( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        typedef typename M1::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 1;\n\n        const_ret_type apply ( long r, long c) const\n        { return std::min(this->m1(r,c),this->m2(r,c)); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_binary_min<EXP1,EXP2> > min_pointwise (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc(), \n            \"\\t const matrix_exp min_pointwise(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            );\n        typedef op_binary_min<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_min_pointwise3 : basic_op_mmm<M1,M2,M3>\n    {\n        op_min_pointwise3( const M1& m1_, const M2& m2_, const M3& m3_) : \n            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + 2;\n\n        const_ret_type apply (long r, long c) const\n        { return std::min(this->m1(r,c),std::min(this->m2(r,c),this->m3(r,c))); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    inline const matrix_op<op_min_pointwise3<EXP1,EXP2,EXP3> > \n    min_pointwise (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b, \n        const matrix_exp<EXP3>& c\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc(), \n            \"\\tconst matrix_exp min_pointwise(a,b,c)\"\n            << \"\\n\\tYou can only make a do a pointwise min between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc() \n            );\n\n        typedef op_min_pointwise3<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_binary_max : basic_op_mm<M1,M2>\n    {\n        op_binary_max( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        typedef typename M1::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 1;\n\n        const_ret_type apply ( long r, long c) const\n        { return std::max(this->m1(r,c),this->m2(r,c)); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_binary_max<EXP1,EXP2> > max_pointwise (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc(), \n            \"\\t const matrix_exp max_pointwise(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            );\n        typedef op_binary_max<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_max_pointwise3 : basic_op_mmm<M1,M2,M3>\n    {\n        op_max_pointwise3( const M1& m1_, const M2& m2_, const M3& m3_) : \n            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + 2;\n\n        const_ret_type apply (long r, long c) const\n        { return std::max(this->m1(r,c),std::max(this->m2(r,c),this->m3(r,c))); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    inline const matrix_op<op_max_pointwise3<EXP1,EXP2,EXP3> > \n    max_pointwise (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b, \n        const matrix_exp<EXP3>& c\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc(), \n            \"\\tconst matrix_exp max_pointwise(a,b,c)\"\n            << \"\\n\\tYou can only make a do a pointwise max between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc() \n            );\n\n        typedef op_max_pointwise3<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    typename enable_if_c<std::numeric_limits<typename EXP::type>::is_integer, double>::type length (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(is_vector(m) == true, \n            \"\\ttype length(const matrix_exp& m)\"\n            << \"\\n\\tm must be a row or column vector\"\n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        \n        return std::sqrt(static_cast<double>(sum(squared(m))));\n    }\n    \n    template <\n        typename EXP\n        >\n    typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, const typename EXP::type>::type length (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(is_vector(m) == true, \n            \"\\ttype length(const matrix_exp& m)\"\n            << \"\\n\\tm must be a row or column vector\"\n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        return std::sqrt(sum(squared(m)));\n    }\n \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type length_squared (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(is_vector(m) == true, \n            \"\\ttype length_squared(const matrix_exp& m)\"\n            << \"\\n\\tm must be a row or column vector\"\n            << \"\\n\\tm.nr():     \" << m.nr() \n            << \"\\n\\tm.nc():     \" << m.nc() \n            );\n        return sum(squared(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    \n    template <typename M>\n    struct op_trans \n    {\n        op_trans( const M& m_) : m(m_){}\n\n        const M& m;\n\n        const static long cost = M::cost;\n        const static long NR = M::NC;\n        const static long NC = M::NR;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const { return m(c,r); }\n\n        long nr () const { return m.nc(); }\n        long nc () const { return m.nr(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n\n    }; \n\n    template <\n        typename M\n        >\n    const matrix_op<op_trans<M> > trans (\n        const matrix_exp<M>& m\n    )\n    {\n        typedef op_trans<M> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// don't to anything at all for diagonal matrices\n    template <\n        typename M\n        >\n    const matrix_diag_exp<M>& trans (\n        const matrix_diag_exp<M>& m\n    )\n    {\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// I introduced this struct because it avoids an inane compiler warning from gcc\n    template <typename EXP>\n    struct is_not_ct_vector{ static const bool value = (EXP::NR != 1 && EXP::NC != 1); };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    typename enable_if_c<(is_not_ct_vector<EXP1>::value) || (is_not_ct_vector<EXP2>::value),\n                         typename EXP1::type>::type \n    dot (\n        const matrix_exp<EXP1>& m1,\n        const matrix_exp<EXP2>& m2\n    )\n    {\n        // You are getting an error on this line because you are trying to \n        // compute the dot product between two matrices that aren't both vectors (i.e. \n        // they aren't column or row matrices).\n        COMPILE_TIME_ASSERT(EXP1::NR*EXP1::NC == 0 ||\n                            EXP2::NR*EXP2::NC == 0);\n\n        DLIB_ASSERT(is_vector(m1) && is_vector(m2) && m1.size() == m2.size() &&\n                    m1.size() > 0, \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between non-empty vectors of equal length.\"\n            << \"\\n\\t is_vector(m1): \" << is_vector(m1) \n            << \"\\n\\t is_vector(m2): \" << is_vector(m2) \n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n\n        if (is_col_vector(m1) && is_col_vector(m2)) return (trans(m1)*m2)(0);\n        if (is_col_vector(m1) && is_row_vector(m2)) return (m2*m1)(0);\n        if (is_row_vector(m1) && is_col_vector(m2)) return (m1*m2)(0);\n\n        //if (is_row_vector(m1) && is_row_vector(m2)) \n        return (m1*trans(m2))(0);\n    }\n\n    template < typename EXP1, typename EXP2 >\n    typename enable_if_c<EXP1::NR == 1 && EXP2::NR == 1 && EXP1::NC != 1 && EXP2::NC != 1, typename EXP1::type>::type \n    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2) \n    { \n        DLIB_ASSERT(m1.size() == m2.size(), \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between vectors of equal length\"\n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n        \n        return m1*trans(m2); \n    }\n\n    template < typename EXP1, typename EXP2 >\n    typename enable_if_c<EXP1::NR == 1 && EXP2::NC == 1 && EXP1::NC != 1 && EXP2::NR != 1, typename EXP1::type>::type \n    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2) \n    { \n        DLIB_ASSERT(m1.size() == m2.size(), \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between vectors of equal length\"\n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n        \n        return m1*m2; \n    }\n\n    template < typename EXP1, typename EXP2 >\n    typename enable_if_c<EXP1::NC == 1 && EXP2::NR == 1 && EXP1::NR != 1 && EXP2::NC != 1, typename EXP1::type>::type \n    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2) \n    { \n        DLIB_ASSERT(m1.size() == m2.size(), \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between vectors of equal length\"\n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n        \n        return m2*m1; \n    }\n\n    template < typename EXP1, typename EXP2 >\n    typename enable_if_c<EXP1::NC == 1 && EXP2::NC == 1 && EXP1::NR != 1 && EXP2::NR != 1, typename EXP1::type>::type \n    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2) \n    { \n        DLIB_ASSERT(m1.size() == m2.size(), \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between vectors of equal length\"\n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n        \n        return trans(m1)*m2; \n    }\n\n    template < typename EXP1, typename EXP2 >\n    typename enable_if_c<(EXP1::NC*EXP1::NR == 1) || (EXP2::NC*EXP2::NR == 1), typename EXP1::type>::type \n    dot ( const matrix_exp<EXP1>& m1, const matrix_exp<EXP2>& m2) \n    { \n        DLIB_ASSERT(m1.size() == m2.size(), \n            \"\\t type dot(const matrix_exp& m1, const matrix_exp& m2)\"\n            << \"\\n\\t You can only compute the dot product between vectors of equal length\"\n            << \"\\n\\t m1.size():     \" << m1.size() \n            << \"\\n\\t m2.size():     \" << m2.size() \n            );\n        \n        return m1(0)*m2(0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, long R, long C>\n    struct op_removerc \n    {\n        op_removerc( const M& m_) : m(m_){}\n\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);\n        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply (long r, long c) const\n        { \n            if (r < R)\n            {\n                if (c < C)\n                    return m(r,c); \n                else\n                    return m(r,c+1); \n            }\n            else\n            {\n                if (c < C)\n                    return m(r+1,c); \n                else\n                    return m(r+1,c+1); \n            }\n        }\n\n        long nr () const { return m.nr() - 1; }\n        long nc () const { return m.nc() - 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <typename M>\n    struct op_removerc2 \n    {\n        op_removerc2( const M& m_, const long R_, const long C_) : m(m_), R(R_), C(C_){}\n        const M& m;\n        const long R;\n        const long C;\n\n        const static long cost = M::cost+2;\n        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);\n        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply (long r, long c) const\n        { \n            if (r < R)\n            {\n                if (c < C)\n                    return m(r,c); \n                else\n                    return m(r,c+1); \n            }\n            else\n            {\n                if (c < C)\n                    return m(r+1,c); \n                else\n                    return m(r+1,c+1); \n            }\n        }\n\n        long nr () const { return m.nr() - 1; }\n        long nc () const { return m.nc() - 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        long R,\n        long C,\n        typename EXP\n        >\n    const matrix_op<op_removerc<EXP,R,C> > removerc (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can't remove a row from a matrix with only one row\n        COMPILE_TIME_ASSERT((EXP::NR > R && R >= 0) || EXP::NR == 0);\n        // you can't remove a column from a matrix with only one column \n        COMPILE_TIME_ASSERT((EXP::NC > C && C >= 0) || EXP::NR == 0);\n        DLIB_ASSERT(m.nr() > R && R >= 0 && m.nc() > C && C >= 0, \n            \"\\tconst matrix_exp removerc<R,C>(const matrix_exp& m)\"\n            << \"\\n\\tYou can't remove a row/column from a matrix if it doesn't have that row/column\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tR:      \" << R \n            << \"\\n\\tC:      \" << C \n            );\n        typedef op_removerc<EXP,R,C> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_removerc2<EXP> >  removerc (\n        const matrix_exp<EXP>& m,\n        long R,\n        long C\n    )\n    {\n        DLIB_ASSERT(m.nr() > R && R >= 0 && m.nc() > C && C >= 0, \n            \"\\tconst matrix_exp removerc(const matrix_exp& m,R,C)\"\n            << \"\\n\\tYou can't remove a row/column from a matrix if it doesn't have that row/column\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tR:      \" << R \n            << \"\\n\\tC:      \" << C \n            );\n        typedef op_removerc2<EXP> op;\n        return matrix_op<op>(op(m.ref(),R,C));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, long C>\n    struct op_remove_col \n    {\n        op_remove_col( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = M::NR;\n        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (c < C)\n            {\n                return m(r,c); \n            }\n            else\n            {\n                return m(r,c+1); \n            }\n        }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc() - 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <typename M>\n    struct op_remove_col2 \n    {\n        op_remove_col2( const M& m_,  const long C_) : m(m_), C(C_){}\n        const M& m;\n        const long C;\n\n        const static long cost = M::cost+2;\n        const static long NR = M::NR;\n        const static long NC = (M::NC==0) ? 0 : (M::NC - 1);\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (c < C)\n            {\n                return m(r,c); \n            }\n            else\n            {\n                return m(r,c+1); \n            }\n        }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc() - 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        long C,\n        typename EXP\n        >\n    const matrix_op<op_remove_col<EXP, C> > remove_col (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // You can't remove the given column from the matrix because the matrix doesn't\n        // have a column with that index.\n        COMPILE_TIME_ASSERT((EXP::NC > C && C >= 0) || EXP::NC == 0);\n        DLIB_ASSERT(m.nc() > C && C >= 0 , \n            \"\\tconst matrix_exp remove_col<C>(const matrix_exp& m)\"\n            << \"\\n\\tYou can't remove a col from a matrix if it doesn't have it\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tC:      \" << C \n            );\n        typedef op_remove_col<EXP,C> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_remove_col2<EXP> > remove_col (\n        const matrix_exp<EXP>& m,\n        long C\n    )\n    {\n        DLIB_ASSERT(m.nc() > C && C >= 0 , \n            \"\\tconst matrix_exp remove_col(const matrix_exp& m,C)\"\n            << \"\\n\\tYou can't remove a col from a matrix if it doesn't have it\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tC:      \" << C \n            );\n        typedef op_remove_col2<EXP> op;\n        return matrix_op<op>(op(m.ref(),C));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, long R>\n    struct op_remove_row \n    {\n        op_remove_row( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r < R)\n            {\n                return m(r,c); \n            }\n            else\n            {\n                return m(r+1,c); \n            }\n        }\n\n        long nr () const { return m.nr() - 1; }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <typename M>\n    struct op_remove_row2 \n    {\n        op_remove_row2( const M& m_,  const long R_) : m(m_), R(R_){}\n        const M& m;\n        const long R;\n\n        const static long cost = M::cost+2;\n        const static long NR = (M::NR==0) ? 0 : (M::NR - 1);\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r < R)\n            {\n                return m(r,c); \n            }\n            else\n            {\n                return m(r+1,c); \n            }\n        }\n\n        long nr () const { return m.nr() - 1; }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        long R,\n        typename EXP\n        >\n    const matrix_op<op_remove_row<EXP,R> > remove_row (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // You can't remove the given row from the matrix because the matrix doesn't\n        // have a row with that index.\n        COMPILE_TIME_ASSERT((EXP::NR > R && R >= 0) || EXP::NR == 0);\n        DLIB_ASSERT(m.nr() > R && R >= 0, \n            \"\\tconst matrix_exp remove_row<R>(const matrix_exp& m)\"\n            << \"\\n\\tYou can't remove a row from a matrix if it doesn't have it\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tR:      \" << R \n            );\n        typedef op_remove_row<EXP,R> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_remove_row2<EXP> > remove_row (\n        const matrix_exp<EXP>& m,\n        long R\n    )\n    {\n        DLIB_ASSERT(m.nr() > R && R >= 0, \n            \"\\tconst matrix_exp remove_row(const matrix_exp& m, long R)\"\n            << \"\\n\\tYou can't remove a row from a matrix if it doesn't have it\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tR:      \" << R \n            );\n        typedef op_remove_row2<EXP> op;\n        return matrix_op<op>(op(m.ref(),R));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_diagm \n    {\n        op_diagm( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long N = M::NC*M::NR;\n        const static long NR = N;\n        const static long NC = N;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r==c)\n                return m(r); \n            else\n                return 0;\n        }\n\n        long nr () const { return (m.nr()>m.nc())? m.nr():m.nc(); }\n        long nc () const { return (m.nr()>m.nc())? m.nr():m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_diag_op<op_diagm<EXP> > diagm (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // You can only make a diagonal matrix out of a row or column vector\n        COMPILE_TIME_ASSERT(EXP::NR == 0 || EXP::NR == 1 || EXP::NC == 1 || EXP::NC == 0);\n        DLIB_ASSERT(is_vector(m), \n            \"\\tconst matrix_exp diagm(const matrix_exp& m)\"\n            << \"\\n\\tYou can only apply diagm() to a row or column matrix\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            );\n        typedef op_diagm<EXP> op;\n        return matrix_diag_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_diagm_mult : basic_op_mm<M1,M2>\n    {\n        op_diagm_mult( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        typedef typename M1::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 1;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r == c)\n                return this->m1(r,c)*this->m2(r,c); \n            else\n                return 0;\n        }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_diag_op<op_diagm_mult<EXP1,EXP2> > operator* (\n        const matrix_diag_exp<EXP1>& a,\n        const matrix_diag_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type, typename EXP2::type>::value));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n                    a.nc() == b.nc(), \n            \"\\tconst matrix_exp operator(const matrix_diag_exp& a, const matrix_diag_exp& b)\"\n            << \"\\n\\tYou can only multiply diagonal matrices together if they are the same size\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            );\n        typedef op_diagm_mult<EXP1,EXP2> op;\n        return matrix_diag_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_diag \n    {\n        op_diag( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost;\n        const static long NR = tmin<M::NR,M::NC>::value;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long ) const { return m(r,r); }\n\n        long nr () const { return std::min(m.nc(),m.nr()); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_diag<EXP> > diag (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_diag<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <typename EXP>\n    struct diag_exp\n    {\n        typedef matrix_op<op_diag<EXP> > type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename target_type>\n    struct op_cast \n    {\n        op_cast( const M& m_) : m(m_){}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef target_type type;\n        typedef const target_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const { return static_cast<target_type>(m(r,c)); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }\n    };\n\n    template <\n        typename target_type,\n        typename EXP\n        >\n    const matrix_op<op_cast<EXP, target_type> > matrix_cast (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_cast<EXP, target_type> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type lessthan(const type& val, const S& s)\n        {\n            if (val < s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_lessthan, impl::lessthan, 1);\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan<EXP,S> > >::type operator< (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_lessthan<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan<EXP,S> > >::type operator> (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_lessthan<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type lessthan_eq(const type& val, const S& s)\n        {\n            if (val <= s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_lessthan_eq, impl::lessthan_eq, 1);\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan_eq<EXP,S> > >::type operator<= (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_lessthan_eq<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_lessthan_eq<EXP,S> > >::type operator>= (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_lessthan_eq<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type greaterthan(const type& val, const S& s)\n        {\n            if (val > s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_greaterthan, impl::greaterthan, 1);\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan<EXP,S> > >::type operator> (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_greaterthan<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan<EXP,S> > >::type operator< (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_greaterthan<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type greaterthan_eq(const type& val, const S& s)\n        {\n            if (val >= s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_greaterthan_eq, impl::greaterthan_eq, 1);\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan_eq<EXP,S> > >::type operator>= (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_greaterthan_eq<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_greaterthan_eq<EXP,S> > >::type operator<= (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_greaterthan_eq<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type equal_to(const type& val, const S& s)\n        {\n            if (val == s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_equal_to, impl::equal_to, 1);\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_equal_to<EXP,S> > >::type operator== (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT( is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_equal_to<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_equal_to<EXP,S> > >::type operator== (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT( is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_equal_to<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename type, typename S>\n        inline type not_equal_to(const type& val, const S& s)\n        {\n            if (val != s)\n                return 1;\n            else\n                return 0;\n        }\n        \n    }\n    DLIB_DEFINE_OP_MS(op_not_equal_to, impl::not_equal_to, 1);\n\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_not_equal_to<EXP,S> > >::type operator!= (\n        const matrix_exp<EXP>& m,\n        const S& s\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_not_equal_to<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n    template <\n        typename EXP,\n        typename S\n        >\n    const typename enable_if<is_built_in_scalar_type<S>, matrix_op<op_not_equal_to<EXP,S> > >::type operator!= (\n        const S& s,\n        const matrix_exp<EXP>& m\n    )\n    {\n        // you can only use this relational operator with the built in scalar types like\n        // long, float, etc.\n        COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\n\n        typedef op_not_equal_to<EXP,S> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM,\n        typename U,\n        typename L\n        >\n    typename disable_if<is_matrix<U>,void>::type set_all_elements (\n        matrix<T,NR,NC,MM,L>& m,\n        const U& value\n    )\n    {\n        // The value you are trying to assign to each element of the m matrix\n        // doesn't have the appropriate type.\n        COMPILE_TIME_ASSERT(is_matrix<T>::value == is_matrix<U>::value);\n\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                m(r,c) = static_cast<T>(value);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM,\n        typename U,\n        typename L\n        >\n    typename enable_if<is_matrix<U>,void>::type set_all_elements (\n        matrix<T,NR,NC,MM,L>& m,\n        const U& value\n    )\n    {\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                m(r,c) = value;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    inline const typename matrix_exp<EXP>::matrix_type tmp (\n        const matrix_exp<EXP>& m\n    )\n    {\n        return typename matrix_exp<EXP>::matrix_type (m);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    constexpr bool is_row_major (\n        const matrix_exp<EXP>&\n    )\n    {\n        return is_same_type<typename EXP::layout_type,row_major_layout>::value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename lazy_disable_if<is_matrix<typename EXP::type>, EXP>::type sum (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = 0;\n        if (is_row_major(m))\n        {\n            for (long r = 0; r < m.nr(); ++r)\n            {\n                for (long c = 0; c < m.nc(); ++c)\n                {\n                    val += m(r,c);\n                }\n            }\n        }\n        else\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                for (long r = 0; r < m.nr(); ++r)\n                {\n                    val += m(r,c);\n                }\n            }\n        }\n        return val;\n    }\n\n    template <\n        typename EXP\n        >\n    const typename lazy_enable_if<is_matrix<typename EXP::type>, EXP>::type sum (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val;\n        if (m.size() > 0)\n            val.set_size(m(0,0).nr(),m(0,0).nc()); \n        set_all_elements(val,0);\n\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                val += m(r,c);\n            }\n        }\n        return val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_sumr \n    {\n        op_sumr(const M& m_) : m(m_) {}\n        const M& m;\n\n        const static long cost = M::cost+10;\n        const static long NR = 1;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long , long c) const\n        { \n            type temp = m(0,c);\n            for (long r = 1; r < m.nr(); ++r)\n                temp += m(r,c);\n            return temp; \n        }\n\n        long nr () const { return 1; }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    }; \n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_sumr<EXP> > sum_rows (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0 , \n                    \"\\tconst matrix_exp sum_rows(m)\"\n                    << \"\\n\\t The matrix can't be empty\"\n                    << \"\\n\\t m.size(): \" << m.size() \n        );\n        typedef op_sumr<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_sumc \n    {\n        op_sumc(const M& m_) : m(m_) {}\n        const M& m;\n\n        const static long cost = M::cost + 10;\n        const static long NR = M::NR;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long ) const\n        { \n            type temp = m(r,0);\n            for (long c = 1; c < m.nc(); ++c)\n                temp += m(r,c);\n            return temp; \n        }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    }; \n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_sumc<EXP> > sum_cols (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.size() > 0 , \n                    \"\\tconst matrix_exp sum_cols(m)\"\n                    << \"\\n\\t The matrix can't be empty\"\n                    << \"\\n\\t m.size(): \" << m.size() \n        );\n        typedef op_sumc<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    inline const typename disable_if<is_complex<typename EXP::type>, typename matrix_exp<EXP>::type>::type mean (\n        const matrix_exp<EXP>& m\n    )\n    {\n        return sum(m)/(m.nr()*m.nc());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    inline const typename enable_if<is_complex<typename EXP::type>, typename matrix_exp<EXP>::type>::type mean (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename EXP::type::value_type type;\n        return sum(m)/(type)(m.nr()*m.nc());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type variance (\n        const matrix_exp<EXP>& m\n    )\n    {\n        using std::pow;\n        using dlib::pow;\n        const typename matrix_exp<EXP>::type avg = mean(m);\n\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val;\n        val = 0;\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                val += pow(m(r,c) - avg,2);\n            }\n        }\n\n        if (m.nr() * m.nc() <= 1)\n        {\n            return val;\n        }\n        else\n        {\n            // Note, for some reason, in gcc 4.1 performing this division using a\n            // double instead of a long value avoids a segmentation fault.  That is, \n            // using 1.0 instead of 1 does the trick.\n            return val/(m.nr()*m.nc() - 1.0);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type stddev (\n        const matrix_exp<EXP>& m\n    )\n    {\n        using std::sqrt;\n        using dlib::sqrt;\n        return sqrt(variance(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// this is a workaround for a bug in visual studio 7.1\n    template <typename EXP>\n    struct visual_studio_sucks_cov_helper\n    {\n        typedef typename EXP::type inner_type;\n        typedef matrix<typename inner_type::type, inner_type::NR, inner_type::NR, typename EXP::mem_manager_type> type;\n    };\n\n    template <\n        typename EXP\n        >\n    const typename visual_studio_sucks_cov_helper<EXP>::type covariance (\n        const matrix_exp<EXP>& m\n    )\n    {\n        // perform static checks to make sure m is a column vector \n        COMPILE_TIME_ASSERT(EXP::NR == 0 || EXP::NR > 1);\n        COMPILE_TIME_ASSERT(EXP::NC == 1 || EXP::NC == 0);\n\n        // perform static checks to make sure the matrices contained in m are column vectors\n        COMPILE_TIME_ASSERT(EXP::type::NC == 1 || EXP::type::NC == 0 );\n\n        DLIB_ASSERT(m.size() > 1 && is_col_vector(m), \n            \"\\tconst matrix covariance(const matrix_exp& m)\"\n            << \"\\n\\tYou can only apply covariance() to a column matrix\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            );\n#ifdef ENABLE_ASSERTS\n        for (long i = 0; i < m.nr(); ++i)\n        {\n            DLIB_ASSERT(m(0).size() == m(i).size() && m(i).size() > 0 && is_col_vector(m(i)), \n                   \"\\tconst matrix covariance(const matrix_exp& m)\"\n                   << \"\\n\\tYou can only apply covariance() to a column matrix of column matrices\"\n                   << \"\\n\\tm(0).size(): \" << m(0).size()\n                   << \"\\n\\tm(i).size(): \" << m(i).size() \n                   << \"\\n\\tis_col_vector(m(i)): \" << (is_col_vector(m(i)) ? \"true\" : \"false\")\n                   << \"\\n\\ti:         \" << i \n                );\n        }\n#endif\n\n        // now perform the actual calculation of the covariance matrix.\n        typename visual_studio_sucks_cov_helper<EXP>::type cov(m(0).nr(),m(0).nr());\n        set_all_elements(cov,0);\n\n        const typename EXP::type avg = mean(m);\n\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            cov += (m(r) - avg)*trans(m(r) - avg);\n        }\n\n        cov *= 1.0 / (m.nr() - 1.0);\n        return cov;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const typename matrix_exp<EXP>::type prod (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef typename matrix_exp<EXP>::type type;\n\n        type val = 1;\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                val *= m(r,c);\n            }\n        }\n        return val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    struct op_uniform_matrix_3 : does_not_alias \n    {\n        op_uniform_matrix_3(const long& rows_, const long& cols_, const T& val_ ) : \n            rows(rows_), cols(cols_), val(val_)  {}\n\n        const long rows;\n        const long cols;\n        const T val;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T& const_ret_type;\n        const_ret_type apply (long, long ) const { return val; }\n\n        long nr() const { return rows; }\n        long nc() const { return cols; }\n    };\n\n    template <\n        typename T\n        >\n    const matrix_op<op_uniform_matrix_3<T> > uniform_matrix (\n        long nr,\n        long nc,\n        const T& val\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tconst matrix_exp uniform_matrix<T>(nr, nc, val)\"\n            << \"\\n\\tnr and nc have to be bigger than 0\"\n            << \"\\n\\tnr: \" << nr\n            << \"\\n\\tnc: \" << nc\n            );\n        typedef op_uniform_matrix_3<T> op;\n        return matrix_op<op>(op(nr, nc, val));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_uniform_matrix_3<T> > zeros_matrix (\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tconst matrix_exp zeros_matrix<T>(nr, nc)\"\n            << \"\\n\\tnr and nc have to be >= 0\"\n            << \"\\n\\tnr: \" << nr\n            << \"\\n\\tnc: \" << nc\n            );\n        typedef op_uniform_matrix_3<T> op;\n        return matrix_op<op>(op(nr, nc, 0));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_uniform_matrix_3<typename EXP::type> > zeros_matrix (\n        const matrix_exp<EXP>& mat\n    )\n    {\n        DLIB_ASSERT(mat.nr() >= 0 && mat.nc() >= 0, \n            \"\\tconst matrix_exp zeros_matrix(mat)\"\n            << \"\\n\\t nr and nc have to be >= 0\"\n            << \"\\n\\t mat.nr(): \" << mat.nr()\n            << \"\\n\\t mat.nc(): \" << mat.nc()\n            );\n        typedef typename EXP::type T;\n        typedef op_uniform_matrix_3<T> op;\n        return matrix_op<op>(op(mat.nr(), mat.nc(), 0));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_uniform_matrix_3<T> > ones_matrix (\n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tconst matrix_exp ones_matrix<T>(nr, nc)\"\n            << \"\\n\\tnr and nc have to be >= 0\"\n            << \"\\n\\tnr: \" << nr\n            << \"\\n\\tnc: \" << nc\n            );\n        typedef op_uniform_matrix_3<T> op;\n        return matrix_op<op>(op(nr, nc, 1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_uniform_matrix_3<typename EXP::type> > ones_matrix (\n        const matrix_exp<EXP>& mat\n    )\n    {\n        DLIB_ASSERT(mat.nr() >= 0 && mat.nc() >= 0, \n            \"\\tconst matrix_exp ones_matrix(mat)\"\n            << \"\\n\\t nr and nc have to be >= 0\"\n            << \"\\n\\t mat.nr(): \" << mat.nr()\n            << \"\\n\\t mat.nc(): \" << mat.nc()\n            );\n        typedef typename EXP::type T;\n        typedef op_uniform_matrix_3<T> op;\n        return matrix_op<op>(op(mat.nr(), mat.nc(), 1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long NR_, \n        long NC_ \n        >\n    struct op_uniform_matrix_2 : does_not_alias \n    {\n        op_uniform_matrix_2( const T& val_ ) : val(val_) {}\n        const T val;\n\n        const static long cost = 1;\n        const static long NR = NR_;\n        const static long NC = NC_;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T& const_ret_type;\n\n        const_ret_type apply (long , long ) const { return val; }\n\n        long nr() const { return NR; }\n        long nc() const { return NC; }\n    };\n\n    template <\n        typename T,\n        long NR, \n        long NC\n        >\n    const matrix_op<op_uniform_matrix_2<T,NR,NC> > uniform_matrix (\n        const T& val\n    )\n    {\n        COMPILE_TIME_ASSERT(NR > 0 && NC > 0);\n\n        typedef op_uniform_matrix_2<T,NR,NC> op;\n        return matrix_op<op>(op(val));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long NR_, \n        long NC_, \n        T val\n        >\n    struct op_uniform_matrix : does_not_alias \n    {\n        const static long cost = 1;\n        const static long NR = NR_;\n        const static long NC = NC_;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T const_ret_type;\n        const_ret_type apply ( long , long ) const { return val; }\n\n        long nr() const { return NR; }\n        long nc() const { return NC; }\n    };\n\n    template <\n        typename T, \n        long NR, \n        long NC, \n        T val\n        >\n    const matrix_op<op_uniform_matrix<T,NR,NC,val> > uniform_matrix (\n    )\n    {\n        COMPILE_TIME_ASSERT(NR > 0 && NC > 0);\n        typedef op_uniform_matrix<T,NR,NC,val> op;\n        return matrix_op<op>(op());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    struct op_gaussian_randm : does_not_alias \n    {\n        op_gaussian_randm (\n            long nr_,\n            long nc_,\n            unsigned long seed_\n        ) :_nr(nr_), _nc(nc_), seed(seed_){}\n\n        const long _nr;\n        const long _nc;\n        const unsigned long seed;\n\n        const static long cost = 100;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef double type;\n        typedef double const_ret_type;\n        const_ret_type apply ( long r, long c) const { return gaussian_random_hash(r,c,seed); }\n\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n    };\n\n    inline const matrix_op<op_gaussian_randm> gaussian_randm (\n        long nr,\n        long nc,\n        unsigned long seed = 0\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tmatrix_exp gaussian_randm(nr, nc, seed)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tnr: \" << nr \n            << \"\\n\\tnc: \" << nc \n            );\n\n        typedef op_gaussian_randm op;\n        return matrix_op<op>(op(nr,nc,seed));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_add_diag \n    {\n        op_add_diag( const M& m_, const typename M::type& value_) : m(m_), value(value_){}\n        const M& m;\n        const typename M::type value;\n\n        const static long cost = M::cost+1;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r==c)\n                return m(r,c)+value; \n            else\n                return m(r,c);\n        }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T \n        >\n    struct op_identity_matrix_2 : does_not_alias \n    {\n        op_identity_matrix_2(const long& size_) : size(size_) {}\n\n        const long size;\n\n        const static long cost = 1;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T const_ret_type;\n        const_ret_type apply (long r, long c) const { return static_cast<type>(r == c); }\n\n        long nr() const { return size; }\n        long nc() const { return size; }\n    };\n\n    template <\n        typename T,\n        typename U\n        >\n    const matrix_diag_op<op_identity_matrix_2<T> > identity_matrix (\n        const U& size \n    )\n    {\n        // the size argument must be some scalar value, not a matrix!\n        COMPILE_TIME_ASSERT(is_matrix<U>::value == false);\n\n        DLIB_ASSERT(size > 0, \n            \"\\tconst matrix_exp identity_matrix<T>(size)\"\n            << \"\\n\\tsize must be bigger than 0\"\n            << \"\\n\\tsize: \" << size \n            );\n        typedef op_identity_matrix_2<T> op;\n        return matrix_diag_op<op>(op(size));\n    }\n\n    template <\n        typename EXP \n        >\n    const matrix_diag_op<op_identity_matrix_2<typename EXP::type> > identity_matrix (\n        const matrix_exp<EXP>& mat\n    )\n    {\n        DLIB_ASSERT(mat.nr() == mat.nc(), \n            \"\\tconst matrix_exp identity_matrix(mat)\"\n            << \"\\n\\t mat must be a square matrix.\"\n            << \"\\n\\t mat.nr(): \" << mat.nr() \n            << \"\\n\\t mat.nc(): \" << mat.nc() \n            );\n        typedef typename EXP::type T;\n        typedef op_identity_matrix_2<T> op;\n        return matrix_diag_op<op>(op(mat.nr()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<EXP>& lhs,\n        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& DLIB_IF_ASSERT(rhs)\n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(lhs.ref(),1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        typename T\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& DLIB_IF_ASSERT(lhs), \n        const matrix_exp<EXP>& rhs\n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(rhs.ref(),1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long N\n        >\n    struct op_const_diag_matrix : does_not_alias \n    {\n        op_const_diag_matrix(const long& size_, const T& value_) : size(size_),value(value_) {}\n\n        const long size;\n        const T value;\n\n        const static long cost = 1;\n        const static long NR = N;\n        const static long NC = N;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T const_ret_type;\n        const_ret_type apply (long r, long c) const \n        { \n            if (r == c)\n                return value;\n            else\n                return 0;\n        }\n\n        long nr() const { return size; }\n        long nc() const { return size; }\n    };\n\n    template <\n        typename T,\n        typename U\n        >\n    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (\n        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m,\n        const U& value\n    )\n    {\n        typedef op_const_diag_matrix<T,0> op;\n        return matrix_diag_op<op>(op(m.nr(), value));\n    }\n\n    template <\n        typename T,\n        typename U\n        >\n    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (\n        const U& value,\n        const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m\n    )\n    {\n        typedef op_const_diag_matrix<T,0> op;\n        return matrix_diag_op<op>(op(m.nr(), value));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        typename T,\n        long N\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<EXP>& lhs,\n        const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& rhs \n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(lhs.ref(),rhs.ref().op.value));\n    }\n\n    template <\n        typename EXP,\n        typename T,\n        long N\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& lhs, \n        const matrix_exp<EXP>& rhs\n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(rhs.ref(),lhs.ref().op.value));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long N\n        >\n    struct op_identity_matrix : does_not_alias \n    {\n        const static long cost = 1;\n        const static long NR = N;\n        const static long NC = N;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n        typedef T type;\n        typedef const T const_ret_type;\n        const_ret_type apply ( long r, long c) const { return static_cast<type>(r == c); }\n\n        long nr () const { return NR; }\n        long nc () const { return NC; }\n    };\n\n    template <\n        typename T, \n        long N\n        >\n    const matrix_diag_op<op_identity_matrix<T,N> > identity_matrix (\n    )\n    {\n        COMPILE_TIME_ASSERT(N > 0);\n\n        typedef op_identity_matrix<T,N> op;\n        return matrix_diag_op<op>(op());\n    }\n\n    template <\n        typename T,\n        typename U,\n        long N\n        >\n    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (\n        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m,\n        const U& value\n    )\n    {\n        typedef op_const_diag_matrix<T,N> op;\n        return matrix_diag_op<op>(op(m.nr(), value));\n    }\n\n    template <\n        typename T,\n        typename U,\n        long N\n        >\n    const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (\n        const U& value,\n        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m\n    )\n    {\n        typedef op_const_diag_matrix<T,N> op;\n        return matrix_diag_op<op>(op(m.nr(), value));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        typename T,\n        long N\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& DLIB_IF_ASSERT(lhs), \n        const matrix_exp<EXP>& rhs\n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(rhs.ref(),1));\n    }\n\n    template <\n        typename EXP,\n        typename T,\n        long N\n        >\n    const matrix_op<op_add_diag<EXP> > operator+ (\n        const matrix_exp<EXP>& lhs,\n        const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& DLIB_IF_ASSERT(rhs)\n    )\n    {\n        // both matrices must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));\n\n        // You can only add matrices together if they both have the same number of rows and columns.\n        DLIB_ASSERT(lhs.nc() == rhs.nc() &&\n                    lhs.nr() == rhs.nr(), \n            \"\\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)\"\n            << \"\\n\\tYou are trying to add two incompatible matrices together\"\n            << \"\\n\\tlhs.nr(): \" << lhs.nr()\n            << \"\\n\\tlhs.nc(): \" << lhs.nc()\n            << \"\\n\\trhs.nr(): \" << rhs.nr()\n            << \"\\n\\trhs.nc(): \" << rhs.nc()\n            << \"\\n\\t&lhs: \" << &lhs \n            << \"\\n\\t&rhs: \" << &rhs \n            );\n\n\n        typedef op_add_diag<EXP> op;\n        return matrix_op<op>(op(lhs.ref(),1));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, long R, long C>\n    struct op_rotate \n    {\n        op_rotate(const M& m_) : m(m_) {}\n        const M& m;\n\n        const static long cost = M::cost + 2;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        const_ret_type apply ( long r, long c) const { return m((r+R)%m.nr(),(c+C)%m.nc()); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        long R,\n        long C,\n        typename EXP\n        >\n    const matrix_op<op_rotate<EXP,R,C> > rotate (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_rotate<EXP,R,C> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        // A template to tell me if two types can be multiplied together in a sensible way.  Here\n        // I'm saying it is ok if they are both the same type or one is the complex version of the other.\n        template <typename T, typename U> struct compatible { static const bool value = false;  typedef T type; };\n        template <typename T>             struct compatible<T,T> { static const bool value = true; typedef T type; };\n        template <typename T>             struct compatible<std::complex<T>,T> { static const bool value = true; typedef std::complex<T> type;  };\n        template <typename T>             struct compatible<T,std::complex<T> > { static const bool value = true; typedef std::complex<T> type; };\n    }\n\n\n    template <typename M1, typename M2>\n    struct op_pointwise_multiply : basic_op_mm<M1,M2>\n    {\n        op_pointwise_multiply( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        typedef typename impl::compatible<typename M1::type, typename M2::type>::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 1;\n\n        const_ret_type apply ( long r, long c) const\n        { return this->m1(r,c)*this->m2(r,c); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_pointwise_multiply<EXP1,EXP2> > pointwise_multiply (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((impl::compatible<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc(), \n            \"\\tconst matrix_exp pointwise_multiply(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\tYou can only make a do a pointwise multiply with two equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            );\n        typedef op_pointwise_multiply<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_pointwise_multiply3 : basic_op_mmm<M1,M2,M3>\n    {\n        op_pointwise_multiply3( const M1& m1_, const M2& m2_, const M3& m3_) : \n            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + 2;\n\n        const_ret_type apply (long r, long c) const\n        { return this->m1(r,c)*this->m2(r,c)*this->m3(r,c); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    inline const matrix_op<op_pointwise_multiply3<EXP1,EXP2,EXP3> > \n        pointwise_multiply (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b, \n        const matrix_exp<EXP3>& c\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc(), \n            \"\\tconst matrix_exp pointwise_multiply(a,b,c)\"\n            << \"\\n\\tYou can only make a do a pointwise multiply between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc() \n            );\n\n        typedef op_pointwise_multiply3<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3, typename M4>\n    struct op_pointwise_multiply4 : basic_op_mmmm<M1,M2,M3,M4>\n    {\n        op_pointwise_multiply4( const M1& m1_, const M2& m2_, const M3& m3_, const M4& m4_) : \n            basic_op_mmmm<M1,M2,M3,M4>(m1_,m2_,m3_,m4_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + M4::cost + 3;\n\n        const_ret_type apply (long r, long c) const\n        { return this->m1(r,c)*this->m2(r,c)*this->m3(r,c)*this->m4(r,c); }\n    };\n\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3,\n        typename EXP4\n        >\n    inline const matrix_op<op_pointwise_multiply4<EXP1,EXP2,EXP3,EXP4> > pointwise_multiply (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b, \n        const matrix_exp<EXP3>& c,\n        const matrix_exp<EXP4>& d\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP3::type,typename EXP4::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0 );\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        COMPILE_TIME_ASSERT(EXP3::NR == EXP4::NR || EXP3::NR == 0 || EXP4::NR == 0);\n        COMPILE_TIME_ASSERT(EXP3::NC == EXP4::NC || EXP3::NC == 0 || EXP4::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc() &&\n               c.nr() == d.nr() &&\n               c.nc() == d.nc(), \n            \"\\tconst matrix_exp pointwise_multiply(a,b,c,d)\"\n            << \"\\n\\tYou can only make a do a pointwise multiply between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc() \n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc() \n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc() \n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc() \n            );\n\n        typedef op_pointwise_multiply4<EXP1,EXP2,EXP3,EXP4> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref(),d.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_pointwise_divide : basic_op_mm<M1,M2>\n    {\n        op_pointwise_divide( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\n\n        typedef typename impl::compatible<typename M1::type, typename M2::type>::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 1;\n\n        const_ret_type apply ( long r, long c) const\n        { return this->m1(r,c)/this->m2(r,c); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_pointwise_divide<EXP1,EXP2> > pointwise_divide (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b\n    )\n    {\n        COMPILE_TIME_ASSERT((impl::compatible<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc(),\n            \"\\tconst matrix_exp pointwise_divide(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\tYou can only make a do a pointwise divide with two equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc()\n            );\n        typedef op_pointwise_divide<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_pointwise_divide3 : basic_op_mmm<M1,M2,M3>\n    {\n        op_pointwise_divide3( const M1& m1_, const M2& m2_, const M3& m3_) :\n            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + 2;\n\n        const_ret_type apply (long r, long c) const\n        { return this->m1(r,c)/this->m2(r,c)/this->m3(r,c); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    inline const matrix_op<op_pointwise_divide3<EXP1,EXP2,EXP3> >\n        pointwise_divide (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b,\n        const matrix_exp<EXP3>& c\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc(),\n            \"\\tconst matrix_exp pointwise_divide(a,b,c)\"\n            << \"\\n\\tYou can only make a do a pointwise divide between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc()\n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc()\n            );\n\n        typedef op_pointwise_divide3<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3, typename M4>\n    struct op_pointwise_divide4 : basic_op_mmmm<M1,M2,M3,M4>\n    {\n        op_pointwise_divide4( const M1& m1_, const M2& m2_, const M3& m3_, const M4& m4_) :\n            basic_op_mmmm<M1,M2,M3,M4>(m1_,m2_,m3_,m4_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + M4::cost + 3;\n\n        const_ret_type apply (long r, long c) const\n        { return this->m1(r,c)/this->m2(r,c)/this->m3(r,c)/this->m4(r,c); }\n    };\n\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3,\n        typename EXP4\n        >\n    inline const matrix_op<op_pointwise_divide4<EXP1,EXP2,EXP3,EXP4> > pointwise_divide (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b,\n        const matrix_exp<EXP3>& c,\n        const matrix_exp<EXP4>& d\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP3::type,typename EXP4::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        COMPILE_TIME_ASSERT(EXP3::NR == EXP4::NR || EXP3::NR == 0 || EXP4::NR == 0);\n        COMPILE_TIME_ASSERT(EXP3::NC == EXP4::NC || EXP3::NC == 0 || EXP4::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() &&\n               a.nc() == b.nc() &&\n               b.nr() == c.nr() &&\n               b.nc() == c.nc() &&\n               c.nr() == d.nr() &&\n               c.nc() == d.nc(),\n            \"\\tconst matrix_exp pointwise_divide(a,b,c,d)\"\n            << \"\\n\\tYou can only make a do a pointwise divide between equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc()\n            << \"\\n\\tc.nr(): \" << c.nr()\n            << \"\\n\\tc.nc(): \" << c.nc()\n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc()\n            );\n\n        typedef op_pointwise_divide4<EXP1,EXP2,EXP3,EXP4> op;\n        return matrix_op<op>(op(a.ref(),b.ref(),c.ref(),d.ref()));\n\t}\n\n    // ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_pointwise_pow : basic_op_mm<M1, M2>\n    {\n        op_pointwise_pow(const M1& m1_, const M2& m2_) : basic_op_mm<M1, M2>(m1_, m2_) {}\n\n        typedef typename impl::compatible<typename M1::type, typename M2::type>::type type;\n        typedef const type const_ret_type;\n        const static long cost = M1::cost + M2::cost + 7;\n\n        const_ret_type apply(long r, long c) const\n        { return std::pow(this->m1(r, c), this->m2(r, c)); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_pointwise_pow<EXP1, EXP2>> pointwise_pow (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b\n    )\n    {\n        COMPILE_TIME_ASSERT((impl::compatible<typename EXP1::type, typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\n        DLIB_ASSERT(a.nr() == b.nr() && a.nc() == b.nc(),\n            \"\\tconst matrix_exp pointwise_pow(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\tYou can only make a do a pointwise power with two equally sized matrices\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\tb.nc(): \" << b.nc()\n        );\n        typedef op_pointwise_pow<EXP1, EXP2> op;\n        return matrix_op<op>(op(a.ref(), b.ref()));\n    }\n\n    // ----------------------------------------------------------------------------------------\n\n    template <\n        typename P,\n        int type = static_switch<\n            pixel_traits<P>::grayscale,\n            pixel_traits<P>::rgb,\n            pixel_traits<P>::hsi,\n            pixel_traits<P>::hsv,\n            pixel_traits<P>::rgb_alpha,\n            pixel_traits<P>::lab\n            >::value\n        >\n    struct pixel_to_vector_helper;\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,1>\n    {\n        template <typename M>\n        static void assign (\n            M& m,\n            const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel);\n        }\n    };\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,2>\n    {\n        template <typename M>\n        static void assign (\n            M& m,\n            const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel.red);\n            m(1) = static_cast<typename M::type>(pixel.green);\n            m(2) = static_cast<typename M::type>(pixel.blue);\n        }\n    };\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,3>\n    {\n        template <typename M>\n        static void assign (\n            M& m,\n            const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel.h);\n            m(1) = static_cast<typename M::type>(pixel.s);\n            m(2) = static_cast<typename M::type>(pixel.i);\n        }\n    };\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,4>\n    {\n        template <typename M>\n        static void assign (\n            M& m,\n            const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel.h);\n            m(1) = static_cast<typename M::type>(pixel.s);\n            m(2) = static_cast<typename M::type>(pixel.v);\n        }\n    };\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,5>\n    {\n        template <typename M>\n        static void assign (\n            M& m,\n            const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel.red);\n            m(1) = static_cast<typename M::type>(pixel.green);\n            m(2) = static_cast<typename M::type>(pixel.blue);\n            m(3) = static_cast<typename M::type>(pixel.alpha);\n        }\n    };\n\n    template <typename P>\n    struct pixel_to_vector_helper<P,6>\n    {\n        template <typename M>\n        static void assign (\n                M& m,\n                const P& pixel\n        )\n        {\n            m(0) = static_cast<typename M::type>(pixel.l);\n            m(1) = static_cast<typename M::type>(pixel.a);\n            m(2) = static_cast<typename M::type>(pixel.b);\n        }\n    };\n\n\n    template <\n        typename T,\n        typename P\n        >\n    inline const matrix<T,pixel_traits<P>::num,1> pixel_to_vector (\n        const P& pixel\n    )\n    {\n        COMPILE_TIME_ASSERT(pixel_traits<P>::num > 0);\n        matrix<T,pixel_traits<P>::num,1> m;\n        pixel_to_vector_helper<P>::assign(m,pixel);\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P,\n        int type = static_switch<\n            pixel_traits<P>::grayscale,\n            pixel_traits<P>::rgb,\n            pixel_traits<P>::hsi,\n            pixel_traits<P>::hsv,\n            pixel_traits<P>::rgb_alpha,\n            pixel_traits<P>::lab\n            >::value\n        >\n    struct vector_to_pixel_helper;\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,1>\n    {\n        template <typename M>\n        static void assign (\n            P& pixel,\n            const M& m\n        )\n        {\n            pixel = static_cast<P>(m(0));\n        }\n    };\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,2>\n    {\n        template <typename M>\n        static void assign (\n            P& pixel,\n            const M& m\n        )\n        {\n            pixel.red = static_cast<unsigned char>(m(0));\n            pixel.green = static_cast<unsigned char>(m(1));\n            pixel.blue = static_cast<unsigned char>(m(2));\n        }\n    };\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,3>\n    {\n        template <typename M>\n        static void assign (\n            P& pixel,\n            const M& m\n        )\n        {\n            pixel.h = static_cast<unsigned char>(m(0));\n            pixel.s = static_cast<unsigned char>(m(1));\n            pixel.i = static_cast<unsigned char>(m(2));\n        }\n    };\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,4>\n    {\n        template <typename M>\n        static void assign (\n            P& pixel,\n            const M& m\n        )\n        {\n            pixel.h = static_cast<unsigned char>(m(0));\n            pixel.s = static_cast<unsigned char>(m(1));\n            pixel.v = static_cast<unsigned char>(m(2));\n        }\n    };\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,5>\n    {\n        template <typename M>\n        static void assign (\n            P& pixel,\n            const M& m\n        )\n        {\n            pixel.red = static_cast<unsigned char>(m(0));\n            pixel.green = static_cast<unsigned char>(m(1));\n            pixel.blue = static_cast<unsigned char>(m(2));\n            pixel.alpha = static_cast<unsigned char>(m(3));\n        }\n    };\n\n    template <typename P>\n    struct vector_to_pixel_helper<P,6>\n    {\n        template <typename M>\n        static void assign (\n                P& pixel,\n                const M& m\n        )\n        {\n            pixel.l = static_cast<unsigned char>(m(0));\n            pixel.a = static_cast<unsigned char>(m(1));\n            pixel.b = static_cast<unsigned char>(m(2));\n        }\n    };\n\n    template <\n        typename P,\n        typename EXP\n        >\n    inline void vector_to_pixel (\n        P& pixel,\n        const matrix_exp<EXP>& vector \n    )\n    {\n        COMPILE_TIME_ASSERT(pixel_traits<P>::num == matrix_exp<EXP>::NR);\n        COMPILE_TIME_ASSERT(matrix_exp<EXP>::NC == 1);\n        vector_to_pixel_helper<P>::assign(pixel,vector);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, long lower, long upper>\n    struct op_clamp : basic_op_m<M>\n    {\n        op_clamp( const M& m_) : basic_op_m<M>(m_){}\n\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        const static long cost = M::cost + 2;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            const type temp = this->m(r,c);\n            if (temp > static_cast<type>(upper))\n                return static_cast<type>(upper);\n            else if (temp < static_cast<type>(lower))\n                return static_cast<type>(lower);\n            else\n                return temp;\n        }\n    };\n\n    template <\n        long l, \n        long u,\n        typename EXP\n        >\n    const matrix_op<op_clamp<EXP,l,u> > clamp (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_clamp<EXP,l,u> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_clamp2 : basic_op_m<M>\n    {\n        typedef typename M::type type;\n\n        op_clamp2( const M& m_, const type& l, const type& u) : \n            basic_op_m<M>(m_), lower(l), upper(u){}\n\n        const type& lower;\n        const type& upper;\n\n        typedef const typename M::type const_ret_type;\n        const static long cost = M::cost + 2;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            const type temp = this->m(r,c);\n            if (temp > upper)\n                return upper;\n            else if (temp < lower)\n                return lower;\n            else\n                return temp;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_clamp2<EXP> > clamp (\n        const matrix_exp<EXP>& m,\n        const typename EXP::type& lower,\n        const typename EXP::type& upper\n    )\n    {\n        typedef op_clamp2<EXP> op;\n        return matrix_op<op>(op(m.ref(),lower, upper));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2, typename M3>\n    struct op_clamp_m : basic_op_mmm<M1,M2,M3>\n    {\n        op_clamp_m( const M1& m1_, const M2& m2_, const M3& m3_) : \n            basic_op_mmm<M1,M2,M3>(m1_,m2_,m3_){}\n\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        const static long cost = M1::cost + M2::cost + M3::cost + 2;\n\n        const_ret_type apply (long r, long c) const\n        { \n            const type val = this->m1(r,c);\n            const type lower = this->m2(r,c);\n            const type upper = this->m3(r,c);\n            if (val <= upper)\n            {\n                if (lower <= val)\n                    return val;\n                else\n                    return lower;\n            }\n            else \n            {\n                return upper;\n            }\n        }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    const matrix_op<op_clamp_m<EXP1,EXP2,EXP3> > \n    clamp (\n        const matrix_exp<EXP1>& m,\n        const matrix_exp<EXP2>& lower, \n        const matrix_exp<EXP3>& upper\n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP2::type,typename EXP3::type>::value == true));\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NR == 0 || EXP2::NC == 0);\n        COMPILE_TIME_ASSERT(EXP2::NR == EXP3::NR || EXP2::NR == 0 || EXP3::NR == 0);\n        COMPILE_TIME_ASSERT(EXP2::NC == EXP3::NC || EXP2::NC == 0 || EXP3::NC == 0);\n        DLIB_ASSERT(m.nr() == lower.nr() &&\n                    m.nc() == lower.nc() &&\n                    m.nr() == upper.nr() &&\n                    m.nc() == upper.nc(),\n            \"\\tconst matrix_exp clamp(m,lower,upper)\"\n            << \"\\n\\t Invalid inputs were given to this function.\"\n            << \"\\n\\t m.nr():     \" << m.nr()\n            << \"\\n\\t m.nc():     \" << m.nc() \n            << \"\\n\\t lower.nr(): \" << lower.nr()\n            << \"\\n\\t lower.nc(): \" << lower.nc() \n            << \"\\n\\t upper.nr(): \" << upper.nr()\n            << \"\\n\\t upper.nc(): \" << upper.nc() \n            );\n\n        typedef op_clamp_m<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(m.ref(),lower.ref(),upper.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_lowerbound : basic_op_m<M>\n    {\n        typedef typename M::type type;\n\n        op_lowerbound( const M& m_, const type& thresh_) : \n            basic_op_m<M>(m_), thresh(thresh_){}\n\n        const type& thresh;\n\n        typedef const typename M::type const_ret_type;\n        const static long cost = M::cost + 2;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            const type temp = this->m(r,c);\n            if (temp >= thresh)\n                return temp;\n            else\n                return thresh;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_lowerbound<EXP> > lowerbound (\n        const matrix_exp<EXP>& m,\n        const typename EXP::type& thresh\n    )\n    {\n        typedef op_lowerbound<EXP> op;\n        return matrix_op<op>(op(m.ref(), thresh));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_upperbound : basic_op_m<M>\n    {\n        typedef typename M::type type;\n\n        op_upperbound( const M& m_, const type& thresh_) : \n            basic_op_m<M>(m_), thresh(thresh_){}\n\n        const type& thresh;\n\n        typedef const typename M::type const_ret_type;\n        const static long cost = M::cost + 2;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            const type temp = this->m(r,c);\n            if (temp <= thresh)\n                return temp;\n            else\n                return thresh;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_upperbound<EXP> > upperbound (\n        const matrix_exp<EXP>& m,\n        const typename EXP::type& thresh\n    )\n    {\n        typedef op_upperbound<EXP> op;\n        return matrix_op<op>(op(m.ref(), thresh));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_reshape \n    {\n        op_reshape(const M& m_, const long& rows_, const long& cols_) : m(m_),rows(rows_),cols(cols_) {}\n        const M& m;\n        const long rows;\n        const long cols;\n\n        const static long cost = M::cost+2;\n        const static long NR = 0;\n        const static long NC = 0;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            const long idx = r*cols + c;\n            return m(idx/m.nc(), idx%m.nc());\n        }\n\n        long nr () const { return rows; }\n        long nc () const { return cols; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_reshape<EXP> > reshape (\n        const matrix_exp<EXP>& m,\n        const long& rows,\n        const long& cols \n    )\n    {\n        DLIB_ASSERT(m.size() == rows*cols && rows > 0 && cols > 0, \n            \"\\tconst matrix_exp reshape(m, rows, cols)\"\n            << \"\\n\\t The size of m must match the dimensions you want to reshape it into.\"\n            << \"\\n\\t m.size():  \" << m.size()\n            << \"\\n\\t rows*cols: \" << rows*cols \n            << \"\\n\\t rows:      \" << rows \n            << \"\\n\\t cols:      \" << cols \n            );\n\n        typedef op_reshape<EXP> op;\n        return matrix_op<op>(op(m.ref(), rows, cols));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    typename disable_if<is_complex<typename EXP1::type>,bool>::type equal (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b,\n        const typename EXP1::type eps = 100*std::numeric_limits<typename EXP1::type>::epsilon()\n    )\n    {\n        // check if the dimensions don't match\n        if (a.nr() != b.nr() || a.nc() != b.nc())\n            return false;\n\n        for (long r = 0; r < a.nr(); ++r)\n        {\n            for (long c = 0; c < a.nc(); ++c)\n            {\n                if (std::abs(a(r,c)-b(r,c)) > eps)\n                    return false;\n            }\n        }\n\n        // no non-equal points found so we return true \n        return true;\n    }\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    typename enable_if<is_complex<typename EXP1::type>,bool>::type equal (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b,\n        const typename EXP1::type::value_type eps = 100*std::numeric_limits<typename EXP1::type::value_type>::epsilon()\n    )\n    {\n        // check if the dimensions don't match\n        if (a.nr() != b.nr() || a.nc() != b.nc())\n            return false;\n\n        for (long r = 0; r < a.nr(); ++r)\n        {\n            for (long c = 0; c < a.nc(); ++c)\n            {\n                if (std::abs(real(a(r,c)-b(r,c))) > eps ||\n                    std::abs(imag(a(r,c)-b(r,c))) > eps)\n                    return false;\n            }\n        }\n\n        // no non-equal points found so we return true \n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_scale_columns  \n    {\n        op_scale_columns(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n\n        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(c); }\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) ; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_scale_columns<EXP1,EXP2> > scale_columns (\n        const matrix_exp<EXP1>& m,\n        const matrix_exp<EXP2>& v \n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        // The v argument must be a row or column vector.\n        COMPILE_TIME_ASSERT((EXP2::NC == 1 || EXP2::NC == 0) || (EXP2::NR == 1 || EXP2::NR == 0));\n\n        // figure out the compile time known length of v\n        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);\n\n        // the length of v must match the number of columns in m\n        COMPILE_TIME_ASSERT(EXP1::NC == v_len || EXP1::NC == 0 || v_len == 0);\n\n        DLIB_ASSERT(is_vector(v) == true && v.size() == m.nc(), \n            \"\\tconst matrix_exp scale_columns(m, v)\"\n            << \"\\n\\tv must be a row or column vector and its length must match the number of columns in m\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tv.nr(): \" << v.nr()\n            << \"\\n\\tv.nc(): \" << v.nc() \n            );\n        typedef op_scale_columns<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),v.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_scale_columns_diag  \n    {\n        op_scale_columns_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n\n        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(c,c); }\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) ; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.aliases(item); }\n    };\n\n// turn expressions of the form mat*diagonal_matrix into scale_columns(mat, d)\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_scale_columns_diag<EXP1,EXP2> > operator* (\n        const matrix_exp<EXP1>& m,\n        const matrix_diag_exp<EXP2>& d \n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n\n        // figure out the compile time known length of d\n        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);\n\n        // the length of d must match the number of columns in m\n        COMPILE_TIME_ASSERT(EXP1::NC == v_len || EXP1::NC == 0 || v_len == 0);\n\n        DLIB_ASSERT(m.nc() == d.nr(), \n            \"\\tconst matrix_exp operator*(m, d)\"\n            << \"\\n\\tmatrix dimensions don't match\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc() \n            );\n        typedef op_scale_columns_diag<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),d.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_scale_rows  \n    {\n        op_scale_rows(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n\n        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(r); }\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) ; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_scale_rows<EXP1,EXP2> > scale_rows (\n        const matrix_exp<EXP1>& m,\n        const matrix_exp<EXP2>& v \n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        // The v argument must be a row or column vector.\n        COMPILE_TIME_ASSERT((EXP2::NC == 1 || EXP2::NC == 0) || (EXP2::NR == 1 || EXP2::NR == 0));\n\n        // figure out the compile time known length of v\n        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);\n\n        // the length of v must match the number of rows in m\n        COMPILE_TIME_ASSERT(EXP1::NR == v_len || EXP1::NR == 0 || v_len == 0);\n\n        DLIB_ASSERT(is_vector(v) == true && v.size() == m.nr(), \n            \"\\tconst matrix_exp scale_rows(m, v)\"\n            << \"\\n\\tv must be a row or column vector and its length must match the number of rows in m\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tv.nr(): \" << v.nr()\n            << \"\\n\\tv.nc(): \" << v.nc() \n            );\n        typedef op_scale_rows<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),v.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_scale_rows_diag  \n    {\n        op_scale_rows_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR;\n        const static long NC = M1::NC;\n\n        const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(r,r); }\n\n        long nr () const { return m1.nr(); }\n        long nc () const { return m1.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) ; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.destructively_aliases(item) || m2.aliases(item); }\n    };\n\n// turn expressions of the form diagonal_matrix*mat into scale_rows(mat, d)\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_scale_rows_diag<EXP1,EXP2> > operator* (\n        const matrix_diag_exp<EXP2>& d, \n        const matrix_exp<EXP1>& m\n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n\n        // figure out the compile time known length of d\n        const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);\n\n        // the length of d must match the number of rows in m\n        COMPILE_TIME_ASSERT(EXP1::NR == v_len || EXP1::NR == 0 || v_len == 0);\n\n        DLIB_ASSERT(d.nc() == m.nr(), \n            \"\\tconst matrix_exp operator*(d, m)\"\n            << \"\\n\\tThe dimensions of the d and m matrices don't match.\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc() \n            );\n        typedef op_scale_rows_diag<EXP1,EXP2> op;\n        return matrix_op<op>(op(m.ref(),d.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    /*\n        The idea here is to catch expressions of the form d*M*d where d is diagonal and M\n        is some square matrix and turn them into something equivalent to \n        pointwise_multiply(diag(d)*trans(diag(d)), M).\n\n        The reason for this is that doing it this way is more numerically stable.  In particular,\n        doing 2 matrix multiplies as suggested by d*M*d could result in an asymmetric matrix even \n        if M is symmetric to begin with. \n    */\n\n    template <typename M1, typename M2, typename M3>\n    struct op_diag_m_diag  \n    {\n        // This operator represents M1*M2*M3 where M1 and M3 are diagonal\n\n        op_diag_m_diag(const M1& m1_, const M2& m2_, const M3& m3_) : m1(m1_), m2(m2_), m3(m3_) {}\n        const M1& m1;\n        const M2& m2;\n        const M3& m3;\n\n        const static long cost = M1::cost + M2::cost + M3::cost + 1;\n        typedef typename M2::type type;\n        typedef const typename M2::type const_ret_type;\n        typedef typename M2::mem_manager_type mem_manager_type;\n        typedef typename M2::layout_type layout_type;\n        const static long NR = M2::NR;\n        const static long NC = M2::NC;\n\n        const_ret_type apply ( long r, long c) const { return (m1(r,r)*m3(c,c))*m2(r,c); }\n\n        long nr () const { return m2.nr(); }\n        long nc () const { return m2.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item) || m3.aliases(item) ; }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m2.destructively_aliases(item) || m1.aliases(item) || m3.aliases(item) ; }\n    };\n\n    // catch d*(M*d) = EXP1*EXP2*EXP3\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    const matrix_op<op_diag_m_diag<EXP1,EXP2,EXP3> > operator* (\n        const matrix_diag_exp<EXP1>& d,\n        const matrix_exp<matrix_op<op_scale_columns_diag<EXP2,EXP3> > >& m\n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n\n        // figure out the compile time known length of d\n        const long v_len = ((EXP1::NR)*(EXP1::NC) == 0)? 0 : (tmax<EXP1::NR,EXP1::NC>::value);\n\n        // the length of d must match the number of rows in m\n        COMPILE_TIME_ASSERT(EXP2::NR == v_len || EXP2::NR == 0 || v_len == 0);\n\n        DLIB_ASSERT(d.nc() == m.nr(), \n            \"\\tconst matrix_exp operator*(d, m)\"\n            << \"\\n\\tmatrix dimensions don't match\"\n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc() \n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            );\n        typedef op_diag_m_diag<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(d.ref(), m.ref().op.m1, m.ref().op.m2));\n    }\n\n    // catch (d*M)*d = EXP1*EXP2*EXP3\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3\n        >\n    const matrix_op<op_diag_m_diag<EXP1,EXP2,EXP3> > operator* (\n        const matrix_exp<matrix_op<op_scale_rows_diag<EXP2,EXP1> > >& m,\n        const matrix_diag_exp<EXP3>& d \n    )\n    {\n        // Both arguments to this function must contain the same type of element\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP3::type,typename EXP2::type>::value == true));\n\n        // figure out the compile time known length of d\n        const long v_len = ((EXP3::NR)*(EXP3::NC) == 0)? 0 : (tmax<EXP3::NR,EXP3::NC>::value);\n\n        // the length of d must match the number of columns in m\n        COMPILE_TIME_ASSERT(EXP2::NC == v_len || EXP2::NC == 0 || v_len == 0);\n\n        DLIB_ASSERT(m.nc() == d.nr(), \n            \"\\tconst matrix_exp operator*(m, d)\"\n            << \"\\n\\tmatrix dimensions don't match\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\td.nr(): \" << d.nr()\n            << \"\\n\\td.nc(): \" << d.nc() \n            );\n        typedef op_diag_m_diag<EXP1,EXP2,EXP3> op;\n        return matrix_op<op>(op(m.ref().op.m2, m.ref().op.m1, d.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    struct sort_columns_sort_helper\n    {\n        template <typename T>\n        bool operator() (\n            const T& item1,\n            const T& item2\n        ) const\n        {\n            return item1.first < item2.first;\n        }\n    };\n\n    template <\n        typename T, long NR, long NC, typename mm, typename l1,\n        long NR2, long NC2, typename mm2, typename l2\n        >\n    void sort_columns (\n        matrix<T,NR,NC,mm,l1>& m,\n        matrix<T,NR2,NC2,mm2,l2>& v\n    )\n    {\n        COMPILE_TIME_ASSERT(NC2 == 1 || NC2 == 0);\n        COMPILE_TIME_ASSERT(NC == NR2 || NC == 0 || NR2 == 0);\n\n        DLIB_ASSERT(is_col_vector(v) == true && v.size() == m.nc(), \n            \"\\tconst matrix_exp sort_columns(m, v)\"\n            << \"\\n\\tv must be a column vector and its length must match the number of columns in m\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tv.nr(): \" << v.nr()\n            << \"\\n\\tv.nc(): \" << v.nc() \n            );\n\n\n\n        // Now we have to sort the given vectors in the m matrix according\n        // to how big their corresponding v(column index) values are.\n        typedef std::pair<T, matrix<T,0,1,mm> > col_pair;\n        typedef std_allocator<col_pair, mm> alloc;\n        std::vector<col_pair,alloc> colvalues;\n        col_pair p;\n        for (long r = 0; r < v.nr(); ++r)\n        {\n            p.first = v(r);\n            p.second = colm(m,r);\n            colvalues.push_back(p);\n        }\n        std::sort(colvalues.begin(), colvalues.end(), sort_columns_sort_helper());\n        \n        for (long i = 0; i < v.nr(); ++i)\n        {\n            v(i) = colvalues[i].first;\n            set_colm(m,i) = colvalues[i].second;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename mm, typename l1,\n        long NR2, long NC2, typename mm2, typename l2\n        >\n    void rsort_columns (\n        matrix<T,NR,NC,mm,l1>& m,\n        matrix<T,NR2,NC2,mm2,l2>& v\n    )\n    {\n        COMPILE_TIME_ASSERT(NC2 == 1 || NC2 == 0);\n        COMPILE_TIME_ASSERT(NC == NR2 || NC == 0 || NR2 == 0);\n\n        DLIB_ASSERT(is_col_vector(v) == true && v.size() == m.nc(), \n            \"\\tconst matrix_exp rsort_columns(m, v)\"\n            << \"\\n\\tv must be a column vector and its length must match the number of columns in m\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tv.nr(): \" << v.nr()\n            << \"\\n\\tv.nc(): \" << v.nc() \n            );\n\n\n\n        // Now we have to sort the given vectors in the m matrix according\n        // to how big their corresponding v(column index) values are.\n        typedef std::pair<T, matrix<T,0,1,mm> > col_pair;\n        typedef std_allocator<col_pair, mm> alloc;\n        std::vector<col_pair,alloc> colvalues;\n        col_pair p;\n        for (long r = 0; r < v.nr(); ++r)\n        {\n            p.first = v(r);\n            p.second = colm(m,r);\n            colvalues.push_back(p);\n        }\n        std::sort(colvalues.rbegin(), colvalues.rend(), sort_columns_sort_helper());\n        \n        for (long i = 0; i < v.nr(); ++i)\n        {\n            v(i) = colvalues[i].first;\n            set_colm(m,i) = colvalues[i].second;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_tensor_product \n    {\n        op_tensor_product(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        const static long NR = M1::NR*M2::NR;\n        const static long NC = M1::NC*M2::NC;\n        typedef typename M1::type type;\n        typedef const typename M1::type const_ret_type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            return m1(r/m2.nr(),c/m2.nc())*m2(r%m2.nr(),c%m2.nc()); \n        }\n\n        long nr () const { return m1.nr()*m2.nr(); }\n        long nc () const { return m1.nc()*m2.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_tensor_product<EXP1,EXP2> > tensor_product (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        typedef op_tensor_product<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_make_symmetric : basic_op_m<M>\n    {\n        op_make_symmetric ( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r >= c)\n                return this->m(r,c);\n            else\n                return this->m(c,r);\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_make_symmetric<EXP> > make_symmetric (\n        const matrix_exp<EXP>& m\n    )\n    {\n        DLIB_ASSERT(m.nr() == m.nc(), \n            \"\\tconst matrix make_symmetric(m)\"\n            << \"\\n\\t m must be a square matrix\"\n            << \"\\n\\t m.nr(): \" << m.nr()\n            << \"\\n\\t m.nc(): \" << m.nc()\n            );\n\n        typedef op_make_symmetric<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_lowerm : basic_op_m<M>\n    {\n        op_lowerm( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+2;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r >= c)\n                return this->m(r,c); \n            else\n                return 0;\n        }\n    };\n\n    template <typename M>\n    struct op_lowerm_s : basic_op_m<M>\n    {\n        typedef typename M::type type;\n        op_lowerm_s( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+2;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r > c)\n                return this->m(r,c); \n            else if (r==c)\n                return s;\n            else\n                return 0;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_lowerm<EXP> > lowerm (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_lowerm<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_lowerm_s<EXP> > lowerm (\n        const matrix_exp<EXP>& m,\n        typename EXP::type s\n        )\n    {\n        typedef op_lowerm_s<EXP> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_upperm : basic_op_m<M>\n    {\n        op_upperm( const M& m_) : basic_op_m<M>(m_){}\n\n        const static long cost = M::cost+2;\n        typedef typename M::type type;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r <= c)\n                return this->m(r,c); \n            else\n                return 0;\n        }\n    };\n\n    template <typename M>\n    struct op_upperm_s : basic_op_m<M>\n    {\n        typedef typename M::type type;\n        op_upperm_s( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\n\n        const type s;\n\n        const static long cost = M::cost+2;\n        typedef const typename M::type const_ret_type;\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r < c)\n                return this->m(r,c); \n            else if (r==c)\n                return s;\n            else\n                return 0;\n        }\n    };\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_upperm<EXP> > upperm (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_upperm<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_upperm_s<EXP> > upperm (\n        const matrix_exp<EXP>& m,\n        typename EXP::type s\n        )\n    {\n        typedef op_upperm_s<EXP> op;\n        return matrix_op<op>(op(m.ref(),s));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename rand_gen>\n    inline const matrix<double> randm( \n        long nr,\n        long nc,\n        rand_gen& rnd\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tconst matrix randm(nr, nc, rnd)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tnr: \" << nr \n            << \"\\n\\tnc: \" << nc \n            );\n\n        matrix<double> m(nr,nc);\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                m(r,c) = rnd.get_random_double();\n            }\n        }\n\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const matrix<double> randm( \n        long nr,\n        long nc\n    )\n    {\n        DLIB_ASSERT(nr >= 0 && nc >= 0, \n            \"\\tconst matrix randm(nr, nc)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tnr: \" << nr \n            << \"\\n\\tnc: \" << nc \n            );\n\n        matrix<double> m(nr,nc);\n        // make a double that contains RAND_MAX + the smallest number that still\n        // makes the resulting double slightly bigger than static_cast<double>(RAND_MAX)\n        double max_val = RAND_MAX;\n        max_val += std::numeric_limits<double>::epsilon()*RAND_MAX;\n\n        for (long r = 0; r < m.nr(); ++r)\n        {\n            for (long c = 0; c < m.nc(); ++c)\n            {\n                m(r,c) = std::rand()/max_val;\n            }\n        }\n\n        return m;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline const matrix_range_exp<double> linspace (\n        double start,\n        double end,\n        long num\n    ) \n    { \n        DLIB_ASSERT(num >= 0, \n            \"\\tconst matrix_exp linspace(start, end, num)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tstart: \" << start \n            << \"\\n\\tend:   \" << end\n            << \"\\n\\tnum:   \" << num \n            );\n\n        return matrix_range_exp<double>(start,end,num,false); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_linpiece  \n    {\n        op_linpiece(const double val_, const M& joints_) : joints(joints_), val(val_){}\n\n        const M& joints;\n        const double val;\n\n        const static long cost = 10; \n\n        const static long NR = (M::NR*M::NC==0) ? (0) : (M::NR*M::NC-1); \n        const static long NC = 1; \n        typedef typename M::type type;\n        typedef default_memory_manager mem_manager_type;\n        typedef row_major_layout layout_type;\n\n        typedef type const_ret_type;\n        const_ret_type apply (long i, long ) const \n        { \n            if (joints(i) < val)\n                return std::min<type>(val,joints(i+1)) - joints(i);\n            else\n                return 0;\n        }\n\n        long nr () const { return joints.size()-1; }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return joints.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return joints.aliases(item); }\n    }; \n\n    template < typename EXP >\n    const matrix_op<op_linpiece<EXP> > linpiece (\n        const double val,\n        const matrix_exp<EXP>& joints\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_vector(joints) && joints.size() >= 2, \n            \"\\t matrix_exp linpiece()\"\n            << \"\\n\\t Invalid inputs were given to this function \"\n            << \"\\n\\t is_vector(joints): \" << is_vector(joints) \n            << \"\\n\\t joints.size():     \" << joints.size() \n            );\n#ifdef ENABLE_ASSERTS\n        for (long i = 1; i < joints.size(); ++i)\n        {\n            DLIB_ASSERT(joints(i-1) < joints(i), \n                \"\\t matrix_exp linpiece()\"\n                << \"\\n\\t Invalid inputs were given to this function \"\n                << \"\\n\\t joints(\"<<i-1<<\"): \" << joints(i-1) \n                << \"\\n\\t joints(\"<<i<<\"): \" << joints(i) \n            );\n        }\n#endif\n        \n        typedef op_linpiece<EXP> op;\n        return matrix_op<op>(op(val,joints.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n    inline const matrix_log_range_exp<double> logspace (\n        double start,\n        double end,\n        long num\n    ) \n    { \n        DLIB_ASSERT(num >= 0, \n            \"\\tconst matrix_exp logspace(start, end, num)\"\n            << \"\\n\\tInvalid inputs to this function\"\n            << \"\\n\\tstart: \" << start \n            << \"\\n\\tend:   \" << end\n            << \"\\n\\tnum:   \" << num \n            );\n\n        return matrix_log_range_exp<double>(start,end,num); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_cart_prod  \n    {\n        op_cart_prod(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_) {}\n        const M1& m1;\n        const M2& m2;\n\n        const static long cost = M1::cost+M2::cost+1;\n        typedef typename M1::type type;\n        typedef const typename M1::const_ret_type const_ret_type;\n\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n        const static long NR = M1::NR+M2::NR;\n        const static long NC = M1::NC*M2::NC;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r < m1.nr())\n                return m1(r, c/m2.nc());\n            else\n                return m2(r-m1.nr(), c%m2.nc());\n        }\n\n        long nr () const { return m1.nr() + m2.nr(); }\n        long nc () const { return m1.nc() * m2.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    const matrix_op<op_cart_prod<EXP1,EXP2> > cartesian_product (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n\n        typedef op_cart_prod<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_mat_to_vect \n    {\n        op_mat_to_vect(const M& m_) : m(m_) {}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = M::NC*M::NR;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply ( long r, long ) const { return m(r/m.nc(), r%m.nc()); }\n\n        long nr () const { return m.size(); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    }; \n\n    template <\n        typename EXP\n        >\n    const matrix_op<op_mat_to_vect<EXP> > reshape_to_column_vector (\n        const matrix_exp<EXP>& m\n    )\n    {\n        typedef op_mat_to_vect<EXP> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR_,\n        long NC_,\n        typename MM\n        >\n    struct op_mat_to_vect2\n    {\n        typedef matrix<T,NR_,NC_,MM,row_major_layout> M;\n        op_mat_to_vect2(const M& m_) : m(m_) {}\n        const M& m;\n\n        const static long cost = M::cost+2;\n        const static long NR = M::NC*M::NR;\n        const static long NC = 1;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply ( long r, long ) const { return (&m(0,0))[r]; }\n\n        long nr () const { return m.size(); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    }; \n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM\n        >\n    const matrix_op<op_mat_to_vect2<T,NR,NC,MM> > reshape_to_column_vector (\n        const matrix<T,NR,NC,MM,row_major_layout>& m\n    )\n    {\n        typedef op_mat_to_vect2<T,NR,NC,MM> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_join_rows \n    {\n        op_join_rows(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),_nr(std::max(m1.nr(),m2.nr())) {}\n        const M1& m1;\n        const M2& m2;\n        const long _nr;\n\n        template <typename T, typename U, bool selection>\n        struct type_selector;\n        template <typename T, typename U>\n        struct type_selector<T,U,true> { typedef T type; };\n        template <typename T, typename U>\n        struct type_selector<T,U,false> { typedef U type; };\n\n        // If both const_ret_types are references then we should use them as the const_ret_type type\n        // but otherwise we should use the normal type.  \n        typedef typename M1::const_ret_type T1;\n        typedef typename M1::type T2;\n        typedef typename M2::const_ret_type T3;\n        typedef typename type_selector<T1, T2, is_reference_type<T1>::value && is_reference_type<T3>::value>::type const_ret_type;\n\n        const static long cost = M1::cost + M2::cost + 1;\n        const static long NR = tmax<M1::NR, M2::NR>::value;\n        const static long NC = (M1::NC*M2::NC != 0)? (M1::NC+M2::NC) : (0);\n        typedef typename M1::type type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const\n        { \n            if (c < m1.nc())\n                return m1(r,c);\n            else\n                return m2(r,c-m1.nc());\n        }\n\n        long nr () const { return _nr; }\n        long nc () const { return m1.nc()+m2.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_join_rows<EXP1,EXP2> > join_rows (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        // You are getting an error on this line because you are trying to join two matrices that\n        // don't have the same number of rows\n        COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || (EXP1::NR*EXP2::NR == 0));\n\n        DLIB_ASSERT(a.nr() == b.nr() || a.size() == 0 || b.size() == 0,\n            \"\\tconst matrix_exp join_rows(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\tYou can only use join_rows() if both matrices have the same number of rows\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nc(): \" << b.nc()\n            );\n\n        typedef op_join_rows<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M1, typename M2>\n    struct op_join_cols \n    {\n        op_join_cols(const M1& m1_, const M2& m2_) : m1(m1_),m2(m2_),_nc(std::max(m1.nc(),m2.nc())) {}\n        const M1& m1;\n        const M2& m2;\n        const long _nc;\n\n        template <typename T, typename U, bool selection>\n        struct type_selector;\n        template <typename T, typename U>\n        struct type_selector<T,U,true> { typedef T type; };\n        template <typename T, typename U>\n        struct type_selector<T,U,false> { typedef U type; };\n\n        // If both const_ret_types are references then we should use them as the const_ret_type type\n        // but otherwise we should use the normal type.  \n        typedef typename M1::const_ret_type T1;\n        typedef typename M1::type T2;\n        typedef typename M2::const_ret_type T3;\n        typedef typename type_selector<T1, T2, is_reference_type<T1>::value && is_reference_type<T3>::value>::type const_ret_type;\n\n\n\n        const static long cost = M1::cost + M2::cost + 1;\n        const static long NC = tmax<M1::NC, M2::NC>::value;\n        const static long NR = (M1::NR*M2::NR != 0)? (M1::NR+M2::NR) : (0);\n        typedef typename M1::type type;\n        typedef typename M1::mem_manager_type mem_manager_type;\n        typedef typename M1::layout_type layout_type;\n\n        const_ret_type apply ( long r, long c) const\n        { \n            if (r < m1.nr())\n                return m1(r,c);\n            else\n                return m2(r-m1.nr(),c);\n        }\n\n        long nr () const { return m1.nr()+m2.nr(); }\n        long nc () const { return _nc; }\n\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const \n        { return m1.aliases(item) || m2.aliases(item); }\n    };\n\n    template <\n        typename EXP1,\n        typename EXP2\n        >\n    inline const matrix_op<op_join_cols<EXP1,EXP2> > join_cols (\n        const matrix_exp<EXP1>& a,\n        const matrix_exp<EXP2>& b \n    )\n    {\n        COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\n        // You are getting an error on this line because you are trying to join two matrices that\n        // don't have the same number of columns \n        COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || (EXP1::NC*EXP2::NC == 0));\n\n        DLIB_ASSERT(a.nc() == b.nc() || a.size() == 0 || b.size() == 0,\n            \"\\tconst matrix_exp join_cols(const matrix_exp& a, const matrix_exp& b)\"\n            << \"\\n\\tYou can only use join_cols() if both matrices have the same number of columns\"\n            << \"\\n\\ta.nr(): \" << a.nr()\n            << \"\\n\\tb.nr(): \" << b.nr()\n            << \"\\n\\ta.nc(): \" << a.nc()\n            << \"\\n\\tb.nc(): \" << b.nc()\n            );\n\n        typedef op_join_cols<EXP1,EXP2> op;\n        return matrix_op<op>(op(a.ref(),b.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_fliplr \n    {\n        op_fliplr( const M& m_) : m(m_){}\n\n        const M& m;\n\n        const static long cost = M::cost;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const { return m(r,m.nc()-c-1); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n\n    }; \n\n    template <\n        typename M\n        >\n    const matrix_op<op_fliplr<M> > fliplr (\n        const matrix_exp<M>& m\n    )\n    {\n        typedef op_fliplr<M> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_flipud \n    {\n        op_flipud( const M& m_) : m(m_){}\n\n        const M& m;\n\n        const static long cost = M::cost;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const { return m(m.nr()-r-1,c); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n\n    }; \n\n    template <\n        typename M\n        >\n    const matrix_op<op_flipud<M> > flipud (\n        const matrix_exp<M>& m\n    )\n    {\n        typedef op_flipud<M> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M>\n    struct op_flip \n    {\n        op_flip( const M& m_) : m(m_){}\n\n        const M& m;\n\n        const static long cost = M::cost;\n        const static long NR = M::NR;\n        const static long NC = M::NC;\n        typedef typename M::type type;\n        typedef typename M::const_ret_type const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n\n        const_ret_type apply (long r, long c) const { return m(m.nr()-r-1, m.nc()-c-1); }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n\n    }; \n\n    template <\n        typename M\n        >\n    const matrix_op<op_flip<M> > flip (\n        const matrix_exp<M>& m\n    )\n    {\n        typedef op_flip<M> op;\n        return matrix_op<op>(op(m.ref()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, long NR, long NC, typename MM, typename L>\n    uint32 hash (\n        const matrix<T,NR,NC,MM,L>& item,\n        uint32 seed = 0\n    )\n    {\n        DLIB_ASSERT_HAS_STANDARD_LAYOUT(T);\n\n        if (item.size() == 0)\n            return 0;\n        else\n            return murmur_hash3(&item(0,0), sizeof(T)*item.size(), seed);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_UTILITIES_\n\n"
  },
  {
    "path": "dlib/matrix/matrix_utilities_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MATRIx_UTILITIES_ABSTRACT_\n#ifdef DLIB_MATRIx_UTILITIES_ABSTRACT_\n\n#include \"matrix_abstract.h\"\n#include <complex>\n#include \"../pixel.h\"\n#include \"../geometry/rectangle.h\"\n#inclue <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                   Simple matrix utilities \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    constexpr bool is_row_major (\n        const matrix_exp<EXP>&\n    );\n    /*!\n        ensures\n            - returns true if and only if the given matrix expression uses the row_major_layout.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp diag (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a column vector R that contains the elements from the diagonal \n              of m in the order R(0)==m(0,0), R(1)==m(1,1), R(2)==m(2,2) and so on.\n    !*/\n\n    template <typename EXP>\n    struct diag_exp\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This struct allows you to determine the type of matrix expression \n                object returned from the diag() function.  An example makes its\n                use clear:\n\n                template <typename EXP>\n                void do_something( const matrix_exp<EXP>& mat)\n                {\n                    // d is a matrix expression that aliases mat.\n                    typename diag_exp<EXP>::type d = diag(mat);\n\n                    // Print the diagonal of mat.  So we see that by using\n                    // diag_exp we can save the object returned by diag() in\n                    // a local variable.    \n                    cout << d << endl;\n\n                    // Note that you can only save the return value of diag() to\n                    // a local variable if the argument to diag() has a lifetime\n                    // beyond the diag() expression.  The example shown above is\n                    // OK but the following would result in undefined behavior:\n                    typename diag_exp<EXP>::type bad = diag(mat + mat);\n                }\n        !*/\n        typedef type_of_expression_returned_by_diag type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp diagm (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_vector(m) == true\n              (i.e. m is a row or column matrix)\n        ensures\n            - returns a square matrix M such that:\n                - diag(M) == m\n                - non diagonal elements of M are 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp trans (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the transpose of the matrix m\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_type::type dot (\n        const matrix_exp& m1,\n        const matrix_exp& m2\n    );\n    /*!\n        requires\n            - is_vector(m1) == true\n            - is_vector(m2) == true\n            - m1.size() == m2.size()\n            - m1.size() > 0\n        ensures\n            - returns the dot product between m1 and m2. That is, this function \n              computes and returns the sum, for all i, of m1(i)*m2(i).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp lowerm (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - M is the lower triangular part of m.  That is:\n                    - if (r >= c) then\n                        - M(r,c) == m(r,c)\n                    - else\n                        - M(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp lowerm (\n        const matrix_exp& m,\n        const matrix_exp::type scalar_value\n    );\n    /*!\n        ensures\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - M is the lower triangular part of m except that the diagonal has\n                  been set to scalar_value.  That is:\n                    - if (r > c) then\n                        - M(r,c) == m(r,c)\n                    - else if (r == c) then\n                        - M(r,c) == scalar_value \n                    - else\n                        - M(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp upperm (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - M is the upper triangular part of m.  That is:\n                    - if (r <= c) then\n                        - M(r,c) == m(r,c)\n                    - else\n                        - M(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp upperm (\n        const matrix_exp& m,\n        const matrix_exp::type scalar_value\n    );\n    /*!\n        ensures\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - M is the upper triangular part of m except that the diagonal has\n                  been set to scalar_value.  That is:\n                    - if (r < c) then\n                        - M(r,c) == m(r,c)\n                    - else if (r == c) then\n                        - M(r,c) == scalar_value \n                    - else\n                        - M(r,c) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp make_symmetric (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.nr() == m.nc()\n              (i.e. m must be a square matrix)\n        ensures\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - M is a symmetric matrix, that is, M == trans(M) and\n                  it is constructed from the lower triangular part of m.  Specifically,\n                  we have:\n                    - lowerm(M) == lowerm(m)\n                    - upperm(M) == trans(lowerm(m))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long NR, \n        long NC, \n        T val\n        >\n    const matrix_exp uniform_matrix (\n    );\n    /*!\n        requires\n            - NR > 0 && NC > 0\n        ensures\n            - returns an NR by NC matrix with elements of type T and all set to val.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR, \n        long NC\n        >\n    const matrix_exp uniform_matrix (\n        const T& val\n    );\n    /*!\n        requires\n            - NR > 0 && NC > 0\n        ensures\n            - returns an NR by NC matrix with elements of type T and all set to val.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp uniform_matrix (\n        long nr,\n        long nc,\n        const T& val\n    );\n    /*!\n        requires\n            - nr >= 0 && nc >= 0\n        ensures\n            - returns an nr by nc matrix with elements of type T and all set to val.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp ones_matrix (\n        const matrix_exp& mat\n    );\n    /*!\n        requires\n            - mat.nr() >= 0 && mat.nc() >= 0\n        ensures\n            - Let T denote the type of element in mat. Then this function\n              returns uniform_matrix<T>(mat.nr(), mat.nc(), 1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp ones_matrix (\n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - nr >= 0 && nc >= 0\n        ensures\n            - returns uniform_matrix<T>(nr, nc, 1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp zeros_matrix (\n        const matrix_exp& mat\n    );\n    /*!\n        requires\n            - mat.nr() >= 0 && mat.nc() >= 0\n        ensures\n            - Let T denote the type of element in mat. Then this function\n              returns uniform_matrix<T>(mat.nr(), mat.nc(), 0)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp zeros_matrix (\n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - nr >= 0 && nc >= 0\n        ensures\n            - returns uniform_matrix<T>(nr, nc, 0)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp identity_matrix (\n        const matrix_exp& mat\n    );\n    /*!\n        requires\n            - mat.nr() == mat.nc()\n        ensures\n            - returns an identity matrix with the same dimensions as mat and\n              containing the same type of elements as mat.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp identity_matrix (\n        long N\n    );\n    /*!\n        requires\n            - N > 0\n        ensures\n            - returns an N by N identity matrix with elements of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long N\n        >\n    const matrix_exp identity_matrix (\n    );\n    /*!\n        requires\n            - N > 0\n        ensures\n            - returns an N by N identity matrix with elements of type T.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp linspace (\n        double start,\n        double end,\n        long num\n    );\n    /*!\n        requires\n            - num >= 0\n        ensures\n            - returns a matrix M such that:\n                - M::type == double \n                - is_row_vector(M) == true\n                - M.size() == num\n                - M == a row vector with num linearly spaced values beginning with start\n                  and stopping with end.  \n                - M(num-1) == end \n                - if (num > 1) then\n                    - M(0) == start\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp logspace (\n        double start,\n        double end,\n        long num\n    );\n    /*!\n        requires\n            - num >= 0\n        ensures\n            - returns a matrix M such that:\n                - M::type == double \n                - is_row_vector(M) == true\n                - M.size() == num\n                - M == a row vector with num logarithmically spaced values beginning with \n                  10^start and stopping with 10^end.  \n                  (i.e. M == pow(10, linspace(start, end, num)))\n                - M(num-1) == 10^end\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp linpiece (\n        const double val,\n        const matrix_exp& joints\n    );\n    /*!\n        requires\n            - is_vector(joints) == true\n            - joints.size() >= 2\n            - for all valid i < j:\n                - joints(i) < joints(j)\n        ensures\n            - linpiece() is useful for creating piecewise linear functions of val.  For\n              example, if w is a parameter vector then you can represent a piecewise linear\n              function of val as: f(val) = dot(w, linpiece(val, linspace(0,100,5))).  In\n              this case, f(val) is piecewise linear on the intervals [0,25], [25,50],\n              [50,75], [75,100].  Moreover, w(i) defines the derivative of f(val) in the\n              i-th interval.  Finally, outside the interval [0,100] f(val) has a derivative\n              of zero and f(0) == 0.\n            - To be precise, this function returns a column vector L such that:\n                - L.size() == joints.size()-1\n                - is_col_vector(L) == true\n                - L contains the same type of elements as joints.\n                - for all valid i:\n                - if (joints(i) < val)\n                    - L(i) == min(val,joints(i+1)) - joints(i)\n                - else\n                    - L(i) == 0\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long R,\n        long C\n        >\n    const matrix_exp rotate (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                  R( (r+R)%m.nr() , (c+C)%m.nc() ) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp fliplr (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - flips the matrix m from left to right and returns the result.  \n              I.e. reverses the order of the columns.\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - for all valid r and c:\n                  M(r,c) == m(r, m.nc()-c-1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp flipud (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - flips the matrix m from up to down and returns the result.  \n              I.e. reverses the order of the rows.\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - for all valid r and c:\n                  M(r,c) == m(m.nr()-r-1, c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp flip (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - flips the matrix m from up to down and left to right and returns the \n              result.  I.e. returns flipud(fliplr(m)).\n            - returns a matrix M such that:\n                - M::type == the same type that was in m\n                - M has the same dimensions as m\n                - for all valid r and c:\n                  M(r,c) == m(m.nr()-r-1, m.nc()-c-1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp reshape (\n        const matrix_exp& m,\n        long rows,\n        long cols\n    );\n    /*!\n        requires\n            - m.size() == rows*cols\n            - rows > 0\n            - cols > 0\n        ensures\n            - returns a matrix M such that: \n                - M.nr() == rows\n                - M.nc() == cols\n                - M.size() == m.size()\n                - for all valid r and c:\n                    - let IDX = r*cols + c\n                    - M(r,c) == m(IDX/m.nc(), IDX%m.nc())\n\n            - i.e. The matrix m is reshaped into a new matrix of rows by cols\n              dimension.  Additionally, the elements of m are laid into M in row major \n              order.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp reshape_to_column_vector (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix M such that: \n                - is_col_vector(M) == true\n                - M.size() == m.size()\n                - for all valid r and c:\n                    - m(r,c) == M(r*m.nc() + c)\n\n            - i.e. The matrix m is reshaped into a column vector.  Note that\n              the elements are pulled out in row major order.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long R,\n        long C\n        >\n    const matrix_exp removerc (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.nr() > R >= 0\n            - m.nc() > C >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() - 1\n                - M.nc() == m.nc() - 1\n                - M == m with its R row and C column removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp removerc (\n        const matrix_exp& m,\n        long R,\n        long C\n    );\n    /*!\n        requires\n            - m.nr() > R >= 0\n            - m.nc() > C >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() - 1\n                - M.nc() == m.nc() - 1\n                - M == m with its R row and C column removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long R\n        >\n    const matrix_exp remove_row (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.nr() > R >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() - 1\n                - M.nc() == m.nc() \n                - M == m with its R row removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp remove_row (\n        const matrix_exp& m,\n        long R\n    );\n    /*!\n        requires\n            - m.nr() > R >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() - 1\n                - M.nc() == m.nc() \n                - M == m with its R row removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long C\n        >\n    const matrix_exp remove_col (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.nc() > C >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() \n                - M.nc() == m.nc() - 1 \n                - M == m with its C column removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp remove_col (\n        const matrix_exp& m,\n        long C\n    );\n    /*!\n        requires\n            - m.nc() > C >= 0\n        ensures\n            - returns a matrix M such that:\n                - M.nr() == m.nr() \n                - M.nc() == m.nc() - 1 \n                - M == m with its C column removed\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n       typename target_type\n       >\n    const matrix_exp matrix_cast (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R where for all valid r and c:\n              R(r,c) == static_cast<target_type>(m(r,c))\n              also, R has the same dimensions as m.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        long NR,\n        long NC,\n        typename MM,\n        typename U,\n        typename L\n        >\n    void set_all_elements (\n        matrix<T,NR,NC,MM,L>& m,\n        U value\n    );\n    /*!\n        ensures\n            - for all valid r and c:\n              m(r,c) == value\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::matrix_type tmp (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a temporary matrix object that is a copy of m. \n              (This allows you to easily force a matrix_exp to fully evaluate)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        long NR, \n        long NC, \n        typename MM, \n        typename L\n        >\n    uint32 hash (\n        const matrix<T,NR,NC,MM,L>& item,\n        uint32 seed = 0\n    );\n    /*!\n        requires\n            - T is a standard layout type (e.g. a POD type like int, float, \n              or a simple struct).\n        ensures\n            - returns a 32bit hash of the data stored in item.  \n            - Each value of seed results in a different hash function being used.  \n              (e.g. hash(item,0) should generally not be equal to hash(item,1))\n            - uses the murmur_hash3() routine to compute the actual hash.\n            - Note that if the memory layout of the elements in item change between\n              hardware platforms then hash() will give different outputs.  If you want\n              hash() to always give the same output for the same input then you must \n              ensure that elements of item always have the same layout in memory.\n              Typically this means using fixed width types and performing byte swapping\n              to account for endianness before passing item to hash().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    // if matrix_exp contains non-complex types (e.g. float, double)\n    bool equal (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp::type epsilon = 100*std::numeric_limits<matrix_exp::type>::epsilon()\n    );\n    /*!\n        ensures\n            - if (a and b don't have the same dimensions) then\n                - returns false\n            - else if (there exists an r and c such that abs(a(r,c)-b(r,c)) > epsilon) then\n                - returns false\n            - else\n                - returns true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    // if matrix_exp contains std::complex types \n    bool equal (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp::type::value_type epsilon = 100*std::numeric_limits<matrix_exp::type::value_type>::epsilon()\n    );\n    /*!\n        ensures\n            - if (a and b don't have the same dimensions) then\n                - returns false\n            - else if (there exists an r and c such that abs(real(a(r,c)-b(r,c))) > epsilon \n              or abs(imag(a(r,c)-b(r,c))) > epsilon) then\n                - returns false\n            - else\n                - returns true\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp pointwise_multiply (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a.nr() == b.nr()\n            - a.nc() == b.nc()\n            - a and b both contain the same type of element (one or both\n              can also be of type std::complex so long as the underlying type\n              in them is the same)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R has the same dimensions as a and b. \n                - for all valid r and c:\n                  R(r,c) == a(r,c) * b(r,c)\n    !*/\n\n    const matrix_exp pointwise_multiply (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c \n    );\n    /*!\n        performs pointwise_multiply(a,pointwise_multiply(b,c));\n    !*/\n\n    const matrix_exp pointwise_multiply (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c,\n        const matrix_exp& d \n    );\n    /*!\n        performs pointwise_multiply(pointwise_multiply(a,b),pointwise_multiply(c,d));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp pointwise_divide(\n        const matrix_exp& a,\n        const matrix_exp& b\n    );\n    /*!\n        requires\n            - a.nr() == b.nr()\n            - a.nc() == b.nc()\n            - a and b both contain the same type of element (one or both\n              can also be of type std::complex so long as the underlying type\n              in them is the same)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R has the same dimensions as a and b.\n                - for all valid r and c:\n                  R(r,c) == a(r,c) / b(r,c)\n    !*/\n\n    const matrix_exp pointwise_divide(\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c\n    );\n    /*!\n        performs pointwise_divide(pointwise_divide(a,b),c);\n    !*/\n\n    const matrix_exp pointwise_divide(\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c,\n        const matrix_exp& d\n    );\n    /*!\n        performs pointwise_divide(pointwise_divide(pointwise_divide(pointwise_divide(a,b),c),d));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp pointwise_pow (\n        const matrix_exp& a,\n        const matrix_exp& b\n    );\n    /*!\n        requires\n            - a.nr() == b.nr()\n            - a.nc() == b.nc()\n            - a and b both contain the same type of element (one or both\n              can also be of type std::complex so long as the underlying type\n              in them is the same)\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R has the same dimensions as a and b.\n                - for all valid r and c:\n                  R(r,c) == std::pow(a(r,c), b(r,c))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp join_rows (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a.nr() == b.nr() || a.size() == 0 || b.size() == 0\n            - a and b both contain the same type of element\n        ensures\n            - This function joins two matrices together by concatenating their rows.\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R.nr() == a.nr() == b.nr()\n                - R.nc() == a.nc() + b.nc()\n                - for all valid r and c:\n                    - if (c < a.nc()) then\n                        - R(r,c) == a(r,c) \n                    - else\n                        - R(r,c) == b(r, c-a.nc()) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp join_cols (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a.nc() == b.nc() || a.size() == 0 || b.size() == 0\n            - a and b both contain the same type of element\n        ensures\n            - This function joins two matrices together by concatenating their columns.\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R.nr() == a.nr() + b.nr()\n                - R.nc() == a.nc() == b.nc()\n                - for all valid r and c:\n                    - if (r < a.nr()) then\n                        - R(r,c) == a(r,c) \n                    - else\n                        - R(r,c) == b(r-a.nr(), c) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp tensor_product (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a and b both contain the same type of element\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R.nr() == a.nr() * b.nr()  \n                - R.nc() == a.nc() * b.nc()  \n                - for all valid r and c:\n                  R(r,c) == a(r/b.nr(), c/b.nc()) * b(r%b.nr(), c%b.nc())\n                - I.e. R is the tensor product of matrix a with matrix b\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp cartesian_product (\n        const matrix_exp& A,\n        const matrix_exp& B \n    );\n    /*!\n        requires\n            - A and B both contain the same type of element\n        ensures\n            - Think of A and B as sets of column vectors.  Then this function \n              returns a matrix that contains a set of column vectors that is\n              the Cartesian product of the sets A and B.  That is, the resulting\n              matrix contains every possible combination of vectors from both A and\n              B.\n            - returns a matrix R such that:\n                - R::type == the same type that was in A and B.\n                - R.nr() == A.nr() + B.nr()  \n                - R.nc() == A.nc() * B.nc()  \n                - Each column of R is the concatenation of a column vector\n                  from A with a column vector from B.  \n                - for all valid r and c:\n                    - if (r < A.nr()) then\n                        - R(r,c) == A(r, c/B.nc())\n                    - else\n                        - R(r,c) == B(r-A.nr(), c%B.nc())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp scale_columns (\n        const matrix_exp& m,\n        const matrix_exp& v\n    );\n    /*!\n        requires\n            - is_vector(v) == true\n            - v.size() == m.nc()\n            - m and v both contain the same type of element\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m and v.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                  R(r,c) == m(r,c) * v(c)\n                - i.e. R is the result of multiplying each of m's columns by\n                  the corresponding scalar in v.\n\n            - Note that this function is identical to the expression m*diagm(v).  \n              That is, the * operator is overloaded for this case and will invoke\n              scale_columns() automatically as appropriate.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp scale_rows (\n        const matrix_exp& m,\n        const matrix_exp& v\n    );\n    /*!\n        requires\n            - is_vector(v) == true\n            - v.size() == m.nr()\n            - m and v both contain the same type of element\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m and v.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                  R(r,c) == m(r,c) * v(r)\n                - i.e. R is the result of multiplying each of m's rows by\n                  the corresponding scalar in v.\n\n            - Note that this function is identical to the expression diagm(v)*m.  \n              That is, the * operator is overloaded for this case and will invoke\n              scale_rows() automatically as appropriate.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void sort_columns (\n        matrix<T>& m,\n        matrix<T>& v\n    );\n    /*!\n        requires\n            - is_col_vector(v) == true\n            - v.size() == m.nc()\n            - m and v both contain the same type of element\n        ensures\n            - the dimensions for m and v are not changed\n            - sorts the columns of m according to the values in v.\n              i.e. \n                - #v == the contents of v but in sorted order according to\n                  operator<.  So smaller elements come first.\n                - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)\n                - colm(#m,new(i)) == colm(m,i) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void rsort_columns (\n        matrix<T>& m,\n        matrix<T>& v\n    );\n    /*!\n        requires\n            - is_col_vector(v) == true\n            - v.size() == m.nc()\n            - m and v both contain the same type of element\n        ensures\n            - the dimensions for m and v are not changed\n            - sorts the columns of m according to the values in v.\n              i.e. \n                - #v == the contents of v but in sorted order according to\n                  operator>.  So larger elements come first.\n                - Let #v(new(i)) == v(i) (i.e. new(i) is the index element i moved to)\n                - colm(#m,new(i)) == colm(m,i) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type length_squared (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_vector(m) == true\n        ensures\n            - returns sum(squared(m))\n              (i.e. returns the square of the length of the vector m)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type length (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_vector(m) == true\n        ensures\n            - returns sqrt(sum(squared(m)))\n              (i.e. returns the length of the vector m)\n            - if (m contains integer valued elements) then  \n                - The return type is a double that represents the length.  Therefore, the\n                  return value of length() is always represented using a floating point\n                  type. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool is_row_vector (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - if (m.nr() == 1) then\n                - return true\n            - else\n                - returns false\n    !*/\n\n    bool is_col_vector (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - if (m.nc() == 1) then\n                - return true\n            - else\n                - returns false\n    !*/\n\n    bool is_vector (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - if (is_row_vector(m) || is_col_vector(m)) then\n                - return true\n            - else\n                - returns false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    bool is_finite (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns true if all the values in m are finite values and also not any kind\n              of NaN value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                      Thresholding relational operators \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator< (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) < s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator< (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s < m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator<= (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) <= s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator<= (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s <= m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator> (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) > s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator> (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s > m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator>= (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) >= s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator>= (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s >= m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator== (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) == s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator== (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s == m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator!= (\n        const matrix_exp& m,\n        const S& s\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (m(r,c) != s) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename S>\n    const matrix_exp operator!= (\n        const S& s,\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_built_in_scalar_type<S>::value == true \n            - is_built_in_scalar_type<matrix_exp::type>::value == true\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m.\n                - R has the same dimensions as m. \n                - for all valid r and c:\n                    - if (s != m(r,c)) then\n                        - R(r,c) == 1\n                    - else\n                        - R(r,c) == 0\n                - i.e. R is a binary matrix of all 1s or 0s.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                              Statistics\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type min (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns the value of the smallest element of m.  If m contains complex\n              elements then the element returned is the one with the smallest norm\n              according to std::norm().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp min_pointwise (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a.nr() == b.nr()\n            - a.nc() == b.nc()\n            - a and b both contain the same type of element \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R has the same dimensions as a and b. \n                - for all valid r and c:\n                  R(r,c) == std::min(a(r,c), b(r,c))\n    !*/\n\n    const matrix_exp min_pointwise (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c \n    );\n    /*!\n        performs min_pointwise(a,min_pointwise(b,c));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type max (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns the value of the biggest element of m.  If m contains complex\n              elements then the element returned is the one with the largest norm\n              according to std::norm().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp max_pointwise (\n        const matrix_exp& a,\n        const matrix_exp& b \n    );\n    /*!\n        requires\n            - a.nr() == b.nr()\n            - a.nc() == b.nc()\n            - a and b both contain the same type of element \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in a and b.\n                - R has the same dimensions as a and b. \n                - for all valid r and c:\n                  R(r,c) == std::max(a(r,c), b(r,c))\n    !*/\n\n    const matrix_exp max_pointwise (\n        const matrix_exp& a,\n        const matrix_exp& b,\n        const matrix_exp& c \n    );\n    /*!\n        performs max_pointwise(a,max_pointwise(b,c));\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void find_min_and_max (\n        const matrix_exp& m,\n        matrix_exp::type& min_val,\n        matrix_exp::type& max_val\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - #min_val == min(m)\n            - #max_val == max(m)\n            - This function computes both the min and max in just one pass\n              over the elements of the matrix m.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    long index_of_max (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_vector(m) == true\n            - m.size() > 0 \n        ensures\n            - returns the index of the largest element in m.  \n              (i.e. m(index_of_max(m)) == max(m))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    long index_of_min (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - is_vector(m) == true\n            - m.size() > 0 \n        ensures\n            - returns the index of the smallest element in m.  \n              (i.e. m(index_of_min(m)) == min(m))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point max_point (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns the location of the maximum element of the array, that is, if the\n              returned point is P then it will be the case that: m(P.y(),P.x()) == max(m).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    dlib::vector<double,2> max_point_interpolated (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - Like max_point(), this function finds the location in m with the largest\n              value.  However, we additionally use some quadratic interpolation to find the\n              location of the maximum point with sub-pixel accuracy.  Therefore, the\n              returned point is equal to max_point(m) + some small sub-pixel delta.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    point min_point (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns the location of the minimum element of the array, that is, if the\n              returned point is P then it will be the case that: m(P.y(),P.x()) == min(m).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type sum (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the sum of all elements in m\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sum_rows (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns a row matrix that contains the sum of all the rows vectors in m. \n            - returns a matrix M such that\n                - M::type == the same type that was in m\n                - M.nr() == 1\n                - M.nc() == m.nc()\n                - for all valid i:\n                    - M(i) == sum(colm(m,i)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp sum_cols (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - m.size() > 0\n        ensures\n            - returns a column matrix that contains the sum of all the columns vectors in m. \n            - returns a matrix M such that\n                - M::type == the same type that was in m\n                - M.nr() == m.nr() \n                - M.nc() == 1\n                - for all valid i:\n                    - M(i) == sum(rowm(m,i)) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type prod (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the results of multiplying all elements of m together. \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type mean (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the mean of all elements in m. \n              (i.e. returns sum(m)/(m.nr()*m.nc()))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type variance (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns the unbiased sample variance of all elements in m \n              (i.e. 1.0/(m.nr()*m.nc() - 1)*(sum of all pow(m(i,j) - mean(m),2)))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp::type stddev (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns sqrt(variance(m))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix covariance (\n        const matrix_exp& m\n    );\n    /*!\n        requires\n            - matrix_exp::type == a dlib::matrix object\n            - is_col_vector(m) == true\n            - m.size() > 1\n            - for all valid i, j:\n                - is_col_vector(m(i)) == true \n                - m(i).size() > 0\n                - m(i).size() == m(j).size() \n                - i.e. m contains only column vectors and all the column vectors\n                  have the same non-zero length\n        ensures\n            - returns the unbiased sample covariance matrix for the set of samples\n              in m.  \n              (i.e. 1.0/(m.nr()-1)*(sum of all (m(i) - mean(m))*trans(m(i) - mean(m))))\n            - the returned matrix will contain elements of type matrix_exp::type::type.\n            - the returned matrix will have m(0).nr() rows and columns.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename rand_gen>\n    const matrix<double> randm( \n        long nr,\n        long nc,\n        rand_gen& rnd\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n            - rand_gen == an object that implements the rand/rand_float_abstract.h interface\n        ensures\n            - generates a random matrix using the given rnd random number generator\n            - returns a matrix M such that\n                - M::type == double\n                - M.nr() == nr\n                - M.nc() == nc\n                - for all valid i, j:\n                    - M(i,j) == a random number such that 0 <= M(i,j) < 1\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const matrix<double> randm( \n        long nr,\n        long nc\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n        ensures\n            - generates a random matrix using std::rand() \n            - returns a matrix M such that\n                - M::type == double\n                - M.nr() == nr\n                - M.nc() == nc\n                - for all valid i, j:\n                    - M(i,j) == a random number such that 0 <= M(i,j) < 1\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline const matrix_exp gaussian_randm (\n        long nr,\n        long nc,\n        unsigned long seed = 0\n    );\n    /*!\n        requires\n            - nr >= 0\n            - nc >= 0\n        ensures\n            - returns a matrix with its values filled with 0 mean unit variance Gaussian\n              random numbers.  \n            - Each setting of the seed results in a different random matrix.\n            - The returned matrix is lazily evaluated using the expression templates\n              technique.  This means that the returned matrix doesn't take up any memory\n              and is only an expression template.  The values themselves are computed on\n              demand using the gaussian_random_hash() routine.  \n            - returns a matrix M such that\n                - M::type == double\n                - M.nr() == nr\n                - M.nc() == nc\n                - for all valid i, j:\n                    - M(i,j) == gaussian_random_hash(i,j,seed) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                                 Pixel and Image Utilities\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename P\n        >\n    const matrix<T,pixel_traits<P>::num,1> pixel_to_vector (\n        const P& pixel\n    );\n    /*!\n        requires\n            - pixel_traits<P> must be defined\n        ensures\n            - returns a matrix M such that:\n                - M::type == T\n                - M::NC == 1 \n                - M::NR == pixel_traits<P>::num\n                - if (pixel_traits<P>::grayscale) then\n                    - M(0) == pixel \n                - if (pixel_traits<P>::rgb) then\n                    - M(0) == pixel.red \n                    - M(1) == pixel.green \n                    - M(2) == pixel.blue \n                - if (pixel_traits<P>::hsi) then\n                    - M(0) == pixel.h \n                    - M(1) == pixel.s \n                    - M(2) == pixel.i \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P\n        >\n    void vector_to_pixel (\n        P& pixel,\n        const matrix_exp& vector \n    );\n    /*!\n        requires\n            - vector::NR == pixel_traits<P>::num\n            - vector::NC == 1 \n              (i.e. you have to use a statically dimensioned vector)\n        ensures\n            - if (pixel_traits<P>::grayscale) then\n                - pixel == M(0) \n            - if (pixel_traits<P>::rgb) then\n                - pixel.red   == M(0)  \n                - pixel.green == M(1) \n                - pixel.blue  == M(2)  \n            - if (pixel_traits<P>::hsi) then\n                - pixel.h == M(0)\n                - pixel.s == M(1)\n                - pixel.i == M(2)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        long lower,\n        long upper \n        >\n    const matrix_exp clamp (\n        const matrix_exp& m\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) > upper) then\n                        - R(r,c) == upper\n                    - else if (m(r,c) < lower) then\n                        - R(r,c) == lower\n                    - else\n                        - R(r,c) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp clamp (\n        const matrix_exp& m,\n        const matrix_exp::type& lower,\n        const matrix_exp::type& upper\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) > upper) then\n                        - R(r,c) == upper\n                    - else if (m(r,c) < lower) then\n                        - R(r,c) == lower\n                    - else\n                        - R(r,c) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp clamp (\n        const matrix_exp& m,\n        const matrix_exp& lower,\n        const matrix_exp& upper\n    );\n    /*!\n        requires\n            - m.nr() == lower.nr()\n            - m.nc() == lower.nc()\n            - m.nr() == upper.nr()\n            - m.nc() == upper.nc()\n            - m, lower, and upper all contain the same type of elements. \n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) > upper(r,c)) then\n                        - R(r,c) == upper(r,c)\n                    - else if (m(r,c) < lower(r,c)) then\n                        - R(r,c) == lower(r,c)\n                    - else\n                        - R(r,c) == m(r,c)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp lowerbound (\n        const matrix_exp& m,\n        const matrix_exp::type& thresh \n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) >= thresh) then\n                        - R(r,c) == m(r,c)\n                    - else\n                        - R(r,c) == thresh\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const matrix_exp upperbound (\n        const matrix_exp& m,\n        const matrix_exp::type& thresh \n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R::type == the same type that was in m\n                - R has the same dimensions as m\n                - for all valid r and c:\n                    - if (m(r,c) <= thresh) then\n                        - R(r,c) == m(r,c)\n                    - else\n                        - R(r,c) == thresh\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MATRIx_UTILITIES_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/matrix/symmetric_matrix_cache.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_\n#define DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_\n\n#include \"symmetric_matrix_cache_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n#include \"../array.h\"\n\nnamespace dlib \n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename cache_element_type>\n    struct op_symm_cache : basic_op_m<M>\n    {\n        inline op_symm_cache( \n            const M& m_,\n            long max_size_megabytes_\n        ) : \n            basic_op_m<M>(m_),\n            max_size_megabytes(max_size_megabytes_),\n            is_initialized(false)\n        {\n            lookup.assign(this->m.nr(), -1);\n\n            diag_cache = matrix_cast<cache_element_type>(dlib::diag(m_));\n        }\n\n        op_symm_cache (\n            const op_symm_cache& item\n        ) :\n            basic_op_m<M>(item.m),\n            diag_cache(item.diag_cache),\n            max_size_megabytes(item.max_size_megabytes),\n            is_initialized(false)\n        {\n            lookup.assign(this->m.nr(), -1);\n        }\n\n        typedef cache_element_type type;\n        typedef const cache_element_type& const_ret_type;\n        const static long cost = M::cost + 3;\n\n        inline const_ret_type apply ( long r, long c) const\n        { \n            if (lookup[c] != -1)\n            {\n                return cache[lookup[c]](r);\n            }\n            else if (r == c)\n            {\n                return diag_cache(r);\n            }\n            else if (lookup[r] != -1)\n            {\n                // the matrix is symmetric so this is legit\n                return cache[lookup[r]](c);\n            }\n            else\n            {\n                add_col_to_cache(c);\n                return cache[lookup[c]](r);\n            }\n        }\n\n        inline std::pair<const type*,long*> col(long i) const \n        /*!\n            requires\n                - 0 <= i < nc()\n            ensures\n                - returns a pair P such that:\n                    - P.first == a pointer to the first element of the ith column\n                    - P.second == a pointer to the integer used to count the number of\n                      outstanding references to the ith column.\n        !*/\n        { \n            if (is_cached(i) == false)\n                add_col_to_cache(i);\n\n            // find where this column is in the cache\n            long idx = lookup[i];\n            if (idx == next)\n            {\n                // if this column was the next to be replaced\n                // then make sure that doesn't happen\n                next = (next + 1)%cache.size();\n            }\n\n            return std::make_pair(&cache[idx](0), &references[idx]); \n        }\n\n        const type* diag() const { init(); return &diag_cache(0); }\n\n        long* diag_ref_count() const\n        {\n            return &diag_reference_count;\n        }\n\n    private:\n        inline bool is_cached (\n            long r\n        ) const\n        {\n            return (lookup[r] != -1);\n        }\n\n        inline void init() const\n        {\n            if (is_initialized == false)\n            {\n                // figure out how many columns of the matrix we can have\n                // with the given amount of memory.\n                long max_size = (max_size_megabytes*1024*1024)/(this->m.nr()*sizeof(type));\n                // don't let it be 0 or 1\n                if (max_size <= 1)\n                    max_size = 2;\n\n                const long size = std::min(max_size,this->m.nr());\n\n                diag_reference_count = 0;\n\n                references.set_max_size(this->m.nr());\n                references.set_size(size);\n                for (unsigned long i = 0; i < references.size(); ++i)\n                    references[i] = 0;\n\n                cache.set_max_size(this->m.nr());\n                cache.set_size(size);\n\n                rlookup.assign(size,-1);\n                next = 0;\n\n                is_initialized = true;\n            }\n        }\n\n        void make_sure_next_is_unreferenced (\n        ) const\n        {\n            if (references[next] != 0)\n            {\n                // find an unreferenced element of the cache\n                unsigned long i;\n                for (i = 1; i < references.size(); ++i)\n                {\n                    const unsigned long idx = (next+i)%references.size();\n                    if (references[idx] == 0)\n                    {\n                        next = idx;\n                        break;\n                    }\n                }\n\n                // if all elements of the cache are referenced then make the cache bigger\n                // and use the new element.\n                if (references[next] != 0)\n                {\n                    cache.resize(cache.size()+1);\n\n                    next = references.size();\n                    references.resize(references.size()+1);\n                    references[next] = 0;\n\n                    rlookup.push_back(-1);\n                }\n            }\n        }\n\n        inline void add_col_to_cache(\n            long c\n        ) const\n        {\n            init();\n            make_sure_next_is_unreferenced();\n\n            // if the lookup table is pointing to cache[next] then clear lookup[next]\n            if (rlookup[next] != -1)\n                lookup[rlookup[next]] = -1;\n\n            // make the lookup table so that it says c is now cached at the spot indicated by next\n            lookup[c] = next;\n            rlookup[next] = c;\n\n            // compute this column in the matrix and store it in the cache\n            cache[next] = matrix_cast<cache_element_type>(colm(this->m,c));\n\n            next = (next + 1)%cache.size();\n        }\n\n        /*!\n        INITIAL VALUE\n            - for all valid x:\n                - lookup(x) == -1 \n\n            - diag_cache == the diagonal of the original matrix\n            - is_initialized == false \n            - max_size_megabytes == the max_size_megabytes from symmetric_matrix_cache()\n\n        CONVENTION\n            - diag_cache == the diagonal of the original matrix\n            - lookup.size() == diag_cache.size()\n\n            - if (is_initialized) then\n                - if (lookup[c] != -1) then\n                    - cache[lookup[c]] == the cached column c of the matrix\n                    - rlookup[lookup[c]] == c\n\n                - if (rlookup[x] != -1) then\n                    - lookup[rlookup[x]] == x\n                    - cache[x] == the cached column rlookup[x] of the matrix\n\n                - next == the next element in the cache table to use to cache something \n                - references[i] == the number of outstanding references to cache element cache[i]\n\n                - diag_reference_count == the number of outstanding references to diag_cache. \n                  (this isn't really needed.  It's just here so that we can reuse the matrix\n                  expression from colm() to implement diag())\n        !*/\n\n\n        mutable array<matrix<type,0,1,typename M::mem_manager_type> > cache;\n        mutable array<long> references;\n        matrix<type,0,1,typename M::mem_manager_type> diag_cache;\n        mutable std::vector<long> lookup;\n        mutable std::vector<long> rlookup;\n        mutable long next;\n\n        const long max_size_megabytes;\n        mutable bool is_initialized;\n        mutable long diag_reference_count;\n\n    };\n\n    template <\n        typename cache_element_type,\n        typename EXP\n        >\n    const matrix_op<op_symm_cache<EXP,cache_element_type> >  symmetric_matrix_cache (\n        const matrix_exp<EXP>& m,\n        long max_size_megabytes\n    )\n    {\n        // Don't check that m is symmetric since doing so would be extremely onerous for the\n        // kinds of matrices intended for use with the symmetric_matrix_cache.  Check everything\n        // else though.\n        DLIB_ASSERT(m.size() > 0 && m.nr() == m.nc() && max_size_megabytes >= 0, \n            \"\\tconst matrix_exp symmetric_matrix_cache(const matrix_exp& m, max_size_megabytes)\"\n            << \"\\n\\t You have given invalid arguments to this function\"\n            << \"\\n\\t m.nr():             \" << m.nr()\n            << \"\\n\\t m.nc():             \" << m.nc() \n            << \"\\n\\t m.size():           \" << m.size() \n            << \"\\n\\t max_size_megabytes: \" << max_size_megabytes \n            );\n\n        typedef op_symm_cache<EXP,cache_element_type> op;\n        return matrix_op<op>(op(m.ref(), max_size_megabytes));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename cache_element_type>\n    struct op_colm_symm_cache \n    {\n        typedef cache_element_type type;\n\n        op_colm_symm_cache(\n            const M& m_,\n            const type* data_,\n            long* ref_count_ \n        ) : \n            m(m_), \n            data(data_),\n            ref_count(ref_count_)\n        {\n            *ref_count += 1;\n        }\n\n        op_colm_symm_cache (\n            const op_colm_symm_cache& item\n        ) :\n            m(item.m), \n            data(item.data),\n            ref_count(item.ref_count)\n        {\n            *ref_count += 1;\n        }\n\n        ~op_colm_symm_cache(\n        )\n        {\n            *ref_count -= 1;\n        }\n\n        const M& m;\n\n        const type* const data;\n        long* const ref_count;\n\n        const static long cost = M::cost;\n        const static long NR = M::NR;\n        const static long NC = 1;\n        typedef const type& const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        inline const_ret_type apply ( long r, long) const { return data[r]; }\n\n        long nr () const { return m.nr(); }\n        long nc () const { return 1; }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP,\n        typename cache_element_type\n        >\n    inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > colm (\n        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m,\n        long col \n    )\n    {\n        DLIB_ASSERT(col >= 0 && col < m.nc(), \n            \"\\tconst matrix_exp colm(const matrix_exp& m, row)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\tcol:    \" << col \n            );\n\n        std::pair<const cache_element_type*,long*> p = m.ref().op.col(col);\n\n        typedef op_colm_symm_cache<EXP,cache_element_type> op;\n        return matrix_op<op>(op(m.ref().op.m, \n                                p.first,\n                                p.second));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP,\n        typename cache_element_type\n        >\n    inline const matrix_op<op_colm_symm_cache<EXP,cache_element_type> > diag (\n        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m\n    )\n    {\n        typedef op_colm_symm_cache<EXP,cache_element_type> op;\n        return matrix_op<op>(op(m.ref().op.m, \n                                m.ref().op.diag(),\n                                m.ref().op.diag_ref_count()));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename M, typename cache_element_type>\n    struct op_rowm_symm_cache \n    {\n        typedef cache_element_type type;\n\n        op_rowm_symm_cache(\n            const M& m_,\n            const type* data_,\n            long* ref_count_ \n        ) : \n            m(m_), \n            data(data_),\n            ref_count(ref_count_)\n        {\n            *ref_count += 1;\n        }\n\n        op_rowm_symm_cache (\n            const op_rowm_symm_cache& item\n        ) :\n            m(item.m), \n            data(item.data),\n            ref_count(item.ref_count)\n        {\n            *ref_count += 1;\n        }\n\n        ~op_rowm_symm_cache(\n        )\n        {\n            *ref_count -= 1;\n        }\n\n        const M& m;\n\n        const type* const data;\n        long* const ref_count;\n\n        const static long cost = M::cost;\n        const static long NR = 1;\n        const static long NC = M::NC;\n        typedef const type& const_ret_type;\n        typedef typename M::mem_manager_type mem_manager_type;\n        typedef typename M::layout_type layout_type;\n        inline const_ret_type apply ( long , long c) const { return data[c]; }\n\n        long nr () const { return 1; }\n        long nc () const { return m.nc(); }\n\n        template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }\n        template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }\n    };\n\n    template <\n        typename EXP,\n        typename cache_element_type\n        >\n    inline const matrix_op<op_rowm_symm_cache<EXP,cache_element_type> > rowm (\n        const matrix_exp<matrix_op<op_symm_cache<EXP,cache_element_type> > >& m,\n        long row \n    )\n    {\n        DLIB_ASSERT(row >= 0 && row < m.nr(), \n            \"\\tconst matrix_exp rowm(const matrix_exp& m, row)\"\n            << \"\\n\\tYou have specified invalid sub matrix dimensions\"\n            << \"\\n\\tm.nr(): \" << m.nr()\n            << \"\\n\\tm.nc(): \" << m.nc() \n            << \"\\n\\trow:    \" << row \n            );\n\n        std::pair<const cache_element_type*,long*> p = m.ref().op.col(row);\n\n        typedef op_rowm_symm_cache<EXP,cache_element_type> op;\n        return matrix_op<op>(op(m.ref().op.m, \n                                p.first,\n                                p.second));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP, typename cache_element_type>\n    struct colm_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >\n    {\n        typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;\n    };\n\n    template <typename EXP, typename cache_element_type>\n    struct rowm_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >\n    {\n        typedef matrix_op<op_rowm_symm_cache<EXP, cache_element_type> > type;\n    };\n\n    template <typename EXP, typename cache_element_type>\n    struct diag_exp<matrix_op<op_symm_cache<EXP, cache_element_type> > >\n    {\n        typedef matrix_op<op_colm_symm_cache<EXP, cache_element_type> > type;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SYMMETRIC_MATRIX_CAcHE_Hh_\n\n"
  },
  {
    "path": "dlib/matrix/symmetric_matrix_cache_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#define DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_\n#ifndef DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_\n\n#include \"matrix_abstract.h\"\n\nnamespace dlib \n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename cache_element_type\n        >\n    const matrix_exp symmetric_matrix_cache (\n        const matrix_exp& m,\n        long max_size_megabytes\n    );\n    /*!\n        requires\n            - m.size() > 0\n            - m.nr() == m.nc()\n            - max_size_megabytes >= 0\n        ensures\n            - This function assumes that m is symmetric.  If m is not symmetric then it won't\n              crash but you will get incorrect results.\n            - This method creates a matrix expression which internally caches the elements\n              of m so that they can be accessed quickly.  It is useful if m is some kind of\n              complex matrix expression which is both very large and expensive to evaluate.\n              An example would be a kernel_matrix() expression with an expensive kernel and\n              a large number of samples.  Such an expression would result in a huge matrix,\n              potentially too big to store in memory.  The symmetric_matrix_cache() then makes\n              it easy to store just the parts of a matrix expression which are accessed most \n              often in memory.  The specific details are defined below.\n            - returns a matrix M such that\n                - M == m\n                  (i.e. M represents the same matrix as m)\n                - M will cache elements of m and hold them internally so they can be quickly \n                  accessed.  In particular, M will attempt to allocate no more than \n                  max_size_megabytes megabytes of memory for the purposes of caching\n                  elements of m.  When an element of the matrix is accessed it is either\n                  retrieved from the cache, or if this is not possible, then an entire\n                  column of m is loaded into a part of the cache which hasn't been used\n                  recently and the needed element returned.\n                - diag(m) is always loaded into the cache and is stored separately from \n                  the cached columns.  That means accesses to the diagonal elements of m\n                  are always fast.\n                - M will store the cached elements of m as cache_element_type objects.\n                  Typically, cache_element_type will be float or double.  \n                - To avoid repeated cache lookups, the following operations are optimized for\n                  use with the symmetric_matrix_cache():\n                    - diag(M), rowm(M,row_idx), colm(M,col_idx)\n                      These methods will perform only one cache lookup operation for an\n                      entire row/column/diagonal worth of data.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SYMMETRIC_MATRIX_CAcHE_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/matrix.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MATRIx_HEADER\n#define DLIB_MATRIx_HEADER\n\n#include \"matrix/matrix.h\"\n#include \"matrix/matrix_utilities.h\"\n#include \"matrix/matrix_subexp.h\"\n#include \"matrix/matrix_math_functions.h\"\n#include \"matrix/matrix_assign.h\"\n#include \"matrix/matrix_la.h\"\n#include \"matrix/symmetric_matrix_cache.h\"\n#include \"matrix/matrix_conv.h\"\n#include \"matrix/matrix_read_from_istream.h\"\n#include \"matrix/matrix_fft.h\"\n#include \"matrix/matrix_generic_image.h\"\n\n#ifdef DLIB_USE_BLAS\n#include \"matrix/matrix_blas_bindings.h\"\n#endif\n\n#endif // DLIB_MATRIx_HEADER\n\n\n"
  },
  {
    "path": "dlib/md5/md5_kernel_1.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MD5_KERNEL_1_CPp_\n#define DLIB_MD5_KERNEL_1_CPp_\n#include \"md5_kernel_1.h\"\n#include \"../uintn.h\"\n\n#include <sstream>\n#include <cstring>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace md5_stuff\n    {\n        \n        inline uint32 F (\n            uint32 x, \n            uint32 y, \n            uint32 z\n        )\n        {\n            return ( (x&y) | ((~x)&z) );\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline uint32 G (\n            uint32 x, \n            uint32 y, \n            uint32 z\n        )\n        {\n            return ( (x&z) | (y&(~z)) );\n        }\n\n    // ------------------------------------------------------------------------------------\n        \n        inline uint32 H (\n            uint32 x, \n            uint32 y, \n            uint32 z\n        ) \n        {\n            return ( x^y^z );\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline uint32 I (\n            uint32 x, \n            uint32 y, \n            uint32 z\n        )\n        {\n            return ( y ^ (x|(~z)) );\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline uint32 rotate_left (\n            uint32 x, \n            uint32 n\n        )\n        {\n            return  ( (x<<n) | (x>>(32-n)) );\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void FF (\n            uint32& a, \n            uint32 b, \n            uint32 c, \n            uint32 d, \n            uint32 x, \n            uint32 s, \n            uint32 ac\n        ) \n        { \n            a += F(b, c, d) + x + ac; \n            a = rotate_left(a, s); \n            a += b; \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void GG (\n            uint32& a, \n            uint32 b, \n            uint32 c, \n            uint32 d, \n            uint32 x, \n            uint32 s, \n            uint32 ac\n        ) \n        { \n            a += G(b, c, d) + x + ac; \n            a = rotate_left(a, s); \n            a += b; \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void HH (\n            uint32& a, \n            uint32 b, \n            uint32 c, \n            uint32 d, \n            uint32 x, \n            uint32 s, \n            uint32 ac\n        ) \n        { \n            a += H(b, c, d) + x + ac; \n            a = rotate_left(a, s); \n            a += b; \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline void II (\n            uint32& a, \n            uint32 b, \n            uint32 c, \n            uint32 d, \n            uint32 x, \n            uint32 s, \n            uint32 ac\n        ) \n        { \n            a += I(b, c, d) + x + ac; \n            a = rotate_left(a, s); \n            a += b; \n        }\n\n    // ------------------------------------------------------------------------------------\n\n        void scramble_block (\n            uint32& a,\n            uint32& b,\n            uint32& c,\n            uint32& d,\n            uint32* x\n        )\n        {\n            const uint32 S11 = 7;\n            const uint32 S12 = 12;\n            const uint32 S13 = 17;\n            const uint32 S14 = 22;\n            const uint32 S21 = 5;\n            const uint32 S22 = 9;\n            const uint32 S23 = 14;\n            const uint32 S24 = 20;\n            const uint32 S31 = 4;\n            const uint32 S32 = 11;\n            const uint32 S33 = 16;\n            const uint32 S34 = 23;\n            const uint32 S41 = 6;\n            const uint32 S42 = 10;\n            const uint32 S43 = 15;\n            const uint32 S44 = 21;\n\n\n            // round 1\n            FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1\n            FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2\n            FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3\n            FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4\n            FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5\n            FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6\n            FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7\n            FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8\n            FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9\n            FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10\n            FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11\n            FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12\n            FF (a, b, c, d, x[12], S11, 0x6b901122); // 13\n            FF (d, a, b, c, x[13], S12, 0xfd987193); // 14\n            FF (c, d, a, b, x[14], S13, 0xa679438e); // 15\n            FF (b, c, d, a, x[15], S14, 0x49b40821); // 16\n\n            // Round 2 \n            GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17\n            GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18\n            GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19\n            GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20\n            GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21\n            GG (d, a, b, c, x[10], S22,  0x2441453); // 22\n            GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23\n            GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24\n            GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25\n            GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26\n            GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27\n            GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28\n            GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29\n            GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30\n            GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31\n            GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32\n\n            // Round 3 \n            HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33\n            HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34\n            HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35\n            HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36\n            HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37\n            HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38\n            HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39\n            HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40\n            HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41\n            HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42\n            HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43\n            HH (b, c, d, a, x[ 6], S34,  0x4881d05); // 44\n            HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45\n            HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46\n            HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47\n            HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48\n\n            // Round 4 \n            II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49\n            II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50\n            II (c, d, a, b, x[14], S43, 0xab9423a7); // 51\n            II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52\n            II (a, b, c, d, x[12], S41, 0x655b59c3); // 53\n            II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54\n            II (c, d, a, b, x[10], S43, 0xffeff47d); // 55\n            II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56\n            II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57\n            II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58\n            II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59\n            II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60\n            II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61\n            II (d, a, b, c, x[11], S42, 0xbd3af235); // 62\n            II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63\n            II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64\n        }\n\n    } \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n\n    const std::string md5 (\n        const std::string& input\n    )\n    {\n        unsigned char output[16];\n        md5 ( \n            reinterpret_cast<const unsigned char*>(input.data()),\n            static_cast<unsigned long>(input.size()),\n            output\n            );\n\n        \n        std::stringstream temp;\n        for (int i = 0; i < 16; ++i)\n        {\n            temp.fill('0');\n            temp.width(2);\n            temp << std::hex << static_cast<unsigned int>(output[i]);\n        }\n        \n        return temp.str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        const unsigned char* input,\n        unsigned long len,\n        unsigned char* output\n    )\n    {\n        using namespace md5_stuff;\n\n\n\n\n        // make a temp version of input with enough space for padding and len appended\n        unsigned long extra_len = 64-len%64;\n        if (extra_len <= 8)\n            extra_len += 64;\n        unsigned char* temp = new unsigned char[extra_len + len];\n\n        // number of 16 word blocks\n        const unsigned long N = (extra_len + len)/64;\n\n        const unsigned char* input2 = input;\n        unsigned char* temp2 = temp;\n        unsigned char* end = temp+len;\n\n        // copy input into temp\n        while (temp2 != end)\n        {\n            *temp2 = *input2;\n            ++temp2;\n            ++input2;\n        }\n\n        // pad temp\n        end += extra_len-8;\n        *temp2 = static_cast<unsigned char>(0x80);\n        ++temp2;\n        while (temp2 != end)\n        {\n            *temp2 = 0;\n            ++temp2;\n        }\n\n        // make len the number of bits in the original message\n        // but first multiply len by 8 and since len is only 32 bits the number might\n        // overflow so we will carry out the multiplication manually and end up with\n        // the result in the base 65536 number with three digits\n        // result = low + high*65536 + upper*65536*65536\n        unsigned long low = len & 0xFFFF;\n        unsigned long high = len >> 16;\n        unsigned long upper;\n        unsigned long tmp;\n        tmp = low * 8;\n        low = tmp & 0xFFFF;\n        tmp = high * 8 + (tmp>>16);\n        high = tmp & 0xFFFF;\n        upper = tmp >> 16;\n        \n\n        // append the length\n        *temp2 = static_cast<unsigned char>(low&0xFF);\n        ++temp2;\n        *temp2 = static_cast<unsigned char>((low>>8)&0xFF);\n        ++temp2;\n        *temp2 = static_cast<unsigned char>((high)&0xFF);\n        ++temp2;\n        *temp2 = static_cast<unsigned char>((high>>8)&0xFF);\n        ++temp2;\n        *temp2 = static_cast<unsigned char>((upper)&0xFF);;\n        ++temp2;\n        *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);;\n        ++temp2;\n        *temp2 = 0;\n        ++temp2;\n        *temp2 = 0;\n        \n\n        uint32 a = 0x67452301;\n        uint32 b = 0xefcdab89;\n        uint32 c = 0x98badcfe;\n        uint32 d = 0x10325476;\n\n\n        // an array of 16 words\n        uint32 x[16];\n\n        for (unsigned long i = 0; i < N; ++i)\n        {\n    \n            // copy a block of 16 words from m into x\n            for (unsigned long j = 0; j < 16; ++j)\n            {\n                x[j] = (\n                    (static_cast<uint32>(temp[4*(j + 16*i) + 3]) << 24) |\n                    (static_cast<uint32>(temp[4*(j + 16*i) + 2]) << 16) |\n                    (static_cast<uint32>(temp[4*(j + 16*i) + 1]) << 8 ) |\n                    (static_cast<uint32>(temp[4*(j + 16*i)    ])      )\n                    );               \n            }\n\n            uint32 aa = a;\n            uint32 bb = b;\n            uint32 cc = c;\n            uint32 dd = d;\n\n\n            scramble_block(a,b,c,d,x);\n\n\n            a = a + aa;\n            b = b + bb;\n            c = c + cc;\n            d = d + dd;\n\n        }\n\n\n        // put a, b, c, and d into output\n        output[0]   = static_cast<unsigned char>((a)    &0xFF);\n        output[1]   = static_cast<unsigned char>((a>>8) &0xFF);\n        output[2]   = static_cast<unsigned char>((a>>16)&0xFF);\n        output[3]   = static_cast<unsigned char>((a>>24)&0xFF);\n\n        output[4]   = static_cast<unsigned char>((b)    &0xFF);\n        output[5]   = static_cast<unsigned char>((b>>8) &0xFF);\n        output[6]   = static_cast<unsigned char>((b>>16)&0xFF);\n        output[7]   = static_cast<unsigned char>((b>>24)&0xFF);\n\n        output[8]   = static_cast<unsigned char>((c)    &0xFF);\n        output[9]   = static_cast<unsigned char>((c>>8) &0xFF);\n        output[10]  = static_cast<unsigned char>((c>>16)&0xFF);\n        output[11]  = static_cast<unsigned char>((c>>24)&0xFF);\n\n        output[12]  = static_cast<unsigned char>((d)    &0xFF);\n        output[13]  = static_cast<unsigned char>((d>>8) &0xFF);\n        output[14]  = static_cast<unsigned char>((d>>16)&0xFF);\n        output[15]  = static_cast<unsigned char>((d>>24)&0xFF);\n\n        delete [] temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string md5 (\n        std::istream& input\n    )\n    {\n        unsigned char output[16];\n        md5 ( \n            input,\n            output\n            );\n\n        \n        std::stringstream temp;\n        for (int i = 0; i < 16; ++i)\n        {\n            temp.fill('0');\n            temp.width(2);\n            temp << std::hex << static_cast<unsigned int>(output[i]);\n        }\n        \n        return temp.str();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        std::istream& input,\n        unsigned char* output\n    )\n    {\n        using namespace md5_stuff;\n\n\n                \n\n        uint32 a = 0x67452301;\n        uint32 b = 0xefcdab89;\n        uint32 c = 0x98badcfe;\n        uint32 d = 0x10325476;\n\n\n\n        std::streamsize len = 0;\n\n        // an array of 16 words\n        uint32 x[16];\n        unsigned char temp[64];\n\n\n\n        bool write_length = false;\n        bool at_end = false;\n        std::streambuf& inputbuf = *input.rdbuf();\n        while(!at_end)\n        {\n            std::streamsize num = inputbuf.sgetn(reinterpret_cast<char*>(temp),64);\n            len += num;\n\n            // if we hit the end of the stream then pad and add length\n            if (num < 64)\n            {\n                at_end = true;\n                unsigned char* temp2 = temp;\n                unsigned char* end;\n                if (num < 56)\n                    end = temp+56;\n                else\n                    end = temp+64;\n\n                temp2 += num;\n\n                // apply padding\n                *temp2 = 0x80;\n                ++temp2;\n                while (temp2 != end)\n                {\n                    *temp2 = 0;\n                    ++temp2;\n                }\n\n\n                if (num < 56)\n                {\n                    write_length = true;\n                    // make len the number of bits in the original message\n                    // but first multiply len by 8 and since len is only 32 bits the number might\n                    // overflow so we will carry out the multiplication manually and end up with\n                    // the result in the base 65536 number with three digits\n                    // result = low + high*65536 + upper*65536*65536\n                    unsigned long low = len & 0xFFFF;\n                    unsigned long high = len >> 16;\n                    unsigned long upper;\n                    unsigned long tmp;\n                    tmp = low * 8;\n                    low = tmp & 0xFFFF;\n                    tmp = high * 8 + (tmp>>16);\n                    high = tmp & 0xFFFF;\n                    upper = tmp >> 16;\n\n\n                    // append the length\n                    *temp2 = static_cast<unsigned char>(low&0xFF);\n                    ++temp2;\n                    *temp2 = static_cast<unsigned char>((low>>8)&0xFF);\n                    ++temp2;\n                    *temp2 = static_cast<unsigned char>((high)&0xFF);\n                    ++temp2;\n                    *temp2 = static_cast<unsigned char>((high>>8)&0xFF);\n                    ++temp2;\n                    *temp2 = static_cast<unsigned char>((upper)&0xFF);;\n                    ++temp2;\n                    *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);;\n                    ++temp2;\n                    *temp2 = 0;\n                    ++temp2;\n                    *temp2 = 0;\n                }\n\n\n            }\n\n\n            // copy a block of 16 words from m into x\n            for (unsigned long i = 0; i < 16; ++i)\n            {\n                x[i] = (\n                    (static_cast<uint32>(temp[4*i + 3]) << 24) |\n                    (static_cast<uint32>(temp[4*i + 2]) << 16) |\n                    (static_cast<uint32>(temp[4*i + 1]) << 8 ) |\n                    (static_cast<uint32>(temp[4*i    ])      )\n                    );               \n            }\n            \n\n            uint32 aa = a;\n            uint32 bb = b;\n            uint32 cc = c;\n            uint32 dd = d;\n\n\n            scramble_block(a,b,c,d,x);\n\n\n            a = a + aa;\n            b = b + bb;\n            c = c + cc;\n            d = d + dd;\n\n        }\n\n        if (!write_length)\n        {\n            uint64 temp = len*8;\n\n            uint32 aa = a;\n            uint32 bb = b;\n            uint32 cc = c;\n            uint32 dd = d;\n\n            std::memset(x, 0, sizeof(x));\n            x[15] = (temp>>32);\n            x[14] = (temp&0xFFFFFFFF);\n\n            scramble_block(a,b,c,d,x);\n\n\n            a = a + aa;\n            b = b + bb;\n            c = c + cc;\n            d = d + dd;\n\n        }\n\n\n        // put a, b, c, and d into output\n        output[0]   = static_cast<unsigned char>((a)    &0xFF);\n        output[1]   = static_cast<unsigned char>((a>>8) &0xFF);\n        output[2]   = static_cast<unsigned char>((a>>16)&0xFF);\n        output[3]   = static_cast<unsigned char>((a>>24)&0xFF);\n\n        output[4]   = static_cast<unsigned char>((b)    &0xFF);\n        output[5]   = static_cast<unsigned char>((b>>8) &0xFF);\n        output[6]   = static_cast<unsigned char>((b>>16)&0xFF);\n        output[7]   = static_cast<unsigned char>((b>>24)&0xFF);\n\n        output[8]   = static_cast<unsigned char>((c)    &0xFF);\n        output[9]   = static_cast<unsigned char>((c>>8) &0xFF);\n        output[10]  = static_cast<unsigned char>((c>>16)&0xFF);\n        output[11]  = static_cast<unsigned char>((c>>24)&0xFF);\n\n        output[12]  = static_cast<unsigned char>((d)    &0xFF);\n        output[13]  = static_cast<unsigned char>((d>>8) &0xFF);\n        output[14]  = static_cast<unsigned char>((d>>16)&0xFF);\n        output[15]  = static_cast<unsigned char>((d>>24)&0xFF);\n\n        input.clear(std::ios::eofbit);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n#endif // DLIB_MD5_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/md5/md5_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MD5_KERNEl_1_\n#define DLIB_MD5_KERNEl_1_\n\n#include \"md5_kernel_abstract.h\"\n#include <string>\n#include <iosfwd>\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string md5 (\n        const std::string& input\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        const unsigned char* input,\n        unsigned long len,\n        unsigned char* output\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string md5 (\n        std::istream& input\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        std::istream& input,\n        unsigned char* output\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"md5_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_MD5_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/md5/md5_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MD5_KERNEl_ABSTRACT_\n#ifdef DLIB_MD5_KERNEl_ABSTRACT_\n\n#include <string>\n#include <iosfwd>\n\nnamespace dlib\n{\n\n    /*!\n        NOTE:\n        This is the RSA Data Security, Inc. MD5 Message-Digest Algorithm\n        as described in rfc1321\n\n        For the functions which return a unsigned char*.  The array contains \n        the 16 bytes of the digest and are in the correct order.  \n        i.e.  output[0], output[1], output[2], ...\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string md5 (\n        const std::string& input\n    );\n    /*!\n        ensures\n            - returns the md5 digest of input as a hexadecimal string\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        const unsigned char* input,\n        unsigned long len,\n        unsigned char* output\n    );\n    /*!\n        requires\n            - input  == pointer to len bytes \n            - output == pointer to 16 bytes \n            - input != output\n        ensures\n            - #output == the md5 digest of input.  \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    const std::string md5 (\n        std::istream& input\n    );\n    /*!\n        requires\n            - input.fail() == false\n        ensures\n            - returns the md5 digest of input as a hexadecimal string\n            - #input.eof()     == true \n            - #input.fail()    == false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void md5 (\n        std::istream& input\n        unsigned char* output\n    );\n    /*!\n        requires\n            - input.fail() == false\n            - output       == pointer to 16 bytes\n        ensures\n            - #output       == the md5 digest of input \n            - #input.eof()  == true \n            - #input.fail() == false\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MD5_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/md5.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#include \"md5/md5_kernel_1.h\"\n"
  },
  {
    "path": "dlib/media/ffmpeg_demuxer.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_FFMPEG_DEMUXER\n#define DLIB_FFMPEG_DEMUXER\n\n#include <chrono>\n#include <queue>\n#include <functional>\n#include <unordered_map>\n#include \"ffmpeg_utils.h\"\n#include \"../functional.h\"\n#include \"../constexpr_if.h\"\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class Callback,\n          std::enable_if_t<dlib::is_invocable<Callback, frame&>::value, bool> = true\n        >\n        auto wrap (\n            Callback&&              clb,\n            const resizing_args&    args_image = resizing_args{},\n            const resampling_args&  args_audio = resampling_args{}\n        );\n        /*!\n            requires\n                - Callback is a callback type with signature void(frame&)\n            ensures\n                - returns a new conforming callback which can be passed to\n                    decoder::push()\n                    decoder::flush()\n                - The callback returned by wrap() captures `clb`, `args_image` and `args_audio` by VALUE\n                - When a new frame object `f` is decoded it is optionally resized or resampled then \n                  the callback `clb` is invoked by passing `f` by reference like so: clb(f)\n                - It is safe for the callback `clb` to swap or move `f` when passed by reference in clb(f).\n                - Resizing is performed if:\n                    - the decoded frame `f` satisfies f.is_image() == true\n                    - args_image is non-empty\n                    - args_image.h      != f.height() or \n                      args_image.w      != f.width() or \n                      args_image.fmt    != f.pixfmt() \n                - Resampling is performed if:\n                    - the decoded frame `f` satisfies f.is_audio() == true\n                    - args_audio is non-empty\n                    - args_audio.sample_rate    != f.sample_rate() or \n                      args_audio.channel_layout != f.layout() or \n                      args_audio.fmt            != f.samplefmt()\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class Callback,\n          std::enable_if_t<is_callable<Callback>::value, bool> = true,\n          std::enable_if_t<callable_nargs<Callback>::value == 1, bool> = true,\n          std::enable_if_t<is_image_type<std::remove_reference_t<callable_arg<0, Callback>>>::value, bool> = true\n        >\n        auto wrap (\n            Callback&& clb\n        );\n        /*!\n            requires\n                - Callback is a callback type with signature void(image_type&)\n                  where image_type is an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h\n            ensures\n                - returns a new conforming callback which can be passed to\n                    decoder::push()\n                    decoder::flush()\n                - The callback returned by wrap() captures `clb` by VALUE.\n                - When a new frame object is decoded, it is converted to an image_type object `img`,\n                  then the callback `clb` is invoked like so: `clb(img)`\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        auto wrap (\n            std::queue<frame>& queue,\n            const resizing_args& args_image = resizing_args{},\n            const resampling_args& args_audio = resampling_args{}\n        );\n        /*!\n            ensures\n                - returns a new conforming callback which can be passed to\n                    decoder::push()\n                    decoder::flush()\n                - The callback returned by wrap() captures `queue` by REFERENCE, \n                  both `args_image` and `args_audio` by VALUE.\n                - When a new frame object `f` is decoded, it is optionally resized or resampled,\n                  then added to `queue`.\n                - Resizing is performed if:\n                    - the decoded frame `f` satisfies f.is_image() == true\n                    - args_image is non-empty\n                    - args_image.h != f.height() or \n                      args_image.w != f.width() or \n                      args_image.fmt != f.pixfmt() \n                - Resampling is performed if:\n                    - the decoded frame `f` satisfied f.is_audio() == true\n                    - args_audio is non-empty\n                    - args_audio.sample_rate != f.sample_rate() or \n                      args_audio.channel_layout != f.layout() or \n                      args_audio.fmt != f.samplefmt()\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class image_type>\n        auto wrap (\n            std::queue<image_type>& queue\n        );\n        /*!\n            requires\n                - image_type is an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h\n            ensures\n                - returns a new conforming callback which can be passed to\n                    decoder::push()\n                    decoder::flush()\n                - The callback returned by wrap() captures `queue` by REFERENCE.\n                - When a new frame object is decoded, it is converted to an image_type object `img`,\n                  then added to `queue`\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct decoder_codec_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments passed to the decoder and demuxer classes.\n                    Non-default values will configure the codecs.\n                    Note, for decoder, these are essential as they cannot be guessed.\n                    For demuxer, these are derived from the input file or network connection.\n                    Note, for some demuxers, you may still want to set these. For example, network demuxers\n                    such as RTSP or HTTP may require setting codec_options.\n            !*/\n\n            // Codec ID used to configure the decoder. Used by decoder, IGNORED by demuxer.\n            AVCodecID codec{AV_CODEC_ID_NONE};\n\n            // Codec name used to configure the decoder. This is used if codec == AV_CODEC_ID_NONE. Used by decoder, IGNORED by demuxer.\n            std::string codec_name;\n\n            // A dictionary of AVCodecContext and codec-private options. Used by \"avcodec_open2()\"\n            // This is less likely to be used when using demuxer objects, unless using network demuxers.\n            std::unordered_map<std::string, std::string> codec_options;\n\n            // Sets AVCodecContext::bit_rate if non-negative. Otherwise, ffmpeg's default is used.\n            int64_t bitrate{-1};\n\n            // OR-ed with AVCodecContext::flags if non-negative. Otherwise, ffmpeg's default is used.\n            int flags{0};\n\n            // Sets AVCodecContext::thread_count if non-negative. Otherwise, ffmpeg-s default is used. \n            // Some codecs can be multi-threaded. Setting this enables this and controls the size of the thread pool.\n            // Not all codecs can be parallelised.\n            int thread_count{-1};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n        \n        class decoder\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class is a libavcodec wrapper which decodes video or audio from raw memory.\n                    Note, if you are reading raw memory from file, it is easier to use demuxer\n                    as it also works with raw codec files like .h264 files.\n                    This class is suitable for example when reading raw encoded data from a socket,\n                    or interfacing with another library that provides encoded data.\n            !*/\n\n            using args = decoder_codec_args;\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This holds constructor arguments for decoder.\n            !*/\n\n            decoder() = default;\n            /*!\n                ensures\n                    - is_open() == false\n            !*/\n\n            explicit decoder(const args &a);\n            /*!\n                ensures\n                    - Creates a decoder using args.\n            !*/\n\n            bool is_open() const noexcept;\n            /*!\n                ensures\n                    - returns true if frames are available, i.e. read() == true\n            !*/\n\n            bool is_image_decoder() const noexcept;\n            /*!\n                ensures\n                    - returns true if is_open() == true and codec is an image/gif/video codec\n            !*/\n\n            bool is_audio_decoder() const noexcept;\n            /*!\n                ensures\n                    - returns true if is_open() == true and codec is an audio codec\n            !*/\n\n            AVCodecID get_codec_id() const noexcept;\n            /*!\n                requires\n                    - is_open() == true\n                ensures\n                    - returns the codec id. See ffmpeg documentation or libavcodec/codec_id.h\n            !*/\n\n            std::string get_codec_name() const noexcept;\n            /*!\n                requires\n                    - is_open() == true\n                ensures\n                    - returns string representation of codec id.\n            !*/\n\n            int height() const noexcept;\n            /*!\n                requires\n                    - is_image_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                      The height cannot be deduced from codec only. It can only be deduced from decoded data.\n                ensures \n                    - returns height of encoded images\n            !*/\n\n            int width() const noexcept;\n            /*!\n                requires\n                    - is_image_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns width of encoded images\n            !*/\n\n            AVPixelFormat pixel_fmt() const noexcept;\n            /*!\n                requires\n                    - is_image_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns pixel format of encoded images\n            !*/\n\n            /*! audio properties !*/\n\n            int sample_rate() const noexcept;\n            /*!\n                requires\n                    - is_audio_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns sample rate of encoded audio frames\n            !*/\n\n            uint64_t channel_layout() const noexcept;\n            /*!\n                requires\n                    - is_audio_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns channel layout of encoded audio frames\n            !*/\n\n            AVSampleFormat sample_fmt() const noexcept;\n            /*!\n                requires\n                    - is_audio_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns sample format of encoded audio frames\n            !*/\n\n            int nchannels() const noexcept;\n            /*!\n                requires\n                    - is_audio_decoder() == true\n                    - must have called push_encoded() enough times such that a call to read() would have returned a frame.\n                ensures\n                    - returns the number of channels (e.g. 2 if stereo, 1 if mono) of encoded audio frames\n            !*/\n\n            template <class Callback> \n            bool push (\n                const uint8_t*  encoded, \n                int             nencoded,\n                Callback&&      clb\n            );\n            /*!\n                requires\n                    - is_open() == true\n                    - clb is a valid callback created using one of the dlib::ffmpeg::wrap() global functions\n                    - clb must not call decoder::push() or decoder::flush(), i.e. the callback does not exhibit recursion.\n                ensures\n                    - encodes data\n                    - clb may get invoked with new frames\n            !*/\n\n            template <class Callback>\n            void flush(Callback&& clb);\n            /*!\n                requires\n                    - is_open() == true\n                    - clb is a valid callback created using one of the dlib::ffmpeg::wrap() global functions\n                    - clb must not call decoder::push() or decoder::flush(), i.e. the callback does not exhibit recursion.\n                ensures\n                    - Flushes the decoder. This must be called when there is no more data to be decoded. Last remaining frames will be available.\n                    - calls push_encoded(nullptr, 0)\n            !*/\n\n        private:\n            friend class demuxer;\n\n            bool open (\n                const args&                     a,\n                details::av_ptr<AVCodecContext> pCodecCtx_,\n                const AVCodec*                  codec,\n                AVRational                      timebase_\n            );\n\n            template <class Callback> bool push_padded(const uint8_t *encoded, int nencoded, Callback&& clb);\n            template <class Callback> bool push(const details::av_ptr<AVPacket>& pkt, Callback&& clb);\n\n            args                                    args_;\n            bool                                    open_{false};\n            bool                                    decoding{false};\n            AVRational                              timebase;\n            details::av_ptr<AVCodecParserContext>   parser;\n            details::av_ptr<AVCodecContext>         pCodecCtx;\n            details::av_ptr<AVPacket>               packet;\n            frame                                   avframe;\n            details::resizer                        resizer_image;\n            details::resampler                      resizer_audio;\n            std::vector<uint8_t>                    encoded_buffer;\n            uint64_t                                next_pts{0};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        class demuxer\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class is a libavformat wrapper which demuxes video and/or audio streams from file and decodes them.\n                    It is analogous to OpenCV's cv::VideoCapture class but is more configurable, supports audio, \n                    devices (X11, webcam, microphone, ...) and network streams such as RTSP, HTTP, and more.\n                    Note that a video file, e.g. MP4, can contain multiple streams: video, audio, subtitles, etc.\n                    This class can decode both video and audio at the same time.\n                    For audio files, e.g. MP3, FLAG, it only decodes audio.\n            !*/\n\n            struct args\n            {\n                /*!\n                    WHAT THIS OBJECT REPRESENTS\n                        This holds constructor arguments for demuxer.\n                !*/\n\n                args() = default;\n                /*!\n                    ensures\n                        - Default constructor\n                !*/\n\n                args(const std::string& filepath);\n                /*!\n                    ensures\n                        - this->filepath = filepath\n                !*/\n\n                args(const std::string& filepath, video_enabled_t video_on, audio_enabled_t audio_on);\n                /*!\n                    ensures\n                        - this->filepath        = filepath\n                        - this->enable_image    = video_on.enabled\n                        - this->enable_audio    = audio_on.enabled\n                !*/\n\n                // Filepath, URL or device\n                std::string filepath;\n\n                // Input format hint. e.g. 'rtsp', 'X11', 'alsa', etc. 99% of the time, users are not required to specify this as libavformat tries to guess it.\n                std::string input_format;\n\n                // A dictionary filled with AVFormatContext and demuxer-private options. Used by \"avformat_open_input()\"\".\n                // Please see libavformat documentation for more details\n                std::unordered_map<std::string, std::string> format_options;\n\n                // Sets AVFormatContext::probsize\n                // Please see libavformat documentation for more details\n                int probesize{-1};\n\n                // Only relevant to network demuxers such as RTSP, HTTP etc.\n                // Connection/listening timeout. \n                std::chrono::milliseconds connect_timeout{std::chrono::milliseconds::max()};\n                \n                // Only relevant to network demuxers such as RTSP, HTTP etc\n                // Read timeout. \n                std::chrono::milliseconds read_timeout{std::chrono::milliseconds::max()};\n\n                // Only relevant to network demuxers such as RTSP, HTTP etc\n                // Connection/listening interruption callback.\n                // The constructor periodically calls interrupter() while waiting on the network. If it returns true, then\n                // the connection is aborted and the demuxer is closed.\n                // So user may use this in conjunction with some thread-safe shared state to signal an abort/interrupt.\n                std::function<bool()> interrupter;\n\n                // Video stream codec arguments\n                decoder_codec_args args_codec_image;\n\n                // Audio stream codec arguments\n                decoder_codec_args args_codec_audio;\n                \n                // Whether or not to decode video stream.\n                bool enable_image{true};\n\n                // Whether or not to decode audio stream.\n                bool enable_audio{true};\n\n                // Sets the output frame rate for any device that allows you to do so, e.g. webcam, x11grab, etc. Does not apply to files. If -1, ignored.\n                int framerate{-1};\n\n                // Sets output height for any device that allows you to do so, e.g. webcam, x11grab, etc. Dot not apply to files. If -1, ignored.\n                int height{-1};\n\n                // Sets output width for any device that allows you to do so, e.g. webcam, x11grab, etc. Dot not apply to files. If -1, ignored.\n                int width{-1};\n            };\n\n            demuxer() = default;\n            /*!\n                ensures\n                    - is_open() == false\n            !*/\n\n            demuxer(const args& a);\n            /*!\n                ensures\n                    - Creates a demuxer using args.\n            !*/\n\n            demuxer(demuxer&& other) noexcept;\n            /*!\n                ensures\n                    - Move constructor\n                    - After move, other.is_open() == false\n            !*/\n\n            demuxer& operator=(demuxer&& other) noexcept;\n            /*!\n                ensures\n                    - Move assignment\n                    - After move, other.is_open() == false\n            !*/\n\n            bool is_open() const noexcept;\n            /*!\n                ensures\n                    - returns true if frames are available, i.e. read() == true\n            !*/\n\n            bool audio_enabled() const noexcept;\n            /*!\n                requires\n                    - args.enable_audio == true\n                ensures\n                    - returns true if is_open() == true and an audio stream is available and open\n            !*/\n\n            bool video_enabled() const noexcept;\n            /*!\n                requires\n                    - args.enable_image == true\n                ensures\n                    - returns true if is_open() == true and an video stream is available and open.\n            !*/\n\n            int height() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns height of encoded images\n                    - else\n                        - returns 0\n            !*/\n\n            int width() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns width of encoded images\n                    - else\n                        - returns 0\n            !*/\n\n            AVPixelFormat pixel_fmt() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns pixel format of encoded images\n                    - else\n                        - returns AV_PIX_FMT_NONE\n            !*/\n\n            float fps() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns frame rate (frames per second) of video\n                    - else\n                        - returns 0\n            !*/\n\n            int estimated_nframes() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - estimates and returns number of frames in video stream\n                    - else\n                        - returns 0\n            !*/\n\n            AVCodecID get_video_codec_id() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns codec ID of video stream\n                    - else\n                        - returns AV_CODEC_ID_NONE\n            !*/\n\n            std::string get_video_codec_name() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns codec name of video stream\n                    - else\n                        - returns \"\"\n            !*/\n\n            int sample_rate() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns sample rate of encoded audio frames\n                    - else\n                        - returns 0\n            !*/\n\n            uint64_t channel_layout() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns channel layout of encoded audio frames (e.g. AV_CH_LAYOUT_STEREO)\n                    - else\n                        - returns 0\n            !*/\n\n            AVSampleFormat sample_fmt() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns sample format of encoded audio frames (e.g. AV_SAMPLE_FMT_S16)\n                    - else\n                        - returns AV_SAMPLE_FMT_NONE\n            !*/\n\n            int nchannels() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns the number of channels in the encoded audio frames (e.g. 1 for mono, 2 for stereo)\n                    - else\n                        - returns 0\n            !*/\n\n            int estimated_total_samples() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns estimated number of samples in audio stream\n                    - else\n                        - returns 0\n            !*/\n\n            AVCodecID get_audio_codec_id() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns codec ID of audio stream\n                    - else\n                        - returns AV_CODEC_ID_NONE\n            !*/\n\n            std::string get_audio_codec_name() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns codec name of audio stream\n                    - else\n                        - returns \"\"\n            !*/\n\n            float duration() const noexcept;\n            /*!\n                ensures \n                    - if (is_open())\n                        - returns an estimated duration of file in seconds\n                    - else\n                        - returns 0\n            !*/\n\n            const std::unordered_map<std::string, std::string>& get_metadata() const noexcept;\n            /*!\n                ensures \n                    - if (is_open())\n                        - returns metadata in file\n            !*/\n\n            float get_rotation_angle() const noexcept;\n            /*!\n                ensures \n                    - if (is_open())\n                        - returns video rotation angle from metadata if available\n                    - else\n                        - returns 0\n            !*/\n\n            bool read (\n                frame& frame,\n                const resizing_args&   args_image = resizing_args{}, \n                const resampling_args& args_audio = resampling_args{}\n            );\n            /*!\n                ensures \n                    - if (is_open())\n                        - returns true\n                        - frame.is_empty() == false\n                        - optionally converts frame using args_image if frame.is_image() == true, or args_audio if frame.is_audio() == true\n                    - else\n                        - returns false and frame.is_empty() == true\n            !*/\n\n            template <\n              class image_type,\n              is_image_check<image_type> = true\n            >\n            bool read (\n                image_type& img\n            );\n            /*!\n                requires\n                    - image_type == an image object that implements the interface defined in\n                      dlib/image_processing/generic_image.h\n\n                ensures \n                    - keeps reading the file until one of the following is true:\n                        - is_open() == false, in which case return false;\n                        - an image is found, in which case it is converted to image_type appropriately and returns true\n                    - If num_rows(img) > 0 or num_cols(img) > 0 :\n                        then the frame is resized to fit those dimensions.\n                    - If num_rows(img) == 0 and num_cols(img) == 0:\n                        then the frame is copied to \"img\"\n            !*/\n\n        private:\n            bool open(const args& a);\n            bool object_alive() const noexcept;\n            bool interrupt_callback();\n            void populate_metadata();\n            bool fill_queue();\n\n            struct {\n                args                                    args_;\n                details::av_ptr<AVFormatContext>        pFormatCtx;\n                details::av_ptr<AVPacket>               packet;\n                decoder                                 channel_video;\n                decoder                                 channel_audio;\n                int                                     stream_id_video{-1};\n                int                                     stream_id_audio{-1};\n                std::chrono::system_clock::time_point   connecting_time{};\n                std::chrono::system_clock::time_point   connected_time{};\n                std::chrono::system_clock::time_point   last_read_time{};\n                std::unordered_map<std::string, std::string> metadata;\n                std::queue<frame>                       frame_queue;\n            } st;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type,\n          is_image_check<image_type> = true\n        >\n        void load_frame(\n            image_type& image,\n            const std::string& file_name\n        );\n        /*!\n            requires\n                - image_type must be a type conforming to the generic image interface.\n            ensures\n                - reads the first frame of the image or video pointed by file_name and\n                  loads into image.\n        !*/\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////// DEFINITIONS  ////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n\n// ---------------------------------------------------------------------------------------------------\n\n        namespace details\n        {\n            inline void convert (\n                const frame&            src_frame,\n                frame&                  dst_frame,\n                resizer&                resizer,\n                resampler&              resampler,\n                const resizing_args&    args_image, \n                const resampling_args&  args_audio\n            )\n            {\n                if (src_frame.is_image())\n                {\n                    resizer.resize(\n                        src_frame,\n                        args_image.h > 0                  ? args_image.h :   src_frame.height(),\n                        args_image.w > 0                  ? args_image.w :   src_frame.width(),\n                        args_image.fmt != AV_PIX_FMT_NONE ? args_image.fmt : src_frame.pixfmt(),\n                        dst_frame);\n                }\n                else\n                {\n                    resampler.resize(\n                        src_frame,\n                        args_audio.sample_rate > 0            ? args_audio.sample_rate      : src_frame.sample_rate(),\n                        args_audio.channel_layout > 0         ? args_audio.channel_layout   : src_frame.layout(),\n                        args_audio.fmt != AV_SAMPLE_FMT_NONE  ? args_audio.fmt              : src_frame.samplefmt(),\n                        dst_frame);\n                }\n            }\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class Callback,\n          std::enable_if_t<dlib::is_invocable<Callback, frame&>::value, bool>\n        >\n        inline auto wrap (\n            Callback&&              clb,\n            const resizing_args&    args_image,\n            const resampling_args&  args_audio\n        )\n        {\n            using namespace details;\n\n            return [=, pclb = std::forward<Callback>(clb)] (\n                frame&      f, \n                resizer&    resizer, \n                resampler&  resampler\n            ) mutable\n            {\n                convert(f, f, resizer, resampler, args_image, args_audio);\n                pclb(f);\n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class Callback,\n          std::enable_if_t<is_callable<Callback>::value, bool>,\n          std::enable_if_t<callable_nargs<Callback>::value == 1, bool>,\n          std::enable_if_t<is_image_type<std::remove_reference_t<callable_arg<0, Callback>>>::value, bool>\n        >\n        inline auto wrap (\n            Callback&& clb\n        )\n        {\n            using namespace details;\n            using image_type = std::remove_reference_t<callable_arg<0, Callback>>;\n\n            return [img = image_type{}, pclb = std::forward<Callback>(clb)] (\n                frame&      f, \n                resizer&    resizer, \n                resampler&  resampler\n            ) mutable\n            {\n                if (f.is_image())\n                {\n                    convert (\n                        f, f,\n                        resizer,\n                        resampler,\n                        {0,0,pix_traits<pixel_type_t<image_type>>::fmt},\n                        {}\n                    );\n\n                    convert(f, img);\n                    pclb(img);\n                } \n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline auto wrap (\n            std::queue<frame>& queue,\n            const resizing_args& args_image,\n            const resampling_args& args_audio\n        )\n        {\n            using namespace details;\n\n            return [&queue, args_image, args_audio] (\n                frame&      f, \n                resizer&    resizer, \n                resampler&  resampler\n            ) mutable\n            {\n                convert(f, f, resizer, resampler, args_image, args_audio);\n                queue.push(std::move(f));\n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class image_type>\n        inline auto wrap (\n            std::queue<image_type>& queue\n        )\n        {\n            using namespace details;\n\n            return [&queue] (\n                frame&      f, \n                resizer&    resizer, \n                resampler&  resampler\n            ) mutable\n            {\n                if (f.is_image())\n                {\n                    convert (\n                        f, f,\n                        resizer,\n                        resampler,\n                        {0,0,pix_traits<pixel_type_t<image_type>>::fmt},\n                        {}\n                    );\n\n                    image_type img;\n                    convert(f, img);\n                    queue.push(std::move(img));\n                } \n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline decoder::decoder(const args &a)\n        {\n            using namespace details;\n\n            DLIB_ASSERT(a.codec != AV_CODEC_ID_NONE || a.codec_name != \"\", \"At least args_codec.codec or args_codec.codec_name must be set\");\n            \n            register_ffmpeg();\n            \n            const AVCodec* pCodec = nullptr;\n\n            if (a.codec != AV_CODEC_ID_NONE)\n                pCodec = avcodec_find_decoder(a.codec);\n            else if (!a.codec_name.empty())\n                pCodec = avcodec_find_decoder_by_name(a.codec_name.c_str());\n\n            if (!pCodec)\n            {\n                logger_dlib_wrapper() << LERROR \n                    << \"Codec \"\n                    << avcodec_get_name(a.codec)\n                    << \" / \"\n                    << a.codec_name\n                    << \" not found.\";\n                return;\n            }\n\n            av_ptr<AVCodecContext> pCodecCtx_{avcodec_alloc_context3(pCodec)};\n\n            if (!pCodecCtx_)\n            {\n                logger_dlib_wrapper() << LERROR << \"avcodec_alloc_context3() failed to allocate codec context for \" << pCodec->name;\n                return;\n            }\n\n            if (pCodecCtx_->codec_id == AV_CODEC_ID_AAC)\n                pCodecCtx_->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;\n\n\n            timebase = pCodecCtx_->time_base;\n\n            if (!open(a, std::move(pCodecCtx_), pCodec,  timebase))\n                return;\n\n            // It's very likely ALL the PCM codecs don't require a parser\n            const bool no_parser_required = pCodec->id == AV_CODEC_ID_PCM_S16LE ||\n                                            pCodec->id == AV_CODEC_ID_PCM_U8;\n\n            if (!no_parser_required)\n            {\n                parser.reset(av_parser_init(pCodec->id));\n                if (!parser)\n                {\n                    logger_dlib_wrapper() << LERROR << \"av_parser_init() failed codec \" << pCodec->name << \" not found\";\n                    pCodecCtx = nullptr;\n                    return;\n                }\n            }\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline bool decoder::open (\n            const args&                     a,\n            details::av_ptr<AVCodecContext> pCodecCtx_,\n            const AVCodec*                  codec,\n            AVRational                      timebase_\n        )\n        {\n            using namespace details;\n\n            args_       = a;\n            timebase    = timebase_;\n            packet      = make_avpacket();\n\n            if (args_.bitrate > 0)\n                pCodecCtx_->bit_rate = args_.bitrate;\n            if (args_.flags > 0)\n                pCodecCtx_->flags |= args_.flags;\n            if (args_.thread_count > 0)\n                pCodecCtx_->thread_count = args_.thread_count;\n\n            av_dict opt = args_.codec_options;\n            int ret = avcodec_open2(pCodecCtx_.get(), codec, opt.get());\n\n            if (ret < 0)\n                return fail(\"avcodec_open2() failed : \", get_av_error(ret));\n            \n            pCodecCtx = std::move(pCodecCtx_);\n            open_ = true;\n            return true;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        enum extract_state\n        {\n            EXTRACT_SEND_PACKET,\n            EXTRACT_READ_FRAME_THEN_DONE,\n            EXTRACT_READ_FRAME_THEN_SEND_PACKET,\n            EXTRACT_DONE,\n            EXTRACT_ERROR = -1\n        };\n\n        template<class Callback>\n        inline bool decoder::push (\n            const details::av_ptr<AVPacket>& pkt,\n            Callback&& clb\n        )\n        {\n            using namespace details;\n            using std::chrono::duration_cast;\n            using std::chrono::system_clock;\n            using std::chrono::nanoseconds;\n\n            const auto send_packet = [&](extract_state& state)\n            {\n                const int ret = avcodec_send_packet(pCodecCtx.get(), pkt.get());\n\n                if (ret >= 0) {\n                    state   = EXTRACT_READ_FRAME_THEN_DONE;\n                } else if (ret == AVERROR(EAGAIN)) {\n                    state   = EXTRACT_READ_FRAME_THEN_SEND_PACKET;\n                } else if (ret == AVERROR_EOF) {\n                    open_ = false;\n                    state = EXTRACT_DONE;\n                } else {\n                    open_ = false;\n                    state = EXTRACT_ERROR;\n                    logger_dlib_wrapper() << LERROR << \"avcodec_send_packet() failed : \" << get_av_error(ret);\n                }\n            };\n\n            const auto recv_frame = [&](extract_state& state, bool resend)\n            {\n                if (!avframe.f)\n                    avframe.f = make_avframe();\n                const int ret = avcodec_receive_frame(pCodecCtx.get(), avframe.f.get());\n\n                if (ret == AVERROR(EAGAIN) && resend)\n                    state   = EXTRACT_SEND_PACKET;\n                else if (ret == AVERROR(EAGAIN))\n                    state   = EXTRACT_DONE;\n                else if (ret == AVERROR_EOF) {\n                    open_ = false;\n                    state = EXTRACT_DONE;\n                }\n                else if (ret < 0)\n                {\n                    open_ = false;\n                    state = EXTRACT_ERROR;\n                    logger_dlib_wrapper() << LERROR << \"avcodec_receive_frame() failed : \" << get_av_error(ret);\n                }\n                else\n                {\n                    const AVRational tb         = avframe.is_image() ? timebase : AVRational{1, avframe.sample_rate()};\n                    const uint64_t pts          = avframe.is_image() ? avframe.f->pts : next_pts;\n                    avframe.timestamp           = system_clock::time_point{duration_cast<system_clock::duration>(nanoseconds{av_rescale_q(pts, tb, {1,1000000000})})};\n                    next_pts                    += avframe.is_image() ? 1 : avframe.f->nb_samples;\n                    avframe.f->pict_type = AV_PICTURE_TYPE_NONE;\n                    std::forward<Callback>(clb)(avframe, resizer_image, resizer_audio);\n                }\n            };\n\n            extract_state state = pCodecCtx ? EXTRACT_SEND_PACKET : EXTRACT_ERROR;\n\n            while (state != EXTRACT_ERROR && state != EXTRACT_DONE)\n            {\n                switch(state)\n                {\n                    case EXTRACT_SEND_PACKET:                   send_packet(state);         break;\n                    case EXTRACT_READ_FRAME_THEN_DONE:          recv_frame(state, false);   break;\n                    case EXTRACT_READ_FRAME_THEN_SEND_PACKET:   recv_frame(state, true);    break;\n                    default: break;\n                }\n            }\n\n            return state != EXTRACT_ERROR;\n        }\n\n        template <class Callback>\n        inline bool decoder::push_padded (\n            const uint8_t*  encoded, \n            int             nencoded,\n            Callback&&      clb\n        )\n        {\n            using namespace details;\n\n            if (!is_open())\n                return false;\n\n            const auto parse = [&]\n            {\n                if (parser)\n                {\n                    const int ret = av_parser_parse2(\n                        parser.get(),\n                        pCodecCtx.get(),\n                        &packet->data,\n                        &packet->size,\n                        encoded,\n                        nencoded,\n                        AV_NOPTS_VALUE,\n                        AV_NOPTS_VALUE,\n                        0\n                    );\n\n                    if (ret < 0)\n                        return fail(\"AV : error while parsing encoded buffer\");\n\n                    encoded  += ret;\n                    nencoded -= ret;\n                } else\n                {\n                    /*! Codec does not require parser !*/\n                    packet->data = const_cast<uint8_t *>(encoded);\n                    packet->size = nencoded;\n                    encoded      += nencoded;\n                    nencoded     = 0;\n                }\n\n                return true;\n            };\n\n            const bool flushing = encoded == nullptr && nencoded == 0;\n            bool ok = true;\n\n            while (ok && (nencoded > 0 || flushing))\n            {\n                // Parse data OR flush parser\n                ok = parse();\n\n                // If data is available, decode\n                if (ok && packet->size > 0)\n                    ok = push(packet, std::forward<Callback>(clb));\n                \n                // If flushing, you keep parsing until you get an empty packet\n                if (packet->size == 0 && flushing)\n                    break;\n            }\n\n            if (flushing)\n            {\n                // Flush codec. After this, pCodecCtx == nullptr since AVERROR_EOF will be returned at some point.\n                ok = push(nullptr, std::forward<Callback>(clb));\n            }\n        \n            return ok;\n        }\n\n        template <class Callback>\n        inline bool decoder::push (\n            const uint8_t*  encoded, \n            int             nencoded,\n            Callback&&      clb\n        )\n        {\n            DLIB_ASSERT(!decoding, \"Recursion in push() no supported\");\n            decoding = true;\n\n            bool ok = true;\n\n            if (encoded == nullptr && nencoded == 0)\n            {\n                ok = push_padded(nullptr, 0, std::forward<Callback>(clb));\n            }\n            else\n            {\n                if (nencoded > AV_INPUT_BUFFER_PADDING_SIZE)\n                {\n                    const int blocksize = nencoded - AV_INPUT_BUFFER_PADDING_SIZE;\n\n                    ok = push_padded(encoded, blocksize, std::forward<Callback>(clb));\n                    encoded  += blocksize;\n                    nencoded -= blocksize; // == AV_INPUT_BUFFER_PADDING_SIZE\n                }\n\n                if (ok)\n                {\n                    encoded_buffer.resize(nencoded + AV_INPUT_BUFFER_PADDING_SIZE);\n                    std::memcpy(encoded_buffer.data(), encoded, nencoded);\n                    ok = push_padded(encoded_buffer.data(), nencoded, std::forward<Callback>(clb));\n                }\n            }\n\n            decoding = false;\n            return ok;\n        }\n\n        template<class Callback>\n        inline void decoder::flush(Callback&& clb)\n        {\n            push(nullptr, 0, std::forward<Callback>(clb));\n        }\n\n        inline bool             decoder::is_open()          const noexcept { return pCodecCtx && open_; }\n        inline bool             decoder::is_image_decoder() const noexcept { return pCodecCtx && pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO; }\n        inline bool             decoder::is_audio_decoder() const noexcept { return pCodecCtx && pCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO; }\n        inline AVCodecID        decoder::get_codec_id()     const noexcept { return pCodecCtx ? pCodecCtx->codec_id : AV_CODEC_ID_NONE; }\n        inline std::string      decoder::get_codec_name()   const noexcept { return pCodecCtx ? avcodec_get_name(pCodecCtx->codec_id) : \"NONE\"; }\n        inline int              decoder::height()           const noexcept { return pCodecCtx ? pCodecCtx->height       : 0; }\n        inline int              decoder::width()            const noexcept { return pCodecCtx ? pCodecCtx->width        : 0; }\n        inline AVPixelFormat    decoder::pixel_fmt()        const noexcept { return pCodecCtx ? pCodecCtx->pix_fmt      : AV_PIX_FMT_NONE; }\n        inline int              decoder::sample_rate()      const noexcept { return pCodecCtx ? pCodecCtx->sample_rate  : 0; }\n        inline AVSampleFormat   decoder::sample_fmt()       const noexcept { return pCodecCtx ? pCodecCtx->sample_fmt   : AV_SAMPLE_FMT_NONE; }\n        inline uint64_t         decoder::channel_layout()   const noexcept { return details::get_layout(pCodecCtx.get()); }\n        inline int              decoder::nchannels()        const noexcept { return details::get_nchannels(channel_layout()); }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline demuxer::args::args(const std::string& filepath_)\n        : filepath{filepath_}\n        {\n        }\n\n        inline demuxer::args::args(\n            const std::string& filepath_, \n            video_enabled_t video_on, \n            audio_enabled_t audio_on\n        ) : filepath{filepath_},\n            enable_image{video_on.enabled},\n            enable_audio{audio_on.enabled}\n        {\n        }\n\n        inline demuxer::demuxer(const args &a)\n        {\n            if (!open(a))\n                st.pFormatCtx = nullptr;\n        }\n\n        inline demuxer::demuxer(demuxer &&other) noexcept\n        : st{std::move(other.st)}\n        {\n            if (st.pFormatCtx)\n                st.pFormatCtx->opaque = this;\n        }\n\n        inline demuxer& demuxer::operator=(demuxer &&other) noexcept\n        {\n            st = std::move(other.st);\n            if (st.pFormatCtx)\n                st.pFormatCtx->opaque = this;\n            return *this;\n        }\n\n        inline bool demuxer::open(const args& a)\n        {\n            using namespace details;\n            using std::chrono::system_clock;\n\n            details::register_ffmpeg();\n\n            st = {};\n            st.args_ = a;\n\n            AVFormatContext* pFormatCtx = avformat_alloc_context();\n            pFormatCtx->opaque = this;\n            pFormatCtx->interrupt_callback.opaque   = pFormatCtx;\n            pFormatCtx->interrupt_callback.callback = [](void* ctx) -> int {\n                AVFormatContext* pFormatCtx = (AVFormatContext*)ctx;\n                demuxer* me = (demuxer*)pFormatCtx->opaque;\n                return me->interrupt_callback();\n            };\n\n            if (st.args_.probesize > 0)\n                pFormatCtx->probesize = st.args_.probesize;\n\n            // Hacking begins. \n            if (st.args_.height > 0 && \n                st.args_.width > 0 && \n                st.args_.format_options.find(\"video_size\") == st.args_.format_options.end())\n            {\n                // See if format supports \"video_size\"\n                st.args_.format_options[\"video_size\"] = std::to_string(st.args_.width) + \"x\" + std::to_string(st.args_.height);\n            }\n\n            if (st.args_.framerate > 0 &&\n                st.args_.format_options.find(\"framerate\") == st.args_.format_options.end())\n            {\n                // See if format supports \"framerate\"\n                st.args_.format_options[\"framerate\"] = std::to_string(st.args_.framerate);\n            }\n\n#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 0, 100)\n            using AVInputputFormatPtr   = AVInputFormat*;\n            using AVCodecPtr            = AVCodec*;\n#else\n            using AVInputputFormatPtr   = const AVInputFormat*;\n            using AVCodecPtr            = const AVCodec*;\n#endif\n\n            av_dict opts = st.args_.format_options;\n            AVInputputFormatPtr input_format = st.args_.input_format.empty() ? nullptr : av_find_input_format(st.args_.input_format.c_str());\n\n            st.connecting_time = system_clock::now();\n            st.connected_time  = system_clock::time_point::max();\n\n            int ret = avformat_open_input(&pFormatCtx,\n                                        st.args_.filepath.c_str(),\n                                        input_format,\n                                        opts.get());\n\n            if (ret != 0)\n                return fail(\"avformat_open_input() failed with error : \", get_av_error(ret));\n\n            if (opts.size() > 0)\n            {\n                printf(\"demuxer::args::format_options ignored:\\n\");\n                opts.print();\n            }\n\n            st.connected_time = system_clock::now();\n            st.pFormatCtx.reset(std::exchange(pFormatCtx, nullptr));\n\n            ret = avformat_find_stream_info(st.pFormatCtx.get(), NULL);\n\n            if (ret < 0)\n                return fail(\"avformat_find_stream_info() failed with error : \", get_av_error(ret));\n\n            const auto setup_stream = [&](bool is_video)\n            {\n                const AVMediaType media_type = is_video ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO;\n\n                AVCodecPtr pCodec = nullptr;\n                const int stream_id = av_find_best_stream(st.pFormatCtx.get(), media_type, -1, -1, &pCodec, 0);\n\n                if (stream_id == AVERROR_STREAM_NOT_FOUND)\n                    return true; //You might be asking for both video and audio but only video is available. That's OK. Just provide video.\n\n                else if (stream_id == AVERROR_DECODER_NOT_FOUND)\n                    return fail(\"av_find_best_stream() : decoder not found for stream type : \", av_get_media_type_string(media_type));\n\n                else if (stream_id < 0)\n                    return fail(\"av_find_best_stream() failed : \", get_av_error(stream_id));\n\n                av_ptr<AVCodecContext> pCodecCtx{avcodec_alloc_context3(pCodec)};\n\n                if (!pCodecCtx)\n                    return fail(\"avcodec_alloc_context3() failed to allocate codec context for \", pCodec->name);\n\n                const int ret = avcodec_parameters_to_context(pCodecCtx.get(), st.pFormatCtx->streams[stream_id]->codecpar);\n                if (ret < 0)\n                    return fail(\"avcodec_parameters_to_context() failed : \", get_av_error(ret));\n\n                if (pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO)\n                {\n                    if (pCodecCtx->height   == 0 ||\n                        pCodecCtx->width    == 0 ||\n                        pCodecCtx->pix_fmt  == AV_PIX_FMT_NONE)\n                        return fail(\"Codec parameters look wrong : (h,w,pixel_fmt) : (\",\n                                pCodecCtx->height, \",\",\n                                pCodecCtx->width,  \",\",\n                                get_pixel_fmt_str(pCodecCtx->pix_fmt), \")\");\n                }\n                else if (pCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO)\n                {\n                    check_layout(pCodecCtx.get());\n\n                    if (pCodecCtx->sample_rate == 0 ||\n                        pCodecCtx->sample_fmt  == AV_SAMPLE_FMT_NONE ||\n                        channel_layout_empty(pCodecCtx.get()))\n                        return fail(\"Codec parameters look wrong :\",\n                            \" sample_rate : \", pCodecCtx->sample_rate,\n                            \" sample format : \", get_audio_fmt_str(pCodecCtx->sample_fmt),\n                            \" channel layout : \", get_channel_layout_str(pCodecCtx.get()));\n                }\n                else\n                    return fail(\"Unrecognized media type \", pCodecCtx->codec_type);\n\n                if (is_video)\n                {\n                    st.channel_video.open(\n                        st.args_.args_codec_image,\n                        std::move(pCodecCtx), \n                        pCodec,\n                        st.pFormatCtx->streams[stream_id]->time_base\n                    );\n\n                    st.stream_id_video = stream_id;\n                }\n                else\n                {\n                    st.channel_audio.open(\n                        st.args_.args_codec_audio,\n                        std::move(pCodecCtx), \n                        pCodec,\n                        st.pFormatCtx->streams[stream_id]->time_base\n                    );\n\n                    st.stream_id_audio = stream_id;\n                }\n\n                return true;\n            };\n\n            if (st.args_.enable_image && !setup_stream(true))\n                return false;\n\n            if (st.args_.enable_audio && !setup_stream(false))\n                return false;\n\n            if (!st.channel_audio.is_open() && !st.channel_video.is_open())\n                return fail(\"At least one of video and audio channels must be enabled\");\n\n            populate_metadata();\n\n            st.packet = make_avpacket();\n            return true;\n        }\n\n        inline bool demuxer::object_alive() const noexcept\n        {\n            return st.pFormatCtx != nullptr && (st.channel_video.is_open() || st.channel_audio.is_open());\n        }\n\n        inline bool demuxer::is_open() const noexcept\n        {\n            return object_alive() || !st.frame_queue.empty();\n        }\n\n        inline bool demuxer::interrupt_callback()\n        {\n            const auto now = std::chrono::system_clock::now();\n\n            if (st.args_.connect_timeout < std::chrono::milliseconds::max() && // check there is a timeout\n                now < st.connected_time &&                                     // we haven't already connected\n                now > (st.connecting_time + st.args_.connect_timeout)          // we've timed-out\n            )\n                return true;\n\n            if (st.args_.read_timeout < std::chrono::milliseconds::max() &&   // check there is a timeout\n                now > (st.last_read_time + st.args_.read_timeout)             // we've timed-out\n            )\n                return true;\n\n            if (st.args_.interrupter && st.args_.interrupter())               // check user-specified callback\n                return true;\n\n            return false;\n        }\n\n        inline void demuxer::populate_metadata()\n        {\n            AVDictionaryEntry *tag = nullptr;\n            while ((tag = av_dict_get(st.pFormatCtx->metadata, \"\", tag, AV_DICT_IGNORE_SUFFIX)))\n                st.metadata.emplace(tag->key, tag->value);\n            \n            tag = nullptr;\n            for (unsigned int i = 0; i < st.pFormatCtx->nb_streams; i++)\n                while ((tag = av_dict_get(st.pFormatCtx->streams[i]->metadata, \"\", tag, AV_DICT_IGNORE_SUFFIX)))\n                    st.metadata.emplace(std::string(\"stream_\") + std::to_string(i) + \"_\" + std::string(tag->key), tag->value);\n        }\n\n        inline bool demuxer::fill_queue()\n        {\n            using namespace details;\n\n            if (!st.frame_queue.empty())\n                return true;\n\n            decoder* channel{nullptr};\n\n            const auto parse = [&]\n            {\n                channel = nullptr;\n                av_packet_unref(st.packet.get());\n\n                const int ret = av_read_frame(st.pFormatCtx.get(), st.packet.get());\n\n                if (ret == AVERROR_EOF)\n                    return false;\n   \n                else if (ret < 0)\n                    return fail(\"av_read_frame() failed : \", get_av_error(ret));\n \n                if (st.packet->stream_index == st.stream_id_video)\n                    channel = &st.channel_video;\n\n                else if (st.packet->stream_index == st.stream_id_audio)\n                    channel = &st.channel_audio;\n\n                return true;\n            };\n\n            bool ok{true};\n\n            while (object_alive() && st.frame_queue.empty() && ok)\n            {\n                ok = parse();\n\n                if (ok && channel && st.packet->size > 0)\n                {\n                    // Decode\n                    ok = channel->push(st.packet, wrap(st.frame_queue));\n                }\n            }\n\n            if (!ok)\n            {\n                // Flush\n                st.channel_video.push(nullptr, wrap(st.frame_queue));\n                st.channel_audio.push(nullptr, wrap(st.frame_queue));\n            }\n\n            return !st.frame_queue.empty();\n        }\n\n        inline bool demuxer::read (\n            frame&                  dst_frame,\n            const resizing_args&    args_image, \n            const resampling_args&  args_audio\n        )\n        {\n            using namespace details;\n\n            if (!fill_queue())\n                return false;\n\n            dst_frame = std::move(st.frame_queue.front());\n            st.frame_queue.pop();\n\n            convert (\n                dst_frame,\n                dst_frame,\n                st.channel_video.resizer_image,\n                st.channel_audio.resizer_audio,\n                args_image,\n                args_audio\n            );\n\n            return true;\n        }\n\n        template <\n          class image_type,\n          is_image_check<image_type>\n        >\n        inline bool demuxer::read (\n            image_type& img\n        )\n        {\n            using namespace details;\n\n            while (fill_queue())\n            {\n                frame f = std::move(st.frame_queue.front());\n                st.frame_queue.pop();\n\n                if (f.is_image())\n                {\n                    convert (\n                        f,\n                        f,\n                        st.channel_video.resizer_image,\n                        st.channel_audio.resizer_audio,\n                        {img.nr() > 0 ? (int)img.nr() : f.height(),\n                         img.nc() > 0 ? (int)img.nc() : f.width(),\n                         pix_traits<pixel_type_t<image_type>>::fmt},\n                        {}\n                    );\n\n                    convert(f, img);\n                    \n                    return true;\n                } \n            }\n\n            return false;\n        }\n\n        inline bool            demuxer::video_enabled()         const noexcept { return st.channel_video.is_image_decoder(); }\n        inline bool            demuxer::audio_enabled()         const noexcept { return st.channel_audio.is_audio_decoder(); }\n        inline int             demuxer::height()                const noexcept { return st.channel_video.height(); }\n        inline int             demuxer::width()                 const noexcept { return st.channel_video.width(); }\n        inline AVPixelFormat   demuxer::pixel_fmt()             const noexcept { return st.channel_video.pixel_fmt(); }\n        inline AVCodecID       demuxer::get_video_codec_id()    const noexcept { return st.channel_video.get_codec_id(); }\n        inline std::string     demuxer::get_video_codec_name()  const noexcept { return st.channel_video.get_codec_name(); }\n\n        inline int             demuxer::sample_rate()           const noexcept { return st.channel_audio.sample_rate(); }\n        inline uint64_t        demuxer::channel_layout()        const noexcept { return st.channel_audio.channel_layout(); }\n        inline AVSampleFormat  demuxer::sample_fmt()            const noexcept { return st.channel_audio.sample_fmt(); }\n        inline int             demuxer::nchannels()             const noexcept { return st.channel_audio.nchannels(); }\n        inline AVCodecID       demuxer::get_audio_codec_id()    const noexcept { return st.channel_audio.get_codec_id(); }\n        inline std::string     demuxer::get_audio_codec_name()  const noexcept { return st.channel_audio.get_codec_name(); }\n\n        inline float demuxer::fps() const noexcept\n        {\n            /*!\n                Do we need to adjust _pFormatCtx->fps_probe_size ?\n                Do we need to adjust _pFormatCtx->max_analyze_duration ?\n            !*/\n            if (st.channel_video.is_image_decoder() && st.pFormatCtx)\n            {\n                const float num = st.pFormatCtx->streams[st.stream_id_video]->avg_frame_rate.num;\n                const float den = st.pFormatCtx->streams[st.stream_id_video]->avg_frame_rate.den;\n                return num / den;\n            }\n\n            return 0.0f;\n        }\n\n        inline int demuxer::estimated_nframes() const noexcept\n        {\n            return st.channel_video.is_image_decoder() ? st.pFormatCtx->streams[st.stream_id_video]->nb_frames : 0;\n        }\n\n        inline int demuxer::estimated_total_samples() const noexcept\n        {\n            if (st.channel_audio.is_audio_decoder())\n            {\n                const AVRational src_time_base = st.pFormatCtx->streams[st.stream_id_audio]->time_base;\n                const AVRational dst_time_base = {1, sample_rate()};\n                return av_rescale_q(st.pFormatCtx->streams[st.stream_id_audio]->duration, src_time_base, dst_time_base);\n            }\n            return 0;\n        }\n\n        inline float demuxer::duration() const noexcept\n        {\n            return st.pFormatCtx ? (float)av_rescale_q(st.pFormatCtx->duration, {1, AV_TIME_BASE}, {1, 1000000}) * 1e-6 : 0.0f;\n        }\n\n        inline const std::unordered_map<std::string, std::string>& demuxer::get_metadata() const noexcept\n        {\n            return st.metadata;\n        }\n\n        inline float demuxer::get_rotation_angle() const noexcept\n        {\n            const auto it = st.metadata.find(\"rotate\");\n            return it != st.metadata.end() ? std::stof(it->second) : 0;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type,\n          is_image_check<image_type>\n        >\n        inline void load_frame(image_type& image, const std::string& file_name)\n        {\n            if (!demuxer({file_name, video_enabled, audio_disabled}).read(image))\n                throw error(EIMAGE_LOAD, \"ffmpeg::load_frame: error while loading \" + file_name);\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif //DLIB_FFMPEG_DEMUXER\n"
  },
  {
    "path": "dlib/media/ffmpeg_details.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n/*\n    PRIVATE IMPLEMENTATION DETAILS\n    USERS, YOU DO NOT NEED TO READ THIS\n*/\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n/*\n    Notes for developers:\n\n    The file structure for all things ffmpeg is as follows:\n\n        - ffmpeg_details.h  : contains implementations details only and everything must be in the\n                              dlib::ffmpeg::details namespace\n        \n        - ffmpeg_utils.h    : contains common public API. Definitions go at the bottom of the file\n                              underneath a block comment saying \"DEFINITIONS\"\n                              Also contains implementation details that depend on the public API.\n                              This must still go in the dlib::ffmpeg::details namespace\n        \n        - ffmpeg_demuxer.h  : contains public API for all things decoding. Similarly, definitions go \n                              at the bottom of the file underneath a block comment saying \"DEFINITIONS\".\n\n        - ffmpeg_muxer.h  :   contains public API for all things encoding. Similarly, definitions go \n                              at the bottom of the file underneath a block comment saying \"DEFINITIONS\".\n                            \n*/\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#ifndef DLIB_FFMPEG_DETAILS\n#define DLIB_FFMPEG_DETAILS\n\n#include \"../test_for_odr_violations.h\"\n\n#ifndef DLIB_USE_FFMPEG\nstatic_assert(false, \"This version of dlib isn't built with the FFMPEG wrappers\");\n#endif\n\nextern \"C\" {\n#include <libavutil/dict.h>\n#include <libavutil/opt.h>\n#include <libavutil/pixdesc.h>\n#include <libavutil/frame.h>\n#include <libavutil/channel_layout.h>\n#include <libavutil/audio_fifo.h>\n#include <libavutil/imgutils.h>\n#include <libavutil/log.h>\n#include <libswscale/swscale.h>\n#include <libswresample/swresample.h>\n#include <libavformat/avformat.h>\n#include <libavdevice/avdevice.h>\n#include <libavcodec/avcodec.h>\n}\n\n#include <string>\n#include <memory>\n#include \"../logger.h\"\n\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)\n#define FFMPEG_HAS_CH_LAYOUT 1\n#endif\n\nnamespace dlib { namespace ffmpeg { namespace details\n{\n\n// ---------------------------------------------------------------------------------------------------\n\n    inline dlib::logger& logger_ffmpeg_private()\n    {\n        static dlib::logger GLOBAL(\"ffmpeg.internal\");\n        return GLOBAL;\n    }\n// ---------------------------------------------------------------------------------------------------\n\n    inline void register_ffmpeg()\n    {\n        static const bool REGISTERED = []\n        {\n            avdevice_register_all();\n#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)\n            // See https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L91\n            avcodec_register_all();\n#endif\n#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) \n            // See https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L86\n            av_register_all();\n#endif\n\n            av_log_set_callback([](void* ptr, int level, const char *fmt, va_list vl) \n            {\n                auto& logger = logger_ffmpeg_private();\n\n                char line[256] = {0};\n                static int print_prefix = 1;\n\n                // Not sure if copying to vl2 is required by internal ffmpeg functions do this...\n                va_list vl2;\n                va_copy(vl2, vl);\n                int size = av_log_format_line2(ptr, level, fmt, vl2, &line[0], sizeof(line), &print_prefix);\n                va_end(vl2);\n\n                // Remove all '\\n' since dlib's logger already adds one\n                size = std::min<int>(size, sizeof(line) - 1);\n                line[size] = '\\0';\n                for (int i = size - 1 ; i >= 0 ; --i)\n                    if (line[i] == '\\n')\n                        line[i] = ' ';\n\n                switch(level)\n                {\n                    case AV_LOG_PANIC:\n                    case AV_LOG_FATAL:      logger << LFATAL << line; break;\n                    case AV_LOG_ERROR:      logger << LERROR << line; break;\n                    case AV_LOG_WARNING:    logger << LWARN  << line; break;\n                    case AV_LOG_INFO:       \n                    case AV_LOG_VERBOSE:    logger << LINFO  << line; break;\n                    case AV_LOG_DEBUG:      logger << LDEBUG << line; break;\n                    case AV_LOG_TRACE:      logger << LTRACE << line; break;\n                    default: break;\n                }\n            });\n\n            return true;\n        }();\n        (void)REGISTERED;\n    }        \n\n// ---------------------------------------------------------------------------------------------------\n\n    inline std::string get_av_error(int ret)\n    {\n        char buf[128] = {0};\n        int suc = av_strerror(ret, buf, sizeof(buf));\n        return suc == 0 ? buf : \"couldn't set error\";\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    ///////////////////////////\n    // Channel layout stuff \n    ///////////////////////////\n\n    inline uint64_t get_layout_from_channels(const std::size_t nchannels)\n    {\n        // This function is a bit ambiguous but good enough for dlib.\n        // Multiple layouts can have the same number of channels\n        switch(nchannels)\n        {\n            case 1: return AV_CH_LAYOUT_MONO;\n            case 2: return AV_CH_LAYOUT_STEREO;\n            default: DLIB_CASSERT(false, \"Don't support \" << nchannels << \" yet\"); return 0;\n        }\n    }\n\n#if FFMPEG_HAS_CH_LAYOUT\n\n    inline AVChannelLayout convert_layout(const uint64_t channel_layout)\n    {\n        AVChannelLayout ch_layout;\n        ch_layout.order         = AV_CHANNEL_ORDER_NATIVE;\n        ch_layout.u.mask        = channel_layout;\n        ch_layout.nb_channels   = [=] \n        {\n            switch(channel_layout)\n            {\n                case AV_CH_LAYOUT_MONO:                 return 1;\n                case AV_CH_LAYOUT_STEREO:               return 2;\n                case AV_CH_LAYOUT_2POINT1:              return 3;\n                case AV_CH_LAYOUT_2_1:                  return 3;\n                case AV_CH_LAYOUT_SURROUND:             return 3;\n                case AV_CH_LAYOUT_3POINT1:              return 4;\n                case AV_CH_LAYOUT_4POINT0:              return 4;\n                case AV_CH_LAYOUT_4POINT1:              return 5;\n                case AV_CH_LAYOUT_2_2:                  return 4;\n                case AV_CH_LAYOUT_QUAD:                 return 4;\n                case AV_CH_LAYOUT_5POINT0:              return 5;\n                case AV_CH_LAYOUT_5POINT1:              return 6;\n                case AV_CH_LAYOUT_5POINT0_BACK:         return 5;\n                case AV_CH_LAYOUT_5POINT1_BACK:         return 6;\n                case AV_CH_LAYOUT_6POINT0:              return 6;\n                case AV_CH_LAYOUT_6POINT0_FRONT:        return 6;\n                case AV_CH_LAYOUT_HEXAGONAL:            return 6;\n                case AV_CH_LAYOUT_6POINT1:              return 7;\n                case AV_CH_LAYOUT_6POINT1_BACK:         return 7;\n                case AV_CH_LAYOUT_6POINT1_FRONT:        return 7;\n                case AV_CH_LAYOUT_7POINT0:              return 7;\n                case AV_CH_LAYOUT_7POINT0_FRONT:        return 7;\n                case AV_CH_LAYOUT_7POINT1:              return 8;\n                case AV_CH_LAYOUT_7POINT1_WIDE:         return 8;\n                case AV_CH_LAYOUT_7POINT1_WIDE_BACK:    return 8;\n                case AV_CH_LAYOUT_OCTAGONAL:            return 8;\n                case AV_CH_LAYOUT_HEXADECAGONAL:        return 16;\n                case AV_CH_LAYOUT_STEREO_DOWNMIX:       return 2;\n#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 58, 100)\n                case AV_CH_LAYOUT_22POINT2:             return 24;\n#endif\n                default: break;\n            }\n            return 0;\n        }();\n\n        return ch_layout;\n    }\n\n    inline std::string get_channel_layout_str(const AVChannelLayout& ch_layout)\n    {\n        std::string str(32, '\\0');\n        const int ret = av_channel_layout_describe(&ch_layout, &str[0], str.size());\n        if (ret > 0)\n            str.resize(ret);\n        else\n            str.clear();\n        return str;\n    }\n\n    inline std::string get_channel_layout_str(uint64_t channel_layout)\n    {\n        return get_channel_layout_str(convert_layout(channel_layout));\n    }\n\n    inline std::string get_channel_layout_str(const AVCodecContext* pCodecCtx)\n    {\n        return get_channel_layout_str(pCodecCtx->ch_layout);\n    }\n\n    inline bool channel_layout_empty(const AVCodecContext* pCodecCtx)\n    {\n        return av_channel_layout_check(&pCodecCtx->ch_layout) == 0;\n    }\n\n    inline bool channel_layout_empty(const AVFrame* frame)\n    {\n        return frame && av_channel_layout_check(&frame->ch_layout) == 0;\n    }\n\n    inline uint64_t get_layout(const AVCodecContext* pCodecCtx)\n    {\n        return pCodecCtx ? pCodecCtx->ch_layout.u.mask : 0;\n    }\n\n    inline uint64_t get_layout(const AVFrame* frame)\n    {\n        return frame ? frame->ch_layout.u.mask : 0;\n    }\n\n    inline void set_layout(AVCodecContext* pCodecCtx, const uint64_t channel_layout)\n    {\n        pCodecCtx->ch_layout = convert_layout(channel_layout);\n    }\n\n    inline void set_layout(AVFrame* frame, const uint64_t channel_layout)\n    {\n        frame->ch_layout = convert_layout(channel_layout);\n    }\n\n    inline int get_nchannels(const AVCodecContext* pCodecCtx)\n    {\n        return pCodecCtx ? pCodecCtx->ch_layout.nb_channels : 0;\n    }\n\n    inline int get_nchannels(const AVFrame* frame)\n    {\n        return frame ? frame->ch_layout.nb_channels : 0;\n    }\n\n    inline int get_nchannels(const uint64_t channel_layout)\n    {\n        return convert_layout(channel_layout).nb_channels;\n    }\n\n    inline void check_layout(AVCodecContext* pCodecCtx)\n    {\n        if (get_layout(pCodecCtx) == 0 && pCodecCtx->ch_layout.nb_channels > 0)\n            av_channel_layout_default(&pCodecCtx->ch_layout, pCodecCtx->ch_layout.nb_channels);\n    }\n\n#else\n\n    inline std::string get_channel_layout_str(uint64_t channel_layout)\n    {\n        std::string str(32, '\\0');\n        av_get_channel_layout_string(&str[0], str.size(), 0, channel_layout);\n        str.resize(strlen(str.data()));\n        return str;\n    }\n\n    inline std::string get_channel_layout_str(const AVCodecContext* pCodecCtx)\n    {\n        return get_channel_layout_str(pCodecCtx->channel_layout);\n    }\n\n    inline bool channel_layout_empty(const AVCodecContext* pCodecCtx)\n    {\n        return pCodecCtx->channel_layout == 0;\n    }\n\n    inline bool channel_layout_empty(const AVFrame* frame)\n    {\n        return frame->channel_layout == 0;\n    }\n\n    inline uint64_t get_layout(const AVCodecContext* pCodecCtx)\n    {\n        return pCodecCtx ? pCodecCtx->channel_layout : 0;\n    }\n\n    inline uint64_t get_layout(const AVFrame* frame)\n    {\n        return frame ? frame->channel_layout : 0;\n    }\n\n    inline void set_layout(AVCodecContext* pCodecCtx, const uint64_t channel_layout)\n    {\n        pCodecCtx->channel_layout = channel_layout;\n    }\n\n    inline void set_layout(AVFrame* frame, const uint64_t channel_layout)\n    {\n        frame->channel_layout = channel_layout;\n    }\n\n    inline int get_nchannels(const uint64_t channel_layout)\n    {\n        return av_get_channel_layout_nb_channels(channel_layout);\n    }\n\n    inline int get_nchannels(const AVCodecContext* pCodecCtx)\n    {\n        return pCodecCtx ? get_nchannels(pCodecCtx->channel_layout) : 0;\n    }\n\n    inline int get_nchannels(const AVFrame* frame)\n    {\n        return frame ? get_nchannels(frame->channel_layout) : 0;\n    }    \n\n    inline void check_layout(AVCodecContext* pCodecCtx) \n    {\n        if (pCodecCtx->channel_layout == 0 && pCodecCtx->channels > 0)\n            pCodecCtx->channel_layout = av_get_default_channel_layout(pCodecCtx->channels);\n    }       \n#endif\n\n// ---------------------------------------------------------------------------------------------------\n\n    struct av_deleter\n    {\n        void operator()(AVFrame* ptr)               const;\n        void operator()(AVPacket* ptr)              const;\n        void operator()(AVAudioFifo* ptr)           const;\n        void operator()(SwsContext* ptr)            const;\n        void operator()(SwrContext* ptr)            const;\n        void operator()(AVCodecContext* ptr)        const;\n        void operator()(AVCodecParserContext* ptr)  const;\n        void operator()(AVFormatContext* ptr)       const;\n        void operator()(AVDeviceInfoList* ptr)      const;\n    };\n\n    inline void av_deleter::operator()(AVFrame *ptr)               const { if (ptr) av_frame_free(&ptr); }\n    inline void av_deleter::operator()(AVPacket *ptr)              const { if (ptr) av_packet_free(&ptr); }\n    inline void av_deleter::operator()(AVAudioFifo *ptr)           const { if (ptr) av_audio_fifo_free(ptr); }\n    inline void av_deleter::operator()(SwsContext *ptr)            const { if (ptr) sws_freeContext(ptr); }\n    inline void av_deleter::operator()(SwrContext *ptr)            const { if (ptr) swr_free(&ptr); }\n    inline void av_deleter::operator()(AVCodecContext *ptr)        const { if (ptr) avcodec_free_context(&ptr); }\n    inline void av_deleter::operator()(AVCodecParserContext *ptr)  const { if (ptr) av_parser_close(ptr); }\n    inline void av_deleter::operator()(AVDeviceInfoList* ptr)      const { if (ptr) avdevice_free_list_devices(&ptr); }\n    inline void av_deleter::operator()(AVFormatContext *ptr)       const \n    { \n        if (ptr) \n        {\n            if (ptr->iformat)\n                avformat_close_input(&ptr); \n            else if (ptr->oformat)\n                avformat_free_context(ptr);\n        }\n    }\n\n    template<class AVObject>\n    using av_ptr = std::unique_ptr<AVObject, details::av_deleter>;\n\n\n// ---------------------------------------------------------------------------------------------------\n\n    inline av_ptr<AVFrame> make_avframe()\n    {\n        av_ptr<AVFrame> obj(av_frame_alloc());\n        if (!obj)\n            throw std::runtime_error(\"Failed to allocate AVframe\");\n        return obj;\n    }\n\n    inline av_ptr<AVPacket> make_avpacket()\n    {\n        av_ptr<AVPacket> obj(av_packet_alloc());\n        if (!obj)\n            throw std::runtime_error(\"Failed to allocate AVPacket\");\n        return obj;\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    struct av_dict\n    {\n        av_dict() = default;\n        av_dict(const std::unordered_map<std::string, std::string> &options);\n        av_dict(const av_dict &ori);\n        av_dict &operator=(const av_dict &ori);\n        av_dict(av_dict &&ori) noexcept;\n        av_dict &operator=(av_dict &&ori) noexcept;\n        ~av_dict();\n        size_t size() const;\n        void print() const;\n        AVDictionary** get();\n\n        AVDictionary *avdic = nullptr;\n    };\n\n    inline av_dict::av_dict(const std::unordered_map<std::string, std::string>& options)\n    {\n        int ret = 0;\n\n        for (const auto& opt : options) {\n            if ((ret = av_dict_set(&avdic, opt.first.c_str(), opt.second.c_str(), 0)) < 0) {\n                printf(\"av_dict_set() failed : %s\\n\", get_av_error(ret).c_str());\n                break;\n            }\n        }\n    }\n\n    inline av_dict::av_dict(const av_dict& ori)\n    {\n        av_dict_copy(&avdic, ori.avdic, 0);\n    }\n\n    inline av_dict& av_dict::operator=(const av_dict& ori)\n    {\n        *this = std::move(av_dict{ori});\n        return *this;\n    }\n\n    inline av_dict::av_dict(av_dict &&ori) noexcept\n    : avdic{std::exchange(ori.avdic, nullptr)}\n    {\n    }\n\n    inline av_dict &av_dict::operator=(av_dict &&ori) noexcept\n    {\n        if (this != &ori)\n            avdic = std::exchange(ori.avdic, nullptr);\n        return *this;\n    }\n\n    inline av_dict::~av_dict()\n    {\n        if (avdic)\n            av_dict_free(&avdic);\n    }\n\n    inline AVDictionary** av_dict::get()\n    {\n        return avdic ? &avdic: nullptr;\n    }\n\n    inline std::size_t av_dict::size() const\n    {\n        return avdic ? av_dict_count(avdic) : 0;\n    }\n\n    inline void av_dict::print() const\n    {\n        if (avdic)\n        {\n            AVDictionaryEntry *tag = nullptr;\n            while ((tag = av_dict_get(avdic, \"\", tag, AV_DICT_IGNORE_SUFFIX)))\n                printf(\"%s : %s\\n\", tag->key, tag->value);\n        }\n    }    \n\n// ---------------------------------------------------------------------------------------------------\n\n    inline AVCodecID pick_codec_from_filename(const std::string& filename)\n    {\n        const auto ext_pos = filename.find_last_of(\".\");\n\n        if (ext_pos != std::string::npos)\n        {\n            const std::string ext = filename.substr(ext_pos + 1);\n\n            if (ext == \"png\" || ext == \"PNG\")\n                return AV_CODEC_ID_PNG;\n            else if (ext == \"jpeg\" || ext == \"jpg\" || ext == \"JPEG\")\n                return AV_CODEC_ID_MJPEG;\n            else if (ext == \"tiff\")\n                return AV_CODEC_ID_TIFF;\n            else if (ext == \"webp\")\n                return AV_CODEC_ID_WEBP;\n            else if (ext == \"bmp\")\n                return AV_CODEC_ID_BMP;\n            else if (ext == \"h264\")\n                return AV_CODEC_ID_H264;\n            else if (ext == \"h265\" || ext == \"hevc\")\n                return AV_CODEC_ID_H265;\n            else if (ext == \"aac\")\n                return AV_CODEC_ID_AAC;\n            else if (ext == \"ac3\")\n                return AV_CODEC_ID_AC3;\n            else if (ext == \"jls\")\n                return AV_CODEC_ID_JPEGLS;\n            else if (ext == \"jp2\")\n                return AV_CODEC_ID_JPEG2000;\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 37, 100)\n            else if (ext == \"jxl\")\n                return AV_CODEC_ID_JPEGXL;\n#endif\n        }\n\n        return AV_CODEC_ID_NONE;\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n}}}\n\n#endif //DLIB_FFMPEG_DETAILS\n"
  },
  {
    "path": "dlib/media/ffmpeg_muxer.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_VIDEO_MUXER\n#define DLIB_VIDEO_MUXER\n\n#include <chrono>\n#include <queue>\n#include <functional>\n#include <unordered_map>\n#include \"ffmpeg_utils.h\"\n#include \"../functional.h\"\n#include \"../constexpr_if.h\"\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n// ---------------------------------------------------------------------------------------------------\n\n        struct encoder_image_args : resizing_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments passed to the encoder and muxer classes.\n                    These must be set to non-zero or non-trivial values as they are used to configure \n                    the underlying codec and optionally, an internal image scaler.\n                    Any frame that is pushed to encoder or muxer instances is resized to the codec's \n                    pre-configured settings if their dimensions or pixel format don't match.\n                    For example, if the codec is configured to use height 512, width 384 and RGB format,\n                    using the variables below, and the frames already have these settings when pushed, \n                    then no resizing is performed. If however they don't, then they are first resized. \n            !*/\n\n            // Target framerate of codec/muxer\n            int framerate{0};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct encoder_audio_args : resampling_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments passed to the encoder and muxer classes.\n                    These must be set to non-zero or non-trivial values as they are used to configure \n                    the underlying codec and optionally, an internal audio resampler.\n                    Any frame that is pushed to encoder or muxer instances is resampled to the codec's\n                    pre-configured settings if their sample format, sample rate or channel layout, don't match.\n            !*/\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct encoder_codec_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments passed to the encoder and muxer classes.\n                    Some of these must be set to non-zero or non-trivial values as they are used \n                    to configure the underlying codec. Others will only be used if non-zero or\n                    non-trivial.\n            !*/\n\n            // Codec ID used to configure the encoder. Either codec or codec_name MUST be set.\n            AVCodecID codec{AV_CODEC_ID_NONE};\n\n            // Codec name used to configure the encoder. This is used if codec == AV_CODEC_ID_NONE.\n            std::string codec_name;\n\n            // A dictionary of AVCodecContext and codec-private options. Used by \"avcodec_open2()\"\n            std::unordered_map<std::string, std::string> codec_options;\n\n            // Sets AVCodecContext::bit_rate if non-negative.\n            int64_t bitrate{-1};\n\n            // Sets AVCodecContext::gop_size if non-negative.\n            int gop_size{-1};\n\n            // OR-ed with AVCodecContext::flags if non-negative.\n            int flags{0};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        class encoder\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class is a libavcodec wrapper which encodes video or audio to raw memory.\n                    Note, if you are creating a media file, it is easier to use the muxer object\n                    as it also works with raw codec files like .h264 files.\n                    This class is suitable for example if you need to send raw packets over a socket\n                    or interface with another library that requires encoded data, not raw images\n                    or raw audio samples.\n            !*/\n\n            struct args\n            {\n                /*!\n                    WHAT THIS OBJECT REPRESENTS\n                        This holds constructor arguments for encoder.\n                !*/\n                encoder_codec_args args_codec;\n                encoder_image_args args_image;\n                encoder_audio_args args_audio;\n            };\n\n            encoder() = default;\n            /*!\n                ensures\n                    - is_open() == false\n            !*/\n\n            encoder(const args& a);\n            /*!\n                requires\n                    - a.args_codec.codec or a.args_codec.codec_name are set\n                    - Either a.args_image or a.args_audio is fully set\n                ensures\n                    - Constructs encoder from args and sink\n                    - is_open() == true\n            !*/\n\n            bool is_open() const noexcept;\n            /*!\n                ensures\n                    - Returns true if the codec is open and user may call push()\n            !*/\n\n            bool is_image_encoder() const noexcept;\n            /*!\n                ensures\n                    - Returns true if the codec is an image encoder.\n            !*/\n\n            bool is_audio_encoder() const noexcept;\n            /*!\n                ensures\n                    - Returns true if the codec is an audio encoder.\n            !*/\n\n            AVCodecID get_codec_id() const noexcept;\n            /*!\n                requires\n                    - is_open() == true\n                ensures\n                    - returns the codec id. See ffmpeg documentation or libavcodec/codec_id.h\n            !*/\n\n            std::string get_codec_name() const noexcept;\n            /*!\n                requires\n                    - is_open() == true\n                ensures\n                    - returns string representation of codec id.\n            !*/\n\n            int height() const noexcept;\n            /*!\n                requires\n                    - is_image_encoder() == true\n                ensures\n                    - returns the height of the configured codec, not necessarily the\n                      height of frames passed to push(frame)\n            !*/\n\n            int width() const noexcept;\n            /*!\n                requires\n                    - is_image_encoder() == true\n                ensures\n                    - returns the width of the configured codec, not necessarily the\n                      width of frames passed to push(frame)\n            !*/\n\n            AVPixelFormat pixel_fmt() const noexcept;\n            /*!\n                requires\n                    - is_image_encoder() == true\n                ensures\n                    - returns the pixel format of the configured codec, not necessarily the\n                      pixel format of frames passed to push(frame)\n            !*/\n\n            int fps() const noexcept;\n             /*!\n                requires\n                    - is_image_encoder() == true\n                ensures\n                    - returns the configured framerate of the codec.\n            !*/\n\n            int sample_rate() const noexcept;\n            /*!\n                requires\n                    - is_audio_encoder() == true\n                ensures\n                    - returns the sample rate of the configured codec, not necessarily the\n                      sample rate of frames passed to push(frame)\n            !*/\n\n            uint64_t channel_layout() const noexcept;\n            /*!\n                requires\n                    - is_audio_encoder() == true\n                ensures\n                    - returns the channel layout of the configured codec, not necessarily the\n                      channel layout of frames passed to push(frame).\n                      e.g. AV_CH_LAYOUT_STEREO, AV_CH_LAYOUT_MONO etc.\n            !*/\n\n            AVSampleFormat sample_fmt() const noexcept;\n            /*!\n                requires\n                    - is_audio_encoder() == true\n                ensures\n                    - returns the sample format of the configured codec, not necessarily the\n                      sample format of frames passed to push(frame)\n            !*/\n\n            int nchannels() const noexcept;\n            /*!\n                requires\n                    - is_audio_encoder() == true\n                ensures\n                    - returns the number of audio channels in the configured codec.\n            !*/\n\n            template <class Callback>\n            bool push (\n                frame f,\n                Callback&& sink\n            );\n            /*!\n                requires\n                    - if is_image_encoder() == true, then f.is_image() == true\n                    - if is_audio_encoder() == true, then f.is_audio() == true\n                    - sink is set to a valid callback with signature bool(size_t, const char*)\n                      for writing packet data. dlib/media/sink.h contains callback wrappers for\n                      different buffer types.\n                    - sink does not call encoder::push() or encoder::flush(),\n                      i.e., the callback does not create a recursive loop. \n                ensures\n                    - If f does not have matching settings to the codec, it is either\n                      resized or resampled before being pushed to the codec and encoded.\n                    - The sink callback may or may not be invoked as the underlying resampler, \n                      audio fifo and codec all have their own buffers.\n                    - Returns true if successfully encoded, even if sink wasn't invoked.\n                    - Returns false if either EOF, i.e. flush() has been previously called,\n                      or an error occurred, in which case is_open() == false.\n            !*/\n\n            template <\n              class image_type,\n              class Callback,\n              is_image_check<image_type> = true\n            >\n            bool push (\n                const image_type& img,\n                Callback&& sink\n            );\n            /*!\n                requires\n                    - is_image_encoder() == true\n                    - sink is set to a valid callback with signature bool(size_t, const char*)\n                      for writing packet data. dlib/media/sink.h contains callback wrappers for\n                      different buffer types.\n                    - sink does not call encoder::push() or encoder::flush(),\n                      i.e., the callback does not create a recursive loop. \n                ensures\n                    - Encodes img using the constructor arguments, which may incur a resizing\n                      operation if the image dimensions and pixel type don't match the codec. \n                    - The sink callback may or may not be invoked as the underlying codec \n                      can buffer if necessary.\n                    - Returns true if successfully encoded, even if sink wasn't invoked.\n                    - Returns false if either EOF, i.e. flush() has been previously called,\n                      or an error occurred, in which case is_open() == false.\n            !*/\n\n            template <class Callback>\n            void flush (\n                Callback&& sink\n            );\n            /*!\n                requires\n                    - sink is set to a valid callback with signature bool(size_t, const char*)\n                      for writing packet data. dlib/media/sink.h contains callback wrappers for\n                      different buffer types.\n                    - sink does not call encoder::push() or encoder::flush(),\n                      i.e., the callback does not create a recursive loop. \n                ensures\n                    - Flushes the codec. This must be called when there are no more frames to be encoded.\n                    - sink will likely be invoked.\n                    - is_open() == false\n                    - Becomes a no-op after the first time you call this.\n            !*/\n\n        private:\n            friend class muxer;\n\n            bool open();\n\n            args                            args_;\n            bool                            open_{false};\n            bool                            encoding{false};\n            details::av_ptr<AVCodecContext> pCodecCtx;\n            details::av_ptr<AVPacket>       packet;\n            int                             next_pts{0};\n            details::resizer                resizer_image;\n            details::resampler              resizer_audio;\n            details::audio_fifo             fifo;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        class muxer\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class is a libavformat wrapper which muxes video and/or audio streams to file.\n                    It is analogous to OpenCV's cv::VideoWriter class but is more configurable, supports audio, \n                    devices (X11, speaker, ...) and network streams such as RTSP, HTTP, and more.\n                    Note that a video file, e.g. MP4, can contain multiple streams: video, audio, subtitles, etc.\n                    This class can encode both video and audio at the same time.\n            !*/\n\n            struct args\n            {\n                /*!\n                    WHAT THIS OBJECT REPRESENTS\n                        This holds constructor arguments for muxer.\n                !*/\n\n                args() = default;\n                /*!\n                    ensures\n                        - Default constructor.\n                !*/\n\n                args(const std::string& filepath);\n                /*!\n                    ensures\n                        - this->filepath = filepath\n                !*/\n\n                // Filepath, URL or device this object will write data to.\n                std::string filepath;\n\n                // Output format hint. e.g. 'rtsp', 'X11', 'alsa', etc. 99% of the time, users are not required to specify this as libavformat tries to guess it.\n                std::string output_format;\n\n                // A dictionary filled with AVFormatContext and muxer-private options. Used by \"avformat_write_header()\"\".\n                // Please see libavformat documentation for more details\n                std::unordered_map<std::string, std::string> format_options;\n\n                // An AVDictionary filled with protocol-private options. Used by avio_open2()\n                std::unordered_map<std::string, std::string> protocol_options;\n\n                // See documentation for AVFormatContext::max_delay\n                int max_delay{-1};\n\n                // Only relevant to network muxers such as RTSP, HTTP etc.\n                // Connection/listening timeout. \n                std::chrono::milliseconds connect_timeout{std::chrono::milliseconds::max()};\n                \n                // Only relevant to network muxers such as RTSP, HTTP etc\n                // Read timeout. \n                std::chrono::milliseconds read_timeout{std::chrono::milliseconds::max()};\n\n                // Only relevant to network muxers such as RTSP, HTTP etc\n                // Connection/listening interruption callback.\n                // The constructor periodically calls interrupter() while waiting on the network. If it returns true, then\n                // the connection is aborted and the muxer is closed.\n                // So user may use this in conjunction with some thread-safe shared state to signal an abort/interrupt.\n                std::function<bool()> interrupter;\n\n                // Video stream arguments\n                struct : encoder_codec_args, encoder_image_args{} args_image;\n\n                // Audio stream arguments\n                struct : encoder_codec_args, encoder_audio_args{} args_audio;\n                \n                // Whether or not to encode video stream.\n                bool enable_image{true};\n\n                // Whether or not to encode audio stream.\n                bool enable_audio{true};\n            };\n\n            muxer() = default;\n            /*!\n                ensures\n                    - is_open() == false\n            !*/\n\n            muxer(const args& a);\n            /*!\n                ensures\n                    - Constructs muxer using args\n            !*/\n\n            muxer(muxer&& other) noexcept;\n            /*!\n                ensures\n                    - Move constructor\n                    - After move, other.is_open() == false\n            !*/\n\n            muxer& operator=(muxer&& other) noexcept;\n            /*!\n                ensures\n                    - Move assignment\n                    - After move, other.is_open() == false\n            !*/\n\n            ~muxer();\n            /*!\n                ensures\n                    - Calls flush() if not already called\n                    - Closes the underlying file/socket\n            !*/\n\n            bool is_open() const noexcept;\n            /*!\n                ensures\n                    - Returns true if underlying container and codecs are open\n                    - User may call push()\n            !*/\n\n            bool audio_enabled() const noexcept;\n            /*!\n                requires\n                    - args.enable_audio == true\n                ensures\n                    - returns true if is_open() == true and an audio stream is available and open\n            !*/\n\n            bool video_enabled() const noexcept;\n            /*!\n                requires\n                    - args.enable_video == true\n                ensures\n                    - returns true if is_open() == true and a video stream is available and open\n            !*/\n\n            int height() const noexcept;\n            /*!\n                ensures\n                    - if (video_enabled())\n                        - returns the height of the configured codec, not necessarily the height of\n                          frames passed to push(frame).\n                    - else\n                        - returns 0\n            !*/\n\n            int width() const noexcept;\n            /*!\n                ensures\n                    - if (video_enabled())\n                        - returns the width of the configured codec, not necessarily the\n                          width of frames passed to push(frame).\n                    - else\n                        - returns 0\n            !*/\n\n            AVPixelFormat pixel_fmt() const noexcept;\n            /*!\n                ensures\n                    - if (video_enabled())\n                        - returns the pixel format of the configured codec, not necessarily the\n                          pixel format of frames passed to push(frame).\n                    - else\n                        - returns AV_PIX_FMT_NONE\n            !*/\n\n            float fps() const noexcept;\n            /*!\n                ensures\n                    - if (video_enabled())\n                        - returns the framerate of the configured codec\n                    - else\n                        - returns 0\n            !*/\n\n            int estimated_nframes() const noexcept;\n            /*!\n                ensures\n                    - returns ffmpeg's estimation of how many video frames are in the file without reading any frames\n                    - See ffmpeg's documentation for AVStream::nb_frames\n                    - Note, this is known to not always work with ffmpeg v3 with certain files. Most of the time it does\n                      Do not make your code rely on this\n            !*/\n\n            AVCodecID get_video_codec_id() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns codec ID of video stream\n                    - else\n                        - returns AV_CODEC_ID_NONE\n            !*/\n\n            std::string get_video_codec_name() const noexcept;\n            /*!\n                ensures \n                    - if (video_enabled())\n                        - returns codec name of video stream\n                    - else\n                        - returns \"\"\n            !*/\n\n            int sample_rate() const noexcept;\n            /*!\n                ensures\n                    - if (audio_enabled())\n                        - returns the sample rate of the configured codec, not necessarily the\n                          sample rate of frames passed to push(frame).\n                    - else\n                        - returns 0\n            !*/\n\n            uint64_t channel_layout() const noexcept;\n            /*!\n                ensures\n                    - if (audio_enabled())\n                        - returns the channel layout of the configured codec, not necessarily the\n                          channel layout of frames passed to push(frame).\n                    - else\n                        - returns 0\n            !*/\n\n            int nchannels() const noexcept;\n            /*!\n                ensures\n                    - if (audio_enabled())\n                        - returns the number of audio channels in the configured codec, not necessarily the\n                          number of channels in frames passed to push(frame).\n                    - else\n                        - returns 0\n            !*/\n\n            AVSampleFormat sample_fmt() const noexcept;\n            /*!\n                ensures\n                    - if (audio_enabled())\n                        - returns the sample format of the configured codec, not necessarily the\n                          sample format of frames passed to push(frame).\n                    - else\n                        - returns AV_SAMPLE_FMT_NONE\n            !*/\n\n            int estimated_total_samples() const noexcept;\n            /*!\n                ensures\n                    - if (audio_enabled())\n                        - returns an estimation fo the total number of audio samples in the audio stream\n                    - else\n                        - returns 0\n            !*/\n\n            AVCodecID get_audio_codec_id() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns codec ID of audio stream\n                    - else\n                        - returns AV_CODEC_ID_NONE\n            !*/\n\n            std::string get_audio_codec_name() const noexcept;\n            /*!\n                ensures \n                    - if (audio_enabled())\n                        - returns codec name of audio stream\n                    - else\n                        - returns \"\"\n            !*/\n\n            bool push(frame f);\n            /*!\n                requires\n                    - if is_image_encoder() == true, then f.is_image() == true\n                    - if is_audio_encoder() == true, then f.is_audio() == true\n                ensures\n                    - If f does not have matching settings to the codec, it is either\n                      resized or resampled before being pushed to the muxer.\n                    - Encodes and writes the encoded data to file/socket\n                    - Returns true if successfully encoded.\n                    - Returns false if either EOF, i.e. flush() has been previously called,\n                      or an error occurred, in which case is_open() == false.\n            !*/\n\n            template <\n              class image_type,\n              is_image_check<image_type> = true\n            >\n            bool push(const image_type& img);\n            /*!\n                requires\n                    - is_image_encoder() == true\n                ensures\n                    - Encodes img using the constructor arguments, which may incur a resizing\n                      operation if the image dimensions and pixel type don't match the codec. \n                    - Encodes and writes the encoded data to file/socket\n                    - Returns true if successfully encoded.\n                    - Returns false if either EOF, i.e. flush() has been previously called,\n                      or an error occurred, in which case is_open() == false.\n            !*/\n\n            void flush();\n            /*!\n                ensures\n                    - Flushes the file.\n                    - is_open() == false\n            !*/\n\n        private:\n\n            bool open(const args& a);\n            bool interrupt_callback();\n\n            struct {\n                args                                    args_;\n                details::av_ptr<AVFormatContext>        pFormatCtx;\n                encoder                                 encoder_image;\n                encoder                                 encoder_audio;\n                int                                     stream_id_video{-1};\n                int                                     stream_id_audio{-1};\n                std::chrono::system_clock::time_point   connecting_time{};\n                std::chrono::system_clock::time_point   connected_time{};\n                std::chrono::system_clock::time_point   last_read_time{};\n            } st;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type,\n          is_image_check<image_type> = true\n        >\n        void save_frame(\n            const image_type& image,\n            const std::string& file_name,\n            const std::unordered_map<std::string, std::string>& codec_options = {}\n        );\n        /*!\n            requires\n                - image_type must be a type conforming to the generic image interface.\n            ensures\n                - encodes the image into the file pointed by file_name using options described in codec_options.\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////// DEFINITIONS  ////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n        namespace details\n        {\n\n// ---------------------------------------------------------------------------------------------------\n\n            inline bool operator==(const AVRational& a, const AVRational& b) {return a.num == b.num && a.den == b.den;}\n            inline bool operator!=(const AVRational& a, const AVRational& b) {return !(a == b);}\n            inline bool operator==(const AVRational& a, int framerate)       {return a.den > 0 && (a.num / a.den) == framerate;}\n            inline bool operator!=(const AVRational& a, int framerate)       {return !(a == framerate);}\n            inline int  to_int(const AVRational& a)                          {return a.num / a.den;}\n            inline AVRational inv(const AVRational& a)                       {return {a.den, a.num};}\n\n// ---------------------------------------------------------------------------------------------------\n\n            inline void check_properties(\n                const AVCodec*  pCodec,\n                AVCodecContext* pCodecCtx\n            )\n            {\n                // Video properties\n                const AVRational*   supported_framerates{nullptr};\n                int                 nsupported_framerates{0};\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)\n                avcodec_get_supported_config(pCodecCtx, NULL, AV_CODEC_CONFIG_FRAME_RATE, 0, (const void**)&supported_framerates, &nsupported_framerates);\n#else\n                supported_framerates = pCodec->supported_framerates;\n                for (; supported_framerates != nullptr && supported_framerates[nsupported_framerates] != AVRational{0,0}  ; ++nsupported_framerates) {}\n#endif\n                if (supported_framerates && nsupported_framerates > 0 && pCodecCtx->framerate != 0)\n                {\n                    bool framerate_supported = false;\n\n                    for (int i = 0 ; i < nsupported_framerates ; ++i)\n                    {\n                        if (pCodecCtx->framerate == supported_framerates[i])\n                        {\n                            framerate_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!framerate_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO \n                            << \"Requested framerate \"\n                            << pCodecCtx->framerate.num / pCodecCtx->framerate.den\n                            << \" not supported. Changing to default \"\n                            << supported_framerates[0].num / supported_framerates[0].den;\n\n                        pCodecCtx->framerate = supported_framerates[0];\n                    }\n                }\n                const enum AVPixelFormat* pix_fmts{nullptr};\n                int                       npix_fmts{0};\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)\n                avcodec_get_supported_config(pCodecCtx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, 0, (const void**)&pix_fmts, &npix_fmts);\n#else\n                pix_fmts = pCodec->pix_fmts;\n                for (; pix_fmts != nullptr && pix_fmts[npix_fmts] != AV_PIX_FMT_NONE ; ++npix_fmts) {}\n#endif\n                if (pix_fmts && npix_fmts > 0)\n                {\n                    bool pix_fmt_supported = false;\n\n                    for (int i = 0 ; i < npix_fmts; ++i)\n                    {\n                        if (pCodecCtx->pix_fmt == pix_fmts[i])\n                        {\n                            pix_fmt_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!pix_fmt_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO\n                            << \"Requested pixel format \"\n                            << av_get_pix_fmt_name(pCodecCtx->pix_fmt)\n                            << \" not supported. Changing to default \"\n                            << av_get_pix_fmt_name(pix_fmts[0]);\n\n                        pCodecCtx->pix_fmt = pix_fmts[0];\n                    }\n                }\n\n                // Audio properties\n                const int*  supported_samplerates{nullptr};\n                int         nsupported_samplerates{0};\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)\n                avcodec_get_supported_config(pCodecCtx, NULL, AV_CODEC_CONFIG_SAMPLE_RATE, 0, (const void**)&supported_samplerates, &nsupported_samplerates);\n#else\n                supported_samplerates = pCodec->supported_samplerates;\n                for (; supported_samplerates != nullptr && supported_samplerates[nsupported_samplerates] != 0 ; ++nsupported_samplerates) {}\n#endif\n                if (supported_samplerates && nsupported_samplerates > 0)\n                {\n                    bool sample_rate_supported = false;\n\n                    for (int i = 0 ; i < nsupported_samplerates ; ++i)\n                    {\n                        if (pCodecCtx->sample_rate == supported_samplerates[i])\n                        {\n                            sample_rate_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!sample_rate_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO\n                            << \"Requested sample rate \"\n                            << pCodecCtx->sample_rate\n                            << \" not supported. Changing to default \"\n                            << supported_samplerates[0];\n\n                        pCodecCtx->sample_rate = supported_samplerates[0];\n                    }\n                }\n                const AVSampleFormat* sample_fmts{nullptr};\n                int                   nsample_fmts{0};\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)\n                avcodec_get_supported_config(pCodecCtx, NULL, AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, (const void**)&sample_fmts, &nsample_fmts);\n#else\n                sample_fmts = pCodec->sample_fmts;\n                for (; sample_fmts != nullptr && sample_fmts[nsample_fmts] != AV_SAMPLE_FMT_NONE ; ++nsample_fmts) {}\n#endif\n                if (sample_fmts && nsample_fmts > 0)\n                {\n                    bool sample_fmt_supported = false;\n\n                    for (int i = 0 ; i < nsample_fmts ; ++i)\n                    {\n                        if (pCodecCtx->sample_fmt == sample_fmts[i])\n                        {\n                            sample_fmt_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!sample_fmt_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO\n                            << \"Requested sample format \"\n                            << av_get_sample_fmt_name(pCodecCtx->sample_fmt)\n                            << \" not supported. Changing to default \"\n                            << av_get_sample_fmt_name(sample_fmts[0]);\n\n                        pCodecCtx->sample_fmt = sample_fmts[0];\n                    }\n                }\n\n#if FFMPEG_HAS_CH_LAYOUT\n                const AVChannelLayout* ch_layouts{nullptr};\n                int                    nch_layouts{0};\n#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(61, 13, 100)\n                avcodec_get_supported_config(pCodecCtx, NULL, AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0, (const void**)&ch_layouts, &nch_layouts);\n#else\n                ch_layouts = pCodec->ch_layouts;\n                for (; ch_layouts != nullptr && av_channel_layout_check(&ch_layouts[nch_layouts]) ; ++nch_layouts) {}\n#endif\n                if (ch_layouts && nch_layouts > 0)\n                {\n                    bool channel_layout_supported = false;\n\n                    for (int i = 0 ; i < nch_layouts ; ++i)\n                    {\n                        if (av_channel_layout_compare(&pCodecCtx->ch_layout, &ch_layouts[i]) == 0)\n                        {\n                            channel_layout_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!channel_layout_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO\n                            << \"Channel layout \"\n                            << details::get_channel_layout_str(pCodecCtx)\n                            << \" not supported. Changing to default \"\n                            << details::get_channel_layout_str(ch_layouts[0]);\n\n                        av_channel_layout_copy(&pCodecCtx->ch_layout, &ch_layouts[0]);\n                    }\n                }\n#else\n                if (pCodec->channel_layouts)\n                {\n                    bool channel_layout_supported = false;\n\n                    for (int i = 0 ; pCodec->channel_layouts[i] != 0 ; i++)\n                    {\n                        if (pCodecCtx->channel_layout == pCodec->channel_layouts[i])\n                        {\n                            channel_layout_supported = true;\n                            break;\n                        }\n                    }\n\n                    if (!channel_layout_supported)\n                    {\n                        logger_dlib_wrapper() << LINFO \n                            << \"Channel layout \"\n                            << details::get_channel_layout_str(pCodecCtx)\n                            << \" not supported. Changing to default \"\n                            << dlib::ffmpeg::get_channel_layout_str(pCodec->channel_layouts[0]);\n\n                        pCodecCtx->channel_layout = pCodec->channel_layouts[0];\n                    }\n                }\n#endif\n            }\n\n// ---------------------------------------------------------------------------------------------------\n\n            inline bool check_codecs (\n                const bool              is_video,\n                const std::string&      filename,\n                const AVOutputFormat*   oformat,\n                encoder::args&          args\n            )\n            {\n                // Check the codec is supported by this muxer\n                const auto supported_codecs = list_codecs_for_muxer(oformat);\n\n                const auto codec_supported = [&](AVCodecID id, const std::string& name)\n                {\n                    return std::find_if(begin(supported_codecs), end(supported_codecs), [&](const auto& supported) {\n                        return id != AV_CODEC_ID_NONE ? id == supported.codec_id : name == supported.codec_name;\n                    }) != end(supported_codecs);\n                };\n\n                if (codec_supported(args.args_codec.codec, args.args_codec.codec_name))\n                    return true;\n\n                logger_dlib_wrapper() << LWARN\n                    << \"Codec \" << avcodec_get_name(args.args_codec.codec) << \" or \" << args.args_codec.codec_name\n                    << \" cannot be stored in this file\";\n\n                // Pick codec based on file extension\n                args.args_codec.codec = pick_codec_from_filename(filename);\n\n                if (codec_supported(args.args_codec.codec, \"\"))\n                {\n                    logger_dlib_wrapper() << LWARN  << \"Picking codec \" << avcodec_get_name(args.args_codec.codec);\n                    return true;\n                }\n                    \n                // Pick the default codec as suggested by FFmpeg\n                args.args_codec.codec = is_video ? oformat->video_codec : oformat->audio_codec;\n\n                if (args.args_codec.codec != AV_CODEC_ID_NONE)\n                {\n                    logger_dlib_wrapper() << LWARN  << \"Picking default codec \" << avcodec_get_name(args.args_codec.codec);\n                    return true;\n                }\n                    \n                logger_dlib_wrapper() << LWARN \n                    << \"List of supported codecs for muxer \" << oformat->name << \" in this installation of ffmpeg:\";\n\n                for (const auto& supported : supported_codecs)\n                    logger_dlib_wrapper() << LWARN << \"    \" << supported.codec_name;\n                        \n                return false;\n            }\n\n// ---------------------------------------------------------------------------------------------------\n\n        }\n\n        inline encoder::encoder(\n            const args& a\n        ) : args_(a)\n        {\n            if (!open())\n                pCodecCtx = nullptr;\n        }\n\n        inline bool encoder::open()\n        {\n            using namespace details;\n\n            register_ffmpeg();\n\n            packet = make_avpacket();\n            const AVCodec* pCodec = nullptr;\n\n            if (args_.args_codec.codec != AV_CODEC_ID_NONE)\n                pCodec = avcodec_find_encoder(args_.args_codec.codec);\n            else if (!args_.args_codec.codec_name.empty())\n                pCodec = avcodec_find_encoder_by_name(args_.args_codec.codec_name.c_str());\n\n            if (!pCodec)\n                return fail(\"Codec \",  avcodec_get_name(args_.args_codec.codec), \" or \", args_.args_codec.codec_name, \" not found\");\n\n            pCodecCtx.reset(avcodec_alloc_context3(pCodec));\n            if (!pCodecCtx)\n                return fail(\"AV : failed to allocate codec context for \", pCodec->name, \" : likely ran out of memory\");\n\n            if (args_.args_codec.bitrate > 0)\n                pCodecCtx->bit_rate = args_.args_codec.bitrate;\n            if (args_.args_codec.gop_size > 0)\n                pCodecCtx->gop_size = args_.args_codec.gop_size;\n            if (args_.args_codec.flags > 0)\n                pCodecCtx->flags |= args_.args_codec.flags;\n\n            if (pCodec->type == AVMEDIA_TYPE_VIDEO)\n            {\n                if (args_.args_image.h          <= 0               ||\n                    args_.args_image.w          <= 0               ||\n                    args_.args_image.fmt        == AV_PIX_FMT_NONE ||\n                    args_.args_image.framerate  <= 0)\n                {\n                    return fail(pCodec->name, \" is an image codec. height, width, fmt (pixel format) and framerate must be set\");\n                }\n\n                pCodecCtx->height       = args_.args_image.h;\n                pCodecCtx->width        = args_.args_image.w;\n                pCodecCtx->pix_fmt      = args_.args_image.fmt;\n                pCodecCtx->framerate    = AVRational{args_.args_image.framerate, 1};\n                check_properties(pCodec, pCodecCtx.get());\n                pCodecCtx->time_base    = inv(pCodecCtx->framerate);\n            }\n            else if (pCodec->type == AVMEDIA_TYPE_AUDIO)\n            {\n                if (args_.args_audio.sample_rate <= 0 ||\n                    args_.args_audio.channel_layout <= 0 ||\n                    args_.args_audio.fmt == AV_SAMPLE_FMT_NONE) \n                {\n                    return fail(pCodec->name, \" is an audio codec. sample_rate, channel_layout and fmt (sample format) must be set\");\n                }\n\n                pCodecCtx->sample_rate      = args_.args_audio.sample_rate;\n                pCodecCtx->sample_fmt       = args_.args_audio.fmt;\n                set_layout(pCodecCtx.get(), args_.args_audio.channel_layout);\n                check_properties(pCodec, pCodecCtx.get());\n                pCodecCtx->time_base        = AVRational{ 1, pCodecCtx->sample_rate };\n\n                if (pCodecCtx->codec_id == AV_CODEC_ID_AAC) {\n                    pCodecCtx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;\n                }\n            }\n\n            av_dict opt = args_.args_codec.codec_options;\n            const int ret = avcodec_open2(pCodecCtx.get(), pCodec, opt.get());\n            if (ret < 0)\n                return fail(\"avcodec_open2() failed : \", get_av_error(ret));\n\n            if (pCodec->type == AVMEDIA_TYPE_AUDIO)\n            {\n                fifo = audio_fifo(pCodecCtx->frame_size,\n                                  pCodecCtx->sample_fmt,\n                                  get_nchannels(pCodecCtx.get()));\n            }\n\n            open_ = true;\n            return open_;\n        }\n\n        inline bool            encoder::is_open()          const noexcept { return pCodecCtx != nullptr && open_; }\n        inline bool            encoder::is_image_encoder() const noexcept { return pCodecCtx && pCodecCtx->codec_type == AVMEDIA_TYPE_VIDEO; }\n        inline bool            encoder::is_audio_encoder() const noexcept { return pCodecCtx && pCodecCtx->codec_type == AVMEDIA_TYPE_AUDIO; }\n        inline AVCodecID       encoder::get_codec_id()     const noexcept { return pCodecCtx ? pCodecCtx->codec_id : AV_CODEC_ID_NONE; }\n        inline std::string     encoder::get_codec_name()   const noexcept { return pCodecCtx ? avcodec_get_name(pCodecCtx->codec_id) : \"NONE\"; }\n        inline int             encoder::fps()              const noexcept { return pCodecCtx ? details::to_int(pCodecCtx->framerate) : 0; }\n        inline int             encoder::height()           const noexcept { return pCodecCtx ? pCodecCtx->height            : 0; }\n        inline int             encoder::width()            const noexcept { return pCodecCtx ? pCodecCtx->width             : 0; }\n        inline AVPixelFormat   encoder::pixel_fmt()        const noexcept { return pCodecCtx ? pCodecCtx->pix_fmt           : AV_PIX_FMT_NONE; }\n        inline int             encoder::sample_rate()      const noexcept { return pCodecCtx ? pCodecCtx->sample_rate       : 0; }\n        inline AVSampleFormat  encoder::sample_fmt()       const noexcept { return pCodecCtx ? pCodecCtx->sample_fmt        : AV_SAMPLE_FMT_NONE; }\n        inline uint64_t        encoder::channel_layout()   const noexcept { return details::get_layout(pCodecCtx.get()); }\n        inline int             encoder::nchannels()        const noexcept { return details::get_nchannels(pCodecCtx.get()); }\n\n        enum encoding_state\n        {\n            ENCODE_SEND_FRAME,\n            ENCODE_READ_PACKET_THEN_DONE,\n            ENCODE_READ_PACKET_THEN_SEND_FRAME,\n            ENCODE_DONE,\n            ENCODE_ERROR = -1\n        };\n        \n        template <class Callback>\n        inline bool encoder::push (\n            frame f_,\n            Callback&& clb\n        )\n        {\n            using namespace details;\n\n            if (!is_open())\n                return false;\n\n            DLIB_ASSERT(!encoding, \"Recursion in push() not supported\");\n            encoding = true;\n\n            std::vector<frame> frames;\n\n            // Resize if image. Resample if audio. Push through audio fifo if necessary (some audio codecs requires fixed size frames)\n            if (f_.is_image())\n            {\n                resizer_image.resize(f_, pCodecCtx->height, pCodecCtx->width, pCodecCtx->pix_fmt, f_);\n                frames.push_back(std::move(f_));\n            }\n            else if (f_.is_audio())\n            {\n                resizer_audio.resize(f_, pCodecCtx->sample_rate, get_layout(pCodecCtx.get()), pCodecCtx->sample_fmt, f_);\n                frames = fifo.push_pull(std::move(f_));\n            }\n            else\n            {\n                // FLUSH\n                frames.push_back(std::move(f_));\n            }\n\n            // Set pts based on tracked state. Ignore timestamps for now\n            for (auto& f : frames)\n            {\n                if (f.f)\n                {\n                    f.f->pts = next_pts;\n                    next_pts += (f.is_image() ? 1 : f.nsamples());\n                }\n            }\n\n            const auto send_frame = [&](encoding_state& state, frame& f)\n            {\n                const int ret = avcodec_send_frame(pCodecCtx.get(), f.f.get());\n\n                if (ret >= 0) {\n                    state   = ENCODE_READ_PACKET_THEN_DONE;\n                } else if (ret == AVERROR(EAGAIN)) {\n                    state   = ENCODE_READ_PACKET_THEN_SEND_FRAME;\n                } else if (ret == AVERROR_EOF) {\n                    open_   = false;\n                    state   = ENCODE_DONE;\n                } else {\n                    open_   = false;\n                    state   = ENCODE_ERROR;\n                    logger_dlib_wrapper() << LERROR << \"avcodec_send_frame() failed : \" << get_av_error(ret);\n                }\n            };\n\n            const auto recv_packet = [&](encoding_state& state, bool resend)\n            {\n                const int ret = avcodec_receive_packet(pCodecCtx.get(), packet.get());\n\n                if (ret == AVERROR(EAGAIN) && resend)\n                    state   = ENCODE_SEND_FRAME;\n                else if (ret == AVERROR(EAGAIN))\n                    state   = ENCODE_DONE;\n                else if (ret == AVERROR_EOF) {\n                    open_   = false;\n                    state   = ENCODE_DONE;\n                }\n                else if (ret < 0)\n                {\n                    open_   = false;\n                    state   = ENCODE_ERROR;\n                    logger_dlib_wrapper() << LERROR << \"avcodec_receive_packet() failed : \" << get_av_error(ret);\n                }\n                else\n                {\n                    if (!switch_(bools(dlib::is_invocable_r<bool, Callback, std::size_t, const char*>{},\n                                       dlib::is_invocable_r<bool, Callback, AVCodecContext*, AVPacket*>{}),\n                        [&](true_t, false_t, auto _) {\n                            return _(clb)(packet->size, (const char*)packet->data);\n                        },\n                        [&](false_t, true_t, auto _) {\n                            return _(clb)(pCodecCtx.get(), packet.get());\n                        },\n                        [&](false_t, false_t, auto _) {\n                            static_assert(_(false), \"Callback is a bad callback type\");\n                            return false;\n                        }\n                    ))\n                    {\n                        open_   = false;\n                        state   = ENCODE_ERROR;\n                    }\n                }\n            };\n\n            encoding_state state = ENCODE_SEND_FRAME;\n\n            for (size_t i = 0 ; i < frames.size() && is_open() ; ++i)\n            {\n                state = ENCODE_SEND_FRAME;\n\n                while (state != ENCODE_DONE && state != ENCODE_ERROR)\n                {\n                    switch(state)\n                    {\n                        case ENCODE_SEND_FRAME:                     send_frame(state, frames[i]);   break;\n                        case ENCODE_READ_PACKET_THEN_DONE:          recv_packet(state, false);      break;\n                        case ENCODE_READ_PACKET_THEN_SEND_FRAME:    recv_packet(state, true);       break;\n                        default: break;\n                    }\n                }\n            }\n\n            encoding = false;\n            return state != ENCODE_ERROR;\n        }\n\n        template <\n            class image_type,\n            class Callback,\n            is_image_check<image_type>\n        >\n        inline bool encoder::push (\n            const image_type& img,\n            Callback&& sink\n        )\n        {\n            // Unfortunately, FFmpeg assumes all data is over-aligned, and therefore,\n            // even though the API has facilities to convert img directly to a frame object,\n            // we cannot use it because it assumes the data in img is over-aligned, and of \n            // course, it is not. Shame. At some point, I'll more digging to see if we \n            // can get around this without doing a brute force copy like below.\n            using namespace details;\n            frame f;\n            convert(img, f);\n            return push(std::move(f), std::forward<Callback>(sink));\n        }\n\n        template <class Callback>\n        inline void encoder::flush(Callback&& clb)\n        {\n            push(frame{}, std::forward<Callback>(clb));\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        namespace details\n        {\n            inline auto muxer_sink(AVFormatContext* pFormatCtx, int stream_id)\n            {\n                return [=](AVCodecContext* pCodecCtx, AVPacket* pkt)\n                {\n                    AVStream* stream = pFormatCtx->streams[stream_id];\n                    av_packet_rescale_ts(pkt, pCodecCtx->time_base, stream->time_base);\n                    pkt->stream_index = stream_id;\n                    int ret = av_interleaved_write_frame(pFormatCtx, pkt);\n                    if (ret < 0)\n                        logger_dlib_wrapper() << LERROR << \"av_interleaved_write_frame() failed : \" << get_av_error(ret);\n                    return ret == 0;\n                };\n            }\n        }   \n        \n        inline muxer::muxer(const args &a)\n        {\n            if (!open(a))\n                st.pFormatCtx = nullptr;\n        }\n\n        inline muxer::muxer(muxer &&other) noexcept\n        : st{std::move(other.st)}\n        {\n            if (st.pFormatCtx)\n                st.pFormatCtx->opaque = this;\n        }\n\n        inline muxer& muxer::operator=(muxer &&other) noexcept\n        {\n            if (this != &other)\n            {\n                flush();\n                st = std::move(other.st);\n                if (st.pFormatCtx)\n                    st.pFormatCtx->opaque = this;\n            }\n            return *this;\n        }\n\n        inline muxer::~muxer()\n        {\n            flush();\n        }\n\n        inline bool muxer::open(const args& a)\n        {\n            using namespace details;\n            using std::chrono::system_clock;\n\n            st = {};\n            st.args_ = a;\n\n            if (!st.args_.enable_audio && !st.args_.enable_image)\n                return fail(\"You need to set at least one of `enable_audio` or `enable_image`\");\n\n            {\n                st.connecting_time = system_clock::now();\n                st.connected_time  = system_clock::time_point::max();\n\n                const char* const format_name   = st.args_.output_format.empty() ? nullptr : st.args_.output_format.c_str();\n                const char* const filename      = st.args_.filepath.empty()      ? nullptr : st.args_.filepath.c_str();\n                AVFormatContext* pFormatCtx = nullptr;\n                int ret = avformat_alloc_output_context2(&pFormatCtx, nullptr, format_name, filename);\n\n                if (ret < 0)\n                    return fail(\"avformat_alloc_output_context2() failed : \", get_av_error(ret));\n\n                st.pFormatCtx.reset(pFormatCtx);\n            }\n\n            int stream_counter{0};\n\n            const auto setup_stream = [&](bool is_video)\n            {\n                // Setup encoder for this stream\n                auto&   enc       = is_video ? st.encoder_image     : st.encoder_audio;\n                int&    stream_id = is_video ? st.stream_id_video   : st.stream_id_audio;\n\n                encoder::args args;\n\n                if (is_video)\n                {\n                    args.args_codec = st.args_.args_image;\n                    args.args_image = st.args_.args_image;\n                }\n                else\n                {\n                    args.args_codec = st.args_.args_audio;\n                    args.args_audio = st.args_.args_audio;\n                }\n\n                if (st.pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)\n                    args.args_codec.flags |= AV_CODEC_FLAG_GLOBAL_HEADER;\n\n                if (!check_codecs(is_video, st.args_.filepath, st.pFormatCtx->oformat, args))\n                    return false;\n\n                // Codec is supported by muxer, so create encoder\n                enc = encoder(args);\n\n                if (!enc.is_open())\n                    return false;\n\n                AVStream* stream = avformat_new_stream(st.pFormatCtx.get(), enc.pCodecCtx->codec);\n\n                if (!stream)\n                    return fail(\"avformat_new_stream() failed\");\n\n                stream_id           = stream_counter;\n                stream->id          = stream_counter;\n                stream->time_base   = enc.pCodecCtx->time_base;\n                ++stream_counter;\n\n                int ret = avcodec_parameters_from_context(stream->codecpar, enc.pCodecCtx.get());\n\n                if (ret < 0)\n                    return fail(\"avcodec_parameters_from_context() failed : \", get_av_error(ret));\n\n                return true;\n            };\n\n            if (st.args_.enable_image && !setup_stream(true))\n                return false;\n\n            if (st.args_.enable_audio && !setup_stream(false))\n                return false;\n\n            st.pFormatCtx->opaque = this;\n            st.pFormatCtx->interrupt_callback.opaque    = st.pFormatCtx.get();\n            st.pFormatCtx->interrupt_callback.callback  = [](void* ctx) -> int {\n                AVFormatContext* pFormatCtx = (AVFormatContext*)ctx;\n                muxer* me = (muxer*)pFormatCtx->opaque;\n                return me->interrupt_callback();\n            };\n\n            if (st.args_.max_delay > 0)\n                st.pFormatCtx->max_delay = st.args_.max_delay;\n\n            if ((st.pFormatCtx->oformat->flags & AVFMT_NOFILE) == 0)\n            {\n                av_dict opt = st.args_.protocol_options;\n\n                int ret = avio_open2(&st.pFormatCtx->pb, st.args_.filepath.c_str(), AVIO_FLAG_WRITE, &st.pFormatCtx->interrupt_callback, opt.get());\n\n                if (ret < 0)\n                    return fail(\"avio_open2() failed : \", get_av_error(ret));\n            }\n\n            av_dict opt = st.args_.format_options;\n\n            int ret = avformat_write_header(st.pFormatCtx.get(), opt.get());\n\n            if (ret < 0)\n                return fail(\"avformat_write_header() failed : \", get_av_error(ret));\n\n            st.connected_time = system_clock::now();\n\n            return true;\n        }\n\n        inline bool muxer::interrupt_callback()\n        {\n            const auto now = std::chrono::system_clock::now();\n\n            if (st.args_.connect_timeout < std::chrono::milliseconds::max() && // check there is a timeout\n                now < st.connected_time &&                                     // we haven't already connected\n                now > (st.connecting_time + st.args_.connect_timeout)          // we've timed-out\n            )\n                return true;\n\n            if (st.args_.read_timeout < std::chrono::milliseconds::max() &&   // check there is a timeout\n                now > (st.last_read_time + st.args_.read_timeout)             // we've timed-out\n            )\n                return true;\n\n            if (st.args_.interrupter && st.args_.interrupter())               // check user-specified callback\n                return true;\n\n            return false;\n        }\n\n        inline bool muxer::push(frame f)\n        {\n            using namespace details;\n\n            if (!is_open())\n                return false;\n\n            if (f.is_image())\n            {\n                if (!st.encoder_image.is_open())\n                    return fail(\"frame is an image type but image encoder is not initialized\");\n\n                return st.encoder_image.push(std::move(f), muxer_sink(st.pFormatCtx.get(), st.stream_id_video));\n            }\n\n            else if (f.is_audio())\n            {\n                if (!st.encoder_audio.is_open())\n                    return fail(\"frame is of audio type but audio encoder is not initialized\");\n\n                return st.encoder_audio.push(std::move(f), muxer_sink(st.pFormatCtx.get(), st.stream_id_audio));\n            }\n\n            return false;\n        }\n\n        template <\n            class image_type,\n            is_image_check<image_type>\n        >\n        bool muxer::push(const image_type& img)\n        {\n            using namespace details;\n\n            return is_open() &&\n                   st.encoder_image.is_open() &&\n                   st.encoder_image.push(img, muxer_sink(st.pFormatCtx.get(), st.stream_id_video));\n        }\n\n        inline void muxer::flush()\n        {\n            using namespace details;\n            \n            if (!is_open())\n                return;\n\n            // Flush the encoder but don't actually close the underlying AVCodecContext\n            st.encoder_image.flush(muxer_sink(st.pFormatCtx.get(), st.stream_id_video));\n            st.encoder_audio.flush(muxer_sink(st.pFormatCtx.get(), st.stream_id_audio));\n\n            const int ret = av_write_trailer(st.pFormatCtx.get());\n            if (ret < 0)\n                logger_dlib_wrapper() << LERROR << \"av_write_trailer() failed : \" << details::get_av_error(ret);\n\n            if ((st.pFormatCtx->oformat->flags & AVFMT_NOFILE) == 0)\n                avio_closep(&st.pFormatCtx->pb);\n\n            st.pFormatCtx = nullptr;\n            st.encoder_image = {};\n            st.encoder_audio = {};\n        }\n\n        inline bool             muxer::is_open()                const noexcept { return video_enabled() || audio_enabled(); }\n        inline bool             muxer::video_enabled()          const noexcept { return st.pFormatCtx != nullptr && st.encoder_image.is_image_encoder(); }\n        inline bool             muxer::audio_enabled()          const noexcept { return st.pFormatCtx != nullptr && st.encoder_audio.is_audio_encoder(); }\n        inline int              muxer::height()                 const noexcept { return st.encoder_image.height(); }\n        inline int              muxer::width()                  const noexcept { return st.encoder_image.width(); }\n        inline AVPixelFormat    muxer::pixel_fmt()              const noexcept { return st.encoder_image.pixel_fmt(); }\n        inline AVCodecID        muxer::get_video_codec_id()     const noexcept { return st.encoder_image.get_codec_id(); }\n        inline std::string      muxer::get_video_codec_name()   const noexcept { return st.encoder_image.get_codec_name(); }\n        inline int              muxer::sample_rate()            const noexcept { return st.encoder_audio.sample_rate(); }\n        inline uint64_t         muxer::channel_layout()         const noexcept { return st.encoder_audio.channel_layout(); }\n        inline int              muxer::nchannels()              const noexcept { return st.encoder_audio.nchannels(); }\n        inline AVSampleFormat   muxer::sample_fmt()             const noexcept { return st.encoder_audio.sample_fmt(); }\n        inline AVCodecID        muxer::get_audio_codec_id()     const noexcept { return st.encoder_audio.get_codec_id(); }\n        inline std::string      muxer::get_audio_codec_name()   const noexcept { return st.encoder_audio.get_codec_name(); }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type,\n          is_image_check<image_type>\n        >\n        inline void save_frame(\n            const image_type& image,\n            const std::string& file_name,\n            const std::unordered_map<std::string, std::string>& codec_options\n        )\n        {\n            muxer writer([&] {\n                muxer::args args;\n                args.filepath               = file_name;\n                args.enable_image           = true;\n                args.enable_audio           = false;\n                args.args_image.h           = num_rows(image);\n                args.args_image.w           = num_columns(image);\n                args.args_image.framerate   = 1;\n                args.args_image.fmt         = pix_traits<pixel_type_t<image_type>>::fmt;\n                args.args_image.codec_options = codec_options;\n                args.format_options[\"update\"] = \"1\";\n                return args;\n            }());\n\n            if (!writer.push(image))\n                throw error(EIMAGE_SAVE, \"ffmpeg::save_frame: error while saving \" + file_name);\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif //DLIB_VIDEO_MUXER\n"
  },
  {
    "path": "dlib/media/ffmpeg_utils.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_FFMPEG_UTILS\n#define DLIB_FFMPEG_UTILS\n\n#include \"../test_for_odr_violations.h\"\n\n#ifndef DLIB_USE_FFMPEG\nstatic_assert(false, \"This version of dlib isn't built with the FFMPEG wrappers\");\n#endif\n\n#include <cstdint>\n#include <stdexcept>\n#include <memory>\n#include <algorithm>\n#include <string>\n#include <chrono>\n#include <vector>\n#include <array>\n#include <unordered_map>\n#include <iostream>\n#include \"../image_processing/generic_image.h\"\n#include \"../pixel.h\"\n#include \"../assert.h\"\n#include \"ffmpeg_details.h\"\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n\n// ---------------------------------------------------------------------------------------------------\n\n        std::string get_pixel_fmt_str(AVPixelFormat fmt);\n        /*!\n            ensures\n                - Returns a string description of AVPixelFormat\n        !*/\n\n        std::string get_audio_fmt_str(AVSampleFormat fmt);\n        /*!\n            ensures\n                - Returns a string description of AVSampleFormat\n        !*/\n\n        std::string get_channel_layout_str(uint64_t layout);\n        /*!\n            ensures\n                - Returns a string description of a channel layout, where layout is e.g. AV_CH_LAYOUT_STEREO\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        dlib::logger& logger_ffmpeg();\n        /*!\n            ensures\n                - Returns a global logger used by the internal ffmpeg libraries. \n                - You may set the logging level using .set_level() to supress or enable certain logs.\n        !*/\n\n        dlib::logger& logger_dlib_wrapper();\n        /*!\n            ensures\n                - Returns a global logger used by dlib's ffmpeg wrappers.\n                - You may set the logging level using .set_level() to supress or enable certain logs.\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        namespace details { class resampler; }\n\n        class frame\n        {\n        public:\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class wraps AVFrame* into a std::unique_ptr with an appropriate deleter.\n                    It also has a std::chrono timestamp which closely matches the AVFrame's internal pts.\n                    It has a bunch of helper functions for retrieving the frame's properties.\n                    We strongly recommend you read ffmegs documentation on AVFrame.\n\n                    FFmpeg's AVFrame object is basically a type-erased frame object, which can contain, \n                    image, audio or other types of streamable data.\n                    The pixel format (image), sample format (audio), number of channels (audio), \n                    pixel/sample type (u8, s16, f32, etc) are also erased and defined as runtime parameters.\n\n                    Users should avoid using this object directly if they can, instead use the conversion functions\n                    dlib::ffmpeg::convert() which will convert to and back appropriate dlib objects.\n                    For example, when using dlib::ffmpeg::decoder or dlib::ffmpeg::demuxer, directly after calling\n                    .read(), use convert() to get a dlib object which you can then use for your computer vision,\n                    or DNN application.\n\n                    If users need to use frame objects directly, maybe because RGB or BGR aren't appropriate, \n                    and they would rather use the default format returned by their codec, then use\n                    frame::get_frame().data and frame::get_frame().linesize to iterate or copy the data.\n                    Please carefully read FFMpeg's documentation on how to interpret those fields.\n                    Also, users must not copy AVFrame directly. It is a C object, and therefore does not\n                    support RAII. If you need to make copies, use the frame object (which wraps AVFrame)\n                    which has well defined copy (and move) semantics.\n            !*/\n\n            frame() = default;\n            /*!\n                ensures\n                    - is_empty() == true\n            !*/\n\n            frame(frame&& ori) = default;\n            /*!\n                ensures\n                    - Move constructor\n                    - After move, ori.is_empty() == true\n            !*/\n\n            frame& operator=(frame&& ori) = default;\n            /*!\n                ensures\n                    - Move assign operator\n                    - After move, ori.is_empty() == true\n            !*/\n\n            frame(const frame& ori);\n            /*!\n                ensures\n                    - Copy constructor\n            !*/\n\n            frame& operator=(const frame& ori);\n            /*!\n                ensures\n                    - Copy assign operator\n            !*/\n\n            frame(\n                int                                     h,\n                int                                     w,\n                AVPixelFormat                           pixfmt,\n                std::chrono::system_clock::time_point   timestamp_us\n            );\n            /*!\n                ensures\n                    - Create a an image frame object with these parameters.\n                    - is_image() == true\n                    - is_audio() == false\n                    - is_empty() == false\n            !*/\n\n            frame(\n                int                                     sample_rate,\n                int                                     nb_samples,\n                uint64_t                                channel_layout,\n                AVSampleFormat                          samplefmt,\n                std::chrono::system_clock::time_point   timestamp\n            );\n            /*!\n                ensures\n                    - Create a an audio frame object with these parameters.\n                    - is_image() == false\n                    - is_audio() == true\n                    - is_empty() == false\n            !*/\n\n            bool is_empty() const noexcept;\n            /*!\n                ensures\n                    - Returns true if is_image() == false and is_audio() == false\n            !*/\n\n            bool is_image() const noexcept;\n            /*!\n                ensures\n                    - Returns true if underlying AVFrame* != nullptr, height() > 0, width() > 0 and pixfmt() != AV_PIX_FMT_NONE\n            !*/\n\n            bool is_audio() const noexcept;\n            /*!\n                ensures\n                    - Returns true if underlying AVFrame* != nullptr, height() > 0, width() > 0 and pixfmt() != AV_PIX_FMT_NONE\n            !*/\n\n            AVPixelFormat pixfmt() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is image type, returns pixel format, otherwise, returns AV_PIX_FMT_NONE\n            !*/\n\n            int height() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is image type, returns height, otherwise 0\n            !*/\n\n            int width() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is image type, returns width, otherwise 0\n            !*/\n\n            int nsamples() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is audio type, returns number of samples, otherwise 0\n            !*/\n\n            int  nchannels() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is audio type, returns number of channels, e.g. 1 for mono, 2 for stereo, otherwise 0\n            !*/\n\n            uint64_t layout() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is audio type, returns channel layout, e.g. AV_CH_LAYOUT_MONO or AV_CH_LAYOUT_STEREO, otherwise 0\n            !*/\n\n            AVSampleFormat samplefmt() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is audio type, returns sample format, otherwise, returns AV_SAMPLE_FMT_NONE\n            !*/\n\n            int sample_rate() const noexcept;\n            /*!\n                ensures\n                    - If underlying AVFrame* is audio type, returns sample rate, otherwise, returns 0\n            !*/\n\n            std::chrono::system_clock::time_point get_timestamp() const noexcept;\n            /*!\n                ensures\n                    - If possible, returns a timestamp associtated with this frame. This is not always possible, it depends on whether the information\n                      is provided by the codec and/or the muxer. dlib will do it's best to get a timestamp for you.\n            !*/\n\n            const AVFrame& get_frame() const;\n            /*!\n                requires\n                    - is_empty() == false\n\n                ensures\n                    - Returns a const reference to the underyling AVFrame object. DO NOT COPY THIS OBJECT! RAII is not supported on this sub-object.\n                      Use with care! Prefer to use dlib's convert() functions to convert to and back dlib objects.\n            !*/\n\n            AVFrame& get_frame();\n            /*!\n                requires\n                    - is_empty() == false\n                ensures\n                    - Returns a non-const reference to the underlying AVFrame object. DO NOT COPY THIS OBJECT! RAII is not supported on this sub-object.\n                      Use with care! Prefer to use dlib's convert() functions to convert to and back dlib objects.\n            !*/\n\n            void set_params(\n                int                                     h,\n                int                                     w,\n                AVPixelFormat                           pixfmt,\n                int                                     sample_rate,\n                int                                     nb_samples,\n                uint64_t                                channel_layout,\n                AVSampleFormat                          samplefmt,\n                std::chrono::system_clock::time_point   timestamp\n            );\n            /*!\n                requires\n                    - For images, set sample_rate = nb_samples = channel_layout = 0, and samplefmt = AV_SAMPLE_FMT_NONE\n                    - For audio, set h = w = 0 and pixfmt = AV_PIX_FMT_NONE\n                ensures\n                    - Resizes the frame to the corresponding dims.\n                    - is_empty()        == false\n                    - is_image()        == (h > 0 && w > 0 && pixfmt != AV_PIX_FMT_NONE)\n                    - is_audio()        == (sample_rate > 0 && nb_samples > 0 && channel_layout > 0 && samplefmt != AV_SAMPLE_FMT_NONE)\n                    - height()          == h\n                    - width()           == w\n                    - pixfmt()          == pixfmt\n                    - sample_rate()     == sample_rate\n                    - layout()          == channel_layout\n                    - samplefmt()       == samplefmt\n                    - get_timestamp()   == timestamp\n            !*/\n\n            void clear();\n            /*!\n                ensures\n                    - is_empty() == true\n            !*/\n\n        private:\n\n            friend class details::resampler;\n            friend class encoder;\n            friend class decoder;\n\n            void copy_from(const frame& other);\n\n            details::av_ptr<AVFrame> f;\n            std::chrono::system_clock::time_point timestamp;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class PixelType>\n        struct pix_traits\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a type trait for converting a sample type to ffmpeg's AVPixelFormat obj.\n            !*/\n        };\n\n        template<> struct pix_traits<uint8_t>           { constexpr static AVPixelFormat fmt = AV_PIX_FMT_GRAY8; };\n        template<> struct pix_traits<rgb_pixel>         { constexpr static AVPixelFormat fmt = AV_PIX_FMT_RGB24; };\n        template<> struct pix_traits<bgr_pixel>         { constexpr static AVPixelFormat fmt = AV_PIX_FMT_BGR24; };\n        template<> struct pix_traits<rgb_alpha_pixel>   { constexpr static AVPixelFormat fmt = AV_PIX_FMT_RGBA;  };\n        template<> struct pix_traits<bgr_alpha_pixel>   { constexpr static AVPixelFormat fmt = AV_PIX_FMT_BGRA;  };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class SampleType>\n        struct sample_traits \n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a type trait for converting a sample type to ffmpeg's AVSampleFormat obj.\n            !*/\n        };\n\n        template<> struct sample_traits<uint8_t> { constexpr static AVSampleFormat fmt = AV_SAMPLE_FMT_U8; };\n        template<> struct sample_traits<int16_t> { constexpr static AVSampleFormat fmt = AV_SAMPLE_FMT_S16; };\n        template<> struct sample_traits<int32_t> { constexpr static AVSampleFormat fmt = AV_SAMPLE_FMT_S32; };\n        template<> struct sample_traits<float>   { constexpr static AVSampleFormat fmt = AV_SAMPLE_FMT_FLT; };\n        template<> struct sample_traits<double>  { constexpr static AVSampleFormat fmt = AV_SAMPLE_FMT_DBL; };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class SampleType, std::size_t Channels>\n        struct audio\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object is a typed audio buffer which can convert to and back dlib::ffmpeg::frame.\n            !*/\n\n            using sample = std::array<SampleType, Channels>;\n            using format = SampleType;\n            constexpr static std::size_t nchannels = Channels;\n\n            std::vector<sample>                     samples;\n            float                                   sample_rate{0};\n            std::chrono::system_clock::time_point   timestamp{};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct codec_details\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object informs on available codecs provided by the installation of ffmpeg dlib is linked against.\n            !*/\n\n            AVCodecID   codec_id{AV_CODEC_ID_NONE};\n            std::string codec_name;\n            bool supports_encoding{false};\n            bool supports_decoding{false};\n        };\n\n        struct muxer_details\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object informs on available muxers provided by the installation of ffmpeg dlib is linked against.\n            !*/\n\n            std::string name;\n            std::vector<codec_details> supported_codecs;\n        };\n\n        struct device_details\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object informs on available device types provided by the installation of ffmpeg dlib is linked against.\n            !*/\n\n            std::string device_type;\n            bool        is_audio_type{false};\n            bool        is_video_type{false};\n        };\n\n        struct device_instance\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This object informs on the currently available device instances readable by ffmpeg.\n            !*/\n\n            std::string name;\n            std::string description;\n        };\n\n        const std::vector<std::string>& list_protocols();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg protocols\n        !*/\n\n        const std::vector<std::string>& list_demuxers();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg demuxers\n        !*/\n\n        const std::vector<muxer_details>& list_muxers();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg muxers\n        !*/\n        \n        const std::vector<codec_details>& list_codecs();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg codecs with information on whether decoding and/or encoding is supported.\n                  Note that not all codecs support encoding, unless your installation of ffmpeg is built with third party library\n                  dependencies like libx264, libx265, etc.\n        !*/\n\n        const std::vector<device_details>& list_input_device_types();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg input device types (e.g. alsa, v4l2, etc)\n        !*/\n\n        const std::vector<device_details>& list_output_device_types();\n        /*!\n            ensures\n                - returns a list of all available ffmpeg output device types (e.g. alsa, v4l2, etc)\n        !*/\n\n        std::vector<device_instance> list_input_device_instances(const std::string& device_type);\n        /*!\n            ensures\n                - returns a list of all available ffmpeg input device instances for device type *device_type (e.g. hw:0,0, /dev/video0, etc)\n        !*/\n\n        std::vector<device_instance> list_output_device_instances(const std::string& device_type);\n        /*!\n            ensures\n                - returns a list of all available ffmpeg output device instances for device type *device_type (e.g. hw:0,0, /dev/video0, etc)\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n    \n        struct video_enabled_t\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a strong type which controls whether or not we want\n                    to enable video decoding in demuxer or video encoding in muxer.\n\n                    For example, you can now use the convenience constructor:\n\n                        demuxer cap(filename, video_enabled, audio_disabled);\n            !*/\n\n            constexpr explicit video_enabled_t(bool enabled_) : enabled{enabled_} {}\n            bool enabled{false};\n        };\n\n        constexpr video_enabled_t video_enabled{true};\n        constexpr video_enabled_t video_disabled{false};\n\n        struct audio_enabled_t\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a strong type which controls whether or not we want\n                    to enable audio decoding in demuxer or audio encoding in muxer\n            !*/\n\n            constexpr explicit audio_enabled_t(bool enabled_) : enabled{enabled_} {}\n            bool enabled{false};\n        };\n\n        constexpr audio_enabled_t audio_enabled{true};\n        constexpr audio_enabled_t audio_disabled{false};\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type, \n          is_image_check<image_type> = true\n        >\n        void convert(const frame& f, image_type& image);\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h \n                - f.is_image() == true\n                - f.pixfmt() == pix_traits<pixel_type_t<image_type>>::fmt\n            ensures\n                - converts a frame object into array2d<rgb_pixel>\n        !*/\n\n        template <\n          class image_type, \n          is_image_check<image_type> = true\n        >\n        void convert(const image_type& img, frame& f);\n        /*!\n            requires\n                - image_type == an image object that implements the interface defined in\n                  dlib/image_processing/generic_image.h\n            ensures\n                - converts a dlib image into a frame object\n        !*/\n\n        template<class SampleFmt, std::size_t Channels>\n        void convert(const frame& f, audio<SampleFmt, Channels>& obj);\n        /*!\n            requires\n                - f.is_audio()  == true\n                - f.samplefmt() == sample_traits<SampleFmt>::fmt\n                - f.nchannels() == Channels\n            ensures\n                - converts a frame object into audio object\n        !*/\n\n        template<class SampleFmt, std::size_t Channels>\n        void convert(const audio<SampleFmt, Channels>& audio, frame& b);\n        /*!\n            ensures\n                - converts a dlib audio object into a frame object\n        !*/\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct resizing_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments used for resizing an image frame.\n                    When all arguments are zero or defaulted, then no resizing is undertaken,\n                    and the src frame is memcpy'd to the dst frame.\n\n                    Note:\n                        - \"fmt\" can take any value starting with AV_PIX_FMT_\n                          See libavutil/pixfmt.h for options.\n            !*/\n\n            int             h{0};\n            int             w{0};\n            AVPixelFormat   fmt{AV_PIX_FMT_NONE};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        struct resampling_args\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This class groups a set of arguments used for resampling an audio frame.\n                    When all arguments are zero or defaulted, then no resampling is undertaken,\n                    and the src frame is memcpy'd to the dst frame.\n\n                    Note:\n                        - \"channel_layout\" can take values starting with AV_CH_LAYOUT_ \n                          See libavutil/channel_layout.h for options.\n                        - \"fmt\" can take any value starting with AV_SAMPLE_FMT_\n                          See libavutil/samplefmt.h for options.\n            !*/\n\n            int             sample_rate{0};\n            uint64_t        channel_layout{0};\n            AVSampleFormat  fmt{AV_SAMPLE_FMT_NONE};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////// DEFINITIONS  ////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n\n// ---------------------------------------------------------------------------------------------------\n\n        namespace details\n        {\n            template<class... Args>\n            inline bool fail(Args&&... args)\n            {\n                auto ret = logger_dlib_wrapper() << LERROR;\n#ifdef __cpp_fold_expressions\n                ((ret << args),...);\n#else\n                (void)std::initializer_list<int>{((ret << args), 0)...};\n#endif\n                return false;\n            }\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline std::string get_pixel_fmt_str(AVPixelFormat fmt)\n        {\n            const char* name = av_get_pix_fmt_name(fmt);\n            return name ? std::string(name) : std::string(\"unknown\");\n        }\n\n        inline std::string get_audio_fmt_str(AVSampleFormat fmt)\n        {\n            const char* name = av_get_sample_fmt_name(fmt);\n            return name ? std::string(name) : std::string(\"unknown\");\n        }\n\n        inline std::string get_channel_layout_str(uint64_t channel_layout)\n        {\n            return details::get_channel_layout_str(channel_layout);\n        }    \n\n// ---------------------------------------------------------------------------------------------------\n\n        inline dlib::logger& logger_ffmpeg()\n        {\n            details::register_ffmpeg();\n            return details::logger_ffmpeg_private();\n        }\n\n        inline dlib::logger& logger_dlib_wrapper()\n        {\n            static dlib::logger GLOBAL(\"ffmpeg.dlib\");\n            return GLOBAL;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        namespace details\n        {\n        \n// ---------------------------------------------------------------------------------------------------\n\n            class resizer\n            {\n            public:\n                void resize(\n                    const frame &src,\n                    const int dst_h, const int dst_w, const AVPixelFormat dst_fmt,\n                    frame &dst\n                );\n\n                void resize(\n                    const frame &src,\n                    frame &dst\n                );\n\n            private:\n                av_ptr<SwsContext> imgConvertCtx;\n            };\n\n            inline void resizer::resize (\n                const frame& src,\n                const int dst_h, const int dst_w, const AVPixelFormat dst_fmt,\n                frame& dst\n            )\n            {\n                DLIB_CASSERT(src.is_image(), \"src.is_image() == false\");\n\n                imgConvertCtx.reset(sws_getCachedContext(imgConvertCtx.release(),\n                                                         src.width(), src.height(), src.pixfmt(),\n                                                         dst_w,       dst_h,        dst_fmt,\n                                                         SWS_FAST_BILINEAR, NULL, NULL, NULL));\n\n                const bool is_same_object = &src == &dst;\n                const bool is_copy = std::make_tuple(src.height(), src.width(), src.pixfmt()) == std::tie(dst_h, dst_w, dst_fmt);\n\n                if (is_same_object && is_copy)\n                    return;\n\n                frame* ptr = &dst;\n                frame tmp;\n\n                if (is_same_object)\n                    ptr = &tmp;\n                \n                ptr->set_params(dst_h, dst_w, dst_fmt, 0, 0, 0, AV_SAMPLE_FMT_NONE, src.get_timestamp());\n\n                sws_scale(imgConvertCtx.get(),\n                          src.get_frame().data,  src.get_frame().linesize, 0, src.height(),\n                          ptr->get_frame().data, ptr->get_frame().linesize);\n\n                if (is_same_object)\n                    dst = std::move(tmp);\n            }\n\n            inline void resizer::resize(\n                const frame& src,\n                frame& dst\n            )\n            {\n                resize(src, src.height(), src.width(), src.pixfmt(), dst);\n            }\n\n// ---------------------------------------------------------------------------------------------------\n\n            class resampler\n            {\n            public:\n                void reset(\n                    const int src_sample_rate, const uint64_t src_channel_layout, const AVSampleFormat src_fmt,\n                    const int dst_sample_rate, const uint64_t dst_channel_layout, const AVSampleFormat dst_fmt\n                );\n\n                void resize(\n                    const frame &src,\n                    const int dst_sample_rate, const uint64_t dst_channel_layout, const AVSampleFormat dst_fmt,\n                    frame &dst\n                );\n\n                void resize(\n                    const frame &src,\n                    frame &dst\n                );\n\n            private:\n\n                int             src_sample_rate{0};\n                uint64_t        src_channel_layout{AV_CH_LAYOUT_STEREO};\n                AVSampleFormat  src_fmt{AV_SAMPLE_FMT_NONE};\n\n                int             dst_sample_rate{0};\n                uint64_t        dst_channel_layout{AV_CH_LAYOUT_STEREO};\n                AVSampleFormat  dst_fmt{AV_SAMPLE_FMT_NONE};\n\n                av_ptr<SwrContext>  audioResamplerCtx;\n                uint64_t            tracked_samples{0};\n            };\n\n            inline void resampler::reset(\n                const int src_sample_rate_, const uint64_t src_channel_layout_, const AVSampleFormat src_fmt_,\n                const int dst_sample_rate_, const uint64_t dst_channel_layout_, const AVSampleFormat dst_fmt_\n            )\n            {\n                using namespace details;\n\n                auto this_params = std::tie(src_sample_rate,\n                                            src_channel_layout,\n                                            src_fmt,\n                                            dst_sample_rate,\n                                            dst_channel_layout,\n                                            dst_fmt);\n                auto new_params  = std::tie(src_sample_rate_,\n                                            src_channel_layout_,\n                                            src_fmt_,\n                                            dst_sample_rate_,\n                                            dst_channel_layout_,\n                                            dst_fmt_);\n\n                if (this_params != new_params)\n                {\n                    this_params = new_params;\n\n                    audioResamplerCtx = nullptr;\n\n                    if (std::tie(src_sample_rate, src_channel_layout, src_fmt) !=\n                        std::tie(dst_sample_rate, dst_channel_layout, dst_fmt))\n                    {\n#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100) \n                        AVChannelLayout layout_src = convert_layout(src_channel_layout);\n                        AVChannelLayout layout_dst = convert_layout(dst_channel_layout);\n                        \n                        SwrContext* ptr{nullptr};\n                        const int ret = swr_alloc_set_opts2(&ptr,\n                            &layout_dst, dst_fmt, dst_sample_rate,\n                            &layout_src, src_fmt, src_sample_rate,\n                            0, nullptr\n                        );\n                        DLIB_CASSERT(ret == 0, \"swr_alloc_set_opts2() failed : \" << get_av_error(ret));\n                        audioResamplerCtx.reset(ptr);\n#else\n                        audioResamplerCtx.reset(swr_alloc_set_opts(NULL,\n                                                                   dst_channel_layout, dst_fmt_, dst_sample_rate_,\n                                                                   src_channel_layout, src_fmt_, src_sample_rate_,\n                                                                   0, NULL));\n                        const int ret =  swr_init(audioResamplerCtx.get());\n                        DLIB_CASSERT(ret == 0, \"swr_init() failed : \" << get_av_error(ret));\n#endif\n                    }\n                }\n            }\n\n            inline void resampler::resize(\n                const frame&            src,\n                const int               dst_sample_rate_,\n                const uint64_t          dst_channel_layout_,\n                const AVSampleFormat    dst_samplefmt_,\n                frame&                  dst\n            )\n            {\n                using namespace details;\n                using std::chrono::system_clock;\n\n                DLIB_CASSERT(src.is_audio(), \"src.is_audio() == false\");\n\n                const bool is_same_object = std::addressof(src) == std::addressof(dst);\n\n                reset(src.sample_rate(),         src.layout(), src.samplefmt(),\n                      dst_sample_rate_,  dst_channel_layout_,  dst_samplefmt_);\n\n                if (audioResamplerCtx)\n                {\n                    av_ptr<AVFrame> tmp = make_avframe();\n                    tmp->sample_rate    = dst_sample_rate;\n                    tmp->format         = (int)dst_fmt;\n                    set_layout(tmp.get(), dst_channel_layout);\n\n                    const int ret = swr_convert_frame(audioResamplerCtx.get(), tmp.get(), &src.get_frame());\n                    if (ret < 0)\n                        throw std::runtime_error(\"swr_convert_frame() failed : \" + get_av_error(ret));\n\n                    dst.f           = std::move(tmp);\n                    dst.f->pts      = tracked_samples;\n                    dst.timestamp   = system_clock::time_point{system_clock::duration{av_rescale_q(tracked_samples,\n                                                                                        {1, dst_sample_rate},\n                                                                                        {system_clock::duration::period::num, system_clock::duration::period::den})}};\n                    tracked_samples += dst.nsamples();\n\n                }\n                else if (!is_same_object)\n                {\n                    dst = src;\n                }\n            }\n\n            inline void resampler::resize(\n                const frame& src,\n                frame& dst\n            )\n            {\n                resize(src, dst_sample_rate, dst_channel_layout, dst_fmt, dst);\n            }\n\n// ---------------------------------------------------------------------------------------------------\n\n            class audio_fifo\n            {\n            public:\n                audio_fifo() = default;\n\n                audio_fifo(\n                    const int            codec_frame_size,\n                    const AVSampleFormat sample_format,\n                    const int            nchannels\n                );\n\n                std::vector<frame> push_pull(\n                    frame &&in\n                );\n\n            private:\n\n                int                 frame_size{0};\n                AVSampleFormat      fmt{AV_SAMPLE_FMT_NONE};\n                int                 nchannels{0};\n                uint64_t            sample_count{0};\n                av_ptr<AVAudioFifo> fifo;\n            };\n\n            inline audio_fifo::audio_fifo(\n                const int            codec_frame_size_,\n                const AVSampleFormat sample_format_,\n                const int            nchannels_\n            ) : frame_size(codec_frame_size_),\n                fmt(sample_format_),\n                nchannels(nchannels_)\n            {\n                if (frame_size > 0)\n                {\n                    fifo.reset(av_audio_fifo_alloc(fmt, nchannels, frame_size));\n                    if (!fifo)\n                        throw std::runtime_error(\"av_audio_fifo_alloc() failed\");\n                }\n            }\n\n            inline std::vector<frame> audio_fifo::push_pull(\n                frame&& in\n            )\n            {\n                using std::chrono::system_clock;\n                DLIB_ASSERT(in.is_audio(), \"this isn't an audio frame\");\n\n                std::vector<frame> outs;\n\n                //check that the configuration hasn't suddenly changed this would be exceptional\n                auto current_params = std::tie(fmt, nchannels);\n                auto new_params     = std::make_tuple(in.samplefmt(), in.nchannels());\n\n                if (current_params != new_params)\n                    throw std::runtime_error(\"new audio frame params differ from first \");\n\n                if (frame_size == 0)\n                {\n                    outs.push_back(std::move(in));\n                }\n                else\n                {\n                    if (av_audio_fifo_write(fifo.get(), (void**)in.get_frame().data, in.nsamples()) != in.nsamples())\n                        throw std::runtime_error(\"av_audio_fifo_write() failed to write all samples\");\n\n                    while (av_audio_fifo_size(fifo.get()) >= frame_size)\n                    {\n                        const system_clock::time_point timestamp{system_clock::duration{av_rescale_q(\n                                sample_count,\n                                {1, in.sample_rate()},\n                                {system_clock::duration::period::num, system_clock::duration::period::den})}};\n\n                        frame out(in.sample_rate(), frame_size, in.layout(), in.samplefmt(), timestamp);\n\n                        if (av_audio_fifo_read(fifo.get(), (void**)out.get_frame().data, out.nsamples()) != out.nsamples())\n                            throw std::runtime_error(\"av_audio_fifo_read() failed to read all requested samples\");\n\n                        sample_count += out.nsamples();\n                        outs.push_back(std::move(out));\n                    }\n                }\n\n                return outs;\n            }\n\n// ---------------------------------------------------------------------------------------------------\n\n        }\n\n// ---------------------------------------------------------------------------------------------------\n        inline void frame::clear()\n        {\n            f = nullptr;\n            timestamp = std::chrono::system_clock::time_point{};\n        }\n\n        inline void frame::set_params(\n            int             h,\n            int             w,\n            AVPixelFormat   pixfmt,\n            int             sample_rate,\n            int             nb_samples,\n            uint64_t        channel_layout,\n            AVSampleFormat  samplefmt,\n            std::chrono::system_clock::time_point timestamp_\n        )\n        {\n            using namespace details;\n\n            const int format = (h > 0 && w > 0) ? (int)pixfmt : (int)samplefmt;\n\n            if (!f ||\n                std::tie(f->height, f->width, f->sample_rate, f->nb_samples, f->format) != \n                std::tie(   h,         w,        sample_rate,    nb_samples,    format) ||\n                get_layout(f.get()) != channel_layout)\n            {\n                f = make_avframe();\n                f->height           = h;\n                f->width            = w;\n                f->sample_rate      = sample_rate;\n                f->nb_samples       = nb_samples;\n                f->format           = h > 0 && w > 0 ? (int)pixfmt : (int)samplefmt;\n                set_layout(f.get(), channel_layout);\n\n                // The ffmpeg documentation recommends you always use align==0.\n                // However, in ffmpeg 3.2, there is a bug where if you do that, data buffers don't get allocated.\n                // So workaround is to manually set align==32\n                // Not ideal, but i've checked the source code in ffmpeg 3.3, 4.4 and 5.0 libavutil/frame.c\n                // and in every case, if align==0, then align=32\n                const int align = 32;\n\n                const int ret = av_frame_get_buffer(f.get(), align);\n                if (ret < 0)\n                {\n                    f = nullptr;\n                    throw std::runtime_error(\"av_frame_get_buffer() failed : \" + get_av_error(ret));\n                }\n            }\n\n            timestamp = timestamp_;\n            if (is_audio())\n                f->pts = av_rescale_q(timestamp.time_since_epoch().count(),\n                                      {decltype(timestamp)::period::num, (decltype(timestamp)::period::den)},\n                                      {1, f->sample_rate});\n        }\n\n        inline frame::frame(\n            int h,\n            int w,\n            AVPixelFormat fmt,\n            std::chrono::system_clock::time_point timestamp\n        )\n        {\n            set_params(h, w, fmt, 0, 0, 0, AV_SAMPLE_FMT_NONE, timestamp);\n        }\n\n        inline frame::frame(\n            int             sample_rate,\n            int             nb_samples,\n            uint64_t        channel_layout,\n            AVSampleFormat  fmt,\n            std::chrono::system_clock::time_point timestamp\n        )\n        {\n            set_params(0,0,AV_PIX_FMT_NONE, sample_rate, nb_samples, channel_layout, fmt, timestamp);\n        }\n\n        inline frame::frame(const frame &ori)\n        {\n            copy_from(ori);\n        }\n\n        inline frame& frame::operator=(const frame& ori)\n        {\n            if (this != &ori)\n                copy_from(ori);\n            return *this;\n        }\n\n        inline void frame::copy_from(const frame& ori)\n        {\n            using namespace details;\n\n            if (ori.is_empty())\n            {\n                clear();\n            }\n            else\n            {\n                if (is_empty() ||\n                    std::tie(    f->height,     f->width,     f->format,     f->sample_rate,     f->nb_samples) !=\n                    std::tie(ori.f->height, ori.f->width, ori.f->format, ori.f->sample_rate, ori.f->nb_samples) ||\n                    get_layout(f.get()) != get_layout(ori.f.get()))\n                {\n                    set_params(ori.f->height,\n                               ori.f->width,\n                               (AVPixelFormat)ori.f->format,\n                               ori.f->sample_rate,\n                               ori.f->nb_samples,\n                               ori.layout(),\n                               (AVSampleFormat)ori.f->format,\n                               ori.timestamp);\n                }\n\n                av_frame_copy(f.get(), ori.f.get());\n                av_frame_copy_props(f.get(), ori.f.get());\n                // The following silences a warning message about too many b-frames.\n                f->pict_type = AV_PICTURE_TYPE_NONE;\n            }\n        }\n\n        inline bool frame::is_image() const noexcept\n        {\n            return f && f->width > 0 && f->height > 0 && f->format != AV_PIX_FMT_NONE;\n        }\n\n        inline bool frame::is_audio() const noexcept\n        {\n            return f && f->nb_samples > 0 && f->sample_rate > 0 && f->format != AV_SAMPLE_FMT_NONE && !details::channel_layout_empty(f.get());\n        }\n\n        inline bool                 frame::is_empty()   const noexcept { return !is_image() && !is_audio(); }\n        inline AVPixelFormat        frame::pixfmt()     const noexcept { return is_image() ? (AVPixelFormat)f->format : AV_PIX_FMT_NONE; }\n        inline int                  frame::height()     const noexcept { return is_image() ? f->height : 0; }\n        inline int                  frame::width()      const noexcept { return is_image() ? f->width : 0; }\n        inline AVSampleFormat       frame::samplefmt()  const noexcept { return is_audio() ? (AVSampleFormat)f->format : AV_SAMPLE_FMT_NONE; }\n        inline int                  frame::nsamples()   const noexcept { return is_audio() ? f->nb_samples : 0; }\n        inline int                  frame::sample_rate() const noexcept{ return is_audio() ? f->sample_rate : 0; }\n        inline uint64_t             frame::layout()     const noexcept { return is_audio() ? details::get_layout(f.get()) : 0; }\n        inline int                  frame::nchannels()  const noexcept { return is_audio() ? details::get_nchannels(f.get()) : 0; } \n        inline const AVFrame&       frame::get_frame()  const { DLIB_CASSERT(f, \"is_empty() == true\"); return *f; }\n        inline AVFrame&             frame::get_frame()        { DLIB_CASSERT(f, \"is_empty() == true\"); return *f; }\n        inline std::chrono::system_clock::time_point frame::get_timestamp() const noexcept { return timestamp; }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<std::string>& list_protocols()\n        {\n            const static auto protocols = []\n            {\n                details::register_ffmpeg();\n                std::vector<std::string> protocols;\n                void* opaque = nullptr;\n                const char* name = 0;\n                while ((name = avio_enum_protocols(&opaque, 0)))\n                    protocols.emplace_back(name);\n\n                opaque  = nullptr;\n                name    = 0;\n\n                while ((name = avio_enum_protocols(&opaque, 1)))\n                    protocols.emplace_back(name);\n\n                return protocols;\n            }();\n\n            return protocols;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<std::string>& list_demuxers()\n        {\n            const static auto demuxers = []\n            {\n                details::register_ffmpeg();\n                std::vector<std::string> demuxers;\n                const AVInputFormat* demuxer = nullptr;\n\n#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)\n                // See https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L86\n                while ((demuxer = av_iformat_next(demuxer)))\n#else\n                void* opaque = nullptr;\n                while ((demuxer = av_demuxer_iterate(&opaque)))\n#endif\n                    demuxers.push_back(demuxer->name);\n\n                return demuxers;\n            }();\n\n            return demuxers;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline std::vector<codec_details> list_codecs_for_muxer (\n            const AVOutputFormat* oformat\n        )\n        {\n            std::vector<codec_details> supported_codecs;\n\n            for (const auto& codec : list_codecs())\n                if (avformat_query_codec(oformat, codec.codec_id, FF_COMPLIANCE_STRICT) == 1)\n                    supported_codecs.push_back(codec);\n            \n            return supported_codecs;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<muxer_details>& list_muxers()\n        {\n            const static auto ret = []\n            {\n                details::register_ffmpeg();\n\n                std::vector<muxer_details> all_details;\n                const AVOutputFormat* muxer = nullptr;\n\n#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)\n                // See https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L86\n                while ((muxer = av_oformat_next(muxer)))\n#else\n                void* opaque = nullptr;\n                while ((muxer = av_muxer_iterate(&opaque)))\n#endif\n                {\n                    muxer_details details;\n                    details.name                = muxer->name;\n                    details.supported_codecs    = list_codecs_for_muxer(muxer);\n                    all_details.push_back(details);\n                }      \n            \n                return all_details;\n            }();\n\n            return ret;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<codec_details>& list_codecs()\n        {\n            const static auto ret = []\n            {\n                details::register_ffmpeg();\n                std::vector<codec_details> details;\n\n        #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)\n                // See https://github.com/FFmpeg/FFmpeg/blob/70d25268c21cbee5f08304da95be1f647c630c15/doc/APIchanges#L91\n                AVCodec* codec = nullptr;\n                while ((codec = av_codec_next(codec)))\n        #else\n                const AVCodec* codec = nullptr;\n                void* opaque = nullptr;\n                while ((codec = av_codec_iterate(&opaque)))\n        #endif\n                {\n                    codec_details detail;\n                    detail.codec_id     = codec->id;\n                    detail.codec_name   = codec->name;\n                    detail.supports_encoding = av_codec_is_encoder(codec);\n                    detail.supports_decoding = av_codec_is_decoder(codec);\n                    details.push_back(std::move(detail));\n                }\n\n                //sort\n                std::sort(details.begin(), details.end(), [](const codec_details& a, const codec_details& b) {return a.codec_name < b.codec_name;});\n                //merge\n                for (size_t i = 0 ; i < details.size() ; ++i)\n                {\n                    for (size_t j = i + 1 ; j < details.size() ; ++j)\n                    {\n                        if (details[i].codec_name == details[j].codec_name)\n                        {\n                            details[i].supports_encoding |= details[j].supports_encoding;\n                            details[i].supports_decoding |= details[j].supports_decoding;\n                            details[j] = {};\n                        }\n                    }\n                }\n                \n                details.erase(std::remove_if(details.begin(), details.end(), [](const auto& d) {return d.codec_name.empty();}), details.end());\n\n                return details;\n            }();\n\n            return ret;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<device_details>& list_input_device_types()\n        {\n            const static auto ret = []\n            {\n                details::register_ffmpeg();\n                std::vector<device_details> devices;\n\n#if LIBAVDEVICE_VERSION_INT < AV_VERSION_INT(59, 0, 100)\n                using AVInputFormatPtr = AVInputFormat*;\n#else\n                using AVInputFormatPtr = const AVInputFormat*;\n#endif\n\n                AVInputFormatPtr device{nullptr};\n\n                while ((device = av_input_audio_device_next(device)))\n                {\n                    device_details details;\n                    details.device_type     = device->name;\n                    details.is_audio_type   = true;\n                    devices.push_back(std::move(details));\n                }\n\n                device = nullptr;\n\n                while ((device = av_input_video_device_next(device)))\n                {\n                    device_details details;\n                    details.device_type     = device->name;\n                    details.is_video_type   = true;\n                    devices.push_back(std::move(details));\n                }\n\n                return devices;\n            }();\n\n            return ret;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline std::vector<device_instance> list_input_device_instances(const std::string& device_type)\n        {\n            const auto& types = list_input_device_types();\n            auto ret = std::find_if(types.begin(), types.end(), [&](const auto& type) {return type.device_type == device_type;});\n            if (ret == types.end())\n                return {};\n\n            std::vector<device_instance> instances;\n\n            details::av_ptr<AVDeviceInfoList> managed;\n            AVDeviceInfoList* device_list = nullptr;\n            avdevice_list_input_sources(nullptr, ret->device_type.c_str(), nullptr, &device_list);\n            managed.reset(device_list);\n\n            if (device_list)\n            {\n                for (int i = 0 ; i < device_list->nb_devices ; ++i)\n                {\n                    device_instance instance;\n                    instance.name        = std::string(device_list->devices[i]->device_name);\n                    instance.description = std::string(device_list->devices[i]->device_description);\n                    instances.push_back(std::move(instance));\n                }\n            }\n\n            return instances;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline const std::vector<device_details>& list_output_device_types()\n        {\n            const static auto ret = []\n            {\n                details::register_ffmpeg();\n                std::vector<device_details> devices;\n\n    #if LIBAVDEVICE_VERSION_INT < AV_VERSION_INT(59, 0, 100)\n                using AVOutputFormatPtr = AVOutputFormat*;\n    #else\n                using AVOutputFormatPtr = const AVOutputFormat*;\n    #endif\n\n                AVOutputFormatPtr device{nullptr};\n\n                while ((device = av_output_audio_device_next(device)))\n                {\n                    device_details details;\n                    details.device_type     = std::string(device->name);\n                    details.is_audio_type   = true;\n                    devices.push_back(std::move(details));\n                }\n\n                device = nullptr;\n\n                while ((device = av_output_video_device_next(device)))\n                {\n                    device_details details;\n                    details.device_type     = std::string(device->name);\n                    details.is_video_type   = true;\n                    devices.push_back(std::move(details));\n                }\n\n                return devices;\n            }();\n\n            return ret;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline std::vector<device_instance> list_output_device_instances(const std::string& device_type)\n        {\n            const auto& types = list_output_device_types();\n            auto ret = std::find_if(types.begin(), types.end(), [&](const auto& type) {return type.device_type == device_type;});\n            if (ret == types.end())\n                return {};\n\n            std::vector<device_instance> instances;\n\n            details::av_ptr<AVDeviceInfoList> managed;\n            AVDeviceInfoList* device_list = nullptr;\n            avdevice_list_output_sinks(nullptr, ret->device_type.c_str(), nullptr, &device_list);\n            managed.reset(device_list);\n\n            if (device_list)\n            {\n                for (int i = 0 ; i < device_list->nb_devices ; ++i)\n                {\n                    device_instance instance;\n                    instance.name        = std::string(device_list->devices[i]->device_name);\n                    instance.description = std::string(device_list->devices[i]->device_description);\n                    instances.push_back(std::move(instance));\n                }\n            }\n\n            return instances;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class image_type, \n          is_image_check<image_type>\n        >\n        inline void convert(const frame& f, image_type& image)\n        {\n            using pixel = pixel_type_t<image_type>;\n            \n            DLIB_ASSERT(f.is_image(), \"frame isn't an image type\");\n            DLIB_ASSERT(f.pixfmt() == pix_traits<pixel>::fmt, \"frame doesn't have correct format\");\n        \n            image.set_size(f.height(), f.width());\n            const size_t imgsize = image.nr()*image.nc()*sizeof(pixel);\n            const size_t expsize = av_image_get_buffer_size(f.pixfmt(), f.width(), f.height(), 1);\n            DLIB_ASSERT(imgsize == expsize, \"image size in bytes != expected buffer size required by ffmpeg to do a copy\");\n            (void)imgsize;\n            (void)expsize;\n\n            const int ret = av_image_copy_to_buffer((uint8_t*)image.begin(), \n                                                    imgsize, \n                                                    f.get_frame().data, \n                                                    f.get_frame().linesize, \n                                                    f.pixfmt(), \n                                                    f.width(), \n                                                    f.height(), \n                                                    1);    \n            \n            DLIB_ASSERT(ret == (int)expsize, \"av_image_copy_to_buffer() error : \" << details::get_av_error(ret));\n            (void)ret;\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<\n          class image_type, \n          is_image_check<image_type>\n        >\n        inline void convert(const image_type& img, frame& f)\n        {\n            using pixel = pixel_type_t<image_type>;\n\n            if (f.height() != img.nr() ||\n                f.width()  != img.nc() ||\n                f.pixfmt() != pix_traits<pixel>::fmt)\n            {\n                f.set_params(img.nr(), img.nc(), pix_traits<pixel>::fmt, 0, 0, 0, AV_SAMPLE_FMT_NONE, {});\n            }\n\n            const size_t imgsize            = img.nr()*img.nc()*sizeof(pixel);\n            int         src_linesizes[4]    = {0};\n            uint8_t*    src_pointers[4]     = {nullptr};\n\n            const int ret = av_image_fill_arrays(src_pointers, src_linesizes, (uint8_t*)img.begin(), f.pixfmt(), f.width(), f.height(), 1);\n            DLIB_ASSERT(ret == imgsize, \"av_image_fill_arrays()  error : \" << details::get_av_error(ret));\n            (void)imgsize;\n            (void)ret;\n            \n            av_image_copy(f.get_frame().data,\n                          f.get_frame().linesize,\n                          (const uint8_t**)src_pointers,\n                          src_linesizes,\n                          f.pixfmt(),\n                          f.width(),\n                          f.height());\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class SampleFmt, std::size_t Channels>\n        inline void convert(const frame& f, audio<SampleFmt, Channels>& obj)\n        {\n            using sample = typename audio<SampleFmt, Channels>::sample;\n\n            DLIB_ASSERT(f.is_audio(), \"frame must be of audio type\");\n            DLIB_ASSERT(f.samplefmt() == sample_traits<SampleFmt>::fmt, \"audio buffer has wrong format for this type. Make sure correct args are passed to constructor of decoder/demuxer/encoder/muxer\");\n            DLIB_ASSERT(f.nchannels() == Channels, \"wrong number of channels\");\n\n            obj.timestamp   = f.get_timestamp();\n            obj.sample_rate = f.sample_rate();\n            obj.samples.resize(f.nsamples());\n\n            uint8_t* dst_pointers[8]    = {nullptr}; \n            int      dst_linesize       = 0;\n\n            const int bufsize  = obj.samples.size()*sizeof(sample);\n            const int expsize1 = av_samples_get_buffer_size(&dst_linesize, f.nchannels(), f.nsamples(), f.samplefmt(), 1);\n            const int expsize2 = av_samples_fill_arrays(dst_pointers, &dst_linesize, (uint8_t*)obj.samples.data(), f.nchannels(), f.nsamples(), f.samplefmt(), 1);\n            DLIB_ASSERT(bufsize == expsize1, \"audio size in bytes != expected buffer size required by ffmpeg to do a copy\");\n            DLIB_ASSERT(expsize1 == expsize2, \"inconsistent audio buffer sizes returned by ffmpeg\");\n            (void)bufsize;\n            (void)expsize1;\n            (void)expsize2;\n\n            av_samples_copy(dst_pointers, f.get_frame().data, 0, 0, f.nsamples(), f.nchannels(), f.samplefmt());\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        template<class SampleFmt, std::size_t Channels>\n        inline void convert(const audio<SampleFmt, Channels>& obj, frame& f)\n        {\n            using namespace details;\n            using sample = typename audio<SampleFmt, Channels>::sample;\n\n            if (f.samplefmt()   != sample_traits<SampleFmt>::fmt ||\n                f.layout()      != get_layout_from_channels(Channels) ||\n                f.sample_rate() != obj.sample_rate ||\n                f.nsamples()    != obj.samples.size())\n            {\n                f = frame(obj.sample_rate, \n                          obj.samples.size(), \n                          get_layout_from_channels(Channels), \n                          sample_traits<SampleFmt>::fmt, \n                          obj.timestamp);\n            }\n\n            uint8_t* src_pointers[8]    = {nullptr}; \n            int      src_linesize       = 0;\n\n            const int bufsize  = obj.samples.size()*sizeof(sample);\n            const int expsize1 = av_samples_get_buffer_size(&src_linesize, f.nchannels(), f.nsamples(), f.samplefmt(), 1);\n            const int expsize2 = av_samples_fill_arrays(src_pointers, &src_linesize, (const uint8_t*)obj.samples.data(), f.nchannels(), f.nsamples(), f.samplefmt(), 1);\n            DLIB_ASSERT(bufsize == expsize1, \"audio size in bytes != expected buffer size required by ffmpeg to do a copy\");\n            DLIB_ASSERT(expsize1 == expsize2, \"inconsistent audio buffer sizes returned by ffmpeg\");\n            (void)bufsize;\n            (void)expsize1;\n            (void)expsize2;\n\n            av_samples_copy(f.get_frame().data, src_pointers, 0, 0, f.nsamples(), f.nchannels(), f.samplefmt());\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif //DLIB_FFMPEG_UTILS\n"
  },
  {
    "path": "dlib/media/sink.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_FFMPEG_SINK\n#define DLIB_FFMPEG_SINK\n\n#include <cstdint>\n#include <vector>\n#include <ostream>\n#include \"../type_traits.h\"\n\nnamespace dlib\n{\n    namespace ffmpeg\n    {\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class Byte, \n          class Allocator,\n          std::enable_if_t<is_byte<Byte>::value, bool> = true\n        >\n        auto sink(std::vector<Byte, Allocator>& buf)\n        /*!\n            requires\n                - Byte must be a byte type, e.g. char, int8_t or uint8_t\n            ensures\n                - returns a function object with signature bool(std::size_t N, const char* data).  When\n                  called that function appends the first N bytes pointed to by data onto the end of buf.\n                - The returned function is valid only as long as buf exists.\n                - The function always returns true.        \n        !*/\n        {\n            return [&](std::size_t ndata, const char* data) {\n                buf.insert(buf.end(), data, data + ndata);\n                return true;\n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n        inline auto sink(std::ostream& out)\n        /*!\n            ensures\n                - returns a function object with signature bool(std::size_t N, const char* data).  When\n                  called that function writes the first N bytes pointed to by data to out.\n                - The returned view is valid only as long as out exists.\n                - Returns out.good(). I.e. returns true if the write to the stream succeeded and false otherwise.       \n        !*/\n        {\n            return [&](std::size_t ndata, const char* data) {\n                out.write(data, ndata);\n                return out.good();\n            };\n        }\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n}\n\n#endif //DLIB_FFMPEG_SINK"
  },
  {
    "path": "dlib/media.h",
    "content": "\n// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_MEDIA \n#define DLIB_MEDIA\n\n#include \"test_for_odr_violations.h\"\n\n#ifndef DLIB_USE_FFMPEG\nstatic_assert(false, \"This version of dlib isn't built with the FFMPEG wrappers\");\n#endif\n\n#include \"media/ffmpeg_utils.h\"\n#include \"media/ffmpeg_demuxer.h\"\n#include \"media/ffmpeg_muxer.h\"\n#include \"media/sink.h\"\n\n#endif // DLIB_MEDIA \n"
  },
  {
    "path": "dlib/member_function_pointer/make_mfp.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAKE_MFp_H_\n#define DLIB_MAKE_MFp_H_\n\n#include \"member_function_pointer_kernel_1.h\"\n#include \"make_mfp_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    member_function_pointer<> make_mfp (\n        T& object,\n        void (T::*cb)()\n    )\n    {\n        member_function_pointer<> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n    template <\n        typename T\n        >\n    member_function_pointer<> make_mfp (\n        const T& object,\n        void (T::*cb)()const\n    )\n    {\n        member_function_pointer<> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1\n        >\n    member_function_pointer<A1> make_mfp (\n        T& object,\n        void (T::*cb)(A1)\n    )\n    {\n        member_function_pointer<A1> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n    template <\n        typename T,\n        typename A1\n        >\n    member_function_pointer<A1> make_mfp (\n        const T& object,\n        void (T::*cb)(A1)const\n    )\n    {\n        member_function_pointer<A1> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2\n        >\n    member_function_pointer<A1,A2> make_mfp (\n        T& object,\n        void (T::*cb)(A1,A2)\n    )\n    {\n        member_function_pointer<A1,A2> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n    template <\n        typename T,\n        typename A1,\n        typename A2\n        >\n    member_function_pointer<A1,A2> make_mfp (\n        const T& object,\n        void (T::*cb)(A1,A2)const\n    )\n    {\n        member_function_pointer<A1,A2> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3\n        >\n    member_function_pointer<A1,A2,A3> make_mfp (\n        T& object,\n        void (T::*cb)(A1,A2,A3)\n    )\n    {\n        member_function_pointer<A1,A2,A3> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3\n        >\n    member_function_pointer<A1,A2,A3> make_mfp (\n        const T& object,\n        void (T::*cb)(A1,A2,A3)const\n    )\n    {\n        member_function_pointer<A1,A2,A3> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3,\n        typename A4\n        >\n    member_function_pointer<A1,A2,A3,A4> make_mfp (\n        T& object,\n        void (T::*cb)(A1,A2,A3,A4)\n    )\n    {\n        member_function_pointer<A1,A2,A3,A4> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3,\n        typename A4\n        >\n    member_function_pointer<A1,A2,A3,A4> make_mfp (\n        const T& object,\n        void (T::*cb)(A1,A2,A3,A4)const\n    )\n    {\n        member_function_pointer<A1,A2,A3,A4> temp;\n        temp.set(object, cb);\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAKE_MFp_H_\n\n\n\n"
  },
  {
    "path": "dlib/member_function_pointer/make_mfp_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MAKE_MFp_ABSTRACT_\n#ifdef DLIB_MAKE_MFp_ABSTRACT_\n\n#include \"member_function_pointer_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    member_function_pointer<> make_mfp (\n        T& object,\n        void (T::*cb)()\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP() will call (object.*cb)()\n    !*/\n\n    template <\n        typename T\n        >\n    member_function_pointer<> make_mfp (\n        const T& object,\n        void (T::*cb)()const\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP() will call (object.*cb)()\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1\n        >\n    member_function_pointer<A1> make_mfp (\n        T& object,\n        void (T::*cb)(A1 a1)\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1) will call (object.*cb)(a1)\n    !*/\n\n    template <\n        typename T,\n        typename A1\n        >\n    member_function_pointer<A1> make_mfp (\n        const T& object,\n        void (T::*cb)(A1 a1)const\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1) will call (object.*cb)(a1)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2\n        >\n    member_function_pointer<A1,A2> make_mfp (\n        T& object,\n        void (T::*cb)(A1 a1, A2 a2)\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2) will call (object.*cb)(a1,a2)\n    !*/\n\n    template <\n        typename T,\n        typename A1,\n        typename A2\n        >\n    member_function_pointer<A1,A2> make_mfp (\n        const T& object,\n        void (T::*cb)(A1 a1, A2 a2)const\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2) will call (object.*cb)(a1,a2)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3\n        >\n    member_function_pointer<A1,A2,A3> make_mfp (\n        T& object,\n        void (T::*cb)(A1 a1, A2 a2, A3 a3)\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2,a3) will call (object.*cb)(a1,a2,a3)\n    !*/\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3\n        >\n    member_function_pointer<A1,A2,A3> make_mfp (\n        const T& object,\n        void (T::*cb)(A1 a1, A2 a2, A3 a3)const\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2,a3) will call (object.*cb)(a1,a2,a3)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3,\n        typename A4\n        >\n    member_function_pointer<A1,A2,A3,A4> make_mfp (\n        T& object,\n        void (T::*cb)(A1 a1, A2 a2, A3 a3, A4 a4)\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2,a3,a4) will call (object.*cb)(a1,a2,a3,a4)\n    !*/\n\n    template <\n        typename T,\n        typename A1,\n        typename A2,\n        typename A3,\n        typename A4\n        >\n    member_function_pointer<A1,A2,A3,A4> make_mfp (\n        const T& object,\n        void (T::*cb)(A1 a1, A2 a2, A3 a3, A4 a4)const\n    );\n    /*!\n        requires\n            - cb == a valid member function pointer for class T\n        ensures\n            - returns a member function pointer object MFP such that:\n                - MFP.is_set() == true\n                - calls to MFP(a1,a2,a3,a4) will call (object.*cb)(a1,a2,a3,a4)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAKE_MFp_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/member_function_pointer/member_function_pointer_kernel_1.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_\n#define DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"member_function_pointer_kernel_abstract.h\"\n#include \"../enable_if.h\"\n#include <new>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1 = void,\n        typename PARAM2 = void,\n        typename PARAM3 = void,\n        typename PARAM4 = void\n        >\n    class member_function_pointer;\n\n// ----------------------------------------------------------------------------------------\n\n#define DLIB_MFP_SC DLIB_ASSERT(cb != 0,                                \\\n                   \"\\tvoid member_function_pointer::set\"                \\\n                   << \"\\n\\tthe member function pointer can't be null\"   \\\n                   << \"\\n\\tthis: \" << this   );\n\n\n#define DLIB_MFP_OC DLIB_ASSERT(this->is_set() == true ,                            \\\n                   \"\\tvoid member_function_pointer::operator()\"                     \\\n                   << \"\\n\\tYou must call set() before you can use this function\"    \\\n                   << \"\\n\\tthis: \" << this);\n\n// ----------------------------------------------------------------------------------------\n\n    template <unsigned long num_args>\n    class mfp_kernel_1_base_class\n    {\n        /*\n            All member function pointer classes inherit from this class.  This\n            is where most of the things in a member function pointer are defined.\n\n            The reason for the num_args template argument to this class is to prevent\n            any sort of implicit casting between derived member function pointer classes\n            that take different numbers of arguments.\n        */\n    protected:\n        enum mfp_type { mfp_nonconst, mfp_const, mfp_null};\n\n        class mp_base_base\n        {\n        public:\n            mp_base_base(void* ptr, mfp_type type_) : o(ptr),type(type_) {}\n            virtual ~mp_base_base(){}\n            virtual void clone(void* ptr) const = 0;\n            virtual bool is_same (const mp_base_base* item) const = 0;\n            bool is_set () const { return o!=0; }\n\n            void* const o;\n            const mfp_type type;\n        };\n\n        template <typename T>\n        class mp_null : public mp_base_base \n        {\n        public:\n            typedef void (T::*mfp_pointer_type)() ;\n\n            mp_null (void* , mfp_pointer_type ) : mp_base_base(0,mfp_null), callback(0) {}\n            mp_null () : mp_base_base(0,mfp_null), callback(0) {}\n\n            const mfp_pointer_type callback;\n        };\n\n        template <typename mp_impl>\n        class mp_impl_T : public mp_impl \n        {\n            /*\n                This class supplies the implementations clone() and is_same() for any\n                classes that inherit from mp_base_base.  It does this in a very\n                roundabout way...\n            */\n               \n        public:\n            typedef typename mp_impl::mfp_pointer_type mfp_pointer_type;\n\n            mp_impl_T() : mp_impl(0,0) {}\n            mp_impl_T(void* ptr, mfp_pointer_type cb) : mp_impl(ptr,cb) {}\n\n            template <unsigned long mem_size>\n            void safe_clone(stack_based_memory_block<mem_size>& buf)\n            {\n                // This is here just to validate the assumption that our block of memory we have made\n                // in mp_memory is the right size to store the data for this object.  If you\n                // get a compiler error on this line then email me :)\n                COMPILE_TIME_ASSERT(sizeof(mp_impl_T) <= mem_size);\n                clone(buf.get());\n            }\n\n            void clone   (void* ptr) const  { new(ptr) mp_impl_T(this->o,this->callback); }\n            bool is_same (const mp_base_base* item) const \n            {\n                if (item->o == 0 && this->o == 0)\n                {\n                    return true;\n                }\n                else if (item->o == this->o && this->type == item->type)\n                {\n                    const mp_impl* i = reinterpret_cast<const mp_impl*>(item);\n                    return (i->callback == this->callback);\n                }\n                return false;\n            }\n        };\n\n        // MSVC with the /vms option, we get C2287 since the dummy class requires virtual\n        // inheritance. Adding the __virtual_inheritance specifier explicitly fixes the issue,\n        // but then Clang-CL no longer accepts it.\n        #if defined(_MSC_VER) && !defined(__clang__)\n            #define DLIB_MSVC_INHERITANCE_VIRTUAL __virtual_inheritance\n        #else\n            #define DLIB_MSVC_INHERITANCE_VIRTUAL\n        #endif\n\n        struct dummy_base { virtual void nonnull() {}; virtual ~dummy_base(){}; int a; };\n        struct DLIB_MSVC_INHERITANCE_VIRTUAL dummy : virtual public dummy_base{ void nonnull() {}; };\n\n        #undef DLIB_MSVC_INHERITANCE_VIRTUAL\n\n        typedef mp_impl_T<mp_null<dummy> > mp_null_impl;\n    public:\n\n        mfp_kernel_1_base_class (\n            const mfp_kernel_1_base_class& item\n        ) { item.mp()->clone(mp_memory.get()); }\n\n        mfp_kernel_1_base_class (  \n        ) { mp_null_impl().safe_clone(mp_memory); }\n\n        bool operator == (\n            const mfp_kernel_1_base_class& item\n        ) const { return mp()->is_same(item.mp()); }\n\n        bool operator != (\n            const mfp_kernel_1_base_class& item\n        ) const { return !(*this == item); }\n\n        mfp_kernel_1_base_class& operator= (\n            const mfp_kernel_1_base_class& item\n        ) { mfp_kernel_1_base_class(item).swap(*this); return *this;  }\n\n        ~mfp_kernel_1_base_class (\n        ) { destroy_mp_memory(); }\n\n        void clear(\n        ) { mfp_kernel_1_base_class().swap(*this); }\n\n        bool is_set (\n        ) const { return mp()->is_set(); } \n\n    private:\n        typedef void (dummy::*safe_bool)();\n\n    public:\n        operator safe_bool () const { return is_set() ? &dummy::nonnull : 0; }\n        bool operator!() const { return !is_set(); }\n\n        void swap (\n            mfp_kernel_1_base_class& item\n        ) \n        {  \n            // make a temp copy of item\n            mfp_kernel_1_base_class temp(item);\n\n            // destory the stuff in item\n            item.destroy_mp_memory();\n            // copy *this into item\n            mp()->clone(item.mp_memory.get());\n\n            // destory the stuff in this \n            destroy_mp_memory();\n            // copy temp into *this\n            temp.mp()->clone(mp_memory.get());\n        }\n\n    protected:\n\n        // The reason for adding 1 here is because visual studio 2003 will sometimes\n        // try to compile this code with sizeof(mp_null_impl) == 0 (which is a bug in visual studio).\n        // Fortunately, no actual real instances of this template seem to end up with that screwed up\n        // value so everything works fine if we just add 1 so that this degenerate case doesn't cause\n        // trouble.  Note that we know it all works fine because safe_clone() checks the size of this\n        // memory block whenever the member function pointer is used.  \n        stack_based_memory_block<sizeof(mp_null_impl)+1> mp_memory;\n\n        void destroy_mp_memory (\n        )\n        {\n            // Honestly this probably doesn't even do anything but I'm putting\n            // it here just for good measure.\n            mp()->~mp_base_base();\n        }\n\n        mp_base_base*       mp ()       { return static_cast<mp_base_base*>(mp_memory.get()); }\n        const mp_base_base* mp () const { return static_cast<const mp_base_base*>(mp_memory.get()); }\n        \n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    class member_function_pointer<void,void,void,void> : public mfp_kernel_1_base_class<0>\n    {\n        class mp_base : public mp_base_base {\n        public:\n            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}\n            virtual void call() const = 0;\n        };\n\n        template <typename T>\n        class mp_impl : public mp_base {\n        public:\n            typedef void (T::*mfp_pointer_type)() ;\n            void call () const { (static_cast<T*>(this->o)->*callback)(); }\n\n            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n        template <typename T>\n        class mp_impl_const : public mp_base {\n        public:\n            typedef void ((T::*mfp_pointer_type)()const);\n            void call () const  { (static_cast<const T*>(this->o)->*callback)(); }\n\n            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n    public:\n        typedef void param1_type;\n        typedef void param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        // These two typedefs are here for backwards compatibility with previous versions\n        // of dlib.\n        typedef member_function_pointer kernel_1a;\n        typedef member_function_pointer kernel_1a_c;\n\n\n        void operator() () const { DLIB_MFP_OC; static_cast<const mp_base*>(mp_memory.get())->call(); }\n\n        // the reason for putting disable_if on this function is that it avoids an overload\n        // resolution bug in visual studio.\n        template <typename T> typename disable_if<is_const_type<T>,void>::type \n        set(T& object, typename mp_impl<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }\n\n        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1\n        >\n    class member_function_pointer<PARAM1,void,void,void> : public mfp_kernel_1_base_class<1>\n    {\n        class mp_base : public mp_base_base {\n        public:\n            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}\n            virtual void call(PARAM1) const = 0;\n        };\n\n        template <typename T>\n        class mp_impl : public mp_base {\n        public:\n            typedef void (T::*mfp_pointer_type)(PARAM1) ;\n            void call (PARAM1 p1) const { (static_cast<T*>(this->o)->*callback)(p1); }\n\n            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n        template <typename T>\n        class mp_impl_const : public mp_base {\n        public:\n            typedef void ((T::*mfp_pointer_type)(PARAM1)const);\n            void call (PARAM1 p1) const  { (static_cast<const T*>(this->o)->*callback)(p1); }\n\n            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n    public:\n        typedef PARAM1 param1_type;\n        typedef void param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        // These two typedefs are here for backwards compatibility with previous versions\n        // of dlib.\n        typedef member_function_pointer kernel_1a;\n        typedef member_function_pointer kernel_1a_c;\n\n\n        void operator() (PARAM1 p1) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1); }\n\n        // the reason for putting disable_if on this function is that it avoids an overload\n        // resolution bug in visual studio.\n        template <typename T> typename disable_if<is_const_type<T>,void>::type \n        set(T& object, typename mp_impl<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }\n\n        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2\n        >\n    class member_function_pointer<PARAM1,PARAM2,void,void> : public mfp_kernel_1_base_class<2>\n    {\n        class mp_base : public mp_base_base {\n        public:\n            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}\n            virtual void call(PARAM1,PARAM2) const = 0;\n        };\n\n        template <typename T>\n        class mp_impl : public mp_base {\n        public:\n            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2) ;\n            void call (PARAM1 p1, PARAM2 p2) const { (static_cast<T*>(this->o)->*callback)(p1,p2); }\n\n            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n        template <typename T>\n        class mp_impl_const : public mp_base {\n        public:\n            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2)const);\n            void call (PARAM1 p1, PARAM2 p2) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2); }\n\n            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        // These two typedefs are here for backwards compatibility with previous versions\n        // of dlib.\n        typedef member_function_pointer kernel_1a;\n        typedef member_function_pointer kernel_1a_c;\n\n        void operator() (PARAM1 p1, PARAM2 p2) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2); }\n\n        // the reason for putting disable_if on this function is that it avoids an overload\n        // resolution bug in visual studio.\n        template <typename T> typename disable_if<is_const_type<T>,void>::type \n        set(T& object, typename mp_impl<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }\n\n        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2,\n        typename PARAM3\n        >\n    class member_function_pointer<PARAM1,PARAM2,PARAM3,void> : public mfp_kernel_1_base_class<3>\n    {\n        class mp_base : public mp_base_base {\n        public:\n            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}\n            virtual void call(PARAM1,PARAM2,PARAM3) const = 0;\n        };\n\n        template <typename T>\n        class mp_impl : public mp_base {\n        public:\n            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3) ;\n            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3); }\n\n            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n        template <typename T>\n        class mp_impl_const : public mp_base {\n        public:\n            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3)const);\n            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3); }\n\n            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef PARAM3 param3_type;\n        typedef void param4_type;\n\n        // These two typedefs are here for backwards compatibility with previous versions\n        // of dlib.\n        typedef member_function_pointer kernel_1a;\n        typedef member_function_pointer kernel_1a_c;\n\n        void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3); }\n\n        // the reason for putting disable_if on this function is that it avoids an overload\n        // resolution bug in visual studio.\n        template <typename T> typename disable_if<is_const_type<T>,void>::type \n        set(T& object, typename mp_impl<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }\n\n        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2,\n        typename PARAM3,\n        typename PARAM4\n        >\n    class member_function_pointer : public mfp_kernel_1_base_class<4>\n    {\n        class mp_base : public mp_base_base {\n        public:\n            mp_base(void* ptr, mfp_type type_) : mp_base_base(ptr,type_) {}\n            virtual void call(PARAM1,PARAM2,PARAM3,PARAM4) const = 0;\n        };\n\n        template <typename T>\n        class mp_impl : public mp_base {\n        public:\n            typedef void (T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3, PARAM4) ;\n            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const { (static_cast<T*>(this->o)->*callback)(p1,p2,p3,p4); }\n\n            mp_impl      ( void* object, mfp_pointer_type cb) : mp_base(object, mfp_nonconst), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n        template <typename T>\n        class mp_impl_const : public mp_base {\n        public:\n            typedef void ((T::*mfp_pointer_type)(PARAM1,PARAM2,PARAM3,PARAM4)const);\n            void call (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const  { (static_cast<const T*>(this->o)->*callback)(p1,p2,p3,p4); }\n\n            mp_impl_const ( void* object, mfp_pointer_type cb) : mp_base(object,mfp_const), callback(cb) {}\n            const mfp_pointer_type callback;\n        };\n\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef PARAM3 param3_type;\n        typedef PARAM4 param4_type;\n\n        // These two typedefs are here for backwards compatibility with previous versions\n        // of dlib.\n        typedef member_function_pointer kernel_1a;\n        typedef member_function_pointer kernel_1a_c;\n\n        void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const \n        { DLIB_MFP_OC;  static_cast<const mp_base*>(mp_memory.get())->call(p1,p2,p3,p4); }\n\n        // the reason for putting disable_if on this function is that it avoids an overload\n        // resolution bug in visual studio.\n        template <typename T> typename disable_if<is_const_type<T>,void>::type \n        set(T& object, typename mp_impl<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory); }\n\n        template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) \n        { DLIB_MFP_SC;  destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory); }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/member_function_pointer/member_function_pointer_kernel_abstract.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_\n#ifdef DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1 = void,\n        typename PARAM2 = void,\n        typename PARAM3 = void,\n        typename PARAM4 = void\n        >\n    class member_function_pointer;\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    class member_function_pointer<void,void,void,void>\n    {\n        /*!\n            INITIAL VALUE\n                is_set() == false\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a member function pointer.  It is useful because\n                instances of this object can be created without needing to know the type\n                of object whose member function we will be calling.\n\n                There are five template specializations of this object.  The first \n                represents a pointer to a member function taking no parameters, the\n                second represents a pointer to a member function taking one parameter, \n                the third to one taking two parameters, and so on.\n\n                You specify the parameters to your member function pointer by filling in\n                the PARAM template parameters.  For example:\n\n                    To use a pointer to a function with no parameters you would say:\n                        member_function_pointer<> my_pointer;\n                    To use a pointer to a function that takes a single int you would say:\n                        member_function_pointer<int> my_pointer;\n                    To use a pointer to a function that takes an int and then a reference\n                    to a string you would say:\n                        member_function_pointer<int,string&> my_pointer;\n\n                Also note that the formal comments are only present for the first \n                template specialization.  They are all exactly the same except for the \n                number of parameters each takes in its member function pointer.\n        !*/\n\n    public:\n        typedef void param1_type;\n        typedef void param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        member_function_pointer (  \n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n        !*/\n\n        member_function_pointer(\n            const member_function_pointer& item\n        );\n        /*!\n            ensures\n                - *this == item\n        !*/\n\n        ~member_function_pointer (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n        !*/\n\n        member_function_pointer& operator=(\n            const member_function_pointer& item\n        );\n        /*!\n            ensures\n                - *this == item\n        !*/\n\n        bool operator == (\n            const member_function_pointer& item\n        ) const;\n        /*!\n            ensures\n                - if (is_set() == false && item.is_set() == false) then\n                    - returns true\n                - else if (both *this and item point to the same member function\n                  in the same object instance) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        bool operator != (\n            const member_function_pointer& item\n        ) const;\n        /*!\n            ensures\n                - returns !(*this == item)\n        !*/\n\n        void clear(\n        );\n        /*!\n            ensures\n                - #*this has its initial value\n        !*/\n\n        bool is_set (\n        ) const;\n        /*!\n            ensures\n                - if (this->set() has been called) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        template <\n            typename T\n            >\n        void set (\n            T& object,\n            void (T::*cb)()\n        );\n        /*!\n            requires\n                - cb == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*cb)()\n        !*/\n\n        template <\n            typename T\n            >\n        void set (\n            const T& object,\n            void (T::*cb)()const\n        );\n        /*!\n            requires\n                - cb == a valid member function pointer for class T\n            ensures\n                - #is_set() == true\n                - calls to this->operator() will call (object.*cb)()\n        !*/\n\n        operator some_undefined_pointer_type (\n        ) const;\n        /*!\n            ensures\n                - if (is_set()) then\n                    - returns a non 0 value\n                - else\n                    - returns a 0 value\n        !*/\n\n        bool operator! (\n        ) const;\n        /*!\n            ensures\n                - returns !is_set()\n        !*/\n\n        void operator () (\n        ) const;\n        /*!\n            requires\n                - is_set() == true\n            ensures\n                - calls the member function on the object specified by the last \n                  call to this->set()\n            throws\n                - any exception thrown by the member function specified by\n                  the previous call to this->set().\n                    If any of these exceptions are thrown then the call to this \n                    function will have no effect on *this.                  \n        !*/\n\n        void swap (\n            member_function_pointer& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/ \n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1\n        >\n    class member_function_pointer<PARAM1,void,void,void>\n    {\n    public:\n        typedef PARAM1 param1_type;\n        typedef void param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        member_function_pointer ();\n\n        member_function_pointer(\n            const member_function_pointer& item\n        );\n\n        ~member_function_pointer (\n        );\n\n        member_function_pointer& operator=(\n            const member_function_pointer& item\n        );\n\n        bool operator == (\n            const member_function_pointer& item\n        ) const;\n\n        bool operator != (\n            const member_function_pointer& item\n        ) const;\n\n        void clear();\n\n        bool is_set () const;\n\n        template <typename T>\n        void set (\n            T& object,\n            void (T::*cb)(PARAM1)\n        );\n\n        template <typename T>\n        void set (\n            const T& object,\n            void (T::*cb)(PARAM1)const\n        );\n\n        operator some_undefined_pointer_type (\n        ) const;\n\n        bool operator! (\n        ) const;\n\n        void operator () (\n            PARAM1 param1\n        ) const;\n\n        void swap (\n            member_function_pointer& item\n        );\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2\n        >\n    class member_function_pointer<PARAM1,PARAM2,void,void>\n    {\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef void param3_type;\n        typedef void param4_type;\n\n        member_function_pointer ();\n\n        member_function_pointer(\n            const member_function_pointer& item\n        );\n\n        ~member_function_pointer (\n        );\n\n        member_function_pointer& operator=(\n            const member_function_pointer& item\n        );\n\n        bool operator == (\n            const member_function_pointer& item\n        ) const;\n\n        bool operator != (\n            const member_function_pointer& item\n        ) const;\n\n        void clear();\n\n        bool is_set () const;\n\n        template <typename T>\n        void set (\n            T& object,\n            void (T::*cb)(PARAM1,PARAM2)\n        );\n\n        template <typename T>\n        void set (\n            const T& object,\n            void (T::*cb)(PARAM1,PARAM2)const\n        );\n\n        operator some_undefined_pointer_type (\n        ) const;\n\n        bool operator! (\n        ) const;\n\n        void operator () (\n            PARAM1 param1,\n            PARAM2 param2\n        ) const;\n\n        void swap (\n            member_function_pointer& item\n        );\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2,\n        typename PARAM3\n        >\n    class member_function_pointer<PARAM1,PARAM2,PARAM3,void>\n    {\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef PARAM3 param3_type;\n        typedef void param4_type;\n\n        member_function_pointer ();\n\n        member_function_pointer(\n            const member_function_pointer& item\n        );\n\n        ~member_function_pointer (\n        );\n\n        member_function_pointer& operator=(\n            const member_function_pointer& item\n        );\n\n        bool operator == (\n            const member_function_pointer& item\n        ) const;\n\n        bool operator != (\n            const member_function_pointer& item\n        ) const;\n\n        void clear();\n\n        bool is_set () const;\n\n        template <typename T>\n        void set (\n            T& object,\n            void (T::*cb)(PARAM1,PARAM2,PARAM3)\n        );\n\n        template <typename T>\n        void set (\n            const T& object,\n            void (T::*cb)(PARAM1,PARAM2,PARAM3)const\n        );\n\n        operator some_undefined_pointer_type (\n        ) const;\n\n        bool operator! (\n        ) const;\n\n        void operator () (\n            PARAM1 param1,\n            PARAM2 param2,\n            PARAM2 param3\n        ) const;\n\n        void swap (\n            member_function_pointer& item\n        );\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename PARAM1,\n        typename PARAM2,\n        typename PARAM3,\n        typename PARAM4\n        >\n    class member_function_pointer\n    {\n    public:\n        typedef PARAM1 param1_type;\n        typedef PARAM2 param2_type;\n        typedef PARAM3 param3_type;\n        typedef PARAM4 param4_type;\n\n        member_function_pointer ();\n\n        member_function_pointer(\n            const member_function_pointer& item\n        );\n\n        ~member_function_pointer (\n        );\n\n        member_function_pointer& operator=(\n            const member_function_pointer& item\n        );\n\n        bool operator == (\n            const member_function_pointer& item\n        ) const;\n\n        bool operator != (\n            const member_function_pointer& item\n        ) const;\n\n        void clear();\n\n        bool is_set () const;\n\n        template <typename T>\n        void set (\n            T& object,\n            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)\n        );\n\n        template <typename T>\n        void set (\n            const T& object,\n            void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)const\n        );\n\n        operator some_undefined_pointer_type (\n        ) const;\n\n        bool operator! (\n        ) const;\n\n        void operator () (\n            PARAM1 param1,\n            PARAM2 param2,\n            PARAM2 param3,\n            PARAM2 param4\n        ) const;\n\n        void swap (\n            member_function_pointer& item\n        );\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n\n}\n\n#endif // DLIB_MEMBER_FUNCTION_POINTER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/member_function_pointer.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMBER_FUNCTION_POINTEr_\n#define DLIB_MEMBER_FUNCTION_POINTEr_\n\n#include \"member_function_pointer/member_function_pointer_kernel_1.h\"\n#include \"member_function_pointer/make_mfp.h\"\n\n#endif // DLIB_MEMBER_FUNCTION_POINTEr_ \n\n"
  },
  {
    "path": "dlib/memory_manager/memory_manager_kernel_1.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_KERNEl_1_\n#define DLIB_MEMORY_MANAGER_KERNEl_1_\n\n#include \"../algs.h\"\n#include \"memory_manager_kernel_abstract.h\"\n#include \"../assert.h\"\n#include <new>\n\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        size_t max_pool_size\n        >\n    class memory_manager_kernel_1\n    {\n        /*!            \n            INITIAL VALUE\n                allocations == 0\n                next == 0\n                pool_size == 0\n\n            REQUIREMENTS ON max_pool_size \n                max_pool_size is the maximum number of nodes we will keep in our linked list at once.\n                So you can put any value in for this argument.\n\n            CONVENTION\n                This memory manager implementation allocates T objects one at a time when there are\n                allocation requests.  Then when there is a deallocate request the returning T object\n                is place into a list of free blocks if that list has less than max_pool_size \n                blocks in it.  subsequent allocation requests will be serviced by drawing from the\n                free list whenever it isn't empty.\n\n\n                allocations == get_number_of_allocations()\n\n                - if (next != 0) then\n                    - next == the next pointer to return from allocate()\n                      and next == pointer to the first node in a linked list.  each node\n                      is one item in the memory pool.    \n                    - the last node in the linked list has next set to 0\n                    - pool_size == the number of nodes in the linked list\n                    - pool_size <= max_pool_size\n                - else\n                    - we need to call new to get the next pointer to return from allocate()\n\n        !*/\n\n        union node\n        {\n            node* next;\n            char item[sizeof(T)];\n        };\n\n    public:\n\n        typedef T type;\n\n        template <typename U>\n        struct rebind {\n            typedef memory_manager_kernel_1<U,max_pool_size> other;\n        };\n\n\n        memory_manager_kernel_1(\n        ) :\n            allocations(0),\n            next(0),\n            pool_size(0)\n        {\n        }\n\n        virtual ~memory_manager_kernel_1(\n        )\n        {\n\n            while (next != 0)\n            {\n                node* temp = next;\n                next = next->next;\n                ::operator delete ( static_cast<void*>(temp));\n            }\n        }\n\n        size_t get_number_of_allocations (\n        ) const { return allocations; }\n\n        T* allocate_array (\n            size_t size\n        )\n        {\n            T* temp = new T[size];\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate_array (\n            T* item\n        )\n        {\n            --allocations;\n            delete [] item;\n        }\n\n        T* allocate (\n        ) \n        {              \n            T* temp;\n            if (next != 0)\n            {\n                temp = reinterpret_cast<T*>(next);\n\n                node* n = next->next;\n\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    next->next = n;\n                    throw;\n                }\n\n                next = n;\n\n                --pool_size;\n            }\n            else\n            {\n                temp = static_cast<T*>(::operator new(sizeof(node)));\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    // construction of the new object threw so delete the block of memory\n                    ::operator delete ( static_cast<void*>(temp));\n                    throw;\n                }\n            }\n\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate (\n            T* item\n        ) \n        { \n            --allocations;  \n            item->~T();\n\n            if (pool_size >= max_pool_size)\n            {\n                ::operator delete ( static_cast<void*>(item));\n                return;\n            }\n\n            // add this memory chunk into our linked list.\n            node* temp = reinterpret_cast<node*>(item);\n            temp->next = next;\n            next = temp;                \n            ++pool_size;\n        }\n\n        void swap (\n            memory_manager_kernel_1& item\n        ) \n        { \n            exchange(allocations,item.allocations); \n            exchange(next,item.next); \n            exchange(pool_size,item.pool_size);\n        }\n\n    private:\n\n        // data members\n        size_t allocations;\n        node* next;\n        size_t pool_size;\n\n        // restricted functions\n        memory_manager_kernel_1(memory_manager_kernel_1&);        // copy constructor\n        memory_manager_kernel_1& operator=(memory_manager_kernel_1&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    class memory_manager_kernel_1<T,0>\n    {\n        /*!            \n            INITIAL VALUE\n                allocations == 0\n\n            CONVENTION\n                This memory manager just calls new and delete directly so it doesn't \n                really do anything.\n\n                allocations == get_number_of_allocations()\n        !*/\n\n    public:\n\n        typedef T type;\n\n        template <typename U>\n        struct rebind {\n            typedef memory_manager_kernel_1<U,0> other;\n        };\n\n\n        memory_manager_kernel_1(\n        ) :\n            allocations(0)\n        {\n        }\n\n        virtual ~memory_manager_kernel_1(\n        )\n        {\n        }\n\n        size_t get_number_of_allocations (\n        ) const { return allocations; }\n\n        T* allocate_array (\n            size_t size\n        )\n        {\n            T* temp = new T[size];\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate_array (\n            T* item\n        )\n        {\n            --allocations;\n            delete [] item;\n        }\n\n        T* allocate (\n        ) \n        {              \n            T* temp = new T;\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate (\n            T* item\n        ) \n        { \n            delete item;\n            --allocations;  \n        }\n\n        void swap (\n            memory_manager_kernel_1& item\n        ) \n        { \n            exchange(allocations,item.allocations); \n        }\n\n    private:\n\n        // data members\n        size_t allocations;\n\n        // restricted functions\n        memory_manager_kernel_1(memory_manager_kernel_1&);        // copy constructor\n        memory_manager_kernel_1& operator=(memory_manager_kernel_1&);    // assignment operator\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        size_t max_pool_size\n        >\n    inline void swap (\n        memory_manager_kernel_1<T,max_pool_size>& a, \n        memory_manager_kernel_1<T,max_pool_size>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_KERNEl_1_\n\n\n\n"
  },
  {
    "path": "dlib/memory_manager/memory_manager_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_KERNEl_2_\n#define DLIB_MEMORY_MANAGER_KERNEl_2_\n\n#include \"../algs.h\"\n#include \"memory_manager_kernel_abstract.h\"\n#include \"../assert.h\"\n#include <new>\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        size_t chunk_size\n        >\n    class memory_manager_kernel_2\n    {\n        /*!            \n            INITIAL VALUE\n                allocations == 0\n                next == 0\n                first_chunk == 0\n\n            REQUIREMENTS ON chunk_size\n                chunk_size is the number of items of type T we will allocate at a time. so\n                it must be > 0.\n\n            CONVENTION\n                This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T)\n                bytes.  All the sizeof(T) subblocks are kept in a linked list of free memory blocks\n                and are given out whenever an allocation request occurs.  Also, memory is not freed\n                until this object is destructed.  \n\n                Note that array allocations are not memory managed.\n                \n\n\n                allocations == get_number_of_allocations()\n\n                - if (next != 0) then\n                    - next == the next pointer to return from allocate()\n                      and next == pointer to the first node in a linked list.  each node\n                      is one item in the memory pool.    \n                    - the last node in the linked list has next set to 0\n                - else\n                    - we need to call new to get the next pointer to return from allocate()\n\n\n                - if (first_chunk != 0) then\n                    - first_chunk == the first node in a linked list that contains pointers \n                      to all the chunks we have ever allocated.  The last link in the list\n                      has its next pointer set to 0.\n        !*/\n\n        union node\n        {\n            node* next;\n            char item[sizeof(T)];\n        };\n\n        struct chunk_node\n        {\n            node* chunk;\n            chunk_node* next;\n        };\n\n    public:\n\n        typedef T type;\n\n        template <typename U>\n        struct rebind {\n            typedef memory_manager_kernel_2<U,chunk_size> other;\n        };\n\n\n        memory_manager_kernel_2(\n        ) :\n            allocations(0),\n            next(0),\n            first_chunk(0)\n        {\n            // You FOOL!  You can't have a zero chunk_size.\n            COMPILE_TIME_ASSERT(chunk_size > 0);\n        }\n\n        virtual ~memory_manager_kernel_2(\n        )\n        {\n            if (allocations == 0)\n            {\n                while (first_chunk != 0)\n                {\n                    chunk_node* temp = first_chunk;\n                    first_chunk = first_chunk->next;\n                    // delete the memory chunk \n                    ::operator delete ( static_cast<void*>(temp->chunk));\n                    // delete the chunk_node\n                    delete temp;\n                }\n            }\n        }\n\n        size_t get_number_of_allocations (\n        ) const { return allocations; }\n\n        T* allocate_array (\n            size_t size\n        )\n        {\n            T* temp = new T[size];\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate_array (\n            T* item\n        )\n        {\n            --allocations;\n            delete [] item;\n        }\n\n        T* allocate (\n        ) \n        {              \n            T* temp = 0;\n            if (next != 0)\n            {\n                temp = reinterpret_cast<T*>(next);\n                node* n = next->next;\n\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    next->next = n;\n                    throw;\n                }\n\n                next = n;\n            }\n            else\n            {\n                // the linked list is empty so we need to allocate some more memory\n                node* block = 0;\n                block = static_cast<node*>(::operator new (sizeof(node)*chunk_size));\n\n                // the first part of this block can be our new object\n                temp = reinterpret_cast<T*>(block);\n\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    // construction of the new object threw so delete the block of memory\n                    ::operator delete ( static_cast<void*>(block));\n                    throw;\n                }\n\n                // allocate a new chunk_node\n                chunk_node* chunk;\n                try {chunk = new chunk_node; }\n                catch (...) \n                { \n                    temp->~T();\n                    ::operator delete ( static_cast<void*>(block));\n                    throw;\n                }\n\n                // add this block into the chunk list\n                chunk->chunk = block;\n                chunk->next = first_chunk;\n                first_chunk = chunk;\n\n\n                ++block;\n                // now add the rest of the block into the linked list of free nodes.\n                for (size_t i = 0; i < chunk_size-1; ++i)\n                {\n                    block->next = next;\n                    next = block;\n                    ++block;\n                }\n\n            }\n\n\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate (\n            T* item\n        ) \n        { \n            --allocations;  \n            item->~T();\n\n            // add this memory into our linked list.\n            node* temp = reinterpret_cast<node*>(item);\n            temp->next = next;\n            next = temp;                \n        }\n\n        void swap (\n            memory_manager_kernel_2& item\n        ) \n        { \n            exchange(allocations,item.allocations); \n            exchange(next,item.next); \n            exchange(first_chunk,item.first_chunk);\n        }\n\n    private:\n\n        // data members\n        size_t allocations;\n        node* next;\n\n        chunk_node* first_chunk;\n\n\n\n\n        // restricted functions\n        memory_manager_kernel_2(memory_manager_kernel_2&);        // copy constructor\n        memory_manager_kernel_2& operator=(memory_manager_kernel_2&);    // assignment operator\n    };\n\n    template <\n        typename T,\n        size_t chunk_size\n        >\n    inline void swap (\n        memory_manager_kernel_2<T,chunk_size>& a, \n        memory_manager_kernel_2<T,chunk_size>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/memory_manager/memory_manager_kernel_3.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_KERNEl_3_\n#define DLIB_MEMORY_MANAGER_KERNEl_3_\n\n#include \"../algs.h\"\n#include \"memory_manager_kernel_abstract.h\"\n#include \"../assert.h\"\n#include <new>\n#include \"memory_manager_kernel_2.h\"\n#include \"../binary_search_tree/binary_search_tree_kernel_2.h\"\n\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        size_t chunk_size\n        >\n    class memory_manager_kernel_3\n    {\n        /*!            \n            INITIAL VALUE\n                allocations == 0\n                next == 0\n                first_chunk == 0\n                bst_of_arrays == 0\n\n            REQUIREMENTS ON chunk_size\n                chunk_size is the number of items of type T we will allocate at a time. so\n                it must be > 0.\n\n            CONVENTION\n                This memory manager implementation allocates memory in blocks of chunk_size*sizeof(T)\n                bytes.  All the sizeof(T) subblocks are kept in a linked list of free memory blocks\n                and are given out whenever an allocation request occurs.  Also, memory is not freed\n                until this object is destructed.  \n                \n\n\n                allocations == get_number_of_allocations()\n\n                - if (next != 0) then\n                    - next == the next pointer to return from allocate()\n                      and next == pointer to the first node in a linked list.  each node\n                      is one item in the memory pool.    \n                    - the last node in the linked list has next set to 0\n                - else\n                    - we need to call new to get the next pointer to return from allocate()\n\n                - if (arrays != 0) then\n                    - someone has called allocate_array()\n                    - (*arrays)[size] == an array of size bytes of memory  \n\n                - if (first_chunk != 0) then\n                    - first_chunk == the first node in a linked list that contains pointers \n                      to all the chunks we have ever allocated.  The last link in the list\n                      has its next pointer set to 0.\n        !*/\n\n        union node\n        {\n            node* next;\n            char item[sizeof(T)];\n        };\n\n        struct chunk_node\n        {\n            node* chunk;\n            chunk_node* next;\n        };\n\n\n        typedef binary_search_tree_kernel_2<\n            size_t,\n            char*,\n            memory_manager_kernel_2<char,5>\n            > bst_of_arrays; \n\n    public:\n\n        typedef T type;\n\n        template <typename U>\n        struct rebind {\n            typedef memory_manager_kernel_3<U,chunk_size> other;\n        };\n\n\n        memory_manager_kernel_3(\n        ) :\n            allocations(0),\n            next(0),\n            first_chunk(0),\n            arrays(0)\n        {\n            // You FOOL!  You can't have a zero chunk_size.\n            COMPILE_TIME_ASSERT(chunk_size > 0);\n        }\n\n        virtual ~memory_manager_kernel_3(\n        )\n        {\n            if (allocations == 0)\n            {\n                while (first_chunk != 0)\n                {\n                    chunk_node* temp = first_chunk;\n                    first_chunk = first_chunk->next;\n                    // delete the memory chunk \n                    ::operator delete ( static_cast<void*>(temp->chunk));\n                    // delete the chunk_node\n                    delete temp;\n                }\n            }\n\n            if (arrays)\n            {\n                arrays->reset();\n                while (arrays->move_next())\n                {\n                    ::operator delete (arrays->element().value());\n                }\n                delete arrays;\n            }\n        }\n\n        size_t get_number_of_allocations (\n        ) const { return allocations; }\n\n        T* allocate_array (\n            size_t size\n        )\n        {\n            size_t block_size = sizeof(T)*size + sizeof(size_t)*2;\n\n            // make sure we have initialized the arrays object.\n            if (arrays == 0)\n            {\n                arrays = new bst_of_arrays;\n            }\n\n            char* temp;\n\n            // see if we have a suitable block of memory already.\n            arrays->position_enumerator(block_size);\n            if (arrays->current_element_valid())\n            {\n                // we have a suitable block of memory already so use that one.\n                arrays->remove_current_element(block_size,temp); \n            }\n            else\n            {\n                temp = static_cast<char*>(::operator new(block_size));\n            }\n\n            reinterpret_cast<size_t*>(temp)[0] = block_size;\n            reinterpret_cast<size_t*>(temp)[1] = size;\n            temp += sizeof(size_t)*2;\n\n            try\n            {\n                initialize_array(reinterpret_cast<T*>(temp),size);\n            }\n            catch (...)\n            {\n                // something was thrown while we were initializing the array so\n                // stick our memory block into arrays and rethrow the exception\n                temp -= sizeof(size_t)*2;\n                arrays->add(block_size,temp);\n                throw;\n            }\n\n            ++allocations;\n            return reinterpret_cast<T*>(temp);\n        }\n\n        void deallocate_array (\n            T* item\n        )\n        {\n            char* temp = reinterpret_cast<char*>(item);\n            temp -= sizeof(size_t)*2;\n            size_t block_size = reinterpret_cast<size_t*>(temp)[0];\n            size_t size = reinterpret_cast<size_t*>(temp)[1];\n\n            deinitialize_array(item,size);\n\n            arrays->add(block_size,temp);\n            \n            --allocations;\n        }\n\n        T* allocate (\n        ) \n        {              \n            T* temp;\n            if (next != 0)\n            {\n                temp = reinterpret_cast<T*>(next);\n                node* n = next->next;\n\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    next->next = n;\n                    throw;\n                }\n\n                next = n;\n            }\n            else\n            {\n                // the linked list is empty so we need to allocate some more memory\n                node* block = static_cast<node*>(::operator new (sizeof(node)*chunk_size));\n\n                // the first part of this block can be our new object\n                temp = reinterpret_cast<T*>(block);\n\n                try\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(temp))T();\n                }\n                catch (...)\n                {\n                    // construction of the new object threw so delete the block of memory\n                    ::operator delete ( static_cast<void*>(block));\n                    throw;\n                }\n\n                // allocate a new chunk_node\n                chunk_node* chunk;\n                try {chunk = new chunk_node; }\n                catch (...) \n                { \n                    temp->~T();\n                    ::operator delete ( static_cast<void*>(block));\n                    throw;\n                }\n\n                // add this block into the chunk list\n                chunk->chunk = block;\n                chunk->next = first_chunk;\n                first_chunk = chunk;\n\n\n                ++block;\n                // now add the rest of the block into the linked list of free nodes.\n                for (size_t i = 0; i < chunk_size-1; ++i)\n                {\n                    block->next = next;\n                    next = block;\n                    ++block;\n                }\n\n            }\n\n\n            ++allocations;\n            return temp;\n        }\n\n        void deallocate (\n            T* item\n        ) \n        { \n            --allocations;  \n            item->~T();\n\n            // add this memory into our linked list.\n            node* temp = reinterpret_cast<node*>(item);\n            temp->next = next;\n            next = temp;                \n        }\n\n        void swap (\n            memory_manager_kernel_3& item\n        ) \n        { \n            exchange(allocations,item.allocations); \n            exchange(next,item.next); \n            exchange(first_chunk,item.first_chunk);\n            exchange(arrays,item.arrays);\n        }\n\n    private:\n\n        // data members\n        size_t allocations;\n        node* next;\n\n        chunk_node* first_chunk;\n        bst_of_arrays* arrays;\n\n\n        void initialize_array (\n            T* array,\n            size_t size\n        ) const\n        {\n            size_t i;\n            try\n            {\n                for (i = 0; i < size; ++i)\n                {\n                    // construct this new T object with placement new.\n                    new (static_cast<void*>(array+i))T();\n                }\n            }\n            catch (...)\n            {\n                // Catch any exceptions thrown during the construction process\n                // and then destruct any T objects that actually were successfully\n                // constructed.\n                for (size_t j = 0; j < i; ++j)\n                {\n                    array[i].~T();\n                }\n                throw;\n            }\n        }\n\n        void deinitialize_array (\n            T* array,\n            size_t size\n        ) const\n        {\n            for (size_t i = 0; i < size; ++i)\n            {\n                array[i].~T();\n            }\n        }\n\n        // don't do any initialization for the built in types\n        void initialize_array(unsigned char*, size_t) {} \n        void deinitialize_array(unsigned char*, size_t) {}\n        void initialize_array(signed char*, size_t) {} \n        void deinitialize_array(signed char*, size_t) {}\n        void initialize_array(char*, size_t) {} \n        void deinitialize_array(char*, size_t) {}\n        void initialize_array(int*, size_t) {} \n        void deinitialize_array(int*, size_t) {}\n        void initialize_array(unsigned int*, size_t) {} \n        void deinitialize_array(unsigned int*, size_t) {}\n        void initialize_array(unsigned long*, size_t) {} \n        void deinitialize_array(unsigned long*, size_t) {}\n        void initialize_array(long*, size_t) {} \n        void deinitialize_array(long*, size_t) {}\n        void initialize_array(float*, size_t) {} \n        void deinitialize_array(float*, size_t) {}\n        void initialize_array(double*, size_t) {} \n        void deinitialize_array(double*, size_t) {}\n        void initialize_array(short*, size_t) {} \n        void deinitialize_array(short*, size_t) {}\n        void initialize_array(unsigned short*, size_t) {} \n        void deinitialize_array(unsigned short*, size_t) {}\n\n\n\n        // restricted functions\n        memory_manager_kernel_3(memory_manager_kernel_3&);        // copy constructor\n        memory_manager_kernel_3& operator=(memory_manager_kernel_3&);    // assignment operator\n    };\n\n    template <\n        typename T,\n        size_t chunk_size\n        >\n    inline void swap (\n        memory_manager_kernel_3<T,chunk_size>& a, \n        memory_manager_kernel_3<T,chunk_size>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_KERNEl_3_\n\n"
  },
  {
    "path": "dlib/memory_manager/memory_manager_kernel_abstract.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_\n#ifdef DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n    template <\n        typename T\n        >\n    class memory_manager\n    {\n        /*!      \n            REQUIREMENTS ON T\n                T must have a default constructor.      \n\n            INITIAL VALUE\n                get_number_of_allocations() == 0\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some kind of memory manager or memory pool.\n        !*/\n        \n        public:\n\n            typedef T type;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager<U> other;\n            };\n\n            memory_manager(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n            !*/\n\n            virtual ~memory_manager(\n            ); \n            /*!\n                ensures\n                    - if (get_number_of_allocations() == 0) then\n                        - all resources associated with *this have been released.\n                    - else\n                        - The memory still allocated will not be deleted and this\n                          causes a memory leak. \n            !*/\n\n            size_t get_number_of_allocations (\n            ) const;\n            /*!\n                ensures\n                    - returns the current number of outstanding allocations\n            !*/\n \n            T* allocate (\n            );\n            /*!\n                ensures\n                    - allocates a new object of type T and returns a pointer to it.\n                    - #get_number_of_allocations() == get_number_of_allocations() + 1\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      this->allocate(). (i.e. you can't deallocate a pointer you\n                      got from a different memory_manager instance.)\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - deallocates the object pointed to by item\n                    - #get_number_of_allocations() == get_number_of_allocations() - 1\n            !*/\n\n            T* allocate_array (\n                size_t size\n            );\n            /*!\n                ensures\n                    - allocates a new array of size objects of type T and returns a \n                      pointer to it.\n                    - #get_number_of_allocations() == get_number_of_allocations() + 1\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate_array (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      this->allocate_array(). (i.e. you can't deallocate a pointer you\n                      got from a different memory_manager instance and it must be an\n                      array.)\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - deallocates the array pointed to by item\n                    - #get_number_of_allocations() == get_number_of_allocations() - 1\n            !*/\n\n            void swap (\n                memory_manager& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n        private:\n\n            // restricted functions\n            memory_manager(memory_manager&);        // copy constructor\n            memory_manager& operator=(memory_manager&);    // assignment operator\n    };\n\n    template <\n        typename T\n        >\n    inline void swap (\n        memory_manager<T>& a, \n        memory_manager<T>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/memory_manager.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGEr_\n#define DLIB_MEMORY_MANAGEr_\n\n#include \"memory_manager/memory_manager_kernel_1.h\"\n#include \"memory_manager/memory_manager_kernel_2.h\"\n#include \"memory_manager/memory_manager_kernel_3.h\"\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename T\n        >\n    class memory_manager\n    {\n        memory_manager() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1        \n        typedef      memory_manager_kernel_1<T,0>\n                     kernel_1a;\n        typedef      memory_manager_kernel_1<T,10>\n                     kernel_1b;\n        typedef      memory_manager_kernel_1<T,100>\n                     kernel_1c;\n        typedef      memory_manager_kernel_1<T,1000>\n                     kernel_1d;\n        typedef      memory_manager_kernel_1<T,10000>\n                     kernel_1e;\n        typedef      memory_manager_kernel_1<T,100000>\n                     kernel_1f;\n      \n        // kernel_2        \n        typedef      memory_manager_kernel_2<T,10>\n                     kernel_2a;\n        typedef      memory_manager_kernel_2<T,100>\n                     kernel_2b;\n        typedef      memory_manager_kernel_2<T,1000>\n                     kernel_2c;\n        typedef      memory_manager_kernel_2<T,10000>\n                     kernel_2d;\n        typedef      memory_manager_kernel_2<T,100000>\n                     kernel_2e;\n      \n      \n        // kernel_3        \n        typedef      memory_manager_kernel_3<T,10>\n                     kernel_3a;\n        typedef      memory_manager_kernel_3<T,100>\n                     kernel_3b;\n        typedef      memory_manager_kernel_3<T,1000>\n                     kernel_3c;\n        typedef      memory_manager_kernel_3<T,10000>\n                     kernel_3d;\n        typedef      memory_manager_kernel_3<T,100000>\n                     kernel_3e;\n      \n      \n           \n\n    };\n}\n\n#endif // DLIB_MEMORY_MANAGEr_\n\n"
  },
  {
    "path": "dlib/memory_manager_global/memory_manager_global_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_GLOBAl_1_\n#define DLIB_MEMORY_MANAGER_GLOBAl_1_\n\n#include \"../algs.h\"\n#include \"../memory_manager/memory_manager_kernel_abstract.h\"\n#include \"memory_manager_global_kernel_abstract.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        typename factory\n        >\n    class memory_manager_global_kernel_1\n    {\n        /*!      \n            INITIAL VALUE\n                - *global_mm == get_global_memory_manager()\n\n            CONVENTION\n                - global_mm->get_number_of_allocations() == get_number_of_allocations()\n                - *global_mm == get_global_memory_manager()\n        !*/\n        \n        public:\n\n            typedef typename factory::template return_type<T>::type mm_global_type; \n\n            typedef T type;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager_global_kernel_1<U,factory> other;\n            };\n\n            memory_manager_global_kernel_1(\n            ) :\n                global_mm(factory::template get_instance<T>())\n            {}\n\n            virtual ~memory_manager_global_kernel_1(\n            )  {}\n\n            size_t get_number_of_allocations (\n            ) const { return global_mm->get_number_of_allocations(); }\n\n            mm_global_type& get_global_memory_manager (\n            ) { return *global_mm; }\n\n            T* allocate (\n            )\n            {\n                return global_mm->allocate(); \n            }\n\n            void deallocate (\n                T* item\n            )\n            {\n                global_mm->deallocate(item); \n            }\n\n            T* allocate_array (\n                size_t size\n            ) \n            { \n                return global_mm->allocate_array(size); \n            }\n\n            void deallocate_array (\n                T* item\n            ) \n            { \n                global_mm->deallocate_array(item); \n            }\n\n            void swap (\n                memory_manager_global_kernel_1& item\n            )\n            {\n                exchange(item.global_mm, global_mm);\n            }\n\n        private:\n\n            mm_global_type* global_mm;\n\n\n            // restricted functions\n            memory_manager_global_kernel_1(memory_manager_global_kernel_1&);        // copy constructor\n            memory_manager_global_kernel_1& operator=(memory_manager_global_kernel_1&);    // assignment operator\n    };\n\n    template <\n        typename T,\n        typename factory\n        >\n    inline void swap (\n        memory_manager_global_kernel_1<T,factory>& a, \n        memory_manager_global_kernel_1<T,factory>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_GLOBAl_1_\n\n\n\n"
  },
  {
    "path": "dlib/memory_manager_global/memory_manager_global_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_\n#ifdef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_\n\n#include \"../algs.h\"\n#include \"../memory_manager/memory_manager_kernel_abstract.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        typename factory\n        >\n    class memory_manager_global\n    {\n        /*!      \n            REQUIREMENTS ON T\n                T must have a default constructor.      \n\n            REQUIREMENTS ON factory\n                factory must be defined as follows:\n                struct factory\n                {\n                    template <typename U>\n                    struct return_type {\n                        typedef typename memory_manager_type<U> type;\n                    };\n\n                    template <typename U>\n                    static typename return_type<U>::type* get_instance (\n                    );\n                    / *!\n                        ensures\n                            - returns a pointer to an instance of a memory_manager object\n                              where memory_manager_type implements the interface defined \n                              by dlib/memory_manager/memory_manager_kernel_abstract.h\n                    !* /\n                };\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some kind of global memory manager or memory pool.  \n                It is identical to the memory_manager object except that it gets all of \n                its allocations from a global instance of a memory_manager object which \n                is provided by the factory object's static member get_instance().\n\n            THREAD SAFETY\n                This object is, by itself, threadsafe.  However, if you want to use this\n                object in multiple threads then you must ensure that your factory is\n                threadsafe.  This means its factory::get_instance() method should be \n                threadsafe and the memory_manager object it returns must also be threadsafe.\n        !*/\n        \n        public:\n\n            typedef typename factory::template return_type<T>::type mm_global_type; \n\n            typedef T type;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager_global<U,factory> other;\n            };\n\n            memory_manager_global(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                    - #get_global_memory_manager() == the memory manager that was \n                      returned by a call to factory::get_instance<T>()\n                throws\n                    - std::bad_alloc\n            !*/\n\n            virtual ~memory_manager_global(\n            ); \n            /*!\n                ensures\n                    - This destructor has no effect on the global memory_manager\n                      get_global_memory_manager().\n            !*/\n\n            size_t get_number_of_allocations (\n            ) const;\n            /*!\n                ensures\n                    - returns get_global_memory_manager().get_number_of_allocations()\n            !*/\n\n            mm_global_type& get_global_memory_manager (\n            );\n            /*!\n                ensures\n                    - returns a reference to the global memory manager instance being\n                      used by *this.\n            !*/\n\n            T* allocate (\n            );\n            /*!\n                ensures\n                    - #get_number_of_allocations() == get_number_of_allocations() + 1\n                    - returns get_global_memory_manager().allocate()\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      the get_global_memory_manager() object's allocate() method.\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - calls get_global_memory_manager().deallocate(item)\n                    - #get_number_of_allocations() == get_number_of_allocations() - 1\n            !*/\n\n            T* allocate_array (\n                size_t size\n            );\n            /*!\n                ensures\n                    - #get_number_of_allocations() == get_number_of_allocations() + 1\n                    - returns get_global_memory_manager().allocate_array()\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate_array() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate_array (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      the get_global_memory_manager() object's allocate_array() method.\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - calls get_global_memory_manager().deallocate_array(item)\n                    - #get_number_of_allocations() == get_number_of_allocations() - 1\n            !*/\n\n            void swap (\n                memory_manager_global& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n        private:\n\n            // restricted functions\n            memory_manager_global(memory_manager_global&);        // copy constructor\n            memory_manager_global& operator=(memory_manager_global&);    // assignment operator\n    };\n\n    template <\n        typename T,\n        typename factory\n        >\n    inline void swap (\n        memory_manager_global<T,factory>& a, \n        memory_manager_global<T,factory>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/memory_manager_global.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_GLOBAl_\n#define DLIB_MEMORY_MANAGER_GLOBAl_\n\n#include \"memory_manager_global/memory_manager_global_kernel_1.h\"\n#include \"memory_manager.h\"\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename factory\n        >\n    class memory_manager_global\n    {\n        memory_manager_global() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1        \n        typedef      memory_manager_global_kernel_1<T,factory>\n                     kernel_1a;\n      \n      \n           \n\n    };\n}\n\n#endif // DLIB_MEMORY_MANAGER_GLOBAl_\n\n"
  },
  {
    "path": "dlib/memory_manager_stateless/memory_manager_stateless_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_STATELESs_1_\n#define DLIB_MEMORY_MANAGER_STATELESs_1_\n\n#include \"memory_manager_stateless_kernel_abstract.h\"\n#include <memory>\n\nnamespace dlib\n{\n    template <\n        typename T\n        >\n    class memory_manager_stateless_kernel_1\n    {\n        /*!      \n            this implementation just calls new and delete directly\n        !*/\n        \n        public:\n\n            typedef T type;\n            const static bool is_stateless = true;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager_stateless_kernel_1<U> other;\n            };\n\n            memory_manager_stateless_kernel_1(\n            )\n            {}\n\n            virtual ~memory_manager_stateless_kernel_1(\n            ) {}\n\n            T* allocate (\n            )\n            {\n                return new T; \n            }\n\n            void deallocate (\n                T* item\n            )\n            {\n                delete item;\n            }\n\n            T* allocate_array (\n                size_t size\n            ) \n            { \n                return new T[size];\n            }\n\n            void deallocate_array (\n                T* item\n            ) \n            { \n                delete [] item;\n            }\n\n            void swap (memory_manager_stateless_kernel_1&)\n            {}\n\n            std::unique_ptr<T> extract(\n                T* item\n            )\n            {\n                return std::unique_ptr<T>(item);\n            }\n\n            std::unique_ptr<T[]> extract_array(\n                T* item\n            )\n            {\n                return std::unique_ptr<T[]>(item);\n            }\n\n        private:\n\n            // restricted functions\n            memory_manager_stateless_kernel_1(memory_manager_stateless_kernel_1&);        // copy constructor\n            memory_manager_stateless_kernel_1& operator=(memory_manager_stateless_kernel_1&);    // assignment operator\n    };\n\n    template <\n        typename T\n        >\n    inline void swap (\n        memory_manager_stateless_kernel_1<T>& a, \n        memory_manager_stateless_kernel_1<T>& b \n    ) { a.swap(b); }   \n\n}\n\n#endif // DLIB_MEMORY_MANAGER_STATELESs_1_\n\n\n\n"
  },
  {
    "path": "dlib/memory_manager_stateless/memory_manager_stateless_kernel_2.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_STATELESs_2_\n#define DLIB_MEMORY_MANAGER_STATELESs_2_\n\n#include \"../algs.h\"\n#include \"memory_manager_stateless_kernel_abstract.h\"\n#include \"../threads.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        typename mem_manager \n        >\n    class memory_manager_stateless_kernel_2\n    {\n        /*!      \n            REQUIREMENTS ON mem_manager\n                mem_manager must be an implementation of memory_manager/memory_manager_kernel_abstract.h\n\n            CONVENTION\n                this object has a single global instance of mem_manager \n        !*/\n\n        public:\n\n            typedef T type;\n            const static bool is_stateless = true;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager_stateless_kernel_2<U,mem_manager> other;\n            };\n\n            memory_manager_stateless_kernel_2(\n            )\n            { \n                // call this just to make sure the mutex is is initialized before \n                // multiple threads start calling the member functions.\n                global_mutex();\n            }\n\n            virtual ~memory_manager_stateless_kernel_2(\n            ) {}\n\n            T* allocate (\n            )\n            {\n                auto_mutex M(global_mutex());\n                return global_mm().allocate();\n            }\n\n            void deallocate (\n                T* item\n            )\n            {\n                auto_mutex M(global_mutex());\n                return global_mm().deallocate(item);\n            }\n\n            T* allocate_array (\n                size_t size\n            ) \n            { \n                auto_mutex M(global_mutex());\n                return global_mm().allocate_array(size);\n            }\n\n            void deallocate_array (\n                T* item\n            ) \n            { \n                auto_mutex M(global_mutex());\n                return global_mm().deallocate_array(item);\n            }\n\n            void swap (memory_manager_stateless_kernel_2&)\n            {}\n\n        private:\n\n            static mutex& global_mutex (\n            )\n            {\n                static mutex lock;\n                return lock;\n            }\n\n            typedef typename mem_manager::template rebind<T>::other rebound_mm_type; \n\n            static rebound_mm_type& global_mm (\n            ) \n            {\n                static rebound_mm_type mm;\n                return mm;\n            }\n\n            // restricted functions\n            memory_manager_stateless_kernel_2(memory_manager_stateless_kernel_2&);        // copy constructor\n            memory_manager_stateless_kernel_2& operator=(memory_manager_stateless_kernel_2&);    // assignment operator\n    };\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        memory_manager_stateless_kernel_2<T,mem_manager>& a, \n        memory_manager_stateless_kernel_2<T,mem_manager>& b \n    ) { a.swap(b); }   \n\n}\n\n#endif // DLIB_MEMORY_MANAGER_STATELESs_2_\n\n\n\n\n"
  },
  {
    "path": "dlib/memory_manager_stateless/memory_manager_stateless_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_\n#ifdef DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_\n\n#include \"../algs.h\"\n#include <memory>\n\nnamespace dlib\n{\n    template <\n        typename T\n        >\n    class memory_manager_stateless\n    {\n        /*!      \n            REQUIREMENTS ON T\n                T must have a default constructor.      \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents some kind of stateless memory manager or memory pool.  \n                Stateless means that all instances (instances of the same kernel implementation that is) \n                of this object are identical and can be used interchangeably.  Note that \n                implementations are allowed to have some shared global state such as a \n                global memory pool.\n\n            THREAD SAFETY\n                This object is thread safe.  You may access it from any thread at any time\n                without synchronizing access.\n        !*/\n        \n        public:\n\n            typedef T type;\n            const static bool is_stateless = true;\n\n            template <typename U>\n            struct rebind {\n                typedef memory_manager_stateless<U> other;\n            };\n\n            memory_manager_stateless(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n            !*/\n\n            virtual ~memory_manager_stateless(\n            ); \n            /*!\n                ensures\n                    - frees any resources used by *this but has no effect on any shared global\n                      resources used by the implementation.\n            !*/\n\n            T* allocate (\n            );\n            /*!\n                ensures\n                    - allocates a new object of type T and returns a pointer to it.\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      allocate(). (i.e. The pointer you are deallocating must have\n                      come from the same implementation of memory_manager_stateless\n                      that is trying to deallocate it.)\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - deallocates the object pointed to by item\n            !*/\n\n            T* allocate_array (\n                size_t size\n            );\n            /*!\n                ensures\n                    - allocates a new array of size objects of type T and returns a \n                      pointer to it.\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor.\n                        If this exception is thrown then the call to allocate() \n                        has no effect on #*this.\n            !*/\n\n            void deallocate_array (\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      allocate_array(). (i.e. The pointer you are deallocating must have\n                      come from the same implementation of memory_manager_stateless\n                      that is trying to deallocate it.)\n                    - the memory pointed to by item hasn't already been deallocated.\n                ensures\n                    - deallocates the array pointed to by item\n            !*/\n\n            void swap (\n                memory_manager_stateless& item\n            );\n            /*!\n                ensures\n                    - this function has no effect on *this or item.  It is just provided \n                      to make this object's interface more compatible with the other \n                      memory managers.\n            !*/ \n\n            std::unique_ptr<T> extract(\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      allocate(). \n                ensures\n                    - returns a unique_ptr that owns item.  That is, if the returned ptr is\n                      PTR then PTR.get() == item.  Therefore, this function extracts item\n                      from the memory manager's internal pool.  Therefore, you shouldn't \n                      call deallocate(item) after this.\n                    - Note that not all memory managers implement extract().\n            !*/\n\n            std::unique_ptr<T[]> extract_array(\n                T* item\n            );\n            /*!\n                requires\n                    - item == is a pointer to memory that was obtained from a call to\n                      allocate_array(). \n                ensures\n                    - returns a unique_ptr that owns item.  That is, if the returned ptr is\n                      PTR then PTR.get() == item.  Therefore, this function extracts item\n                      from the memory manager's internal pool.  Therefore, you shouldn't \n                      call deallocate_array(item) after this.\n                    - Note that not all memory managers implement extract().\n            !*/\n\n        private:\n\n            // restricted functions\n            memory_manager_stateless(memory_manager_stateless&);        // copy constructor\n            memory_manager_stateless& operator=(memory_manager_stateless&);    // assignment operator\n    };\n\n    template <\n        typename T\n        >\n    inline void swap (\n        memory_manager_stateless<T>& a, \n        memory_manager_stateless<T>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_MEMORY_MANAGER_STATELESs_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/memory_manager_stateless.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MEMORY_MANAGER_STATELESs_\n#define DLIB_MEMORY_MANAGER_STATELESs_\n\n#include \"memory_manager_stateless/memory_manager_stateless_kernel_1.h\"\n#include \"memory_manager_stateless/memory_manager_stateless_kernel_2.h\"\n#include \"memory_manager.h\"\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename T\n        >\n    class memory_manager_stateless\n    {\n        memory_manager_stateless() {}\n\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1        \n        typedef      memory_manager_stateless_kernel_1<T>\n                     kernel_1a;\n      \n        // kernel_2        \n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1a>\n                     kernel_2_1a;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1b>\n                     kernel_2_1b;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1c>\n                     kernel_2_1c;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1d>\n                     kernel_2_1d;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1e>\n                     kernel_2_1e;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_1f>\n                     kernel_2_1f;\n\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_2a>\n                     kernel_2_2a;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_2b>\n                     kernel_2_2b;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_2c>\n                     kernel_2_2c;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_2d>\n                     kernel_2_2d;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_2e>\n                     kernel_2_2e;\n      \n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_3a>\n                     kernel_2_3a;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_3b>\n                     kernel_2_3b;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_3c>\n                     kernel_2_3c;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_3d>\n                     kernel_2_3d;\n        typedef      memory_manager_stateless_kernel_2<T,memory_manager<char>::kernel_3e>\n                     kernel_2_3e;\n      \n\n    };\n}\n\n#endif // DLIB_MEMORY_MANAGER_STATELESs_\n\n"
  },
  {
    "path": "dlib/metaprogramming.h",
    "content": "// Copyright (C) 2017  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_METApROGRAMMING_Hh_\n#define DLIB_METApROGRAMMING_Hh_\n\n#include \"constexpr_if.h\"\n#include \"functional.h\"\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    template <size_t... n>\n    struct compile_time_integer_list \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                The point of this type is to, as the name suggests, hold a compile time list of integers.\n                As an example, here is something simple you could do with it:\n                    template <size_t... ints>\n                    void print_compile_time_ints (\n                        compile_time_integer_list<ints...>\n                    )\n                    {\n                        print(ints...);\n                    }\n                    int main()\n                    {\n                        print_compile_time_ints(compile_time_integer_list<0,4,9>());\n                    }\n                Which just calls: print(0,4,9);\n                This is a simple example, but this kind of thing is useful in larger and\n                more complex template metaprogramming constructs.\n        !*/\n\n        template <size_t m>\n        struct push_back\n        {\n            typedef compile_time_integer_list<n..., m> type;\n        };\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <size_t max>\n    struct make_compile_time_integer_range\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object makes a compile_time_integer_list containing the integers in the range [1,max] inclusive.\n                For example:\n                    make_compile_time_integer_range<4>::type\n                evaluates to:\n                    compile_time_integer_list<1,2,3,4>\n        !*/\n\n        typedef typename make_compile_time_integer_range<max-1>::type::template push_back<max>::type type;\n    };\n    // base case\n    template <> struct make_compile_time_integer_range<0> { typedef compile_time_integer_list<> type; };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename Funct, typename... Args>\n    bool call_if_valid(Funct&& f, Args&&... args) \n    /*!\n        ensures\n            - if f(std::forward<Args>(args)...) is a valid expression then we evaluate it and return\n              true.  Otherwise we do nothing and return false.\n    !*/\n    {\n        return switch_(bools(is_invocable<Funct, Args...>{}),\n            [&](true_t, auto _) {\n                _(std::forward<Funct>(f))(std::forward<Args>(args)...);\n                return true;\n            },\n            [](auto...) {\n                return false;\n            }\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_METApROGRAMMING_Hh_\n\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_kernel_1.cpp",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEL_1_CPp_\n#define DLIB_MISC_API_KERNEL_1_CPp_\n\n#include \"../platform.h\"\n#include \"../threads.h\"\n\n#ifdef WIN32\n\n#include \"misc_api_kernel_1.h\"\n\n#include \"../windows_magic.h\"\n#include <windows.h>\n#include <mmsystem.h>\n\n// tell visual studio to link to the library needed to call timeGetTime() \n#ifdef _MSC_VER\n#pragma comment (lib, \"winmm.lib\")\n#endif\n\n#ifdef __BORLANDC__\n// Apparently the borland compiler doesn't define this.\n#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)\n#endif\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    void sleep (\n        unsigned long milliseconds\n    )\n    {\n        ::Sleep(milliseconds);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace\n    {\n        mutex& cwd_mutex()\n        {\n            static mutex m;\n            return m;\n        }\n        // Make sure the above mutex gets constructed before main() \n        // starts.  This way we can be pretty sure it will be constructed\n        // before any threads could possibly call set_current_dir() or\n        // get_current_dir() simultaneously.\n        struct construct_cwd_mutex\n        {\n            construct_cwd_mutex()\n            {\n                cwd_mutex();\n            }\n        } oaimvweoinvwe;\n    }\n\n    std::string get_current_dir (\n    )\n    {\n        // need to lock a mutex here because getting and setting the\n        // current working directory is not thread safe on windows.\n        auto_mutex lock(cwd_mutex());\n        char buf[1024];\n        if (GetCurrentDirectoryA(sizeof(buf),buf) == 0)\n        {\n            return std::string();\n        }\n        else\n        {\n            return std::string(buf);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void set_current_dir (\n        const std::string& new_dir\n    )\n    {\n        // need to lock a mutex here because getting and setting the\n        // current working directory is not thread safe on windows.\n        auto_mutex lock(cwd_mutex());\n        if (SetCurrentDirectoryA(new_dir.c_str()) == 0)\n        {\n            throw set_current_dir_error(\"Error changing current dir to '\" + new_dir + \"'\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    uint64 timestamper::\n    get_timestamp (\n    ) const\n    {\n        unsigned long temp = timeGetTime();\n        if (temp >= last_time)\n        {            \n            last_time = temp;\n            return (offset + temp)*1000;\n        }\n        else\n        {\n            last_time = temp;\n\n            // there was overflow since the last call so we need to make the offset\n            // bigger to account for that\n            offset += dword_max;\n            return (offset + temp)*1000;\n        }        \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void create_directory (\n        const std::string& dir\n    )\n    {\n        if (CreateDirectoryA(dir.c_str(),0) == 0)\n        {\n            // an error has occurred\n            if (GetLastError() == ERROR_ALREADY_EXISTS)\n            {\n                // make sure this is actually a directory\n                DWORD attribs = GetFileAttributesA(dir.c_str());\n                if (attribs == INVALID_FILE_ATTRIBUTES ||\n                    (attribs&FILE_ATTRIBUTE_DIRECTORY) == 0)\n                {\n                    // it isn't a directory\n                    throw dir_create_error(dir);\n                }\n            }\n            else\n            {\n                throw dir_create_error(dir);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n    \n}\n\n#endif // WIN32\n\n#endif // DLIB_MISC_API_KERNEL_1_CPp_\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_kernel_1.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEl_1_\n#define DLIB_MISC_API_KERNEl_1_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n\n#include \"misc_api_kernel_abstract.h\"\n#include \"../algs.h\"\n#include <string>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void sleep (\n        unsigned long milliseconds\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    std::string get_current_dir (\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class set_current_dir_error : public error\n    {\n    public:\n        set_current_dir_error(\n            const std::string& a\n        ): error(a) {}\n    };\n\n    void set_current_dir (\n        const std::string& new_dir\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class timestamper \n    {\n        /*!\n            INITIAL VALUE\n                - last_time == 0\n                - offset == 0\n                - dword_max == 2^32\n\n            CONVENTION\n                - last_time == the time returned by GetTickCount() the last time we\n                  called it.\n                - offset == the number of microseconds we should add to the result of\n                  GetTickCount() so that it is correct.\n                - dword_max == 2^32.  \n                  This is the number of values representable by a DWORD.  \n        !*/\n\n        mutable unsigned long last_time;\n        mutable uint64 offset;\n        mutable uint64 dword_max;\n\n    public:\n        timestamper(\n        ) :\n            last_time(0),\n            offset(0)\n        {\n            dword_max = 0xFFFFFFFF;\n            ++dword_max;\n        }\n\n        uint64 get_timestamp (\n        ) const;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class dir_create_error : public error \n    {\n    public:\n        dir_create_error(\n            const std::string& dir_name\n        ) : \n            error(EDIR_CREATE,\"Error creating directory '\" + dir_name + \"'.\"),\n            name(dir_name)\n        {}\n\n        ~dir_create_error() noexcept {}\n        const std::string name;\n    }; \n\n    void create_directory (\n        const std::string& dir\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"misc_api_kernel_1.cpp\"\n#endif\n\n#endif // DLIB_MISC_API_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_kernel_2.cpp",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEL_2_CPp_\n#define DLIB_MISC_API_KERNEL_2_CPp_\n#include \"../platform.h\"\n\n#ifdef DLIB_POSIX\n\n#include <unistd.h>\n#include \"misc_api_kernel_2.h\"\n#include <sys/time.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <errno.h>\n\nnamespace dlib\n{\n// ----------------------------------------------------------------------------------------\n\n    void sleep (\n        unsigned long milliseconds\n    )\n    {\n        // in HP-UX you can only usleep for less than a second \n#ifdef HPUX\n        if (milliseconds >= 1000)\n        {\n            ::sleep(milliseconds/1000);\n            unsigned long remaining = milliseconds%1000;\n            if (remaining > 0)\n                ::usleep(remaining*1000);\n        }\n        else\n        {\n            ::usleep(milliseconds*1000);\n        }\n#else\n        ::usleep(milliseconds*1000);\n#endif\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    std::string get_current_dir (\n    )\n    {\n        char buf[1024];\n        if (getcwd(buf,sizeof(buf)) == 0)\n        {\n            return std::string();\n        }\n        else\n        {\n            return std::string(buf);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void set_current_dir (\n        const std::string& new_dir\n    )\n    {\n        if (chdir(new_dir.c_str()))\n        {\n            throw set_current_dir_error(\"Error changing current dir to '\" + new_dir + \"'\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    uint64 timestamper::\n    get_timestamp (\n    ) const\n    {\n        uint64 ts;\n        timeval curtime;\n        gettimeofday(&curtime,0);       \n\n        ts = curtime.tv_sec;\n        ts *= 1000000;\n        ts += curtime.tv_usec;\n        return ts;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void create_directory (\n        const std::string& dir\n    )\n    {\n        if (mkdir(dir.c_str(),0777))\n        {\n            // an error has occurred\n            if (errno == EEXIST)\n            {\n                struct stat buffer;\n                // now check that this is actually a valid directory\n                if (::stat(dir.c_str(),&buffer))\n                {\n                    // the directory was not found\n                    throw dir_create_error(dir);\n                }\n                else if (S_ISDIR(buffer.st_mode) == 0)\n                {\n                    // It is not a directory\n                    throw dir_create_error(dir);\n                }\n            }\n            else\n            {\n                throw dir_create_error(dir);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_POSIX\n\n#endif // DLIB_MISC_API_KERNEL_2_CPp_\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEl_2_\n#define DLIB_MISC_API_KERNEl_2_\n\n#ifdef DLIB_ISO_CPP_ONLY\n#error \"DLIB_ISO_CPP_ONLY is defined so you can't use this OS dependent code.  Turn DLIB_ISO_CPP_ONLY off if you want to use it.\"\n#endif\n\n\n#include \"misc_api_kernel_abstract.h\"\n#include \"../algs.h\"\n#include <string>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    void sleep (\n        unsigned long milliseconds\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    std::string get_current_dir (\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class set_current_dir_error : public error\n    {\n    public:\n        set_current_dir_error(\n            const std::string& a\n        ): error(a) {}\n    };\n\n    void set_current_dir (\n        const std::string& new_dir\n    );\n\n// ----------------------------------------------------------------------------------------\n\n    class timestamper \n    {\n    public:\n        uint64 get_timestamp (\n        ) const;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class dir_create_error : public error \n    {\n    public:\n        dir_create_error(\n            const std::string& dir_name\n        ) : \n            error(EDIR_CREATE,\"Error creating directory '\" + dir_name + \"'.\"),\n            name(dir_name)\n        {}\n        const std::string& name;\n    }; \n\n\n    void create_directory (\n        const std::string& dir\n    );\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"misc_api_kernel_2.cpp\"\n#endif\n\n#endif // DLIB_MISC_API_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_kernel_abstract.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MISC_API_KERNEl_ABSTRACT_\n#ifdef DLIB_MISC_API_KERNEl_ABSTRACT_\n\n#include <string>\n#include \"../uintn.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        GENERAL COMMENTS\n            This file just contains miscellaneous api functions\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    void sleep (\n        unsigned long milliseconds\n    );\n    /*!\n        ensures\n            - causes the calling thread to sleep for the given number of \n              milliseconds.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    std::string get_current_dir (\n    );\n    /*!\n        ensures\n            - if (no errors occur) then\n                - returns the path to the current working directory\n            - else\n                - returns \"\"\n        throws\n            - std::bad_alloc\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class set_current_dir_error : public error;\n\n    void set_current_dir (\n        const std::string& new_dir\n    );\n    /*!\n        ensures\n            - sets the current working directory to new_dir\n        throws\n            - std::bad_alloc\n            - set_current_dir_error\n              This exception is thrown if there is an error when attempting\n              to change the current working directory.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class locally_change_current_dir : noncopyable\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a RAII tool for safely switching the current directory\n                to a new directory and then automatically switching back to the original\n                directory upon this object's destruction.\n        !*/\n    public:\n        explicit locally_change_current_dir (\n            const std::string& new_dir\n        );\n        /*!\n            ensures\n                - calls set_current_dir(new_dir)\n                - #old_dir() == The value of get_current_dir() prior to switching to new_dir.\n        !*/\n\n        const std::string& old_dir (\n        ) const;\n        /*!\n            ensures\n                - returns the directory we switch back to once this object is destructed.\n        !*/\n\n        ~locally_change_current_dir(\n        );\n        /*!\n            ensures\n                - if (revert() hasn't already been called) then\n                    - calls set_current_dir(old_dir())\n        !*/\n\n        void revert (\n        );\n        /*!\n            ensures\n                - if (revert() hasn't already been called) then\n                    - calls set_current_dir(old_dir())\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class dir_create_error : public error { \n    public:\n        const std::string name\n    }; \n\n    void create_directory (\n        const std::string& dir\n    );\n    /*!\n        ensures\n            - if (dir does not already exist) then\n                - creates the given directory.\n            - else\n                - the call to create_directory() has no effect.\n        throws\n            - dir_create_error\n                This exception is thrown if we were unable to create the requested\n                directory and it didn't already exist.  The type member of the exception \n                will bet set to EDIR_CREATE and the name member will be set to dir.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class timestamper \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a timer that is capable of returning \n                timestamps.\n\n                Note that the time is measured in microseconds but you are not \n                guaranteed to have that level of resolution.  The actual resolution\n                is implementation dependent.\n        !*/\n\n    public:\n        uint64 get_timestamp (\n        ) const;\n        /*!\n            ensures\n                - returns a timestamp that measures the time in microseconds since an \n                  arbitrary point in the past.  Note that this arbitrary point remains\n                  the same between all calls to get_timestamp().\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MISC_API_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/misc_api/misc_api_shared.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_ShARED_Hh_\n#define DLIB_MISC_API_ShARED_Hh_\n\n#include <string>\n#include \"../noncopyable.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class locally_change_current_dir : noncopyable\n    {\n    public:\n        explicit locally_change_current_dir (\n            const std::string& new_dir\n        )\n        {\n            reverted = false;\n            _old_dir = get_current_dir();\n            set_current_dir(new_dir);\n        }\n\n        ~locally_change_current_dir()\n        {\n            revert();\n        }\n\n        const std::string& old_dir (\n        ) const \n        {\n            return _old_dir;\n        }\n\n        void revert (\n        )\n        {\n            if (!reverted)\n            {\n                set_current_dir(_old_dir);\n                reverted = true;\n            }\n        }\n\n    private:\n        bool reverted;\n        std::string _old_dir;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MISC_API_ShARED_Hh_\n\n"
  },
  {
    "path": "dlib/misc_api/posix.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEl_1_\n#include \"misc_api_kernel_2.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/misc_api/windows.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MISC_API_KERNEl_2_\n#include \"misc_api_kernel_1.h\"\n#endif\n\n"
  },
  {
    "path": "dlib/misc_api.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifndef DLIB_MISC_APi_\n#define DLIB_MISC_APi_\n\n#include \"platform.h\"\n\n#ifdef WIN32\n#include \"misc_api/windows.h\"\n#endif\n\n#ifndef WIN32\n#include \"misc_api/posix.h\"\n#endif\n\n#include \"misc_api/misc_api_shared.h\"\n\n#endif // DLIB_MISC_APi_\n\n"
  },
  {
    "path": "dlib/mlp/mlp_kernel_1.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MLp_KERNEL_1_\n#define DLIB_MLp_KERNEL_1_\n\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../matrix.h\"\n#include \"../rand.h\"\n#include \"mlp_kernel_abstract.h\"\n#include <ctime>\n#include <sstream>\n\nnamespace dlib\n{\n\n    class mlp_kernel_1 : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                The network is initially initialized with random weights \n\n            CONVENTION\n                - input_layer_nodes() == input_nodes\n                - first_hidden_layer_nodes() == first_hidden_nodes\n                - second_hidden_layer_nodes() == second_hidden_nodes\n                - output_layer_nodes() == output_nodes\n                - get_alpha == alpha\n                - get_momentum() == momentum\n\n\n                - if (second_hidden_nodes == 0) then\n                    - for all i and j:\n                        - w1(i,j) == the weight on the link from node i in the first hidden layer \n                          to input node j\n                        - w3(i,j) == the weight on the link from node i in the output layer \n                          to first hidden layer node j\n                    - for all i and j:\n                        - w1m == the momentum terms for w1 from the previous update \n                        - w3m == the momentum terms for w3 from the previous update \n                - else\n                    - for all i and j:\n                        - w1(i,j) == the weight on the link from node i in the first hidden layer \n                          to input node j\n                        - w2(i,j) == the weight on the link from node i in the second hidden layer \n                          to first hidden layer node j\n                        - w3(i,j) == the weight on the link from node i in the output layer \n                          to second hidden layer node j\n                    - for all i and j:\n                        - w1m == the momentum terms for w1 from the previous update \n                        - w2m == the momentum terms for w2 from the previous update \n                        - w3m == the momentum terms for w3 from the previous update \n        !*/\n\n    public:\n\n        mlp_kernel_1 (\n            long nodes_in_input_layer,\n            long nodes_in_first_hidden_layer, \n            long nodes_in_second_hidden_layer = 0, \n            long nodes_in_output_layer = 1,\n            double alpha_ = 0.1,\n            double momentum_ = 0.8\n        ) :\n            input_nodes(nodes_in_input_layer),\n            first_hidden_nodes(nodes_in_first_hidden_layer),\n            second_hidden_nodes(nodes_in_second_hidden_layer),\n            output_nodes(nodes_in_output_layer),\n            alpha(alpha_),\n            momentum(momentum_)\n        {\n\n            // seed the random number generator\n            std::ostringstream sout;\n            sout << time(0);\n            rand_nums.set_seed(sout.str());\n\n            w1.set_size(first_hidden_nodes+1, input_nodes+1);\n            w1m.set_size(first_hidden_nodes+1, input_nodes+1);\n            z.set_size(input_nodes+1,1);\n\n            if (second_hidden_nodes != 0)\n            {\n                w2.set_size(second_hidden_nodes+1, first_hidden_nodes+1);\n                w3.set_size(output_nodes, second_hidden_nodes+1);\n\n                w2m.set_size(second_hidden_nodes+1, first_hidden_nodes+1);\n                w3m.set_size(output_nodes, second_hidden_nodes+1);\n            }\n            else\n            {\n                w3.set_size(output_nodes, first_hidden_nodes+1);\n\n                w3m.set_size(output_nodes, first_hidden_nodes+1);\n            }\n\n            reset();\n        }\n\n        virtual ~mlp_kernel_1 (\n        ) {}\n\n        void reset (\n        ) \n        {\n            // randomize the weights for the first layer\n            for (long r = 0; r < w1.nr(); ++r)\n                for (long c = 0; c < w1.nc(); ++c)\n                    w1(r,c) = rand_nums.get_random_double();\n\n            // randomize the weights for the second layer\n            for (long r = 0; r < w2.nr(); ++r)\n                for (long c = 0; c < w2.nc(); ++c)\n                    w2(r,c) = rand_nums.get_random_double();\n\n            // randomize the weights for the third layer\n            for (long r = 0; r < w3.nr(); ++r)\n                for (long c = 0; c < w3.nc(); ++c)\n                    w3(r,c) = rand_nums.get_random_double();\n\n            // zero all the momentum terms\n            set_all_elements(w1m,0);\n            set_all_elements(w2m,0);\n            set_all_elements(w3m,0);\n        }\n\n        long input_layer_nodes (\n        ) const { return input_nodes; }\n\n        long first_hidden_layer_nodes (\n        ) const { return first_hidden_nodes; }\n\n        long second_hidden_layer_nodes (\n        ) const { return second_hidden_nodes; }\n\n        long output_layer_nodes (\n        ) const { return output_nodes; }\n\n        double get_alpha (\n        ) const { return alpha; }\n\n        double get_momentum (\n        ) const { return momentum; }\n\n        template <typename EXP>\n        const matrix<double> operator() (\n            const matrix_exp<EXP>& in \n        ) const\n        {\n            for (long i = 0; i < in.nr(); ++i)\n                z(i) = in(i);\n            // insert the bias \n            z(z.nr()-1) = -1;\n\n            tmp1 = sigmoid(w1*z);\n            // insert the bias \n            tmp1(tmp1.nr()-1) = -1;\n\n            if (second_hidden_nodes == 0)\n            {\n                return sigmoid(w3*tmp1);\n            }\n            else\n            {\n                tmp2 = sigmoid(w2*tmp1);\n                // insert the bias \n                tmp2(tmp2.nr()-1) = -1;\n\n                return sigmoid(w3*tmp2);\n            }\n        }\n\n        template <typename EXP1, typename EXP2>\n        void train (\n            const matrix_exp<EXP1>& example_in,\n            const matrix_exp<EXP2>& example_out \n        )\n        {\n            for (long i = 0; i < example_in.nr(); ++i)\n                z(i) = example_in(i);\n            // insert the bias \n            z(z.nr()-1) = -1;\n\n            tmp1 = sigmoid(w1*z);\n            // insert the bias \n            tmp1(tmp1.nr()-1) = -1;\n\n\n            if (second_hidden_nodes == 0)\n            {\n                o = sigmoid(w3*tmp1);\n\n                // now compute the errors and propagate them backwards though the network\n                e3 = pointwise_multiply(example_out-o, uniform_matrix<double>(output_nodes,1,1.0)-o, o);\n                e1 = pointwise_multiply(tmp1, uniform_matrix<double>(first_hidden_nodes+1,1,1.0) - tmp1, trans(w3)*e3 );\n\n                // compute the new weight updates\n                w3m = alpha * e3*trans(tmp1) + w3m*momentum;\n                w1m = alpha * e1*trans(z)    + w1m*momentum;\n\n                // now update the weights\n                w1 += w1m;\n                w3 += w3m;\n            }\n            else\n            {\n                tmp2 = sigmoid(w2*tmp1);\n                // insert the bias \n                tmp2(tmp2.nr()-1) = -1;\n\n                o = sigmoid(w3*tmp2);\n\n\n                // now compute the errors and propagate them backwards though the network\n                e3 = pointwise_multiply(example_out-o, uniform_matrix<double>(output_nodes,1,1.0)-o, o);\n                e2 = pointwise_multiply(tmp2, uniform_matrix<double>(second_hidden_nodes+1,1,1.0) - tmp2, trans(w3)*e3 );\n                e1 = pointwise_multiply(tmp1, uniform_matrix<double>(first_hidden_nodes+1,1,1.0) - tmp1, trans(w2)*e2 );\n\n                // compute the new weight updates\n                w3m = alpha * e3*trans(tmp2) + w3m*momentum;\n                w2m = alpha * e2*trans(tmp1) + w2m*momentum;\n                w1m = alpha * e1*trans(z)    + w1m*momentum;\n\n                // now update the weights\n                w1 += w1m;\n                w2 += w2m;\n                w3 += w3m;\n            }\n        }\n\n        template <typename EXP>\n        void train (\n            const matrix_exp<EXP>& example_in,\n            double example_out\n        )\n        {\n            matrix<double,1,1> e_out;\n            e_out(0) = example_out;\n            train(example_in,e_out);\n        }\n\n        double get_average_change (\n        ) const\n        {\n            // sum up all the weight changes\n            double delta = sum(abs(w1m)) + sum(abs(w2m)) + sum(abs(w3m));\n\n            // divide by the number of weights\n            delta /=  w1m.nr()*w1m.nc() + \n                w2m.nr()*w2m.nc() + \n                w3m.nr()*w3m.nc();\n\n            return delta;\n        }\n\n        void swap (\n            mlp_kernel_1& item\n        )\n        {\n            exchange(input_nodes, item.input_nodes);\n            exchange(first_hidden_nodes, item.first_hidden_nodes);\n            exchange(second_hidden_nodes, item.second_hidden_nodes);\n            exchange(output_nodes, item.output_nodes);\n            exchange(alpha, item.alpha);\n            exchange(momentum, item.momentum);\n\n            w1.swap(item.w1);\n            w2.swap(item.w2);\n            w3.swap(item.w3);\n\n            w1m.swap(item.w1m);\n            w2m.swap(item.w2m);\n            w3m.swap(item.w3m);\n\n            // even swap the temporary matrices because this may ultimately result in \n            // fewer calls to new and delete.\n            e1.swap(item.e1);\n            e2.swap(item.e2);\n            e3.swap(item.e3);\n            z.swap(item.z);\n            tmp1.swap(item.tmp1);\n            tmp2.swap(item.tmp2);\n            o.swap(item.o);\n        }\n\n\n        friend void serialize (\n            const mlp_kernel_1& item, \n            std::ostream& out\n        );\n\n        friend void deserialize (\n            mlp_kernel_1& item, \n            std::istream& in\n        );\n\n    private:\n\n        long input_nodes;\n        long first_hidden_nodes;\n        long second_hidden_nodes;\n        long output_nodes;\n        double alpha;\n        double momentum;\n\n        matrix<double> w1;\n        matrix<double> w2;\n        matrix<double> w3;\n\n        matrix<double> w1m;\n        matrix<double> w2m;\n        matrix<double> w3m;\n\n\n        rand rand_nums;\n\n        // temporary storage\n        mutable matrix<double> e1, e2, e3;\n        mutable matrix<double> z, tmp1, tmp2, o;\n    };   \n\n    inline void swap (\n        mlp_kernel_1& a, \n        mlp_kernel_1& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const mlp_kernel_1& item, \n        std::ostream& out\n    )   \n    {\n        try\n        {\n            serialize(item.input_nodes, out);\n            serialize(item.first_hidden_nodes, out);\n            serialize(item.second_hidden_nodes, out);\n            serialize(item.output_nodes, out);\n            serialize(item.alpha, out);\n            serialize(item.momentum, out);\n\n            serialize(item.w1, out);\n            serialize(item.w2, out);\n            serialize(item.w3, out);\n\n            serialize(item.w1m, out);\n            serialize(item.w2m, out);\n            serialize(item.w3m, out);\n        }\n        catch (serialization_error& e)\n        { \n            throw serialization_error(e.info + \"\\n   while serializing object of type mlp_kernel_1\"); \n        }\n    }\n\n    inline void deserialize (\n        mlp_kernel_1& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.input_nodes, in);\n            deserialize(item.first_hidden_nodes, in);\n            deserialize(item.second_hidden_nodes, in);\n            deserialize(item.output_nodes, in);\n            deserialize(item.alpha, in);\n            deserialize(item.momentum, in);\n\n            deserialize(item.w1, in);\n            deserialize(item.w2, in);\n            deserialize(item.w3, in);\n\n            deserialize(item.w1m, in);\n            deserialize(item.w2m, in);\n            deserialize(item.w3m, in);\n\n            item.z.set_size(item.input_nodes+1,1);\n        }\n        catch (serialization_error& e)\n        { \n            // give item a reasonable value since the deserialization failed\n            mlp_kernel_1(1,1).swap(item);\n            throw serialization_error(e.info + \"\\n   while deserializing object of type mlp_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MLp_KERNEL_1_\n\n"
  },
  {
    "path": "dlib/mlp/mlp_kernel_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MLp_ABSTRACT_\n#ifdef DLIB_MLp_ABSTRACT_\n\n#include \"../algs.h\"\n#include \"../serialize.h\"\n#include \"../matrix/matrix_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class mlp : noncopyable\n    {\n        /*!\n            INITIAL VALUE\n                The network is initially initialized with random weights \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a multilayer layer perceptron network that is\n                trained using the back propagation algorithm.  The training algorithm also\n                incorporates the momentum method.  That is, each round of back propagation\n                training also adds a fraction of the previous update.  This fraction\n                is controlled by the momentum term set in the constructor.  \n\n                The activation function used at each node is the sigmoid function.  I.e.\n                sigmoid(x) = 1/(1 + pow(e,-x)).  Thus the output of the network is\n                always in the range [0,1]\n        !*/\n\n    public:\n\n        mlp (\n            long nodes_in_input_layer,\n            long nodes_in_first_hidden_layer, \n            long nodes_in_second_hidden_layer = 0, \n            long nodes_in_output_layer = 1,\n            double alpha = 0.1,\n            double momentum = 0.8\n        );\n        /*!\n            requires\n                - nodes_in_input_layer > 0\n                - nodes_in_first_hidden_layer > 0\n                - nodes_in_second_hidden_layer >= 0\n                - nodes_in_output_layer > 0\n            ensures\n                - #*this is properly initialized \n                - #input_layer_nodes() == nodes_in_input_layer\n                - #first_hidden_layer_nodes() == nodes_in_first_hidden_layer\n                - #second_hidden_layer_nodes() == nodes_in_second_hidden_layer\n                - #output_layer_nodes() == nodes_in_output_layer\n                - #get_alpha() == alpha\n                - #get_momentum() == momentum\n            throws\n                - std::bad_alloc\n                    if this is thrown the mlp will be unusable but \n                    will not leak memory\n        !*/\n\n        virtual ~mlp (\n        );\n        /*!\n            ensures\n                - all resources associated with #*this have been released\n        !*/\n\n        void reset (\n        ) const;\n        /*!\n            ensures\n                - reinitialize the network with random weights\n        !*/\n\n        long input_layer_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the input layer\n        !*/\n\n        long first_hidden_layer_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the first hidden layer.  This is\n                  the hidden layer that is directly connected to the input layer.\n        !*/\n\n        long second_hidden_layer_nodes (\n        ) const;\n        /*!\n            ensures\n                - if (this network has a second hidden layer) then\n                    - returns the number of nodes in the second hidden layer.  This is \n                      the hidden layer that is directly connected to the output layer.\n                - else\n                    - returns 0\n        !*/\n\n        long output_layer_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the output layer\n        !*/\n\n        double get_alpha (\n        ) const;\n        /*!\n            ensures\n                - returns the back propagation learning rate used by this object.\n        !*/\n\n        double get_momentum (\n        ) const;\n        /*!\n            ensures\n                - returns the momentum term used by this object during back propagation\n                  training.  The momentum is is the fraction of a previous update to \n                  carry forward to the next call to train()\n        !*/\n\n        template <typename EXP>\n        const matrix<double> operator() (\n            const matrix_exp<EXP>& in \n        ) const;\n        /*!\n            requires\n                - in.nr() == input_layer_nodes()\n                - in.nc() == 1\n                - EXP::type == double\n            ensures\n                - returns the output of the network when it is given the\n                  input in.  The output's elements are always in the range\n                  of 0.0 to 1.0\n        !*/\n\n        template <typename EXP1, typename EXP2>\n        void train (\n            const matrix_exp<EXP1>& example_in,\n            const matrix_exp<EXP2>& example_out \n        );\n        /*!\n            requires\n                - example_in.nr() == input_layer_nodes()\n                - example_in.nc() == 1\n                - example_out.nr() == output_layer_nodes()\n                - example_out.nc() == 1\n                - max(example_out) <= 1.0 && min(example_out) >= 0.0\n                - EXP1::type == double\n                - EXP2::type == double\n            ensures\n                - trains the network that the correct output when given example_in \n                  should be example_out.\n        !*/\n\n        template <typename EXP>\n        void train (\n            const matrix_exp<EXP>& example_in,\n            double example_out\n        );\n        /*!\n            requires\n                - example_in.nr() == input_layer_nodes()\n                - example_in.nc() == 1\n                - output_layer_nodes() == 1\n                - example_out <= 1.0 && example_out >= 0.0\n                - EXP::type == double\n            ensures\n                - trains the network that the correct output when given example_in \n                  should be example_out.\n        !*/\n\n        double get_average_change (\n        ) const;\n        /*!\n            ensures\n                - returns the average change in the node weights in the\n                  neural network during the last call to train()\n        !*/\n\n        void swap (\n            mlp& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };   \n   \n    inline void swap (\n        mlp& a, \n        mlp& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    void serialize (\n        const mlp& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        mlp& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MLp_ABSTRACT_ \n\n\n"
  },
  {
    "path": "dlib/mlp/mlp_kernel_c.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MLP_KERNEl_C_\n#define DLIB_MLP_KERNEl_C_\n\n#include \"mlp_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n\n    template <\n        typename mlp_base // is an implementation of mlp_kernel_abstract.h\n        >\n    class mlp_kernel_c : public mlp_base\n    {\n        long verify_constructor_args (\n            long nodes_in_input_layer,\n            long nodes_in_first_hidden_layer, \n            long nodes_in_second_hidden_layer, \n            long nodes_in_output_layer\n            )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(nodes_in_input_layer > 0 &&\n                    nodes_in_first_hidden_layer > 0 &&\n                    nodes_in_second_hidden_layer >= 0 &&\n                    nodes_in_output_layer > 0,\n                    \"\\tconst mlp::constructor()\"\n                    << \"\\n\\tinvalid constructor arguments\"\n                    << \"\\n\\tnodes_in_input_layer:         \" << nodes_in_input_layer \n                    << \"\\n\\tnodes_in_first_hidden_layer:  \" << nodes_in_first_hidden_layer \n                    << \"\\n\\tnodes_in_second_hidden_layer: \" << nodes_in_second_hidden_layer \n                    << \"\\n\\tnodes_in_output_layer:        \" << nodes_in_output_layer \n            );\n\n            return nodes_in_input_layer;\n        }\n\n    public:\n\n        mlp_kernel_c (\n            long nodes_in_input_layer,\n            long nodes_in_first_hidden_layer, \n            long nodes_in_second_hidden_layer = 0, \n            long nodes_in_output_layer = 1,\n            double alpha = 0.1,\n            double momentum = 0.8\n        ) : mlp_base( verify_constructor_args(\n                        nodes_in_input_layer, \n                        nodes_in_input_layer, \n                        nodes_in_second_hidden_layer,\n                        nodes_in_output_layer),\n                      nodes_in_first_hidden_layer,\n                      nodes_in_second_hidden_layer,\n                      nodes_in_output_layer,\n                      alpha,\n                      momentum)\n        {\n        }\n\n        template <typename EXP>\n        const matrix<double> operator() (\n            const matrix_exp<EXP>& in \n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(in.nr() == this->input_layer_nodes() &&\n                    in.nc() == 1,\n                    \"\\tconst matrix<double> mlp::operator()(matrix_exp)\"\n                    << \"\\n\\tthe input matrix dimensions are not correct\"\n                    << \"\\n\\tin.nr():             \" << in.nr() \n                    << \"\\n\\tin.nc():             \" << in.nc() \n                    << \"\\n\\tinput_layer_nodes(): \" << this->input_layer_nodes() \n                    << \"\\n\\tthis:                \" << this\n            );\n\n            return mlp_base::operator()(in);\n        }\n\n        template <typename EXP1, typename EXP2>\n        void train (\n            const matrix_exp<EXP1>& example_in,\n            const matrix_exp<EXP2>& example_out \n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(example_in.nr() == this->input_layer_nodes() &&\n                    example_in.nc() == 1 &&\n                    example_out.nr() == this->output_layer_nodes() &&\n                    example_out.nc() == 1 &&\n                    max(example_out) <= 1.0 && min(example_out) >= 0.0,\n                    \"\\tvoid mlp::train(matrix_exp, matrix_exp)\"\n                    << \"\\n\\tthe training example dimensions are not correct\"\n                    << \"\\n\\texample_in.nr():      \" << example_in.nr() \n                    << \"\\n\\texample_in.nc():      \" << example_in.nc() \n                    << \"\\n\\texample_out.nr():     \" << example_out.nr() \n                    << \"\\n\\texample_out.nc():     \" << example_out.nc() \n                    << \"\\n\\tmax(example_out):     \" << max(example_out) \n                    << \"\\n\\tmin(example_out):     \" << min(example_out) \n                    << \"\\n\\tinput_layer_nodes():  \" << this->input_layer_nodes() \n                    << \"\\n\\toutput_layer_nodes(): \" << this->output_layer_nodes() \n                    << \"\\n\\tthis:                 \" << this\n            );\n\n            mlp_base::train(example_in,example_out);\n        }\n\n        template <typename EXP>\n        void train (\n            const matrix_exp<EXP>& example_in,\n            double example_out\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(example_in.nr() == this->input_layer_nodes() &&\n                    example_in.nc() == 1 &&\n                    this->output_layer_nodes() == 1 &&\n                    example_out <= 1.0 && example_out >= 0.0,\n                    \"\\tvoid mlp::train(matrix_exp, double)\"\n                    << \"\\n\\tthe training example dimensions are not correct\"\n                    << \"\\n\\texample_in.nr():      \" << example_in.nr() \n                    << \"\\n\\texample_in.nc():      \" << example_in.nc() \n                    << \"\\n\\texample_out:          \" << example_out \n                    << \"\\n\\tinput_layer_nodes():  \" << this->input_layer_nodes() \n                    << \"\\n\\toutput_layer_nodes(): \" << this->output_layer_nodes() \n                    << \"\\n\\tthis:                 \" << this\n            );\n\n            mlp_base::train(example_in,example_out);\n        }\n\n    };\n\n    template <\n        typename mlp_base\n        >\n    inline void swap (\n        mlp_kernel_c<mlp_base>& a, \n        mlp_kernel_c<mlp_base>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MLP_KERNEl_C_\n\n\n"
  },
  {
    "path": "dlib/mlp.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MLp_\n#define DLIB_MLp_\n\n#include \"mlp/mlp_kernel_1.h\"\n#include \"mlp/mlp_kernel_c.h\"\n\nnamespace dlib\n{\n\n    class mlp\n    {\n        mlp() {}\n\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     mlp_kernel_1    \n                    kernel_1a;\n        typedef     mlp_kernel_c<kernel_1a >\n                    kernel_1a_c;   \n\n    };\n}\n\n#endif // DLIB_MLp_\n\n"
  },
  {
    "path": "dlib/noncopyable.h",
    "content": "//  (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost\n//  Software License, Version 1.0. (See accompanying file\n//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//  Contributed by Dave Abrahams\n//  See http://www.boost.org/libs/utility for documentation.\n\n#ifndef DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED\n#define DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED\n\n\nnamespace dlib\n{\n    class noncopyable\n    {\n        /*!\n            This class makes it easier to declare a class as non-copyable.\n            If you want to make an object that can't be copied just inherit\n            from this object.\n        !*/\n\n    protected:\n        noncopyable() = default;\n        ~noncopyable() = default;\n    private:  // emphasize the following members are private\n        noncopyable(const noncopyable&);\n        const noncopyable& operator=(const noncopyable&);\n\n    };\n}\n\n#endif  // DLIB_BOOST_NONCOPYABLE_HPP_INCLUDED\n\n"
  },
  {
    "path": "dlib/numeric_constants.h",
    "content": "//Copyright (C) 2013 Steve Taylor (steve98654@gmail.com), Davis E. King\n//License: Boost Software License.  See LICENSE.txt for full license.\n#ifndef DLIB_NUMERIC_CONSTANTs_H_\n#define DLIB_NUMERIC_CONSTANTs_H_\n\nnamespace dlib \n{\n\n    // pi -- Pi\n    constexpr double pi = 3.1415926535897932384626433832795029L;\n\n    // pi_2 -- Pi / 2\n    constexpr double pi_2 = 1.5707963267948966192313216916397514L;\n    \n    // pi_3 -- Pi / 3\n    constexpr double pi_3 = 1.0471975511965977461542144610931676L;\n\n    // pi_4 -- Pi / 4\n    constexpr double pi_4 = 0.7853981633974483096156608458198757L;\n\n    // e  -- Euler's Constant\n    constexpr double e = 2.7182818284590452353602874713526625L;\n    constexpr double euler = e;\n\n    // sqrt_2 -- The square root of 2\n    constexpr double sqrt_2 = 1.4142135623730950488016887242096981L;\n\n    // sqrt_3 -- The square root of 3\n    constexpr double sqrt_3 = 1.7320508075688772935274463415058723L;\n\n    // log10_2 -- The logarithm base 10 of two\n    constexpr double log10_2 = 0.30102999566398119521;\n\n    // light_spd -- The speed of light in vacuum in meters per second\n    constexpr double light_spd = 2.99792458e8;\n\n    // newton_G  -- Newton's gravitational constant (in metric units of m^3/(kg*s^2))\n    constexpr double newton_G = 6.67384e-11;\n\n    // planck_cst -- Planck's constant (in units of Joules * seconds) \n    constexpr double planck_cst = 6.62606957e-34;\n\n    // golden_ratio -- The Golden Ratio\n    constexpr double golden_ratio = 1.6180339887498948482;\n\n    // euler_gamma -- The Euler Mascheroni Constant \n    constexpr double euler_gamma = 0.5772156649015328606065120900824024L;\n\n    // catalan -- Catalan's Constant\n    constexpr double catalan = 0.91596559417721901505;\n\n    // glaisher -- Glaisher Kinkelin constant\n    constexpr double glaisher = 1.2824271291006226369;\n\n    // khinchin -- Khinchin's constant\n    constexpr double khinchin = 2.6854520010653064453;\n\n    // apery -- Apery's constant\n    constexpr double apery = 1.2020569031595942854;\n}\n\n#endif //DLIB_NUMERIC_CONSTANTs_H_\n\n"
  },
  {
    "path": "dlib/numerical_integration/integrate_function_adapt_simpson.h",
    "content": "// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com)\n// License: Boost Software License  See LICENSE.txt for full license\n#ifndef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSONh_\n#define DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSONh_\n\n#include \"integrate_function_adapt_simpson_abstract.h\"\n#include \"../assert.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    template <typename T, typename funct>\n    T impl_adapt_simp_stop(const funct& f, T a, T b, T fa, T fm, T fb, T is, int cnt)\n    {\n        const int maxint = 500;\n\n        T m   = (a + b)/2.0;\n        T h   = (b - a)/4.0;\n        T fml = f(a + h);\n        T fmr = f(b - h);\n        T i1 = h/1.5*(fa+4.0*fm+fb);\n        T i2 = h/3.0*(fa+4.0*(fml+fmr)+2.0*fm+fb);\n        i1 = (16.0*i2 - i1)/15.0;\n        T Q = 0;\n\n        if ((std::abs(i1-i2) <= std::abs(is)) || (m <= a) || (b <= m))\n        {\n            Q = i1;\n        }\n        else \n        {\n            if(cnt < maxint)\n            {\n                cnt = cnt + 1;\n\n                Q = impl_adapt_simp_stop(f,a,m,fa,fml,fm,is,cnt) \n                    + impl_adapt_simp_stop(f,m,b,fm,fmr,fb,is,cnt); \n            }\n        }\n\n        return Q;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename funct>\n    T integrate_function_adapt_simp(\n        const funct& f,\n        T a,\n        T b,\n        T tol = 1e-10\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(b > a && tol > 0,\n            \"\\t T integrate_function_adapt_simp()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            << \"\\n\\t a:   \" << a\n            << \"\\n\\t b:   \" << b\n            << \"\\n\\t tol: \" << tol \n            );\n\n        T eps = std::numeric_limits<T>::epsilon();\n        if(tol < eps)\n        {\n            tol = eps;\n        }\n\n        const T ba = b-a;\n        const T fa = f(a);\n        const T fb = f(b);\n        const T fm = f((a+b)/2);\n\n        T is = ba/8*(fa+fb+fm+ f(a + 0.9501*ba) + f(a + 0.2311*ba) + f(a + 0.6068*ba)\n            + f(a + 0.4860*ba) + f(a + 0.8913*ba));\n\n        if(is == 0)\n        {\n            is = b-a;\n        }\n\n        is = is*tol;\n\n        int cnt = 0;\n\n        return impl_adapt_simp_stop(f, a, b, fa, fm, fb, is, cnt);\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSONh_\n"
  },
  {
    "path": "dlib/numerical_integration/integrate_function_adapt_simpson_abstract.h",
    "content": "// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com)\n// License: Boost Software License  See LICENSE.txt for the full license.\n#undef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_\n#ifdef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_\n\nnamespace dlib\n{\n\n    template <typename T, typename funct>\n    T integrate_function_adapt_simp(\n        const funct& f, \n        T a, \n        T b, \n        T tol = 1e-10\n    );\n    /*!\n        requires \n            - b > a\n            - tol > 0\n            - T should be either float, double, or long double\n            - The expression f(a) should be a valid expression that evaluates to a T.\n              I.e. f() should be a real valued function of a single variable.\n        ensures\n            - returns an approximation of the integral of f over the domain [a,b] using the\n              adaptive Simpson method outlined in Gander, W. and W. Gautshi, \"Adaptive\n              Quadrature -- Revisited\" BIT, Vol. 40, (2000), pp.84-101\n            - tol is a tolerance parameter that determines the overall accuracy of\n              approximated integral.  We suggest a default value of 1e-10 for tol. \n    !*/\n\n}\n\n#endif // DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_ABSTRACTh_\n\n"
  },
  {
    "path": "dlib/numerical_integration.h",
    "content": "// Copyright (C) 2013 Steve Taylor (steve98654@gmail.com)\n// License: Boost Software License  See LICENSE.txt for the full license.\n#ifndef DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_HEADER\n#define DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_HEADER\n\n#include \"numerical_integration/integrate_function_adapt_simpson.h\"\n\n#endif // DLIB_INTEGRATE_FUNCTION_ADAPT_SIMPSON_HEADER\n"
  },
  {
    "path": "dlib/opencv/cv_image.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_CvIMAGE_H_\n#define DLIB_CvIMAGE_H_\n\n#include <opencv2/core/core.hpp>\n#include <opencv2/core/types_c.h>\n#include \"cv_image_abstract.h\"\n#include \"../algs.h\"\n#include \"../pixel.h\"\n#include \"../matrix/matrix_mat.h\"\n#include \"../image_processing/generic_image.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename pixel_type\n        >\n    class cv_image\n    {\n    public:\n        typedef pixel_type type;\n        typedef default_memory_manager mem_manager_type;\n\n        cv_image (const cv::Mat& img) \n        {\n            DLIB_CASSERT(img.depth() == cv::DataType<typename pixel_traits<pixel_type>::basic_pixel_type>::depth &&\n                         img.channels() == pixel_traits<pixel_type>::num, \n                         \"The pixel type you gave doesn't match pixel used by the open cv Mat object.\"\n                         << \"\\n\\t img.depth():    \" << img.depth() \n                         << \"\\n\\t img.cv::DataType<typename pixel_traits<pixel_type>::basic_pixel_type>::depth: \" \n                            << cv::DataType<typename pixel_traits<pixel_type>::basic_pixel_type>::depth \n                         << \"\\n\\t img.channels(): \" << img.channels() \n                         << \"\\n\\t img.pixel_traits<pixel_type>::num: \" << pixel_traits<pixel_type>::num \n                         );\n// Note, do NOT use CV_VERSION_MAJOR because in OpenCV 2 CV_VERSION_MAJOR actually held\n// CV_VERSION_MINOR and instead they used CV_VERSION_EPOCH.  So for example, in OpenCV\n// 2.4.9.1 CV_VERSION_MAJOR==4 and CV_VERSION_EPOCH==2.  However, CV_MAJOR_VERSION has always\n// (seemingly) held the actual major version number, so we use that to test for the OpenCV major\n// version.\n#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_SUBMINOR_VERSION >= 9)\n            IplImage temp = cvIplImage(img);\n#else\n            IplImage temp = img;\n#endif\n            init(&temp);\n        }\n\n        cv_image (const IplImage img) \n        {\n            init(&img);\n        }\n\n        cv_image (const IplImage* img) \n        {\n            init(img);\n        }\n\n        cv_image() : _data(0), _widthStep(0), _nr(0), _nc(0) {}\n\n        size_t size () const { return static_cast<size_t>(_nr*_nc); }\n\n        inline pixel_type* operator[](const long row ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(0 <= row && row < nr(),\n                \"\\tpixel_type* cv_image::operator[](row)\"\n                << \"\\n\\t you have asked for an out of bounds row \" \n                << \"\\n\\t row:  \" << row\n                << \"\\n\\t nr(): \" << nr() \n                << \"\\n\\t this:  \" << this\n                );\n\n            return reinterpret_cast<pixel_type*>( _data + _widthStep*row);\n        }\n\n        inline const pixel_type* operator[](const long row ) const\n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(0 <= row && row < nr(),\n                \"\\tconst pixel_type* cv_image::operator[](row)\"\n                << \"\\n\\t you have asked for an out of bounds row \" \n                << \"\\n\\t row:  \" << row\n                << \"\\n\\t nr(): \" << nr() \n                << \"\\n\\t this:  \" << this\n                );\n\n            return reinterpret_cast<const pixel_type*>( _data + _widthStep*row);\n        }\n\n        inline const pixel_type& operator()(const long row, const long column) const\n        {\n          DLIB_ASSERT(0<= column && column < nc(),\n              \"\\tcont pixel_type& cv_image::operator()(const long rown const long column)\"\n              << \"\\n\\t you have asked for an out of bounds column \"\n              << \"\\n\\t column: \" << column\n              << \"\\n\\t nc(): \" << nc()\n              << \"\\n\\t this:  \" << this\n              );\n\n          return (*this)[row][column];\n        }\n\n        inline pixel_type& operator()(const long row, const long column)\n        {\n          DLIB_ASSERT(0<= column && column < nc(),\n              \"\\tcont pixel_type& cv_image::operator()(const long rown const long column)\"\n              << \"\\n\\t you have asked for an out of bounds column \"\n              << \"\\n\\t column: \" << column\n              << \"\\n\\t nc(): \" << nc()\n              << \"\\n\\t this:  \" << this\n              );\n\n          return (*this)[row][column];\n        }\n\n        long nr() const { return _nr; }\n        long nc() const { return _nc; }\n        size_t width_step() const { return _widthStep; }\n\n    private:\n\n        void init (const IplImage* img) \n        {\n            DLIB_CASSERT( img->dataOrder == 0, \"Only interleaved color channels are supported with cv_image\"); \n            DLIB_CASSERT((img->depth&0xFF)/8*img->nChannels == sizeof(pixel_type), \n                         \"The pixel type you gave doesn't match the size of pixel used by the open cv image struct\");\n\n            _data = img->imageData;\n            _widthStep = img->widthStep;\n            _nr = img->height;\n            _nc = img->width;\n\n        }\n\n        char* _data;\n        long _widthStep;\n        long _nr;\n        long _nc;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_op<op_array2d_to_mat<cv_image<T> > > mat (\n        const cv_image<T>& m \n    )\n    {\n        typedef op_array2d_to_mat<cv_image<T> > op;\n        return matrix_op<op>(op(m));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n// Define the global functions that make cv_image a proper \"generic image\" according to\n// ../image_processing/generic_image.h\n    template <typename T>\n    struct image_traits<cv_image<T> >\n    {\n        typedef T pixel_type;\n    };\n\n    template <typename T>\n    inline long num_rows( const cv_image<T>& img) { return img.nr(); }\n    template <typename T>\n    inline long num_columns( const cv_image<T>& img) { return img.nc(); }\n\n    template <typename T>\n    inline void* image_data(\n        cv_image<T>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T>\n    inline const void* image_data(\n        const cv_image<T>& img\n    )\n    {\n        if (img.size() != 0)\n            return &img[0][0];\n        else\n            return 0;\n    }\n\n    template <typename T>\n    inline size_t width_step(\n        const cv_image<T>& img\n    ) \n    { \n        return img.width_step(); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_CvIMAGE_H_\n\n"
  },
  {
    "path": "dlib/opencv/cv_image_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPENCV_IMAGE_AbSTRACT_H_\n#ifdef DLIB_OPENCV_IMAGE_AbSTRACT_H_\n\n#include <opencv2/core/core.hpp>\n#include <opencv2/core/types_c.h>\n#include \"../algs.h\"\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename pixel_type\n        >\n    class cv_image\n    {\n        /*!\n            REQUIREMENTS ON pixel_type\n                pixel_type just needs to be something that matches the pixel memory\n                layout of whatever OpenCV image you are going to use with this object.\n                For example, you might use unsigned char or bgr_pixel depending\n                on what you needed.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is meant to be used as a simple wrapper around the OpenCV\n                IplImage struct or Mat object.  Using this class template you can turn\n                an OpenCV image into something that looks like a normal dlib style \n                image object.\n\n                So you should be able to use cv_image objects with many of the image\n                processing functions in dlib as well as the GUI tools for displaying\n                images on the screen.\n\n                Note that this object does NOT take ownership of the image data you \n                give to it.  This means it is up to you to make sure the OpenCV image\n                is properly freed at some point.  This also means that an instance of \n                this object can only be used as long as the OpenCV image it references \n                remains valid, since a cv_image just points to the OpenCV image's \n                memory directly.\n        !*/\n\n    public:\n        typedef pixel_type type;\n        typedef default_memory_manager mem_manager_type;\n\n        cv_image (\n            const IplImage* img\n        );\n        /*!\n            requires\n                - img->dataOrder == 0\n                  (i.e. Only interleaved color channels are supported with cv_image)\n                - (img->depth&0xFF)/8*img->nChannels == sizeof(pixel_type)\n                  (i.e. The size of the pixel_type needs to match the size of the pixels \n                  inside the OpenCV image)\n            ensures\n                - #nr() == img->height\n                  #nc() == img->width\n                - using the operator[] on this object you will be able to access the pixels\n                  inside this OpenCV image.\n        !*/\n\n        cv_image (\n            const IplImage img\n        );\n        /*!\n            requires\n                - img.dataOrder == 0\n                  (i.e. Only interleaved color channels are supported with cv_image)\n                - (img.depth&0xFF)/8*img.nChannels == sizeof(pixel_type)\n                  (i.e. The size of the pixel_type needs to match the size of the pixels \n                  inside the OpenCV image)\n            ensures\n                - #nr() == img.height\n                  #nc() == img.width\n                - using the operator[] on this object you will be able to access the pixels\n                  inside this OpenCV image.\n        !*/\n\n        cv_image (\n            const cv::Mat img\n        ); \n        /*!\n            requires\n                - img.depth() == cv::DataType<pixel_traits<pixel_type>::basic_pixel_type>::depth\n                  (i.e. The pixel_type template argument needs to match the type of pixel \n                  used inside the OpenCV image)\n                - img.channels() == pixel_traits<pixel_type>::num\n                  (i.e. the number of channels in the pixel_type needs to match the number of \n                  channels in the OpenCV image)\n            ensures\n                - #nr() == img.rows\n                - #nc() == img.cols\n                - using the operator[] on this object you will be able to access the pixels\n                  inside this OpenCV image.\n        !*/\n\n        cv_image(\n        ); \n        /*!\n            ensures\n                - #nr() == 0\n                - #nc() == 0\n        !*/\n\n        ~cv_image (\n        );\n        /*!\n            ensures\n                - This function does nothing.  e.g. It doesn't delete the OpenCV \n                  image used by this cv_image object\n        !*/\n\n        long nr(\n        ) const; \n        /*!\n            ensures\n                - returns the number of rows in this image\n        !*/\n\n        long nc(\n        ) const;\n        /*!\n            ensures\n                - returns the number of columns in this image\n        !*/\n\n        size_t size (\n        ) const; \n        /*!\n            ensures\n                - returns nr()*nc()\n                  (i.e. returns the number of pixels in this image)\n        !*/\n\n        inline pixel_type* operator[] (\n            const long row \n        );\n        /*!\n            requires\n                - 0 <= row < nr()\n            ensures\n                - returns a pointer to the first pixel in the given row\n                  of this image\n        !*/\n\n        inline const pixel_type* operator[] (\n            const long row \n        ) const;\n        /*!\n            requires\n                - 0 <= row < nr()\n            ensures\n                - returns a pointer to the first pixel in the given row\n                  of this image\n        !*/\n\n        inline const pixel_type& operator()(\n            const long row, const long column\n        ) const\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= column < nc()\n            ensures\n                - returns a const reference to the pixel at coordinates (row, column)\n                  of this image\n        !*/\n\n        inline pixel_type& operator()(\n            const long row, const long column\n        )\n        /*!\n            requires\n                - 0 <= row < nr()\n                - 0 <= column < nc()\n            ensures\n                - returns a reference to the pixel at coordinates (row, column)\n                  of this image\n        !*/\n\n        size_t width_step (\n        ) const;\n        /*!\n            ensures\n                - returns the size of one row of the image, in bytes.  \n                  More precisely, return a number N such that:\n                  (char*)&item[0][0] + N == (char*)&item[1][0].\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    const matrix_exp mat (\n        const cv_image<T>& img\n    );\n    /*!\n        ensures\n            - returns a matrix R such that:\n                - R.nr() == img.nr() \n                - R.nc() == img.nc()\n                - for all valid r and c:\n                  R(r, c) == img[r][c]\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPENCV_IMAGE_AbSTRACT_H_\n\n"
  },
  {
    "path": "dlib/opencv/to_open_cv.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_TO_OPEN_Cv_Hh_\n#define DLIB_TO_OPEN_Cv_Hh_\n\n#include <opencv2/core/core.hpp>\n#include \"to_open_cv_abstract.h\"\n#include \"../pixel.h\"\n#include \"../matrix/matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename image_type\n        >\n    cv::Mat toMat (\n        image_type& img\n    )\n    {\n        if (image_size(img) == 0)\n            return cv::Mat();\n\n        typedef typename image_traits<image_type>::pixel_type type;\n        typedef typename pixel_traits<type>::basic_pixel_type basic_pixel_type;\n        if (pixel_traits<type>::num == 1)\n        {\n            return cv::Mat(num_rows(img), num_columns(img), cv::DataType<basic_pixel_type>::type, image_data(img), width_step(img));\n        }\n        else\n        {\n            int depth = sizeof(typename pixel_traits<type>::basic_pixel_type)*8;\n            int channels = pixel_traits<type>::num;\n            int thetype = CV_MAKETYPE(depth, channels);\n            return cv::Mat(num_rows(img), num_columns(img), thetype, image_data(img), width_step(img));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_TO_OPEN_Cv_Hh_\n\n"
  },
  {
    "path": "dlib/opencv/to_open_cv_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_TO_OPEN_Cv_ABSTRACTh_\n#ifdef DLIB_TO_OPEN_Cv_ABSTRACTh_\n\n#include <opencv2/core/core.hpp>\n#include \"../pixel.h\"\n\nnamespace dlib\n{\n    template <\n        typename image_type\n        >\n    cv::Mat toMat (\n        image_type& img\n    );\n    /*!\n        requires\n            - image_type == an image object that implements the interface defined in\n              dlib/image_processing/generic_image.h or a dlib::matrix object which uses a\n              row_major_layout.\n            - pixel_traits is defined for the contents of img.\n        ensures\n            - returns an OpenCV Mat object which represents the same image as img.  This\n              is done by setting up the Mat object to point to the same memory as img.\n              Therefore, the returned Mat object is valid only as long as pointers\n              to the pixels in img remain valid.\n    !*/\n}\n\n#endif // DLIB_TO_OPEN_Cv_ABSTRACTh_\n\n\n\n"
  },
  {
    "path": "dlib/opencv.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_OPEnCV_HEADER\n#define DLIB_OPEnCV_HEADER\n\n#include \"opencv/cv_image.h\"\n#include \"opencv/to_open_cv.h\"\n\n#endif // DLIB_OPEnCV_HEADER\n\n\n\n\n"
  },
  {
    "path": "dlib/optimization/elastic_net.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ElASTIC_NET_Hh_\n#define DLIB_ElASTIC_NET_Hh_\n\n#include \"../matrix.h\"\n#include \"elastic_net_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class elastic_net\n    {\n    public:\n\n        template <typename EXP>\n        explicit elastic_net(\n            const matrix_exp<EXP>& XX\n        ) : eps(1e-5), max_iterations(50000), verbose(false)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(XX.size() > 0 &&\n                        XX.nr() == XX.nc(),\n                \"\\t elastic_net::elastic_net(XX)\"\n                << \" \\n\\t XX must be a non-empty square matrix.\"\n                << \" \\n\\t XX.nr():   \" << XX.nr() \n                << \" \\n\\t XX.nc():   \" << XX.nc() \n                << \" \\n\\t this: \" << this\n                );\n\n\n            // If the number of columns in X is big and in particular bigger than the number of\n            // rows then we can get rid of them by doing some SVD magic.  Doing this doesn't\n            // make the final results of anything change but makes all the matrices have\n            // dimensions that are X.nr() in size, which can be much smaller.\n            matrix<double,0,1> s;\n            svd3(XX,u,eig_vals,eig_vects);\n            s = sqrt(eig_vals);\n            X = eig_vects*diagm(s);\n            u = eig_vects*inv(diagm(s));\n\n\n\n            samples.resize(X.nr()*2);\n\n            for (size_t i = 0; i < samples.size(); ++i)\n                index.push_back(i);\n            active_size = index.size();\n\n\n            // setup the training samples used in the SVM optimizer below\n            for (size_t i = 0; i < samples.size(); ++i)\n            {\n                auto& x = samples[i];\n                const long idx = i/2;\n                if (i%2 == 0)\n                    x.label = +1;\n                else\n                    x.label = -1;\n\n                x.r = idx%X.nr();\n            }\n        }\n\n        template <typename EXP1, typename EXP2>\n        elastic_net(\n            const matrix_exp<EXP1>& XX,\n            const matrix_exp<EXP2>& XY\n        ) : elastic_net(XX)\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(XX.size() > 0 && \n                        XX.nr() == XX.nc() &&\n                        is_col_vector(XY) && \n                        XX.nc() == XY.size() ,\n                \"\\t elastic_net::elastic_net(XX,XY)\"\n                << \" \\n\\t Invalid inputs were given to this function.\"\n                << \" \\n\\t XX.size(): \" << XX.size() \n                << \" \\n\\t is_col_vector(XY): \" << is_col_vector(XY) \n                << \" \\n\\t XX.nr():   \" << XX.nr() \n                << \" \\n\\t XX.nc():   \" << XX.nc() \n                << \" \\n\\t XY.size(): \" << XY.size() \n                << \" \\n\\t this: \" << this\n                );\n\n            set_xy(XY);\n        }\n\n        long size (\n        ) const { return u.nr(); }\n\n        template <typename EXP>\n        void set_xy(\n            const matrix_exp<EXP>& XY\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_col_vector(XY) && \n                        XY.size() == size(),\n                \"\\t void elastic_net::set_y(Y)\"\n                << \" \\n\\t Invalid inputs were given to this function.\"\n                << \" \\n\\t is_col_vector(XY): \" << is_col_vector(XY) \n                << \" \\n\\t size():    \" << size() \n                << \" \\n\\t XY.size(): \" << XY.size() \n                << \" \\n\\t this: \" << this\n                );\n\n            Y = trans(u)*XY;\n            // We can use the ynorm after it has been projected because the only place Y\n            // appears in the algorithm is in terms of dot products with w and x vectors.\n            // But those vectors are always in the span of X and therefore we only see the\n            // part of the norm of Y that is in the span of X (and hence u since u and X\n            // have the same span by construction)\n            ynorm = length_squared(Y); \n            xdoty = X*Y;\n            eig_vects_xdoty = trans(eig_vects)*xdoty;\n\n            w.set_size(Y.size());\n            // zero out any memory of previous solutions\n            alpha.assign(X.nr()*2, 0);\n        }\n\n        bool have_target_values (\n        ) const { return Y.size() != 0; }\n\n        void set_epsilon(\n            double eps_\n        ) \n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(eps_ > 0,\n                \"\\t void elastic_net::set_epsilon()\"\n                << \" \\n\\t eps_ must be greater than 0\"\n                << \" \\n\\t eps_: \" << eps_ \n                << \" \\n\\t this: \" << this\n                );\n\n            eps = eps_;\n        }\n\n        unsigned long get_max_iterations (\n        ) const { return max_iterations; }\n\n        void set_max_iterations (\n            unsigned long max_iter\n        ) \n        {\n            max_iterations = max_iter;\n        }\n\n        void be_verbose (\n        )\n        {\n            verbose = true;\n        }\n\n        void be_quiet (\n        )\n        {\n            verbose = false;\n        }\n\n        double get_epsilon (\n        ) const { return eps; }\n\n        matrix<double,0,1> operator() (\n            double ridge_lambda,\n            double lasso_budget = std::numeric_limits<double>::infinity()\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(have_target_values() && \n                        ridge_lambda > 0 && \n                        lasso_budget > 0 ,\n                \"\\t matrix<double,0,1> elastic_net::operator()()\"\n                << \" \\n\\t Invalid inputs were given to this function.\"\n                << \" \\n\\t have_target_values(): \" << have_target_values() \n                << \" \\n\\t ridge_lambda: \" << ridge_lambda \n                << \" \\n\\t lasso_budget: \" << lasso_budget \n                << \" \\n\\t this: \" << this\n                );\n\n\n            // First check if lasso_budget is so big that it isn't even active.  We do this\n            // by doing just ridge regression and checking the result.\n            matrix<double,0,1> betas = eig_vects*tmp(inv(diagm(eig_vals + ridge_lambda))*eig_vects_xdoty);\n            if (sum(abs(betas)) <= lasso_budget)\n                return betas;\n\n\n            // Set w back to 0.  We will compute the w corresponding to what is currently\n            // in alpha layer on.  This way w and alpha are always in sync.\n            w = 0;\n            wy_mult = 0;\n            wdoty = 0;\n\n\n            // return dot(w,x)\n            auto dot = [&](const matrix<double,0,1>& w, const en_sample2& x)\n            {\n                const double xmul = -x.label*(1/lasso_budget);\n                // Do the base dot product but don't forget to add in the -(1/t)*y part from the svm reduction paper\n                double val = rowm(X,x.r)*w + xmul*wdoty + wy_mult*xdoty(x.r) + xmul*wy_mult*ynorm;\n\n                return val;\n            };\n\n\n            // perform w += scale*x;\n            auto add_to = [&](matrix<double,0,1>& w, double scale, const en_sample2& x)\n            {\n                const double xmul = -x.label*(1/lasso_budget);\n                wy_mult += scale*xmul;\n                wdoty += scale*xdoty(x.r);\n                w += scale*trans(rowm(X,x.r));\n\n            };\n\n            const double Dii = ridge_lambda;\n\n            // setup the training samples used in the SVM optimizer below\n            for (size_t i = 0; i < samples.size(); ++i)\n            {\n                auto& x = samples[i];\n\n                const double xmul = -x.label*(1/lasso_budget);\n                x.xdotx = xmul*xmul*ynorm;\n                for (long c = 0; c < X.nc(); ++c)\n                    x.xdotx += std::pow(X(x.r,c)+xmul*Y(c), 2.0) - std::pow(xmul*Y(c),2.0);\n\n                // compute the correct w given whatever might be in alpha.\n                if (alpha[i] != 0)\n                    add_to(w, x.label*alpha[i], samples[i]);\n            }\n\n\n            // Now run the optimizer\n            double PG_max_prev = std::numeric_limits<double>::infinity();\n            double PG_min_prev = -std::numeric_limits<double>::infinity();\n\n\n            unsigned int iter;\n            for (iter = 0; iter < max_iterations; ++iter)\n            {\n                // randomly shuffle the indices\n                for (unsigned long i = 0; i < active_size; ++i)\n                {\n                    // pick a random index >= i\n                    const long j = i + rnd.get_random_32bit_number()%(active_size-i);\n                    std::swap(index[i], index[j]);\n                }\n\n                double PG_max = -std::numeric_limits<double>::infinity();\n                double PG_min = std::numeric_limits<double>::infinity();\n                for (size_t ii = 0; ii < active_size; ++ii)\n                {\n                    const auto i = index[ii];\n                    const auto& x = samples[i];\n                    double G = x.label*dot(w, x) - 1 + Dii*alpha[i];\n\n                    double PG = 0;\n                    if (alpha[i] == 0)\n                    {\n                        if (G > PG_max_prev)\n                        {\n                            // shrink the active set of training examples\n                            --active_size;\n                            std::swap(index[ii], index[active_size]);\n                            --ii;\n                            continue;\n                        }\n\n                        if (G < 0)\n                            PG = G;\n                    }\n                    else\n                    {\n                        PG = G;\n                    }\n\n                    if (PG > PG_max) \n                        PG_max = PG;\n                    if (PG < PG_min) \n                        PG_min = PG;\n\n                    // if PG != 0\n                    if (std::abs(PG) > 1e-12)\n                    {\n                        const double alpha_old = alpha[i];\n                        alpha[i] = std::max(alpha[i] - G/(x.xdotx+Dii), (double)0.0);\n                        const double delta = (alpha[i]-alpha_old)*x.label;\n                        add_to(w, delta, x);\n                    }\n                }\n\n                if (verbose)\n                {\n                    std::cout << \"gap:         \" << PG_max - PG_min << std::endl;\n                    std::cout << \"active_size: \" << active_size << std::endl;\n                    std::cout << \"iter:        \" << iter << std::endl;\n                    std::cout << std::endl;\n                }\n\n                if (PG_max - PG_min <= eps)\n                {\n                    // stop if we are within eps tolerance and the last iteration\n                    // was over all the samples\n                    if (active_size == index.size())\n                        break;\n\n                    // Turn off shrinking on the next iteration.  We will stop if the\n                    // tolerance is still <= eps when shrinking is off.\n                    active_size = index.size();\n                    PG_max_prev = std::numeric_limits<double>::infinity();\n                    PG_min_prev = -std::numeric_limits<double>::infinity();\n                }\n                else\n                {\n                    PG_max_prev = PG_max;\n                    PG_min_prev = PG_min;\n                    if (PG_max_prev <= 0)\n                        PG_max_prev = std::numeric_limits<double>::infinity();\n                    if (PG_min_prev >= 0)\n                        PG_min_prev = -std::numeric_limits<double>::infinity();\n                }\n\n\n                // recalculate wdoty every so often to avoid drift.\n                if (iter%100 == 0)\n                    wdoty = dlib::dot(Y, w);\n            }\n\n\n            betas.set_size(alpha.size()/2);\n            for (long i = 0; i < betas.size(); ++i)\n                betas(i) = lasso_budget*(alpha[2*i] - alpha[2*i+1]);\n            betas /= sum(mat(alpha));\n            return betas;\n        }\n\n\n    private:\n\n        struct en_sample2\n        {\n            // X location\n            long r;\n\n\n            double label;\n\n            double xdotx;\n        };\n\n        std::vector<en_sample2> samples;\n        std::vector<double> alpha;\n        double ynorm;\n        matrix<double> X;\n        matrix<double,0,1> Y;\n        matrix<double,0,1> xdoty;\n        double wdoty;\n        double wy_mult; // logically, the real w is what is in the w vector + wy_mult*Y\n        matrix<double,0,1> w;\n        std::vector<long> index; \n        unsigned long active_size;\n\n        matrix<double,0,1> eig_vects_xdoty;\n        matrix<double,0,1> eig_vals;\n        matrix<double> eig_vects;\n        matrix<double> u;\n\n        dlib::rand rnd;\n\n\n        double eps;\n        unsigned long max_iterations;\n        bool verbose;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ElASTIC_NET_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/elastic_net_abstract.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ElASTIC_NET_ABSTRACT_Hh_\n#ifdef DLIB_ElASTIC_NET_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class elastic_net\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for solving the following optimization problem:\n\n                    min_w:      length_squared(X*w - Y) + ridge_lambda*length_squared(w)\n                    such that:  sum(abs(w)) <= lasso_budget\n\n                That is, it solves the elastic net optimization problem.  This object also\n                has the special property that you can quickly obtain different solutions\n                for different settings of ridge_lambda, lasso_budget, and target Y values.\n\n                This is because a large amount of work is precomputed in the constructor.\n                The solver will also remember the previous solution and will use that to\n                warm start subsequent invocations.  Therefore, you can efficiently get\n                solutions for a wide range of regularization parameters.\n                \n                \n                The particular algorithm used to solve it is described in the paper:\n                    Zhou, Quan, et al. \"A reduction of the elastic net to support vector\n                    machines with an application to gpu computing.\" arXiv preprint\n                    arXiv:1409.1976 (2014).  APA \n\n                And for the SVM solver sub-component we use the algorithm from:\n                    Hsieh, Cho-Jui, et al. \"A dual coordinate descent method for large-scale\n                    linear SVM.\" Proceedings of the 25th international conference on Machine\n                    learning. ACM, 2008. \n        !*/\n\n    public:\n\n        template <typename EXP>\n        explicit elastic_net(\n            const matrix_exp<EXP>& XX\n        ); \n        /*!\n            requires\n                - XX.size() != 0\n                - XX.nr() == XX.nc()\n            ensures\n                - #get_epsilon() == 1e-5\n                - #get_max_iterations() == 50000\n                - This object will not be verbose unless be_verbose() is called.\n                - #size() == XX.nc()\n                - #have_target_values() == false\n                - We interpret XX as trans(X)*X where X is as defined in the objective\n                  function discussed above in WHAT THIS OBJECT REPRESENTS.\n        !*/\n\n        template <typename EXP1, typename EXP2>\n        elastic_net(\n            const matrix_exp<EXP1>& XX,\n            const matrix_exp<EXP2>& XY\n        ); \n        /*!\n            requires\n                - XX.size() != 0\n                - XX.nr() == XX.nc()\n                - is_col_vector(XY)\n                - XX.nc() == Y.size()\n            ensures\n                - constructs this object by calling the elastic_net(XX) constructor and\n                  then calling this->set_xy(XY).\n                - #have_target_values() == true \n                - We interpret XX as trans(X)*X where X is as defined in the objective\n                  function discussed above in WHAT THIS OBJECT REPRESENTS.  Similarly, XY\n                  should be trans(X)*Y.\n        !*/\n\n        long size (\n        ) const; \n        /*!\n            ensures\n                - returns the dimensionality of the data loaded into this object.  That is,\n                  how many elements are in the optimal w vector?  This function returns\n                  that number.\n        !*/\n\n        bool have_target_values (\n        ) const;\n        /*!\n            ensures\n                - returns true if set_xy() has been called and false otherwise.\n        !*/\n\n        template <typename EXP>\n        void set_xy(\n            const matrix_exp<EXP>& XY\n        );\n        /*!\n            requires\n                - is_col_vector(Y)\n                - Y.size() == size()\n            ensures\n                - #have_target_values() == true\n                - Sets the target values of the regression.  Note that we expect the given\n                  matrix, XY, to be equal to trans(X)*Y, where X and Y have the definitions\n                  discussed above in WHAT THIS OBJECT REPRESENTS.\n        !*/\n\n        void set_epsilon(\n            double eps\n        );\n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_epsilon() == eps\n        !*/\n\n        double get_epsilon (\n        ) const;\n        /*!\n            ensures\n                - returns the error epsilon that determines when the solver should stop.\n                  Smaller values may result in a more accurate solution but take longer to\n                  execute.  \n        !*/\n\n        unsigned long get_max_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the maximum number of iterations the optimizer is allowed to run\n                  before it is required to stop and return a result.\n        !*/\n\n        void set_max_iterations (\n            unsigned long max_iter\n        );\n        /*!\n            ensures\n                - #get_max_iterations() == max_iter\n        !*/\n\n        void be_verbose (\n        );\n        /*!\n            ensures\n                - This object will print status messages to standard out so that a \n                  user can observe the progress of the algorithm.\n        !*/\n\n        void be_quiet (\n        );\n        /*!\n            ensures\n                - this object will not print anything to standard out.\n        !*/\n\n\n        matrix<double,0,1> operator() (\n            double ridge_lambda,\n            double lasso_budget = std::numeric_limits<double>::infinity()\n        );\n        /*!\n            requires\n                - have_target_values() == true\n                - ridge_lambda > 0\n                - lasso_budget > 0\n            ensures\n                - Solves the optimization problem described in the WHAT THIS OBJECT\n                  REPRESENTS section above and returns the optimal w.\n                - The returned vector has size() elements.\n                - if (lasso_budget == infinity) then\n                    - The lasso constraint is ignored \n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_ElASTIC_NET_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/find_max_factor_graph_nmplp.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_\n#define DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_\n\n#include \"find_max_factor_graph_nmplp_abstract.h\"\n#include <vector>\n#include <map>\n#include \"../matrix.h\"\n#include \"../hash.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        class simple_hash_map\n        {\n        public:\n\n            simple_hash_map(\n            ) : \n                scan_dist(6)\n            {\n                data.resize(5000);\n            }\n\n            void insert (\n                const unsigned long a,\n                const unsigned long b,\n                const unsigned long value\n            ) \n            /*!\n                requires\n                    - a != std::numeric_limits<unsigned long>::max()\n                ensures\n                    - #(*this)(a,b) == value\n            !*/\n            {\n                const uint32 h = murmur_hash3_2(a,b)%(data.size()-scan_dist);\n\n                const unsigned long empty_bucket = std::numeric_limits<unsigned long>::max();\n\n                for (uint32 i = 0; i < scan_dist; ++i)\n                {\n                    if (data[i+h].key1 == empty_bucket)\n                    {\n                        data[i+h].key1 = a;\n                        data[i+h].key2 = b;\n                        data[i+h].value = value;\n                        return;\n                    }\n                }\n\n                // if we get this far it means the hash table is filling up.  So double its size.\n                std::vector<bucket> new_data;\n                new_data.resize(data.size()*2);\n                new_data.swap(data);\n                for (uint32 i = 0; i < new_data.size(); ++i)\n                {\n                    if (new_data[i].key1 != empty_bucket)\n                    {\n                        insert(new_data[i].key1, new_data[i].key2, new_data[i].value);\n                    }\n                }\n\n                insert(a,b,value);\n            }\n\n            unsigned long operator() (\n                const unsigned long a,\n                const unsigned long b\n            ) const\n            /*!\n                requires\n                    - this->insert(a,b,some_value) has been called\n                ensures\n                    - returns the value stored at key (a,b)\n            !*/\n            {\n                DLIB_ASSERT(a != b, \"An invalid map_problem was given to find_max_factor_graph_nmplp().\"\n                            << \"\\nNode \" << a << \" is listed as being a neighbor with itself, which is illegal.\");\n\n                uint32 h = murmur_hash3_2(a,b)%(data.size()-scan_dist);\n\n\n                for (unsigned long i = 0; i < scan_dist; ++i)\n                {\n                    if (data[h].key1 == a && data[h].key2 == b)\n                    {\n                        return data[h].value;\n                    }\n                    ++h;\n                }\n                \n\n                // this should never happen (since this function requires (a,b) to be in the hash table\n                DLIB_ASSERT(false, \"An invalid map_problem was given to find_max_factor_graph_nmplp().\"\n                            << \"\\nThe nodes in the map_problem are inconsistent because node \"<<a<<\" is in the neighbor list\"\n                            << \"\\nof node \"<<b<< \" but node \"<<b<<\" isn't in the neighbor list of node \"<<a<<\".  The neighbor relationship\"\n                            << \"\\nis supposed to be symmetric.\"\n                            );\n                return 0;\n            }\n\n        private:\n\n            struct bucket\n            {\n                // having max() in key1 indicates that the bucket isn't used.\n                bucket() : key1(std::numeric_limits<unsigned long>::max()) {}\n                unsigned long key1;\n                unsigned long key2;\n                unsigned long value;\n            };\n\n            std::vector<bucket> data;\n            const unsigned int scan_dist;\n        };\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_problem\n        >\n    void find_max_factor_graph_nmplp (\n        const map_problem& prob,\n        std::vector<unsigned long>& map_assignment,\n        unsigned long max_iter,\n        double eps\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT( eps > 0,\n                     \"\\t void find_max_factor_graph_nmplp()\"\n                     << \"\\n\\t eps must be greater than zero\"\n                     << \"\\n\\t eps:  \" << eps \n                );\n\n        /*\n            This function is an implementation of the NMPLP algorithm introduced in the \n            following papers:\n                Fixing Max-Product: Convergent Message Passing Algorithms for MAP LP-Relaxations (2008)\n                by Amir Globerson and Tommi Jaakkola\n\n                Introduction to dual decomposition for inference (2011)\n                by David Sontag, Amir Globerson, and Tommi Jaakkola \n\n            In particular, this function implements the star MPLP update equations shown as\n            equation 1.20 from the paper Introduction to dual decomposition for inference\n            (the method was called NMPLP in the first paper).  It should also be noted that\n            the original description of the NMPLP in the first paper had an error in the\n            equations and the second paper contains corrected equations, which is what this \n            function uses.\n        */\n\n        typedef typename map_problem::node_iterator node_iterator;\n        typedef typename map_problem::neighbor_iterator neighbor_iterator;\n\n        map_assignment.resize(prob.number_of_nodes());\n\n\n        if (prob.number_of_nodes() == 0)\n            return;\n\n\n        std::vector<double> delta_elements;\n        delta_elements.reserve(prob.number_of_nodes()*prob.num_states(prob.begin())*3);\n\n        impl::simple_hash_map delta_idx;\n\n\n\n        // Initialize delta to zero and fill up the hash table with the appropriate values\n        // so we can index into delta later on.\n        for (node_iterator i = prob.begin(); i != prob.end(); ++i)\n        {\n            const unsigned long id_i = prob.node_id(i);\n\n            for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)\n            {\n                const unsigned long id_j = prob.node_id(j);\n                delta_idx.insert(id_i, id_j, delta_elements.size());\n\n                const unsigned long num_states_xj = prob.num_states(j);\n                for (unsigned long xj = 0; xj < num_states_xj; ++xj)\n                    delta_elements.push_back(0);\n            }\n        }\n\n\n        std::vector<double> gamma_i;\n        std::vector<std::vector<double> > gamma_ji;\n        std::vector<std::vector<double> > delta_to_j_no_i;\n        // These arrays will end up with a length equal to the maximum number of neighbors\n        // of any node in the graph.  So reserve a bigish number of slots so that we are\n        // very unlikely to need to preform an expensive reallocation during the\n        // optimization.\n        gamma_ji.reserve(10000);\n        delta_to_j_no_i.reserve(10000);\n\n\n        double max_change = eps + 1; \n        // Now do the main body of the optimization. \n        unsigned long iter;\n        for (iter = 0; iter < max_iter && max_change > eps; ++iter)\n        {\n            max_change = -std::numeric_limits<double>::infinity();\n\n            for (node_iterator i = prob.begin(); i != prob.end(); ++i)\n            {\n                const unsigned long id_i = prob.node_id(i);\n                const unsigned long num_states_xi = prob.num_states(i);\n                gamma_i.assign(num_states_xi, 0);\n\n                double num_neighbors = 0;\n\n                unsigned int jcnt = 0;\n                // first we fill in the gamma vectors\n                for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)\n                {\n                    // Make sure these arrays are big enough to hold all the neighbor\n                    // information.\n                    if (jcnt >= gamma_ji.size())\n                    {\n                        gamma_ji.resize(gamma_ji.size()+1);\n                        delta_to_j_no_i.resize(delta_to_j_no_i.size()+1);\n                    }\n\n                    ++num_neighbors;\n                    const unsigned long id_j = prob.node_id(j);\n                    const unsigned long num_states_xj = prob.num_states(j);\n\n                    gamma_ji[jcnt].assign(num_states_xi, -std::numeric_limits<double>::infinity());\n                    delta_to_j_no_i[jcnt].assign(num_states_xj, 0);\n\n                    // compute delta_j^{-i} and store it in delta_to_j_no_i[jcnt]  \n                    for (neighbor_iterator k = prob.begin(j); k != prob.end(j); ++k)\n                    {\n                        const unsigned long id_k = prob.node_id(k);\n                        if (id_k==id_i)\n                            continue;\n                        const double* const delta_kj = &delta_elements[delta_idx(id_k,id_j)];\n                        for (unsigned long xj = 0; xj < num_states_xj; ++xj)\n                        {\n                            delta_to_j_no_i[jcnt][xj] += delta_kj[xj];\n                        }\n                    }\n\n                    // now compute gamma values\n                    for (unsigned long xi = 0; xi < num_states_xi; ++xi)\n                    {\n                        for (unsigned long xj = 0; xj < num_states_xj; ++xj)\n                        {\n                            gamma_ji[jcnt][xi] = std::max(gamma_ji[jcnt][xi], prob.factor_value(i,j,xi,xj) + delta_to_j_no_i[jcnt][xj]);\n                        }\n                        gamma_i[xi] += gamma_ji[jcnt][xi];\n                    }\n                    ++jcnt;\n                }\n\n                // now update the delta values\n                jcnt = 0;\n                for (neighbor_iterator j = prob.begin(i); j != prob.end(i); ++j)\n                {\n                    const unsigned long id_j = prob.node_id(j);\n                    const unsigned long num_states_xj = prob.num_states(j);\n\n                    // messages from j to i\n                    double* const delta_ji = &delta_elements[delta_idx(id_j,id_i)];\n\n                    // messages from i to j\n                    double* const delta_ij = &delta_elements[delta_idx(id_i,id_j)];\n\n                    for (unsigned long xj = 0; xj < num_states_xj; ++xj)\n                    {\n                        double best_val = -std::numeric_limits<double>::infinity();\n\n                        for (unsigned long xi = 0; xi < num_states_xi; ++xi)\n                        {\n                            double val = prob.factor_value(i,j,xi,xj) + 2/(num_neighbors+1)*gamma_i[xi] -gamma_ji[jcnt][xi];\n                            if (val > best_val)\n                                best_val = val;\n                        }\n                        best_val = -0.5*delta_to_j_no_i[jcnt][xj] + 0.5*best_val;\n\n                        if (std::abs(delta_ij[xj] - best_val) > max_change)\n                            max_change = std::abs(delta_ij[xj] - best_val);\n\n                        delta_ij[xj] = best_val;\n                    }\n\n                    for (unsigned long xi = 0; xi < num_states_xi; ++xi)\n                    {\n                        double new_val = -1/(num_neighbors+1)*gamma_i[xi] + gamma_ji[jcnt][xi];\n                        if (std::abs(delta_ji[xi] - new_val) > max_change)\n                            max_change = std::abs(delta_ji[xi] - new_val);\n                        delta_ji[xi] = new_val;\n                    }\n                    ++jcnt;\n                }\n            }\n        }\n\n\n        // now decode the \"beliefs\"\n        std::vector<double> b;\n        for (node_iterator i = prob.begin(); i != prob.end(); ++i)\n        {\n            const unsigned long id_i = prob.node_id(i);\n            b.assign(prob.num_states(i), 0);\n\n            for (neighbor_iterator k = prob.begin(i); k != prob.end(i); ++k)\n            {\n                const unsigned long id_k = prob.node_id(k);\n\n                for (unsigned long xi = 0; xi < b.size(); ++xi)\n                {\n                    const double* const delta_ki = &delta_elements[delta_idx(id_k,id_i)];\n                    b[xi] += delta_ki[xi];\n                }\n            }\n\n            map_assignment[id_i] = index_of_max(mat(b));\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/find_max_factor_graph_nmplp_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_\n#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_\n\n#include <vector>\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class map_problem \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a factor graph or graphical model.  In \n                particular, this object defines the interface a MAP problem on\n                a factor graph must implement if it is to be solved using the \n                find_max_factor_graph_nmplp() routine defined at the bottom of this file.  \n\n                Note that there is no dlib::map_problem object.  What you are\n                looking at here is simply the interface definition for a map problem.\n                You must implement your own version of this object for the problem\n                you wish to solve and then pass it to the find_max_factor_graph_nmplp() routine.\n\n\n                Note also that a factor graph should not have any nodes which are \n                neighbors with themselves.  Additionally, the graph is undirected. This\n                mean that if A is a neighbor of B then B must be a neighbor of A for\n                the map problem to be valid.\n\n\n                Finally, note that the \"neighbor\" relationship between nodes means the\n                following:  Two nodes are neighbors if and only if there is a potential \n                function (implemented by the factor_value() method) which operates on \n                the nodes.\n        !*/\n\n    public:\n\n        class node_iterator\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a simple forward iterator for iterating over \n                    the nodes/variables in this factor graph.  \n\n                    Note that you can't dereference the iterator and\n                    obtain a value.  That is, the iterator is opaque to \n                    the user.  It is used only as an argument to the other \n                    methods defined in this interface.\n            !*/\n\n        public:\n            node_iterator(\n            );\n            /*!\n                ensures\n                    - constructs an iterator in an undefined state\n            !*/\n\n            node_iterator(\n                const node_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n            !*/\n\n            node_iterator& operator= (\n                const node_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n                    - returns #*this\n            !*/\n\n            bool operator== (\n                const node_iterator& item\n            ) const; \n            /*!\n                ensures\n                    - returns true if *this and item both reference\n                      the same node in the factor graph and false \n                      otherwise.\n            !*/\n\n            bool operator!= (\n                const node_iterator& item\n            ) const;\n            /*!\n                ensures\n                    - returns false if *this and item both reference\n                      the same node in the factor graph and true \n                      otherwise.\n            !*/\n\n            node_iterator& operator++(\n            );\n            /*!\n                ensures\n                    - advances *this to the next node in the factor graph.\n                    - returns a reference to the updated *this\n                      (i.e. this is the ++object form of the increment operator)\n            !*/\n        };\n\n        class neighbor_iterator\n        {\n            /*!\n                WHAT THIS OBJECT REPRESENTS\n                    This is a simple forward iterator for iterating over \n                    the nodes/variables in this factor graph.  This version\n                    of the iterator is used for iterating over the neighbors\n                    of another node in the graph.\n            !*/\n\n        public:\n            neighbor_iterator(\n            ); \n            /*!\n                ensures\n                    - constructs an iterator in an undefined state\n            !*/\n\n            neighbor_iterator(\n                const neighbor_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n            !*/\n\n            neighbor_iterator& operator= (\n                const neighbor_iterator& item\n            );\n            /*!\n                ensures\n                    - #*this is a copy of item\n                    - returns #*this\n            !*/\n\n            bool operator== (\n                const neighbor_iterator& item\n            ) const; \n            /*!\n                ensures\n                    - returns true if *this and item both reference\n                      the same node in the factor graph and false \n                      otherwise.\n            !*/\n\n            bool operator!= (\n                const neighbor_iterator& item\n            ) const;\n            /*!\n                ensures\n                    - returns false if *this and item both reference\n                      the same node in the factor graph and true \n                      otherwise.\n            !*/\n\n            neighbor_iterator& operator++(\n            ); \n            /*!\n                ensures\n                    - advances *this to the next node in the factor graph.\n                    - returns a reference to the updated *this\n                      (i.e. this is the ++object form of the increment operator) \n            !*/\n        };\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the factor graph.  Or in other words, \n                  returns the number of variables in the MAP problem.\n        !*/\n\n        node_iterator begin(\n        ) const;\n        /*!\n            ensures\n                - returns an iterator to the first node in the graph.  If no such\n                  node exists then returns end().\n        !*/\n\n        node_iterator end(\n        ) const;\n        /*!\n            ensures\n                - returns an iterator to one past the last node in the graph.\n        !*/\n\n        neighbor_iterator begin(\n            const node_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [begin(), end()))\n            ensures\n                - returns an iterator to the first neighboring node of the node\n                  referenced by it.  If no such node exists then returns end(it).\n        !*/\n\n        neighbor_iterator begin(\n            const neighbor_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator. (i.e. it must be in the range \n                  [begin(i), end(i)) where i is some valid iterator. ) \n            ensures\n                - returns an iterator to the first neighboring node of the node\n                  referenced by it.  If no such node exists then returns end(it).\n        !*/\n\n        neighbor_iterator end(\n            const node_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [begin(), end()))\n            ensures\n                - returns an iterator to one past the last neighboring node of the node\n                  referenced by it.\n        !*/\n\n        neighbor_iterator end(\n            const neighbor_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator. (i.e. it must be in the range \n                  [begin(i), end(i)) where i is some valid iterator. ) \n            ensures\n                - returns an iterator to one past the last neighboring node of the node\n                  referenced by it.\n        !*/\n\n        unsigned long node_id (\n            const node_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [begin(), end()))\n            ensures\n                - returns a number ID such that:\n                    - 0 <= ID < number_of_nodes()\n                    - ID == a number which uniquely identifies the node pointed to by it.\n        !*/\n\n        unsigned long node_id (\n            const neighbor_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator. (i.e. it must be in the range \n                  [begin(i), end(i)) where i is some valid iterator. ) \n            ensures\n                - returns a number ID such that:\n                    - 0 <= ID < number_of_nodes()\n                    - ID == a number which uniquely identifies the node pointed to by it.\n        !*/\n\n        unsigned long num_states (\n            const node_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator (i.e. it must be in the range [begin(), end()))\n            ensures\n                - returns the number of states attainable by the node/variable referenced by it.\n        !*/\n\n        unsigned long num_states (\n            const neighbor_iterator& it\n        ) const;\n        /*!\n            requires\n                - it == a valid iterator. (i.e. it must be in the range \n                  [begin(i), end(i)) where i is some valid iterator. ) \n            ensures\n                - returns the number of states attainable by the node/variable referenced by it.\n        !*/\n\n        // The next four functions all have the same contract.\n        double factor_value (const node_iterator& it1,     const node_iterator& it2,     unsigned long s1, unsigned long s2) const;\n        double factor_value (const neighbor_iterator& it1, const node_iterator& it2,     unsigned long s1, unsigned long s2) const;\n        double factor_value (const node_iterator& it1,     const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const;\n        double factor_value (const neighbor_iterator& it1, const neighbor_iterator& it2, unsigned long s1, unsigned long s2) const;\n        /*!\n            requires\n                - it1 == a valid iterator\n                - it2 == a valid iterator\n                - 0 <= s1 < num_states(it1)\n                - 0 <= s2 < num_states(it2)\n                - it1 and it2 reference nodes which are neighbors in the factor graph\n            ensures\n                - returns the value of the factor/potential function for the given pair of \n                  nodes, defined by it1 and it2, for the case where they take on the values\n                  s1 and s2 respectively.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_problem\n        >\n    void find_max_factor_graph_nmplp (\n        const map_problem& prob,\n        std::vector<unsigned long>& map_assignment,\n        unsigned long max_iter,\n        double eps\n    );\n    /*!\n        requires\n            - for all valid i: prob.num_states(i) >= 2\n            - map_problem == an object with an interface compatible with the map_problem\n              object defined at the top of this file.\n            - eps > 0\n        ensures\n            - This function is a tool for approximately solving the given MAP problem in a graphical \n              model or factor graph with pairwise potential functions.  That is, it attempts \n              to solve a certain kind of optimization problem which can be defined as follows:\n                 maximize: f(X)\n                 where X is a set of integer valued variables and f(X) can be written as the \n                 sum of functions which each involve only two variables from X.  In reference \n                 to the prob object, the nodes in prob represent the variables in X and the \n                 functions which are summed are represented by prob.factor_value().\n            - #map_assignment == the result of the optimization.   \n            - #map_assignment.size() == prob.number_of_nodes()\n            - for all valid i:\n                - #map_assignment[prob.node_id(i)] < prob.num_states(i)\n                - #map_assignment[prob.node_id(i)] == The approximate MAP assignment for node/variable i.\n            - eps controls the stopping condition, smaller values of eps lead to more accurate \n              solutions of the relaxed linear program but may take more iterations.  Note that\n              the algorithm will never execute more than max_iter iterations regardless of\n              the setting of eps.\n            - If the graph is tree-structured then this routine always gives the exact solution \n              to the MAP problem.  However, for graphs with cycles, the solution may be approximate.\n              \n\n            - This function is an implementation of the NMPLP algorithm introduced in the\n              following papers:\n                Fixing Max-Product: Convergent Message Passing Algorithms for MAP LP-Relaxations (2008)\n                by Amir Globerson and Tommi Jaakkola\n\n                Introduction to dual decomposition for inference (2011)\n                by David Sontag, Amir Globerson, and Tommi Jaakkola \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_nMPLP_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/find_max_factor_graph_viterbi.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_\n#define DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_\n\n#include \"find_max_factor_graph_viterbi_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include \"../array2d.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        struct viterbi_data\n        {\n            viterbi_data() :val(-std::numeric_limits<double>::infinity()), back_index(0) {}\n            double val;\n            unsigned long back_index;\n        };\n\n        template <long NC>\n        inline bool advance_state(\n            matrix<unsigned long,1,NC>& node_states,\n            unsigned long num_states\n        )\n        /*!\n            ensures\n                - advances node_states to the next state by adding 1\n                  to node_states(node_states.size()-1) and carrying any \n                  rollover (modulo num_states).  Stores the result into #node_states.\n                - if (#node_states is all zeros) then\n                    - returns false\n                - else\n                    - returns true\n        !*/\n        {\n            for (long i = node_states.size()-1; i >= 0; --i)\n            {\n                node_states(i) += 1;\n                if (node_states(i) < num_states)\n                    return true;\n\n                node_states(i) = 0;\n            }\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_problem\n        >\n    void find_max_factor_graph_viterbi (\n        const map_problem& prob,\n        std::vector<unsigned long>& map_assignment\n    )\n    {\n        using namespace dlib::impl;\n        const unsigned long order = prob.order();\n        const unsigned long num_states = prob.num_states();\n\n\n        DLIB_ASSERT(prob.num_states() > 0,\n            \"\\t void find_max_factor_graph_viterbi()\"\n            << \"\\n\\t The nodes in a factor graph have to be able to take on more than 0 states.\"\n            );\n        DLIB_ASSERT(std::pow(num_states,(double)order) < std::numeric_limits<unsigned long>::max(),\n            \"\\t void find_max_factor_graph_viterbi()\"\n            << \"\\n\\t The order is way too large for this algorithm to handle.\"\n            << \"\\n\\t order:      \" << order\n            << \"\\n\\t num_states: \" << num_states \n            << \"\\n\\t std::pow(num_states,order):                \" << std::pow(num_states,(double)order) \n            << \"\\n\\t std::numeric_limits<unsigned long>::max(): \" << std::numeric_limits<unsigned long>::max() \n            );\n\n        if (prob.number_of_nodes() == 0)\n        {\n            map_assignment.clear();\n            return;\n        }\n\n        if (order == 0)\n        {\n            map_assignment.resize(prob.number_of_nodes());\n            for (unsigned long i = 0; i < map_assignment.size(); ++i)\n            {\n                matrix<unsigned long,1,1> node_state;\n                unsigned long best_state = 0;\n                double best_val = -std::numeric_limits<double>::infinity();\n                for (unsigned long s = 0; s < num_states; ++s)\n                {\n                    node_state(0) = s;\n                    const double temp = prob.factor_value(i,node_state);\n                    if (temp > best_val)\n                    {\n                        best_val = temp;\n                        best_state = s;\n                    }\n                }\n                map_assignment[i] = best_state;\n            }\n            return;\n        }\n\n\n        const unsigned long trellis_size = static_cast<unsigned long>(std::pow(num_states,(double)order)); \n        unsigned long init_ring_size = 1; \n\n        array2d<impl::viterbi_data> trellis;\n        trellis.set_size(prob.number_of_nodes(), trellis_size);\n\n\n        for (unsigned long node = 0; node < prob.number_of_nodes(); ++node)\n        {\n\n            if (node < order)\n            {\n                matrix<unsigned long,1,0> node_states;\n                node_states.set_size(std::min<int>(node, order) + 1);\n                node_states = 0;\n\n                unsigned long idx = 0;\n                if (node == 0)\n                {\n                    do \n                    {\n                        trellis[node][idx].val = prob.factor_value(node,node_states);\n                        ++idx;\n                    } while(advance_state(node_states,num_states));\n                }\n                else\n                {\n                    init_ring_size *= num_states;\n                    do \n                    {\n                        const unsigned long back_index = idx%init_ring_size;\n                        trellis[node][idx].val = prob.factor_value(node,node_states) + trellis[node-1][back_index].val;\n                        trellis[node][idx].back_index = back_index;\n                        ++idx;\n                    } while(advance_state(node_states,num_states));\n\n                }\n            }\n            else if (order == 1)\n            {\n                /*\n                    WHAT'S THE DEAL WITH THIS PREPROCESSOR MACRO?\n                        Well, if we can declare the dimensions of node_states as a compile\n                        time constant then this function runs significantly faster.  So this macro\n                        is here to let us do that.  It just lets us avoid replicating this code\n                        block in the following if statements for different order sizes.\n                */\n#define DLIB_FMFGV_WORK                                                                                                     \\\n                node_states = 0;                                                                                            \\\n                unsigned long count = 0;                                                                                    \\\n                for (unsigned long i = 0; i < trellis_size; ++i)                                                            \\\n                {                                                                                                           \\\n                    unsigned long back_index = 0;                                                                           \\\n                    double best_score = -std::numeric_limits<double>::infinity();                                           \\\n                    for (unsigned long s = 0; s < num_states; ++s)                                                          \\\n                    {                                                                                                       \\\n                        const double temp = prob.factor_value(node,node_states) + trellis[node-1][count%trellis_size].val;  \\\n                        if (temp > best_score)                                                                              \\\n                        {                                                                                                   \\\n                            best_score = temp;                                                                              \\\n                            back_index = count%trellis_size;                                                                \\\n                        }                                                                                                   \\\n                        advance_state(node_states,num_states);                                                              \\\n                        ++count;                                                                                            \\\n                    }                                                                                                       \\\n                    trellis[node][i].val = best_score;                                                                      \\\n                    trellis[node][i].back_index = back_index;                                                               \\\n                }\n\n                matrix<unsigned long,1,2> node_states;\n                DLIB_FMFGV_WORK\n            }\n            else if (order == 2)\n            {\n                matrix<unsigned long,1,3> node_states;\n                DLIB_FMFGV_WORK\n            }\n            else if (order == 3)\n            {\n                matrix<unsigned long,1,4> node_states;\n                DLIB_FMFGV_WORK\n            }\n            else \n            {\n                // The general case, here we don't define the size of node_states at compile time.\n                matrix<unsigned long,1,0> node_states(order+1);\n                DLIB_FMFGV_WORK\n            }\n        }\n\n\n        map_assignment.resize(prob.number_of_nodes());\n        // Figure out which state of the last node has the biggest value. \n        unsigned long back_index = 0;\n        double best_val = -std::numeric_limits<double>::infinity();\n        for (long i = 0; i < trellis.nc(); ++i)\n        {\n            if (trellis[trellis.nr()-1][i].val > best_val)\n            {\n                best_val = trellis[trellis.nr()-1][i].val;\n                back_index = i;\n            }\n        }\n        // Follow the back links to find the decoding.\n        for (long node = map_assignment.size()-1; node >= 0; --node)\n        {\n            map_assignment[node] = back_index/init_ring_size;\n            back_index = trellis[node][back_index].back_index;\n            if (node < (long)order)\n                init_ring_size /= num_states;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/find_max_factor_graph_viterbi_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_\n#ifdef DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_\n\n#include <vector>\n#include \"../matrix.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class map_problem \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a chain-structured factor graph or graphical \n                model.  In particular, this object defines the interface a MAP problem \n                on a factor graph must implement if it is to be solved using the \n                find_max_factor_graph_viterbi() routine defined at the bottom of this file.  \n\n                Note that there is no dlib::map_problem object.  What you are looking \n                at here is simply the interface definition for a map problem.  You must \n                implement your own version of this object for the problem you wish to \n                solve and then pass it to the find_max_factor_graph_viterbi() routine.\n        !*/\n\n    public:\n\n        unsigned long order (\n        ) const;\n        /*!\n            ensures\n                - returns the order of this model.  The order has the following interpretation:\n                  This model can represent a high order Markov chain.  If order()==1 then map_problem\n                  represents a basic chain-structured graph where nodes only depend on their immediate\n                  neighbors.  However, high order Markov models can also be used by setting order() > 1.\n        !*/\n\n        unsigned long num_states (\n        ) const;\n        /*!\n            ensures\n                - returns the number of states attainable by each variable/node in the graph.\n        !*/\n\n        unsigned long number_of_nodes (\n        ) const;\n        /*!\n            ensures\n                - returns the number of nodes in the factor graph.  Or in other words, \n                  returns the number of variables in the MAP problem.\n        !*/\n\n        template <\n            typename EXP \n            >\n        double factor_value (\n            unsigned long node_id,\n            const matrix_exp<EXP>& node_states\n        ) const;\n        /*!\n            requires\n                - EXP::type == unsigned long\n                  (i.e. node_states contains unsigned longs)\n                - node_id < number_of_nodes()\n                - node_states.size() == min(node_id, order()) + 1\n                - is_vector(node_states) == true\n                - max(node_states) < num_states()\n            ensures\n                - In a chain-structured graph, each node has a potential function associated with\n                  it.  The potential function operates on the variable given by the node as well\n                  as the order() previous variables.  Therefore, factor_value() returns the value \n                  of the factor/potential function associated with node node_id where the following \n                  nodes take on the values defined below:\n                    - node_states(0) == the value of the node with ID node_id\n                    - node_states(i) == the value of the node with ID node_id-i\n                - It is ok for this function to return a value of -std::numeric_limits<double>::infinity().\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename map_problem\n        >\n    void find_max_factor_graph_viterbi (\n        const map_problem& prob,\n        std::vector<unsigned long>& map_assignment\n    );\n    /*!\n        requires\n            - prob.num_states() > 0\n            - std::pow(prob.num_states(), prob.order()) < std::numeric_limits<unsigned long>::max()\n              (i.e. The Viterbi algorithm is exponential in the order of the map problem.  So don't \n              make order too large.)\n            - map_problem == an object with an interface compatible with the map_problem\n              object defined at the top of this file.\n        ensures\n            - This function is a tool for exactly solving the MAP problem in a chain-structured \n              graphical model or factor graph.  That is, it attempts to solve a certain kind of \n              optimization problem which can be defined as follows:\n                - Let X denote a set of prob.number_of_nodes() integer valued variables, each taking\n                  a value in the range [0, prob.num_states()).\n                - Let X(i) = the ith variable in X.\n                - Let F(i) = factor_value_i(X(i), X(i-1), ..., X(i-prob.order()))\n                  (This is the value returned by prob.factor_value(i, node_states).  Note that\n                  each factor's value function operates on at most prob.order()+1 variables.\n                  Moreover, the variables are adjacent and hence the graph is \"chain-structured\".)\n\n                 Then this function finds the assignments to the X variables which  \n                 maximizes: sum over all valid i: F(i)\n\n            - #map_assignment == the result of the optimization.   \n            - #map_assignment.size() == prob.number_of_nodes()\n            - for all valid i:\n                - #map_assignment[i] < prob.num_states()\n                - #map_assignment[i] == The MAP assignment for node/variable i.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_FACTOR_GRAPH_VITERBi_ABSTRACT_Hh_\n\n\n\n"
  },
  {
    "path": "dlib/optimization/find_max_parse_cky.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_FIND_MAX_PaRSE_CKY_Hh_\n#define DLIB_FIND_MAX_PaRSE_CKY_Hh_\n\n#include \"find_max_parse_cky_abstract.h\"\n#include <vector>\n#include <string>\n#include <sstream>\n#include \"../serialize.h\" \n#include \"../array2d.h\"\n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct constituent \n    {\n        unsigned long begin, end, k;\n        T left_tag; \n        T right_tag;\n    };\n\n    template <typename T>\n    void serialize(\n        const constituent<T>& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.begin, out);\n        serialize(item.end, out);\n        serialize(item.k, out);\n        serialize(item.left_tag, out);\n        serialize(item.right_tag, out);\n    }\n\n    template <typename T>\n    void deserialize(\n        constituent<T>& item,\n        std::istream& in \n    )\n    {\n        deserialize(item.begin, in);\n        deserialize(item.end, in);\n        deserialize(item.k, in);\n        deserialize(item.left_tag, in);\n        deserialize(item.right_tag, in);\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    const unsigned long END_OF_TREE = 0xFFFFFFFF;\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct parse_tree_element\n    {\n        constituent<T> c;\n        T tag; // id for the constituent corresponding to this level of the tree\n\n        unsigned long left;\n        unsigned long right; \n        double score; \n    };\n\n    template <typename T>\n    void serialize (\n        const parse_tree_element<T>& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.c, out);\n        serialize(item.tag, out);\n        serialize(item.left, out);\n        serialize(item.right, out);\n        serialize(item.score, out);\n    }\n\n    template <typename T>\n    void deserialize (\n        parse_tree_element<T>& item,\n        std::istream& in \n    )\n    {\n        deserialize(item.c, in);\n        deserialize(item.tag, in);\n        deserialize(item.left, in);\n        deserialize(item.right, in);\n        deserialize(item.score, in);\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        unsigned long fill_parse_tree(\n            std::vector<parse_tree_element<T> >& parse_tree, \n            const T& tag,\n            const array2d<std::map<T, parse_tree_element<T> > >& back, \n            long r, long c\n        )\n        /*!\n            requires\n                - back[r][c].size() == 0 || back[r][c].count(tag) != 0\n        !*/\n        {\n            // base case of the recursion \n            if (back[r][c].size() == 0)\n            {\n                return END_OF_TREE;\n            }\n\n            const unsigned long idx = parse_tree.size();\n            const parse_tree_element<T>& item = back[r][c].find(tag)->second;\n            parse_tree.push_back(item);\n\n            const long k = item.c.k;\n            const unsigned long idx_left  = fill_parse_tree(parse_tree, item.c.left_tag, back, r, k-1); \n            const unsigned long idx_right = fill_parse_tree(parse_tree, item.c.right_tag, back, k, c); \n            parse_tree[idx].left = idx_left;\n            parse_tree[idx].right = idx_right;\n            return idx;\n        }\n    }\n\n    template <typename T, typename production_rule_function>\n    void find_max_parse_cky (\n        const std::vector<T>& sequence,\n        const production_rule_function& production_rules,\n        std::vector<parse_tree_element<T> >& parse_tree\n    )\n    {\n        parse_tree.clear();\n        if (sequence.size() == 0)\n            return;\n\n        array2d<std::map<T,double> > table(sequence.size(), sequence.size());\n        array2d<std::map<T,parse_tree_element<T> > > back(sequence.size(), sequence.size());\n        typedef typename std::map<T,double>::iterator itr;\n        typedef typename std::map<T,parse_tree_element<T> >::iterator itr_b;\n\n        for (long r = 0; r < table.nr(); ++r)\n            table[r][r][sequence[r]] = 0;\n\n        std::vector<std::pair<T,double> > possible_tags;\n\n        for (long r = table.nr()-2; r >= 0; --r)\n        {\n            for (long c = r+1; c < table.nc(); ++c)\n            {\n                for (long k = r; k < c; ++k)\n                {\n                    for (itr i = table[k+1][c].begin(); i != table[k+1][c].end(); ++i)\n                    {\n                        for (itr j = table[r][k].begin(); j != table[r][k].end(); ++j)\n                        {\n                            constituent<T> con;\n                            con.begin = r;\n                            con.end = c+1;\n                            con.k = k+1;\n                            con.left_tag = j->first;\n                            con.right_tag = i->first;\n                            possible_tags.clear();\n                            production_rules(sequence, con, possible_tags);\n                            for (unsigned long m = 0; m < possible_tags.size(); ++m)\n                            {\n                                const double score = possible_tags[m].second + i->second + j->second;\n                                itr match = table[r][c].find(possible_tags[m].first);\n                                if (match == table[r][c].end() || score > match->second)\n                                {\n                                    table[r][c][possible_tags[m].first] = score;\n                                    parse_tree_element<T> item;\n                                    item.c = con;\n                                    item.score = score;\n                                    item.tag = possible_tags[m].first;\n                                    item.left = END_OF_TREE;\n                                    item.right = END_OF_TREE;\n                                    back[r][c][possible_tags[m].first] = item;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n\n        // now use back pointers to build the parse trees\n        const long r = 0;\n        const long c = back.nc()-1;\n        if (back[r][c].size() != 0)\n        {\n\n            // find the max scoring element in back[r][c]\n            itr_b max_i = back[r][c].begin();\n            itr_b i = max_i;\n            ++i;\n            for (; i != back[r][c].end(); ++i)\n            {\n                if (i->second.score > max_i->second.score)\n                    max_i = i;\n            }\n\n            parse_tree.reserve(c);\n            impl::fill_parse_tree(parse_tree, max_i->second.tag, back, r, c);\n        }\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    class parse_tree_to_string_error : public error\n    {\n    public:\n        parse_tree_to_string_error(const std::string& str): error(str) {}\n    };\n\n    namespace impl\n    {\n        template <bool enabled, typename T>\n        typename enable_if_c<enabled>::type conditional_print(\n            const T& item,\n            std::ostream& out\n        ) { out << item << \" \"; }\n\n        template <bool enabled, typename T>\n        typename disable_if_c<enabled>::type conditional_print(\n            const T& ,\n            std::ostream& \n        ) {  }\n\n        template <bool print_tag, bool skip_tag, typename T, typename U >\n        void print_parse_tree_helper (\n            const std::vector<parse_tree_element<T> >& tree,\n            const std::vector<U>& words,\n            unsigned long i,\n            const T& tag_to_skip,\n            std::ostream& out\n        )\n        {\n            if (!skip_tag || tree[i].tag != tag_to_skip)\n                out << \"[\";\n\n            bool left_recurse = false;\n\n            // Only print if we are supposed to.  Doing it this funny way avoids compiler\n            // errors in parse_tree_to_string() for the case where tag isn't\n            // printable.\n            if (!skip_tag || tree[i].tag != tag_to_skip)\n                conditional_print<print_tag>(tree[i].tag, out);\n\n            if (tree[i].left < tree.size())\n            {\n                left_recurse = true;\n                print_parse_tree_helper<print_tag,skip_tag>(tree, words, tree[i].left, tag_to_skip, out);\n            }\n            else\n            {\n                if ((tree[i].c.begin) < words.size())\n                {\n                    out << words[tree[i].c.begin] << \" \";\n                }\n                else\n                {\n                    std::ostringstream sout;\n                    sout << \"Parse tree refers to element \" << tree[i].c.begin \n                         << \" of sequence which is only of size \" << words.size() << \".\";\n                    throw parse_tree_to_string_error(sout.str());\n                }\n            }\n\n            if (left_recurse == true)\n                out << \" \";\n\n            if (tree[i].right < tree.size())\n            {\n                print_parse_tree_helper<print_tag,skip_tag>(tree, words, tree[i].right, tag_to_skip, out);\n            }\n            else\n            {\n                if (tree[i].c.k < words.size())\n                {\n                    out << words[tree[i].c.k];\n                }\n                else\n                {\n                    std::ostringstream sout;\n                    sout << \"Parse tree refers to element \" << tree[i].c.k \n                         << \" of sequence which is only of size \" << words.size() << \".\";\n                    throw parse_tree_to_string_error(sout.str());\n                }\n            }\n\n\n            if (!skip_tag || tree[i].tag != tag_to_skip)\n                out << \"]\";\n        }\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    std::string parse_tree_to_string (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const unsigned long root_idx = 0\n    )\n    {\n        if (root_idx >= tree.size())\n            return \"\";\n\n        std::ostringstream sout;\n        impl::print_parse_tree_helper<false,false>(tree, words, root_idx, tree[root_idx].tag, sout);\n        return sout.str();\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    std::string parse_tree_to_string_tagged (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const unsigned long root_idx = 0\n    )\n    {\n        if (root_idx >= tree.size())\n            return \"\";\n\n        std::ostringstream sout;\n        impl::print_parse_tree_helper<true,false>(tree, words, root_idx, tree[root_idx].tag, sout);\n        return sout.str();\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    std::string parse_trees_to_string (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const T& tag_to_skip\n    )\n    {\n        if (tree.size() == 0)\n            return \"\";\n\n        std::ostringstream sout;\n        impl::print_parse_tree_helper<false,true>(tree, words, 0, tag_to_skip, sout);\n        return sout.str();\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    std::string parse_trees_to_string_tagged (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const T& tag_to_skip\n    )\n    {\n        if (tree.size() == 0)\n            return \"\";\n\n        std::ostringstream sout;\n        impl::print_parse_tree_helper<true,true>(tree, words, 0, tag_to_skip, sout);\n        return sout.str();\n    }\n\n// -----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename T>\n        void helper_find_trees_without_tag (\n            const std::vector<parse_tree_element<T> >& tree,\n            const T& tag,\n            std::vector<unsigned long>& tree_roots,\n            unsigned long idx\n        )\n        {\n            if (idx < tree.size())\n            {\n                if (tree[idx].tag != tag)\n                {\n                    tree_roots.push_back(idx);\n                }\n                else\n                {\n                    helper_find_trees_without_tag(tree, tag, tree_roots, tree[idx].left);\n                    helper_find_trees_without_tag(tree, tag, tree_roots, tree[idx].right);\n                }\n            }\n        }\n    }\n\n    template <typename T>\n    void find_trees_not_rooted_with_tag (\n        const std::vector<parse_tree_element<T> >& tree,\n        const T& tag,\n        std::vector<unsigned long>& tree_roots \n    )\n    {\n        tree_roots.clear();\n        impl::helper_find_trees_without_tag(tree, tag, tree_roots, 0);\n    }\n\n// -----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_PaRSE_CKY_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/find_max_parse_cky_abstract.h",
    "content": "// Copyright (C) 2012  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_\n#ifdef DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_\n\n#include <vector>\n#include <string>\n#include \"../algs.h\" \n#include \"../serialize.h\" \n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    struct constituent \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents the linguistic idea of a constituent, that is, a\n                group of words that functions as a single unit.  In particular, it\n                represents a combination of two constituents into a new constituent.\n\n                Additionally, a constituent object represents a range of words relative to\n                some std::vector of words.  The range is from [begin, end) (i.e. including\n                begin but not including end, so using the normal C++ iterator notation).\n                Moreover, a constituent is always composed of two parts, each having a tag.\n                Therefore, the left part is composed of the words in the range [begin,k)\n                and has tag left_tag while the right part of the constituent contains the\n                words in the range [k,end) and has the tag right_tag.\n\n                The tags are user defined objects of type T.  In general, they are used to\n                represent syntactic categories such as noun phrase, verb phrase, etc.\n        !*/\n\n        unsigned long begin, end, k;\n        T left_tag; \n        T right_tag;\n    };\n\n    template <\n        typename T\n        >\n    void serialize(\n        const constituent<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support\n    !*/\n\n    template <\n        typename T\n        >\n    void deserialize(\n        constituent<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n    /*!A END_OF_TREE is used to indicate that parse_tree_element::left or\n         parse_tree_element::right doesn't point to another subtree.\n    !*/\n    const unsigned long END_OF_TREE = 0xFFFFFFFF;\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    struct parse_tree_element\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is used to represent a node in a binary parse tree.  An entire\n                parse tree is represented by a std::vector of parse_tree_element objects.\n                We follow the convention that the first element of this vector is always\n                the root of the entire tree.\n\n                The fields of this object have the following interpretations:   \n                    - c == the constituent spanned by this node in the parse tree.\n                      Therefore, the node spans the words in the range [c.begin, c.end).\n                    - tag == the syntactic category of this node in the parse tree.\n                    - score == the score or log likelihood for this parse tree.  In\n                      general, this is the sum of scores of all the production rules used\n                      to build the tree rooted at the current node.\n                    - let PT denote the vector of parse_tree_elements that defines an\n                      entire parse tree.  Then we have:\n                        - if (left != END_OF_TREE) then\n                            - PT[left] == the left sub-tree of the current node.\n                            - PT[left] spans the words [c.begin, c.k)\n                            - PT[left].tag == c.left_tag\n                        - else\n                            - there is no left sub-tree\n\n                        - if (right != END_OF_TREE) then\n                            - PT[right] == the right sub-tree of the current node.\n                            - PT[right] spans the words [c.k, c.end)\n                            - PT[right].tag == c.right_tag\n                        - else\n                            - there is no right sub-tree\n        !*/\n\n        constituent<T> c;\n        T tag; \n        double score; \n\n        unsigned long left;\n        unsigned long right; \n    };\n\n    template <\n        typename T\n        >\n    void serialize (\n        const parse_tree_element<T>& item,\n        std::ostream& out\n    );\n    /*!\n        provides serialization support\n    !*/\n\n    template <\n        typename T\n        >\n    void deserialize (\n        parse_tree_element<T>& item,\n        std::istream& in \n    );\n    /*!\n        provides deserialization support \n    !*/\n\n// -----------------------------------------------------------------------------------------\n// -----------------------------------------------------------------------------------------\n\n    void example_production_rule_function (\n        const std::vector<T>& words,\n        const constituent<T>& c,\n        std::vector<std::pair<T,double> >& possible_tags\n    )\n    /*!\n        requires\n            - 0 <= c.begin < c.k < c.end <= words.size()\n            - possible_tags.size() == 0 \n        ensures\n            - Finds all the syntactic categories that can be used to label c and puts those\n              categories, along with their scores, into possible_tags.  Or in other words,\n              this function determines which production rules can be used to turn the left\n              and right sub-constituents in c into a single constituent.  The contents of c\n              have the following interpretations:\n                - The left sub-constituent has syntactic category c.left_tag \n                - for all i such that c.begin <= i < c.k: \n                    - words[i] is part of the left sub-constituent.\n                - The right sub-constituent has syntactic category c.right_tag \n                - for all i such that c.k <= i < c.end: \n                    - words[i] is part of the right sub-constituent.\n\n            - Note that example_production_rule_function() is not a real function.  It is\n              here just to show you how to define production rule producing functions for\n              use with the find_max_parse_cky() routine defined below.\n    !*/\n\n    template <\n        typename T, \n        typename production_rule_function\n        >\n    void find_max_parse_cky (\n        const std::vector<T>& words,\n        const production_rule_function& production_rules,\n        std::vector<parse_tree_element<T> >& parse_tree\n    );\n    /*!\n        requires\n            - production_rule_function == a function or function object with the same\n              interface as example_production_rule_function defined above.\n            - It must be possible to store T objects in a std::map.\n        ensures\n            - Uses the CKY algorithm to find the most probable/highest scoring binary parse\n              tree of the given vector of words.  \n            - if (#parse_tree.size() == 0) then\n                - There is no parse tree, using the given production_rules, that can cover\n                  the given word sequence.\n            - else\n                - #parse_tree == the highest scoring parse tree that covers all the\n                  elements of words.\n                - #parse_tree[0] == the root node of the parse tree.\n                - #parse_tree[0].score == the score of the parse tree.  This is the sum of\n                  the scores of all production rules used to construct the tree.\n                - #parse_tree[0].begin == 0\n                - #parse_tree[0].end == words.size()\n            - This function uses production_rules() to find out what the allowed production\n              rules are.  That is, production_rules() defines all properties of the grammar\n              used by find_max_parse_cky(). \n    !*/\n\n// -----------------------------------------------------------------------------------------\n// -----------------------------------------------------------------------------------------\n\n    class parse_tree_to_string_error : public error\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception thrown by parse_tree_to_string() and\n                parse_tree_to_string_tagged() if the inputs are discovered to be invalid.\n        !*/\n    };\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename U\n        >\n    std::string parse_tree_to_string (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const unsigned long root_idx = 0\n    );\n    /*!\n        requires\n            - It must be possible to print U objects to an ostream using operator<<\n              (typically, U would be something like std::string)\n        ensures\n            - Interprets tree as a parse tree defined over the given sequence of words.  \n            - returns a bracketed string that represents the parse tree over the words.  \n              For example, suppose the following parse tree is input:\n\n                        /\\\n                       /  \\\n                      /\\   \\\n                     /  \\   \\\n                   the dog  ran\n\n              Then the output would be the string \"[[the dog] ran]\"\n            - Only the sub-tree rooted at tree[root_idx] will be output.  If root_idx >= \n              tree.size() then the empty string is returned.\n        throws\n            - parse_tree_to_string_error\n                This exception is thrown if an invalid tree is detected.  This might happen\n                if the tree refers to elements of words that don't exist because words is\n                shorted than it is supposed to be.\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename U\n        >\n    std::string parse_tree_to_string_tagged (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const unsigned long root_idx = 0\n    );\n    /*!\n        requires\n            - It must be possible to print T objects to an ostream using operator<<\n            - It must be possible to print U objects to an ostream using operator<<\n              (typically, U would be something like std::string)\n        ensures\n            - This function does the same thing as parse_tree_to_string() except that it\n              also includes the parse_tree_element::tag object in the output.  Therefore,\n              the tag of each bracket will be included as the first token inside the\n              bracket.  For example, suppose the following parse tree is input (where tags\n              are shown at the vertices):\n\n                        S\n                        /\\\n                      NP  \\\n                      /\\   \\\n                     /  \\   \\\n                   the dog  ran\n\n              Then the output would be the string \"[S [NP the dog] ran]\"\n            - Only the sub-tree rooted at tree[root_idx] will be output.  If root_idx >=\n              tree.size() then the empty string is returned.\n        throws\n            - parse_tree_to_string_error\n                This exception is thrown if an invalid tree is detected.  This might happen\n                if the tree refers to elements of words that don't exist because words is\n                shorted than it is supposed to be.\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename U\n        >\n    std::string parse_trees_to_string (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const T& tag_to_skip\n    );\n    /*!\n        requires\n            - It must be possible to print U objects to an ostream using operator<<\n              (typically, U would be something like std::string)\n        ensures\n            - This function behaves just like parse_tree_to_string() except that it will\n              not print the brackets (i.e. []) for the top most parts of the tree which\n              have tags equal to tag_to_skip.  It will however print all the words.\n              Therefore, this function only includes brackets on the subtrees which begin\n              with a tag other than tag_to_skip.\n        throws\n            - parse_tree_to_string_error\n                This exception is thrown if an invalid tree is detected.  This might happen\n                if the tree refers to elements of words that don't exist because words is\n                shorted than it is supposed to be.\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T, \n        typename U\n        >\n    std::string parse_trees_to_string_tagged (\n        const std::vector<parse_tree_element<T> >& tree,\n        const std::vector<U>& words,\n        const T& tag_to_skip\n    );\n    /*!\n        requires\n            - It must be possible to print T objects to an ostream using operator<<\n            - It must be possible to print U objects to an ostream using operator<<\n              (typically, U would be something like std::string)\n        ensures\n            - This function behaves just like parse_tree_to_string_tagged() except that it\n              will not print the brackets (i.e. []) for the top most parts of the tree\n              which have tags equal to tag_to_skip.  It will however print all the words.\n              Therefore, this function only includes brackets on the subtrees which begin\n              with a tag other than tag_to_skip.\n        throws\n            - parse_tree_to_string_error\n                This exception is thrown if an invalid tree is detected.  This might happen\n                if the tree refers to elements of words that don't exist because words is\n                shorted than it is supposed to be.\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void find_trees_not_rooted_with_tag (\n        const std::vector<parse_tree_element<T> >& tree,\n        const T& tag,\n        std::vector<unsigned long>& tree_roots \n    );\n    /*!\n        requires\n            - objects of type T must be comparable using operator==\n        ensures\n            - Finds all the largest non-overlapping trees in tree that are not rooted with\n              the given tag.  \n            - find_trees_not_rooted_with_tag() is useful when you want to cut a parse tree\n              into a bunch of sub-trees and you know that the top level of the tree is all\n              composed of the same kind of tag.  So if you want to just \"slice off\" the top\n              of the tree where this tag lives then this function is useful for doing that.\n            - #tree_roots.size() == the number of sub-trees found.\n            - for all valid i:\n                - tree[#tree_roots[i]].tag != tag\n            - To make the operation of this function clearer, here are a few examples of\n              what it will do:\n                - if (tree[0].tag != tag) then \n                    - #tree_roots.size() == 0\n                    - #tree_roots[0] == 0\n                - else if (tree[0].tag == tag but its immediate children's tags are not equal to tag) then \n                    - #tree_roots.size() == 2\n                    - #tree_roots[0] == tree[0].left\n                    - #tree_roots[1] == tree[0].right\n    !*/\n\n// -----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_FIND_MAX_PARsE_CKY_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/find_optimal_parameters.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_fIND_OPTIMAL_PARAMETERS_Hh_\n#define DLIB_fIND_OPTIMAL_PARAMETERS_Hh_\n\n#include \"../matrix.h\"\n#include \"find_optimal_parameters_abstract.h\"\n#include \"optimization_bobyqa.h\"\n#include \"optimization_line_search.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double find_optimal_parameters (\n        double initial_search_radius,\n        double eps,\n        const unsigned int max_f_evals,\n        matrix<double,0,1>& x,\n        const matrix<double,0,1>& x_lower,\n        const matrix<double,0,1>& x_upper,\n        const funct& f\n    ) \n    {\n        DLIB_CASSERT(x.size() == x_lower.size() && x_lower.size() == x_upper.size() && x.size() > 0,\n            \"\\t double find_optimal_parameters()\"\n            << \"\\n\\t x.size():       \" << x.size()\n            << \"\\n\\t x_lower.size(): \" << x_lower.size()\n            << \"\\n\\t x_upper.size(): \" << x_upper.size()\n            );\n\n        // check the requirements.  Also split the assert up so that the error message isn't huge.\n        DLIB_CASSERT(max_f_evals > 1 && eps > 0 && initial_search_radius > eps,\n            \"\\t double find_optimal_parameters()\"\n            << \"\\n\\t Invalid arguments have been given to this function\"\n            << \"\\n\\t initial_search_radius: \" << initial_search_radius\n            << \"\\n\\t eps:                   \" << eps\n            << \"\\n\\t max_f_evals:           \" << max_f_evals\n        );\n\n        DLIB_CASSERT( min(x_upper - x_lower) > 0 &&\n                     min(x - x_lower) >= 0 && min(x_upper - x) >= 0,\n            \"\\t double find_optimal_parameters()\"\n            << \"\\n\\t The bounds constraints have to make sense and also contain the starting point.\"\n            << \"\\n\\t min(x_upper - x_lower):                         \" << min(x_upper - x_lower) \n            << \"\\n\\t min(x - x_lower) >= 0 && min(x_upper - x) >= 0: \" << (min(x - x_lower) >= 0 && min(x_upper - x) >= 0)\n        );\n\n        // if the search radius is too big then shrink it so it fits inside the bounds.\n        if (initial_search_radius*2 >= min(x_upper-x_lower))\n            initial_search_radius = 0.5*min(x_upper-x_lower)*0.99;\n\n\n        double objective_val = std::numeric_limits<double>::infinity();\n        size_t num_iter_used = 0;\n        if (x.size() == 1)\n        {\n            // BOBYQA requires x to have at least 2 variables in it.  So we can't call it in\n            // this case.  Instead we call find_min_single_variable().\n            matrix<double,0,1> temp(1);\n            auto ff = [&](const double& xx)\n            {\n                temp = xx;\n                double obj = f(temp);  \n                ++num_iter_used;\n                // keep track of the best x.\n                if (obj < objective_val)\n                {\n                    objective_val = obj;\n                    x = temp;\n                }\n                return obj;\n            };\n            try\n            {\n                double dx = x(0);\n                find_min_single_variable(ff, dx, x_lower(0), x_upper(0), eps, max_f_evals, initial_search_radius);\n            } catch (optimize_single_variable_failure& )\n            {\n            }\n        }\n        else\n        {\n            auto ff = [&](const matrix<double,0,1>& xx)\n            {\n                double obj = f(xx); \n                ++num_iter_used;\n                // keep track of the best x.\n                if (obj < objective_val)\n                {\n                    objective_val = obj;\n                    x = xx;\n                }\n                return obj;\n            };\n            try\n            {\n                matrix<double,0,1> start_x = x;\n                find_min_bobyqa(ff, start_x, 2*x.size()+1, x_lower, x_upper, initial_search_radius, eps, max_f_evals);\n            } catch (bobyqa_failure& )\n            {\n            }\n        }\n\n        return objective_val;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_fIND_OPTIMAL_PARAMETERS_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/find_optimal_parameters_abstract.h",
    "content": "// Copyright (C) 2016  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_\n#ifdef DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double find_optimal_parameters (\n        double initial_search_radius,\n        double eps,\n        const unsigned int max_f_evals,\n        matrix<double,0,1>& x,\n        const matrix<double,0,1>& x_lower,\n        const matrix<double,0,1>& x_upper,\n        const funct& f\n    );\n    /*!\n        requires\n            - f(x) must be a valid expression that evaluates to a double\n            - x.size() == x_lower.size() == x_upper.size()\n            - x.size() > 0\n            - 0 < eps < initial_search_radius \n            - max_f_evals > 1\n            - min(x_upper - x_lower) > 0 \n            - min(x - x_lower) >= 0 && min(x_upper - x) >= 0\n              (i.e. the given x should be within the bounds defined by x_lower and x_upper)\n        ensures\n            - Performs a constrained minimization of the function f() starting from \n              the initial point x.  \n            - This function does not require derivatives of f().  Instead, it uses\n              derivative free methods to find the best setting of x.  In particular, it\n              will begin by searching within a sphere of radius initial_search_radius\n              around x and will continue searching until either f() has been called\n              max_f_evals times or the search area has been shrunk to less than eps radius.\n            - #x == the value of x (within the bounds defined by x_lower and x_upper) that \n              was found to minimize f().  More precisely, it will always be true that:\n                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0\n            - returns f(#x). \n        throws\n            - No exception is thrown for executing max_f_evals iterations.  This function\n              will simply output the best x it has seen if it runs out of iterations.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_fIND_OPTIMAL_PARAMETERS_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/isotonic_regression.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_ISOTONIC_ReGRESSION_H_\n#define DLIB_ISOTONIC_ReGRESSION_H_\n\n#include \"isotonic_regression_abstract.h\"\n#include <vector>\n#include <utility>\n#include <cstddef>\n\nnamespace dlib\n{\n    class isotonic_regression\n    {\n    public:\n\n        template <\n            typename const_iterator, \n            typename iterator\n            >\n        void operator() (\n            const_iterator begin,\n            const_iterator end,\n            iterator obegin\n        )\n        {\n            do_isotonic_regression(begin, end);\n\n            // unpack blocks to output\n            for (auto& block : blocks)\n            {\n                for (size_t k = 0; k < block.num; ++k)\n                    set_val(*obegin++, block.avg);\n            }\n\n            blocks.clear();\n        }\n\n        void operator() (\n            std::vector<double>& vect\n        ) { (*this)(vect.begin(), vect.end(), vect.begin()); }\n\n        template <typename T, typename U>\n        void operator() (\n            std::vector<std::pair<T,U>>& vect\n        ) { (*this)(vect.begin(), vect.end(), vect.begin()); }\n\n\n        template <\n            typename const_iterator, \n            typename iterator\n            >\n        void fit_with_linear_output_interpolation (\n            const_iterator begin,\n            const_iterator end,\n            iterator obegin\n        )\n        {\n            do_isotonic_regression(begin, end);\n\n            // Unpack blocks to output, but here instead of producing the step function\n            // output we linearly interpolate.  Note that this actually fits the data less\n            // than the step-function, but in many applications might be closer to what you\n            // really want when using isotonic_regression than the step function.\n            for (size_t i = 0; i < blocks.size(); ++i)\n            {\n                auto& block = blocks[i];\n\n                double prev = (blocks.front().avg + block.avg)/2;\n                if (i > 0)\n                    prev = (blocks[i-1].avg+block.avg)/2;\n\n                double next = (blocks.back().avg + block.avg)/2;\n                if (i+1 < blocks.size())\n                    next = (blocks[i+1].avg+block.avg)/2;\n\n                for (size_t k = 0; k < block.num; ++k)\n                {\n                    const auto mid = block.num/2.0;\n                    if (k < mid)\n                    {\n                        const double alpha = k/mid;\n                        set_val(*obegin++, (1-alpha)*prev + alpha*block.avg);\n                    }\n                    else\n                    {\n                        const double alpha = k/mid-1;\n                        set_val(*obegin++, alpha*next + (1-alpha)*block.avg);\n                    }\n                }\n            }\n\n            blocks.clear();\n        }\n\n        void fit_with_linear_output_interpolation (\n            std::vector<double>& vect\n        ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }\n\n        template <typename T, typename U>\n        void fit_with_linear_output_interpolation (\n            std::vector<std::pair<T,U>>& vect\n        ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }\n\n    private:\n\n        template <\n            typename const_iterator\n            >\n        void do_isotonic_regression (\n            const_iterator begin,\n            const_iterator end\n        )\n        {\n            blocks.clear();\n\n            // Do the actual isotonic regression.  The output is a step-function and is\n            // stored in the vector of blocks.\n            for (auto i = begin; i != end; ++i)\n            {\n                blocks.emplace_back(get_val(*i));\n                while (blocks.size() > 1 && prev_block().avg > current_block().avg)\n                {\n                    // merge the last two blocks.\n                    prev_block() = prev_block() + current_block();\n                    blocks.pop_back();\n                }\n            }\n        }\n\n\n        template <typename T>\n        static double get_val(const T& v) { return v;}\n\n        template <typename T, typename U>\n        static double get_val(const std::pair<T,U>& v) { return v.second;}\n\n        template <typename T>\n        static void set_val(T& v, double val) { v = val;}\n\n        template <typename T, typename U>\n        static void set_val(std::pair<T,U>& v, double val) { v.second = val;}\n\n\n\n        struct block_t\n        {\n            block_t(double val) : num(1), avg(val) {}\n            block_t(size_t n, double val) : num(n), avg(val) {}\n\n            size_t num;\n            double avg;\n\n            inline block_t operator+(const block_t& rhs) const\n            {\n                return block_t(num+rhs.num,\n                    (num*avg + rhs.num*rhs.avg)/(num+rhs.num));\n            }\n        };\n\n        inline block_t& prev_block() { return blocks[blocks.size()-2]; }\n        inline block_t& current_block() { return blocks.back(); }\n\n        std::vector<block_t> blocks;\n    };\n}\n\n#endif // DLIB_ISOTONIC_ReGRESSION_H_\n\n\n"
  },
  {
    "path": "dlib/optimization/isotonic_regression_abstract.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_\n#ifdef DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_\n\n#include <vector>\n#include <utility>\n\nnamespace dlib\n{\n    class isotonic_regression\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for performing 1-D isotonic regression. That is, it\n                finds the least squares fit of a non-parametric curve to some user supplied\n                data, subject to the constraint that the fitted curve is non-decreasing.\n\n                This is done using the fast O(n) pool adjacent violators algorithm.\n        !*/\n\n    public:\n\n        template <\n            typename const_iterator, \n            typename iterator\n            >\n        void operator() (\n            const_iterator begin,\n            const_iterator end,\n            iterator obegin\n        );\n        /*!\n            requires\n                - [begin,end) is an iterator range of float or doubles or a range of\n                  std::pair<T,double> or std::pair<T,float> where T an be anything.\n                - obegin points to an iterator range at least std::distance(begin,end) elements. \n                - obegin points to an iterator range of objects of type float, double, std::pair<T,float>, or std::pair<T,double>.\n            ensures\n                - Given the range of real values stored in [begin,end), this method performs isotonic regression\n                  on this data and writes the results to obegin.  To be specific:\n                    - let IN refer to the input values stored in the iterator range [begin,end).\n                    - let OUT refer to the output values stored in the iterator range [obegin, obegin+std::distance(begin,end)).\n                    - This function populates OUT with values such that the sum_i of\n                      (IN[i]-OUT[i])^2 is minimized, subject to the constraint that \n                      OUT[i] <= OUT[i+1], i.e. that OUT is monotonic.\n                - It is OK for [begin,end) to overlap with the range pointed to by obegin.\n                  That is, this function can run in-place.\n                - Note that when the inputs or outputs are std::pairs this algorithm only\n                  looks at the .second field of the pair.  It therefore still treats these\n                  iterator ranges as ranges of reals since it only looks at the .second\n                  field, which is a real number.  The .first field is entirely ignored.\n        !*/\n\n        void operator() (\n            std::vector<double>& vect\n        ) { (*this)(vect.begin(), vect.end(), vect.begin()); }\n        /*!\n            ensures\n                - performs in-place isotonic regression.  Therefore, #vect will contain the\n                  isotonic regression of vect.\n                - #vect.size() == vect.size()\n        !*/\n\n        template <typename T, typename U>\n        void operator() (\n            std::vector<std::pair<T,U>>& vect\n        ) { (*this)(vect.begin(), vect.end(), vect.begin()); }\n        /*!\n            ensures\n                - performs in-place isotonic regression.  Therefore, #vect will contain the\n                  isotonic regression of vect.\n                - #vect.size() == vect.size()\n        !*/\n\n\n        template <\n            typename const_iterator, \n            typename iterator\n            >\n        void fit_with_linear_output_interpolation (\n            const_iterator begin,\n            const_iterator end,\n            iterator obegin\n        );\n        /*!\n            requires\n                - [begin,end) is an iterator range of float or doubles or a range of\n                  std::pair<T,double> or std::pair<T,float> where T an be anything.\n                - obegin points to an iterator range at least std::distance(begin,end). \n                - obegin points to an iterator range of objects of type float, double, std::pair<T,float>, or std::pair<T,double>.\n            ensures\n                - This function behaves just like (*this)(begin,end,obegin) except that the\n                  output is interpolated.  To explain, note that the optimal output of\n                  isotonic regression is a step function.  However, in many applications\n                  that isn't really what you want.  You want something smoother.  So\n                  fit_with_linear_output_interpolation() does isotonic regression and then\n                  linearly interpolates the step function into a piecewise linear function.\n        !*/\n\n        void fit_with_linear_output_interpolation (\n            std::vector<double>& vect\n        ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }\n        /*!\n            ensures\n                - performs in-place isotonic regression.  Therefore, #vect will contain the\n                  isotonic regression of vect.\n                - #vect.size() == vect.size()\n        !*/\n\n        template <typename T, typename U>\n        void fit_with_linear_output_interpolation (\n            std::vector<std::pair<T,U>>& vect\n        ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }\n        /*!\n            ensures\n                - performs in-place isotonic regression.  Therefore, #vect will contain the\n                  isotonic regression of vect.\n                - #vect.size() == vect.size()\n        !*/\n\n    };\n}\n\n#endif // DLIB_ISOTONIC_ReGRESSION_ABSTRACT_H_\n\n\n\n"
  },
  {
    "path": "dlib/optimization/max_cost_assignment.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAX_COST_ASSIgNMENT_Hh_\n#define DLIB_MAX_COST_ASSIgNMENT_Hh_\n\n#include \"max_cost_assignment_abstract.h\"\n#include \"../matrix.h\"\n#include <vector>\n#include <deque>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    typename EXP::type assignment_cost (\n        const matrix_exp<EXP>& cost,\n        const std::vector<long>& assignment\n    )\n    {\n        DLIB_ASSERT(cost.nr() == cost.nc(),\n            \"\\t type assignment_cost(cost,assignment)\"\n            << \"\\n\\t cost.nr(): \" << cost.nr()\n            << \"\\n\\t cost.nc(): \" << cost.nc()\n            );\n#ifdef ENABLE_ASSERTS\n        // can't call max on an empty vector. So put an if here to guard against it.\n        if (assignment.size() > 0)\n        {\n            DLIB_ASSERT(0 <= min(mat(assignment)) && max(mat(assignment)) < cost.nr(),\n                \"\\t type assignment_cost(cost,assignment)\"\n                << \"\\n\\t cost.nr(): \" << cost.nr()\n                << \"\\n\\t cost.nc(): \" << cost.nc()\n                << \"\\n\\t min(assignment): \" << min(mat(assignment)) \n                << \"\\n\\t max(assignment): \" << max(mat(assignment)) \n                );\n        }\n#endif\n\n        typename EXP::type temp = 0;\n        for (unsigned long i = 0; i < assignment.size(); ++i)\n        {\n            temp += cost(i, assignment[i]);\n        }\n        return temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <typename EXP>\n        inline void compute_slack(\n            const long x,\n            std::vector<typename EXP::type>& slack,\n            std::vector<long>& slackx,\n            const matrix_exp<EXP>& cost,\n            const std::vector<typename EXP::type>& lx,\n            const std::vector<typename EXP::type>& ly\n        )\n        {\n            for (long y = 0; y < cost.nc(); ++y)\n            {\n                if (lx[x] + ly[y] - cost(x,y) < slack[y])\n                {\n                    slack[y] = lx[x] + ly[y] - cost(x,y);\n                    slackx[y] = x;\n                }\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    std::vector<long> max_cost_assignment (\n        const matrix_exp<EXP>& cost_\n    )                         \n    {\n        const_temp_matrix<EXP> cost(cost_);\n        typedef typename EXP::type type;\n        // This algorithm only works if the elements of the cost matrix can be reliably \n        // compared using operator==. However, comparing for equality with floating point\n        // numbers is not a stable operation. So you need to use an integer cost matrix.\n        COMPILE_TIME_ASSERT(std::numeric_limits<type>::is_integer);\n        DLIB_ASSERT(cost.nr() == cost.nc(),\n            \"\\t std::vector<long> max_cost_assignment(cost)\"\n            << \"\\n\\t cost.nr(): \" << cost.nr()\n            << \"\\n\\t cost.nc(): \" << cost.nc()\n            );\n\n        using namespace dlib::impl;\n        /*\n            I based the implementation of this algorithm on the description of the\n            Hungarian algorithm on the following websites:\n                http://www.math.uwo.ca/~mdawes/courses/344/kuhn-munkres.pdf\n                http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=hungarianAlgorithm\n\n            Note that this is the fast O(n^3) version of the algorithm.\n        */\n\n        if (cost.size() == 0)\n            return std::vector<long>();\n\n        std::vector<type> lx, ly;\n        std::vector<long> xy;\n        std::vector<long> yx;\n        std::vector<char> S, T;\n        std::vector<type> slack;\n        std::vector<long> slackx;\n        std::vector<long> aug_path;\n\n\n\n\n        // Initially, nothing is matched. \n        xy.assign(cost.nc(), -1);\n        yx.assign(cost.nc(), -1);\n        /*\n            We maintain the following invariant:\n                Vertex x is matched to vertex xy[x] and\n                vertex y is matched to vertex yx[y].\n\n                A value of -1 means a vertex isn't matched to anything.  Moreover,\n                x corresponds to rows of the cost matrix and y corresponds to the\n                columns of the cost matrix.  So we are matching X to Y.\n        */\n\n\n        // Create an initial feasible labeling.  Moreover, in the following\n        // code we will always have: \n        //     for all valid x and y:  lx[x] + ly[y] >= cost(x,y)\n        lx.resize(cost.nc());\n        ly.assign(cost.nc(),0);\n        for (long x = 0; x < cost.nr(); ++x)\n            lx[x] = max(rowm(cost,x));\n\n        // Now grow the match set by picking edges from the equality subgraph until\n        // we have a complete matching.\n        for (long match_size = 0; match_size < cost.nc(); ++match_size)\n        {\n            std::deque<long> q;\n\n            // Empty out the S and T sets\n            S.assign(cost.nc(), false);\n            T.assign(cost.nc(), false);\n\n            // clear out old slack values\n            slack.assign(cost.nc(), std::numeric_limits<type>::max());\n            slackx.resize(cost.nc());\n            /*\n                slack and slackx are maintained such that we always\n                have the following (once they get initialized by compute_slack() below):\n                    - for all y:\n                        - let x == slackx[y]\n                        - slack[y] == lx[x] + ly[y] - cost(x,y)\n            */\n\n            aug_path.assign(cost.nc(), -1);\n\n            for (long x = 0; x < cost.nc(); ++x)\n            {\n                // If x is not matched to anything\n                if (xy[x] == -1)\n                {\n                    q.push_back(x);\n                    S[x] = true;\n\n                    compute_slack(x, slack, slackx, cost, lx, ly);\n                    break;\n                }\n            }\n\n\n            long x_start = 0;\n            long y_start = 0;\n\n            // Find an augmenting path.  \n            bool found_augmenting_path = false;\n            while (!found_augmenting_path)\n            {\n                while (q.size() > 0 && !found_augmenting_path)\n                {\n                    const long x = q.front();\n                    q.pop_front();\n                    for (long y = 0; y < cost.nc(); ++y)\n                    {\n                        if (cost(x,y) == lx[x] + ly[y] && !T[y])\n                        {\n                            // if vertex y isn't matched with anything\n                            if (yx[y] == -1) \n                            {\n                                y_start = y;\n                                x_start = x;\n                                found_augmenting_path = true;\n                                break;\n                            }\n\n                            T[y] = true;\n                            q.push_back(yx[y]);\n\n                            aug_path[yx[y]] = x;\n                            S[yx[y]] = true;\n                            compute_slack(yx[y], slack, slackx, cost, lx, ly);\n                        }\n                    }\n                }\n\n                if (found_augmenting_path)\n                    break;\n\n\n                // Since we didn't find an augmenting path we need to improve the \n                // feasible labeling stored in lx and ly.  We also need to keep the\n                // slack updated accordingly.\n                type delta = std::numeric_limits<type>::max();\n                for (unsigned long i = 0; i < T.size(); ++i)\n                {\n                    if (!T[i])\n                        delta = std::min(delta, slack[i]);\n                }\n                for (unsigned long i = 0; i < T.size(); ++i)\n                {\n                    if (S[i])\n                        lx[i] -= delta;\n\n                    if (T[i])\n                        ly[i] += delta;\n                    else\n                        slack[i] -= delta;\n                }\n\n\n\n                q.clear();\n                for (long y = 0; y < cost.nc(); ++y)\n                {\n                    if (!T[y] && slack[y] == 0)\n                    {\n                        // if vertex y isn't matched with anything\n                        if (yx[y] == -1)\n                        {\n                            x_start = slackx[y];\n                            y_start = y;\n                            found_augmenting_path = true;\n                            break;\n                        }\n                        else\n                        {\n                            T[y] = true;\n                            if (!S[yx[y]])\n                            {\n                                q.push_back(yx[y]);\n\n                                aug_path[yx[y]] = slackx[y];\n                                S[yx[y]] = true;\n                                compute_slack(yx[y], slack, slackx, cost, lx, ly);\n                            }\n                        }\n                    }\n                }\n            } // end while (!found_augmenting_path)\n\n            // Flip the edges along the augmenting path.  This means we will add one more\n            // item to our matching.\n            for (long cx = x_start, cy = y_start, ty; \n                 cx != -1; \n                 cx = aug_path[cx], cy = ty)\n            {\n                ty = xy[cx];\n                yx[cy] = cx;\n                xy[cx] = cy;\n            }\n\n        }\n\n\n        return xy;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAX_COST_ASSIgNMENT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/max_cost_assignment_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_\n#ifdef DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include <vector>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    typename EXP::type assignment_cost (\n        const matrix_exp<EXP>& cost,\n        const std::vector<long>& assignment\n    );\n    /*!\n        requires\n            - cost.nr() == cost.nc()\n            - for all valid i:\n                - 0 <= assignment[i] < cost.nr()\n        ensures\n            - Interprets cost as a cost assignment matrix. That is, cost(i,j) \n              represents the cost of assigning i to j.  \n            - Interprets assignment as a particular set of assignments. That is,\n              i is assigned to assignment[i].\n            - returns the cost of the given assignment. That is, returns\n              a number which is:\n                sum over i: cost(i,assignment[i])\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    std::vector<long> max_cost_assignment (\n        const matrix_exp<EXP>& cost\n    );\n    /*!\n        requires\n            - EXP::type == some integer type (e.g. int)\n              (i.e. cost must contain integers rather than floats or doubles)\n            - cost.nr() == cost.nc()\n        ensures\n            - Finds and returns the solution to the following optimization problem:\n\n                Maximize: f(A) == assignment_cost(cost, A)\n                Subject to the following constraints:\n                    - The elements of A are unique. That is, there aren't any \n                      elements of A which are equal.  \n                    - A.size() == cost.nr()\n\n            - This function implements the O(N^3) version of the Hungarian algorithm \n              where N is the number of rows in the cost matrix.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAX_COST_ASSIgNMENT_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/max_sum_submatrix.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_MAX_SUM_SUBMaTRIX_Hh_\n#define DLIB_MAX_SUM_SUBMaTRIX_Hh_\n\n#include \"max_sum_submatrix_abstract.h\"\n#include \"../matrix.h\"\n#include <vector>\n#include <queue>\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n    namespace impl\n    {\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        struct range_set\n        {\n            int top_min;\n            int top_max;\n            int bottom_min;\n            int bottom_max;\n            T weight;\n\n            bool operator<(const range_set& item) const { return weight < item.weight; }\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        bool is_terminal_set (\n            const range_set<T>& item\n        )\n        {\n            return (item.top_min  >= item.top_max &&\n                    item.bottom_min >= item.bottom_max);\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename T>\n        void split (\n            const range_set<T>& rset,\n            range_set<T>& a,\n            range_set<T>& b\n        )\n        {\n            if (rset.top_max - rset.top_min > rset.bottom_max - rset.bottom_min)\n            {\n                // split top\n                const int middle = (rset.top_max + rset.top_min)/2;\n                a.top_min = rset.top_min;\n                a.top_max = middle;\n                b.top_min = middle+1;\n                b.top_max = rset.top_max;\n\n                a.bottom_min = rset.bottom_min;\n                a.bottom_max = rset.bottom_max;\n                b.bottom_min = rset.bottom_min;\n                b.bottom_max = rset.bottom_max;\n            }\n            else\n            {\n                // split bottom\n                const int middle = (rset.bottom_max + rset.bottom_min)/2;\n                a.bottom_min = rset.bottom_min;\n                a.bottom_max = middle;\n                b.bottom_min = middle+1;\n                b.bottom_max = rset.bottom_max;\n\n                a.top_min = rset.top_min;\n                a.top_max = rset.top_max;\n                b.top_min = rset.top_min;\n                b.top_max = rset.top_max;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <typename EXP, typename T>\n        void find_best_column_range (\n            const matrix_exp<EXP>& sum_pos,\n            const matrix_exp<EXP>& sum_neg,\n            const range_set<T>& row_range,\n            T& weight,\n            int& left,\n            int& right\n        )\n        {\n            left = 0;\n            right = -1;\n            weight = 0;\n            T cur_sum = 0;\n            int cur_pos = 0;\n            for (long c = 0; c < sum_pos.nc(); ++c)\n            {\n                // compute the value for the current column\n                T temp = sum_pos(row_range.bottom_max+1,c) - sum_pos(row_range.top_min,c);\n                if (row_range.top_max <= row_range.bottom_min)\n                    temp += sum_neg(row_range.bottom_min+1,c) - sum_neg(row_range.top_max,c);\n\n\n                cur_sum += temp;\n                if (cur_sum > weight)\n                {\n                    left = cur_pos;\n                    right = c;\n                    weight = cur_sum;\n                }\n\n                if (cur_sum <= 0)\n                {\n                    cur_sum = 0;\n                    cur_pos = c+1;\n                }\n\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename EXP>\n    std::vector<rectangle> max_sum_submatrix(\n        const matrix_exp<EXP>& mat,\n        unsigned long max_rects,\n        double thresh_ = 0\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(thresh_ >= 0 && mat.size() > 0,\n            \"\\t std::vector<rectangle> max_sum_submatrix()\"\n            << \"\\n\\t Invalid arguments were given to this function.\"\n            << \"\\n\\t mat.size(): \" << mat.size()\n            << \"\\n\\t thresh_:    \" << thresh_\n            );\n\n        /*\n            This function is basically an implementation of the efficient subwindow search (I-ESS)\n            algorithm presented in the following paper: \n                Efficient Algorithms for Subwindow Search in Object Detection and Localization\n                by Senjian An, Patrick Peursum, Wanquan Liu and Svetha Venkatesh\n                In CVPR 2009\n\n        */\n\n\n        if (max_rects == 0)\n            return std::vector<rectangle>();\n\n        using namespace dlib::impl;\n        typedef typename EXP::type element_type;\n        typedef typename promote<element_type>::type scalar_type;\n\n        const scalar_type thresh = static_cast<scalar_type>(thresh_);\n\n\n        matrix<scalar_type> sum_pos;\n        matrix<scalar_type> sum_neg;\n        sum_pos.set_size(mat.nr()+1, mat.nc());\n        sum_neg.set_size(mat.nr()+1, mat.nc());\n        // integrate over the rows.  \n        for (long c = 0; c < mat.nc(); ++c)\n        {\n            sum_pos(0,c) = 0;\n            sum_neg(0,c) = 0;\n        }\n        for (long r = 0; r < mat.nr(); ++r)\n        {\n            for (long c = 0; c < mat.nc(); ++c)\n            {\n                if (mat(r,c) > 0)\n                {\n                    sum_pos(r+1,c) = mat(r,c) + sum_pos(r,c);\n                    sum_neg(r+1,c) = sum_neg(r,c);\n                }\n                else\n                {\n                    sum_pos(r+1,c) = sum_pos(r,c);\n                    sum_neg(r+1,c) = mat(r,c) + sum_neg(r,c);\n                }\n            }\n        }\n\n        std::priority_queue<range_set<scalar_type> > q;\n\n        // the range_sets will represent ranges of columns \n        range_set<scalar_type> universe_set;\n        universe_set.bottom_min = 0;\n        universe_set.top_min = 0;\n        universe_set.bottom_max = mat.nr()-1;\n        universe_set.top_max = mat.nr()-1;\n        universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr()));\n\n        q.push(universe_set);\n\n        std::vector<rectangle> results;\n        std::vector<scalar_type> temp_pos(mat.nc());\n        std::vector<scalar_type> temp_neg(mat.nc());\n\n        while (q.size() > 0)\n        {\n            if (is_terminal_set(q.top()))\n            {\n                int left, right;\n                scalar_type weight;\n                find_best_column_range(sum_pos, sum_neg, q.top(), weight, left, right);\n\n                rectangle rect(left, q.top().top_min, \n                               right, q.top().bottom_min);\n\n                if (weight <= thresh)\n                    break;\n\n                results.push_back(rect);\n\n                if (results.size() >= max_rects)\n                    break;\n\n                q = std::priority_queue<range_set<scalar_type> >();\n                // We are going to blank out the weights we just used.  So adjust the sum images appropriately.\n                for (long c = rect.left(); c <= rect.right(); ++c)\n                {\n                    temp_pos[c] = sum_pos(rect.bottom()+1,c) - sum_pos(rect.top(),c);\n                    temp_neg[c] = sum_neg(rect.bottom()+1,c) - sum_neg(rect.top(),c);\n                }\n                // blank out the area inside the rectangle\n                for (long r = rect.top(); r <= rect.bottom(); ++r)\n                {\n                    for (long c = rect.left(); c <= rect.right(); ++c)\n                    {\n                        sum_pos(r+1,c) = sum_pos(r,c);\n                        sum_neg(r+1,c) = sum_neg(r,c);\n                    }\n                }\n                // account for the area below the rectangle\n                for (long r = rect.bottom()+2; r < sum_pos.nr(); ++r)\n                {\n                    for (long c = rect.left(); c <= rect.right(); ++c)\n                    {\n                        sum_pos(r,c) -= temp_pos[c];\n                        sum_neg(r,c) -= temp_neg[c];\n                    }\n                }\n\n\n                universe_set.weight = sum(rowm(dlib::mat(sum_pos),mat.nr()));\n                if (universe_set.weight <= thresh)\n                    break;\n\n                q.push(universe_set);\n                continue;\n            }\n\n            range_set<scalar_type> a, b;\n            split(q.top(), a,b);\n            q.pop();\n\n            // these variables are not used at this point in the algorithm.\n            int a_left, a_right;\n            int b_left, b_right;\n\n            find_best_column_range(sum_pos, sum_neg, a, a.weight, a_left, a_right);\n            find_best_column_range(sum_pos, sum_neg, b, b.weight, b_left, b_right);\n\n            if (a.weight > thresh)\n                q.push(a);\n            if (b.weight > thresh)\n                q.push(b);\n\n        }\n\n\n        return results;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAX_SUM_SUBMaTRIX_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/max_sum_submatrix_abstract.h",
    "content": "// Copyright (C) 2011  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_\n#ifdef DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include <vector>\n#include \"../geometry.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP\n        >\n    std::vector<rectangle> max_sum_submatrix(\n        const matrix_exp<EXP>& mat,\n        unsigned long max_rects,\n        double thresh = 0\n    );\n    /*!\n        requires\n            - thresh >= 0\n            - mat.size() != 0\n        ensures\n            - This function finds the submatrix within mat which has the largest sum.  It then\n              zeros out that submatrix and repeats the process until no more maximal submatrices can \n              be found.  The std::vector returned will be ordered so that the rectangles with the\n              largest sum come first. \n            - Each submatrix must have a sum greater than thresh.  If no such submatrix exists then\n              the algorithm terminates and returns an empty std::vector.  \n            - At most max_rects rectangles are returned. \n\n            - This function is basically an implementation of the efficient subwindow search (I-ESS)\n              algorithm presented in the following paper: \n                Efficient Algorithms for Subwindow Search in Object Detection and Localization\n                by Senjian An, Patrick Peursum, Wanquan Liu and Svetha Venkatesh\n                In CVPR 2009\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_MAX_SUM_SUBMaTRIX_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_H_\n#define DLIB_OPTIMIZATIOn_H_\n\n#include <cmath>\n#include <limits>\n#include \"optimization_abstract.h\"\n#include \"optimization_search_strategies.h\"\n#include \"optimization_stop_strategies.h\"\n#include \"optimization_line_search.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                    Functions that transform other functions  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct>\n    class central_differences\n    {\n    public:\n        central_differences(const funct& f_, double eps_ = 1e-7) : f(f_), eps(eps_){}\n\n        template <typename T>\n        typename T::matrix_type operator()(const T& x) const\n        {\n            // T must be some sort of dlib matrix \n            COMPILE_TIME_ASSERT(is_matrix<T>::value);\n\n            typename T::matrix_type der(x.size());\n            typename T::matrix_type e(x);\n            for (long i = 0; i < x.size(); ++i)\n            {\n                const double old_val = e(i);\n\n                e(i) += eps;\n                const double delta_plus = f(e);\n                e(i) = old_val - eps;\n                const double delta_minus = f(e);\n\n                der(i) = (delta_plus - delta_minus)/((old_val+eps)-(old_val-eps)); \n\n                // and finally restore the old value of this element\n                e(i) = old_val;\n            }\n\n            return der;\n        }\n\n        template <typename T, typename U>\n        typename U::matrix_type operator()(const T& item, const U& x) const\n        {\n            // U must be some sort of dlib matrix \n            COMPILE_TIME_ASSERT(is_matrix<U>::value);\n\n            typename U::matrix_type der(x.size());\n            typename U::matrix_type e(x);\n            for (long i = 0; i < x.size(); ++i)\n            {\n                const double old_val = e(i);\n\n                e(i) += eps;\n                const double delta_plus = f(item,e);\n                e(i) = old_val - eps;\n                const double delta_minus = f(item,e);\n\n                der(i) = (delta_plus - delta_minus)/((old_val+eps)-(old_val-eps)); \n\n                // and finally restore the old value of this element\n                e(i) = old_val;\n            }\n\n            return der;\n        }\n        \n\n        double operator()(const double& x) const\n        {\n            return (f(x+eps)-f(x-eps))/((x+eps)-(x-eps));\n        }\n\n    private:\n        const funct& f;\n        const double eps;\n    };\n\n    template <typename funct>\n    const central_differences<funct> derivative(const funct& f) { return central_differences<funct>(f); }\n    template <typename funct>\n    const central_differences<funct> derivative(const funct& f, double eps) \n    { \n        DLIB_ASSERT (\n            eps > 0,\n            \"\\tcentral_differences derivative(f,eps)\"\n            << \"\\n\\tYou must give an epsilon > 0\"\n            << \"\\n\\teps:     \" << eps \n        );\n        return central_differences<funct>(f,eps); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct, typename EXP1, typename EXP2>\n    struct clamped_function_object\n    {\n        clamped_function_object(\n            const funct& f_,\n            const matrix_exp<EXP1>& x_lower_,\n            const matrix_exp<EXP2>& x_upper_ \n        ) : f(f_), x_lower(x_lower_), x_upper(x_upper_)\n        {\n        }\n\n        template <typename T>\n        double operator() (\n            const T& x\n        ) const\n        {\n            return f(clamp(x,x_lower,x_upper));\n        }\n        \n        const funct& f;\n        const matrix_exp<EXP1>& x_lower;\n        const matrix_exp<EXP2>& x_upper; \n    };\n\n    template <typename funct, typename EXP1, typename EXP2>\n    clamped_function_object<funct,EXP1,EXP2> clamp_function(\n        const funct& f,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper \n    ) { return clamped_function_object<funct,EXP1,EXP2>(f,x_lower,x_upper); }\n\n// ----------------------------------------------------------------------------------------\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                    Functions that perform unconstrained optimization \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_min (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x, \n        double min_f\n    )\n    {\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x),\n            \"\\tdouble find_min()\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tx.nc():    \" << x.nc()\n        );\n\n\n        T g, s;\n\n        double f_value = f(x);\n        g = der(x);\n\n        if (!is_finite(f_value))\n            throw error(\"The objective function generated non-finite outputs\");\n        if (!is_finite(g))\n            throw error(\"The objective function generated non-finite outputs\");\n\n        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f)\n        {\n            s = search_strategy.get_next_direction(x, f_value, g);\n\n            double alpha = line_search(\n                        make_line_search_function(f,x,s, f_value),\n                        f_value,\n                        make_line_search_function(der,x,s, g),\n                        dot(g,s), // compute initial gradient for the line search\n                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), min_f,\n                        search_strategy.get_max_line_search_iterations());\n\n            // Take the search step indicated by the above line search\n            x += alpha*s;\n\n            if (!is_finite(f_value))\n                throw error(\"The objective function generated non-finite outputs\");\n            if (!is_finite(g))\n                throw error(\"The objective function generated non-finite outputs\");\n        }\n\n        return f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_max (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x, \n        double max_f\n    )\n    {\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x),\n            \"\\tdouble find_max()\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tx.nc():    \" << x.nc()\n        );\n\n        T g, s;\n\n        // This function is basically just a copy of find_min() but with - put in the right places\n        // to flip things around so that it ends up looking for the max rather than the min.\n\n        double f_value = -f(x);\n        g = -der(x);\n\n        if (!is_finite(f_value))\n            throw error(\"The objective function generated non-finite outputs\");\n        if (!is_finite(g))\n            throw error(\"The objective function generated non-finite outputs\");\n\n        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > -max_f)\n        {\n            s = search_strategy.get_next_direction(x, f_value, g);\n\n            double alpha = line_search(\n                        negate_function(make_line_search_function(f,x,s, f_value)),\n                        f_value,\n                        negate_function(make_line_search_function(der,x,s, g)),\n                        dot(g,s), // compute initial gradient for the line search\n                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), -max_f,\n                        search_strategy.get_max_line_search_iterations()\n                        );\n\n            // Take the search step indicated by the above line search\n            x += alpha*s;\n\n            // Don't forget to negate these outputs from the line search since they are \n            // from the unnegated versions of f() and der()\n            g *= -1;\n            f_value *= -1;\n\n            if (!is_finite(f_value))\n                throw error(\"The objective function generated non-finite outputs\");\n            if (!is_finite(g))\n                throw error(\"The objective function generated non-finite outputs\");\n\n            // Gradient is zero, no more progress is possible.  So stop.\n            if (alpha == 0)\n                break;\n        }\n\n        return -f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct,\n        typename T\n        >\n    double find_min_using_approximate_derivatives (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f,\n        T& x,\n        double min_f,\n        double derivative_eps = 1e-7\n    )\n    {\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x) && derivative_eps > 0,\n            \"\\tdouble find_min_using_approximate_derivatives()\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tx.nc():         \" << x.nc()\n            << \"\\n\\tderivative_eps: \" << derivative_eps \n        );\n\n        T g, s;\n\n        double f_value = f(x);\n        g = derivative(f,derivative_eps)(x);\n\n        if (!is_finite(f_value))\n            throw error(\"The objective function generated non-finite outputs\");\n        if (!is_finite(g))\n            throw error(\"The objective function generated non-finite outputs\");\n\n        while(stop_strategy.should_continue_search(x, f_value, g) && f_value > min_f)\n        {\n            s = search_strategy.get_next_direction(x, f_value, g);\n\n            double alpha = line_search(\n                        make_line_search_function(f,x,s,f_value),\n                        f_value,\n                        derivative(make_line_search_function(f,x,s),derivative_eps),\n                        dot(g,s),  // Sometimes the following line is a better way of determining the initial gradient. \n                        //derivative(make_line_search_function(f,x,s),derivative_eps)(0),\n                        search_strategy.get_wolfe_rho(), search_strategy.get_wolfe_sigma(), min_f,\n                        search_strategy.get_max_line_search_iterations()\n                        );\n\n            // Take the search step indicated by the above line search\n            x += alpha*s;\n\n            g = derivative(f,derivative_eps)(x);\n\n            if (!is_finite(f_value))\n                throw error(\"The objective function generated non-finite outputs\");\n            if (!is_finite(g))\n                throw error(\"The objective function generated non-finite outputs\");\n        }\n\n        return f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct,\n        typename T\n        >\n    double find_max_using_approximate_derivatives (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f,\n        T& x,\n        double max_f,\n        double derivative_eps = 1e-7\n    )\n    {\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x) && derivative_eps > 0,\n            \"\\tdouble find_max_using_approximate_derivatives()\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tx.nc():         \" << x.nc()\n            << \"\\n\\tderivative_eps: \" << derivative_eps \n        );\n\n        // Just negate the necessary things and call the find_min version of this function.\n        return -find_min_using_approximate_derivatives(\n            search_strategy, \n            stop_strategy, \n            negate_function(f),\n            x,\n            -max_f,\n            derivative_eps\n        );\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                      Functions for box constrained optimization\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename V>\n    T zero_bounded_variables (\n        const double eps,\n        T vect,\n        const T& x,\n        const T& gradient,\n        const U& x_lower,\n        const V& x_upper\n    )\n    {\n        for (long i = 0; i < gradient.size(); ++i)\n        {\n            const double tol = eps*std::abs(x(i));\n            // if x(i) is an active bound constraint\n            if (x_lower(i)+tol >= x(i) && gradient(i) > 0)\n                vect(i) = 0;\n            else if (x_upper(i)-tol <= x(i) && gradient(i) < 0)\n                vect(i) = 0;\n        }\n        return vect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U, typename V>\n    T gap_step_assign_bounded_variables (\n        const double eps,\n        T vect,\n        const T& x,\n        const T& gradient,\n        const U& x_lower,\n        const V& x_upper\n    )\n    {\n        for (long i = 0; i < gradient.size(); ++i)\n        {\n            const double tol = eps*std::abs(x(i));\n            // If x(i) is an active bound constraint then we should set its search\n            // direction such that a single step along the direction either does nothing or\n            // closes the gap of size tol before hitting the bound exactly.\n            if (x_lower(i)+tol >= x(i) && gradient(i) > 0)\n                vect(i) = x_lower(i)-x(i);\n            else if (x_upper(i)-tol <= x(i) && gradient(i) < 0)\n                vect(i) = x_upper(i)-x(i);\n        }\n        return vect;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T,\n        typename EXP1,\n        typename EXP2\n        >\n    double find_min_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper\n    )\n    {\n        /*\n            The implementation of this function is more or less based on the discussion in\n            the paper Projected Newton-type Methods in Machine Learning by Mark Schmidt, et al.\n        */\n\n        // make sure the requires clause is not violated\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&\n            x.size() == x_lower.size() && x.size() == x_upper.size(),\n            \"\\tdouble find_min_box_constrained()\"\n            << \"\\n\\t The inputs to this function must be equal length column vectors.\"\n            << \"\\n\\t is_col_vector(x):       \" << is_col_vector(x)\n            << \"\\n\\t is_col_vector(x_upper): \" << is_col_vector(x_upper)\n            << \"\\n\\t is_col_vector(x_upper): \" << is_col_vector(x_upper)\n            << \"\\n\\t x.size():               \" << x.size()\n            << \"\\n\\t x_lower.size():         \" << x_lower.size()\n            << \"\\n\\t x_upper.size():         \" << x_upper.size()\n        );\n        DLIB_ASSERT (\n            min(x_upper-x_lower) >= 0,\n            \"\\tdouble find_min_box_constrained()\"\n            << \"\\n\\t You have to supply proper box constraints to this function.\"\n            << \"\\n\\r min(x_upper-x_lower): \" << min(x_upper-x_lower)\n        );\n\n\n        T g, s;\n        double f_value = f(x);\n        g = der(x);\n\n        if (!is_finite(f_value))\n            throw error(\"The objective function generated non-finite outputs\");\n        if (!is_finite(g))\n            throw error(\"The objective function generated non-finite outputs\");\n\n        // gap_eps determines how close we have to get to a bound constraint before we\n        // start basically dropping it from the optimization and consider it to be an\n        // active constraint.\n        const double gap_eps = 1e-8;\n\n        double last_alpha = 1;\n        while(stop_strategy.should_continue_search(x, f_value, g))\n        {\n            s = search_strategy.get_next_direction(x, f_value, zero_bounded_variables(gap_eps, g, x, g, x_lower, x_upper));\n            s = gap_step_assign_bounded_variables(gap_eps, s, x, g, x_lower, x_upper);\n\n            double alpha = backtracking_line_search(\n                        make_line_search_function(clamp_function(f,x_lower,x_upper), x, s, f_value),\n                        f_value,\n                        dot(g,s), // compute gradient for the line search\n                        last_alpha, \n                        search_strategy.get_wolfe_rho(), \n                        search_strategy.get_max_line_search_iterations());\n\n            // Do a trust region style thing for alpha.  The idea is that if we take a\n            // small step then we are likely to take another small step.  So we reuse the\n            // alpha from the last iteration unless the line search didn't shrink alpha at\n            // all, in that case, we start with a bigger alpha next time.\n            if (alpha == last_alpha)\n                last_alpha = std::min(last_alpha*10,1.0);\n            else\n                last_alpha = alpha;\n\n            // Take the search step indicated by the above line search\n            x = dlib::clamp(x + alpha*s, x_lower, x_upper);\n            g = der(x);\n\n            if (!is_finite(f_value))\n                throw error(\"The objective function generated non-finite outputs\");\n            if (!is_finite(g))\n                throw error(\"The objective function generated non-finite outputs\");\n        }\n\n        return f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_min_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        double x_lower,\n        double x_upper\n    )\n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        typedef typename T::type scalar_type;\n        return find_min_box_constrained(search_strategy,\n                                        stop_strategy,\n                                        f,\n                                        der,\n                                        x,\n                                        uniform_matrix<scalar_type>(x.size(),1,x_lower),\n                                        uniform_matrix<scalar_type>(x.size(),1,x_upper) );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T,\n        typename EXP1,\n        typename EXP2\n        >\n    double find_max_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper\n    )\n    {\n        // make sure the requires clause is not violated\n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        DLIB_CASSERT (\n            is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&\n            x.size() == x_lower.size() && x.size() == x_upper.size(),\n            \"\\tdouble find_max_box_constrained()\"\n            << \"\\n\\t The inputs to this function must be equal length column vectors.\"\n            << \"\\n\\t is_col_vector(x):       \" << is_col_vector(x)\n            << \"\\n\\t is_col_vector(x_upper): \" << is_col_vector(x_upper)\n            << \"\\n\\t is_col_vector(x_upper): \" << is_col_vector(x_upper)\n            << \"\\n\\t x.size():               \" << x.size()\n            << \"\\n\\t x_lower.size():         \" << x_lower.size()\n            << \"\\n\\t x_upper.size():         \" << x_upper.size()\n        );\n        DLIB_ASSERT (\n            min(x_upper-x_lower) >= 0,\n            \"\\tdouble find_max_box_constrained()\"\n            << \"\\n\\t You have to supply proper box constraints to this function.\"\n            << \"\\n\\r min(x_upper-x_lower): \" << min(x_upper-x_lower)\n        );\n\n        // This function is basically just a copy of find_min_box_constrained() but with - put \n        // in the right places to flip things around so that it ends up looking for the max\n        // rather than the min.\n\n        T g, s;\n        double f_value = -f(x);\n        g = -der(x);\n\n        if (!is_finite(f_value))\n            throw error(\"The objective function generated non-finite outputs\");\n        if (!is_finite(g))\n            throw error(\"The objective function generated non-finite outputs\");\n\n        // gap_eps determines how close we have to get to a bound constraint before we\n        // start basically dropping it from the optimization and consider it to be an\n        // active constraint.\n        const double gap_eps = 1e-8;\n\n        double last_alpha = 1;\n        while(stop_strategy.should_continue_search(x, f_value, g))\n        {\n            s = search_strategy.get_next_direction(x, f_value, zero_bounded_variables(gap_eps, g, x, g, x_lower, x_upper));\n            s = gap_step_assign_bounded_variables(gap_eps, s, x, g, x_lower, x_upper);\n\n            double alpha = backtracking_line_search(\n                        negate_function(make_line_search_function(clamp_function(f,x_lower,x_upper), x, s, f_value)),\n                        f_value,\n                        dot(g,s), // compute gradient for the line search\n                        last_alpha, \n                        search_strategy.get_wolfe_rho(), \n                        search_strategy.get_max_line_search_iterations());\n\n            // Do a trust region style thing for alpha.  The idea is that if we take a\n            // small step then we are likely to take another small step.  So we reuse the\n            // alpha from the last iteration unless the line search didn't shrink alpha at\n            // all, in that case, we start with a bigger alpha next time.\n            if (alpha == last_alpha)\n                last_alpha = std::min(last_alpha*10,1.0);\n            else\n                last_alpha = alpha;\n\n            // Take the search step indicated by the above line search\n            x = dlib::clamp(x + alpha*s, x_lower, x_upper);\n            g = -der(x);\n\n            // Don't forget to negate the output from the line search since it is  from the\n            // unnegated version of f() \n            f_value *= -1;\n\n            if (!is_finite(f_value))\n                throw error(\"The objective function generated non-finite outputs\");\n            if (!is_finite(g))\n                throw error(\"The objective function generated non-finite outputs\");\n        }\n\n        return -f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_max_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        double x_lower,\n        double x_upper\n    )\n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        typedef typename T::type scalar_type;\n        return find_max_box_constrained(search_strategy,\n                                        stop_strategy,\n                                        f,\n                                        der,\n                                        x,\n                                        uniform_matrix<scalar_type>(x.size(),1,x_lower),\n                                        uniform_matrix<scalar_type>(x.size(),1,x_upper) );\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_H_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_ABSTRACT_\n#ifdef DLIB_OPTIMIZATIOn_ABSTRACT_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n#include \"optimization_search_strategies_abstract.h\"\n#include \"optimization_stop_strategies_abstract.h\"\n#include \"optimization_line_search_abstract.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                    Functions that transform other functions  \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    class central_differences;\n    /*!\n        This is a function object that represents the derivative of some other\n        function. \n\n        Note that if funct is a function of a double then the derivative of \n        funct is just a double but if funct is a function of a dlib::matrix (i.e. a\n        function of many variables) then its derivative is a gradient vector (a column\n        vector in particular).\n    !*/\n\n    template <\n        typename funct\n        >\n    const central_differences<funct> derivative(\n        const funct& f, \n        double eps\n    );\n    /*!\n        requires\n            - f == a function that returns a scalar\n            - f must have one of the following forms:\n                - double f(double)\n                - double f(dlib::matrix)  (where the matrix is a column vector)\n                - double f(T, dlib::matrix)  (where the matrix is a column vector.  In \n                  this case the derivative of f is taken with respect to the second argument.)\n            - eps > 0\n        ensures\n            - returns a function that represents the derivative of the function f.  It\n              is approximated numerically by:\n                  (f(x+eps)-f(x-eps))/(2*eps)\n    !*/\n\n    template <\n        typename funct\n        >\n    const central_differences<funct> derivative(\n        const funct& f\n    );\n    /*!\n        ensures\n            - returns derivative(f, 1e-7)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct, \n        typename EXP1, \n        typename EXP2\n        >\n    clamped_function_object<funct,EXP1,EXP2> clamp_function (\n        const funct& f,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper \n    );\n    /*!\n        requires\n            - f == a function that takes a matrix and returns a scalar value.  Moreover, f\n              must be capable of taking in matrices with the same dimensions as x_lower and\n              x_upper.  So f(x_lower) must be a valid expression that evaluates to a scalar\n              value.\n            - x_lower.nr() == x_upper.nr() && x_lower.nc() == x_upper.nc()\n              (i.e. x_lower and x_upper must have the same dimensions)\n            - x_lower and x_upper must contain the same type of elements.\n        ensures\n            - returns a function object that represents the function g(x) where\n              g(x) == f(clamp(x,x_lower,x_upper))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                    Functions that perform unconstrained optimization \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_min (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x, \n        double min_f\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n        ensures\n            - Performs an unconstrained minimization of the function f() using the given\n              search_strategy and starting from the initial point x.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or f(#x) < min_f.\n            - #x == the value of x that was found to minimize f()\n            - returns f(#x). \n            - When this function makes calls to f() and der() it always does so by\n              first calling f() and then calling der().  That is, these two functions\n              are always called in pairs with f() being called first and then der()\n              being called second.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_max (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x, \n        double max_f\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n        ensures\n            - Performs an unconstrained maximization of the function f() using the given\n              search_strategy and starting from the initial point x.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or f(#x) > max_f.\n            - #x == the value of x that was found to maximize f()\n            - returns f(#x). \n            - When this function makes calls to f() and der() it always does so by\n              first calling f() and then calling der().  That is, these two functions\n              are always called in pairs with f() being called first and then der()\n              being called second.\n            - Note that this function solves the maximization problem by converting it \n              into a minimization problem.  Therefore, the values of f and its derivative\n              reported to the stopping strategy will be negated.  That is, stop_strategy\n              will see -f() and -der().  All this really means is that the status messages\n              from a stopping strategy in verbose mode will display a negated objective\n              value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct,\n        typename T\n        >\n    double find_min_using_approximate_derivatives (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f,\n        T& x,\n        double min_f,\n        double derivative_eps = 1e-7\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - is_col_vector(x) == true\n            - derivative_eps > 0 \n        ensures\n            - Performs an unconstrained minimization of the function f() using the given\n              search_strategy and starting from the initial point x.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or f(#x) < min_f.\n            - #x == the value of x that was found to minimize f()\n            - returns f(#x). \n            - Uses the dlib::derivative(f,derivative_eps) function to compute gradient\n              information.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct,\n        typename T\n        >\n    double find_max_using_approximate_derivatives (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f,\n        T& x,\n        double max_f,\n        double derivative_eps = 1e-7\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - is_col_vector(x) == true\n            - derivative_eps > 0 \n        ensures\n            - Performs an unconstrained maximization of the function f() using the given\n              search_strategy and starting from the initial point x.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or f(#x) > max_f.\n            - #x == the value of x that was found to maximize f()\n            - returns f(#x). \n            - Uses the dlib::derivative(f,derivative_eps) function to compute gradient\n              information.\n            - Note that this function solves the maximization problem by converting it \n              into a minimization problem.  Therefore, the values of f and its derivative\n              reported to the stopping strategy will be negated.  That is, stop_strategy\n              will see -f() and -der().  All this really means is that the status messages\n              from a stopping strategy in verbose mode will display a negated objective\n              value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                  Functions that perform box constrained optimization \n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T,\n        typename EXP1,\n        typename EXP2\n        >\n    double find_min_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n            - is_col_vector(x_lower) == true\n            - is_col_vector(x_upper) == true\n            - x.size() == x_lower.size() == x_upper.size()\n              (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality)\n            - min(x_upper-x_lower) >= 0\n              (i.e. x_upper must contain upper bounds relative to x_lower)\n        ensures\n            - Performs a box constrained minimization of the function f() using the given\n              search_strategy and starting from the initial point x.  That is, we try to\n              find the x value that minimizes f(x) but is also within the box constraints \n              specified by x_lower and x_upper.  That is, we ensure that #x satisfies: \n                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0\n            - This function uses a backtracking line search along with a gradient projection\n              step to handle the box constraints.\n            - The function is optimized until stop_strategy decides that an acceptable\n              point has been found. \n            - #x == the value of x that was found to minimize f() within the given box\n              constraints.\n            - returns f(#x). \n            - The last call to f() will be made with f(#x).  \n            - When calling f() and der(), the input passed to them will always be inside\n              the box constraints defined by x_lower and x_upper.\n            - When calling der(x), it will always be the case that the last call to f() was\n              made with the same x value.  This means that you can reuse any intermediate\n              results from the previous call to f(x) inside der(x) rather than recomputing\n              them inside der(x).\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_min_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const double x_lower,\n        const double x_upper\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n            - x_lower < x_upper\n        ensures\n            - This function is identical to find_min_box_constrained() as defined above\n              except that it takes x_lower and x_upper as doubles rather than column\n              vectors.  In this case, all variables have the same lower bound of x_lower\n              and similarly have the same upper bound of x_upper.  Therefore, this is just\n              a convenience function for calling find_max_box_constrained() when all\n              variables have the same bound constraints.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T,\n        typename EXP1,\n        typename EXP2\n        >\n    double find_max_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const matrix_exp<EXP1>& x_lower,\n        const matrix_exp<EXP2>& x_upper\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n            - is_col_vector(x_lower) == true\n            - is_col_vector(x_upper) == true\n            - x.size() == x_lower.size() == x_upper.size()\n              (i.e. x, x_lower, and x_upper need to all be column vectors of the same dimensionality)\n            - min(x_upper-x_lower) >= 0\n              (i.e. x_upper must contain upper bounds relative to x_lower)\n        ensures\n            - Performs a box constrained maximization of the function f() using the given\n              search_strategy and starting from the initial point x.  That is, we try to\n              find the x value that maximizes f(x) but is also within the box constraints \n              specified by x_lower and x_upper.  That is, we ensure that #x satisfies: \n                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0\n            - This function uses a backtracking line search along with a gradient projection\n              step to handle the box constraints.\n            - The function is optimized until stop_strategy decides that an acceptable\n              point has been found. \n            - #x == the value of x that was found to maximize f() within the given box\n              constraints.\n            - returns f(#x). \n            - The last call to f() will be made with f(#x).  \n            - When calling f() and der(), the input passed to them will always be inside\n              the box constraints defined by x_lower and x_upper.\n            - When calling der(x), it will always be the case that the last call to f() was\n              made with the same x value.  This means that you can reuse any intermediate\n              results from the previous call to f(x) inside der(x) rather than recomputing\n              them inside der(x).\n            - Note that this function solves the maximization problem by converting it \n              into a minimization problem.  Therefore, the values of f and its derivative\n              reported to the stopping strategy will be negated.  That is, stop_strategy\n              will see -f() and -der().  All this really means is that the status messages\n              from a stopping strategy in verbose mode will display a negated objective\n              value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n    \n    template <\n        typename search_strategy_type,\n        typename stop_strategy_type,\n        typename funct, \n        typename funct_der, \n        typename T\n        >\n    double find_max_box_constrained (\n        search_strategy_type search_strategy,\n        stop_strategy_type stop_strategy,\n        const funct& f, \n        const funct_der& der, \n        T& x,\n        const double x_lower,\n        const double x_upper\n    );\n    /*!\n        requires\n            - search_strategy == an object that defines a search strategy such as one \n              of the objects from dlib/optimization/optimization_search_strategies_abstract.h\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - f(x) must be a valid expression that evaluates to a double\n            - der(x) must be a valid expression that evaluates to the derivative of f() at x.\n            - is_col_vector(x) == true\n            - x_lower < x_upper\n        ensures\n            - This function is identical to find_max_box_constrained() as defined above\n              except that it takes x_lower and x_upper as doubles rather than column\n              vectors.  In this case, all variables have the same lower bound of x_lower\n              and similarly have the same upper bound of x_upper.  Therefore, this is just\n              a convenience function for calling find_max_box_constrained() when all\n              variables have the same bound constraints.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_ABSTRACT_\n\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_bobyqa.h",
    "content": "// Copyright (C) 2009 M.J.D. Powell, Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_BOBYQA_Hh_\n#define DLIB_OPTIMIZATIOn_BOBYQA_Hh_\n\n/*\n    The code in this file is derived from Powell's BOBYQA Fortran code.\n    It was created by running f2c on the original Fortran code and then \n    massaging the resulting C code into what you can see below.\n\n\n    The following paper, published in 2009 by Powell, describes the\n    detailed workings of the BOBYQA algorithm.  \n\n        The BOBYQA algorithm for bound constrained optimization \n        without derivatives by M.J.D. Powell\n*/\n\n#include <algorithm>\n#include <cmath>\n#include <memory>\n\n#include \"../matrix.h\"\n#include \"optimization_bobyqa_abstract.h\"\n#include \"optimization.h\"\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n\n    class bobyqa_failure : public error {\n    public: bobyqa_failure(const std::string& s):error(s){}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class bobyqa_implementation\n    {\n        typedef long integer;\n        typedef double doublereal;\n\n    public:\n\n        template <\n            typename funct,\n            typename T, \n            typename U\n            >\n        double find_min (\n            const funct& f,\n            T& x,\n            long npt,\n            const U& xl_,\n            const U& xu_,\n            const double rhobeg,\n            const double rhoend,\n            const long max_f_evals\n        ) const\n        {\n            const unsigned long n = x.size();\n            const unsigned long w_size = (npt+5)*(npt+n)+3*n*(n+5)/2;\n            std::unique_ptr<doublereal[]> w(new doublereal[w_size]);\n\n            // make these temporary matrices becuse U might be some\n            // kind of matrix_exp that doesn't support taking the address\n            // of the first element.\n            matrix<double,0,1> xl(xl_);\n            matrix<double,0,1> xu(xu_);\n\n            \n            return bobyqa_ (f,\n                            x.size(),\n                            npt,\n                            &x(0),\n                            &xl(0),\n                            &xu(0),\n                            rhobeg,\n                            rhoend,\n                            max_f_evals,\n                            w.get() );\n        }\n\n    private:\n\n\n        template <typename funct>\n        doublereal bobyqa_(\n            const funct& calfun,\n            const integer n, \n            const integer npt, \n            doublereal *x, \n            const doublereal *xl,\n            const doublereal *xu,\n            const doublereal rhobeg,\n            const doublereal rhoend,\n            const integer maxfun,\n            doublereal *w\n        ) const\n        {\n\n            /* System generated locals */\n            integer i__1;\n            doublereal d__1, d__2;\n\n            /* Local variables */\n            integer j, id_, np, iw, igo, ihq, ixb, ixa, ifv, isl, jsl, ipq, ivl, ixn, ixo, ixp, isu, jsu, ndim;\n            doublereal temp, zero;\n            integer ibmat, izmat;\n\n\n            /*     This subroutine seeks the least value of a function of many variables, */\n            /*     by applying a trust region method that forms quadratic models by */\n            /*     interpolation. There is usually some freedom in the interpolation */\n            /*     conditions, which is taken up by minimizing the Frobenius norm of */\n            /*     the change to the second derivative of the model, beginning with the */\n            /*     zero matrix. The values of the variables are constrained by upper and */\n            /*     lower bounds. The arguments of the subroutine are as follows. */\n\n            /*     N must be set to the number of variables and must be at least two. */\n            /*     NPT is the number of interpolation conditions. Its value must be in */\n            /*       the interval [N+2,(N+1)(N+2)/2]. Choices that exceed 2*N+1 are not */\n            /*       recommended. */\n            /*     Initial values of the variables must be set in X(1),X(2),...,X(N). They */\n            /*       will be changed to the values that give the least calculated F. */\n            /*     For I=1,2,...,N, XL(I) and XU(I) must provide the lower and upper */\n            /*       bounds, respectively, on X(I). The construction of quadratic models */\n            /*       requires XL(I) to be strictly less than XU(I) for each I. Further, */\n            /*       the contribution to a model from changes to the I-th variable is */\n            /*       damaged severely by rounding errors if XU(I)-XL(I) is too small. */\n            /*     RHOBEG and RHOEND must be set to the initial and final values of a trust */\n            /*       region radius, so both must be positive with RHOEND no greater than */\n            /*       RHOBEG. Typically, RHOBEG should be about one tenth of the greatest */\n            /*       expected change to a variable, while RHOEND should indicate the */\n            /*       accuracy that is required in the final values of the variables. An */\n            /*       error return occurs if any of the differences XU(I)-XL(I), I=1,...,N, */\n            /*       is less than 2*RHOBEG. */\n            /*     MAXFUN must be set to an upper bound on the number of calls of CALFUN. */\n            /*     The array W will be used for working space. Its length must be at least */\n            /*       (NPT+5)*(NPT+N)+3*N*(N+5)/2. */\n\n            /* Parameter adjustments */\n            --w;\n            --xu;\n            --xl;\n            --x;\n\n            /* Function Body */\n            np = n + 1;\n\n            /*     Return if the value of NPT is unacceptable. */\n            if (npt < n + 2 || npt > (n + 2) * np / 2) {\n                throw bobyqa_failure(\"Return from BOBYQA because NPT is not in the required interval\");\n                //goto L40;\n            }\n\n            /*     Partition the working space array, so that different parts of it can */\n            /*     be treated separately during the calculation of BOBYQB. The partition */\n            /*     requires the first (NPT+2)*(NPT+N)+3*N*(N+5)/2 elements of W plus the */\n            /*     space that is taken by the last array in the argument list of BOBYQB. */\n\n            ndim = npt + n;\n            ixb = 1;\n            ixp = ixb + n;\n            ifv = ixp + n * npt;\n            ixo = ifv + npt;\n            igo = ixo + n;\n            ihq = igo + n;\n            ipq = ihq + n * np / 2;\n            ibmat = ipq + npt;\n            izmat = ibmat + ndim * n;\n            isl = izmat + npt * (npt - np);\n            isu = isl + n;\n            ixn = isu + n;\n            ixa = ixn + n;\n            id_ = ixa + n;\n            ivl = id_ + n;\n            iw = ivl + ndim;\n\n            /*     Return if there is insufficient space between the bounds. Modify the */\n            /*     initial X if necessary in order to avoid conflicts between the bounds */\n            /*     and the construction of the first quadratic model. The lower and upper */\n            /*     bounds on moves from the updated X are set now, in the ISL and ISU */\n            /*     partitions of W, in order to provide useful and exact information about */\n            /*     components of X that become within distance RHOBEG from their bounds. */\n\n            zero = 0.;\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                temp = xu[j] - xl[j];\n                if (temp < rhobeg + rhobeg) {\n                    throw bobyqa_failure(\"Return from BOBYQA because one of the differences in x_lower and x_upper is less than 2*rho_begin\");\n                    //goto L40;\n                }\n                jsl = isl + j - 1;\n                jsu = jsl + n;\n                w[jsl] = xl[j] - x[j];\n                w[jsu] = xu[j] - x[j];\n                if (w[jsl] >= -(rhobeg)) {\n                    if (w[jsl] >= zero) {\n                        x[j] = xl[j];\n                        w[jsl] = zero;\n                        w[jsu] = temp;\n                    } else {\n                        x[j] = xl[j] + rhobeg;\n                        w[jsl] = -(rhobeg);\n                        /* Computing MAX */\n                        d__1 = xu[j] - x[j];\n                        w[jsu] = std::max(d__1,rhobeg);\n                    }\n                } else if (w[jsu] <= rhobeg) {\n                    if (w[jsu] <= zero) {\n                        x[j] = xu[j];\n                        w[jsl] = -temp;\n                        w[jsu] = zero;\n                    } else {\n                        x[j] = xu[j] - rhobeg;\n                        /* Computing MIN */\n                        d__1 = xl[j] - x[j], d__2 = -(rhobeg);\n                        w[jsl] = std::min(d__1,d__2);\n                        w[jsu] = rhobeg;\n                    }\n                }\n                /* L30: */\n            }\n\n            /*     Make the call of BOBYQB. */\n\n            return bobyqb_(calfun, n, npt, &x[1], &xl[1], &xu[1], rhobeg, rhoend, maxfun, &w[\n                    ixb], &w[ixp], &w[ifv], &w[ixo], &w[igo], &w[ihq], &w[ipq], &w[\n                    ibmat], &w[izmat], ndim, &w[isl], &w[isu], &w[ixn], &w[ixa], &w[\n                    id_], &w[ivl], &w[iw]);\n            //L40:\n            ;\n        } /* bobyqa_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename funct>\n        doublereal bobyqb_(\n            const funct& calfun,\n            const integer n,\n            const integer npt,\n            doublereal *x,\n            const doublereal *xl,\n            const doublereal *xu,\n            const doublereal rhobeg,\n            const doublereal rhoend,\n            const integer maxfun,\n            doublereal *xbase, \n            doublereal *xpt,\n            doublereal *fval,\n            doublereal *xopt,\n            doublereal *gopt,\n            doublereal *hq,\n            doublereal *pq,\n            doublereal *bmat,\n            doublereal *zmat, \n            const integer ndim,\n            doublereal *sl,\n            doublereal *su, \n            doublereal *xnew, \n            doublereal *xalt,\n            doublereal *d__,\n            doublereal *vlag, \n            doublereal *w\n        ) const\n        {\n            /* System generated locals */\n            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1, \n            zmat_offset, i__1, i__2, i__3;\n            doublereal d__1, d__2, d__3, d__4;\n\n            /* Local variables */\n            doublereal f = 0;\n            integer i__, j, k, ih, nf, jj, nh, ip, jp;\n            doublereal dx;\n            integer np;\n            doublereal den = 0, one = 0, ten = 0, dsq = 0, rho = 0, sum = 0, two = 0, diff = 0, half = 0, beta = 0, gisq = 0;\n            integer knew = 0;\n            doublereal temp, suma, sumb, bsum, fopt;\n            integer kopt = 0, nptm;\n            doublereal zero, curv;\n            integer ksav;\n            doublereal gqsq = 0, dist = 0, sumw = 0, sumz = 0, diffa = 0, diffb = 0, diffc = 0, hdiag = 0;\n            integer kbase;\n            doublereal alpha = 0, delta = 0, adelt = 0, denom = 0, fsave = 0, bdtol = 0, delsq = 0;\n            integer nresc, nfsav;\n            doublereal ratio = 0, dnorm = 0, vquad = 0, pqold = 0, tenth = 0;\n            integer itest;\n            doublereal sumpq, scaden;\n            doublereal errbig, cauchy=0, fracsq, biglsq, densav;\n            doublereal bdtest;\n            doublereal crvmin, frhosq;\n            doublereal distsq;\n            integer ntrits;\n            doublereal xoptsq;\n\n\n\n            /*     The arguments N, NPT, X, XL, XU, RHOBEG, RHOEND, IPRINT and MAXFUN */\n            /*       are identical to the corresponding arguments in SUBROUTINE BOBYQA. */\n            /*     XBASE holds a shift of origin that should reduce the contributions */\n            /*       from rounding errors to values of the model and Lagrange functions. */\n            /*     XPT is a two-dimensional array that holds the coordinates of the */\n            /*       interpolation points relative to XBASE. */\n            /*     FVAL holds the values of F at the interpolation points. */\n            /*     XOPT is set to the displacement from XBASE of the trust region centre. */\n            /*     GOPT holds the gradient of the quadratic model at XBASE+XOPT. */\n            /*     HQ holds the explicit second derivatives of the quadratic model. */\n            /*     PQ contains the parameters of the implicit second derivatives of the */\n            /*       quadratic model. */\n            /*     BMAT holds the last N columns of H. */\n            /*     ZMAT holds the factorization of the leading NPT by NPT submatrix of H, */\n            /*       this factorization being ZMAT times ZMAT^T, which provides both the */\n            /*       correct rank and positive semi-definiteness. */\n            /*     NDIM is the first dimension of BMAT and has the value NPT+N. */\n            /*     SL and SU hold the differences XL-XBASE and XU-XBASE, respectively. */\n            /*       All the components of every XOPT are going to satisfy the bounds */\n            /*       SL(I) .LEQ. XOPT(I) .LEQ. SU(I), with appropriate equalities when */\n            /*       XOPT is on a constraint boundary. */\n            /*     XNEW is chosen by SUBROUTINE TRSBOX or ALTMOV. Usually XBASE+XNEW is the */\n            /*       vector of variables for the next call of CALFUN. XNEW also satisfies */\n            /*       the SL and SU constraints in the way that has just been mentioned. */\n            /*     XALT is an alternative to XNEW, chosen by ALTMOV, that may replace XNEW */\n            /*       in order to increase the denominator in the updating of UPDATE. */\n            /*     D is reserved for a trial step from XOPT, which is usually XNEW-XOPT. */\n            /*     VLAG contains the values of the Lagrange functions at a new point X. */\n            /*       They are part of a product that requires VLAG to be of length NDIM. */\n            /*     W is a one-dimensional array that is used for working space. Its length */\n            /*       must be at least 3*NDIM = 3*(NPT+N). */\n\n            /*     Set some constants. */\n\n            /* Parameter adjustments */\n            zmat_dim1 = npt;\n            zmat_offset = 1 + zmat_dim1;\n            zmat -= zmat_offset;\n            xpt_dim1 = npt;\n            xpt_offset = 1 + xpt_dim1;\n            xpt -= xpt_offset;\n            --x;\n            --xl;\n            --xu;\n            --xbase;\n            --fval;\n            --xopt;\n            --gopt;\n            --hq;\n            --pq;\n            bmat_dim1 = ndim;\n            bmat_offset = 1 + bmat_dim1;\n            bmat -= bmat_offset;\n            --sl;\n            --su;\n            --xnew;\n            --xalt;\n            --d__;\n            --vlag;\n            --w;\n\n            /* Function Body */\n            half = .5;\n            one = 1.;\n            ten = 10.;\n            tenth = .1;\n            two = 2.;\n            zero = 0.;\n            np = n + 1;\n            nptm = npt - np;\n            nh = n * np / 2;\n\n            /*     The call of PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ, */\n            /*     BMAT and ZMAT for the first iteration, with the corresponding values of */\n            /*     of NF and KOPT, which are the number of calls of CALFUN so far and the */\n            /*     index of the interpolation point at the trust region centre. Then the */\n            /*     initial XOPT is set too. The branch to label 720 occurs if MAXFUN is */\n            /*     less than NPT. GOPT will be updated if KOPT is different from KBASE. */\n\n            prelim_(calfun, n, npt, &x[1], &xl[1], &xu[1], rhobeg, maxfun, &xbase[1], \n                    &xpt[xpt_offset], &fval[1], &gopt[1], &hq[1], &pq[1], &bmat[bmat_offset], \n                    &zmat[zmat_offset], ndim, &sl[1], &su[1], nf, kopt);\n            xoptsq = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                xopt[i__] = xpt[kopt + i__ * xpt_dim1];\n                /* L10: */\n                /* Computing 2nd power */\n                d__1 = xopt[i__];\n                xoptsq += d__1 * d__1;\n            }\n            fsave = fval[1];\n            if (nf < npt) {\n                throw bobyqa_failure(\"Return from BOBYQA because the objective function has been called max_f_evals times.\");\n                //goto L720;\n            }\n            kbase = 1;\n\n            /*     Complete the settings that are required for the iterative procedure. */\n\n            rho = rhobeg;\n            delta = rho;\n            nresc = nf;\n            ntrits = 0;\n            diffa = zero;\n            diffb = zero;\n            itest = 0;\n            nfsav = nf;\n\n            /*     Update GOPT if necessary before the first iteration and after each */\n            /*     call of RESCUE that makes a call of CALFUN. */\n\nL20:\n            if (kopt != kbase) {\n                ih = 0;\n                i__1 = n;\n                for (j = 1; j <= i__1; ++j) {\n                    i__2 = j;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        ++ih;\n                        if (i__ < j) {\n                            gopt[j] += hq[ih] * xopt[i__];\n                        }\n                        /* L30: */\n                        gopt[i__] += hq[ih] * xopt[j];\n                    }\n                }\n                if (nf > npt) {\n                    i__2 = npt;\n                    for (k = 1; k <= i__2; ++k) {\n                        temp = zero;\n                        i__1 = n;\n                        for (j = 1; j <= i__1; ++j) {\n                            /* L40: */\n                            temp += xpt[k + j * xpt_dim1] * xopt[j];\n                        }\n                        temp = pq[k] * temp;\n                        i__1 = n;\n                        for (i__ = 1; i__ <= i__1; ++i__) {\n                            /* L50: */\n                            gopt[i__] += temp * xpt[k + i__ * xpt_dim1];\n                        }\n                    }\n                }\n            }\n\n            /*     Generate the next point in the trust region that provides a small value */\n            /*     of the quadratic model subject to the constraints on the variables. */\n            /*     The integer NTRITS is set to the number \"trust region\" iterations that */\n            /*     have occurred since the last \"alternative\" iteration. If the length */\n            /*     of XNEW-XOPT is less than HALF*RHO, however, then there is a branch to */\n            /*     label 650 or 680 with NTRITS=-1, instead of calculating F at XNEW. */\n\nL60:\n            trsbox_(n, npt, &xpt[xpt_offset], &xopt[1], &gopt[1], &hq[1], &pq[1], &sl[1], \n                    &su[1], delta, &xnew[1], &d__[1], &w[1], &w[np], &w[np + n],\n                    &w[np + (n << 1)], &w[np + n * 3], &dsq, &crvmin);\n            /* Computing MIN */\n            d__1 = delta, d__2 = std::sqrt(dsq);\n            dnorm = std::min(d__1,d__2);\n            if (dnorm < half * rho) {\n                ntrits = -1;\n                /* Computing 2nd power */\n                d__1 = ten * rho;\n                distsq = d__1 * d__1;\n                if (nf <= nfsav + 2) {\n                    goto L650;\n                }\n\n                /*     The following choice between labels 650 and 680 depends on whether or */\n                /*     not our work with the current RHO seems to be complete. Either RHO is */\n                /*     decreased or termination occurs if the errors in the quadratic model at */\n                /*     the last three interpolation points compare favourably with predictions */\n                /*     of likely improvements to the model within distance HALF*RHO of XOPT. */\n\n                /* Computing MAX */\n                d__1 = std::max(diffa,diffb);\n                errbig = std::max(d__1,diffc);\n                frhosq = rho * .125 * rho;\n                if (crvmin > zero && errbig > frhosq * crvmin) {\n                    goto L650;\n                }\n                bdtol = errbig / rho;\n                i__1 = n;\n                for (j = 1; j <= i__1; ++j) {\n                    bdtest = bdtol;\n                    if (xnew[j] == sl[j]) {\n                        bdtest = w[j];\n                    }\n                    if (xnew[j] == su[j]) {\n                        bdtest = -w[j];\n                    }\n                    if (bdtest < bdtol) {\n                        curv = hq[(j + j * j) / 2];\n                        i__2 = npt;\n                        for (k = 1; k <= i__2; ++k) {\n                            /* L70: */\n                            /* Computing 2nd power */\n                            d__1 = xpt[k + j * xpt_dim1];\n                            curv += pq[k] * (d__1 * d__1);\n                        }\n                        bdtest += half * curv * rho;\n                        if (bdtest < bdtol) {\n                            goto L650;\n                        }\n                    }\n                    /* L80: */\n                }\n                goto L680;\n            }\n            ++ntrits;\n\n            /*     Severe cancellation is likely to occur if XOPT is too far from XBASE. */\n            /*     If the following test holds, then XBASE is shifted so that XOPT becomes */\n            /*     zero. The appropriate changes are made to BMAT and to the second */\n            /*     derivatives of the current model, beginning with the changes to BMAT */\n            /*     that do not depend on ZMAT. VLAG is used temporarily for working space. */\n\nL90:\n            if (dsq <= xoptsq * .001) {\n                fracsq = xoptsq * .25;\n                sumpq = zero;\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    sumpq += pq[k];\n                    sum = -half * xoptsq;\n                    i__2 = n;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        /* L100: */\n                        sum += xpt[k + i__ * xpt_dim1] * xopt[i__];\n                    }\n                    w[npt + k] = sum;\n                    temp = fracsq - half * sum;\n                    i__2 = n;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        w[i__] = bmat[k + i__ * bmat_dim1];\n                        vlag[i__] = sum * xpt[k + i__ * xpt_dim1] + temp * xopt[i__];\n                        ip = npt + i__;\n                        i__3 = i__;\n                        for (j = 1; j <= i__3; ++j) {\n                            /* L110: */\n                            bmat[ip + j * bmat_dim1] = bmat[ip + j * bmat_dim1] + w[\n                                i__] * vlag[j] + vlag[i__] * w[j];\n                        }\n                    }\n                }\n\n                /*     Then the revisions of BMAT that depend on ZMAT are calculated. */\n\n                i__3 = nptm;\n                for (jj = 1; jj <= i__3; ++jj) {\n                    sumz = zero;\n                    sumw = zero;\n                    i__2 = npt;\n                    for (k = 1; k <= i__2; ++k) {\n                        sumz += zmat[k + jj * zmat_dim1];\n                        vlag[k] = w[npt + k] * zmat[k + jj * zmat_dim1];\n                        /* L120: */\n                        sumw += vlag[k];\n                    }\n                    i__2 = n;\n                    for (j = 1; j <= i__2; ++j) {\n                        sum = (fracsq * sumz - half * sumw) * xopt[j];\n                        i__1 = npt;\n                        for (k = 1; k <= i__1; ++k) {\n                            /* L130: */\n                            sum += vlag[k] * xpt[k + j * xpt_dim1];\n                        }\n                        w[j] = sum;\n                        i__1 = npt;\n                        for (k = 1; k <= i__1; ++k) {\n                            /* L140: */\n                            bmat[k + j * bmat_dim1] += sum * zmat[k + jj * zmat_dim1];\n                        }\n                    }\n                    i__1 = n;\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        ip = i__ + npt;\n                        temp = w[i__];\n                        i__2 = i__;\n                        for (j = 1; j <= i__2; ++j) {\n                            /* L150: */\n                            bmat[ip + j * bmat_dim1] += temp * w[j];\n                        }\n                    }\n                }\n\n                /*     The following instructions complete the shift, including the changes */\n                /*     to the second derivative parameters of the quadratic model. */\n\n                ih = 0;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    w[j] = -half * sumpq * xopt[j];\n                    i__1 = npt;\n                    for (k = 1; k <= i__1; ++k) {\n                        w[j] += pq[k] * xpt[k + j * xpt_dim1];\n                        /* L160: */\n                        xpt[k + j * xpt_dim1] -= xopt[j];\n                    }\n                    i__1 = j;\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        ++ih;\n                        hq[ih] = hq[ih] + w[i__] * xopt[j] + xopt[i__] * w[j];\n                        /* L170: */\n                        bmat[npt + i__ + j * bmat_dim1] = bmat[npt + j + i__ * \n                            bmat_dim1];\n                    }\n                }\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    xbase[i__] += xopt[i__];\n                    xnew[i__] -= xopt[i__];\n                    sl[i__] -= xopt[i__];\n                    su[i__] -= xopt[i__];\n                    /* L180: */\n                    xopt[i__] = zero;\n                }\n                xoptsq = zero;\n            }\n            if (ntrits == 0) {\n                goto L210;\n            }\n            goto L230;\n\n            /*     XBASE is also moved to XOPT by a call of RESCUE. This calculation is */\n            /*     more expensive than the previous shift, because new matrices BMAT and */\n            /*     ZMAT are generated from scratch, which may include the replacement of */\n            /*     interpolation points whose positions seem to be causing near linear */\n            /*     dependence in the interpolation conditions. Therefore RESCUE is called */\n            /*     only if rounding errors have reduced by at least a factor of two the */\n            /*     denominator of the formula for updating the H matrix. It provides a */\n            /*     useful safeguard, but is not invoked in most applications of BOBYQA. */\n\nL190:\n            nfsav = nf;\n            kbase = kopt;\n            rescue_(calfun, n, npt, &xl[1], &xu[1], maxfun, &xbase[1], &xpt[\n                    xpt_offset], &fval[1], &xopt[1], &gopt[1], &hq[1], &pq[1], &bmat[\n                    bmat_offset], &zmat[zmat_offset], ndim, &sl[1], &su[1], nf, delta, \n                    kopt, &vlag[1], &w[1], &w[n + np], &w[ndim + np]);\n\n            /*     XOPT is updated now in case the branch below to label 720 is taken. */\n            /*     Any updating of GOPT occurs after the branch below to label 20, which */\n            /*     leads to a trust region iteration as does the branch to label 60. */\n\n            xoptsq = zero;\n            if (kopt != kbase) {\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    xopt[i__] = xpt[kopt + i__ * xpt_dim1];\n                    /* L200: */\n                    /* Computing 2nd power */\n                    d__1 = xopt[i__];\n                    xoptsq += d__1 * d__1;\n                }\n            }\n            if (nf < 0) {\n                nf = maxfun;\n                throw bobyqa_failure(\"Return from BOBYQA because the objective function has been called max_f_evals times.\");\n                //goto L720;\n            }\n            nresc = nf;\n            if (nfsav < nf) {\n                nfsav = nf;\n                goto L20;\n            }\n            if (ntrits > 0) {\n                goto L60;\n            }\n\n            /*     Pick two alternative vectors of variables, relative to XBASE, that */\n            /*     are suitable as new positions of the KNEW-th interpolation point. */\n            /*     Firstly, XNEW is set to the point on a line through XOPT and another */\n            /*     interpolation point that minimizes the predicted value of the next */\n            /*     denominator, subject to ||XNEW - XOPT|| .LEQ. ADELT and to the SL */\n            /*     and SU bounds. Secondly, XALT is set to the best feasible point on */\n            /*     a constrained version of the Cauchy step of the KNEW-th Lagrange */\n            /*     function, the corresponding value of the square of this function */\n            /*     being returned in CAUCHY. The choice between these alternatives is */\n            /*     going to be made when the denominator is calculated. */\n\nL210:\n            altmov_(n, npt, &xpt[xpt_offset], &xopt[1], &bmat[bmat_offset], &zmat[zmat_offset], \n                    ndim, &sl[1], &su[1], kopt, knew, adelt, &xnew[1], \n                    &xalt[1], alpha, cauchy, &w[1], &w[np], &w[ndim + 1]);\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                /* L220: */\n                d__[i__] = xnew[i__] - xopt[i__];\n            }\n\n            /*     Calculate VLAG and BETA for the current choice of D. The scalar */\n            /*     product of D with XPT(K,.) is going to be held in W(NPT+K) for */\n            /*     use when VQUAD is calculated. */\n\nL230:\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                suma = zero;\n                sumb = zero;\n                sum = zero;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    suma += xpt[k + j * xpt_dim1] * d__[j];\n                    sumb += xpt[k + j * xpt_dim1] * xopt[j];\n                    /* L240: */\n                    sum += bmat[k + j * bmat_dim1] * d__[j];\n                }\n                w[k] = suma * (half * suma + sumb);\n                vlag[k] = sum;\n                /* L250: */\n                w[npt + k] = suma;\n            }\n            beta = zero;\n            i__1 = nptm;\n            for (jj = 1; jj <= i__1; ++jj) {\n                sum = zero;\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L260: */\n                    sum += zmat[k + jj * zmat_dim1] * w[k];\n                }\n                beta -= sum * sum;\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L270: */\n                    vlag[k] += sum * zmat[k + jj * zmat_dim1];\n                }\n            }\n            dsq = zero;\n            bsum = zero;\n            dx = zero;\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                /* Computing 2nd power */\n                d__1 = d__[j];\n                dsq += d__1 * d__1;\n                sum = zero;\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    /* L280: */\n                    sum += w[k] * bmat[k + j * bmat_dim1];\n                }\n                bsum += sum * d__[j];\n                jp = npt + j;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    /* L290: */\n                    sum += bmat[jp + i__ * bmat_dim1] * d__[i__];\n                }\n                vlag[jp] = sum;\n                bsum += sum * d__[j];\n                /* L300: */\n                dx += d__[j] * xopt[j];\n            }\n            beta = dx * dx + dsq * (xoptsq + dx + dx + half * dsq) + beta - bsum;\n            vlag[kopt] += one;\n\n            /*     If NTRITS is zero, the denominator may be increased by replacing */\n            /*     the step D of ALTMOV by a Cauchy step. Then RESCUE may be called if */\n            /*     rounding errors have damaged the chosen denominator. */\n\n            if (ntrits == 0) {\n                /* Computing 2nd power */\n                d__1 = vlag[knew];\n                denom = d__1 * d__1 + alpha * beta;\n                if (denom < cauchy && cauchy > zero) {\n                    i__2 = n;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        xnew[i__] = xalt[i__];\n                        /* L310: */\n                        d__[i__] = xnew[i__] - xopt[i__];\n                    }\n                    cauchy = zero;\n                    goto L230;\n                }\n                /* Computing 2nd power */\n                d__1 = vlag[knew];\n                if (denom <= half * (d__1 * d__1)) {\n                    if (nf > nresc) {\n                        goto L190;\n                    }\n                    throw bobyqa_failure(\"Return from BOBYQA because of much cancellation in a denominator.\");\n                    //goto L720;\n                }\n\n                /*     Alternatively, if NTRITS is positive, then set KNEW to the index of */\n                /*     the next interpolation point to be deleted to make room for a trust */\n                /*     region step. Again RESCUE may be called if rounding errors have damaged */\n                /*     the chosen denominator, which is the reason for attempting to select */\n                /*     KNEW before calculating the next value of the objective function. */\n\n            } else {\n                delsq = delta * delta;\n                scaden = zero;\n                biglsq = zero;\n                knew = 0;\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    if (k == kopt) {\n                        goto L350;\n                    }\n                    hdiag = zero;\n                    i__1 = nptm;\n                    for (jj = 1; jj <= i__1; ++jj) {\n                        /* L330: */\n                        /* Computing 2nd power */\n                        d__1 = zmat[k + jj * zmat_dim1];\n                        hdiag += d__1 * d__1;\n                    }\n                    /* Computing 2nd power */\n                    d__1 = vlag[k];\n                    den = beta * hdiag + d__1 * d__1;\n                    distsq = zero;\n                    i__1 = n;\n                    for (j = 1; j <= i__1; ++j) {\n                        /* L340: */\n                        /* Computing 2nd power */\n                        d__1 = xpt[k + j * xpt_dim1] - xopt[j];\n                        distsq += d__1 * d__1;\n                    }\n                    /* Computing MAX */\n                    /* Computing 2nd power */\n                    d__3 = distsq / delsq;\n                    d__1 = one, d__2 = d__3 * d__3;\n                    temp = std::max(d__1,d__2);\n                    if (temp * den > scaden) {\n                        scaden = temp * den;\n                        knew = k;\n                        denom = den;\n                    }\n                    /* Computing MAX */\n                    /* Computing 2nd power */\n                    d__3 = vlag[k];\n                    d__1 = biglsq, d__2 = temp * (d__3 * d__3);\n                    biglsq = std::max(d__1,d__2);\nL350:\n                    ;\n                }\n                if (scaden <= half * biglsq) {\n                    if (nf > nresc) {\n                        goto L190;\n                    }\n                    throw bobyqa_failure(\"Return from BOBYQA because of much cancellation in a denominator.\");\n                    //goto L720;\n                }\n            }\n\n            /*     Put the variables for the next calculation of the objective function */\n            /*       in XNEW, with any adjustments for the bounds. */\n\n\n            /*     Calculate the value of the objective function at XBASE+XNEW, unless */\n            /*       the limit on the number of calculations of F has been reached. */\n\nL360:\n            i__2 = n;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                /* Computing MIN */\n                /* Computing MAX */\n                d__3 = xl[i__], d__4 = xbase[i__] + xnew[i__];\n                d__1 = std::max(d__3,d__4), d__2 = xu[i__];\n                x[i__] = std::min(d__1,d__2);\n                if (xnew[i__] == sl[i__]) {\n                    x[i__] = xl[i__];\n                }\n                if (xnew[i__] == su[i__]) {\n                    x[i__] = xu[i__];\n                }\n                /* L380: */\n            }\n            if (nf >= maxfun) {\n                throw bobyqa_failure(\"Return from BOBYQA because the objective function has been called max_f_evals times.\");\n                //goto L720;\n            }\n            ++nf;\n            f = calfun(mat(&x[1], n));\n            if (ntrits == -1) {\n                fsave = f;\n                goto L720;\n            }\n\n            /*     Use the quadratic model to predict the change in F due to the step D, */\n            /*       and set DIFF to the error of this prediction. */\n\n            fopt = fval[kopt];\n            vquad = zero;\n            ih = 0;\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                vquad += d__[j] * gopt[j];\n                i__1 = j;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    ++ih;\n                    temp = d__[i__] * d__[j];\n                    if (i__ == j) {\n                        temp = half * temp;\n                    }\n                    /* L410: */\n                    vquad += hq[ih] * temp;\n                }\n            }\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                /* L420: */\n                /* Computing 2nd power */\n                d__1 = w[npt + k];\n                vquad += half * pq[k] * (d__1 * d__1);\n            }\n            diff = f - fopt - vquad;\n            diffc = diffb;\n            diffb = diffa;\n            diffa = std::abs(diff);\n            if (dnorm > rho) {\n                nfsav = nf;\n            }\n\n            /*     Pick the next value of DELTA after a trust region step. */\n\n            if (ntrits > 0) {\n                if (vquad >= zero) {\n                    throw bobyqa_failure(\"Return from BOBYQA because a trust region step has failed to reduce Q.\");\n                    //goto L720;\n                }\n                ratio = (f - fopt) / vquad;\n                if (ratio <= tenth) {\n                    /* Computing MIN */\n                    d__1 = half * delta;\n                    delta = std::min(d__1,dnorm);\n                } else if (ratio <= .7) {\n                    /* Computing MAX */\n                    d__1 = half * delta;\n                    delta = std::max(d__1,dnorm);\n                } else {\n                    /* Computing MAX */\n                    d__1 = half * delta, d__2 = dnorm + dnorm;\n                    delta = std::max(d__1,d__2);\n                }\n                if (delta <= rho * 1.5) {\n                    delta = rho;\n                }\n\n                /*     Recalculate KNEW and DENOM if the new F is less than FOPT. */\n\n                if (f < fopt) {\n                    ksav = knew;\n                    densav = denom;\n                    delsq = delta * delta;\n                    scaden = zero;\n                    biglsq = zero;\n                    knew = 0;\n                    i__1 = npt;\n                    for (k = 1; k <= i__1; ++k) {\n                        hdiag = zero;\n                        i__2 = nptm;\n                        for (jj = 1; jj <= i__2; ++jj) {\n                            /* L440: */\n                            /* Computing 2nd power */\n                            d__1 = zmat[k + jj * zmat_dim1];\n                            hdiag += d__1 * d__1;\n                        }\n                        /* Computing 2nd power */\n                        d__1 = vlag[k];\n                        den = beta * hdiag + d__1 * d__1;\n                        distsq = zero;\n                        i__2 = n;\n                        for (j = 1; j <= i__2; ++j) {\n                            /* L450: */\n                            /* Computing 2nd power */\n                            d__1 = xpt[k + j * xpt_dim1] - xnew[j];\n                            distsq += d__1 * d__1;\n                        }\n                        /* Computing MAX */\n                        /* Computing 2nd power */\n                        d__3 = distsq / delsq;\n                        d__1 = one, d__2 = d__3 * d__3;\n                        temp = std::max(d__1,d__2);\n                        if (temp * den > scaden) {\n                            scaden = temp * den;\n                            knew = k;\n                            denom = den;\n                        }\n                        /* L460: */\n                        /* Computing MAX */\n                        /* Computing 2nd power */\n                        d__3 = vlag[k];\n                        d__1 = biglsq, d__2 = temp * (d__3 * d__3);\n                        biglsq = std::max(d__1,d__2);\n                    }\n                    if (scaden <= half * biglsq) {\n                        knew = ksav;\n                        denom = densav;\n                    }\n                }\n            }\n\n            /*     Update BMAT and ZMAT, so that the KNEW-th interpolation point can be */\n            /*     moved. Also update the second derivative terms of the model. */\n\n            update_(n, npt, &bmat[bmat_offset], &zmat[zmat_offset], ndim, &vlag[1], \n                    beta, denom, knew, &w[1]);\n            ih = 0;\n            pqold = pq[knew];\n            pq[knew] = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                temp = pqold * xpt[knew + i__ * xpt_dim1];\n                i__2 = i__;\n                for (j = 1; j <= i__2; ++j) {\n                    ++ih;\n                    /* L470: */\n                    hq[ih] += temp * xpt[knew + j * xpt_dim1];\n                }\n            }\n            i__2 = nptm;\n            for (jj = 1; jj <= i__2; ++jj) {\n                temp = diff * zmat[knew + jj * zmat_dim1];\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    /* L480: */\n                    pq[k] += temp * zmat[k + jj * zmat_dim1];\n                }\n            }\n\n            /*     Include the new interpolation point, and make the changes to GOPT at */\n            /*     the old XOPT that are caused by the updating of the quadratic model. */\n\n            fval[knew] = f;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                xpt[knew + i__ * xpt_dim1] = xnew[i__];\n                /* L490: */\n                w[i__] = bmat[knew + i__ * bmat_dim1];\n            }\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                suma = zero;\n                i__2 = nptm;\n                for (jj = 1; jj <= i__2; ++jj) {\n                    /* L500: */\n                    suma += zmat[knew + jj * zmat_dim1] * zmat[k + jj * zmat_dim1];\n                }\n                sumb = zero;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    /* L510: */\n                    sumb += xpt[k + j * xpt_dim1] * xopt[j];\n                }\n                temp = suma * sumb;\n                i__2 = n;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    /* L520: */\n                    w[i__] += temp * xpt[k + i__ * xpt_dim1];\n                }\n            }\n            i__2 = n;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                /* L530: */\n                gopt[i__] += diff * w[i__];\n            }\n\n            /*     Update XOPT, GOPT and KOPT if the new calculated F is less than FOPT. */\n\n            if (f < fopt) {\n                kopt = knew;\n                xoptsq = zero;\n                ih = 0;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    xopt[j] = xnew[j];\n                    /* Computing 2nd power */\n                    d__1 = xopt[j];\n                    xoptsq += d__1 * d__1;\n                    i__1 = j;\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        ++ih;\n                        if (i__ < j) {\n                            gopt[j] += hq[ih] * d__[i__];\n                        }\n                        /* L540: */\n                        gopt[i__] += hq[ih] * d__[j];\n                    }\n                }\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    temp = zero;\n                    i__2 = n;\n                    for (j = 1; j <= i__2; ++j) {\n                        /* L550: */\n                        temp += xpt[k + j * xpt_dim1] * d__[j];\n                    }\n                    temp = pq[k] * temp;\n                    i__2 = n;\n                    for (i__ = 1; i__ <= i__2; ++i__) {\n                        /* L560: */\n                        gopt[i__] += temp * xpt[k + i__ * xpt_dim1];\n                    }\n                }\n            }\n\n            /*     Calculate the parameters of the least Frobenius norm interpolant to */\n            /*     the current data, the gradient of this interpolant at XOPT being put */\n            /*     into VLAG(NPT+I), I=1,2,...,N. */\n\n            if (ntrits > 0) {\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    vlag[k] = fval[k] - fval[kopt];\n                    /* L570: */\n                    w[k] = zero;\n                }\n                i__2 = nptm;\n                for (j = 1; j <= i__2; ++j) {\n                    sum = zero;\n                    i__1 = npt;\n                    for (k = 1; k <= i__1; ++k) {\n                        /* L580: */\n                        sum += zmat[k + j * zmat_dim1] * vlag[k];\n                    }\n                    i__1 = npt;\n                    for (k = 1; k <= i__1; ++k) {\n                        /* L590: */\n                        w[k] += sum * zmat[k + j * zmat_dim1];\n                    }\n                }\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    sum = zero;\n                    i__2 = n;\n                    for (j = 1; j <= i__2; ++j) {\n                        /* L600: */\n                        sum += xpt[k + j * xpt_dim1] * xopt[j];\n                    }\n                    w[k + npt] = w[k];\n                    /* L610: */\n                    w[k] = sum * w[k];\n                }\n                gqsq = zero;\n                gisq = zero;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    sum = zero;\n                    i__2 = npt;\n                    for (k = 1; k <= i__2; ++k) {\n                        /* L620: */\n                        sum = sum + bmat[k + i__ * bmat_dim1] * vlag[k] + xpt[k + i__ \n                            * xpt_dim1] * w[k];\n                    }\n                    if (xopt[i__] == sl[i__]) {\n                        /* Computing MIN */\n                        d__2 = zero, d__3 = gopt[i__];\n                        /* Computing 2nd power */\n                        d__1 = std::min(d__2,d__3);\n                        gqsq += d__1 * d__1;\n                        /* Computing 2nd power */\n                        d__1 = std::min(zero,sum);\n                        gisq += d__1 * d__1;\n                    } else if (xopt[i__] == su[i__]) {\n                        /* Computing MAX */\n                        d__2 = zero, d__3 = gopt[i__];\n                        /* Computing 2nd power */\n                        d__1 = std::max(d__2,d__3);\n                        gqsq += d__1 * d__1;\n                        /* Computing 2nd power */\n                        d__1 = std::max(zero,sum);\n                        gisq += d__1 * d__1;\n                    } else {\n                        /* Computing 2nd power */\n                        d__1 = gopt[i__];\n                        gqsq += d__1 * d__1;\n                        gisq += sum * sum;\n                    }\n                    /* L630: */\n                    vlag[npt + i__] = sum;\n                }\n\n                /*     Test whether to replace the new quadratic model by the least Frobenius */\n                /*     norm interpolant, making the replacement if the test is satisfied. */\n\n                ++itest;\n                if (gqsq < ten * gisq) {\n                    itest = 0;\n                }\n                if (itest >= 3) {\n                    i__1 = std::max(npt,nh);\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        if (i__ <= n) {\n                            gopt[i__] = vlag[npt + i__];\n                        }\n                        if (i__ <= npt) {\n                            pq[i__] = w[npt + i__];\n                        }\n                        if (i__ <= nh) {\n                            hq[i__] = zero;\n                        }\n                        itest = 0;\n                        /* L640: */\n                    }\n                }\n            }\n\n            /*     If a trust region step has provided a sufficient decrease in F, then */\n            /*     branch for another trust region calculation. The case NTRITS=0 occurs */\n            /*     when the new interpolation point was reached by an alternative step. */\n\n            if (ntrits == 0) {\n                goto L60;\n            }\n            if (f <= fopt + tenth * vquad) {\n                goto L60;\n            }\n\n            /*     Alternatively, find out if the interpolation points are close enough */\n            /*       to the best point so far. */\n\n            /* Computing MAX */\n            /* Computing 2nd power */\n            d__3 = two * delta;\n            /* Computing 2nd power */\n            d__4 = ten * rho;\n            d__1 = d__3 * d__3, d__2 = d__4 * d__4;\n            distsq = std::max(d__1,d__2);\nL650:\n            knew = 0;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                sum = zero;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    /* L660: */\n                    /* Computing 2nd power */\n                    d__1 = xpt[k + j * xpt_dim1] - xopt[j];\n                    sum += d__1 * d__1;\n                }\n                if (sum > distsq) {\n                    knew = k;\n                    distsq = sum;\n                }\n                /* L670: */\n            }\n\n            /*     If KNEW is positive, then ALTMOV finds alternative new positions for */\n            /*     the KNEW-th interpolation point within distance ADELT of XOPT. It is */\n            /*     reached via label 90. Otherwise, there is a branch to label 60 for */\n            /*     another trust region iteration, unless the calculations with the */\n            /*     current RHO are complete. */\n\n            if (knew > 0) {\n                dist = std::sqrt(distsq);\n                if (ntrits == -1) {\n                    /* Computing MIN */\n                    d__1 = tenth * delta, d__2 = half * dist;\n                    delta = std::min(d__1,d__2);\n                    if (delta <= rho * 1.5) {\n                        delta = rho;\n                    }\n                }\n                ntrits = 0;\n                /* Computing MAX */\n                /* Computing MIN */\n                d__2 = tenth * dist;\n                d__1 = std::min(d__2,delta);\n                adelt = std::max(d__1,rho);\n                dsq = adelt * adelt;\n                goto L90;\n            }\n            if (ntrits == -1) {\n                goto L680;\n            }\n            if (ratio > zero) {\n                goto L60;\n            }\n            if (std::max(delta,dnorm) > rho) {\n                goto L60;\n            }\n\n            /*     The calculations with the current value of RHO are complete. Pick the */\n            /*       next values of RHO and DELTA. */\n\nL680:\n            if (rho > rhoend) {\n                delta = half * rho;\n                ratio = rho / rhoend;\n                if (ratio <= 16.) {\n                    rho = rhoend;\n                } else if (ratio <= 250.) {\n                    rho = std::sqrt(ratio) * rhoend;\n                } else {\n                    rho = tenth * rho;\n                }\n                delta = std::max(delta,rho);\n                ntrits = 0;\n                nfsav = nf;\n                goto L60;\n            }\n\n            /*     Return from the calculation, after another Newton-Raphson step, if */\n            /*       it is too short to have been tried before. */\n\n            if (ntrits == -1) {\n                goto L360;\n            }\nL720:\n            if (fval[kopt] <= fsave) {\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    /* Computing MIN */\n                    /* Computing MAX */\n                    d__3 = xl[i__], d__4 = xbase[i__] + xopt[i__];\n                    d__1 = std::max(d__3,d__4), d__2 = xu[i__];\n                    x[i__] = std::min(d__1,d__2);\n                    if (xopt[i__] == sl[i__]) {\n                        x[i__] = xl[i__];\n                    }\n                    if (xopt[i__] == su[i__]) {\n                        x[i__] = xu[i__];\n                    }\n                    /* L730: */\n                }\n                f = fval[kopt];\n            }\n\n            return f;\n        } /* bobyqb_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        void altmov_(\n            const integer n,\n            const integer npt,\n            const doublereal *xpt, \n            const doublereal *xopt,\n            const doublereal *bmat,\n            const doublereal *zmat,\n            const integer ndim, \n            const doublereal *sl,\n            const doublereal *su,\n            const integer kopt,\n            const integer knew, \n            const doublereal adelt,\n            doublereal *xnew,\n            doublereal *xalt,\n            doublereal& alpha,\n            doublereal& cauchy,\n            doublereal *glag,\n            doublereal *hcol, \n            doublereal *w\n        ) const\n        {\n            /* System generated locals */\n            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1, \n            zmat_offset, i__1, i__2;\n            doublereal d__1, d__2, d__3, d__4;\n\n\n            /* Local variables */\n            integer i__, j, k;\n            doublereal ha, gw, one, diff, half;\n            integer ilbd, isbd;\n            doublereal slbd;\n            integer iubd;\n            doublereal vlag, subd, temp;\n            integer ksav = 0;\n            doublereal step = 0, zero = 0, curv = 0;\n            integer iflag;\n            doublereal scale = 0, csave = 0, tempa = 0, tempb = 0, tempd = 0, const__ = 0, sumin = 0, \n                       ggfree = 0;\n            integer ibdsav = 0;\n            doublereal dderiv = 0, bigstp = 0, predsq = 0, presav = 0, distsq = 0, stpsav = 0, wfixsq = 0, wsqsav = 0;\n\n\n            /*     The arguments N, NPT, XPT, XOPT, BMAT, ZMAT, NDIM, SL and SU all have */\n            /*       the same meanings as the corresponding arguments of BOBYQB. */\n            /*     KOPT is the index of the optimal interpolation point. */\n            /*     KNEW is the index of the interpolation point that is going to be moved. */\n            /*     ADELT is the current trust region bound. */\n            /*     XNEW will be set to a suitable new position for the interpolation point */\n            /*       XPT(KNEW,.). Specifically, it satisfies the SL, SU and trust region */\n            /*       bounds and it should provide a large denominator in the next call of */\n            /*       UPDATE. The step XNEW-XOPT from XOPT is restricted to moves along the */\n            /*       straight lines through XOPT and another interpolation point. */\n            /*     XALT also provides a large value of the modulus of the KNEW-th Lagrange */\n            /*       function subject to the constraints that have been mentioned, its main */\n            /*       difference from XNEW being that XALT-XOPT is a constrained version of */\n            /*       the Cauchy step within the trust region. An exception is that XALT is */\n            /*       not calculated if all components of GLAG (see below) are zero. */\n            /*     ALPHA will be set to the KNEW-th diagonal element of the H matrix. */\n            /*     CAUCHY will be set to the square of the KNEW-th Lagrange function at */\n            /*       the step XALT-XOPT from XOPT for the vector XALT that is returned, */\n            /*       except that CAUCHY is set to zero if XALT is not calculated. */\n            /*     GLAG is a working space vector of length N for the gradient of the */\n            /*       KNEW-th Lagrange function at XOPT. */\n            /*     HCOL is a working space vector of length NPT for the second derivative */\n            /*       coefficients of the KNEW-th Lagrange function. */\n            /*     W is a working space vector of length 2N that is going to hold the */\n            /*       constrained Cauchy step from XOPT of the Lagrange function, followed */\n            /*       by the downhill version of XALT when the uphill step is calculated. */\n\n            /*     Set the first NPT components of W to the leading elements of the */\n            /*     KNEW-th column of the H matrix. */\n\n            /* Parameter adjustments */\n            zmat_dim1 = npt;\n            zmat_offset = 1 + zmat_dim1;\n            zmat -= zmat_offset;\n            xpt_dim1 = npt;\n            xpt_offset = 1 + xpt_dim1;\n            xpt -= xpt_offset;\n            --xopt;\n            bmat_dim1 = ndim;\n            bmat_offset = 1 + bmat_dim1;\n            bmat -= bmat_offset;\n            --sl;\n            --su;\n            --xnew;\n            --xalt;\n            --glag;\n            --hcol;\n            --w;\n\n            /* Function Body */\n            half = .5;\n            one = 1.;\n            zero = 0.;\n            const__ = one + std::sqrt(2.);\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                /* L10: */\n                hcol[k] = zero;\n            }\n            i__1 = npt - n - 1;\n            for (j = 1; j <= i__1; ++j) {\n                temp = zmat[knew + j * zmat_dim1];\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L20: */\n                    hcol[k] += temp * zmat[k + j * zmat_dim1];\n                }\n            }\n            alpha = hcol[knew];\n            ha = half * alpha;\n\n            /*     Calculate the gradient of the KNEW-th Lagrange function at XOPT. */\n\n            i__2 = n;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                /* L30: */\n                glag[i__] = bmat[knew + i__ * bmat_dim1];\n            }\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                temp = zero;\n                i__1 = n;\n                for (j = 1; j <= i__1; ++j) {\n                    /* L40: */\n                    temp += xpt[k + j * xpt_dim1] * xopt[j];\n                }\n                temp = hcol[k] * temp;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    /* L50: */\n                    glag[i__] += temp * xpt[k + i__ * xpt_dim1];\n                }\n            }\n\n            /*     Search for a large denominator along the straight lines through XOPT */\n            /*     and another interpolation point. SLBD and SUBD will be lower and upper */\n            /*     bounds on the step along each of these lines in turn. PREDSQ will be */\n            /*     set to the square of the predicted denominator for each line. PRESAV */\n            /*     will be set to the largest admissible value of PREDSQ that occurs. */\n\n            presav = zero;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                if (k == kopt) {\n                    goto L80;\n                }\n                dderiv = zero;\n                distsq = zero;\n                i__2 = n;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    temp = xpt[k + i__ * xpt_dim1] - xopt[i__];\n                    dderiv += glag[i__] * temp;\n                    /* L60: */\n                    distsq += temp * temp;\n                }\n                subd = adelt / std::sqrt(distsq);\n                slbd = -subd;\n                ilbd = 0;\n                iubd = 0;\n                sumin = std::min(one,subd);\n\n                /*     Revise SLBD and SUBD if necessary because of the bounds in SL and SU. */\n\n                i__2 = n;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    temp = xpt[k + i__ * xpt_dim1] - xopt[i__];\n                    if (temp > zero) {\n                        if (slbd * temp < sl[i__] - xopt[i__]) {\n                            slbd = (sl[i__] - xopt[i__]) / temp;\n                            ilbd = -i__;\n                        }\n                        if (subd * temp > su[i__] - xopt[i__]) {\n                            /* Computing MAX */\n                            d__1 = sumin, d__2 = (su[i__] - xopt[i__]) / temp;\n                            subd = std::max(d__1,d__2);\n                            iubd = i__;\n                        }\n                    } else if (temp < zero) {\n                        if (slbd * temp > su[i__] - xopt[i__]) {\n                            slbd = (su[i__] - xopt[i__]) / temp;\n                            ilbd = i__;\n                        }\n                        if (subd * temp < sl[i__] - xopt[i__]) {\n                            /* Computing MAX */\n                            d__1 = sumin, d__2 = (sl[i__] - xopt[i__]) / temp;\n                            subd = std::max(d__1,d__2);\n                            iubd = -i__;\n                        }\n                    }\n                    /* L70: */\n                }\n\n                /*     Seek a large modulus of the KNEW-th Lagrange function when the index */\n                /*     of the other interpolation point on the line through XOPT is KNEW. */\n\n                if (k == knew) {\n                    diff = dderiv - one;\n                    step = slbd;\n                    vlag = slbd * (dderiv - slbd * diff);\n                    isbd = ilbd;\n                    temp = subd * (dderiv - subd * diff);\n                    if (std::abs(temp) > std::abs(vlag)) {\n                        step = subd;\n                        vlag = temp;\n                        isbd = iubd;\n                    }\n                    tempd = half * dderiv;\n                    tempa = tempd - diff * slbd;\n                    tempb = tempd - diff * subd;\n                    if (tempa * tempb < zero) {\n                        temp = tempd * tempd / diff;\n                        if (std::abs(temp) > std::abs(vlag)) {\n                            step = tempd / diff;\n                            vlag = temp;\n                            isbd = 0;\n                        }\n                    }\n\n                    /*     Search along each of the other lines through XOPT and another point. */\n\n                } else {\n                    step = slbd;\n                    vlag = slbd * (one - slbd);\n                    isbd = ilbd;\n                    temp = subd * (one - subd);\n                    if (std::abs(temp) > std::abs(vlag)) {\n                        step = subd;\n                        vlag = temp;\n                        isbd = iubd;\n                    }\n                    if (subd > half) {\n                        if (std::abs(vlag) < .25) {\n                            step = half;\n                            vlag = .25;\n                            isbd = 0;\n                        }\n                    }\n                    vlag *= dderiv;\n                }\n\n                /*     Calculate PREDSQ for the current line search and maintain PRESAV. */\n\n                temp = step * (one - step) * distsq;\n                predsq = vlag * vlag * (vlag * vlag + ha * temp * temp);\n                if (predsq > presav) {\n                    presav = predsq;\n                    ksav = k;\n                    stpsav = step;\n                    ibdsav = isbd;\n                }\nL80:\n                ;\n            }\n\n            /*     Construct XNEW in a way that satisfies the bound constraints exactly. */\n\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                temp = xopt[i__] + stpsav * (xpt[ksav + i__ * xpt_dim1] - xopt[i__]);\n                /* L90: */\n                /* Computing MAX */\n                /* Computing MIN */\n                d__3 = su[i__];\n                d__1 = sl[i__], d__2 = std::min(d__3,temp);\n                xnew[i__] = std::max(d__1,d__2);\n            }\n            if (ibdsav < 0) {\n                xnew[-ibdsav] = sl[-ibdsav];\n            }\n            if (ibdsav > 0) {\n                xnew[ibdsav] = su[ibdsav];\n            }\n\n            /*     Prepare for the iterative method that assembles the constrained Cauchy */\n            /*     step in W. The sum of squares of the fixed components of W is formed in */\n            /*     WFIXSQ, and the free components of W are set to BIGSTP. */\n\n            bigstp = adelt + adelt;\n            iflag = 0;\nL100:\n            wfixsq = zero;\n            ggfree = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                w[i__] = zero;\n                /* Computing MIN */\n                d__1 = xopt[i__] - sl[i__], d__2 = glag[i__];\n                tempa = std::min(d__1,d__2);\n                /* Computing MAX */\n                d__1 = xopt[i__] - su[i__], d__2 = glag[i__];\n                tempb = std::max(d__1,d__2);\n                if (tempa > zero || tempb < zero) {\n                    w[i__] = bigstp;\n                    /* Computing 2nd power */\n                    d__1 = glag[i__];\n                    ggfree += d__1 * d__1;\n                }\n                /* L110: */\n            }\n            if (ggfree == zero) {\n                cauchy = zero;\n                goto L200;\n            }\n\n            /*     Investigate whether more components of W can be fixed. */\n\nL120:\n            temp = adelt * adelt - wfixsq;\n            if (temp > zero) {\n                wsqsav = wfixsq;\n                step = std::sqrt(temp / ggfree);\n                ggfree = zero;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    if (w[i__] == bigstp) {\n                        temp = xopt[i__] - step * glag[i__];\n                        if (temp <= sl[i__]) {\n                            w[i__] = sl[i__] - xopt[i__];\n                            /* Computing 2nd power */\n                            d__1 = w[i__];\n                            wfixsq += d__1 * d__1;\n                        } else if (temp >= su[i__]) {\n                            w[i__] = su[i__] - xopt[i__];\n                            /* Computing 2nd power */\n                            d__1 = w[i__];\n                            wfixsq += d__1 * d__1;\n                        } else {\n                            /* Computing 2nd power */\n                            d__1 = glag[i__];\n                            ggfree += d__1 * d__1;\n                        }\n                    }\n                    /* L130: */\n                }\n                if (wfixsq > wsqsav && ggfree > zero) {\n                    goto L120;\n                }\n            }\n\n            /*     Set the remaining free components of W and all components of XALT, */\n            /*     except that W may be scaled later. */\n\n            gw = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (w[i__] == bigstp) {\n                    w[i__] = -step * glag[i__];\n                    /* Computing MAX */\n                    /* Computing MIN */\n                    d__3 = su[i__], d__4 = xopt[i__] + w[i__];\n                    d__1 = sl[i__], d__2 = std::min(d__3,d__4);\n                    xalt[i__] = std::max(d__1,d__2);\n                } else if (w[i__] == zero) {\n                    xalt[i__] = xopt[i__];\n                } else if (glag[i__] > zero) {\n                    xalt[i__] = sl[i__];\n                } else {\n                    xalt[i__] = su[i__];\n                }\n                /* L140: */\n                gw += glag[i__] * w[i__];\n            }\n\n            /*     Set CURV to the curvature of the KNEW-th Lagrange function along W. */\n            /*     Scale W by a factor less than one if that can reduce the modulus of */\n            /*     the Lagrange function at XOPT+W. Set CAUCHY to the final value of */\n            /*     the square of this function. */\n\n            curv = zero;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                temp = zero;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    /* L150: */\n                    temp += xpt[k + j * xpt_dim1] * w[j];\n                }\n                /* L160: */\n                curv += hcol[k] * temp * temp;\n            }\n            if (iflag == 1) {\n                curv = -curv;\n            }\n            if (curv > -gw && curv < -const__ * gw) {\n                scale = -gw / curv;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    temp = xopt[i__] + scale * w[i__];\n                    /* L170: */\n                    /* Computing MAX */\n                    /* Computing MIN */\n                    d__3 = su[i__];\n                    d__1 = sl[i__], d__2 = std::min(d__3,temp);\n                    xalt[i__] = std::max(d__1,d__2);\n                }\n                /* Computing 2nd power */\n                d__1 = half * gw * scale;\n                cauchy = d__1 * d__1;\n            } else {\n                /* Computing 2nd power */\n                d__1 = gw + half * curv;\n                cauchy = d__1 * d__1;\n            }\n\n            /*     If IFLAG is zero, then XALT is calculated as before after reversing */\n            /*     the sign of GLAG. Thus two XALT vectors become available. The one that */\n            /*     is chosen is the one that gives the larger value of CAUCHY. */\n\n            if (iflag == 0) {\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    glag[i__] = -glag[i__];\n                    /* L180: */\n                    w[n + i__] = xalt[i__];\n                }\n                csave = cauchy;\n                iflag = 1;\n                goto L100;\n            }\n            if (csave > cauchy) {\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    /* L190: */\n                    xalt[i__] = w[n + i__];\n                }\n                cauchy = csave;\n            }\nL200:\n            ;\n        } /* altmov_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename funct>\n        void prelim_(\n            const funct& calfun,\n            const integer n,\n            const integer npt,\n            doublereal *x, \n            const doublereal *xl,\n            const doublereal *xu,\n            const doublereal rhobeg,\n            const integer maxfun,\n            doublereal *xbase,\n            doublereal *xpt,\n            doublereal *fval,\n            doublereal *gopt,\n            doublereal *hq,\n            doublereal *pq,\n            doublereal *bmat, \n            doublereal *zmat,\n            const integer ndim,\n            const doublereal *sl,\n            const doublereal *su, \n            integer& nf, \n            integer& kopt\n        ) const\n        {\n            /* System generated locals */\n            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1, \n            zmat_offset, i__1, i__2;\n            doublereal d__1, d__2, d__3, d__4;\n\n\n            /* Local variables */\n            doublereal f;\n            integer i__, j, k, ih, np, nfm;\n            doublereal one;\n            integer nfx = 0, ipt = 0, jpt = 0;\n            doublereal two = 0, fbeg = 0, diff = 0, half = 0, temp = 0, zero = 0, recip = 0, stepa = 0, stepb = 0;\n            integer itemp;\n            doublereal rhosq;\n\n\n\n            /*     The arguments N, NPT, X, XL, XU, RHOBEG, IPRINT and MAXFUN are the */\n            /*       same as the corresponding arguments in SUBROUTINE BOBYQA. */\n            /*     The arguments XBASE, XPT, FVAL, HQ, PQ, BMAT, ZMAT, NDIM, SL and SU */\n            /*       are the same as the corresponding arguments in BOBYQB, the elements */\n            /*       of SL and SU being set in BOBYQA. */\n            /*     GOPT is usually the gradient of the quadratic model at XOPT+XBASE, but */\n            /*       it is set by PRELIM to the gradient of the quadratic model at XBASE. */\n            /*       If XOPT is nonzero, BOBYQB will change it to its usual value later. */\n            /*     NF is maintaned as the number of calls of CALFUN so far. */\n            /*     KOPT will be such that the least calculated value of F so far is at */\n            /*       the point XPT(KOPT,.)+XBASE in the space of the variables. */\n\n            /*     SUBROUTINE PRELIM sets the elements of XBASE, XPT, FVAL, GOPT, HQ, PQ, */\n            /*     BMAT and ZMAT for the first iteration, and it maintains the values of */\n            /*     NF and KOPT. The vector X is also changed by PRELIM. */\n\n            /*     Set some constants. */\n\n            /* Parameter adjustments */\n            zmat_dim1 = npt;\n            zmat_offset = 1 + zmat_dim1;\n            zmat -= zmat_offset;\n            xpt_dim1 = npt;\n            xpt_offset = 1 + xpt_dim1;\n            xpt -= xpt_offset;\n            --x;\n            --xl;\n            --xu;\n            --xbase;\n            --fval;\n            --gopt;\n            --hq;\n            --pq;\n            bmat_dim1 = ndim;\n            bmat_offset = 1 + bmat_dim1;\n            bmat -= bmat_offset;\n            --sl;\n            --su;\n\n            /* Function Body */\n            half = .5;\n            one = 1.;\n            two = 2.;\n            zero = 0.;\n            rhosq = rhobeg * rhobeg;\n            recip = one / rhosq;\n            np = n + 1;\n\n            /*     Set XBASE to the initial vector of variables, and set the initial */\n            /*     elements of XPT, BMAT, HQ, PQ and ZMAT to zero. */\n\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                xbase[j] = x[j];\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L10: */\n                    xpt[k + j * xpt_dim1] = zero;\n                }\n                i__2 = ndim;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    /* L20: */\n                    bmat[i__ + j * bmat_dim1] = zero;\n                }\n            }\n            i__2 = n * np / 2;\n            for (ih = 1; ih <= i__2; ++ih) {\n                /* L30: */\n                hq[ih] = zero;\n            }\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                pq[k] = zero;\n                i__1 = npt - np;\n                for (j = 1; j <= i__1; ++j) {\n                    /* L40: */\n                    zmat[k + j * zmat_dim1] = zero;\n                }\n            }\n\n            /*     Begin the initialization procedure. NF becomes one more than the number */\n            /*     of function values so far. The coordinates of the displacement of the */\n            /*     next initial interpolation point from XBASE are set in XPT(NF+1,.). */\n\n            nf = 0;\nL50:\n            nfm = nf;\n            nfx = nf - n;\n            ++(nf);\n            if (nfm <= n << 1) {\n                if (nfm >= 1 && nfm <= n) {\n                    stepa = rhobeg;\n                    if (su[nfm] == zero) {\n                        stepa = -stepa;\n                    }\n                    xpt[nf + nfm * xpt_dim1] = stepa;\n                } else if (nfm > n) {\n                    stepa = xpt[nf - n + nfx * xpt_dim1];\n                    stepb = -(rhobeg);\n                    if (sl[nfx] == zero) {\n                        /* Computing MIN */\n                        d__1 = two * rhobeg, d__2 = su[nfx];\n                        stepb = std::min(d__1,d__2);\n                    }\n                    if (su[nfx] == zero) {\n                        /* Computing MAX */\n                        d__1 = -two * rhobeg, d__2 = sl[nfx];\n                        stepb = std::max(d__1,d__2);\n                    }\n                    xpt[nf + nfx * xpt_dim1] = stepb;\n                }\n            } else {\n                itemp = (nfm - np) / n;\n                jpt = nfm - itemp * n - n;\n                ipt = jpt + itemp;\n                if (ipt > n) {\n                    itemp = jpt;\n                    jpt = ipt - n;\n                    ipt = itemp;\n                }\n                xpt[nf + ipt * xpt_dim1] = xpt[ipt + 1 + ipt * xpt_dim1];\n                xpt[nf + jpt * xpt_dim1] = xpt[jpt + 1 + jpt * xpt_dim1];\n            }\n\n            /*     Calculate the next value of F. The least function value so far and */\n            /*     its index are required. */\n\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                /* Computing MIN */\n                /* Computing MAX */\n                d__3 = xl[j], d__4 = xbase[j] + xpt[nf + j * xpt_dim1];\n                d__1 = std::max(d__3,d__4), d__2 = xu[j];\n                x[j] = std::min(d__1,d__2);\n                if (xpt[nf + j * xpt_dim1] == sl[j]) {\n                    x[j] = xl[j];\n                }\n                if (xpt[nf + j * xpt_dim1] == su[j]) {\n                    x[j] = xu[j];\n                }\n                /* L60: */\n            }\n            f = calfun(mat(&x[1],n));\n            fval[nf] = f;\n            if (nf == 1) {\n                fbeg = f;\n                kopt = 1;\n            } else if (f < fval[kopt]) {\n                kopt = nf;\n            }\n\n            /*     Set the nonzero initial elements of BMAT and the quadratic model in the */\n            /*     cases when NF is at most 2*N+1. If NF exceeds N+1, then the positions */\n            /*     of the NF-th and (NF-N)-th interpolation points may be switched, in */\n            /*     order that the function value at the first of them contributes to the */\n            /*     off-diagonal second derivative terms of the initial quadratic model. */\n\n            if (nf <= (n << 1) + 1) {\n                if (nf >= 2 && nf <= n + 1) {\n                    gopt[nfm] = (f - fbeg) / stepa;\n                    if (npt < nf + n) {\n                        bmat[nfm * bmat_dim1 + 1] = -one / stepa;\n                        bmat[nf + nfm * bmat_dim1] = one / stepa;\n                        bmat[npt + nfm + nfm * bmat_dim1] = -half * rhosq;\n                    }\n                } else if (nf >= n + 2) {\n                    ih = nfx * (nfx + 1) / 2;\n                    temp = (f - fbeg) / stepb;\n                    diff = stepb - stepa;\n                    hq[ih] = two * (temp - gopt[nfx]) / diff;\n                    gopt[nfx] = (gopt[nfx] * stepb - temp * stepa) / diff;\n                    if (stepa * stepb < zero) {\n                        if (f < fval[nf - n]) {\n                            fval[nf] = fval[nf - n];\n                            fval[nf - n] = f;\n                            if (kopt == nf) {\n                                kopt = nf - n;\n                            }\n                            xpt[nf - n + nfx * xpt_dim1] = stepb;\n                            xpt[nf + nfx * xpt_dim1] = stepa;\n                        }\n                    }\n                    bmat[nfx * bmat_dim1 + 1] = -(stepa + stepb) / (stepa * stepb);\n                    bmat[nf + nfx * bmat_dim1] = -half / xpt[nf - n + nfx * \n                        xpt_dim1];\n                    bmat[nf - n + nfx * bmat_dim1] = -bmat[nfx * bmat_dim1 + 1] - \n                        bmat[nf + nfx * bmat_dim1];\n                    zmat[nfx * zmat_dim1 + 1] = std::sqrt(two) / (stepa * stepb);\n                    zmat[nf + nfx * zmat_dim1] = std::sqrt(half) / rhosq;\n                    zmat[nf - n + nfx * zmat_dim1] = -zmat[nfx * zmat_dim1 + 1] - \n                        zmat[nf + nfx * zmat_dim1];\n                }\n\n                /*     Set the off-diagonal second derivatives of the Lagrange functions and */\n                /*     the initial quadratic model. */\n\n            } else {\n                ih = ipt * (ipt - 1) / 2 + jpt;\n                zmat[nfx * zmat_dim1 + 1] = recip;\n                zmat[nf + nfx * zmat_dim1] = recip;\n                zmat[ipt + 1 + nfx * zmat_dim1] = -recip;\n                zmat[jpt + 1 + nfx * zmat_dim1] = -recip;\n                temp = xpt[nf + ipt * xpt_dim1] * xpt[nf + jpt * xpt_dim1];\n                hq[ih] = (fbeg - fval[ipt + 1] - fval[jpt + 1] + f) / temp;\n            }\n            if (nf < npt && nf < maxfun) {\n                goto L50;\n            }\n\n        } /* prelim_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        template <typename funct>\n        void rescue_ (\n            const funct& calfun,\n            const integer n,\n            const integer npt,\n            const doublereal *xl, \n            const doublereal *xu,\n            const integer maxfun,\n            doublereal *xbase, \n            doublereal *xpt, \n            doublereal *fval,\n            doublereal *xopt,\n            doublereal *gopt,\n            doublereal *hq, \n            doublereal *pq,\n            doublereal *bmat,\n            doublereal *zmat, \n            const integer ndim,\n            doublereal *sl,\n            doublereal *su,\n            integer& nf, \n            const doublereal delta,\n            integer& kopt,\n            doublereal *vlag,\n            doublereal * ptsaux,\n            doublereal *ptsid,\n            doublereal *w\n        ) const\n        {\n            /* System generated locals */\n            integer xpt_dim1, xpt_offset, bmat_dim1, bmat_offset, zmat_dim1, \n            zmat_offset, i__1, i__2, i__3;\n            doublereal d__1, d__2, d__3, d__4;\n\n\n            /* Local variables */\n            doublereal f;\n            integer i__, j, k, ih, jp, ip, iq, np, iw;\n            doublereal xp = 0, xq = 0, den = 0;\n            integer ihp = 0;\n            doublereal one;\n            integer ihq, jpn, kpt;\n            doublereal sum = 0, diff = 0, half = 0, beta = 0;\n            integer kold;\n            doublereal winc;\n            integer nrem, knew;\n            doublereal temp, bsum;\n            integer nptm;\n            doublereal zero = 0, hdiag = 0, fbase = 0, sfrac = 0, denom = 0, vquad = 0, sumpq = 0;\n            doublereal dsqmin, distsq, vlmxsq;\n\n\n\n            /*     The arguments N, NPT, XL, XU, IPRINT, MAXFUN, XBASE, XPT, FVAL, XOPT, */\n            /*       GOPT, HQ, PQ, BMAT, ZMAT, NDIM, SL and SU have the same meanings as */\n            /*       the corresponding arguments of BOBYQB on the entry to RESCUE. */\n            /*     NF is maintained as the number of calls of CALFUN so far, except that */\n            /*       NF is set to -1 if the value of MAXFUN prevents further progress. */\n            /*     KOPT is maintained so that FVAL(KOPT) is the least calculated function */\n            /*       value. Its correct value must be given on entry. It is updated if a */\n            /*       new least function value is found, but the corresponding changes to */\n            /*       XOPT and GOPT have to be made later by the calling program. */\n            /*     DELTA is the current trust region radius. */\n            /*     VLAG is a working space vector that will be used for the values of the */\n            /*       provisional Lagrange functions at each of the interpolation points. */\n            /*       They are part of a product that requires VLAG to be of length NDIM. */\n            /*     PTSAUX is also a working space array. For J=1,2,...,N, PTSAUX(1,J) and */\n            /*       PTSAUX(2,J) specify the two positions of provisional interpolation */\n            /*       points when a nonzero step is taken along e_J (the J-th coordinate */\n            /*       direction) through XBASE+XOPT, as specified below. Usually these */\n            /*       steps have length DELTA, but other lengths are chosen if necessary */\n            /*       in order to satisfy the given bounds on the variables. */\n            /*     PTSID is also a working space array. It has NPT components that denote */\n            /*       provisional new positions of the original interpolation points, in */\n            /*       case changes are needed to restore the linear independence of the */\n            /*       interpolation conditions. The K-th point is a candidate for change */\n            /*       if and only if PTSID(K) is nonzero. In this case let p and q be the */\n            /*       integer parts of PTSID(K) and (PTSID(K)-p) multiplied by N+1. If p */\n            /*       and q are both positive, the step from XBASE+XOPT to the new K-th */\n            /*       interpolation point is PTSAUX(1,p)*e_p + PTSAUX(1,q)*e_q. Otherwise */\n            /*       the step is PTSAUX(1,p)*e_p or PTSAUX(2,q)*e_q in the cases q=0 or */\n            /*       p=0, respectively. */\n            /*     The first NDIM+NPT elements of the array W are used for working space. */\n            /*     The final elements of BMAT and ZMAT are set in a well-conditioned way */\n            /*       to the values that are appropriate for the new interpolation points. */\n            /*     The elements of GOPT, HQ and PQ are also revised to the values that are */\n            /*       appropriate to the final quadratic model. */\n\n            /*     Set some constants. */\n\n            /* Parameter adjustments */\n            zmat_dim1 = npt;\n            zmat_offset = 1 + zmat_dim1;\n            zmat -= zmat_offset;\n            xpt_dim1 = npt;\n            xpt_offset = 1 + xpt_dim1;\n            xpt -= xpt_offset;\n            --xl;\n            --xu;\n            --xbase;\n            --fval;\n            --xopt;\n            --gopt;\n            --hq;\n            --pq;\n            bmat_dim1 = ndim;\n            bmat_offset = 1 + bmat_dim1;\n            bmat -= bmat_offset;\n            --sl;\n            --su;\n            --vlag;\n            ptsaux -= 3;\n            --ptsid;\n            --w;\n\n            /* Function Body */\n            half = .5;\n            one = 1.;\n            zero = 0.;\n            np = n + 1;\n            sfrac = half / (doublereal) np;\n            nptm = npt - np;\n\n            /*     Shift the interpolation points so that XOPT becomes the origin, and set */\n            /*     the elements of ZMAT to zero. The value of SUMPQ is required in the */\n            /*     updating of HQ below. The squares of the distances from XOPT to the */\n            /*     other interpolation points are set at the end of W. Increments of WINC */\n            /*     may be added later to these squares to balance the consideration of */\n            /*     the choice of point that is going to become current. */\n\n            sumpq = zero;\n            winc = zero;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                distsq = zero;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    xpt[k + j * xpt_dim1] -= xopt[j];\n                    /* L10: */\n                    /* Computing 2nd power */\n                    d__1 = xpt[k + j * xpt_dim1];\n                    distsq += d__1 * d__1;\n                }\n                sumpq += pq[k];\n                w[ndim + k] = distsq;\n                winc = std::max(winc,distsq);\n                i__2 = nptm;\n                for (j = 1; j <= i__2; ++j) {\n                    /* L20: */\n                    zmat[k + j * zmat_dim1] = zero;\n                }\n            }\n\n            /*     Update HQ so that HQ and PQ define the second derivatives of the model */\n            /*     after XBASE has been shifted to the trust region centre. */\n\n            ih = 0;\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                w[j] = half * sumpq * xopt[j];\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    /* L30: */\n                    w[j] += pq[k] * xpt[k + j * xpt_dim1];\n                }\n                i__1 = j;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    ++ih;\n                    /* L40: */\n                    hq[ih] = hq[ih] + w[i__] * xopt[j] + w[j] * xopt[i__];\n                }\n            }\n\n            /*     Shift XBASE, SL, SU and XOPT. Set the elements of BMAT to zero, and */\n            /*     also set the elements of PTSAUX. */\n\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                xbase[j] += xopt[j];\n                sl[j] -= xopt[j];\n                su[j] -= xopt[j];\n                xopt[j] = zero;\n                /* Computing MIN */\n                d__1 = delta, d__2 = su[j];\n                ptsaux[(j << 1) + 1] = std::min(d__1,d__2);\n                /* Computing MAX */\n                d__1 = -(delta), d__2 = sl[j];\n                ptsaux[(j << 1) + 2] = std::max(d__1,d__2);\n                if (ptsaux[(j << 1) + 1] + ptsaux[(j << 1) + 2] < zero) {\n                    temp = ptsaux[(j << 1) + 1];\n                    ptsaux[(j << 1) + 1] = ptsaux[(j << 1) + 2];\n                    ptsaux[(j << 1) + 2] = temp;\n                }\n                if ((d__2 = ptsaux[(j << 1) + 2], std::abs(d__2)) < half * (d__1 = ptsaux[(\n                            j << 1) + 1], std::abs(d__1))) {\n                    ptsaux[(j << 1) + 2] = half * ptsaux[(j << 1) + 1];\n                }\n                i__2 = ndim;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    /* L50: */\n                    bmat[i__ + j * bmat_dim1] = zero;\n                }\n            }\n            fbase = fval[kopt];\n\n            /*     Set the identifiers of the artificial interpolation points that are */\n            /*     along a coordinate direction from XOPT, and set the corresponding */\n            /*     nonzero elements of BMAT and ZMAT. */\n\n            ptsid[1] = sfrac;\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                jp = j + 1;\n                jpn = jp + n;\n                ptsid[jp] = (doublereal) j + sfrac;\n                if (jpn <= npt) {\n                    ptsid[jpn] = (doublereal) j / (doublereal) np + sfrac;\n                    temp = one / (ptsaux[(j << 1) + 1] - ptsaux[(j << 1) + 2]);\n                    bmat[jp + j * bmat_dim1] = -temp + one / ptsaux[(j << 1) + 1];\n                    bmat[jpn + j * bmat_dim1] = temp + one / ptsaux[(j << 1) + 2];\n                    bmat[j * bmat_dim1 + 1] = -bmat[jp + j * bmat_dim1] - bmat[jpn + \n                        j * bmat_dim1];\n                    zmat[j * zmat_dim1 + 1] = std::sqrt(2.) / (d__1 = ptsaux[(j << 1) + 1] \n                                                          * ptsaux[(j << 1) + 2], std::abs(d__1));\n                    zmat[jp + j * zmat_dim1] = zmat[j * zmat_dim1 + 1] * ptsaux[(j << \n                                                                                 1) + 2] * temp;\n                    zmat[jpn + j * zmat_dim1] = -zmat[j * zmat_dim1 + 1] * ptsaux[(j \n                                                                                   << 1) + 1] * temp;\n                } else {\n                    bmat[j * bmat_dim1 + 1] = -one / ptsaux[(j << 1) + 1];\n                    bmat[jp + j * bmat_dim1] = one / ptsaux[(j << 1) + 1];\n                    /* Computing 2nd power */\n                    d__1 = ptsaux[(j << 1) + 1];\n                    bmat[j + npt + j * bmat_dim1] = -half * (d__1 * d__1);\n                }\n                /* L60: */\n            }\n\n            /*     Set any remaining identifiers with their nonzero elements of ZMAT. */\n\n            if (npt >= n + np) {\n                i__2 = npt;\n                for (k = np << 1; k <= i__2; ++k) {\n                    iw = (integer) (((doublereal) (k - np) - half) / (doublereal) (n)\n                    );\n                    ip = k - np - iw * n;\n                    iq = ip + iw;\n                    if (iq > n) {\n                        iq -= n;\n                    }\n                    ptsid[k] = (doublereal) ip + (doublereal) iq / (doublereal) np + \n                        sfrac;\n                    temp = one / (ptsaux[(ip << 1) + 1] * ptsaux[(iq << 1) + 1]);\n                    zmat[(k - np) * zmat_dim1 + 1] = temp;\n                    zmat[ip + 1 + (k - np) * zmat_dim1] = -temp;\n                    zmat[iq + 1 + (k - np) * zmat_dim1] = -temp;\n                    /* L70: */\n                    zmat[k + (k - np) * zmat_dim1] = temp;\n                }\n            }\n            nrem = npt;\n            kold = 1;\n            knew = kopt;\n\n            /*     Reorder the provisional points in the way that exchanges PTSID(KOLD) */\n            /*     with PTSID(KNEW). */\n\nL80:\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                temp = bmat[kold + j * bmat_dim1];\n                bmat[kold + j * bmat_dim1] = bmat[knew + j * bmat_dim1];\n                /* L90: */\n                bmat[knew + j * bmat_dim1] = temp;\n            }\n            i__2 = nptm;\n            for (j = 1; j <= i__2; ++j) {\n                temp = zmat[kold + j * zmat_dim1];\n                zmat[kold + j * zmat_dim1] = zmat[knew + j * zmat_dim1];\n                /* L100: */\n                zmat[knew + j * zmat_dim1] = temp;\n            }\n            ptsid[kold] = ptsid[knew];\n            ptsid[knew] = zero;\n            w[ndim + knew] = zero;\n            --nrem;\n            if (knew != kopt) {\n                temp = vlag[kold];\n                vlag[kold] = vlag[knew];\n                vlag[knew] = temp;\n\n                /*     Update the BMAT and ZMAT matrices so that the status of the KNEW-th */\n                /*     interpolation point can be changed from provisional to original. The */\n                /*     branch to label 350 occurs if all the original points are reinstated. */\n                /*     The nonnegative values of W(NDIM+K) are required in the search below. */\n\n                update_(n, npt, &bmat[bmat_offset], &zmat[zmat_offset], ndim, &vlag[1], \n                        beta, denom, knew, &w[1]);\n                if (nrem == 0) {\n                    goto L350;\n                }\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L110: */\n                    w[ndim + k] = (d__1 = w[ndim + k], std::abs(d__1));\n                }\n            }\n\n            /*     Pick the index KNEW of an original interpolation point that has not */\n            /*     yet replaced one of the provisional interpolation points, giving */\n            /*     attention to the closeness to XOPT and to previous tries with KNEW. */\n\nL120:\n            dsqmin = zero;\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                if (w[ndim + k] > zero) {\n                    if (dsqmin == zero || w[ndim + k] < dsqmin) {\n                        knew = k;\n                        dsqmin = w[ndim + k];\n                    }\n                }\n                /* L130: */\n            }\n            if (dsqmin == zero) {\n                goto L260;\n            }\n\n            /*     Form the W-vector of the chosen original interpolation point. */\n\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                /* L140: */\n                w[npt + j] = xpt[knew + j * xpt_dim1];\n            }\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                sum = zero;\n                if (k == kopt) {\n                } else if (ptsid[k] == zero) {\n                    i__1 = n;\n                    for (j = 1; j <= i__1; ++j) {\n                        /* L150: */\n                        sum += w[npt + j] * xpt[k + j * xpt_dim1];\n                    }\n                } else {\n                    ip = (integer) ptsid[k];\n                    if (ip > 0) {\n                        sum = w[npt + ip] * ptsaux[(ip << 1) + 1];\n                    }\n                    iq = (integer) ((doublereal) np * ptsid[k] - (doublereal) (ip * \n                                                                               np));\n                    if (iq > 0) {\n                        iw = 1;\n                        if (ip == 0) {\n                            iw = 2;\n                        }\n                        sum += w[npt + iq] * ptsaux[iw + (iq << 1)];\n                    }\n                }\n                /* L160: */\n                w[k] = half * sum * sum;\n            }\n\n            /*     Calculate VLAG and BETA for the required updating of the H matrix if */\n            /*     XPT(KNEW,.) is reinstated in the set of interpolation points. */\n\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                sum = zero;\n                i__1 = n;\n                for (j = 1; j <= i__1; ++j) {\n                    /* L170: */\n                    sum += bmat[k + j * bmat_dim1] * w[npt + j];\n                }\n                /* L180: */\n                vlag[k] = sum;\n            }\n            beta = zero;\n            i__2 = nptm;\n            for (j = 1; j <= i__2; ++j) {\n                sum = zero;\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    /* L190: */\n                    sum += zmat[k + j * zmat_dim1] * w[k];\n                }\n                beta -= sum * sum;\n                i__1 = npt;\n                for (k = 1; k <= i__1; ++k) {\n                    /* L200: */\n                    vlag[k] += sum * zmat[k + j * zmat_dim1];\n                }\n            }\n            bsum = zero;\n            distsq = zero;\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                sum = zero;\n                i__2 = npt;\n                for (k = 1; k <= i__2; ++k) {\n                    /* L210: */\n                    sum += bmat[k + j * bmat_dim1] * w[k];\n                }\n                jp = j + npt;\n                bsum += sum * w[jp];\n                i__2 = ndim;\n                for (ip = npt + 1; ip <= i__2; ++ip) {\n                    /* L220: */\n                    sum += bmat[ip + j * bmat_dim1] * w[ip];\n                }\n                bsum += sum * w[jp];\n                vlag[jp] = sum;\n                /* L230: */\n                /* Computing 2nd power */\n                d__1 = xpt[knew + j * xpt_dim1];\n                distsq += d__1 * d__1;\n            }\n            beta = half * distsq * distsq + beta - bsum;\n            vlag[kopt] += one;\n\n            /*     KOLD is set to the index of the provisional interpolation point that is */\n            /*     going to be deleted to make way for the KNEW-th original interpolation */\n            /*     point. The choice of KOLD is governed by the avoidance of a small value */\n            /*     of the denominator in the updating calculation of UPDATE. */\n\n            denom = zero;\n            vlmxsq = zero;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                if (ptsid[k] != zero) {\n                    hdiag = zero;\n                    i__2 = nptm;\n                    for (j = 1; j <= i__2; ++j) {\n                        /* L240: */\n                        /* Computing 2nd power */\n                        d__1 = zmat[k + j * zmat_dim1];\n                        hdiag += d__1 * d__1;\n                    }\n                    /* Computing 2nd power */\n                    d__1 = vlag[k];\n                    den = beta * hdiag + d__1 * d__1;\n                    if (den > denom) {\n                        kold = k;\n                        denom = den;\n                    }\n                }\n                /* L250: */\n                /* Computing MAX */\n                /* Computing 2nd power */\n                d__3 = vlag[k];\n                d__1 = vlmxsq, d__2 = d__3 * d__3;\n                vlmxsq = std::max(d__1,d__2);\n            }\n            if (denom <= vlmxsq * .01) {\n                w[ndim + knew] = -w[ndim + knew] - winc;\n                goto L120;\n            }\n            goto L80;\n\n            /*     When label 260 is reached, all the final positions of the interpolation */\n            /*     points have been chosen although any changes have not been included yet */\n            /*     in XPT. Also the final BMAT and ZMAT matrices are complete, but, apart */\n            /*     from the shift of XBASE, the updating of the quadratic model remains to */\n            /*     be done. The following cycle through the new interpolation points begins */\n            /*     by putting the new point in XPT(KPT,.) and by setting PQ(KPT) to zero, */\n            /*     except that a RETURN occurs if MAXFUN prohibits another value of F. */\n\nL260:\n            i__1 = npt;\n            for (kpt = 1; kpt <= i__1; ++kpt) {\n                if (ptsid[kpt] == zero) {\n                    goto L340;\n                }\n                if (nf >= maxfun) {\n                    nf = -1;\n                    goto L350;\n                }\n                ih = 0;\n                i__2 = n;\n                for (j = 1; j <= i__2; ++j) {\n                    w[j] = xpt[kpt + j * xpt_dim1];\n                    xpt[kpt + j * xpt_dim1] = zero;\n                    temp = pq[kpt] * w[j];\n                    i__3 = j;\n                    for (i__ = 1; i__ <= i__3; ++i__) {\n                        ++ih;\n                        /* L270: */\n                        hq[ih] += temp * w[i__];\n                    }\n                }\n                pq[kpt] = zero;\n                ip = (integer) ptsid[kpt];\n                iq = (integer) ((doublereal) np * ptsid[kpt] - (doublereal) (ip * np))\n                    ;\n                if (ip > 0) {\n                    xp = ptsaux[(ip << 1) + 1];\n                    xpt[kpt + ip * xpt_dim1] = xp;\n                }\n                if (iq > 0) {\n                    xq = ptsaux[(iq << 1) + 1];\n                    if (ip == 0) {\n                        xq = ptsaux[(iq << 1) + 2];\n                    }\n                    xpt[kpt + iq * xpt_dim1] = xq;\n                }\n\n                /*     Set VQUAD to the value of the current model at the new point. */\n\n                vquad = fbase;\n                if (ip > 0) {\n                    ihp = (ip + ip * ip) / 2;\n                    vquad += xp * (gopt[ip] + half * xp * hq[ihp]);\n                }\n                if (iq > 0) {\n                    ihq = (iq + iq * iq) / 2;\n                    vquad += xq * (gopt[iq] + half * xq * hq[ihq]);\n                    if (ip > 0) {\n                        iw = std::max(ihp,ihq) - (i__3 = ip - iq, std::abs(i__3));\n                        vquad += xp * xq * hq[iw];\n                    }\n                }\n                i__3 = npt;\n                for (k = 1; k <= i__3; ++k) {\n                    temp = zero;\n                    if (ip > 0) {\n                        temp += xp * xpt[k + ip * xpt_dim1];\n                    }\n                    if (iq > 0) {\n                        temp += xq * xpt[k + iq * xpt_dim1];\n                    }\n                    /* L280: */\n                    vquad += half * pq[k] * temp * temp;\n                }\n\n                /*     Calculate F at the new interpolation point, and set DIFF to the factor */\n                /*     that is going to multiply the KPT-th Lagrange function when the model */\n                /*     is updated to provide interpolation to the new function value. */\n\n                i__3 = n;\n                for (i__ = 1; i__ <= i__3; ++i__) {\n                    /* Computing MIN */\n                    /* Computing MAX */\n                    d__3 = xl[i__], d__4 = xbase[i__] + xpt[kpt + i__ * xpt_dim1];\n                    d__1 = std::max(d__3,d__4), d__2 = xu[i__];\n                    w[i__] = std::min(d__1,d__2);\n                    if (xpt[kpt + i__ * xpt_dim1] == sl[i__]) {\n                        w[i__] = xl[i__];\n                    }\n                    if (xpt[kpt + i__ * xpt_dim1] == su[i__]) {\n                        w[i__] = xu[i__];\n                    }\n                    /* L290: */\n                }\n                ++(nf);\n                f = calfun(mat(&w[1],n));\n                fval[kpt] = f;\n                if (f < fval[kopt]) {\n                    kopt = kpt;\n                }\n                diff = f - vquad;\n\n                /*     Update the quadratic model. The RETURN from the subroutine occurs when */\n                /*     all the new interpolation points are included in the model. */\n\n                i__3 = n;\n                for (i__ = 1; i__ <= i__3; ++i__) {\n                    /* L310: */\n                    gopt[i__] += diff * bmat[kpt + i__ * bmat_dim1];\n                }\n                i__3 = npt;\n                for (k = 1; k <= i__3; ++k) {\n                    sum = zero;\n                    i__2 = nptm;\n                    for (j = 1; j <= i__2; ++j) {\n                        /* L320: */\n                        sum += zmat[k + j * zmat_dim1] * zmat[kpt + j * zmat_dim1];\n                    }\n                    temp = diff * sum;\n                    if (ptsid[k] == zero) {\n                        pq[k] += temp;\n                    } else {\n                        ip = (integer) ptsid[k];\n                        iq = (integer) ((doublereal) np * ptsid[k] - (doublereal) (ip \n                                                                                   * np));\n                        ihq = (iq * iq + iq) / 2;\n                        if (ip == 0) {\n                            /* Computing 2nd power */\n                            d__1 = ptsaux[(iq << 1) + 2];\n                            hq[ihq] += temp * (d__1 * d__1);\n                        } else {\n                            ihp = (ip * ip + ip) / 2;\n                            /* Computing 2nd power */\n                            d__1 = ptsaux[(ip << 1) + 1];\n                            hq[ihp] += temp * (d__1 * d__1);\n                            if (iq > 0) {\n                                /* Computing 2nd power */\n                                d__1 = ptsaux[(iq << 1) + 1];\n                                hq[ihq] += temp * (d__1 * d__1);\n                                iw = std::max(ihp,ihq) - (i__2 = iq - ip, std::abs(i__2));\n                                hq[iw] += temp * ptsaux[(ip << 1) + 1] * ptsaux[(iq <<\n                                                                                 1) + 1];\n                            }\n                        }\n                    }\n                    /* L330: */\n                }\n                ptsid[kpt] = zero;\nL340:\n                ;\n            }\nL350:\n            ;\n        } /* rescue_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        void trsbox_(\n            const integer n,\n            const integer npt,\n            const doublereal *xpt, \n            const doublereal *xopt,\n            const doublereal *gopt,\n            const doublereal *hq,\n            const doublereal *pq, \n            const doublereal *sl,\n            const doublereal *su,\n            const doublereal delta,\n            doublereal *xnew, \n            doublereal *d__,\n            doublereal *gnew,\n            doublereal *xbdi,\n            doublereal *s, \n            doublereal *hs,\n            doublereal *hred,\n            doublereal *dsq,\n            doublereal *crvmin\n        ) const\n        {\n            /* System generated locals */\n            integer xpt_dim1, xpt_offset, i__1, i__2;\n            doublereal d__1, d__2, d__3, d__4;\n\n            /* Local variables */\n            integer i__, j, k, ih;\n            doublereal ds;\n            integer iu;\n            doublereal dhd, dhs, cth, one, shs, sth, ssq, half, beta, sdec, blen;\n            integer iact = 0, nact = 0;\n            doublereal angt, qred;\n            integer isav;\n            doublereal temp = 0, zero = 0, xsav = 0, xsum = 0, angbd = 0, dredg = 0, sredg = 0;\n            integer iterc;\n            doublereal resid = 0, delsq = 0, ggsav = 0, tempa = 0, tempb = 0,  \n                       redmax = 0, dredsq = 0, redsav = 0, onemin = 0, gredsq = 0, rednew = 0;\n            integer itcsav = 0;\n            doublereal rdprev = 0, rdnext = 0, stplen = 0, stepsq = 0;\n            integer itermax = 0;\n\n\n            /*     The arguments N, NPT, XPT, XOPT, GOPT, HQ, PQ, SL and SU have the same */\n            /*       meanings as the corresponding arguments of BOBYQB. */\n            /*     DELTA is the trust region radius for the present calculation, which */\n            /*       seeks a small value of the quadratic model within distance DELTA of */\n            /*       XOPT subject to the bounds on the variables. */\n            /*     XNEW will be set to a new vector of variables that is approximately */\n            /*       the one that minimizes the quadratic model within the trust region */\n            /*       subject to the SL and SU constraints on the variables. It satisfies */\n            /*       as equations the bounds that become active during the calculation. */\n            /*     D is the calculated trial step from XOPT, generated iteratively from an */\n            /*       initial value of zero. Thus XNEW is XOPT+D after the final iteration. */\n            /*     GNEW holds the gradient of the quadratic model at XOPT+D. It is updated */\n            /*       when D is updated. */\n            /*     XBDI is a working space vector. For I=1,2,...,N, the element XBDI(I) is */\n            /*       set to -1.0, 0.0, or 1.0, the value being nonzero if and only if the */\n            /*       I-th variable has become fixed at a bound, the bound being SL(I) or */\n            /*       SU(I) in the case XBDI(I)=-1.0 or XBDI(I)=1.0, respectively. This */\n            /*       information is accumulated during the construction of XNEW. */\n            /*     The arrays S, HS and HRED are also used for working space. They hold the */\n            /*       current search direction, and the changes in the gradient of Q along S */\n            /*       and the reduced D, respectively, where the reduced D is the same as D, */\n            /*       except that the components of the fixed variables are zero. */\n            /*     DSQ will be set to the square of the length of XNEW-XOPT. */\n            /*     CRVMIN is set to zero if D reaches the trust region boundary. Otherwise */\n            /*       it is set to the least curvature of H that occurs in the conjugate */\n            /*       gradient searches that are not restricted by any constraints. The */\n            /*       value CRVMIN=-1.0D0 is set, however, if all of these searches are */\n            /*       constrained. */\n\n            /*     A version of the truncated conjugate gradient is applied. If a line */\n            /*     search is restricted by a constraint, then the procedure is restarted, */\n            /*     the values of the variables that are at their bounds being fixed. If */\n            /*     the trust region boundary is reached, then further changes may be made */\n            /*     to D, each one being in the two dimensional space that is spanned */\n            /*     by the current D and the gradient of Q at XOPT+D, staying on the trust */\n            /*     region boundary. Termination occurs when the reduction in Q seems to */\n            /*     be close to the greatest reduction that can be achieved. */\n\n            /*     Set some constants. */\n\n            /* Parameter adjustments */\n            xpt_dim1 = npt;\n            xpt_offset = 1 + xpt_dim1;\n            xpt -= xpt_offset;\n            --xopt;\n            --gopt;\n            --hq;\n            --pq;\n            --sl;\n            --su;\n            --xnew;\n            --d__;\n            --gnew;\n            --xbdi;\n            --s;\n            --hs;\n            --hred;\n\n            /* Function Body */\n            half = .5;\n            one = 1.;\n            onemin = -1.;\n            zero = 0.;\n\n            /*     The sign of GOPT(I) gives the sign of the change to the I-th variable */\n            /*     that will reduce Q from its value at XOPT. Thus XBDI(I) shows whether */\n            /*     or not to fix the I-th variable at one of its bounds initially, with */\n            /*     NACT being set to the number of fixed variables. D and GNEW are also */\n            /*     set for the first iteration. DELSQ is the upper bound on the sum of */\n            /*     squares of the free variables. QRED is the reduction in Q so far. */\n\n            iterc = 0;\n            nact = 0;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                xbdi[i__] = zero;\n                if (xopt[i__] <= sl[i__]) {\n                    if (gopt[i__] >= zero) {\n                        xbdi[i__] = onemin;\n                    }\n                } else if (xopt[i__] >= su[i__]) {\n                    if (gopt[i__] <= zero) {\n                        xbdi[i__] = one;\n                    }\n                }\n                if (xbdi[i__] != zero) {\n                    ++nact;\n                }\n                d__[i__] = zero;\n                /* L10: */\n                gnew[i__] = gopt[i__];\n            }\n            delsq = delta * delta;\n            qred = zero;\n            *crvmin = onemin;\n\n            /*     Set the next search direction of the conjugate gradient method. It is */\n            /*     the steepest descent direction initially and when the iterations are */\n            /*     restarted because a variable has just been fixed by a bound, and of */\n            /*     course the components of the fixed variables are zero. ITERMAX is an */\n            /*     upper bound on the indices of the conjugate gradient iterations. */\n\nL20:\n            beta = zero;\nL30:\n            stepsq = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] != zero) {\n                    s[i__] = zero;\n                } else if (beta == zero) {\n                    s[i__] = -gnew[i__];\n                } else {\n                    s[i__] = beta * s[i__] - gnew[i__];\n                }\n                /* L40: */\n                /* Computing 2nd power */\n                d__1 = s[i__];\n                stepsq += d__1 * d__1;\n            }\n            if (stepsq == zero) {\n                goto L190;\n            }\n            if (beta == zero) {\n                gredsq = stepsq;\n                itermax = iterc + n - nact;\n            }\n            if (gredsq * delsq <= qred * 1e-4 * qred) {\n                goto L190;\n            }\n\n            /*     Multiply the search direction by the second derivative matrix of Q and */\n            /*     calculate some scalars for the choice of steplength. Then set BLEN to */\n            /*     the length of the the step to the trust region boundary and STPLEN to */\n            /*     the steplength, ignoring the simple bounds. */\n\n            goto L210;\nL50:\n            resid = delsq;\n            ds = zero;\n            shs = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] == zero) {\n                    /* Computing 2nd power */\n                    d__1 = d__[i__];\n                    resid -= d__1 * d__1;\n                    ds += s[i__] * d__[i__];\n                    shs += s[i__] * hs[i__];\n                }\n                /* L60: */\n            }\n            if (resid <= zero) {\n                goto L90;\n            }\n            temp = std::sqrt(stepsq * resid + ds * ds);\n            if (ds < zero) {\n                blen = (temp - ds) / stepsq;\n            } else {\n                blen = resid / (temp + ds);\n            }\n            stplen = blen;\n            if (shs > zero) {\n                /* Computing MIN */\n                d__1 = blen, d__2 = gredsq / shs;\n                stplen = std::min(d__1,d__2);\n            }\n\n            /*     Reduce STPLEN if necessary in order to preserve the simple bounds, */\n            /*     letting IACT be the index of the new constrained variable. */\n\n            iact = 0;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (s[i__] != zero) {\n                    xsum = xopt[i__] + d__[i__];\n                    if (s[i__] > zero) {\n                        temp = (su[i__] - xsum) / s[i__];\n                    } else {\n                        temp = (sl[i__] - xsum) / s[i__];\n                    }\n                    if (temp < stplen) {\n                        stplen = temp;\n                        iact = i__;\n                    }\n                }\n                /* L70: */\n            }\n\n            /*     Update CRVMIN, GNEW and D. Set SDEC to the decrease that occurs in Q. */\n\n            sdec = zero;\n            if (stplen > zero) {\n                ++iterc;\n                temp = shs / stepsq;\n                if (iact == 0 && temp > zero) {\n                    *crvmin = std::min(*crvmin,temp);\n                    if (*crvmin == onemin) {\n                        *crvmin = temp;\n                    }\n                }\n                ggsav = gredsq;\n                gredsq = zero;\n                i__1 = n;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    gnew[i__] += stplen * hs[i__];\n                    if (xbdi[i__] == zero) {\n                        /* Computing 2nd power */\n                        d__1 = gnew[i__];\n                        gredsq += d__1 * d__1;\n                    }\n                    /* L80: */\n                    d__[i__] += stplen * s[i__];\n                }\n                /* Computing MAX */\n                d__1 = stplen * (ggsav - half * stplen * shs);\n                sdec = std::max(d__1,zero);\n                qred += sdec;\n            }\n\n            /*     Restart the conjugate gradient method if it has hit a new bound. */\n\n            if (iact > 0) {\n                ++nact;\n                xbdi[iact] = one;\n                if (s[iact] < zero) {\n                    xbdi[iact] = onemin;\n                }\n                /* Computing 2nd power */\n                d__1 = d__[iact];\n                delsq -= d__1 * d__1;\n                if (delsq <= zero) {\n                    goto L90;\n                }\n                goto L20;\n            }\n\n            /*     If STPLEN is less than BLEN, then either apply another conjugate */\n            /*     gradient iteration or RETURN. */\n\n            if (stplen < blen) {\n                if (iterc == itermax) {\n                    goto L190;\n                }\n                if (sdec <= qred * .01) {\n                    goto L190;\n                }\n                beta = gredsq / ggsav;\n                goto L30;\n            }\nL90:\n            *crvmin = zero;\n\n            /*     Prepare for the alternative iteration by calculating some scalars */\n            /*     and by multiplying the reduced D by the second derivative matrix of */\n            /*     Q, where S holds the reduced D in the call of GGMULT. */\n\nL100:\n            if (nact >= n - 1) {\n                goto L190;\n            }\n            dredsq = zero;\n            dredg = zero;\n            gredsq = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] == zero) {\n                    /* Computing 2nd power */\n                    d__1 = d__[i__];\n                    dredsq += d__1 * d__1;\n                    dredg += d__[i__] * gnew[i__];\n                    /* Computing 2nd power */\n                    d__1 = gnew[i__];\n                    gredsq += d__1 * d__1;\n                    s[i__] = d__[i__];\n                } else {\n                    s[i__] = zero;\n                }\n                /* L110: */\n            }\n            itcsav = iterc;\n            goto L210;\n\n            /*     Let the search direction S be a linear combination of the reduced D */\n            /*     and the reduced G that is orthogonal to the reduced D. */\n\nL120:\n            ++iterc;\n            temp = gredsq * dredsq - dredg * dredg;\n            if (temp <= qred * 1e-4 * qred) {\n                goto L190;\n            }\n            temp = std::sqrt(temp);\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] == zero) {\n                    s[i__] = (dredg * d__[i__] - dredsq * gnew[i__]) / temp;\n                } else {\n                    s[i__] = zero;\n                }\n                /* L130: */\n            }\n            sredg = -temp;\n\n            /*     By considering the simple bounds on the variables, calculate an upper */\n            /*     bound on the tangent of half the angle of the alternative iteration, */\n            /*     namely ANGBD, except that, if already a free variable has reached a */\n            /*     bound, there is a branch back to label 100 after fixing that variable. */\n\n            angbd = one;\n            iact = 0;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] == zero) {\n                    tempa = xopt[i__] + d__[i__] - sl[i__];\n                    tempb = su[i__] - xopt[i__] - d__[i__];\n                    if (tempa <= zero) {\n                        ++nact;\n                        xbdi[i__] = onemin;\n                        goto L100;\n                    } else if (tempb <= zero) {\n                        ++nact;\n                        xbdi[i__] = one;\n                        goto L100;\n                    }\n                    /* Computing 2nd power */\n                    d__1 = d__[i__];\n                    /* Computing 2nd power */\n                    d__2 = s[i__];\n                    ssq = d__1 * d__1 + d__2 * d__2;\n                    /* Computing 2nd power */\n                    d__1 = xopt[i__] - sl[i__];\n                    temp = ssq - d__1 * d__1;\n                    if (temp > zero) {\n                        temp = std::sqrt(temp) - s[i__];\n                        if (angbd * temp > tempa) {\n                            angbd = tempa / temp;\n                            iact = i__;\n                            xsav = onemin;\n                        }\n                    }\n                    /* Computing 2nd power */\n                    d__1 = su[i__] - xopt[i__];\n                    temp = ssq - d__1 * d__1;\n                    if (temp > zero) {\n                        temp = std::sqrt(temp) + s[i__];\n                        if (angbd * temp > tempb) {\n                            angbd = tempb / temp;\n                            iact = i__;\n                            xsav = one;\n                        }\n                    }\n                }\n                /* L140: */\n            }\n\n            /*     Calculate HHD and some curvatures for the alternative iteration. */\n\n            goto L210;\nL150:\n            shs = zero;\n            dhs = zero;\n            dhd = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                if (xbdi[i__] == zero) {\n                    shs += s[i__] * hs[i__];\n                    dhs += d__[i__] * hs[i__];\n                    dhd += d__[i__] * hred[i__];\n                }\n                /* L160: */\n            }\n\n            /*     Seek the greatest reduction in Q for a range of equally spaced values */\n            /*     of ANGT in [0,ANGBD], where ANGT is the tangent of half the angle of */\n            /*     the alternative iteration. */\n\n            redmax = zero;\n            isav = 0;\n            redsav = zero;\n            iu = (integer) (angbd * 17. + 3.1);\n            i__1 = iu;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                angt = angbd * (doublereal) i__ / (doublereal) iu;\n                sth = (angt + angt) / (one + angt * angt);\n                temp = shs + angt * (angt * dhd - dhs - dhs);\n                rednew = sth * (angt * dredg - sredg - half * sth * temp);\n                if (rednew > redmax) {\n                    redmax = rednew;\n                    isav = i__;\n                    rdprev = redsav;\n                } else if (i__ == isav + 1) {\n                    rdnext = rednew;\n                }\n                /* L170: */\n                redsav = rednew;\n            }\n\n            /*     Return if the reduction is zero. Otherwise, set the sine and cosine */\n            /*     of the angle of the alternative iteration, and calculate SDEC. */\n\n            if (isav == 0) {\n                goto L190;\n            }\n            if (isav < iu) {\n                temp = (rdnext - rdprev) / (redmax + redmax - rdprev - rdnext);\n                angt = angbd * ((doublereal) isav + half * temp) / (doublereal) iu;\n            }\n            cth = (one - angt * angt) / (one + angt * angt);\n            sth = (angt + angt) / (one + angt * angt);\n            temp = shs + angt * (angt * dhd - dhs - dhs);\n            sdec = sth * (angt * dredg - sredg - half * sth * temp);\n            if (sdec <= zero) {\n                goto L190;\n            }\n\n            /*     Update GNEW, D and HRED. If the angle of the alternative iteration */\n            /*     is restricted by a bound on a free variable, that variable is fixed */\n            /*     at the bound. */\n\n            dredg = zero;\n            gredsq = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                gnew[i__] = gnew[i__] + (cth - one) * hred[i__] + sth * hs[i__];\n                if (xbdi[i__] == zero) {\n                    d__[i__] = cth * d__[i__] + sth * s[i__];\n                    dredg += d__[i__] * gnew[i__];\n                    /* Computing 2nd power */\n                    d__1 = gnew[i__];\n                    gredsq += d__1 * d__1;\n                }\n                /* L180: */\n                hred[i__] = cth * hred[i__] + sth * hs[i__];\n            }\n            qred += sdec;\n            if (iact > 0 && isav == iu) {\n                ++nact;\n                xbdi[iact] = xsav;\n                goto L100;\n            }\n\n            /*     If SDEC is sufficiently small, then RETURN after setting XNEW to */\n            /*     XOPT+D, giving careful attention to the bounds. */\n\n            if (sdec > qred * .01) {\n                goto L120;\n            }\nL190:\n            *dsq = zero;\n            i__1 = n;\n            for (i__ = 1; i__ <= i__1; ++i__) {\n                /* Computing MAX */\n                /* Computing MIN */\n                d__3 = xopt[i__] + d__[i__], d__4 = su[i__];\n                d__1 = std::min(d__3,d__4), d__2 = sl[i__];\n                xnew[i__] = std::max(d__1,d__2);\n                if (xbdi[i__] == onemin) {\n                    xnew[i__] = sl[i__];\n                }\n                if (xbdi[i__] == one) {\n                    xnew[i__] = su[i__];\n                }\n                d__[i__] = xnew[i__] - xopt[i__];\n                /* L200: */\n                /* Computing 2nd power */\n                d__1 = d__[i__];\n                *dsq += d__1 * d__1;\n            }\n            return;\n            /*     The following instructions multiply the current S-vector by the second */\n            /*     derivative matrix of the quadratic model, putting the product in HS. */\n            /*     They are reached from three different parts of the software above and */\n            /*     they can be regarded as an external subroutine. */\n\nL210:\n            ih = 0;\n            i__1 = n;\n            for (j = 1; j <= i__1; ++j) {\n                hs[j] = zero;\n                i__2 = j;\n                for (i__ = 1; i__ <= i__2; ++i__) {\n                    ++ih;\n                    if (i__ < j) {\n                        hs[j] += hq[ih] * s[i__];\n                    }\n                    /* L220: */\n                    hs[i__] += hq[ih] * s[j];\n                }\n            }\n            i__2 = npt;\n            for (k = 1; k <= i__2; ++k) {\n                if (pq[k] != zero) {\n                    temp = zero;\n                    i__1 = n;\n                    for (j = 1; j <= i__1; ++j) {\n                        /* L230: */\n                        temp += xpt[k + j * xpt_dim1] * s[j];\n                    }\n                    temp *= pq[k];\n                    i__1 = n;\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        /* L240: */\n                        hs[i__] += temp * xpt[k + i__ * xpt_dim1];\n                    }\n                }\n                /* L250: */\n            }\n            if (*crvmin != zero) {\n                goto L50;\n            }\n            if (iterc > itcsav) {\n                goto L150;\n            }\n            i__2 = n;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                /* L260: */\n                hred[i__] = hs[i__];\n            }\n            goto L120;\n        } /* trsbox_ */\n\n    // ----------------------------------------------------------------------------------------\n\n        void update_(\n            const integer n,\n            const integer npt,\n            doublereal *bmat, \n            doublereal *zmat,\n            const integer ndim,\n            doublereal *vlag,\n            const doublereal beta, \n            const doublereal denom,\n            const integer knew,\n            doublereal *w\n        ) const\n        {\n            /* System generated locals */\n            integer bmat_dim1, bmat_offset, zmat_dim1, zmat_offset, i__1, i__2;\n            doublereal d__1, d__2, d__3;\n\n            /* Local variables */\n            integer i__, j, k, jp;\n            doublereal one, tau, temp;\n            integer nptm;\n            doublereal zero, alpha, tempa, tempb, ztest;\n\n\n            /*     The arrays BMAT and ZMAT are updated, as required by the new position */\n            /*     of the interpolation point that has the index KNEW. The vector VLAG has */\n            /*     N+NPT components, set on entry to the first NPT and last N components */\n            /*     of the product Hw in equation (4.11) of the Powell (2006) paper on */\n            /*     NEWUOA. Further, BETA is set on entry to the value of the parameter */\n            /*     with that name, and DENOM is set to the denominator of the updating */\n            /*     formula. Elements of ZMAT may be treated as zero if their moduli are */\n            /*     at most ZTEST. The first NDIM elements of W are used for working space. */\n\n            /*     Set some constants. */\n\n            /* Parameter adjustments */\n            zmat_dim1 = npt;\n            zmat_offset = 1 + zmat_dim1;\n            zmat -= zmat_offset;\n            bmat_dim1 = ndim;\n            bmat_offset = 1 + bmat_dim1;\n            bmat -= bmat_offset;\n            --vlag;\n            --w;\n\n            /* Function Body */\n            one = 1.;\n            zero = 0.;\n            nptm = npt - n - 1;\n            ztest = zero;\n            i__1 = npt;\n            for (k = 1; k <= i__1; ++k) {\n                i__2 = nptm;\n                for (j = 1; j <= i__2; ++j) {\n                    /* L10: */\n                    /* Computing MAX */\n                    d__2 = ztest, d__3 = (d__1 = zmat[k + j * zmat_dim1], std::abs(d__1));\n                    ztest = std::max(d__2,d__3);\n                }\n            }\n            ztest *= 1e-20;\n\n            /*     Apply the rotations that put zeros in the KNEW-th row of ZMAT. */\n\n            i__2 = nptm;\n            for (j = 2; j <= i__2; ++j) {\n                if ((d__1 = zmat[knew + j * zmat_dim1], std::abs(d__1)) > ztest) {\n                    /* Computing 2nd power */\n                    d__1 = zmat[knew + zmat_dim1];\n                    /* Computing 2nd power */\n                    d__2 = zmat[knew + j * zmat_dim1];\n                    temp = std::sqrt(d__1 * d__1 + d__2 * d__2);\n                    tempa = zmat[knew + zmat_dim1] / temp;\n                    tempb = zmat[knew + j * zmat_dim1] / temp;\n                    i__1 = npt;\n                    for (i__ = 1; i__ <= i__1; ++i__) {\n                        temp = tempa * zmat[i__ + zmat_dim1] + tempb * zmat[i__ + j * \n                            zmat_dim1];\n                        zmat[i__ + j * zmat_dim1] = tempa * zmat[i__ + j * zmat_dim1] \n                            - tempb * zmat[i__ + zmat_dim1];\n                        /* L20: */\n                        zmat[i__ + zmat_dim1] = temp;\n                    }\n                }\n                zmat[knew + j * zmat_dim1] = zero;\n                /* L30: */\n            }\n\n            /*     Put the first NPT components of the KNEW-th column of HLAG into W, */\n            /*     and calculate the parameters of the updating formula. */\n\n            i__2 = npt;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                w[i__] = zmat[knew + zmat_dim1] * zmat[i__ + zmat_dim1];\n                /* L40: */\n            }\n            alpha = w[knew];\n            tau = vlag[knew];\n            vlag[knew] -= one;\n\n            /*     Complete the updating of ZMAT. */\n\n            temp = std::sqrt(denom);\n            tempb = zmat[knew + zmat_dim1] / temp;\n            tempa = tau / temp;\n            i__2 = npt;\n            for (i__ = 1; i__ <= i__2; ++i__) {\n                /* L50: */\n                zmat[i__ + zmat_dim1] = tempa * zmat[i__ + zmat_dim1] - tempb * vlag[\n                    i__];\n            }\n\n            /*     Finally, update the matrix BMAT. */\n\n            i__2 = n;\n            for (j = 1; j <= i__2; ++j) {\n                jp = npt + j;\n                w[jp] = bmat[knew + j * bmat_dim1];\n                tempa = (alpha * vlag[jp] - tau * w[jp]) / denom;\n                tempb = (-(beta) * w[jp] - tau * vlag[jp]) / denom;\n                i__1 = jp;\n                for (i__ = 1; i__ <= i__1; ++i__) {\n                    bmat[i__ + j * bmat_dim1] = bmat[i__ + j * bmat_dim1] + tempa * \n                        vlag[i__] + tempb * w[i__];\n                    if (i__ > npt) {\n                        bmat[jp + (i__ - npt) * bmat_dim1] = bmat[i__ + j * \n                            bmat_dim1];\n                    }\n                    /* L60: */\n                }\n            }\n        } /* update_ */\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct,\n        typename T, \n        typename U\n        >\n    double find_min_bobyqa (\n        const funct& f,\n        T& x,\n        long npt,\n        const U& x_lower,\n        const U& x_upper,\n        const double rho_begin,\n        const double rho_end,\n        const long max_f_evals\n    ) \n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        // check the requirements.  Also split the assert up so that the error message isn't huge.\n        DLIB_CASSERT(is_col_vector(x) && is_col_vector(x_lower) && is_col_vector(x_upper) &&\n                    x.size() == x_lower.size() && x_lower.size() == x_upper.size() &&\n                    x.size() > 1 && max_f_evals > 1,\n            \"\\tdouble find_min_bobyqa()\"\n            << \"\\n\\t Invalid arguments have been given to this function\"\n            << \"\\n\\t is_col_vector(x):       \" << is_col_vector(x) \n            << \"\\n\\t is_col_vector(x_lower): \" << is_col_vector(x_lower) \n            << \"\\n\\t is_col_vector(x_upper): \" << is_col_vector(x_upper) \n            << \"\\n\\t x.size():               \" << x.size()\n            << \"\\n\\t x_lower.size():         \" << x_lower.size()\n            << \"\\n\\t x_upper.size():         \" << x_upper.size()\n            << \"\\n\\t max_f_evals:            \" << max_f_evals\n        );\n\n        DLIB_CASSERT(x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2 &&\n                    0 < rho_end && rho_end < rho_begin &&\n                    min(x_upper - x_lower) > 2*rho_begin &&\n                    min(x - x_lower) >= 0 && min(x_upper - x) >= 0,\n            \"\\tdouble find_min_bobyqa()\"\n            << \"\\n\\t Invalid arguments have been given to this function\"\n            << \"\\n\\t ntp in valid range: \" << (x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2)\n            << \"\\n\\t npt:                \" << npt \n            << \"\\n\\t rho_begin:          \" << rho_begin \n            << \"\\n\\t rho_end:            \" << rho_end\n            << \"\\n\\t min(x_upper - x_lower) > 2*rho_begin:           \" << (min(x_upper - x_lower) > 2*rho_begin)\n            << \"\\n\\t min(x - x_lower) >= 0 && min(x_upper - x) >= 0: \" << (min(x - x_lower) >= 0 && min(x_upper - x) >= 0)\n        );\n\n\n        bobyqa_implementation impl;\n        return impl.find_min(f, x, npt, x_lower, x_upper, rho_begin, rho_end, max_f_evals);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct,\n        typename T, \n        typename U\n        >\n    double find_max_bobyqa (\n        const funct& f,\n        T& x,\n        long npt,\n        const U& x_lower,\n        const U& x_upper,\n        const double rho_begin,\n        const double rho_end,\n        const long max_f_evals\n    ) \n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        return -find_min_bobyqa(negate_function(f), x, npt, x_lower, x_upper, rho_begin, rho_end, max_f_evals);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_BOBYQA_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_bobyqa_abstract.h",
    "content": "// Copyright (C) 2009  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_\n#ifdef DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n\n// ----------------------------------------------------------------------------------------\n\n/*\n    This file defines the dlib interface to the BOBYQA software developed by M.J.D Powell.\n    BOBYQA is a method for optimizing a function in the absence of derivative information.  \n    Powell described it as a method that seeks the least value of a function of many \n    variables, by applying a trust region method that forms quadratic models by \n    interpolation.  There is usually some freedom in the interpolation conditions, \n    which is taken up by minimizing the Frobenius norm of the change to the second \n    derivative of the model, beginning with the zero matrix. The values of the variables \n    are constrained by upper and lower bounds.  \n\n\n    The following paper, published in 2009 by Powell, describes the\n    detailed working of the BOBYQA algorithm.  \n\n        The BOBYQA algorithm for bound constrained optimization \n        without derivatives by M.J.D. Powell\n*/\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    class bobyqa_failure : public error;\n    /*!\n        This is the exception class used by the functions defined in this file.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct,\n        typename T, \n        typename U\n        >\n    double find_min_bobyqa (\n        const funct& f,\n        T& x,\n        long npt,\n        const U& x_lower,\n        const U& x_upper,\n        const double rho_begin,\n        const double rho_end,\n        const long max_f_evals\n    );\n    /*!\n        requires\n            - f(x) must be a valid expression that evaluates to a double\n            - is_col_vector(x) == true\n            - is_col_vector(x_lower) == true\n            - is_col_vector(x_upper) == true\n            - x.size() == x_lower.size() == x_upper.size()\n            - x.size() > 1\n            - x.size() + 2 <= npt <= (x.size()+1)*(x.size()+2)/2\n            - 0 < rho_end < rho_begin\n            - min(x_upper - x_lower) > 2*rho_begin\n              (i.e. the lower and upper bounds on each x element must be larger than 2*rho_begin)\n            - min(x - x_lower) >= 0 && min(x_upper - x) >= 0\n              (i.e. the given x should be within the bounds defined by x_lower and x_upper)\n            - max_f_evals > 1\n        ensures\n            - Performs a constrained minimization of the function f() starting from \n              the initial point x.  \n            - The BOBYQA algorithm uses a number of interpolating points to perform its\n              work.  The npt argument controls how many points get used.  Typically,\n              a good value to use is 2*x.size()+1.\n            - #x == the value of x (within the bounds defined by x_lower and x_upper) that \n              was found to minimize f().  More precisely:\n                - min(#x - x_lower) >= 0 && min(x_upper - #x) >= 0\n            - returns f(#x). \n            - rho_begin and rho_end are used as the initial and final values of a trust \n              region radius.  Typically, rho_begin should be about one tenth of the greatest \n              expected change to a variable, while rho_end should indicate the accuracy that \n              is required in the final values of the variables. \n        throws\n            - bobyqa_failure\n                This exception is thrown if the algorithm is unable to make progress towards\n                solving the problem.  This may occur because the algorithm detects excessive\n                numerical errors or because max_f_evals of f() have occurred without reaching\n                convergence.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct,\n        typename T, \n        typename U\n        >\n    double find_max_bobyqa (\n        const funct& f,\n        T& x,\n        long npt,\n        const U& x_lower,\n        const U& x_upper,\n        const double rho_begin,\n        const double rho_end,\n        const long max_f_evals\n    );\n    /*!\n        This function is identical to the find_min_bobyqa() routine defined above\n        except that it negates the f() function before performing optimization.  \n        Thus this function will attempt to find the maximizer of f() rather than \n        the minimizer.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_BOBYQA_ABSTRACT_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_least_squares.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_\n#define DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_\n\n#include \"../matrix.h\"\n#include \"optimization_trust_region.h\"\n#include \"optimization_least_squares_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename column_vector_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type\n        >\n    class least_squares_function_model \n    {\n    public:\n        least_squares_function_model (\n            const funct_type& f_,\n            const funct_der_type& der_,\n            const vector_type& list_\n        ) : f(f_), der(der_), list(list_) \n        {\n            S = 0;\n            last_f = 0;\n            last_f2 = 0;\n\n            r.set_size(list.size(),1);\n        }\n\n        const funct_type& f;\n        const funct_der_type& der;\n        const vector_type& list;\n\n        typedef typename column_vector_type::type type;\n        typedef typename column_vector_type::mem_manager_type mem_manager_type;\n        typedef typename column_vector_type::layout_type layout_type;\n        const static long NR = column_vector_type::NR;\n\n        typedef column_vector_type column_vector;\n        typedef matrix<type,NR,NR,mem_manager_type,layout_type> general_matrix;\n\n\n        type operator() ( \n            const column_vector& x\n        ) const\n        {\n            type result = 0;\n            for (long i = 0; i < list.size(); ++i)\n            {\n                const type temp = f(list(i), x);\n                // save the residual for later\n                r(i) = temp;\n                result += temp*temp;\n            }\n\n            last_f = 0.5*result;\n            return 0.5*result;\n        }\n\n        void get_derivative_and_hessian (\n            const column_vector& x,\n            column_vector& d,\n            general_matrix& h\n        ) const\n        {\n            J.set_size(list.size(), x.size());\n\n            // compute the Jacobian\n            for (long i = 0; i < list.size(); ++i)\n            {\n                set_rowm(J,i) = trans(der(list(i), x));\n            }\n\n            // Compute the Levenberg-Marquardt gradient and hessian\n            d = trans(J)*r;\n            h = trans(J)*J;\n\n            if (S.size() == 0)\n            {\n                S.set_size(x.size(), x.size());\n                S = 0;\n            }\n\n            // If this isn't the first iteration then check if using\n            // a quasi-newton update helps things.\n            if (last_r.size() != 0)\n            {\n\n                s = x - last_x;\n                y = d - last_d;\n                yy = d - trans(last_J)*r;\n\n                const type ys = trans(y)*s;\n                vtemp = yy - S*s;\n                const type temp2 = std::abs(trans(s)*S*s);\n                type scale = (temp2 != 0) ? std::min<type>(1, std::abs(dot(s,yy))/temp2)  :  1;\n\n                if (ys != 0)\n                    S = scale*S + (vtemp*trans(y) + y*trans(vtemp))/(ys) - dot(vtemp,s)/ys/ys*y*trans(y);\n                else\n                    S *= scale;\n\n                // check how well both the models fit the last change we saw in f()\n                const type measured_delta = last_f2 - last_f;\n                s = -s;\n                const type h_predicted_delta = 0.5*trans(s)*h*s + trans(d)*s;\n                const type s_predicted_delta = 0.5*trans(s)*(h+S)*s + trans(d)*s;\n\n                const type h_error = std::abs((h_predicted_delta/measured_delta) - 1);\n                const type s_error = std::abs((s_predicted_delta/measured_delta) - 1);\n\n                if (s_error < h_error && h_error > 0.01)\n                {\n                    h += make_symmetric(S);\n                }\n                else if (s_error > 10)\n                {\n                    S = 0;\n                }\n\n                // put r into last_r\n                r.swap(last_r);\n            }\n            else\n            {\n                // put r into last_r\n                last_r = r;\n            }\n\n            J.swap(last_J);\n            last_x = x;\n            last_d = d;\n\n            last_f2 = last_f;\n        }\n\n        mutable type last_f;   // value of function we saw in last operator()\n        mutable type last_f2;  // value of last_f we saw in get_derivative_and_hessian()\n        mutable matrix<type,0,1,mem_manager_type,layout_type> r;\n        mutable column_vector vtemp;\n        mutable column_vector s, y, yy;\n\n        mutable general_matrix S;\n        mutable column_vector last_x;\n        mutable column_vector last_d;\n        mutable matrix<type,0,1,mem_manager_type,layout_type> last_r;\n        mutable matrix<type,0,NR,mem_manager_type,layout_type> last_J;\n        mutable matrix<type,0,NR,mem_manager_type,layout_type> J;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename column_vector_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type\n        >\n    least_squares_function_model<column_vector_type,funct_type,funct_der_type,vector_type> least_squares_model (\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list\n    )\n    {\n        return least_squares_function_model<column_vector_type,funct_type,funct_der_type,vector_type>(f,der,list);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type,\n        typename T\n        >\n    double solve_least_squares (\n        stop_strategy_type stop_strategy,\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list,\n        T& x, \n        double radius = 1\n    )\n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_vector(mat(list)) && list.size() > 0 && \n                    is_col_vector(x) && radius > 0,\n            \"\\t double solve_least_squares()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t is_vector(list):  \" << is_vector(mat(list)) \n            << \"\\n\\t list.size():      \" << list.size() \n            << \"\\n\\t is_col_vector(x): \" << is_col_vector(x) \n            << \"\\n\\t radius:           \" << radius\n            );\n\n        return find_min_trust_region(stop_strategy,\n                                     least_squares_model<T>(f, der, mat(list)), \n                                     x, \n                                     radius);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename column_vector_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type\n        >\n    class least_squares_lm_function_model \n    {\n    public:\n        least_squares_lm_function_model (\n            const funct_type& f_,\n            const funct_der_type& der_,\n            const vector_type& list_\n        ) : f(f_), der(der_), list(list_) \n        {\n            r.set_size(list.size(),1);\n        }\n\n        const funct_type& f;\n        const funct_der_type& der;\n        const vector_type& list;\n\n        typedef typename column_vector_type::type type;\n        typedef typename column_vector_type::mem_manager_type mem_manager_type;\n        typedef typename column_vector_type::layout_type layout_type;\n        const static long NR = column_vector_type::NR;\n\n        typedef column_vector_type column_vector;\n        typedef matrix<type,NR,NR,mem_manager_type,layout_type> general_matrix;\n\n        mutable matrix<type,0,1,mem_manager_type,layout_type> r;\n        mutable column_vector vtemp;\n\n        type operator() ( \n            const column_vector& x\n        ) const\n        {\n            type result = 0;\n            for (long i = 0; i < list.size(); ++i)\n            {\n                const type temp = f(list(i), x);\n                // save the residual for later\n                r(i) = temp;\n                result += temp*temp;\n            }\n\n            return 0.5*result;\n        }\n\n        void get_derivative_and_hessian (\n            const column_vector& x,\n            column_vector& d,\n            general_matrix& h\n        ) const\n        {\n            d = 0;\n            h = 0;\n            for (long i = 0; i < list.size(); ++i)\n            {\n                vtemp = der(list(i), x); \n                d += r(i)*vtemp;\n                h += vtemp*trans(vtemp);\n            }\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename column_vector_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type\n        >\n    least_squares_lm_function_model<column_vector_type,funct_type,funct_der_type,vector_type> least_squares_lm_model (\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list\n    )\n    {\n        return least_squares_lm_function_model<column_vector_type,funct_type,funct_der_type,vector_type>(f,der,list);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type,\n        typename T\n        >\n    double solve_least_squares_lm (\n        stop_strategy_type stop_strategy,\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list,\n        T& x, \n        double radius = 1\n    )\n    {\n        // The starting point (i.e. x) must be a column vector.  \n        COMPILE_TIME_ASSERT(T::NC <= 1);\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_vector(mat(list)) && list.size() > 0 && \n                    is_col_vector(x) && radius > 0,\n            \"\\t double solve_least_squares_lm()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t is_vector(list):  \" << is_vector(mat(list)) \n            << \"\\n\\t list.size():      \" << list.size() \n            << \"\\n\\t is_col_vector(x): \" << is_col_vector(x) \n            << \"\\n\\t radius:           \" << radius\n            );\n\n        return find_min_trust_region(stop_strategy,\n                                     least_squares_lm_model<T>(f, der, mat(list)), \n                                     x, \n                                     radius);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_LEAST_SQuARES_H_h_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_least_squares_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_\n#ifdef DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_\n\n#include \"../matrix/matrix_abstract.h\"\n#include \"optimization_trust_region_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type,\n        typename T\n        >\n    double solve_least_squares (\n        stop_strategy_type stop_strategy,\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list,\n        T& x, \n        double radius = 1\n    );\n    /*!\n        requires\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - list == a matrix or something convertible to a matrix via mat()\n              such as a std::vector.\n            - is_vector(list) == true\n            - list.size() > 0\n            - is_col_vector(x) == true\n            - radius > 0\n            - for all valid i:\n                - f(list(i),x) must be a valid expression that evaluates to a floating point value.\n                - der(list(i),x) must be a valid expression that evaluates to the derivative of f(list(i),x) \n                  with respect to x. This derivative must take the form of a column vector.\n        ensures\n            - This function performs an unconstrained minimization of the least squares\n              function g(x) defined by:\n                - g(x) = sum over all i: 0.5*pow( f(list(i),x), 2 )\n            - This method combines the Levenberg-Marquardt method with a quasi-newton method\n              for approximating the second order terms of the hessian and is appropriate for\n              large residual problems (i.e. problems where the f() function isn't driven to 0).  \n              In particular, it uses the method of Dennis, Gay, and Welsch as described in \n              Numerical Optimization by Nocedal and Wright (second edition).\n            - Since this is a trust region algorithm, the radius parameter defines the initial \n              size of the trust region.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or the trust region subproblem fails to make progress.\n            - #x == the value of x that was found to minimize g()\n            - returns g(#x). \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_type,\n        typename funct_der_type,\n        typename vector_type,\n        typename T\n        >\n    double solve_least_squares_lm (\n        stop_strategy_type stop_strategy,\n        const funct_type& f,\n        const funct_der_type& der,\n        const vector_type& list,\n        T& x, \n        double radius = 1\n    );\n    /*!\n        requires\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - list == a matrix or something convertible to a matrix via mat()\n              such as a std::vector.\n            - is_vector(list) == true\n            - list.size() > 0\n            - is_col_vector(x) == true\n            - radius > 0\n            - for all valid i:\n                - f(list(i),x) must be a valid expression that evaluates to a floating point value.\n                - der(list(i),x) must be a valid expression that evaluates to the derivative of f(list(i),x) \n                  with respect to x.  This derivative must take the form of a column vector.\n        ensures\n            - This function performs an unconstrained minimization of the least squares\n              function g(x) defined by:\n                - g(x) = sum over all i: 0.5*pow( f(list(i),x), 2 )\n            - This method implements a plain Levenberg-Marquardt approach for approximating\n              the hessian of g().  Therefore, it is most appropriate for small residual problems\n              (i.e. problems where f() goes to 0 at the solution).\n            - Since this is a trust region algorithm, the radius parameter defines the initial \n              size of the trust region.  \n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or the trust region subproblem fails to make progress.\n            - #x == the value of x that was found to minimize g()\n            - returns g(#x). \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_LEAST_SQUARES_ABSTRACT_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_line_search.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_LINE_SEARCH_H_\n#define DLIB_OPTIMIZATIOn_LINE_SEARCH_H_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n#include \"optimization_line_search_abstract.h\"\n#include <utility>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct, typename T>\n    class line_search_funct \n    {\n    public:\n        line_search_funct(const funct& f_, const T& start_, const T& direction_) \n            : f(f_),start(start_), direction(direction_), matrix_r(0), scalar_r(0)\n        {}\n\n        line_search_funct(const funct& f_, const T& start_, const T& direction_, T& r) \n            : f(f_),start(start_), direction(direction_), matrix_r(&r), scalar_r(0)\n        {}\n\n        line_search_funct(const funct& f_, const T& start_, const T& direction_, double& r) \n            : f(f_),start(start_), direction(direction_), matrix_r(0), scalar_r(&r)\n        {}\n\n        double operator()(const double& x) const\n        {\n            return get_value(f(start + x*direction));\n        }\n\n    private:\n\n        double get_value (const double& r) const\n        {\n            // save a copy of this value for later\n            if (scalar_r)\n                *scalar_r = r;\n\n            return r;\n        }\n\n        template <typename U>\n        double get_value (const U& r) const\n        {\n            // U should be a matrix type\n            COMPILE_TIME_ASSERT(is_matrix<U>::value);\n\n            // save a copy of this value for later\n            if (matrix_r)\n                *matrix_r = r;\n\n            return dot(r,direction);\n        }\n\n        const funct& f;\n        const T& start;\n        const T& direction;\n        T* matrix_r;\n        double* scalar_r;\n    };\n\n    template <typename funct, typename T>\n    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction) \n    { \n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        DLIB_ASSERT (\n            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),\n            \"\\tline_search_funct make_line_search_function(f,start,direction)\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tstart.nc():     \" << start.nc()\n            << \"\\n\\tdirection.nc(): \" << direction.nc()\n            << \"\\n\\tstart.nr():     \" << start.nr()\n            << \"\\n\\tdirection.nr(): \" << direction.nr()\n        );\n        return line_search_funct<funct,T>(f,start,direction); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct, typename T>\n    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction, double& f_out) \n    { \n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        DLIB_ASSERT (\n            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),\n            \"\\tline_search_funct make_line_search_function(f,start,direction)\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tstart.nc():     \" << start.nc()\n            << \"\\n\\tdirection.nc(): \" << direction.nc()\n            << \"\\n\\tstart.nr():     \" << start.nr()\n            << \"\\n\\tdirection.nr(): \" << direction.nr()\n        );\n        return line_search_funct<funct,T>(f,start,direction, f_out); \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct, typename T>\n    const line_search_funct<funct,T> make_line_search_function(const funct& f, const T& start, const T& direction, T& grad_out) \n    { \n        COMPILE_TIME_ASSERT(is_matrix<T>::value);\n        DLIB_ASSERT (\n            is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size(),\n            \"\\tline_search_funct make_line_search_function(f,start,direction)\"\n            << \"\\n\\tYou have to supply column vectors to this function\"\n            << \"\\n\\tstart.nc():     \" << start.nc()\n            << \"\\n\\tdirection.nc(): \" << direction.nc()\n            << \"\\n\\tstart.nr():     \" << start.nr()\n            << \"\\n\\tdirection.nr(): \" << direction.nr()\n        );\n        return line_search_funct<funct,T>(f,start,direction,grad_out); \n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double f1,\n        double d1,\n        double limit = 1\n    )\n    {\n        const double n = 3*(f1 - f0) - 2*d0 - d1;\n        const double e = d0 + d1 - 2*(f1 - f0);\n\n\n        // find the minimum of the derivative of the polynomial\n\n        double temp = std::max(n*n - 3*e*d0,0.0);\n\n        if (temp < 0)\n            return 0.5;\n\n        temp = std::sqrt(temp);\n\n        if (std::abs(e) <= std::numeric_limits<double>::epsilon())\n            return 0.5;\n\n        // figure out the two possible min values\n        double x1 = (temp - n)/(3*e);\n        double x2 = -(temp + n)/(3*e);\n\n        // compute the value of the interpolating polynomial at these two points\n        double y1 = f0 + d0*x1 + n*x1*x1 + e*x1*x1*x1;\n        double y2 = f0 + d0*x2 + n*x2*x2 + e*x2*x2*x2;\n\n        // pick the best point\n        double x;\n        if (y1 < y2)\n            x = x1;\n        else\n            x = x2;\n\n        // now make sure the minimum is within the allowed range of [0,limit] \n        return put_in_range(0,limit,x);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double f1\n    )\n    {\n        const double temp = 2*(f1 - f0 - d0);\n        if (std::abs(temp) <= d0*std::numeric_limits<double>::epsilon())\n            return 0.5;\n\n        const double alpha = -d0/temp;\n\n        // now make sure the minimum is within the allowed range of (0,1) \n        return put_in_range(0,1,alpha);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double x1,\n        double f_x1,\n        double x2,\n        double f_x2\n    )\n    {\n        DLIB_ASSERT(0 < x1 && x1 < x2,\"Invalid inputs were given to this function.\\n\"\n            << \"x1: \" << x1 \n            << \"    x2: \" << x2 \n            );\n        // The contents of this function follow the equations described on page 58 of the\n        // book Numerical Optimization by Nocedal and Wright, second edition.\n        matrix<double,2,2> m;\n        matrix<double,2,1> v;\n\n        const double aa2 = x2*x2;\n        const double aa1 = x1*x1;\n        m =  aa2,       -aa1,\n            -aa2*x2, aa1*x1;   \n        v = f_x1 - f0 - d0*x1,\n            f_x2 - f0 - d0*x2;\n\n\n        double temp = aa2*aa1*(x1-x2);\n\n        // just take a guess if this happens\n        if (temp == 0 || std::fpclassify(temp) == FP_SUBNORMAL)\n        {\n            return x1/2.0;\n        }\n\n        matrix<double,2,1> temp2;\n        temp2 = m*v/temp;\n        const double a = temp2(0);\n        const double b = temp2(1);\n\n        temp = b*b - 3*a*d0;\n        if (temp < 0 || a == 0)\n        {\n            // This is probably a line so just pick the lowest point\n            if (f0 < f_x2)\n                return 0;\n            else\n                return x2;\n        }\n        temp = (-b + std::sqrt(temp))/(3*a);\n        return put_in_range(0, x2, temp);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline double lagrange_poly_min_extrap (\n        double p1, \n        double p2,\n        double p3,\n        double f1,\n        double f2,\n        double f3\n    )\n    {\n        DLIB_ASSERT(p1 < p2 && p2 < p3 && f1 >= f2 && f2 <= f3,\n                     \"   p1: \" << p1 \n                     << \"   p2: \" << p2 \n                     << \"   p3: \" << p3  \n                     << \"   f1: \" << f1 \n                     << \"   f2: \" << f2 \n                     << \"   f3: \" << f3);\n\n        // This formula is out of the book Nonlinear Optimization by Andrzej Ruszczynski.  See section 5.2.\n        double temp1 =    f1*(p3*p3 - p2*p2) + f2*(p1*p1 - p3*p3) + f3*(p2*p2 - p1*p1);\n        double temp2 = 2*(f1*(p3 - p2)       + f2*(p1 - p3)       + f3*(p2 - p1) );\n\n        if (temp2 == 0)\n        {\n            return p2;\n        }\n\n        const double result = temp1/temp2;\n\n        // do a final sanity check to make sure the result is in the right range\n        if (p1 <= result && result <= p3)\n        {\n            return result;\n        }\n        else\n        {\n            return std::min(std::max(p1,result),p3);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct, \n        typename funct_der\n        >\n    double line_search (\n        const funct& f, \n        const double f0,\n        const funct_der& der, \n        const double d0,\n        double rho, \n        double sigma, \n        double min_f,\n        unsigned long max_iter \n    )\n    {\n        DLIB_ASSERT (\n            0 < rho && rho < sigma && sigma < 1 && max_iter > 0,\n            \"\\tdouble line_search()\"\n            << \"\\n\\tYou have given invalid arguments to this function\"\n            << \"\\n\\t sigma:    \" << sigma\n            << \"\\n\\t rho:      \" << rho \n            << \"\\n\\t max_iter: \" << max_iter \n        );\n\n        // The bracketing phase of this function is implemented according to block 2.6.2 from\n        // the book Practical Methods of Optimization by R. Fletcher.   The sectioning \n        // phase is an implementation of 2.6.4 from the same book.\n\n        // 1 <= tau1a < tau1b. Controls the alpha jump size during the bracketing phase of\n        // the search.\n        const double tau1a = 1.4;\n        const double tau1b = 9;\n\n        // it must be the case that 0 < tau2 < tau3 <= 1/2 for the algorithm to function\n        // correctly but the specific values of tau2 and tau3 aren't super important.\n        const double tau2 = 1.0/10.0;\n        const double tau3 = 1.0/2.0;\n\n\n        // Stop right away and return a step size of 0 if the gradient is 0 at the starting point\n        if (std::abs(d0) <= std::abs(f0)*std::numeric_limits<double>::epsilon())\n            return 0;\n\n        // Stop right away if the current value is good enough according to min_f\n        if (f0 <= min_f)\n            return 0;\n\n        // Figure out a reasonable upper bound on how large alpha can get.\n        const double mu = (min_f-f0)/(rho*d0);\n\n\n        double alpha = 1;\n        if (mu < 0)\n            alpha = -alpha;\n        alpha = put_in_range(0, 0.65*mu, alpha);\n\n\n        double last_alpha = 0;\n        double last_val = f0;\n        double last_val_der = d0;\n\n        // The bracketing stage will find a range of points [a,b]\n        // that contains a reasonable solution to the line search\n        double a, b;\n\n        // These variables will hold the values and derivatives of f(a) and f(b)\n        double a_val, b_val, a_val_der, b_val_der;\n\n        // This thresh value represents the Wolfe curvature condition\n        const double thresh = std::abs(sigma*d0);\n\n        unsigned long itr = 0;\n        // do the bracketing stage to find the bracket range [a,b]\n        while (true)\n        {\n            ++itr;\n            const double val = f(alpha);\n            const double val_der = der(alpha);\n\n            // we are done with the line search since we found a value smaller\n            // than the minimum f value\n            if (val <= min_f)\n                return alpha;\n\n            if (val > f0 + rho*alpha*d0 || val >= last_val)\n            {\n                a_val = last_val;\n                a_val_der = last_val_der;\n                b_val = val;\n                b_val_der = val_der;\n\n                a = last_alpha;\n                b = alpha;\n                break;\n            }\n\n            if (std::abs(val_der) <= thresh)\n                return alpha;\n\n            // if we are stuck not making progress then quit with the current alpha\n            if (last_alpha == alpha || itr >= max_iter)\n                return alpha;\n\n            if (val_der >= 0)\n            {\n                a_val = val;\n                a_val_der = val_der;\n                b_val = last_val;\n                b_val_der = last_val_der;\n\n                a = alpha;\n                b = last_alpha;\n                break;\n            }\n\n\n\n            const double temp = alpha;\n            // Pick a larger range [first, last].  We will pick the next alpha in that\n            // range.\n            double first, last;\n            if (mu > 0)\n            {\n                first = std::min(mu, alpha + tau1a*(alpha - last_alpha));\n                last  = std::min(mu, alpha + tau1b*(alpha - last_alpha));\n            }\n            else\n            {\n                first = std::max(mu, alpha + tau1a*(alpha - last_alpha));\n                last  = std::max(mu, alpha + tau1b*(alpha - last_alpha));\n            }\n            \n\n\n            // pick a point between first and last by doing some kind of interpolation\n            if (last_alpha < alpha)\n                alpha = last_alpha + (alpha-last_alpha)*poly_min_extrap(last_val, last_val_der, val, val_der, 1e10);\n            else\n                alpha = alpha + (last_alpha-alpha)*poly_min_extrap(val, val_der, last_val, last_val_der, 1e10);\n\n            alpha = put_in_range(first,last,alpha);\n\n            last_alpha = temp;\n\n            last_val = val;\n            last_val_der = val_der;\n\n        }\n\n\n        // Now do the sectioning phase from 2.6.4\n        while (true)\n        {\n            ++itr;\n            double first = a + tau2*(b-a);\n            double last = b - tau3*(b-a);\n\n            // use interpolation to pick alpha between first and last\n            alpha = a + (b-a)*poly_min_extrap(a_val, a_val_der, b_val, b_val_der);\n            alpha = put_in_range(first,last,alpha);\n\n            const double val = f(alpha);\n            const double val_der = der(alpha);\n\n            // we are done with the line search since we found a value smaller\n            // than the minimum f value or we ran out of iterations.\n            if (val <= min_f || itr >= max_iter)\n                return alpha;\n\n            // stop if the interval gets so small that it isn't shrinking any more due to rounding error \n            if (a == first || b == last)\n            {\n                return b;\n            }\n\n            // If alpha has basically become zero then just stop.  Think of it like this,\n            // if we take the largest possible alpha step will the objective function\n            // change at all?  If not then there isn't any point looking for a better\n            // alpha.\n            const double max_possible_alpha = std::max(std::abs(a),std::abs(b));\n            if (std::abs(max_possible_alpha*d0) <= std::abs(f0)*std::numeric_limits<double>::epsilon())\n                return alpha;\n\n\n            if (val > f0 + rho*alpha*d0 || val >= a_val)\n            {\n                b = alpha;\n                b_val = val;\n                b_val_der = val_der;\n            }\n            else\n            {\n                if (std::abs(val_der) <= thresh)\n                    return alpha;\n\n                if ( (b-a)*val_der >= 0)\n                {\n                    b = a;\n                    b_val = a_val;\n                    b_val_der = a_val_der;\n                }\n\n                a = alpha;\n                a_val = val;\n                a_val_der = val_der;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double backtracking_line_search (\n        const funct& f, \n        double f0,\n        double d0,\n        double alpha,\n        double rho, \n        unsigned long max_iter \n    )\n    {\n        DLIB_ASSERT (\n            0 < rho && rho < 1 && max_iter > 0,\n            \"\\tdouble backtracking_line_search()\"\n            << \"\\n\\tYou have given invalid arguments to this function\"\n            << \"\\n\\t rho:      \" << rho \n            << \"\\n\\t max_iter: \" << max_iter \n        );\n\n        // make sure alpha is going in the right direction.  That is, it should be opposite\n        // the direction of the gradient.\n        if ((d0 > 0 && alpha > 0) ||\n            (d0 < 0 && alpha < 0))\n        {\n            alpha *= -1;\n        }\n\n        bool have_prev_alpha = false;\n        double prev_alpha = 0;\n        double prev_val = 0;\n        unsigned long iter = 0;\n        while (true)\n        {\n            ++iter;\n            const double val = f(alpha);\n            if (val <= f0 + alpha*rho*d0 || iter >= max_iter)\n            {\n                return alpha;\n            }\n            else\n            {\n                // Interpolate a new alpha.  We also make sure the step by which we\n                // reduce alpha is not super small.\n                double step;\n                if (!have_prev_alpha)\n                {\n                    if (d0 < 0)\n                        step = alpha*put_in_range(0.1,0.9, poly_min_extrap(f0, d0, val));\n                    else\n                        step = alpha*put_in_range(0.1,0.9, poly_min_extrap(f0, -d0, val));\n                    have_prev_alpha = true;\n                }\n                else\n                {\n                    if (d0 < 0)\n                        step = put_in_range(0.1*alpha,0.9*alpha, poly_min_extrap(f0, d0, alpha, val, prev_alpha, prev_val));\n                    else\n                        step = put_in_range(0.1*alpha,0.9*alpha, -poly_min_extrap(f0, -d0, -alpha, val, -prev_alpha, prev_val));\n                }\n\n                prev_alpha = alpha;\n                prev_val = val;\n\n                alpha = step;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class optimize_single_variable_failure : public error {\n    public: optimize_single_variable_failure(const std::string& s):error(s){}\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct>\n    double find_min_single_variable (\n        const funct& f,\n        double& starting_point,\n        const double begin = -1e200,\n        const double end = 1e200,\n        const double eps = 1e-3,\n        const long max_iter = 100,\n        const double initial_search_radius = 1\n    )\n    {\n        DLIB_CASSERT( eps > 0 &&\n                      max_iter > 1 &&\n                      begin <= starting_point && starting_point <= end && \n                      initial_search_radius > 0,\n                      \"eps: \" << eps\n                      << \"\\n max_iter: \"<< max_iter \n                      << \"\\n begin: \"<< begin \n                      << \"\\n end:   \"<< end \n                      << \"\\n starting_point: \"<< starting_point \n                      << \"\\n initial_search_radius: \"<< initial_search_radius \n        );\n\n        double search_radius = initial_search_radius;\n\n        double p1=0, p2=0, p3=0, f1=0, f2=0, f3=0;\n        long f_evals = 1;\n\n        if (begin == end)\n        {\n            return f(starting_point);\n        }\n\n        using std::abs;\n        using std::min;\n        using std::max;\n\n        // find three bracketing points such that f1 > f2 < f3.   Do this by generating a sequence\n        // of points expanding away from 0.   Also note that, in the following code, it is always the\n        // case that p1 < p2 < p3.\n\n\n\n        // The first thing we do is get a starting set of 3 points that are inside the [begin,end] bounds\n        p1 = max(starting_point-search_radius, begin);\n        p3 = min(starting_point+search_radius, end);\n        f1 = f(p1);\n        f3 = f(p3);\n\n        if (starting_point == p1 || starting_point == p3)\n        {\n            p2 = (p1+p3)/2;\n            f2 = f(p2);\n        }\n        else\n        {\n            p2 = starting_point;\n            f2 = f(starting_point);\n        }\n\n        f_evals += 2;\n\n        // Now we have 3 points on the function.  Start looking for a bracketing set such that\n        // f1 > f2 < f3 is the case.\n        while ( !(f1 > f2 && f2 < f3))\n        {\n            // check for hitting max_iter or if the interval is now too small\n            if (f_evals >= max_iter)\n            {\n                throw optimize_single_variable_failure(\n                    \"The max number of iterations of single variable optimization have been reached\\n\"\n                    \"without converging.\");\n            }\n            if (p3-p1 < eps)\n            {\n                if (f1 < min(f2,f3)) \n                {\n                    starting_point = p1;\n                    return f1;\n                }\n\n                if (f2 < min(f1,f3)) \n                {\n                    starting_point = p2;\n                    return f2;\n                }\n\n                starting_point = p3;\n                return f3;\n            }\n            \n            // If the left most points are identical in function value then expand out the\n            // left a bit, unless it's already at bound or we would drop that left most\n            // point anyway because it's bad.\n            if (f1==f2 && f1<f3 && p1!=begin)\n            {\n                p1 = max(p1 - search_radius, begin);\n                f1 = f(p1);\n                ++f_evals;\n                search_radius *= 2;\n                continue;\n            }\n            if (f2==f3 && f3<f1 && p3!=end)\n            {\n                p3 = min(p3 + search_radius, end);\n                f3 = f(p3);\n                ++f_evals;\n                search_radius *= 2;\n                continue;\n            }\n\n\n            // if f1 is small then take a step to the left\n            if (f1 <= f3)\n            { \n                // check if the minimum is butting up against the bounds and if so then pick\n                // a point between p1 and p2 in the hopes that shrinking the interval will\n                // be a good thing to do.  Or if p1 and p2 aren't differentiated then try and\n                // get them to obtain different values.\n                if (p1 == begin || (f1 == f2 && (end-begin) < search_radius ))\n                {\n                    p3 = p2;\n                    f3 = f2;\n\n                    p2 = (p1+p2)/2.0;\n                    f2 = f(p2);\n                }\n                else\n                {\n                    // pick a new point to the left of our current bracket\n                    p3 = p2;\n                    f3 = f2;\n\n                    p2 = p1;\n                    f2 = f1;\n\n                    p1 = max(p1 - search_radius, begin);\n                    f1 = f(p1);\n\n                    search_radius *= 2;\n                }\n\n            }\n            // otherwise f3 is small and we should take a step to the right\n            else \n            {\n                // check if the minimum is butting up against the bounds and if so then pick\n                // a point between p2 and p3 in the hopes that shrinking the interval will\n                // be a good thing to do.  Or if p2 and p3 aren't differentiated then try and\n                // get them to obtain different values.\n                if (p3 == end || (f2 == f3 && (end-begin) < search_radius))\n                {\n                    p1 = p2;\n                    f1 = f2;\n\n                    p2 = (p3+p2)/2.0;\n                    f2 = f(p2);\n                }\n                else\n                {\n                    // pick a new point to the right of our current bracket\n                    p1 = p2;\n                    f1 = f2;\n\n                    p2 = p3;\n                    f2 = f3;\n\n                    p3 = min(p3 + search_radius, end);\n                    f3 = f(p3);\n\n                    search_radius *= 2;\n                }\n            }\n\n            ++f_evals;\n        }\n\n\n        // Loop until we have done the max allowable number of iterations or\n        // the bracketing window is smaller than eps.\n        // Within this loop we maintain the invariant that: f1 > f2 < f3 and p1 < p2 < p3\n        const double tau = 0.1;\n        while( f_evals < max_iter && p3-p1 > eps)\n        {\n            double p_min = lagrange_poly_min_extrap(p1,p2,p3, f1,f2,f3);\n\n\n            // make sure p_min isn't too close to the three points we already have\n            if (p_min < p2)\n            {\n                const double min_dist = (p2-p1)*tau;\n                if (abs(p1-p_min) < min_dist) \n                {\n                    p_min = p1 + min_dist;\n                }\n                else if (abs(p2-p_min) < min_dist)\n                {\n                    p_min = p2 - min_dist;\n                }\n            }\n            else\n            {\n                const double min_dist = (p3-p2)*tau;\n                if (abs(p2-p_min) < min_dist) \n                {\n                    p_min = p2 + min_dist;\n                }\n                else if (abs(p3-p_min) < min_dist)\n                {\n                    p_min = p3 - min_dist;\n                }\n            }\n\n            // make sure one side of the bracket isn't super huge compared to the other\n            // side.  If it is then contract it.\n            const double bracket_ratio = abs(p1-p2)/abs(p2-p3);\n            // Force p_min to be on a reasonable side.  But only if lagrange_poly_min_extrap()\n            // didn't put it on a good side already.\n            if (bracket_ratio >= 10)\n            { \n                if (p_min > p2)\n                    p_min = (p1+p2)/2;\n            }\n            else if (bracket_ratio <= 0.1) \n            {\n                if (p_min < p2)\n                    p_min = (p2+p3)/2;\n            }\n\n\n            const double f_min = f(p_min);\n\n\n            // Remove one of the endpoints of our bracket depending on where the new point falls.\n            if (p_min < p2)\n            {\n                if (f1 > f_min && f_min < f2)\n                {\n                    p3 = p2;\n                    f3 = f2;\n                    p2 = p_min;\n                    f2 = f_min;\n                }\n                else\n                {\n                    p1 = p_min;\n                    f1 = f_min;\n                }\n            }\n            else\n            {\n                if (f2 > f_min && f_min < f3)\n                {\n                    p1 = p2;\n                    f1 = f2;\n                    p2 = p_min;\n                    f2 = f_min;\n                }\n                else\n                {\n                    p3 = p_min;\n                    f3 = f_min;\n                }\n            }\n\n\n            ++f_evals;\n        }\n\n        if (f_evals >= max_iter)\n        {\n            throw optimize_single_variable_failure(\n                \"The max number of iterations of single variable optimization have been reached\\n\"\n                \"without converging.\");\n        }\n\n        starting_point = p2;\n        return f2;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct>\n    class negate_function_object \n    {\n    public:\n        negate_function_object(const funct& f_) : f(f_){}\n\n        template <typename T>\n        double operator()(const T& x) const\n        {\n            return -f(x);\n        }\n\n    private:\n        const funct& f;\n    };\n\n    template <typename funct>\n    const negate_function_object<funct> negate_function(const funct& f) { return negate_function_object<funct>(f); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct>\n    double find_max_single_variable (\n        const funct& f,\n        double& starting_point,\n        const double begin = -1e200,\n        const double end = 1e200,\n        const double eps = 1e-3,\n        const long max_iter = 100,\n        const double initial_search_radius = 1\n    )\n    {\n        return -find_min_single_variable(negate_function(f), starting_point, begin, end, eps, max_iter, initial_search_radius);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_LINE_SEARCH_H_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_line_search_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_ABSTRACT_\n#ifdef DLIB_OPTIMIZATIOn_ABSTRACT_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct, \n        typename T\n        >\n    class line_search_funct; \n    /*!\n        This object is a function object that represents a line search function.\n\n        Moreover, it represents a function with the signature:\n            double l(double x)\n    !*/\n\n    template <\n        typename funct, \n        typename T\n        >\n    const line_search_funct<funct,T> make_line_search_function (\n        const funct& f, \n        const T& start, \n        const T& direction\n    ); \n    /*!\n        requires\n            - is_col_vector(start) && is_col_vector(direction) && start.size() == direction.size() \n              (i.e. start and direction should be column vectors of the same size)\n            - f must return either a double or a column vector the same length as start\n            - f(start + 1.5*direction) should be a valid expression\n        ensures\n            - if (f returns a double) then\n                - returns a line search function that computes l(x) == f(start + x*direction)\n            - else\n                - returns a line search function that computes l(x) == dot(f(start + x*direction),direction).\n                  That is, we assume f is the derivative of some other function and that what\n                  f returns is a gradient vector. \n                  So the following two expressions both create the derivative of l(x): \n                    - derivative(make_line_search_function(funct,start,direction))\n                    - make_line_search_function(derivative(funct),start,direction)\n    !*/\n\n    template <\n        typename funct, \n        typename T\n        >\n    const line_search_funct<funct,T> make_line_search_function (\n        const funct& f, \n        const T& start, \n        const T& direction,\n        double& f_out\n    ); \n    /*!\n        This function is identical to the above three argument version of make_line_search_function() \n        except that, if f() outputs a double, every time f() is evaluated its output is also stored \n        into f_out.\n    !*/\n\n    template <\n        typename funct, \n        typename T\n        >\n    const line_search_funct<funct,T> make_line_search_function (\n        const funct& f, \n        const T& start, \n        const T& direction,\n        T& gradient_out\n    ); \n    /*!\n        This function is identical to the above three argument version of make_line_search_function() \n        except that, if f() outputs a column vector, every time f() is evaluated its output is also \n        stored into gradient_out.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double f1,\n        double d1,\n        double limit = 1\n    );\n    /*!\n        ensures\n            - let c(x) be a 3rd degree polynomial such that:\n                - c(0) == f0\n                - c(1) == f1\n                - derivative of c(x) at x==0 is d0\n                - derivative of c(x) at x==1 is d1\n            - returns the point in the range [0,limit] that minimizes the polynomial c(x) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double f1\n    );\n    /*!\n        ensures\n            - let c(x) be a 2nd degree polynomial such that:\n                - c(0) == f0\n                - c(1) == f1\n                - derivative of c(x) at x==0 is d0\n            - returns the point in the range [0,1] that minimizes the polynomial c(x) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double poly_min_extrap (\n        double f0,\n        double d0,\n        double x1,\n        double f_x1,\n        double x2,\n        double f_x2\n    )\n    /*!\n        requires\n            - 0 < x1 < x2\n        ensures\n            - let f(x) be a 3rd degree polynomial such that:\n                - f(0) == f0\n                - derivative of f(x) at x==0 is d0\n                - f(x1) == f_x1\n                - f(x2) == f_x2\n            - returns the point in the range [0,x2] that minimizes the polynomial f(x) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline double lagrange_poly_min_extrap (\n        double p1, \n        double p2,\n        double p3,\n        double f1,\n        double f2,\n        double f3\n    );\n    /*!\n        requires\n            - f1 >= f2 <= f3\n            - p1 < p2 < p3\n        ensures\n            - let c(x) be the second order Lagrange polynomial that interpolates the\n              points p1, p2, and p3 where c(p1)==f1, c(p2)==f2, and c(p3)==f3\n            - this function returns the point in the range [p1,p3] that minimizes \n              the polynomial c(x) \n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct, \n        typename funct_der\n        >\n    double line_search (\n        const funct& f, \n        const double f0,\n        const funct_der& der, \n        const double d0,\n        double rho, \n        double sigma, \n        double min_f,\n        unsigned long max_iter\n    )\n    /*!\n        requires\n            - 0 < rho < sigma < 1\n            - f and der are scalar functions of scalars\n              (e.g. line_search_funct objects)\n            - der is the derivative of f\n            - f0 == f(0)\n            - d0 == der(0)\n            - max_iter > 0\n        ensures\n            - Performs a line search and uses the strong Wolfe conditions to decide when\n              the search can stop.  \n                - rho == the parameter of the Wolfe sufficient decrease condition\n                - sigma == the parameter of the Wolfe curvature condition\n                - max_iter == the maximum number of iterations allowable.  After this\n                  many evaluations of f() line_search() is guaranteed to terminate.\n            - returns a value alpha such that f(alpha) is significantly closer to \n              the minimum of f than f(0).\n            - It is assumed that the minimum possible value of f(x) is min_f.  So if\n              an alpha is found such that f(alpha) <= min_f then the search stops\n              immediately.\n            - This function is also optimized for the case where der(0) is negative.  I.e.\n              positive values of the argument to f() should be in a descent direction.  \n            - When this function makes calls to f() and der() it always does so by\n              first calling f() and then calling der().  That is, these two functions\n              are always called in pairs with f() being called first and then der()\n              being called second.\n    !*/\n\n    /*\n        A good discussion of the Wolfe conditions and line search algorithms in \n        general can be found in the book Practical Methods of Optimization by R. Fletcher\n        and also in the more recent book Numerical Optimization by Nocedal and Wright.\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double backtracking_line_search (\n        const funct& f, \n        double f0,\n        double d0,\n        double alpha,\n        double rho, \n        unsigned long max_iter \n    );\n    /*!\n        requires\n            - 0 < rho < 1\n            - f is a scalar function of scalars \n              (e.g. a line_search_funct object)\n            - f0 == f(0)\n            - d0 == the derivative of f() at f(0). \n            - max_iter > 0\n        ensures\n            - Performs a backtracking line search and uses the Armijo sufficient decrease\n              rule to decide when the search can stop.\n                - rho == the parameter of the sufficient decrease condition. \n                - max_iter == the maximum number of iterations allowable.  After this many\n                  evaluations of f() backtracking_line_search() is guaranteed to terminate.\n            - The line search starts with the input alpha value and then backtracks until\n              it finds a good enough alpha value.  Once found, it returns the alpha value\n              such that f(alpha) is significantly closer to the minimum of f than f(0).\n            - The returned value of alpha will always be the last value of alpha which was\n              passed to f().  That is, it will always be the case that the last call to f()\n              made by backtracking_line_search() was f(alpha) where alpha is the return\n              value from this function.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    const negate_function_object<funct> negate_function(\n        const funct& f\n    );\n    /*!\n        requires\n            - f == a function that returns a scalar\n        ensures\n            - returns a function that represents the negation of f.  That is,\n              the returned function object represents g(x) == -f(x)\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class optimize_single_variable_failure : public error;\n    /*!\n        This is the exception class used by the functions defined below.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double find_min_single_variable (\n        const funct& f,\n        double& starting_point,\n        const double begin = -1e200,\n        const double end = 1e200,\n        const double eps = 1e-3,\n        const long max_iter = 100,\n        const double initial_search_radius = 1\n    )\n    /*!\n        requires\n            - eps > 0\n            - max_iter > 1\n            - begin <= starting_point <= end\n            - f must be a function of a double that returns a double\n              (e.g. f(starting_point) should be a valid expression that evaluates to a double)\n            - initial_search_radius > 0\n        ensures\n            - Finds a point P such that:\n                - P is a local minimum of the function f().   \n                - begin <= P <= end\n            - Evaluates f() no more than max_iter times\n            - Stops searching when the window around the minimum point is smaller than eps.\n              The search will begin with the given starting_point and expand out to the\n              left and right by initial_search_radius sized steps.  So if you think the\n              minimum is likely to be found within X distance from the starting_point then\n              set initial_search_radius to X.\n            - #starting_point == P\n            - returns f(P)\n        throws\n            - optimize_single_variable_failure \n                This exception is thrown if max_iter iterations are performed without \n                determining the min point to the requested accuracy of eps.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename funct\n        >\n    double find_max_single_variable (\n        const funct& f,\n        double& starting_point,\n        const double begin = -1e200,\n        const double end = 1e200,\n        const double eps = 1e-3,\n        const long max_iter = 100,\n        const double initial_search_radius = 1\n    )\n    /*!\n        requires\n            - eps > 0\n            - max_iter > 1\n            - begin <= starting_point <= end\n            - f must be a function of a double that returns a double\n              (e.g. f(starting_point) should be a valid expression that evaluates to a double)\n            - initial_search_radius > 0\n        ensures\n            - Finds a point P such that:\n                - P is a local maximum of the function f().   \n                - begin <= P <= end\n            - Evaluates f() no more than max_iter times\n            - Stops searching when the window around the maximum point is smaller than eps.\n              The search will begin with the given starting_point and expand out to the\n              left and right by initial_search_radius sized steps.  So if you think the\n              maximum is likely to be found within X distance from the starting_point then\n              set initial_search_radius to X.\n            - #starting_point == P\n            - returns f(P)\n        throws\n            - optimize_single_variable_failure \n                This exception is thrown if max_iter iterations are performed without \n                determining the max point to the requested accuracy of eps.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_oca.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIoN_OCA_Hh_\n#define DLIB_OPTIMIZATIoN_OCA_Hh_\n\n#include \"optimization_oca_abstract.h\"\n\n#include \"../matrix.h\"\n#include \"optimization_solve_qp_using_smo.h\"\n#include <vector>\n#include \"../sequence.h\"\n#include <chrono>\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    template <typename matrix_type>\n    class oca_problem\n    {\n    public:\n        typedef typename matrix_type::type scalar_type;\n\n        virtual ~oca_problem() {}\n\n        virtual bool risk_has_lower_bound (\n            scalar_type& \n        ) const { return false; }\n\n        virtual bool optimization_status (\n            scalar_type ,\n            scalar_type ,\n            scalar_type ,\n            scalar_type ,\n            unsigned long,\n            unsigned long\n        ) const = 0;\n\n        virtual scalar_type get_c (\n        ) const = 0;\n\n        virtual long get_num_dimensions (\n        ) const = 0;\n\n        virtual void get_risk (\n            matrix_type& current_solution,\n            scalar_type& risk_value,\n            matrix_type& risk_subgradient\n        ) const = 0;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class oca\n    {\n    public:\n\n        oca () \n        {\n            sub_eps = 1e-2;\n            sub_max_iter = 50000;\n\n            inactive_thresh = 20;\n            max_runtime = std::chrono::hours(24*356*290); // 290 years\n        }\n\n        void set_subproblem_epsilon (\n            double eps_\n        ) { sub_eps = eps_; }\n\n        double get_subproblem_epsilon (\n        ) const { return sub_eps; }\n\n        void set_subproblem_max_iterations (\n            unsigned long sub_max_iter_\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(sub_max_iter_ > 0,\n                \"\\t void oca::set_subproblem_max_iterations\"\n                << \"\\n\\t max iterations must be greater than 0\"\n                << \"\\n\\t sub_max_iter_: \" << sub_max_iter_\n                << \"\\n\\t this: \" << this\n                );\n\n            sub_max_iter = sub_max_iter_; \n        }\n\n        unsigned long get_subproblem_max_iterations (\n        ) const { return sub_max_iter; }\n\n        void set_max_runtime (\n            const std::chrono::nanoseconds& max_runtime_\n        ) \n        {\n            max_runtime = max_runtime_;\n        }\n\n        std::chrono::nanoseconds get_max_runtime (\n        ) const\n        {\n            return max_runtime;\n        }\n\n        void set_inactive_plane_threshold (\n            unsigned long inactive_thresh_\n        ) \n        { \n            // make sure requires clause is not broken\n            DLIB_ASSERT(inactive_thresh_ > 0,\n                \"\\t void oca::set_inactive_plane_threshold\"\n                << \"\\n\\t inactive threshold must be greater than 0\"\n                << \"\\n\\t inactive_thresh_: \" << inactive_thresh_\n                << \"\\n\\t this: \" << this\n                );\n\n            inactive_thresh = inactive_thresh_; \n        }\n\n        unsigned long get_inactive_plane_threshold (\n        ) const { return inactive_thresh; }\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type operator() (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            unsigned long num_nonnegative = 0,\n            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()\n        ) const\n        {\n            matrix_type empty_prior;\n            return oca_impl(problem, w, empty_prior, false, num_nonnegative, force_weight_to_1, 0);\n        }\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type solve_with_elastic_net (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            double lasso_lambda,\n            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()\n        ) const\n        {\n            matrix_type empty_prior;\n            return oca_impl(problem, w, empty_prior, false, 0, force_weight_to_1, lasso_lambda);\n        }\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type operator() (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            const matrix_type& prior\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(is_col_vector(prior) && prior.size() == problem.get_num_dimensions(),\n                \"\\t scalar_type oca::operator()\"\n                << \"\\n\\t The prior vector does not have the correct dimensions.\"\n                << \"\\n\\t is_col_vector(prior):         \" << is_col_vector(prior) \n                << \"\\n\\t prior.size():                 \" << prior.size() \n                << \"\\n\\t problem.get_num_dimensions(): \" << problem.get_num_dimensions() \n                << \"\\n\\t this:                         \" << this\n                );\n            // disable the force weight to 1 option for this mode.  We also disable the\n            // non-negative constraints.\n            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max();\n            return oca_impl(problem, w, prior, true, 0, force_weight_to_1, 0);\n        }\n\n    private:\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type oca_impl (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            const matrix_type& prior,\n            bool have_prior,\n            unsigned long num_nonnegative,\n            unsigned long force_weight_to_1,\n            const double lasso_lambda\n        ) const\n        {\n            const unsigned long num_dims = problem.get_num_dimensions();\n\n            // make sure requires clause is not broken\n            DLIB_ASSERT(problem.get_c() > 0 &&\n                        problem.get_num_dimensions() > 0 && \n                        0 <= lasso_lambda && lasso_lambda < 1,\n                \"\\t scalar_type oca::operator()\"\n                << \"\\n\\t The oca_problem is invalid\"\n                << \"\\n\\t problem.get_c():              \" << problem.get_c() \n                << \"\\n\\t problem.get_num_dimensions(): \" << num_dims \n                << \"\\n\\t lasso_lambda:                 \" << lasso_lambda \n                << \"\\n\\t this: \" << this\n                );\n            if (have_prior)\n            {\n                DLIB_ASSERT(lasso_lambda == 0, \"Solver doesn't support using a prior with lasso.\");\n                DLIB_ASSERT(num_nonnegative == 0, \"Solver doesn't support using a prior with non-negative constraints.\");\n            }\n            else if (lasso_lambda != 0)\n            {\n                DLIB_ASSERT(num_nonnegative == 0, \"Solver doesn't support using lasso with non-negative constraints.\");\n            }\n\n            const double ridge_lambda = 1-lasso_lambda;\n\n            if (num_nonnegative > num_dims)\n                num_nonnegative = num_dims;\n\n            typedef typename matrix_type::type scalar_type;\n            typedef typename matrix_type::layout_type layout_type;\n            typedef typename matrix_type::mem_manager_type mem_manager_type;\n            typedef matrix_type vect_type;\n\n            const scalar_type C = problem.get_c();\n\n            typename sequence<vect_type>::kernel_2a planes;\n            std::vector<scalar_type> bs, miss_count;\n\n            vect_type new_plane, alpha, btemp;\n\n            w.set_size(num_dims, 1);\n            w = 0;\n\n            // The current objective value.  Note also that w always contains \n            // the current solution.\n            scalar_type cur_obj = std::numeric_limits<scalar_type>::max();\n\n            // This will hold the cutting plane objective value.  This value is\n            // a lower bound on the true optimal objective value.\n            scalar_type cp_obj = 0;\n\n            matrix<scalar_type,0,0,mem_manager_type, layout_type> K, Ktmp;\n            matrix<scalar_type,0,1,mem_manager_type, layout_type> lambda, d;\n            if (lasso_lambda != 0)\n                d.set_size(num_dims);\n            else\n                d.set_size(num_nonnegative);\n            d = lasso_lambda*ones_matrix(d);\n\n            scalar_type R_lower_bound;\n            if (problem.risk_has_lower_bound(R_lower_bound))\n            {\n                // The flat lower bounding plane is always good to have if we know\n                // what it is.\n                bs.push_back(R_lower_bound);\n                new_plane = zeros_matrix(w);\n                planes.add(0, new_plane);\n                alpha = uniform_matrix<scalar_type>(1,1, C);\n                miss_count.push_back(0);\n\n                K.set_size(1,1);\n                K(0,0) = 0;\n            }\n\n            const double prior_norm = have_prior ?  0.5*dot(prior,prior) : 0;\n\n            const auto time_to_stop = std::chrono::steady_clock::now() + max_runtime;\n\n            unsigned long counter = 0;\n            while (true)\n            {\n\n                // add the next cutting plane\n                scalar_type cur_risk;\n                if (force_weight_to_1 < (unsigned long)w.size())\n                    w(force_weight_to_1) = 1;\n\n                problem.get_risk(w, cur_risk, new_plane);\n\n                if (force_weight_to_1 < (unsigned long)w.size())\n                {\n                    // We basically arrange for the w(force_weight_to_1) element and all\n                    // subsequent elements of w to not be involved in the optimization at\n                    // all.  An easy way to do this is to just make sure the elements of w\n                    // corresponding elements in the subgradient are always set to zero\n                    // while we run the cutting plane algorithm.  The only time\n                    // w(force_weight_to_1) is 1 is when we pass it to the oca_problem.\n                    set_rowm(w, range(force_weight_to_1, w.size()-1)) = 0;\n                    set_rowm(new_plane, range(force_weight_to_1, new_plane.size()-1)) = 0;\n                }\n\n                if (have_prior)\n                    bs.push_back(cur_risk - dot(w,new_plane) + dot(prior,new_plane));\n                else\n                    bs.push_back(cur_risk - dot(w,new_plane));\n                planes.add(planes.size(), new_plane);\n                miss_count.push_back(0);\n\n                // If alpha is empty then initialize it (we must always have sum(alpha) == C).  \n                // But otherwise, just append a zero.\n                if (alpha.size() == 0)\n                    alpha = uniform_matrix<scalar_type>(1,1, C);\n                else\n                    alpha = join_cols(alpha,zeros_matrix<scalar_type>(1,1));\n\n                const scalar_type wnorm = 0.5*ridge_lambda*trans(w)*w + lasso_lambda*sum(abs(w));\n                const double prior_part = have_prior? dot(w,prior) : 0;\n                cur_obj = wnorm + C*cur_risk + prior_norm-prior_part;\n\n                // report current status\n                const scalar_type risk_gap = cur_risk - (cp_obj-wnorm+prior_part-prior_norm)/C;\n                if (counter > 0 && problem.optimization_status(cur_obj, cur_obj - cp_obj, \n                                                               cur_risk, risk_gap, planes.size(), counter))\n                {\n                    break;\n                }\n                if (std::chrono::steady_clock::now() >= time_to_stop)\n                    break;\n\n                // compute kernel matrix for all the planes\n                K.swap(Ktmp);\n                K.set_size(planes.size(), planes.size());\n                // copy over the old K matrix\n                set_subm(K, 0,0, Ktmp.nr(), Ktmp.nc()) = Ktmp;\n\n                // now add the new row and column to K\n                for (unsigned long c = 0; c < planes.size(); ++c)\n                {\n                    K(c, Ktmp.nc()) = dot(planes[c], planes[planes.size()-1]);\n                    K(Ktmp.nc(), c) = K(c,Ktmp.nc());\n                }\n\n\n                // solve the cutting plane subproblem for the next w.   We solve it to an\n                // accuracy that is related to how big the error gap is.  Also, we multiply\n                // by ridge_lambda because the objective function for the QP we solve was\n                // implicitly scaled by ridge_lambda.  That is, we want to ask the QP\n                // solver to solve the problem until the duality gap is 0.1 times smaller\n                // than what it is now.  So the factor of ridge_lambda is necessary to make\n                // this happen. \n                scalar_type eps = std::min<scalar_type>(sub_eps, 0.1*ridge_lambda*(cur_obj-cp_obj));\n                // just a sanity check\n                if (eps < 1e-16)\n                    eps = 1e-16;\n                // Note that we warm start this optimization by using the alpha from the last\n                // iteration as the starting point.\n                if (lasso_lambda != 0)\n                {\n                    // copy planes into a matrix so we can call solve_qp4_using_smo()\n                    matrix<scalar_type,0,0,mem_manager_type, layout_type> planes_mat(num_dims,planes.size());\n                    for (unsigned long i = 0; i < planes.size(); ++i)\n                        set_colm(planes_mat,i) = planes[i];\n\n                    btemp = ridge_lambda*mat(bs) - trans(planes_mat)*d;\n                    solve_qp4_using_smo(planes_mat, K, btemp, d, alpha, lambda, eps, sub_max_iter, (scalar_type)(2*lasso_lambda)); \n                }\n                else if (num_nonnegative != 0)\n                {\n                    // copy planes into a matrix so we can call solve_qp4_using_smo()\n                    matrix<scalar_type,0,0,mem_manager_type, layout_type> planes_mat(num_nonnegative,planes.size());\n                    for (unsigned long i = 0; i < planes.size(); ++i)\n                        set_colm(planes_mat,i) = colm(planes[i],0,num_nonnegative);\n\n                    solve_qp4_using_smo(planes_mat, K, mat(bs), d, alpha, lambda, eps, sub_max_iter); \n                }\n                else\n                {\n                    solve_qp_using_smo(K, mat(bs), alpha, eps, sub_max_iter); \n                }\n\n                // construct the w that minimized the subproblem.\n                w = -alpha(0)*planes[0];\n                for (unsigned long i = 1; i < planes.size(); ++i)\n                    w -= alpha(i)*planes[i];\n                if (lasso_lambda != 0)\n                    w = (lambda-d+w)/ridge_lambda;\n                else if (num_nonnegative != 0) // threshold the first num_nonnegative w elements if necessary.\n                    set_rowm(w,range(0,num_nonnegative-1)) = lowerbound(rowm(w,range(0,num_nonnegative-1)),0);\n\n                for (long i = 0; i < alpha.size(); ++i)\n                {\n                    if (alpha(i) != 0)\n                        miss_count[i] = 0;\n                    else\n                        miss_count[i] += 1;\n                }\n\n                // Compute the lower bound on the true objective given to us by the cutting \n                // plane subproblem.\n                cp_obj = -0.5*ridge_lambda*trans(w)*w + trans(alpha)*mat(bs);\n                if (have_prior)\n                    w += prior;\n\n                // If it has been a while since a cutting plane was an active constraint then\n                // we should throw it away.\n                while (max(mat(miss_count)) >= inactive_thresh)\n                {\n                    const long idx = index_of_max(mat(miss_count));\n                    bs.erase(bs.begin()+idx);\n                    miss_count.erase(miss_count.begin()+idx);\n                    K = removerc(K, idx, idx);\n                    alpha = remove_row(alpha,idx);\n                    planes.remove(idx, new_plane);\n                }\n\n                ++counter;\n            }\n\n            if (force_weight_to_1 < (unsigned long)w.size())\n                w(force_weight_to_1) = 1;\n\n            return cur_obj;\n        }\n\n        double sub_eps;\n\n        unsigned long sub_max_iter;\n\n        unsigned long inactive_thresh;\n\n        std::chrono::nanoseconds max_runtime;\n    };\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_OPTIMIZATIoN_OCA_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_oca_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_\n#ifdef DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_\n\n#include <chrono>\n\n// ----------------------------------------------------------------------------------------\n\nnamespace dlib\n{\n    template <typename matrix_type>\n    class oca_problem\n    {\n        /*!\n            REQUIREMENTS ON matrix_type\n                - matrix_type == a dlib::matrix capable of storing column vectors\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is the interface used to define the optimization \n                problems solved by the oca optimizer defined later in this file.\n\n                OCA solves optimization problems with the following form:\n                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)\n\n                    Where R(w) is a user-supplied convex function and C > 0.  Optionally,\n                    there can also be non-negativity constraints on some or all of the \n                    elements of w.\n\n                Or it can alternatively solve:\n                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)\n\n                    Where prior is a user supplied vector and R(w) has the same\n                    interpretation as above.\n                       \n                Or it can use the elastic net regularizer:\n                    Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w)\n\n                    Where lasso_lambda is a number in the range [0, 1) and controls\n                    trade-off between doing L1 and L2 regularization.  R(w) has the same\n                    interpretation as above.\n                       \n\n                Note that the stopping condition must be provided by the user\n                in the form of the optimization_status() function.\n        !*/\n\n    public:\n\n        typedef typename matrix_type::type scalar_type;\n\n        virtual ~oca_problem() {}\n\n        virtual bool risk_has_lower_bound (\n            scalar_type& lower_bound\n        ) const { return false; }\n        /*!\n            ensures\n                - if (R(w) >= a constant for all values of w) then\n                    - returns true\n                    - #lower_bound == the constant that lower bounds R(w)\n                - else\n                    - returns false\n        !*/\n\n        virtual bool optimization_status (\n            scalar_type current_objective_value,\n            scalar_type current_error_gap,\n            scalar_type current_risk_value,\n            scalar_type current_risk_gap,\n            unsigned long num_cutting_planes,\n            unsigned long num_iterations\n        ) const = 0;\n        /*!\n            requires\n                - This function is called by the OCA optimizer each iteration.  \n                - current_objective_value == the current value of the objective function f(w)\n                - current_error_gap == The bound on how much lower the objective function\n                  can drop before we reach the optimal point.  At the optimal solution the\n                  error gap is equal to 0.\n                - current_risk_value == the current value of the R(w) term of the objective function.\n                - current_risk_gap == the bound on how much lower the risk term can go.  At the optimal\n                  solution the risk gap is zero.\n                - num_cutting_planes == the number of cutting planes the algorithm is currently using.\n                - num_iterations == A count of the total number of iterations that have executed\n                  since we started running the optimization.\n            ensures\n                - If it is appropriate to terminate the optimization then this function returns true\n                  and false otherwise.\n        !*/\n\n        virtual scalar_type get_c (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the C parameter\n        !*/\n\n        virtual long get_num_dimensions (\n        ) const = 0;\n        /*!\n            ensures\n                - returns the number of free variables in this optimization problem\n        !*/\n\n        virtual void get_risk (\n            matrix_type& current_solution,\n            scalar_type& risk_value,\n            matrix_type& risk_subgradient\n        ) const = 0;\n        /*!\n            requires\n                - is_col_vector(current_solution) == true\n                - current_solution.size() == get_num_dimensions()\n            ensures\n                - #current_solution will be set to one of the following:\n                    - current_solution (i.e. it won't be modified at all)\n                    - The result of a line search passing through current_solution.  \n                - #risk_value == R(#current_solution) \n                - #risk_subgradient == an element of the subgradient of R() at the \n                  point #current_solution\n                - Note that #risk_value and #risk_subgradient are NOT multiplied by get_c()\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class oca\n    {\n        /*!\n            INITIAL VALUE\n                - get_subproblem_epsilon() == 1e-2\n                - get_subproblem_max_iterations() == 50000\n                - get_inactive_plane_threshold() == 20\n                - get_max_runtime() == std::chrono::hours(24*356*290)\n                  (i.e. 290 years, so basically forever)\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for solving the optimization problem defined above\n                by the oca_problem abstract class.  \n\n                For reference, OCA solves optimization problems with the following form:\n                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)\n\n                    Where R(w) is a user-supplied convex function and C > 0.  Optionally,\n                    this object can also add non-negativity constraints to some or all\n                    of the elements of w.\n\n                Or it can alternatively solve:\n                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)\n\n                    Where prior is a user supplied vector and R(w) has the same\n                    interpretation as above.\n                       \n                Or it can use the elastic net regularizer:\n                    Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w)\n\n                    Where lasso_lambda is a number in the range [0, 1) and controls\n                    trade-off between doing L1 and L2 regularization.  R(w) has the same\n                    interpretation as above.\n                       \n\n                For a detailed discussion you should consult the following papers\n                from the Journal of Machine Learning Research:\n                    Optimized Cutting Plane Algorithm for Large-Scale Risk Minimization\n                        Vojtech Franc, Soren Sonnenburg; 10(Oct):2157--2192, 2009. \n\n                    Bundle Methods for Regularized Risk Minimization\n                        Choon Hui Teo, S.V.N. Vishwanthan, Alex J. Smola, Quoc V. Le; 11(Jan):311-365, 2010. \n        !*/\n    public:\n\n        oca (\n        ); \n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type operator() (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            unsigned long num_nonnegative = 0,\n            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()\n        ) const;\n        /*!\n            requires\n                - problem.get_c() > 0\n                - problem.get_num_dimensions() > 0\n            ensures\n                - solves the given oca problem and stores the solution in #w.  In particular,\n                  this function solves:\n                    Minimize: f(w) == 0.5*length_squared(w) + C*R(w)\n                - The optimization algorithm runs until problem.optimization_status() \n                  indicates it is time to stop.\n                - returns the objective value at the solution #w\n                - if (num_nonnegative != 0) then\n                    - Adds the constraint that #w(i) >= 0 for all i < num_nonnegative.\n                      That is, the first num_nonnegative elements of #w will always be\n                      non-negative.  This includes the copies of w passed to get_risk()\n                      in the form of the current_solution vector as well as the final\n                      output of this function.\n                - if (force_weight_to_1 < problem.get_num_dimensions()) then\n                    - The optimizer enforces the following constraints:\n                        - #w(force_weight_to_1) == 1\n                        - for all i > force_weight_to_1:\n                            - #w(i) == 0 \n                        - That is, the element in the weight vector at the index indicated\n                          by force_weight_to_1 will have a value of 1 upon completion of\n                          this function, while all subsequent elements of w will have\n                          values of 0.\n        !*/\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type operator() (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            const matrix_type& prior\n        ) const;\n        /*!\n            requires\n                - problem.get_c() > 0\n                - problem.get_num_dimensions() > 0\n                - is_col_vector(prior) == true\n                - prior.size() == problem.get_num_dimensions()\n            ensures\n                - solves the given oca problem and stores the solution in #w.\n                - In this mode, we solve a version of the problem with a different\n                  regularizer.  In particular, this function solves:\n                    Minimize: f(w) == 0.5*length_squared(w-prior) + C*R(w)\n                - The optimization algorithm runs until problem.optimization_status() \n                  indicates it is time to stop.\n                - returns the objective value at the solution #w\n        !*/\n\n        template <\n            typename matrix_type\n            >\n        typename matrix_type::type solve_with_elastic_net (\n            const oca_problem<matrix_type>& problem,\n            matrix_type& w,\n            scalar_type lasso_lambda,\n            unsigned long force_weight_to_1 = std::numeric_limits<unsigned long>::max()\n        ) const;\n        /*!\n            requires\n                - problem.get_c() > 0\n                - problem.get_num_dimensions() > 0\n                - 0 <= lasso_lambda < 1\n            ensures\n                - Solves the given oca problem and stores the solution in #w, but uses an\n                  elastic net regularizer instead of the normal L2 regularizer.  In\n                  particular, this function solves:\n                    Minimize: f(w) == 0.5*(1-lasso_lambda)*length_squared(w) + lasso_lambda*sum(abs(w)) + C*R(w)\n                - The optimization algorithm runs until problem.optimization_status() \n                  indicates it is time to stop.\n                - returns the objective value at the solution #w\n                - if (force_weight_to_1 < problem.get_num_dimensions()) then\n                    - The optimizer enforces the following constraints:\n                        - #w(force_weight_to_1) == 1\n                        - for all i > force_weight_to_1:\n                            - #w(i) == 0 \n                        - That is, the element in the weight vector at the index indicated\n                          by force_weight_to_1 will have a value of 1 upon completion of\n                          this function, while all subsequent elements of w will have\n                          values of 0.\n        !*/\n\n        void set_subproblem_epsilon (\n            double eps\n        ); \n        /*!\n            requires\n                - eps > 0\n            ensures\n                - #get_subproblem_epsilon() == eps \n        !*/\n\n        double get_subproblem_epsilon (\n        ) const; \n        /*!\n            ensures\n                - returns the accuracy used in solving the quadratic programming\n                  subproblem that is part of the overall OCA algorithm.\n        !*/\n\n        void set_subproblem_max_iterations (\n            unsigned long sub_max_iter\n        ); \n        /*!\n            requires\n                - sub_max_iter > 0\n            ensures\n                - #get_subproblem_max_iterations() == sub_max_iter\n        !*/\n\n        unsigned long get_subproblem_max_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the maximum number of iterations this object will perform\n                  while attempting to solve each quadratic programming subproblem.\n        !*/\n\n        void set_inactive_plane_threshold (\n            unsigned long inactive_thresh\n        ); \n        /*!\n            requires\n                - inactive_thresh > 0\n            ensures\n                - #get_inactive_plane_threshold() == inactive_thresh\n        !*/\n\n        unsigned long get_inactive_plane_threshold (\n        ) const; \n        /*!\n            ensures\n                - As OCA runs it builds up a set of cutting planes.  Typically\n                  cutting planes become inactive after a certain point and can then\n                  be removed.  This function returns the number of iterations of\n                  inactivity required before a cutting plane is removed.\n        !*/\n\n        void set_max_runtime (\n            const std::chrono::nanoseconds& max_runtime\n        ) const;\n        /*!\n            ensures\n                - #get_max_runtime() == max_runtime\n        !*/\n\n        std::chrono::nanoseconds get_max_runtime (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum amount of time we will let the solver run before \n                  making it terminate.\n        !*/\n\n    };\n}\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_OPTIMIZATION_OCA_ABsTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_search_strategies.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_\n#define DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n#include \"optimization_search_strategies_abstract.h\"\n#include \"../sequence.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class cg_search_strategy\n    {\n    public:\n        cg_search_strategy() : been_used(false) {}\n\n        double get_wolfe_rho (\n        ) const { return 0.001; }\n\n        double get_wolfe_sigma (\n        ) const { return 0.01; }\n\n        unsigned long get_max_line_search_iterations (\n        ) const { return 100; }\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& ,\n            const double ,\n            const T& funct_derivative\n        )\n        {\n            if (been_used == false)\n            {\n                been_used = true;\n                prev_direction = -funct_derivative;\n            }\n            else\n            {\n                // Use the Polak-Ribiere (4.1.12) conjugate gradient described by Fletcher on page 83\n                const double temp = trans(prev_derivative)*prev_derivative;\n                // If this value hits zero then just use the direction of steepest descent.\n                if (std::abs(temp) < std::numeric_limits<double>::epsilon())\n                {\n                    prev_derivative = funct_derivative;\n                    prev_direction = -funct_derivative;\n                    return prev_direction;\n                }\n\n                double b = trans(funct_derivative-prev_derivative)*funct_derivative/(temp);\n                prev_direction = -funct_derivative + b*prev_direction;\n\n            }\n\n            prev_derivative = funct_derivative;\n            return prev_direction;\n        }\n\n    private:\n        bool been_used;\n        matrix<double,0,1> prev_derivative;\n        matrix<double,0,1> prev_direction;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class bfgs_search_strategy\n    {\n    public:\n        bfgs_search_strategy() : been_used(false), been_used_twice(false) {}\n\n        double get_wolfe_rho (\n        ) const { return 0.01; }\n\n        double get_wolfe_sigma (\n        ) const { return 0.9; }\n\n        unsigned long get_max_line_search_iterations (\n        ) const { return 100; }\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& x,\n            const double ,\n            const T& funct_derivative\n        )\n        {\n            if (been_used == false)\n            {\n                been_used = true;\n                H = identity_matrix<double>(x.size());\n            }\n            else\n            {\n                // update H with the BFGS formula from (3.2.12) on page 55 of Fletcher \n                delta = (x-prev_x); \n                gamma = funct_derivative-prev_derivative;\n\n                double dg = dot(delta,gamma);\n\n                // Try to set the initial value of the H matrix to something reasonable if we are still\n                // in the early stages of figuring out what it is.  This formula below is what is suggested\n                // in the book Numerical Optimization by Nocedal and Wright in the chapter on Quasi-Newton methods.\n                if (been_used_twice == false)\n                {\n                    double gg = trans(gamma)*gamma;\n                    if (std::abs(gg) > std::numeric_limits<double>::epsilon())\n                    {\n                        const double temp = put_in_range(0.01, 100, dg/gg);\n                        H = diagm(uniform_matrix<double>(x.size(),1, temp));\n                        been_used_twice = true;\n                    }\n                }\n\n                Hg = H*gamma;\n                gH = trans(trans(gamma)*H);\n                double gHg = trans(gamma)*H*gamma;\n                if (gHg < std::numeric_limits<double>::infinity() && dg < std::numeric_limits<double>::infinity() &&\n                    dg != 0)\n                {\n                    H += (1 + gHg/dg)*delta*trans(delta)/(dg) - (delta*trans(gH) + Hg*trans(delta))/(dg);\n                }\n                else\n                {\n                    H = identity_matrix<double>(H.nr());\n                    been_used_twice = false;\n                }\n            }\n\n            prev_x = x;\n            prev_direction = -H*funct_derivative;\n            prev_derivative = funct_derivative;\n            return prev_direction;\n        }\n\n    private:\n        bool been_used;\n        bool been_used_twice;\n        matrix<double,0,1> prev_x;\n        matrix<double,0,1> prev_derivative;\n        matrix<double,0,1> prev_direction;\n        matrix<double> H;\n        matrix<double,0,1> delta, gamma, Hg, gH;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class lbfgs_search_strategy\n    {\n    public:\n        explicit lbfgs_search_strategy(unsigned long max_size_) : max_size(max_size_), been_used(false) \n        {\n            DLIB_ASSERT (\n                max_size > 0,\n                \"\\t lbfgs_search_strategy(max_size)\"\n                << \"\\n\\t max_size can't be zero\"\n            );\n        }\n\n        lbfgs_search_strategy(const lbfgs_search_strategy& item) \n        {\n            max_size = item.max_size;\n            been_used = item.been_used;\n            prev_x = item.prev_x;\n            prev_derivative = item.prev_derivative;\n            prev_direction = item.prev_direction;\n            alpha = item.alpha;\n            dh_temp = item.dh_temp;\n        }\n\n        double get_wolfe_rho (\n        ) const { return 0.01; }\n\n        double get_wolfe_sigma (\n        ) const { return 0.9; }\n\n        unsigned long get_max_line_search_iterations (\n        ) const { return 100; }\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& x,\n            const double ,\n            const T& funct_derivative\n        )\n        {\n            prev_direction = -funct_derivative;\n\n            if (been_used == false)\n            {\n                been_used = true;\n            }\n            else\n            {\n                // add an element into the stored data sequence\n                dh_temp.s = x - prev_x;\n                dh_temp.y = funct_derivative - prev_derivative;\n                double temp = dot(dh_temp.s, dh_temp.y);\n                // only accept this bit of data if temp isn't zero\n                if (std::abs(temp) > std::numeric_limits<double>::epsilon())\n                {\n                    dh_temp.rho = 1/temp;\n                    data.add(data.size(), dh_temp);\n                }\n                else\n                {\n                    data.clear();\n                }\n\n                if (data.size() > 0)\n                {\n                    // This block of code is from algorithm 7.4 in the Nocedal book.\n\n                    alpha.resize(data.size());\n                    for (unsigned long i = data.size()-1; i < data.size(); --i)\n                    {\n                        alpha[i] = data[i].rho*dot(data[i].s, prev_direction);\n                        prev_direction -= alpha[i]*data[i].y;\n                    }\n\n                    // Take a guess at what the first H matrix should be.  This formula below is what is suggested\n                    // in the book Numerical Optimization by Nocedal and Wright in the chapter on Large Scale \n                    // Unconstrained Optimization (in the L-BFGS section).\n                    double H_0 = 1.0/data[data.size()-1].rho/dot(data[data.size()-1].y, data[data.size()-1].y);\n                    H_0 = put_in_range(0.001, 1000.0, H_0);\n                    prev_direction *= H_0;\n\n                    for (unsigned long i = 0; i < data.size(); ++i)\n                    {\n                        double beta = data[i].rho*dot(data[i].y, prev_direction);\n                        prev_direction += data[i].s * (alpha[i] - beta);\n                    }\n                }\n\n            }\n\n            if (data.size() > max_size)\n            {\n                // remove the oldest element in the data sequence\n                data.remove(0, dh_temp);\n            }\n\n            prev_x = x;\n            prev_derivative = funct_derivative;\n            return prev_direction;\n        }\n\n    private:\n\n        struct data_helper\n        {\n            matrix<double,0,1> s;\n            matrix<double,0,1> y;\n            double rho;\n\n            friend void swap(data_helper& a, data_helper& b)\n            {\n                a.s.swap(b.s);\n                a.y.swap(b.y);\n                std::swap(a.rho, b.rho);\n            }\n        };\n        sequence<data_helper>::kernel_2a data;\n\n        unsigned long max_size;\n        bool been_used;\n        matrix<double,0,1> prev_x;\n        matrix<double,0,1> prev_derivative;\n        matrix<double,0,1> prev_direction;\n        std::vector<double> alpha;\n\n        data_helper dh_temp;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename hessian_funct>\n    class newton_search_strategy_obj\n    {\n    public:\n        explicit newton_search_strategy_obj(\n            const hessian_funct& hess\n        ) : hessian(hess) {}\n\n        double get_wolfe_rho (\n        ) const { return 0.01; }\n\n        double get_wolfe_sigma (\n        ) const { return 0.9; }\n\n        unsigned long get_max_line_search_iterations (\n        ) const { return 100; }\n\n        template <typename T>\n        const matrix<double,0,1> get_next_direction (\n            const T& x,\n            const double ,\n            const T& funct_derivative\n        )\n        {\n            return -inv(hessian(x))*funct_derivative;\n        }\n\n    private:\n        hessian_funct hessian;\n    };\n\n    template <typename hessian_funct>\n    newton_search_strategy_obj<hessian_funct> newton_search_strategy (\n        hessian_funct hessian\n    ) { return newton_search_strategy_obj<hessian_funct>(hessian); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_H_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_search_strategies_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_\n#ifdef DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n    /*\n        A good discussion of the search strategies in this file can be found in the \n        following book:  Numerical Optimization by Nocedal and Wright.\n    */\n\n// ----------------------------------------------------------------------------------------\n\n    class cg_search_strategy\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for determining which direction\n                a line search should be carried out along.  This particular object\n                is an implementation of the Polak-Ribiere conjugate gradient method\n                for determining this direction.\n\n                This method uses an amount of memory that is linear in the number\n                of variables to be optimized.  So it is capable of handling problems\n                with a very large number of variables.  However, it is generally\n                not as good as the L-BFGS algorithm (which is defined below in\n                the lbfgs_search_strategy class).\n        !*/\n\n    public:\n        cg_search_strategy(\n        );\n        /*!\n            ensures\n                - This object is properly initialized and ready to generate\n                  search directions.\n        !*/\n\n        double get_wolfe_rho (\n        ) const;\n        /*!\n            ensures\n                - returns the value of the Wolfe rho parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        double get_wolfe_sigma (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the Wolfe sigma parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        unsigned long get_max_line_search_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the max iterations parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - this function is only called once per search iteration\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - Assuming that a line search is going to be conducted starting from the point x,\n                  this function returns the direction in which the search should proceed.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class bfgs_search_strategy\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for determining which direction\n                a line search should be carried out along.  This particular object\n                is an implementation of the BFGS quasi-newton method for determining \n                this direction.\n\n                This method uses an amount of memory that is quadratic in the number\n                of variables to be optimized.  It is generally very effective but \n                if your problem has a very large number of variables then it isn't \n                appropriate.  Instead You should try the lbfgs_search_strategy.\n        !*/\n\n    public:\n        bfgs_search_strategy(\n        );\n        /*!\n            ensures\n                - This object is properly initialized and ready to generate\n                  search directions.\n        !*/\n\n        double get_wolfe_rho (\n        ) const;\n        /*!\n            ensures\n                - returns the value of the Wolfe rho parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        double get_wolfe_sigma (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the Wolfe sigma parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        unsigned long get_max_line_search_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the max iterations parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - this function is only called once per search iteration\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - Assuming that a line search is going to be conducted starting from the point x,\n                  this function returns the direction in which the search should proceed.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class lbfgs_search_strategy\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for determining which direction\n                a line search should be carried out along.  This particular object\n                is an implementation of the L-BFGS quasi-newton method for determining \n                this direction.\n\n                This method uses an amount of memory that is linear in the number\n                of variables to be optimized.  This makes it an excellent method \n                to use when an optimization problem has a large number of variables.\n        !*/\n    public:\n        explicit lbfgs_search_strategy(\n            unsigned long max_size\n        ); \n        /*!\n            requires\n                - max_size > 0\n            ensures\n                - This object is properly initialized and ready to generate\n                  search directions.\n                - L-BFGS works by remembering a certain number of position and gradient \n                  pairs.  It uses this remembered information to compute search directions.\n                  The max_size argument determines how many of these pairs will be remembered.\n                  Typically, using between 3 and 30 pairs performs well for many problems.\n        !*/\n\n        double get_wolfe_rho (\n        ) const;\n        /*!\n            ensures\n                - returns the value of the Wolfe rho parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        double get_wolfe_sigma (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the Wolfe sigma parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        unsigned long get_max_line_search_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the max iterations parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        template <typename T>\n        const matrix<double,0,1>& get_next_direction (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - this function is only called once per search iteration\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - Assuming that a line search is going to be conducted starting from the point x,\n                  this function returns the direction in which the search should proceed.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename hessian_funct\n        >\n    class newton_search_strategy_obj\n    {\n        /*!\n            REQUIREMENTS ON hessian_funct\n                Objects of hessian_funct type must be function objects which\n                take a single argument and return a dlib::matrix of doubles.  The\n                single argument must be a dlib::matrix capable of representing\n                column vectors of doubles.  hessian_funct must also be copy \n                constructable.  \n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for determining which direction\n                a line search should be carried out along.  This particular object\n                is an implementation of the newton method for determining this \n                direction.  That is, it uses the following formula to determine\n                the direction:\n                    search_direction = -inv(hessian(x))*derivative\n        !*/\n    public:\n        explicit newton_search_strategy_obj(\n            const hessian_funct& hess\n        ); \n        /*!\n            ensures\n                - This object is properly initialized and ready to generate\n                  search directions.\n                - hess will be used by this object to generate the needed hessian\n                  matrices every time get_next_direction() is called.\n        !*/\n\n        double get_wolfe_rho (\n        ) const;\n        /*!\n            ensures\n                - returns the value of the Wolfe rho parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        double get_wolfe_sigma (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the Wolfe sigma parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        unsigned long get_max_line_search_iterations (\n        ) const; \n        /*!\n            ensures\n                - returns the value of the max iterations parameter that should be used when \n                  this search strategy is used with the line_search() function.\n        !*/\n\n        template <typename T>\n        const matrix<double,0,1> get_next_direction (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - Assuming that a line search is going to be conducted starting from the \n                  point x, this function returns the direction in which the search should \n                  proceed.\n                - In particular, the search direction will be given by:\n                    - search_direction = -inv(hessian(x))*funct_derivative\n        !*/\n\n    };\n\n    template <typename hessian_funct>\n    newton_search_strategy_obj<hessian_funct> newton_search_strategy (\n        hessian_funct hessian\n    ) { return newton_search_strategy_obj<hessian_funct>(hessian); }\n    /*!\n        ensures\n            - constructs and returns a newton_search_strategy_obj.  \n              This function is just a helper to make the syntax for creating\n              these objects a little simpler.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_SEARCH_STRATEGIES_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp2_using_smo.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SOLVE_QP2_USING_SMo_Hh_\n#define DLIB_SOLVE_QP2_USING_SMo_Hh_\n\n#include \"optimization_solve_qp2_using_smo_abstract.h\"\n#include <cmath>\n#include <limits>\n#include <sstream>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib \n{\n\n// ----------------------------------------------------------------------------------------\n\n    class invalid_nu_error : public dlib::error \n    { \n    public: \n        invalid_nu_error(const std::string& msg, double nu_) : dlib::error(msg), nu(nu_) {};\n        const double nu;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename T::type maximum_nu_impl (\n        const T& y\n    )\n    {\n        typedef typename T::type scalar_type;\n        // make sure requires clause is not broken\n        DLIB_ASSERT(y.size() > 1 && is_col_vector(y),\n            \"\\ttypedef T::type maximum_nu(y)\"\n            << \"\\n\\ty should be a column vector with more than one entry\"\n            << \"\\n\\ty.nr(): \" << y.nr() \n            << \"\\n\\ty.nc(): \" << y.nc() \n            );\n\n        long pos_count = 0;\n        long neg_count = 0;\n        for (long r = 0; r < y.nr(); ++r)\n        {\n            if (y(r) == 1.0)\n            {\n                ++pos_count;\n            }\n            else if (y(r) == -1.0)\n            {\n                ++neg_count;\n            }\n            else\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT(y(r) == -1.0 || y(r) == 1.0,\n                       \"\\ttypedef T::type maximum_nu(y)\"\n                       << \"\\n\\ty should contain only 1 and 0 entries\"\n                       << \"\\n\\tr:    \" << r \n                       << \"\\n\\ty(r): \" << y(r) \n                );\n            }\n        }\n        return static_cast<scalar_type>(2.0*(scalar_type)std::min(pos_count,neg_count)/(scalar_type)y.nr());\n    }\n\n    template <\n        typename T\n        >\n    typename T::type maximum_nu (\n        const T& y\n    )\n    {\n        return maximum_nu_impl(mat(y));\n    }\n\n    template <\n        typename T\n        >\n    typename T::value_type maximum_nu (\n        const T& y\n    )\n    {\n        return maximum_nu_impl(mat(y));\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class solve_qp2_using_smo\n    {\n    public:\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;\n\n\n        template <\n            typename EXP1,\n            typename EXP2,\n            long NR\n            >\n        unsigned long operator() ( \n            const matrix_exp<EXP1>& Q,\n            const matrix_exp<EXP2>& y,\n            const scalar_type nu,\n            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,\n            scalar_type eps\n        ) \n        {\n            DLIB_ASSERT(Q.nr() == Q.nc() && y.size() == Q.nr() && y.size() > 1 && is_col_vector(y) &&\n                        sum((y == +1) + (y == -1)) == y.size() &&\n                        0 < nu && nu <= 1 &&\n                        eps > 0,\n                \"\\t void solve_qp2_using_smo::operator()\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t Q.nr():                     \" << Q.nr() \n                << \"\\n\\t Q.nc():                     \" << Q.nc() \n                << \"\\n\\t is_col_vector(y):           \" << is_col_vector(y) \n                << \"\\n\\t y.size():                   \" << y.size() \n                << \"\\n\\t sum((y == +1) + (y == -1)): \" << sum((y == +1) + (y == -1)) \n                << \"\\n\\t nu:                         \" << nu \n                << \"\\n\\t eps:                        \" << eps \n                );\n\n            alpha.set_size(Q.nr(),1);\n            df.set_size(Q.nr());\n\n            // now initialize alpha\n            set_initial_alpha(y, nu, alpha);\n\n            const scalar_type tau = 1e-12;\n\n            typedef typename colm_exp<EXP1>::type col_type;\n\n            set_all_elements(df, 0);\n            // initialize df.  Compute df = Q*alpha\n            for (long r = 0; r < df.nr(); ++r)\n            {\n                if (alpha(r) != 0)\n                {\n                    df += alpha(r)*matrix_cast<scalar_type>(colm(Q,r));\n                }\n            }\n\n            unsigned long count = 0;\n\n            // now perform the actual optimization of alpha\n            long i=0, j=0;\n            while (find_working_group(y,alpha,Q,df,tau,eps,i,j))\n            {\n                ++count;\n                const scalar_type old_alpha_i = alpha(i);\n                const scalar_type old_alpha_j = alpha(j);\n\n                optimize_working_pair(alpha,Q,df,tau,i,j);\n\n                // update the df vector now that we have modified alpha(i) and alpha(j)\n                scalar_type delta_alpha_i = alpha(i) - old_alpha_i;\n                scalar_type delta_alpha_j = alpha(j) - old_alpha_j;\n\n                col_type Q_i = colm(Q,i);\n                col_type Q_j = colm(Q,j);\n                for(long k = 0; k < df.nr(); ++k)\n                    df(k) += Q_i(k)*delta_alpha_i + Q_j(k)*delta_alpha_j;\n            }\n\n            return count;\n        }\n\n        const column_matrix& get_gradient (\n        ) const { return df; }\n\n    private:\n\n    // -------------------------------------------------------------------------------------\n\n        template <\n            typename scalar_type,\n            typename scalar_vector_type,\n            typename scalar_vector_type2\n            >\n        inline void set_initial_alpha (\n            const scalar_vector_type& y,\n            const scalar_type nu,\n            scalar_vector_type2& alpha\n        ) const\n        {\n            set_all_elements(alpha,0);\n            const scalar_type l = y.nr();\n            scalar_type temp = nu*l/2;\n            long num = (long)std::floor(temp);\n            long num_total = (long)std::ceil(temp);\n\n            bool has_slack = false;\n            int count = 0;\n            for (int i = 0; i < alpha.nr(); ++i)\n            {\n                if (y(i) == 1)\n                {\n                    if (count < num)\n                    {\n                        ++count;\n                        alpha(i) = 1;\n                    }\n                    else \n                    {\n                        has_slack = true;\n                        if (num_total > num)\n                        {\n                            ++count;\n                            alpha(i) = temp - std::floor(temp);\n                        }\n                        break;\n                    }\n                }\n            }\n\n            if (count != num_total || has_slack == false)\n            {\n                std::ostringstream sout;\n                sout << \"Invalid nu of \" << nu << \".  It is required that: 0 < nu < \" << 2*(scalar_type)count/y.nr();\n                throw invalid_nu_error(sout.str(),nu);\n            }\n\n            has_slack = false;\n            count = 0;\n            for (int i = 0; i < alpha.nr(); ++i)\n            {\n                if (y(i) == -1)\n                {\n                    if (count < num)\n                    {\n                        ++count;\n                        alpha(i) = 1;\n                    }\n                    else \n                    {\n                        has_slack = true;\n                        if (num_total > num)\n                        {\n                            ++count;\n                            alpha(i) = temp - std::floor(temp);\n                        }\n                        break;\n                    }\n                }\n            }\n\n            if (count != num_total || has_slack == false)\n            {\n                std::ostringstream sout;\n                sout << \"Invalid nu of \" << nu << \".  It is required that: 0 < nu < \" << 2*(scalar_type)count/y.nr();\n                throw invalid_nu_error(sout.str(),nu);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename scalar_vector_type,\n            typename scalar_type,\n            typename EXP,\n            typename U, typename V\n            >\n        inline bool find_working_group (\n            const V& y,\n            const U& alpha,\n            const matrix_exp<EXP>& Q,\n            const scalar_vector_type& df,\n            const scalar_type tau,\n            const scalar_type eps,\n            long& i_out,\n            long& j_out\n        ) const\n        {\n            long ip = 0;\n            long jp = 0;\n            long in = 0;\n            long jn = 0;\n\n\n            typedef typename colm_exp<EXP>::type col_type;\n            typedef typename diag_exp<EXP>::type diag_type;\n\n            scalar_type ip_val = -std::numeric_limits<scalar_type>::infinity();\n            scalar_type jp_val = std::numeric_limits<scalar_type>::infinity();\n            scalar_type in_val = -std::numeric_limits<scalar_type>::infinity();\n            scalar_type jn_val = std::numeric_limits<scalar_type>::infinity();\n\n            // loop over the alphas and find the maximum ip and in indices.\n            for (long i = 0; i < alpha.nr(); ++i)\n            {\n                if (y(i) == 1)\n                {\n                    if (alpha(i) < 1.0)\n                    {\n                        if (-df(i) > ip_val)\n                        {\n                            ip_val = -df(i);\n                            ip = i;\n                        }\n                    }\n                }\n                else\n                {\n                    if (alpha(i) > 0.0)\n                    {\n                        if (df(i) > in_val)\n                        {\n                            in_val = df(i);\n                            in = i;\n                        }\n                    }\n                }\n            }\n\n            scalar_type Mp = std::numeric_limits<scalar_type>::infinity();\n            scalar_type Mn = std::numeric_limits<scalar_type>::infinity();\n\n            // Pick out the columns and diagonal of Q we need below.  Doing\n            // it this way is faster if Q is actually a symmetric_matrix_cache\n            // object.\n            col_type Q_ip = colm(Q,ip);\n            col_type Q_in = colm(Q,in);\n            diag_type Q_diag = diag(Q);\n\n\n\n            // now we need to find the minimum jp and jn indices\n            for (long j = 0; j < alpha.nr(); ++j)\n            {\n                if (y(j) == 1)\n                {\n                    if (alpha(j) > 0.0)\n                    {\n                        scalar_type b = ip_val + df(j);\n                        if (-df(j) < Mp)\n                            Mp = -df(j);\n\n                        if (b > 0)\n                        {\n                            scalar_type a = Q_ip(ip) + Q_diag(j) - 2*Q_ip(j); \n                            if (a <= 0)\n                                a = tau;\n                            scalar_type temp = -b*b/a;\n                            if (temp < jp_val)\n                            {\n                                jp_val = temp;\n                                jp = j;\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    if (alpha(j) < 1.0)\n                    {\n                        scalar_type b = in_val - df(j);\n                        if (df(j) < Mn)\n                            Mn = df(j);\n\n                        if (b > 0)\n                        {\n                            scalar_type a = Q_in(in) + Q_diag(j) - 2*Q_in(j); \n                            if (a <= 0)\n                                a = tau;\n                            scalar_type temp = -b*b/a;\n                            if (temp < jn_val)\n                            {\n                                jn_val = temp;\n                                jn = j;\n                            }\n                        }\n                    }\n                }\n            }\n\n            // if we are at the optimal point then return false so the caller knows\n            // to stop optimizing\n            if (std::max(ip_val - Mp, in_val - Mn) < eps)\n                return false;\n\n            if (jp_val < jn_val)\n            {\n                i_out = ip;\n                j_out = jp;\n            }\n            else\n            {\n                i_out = in;\n                j_out = jn;\n            }\n\n            return true;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename EXP,\n            typename T, typename U\n            >\n        inline void optimize_working_pair (\n            T& alpha,\n            const matrix_exp<EXP>& Q,\n            const U& df,\n            const scalar_type tau,\n            const long i,\n            const long j\n        ) const\n        {\n            scalar_type quad_coef = Q(i,i)+Q(j,j)-2*Q(j,i);\n            if (quad_coef <= 0)\n                quad_coef = tau;\n            scalar_type delta = (df(i)-df(j))/quad_coef;\n            scalar_type sum = alpha(i) + alpha(j);\n            alpha(i) -= delta;\n            alpha(j) += delta;\n\n            if(sum > 1)\n            {\n                if(alpha(i) > 1)\n                {\n                    alpha(i) = 1;\n                    alpha(j) = sum - 1;\n                }\n                else if(alpha(j) > 1)\n                {\n                    alpha(j) = 1;\n                    alpha(i) = sum - 1;\n                }\n            }\n            else\n            {\n                if(alpha(j) < 0)\n                {\n                    alpha(j) = 0;\n                    alpha(i) = sum;\n                }\n                else if(alpha(i) < 0)\n                {\n                    alpha(i) = 0;\n                    alpha(j) = sum;\n                }\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        column_matrix df; // gradient of f(alpha)\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SOLVE_QP2_USING_SMo_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp2_using_smo_abstract.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_\n#ifdef DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_\n\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class invalid_nu_error : public dlib::error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is an exception class used to indicate that a\n                value of nu given to the solve_qp2_using_smo object is incompatible \n                with the constraints of the quadratic program.\n\n                this->nu will be set to the invalid value of nu used.\n        !*/\n\n    public: \n        invalid_nu_error(const std::string& msg, double nu_) : dlib::error(msg), nu(nu_) {};\n        const double nu;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    typename T::type maximum_nu (\n        const T& y\n    );\n    /*!\n        requires\n            - T == a matrix object or an object convertible to a matrix via mat()\n            - is_col_vector(y) == true\n            - y.size() > 1\n            - sum((y == +1) + (y == -1)) == y.size()\n              (i.e. all elements of y must be equal to +1 or -1)\n        ensures\n            - returns the maximum valid nu that can be used with solve_qp2_using_smo and\n              the given y vector.\n              (i.e. 2.0*min(sum(y == +1), sum(y == -1))/y.size())\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class solve_qp2_using_smo\n    {\n        /*!\n            REQUIREMENTS ON matrix_type\n                Must be some type of dlib::matrix.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for solving the following quadratic programming\n                problem using the sequential minimal optimization algorithm:  \n\n                  Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha \n                  subject to the following constraints:\n                    - sum(alpha) == nu*y.size() \n                    - 0 <= min(alpha) && max(alpha) <= 1 \n                    - trans(y)*alpha == 0\n\n                  Where all elements of y must be equal to +1 or -1 and f is convex.  \n                  This means that Q should be symmetric and positive-semidefinite.\n                \n                \n                This object implements the strategy used by the LIBSVM tool.  The following papers\n                can be consulted for additional details:\n                    - Chang and Lin, Training {nu}-Support Vector Classifiers: Theory and Algorithms\n                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector \n                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm\n        !*/\n\n    public:\n\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;\n\n        template <\n            typename EXP1,\n            typename EXP2,\n            long NR\n            >\n        unsigned long operator() ( \n            const matrix_exp<EXP1>& Q,\n            const matrix_exp<EXP2>& y,\n            const scalar_type nu,\n            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,\n            scalar_type eps\n        );\n        /*!\n            requires\n                - Q.nr() == Q.nc()\n                - is_col_vector(y) == true\n                - y.size() == Q.nr()\n                - y.size() > 1\n                - sum((y == +1) + (y == -1)) == y.size()\n                  (i.e. all elements of y must be equal to +1 or -1)\n                - alpha must be capable of representing a vector of size y.size() elements\n                - 0 < nu <= 1\n                - eps > 0\n            ensures\n                - This function solves the quadratic program defined in this class's main comment.\n                - The solution to the quadratic program will be stored in #alpha.\n                - #alpha.size() == y.size()\n                - This function uses an implementation of the sequential minimal optimization \n                  algorithm.  It runs until the KKT violation is less than eps.  So eps controls \n                  how accurate the solution is and smaller values result in better solutions.\n                  (a reasonable eps is usually about 1e-3)\n                - #get_gradient() == Q*(#alpha)\n                  (i.e. stores the gradient of f() at #alpha in get_gradient())\n                - returns the number of iterations performed.  \n            throws\n                - invalid_nu_error\n                  This exception is thrown if nu >= maximum_nu(y).  \n                  (some values of nu cause the constraints to become impossible to satisfy. \n                  If this is detected then an exception is thrown).\n        !*/\n\n        const column_matrix& get_gradient (\n        ) const;\n        /*!\n            ensures\n                - returns the gradient vector at the solution of the last problem solved\n                  by this object.  If no problem has been solved then returns an empty\n                  vector.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_SOLVE_QP2_USING_SMO_ABSTRACT_H_\n\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp3_using_smo.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SOLVE_QP3_USING_SMo_Hh_\n#define DLIB_SOLVE_QP3_USING_SMo_Hh_\n\n#include \"optimization_solve_qp3_using_smo_abstract.h\"\n#include <cmath>\n#include <limits>\n#include <sstream>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib \n{\n\n// ----------------------------------------------------------------------------------------\n\n    class invalid_qp3_error : public dlib::error \n    { \n\n    public: \n        invalid_qp3_error(\n            const std::string& msg, \n            double B_,\n            double Cp_,\n            double Cn_\n        ) : \n            dlib::error(msg), \n            B(B_),\n            Cp(Cp_),\n            Cn(Cn_)\n        {};\n\n        const double B;\n        const double Cp;\n        const double Cn;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class solve_qp3_using_smo\n    {\n    public:\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;\n\n\n        template <\n            typename EXP1,\n            typename EXP2,\n            typename EXP3,\n            long NR\n            >\n        unsigned long operator() ( \n            const matrix_exp<EXP1>& Q,\n            const matrix_exp<EXP2>& p,\n            const matrix_exp<EXP3>& y,\n            const scalar_type B,\n            const scalar_type Cp,\n            const scalar_type Cn,\n            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,\n            scalar_type eps\n        ) \n        {\n            DLIB_ASSERT(Q.nr() == Q.nc() && y.size() == Q.nr() && p.size() == y.size() && \n                        y.size() > 0 && is_col_vector(y) && is_col_vector(p) &&\n                        sum((y == +1) + (y == -1)) == y.size() &&\n                        Cp > 0 && Cn > 0 &&\n                        eps > 0,\n                \"\\t void solve_qp3_using_smo::operator()\"\n                << \"\\n\\t invalid arguments were given to this function\"\n                << \"\\n\\t Q.nr():                     \" << Q.nr() \n                << \"\\n\\t Q.nc():                     \" << Q.nc() \n                << \"\\n\\t is_col_vector(p):           \" << is_col_vector(p) \n                << \"\\n\\t p.size():                   \" << p.size() \n                << \"\\n\\t is_col_vector(y):           \" << is_col_vector(y) \n                << \"\\n\\t y.size():                   \" << y.size() \n                << \"\\n\\t sum((y == +1) + (y == -1)): \" << sum((y == +1) + (y == -1)) \n                << \"\\n\\t Cp:                         \" << Cp\n                << \"\\n\\t Cn:                         \" << Cn\n                << \"\\n\\t eps:                        \" << eps \n                );\n\n\n\n            set_initial_alpha(y, B, Cp, Cn, alpha);\n\n\n            const scalar_type tau = 1e-12;\n\n            typedef typename colm_exp<EXP1>::type col_type;\n\n            // initialize df.  Compute df = Q*alpha + p\n            df = p;\n            for (long r = 0; r < df.nr(); ++r)\n            {\n                if (alpha(r) != 0)\n                {\n                    df += alpha(r)*matrix_cast<scalar_type>(colm(Q,r));\n                }\n            }\n\n            unsigned long count = 0;\n            // now perform the actual optimization of alpha\n            long i=0, j=0;\n            while (find_working_group(y,alpha,Q,df,Cp,Cn,tau,eps,i,j))\n            {\n                ++count;\n                const scalar_type old_alpha_i = alpha(i);\n                const scalar_type old_alpha_j = alpha(j);\n\n                optimize_working_pair(alpha,Q,y,df,tau,i,j, Cp, Cn );\n\n                // update the df vector now that we have modified alpha(i) and alpha(j)\n                scalar_type delta_alpha_i = alpha(i) - old_alpha_i;\n                scalar_type delta_alpha_j = alpha(j) - old_alpha_j;\n\n                col_type Q_i = colm(Q,i);\n                col_type Q_j = colm(Q,j);\n                for(long k = 0; k < df.nr(); ++k)\n                    df(k) += Q_i(k)*delta_alpha_i + Q_j(k)*delta_alpha_j;\n            }\n\n            return count;\n        }\n\n        const column_matrix& get_gradient (\n        ) const { return df; }\n\n    private:\n\n    // -------------------------------------------------------------------------------------\n\n        template <\n            typename scalar_type,\n            typename scalar_vector_type,\n            typename scalar_vector_type2\n            >\n        inline void set_initial_alpha (\n            const scalar_vector_type& y,\n            const scalar_type B,\n            const scalar_type Cp,\n            const scalar_type Cn,\n            scalar_vector_type2& alpha\n        ) const\n        {\n            alpha.set_size(y.size());\n\n            set_all_elements(alpha,0);\n\n            // It's easy in the B == 0 case\n            if (B == 0)\n                return;\n\n            const scalar_type C = (B > 0)?  Cp : Cn;\n\n            scalar_type temp = std::abs(B)/C;\n            long num = (long)std::floor(temp);\n            long num_total = (long)std::ceil(temp);\n\n            const scalar_type B_sign = (B > 0)? 1 : -1;\n\n            long count = 0;\n            for (long i = 0; i < alpha.nr(); ++i)\n            {\n                if (y(i) == B_sign)\n                {\n                    if (count < num)\n                    {\n                        ++count;\n                        alpha(i) = C;\n                    }\n                    else \n                    {\n                        if (count < num_total)\n                        {\n                            ++count;\n                            alpha(i) = C*(temp - std::floor(temp));\n                        }\n                        break;\n                    }\n                }\n            }\n\n            if (count != num_total)\n            {\n                std::ostringstream sout;\n                sout << \"Invalid QP3 constraint parameters of B: \" << B << \", Cp: \" << Cp << \", Cn: \"<< Cn;\n                throw invalid_qp3_error(sout.str(),B,Cp,Cn);\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename scalar_vector_type,\n            typename scalar_type,\n            typename EXP,\n            typename U, typename V\n            >\n        inline bool find_working_group (\n            const V& y,\n            const U& alpha,\n            const matrix_exp<EXP>& Q,\n            const scalar_vector_type& df,\n            const scalar_type Cp,\n            const scalar_type Cn,\n            const scalar_type tau,\n            const scalar_type eps,\n            long& i_out,\n            long& j_out\n        ) const\n        {\n            long ip = 0;\n            long jp = 0;\n\n            typedef typename colm_exp<EXP>::type col_type;\n            typedef typename diag_exp<EXP>::type diag_type;\n\n            scalar_type ip_val = -std::numeric_limits<scalar_type>::infinity();\n            scalar_type jp_val = std::numeric_limits<scalar_type>::infinity();\n\n            // loop over the alphas and find the maximum ip and in indices.\n            for (long i = 0; i < alpha.nr(); ++i)\n            {\n                if (y(i) == 1)\n                {\n                    if (alpha(i) < Cp)\n                    {\n                        if (-df(i) > ip_val)\n                        {\n                            ip_val = -df(i);\n                            ip = i;\n                        }\n                    }\n                }\n                else\n                {\n                    if (alpha(i) > 0.0)\n                    {\n                        if (df(i) > ip_val)\n                        {\n                            ip_val = df(i);\n                            ip = i;\n                        }\n                    }\n                }\n            }\n\n            scalar_type Mp = -std::numeric_limits<scalar_type>::infinity();\n\n            // Pick out the column and diagonal of Q we need below.  Doing\n            // it this way is faster if Q is actually a symmetric_matrix_cache\n            // object.\n            col_type Q_ip = colm(Q,ip);\n            diag_type Q_diag = diag(Q);\n\n\n\n            // now we need to find the minimum jp indices\n            for (long j = 0; j < alpha.nr(); ++j)\n            {\n                if (y(j) == 1)\n                {\n                    if (alpha(j) > 0.0)\n                    {\n                        scalar_type b = ip_val + df(j);\n                        if (df(j) > Mp)\n                            Mp = df(j);\n\n                        if (b > 0)\n                        {\n                            scalar_type a = Q_ip(ip) + Q_diag(j) - 2*y(ip)*Q_ip(j); \n                            if (a <= 0)\n                                a = tau;\n                            scalar_type temp = -b*b/a;\n                            if (temp < jp_val)\n                            {\n                                jp_val = temp;\n                                jp = j;\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    if (alpha(j) < Cn)\n                    {\n                        scalar_type b = ip_val - df(j);\n                        if (-df(j) > Mp)\n                            Mp = -df(j);\n\n                        if (b > 0)\n                        {\n                            scalar_type a = Q_ip(ip) + Q_diag(j) + 2*y(ip)*Q_ip(j); \n                            if (a <= 0)\n                                a = tau;\n                            scalar_type temp = -b*b/a;\n                            if (temp < jp_val)\n                            {\n                                jp_val = temp;\n                                jp = j;\n                            }\n                        }\n                    }\n                }\n            }\n\n            // if we are at the optimal point then return false so the caller knows\n            // to stop optimizing\n            if (Mp + ip_val < eps)\n                return false;\n\n\n            i_out = ip;\n            j_out = jp;\n\n            return true;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename EXP,\n            typename EXP2,\n            typename T, typename U\n            >\n        inline void optimize_working_pair (\n            T& alpha,\n            const matrix_exp<EXP>& Q,\n            const matrix_exp<EXP2>& y,\n            const U& df,\n            const scalar_type& tau,\n            const long i,\n            const long j,\n            const scalar_type& Cp,\n            const scalar_type& Cn\n        ) const\n        {\n            const scalar_type Ci = (y(i) > 0 )? Cp : Cn;\n            const scalar_type Cj = (y(j) > 0 )? Cp : Cn;\n\n            if (y(i) != y(j))\n            {\n                scalar_type quad_coef = Q(i,i)+Q(j,j)+2*Q(j,i);\n                if (quad_coef <= 0)\n                    quad_coef = tau;\n                scalar_type delta = (-df(i)-df(j))/quad_coef;\n                scalar_type diff = alpha(i) - alpha(j);\n                alpha(i) += delta;\n                alpha(j) += delta;\n\n                if (diff > 0)\n                {\n                    if (alpha(j) < 0)\n                    {\n                        alpha(j) = 0;\n                        alpha(i) = diff;\n                    }\n                }\n                else\n                {\n                    if (alpha(i) < 0)\n                    {\n                        alpha(i) = 0;\n                        alpha(j) = -diff;\n                    }\n                }\n\n                if (diff > Ci - Cj)\n                {\n                    if (alpha(i) > Ci)\n                    {\n                        alpha(i) = Ci;\n                        alpha(j) = Ci - diff;\n                    }\n                }\n                else\n                {\n                    if (alpha(j) > Cj)\n                    {\n                        alpha(j) = Cj;\n                        alpha(i) = Cj + diff;\n                    }\n                }\n            }\n            else\n            {\n                scalar_type quad_coef = Q(i,i)+Q(j,j)-2*Q(j,i);\n                if (quad_coef <= 0)\n                    quad_coef = tau;\n                scalar_type delta = (df(i)-df(j))/quad_coef;\n                scalar_type sum = alpha(i) + alpha(j);\n                alpha(i) -= delta;\n                alpha(j) += delta;\n\n                if(sum > Ci)\n                {\n                    if(alpha(i) > Ci)\n                    {\n                        alpha(i) = Ci;\n                        alpha(j) = sum - Ci;\n                    }\n                }\n                else\n                {\n                    if(alpha(j) < 0)\n                    {\n                        alpha(j) = 0;\n                        alpha(i) = sum;\n                    }\n                }\n\n                if(sum > Cj)\n                {\n                    if(alpha(j) > Cj)\n                    {\n                        alpha(j) = Cj;\n                        alpha(i) = sum - Cj;\n                    }\n                }\n                else\n                {\n                    if(alpha(i) < 0)\n                    {\n                        alpha(i) = 0;\n                        alpha(j) = sum;\n                    }\n                }\n\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        column_matrix df; // gradient of f(alpha)\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SOLVE_QP3_USING_SMo_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp3_using_smo_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_\n#ifdef DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_\n\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class invalid_qp3_error : public dlib::error \n    { \n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is an exception class used to indicate that the values \n                of B, Cp, and Cn given to the solve_qp3_using_smo object are incompatible \n                with the constraints of the quadratic program.\n\n                this->B, this->Cp, and this->Cn will be set to the invalid values used.\n        !*/\n\n    public: \n        invalid_qp3_error( const std::string& msg, double B_, double Cp_, double Cn_) : \n            dlib::error(msg), B(B_), Cp(Cp_), Cn(Cn_) {};\n\n        const double B;\n        const double Cp;\n        const double Cn;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename matrix_type\n        >\n    class solve_qp3_using_smo\n    {\n        /*!\n            REQUIREMENTS ON matrix_type\n                Must be some type of dlib::matrix.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for solving the following quadratic programming\n                problem using the sequential minimal optimization algorithm:  \n\n                  Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(p)*alpha\n                  subject to the following constraints:\n                    - for all i such that y(i) == +1:  0 <= alpha(i) <= Cp \n                    - for all i such that y(i) == -1:  0 <= alpha(i) <= Cn \n                    - trans(y)*alpha == B \n\n                  Where all elements of y must be equal to +1 or -1 and f is convex.  \n                  This means that Q should be symmetric and positive-semidefinite.\n                \n                \n                This object implements the strategy used by the LIBSVM tool.  The following papers\n                can be consulted for additional details:\n                    - Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector \n                      machines, 2001. Software available at http://www.csie.ntu.edu.tw/~cjlin/libsvm\n                    - Working Set Selection Using Second Order Information for Training Support Vector Machines by\n                      Fan, Chen, and Lin.  In the Journal of Machine Learning Research 2005.\n        !*/\n\n    public:\n\n        typedef typename matrix_type::mem_manager_type mem_manager_type;\n        typedef typename matrix_type::type scalar_type;\n        typedef typename matrix_type::layout_type layout_type;\n        typedef matrix<scalar_type,0,0,mem_manager_type,layout_type> general_matrix;\n        typedef matrix<scalar_type,0,1,mem_manager_type,layout_type> column_matrix;\n\n        template <\n            typename EXP1,\n            typename EXP2,\n            typename EXP3,\n            long NR\n            >\n        unsigned long operator() ( \n            const matrix_exp<EXP1>& Q,\n            const matrix_exp<EXP2>& p,\n            const matrix_exp<EXP3>& y,\n            const scalar_type B,\n            const scalar_type Cp,\n            const scalar_type Cn,\n            matrix<scalar_type,NR,1,mem_manager_type, layout_type>& alpha,\n            scalar_type eps\n        );\n        /*!\n            requires\n                - Q.nr() == Q.nc()\n                - is_col_vector(y) == true\n                - is_col_vector(p) == true\n                - p.size() == y.size() == Q.nr()\n                - y.size() > 0\n                - sum((y == +1) + (y == -1)) == y.size()\n                  (i.e. all elements of y must be equal to +1 or -1)\n                - alpha must be capable of representing a vector of size y.size() elements\n                - Cp > 0\n                - Cn > 0\n                - eps > 0\n            ensures\n                - This function solves the quadratic program defined in this class's main comment.\n                - The solution to the quadratic program will be stored in #alpha.\n                - #alpha.size() == y.size()\n                - This function uses an implementation of the sequential minimal optimization \n                  algorithm.  It runs until the KKT violation is less than eps.  So eps controls \n                  how accurate the solution is and smaller values result in better solutions.\n                  (a reasonable eps is usually about 1e-3)\n                - #get_gradient() == Q*(#alpha)\n                  (i.e. stores the gradient of f() at #alpha in get_gradient())\n                - returns the number of iterations performed.  \n            throws\n                - invalid_qp3_error\n                  This exception is thrown if the given parameters cause the constraints\n                  of the quadratic programming problem to be impossible to satisfy. \n        !*/\n\n        const column_matrix& get_gradient (\n        ) const;\n        /*!\n            ensures\n                - returns the gradient vector at the solution of the last problem solved\n                  by this object.  If no problem has been solved then returns an empty\n                  vector.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_SOLVE_QP3_USING_SMO_ABSTRACT_H_\n\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp_using_smo.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_\n#define DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_\n\n#include \"optimization_solve_qp_using_smo_abstract.h\"\n#include \"../matrix.h\"\n#include <map>\n#include \"../unordered_pair.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*\n        The algorithm defined in the solve_qp_using_smo() function below can be\n        derived by using an important theorem from the theory of constrained optimization.\n        This theorem tells us that any optimal point of a constrained function must\n        satisfy what are called the KKT conditions (also sometimes called just the KT \n        conditions, especially in older literature).  A very good book to consult \n        regarding this topic is Practical Methods of Optimization (second edition) by \n        R. Fletcher.  Below I will try to explain the general idea of how this is \n        applied.\n\n        Let e == ones_matrix(alpha.size(),1)\n\n        First, note that the function below solves the following quadratic program.  \n            Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b\n            subject to the following constraints:\n                - trans(e)*alpha == C (i.e. the sum of alpha values doesn't change)\n                - min(alpha) >= 0 (i.e. all alpha values are nonnegative)\n            Where f is convex.  This means that Q should be positive-semidefinite.\n\n\n        To get from this problem formulation to the algorithm below we have to \n        consider the KKT conditions.  They tell us that any solution to the above\n        problem must satisfy the following 5 conditions:\n            1. trans(e)*alpha == C\n            2. min(alpha) >= 0\n\n            3. Let L(alpha, x, y) == f(alpha) - trans(x)*alpha - y*(trans(e)*alpha - C)\n               Where x is a vector of length alpha.size() and y is a single scalar.\n               Then the derivative of L with respect to alpha must == 0\n               So we get the following as our 3rd condition:\n               f'(alpha) - x - y*e == 0\n\n            4. min(x) >= 0 (i.e. all x values are nonnegative)\n            5. pointwise_multiply(x, alpha) == 0\n               (i.e. only one member of each x(i) and alpha(i) pair can be non-zero)\n        \n        \n        From 3 we can easily obtain this rule:\n            for all i: f'(alpha)(i) - x(i) == y\n\n        If we then consider 4 and 5 we see that we can infer that the following\n        must also be the case:\n            - if (alpha(i) > 0) then\n                - x(i) == 0\n                - f'(alpha)(i) == y\n            - else\n                - x(i) == some nonnegative number\n                - f'(alpha)(i) >= y\n\n        \n        The important thing to take away is the final rule.  It tells us that at the\n        optimal solution all elements of the gradient of f have the same value if \n        their corresponding alpha is non-zero.  It also tells us that all the other\n        gradient values are bigger than y.  We can use this information to help us\n        pick which alpha variables to optimize at each iteration. \n    */\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_using_smo ( \n        const matrix_exp<EXP1>& Q,\n        const matrix_exp<EXP2>& b,\n        matrix<T,NR,NC,MM,L>& alpha,\n        T eps,\n        unsigned long max_iter\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(Q.nr() == Q.nc() &&\n                     is_col_vector(b) &&\n                     is_col_vector(alpha) &&\n                     b.size() == alpha.size() &&\n                     b.size() == Q.nr() &&\n                     alpha.size() > 0 &&\n                     min(alpha) >= 0 &&\n                     eps > 0 &&\n                     max_iter > 0,\n                     \"\\t unsigned long solve_qp_using_smo()\"\n                     << \"\\n\\t Invalid arguments were given to this function\"\n                     << \"\\n\\t Q.nr():               \" << Q.nr()\n                     << \"\\n\\t Q.nc():               \" << Q.nc()\n                     << \"\\n\\t is_col_vector(b):     \" << is_col_vector(b)\n                     << \"\\n\\t is_col_vector(alpha): \" << is_col_vector(alpha)\n                     << \"\\n\\t b.size():             \" << b.size() \n                     << \"\\n\\t alpha.size():         \" << alpha.size() \n                     << \"\\n\\t Q.nr():               \" << Q.nr() \n                     << \"\\n\\t min(alpha):           \" << min(alpha) \n                     << \"\\n\\t eps:                  \" << eps \n                     << \"\\n\\t max_iter:             \" << max_iter \n        );\n\n        const T C = sum(alpha);\n\n        // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha.  \n        matrix<T,NR,NC,MM,L> df = Q*alpha - b;\n\n        const T tau = 1000*std::numeric_limits<T>::epsilon();\n\n        T big, little;\n        unsigned long iter = 0;\n        for (; iter < max_iter; ++iter)\n        {\n            // Find the two elements of df that satisfy the following:\n            //    - little_idx == index_of_min(df)\n            //    - big_idx   == the index of the largest element in df such that alpha(big_idx) > 0\n            // These two indices will tell us which two alpha values are most in violation of the KKT \n            // optimality conditions.  \n            big = -std::numeric_limits<T>::max();\n            long big_idx = 0;\n            little = std::numeric_limits<T>::max();\n            long little_idx = 0;\n            for (long i = 0; i < df.nr(); ++i)\n            {\n                if (df(i) > big && alpha(i) > 0)\n                {\n                    big = df(i);\n                    big_idx = i;\n                }\n                if (df(i) < little)\n                {\n                    little = df(i);\n                    little_idx = i;\n                }\n            }\n\n            // Check if the KKT conditions are still violated and stop if so.  \n            //if (alpha(little_idx) > 0 && (big - little) < eps)\n            //    break;\n\n            // Check how big the duality gap is and stop when it goes below eps.  \n            // The duality gap is the gap between the objective value of the function\n            // we are optimizing and the value of its primal form.  This value is always \n            // greater than or equal to the distance to the optimum solution so it is a \n            // good way to decide if we should stop.   See the book referenced above for \n            // more information.  In particular, see the part about the Wolfe Dual.\n            if (trans(alpha)*df - C*little < eps)\n                break;\n\n\n            // Save these values, we will need them later.\n            const T old_alpha_big = alpha(big_idx);\n            const T old_alpha_little = alpha(little_idx);\n\n\n            // Now optimize the two variables we just picked. \n            T quad_coef = Q(big_idx,big_idx) + Q(little_idx,little_idx) - 2*Q(big_idx, little_idx);\n            if (quad_coef <= tau)\n                quad_coef = tau;\n            const T delta = (big - little)/quad_coef;\n            alpha(big_idx) -= delta;\n            alpha(little_idx) += delta;\n\n            // Make sure alpha stays feasible.  That is, make sure the updated alpha doesn't\n            // violate the non-negativity constraint.  \n            if (alpha(big_idx) < 0)\n            {\n                // Since an alpha can't be negative we will just set it to 0 and shift all the\n                // weight to the other alpha.\n                alpha(big_idx) = 0;\n                alpha(little_idx) = old_alpha_big + old_alpha_little;\n            }\n\n            // Every 300 iterations\n            if ((iter%300) == 299)\n            {\n                // Perform this form of the update every so often because doing so can help\n                // avoid the buildup of numerical errors you get with the alternate update\n                // below.\n                df = Q*alpha - b;\n            }\n            else\n            {\n                // Now update the gradient. We will perform the equivalent of: df = Q*alpha - b;\n                const T delta_alpha_big   = alpha(big_idx) - old_alpha_big;\n                const T delta_alpha_little = alpha(little_idx) - old_alpha_little;\n\n                for(long k = 0; k < df.nr(); ++k)\n                    df(k) += Q(big_idx,k)*delta_alpha_big + Q(little_idx,k)*delta_alpha_little;;\n            }\n        }\n\n        /*\n        cout << \"SMO: \" << endl;\n        cout << \"   duality gap: \"<< trans(alpha)*df - C*min(df) << endl;\n        cout << \"   KKT gap:     \"<< big-little << endl;\n        cout << \"   iter:        \"<< iter+1 << endl;\n        cout << \"   eps:         \"<< eps << endl;\n        */\n\n        return iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3,\n        typename EXP4,\n        typename T, long NR, long NC, typename MM, typename L,\n        long NR2, long NC2\n        >\n    unsigned long solve_qp4_using_smo ( \n        const matrix_exp<EXP1>& A,\n        const matrix_exp<EXP2>& Q,\n        const matrix_exp<EXP3>& b,\n        const matrix_exp<EXP4>& d,\n        matrix<T,NR,NC,MM,L>& alpha,\n        matrix<T,NR2,NC2,MM,L>& lambda,\n        T eps,\n        unsigned long max_iter,\n        T max_lambda = std::numeric_limits<T>::infinity()\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(A.nc() == alpha.size() &&\n                     Q.nr() == Q.nc() &&\n                     is_col_vector(b) &&\n                     is_col_vector(alpha) &&\n                     b.size() == alpha.size() &&\n                     b.size() == Q.nr() &&\n                     alpha.size() > 0 &&\n                     min(alpha) >= 0 &&\n                     eps > 0 &&\n                     max_iter > 0,\n                     \"\\t void solve_qp4_using_smo()\"\n                     << \"\\n\\t Invalid arguments were given to this function\"\n                     << \"\\n\\t A.nc():               \" << A.nc()\n                     << \"\\n\\t Q.nr():               \" << Q.nr()\n                     << \"\\n\\t Q.nc():               \" << Q.nc()\n                     << \"\\n\\t is_col_vector(b):     \" << is_col_vector(b)\n                     << \"\\n\\t is_col_vector(alpha): \" << is_col_vector(alpha)\n                     << \"\\n\\t b.size():             \" << b.size() \n                     << \"\\n\\t alpha.size():         \" << alpha.size() \n                     << \"\\n\\t Q.nr():               \" << Q.nr() \n                     << \"\\n\\t min(alpha):           \" << min(alpha) \n                     << \"\\n\\t eps:                  \" << eps \n                     << \"\\n\\t max_iter:             \" << max_iter \n        );\n        DLIB_ASSERT(is_col_vector(d) == true &&\n                     max_lambda >= 0 &&\n                     d.size() == A.nr(),\n                     \"\\t void solve_qp4_using_smo()\"\n                     << \"\\n\\t Invalid arguments were given to this function\"\n                     << \"\\n\\t A.nr():     \" << A.nr()\n                     << \"\\n\\t d.size():   \" << d.size()\n                     << \"\\n\\t max_lambda: \" << max_lambda\n        );\n\n        const T C = sum(alpha);\n\n        /*\n            For this optimization problem, it is the case that the optimal\n            value of lambda is given by a simple closed form expression if we\n            know the optimal alpha.  So what we will do is to just optimize \n            alpha and every now and then we will update lambda with its optimal\n            value.  Therefore, we use essentially the same method as the\n            solve_qp_using_smo() routine.  \n        */\n\n        const bool d_is_zero = d==zeros_matrix(d);\n\n        // compute optimal lambda for current alpha\n        if (d_is_zero)\n            lambda = A*alpha;\n        else\n            lambda = A*alpha + d;\n        lambda = dlib::clamp(lambda, 0, max_lambda);\n\n        // Compute f'(alpha) (i.e. the gradient of f(alpha) with respect to alpha) for the current alpha.  \n        matrix<T,NR,NC,MM,L> df = Q*alpha - b - trans(A)*lambda;\n\n        const T tau = 1000*std::numeric_limits<T>::epsilon();\n\n        T big, little;\n        unsigned long iter = 0;\n        for (; iter < max_iter; ++iter)\n        {\n            // Find the two elements of df that satisfy the following:\n            //    - little_idx == index_of_min(df)\n            //    - big_idx   == the index of the largest element in df such that alpha(big_idx) > 0\n            // These two indices will tell us which two alpha values are most in violation of the KKT \n            // optimality conditions.  \n            big = -std::numeric_limits<T>::max();\n            long big_idx = 0;\n            little = std::numeric_limits<T>::max();\n            long little_idx = 0;\n            for (long i = 0; i < df.nr(); ++i)\n            {\n                if (df(i) > big && alpha(i) > 0)\n                {\n                    big = df(i);\n                    big_idx = i;\n                }\n                if (df(i) < little)\n                {\n                    little = df(i);\n                    little_idx = i;\n                }\n            }\n\n            // Check how big the duality gap is and stop when it goes below eps.  \n            // The duality gap is the gap between the objective value of the function\n            // we are optimizing and the value of its primal form.  This value is always \n            // greater than or equal to the distance to the optimum solution so it is a \n            // good way to decide if we should stop.   \n            if (trans(alpha)*df - C*little < eps)\n            {\n                // compute optimal lambda and recheck the duality gap to make\n                // sure we have really converged.\n                if (d_is_zero)\n                    lambda = A*alpha;\n                else\n                    lambda = A*alpha + d;\n                lambda = dlib::clamp(lambda, 0, max_lambda);\n                df = Q*alpha - b - trans(A)*lambda;\n\n                if (trans(alpha)*df - C*min(df) < eps)\n                    break;\n                else\n                    continue;\n            }\n\n\n            // Save these values, we will need them later.\n            const T old_alpha_big = alpha(big_idx);\n            const T old_alpha_little = alpha(little_idx);\n\n\n            // Now optimize the two variables we just picked. \n            T quad_coef = Q(big_idx,big_idx) + Q(little_idx,little_idx) - 2*Q(big_idx, little_idx);\n            if (quad_coef <= tau)\n                quad_coef = tau;\n            const T delta = (big - little)/quad_coef;\n            alpha(big_idx) -= delta;\n            alpha(little_idx) += delta;\n\n            // Make sure alpha stays feasible.  That is, make sure the updated alpha doesn't\n            // violate the non-negativity constraint.  \n            if (alpha(big_idx) < 0)\n            {\n                // Since an alpha can't be negative we will just set it to 0 and shift all the\n                // weight to the other alpha.\n                alpha(big_idx) = 0;\n                alpha(little_idx) = old_alpha_big + old_alpha_little;\n            }\n\n\n            // Every 300 iterations\n            if ((iter%300) == 299)\n            {\n                // compute the optimal lambda for the current alpha\n                if (d_is_zero)\n                    lambda = A*alpha;\n                else\n                    lambda = A*alpha + d;\n                lambda = dlib::clamp(lambda, 0, max_lambda);\n\n                // Perform this form of the update every so often because doing so can help\n                // avoid the buildup of numerical errors you get with the alternate update\n                // below.\n                df = Q*alpha - b - trans(A)*lambda;\n            }\n            else\n            {\n                // Now update the gradient. We will perform the equivalent of: df = Q*alpha - b;\n                const T delta_alpha_big   = alpha(big_idx) - old_alpha_big;\n                const T delta_alpha_little = alpha(little_idx) - old_alpha_little;\n\n                for(long k = 0; k < df.nr(); ++k)\n                    df(k) += Q(big_idx,k)*delta_alpha_big + Q(little_idx,k)*delta_alpha_little;;\n            }\n        }\n\n        /*\n        cout << \"SMO: \" << endl;\n        cout << \"   duality gap: \"<< trans(alpha)*df - C*min(df) << endl;\n        cout << \"   KKT gap:     \"<< big-little << endl;\n        cout << \"   iter:        \"<< iter+1 << endl;\n        cout << \"   eps:         \"<< eps << endl;\n        */\n\n\n        return iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_box_constrained ( \n        const matrix_exp<EXP1>& Q,\n        const matrix_exp<EXP2>& b,\n        matrix<T,NR,NC,MM,L>& alpha,\n        const matrix<T,NR,NC,MM,L>& lower,\n        const matrix<T,NR,NC,MM,L>& upper,\n        T eps = 1e-10,\n        unsigned long max_iter = 30000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(Q.nr() == Q.nc() &&\n                     alpha.size() == lower.size() &&\n                     alpha.size() == upper.size() &&\n                     is_col_vector(b) &&\n                     is_col_vector(alpha) &&\n                     is_col_vector(lower) &&\n                     is_col_vector(upper) &&\n                     b.size() == alpha.size() &&\n                     b.size() == Q.nr() &&\n                     alpha.size() > 0 &&\n                     0 <= min(alpha-lower) &&\n                     0 <= max(upper-alpha) &&\n                     eps > 0 &&\n                     max_iter > 0,\n                     \"\\t unsigned long solve_qp_box_constrained()\"\n                     << \"\\n\\t Invalid arguments were given to this function\"\n                     << \"\\n\\t Q.nr():               \" << Q.nr()\n                     << \"\\n\\t Q.nc():               \" << Q.nc()\n                     << \"\\n\\t is_col_vector(b):     \" << is_col_vector(b)\n                     << \"\\n\\t is_col_vector(alpha): \" << is_col_vector(alpha)\n                     << \"\\n\\t is_col_vector(lower): \" << is_col_vector(lower)\n                     << \"\\n\\t is_col_vector(upper): \" << is_col_vector(upper)\n                     << \"\\n\\t b.size():             \" << b.size() \n                     << \"\\n\\t alpha.size():         \" << alpha.size() \n                     << \"\\n\\t lower.size():         \" << lower.size() \n                     << \"\\n\\t upper.size():         \" << upper.size() \n                     << \"\\n\\t Q.nr():               \" << Q.nr() \n                     << \"\\n\\t min(alpha-lower):     \" << min(alpha-lower) \n                     << \"\\n\\t max(upper-alpha):     \" << max(upper-alpha) \n                     << \"\\n\\t eps:                  \" << eps \n                     << \"\\n\\t max_iter:             \" << max_iter \n        );\n\n\n        // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha.  \n        matrix<T,NR,NC,MM,L> df = Q*alpha + b;\n        matrix<T,NR,NC,MM,L> QQ = reciprocal_max(diag(Q));\n\n        // First we use a coordinate descent method to initialize alpha. \n        double max_df = 0;\n        for (long iter = 0; iter < alpha.size()*2; ++iter)\n        {\n            max_df = 0;\n            long best_r =0;\n            // find the best alpha to optimize.\n            for (long r = 0; r < Q.nr(); ++r)\n            {\n                if (alpha(r) <= lower(r) && df(r) > 0)\n                    ;//alpha(r) = lower(r);\n                else if (alpha(r) >= upper(r) && df(r) < 0)\n                    ;//alpha(r) = upper(r);\n                else if (std::abs(df(r)) > max_df)\n                {\n                    best_r = r;\n                    max_df = std::abs(df(r));\n                }\n            }\n\n            // now optimize alpha(best_r)\n            const long r = best_r;\n            const T old_alpha = alpha(r);\n            alpha(r) = -(df(r)-Q(r,r)*alpha(r))*QQ(r);\n            if (alpha(r) < lower(r))\n                alpha(r) = lower(r);\n            else if (alpha(r) > upper(r))\n                alpha(r) = upper(r);\n\n            const T delta = old_alpha-alpha(r);\n\n            // Now update the gradient. We will perform the equivalent of: df = Q*alpha + b;\n            for(long k = 0; k < df.nr(); ++k)\n                df(k) -= Q(r,k)*delta;\n        }\n        //cout << \"max_df: \" << max_df << endl;\n        //cout << \"objective value: \" << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha << endl;\n\n\n\n        // Now do the main iteration block of this solver.  The coordinate descent method\n        // we used above can improve the objective rapidly in the beginning.  However,\n        // Nesterov's method has more rapid convergence once it gets going so this is what\n        // we use for the main iteration.\n        matrix<T,NR,NC,MM,L> v, v_old; \n        v = alpha;\n        // We need to get an upper bound on the Lipschitz constant for this QP. Since that\n        // is just the max eigenvalue of Q we can do it using Gershgorin disks.\n        const T lipschitz_bound = max(diag(Q) + (sum_cols(abs(Q)) - abs(diag(Q))));\n        double lambda = 1;\n        unsigned long iter;\n        for (iter = 0; iter < max_iter; ++iter)\n        {\n            const double next_lambda = (1 + std::sqrt(1+4*lambda*lambda))/2;\n            const double gamma = (1-lambda)/next_lambda;\n            lambda = next_lambda;\n\n            v_old = v;\n\n            // now take a projected gradient step using Nesterov's method.\n            v = clamp(alpha - 1.0/lipschitz_bound * df, lower, upper);\n            alpha = dlib::clamp((1-gamma)*v + gamma*v_old, lower, upper);\n\n            df = Q*alpha + b;\n\n            // check for convergence every 10 iterations\n            if (iter%10 == 0)\n            {\n                max_df = 0;\n                double absalpha = 0;\n                double thealpha = 0;\n                for (long r = 0; r < Q.nr(); ++r)\n                {\n                    absalpha += std::abs(alpha(r));\n                    if (alpha(r) <= lower(r) && df(r) > 0)\n                        ;//alpha(r) = lower(r);\n                    else if (alpha(r) >= upper(r) && df(r) < 0)\n                        ;//alpha(r) = upper(r);\n                    else if (std::abs(df(r)) > max_df)\n                    {\n                        max_df = std::abs(df(r));\n                        thealpha = std::abs(alpha(r));\n                    }\n                }\n                absalpha /= Q.nr();\n                // Stop when the magnitude of the changes we are making to alpha are eps\n                // smaller than the typical alpha.\n                if (max_df/lipschitz_bound <= eps*std::min(thealpha,absalpha))\n                    break;\n            }\n        }\n\n        //cout << \"max_df: \" << max_df << endl;\n        //cout << \"objective value: \" << 0.5*trans(alpha)*Q*alpha + trans(b)*alpha << endl;\n        return iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        // Check if each vector in Q_offdiag is actually a constant times the 1s vector.\n        template <\n            typename T, long NR, long NC, typename MM, typename L\n            >\n        bool has_uniform_offdiag_vectors(\n            const std::map<unordered_pair<size_t>, matrix<T,NR,NC,MM,L>>& Q_offdiag\n        )\n        {\n            for (auto& x : Q_offdiag)\n            {\n                auto ref = x.second(0);\n                for (auto& y : x.second)\n                    if (ref != y)\n                        return false;\n            }\n            return true;\n        }\n\n        template <\n            typename T, long NR, long NC, typename MM, typename L\n            >\n        matrix<T,0,0,MM,L> compact_offdiag(\n            const size_t& num_blocks,\n            const std::map<unordered_pair<size_t>, matrix<T,NR,NC,MM,L>>& Q_offdiag\n        )\n        {\n            matrix<T,0,0,MM,L> temp;\n            // we can only compact the offdiag information if they are uniform vectors\n            if (!has_uniform_offdiag_vectors(Q_offdiag))\n                return temp;\n\n            temp.set_size(num_blocks, num_blocks);\n            temp = 0;\n\n            for (auto& x : Q_offdiag)\n            {\n                long r = x.first.first;\n                long c = x.first.second;\n                temp(r,c) = x.second(0);\n                temp(c,r) = x.second(0);\n            }\n\n            return temp;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_box_constrained_blockdiag ( \n        const std::vector<matrix<T,NR,NR,MM,L>>& Q_blocks,\n        const std::vector<matrix<T,NR,NC,MM,L>>& bs,\n        const std::map<unordered_pair<size_t>, matrix<T,NR,NC,MM,L>>& Q_offdiag,\n        std::vector<matrix<T,NR,NC,MM,L>>& alphas,\n        const std::vector<matrix<T,NR,NC,MM,L>>& lowers,\n        const std::vector<matrix<T,NR,NC,MM,L>>& uppers,\n        T eps = 1e-10,\n        unsigned long max_iter = 30000\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(Q_blocks.size() > 0);\n        DLIB_CASSERT(Q_blocks.size() == bs.size() && \n                     Q_blocks.size() == alphas.size() &&\n                     Q_blocks.size() == lowers.size() &&\n                     Q_blocks.size() == uppers.size(),\n                   \"Q_blocks.size():  \"<< Q_blocks.size() << \"\\n\" <<\n                   \"bs.size():        \"<< bs.size() << \"\\n\" <<\n                   \"alphas.size():    \"<< alphas.size() << \"\\n\" <<\n                   \"lowers.size():    \"<< lowers.size() << \"\\n\" <<\n                   \"uppers.size():    \"<< uppers.size() << \"\\n\"\n                   );\n        for (auto& Q : Q_blocks)\n        {\n            DLIB_CASSERT(Q.nr() == Q.nc(), \"All the matrices in Q_blocks have the same dimensions.\");\n            DLIB_CASSERT(Q.size() > 0, \"All the matrices in Q_blocks must be non-empty and have the same dimensions.\");\n            DLIB_CASSERT(Q.nr() == Q_blocks[0].nr() && Q.nc() == Q_blocks[0].nc(), \"All the matrices in Q_blocks have the same dimensions.\");\n        }\n#ifdef ENABLE_ASSERTS\n        for (size_t i = 0; i < alphas.size(); ++i)\n        {\n            DLIB_CASSERT(is_col_vector(bs[i]) && bs[i].size() == Q_blocks[0].nr(),\n                \"is_col_vector(bs[\"<<i<<\"]): \" << is_col_vector(bs[i]) << \"\\n\" <<\n                \"bs[\"<<i<<\"].size():         \" << bs[i].size() << \"\\n\" <<\n                \"Q_blocks[0].nr():           \" << Q_blocks[0].nr());\n\n            for (auto& Qoffdiag : Q_offdiag)\n            {\n                auto& Q_offdiag_element = Qoffdiag.second;\n                long r = Qoffdiag.first.first;\n                long c = Qoffdiag.first.second;\n                DLIB_CASSERT(is_col_vector(Q_offdiag_element) && Q_offdiag_element.size() == Q_blocks[0].nr(),\n                    \"is_col_vector(Q_offdiag[\"<<r<<\",\"<<c<<\"]): \" << is_col_vector(Q_offdiag_element) << \"\\n\" <<\n                    \"Q_offdiag[\"<<r<<\",\"<<c<<\"].size():         \" << Q_offdiag_element.size() << \"\\n\" <<\n                    \"Q_blocks[0].nr():                  \" << Q_blocks[0].nr());\n            }\n\n            DLIB_CASSERT(is_col_vector(alphas[i]) && alphas[i].size() == Q_blocks[0].nr(),\n                \"is_col_vector(alphas[\"<<i<<\"]): \" << is_col_vector(alphas[i]) << \"\\n\" <<\n                \"alphas[\"<<i<<\"].size():         \" << alphas[i].size() << \"\\n\" <<\n                \"Q_blocks[0].nr():               \" << Q_blocks[0].nr());\n\n            DLIB_CASSERT(is_col_vector(lowers[i]) && lowers[i].size() == Q_blocks[0].nr(),\n                \"is_col_vector(lowers[\"<<i<<\"]): \" << is_col_vector(lowers[i]) << \"\\n\" <<\n                \"lowers[\"<<i<<\"].size():         \" << lowers[i].size() << \"\\n\" <<\n                \"Q_blocks[0].nr():               \" << Q_blocks[0].nr());\n\n            DLIB_CASSERT(is_col_vector(uppers[i]) && uppers[i].size() == Q_blocks[0].nr(),\n                \"is_col_vector(uppers[\"<<i<<\"]): \" << is_col_vector(uppers[i]) << \"\\n\" <<\n                \"uppers[\"<<i<<\"].size():         \" << uppers[i].size() << \"\\n\" <<\n                \"Q_blocks[0].nr():               \" << Q_blocks[0].nr());\n\n            DLIB_CASSERT(0 <= min(alphas[i]-lowers[i]), \"min(alphas[\"<<i<<\"]-lowers[\"<<i<<\"]): \" << min(alphas[i]-lowers[i]));\n            DLIB_CASSERT(0 <= max(uppers[i]-alphas[i]), \"max(uppers[\"<<i<<\"]-alphas[\"<<i<<\"]): \" << max(uppers[i]-alphas[i]));\n        }\n        DLIB_CASSERT(eps > 0 && max_iter > 0, \"eps: \" << eps << \"\\nmax_iter: \"<< max_iter);\n#endif // ENABLE_ASSERTS\n\n\n        const auto offdiag_compact = impl::compact_offdiag(Q_blocks.size(), Q_offdiag);\n        matrix<T,0,0,MM,L> temp, alphas_compact;\n\n        // Compute f'(alpha) (i.e. the gradient of f(alpha)) for the current alpha.  \n        std::vector<matrix<T,NR,NC,MM,L>> df;// = Q*alpha + b;\n        auto compute_df = [&]()\n        {\n            df.resize(Q_blocks.size());\n            for (size_t i = 0; i < df.size(); ++i)\n                df[i] = Q_blocks[i]*alphas[i] + bs[i];\n\n\n            // Don't forget to include the Q_offdiag terms in the computation.  Note that\n            // we have two options for how we can compute this part.  If Q_offdiag is\n            // uniform and can be compacted into a simple matrix and there are a lot of off\n            // diagonal entries then it's faster to do it as a matrix multiply.  Otherwise\n            // we do the more general computation.\n            if (offdiag_compact.size() != 0 && Q_offdiag.size() > Q_blocks.size()*5)\n            {\n                // Do it as a matrix multiply (with a bit of data shuffling)\n                alphas_compact.set_size(alphas[0].size(), offdiag_compact.nr());\n                for (long c = 0; c < alphas_compact.nc(); ++c)\n                    set_colm(alphas_compact,c) = alphas[c];\n                temp = alphas_compact*offdiag_compact;\n                for (size_t i = 0; i < df.size(); ++i)\n                    df[i] += colm(temp,i);\n            }\n            else\n            {\n                // Do the fully general computation that allows for non-uniform values in\n                // the off diagonal vectors.\n                for (auto& p : Q_offdiag)\n                {\n                    long r = p.first.first;\n                    long c = p.first.second;\n                    df[r] += pointwise_multiply(p.second, alphas[c]);\n                    if (r != c)\n                        df[c] += pointwise_multiply(p.second, alphas[r]);\n                }\n            }\n        };\n        compute_df();\n\n\n\n        std::vector<matrix<T,NR,NC,MM,L>> Q_diag, Q_ggd;\n        std::vector<matrix<T,NR,NC,MM,L>> QQ;// = reciprocal_max(diag(Q));\n        QQ.resize(Q_blocks.size());\n        Q_diag.resize(Q_blocks.size());\n        Q_ggd.resize(Q_blocks.size());\n\n        // We need to get an upper bound on the Lipschitz constant for this QP. Since that\n        // is just the max eigenvalue of Q we can do it using Gershgorin disks.\n        //const T lipschitz_bound = max(diag(Q) + (sum_cols(abs(Q)) - abs(diag(Q))));\n        for (size_t i = 0; i < QQ.size(); ++i)\n        {\n            auto f = Q_offdiag.find(make_unordered_pair(i,i));\n            if (f != Q_offdiag.end())\n                Q_diag[i] = diag(Q_blocks[i]) + f->second;\n            else\n                Q_diag[i] = diag(Q_blocks[i]);\n            QQ[i] = reciprocal_max(Q_diag[i]);\n\n            Q_ggd[i] = Q_diag[i] + (sum_cols(abs(Q_blocks[i]))-abs(diag(Q_blocks[i])));\n        }\n        for (auto& p : Q_offdiag)\n        {\n            long r = p.first.first;\n            long c = p.first.second;\n            if (r != c)\n            {\n                Q_ggd[r] += abs(p.second);\n                Q_ggd[c] += abs(p.second);\n            }\n        }\n        T lipschitz_bound = -std::numeric_limits<T>::infinity();\n        for (auto& x : Q_ggd)\n            lipschitz_bound = std::max(lipschitz_bound, max(x));\n\n\n        const long num_variables = alphas.size()*alphas[0].size();\n\n        // First we use a coordinate descent method to initialize alpha. \n        double max_df = 0;\n        for (long iter = 0; iter < num_variables*2; ++iter)\n        {\n            max_df = 0;\n            long best_r =0;\n            size_t best_r2 =0;\n            // find the best alpha to optimize.\n            for (size_t r2 = 0; r2 < alphas.size(); ++r2) \n            {\n                auto& alpha = alphas[r2];\n                auto& df_ = df[r2];\n                auto& lower = lowers[r2];\n                auto& upper = uppers[r2];\n                for (long r = 0; r < alpha.nr(); ++r)\n                {\n                    if (alpha(r) <= lower(r) && df_(r) > 0)\n                        ;//alpha(r) = lower(r);\n                    else if (alpha(r) >= upper(r) && df_(r) < 0)\n                        ;//alpha(r) = upper(r);\n                    else if (std::abs(df_(r)) > max_df)\n                    {\n                        best_r = r;\n                        best_r2 = r2;\n                        max_df = std::abs(df_(r));\n                    }\n                }\n            }\n\n            // now optimize alphas[best_r2](best_r)\n            const long r = best_r;\n            auto& alpha = alphas[best_r2];\n            auto& lower = lowers[best_r2];\n            auto& upper = uppers[best_r2];\n            auto& df_ = df[best_r2];\n            const T old_alpha = alpha(r);\n            alpha(r) = -(df_(r)-Q_diag[best_r2](r)*alpha(r))*QQ[best_r2](r);\n            if (alpha(r) < lower(r))\n                alpha(r) = lower(r);\n            else if (alpha(r) > upper(r))\n                alpha(r) = upper(r);\n\n            const T delta = old_alpha-alpha(r);\n\n            // Now update the gradient. We will perform the equivalent of: df = Q*alpha +\n            // b; except we only need to compute one column of the matrix multiply because\n            // only one element of alpha changed.\n            auto& Q = Q_blocks[best_r2];\n            for(long k = 0; k < df_.nr(); ++k)\n                df_(k) -= Q(r,k)*delta;\n            for(size_t j = 0; j < Q_blocks.size(); ++j)\n            {\n                auto f = Q_offdiag.find(make_unordered_pair(best_r2, j));\n                if (f != Q_offdiag.end())\n                    df[j](r) -= f->second(r)*delta;\n            }\n        }\n\n\n\n\n        std::vector<matrix<T,NR,NC,MM,L>> v(alphas), v_old(alphas.size());\n        double lambda = 1;\n        unsigned long iter;\n        // Now do the main iteration block of this solver.  The coordinate descent method\n        // we used above can improve the objective rapidly in the beginning.  However,\n        // Nesterov's method has more rapid convergence once it gets going so this is what\n        // we use for the main iteration.\n        for (iter = 0; iter < max_iter; ++iter)\n        {\n            const double next_lambda = (1 + std::sqrt(1+4*lambda*lambda))/2;\n            const double gamma = (1-lambda)/next_lambda;\n            lambda = next_lambda;\n\n            v_old.swap(v);\n\n\n            // now take a projected gradient step using Nesterov's method.\n            for (size_t j = 0; j < alphas.size(); ++j)\n            {\n                v[j] = clamp(alphas[j] - 1.0/lipschitz_bound * df[j], lowers[j], uppers[j]);\n                alphas[j] = clamp((1-gamma)*v[j] + gamma*v_old[j], lowers[j], uppers[j]);\n            }\n\n            //df = Q*alpha + b;\n            compute_df();\n\n            // check for convergence every 10 iterations\n            if (iter%10 == 0)\n            {\n                max_df = 0;\n                double absalpha = 0;\n                double thealpha = 0;\n                for (size_t r2 = 0; r2 < alphas.size(); ++r2) \n                {\n                    auto& alpha = alphas[r2];\n                    auto& df_ = df[r2];\n                    auto& lower = lowers[r2];\n                    auto& upper = uppers[r2];\n                    for (long r = 0; r < alpha.nr(); ++r)\n                    {\n                        absalpha += std::abs(alpha(r));\n                        if (alpha(r) <= lower(r) && df_(r) > 0)\n                            ;//alpha(r) = lower(r);\n                        else if (alpha(r) >= upper(r) && df_(r) < 0)\n                            ;//alpha(r) = upper(r);\n                        else if (std::abs(df_(r)) > max_df)\n                        {\n                            max_df = std::abs(df_(r));\n                            thealpha = std::abs(alpha(r));\n                        }\n                    }\n                }\n                absalpha /= num_variables;\n                // Stop when the magnitude of the changes we are making to alpha are eps\n                // smaller than the typical alpha.\n                if (max_df/lipschitz_bound <= eps*std::min(thealpha,absalpha))\n                    break;\n            }\n        }\n\n        return iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NRa, long NRb\n        >\n    unsigned long find_gap_between_convex_hulls (\n        const matrix_exp<EXP1>& A,\n        const matrix_exp<EXP2>& B,\n        matrix<T,NRa,1>& cA,\n        matrix<T,NRb,1>& cB,\n        const double eps,\n        const unsigned long max_iter = 1000\n    )\n    {\n        DLIB_CASSERT(A.size() != 0);\n        DLIB_CASSERT(B.size() != 0);\n        DLIB_CASSERT(A.nr() == B.nr(), \"The dimensionality of the points in both convex hull sets must match\");\n        DLIB_CASSERT(eps > 0);\n        DLIB_CASSERT(max_iter > 0);\n\n        cA.set_size(A.nc());\n        cB.set_size(B.nc());\n\n        // initialize to the centroids of A and B respectively.\n        cA = 1.0/cA.size();\n        cB = 1.0/cB.size();\n\n\n        matrix<T> AA, BB, AB, ABb, ABa;\n\n        AA = trans(A)*A;\n        BB = trans(B)*B;\n        AB = trans(A)*B;\n\n        unsigned long iter = 0;\n        for (iter = 0; iter < max_iter; ++iter)\n        {\n            // find the convex combination of A that is nearest to B*cB\n            ABb = AB*cB;\n            const auto smo_iter1 = solve_qp_using_smo(AA, ABb, cA, eps, cA.size());\n\n            // now find the convex combination of B that is nearest to A*cA\n            ABa = trans(AB)*cA;\n            const auto smo_iter2 = solve_qp_using_smo(BB, ABa, cB, eps, cB.size());\n\n            // stop if the QP solvers failed to improve \n            if (smo_iter1 == 1 && smo_iter2 == 1)\n                break;\n        }\n\n\n        return iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_solve_qp_using_smo_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_\n#ifdef DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_\n\n#include \"../matrix.h\"\n#include <map>\n#include \"../unordered_pair.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_using_smo ( \n        const matrix_exp<EXP1>& Q,\n        const matrix_exp<EXP2>& b,\n        matrix<T,NR,NC,MM,L>& alpha,\n        T eps,\n        unsigned long max_iter\n    );\n    /*!\n        requires\n            - Q.nr() == Q.nc()\n            - is_col_vector(b) == true\n            - is_col_vector(alpha) == true\n            - b.size() == alpha.size() == Q.nr()\n            - alpha.size() > 0\n            - min(alpha) >= 0\n            - eps > 0\n            - max_iter > 0\n        ensures\n            - Let C == sum(alpha) (i.e. C is the sum of the alpha values you \n              supply to this function)\n            - This function solves the following quadratic program:\n                Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b\n                subject to the following constraints:\n                    - sum(alpha) == C (i.e. the sum of alpha values doesn't change)\n                    - min(alpha) >= 0 (i.e. all alpha values are nonnegative)\n                Where f is convex.  This means that Q should be positive-semidefinite.\n            - The solution to the above QP will be stored in #alpha.\n            - This function uses a simple implementation of the sequential minimal\n              optimization algorithm.  It starts the algorithm with the given alpha\n              and it works on the problem until the duality gap (i.e. how far away\n              we are from the optimum solution) is less than eps.  So eps controls \n              how accurate the solution is and smaller values result in better solutions.\n            - At most max_iter iterations of optimization will be performed.  \n            - returns the number of iterations performed.  If this method fails to\n              converge to eps accuracy then the number returned will be max_iter+1.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename EXP3,\n        typename T, long NR, long NC, typename MM, typename L,\n        long NR2, long NC2\n        >\n    unsigned long solve_qp4_using_smo ( \n        const matrix_exp<EXP1>& A,\n        const matrix_exp<EXP2>& Q,\n        const matrix_exp<EXP3>& b,\n        const matrix_exp<EXP4>& d,\n        matrix<T,NR,NC,MM,L>& alpha,\n        matrix<T,NR2,NC2,MM,L>& lambda,\n        T eps,\n        unsigned long max_iter,\n        T max_lambda = std::numeric_limits<T>::infinity()\n    );\n    /*!\n        requires\n            - A.nc() == alpha.size()\n            - Q.nr() == Q.nc()\n            - is_col_vector(b) == true\n            - is_col_vector(d) == true\n            - is_col_vector(alpha) == true\n            - b.size() == alpha.size() == Q.nr()\n            - d.size() == A.nr()\n            - alpha.size() > 0\n            - min(alpha) >= 0\n            - eps > 0\n            - max_iter > 0\n            - max_lambda >= 0\n        ensures\n            - Let C == sum(alpha) (i.e. C is the sum of the alpha values you \n              supply to this function)\n            - This function solves the following quadratic program:\n                Minimize: f(alpha,lambda) == 0.5*trans(alpha)*Q*alpha - trans(alpha)*b + \n                                             0.5*trans(lambda)*lambda - trans(lambda)*A*alpha - trans(lambda)*d\n                subject to the following constraints:\n                    - sum(alpha)  == C (i.e. the sum of alpha values doesn't change)\n                    - min(alpha)  >= 0 (i.e. all alpha values are nonnegative)\n                    - min(lambda) >= 0 (i.e. all lambda values are nonnegative)\n                    - max(lambda) <= max_lambda (i.e. all lambda values are less than max_lambda)\n                Where f is convex.  This means that Q should be positive-semidefinite.\n            - If you don't want an upper limit on lambda then max_lambda can be set to\n              infinity.\n            - The solution to the above QP will be stored in #alpha and #lambda.  \n            - This function uses a simple implementation of the sequential minimal\n              optimization algorithm.  It starts the algorithm with the given alpha\n              and it works on the problem until the duality gap (i.e. how far away\n              we are from the optimum solution) is less than eps.  So eps controls \n              how accurate the solution is and smaller values result in better solutions.\n              The initial value of lambda is ignored since the optimal lambda can be\n              obtained via a simple closed form expression given alpha.\n            - At most max_iter iterations of optimization will be performed.  \n            - returns the number of iterations performed.  If this method fails to\n              converge to eps accuracy then the number returned will be max_iter+1.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_box_constrained ( \n        const matrix_exp<EXP1>& Q,\n        const matrix_exp<EXP2>& b,\n        matrix<T,NR,NC,MM,L>& alpha,\n        const matrix<T,NR,NC,MM,L>& lower,\n        const matrix<T,NR,NC,MM,L>& upper,\n        T eps = 1e-10,\n        unsigned long max_iter = 30000\n    );\n    /*!\n        requires\n            - Q.nr() == Q.nc()\n            - alpha.size() == lower.size() == upper.size()\n            - is_col_vector(b) == true\n            - is_col_vector(alpha) == true\n            - is_col_vector(lower) == true\n            - is_col_vector(upper) == true\n            - b.size() == alpha.size() == Q.nr()\n            - alpha.size() > 0\n            - 0 <= min(alpha-lower)\n            - 0 <= max(upper-alpha)\n            - eps > 0\n            - max_iter > 0\n        ensures\n            - This function solves the following quadratic program:\n                Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(b)*alpha \n                subject to the following box constraints on alpha:\n                    - 0 <= min(alpha-lower)\n                    - 0 <= max(upper-alpha)\n                Where f is convex.  This means that Q should be positive-semidefinite.\n            - The solution to the above QP will be stored in #alpha.\n            - This function uses a combination of a SMO algorithm along with Nesterov's\n              method as the main iteration of the solver.  It starts the algorithm with the\n              given alpha and works on the problem until the magnitude of the changes we\n              are making to alpha are eps times smaller than the typical values in alpha.\n              So eps controls how accurate the solution is and smaller values result in\n              better solutions.\n            - At most max_iter iterations of optimization will be performed.  \n            - returns the number of iterations performed.  If this method fails to\n              converge to eps accuracy then the number returned will be max_iter+1.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_qp_box_constrained_blockdiag ( \n        const std::vector<matrix<T,NR,NR,MM,L>>& Q_blocks,\n        const std::vector<matrix<T,NR,NC,MM,L>>& bs,\n        const std::map<unordered_pair<size_t>, matrix<T,NR,NC,MM,L>>& Q_offdiag,\n        std::vector<matrix<T,NR,NC,MM,L>>& alphas,\n        const std::vector<matrix<T,NR,NC,MM,L>>& lowers,\n        const std::vector<matrix<T,NR,NC,MM,L>>& uppers,\n        T eps = 1e-10,\n        unsigned long max_iter = 30000\n    );\n    /*!\n        requires\n            - Q_blocks.size() > 0\n            - Q_blocks.size() == bs.size() == alphas.size() == lowers.size() == uppers.size()\n            - All the matrices in Q_blocks have the same dimensions.  Moreover, they are\n              non-empty square matrices.\n            - All the matrices in bs, Q_offdiag, alphas, lowers, and uppers have the same\n              dimensions.  Moreover, they are all column vectors.\n            - Q_blocks[0].nr() == alphas[0].size()\n              (i.e. the dimensionality of the column vectors in alphas must match the\n              dimensionality of the square matrices in Q_blocks.)\n            - for all valid i:\n                - 0 <= min(alphas[i]-lowers[i])\n                - 0 <= max(uppers[i]-alphas[i])\n            - eps > 0\n            - max_iter > 0\n        ensures\n            - This function solves the same QP as solve_qp_box_constrained(), except it is\n              optimized for the case where the Q matrix has a certain sparsity structure.\n              To be precise:\n                - Let Q1 be a block diagonal matrix with the elements of Q_blocks placed\n                  along its diagonal, and in the order contained in Q_blocks.  \n                - Let Q2 be a matrix with the same size as Q1, except instead of being block diagonal, it\n                  is block structured into Q_blocks.nr() by Q_blocks.nc() blocks.  If we let (r,c) be the\n                  coordinate of each block then each block contains the matrix\n                  diagm(Q_offdiag[make_unordered_pair(r,c)]) or the zero matrix if Q_offdiag has no entry\n                  for the coordinate (r,c).\n                - Let Q == Q1+Q2\n                - Let b == the concatenation of all the vectors in bs into one big vector.\n                - Let alpha == the concatenation of all the vectors in alphas into one big vector.\n                - Let lower == the concatenation of all the vectors in lowers into one big vector.\n                - Let upper == the concatenation of all the vectors in uppers into one big vector.\n                - Then this function solves the following quadratic program:\n                    Minimize: f(alpha) == 0.5*trans(alpha)*Q*alpha + trans(b)*alpha \n                    subject to the following box constraints on alpha:\n                        - 0 <= min(alpha-lower)\n                        - 0 <= max(upper-alpha)\n                    Where f is convex.  This means that Q should be positive-semidefinite.\n                - More specifically, this function is identical to\n                  solve_qp_box_constrained(Q, b, alpha, lower, upper, eps, max_iter),\n                  except that it runs faster since it avoids unnecessary computation by\n                  taking advantage of the sparsity structure in the QP.\n            - The solution to the above QP will be stored in #alphas.\n            - This function uses a combination of a SMO algorithm along with Nesterov's\n              method as the main iteration of the solver.  It starts the algorithm with the\n              given alpha and works on the problem until the magnitude of the changes we\n              are making to alpha are eps times smaller than the typical values in alpha.\n              So eps controls how accurate the solution is and smaller values result in\n              better solutions.\n            - At most max_iter iterations of optimization will be performed.  \n            - returns the number of iterations performed.  If this method fails to\n              converge to eps accuracy then the number returned will be max_iter+1.\n    !*/\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NRa, long NRb\n        >\n    unsigned long find_gap_between_convex_hulls (\n        const matrix_exp<EXP1>& A,\n        const matrix_exp<EXP2>& B,\n        matrix<T,NRa,1>& cA,\n        matrix<T,NRb,1>& cB,\n        const double eps,\n        const unsigned long max_iter = 1000\n    );\n    /*!\n        requires\n            - A.nr() == B.nr()\n            - A.size() != 0\n            - B.size() != 0\n            - eps > 0\n            - max_iter > 0\n        ensures\n            - If you think of A and B as sets of column vectors, then we can identify the\n              convex sets hullA and hullB, which are the convex hulls of A and B\n              respectively.  This function finds the pair of points in hullA and hullB that\n              are nearest to each other.  To be precise, this function solves the following\n              quadratic program:\n                Minimize: f(cA,cB) == length_squared(A*cA - B*cB) \n                subject to the following constraints on cA and cB:\n                    - is_col_vector(cA) == true && cA.size() == A.nc()\n                    - is_col_vector(cB) == true && cB.size() == B.nc()\n                    - sum(cA) == 1 && min(cA) >= 0\n                    - sum(cB) == 1 && min(cB) >= 0\n            - This function uses an iterative block coordinate descent algorithm to solve\n              the QP.  It runs until either max_iter iterations have been performed or the\n              QP is solved to at least eps accuracy.\n            - returns the number of iterations performed.  If this method fails to\n              converge to eps accuracy then the number returned will be max_iter+1.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_SOLVE_QP_UsING_SMO_ABSTRACT_Hh_\n\n\n"
  },
  {
    "path": "dlib/optimization/optimization_stop_strategies.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_\n#define DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix.h\"\n#include \"../algs.h\"\n#include \"optimization_stop_strategies_abstract.h\"\n#include <iostream>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class objective_delta_stop_strategy\n    {\n    public:\n        explicit objective_delta_stop_strategy (\n            double min_delta = 1e-7\n        ) : _verbose(false), _been_used(false), _min_delta(min_delta), _max_iter(0), _cur_iter(0), _prev_funct_value(0) \n        {\n            DLIB_ASSERT (\n                min_delta >= 0,\n                \"\\t objective_delta_stop_strategy(min_delta)\"\n                << \"\\n\\t min_delta can't be negative\"\n                << \"\\n\\t min_delta: \" << min_delta\n            );\n        }\n\n        objective_delta_stop_strategy (\n            double min_delta,\n            unsigned long max_iter\n        ) : _verbose(false), _been_used(false), _min_delta(min_delta), _max_iter(max_iter), _cur_iter(0), _prev_funct_value(0) \n        {\n            DLIB_ASSERT (\n                min_delta >= 0 && max_iter > 0,\n                \"\\t objective_delta_stop_strategy(min_delta, max_iter)\"\n                << \"\\n\\t min_delta can't be negative and max_iter can't be 0\"\n                << \"\\n\\t min_delta: \" << min_delta\n                << \"\\n\\t max_iter:  \" << max_iter \n            );\n        }\n\n        objective_delta_stop_strategy& be_verbose( \n        ) \n        {\n            _verbose = true;\n            return *this;\n        }\n\n        template <typename T>\n        bool should_continue_search (\n            const T& ,\n            const double funct_value,\n            const T& \n        ) \n        {\n            if (_verbose)\n            {\n                std::cout << \"iteration: \" << _cur_iter << \"   objective: \" << funct_value << std::endl;\n            }\n\n            ++_cur_iter;\n            if (_been_used)\n            {\n                // Check if we have hit the max allowable number of iterations.  (but only\n                // check if _max_iter is enabled (i.e. not 0)).\n                if (_max_iter != 0 && _cur_iter > _max_iter)\n                    return false;\n\n                // check if the function change was too small\n                if (std::abs(funct_value - _prev_funct_value) < _min_delta)\n                    return false;\n            }\n\n            _been_used = true;\n            _prev_funct_value = funct_value;\n            return true;\n        }\n\n    private:\n        bool _verbose;\n\n        bool _been_used;\n        double _min_delta;\n        unsigned long _max_iter;\n        unsigned long _cur_iter;\n        double _prev_funct_value;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class gradient_norm_stop_strategy\n    {\n    public:\n        explicit gradient_norm_stop_strategy (\n            double min_norm = 1e-7\n        ) : _verbose(false), _min_norm(min_norm), _max_iter(0), _cur_iter(0) \n        {\n            DLIB_ASSERT (\n                min_norm >= 0,\n                \"\\t gradient_norm_stop_strategy(min_norm)\"\n                << \"\\n\\t min_norm can't be negative\"\n                << \"\\n\\t min_norm: \" << min_norm\n            );\n        }\n\n        gradient_norm_stop_strategy (\n            double min_norm,\n            unsigned long max_iter\n        ) : _verbose(false), _min_norm(min_norm), _max_iter(max_iter), _cur_iter(0) \n        {\n            DLIB_ASSERT (\n                min_norm >= 0 && max_iter > 0,\n                \"\\t gradient_norm_stop_strategy(min_norm, max_iter)\"\n                << \"\\n\\t min_norm can't be negative and max_iter can't be 0\"\n                << \"\\n\\t min_norm: \" << min_norm\n                << \"\\n\\t max_iter:  \" << max_iter \n            );\n        }\n\n        gradient_norm_stop_strategy& be_verbose( \n        ) \n        {\n            _verbose = true;\n            return *this;\n        }\n\n        template <typename T>\n        bool should_continue_search (\n            const T& ,\n            const double funct_value,\n            const T& funct_derivative\n        ) \n        {\n            if (_verbose)\n            {\n                std::cout << \"iteration: \" << _cur_iter << \"   objective: \" << funct_value << \"   gradient norm: \" << length(funct_derivative) << std::endl;\n            }\n\n            ++_cur_iter;\n\n            // Check if we have hit the max allowable number of iterations.  (but only\n            // check if _max_iter is enabled (i.e. not 0)).\n            if (_max_iter != 0 && _cur_iter > _max_iter)\n                return false;\n\n            // check if the gradient norm is too small \n            if (length(funct_derivative) < _min_norm)\n                return false;\n\n            return true;\n        }\n\n    private:\n        bool _verbose;\n\n        double _min_norm;\n        unsigned long _max_iter;\n        unsigned long _cur_iter;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_STOP_STRATEGIES_H_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_stop_strategies_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_\n#ifdef DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_\n\n#include <cmath>\n#include <limits>\n#include \"../matrix/matrix_abstract.h\"\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class objective_delta_stop_strategy\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for deciding if an optimization\n                algorithm should terminate.   This particular object looks at the \n                change in the objective function from one iteration to the next and \n                bases its decision on how large this change is.  If the change\n                is below a user given threshold then the search stops.\n        !*/\n\n    public:\n        explicit objective_delta_stop_strategy (\n            double min_delta = 1e-7\n        ); \n        /*!\n            requires\n                - min_delta >= 0\n            ensures\n                - This stop strategy object will only consider a search to be complete\n                  if a change in an objective function from one iteration to the next\n                  is less than min_delta.\n        !*/\n\n        objective_delta_stop_strategy (\n            double min_delta,\n            unsigned long max_iter\n        );\n        /*!\n            requires\n                - min_delta >= 0\n                - max_iter > 0\n            ensures\n                - This stop strategy object will only consider a search to be complete\n                  if a change in an objective function from one iteration to the next\n                  is less than min_delta or more than max_iter iterations has been\n                  executed.\n        !*/\n\n        objective_delta_stop_strategy& be_verbose( \n        );\n        /*!\n            ensures\n                - causes this object to print status messages to standard out \n                  every time should_continue_search() is called.\n                - returns *this\n        !*/\n\n        template <typename T>\n        bool should_continue_search (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - this function is only called once per search iteration\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - returns true if the point x doest not satisfy the stopping condition and\n                  false otherwise.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    class gradient_norm_stop_strategy\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a strategy for deciding if an optimization\n                algorithm should terminate.   This particular object looks at the \n                norm (i.e. the length) of the current gradient vector and stops \n                if it is smaller than a user given threshold.  \n        !*/\n\n    public:\n        explicit gradient_norm_stop_strategy (\n            double min_norm = 1e-7\n        ); \n        /*!\n            requires\n                - min_norm >= 0\n            ensures\n                - This stop strategy object will only consider a search to be complete\n                  if the current gradient norm is less than min_norm\n        !*/\n\n        gradient_norm_stop_strategy (\n            double min_norm,\n            unsigned long max_iter\n        );\n        /*!\n            requires\n                - min_norm >= 0\n                - max_iter > 0\n            ensures\n                - This stop strategy object will only consider a search to be complete\n                  if the current gradient norm is less than min_norm or more than \n                  max_iter iterations has been executed.\n        !*/\n\n        gradient_norm_stop_strategy& be_verbose( \n        );\n        /*!\n            ensures\n                - causes this object to print status messages to standard out \n                  every time should_continue_search() is called.\n                - returns *this\n        !*/\n\n        template <typename T>\n        bool should_continue_search (\n            const T& x,\n            const double funct_value,\n            const T& funct_derivative\n        );\n        /*!\n            requires\n                - this function is only called once per search iteration\n                - for some objective function f():\n                    - x == the search point for the current iteration\n                    - funct_value == f(x)\n                    - funct_derivative == derivative(f)(x)\n            ensures\n                - returns true if the point x doest not satisfy the stopping condition and\n                  false otherwise.\n        !*/\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATIOn_STOP_STRATEGIES_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_trust_region.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_\n#define DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_\n\n#include \"../matrix.h\"\n#include \"optimization_trust_region_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_trust_region_subproblem ( \n        const matrix_exp<EXP1>& B,\n        const matrix_exp<EXP2>& g,\n        const typename EXP1::type radius,\n        matrix<T,NR,NC,MM,L>& p,\n        double eps,\n        unsigned long max_iter\n    )\n    {\n        /*\n            This is an implementation of algorithm 4.3(Trust Region Subproblem)\n            from the book Numerical Optimization by Nocedal and Wright.  Some of\n            the details are also from Practical Methods of Optimization by Fletcher.\n        */\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(B.nr() == B.nc() && is_col_vector(g) && g.size() == B.nr(),\n            \"\\t unsigned long solve_trust_region_subproblem()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t B.nr():            \" << B.nr()\n            << \"\\n\\t B.nc():            \" << B.nc()\n            << \"\\n\\t is_col_vector(g):  \" << is_col_vector(g) \n            << \"\\n\\t g.size():          \" << g.size() \n            );\n        DLIB_ASSERT(radius > 0 && eps > 0 && max_iter > 0,\n            \"\\t unsigned long solve_trust_region_subproblem()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t radius:   \" << radius\n            << \"\\n\\t eps:      \" << eps \n            << \"\\n\\t max_iter: \" << max_iter \n            );\n\n\n        const_temp_matrix<EXP1> BB(B);\n        const_temp_matrix<EXP2> gg(g);\n\n        p.set_size(g.nr(),g.nc());\n        p = 0;\n\n\n        const T numeric_eps = max(diag(abs(BB)))*std::numeric_limits<T>::epsilon();\n\n        matrix<T,EXP1::NR,EXP2::NR,MM,L> R;\n\n        T lambda = 0;\n\n        // We need to put a bracket around lambda.  It can't go below 0.  We\n        // can get an upper bound using Gershgorin disks.  \n        // This number is a lower bound on the eigenvalues in BB\n        const T BB_min_eigenvalue = min(diag(BB) - (sum_cols(abs(BB)) - abs(diag(BB))));\n\n        const T g_norm = length(gg);\n\n        T lambda_min = 0;\n        T lambda_max = put_in_range(0, \n                                    std::numeric_limits<T>::max(), \n                                    g_norm/radius - BB_min_eigenvalue);\n\n\n        // If we can tell that the minimum is at 0 then don't do anything.  Just return the answer. \n        if (g_norm < numeric_eps && BB_min_eigenvalue > numeric_eps)\n        {\n            return 0;\n        }\n\n\n        // how much lambda has changed recently\n        T lambda_delta = 0;\n\n        for (unsigned long i = 0; i < max_iter; ++i)\n        {\n            R = chol(BB + lambda*identity_matrix<T>(BB.nr()));\n\n            // if the cholesky decomposition doesn't exist. \n            if (R(R.nr()-1, R.nc()-1) <= 0)\n            {\n                // If B is indefinite and g is equal to 0 then we should\n                // quit this loop and go right to the eigenvalue decomposition method.\n                if (g_norm <= numeric_eps)\n                    break;\n\n                // narrow the bracket on lambda.  Obviously the current lambda is\n                // too small.\n                lambda_min = lambda;\n\n                // jump towards the max value.  Eventually there will\n                // be a lambda that results in a cholesky decomposition.\n                const T alpha = 0.10;\n                lambda = (1-alpha)*lambda + alpha*lambda_max;\n                continue;\n            }\n\n            using namespace blas_bindings;\n\n            p = -gg;\n            // Solve RR'*p = -g for p.\n            // Solve R*q = -g for q where q = R'*p.\n            if (R.nr() == 2)\n            {\n                p(0) = p(0)/R(0,0);\n                p(1) = (p(1)-R(1,0)*p(0))/R(1,1);\n            }\n            else\n            {\n                triangular_solver(CblasLeft, CblasLower, CblasNoTrans, CblasNonUnit, R, p);\n            }\n            const T q_norm = length(p);\n\n            // Solve R'*p = q for p.\n            if (R.nr() == 2)\n            {\n                p(1) = p(1)/R(1,1);\n                p(0) = (p(0)-R(1,0)*p(1))/R(0,0);\n            }\n            else\n            {\n                triangular_solver(CblasLeft, CblasLower, CblasTrans, CblasNonUnit, R, p);\n            }\n            const T p_norm = length(p);\n\n            // check if we are done.  \n            if (lambda == 0)\n            {\n                if (p_norm < radius)\n                {\n                    // i will always be 0 in this case.  So we return 1.\n                    return i+1;\n                }\n            }\n            else\n            {\n                // if we are close enough to the solution then terminate\n                if (std::abs(p_norm - radius)/radius < eps)\n                    return i+1;\n            }\n\n            // shrink our bracket on lambda\n            if (p_norm < radius)\n                lambda_max = lambda;\n            else\n                lambda_min = lambda;\n\n\n            if (p_norm <= radius*std::numeric_limits<T>::epsilon())\n            {\n                const T alpha = 0.01;\n                lambda = (1-alpha)*lambda_min + alpha*lambda_max;\n                continue;\n            }\n\n            const T old_lambda = lambda;\n\n            // figure out which lambda to try next\n            lambda = lambda + std::pow(q_norm/p_norm,2)*(p_norm - radius)/radius;\n\n            // make sure the chosen lambda is within our bracket (but not exactly at either end).\n            const T gap = (lambda_max-lambda_min)*0.01;\n            lambda = put_in_range(lambda_min+gap, lambda_max-gap, lambda);\n\n            // Keep track of how much lambda is thrashing around inside the search bracket.  If it\n            // keeps moving around a whole lot then cut the search bracket in half.\n            lambda_delta += std::abs(lambda - old_lambda);\n            if (lambda_delta > 3*(lambda_max-lambda_min))\n            {\n                lambda = (lambda_min+lambda_max)/2;\n                lambda_delta = 0;\n            }\n        } // end for loop\n\n\n        // We are probably in the \"hard case\".   Use an eigenvalue decomposition to sort things out.\n        // Either that or the eps was just set too tight and really we are already done.\n        eigenvalue_decomposition<EXP1> ed(make_symmetric(BB));\n\n        matrix<T,NR,NC,MM,L> ev = ed.get_real_eigenvalues();\n        const long min_eig_idx = index_of_min(ev);\n\n\n        ev -= min(ev);\n        // zero out any values which are basically zero\n        ev = pointwise_multiply(ev, ev > max(abs(ev))*std::numeric_limits<T>::epsilon());\n        ev = reciprocal(ev);\n\n\n        // figure out part of what p should be assuming we are in the hard case.\n        matrix<T,NR,NC,MM,L> p_hard;\n        p_hard = trans(ed.get_pseudo_v())*gg;\n        p_hard = diagm(ev)*p_hard;\n        p_hard = ed.get_pseudo_v()*p_hard;\n\n\n        // If we really are in the hard case then this if will be true.  Otherwise, the p\n        // we found in the \"easy case\" loop up top is the best answer.\n        if (length(p_hard) < radius && length(p_hard) >= length(p))\n        {\n            // adjust the length of p_hard by adding a component along the eigenvector associated with\n            // the smallest eigenvalue.  We want to make it the case that length(p) == radius.\n            const T tau = std::sqrt(radius*radius - length_squared(p_hard));\n            p = p_hard + tau*colm(ed.get_pseudo_v(),min_eig_idx);\n\n\n            // if we have to do an eigenvalue decomposition then say we did all the iterations\n            return max_iter;\n        }\n\n        // if we get this far it means we didn't converge to eps accuracy. \n        return max_iter+1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace impl\n    {\n        template <\n            typename EXP1,\n            typename EXP2,\n            typename EXP3\n            >\n        bool bounds_violated (\n            const matrix_exp<EXP1>& v,\n            const matrix_exp<EXP2>& l,\n            const matrix_exp<EXP3>& u\n        )\n        {\n            DLIB_ASSERT(v.nr() == l.nr() && v.nr() == u.nr());\n            DLIB_ASSERT(v.nc() == l.nc() && v.nc() == u.nc());\n            for (long r = 0; r < v.nr(); ++r)\n            {\n                for (long c = 0; c < v.nc(); c++)\n                {\n                    if (!(l(r,c) <= v(r,c) && v(r,c) <= u(r,c)))\n                        return true;\n                }\n            }\n            return false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L,\n        typename EXP3\n        >\n    void solve_trust_region_subproblem_bounded ( \n        const matrix_exp<EXP1>& B_,\n        const matrix_exp<EXP2>& g_,\n        const typename EXP1::type radius_,\n        matrix<T,NR,NC,MM,L>& p_,\n        double eps,\n        unsigned long max_iter,\n        const matrix_exp<EXP3>& lower_,\n        const matrix_exp<EXP3>& upper_\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(B_.nr() == B_.nc() && is_col_vector(g_) && g_.size() == B_.nr(),\n            \"\\t unsigned long solve_trust_region_subproblem_bounded()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t B_.nr():            \" << B_.nr()\n            << \"\\n\\t B_.nc():            \" << B_.nc()\n            << \"\\n\\t is_col_vector(g_):  \" << is_col_vector(g_) \n            << \"\\n\\t g_.size():          \" << g_.size() \n            );\n        DLIB_ASSERT(radius_ > 0 && eps > 0 && max_iter > 0,\n            \"\\t unsigned long solve_trust_region_subproblem_bounded()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t radius_:   \" << radius_\n            << \"\\n\\t eps:      \" << eps \n            << \"\\n\\t max_iter: \" << max_iter \n            );\n        DLIB_ASSERT(is_col_vector(lower_) && lower_.size() == g_.size());\n        DLIB_ASSERT(is_col_vector(upper_) && upper_.size() == g_.size());\n        DLIB_ASSERT(max(upper_-lower_) >= 0);\n        // make sure the problem is feasible.  That is, there should be a point inside the\n        // lower and upper bounds that has a norm <= radius_\n        DLIB_ASSERT(length(clamp(zeros_matrix(lower_),lower_,upper_)) <= radius_, \n            \"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.\");\n\n        // We are going to solve this by greedily finding the most violated bound constraint,\n        // locking that variable to its constrained value, removing it from the problem,\n        // and then resolving.  We do that until no more constraint violations are present.\n\n        solve_trust_region_subproblem(B_,g_,radius_,p_,eps,max_iter);\n\n\n        // just stop here if all the bounds are satisfied.\n        if (!impl::bounds_violated(p_, lower_, upper_))\n            return;\n\n        matrix<double> B = matrix_cast<double>(B_);\n        matrix<double,0,1> g = matrix_cast<double>(g_);\n        double radius = radius_;\n        matrix<double,0,1> p = matrix_cast<double>(p_);\n        matrix<double,0,1> lower = matrix_cast<double>(lower_);\n        matrix<double,0,1> upper = matrix_cast<double>(upper_);\n\n        // keep a table that tells us how to map any reduced QP back to the original QP\n        std::vector<long> idxs(g.size());\n        for (size_t i = 0; i < idxs.size(); ++i)\n            idxs[i] = i;\n\n\n        // while we haven't found a p that satisfies the bounds constraints\n        while(impl::bounds_violated(p, lower, upper) )\n        {\n            // Find the most violated variable and fix its value to a constant (the bound\n            // value).\n            long most_violated_idx = 0;\n            double max_violation = 0;\n            double bounded_value = 0;\n            for (long i = 0; i < lower.size(); ++i)\n            {\n                if (!(lower(i) <= p(i) && p(i) <= upper(i)))\n                {\n                    if (lower(i)-p(i) > max_violation)\n                    {\n                        max_violation = lower(i)-p(i);\n                        most_violated_idx = i;\n                        bounded_value = lower(i);\n                    }\n                    else if (p(i)-upper(i) > max_violation)\n                    {\n                        max_violation = p(i)-upper(i);\n                        most_violated_idx = i;\n                        bounded_value = upper(i);\n                    }\n                }\n            }\n\n            // assign this variable to its final value.\n            p_(idxs[most_violated_idx]) = bounded_value;\n\n\n            // now reduce the QP by removing the variable p_(idxs[most_violated_idx]).  \n            idxs.erase(idxs.begin()+most_violated_idx);\n            // we are out of variables to remove since everything is at bounds.\n            if (idxs.size() == 0)\n                break;\n\n            lower = remove_row(lower,most_violated_idx);\n            upper = remove_row(upper,most_violated_idx);\n            g += colm(B,most_violated_idx)*bounded_value;\n            g = remove_row(g,most_violated_idx);\n            p = remove_row(p,most_violated_idx);\n            B = removerc(B,most_violated_idx, most_violated_idx);\n\n            // Removing a variable changes the radius, so we have to subtract the bounded\n            // value from the radius so as to not change the effective radius for the whole\n            // problem.\n            double squared_radius = radius*radius - bounded_value*bounded_value;\n            if (squared_radius <= 0)\n            {\n                p = 0;\n                break;\n            }\n            radius = std::sqrt(squared_radius);\n\n\n            solve_trust_region_subproblem(B,g,radius,p,eps,max_iter);\n        }\n\n        // assign the non-bound-constrained variables to their final values\n        for (size_t i = 0; i < idxs.size(); ++i)\n            p_(idxs[i]) = p(i);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_model\n        >\n    double find_min_trust_region (\n        stop_strategy_type stop_strategy,\n        const funct_model& model, \n        typename funct_model::column_vector& x, \n        double radius = 1\n    )\n    {\n        /*\n            This is an implementation of algorithm 4.1(Trust Region)\n            from the book Numerical Optimization by Nocedal and Wright.  \n        */\n\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_col_vector(x) && radius > 0,\n            \"\\t double find_min_trust_region()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t is_col_vector(x): \" << is_col_vector(x) \n            << \"\\n\\t radius:           \" << radius\n            );\n\n        const double initial_radius = radius;\n\n        typedef typename funct_model::column_vector T;\n        typedef typename T::type type;\n\n        typename funct_model::general_matrix h;\n        typename funct_model::column_vector g, p, d;\n        type f_value = model(x);\n\n        model.get_derivative_and_hessian(x,g,h);\n\n        DLIB_ASSERT(is_finite(x), \"The objective function generated non-finite outputs\");\n        DLIB_ASSERT(is_finite(g), \"The objective function generated non-finite outputs\");\n        DLIB_ASSERT(is_finite(h), \"The objective function generated non-finite outputs\");\n\n        // Sometimes the loop below won't modify x because the trust region step failed.\n        // This bool tells us when we are in that case.\n        bool stale_x = false;\n\n        while(stale_x || stop_strategy.should_continue_search(x, f_value, g))\n        {\n            const unsigned long iter = solve_trust_region_subproblem(h,\n                                                                     g,\n                                                                     radius,\n                                                                     p, \n                                                                     0.1, \n                                                                     20);\n\n\n            const type new_f_value = model(x+p);\n            const type predicted_improvement = -0.5*trans(p)*h*p - trans(g)*p;\n            const type measured_improvement = (f_value - new_f_value);\n\n            // If the sub-problem can't find a way to improve then stop.  This only happens when p is essentially 0.\n            if (std::abs(predicted_improvement) <= std::abs(measured_improvement)*std::numeric_limits<type>::epsilon())\n                break;\n\n            // predicted_improvement shouldn't be negative but it might be if something went\n            // wrong in the trust region solver.  So put abs() here to guard against that.  This\n            // way the sign of rho is determined only by the sign of measured_improvement.\n            //\n            // When the predicted improvement is below the floating point resolution of f_value,\n            // the measured improvement (f_value - new_f_value) is dominated by rounding noise\n            // and rho becomes meaningless.  In this case we trust the quadratic model and treat\n            // the step as a perfect match (rho = 1).\n            const type abs_pred = std::abs(predicted_improvement);\n            const type f_eps = std::abs(f_value) * std::numeric_limits<type>::epsilon();\n            const type rho = (abs_pred < f_eps) ? type(1) : measured_improvement/abs_pred;\n\n            if (!is_finite(rho))\n                break;\n            \n            if (rho < 0.25)\n            {\n                radius *= 0.25;\n\n                // something has gone horribly wrong if the radius has shrunk to zero.  So just\n                // give up if that happens.\n                if (radius <= initial_radius*std::numeric_limits<double>::epsilon())\n                    break;\n            }\n            else\n            {\n                // if rho > 0.75 and we are being checked by the radius \n                if (rho > 0.75 && iter > 1)\n                {\n                    radius = std::min<type>(1000,  2*radius);\n                }\n            }\n\n            if (rho > 0)\n            {\n                x = x + p;\n                f_value = new_f_value;\n                model.get_derivative_and_hessian(x,g,h);\n                stale_x = false;\n            }\n            else\n            {\n                stale_x = true;\n            }\n\n            DLIB_ASSERT(is_finite(x), \"The objective function generated non-finite outputs\");\n            DLIB_ASSERT(is_finite(g), \"The objective function generated non-finite outputs\");\n            DLIB_ASSERT(is_finite(h), \"The objective function generated non-finite outputs\");\n        }\n\n        return f_value;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename funct_model>\n    struct negate_tr_model \n    {\n        negate_tr_model( const funct_model& m) : model(m) {}\n\n        const funct_model& model;\n\n        typedef typename funct_model::column_vector column_vector;\n        typedef typename funct_model::general_matrix general_matrix;\n\n        template <typename T>\n        typename T::type operator() (const T& x) const\n        {\n            return -model(x);\n        }\n\n        template <typename T, typename U>\n        void get_derivative_and_hessian (\n            const T& x,\n            T& d,\n            U& h\n        ) const \n        {\n            model.get_derivative_and_hessian(x,d,h);\n            d = -d;\n            h = -h;\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_model\n        >\n    double find_max_trust_region (\n        stop_strategy_type stop_strategy,\n        const funct_model& model, \n        typename funct_model::column_vector& x, \n        double radius = 1\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_ASSERT(is_col_vector(x) && radius > 0,\n            \"\\t double find_max_trust_region()\"\n            << \"\\n\\t invalid arguments were given to this function\"\n            << \"\\n\\t is_col_vector(x): \" << is_col_vector(x) \n            << \"\\n\\t radius:           \" << radius\n            );\n\n        return -find_min_trust_region(stop_strategy,\n                                      negate_tr_model<funct_model>(model),\n                                      x,\n                                      radius);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_TRUST_REGIoN_Hh_\n\n"
  },
  {
    "path": "dlib/optimization/optimization_trust_region_abstract.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_\n#ifdef DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_\n\n#include \"../matrix/matrix_abstract.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L\n        >\n    unsigned long solve_trust_region_subproblem ( \n        const matrix_exp<EXP1>& B,\n        const matrix_exp<EXP2>& g,\n        const typename EXP1::type radius,\n        matrix<T,NR,NC,MM,L>& p,\n        double eps,\n        unsigned long max_iter\n    );\n    /*!\n        requires\n            - B == trans(B)\n              (i.e. B should be a symmetric matrix)\n            - B.nr() == B.nc()\n            - is_col_vector(g) == true\n            - g.size() == B.nr()\n            - p is capable of containing a column vector the size of g\n              (i.e. p = g; should be a legal expression)\n            - radius > 0\n            - eps > 0\n            - max_iter > 0\n        ensures\n            - This function solves the following optimization problem:\n                Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p\n                subject to the following constraint:\n                    - length(p) <= radius\n            - returns the number of iterations performed.  If this method fails to converge\n              to eps accuracy then the number returned will be max_iter+1.\n            - if (this function didn't terminate due to hitting the max_iter iteration limit) then\n                - if this function returns 0 or 1 then we are not hitting the radius bound Otherwise, \n                  the radius constraint is active and std::abs(length(#p)-radius)/radius <= eps.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename EXP1,\n        typename EXP2,\n        typename T, long NR, long NC, typename MM, typename L,\n        typename EXP3\n        >\n    void solve_trust_region_subproblem_bounded ( \n        const matrix_exp<EXP1>& B,\n        const matrix_exp<EXP2>& g,\n        const typename EXP1::type radius,\n        matrix<T,NR,NC,MM,L>& p,\n        double eps,\n        unsigned long max_iter,\n        const matrix_exp<EXP3>& lower,\n        const matrix_exp<EXP3>& upper\n    );\n    /*!\n        requires\n            - B == trans(B)\n              (i.e. B should be a symmetric matrix)\n            - B.nr() == B.nc()\n            - is_col_vector(g) == true\n            - is_col_vector(lower) == true\n            - is_col_vector(upper) == true\n            - g.size() == B.nr()\n            - lower.size() == B.nr()\n            - upper.size() == B.nr()\n            - p is capable of containing a column vector the size of g\n              (i.e. p = g; should be a legal expression)\n            - radius > 0\n            - eps > 0\n            - max_iter > 0\n            - min(upper-lower) >= 0\n            - length(clamp(zeros_matrix(lower),lower,upper)) <= radius\n              (i.e. the lower and upper bounds can't exclude all points with the desired radius.)\n        ensures\n            - This function solves the following optimization problem:\n                Minimize: f(p) == 0.5*trans(p)*B*p + trans(g)*p\n                subject to the following constraints:\n                    - length(p) <= radius\n                    - lower(i) <= p(i) <= upper(i), for all i\n            - Solves the problem to eps accuracy.  We do this by greedily finding the most\n              violated bound constraint, locking that variable to its constrained value, removing\n              it from the problem, and then resolving.  We do that until no more constraint\n              violations are present.  Each time we just call solve_trust_region_subproblem() \n              to get the solution and pass eps and max_iter directly to these calls to\n              solve_trust_region_subproblem().\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    class function_model \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object defines the interface for a function model\n                used by the trust-region optimizers defined below.\n\n                In particular, this object represents a function f() and\n                its associated derivative and hessian.\n\n        !*/\n\n    public:\n\n        // Define the type used to represent column vectors\n        typedef matrix<double,0,1> column_vector;\n        // Define the type used to represent the hessian matrix\n        typedef matrix<double> general_matrix;\n\n        double operator() ( \n            const column_vector& x\n        ) const;\n        /*!\n            ensures\n                - returns f(x)\n                  (i.e. evaluates this model at the given point and returns the value)\n        !*/\n\n        void get_derivative_and_hessian (\n            const column_vector& x,\n            column_vector& d,\n            general_matrix& h\n        ) const;\n        /*!\n            ensures\n                - #d == the derivative of f() at x\n                - #h == the hessian matrix of f() at x\n                - is_col_vector(#d) == true\n                - #d.size() == x.size()\n                - #h.nr() == #h.nc() == x.size()\n                - #h == trans(#h)\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_model\n        >\n    double find_min_trust_region (\n        stop_strategy_type stop_strategy,\n        const funct_model& model, \n        typename funct_model::column_vector& x, \n        double radius = 1\n    );\n    /*!\n        requires\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - is_col_vector(x) == true\n            - radius > 0\n            - model must be an object with an interface as defined by the function_model\n              example object shown above.\n        ensures\n            - Performs an unconstrained minimization of the function defined by model \n              starting from the initial point x.  This function uses a trust region\n              algorithm to perform the minimization.  The radius parameter defines\n              the initial size of the trust region.\n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or the trust region subproblem fails to make progress.\n            - #x == the value of x that was found to minimize model()\n            - returns model(#x). \n            - When this function makes calls to model.get_derivative_and_hessian() it always \n              does so by first calling model() and then calling model.get_derivative_and_hessian().  \n              That is, any call to model.get_derivative_and_hessian(val) will always be \n              preceded by a call to model(val) with the same value.  This way you can reuse \n              any redundant computations performed by model() and model.get_derivative_and_hessian()\n              as appropriate.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename stop_strategy_type,\n        typename funct_model\n        >\n    double find_max_trust_region (\n        stop_strategy_type stop_strategy,\n        const funct_model& model, \n        typename funct_model::column_vector& x, \n        double radius = 1\n    );\n    /*!\n        requires\n            - stop_strategy == an object that defines a stop strategy such as one of \n              the objects from dlib/optimization/optimization_stop_strategies_abstract.h\n            - is_col_vector(x) == true\n            - radius > 0\n            - model must be an object with an interface as defined by the function_model\n              example object shown above.\n        ensures\n            - Performs an unconstrained maximization of the function defined by model \n              starting from the initial point x.  This function uses a trust region\n              algorithm to perform the maximization.  The radius parameter defines\n              the initial size of the trust region.\n            - The function is optimized until stop_strategy decides that an acceptable \n              point has been found or the trust region subproblem fails to make progress.\n            - #x == the value of x that was found to maximize model()\n            - returns model(#x). \n            - When this function makes calls to model.get_derivative_and_hessian() it always \n              does so by first calling model() and then calling model.get_derivative_and_hessian().  \n              That is, any call to model.get_derivative_and_hessian(val) will always be \n              preceded by a call to model(val) with the same value.  This way you can reuse \n              any redundant computations performed by model() and model.get_derivative_and_hessian()\n              as appropriate.\n            - Note that this function solves the maximization problem by converting it \n              into a minimization problem.  Therefore, the values of model() and its derivative\n              reported to the stopping strategy will be negated.  That is, stop_strategy\n              will see -model() and -derivative.  All this really means is that the status \n              messages from a stopping strategy in verbose mode will display a negated objective\n              value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_OPTIMIZATION_TRUST_REGIoN_H_ABSTRACTh_\n\n\n"
  },
  {
    "path": "dlib/optimization.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIMIZATIOn_HEADER\n#define DLIB_OPTIMIZATIOn_HEADER\n\n#include \"optimization/optimization.h\"\n#include \"optimization/optimization_bobyqa.h\"\n#include \"optimization/optimization_solve_qp_using_smo.h\"\n#include \"optimization/optimization_solve_qp2_using_smo.h\"\n#include \"optimization/optimization_solve_qp3_using_smo.h\"\n#include \"optimization/optimization_oca.h\"\n#include \"optimization/optimization_trust_region.h\"\n#include \"optimization/optimization_least_squares.h\"\n#include \"optimization/max_cost_assignment.h\"\n#include \"optimization/max_sum_submatrix.h\"\n#include \"optimization/find_max_factor_graph_nmplp.h\"\n#include \"optimization/find_max_factor_graph_viterbi.h\"\n#include \"optimization/find_max_parse_cky.h\"\n#include \"optimization/isotonic_regression.h\"\n\n#endif // DLIB_OPTIMIZATIOn_HEADER\n\n\n\n"
  },
  {
    "path": "dlib/optional.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OPTIONAL_H\n#define DLIB_OPTIONAL_H\n\n#include <exception>\n#include <initializer_list>\n#include \"functional.h\"\n\nnamespace dlib\n{\n\n// ---------------------------------------------------------------------------------------------------\n\n    class bad_optional_access : public std::exception \n    {\n    public:\n        bad_optional_access() = default;\n        const char *what() const noexcept { return \"Optional has no value\"; }\n    };\n\n// ---------------------------------------------------------------------------------------------------\n\n    struct nullopt_t \n    {\n        nullopt_t() = delete;\n        constexpr explicit nullopt_t(int) noexcept {}\n    };\n\n    static constexpr nullopt_t nullopt{int{}};\n\n// ---------------------------------------------------------------------------------------------------\n\n    template<class T>\n    class optional;\n    /*!\n        WHAT THIS OBJECT REPRESENTS \n            This is a standard's compliant backport of std::optional that works with C++14.\n            It includes C++23 monadic interfaces\n\n            Therefore, refer to https://en.cppreference.com/w/cpp/utility/optional for docs on the\n            interface of optional.\n    !*/\n\n\n// ---------------------------------------------------------------------------------------------------\n// ---------------------------------------------------------------------------------------------------\n//                                IMPLEMENTATION DETAILS BELOW\n// ---------------------------------------------------------------------------------------------------\n// ---------------------------------------------------------------------------------------------------\n\n    namespace details\n    {\n        template<class T>\n        struct is_optional : std::false_type{};\n\n        template<class T>\n        struct is_optional<dlib::optional<T>> : std::true_type{};\n\n        template<class T, class U>\n        using is_constructible_from = And<\n            !std::is_constructible<T,       dlib::optional<U>&>::value,\n            !std::is_constructible<T, const dlib::optional<U>&>::value,\n            !std::is_constructible<T,       dlib::optional<U>&&>::value,\n            !std::is_constructible<T, const dlib::optional<U>&&>::value,\n            !std::is_convertible<      dlib::optional<U>&, T>::value,\n            !std::is_convertible<const dlib::optional<U>&, T>::value,\n            !std::is_convertible<      dlib::optional<U>&&, T>::value,\n            !std::is_convertible<const dlib::optional<U>&&, T>::value\n        >;\n\n        template<class T, class U>\n        using is_assignable_from = And<\n            is_constructible_from<T,U>::value,\n            std::is_assignable<T&,       dlib::optional<U>&>::value,\n            std::is_assignable<T&, const dlib::optional<U>&>::value,\n            std::is_assignable<T&,       dlib::optional<U>&&>::value,\n            std::is_assignable<T&, const dlib::optional<U>&&>::value\n        >;\n\n        template<class T, class U>\n        using is_copy_convertible = std::enable_if_t<\n            is_constructible_from<T,U>::value &&\n            std::is_constructible<T, const U&>::value,\n            bool\n        >;\n\n        template<class T, class U>\n        using is_move_convertible = std::enable_if_t<\n            is_constructible_from<T,U>::value &&\n            std::is_constructible<T, U&&>::value,\n            bool\n        >;\n\n        template<class T, class U>\n        using is_copy_assignable = std::enable_if_t<\n            is_assignable_from<T,U>::value              &&\n            std::is_constructible<T, const U&>::value   &&\n            std::is_assignable<T&, const U&>::value,\n            bool\n        >;\n\n        template<class T, class U>\n        using is_move_assignable = std::enable_if_t<\n            is_assignable_from<T,U>::value      &&\n            std::is_constructible<T, U>::value  &&\n            std::is_assignable<T&, U>::value,\n            bool\n        >;\n\n        template<class T, class U, class U_ = std::decay_t<U>>\n        using is_construct_convertible_from = std::enable_if_t<\n            std::is_constructible<T, U&&>::value &&\n            !std::is_same<U_, in_place_t>::value &&\n            !std::is_same<U_, dlib::optional<T>>::value,\n            bool\n        >;\n\n        template <class T, class U, class U_ = std::decay_t<U>>\n        using is_assign_convertible_from = std::enable_if_t<\n            std::is_constructible<T, U>::value  && \n            std::is_assignable<T&, U>::value    &&\n            !std::is_same<U_, dlib::optional<T>>::value &&\n            (!std::is_scalar<T>::value || !std::is_same<T, U_>::value),\n            bool\n        >;\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class T,\n          bool = std::is_trivially_destructible<T>::value\n        >\n        struct optional_storage\n        {\n            constexpr optional_storage() noexcept\n            : e{}, active{false}\n            {}\n\n            template<class ...U>\n            constexpr optional_storage(in_place_t, U&& ...u) noexcept(std::is_nothrow_constructible<T,U...>::value)\n            : val{std::forward<U>(u)...}, active{true} \n            {}\n\n            ~optional_storage() noexcept(std::is_nothrow_destructible<T>::value)\n            {\n                if (active)\n                    val.~T();\n            }           \n\n            struct empty{};\n            union {T val; empty e;};\n            bool active{false};\n        };\n\n        template <class T>\n        struct optional_storage<T, true>\n        {\n            constexpr optional_storage() noexcept\n            : e{}, active{false}\n            {}\n\n            template<class ...U>\n            constexpr optional_storage(in_place_t, U&& ...u) noexcept(std::is_nothrow_constructible<T,U...>::value)\n            : val{std::forward<U>(u)...}, active{true} \n            {}\n\n            struct empty{};\n            union {T val; empty e;};\n            bool active{false};\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <class T>\n        struct optional_ops : optional_storage<T> \n        {\n            using optional_storage<T>::optional_storage;\n\n            template <class... U> \n            constexpr void construct(U&&... u) noexcept(std::is_nothrow_constructible<T,U...>::value)\n            {\n                new (std::addressof(this->val)) T(std::forward<U>(u)...);\n                this->active = true;\n            }\n\n            template<class Optional>\n            constexpr void assign(Optional&& rhs) noexcept(std::is_nothrow_constructible<T,Optional>::value &&\n                                                           std::is_nothrow_assignable<T&,Optional>::value)\n            {\n                if (this->active && rhs.active)\n                    this->val = std::forward<Optional>(rhs).val;\n                else if (!this->active && rhs.active)\n                    construct(std::forward<Optional>(rhs).val);\n                else if (this->active && !rhs.active)\n                    destruct();\n            }\n\n            constexpr void destruct() noexcept(std::is_nothrow_destructible<T>::value)\n            {\n                if (this->active)\n                {\n                    this->val.~T();\n                    this->active = false;\n                }\n            }\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <class T, bool = std::is_trivially_copy_constructible<T>::value>\n        struct optional_copy : optional_ops<T> \n        {\n            using optional_ops<T>::optional_ops;\n        };\n\n        template <class T>\n        struct optional_copy<T, false> : optional_ops<T> \n        {\n            using optional_ops<T>::optional_ops;\n\n            constexpr optional_copy()                                       = default;\n            constexpr optional_copy(optional_copy&& rhs)                    = default;\n            constexpr optional_copy &operator=(const optional_copy& rhs)    = default;\n            constexpr optional_copy &operator=(optional_copy&& rhs)         = default;\n\n            constexpr optional_copy(const optional_copy& rhs) noexcept(std::is_nothrow_copy_constructible<T>::value)\n            : optional_ops<T>() \n            {\n                if (rhs.active)\n                    this->construct(rhs.val);\n            }\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <class T, bool = std::is_trivially_move_constructible<T>::value>\n        struct optional_move : optional_copy<T> \n        {\n            using optional_copy<T>::optional_copy;\n        };\n\n        template <class T> \n        struct optional_move<T, false> : optional_copy<T> \n        {\n            using optional_copy<T>::optional_copy;\n\n            constexpr optional_move()                                       = default;\n            constexpr optional_move(const optional_move& rhs)               = default;\n            constexpr optional_move& operator=(const optional_move& rhs)    = default;\n            constexpr optional_move& operator=(optional_move&& rhs)         = default;\n\n            constexpr optional_move(optional_move&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value)\n            {\n                if (rhs.active)\n                    this->construct(std::move(rhs.val));\n            }\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class T, \n          bool = std::is_trivially_copy_assignable<T>::value       &&\n                 std::is_trivially_copy_constructible<T>::value    &&\n                 std::is_trivially_destructible<T>::value\n        >\n        struct optional_copy_assign : optional_move<T> \n        {\n            using optional_move<T>::optional_move;\n        };\n\n        template <class T>\n        struct optional_copy_assign<T, false> : optional_move<T> \n        {\n            using optional_move<T>::optional_move;\n\n            constexpr optional_copy_assign()                                        = default;\n            constexpr optional_copy_assign(const optional_copy_assign& rhs)         = default;\n            constexpr optional_copy_assign(optional_copy_assign&& rhs)              = default;\n            constexpr optional_copy_assign& operator=(optional_copy_assign &&rhs)   = default;\n\n            constexpr optional_copy_assign& operator=(const optional_copy_assign &rhs) \n            noexcept(std::is_nothrow_copy_constructible<T>::value && \n                    std::is_nothrow_copy_assignable<T>::value)\n            {\n                this->assign(rhs);\n                return *this;\n            }        \n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class T, \n          bool = std::is_trivially_destructible<T>::value       &&\n                 std::is_trivially_move_constructible<T>::value &&\n                 std::is_trivially_move_assignable<T>::value\n        >\n        struct optional_move_assign : optional_copy_assign<T> \n        {\n            using optional_copy_assign<T>::optional_copy_assign;\n        };\n\n        template <class T>\n        struct optional_move_assign<T, false> : optional_copy_assign<T> \n        {\n            using optional_copy_assign<T>::optional_copy_assign;\n\n            constexpr optional_move_assign()                                              = default;\n            constexpr optional_move_assign(const optional_move_assign &rhs)               = default;\n            constexpr optional_move_assign(optional_move_assign &&rhs)                    = default;\n            constexpr optional_move_assign& operator=(const optional_move_assign &rhs)    = default;\n\n            constexpr optional_move_assign& operator=(optional_move_assign &&rhs) \n            noexcept(std::is_nothrow_move_constructible<T>::value && \n                    std::is_nothrow_move_assignable<T>::value)\n            {\n                this->assign(std::move(rhs));\n                return *this;\n            }\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class T, \n          bool copyable = std::is_copy_constructible<T>::value,\n          bool moveable = std::is_move_constructible<T>::value\n        >\n        struct optional_delete_constructors\n        {\n            constexpr optional_delete_constructors()                                                = default;\n            constexpr optional_delete_constructors(const optional_delete_constructors&)             = default;\n            constexpr optional_delete_constructors(optional_delete_constructors&&)                  = default;\n            constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;\n            constexpr optional_delete_constructors& operator=(optional_delete_constructors &&)      = default;\n        };\n\n        template <class T> \n        struct optional_delete_constructors<T, true, false> \n        {\n            constexpr optional_delete_constructors()                                                = default;\n            constexpr optional_delete_constructors(const optional_delete_constructors&)             = default;\n            constexpr optional_delete_constructors(optional_delete_constructors&&)                  = delete;\n            constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;\n            constexpr optional_delete_constructors& operator=(optional_delete_constructors &&)      = default;\n        };\n\n        template <class T> \n        struct optional_delete_constructors<T, false, true>\n        {\n            constexpr optional_delete_constructors()                                                = default;\n            constexpr optional_delete_constructors(const optional_delete_constructors&)             = delete;\n            constexpr optional_delete_constructors(optional_delete_constructors&&)                  = default;\n            constexpr optional_delete_constructors& operator=(const optional_delete_constructors &) = default;\n            constexpr optional_delete_constructors& operator=(optional_delete_constructors &&)      = default;\n        };\n\n        template <class T> \n        struct optional_delete_constructors<T, false, false>\n        {\n            constexpr optional_delete_constructors()                                                = default;\n            constexpr optional_delete_constructors(const optional_delete_constructors&)             = delete;\n            constexpr optional_delete_constructors(optional_delete_constructors&&)                  = delete;\n            constexpr optional_delete_constructors& operator=(const optional_delete_constructors&)  = default;\n            constexpr optional_delete_constructors& operator=(optional_delete_constructors &&)      = default;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n        template <\n          class T,\n          bool copyable = (std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value),\n          bool moveable = (std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)\n        >\n        struct optional_delete_assign\n        {\n            constexpr optional_delete_assign()                                          = default;\n            constexpr optional_delete_assign(const optional_delete_assign &)            = default;\n            constexpr optional_delete_assign(optional_delete_assign &&)                 = default;\n            constexpr optional_delete_assign& operator=(const optional_delete_assign &) = default;\n            constexpr optional_delete_assign& operator=(optional_delete_assign &&)      = default;\n        };\n\n        template <class T> \n        struct optional_delete_assign<T, true, false>\n        {\n            constexpr optional_delete_assign()                                          = default;\n            constexpr optional_delete_assign(const optional_delete_assign &)            = default;\n            constexpr optional_delete_assign(optional_delete_assign &&)                 = default;\n            constexpr optional_delete_assign& operator=(const optional_delete_assign &) = default;\n            constexpr optional_delete_assign& operator=(optional_delete_assign &&)      = delete;\n        };\n\n        template <class T> \n        struct optional_delete_assign<T, false, true>\n        {\n            constexpr optional_delete_assign()                                          = default;\n            constexpr optional_delete_assign(const optional_delete_assign &)            = default;\n            constexpr optional_delete_assign(optional_delete_assign &&)                 = default;\n            constexpr optional_delete_assign& operator=(const optional_delete_assign &) = delete;\n            constexpr optional_delete_assign& operator=(optional_delete_assign &&)      = default;\n        };\n\n        template <class T> \n        struct optional_delete_assign<T, false, false>\n        {\n            constexpr optional_delete_assign()                                          = default;\n            constexpr optional_delete_assign(const optional_delete_assign &)            = default;\n            constexpr optional_delete_assign(optional_delete_assign &&)                 = default;\n            constexpr optional_delete_assign& operator=(const optional_delete_assign &) = delete;\n            constexpr optional_delete_assign& operator=(optional_delete_assign &&)      = delete;\n        };\n\n// ---------------------------------------------------------------------------------------------------\n\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    template <class T>\n    class optional : private details::optional_move_assign<T>,\n                     private details::optional_delete_constructors<T>,\n                     private details::optional_delete_assign<T> \n    {\n        using base = details::optional_move_assign<T>;\n\n        static_assert(!std::is_reference<T>::value,         \"optional<T&> not allowed\");\n        static_assert(!std::is_same<T, in_place_t>::value,  \"optional<in_place_t> not allowed\");\n        static_assert(!std::is_same<T, nullopt_t>::value,   \"optional<nullopt_t> not allowed\");\n\n    public:\n        using value_type = T;\n        \n        constexpr optional()                                = default;\n        constexpr optional(const optional &rhs)             = default;\n        constexpr optional(optional &&rhs)                  = default;\n        constexpr optional& operator=(const optional &rhs)  = default;\n        constexpr optional& operator=(optional &&rhs)       = default;\n        ~optional()                                         = default;\n\n        constexpr optional(nullopt_t) noexcept {}\n\n        constexpr optional& operator=(nullopt_t) noexcept \n        {\n            if (*this)\n                reset();\n            return *this;\n        }\n\n        template <\n          class U, \n          details::is_copy_convertible<T,U> = true,\n          std::enable_if_t<!std::is_convertible<const U&, T>::value, bool> = true\n        >\n        constexpr explicit optional(const optional<U> &rhs) noexcept(std::is_nothrow_constructible<T,const U&>::value)\n        {\n            if (rhs)\n                this->construct(*rhs);\n        }\n\n        template <\n          class U, \n          details::is_copy_convertible<T,U> = true,\n          std::enable_if_t<std::is_convertible<const U&, T>::value, bool> = true\n        >\n        constexpr optional(const optional<U> &rhs) noexcept(std::is_nothrow_constructible<T,const U&>::value)\n        {\n            if (rhs)\n                this->construct(*rhs);\n        }\n\n        template <\n          class U, \n          details::is_move_convertible<T,U> = true,\n          std::enable_if_t<!std::is_convertible<U&&, T>::value, bool> = true\n        >\n        constexpr explicit optional(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T,U&&>::value)\n        {\n            if (rhs)\n                this->construct(std::move(*rhs));\n        }\n\n        template <\n          class U, \n          details::is_move_convertible<T,U> = true,\n          std::enable_if_t<std::is_convertible<U&&, T>::value, bool> = true\n        >\n        constexpr optional(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T,U&&>::value)\n        {\n            if (rhs)\n                this->construct(std::move(*rhs));\n        }\n\n        template <\n          class... Args,\n          std::enable_if_t<std::is_constructible<T, Args...>::value, bool> = true\n        >\n        constexpr explicit optional (\n            in_place_t,\n            Args&&... args\n        ) noexcept(std::is_nothrow_constructible<T,Args&&...>::value)\n        : base(in_place, std::forward<Args>(args)...)\n        {\n        }\n\n        template <\n          class U, \n          class... Args,\n          std::enable_if_t<std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value, bool> = true\n        >\n        constexpr explicit optional (\n            in_place_t,\n            std::initializer_list<U> il,\n            Args &&... args\n        ) noexcept(std::is_nothrow_constructible<T,std::initializer_list<U>&,Args&&...>::value)\n        {\n            this->construct(il, std::forward<Args>(args)...);\n        }\n\n        template<\n          class U,\n          details::is_construct_convertible_from<T,U> = true,\n          std::enable_if_t<!std::is_convertible<U&&, T>::value, bool> = true\n        >\n        constexpr explicit optional(U &&u) noexcept(std::is_nothrow_constructible<T, U&&>::value)\n        : base(in_place, std::forward<U>(u))\n        {\n        }\n\n        template<\n          class U,\n          details::is_construct_convertible_from<T,U> = true,\n          std::enable_if_t<std::is_convertible<U&&, T>::value, bool> = true\n        >\n        constexpr optional(U &&u) noexcept(std::is_nothrow_constructible<T, U&&>::value)\n        : base(in_place, std::forward<U>(u))\n        {\n        }      \n\n        template <\n          class U,\n          details::is_copy_assignable<T, U> = true\n        >\n        constexpr optional &operator=(const optional<U>& rhs) noexcept(std::is_nothrow_constructible<T, const U&>::value &&\n                                                                       std::is_nothrow_assignable<T, const U&>::value)\n        {\n            this->assign(rhs);\n            return *this;\n        }\n\n        template <\n          class U,\n          details::is_move_assignable<T, U> = true\n        >\n        constexpr optional &operator=(optional<U>&& rhs) noexcept(std::is_nothrow_constructible<T, U>::value &&\n                                                                  std::is_nothrow_assignable<T, U>::value)\n        {\n            this->assign(std::move(rhs));\n            return *this;\n        }\n        \n        template <\n          class U, \n          details::is_assign_convertible_from<T,U> = true\n        >\n        constexpr optional& operator=(U &&u) noexcept(std::is_nothrow_constructible<T, U>::value &&\n                                                      std::is_nothrow_assignable<T, U>::value)\n        {\n            if (*this)\n                **this = std::forward<U>(u);\n            else\n                this->construct(std::forward<U>(u));\n            return *this;\n        }\n\n        template <class... Args> \n        constexpr T& emplace(Args &&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value)\n        {\n            reset();\n            this->construct(std::forward<Args>(args)...);\n            return **this;\n        }\n\n        template <class U, class... Args>\n        constexpr T& emplace(std::initializer_list<U> il, Args &&... args) \n        {\n            reset();\n            this->construct(il, std::forward<Args>(args)...);\n            return **this;   \n        }\n\n        void swap(optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value &&\n                                          dlib::is_nothrow_swappable<T>::value) \n        {\n            using std::swap;\n\n            if (*this && rhs)\n            {\n                swap(**this, *rhs);\n            }\n                \n            else if (*this && !rhs)\n            {\n                rhs = std::move(**this);\n                reset();\n            }\n            \n            else if (!*this && rhs)\n            {\n                *this = std::move(*rhs);\n                rhs.reset();\n            }\n        }\n\n        constexpr const T*  operator->() const  noexcept { return &this->val; }\n        constexpr T*        operator->()        noexcept { return &this->val; }\n        constexpr T&        operator*() &       noexcept { return this->val; }\n        constexpr const T&  operator*() const&  noexcept { return this->val; }\n        constexpr T&&       operator*() &&      noexcept { return std::move(this->val); }\n        constexpr const T&& operator*() const&& noexcept { return std::move(this->val); }\n        constexpr explicit  operator bool() const noexcept { return this->active; }\n        constexpr bool      has_value()     const noexcept { return this->active; }\n\n        constexpr T& value() & \n        {\n            if (*this)\n                return **this;\n            throw bad_optional_access();\n        }\n\n        constexpr const T& value() const & \n        {\n            if (*this)\n                return **this;\n            throw bad_optional_access();\n        }\n\n        constexpr T&& value() && \n        {\n            if (*this)\n                return std::move(**this);\n            throw bad_optional_access();\n        }\n\n        constexpr const T&& value() const && \n        {\n            if (*this)\n                return std::move(**this);\n            throw bad_optional_access();\n        }\n\n        template <class U> \n        constexpr T value_or(U &&u) const & \n        {\n            return *this ? **this : static_cast<T>(std::forward<U>(u));\n        }\n\n        template <class U> \n        constexpr T value_or(U &&u) && \n        {\n            return *this ? std::move(**this) : static_cast<T>(std::forward<U>(u));\n        }\n\n        void reset() noexcept(std::is_nothrow_destructible<T>::value)\n        {\n            this->destruct();\n        }\n\n        template <\n          class F,\n          class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,T&>>,\n          std::enable_if_t<details::is_optional<Return>::value, bool> = true\n        >\n        constexpr auto and_then(F&& f) &\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), **this);\n            else\n                return Return{};\n        }\n\n        template <\n          class F,\n          class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T&>>,\n          std::enable_if_t<details::is_optional<Return>::value, bool> = true\n        >\n        constexpr auto and_then(F&& f) const&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), **this);\n            else\n                return Return{};\n        }\n\n        template <\n          class F,\n          class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,T>>,\n          std::enable_if_t<details::is_optional<Return>::value, bool> = true\n        >\n        constexpr auto and_then(F&& f) &&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), std::move(**this));\n            else\n                return Return{};\n        }\n\n        template <\n          class F,\n          class Return = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T>>,\n          std::enable_if_t<details::is_optional<Return>::value, bool> = true\n        >\n        constexpr auto and_then(F&& f) const&&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), std::move(**this));\n            else\n                return Return{};\n        }\n\n        template <\n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F, T&>>,\n          std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,\n          std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true\n        >\n        constexpr dlib::optional<U> transform(F&& f) &\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), **this);\n            else\n                return dlib::optional<U>{};\n        }\n\n        template <\n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F, const T&>>,\n          std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,\n          std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true\n        >\n        constexpr dlib::optional<U> transform(F&& f) const&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), **this);\n            else\n                return dlib::optional<U>{};\n        }\n\n        template <\n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F,T>>,\n          std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,\n          std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true\n        >\n        constexpr dlib::optional<U> transform(F&& f) &&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), std::move(**this));\n            else\n                return dlib::optional<U>{};\n        }\n\n        template <\n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F,const T>>,\n          std::enable_if_t<!std::is_same<U, dlib::in_place_t>::value, bool> = true,\n          std::enable_if_t<!std::is_same<U, dlib::nullopt_t>::value, bool> = true\n        >\n        constexpr dlib::optional<U> transform(F&& f) const&&\n        {\n            if (*this)\n                return dlib::invoke(std::forward<F>(f), std::move(**this));\n            else\n                return dlib::optional<U>{};\n        }\n\n        template < \n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F>>,\n          std::enable_if_t<std::is_same<U, dlib::optional<T>>::value, bool> = true\n        >\n        constexpr optional or_else( F&& f ) const&\n        {\n            return *this ? *this : std::forward<F>(f)();\n        }\n\n        template < \n          class F,\n          class U = dlib::remove_cvref_t<dlib::invoke_result_t<F>>,\n          std::enable_if_t<std::is_same<U, dlib::optional<T>>::value, bool> = true\n        >\n        constexpr optional or_else( F&& f ) &&\n        {\n            return *this ? std::move(*this) : std::forward<F>(f)();\n        }\n    };\n\n// ---------------------------------------------------------------------------------------------------\n\n    template <class T, class U>\n    constexpr bool operator==(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() == std::declval<T>()))\n    {        \n        return bool(lhs) == bool(rhs) && (!bool(lhs) || *lhs == *rhs);\n    }\n\n    template <class T, class U> \n    constexpr bool operator!=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() != std::declval<T>()))\n    { \n        return !(lhs == rhs); \n    }\n        \n    template <class T, class U> \n    constexpr bool operator<(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() < std::declval<T>()))\n    {\n        return bool(rhs) && (!bool(lhs) || *lhs < *rhs);\n    }\n\n    template <class T, class U>\n    constexpr bool operator>=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() >= std::declval<T>()))\n    {\n        return !(lhs < rhs);\n    }\n    \n    template <class T, class U>\n    constexpr bool operator>(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() > std::declval<T>()))\n    {\n        return bool(lhs) && (!bool(rhs) || *lhs > *rhs);\n    }\n\n    template <class T, class U>\n    constexpr bool operator<=(const optional<T> &lhs, const optional<U> &rhs) noexcept(noexcept(std::declval<T>() <= std::declval<T>()))\n    {\n        return !(lhs > rhs);\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    template <class T>\n    constexpr bool operator==(const optional<T> &lhs, nullopt_t) noexcept\n    {\n        return !bool(lhs);\n    }\n\n    template <class T>\n    constexpr bool operator==(nullopt_t, const optional<T> &rhs) noexcept \n    {\n        return !bool(rhs);\n    }\n        \n    template <class T>\n    constexpr bool operator!=(const optional<T> &lhs, nullopt_t) noexcept \n    {\n        return bool(lhs);\n    }\n\n    template <class T>\n    constexpr bool operator!=(nullopt_t, const optional<T> &rhs) noexcept \n    {\n        return bool(rhs);\n    }\n        \n    template <class T>\n    constexpr bool operator<(const optional<T> &, nullopt_t) noexcept \n    {\n        return false;\n    }\n        \n    template <class T>\n    constexpr bool operator<(nullopt_t, const optional<T> &rhs) noexcept \n    {\n        return bool(rhs);\n    }\n\n    template <class T>\n    constexpr bool operator<=(const optional<T> &lhs, nullopt_t) noexcept\n    {\n        return !bool(lhs);\n    }\n\n    template <class T>\n    constexpr bool operator<=(nullopt_t, const optional<T> &) noexcept \n    {\n        return true;\n    }\n\n    template <class T>\n    constexpr bool operator>(const optional<T> &lhs, nullopt_t) noexcept\n    {\n        return bool(lhs);\n    }\n\n    template <class T>\n    constexpr bool operator>(nullopt_t, const optional<T> &) noexcept \n    {\n        return false;\n    }\n\n    template <class T>\n    constexpr bool operator>=(const optional<T> &, nullopt_t) noexcept \n    {\n        return true;\n    }\n\n    template <class T>\n    constexpr bool operator>=(nullopt_t, const optional<T> &rhs) noexcept \n    {\n        return !rhs.has_value();\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    template <class T, class U>\n    constexpr bool operator==(const optional<T> &lhs, const U &rhs) \n    {\n        return bool(lhs) ? *lhs == rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator==(const U &lhs, const optional<T> &rhs) \n    {\n        return bool(rhs) ? lhs == *rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator!=(const optional<T> &lhs, const U &rhs) \n    {\n        return bool(lhs) ? *lhs != rhs : true;\n    }\n\n    template <class T, class U>\n    constexpr bool operator!=(const U &lhs, const optional<T> &rhs) \n    {\n        return bool(rhs) ? lhs != *rhs : true;\n    }\n\n    template <class T, class U>\n    constexpr bool operator<(const optional<T> &lhs, const U &rhs) \n    {\n        return bool(lhs) ? *lhs < rhs : true;\n    }\n\n    template <class T, class U>\n    constexpr bool operator<(const U &lhs, const optional<T> &rhs) \n    {\n        return bool(rhs) ? lhs < *rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator<=(const optional<T> &lhs, const U &rhs)\n    {\n        return bool(lhs) ? *lhs <= rhs : true;\n    }\n\n    template <class T, class U>\n    constexpr bool operator<=(const U &lhs, const optional<T> &rhs)\n    {\n        return bool(rhs) ? lhs <= *rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator>(const optional<T> &lhs, const U &rhs) \n    {\n        return bool(lhs) ? *lhs > rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator>(const U &lhs, const optional<T> &rhs)\n    {\n        return bool(rhs) ? lhs > *rhs : true;\n    }\n\n    template <class T, class U>\n    constexpr bool operator>=(const optional<T> &lhs, const U &rhs) \n    {\n        return bool(lhs) ? *lhs >= rhs : false;\n    }\n\n    template <class T, class U>\n    constexpr bool operator>=(const U &lhs, const optional<T> &rhs)\n    {\n        return bool(rhs) ? lhs >= *rhs : true;\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    template <\n        class T,\n        std::enable_if_t<\n        std::is_move_constructible<T>::value &&\n        dlib::is_swappable<T>::value,\n        bool> = true\n    >\n    void swap(dlib::optional<T>& lhs, dlib::optional<T>& rhs) noexcept(noexcept(lhs.swap(rhs))) \n    {\n        return lhs.swap(rhs);\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n    template< class T >\n    constexpr dlib::optional<std::decay_t<T>> make_optional( T&& value )\n    {\n        return dlib::optional<std::decay_t<T>>(std::forward<T>(value));\n    }\n\n    template< class T, class... Args >\n    constexpr dlib::optional<T> make_optional( Args&&... args )\n    {\n        return dlib::optional<T>(dlib::in_place, std::forward<Args>(args)...);\n    }\n\n    template< class T, class U, class... Args >\n    constexpr dlib::optional<T> make_optional( std::initializer_list<U> il, Args&&... args )\n    {\n        return dlib::optional<T>(dlib::in_place, il, std::forward<Args>(args)...);\n    }\n\n// ---------------------------------------------------------------------------------------------------\n\n}\n\n#endif\n"
  },
  {
    "path": "dlib/ostream",
    "content": "#include \"dlib_include_path_tutorial.txt\"\n"
  },
  {
    "path": "dlib/overloaded.h",
    "content": "// Copyright (C) 2022  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_OVERLOADED_H_\n#define DLIB_OVERLOADED_H_\n\n#include <utility>\n#include <type_traits>\n\nnamespace dlib\n{\n    namespace detail\n    {\n#if __cpp_fold_expressions\n        template<typename ...Base>\n        struct overloaded_helper : Base...\n        {\n            template<typename... T>\n            constexpr overloaded_helper(T&& ... t)\n            noexcept((std::is_nothrow_constructible<Base,T&&>::value && ...))\n            : Base{std::forward<T>(t)}... {}\n\n            using Base::operator()...;\n        };\n#else\n        template<typename Base, typename ... BaseRest>\n        struct overloaded_helper: Base, overloaded_helper<BaseRest...>\n        {\n            template<typename T, typename ... TRest>\n            constexpr overloaded_helper(T&& t, TRest&& ...trest) \n            noexcept(std::is_nothrow_constructible<Base, T&&>::value && std::is_nothrow_constructible<overloaded_helper<BaseRest...>, TRest&&...>::value)\n            : Base{std::forward<T>(t)},\n              overloaded_helper<BaseRest...>{std::forward<TRest>(trest)...}\n            {}\n\n            using Base::operator();\n            using overloaded_helper<BaseRest...>::operator();\n        };\n\n        template<typename Base>\n        struct overloaded_helper<Base> : Base\n        {\n            template<typename T>\n            constexpr overloaded_helper<Base>(T&& t) \n            noexcept(std::is_nothrow_constructible<Base, T&&>::value)\n            : Base{std::forward<T>(t)}\n            {}\n\n            using Base::operator();\n        };\n#endif //__cpp_fold_expressions\n    }\n    \n    template<typename... T>\n    constexpr auto overloaded(T&&... t)\n    /*!\n        This is a helper function for combining many callable objects (usually lambdas), into\n        an overload-able set. This can be used in visitor patterns like\n            - dlib::type_safe_union::apply_to_contents()\n            - dlib::visit()\n            - dlib::for_each_type()\n            - dlib::switch_()\n\n        A picture paints a thousand words:\n\n        using tsu = type_safe_union<int,float,std::string>;\n\n        tsu a = std::string(\"hello there\");\n\n        std::string result;\n\n        a.apply_to_contents(overloaded(\n            [&result](int) {\n                result = std::string(\"int\");\n            },\n            [&result](float) {\n                result = std::string(\"float\");\n            },\n            [&result](const std::string& item) {\n                result = item;\n            }\n        ));\n\n        assert(result == \"hello there\");\n        result = \"\";\n\n        result = visit(overloaded(\n            [](int) {\n                return std::string(\"int\");\n            },\n            [](float) {\n                return std::string(\"float\");\n            },\n            [](const std::string& item) {\n                return item;\n            }\n        ), a);\n\n        assert(result == \"hello there\");\n\n        std::vector<int> type_ids;\n\n        for_each_type(a, overloaded(\n            [&type_ids](in_place_tag<int>, tsu& me) {\n                type_ids.push_back(me.get_type_id<int>());\n            },\n            [&type_ids](in_place_tag<float>, tsu& me) {\n                type_ids.push_back(me.get_type_id<float>());\n            },\n            [&type_ids](in_place_tag<std::string>, tsu& me) {\n                type_ids.push_back(me.get_type_id<std::string>());\n            }\n        ));\n\n        assert(type_ids == vector<int>({0,1,2}));\n    !*/\n    noexcept(std::is_nothrow_constructible<detail::overloaded_helper<std::decay_t<T>...>, T&&...>::value)\n    {\n        return detail::overloaded_helper<std::decay_t<T>...>{std::forward<T>(t)...};\n    }\n}\n\n#endif //DLIB_OVERLOADED_H_\n"
  },
  {
    "path": "dlib/pipe/pipe_kernel_1.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PIPE_KERNEl_1_ \n#define DLIB_PIPE_KERNEl_1_ \n\n#include \"../algs.h\"\n#include \"../threads.h\"\n#include \"pipe_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T\n        >\n    class pipe \n    {\n        /*!\n            INITIAL VALUE\n                - pipe_size == 0\n                - pipe_max_size == defined by constructor\n                - enabled == true\n                - data == a pointer to an array of ((pipe_max_size>0)?pipe_max_size:1) T objects.\n                - dequeue_waiters == 0\n                - enqueue_waiters == 0\n                - first == 1\n                - last == 1\n                - unblock_sig_waiters == 0\n\n            CONVENTION\n                - size() == pipe_size\n                - max_size() == pipe_max_size\n                - is_enabled() == enabled\n\n                - m == the mutex used to lock access to all the members of this class\n\n                - dequeue_waiters == the number of threads blocked on calls to dequeue()\n                - enqueue_waiters == the number of threads blocked on calls to enqueue() and \n                  wait_until_empty()\n                - unblock_sig_waiters == the number of threads blocked on calls to \n                  wait_for_num_blocked_dequeues() and the destructor.  (i.e. the number of\n                  blocking calls to unblock_sig.wait())\n\n                - dequeue_sig == the signaler that threads blocked on calls to dequeue() wait on\n                - enqueue_sig == the signaler that threads blocked on calls to enqueue() \n                  or wait_until_empty() wait on.\n                - unblock_sig == the signaler that is signaled when a thread stops blocking on a call\n                  to enqueue() or dequeue().  It is also signaled when a dequeue that will probably\n                  block is called.  The destructor and wait_for_num_blocked_dequeues are the only \n                  things that will wait on this signaler.\n\n                - if (pipe_size > 0) then\n                    - data[first] == the next item to dequeue\n                    - data[last] == the item most recently added via enqueue, so the last to dequeue.\n                - else if (pipe_max_size == 0)\n                    - if (first == 0 && last == 0) then\n                        - data[0] == the next item to dequeue\n                    - else if (first == 0 && last == 1) then \n                        - data[0] has been taken out already by a dequeue\n        !*/\n\n    public:\n        // this is here for backwards compatibility with older versions of dlib.\n        typedef pipe kernel_1a;\n\n        typedef T type;\n\n        explicit pipe (  \n            size_t maximum_size\n        );\n\n        virtual ~pipe (\n        );\n\n        void empty (\n        );\n\n        void wait_until_empty (\n        ) const;\n\n        void wait_for_num_blocked_dequeues (\n            unsigned long num\n        )const;\n\n        void enable (\n        );\n\n        void disable (\n        );\n\n        bool is_enqueue_enabled (\n        ) const;\n\n        void disable_enqueue (\n        );\n\n        void enable_enqueue (\n        );\n\n        bool is_dequeue_enabled (\n        ) const;\n\n        void disable_dequeue (\n        );\n\n        void enable_dequeue (\n        );\n\n        bool is_enabled (\n        ) const;\n\n        size_t max_size (\n        ) const;\n\n        size_t size (\n        ) const;\n\n        bool enqueue (\n            T& item\n        );\n\n        bool enqueue (\n            T&& item\n        ) { return enqueue(item); }\n\n        bool dequeue (\n            T& item\n        );\n\n        bool enqueue_or_timeout (\n            T& item,\n            unsigned long timeout\n        );\n\n        bool enqueue_or_timeout (\n            T&& item,\n            unsigned long timeout\n        ) { return enqueue_or_timeout(item,timeout); }\n\n        bool dequeue_or_timeout (\n            T& item,\n            unsigned long timeout\n        );\n\n    private:\n\n        size_t pipe_size;\n        const size_t pipe_max_size;\n        bool enabled;\n\n        T* const data;\n\n        size_t first;\n        size_t last;\n\n        mutex m;\n        signaler dequeue_sig;\n        signaler enqueue_sig;\n        signaler unblock_sig;\n\n        unsigned long dequeue_waiters;\n        mutable unsigned long enqueue_waiters;\n        mutable unsigned long unblock_sig_waiters;\n        bool enqueue_enabled;\n        bool dequeue_enabled;\n\n        // restricted functions\n        pipe(const pipe&);        // copy constructor\n        pipe& operator=(const pipe&);    // assignment operator\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                      member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    pipe<T>::\n    pipe (  \n        size_t maximum_size\n    ) : \n        pipe_size(0),\n        pipe_max_size(maximum_size),\n        enabled(true),\n        data(new T[(maximum_size>0) ? maximum_size : 1]),\n        first(1),\n        last(1),\n        dequeue_sig(m),\n        enqueue_sig(m),\n        unblock_sig(m),\n        dequeue_waiters(0),\n        enqueue_waiters(0),\n        unblock_sig_waiters(0),\n        enqueue_enabled(true),\n        dequeue_enabled(true)\n    {\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    pipe<T>::\n    ~pipe (\n    )\n    {\n        auto_mutex M(m);\n        ++unblock_sig_waiters;\n\n        // first make sure no one is blocked on any calls to enqueue() or dequeue()\n        enabled = false;\n        dequeue_sig.broadcast();\n        enqueue_sig.broadcast();\n        unblock_sig.broadcast();\n\n        // wait for all threads to unblock\n        while (dequeue_waiters > 0 || enqueue_waiters > 0 || unblock_sig_waiters > 1)\n            unblock_sig.wait();\n\n        delete [] data;\n        --unblock_sig_waiters;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    empty (\n    )\n    {\n        auto_mutex M(m);\n        pipe_size = 0;\n\n        // let any calls to enqueue() know that the pipe is now empty\n        if (enqueue_waiters > 0)\n            enqueue_sig.broadcast();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    wait_until_empty (\n    ) const\n    {\n        auto_mutex M(m);\n        // this function is sort of like a call to enqueue so treat it like that\n        ++enqueue_waiters;\n\n        while (pipe_size > 0 && enabled && dequeue_enabled )\n            enqueue_sig.wait();\n\n        // let the destructor know we are ending if it is blocked waiting\n        if (enabled == false)\n            unblock_sig.broadcast();\n\n        --enqueue_waiters;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    enable (\n    )\n    {\n        auto_mutex M(m);\n        enabled = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    disable (\n    )\n    {\n        auto_mutex M(m);\n        enabled = false;\n        dequeue_sig.broadcast();\n        enqueue_sig.broadcast();\n        unblock_sig.broadcast();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    is_enabled (\n    ) const\n    {\n        auto_mutex M(m);\n        return enabled;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    size_t pipe<T>::\n    max_size (\n    ) const\n    {\n        auto_mutex M(m);\n        return pipe_max_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    size_t pipe<T>::\n    size (\n    ) const\n    {\n        auto_mutex M(m);\n        return pipe_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    enqueue (\n        T& item\n    )\n    {\n        auto_mutex M(m);\n        ++enqueue_waiters;\n\n        // wait until there is room or we are disabled \n        while (pipe_size == pipe_max_size && enabled && enqueue_enabled &&\n               !(pipe_max_size == 0 && first == 1) )\n            enqueue_sig.wait();\n\n        if (enabled == false || enqueue_enabled == false)\n        {\n            --enqueue_waiters;\n            // let the destructor know we are unblocking\n            unblock_sig.broadcast();\n            return false;\n        }\n\n        // set the appropriate values for first and last\n        if (pipe_size == 0)\n        {\n            first = 0;\n            last = 0;\n        }\n        else\n        {\n            last = (last+1)%pipe_max_size;\n        }\n\n\n        exchange(item,data[last]);\n\n        // wake up a call to dequeue() if there are any currently blocked\n        if (dequeue_waiters > 0)\n            dequeue_sig.signal();\n\n        if (pipe_max_size > 0)\n        {\n            ++pipe_size;\n        }\n        else\n        {\n            // wait for a dequeue to take the item out\n            while (last == 0 && enabled && enqueue_enabled)\n                enqueue_sig.wait();\n\n            if (last == 0 && (enabled == false || enqueue_enabled == false))\n            {\n                last = 1;\n                first = 1;\n\n                // no one dequeued this object to put it back into item\n                exchange(item,data[0]);\n\n                --enqueue_waiters;\n                // let the destructor know we are unblocking\n                if (unblock_sig_waiters > 0)\n                    unblock_sig.broadcast();\n                return false;\n            }\n\n            last = 1;\n            first = 1;\n\n            // tell any waiting calls to enqueue() that one of them can proceed\n            if (enqueue_waiters > 1)\n                enqueue_sig.broadcast();\n\n            // let the destructor know we are unblocking\n            if (enabled == false && unblock_sig_waiters > 0)\n                unblock_sig.broadcast();\n        }\n\n        --enqueue_waiters;\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    dequeue (\n        T& item\n    )\n    {\n        auto_mutex M(m);\n        ++dequeue_waiters;\n\n        if (pipe_size == 0)\n        {\n            // notify wait_for_num_blocked_dequeues()\n            if (unblock_sig_waiters > 0)\n                unblock_sig.broadcast();\n\n            // notify any blocked enqueue_or_timeout() calls\n            if (enqueue_waiters > 0)\n                enqueue_sig.broadcast();\n        }\n\n        // wait until there is something in the pipe or we are disabled \n        while (pipe_size == 0 && enabled && dequeue_enabled &&\n               !(pipe_max_size == 0 && first == 0 && last == 0) )\n            dequeue_sig.wait();\n\n        if (enabled == false || dequeue_enabled == false)\n        {\n            --dequeue_waiters;\n            // let the destructor know we are unblocking\n            unblock_sig.broadcast();\n            return false;\n        }\n\n        exchange(item,data[first]);\n\n        if (pipe_max_size > 0)\n        {\n            // set the appropriate values for first \n            first = (first+1)%pipe_max_size;\n\n            --pipe_size;\n        }\n        else\n        {\n            // let the enqueue waiting on us know that we took the \n            // item out already.\n            last = 1;\n        }\n\n        // wake up a call to enqueue() if there are any currently blocked\n        if (enqueue_waiters > 0)\n            enqueue_sig.broadcast();\n\n        --dequeue_waiters;\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    enqueue_or_timeout (\n        T& item,\n        unsigned long timeout\n    )\n    {\n        auto_mutex M(m);\n        ++enqueue_waiters;\n\n        // wait until there is room or we are disabled or \n        // we run out of time.\n        bool timed_out = false;\n        while (pipe_size == pipe_max_size && enabled && enqueue_enabled &&\n               !(pipe_max_size == 0 && dequeue_waiters > 0 && first == 1) )\n        {\n            if (timeout == 0 || enqueue_sig.wait_or_timeout(timeout) == false)\n            {\n                timed_out = true;\n                break;\n            }\n        }\n\n        if (enabled == false || timed_out || enqueue_enabled == false)\n        {\n            --enqueue_waiters;\n            // let the destructor know we are unblocking\n            unblock_sig.broadcast();\n            return false;\n        }\n\n        // set the appropriate values for first and last\n        if (pipe_size == 0)\n        {\n            first = 0;\n            last = 0;\n        }\n        else\n        {\n            last = (last+1)%pipe_max_size;\n        }\n\n\n        exchange(item,data[last]);\n\n        // wake up a call to dequeue() if there are any currently blocked\n        if (dequeue_waiters > 0)\n            dequeue_sig.signal();\n\n        if (pipe_max_size > 0)\n        {\n            ++pipe_size;\n        }\n        else\n        {\n            // wait for a dequeue to take the item out\n            while (last == 0 && enabled && enqueue_enabled)\n                enqueue_sig.wait();\n\n            if (last == 0 && (enabled == false || enqueue_enabled == false))\n            {\n                last = 1;\n                first = 1;\n\n                // no one dequeued this object to put it back into item\n                exchange(item,data[0]);\n\n                --enqueue_waiters;\n                // let the destructor know we are unblocking\n                if (unblock_sig_waiters > 0)\n                    unblock_sig.broadcast();\n                return false;\n            }\n\n            last = 1;\n            first = 1;\n\n            // tell any waiting calls to enqueue() that one of them can proceed\n            if (enqueue_waiters > 1)\n                enqueue_sig.broadcast();\n\n            // let the destructor know we are unblocking\n            if (enabled == false && unblock_sig_waiters > 0)\n                unblock_sig.broadcast();\n        }\n\n        --enqueue_waiters;\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    dequeue_or_timeout (\n        T& item,\n        unsigned long timeout\n    )\n    {\n        auto_mutex M(m);\n        ++dequeue_waiters;\n\n        if (pipe_size == 0)\n        {\n            // notify wait_for_num_blocked_dequeues()\n            if (unblock_sig_waiters > 0)\n                unblock_sig.broadcast();\n\n            // notify any blocked enqueue_or_timeout() calls\n            if (enqueue_waiters > 0)\n                enqueue_sig.broadcast();\n        }\n\n        bool timed_out = false;\n        // wait until there is something in the pipe or we are disabled or we timeout.\n        while (pipe_size == 0 && enabled && dequeue_enabled &&\n               !(pipe_max_size == 0 && first == 0 && last == 0) )\n        {\n            if (timeout == 0 || dequeue_sig.wait_or_timeout(timeout) == false)\n            {\n                timed_out = true;\n                break;\n            }\n        }\n\n        if (enabled == false || timed_out || dequeue_enabled == false)\n        {\n            --dequeue_waiters;\n            // let the destructor know we are unblocking\n            unblock_sig.broadcast();\n            return false;\n        }\n\n        exchange(item,data[first]);\n\n        if (pipe_max_size > 0)\n        {\n            // set the appropriate values for first \n            first = (first+1)%pipe_max_size;\n\n            --pipe_size;\n        }\n        else\n        {\n            // let the enqueue waiting on us know that we took the \n            // item out already.\n            last = 1;\n        }\n\n        // wake up a call to enqueue() if there are any currently blocked\n        if (enqueue_waiters > 0)\n            enqueue_sig.broadcast();\n\n        --dequeue_waiters;\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    wait_for_num_blocked_dequeues (\n        unsigned long num\n    )const\n    {\n        auto_mutex M(m);\n        ++unblock_sig_waiters;\n\n        while ( (dequeue_waiters < num || pipe_size != 0) && enabled && dequeue_enabled)\n            unblock_sig.wait();\n\n        // let the destructor know we are ending if it is blocked waiting\n        if (enabled == false)\n            unblock_sig.broadcast();\n\n        --unblock_sig_waiters;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    is_enqueue_enabled (\n    ) const\n    {\n        auto_mutex M(m);\n        return enqueue_enabled;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    disable_enqueue (\n    )\n    {\n        auto_mutex M(m);\n        enqueue_enabled = false;\n        enqueue_sig.broadcast();\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    enable_enqueue (\n    )\n    {\n        auto_mutex M(m);\n        enqueue_enabled = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    bool pipe<T>::\n    is_dequeue_enabled (\n    ) const\n    {\n        auto_mutex M(m);\n        return dequeue_enabled;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    disable_dequeue (\n    )\n    {\n        auto_mutex M(m);\n        dequeue_enabled = false;\n        dequeue_sig.broadcast();\n    }\n\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    void pipe<T>::\n    enable_dequeue (\n    )\n    {\n        auto_mutex M(m);\n        dequeue_enabled = true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PIPE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/pipe/pipe_kernel_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_PIPE_KERNEl_ABSTRACT_ \n#ifdef DLIB_PIPE_KERNEl_ABSTRACT_ \n\n#include \"../threads.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T\n        >\n    class pipe \n    {\n        /*!\n            REQUIREMENTS ON T\n                T must be swappable by a global swap() \n                T must have a default constructor\n\n            INITIAL VALUE\n                size() == 0\n                is_enabled() == true\n                is_enqueue_enabled() == true\n                is_dequeue_enabled() == true\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a first in first out queue with a fixed maximum size containing \n                items of type T.  It is suitable for passing objects between threads.\n                \n            THREAD SAFETY\n                All methods of this class are thread safe.  You may call them from any\n                thread and any number of threads my call them at once.\n        !*/\n\n    public:\n\n        typedef T type;\n\n        explicit pipe (  \n            size_t maximum_size\n        );\n        /*!\n            ensures                \n                - #*this is properly initialized\n                - #max_size() == maximum_size\n            throws\n                - std::bad_alloc\n                - dlib::thread_error\n        !*/\n\n        virtual ~pipe (\n        );\n        /*!\n            ensures\n                - any resources associated with *this have been released\n                - disables (i.e. sets is_enabled() == false) this object so that \n                  all calls currently blocking on it will return immediately. \n        !*/\n\n        void enable (\n        );\n        /*!\n            ensures\n                - #is_enabled() == true\n        !*/\n\n        void disable (\n        );\n        /*!\n            ensures\n                - #is_enabled() == false\n                - causes all current and future calls to enqueue(), dequeue(),\n                  enqueue_or_timeout() and dequeue_or_timeout() to not block but \n                  to return false immediately until enable() is called.\n                - causes all current and future calls to wait_until_empty() and\n                  wait_for_num_blocked_dequeues() to not block but return\n                  immediately until enable() is called.\n        !*/\n\n        bool is_enabled (\n        ) const;\n        /*!\n            ensures\n                - returns true if this pipe is currently enabled, false otherwise.\n        !*/\n\n        void empty (\n        );\n        /*!\n            ensures\n                - #size() == 0\n        !*/\n\n        void wait_until_empty (\n        ) const;\n        /*!\n            ensures\n                - blocks until one of the following is the case:\n                    - size() == 0  \n                    - is_enabled() == false\n                    - is_dequeue_enabled() == false\n        !*/\n\n        void wait_for_num_blocked_dequeues (\n           unsigned long num\n        ) const;\n        /*!\n            ensures\n                - blocks until one of the following is the case: \n                    - size() == 0 and the number of threads blocked on calls \n                      to dequeue() and dequeue_or_timeout() is greater than \n                      or equal to num.\n                    - is_enabled() == false\n                    - is_dequeue_enabled() == false\n        !*/\n\n        bool is_enqueue_enabled (\n        ) const;\n        /*!\n            ensures\n                - returns true if the enqueue() and enqueue_or_timeout() functions are \n                  currently enabled, returns false otherwise.  (note that the higher \n                  level is_enabled() function can overrule this one.  So if \n                  is_enabled() == false then enqueue functions are still disabled even\n                  if is_enqueue_enabled() returns true.  But if is_enqueue_enabled() == false \n                  then enqueue functions are always disabled no matter the state of \n                  is_enabled())\n        !*/\n\n        void disable_enqueue (\n        );\n        /*!\n            ensures\n                - #is_enqueue_enabled() == false \n                - causes all current and future calls to enqueue() and\n                  enqueue_or_timeout() to not block but to return false \n                  immediately until enable_enqueue() is called.\n        !*/\n\n        void enable_enqueue (\n        );\n        /*!\n            ensures\n                - #is_enqueue_enabled() == true\n        !*/\n\n        bool is_dequeue_enabled (\n        ) const;\n        /*!\n            ensures\n                - returns true if the dequeue() and dequeue_or_timeout() functions are \n                  currently enabled, returns false otherwise.  (note that the higher \n                  level is_enabled() function can overrule this one.  So if \n                  is_enabled() == false then dequeue functions are still disabled even\n                  if is_dequeue_enabled() returns true.  But if is_dequeue_enabled() == false \n                  then dequeue functions are always disabled no matter the state of \n                  is_enabled())\n        !*/\n\n        void disable_dequeue (\n        );\n        /*!\n            ensures\n                - #is_dequeue_enabled() == false \n                - causes all current and future calls to dequeue() and\n                  dequeue_or_timeout() to not block but to return false \n                  immediately until enable_dequeue() is called.\n        !*/\n\n        void enable_dequeue (\n        );\n        /*!\n            ensures\n                - #is_dequeue_enabled() == true\n        !*/\n\n        size_t max_size (\n        ) const;\n        /*!\n            ensures\n                - returns the maximum number of objects of type T that this \n                  pipe can contain.\n        !*/\n\n        size_t size (\n        ) const;\n        /*!\n            ensures\n                - returns the number of objects of type T that this\n                  object currently contains.\n        !*/\n\n        bool enqueue (\n            T& item\n        );\n        /*!\n            ensures\n                - if (size() == max_size()) then\n                    - this call to enqueue() blocks until one of the following is the case:\n                        - there is room in the pipe for another item\n                        - max_size() == 0 and another thread is trying to dequeue from this \n                          pipe and we can pass our item object directly to that thread.\n                        - someone calls disable() \n                        - someone calls disable_enqueue()\n                - else\n                    - this call does not block.\n                - if (this call to enqueue() returns true) then\n                    - #is_enabled() == true \n                    - #is_enqueue_enabled() == true\n                    - if (max_size() == 0) then\n                        - using global swap, item was passed directly to a \n                          thread attempting to dequeue from this pipe\n                    - else\n                        - using global swap, item was added into this pipe.\n                    - #item is in an undefined but valid state for its type \n                - else\n                    - item was NOT added into the pipe\n                    - #item == item (i.e. the value of item is unchanged)\n        !*/\n\n        bool enqueue (T&& item) { return enqueue(item); }\n        /*!\n            enable enqueueing from rvalues \n        !*/\n\n        bool enqueue_or_timeout (\n            T& item,\n            unsigned long timeout\n        );\n        /*!\n            ensures\n                - if (size() == max_size() && timeout > 0) then\n                    - this call to enqueue_or_timeout() blocks until one of the following is the case:\n                        - there is room in the pipe to add another item\n                        - max_size() == 0 and another thread is trying to dequeue from this pipe \n                          and we can pass our item object directly to that thread.\n                        - someone calls disable() \n                        - someone calls disable_enqueue() \n                        - timeout milliseconds passes\n                - else\n                    - this call does not block. \n                - if (this call to enqueue() returns true) then\n                    - #is_enabled() == true \n                    - #is_enqueue_enabled() == true\n                    - if (max_size() == 0) then\n                        - using global swap, item was passed directly to a \n                          thread attempting to dequeue from this pipe\n                    - else\n                        - using global swap, item was added into this pipe.\n                    - #item is in an undefined but valid state for its type\n                - else\n                    - item was NOT added into the pipe\n                    - #item == item (i.e. the value of item is unchanged)\n        !*/\n\n        bool enqueue_or_timeout (T&& item, unsigned long timeout) { return enqueue_or_timeout(item,timeout); }\n        /*!\n            enable enqueueing from rvalues \n        !*/\n\n        bool dequeue (\n            T& item\n        );\n        /*!\n            ensures\n                - if (size() == 0) then\n                    - this call to dequeue() blocks until one of the following is the case:\n                        - there is something in the pipe we can dequeue\n                        - max_size() == 0 and another thread is trying to enqueue an item \n                          onto this pipe and we can receive our item directly from that thread.  \n                        - someone calls disable()\n                        - someone calls disable_dequeue()\n                - else\n                    - this call does not block.\n                - if (this call to dequeue() returns true) then\n                    - #is_enabled() == true \n                    - #is_dequeue_enabled() == true \n                    - the oldest item that was enqueued into this pipe has been\n                      swapped into #item.\n                - else\n                    - nothing was dequeued from this pipe.\n                    - #item == item (i.e. the value of item is unchanged)\n        !*/\n\n        bool dequeue_or_timeout (\n            T& item,\n            unsigned long timeout\n        );\n        /*!\n            ensures\n                - if (size() == 0 && timeout > 0) then\n                    - this call to dequeue_or_timeout() blocks until one of the following is the case:\n                        - there is something in the pipe we can dequeue \n                        - max_size() == 0 and another thread is trying to enqueue an item onto this \n                          pipe and we can receive our item directly from that thread.  \n                        - someone calls disable() \n                        - someone calls disable_dequeue()\n                        - timeout milliseconds passes\n                - else\n                    - this call does not block.\n                - if (this call to dequeue_or_timeout() returns true) then\n                    - #is_enabled() == true \n                    - #is_dequeue_enabled() == true \n                    - the oldest item that was enqueued into this pipe has been\n                      swapped into #item.\n                - else\n                    - nothing was dequeued from this pipe.\n                    - #item == item (i.e. the value of item is unchanged)\n        !*/\n\n    private:\n\n        // restricted functions\n        pipe(const pipe&);        // copy constructor\n        pipe& operator=(const pipe&);    // assignment operator\n\n    };    \n\n}\n\n#endif // DLIB_PIPE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/pipe.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PIPe_\n#define DLIB_PIPe_ \n\n#include \"pipe/pipe_kernel_1.h\"\n\n\n#endif // DLIB_PIPe_\n\n"
  },
  {
    "path": "dlib/pixel.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PIXEl_ \n#define DLIB_PIXEl_\n\n#include <iostream>\n#include \"serialize.h\"\n#include <cmath>\n#include \"algs.h\"\n#include \"uintn.h\"\n#include <limits>\n#include <complex>\n#include \"enable_if.h\"\n#include \"type_traits.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    /*!\n        This file contains definitions of pixel objects and related classes and\n        functionality.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct pixel_traits;\n    /*!\n        WHAT THIS OBJECT REPRESENTS\n            As the name implies, this is a traits class for pixel types.\n            It defines the properties of a pixel.\n\n        This traits class will define the following public static members:\n            - bool grayscale\n            - bool rgb\n            - bool rgb_alpha\n            - bool hsi\n            - bool lab\n\n            - bool has_alpha\n            - bool bgr_layout\n\n            - long num \n\n            - basic_pixel_type\n            - basic_pixel_type min()\n            - basic_pixel_type max()\n            - is_unsigned\n\n        The above public constants are subject to the following constraints:\n            - only one of grayscale, rgb, rgb_alpha, hsi or lab is true\n            - if (rgb == true) then\n                - The type T will be a struct with 3 public members of type \n                  unsigned char named \"red\" \"green\" and \"blue\".  \n                - This type of pixel represents the RGB color space.\n                - num == 3\n                - has_alpha == false\n                - bgr_layout == true if the channel order is BGR, and false if it's RGB\n                - basic_pixel_type == unsigned char\n                - min() == 0 \n                - max() == 255\n                - is_unsigned == true\n            - if (rgb_alpha == true) then\n                - The type T will be a struct with 4 public members of type \n                  unsigned char named \"red\" \"green\" \"blue\" and \"alpha\".  \n                - This type of pixel represents the RGB color space with\n                  an alpha channel where an alpha of 0 represents a pixel\n                  that is totally transparent and 255 represents a pixel \n                  with maximum opacity.\n                - num == 4\n                - has_alpha == true \n                - bgr_layout == true if the channel order is BGR, and false if it's RGB\n                - basic_pixel_type == unsigned char\n                - min() == 0 \n                - max() == 255\n                - is_unsigned == true\n            - else if (hsi == true) then\n                - The type T will be a struct with 3 public members of type\n                  unsigned char named \"h\" \"s\" and \"i\".  \n                - This type of pixel represents the HSI color space.\n                - num == 3\n                - has_alpha == false \n                - basic_pixel_type == unsigned char\n                - min() == 0 \n                - max() == 255\n                - is_unsigned == true\n            - else if (hsv == true) then\n                - The type T will be a struct with 3 public members of type\n                  unsigned char named \"h\" \"s\" and \"v\".\n                - This type of pixel represents the HSV color space.\n                - num == 3\n                - has_alpha == false\n                - basic_pixel_type == unsigned char\n                - min() == 0\n                - max() == 255\n                - is_unsigned == true\n             - else if (lab == true) then\n                - The type T will be a struct with 3 public members of type\n                  unsigned char named \"l\" \"a\" and \"b\".\n                - This type of pixel represents the Lab color space.\n                - num == 3\n                - has_alpha == false\n                - basic_pixel_type == unsigned char\n                - min() == 0\n                - max() == 255\n                - is_unsigned == true \n            - else\n                - grayscale == true\n                - This type of pixel represents a grayscale color space.  T \n                  will be some kind of basic scalar type such as unsigned int.\n                - num == 1\n                - has_alpha == false \n                - basic_pixel_type == T \n                - min() == the minimum obtainable value of objects of type T \n                - max() == the maximum obtainable value of objects of type T \n                - is_unsigned is true if min() == 0 and false otherwise\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A is_pixel_type\n\n       This type traits template tells you if Pixel is a pixel type.  I.e. if it has a pixel_traits<> specialization.\n       E.g. is_pixel_type<std::string>::value == false\n            is_pixel_type<rgb_pixel>::value == true\n    !*/\n    template <class Pixel>\n    using is_pixel_type = is_complete_type<pixel_traits<Pixel>>;\n\n    /*!A is_pixel_check\n\n        This is a SFINAE tool for restricting a template to only pixel types.\n    !*/\n    template<class Pixel>\n    using is_pixel_check = std::enable_if_t<is_pixel_type<Pixel>::value, bool>;\n\n// ----------------------------------------------------------------------------------------\n\n    struct rgb_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an RGB colored graphical pixel.\n        !*/\n\n        rgb_pixel (\n        ) {}\n\n        rgb_pixel (\n            unsigned char red_,\n            unsigned char green_,\n            unsigned char blue_\n        ) : red(red_), green(green_), blue(blue_) {}\n\n        unsigned char red;\n        unsigned char green;\n        unsigned char blue;\n\n        bool operator == (const rgb_pixel& that) const\n        {\n            return this->red   == that.red\n                && this->green == that.green\n                && this->blue  == that.blue;\n        }\n\n        bool operator != (const rgb_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };\n\n    static_assert(sizeof(rgb_pixel) == 3, \"sizeof(rgb_pixel) != 3. Type punning won't work on arrays of rgb_pixel's\");\n\n// ----------------------------------------------------------------------------------------\n\n    struct bgr_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an BGR colored graphical pixel.\n                (the reason it exists in addition to the rgb_pixel is so you can lay\n                it down on top of a memory region that organizes its color data in the\n                BGR format and still be able to read it)\n        !*/\n\n        bgr_pixel (\n        ) {}\n\n        bgr_pixel (\n            unsigned char blue_,\n            unsigned char green_,\n            unsigned char red_\n        ) : blue(blue_), green(green_), red(red_) {}\n\n        unsigned char blue;\n        unsigned char green;\n        unsigned char red;\n\n        bool operator == (const bgr_pixel& that) const\n        {\n            return this->blue  == that.blue\n                && this->green == that.green\n                && this->red   == that.red;\n        }\n\n        bool operator != (const bgr_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };\n\n    static_assert(sizeof(bgr_pixel) == 3, \"sizeof(bgr_pixel) != 3. Type punning won't work on arrays of bgr_pixel's\");\n\n// ----------------------------------------------------------------------------------------\n\n    struct rgb_alpha_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an RGB colored graphical pixel\n                with an alpha channel.\n        !*/\n\n        rgb_alpha_pixel (\n        ) {}\n\n        rgb_alpha_pixel (\n            unsigned char red_,\n            unsigned char green_,\n            unsigned char blue_,\n            unsigned char alpha_\n        ) : red(red_), green(green_), blue(blue_), alpha(alpha_) {}\n\n        unsigned char red;\n        unsigned char green;\n        unsigned char blue;\n        unsigned char alpha;\n\n        bool operator == (const rgb_alpha_pixel& that) const\n        {\n            return this->red   == that.red\n                && this->green == that.green\n                && this->blue  == that.blue\n                && this->alpha == that.alpha;\n        }\n\n        bool operator != (const rgb_alpha_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };\n\n    static_assert(sizeof(rgb_alpha_pixel) == 4, \"sizeof(rgb_alpha_pixel) != 4. Type punning won't work on arrays of rgb_alpha_pixel's\");\n\n// ----------------------------------------------------------------------------------------\n\n    struct bgr_alpha_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an BGR colored graphical pixel\n                with an alpha channel.\n        !*/\n\n        bgr_alpha_pixel (\n        ) {}\n\n        bgr_alpha_pixel (\n            unsigned char blue_,\n            unsigned char green_,\n            unsigned char red_,\n            unsigned char alpha_\n        ) : blue(blue_), green(green_), red(red_), alpha(alpha_) {}\n\n        unsigned char blue;\n        unsigned char green;\n        unsigned char red;\n        unsigned char alpha;\n\n        bool operator == (const bgr_alpha_pixel& that) const\n        {\n            return this->blue == that.blue\n                && this->green == that.green\n                && this->red == that.red\n                && this->alpha == that.alpha;\n        }\n\n        bool operator != (const bgr_alpha_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };\n\n    static_assert(sizeof(bgr_alpha_pixel) == 4, \"sizeof(bgr_alpha_pixel) != 4. Type punning won't work on arrays of bgr_alpha_pixel's\");\n\n// ----------------------------------------------------------------------------------------\n\n    struct hsi_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an HSI colored graphical pixel.\n        !*/\n\n        hsi_pixel (\n        ) {}\n\n        hsi_pixel (\n            unsigned char h_,\n            unsigned char s_,\n            unsigned char i_\n        ) : h(h_), s(s_), i(i_) {}\n\n        unsigned char h;\n        unsigned char s;\n        unsigned char i;\n\n        bool operator == (const hsi_pixel& that) const\n        {\n            return this->h == that.h\n                && this->s == that.s\n                && this->i == that.i;\n        }\n\n        bool operator != (const hsi_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    struct hsv_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an HSV colored graphical pixel.\n        !*/\n\n        hsv_pixel (\n        ) {}\n\n        hsv_pixel (\n            unsigned char h_,\n            unsigned char s_,\n            unsigned char v_\n        ) : h(h_), s(s_), v(v_) {}\n\n        unsigned char h;\n        unsigned char s;\n        unsigned char v;\n\n        bool operator == (const hsv_pixel& that) const\n        {\n            return this->h == that.h\n                && this->s == that.s\n                && this->v == that.v;\n        }\n\n        bool operator != (const hsv_pixel& that) const\n        {\n            return !(*this == that);\n        }\n    };\n\n    // ----------------------------------------------------------------------------------------\n\n    struct lab_pixel\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple struct that represents an Lab colored graphical pixel.\n        !*/\n\n        lab_pixel (\n        ) {}\n\n        lab_pixel (\n                unsigned char l_,\n                unsigned char a_,\n                unsigned char b_\n        ) : l(l_), a(a_), b(b_) {}\n\n        unsigned char l;\n        unsigned char a;\n        unsigned char b;\n\n        bool operator == (const lab_pixel& that) const\n        {\n            return this->l == that.l\n                && this->a == that.a\n                && this->b == that.b;\n        }\n\n        bool operator != (const lab_pixel& that) const\n        {\n            return !(*this == that);\n        }\n\n    };    \n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P1,\n        typename P2  \n        >\n    inline void assign_pixel (\n        P1& dest,\n        const P2& src\n    );\n    /*!\n        requires\n            - pixel_traits<P1> must be defined\n            - pixel_traits<P2> must be defined\n        ensures\n            - if (P1 and P2 are the same type of pixel) then\n                - simply copies the value of src into dest.  In other words,\n                  dest will be identical to src after this function returns.\n            - else if (P1 and P2 are not the same type of pixel) then\n                - assigns pixel src to pixel dest and does any necessary color space\n                  conversions.   \n                - When converting from a grayscale color space with more than 255 values the\n                  pixel intensity is saturated at pixel_traits<P1>::max() or pixel_traits<P1>::min()\n                  as appropriate.\n                - if (the dest pixel has an alpha channel and the src pixel doesn't) then\n                    - #dest.alpha == 255 \n                - else if (the src pixel has an alpha channel but the dest pixel doesn't) then\n                    - #dest == the original dest value blended with the src value according\n                      to the alpha channel in src.  \n                      (i.e.  #dest == src*(alpha/255) + dest*(1-alpha/255))\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P\n        >\n    inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (\n        const P& src\n    );\n    /*!\n        requires\n            - pixel_traits<P> must be defined\n        ensures\n            - if (pixel_traits<P>::grayscale == true) then\n                - returns src\n            - else\n                - converts src to grayscale and returns the resulting value.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P,\n        typename T\n        >\n    inline void assign_pixel_intensity (\n        P& dest,\n        const T& new_intensity\n    );\n    /*!\n        requires\n            - pixel_traits<P> must be defined\n            - pixel_traits<T> must be defined\n        ensures\n            - This function changes the intensity of the dest pixel. So if the pixel in \n              question is a grayscale pixel then it simply assigns that pixel with the \n              value of get_pixel_intensity(new_intensity).  However, if the pixel is not \n              a grayscale pixel then it converts the pixel to the HSI color space and sets \n              the I channel to the given intensity and then converts this HSI value back to \n              the original pixel's color space.\n            - Note that we don't necessarily have #get_pixel_intensity(dest) == get_pixel_intensity(new_intensity) \n              due to vagaries of how converting to and from HSI works out.\n            - if (the dest pixel has an alpha channel) then\n                - #dest.alpha == dest.alpha\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const rgb_pixel& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support for the rgb_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        rgb_pixel& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support for the rgb_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const bgr_pixel& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support for the bgr_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        bgr_pixel& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support for the bgr_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const rgb_alpha_pixel& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support for the rgb_alpha_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        rgb_alpha_pixel& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support for the rgb_alpha_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const hsi_pixel& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support for the hsi_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n            const lab_pixel& item,\n            std::ostream& out\n    );\n    /*!\n        provides serialization support for the lab_pixel struct\n    !*/\n\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        hsi_pixel& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support for the hsi_pixel struct\n    !*/\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n            lab_pixel& item,\n            std::istream& in\n    );\n    /*!\n        provides deserialization support for the lab_pixel struct\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    struct pixel_traits<rgb_pixel>\n    {\n        constexpr static bool rgb  = true;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        enum { num = 3};\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    struct pixel_traits<bgr_pixel>\n    {\n        constexpr static bool rgb  = true;\n        constexpr static bool bgr_layout  = true;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    struct pixel_traits<rgb_alpha_pixel>\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = true;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 4;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = true;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <>\n    struct pixel_traits<bgr_alpha_pixel>\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout = true;\n        constexpr static bool rgb_alpha  = true;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 4;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = true;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <>\n    struct pixel_traits<hsi_pixel>\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = true;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <>\n    struct pixel_traits<hsv_pixel>\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = true;\n        constexpr static bool lab = false;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <>\n    struct pixel_traits<lab_pixel>\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = false;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = true;\n        constexpr static long num = 3;\n        typedef unsigned char basic_pixel_type;\n        static basic_pixel_type min() { return 0;}\n        static basic_pixel_type max() { return 255;}\n        constexpr static bool is_unsigned = true;\n        constexpr static bool has_alpha = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct grayscale_pixel_traits\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = true;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 1;\n        constexpr static bool has_alpha = false;\n        typedef T basic_pixel_type;\n        static basic_pixel_type min() { return std::numeric_limits<T>::min();}\n        static basic_pixel_type max() { return std::numeric_limits<T>::max();}\n        constexpr static bool is_unsigned = is_unsigned_type<T>::value;\n    };\n\n    template <> struct pixel_traits<unsigned char>  : public grayscale_pixel_traits<unsigned char> {};\n    template <> struct pixel_traits<unsigned short> : public grayscale_pixel_traits<unsigned short> {};\n    template <> struct pixel_traits<unsigned int>   : public grayscale_pixel_traits<unsigned int> {};\n    template <> struct pixel_traits<unsigned long>  : public grayscale_pixel_traits<unsigned long> {};\n\n    template <> struct pixel_traits<char>           : public grayscale_pixel_traits<char> {};\n    template <> struct pixel_traits<signed char>    : public grayscale_pixel_traits<signed char> {};\n    template <> struct pixel_traits<short>          : public grayscale_pixel_traits<short> {};\n    template <> struct pixel_traits<int>            : public grayscale_pixel_traits<int> {};\n    template <> struct pixel_traits<long>           : public grayscale_pixel_traits<long> {};\n\n    template <> struct pixel_traits<int64>          : public grayscale_pixel_traits<int64> {};\n    template <> struct pixel_traits<uint64>         : public grayscale_pixel_traits<uint64> {};\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    struct float_grayscale_pixel_traits\n    {\n        constexpr static bool rgb  = false;\n        constexpr static bool bgr_layout  = false;\n        constexpr static bool rgb_alpha  = false;\n        constexpr static bool grayscale = true;\n        constexpr static bool hsi = false;\n        constexpr static bool hsv = false;\n        constexpr static bool lab = false;\n        constexpr static long num = 1;\n        constexpr static bool has_alpha = false;\n        typedef T basic_pixel_type;\n        static basic_pixel_type min() { return -std::numeric_limits<T>::max();}\n        static basic_pixel_type max() { return std::numeric_limits<T>::max();}\n        constexpr static bool is_unsigned = false;\n    };\n\n    template <> struct pixel_traits<float>          : public float_grayscale_pixel_traits<float> {};\n    template <> struct pixel_traits<double>         : public float_grayscale_pixel_traits<double> {};\n    template <> struct pixel_traits<long double>    : public float_grayscale_pixel_traits<long double> {};\n\n    // These are here mainly so you can easily copy images into complex arrays.  This is\n    // useful when you want to do a FFT on an image or some similar operation.\n    template <> struct pixel_traits<std::complex<float> > :       public float_grayscale_pixel_traits<float> {};\n    template <> struct pixel_traits<std::complex<double> > :      public float_grayscale_pixel_traits<double> {};\n    template <> struct pixel_traits<std::complex<long double> > : public float_grayscale_pixel_traits<long double> {};\n\n// ----------------------------------------------------------------------------------------\n\n    // The following is a bunch of conversion stuff for the assign_pixel function.\n\n    namespace assign_pixel_helpers\n    {\n\n    // -----------------------------\n        // all the same kind \n\n        template < typename P >\n        typename enable_if_c<pixel_traits<P>::grayscale>::type\n        assign(P& dest, const P& src) \n        { \n            dest = src;\n        }\n\n    // -----------------------------\n\n        template <typename T>\n        typename unsigned_type<T>::type make_unsigned (\n            const T& val\n        ) { return static_cast<typename unsigned_type<T>::type>(val); }\n\n        inline float make_unsigned(const float& val) { return val; }\n        inline double make_unsigned(const double& val) { return val; }\n        inline long double make_unsigned(const long double& val) { return val; }\n\n\n        template <typename T, typename P>\n        typename enable_if_c<pixel_traits<T>::is_unsigned == pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (\n            const P& p\n        ) \n        /*!\n            ensures\n                - returns true if p is <= max value of T\n        !*/\n        { \n            return p <= pixel_traits<T>::max();         \n        }\n\n        template <typename T, typename P>\n        typename enable_if_c<pixel_traits<T>::is_unsigned && !pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (\n            const P& p\n        ) \n        { \n            if (p <= 0)\n                return true;\n            else if (make_unsigned(p) <= pixel_traits<T>::max())\n                return true;\n            else\n                return false;\n        }\n\n        template <typename T, typename P>\n        typename enable_if_c<!pixel_traits<T>::is_unsigned && pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (\n            const P& p\n        ) \n        { \n            return p <= make_unsigned(pixel_traits<T>::max());\n        }\n\n    // -----------------------------\n\n        template <typename T, typename P>\n        typename enable_if_c<pixel_traits<P>::is_unsigned, bool >::type greater_or_equal_to_min (\n            const P& \n        ) { return true; }\n        /*!\n            ensures\n                - returns true if p is >= min value of T\n        !*/\n\n        template <typename T, typename P>\n        typename enable_if_c<!pixel_traits<P>::is_unsigned && pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (\n            const P& p\n        ) \n        { \n            return p >= 0;\n        }\n\n        template <typename T, typename P>\n        typename enable_if_c<!pixel_traits<P>::is_unsigned && !pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (\n            const P& p\n        ) \n        { \n            return p >= pixel_traits<T>::min();\n        }\n    // -----------------------------\n\n        // Apparently Visual Studio's optimizer complains about branches that would not be taken anyway.\n#if defined (_MSC_VER)\n#pragma warning ( push )\n#pragma warning ( disable: 4756 )\n#endif\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src) \n        { \n            /*\n                The reason for these weird comparison functions is to avoid getting compiler\n                warnings about comparing signed types to unsigned and stuff like that.  \n            */\n\n            if (less_or_equal_to_max<P1>(src))\n                if (greater_or_equal_to_min<P1>(src))\n                    dest = static_cast<P1>(src);\n                else\n                    dest = pixel_traits<P1>::min();\n            else\n                dest = pixel_traits<P1>::max();\n        }\n\n#if defined (_MSC_VER)\n#pragma warning ( pop )\n#endif\n\n    // -----------------------------\n    // -----------------------------\n    // -----------------------------\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.red = src.red; \n            dest.green = src.green; \n            dest.blue = src.blue; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.red = src.red; \n            dest.green = src.green; \n            dest.blue = src.blue; \n            dest.alpha = src.alpha; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.h = src.h; \n            dest.s = src.s; \n            dest.i = src.i; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.h = src.h; \n            dest.s = src.s; \n            dest.v = src.v; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            dest.l = src.l;\n            dest.a = src.a;\n            dest.b = src.b;\n        }\n\n    // -----------------------------\n        // dest is a grayscale\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src) \n        { \n            const unsigned int temp = ((static_cast<unsigned int>(src.red) +\n                                        static_cast<unsigned int>(src.green) +  \n                                        static_cast<unsigned int>(src.blue))/3);\n            assign_pixel(dest, temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src) \n        { \n\n            const unsigned char avg = static_cast<unsigned char>((static_cast<unsigned int>(src.red) +\n                                                                  static_cast<unsigned int>(src.green) +  \n                                                                  static_cast<unsigned int>(src.blue))/3); \n\n            if (src.alpha == 255)\n            {\n                assign_pixel(dest, avg);\n            }\n            else\n            {\n                // perform this assignment using fixed point arithmetic: \n                // dest = src*(alpha/255) + dest*(1 - alpha/255);\n                // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);\n                // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);\n                // dest = dest*1 + (src - dest)*(alpha/255);\n                // dest += (src - dest)*(alpha/255);\n\n                int temp = avg;\n                // copy dest into dest_copy using assign_pixel to avoid potential\n                // warnings about implicit float to int warnings.\n                int dest_copy;\n                assign_pixel(dest_copy, dest);\n\n                temp -= dest_copy;\n\n                temp *= src.alpha;\n\n                temp /= 255;\n\n                assign_pixel(dest, temp+dest_copy);\n            }\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src) \n        { \n            assign_pixel(dest, src.i);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src) \n        { \n            assign_pixel(dest, src.v);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            assign_pixel(dest, src.l);\n        }\n\n\n    // -----------------------------\n\n        struct HSL\n        {\n            double h;\n            double s;\n            double l;\n        };\n\n        struct HSV\n        {\n            double h;\n            double s;\n            double v;\n        };\n\n        struct COLOUR\n        {\n            double r;\n            double g;\n            double b;\n        };\n\n        /*\n            I found this excellent bit of code for dealing with HSL spaces at \n            http://local.wasp.uwa.edu.au/~pbourke/colour/hsl/\n        */\n        /*\n            Calculate HSL from RGB\n            Hue is in degrees\n            Lightness is between 0 and 1\n            Saturation is between 0 and 1\n        */\n        inline HSL RGB2HSL(COLOUR c1)\n        {\n            double themin,themax,delta;\n            HSL c2;\n\n            themin = std::min(c1.r,std::min(c1.g,c1.b));\n            themax = std::max(c1.r,std::max(c1.g,c1.b));\n            delta = themax - themin;\n            c2.l = (themin + themax) / 2;\n            c2.s = 0;\n            if (c2.l > 0 && c2.l < 1)\n                c2.s = delta / (c2.l < 0.5 ? (2*c2.l) : (2-2*c2.l));\n            c2.h = 0;\n            if (delta > 0) {\n                if (themax == c1.r && themax != c1.g)\n                    c2.h += (c1.g - c1.b) / delta;\n                if (themax == c1.g && themax != c1.b)\n                    c2.h += (2 + (c1.b - c1.r) / delta);\n                if (themax == c1.b && themax != c1.r)\n                    c2.h += (4 + (c1.r - c1.g) / delta);\n                c2.h *= 60;\n            }\n            return(c2);\n        }\n\n        /*\n            Calculate RGB from HSL, reverse of RGB2HSL()\n            Hue is in degrees\n            Lightness is between 0 and 1\n            Saturation is between 0 and 1\n        */\n        inline COLOUR HSL2RGB(HSL c1)\n        {\n            COLOUR c2,sat,ctmp;\n\n            if (c1.h < 120) {\n                sat.r = (120 - c1.h) / 60.0;\n                sat.g = c1.h / 60.0;\n                sat.b = 0;\n            } else if (c1.h < 240) {\n                sat.r = 0;\n                sat.g = (240 - c1.h) / 60.0;\n                sat.b = (c1.h - 120) / 60.0;\n            } else {\n                sat.r = (c1.h - 240) / 60.0;\n                sat.g = 0;\n                sat.b = (360 - c1.h) / 60.0;\n            }\n            sat.r = std::min(sat.r,1.0);\n            sat.g = std::min(sat.g,1.0);\n            sat.b = std::min(sat.b,1.0);\n\n            ctmp.r = 2 * c1.s * sat.r + (1 - c1.s);\n            ctmp.g = 2 * c1.s * sat.g + (1 - c1.s);\n            ctmp.b = 2 * c1.s * sat.b + (1 - c1.s);\n\n            if (c1.l < 0.5) {\n                c2.r = c1.l * ctmp.r;\n                c2.g = c1.l * ctmp.g;\n                c2.b = c1.l * ctmp.b;\n            } else {\n                c2.r = (1 - c1.l) * ctmp.r + 2 * c1.l - 1;\n                c2.g = (1 - c1.l) * ctmp.g + 2 * c1.l - 1;\n                c2.b = (1 - c1.l) * ctmp.b + 2 * c1.l - 1;\n            }\n\n            return(c2);\n        }\n\n        /*\n            Calculate HSV from RGB\n            Hue is in degrees\n            Saturation is between 0 and 1\n            Value is between 0 and 1\n        */\n        inline HSV RGB2HSV(COLOUR in)\n        {\n            HSV out;\n\n            const double themin = std::min({in.r, in.g, in.b});\n            const double max = std::max({in.r, in.g, in.b});\n            const double delta = max - themin;\n\n            out.v = max;\n            if (delta < 0.00001)\n            {\n                out.s = 0;\n                out.h = 0;\n                return out;\n            }\n            if (max > 0.0)\n            {\n                out.s = (delta / max);\n            }\n            else\n            {\n                out.s = 0.0;\n                out.h = NAN;\n                return out;\n            }\n            if (in.r >= max)\n            {\n                out.h = (in.g - in.b) / delta;\n            }\n            else\n            {\n                if (in.g >= max)\n                    out.h = 2.0 + (in.b - in.r) / delta;\n                else\n                    out.h = 4.0 + (in.r - in.g) / delta;\n            }\n\n            out.h *= 60.0;\n\n            if (out.h < 0.0)\n                out.h += 360.0;\n\n            return out;\n        }\n\n        // -----------------------------\n\n        /*\n            Calculate RGB from HSV, reverse of RGB2HSV()\n            Hue is in degrees\n            Saturation is between 0 and 1\n            Value is between 0 and 1\n        */\n        inline COLOUR HSV2RGB(HSV in)\n        {\n            COLOUR out;\n\n            if (in.s <= 0.0)\n            {\n                out.r = in.v;\n                out.g = in.v;\n                out.b = in.v;\n                return out;\n            }\n\n            const double hh = (in.h >= 360 ? 0.0 : in.h) / 60.0;\n            const long i = static_cast<long>(hh);\n            const double ff = hh - i;\n            const double p = in.v * (1.0 - in.s);\n            const double q = in.v * (1.0 - (in.s * ff));\n            const double t = in.v * (1.0 - (in.s * (1.0 - ff)));\n\n            switch (i)\n            {\n            case 0:\n                out.r = in.v;\n                out.g = t;\n                out.b = p;\n                break;\n            case 1:\n                out.r = q;\n                out.g = in.v;\n                out.b = p;\n                break;\n            case 2:\n                out.r = p;\n                out.g = in.v;\n                out.b = t;\n                break;\n            case 3:\n                out.r = p;\n                out.g = q;\n                out.b = in.v;\n                break;\n            case 4:\n                out.r = t;\n                out.g = p;\n                out.b = in.v;\n                break;\n            default:\n                out.r = in.v;\n                out.g = p;\n                out.b = q;\n                break;\n            }\n            return out;\n        }\n\n        // -----------------------------\n\n        struct Lab\n        {\n            double l;\n            double a;\n            double b;\n        };\n        /*\n            Calculate Lab from RGB\n            L is between 0 and 100\n            a is between -128 and 127\n            b is between -128 and 127\n            RGB is between 0.0 and 1.0\n        */\n        inline Lab RGB2Lab(COLOUR c1)\n        {\n            Lab c2;\n\n            double var_R = c1.r;\n            double var_G = c1.g;\n            double var_B = c1.b;\n\n            if (var_R > 0.04045) {\n                var_R = std::pow(((var_R + 0.055) / 1.055), 2.4);\n            } else {\n                var_R = var_R / 12.92;\n            }\n\n            if (var_G > 0.04045) {\n                var_G = std::pow(((var_G + 0.055) / 1.055), 2.4);\n            } else {\n                var_G = var_G / 12.92;\n            }\n\n            if (var_B > 0.04045) {\n                var_B = std::pow(((var_B + 0.055) / 1.055), 2.4);\n            } else {\n                var_B = var_B / 12.92;\n            }\n\n            var_R = var_R * 100;\n            var_G = var_G * 100;\n            var_B = var_B * 100;\n\n//Observer. = 2°, Illuminant = D65\n            double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;\n            double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;\n            double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;\n\n            double var_X = X / 95.047;\n            double var_Y = Y / 100.000;\n            double var_Z = Z / 108.883;\n\n            if (var_X > 0.008856) {\n                var_X = std::pow(var_X, (1.0 / 3));\n            }\n            else {\n                var_X = (7.787 * var_X) + (16.0 / 116);\n            }\n\n            if (var_Y > 0.008856) {\n                var_Y = std::pow(var_Y, (1.0 / 3));\n            }\n            else {\n                var_Y = (7.787 * var_Y) + (16.0 / 116);\n            }\n\n            if (var_Z > 0.008856) {\n                var_Z = std::pow(var_Z, (1.0 / 3));\n            }\n            else {\n                var_Z = (7.787 * var_Z) + (16.0 / 116);\n            }\n\n            //clamping\n            c2.l = std::max(0.0, (116.0 * var_Y) - 16);\n            c2.a = std::max(-128.0, std::min(127.0, 500.0 * (var_X - var_Y)));\n            c2.b = std::max(-128.0, std::min(127.0, 200.0 * (var_Y - var_Z)));\n\n            return c2;\n        }\n\n        /*\n            Calculate RGB from Lab, reverse of RGB2LAb()\n            L is between 0 and 100\n            a is between -128 and 127\n            b is between -128 and 127\n            RGB is between 0.0 and 1.0\n        */\n        inline COLOUR Lab2RGB(Lab c1) {\n            COLOUR c2;\n\n            double var_Y = (c1.l + 16) / 116.0;\n            double var_X = (c1.a / 500.0) + var_Y;\n            double var_Z = var_Y - (c1.b / 200);\n\n            if (std::pow(var_Y, 3) > 0.008856) {\n                var_Y = std::pow(var_Y, 3);\n            } else {\n                var_Y = (var_Y - 16.0 / 116) / 7.787;\n            }\n\n            if (std::pow(var_X, 3) > 0.008856) {\n                var_X = std::pow(var_X, 3);\n            } else {\n                var_X = (var_X - 16.0 / 116) / 7.787;\n            }\n\n            if (std::pow(var_Z, 3) > 0.008856) {\n                var_Z = std::pow(var_Z, 3);\n            } else {\n                var_Z = (var_Z - 16.0 / 116) / 7.787;\n            }\n\n            double X = var_X * 95.047;\n            double Y = var_Y * 100.000;\n            double Z = var_Z * 108.883;\n\n            var_X = X / 100.0;\n            var_Y = Y / 100.0;\n            var_Z = Z / 100.0;\n\n            double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;\n            double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;\n            double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;\n\n            if (var_R > 0.0031308) {\n                var_R = 1.055 * std::pow(var_R, (1 / 2.4)) - 0.055;\n            } else {\n                var_R = 12.92 * var_R;\n            }\n\n            if (var_G > 0.0031308) {\n                var_G = 1.055 * std::pow(var_G, (1 / 2.4)) - 0.055;\n            } else {\n                var_G = 12.92 * var_G;\n            }\n\n            if (var_B > 0.0031308) {\n                var_B = 1.055 * std::pow(var_B, (1 / 2.4)) - 0.055;\n            } else {\n                var_B = 12.92 * var_B;\n            }\n\n            // clamping\n            c2.r = std::max(0.0, std::min(1.0, var_R));\n            c2.g = std::max(0.0, std::min(1.0, var_G));\n            c2.b = std::max(0.0, std::min(1.0, var_B));\n\n            return (c2);\n        }\n\n\n    // -----------------------------\n        // dest is a color rgb_pixel\n\n        template < typename P1 >\n        typename enable_if_c<pixel_traits<P1>::rgb>::type\n        assign(P1& dest, const unsigned char& src) \n        { \n            dest.red = src; \n            dest.green = src; \n            dest.blue = src; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src) \n        { \n            unsigned char p;\n            assign_pixel(p, src);\n            dest.red = p; \n            dest.green = p; \n            dest.blue = p; \n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src) \n        { \n            if (src.alpha == 255)\n            {\n                dest.red = src.red;\n                dest.green = src.green;\n                dest.blue = src.blue;\n            }\n            else\n            {\n                // perform this assignment using fixed point arithmetic: \n                // dest = src*(alpha/255) + dest*(1 - alpha/255);\n                // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);\n                // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);\n                // dest = dest*1 + (src - dest)*(alpha/255);\n                // dest += (src - dest)*(alpha/255);\n\n                unsigned int temp_r = src.red;\n                unsigned int temp_g = src.green;\n                unsigned int temp_b = src.blue;\n\n                temp_r -= dest.red;\n                temp_g -= dest.green;\n                temp_b -= dest.blue;\n\n                temp_r *= src.alpha;\n                temp_g *= src.alpha;\n                temp_b *= src.alpha;\n\n                temp_r >>= 8;\n                temp_g >>= 8;\n                temp_b >>= 8;\n\n                dest.red += static_cast<unsigned char>(temp_r&0xFF);\n                dest.green += static_cast<unsigned char>(temp_g&0xFF);\n                dest.blue += static_cast<unsigned char>(temp_b&0xFF);\n            }\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c;\n            HSL h;\n            h.h = src.h;\n            h.h = h.h/255.0*360;\n            h.s = src.s/255.0;\n            h.l = src.i/255.0;\n            c = HSL2RGB(h);\n\n            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c;\n            HSV h;\n            h.h = src.h;\n            h.h = h.h/255.0*360;\n            h.s = src.s/255.0;\n            h.v = src.v/255.0;\n            c = HSV2RGB(h);\n\n            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            COLOUR c;\n            Lab l;\n            l.l = (src.l/255.0)*100;\n            l.a = (src.a-128.0);\n            l.b = (src.b-128.0);\n            c = Lab2RGB(l);\n\n            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);\n        }\n\n\n    // -----------------------------\n    // dest is a color rgb_alpha_pixel\n\n        template < typename P1 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha>::type\n        assign(P1& dest, const unsigned char& src) \n        { \n            dest.red = src; \n            dest.green = src; \n            dest.blue = src; \n            dest.alpha = 255;\n        }\n\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src) \n        { \n            unsigned char p;\n            assign_pixel(p, src);\n\n            dest.red = p; \n            dest.green = p; \n            dest.blue = p; \n            dest.alpha = 255;\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.red = src.red;\n            dest.green = src.green;\n            dest.blue = src.blue;\n            dest.alpha = 255;\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c;\n            HSL h;\n            h.h = src.h;\n            h.h = h.h/255.0*360;\n            h.s = src.s/255.0;\n            h.l = src.i/255.0;\n            c = HSL2RGB(h);\n\n            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);\n            dest.alpha = 255;\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c;\n            HSV h;\n            h.h = src.h;\n            h.h = h.h/255.0*360;\n            h.s = src.s/255.0;\n            h.v = src.v/255.0;\n            c = HSV2RGB(h);\n\n            dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);\n            dest.alpha = 255;\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            COLOUR c;\n            Lab l;\n            l.l = (src.l/255.0)*100;\n            l.a = (src.a-128.0);\n            l.b = (src.b-128.0);\n            c = Lab2RGB(l);\n\n            dest.red = static_cast<unsigned char>(c.r * 255 + 0.5);\n            dest.green = static_cast<unsigned char>(c.g * 255 + 0.5);\n            dest.blue = static_cast<unsigned char>(c.b * 255 + 0.5);\n            dest.alpha = 255;\n        }\n    // -----------------------------\n        // dest is an hsi pixel\n\n        template < typename P1>\n        typename enable_if_c<pixel_traits<P1>::hsi>::type\n        assign(P1& dest, const unsigned char& src) \n        { \n            dest.h = 0;\n            dest.s = 0;\n            dest.i = src;\n        }\n\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.h = 0;\n            dest.s = 0;\n            assign_pixel(dest.i, src);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c1;\n            HSL c2;\n            c1.r = src.red/255.0;\n            c1.g = src.green/255.0;\n            c1.b = src.blue/255.0;\n            c2 = RGB2HSL(c1);\n\n            dest.h = static_cast<unsigned char>(c2.h/360.0*255.0 + 0.5);\n            dest.s = static_cast<unsigned char>(c2.s*255.0 + 0.5);\n            dest.i = static_cast<unsigned char>(c2.l*255.0 + 0.5);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src) \n        { \n            rgb_pixel temp;\n            // convert target hsi pixel to rgb\n            assign_pixel_helpers::assign(temp,dest);\n\n            // now assign the rgb_alpha value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n\n            // now we can just go assign the new rgb value to the\n            // hsi pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n            // convert hsv value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n            // now we can just go assign the new rgb value to the\n            // hsi pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n            // convert lab value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n            // now we can just go assign the new rgb value to the\n            // hsi pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n    // -----------------------------\n        // dest is an hsv pixel\n\n        template < typename P1>\n        typename enable_if_c<pixel_traits<P1>::hsv>::type\n        assign(P1& dest, const unsigned char& src) \n        { \n            dest.h = 0;\n            dest.s = 0;\n            dest.v = src;\n        }\n\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src) \n        { \n            dest.h = 0;\n            dest.s = 0;\n            assign_pixel(dest.v, src);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src) \n        { \n            COLOUR c1;\n            HSV c2;\n            c1.r = src.red/255.0;\n            c1.g = src.green/255.0;\n            c1.b = src.blue/255.0;\n            c2 = RGB2HSV(c1);\n\n            dest.h = static_cast<unsigned char>(c2.h/360.0*255.0 + 0.5);\n            dest.s = static_cast<unsigned char>(c2.s*255.0 + 0.5);\n            dest.v = static_cast<unsigned char>(c2.v*255.0 + 0.5);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src) \n        { \n            rgb_pixel temp;\n            // convert target hsv pixel to rgb\n            assign_pixel_helpers::assign(temp,dest);\n\n            // now assign the rgb_alpha value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n\n            // now we can just go assign the new rgb value to the\n            // hsv pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n            // convert hsi value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n            // now we can just go assign the new rgb value to the\n            // hsv pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::hsv && pixel_traits<P2>::lab>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n            // convert lab value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n            // now we can just go assign the new rgb value to the\n            // hsv pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n    // -----------------------------\n        // dest is an lab pixel\n        template < typename P1>\n        typename enable_if_c<pixel_traits<P1>::lab>::type\n        assign(P1& dest, const unsigned char& src)\n        {\n            dest.a = 128;\n            dest.b = 128;\n            dest.l = src;\n        }\n\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::grayscale>::type\n        assign(P1& dest, const P2& src)\n        {\n            dest.a = 128;\n            dest.b = 128;\n            assign_pixel(dest.l, src);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb>::type\n        assign(P1& dest, const P2& src)\n        {\n            COLOUR c1;\n            Lab c2;\n            c1.r = src.red / 255.0;\n            c1.g = src.green / 255.0;\n            c1.b = src.blue / 255.0;\n            c2 = RGB2Lab(c1);\n\n            dest.l = static_cast<unsigned char>((c2.l / 100) * 255 + 0.5);\n            dest.a = static_cast<unsigned char>(c2.a + 128 + 0.5);\n            dest.b = static_cast<unsigned char>(c2.b + 128 + 0.5);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb_alpha>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n            // convert target lab pixel to rgb\n            assign_pixel_helpers::assign(temp,dest);\n\n            // now assign the rgb_alpha value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n\n            // now we can just go assign the new rgb value to the\n            // lab pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::hsi>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n\n            // convert hsi value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n\n            // now we can just go assign the new rgb value to the\n            // lab pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n\n        template < typename P1, typename P2 >\n        typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::hsv>::type\n        assign(P1& dest, const P2& src)\n        {\n            rgb_pixel temp;\n\n            // convert hsv value to our temp rgb pixel\n            assign_pixel_helpers::assign(temp,src);\n\n            // now we can just go assign the new rgb value to the\n            // lab pixel\n            assign_pixel_helpers::assign(dest,temp);\n        }\n    }\n\n    // -----------------------------\n\n    template < typename P1, typename P2 >\n    inline void assign_pixel (\n        P1& dest,\n        const P2& src\n    ) { assign_pixel_helpers::assign(dest,src); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P,\n        typename T\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale>::type assign_pixel_intensity_helper (\n        P& dest,\n        const T& new_intensity\n    )\n    {\n        assign_pixel(dest, new_intensity);\n    }\n\n    template <\n        typename P,\n        typename T\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale == false &&\n                                pixel_traits<P>::has_alpha>::type assign_pixel_intensity_helper (\n        P& dest,\n        const T& new_intensity\n    )\n    {\n        hsi_pixel p;\n        const unsigned long old_alpha = dest.alpha;\n        dest.alpha = 255;\n        rgb_pixel temp;\n        assign_pixel(temp, dest); // put dest into an rgb_pixel to avoid the somewhat complicated assign_pixel(hsi,rgb_alpha).\n        assign_pixel(p,temp);\n        assign_pixel(p.i, new_intensity);\n        assign_pixel(dest,p);\n        dest.alpha = old_alpha;\n    }\n\n    template <\n        typename P,\n        typename T\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale == false &&\n                                pixel_traits<P>::has_alpha == false>::type assign_pixel_intensity_helper (\n        P& dest,\n        const T& new_intensity\n    )\n    {\n        hsi_pixel p;\n        assign_pixel(p,dest);\n        assign_pixel(p.i, new_intensity);\n        assign_pixel(dest,p);\n    }\n\n    template <\n        typename P,\n        typename T\n        >\n    inline void assign_pixel_intensity (\n        P& dest,\n        const T& new_intensity\n    )\n    {\n        assign_pixel_intensity_helper(dest, new_intensity);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename P\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale, P>::type get_pixel_intensity_helper (\n        const P& src \n    )\n    {\n        return src;\n    }\n\n    template <\n        typename P\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&\n                                pixel_traits<P>::has_alpha, \n                                typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (\n        const P& src\n    )\n    {\n        P temp = src;\n        temp.alpha = 255;\n        typename pixel_traits<P>::basic_pixel_type p;\n        assign_pixel(p,temp);\n        return p;\n    }\n\n    template <\n        typename P\n        >\n    inline typename enable_if_c<pixel_traits<P>::grayscale == false&&\n                                pixel_traits<P>::has_alpha == false, \n                                typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (\n        const P& src\n    )\n    {\n        typename pixel_traits<P>::basic_pixel_type p;\n        assign_pixel(p,src);\n        return p;\n    }\n\n    template <\n        typename P\n        >\n    inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (\n        const P& src\n    )\n    {\n        return get_pixel_intensity_helper(src);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const rgb_alpha_pixel& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.red,out);\n            serialize(item.green,out);\n            serialize(item.blue,out);\n            serialize(item.alpha,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type rgb_alpha_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        rgb_alpha_pixel& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.red,in);\n            deserialize(item.green,in);\n            deserialize(item.blue,in);\n            deserialize(item.alpha,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type rgb_alpha_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const rgb_pixel& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.red,out);\n            serialize(item.green,out);\n            serialize(item.blue,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type rgb_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        rgb_pixel& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.red,in);\n            deserialize(item.green,in);\n            deserialize(item.blue,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type rgb_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const bgr_pixel& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.blue,out);\n            serialize(item.green,out);\n            serialize(item.red,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type bgr_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        bgr_pixel& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.blue,in);\n            deserialize(item.green,in);\n            deserialize(item.red,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type bgr_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const hsi_pixel& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.h,out);\n            serialize(item.s,out);\n            serialize(item.i,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type hsi_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        hsi_pixel& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.h,in);\n            deserialize(item.s,in);\n            deserialize(item.i,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hsi_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const hsv_pixel& item, \n        std::ostream& out \n    )   \n    {\n        try\n        {\n            serialize(item.h,out);\n            serialize(item.s,out);\n            serialize(item.v,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type hsv_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n        hsv_pixel& item, \n        std::istream& in\n    )   \n    {\n        try\n        {\n            deserialize(item.h,in);\n            deserialize(item.s,in);\n            deserialize(item.v,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type hsv_pixel\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n            const lab_pixel& item,\n            std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.l,out);\n            serialize(item.a,out);\n            serialize(item.b,out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type lab_pixel\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void deserialize (\n            lab_pixel& item,\n            std::istream& in\n    )\n    {\n        try\n        {\n            deserialize(item.l,in);\n            deserialize(item.a,in);\n            deserialize(item.b,in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing object of type lab_pixel\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_PIXEl_ \n\n"
  },
  {
    "path": "dlib/platform.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n\n#ifdef DLIB_ALL_SOURCE_END\n#include \"dlib_basic_cpp_build_tutorial.txt\"\n#endif\n\n#ifndef DLIB_PLATFORm_\n#define DLIB_PLATFORm_\n\n\n/*!\n    This file ensures that:\n        - if (we are compiling under a posix platform) then\n            - DLIB_POSIX will be defined\n            - if (this is also Mac OS X) then\n                - MACOSX will be defined\n            - if (this is also HP-UX) then\n                - HPUX will be defined\n        - if (we are compiling under an MS Windows platform) then\n            - WIN32 will be defined\n!*/\n\n\n/*\n    A good reference for this sort of information is\n    http://predef.sourceforge.net/\n*/\n\n// Define WIN32 if this is MS Windows\n#ifndef WIN32\n    #if defined( _MSC_VER) || defined(__BORLANDC__) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__)\n    #define WIN32 \n    #endif \n#endif\n\n#ifndef WIN32\n    // since this is the only other platform the library currently supports\n    // just assume it is DLIB_POSIX if it isn't WIN32\n    #ifndef DLIB_POSIX\n        #define DLIB_POSIX\n    #endif\n \n    #ifndef HPUX\n       #if defined(__hpux ) || defined(hpux) || defined (_hpux)\n       #define HPUX\n       #endif\t\n    #endif\n\n    #ifndef MACOSX\n        #ifdef __MACOSX__\n        #define MACOSX\n        #endif \n        #ifdef __APPLE__\n        #define MACOSX\n        #endif\n    #endif\n\n#endif\n\n\n\n\n#endif // DLIB_PLATFORm_\n\n"
  },
  {
    "path": "dlib/python/numpy_image.h",
    "content": "// Copyright (C) 2014  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PYTHON_NuMPY_IMAGE_Hh_\n#define DLIB_PYTHON_NuMPY_IMAGE_Hh_\n\n#include <dlib/algs.h>\n#include <dlib/error.h>\n#include <dlib/matrix.h>\n#include <dlib/pixel.h>\n#include <string>\n#include <memory>\n#include <pybind11/numpy.h>\n#include <pybind11/pybind11.h>\n#include <dlib/image_transforms/assign_image.h>\n#include <stdint.h>\n#include <type_traits>\n\nnamespace py = pybind11;\n\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    bool is_image (\n        const py::array& img \n    )\n    /*!\n        ensures\n            - returns true if and only if the given python numpy array can reasonably be\n              interpreted as an image containing pixel_type pixels.\n    !*/\n    {\n        using basic_pixel_type = typename pixel_traits<pixel_type>::basic_pixel_type;\n        const size_t expected_channels = pixel_traits<pixel_type>::num;\n\n        const bool has_correct_number_of_dims = (img.ndim()==2 && expected_channels==1) || \n                                                (img.ndim()==3 && img.shape(2)==expected_channels);\n\n        return img.dtype().kind() == py::dtype::of<basic_pixel_type>().kind() && \n               img.itemsize() == sizeof(basic_pixel_type) && \n               has_correct_number_of_dims;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void assert_correct_num_channels_in_image (\n        const py::array& img\n    )\n    {\n        const size_t expected_channels = pixel_traits<pixel_type>::num;\n        if (expected_channels == 1)\n        {\n            if (!(img.ndim() == 2 || (img.ndim()==3&&img.shape(2)==1)))\n                throw dlib::error(\"Expected a 2D numpy array, but instead got one with \" + std::to_string(img.ndim()) + \" dimensions.\");\n        }\n        else\n        {\n            if (img.ndim() != 3)\n            {\n                throw dlib::error(\"Expected a numpy array with 3 dimensions, but instead got one with \" + std::to_string(img.ndim()) + \" dimensions.\");\n            }\n            else if (img.shape(2) != expected_channels)\n            {\n                if (pixel_traits<pixel_type>::rgb)\n                    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.\");\n                else\n                    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.\");\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    void assert_is_image (\n        const py::array& obj\n    )\n    {\n        if (!is_image<pixel_type>(obj))\n        {\n            assert_correct_num_channels_in_image<pixel_type>(obj);\n\n            using basic_pixel_type = typename pixel_traits<pixel_type>::basic_pixel_type;\n            const char expected_type = py::dtype::of<basic_pixel_type>().kind();\n            const char got_type = obj.dtype().kind();\n\n            const size_t expected_size = sizeof(basic_pixel_type);\n            const size_t got_size = obj.itemsize();\n\n            auto toname = [](char type, size_t size) {\n                if (type == 'i' && size == 1) return \"int8\";\n                else if (type == 'i' && size == 2) return \"int16\";\n                else if (type == 'i' && size == 4) return \"int32\";\n                else if (type == 'i' && size == 8) return \"int64\";\n                else if (type == 'u' && size == 1) return \"uint8\";\n                else if (type == 'u' && size == 2) return \"uint16\";\n                else if (type == 'u' && size == 4) return \"uint32\";\n                else if (type == 'u' && size == 8) return \"uint64\";\n                else if (type == 'f' && size == 4) return \"float32\";\n                else if (type == 'd' && size == 8) return \"float64\";\n                else DLIB_CASSERT(false, \"unknown type\");\n            };\n\n            throw dlib::error(\"Expected numpy array with elements of type \" + std::string(toname(expected_type,expected_size)) + \" but got \" + toname(got_type, got_size) + \".\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename pixel_type\n        >\n    class numpy_image : public py::array_t<typename pixel_traits<pixel_type>::basic_pixel_type, py::array::c_style>\n    {\n        /*!\n            REQUIREMENTS ON pixel_type\n                - is a dlib pixel type, this just means that dlib::pixel_traits<pixel_type>\n                  is defined.\n\n            WHAT THIS OBJECT REPRESENTS\n                This is an image object that implements dlib's generic image interface and\n                is backed by a numpy array.  It therefore is easily interchanged with\n                python since there is no copying.  It is functionally just a pybind11\n                array_t object with the additional routines needed to conform to dlib's\n                generic image API.  It also includes appropriate runtime checks to make\n                sure that the numpy array is always typed and sized appropriately relative\n                to the supplied pixel_type. \n        !*/\n    public:\n\n        numpy_image() = default;\n\n        numpy_image(\n            const py::array& img\n        ) : py::array_t<typename pixel_traits<pixel_type>::basic_pixel_type, py::array::c_style>(img)\n        {\n            assert_is_image<pixel_type>(img);\n        }\n\n        numpy_image (\n            long rows,\n            long cols\n        )\n        {\n            set_size(rows,cols);\n        }\n\n        numpy_image (\n            const py::object& img\n        ) : numpy_image(img.cast<py::array>()) {}\n\n        numpy_image(\n            const numpy_image& img\n        ) = default;\n\n        numpy_image& operator= (\n            const py::object& rhs\n        )\n        {\n            *this = numpy_image(rhs);\n            return *this;\n        }\n\n        numpy_image& operator= (\n            const py::array_t<typename pixel_traits<pixel_type>::basic_pixel_type, py::array::c_style>& rhs\n        )\n        {\n            *this = numpy_image(rhs);\n            return *this;\n        }\n\n        numpy_image& operator= (\n            const numpy_image& rhs\n        ) = default;\n\n        template <long NR, long NC>\n        numpy_image (\n            matrix<pixel_type,NR,NC>&& rhs\n        ) : numpy_image(convert_to_numpy(std::move(rhs))) {}\n\n        template <long NR, long NC>\n        numpy_image& operator= (\n            matrix<pixel_type,NR,NC>&& rhs\n        )\n        {\n            *this = numpy_image(rhs);\n            return *this;\n        }\n\n        void set_size(size_t rows, size_t cols)\n        {\n            using basic_pixel_type = typename pixel_traits<pixel_type>::basic_pixel_type;\n            constexpr size_t channels = pixel_traits<pixel_type>::num;\n            if (channels != 1)\n                *this = py::array_t<basic_pixel_type, py::array::c_style>({rows, cols, channels});\n            else\n                *this = py::array_t<basic_pixel_type, py::array::c_style>({rows, cols});\n        }\n\n    private:\n        static py::array_t<typename pixel_traits<pixel_type>::basic_pixel_type, py::array::c_style> convert_to_numpy(matrix<pixel_type>&& img)\n        {\n            using basic_pixel_type = typename pixel_traits<pixel_type>::basic_pixel_type;\n            const size_t dtype_size = sizeof(basic_pixel_type);\n            const auto rows = static_cast<const size_t>(num_rows(img));\n            const auto cols = static_cast<const size_t>(num_columns(img));\n            const size_t channels = pixel_traits<pixel_type>::num;\n            const size_t image_size = dtype_size * rows * cols * channels;\n\n            std::unique_ptr<pixel_type[]> arr_ptr = img.steal_memory();\n            basic_pixel_type* arr = (basic_pixel_type *) arr_ptr.release();\n\n            if (channels == 1)\n            {\n                return pybind11::template array_t<basic_pixel_type, py::array::c_style>(\n                    {rows, cols},                                                       // shape\n                    {dtype_size*cols, dtype_size},                                      // strides\n                    arr,                                                                // pointer\n                    pybind11::capsule{ arr, [](void *arr_p) { delete[] reinterpret_cast<basic_pixel_type*>(arr_p); } }\n                );\n            }\n            else\n            {\n                return pybind11::template array_t<basic_pixel_type, py::array::c_style>(\n                    {rows, cols, channels},                                                     // shape\n                    {dtype_size * cols * channels, dtype_size * channels, dtype_size},          // strides\n                    arr,                                                                        // pointer\n                    pybind11::capsule{ arr, [](void *arr_p) { delete[] reinterpret_cast<basic_pixel_type*>(arr_p); } }\n                );\n            }\n        }\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    void assign_image (\n        numpy_image<pixel_type>& dest,\n        const py::array& src\n    )\n    {\n        if (is_image<pixel_type>(src))     dest = src;\n        else if (is_image<uint8_t>(src))   assign_image(dest, numpy_image<uint8_t>(src));\n        else if (is_image<uint16_t>(src))  assign_image(dest, numpy_image<uint16_t>(src));\n        else if (is_image<uint32_t>(src))  assign_image(dest, numpy_image<uint32_t>(src));\n        else if (is_image<uint64_t>(src))  assign_image(dest, numpy_image<uint64_t>(src));\n        else if (is_image<int8_t>(src))    assign_image(dest, numpy_image<int8_t>(src));\n        else if (is_image<int16_t>(src))   assign_image(dest, numpy_image<int16_t>(src));\n        else if (is_image<int32_t>(src))   assign_image(dest, numpy_image<int32_t>(src));\n        else if (is_image<int64_t>(src))   assign_image(dest, numpy_image<int64_t>(src));\n        else if (is_image<float>(src))     assign_image(dest, numpy_image<float>(src));\n        else if (is_image<double>(src))    assign_image(dest, numpy_image<double>(src));\n        else if (is_image<rgb_pixel>(src)) assign_image(dest, numpy_image<rgb_pixel>(src));\n        else if (is_image<rgb_alpha_pixel>(src)) assign_image(dest, numpy_image<rgb_alpha_pixel>(src));\n        else DLIB_CASSERT(false, \"Unsupported pixel type used in assign_image().\");\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n//                          BORING IMPLEMENTATION STUFF\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <typename pixel_type>\n    long num_rows(const numpy_image<pixel_type>& img)\n    {\n        if (img.size()==0)\n            return 0;\n\n        assert_correct_num_channels_in_image<pixel_type>(img);\n        return img.shape(0);\n    }\n\n    template <typename pixel_type>\n    long num_columns(const numpy_image<pixel_type>& img)\n    {\n        if (img.size()==0)\n            return 0;\n\n        assert_correct_num_channels_in_image<pixel_type>(img);\n        return img.shape(1);\n    }\n\n    template <typename pixel_type>\n    void set_image_size(numpy_image<pixel_type>& img, size_t rows, size_t cols)\n    {\n        img.set_size(rows, cols);\n    }\n\n    template <typename pixel_type>\n    void* image_data(numpy_image<pixel_type>& img)\n    {\n        if (img.size()==0)\n            return 0;\n\n        assert_is_image<pixel_type>(img);\n        return img.mutable_data(0);\n    }\n\n    template <typename pixel_type>\n    const void* image_data (const numpy_image<pixel_type>& img)\n    {\n        if (img.size()==0)\n            return 0;\n\n        assert_is_image<pixel_type>(img);\n        return img.data(0);\n    }\n\n    template <typename pixel_type>\n    size_t width_step (const numpy_image<pixel_type>& img)\n    {\n        if (img.size()==0)\n            return 0;\n\n        assert_correct_num_channels_in_image<pixel_type>(img);\n        using basic_pixel_type = typename pixel_traits<pixel_type>::basic_pixel_type;\n        if (img.ndim()==3 && img.strides(2) != sizeof(basic_pixel_type))\n            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)));\n        if (img.strides(1) != sizeof(pixel_type))\n            throw dlib::error(\"The stride of the 2nd dimension (the columns dimension) of the numpy array must be \" + std::to_string(sizeof(pixel_type)));\n\n        return img.strides(0);\n    }\n\n    template <typename pixel_type>\n    void swap(numpy_image<pixel_type>& a, numpy_image<pixel_type>& b)\n    {\n        std::swap(a,b);\n    }\n\n\n    template <typename T> \n    struct image_traits<numpy_image<T>>\n    {\n        typedef T pixel_type;\n    };\n}\n\n// ----------------------------------------------------------------------------------------\n\nnamespace pybind11\n{\n    namespace detail\n    {\n        template <typename pixel_type> struct handle_type_name<dlib::numpy_image<pixel_type>> \n        {\n            using basic_pixel_type = typename dlib::pixel_traits<pixel_type>::basic_pixel_type;\n\n            static constexpr auto getname()\n            {\n                constexpr long channels = dlib::pixel_traits<pixel_type>::num;\n\n                if (channels == 1)\n                    return _(\"numpy.ndarray[(rows,cols),  \") + npy_format_descriptor<basic_pixel_type>::name + _(\"]\");\n                else if (channels == 2)\n                    return _(\"numpy.ndarray[(rows,cols,2),\") + npy_format_descriptor<basic_pixel_type>::name + _(\"]\");\n                else if (channels == 3)\n                    return _(\"numpy.ndarray[(rows,cols,3),\") + npy_format_descriptor<basic_pixel_type>::name + _(\"]\");\n                else if (channels == 4)\n                    return _(\"numpy.ndarray[(rows,cols,4),\") + npy_format_descriptor<basic_pixel_type>::name + _(\"]\");\n                else\n                    return _(\"numpy.ndarray[(rows,cols,N),\") + npy_format_descriptor<basic_pixel_type>::name + _(\"]\");\n            }\n\n            static constexpr auto name = getname();\n        };\n\n        template <typename pixel_type>\n        struct pyobject_caster<dlib::numpy_image<pixel_type>> {\n            using type = dlib::numpy_image<pixel_type>;\n\n            bool load(handle src, bool /*convert*/) {\n                // If passed a tuple where the first element of the tuple is a valid\n                // numpy_image then bind the numpy_image to that element of the tuple.\n                // We do this because there is a pattern of returning an image and some\n                // associated metadata.  This allows the returned tuple from such functions\n                // to also be treated as an image without needing to unpack the first\n                // argument.\n                if (PyTuple_Check(src.ptr()) && PyTuple_Size(src.ptr()) >= 1)\n                    src = reinterpret_borrow<py::tuple>(src)[0];\n\n                if (!type::check_(src))\n                    return false;\n                // stash the output of ensure into a temp variable since assigning it to\n                // value (the member variable created by the PYBIND11_TYPE_CASTER)\n                // apparently causes the return bool value to be ignored? \n                auto temp = type::ensure(src);\n                if (!dlib::is_image<pixel_type>(temp))\n                    return false;\n                value = temp;\n                return static_cast<bool>(value);\n            }\n\n            static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {\n                return src.inc_ref();\n            }\n            PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);\n        };\n    }\n}\n\n\n// ----------------------------------------------------------------------------------------\n\n#endif // DLIB_PYTHON_NuMPY_IMAGE_Hh_\n\n"
  },
  {
    "path": "dlib/python/pyassert.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PYaSSERT_Hh_\n#define DLIB_PYaSSERT_Hh_\n\n#include <pybind11/pybind11.h>\n\n#define pyassert(_exp,_message)                                             \\\n    {if ( !(_exp) )                                                         \\\n    {                                                                       \\\n        namespace py = pybind11;                                            \\\n        PyErr_SetString( PyExc_ValueError, _message );                      \\\n        throw py::error_already_set();                                      \\\n    }}\n\n#endif // DLIB_PYaSSERT_Hh_\n\n"
  },
  {
    "path": "dlib/python/pybind_utils.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PYBIND_UtILS_Hh_\n#define DLIB_PYBIND_UtILS_Hh_\n\n#include <pybind11/pybind11.h>\n#include <vector>\n#include <string>\n#include <dlib/serialize.h>\n#include <array>\n\nnamespace py = pybind11;\n\nnamespace dlib\n{\n\n    template <typename T>\n    std::vector<T> python_list_to_vector (\n        const py::list& obj\n    )\n    /*!\n        ensures\n            - converts a python object into a std::vector<T> and returns it.\n    !*/\n    {\n        std::vector<T> vect(len(obj));\n        for (unsigned long i = 0; i < vect.size(); ++i)\n        {\n            vect[i] = obj[i].cast<T>();\n        }\n        return vect;\n    }\n\n    template <typename T,size_t N>\n    std::array<T,N> python_list_to_array (\n        const py::list& the_list\n    )\n    /*!\n        ensures\n            - converts a python object into a std::array<T,N> and returns it.\n    !*/\n    {\n        DLIB_CASSERT(len(the_list) == N, \"Expected a list of \" << N << \" things.\");\n        std::array<T,N> vect;\n        for (unsigned long i = 0; i < vect.size(); ++i)\n        {\n            vect[i] = the_list[i].cast<T>();\n        }\n        return vect;\n    }\n\n    template <typename T>\n    py::list vector_to_python_list (\n        const std::vector<T>& vect\n    )\n    /*!\n        ensures\n            - converts a std::vector<T> into a python list object.\n    !*/\n    {\n        py::list obj;\n        for (unsigned long i = 0; i < vect.size(); ++i)\n            obj.append(vect[i]);\n        return obj;\n    }\n\n    template <typename T>\n    void extend_vector_with_python_list (\n        std::vector<T> &v,\n        const py::list &l\n    )\n    /*!\n        ensures\n            - appends items from a python list to the end of std::vector<T>.\n    !*/\n    {\n        for (const auto &item : l)\n            v.push_back(item.cast<T>());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    std::shared_ptr<T> load_object_from_file (\n        const std::string& filename\n    )\n    /*!\n        ensures\n            - deserializes an object of type T from the given file and returns it.\n    !*/\n    {\n        std::ifstream fin(filename.c_str(), std::ios::binary);\n        if (!fin)\n            throw dlib::error(\"Unable to open \" + filename);\n        auto obj = std::make_shared<T>();\n        deserialize(*obj, fin);\n        return obj;\n    }\n}\n\n// ----------------------------------------------------------------------------------------\n\n\n#endif // DLIB_PYBIND_UtILS_Hh_\n\n"
  },
  {
    "path": "dlib/python/serialize_pickle.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERIALIZE_PiCKLE_Hh_\n#define DLIB_SERIALIZE_PiCKLE_Hh_\n\n#include <dlib/serialize.h>\n#include <pybind11/pybind11.h>\n#include <sstream>\n#include <dlib/vectorstream.h>\n\nnamespace py = pybind11;\n\nnamespace dlib\n{\n\n    template<typename T>\n    py::tuple getstate(const T& item)\n    {\n        using namespace dlib;\n        std::vector<char> buf;\n        buf.reserve(5000);\n        vectorstream sout(buf);\n        serialize(item, sout);\n        return py::make_tuple(py::handle(\n                PyBytes_FromStringAndSize(buf.size()?&buf[0]:0, buf.size())));\n    }\n\n    template<typename T>\n    T setstate(py::tuple state)\n    {\n        using namespace dlib;\n        if (len(state) != 1)\n        {\n            PyErr_SetObject(PyExc_ValueError,\n                py::str(\"expected 1-item tuple in call to __setstate__; got {}\").format(state).ptr()\n            );\n            throw py::error_already_set();\n        }\n\n        // We used to serialize by converting to a str but the boost.python routines for\n        // doing this don't work in Python 3.  You end up getting an error about invalid\n        // UTF-8 encodings.  So instead we access the python C interface directly and use\n        // bytes objects.  However, we keep the deserialization code that worked with str\n        // for backwards compatibility with previously pickled files.\n        T item;\n        py::object obj = state[0];\n        if (py::isinstance<py::str>(obj))\n        {\n            py::str data = state[0].cast<py::str>();\n            std::string temp = data;\n            std::istringstream sin(temp);\n            deserialize(item, sin);\n        }\n        else if(PyBytes_Check(py::object(state[0]).ptr()))\n        {\n            py::object obj = state[0];\n            char* data = PyBytes_AsString(obj.ptr());\n            unsigned long num = PyBytes_Size(obj.ptr());\n            std::istringstream sin(std::string(data, num));\n            deserialize(item, sin);\n        }\n        else\n        {\n            throw error(\"Unable to unpickle, error in input file.\");\n        }\n\n        return item;\n    }\n\n}\n\n#endif // DLIB_SERIALIZE_PiCKLE_Hh_\n\n"
  },
  {
    "path": "dlib/python.h",
    "content": "// Copyright (C) 2013  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_PYTHoN_TOP_\n#define DLIB_PYTHoN_TOP_ \n\n#include \"python/pybind_utils.h\"\n#include \"python/pyassert.h\"\n#include \"python/serialize_pickle.h\"\n#include \"python/numpy_image.h\"\n\n#endif // DLIB_PYTHoN_TOP_\n\n\n"
  },
  {
    "path": "dlib/quantum_computing/quantum_computing.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUANTUM_COMPUTINg_1_\n#define DLIB_QUANTUM_COMPUTINg_1_\n\n#include <complex>\n#include <cmath>\n#include \"../matrix.h\"\n#include \"../rand.h\"\n#include \"../enable_if.h\"\n#include \"../algs.h\"\n#include \"quantum_computing_abstract.h\"\n\nnamespace dlib\n{\n\n    template <typename T>\n    struct gate_traits {};\n\n    namespace qc_helpers\n    {\n\n    // ------------------------------------------------------------------------------------\n\n    // This is a template to compute the value of 2^n at compile time\n        template <long n>\n        struct exp_2_n\n        {\n            COMPILE_TIME_ASSERT(0 <= n && n <= 30);\n            static const long value = exp_2_n<n-1>::value*2;\n        };\n\n        template <>\n        struct exp_2_n<0>\n        {\n            static const long value = 1;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n    typedef std::complex<double> qc_scalar_type;\n\n// ----------------------------------------------------------------------------------------\n\n    class quantum_register\n    {\n    public:\n\n        quantum_register()\n        {\n            set_num_bits(1);\n        }\n\n        int num_bits (\n        ) const\n        {\n            return num_bits_in_register;\n        }\n\n        void set_num_bits (\n            int num_bits\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(1 <= num_bits && num_bits <= 30,\n                \"\\tvoid quantum_register::set_num_bits()\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\tnum_bits: \" << num_bits \n                << \"\\n\\tthis:     \" << this\n                );\n\n            num_bits_in_register = num_bits;\n\n            unsigned long size = 1;\n            for (int i = 0; i < num_bits; ++i)\n                size *= 2;\n\n            state.set_size(size);\n\n            zero_all_bits();\n        }\n\n        void zero_all_bits()\n        {\n            set_all_elements(state,0);\n            state(0) = 1;\n        }\n\n        void append ( \n            const quantum_register& reg\n        )\n        {\n            num_bits_in_register += reg.num_bits_in_register;\n            state = tensor_product(state, reg.state);\n        }\n\n        template <typename rand_type>\n        bool measure_bit (\n            int bit,\n            rand_type& rnd\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(0 <= bit && bit < num_bits(),\n                \"\\tbool quantum_register::measure_bit()\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\tbit:        \" << bit \n                << \"\\n\\tnum_bits(): \" << num_bits() \n                << \"\\n\\tthis:       \" << this\n                );\n\n            const bool value = (rnd.get_random_double() < probability_of_bit(bit));\n\n            // Next we set all the states where this bit doesn't have the given value to 0\n\n            // But first make a mask that selects our bit\n            unsigned long mask = 1;\n            for (int i = 0; i < bit; ++i)\n                mask <<= 1;\n\n            // loop over all the elements in the state vector and zero out those that\n            // conflict with the measurement we just made.\n            for (long r = 0; r < state.nr(); ++r)\n            {\n                const unsigned long field = r;\n                // if this state indicates that the bit should be set and it isn't\n                if ((field & mask) && !value)\n                {\n                    state(r) = 0;\n                }\n                // else if this state indicates that the bit should not be set and it is \n                else if (!(field & mask) && value)\n                {\n                    state(r) = 0;\n                }\n            }\n\n            // normalize the state\n            state = state/(std::sqrt(sum(norm(state))));\n\n            return value;\n        }\n\n        template <typename rand_type>\n        bool measure_and_remove_bit (\n            int bit,\n            rand_type& rnd\n        )\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(0 <= bit && bit < num_bits() && num_bits() > 0,\n                \"\\tbool quantum_register::measure_and_remove_bit()\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\tbit:        \" << bit \n                << \"\\n\\tnum_bits(): \" << num_bits() \n                << \"\\n\\tthis:       \" << this\n                );\n\n\n            const bool value = (rnd.get_random_double() < probability_of_bit(bit));\n            quantum_register temp;\n            temp.set_num_bits(num_bits()-1);\n\n\n            // Next we set all the states where this bit doesn't have the given value to 0\n\n            // But first make a mask that selects our bit\n            unsigned long mask = 1;\n            for (int i = 0; i < bit; ++i)\n                mask <<= 1;\n\n            long count = 0;\n            for (long r = 0; r < state.nr(); ++r)\n            {\n                const unsigned long field = r;\n                // if this basis vector is one that matches the measured state then keep it\n                if (((field & mask) != 0) == value)\n                {\n                    temp.state(count) = state(r);\n                    ++count;\n                }\n            }\n\n            // normalize the state\n            temp.state = temp.state/std::sqrt(sum(norm(temp.state)));\n\n            temp.swap(*this);\n\n            return value;\n        }\n\n        double probability_of_bit (\n            int bit\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(0 <= bit && bit < num_bits(),\n                \"\\tdouble quantum_register::probability_of_bit()\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\tbit:        \" << bit \n                << \"\\n\\tnum_bits(): \" << num_bits() \n                << \"\\n\\tthis:       \" << this\n                );\n\n\n            // make a mask that selects our bit\n            unsigned long mask = 1;\n            for (int i = 0; i < bit; ++i)\n                mask <<= 1;\n\n            // now find the total probability of all the states that have the given bit set\n            double prob = 0;\n            for (long r = 0; r < state.nr(); ++r)\n            {\n                const unsigned long field = r;\n                if (field & mask)\n                {\n                    prob += std::norm(state(r));\n                }\n            }\n\n\n            return prob;\n        }\n\n        const matrix<qc_scalar_type,0,1>& state_vector() const { return state; }\n        matrix<qc_scalar_type,0,1>& state_vector() { return state; }\n\n        void swap (\n            quantum_register& item\n        )\n        {\n            exchange(num_bits_in_register, item.num_bits_in_register);\n            state.swap(item.state);\n        }\n\n    private:\n\n        int num_bits_in_register;\n        matrix<qc_scalar_type,0,1> state;\n    };\n\n    inline void swap (\n        quantum_register& a,\n        quantum_register& b\n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class gate_exp\n    {\n    public:\n        static const long num_bits = gate_traits<T>::num_bits;\n        static const long dims = gate_traits<T>::dims;\n\n        gate_exp(T& exp_) : exp(exp_) {}\n\n        const qc_scalar_type operator() (long r, long c) const { return exp(r,c); }\n\n        const matrix<qc_scalar_type> mat (\n        ) const\n        {\n            matrix<qc_scalar_type,dims,dims> m;\n            for (long r = 0; r < m.nr(); ++r)\n            {\n                for (long c = 0; c < m.nc(); ++c)\n                {\n                    m(r,c) = exp(r,c);\n                }\n            }\n            return m;\n        }\n\n        void apply_gate_to (quantum_register& reg) const\n        {\n            // make sure requires clause is not broken\n            DLIB_CASSERT(reg.num_bits() == num_bits,\n                \"\\tvoid gate_exp::apply_gate_to()\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\treg.num_bits(): \" << reg.num_bits() \n                << \"\\n\\tnum_bits:       \" << num_bits \n                << \"\\n\\tthis:           \" << this\n                );\n\n\n            quantum_register temp(reg);\n\n\n            // check if any of the elements of the register are 1 and if so then\n            // we don't have to do the full matrix multiply.  Or check if only a small number are non-zero.\n            long non_zero_elements = 0;\n            for (long r = 0; r < dims; ++r)\n            {\n                if (reg.state_vector()(r) != qc_scalar_type(0))\n                    ++non_zero_elements;\n\n                reg.state_vector()(r) = 0;\n            }\n\n\n            if (non_zero_elements > 3)\n            {\n                // do a full matrix multiply to compute the output state\n                for (long r = 0; r < dims; ++r)\n                {\n                    reg.state_vector()(r) = compute_state_element(temp.state_vector(),r);\n                }\n            }\n            else\n            {\n                // do a matrix multiply but only use the columns in the gate matrix \n                // that correspond to the non-zero register elements\n                for (long r = 0; r < dims; ++r)\n                {\n                    if (temp.state_vector()(r) != qc_scalar_type(0))\n                    {\n                        for (long i = 0; i < dims; ++i)\n                        {\n                            reg.state_vector()(i) += temp.state_vector()(r)*exp(i,r);\n                        }\n                    }\n                }\n            }\n        }\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(reg.nr() == dims && reg.nc() == 1 && \n                         0 <= row_idx && row_idx < dims,\n                \"\\tqc_scalar_type gate_exp::compute_state_element(reg,row_idx)\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\treg.nr(): \" << reg.nr() \n                << \"\\n\\treg.nc(): \" << reg.nc()\n                << \"\\n\\tdims:     \" << dims\n                << \"\\n\\trow_idx:  \" << row_idx \n                << \"\\n\\tthis:     \" << this\n                );\n\n\n            return this->exp.compute_state_element(reg,row_idx);\n        }\n\n        const T& ref() const { return exp; }\n\n    private:\n        T& exp;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n\n    template <typename T, typename U>\n    class composite_gate;\n\n    template <typename T, typename U>\n    struct gate_traits<composite_gate<T,U> >\n    {\n        static const long num_bits = T::num_bits + U::num_bits;\n        static const long dims = qc_helpers::exp_2_n<num_bits>::value;\n    };\n\n    template <typename T, typename U>\n    class composite_gate : public gate_exp<composite_gate<T,U> >\n    {\n    public:\n\n        typedef T lhs_type;\n        typedef U rhs_type;\n\n        composite_gate(const composite_gate& g) : gate_exp<composite_gate>(*this), lhs(g.lhs), rhs(g.rhs) {}\n\n        composite_gate(\n            const gate_exp<T>& lhs_,\n            const gate_exp<U>& rhs_\n        ) : gate_exp<composite_gate>(*this), lhs(lhs_.ref()), rhs(rhs_.ref()) {}\n\n\n\n        static const long num_bits = gate_traits<composite_gate>::num_bits;\n        static const long dims = gate_traits<composite_gate>::dims;\n\n        const qc_scalar_type operator() (long r, long c) const { return lhs(r/U::dims,c/U::dims)*rhs(r%U::dims, c%U::dims); }\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(reg.nr() == dims && reg.nc() == 1 && \n                         0 <= row_idx && row_idx < dims,\n                \"\\tqc_scalar_type composite_gate::compute_state_element(reg,row_idx)\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\treg.nr(): \" << reg.nr() \n                << \"\\n\\treg.nc(): \" << reg.nc()\n                << \"\\n\\tdims:     \" << dims\n                << \"\\n\\trow_idx:  \" << row_idx \n                << \"\\n\\tthis:     \" << this\n                );\n\n\n            qc_scalar_type result = 0;\n            for (long c = 0; c < T::dims; ++c)\n            {\n                if (lhs(row_idx/U::dims,c) != qc_scalar_type(0))\n                {\n                    result += lhs(row_idx/U::dims,c) * rhs.compute_state_element(subm(reg,c*U::dims,0,U::dims,1), row_idx%U::dims);\n                }\n            }\n\n            return result;\n        }\n\n\n        const T lhs;\n        const U rhs;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <long bits>\n    class gate;\n    template <long bits>\n    struct gate_traits<gate<bits> >\n    {\n        static const long num_bits = bits;\n        static const long dims = qc_helpers::exp_2_n<num_bits>::value;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <long bits>\n    class gate : public gate_exp<gate<bits> >\n    {\n    public:\n        gate() : gate_exp<gate>(*this) { set_all_elements(data,0); }\n        gate(const gate& g) :gate_exp<gate>(*this), data(g.data) {}\n\n        template <typename T>\n        explicit gate(const gate_exp<T>& g) : gate_exp<gate>(*this) \n        {\n            COMPILE_TIME_ASSERT(T::num_bits == num_bits);\n            for (long r = 0; r < dims; ++r)\n            {\n                for (long c = 0; c < dims; ++c)\n                {\n                    data(r,c) = g(r,c);\n                }\n            }\n        }\n\n        static const long num_bits = gate_traits<gate>::num_bits;\n        static const long dims = gate_traits<gate>::dims;\n\n        const qc_scalar_type& operator() (long r, long c) const { return data(r,c); }\n        qc_scalar_type& operator() (long r, long c)  { return data(r,c); }\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const\n        {\n            // make sure requires clause is not broken\n            DLIB_ASSERT(reg.nr() == dims && reg.nc() == 1 && \n                         0 <= row_idx && row_idx < dims,\n                \"\\tqc_scalar_type gate::compute_state_element(reg,row_idx)\"\n                << \"\\n\\tinvalid arguments to this function\"\n                << \"\\n\\treg.nr(): \" << reg.nr() \n                << \"\\n\\treg.nc(): \" << reg.nc()\n                << \"\\n\\tdims:     \" << dims\n                << \"\\n\\trow_idx:  \" << row_idx \n                << \"\\n\\tthis:     \" << this\n                );\n\n\n            return (data*reg)(row_idx);\n        }\n\n    private:\n\n        matrix<qc_scalar_type,dims,dims> data;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    namespace qc_helpers\n    {\n        // This is the maximum number of bits used for cached sub-matrices in composite_gate expressions\n        const int qc_block_chunking_size = 8;\n\n        template <typename T>\n        struct is_composite_gate { const static bool value = false; };\n        template <typename T, typename U>\n        struct is_composite_gate<composite_gate<T,U> > { const static bool value = true; };\n\n\n        // These overloads all deal with intelligently composing chains of composite_gate expressions\n        // such that the resulting expression has the form:\n        //    (gate_exp,(gate_exp,(gate_exp,(gate_exp()))))\n        // and each gate_exp contains a cached gate matrix for a gate of at most qc_block_chunking_size bits.  \n        // This facilitates the optimizations in the compute_state_element() function. \n        template <typename T, typename U, typename V, typename enabled = void>\n        struct combine_gates;\n\n        // This is a base case of this recursive template.  It takes care of converting small composite_gates into\n        // cached gate objects.\n        template <typename T, typename U, typename V>\n        struct combine_gates<T,U,V,typename enable_if_c<(T::num_bits + U::num_bits <= qc_block_chunking_size)>::type >\n        {\n            typedef composite_gate<gate<T::num_bits + U::num_bits>,V>  result_type;\n\n            static const result_type eval (\n                const composite_gate<T,U>& lhs,\n                const gate_exp<V>& rhs\n            ) \n            {\n                typedef gate<T::num_bits + U::num_bits> gate_type;\n                return composite_gate<gate_type,V>(gate_type(lhs), rhs);\n            }\n        };\n\n        // this is the recursive step of this template\n        template <typename T, typename U, typename V>\n        struct combine_gates<T,U,V,typename enable_if_c<(is_composite_gate<U>::value == true)>::type >\n        {\n            typedef typename combine_gates<typename U::lhs_type, typename U::rhs_type, V>::result_type inner_type;\n            typedef composite_gate<T,inner_type> result_type;\n\n            static const result_type eval (\n                const composite_gate<T,U>& lhs,\n                const gate_exp<V>& rhs\n            )\n            {\n                return composite_gate<T,inner_type>(lhs.lhs, combine_gates<typename U::lhs_type, typename U::rhs_type, V>::eval(lhs.rhs,rhs));\n            }\n\n        };\n\n        // This is a base case of this recursive template.  It takes care of adding new gates when the left\n        // hand side is too big to just turn it into a cached gate object.\n        template <typename T, typename U, typename V>\n        struct combine_gates<T,U,V,typename enable_if_c<(T::num_bits + U::num_bits > qc_block_chunking_size && \n                                                         is_composite_gate<U>::value == false)>::type >\n        {\n            typedef composite_gate<T,composite_gate<U, V> > result_type;\n\n            static const result_type eval (\n                const composite_gate<T,U>& lhs,\n                const gate_exp<V>& rhs\n            ) \n            {\n                return result_type(lhs.lhs, composite_gate<U,V>(lhs.rhs, rhs)); \n            }\n\n        };\n\n    }\n\n    template <typename T, typename U>\n    const composite_gate<T,U> operator, ( \n        const gate_exp<T>& lhs,\n        const gate_exp<U>& rhs\n    )\n    {\n        return composite_gate<T,U>(lhs,rhs);\n    }\n\n    template <typename T, typename U, typename V>\n    const typename qc_helpers::combine_gates<T,U,V>::result_type operator, ( \n        const composite_gate<T,U>& lhs,\n        const gate_exp<V>& rhs\n    )\n    {\n        return qc_helpers::combine_gates<T,U,V>::eval(lhs,rhs);\n    }\n\n    // If you are getting an error here then it means that you are trying to combine a gate expression\n    // with an integer somewhere (and that is an error).  \n    template <typename T> void operator, ( const gate_exp<T>&, int) { COMPILE_TIME_ASSERT(sizeof(T) > 100000000); }\n    template <typename T> void operator, ( int, const gate_exp<T>&) { COMPILE_TIME_ASSERT(sizeof(T) > 100000000); }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace quantum_gates\n    {\n        template <int control_bit, int target_bit>\n        class cnot;\n\n        template <int control_bit1, int control_bit2, int target_bit>\n        class toffoli;\n    }\n\n    template <int control_bit, int target_bit>\n    struct gate_traits<quantum_gates::cnot<control_bit, target_bit> >\n    {\n        static const long num_bits = tabs<control_bit-target_bit>::value+1;\n        static const long dims = qc_helpers::exp_2_n<num_bits>::value;\n    };\n\n    template <int control_bit1, int control_bit2, int target_bit>\n    struct gate_traits<quantum_gates::toffoli<control_bit1, control_bit2, target_bit> >\n    {\n        static const long num_bits = tmax<tabs<control_bit1-target_bit>::value, \n                                            tabs<control_bit2-target_bit>::value>::value+1;\n        static const long dims = qc_helpers::exp_2_n<num_bits>::value;\n    };\n\n\n// ----------------------------------------------------------------------------------------\n\n    namespace quantum_gates\n    {\n\n        inline const gate<1> hadamard(\n        )\n        {\n            gate<1> h;\n            h(0,0) = std::sqrt(1/2.0);\n            h(0,1) = std::sqrt(1/2.0);\n            h(1,0) = std::sqrt(1/2.0);\n            h(1,1) = -std::sqrt(1/2.0);\n            return h;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const gate<1> x(\n        )\n        {\n            gate<1> x;\n            x(0,1) = 1;\n            x(1,0) = 1;\n            return x;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const gate<1> y(\n        )\n        {\n            gate<1> x;\n            qc_scalar_type i(0,1);\n            x(0,1) = -i;\n            x(1,0) = i;\n            return x;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const gate<1> z(\n        )\n        {\n            gate<1> z;\n            z(0,0) = 1;\n            z(1,1) = -1;\n            return z;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        inline const gate<1> noop(\n        )\n        {\n            gate<1> i;\n            i(0,0) = 1;\n            i(1,1) = 1;\n            return i;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <int control_bit, int target_bit>\n        class cnot : public gate_exp<cnot<control_bit, target_bit> >\n        {\n        public:\n            COMPILE_TIME_ASSERT(control_bit != target_bit);\n\n            cnot() : gate_exp<cnot>(*this) \n            {\n                const int min_bit = std::min(control_bit, target_bit);\n\n                control_mask = 1;\n                target_mask = 1;\n\n                // make the masks so that their only on bit corresponds to the given control_bit and target_bit bits\n                for (int i = 0; i < control_bit-min_bit; ++i)\n                    control_mask <<= 1;\n                for (int i = 0; i < target_bit-min_bit; ++i)\n                    target_mask <<= 1;\n            }\n\n            static const long num_bits = gate_traits<cnot>::num_bits;\n            static const long dims = gate_traits<cnot>::dims;\n\n            const qc_scalar_type operator() (long r, long c) const \n            { \n                unsigned long output;\n                // if the input control bit is set\n                if (control_mask&c)\n                {\n                    output = c^target_mask;\n                }\n                else\n                {\n                    output = c;\n                }\n\n                if ((unsigned long)r == output)\n                    return 1;\n                else\n                    return 0;\n            }\n\n            template <typename exp>\n            qc_scalar_type compute_state_element (\n                const matrix_exp<exp>& reg,\n                long row_idx\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT(reg.nr() == dims && reg.nc() == 1 && \n                            0 <= row_idx && row_idx < dims,\n                    \"\\tqc_scalar_type cnot::compute_state_element(reg,row_idx)\"\n                    << \"\\n\\tinvalid arguments to this function\"\n                    << \"\\n\\treg.nr(): \" << reg.nr() \n                    << \"\\n\\treg.nc(): \" << reg.nc()\n                    << \"\\n\\tdims:     \" << dims\n                    << \"\\n\\trow_idx:  \" << row_idx \n                    << \"\\n\\tthis:     \" << this\n                    );\n\n\n                unsigned long output = row_idx;\n                // if the input control bit is set\n                if (control_mask&output)\n                {\n                    output = output^target_mask;\n                }\n\n                return reg(output);\n            }\n\n        private:\n\n            unsigned long control_mask;\n            unsigned long target_mask;\n\n\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template <int control_bit1, int control_bit2, int target_bit>\n        class toffoli : public gate_exp<toffoli<control_bit1, control_bit2, target_bit> >\n        {\n        public:\n            COMPILE_TIME_ASSERT(control_bit1 != target_bit && control_bit2 != target_bit && control_bit1 != control_bit2);\n            COMPILE_TIME_ASSERT((control_bit1 < target_bit && control_bit2 < target_bit) ||(control_bit1 > target_bit && control_bit2 > target_bit) );\n\n            toffoli() : gate_exp<toffoli>(*this) \n            {\n                const int min_bit = std::min(std::min(control_bit1, control_bit2), target_bit);\n\n                control1_mask = 1;\n                control2_mask = 1;\n                target_mask = 1;\n\n                // make the masks so that their only on bit corresponds to the given control_bit1 and target_bit bits\n                for (int i = 0; i < control_bit1-min_bit; ++i)\n                    control1_mask <<= 1;\n                for (int i = 0; i < control_bit2-min_bit; ++i)\n                    control2_mask <<= 1;\n                for (int i = 0; i < target_bit-min_bit; ++i)\n                    target_mask <<= 1;\n            }\n\n            static const long num_bits = gate_traits<toffoli>::num_bits;\n            static const long dims = gate_traits<toffoli>::dims;\n\n            const qc_scalar_type operator() (long r, long c) const \n            { \n                unsigned long output;\n                // if the input control bits are set\n                if ((control1_mask&c) && (control2_mask&c))\n                {\n                    output = c^target_mask;\n                }\n                else\n                {\n                    output = c;\n                }\n\n                if ((unsigned long)r == output)\n                    return 1;\n                else\n                    return 0;\n            }\n\n            template <typename exp>\n            qc_scalar_type compute_state_element (\n                const matrix_exp<exp>& reg,\n                long row_idx\n            ) const\n            {\n                // make sure requires clause is not broken\n                DLIB_ASSERT(reg.nr() == dims && reg.nc() == 1 && \n                            0 <= row_idx && row_idx < dims,\n                    \"\\tqc_scalar_type toffoli::compute_state_element(reg,row_idx)\"\n                    << \"\\n\\tinvalid arguments to this function\"\n                    << \"\\n\\treg.nr(): \" << reg.nr() \n                    << \"\\n\\treg.nc(): \" << reg.nc()\n                    << \"\\n\\tdims:     \" << dims\n                    << \"\\n\\trow_idx:  \" << row_idx \n                    << \"\\n\\tthis:     \" << this\n                    );\n\n\n                unsigned long output;\n                // if the input control bits are set\n                if ((control1_mask&row_idx) && (control2_mask&row_idx))\n                {\n                    output = row_idx^target_mask;\n                }\n                else\n                {\n                    output = row_idx;\n                }\n\n                return reg(output);\n\n            }\n\n        private:\n\n            unsigned long control1_mask;\n            unsigned long control2_mask;\n            unsigned long target_mask;\n\n\n        };\n\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUANTUM_COMPUTINg_1_\n\n\n"
  },
  {
    "path": "dlib/quantum_computing/quantum_computing_abstract.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_QUANTUM_COMPUTINg_ABSTRACT_\n#ifdef DLIB_QUANTUM_COMPUTINg_ABSTRACT_\n\n#include <complex>\n#include \"../matrix.h\"\n#include \"../rand.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    typedef std::complex<double> qc_scalar_type;\n\n// ----------------------------------------------------------------------------------------\n\n    class quantum_register\n    {\n        /*!\n            INITIAL VALUE\n                - num_bits() == 1\n                - state_vector().nr() == 2\n                - state_vector().nc() == 1\n                - state_vector()(0) == 1\n                - state_vector()(1) == 0\n                - probability_of_bit(0) == 0\n\n                - i.e. This register represents a single quantum bit and it is\n                  completely in the 0 state.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a set of quantum bits.\n        !*/\n\n    public:\n\n        quantum_register(\n        );\n        /*!\n            ensures\n                - this object is properly initialized\n        !*/\n\n        int num_bits (\n        ) const;\n        /*!\n            ensures\n                - returns the number of quantum bits in this register\n        !*/\n\n        void set_num_bits (\n            int new_num_bits\n        );\n        /*!\n            requires\n                - 1 <= new_num_bits <= 30\n            ensures\n                - #num_bits() == new_num_bits\n                - #state_vector().nr() == 2^new_num_bits\n                  (i.e. the size of the state_vector is exponential in the number of bits in a register)\n                - for all valid i:\n                    - probability_of_bit(i) == 0\n        !*/\n\n        void zero_all_bits(\n        );\n        /*!\n            ensures\n                - for all valid i:\n                    - probability_of_bit(i) == 0\n        !*/\n\n        void append ( \n            const quantum_register& reg\n        );\n        /*!\n            ensures\n                - #num_bits() == num_bits() + reg.num_bits()\n                - #this->state_vector() == tensor_product(this->state_vector(), reg.state_vector())\n                - The original bits in *this become the high order bits of the resulting \n                  register and all the bits in reg end up as the low order bits in the\n                  resulting register.\n        !*/\n\n        double probability_of_bit (\n            int bit\n        ) const;\n        /*!\n            requires\n                - 0 <= bit < num_bits()\n            ensures\n                - returns the probability of measuring the given bit and it being in the 1 state.\n                - The returned value is also equal to the sum of norm(state_vector()(i)) for all\n                  i where the bit'th bit in i is set to 1. (note that the lowest order bit is bit 0)\n        !*/\n\n        template <typename rand_type>\n        bool measure_bit (\n            int bit,\n            rand_type& rnd\n        );\n        /*!\n            requires\n                - 0 <= bit < num_bits()\n                - rand_type == an implementation of dlib/rand/rand_float_abstract.h\n            ensures\n                - measures the given bit in this register.  Let R denote the boolean\n                  result of the measurement, where true means the bit was measured to\n                  have value 1 and false means it had a value of 0.\n                - if (R == true) then\n                    - returns true\n                    - #probability_of_bit(bit) == 1\n                - else\n                    - returns false\n                    - #probability_of_bit(bit) == 0\n        !*/\n\n        template <typename rand_type>\n        bool measure_and_remove_bit (\n            int bit,\n            rand_type& rnd\n        );\n        /*!\n            requires\n                - num_bits() > 1\n                - 0 <= bit < num_bits()\n                - rand_type == an implementation of dlib/rand/rand_float_abstract.h\n            ensures\n                - measures the given bit in this register.  Let R denote the boolean\n                  result of the measurement, where true means the bit was measured to\n                  have value 1 and false means it had a value of 0.\n                - #num_bits() == num_bits() - 1\n                - removes the bit that was measured from this register.\n                - if (R == true) then\n                    - returns true\n                - else\n                    - returns false\n        !*/\n\n        const matrix<qc_scalar_type,0,1>& state_vector(\n        ) const;\n        /*!\n            ensures\n                - returns a const reference to the state vector that describes the state of\n                  the quantum bits in this register.\n        !*/\n\n        matrix<qc_scalar_type,0,1>& state_vector(\n        );\n        /*!\n            ensures\n                - returns a non-const reference to the state vector that describes the state of\n                  the quantum bits in this register.\n        !*/\n\n        void swap (\n            quantum_register& item\n        );\n        /*!\n            ensures\n                - swaps *this and item\n        !*/\n\n    };\n\n    inline void swap (\n        quantum_register& a,\n        quantum_register& b\n    ) { a.swap(b); }\n    /*!\n        provides a global swap function\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    class gate_exp\n    {\n        /*!\n            REQUIREMENTS ON T\n                T must be some object that inherits from gate_exp and implements its own\n                version of operator() and compute_state_element().\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents an expression that evaluates to a quantum gate \n                that operates on T::num_bits qubits.\n\n                This object makes it easy to create new types of gate objects. All\n                you need to do is inherit from gate_exp in the proper way and \n                then you can use your new gate objects in conjunction with all the \n                others.\n        !*/\n\n    public:\n\n        static const long num_bits = T::num_bits;\n        static const long dims = T::dims; \n\n        gate_exp(\n            T& exp\n        );\n        /*!\n            ensures\n                - #&ref() == &exp\n        !*/\n\n        const qc_scalar_type operator() (\n            long r, \n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= r < dims\n                - 0 <= c < dims\n            ensures\n                - returns ref()(r,c)\n        !*/\n\n        void apply_gate_to (\n            quantum_register& reg\n        ) const;\n        /*!\n            requires\n                - reg.num_bits() == num_bits\n            ensures\n                - applies this quantum gate to the given quantum register\n                - Let M represent the matrix for this quantum gate, then\n                  #reg().state_vector() = M*reg().state_vector()\n        !*/\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const;\n        /*!\n            requires\n                - reg.nr() == dims\n                - reg.nc() == 1\n                - 0 <= row_idx < dims\n            ensures\n                - Let M represent the matrix for this gate, then   \n                  this function returns rowm(M*reg, row_idx)\n                  (i.e. returns the row_idx row of what you get when you apply this\n                  gate to the given column vector in reg)\n                - This function works by calling ref().compute_state_element(reg,row_idx)\n        !*/\n\n        const T& ref(\n        );\n        /*!\n            ensures\n                - returns a reference to the subexpression contained in this object\n        !*/\n\n        const matrix<qc_scalar_type> mat (\n        ) const;\n        /*!\n            ensures\n                - returns a dense matrix object that contains the matrix for this gate\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    class composite_gate : public gate_exp<composite_gate<T,U> >\n    {\n        /*!\n            REQUIREMENTS ON T AND U\n                Both must be gate expressions that inherit from gate_exp\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a quantum gate that is the tensor product of \n                two other quantum gates.\n\n\n                As an example, suppose you have 3 registers, reg_high, reg_low, and reg_all.  Also\n                suppose that reg_all is what you get when you append reg_high and reg_low,\n                so reg_all.state_vector() == tensor_product(reg_high.state_vector(),reg_low.state_vector()).\n                \n                Then applying a composite gate to reg_all would give you the same thing as\n                applying the lhs gate to reg_high and the rhs gate to reg_low and then appending \n                the two resulting registers.  So the lhs gate of a composite_gate applies to\n                the high order bits of a regitser and the rhs gate applies to the lower order bits.\n        !*/\n    public:\n\n        composite_gate (\n            const composite_gate& g\n        );\n        /*!\n            ensures\n                - *this is a copy of g\n        !*/\n\n        composite_gate(\n            const gate_exp<T>& lhs_, \n            const gate_exp<U>& rhs_\n        ): \n        /*!\n            ensures\n                - #lhs == lhs_.ref()\n                - #rhs == rhs_.ref()\n                - #num_bits == T::num_bits + U::num_bits\n                - #dims == 2^num_bits\n                - #&ref() == this\n        !*/\n\n        const qc_scalar_type operator() (\n            long r, \n            long c\n        ) const; \n        /*!\n            requires\n                - 0 <= r < dims\n                - 0 <= c < dims\n            ensures\n                - Let M denote the tensor product of lhs with rhs, then this function\n                  returns M(r,c)\n                  (i.e. returns lhs(r/U::dims,c/U::dims)*rhs(r%U::dims, c%U::dims))\n        !*/\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const;\n        /*!\n            requires\n                - reg.nr() == dims\n                - reg.nc() == 1\n                - 0 <= row_idx < dims\n            ensures\n                - Let M represent the matrix for this gate, then this function\n                  returns rowm(M*reg, row_idx)\n                  (i.e. returns the row_idx row of what you get when you apply this\n                  gate to the given column vector in reg)\n                - This function works by calling rhs.compute_state_element() and using elements\n                  of the matrix in lhs.  \n        !*/\n\n        static const long num_bits;\n        static const long dims;\n\n        const T lhs;\n        const U rhs;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <long bits>\n    class gate : public gate_exp<gate<bits> >\n    {\n        /*!\n            REQUIREMENTS ON bits\n                0 < bits <= 30\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a quantum gate that operates on bits qubits. \n                It stores its gate matrix explicitly in a dense in-memory matrix. \n        !*/\n\n    public:\n        gate(\n        );\n        /*!\n            ensures\n                - num_bits == bits\n                - dims == 2^bits\n                - #&ref() == this\n                - for all valid r and c:\n                    #(*this)(r,c) == 0\n        !*/\n\n        gate (\n            const gate& g\n        );\n        /*!\n            ensures\n                - *this is a copy of g\n        !*/\n\n        template <typename T>\n        explicit gate(\n            const gate_exp<T>& g\n        );\n        /*!\n            requires\n                - T::num_bits == num_bits\n            ensures\n                - num_bits == bits\n                - dims == 2^bits\n                - #&ref() == this\n                - for all valid r and c:\n                    #(*this)(r,c) == g(r,c)\n        !*/\n\n        const qc_scalar_type& operator() (\n            long r, \n            long c\n        ) const;\n        /*!\n            requires\n                - 0 <= r < dims\n                - 0 <= c < dims\n            ensures\n                - Let M denote the matrix for this gate, then this function\n                  returns a const reference to M(r,c)\n        !*/\n\n        qc_scalar_type& operator() (\n            long r, \n            long c\n        );\n        /*!\n            requires\n                - 0 <= r < dims\n                - 0 <= c < dims\n            ensures\n                - Let M denote the matrix for this gate, then this function \n                  returns a non-const reference to M(r,c)\n        !*/\n\n        template <typename exp>\n        qc_scalar_type compute_state_element (\n            const matrix_exp<exp>& reg,\n            long row_idx\n        ) const;\n        /*!\n            requires\n                - reg.nr() == dims\n                - reg.nc() == 1\n                - 0 <= row_idx < dims\n            ensures\n                - Let M represent the matrix for this gate, then this function\n                  returns rowm(M*reg, row_idx)\n                  (i.e. returns the row_idx row of what you get when you apply this\n                  gate to the given column vector in reg)\n        !*/\n\n        static const long num_bits;\n        static const long dims;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename U>\n    const composite_gate<T,U> operator, ( \n        const gate_exp<T>& lhs,\n        const gate_exp<U>& rhs\n    ) { return composite_gate<T,U>(lhs,rhs); }\n    /*!\n        ensures\n            - returns a composite_gate that represents the tensor product of the lhs\n              gate with the rhs gate.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    namespace quantum_gates\n    {\n\n        inline const gate<1> hadamard(\n        );\n        /*!\n            ensures\n                - returns the Hadamard gate.\n                  (i.e. A gate with a matrix of\n                                 |1, 1|\n                     1/sqrt(2) * |1,-1|   )\n        !*/\n\n        inline const gate<1> x(\n        );\n        /*!\n            ensures\n                - returns the not gate.\n                  (i.e. A gate with a matrix of\n                      |0, 1|\n                      |1, 0|   )\n        !*/\n\n        inline const gate<1> y(\n        );\n        /*!\n            ensures\n                - returns the y gate.\n                  (i.e. A gate with a matrix of\n                      |0,-i|\n                      |i, 0|   )\n        !*/\n\n        inline const gate<1> z(\n        );\n        /*!\n            ensures\n                - returns the z gate.\n                  (i.e. A gate with a matrix of\n                      |1, 0|\n                      |0,-1|   )\n        !*/\n\n        inline const gate<1> noop(\n        );\n        /*!\n            ensures\n                - returns the no-op or identity gate.\n                  (i.e. A gate with a matrix of\n                      |1, 0|\n                      |0, 1|   )\n        !*/\n\n        template <\n            int control_bit,\n            int target_bit\n            >\n        class cnot : public gate_exp<cnot<control_bit, target_bit> >\n        {\n            /*!\n                REQUIREMENTS ON control_bit AND target_bit\n                    - control_bit != target_bit\n\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents the controlled-not quantum gate.  It is a gate that\n                    operates on abs(control_bit-target_bit)+1 qubits.   \n\n                    In terms of the computational basis vectors, this gate maps input\n                    vectors to output vectors in the following way:\n                        - if (the input vector corresponds to a state where the control_bit\n                          qubit is 1) then\n                            - this gate outputs the computational basis vector that\n                              corresponds to the state where the target_bit has been flipped\n                              with respect to the input vector\n                        - else\n                            - this gate outputs the input vector unmodified\n\n            !*/\n        };\n\n        template <\n            int control_bit1,\n            int control_bit2,\n            int target_bit\n            >\n        class toffoli : public gate_exp<toffoli<control_bit1, control_bit2, target_bit> >\n        {\n            /*!\n                REQUIREMENTS ON control_bit1, control_bit2, AND target_bit\n                    - all the arguments denote different bits, i.e.:\n                        - control_bit1 != target_bit\n                        - control_bit2 != target_bit\n                        - control_bit1 != control_bit2\n                    - The target bit can't be in-between the control bits, i.e.:\n                        - (control_bit1 < target_bit && control_bit2 < target_bit) ||\n                          (control_bit1 > target_bit && control_bit2 > target_bit) \n\n                WHAT THIS OBJECT REPRESENTS\n                    This object represents the toffoli variant of a controlled-not quantum gate.  \n                    It is a gate that operates on max(abs(control_bit2-target_bit),abs(control_bit1-target_bit))+1 \n                    qubits.   \n\n                    In terms of the computational basis vectors, this gate maps input\n                    vectors to output vectors in the following way:\n                        - if (the input vector corresponds to a state where the control_bit1 and\n                          control_bit2 qubits are 1) then\n                            - this gate outputs the computational basis vector that\n                              corresponds to the state where the target_bit has been flipped\n                              with respect to the input vector\n                        - else\n                            - this gate outputs the input vector unmodified\n\n            !*/\n        };\n\n    // ------------------------------------------------------------------------------------\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUANTUM_COMPUTINg_ABSTRACT_\n\n\n\n"
  },
  {
    "path": "dlib/quantum_computing.h",
    "content": "// Copyright (C) 2008  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUANTUM_COMPUTINg_H_\n#define DLIB_QUANTUM_COMPUTINg_H_ \n\n#include \"quantum_computing/quantum_computing.h\"\n\n#endif // DLIB_QUANTUM_COMPUTINg_H_ \n\n\n\n\n"
  },
  {
    "path": "dlib/queue/queue_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUEUE_KERNEl_1_\n#define DLIB_QUEUE_KERNEl_1_\n\n#include \"queue_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class queue_kernel_1 : public enumerable<T>,\n                           public remover<T>\n    {\n\n        /*!\n            INITIAL VALUE\n                queue_size == 0   \n                current_element == 0\n                at_start_ == true\n            \n            CONVENTION\n                queue_size == the number of elements in the queue\n                at_start() == at_start_\n                current_element_valid() == (current_element != 0)\n                element() == current_element->item\n\n                if (queue_size > 0)\n                {\n                    in points to the last element to be inserted into the queue\n                    out points to the next element to be dequeued\n\n                    each node points to the node inserted after it except for the most \n                    recently inserted node\n\n                    current_element == 0\n                }\n                \n        !*/\n\n\n        struct node\n        {\n            node* last;\n\n            T item;\n        };\n\n\n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            queue_kernel_1 (\n            ) :\n                in(0),\n                out(0),\n                queue_size(0),\n                current_element(0),\n                at_start_(true)\n            {\n            }\n\n            virtual ~queue_kernel_1 (\n            ); \n\n            inline void clear(\n            );\n\n            void enqueue (\n                T& item\n            );\n\n            void dequeue (\n                T& item\n            );\n\n            void cat (\n                queue_kernel_1& item\n            );\n\n            T& current (\n            );\n\n            const T& current (\n            ) const;\n            \n            void swap (\n                queue_kernel_1& item\n            );\n\n            // functions from the remover interface\n            inline void remove_any (\n                T& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            inline const T& element (\n            ) const;\n\n            inline T& element (\n            );\n\n            bool move_next (\n            ) const;\n\n        private:\n\n            void delete_nodes (\n                node* start,\n                unsigned long length\n            );\n            /*!\n                requires\n                    - start points to a node in a singly linked list \n                    - start->last points to the next node in the list \n                    - there are at least length nodes in the list beginning with start\n                ensures\n                    - length nodes have been deleted starting with the node pointed \n                      to by start\n            !*/\n\n            // data members\n\n            node* in;\n            node* out;\n            unsigned long queue_size;\n            mutable node* current_element;\n            mutable bool at_start_;\n\n            // restricted functions\n            queue_kernel_1(queue_kernel_1&);        // copy constructor\n            queue_kernel_1& operator=(queue_kernel_1&);    // assignment operator\n\n    };\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        queue_kernel_1<T,mem_manager>& a, \n        queue_kernel_1<T,mem_manager>& b \n    ) { a.swap(b); } \n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        queue_kernel_1<T,mem_manager>& item,  \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            T temp;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(temp,in);\n                item.enqueue(temp);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type queue_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    queue_kernel_1<T,mem_manager>::\n    ~queue_kernel_1 (\n    )\n    {\n        delete_nodes(out,queue_size);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    clear (\n    )\n    {\n        delete_nodes(out,queue_size);\n        queue_size = 0;\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    enqueue (\n        T& item\n    )\n    {\n        // make new node\n        node* temp = new node;\n\n        // swap item into new node\n        exchange(item,temp->item);\n        \n        if (queue_size == 0)\n            out = temp;\n        else\n            in->last = temp;\n\n        // make in point to the new node\n        in = temp;\n        \n        ++queue_size;\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    dequeue (\n        T& item\n    )\n    {\n        // swap out into item\n        exchange(item,out->item);\n\n        --queue_size;\n\n        if (queue_size == 0)\n        {\n            delete out;\n        }\n        else\n        {\n            node* temp = out;\n            \n            // move out pointer to the next element in the queue\n            out = out->last;\n\n            // delete old node\n            delete temp;\n        }\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    cat (\n        queue_kernel_1<T,mem_manager>& item\n    )\n    {\n        if (item.queue_size > 0)\n        {\n            if (queue_size > 0)\n            {\n                in->last = item.out;\n            }\n            else\n            {\n                out = item.out;\n            }\n\n\n            in = item.in;\n            queue_size += item.queue_size;\n            item.queue_size = 0;\n        }\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& queue_kernel_1<T,mem_manager>::\n    current (\n    )\n    {\n        return out->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& queue_kernel_1<T,mem_manager>::\n    current (\n    ) const\n    {\n        return out->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    swap (\n        queue_kernel_1<T,mem_manager>& item\n    )\n    {\n        node* in_temp = in;\n        node* out_temp = out;\n        unsigned long queue_size_temp = queue_size;\n        node* current_element_temp = current_element;\n        bool at_start_temp = at_start_;\n\n        in = item.in;\n        out = item.out;\n        queue_size = item.queue_size;\n        current_element = item.current_element;\n        at_start_ = item.at_start_;\n\n        item.in = in_temp;\n        item.out = out_temp;\n        item.queue_size = queue_size_temp;\n        item.current_element = current_element_temp;\n        item.at_start_ = at_start_temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool queue_kernel_1<T,mem_manager>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    size_t queue_kernel_1<T,mem_manager>::\n    size (\n    ) const\n    {\n        return queue_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool queue_kernel_1<T,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& queue_kernel_1<T,mem_manager>::\n    element (\n    ) const\n    {\n        return current_element->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& queue_kernel_1<T,mem_manager>::\n    element (\n    )\n    {\n        return current_element->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool queue_kernel_1<T,mem_manager>::\n    move_next (\n    ) const\n    {\n        if (at_start_)\n        {\n            at_start_ = false;\n            // if the queue is empty then there is nothing to do\n            if (queue_size == 0)\n            {\n                return false;\n            }\n            else\n            {\n                current_element = out;\n                return true;\n            }\n        }\n        else\n        {\n            // if we are at the last element then the enumeration has finished\n            if (current_element == in || current_element == 0)\n            {\n                current_element = 0;\n                return false;\n            }\n            else\n            {\n                current_element = current_element->last;\n                return true;\n            }           \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // remover function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    remove_any (\n        T& item\n    ) \n    {\n        dequeue(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void queue_kernel_1<T,mem_manager>::\n    delete_nodes (\n        node* start,\n        unsigned long length\n    )\n    {\n        node* temp;\n        while (length)\n        {\n            temp = start->last;\n            delete start;\n            start = temp;\n            --length;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUEUE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/queue/queue_kernel_2.h",
    "content": "// Copyright (C) 2004  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUEUE_KERNEl_2_\n#define DLIB_QUEUE_KERNEl_2_\n\n#include \"queue_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager = default_memory_manager\n        >\n    class queue_kernel_2 : public enumerable<T>,\n                           public remover<T>\n    {\n\n        /*!\n            REQUIREMENTS ON block_size\n                0 < block_size < 2000000000\n\n            INITIAL VALUE\n                queue_size == 0   \n                current_element == 0\n                at_start_ == true\n            \n            CONVENTION\n                queue_size == the number of elements in the queue\n                at_start() == at_start_\n                current_element_valid() == (current_element != 0)\n                if (current_element_valid()) then\n                    element() == current_element->item[current_element_pos]\n\n                if (queue_size > 0)                \n                {                    \n                    in->item[in_pos] == the spot where we will put the next item added\n                                        into the queue\n                    out->item[out_pos] == current()\n\n                    when enqueuing elements inside each node item[0] is filled first, then \n                    item[1], then item[2], etc.\n                                                         \n\n                    each node points to the node inserted after it except for the most \n                    recently inserted node.  \n                }\n                \n        !*/\n\n\n        struct node\n        {\n            node* next;\n\n            T item[block_size];\n        };\n\n        \n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            queue_kernel_2 (\n            ) :\n                in(0),\n                out(0),\n                queue_size(0),\n                current_element(0),\n                at_start_(true)\n            {\n            }\n\n            virtual ~queue_kernel_2 (\n            ); \n\n            inline void clear(\n            );\n\n            void enqueue (\n                T& item\n            );\n\n            void dequeue (\n                T& item\n            );\n\n            void cat (\n                queue_kernel_2& item\n            );\n\n            T& current (\n            );\n\n            const T& current (\n            ) const;            \n\n            void swap (\n                queue_kernel_2& item\n            );\n\n            // functions from the remover interface\n            inline void remove_any (\n                T& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            inline bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            inline const T& element (\n            ) const;\n\n            inline T& element (\n            );\n\n            bool move_next (\n            ) const;\n\n        private:\n\n            void delete_nodes (\n                node* start,\n                node* end\n            );\n            /*!\n                requires\n                    - start points to a node in a singly linked list \n                    - start->next points to the next node in the list \n                    - by following the next pointers you eventually hit the node pointed\n                      to by end\n                ensures\n                    - calls delete on the start node, the end node, and all nodes in between\n            !*/\n\n            // data members\n\n            typename mem_manager::template rebind<node>::other pool; \n\n            node* in;\n            node* out;\n            size_t queue_size;\n            size_t in_pos;\n            size_t out_pos;\n\n\n            mutable node* current_element;\n            mutable size_t current_element_pos;\n            mutable bool at_start_;\n\n            // restricted functions\n            queue_kernel_2(queue_kernel_2&);        // copy constructor\n            queue_kernel_2& operator=(queue_kernel_2&);    // assignment operator\n\n    };\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    inline void swap (\n        queue_kernel_2<T,block_size,mem_manager>& a, \n        queue_kernel_2<T,block_size,mem_manager>& b \n    ) { a.swap(b); } \n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void deserialize (\n        queue_kernel_2<T,block_size,mem_manager>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            T temp;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(temp,in);\n                item.enqueue(temp);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type queue_kernel_2\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    queue_kernel_2<T,block_size,mem_manager>::\n    ~queue_kernel_2 (\n    )\n    {\n        COMPILE_TIME_ASSERT(0 < block_size && block_size < (unsigned long)(2000000000));\n\n        if (queue_size > 0)\n            delete_nodes(out,in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    clear (\n    )\n    {\n        if (queue_size > 0)\n        {\n            delete_nodes(out,in);\n            queue_size = 0;\n        }\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    enqueue (\n        T& item\n    )\n    {\n        if (queue_size == 0)\n        {\n            out = in = pool.allocate();\n            in_pos = 0;\n            out_pos = 0;\n        }\n        else if (in_pos >= block_size)\n        {            \n            in->next = pool.allocate();\n            in_pos = 0;\n            in = in->next;\n        }\n\n        exchange(item,in->item[in_pos]);\n        ++in_pos;\n\n        ++queue_size;\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    dequeue (\n        T& item\n    )\n    {\n        // swap out into item\n        exchange(item,out->item[out_pos]);\n        \n        ++out_pos;\n        --queue_size;\n\n        // if this was the last element in this node then remove this node\n        if (out_pos == block_size)\n        {\n            out_pos = 0;\n            node* temp = out;\n            out = out->next;\n            pool.deallocate(temp);\n        }\n        else if (queue_size == 0)\n        {\n            pool.deallocate(out);\n        }\n\n        // put the enumerator at the start\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    cat (\n        queue_kernel_2<T,block_size,mem_manager>& item\n    )\n    {\n        if (queue_size > 0)\n        {\n            T temp;\n            assign_zero_if_built_in_scalar_type(temp);\n            while (item.size() > 0)\n            {\n                item.dequeue(temp);\n                enqueue(temp);\n            }\n        }\n        else\n        {\n            in = item.in;\n            out = item.out;\n            out_pos = item.out_pos;\n            in_pos = item.in_pos;\n\n            queue_size = item.queue_size;\n            item.queue_size = 0;\n\n            // put the enumerator at the start\n            reset();\n        }       \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    T& queue_kernel_2<T,block_size,mem_manager>::\n    current (\n    )\n    {\n        return out->item[out_pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    const T& queue_kernel_2<T,block_size,mem_manager>::\n    current (\n    ) const\n    {\n        return out->item[out_pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    swap (\n        queue_kernel_2<T,block_size,mem_manager>& item\n    )\n    {\n        exchange(in,item.in);\n        exchange(out,item.out);\n        exchange(queue_size,item.queue_size);\n        exchange(in_pos,item.in_pos);\n        exchange(out_pos,item.out_pos);\n        exchange(current_element,item.current_element);\n        exchange(current_element_pos,item.current_element_pos);\n        exchange(at_start_,item.at_start_);        \n        pool.swap(item.pool);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    size_t queue_kernel_2<T,block_size,mem_manager>::\n    size (\n    ) const\n    {\n        return queue_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    bool queue_kernel_2<T,block_size,mem_manager>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    bool queue_kernel_2<T,block_size,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    const T& queue_kernel_2<T,block_size,mem_manager>::\n    element (\n    ) const\n    {\n        return current_element->item[current_element_pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    T& queue_kernel_2<T,block_size,mem_manager>::\n    element (\n    )\n    {\n        return current_element->item[current_element_pos];\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    bool queue_kernel_2<T,block_size,mem_manager>::\n    move_next (\n    ) const\n    {\n        if (at_start_)\n        {\n            at_start_ = false;\n            // if the queue is empty then there is nothing to do\n            if (queue_size == 0)\n            {\n                return false;\n            }\n            else\n            {\n                current_element = out;\n                current_element_pos = out_pos;\n                return true;\n            }\n        }\n        else if (current_element == 0)\n        {\n            return false;\n        }\n        else\n        {\n            ++current_element_pos;\n            // if we are at the last element then the enumeration has finished\n            if (current_element == in && current_element_pos == in_pos )\n            {\n                current_element = 0;\n                return false;\n            }\n            else if (current_element_pos == block_size)\n            {\n                current_element_pos = 0;\n                current_element = current_element->next;               \n            }           \n\n            return true;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // remover function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    remove_any (\n        T& item\n    ) \n    {\n        dequeue(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        unsigned long block_size,\n        typename mem_manager\n        >\n    void queue_kernel_2<T,block_size,mem_manager>::\n    delete_nodes (\n        node* start,\n        node* end\n    )\n    {\n        node* temp;\n        while (start != end)\n        {\n            temp = start;\n            start = start->next;\n            pool.deallocate(temp);\n        }\n        pool.deallocate(start);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUEUE_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/queue/queue_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_QUEUE_KERNEl_ABSTRACT_\n#ifdef DLIB_QUEUE_KERNEl_ABSTRACT_\n\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class queue : public enumerable<T>,\n                  public remover<T>\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must be swappable by a global swap() \n                T must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap() and current() functions do not invalidate pointers or \n                references to internal data.\n                All other functions have no such guarantee.\n\n            INITIAL VALUE\n                size() == 0    \n\n            ENUMERATION ORDER\n                The enumerator will iterate over the elements in the queue in the\n                same order they would be removed by repeated calls to dequeue().\n                (e.g. current() would be the first element enumerated)\n\n            WHAT THIS OBJECT REPRESENTS\n                This is a first in first out queue containing items of type T\n                \n                e.g. if the queue is {b,c,d,e} and then 'a' is enqueued\n                the queue becomes {a,b,c,d,e} and then calling dequeue takes e out\n                making the queue {a,b,c,d}\n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n        !*/\n        \n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            queue (\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            virtual ~queue (\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void enqueue (\n                T& item\n            );\n            /*!\n                ensures\n                    - item is now at the left end of #*this  \n                    - #item has an initial value for its type \n                    - #size() == size() + 1\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if enqueue() throws then it has no effect\n            !*/\n\n            void dequeue (\n                T& item\n            );\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - #size() == size() - 1\n                    - the far right element of *this has been removed and swapped \n                      into #item \n                    - #at_start() == true\n            !*/\n\n            void cat (\n                queue& item\n            );\n            /*!\n                ensures\n                    - item has been concatenated onto the left end of *this. \n                      i.e. item.current() is attached onto the left end of *this and\n                      the left most element in item will also be the left most item \n                      in #*this \n                    - #size() == size() + item.size() \n                    - #item has its initial value \n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if cat() throws then the state of #item and *this is undefined\n                        until clear() is successfully called on them.\n            !*/\n\n            T& current (\n            );\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - returns a const reference to the next element to be dequeued.\n                      i.e.  the right most element.\n            !*/\n\n            const T& current (\n            ) const;\n            /*!\n                requires\n                    - size() != 0\n                ensures\n                    - returns a non-const reference to the next element to be dequeued.\n                      i.e.  the right most element.\n            !*/\n            \n            void swap (\n                queue& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n        private:\n\n            // restricted functions\n            queue(queue&);        // copy constructor\n            queue& operator=(queue&);    // assignment operator\n\n    };\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        queue<T,mem_manager>& a, \n        queue<T,mem_manager>& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        queue<T,mem_manager>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_QUEUE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/queue/queue_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUEUE_KERNEl_C_\n#define DLIB_QUEUE_KERNEl_C_\n\n#include \"queue_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n\n    template <\n        typename queue_base // is an implementation of queue_kernel_abstract.h\n        >\n    class queue_kernel_c : public queue_base\n    {\n        typedef typename queue_base::type T;\n\n        public:\n\n            void dequeue (\n                T& item\n            );\n\n            T& current (\n            );\n\n            const T& current (\n            ) const;\n\n            const T& element (\n            ) const;\n\n            T& element (\n            );\n\n            void remove_any (\n                T& item\n            );\n\n    };\n\n    template <\n        typename queue_base\n        >\n    inline void swap (\n        queue_kernel_c<queue_base>& a, \n        queue_kernel_c<queue_base>& b \n    ) { a.swap(b); }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    void queue_kernel_c<queue_base>::\n    dequeue (\n        T& item\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->size() != 0,\n            \"\\tvoid queue::dequeue\"\n            << \"\\n\\tsize of queue should not be zero\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        queue_base::dequeue(item);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    const typename queue_base::type& queue_kernel_c<queue_base>::\n    current (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->size() != 0,\n            \"\\tconst T& queue::current\"\n            << \"\\n\\tsize of queue should not be zero\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return queue_base::current();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    typename queue_base::type& queue_kernel_c<queue_base>::\n    current (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->size() != 0,\n            \"\\tT& queue::current\"\n            << \"\\n\\tsize of queue should not be zero\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return queue_base::current();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    const typename queue_base::type& queue_kernel_c<queue_base>::\n    element (\n    ) const\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tconst T& queue::element\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return queue_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    typename queue_base::type& queue_kernel_c<queue_base>::\n    element (\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(this->current_element_valid() == true,\n            \"\\tT& queue::element\"\n            << \"\\n\\tyou can't access the current element if it doesn't exist\"\n            << \"\\n\\tthis: \" << this\n            );\n\n        // call the real function\n        return queue_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    void queue_kernel_c<queue_base>::\n    remove_any (\n        T& item\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->size() > 0),\n            \"\\tvoid queue::remove_any\"\n            << \"\\n\\tsize() must be greater than zero if something is going to be removed\"\n            << \"\\n\\tsize(): \" << this->size() \n            << \"\\n\\tthis:   \" << this\n            );\n\n        // call the real function\n        queue_base::remove_any(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUEUE_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/queue/queue_sort_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUEUE_SORt_1_\n#define DLIB_QUEUE_SORt_1_\n\n#include \"queue_sort_abstract.h\"\n#include \"../algs.h\"\n#include <vector>\n#include \"../sort.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename queue_base \n        >\n    class queue_sort_1 : public queue_base\n    {\n        typedef typename queue_base::type T;\n\n        public:\n\n            /*!\n                This implementation uses the QuickSort algorithm and\n                when the quicksort depth goes too high it uses the dlib::qsort_array()\n                function on the data.\n            !*/\n\n            void sort (\n            );\n\n            template <typename compare_type>\n            void sort (\n                const compare_type& compare\n            )\n            {\n                if (this->size() > 1)\n                {\n                    sort_this_queue(*this,0,compare);\n                }\n            }\n\n        private:\n\n            template <typename compare_type>\n            void sort_this_queue (\n                queue_base& queue,\n                long depth,\n                const compare_type& compare\n            )\n            /*!\n                ensures\n                    each element in the queue is < the element behind it according\n                    to compare\n            !*/\n            {\n                if (queue.size() <= 1)\n                {\n                    // already sorted\n                }\n                else if (queue.size() <= 29)\n                {\n                    T vect[29];\n                    const unsigned long size = queue.size();\n                    for (unsigned long i = 0; i < size; ++i)\n                    {\n                        queue.dequeue(vect[i]);\n                    }\n                    isort_array(vect,0,size-1,compare);\n                    for (unsigned long i = 0; i < size; ++i)\n                    {\n                        queue.enqueue(vect[i]);\n                    }\n                }\n                else if (depth > 50)\n                {\n                    std::vector<T> vect(queue.size());\n                    for (unsigned long i = 0; i < vect.size(); ++i)\n                    {\n                        queue.dequeue(vect[i]);\n                    }\n                    hsort_array(vect,0,vect.size()-1,compare);\n                    for (unsigned long i = 0; i < vect.size(); ++i)\n                    {\n                        queue.enqueue(vect[i]);\n                    }\n                }\n                else\n                {\n                    queue_base left, right;\n                    T partition_element;\n                    T temp;\n                    // do this just to avoid a compiler warning\n                    assign_zero_if_built_in_scalar_type(temp);\n                    assign_zero_if_built_in_scalar_type(partition_element);\n\n                    queue.dequeue(partition_element);\n\n                    // partition queue into left and right\n                    while (queue.size() > 0)\n                    {\n                        queue.dequeue(temp);\n                        if (compare(temp , partition_element))\n                        {\n                            left.enqueue(temp);\n                        }\n                        else\n                        {\n                            right.enqueue(temp);\n                        }\n                    }\n\n\n                    long ratio;\n                    if (left.size() > right.size())\n                        ratio = left.size()/(right.size()+1);  // add 1 so we can't divide by zero\n                    else\n                        ratio = right.size()/(left.size()+1);\n\n                    sort_this_queue(left,ratio+depth,compare);\n                    sort_this_queue(right,ratio+depth,compare);\n\n                    // combine the two queues\n                    left.swap(queue);\n                    queue.enqueue(partition_element);\n                    queue.cat(right);\n                }\n            }\n\n\n    };\n\n    template <\n        typename queue_base\n        >\n    inline void swap (\n        queue_sort_1<queue_base>& a, \n        queue_sort_1<queue_base>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename queue_base\n        >\n    void queue_sort_1<queue_base>::\n    sort (\n    )\n    {\n        if (this->size() > 1)\n        {\n            sort_this_queue(*this,0,std::less<typename queue_base::type>());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_QUEUE_SORt_1_\n\n"
  },
  {
    "path": "dlib/queue/queue_sort_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_QUEUE_SORt_ABSTRACT_\n#ifdef DLIB_QUEUE_SORt_ABSTRACT_\n\n\n#include \"queue_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename queue_base\n        >\n    class queue_sort : public queue_base\n    {\n\n        /*!\n            REQUIREMENTS ON QUEUE_BASE\n                - is an implementation of queue/queue_kernel_abstract.h\n                - queue_base::type must be a type with that is comparable via operator<\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                sort() may invalidate pointers and references to internal data.\n\n            WHAT THIS EXTENSION DOES FOR QUEUE\n                This gives a queue the ability to sort its contents by calling sort().\n        !*/\n\n\n        public:\n\n            void sort (\n            );\n            /*!\n                ensures\n                    - for all elements in #*this the ith element is <= the i+1 element\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        data may be lost if sort() throws\n            !*/\n\n            template <typename compare_type>\n            void sort (\n                const compare_type& compare\n            );\n            /*!\n                ensures\n                    - for all elements in #*this the ith element is <= the i+1 element\n                    - uses compare(a,b) as the < operator.  So if compare(a,b) == true\n                      then a comes before b in the resulting ordering.  \n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        data may be lost if sort() throws\n            !*/\n    };\n\n    template <\n        template queue_base\n        >\n    inline void swap (\n        queue_sort<queue_base>& a, \n        queue_sort<queue_base>& b \n    ) { a.swap(b); }  \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_QUEUE_SORt_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/queue.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_QUEUe_\n#define DLIB_QUEUe_\n\n#include \"queue/queue_kernel_1.h\"\n#include \"queue/queue_kernel_2.h\"\n#include \"queue/queue_kernel_c.h\"\n\n#include \"queue/queue_sort_1.h\"\n\n\n#include \"algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager \n        >\n    class queue\n    {\n        queue() {}\n    public:\n                \n\n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     queue_kernel_1<T,mem_manager>    \n                    kernel_1a;\n        typedef     queue_kernel_c<kernel_1a>\n                    kernel_1a_c;\n \n\n        // kernel_2a        \n        typedef     queue_kernel_2<T,20,mem_manager>    \n                    kernel_2a;\n        typedef     queue_kernel_c<kernel_2a>\n                    kernel_2a_c;\n\n\n        // kernel_2b        \n        typedef     queue_kernel_2<T,100,mem_manager>    \n                    kernel_2b;\n        typedef     queue_kernel_c<kernel_2b>\n                    kernel_2b_c;\n\n\n\n\n        //---------- extensions ------------\n\n        // sort_1 extend kernel_1a\n        typedef     queue_sort_1<kernel_1a>\n                    sort_1a;\n        typedef     queue_sort_1<kernel_1a_c>\n                    sort_1a_c;\n\n\n        // sort_1 extend kernel_2a\n        typedef     queue_sort_1<kernel_2a>\n                    sort_1b;\n        typedef     queue_sort_1<kernel_2a_c>\n                    sort_1b_c;\n\n\n\n        // sort_1 extend kernel_2b\n        typedef     queue_sort_1<kernel_2b>\n                    sort_1c;\n        typedef     queue_sort_1<kernel_2b_c>\n                    sort_1c_c;\n\n\n\n\n\n    };\n}\n\n#endif // DLIB_QUEUe_\n\n"
  },
  {
    "path": "dlib/rand/mersenne_twister.h",
    "content": "/* boost random/mersenne_twister.hpp header file\n *\n * Copyright Jens Maurer 2000-2001\n * Distributed under the Boost Software License, Version 1.0. (See\n * accompanying file LICENSE_1_0.txt or copy at\n * http://www.boost.org/LICENSE_1_0.txt)\n *\n * See http://www.boost.org for most recent version including documentation.\n *\n * $Id: mersenne_twister.hpp,v 1.20 2005/07/21 22:04:31 jmaurer Exp $\n *\n * Revision history\n *  2001-02-18  moved to individual header files\n*/\n\n#ifndef DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP\n#define DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP\n\n#include <iostream>\n#include <algorithm>     // std::copy\n#include <stdexcept>\n#include \"../uintn.h\"\n#include \"../serialize.h\"\n\nnamespace dlib \n{\n    namespace random_helpers \n    {\n\n    // ------------------------------------------------------------------------------------\n\n        // http://www.math.keio.ac.jp/matumoto/emt.html\n        template<\n            class UIntType, \n            int w, \n            int n,\n            int m,\n            int r,\n            UIntType a,\n            int u,\n            int s,\n            UIntType b,\n            int t,\n            UIntType c,\n            int l,\n            UIntType val\n            >\n        class mersenne_twister\n        {\n        public:\n            typedef UIntType result_type;\n            const static int word_size = w;\n            const static int state_size = n;\n            const static int shift_size = m;\n            const static int mask_bits = r;\n            const static UIntType parameter_a = a;\n            const static int output_u = u;\n            const static int output_s = s;\n            const static UIntType output_b = b;\n            const static int output_t = t;\n            const static UIntType output_c = c;\n            const static int output_l = l;\n\n            const static bool has_fixed_range = false;\n\n            mersenne_twister() { seed(); }\n\n            explicit mersenne_twister(UIntType value) { seed(value); }\n\n            void seed () { seed(UIntType(5489)); }\n\n            // compiler-generated copy ctor and assignment operator are fine\n\n            void seed(UIntType value)\n            {\n                // New seeding algorithm from \n                // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html\n                // In the previous versions, MSBs of the seed affected only MSBs of the\n                // state x[].\n                const UIntType mask = ~0u;\n                x[0] = value & mask;\n                for (i = 1; i < n; i++) {\n                    // See Knuth \"The Art of Computer Programming\" Vol. 2, 3rd ed., page 106\n                    x[i] = (1812433253UL * (x[i-1] ^ (x[i-1] >> (w-2))) + i) & mask;\n                }\n            }\n\n            result_type min() const { return 0; }\n            result_type max() const\n            {\n                // avoid \"left shift count >= with of type\" warning\n                result_type res = 0;\n                for(int i = 0; i < w; ++i)\n                    res |= (1u << i);\n                return res;\n            }\n\n            result_type operator()();\n\n            friend void serialize(\n                const mersenne_twister& item, \n                std::ostream& out\n            )\n            {\n                dlib::serialize(item.x, out);\n                dlib::serialize(item.i, out);\n            }\n\n            friend void deserialize(\n                mersenne_twister& item, \n                std::istream& in \n            )\n            {\n                dlib::deserialize(item.x, in);\n                dlib::deserialize(item.i, in);\n            }\n\n        private:\n\n            void twist(int block);\n\n            // state representation: next output is o(x(i))\n            //   x[0]  ... x[k] x[k+1] ... x[n-1]     x[n]     ... x[2*n-1]   represents\n            //  x(i-k) ... x(i) x(i+1) ... x(i-k+n-1) x(i-k-n) ... x[i(i-k-1)]\n            // The goal is to always have x(i-n) ... x(i-1) available for\n            // operator== and save/restore.\n\n            UIntType x[2*n]; \n            int i;\n        };\n\n    // ------------------------------------------------------------------------------------\n\n        template<\n            class UIntType, int w, int n, int m, int r, UIntType a, int u,\n            int s, UIntType b, int t, UIntType c, int l, UIntType val\n            >\n        void mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::twist(\n            int block\n        )\n        {\n            const UIntType upper_mask = (~0u) << r;\n            const UIntType lower_mask = ~upper_mask;\n\n            if(block == 0) {\n                for(int j = n; j < 2*n; j++) {\n                    UIntType y = (x[j-n] & upper_mask) | (x[j-(n-1)] & lower_mask);\n                    x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);\n                }\n            } else if (block == 1) {\n                // split loop to avoid costly modulo operations\n                {  // extra scope for MSVC brokenness w.r.t. for scope\n                    for(int j = 0; j < n-m; j++) {\n                        UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);\n                        x[j] = x[j+n+m] ^ (y >> 1) ^ (y&1 ? a : 0);\n                    }\n                }\n\n                for(int j = n-m; j < n-1; j++) {\n                    UIntType y = (x[j+n] & upper_mask) | (x[j+n+1] & lower_mask);\n                    x[j] = x[j-(n-m)] ^ (y >> 1) ^ (y&1 ? a : 0);\n                }\n                // last iteration\n                UIntType y = (x[2*n-1] & upper_mask) | (x[0] & lower_mask);\n                x[n-1] = x[m-1] ^ (y >> 1) ^ (y&1 ? a : 0);\n                i = 0;\n            }\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template<\n            class UIntType, int w, int n, int m, int r, UIntType a, int u,\n            int s, UIntType b, int t, UIntType c, int l, UIntType val\n            >\n        inline typename mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::result_type\n        mersenne_twister<UIntType,w,n,m,r,a,u,s,b,t,c,l,val>::operator()(\n        )\n        {\n            if(i == n)\n                twist(0);\n            else if(i >= 2*n)\n                twist(1);\n            // Step 4\n            UIntType z = x[i];\n            ++i;\n            z ^= (z >> u);\n            z ^= ((z << s) & b);\n            z ^= ((z << t) & c);\n            z ^= (z >> l);\n            return z;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n    } // namespace random\n\n\n    typedef random_helpers::mersenne_twister<uint32,32,351,175,19,0xccab8ee7,11,\n    7,0x31b6ab00,15,0xffe50000,17, 0xa37d3c92> mt11213b;\n\n    // validation by experiment from mt19937.c\n    typedef random_helpers::mersenne_twister<uint32,32,624,397,31,0x9908b0df,11,\n    7,0x9d2c5680,15,0xefc60000,18, 3346425566U> mt19937;\n\n} // namespace dlib \n\n\n#endif // DLIB_BOOST_RANDOM_MERSENNE_TWISTER_HPP\n\n"
  },
  {
    "path": "dlib/rand/rand_kernel_1.h",
    "content": "// Copyright (C) 2007  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RAND_KERNEl_1_\n#define DLIB_RAND_KERNEl_1_\n\n#include <string>\n#include <complex>\n#include \"../algs.h\"\n#include \"rand_kernel_abstract.h\"\n#include \"mersenne_twister.h\"\n#include \"../is_kind.h\"\n#include <iostream>\n#include \"../serialize.h\"\n#include \"../string.h\"\n\nnamespace dlib\n{\n\n\n    class rand\n    {\n\n        /*!       \n            INITIAL VALUE\n                - seed == \"\"\n\n            CONVENTION\n                - the random numbers come from the boost mersenne_twister code\n                - get_seed() == seed\n        !*/\n        \n        public:\n\n            // These typedefs are here for backwards compatibility with older versions of dlib.\n            typedef rand kernel_1a;\n            typedef rand float_1a;\n\n            rand(\n            ) \n            {\n                init();\n            }\n\n            rand (\n                time_t seed_value\n            )\n            {\n                init();\n                set_seed(cast_to_string(seed_value));\n            }\n\n            rand (\n                const std::string& seed_value\n            )\n            {\n                init();\n                set_seed(seed_value);\n            }\n\n            virtual ~rand(\n            )\n            {}\n\n            void clear(\n            )\n            {\n                mt.seed();\n                seed.clear();\n\n                has_gaussian = false;\n                next_gaussian = 0;\n\n                // prime the generator a bit\n                for (int i = 0; i < 10000; ++i)\n                    mt();\n            }\n \n            const std::string& get_seed (\n            )\n            {\n                return seed;\n            }\n\n            void set_seed (\n                const std::string& value\n            )\n            {\n                seed = value;\n\n                // make sure we do the seeding so that using a seed of \"\" gives the same\n                // state as calling this->clear()\n                if (value.size() != 0)\n                {\n                    uint32 s = 0;\n                    for (std::string::size_type i = 0; i < seed.size(); ++i)\n                    {\n                        s = (s*37) + static_cast<uint32>(seed[i]);\n                    }\n                    mt.seed(s);\n                }\n                else\n                {\n                    mt.seed();\n                }\n\n                // prime the generator a bit\n                for (int i = 0; i < 10000; ++i)\n                    mt();\n\n\n                has_gaussian = false;\n                next_gaussian = 0;\n            }\n\n            unsigned char get_random_8bit_number (\n            )\n            {\n                return static_cast<unsigned char>(mt());\n            }\n\n            uint16 get_random_16bit_number (\n            )\n            {\n                return static_cast<uint16>(mt());\n            }\n\n            inline uint32 get_random_32bit_number (\n            )\n            {\n                return mt();\n            }\n\n            inline uint64 get_random_64bit_number (\n            )\n            {\n                const uint64 a = get_random_32bit_number();\n                const uint64 b = get_random_32bit_number();\n                return (a<<32)|b;\n            }\n\n            double get_double_in_range (\n                double begin,\n                double end\n            )\n            {\n                DLIB_ASSERT(begin <= end);\n                return begin + get_random_double()*(end-begin);\n            }\n\n            long long get_integer_in_range(\n                long long begin,\n                long long end\n            )\n            {\n                DLIB_ASSERT(begin <= end);\n                if (begin == end)\n                    return begin;\n\n                auto r = get_random_64bit_number();\n                const auto limit = std::numeric_limits<decltype(r)>::max();\n                const auto range = end-begin;\n                // Use rejection sampling to remove the biased sampling you would get with\n                // the naive get_random_64bit_number()%range sampling. \n                while(r >= (limit/range)*range)\n                    r = get_random_64bit_number();\n\n                return begin + static_cast<long long>(r%range);\n            }\n\n            long long get_integer(\n                long long end\n            )\n            {\n                DLIB_ASSERT(end >= 0);\n\n                return get_integer_in_range(0,end);\n            }\n\n            double get_random_double (\n            )\n            {\n                uint32 temp;\n\n                temp = rand::get_random_32bit_number();\n                temp &= 0xFFFFFF;\n\n                double val = static_cast<double>(temp);\n\n                val *= 0x1000000;\n\n                temp = rand::get_random_32bit_number();\n                temp &= 0xFFFFFF;\n\n                val += temp;\n\n                val /= max_val;\n\n                if (val < 1.0)\n                {\n                    return val;\n                }\n                else\n                {\n                    // return a value slightly less than 1.0\n                    return 1.0 - std::numeric_limits<double>::epsilon();\n                }\n            }\n\n            float get_random_float (\n            )\n            {\n                uint32 temp;\n\n                temp = rand::get_random_32bit_number();\n                temp &= 0xFFFFFF;\n\n                const float scale = 1.0/0x1000000;\n\n                const float val = static_cast<float>(temp)*scale;\n                if (val < 1.0f)\n                {\n                    return val;\n                }\n                else\n                {\n                    // return a value slightly less than 1.0\n                    return 1.0f - std::numeric_limits<float>::epsilon();\n                }\n            }\n  \n            std::complex<double> get_random_complex_gaussian (\n            )\n            {\n                double x1, x2, w;\n\n                const double rndmax = std::numeric_limits<dlib::uint32>::max();\n\n                // Generate a pair of Gaussian random numbers using the Box-Muller transformation.\n                do \n                {\n                    const double rnd1 = get_random_32bit_number()/rndmax;\n                    const double rnd2 = get_random_32bit_number()/rndmax;\n\n                    x1 = 2.0 * rnd1 - 1.0;\n                    x2 = 2.0 * rnd2 - 1.0;\n                    w = x1 * x1 + x2 * x2;\n                } while ( w >= 1.0 );\n\n                w = std::sqrt( (-2.0 * std::log( w ) ) / w );\n                return std::complex<double>(x1 * w, x2 * w);\n            }\n\n            double get_random_gaussian (\n            )\n            {\n                if (has_gaussian)\n                {\n                    has_gaussian = false;\n                    return next_gaussian;\n                }\n                \n                std::complex<double> r = get_random_complex_gaussian();\n                next_gaussian = r.imag();\n                has_gaussian = true;\n                return r.real();\n            }\n\n            double get_random_exponential (\n                double lambda\n            )\n            {\n                DLIB_ASSERT(lambda > 0, \"lambda must be greater than zero\");\n                double u = 0.0;\n                while (u == 0.0)\n                    u = get_random_double();\n                return -std::log( u ) / lambda;\n            }\n\n            double get_random_weibull (\n                double lambda,\n                double k,\n                double gamma\n            )\n            {\n                DLIB_ASSERT(k > 0, \"k must be greater than zero\");\n                DLIB_ASSERT(lambda > 0, \"lambda must be greater than zero\");\n                double u = 0.0;\n                while (u == 0.0)\n                    u = get_random_double();\n                return gamma + lambda*std::pow(-std::log(u), 1.0 / k);\n            }\n\n            double get_random_beta (\n                double alpha,\n                double beta\n            )\n            {\n                DLIB_CASSERT(alpha > 0, \"alpha must be greater than zero\")\n                DLIB_CASSERT(beta > 0, \"beta must be greater than zero\");\n                auto u = std::pow(get_random_double(), 1 / alpha);\n                auto v = std::pow(get_random_double(), 1 / beta);\n                while ((u + v) > 1 || (u == 0 && v == 0))\n                {\n                    u = std::pow(get_random_double(), 1 / alpha);\n                    v = std::pow(get_random_double(), 1 / beta);\n                }\n                return u / (u + v);\n            }\n\n            void swap (\n                rand& item\n            )\n            {\n                exchange(mt,item.mt);\n                exchange(seed, item.seed);\n                exchange(has_gaussian, item.has_gaussian);\n                exchange(next_gaussian, item.next_gaussian);\n            }\n    \n            friend void serialize(\n                const rand& item, \n                std::ostream& out\n            );\n\n            friend void deserialize(\n                rand& item, \n                std::istream& in \n            );\n\n        private:\n\n            void init()\n            {\n                // prime the generator a bit\n                for (int i = 0; i < 10000; ++i)\n                    mt();\n\n                max_val =  0xFFFFFF;\n                max_val *= 0x1000000;\n                max_val += 0xFFFFFF;\n                max_val += 0.05;\n\n\n                has_gaussian = false;\n                next_gaussian = 0;\n            }\n\n            mt19937 mt;\n\n            std::string seed;\n\n\n            double max_val;\n            bool has_gaussian;\n            double next_gaussian;\n    };\n\n\n    inline void swap (\n        rand& a, \n        rand& b \n    ) { a.swap(b); }   \n\n\n    template <>\n    struct is_rand<rand>\n    {\n        static const bool value = true; \n    };\n\n    inline void serialize(\n        const rand& item, \n        std::ostream& out\n    )\n    {\n        int version = 1;\n        serialize(version, out);\n\n        serialize(item.mt, out);\n        serialize(item.seed, out);\n        serialize(item.has_gaussian, out);\n        serialize(item.next_gaussian, out);\n    }\n\n    inline void deserialize(\n        rand& item, \n        std::istream& in \n    )\n    {\n        int version;\n        deserialize(version, in);\n        if (version != 1)\n            throw serialization_error(\"Error deserializing object of type rand: unexpected version.\"); \n\n        deserialize(item.mt, in);\n        deserialize(item.seed, in);\n        deserialize(item.has_gaussian, in);\n        deserialize(item.next_gaussian, in);\n    }\n}\n\n#endif // DLIB_RAND_KERNEl_1_\n\n\n"
  },
  {
    "path": "dlib/rand/rand_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RAND_KERNEl_ABSTRACT_\n#ifdef DLIB_RAND_KERNEl_ABSTRACT_\n\n#include <string>\n#include <complex>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n\n    class rand\n    {\n\n        /*!      \n            INITIAL VALUE\n                get_seed() == \"\"\n\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a pseudorandom number generator.\n        !*/\n        \n        public:\n\n\n            rand(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n            !*/\n\n            rand (\n                time_t seed_value\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                    - #get_seed() == cast_to_string(seed_value) \n                    - This version of the constructor is equivalent to using\n                      the default constructor and then calling set_seed(cast_to_string(seed_value))\n                throws\n                    - std::bad_alloc\n            !*/\n\n            rand (\n                const std::string& seed_value\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                    - #get_seed() == seed_value\n                    - This version of the constructor is equivalent to using\n                      the default constructor and then calling set_seed(seed_value)\n                throws\n                    - std::bad_alloc\n            !*/\n\n            virtual ~rand(\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            const std::string& get_seed (\n            );\n            /*!\n                ensures\n                    - returns the string currently being used as the random seed.\n            !*/\n\n            void set_seed (\n                const std::string& value\n            );\n            /*!\n                ensures\n                    - #get_seed() == value\n            !*/\n\n            unsigned char get_random_8bit_number (\n            );\n            /*!\n                ensures\n                    - returns a pseudorandom number in the range 0 to 255\n            !*/\n\n            uint16 get_random_16bit_number (\n            );\n            /*!\n                ensures\n                    - returns a pseudorandom number in the range 0 to 2^16-1 \n            !*/\n\n            uint32 get_random_32bit_number (\n            );\n            /*!\n                ensures\n                    - returns a pseudorandom number in the range 0 to 2^32-1 \n            !*/\n\n            uint64 get_random_64bit_number (\n            );\n            /*!\n                ensures\n                    - returns a pseudorandom number in the range 0 to 2^64-1 \n            !*/\n\n            float get_random_float (\n            );\n            /*!\n                ensures\n                    - returns a random float number N where:  0.0 <= N < 1.0.\n            !*/\n\n            double get_random_double (\n            );\n            /*!\n                ensures\n                    - returns a random double number N where:  0.0 <= N < 1.0.\n            !*/\n\n            double get_double_in_range (\n                double begin,\n                double end\n            );\n            /*!\n                requires\n                    - begin <= end\n                ensures\n                    - if (begin < end) then\n                        - returns a random double number N where:  begin <= N < end.\n                    - else\n                        - returns begin\n            !*/\n\n            long long get_integer_in_range(\n                long long begin,\n                long long end\n            );\n            /*!\n                requires\n                    - begin <= end\n                ensures\n                    - returns a random integer N selected from the range: begin <= N < end\n                      The integer is selected uniformly at random.  If begin==end then\n                      begin is returned.\n            !*/\n\n            long long get_integer(\n                long long end\n            );\n            /*!\n                requires\n                    - 0 <= end\n                ensures\n                    - returns get_integer_in_range(0,end)\n            !*/\n\n            double get_random_gaussian (\n            );\n            /*!\n                ensures\n                    - returns a random number sampled from a Gaussian distribution \n                      with mean 0 and standard deviation 1. \n            !*/\n\n            std::complex<double> get_random_complex_gaussian (\n            );\n            /*!\n                ensures\n                    - returns a random complex number sampled from a Gaussian distribution \n                      with mean 0 and standard deviation 1. \n            !*/\n            \n            double get_random_exponential (\n                double lambda\n            );\n            /*!\n                ensures\n                    - returns a random number sampled from an exponential distribution\n                      with rate parameter lambda\n            !*/\n\n            double get_random_weibull (\n                double lambda,\n                double k,\n                double gamma\n            );\n            /*!\n                ensures\n                    - returns a random number sampled from a Weibull distribution\n                      with shape parameter k, scale parameter lambda and \n                      threshold parameter gamma.\n            !*/\n\n            double get_random_beta (\n                double alpha,\n                double beta,\n            )\n            /*!\n                requires\n                    - alpha > 0\n                    - beta > 0\n                ensures\n                    - returns a random number sampled from a Beta distribution\n                      with shape parameters alpha and beta.\n            !*/\n\n            void swap (\n                rand& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n    };\n\n    inline void swap (\n        rand& a, \n        rand& b \n    ) { a.swap(b); }   \n    /*!\n        provides a global swap function\n    !*/\n\n    void serialize (\n        const rand& item, \n        std::ostream& out \n    );   \n    /*!\n        provides serialization support \n    !*/\n\n    void deserialize (\n        rand& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_RAND_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/rand.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANd_\n#define DLIB_RANd_\n\n#include \"rand/rand_kernel_1.h\"\n\n#endif // DLIB_RANd_\n\n"
  },
  {
    "path": "dlib/random_forest/random_forest_regression.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANdOM_FOREST_REGRESSION_H_\n#define DLIB_RANdOM_FOREST_REGRESSION_H_\n\n#include \"random_forest_regression_abstract.h\"\n#include <vector>\n#include \"../matrix.h\"\n#include <algorithm>\n#include \"../threads.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class dense_feature_extractor\n    {\n\n    public:\n        typedef uint32_t feature;\n        typedef matrix<double,0,1> sample_type;\n\n        dense_feature_extractor(\n        ) = default;\n\n        void setup (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y \n        ) \n        {\n            DLIB_CASSERT(x.size() > 0);\n            DLIB_CASSERT(x.size() == y.size());\n            for (auto& el : x)\n                DLIB_CASSERT(el.size() == x[0].size(), \"All the vectors in a training set have to have the same dimensionality.\");\n\n            DLIB_CASSERT(x[0].size() != 0, \"The vectors can't be empty.\");\n\n            num_feats = x[0].size();\n        }\n\n\n        void get_random_features (\n            dlib::rand& rnd,\n            size_t num,\n            std::vector<feature>& feats\n        ) const\n        {\n            DLIB_ASSERT(max_num_feats() != 0);\n            num = std::min(num, num_feats);\n\n            feats.clear();\n            for (size_t i = 0; i < num_feats; ++i)\n                feats.push_back(i);\n\n            // now pick num features at random\n            for (size_t i = 0; i < num; ++i)\n            {\n                auto idx = rnd.get_integer_in_range(i,num_feats);\n                std::swap(feats[i], feats[idx]);\n            }\n            feats.resize(num);\n        }\n\n        double extract_feature_value (\n            const sample_type& item,\n            const feature& f\n        ) const\n        {\n            DLIB_ASSERT(max_num_feats() != 0);\n            return item(f);\n        }\n\n        size_t max_num_feats (\n        ) const\n        {\n            return num_feats;\n        }\n\n        friend void serialize(const dense_feature_extractor& item, std::ostream& out)\n        {\n            serialize(\"dense_feature_extractor\", out);\n            serialize(item.num_feats, out);\n        }\n\n        friend void deserialize(dense_feature_extractor& item, std::istream& in)\n        {\n            check_serialized_version(\"dense_feature_extractor\", in);\n            deserialize(item.num_feats, in);\n        }\n\n    private:\n        size_t num_feats = 0;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    struct internal_tree_node\n    {\n        uint32_t left;\n        uint32_t right;\n        float split_threshold;\n        typename feature_extractor::feature split_feature;\n    };\n\n    template <typename feature_extractor>\n    void serialize(const internal_tree_node<feature_extractor>& item, std::ostream& out)\n    {\n        serialize(item.left, out);\n        serialize(item.right, out);\n        serialize(item.split_threshold, out);\n        serialize(item.split_feature, out);\n    }\n\n    template <typename feature_extractor>\n    void deserialize(internal_tree_node<feature_extractor>& item, std::istream& in)\n    {\n        deserialize(item.left, in);\n        deserialize(item.right, in);\n        deserialize(item.split_threshold, in);\n        deserialize(item.split_feature, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor = dense_feature_extractor\n        >\n    class random_forest_regression_function\n    {\n\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::sample_type sample_type;\n\n        random_forest_regression_function(\n        ) = default;\n\n        random_forest_regression_function (\n            feature_extractor_type&& fe_,\n            std::vector<std::vector<internal_tree_node<feature_extractor>>>&& trees_,\n            std::vector<std::vector<float>>&& leaves_\n        ) :\n            fe(std::move(fe_)),\n            trees(std::move(trees_)),\n            leaves(std::move(leaves_))\n        {\n            DLIB_ASSERT(trees.size() > 0);\n            DLIB_ASSERT(trees.size() == leaves.size(), \"Every set of tree nodes has to have leaves\");\n#ifdef ENABLE_ASSERTS\n            for (size_t i = 0; i < trees.size(); ++i)\n            {\n                DLIB_ASSERT(trees[i].size() > 0, \"A tree can't have 0 leaves.\");\n                for (auto& node : trees[i])\n                {\n                    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.\");\n                    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.\");\n                }\n            }\n#endif\n        }\n\n        size_t get_num_trees(\n        ) const\n        {\n            return trees.size();\n        }\n\n        const std::vector<std::vector<internal_tree_node<feature_extractor>>>& get_internal_tree_nodes (\n        ) const { return trees; }\n\n        const std::vector<std::vector<float>>& get_tree_leaves (\n        ) const { return leaves; }\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const { return fe; }\n\n        double operator() (\n            const sample_type& x\n        ) const\n        {\n            DLIB_ASSERT(get_num_trees() > 0);\n\n            double accum = 0;\n\n            for (size_t i = 0; i < trees.size(); ++i)\n            {\n                auto& tree = trees[i];\n                // walk the tree to the leaf\n                uint32_t idx = 0;\n                while(idx < tree.size())\n                {\n                    auto feature_value = fe.extract_feature_value(x, tree[idx].split_feature);\n                    if (feature_value < tree[idx].split_threshold)\n                        idx = tree[idx].left;\n                    else\n                        idx = tree[idx].right;\n                }\n                // compute leaf index \n                accum += leaves[i][idx-tree.size()];\n            }\n\n            return accum/trees.size();\n        }\n\n        friend void serialize(const random_forest_regression_function& item, std::ostream& out)\n        {\n            serialize(\"random_forest_regression_function\", out);\n            serialize(item.fe, out);\n            serialize(item.trees, out);\n            serialize(item.leaves, out);\n        }\n\n        friend void deserialize(random_forest_regression_function& item, std::istream& in)\n        {\n            check_serialized_version(\"random_forest_regression_function\", in);\n            deserialize(item.fe, in);\n            deserialize(item.trees, in);\n            deserialize(item.leaves, in);\n        }\n\n    private:\n\n        /*!\n            CONVENTION\n                - trees.size() == leaves.size()\n                - Any .left or .right index in trees that is larger than the number of\n                  nodes in the tree references a leaf. Moreover, the index of the leaf is\n                  computed by subtracting the number of nodes in the tree.\n        !*/\n\n        feature_extractor_type fe;\n\n        // internal nodes of trees\n        std::vector<std::vector<internal_tree_node<feature_extractor>>> trees;\n        // leaves of trees\n        std::vector<std::vector<float>> leaves;\n\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor = dense_feature_extractor\n        >\n    class random_forest_regression_trainer\n    {\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef random_forest_regression_function<feature_extractor> trained_function_type;\n        typedef typename feature_extractor::sample_type sample_type;\n\n\n        random_forest_regression_trainer (\n        ) = default;\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const\n        {\n            return fe_;\n        }\n\n        void set_feature_extractor (\n            const feature_extractor_type& feat_extractor\n        )\n        {\n            fe_ = feat_extractor;\n        }\n\n        void set_seed (\n            const std::string& seed\n        )\n        {\n            random_seed = seed;\n        }\n\n        const std::string& get_random_seed (\n        ) const\n        {\n            return random_seed;\n        }\n\n        size_t get_num_trees (\n        ) const\n        {\n            return num_trees;\n        }\n\n        void set_num_trees (\n            size_t num\n        )\n        {\n            DLIB_CASSERT(num > 0);\n            num_trees = num;\n        }\n\n        void set_feature_subsampling_fraction (\n            double frac\n        )\n        {\n            DLIB_CASSERT(0 < frac && frac <= 1);\n            feature_subsampling_frac = frac;\n        }\n\n        double get_feature_subsampling_frac(\n        ) const\n        {\n            return feature_subsampling_frac;\n        }\n\n        void set_min_samples_per_leaf (\n            size_t num\n        )\n        {\n            DLIB_ASSERT(num > 0);\n            min_samples_per_leaf = num;\n        }\n\n        size_t get_min_samples_per_leaf(\n        ) const\n        {\n            return min_samples_per_leaf;\n        }\n\n        void be_verbose (\n        )\n        {\n            verbose = true;\n        }\n\n        void be_quiet (\n        )\n        {\n            verbose = false;\n        }\n\n        trained_function_type train (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y \n        ) const\n        {\n            std::vector<double> junk; \n            return do_train(x,y,junk,false);\n        }\n\n        trained_function_type train (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y,\n            std::vector<double>& oob_values \n        ) const\n        {\n            return do_train(x,y,oob_values,true);\n        }\n\n    private:\n\n        trained_function_type do_train (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y,\n            std::vector<double>& oob_values, \n            bool compute_oob_values\n        ) const \n        {\n            DLIB_CASSERT(x.size() == y.size());\n            DLIB_CASSERT(x.size() > 0);\n\n            feature_extractor_type fe = fe_;\n            fe.setup(x,y);\n\n            DLIB_CASSERT(fe.max_num_feats() != 0);\n\n            std::vector<std::vector<internal_tree_node<feature_extractor>>> all_trees(num_trees);\n            std::vector<std::vector<float>> all_leaves(num_trees);\n\n            const size_t feats_per_node = std::max(1.0,std::round(fe.max_num_feats()*feature_subsampling_frac));\n\n            // Each tree couldn't have more than this many interior nodes.  It might\n            // end up having less though. We need to know this value because the way\n            // we mark a left or right pointer in a tree as pointing to a leaf is by\n            // making its index larger than the number of interior nodes in the tree.\n            // But we don't know the tree's size before we finish building it.  So we\n            // will use max_num_nodes as a proxy during tree construction and then go\n            // back and fix it once a tree's size is known.\n            const uint32_t max_num_nodes = y.size(); \n\n            std::vector<uint32_t> oob_hits;\n\n            if (compute_oob_values)\n            {\n                oob_values.resize(y.size());\n                oob_hits.resize(y.size());\n            }\n\n\n            std::mutex m;\n\n            // Calling build_tree(i) creates the ith tree and stores the results in\n            // all_trees and all_leaves.\n            auto build_tree = [&](long i)\n            {\n                dlib::rand rnd(random_seed + std::to_string(i));\n                auto& tree = all_trees[i];\n                auto& leaves = all_leaves[i];\n\n                // Check if there are fewer than min_samples_per_leaf and if so then\n                // don't make any tree.  Just average the things and be done. \n                if (y.size() <= min_samples_per_leaf)\n                {\n                    leaves.push_back(mean(mat(y)));\n                    return;\n                }\n\n\n                double sumy = 0;\n                // pick a random bootstrap of the data.\n                std::vector<std::pair<float,uint32_t>> idxs(y.size());\n                for (auto& idx : idxs) {\n                    idx = std::make_pair(0.0f, static_cast<uint32_t>(rnd.get_integer(y.size())));\n                    sumy += y[idx.second];\n                }\n\n                // We are going to use ranges_to_process as a stack that tracks which\n                // range of samples we are going to split next.\n                std::vector<range_t> ranges_to_process;\n                // start with the root of the tree, i.e. the entire range of training\n                // samples.\n                ranges_to_process.emplace_back(sumy, 0, static_cast<uint32_t>(y.size()));\n                // push an unpopulated root node into the tree.  We will populate it\n                // when we process its corresponding range. \n                tree.emplace_back();\n\n                std::vector<typename feature_extractor::feature> feats;\n\n                while(ranges_to_process.size() > 0)\n                {\n                    // Grab the next range/node to process.\n                    const auto range = ranges_to_process.back();\n                    ranges_to_process.pop_back();\n\n\n                    // Get the split features we will consider at this node.\n                    fe.get_random_features(rnd, feats_per_node, feats);\n                    // Then find the best split\n                    auto best_split = find_best_split_among_feats(fe, range, feats, x, y, idxs); \n\n                    range_t left_split(best_split.left_sum, range.begin, best_split.split_idx);\n                    range_t right_split(best_split.right_sum, best_split.split_idx, range.end);\n\n                    DLIB_ASSERT(left_split.begin < left_split.end);\n                    DLIB_ASSERT(right_split.begin < right_split.end);\n\n                    // Now that we know the split we can populate the parent node we popped\n                    // from ranges_to_process.\n                    tree[range.tree_idx].split_threshold = best_split.split_threshold; \n                    tree[range.tree_idx].split_feature = best_split.split_feature; \n\n                    // If the left split is big enough to make a new interior leaf\n                    // node. We also stop splitting if all the samples went into this node.\n                    // This could happen if the features are all uniform so there just\n                    // isn't any way to split them anymore.\n                    if (left_split.size() > min_samples_per_leaf && right_split.size() != 0)\n                    {\n                        // allocate an interior leaf node for it.\n                        left_split.tree_idx = tree.size();\n                        tree.emplace_back(); \n                        // set the pointer in the parent node to the newly allocated\n                        // node.\n                        tree[range.tree_idx].left  = left_split.tree_idx;\n\n                        ranges_to_process.emplace_back(left_split);\n                    }\n                    else\n                    {\n                        // Add to leaves.  Don't forget to set the pointer in the\n                        // parent node to the newly allocated leaf node.\n                        tree[range.tree_idx].left = leaves.size() + max_num_nodes;\n                        leaves.emplace_back(static_cast<float>(left_split.avg()));\n                    }\n\n\n                    // If the right split is big enough to make a new interior leaf\n                    // node. We also stop splitting if all the samples went into this node.\n                    // This could happen if the features are all uniform so there just\n                    // isn't any way to split them anymore.\n                    if (right_split.size() > min_samples_per_leaf && left_split.size() != 0)\n                    {\n                        // allocate an interior leaf node for it.\n                        right_split.tree_idx = tree.size();\n                        tree.emplace_back(); \n                        // set the pointer in the parent node to the newly allocated\n                        // node.\n                        tree[range.tree_idx].right  = right_split.tree_idx;\n\n                        ranges_to_process.emplace_back(right_split);\n                    }\n                    else\n                    {\n                        // Add to leaves.  Don't forget to set the pointer in the\n                        // parent node to the newly allocated leaf node.\n                        tree[range.tree_idx].right = leaves.size() + max_num_nodes;\n                        leaves.emplace_back(static_cast<float>(right_split.avg()));\n                    }\n                } // end while (still building tree)\n\n                // Fix the leaf pointers in the tree now that we know the correct\n                // tree.size() value.\n                DLIB_CASSERT(max_num_nodes >= tree.size()); \n                const auto offset = max_num_nodes - tree.size();\n                for (auto& n : tree)\n                {\n                    if (n.left >= max_num_nodes)\n                        n.left -= offset;\n                    if (n.right >= max_num_nodes)\n                        n.right -= offset;\n                }\n                \n\n                if (compute_oob_values)\n                {\n                    std::sort(idxs.begin(), idxs.end(), \n                        [](const std::pair<float,uint32_t>& a, const std::pair<float,uint32_t>& b) {return a.second<b.second; });\n\n                    std::lock_guard<std::mutex> lock(m);\n\n                    size_t j = 0;\n                    for (size_t i = 0; i < oob_values.size(); ++i)\n                    {\n                        // check if i is in idxs\n                        while(j < idxs.size() && i > idxs[j].second)\n                            ++j;\n\n                        // i isn't in idxs so it's an oob sample and we should process it.\n                        if (j == idxs.size() || idxs[j].second != i)\n                        {\n                            oob_hits[i]++;\n\n                            // walk the tree to find the leaf value for this oob sample\n                            uint32_t idx = 0;\n                            while(idx < tree.size())\n                            {\n                                auto feature_value = fe.extract_feature_value(x[i], tree[idx].split_feature);\n                                if (feature_value < tree[idx].split_threshold)\n                                    idx = tree[idx].left;\n                                else\n                                    idx = tree[idx].right;\n                            }\n                            oob_values[i] += leaves[idx-tree.size()];\n                        }\n                    }\n                }\n            };\n\n            if (verbose)\n                parallel_for_verbose(0, num_trees, build_tree);\n            else\n                parallel_for(0, num_trees, build_tree);\n\n\n            if (compute_oob_values)\n            {\n                double meanval = 0;\n                double cnt = 0;\n                for (size_t i = 0; i < oob_values.size(); ++i)\n                {\n                    if (oob_hits[i] != 0)\n                    {\n                        oob_values[i] /= oob_hits[i];\n                        meanval += oob_values[i];\n                        ++cnt;\n                    }\n                }\n\n                // If there are some elements that didn't get hits, we set their oob values\n                // to the mean oob value.\n                if (cnt != 0)\n                {\n                    const double typical_value = meanval/cnt;\n                    for (size_t i = 0; i < oob_values.size(); ++i)\n                    {\n                        if (oob_hits[i] == 0)\n                            oob_values[i] = typical_value;\n                    }\n                }\n            }\n\n            return trained_function_type(std::move(fe), std::move(all_trees), std::move(all_leaves));\n        }\n\n        struct range_t \n        {\n            range_t(\n                double sumy,\n                uint32_t begin,\n                uint32_t end\n            ) : sumy(sumy), begin(begin), end(end), tree_idx(0) {}\n\n            double sumy;\n            uint32_t begin;\n            uint32_t end;\n\n            // Every range object corresponds to an entry in a tree. This tells you the\n            // tree node that owns the range.\n            uint32_t tree_idx; \n\n            uint32_t size() const { return end-begin; }\n            double avg() const { return sumy/size(); }\n        };\n\n        struct best_split_details\n        {\n            double score = -std::numeric_limits<double>::infinity();\n            double left_sum;\n            double right_sum;\n            uint32_t split_idx;\n            double split_threshold;\n            typename feature_extractor::feature split_feature;\n\n            bool operator < (const best_split_details& rhs) const\n            {\n                return score < rhs.score;\n            }\n        };\n\n        static best_split_details find_best_split (\n            const range_t& range,\n            const std::vector<double>& y,\n            const std::vector<std::pair<float,uint32_t>>& idxs\n        )\n        /*!\n            requires\n                - max(mat(idxs)) < y.size()\n                - range.sumy == sum of y[idxs[j].second] for all valid j in range [range.begin, range.end). \n            ensures\n                - finds a threshold T such that there exists an i satisfying the following:\n                    - y[idxs[j].second] < T for all j <= i\n                    - y[idxs[j].second] > T for all j > i\n                  Therefore, the threshold T partitions the contents of y into two groups,\n                  relative to the ordering established by idxs.  Moreover the partitioning\n                  of y values into two groups has the additional requirement that it is\n                  optimal in the sense that the sum of the squared deviations from each\n                  partition's mean is minimized.\n        !*/\n        {\n\n            size_t best_i = range.begin;\n            double best_score = -1;\n            double left_sum = 0;\n            double best_left_sum = y[idxs[range.begin].second];\n            const auto size = range.size();\n            size_t left_size = 0;\n            for (size_t i = range.begin; i+1 < range.end; ++i)\n            {\n                ++left_size;\n                left_sum += y[idxs[i].second];\n\n                // Don't split here because the next element has the same feature value so\n                // we can't *really* split here.\n                if (idxs[i].first==idxs[i+1].first)\n                    continue;\n\n                const double right_sum = range.sumy-left_sum;\n\n                const double score = left_sum*left_sum/left_size + right_sum*right_sum/(size-left_size);\n\n                if (score > best_score)\n                {\n                    best_score = score;\n                    best_i = i;\n                    best_left_sum = left_sum;\n                }\n            }\n\n            best_split_details result;\n            result.score = best_score;\n            result.left_sum = best_left_sum;\n            result.right_sum = range.sumy-best_left_sum;\n            result.split_idx = best_i+1; // one past the end of the left range\n            result.split_threshold = (idxs[best_i].first+idxs[best_i+1].first)/2;\n\n            return result;\n        }\n\n\n        static best_split_details find_best_split_among_feats(\n            const feature_extractor& fe,\n            const range_t& range, \n            const std::vector<typename feature_extractor::feature>& feats, \n            const std::vector<sample_type>& x,\n            const std::vector<double>& y,\n            std::vector<std::pair<float,uint32_t>>& idxs\n        )\n        {\n            auto compare_first = [](const std::pair<float,uint32_t>& a, const std::pair<float,uint32_t>& b) { return a.first<b.first; };\n            best_split_details best;\n            for (auto& feat : feats)\n            {\n                // Extract feature values for this feature and sort the indexes based on\n                // that feature so we can then find the best split.\n                for (auto i = range.begin; i < range.end; ++i)\n                    idxs[i].first = fe.extract_feature_value(x[idxs[i].second], feat);\n\n                std::stable_sort(idxs.begin()+range.begin, idxs.begin()+range.end, compare_first);\n\n                auto split = find_best_split(range, y, idxs);\n\n                if (best < split)\n                {\n                    best = split;\n                    best.split_feature = feat;\n                }\n            }\n\n            // resort idxs based on winning feat\n            for (auto i = range.begin; i < range.end; ++i)\n                idxs[i].first = fe.extract_feature_value(x[idxs[i].second], best.split_feature);\n            std::stable_sort(idxs.begin()+range.begin, idxs.begin()+range.end, compare_first);\n\n            return best;\n        }\n\n        std::string random_seed;\n        size_t num_trees = 1000;\n        double feature_subsampling_frac = 1.0/3.0;\n        size_t min_samples_per_leaf = 5;\n        feature_extractor_type fe_;\n        bool verbose = false;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANdOM_FOREST_REGRESSION_H_\n\n\n"
  },
  {
    "path": "dlib/random_forest/random_forest_regression_abstract.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_RANdOM_FOREST_REGRESION_ABSTRACT_H_\n#ifdef DLIB_RANdOM_FOREST_REGRESION_ABSTRACT_H_\n\n#include <vector>\n#include \"../matrix.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class dense_feature_extractor\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is a tool for extracting features from objects.  In particular,\n                it is designed to be used with the random forest regression tools discussed\n                below.\n\n                This particular feature extract does almost nothing since it works on\n                vectors in R^n and simply selects elements from each vector.  However, the\n                tools below are templated and allow you to design your own feature extractors\n                that operate on whatever object types you create.  So for example, maybe\n                you want to perform regression on images rather than vectors.  Moreover,\n                your feature extraction could be more complex.  Maybe you are selecting\n                differences between pairs of pixels in an image or doing something\n                involving geometric transforms during feature extraction.  Any of these\n                kinds of more complex feature extraction patterns can be realized with the\n                random forest tools by implementing your own feature extractor object and\n                using it with the random forest objects.\n\n                Therefore, you should consider this dense_feature_extractor as an example\n                that documents the interface as well as the simple default extractor for\n                use with dense vectors.\n\n\n            THREAD SAFETY\n                It is safe to call const members of this object from multiple threads.  ANY\n                USER DEFINED FEATURE EXTRACTORS MUST ALSO MEET THIS GUARONTEE AS WELL SINCE\n                IT IS ASSUMED BY THE RANDOM FOREST TRAINING ROUTINES.\n        !*/\n\n    public:\n        typedef uint32_t feature;\n        typedef matrix<double,0,1> sample_type;\n\n        dense_feature_extractor(\n        );\n        /*!\n            ensures\n                - #max_num_feats() == 0\n        !*/\n\n        void setup (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y \n        );\n        /*!\n            requires\n                - x.size() == y.size()\n                - x.size() > 0\n                - x[0].size() > 0\n                - all the vectors in x have the same dimensionality.\n            ensures\n                - Configures this feature extractor to work on the given training data.\n                  For dense feature extractors all we do is record the dimensionality of\n                  the training vectors.\n                - #max_num_feats() == x[0].size()\n                  (In general, setup() sets max_num_feats() to some non-zero value so that\n                  the other methods of this object can then be called.  The point of setup() \n                  is to allow a feature extractor to gather whatever statistics it needs from \n                  training data.  That is, more complex feature extraction strategies my\n                  themselves be trained from data.)\n        !*/\n\n        void get_random_features (\n            dlib::rand& rnd,\n            size_t num,\n            std::vector<feature>& feats\n        ) const;\n        /*!\n            requires\n                - max_num_feats() != 0\n            ensures\n                - #feats.size() == min(num, max_num_feats())\n                - This function randomly identifies num features and stores them into feats.  \n                  These feature objects can then be used with extract_feature_value() to\n                  obtain a value from any particular sample_type object.  This value is the\n                  \"feature value\" used by a decision tree algorithm to deice how to split\n                  and traverse trees.   \n                - The above two conditions define the behavior of get_random_features() in\n                  general. For this specific implementation of the feature extraction interface \n                  this function selects num integer values from the range [0, max_num_feats()), \n                  without replacement.  These values are stored into feats.\n        !*/\n\n        double extract_feature_value (\n            const sample_type& item,\n            const feature& f\n        ) const;\n        /*!\n            requires\n                - #max_num_feats() != 0\n                - f was produced from a call to get_random_features().\n            ensures\n                - Extracts the feature value corresponding to f. For this simple dense\n                  feature extractor this simply means returning item(f).  But in general\n                  you can design feature extractors that do something more complex.\n        !*/\n\n        size_t max_num_feats (\n        ) const;\n        /*!\n            ensures\n                - returns the number of distinct features this object might extract.  That is,\n                  a feature extractor essentially defines a mapping from sample_type objects to\n                  vectors in R^max_num_feats().\n        !*/\n    };\n\n    void serialize(const dense_feature_extractor& item, std::ostream& out);\n    void deserialize(dense_feature_extractor& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor\n        >\n    struct internal_tree_node\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object is an internal node in a regression tree.  See the code of\n                random_forest_regression_function to see how it is used to create a tree.\n        !*/\n\n        uint32_t left;\n        uint32_t right;\n        float split_threshold;\n        typename feature_extractor::feature split_feature;\n    };\n\n    template <typename feature_extractor>\n    void serialize(const internal_tree_node<feature_extractor>& item, std::ostream& out);\n    template <typename feature_extractor>\n    void deserialize(internal_tree_node<feature_extractor>& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor = dense_feature_extractor\n        >\n    class random_forest_regression_function\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor\n                feature_extractor must be dense_feature_extractor or a type with a\n                compatible interface.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a regression forest.  This is a collection of\n                decision trees that take an object as input and each vote on a real value\n                to associate with the object.  The final real value output is the average\n                of all the votes from each of the trees.\n        !*/\n\n    public:\n\n        typedef feature_extractor feature_extractor_type;\n        typedef typename feature_extractor::sample_type sample_type;\n\n        random_forest_regression_function(\n        );\n        /*!\n            ensures\n                - #num_trees() == 0\n        !*/\n\n        random_forest_regression_function (\n            feature_extractor_type&& fe_,\n            std::vector<std::vector<internal_tree_node<feature_extractor>>>&& trees_,\n            std::vector<std::vector<float>>&& leaves_\n        );\n        /*!\n            requires\n                - trees.size() > 0\n                - trees.size() = leaves.size()\n                - for all valid i:\n                    - leaves[i].size() > 0 \n                    - trees[i].size()+leaves[i].size() > the maximal left or right index values in trees[i].\n                      (i.e. each left or right value must index to some existing internal tree node or leaf node).\n            ensures\n                - #get_internal_tree_nodes() == trees_\n                - #get_tree_leaves() == leaves_\n                - #get_feature_extractor() == fe_\n        !*/\n\n        size_t get_num_trees(\n        ) const;\n        /*!\n            ensures\n                - returns the number of trees in this regression forest.\n        !*/\n\n        const std::vector<std::vector<internal_tree_node<feature_extractor>>>& get_internal_tree_nodes (\n        ) const; \n        /*!\n            ensures\n                - returns the internal tree nodes that define the regression trees.\n                - get_internal_tree_nodes().size() == get_num_trees()\n        !*/\n\n        const std::vector<std::vector<float>>& get_tree_leaves (\n        ) const; \n        /*!\n            ensures\n                - returns the tree leaves that define the regression trees.\n                - get_tree_leaves().size() == get_num_trees()\n        !*/\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const;\n        /*!\n            ensures\n                - returns the feature extractor used by the trees. \n        !*/\n\n        double operator() (\n            const sample_type& x\n        ) const;\n        /*!\n            requires\n                - get_num_trees() > 0\n            ensures\n                - Maps x to a real value and returns the value.  To do this, we find the\n                  get_num_trees() leaf values associated with x and then return the average\n                  of these leaf values.   \n        !*/\n    };\n\n    void serialize(const random_forest_regression_function& item, std::ostream& out);\n    void deserialize(random_forest_regression_function& item, std::istream& in);\n    /*!\n        provides serialization support\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename feature_extractor = dense_feature_extractor\n        >\n    class random_forest_regression_trainer\n    {\n        /*!\n            REQUIREMENTS ON feature_extractor\n                feature_extractor must be dense_feature_extractor or a type with a\n                compatible interface.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object implements Breiman's classic random forest regression\n                algorithm.  The algorithm learns to map objects, nominally vectors in R^n,\n                into the reals.  It essentially optimizes the mean squared error by fitting\n                a bunch of decision trees, each of which vote on the output value of the\n                regressor. The final prediction is obtained by averaging all the\n                predictions. \n\n                For more information on the algorithm see:\n                    Breiman, Leo. \"Random forests.\" Machine learning 45.1 (2001): 5-32.\n        !*/\n\n    public:\n        typedef feature_extractor feature_extractor_type;\n        typedef random_forest_regression_function<feature_extractor> trained_function_type;\n        typedef typename feature_extractor::sample_type sample_type;\n\n\n        random_forest_regression_trainer (\n        );\n        /*!\n            ensures\n                - #get_min_samples_per_leaf() == 5\n                - #get_num_trees() == 1000\n                - #get_feature_subsampling_frac() == 1.0/3.0\n                - #get_feature_extractor() == a default initialized feature extractor.\n                - #get_random_seed() == \"\"\n                - this object is not verbose.\n        !*/\n\n        const feature_extractor_type& get_feature_extractor (\n        ) const;\n        /*!\n            ensures\n                - returns the feature extractor used when train() is invoked.\n        !*/\n\n        void set_feature_extractor (\n            const feature_extractor_type& feat_extractor\n        );\n        /*!\n            ensures\n                - #get_feature_extractor() == feat_extractor\n        !*/\n\n        void set_seed (\n            const std::string& seed\n        );\n        /*!\n            ensures\n                - #get_random_seed() == seed\n        !*/\n\n        const std::string& get_random_seed (\n        ) const;\n        /*!\n            ensures\n                - A central part of this algorithm is random selection of both training\n                  samples and features. This function returns the seed used to initialized\n                  the random number generator used for these random selections.\n        !*/\n\n        size_t get_num_trees (\n        ) const;\n        /*!\n            ensures\n                - Random forests built by this object will contain get_num_trees() trees.\n        !*/\n\n        void set_num_trees (\n            size_t num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_num_trees() == num\n        !*/\n\n        void set_feature_subsampling_fraction (\n            double frac\n        );\n        /*!\n            requires\n                - 0 < frac <= 1\n            ensures\n                - #get_feature_subsampling_frac() == frac\n        !*/\n\n        double get_feature_subsampling_frac(\n        ) const;\n        /*!\n            ensures\n                - When we build trees, at each node we don't look at all the available\n                  features.  We consider only get_feature_subsampling_frac() fraction of\n                  them, selected at random.\n        !*/\n\n        void set_min_samples_per_leaf (\n            size_t num\n        );\n        /*!\n            requires\n                - num > 0\n            ensures\n                - #get_min_samples_per_leaf() == num\n        !*/\n\n        size_t get_min_samples_per_leaf(\n        ) const;\n        /*!\n            ensures\n                - When building trees, each leaf node in a tree will contain at least\n                  get_min_samples_per_leaf() samples.  This means that the output votes of\n                  each tree are averages of at least get_min_samples_per_leaf() y values.\n        !*/\n\n        void be_verbose (\n        );\n        /*!\n            ensures\n                - This object will print status messages to standard out so that the\n                  progress of training can be tracked..\n        !*/\n\n        void be_quiet (\n        );\n        /*!\n            ensures\n                - this object will not print anything to standard out\n        !*/\n\n        random_forest_regression_function<feature_extractor> train (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y,\n            std::vector<double>& oob_values \n        ) const;\n        /*!\n            requires\n                - x.size() == y.size()\n                - x.size() > 0\n                - Running following code:\n                    auto fe = get_feature_extractor()\n                    fe.setup(x,y);\n                  Must be valid and result in fe.max_num_feats() != 0\n            ensures\n                - This function fits a regression forest to the given training data.  The\n                  goal being to regress x to y in the mean squared sense.  It therefore\n                  fits regression trees and returns the resulting random_forest_regression_function \n                  RF, which will have the following properties:\n                    - RF.get_num_trees() == get_num_trees()\n                    - for all valid i:\n                        - RF(x[i]) should output a value close to y[i]\n                    - RF.get_feature_extractor() will be a copy of this->get_feature_extractor() \n                      that has been configured by a call the feature extractor's setup() routine.\n                  To run the algorithm we need to use a feature extractor.  We obtain a\n                  valid feature extractor by making a copy of get_feature_extractor(), then\n                  invoking setup(x,y) on it.  This feature extractor is what is used to fit\n                  the trees and is also the feature extractor stored in the returned random\n                  forest.\n                - #oob_values.size() == y.size()\n                - for all valid i:  \n                    - #oob_values[i] == the \"out of bag\" prediction for y[i].  It is\n                      calculated by computing the average output from trees not trained on\n                      y[i].  This is similar to a leave-one-out cross-validation prediction\n                      of y[i] and can be used to estimate the generalization error of the\n                      regression forest.  \n                - Training uses all the available CPU cores.\n        !*/\n\n        random_forest_regression_function<feature_extractor> train (\n            const std::vector<sample_type>& x,\n            const std::vector<double>& y \n        ) const;\n        /*!\n            requires\n                - x.size() == y.size()\n                - x.size() > 0\n                - Running following code:\n                    auto fe = get_feature_extractor()\n                    fe.setup(x,y);\n                  Must be valid and result in fe.max_num_feats() != 0\n            ensures\n                - This function is identical to train(x,y,oob_values) except that the\n                  oob_values are not calculated.\n        !*/\n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_RANdOM_FOREST_REGRESION_ABSTRACT_H_\n\n"
  },
  {
    "path": "dlib/random_forest.h",
    "content": "// Copyright (C) 2018  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_RANDOM_FOReST_H_\n#define DLIB_RANDOM_FOReST_H_\n\n#include \"random_forest/random_forest_regression.h\"\n\n#endif // DLIB_RANDOM_FOReST_H_\n\n\n"
  },
  {
    "path": "dlib/ref.h",
    "content": "// Copyright (C) 2010  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_REFERENCE_WRAPpER_H_\n#define DLIB_REFERENCE_WRAPpER_H_\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template<\n        typename T\n        > \n    class reference_wrapper \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a simple object that just holds a reference to another object. \n                It is useful because it can serve as a kind of \"copyable reference\".  \n        !*/\n\n    public:\n        typedef T type;\n\n        explicit reference_wrapper(T& o) : obj(&o) {}\n\n        operator T&()    const { return  *obj; }\n        T& get()         const { return  *obj; }\n\n    private:\n        T* obj;\n    };\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    reference_wrapper<T> ref(\n        T& obj\n    ) { return reference_wrapper<T>(obj); }\n    /*!\n        ensures\n            - returns a reference_wrapper that contains a reference to obj.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    reference_wrapper<T> ref(\n        reference_wrapper<T> obj\n    ) { return obj; }\n    /*!\n        ensures\n            - returns the given reference_wrapper object without modification\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    reference_wrapper<const T> cref(\n        const T& obj\n    ) { return reference_wrapper<const T>(obj); }\n    /*!\n        ensures\n            - returns a reference_wrapper that contains a constant reference to obj.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    reference_wrapper<const T> cref(\n        reference_wrapper<T> obj\n    ) { return cref(obj.get()); }\n    /*!\n        ensures\n            - converts the given reference_wrapper into a reference_wrapper that contains a\n              constant reference.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_REFERENCE_WRAPpER_H_\n\n"
  },
  {
    "path": "dlib/reference_counter/reference_counter_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_REFERENCE_COUNTER_KERNEl_1_\n#define DLIB_REFERENCE_COUNTER_KERNEl_1_\n\n#include \"reference_counter_kernel_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename copy = copy_functor<T>\n        >\n    class reference_counter_kernel_1 \n    {\n\n        /*!\n                INITIAL VALUE\n                    *data = item of type T with its initial value\n                    *count = 1\n\n                CONVENTION\n                    *data = pointer to item of type T\n                    *count = number of references to *data\n\n                    if clear() threw an exception then count = 0 and data is not a \n                    valid pointer\n        !*/\n\n        public:\n\n            typedef T type;\n\n\n            reference_counter_kernel_1 (\n            );\n\n            inline reference_counter_kernel_1 ( \n                const reference_counter_kernel_1& item\n            );\n\n            virtual ~reference_counter_kernel_1 (\n            ); \n\n            void clear (\n            );\n\n            T& modify (\n            );\n\n            inline const T& access (\n            ) const;\n\n            inline reference_counter_kernel_1& operator= (\n                const reference_counter_kernel_1& rhs\n            );\n\n            inline void swap (\n                reference_counter_kernel_1& item\n            );\n\n\n        private:\n\n            T* data;\n            unsigned long* count;\n            mutable copy copy_item;\n    };\n\n    template <\n        typename T,\n        typename copy\n        >\n    inline void swap (\n        reference_counter_kernel_1<T,copy>& a, \n        reference_counter_kernel_1<T,copy>& b \n    ) { a.swap(b); }   \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    reference_counter_kernel_1<T,copy>::\n    reference_counter_kernel_1 (\n    ) \n    {\n        data = new T;\n        try { count = new unsigned long; }\n        catch (...) { delete data; throw; }\n\n        *count = 1;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    reference_counter_kernel_1<T,copy>::\n    reference_counter_kernel_1 ( \n        const reference_counter_kernel_1<T,copy>& item\n    ) : \n        data(item.data),\n        count(item.count)\n    {\n        ++(*count);\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    reference_counter_kernel_1<T,copy>::\n    ~reference_counter_kernel_1 (\n    )\n    {\n        if (*count > 1)\n        {\n            // if there are other references to this data\n            --(*count);\n        }\n        else\n        {\n            // if there are no other references to this data\n            delete count;\n            delete data;\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    void reference_counter_kernel_1<T,copy>::\n    clear (\n    )\n    {\n        // if an exception was thrown last time clear() was called then do this\n        if (count == 0)\n        {\n            data = new T;\n            try { count = new unsigned long; }\n            catch (...) { delete data; throw; }\n\n            *count = 1;            \n        }\n        // if there are other references to the data then do this\n        else if (*count > 1)\n        {\n            --(*count);\n\n            try { data = new T; }               \n            catch (...) { count = 0; throw; }\n\n            try { count = new unsigned long; }  \n            catch (...) { delete data; count = 0; throw; }\n\n            *count = 1;\n\n        }\n        else\n        {\n            // if there are no other references to this data\n            *count = 1;\n            delete data;\n            try { data = new T; } catch (...) { delete count; count = 0; throw; }\n        }\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    T& reference_counter_kernel_1<T,copy>::\n    modify (\n    )\n    {\n        // if this is not the only reference then make a new copy\n        if ( *count > 1 )\n        {\n            T&              old_data    = *data;\n            unsigned long&  old_count   = *count;\n\n\n            // get memory for the new copy\n            try { data = new T; }               \n            catch (...) { data = &old_data; throw; }\n\n            try { count = new unsigned long; }  \n            catch (...) {delete data; data = &old_data; count = &old_count; throw;}\n\n            // decrement the number of references to old_data\n            --(old_count);\n\n            *count = 1;\n\n            // make a copy of the old data\n            try { copy_item(old_data,*data); }  \n            catch (...) \n            { delete data; delete count; data = &old_data; count = &old_count; }\n\n        }\n\n        return *data;\n\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    const T& reference_counter_kernel_1<T,copy>::\n    access (\n    ) const\n    {\n        return *data;\n    }\n    \n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    reference_counter_kernel_1<T,copy>& reference_counter_kernel_1<T,copy>::\n    operator= (\n        const reference_counter_kernel_1<T,copy>& rhs\n    )\n    {\n        if (this == &rhs)\n            return *this;\n\n        // delete the current data if this is the last reference to it\n        if (*count > 1)\n        {\n            // if there are other references to this data\n            --(*count);\n        }\n        else\n        {\n            // if there are no other references to this data\n            delete count;\n            delete data;\n        }        \n\n        // copy the pointers\n        count = (rhs.count);\n        data = (rhs.data);\n        ++(*count);\n\n        return *this;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename copy\n        >\n    void reference_counter_kernel_1<T,copy>::\n    swap (\n        reference_counter_kernel_1<T,copy>& item\n    )\n    {\n        T* data_temp                = data;\n        unsigned long* count_temp   = count;\n\n        data    = item.data;\n        count   = item.count;\n\n        item.data   = data_temp;\n        item.count  = count_temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_REFERENCE_COUNTER_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/reference_counter/reference_counter_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_\n#ifdef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_\n\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename copy = copy_functor<T>\n        >\n    class reference_counter\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must have a default constructor\n\n            REQUIREMENTS ON copy\n                it should be a function object that copies an object of type T. and\n                it must have a default constructor and\n                operator() should be overloaded as \n                void operator()(const T& source, T& destination);\n                copy may throw any exception \n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap() and access() functions do not invalidate pointers or \n                references to internal data.\n                All other functions have no such guarantee\n  \n\n            INITIAL VALUE\n                reference_counter contains one object of type T and\n                this object of type T has its initial value\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a container for an object of type T and \n                provides reference counting capabilities for the object it contains   \n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n\n        !*/\n\n        public:\n\n            typedef T type;\n\n            reference_counter (\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            reference_counter ( \n                const reference_counter& item\n            );\n            /*!\n                ensures\n                    - #access() == item.access()\n            !*/\n\n            virtual ~reference_counter (\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear (\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            T& modify (\n            );\n            /*!\n                ensures\n                    - returns a non-const reference to the item contained in *this \n                    - the item is ok to modify.  i.e. there are no other references to it\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        modify() may throw this exception if there are other references\n                        to the item and there is not enough memory to copy it. If modify()\n                        throws then it has no effect.    \n            !*/\n\n            const T& access (\n            ) const;\n            /*!\n                ensures\n                    - returns a const reference to the item contained in *this \n                    - there may be other references to to the item\n            !*/\n\n            reference_counter& operator= (\n                const reference_counter& rhs\n            );\n            /*!\n                ensures\n                    - #access() == rhs.access() \n            !*/\n\n            void swap (\n                reference_counter& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n    };\n\n    template <\n        typename T,\n        typename copy\n        >\n    inline void swap (\n        reference_counter<T,copy>& a, \n        reference_counter<T,copy>& b \n    ) { a.swap(b); }  \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/reference_counter.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_REFERENCE_COUNTEr_\n#define DLIB_REFERENCE_COUNTEr_\n\n#include \"reference_counter/reference_counter_kernel_1.h\"\n#include \"algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename copy = copy_functor<T>\n        >\n    class reference_counter\n    {\n        reference_counter() {}\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     reference_counter_kernel_1<T,copy>    \n                    kernel_1a;\n\n    };\n}\n\n#endif // DLIB_REFERENCE_COUNTEr_\n\n"
  },
  {
    "path": "dlib/revision.h.in",
    "content": "#ifndef DLIB_REVISION_H\n#define DLIB_MAJOR_VERSION  @CPACK_PACKAGE_VERSION_MAJOR@\n#define DLIB_MINOR_VERSION  @CPACK_PACKAGE_VERSION_MINOR@\n#define DLIB_PATCH_VERSION  @CPACK_PACKAGE_VERSION_PATCH@\n#endif\n\n"
  },
  {
    "path": "dlib/scope.h",
    "content": "// Copyright (C) 2023  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SCOPE_H_\n#define DLIB_SCOPE_H_ \n\n#include <utility>\n#include <functional>\n#include <type_traits>\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    template<class Fn>\n    class scope_exit\n    {\n    /*!\n        WHAT THIS OBJECT REPRESENTS \n            This is a standard's compliant backport of std::experimental::scope_exit that works with C++14.\n\n            Therefore, refer to https://en.cppreference.com/w/cpp/experimental/scope_exit for docs on the\n            interface of scope_exit.\n    !*/\n\n    private:\n        Fn f_;\n        bool active_{true};\n\n    public:\n        constexpr scope_exit()                                = delete;\n        constexpr scope_exit(const scope_exit &)              = delete;\n        constexpr scope_exit &operator=(const scope_exit &)   = delete;\n        constexpr scope_exit &operator=(scope_exit &&)        = delete;\n\n        constexpr scope_exit(scope_exit &&other) noexcept(std::is_nothrow_move_constructible<Fn>::value)\n        : f_{std::move(other.f_)}, active_{std::exchange(other.active_, false)}\n        {}\n\n        template<\n        class F, \n        std::enable_if_t<!std::is_same<std::decay_t<F>, scope_exit>::value, bool> = true\n        >\n        explicit scope_exit(F&& f) noexcept(std::is_nothrow_constructible<Fn,F>::value)\n        : f_{std::forward<F>(f)}, active_{true}\n        {}\n    \n        ~scope_exit() noexcept \n        {\n            if (active_)\n                f_();\n        }\n\n        void release() noexcept { active_ = false; }\n    };\n\n    template<class Fn>\n    auto make_scope_exit(Fn&& f)\n    /*!\n        ensures:\n            - This is factory function that wraps the callback in a scope_exit object.\n    !*/\n\n    {\n        return scope_exit<std::decay_t<Fn>>(std::forward<Fn>(f));\n    }\n\n#ifdef __cpp_deduction_guides\n    template<class Fn>\n    scope_exit(Fn) -> scope_exit<Fn>;\n#endif\n\n// ----------------------------------------------------------------------------------------\n\n    using scope_exit_erased = scope_exit<std::function<void()>>;\n    /*!\n        WHAT THIS OBJECT REPRESENTS \n            This is a type erased version of scope_exit. I.e. there is no template parameter.\n            Use this object if you wish to hide the exact function signature, for example\n            if splitting a declaration and definition across a header file and cpp file.\n            This does come at a slight performance penalty since it may incur a heap allocation\n            and due to a pointer indirection, the compiler may not inline your callback.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif //DLIB_SCOPE_H_"
  },
  {
    "path": "dlib/sequence/sequence_compare_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_COMPARe_1_\n#define DLIB_SEQUENCE_COMPARe_1_\n\n#include \"sequence_compare_abstract.h\"\n\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base \n        >\n    class sequence_compare_1 : public seq_base\n    {\n        typedef typename seq_base::type T;\n\n    public:\n\n        bool operator< (\n            const sequence_compare_1& rhs\n        ) const;\n\n        bool operator== (\n            const sequence_compare_1& rhs\n        ) const;\n\n    };\n\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_compare_1<seq_base>& a, \n        sequence_compare_1<seq_base>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    bool sequence_compare_1<seq_base>::\n    operator< (\n        const sequence_compare_1<seq_base>& rhs\n    ) const\n    {\n        unsigned int length;\n        if (this->size() < rhs.size())\n            length = this->size();\n        else\n            length = rhs.size();\n\n        for (unsigned long i = 0; i < length; ++i)\n        {\n            if ((*this)[i] < rhs[i])\n                return true;\n            else if ( !((*this)[i] == rhs[i]) )\n                return false;\n        }\n        // they are equal so far\n        if (this->size() < rhs.size())\n            return true;\n        else\n            return false;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    bool sequence_compare_1<seq_base>::\n    operator== (\n        const sequence_compare_1<seq_base>& rhs\n    ) const\n    {\n        if (this->size() != rhs.size())\n            return false;\n\n        for (unsigned long i = 0; i < this->size(); ++i)\n        {\n            if (!((*this)[i] == rhs[i]))\n                return false;\n        }\n        return true;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEQUENCE_COMPARe_1_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_compare_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SEQUENCE_COMPARe_ABSTRACT_\n#ifdef DLIB_SEQUENCE_COMPARe_ABSTRACT_\n\n#include \"sequence_kernel_abstract.h\"\n\n#include \"../algs.h\"\n\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base\n        >\n    class sequence_compare : public seq_base\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must implement operator< for its type and\n                T must implement operator== for its type\n\n            REQUIREMENTS ON SEQUENCE_BASE\n                must be an implementation of sequence/sequence_kernel_abstract.h\n\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                operator== and operator< do not invalidate pointers or references to \n                data members\n\n            WHAT THIS EXTENSION DOES FOR sequence\n                This gives a sequence the ability to compare itself to other \n                sequences using the < and == operators. \n        !*/\n\n    public:\n\n        bool operator< (\n            const sequence_compare& rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if there exists an integer j such that 0 <= j < size() \n                  and for all integers i such that 0 <= i < j where it is true that\n                  (*this)[i] <= rhs[i] and (*this)[j] < rhs[j] \n                - returns false if there is no j that will satisfy the above conditions\n        !*/\n\n        bool operator== (\n            const sequence_compare& rhs\n        ) const;\n        /*!\n            ensures\n                - returns true if for all i: (*this)[i] == rhs[i] else returns false                   \n        !*/\n\n    };\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_compare<seq_base>& a, \n        sequence_compare<seq_base>& b \n    ) { a.swap(b); } \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_SEQUENCE_COMPARe_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_kernel_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_KERNEl_1_\n#define DLIB_SEQUENCE_KERNEl_1_\n\n#include \"sequence_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class sequence_kernel_1 : public enumerable<T>,\n                              public remover<T>\n    {\n\n        /*!\n            INITIAL VALUE\n                - tree_root == 0\n                - tree_size == 0 \n                - at_start_ == true\n                - current_element == 0\n                - stack == array of 50 node pointers\n                - stack_pos == 0         \n\n            CONVENTION\n                \n                - if (tree_size > 0)\n                    - tree_root == pointer to the root node of the binary search tree\n                - else\n                    - tree_root == 0\n\n\n\n                - stack[stack_pos-1] == pop()\n\n                - current_element_valid() == (current_element != 0)\n                \n                - at_start_ == at_start()\n                - if (current_element != 0 && current_element != tree_root) then\n                    - stack[stack_pos-1] == the parent of the node pointed to by current_element\n\n                - if (current_element_valid()) then\n                    - element() == current_element->item\n\n\n\n                - tree_size == size()\n                - (*this)[i] == return_reference(i)\n\n\n                - for all nodes:\n                    - left_size == the number of elements in the left subtree. \n                    - left points to the left subtree or 0 if there is no left subtree. \n                    - right points to the right subtree or 0 if there is no right subtree. \n\n                    - all elements in a left subtree have a position in the sequence < that \n                      of the root of the current tree. \n\n                    - all elements in a right subtree have a position in the \n                      sequence > that of the root of the current tree.      \n\n                    - item is the sequence element for that node. \n                    - balance:\n                        - balance == 0 if both subtrees have the same height\n                        - balance == -1 if the left subtree has a height that is \n                          greater than the height of the right subtree by 1\n                        - balance == 1 if the right subtree has a height that is \n                          greater than the height of the left subtree by 1\n                    - for all subtrees:\n                        - the height of the left and right subtrees differ by at most one\n\n        !*/\n\n\n        class node\n        {\n        public:\n            node* left;\n            node* right;\n            unsigned long left_size;\n            T item;\n            signed char balance;            \n        };\n\n\n        \n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            sequence_kernel_1 (\n            ) : \n                tree_root(0),\n                tree_size(0),\n                stack(ppool.allocate_array(50)),\n                current_element(0),\n                at_start_(true),\n                stack_pos(0)\n            {}\n\n            virtual ~sequence_kernel_1 (\n            );\n\n            inline void clear (\n            );\n\n            void add (\n                unsigned long pos,\n                T& item\n            );\n\n            void remove (\n                unsigned long pos,\n                T& item\n            );\n\n            void cat (\n                sequence_kernel_1& item\n            );\n\n            const T& operator[] (\n                unsigned long pos\n            ) const;\n            \n            T& operator[] (\n                unsigned long pos\n            );\n\n            inline void swap (\n                sequence_kernel_1& item\n            );\n\n            // functions from the remover interface\n            inline void remove_any (\n                T& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            const T& element (\n            ) const;\n\n            T& element (\n            );\n\n            bool move_next (\n            ) const;\n\n\n        private:\n\n            void delete_nodes (\n                node* t\n            );\n            /*!\n                requires\n                    - t == a pointer to a valid node\n                ensures\n                    - deletes t and all its sub nodes.\n            !*/\n\n            inline void rotate_left (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == 2 \n                    - t->right->balance == 0 or 1\n                ensures\n                    - #t is still a binary search tree \n                    - #t->balance is between 1 and -1 \n                    - #t now has a height smaller by 1 if #t->balance == 0\n            !*/\n\n            inline void rotate_right (\n                node*& t\n            );\n            /*!\n                requires\n                    - t->balance == -2 \n                    - t->left->balance == 0 or -1\n                ensures\n                    - #t is still a binary search tree \n                    - #t->balance is between 1 and -1 \n                    - #t now has a height smaller by 1 if #t->balance == 0\n\n            !*/\n\n            inline void double_rotate_right (\n                node*& t\n            );\n            /*!\n                requires\n                    - #t->balance == -2 \n                    - #t->left->balance == 1\n                ensures\n                    - #t is still a binary search tree \n                    - #t now has a balance of 0 \n                    - #t now has a height smaller by 1             \n            !*/\n\n            inline void double_rotate_left (\n                node*& t\n            );\n            /*!\n                requires\n                    - #t->balance == 2 \n                    - #t->right->balance == -1\n                ensures\n                    - #t is still a binary search tree \n                    - #t now has a balance of 0 and\n                    - #t now has a height smaller by 1\n            !*/\n\n            bool remove_least_element_in_tree (\n                node*& t,\n                T& item\n            );\n            /*!\n                requires\n                    - t != 0  (i.e. there must be something in the tree to remove)\n                ensures\n                    - the least node in t has been removed \n                    - the least node element in t has been put into #item \n                    - #t is still a binary search tree \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            bool add_to_tree (\n                node*& t,\n                unsigned long pos,\n                T& item\n            );\n            /*!\n                requires\n                    - pos <= the number of items in the tree\n                ensures\n                    - item has been added to #t \n                    - #return_reference(pos) == item \n                    - the convention is still satisfied \n                    - #item has an initial value for its type \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has grown by one\n            !*/\n\n            bool remove_from_tree (\n                node*& t,\n                unsigned long pos,\n                T& item\n            );\n            /*!\n                requires\n                    - there is an item in the tree associated with pos\n                ensures\n                    - the element in the tree associated with pos has been removed \n                      and put into #item                                                  \n                    - the convention is still satisfied                                   \n                    - returns false if the height of the tree has not changed \n                    - returns true if the height of the tree has shrunk by one\n            !*/\n\n            const T& return_reference (\n                const node* t,\n                unsigned long pos\n            ) const;\n            /*!\n                requires\n                    - there is an item in the tree associated with pos\n                ensures\n                    - returns a const reference to the item in the tree associated with pos\n            !*/\n\n            T& return_reference (\n                node* t,\n                unsigned long pos\n            );\n            /*!\n                requires\n                    - there is an item in the tree associated with pos\n                ensures\n                    - returns a non-const reference to the item in the tree associated \n                      with pos\n            !*/\n\n            inline bool keep_node_balanced (\n                node*& t\n            );\n            /*!\n                requires\n                    - t != 0\n                ensures\n                    - if (t->balance is < 1 or > 1) then \n                        - keep_node_balanced() will ensure that t->balance == 0, -1, or 1\n                    - returns true if it made the tree one height shorter \n                    - returns false if it didn't change the height\n            !*/\n\n            void push (\n                node* n\n            ) const { stack[stack_pos] = n; ++stack_pos; }\n            /*!\n                ensures\n                    - pushes n onto the stack\n            !*/\n            \n\n            node* pop (\n            ) const { --stack_pos; return stack[stack_pos]; }\n            /*!\n                ensures\n                    - pops the top of the stack and returns it\n            !*/\n\n            // data members\n            typename mem_manager::template rebind<node>::other pool;\n            typename mem_manager::template rebind<node*>::other ppool;\n\n            node* tree_root;\n            unsigned long tree_size;\n\n            mutable node** stack;\n            mutable node* current_element;\n            mutable bool at_start_;\n            mutable unsigned char stack_pos;\n\n            // restricted functions\n            sequence_kernel_1(sequence_kernel_1&);        // copy constructor\n            sequence_kernel_1& operator=(sequence_kernel_1&); // assignment operator        \n\n    };\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        sequence_kernel_1<T,mem_manager>& a, \n        sequence_kernel_1<T,mem_manager>& b \n    ) { a.swap(b); } \n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        sequence_kernel_1<T,mem_manager>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            T temp;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(temp,in);\n                item.add(i,temp);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type sequence_kernel_1\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    sequence_kernel_1<T,mem_manager>::\n    ~sequence_kernel_1 (\n    )\n    {\n        ppool.deallocate_array(stack);\n        if (tree_size > 0)\n        {\n            delete_nodes(tree_root);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    swap (\n        sequence_kernel_1<T,mem_manager>& item\n    )\n    {        \n        exchange(stack,item.stack);\n        exchange(stack_pos,item.stack_pos);\n        \n        pool.swap(item.pool);\n        ppool.swap(item.ppool);\n\n        node* tree_root_temp            = item.tree_root;\n        unsigned long tree_size_temp    = item.tree_size;\n        node* current_element_temp      = item.current_element;\n        bool at_start_temp              = item.at_start_;\n\n        item.tree_root = tree_root;\n        item.tree_size = tree_size;\n        item.current_element = current_element;\n        item.at_start_   = at_start_;\n\n        tree_root = tree_root_temp;\n        tree_size = tree_size_temp;\n        current_element = current_element_temp;\n        at_start_   = at_start_temp;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    size_t sequence_kernel_1<T,mem_manager>::\n    size (\n    ) const\n    {\n        return tree_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& sequence_kernel_1<T,mem_manager>::\n    operator[] (\n        unsigned long pos\n    ) const\n    {\n        return return_reference(tree_root,pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& sequence_kernel_1<T,mem_manager>::\n    operator[] (\n        unsigned long pos\n    )\n    {\n        return return_reference(tree_root,pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    add (\n        unsigned long pos,\n        T& item\n    )\n    {\n        add_to_tree(tree_root,pos,item);\n        ++tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    remove (\n        unsigned long pos,\n        T& item\n    )\n    {\n        remove_from_tree(tree_root,pos,item);\n        --tree_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    cat (\n        sequence_kernel_1<T,mem_manager>& item\n    )\n    {   \n        for (unsigned long i = 0; i < item.tree_size; ++i)\n        {\n            add_to_tree(\n                tree_root,\n                tree_size,\n                return_reference(item.tree_root,i)\n            );\n\n            ++tree_size;\n        }\n\n        item.clear();   \n        // reset the enumerator\n        reset();     \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    clear (\n    )\n    {\n        if (tree_size > 0)\n        {\n            delete_nodes(tree_root);\n            tree_root = 0;\n            tree_size = 0;\n        }    \n        // reset the enumerator\n        reset();    \n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_element = 0;\n        stack_pos = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return (current_element != 0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& sequence_kernel_1<T,mem_manager>::\n    element (\n    ) const\n    {\n        return current_element->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& sequence_kernel_1<T,mem_manager>::\n    element (\n    )\n    {\n        return current_element->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    move_next (\n    ) const\n    {\n        // if we haven't started iterating yet\n        if (at_start_)\n        {\n            at_start_ = false;\n            if (tree_size == 0)\n            {\n                return false;\n            }\n            else\n            {                    \n                // find the first element in the tree\n                current_element = tree_root;\n                node* temp = current_element->left;\n                while (temp != 0)\n                {\n                    push(current_element);\n                    current_element = temp;\n                    temp = current_element->left;\n                }\n                return true;\n            }\n        }\n        else\n        {\n            if (current_element == 0)\n            {\n                return false;\n            }\n            else\n            {\n                node* temp;\n                bool went_up;  // true if we went up the tree from a child node to parent\n                bool from_left = false; // true if we went up and were coming from a left child node\n                // find the next element in the tree\n                if (current_element->right != 0)\n                {\n                    // go right and down    \n                    temp = current_element;\n                    push(current_element);\n                    current_element = temp->right;\n                    went_up = false;\n                }\n                else\n                {\n                    // go up to the parent if we can\n                    if (current_element == tree_root)\n                    {\n                        // in this case we have iterated over all the element of the tree\n                        current_element = 0;\n                        return false;\n                    }\n                    went_up = true;\n                    node* parent = pop();\n\n\n                    from_left = (parent->left == current_element);\n                    // go up to parent\n                    current_element = parent;\n                }\n\n\n                while (true)\n                {\n                    if (went_up)\n                    {\n                        if (from_left)\n                        {\n                            // in this case we have found the next node\n                            break;\n                        }\n                        else\n                        {\n                            if (current_element == tree_root)\n                            {\n                                // in this case we have iterated over all the elements\n                                // in the tree\n                                current_element = 0;\n                                return false;\n                            }\n                            // we should go up\n                            node* parent = pop();\n                            from_left = (parent->left == current_element);                            \n                            current_element = parent;\n                        }\n                    }\n                    else\n                    {\n                        // we just went down to a child node\n                        if (current_element->left != 0)\n                        {\n                            // go left\n                            went_up = false;\n                            temp = current_element;\n                            push(current_element);\n                            current_element = temp->left;\n                        }\n                        else\n                        {\n                            // if there is no left child then we have found the next node\n                            break;\n                        }\n                    }\n                }\n\n                return true;               \n            }\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // remover function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    remove_any (\n        T& item\n    ) \n    {\n        remove(0,item);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    rotate_left (\n        node*& t\n    ) \n    {\n\n        // set the new balance numbers\n        if (t->right->balance == 1)\n        {\n            t->balance = 0;\n            t->right->balance = 0;\n        }\n        else\n        {\n            t->balance = 1;\n            t->right->balance = -1;            \n        }\n\n        // perform the rotation\n        node* temp = t->right;\n        t->right = temp->left;\n        temp->left = t;\n        t = temp;\n\n\n        // set left_size to its correct value\n        t->left_size += t->left->left_size + 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    rotate_right (\n        node*& t\n    ) \n    {\n        // set the new balance numbers\n        if (t->left->balance == -1)\n        {\n            t->balance = 0;\n            t->left->balance = 0;\n        }\n        else\n        {\n            t->balance = -1;\n            t->left->balance = 1;            \n        }\n\n        // preform the rotation\n        node* temp = t->left;\n        t->left = temp->right;\n        temp->right = t;\n        t = temp;    \n\n\n        // set left_size to its correct value\n        t->right->left_size -= t->left_size + 1;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    double_rotate_right (\n        node*& t\n    )\n    {\n\n        node* temp = t;\n        t = t->left->right;\n        \n        temp->left->right = t->left;\n        t->left = temp->left;\n\n        temp->left = t->right;\n        t->right = temp;\n\n        if (t->balance < 0)\n        {  \n            t->left->balance = 0;\n            t->right->balance = 1;\n        }\n        else if (t->balance > 0)\n        {\n            t->left->balance = -1;\n            t->right->balance = 0;\n        }\n        else \n        {\n            t->left->balance = 0;\n            t->right->balance = 0;\n        }\n        t->balance = 0;\n\n\n        // set left_size to its correct value\n        t->left_size += t->left->left_size + 1;\n        t->right->left_size -= t->left_size + 1;\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    double_rotate_left (\n        node*& t\n    )\n    {\n        node* temp = t;\n        t = t->right->left;\n        \n        temp->right->left = t->right;\n        t->right = temp->right;\n\n        temp->right = t->left;\n        t->left = temp;\n\n        if (t->balance < 0)\n        {  \n            t->left->balance = 0;\n            t->right->balance = 1;\n        }\n        else if (t->balance > 0)\n        {\n            t->left->balance = -1;\n            t->right->balance = 0;\n        }\n        else \n        {\n            t->left->balance = 0;\n            t->right->balance = 0;\n        }\n\n        t->balance = 0;\n\n        // set left_size to its correct value\n        t->right->left_size -= t->left_size + 1;\n        t->left_size += t->left->left_size + 1;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    remove_least_element_in_tree (\n        node*& t,\n        T& item\n    ) \n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n\n        // if the left tree is an empty tree\n        if ( tree.left == 0)\n        {\n            // swap nodes element into item\n            exchange(tree.item,item);\n\n            // plug hole left by removing this node\n            t = tree.right;\n\n            // delete the node that was just removed\n            tree.right = 0;\n            delete_nodes(&tree);    \n\n            // return that the height of this part of the tree has decreased\n            return true;\n        }\n        else\n        {\n            // subtract one from the left size\n            --tree.left_size;\n\n            // keep going left\n\n            // if remove made the tree one height shorter\n            if ( remove_least_element_in_tree(tree.left,item) ) \n            {\n                // if this caused the current tree to strink then report that\n                if ( tree.balance == -1)\n                {\n                    ++tree.balance;\n                    return true;\n                }\n                else\n                {\n                    ++tree.balance;\n                    return keep_node_balanced(t);\n                }                \n            }\n\n            return false;            \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    add_to_tree (\n        node*& t,\n        unsigned long pos,\n        T& item\n    ) \n    {\n        // if found place to add\n        if (t == 0)\n        {\n            // create a node to add new item into\n            t = pool.allocate();\n\n            // make a reference to the current node so we don't have to dereference \n            // a pointer a bunch of times\n            node& tree = *t;\n\n\n            // set left and right pointers to 0 to indicate that there are no \n            // left or right subtrees\n            tree.left = 0;\n            tree.right = 0;\n            tree.balance = 0;\n            tree.left_size = 0;\n\n            // put item into t\n            exchange(item,tree.item);\n\n            // indicate that the height of this tree has increased\n            return true;\n        }\n        else  // keep looking for a place to add the new item\n        {\n            // make a reference to the current node so we don't have to dereference \n            // a pointer a bunch of times\n            node& tree = *t;\n            signed char old_balance = tree.balance;\n\n            // add the new item to whatever subtree it should go into\n            if ( pos < tree.left_size + 1 )\n            {\n                tree.balance -= add_to_tree(tree.left,pos,item);\n                ++tree.left_size;\n            }\n            else\n                tree.balance += add_to_tree(tree.right,pos - tree.left_size - 1,item);\n\n\n            // if the tree was balanced to start with\n            if (old_balance == 0)\n            {\n                // if its not balanced anymore then it grew in height\n                if (tree.balance != 0)\n                    return true;\n                else\n                    return false;\n            }\n            else\n            {\n                // if the tree is now balanced then it didn't grow\n                if (tree.balance == 0)\n                {\n                    return false;\n                }\n                else\n                {\n                    // if the tree needs to be balanced\n                    if (tree.balance != old_balance)\n                    {\n                        return !keep_node_balanced(t);\n                    }\n                    // if there has been no change in the heights\n                    else\n                    {\n                        return false;\n                    }\n                }\n            }\n        }  \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    remove_from_tree (\n        node*& t,\n        unsigned long pos,\n        T& item\n    ) \n    {\n        \n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n\n        // if item is on the left\n        if (pos < tree.left_size)\n        {\n            // adjust the left size\n            --tree.left_size;\n\n            // if the left side of the tree has the greatest height\n            if (tree.balance == -1)\n            {\n                tree.balance += remove_from_tree(tree.left,pos,item);\n                return !tree.balance;\n            }\n            else\n            {\n                tree.balance += remove_from_tree(tree.left,pos,item);\n                return keep_node_balanced(t);\n            }\n             \n        }\n        // if item is found\n        else if (pos == tree.left_size)\n        {\n            // if there is no left node\n            if (tree.left == 0)\n            {\n                // swap nodes element into item\n                exchange(tree.item,item);\n\n                // plug hole left by removing this node and free memory\n                t = tree.right;  // plug hole with right subtree\n                \n                // delete old node\n                tree.right = 0;\n                delete_nodes(&tree);  \n\n                // indicate that the height has changed\n                return true;\n            }\n            // if there is no right node\n            else if (tree.right == 0)\n            {\n                // swap nodes element into item\n                exchange(tree.item,item);\n\n                // plug hole left by removing this node and free memory\n                t = tree.left;  // plug hole with left subtree\n\n                // delete old node\n                tree.left = 0;\n                delete_nodes(&tree);  \n\n                // indicate that the height of this tree has changed\n                return true;\n            }\n            // if there are both a left and right sub node\n            else\n            {\n                // get an element that can replace the one being removed and do this \n                // if it made the right subtree shrink by one\n                if (remove_least_element_in_tree(tree.right,item))\n                {\n                    // adjust the tree height\n                    --tree.balance;\n\n                    // put the element into item copy and also plug the \n                    // hole with the smallest element from the right.\n                    exchange(item,tree.item);\n\n                    // if the height of the current tree has dropped by one\n                    if (tree.balance == 0)\n                    {\n                        return true;\n                    }\n                    else\n                    {\n                        return keep_node_balanced(t);\n                    }\n                }\n                // else this remove did not effect the height of this tree\n                else\n                {\n                    // put the element into item copy and also plug the \n                    // hole with the smallest element from the right.\n                    exchange(item,tree.item);\n\n                    return false;\n                }\n\n            }\n        }\n        // if item is on the right\n        else\n        {\n\n            // if the right side of the tree has the greatest height\n            if (tree.balance == 1)\n            {\n                tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);\n                return !tree.balance;\n            }\n            else\n            {\n                tree.balance -= remove_from_tree(tree.right,pos - tree.left_size - 1,item);\n                return keep_node_balanced(t);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& sequence_kernel_1<T,mem_manager>::\n    return_reference (\n        node* t,\n        unsigned long pos\n    ) \n    {\n        while (true)\n        {\n            // if we have found the node\n            if (pos == t->left_size)\n                return t->item;\n            \n            if (pos < t->left_size)\n            {\n                // go left\n                t = t->left;\n            }\n            else\n            {\n                // go right\n                pos -= t->left_size+1;\n                t = t->right;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& sequence_kernel_1<T,mem_manager>::\n    return_reference (\n        const node* t,\n        unsigned long pos\n    ) const\n    {\n        while (true)\n        {\n            // if we have found the node\n            if (pos == t->left_size)\n                return t->item;\n            \n            if (pos < t->left_size)\n            {\n                // go left\n                t = t->left;\n            }\n            else\n            {\n                // go right\n                pos -= t->left_size+1;\n                t = t->right;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_1<T,mem_manager>::\n    keep_node_balanced (\n        node*& t\n    )\n    {\n        // make a reference to the current node so we don't have to dereference \n        // a pointer a bunch of times\n        node& tree = *t;\n \n        // if tree does not need to be balanced then return false\n        if (tree.balance == 0)\n            return false;\n\n\n        // if tree needs to be rotated left\n        if (tree.balance == 2)\n        {\n            if (tree.right->balance >= 0)\n                rotate_left(t);\n            else\n                double_rotate_left(t);\n        }\n        // else if the tree needs to be rotated right\n        else if (tree.balance == -2)\n        {\n            if (tree.left->balance <= 0)\n                rotate_right(t);\n            else\n                double_rotate_right(t);\n        }\n   \n\n        if (t->balance == 0)\n            return true;\n        else\n            return false; \n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_1<T,mem_manager>::\n    delete_nodes (\n        node* t\n    )\n    {\n        if (t->left) \n            delete_nodes(t->left); \n        if (t->right) \n            delete_nodes(t->right); \n        pool.deallocate(t);\n    }\n\n// ----------------------------------------------------------------------------------------\n}\n\n#endif // DLIB_SEQUENCE_KERNEl_1_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_kernel_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_KERNEl_2_\n#define DLIB_SEQUENCE_KERNEl_2_\n\n#include \"sequence_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n\nnamespace dlib\n{\n\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class sequence_kernel_2 : public enumerable<T>,\n                              public remover<T>\n    {\n        /*!\n            INITIAL VALUE\n                sequence_size   == 0 \n                at_start_       == true\n                current_enumeration_node == 0\n\n            CONVENTION\n                sequence_size == the number of elements in the sequence\n\n                at_start_ == at_start()\n                (current_enumeration_node!=0) == current_element_valid()\n                if (current_enumeration_node!=0) then\n                    current_enumeration_node->item == element()\n                    current_enumeration_pos == the position of the node pointed to by\n                                               current_enumeration_node\n\n                if ( sequence_size > 0 )\n                {\n                    current_node        == pointer to a node in the linked list and\n                    current_node->right->right->... eventually == current_node and\n                    current_node->left->left->... eventually == current_node and\n                    current_pos         == the position in the sequence of \n                                           current_node->item\n                }\n\n        !*/\n\n        struct node {\n            T item;\n            node* right;\n            node* left;\n        };\n        \n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            sequence_kernel_2 (\n            ) :\n                sequence_size(0),\n                at_start_(true),\n                current_enumeration_node(0)\n            {}\n\n            virtual ~sequence_kernel_2 (\n            ); \n\n            inline void clear (\n            );\n\n            void add (\n                unsigned long pos,\n                T& item\n            );\n\n            void remove (\n                unsigned long pos,\n                T& item\n            );\n\n            void cat (\n                sequence_kernel_2& item\n            );\n\n            const T& operator[] (\n                unsigned long pos\n            ) const;\n            \n            T& operator[] (\n                unsigned long pos\n            );\n\n            void swap (\n                sequence_kernel_2& item\n            );\n \n            // functions from the remover interface\n            inline void remove_any (\n                T& item\n            );\n\n            // functions from the enumerable interface\n            inline size_t size (\n            ) const;\n\n            bool at_start (\n            ) const;\n\n            inline void reset (\n            ) const;\n\n            bool current_element_valid (\n            ) const;\n\n            const T& element (\n            ) const;\n\n            T& element (\n            );\n\n            bool move_next (\n            ) const;\n\n        private:\n\n            void delete_nodes (\n                node* current_node,\n                unsigned long sequence_size\n            );\n            /*!\n                requires\n                    CONVENTION IS CORRECT\n                ensures\n                    all memory associated with the ring of nodes has been freed\n            !*/\n\n            void move_to_pos (\n                node*& current_node,\n                unsigned long& current_pos,\n                unsigned long pos,\n                unsigned long size\n            ) const;\n            /*!\n                requires\n                    everything in the CONVENTION is correct and\n                    there is a node corresponding to pos in the CONVENTION and\n                    0 <= pos < size\n                ensures\n                    current_pos == pos and\n                    current_node->item is the item in the sequence associated with \n                    position pos\n            !*/\n\n            // data members\n            unsigned long sequence_size;\n            mutable node* current_node;\n            mutable unsigned long current_pos;\n            mutable bool at_start_;\n            mutable node* current_enumeration_node;\n            mutable unsigned long current_enumeration_pos;\n\n            // restricted functions\n            sequence_kernel_2(sequence_kernel_2&);        // copy constructor\n            sequence_kernel_2& operator=(sequence_kernel_2&); // assignment operator        \n\n    };\n\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        sequence_kernel_2<T,mem_manager>& a, \n        sequence_kernel_2<T,mem_manager>& b \n    ) { a.swap(b); }   \n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        sequence_kernel_2<T,mem_manager>& item, \n        std::istream& in\n    )\n    {\n        try\n        {\n            item.clear();\n            unsigned long size;\n            deserialize(size,in);\n            T temp;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(temp,in);\n                item.add(i,temp);\n            }\n        }\n        catch (serialization_error& e)\n        { \n            item.clear();\n            throw serialization_error(e.info + \"\\n   while deserializing object of type sequence_kernel_2\"); \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    sequence_kernel_2<T,mem_manager>::\n    ~sequence_kernel_2 (\n    )\n    {\n        delete_nodes(current_node,sequence_size);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    clear (\n    )\n    {\n        if (sequence_size != 0)\n        {\n            delete_nodes(current_node,sequence_size);\n            sequence_size = 0;\n        }\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    add (\n        unsigned long pos,\n        T& item\n    )\n    {\n        // make new node and swap item into it\n        node* new_node = new node;\n        exchange(item,new_node->item);\n\n        if (sequence_size > 0)\n        {\n            if (pos == sequence_size)\n            {\n                move_to_pos(current_node,current_pos,pos-1,sequence_size);\n                \n                node& n_node = *new_node;\n                node& c_node = *current_node;\n\n                // make new node point to the nodes to its left and right\n                n_node.right = c_node.right;\n                n_node.left  = current_node;\n\n                // make the left node point back to new_node\n                c_node.right->left = new_node;\n\n                // make the right node point back to new_node\n                c_node.right = new_node;\n                current_pos = pos;\n\n            }\n            else\n            {\n                move_to_pos(current_node,current_pos,pos,sequence_size);\n\n                node& n_node = *new_node;\n                node& c_node = *current_node;\n\n                // make new node point to the nodes to its left and right\n                n_node.right = current_node;\n                n_node.left  = c_node.left;\n\n                // make the left node point back to new_node\n                c_node.left->right = new_node;\n\n                // make the right node point back to new_node\n                c_node.left = new_node;\n            }\n            \n        }\n        else\n        {\n            current_pos = 0;\n            new_node->left = new_node;\n            new_node->right = new_node;\n        }\n\n        // make the new node the current node\n        current_node = new_node;    \n    \n        ++sequence_size;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    remove (\n        unsigned long pos,\n        T& item\n    )\n    {\n        move_to_pos(current_node,current_pos,pos,sequence_size);\n        node& c_node = *current_node;\n        exchange(c_node.item,item);\n        \n        node* temp = current_node;\n        \n        // close up gap left by remove\n        c_node.left->right = c_node.right;\n        c_node.right->left = c_node.left;\n\n        current_node = c_node.right;\n\n        --sequence_size;\n\n        delete temp;\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& sequence_kernel_2<T,mem_manager>::\n    operator[] (\n        unsigned long pos\n    ) const\n    {\n        move_to_pos(current_node,current_pos,pos,sequence_size);\n        return current_node->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    cat (\n        sequence_kernel_2<T,mem_manager>& item\n    )\n    {\n        if (item.sequence_size > 0)\n        {\n            if (sequence_size > 0)\n            {\n                // move both sequences to a convenient location\n                move_to_pos(current_node,current_pos,0,sequence_size);\n                item.move_to_pos (\n                    item.current_node,\n                    item.current_pos,\n                    item.sequence_size-1,\n                    item.sequence_size\n                );\n\n                // make copies of poitners\n                node& item_right = *item.current_node->right;\n                node& left = *current_node->left;\n\n\n                item.current_node->right = current_node;\n                current_node->left = item.current_node;\n\n                left.right = &item_right;\n                item_right.left = &left;\n\n                // set sizes\n                sequence_size += item.sequence_size;\n                item.sequence_size = 0;\n            }\n            else\n            {\n                // *this is empty so just swap\n                item.swap(*this);                \n            }\n        }\n        item.clear();\n        // reset the enumerator\n        reset();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& sequence_kernel_2<T,mem_manager>::\n    operator[] (\n        unsigned long pos\n    ) \n    {\n        move_to_pos(current_node,current_pos,pos,sequence_size);\n        return current_node->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    size_t sequence_kernel_2<T,mem_manager>::\n    size (\n    ) const\n    {\n        return sequence_size;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    swap (\n        sequence_kernel_2<T,mem_manager>& item\n    )\n    {\n        unsigned long   sequence_size_temp         = item.sequence_size;\n        node*           current_node_temp          = item.current_node;\n        unsigned long   current_pos_temp           = item.current_pos;\n        bool            at_start_temp              = item.at_start_;\n        node*           current_enumeration_node_temp = item.current_enumeration_node;\n        unsigned long   current_enumeration_pos_temp = item.current_enumeration_pos;\n\n        item.sequence_size  = sequence_size;\n        item.current_node   = current_node;\n        item.current_pos    = current_pos;\n        item.at_start_      = at_start_;\n        item.current_enumeration_node = current_enumeration_node;\n        item.current_enumeration_pos = current_enumeration_pos;\n\n        sequence_size   = sequence_size_temp;\n        current_node    = current_node_temp;\n        current_pos     = current_pos_temp;\n        at_start_       = at_start_temp;\n        current_enumeration_node = current_enumeration_node_temp;\n        current_enumeration_pos = current_enumeration_pos_temp;\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // enumerable function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_2<T,mem_manager>::\n    at_start (\n    ) const\n    {\n        return at_start_;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    reset (\n    ) const\n    {\n        at_start_ = true;\n        current_enumeration_node = 0;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_2<T,mem_manager>::\n    current_element_valid (\n    ) const\n    {\n        return (current_enumeration_node!=0);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    const T& sequence_kernel_2<T,mem_manager>::\n    element (\n    ) const\n    {\n        return current_enumeration_node->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    T& sequence_kernel_2<T,mem_manager>::\n    element (\n    )\n    {\n        return current_enumeration_node->item;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    bool sequence_kernel_2<T,mem_manager>::\n    move_next (\n    ) const\n    {\n        if (at_start_ && sequence_size>0)\n        {            \n            move_to_pos(current_node,current_pos,0,sequence_size);            \n            current_enumeration_node = current_node;\n            current_enumeration_pos = 0;\n        }\n        else if (current_enumeration_node!=0)\n        {\n            ++current_enumeration_pos;\n            if (current_enumeration_pos<sequence_size)\n            {                \n                current_enumeration_node = current_enumeration_node->right;\n            }\n            else\n            {\n                // we have reached the end of the sequence\n                current_enumeration_node = 0;\n            }\n        }\n\n        at_start_ = false;\n        return (current_enumeration_node!=0);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // remover function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    remove_any (\n        T& item\n    ) \n    {\n        remove(0,item);\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n    // private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    delete_nodes (\n        node* current_node,\n        unsigned long sequence_size\n    )\n    {\n        node* temp;\n        while (sequence_size)\n        {\n            temp = current_node->right;\n            delete current_node;\n            current_node = temp;\n            --sequence_size;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void sequence_kernel_2<T,mem_manager>::\n    move_to_pos (\n        node*& current_node,\n        unsigned long& current_pos,\n        unsigned long pos,\n        unsigned long size\n    ) const\n    {\n        if ( current_pos > pos)\n        {\n            // number of hops in each direction needed to reach pos\n            unsigned long right = size + pos - current_pos;\n            unsigned long left = current_pos - pos;\n            current_pos = pos;\n\n            if (left < right)\n            {\n                // move left to position pos\n                for (; left > 0; --left)\n                    current_node = current_node->left;\n            }\n            else\n            {\n                // move left to position pos\n                for (; right > 0; --right)\n                    current_node = current_node->right;\n            }\n        }\n        else if (current_pos != pos)\n        {\n            // number of hops in each direction needed to reach pos\n            unsigned long right = pos - current_pos;\n            unsigned long left = size - pos + current_pos;\n            current_pos = pos;\n\n            if (left < right)\n            {\n                // move left to position pos\n                for (; left > 0; --left)\n                    current_node = current_node->left;\n            }\n            else\n            {\n                // move left to position pos\n                for (; right > 0; --right)\n                    current_node = current_node->right;\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEQUENCE_KERNEl_2_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SEQUENCE_KERNEl_ABSTRACT_\n#ifdef DLIB_SEQUENCE_KERNEl_ABSTRACT_\n\n#include \"../interfaces/enumerable.h\"\n#include \"../interfaces/remover.h\"\n#include \"../serialize.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class sequence : public enumerable<T>,\n                     public remover<T>\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must be swappable by a global swap() and\n                T must have a default constructor\n\n            REQUIREMENTS ON mem_manager\n                must be an implementation of memory_manager/memory_manager_kernel_abstract.h or\n                must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or\n                must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h \n                mem_manager::type can be set to anything.\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                swap() and operator[] functions do not invalidate pointers or \n                references to internal data.\n                All other functions have no such guarantees.\n\n            ENUMERATION ORDER\n                The enumerator will iterate over the elements in the sequence from\n                the 0th element to the (size()-1)th element.\n\n            INITIAL VALUE\n                size() == 0   \n             \n            WHAT THIS OBJECT REPRESENTS\n                sequence contains items of type T\n\n                This object represents an ordered sequence of items, each item is \n                associated with an integer value.   \n                The items are numbered from 0 to size()-1\n\n                Also note that unless specified otherwise, no member functions\n                of this object throw exceptions.\n        !*/\n        \n        public:\n\n            typedef T type;\n            typedef mem_manager mem_manager_type;\n\n            sequence (\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n            !*/\n\n            virtual ~sequence (\n            ); \n            /*!\n                ensures\n                    - all memory associated with *this has been released\n            !*/\n\n            void clear (\n            );\n            /*!\n                ensures\n                    - #*this has its initial value\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if this exception is thrown then *this is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void add (\n                unsigned long pos,\n                T& item\n            );\n            /*!\n                requires\n                    - pos <= size()\n                ensures\n                    - #size() == size() + 1\n                    - #item has an initial value for its type\n                    - #operator[](pos) == item\n                      i.e. item has been inserted into *this between the elements which\n                      were previously at position pos-1 and pos\n                    - #at_start() == true\n                throws\n                    - std::bad_alloc or any exception thrown by T's constructor\n                        if add() throws then it has no effect\n            !*/\n\n            void remove (\n                unsigned long pos,\n                T& item\n            );\n            /*!\n                requires\n                    - pos < size()\n                ensures\n                    - #size() == size() - 1\n                    - the element at the position pos in *this has been removed and \n                      swapped into #item\n                    - #at_start() == true\n            !*/\n\n            void cat (\n                sequence& item\n            );\n            /*!\n                requires\n                    - &item != this  (i.e. you can't concatenate a sequence onto itself)\n                ensures\n                    - item has been concatenated onto the end of *this \n                      i.e. item[0] becomes (#*this)[size()], item[1] \n                      becomes (#*this)[size()+1], etc.\n                    - #size() == size() + item.size() \n                    - #item has its initial value \n                    - #at_start() == true\n            !*/\n\n            const T& operator[] (\n                unsigned long pos\n            ) const;\n            /*!\n                requires\n                    - pos < size()\n                ensures\n                    - returns a const reference to the element at position pos\n            !*/\n            \n            T& operator[] (\n                unsigned long pos\n            );\n            /*!\n                requires\n                    - pos < size()\n                ensures\n                    - returns a non-const reference to the element at position pos\n            !*/\n\n            void swap (\n                sequence& item\n            );\n            /*!\n                ensures\n                    - swaps *this and item\n            !*/ \n\n\n        private:\n\n            // restricted functions\n            sequence(sequence&);        // copy constructor\n            sequence& operator=(sequence&);    // assignment operator        \n\n    };\n\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    inline void swap (\n        sequence<T,mem_manager>& a, \n        sequence<T,mem_manager>& b \n    ) { a.swap(b); }  \n    /*!\n        provides a global swap function\n    !*/\n\n    template <\n        typename T,\n        typename mem_manager\n        >\n    void deserialize (\n        sequence<T,mem_manager>& item, \n        std::istream& in\n    );   \n    /*!\n        provides deserialization support \n    !*/\n}\n\n#endif // DLIB_SEQUENCE_KERNEl_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_kernel_c.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_KERNEl_C_\n#define DLIB_SEQUENCE_KERNEl_C_\n\n#include \"sequence_kernel_abstract.h\"\n#include \"../algs.h\"\n#include \"../assert.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base\n        >\n    class sequence_kernel_c : public seq_base\n    {\n        typedef typename seq_base::type T;\n    public:\n\n\n        void add (\n            unsigned long pos,\n            T& item\n        );\n\n        void remove (\n            unsigned long pos,\n            T& item\n        );\n\n        const T& operator[] (\n            unsigned long pos\n        ) const;\n\n        T& operator[] (\n            unsigned long pos\n        );\n\n        void cat (\n            sequence_kernel_c& item\n        );\n\n        const T& element (\n        ) const;\n\n        T& element (\n        );\n\n        void remove_any (\n            T& item\n        );\n\n    };\n\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_kernel_c<seq_base>& a, \n        sequence_kernel_c<seq_base>& b \n    ) { a.swap(b); }  \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_kernel_c<seq_base>::\n    add(\n        unsigned long pos,\n        T& item\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( pos <= this->size() ), \n                \"\\tvoid sequence::add\"\n                << \"\\n\\tpos must be >= 0 and <= size()\" \n                << \"\\n\\tpos: \" << pos \n                << \"\\n\\tsize(): \" << this->size()\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        seq_base::add(pos,item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_kernel_c<seq_base>::\n    cat (\n        sequence_kernel_c<seq_base>& item\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(&item != this, \n                \"\\tvoid sequence::cat\"\n                << \"\\n\\tyou can't concatenate a sequence onto itself\" \n                << \"\\n\\t&item: \" << &item\n                << \"\\n\\tthis:  \" << this\n        );\n\n        // call the real function\n        seq_base::cat(item);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_kernel_c<seq_base>::\n    remove (\n        unsigned long pos,\n        T& item\n    )\n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( pos < this->size() ), \n                \"\\tvoid sequence::remove\"\n                << \"\\n\\tpos must be >= 0 and < size()\" \n                << \"\\n\\tpos: \" << pos \n                << \"\\n\\tsize(): \" << this->size()\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        seq_base::remove(pos,item);\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    const typename seq_base::type& sequence_kernel_c<seq_base>::\n    operator[] (\n        unsigned long pos\n    ) const\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( pos < this->size() ), \n                \"\\tconst T& sequence::operator[]\"\n                << \"\\n\\tpos must be >= 0 and < size()\" \n                << \"\\n\\tpos: \" << pos \n                << \"\\n\\tsize(): \" << this->size()\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        return seq_base::operator[](pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    typename seq_base::type& sequence_kernel_c<seq_base>::\n    operator[] (\n        unsigned long pos\n    )\n    {\n\n        // make sure requires clause is not broken\n        DLIB_CASSERT(( pos < this->size() ), \n                \"\\tT& sequence::operator[]\"\n                << \"\\n\\tpos must be >= 0 and < size()\" \n                << \"\\n\\tpos: \" << pos \n                << \"\\n\\tsize(): \" << this->size()\n                << \"\\n\\tthis: \" << this\n        );\n\n        // call the real function\n        return seq_base::operator[](pos);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    const typename seq_base::type& sequence_kernel_c<seq_base>::\n    element (\n    ) const\n    {\n        DLIB_CASSERT(this->current_element_valid() == true,\n                \"\\tconst T& sequence::element() const\"\n                << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                << \"\\n\\tthis: \" << this\n        );\n\n        return seq_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    typename seq_base::type& sequence_kernel_c<seq_base>::\n    element (\n    ) \n    {\n        DLIB_CASSERT(this->current_element_valid() == true,\n                \"\\tT& sequence::element()\"\n                << \"\\n\\tyou can't access the current element if it doesn't exist\"\n                << \"\\n\\tthis: \" << this\n        );\n\n        return seq_base::element();\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_kernel_c<seq_base>::\n    remove_any (\n        T& item\n    ) \n    {\n        // make sure requires clause is not broken\n        DLIB_CASSERT( (this->size() > 0),\n                 \"\\tvoid sequence::remove_any\"\n                 << \"\\n\\tsize() must be greater than zero if something is going to be removed\"\n                 << \"\\n\\tsize(): \" << this->size() \n                 << \"\\n\\tthis:   \" << this\n        );\n\n        // call the real function\n        seq_base::remove_any(item);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEQUENCE_KERNEl_C_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_sort_1.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_SORt_1_\n#define DLIB_SEQUENCE_SORt_1_\n\n#include \"sequence_sort_abstract.h\"\n#include \"../algs.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base \n        >\n    class sequence_sort_1 : public seq_base\n    {\n        typedef typename seq_base::type T;\n\n    public:\n\n        /*!\n            this is a median of three version of the QuickSort algorithm and\n            it sorts sequences of less than 30 elements with a selection sort\n        !*/\n\n        void sort (\n        );\n\n    private:\n\n        void sort_this_sequence (\n            seq_base& sequence\n        );\n        /*!\n            ensures\n                - each element in the sequence is < the element behind it\n        !*/\n\n        void selection_sort (\n            seq_base& sequence\n        );\n        /*!\n            ensures\n                - sequence is sorted with a selection_sort\n        !*/\n\n\n    };\n\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_sort_1<seq_base>& a, \n        sequence_sort_1<seq_base>& b \n    ) { a.swap(b); } \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_sort_1<seq_base>::\n    sort (\n    )\n    {\n        if (this->size() > 1)\n        {\n            sort_this_sequence(*this);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// private member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_sort_1<seq_base>::\n    sort_this_sequence (\n        seq_base& sequence\n    )\n    {\n        if (sequence.size() < 30)\n        {\n            selection_sort(sequence);\n        }\n        else \n        {\n            seq_base left, right;\n            T partition_element;\n\n            sequence.remove(0,partition_element);\n\n            dlib::median (\n                partition_element,\n                sequence[sequence.size()-1],\n                sequence[(sequence.size()-1)/2]\n            );\n\n            // partition sequence into left and right\n            T temp;\n            while (sequence.size() > 0)\n            {\n                sequence.remove(0,temp);\n                if (temp < partition_element)\n                {\n                    left.add(0,temp);\n                }\n                else\n                {\n                    right.add(0,temp);\n                }\n            }\n\n            sort_this_sequence(left);\n            sort_this_sequence(right);\n\n            // combine left and right into sequence\n            left.swap(sequence);\n            sequence.add(sequence.size(),partition_element);\n            sequence.cat(right);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_sort_1<seq_base>::\n    selection_sort (\n        seq_base& sequence\n    )\n    {\n        if (sequence.size() > 2)\n        {\n            T temp[29];\n            unsigned long ssize = sequence.size();\n\n            for (unsigned long i = 0; i < ssize; ++i)\n                sequence.remove(0,temp[i]);\n\n            unsigned long smallest;\n            for (unsigned long i = 0; i < ssize - 1; ++i)\n            {    \n                // find smallest element and swap into i\n                smallest = i;\n                for (unsigned long j = i+1; j < ssize; ++j)\n                {\n                    if (temp[j] < temp[smallest])\n                        smallest = j;\n                }\n                exchange(temp[smallest],temp[i]);\n            }\n\n            for (unsigned long i = 0; i < ssize; ++i)\n                sequence.add(i,temp[i]);\n        }\n        else if (sequence.size() == 2)\n        {\n            if (sequence[1] < sequence[0])\n            {\n                exchange(sequence[0],sequence[1]);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEQUENCE_SORt_1_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_sort_2.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCE_SORt_2_\n#define DLIB_SEQUENCE_SORt_2_\n\n#include \"sequence_sort_abstract.h\"\n#include \"../algs.h\"\n#include \"../sort.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base \n        >\n    class sequence_sort_2 : public seq_base\n    {\n        typedef typename seq_base::type T;\n\n    public:\n\n        /*!\n            this is a version of the QuickSort algorithm\n            this uses the dlib::qsort_array function\n        !*/\n\n        void sort (\n        );\n\n\n    };\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_sort_2<seq_base>& a, \n        sequence_sort_2<seq_base>& b \n    ) { a.swap(b); }    \n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// member function definitions\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename seq_base\n        >\n    void sequence_sort_2<seq_base>::\n    sort (\n    )\n    {\n        if (this->size() > 1)\n        {\n            dlib::qsort_array(*this,0,this->size()-1);\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SEQUENCE_SORt_2_\n\n"
  },
  {
    "path": "dlib/sequence/sequence_sort_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SEQUENCE_SORt_ABSTRACT_\n#ifdef DLIB_SEQUENCE_SORt_ABSTRACT_\n\n#include \"sequence_kernel_abstract.h\"\n\nnamespace dlib\n{\n\n    template <\n        typename seq_base\n        >\n    class sequence_sort : public seq_base\n    {\n\n        /*!\n            REQUIREMENTS ON T\n                T must implement operator< for its type\n\n            REQUIREMENTS ON seq_base \n                must be an implementation of sequence/sequence_kernel_abstract.h\n\n\n\n            POINTERS AND REFERENCES TO INTERNAL DATA\n                sort() may invalidate pointers and references to data members.\n\n            WHAT THIS EXTENSION DOES FOR sequence\n                this gives a sequence the ability to sort its contents by calling sort()\n        !*/\n\n\n    public:\n\n        void sort (\n        );\n        /*!\n            ensures\n                - for all elements in #*this the ith element is <= the i+1 element\n                - #at_start() == true\n            throws\n                - std::bad_alloc or any exception thrown by T's constructor\n                    data may be lost if sort() throws\n        !*/\n\n\n    };\n\n\n    template <\n        typename seq_base\n        >\n    inline void swap (\n        sequence_sort<seq_base>& a, \n        sequence_sort<seq_base>& b \n    ) { a.swap(b); } \n    /*!\n        provides a global swap function\n    !*/\n\n}\n\n#endif // DLIB_SEQUENCE_SORt_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/sequence.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SEQUENCe_\n#define DLIB_SEQUENCe_\n\n#include \"sequence/sequence_kernel_1.h\"\n#include \"sequence/sequence_kernel_2.h\"\n#include \"sequence/sequence_kernel_c.h\"\n\n#include \"sequence/sequence_compare_1.h\"\n#include \"sequence/sequence_sort_1.h\"\n#include \"sequence/sequence_sort_2.h\"\n#include \"algs.h\"\n\n\n\n\nnamespace dlib\n{\n\n    template <\n        typename T,\n        typename mem_manager = default_memory_manager\n        >\n    class sequence\n    {\n\n        sequence() {}\n    public:\n        \n        //----------- kernels ---------------\n\n        // kernel_1a        \n        typedef     sequence_kernel_1<T,mem_manager>    \n                    kernel_1a;\n        typedef     sequence_kernel_c<kernel_1a>\n                    kernel_1a_c;\n\n        // kernel_2a\n        typedef     sequence_kernel_2<T,mem_manager>\n                    kernel_2a;\n        typedef     sequence_kernel_c<kernel_2a>\n                    kernel_2a_c;\n\n\n        //---------- extensions ------------\n\n        // compare_1 extend kernel_1a\n        typedef     sequence_compare_1<kernel_1a >\n                    compare_1a;\n        typedef     sequence_compare_1<kernel_1a_c>\n                    compare_1a_c;\n\n        // compare_1 extend kernel_2a\n        typedef     sequence_compare_1<kernel_2a >\n                    compare_1b;\n        typedef     sequence_compare_1<kernel_2a_c>\n                    compare_1b_c;\n\n        \n\n        // sort_1 extend kernel_2a\n        typedef     sequence_sort_1<kernel_2a>\n                    sort_1a;\n        typedef     sequence_sort_1<kernel_2a_c>\n                    sort_1a_c;\n\n        // sort_2 extend kernel_1a\n        typedef     sequence_sort_2<kernel_1a>\n                    sort_2a;\n        typedef     sequence_sort_2<kernel_1a_c>\n                    sort_2a_c;\n\n\n\n\n\n\n    };\n}\n\n#endif // DLIB_SEQUENCe_\n\n"
  },
  {
    "path": "dlib/serialize.h",
    "content": "// Copyright (C) 2005  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERIALIZe_\n#define DLIB_SERIALIZe_\n\n/*!\n    There are two global functions in the dlib namespace that provide serialization and\n    deserialization support.  Their signatures and specifications are as follows:\n        \n        void serialize (\n            const serializable_type& item,\n            std::ostream& out\n        );\n        /!*\n            ensures\n                - writes the state of item to the output stream out\n                - if (serializable_type implements the enumerable interface) then\n                    - item.at_start() == true\n            throws                    \n                - serialization_error\n                    This exception is thrown if there is some problem which prevents\n                    us from successfully writing item to the output stream.\n                - any other exception\n        *!/\n\n        void deserialize (\n            serializable_type& item,\n            std::istream& in\n        );\n        /!*\n            ensures\n                - #item == a deserialized copy of the serializable_type that was\n                  in the input stream in.\n                - Reads all the bytes associated with the serialized serializable_type\n                  contained inside the input stream and no more.  This means you\n                  can serialize multiple objects to an output stream and then read\n                  them all back in, one after another, using deserialize().\n                - if (serializable_type implements the enumerable interface) then\n                    - item.at_start() == true\n            throws                    \n                - serialization_error\n                    This exception is thrown if there is some problem which prevents\n                    us from successfully deserializing item from the input stream.\n                    If this exception is thrown then item will have an initial value \n                    for its type.\n                - any other exception\n        *!/\n\n    For convenience, you can also serialize to a file using this syntax:\n        serialize(\"your_file.dat\") << some_object << another_object;\n\n        // or to a memory buffer.\n        std::vector<char> memory_buffer;\n        serialize(memory_buffer) << some_object << another_object;\n\n        // or some other stream\n        std::ostringstream memory_buffer2;\n        serialize(memory_buffer2) << some_object << another_object;\n\n    That overwrites the contents of your_file.dat with the serialized data from some_object\n    and another_object.  Then to recall the objects from the file you can do:\n        deserialize(\"your_file.dat\") >> some_object >> another_object;\n        // or from a memory buffer or another stream called memory_buffer.\n        deserialize(memory_buffer) >> some_object >> another_object;\n\n    Finally, you can chain as many objects together using the << and >> operators as you\n    like.\n\n\n    This file provides serialization support to the following object types:\n        - The C++ base types (NOT including raw pointer)\n        - std::string\n        - std::wstring\n        - std::vector\n        - std::list\n        - std::forward_list\n        - std::array\n        - std::deque\n        - std::map\n        - std::unordered_map\n        - std::multimap\n        - std::unordered_multimap\n        - std::set\n        - std::unordered_set\n        - std::multiset\n        - std::unordered_multiset\n        - std::pair\n        - std::tuple\n        - std::complex\n        - std::unique_ptr\n        - std::shared_ptr\n        - std::variant (if C++17 is used)\n        - std::optional (if C++17 is used) \n        - dlib::uint64\n        - dlib::int64\n        - float_details\n        - enumerable<T> where T is a serializable type\n        - map_pair<D,R> where D and R are both serializable types.\n        - C style arrays of serializable types\n        - Google protocol buffer objects.\n\n    This file provides deserialization support to the following object types:\n        - The C++ base types (NOT including raw pointers)\n        - std::string\n        - std::wstring\n        - std::vector\n        - std::list\n        - std::forward_list\n        - std::array\n        - std::deque\n        - std::map\n        - std::unordered_map\n        - std::multimap\n        - std::unordered_multimap\n        - std::set\n        - std::unordered_set\n        - std::multiset\n        - std::unordered_multiset\n        - std::pair\n        - std::tuple\n        - std::complex\n        - std::unique_ptr\n        - std::shared_ptr\n        - std::variant (if C++17 is used)\n        - std::optional (if C++17 is used)\n        - dlib::uint64\n        - dlib::int64\n        - float_details\n        - C style arrays of serializable types\n        - Google protocol buffer objects.\n\n    Support for deserialization of objects which implement the enumerable or\n    map_pair interfaces is the responsibility of those objects.  \n    \n    Note that you can deserialize an integer value to any integral type (except for a \n    char type) if its value will fit into the target integer type.  I.e.  the types \n    short, int, long, unsigned short, unsigned int, unsigned long, and dlib::uint64 \n    can all receive serialized data from each other so long as the actual serialized \n    value fits within the receiving integral type's range.\n\n    Also note that for any container to be serializable the type of object it contains \n    must be serializable.\n\n    FILE STREAMS\n        If you are serializing to and from file streams it is important to \n        remember to set the file streams to binary mode using the std::ios::binary\n        flag.  \n\n\n    INTEGRAL SERIALIZATION FORMAT\n        All C++ integral types (except the char types) are serialized to the following\n        format:\n        The first byte is a control byte.  It tells you if the serialized number is \n        positive or negative and also tells you how many of the following bytes are \n        part of the number.  The absolute value of the number is stored in little \n        endian byte order and follows the control byte.\n\n        The control byte:  \n            The high order bit of the control byte is a flag that tells you if the\n            encoded number is negative or not.  It is set to 1 when the number is\n            negative and 0 otherwise.\n            The 4 low order bits of the control byte represent an unsigned number\n            and tells you how many of the following bytes are part of the encoded\n            number.\n\n    bool SERIALIZATION FORMAT\n        A bool value is serialized as the single byte character '1' or '0' in ASCII.\n        Where '1' indicates true and '0' indicates false.\n\n    FLOATING POINT SERIALIZATION FORMAT\n        To serialize a floating point value we convert it into a float_details object and\n        then serialize the exponent and mantissa values using dlib's integral serialization\n        format.  Therefore, the output is first the exponent and then the mantissa.  Note that\n        the mantissa is a signed integer (i.e. there is not a separate sign bit).\n\n\n    MAKING YOUR OWN CUSTOM OBJECTS SERIALIZABLE\n        Suppose you create your own type, my_custom_type, and you want it to be serializable.  I.e.\n        you want to be able to use the tools above to save and load it.  E.g. maybe you have a\n        std::vector<my_custom_type> you wish to save.\n\n        To make my_custom_type properly serializable all you have to do is define global serialize\n        and deserialize functions **IN THE SAME NAMESPACE AS MY_CUSTOM_TYPE**.  You must define them\n        in your namespace so that argument dependent lookup will be able to find them.  So your code\n        might look like this:\n\n            namespace your_namespace \n            {\n                struct my_custom_type\n                {\n                    int a;\n                    float b;\n                    std::vector<float> c;\n                };\n                void serialize (const my_custom_type& item, std::ostream& out);\n                void deserialize (my_custom_type& item, std::istream& in);\n            }\n       \n        That's all you need to do.  You may optionally avail yourself of the\n        DLIB_DEFINE_DEFAULT_SERIALIZATION macro, which generates global friend serialize and\n        deserialize functions for you.  In that case you would do this instead:\n\n            namespace your_namespace \n            {\n                struct my_custom_type\n                {\n                    int a;\n                    float b;\n                    std::vector<float> c;\n\n                    DLIB_DEFINE_DEFAULT_SERIALIZATION(my_custom_type, a, b, c);\n                };\n            }\n\n!*/\n\n\n#include \"algs.h\"\n#include \"assert.h\"\n#include <iomanip>\n#include <cstddef>\n#include <iostream>\n#include <fstream>\n#include <string>\n#include <vector>\n#include <list>\n#include <forward_list>\n#include <array>\n#include <deque>\n#include <complex>\n#include <map>\n#include <unordered_map>\n#include <tuple>\n#include <memory>\n#include <set>\n#include <unordered_set>\n#include <limits>\n#include <type_traits>\n#include <utility>\n#if __cplusplus >= 201703L\n#include <variant>\n#include <optional>\n#endif\n#include \"uintn.h\"\n#include \"interfaces/enumerable.h\"\n#include \"interfaces/map_pair.h\"\n#include \"enable_if.h\"\n#include \"unicode.h\"\n#include \"byte_orderer.h\"\n#include \"float_details.h\"\n#include \"vectorstream.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    class serialization_error : public error \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is the exception object.  It is thrown if serialization or\n                deserialization fails.\n        !*/\n\n    public: \n        serialization_error(const std::string& e):error(e) {}\n    };\n\n\n    void check_serialized_version(\n        const std::string& expected_version, \n        std::istream& in\n    );\n    /*!\n        ensures\n            - Deserializes a string from in and if it doesn't match expected_version we\n              throw serialization_error.\n    !*/\n\n// ----------------------------------------------------------------------------------------\n\n    /*!A ramdump information !*/\n    template <typename T>\n    struct ramdump_t\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is a type decoration used to indicate that serialization should be\n                done by simply dumping the memory of some object to disk as fast as\n                possible without any sort of conversions.  This means that the data written\n                will be \"non-portable\" in the sense that the format output by a RAM dump\n                may depend on things like the endianness of your CPU or settings of certain\n                compiler switches.\n\n                You use this object like this:\n                   serialize(\"yourfile.dat\") << ramdump(yourobject);\n                   deserialize(\"yourfile.dat\") >> ramdump(yourobject);\n                or \n                   serialize(ramdump(yourobject), out);\n                   deserialize(ramdump(yourobject), in);\n\n                Also, not all objects have a ramdump mode.  If you try to use ramdump on an\n                object that does not define a serialization dump for ramdump you will get a\n                compiler error.\n        !*/\n        ramdump_t(T& item_) : item(item_) {}\n        T& item;\n    };\n\n    // This function just makes a ramdump that wraps an object.\n    template <typename T>\n    ramdump_t<typename std::remove_reference<T>::type> ramdump(T&& item) \n    { \n        return ramdump_t<typename std::remove_reference<T>::type>(item); \n    }\n\n\n    template <\n        typename T\n        >\n    void serialize (\n        const ramdump_t<const T>& item_, \n        std::ostream& out\n    )\n    {\n        // Move the const from inside the ramdump_t template to outside so we can bind\n        // against a serialize() call that takes just a const ramdump_t<T>.  Doing this\n        // saves you from needing to write multiple overloads of serialize() to handle\n        // these different const placement cases.\n        const auto temp = ramdump(const_cast<T&>(item_.item));\n        serialize(temp, out);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    namespace ser_helper\n    {\n\n        template <\n            typename T\n            >\n        typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (\n            T item,\n            std::ostream& out\n        )\n        /*!\n            requires\n                - T is a signed integral type\n            ensures\n                - if (no problems occur serializing item) then\n                    - writes item to out\n                    - returns false\n                - else\n                    - returns true\n        !*/\n        {\n            COMPILE_TIME_ASSERT(sizeof(T) <= 8);\n            unsigned char buf[9];\n            unsigned char size = sizeof(T);\n            unsigned char neg;\n            if (item < 0)\n            {\n                neg = 0x80;\n                item *= -1;\n            }\n            else\n            {\n                neg = 0;\n            }\n\n            for (unsigned char i = 1; i <= sizeof(T); ++i)\n            {\n                buf[i] = static_cast<unsigned char>(item&0xFF);                \n                item >>= 8;\n                if (item == 0) { size = i; break; }\n            }\n\n            std::streambuf* sbuf = out.rdbuf();\n            buf[0] = size|neg;\n            if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)\n            {\n                out.setstate(std::ios::eofbit | std::ios::badbit);\n                return true;\n            }\n\n            return false;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        typename enable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (\n            T& item,\n            std::istream& in\n        )\n        /*!\n            requires\n                - T is a signed integral type\n            ensures\n                - if (there are no problems deserializing item) then\n                    - returns false\n                    - #item == the value stored in in\n                - else\n                    - returns true\n\n        !*/\n        {\n            COMPILE_TIME_ASSERT(sizeof(T) <= 8);\n\n\n            unsigned char buf[8];\n            unsigned char size;\n            bool is_negative;\n\n            std::streambuf* sbuf = in.rdbuf();\n\n            item = 0;\n            int ch = sbuf->sbumpc();\n            if (ch != EOF)\n            {\n                size = static_cast<unsigned char>(ch);\n            }\n            else\n            {\n                in.setstate(std::ios::badbit);\n                return true;\n            }\n\n            if (size&0x80)\n                is_negative = true;\n            else\n                is_negative = false;\n            size &= 0x0F;\n            \n            // check if the serialized object is too big\n            if (size > (unsigned long)tmin<sizeof(T),8>::value || size == 0)\n            {\n                return true;\n            }\n\n            if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)\n            {\n                in.setstate(std::ios::badbit);\n                return true;\n            }\n\n\n            for (unsigned char i = size-1; true; --i)\n            {\n                item <<= 8;\n                item |= buf[i];\n                if (i == 0)\n                    break;\n            }\n\n            if (is_negative)\n                item *= -1;\n        \n\n            return false;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type pack_int (\n            T item,\n            std::ostream& out\n        )\n        /*!\n            requires\n                - T is an unsigned integral type\n            ensures\n                - if (no problems occur serializing item) then\n                    - writes item to out\n                    - returns false\n                - else\n                    - returns true\n        !*/\n        {\n            COMPILE_TIME_ASSERT(sizeof(T) <= 8);\n            unsigned char buf[9];\n            unsigned char size = sizeof(T);\n\n            for (unsigned char i = 1; i <= sizeof(T); ++i)\n            {\n                buf[i] = static_cast<unsigned char>(item&0xFF);                \n                item >>= 8;\n                if (item == 0) { size = i; break; }\n            }\n\n            std::streambuf* sbuf = out.rdbuf();\n            buf[0] = size;\n            if (sbuf->sputn(reinterpret_cast<char*>(buf),size+1) != size+1)\n            {\n                out.setstate(std::ios::eofbit | std::ios::badbit);\n                return true;\n            }\n\n            return false;\n        }\n\n    // ------------------------------------------------------------------------------------\n\n        template <\n            typename T\n            >\n        typename disable_if_c<std::numeric_limits<T>::is_signed,bool>::type unpack_int (\n            T& item,\n            std::istream& in\n        )\n        /*!\n            requires\n                - T is an unsigned integral type\n            ensures\n                - if (there are no problems deserializing item) then\n                    - returns false\n                    - #item == the value stored in in\n                - else\n                    - returns true\n\n        !*/\n        {\n            COMPILE_TIME_ASSERT(sizeof(T) <= 8);\n\n            unsigned char buf[8];\n            unsigned char size;\n\n            item = 0;\n\n            std::streambuf* sbuf = in.rdbuf();\n            int ch = sbuf->sbumpc();\n            if (ch != EOF)\n            {\n                size = static_cast<unsigned char>(ch);\n            }\n            else\n            {\n                in.setstate(std::ios::badbit);\n                return true;\n            }\n\n\n            // mask out the 3 reserved bits\n            size &= 0x8F;\n\n            // check if an error occurred \n            if (size > (unsigned long)tmin<sizeof(T),8>::value || size == 0)\n                return true;\n           \n\n            if (sbuf->sgetn(reinterpret_cast<char*>(&buf),size) != size)\n            {\n                in.setstate(std::ios::badbit);\n                return true;\n            }\n\n            for (unsigned char i = size-1; true; --i)\n            {\n                item <<= 8;\n                item |= buf[i];\n                if (i == 0)\n                    break;\n            }\n\n            return false;\n        }\n\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    #define USE_DEFAULT_INT_SERIALIZATION_FOR(T)  \\\n        inline void serialize (const T& item, std::ostream& out) \\\n        { if (ser_helper::pack_int(item,out)) throw serialization_error(\"Error serializing object of type \" + std::string(#T)); }   \\\n        inline void deserialize (T& item, std::istream& in) \\\n        { if (ser_helper::unpack_int(item,in)) throw serialization_error(\"Error deserializing object of type \" + std::string(#T)); }   \n\n    template <typename T>\n    inline bool pack_byte (\n        const T& ch,\n        std::ostream& out\n    )\n    {\n        std::streambuf* sbuf = out.rdbuf();\n        return (sbuf->sputc((char)ch) == EOF);\n    }\n\n    template <typename T>\n    inline bool unpack_byte (\n        T& ch,\n        std::istream& in\n    )\n    {\n        std::streambuf* sbuf = in.rdbuf();\n        int temp = sbuf->sbumpc();\n        if (temp != EOF)\n        {\n            ch = static_cast<T>(temp);\n            return false;\n        }\n        else\n        {\n            return true;\n        }\n    }\n\n    #define USE_DEFAULT_BYTE_SERIALIZATION_FOR(T)  \\\n        inline void serialize (const T& item,std::ostream& out) \\\n        { if (pack_byte(item,out)) throw serialization_error(\"Error serializing object of type \" + std::string(#T)); } \\\n        inline void deserialize (T& item, std::istream& in) \\\n        { if (unpack_byte(item,in)) throw serialization_error(\"Error deserializing object of type \" + std::string(#T)); }   \n\n// ----------------------------------------------------------------------------------------\n\n    USE_DEFAULT_INT_SERIALIZATION_FOR(short)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(int)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(long)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned short)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned int)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(unsigned long)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(uint64)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(int64)\n    USE_DEFAULT_INT_SERIALIZATION_FOR(char32_t)\n\n    USE_DEFAULT_BYTE_SERIALIZATION_FOR(char)\n    USE_DEFAULT_BYTE_SERIALIZATION_FOR(signed char)\n    USE_DEFAULT_BYTE_SERIALIZATION_FOR(unsigned char)\n\n    // Don't define serialization for wchar_t when using visual studio and\n    // _NATIVE_WCHAR_T_DEFINED isn't defined since if it isn't they improperly set\n    // wchar_t to be a typedef rather than its own type as required by the C++ \n    // standard.\n#if !defined(_MSC_VER) || _NATIVE_WCHAR_T_DEFINED\n    USE_DEFAULT_INT_SERIALIZATION_FOR(wchar_t)\n#endif\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize(\n        const float_details& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.mantissa, out);\n        serialize(item.exponent, out);\n    }\n\n    inline void deserialize(\n        float_details& item,\n        std::istream& in \n    )\n    {\n        deserialize(item.mantissa, in);\n        deserialize(item.exponent, in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    inline void serialize_floating_point (\n        const T& item,\n        std::ostream& out\n    )\n    { \n        try\n        {\n            float_details temp = item;\n            serialize(temp, out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing a floating point number.\"); }\n    }\n\n    template <typename T>\n    inline bool old_deserialize_floating_point (\n        T& item,\n        std::istream& in \n    )\n    {\n        std::ios::fmtflags oldflags = in.flags();  \n        in.flags(static_cast<std::ios_base::fmtflags>(0));\n        std::streamsize ss = in.precision(35); \n        if (in.peek() == 'i')\n        {\n            item = std::numeric_limits<T>::infinity();\n            in.get();\n            in.get();\n            in.get();\n        }\n        else if (in.peek() == 'n')\n        {\n            item = -std::numeric_limits<T>::infinity();\n            in.get();\n            in.get();\n            in.get();\n            in.get();\n        }\n        else if (in.peek() == 'N')\n        {\n            item = std::numeric_limits<T>::quiet_NaN();\n            in.get();\n            in.get();\n            in.get();\n        }\n        else\n        {\n            in >> item; \n        }\n        in.flags(oldflags); \n        in.precision(ss); \n        return (in.get() != ' ');\n    }\n\n    template <typename T>\n    inline void deserialize_floating_point (\n        T& item,\n        std::istream& in \n    )\n    {\n        // check if the serialized data uses the older ASCII based format.  We can check\n        // this easily because the new format starts with the integer control byte which\n        // always has 0 bits in the positions corresponding to the bitmask 0x70.  Moreover,\n        // since the previous format used ASCII numbers we know that no valid bytes can\n        // have bit values of one in the positions indicated 0x70.  So this test looks at\n        // the first byte and checks if the serialized data uses the old format or the new\n        // format.\n        if ((in.rdbuf()->sgetc()&0x70) == 0)\n        {\n            try\n            {\n                // Use the fast and compact binary serialization format.\n                float_details temp;\n                deserialize(temp, in);\n                item = temp;\n            }\n            catch (serialization_error& e)\n            { throw serialization_error(e.info + \"\\n   while deserializing a floating point number.\"); }\n        }\n        else\n        {\n            if (old_deserialize_floating_point(item, in))\n                throw serialization_error(\"Error deserializing a floating point number.\");\n        }\n    }\n\n    inline void serialize ( const float& item, std::ostream& out) \n    { \n        serialize_floating_point(item,out);\n    }\n\n    inline void deserialize (float& item, std::istream& in) \n    { \n        deserialize_floating_point(item,in);\n    }\n\n    inline void serialize ( const double& item, std::ostream& out) \n    { \n        serialize_floating_point(item,out);\n    }\n\n    inline void deserialize (double& item, std::istream& in) \n    { \n        deserialize_floating_point(item,in);\n    }\n\n    inline void serialize ( const long double& item, std::ostream& out) \n    { \n        serialize_floating_point(item,out);\n    }\n\n    inline void deserialize ( long double& item, std::istream& in) \n    { \n        deserialize_floating_point(item,in);\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    inline void serialize (\n        const std::complex<T>& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.real(),out);\n            serialize(item.imag(),out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing an object of type std::complex\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    inline void deserialize (\n        std::complex<T>& item,\n        std::istream& in\n    )\n    {\n        try\n        {\n            T real, imag;\n            deserialize(real,in); \n            deserialize(imag,in); \n            item = std::complex<T>(real,imag);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing an object of type std::complex\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n// prototypes\n\n    template <typename domain, typename range, typename compare, typename alloc>\n    void serialize (\n        const std::map<domain,range, compare, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename range, typename compare, typename alloc>\n    void deserialize (\n        std::map<domain, range, compare, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_map<domain, range, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_map<domain, range, hash, keyEqual, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename range, typename compare, typename alloc>\n    void serialize (\n        const std::multimap<domain,range, compare, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename range, typename compare, typename alloc>\n    void deserialize (\n        std::multimap<domain, range, compare, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,\n        std::istream& in\n    );\n\n    template <typename domain, typename compare, typename alloc>\n    void serialize (\n        const std::set<domain, compare, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename compare, typename alloc>\n    void deserialize (\n        std::set<domain, compare, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_set<domain, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_set<domain, hash, keyEqual, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename compare, typename alloc>\n    void serialize (\n        const std::multiset<domain, compare, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename compare, typename alloc>\n    void deserialize (\n        std::multiset<domain, compare, alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_multiset<domain, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_multiset<domain, hash, keyEqual, alloc>& item,\n        std::istream& in\n    );\n\n    template <typename T, typename alloc>\n    void serialize (\n        const std::vector<T,alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::vector<T,alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename T, typename alloc>\n    void serialize (\n        const std::list<T,alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::list<T,alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename T, typename alloc>\n    void serialize (\n        const std::forward_list<T,alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::forward_list<T,alloc>& item,\n        std::istream& in\n    );\n\n    template <typename T, typename alloc>\n    void serialize (\n        const std::deque<T,alloc>& item,\n        std::ostream& out\n    );\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::deque<T,alloc>& item,\n        std::istream& in\n    );\n    \n    template <typename... Types>\n    void serialize (\n        const std::tuple<Types...>& item,\n        std::ostream& out\n    );\n\n    template <typename... Types>\n    void deserialize (\n        std::tuple<Types...>& item,\n        std::istream& in\n    );\n\n    template <typename T, typename deleter>\n    void serialize (\n        const std::unique_ptr<T, deleter>& item,\n        std::ostream& out\n    );\n\n    template <typename T, typename deleter>\n    void deserialize (\n        std::unique_ptr<T, deleter>& item,\n        std::istream& in\n    );\n    \n    template <typename T>\n    void serialize (\n        const std::shared_ptr<T>& item,\n        std::ostream& out\n    );\n\n    template <typename T>\n    void deserialize (\n        std::shared_ptr<T>& item,\n        std::istream& in\n    );\n    \n    inline void serialize (\n        const std::string& item,\n        std::ostream& out\n    );\n\n    inline void deserialize (\n        std::string& item,\n        std::istream& in\n    );\n\n    inline void serialize (\n        const std::wstring& item,\n        std::ostream& out\n    );\n\n    inline void deserialize (\n        std::wstring& item,\n        std::istream& in\n    );\n\n    inline void serialize (\n        const ustring& item,\n        std::ostream& out\n    );\n\n    inline void deserialize (\n        ustring& item,\n        std::istream& in\n    );\n\n    template <\n        typename T\n        >\n    inline void serialize (\n        const enumerable<T>& item,\n        std::ostream& out\n    );\n\n    template <\n        typename domain,\n        typename range\n        >\n    inline void serialize (\n        const map_pair<domain,range>& item,\n        std::ostream& out\n    );\n\n    template <\n        typename T,\n        size_t length\n        >\n    inline void serialize (\n        const T (&array)[length],\n        std::ostream& out\n    );\n\n    template <\n        typename T,\n        size_t length\n        >\n    inline void deserialize (\n        T (&array)[length],\n        std::istream& in\n    );\n\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        bool item,\n        std::ostream& out\n    )\n    {\n        if (item)\n            out << '1';\n        else\n            out << '0';\n\n        if (!out) \n            throw serialization_error(\"Error serializing object of type bool\");    \n    }\n\n    inline void deserialize (\n        bool& item,\n        std::istream& in\n    )\n    {\n        int ch = in.get();\n        if (ch != EOF)\n        {\n            if (ch == '1')\n                item = true;\n            else if (ch == '0')\n                item = false;\n            else\n                throw serialization_error(\"Error deserializing object of type bool\");    \n        }\n        else\n        {\n            throw serialization_error(\"Error deserializing object of type bool\");    \n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename first_type, typename second_type>\n    void serialize (\n        const std::pair<first_type, second_type>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.first,out); \n            serialize(item.second,out); \n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::pair\"); }\n    }\n\n    template <typename first_type, typename second_type>\n    void deserialize (\n        std::pair<first_type, second_type>& item,\n        std::istream& in \n    )\n    {\n        try\n        { \n            deserialize(item.first,in); \n            deserialize(item.second,in); \n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::pair\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename... Types>\n    void serialize (\n        const std::tuple<Types...>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            for_each_in_tuple(item, [&](auto&& x) {\n                serialize(x, out);\n            });\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::tuple\"); }\n    }\n\n    template <typename... Types>\n    void deserialize (\n        std::tuple<Types...>& item,\n        std::istream& in\n    )\n    {\n        try\n        { \n            for_each_in_tuple(item, [&](auto&& x) {\n                deserialize(x, in);\n            });\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::tuple\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n#if __cplusplus >= 201703L\n    \n    namespace detail\n    {\n        template<typename Variant, std::size_t I = 0>\n        void deserialize_variant_helper(Variant& item, std::istream& in, std::size_t index)\n        {\n            if constexpr (I < std::variant_size_v<Variant>)\n            {\n                if (I == index)\n                {\n                    auto& x = item.template emplace<std::variant_alternative_t<I,Variant>>();\n                    deserialize(x, in);\n                }\n                else\n                {\n                    deserialize_variant_helper<Variant, I+1>(item, in, index);\n                }\n            }\n            else\n            {\n                throw serialization_error(\"deserialize_variant_helper() index is out of range of variant size\");\n            }\n        }\n    }\n    \n    template<typename... Types>\n    void serialize(\n        const std::variant<Types...>& item,\n        std::ostream& out\n    )\n    {\n        serialize(item.index(),  out);\n        std::visit([&out](const auto& x) {\n            serialize(x, out);\n        }, item);\n    }\n    \n    template <typename... Types>\n    void deserialize(\n        std::variant<Types...>& item,\n        std::istream& in\n    )\n    {\n        std::size_t index = 0;\n        deserialize(index, in);\n        detail::deserialize_variant_helper(item, in, index);\n    }\n    \n    template<typename T>\n    void serialize(const std::optional<T>& item, std::ostream& out)\n    {\n        serialize(item.has_value(), out);\n        if (item)\n            serialize(item.value(), out);\n    }\n    \n    template <typename T>\n    void deserialize(std::optional<T>& item, std::istream& in)\n    {\n        bool has_value = false;\n        deserialize(has_value, in);\n        if (has_value)\n        {\n            deserialize(item.has_value() ? item.value() : item.emplace(), in);\n        }\n        else\n        {\n            item.reset();\n        }\n    }\n    \n#endif\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename domain, typename range, typename compare, typename alloc>\n    void serialize (\n        const std::map<domain,range, compare, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n\n            serialize(size,out); \n            typename std::map<domain,range,compare,alloc>::const_iterator i;\n            for (i = item.begin(); i != item.end(); ++i)\n            {\n                serialize(i->first,out);\n                serialize(i->second,out);\n            }\n\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::map\"); }\n    }\n\n    template <typename domain, typename range, typename compare, typename alloc>\n    void deserialize (\n        std::map<domain, range, compare, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n\n            unsigned long size;\n            deserialize(size,in); \n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item[d] = r;\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::map\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_map<domain, range, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n            {\n                serialize(x.first,out);\n                serialize(x.second,out);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::unordered_map\"); }\n    }\n\n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_map<domain, range, hash, keyEqual, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item[d] = r;\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::unordered_map\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename domain, typename range, typename compare, typename alloc>\n    void serialize (\n        const std::multimap<domain,range, compare, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n            {\n                serialize(x.first,out);\n                serialize(x.second,out);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::multimap\"); }\n    }\n\n    template <typename domain, typename range, typename compare, typename alloc>\n    void deserialize (\n        std::multimap<domain, range, compare, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.insert({d,r});\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::multimap\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n            {\n                serialize(x.first,out);\n                serialize(x.second,out);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::unordered_multimap\"); }\n    }\n\n    template <typename domain, typename range, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_multimap<domain, range, hash, keyEqual, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            range r;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                deserialize(r,in);\n                item.insert({d,r});\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::unordered_multimap\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n   \n    template <typename domain, typename compare, typename alloc>\n    void serialize (\n        const std::set<domain, compare, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n\n            serialize(size,out); \n            typename std::set<domain,compare,alloc>::const_iterator i;\n            for (i = item.begin(); i != item.end(); ++i)\n            {\n                serialize(*i,out);\n            }\n\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::set\"); }\n    }\n\n    template <typename domain, typename compare, typename alloc>\n    void deserialize (\n        std::set<domain, compare, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n\n            unsigned long size;\n            deserialize(size,in); \n            domain d;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                item.insert(d);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::set\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_set<domain, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n                serialize(x,out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::unordered_set\"); }\n    }\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_set<domain, hash, keyEqual, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                item.insert(d);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::unordered_set\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename domain, typename compare, typename alloc>\n    void serialize (\n        const std::multiset<domain, compare, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n                serialize(x,out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::multiset\"); }\n    }\n\n    template <typename domain, typename compare, typename alloc>\n    void deserialize (\n        std::multiset<domain, compare, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                item.insert(d);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::multiset\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void serialize (\n        const std::unordered_multiset<domain, hash, keyEqual, alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            serialize(item.size(),out); \n            for (const auto& x : item)\n                serialize(x,out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::unordered_multiset\"); }\n    }\n\n    template <typename domain, typename hash, typename keyEqual, typename alloc>\n    void deserialize (\n        std::unordered_multiset<domain, hash, keyEqual, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            item.clear();\n            std::size_t size;\n            deserialize(size,in); \n            domain d;\n            for (unsigned long i = 0; i < size; ++i)\n            {\n                deserialize(d,in);\n                item.insert(d);\n            }\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::unordered_multiset\"); }\n    }\n        \n// ----------------------------------------------------------------------------------------\n\n    template <typename alloc>\n    void serialize (\n        const std::vector<bool,alloc>& item,\n        std::ostream& out\n    )\n    {\n        std::vector<unsigned char> temp(item.size());\n        for (unsigned long i = 0; i < item.size(); ++i)\n        {\n            if (item[i])\n                temp[i] = '1';\n            else\n                temp[i] = '0';\n        }\n        serialize(temp, out);\n    }\n\n    template <typename alloc>\n    void deserialize (\n        std::vector<bool,alloc>& item,\n        std::istream& in \n    )\n    {\n        std::vector<unsigned char> temp;\n        deserialize(temp, in);\n        item.resize(temp.size());\n        for (unsigned long i = 0; i < temp.size(); ++i)\n        {\n            if (temp[i] == '1')\n                item[i] = true;\n            else\n                item[i] = false;\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc>\n    void serialize (\n        const std::vector<T,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n\n            serialize(size,out); \n            for (unsigned long i = 0; i < item.size(); ++i)\n                serialize(item[i],out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::vector\"); }\n    }\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::vector<T, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size,in); \n            item.resize(size);\n            for (unsigned long i = 0; i < size; ++i)\n                deserialize(item[i],in);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::vector\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename alloc>\n    void serialize (\n        const std::vector<char,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n            serialize(size,out); \n            if (item.size() != 0)\n                out.write(&item[0], item.size());\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::vector\"); }\n    }\n\n    template <typename alloc>\n    void deserialize (\n        std::vector<char, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size,in); \n            item.resize(size);\n            if (item.size() != 0)\n                in.read(&item[0], item.size());\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::vector\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename alloc>\n    void serialize (\n        const std::vector<unsigned char,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n            serialize(size,out); \n            if (item.size() != 0)\n                out.write((char*)&item[0], item.size());\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::vector\"); }\n    }\n\n    template <typename alloc>\n    void deserialize (\n        std::vector<unsigned char, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size,in); \n            item.resize(size);\n            if (item.size() != 0)\n                in.read((char*)&item[0], item.size());\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::vector\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename alloc>\n    void serialize (\n        const std::list<T,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n            serialize(size,out); \n            for (const auto& x : item)\n                serialize(x, out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::list\"); }\n    }\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::list<T,alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size, in);\n            item.resize(size);\n            for (auto& x : item)\n                deserialize(x, in);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::list\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename T, typename alloc>\n    void serialize (\n        const std::forward_list<T,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = std::distance(item.begin(), item.end());\n            serialize(size,out); \n            for (const auto& x : item)\n                serialize(x, out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::forward_list\"); }\n    }\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::forward_list<T,alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size,in); \n            item.resize(size);\n            for (auto& x : item)\n                deserialize(x,in);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::forward_list\"); }\n    }\n    \n// ----------------------------------------------------------------------------------------\n    \n    template <typename T, typename alloc>\n    void serialize (\n        const std::deque<T,alloc>& item,\n        std::ostream& out\n    )\n    {\n        try\n        { \n            const unsigned long size = static_cast<unsigned long>(item.size());\n\n            serialize(size,out); \n            for (unsigned long i = 0; i < item.size(); ++i)\n                serialize(item[i],out);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::deque\"); }\n    }\n\n    template <typename T, typename alloc>\n    void deserialize (\n        std::deque<T, alloc>& item,\n        std::istream& in\n    )\n    {\n        try \n        { \n            unsigned long size;\n            deserialize(size,in); \n            item.resize(size);\n            for (unsigned long i = 0; i < size; ++i)\n                deserialize(item[i],in);\n        }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::deque\"); }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const std::string& item,\n        std::ostream& out\n    )\n    {\n        const unsigned long size = static_cast<unsigned long>(item.size());\n        try{ serialize(size,out); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::string\"); }\n\n        out.write(item.c_str(),size);\n        if (!out) throw serialization_error(\"Error serializing object of type std::string\");\n    }\n\n    inline void deserialize (\n        std::string& item,\n        std::istream& in\n    )\n    {\n        unsigned long size;\n        try { deserialize(size,in); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::string\"); }\n\n        item.resize(size);\n        if (size != 0)\n        {\n            in.read(&item[0],size);\n            if (!in) throw serialization_error(\"Error deserializing object of type std::string\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const std::wstring& item,\n        std::ostream& out\n    )\n    {\n        const unsigned long size = static_cast<unsigned long>(item.size());\n        try{ serialize(size,out); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type std::wstring\"); }\n\n        for (unsigned long i = 0; i < item.size(); ++i)\n            serialize(item[i], out);\n        if (!out) throw serialization_error(\"Error serializing object of type std::wstring\");\n    }\n\n    inline void deserialize (\n        std::wstring& item,\n        std::istream& in\n    )\n    {\n        unsigned long size;\n        try { deserialize(size,in); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type std::wstring\"); }\n\n        item.resize(size);\n        for (unsigned long i = 0; i < item.size(); ++i)\n            deserialize(item[i],in);\n\n        if (!in) throw serialization_error(\"Error deserializing object of type std::wstring\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void serialize (\n        const ustring& item,\n        std::ostream& out\n    )\n    {\n        const unsigned long size = static_cast<unsigned long>(item.size());\n        try{ serialize(size,out); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while serializing object of type ustring\"); }\n\n        for (unsigned long i = 0; i < item.size(); ++i)\n            serialize(item[i], out);\n        if (!out) throw serialization_error(\"Error serializing object of type ustring\");\n    }\n\n    inline void deserialize (\n        ustring& item,\n        std::istream& in\n    )\n    {\n        unsigned long size;\n        try { deserialize(size,in); }\n        catch (serialization_error& e)\n        { throw serialization_error(e.info + \"\\n   while deserializing object of type ustring\"); }\n\n        item.resize(size);\n        for (unsigned long i = 0; i < item.size(); ++i)\n            deserialize(item[i],in);\n\n        if (!in) throw serialization_error(\"Error deserializing object of type ustring\");\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T\n        >\n    inline void serialize (\n        const enumerable<T>& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            item.reset();\n            serialize(item.size(),out);\n            while (item.move_next())\n                serialize(item.element(),out);\n            item.reset();\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type enumerable\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename domain,\n        typename range\n        >\n    inline void serialize (\n        const map_pair<domain,range>& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(item.key(),out);\n            serialize(item.value(),out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing object of type map_pair\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        size_t length\n        >\n    inline void serialize (\n        const T (&array)[length],\n        std::ostream& out\n    )\n    {\n        try\n        {\n            serialize(length,out);\n            for (size_t i = 0; i < length; ++i)\n                serialize(array[i],out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing a C style array\");\n        }\n    }\n\n    template <\n        size_t length\n        >\n    inline void serialize (\n        const char (&array)[length],\n        std::ostream& out\n    )\n    {\n        if (length != 0 && array[length-1] == '\\0')\n        {\n            // If this is a null terminated string then don't serialize the trailing null.\n            // We do this so that the serialization format for C-strings is the same as\n            // std::string.\n            serialize(length-1, out);\n            out.write(array, length-1);\n            if (!out)\n                throw serialization_error(\"Error serializing a C-style string\");\n        }\n        else \n        {\n            try\n            {\n                serialize(length,out);\n            }\n            catch (serialization_error& e)\n            {\n                throw serialization_error(e.info + \"\\n   while serializing a C style array\");\n            }\n            if (length != 0)\n                out.write(array, length);\n            if (!out)\n                throw serialization_error(\"Error serializing a C-style string\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        size_t length\n        >\n    inline void deserialize (\n        T (&array)[length],\n        std::istream& in\n    )\n    {\n        size_t size;\n        try\n        {\n            deserialize(size,in); \n            if (size == length)\n            {\n                for (size_t i = 0; i < length; ++i)\n                    deserialize(array[i],in);            \n            }\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing a C style array\");\n        }\n\n        if (size != length)\n            throw serialization_error(\"Error deserializing a C style array, lengths do not match\");\n    }\n\n    template <\n        size_t length\n        >\n    inline void deserialize (\n        char (&array)[length],\n        std::istream& in\n    )\n    {\n        size_t size;\n        try\n        {\n            deserialize(size,in); \n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing a C style array\");\n        }\n\n        if (size == length)\n        {\n            in.read(array, size);\n            if (!in)\n                throw serialization_error(\"Error deserializing a C-style array\");\n        }\n        else if (size+1 == length)\n        {\n            // In this case we are deserializing a C-style array so we need to add the null\n            // terminator.\n            in.read(array, size);\n            array[size] = '\\0';\n            if (!in)\n                throw serialization_error(\"Error deserializing a C-style string\");\n        }\n        else\n        {\n            throw serialization_error(\"Error deserializing a C style array, lengths do not match\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <\n        typename T,\n        size_t N\n        >\n    inline void serialize (\n        const std::array<T,N>& array,\n        std::ostream& out\n    )\n    {\n        typedef T c_array_type[N];\n        serialize(*(const c_array_type*)array.data(), out);\n    }\n\n    template <\n        typename T,\n        size_t N\n        >\n    inline void deserialize (\n        std::array<T,N>& array,\n        std::istream& in \n    )\n    {\n        typedef T c_array_type[N];\n        deserialize(*(c_array_type*)array.data(), in);\n    }\n\n    template <\n        typename T\n        >\n    inline void serialize (\n        const std::array<T,0>& /*array*/,\n        std::ostream& out\n    )\n    {\n        size_t N = 0;\n        serialize(N, out);\n    }\n\n    template <\n        typename T\n        >\n    inline void deserialize (\n        std::array<T,0>& /*array*/,\n        std::istream& in \n    )\n    {\n        size_t N;\n        deserialize(N, in);\n        if (N != 0)\n        {\n            std::ostringstream sout;\n            sout << \"Expected std::array of size 0 but found a size of \" << N;\n            throw serialization_error(sout.str());\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T, typename deleter>\n    void serialize (\n        const std::unique_ptr<T, deleter>& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            bool is_non_empty = item != nullptr;\n            serialize(is_non_empty, out);\n            if (is_non_empty)\n                serialize(*item, out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing an object of type std::unique_ptr\");\n        }\n    }\n\n    template <typename T, typename deleter>\n    void deserialize (\n        std::unique_ptr<T, deleter>& item,\n        std::istream& in\n    )\n    {\n        try\n        {\n            //when deserializing unique_ptr, this is fresh state, so reset the pointers, even if item is non-empty\n            bool is_non_empty;\n            deserialize(is_non_empty, in);\n            item.reset(is_non_empty ? new T() : nullptr); //can't use make_unique since dlib does not use C++14 as a minimum requirement.\n            \n            if (is_non_empty)\n                deserialize(*item, in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing an object of type std::unique_ptr\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template <typename T>\n    void serialize (\n        const std::shared_ptr<T>& item,\n        std::ostream& out\n    )\n    {\n        try\n        {\n            bool is_non_empty = item != nullptr;\n            serialize(is_non_empty, out);\n            if (is_non_empty)\n                serialize(*item, out);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while serializing an object of type std::shared_ptr\");\n        }\n    }\n\n    template <typename T>\n    void deserialize (\n        std::shared_ptr<T>& item,\n        std::istream& in\n    )\n    {\n        try\n        {\n            //when deserializing shared_ptr, this is fresh state, so reset the pointers, even if item is non-empty\n            bool is_non_empty;\n            deserialize(is_non_empty, in);\n            item = is_non_empty ? std::make_shared<T>() : nullptr;\n            \n            if (is_non_empty)\n                deserialize(*item, in);\n        }\n        catch (serialization_error& e)\n        {\n            throw serialization_error(e.info + \"\\n   while deserializing an object of type std::shared_ptr\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    class proxy_serialize\n    {\n    public:\n        explicit proxy_serialize (\n            const std::string& filename\n        ) : fout_optional_owning_ptr(new std::ofstream(filename.c_str(), std::ios::binary)),\n            fout(*fout_optional_owning_ptr)\n        {\n            if (!fout)\n                throw serialization_error(\"Unable to open \" + filename + \" for writing.\");\n        }\n        \n        explicit proxy_serialize (\n            std::vector<char>& buf\n        ) : fout_optional_owning_ptr(new vectorstream(buf)),\n            fout(*fout_optional_owning_ptr)\n        {\n        }\n        \n        explicit proxy_serialize (\n            std::vector<int8_t>& buf\n        ) : fout_optional_owning_ptr(new vectorstream(buf)),\n            fout(*fout_optional_owning_ptr)\n        {\n        }\n        \n        explicit proxy_serialize (\n            std::vector<uint8_t>& buf\n        ) : fout_optional_owning_ptr(new vectorstream(buf)),\n            fout(*fout_optional_owning_ptr)\n        {\n        }\n        \n        explicit proxy_serialize (\n            std::ostream& ss\n        ) : fout_optional_owning_ptr(nullptr),\n            fout(ss)\n        {}\n        \n        template <typename T>\n        inline proxy_serialize& operator<<(const T& item)\n        {\n            serialize(item, fout);\n            return *this;\n        }\n\n    private:\n        std::unique_ptr<std::ostream> fout_optional_owning_ptr;\n        std::ostream& fout;\n    };\n    \n    class proxy_deserialize\n    {\n    public:\n        explicit proxy_deserialize (\n            const std::string& filename_\n        )  : filename(filename_),\n             fin_optional_owning_ptr(new std::ifstream(filename.c_str(), std::ios::binary)),\n             fin(*fin_optional_owning_ptr)   \n        {\n            if (!fin)\n                throw serialization_error(\"Unable to open \" + filename + \" for reading.\");\n            init();\n        }\n        \n        explicit proxy_deserialize (\n            std::vector<char>& buf\n        ) : fin_optional_owning_ptr(new vectorstream(buf)),\n            fin(*fin_optional_owning_ptr)   \n        {\n            init();\n        }\n        \n        explicit proxy_deserialize (\n            std::vector<int8_t>& buf\n        ) : fin_optional_owning_ptr(new vectorstream(buf)),\n            fin(*fin_optional_owning_ptr)   \n        {\n            init();\n        }\n         \n        explicit proxy_deserialize (\n            std::vector<uint8_t>& buf\n        ) : fin_optional_owning_ptr(new vectorstream(buf)),\n            fin(*fin_optional_owning_ptr)   \n        {\n            init();\n        }\n        \n        explicit proxy_deserialize (\n            std::istream& ss\n        ) : fin_optional_owning_ptr(nullptr),\n            fin(ss)\n        {\n            init();\n        }\n                \n        template <typename T>\n        inline proxy_deserialize& operator>>(T& item)\n        {\n            return doit(item);\n        }\n\n        template <typename T>\n        inline proxy_deserialize& operator>>(ramdump_t<T>&& item)\n        {\n            return doit(std::move(item));\n        }\n        \n    private:\n\n        void init()\n        {\n            // read the file header into a buffer and then seek back to the start of the\n            // file.\n            fin.read(file_header,4);\n            fin.clear();\n            fin.seekg(0);\n        }\n        \n    private:\n        \n        template <typename T>\n        inline proxy_deserialize& doit(T&& item)\n        {\n            try\n            {\n                if (fin.peek() == EOF)\n                    throw serialization_error(\"No more objects were in the stream!\");\n                deserialize(std::forward<T>(item), fin);\n            }\n            catch (serialization_error& e)\n            {\n                std::string suffix;\n                if (looks_like_a_compressed_file())\n                    suffix = \"\\n *** THIS LOOKS LIKE A COMPRESSED FILE.  DID YOU FORGET TO DECOMPRESS IT? *** \\n\";\n\n                const std::string stream_description = filename.empty() ? \"stream\" : \"file '\" + filename + \"'\";\n                \n                if (objects_read == 0)\n                {\n                    throw serialization_error(\"An error occurred while trying to read the first\" \n                        \" object from the \" + stream_description + \".\\nERROR: \" + e.info + \"\\n\" + suffix);\n                }\n                else if (objects_read == 1)\n                {\n                    throw serialization_error(\"An error occurred while trying to read the second\" \n                        \" object from the \" + stream_description + \".\\nERROR: \" + e.info + \"\\n\" + suffix);\n                }\n                else if (objects_read == 2)\n                {\n                    throw serialization_error(\"An error occurred while trying to read the third\" \n                        \" object from the \" + stream_description + \".\\nERROR: \" + e.info + \"\\n\" + suffix);\n                }\n                else \n                {\n                    throw serialization_error(\"An error occurred while trying to read the \" +\n                        std::to_string(objects_read+1) + \"th object from the \" + stream_description + \".\\nERROR: \" + e.info + \"\\n\" + suffix);\n                }\n            }\n            ++objects_read;\n            return *this;\n        }\n\n        int objects_read = 0;\n        const std::string filename = \"\";\n        std::unique_ptr<std::istream> fin_optional_owning_ptr;\n        std::istream& fin;\n\n        // We don't need to look at the file header.  However, it's here because people\n        // keep posting questions to the dlib forums asking why they get file load errors.\n        // Then it turns out that the problem is they have a compressed file that NEEDS TO\n        // BE DECOMPRESSED by bzip2 or whatever and the reason they are getting\n        // deserialization errors is because they didn't decompress the file.  So we are\n        // going to check if this file looks like a compressed file and if so then emit an\n        // error message telling them to unzip the file. :(\n        char file_header[4] = {0,0,0,0};\n\n        bool looks_like_a_compressed_file(\n        ) const \n        {\n            if (file_header[0] == 'B' && file_header[1] == 'Z' && file_header[2] == 'h' &&\n                ('0' <= file_header[3] && file_header[3] <= '9') )\n            {\n                return true;\n            }\n\n            return false;\n        }\n    };\n\n    inline proxy_serialize serialize(const std::string& filename)\n    { return proxy_serialize(filename); }\n    inline proxy_serialize serialize(std::ostream& ss)\n    { return proxy_serialize(ss); }\n    inline proxy_serialize serialize(std::vector<char>& buf)\n    { return proxy_serialize(buf); }\n    inline proxy_serialize serialize(std::vector<int8_t>& buf)\n    { return proxy_serialize(buf); }\n    inline proxy_serialize serialize(std::vector<uint8_t>& buf)\n    { return proxy_serialize(buf); }\n    inline proxy_deserialize deserialize(const std::string& filename)\n    { return proxy_deserialize(filename); }\n    inline proxy_deserialize deserialize(std::istream& ss)\n    { return proxy_deserialize(ss); }\n    inline proxy_deserialize deserialize(std::vector<char>& buf)\n    { return proxy_deserialize(buf); }\n    inline proxy_deserialize deserialize(std::vector<int8_t>& buf)\n    { return proxy_deserialize(buf); }\n    inline proxy_deserialize deserialize(std::vector<uint8_t>& buf)\n    { return proxy_deserialize(buf); }\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n// forward declare the MessageLite object so we can reference it below.\nnamespace google\n{\n    namespace protobuf\n    {\n        class MessageLite;\n    }\n}\n\nnamespace dlib\n{\n\n    /*!A is_protocol_buffer\n        This is a template that tells you if a type is a Google protocol buffer object.  \n    !*/\n\n    template <typename T, typename U = void > \n    struct is_protocol_buffer \n    {\n        static const bool value = false;\n    };\n\n    template <typename T>\n    struct is_protocol_buffer <T,typename enable_if<is_convertible<T*,::google::protobuf::MessageLite*> >::type  >\n    {\n        static const bool value = true;\n    };\n\n    template <typename T>\n    typename enable_if<is_protocol_buffer<T> >::type serialize(const T& item, std::ostream& out)\n    {\n        // Note that Google protocol buffer messages are not self delimiting \n        // (see https://developers.google.com/protocol-buffers/docs/techniques)\n        // This means they don't record their length or where they end, so we have \n        // to record this information ourselves.  So we save the size as a little endian 32bit \n        // integer prefixed onto the front of the message.\n\n        byte_orderer bo;\n\n        // serialize into temp string\n        std::string temp;\n        if (!item.SerializeToString(&temp))\n            throw dlib::serialization_error(\"Error while serializing a Google Protocol Buffer object.\");\n        if (temp.size() > std::numeric_limits<uint32>::max())\n            throw dlib::serialization_error(\"Error while serializing a Google Protocol Buffer object, message too large.\");\n\n        // write temp to the output stream\n        uint32 size = static_cast<uint32>(temp.size());\n        bo.host_to_little(size);\n        out.write((char*)&size, sizeof(size));\n        out.write(temp.c_str(), temp.size());\n    }\n\n    template <typename T>\n    typename enable_if<is_protocol_buffer<T> >::type deserialize(T& item, std::istream& in)\n    {\n        // Note that Google protocol buffer messages are not self delimiting \n        // (see https://developers.google.com/protocol-buffers/docs/techniques)\n        // This means they don't record their length or where they end, so we have \n        // to record this information ourselves.  So we save the size as a little endian 32bit \n        // integer prefixed onto the front of the message.\n\n        byte_orderer bo;\n\n        uint32 size = 0;\n        // read the size\n        in.read((char*)&size, sizeof(size));\n        bo.little_to_host(size);\n        // Empty protos will just be empty.\n        if (size == 0) \n        {\n            item.Clear();\n            return;\n        }\n\n        if (!in)\n            throw dlib::serialization_error(\"Error while deserializing a Google Protocol Buffer object.\");\n\n        // read the bytes into temp\n        std::string temp;\n        temp.resize(size);\n        in.read(&temp[0], size);\n\n        // parse temp into item\n        if (!in || !item.ParseFromString(temp))\n        {\n            throw dlib::serialization_error(\"Error while deserializing a Google Protocol Buffer object.\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    inline void check_serialized_version(const std::string& expected_version, std::istream& in)\n    {\n        std::string version;\n        deserialize(version, in);\n        if (version != expected_version)\n        {\n            throw serialization_error(\"Unexpected version '\"+version+\n                \"' found while deserializing object. Expected version to be '\"+expected_version+\"'.\");\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    template<typename... T>\n    inline void serialize_these(std::ostream& out, const T& ...x)\n    {\n        using dlib::serialize;\n#ifdef __cpp_fold_expressions\n        (serialize(x, out),...);\n#else\n        (void)std::initializer_list<int>{(serialize(x, out),0)...};\n#endif\n    }\n    \n    template<typename... T>\n    inline void deserialize_these(std::istream& in, T& ...x)\n    {\n        using dlib::deserialize;\n#ifdef __cpp_fold_expressions\n        (deserialize(x, in),...);\n#else\n        (void)std::initializer_list<int>{(deserialize(x, in),0)...};\n#endif\n    }\n    \n    #define DLIB_DEFINE_DEFAULT_SERIALIZATION(Type, ...)                \\\n    void serialize_to(std::ostream& dlibDefaultSer$_out) const          \\\n    {                                                                   \\\n        using dlib::serialize;                                          \\\n        using dlib::serialize_these;                                    \\\n        try                                                             \\\n        {                                                               \\\n            /* Write a version header so that if, at a later time, */   \\\n            /* you realize you need to change the serialization    */   \\\n            /* format you can identify which version of the format */   \\\n            /* you are encountering when reading old files.        */   \\\n            int dlibDefaultSer$_version = 1;                            \\\n            serialize(dlibDefaultSer$_version, dlibDefaultSer$_out);    \\\n            serialize_these(dlibDefaultSer$_out, __VA_ARGS__);          \\\n        }                                                               \\\n        catch (dlib::serialization_error& e)                            \\\n        {                                                               \\\n            throw dlib::serialization_error(e.info + \"\\n   while serializing object of type \" #Type); \\\n        }                                                               \\\n    }                                                                   \\\n                                                                        \\\n    void deserialize_from(std::istream& dlibDefaultSer$_in)             \\\n    {                                                                   \\\n        using dlib::deserialize;                                        \\\n        using dlib::deserialize_these;                                  \\\n        try                                                             \\\n        {                                                               \\\n            int dlibDefaultSer$_version = 0;                            \\\n            deserialize(dlibDefaultSer$_version, dlibDefaultSer$_in);   \\\n            if (dlibDefaultSer$_version != 1)                           \\\n                throw dlib::serialization_error(\"Unexpected version found while deserializing \" #Type); \\\n            deserialize_these(dlibDefaultSer$_in, __VA_ARGS__);         \\\n        }                                                               \\\n        catch (dlib::serialization_error& e)                            \\\n        {                                                               \\\n            throw dlib::serialization_error(e.info + \"\\n   while deserializing object of type \" #Type); \\\n        }                                                               \\\n    }                                                                   \\\n    inline friend void serialize(const Type& item, std::ostream& out)   \\\n    {                                                                   \\\n        item.serialize_to(out);                                         \\\n    }                                                                   \\\n    inline friend void deserialize(Type& item, std::istream& in)        \\\n    {                                                                   \\\n        item.deserialize_from(in);                                      \\\n    }\n}\n\n#endif // DLIB_SERIALIZe_\n\n"
  },
  {
    "path": "dlib/server/server_http.cpp",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERVER_HTTP_CPp_\n#define DLIB_SERVER_HTTP_CPp_\n\n#include \"server_http.h\"\n\nnamespace dlib\n{\n\n// ----------------------------------------------------------------------------------------\n\n    namespace http_impl\n    {\n        inline unsigned char to_hex( unsigned char x )  \n        {\n            return x + (x > 9 ? ('A'-10) : '0');\n        }\n\n        const std::string urlencode( const std::string& s )  \n        {\n            std::ostringstream os;\n\n            for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci )\n            {\n                if ( (*ci >= 'a' && *ci <= 'z') ||\n                     (*ci >= 'A' && *ci <= 'Z') ||\n                     (*ci >= '0' && *ci <= '9') )\n                { // allowed\n                    os << *ci;\n                }\n                else if ( *ci == ' ')\n                {\n                    os << '+';\n                }\n                else\n                {\n                    os << '%' << to_hex(*ci >> 4) << to_hex(*ci % 16);\n                }\n            }\n\n            return os.str();\n        }\n\n        inline unsigned char from_hex (\n            unsigned char ch\n        ) \n        {\n            if (ch <= '9' && ch >= '0')\n                ch -= '0';\n            else if (ch <= 'f' && ch >= 'a')\n                ch -= 'a' - 10;\n            else if (ch <= 'F' && ch >= 'A')\n                ch -= 'A' - 10;\n            else \n                ch = 0;\n            return ch;\n        }\n\n        const std::string urldecode (\n            const std::string& str\n        ) \n        {\n            using namespace std;\n            string result;\n            string::size_type i;\n            for (i = 0; i < str.size(); ++i)\n            {\n                if (str[i] == '+')\n                {\n                    result += ' ';\n                }\n                else if (str[i] == '%' && str.size() > i+2)\n                {\n                    const unsigned char ch1 = from_hex(str[i+1]);\n                    const unsigned char ch2 = from_hex(str[i+2]);\n                    const unsigned char ch = (ch1 << 4) | ch2;\n                    result += ch;\n                    i += 2;\n                }\n                else\n                {\n                    result += str[i];\n                }\n            }\n            return result;\n        }\n\n        void parse_url(\n            std::string word, \n            key_value_map& queries\n        )\n        /*!\n            Parses the query string of a URL.  word should be the stuff that comes\n            after the ? in the query URL.\n        !*/\n        {\n            std::string::size_type pos;\n\n            for (pos = 0; pos < word.size(); ++pos)\n            {\n                if (word[pos] == '&')\n                    word[pos] = ' ';\n            }\n\n            std::istringstream sin(word);\n            sin >> word;\n            while (sin)\n            {\n                pos = word.find_first_of(\"=\");\n                if (pos != std::string::npos)\n                {\n                    std::string key = urldecode(word.substr(0,pos));\n                    std::string value = urldecode(word.substr(pos+1));\n\n                    queries[key] = value;\n                }\n                sin >> word;\n            }\n        }\n      \n        void read_with_limit(\n            std::istream& in, \n            std::string& buffer, \n            int delim = '\\n'\n        ) \n        {\n            using namespace std;\n            const size_t max = 64*1024;\n            buffer.clear();\n            buffer.reserve(300);\n\n            while (in.peek() != delim && in.peek() != '\\n' && in.peek() != EOF && buffer.size() < max)\n            {\n                buffer += (char)in.get();\n            }\n\n            // if we quit the loop because the data is longer than expected or we hit EOF\n            if (in.peek() == EOF)\n                throw http_parse_error(\"HTTP field from client terminated incorrectly\", 414);\n            if (buffer.size() == max)\n                throw http_parse_error(\"HTTP field from client is too long\", 414);\n\n            in.get();\n            // eat any remaining whitespace\n            if (delim == ' ')\n            {\n                while (in.peek() == ' ')\n                    in.get();\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    unsigned long parse_http_request ( \n        std::istream& in,\n        incoming_things& incoming,\n        unsigned long max_content_length\n    )\n    {\n        using namespace std;\n        using namespace http_impl;\n        read_with_limit(in, incoming.request_type, ' ');\n\n        // get the path\n        read_with_limit(in, incoming.path, ' ');\n\n        // Get the HTTP/1.1 - Ignore for now...\n        read_with_limit(in, incoming.protocol);\n\n        key_value_map_ci& incoming_headers = incoming.headers;\n        key_value_map& cookies          = incoming.cookies;\n        std::string& path               = incoming.path;\n        std::string& content_type       = incoming.content_type;\n        unsigned long content_length = 0;\n\n        string line;\n        read_with_limit(in, line);\n        string first_part_of_header;\n        string::size_type position_of_double_point;\n        // now loop over all the incoming_headers\n        while (line != \"\\r\")\n        {\n            position_of_double_point = line.find_first_of(':');\n            if ( position_of_double_point != string::npos )\n            {\n                first_part_of_header = dlib::trim(line.substr(0, position_of_double_point));\n\n                if ( !incoming_headers[first_part_of_header].empty() )\n                    incoming_headers[ first_part_of_header ] += \" \";\n                incoming_headers[first_part_of_header] += dlib::trim(line.substr(position_of_double_point+1));\n\n                // look for Content-Type:\n                if (line.size() > 14 && strings_equal_ignore_case(line, \"Content-Type:\", 13))\n                {\n                    content_type = line.substr(14);\n                    if (content_type[content_type.size()-1] == '\\r')\n                        content_type.erase(content_type.size()-1);\n                }\n                // look for Content-Length:\n                else if (line.size() > 16 && strings_equal_ignore_case(line, \"Content-Length:\", 15))\n                {\n                    istringstream sin(line.substr(16));\n                    sin >> content_length;\n                    if (!sin)\n                    {\n                        throw http_parse_error(\"Invalid Content-Length of '\" + line.substr(16) + \"'\", 411);\n                    }\n\n                    if (content_length > max_content_length)\n                    {\n                        std::ostringstream sout;\n                        sout << \"Content-Length of post back is too large.  It must be less than \" << max_content_length;\n                        throw http_parse_error(sout.str(), 413);\n                    }\n                }\n                // look for any cookies\n                else if (line.size() > 6 && strings_equal_ignore_case(line, \"Cookie:\", 7))\n                {\n                    string::size_type pos = 6;\n                    string key, value;\n                    bool seen_key_start = false;\n                    bool seen_equal_sign = false;\n                    while (pos + 1 < line.size())\n                    {\n                        ++pos;\n                        // ignore whitespace between cookies\n                        if (!seen_key_start && line[pos] == ' ')\n                            continue;\n\n                        seen_key_start = true;\n                        if (!seen_equal_sign) \n                        {\n                            if (line[pos] == '=')\n                            {\n                                seen_equal_sign = true;\n                            }\n                            else\n                            {\n                                key += line[pos];\n                            }\n                        }\n                        else\n                        {\n                            if (line[pos] == ';')\n                            {\n                                cookies[urldecode(key)] = urldecode(value);\n                                seen_equal_sign = false;\n                                seen_key_start = false;\n                                key.clear();\n                                value.clear();\n                            }\n                            else\n                            {\n                                value += line[pos];\n                            }\n                        }\n                    }\n                    if (key.size() > 0)\n                    {\n                        cookies[urldecode(key)] = urldecode(value);\n                        key.clear();\n                        value.clear();\n                    }\n                }\n            } // no ':' in it!\n            read_with_limit(in, line);\n        } // while (line != \"\\r\")\n\n\n        // If there is data being posted back to us as a query string then\n        // pick out the queries using parse_url.\n        if ((strings_equal_ignore_case(incoming.request_type, \"POST\") || \n             strings_equal_ignore_case(incoming.request_type, \"PUT\")) && \n            strings_equal_ignore_case(left_substr(content_type,\";\"), \"application/x-www-form-urlencoded\"))\n        {\n            if (content_length > 0)\n            {\n                incoming.body.resize(content_length);\n                in.read(&incoming.body[0],content_length);\n            }\n            parse_url(incoming.body, incoming.queries);\n        }\n\n        string::size_type pos = path.find_first_of(\"?\");\n        if (pos != string::npos)\n        {\n            parse_url(path.substr(pos+1), incoming.queries);\n        }\n\n\n        if (!in)\n            throw http_parse_error(\"Error parsing HTTP request\", 500);\n\n        return content_length;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void read_body (\n        std::istream& in,\n        incoming_things& incoming\n    )\n    {\n        // if the body hasn't already been loaded and there is data to load\n        if (incoming.body.size() == 0 &&\n            incoming.headers.count(\"Content-Length\") != 0)\n        {\n            const unsigned long content_length = string_cast<unsigned long>(incoming.headers[\"Content-Length\"]);\n\n            incoming.body.resize(content_length);\n            if (content_length > 0)\n            {\n                in.read(&incoming.body[0],content_length);\n            }\n        }\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void write_http_response (\n        std::ostream& out,\n        outgoing_things outgoing,\n        const std::string& result\n    )\n    {\n        using namespace http_impl;\n        key_value_map& new_cookies      = outgoing.cookies;\n        key_value_map_ci& response_headers = outgoing.headers;\n\n        // only send this header if the user hasn't told us to send another kind\n        bool has_content_type = false, has_location = false;\n        for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci )\n        {\n            if ( !has_content_type && strings_equal_ignore_case(ci->first , \"content-type\") )\n            {\n                has_content_type = true;\n            }\n            else if ( !has_location && strings_equal_ignore_case(ci->first , \"location\") )\n            {\n                has_location = true;\n            }\n        }\n\n        if ( has_location )\n        {\n            outgoing.http_return = 302;\n        }\n\n        if ( !has_content_type )\n        {\n            response_headers[\"Content-Type\"] = \"text/html\";\n        }\n\n        response_headers[\"Content-Length\"] = cast_to_string(result.size());\n\n        out << \"HTTP/1.0 \" << outgoing.http_return << \" \" << outgoing.http_return_status << \"\\r\\n\";\n\n        // Set any new headers\n        for(key_value_map_ci::const_iterator ci = response_headers.begin(); ci != response_headers.end(); ++ci )\n        {\n            out << ci->first << \": \" << ci->second << \"\\r\\n\";\n        }\n\n        // set any cookies \n        for(key_value_map::const_iterator ci = new_cookies.begin(); ci != new_cookies.end(); ++ci )\n        {\n            out << \"Set-Cookie: \" << urlencode(ci->first) << '=' << urlencode(ci->second) << \"\\r\\n\";\n        }\n        out << \"\\r\\n\" << result;\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void write_http_response (\n        std::ostream& out,\n        const http_parse_error& e \n    )\n    {\n        outgoing_things outgoing;\n        outgoing.http_return = e.http_error_code;\n        outgoing.http_return_status = e.what();\n        write_http_response(out, outgoing, std::string(\"Error processing request: \") + e.what());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    void write_http_response (\n        std::ostream& out,\n        const std::exception& e \n    )\n    {\n        outgoing_things outgoing;\n        outgoing.http_return = 500;\n        outgoing.http_return_status = e.what();\n        write_http_response(out, outgoing, std::string(\"Error processing request: \") + e.what());\n    }\n\n// ----------------------------------------------------------------------------------------\n\n    const logger server_http::dlog(\"dlib.server_http\");\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#endif // DLIB_SERVER_HTTP_CPp_\n\n"
  },
  {
    "path": "dlib/server/server_http_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net), Steven Van Ingelgem\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SERVER_HTTp_ABSTRACT_\n#ifdef DLIB_SERVER_HTTp_ABSTRACT_\n\n#include \"server_iostream_abstract.h\"\n#include <iostream>\n#include <string>\n#include <map>\n\nnamespace dlib\n{\n\n// -----------------------------------------------------------------------------------------\n\n    template <\n        typename Key, \n        typename Value, \n        typename Comparer = std::less<Key> \n        >\n    class constmap : public std::map<Key, Value, Comparer>\n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is simply an extension to the std::map that allows you \n                to use the operator[] accessor with a constant map.  \n        !*/\n    public:\n\n        const Value& operator[](\n            const Key& k\n        ) const;\n        /*!\n            ensures\n                - if (this->find(k) != this->end()) then\n                    - This map contains the given key\n                    - return the value associated with the given key\n                - else\n                    - return a default initialized Value object\n        !*/\n\n        Value& operator[](\n            const Key& k\n        ) { return std::map<Key, Value>::operator [](k); }\n        /*!\n            ensures\n                - This function does the same thing as the normal std::map operator[]\n                  function.\n                - if (this->find(k) != this->end()) then\n                    - This map contains the given key\n                    - return the value associated with the given key\n                - else\n                    - Adds a new entry into the map that is associated with the\n                      given key.  The new entry will be default initialized and\n                      this function returns a reference to it.\n        !*/ \n    };\n\n    typedef constmap<std::string, std::string> key_value_map;\n    // This version of key_value_map treats the key string as being case-insensitive.\n    // For example, a key string of \"Content-Type\" would access the same element as a key\n    // of \"content-type\".\n    typedef constmap<std::string, std::string, less_case_insensitive> key_value_map_ci;\n\n// -----------------------------------------------------------------------------------------\n\n    struct incoming_things \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object contains all the various bits of information that describe a\n                HTTP request that comes into a web server.\n\n                For a detailed discussion of the fields of this object, see the\n                server_http::on_request() method defined later in this file.\n        !*/\n\n        incoming_things (\n            const std::string& foreign_ip_,\n            const std::string& local_ip_,\n            unsigned short foreign_port_,\n            unsigned short local_port_\n        );\n        /*!\n            ensures\n                - #foreign_ip = foreign_ip_\n                - #foreign_port = foreign_port_\n                - #local_ip = local_ip_\n                - #local_port = local_port_\n        !*/\n            \n        std::string path;\n        std::string request_type;\n        std::string content_type;\n        std::string protocol;\n        std::string body;\n\n        key_value_map    queries;\n        key_value_map    cookies;\n        key_value_map_ci headers;\n\n        std::string    foreign_ip;\n        unsigned short foreign_port;\n        std::string    local_ip;\n        unsigned short local_port;\n    };\n\n    struct outgoing_things \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This object contains all the various bits of information that describe a\n                HTTP response from a web server.\n\n                For a detailed discussion of the fields of this object, see the\n                server_http::on_request() method defined later in this file.\n        !*/\n\n        outgoing_things(\n        );\n        /*!\n            ensures\n                - #http_return == 200\n                - #http_return_status == \"OK\"\n        !*/\n\n        key_value_map    cookies;\n        key_value_map_ci headers;\n        unsigned short   http_return;\n        std::string      http_return_status;\n    };\n\n// -----------------------------------------------------------------------------------------\n\n    class http_parse_error : public error \n    {\n        /*!\n            WHAT THIS OBJECT REPRESENTS\n                This is an exception thrown by the parse_http_request() routine if \n                there is a problem.\n        !*/\n    };\n\n// -----------------------------------------------------------------------------------------\n\n    unsigned long parse_http_request ( \n        std::istream& in,\n        incoming_things& incoming,\n        unsigned long max_content_length\n    );\n    /*!\n        ensures\n            - Attempts to read a HTTP GET, POST, or PUT request from the given input\n              stream.\n            - Reads all headers of the request and puts them into #incoming.  In particular,\n              this function populates the following fields:\n                - #incoming.path\n                - #incoming.request_type\n                - #incoming.content_type\n                - #incoming.protocol\n                - #incoming.queries\n                - #incoming.cookies\n                - #incoming.headers\n            - This function also populates the #incoming.body field if and only if the\n              Content-Type field is equal to \"application/x-www-form-urlencoded\".\n              Otherwise, the content is not read from the stream.\n        throws\n            - http_parse_error\n                This exception is thrown if the Content-Length coming from the web\n                browser is greater than max_content_length or if any other problem\n                is detected with the request.\n    !*/\n\n    void read_body (\n        std::istream& in,\n        incoming_things& incoming\n    );\n    /*!\n        requires\n            - parse_http_request(in,incoming,max_content_length) has already been called\n              and therefore populated the fields of incoming.\n        ensures\n            - if (incoming.body has already been populated with the content of an HTTP\n              request) then\n                - this function does nothing\n            - else\n                - reads the body of the HTTP request into #incoming.body.\n    !*/\n\n    void write_http_response (\n        std::ostream& out,\n        outgoing_things outgoing,\n        const std::string& result\n    );\n    /*!\n        ensures\n            - Writes an HTTP response, defined by the data in outgoing, to the given output\n              stream.\n            - The result variable is written out as the content of the response.\n    !*/\n\n    void write_http_response (\n        std::ostream& out,\n        const http_parse_error& e \n    );\n    /*!\n        ensures\n            - Writes an HTTP error response based on the information in the exception \n              object e.\n    !*/\n\n    void write_http_response (\n        std::ostream& out,\n        const std::exception& e \n    );\n    /*!\n        ensures\n            - Writes an HTTP error response based on the information in the exception\n              object e.\n    !*/\n\n// -----------------------------------------------------------------------------------------\n// -----------------------------------------------------------------------------------------\n\n    class server_http : public server_iostream \n    {\n\n        /*!\n            WHAT THIS EXTENSION DOES FOR server_iostream\n                This extension turns the server object into a simple HTTP server.  It only\n                handles HTTP GET, PUT and POST requests and each incoming request triggers\n                the on_request() callback.  \n\n            COOKIE STRINGS\n                The strings returned in the cookies key_value_map should be of the following form:\n                    key:   cookie_name\n                    value: cookie contents; expires=Fri, 31-Dec-2010 23:59:59 GMT; path=/; domain=.example.net\n\n                You don't have to supply all the extra cookie arguments.  So if you just want to\n                set a cookie that will expire when the client's browser is closed you can \n                just say something like incoming.cookies[\"cookie_name\"] = \"cookie contents\";\n\n            HTTP HEADERS\n                The HTTP headers in the incoming.headers and outgoing.headers are the name/value pairs\n                of HTTP headers.  For example, the HTTP header \"Content-Type: text/html\" would be\n                encoded such that outgoing.headers[\"Content-Type\"] == \"text/html\". \n\n                Also note that if you wish to change the content type of your response to the \n                client you may do so by setting the \"Content-Type\" header to whatever you like. \n                However, setting this field manually is not necessary as it will default to \n                \"text/html\" if you don't explicitly set it to something.\n        !*/\n\n    public:\n\n        server_http (\n        );\n        /*!\n            ensures\n                - #get_max_content_length() == 10*1024*1024\n        !*/\n\n        unsigned long get_max_content_length (\n        ) const;\n        /*!\n            ensures\n                - returns the max allowable content length, in bytes, of the post back to\n                  the web server.  If a client attempts to send more data than this then an\n                  error number 413 is returned back to the client and the request is not\n                  processed by the web server.\n        !*/\n\n        void set_max_content_length (\n            unsigned long max_length\n        );\n        /*!\n            ensures\n                - #get_max_content_length() == max_length\n        !*/\n\n    private:\n\n        virtual const std::string on_request (\n            const incoming_things& incoming,\n            outgoing_things& outgoing\n        ) = 0;\n        /*!\n            requires\n                - on_request() is called when there is an HTTP GET or POST request to be serviced \n                - on_request() is run in its own thread \n                - is_running() == true \n                - the number of current on_request() functions running < get_max_connection() \n                - in incoming: \n                    - incoming.path == the path being requested by this request\n                    - incoming.request_type == the type of request, GET or POST\n                    - incoming.content_type == the content type associated with this request\n                    - incoming.protocol == The protocol being used by the web browser (e.g. HTTP/1.1) \n                    - incoming.body == a string that contains the data that was posted back to the\n                      web server by the client (e.g. The string has the length specified by the\n                      Content-Length header).\n                    - incoming.body.size() < get_max_content_length()\n                    - incoming.queries == a map that contains all the key/value pairs in the query \n                      string of this request.  The key and value strings of the query string will\n                      have been decoded back into their original form before being sent to this\n                      function (i.e. '+' decoded back to ' ' and \"%hh\" into its corresponding \n                      ascii value.  So the URL-encoding is decoded automatically)\n                    - incoming.cookies == The set of cookies that came from the client along with \n                      this request.  The cookies will have been decoded back to normal form\n                      from the URL-encoding.\n                    - incoming.headers == a map that contains all the incoming HTTP headers \n                      from the client web browser.  \n                    - incoming.foreign_ip == the foreign ip address for this request \n                    - incoming.foreign_port == the foreign port number for this request\n                    - incoming.local_ip == the IP of the local interface this request is coming in on \n                    - incoming.local_port == the local port number this request is coming in on \n                - in outgoing:\n                    - outgoing.cookies.size() == 0\n                    - outgoing.headers.size() == 0\n                    - outgoing.http_return == 200\n                    - outgoing.http_return_status == \"OK\"\n            ensures\n                - This function returns the HTML page to be displayed as the response to this request. \n                - this function will not call clear()  \n                - #outgoing.cookies == a set of new cookies to pass back to the client along\n                  with the result of this request.  (Note that URL-encoding is automatically applied \n                  so you don't have to do it yourself)\n                - #outgoing.headers == a set of additional headers you wish to appear in the\n                  HTTP response to this request.  (This may be empty, the minimum needed headers\n                  will be added automatically if you don't set them)\n                - outgoing.http_return and outgoing.http_return_status may be set to override the \n                  default HTTP return code of 200 OK\n            throws\n                - throws only exceptions derived from std::exception.  If an exception is thrown\n                  then the error string from the exception is returned to the web browser.\n        !*/\n\n\n    // -----------------------------------------------------------------------\n    //                        Implementation Notes\n    // -----------------------------------------------------------------------\n\n        virtual void on_connect (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& foreign_ip,\n            const std::string& local_ip,\n            unsigned short foreign_port,\n            unsigned short local_port,\n            uint64\n        )\n        /*!\n            on_connect() is the function defined by server_iostream which is overloaded by\n            server_http.  In particular, the server_http's implementation is shown below.\n            In it you can see how the server_http parses the incoming http request, gets a\n            response by calling on_request(), and sends it back using the helper routines\n            defined at the top of this file.\n\n            Therefore, if you want to modify the behavior of the HTTP server, for example,\n            to do some more complex data streaming requiring direct access to the\n            iostreams, then you can do so by defining your own on_connect() routine.  In\n            particular, the default implementation shown below is a good starting point.\n        !*/\n        {\n            try\n            {\n                incoming_things incoming(foreign_ip, local_ip, foreign_port, local_port);\n                outgoing_things outgoing;\n\n                parse_http_request(in, incoming, get_max_content_length());\n                read_body(in, incoming);\n                const std::string& result = on_request(incoming, outgoing);\n                write_http_response(out, outgoing, result);\n            }\n            catch (http_parse_error& e)\n            {\n                write_http_response(out, e);\n            }\n            catch (std::exception& e)\n            {\n                write_http_response(out, e);\n            }\n        }\n    };\n\n}\n\n#endif // DLIB_SERVER_HTTp_ABSTRACT_ \n\n\n\n"
  },
  {
    "path": "dlib/server/server_iostream.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERVER_IOSTREAm_1_\n#define DLIB_SERVER_IOSTREAm_1_\n\n#include <iostream>\n#include \"server_iostream_abstract.h\"\n#include \"../logger.h\"\n#include \"../uintn.h\"\n#include \"server_kernel.h\"\n#include \"../sockstreambuf.h\"\n#include \"../map.h\"\n\n\nnamespace dlib\n{\n\n    class server_iostream : public server \n    {\n\n        /*!\n            INITIAL VALUE\n                - next_id == 0\n                - con_map.size() == 0\n\n            CONVENTION\n                - next_id == the id of the next connection \n                - for all current connections\n                    - con_map[id] == the connection object with the given id\n                - m == the mutex that protects the members of this object\n        !*/\n\n        typedef map<uint64,connection*,memory_manager<char>::kernel_2a>::kernel_1b id_map;\n\n    public:\n        server_iostream(\n        ) :\n            next_id(0)\n        {}\n\n        ~server_iostream(\n        )\n        {\n            server::clear();\n        }\n\n    protected:\n\n        void shutdown_connection (\n            uint64 id\n        )\n        {\n            auto_mutex M(m);\n            if (con_map.is_in_domain(id))\n            {\n                con_map[id]->shutdown();\n            }\n        }\n\n    private:\n\n        virtual void on_connect (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& foreign_ip,\n            const std::string& local_ip,\n            unsigned short foreign_port,\n            unsigned short local_port,\n            uint64 connection_id\n        )=0;\n\n        void on_connect (\n            connection& con\n        )\n        {\n            bool my_fault = true;\n            uint64 this_con_id=0;\n            try\n            {\n                sockstreambuf buf(&con);\n                std::istream in(&buf);\n                std::ostream out(&buf);\n                in.tie(&out);\n\n                // add this connection to the con_map\n                {\n                    auto_mutex M(m);\n                    this_con_id = next_id;\n                    connection* this_con = &con;\n                    con_map.add(this_con_id,this_con);\n                    this_con_id = next_id;\n                    ++next_id;\n                }\n\n                my_fault = false;\n                on_connect(\n                    in,\n                    out,\n                    con.get_foreign_ip(),\n                    con.get_local_ip(),\n                    con.get_foreign_port(),\n                    con.get_local_port(),\n                    this_con_id\n                );\n\n                // remove this connection from the con_map\n                {\n                    auto_mutex M(m);\n                    connection* this_con;\n                    uint64 junk;\n                    con_map.remove(this_con_id,junk,this_con);\n                }\n\n            }\n            catch (std::bad_alloc&)\n            {\n                // make sure we remove this connection from the con_map\n                {\n                    auto_mutex M(m);\n                    if (con_map.is_in_domain(this_con_id))\n                    {\n                        connection* this_con;\n                        uint64 junk;\n                        con_map.remove(this_con_id,junk,this_con);\n                    }\n                }\n\n                _dLog << LERROR << \"We ran out of memory in server_iostream::on_connect()\";\n                // if this is an escaped exception from on_connect then let it fly! \n                // Seriously though, this way it is obvious to the user that something bad happened\n                // since they probably won't have the dlib logger enabled.\n                if (!my_fault)\n                    throw;\n            }\n        }\n\n        uint64 next_id;\n        id_map con_map;\n        const static logger _dLog;\n        mutex m;\n        \n\n    };\n\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"server_iostream.cpp\"\n#endif\n\n#endif // DLIB_SERVER_IOSTREAm_1_\n\n\n\n"
  },
  {
    "path": "dlib/server/server_iostream_abstract.h",
    "content": "// Copyright (C) 2006  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SERVER_IOSTREAm_ABSTRACT_\n#ifdef DLIB_SERVER_IOSTREAm_ABSTRACT_\n\n\n#include \"server_kernel_abstract.h\"\n#include <iostream>\n#include <string>\n#include \"../uintn.h\"\n\nnamespace dlib\n{\n\n    class server_iostream : public server \n    {\n\n        /*!\n            WHAT THIS EXTENSION DOES FOR server \n                This extension redefines the on_connect() function so that\n                instead of giving you a connection object you get an istream \n                and ostream object.\n\n            THREAD SAFETY\n                Note that in on_connect() the input stream in is tied to the output stream \n                out.  This means that when you read from in it will modify out and thus \n                it is not safe to touch in and out concurrently from different threads \n                unless you untie them (which you do by saying in.tie(0);)\n        !*/\n\n    protected:\n\n        void shutdown_connection (\n            uint64 id\n        );\n        /*!\n            ensures\n                - if (there is a connection currently being serviced with the given id) then\n                    - the specified connection is shutdown. (i.e. connection::shutdown() is\n                      called on it so the iostreams operating on it will return EOF)\n        !*/\n\n    private:\n\n        virtual void on_connect (\n            std::istream& in,\n            std::ostream& out,\n            const std::string& foreign_ip,\n            const std::string& local_ip,\n            unsigned short foreign_port,\n            unsigned short local_port,\n            uint64 connection_id\n        )=0;\n        /*!\n            requires\n                - on_connect() is called when there is a new TCP connection that needs\n                  to be serviced.\n                - in == the input stream that reads data from the new connection\n                - out == the output stream that writes data to the new connection\n                - in.tie() == &out (i.e. when you read from in it automatically calls out.flush())\n                - foreign_ip == the foreign ip address for this connection \n                - foreign_port == the foreign port number for this connection \n                - local_ip == the IP of the local interface this connection is using\n                - local_port == the local port number for this connection\n                - on_connect() is run in its own thread \n                - is_running() == true \n                - the number of current connections < get_max_connection() \n                - connection_id == an integer that uniquely identifies this connection. \n                  It can be used by shutdown_connection() to terminate this connection.\n            ensures\n                - when the iostreams hit EOF on_connect() will terminate.  \n                  (because this is how clear() signals you the server is shutting down)\n                - this function will not call clear()  \n            throws\n                - does not throw any exceptions\n        !*/\n\n    };\n\n}\n\n#endif // DLIB_SERVER_IOSTREAm_ABSTRACT_ \n\n\n"
  },
  {
    "path": "dlib/server/server_kernel.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERVER_KERNEL_1_\n#define DLIB_SERVER_KERNEL_1_\n\n#include \"server_kernel_abstract.h\"\n\n#include <memory>\n#include <string>\n\n#include \"../threads.h\"\n#include \"../sockets.h\"\n#include \"../algs.h\"\n#include \"../set.h\"\n#include \"../logger.h\"\n\n\nnamespace dlib\n{\n\n    // These forward declarations are here so we can use them in the typedefs in the server\n    // class.  The reason for this is for backwards compatibility with previous versions of\n    // dlib.\n    class server_http;\n    class server_iostream;\n\n    class server\n    {\n\n\n        /*!\n            INITIAL VALUE\n                listening_port          == 0\n                listening_ip            == \"\"\n                running                 == false\n                shutting_down           == false\n                cons.size()             == 0\n                listening_port_mutex    == a mutex\n                listening_ip_mutex      == a mutex\n                running_mutex           == a mutex\n                running_signaler        == a signaler associated with running_mutex\n                shutting_down_mutex     == a mutex\n                cons_mutex              == a mutex\n                thread_count            == 0\n                thread_count_mutex      == a mutex\n                thread_count_signaler   == a signaler associated with thread_count_mutex\n                thread_count_zero       == a signaler associated with thread_count_mutex\n                max_connections         == 1000 \n                max_connections_mutex   == a mutex for max_connections and graceful_close_timeout\n                graceful_close_timeout  == 500 \n             \n            CONVENTION\n                listening_port          == get_listening_port()\n                listening_ip            == get_listening_ip()\n                running                 == is_running()\n                shutting_down           == true while clear() is running.  this\n                                           bool is used to tell the thread blocked on\n                                           accept that it should terminate\n                cons                    == a set containing all open connections\n                listening_port_mutex    == a mutex for listening_port\n                listening_ip_mutex      == a mutex for listening_ip\n                running_mutex           == a mutex for running\n                running_signaler        == a signaler for running and\n                                           is associated with running_mutex.  it is \n                                           used to signal when running is false\n                shutting_down_mutex     == a mutex for shutting_down\n                cons_mutex              == a mutex for cons\n                thread_count            == the number of threads currently running\n                thread_count_mutex      == a mutex for thread_count\n                thread_count_signaler   == a signaler for thread_count and\n                                           is associated with thread_count_mutex.  it\n                                           is used to signal when thread_count is\n                                           decremented  \n                thread_count_zero       == a signaler for thread_count and\n                                           is associated with thread_count_mutex.  it\n                                           is used to signal when thread_count becomes\n                                           zero\n                max_connections         == get_max_connections()\n                max_connections_mutex   == a mutex for max_connections\n        !*/\n        \n\n        typedef set<connection*>::kernel_1a set_of_connections;\n\n        // this structure is used to pass parameters to new threads\n        struct param\n        {\n            param (\n                server& server_,\n                connection& new_connection_,\n                unsigned long graceful_close_timeout_\n            ) :\n                the_server(server_),\n                new_connection(new_connection_),\n                graceful_close_timeout(graceful_close_timeout_)\n            {}\n\n            server& the_server;\n            connection& new_connection;\n            unsigned long graceful_close_timeout; \n        };\n        \n\n\n        public:\n\n            // These typedefs are here for backward compatibility with previous versions of dlib\n            typedef     server kernel_1a;\n            typedef     server kernel_1a_c;\n            typedef     server_iostream iostream_1a;\n            typedef     server_iostream iostream_1a_c;\n            typedef     server_http http_1a;\n            typedef     server_http http_1a_c;\n\n            server(\n            );\n\n            virtual ~server(\n            ); \n\n            void clear(\n            );\n\n            void start (\n            );\n\n            bool is_running ( \n            ) const;\n\n            const std::string get_listening_ip (\n            ) const;\n\n            int get_listening_port (\n            ) const;\n\n            void set_listening_port (\n                int port\n            );\n\n            void set_listening_ip (\n                const std::string& ip\n            );\n\n            void set_max_connections (\n                int max\n            );\n\n            int get_max_connections (\n            ) const;\n\n            void start_async (\n            );\n\n            void set_graceful_close_timeout (\n                unsigned long timeout\n            );\n\n            unsigned long get_graceful_close_timeout (\n            ) const;\n\n        private:\n\n            void start_async_helper (\n            );\n\n            void start_accepting_connections (\n            );\n\n            void open_listening_socket (\n            );\n\n            virtual void on_connect (\n                connection& new_connection\n            )=0;\n\n            virtual void on_listening_port_assigned (\n            ) {}\n\n            const static logger sdlog;\n\n            static void service_connection(\n                void* item\n            );\n            /*!\n                requires\n                    item is a pointer to a param struct\n                ensures\n                    services the new connection\n                    will take care of closing the connection and \n                    adding the connection to cons when it first starts and\n                    remove the connection from cons and signal that it has \n                    done so when it ends\n            !*/\n\n            // data members\n            int listening_port;\n            std::string listening_ip;\n            bool running;\n            bool shutting_down;\n            set_of_connections cons;\n            mutex listening_port_mutex;\n            mutex listening_ip_mutex;\n            rmutex running_mutex;\n            rsignaler running_signaler;\n            mutex shutting_down_mutex;\n            mutex cons_mutex;\n            int thread_count;\n            mutex thread_count_mutex;\n            signaler thread_count_signaler;\n            int max_connections;\n            mutex max_connections_mutex;\n            signaler thread_count_zero;\n            std::unique_ptr<thread_function> async_start_thread;\n            std::unique_ptr<listener> sock;\n            unsigned long graceful_close_timeout;\n\n\n            // restricted functions\n            server(server&);   \n            server& operator= (\n                server&\n                );    \n    };\n\n// ----------------------------------------------------------------------------------------\n\n}\n\n#ifdef NO_MAKEFILE\n#include \"server_kernel.cpp\"\n#endif\n\n#endif // DLIB_SERVER_KERNEL_1_\n\n"
  },
  {
    "path": "dlib/server/server_kernel_abstract.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#undef DLIB_SERVER_KERNEL_ABSTRACT_\n#ifdef DLIB_SERVER_KERNEL_ABSTRACT_\n\n#include \"../threads/threads_kernel_abstract.h\"\n#include \"../sockets/sockets_kernel_abstract.h\"\n#include <string>\n\n\nnamespace dlib\n{\n    class server\n    {\n\n        /*!\n            INITIAL VALUE\n                get_listening_ip()           == \"\"\n                get_listening_port()         == 0\n                is_running()                 == false\n                get_max_connections()        == 1000\n                get_graceful_close_timeout() == 500 \n\n\n            CALLBACK FUNCTIONS\n            on_connect():\n                To use this object inherit from it and define the pure virtual function\n                on_connect.  Inside this function is where you will handle each new\n                connection.  Note that the connection object passed to on_connect() should\n                NOT be closed, just let the function end and it will be gracefully closed \n                for you.  Also note that each call to on_connect() is run in its own \n                thread.  Also note that on_connect() should NOT throw any exceptions, \n                all exceptions must be dealt with inside on_connect() and cannot be \n                allowed to leave.\n\n            on_listening_port_assigned():\n                This function is called to let the client know that the operating\n                system has assigned a port number to the listening port.  This\n                happens if a port number of zero was given.  Note that this\n                function does not need to be defined.  If you don't care then\n                don't define it and it will do nothing.  Note also that this function\n                is NOT called in its own thread.  Thus, making it block might hang the\n                server.\n\n            WHAT THIS OBJECT REPRESENTS\n                This object represents a server that listens on a port and spawns new\n                threads to handle each new connection.            \n\n                Note that the clear() function does not return until all calls to \n                on_connect() have finished and the start() function has been shutdown.\n                Also note that when clear() is called all open connection objects \n                will be shutdown().\n\n                A note about get_max_connections(): when the maximum number of connections\n                has been reached accept() will simply not be called until the number of\n                open connections drops below get_max_connections().  This means connections\n                will just wait to be serviced, rather than being outright refused.\n\n            THREAD SAFETY\n                All member functions are thread-safe.\n        !*/\n        \n        public:\n\n            server(\n            );\n            /*!\n                ensures \n                    - #*this is properly initialized\n                throws\n                    - std::bad_alloc\n                    - dlib::thread_error\n            !*/\n\n            virtual ~server(\n            ); \n            /*!\n                requires\n                    - is not called from any of server's callbacks\n                ensures\n                    - all resources associated with *this have been released\n            !*/\n\n            void clear(\n            );\n            /*!\n                requires\n                    - is not called from any of server's callbacks\n                ensures\n                    - #*this has its initial value \n                    - all open connection objects passed to on_connect() are shutdown() \n                    - blocks until all calls to on_connect() have finished \n                    - blocks until the start() function has released all its resources\n                throws\n                    - std::bad_alloc\n                        if this exception is thrown then the server object is unusable \n                        until clear() is called and succeeds\n            !*/\n\n            void start (\n            );\n            /*!\n                requires\n                    - is_running() == false\n                ensures\n                    - starts listening on the port and ip specified by get_listening_ip()\n                      and #get_listening_port() for new connections.\n                    - if (get_listening_port() == 0) then\n                        - a port to listen on will be automatically selected \n                        - #get_listening_port() == the selected port being used\n                    - if (get_listening_ip() == \"\" ) then\n                        - all local IPs will be listened on\n                    - blocks until clear() is called or an error occurs  \n                throws\n                    - dlib::socket_error\n                        start() will throw this exception if there is some problem binding\n                        ports and/or starting the server or if there is a problem \n                        accepting new connections while it's running. \n                        If this happens then\n                            - All open connection objects passed to on_connect() are shutdown()\n                              and the exception will not be thrown until all on_connect() calls\n                              have terminated.\n                            - The server will be cleared and returned to its initial value. \n                    - dlib::thread_error\n                        start() will throw this exception if there is a problem \n                        creating new threads.  Or it may throw this exception if there\n                        is a problem creating threading objects. \n                        If this happens then\n                            - All open connection objects passed to on_connect() are shutdown()\n                              and the exception will not be thrown until all on_connect() calls\n                              have terminated.\n                            - The server will be cleared and returned to its initial value. \n                    - std::bad_alloc\n                        start() may throw this exception and if it does then the object \n                        will be unusable until clear() is called and succeeds\n            !*/\n\n            void start_async (\n            );\n            /*!\n                ensures\n                    - starts listening on the port and ip specified by get_listening_ip()\n                      and #get_listening_port() for new connections.  \n                    - if (get_listening_port() == 0) then\n                        - a port to listen on will be automatically selected \n                        - #get_listening_port() == the selected port being used\n                    - if (get_listening_ip() == \"\" ) then\n                        - all local IPs will be listened on\n                    - does NOT block.  That is, this function will return right away and\n                      the server will run on a background thread until clear() or this\n                      object's destructor is called (or until some kind of fatal error\n                      occurs).  \n                    - if an error occurs in the background thread while the server is\n                      running then it will shut itself down, set is_running() to false, and\n                      log the error to a dlib::logger object. \n                    - calling start_async() on a running server has no effect.\n                throws\n                    - dlib::socket_error\n                        start_async() will throw this exception if there is some problem binding\n                        ports and/or starting the server. \n                        If this happens then\n                            - The server will be cleared and returned to its initial value. \n            !*/\n\n            bool is_running ( \n            ) const;\n            /*!\n                ensures\n                    - returns true if start() is running \n                    - returns false if start() is not running or has released all\n                      its resources and is about to terminate\n                throws\n                    - std::bad_alloc\n            !*/\n\n            int get_max_connections (\n            ) const;\n            /*!\n                ensures\n                    - returns the maximum number of connections the server will accept \n                      at a time.\n                    - returns 0 if the server will accept any number of connections\n                throws\n                    - std::bad_alloc\n            !*/\n\n\n            const std::string get_listening_ip (\n            ) const;\n            /*!\n                ensures\n                    - returns the local ip to listen for new connections on \n                    - returns \"\" if ALL local ips are to be listened on\n                throws\n                    - std::bad_alloc\n            !*/\n\n            int get_listening_port (\n            ) const;\n            /*!\n                ensures\n                    - returns the local port number to listen for new connections on \n                    - returns 0 if the local port number has not yet been set\n                throws\n                    - std::bad_alloc\n            !*/\n\n            void set_listening_port (\n                int port\n            );\n            /*!\n                requires\n                    - port >= 0 \n                    - is_running() == false\n                ensures\n                    - #get_listening_port() == port\n                throws\n                    - std::bad_alloc\n            !*/\n\n            void set_listening_ip (\n                const std::string& ip\n            );\n            /*!\n                requires\n                    - is_ip_address(ip) == true or ip == \"\"\n                    - is_running() == false\n                ensures\n                    - #get_listening_ip() == ip                     \n                throws\n                    - std::bad_alloc\n            !*/\n\n            void set_max_connections (\n                int max\n            );\n            /*!\n                requires\n                    - max >= 0\n                ensures\n                    - #get_max_connections() == max\n                throws\n                    - std::bad_alloc\n            !*/\n    \n            void set_graceful_close_timeout (\n                unsigned long timeout\n            );\n            /*!\n                ensures\n                    - #get_graceful_close_timeout() == timeout\n            !*/\n\n            unsigned long get_graceful_close_timeout (\n            ) const;\n            /*!\n                ensures\n                    - When on_connect() terminates, it will close the connection using\n                      close_gracefully().  This is done so that any data still in the\n                      operating system's output buffers gets a chance to be properly\n                      transmitted to the remote host.  Part of this involves waiting for\n                      the remote host to close their end of the connection.  Therefore,\n                      get_graceful_close_timeout() returns the timeout, in milliseconds,\n                      that we wait for the remote host to close their end of the\n                      connection.  This is the timeout value given to close_gracefully().\n            !*/\n\n        private:\n\n            virtual void on_connect (\n                connection& new_connection\n            )=0;\n            /*!\n                requires\n                    - on_connect() is run in its own thread \n                    - is_running() == true \n                    - the number of current connections < get_max_connection() \n                    - new_connection == the new connection to the server which is\n                      to be serviced by this call to on_connect()\n                ensures\n                    - when new_connection is shutdown() on_connect() will terminate \n                    - this function will not call clear()  \n                throws\n                    - does not throw any exceptions\n            !*/\n\n            // do nothing by default\n            virtual void on_listening_port_assigned (\n            ) {}\n            /*!\n                requires\n                    - is called if a listening port of zero was specified and\n                      an actual port number has just been assigned to the server\n                ensures\n                    - this function will not block  \n                    - this function will not call clear()  \n                throws\n                    - does not throw any exceptions\n            !*/\n\n\n            // restricted functions\n            server(server&);        // copy constructor\n            server& operator=(server&);    // assignment operator\n    };\n\n}\n\n#endif // DLIB_SERVER_KERNEL_ABSTRACT_\n\n"
  },
  {
    "path": "dlib/server.h",
    "content": "// Copyright (C) 2003  Davis E. King (davis@dlib.net)\n// License: Boost Software License   See LICENSE.txt for the full license.\n#ifndef DLIB_SERVEr_\n#define DLIB_SERVEr_\n\n#include \"server/server_kernel.h\"\n#include \"server/server_iostream.h\"\n#include \"server/server_http.h\"\n\n\n#endif // DLIB_SERVEr_\n\n"
  }
]